diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e2f6a79affc53..27aebdb4220b4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,10 +10,16 @@ .github/workflows/docker-ephemeral-env.yml @robdiciuccio @craig-rueda @rusackas @eschutho @dpgaspar @nytai @mistercrunch .github/workflows/ephemeral*.yml @robdiciuccio @craig-rueda @rusackas @eschutho @dpgaspar @nytai @mistercrunch -# Notify some committers of changes in the Select component +# Notify some committers of changes in the components /superset-frontend/src/components/Select/ @michael-s-molina @geido @ktmud +/superset-frontend/src/components/MetadataBar/ @michael-s-molina +/superset-frontend/src/components/DropdownContainer/ @michael-s-molina # Notify Helm Chart maintainers about changes in it /helm/superset/ @craig-rueda @dpgaspar @villebro + +# Notify E2E test maintainers of changes + +/superset-frontend/cypress-base/ @jinghua-qa @geido @eschutho @rusackas @betodealmeida diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 0e506cf9fb920..f821eb35246bc 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,6 +1,6 @@ --- name: Bug report -about: Create a report to help us improve +about: Create a report to help us improve Superset's stability! For feature requests please open a discussion at https://github.com/apache/superset/discussions/categories/ideas labels: "#bug" --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 8e6e0da9c9597..0000000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -labels: "#enhancement" - ---- - -Github Discussions is our new home for discussing features and improvements! - -https://github.com/apache/superset/discussions/categories/ideas - -We'd like to keep Github Issues focuses on bugs and SIP's (Superset Improvement Proposals)! - -Please note that feature requests opened as Github Issues will be moved to Discussions. diff --git a/.github/ISSUE_TEMPLATE/sip.md b/.github/ISSUE_TEMPLATE/sip.md index 6c526d6d1fa04..c2b0a14b91400 100644 --- a/.github/ISSUE_TEMPLATE/sip.md +++ b/.github/ISSUE_TEMPLATE/sip.md @@ -1,14 +1,16 @@ --- name: SIP -about: Superset Improvement Proposal +about: Superset Improvement Proposal (See SIP-0: https://github.com/apache/superset/issues/5602) labels: "#SIP" +title: "[SIP] Your Title Here (do not add SIP number)" +asignees: "apache/superset-committers" --- *Please make sure you are familiar with the SIP process documented* -(here)[https://github.com/apache/superset/issues/5602]. The SIP number should be the next number after the latest SIP listed [here](https://github.com/apache/superset/issues?q=is%3Aissue+label%3Asip). +(here)[https://github.com/apache/superset/issues/5602]. The SIP will be numbered by a committer upon acceptance. -## [SIP-\] Proposal for +## [SIP] Proposal for ...<title> ### Motivation diff --git a/.github/actions/chart-testing-action b/.github/actions/chart-testing-action index b0d4458c71155..afea100a51351 160000 --- a/.github/actions/chart-testing-action +++ b/.github/actions/chart-testing-action @@ -1 +1 @@ -Subproject commit b0d4458c71155b54fcf33e11dd465dc923550009 +Subproject commit afea100a513515fbd68b0e72a7bb0ae34cb62aec diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 493868eab966d..7320c23a1432b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,6 +7,7 @@ updates: labels: - npm - dependabot + versioning-strategy: increase - package-ecosystem: "pip" directory: "/requirements/" @@ -21,9 +22,29 @@ updates: schedule: interval: "daily" open-pull-requests-limit: 0 + versioning-strategy: increase - package-ecosystem: "npm" directory: "/docs/" schedule: interval: "daily" open-pull-requests-limit: 0 + versioning-strategy: increase + + - package-ecosystem: "npm" + directory: "/superset-websocket/" + schedule: + interval: "daily" + labels: + - npm + - dependabot + versioning-strategy: increase + + - package-ecosystem: "npm" + directory: "/superset-websocket/utils/client-ws-app/" + schedule: + interval: "daily" + labels: + - npm + - dependabot + versioning-strategy: increase diff --git a/.github/workflows/bashlib.sh b/.github/workflows/bashlib.sh index ae10c342e854d..3eb460f7fd85f 100644 --- a/.github/workflows/bashlib.sh +++ b/.github/workflows/bashlib.sh @@ -183,7 +183,7 @@ cypress-run-all() { nohup flask run --no-debugger -p $port >"$flasklog" 2>&1 </dev/null & local flaskProcessId=$! - cypress-run "*/**/!(*.applitools.test.ts)" + cypress-run "*/**/*" # After job is done, print out Flask log for debugging say "::group::Flask log for default run" @@ -198,7 +198,7 @@ cypress-run-all() { nohup flask run --no-debugger -p $port >"$flasklog" 2>&1 </dev/null & local flaskProcessId=$! - cypress-run "sqllab/!(*.applitools.test.ts)" "Backend persist" + cypress-run "sqllab/*" "Backend persist" # Upload code coverage separately so each page can have separate flags # -c will clean existing coverage reports, -F means add flags @@ -220,14 +220,19 @@ eyes-storybook-dependencies() { } cypress-run-applitools() { + cd "$GITHUB_WORKSPACE/superset-frontend/cypress-base" + local flasklog="${HOME}/flask.log" local port=8081 + local cypress="./node_modules/.bin/cypress run" + local browser=${CYPRESS_BROWSER:-chrome} + export CYPRESS_BASE_URL="http://localhost:${port}" nohup flask run --no-debugger -p $port >"$flasklog" 2>&1 </dev/null & local flaskProcessId=$! - cypress-run "*/**/*.applitools.test.ts" + $cypress --spec "cypress/integration/*/**/*.applitools.test.ts" --browser "$browser" --headless --config ignoreTestFiles="[]" codecov -c -F "cypress" || true diff --git a/.github/workflows/caches.js b/.github/workflows/caches.js index 39d0ad2e6aaf2..66fd7ee95933e 100644 --- a/.github/workflows/caches.js +++ b/.github/workflows/caches.js @@ -25,6 +25,8 @@ const assetsConfig = { path: [`${workspaceDirectory}/superset/static/assets`], hashFiles: [ `${workspaceDirectory}/superset-frontend/src/**/*`, + `${workspaceDirectory}/superset-frontend/packages/**/*`, + `${workspaceDirectory}/superset-frontend/plugins/**/*`, `${workspaceDirectory}/superset-frontend/*.js`, `${workspaceDirectory}/superset-frontend/*.json`, ], diff --git a/.github/workflows/chromatic-master.yml b/.github/workflows/chromatic-master.yml new file mode 100644 index 0000000000000..6cdf10506f00f --- /dev/null +++ b/.github/workflows/chromatic-master.yml @@ -0,0 +1,55 @@ +# .github/workflows/chromatic.yml +# seee https://www.chromatic.com/docs/github-actions +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Workflow name +name: 'Chromatic Storybook Master' + +# Event for the workflow +# Only run if changes were made in superset-frontend folder of repo on merge to Master +on: + # This will trigger when a branch merges to master when the PR has changes in the frontend folder updating the chromatic baseline + push: + branches: + - master + paths: + - "superset-frontend/**" + +# List of jobs +jobs: + chromatic-deployment: + # Operating System + runs-on: ubuntu-latest + # Job steps + steps: + - uses: actions/checkout@v1 + - name: Install dependencies + run: npm ci + working-directory: superset-frontend + # 👇 Build and publish Storybook to Chromatic + - name: Build and publish Storybook to Chromatic + id: chromatic-master + uses: chromaui/action@v1 + # Required options for the Chromatic GitHub Action + with: + # 👇 Location of package.json from root of mono-repo + workingDir: superset-frontend + # 👇 Chromatic projectToken, refer to the manage page to obtain it. + projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + exitZeroOnChanges: true # 👈 Option to prevent the workflow from failing + autoAcceptChanges: true # 👈 Option to accept all changes when merging to master diff --git a/.github/workflows/docker_build_push.sh b/.github/workflows/docker_build_push.sh index 4feea5d802d4f..b969813627c55 100755 --- a/.github/workflows/docker_build_push.sh +++ b/.github/workflows/docker_build_push.sh @@ -50,12 +50,40 @@ docker build --target lean \ -t "${REPO_NAME}:${SHA}" \ -t "${REPO_NAME}:${REFSPEC}" \ -t "${REPO_NAME}:${LATEST_TAG}" \ + --build-arg PY_VER="3.8-slim"\ --label "sha=${SHA}" \ --label "built_at=$(date)" \ --label "target=lean" \ --label "build_actor=${GITHUB_ACTOR}" \ . +# +# Build the "lean39" image +# +docker build --target lean \ + -t "${REPO_NAME}:${SHA}-py39" \ + -t "${REPO_NAME}:${REFSPEC}-py39" \ + -t "${REPO_NAME}:${LATEST_TAG}-py39" \ + --build-arg PY_VER="3.9-slim"\ + --label "sha=${SHA}" \ + --label "built_at=$(date)" \ + --label "target=lean39" \ + --label "build_actor=${GITHUB_ACTOR}" \ + . + +# +# Build the "websocket" image +# +docker build \ + -t "${REPO_NAME}:${SHA}-websocket" \ + -t "${REPO_NAME}:${REFSPEC}-websocket" \ + -t "${REPO_NAME}:${LATEST_TAG}-websocket" \ + --label "sha=${SHA}" \ + --label "built_at=$(date)" \ + --label "target=websocket" \ + --label "build_actor=${GITHUB_ACTOR}" \ + superset-websocket + # # Build the dev image # diff --git a/.github/workflows/license-check.yml b/.github/workflows/license-check.yml new file mode 100644 index 0000000000000..9ae633bdc4920 --- /dev/null +++ b/.github/workflows/license-check.yml @@ -0,0 +1,51 @@ +name: License Check + +on: + push: + branches-ignore: + - "dependabot/**" + pull_request: + +jobs: + license_check: + name: License Check + runs-on: ubuntu-20.04 + steps: + - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" + uses: actions/checkout@v2 + with: + persist-credentials: false + submodules: recursive + - name: Setup Java + uses: actions/setup-java@v1 + with: + java-version: 8 + - name: Generate fossa report + env: + FOSSA_API_KEY: ${{ secrets.FOSSA_API_KEY }} + run: | + set -eo pipefail + if [[ "${{github.event_name}}" != "pull_request" ]]; then + ./scripts/fossa.sh + exit 0 + fi + + URL="https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" + FILES=$(curl -s -X GET -G $URL | jq -r '.[] | .filename') + + cat<<EOF + CHANGED FILES: + $FILES + + EOF + + if [[ "${FILES}" =~ (.*package*\.json|requirements\/[a-z_-]+\.txt|setup\.py) ]]; then + echo "Detected dependency changes... running fossa check" + + ./scripts/fossa.sh + else + echo "No dependency changes... skiping fossa check" + fi + shell: bash + - name: Run license check + run: ./scripts/check_license.sh diff --git a/.github/workflows/misc.yml b/.github/workflows/prefer-typescript.yml similarity index 55% rename from .github/workflows/misc.yml rename to .github/workflows/prefer-typescript.yml index f8b5fb3fc6ffb..8005cf36a3555 100644 --- a/.github/workflows/misc.yml +++ b/.github/workflows/prefer-typescript.yml @@ -1,4 +1,4 @@ -name: Miscellaneous +name: Prefer Typescript on: push: @@ -7,49 +7,6 @@ on: pull_request: jobs: - license_check: - name: License Check - runs-on: ubuntu-20.04 - steps: - - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v2 - with: - persist-credentials: false - submodules: recursive - - name: Setup Java - uses: actions/setup-java@v1 - with: - java-version: 8 - - name: Generate fossa report - env: - FOSSA_API_KEY: ${{ secrets.FOSSA_API_KEY }} - run: | - set -eo pipefail - if [[ "${{github.event_name}}" != "pull_request" ]]; then - ./scripts/fossa.sh - exit 0 - fi - - URL="https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" - FILES=$(curl -s -X GET -G $URL | jq -r '.[] | .filename') - - cat<<EOF - CHANGED FILES: - $FILES - - EOF - - if [[ "${FILES}" =~ (.*package*\.json|requirements\/[a-z_-]+\.txt|setup\.py) ]]; then - echo "Detected dependency changes... running fossa check" - - ./scripts/fossa.sh - else - echo "No dependency changes... skiping fossa check" - fi - shell: bash - - name: Run license check - run: ./scripts/check_license.sh - prefer_typescript: if: github.ref == 'ref/heads/master' && github.event_name == 'pull_request' name: Prefer Typescript diff --git a/.github/workflows/superset-applitool-cypress.yml b/.github/workflows/superset-applitool-cypress.yml index eb7d774233bb3..47fc1a24e4c26 100644 --- a/.github/workflows/superset-applitool-cypress.yml +++ b/.github/workflows/superset-applitool-cypress.yml @@ -32,7 +32,7 @@ jobs: ports: - 15432:5432 redis: - image: redis:5-alpine + image: redis:7-alpine ports: - 16379:6379 steps: diff --git a/.github/workflows/superset-cli.yml b/.github/workflows/superset-cli.yml index 369447e1509c5..65ec8b018f217 100644 --- a/.github/workflows/superset-cli.yml +++ b/.github/workflows/superset-cli.yml @@ -30,7 +30,7 @@ jobs: # GitHub action runner's default installations - 15432:5432 redis: - image: redis:5-alpine + image: redis:7-alpine ports: - 16379:6379 steps: diff --git a/.github/workflows/superset-e2e.yml b/.github/workflows/superset-e2e.yml index f936b544a9cf3..ab82731ac481b 100644 --- a/.github/workflows/superset-e2e.yml +++ b/.github/workflows/superset-e2e.yml @@ -38,7 +38,7 @@ jobs: ports: - 15432:5432 redis: - image: redis:5-alpine + image: redis:7-alpine ports: - 16379:6379 steps: diff --git a/.github/workflows/superset-frontend.yml b/.github/workflows/superset-frontend.yml index 03e2b9e7d4207..bf09d293c6e3a 100644 --- a/.github/workflows/superset-frontend.yml +++ b/.github/workflows/superset-frontend.yml @@ -51,6 +51,11 @@ jobs: if: steps.check.outcome == 'failure' working-directory: ./superset-frontend run: npm run plugins:build-storybook + - name: superset-ui/core coverage + if: steps.check.outcome == 'failure' + working-directory: ./superset-frontend + run: | + npm run core:cover - name: unit tests if: steps.check.outcome == 'failure' working-directory: ./superset-frontend diff --git a/.github/workflows/superset-helm-lint.yml b/.github/workflows/superset-helm-lint.yml index a7f83f561ac25..d0e650839f9a4 100644 --- a/.github/workflows/superset-helm-lint.yml +++ b/.github/workflows/superset-helm-lint.yml @@ -44,3 +44,4 @@ jobs: CT_CHART_DIRS: helm CT_LINT_CONF: lintconf.yaml CT_SINCE: HEAD + CT_CHART_REPOS: bitnami=https://charts.bitnami.com/bitnami diff --git a/.github/workflows/superset-helm-release.yml b/.github/workflows/superset-helm-release.yml index bf896140b6d1c..1559432eb247a 100644 --- a/.github/workflows/superset-helm-release.yml +++ b/.github/workflows/superset-helm-release.yml @@ -3,9 +3,9 @@ name: Release Charts on: push: branches: - - 'master' + - "master" paths: - - 'helm/**' + - "helm/**" jobs: release: @@ -28,6 +28,9 @@ jobs: with: version: v3.5.4 + - name: Add bitnami repo dependency + run: helm repo add bitnami https://charts.bitnami.com/bitnami + - name: Run chart-releaser uses: ./.github/actions/chart-releaser-action with: diff --git a/.github/workflows/superset-python-integrationtest.yml b/.github/workflows/superset-python-integrationtest.yml index 926d6185bf4e8..eae19b234cf34 100644 --- a/.github/workflows/superset-python-integrationtest.yml +++ b/.github/workflows/superset-python-integrationtest.yml @@ -29,7 +29,7 @@ jobs: ports: - 13306:3306 redis: - image: redis:5-alpine + image: redis:7-alpine options: --entrypoint redis-server ports: - 16379:6379 @@ -97,7 +97,7 @@ jobs: # GitHub action runner's default installations - 15432:5432 redis: - image: redis:5-alpine + image: redis:7-alpine ports: - 16379:6379 steps: @@ -156,7 +156,7 @@ jobs: sqlite:///${{ github.workspace }}/.temp/unittest.db services: redis: - image: redis:5-alpine + image: redis:7-alpine ports: - 16379:6379 steps: diff --git a/.github/workflows/superset-python-misc.yml b/.github/workflows/superset-python-misc.yml index 39c52c51bb8ce..739869a7bb915 100644 --- a/.github/workflows/superset-python-misc.yml +++ b/.github/workflows/superset-python-misc.yml @@ -33,8 +33,8 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - cache: 'pip' - cache-dependency-path: 'requirements/testing.txt' + cache: "pip" + cache-dependency-path: "requirements/testing.txt" - name: Install dependencies if: steps.check.outcome == 'failure' uses: ./.github/actions/cached-dependencies @@ -65,7 +65,7 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - cache: 'pip' + cache: "pip" cache-dependency-path: | requirements/base.txt requirements/integration.txt @@ -78,6 +78,15 @@ jobs: pip install wheel pip install -r requirements/base.txt pip install -r requirements/integration.txt + # Add brew to the path - see https://github.com/actions/runner-images/issues/6283 + - name: Enable brew and helm-docs + run: | + echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + echo "HOMEBREW_PREFIX=$HOMEBREW_PREFIX" >>"${GITHUB_ENV}" + echo "HOMEBREW_CELLAR=$HOMEBREW_CELLAR" >>"${GITHUB_ENV}" + echo "HOMEBREW_REPOSITORY=$HOMEBREW_REPOSITORY" >>"${GITHUB_ENV}" + brew install norwoodj/tap/helm-docs - name: pre-commit run: pre-commit run --all-files @@ -97,8 +106,8 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - cache: 'pip' - cache-dependency-path: 'requirements/base.txt' + cache: "pip" + cache-dependency-path: "requirements/base.txt" - name: Install dependencies uses: ./.github/actions/cached-dependencies with: diff --git a/.github/workflows/superset-python-presto-hive.yml b/.github/workflows/superset-python-presto-hive.yml index 097b2f45adf9b..875901b1ec6d7 100644 --- a/.github/workflows/superset-python-presto-hive.yml +++ b/.github/workflows/superset-python-presto-hive.yml @@ -41,7 +41,7 @@ jobs: # GitHub action runner's default installations - 15433:8080 redis: - image: redis:5-alpine + image: redis:7-alpine ports: - 16379:6379 steps: @@ -110,7 +110,7 @@ jobs: # GitHub action runner's default installations - 15432:5432 redis: - image: redis:5-alpine + image: redis:7-alpine ports: - 16379:6379 steps: diff --git a/.github/workflows/superset-websocket.yml b/.github/workflows/superset-websocket.yml index 8a8dc9de2cac0..2f4b0aea04a06 100644 --- a/.github/workflows/superset-websocket.yml +++ b/.github/workflows/superset-websocket.yml @@ -18,7 +18,7 @@ jobs: persist-credentials: false - name: Install dependencies working-directory: ./superset-websocket - run: npm install + run: npm ci - name: lint working-directory: ./superset-websocket run: npm run lint diff --git a/.github/workflows/welcome-new-users.yml b/.github/workflows/welcome-new-users.yml index e55028af94461..ae16bf49c6490 100644 --- a/.github/workflows/welcome-new-users.yml +++ b/.github/workflows/welcome-new-users.yml @@ -8,18 +8,15 @@ jobs: welcome: runs-on: ubuntu-latest permissions: - issues: write + pull-requests: write steps: - name: Welcome Message - uses: actions/first-interaction@v1.0.0 + uses: actions/first-interaction@v1 + continue-on-error: true with: repo-token: ${{ secrets.GITHUB_TOKEN }} pr-message: |- Congrats on making your first PR and thank you for contributing to Superset! :tada: :heart: - We hope to see you in our [Slack](https://apache-superset.slack.com/) community too! - - name: First Time Label - uses: andymckay/labeler@master - with: - add-labels: "new:contributor" - repo-token: ${{ secrets.GITHUB_TOKEN }} + + We hope to see you in our [Slack](https://apache-superset.slack.com/) community too! Not signed up? Use our [Slack App](http://bit.ly/join-superset-slack) to self-register. diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000000000..dcc40721cea28 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,4 @@ +{ + "no-bare-urls": false, + "line-length": false +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b43e10c2cb784..aa0cf4af62d1a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ # repos: - repo: https://github.com/PyCQA/isort - rev: 5.9.3 + rev: 5.12.0 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-mypy @@ -49,11 +49,16 @@ repos: rev: v2.4.1 # Use the sha or tag you want to point at hooks: - id: prettier - args: ['--ignore-path=./superset-frontend/.prettierignore'] - files: 'superset-frontend' + args: ["--ignore-path=./superset-frontend/.prettierignore"] + files: "superset-frontend" # blacklist unsafe functions like make_url (see #19526) - repo: https://github.com/skorokithakis/blacklist-pre-commit-hook rev: e2f070289d8eddcaec0b580d3bde29437e7c8221 hooks: - id: blacklist args: ["--blacklisted-names=make_url", "--ignore=tests/"] + - repo: https://github.com/norwoodj/helm-docs + rev: v1.11.0 + hooks: + - id: helm-docs + files: helm diff --git a/.pylintrc b/.pylintrc index 8814957194bac..848767fe5dcb1 100644 --- a/.pylintrc +++ b/.pylintrc @@ -134,7 +134,9 @@ include-naming-hint=no # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty +property-classes= + abc.abstractproperty, + sqlalchemy.ext.hybrid.hybrid_property # Regular expression matching correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ @@ -303,7 +305,7 @@ ignored-modules=numpy,pandas,alembic.op,sqlalchemy,alembic.context,flask_appbuil # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of # qualified names. -ignored-classes=contextlib.closing,optparse.Values,thread._local,_thread._local,sqlalchemy.orm.scoping.scoped_session +ignored-classes=contextlib.closing,optparse.Values,thread._local,_thread._local # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular diff --git a/CHANGELOG.md b/CHANGELOG.md index b48fd53560b9a..31a7e33c07373 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -570,6 +570,625 @@ under the License. - [#19016](https://github.com/apache/superset/pull/19016) chore: Adding PR to Updating.md (@AAfghahi) - [#18970](https://github.com/apache/superset/pull/18970) chore: Change Dataset legacy editor flag to true (@AAfghahi) +- [2.0.1](#201-fri-nov-4-103402-2022--0400) +- [2.0.0](#200-tue-jun-28-085302-2022--0400) +- [1.5.3 (LTS)](#153-thu-jan-5-150544-2023--0500) +- [1.5.2](#152-wed-sep-14-171151-2022-0530) +- [1.5.1](#151-thu-may-26-144520-2022-0300) +- [1.5.0](#150-fri-apr-22-172330-2022--0400) +- [1.4.2](#142-sat-mar-19-000806-2022-0200) +- [1.4.1](#141) + +### 2.0.1 (Fri Nov 4 10:34:02 2022 -0400) + +**Database Migrations** + +**Features** + +**Fixes** + +- [#22417](https://github.com/apache/superset/pull/22417) fix: fix: Force configuration for SafeMarkdown component in Handlebars(@geido) +- [#21895](https://github.com/apache/superset/pull/21895) feat: Improves SafeMarkdown HTML sanitization (@michael-s-molina) (security-improvement) +- [#21874](https://github.com/apache/superset/pull/21874) feat: Adds a Content Security Policy (CSP) check for production environments (@michael-s-molina)(security-improvement) +- [#21853](https://github.com/apache/superset/pull/21853) feat: Disables HTML rendering in Toast by default (@michael-s-molina)(security-improvement) +- [#21776](https://github.com/apache/superset/pull/21776) fix(CustomFrame): Resolves issue #21731 where date range in explore throws runtime error (@eric-briscoe) +- [#21637](https://github.com/apache/superset/pull/21637) fix: respect chart cache timeout setting (@mayurnewase) +- [#21729](https://github.com/apache/superset/pull/21729) fix: allow adhoc columns in non-aggregate query (@mayurnewase) +- [#21441](https://github.com/apache/superset/pull/21441) fix(cache): respect default cache timeout on v1 chart data requests (@villebro) +- [#22038](https://github.com/apache/superset/pull/22038) fix: datasource save, improve data validation (@dpgaspar) +- [#22022](https://github.com/apache/superset/pull/22022) fix: deprecate approve and request_access endpoint (@dpgaspar) +- [#21964](https://github.com/apache/superset/pull/21964) fix: dashboard api cache decorator (@dpgaspar) +- [#21875](https://github.com/apache/superset/pull/21875) fix: check that imports are ZIPs (@betodealmeida) +- [#21761](https://github.com/apache/superset/pull/21761) fix: flash message on database data upload forms (@dpgaspar) +- [#21759](https://github.com/apache/superset/pull/21759) fix: database schema selector on import data (@dpgaspar) +- [#21729](https://github.com/apache/superset/pull/21729) fix: allow adhoc columns in non-aggregate query (@mayurnewase) +- [#21773](https://github.com/apache/superset/pull/21773) fix: remove deprecated ETagResponseMixin (@eschutho) +- [#21561](https://github.com/apache/superset/pull/21561) fix(report): Fix permission check for set up email report on charts/dashboards. Fixes #21559 (@zhaorui2022) +- [#20651](https://github.com/apache/superset/pull/20651) fix: annotation broken (@zhaoyongjie) +- [#20830](https://github.com/apache/superset/pull/20830) fix: remove element reference in alerts report fetchs (@hughhhh) +- [#20063](https://github.com/apache/superset/pull/20063) fix: Add locale for DatePicker component (@aehanno) +- [#21302](https://github.com/apache/superset/pull/21302) fix: disallow users from viewing other user's profile on config (@dpgaspar) +- [#21154](https://github.com/apache/superset/pull/21154) fix(explore): Prevent unnecessary series limit subquery (@codyml) +- [#21498](https://github.com/apache/superset/pull/21498) fix: set correct favicon from config for login and FAB list views (@mayurnewase) +- [#21380](https://github.com/apache/superset/pull/21380) fix(sqllab): Fix cursor alignment in SQL lab editor by avoiding Lucida Console font on Windows (@MichaelHintz) +- [#20061](https://github.com/apache/superset/pull/20061) fix: Add french translation missing (@aehanno) +- [#21044](https://github.com/apache/superset/pull/21044) fix(plugin-chart-echarts): missing value format in mixed timeseries (@justinpark) +- [#21419](https://github.com/apache/superset/pull/21419) fix: cached common bootstrap Revert (#21018) (@dpgaspar) +- [#21296](https://github.com/apache/superset/pull/21296) fix(plugin-chart-echarts): show zero value in tooltip (@villebro) +- [#21294](https://github.com/apache/superset/pull/21294) fix(explore): Time column label not formatted when GENERIC_X_AXES enabled (@kgabryje) +- [#21272](https://github.com/apache/superset/pull/21272) fix: adds TLS certificate validation option for SMTP (@dpgaspar) +- [#21076](https://github.com/apache/superset/pull/21076) fix(celery cache warmup): add auth and use warm_up_cache endpoint (@nytai) +- [#21216](https://github.com/apache/superset/pull/21216) fix(database-list): hide upload file button if no permission (@stephenLYZ) +- [#21153](https://github.com/apache/superset/pull/21153) fix(sqllab): missing zero values while copy-to-clipboard (@justinpark) +- [#21084](https://github.com/apache/superset/pull/21084) fix(native filters): groupby filter issue (@stevetracvc) +- [#21005](https://github.com/apache/superset/pull/21005) fix(plugin-chart-handlebars): Sort-By and Sort-By-Descending control not work (@stephenLYZ) +- [#20969](https://github.com/apache/superset/pull/20969) fix(dashboard): Fix scroll behaviour in DashboardBuilderSidepane (@EugeneTorap) +- [#21007](https://github.com/apache/superset/pull/21007) fix(plugin-chart-echarts): gauge chart enhancements and fixes (@stephenLYZ) +- [#21032](https://github.com/apache/superset/pull/21032) fix(plugin-chart-echarts): invalid total label location for negative values in stacked bar chart (@justinpark) +- [#20962](https://github.com/apache/superset/pull/20962) fix: Explore scrolled down when navigating from dashboard (@kgabryje) +- [#20946](https://github.com/apache/superset/pull/20946) fix(viz): Show zero percent changes in Big Number Viz (@Antonio-RiveroMartnez) +- [#20819](https://github.com/apache/superset/pull/20819) fix: Temporal X Axis values are not properly displayed if the time column has a custom label defined (@diegomedina248) +- [#20736](https://github.com/apache/superset/pull/20736) fix: getting default value in run-server.sh (@zhaoyongjie) +- [#20733](https://github.com/apache/superset/pull/20733) fix(docker): Make Gunicorn max_requests and max_requests_jitter adjustable (@mdeshmu) +- [#20714](https://github.com/apache/superset/pull/20714) fix: logger message (@betodealmeida) + +**Others** + +- [#21811](https://github.com/apache/superset/pull/21811) chore(sqla): refactor query utils (@villebro) +- [#21811](https://github.com/apache/superset/pull/21811) chore(sqla): refactor query utils (@villebro) +- [#20644](https://github.com/apache/superset/pull/20644) chore(deps): bump moment from 2.29.2 to 2.29.4 in /superset-frontend (@dependabot[bot]) +- [#21721](https://github.com/apache/superset/pull/21721) build: changelog for 2.0.1 (@AAfghahi) +- [#21018](https://github.com/apache/superset/pull/21018) perf: Memoize the common_bootstrap_payload (@bkyryliuk) +- [#21091](https://github.com/apache/superset/pull/21091) chore(deps): unpin holidays dependency version (@ecederstrand) + +### 2.0.0 (Tue Jun 28 08:53:02 2022 -0400) + +**Database Migrations** + +- [#20385](https://github.com/apache/superset/pull/20385) fix(migration): Ensure key_value LargeBinary is encoded as a MEDIUMBLOB as opposed to BLOB for MySQL (@john-bodley) +- [#20284](https://github.com/apache/superset/pull/20284) chore(migrations): Renaming migration files so that they're easier to keep track of (@craig-rueda) +- [#20108](https://github.com/apache/superset/pull/20108) fix: None dataset and schema permissions (@dpgaspar) +- [#18794](https://github.com/apache/superset/pull/18794) feat(business-types): initial implementation of SIP-78 (@cccs-RyanS) +- [#20073](https://github.com/apache/superset/pull/20073) fix(dataset): handle missing sqla uri in migration (@villebro) +- [#19941](https://github.com/apache/superset/pull/19941) fix(reports): Clear last value when state is WORKING (@john-bodley) +- [#19675](https://github.com/apache/superset/pull/19675) chore(docs): Spelling (@jsoref) +- [#19793](https://github.com/apache/superset/pull/19793) fix(SIP-68): handle empty table name during migration (@ktmud) +- [#19786](https://github.com/apache/superset/pull/19786) fix(migrations): coalesce is_temporal when inserting into sl_columns (@cemremengu) +- [#19421](https://github.com/apache/superset/pull/19421) perf: refactor SIP-68 db migrations with INSERT SELECT FROM (@ktmud) +- [#19767](https://github.com/apache/superset/pull/19767) fix: Fix migration for removing time_range_endpoints 3 (@hughhhh) +- [#19728](https://github.com/apache/superset/pull/19728) fix: Removetime_range_endpoints from query context object pt 2 (@hughhhh) +- [#19630](https://github.com/apache/superset/pull/19630) chore: clean up unused imports in db migration scripts (@ktmud) +- [#19577](https://github.com/apache/superset/pull/19577) fix: merge multiple db heads (@eschutho) +- [#19243](https://github.com/apache/superset/pull/19243) fix: cannot delete a database if team member has SQL editor tab that uses that db (@diegomedina248) +- [#19537](https://github.com/apache/superset/pull/19537) chore: block unsafe functions (@betodealmeida) +- [#19513](https://github.com/apache/superset/pull/19513) chore: postpone timerange endpoint removal (@villebro) +- [#19495](https://github.com/apache/superset/pull/19495) perf: speed up db migration for deprecating time_range_endpoints (@ktmud) +- [#19474](https://github.com/apache/superset/pull/19474) fix: handle null params in #18936 migration (@serenajiang) +- [#19423](https://github.com/apache/superset/pull/19423) fix: Remove`time_range_endpoints` from query context object (@hughhhh) +- [#18936](https://github.com/apache/superset/pull/18936) chore: Remove legacy SIP-15 interim logic/flags (@john-bodley) + +**Features** + +- [#20377](https://github.com/apache/superset/pull/20377) feat(standardized form data): keep all columns and metrics (@zhaoyongjie) +- [#20114](https://github.com/apache/superset/pull/20114) feat(chart): Enable caching per user when user impersonation is enabled (@Samira-El) +- [#20408](https://github.com/apache/superset/pull/20408) feat(plugin-chart-echarts): Support stacking negative and positive values (@kgabryje) +- [#20278](https://github.com/apache/superset/pull/20278) feat: Prevent dataset edit modal closing on click-away in edit mode (@reesercollins) +- [#20392](https://github.com/apache/superset/pull/20392) feat: setting limit value when Pie chart switches (@zhaoyongjie) +- [#20373](https://github.com/apache/superset/pull/20373) feat: adding truncate metric control on timeseries charts (@zhaoyongjie) +- [#20248](https://github.com/apache/superset/pull/20248) feat(explore): Implement viz switcher redesign (@kgabryje) +- [#20113](https://github.com/apache/superset/pull/20113) feat(api): Added "kind" to dataset/<pk> endpoint (@reesercollins) +- [#20299](https://github.com/apache/superset/pull/20299) feat(explore): Dataset Panel Options when Source = Query II (@lyndsiWilliams) +- [#20320](https://github.com/apache/superset/pull/20320) feat: Databricks native driver (@betodealmeida) +- [#20313](https://github.com/apache/superset/pull/20313) feat(explore): Denormalize form data in echarts, world map and nvd3 bar and line charts (@kgabryje) +- [#20277](https://github.com/apache/superset/pull/20277) feat: multiple results pane on explore and dashboard (@zhaoyongjie) +- [#19898](https://github.com/apache/superset/pull/19898) feat: When editing the label/title in the Metrics popover, hitting Enter should save what you've typed (@diegomedina248) +- [#16493](https://github.com/apache/superset/pull/16493) feat(plugin-chart-echarts): [feature-parity] support extra control for the area chart V2 (@stephenLYZ) +- [#19855](https://github.com/apache/superset/pull/19855) feat(explore): Frontend implementation of dataset creation from infobox (@lyndsiWilliams) +- [#20165](https://github.com/apache/superset/pull/20165) feat: add modfied col and timezone info to schedule col (@pkdotson) +- [#20144](https://github.com/apache/superset/pull/20144) feat: showing results pane in dashboard (@zhaoyongjie) +- [#20242](https://github.com/apache/superset/pull/20242) feat: derived metrics use different line style (@zhaoyongjie) +- [#20010](https://github.com/apache/superset/pull/20010) feat: standardized form_data (@zhaoyongjie) +- [#19987](https://github.com/apache/superset/pull/19987) feat(superset-ui-core): add feature flag for the analogous colors (@stephenLYZ) +- [#19881](https://github.com/apache/superset/pull/19881) feat(world-map): support color by metric or country column (@stephenLYZ) +- [#19981](https://github.com/apache/superset/pull/19981) feat!: pass datasource_type and datasource_id to form_data (@eschutho) +- [#15241](https://github.com/apache/superset/pull/15241) feat: query datasets from SQL Lab (@betodealmeida) +- [#20129](https://github.com/apache/superset/pull/20129) feat(explore): Fill dashboard name when adding new chart from dashboard view (@kgabryje) +- [#20160](https://github.com/apache/superset/pull/20160) feat(explore): Add empty state to annotations (@kgabryje) +- [#20134](https://github.com/apache/superset/pull/20134) feat: add Query.columns for bootstrap_data (@hughhhh) +- [#20158](https://github.com/apache/superset/pull/20158) feat: add statsd metrics for notifications (@dpgaspar) +- [#20052](https://github.com/apache/superset/pull/20052) feat(Helm Chart): Support resource limits and requests for each component (@rathberm) +- [#20170](https://github.com/apache/superset/pull/20170) feat: add samples endpoint (@zhaoyongjie) +- [#19381](https://github.com/apache/superset/pull/19381) feat: add drag and drop column rearrangement for table viz (@stevetracvc) +- [#20136](https://github.com/apache/superset/pull/20136) feat: Add Certified filter to Datasets (@hughhhh) +- [#20111](https://github.com/apache/superset/pull/20111) feat(dashboard): Chart title click redirects to Explore in new tab (@kgabryje) +- [#20097](https://github.com/apache/superset/pull/20097) feat(plugin-chart-echarts): add support for generic axis to mixed chart (@villebro) +- [#20126](https://github.com/apache/superset/pull/20126) feat(dashboard): Add create chart button in dashboard edit mode (@kgabryje) +- [#20059](https://github.com/apache/superset/pull/20059) feat: Save column data into json_metadata for all Query executions (@hughhhh) +- [#19918](https://github.com/apache/superset/pull/19918) feat(plugin-chart-echarts): support horizontal bar chart (@stephenLYZ) +- [#19902](https://github.com/apache/superset/pull/19902) feat: Explore popovers should close on escape (@diegomedina248) +- [#20049](https://github.com/apache/superset/pull/20049) feat(dashboard): Rearrange items in chart header controls dropdown (@kgabryje) +- [#20030](https://github.com/apache/superset/pull/20030) feat(sip-68): Add DatasourceDAO class to manage querying different datasources easier (@hughhhh) +- [#19581](https://github.com/apache/superset/pull/19581) feat(viz-gallery): add search weight for viz-name (@stephenLYZ) +- [#19999](https://github.com/apache/superset/pull/19999) feat: RLS for SQL Lab (@betodealmeida) +- [#19993](https://github.com/apache/superset/pull/19993) feat(explore): Show confirmation modal if user exits Explore without saving changes (@kgabryje) +- [#19873](https://github.com/apache/superset/pull/19873) feat(css): adds `chartId`-based class to dashboard chart holder (@rusackas) +- [#20002](https://github.com/apache/superset/pull/20002) feat: deprecate /superset/testconn and migrate to api v1 (@zephyring) +- [#19935](https://github.com/apache/superset/pull/19935) feat: deprecate /superset/validate_sql_json migrate to api v1 (@dpgaspar) +- [#20015](https://github.com/apache/superset/pull/20015) feat: add new enums for datasource types (@hughhhh) +- [#19956](https://github.com/apache/superset/pull/19956) feat: Applitools Cypress workflow (@geido) +- [#19852](https://github.com/apache/superset/pull/19852) feat: Run Applitools on public Storybook (@geido) +- [#19963](https://github.com/apache/superset/pull/19963) feat: Add cypress test for downloading chart as image (@codemaster08240328) +- [#19957](https://github.com/apache/superset/pull/19957) feat: switch from `sqlalchemy-trino` to `trino-python-client` (@dungdm93) +- [#19921](https://github.com/apache/superset/pull/19921) feat: deprecate /superset/extra_table_metadata migrate to api v1 (@dpgaspar) +- [#19745](https://github.com/apache/superset/pull/19745) feat: simplify SQLite time grain (@betodealmeida) +- [#19927](https://github.com/apache/superset/pull/19927) feat(chart & legend): make to enable show legend by default (@prosdev0107) +- [#19754](https://github.com/apache/superset/pull/19754) feat: deprecate old API on core superset fave_dashboards (@dpgaspar) +- [#19905](https://github.com/apache/superset/pull/19905) feat: simplify `memoized_func` (@betodealmeida) +- [#19871](https://github.com/apache/superset/pull/19871) feat(filter): make to hide sort filter when time range (@prosdev0107) +- [#19851](https://github.com/apache/superset/pull/19851) feat: add Advanced Analytics into mixed time series chart (@zhaoyongjie) +- [#19692](https://github.com/apache/superset/pull/19692) feat: Update ShortKey for stop query running in SqlLab editor (@codemaster08240328) +- [#17903](https://github.com/apache/superset/pull/17903) feat: Adds plugin-chart-handlebars (@jdbranham) +- [#19748](https://github.com/apache/superset/pull/19748) feat(explore): improve UI in the control panel (@stephenLYZ) +- [#19724](https://github.com/apache/superset/pull/19724) feat: 10/15/30 min grain to Pinot (@hughhhh) +- [#19696](https://github.com/apache/superset/pull/19696) feat(explore): Replace overlay with alert banner when chart controls change (@kgabryje) +- [#19751](https://github.com/apache/superset/pull/19751) feat(explore): Implement data panel redesign (@kgabryje) +- [#19598](https://github.com/apache/superset/pull/19598) feat: add empty states to sqlab editor and select (@pkdotson) +- [#19450](https://github.com/apache/superset/pull/19450) feat: Remove legacy sql alchemy db connection link from G Sheet connection (@codemaster08240328) +- [#19710](https://github.com/apache/superset/pull/19710) feat: Enabling source maps full time (@rusackas) +- [#19671](https://github.com/apache/superset/pull/19671) feat: UI override registry (@suddjian) +- [#19691](https://github.com/apache/superset/pull/19691) feat(explore): More explicit labels of adhoc filter operators (@kgabryje) +- [#19558](https://github.com/apache/superset/pull/19558) feat(explore): Redesign of Run/Save buttons (@kgabryje) +- [#19650](https://github.com/apache/superset/pull/19650) feat(embedded): API get embedded dashboard config by uuid (@lilykuang) +- [#19310](https://github.com/apache/superset/pull/19310) feat(CRUD): add new empty state (@stephenLYZ) +- [#19622](https://github.com/apache/superset/pull/19622) feat(plugin-chart-echarts): add aggregate total for the Pie/Donuct chart (@stephenLYZ) +- [#19314](https://github.com/apache/superset/pull/19314) feat: Move Database Import option into DB Connection modal (@lyndsiWilliams) +- [#19434](https://github.com/apache/superset/pull/19434) feat: deprecate old API and create new API for dashes created by me (@dpgaspar) +- [#19482](https://github.com/apache/superset/pull/19482) feat: add success toast to alerts and reports (@pkdotson) +- [#19574](https://github.com/apache/superset/pull/19574) feat: add a `where_in` filter for Jinja2 (@betodealmeida) +- [#19458](https://github.com/apache/superset/pull/19458) feat(explore): Move timer, row counter and cached pills to chart container (@kgabryje) +- [#19529](https://github.com/apache/superset/pull/19529) feat(explore): Move chart header to top of the page (@kgabryje) +- [#19489](https://github.com/apache/superset/pull/19489) feat(CI): clean up Python tests output (@ktmud) +- [#19308](https://github.com/apache/superset/pull/19308) feat(explore): SQL popover in datasource panel (@kgabryje) +- [#19325](https://github.com/apache/superset/pull/19325) feat(color): support analogous colors to prevent color conflict (@stephenLYZ) +- [#19408](https://github.com/apache/superset/pull/19408) feat(dashboard): Implement empty states for empty tabs (@kgabryje) +- [#19446](https://github.com/apache/superset/pull/19446) feat(explore): Move chart actions into dropdown (@kgabryje) +- [#19394](https://github.com/apache/superset/pull/19394) feat(explore): UI changes in dataset panel on Explore page (@kgabryje) + +**Fixes** + +- [#20382](https://github.com/apache/superset/pull/20382) fix: Allow dataset owners to explore their datasets (@reesercollins) +- [#20419](https://github.com/apache/superset/pull/20419) fix(embedded): Retry when executing alert queries to avoid sending transient errors to users as alert failure notifications (@zhaorui2022) +- [#20555](https://github.com/apache/superset/pull/20555) fix: Respecting max/min opacities, and adding tests. (@rusackas) +- [#20571](https://github.com/apache/superset/pull/20571) fix: Revert #20408 (stacking negative values in echarts bar chart) (@rusackas) +- [#20487](https://github.com/apache/superset/pull/20487) fix(database-modal): form in database model effects results of the database list (@stephenLYZ) +- [#20488](https://github.com/apache/superset/pull/20488) fix(big-number): big number gets cut off on a Dashboard (@stephenLYZ) +- [#16326](https://github.com/apache/superset/pull/16326) fix: SQL Lab cancel query in Redshift database connection does not wo… (@yourssvk) +- [#20362](https://github.com/apache/superset/pull/20362) fix: Unable to download the Dashboard as image in case there's an image added through Markdown (@diegomedina248) +- [#20543](https://github.com/apache/superset/pull/20543) fix: Removes psycopg2 as a required dependency +- [#20442](https://github.com/apache/superset/pull/20442) fix(db): Show the only db install guide when the db is already installed and error is existed while importing file. (@prosdev0107) +- [#20483](https://github.com/apache/superset/pull/20483) fix: bump FAB to 4.1.2 (@dpgaspar) +- [#20493](https://github.com/apache/superset/pull/20493) fix: correction from mmsql to mssql in setup.py (@mdeshmu) +- [#20460](https://github.com/apache/superset/pull/20460) fix: new column UUID conflicts in dual write (@eschutho) +- [#20485](https://github.com/apache/superset/pull/20485) fix: Re-add filter-box time granularity/column (@john-bodley) +- [#20480](https://github.com/apache/superset/pull/20480) fix(docs): prevent some symbols from being copied in docs (@stephenLYZ) +- [#19920](https://github.com/apache/superset/pull/19920) fix(table viz): correctly sort by multiple columns in a table (@stevetracvc) +- [#20402](https://github.com/apache/superset/pull/20402) fix: alert & reports active toggle optimistic update (@diegomedina248) +- [#20472](https://github.com/apache/superset/pull/20472) fix: Changes the return type of get_permissions to be JSON friendly (@michael-s-molina) +- [#20468](https://github.com/apache/superset/pull/20468) fix: async queries limit bug (@AAfghahi) +- [#20257](https://github.com/apache/superset/pull/20257) fix(home): Show home page tabs as pills instead of links (@prosdev0107) +- [#20340](https://github.com/apache/superset/pull/20340) fix: ensure column name in description is string (@betodealmeida) +- [#20350](https://github.com/apache/superset/pull/20350) fix(viz): BigQuery time grain 'minute'/'second' throws an error (@diegomedina248) +- [#20384](https://github.com/apache/superset/pull/20384) fix(chart & table): Prevent the dates from wrapping in table chart (@prosdev0107) +- [#20404](https://github.com/apache/superset/pull/20404) fix: suppress translation warning in jest (@zhaoyongjie) +- [#20451](https://github.com/apache/superset/pull/20451) fix: should raise exception when apply a categorical axis (@zhaoyongjie) +- [#20447](https://github.com/apache/superset/pull/20447) fix: table viz sort icon bottom aligned (@diegomedina248) +- [#20326](https://github.com/apache/superset/pull/20326) fix(fbprophet): Fix weekly frequencies (@john-bodley) +- [#20434](https://github.com/apache/superset/pull/20434) fix(20428): Address-Presto/Trino-Poll-Issue-Refactor (@Thelin90) +- [#20411](https://github.com/apache/superset/pull/20411) fix(dashboard): new created chart did not have high lighted effect when using the permalink of chart share in dashboard (@diegomedina248) +- [#20261](https://github.com/apache/superset/pull/20261) fix(embedded): CSV download for chart (@lilykuang) +- [#20276](https://github.com/apache/superset/pull/20276) fix(cosmetic): cannot find m-r-10 class in superset.less (@Renderz) +- [#20420](https://github.com/apache/superset/pull/20420) fix: rm eslint-plugin-translation-vars engines requirement (@stephenLYZ) +- [#20409](https://github.com/apache/superset/pull/20409) fix(bar-chart-v2): remove marker control from bar chart V2 (@stephenLYZ) +- [#20333](https://github.com/apache/superset/pull/20333) fix(presto): use milliseconds timespec for presto (@mohittt8) +- [#20414](https://github.com/apache/superset/pull/20414) fix: key error on permalink fetch for old permalinks (@eschutho) +- [#20410](https://github.com/apache/superset/pull/20410) fix: Adding extra metrics issue after chart configuration (@codemaster08240328) +- [#20405](https://github.com/apache/superset/pull/20405) fix: Incorrect translations in Chinese in messages.po (@chuancyzhang) +- [#20396](https://github.com/apache/superset/pull/20396) fix(plugin-chart-pivot-table): color weight of Conditional formatting metrics not work (@stephenLYZ) +- [#20361](https://github.com/apache/superset/pull/20361) fix(fonts): Show the all the A's in our workspace correctly, not funky (@prosdev0107) +- [#20383](https://github.com/apache/superset/pull/20383) fix: Unable to export multiple Dashboards with the same name (@diegomedina248) +- [#20363](https://github.com/apache/superset/pull/20363) fix: A newly connected database doesn't appear in the databases list if user connected database using the 'plus' button (@diegomedina248) +- [#20372](https://github.com/apache/superset/pull/20372) fix: update connection modal to use existing catalog (@pkdotson) +- [#20368](https://github.com/apache/superset/pull/20368) fix(VERSIONED_EXPORTS): Ensure dashboards and charts adhere to the VERSIONED_EXPORTS feature flag (@john-bodley) +- [#20351](https://github.com/apache/superset/pull/20351) fix: catch some potential errors on dual write (@eschutho) +- [#20364](https://github.com/apache/superset/pull/20364) fix: query execution time is not fully displayed in bubble icon (@diegomedina248) +- [#20365](https://github.com/apache/superset/pull/20365) fix: Fix typo in Error handling message (@codemaster08240328) +- [#19967](https://github.com/apache/superset/pull/19967) fix: A newly connected database doesn't appear in the databases list if user connected database using the 'plus' button (@diegomedina248) +- [#20348](https://github.com/apache/superset/pull/20348) fix(docker): Make Gunicorn Keepalive Adjustable (@mdeshmu) +- [#19670](https://github.com/apache/superset/pull/19670) fix: Add serviceAccountName to celerybeat pods (@paulinjo) +- [#20315](https://github.com/apache/superset/pull/20315) fix(chart): chart gets cut off on the dashboard (@stephenLYZ) +- [#20324](https://github.com/apache/superset/pull/20324) fix: superset-ui/core coverage (@zhaoyongjie) +- [#20282](https://github.com/apache/superset/pull/20282) fix(explore): Make that see more/see less works correctly with scrolling when error msg is long text. (@prosdev0107) +- [#20296](https://github.com/apache/superset/pull/20296) fix: Alpha are unable to perform a second modification to a Dataset when in Explore (@hughhhh) +- [#20290](https://github.com/apache/superset/pull/20290) fix: Faulty datetime parser regex (@reesercollins) +- [#19761](https://github.com/apache/superset/pull/19761) fix(plugin-chart-echarts): [feature-parity] apply button of annotation layer doesn't work as expected (@stephenLYZ) +- [#20263](https://github.com/apache/superset/pull/20263) fix(embedded): accessing variable response before initialization (@zhaorui2022) +- [#20274](https://github.com/apache/superset/pull/20274) fix(codecov): improve core code coverage (@stephenLYZ) +- [#20187](https://github.com/apache/superset/pull/20187) fix: Database import with cancel_query.. extra field (@codemaster08240328) +- [#20237](https://github.com/apache/superset/pull/20237) fix(cosmetic): Fix Datasource Modal Out Of Box (@Renderz) +- [#20058](https://github.com/apache/superset/pull/20058) fix: Support the Clipboard API in modern browsers (@diegomedina248) +- [#20164](https://github.com/apache/superset/pull/20164) fix(sql lab): View result button is not showing consistently (@diegomedina248) +- [#20171](https://github.com/apache/superset/pull/20171) fix(charts list): do not trigger ListViewError exception for anonymous user (@trepmag) +- [#20178](https://github.com/apache/superset/pull/20178) fix: While exporting CSV , only the entries on first page are getting downloaded even when user is on other pages #17861 (@LahmerIlyas) +- [#20204](https://github.com/apache/superset/pull/20204) fix: Fixes issue where results panel height was incorrect [sc-49045] (@eric-briscoe) +- [#20235](https://github.com/apache/superset/pull/20235) fix: Box Plot Chart throws an error when the average (AVG) / SUM is being calculated on the Metrics (@diegomedina248) +- [#20088](https://github.com/apache/superset/pull/20088) fix: datatype tracking issue on virtual dataset (@codemaster08240328) +- [#20220](https://github.com/apache/superset/pull/20220) fix: dashbaord unable to refresh (@zhaoyongjie) +- [#20228](https://github.com/apache/superset/pull/20228) fix: failed samples should throw exception (@zhaoyongjie) +- [#20203](https://github.com/apache/superset/pull/20203) fix: move columns to datasource object for bootstrap data (@hughhhh) +- [#20151](https://github.com/apache/superset/pull/20151) fix(csv): Ensure df_to_escaped_csv does not coerce integer columns to float (@john-bodley) +- [#20221](https://github.com/apache/superset/pull/20221) fix(legacy-plugin-chart-sunburst): linear color scheme not work when secondary metric is provided (@stephenLYZ) +- [#20223](https://github.com/apache/superset/pull/20223) fix(legacy-plugin-chart-sunburst): chart broken when secondary metric is removed (@stephenLYZ) +- [#20147](https://github.com/apache/superset/pull/20147) fix(cosmetic): Limiting modal height (@rusackas) +- [#20206](https://github.com/apache/superset/pull/20206) fix(sql lab): SQL Lab Compile Query Delay (@diegomedina248) +- [#20201](https://github.com/apache/superset/pull/20201) fix: unable to set destroyOnClose on ModalTrigger (@zhaoyongjie) +- [#20186](https://github.com/apache/superset/pull/20186) fix(db): make to allow to show/hide the password when only creating (@prosdev0107) +- [#20127](https://github.com/apache/superset/pull/20127) fix(database): retrival of tables and views from schema for exasol backend (@Nicoretti) +- [#19899](https://github.com/apache/superset/pull/19899) fix: always create parameter json field (@pkdotson) +- [#20173](https://github.com/apache/superset/pull/20173) fix: avoid while cycle in computeMaxFontSize for big Number run forever when css rule applied (@diegomedina248) +- [#20086](https://github.com/apache/superset/pull/20086) fix(css): transparent linear gradient not working in safari (@stephenLYZ) +- [#19102](https://github.com/apache/superset/pull/19102) fix: string aggregation is incorrect in PivotTableV2 (@diegomedina248) +- [#20011](https://github.com/apache/superset/pull/20011) fix(chart & heatmap): make to fix that y label is rendering out of bounds (@prosdev0107) +- [#20142](https://github.com/apache/superset/pull/20142) fix(explore): handle null control sections (@villebro) +- [#20128](https://github.com/apache/superset/pull/20128) fix: advanced data type API spec and permission name (@dpgaspar) +- [#20107](https://github.com/apache/superset/pull/20107) fix(generic-chart-axes): set x-axis if unset and ff is enabled (@villebro) +- [#20018](https://github.com/apache/superset/pull/20018) fix(modal): add primary button loading state to modals (@kgopal492) +- [#20099](https://github.com/apache/superset/pull/20099) fix: Add cypress test for report page direct link issue (@codemaster08240328) +- [#20068](https://github.com/apache/superset/pull/20068) fix: dbmodal test connection error timeout (@pkdotson) +- [#20092](https://github.com/apache/superset/pull/20092) fix: Revert "feat(explore): Show confirmation modal if user exits Explore without saving changes (#19993) (@kgabryje) +- [#19939](https://github.com/apache/superset/pull/19939) fix(chart & alert): make to show metrics properly (@prosdev0107) +- [#20085](https://github.com/apache/superset/pull/20085) fix: typo in `importexport/api.py` OpenAPI (@betodealmeida) +- [#20051](https://github.com/apache/superset/pull/20051) fix(CRUD): make to fix the dancing when crud view is on hover (@prosdev0107) +- [#20064](https://github.com/apache/superset/pull/20064) fix(chart & gallery): make to add mixed time-series into recommended charts (@prosdev0107) +- [#20013](https://github.com/apache/superset/pull/20013) fix: The dynamic form to connect to Snowflake DB is not returning any errors (@diegomedina248) +- [#20029](https://github.com/apache/superset/pull/20029) fix(plugin-chart-echarts): tooltip of big number truncated at then bottom (@stephenLYZ) +- [#19914](https://github.com/apache/superset/pull/19914) fix: Refactor SQL engine username logic (@john-bodley) +- [#20050](https://github.com/apache/superset/pull/20050) fix: Fixes Tabs style (@michael-s-molina) +- [#20048](https://github.com/apache/superset/pull/20048) fix(homepage): make to show indicator when tab is chosen (@prosdev0107) +- [#20026](https://github.com/apache/superset/pull/20026) fix(chart & filters): make to padding between textarea and buttons (@prosdev0107) +- [#20019](https://github.com/apache/superset/pull/20019) fix(embedded): third party cookies (@lilykuang) +- [#20033](https://github.com/apache/superset/pull/20033) fix: Direct Linking issue on report list: 404 status code. (@codemaster08240328) +- [#19977](https://github.com/apache/superset/pull/19977) fix(word-cloud): fix randomness of each word's rotation (@ebaratte) +- [#20021](https://github.com/apache/superset/pull/20021) fix: native filter truncation rerendering loop on hover (@diegomedina248) +- [#20004](https://github.com/apache/superset/pull/20004) fix: URI form is blank when trying to connect from sql lab (@diegomedina248) +- [#19841](https://github.com/apache/superset/pull/19841) fix: Table chart column config issue (@codemaster08240328) +- [#19877](https://github.com/apache/superset/pull/19877) fix: Making chart update more truthful (@Gwitchr) +- [#19996](https://github.com/apache/superset/pull/19996) fix: Use pull_request_target in Cypress Applitools workflow (@geido) +- [#19972](https://github.com/apache/superset/pull/19972) fix: revert chore(deps): bump d3-svg-legend in /superset-frontend (#19846) (@villebro) +- [#19889](https://github.com/apache/superset/pull/19889) fix: Fix auto-reversion of label/title in the Metrics popover (@diegomedina248) +- [#19903](https://github.com/apache/superset/pull/19903) fix(explore): Explore data table tooltip (@Gwitchr) +- [#19938](https://github.com/apache/superset/pull/19938) fix(chart & table): make to allow highlight in case of numeric column (@prosdev0107) +- [#19839](https://github.com/apache/superset/pull/19839) fix(dashboard): allow users to resize the markdown widget easier (@cccs-Dustin) +- [#19887](https://github.com/apache/superset/pull/19887) fix(hive): Workaround for Python 3.9 s3 transfer issue (@john-bodley) +- [#19936](https://github.com/apache/superset/pull/19936) fix: OpenAPI docs small fixes (@dpgaspar) +- [#19932](https://github.com/apache/superset/pull/19932) fix: can not correctly set force in store (@zhaoyongjie) +- [#19930](https://github.com/apache/superset/pull/19930) fix: memoize primitives (@betodealmeida) +- [#19926](https://github.com/apache/superset/pull/19926) fix(dataset): DAO update (@betodealmeida) +- [#19826](https://github.com/apache/superset/pull/19826) fix: Missing `f` prefix on f-strings (@code-review-doctor) +- [#18988](https://github.com/apache/superset/pull/18988) fix(column-header-tooltip): make that hide the tooltip when the cloum… (@prosdev0107) +- [#19782](https://github.com/apache/superset/pull/19782) fix: chart import error with virtual dataset (@codemaster08240328) +- [#19485](https://github.com/apache/superset/pull/19485) fix: Set fixed maxWidth of the cron schedule modal (@codemaster08240328) +- [#19885](https://github.com/apache/superset/pull/19885) fix: Chart download as image issue (@codemaster08240328) +- [#19883](https://github.com/apache/superset/pull/19883) fix(allow-db-explore): make to check the allow virtual table explore option by default (@prosdev0107) +- [#19835](https://github.com/apache/superset/pull/19835) fix(helm): fix postgresql values (@benjamin-texier) +- [#19758](https://github.com/apache/superset/pull/19758) fix(plugin-chart-echarts): [feature parity] annotation line chart color does not work (@stephenLYZ) +- [#19879](https://github.com/apache/superset/pull/19879) fix(plugin-chart-handlebars): fix overflow, debounce and control reset (@villebro) +- [#19668](https://github.com/apache/superset/pull/19668) fix: Dates alignment in Table viz (@geido) +- [#19876](https://github.com/apache/superset/pull/19876) fix: Cannot re-order metrics by drag and drop (@diegomedina248) +- [#19840](https://github.com/apache/superset/pull/19840) fix(dashboard-css): make to load saved css template (@prosdev0107) +- [#19859](https://github.com/apache/superset/pull/19859) fix: Dashboard report creation error handling (@etr2460) +- [#19857](https://github.com/apache/superset/pull/19857) fix: Update eslint error message to reflect location of antd components (@etr2460) +- [#19605](https://github.com/apache/superset/pull/19605) fix: Query execution time is displayed as invalid date (@diegomedina248) +- [#19694](https://github.com/apache/superset/pull/19694) fix(db & connection): make to show/hide the password when only creating db connection (@prosdev0107) +- [#19778](https://github.com/apache/superset/pull/19778) fix: deck.gl GeoJsonLayer Autozoom & fill/stroke options (@diegomedina248) +- [#19850](https://github.com/apache/superset/pull/19850) fix: Regression on Data and Alerts & Reports Headers (@diegomedina248) +- [#19842](https://github.com/apache/superset/pull/19842) fix: count(distinct column_name) in metrics (@zhaoyongjie) +- [#19843](https://github.com/apache/superset/pull/19843) fix(explore): ignore temporary controls in altered pill (@villebro) +- [#19800](https://github.com/apache/superset/pull/19800) fix: Cypress tests reliability improvements (@diegomedina248) +- [#19575](https://github.com/apache/superset/pull/19575) fix: Show full long number in text email report for table chart. (@codemaster08240328) +- [#19429](https://github.com/apache/superset/pull/19429) fix(dashboard): make to filter the correct certified or non-certified… (@prosdev0107) +- [#13082](https://github.com/apache/superset/pull/13082) fix(sql_lab): Add custom timestamp type for literal casting for presto timestamps (@kekwan) +- [#19797](https://github.com/apache/superset/pull/19797) fix: add missing init files (@suddjian) +- [#19672](https://github.com/apache/superset/pull/19672) fix: trap SQLAlchemy common exceptions & throw 422 error instead (@diegomedina248) +- [#19288](https://github.com/apache/superset/pull/19288) fix: AlertReportCronScheduler tests (@diegomedina248) +- [#19781](https://github.com/apache/superset/pull/19781) fix(world-map): remove categorical color control (@serenajiang) +- [#19792](https://github.com/apache/superset/pull/19792) fix(plugin-chart-table): Resetting controls when switching query mode (@kgabryje) +- [#19755](https://github.com/apache/superset/pull/19755) fix: small cleanup for created by me dashboards API (@dpgaspar) +- [#19784](https://github.com/apache/superset/pull/19784) fix(readme): Remove broken link to legacy gallery (@drluckyspin) +- [#19722](https://github.com/apache/superset/pull/19722) fix: dashboard top level tabs edit (@diegomedina248) +- [#19777](https://github.com/apache/superset/pull/19777) fix(explore): Double divider if no permissions for adding reports (@kgabryje) +- [#19673](https://github.com/apache/superset/pull/19673) fix(import): Add the error alert on failed database import (@prosdev0107) +- [#19518](https://github.com/apache/superset/pull/19518) fix: alert/report created by filter inconsistency with table display (@diegomedina248) +- [#19700](https://github.com/apache/superset/pull/19700) fix: remove expose (@AAfghahi) +- [#19626](https://github.com/apache/superset/pull/19626) fix: deactivate embedding on a dashboard (@suddjian) +- [#19472](https://github.com/apache/superset/pull/19472) fix: Dashboard Edit View Tab Headers Hidden when Dashboard Name is Long (@diegomedina248) +- [#19311](https://github.com/apache/superset/pull/19311) fix(sql lab): add quotes when autocompleting table names with spaces in the editor (@diegomedina248) +- [#19290](https://github.com/apache/superset/pull/19290) fix(sql lab): select edit on query from history doesn't upload editor properly (@diegomedina248) +- [#19420](https://github.com/apache/superset/pull/19420) fix: sql lab ctrl t behaved differently from clicking (@Gwitchr) +- [#19357](https://github.com/apache/superset/pull/19357) fix: Redirect to full url on 401 (@geido) +- [#19001](https://github.com/apache/superset/pull/19001) fix: Line Chart Annotation Info Update (@codemaster08240328) +- [#19714](https://github.com/apache/superset/pull/19714) fix: create virtual table with exotic type (@villebro) +- [#19708](https://github.com/apache/superset/pull/19708) fix(nav): infinite redirect and upload dataset nav permissions (@ktmud) +- [#19430](https://github.com/apache/superset/pull/19430) fix(data-upload): make to change err message (@prosdev0107) +- [#19419](https://github.com/apache/superset/pull/19419) fix(alert & report): make to fix the issue when recreate report (@prosdev0107) +- [#19371](https://github.com/apache/superset/pull/19371) fix: Reset sorting bar issue in Barchart (@codemaster08240328) +- [#19362](https://github.com/apache/superset/pull/19362) fix(sql lab): display the 'View Results' button consistently in the history tab on sync mode (@diegomedina248) +- [#19294](https://github.com/apache/superset/pull/19294) fix: improve alerts & reports modal on small devices (@diegomedina248) +- [#19257](https://github.com/apache/superset/pull/19257) fix(sql lab): table selector should display all the selected tables (@diegomedina248) +- [#19686](https://github.com/apache/superset/pull/19686) fix(plugin-chart-echarts): xAxis scale is not correct when time grain is quarter (@stephenLYZ) +- [#19646](https://github.com/apache/superset/pull/19646) fix(explore): Change copy of cross filters checkbox (@kgabryje) +- [#19586](https://github.com/apache/superset/pull/19586) fix: Navbar styles and Welcome page text (@geido) +- [#19662](https://github.com/apache/superset/pull/19662) fix(database-api): allow search for all columns (@villebro) +- [#19656](https://github.com/apache/superset/pull/19656) fix: allow_browser_login in import/export API (@betodealmeida) +- [#19628](https://github.com/apache/superset/pull/19628) fix: Table Autosizing Has Unnecessary Horizontal Scroll Bars (@diegomedina248) +- [#19573](https://github.com/apache/superset/pull/19573) fix(chart & polygon): make to fix the issue the polygon chart (@prosdev0107) +- [#19051](https://github.com/apache/superset/pull/19051) fix: update Permissions for right nav (@AAfghahi) +- [#19625](https://github.com/apache/superset/pull/19625) fix(test): make test_clean_requests_after_schema_grant more idempotent (@ktmud) +- [#19571](https://github.com/apache/superset/pull/19571) fix: Catch literal colors when theme top level (@geido) +- [#19594](https://github.com/apache/superset/pull/19594) fix: spelling of following (@lzm0) +- [#19569](https://github.com/apache/superset/pull/19569) fix: check type of url before performing string actions (@eschutho) +- [#19570](https://github.com/apache/superset/pull/19570) fix: sqloxide optional (@betodealmeida) +- [#19397](https://github.com/apache/superset/pull/19397) fix: weight tooltip issue (@codemaster08240328) +- [#19313](https://github.com/apache/superset/pull/19313) fix(sql lab): increase the size of the action icons in the history tab (@diegomedina248) +- [#19039](https://github.com/apache/superset/pull/19039) fix(explore): clean data when hidding control (@stephenLYZ) +- [#19444](https://github.com/apache/superset/pull/19444) fix: Error Message is cut off in alerts & reports log page (@codemaster08240328) +- [#19312](https://github.com/apache/superset/pull/19312) fix: adaptive formatting typo in explore dropdowns (@diegomedina248) +- [#19534](https://github.com/apache/superset/pull/19534) fix(explore): Chart header icon paddings (@kgabryje) +- [#19399](https://github.com/apache/superset/pull/19399) fix: native filter dropdown not attached to parent node (@diegomedina248) +- [#19112](https://github.com/apache/superset/pull/19112) fix: Dashboard import holding issue (@codemaster08240328) +- [#19342](https://github.com/apache/superset/pull/19342) fix: Clean up custom css when dashboard unmounted (@codemaster08240328) +- [#19491](https://github.com/apache/superset/pull/19491) fix: Dynamic form to connect to Snowflake DB is not displaying authentication errors (@diegomedina248) +- [#19528](https://github.com/apache/superset/pull/19528) fix: Correct Ukraine map (@wacken89) +- [#19522](https://github.com/apache/superset/pull/19522) fix: add back view for report reload error (@pkdotson) +- [#19519](https://github.com/apache/superset/pull/19519) fix: GSheets rendering from global nav (@hughhhh) +- [#19358](https://github.com/apache/superset/pull/19358) fix(sqllab): make to hide the delete button of most recent query history (@prosdev0107) +- [#19307](https://github.com/apache/superset/pull/19307) fix: Logo resizing on page load (@geido) +- [#19166](https://github.com/apache/superset/pull/19166) fix: time filter should be [start, end) (@zhaoyongjie) + +**Others** + +- [#20620](https://github.com/apache/superset/pull/20620) docs: fix link for Apache Superset source code (@dpgaspar) +- [#20621](https://github.com/apache/superset/pull/20621) chore: bump FAB to 4.1.3 (@dpgaspar) +- [#20486](https://github.com/apache/superset/pull/20486) chore: Updated copy in chart drop down to "View as table" (@lauderbaugh) +- [#20116](https://github.com/apache/superset/pull/20116) style(typo): occured -> occurred (@sfirke) +- [#20401](https://github.com/apache/superset/pull/20401) chore: add action to welcome new users (@eschutho) +- [#20269](https://github.com/apache/superset/pull/20269) chore(docs): Remove cache warming documentation (@ajwhite) +- [#20194](https://github.com/apache/superset/pull/20194) chore: Removes unused vars (@michael-s-molina) +- [#20321](https://github.com/apache/superset/pull/20321) chore: add breaking change information about form_data datasource_type (@eschutho) +- [#20298](https://github.com/apache/superset/pull/20298) chore: Removes no-use-before-define warnings (@michael-s-molina) +- [#20337](https://github.com/apache/superset/pull/20337) chore(dashboard): update Edit Dashboard side panel tabs (@codyml) +- [#20318](https://github.com/apache/superset/pull/20318) chore: Updates the final steps of the release README (@michael-s-molina) +- [#20307](https://github.com/apache/superset/pull/20307) docs: Updates CHANGELOG.md with 1.5.1 fixes (@michael-s-molina) +- [#20308](https://github.com/apache/superset/pull/20308) docs(jinja): Detail how to use Jinja parameters (@EBoisseauSierra) +- [#20304](https://github.com/apache/superset/pull/20304) chore: superset-ui/core code coverage (@zhaoyongjie) +- [#20297](https://github.com/apache/superset/pull/20297) chore(deps): pinning pyjwt to 2.4.0 (@sadpandajoe) +- [#20287](https://github.com/apache/superset/pull/20287) chore(deps): bump numpy 1.22.1 and PyJWT to 2.4.0 (@sadpandajoe) +- [#20272](https://github.com/apache/superset/pull/20272) chore: remove unused codes for samples (@zhaoyongjie) +- [#20289](https://github.com/apache/superset/pull/20289) chore: Adjusts release emails (@michael-s-molina) +- [#20180](https://github.com/apache/superset/pull/20180) docs: facelift the docs (@mistercrunch) +- [#20249](https://github.com/apache/superset/pull/20249) chore: add event logger to reports/alerts CRUD (@AAfghahi) +- [#20273](https://github.com/apache/superset/pull/20273) chore: adjust the psycopg2 version of k8s installation guide (@ensky) +- [#20152](https://github.com/apache/superset/pull/20152) refactor(trino): Handful of updates for the Trino engine (@john-bodley) +- [#20252](https://github.com/apache/superset/pull/20252) chore: use exc_info to pass errors to log warnings (@eschutho) +- [#20154](https://github.com/apache/superset/pull/20154) chore(requirements): Cleanup of Python requirements (@john-bodley) +- [#20226](https://github.com/apache/superset/pull/20226) refactor: decouple DataTableControl (@zhaoyongjie) +- [#20243](https://github.com/apache/superset/pull/20243) docs: Add beans to users list (@kakoni) +- [#20231](https://github.com/apache/superset/pull/20231) docs: Updates release scripts and docs (@michael-s-molina) +- [#20196](https://github.com/apache/superset/pull/20196) chore: bumping min version of shillelagh (@AAfghahi) +- [#20192](https://github.com/apache/superset/pull/20192) chore: Moves date utils to utils folder (@michael-s-molina) +- [#20210](https://github.com/apache/superset/pull/20210) docs: update release instructions (@villebro) +- [#20205](https://github.com/apache/superset/pull/20205) chore(deps): bump swagger-ui-react from 4.1.2 to 4.1.3 in /docs (@dependabot[bot]) +- [#20195](https://github.com/apache/superset/pull/20195) docs: correct case of ClickHouse (@DanRoscigno) +- [#20109](https://github.com/apache/superset/pull/20109) refactor: decouple DataTablesPane (@zhaoyongjie) +- [#20193](https://github.com/apache/superset/pull/20193) refactor: Removes embedded/index.tsx warnings (@michael-s-molina) +- [#20185](https://github.com/apache/superset/pull/20185) docs(security): a typo: Gamma should be in quotes (@jimmytheneutrino) +- [#20146](https://github.com/apache/superset/pull/20146) chore: Implement global header in Dashboard (@geido) +- [#20174](https://github.com/apache/superset/pull/20174) chore: Disable flaky assert in reports cypress test (@kgabryje) +- [#20163](https://github.com/apache/superset/pull/20163) chore: change button name in Sql Lab (@AAfghahi) +- [#20157](https://github.com/apache/superset/pull/20157) chore: filter undefined operators (@zhaoyongjie) +- [#20140](https://github.com/apache/superset/pull/20140) chore(data-table): make formatted dttm the default (@villebro) +- [#20104](https://github.com/apache/superset/pull/20104) chore: fix INTHEWILD sort order and indentation (@villebro) +- [#20093](https://github.com/apache/superset/pull/20093) chore: Add the tnum font property to Table components (@geido) +- [#20103](https://github.com/apache/superset/pull/20103) docs: Update INTHEWILD.md (@fccoelho) +- [#20102](https://github.com/apache/superset/pull/20102) chore: Update aiohttp to 3.8.1 (@diegomedina248) +- [#20066](https://github.com/apache/superset/pull/20066) chore: Set limit for a query in execute_sql_statement (@AAfghahi) +- [#20032](https://github.com/apache/superset/pull/20032) chore: Change copy to Edit chart in Dashboard dropdown (@geido) +- [#20071](https://github.com/apache/superset/pull/20071) chore: Fix and enhance Applitools workflows (@geido) +- [#19966](https://github.com/apache/superset/pull/19966) test: make tabbed dashboard a little more complex (@ktmud) +- [#19976](https://github.com/apache/superset/pull/19976) perf(plugin-chart-table): Add memoization to avoid rerenders (@kgabryje) +- [#20044](https://github.com/apache/superset/pull/20044) chore: Create a generic header component for Explore and Dashboard (@kgabryje) +- [#20046](https://github.com/apache/superset/pull/20046) docs: add changelog and updating entries for 1.5.0 (@villebro) +- [#19962](https://github.com/apache/superset/pull/19962) chore: add doc link for db migration conflict warning (@ktmud) +- [#20034](https://github.com/apache/superset/pull/20034) chore: Changes the no-literal-colors lint rule to throw errors instead of warnings (@michael-s-molina) +- [#20031](https://github.com/apache/superset/pull/20031) chore: Run Applitools + Cypress nightly (@geido) +- [#20006](https://github.com/apache/superset/pull/20006) chore: Removes hard-coded colors from the plugins - iteration 2 (@michael-s-molina) +- [#19130](https://github.com/apache/superset/pull/19130) refactor: Refactor reports for Charts and Dashboards (@AAfghahi) +- [#20016](https://github.com/apache/superset/pull/20016) chore: Removes hard-coded colors - iteration 3 (@michael-s-molina) +- [#19870](https://github.com/apache/superset/pull/19870) docs: Detail front-end development instructions (@EBoisseauSierra) +- [#19971](https://github.com/apache/superset/pull/19971) docs: Add config for running on a WSGI HTTP server (@thinhnd2104) +- [#20008](https://github.com/apache/superset/pull/20008) chore: Upgrades Storybook from 6.4.19 to 6.4.22 (@michael-s-molina) +- [#20009](https://github.com/apache/superset/pull/20009) docs: typo in chart-params markdown file (@JakobMiksch) +- [#19923](https://github.com/apache/superset/pull/19923) chore: Removes hard-coded colors from the plugins - iteration 1 (@michael-s-molina) +- [#19954](https://github.com/apache/superset/pull/19954) chore: convert URLShortLinkButton to typescript (@ktmud) +- [#19929](https://github.com/apache/superset/pull/19929) chore: change subject name from no_name to named for PNGs in (@AAfghahi) +- [#19942](https://github.com/apache/superset/pull/19942) refactor(ReportModal): simplify state reducer and improve error handling (@ktmud) +- [#19770](https://github.com/apache/superset/pull/19770) chore: remove druid datasource from the config (@eschutho) +- [#19911](https://github.com/apache/superset/pull/19911) chore: Fix broken link for DouroECI (@mavimo) +- [#19951](https://github.com/apache/superset/pull/19951) chore: Adds the theme object to chart properties (@michael-s-molina) +- [#19813](https://github.com/apache/superset/pull/19813) chore: get embedded user with roles and permissions (@suddjian) +- [#19897](https://github.com/apache/superset/pull/19897) chore: Adds a storybook to FilterableTable (@michael-s-molina) +- [#19924](https://github.com/apache/superset/pull/19924) chore(reports): Improving logging around failed scheduled reports (@craig-rueda) +- [#19906](https://github.com/apache/superset/pull/19906) revert: "fix(sql lab): display the 'View Results' button consistently in the history tab on sync mode" (@Gwitchr) +- [#19916](https://github.com/apache/superset/pull/19916) chore(deps): bump react-virtualized-auto-sizer from 1.0.2 to 1.0.6 in /superset-frontend (@dependabot[bot]) +- [#19888](https://github.com/apache/superset/pull/19888) chore(deps): bump cross-fetch from 3.1.4 to 3.1.5 in /docs (@dependabot[bot]) +- [#19894](https://github.com/apache/superset/pull/19894) chore(deps-dev): bump eslint-plugin-prettier from 3.3.1 to 4.0.0 in /superset-frontend (@dependabot[bot]) +- [#19602](https://github.com/apache/superset/pull/19602) docs: Added gtag to docusaurus (@AAfghahi) +- [#19878](https://github.com/apache/superset/pull/19878) chore(deps-dev): bump @storybook/client-api from 6.4.19 to 6.4.22 in /superset-frontend (@dependabot[bot]) +- [#19821](https://github.com/apache/superset/pull/19821) test(native filter): refactor and add new test (@jinghua-qa) +- [#19613](https://github.com/apache/superset/pull/19613) chore: Update line-height in SliceHeaderControl (@geido) +- [#19616](https://github.com/apache/superset/pull/19616) chore: Update font-sizes in DatabaseModal (@geido) +- [#19866](https://github.com/apache/superset/pull/19866) chore: fix explore pills (@villebro) +- [#19872](https://github.com/apache/superset/pull/19872) chore: Update aiohttp>=3.7.4 in requirements (@hughhhh) +- [#19874](https://github.com/apache/superset/pull/19874) chore: bump rockset>=0.8.10, <0.9 (@hughhhh) +- [#19864](https://github.com/apache/superset/pull/19864) chore(deps): bump react-syntax-highlighter from 15.4.5 to 15.5.0 in /superset-frontend (@dependabot[bot]) +- [#19828](https://github.com/apache/superset/pull/19828) chore: add custom eslint plugin to prevent translation variables (@stephenLYZ) +- [#19845](https://github.com/apache/superset/pull/19845) chore(deps): bump react-split from 2.0.9 to 2.0.14 in /superset-frontend (@dependabot[bot]) +- [#19846](https://github.com/apache/superset/pull/19846) chore(deps): bump d3-svg-legend from 1.13.0 to 2.25.6 in /superset-frontend (@dependabot[bot]) +- [#19847](https://github.com/apache/superset/pull/19847) chore(deps-dev): bump eslint-plugin-jsx-a11y from 6.4.1 to 6.5.1 in /superset-frontend (@dependabot[bot]) +- [#19853](https://github.com/apache/superset/pull/19853) chore(frontend-tests): Spelling (@jsoref) +- [#19823](https://github.com/apache/superset/pull/19823) docs: updated links for country map scripts (@ktmud) +- [#19829](https://github.com/apache/superset/pull/19829) chore(deps-dev): bump babel-loader from 8.2.4 to 8.2.5 in /superset-frontend (@dependabot[bot]) +- [#19830](https://github.com/apache/superset/pull/19830) chore(deps): bump react-hot-loader from 4.12.20 to 4.13.0 in /superset-frontend (@dependabot[bot]) +- [#19403](https://github.com/apache/superset/pull/19403) chore(deps-dev): bump babel-loader from 8.2.2 to 8.2.4 in /superset-frontend (@dependabot[bot]) +- [#19637](https://github.com/apache/superset/pull/19637) chore(deps): bump moment from 2.29.1 to 2.29.2 in /superset-frontend (@dependabot[bot]) +- [#19681](https://github.com/apache/superset/pull/19681) chore(deps): bump async from 3.2.0 to 3.2.3 in /superset-frontend/cypress-base (@dependabot[bot]) +- [#19680](https://github.com/apache/superset/pull/19680) chore(deps): bump async from 3.2.0 to 3.2.3 in /superset-websocket (@dependabot[bot]) +- [#19020](https://github.com/apache/superset/pull/19020) chore(deps): bump url-parse from 1.5.7 to 1.5.10 in /superset-frontend (@dependabot[bot]) +- [#17978](https://github.com/apache/superset/pull/17978) chore(deps): bump @types/d3-time from 1.1.1 to 3.0.0 in /superset-frontend (@dependabot[bot]) +- [#19727](https://github.com/apache/superset/pull/19727) chore(deps): bump async from 2.6.3 to 2.6.4 in /docs (@dependabot[bot]) +- [#19551](https://github.com/apache/superset/pull/19551) chore(deps): bump minimist from 1.2.5 to 1.2.6 in /superset-websocket (@dependabot[bot]) +- [#19165](https://github.com/apache/superset/pull/19165) chore: simplify error messaging in database modal (@pkdotson) +- [#19790](https://github.com/apache/superset/pull/19790) chore: bump postgres from 10 to 14 (@dpgaspar) +- [#19480](https://github.com/apache/superset/pull/19480) chore: Update UPDATING.md (@john-bodley) +- [#19740](https://github.com/apache/superset/pull/19740) chore: fix grammar error (@zhaoyongjie) +- [#19703](https://github.com/apache/superset/pull/19703) chore(build): upgrade less-loader (@ktmud) +- [#19736](https://github.com/apache/superset/pull/19736) chore: Updates the Select code owners (@michael-s-molina) +- [#19715](https://github.com/apache/superset/pull/19715) docs(install): ubuntu default-libmysqlclient-dev (@cemremengu) +- [#19726](https://github.com/apache/superset/pull/19726) chore: bumping shillelagh (@AAfghahi) +- [#19699](https://github.com/apache/superset/pull/19699) chore: fix typo (@betodealmeida) +- [#19674](https://github.com/apache/superset/pull/19674) chore: upgrade Pillow (@betodealmeida) +- [#19647](https://github.com/apache/superset/pull/19647) chore(explore): Change labels "Group by"/"Series" to "Dimensions" (@kgabryje) +- [#19679](https://github.com/apache/superset/pull/19679) chore(deps): bump urijs from 1.19.8 to 1.19.11 in /superset-frontend (@dependabot[bot]) +- [#19638](https://github.com/apache/superset/pull/19638) chore(deps): bump moment from 2.29.1 to 2.29.2 in /docs (@dependabot[bot]) +- [#19617](https://github.com/apache/superset/pull/19617) chore: updated two github issue templates (@srinify) +- [#19666](https://github.com/apache/superset/pull/19666) chore: Remove TwoTone icons (@geido) +- [#19614](https://github.com/apache/superset/pull/19614) chore: Remove wrong usage of font-size in ExploreViewContainer (@geido) +- [#19593](https://github.com/apache/superset/pull/19593) chore: Update font-sizes in ReportModal (@geido) +- [#19611](https://github.com/apache/superset/pull/19611) chore: Update font-sizes in ImportModal (@geido) +- [#19615](https://github.com/apache/superset/pull/19615) chore: Update font-sizes in AlertReportModal (@geido) +- [#19620](https://github.com/apache/superset/pull/19620) chore: Update font-sizes in QueryPreviewModal (@geido) +- [#19641](https://github.com/apache/superset/pull/19641) chore: clean up dynamic translation strings (@villebro) +- [#19635](https://github.com/apache/superset/pull/19635) refactor: consistent migration tests organization (@ktmud) +- [#19634](https://github.com/apache/superset/pull/19634) test: freeze time for dashboard export test (@ktmud) +- [#19606](https://github.com/apache/superset/pull/19606) test(jinja): refactor to functional tests (@villebro) +- [#19587](https://github.com/apache/superset/pull/19587) chore: cleanup as unknown conversion (@zhaoyongjie) +- [#19562](https://github.com/apache/superset/pull/19562) refactor: Removes the CSS files from the Horizon plugin (@michael-s-molina) +- [#19563](https://github.com/apache/superset/pull/19563) refactor: Removes the CSS files from the Paired T-Test plugin (@michael-s-molina) +- [#19539](https://github.com/apache/superset/pull/19539) refactor: Removes the CSS files from the Parallel Coordinates plugin (@michael-s-molina) +- [#19521](https://github.com/apache/superset/pull/19521) refactor: Removes the CSS files from the Partition plugin (@michael-s-molina) +- [#19493](https://github.com/apache/superset/pull/19493) chore: Removes hard-coded colors from legacy-plugin-chart-sankey (@michael-s-molina) +- [#19462](https://github.com/apache/superset/pull/19462) chore: Remove FilterBox.less (@geido) +- [#19438](https://github.com/apache/superset/pull/19438) chore: Remove crud.less from Datasource (@geido) +- [#19517](https://github.com/apache/superset/pull/19517) chore: Enhance ReactChord style with theme vars (@geido) +- [#19463](https://github.com/apache/superset/pull/19463) chore: Remove TimeTable.less (@geido) +- [#19550](https://github.com/apache/superset/pull/19550) chore(deps): bump minimist from 1.2.5 to 1.2.6 in /superset-embedded-sdk (@dependabot[bot]) +- [#19566](https://github.com/apache/superset/pull/19566) chore(deps): bump node-forge from 1.2.1 to 1.3.1 in /docs (@dependabot[bot]) +- [#19552](https://github.com/apache/superset/pull/19552) chore(deps): bump minimist from 1.2.5 to 1.2.6 in /docs (@dependabot[bot]) +- [#19549](https://github.com/apache/superset/pull/19549) chore(deps): bump minimist from 1.2.5 to 1.2.6 in /superset-frontend/cypress-base (@dependabot[bot]) +- [#19559](https://github.com/apache/superset/pull/19559) docs: update the typo in the documentation (@fatosmorina) +- [#19538](https://github.com/apache/superset/pull/19538) refactor: Removes the CSS files from the Country Map plugin (@michael-s-molina) +- [#19536](https://github.com/apache/superset/pull/19536) chore: Removes hard-coded opacity and spacing from the BigNumber plugin (@michael-s-molina) +- [#19494](https://github.com/apache/superset/pull/19494) refactor: Removes the CSS files from the Sankey Loop plugin (@michael-s-molina) +- [#19492](https://github.com/apache/superset/pull/19492) chore: Remove Legacy Force Directed viz plugin (@geido) +- [#19524](https://github.com/apache/superset/pull/19524) chore: Deprecating /my_queries endpoint (@AAfghahi) +- [#19467](https://github.com/apache/superset/pull/19467) chore(Explore): Change text when saving a chart in a new dashboard (@geido) +- [#19526](https://github.com/apache/superset/pull/19526) chore(database): Creating helper make_url_safe to wrap potential errors (@craig-rueda) +- [#19415](https://github.com/apache/superset/pull/19415) chore: Remove Control.less in Explore (@geido) +- [#19413](https://github.com/apache/superset/pull/19413) chore: Remove unused less file from profile (@geido) +- [#19460](https://github.com/apache/superset/pull/19460) chore: Switch to gender neutral terms (@inclusive-coding-bot) +- [#19486](https://github.com/apache/superset/pull/19486) refactor: Removes the CSS files from the Treemap plugin (@michael-s-molina) +- [#19488](https://github.com/apache/superset/pull/19488) refactor: Removes the CSS files from the Sunburst plugin (@michael-s-molina) +- [#19490](https://github.com/apache/superset/pull/19490) chore: Add theme color to ParallelCoordinates (@geido) +- [#19442](https://github.com/apache/superset/pull/19442) chore: Remove FilterbaleTableStyles.less (@geido) +- [#19441](https://github.com/apache/superset/pull/19441) chore: Remove StyledQueryButton.less (@geido) +- [#19473](https://github.com/apache/superset/pull/19473) refactor: Removes the CSS files from the Rose plugin (@michael-s-molina) +- [#19466](https://github.com/apache/superset/pull/19466) chore: Removes hard-coded colors from legacy-plugin-chart-world-map (@michael-s-molina) +- [#19465](https://github.com/apache/superset/pull/19465) refactor: Removes the CSS files from the DeckGL plugin (@michael-s-molina) +- [#19440](https://github.com/apache/superset/pull/19440) chore: Remove index.less from showSavedQuery (@geido) +- [#19230](https://github.com/apache/superset/pull/19230) chore!: remove `ROW_LEVEL_SECURITY` feature flag (permanently enable) (@suddjian) +- [#19361](https://github.com/apache/superset/pull/19361) chore: remove deprecated config keys and endpoints code 2.0 (@pkdotson) +- [#19261](https://github.com/apache/superset/pull/19261) chore: remove old alerts and configs keys (@pkdotson) +- [#19168](https://github.com/apache/superset/pull/19168) chore: bump celery and Flask (@dpgaspar) +- [#19049](https://github.com/apache/superset/pull/19049) chore: Remove logo forced width (@geido) +- [#19274](https://github.com/apache/superset/pull/19274) chore: remove PUBLIC_ROLE_LIKE_GAMMA deprecated config key (@dpgaspar) +- [#19273](https://github.com/apache/superset/pull/19273) chore: remove deprecated celery cli (@dpgaspar) +- [#19262](https://github.com/apache/superset/pull/19262) chore: update updating with druid no sql deprecation (@eschutho) +- [#19083](https://github.com/apache/superset/pull/19083) chore!: update mutator to take kwargs (@eschutho) +- [#19231](https://github.com/apache/superset/pull/19231) chore!: remove `ENABLE_REACT_CRUD_VIEWS` feature flag (permanently enable) (@suddjian) +- [#19241](https://github.com/apache/superset/pull/19241) chore(superset 2.0): remove front-end deprecated code (@graceguo-supercat) +- [#19107](https://github.com/apache/superset/pull/19107) chore: turn on SQLLAB_BACKEND_PERSISTENCE by default (@ktmud) +- [#19142](https://github.com/apache/superset/pull/19142) chore!: turn on Versioned Export in config.py (@AAfghahi) +- [#19108](https://github.com/apache/superset/pull/19108) chore: Update UPDATING.md with info about flipping dnd feature flag (@kgabryje) +- [#19146](https://github.com/apache/superset/pull/19146) chore!: Remove remove SQLALCHEMY_DOCS_URL and SQLALCHEMY_DISPLAY_TEXT from the config from the config (@hughhhh) +- [#19017](https://github.com/apache/superset/pull/19017) chore: Deprecate Python 3.7 (@john-bodley) +- [#19113](https://github.com/apache/superset/pull/19113) chore(config): Migrating `ENABLE_JAVASCRIPT_CONTROLS` from app config to a feature flag (@rusackas) +- [#19046](https://github.com/apache/superset/pull/19046) chore(explore): Set Drag&Drop feature flags to True by default (@kgabryje) +- [#19016](https://github.com/apache/superset/pull/19016) chore: Adding PR to Updating.md (@AAfghahi) +- [#18970](https://github.com/apache/superset/pull/18970) chore: Change Dataset legacy editor flag to true (@AAfghahi) + +### 1.5.3 (Thu Jan 5 15:05:44 2023 -0500) + +**Database Migrations** + +**Features** + +**Fixes** + +- [#21895](https://github.com/apache/superset/pull/21895) fix: Improves SafeMarkdown HTML sanitization (@michael-s-molina) +- [#21874](https://github.com/apache/superset/pull/21874) fix: Adds a Content Security Policy (CSP) check for production environments (@michael-s-molina) +- [#21853](https://github.com/apache/superset/pull/21853) fix: Disables HTML rendering in Toast by default (@michael-s-molina) +- [#22591](https://github.com/apache/superset/pull/22591) fix: Talisman configuration (@michael-s-molina) +- [#22196](https://github.com/apache/superset/pull/22196) fix(reports): force data generation in csv reports (@mayurnewase) +- [#22038](https://github.com/apache/superset/pull/22038) fix: datasource save, improve data validation (@dpgaspar) +- [#22022](https://github.com/apache/superset/pull/22022) fix: deprecate approve and request_access endpoint (@dpgaspar) +- [#21964](https://github.com/apache/superset/pull/21964) fix: dashboard api cache decorator (@dpgaspar) +- [#21875](https://github.com/apache/superset/pull/21875) fix: check that imports are ZIPs (@betodealmeida) +- [#21761](https://github.com/apache/superset/pull/21761) fix: flash message on database data upload forms (@dpgaspar) +- [#21759](https://github.com/apache/superset/pull/21759) fix: database schema selector on import data (@dpgaspar) +- [#21729](https://github.com/apache/superset/pull/21729) fix: allow adhoc columns in non-aggregate query (@mayurnewase) +- [#21216](https://github.com/apache/superset/pull/21216) fix(database-list): hide upload file button if no permission (@stephenLYZ) + +**Others** + +- [#21811](https://github.com/apache/superset/pull/21811) chore(sqla): refactor query utils (@villebro) + +### 1.5.2 (Wed Sep 14 17:11:51 2022 +0530) + +**Fixes** + +- [#21461](https://github.com/apache/superset/pull/21461) fix: dashboard filter value is cleared when 2 similar dashboards opened in succession (@mayurnewase) +- [#21419](https://github.com/apache/superset/pull/21419) fix: cached common bootstrap Revert (#21018) (@dpgaspar) +- [#21302](https://github.com/apache/superset/pull/21302) fix: disallow users from viewing other user's profile on config (@dpgaspar) +- [#21272](https://github.com/apache/superset/pull/21272) fix: adds TLS certificate validation option for SMTP (@dpgaspar) +- [#21076](https://github.com/apache/superset/pull/21076) fix(celery cache warmup): add auth and use warm_up_cache endpoint (@nytai) +- [#20178](https://github.com/apache/superset/pull/20178) fix: While exporting CSV , only the entries on first page are getting downloaded even when user is on other pages #17861 (@LahmerIlyas) +- [#20058](https://github.com/apache/superset/pull/20058) fix: Support the Clipboard API in modern browsers (@diegomedina248) +- [#20434](https://github.com/apache/superset/pull/20434) fix(20428): Address-Presto/Trino-Poll-Issue-Refactor (@Thelin90) +- [#20348](https://github.com/apache/superset/pull/20348) fix(docker): Make Gunicorn Keepalive Adjustable (@mdeshmu) +- [#20315](https://github.com/apache/superset/pull/20315) fix(chart): chart gets cut off on the dashboard (@stephenLYZ) +- [#20235](https://github.com/apache/superset/pull/20235) fix: Box Plot Chart throws an error when the average (AVG) / SUM is being calculated on the Metrics (@diegomedina248) +- [#20151](https://github.com/apache/superset/pull/20151) fix(csv): Ensure df_to_escaped_csv does not coerce integer columns to float (@john-bodley) +- [#20173](https://github.com/apache/superset/pull/20173) fix: avoid while cycle in computeMaxFontSize for big Number run forever when css rule applied (@diegomedina248) +- [#19570](https://github.com/apache/superset/pull/19570) fix: sqloxide optional (@betodealmeida) + +**Others** + +- [#21439](https://github.com/apache/superset/pull/21439) perf: Memoize the common_bootstrap_payload and include user param (#21018) (@bkyryliuk) +- [#19703](https://github.com/apache/superset/pull/19703) chore(build): upgrade less-loader (@ktmud) +- [#20550](https://github.com/apache/superset/pull/20550) chore: updating python docker image to 3.8.13 (@nisheldo) +- [#21018](https://github.com/apache/superset/pull/21018) perf: Memoize the common_bootstrap_payload (@bkyryliuk) +- [#20974](https://github.com/apache/superset/pull/20974) perf: Implement model specific lookups by id to improve performance (@bkyryliuk) +- [#20273](https://github.com/apache/superset/pull/20273) chore: adjust the psycopg2 version of k8s installation guide (@ensky) + ### 1.5.1 (Thu May 26 14:45:20 2022 +0300) **Fixes** diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index bee3a24a1e781..a328cf44d7706 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -106,7 +106,7 @@ This statement thanks the following, on which it draws for content and inspirati # Slack Community Guidelines -If you decide to join the [Community Slack](https://join.slack.com/t/apache-superset/shared_invite/zt-16jvzmoi8-sI7jKWp~xc2zYRe~NqiY9Q), please adhere to the following rules: +If you decide to join the [Community Slack](http://bit.ly/join-superset-slack), please adhere to the following rules: **1. Treat everyone in the community with respect.** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 653cfe41a5f0c..c8f72d2b22b6a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,7 +52,9 @@ little bit helps, and credit will always be given. - [Revert Guidelines](#revert-guidelines) - [Setup Local Environment for Development](#setup-local-environment-for-development) - [Documentation](#documentation) - - [Images](#images) + - [Local Development](#local-development) + - [Build](#build) + - [Deployment](#deployment) - [Flask server](#flask-server) - [OS Dependencies](#os-dependencies) - [Dependencies](#dependencies) @@ -124,7 +126,7 @@ Here's a list of repositories that contain Superset-related packages: ## Types of Contributions -### Report Bug +### Report a Bug The best way to report a bug is to file an issue on GitHub. Please include: @@ -136,15 +138,17 @@ The best way to report a bug is to file an issue on GitHub. Please include: When posting Python stack traces, please quote them using [Markdown blocks](https://help.github.com/articles/creating-and-highlighting-code-blocks/). +_Please note that feature requests opened as Github Issues will be moved to Discussions._ + ### Submit Ideas or Feature Requests -The best way is to file an issue on GitHub: +The best way is to start an ["Ideas" Discussion thread](https://github.com/apache/superset/discussions/categories/ideas) on GitHub: - Explain in detail how it would work. - Keep the scope as narrow as possible, to make it easier to implement. -- Remember that this is a volunteer-driven project, and that contributions are welcome :) +- Remember that this is a volunteer-driven project, and that your contributions are as welcome as anyone's :) -For large features or major changes to codebase, please create **Superset Improvement Proposal (SIP)**. See template from [SIP-0](https://github.com/apache/superset/issues/5602) +To propose large features or major changes to codebase, and help usher in those changes, please create a **Superset Improvement Proposal (SIP)**. See template from [SIP-0](https://github.com/apache/superset/issues/5602) ### Fix Bugs @@ -160,7 +164,7 @@ Look through the GitHub issues. Issues tagged with Superset could always use better documentation, whether as part of the official Superset docs, -in docstrings, `docs/*.rst` or even on the web as blog posts or +in docstrings, or even on the web as blog posts or articles. See [Documentation](#documentation) for more details. ### Add Translations @@ -388,23 +392,30 @@ cd superset The latest documentation and tutorial are available at https://superset.apache.org/. -The site is written using the Gatsby framework and docz for the -documentation subsection. Find out more about it in `docs/README.md` +The documentation site is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator, the source for which resides in `./docs`. + +#### Local Development -#### Images +To set up a local development environment with hot reloading for the documentation site: -If you're adding new images to the documentation, you'll notice that the images -referenced in the rst, e.g. +```shell +cd docs +yarn install # Installs NPM dependencies +yarn start # Starts development server at http://localhost:3000 +``` - .. image:: _static/images/tutorial/tutorial_01_sources_database.png +#### Build -aren't actually stored in that directory. Instead, you should add and commit -images (and any other static assets) to the `superset-frontend/src/assets/images` directory. -When the docs are deployed to https://superset.apache.org/, images -are copied from there to the `_static/images` directory, just like they're referenced -in the docs. +To create and serve a production build of the documentation site: -For example, the image referenced above actually lives in `superset-frontend/src/assets/images/tutorial`. Since the image is moved during the documentation build process, the docs reference the image in `_static/images/tutorial` instead. +```shell +yarn build +yarn serve +``` + +#### Deployment + +Commits to `master` trigger a rebuild and redeploy of the documentation site. Submit pull requests that modify the documentation with the `docs:` prefix. ### Flask server @@ -413,7 +424,7 @@ For example, the image referenced above actually lives in `superset-frontend/src Make sure your machine meets the [OS dependencies](https://superset.apache.org/docs/installation/installing-superset-from-scratch#os-dependencies) before following these steps. You also need to install MySQL or [MariaDB](https://mariadb.com/downloads). -Ensure that you are using Python version 3.7 or 3.8, then proceed with: +Ensure that you are using Python version 3.8, 3.9, 3.10 or 3.11, then proceed with: ```bash # Create a virtual environment and activate it (recommended) @@ -1021,7 +1032,7 @@ When contributing new React components to Superset, please try to add a Story al ## Translating -We use [Babel](http://babel.pocoo.org/en/latest/) to translate Superset. +We use [Flask-Babel](https://python-babel.github.io/flask-babel/) to translate Superset. In Python files, we import the magic `_` function using: ```python @@ -1064,6 +1075,7 @@ LANGUAGES = { ``` This script will + 1. update the template file `superset/translations/messages.pot` with current application strings. 2. update language files with the new extracted strings. @@ -1285,7 +1297,7 @@ To do this, you'll need to: - Start up a celery worker ```shell script - celery --app=superset.tasks.celery_app:app worker -Ofair + celery --app=superset.tasks.celery_app:app worker -O fair ``` Note that: @@ -1315,6 +1327,7 @@ The following configuration settings are available for async queries (see config - `GLOBAL_ASYNC_QUERIES_REDIS_STREAM_LIMIT_FIREHOSE` - the maximum number of events for all users (FIFO eviction) - `GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME` - the async query feature uses a [JWT](https://tools.ietf.org/html/rfc7519) cookie for authentication, this setting is the cookie's name - `GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE` - JWT cookie secure option +- `GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE` - JWT cookie same site option - `GLOBAL_ASYNC_QUERIES_JWT_COOKIE_DOMAIN` - JWT cookie domain option ([see docs for set_cookie](https://tedboy.github.io/flask/interface_api.response_object.html#flask.Response.set_cookie)) - `GLOBAL_ASYNC_QUERIES_JWT_SECRET` - JWT's use a secret key to sign and validate the contents. This value should be at least 32 bytes and have sufficient randomness for proper security - `GLOBAL_ASYNC_QUERIES_TRANSPORT` - available options: "polling" (HTTP, default), "ws" (WebSocket, requires running superset-websocket server) diff --git a/Dockerfile b/Dockerfile index ae390f596cb98..48612a14e9604 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,65 +16,35 @@ # limitations under the License. # -###################################################################### -# PY stage that simply does a pip install on our requirements -###################################################################### - - -ARG PY_VER=3.8.12 -FROM python:${PY_VER} AS superset-py - -RUN mkdir /app \ - && apt-get update -y \ - && apt-get install -y --no-install-recommends \ - build-essential \ - default-libmysqlclient-dev \ - libpq-dev \ - libsasl2-dev \ - libecpg-dev \ - && rm -rf /var/lib/apt/lists/* - -# First, we just wanna install requirements, which will allow us to utilize the cache -# in order to only build if and only if requirements change -COPY ./requirements/*.txt /app/requirements/ -COPY setup.py MANIFEST.in README.md /app/ -COPY superset-frontend/package.json /app/superset-frontend/ -RUN cd /app \ - && mkdir -p superset/static \ - && touch superset/static/version_info.json \ - && pip install --no-cache -r requirements/local.txt - - ###################################################################### # Node stage to deal with static asset construction ###################################################################### -FROM node:16 AS superset-node - -ARG NPM_VER=7 -RUN npm install -g npm@${NPM_VER} +ARG PY_VER=3.8.16-slim +FROM node:16-slim AS superset-node ARG NPM_BUILD_CMD="build" ENV BUILD_CMD=${NPM_BUILD_CMD} +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true # NPM ci first, as to NOT invalidate previous steps except for when package.json changes RUN mkdir -p /app/superset-frontend -RUN mkdir -p /app/superset/assets + COPY ./docker/frontend-mem-nag.sh / -COPY ./superset-frontend /app/superset-frontend -RUN /frontend-mem-nag.sh \ - && cd /app/superset-frontend \ - && npm ci --legacy-peer-deps +RUN /frontend-mem-nag.sh -# This seems to be the most expensive step -RUN cd /app/superset-frontend \ - && npm run ${BUILD_CMD} \ - && rm -rf node_modules +WORKDIR /app/superset-frontend/ + +COPY superset-frontend/package*.json ./ +RUN npm ci --legacy-peer-deps +COPY ./superset-frontend . + +# This seems to be the most expensive step +RUN npm run ${BUILD_CMD} ###################################################################### # Final lean image... ###################################################################### -ARG PY_VER=3.8.12 FROM python:${PY_VER} AS lean ENV LANG=C.UTF-8 \ @@ -90,17 +60,26 @@ RUN mkdir -p ${PYTHONPATH} \ && apt-get update -y \ && apt-get install -y --no-install-recommends \ build-essential \ + curl \ default-libmysqlclient-dev \ + libsasl2-dev \ libsasl2-modules-gssapi-mit \ libpq-dev \ libecpg-dev \ && rm -rf /var/lib/apt/lists/* -COPY --from=superset-py /usr/local/lib/python3.8/site-packages/ /usr/local/lib/python3.8/site-packages/ -# Copying site-packages doesn't move the CLIs, so let's copy them one by one -COPY --from=superset-py /usr/local/bin/gunicorn /usr/local/bin/celery /usr/local/bin/flask /usr/bin/ +COPY ./requirements/*.txt /app/requirements/ +COPY setup.py MANIFEST.in README.md /app/ + +# setup.py uses the version information in package.json +COPY superset-frontend/package.json /app/superset-frontend/ + +RUN cd /app \ + && mkdir -p superset/static \ + && touch superset/static/version_info.json \ + && pip install --no-cache -r requirements/local.txt + COPY --from=superset-node /app/superset/static/assets /app/superset/static/assets -COPY --from=superset-node /app/superset-frontend /app/superset-frontend ## Lastly, let's install superset itself COPY superset /app/superset @@ -128,15 +107,15 @@ CMD /usr/bin/run-server.sh # Dev image... ###################################################################### FROM lean AS dev -ARG GECKODRIVER_VERSION=v0.28.0 -ARG FIREFOX_VERSION=88.0 +ARG GECKODRIVER_VERSION=v0.32.0 +ARG FIREFOX_VERSION=106.0.3 COPY ./requirements/*.txt ./docker/requirements-*.txt/ /app/requirements/ USER root RUN apt-get update -y \ - && apt-get install -y --no-install-recommends libnss3 libdbus-glib-1-2 libgtk-3-0 libx11-xcb1 + && apt-get install -y --no-install-recommends libnss3 libdbus-glib-1-2 libgtk-3-0 libx11-xcb1 wget # Install GeckoDriver WebDriver RUN wget https://github.com/mozilla/geckodriver/releases/download/${GECKODRIVER_VERSION}/geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz -O /tmp/geckodriver.tar.gz && \ diff --git a/Makefile b/Makefile index 8dc7ffa8f569e..fbe0fc8bfcb17 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,8 @@ # limitations under the License. # -# Python version installed; we need 3.8-3.9 -PYTHON=`command -v python3.9 || command -v python3.8` +# Python version installed; we need 3.8-3.11 +PYTHON=`command -v python3.11 || command -v python3.10 || command -v python3.9 || command -v python3.8` .PHONY: install superset venv pre-commit @@ -47,7 +47,7 @@ superset: superset load-examples # Install node packages - cd superset-frontend; npm install + cd superset-frontend; npm ci update: update-py update-js @@ -70,7 +70,7 @@ update-js: venv: # Create a virtual environment and activate it (recommended) - if ! [ -x "${PYTHON}" ]; then echo "You need Python 3.8 or 3.9 installed"; exit 1; fi + if ! [ -x "${PYTHON}" ]; then echo "You need Python 3.8, 3.9, 3.10 or 3.11 installed"; exit 1; fi test -d venv || ${PYTHON} -m venv venv # setup a python3 virtualenv . venv/bin/activate @@ -101,11 +101,17 @@ node-app: build-cypress: cd superset-frontend; npm run build-instrumented - cd superset-frontend/cypress-base; npm install + cd superset-frontend/cypress-base; npm ci open-cypress: if ! [ $(port) ]; then cd superset-frontend/cypress-base; CYPRESS_BASE_URL=http://localhost:9000 npm run cypress open; fi cd superset-frontend/cypress-base; CYPRESS_BASE_URL=http://localhost:$(port) npm run cypress open +report-celery-worker: + celery --app=superset.tasks.celery_app:app worker + +report-celery-beat: + celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid --schedule /tmp/celerybeat-schedulecd + admin-user: superset fab create-admin diff --git a/README.md b/README.md index 5bea6eed78ba0..ce805862878c4 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ under the License. [![PyPI version](https://badge.fury.io/py/apache-superset.svg)](https://badge.fury.io/py/apache-superset) [![Coverage Status](https://codecov.io/github/apache/superset/coverage.svg?branch=master)](https://codecov.io/github/apache/superset) [![PyPI](https://img.shields.io/pypi/pyversions/apache-superset.svg?maxAge=2592000)](https://pypi.python.org/pypi/apache-superset) -[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://join.slack.com/t/apache-superset/shared_invite/zt-16jvzmoi8-sI7jKWp~xc2zYRe~NqiY9Q) +[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](http://bit.ly/join-superset-slack) [![Documentation](https://img.shields.io/badge/docs-apache.org-blue.svg)](https://superset.apache.org) <img @@ -86,39 +86,39 @@ Superset can query data from any SQL-speaking datastore or data engine (Presto, Here are some of the major database solutions that are supported: <p align="center"> - <img src="superset-frontend/src/assets/images/redshift.png" alt="redshift" border="0" width="106" height="41"/> - <img src="superset-frontend/src/assets/images/google-biquery.png" alt="google-biquery" border="0" width="114" height="43"/> - <img src="superset-frontend/src/assets/images/snowflake.png" alt="snowflake" border="0" width="152" height="46"/> - <img src="superset-frontend/src/assets/images/trino.png" alt="trino" border="0" width="46" height="46"/> - <img src="superset-frontend/src/assets/images/presto.png" alt="presto" border="0" width="152" height="46"/> - <img src="superset-frontend/src/assets/images/druid.png" alt="druid" border="0" width="135" height="37" /> - <img src="superset-frontend/src/assets/images/firebolt.png" alt="firebolt" border="0" width="133" height="21.5" /> - <img src="superset-frontend/src/assets/images/timescale.png" alt="timescale" border="0" width="102" height="26.8" /> - <img src="superset-frontend/src/assets/images/rockset.png" alt="rockset" border="0" width="125" height="51" /> - <img src="superset-frontend/src/assets/images/postgresql.png" alt="postgresql" border="0" width="132" height="81" /> - <img src="superset-frontend/src/assets/images/mysql.png" alt="mysql" border="0" width="119" height="62" /> - <img src="superset-frontend/src/assets/images/mssql-server.png" alt="mssql-server" border="0" width="93" height="74" /> - <img src="superset-frontend/src/assets/images/db2.png" alt="db2" border="0" width="62" height="62" /> - <img src="superset-frontend/src/assets/images/sqlite.png" alt="sqlite" border="0" width="102" height="45" /> - <img src="superset-frontend/src/assets/images/sybase.png" alt="sybase" border="0" width="128" height="47" /> - <img src="superset-frontend/src/assets/images/mariadb.png" alt="mariadb" border="0" width="83" height="63" /> - <img src="superset-frontend/src/assets/images/vertica.png" alt="vertica" border="0" width="128" height="40" /> - <img src="superset-frontend/src/assets/images/oracle.png" alt="oracle" border="0" width="121" height="66" /> - <img src="superset-frontend/src/assets/images/firebird.png" alt="firebird" border="0" width="86" height="56" /> - <img src="superset-frontend/src/assets/images/greenplum.png" alt="greenplum" border="0" width="140" height="45" /> - <img src="superset-frontend/src/assets/images/clickhouse.png" alt="clickhouse" border="0" width="133" height="34" /> - <img src="superset-frontend/src/assets/images/exasol.png" alt="exasol" border="0" width="106" height="59" /> - <img src="superset-frontend/src/assets/images/monet-db.png" alt="monet-db" border="0" width="106" height="46" /> - <img src="superset-frontend/src/assets/images/apache-kylin.png" alt="apache-kylin" border="0" width="56" height="64"/> - <img src="superset-frontend/src/assets/images/hologres.png" alt="hologres" border="0" width="71" height="64"/> - <img src="superset-frontend/src/assets/images/netezza.png" alt="netezza" border="0" width="64" height="64"/> - <img src="superset-frontend/src/assets/images/pinot.png" alt="pinot" border="0" width="165" height="64"/> - <img src="superset-frontend/src/assets/images/teradata.png" alt="teradata" border="0" width="165" height="64"/> - <img src="superset-frontend/src/assets/images/yugabyte.png" alt="yugabyte" border="0" width="180" height="31"/> + <img src="superset-frontend/src/assets/images/redshift.png" alt="redshift" border="0" width="200" height="80"/> + <img src="superset-frontend/src/assets/images/google-biquery.png" alt="google-biquery" border="0" width="200" height="80"/> + <img src="superset-frontend/src/assets/images/snowflake.png" alt="snowflake" border="0" width="200" height="80"/> + <img src="superset-frontend/src/assets/images/trino.png" alt="trino" border="0" width="200" height="80"/> + <img src="superset-frontend/src/assets/images/presto.png" alt="presto" border="0" width="200" height="80"/> + <img src="superset-frontend/src/assets/images/databricks.png" alt="databricks" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/druid.png" alt="druid" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/firebolt.png" alt="firebolt" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/timescale.png" alt="timescale" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/rockset.png" alt="rockset" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/postgresql.png" alt="postgresql" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/mysql.png" alt="mysql" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/mssql-server.png" alt="mssql-server" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/db2.png" alt="db2" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/sqlite.png" alt="sqlite" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/sybase.png" alt="sybase" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/mariadb.png" alt="mariadb" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/vertica.png" alt="vertica" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/oracle.png" alt="oracle" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/firebird.png" alt="firebird" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/greenplum.png" alt="greenplum" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/clickhouse.png" alt="clickhouse" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/exasol.png" alt="exasol" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/monet-db.png" alt="monet-db" border="0" width="200" height="80" /> + <img src="superset-frontend/src/assets/images/apache-kylin.png" alt="apache-kylin" border="0" width="200" height="80"/> + <img src="superset-frontend/src/assets/images/hologres.png" alt="hologres" border="0" width="200" height="80"/> + <img src="superset-frontend/src/assets/images/netezza.png" alt="netezza" border="0" width="200" height="80"/> + <img src="superset-frontend/src/assets/images/pinot.png" alt="pinot" border="0" width="200" height="80"/> + <img src="superset-frontend/src/assets/images/teradata.png" alt="teradata" border="0" width="200" height="80"/> + <img src="superset-frontend/src/assets/images/yugabyte.png" alt="yugabyte" border="0" width="200" height="80"/> </p> -**A more comprehensive list of supported databases** along with the configuration instructions can be found -[here](https://superset.apache.org/docs/databases/installing-database-drivers). +**A more comprehensive list of supported databases** along with the configuration instructions can be found [here](https://superset.apache.org/docs/databases/installing-database-drivers). Want to add support for your datastore or data engine? Read more [here](https://superset.apache.org/docs/frequently-asked-questions#does-superset-work-with-insert-database-engine-here) about the technical requirements. @@ -129,7 +129,7 @@ Want to add support for your datastore or data engine? Read more [here](https:// ## Get Involved - Ask and answer questions on [StackOverflow](https://stackoverflow.com/questions/tagged/apache-superset) using the **apache-superset** tag -- [Join our community's Slack](https://join.slack.com/t/apache-superset/shared_invite/zt-16jvzmoi8-sI7jKWp~xc2zYRe~NqiY9Q) +- [Join our community's Slack](http://bit.ly/join-superset-slack) and please read our [Slack Community Guidelines](https://github.com/apache/superset/blob/master/CODE_OF_CONDUCT.md#slack-community-guidelines) - [Join our dev@superset.apache.org Mailing list](https://lists.apache.org/list.html?dev@superset.apache.org) @@ -142,26 +142,37 @@ how to set up a development environment. ## Resources +Superset 2.0! +- [Superset 2.0 Meetup](https://preset.io/events/superset-2-0-meetup/) +- [Superset 2.0 Release Notes](https://github.com/apache/superset/tree/master/RELEASING/release-notes-2-0) + +Understanding the Superset Points of View +- [The Case for Dataset-Centric Visualization](https://preset.io/blog/dataset-centric-visualization/) +- [Understanding the Superset Semantic Layer](https://preset.io/blog/understanding-superset-semantic-layer/) + + - Getting Started with Superset - [Superset in 2 Minutes using Docker Compose](https://superset.apache.org/docs/installation/installing-superset-using-docker-compose#installing-superset-locally-using-docker-compose) - [Installing Database Drivers](https://superset.apache.org/docs/databases/docker-add-drivers/) - [Building New Database Connectors](https://preset.io/blog/building-database-connector/) - [Create Your First Dashboard](https://superset.apache.org/docs/creating-charts-dashboards/first-dashboard) - [Comprehensive Tutorial for Contributing Code to Apache Superset -](https://preset.io/blog/tutorial-contributing-code-to-apache-superset/) -- [Documentation for Superset End-Users (by Preset)](https://docs.preset.io/docs/terminology) + ](https://preset.io/blog/tutorial-contributing-code-to-apache-superset/) +- [Resources to master Superset by Preset](https://preset.io/resources/) + - Deploying Superset - [Official Docker image](https://hub.docker.com/r/apache/superset) - [Helm Chart](https://github.com/apache/superset/tree/master/helm/superset) + - Recordings of Past [Superset Community Events](https://preset.io/events) - - [Live Demo: Interactive Time-series Analysis with Druid and Superset](https://preset.io/events/2021-03-02-interactive-time-series-analysis-with-druid-and-superset/) + - [Mixed Time Series Charts](https://preset.io/events/mixed-time-series-visualization-in-superset-workshop/) + - [How the Bing Team Customized Superset for the Internal Self-Serve Data & Analytics Platform](https://preset.io/events/how-the-bing-team-heavily-customized-superset-for-their-internal-data/) - [Live Demo: Visualizing MongoDB and Pinot Data using Trino](https://preset.io/events/2021-04-13-visualizing-mongodb-and-pinot-data-using-trino/) - - [Superset Contributor Bootcamp](https://preset.io/events/superset-contributor-bootcamp-dec-21/) - [Introduction to the Superset API](https://preset.io/events/introduction-to-the-superset-api/) - - [Apache Superset 1.3 Meetup](https://preset.io/events/apache-superset-1-3/) - [Building a Database Connector for Superset](https://preset.io/events/2021-02-16-building-a-database-connector-for-superset/) + - Visualizations - - [Building Custom Viz Plugins](https://superset.apache.org/docs/installation/building-custom-viz-plugins) + - [Creating Viz Plugins](https://superset.apache.org/docs/contributing/creating-viz-plugins/) - [Managing and Deploying Custom Viz Plugins](https://medium.com/nmc-techblog/apache-superset-manage-custom-viz-plugins-in-production-9fde1a708e55) - [Why Apache Superset is Betting on Apache ECharts](https://preset.io/blog/2021-4-1-why-echarts/) diff --git a/RELEASING/Dockerfile.from_local_tarball b/RELEASING/Dockerfile.from_local_tarball index 3cd030609b60e..4860db64287cc 100644 --- a/RELEASING/Dockerfile.from_local_tarball +++ b/RELEASING/Dockerfile.from_local_tarball @@ -24,13 +24,13 @@ ENV LANG=C.UTF-8 \ RUN apt-get update -y -# Install dependencies to fix `curl https support error` and `elaying package configuration warning` +# Install dependencies to fix `curl https support error` and `delaying package configuration warning` RUN apt-get install -y apt-transport-https apt-utils # Install superset dependencies # https://superset.apache.org/docs/installation/installing-superset-from-scratch RUN apt-get install -y build-essential libssl-dev \ - libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev + libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev chromium # Install nodejs for custom build # https://nodejs.org/en/download/package-manager/ diff --git a/RELEASING/Dockerfile.from_svn_tarball b/RELEASING/Dockerfile.from_svn_tarball index 482ab474a58e3..3deea5b8d3541 100644 --- a/RELEASING/Dockerfile.from_svn_tarball +++ b/RELEASING/Dockerfile.from_svn_tarball @@ -24,13 +24,13 @@ ENV LANG=C.UTF-8 \ RUN apt-get update -y -# Install dependencies to fix `curl https support error` and `elaying package configuration warning` +# Install dependencies to fix `curl https support error` and `delaying package configuration warning` RUN apt-get install -y apt-transport-https apt-utils # Install superset dependencies # https://superset.apache.org/docs/installation/installing-superset-from-scratch RUN apt-get install -y build-essential libssl-dev \ - libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev + libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev chromium # Install nodejs for custom build # https://nodejs.org/en/download/package-manager/ diff --git a/RELEASING/README.md b/RELEASING/README.md index 1d3285e0ffc32..901d21aefb3d7 100644 --- a/RELEASING/README.md +++ b/RELEASING/README.md @@ -30,6 +30,7 @@ partaking in the process should join the channel. ## Release notes for recent releases +- [2.0](release-notes-2-0/README.md) - [1.5](release-notes-1-5/README.md) - [1.4](release-notes-1-4/README.md) - [1.3](release-notes-1-3/README.md) @@ -289,10 +290,6 @@ git tag ${SUPERSET_VERSION_RC} git push origin ${SUPERSET_VERSION_RC} ``` -### Create a release on Github - -After submitting the tag, follow the steps [here](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to create the release. Use the vote email text as the content for the release description. Make sure to check the "This is a pre-release" checkbox for release canditates. You can check previous releases if you need an example. - ## Preparing the release candidate The first step of preparing an Apache Release is packaging a release candidate @@ -346,7 +343,11 @@ To build and run the recently created tarball **from SVN**: # login using admin/admin ``` -### Voting +## Create a release on Github + +After submitting the tag and testing the release candidate, follow the steps [here](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to create the release on GitHub. Use the vote email text as the content for the release description. Make sure to check the "This is a pre-release" checkbox for release candidates. You can check previous releases if you need an example. + +## Voting Now you're ready to start the [VOTE] thread. Here's an example of a previous release vote thread: @@ -384,7 +385,7 @@ A List of people with -1 vote (ex: John): The script will generate the email text that should be sent to dev@superset.apache.org using an email client. The release version and release candidate number are fetched from the previously set environment variables. -### Validating a release +## Validating a release https://www.apache.org/info/verification.html @@ -458,11 +459,14 @@ while requesting access to push packages. ```bash twine upload dist/apache-superset-${SUPERSET_VERSION}.tar.gz - -# Set your username to token -# Set your password to the token value, including the pypi- prefix ``` +Set your username to `__token__` + +Set your password to the token value, including the `pypi-` prefix + +More information on https://pypi.org/help/#apitoken + ### Announcing Once it's all done, an [ANNOUNCE] thread announcing the release to the dev@ mailing list is the final step. diff --git a/RELEASING/release-notes-2-0/README.md b/RELEASING/release-notes-2-0/README.md new file mode 100644 index 0000000000000..193a1e7424b72 --- /dev/null +++ b/RELEASING/release-notes-2-0/README.md @@ -0,0 +1,152 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +# Release Notes for Superset 2.0 + +Superset 2.0 is a big step forward. This release cleans up many legacy code paths and feature flags, and deprecates lots of legacy behaviors in Superset. + +- [**Developer Experience**](#developer-experience) +- [**Features**](#features) +- [**Config and Feature flags**](#config-and-feature-flags) +- [**Breaking Changes**](#breaking-changes) + +## Developer Experience + +- Addition of a statsd guage metric for Slack and email notifications for increased visibility into errors around alerts / reports ([#20158](https://github.com/apache/superset/pull/20158)) + +- Helm chart now supports resource limits and requests for each component ([#20052](https://github.com/apache/superset/pull/20052)) + +- New Github workflow to test Storybook Netlify instance nightly ([#19852](https://github.com/apache/superset/pull/19852)) + +- Minimum requirement for Superset is now Python 3.8 ([#19017](https://github.com/apache/superset/pull/19017) + +## Features + +**Charting and Dashboard Experience** + +Support for horizontal bar chart added ([#19918](https://github.com/apache/superset/pull/19918)) + +![horizontal](https://user-images.githubusercontent.com/11830681/166248149-4946388a-5051-4d13-a516-50a81e9b5be3.png) + +Time Series Charts now support stacking of both negative and positive values ([#20408](https://github.com/apache/superset/pull/20408)) + +![negative](https://user-images.githubusercontent.com/15073128/174057996-52255bfe-60c3-4727-be99-e328c124e439.png) + +- Pie charts now defaults to a row limit of 100 to prevent crashes when a high-cardinality column is chosen as the dimension ([#20392](https://github.com/apache/superset/pull/20392)) + +- World map chart now supports coloring either by metric or by the country column ([#19881](https://github.com/apache/superset/pull/19881)) + +- Table visualization now supports drag and drop for columns ([#19381](https://github.com/apache/superset/pull/19381)) + +- Mixed chart now supports Advanced Analytics ([#19851](https://github.com/apache/superset/pull/19851)) + +- Add support for generic x-axis (non-time-series) in the Mixed Chart ([#20097](https://github.com/apache/superset/pull/20097)) + +![Image](https://user-images.githubusercontent.com/33317356/168807749-b021c04c-8902-4b4f-a7a4-f21544fb678e.png) + +- Charts can now be created in Edit Dashboard mode ([#20126](https://github.com/apache/superset/pull/20126)) + +![Image](https://user-images.githubusercontent.com/15073128/169251205-2c0f36bb-17e0-4549-aa84-66a58a377603.png) + +- Add aggregate total for Pie charts ([#19622](https://github.com/apache/superset/pull/19622)) + +- Legend is now enabled by default for relevant charts ([#19927](https://github.com/apache/superset/pull/19927)) + +**View Results Experience** + +- Explore and Dashboard views now support displaying of multiple results ([#20277](https://github.com/apache/superset/pull/20277)) + +- Results pane in Dashboard view now more closely mirrors rich functionality from Results pane in Explore ([#20144](https://github.com/apache/superset/pull/20144)) + + +**Quality of Life** + +- Edit Dataset modal now doesn't close when you click away ([#20278](https://github.com/apache/superset/pull/20278)) + +- When editing the label in the Metrics popover, pressing Enter now saves what you typed ([#19898](https://github.com/apache/superset/pull/19898)) + +- When adding new chart from the dashboard view, the dashboard name will now pre-fill ([#20129](https://github.com/apache/superset/pull/20129)) + +- Annotations now have an improved empty state ([#20160](https://github.com/apache/superset/pull/20160)) + +- Confirmational modal is now shown if user exits Explore without saving changes ([#19993](https://github.com/apache/superset/pull/19993)) + +- Explore popovers now close when the Escape key is pressed ([#19902](https://github.com/apache/superset/pull/19902)) + +- Run and Save buttons are redesigned for improved usability ([#19558](https://github.com/apache/superset/pull/19558)) + +**Databases** + +- Native database driver for Databricks ([#20320](https://github.com/apache/superset/pull/20320)) + +- Time grains for SQLite are now simplified ([#19745](https://github.com/apache/superset/pull/19745)) + +- Multiple upgrades to the Trino database engine ([#20152](https://github.com/apache/superset/pull/20152)) + +- Switch from sqlalchemy-trino to trino-python-client ([#19957](https://github.com/apache/superset/pull/19957)) + +- Apache Pinot now supports more time grains in Superset ([#19724](https://github.com/apache/superset/pull/19724)) + +**Jinja** + +- New Jinja macro enables querying / referencing both physical and virtual datasets in SQL Lab ([#15241](https://github.com/apache/superset/pull/15241)) + +- New Jinja macro added to improve experience of including multiple items ([#19574](https://github.com/apache/superset/pull/19574)) + +**Other** + +- Datasets can now be filtered by their certification status ([#20136](https://github.com/apache/superset/pull/20136)) + + +## Config and Feature Flags + +- Initial implementation of advanced types ([#18794](https://github.com/apache/superset/pull/18794)) + - Flag: `ENABLE_ADVANCED_DATA_TYPES` + +- Caching can now be enabled in database setups when user impersonation is enabled ([#20114](https://github.com/apache/superset/pull/20114)) + - Flag: `CACHE_IMPERSONATION` + +- Control behavior for how color palettes are chosen ([#19987](https://github.com/apache/superset/pull/19987)) + - Flag: `USE_ANALAGOUS_COLORS` + +- Enabling non-time-series x-axis in some charts ([#20097](https://github.com/apache/superset/pull/20097)) + - Flag: `GENERIC_CHART_AXES` + +- As part of the 2.0 cleanup efforts, the following feature flags were removed (which means the behavior is now permanently enabled): + - `ROW_LEVEL_SECURITY` + - `ENABLE_REACT_CRUD_VIEWS` + - `PUBLIC_ROLE_LIKE_GAMMA` + +- The following feature flags are now True by default, but can be turned back to False: + - `ENABLE_EXPLORE_DRAG_AND_DROP` + - `ENABLE_DND_WITH_CLICK_UX` + - `DISABLE_LEGACY_DATASOURCE_EDITOR` + - `SQLLAB_BACKEND_PERSISTENCE` + - `VERSIONED_EXPORT` + +- The following config flags were removed: + - `APP_ICON_WIDTH` + +- A number of legacy interim flags were removed around SIP-15 ([#18936](https://github.com/apache/superset/pull/18936)) + +- The `ENABLE_JAVASCRIPT_CONTROLS` flag was moved from an app config to a feature flag + +## Breaking Changes + +To learn more about the breaking changes in 2.0, please read [UPDATING.MD](https://github.com/apache/superset/blob/master/UPDATING.md) diff --git a/RELEASING/release-notes-2-0/changelog.md b/RELEASING/release-notes-2-0/changelog.md new file mode 100644 index 0000000000000..4b3b5ddfaef28 --- /dev/null +++ b/RELEASING/release-notes-2-0/changelog.md @@ -0,0 +1,491 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +### 2.0 (Thu Jun 23 05:39:46 2022 -0600) + +**Database Migrations** + +- [#20385](https://github.com/apache/superset/pull/20385) fix(migration): Ensure key_value LargeBinary is encoded as a MEDIUMBLOB as opposed to BLOB for MySQL (@john-bodley) +- [#20449](https://github.com/apache/superset/pull/20449) fix: RLS new db migration downgrade fails on SQLite (@dpgaspar) +- [#20284](https://github.com/apache/superset/pull/20284) chore(migrations): Renaming migration files so that they're easier to keep track of (@craig-rueda) +- [#20108](https://github.com/apache/superset/pull/20108) fix: None dataset and schema permissions (@dpgaspar) +- [#18794](https://github.com/apache/superset/pull/18794) feat(business-types): initial implementation of SIP-78 (@cccs-RyanS) +- [#20073](https://github.com/apache/superset/pull/20073) fix(dataset): handle missing sqla uri in migration (@villebro) +- [#19941](https://github.com/apache/superset/pull/19941) fix(reports): Clear last value when state is WORKING (@john-bodley) +- [#19675](https://github.com/apache/superset/pull/19675) chore(docs): Spelling (@jsoref) +- [#19793](https://github.com/apache/superset/pull/19793) fix(SIP-68): handle empty table name during migration (@ktmud) +- [#19786](https://github.com/apache/superset/pull/19786) fix(migrations): coalesce is_temporal when inserting into sl_columns (@cemremengu) +- [#19421](https://github.com/apache/superset/pull/19421) perf: refactor SIP-68 db migrations with INSERT SELECT FROM (@ktmud) +- [#19767](https://github.com/apache/superset/pull/19767) fix: Fix migration for removing time_range_endpoints 3 (@hughhhh) +- [#19728](https://github.com/apache/superset/pull/19728) fix: Removetime_range_endpoints from query context object pt 2 (@hughhhh) +- [#19630](https://github.com/apache/superset/pull/19630) chore: clean up unused imports in db migration scripts (@ktmud) +- [#19577](https://github.com/apache/superset/pull/19577) fix: merge multiple db heads (@eschutho) +- [#19243](https://github.com/apache/superset/pull/19243) fix: cannot delete a database if team member has SQL editor tab that uses that db (@diegomedina248) +- [#19537](https://github.com/apache/superset/pull/19537) chore: block unsafe functions (@betodealmeida) +- [#19513](https://github.com/apache/superset/pull/19513) chore: postpone timerange endpoint removal (@villebro) +- [#19495](https://github.com/apache/superset/pull/19495) perf: speed up db migration for deprecating time_range_endpoints (@ktmud) +- [#19474](https://github.com/apache/superset/pull/19474) fix: handle null params in #18936 migration (@serenajiang) +- [#19423](https://github.com/apache/superset/pull/19423) fix: Remove`time_range_endpoints` from query context object (@hughhhh) +- [#18936](https://github.com/apache/superset/pull/18936) chore: Remove legacy SIP-15 interim logic/flags (@john-bodley) + +**Features** +- [#20114](https://github.com/apache/superset/pull/20114) feat(chart): Enable caching per user when user impersonation is enabled (@Samira-El) +- [#20408](https://github.com/apache/superset/pull/20408) feat(plugin-chart-echarts): Support stacking negative and positive values (@kgabryje) +- [#20278](https://github.com/apache/superset/pull/20278) feat: Prevent dataset edit modal closing on click-away in edit mode (@reesercollins) +- [#20392](https://github.com/apache/superset/pull/20392) feat: setting limit value when Pie chart switches (@zhaoyongjie) +- [#20373](https://github.com/apache/superset/pull/20373) feat: adding truncate metric control on timeseries charts (@zhaoyongjie) +- [#20248](https://github.com/apache/superset/pull/20248) feat(explore): Implement viz switcher redesign (@kgabryje) +- [#20113](https://github.com/apache/superset/pull/20113) feat(api): Added "kind" to dataset/<pk> endpoint (@reesercollins) +- [#20299](https://github.com/apache/superset/pull/20299) feat(explore): Dataset Panel Options when Source = Query II (@lyndsiWilliams) +- [#20320](https://github.com/apache/superset/pull/20320) feat: Databricks native driver (@betodealmeida) +- [#20313](https://github.com/apache/superset/pull/20313) feat(explore): Denormalize form data in echarts, world map and nvd3 bar and line charts (@kgabryje) +- [#20277](https://github.com/apache/superset/pull/20277) feat: multiple results pane on explore and dashboard (@zhaoyongjie) +- [#19898](https://github.com/apache/superset/pull/19898) feat: When editing the label/title in the Metrics popover, hitting Enter should save what you've typed (@diegomedina248) +- [#16493](https://github.com/apache/superset/pull/16493) feat(plugin-chart-echarts): [feature-parity] support extra control for the area chart V2 (@stephenLYZ) +- [#19855](https://github.com/apache/superset/pull/19855) feat(explore): Frontend implementation of dataset creation from infobox (@lyndsiWilliams) +- [#20165](https://github.com/apache/superset/pull/20165) feat: add modfied col and timezone info to schedule col (@pkdotson) +- [#20144](https://github.com/apache/superset/pull/20144) feat: showing results pane in dashboard (@zhaoyongjie) +- [#20242](https://github.com/apache/superset/pull/20242) feat: derived metrics use different line style (@zhaoyongjie) +- [#20010](https://github.com/apache/superset/pull/20010) feat: standardized form_data (@zhaoyongjie) +- [#19987](https://github.com/apache/superset/pull/19987) feat(superset-ui-core): add feature flag for the analogous colors (@stephenLYZ) +- [#19881](https://github.com/apache/superset/pull/19881) feat(world-map): support color by metric or country column (@stephenLYZ) +- [#19981](https://github.com/apache/superset/pull/19981) feat!: pass datasource_type and datasource_id to form_data (@eschutho) +- [#15241](https://github.com/apache/superset/pull/15241) feat: query datasets from SQL Lab (@betodealmeida) +- [#20129](https://github.com/apache/superset/pull/20129) feat(explore): Fill dashboard name when adding new chart from dashboard view (@kgabryje) +- [#20160](https://github.com/apache/superset/pull/20160) feat(explore): Add empty state to annotations (@kgabryje) +- [#20134](https://github.com/apache/superset/pull/20134) feat: add Query.columns for bootstrap_data (@hughhhh) +- [#20158](https://github.com/apache/superset/pull/20158) feat: add statsd metrics for notifications (@dpgaspar) +- [#20052](https://github.com/apache/superset/pull/20052) feat(Helm Chart): Support resource limits and requests for each component (@rathberm) +- [#20170](https://github.com/apache/superset/pull/20170) feat: add samples endpoint (@zhaoyongjie) +- [#19381](https://github.com/apache/superset/pull/19381) feat: add drag and drop column rearrangement for table viz (@stevetracvc) +- [#20136](https://github.com/apache/superset/pull/20136) feat: Add Certified filter to Datasets (@hughhhh) +- [#20111](https://github.com/apache/superset/pull/20111) feat(dashboard): Chart title click redirects to Explore in new tab (@kgabryje) +- [#20097](https://github.com/apache/superset/pull/20097) feat(plugin-chart-echarts): add support for generic axis to mixed chart (@villebro) +- [#20126](https://github.com/apache/superset/pull/20126) feat(dashboard): Add create chart button in dashboard edit mode (@kgabryje) +- [#20059](https://github.com/apache/superset/pull/20059) feat: Save column data into json_metadata for all Query executions (@hughhhh) +- [#19918](https://github.com/apache/superset/pull/19918) feat(plugin-chart-echarts): support horizontal bar chart (@stephenLYZ) +- [#19902](https://github.com/apache/superset/pull/19902) feat: Explore popovers should close on escape (@diegomedina248) +- [#20049](https://github.com/apache/superset/pull/20049) feat(dashboard): Rearrange items in chart header controls dropdown (@kgabryje) +- [#20030](https://github.com/apache/superset/pull/20030) feat(sip-68): Add DatasourceDAO class to manage querying different datasources easier (@hughhhh) +- [#19581](https://github.com/apache/superset/pull/19581) feat(viz-gallery): add search weight for viz-name (@stephenLYZ) +- [#19999](https://github.com/apache/superset/pull/19999) feat: RLS for SQL Lab (@betodealmeida) +- [#19993](https://github.com/apache/superset/pull/19993) feat(explore): Show confirmation modal if user exits Explore without saving changes (@kgabryje) +- [#19873](https://github.com/apache/superset/pull/19873) feat(css): adds `chartId`-based class to dashboard chart holder (@rusackas) +- [#20002](https://github.com/apache/superset/pull/20002) feat: deprecate /superset/testconn and migrate to api v1 (@zephyring) +- [#19935](https://github.com/apache/superset/pull/19935) feat: deprecate /superset/validate_sql_json migrate to api v1 (@dpgaspar) +- [#20015](https://github.com/apache/superset/pull/20015) feat: add new enums for datasource types (@hughhhh) +- [#19956](https://github.com/apache/superset/pull/19956) feat: Applitools Cypress workflow (@geido) +- [#19852](https://github.com/apache/superset/pull/19852) feat: Run Applitools on public Storybook (@geido) +- [#19963](https://github.com/apache/superset/pull/19963) feat: Add cypress test for downloading chart as image (@codemaster08240328) +- [#19957](https://github.com/apache/superset/pull/19957) feat: switch from `sqlalchemy-trino` to `trino-python-client` (@dungdm93) +- [#19921](https://github.com/apache/superset/pull/19921) feat: deprecate /superset/extra_table_metadata migrate to api v1 (@dpgaspar) +- [#19745](https://github.com/apache/superset/pull/19745) feat: simplify SQLite time grain (@betodealmeida) +- [#19927](https://github.com/apache/superset/pull/19927) feat(chart & legend): make to enable show legend by default (@prosdev0107) +- [#19754](https://github.com/apache/superset/pull/19754) feat: deprecate old API on core superset fave_dashboards (@dpgaspar) +- [#19905](https://github.com/apache/superset/pull/19905) feat: simplify `memoized_func` (@betodealmeida) +- [#19871](https://github.com/apache/superset/pull/19871) feat(filter): make to hide sort filter when time range (@prosdev0107) +- [#19851](https://github.com/apache/superset/pull/19851) feat: add Advanced Analytics into mixed time series chart (@zhaoyongjie) +- [#19692](https://github.com/apache/superset/pull/19692) feat: Update ShortKey for stop query running in SqlLab editor (@codemaster08240328) +- [#17903](https://github.com/apache/superset/pull/17903) feat: Adds plugin-chart-handlebars (@jdbranham) +- [#19748](https://github.com/apache/superset/pull/19748) feat(explore): improve UI in the control panel (@stephenLYZ) +- [#19724](https://github.com/apache/superset/pull/19724) feat: 10/15/30 min grain to Pinot (@hughhhh) +- [#19696](https://github.com/apache/superset/pull/19696) feat(explore): Replace overlay with alert banner when chart controls change (@kgabryje) +- [#19751](https://github.com/apache/superset/pull/19751) feat(explore): Implement data panel redesign (@kgabryje) +- [#19598](https://github.com/apache/superset/pull/19598) feat: add empty states to sqlab editor and select (@pkdotson) +- [#19450](https://github.com/apache/superset/pull/19450) feat: Remove legacy sql alchemy db connection link from G Sheet connection (@codemaster08240328) +- [#19710](https://github.com/apache/superset/pull/19710) feat: Enabling source maps full time (@rusackas) +- [#19671](https://github.com/apache/superset/pull/19671) feat: UI override registry (@suddjian) +- [#19691](https://github.com/apache/superset/pull/19691) feat(explore): More explicit labels of adhoc filter operators (@kgabryje) +- [#19558](https://github.com/apache/superset/pull/19558) feat(explore): Redesign of Run/Save buttons (@kgabryje) +- [#19650](https://github.com/apache/superset/pull/19650) feat(embedded): API get embedded dashboard config by uuid (@lilykuang) +- [#19310](https://github.com/apache/superset/pull/19310) feat(CRUD): add new empty state (@stephenLYZ) +- [#19622](https://github.com/apache/superset/pull/19622) feat(plugin-chart-echarts): add aggregate total for the Pie/Donuct chart (@stephenLYZ) +- [#19314](https://github.com/apache/superset/pull/19314) feat: Move Database Import option into DB Connection modal (@lyndsiWilliams) +- [#19434](https://github.com/apache/superset/pull/19434) feat: deprecate old API and create new API for dashes created by me (@dpgaspar) +- [#19482](https://github.com/apache/superset/pull/19482) feat: add success toast to alerts and reports (@pkdotson) +- [#19574](https://github.com/apache/superset/pull/19574) feat: add a `where_in` filter for Jinja2 (@betodealmeida) +- [#19458](https://github.com/apache/superset/pull/19458) feat(explore): Move timer, row counter and cached pills to chart container (@kgabryje) +- [#19529](https://github.com/apache/superset/pull/19529) feat(explore): Move chart header to top of the page (@kgabryje) +- [#19489](https://github.com/apache/superset/pull/19489) feat(CI): clean up Python tests output (@ktmud) +- [#19308](https://github.com/apache/superset/pull/19308) feat(explore): SQL popover in datasource panel (@kgabryje) +- [#19325](https://github.com/apache/superset/pull/19325) feat(color): support analogous colors to prevent color conflict (@stephenLYZ) +- [#19408](https://github.com/apache/superset/pull/19408) feat(dashboard): Implement empty states for empty tabs (@kgabryje) +- [#19446](https://github.com/apache/superset/pull/19446) feat(explore): Move chart actions into dropdown (@kgabryje) +- [#19394](https://github.com/apache/superset/pull/19394) feat(explore): UI changes in dataset panel on Explore page (@kgabryje) + +**Fixes** +- [#19920](https://github.com/apache/superset/pull/19920) fix(table viz): correctly sort by multiple columns in a table (@stevetracvc) +- [#20402](https://github.com/apache/superset/pull/20402) fix: alert & reports active toggle optimistic update (@diegomedina248) +- [#20472](https://github.com/apache/superset/pull/20472) fix: Changes the return type of get_permissions to be JSON friendly (@michael-s-molina) +- [#20468](https://github.com/apache/superset/pull/20468) fix: async queries limit bug (@AAfghahi) +- [#20257](https://github.com/apache/superset/pull/20257) fix(home): Show home page tabs as pills instead of links (@prosdev0107) +- [#20340](https://github.com/apache/superset/pull/20340) fix: ensure column name in description is string (@betodealmeida) +- [#20350](https://github.com/apache/superset/pull/20350) fix(viz): BigQuery time grain 'minute'/'second' throws an error (@diegomedina248) +- [#20384](https://github.com/apache/superset/pull/20384) fix(chart & table): Prevent the dates from wrapping in table chart (@prosdev0107) +- [#20404](https://github.com/apache/superset/pull/20404) fix: suppress translation warning in jest (@zhaoyongjie) +- [#20451](https://github.com/apache/superset/pull/20451) fix: should raise exception when apply a categorical axis (@zhaoyongjie) +- [#20447](https://github.com/apache/superset/pull/20447) fix: table viz sort icon bottom aligned (@diegomedina248) +- [#20326](https://github.com/apache/superset/pull/20326) fix(fbprophet): Fix weekly frequencies (@john-bodley) +- [#20434](https://github.com/apache/superset/pull/20434) fix(20428): Address-Presto/Trino-Poll-Issue-Refactor (@Thelin90) +- [#20411](https://github.com/apache/superset/pull/20411) fix(dashboard): new created chart did not have high lighted effect when using the permalink of chart share in dashboard (@diegomedina248) +- [#20261](https://github.com/apache/superset/pull/20261) fix(embedded): CSV download for chart (@lilykuang) +- [#20276](https://github.com/apache/superset/pull/20276) fix(cosmetic): cannot find m-r-10 class in superset.less (@Renderz) +- [#20420](https://github.com/apache/superset/pull/20420) fix: rm eslint-plugin-translation-vars engines requirement (@stephenLYZ) +- [#20409](https://github.com/apache/superset/pull/20409) fix(bar-chart-v2): remove marker control from bar chart V2 (@stephenLYZ) +- [#20333](https://github.com/apache/superset/pull/20333) fix(presto): use milliseconds timespec for presto (@mohittt8) +- [#20414](https://github.com/apache/superset/pull/20414) fix: key error on permalink fetch for old permalinks (@eschutho) +- [#20410](https://github.com/apache/superset/pull/20410) fix: Adding extra metrics issue after chart configuration (@codemaster08240328) +- [#20405](https://github.com/apache/superset/pull/20405) fix: Incorrect translations in Chinese in messages.po (@chuancyzhang) +- [#20396](https://github.com/apache/superset/pull/20396) fix(plugin-chart-pivot-table): color weight of Conditional formatting metrics not work (@stephenLYZ) +- [#20361](https://github.com/apache/superset/pull/20361) fix(fonts): Show the all the A's in our workspace correctly, not funky (@prosdev0107) +- [#20383](https://github.com/apache/superset/pull/20383) fix: Unable to export multiple Dashboards with the same name (@diegomedina248) +- [#20363](https://github.com/apache/superset/pull/20363) fix: A newly connected database doesn't appear in the databases list if user connected database using the 'plus' button (@diegomedina248) +- [#20372](https://github.com/apache/superset/pull/20372) fix: update connection modal to use existing catalog (@pkdotson) +- [#20368](https://github.com/apache/superset/pull/20368) fix(VERSIONED_EXPORTS): Ensure dashboards and charts adhere to the VERSIONED_EXPORTS feature flag (@john-bodley) +- [#20351](https://github.com/apache/superset/pull/20351) fix: catch some potential errors on dual write (@eschutho) +- [#20364](https://github.com/apache/superset/pull/20364) fix: query execution time is not fully displayed in bubble icon (@diegomedina248) +- [#20365](https://github.com/apache/superset/pull/20365) fix: Fix typo in Error handling message (@codemaster08240328) +- [#19967](https://github.com/apache/superset/pull/19967) fix: A newly connected database doesn't appear in the databases list if user connected database using the 'plus' button (@diegomedina248) +- [#20348](https://github.com/apache/superset/pull/20348) fix(docker): Make Gunicorn Keepalive Adjustable (@mdeshmu) +- [#19670](https://github.com/apache/superset/pull/19670) fix: Add serviceAccountName to celerybeat pods (@paulinjo) +- [#20315](https://github.com/apache/superset/pull/20315) fix(chart): chart gets cut off on the dashboard (@stephenLYZ) +- [#20324](https://github.com/apache/superset/pull/20324) fix: superset-ui/core coverage (@zhaoyongjie) +- [#20282](https://github.com/apache/superset/pull/20282) fix(explore): Make that see more/see less works correctly with scrolling when error msg is long text. (@prosdev0107) +- [#20296](https://github.com/apache/superset/pull/20296) fix: Alpha are unable to perform a second modification to a Dataset when in Explore (@hughhhh) +- [#20290](https://github.com/apache/superset/pull/20290) fix: Faulty datetime parser regex (@reesercollins) +- [#19761](https://github.com/apache/superset/pull/19761) fix(plugin-chart-echarts): [feature-parity] apply button of annotation layer doesn't work as expected (@stephenLYZ) +- [#20263](https://github.com/apache/superset/pull/20263) fix(embedded): accessing variable response before initialization (@zhaorui2022) +- [#20274](https://github.com/apache/superset/pull/20274) fix(codecov): improve core code coverage (@stephenLYZ) +- [#20187](https://github.com/apache/superset/pull/20187) fix: Database import with cancel_query.. extra field (@codemaster08240328) +- [#20237](https://github.com/apache/superset/pull/20237) fix(cosmetic): Fix Datasource Modal Out Of Box (@Renderz) +- [#20058](https://github.com/apache/superset/pull/20058) fix: Support the Clipboard API in modern browsers (@diegomedina248) +- [#20164](https://github.com/apache/superset/pull/20164) fix(sql lab): View result button is not showing consistently (@diegomedina248) +- [#20171](https://github.com/apache/superset/pull/20171) fix(charts list): do not trigger ListViewError exception for anonymous user (@trepmag) +- [#20178](https://github.com/apache/superset/pull/20178) fix: While exporting CSV , only the entries on first page are getting downloaded even when user is on other pages #17861 (@LahmerIlyas) +- [#20204](https://github.com/apache/superset/pull/20204) fix: Fixes issue where results panel height was incorrect [sc-49045] (@eric-briscoe) +- [#20235](https://github.com/apache/superset/pull/20235) fix: Box Plot Chart throws an error when the average (AVG) / SUM is being calculated on the Metrics (@diegomedina248) +- [#20088](https://github.com/apache/superset/pull/20088) fix: datatype tracking issue on virtual dataset (@codemaster08240328) +- [#20220](https://github.com/apache/superset/pull/20220) fix: dashbaord unable to refresh (@zhaoyongjie) +- [#20228](https://github.com/apache/superset/pull/20228) fix: failed samples should throw exception (@zhaoyongjie) +- [#20203](https://github.com/apache/superset/pull/20203) fix: move columns to datasource object for bootstrap data (@hughhhh) +- [#20151](https://github.com/apache/superset/pull/20151) fix(csv): Ensure df_to_escaped_csv does not coerce integer columns to float (@john-bodley) +- [#20221](https://github.com/apache/superset/pull/20221) fix(legacy-plugin-chart-sunburst): linear color scheme not work when secondary metric is provided (@stephenLYZ) +- [#20223](https://github.com/apache/superset/pull/20223) fix(legacy-plugin-chart-sunburst): chart broken when secondary metric is removed (@stephenLYZ) +- [#20147](https://github.com/apache/superset/pull/20147) fix(cosmetic): Limiting modal height (@rusackas) +- [#20206](https://github.com/apache/superset/pull/20206) fix(sql lab): SQL Lab Compile Query Delay (@diegomedina248) +- [#20201](https://github.com/apache/superset/pull/20201) fix: unable to set destroyOnClose on ModalTrigger (@zhaoyongjie) +- [#20186](https://github.com/apache/superset/pull/20186) fix(db): make to allow to show/hide the password when only creating (@prosdev0107) +- [#20127](https://github.com/apache/superset/pull/20127) fix(database): retrival of tables and views from schema for exasol backend (@Nicoretti) +- [#19899](https://github.com/apache/superset/pull/19899) fix: always create parameter json field (@pkdotson) +- [#20173](https://github.com/apache/superset/pull/20173) fix: avoid while cycle in computeMaxFontSize for big Number run forever when css rule applied (@diegomedina248) +- [#20086](https://github.com/apache/superset/pull/20086) fix(css): transparent linear gradient not working in safari (@stephenLYZ) +- [#19102](https://github.com/apache/superset/pull/19102) fix: string aggregation is incorrect in PivotTableV2 (@diegomedina248) +- [#20011](https://github.com/apache/superset/pull/20011) fix(chart & heatmap): make to fix that y label is rendering out of bounds (@prosdev0107) +- [#20142](https://github.com/apache/superset/pull/20142) fix(explore): handle null control sections (@villebro) +- [#20128](https://github.com/apache/superset/pull/20128) fix: advanced data type API spec and permission name (@dpgaspar) +- [#20107](https://github.com/apache/superset/pull/20107) fix(generic-chart-axes): set x-axis if unset and ff is enabled (@villebro) +- [#20018](https://github.com/apache/superset/pull/20018) fix(modal): add primary button loading state to modals (@kgopal492) +- [#20099](https://github.com/apache/superset/pull/20099) fix: Add cypress test for report page direct link issue (@codemaster08240328) +- [#20068](https://github.com/apache/superset/pull/20068) fix: dbmodal test connection error timeout (@pkdotson) +- [#20092](https://github.com/apache/superset/pull/20092) fix: Revert "feat(explore): Show confirmation modal if user exits Explore without saving changes (#19993) (@kgabryje) +- [#19939](https://github.com/apache/superset/pull/19939) fix(chart & alert): make to show metrics properly (@prosdev0107) +- [#20085](https://github.com/apache/superset/pull/20085) fix: typo in `importexport/api.py` OpenAPI (@betodealmeida) +- [#20051](https://github.com/apache/superset/pull/20051) fix(CRUD): make to fix the dancing when crud view is on hover (@prosdev0107) +- [#20064](https://github.com/apache/superset/pull/20064) fix(chart & gallery): make to add mixed time-series into recommended charts (@prosdev0107) +- [#20013](https://github.com/apache/superset/pull/20013) fix: The dynamic form to connect to Snowflake DB is not returning any errors (@diegomedina248) +- [#20029](https://github.com/apache/superset/pull/20029) fix(plugin-chart-echarts): tooltip of big number truncated at then bottom (@stephenLYZ) +- [#19914](https://github.com/apache/superset/pull/19914) fix: Refactor SQL engine username logic (@john-bodley) +- [#20050](https://github.com/apache/superset/pull/20050) fix: Fixes Tabs style (@michael-s-molina) +- [#20048](https://github.com/apache/superset/pull/20048) fix(homepage): make to show indicator when tab is chosen (@prosdev0107) +- [#20026](https://github.com/apache/superset/pull/20026) fix(chart & filters): make to padding between textarea and buttons (@prosdev0107) +- [#20019](https://github.com/apache/superset/pull/20019) fix(embedded): third party cookies (@lilykuang) +- [#20033](https://github.com/apache/superset/pull/20033) fix: Direct Linking issue on report list: 404 status code. (@codemaster08240328) +- [#19977](https://github.com/apache/superset/pull/19977) fix(word-cloud): fix randomness of each word's rotation (@ebaratte) +- [#20021](https://github.com/apache/superset/pull/20021) fix: native filter truncation rerendering loop on hover (@diegomedina248) +- [#20004](https://github.com/apache/superset/pull/20004) fix: URI form is blank when trying to connect from sql lab (@diegomedina248) +- [#19841](https://github.com/apache/superset/pull/19841) fix: Table chart column config issue (@codemaster08240328) +- [#19877](https://github.com/apache/superset/pull/19877) fix: Making chart update more truthful (@Gwitchr) +- [#19996](https://github.com/apache/superset/pull/19996) fix: Use pull_request_target in Cypress Applitools workflow (@geido) +- [#19972](https://github.com/apache/superset/pull/19972) fix: revert chore(deps): bump d3-svg-legend in /superset-frontend (#19846) (@villebro) +- [#19889](https://github.com/apache/superset/pull/19889) fix: Fix auto-reversion of label/title in the Metrics popover (@diegomedina248) +- [#19903](https://github.com/apache/superset/pull/19903) fix(explore): Explore data table tooltip (@Gwitchr) +- [#19938](https://github.com/apache/superset/pull/19938) fix(chart & table): make to allow highlight in case of numeric column (@prosdev0107) +- [#19839](https://github.com/apache/superset/pull/19839) fix(dashboard): allow users to resize the markdown widget easier (@cccs-Dustin) +- [#19887](https://github.com/apache/superset/pull/19887) fix(hive): Workaround for Python 3.9 s3 transfer issue (@john-bodley) +- [#19936](https://github.com/apache/superset/pull/19936) fix: OpenAPI docs small fixes (@dpgaspar) +- [#19932](https://github.com/apache/superset/pull/19932) fix: can not correctly set force in store (@zhaoyongjie) +- [#19930](https://github.com/apache/superset/pull/19930) fix: memoize primitives (@betodealmeida) +- [#19926](https://github.com/apache/superset/pull/19926) fix(dataset): DAO update (@betodealmeida) +- [#19826](https://github.com/apache/superset/pull/19826) fix: Missing `f` prefix on f-strings (@code-review-doctor) +- [#18988](https://github.com/apache/superset/pull/18988) fix(column-header-tooltip): make that hide the tooltip when the cloum… (@prosdev0107) +- [#19782](https://github.com/apache/superset/pull/19782) fix: chart import error with virtual dataset (@codemaster08240328) +- [#19485](https://github.com/apache/superset/pull/19485) fix: Set fixed maxWidth of the cron schedule modal (@codemaster08240328) +- [#19885](https://github.com/apache/superset/pull/19885) fix: Chart download as image issue (@codemaster08240328) +- [#19883](https://github.com/apache/superset/pull/19883) fix(allow-db-explore): make to check the allow virtual table explore option by default (@prosdev0107) +- [#19835](https://github.com/apache/superset/pull/19835) fix(helm): fix postgresql values (@benjamin-texier) +- [#19758](https://github.com/apache/superset/pull/19758) fix(plugin-chart-echarts): [feature parity] annotation line chart color does not work (@stephenLYZ) +- [#19879](https://github.com/apache/superset/pull/19879) fix(plugin-chart-handlebars): fix overflow, debounce and control reset (@villebro) +- [#19668](https://github.com/apache/superset/pull/19668) fix: Dates alignment in Table viz (@geido) +- [#19876](https://github.com/apache/superset/pull/19876) fix: Cannot re-order metrics by drag and drop (@diegomedina248) +- [#19840](https://github.com/apache/superset/pull/19840) fix(dashboard-css): make to load saved css template (@prosdev0107) +- [#19859](https://github.com/apache/superset/pull/19859) fix: Dashboard report creation error handling (@etr2460) +- [#19857](https://github.com/apache/superset/pull/19857) fix: Update eslint error message to reflect location of antd components (@etr2460) +- [#19605](https://github.com/apache/superset/pull/19605) fix: Query execution time is displayed as invalid date (@diegomedina248) +- [#19694](https://github.com/apache/superset/pull/19694) fix(db & connection): make to show/hide the password when only creating db connection (@prosdev0107) +- [#19778](https://github.com/apache/superset/pull/19778) fix: deck.gl GeoJsonLayer Autozoom & fill/stroke options (@diegomedina248) +- [#19850](https://github.com/apache/superset/pull/19850) fix: Regression on Data and Alerts & Reports Headers (@diegomedina248) +- [#19842](https://github.com/apache/superset/pull/19842) fix: count(distinct column_name) in metrics (@zhaoyongjie) +- [#19843](https://github.com/apache/superset/pull/19843) fix(explore): ignore temporary controls in altered pill (@villebro) +- [#19800](https://github.com/apache/superset/pull/19800) fix: Cypress tests reliability improvements (@diegomedina248) +- [#19575](https://github.com/apache/superset/pull/19575) fix: Show full long number in text email report for table chart. (@codemaster08240328) +- [#19429](https://github.com/apache/superset/pull/19429) fix(dashboard): make to filter the correct certified or non-certified… (@prosdev0107) +- [#13082](https://github.com/apache/superset/pull/13082) fix(sql_lab): Add custom timestamp type for literal casting for presto timestamps (@kekwan) +- [#19797](https://github.com/apache/superset/pull/19797) fix: add missing init files (@suddjian) +- [#19672](https://github.com/apache/superset/pull/19672) fix: trap SQLAlchemy common exceptions & throw 422 error instead (@diegomedina248) +- [#19288](https://github.com/apache/superset/pull/19288) fix: AlertReportCronScheduler tests (@diegomedina248) +- [#19781](https://github.com/apache/superset/pull/19781) fix(world-map): remove categorical color control (@serenajiang) +- [#19792](https://github.com/apache/superset/pull/19792) fix(plugin-chart-table): Resetting controls when switching query mode (@kgabryje) +- [#19755](https://github.com/apache/superset/pull/19755) fix: small cleanup for created by me dashboards API (@dpgaspar) +- [#19784](https://github.com/apache/superset/pull/19784) fix(readme): Remove broken link to legacy gallery (@drluckyspin) +- [#19722](https://github.com/apache/superset/pull/19722) fix: dashboard top level tabs edit (@diegomedina248) +- [#19777](https://github.com/apache/superset/pull/19777) fix(explore): Double divider if no permissions for adding reports (@kgabryje) +- [#19673](https://github.com/apache/superset/pull/19673) fix(import): Add the error alert on failed database import (@prosdev0107) +- [#19518](https://github.com/apache/superset/pull/19518) fix: alert/report created by filter inconsistency with table display (@diegomedina248) +- [#19700](https://github.com/apache/superset/pull/19700) fix: remove expose (@AAfghahi) +- [#19626](https://github.com/apache/superset/pull/19626) fix: deactivate embedding on a dashboard (@suddjian) +- [#19472](https://github.com/apache/superset/pull/19472) fix: Dashboard Edit View Tab Headers Hidden when Dashboard Name is Long (@diegomedina248) +- [#19311](https://github.com/apache/superset/pull/19311) fix(sql lab): add quotes when autocompleting table names with spaces in the editor (@diegomedina248) +- [#19290](https://github.com/apache/superset/pull/19290) fix(sql lab): select edit on query from history doesn't upload editor properly (@diegomedina248) +- [#19420](https://github.com/apache/superset/pull/19420) fix: sql lab ctrl t behaved differently from clicking (@Gwitchr) +- [#19357](https://github.com/apache/superset/pull/19357) fix: Redirect to full url on 401 (@geido) +- [#19001](https://github.com/apache/superset/pull/19001) fix: Line Chart Annotation Info Update (@codemaster08240328) +- [#19714](https://github.com/apache/superset/pull/19714) fix: create virtual table with exotic type (@villebro) +- [#19708](https://github.com/apache/superset/pull/19708) fix(nav): infinite redirect and upload dataset nav permissions (@ktmud) +- [#19430](https://github.com/apache/superset/pull/19430) fix(data-upload): make to change err message (@prosdev0107) +- [#19419](https://github.com/apache/superset/pull/19419) fix(alert & report): make to fix the issue when recreate report (@prosdev0107) +- [#19371](https://github.com/apache/superset/pull/19371) fix: Reset sorting bar issue in Barchart (@codemaster08240328) +- [#19362](https://github.com/apache/superset/pull/19362) fix(sql lab): display the 'View Results' button consistently in the history tab on sync mode (@diegomedina248) +- [#19294](https://github.com/apache/superset/pull/19294) fix: improve alerts & reports modal on small devices (@diegomedina248) +- [#19257](https://github.com/apache/superset/pull/19257) fix(sql lab): table selector should display all the selected tables (@diegomedina248) +- [#19686](https://github.com/apache/superset/pull/19686) fix(plugin-chart-echarts): xAxis scale is not correct when time grain is quarter (@stephenLYZ) +- [#19646](https://github.com/apache/superset/pull/19646) fix(explore): Change copy of cross filters checkbox (@kgabryje) +- [#19586](https://github.com/apache/superset/pull/19586) fix: Navbar styles and Welcome page text (@geido) +- [#19662](https://github.com/apache/superset/pull/19662) fix(database-api): allow search for all columns (@villebro) +- [#19656](https://github.com/apache/superset/pull/19656) fix: allow_browser_login in import/export API (@betodealmeida) +- [#19628](https://github.com/apache/superset/pull/19628) fix: Table Autosizing Has Unnecessary Horizontal Scroll Bars (@diegomedina248) +- [#19573](https://github.com/apache/superset/pull/19573) fix(chart & polygon): make to fix the issue the polygon chart (@prosdev0107) +- [#19051](https://github.com/apache/superset/pull/19051) fix: update Permissions for right nav (@AAfghahi) +- [#19625](https://github.com/apache/superset/pull/19625) fix(test): make test_clean_requests_after_schema_grant more idempotent (@ktmud) +- [#19571](https://github.com/apache/superset/pull/19571) fix: Catch literal colors when theme top level (@geido) +- [#19594](https://github.com/apache/superset/pull/19594) fix: spelling of following (@lzm0) +- [#19569](https://github.com/apache/superset/pull/19569) fix: check type of url before performing string actions (@eschutho) +- [#19570](https://github.com/apache/superset/pull/19570) fix: sqloxide optional (@betodealmeida) +- [#19397](https://github.com/apache/superset/pull/19397) fix: weight tooltip issue (@codemaster08240328) +- [#19313](https://github.com/apache/superset/pull/19313) fix(sql lab): increase the size of the action icons in the history tab (@diegomedina248) +- [#19039](https://github.com/apache/superset/pull/19039) fix(explore): clean data when hidding control (@stephenLYZ) +- [#19444](https://github.com/apache/superset/pull/19444) fix: Error Message is cut off in alerts & reports log page (@codemaster08240328) +- [#19312](https://github.com/apache/superset/pull/19312) fix: adaptive formatting typo in explore dropdowns (@diegomedina248) +- [#19534](https://github.com/apache/superset/pull/19534) fix(explore): Chart header icon paddings (@kgabryje) +- [#19399](https://github.com/apache/superset/pull/19399) fix: native filter dropdown not attached to parent node (@diegomedina248) +- [#19112](https://github.com/apache/superset/pull/19112) fix: Dashboard import holding issue (@codemaster08240328) +- [#19342](https://github.com/apache/superset/pull/19342) fix: Clean up custom css when dashboard unmounted (@codemaster08240328) +- [#19491](https://github.com/apache/superset/pull/19491) fix: Dynamic form to connect to Snowflake DB is not displaying authentication errors (@diegomedina248) +- [#19528](https://github.com/apache/superset/pull/19528) fix: Correct Ukraine map (@wacken89) +- [#19522](https://github.com/apache/superset/pull/19522) fix: add back view for report reload error (@pkdotson) +- [#19519](https://github.com/apache/superset/pull/19519) fix: GSheets rendering from global nav (@hughhhh) +- [#19358](https://github.com/apache/superset/pull/19358) fix(sqllab): make to hide the delete button of most recent query history (@prosdev0107) +- [#19307](https://github.com/apache/superset/pull/19307) fix: Logo resizing on page load (@geido) +- [#19166](https://github.com/apache/superset/pull/19166) fix: time filter should be [start, end) (@zhaoyongjie) + +**Others** +- [#20116](https://github.com/apache/superset/pull/20116) style(typo): occured -> occurred (@sfirke) +- [#20401](https://github.com/apache/superset/pull/20401) chore: add action to welcome new users (@eschutho) +- [#20269](https://github.com/apache/superset/pull/20269) chore(docs): Remove cache warming documentation (@ajwhite) +- [#20194](https://github.com/apache/superset/pull/20194) chore: Removes unused vars (@michael-s-molina) +- [#20321](https://github.com/apache/superset/pull/20321) chore: add breaking change information about form_data datasource_type (@eschutho) +- [#20298](https://github.com/apache/superset/pull/20298) chore: Removes no-use-before-define warnings (@michael-s-molina) +- [#20337](https://github.com/apache/superset/pull/20337) chore(dashboard): update Edit Dashboard side panel tabs (@codyml) +- [#20318](https://github.com/apache/superset/pull/20318) chore: Updates the final steps of the release README (@michael-s-molina) +- [#20307](https://github.com/apache/superset/pull/20307) docs: Updates CHANGELOG.md with 1.5.1 fixes (@michael-s-molina) +- [#20308](https://github.com/apache/superset/pull/20308) docs(jinja): Detail how to use Jinja parameters (@EBoisseauSierra) +- [#20304](https://github.com/apache/superset/pull/20304) chore: superset-ui/core code coverage (@zhaoyongjie) +- [#20297](https://github.com/apache/superset/pull/20297) chore(deps): pinning pyjwt to 2.4.0 (@sadpandajoe) +- [#20287](https://github.com/apache/superset/pull/20287) chore(deps): bump numpy 1.22.1 and PyJWT to 2.4.0 (@sadpandajoe) +- [#20272](https://github.com/apache/superset/pull/20272) chore: remove unused codes for samples (@zhaoyongjie) +- [#20289](https://github.com/apache/superset/pull/20289) chore: Adjusts release emails (@michael-s-molina) +- [#20180](https://github.com/apache/superset/pull/20180) docs: facelift the docs (@mistercrunch) +- [#20249](https://github.com/apache/superset/pull/20249) chore: add event logger to reports/alerts CRUD (@AAfghahi) +- [#20273](https://github.com/apache/superset/pull/20273) chore: adjust the psycopg2 version of k8s installation guide (@ensky) +- [#20152](https://github.com/apache/superset/pull/20152) refactor(trino): Handful of updates for the Trino engine (@john-bodley) +- [#20252](https://github.com/apache/superset/pull/20252) chore: use exc_info to pass errors to log warnings (@eschutho) +- [#20154](https://github.com/apache/superset/pull/20154) chore(requirements): Cleanup of Python requirements (@john-bodley) +- [#20226](https://github.com/apache/superset/pull/20226) refactor: decouple DataTableControl (@zhaoyongjie) +- [#20243](https://github.com/apache/superset/pull/20243) docs: Add beans to users list (@kakoni) +- [#20231](https://github.com/apache/superset/pull/20231) docs: Updates release scripts and docs (@michael-s-molina) +- [#20196](https://github.com/apache/superset/pull/20196) chore: bumping min version of shillelagh (@AAfghahi) +- [#20192](https://github.com/apache/superset/pull/20192) chore: Moves date utils to utils folder (@michael-s-molina) +- [#20210](https://github.com/apache/superset/pull/20210) docs: update release instructions (@villebro) +- [#20205](https://github.com/apache/superset/pull/20205) chore(deps): bump swagger-ui-react from 4.1.2 to 4.1.3 in /docs (@dependabot[bot]) +- [#20195](https://github.com/apache/superset/pull/20195) docs: correct case of ClickHouse (@DanRoscigno) +- [#20109](https://github.com/apache/superset/pull/20109) refactor: decouple DataTablesPane (@zhaoyongjie) +- [#20193](https://github.com/apache/superset/pull/20193) refactor: Removes embedded/index.tsx warnings (@michael-s-molina) +- [#20185](https://github.com/apache/superset/pull/20185) docs(security): a typo: Gamma should be in quotes (@jimmytheneutrino) +- [#20146](https://github.com/apache/superset/pull/20146) chore: Implement global header in Dashboard (@geido) +- [#20174](https://github.com/apache/superset/pull/20174) chore: Disable flaky assert in reports cypress test (@kgabryje) +- [#20163](https://github.com/apache/superset/pull/20163) chore: change button name in Sql Lab (@AAfghahi) +- [#20157](https://github.com/apache/superset/pull/20157) chore: filter undefined operators (@zhaoyongjie) +- [#20140](https://github.com/apache/superset/pull/20140) chore(data-table): make formatted dttm the default (@villebro) +- [#20104](https://github.com/apache/superset/pull/20104) chore: fix INTHEWILD sort order and indentation (@villebro) +- [#20093](https://github.com/apache/superset/pull/20093) chore: Add the tnum font property to Table components (@geido) +- [#20103](https://github.com/apache/superset/pull/20103) docs: Update INTHEWILD.md (@fccoelho) +- [#20102](https://github.com/apache/superset/pull/20102) chore: Update aiohttp to 3.8.1 (@diegomedina248) +- [#20066](https://github.com/apache/superset/pull/20066) chore: Set limit for a query in execute_sql_statement (@AAfghahi) +- [#20032](https://github.com/apache/superset/pull/20032) chore: Change copy to Edit chart in Dashboard dropdown (@geido) +- [#20071](https://github.com/apache/superset/pull/20071) chore: Fix and enhance Applitools workflows (@geido) +- [#19966](https://github.com/apache/superset/pull/19966) test: make tabbed dashboard a little more complex (@ktmud) +- [#19976](https://github.com/apache/superset/pull/19976) perf(plugin-chart-table): Add memoization to avoid rerenders (@kgabryje) +- [#20044](https://github.com/apache/superset/pull/20044) chore: Create a generic header component for Explore and Dashboard (@kgabryje) +- [#20046](https://github.com/apache/superset/pull/20046) docs: add changelog and updating entries for 1.5.0 (@villebro) +- [#19962](https://github.com/apache/superset/pull/19962) chore: add doc link for db migration conflict warning (@ktmud) +- [#20034](https://github.com/apache/superset/pull/20034) chore: Changes the no-literal-colors lint rule to throw errors instead of warnings (@michael-s-molina) +- [#20031](https://github.com/apache/superset/pull/20031) chore: Run Applitools + Cypress nightly (@geido) +- [#20006](https://github.com/apache/superset/pull/20006) chore: Removes hard-coded colors from the plugins - iteration 2 (@michael-s-molina) +- [#19130](https://github.com/apache/superset/pull/19130) refactor: Refactor reports for Charts and Dashboards (@AAfghahi) +- [#20016](https://github.com/apache/superset/pull/20016) chore: Removes hard-coded colors - iteration 3 (@michael-s-molina) +- [#19870](https://github.com/apache/superset/pull/19870) docs: Detail front-end development instructions (@EBoisseauSierra) +- [#19971](https://github.com/apache/superset/pull/19971) docs: Add config for running on a WSGI HTTP server (@thinhnd2104) +- [#20008](https://github.com/apache/superset/pull/20008) chore: Upgrades Storybook from 6.4.19 to 6.4.22 (@michael-s-molina) +- [#20009](https://github.com/apache/superset/pull/20009) docs: typo in chart-params markdown file (@JakobMiksch) +- [#19923](https://github.com/apache/superset/pull/19923) chore: Removes hard-coded colors from the plugins - iteration 1 (@michael-s-molina) +- [#19954](https://github.com/apache/superset/pull/19954) chore: convert URLShortLinkButton to typescript (@ktmud) +- [#19929](https://github.com/apache/superset/pull/19929) chore: change subject name from no_name to named for PNGs in (@AAfghahi) +- [#19942](https://github.com/apache/superset/pull/19942) refactor(ReportModal): simplify state reducer and improve error handling (@ktmud) +- [#19770](https://github.com/apache/superset/pull/19770) chore: remove druid datasource from the config (@eschutho) +- [#19911](https://github.com/apache/superset/pull/19911) chore: Fix broken link for DouroECI (@mavimo) +- [#19951](https://github.com/apache/superset/pull/19951) chore: Adds the theme object to chart properties (@michael-s-molina) +- [#19813](https://github.com/apache/superset/pull/19813) chore: get embedded user with roles and permissions (@suddjian) +- [#19897](https://github.com/apache/superset/pull/19897) chore: Adds a storybook to FilterableTable (@michael-s-molina) +- [#19924](https://github.com/apache/superset/pull/19924) chore(reports): Improving logging around failed scheduled reports (@craig-rueda) +- [#19906](https://github.com/apache/superset/pull/19906) revert: "fix(sql lab): display the 'View Results' button consistently in the history tab on sync mode" (@Gwitchr) +- [#19916](https://github.com/apache/superset/pull/19916) chore(deps): bump react-virtualized-auto-sizer from 1.0.2 to 1.0.6 in /superset-frontend (@dependabot[bot]) +- [#19888](https://github.com/apache/superset/pull/19888) chore(deps): bump cross-fetch from 3.1.4 to 3.1.5 in /docs (@dependabot[bot]) +- [#19894](https://github.com/apache/superset/pull/19894) chore(deps-dev): bump eslint-plugin-prettier from 3.3.1 to 4.0.0 in /superset-frontend (@dependabot[bot]) +- [#19602](https://github.com/apache/superset/pull/19602) docs: Added gtag to docusaurus (@AAfghahi) +- [#19878](https://github.com/apache/superset/pull/19878) chore(deps-dev): bump @storybook/client-api from 6.4.19 to 6.4.22 in /superset-frontend (@dependabot[bot]) +- [#19821](https://github.com/apache/superset/pull/19821) test(native filter): refactor and add new test (@jinghua-qa) +- [#19613](https://github.com/apache/superset/pull/19613) chore: Update line-height in SliceHeaderControl (@geido) +- [#19616](https://github.com/apache/superset/pull/19616) chore: Update font-sizes in DatabaseModal (@geido) +- [#19866](https://github.com/apache/superset/pull/19866) chore: fix explore pills (@villebro) +- [#19872](https://github.com/apache/superset/pull/19872) chore: Update aiohttp>=3.7.4 in requirements (@hughhhh) +- [#19874](https://github.com/apache/superset/pull/19874) chore: bump rockset>=0.8.10, <0.9 (@hughhhh) +- [#19864](https://github.com/apache/superset/pull/19864) chore(deps): bump react-syntax-highlighter from 15.4.5 to 15.5.0 in /superset-frontend (@dependabot[bot]) +- [#19828](https://github.com/apache/superset/pull/19828) chore: add custom eslint plugin to prevent translation variables (@stephenLYZ) +- [#19845](https://github.com/apache/superset/pull/19845) chore(deps): bump react-split from 2.0.9 to 2.0.14 in /superset-frontend (@dependabot[bot]) +- [#19846](https://github.com/apache/superset/pull/19846) chore(deps): bump d3-svg-legend from 1.13.0 to 2.25.6 in /superset-frontend (@dependabot[bot]) +- [#19847](https://github.com/apache/superset/pull/19847) chore(deps-dev): bump eslint-plugin-jsx-a11y from 6.4.1 to 6.5.1 in /superset-frontend (@dependabot[bot]) +- [#19853](https://github.com/apache/superset/pull/19853) chore(frontend-tests): Spelling (@jsoref) +- [#19823](https://github.com/apache/superset/pull/19823) docs: updated links for country map scripts (@ktmud) +- [#19829](https://github.com/apache/superset/pull/19829) chore(deps-dev): bump babel-loader from 8.2.4 to 8.2.5 in /superset-frontend (@dependabot[bot]) +- [#19830](https://github.com/apache/superset/pull/19830) chore(deps): bump react-hot-loader from 4.12.20 to 4.13.0 in /superset-frontend (@dependabot[bot]) +- [#19403](https://github.com/apache/superset/pull/19403) chore(deps-dev): bump babel-loader from 8.2.2 to 8.2.4 in /superset-frontend (@dependabot[bot]) +- [#19637](https://github.com/apache/superset/pull/19637) chore(deps): bump moment from 2.29.1 to 2.29.2 in /superset-frontend (@dependabot[bot]) +- [#19681](https://github.com/apache/superset/pull/19681) chore(deps): bump async from 3.2.0 to 3.2.3 in /superset-frontend/cypress-base (@dependabot[bot]) +- [#19680](https://github.com/apache/superset/pull/19680) chore(deps): bump async from 3.2.0 to 3.2.3 in /superset-websocket (@dependabot[bot]) +- [#19020](https://github.com/apache/superset/pull/19020) chore(deps): bump url-parse from 1.5.7 to 1.5.10 in /superset-frontend (@dependabot[bot]) +- [#17978](https://github.com/apache/superset/pull/17978) chore(deps): bump @types/d3-time from 1.1.1 to 3.0.0 in /superset-frontend (@dependabot[bot]) +- [#19727](https://github.com/apache/superset/pull/19727) chore(deps): bump async from 2.6.3 to 2.6.4 in /docs (@dependabot[bot]) +- [#19551](https://github.com/apache/superset/pull/19551) chore(deps): bump minimist from 1.2.5 to 1.2.6 in /superset-websocket (@dependabot[bot]) +- [#19165](https://github.com/apache/superset/pull/19165) chore: simplify error messaging in database modal (@pkdotson) +- [#19790](https://github.com/apache/superset/pull/19790) chore: bump postgres from 10 to 14 (@dpgaspar) +- [#19480](https://github.com/apache/superset/pull/19480) chore: Update UPDATING.md (@john-bodley) +- [#19740](https://github.com/apache/superset/pull/19740) chore: fix grammar error (@zhaoyongjie) +- [#19703](https://github.com/apache/superset/pull/19703) chore(build): upgrade less-loader (@ktmud) +- [#19736](https://github.com/apache/superset/pull/19736) chore: Updates the Select code owners (@michael-s-molina) +- [#19715](https://github.com/apache/superset/pull/19715) docs(install): ubuntu default-libmysqlclient-dev (@cemremengu) +- [#19726](https://github.com/apache/superset/pull/19726) chore: bumping shillelagh (@AAfghahi) +- [#19699](https://github.com/apache/superset/pull/19699) chore: fix typo (@betodealmeida) +- [#19674](https://github.com/apache/superset/pull/19674) chore: upgrade Pillow (@betodealmeida) +- [#19647](https://github.com/apache/superset/pull/19647) chore(explore): Change labels "Group by"/"Series" to "Dimensions" (@kgabryje) +- [#19679](https://github.com/apache/superset/pull/19679) chore(deps): bump urijs from 1.19.8 to 1.19.11 in /superset-frontend (@dependabot[bot]) +- [#19638](https://github.com/apache/superset/pull/19638) chore(deps): bump moment from 2.29.1 to 2.29.2 in /docs (@dependabot[bot]) +- [#19617](https://github.com/apache/superset/pull/19617) chore: updated two github issue templates (@srinify) +- [#19666](https://github.com/apache/superset/pull/19666) chore: Remove TwoTone icons (@geido) +- [#19614](https://github.com/apache/superset/pull/19614) chore: Remove wrong usage of font-size in ExploreViewContainer (@geido) +- [#19593](https://github.com/apache/superset/pull/19593) chore: Update font-sizes in ReportModal (@geido) +- [#19611](https://github.com/apache/superset/pull/19611) chore: Update font-sizes in ImportModal (@geido) +- [#19615](https://github.com/apache/superset/pull/19615) chore: Update font-sizes in AlertReportModal (@geido) +- [#19620](https://github.com/apache/superset/pull/19620) chore: Update font-sizes in QueryPreviewModal (@geido) +- [#19641](https://github.com/apache/superset/pull/19641) chore: clean up dynamic translation strings (@villebro) +- [#19635](https://github.com/apache/superset/pull/19635) refactor: consistent migration tests organization (@ktmud) +- [#19634](https://github.com/apache/superset/pull/19634) test: freeze time for dashboard export test (@ktmud) +- [#19606](https://github.com/apache/superset/pull/19606) test(jinja): refactor to functional tests (@villebro) +- [#19587](https://github.com/apache/superset/pull/19587) chore: cleanup as unknown conversion (@zhaoyongjie) +- [#19562](https://github.com/apache/superset/pull/19562) refactor: Removes the CSS files from the Horizon plugin (@michael-s-molina) +- [#19563](https://github.com/apache/superset/pull/19563) refactor: Removes the CSS files from the Paired T-Test plugin (@michael-s-molina) +- [#19539](https://github.com/apache/superset/pull/19539) refactor: Removes the CSS files from the Parallel Coordinates plugin (@michael-s-molina) +- [#19521](https://github.com/apache/superset/pull/19521) refactor: Removes the CSS files from the Partition plugin (@michael-s-molina) +- [#19493](https://github.com/apache/superset/pull/19493) chore: Removes hard-coded colors from legacy-plugin-chart-sankey (@michael-s-molina) +- [#19462](https://github.com/apache/superset/pull/19462) chore: Remove FilterBox.less (@geido) +- [#19438](https://github.com/apache/superset/pull/19438) chore: Remove crud.less from Datasource (@geido) +- [#19517](https://github.com/apache/superset/pull/19517) chore: Enhance ReactChord style with theme vars (@geido) +- [#19463](https://github.com/apache/superset/pull/19463) chore: Remove TimeTable.less (@geido) +- [#19550](https://github.com/apache/superset/pull/19550) chore(deps): bump minimist from 1.2.5 to 1.2.6 in /superset-embedded-sdk (@dependabot[bot]) +- [#19566](https://github.com/apache/superset/pull/19566) chore(deps): bump node-forge from 1.2.1 to 1.3.1 in /docs (@dependabot[bot]) +- [#19552](https://github.com/apache/superset/pull/19552) chore(deps): bump minimist from 1.2.5 to 1.2.6 in /docs (@dependabot[bot]) +- [#19549](https://github.com/apache/superset/pull/19549) chore(deps): bump minimist from 1.2.5 to 1.2.6 in /superset-frontend/cypress-base (@dependabot[bot]) +- [#19559](https://github.com/apache/superset/pull/19559) docs: update the typo in the documentation (@fatosmorina) +- [#19538](https://github.com/apache/superset/pull/19538) refactor: Removes the CSS files from the Country Map plugin (@michael-s-molina) +- [#19536](https://github.com/apache/superset/pull/19536) chore: Removes hard-coded opacity and spacing from the BigNumber plugin (@michael-s-molina) +- [#19494](https://github.com/apache/superset/pull/19494) refactor: Removes the CSS files from the Sankey Loop plugin (@michael-s-molina) +- [#19492](https://github.com/apache/superset/pull/19492) chore: Remove Legacy Force Directed viz plugin (@geido) +- [#19524](https://github.com/apache/superset/pull/19524) chore: Deprecating /my_queries endpoint (@AAfghahi) +- [#19467](https://github.com/apache/superset/pull/19467) chore(Explore): Change text when saving a chart in a new dashboard (@geido) +- [#19526](https://github.com/apache/superset/pull/19526) chore(database): Creating helper make_url_safe to wrap potential errors (@craig-rueda) +- [#19415](https://github.com/apache/superset/pull/19415) chore: Remove Control.less in Explore (@geido) +- [#19413](https://github.com/apache/superset/pull/19413) chore: Remove unused less file from profile (@geido) +- [#19460](https://github.com/apache/superset/pull/19460) chore: Switch to gender neutral terms (@inclusive-coding-bot) +- [#19486](https://github.com/apache/superset/pull/19486) refactor: Removes the CSS files from the Treemap plugin (@michael-s-molina) +- [#19488](https://github.com/apache/superset/pull/19488) refactor: Removes the CSS files from the Sunburst plugin (@michael-s-molina) +- [#19490](https://github.com/apache/superset/pull/19490) chore: Add theme color to ParallelCoordinates (@geido) +- [#19442](https://github.com/apache/superset/pull/19442) chore: Remove FilterbaleTableStyles.less (@geido) +- [#19441](https://github.com/apache/superset/pull/19441) chore: Remove StyledQueryButton.less (@geido) +- [#19473](https://github.com/apache/superset/pull/19473) refactor: Removes the CSS files from the Rose plugin (@michael-s-molina) +- [#19466](https://github.com/apache/superset/pull/19466) chore: Removes hard-coded colors from legacy-plugin-chart-world-map (@michael-s-molina) +- [#19465](https://github.com/apache/superset/pull/19465) refactor: Removes the CSS files from the DeckGL plugin (@michael-s-molina) +- [#19440](https://github.com/apache/superset/pull/19440) chore: Remove index.less from showSavedQuery (@geido) +- [#19230](https://github.com/apache/superset/pull/19230) chore!: remove `ROW_LEVEL_SECURITY` feature flag (permanently enable) (@suddjian) +- [#19361](https://github.com/apache/superset/pull/19361) chore: remove deprecated config keys and endpoints code 2.0 (@pkdotson) +- [#19261](https://github.com/apache/superset/pull/19261) chore: remove old alerts and configs keys (@pkdotson) +- [#19168](https://github.com/apache/superset/pull/19168) chore: bump celery and Flask (@dpgaspar) +- [#19049](https://github.com/apache/superset/pull/19049) chore: Remove logo forced width (@geido) +- [#19274](https://github.com/apache/superset/pull/19274) chore: remove PUBLIC_ROLE_LIKE_GAMMA deprecated config key (@dpgaspar) +- [#19273](https://github.com/apache/superset/pull/19273) chore: remove deprecated celery cli (@dpgaspar) +- [#19262](https://github.com/apache/superset/pull/19262) chore: update updating with druid no sql deprecation (@eschutho) +- [#19083](https://github.com/apache/superset/pull/19083) chore!: update mutator to take kwargs (@eschutho) +- [#19231](https://github.com/apache/superset/pull/19231) chore!: remove `ENABLE_REACT_CRUD_VIEWS` feature flag (permanently enable) (@suddjian) +- [#19241](https://github.com/apache/superset/pull/19241) chore(superset 2.0): remove front-end deprecated code (@graceguo-supercat) +- [#19107](https://github.com/apache/superset/pull/19107) chore: turn on SQLLAB_BACKEND_PERSISTENCE by default (@ktmud) +- [#19142](https://github.com/apache/superset/pull/19142) chore!: turn on Versioned Export in config.py (@AAfghahi) +- [#19108](https://github.com/apache/superset/pull/19108) chore: Update UPDATING.md with info about flipping dnd feature flag (@kgabryje) +- [#19146](https://github.com/apache/superset/pull/19146) chore!: Remove remove SQLALCHEMY_DOCS_URL and SQLALCHEMY_DISPLAY_TEXT from the config from the config (@hughhhh) +- [#19017](https://github.com/apache/superset/pull/19017) chore: Deprecate Python 3.7 (@john-bodley) +- [#19113](https://github.com/apache/superset/pull/19113) chore(config): Migrating `ENABLE_JAVASCRIPT_CONTROLS` from app config to a feature flag (@rusackas) +- [#19046](https://github.com/apache/superset/pull/19046) chore(explore): Set Drag&Drop feature flags to True by default (@kgabryje) +- [#19016](https://github.com/apache/superset/pull/19016) chore: Adding PR to Updating.md (@AAfghahi) +- [#18970](https://github.com/apache/superset/pull/18970) chore: Change Dataset legacy editor flag to true (@AAfghahi) diff --git a/RELEASING/test_run_tarball.sh b/RELEASING/test_run_tarball.sh index 112adc8cffacd..d4c8a9c706a05 100755 --- a/RELEASING/test_run_tarball.sh +++ b/RELEASING/test_run_tarball.sh @@ -26,7 +26,7 @@ if [ -z "${SUPERSET_SVN_DEV_PATH}" ]; then SUPERSET_SVN_DEV_PATH="$HOME/svn/superset_dev" fi -if [ ${1} == "local" ]; then +if [[ -n ${1} ]] && [[ ${1} == "local" ]]; then SUPERSET_RELEASE_RC=apache-superset-"${SUPERSET_VERSION_RC}" SUPERSET_RELEASE_RC_TARBALL="${SUPERSET_RELEASE_RC}"-source.tar.gz SUPERSET_TARBALL_PATH="${SUPERSET_SVN_DEV_PATH}"/${SUPERSET_VERSION_RC}/${SUPERSET_RELEASE_RC_TARBALL} diff --git a/RESOURCES/FEATURE_FLAGS.md b/RESOURCES/FEATURE_FLAGS.md index 26ac6bfde9435..aa4d6c635565d 100644 --- a/RESOURCES/FEATURE_FLAGS.md +++ b/RESOURCES/FEATURE_FLAGS.md @@ -16,49 +16,86 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> + # Superset Feature Flags + This is a list of the current Superset optional features. See config.py for default values. These features can be turned on/off by setting your preferred values in superset_config.py to True/False respectively ## In Development + These features are considered **unfinished** and should only be used on development environments. +[//]: # "PLEASE KEEP THE LIST SORTED ALPHABETICALLY" + - CLIENT_CACHE - DASHBOARD_CACHE - DASHBOARD_NATIVE_FILTERS_SET - DISABLE_DATASET_SOURCE_EDIT +- DRILL_TO_DETAIL +- ENABLE_ADVANCED_DATA_TYPES - ENABLE_EXPLORE_JSON_CSRF_PROTECTION +- ENABLE_TEMPLATE_REMOVE_FILTERS +- HORIZONTAL_FILTER_BAR - KV_STORE - PRESTO_EXPAND_DATA - REMOVE_SLICE_LEVEL_LABEL_COLORS - SHARE_QUERIES_VIA_KV_STORE - TAGGING_SYSTEM -- ENABLE_TEMPLATE_REMOVE_FILTERS ## In Testing + These features are **finished** but currently being tested. They are usable, but may still contain some bugs. +[//]: # "PLEASE KEEP THE LIST SORTED ALPHABETICALLY" + - ALERT_REPORTS: [(docs)](https://superset.apache.org/docs/installation/alerts-reports) -- DYNAMIC_PLUGINS: [(docs)](https://superset.apache.org/docs/installation/running-on-kubernetes) +- ALLOW_FULL_CSV_EXPORT +- CACHE_IMPERSONATION +- CONFIRM_DASHBOARD_DIFF +- DASHBOARD_EDIT_CHART_IN_NEW_TAB +- DASHBOARD_FILTERS_EXPERIMENTAL - DASHBOARD_NATIVE_FILTERS +- DYNAMIC_PLUGINS: [(docs)](https://superset.apache.org/docs/installation/running-on-kubernetes) +- ENABLE_FILTER_BOX_MIGRATION +- ENABLE_JAVASCRIPT_CONTROLS +- GENERIC_CHART_AXES - GLOBAL_ASYNC_QUERIES [(docs)](https://github.com/apache/superset/blob/master/CONTRIBUTING.md#async-chart-queries) +- RLS_IN_SQLLAB +- USE_ANALAGOUS_COLORS +- UX_BETA - VERSIONED_EXPORT -- ENABLE_JAVASCRIPT_CONTROLS ## Stable + These features flags are **safe for production** and have been tested. +[//]: # "PLEASE KEEP THE LIST SORTED ALPHABETICALLY" + +- ALERTS_ATTACH_REPORTS +- ALLOW_ADHOC_SUBQUERY - DASHBOARD_CROSS_FILTERS - DASHBOARD_RBAC [(docs)](https://superset.apache.org/docs/creating-charts-dashboards/first-dashboard#manage-access-to-dashboards) -- ESCAPE_MARKDOWN_HTML +- DISABLE_LEGACY_DATASOURCE_EDITOR +- DRUID_JOINS +- EMBEDDABLE_CHARTS +- EMBEDDED_SUPERSET +- ENABLE_DND_WITH_CLICK_UX +- ENABLE_EXPLORE_DRAG_AND_DROP - ENABLE_TEMPLATE_PROCESSING +- ENFORCE_DB_ENCRYPTION_UI +- ESCAPE_MARKDOWN_HTML - LISTVIEWS_DEFAULT_CARD_VIEW - SCHEDULED_QUERIES [(docs)](https://superset.apache.org/docs/installation/alerts-reports) -- SQL_VALIDATORS_BY_ENGINE [(docs)](https://superset.apache.org/docs/installation/sql-templating) - SQLLAB_BACKEND_PERSISTENCE +- SQL_VALIDATORS_BY_ENGINE [(docs)](https://superset.apache.org/docs/installation/sql-templating) - THUMBNAILS [(docs)](https://superset.apache.org/docs/installation/cache) ## Deprecated Flags + These features flags currently default to True and **will be removed in a future major release**. For this current release you can turn them off by setting your config to False, but it is advised to remove or set these flags in your local configuration to **True** so that you do not experience any unexpected changes in a future release. +[//]: # "PLEASE KEEP THE LIST SORTED ALPHABETICALLY" + - ALLOW_DASHBOARD_DOMAIN_SHARDING - DISPLAY_MARKDOWN_HTML +- FORCE_DATABASE_CONNECTIONS_SSL diff --git a/RESOURCES/INTHEWILD.md b/RESOURCES/INTHEWILD.md index 61c000bf36f7f..0f1cf65c55745 100644 --- a/RESOURCES/INTHEWILD.md +++ b/RESOURCES/INTHEWILD.md @@ -40,6 +40,8 @@ Join our growing community! - [Cape Crypto](https://capecrypto.com) - [Capital Service S.A.](http://capitalservice.pl) [@pkonarzewski] - [Clark.de](http://clark.de/) +- [KarrotPay](https://www.daangnpay.com/) +- [Wise](https://wise.com) [@koszti] - [Xendit](http://xendit.co/) [@LieAlbertTriAdrian] ### Gaming @@ -48,6 +50,7 @@ Join our growing community! ### E-Commerce - [AiHello](https://www.aihello.com) [@ganeshkrishnan1] +- [Bazaar Technologies](https://www.bazaartech.com) [@umair-abro] - [Dragonpass](https://www.dragonpass.com.cn/) [@zhxjdwh] - [Fanatics](https://www.fanatics.com) [@coderfender] - [Fordeal](http://www.fordeal.com) [@Renkai] @@ -70,6 +73,8 @@ Join our growing community! - [Apollo GraphQL](https://www.apollographql.com/) [@evans] - [Astronomer](https://www.astronomer.io) [@ryw] - [Avesta Technologies](https://avestatechnologies.com/) [@TheRum] +- [Caizin](https://caizin.com/) [@tejaskatariya] +- [Careem](https://www.careem.com/) [@SamraHanifCareem] - [Cloudsmith](https://cloudsmith.io) [@alancarson] - [CnOvit](http://www.cnovit.com/) [@xieshaohu] - [Deepomatic](https://deepomatic.com/) [@Zanoellia] @@ -84,10 +89,13 @@ Join our growing community! - [Intercom](https://www.intercom.com/) [@kate-gallo] - [jampp](https://jampp.com/) - [Konfío](http://konfio.mx) [@uis-rodriguez] +- [Mainstrat](https://mainstrat.com/) - [mishmash io](https://mishmash.io/)[@mishmash-io] - [Myra Labs](http://www.myralabs.com/) [@viksit] - [Nielsen](http://www.nielsen.com/) [@amitNielsen] - [Ona](https://ona.io) [@pld] +- [Orange](https://www.orange.com) [@icsu] +- [Oslandia](https://oslandia.com) - [Peak AI](https://www.peak.ai/) [@azhar22k] - [PeopleDoc](https://www.people-doc.com) [@rodo] - [Preset, Inc.](https://preset.io) @@ -120,10 +128,12 @@ Join our growing community! ### Education - [Brilliant.org](https://brilliant.org/) +- [Platzi.com](https://platzi.com/) - [Sunbird](https://www.sunbird.org/) [@eksteporg] - [The GRAPH Network](https://thegraphnetwork.org/)[@fccoelho] - [Udemy](https://www.udemy.com/) [@sungjuly] - [VIPKID](https://www.vipkid.com.cn/) [@illpanda] +- [WikiMedia Foundation](https://wikimediafoundation.org) [@vg] ### Energy - [Airboxlab](https://foobot.io) [@antoine-galataud] @@ -138,13 +148,25 @@ Join our growing community! - [Living Goods](https://www.livinggoods.org) [@chelule] - [Maieutical Labs](https://maieuticallabs.it) [@xrmx] - [QPID Health](http://www.qpidhealth.com/) +- [REDCap Cloud](https://www.redcapcloud.com/) - [TrustMedis](https://trustmedis.com) [@famasya] - [WeSure](https://www.wesure.cn/) ### HR / Staffing +- [Swile](https://www.swile.co/) [@PaoloTerzi] - [Symmetrics](https://www.symmetrics.fyi) +### News +- [Prensa Iberica](https://www.prensaiberica.es/) [@zamar-roura] + +### Government +- [City of Ann Arbor, MI](https://www.a2gov.org/) [@sfirke] + +### Travel +- [Skyscanner](https://www.skyscanner.net/) [@cleslie, @stanhoucke] + ### Others +- [AI inside](https://inside.ai/en/) - [Dropbox](https://www.dropbox.com/) [@bkyryliuk] - [Grassroot](https://www.grassrootinstitute.org/) - [komoot](https://www.komoot.com/) [@christophlingg] diff --git a/UPDATING.md b/UPDATING.md index abfe9a915e6fb..c57098cb0b743 100644 --- a/UPDATING.md +++ b/UPDATING.md @@ -34,6 +34,38 @@ assists people when migrating to a new version. ## 2.0.0 +- [22022](https://github.com/apache/superset/pull/22022): HTTP API endpoints `/superset/approve` and `/superset/request_access` have been deprecated and their HTTP methods were changed from GET to POST +- [20606](https://github.com/apache/superset/pull/20606): When user clicks on chart title or "Edit chart" button in Dashboard page, Explore opens in the same tab. Clicking while holding cmd/ctrl opens Explore in a new tab. To bring back the old behaviour (always opening Explore in a new tab), flip feature flag `DASHBOARD_EDIT_CHART_IN_NEW_TAB` to `True`. +- [20799](https://github.com/apache/superset/pull/20799): Presto and Trino engine will now display tracking URL for running queries in SQL Lab. If for some reason you don't want to show the tracking URL (for example, when your data warehouse hasn't enabled access for to Presto or Trino UI), update `TRACKING_URL_TRANSFORMER` in `config.py` to return `None`. +- [21002](https://github.com/apache/superset/pull/21002): Support Python 3.10 and bump pandas 1.4 and pyarrow 6. +- [21163](https://github.com/apache/superset/pull/21163): The time grain will be decoupled from the time filter column and the time grain control will move below the X-Axis control when `GENERIC_CHART_AXES` feature flags set to `True`. The time grain will be applied on the time column in the column-like controls(x axis, dimensions) instead of the time column in the time section. +- [21284](https://github.com/apache/superset/pull/21284): The non-functional `MAX_TABLE_NAMES` config key has been removed. +- [21794](https://github.com/apache/superset/pull/21794): Deprecates the undocumented `PRESTO_SPLIT_VIEWS_FROM_TABLES` feature flag. Now for Presto, like other engines, only physical tables are treated as tables. + +### Breaking Changes + +- [22798](https://github.com/apache/superset/pull/22798): To make the welcome page more relevant in production environments, the last tab on the welcome page has been changed from to feature all charts/dashboards the user has access to (previously only examples were shown). To keep current behavior unchanged, add the following to your `superset_config.py`: `WELCOME_PAGE_LAST_TAB = "examples"` +- [22328](https://github.com/apache/superset/pull/22328): For deployments that have enabled the "THUMBNAILS" feature flag, the function that calculates dashboard digests has been updated to consider additional properties to more accurately identify changes in the dashboard metadata. This change will invalidate all currently cached dashboard thumbnails. +- [21765](https://github.com/apache/superset/pull/21765): For deployments that have enabled the "ALERT_REPORTS" feature flag, Gamma users will no longer have read and write access to Alerts & Reports by default. To give Gamma users the ability to schedule reports from the Dashboard and Explore view like before, create an additional role with "can read on ReportSchedule" and "can write on ReportSchedule" permissions. To further give Gamma users access to the "Alerts & Reports" menu and CRUD view, add "menu access on Manage" and "menu access on Alerts & Report" permissions to the role. + +### Potential Downtime + +- [21284](https://github.com/apache/superset/pull/21284): A change which drops the unused `dbs.allow_multi_schema_metadata_fetch` column via a (potentially locking) DDL operation. + +### Other + +## 2.0.1 + +- [21895](https://github.com/apache/superset/pull/21895): Markdown components had their security increased by adhering to the same sanitization process enforced by Github. This means that some HTML elements found in markdowns are not allowed anymore due to the security risks they impose. If you're deploying Superset in a trusted environment and wish to use some of the blocked elements, then you can use the HTML_SANITIZATION_SCHEMA_EXTENSIONS configuration to extend the default sanitization schema. There's also the option to disable HTML sanitization using the HTML_SANITIZATION configuration but we do not recommend this approach because of the security risks. Given the provided configurations, we don't view the improved sanitization as a breaking change but as a security patch. + +## Breaking Changes + +## Potential Downtime + +## Other + +## 2.0.0 + - [19046](https://github.com/apache/superset/pull/19046): Enables the drag and drop interface in Explore control panel by default. Flips `ENABLE_EXPLORE_DRAG_AND_DROP` and `ENABLE_DND_WITH_CLICK_UX` feature flags to `True`. - [18936](https://github.com/apache/superset/pull/18936): Removes legacy SIP-15 interim logic/flags—specifically the `SIP_15_ENABLED`, `SIP_15_GRACE_PERIOD_END`, `SIP_15_DEFAULT_TIME_RANGE_ENDPOINTS`, and `SIP_15_TOAST_MESSAGE` flags. Time range endpoints are no longer configurable and strictly adhere to the `[start, end)` paradigm, i.e., inclusive of the start and exclusive of the end. Additionally this change removes the now obsolete `time_range_endpoints` from the form-data and resulting in the cache being busted. - [19570](https://github.com/apache/superset/pull/19570): makes [sqloxide](https://pypi.org/project/sqloxide/) optional so the SIP-68 migration can be run on aarch64. If the migration is taking too long installing sqloxide manually should improve the performance. @@ -56,6 +88,19 @@ assists people when migrating to a new version. - [19017](https://github.com/apache/superset/pull/19017): Removes Python 3.7 support. - [18970](https://github.com/apache/superset/pull/18970): The `DISABLE_LEGACY_DATASOURCE_EDITOR` feature flag is now `True` by default which disables the legacy datasource editor from being shown in the client. +## 1.5.3 + +### Other + +- [22022](https://github.com/apache/superset/pull/22022): HTTP API endpoints `/superset/approve` and `/superset/request_access` have been deprecated and their HTTP methods were changed from GET to POST +- [21895](https://github.com/apache/superset/pull/21895): Markdown components had their security increased by adhering to the same sanitization process enforced by Github. This means that some HTML elements found in markdowns are not allowed anymore due to the security risks they impose. If you're deploying Superset in a trusted environment and wish to use some of the blocked elements, then you can use the HTML_SANITIZATION_SCHEMA_EXTENSIONS configuration to extend the default sanitization schema. There's also the option to disable HTML sanitization using the HTML_SANITIZATION configuration but we do not recommend this approach because of the security risks. Given the provided configurations, we don't view the improved sanitization as a breaking change but as a security patch. + +## 1.5.2 + +### Other + +- [19570](https://github.com/apache/superset/pull/19570): makes [sqloxide](https://pypi.org/project/sqloxide/) optional so the SIP-68 migration can be run on aarch64. If the migration is taking too long installing sqloxide manually should improve the performance. + ## 1.5.0 ### Breaking Changes diff --git a/cccs-build/superset/Dockerfile b/cccs-build/superset/Dockerfile index ff5572bbaded2..129d127688c42 100644 --- a/cccs-build/superset/Dockerfile +++ b/cccs-build/superset/Dockerfile @@ -1,7 +1,7 @@ # Vault CA container import -ARG VAULT_CA_CONTAINER=uchimera.azurecr.io/cccs/hogwarts/vault-ca:master_2921_22315d60 +ARG VAULT_CA_CONTAINER=uchimera.azurecr.io/cccs/hogwarts/vault-ca:master_11376_a25c34e1 FROM $VAULT_CA_CONTAINER AS vault_ca -FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1932-update-cccs-main-to-2.0.1-add-cccs-2.0_20230214125009_b6247 +FROM uchimera.azurecr.io/cccs/superset-base:feature_update-cccs-main-to-2.1.0-add-cccs-2.0_20230425191536_b6649 USER root diff --git a/cccs-build/superset/requirements.txt b/cccs-build/superset/requirements.txt index 16c4b3b74ebcf..c00ba75cd3330 100644 --- a/cccs-build/superset/requirements.txt +++ b/cccs-build/superset/requirements.txt @@ -9,4 +9,4 @@ trino==0.318.0 mysql-connector-python==8.0.26 elasticsearch-dbapi==0.2.4 cachetools~=5.0.0 -typing-extensions<4,>=3.10 +typing-extensions>=4, <5 diff --git a/docker-compose-non-dev.yml b/docker-compose-non-dev.yml index 934349667709a..e72222655184b 100644 --- a/docker-compose-non-dev.yml +++ b/docker-compose-non-dev.yml @@ -26,7 +26,7 @@ x-superset-volumes: &superset-volumes version: "3.7" services: redis: - image: redis:latest + image: redis:7 container_name: superset_cache restart: unless-stopped volumes: @@ -34,7 +34,7 @@ services: db: env_file: docker/.env-non-dev - image: postgres:10 + image: postgres:14 container_name: superset_db restart: unless-stopped volumes: @@ -60,6 +60,8 @@ services: depends_on: *superset-depends-on user: "root" volumes: *superset-volumes + healthcheck: + disable: true superset-worker: image: *superset-image @@ -70,6 +72,8 @@ services: depends_on: *superset-depends-on user: "root" volumes: *superset-volumes + healthcheck: + test: ["CMD-SHELL", "celery inspect ping -A superset.tasks.celery_app:app -d celery@$$HOSTNAME"] superset-worker-beat: image: *superset-image @@ -80,6 +84,8 @@ services: depends_on: *superset-depends-on user: "root" volumes: *superset-volumes + healthcheck: + disable: true volumes: superset_home: diff --git a/docker-compose.yml b/docker-compose.yml index 2c814363e784c..89aecfd9e0e4f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,7 +30,7 @@ x-superset-volumes: &superset-volumes version: "3.7" services: redis: - image: redis:latest + image: redis:7 container_name: superset_cache restart: unless-stopped ports: @@ -100,6 +100,8 @@ services: volumes: *superset-volumes environment: CYPRESS_CONFIG: "${CYPRESS_CONFIG}" + healthcheck: + disable: true superset-node: image: node:16 @@ -118,6 +120,8 @@ services: depends_on: *superset-depends-on user: *superset-user volumes: *superset-volumes + healthcheck: + test: ["CMD-SHELL", "celery inspect ping -A superset.tasks.celery_app:app -d celery@$$HOSTNAME"] # Bump memory limit if processing selenium / thumbnails on superset-worker # mem_limit: 2038m # mem_reservation: 128M @@ -131,6 +135,8 @@ services: depends_on: *superset-depends-on user: *superset-user volumes: *superset-volumes + healthcheck: + disable: true superset-tests-worker: image: *superset-image @@ -147,6 +153,8 @@ services: depends_on: *superset-depends-on user: *superset-user volumes: *superset-volumes + healthcheck: + test: ["CMD-SHELL", "celery inspect ping -A superset.tasks.celery_app:app -d celery@$$HOSTNAME"] volumes: superset_home: diff --git a/docker/.env b/docker/.env index b31d631f2f707..8fa6f45333559 100644 --- a/docker/.env +++ b/docker/.env @@ -23,7 +23,7 @@ DATABASE_PASSWORD=superset DATABASE_USER=superset # database engine specific environment variables -# change the below if you prefers another database engine +# change the below if you prefer another database engine DATABASE_PORT=5432 DATABASE_DIALECT=postgresql POSTGRES_DB=superset @@ -47,3 +47,4 @@ SUPERSET_ENV=development SUPERSET_LOAD_EXAMPLES=yes CYPRESS_CONFIG=false SUPERSET_PORT=8088 +MAPBOX_API_KEY='' diff --git a/docker/.env-non-dev b/docker/.env-non-dev index 1cb5d30bdbbbe..0ae4c1c7932bb 100644 --- a/docker/.env-non-dev +++ b/docker/.env-non-dev @@ -23,7 +23,7 @@ DATABASE_PASSWORD=superset DATABASE_USER=superset # database engine specific environment variables -# change the below if you prefers another database engine +# change the below if you prefer another database engine DATABASE_PORT=5432 DATABASE_DIALECT=postgresql POSTGRES_DB=superset @@ -44,3 +44,4 @@ SUPERSET_ENV=production SUPERSET_LOAD_EXAMPLES=yes CYPRESS_CONFIG=false SUPERSET_PORT=8088 +MAPBOX_API_KEY='' diff --git a/docker/README.md b/docker/README.md index c867121daeced..380b96a5074b7 100644 --- a/docker/README.md +++ b/docker/README.md @@ -23,8 +23,8 @@ Docker is an easy way to get started with Superset. ## Prerequisites -1. Docker! [link](https://www.docker.com/get-started) -2. Docker-compose [link](https://docs.docker.com/compose/install/) +1. [Docker](https://www.docker.com/get-started) +2. [Docker Compose](https://docs.docker.com/compose/install/) ## Configuration diff --git a/docker/docker-bootstrap.sh b/docker/docker-bootstrap.sh index 150f351e4b0d7..0784a0fdf2e5b 100755 --- a/docker/docker-bootstrap.sh +++ b/docker/docker-bootstrap.sh @@ -37,7 +37,7 @@ fi if [[ "${1}" == "worker" ]]; then echo "Starting Celery worker..." - celery --app=superset.tasks.celery_app:app worker -Ofair -l INFO + celery --app=superset.tasks.celery_app:app worker -O fair -l INFO elif [[ "${1}" == "beat" ]]; then echo "Starting Celery beat..." celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid -l INFO -s "${SUPERSET_HOME}"/celerybeat-schedule diff --git a/docker/docker-frontend.sh b/docker/docker-frontend.sh index 4c0d01e079359..a1ad94470ce5b 100755 --- a/docker/docker-frontend.sh +++ b/docker/docker-frontend.sh @@ -17,8 +17,11 @@ # set -e +# Packages needed for puppeteer: +apt update +apt install -y chromium + cd /app/superset-frontend -npm install -g npm@7 npm install -f --no-optional --global webpack webpack-cli npm install -f --no-optional diff --git a/docker/pythonpath_dev/superset_config.py b/docker/pythonpath_dev/superset_config.py index 84c1dc58ab502..7bfe2012c27e9 100644 --- a/docker/pythonpath_dev/superset_config.py +++ b/docker/pythonpath_dev/superset_config.py @@ -81,13 +81,12 @@ def get_env_variable(var_name: str, default: Optional[str] = None) -> str: class CeleryConfig(object): - BROKER_URL = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_CELERY_DB}" - CELERY_IMPORTS = ("superset.sql_lab",) - CELERY_RESULT_BACKEND = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_RESULTS_DB}" - CELERYD_LOG_LEVEL = "DEBUG" - CELERYD_PREFETCH_MULTIPLIER = 1 - CELERY_ACKS_LATE = False - CELERYBEAT_SCHEDULE = { + broker_url = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_CELERY_DB}" + imports = ("superset.sql_lab",) + result_backend = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_RESULTS_DB}" + worker_prefetch_multiplier = 1 + task_acks_late = False + beat_schedule = { "reports.scheduler": { "task": "reports.scheduler", "schedule": crontab(minute="*", hour="*"), diff --git a/docs/README.md b/docs/README.md index f4a122ba2f5b1..1427f21640a2c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,36 +17,4 @@ specific language governing permissions and limitations under the License. --> -# Website - -This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. - -### Installation - -``` -$ yarn install -``` - -### Local Development - -``` -$ yarn start -``` - -This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. - -### Build - -``` -$ yarn build -``` - -This command generates static content into the `build` directory and can be served using any static contents hosting service. - -### Deployment - -``` -$ GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy -``` - -If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. +This is the public documentation site for Superset, built using [Docusaurus 2](https://docusaurus.io/). See [CONTRIBUTING.md](../CONTRIBUTING.md#documentation) for documentation on contributing to documentation. diff --git a/docs/docs/contributing/contributing-page.mdx b/docs/docs/contributing/contributing-page.mdx index 6e205bf0bbf81..1619d7fed7e69 100644 --- a/docs/docs/contributing/contributing-page.mdx +++ b/docs/docs/contributing/contributing-page.mdx @@ -12,7 +12,7 @@ The core contributors (or committers) to Superset communicate primarily in the f which can be joined by anyone): - [Mailing list](https://lists.apache.org/list.html?dev@superset.apache.org) -- [Apache Superset Slack community](https://join.slack.com/t/apache-superset/shared_invite/zt-16jvzmoi8-sI7jKWp~xc2zYRe~NqiY9Q) +- [Apache Superset Slack community](http://bit.ly/join-superset-slack) - [GitHub issues and PR's](https://github.com/apache/superset/issues) More references: diff --git a/docs/docs/contributing/testing-locally.mdx b/docs/docs/contributing/testing-locally.mdx index 22a628b661502..ae08b1878a13f 100644 --- a/docs/docs/contributing/testing-locally.mdx +++ b/docs/docs/contributing/testing-locally.mdx @@ -54,6 +54,20 @@ You can run unit tests found in './tests/unit_tests' for example with pytest. It pytest ./link_to_test.py ``` +#### Testing with local Presto connections + +If you happen to change db engine spec for Presto/Trino, you can run a local Presto cluster with Docker: + +```bash +docker run -p 15433:15433 starburstdata/presto:350-e.6 +``` + +Then update `SUPERSET__SQLALCHEMY_EXAMPLES_URI` to point to local Presto cluster: + +```bash +export SUPERSET__SQLALCHEMY_EXAMPLES_URI=presto://localhost:15433/memory/default +``` + ### Frontend Testing We use [Jest](https://jestjs.io/) and [Enzyme](https://airbnb.io/enzyme/) to test TypeScript/JavaScript. Tests can be run with: diff --git a/docs/docs/contributing/translations.mdx b/docs/docs/contributing/translations.mdx index 52200aedff04a..13572f801e2d3 100644 --- a/docs/docs/contributing/translations.mdx +++ b/docs/docs/contributing/translations.mdx @@ -7,10 +7,10 @@ version: 1 ## Translating -We use [Flask-Babel](https://flask-babel.tkte.ch/) to translate Superset. +We use [Flask-Babel](https://python-babel.github.io/flask-babel/) to translate Superset. In Python files, we use the following -[translation functions](https://flask-babel.tkte.ch/#using-translations) from -`Flask-Babel`: +[translation functions](https://python-babel.github.io/flask-babel/#using-translations) +from `Flask-Babel`: - `gettext` and `lazy_gettext` (usually aliased to `_`): for translating singular strings. - `ngettext`: for translating strings that might become plural. diff --git a/docs/docs/contributing/types-of-contributions.mdx b/docs/docs/contributing/types-of-contributions.mdx index a9fa907f553de..cb6a5a5d863d0 100644 --- a/docs/docs/contributing/types-of-contributions.mdx +++ b/docs/docs/contributing/types-of-contributions.mdx @@ -19,15 +19,17 @@ The best way to report a bug is to file an issue on GitHub. Please include: When posting Python stack traces, please quote them using [Markdown blocks](https://help.github.com/articles/creating-and-highlighting-code-blocks/). +_Please note that feature requests opened as Github Issues will be moved to Discussions._ + ### Submit Ideas or Feature Requests -The best way is to file an issue on GitHub: +The best way is to start an ["Ideas" Discussion thread](https://github.com/apache/superset/discussions/categories/ideas) on GitHub: - Explain in detail how it would work. - Keep the scope as narrow as possible, to make it easier to implement. -- Remember that this is a volunteer-driven project, and that contributions are welcome :) +- Remember that this is a volunteer-driven project, and that your contributions are as welcome as anyone's :) -For large features or major changes to codebase, please create **Superset Improvement Proposal (SIP)**. See template from [SIP-0](https://github.com/apache/superset/issues/5602) +To propose large features or major changes to codebase, and help usher in those changes, please create a **Superset Improvement Proposal (SIP)**. See template from [SIP-0](https://github.com/apache/superset/issues/5602) ### Fix Bugs diff --git a/docs/docs/creating-charts-dashboards/creating-your-first-dashboard.mdx b/docs/docs/creating-charts-dashboards/creating-your-first-dashboard.mdx index ecabf896f8e43..48792e3199794 100644 --- a/docs/docs/creating-charts-dashboards/creating-your-first-dashboard.mdx +++ b/docs/docs/creating-charts-dashboards/creating-your-first-dashboard.mdx @@ -183,7 +183,7 @@ Access to dashboards is managed via owners (users that have edit permissions to Non-owner users access can be managed two different ways: 1. Dataset permissions - if you add to the relevant role permissions to datasets it automatically grants implicit access to all dashboards that uses those permitted datasets -2. Dashboard roles - if you enable **DASHBOARD_RBAC** feature flag then you be able to manage which roles can access the dashboard +2. Dashboard roles - if you enable **DASHBOARD_RBAC** [feature flag](https://superset.apache.org/docs/installation/configuring-superset#feature-flags) then you be able to manage which roles can access the dashboard - Having dashboard access implicitly grants read access to the associated datasets, therefore all charts will load their data even if feature flag is turned on and no roles assigned to roles the access will fallback to **Dataset permissions** diff --git a/docs/docs/databases/athena.mdx b/docs/docs/databases/athena.mdx index feabad302d73b..55282d68adb9e 100644 --- a/docs/docs/databases/athena.mdx +++ b/docs/docs/databases/athena.mdx @@ -32,3 +32,11 @@ following connection string: ``` awsathena+rest://{aws_access_key_id}:{aws_secret_access_key}@athena.{region_name}.amazonaws.com/{schema_name}?s3_staging_dir={s3_staging_dir}&... ``` + +The PyAthena library also allows to assume a specific IAM role, by [importing the datasource from YAML](https://superset.apache.org/docs/miscellaneous/importing-exporting-datasources/#importing-datasources-from-yaml) and passing extra parameters: +``` +databases: + - database_name: awsathena + sqlalchemy_uri: awsathena+rest://athena.{region_name}.amazonaws.com/{schema_name}?s3_staging_dir={s3_staging_dir}&... + extra: "{\"engine_params\": {\"connect_args\": {\"role_arn\": \"{{ ROLE_ARN }}\" }}}" +``` diff --git a/docs/docs/databases/bigquery.mdx b/docs/docs/databases/bigquery.mdx index 6d3ba0750e659..7ea993ae5d4e7 100644 --- a/docs/docs/databases/bigquery.mdx +++ b/docs/docs/databases/bigquery.mdx @@ -8,7 +8,7 @@ version: 1 ## Google BigQuery The recommended connector library for BigQuery is -[pybigquery](https://github.com/mxmzdlv/pybigquery). +[sqlalchemy-bigquery](https://github.com/googleapis/python-bigquery-sqlalchemy). ### Install BigQuery Driver @@ -16,7 +16,7 @@ Follow the steps [here](/docs/databases/docker-add-drivers) about how to install new database drivers when setting up Superset locally via docker-compose. ``` -echo "pybigquery" >> ./docker/requirements-local.txt +echo "sqlalchemy-bigquery" >> ./docker/requirements-local.txt ``` ### Connecting to BigQuery diff --git a/docs/docs/databases/clickhouse.mdx b/docs/docs/databases/clickhouse.mdx index e717b60bf0b24..424e50da9352c 100644 --- a/docs/docs/databases/clickhouse.mdx +++ b/docs/docs/databases/clickhouse.mdx @@ -7,38 +7,36 @@ version: 1 ## ClickHouse -To use ClickHouse with Superset, you will need to add the following Python libraries: +To use ClickHouse with Superset, you will need to add the following Python library: ``` -clickhouse-driver==0.2.0 -clickhouse-sqlalchemy==0.1.6 +clickhouse-connect>=0.4.1 ``` If running Superset using Docker Compose, add the following to your `./docker/requirements-local.txt` file: ``` -clickhouse-driver>=0.2.0 -clickhouse-sqlalchemy>=0.1.6 +clickhouse-connect>=0.4.1 ``` The recommended connector library for ClickHouse is -[sqlalchemy-clickhouse](https://github.com/cloudflare/sqlalchemy-clickhouse). +[clickhouse-connect](https://github.com/ClickHouse/clickhouse-connect). The expected connection string is formatted as follows: ``` -clickhouse+native://<user>:<password>@<host>:<port>/<database>[?options…]clickhouse://{username}:{password}@{hostname}:{port}/{database} +clickhousedb://<user>:<password>@<host>:<port>/<database>[?options…]clickhouse://{username}:{password}@{hostname}:{port}/{database} ``` Here's a concrete example of a real connection string: ``` -clickhouse+native://demo:demo@github.demo.trial.altinity.cloud/default?secure=true +clickhousedb://demo:demo@github.demo.trial.altinity.cloud/default?secure=true ``` -If you're using Clickhouse locally on your computer, you can get away with using a native protocol URL that +If you're using Clickhouse locally on your computer, you can get away with using a http protocol URL that uses the default user without a password (and doesn't encrypt the connection): ``` -clickhouse+native://localhost/default +clickhousedb://localhost/default ``` diff --git a/docs/docs/databases/databricks.mdx b/docs/docs/databases/databricks.mdx index 4070960ce2af5..e9bbd4b685219 100644 --- a/docs/docs/databases/databricks.mdx +++ b/docs/docs/databases/databricks.mdx @@ -33,13 +33,10 @@ You also need to add the following configuration to "Other" -> "Engine Parameter ```json { - "connect_args": {"http_path": "sql/protocolv1/o/****"}, - "http_headers": [["User-Agent", "Apache Superset"]] + "connect_args": {"http_path": "sql/protocolv1/o/****"} } ``` -The `User-Agent` header is optional, but helps Databricks identify traffic from Superset. If you need to use a different header please reach out to Databricks and let them know. - ## Older driver Originally Superset used `databricks-dbapi` to connect to Databricks. You might want to try it if you're having problems with the official Databricks connector: diff --git a/docs/docs/databases/docker-add-drivers.mdx b/docs/docs/databases/docker-add-drivers.mdx index 725a6e671c5b8..cfb504b5e474e 100644 --- a/docs/docs/databases/docker-add-drivers.mdx +++ b/docs/docs/databases/docker-add-drivers.mdx @@ -53,7 +53,7 @@ Rebuild your local image with the new driver baked in: docker-compose build --force-rm ``` -After the rebuild of the Docker images is complete (which make take a few minutes) you can relaunch using the following command: +After the rebuild of the Docker images is complete (which may take a few minutes) you can relaunch using the following command: ``` docker-compose up diff --git a/docs/docs/databases/druid.mdx b/docs/docs/databases/druid.mdx index 6641898aa4973..95e9bbc15a8a9 100644 --- a/docs/docs/databases/druid.mdx +++ b/docs/docs/databases/druid.mdx @@ -18,6 +18,12 @@ The connection string looks like: ``` druid://<User>:<password>@<Host>:<Port-default-9088>/druid/v2/sql ``` +Here's a breakdown of the key components of this connection string: + +User: username portion of the credentials needed to connect to your database +Password: password portion of the credentials needed to connect to your database +Host: IP address (or URL) of the host machine that's running your database +Port: specific port that's exposed on your host machine where your database is running ### Customizing Druid Connection diff --git a/docs/docs/databases/dynamodb.mdx b/docs/docs/databases/dynamodb.mdx new file mode 100644 index 0000000000000..4cb9e1e4f8077 --- /dev/null +++ b/docs/docs/databases/dynamodb.mdx @@ -0,0 +1,20 @@ +--- +title: Amazon DynamoDB +hide_title: true +sidebar_position: 4 +version: 1 +--- + +## AWS DynamoDB + +### PyDynamoDB + +[PyDynamoDB](https://pypi.org/project/PyDynamoDB/) is a Python DB API 2.0 (PEP 249) client for Amazon DynamoDB. + +The connection string for Amazon DynamoDB is as follows: + +``` +dynamodb://{aws_access_key_id}:{aws_secret_access_key}@dynamodb.{region_name}.amazonaws.com:443?connector=superset +``` + +To get more documentation, please visit: [PyDynamoDB WIKI](https://github.com/passren/PyDynamoDB/wiki/5.-Superset). diff --git a/docs/docs/databases/elasticsearch.mdx b/docs/docs/databases/elasticsearch.mdx index 70b7f8f685e2b..6fb922815ca0f 100644 --- a/docs/docs/databases/elasticsearch.mdx +++ b/docs/docs/databases/elasticsearch.mdx @@ -66,3 +66,11 @@ you need to use the `CAST` function,but this function does not support our `time After elasticsearch7.8, you can use the `DATETIME_PARSE` function to solve this problem. The DATETIME_PARSE function is to support our `time_zone` setting, and here you need to fill in your elasticsearch version number in the Other > VERSION setting. the superset will use the `DATETIME_PARSE` function for conversion. + +**Disable SSL Verification** + +To disable SSL verification, add the following to the **SQLALCHEMY URI** field: + +``` +elasticsearch+https://{user}:{password}@{host}:9200/?verify_certs=False +``` diff --git a/docs/docs/databases/installing-database-drivers.mdx b/docs/docs/databases/installing-database-drivers.mdx index cb404fb480a40..ee1b385336db9 100644 --- a/docs/docs/databases/installing-database-drivers.mdx +++ b/docs/docs/databases/installing-database-drivers.mdx @@ -23,6 +23,7 @@ A list of some of the recommended packages. | Database | PyPI package | Connection String | | --------------------------------------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | [Amazon Athena](/docs/databases/athena) | `pip install "PyAthenaJDBC>1.0.9` , `pip install "PyAthena>1.2.0` | `awsathena+rest://{aws_access_key_id}:{aws_secret_access_key}@athena.{region_name}.amazonaws.com/{ ` | +| [Amazon DynamoDB](/docs/databases/dynamodb) | `pip install "PyDynamoDB>=0.4.2` | `dynamodb://{access_key_id}:{secret_access_key}@dynamodb.{region_name}.amazonaws.com?connector=superset` | | [Amazon Redshift](/docs/databases/redshift) | `pip install sqlalchemy-redshift` | ` redshift+psycopg2://<userName>:<DBPassword>@<AWS End Point>:5439/<Database Name>` | | [Apache Drill](/docs/databases/drill) | `pip install sqlalchemy-drill` | `drill+sadrill:// For JDBC drill+jdbc://` | | [Apache Druid](/docs/databases/druid) | `pip install pydruid` | `druid://<User>:<password>@<Host>:<Port-default-9088>/druid/v2/sql` | @@ -34,8 +35,8 @@ A list of some of the recommended packages. | [Apache Spark SQL](/docs/databases/spark-sql) | `pip install pyhive` | `hive://hive@{hostname}:{port}/{database}` | | [Ascend.io](/docs/databases/ascend) | `pip install impyla` | `ascend://{username}:{password}@{hostname}:{port}/{database}?auth_mechanism=PLAIN;use_ssl=true` | | [Azure MS SQL](/docs/databases/sql-server) | `pip install pymssql` | `mssql+pymssql://UserName@presetSQL:TestPassword@presetSQL.database.windows.net:1433/TestSchema` | -| [Big Query](/docs/databases/bigquery) | `pip install pybigquery` | `bigquery://{project_id}` | -| [ClickHouse](/docs/databases/clickhouse) | `pip install clickhouse-driver==0.2.0 && pip install clickhouse-sqlalchemy==0.1.6` | `clickhouse+native://{username}:{password}@{hostname}:{port}/{database}` | +| [Big Query](/docs/databases/bigquery) | `pip install sqlalchemy-bigquery` | `bigquery://{project_id}` | +| [ClickHouse](/docs/databases/clickhouse) | `pip install clickhouse-connect` | `clickhousedb://{username}:{password}@{hostname}:{port}/{database}` | | [CockroachDB](/docs/databases/cockroachdb) | `pip install cockroachdb` | `cockroachdb://root@{hostname}:{port}/{database}?sslmode=disable` | | [Dremio](/docs/databases/dremio) | `pip install sqlalchemy_dremio` | `dremio://user:pwd@host:31010/` | | [Elasticsearch](/docs/databases/elasticsearch) | `pip install elasticsearch-dbapi` | `elasticsearch+http://{user}:{password}@{host}:9200/` | @@ -48,16 +49,16 @@ A list of some of the recommended packages. | [MySQL](/docs/databases/mysql) | `pip install mysqlclient` | `mysql://<UserName>:<DBPassword>@<Database Host>/<Database Name>` | | [Oracle](/docs/databases/oracle) | `pip install cx_Oracle` | `oracle://` | | [PostgreSQL](/docs/databases/postgres) | `pip install psycopg2` | `postgresql://<UserName>:<DBPassword>@<Database Host>/<Database Name>` | -| [Trino](/docs/databases/trino) | `pip install sqlalchemy-trino` | `trino://{username}:{password}@{hostname}:{port}/{catalog}` | +| [Trino](/docs/databases/trino) | `pip install trino` | `trino://{username}:{password}@{hostname}:{port}/{catalog}` | | [Presto](/docs/databases/presto) | `pip install pyhive` | `presto://` | | [SAP Hana](/docs/databases/hana) | `pip install hdbcli sqlalchemy-hana or pip install apache-superset[hana]` | `hana://{username}:{password}@{host}:{port}` | | [Snowflake](/docs/databases/snowflake) | `pip install snowflake-sqlalchemy` | `snowflake://{user}:{password}@{account}.{region}/{database}?role={role}&warehouse={warehouse}` | | SQLite | No additional library needed | `sqlite://` | -| [SQL Server](/docs/databases/sql-server) | `pip install pymssql` | `mssql://` | -| [Teradata](/docs/databases/teradata) | `pip install teradatasqlalchemy ` | `teradata://{user}:{password}@{host}` | +| [SQL Server](/docs/databases/sql-server) | `pip install pymssql` | `mssql+pymssql://` | +| [Teradata](/docs/databases/teradata) | `pip install teradatasqlalchemy` | `teradatasql://{user}:{password}@{host}` | +| [TimescaleDB](/docs/databases/timescaledb) | `pip install psycopg2` | `postgresql://<UserName>:<DBPassword>@<Database Host>:<Port>/<Database Name>` | | [Vertica](/docs/databases/vertica) | `pip install sqlalchemy-vertica-python` | `vertica+vertica_python://<UserName>:<DBPassword>@<Database Host>/<Database Name>` | -| [YugabyteDB](/docs/databases/yugabytedb) | `pip install psycopg2` | `postgresql://<UserName>:<DBPassword>@<Database Host>/<Database Name>` | - +| [YugabyteDB](/docs/databases/yugabytedb) | `pip install psycopg2` | `postgresql://<UserName>:<DBPassword>@<Database Host>/<Database Name>` | --- Note that many other databases are supported, the main criteria being the existence of a functional diff --git a/docs/docs/databases/kusto.mdx b/docs/docs/databases/kusto.mdx new file mode 100644 index 0000000000000..3efe4ac8f5bec --- /dev/null +++ b/docs/docs/databases/kusto.mdx @@ -0,0 +1,26 @@ +--- +name: Kusto +hide_title: true +sidebar_position: 41 +version: 2 +--- + +## Kusto + +The recommended connector library for Kusto is +[sqlalchemy-kusto](https://pypi.org/project/sqlalchemy-kusto/2.0.0/)>=2.0.0. + +The connection string for Kusto (sql dialect) looks like this: + +``` +kustosql+https://{cluster_url}/{database}?azure_ad_client_id={azure_ad_client_id}&azure_ad_client_secret={azure_ad_client_secret}&azure_ad_tenant_id={azure_ad_tenant_id}&msi=False +``` + +The connection string for Kusto (kql dialect) looks like this: + +``` +kustokql+https://{cluster_url}/{database}?azure_ad_client_id={azure_ad_client_id}&azure_ad_client_secret={azure_ad_client_secret}&azure_ad_tenant_id={azure_ad_tenant_id}&msi=False +``` + +Make sure the user has privileges to access and use all required +databases/tables/views. diff --git a/docs/docs/databases/risingwave.mdx b/docs/docs/databases/risingwave.mdx new file mode 100644 index 0000000000000..ddd22d739845c --- /dev/null +++ b/docs/docs/databases/risingwave.mdx @@ -0,0 +1,17 @@ +--- +title: RisingWave +hide_title: true +sidebar_position: 16 +version: 1 +--- + +## RisingWave + +The recommended connector library for RisingWave is +[sqlalchemy-risingwave](https://github.com/risingwavelabs/sqlalchemy-risingwave). + +The expected connection string is formatted as follows: + +``` +risingwave://root@{hostname}:{port}/{database}?sslmode=disable +``` diff --git a/docs/docs/databases/snowflake.mdx b/docs/docs/databases/snowflake.mdx index f0fc1a4a58e59..d128e43016888 100644 --- a/docs/docs/databases/snowflake.mdx +++ b/docs/docs/databases/snowflake.mdx @@ -8,7 +8,7 @@ version: 1 ## Snowflake The recommended connector library for Snowflake is -[snowflake-sqlalchemy](https://pypi.org/project/snowflake-sqlalchemy/1.2.4/)<=1.2.4. (This version is required until Superset migrates to sqlalchemy>=1.4.0) +[snowflake-sqlalchemy](https://pypi.org/project/snowflake-sqlalchemy/). The connection string for Snowflake looks like this: @@ -29,3 +29,31 @@ user/role rights during engine creation by default. However, when pressing the button in the Create or Edit Database dialog, user/role credentials are validated by passing “validate_default_parameters”: True to the connect() method during engine creation. If the user/role is not authorized to access the database, an error is recorded in the Superset logs. + +And if you want connect Snowflake with [Key Pair Authentication](https://docs.snowflake.com/en/user-guide/key-pair-auth.html#step-6-configure-the-snowflake-client-to-use-key-pair-authentication). +Plase make sure you have the key pair and the public key is registered in Snowflake. +To connect Snowflake with Key Pair Authentication, you need to add the following parameters to "SECURE EXTRA" field. + +***Please note that you need to merge multi-line private key content to one line and insert `\n` between each line*** + +``` +{ + "auth_method": "keypair", + "auth_params": { + "privatekey_body": "-----BEGIN ENCRYPTED PRIVATE KEY-----\n...\n...\n-----END ENCRYPTED PRIVATE KEY-----", + "privatekey_pass":"Your Private Key Password" + } + } +``` + +If your private key is stored on server, you can replace "privatekey_body" with “privatekey_path” in parameter. + +``` +{ + "auth_method": "keypair", + "auth_params": { + "privatekey_path":"Your Private Key Path", + "privatekey_pass":"Your Private Key Password" + } +} +``` diff --git a/docs/docs/databases/sql-server.mdx b/docs/docs/databases/sql-server.mdx index f9ceb4c751c7a..8b7c833c8d6b3 100644 --- a/docs/docs/databases/sql-server.mdx +++ b/docs/docs/databases/sql-server.mdx @@ -14,3 +14,10 @@ The connection string for SQL Server looks like this: ``` mssql+pymssql://<Username>:<Password>@<Host>:<Port-default:1433>/<Database Name>/?Encrypt=yes ``` + +It is also possible to connect using [pyodbc](https://pypi.org/project/pyodbc) with the parameter [odbc_connect](https://docs.sqlalchemy.org/en/14/dialects/mssql.html#pass-through-exact-pyodbc-string) + +The connection string for SQL Server looks like this: +``` +mssql+pyodbc:///?odbc_connect=Driver%3D%7BODBC+Driver+17+for+SQL+Server%7D%3BServer%3Dtcp%3A%3Cmy_server%3E%2C1433%3BDatabase%3Dmy_datasbase%3BUid%3Dmy_user_name%3BPwd%3Dmy_password%3BEncrypt%3Dyes%3BConnection+Timeout%3D30 +``` diff --git a/docs/docs/databases/teradata.mdx b/docs/docs/databases/teradata.mdx index 2f765a2146cfe..8b7a91c9146ed 100644 --- a/docs/docs/databases/teradata.mdx +++ b/docs/docs/databases/teradata.mdx @@ -13,7 +13,7 @@ The recommended connector library is The connection string for Teradata looks like this: ``` -teradata://{user}:{password}@{host} +teradatasql://{user}:{password}@{host} ``` ## ODBC Driver diff --git a/docs/docs/databases/timescaledb.mdx b/docs/docs/databases/timescaledb.mdx new file mode 100644 index 0000000000000..2ab93e68b43ff --- /dev/null +++ b/docs/docs/databases/timescaledb.mdx @@ -0,0 +1,38 @@ +--- +title: TimescaleDB +hide_title: true +sidebar_position: 31 +version: 1 +--- + +## TimescaleDB +[TimescaleDB](https://www.timescale.com) is the open-source relational database for time-series and analytics to build powerful data-intensive applications. +TimescaleDB is a PostgreSQL extension, and you can use the standard PostgreSQL connector library, [psycopg2](https://www.psycopg.org/docs/), to connect to the database. + +If you're using docker-compose, psycopg2 comes out of the box with Superset. + +TimescaleDB sample connection parameters: + +- **User Name**: User +- **Password**: Password +- **Database Host**: + - For Localhost: localhost or 127.0.0.1 + - For On Prem: IP address or Host name + - For [Timescale Cloud](https://console.cloud.timescale.com) service: Host name + - For [Managed Service for TimescaleDB](https://portal.managed.timescale.com) service: Host name +- **Database Name**: Database Name +- **Port**: default 5432 or Port number of the service + +The connection string looks like: + +``` +postgresql://{username}:{password}@{host}:{port}/{database name} +``` + +You can require SSL by adding `?sslmode=require` at the end (e.g. in case you use [Timescale Cloud](https://www.timescale.com/cloud)): + +``` +postgresql://{username}:{password}@{host}:{port}/{database name}?sslmode=require +``` + +[Learn more about TimescaleDB!](https://docs.timescale.com/) diff --git a/docs/docs/databases/trino.mdx b/docs/docs/databases/trino.mdx index 50ccf1f27123d..4d6bfcf343205 100644 --- a/docs/docs/databases/trino.mdx +++ b/docs/docs/databases/trino.mdx @@ -56,7 +56,21 @@ In `Secure Extra` field, config as following example: All fields in `auth_params` are passed directly to the [`KerberosAuthentication`](https://github.com/trinodb/trino-python-client/blob/0.306.0/trino/auth.py#L40) class. -#### 3. JWT Authentication +#### 3. Certificate Authentication +In `Secure Extra` field, config as following example: +```json +{ + "auth_method": "certificate", + "auth_params": { + "cert": "/path/to/cert.pem", + "key": "/path/to/key.pem" + } +} +``` + +All fields in `auth_params` are passed directly to the [`CertificateAuthentication`](https://github.com/trinodb/trino-python-client/blob/0.315.0/trino/auth.py#L416) class. + +#### 4. JWT Authentication Config `auth_method` and provide token in `Secure Extra` field ```json { @@ -67,7 +81,7 @@ Config `auth_method` and provide token in `Secure Extra` field } ``` -#### 4. Custom Authentication +#### 5. Custom Authentication To use custom authentication, first you need to add it into `ALLOWED_EXTRA_AUTHENTICATIONS` allow list in Superset config file: ```python diff --git a/docs/docs/frequently-asked-questions.mdx b/docs/docs/frequently-asked-questions.mdx index 04b30b272b44b..779f6c8c8dc77 100644 --- a/docs/docs/frequently-asked-questions.mdx +++ b/docs/docs/frequently-asked-questions.mdx @@ -57,14 +57,6 @@ timeout in configuration. For example: SQLLAB_ASYNC_TIME_LIMIT_SEC = 60 * 60 * 6 ``` -Superset is running on gunicorn web server, which may time out web requests. If you want to increase -the default (50), you can specify the timeout when starting the web server with the -t flag, which -is expressed in seconds. - -``` -superset runserver -t 300 -``` - If you are seeing timeouts (504 Gateway Time-out) when loading dashboard or explore slice, you are probably behind gateway or proxy server (such as Nginx). If it did not receive a timely response from Superset server (which is processing long queries), these web servers will send 504 status code @@ -80,7 +72,7 @@ SUPERSET_WEBSERVER_TIMEOUT = 60 ### Why is the map not visible in the geospatial visualization? You need to register a free account at [Mapbox.com](https://www.mapbox.com), obtain an API key, and add it -to **superset_config.py** at the key MAPBOX_API_KEY: +to **.env** and **.env-non-dev** at the key MAPBOX_API_KEY: ``` MAPBOX_API_KEY = "longstringofalphanumer1c" diff --git a/docs/docs/installation/alerts-reports.mdx b/docs/docs/installation/alerts-reports.mdx index a86f14893ec4d..a193f6ff26593 100644 --- a/docs/docs/installation/alerts-reports.mdx +++ b/docs/docs/installation/alerts-reports.mdx @@ -7,7 +7,7 @@ version: 2 ## Alerts and Reports -(version 1.0.1 and above) +*This covers versions 1.0.1 to current.* Users can configure automated alerts and reports to send dashboards or charts to an email recipient or Slack channel. @@ -20,21 +20,30 @@ Alerts and reports are disabled by default. To turn them on, you need to do some #### Commons -##### In your `superset_config.py` +##### In your `superset_config.py` or `superset_config_docker.py` -- `"ALERT_REPORTS"` feature flag must be turned to True. -- `CELERYBEAT_SCHEDULE` in CeleryConfig must contain schedule for `reports.scheduler`. +- `"ALERT_REPORTS"` [feature flag](https://superset.apache.org/docs/installation/configuring-superset#feature-flags) must be turned to True. +- `beat_schedule` in CeleryConfig must contain schedule for `reports.scheduler`. - At least one of those must be configured, depending on what you want to use: - emails: `SMTP_*` settings - Slack messages: `SLACK_API_TOKEN` +###### Disable dry-run mode + +Screenshots will be taken but no messages actually sent as long as `ALERT_REPORTS_NOTIFICATION_DRY_RUN = True`, its default value in `config.py`. To disable dry-run mode and start receiving email/Slack notifications, set `ALERT_REPORTS_NOTIFICATION_DRY_RUN` to `False` in [superset config](https://github.com/apache/superset/blob/master/docker/pythonpath_dev/superset_config.py). + ##### In your `Dockerfile` - You must install a headless browser, for taking screenshots of the charts and dashboards. Only Firefox and Chrome are currently supported. > If you choose Chrome, you must also change the value of `WEBDRIVER_TYPE` to `"chrome"` in your `superset_config.py`. -Note : All the components required (headless browser, redis, postgres db, celery worker and celery beat) are present in the docker image if you are following [Installing Superset Locally](https://superset.apache.org/docs/installation/installing-superset-using-docker-compose/). -All you need to do is add the required config (See `Detailed Config`). Set `ALERT_REPORTS_NOTIFICATION_DRY_RUN` to `False` in [superset config](https://github.com/apache/superset/blob/master/docker/pythonpath_dev/superset_config.py) to disable dry-run mode and start receiving email/slack notifications. +Note: All the components required (Firefox headless browser, Redis, Postgres db, celery worker and celery beat) are present in the *dev* docker image if you are following [Installing Superset Locally](https://superset.apache.org/docs/installation/installing-superset-using-docker-compose/). +All you need to do is add the required config variables described in this guide (See `Detailed Config`). + +If you are running a non-dev docker image, e.g., a stable release like `apache/superset:2.0.1`, that image does not include a headless browser. Only the `superset_worker` container needs this headless browser to browse to the target chart or dashboard. +You can either install and configure the headless browser - see "Custom Dockerfile" section below - or when deploying via `docker-compose`, modify your `docker-compose.yml` file to use a dev image for the worker container and a stable release image for the `superset_app` container. + +*Note*: In this context, a "dev image" is the same application software as its corresponding non-dev image, just bundled with additional tools. So an image like `2.0.1-dev` is identical to `2.0.1` when it comes to stability, functionality, and running in production. The actual "in-development" versions of Superset - cutting-edge and unstable - are not tagged with version numbers on Docker Hub and will display version `0.0.0-dev` within the Superset UI. #### Slack integration @@ -52,21 +61,23 @@ To send alerts and reports to Slack channels, you need to create a new Slack App 6. The app should now be installed in your workspace, and a "Bot User OAuth Access Token" should have been created. Copy that token in the `SLACK_API_TOKEN` variable of your `superset_config.py`. 7. Restart the service (or run `superset init`) to pull in the new configuration. -Note: when you configure an alert or a report, the Slack channel list take channel names without the leading '#' e.g. use `alerts` instead of `#alerts`. +Note: when you configure an alert or a report, the Slack channel list takes channel names without the leading '#' e.g. use `alerts` instead of `#alerts`. -#### Kubernetes specific +#### Kubernetes-specific - You must have a `celery beat` pod running. If you're using the chart included in the GitHub repository under [helm/superset](https://github.com/apache/superset/tree/master/helm/superset), you need to put `supersetCeleryBeat.enabled = true` in your values override. - You can see the dedicated docs about [Kubernetes installation](/docs/installation/running-on-kubernetes) for more generic details. #### Docker-compose specific -##### You must have in your`docker-compose.yaml` +##### You must have in your `docker-compose.yml` -- a redis message broker +- A Redis message broker - PostgreSQL DB instead of SQLlite -- one or more `celery worker` -- a single `celery beat` +- One or more `celery worker` +- A single `celery beat` + +This process also works in a Docker swarm environment, you would just need to add `Deploy:` to the Superset, Redis and Postgres services along with your specific configs for your swarm. ### Detailed config @@ -76,7 +87,11 @@ You can find documentation about each field in the default `config.py` in the Gi You need to replace default values with your custom Redis, Slack and/or SMTP config. -In the `CeleryConfig`, only the `CELERYBEAT_SCHEDULE` is relative to this feature, the rest of the `CeleryConfig` can be changed for your needs. +Superset uses Celery beat and Celery worker(s) to send alerts and reports. +- The beat is the scheduler that tells the worker when to perform its tasks. This schedule is defined when you create the alert or report. +- The worker will process the tasks that need to be performed when an alert or report is fired. + +In the `CeleryConfig`, only the `beat_schedule` is relevant to this feature, the rest of the `CeleryConfig` can be changed for your needs. ```python from celery.schedules import crontab @@ -124,14 +139,15 @@ SCREENSHOT_LOAD_WAIT = 600 SLACK_API_TOKEN = "xoxb-" # Email configuration -SMTP_HOST = "smtp.sendgrid.net" #change to your host +SMTP_HOST = "smtp.sendgrid.net" # change to your host +SMTP_PORT = 2525 # your port, e.g. 587 SMTP_STARTTLS = True SMTP_SSL_SERVER_AUTH = True # If your using an SMTP server with a valid certificate SMTP_SSL = False -SMTP_USER = "your_user" -SMTP_PORT = 2525 # your port eg. 587 -SMTP_PASSWORD = "your_password" +SMTP_USER = "your_user" # use the empty string "" if using an unauthenticated SMTP server +SMTP_PASSWORD = "your_password" # use the empty string "" if using an unauthenticated SMTP server SMTP_MAIL_FROM = "noreply@youremail.com" +EMAIL_REPORTS_SUBJECT_PREFIX = "[Superset] " # optional - overwrites default value in config.py of "[Report] " # WebDriver configuration # If you use Firefox, you can stick with default values @@ -149,19 +165,70 @@ WEBDRIVER_OPTION_ARGS = [ ] # This is for internal use, you can keep http -WEBDRIVER_BASEURL="http://superset:8088" -# This is the link sent to the recipient, change to your domain eg. https://superset.mydomain.com -WEBDRIVER_BASEURL_USER_FRIENDLY="http://localhost:8088" +WEBDRIVER_BASEURL = "http://superset:8088" +# This is the link sent to the recipient. Change to your domain, e.g. https://superset.mydomain.com +WEBDRIVER_BASEURL_USER_FRIENDLY = "http://localhost:8088" +``` + +You also need +to specify on behalf of which username to render the dashboards. In general dashboards and charts +are not accessible to unauthorized requests, that is why the worker needs to take over credentials +of an existing user to take a snapshot. + +By default, Alerts and Reports are executed as the user that the `THUMBNAIL_SELENIUM_USER` config +parameter is set to. To change this user, just change the config as follows: + +```python +THUMBNAIL_SELENIUM_USER = 'username_with_permission_to_access_dashboards' ``` +In addition, it's also possible to execute the reports as the report owners/creators. This is typically +needed if there isn't a central service account that has access to all objects or databases (e.g. +when using user impersonation on database connections). For this there's the config flag +`ALERTS_REPORTS_EXECUTE_AS` which makes it possible to customize how alerts and reports are executed. +To first try to execute as the creator in the owners list (if present), then fall +back to the creator, then the last modifier in the owners list (if present), then the +last modifier, then an owner (giving priority to the last modifier and then the +creator if either is contained within the list of owners, otherwise the first owner +will be used) and finally `THUMBNAIL_SELENIUM_USER`, set as follows: + +```python +from superset.reports.types import ReportScheduleExecutor + +ALERT_REPORTS_EXECUTE_AS = [ + ReportScheduleExecutor.CREATOR_OWNER, + ReportScheduleExecutor.CREATOR, + ReportScheduleExecutor.MODIFIER_OWNER, + ReportScheduleExecutor.MODIFIER, + ReportScheduleExecutor.OWNER, + ReportScheduleExecutor.SELENIUM, +] +``` + + +**Important notes** + +- Be mindful of the concurrency setting for celery (using `-c 4`). Selenium/webdriver instances can + consume a lot of CPU / memory on your servers. +- In some cases, if you notice a lot of leaked geckodriver processes, try running your celery + processes with `celery worker --pool=prefork --max-tasks-per-child=128 ...` +- It is recommended to run separate workers for the `sql_lab` and `email_reports` tasks. This can be + done using the `queue` field in `task_annotations`. +- Adjust `WEBDRIVER_BASEURL` in your configuration file if celery workers can’t access Superset via + its default value of `http://0.0.0.0:8080/`. + + ### Custom Dockerfile -A webdriver (and headless browser) is needed to capture screenshots of the charts and dashboards which are then sent to the recipient. As the base superset image does not have a webdriver installed, we need to extend it and install the webdriver. +If you're running the dev version of a released Superset image, like `apache/superset:2.0.1-dev`, you should be set with the above. + +But if you're building your own image, or starting with a non-dev version, a webdriver (and headless browser) is needed to capture screenshots of the charts and dashboards which are then sent to the recipient. +Here's how you can modify your Dockerfile to take the screenshots either with Firefox or Chrome. #### Using Firefox ```docker -FROM apache/superset:1.0.1 +FROM apache/superset:2.0.1 USER root @@ -182,7 +249,7 @@ USER superset #### Using Chrome ```docker -FROM apache/superset:1.0.1 +FROM apache/superset:2.0.1 USER root @@ -191,7 +258,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends ./google-chrome-stable_current_amd64.deb && \ rm -f google-chrome-stable_current_amd64.deb -RUN export CHROMEDRIVER_VERSION=$(curl --silent https://chromedriver.storage.googleapis.com/LATEST_RELEASE_88) && \ +RUN export CHROMEDRIVER_VERSION=$(curl --silent https://chromedriver.storage.googleapis.com/LATEST_RELEASE_102) && \ wget -q https://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip && \ unzip chromedriver_linux64.zip -d /usr/bin && \ chmod 755 /usr/bin/chromedriver && \ @@ -202,189 +269,7 @@ RUN pip install --no-cache gevent psycopg2 redis USER superset ``` -> Don't forget to set `WEBDRIVER_TYPE` and `WEBDRIVER_OPTION_ARGS` in your config if you use Chrome. - -### Summary of steps to turn on alerts and reporting: - -Using the templates below, - -1. Create a new directory and create the Dockerfile -2. Build the extended image using the Dockerfile -3. Create the `docker-compose.yaml` file in the same directory -4. Create a new subdirectory called `config` -5. Create the `superset_config.py` file in the `config` subdirectory -6. Run the image using `docker-compose up` in the same directory as the `docker-compose.py` file -7. In a new terminal window, upgrade the DB by running `docker exec -it superset-1.0.1-extended superset db upgrade` -8. Then run `docker exec -it superset-1.0.1-extended superset init` -9. Then setup your admin user if need be, `docker exec -it superset-1.0.1-extended superset fab create-admin` -10. Finally, restart the running instance - `CTRL-C`, then `docker-compose up` - -(note: v 1.0.1 is current at time of writing, you can change the version number to the latest version if a newer version is available) - -### Docker compose - -The docker compose file lists the services that will be used when running the image. The specific services needed for alerts and reporting are outlined below. - -#### Redis message broker - -To ferry requests between the celery worker and the Superset instance, we use a message broker. This template uses Redis. - -#### Replacing SQLite with Postgres - -While it might be possible to use SQLite for alerts and reporting, it is highly recommended using a more production ready DB for Superset in general. Our template uses Postgres. - -#### Celery worker - -The worker will process the tasks that need to be performed when an alert or report is fired. - -#### Celery beat - -The beat is the scheduler that tells the worker when to perform its tasks. This schedule is defined when you create the alert or report. - -#### Full `docker-compose.yaml` configuration - -The Redis, Postgres, Celery worker and Celery beat services are defined in the template: - -Config for `docker-compose.yaml`: - -```docker -version: '3.6' -services: - redis: - image: redis:6.0.9-buster - restart: on-failure - volumes: - - redis:/data - postgres: - image: postgres - restart: on-failure - environment: - POSTGRES_DB: superset - POSTGRES_PASSWORD: superset - POSTGRES_USER: superset - volumes: - - db:/var/lib/postgresql/data - worker: - image: superset-1.0.1-extended - restart: on-failure - healthcheck: - disable: true - depends_on: - - superset - - postgres - - redis - command: "celery --app=superset.tasks.celery_app:app worker --pool=gevent --concurrency=500" - volumes: - - ./config/:/app/pythonpath/ - beat: - image: superset-1.0.1-extended - restart: on-failure - healthcheck: - disable: true - depends_on: - - superset - - postgres - - redis - command: "celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid --schedule /tmp/celerybeat-schedule" - volumes: - - ./config/:/app/pythonpath/ - superset: - image: superset-1.0.1-extended - restart: on-failure - environment: - - SUPERSET_PORT=8088 - ports: - - "8088:8088" - depends_on: - - postgres - - redis - command: gunicorn --bind 0.0.0.0:8088 --access-logfile - --error-logfile - --workers 5 --worker-class gthread --threads 4 --timeout 200 --limit-request-line 4094 --limit-request-field_size 8190 superset.app:create_app() - volumes: - - ./config/:/app/pythonpath/ -volumes: - db: - external: true - redis: - external: false -``` - -### Summary - -With the extended image created by using the `Dockerfile`, and then running that image using `docker-compose.yaml`, plus the required configurations in the `superset_config.py` you should now have alerts and reporting working correctly. - -- The above templates also work in a Docker swarm environment, you would just need to add `Deploy:` to the Superset, Redis and Postgres services along with your specific configs for your swarm - -# Old Reports feature - -## Scheduling and Emailing Reports - -(version 0.38 and below) - -### Email Reports - -Email reports allow users to schedule email reports for: - -- chart and dashboard visualization (attachment or inline) -- chart data (CSV attachment on inline table) - -Enable email reports in your `superset_config.py` file: - -```python -ENABLE_SCHEDULED_EMAIL_REPORTS = True -``` - -This flag enables some permissions that are stored in your database, so you'll want to run `superset init` again if you are running this in a dev environment. -Now you will find two new items in the navigation bar that allow you to schedule email reports: - -- **Manage > Dashboard Emails** -- **Manage > Chart Email Schedules** - -Schedules are defined in [crontab format](https://crontab.guru/) and each schedule can have a list -of recipients (all of them can receive a single mail, or separate mails). For audit purposes, all -outgoing mails can have a mandatory BCC. - -In order get picked up you need to configure a celery worker and a celery beat (see section above -“Celery Tasks”). Your celery configuration also needs an entry `email_reports.schedule_hourly` for -`CELERYBEAT_SCHEDULE`. - -To send emails you need to configure SMTP settings in your `superset_config.py` configuration file. - -```python -EMAIL_NOTIFICATIONS = True - -SMTP_HOST = "email-smtp.eu-west-1.amazonaws.com" -SMTP_STARTTLS = True -SMTP_SSL = False -SMTP_USER = "smtp_username" -SMTP_PORT = 25 -SMTP_PASSWORD = os.environ.get("SMTP_PASSWORD") -SMTP_MAIL_FROM = "insights@komoot.com" -``` - -To render dashboards you need to install a local browser on your Superset instance: - -- [geckodriver](https://github.com/mozilla/geckodriver) for Firefox -- [chromedriver](http://chromedriver.chromium.org/) for Chrome - -You'll need to adjust the `WEBDRIVER_TYPE` accordingly in your configuration. You also need -to specify on behalf of which username to render the dashboards. In general dashboards and charts -are not accessible to unauthorized requests, that is why the worker needs to take over credentials -of an existing user to take a snapshot. - -```python -THUMBNAIL_SELENIUM_USER = 'username_with_permission_to_access_dashboards' -``` - -**Important notes** - -- Be mindful of the concurrency setting for celery (using `-c 4`). Selenium/webdriver instances can - consume a lot of CPU / memory on your servers. -- In some cases, if you notice a lot of leaked geckodriver processes, try running your celery - processes with `celery worker --pool=prefork --max-tasks-per-child=128 ...` -- It is recommended to run separate workers for the `sql_lab` and `email_reports` tasks. This can be - done using the `queue` field in `CELERY_ANNOTATIONS`. -- Adjust `WEBDRIVER_BASEURL` in your configuration file if celery workers can’t access Superset via - its default value of `http://0.0.0.0:8080/`. +Don't forget to set `WEBDRIVER_TYPE` and `WEBDRIVER_OPTION_ARGS` in your config if you use Chrome. ### Schedule Reports @@ -392,94 +277,91 @@ You can optionally allow your users to schedule queries directly in SQL Lab. Thi extra metadata to saved queries, which are then picked up by an external scheduled (like [Apache Airflow](https://airflow.apache.org/)). -To allow scheduled queries, add the following to your configuration file: +To allow scheduled queries, add the following to `SCHEDULED_QUERIES` in your configuration file: ```python -FEATURE_FLAGS = { - # Configuration for scheduling queries from SQL Lab. This information is - # collected when the user clicks "Schedule query", and saved into the `extra` - # field of saved queries. +SCHEDULED_QUERIES = { + # This information is collected when the user clicks "Schedule query", + # and saved into the `extra` field of saved queries. # See: https://github.com/mozilla-services/react-jsonschema-form - 'SCHEDULED_QUERIES': { - 'JSONSCHEMA': { - 'title': 'Schedule', - 'description': ( - 'In order to schedule a query, you need to specify when it ' - 'should start running, when it should stop running, and how ' - 'often it should run. You can also optionally specify ' - 'dependencies that should be met before the query is ' - 'executed. Please read the documentation for best practices ' - 'and more information on how to specify dependencies.' - ), - 'type': 'object', - 'properties': { - 'output_table': { - 'type': 'string', - 'title': 'Output table name', - }, - 'start_date': { - 'type': 'string', - 'title': 'Start date', - # date-time is parsed using the chrono library, see - # https://www.npmjs.com/package/chrono-node#usage - 'format': 'date-time', - 'default': 'tomorrow at 9am', - }, - 'end_date': { - 'type': 'string', - 'title': 'End date', - # date-time is parsed using the chrono library, see - # https://www.npmjs.com/package/chrono-node#usage - 'format': 'date-time', - 'default': '9am in 30 days', - }, - 'schedule_interval': { - 'type': 'string', - 'title': 'Schedule interval', - }, - 'dependencies': { - 'type': 'array', - 'title': 'Dependencies', - 'items': { - 'type': 'string', - }, - }, + 'JSONSCHEMA': { + 'title': 'Schedule', + 'description': ( + 'In order to schedule a query, you need to specify when it ' + 'should start running, when it should stop running, and how ' + 'often it should run. You can also optionally specify ' + 'dependencies that should be met before the query is ' + 'executed. Please read the documentation for best practices ' + 'and more information on how to specify dependencies.' + ), + 'type': 'object', + 'properties': { + 'output_table': { + 'type': 'string', + 'title': 'Output table name', + }, + 'start_date': { + 'type': 'string', + 'title': 'Start date', + # date-time is parsed using the chrono library, see + # https://www.npmjs.com/package/chrono-node#usage + 'format': 'date-time', + 'default': 'tomorrow at 9am', + }, + 'end_date': { + 'type': 'string', + 'title': 'End date', + # date-time is parsed using the chrono library, see + # https://www.npmjs.com/package/chrono-node#usage + 'format': 'date-time', + 'default': '9am in 30 days', }, - }, - 'UISCHEMA': { 'schedule_interval': { - 'ui:placeholder': '@daily, @weekly, etc.', + 'type': 'string', + 'title': 'Schedule interval', }, 'dependencies': { - 'ui:help': ( - 'Check the documentation for the correct format when ' - 'defining dependencies.' - ), + 'type': 'array', + 'title': 'Dependencies', + 'items': { + 'type': 'string', + }, }, }, - 'VALIDATION': [ - # ensure that start_date <= end_date - { - 'name': 'less_equal', - 'arguments': ['start_date', 'end_date'], - 'message': 'End date cannot be before start date', - # this is where the error message is shown - 'container': 'end_date', - }, - ], - # link to the scheduler; this example links to an Airflow pipeline - # that uses the query id and the output table as its name - 'linkback': ( - 'https://airflow.example.com/admin/airflow/tree?' - 'dag_id=query_${id}_${extra_json.schedule_info.output_table}' - ), }, + 'UISCHEMA': { + 'schedule_interval': { + 'ui:placeholder': '@daily, @weekly, etc.', + }, + 'dependencies': { + 'ui:help': ( + 'Check the documentation for the correct format when ' + 'defining dependencies.' + ), + }, + }, + 'VALIDATION': [ + # ensure that start_date <= end_date + { + 'name': 'less_equal', + 'arguments': ['start_date', 'end_date'], + 'message': 'End date cannot be before start date', + # this is where the error message is shown + 'container': 'end_date', + }, + ], + # link to the scheduler; this example links to an Airflow pipeline + # that uses the query id and the output table as its name + 'linkback': ( + 'https://airflow.example.com/admin/airflow/tree?' + 'dag_id=query_${id}_${extra_json.schedule_info.output_table}' + ), } ``` -This feature flag is based on +This configuration is based on [react-jsonschema-form](https://github.com/mozilla-services/react-jsonschema-form) and will add a -button called “Schedule Query” to SQL Lab. When the button is clicked, a modal will show up where +menu item called “Schedule” to SQL Lab. When the menu item is clicked, a modal will show up where the user can add the metadata required for scheduling the query. This information can then be retrieved from the endpoint `/savedqueryviewapi/api/read` and used to diff --git a/docs/docs/installation/cache.mdx b/docs/docs/installation/cache.mdx index aaa8327451b8f..58b4bcb2b0b74 100644 --- a/docs/docs/installation/cache.mdx +++ b/docs/docs/installation/cache.mdx @@ -7,19 +7,49 @@ version: 1 ## Caching -Superset uses [Flask-Caching](https://flask-caching.readthedocs.io/) for caching purposes. Configuring caching is as easy as providing a custom cache config in your -`superset_config.py` that complies with [the Flask-Caching specifications](https://flask-caching.readthedocs.io/en/latest/#configuring-flask-caching). -Flask-Caching supports various caching backends, including Redis, Memcached, SimpleCache (in-memory), or the -local filesystem. Custom cache backends are also supported. See [here](https://flask-caching.readthedocs.io/en/latest/#custom-cache-backends) for specifics. -The following cache configurations can be customized: -- Metadata cache (optional): `CACHE_CONFIG` -- Charting data queried from datasets (optional): `DATA_CACHE_CONFIG` -- SQL Lab query results (optional): `RESULTS_BACKEND`. See [Async Queries via Celery](/docs/installation/async-queries-celery) for details +Superset uses [Flask-Caching](https://flask-caching.readthedocs.io/) for caching purposes. +Flask-Caching supports various caching backends, including Redis (recommended), Memcached, +SimpleCache (in-memory), or the local filesystem. +[Custom cache backends](https://flask-caching.readthedocs.io/en/latest/#custom-cache-backends) +are also supported. + +Caching can be configured by providing a dictionaries in +`superset_config.py` that comply with[the Flask-Caching config specifications](https://flask-caching.readthedocs.io/en/latest/#configuring-flask-caching). + +The following cache configurations can be customized in this way: - Dashboard filter state (required): `FILTER_STATE_CACHE_CONFIG`. - Explore chart form data (required): `EXPLORE_FORM_DATA_CACHE_CONFIG` +- Metadata cache (optional): `CACHE_CONFIG` +- Charting data queried from datasets (optional): `DATA_CACHE_CONFIG` + +For example, to configure the filter state cache using redis: + +```python +FILTER_STATE_CACHE_CONFIG = { + 'CACHE_TYPE': 'RedisCache', + 'CACHE_DEFAULT_TIMEOUT': 86400, + 'CACHE_KEY_PREFIX': 'superset_filter_cache', + 'CACHE_REDIS_URL': 'redis://localhost:6379/0' +} +``` + +### Dependencies + +In order to use dedicated cache stores, additional python libraries must be installed + +- For Redis: we recommend the [redis](https://pypi.python.org/pypi/redis) Python package +- Memcached: we recommend using [pylibmc](https://pypi.org/project/pylibmc/) client library as + `python-memcached` does not handle storing binary data correctly. + +These libraries can be installed using pip. + +### Fallback Metastore Cache + +Note, that some form of Filter State and Explore caching are required. If either of these caches +are undefined, Superset falls back to using a built-in cache that stores data in the metadata +database. While it is recommended to use a dedicated cache, the built-in cache can also be used +to cache other data. -Please note, that Dashboard and Explore caching is required. If these caches are undefined, Superset falls back to using a built-in cache that stores data -in the metadata database. While it is recommended to use a dedicated cache, the built-in cache can also be used to cache other data. For example, to use the built-in cache to store chart data, use the following config: ```python @@ -30,21 +60,25 @@ DATA_CACHE_CONFIG = { } ``` -- Redis (recommended): we recommend the [redis](https://pypi.python.org/pypi/redis) Python package -- Memcached: we recommend using [pylibmc](https://pypi.org/project/pylibmc/) client library as - `python-memcached` does not handle storing binary data correctly. +### Chart Cache Timeout -Both of these libraries can be installed using pip. +The cache timeout for charts may be overridden by the settings for an individual chart, dataset, or +database. Each of these configurations will be checked in order before falling back to the default +value defined in `DATA_CACHE_CONFIG. -For chart data, Superset goes up a “timeout search path”, from a slice's configuration -to the datasource’s, the database’s, then ultimately falls back to the global default -defined in `DATA_CACHE_CONFIG`. +### SQL Lab Query Results -## Celery beat +Caching for SQL Lab query results is used when async queries are enabled and is configured using +`RESULTS_BACKEND`. + +Note that this configuration does not use a flask-caching dictionary for its configuration, but +instead requires a cachelib object. + +See [Async Queries via Celery](/docs/installation/async-queries-celery) for details. ### Caching Thumbnails -This is an optional feature that can be turned on by activating it’s feature flag on config: +This is an optional feature that can be turned on by activating it’s [feature flag](https://superset.apache.org/docs/installation/configuring-superset#feature-flags) on config: ``` FEATURE_FLAGS = { @@ -53,6 +87,13 @@ FEATURE_FLAGS = { } ``` +By default thumbnails are rendered using the `THUMBNAIL_SELENIUM_USER` user account. To render thumbnails as the +logged in user (e.g. in environments that are using user impersonation), use the following configuration: + +```python +THUMBNAIL_EXECUTE_AS = [ExecutorType.CURRENT_USER] +``` + For this feature you will need a cache system and celery workers. All thumbnails are stored on cache and are processed asynchronously by the workers. diff --git a/docs/docs/installation/configuring-superset.mdx b/docs/docs/installation/configuring-superset.mdx index 05f845c114ec0..aefc12d603061 100644 --- a/docs/docs/installation/configuring-superset.mdx +++ b/docs/docs/installation/configuring-superset.mdx @@ -149,7 +149,11 @@ Make sure the pip package [`Authlib`](https://authlib.org/) is installed on the First, configure authorization in Superset `superset_config.py`. ```python +from flask_appbuilder.security.manager import AUTH_OAUTH + +# Set the authentication type to OAuth AUTH_TYPE = AUTH_OAUTH + OAUTH_PROVIDERS = [ { 'name':'egaSSO', 'token_key':'access_token', # Name of the token in the response of access_token_url diff --git a/docs/docs/installation/event-logging.mdx b/docs/docs/installation/event-logging.mdx index 7b9bba1de4e6d..2cb35d5047dcd 100644 --- a/docs/docs/installation/event-logging.mdx +++ b/docs/docs/installation/event-logging.mdx @@ -9,9 +9,11 @@ version: 1 ### Event Logging -Superset by default logs special action events in its internal database. These logs can be accessed +Superset by default logs special action events in its internal database (DBEventLogger). These logs can be accessed on the UI by navigating to **Security > Action Log**. You can freely customize these logs by implementing your own event log class. +**When custom log class is enabled DBEventLogger is disabled and logs stop being populated in UI logs view.** +To achieve both, custom log class should extend built-in DBEventLogger log class. Here's an example of a simple JSON-to-stdout class: diff --git a/docs/docs/installation/installing-superset-from-scratch.mdx b/docs/docs/installation/installing-superset-from-scratch.mdx index 3a12c9db3ac13..b15ccb3157482 100644 --- a/docs/docs/installation/installing-superset-from-scratch.mdx +++ b/docs/docs/installation/installing-superset-from-scratch.mdx @@ -64,7 +64,7 @@ We don't recommend using the system installed Python. Instead, first install the brew install readline pkg-config libffi openssl mysql postgres ``` -You should install a recent version of Python (the official docker image uses 3.8.12). We'd recommend using a Python version manager like [pyenv](https://github.com/pyenv/pyenv) (and also [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv)). +You should install a recent version of Python (the official docker image uses 3.8.16). We'd recommend using a Python version manager like [pyenv](https://github.com/pyenv/pyenv) (and also [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv)). Let's also make sure we have the latest version of `pip` and `setuptools`: diff --git a/docs/docs/installation/installing-superset-using-docker-compose.mdx b/docs/docs/installation/installing-superset-using-docker-compose.mdx index 89ed9f1d63e54..ae53085947a7f 100644 --- a/docs/docs/installation/installing-superset-using-docker-compose.mdx +++ b/docs/docs/installation/installing-superset-using-docker-compose.mdx @@ -84,9 +84,11 @@ and wait for the `superset_node` container to finish building the assets. #### Configuring Docker Compose -The following is for users who want to configure how Superset starts up in Docker Compose; otherwise, you can skip to the next section. +The following is for users who want to configure how Superset runs in Docker Compose; otherwise, you can skip to the next section. -You can configure the Docker Compose settings for dev and non-dev mode with `docker/.env` and `docker/.env-non-dev` respectively. These environment files set the environment for most containers in the Docker Compose setup, and some variables affect multiple containers and others only single ones. +You can install additional python packages and apply config overrides by following the steps mentioned in [docker/README.md](https://github.com/apache/superset/tree/master/docker#configuration) + +You can configure the Docker Compose environment varirables for dev and non-dev mode with `docker/.env` and `docker/.env-non-dev` respectively. These environment files set the environment for most containers in the Docker Compose setup, and some variables affect multiple containers and others only single ones. One important variable is `SUPERSET_LOAD_EXAMPLES` which determines whether the `superset_init` container will load example data and visualizations into the database and Superset. These examples are quite helpful for most people, but probably unnecessary for experienced users. The loading process can sometimes take a few minutes and a good amount of CPU, so you may want to disable it on a resource-constrained device. @@ -116,4 +118,4 @@ When running Superset using `docker` or `docker-compose` it runs in its own dock Here the instructions are for connecting to postgresql (which is running on your host machine) from Superset (which is running in its docker container). Other databases may have slightly different configurations but gist would be same and boils down to 2 steps - 1. **(Mac users may skip this step)** Configuring the local postgresql/database instance to accept public incoming connections. By default postgresql only allows incoming connections from `localhost` only, but re-iterating once again, `localhosts` are different for host machine and docker container. For postgresql this involves make one-line changes to the files `postgresql.conf` and `pg_hba.conf`, you can find helpful links tailored to your OS / PG version on the web easily for this task. For docker it suffices to only whitelist IPs `172.0.0.0/8` instead of `*`, but in any case you are _warned_ that doing this in a production database _may_ have disastrous consequences as you are opening your database to the public internet. -2. Instead of `localhost`, try using `host.docker.internal` (Mac users) or `172.18.0.1` (Linux users) as the host name when attempting to connect to the database. This is docker internal detail, what is happening is that in Mac systems docker creates a dns entry for the host name `host.docker.internal` which resolves to the correct address for the host machine, whereas in linux this is not the case (at least by default). If neither of these 2 hostnames work then you may want to find the exact host name you want to use, for that you can do `ifconfig` or `ip addr show` and look at the IP address of `docker0` interface that must have been created by docker for you. Alternately if you don't even see the `docker0` interface try (if needed with sudo) `docker network inspect bridge` and see if there is an entry for `"Gateway"` and note the IP address. +2. Instead of `localhost`, try using `host.docker.internal` (Mac users, Ubuntu) or `172.18.0.1` (Linux users) as the host name when attempting to connect to the database. This is docker internal detail, what is happening is that in Mac systems docker creates a dns entry for the host name `host.docker.internal` which resolves to the correct address for the host machine, whereas in linux this is not the case (at least by default). If neither of these 2 hostnames work then you may want to find the exact host name you want to use, for that you can do `ifconfig` or `ip addr show` and look at the IP address of `docker0` interface that must have been created by docker for you. Alternately if you don't even see the `docker0` interface try (if needed with sudo) `docker network inspect bridge` and see if there is an entry for `"Gateway"` and note the IP address. diff --git a/docs/docs/installation/running-on-kubernetes.mdx b/docs/docs/installation/running-on-kubernetes.mdx index af76187517082..61fa84721bf19 100644 --- a/docs/docs/installation/running-on-kubernetes.mdx +++ b/docs/docs/installation/running-on-kubernetes.mdx @@ -63,7 +63,7 @@ superset-worker-75b48bbcc-qrq49 1/1 Running 0 4m12s The exact list will depend on some of your specific configuration overrides but you should generally expect: -- N `superset-xxxx-yyyy` and `superset-worker-xxxx-yyyy` pods (depending on your `replicaCount` value) +- N `superset-xxxx-yyyy` and `superset-worker-xxxx-yyyy` pods (depending on your `supersetNode.replicaCount` and `supersetWorker.replicaCount` values) - 1 `superset-postgresql-0` depending on your postgres settings - 1 `superset-redis-master-0` depending on your redis settings - 1 `superset-celerybeat-xxxx-yyyy` pod if you have `supersetCeleryBeat.enabled = true` in your values overrides @@ -123,16 +123,27 @@ init: #### Dependencies -Install additional packages and do any other bootstrap configuration in this script. For production clusters it's -recommended to build own image with this step done in CI. The following example installs the Big Query and Elasticsearch -database drivers so that you can connect to those datasources in your Superset installation. +Install additional packages and do any other bootstrap configuration in the bootstrap script. +For production clusters it's recommended to build own image with this step done in CI. + +:::note + +Superset requires a Python DB-API database driver and a SQLAlchemy +dialect to be installed for each datastore you want to connect to. + +See [Install Database Drivers](/docs/databases/installing-database-drivers) for more information + +::: + +The following example installs the Big Query and Elasticsearch database drivers so that you can +connect to those datasources in your Superset installation: ```yaml bootstrapScript: | #!/bin/bash pip install psycopg2==2.9.1 \ redis==3.2.1 \ - pybigquery==2.26.0 \ + sqlalchemy-bigquery==1.5.0 \ elasticsearch-dbapi==0.2.5 &&\ if [ ! -f ~/bootstrap ]; then echo "Running Superset with uid {{ .Values.runAsUser }}" > ~/bootstrap; fi ``` @@ -226,6 +237,14 @@ Those will also be mounted as secrets and can include sensitive parameters. #### Setting up OAuth +:::note + +OAuth setup requires that the [authlib](https://authlib.org/) Python library is installed. This can +be done using `pip` by updating the `bootstrapScript`. See the [Dependencies](#dependencies) section +for more information. + +::: + ```yaml extraEnv: AUTH_DOMAIN: example.com @@ -239,7 +258,7 @@ configOverrides: # This will make sure the redirect_uri is properly computed, even with SSL offloading ENABLE_PROXY_FIX = True - from flask_appbuilder.security.manager import (AUTH_OAUTH, AUTH_DB) + from flask_appbuilder.security.manager import AUTH_OAUTH AUTH_TYPE = AUTH_OAUTH OAUTH_PROVIDERS = [ { diff --git a/docs/docs/installation/sql-templating.mdx b/docs/docs/installation/sql-templating.mdx index 09373d8999d06..72c2c0a9adb75 100644 --- a/docs/docs/installation/sql-templating.mdx +++ b/docs/docs/installation/sql-templating.mdx @@ -10,7 +10,7 @@ version: 1 ### Jinja Templates SQL Lab and Explore supports [Jinja templating](https://jinja.palletsprojects.com/en/2.11.x/) in queries. -To enable templating, the `ENABLE_TEMPLATE_PROCESSING` feature flag needs to be enabled in +To enable templating, the `ENABLE_TEMPLATE_PROCESSING` [feature flag](https://superset.apache.org/docs/installation/configuring-superset#feature-flags) needs to be enabled in `superset_config.py`. When templating is enabled, python code can be embedded in virtual datasets and in Custom SQL in the filter and metric controls in Explore. By default, the following variables are made available in the Jinja context: @@ -298,7 +298,7 @@ Here's a concrete example: It's possible to query physical and virtual datasets using the `dataset` macro. This is useful if you've defined computed columns and metrics on your datasets, and want to reuse the definition in adhoc SQL Lab queries. -To use the macro, first you need to find the ID of the dataset. This can be done by going to the view showing all the datasets, hovering over the dataset you're interested in, and looking at its URL. For example, if the URL for a dataset is https://superset.example.org/superset/explore/table/42/ its ID is 42. +To use the macro, first you need to find the ID of the dataset. This can be done by going to the view showing all the datasets, hovering over the dataset you're interested in, and looking at its URL. For example, if the URL for a dataset is https://superset.example.org/explore/?dataset_type=table&dataset_id=42 its ID is 42. Once you have the ID you can query it as if it were a table: diff --git a/docs/docs/intro.mdx b/docs/docs/intro.mdx index 77ff12df83e76..2d2de074aec3a 100644 --- a/docs/docs/intro.mdx +++ b/docs/docs/intro.mdx @@ -30,7 +30,7 @@ Superset provides: - A lightweight semantic layer which empowers data analysts to quickly define custom dimensions and metrics - Out-of-the-box support for most SQL-speaking databases - Seamless, in-memory asynchronous caching and queries -- An extensible security model that allows configuration of very intricate rules on on who can access which product features and datasets. +- An extensible security model that allows configuration of very intricate rules on who can access which product features and datasets. - Integration with major authentication backends (database, OpenID, LDAP, OAuth, REMOTE_USER, etc) - The ability to add custom visualization plugins - An API for programmatic customization diff --git a/docs/docs/miscellaneous/country-map-tools.mdx b/docs/docs/miscellaneous/country-map-tools.mdx index 5e490b2057f4f..20d1dbe22c4f2 100644 --- a/docs/docs/miscellaneous/country-map-tools.mdx +++ b/docs/docs/miscellaneous/country-map-tools.mdx @@ -43,6 +43,7 @@ The Country Maps visualization already ships with the maps for the following cou - Syria - Thailand - Timorleste +- Turkey - UK - Ukraine - Uruguay diff --git a/docs/docs/security.mdx b/docs/docs/security.mdx index 283e48d9b0583..e868de6a99aff 100644 --- a/docs/docs/security.mdx +++ b/docs/docs/security.mdx @@ -153,6 +153,43 @@ of a policy and if it's not able to find one, it will issue a warning with the s where CSP policies are defined outside of Superset using other software, administrators can disable the warning using the `CONTENT_SECURITY_POLICY_WARNING` key in `config.py`. +#### CSP Requirements + +* Superset needs both the `'unsafe-eval'` and `'unsafe-inline'` CSP keywords in order to operate. + + ``` + default-src 'self' 'unsafe-eval' 'unsafe-inline' + ``` + +* Some dashbaords load images using data URIs and require `data:` in their `img-src` + + ``` + img-src 'self' data: + ``` + +* MapBox charts use workers and need to connect to MapBox servers in addition to the Superset origin + + ``` + worker-src 'self' blob: + connect-src 'self' https://api.mapbox.com https://events.mapbox.com + ``` + +This is a basic example `TALISMAN_CONFIG` that implements the above requirements, uses `'self'` to +limit content to the same origin as the Superset server, and disallows outdated HTML elements by +setting `object-src` to `'none'`. + +```python +TALISMAN_CONFIG = { + "content_security_policy": { + "default-src": ["'self'", "'unsafe-inline'", "'unsafe-eval'"], + "img-src": ["'self'", "data:"], + "worker-src": ["'self'", "blob:"], + "connect-src": ["'self'", "https://api.mapbox.com", "https://events.mapbox.com"], + "object-src": "'none'", + } +} +``` + ### Reporting Security Vulnerabilities Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 7c86ff067cd0f..e6121cca9348b 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -37,11 +37,14 @@ const config = { projectName: 'superset', // Usually your repo name. themes: ['@saucelabs/theme-github-codeblock'], plugins: [ - ["docusaurus-plugin-less", { - lessOptions: { - javascriptEnabled: true, - } - }], + [ + 'docusaurus-plugin-less', + { + lessOptions: { + javascriptEnabled: true, + }, + }, + ], [ '@docusaurus/plugin-client-redirects', { @@ -185,10 +188,6 @@ const config = { label: 'Getting Started', to: '/docs/intro', }, - { - label: 'Tutorial', - to: '/docs/intro', - }, { label: 'FAQ', to: '/docs/frequently-asked-questions', @@ -208,7 +207,7 @@ const config = { }, { label: 'Slack', - href: 'https://join.slack.com/t/apache-superset/shared_invite/zt-16jvzmoi8-sI7jKWp~xc2zYRe~NqiY9Q', + href: 'http://bit.ly/join-superset-slack', }, { label: 'Mailing List', @@ -229,8 +228,7 @@ const config = { }, footer: { style: 'dark', - links: [ - ], + links: [], copyright: `Copyright © ${new Date().getFullYear()}, The <a href="https://www.apache.org/" target="_blank" rel="noreferrer">Apache Software Foundation</a>, Licensed under the Apache <a href="https://apache.org/licenses/LICENSE-2.0" target="_blank" rel="noreferrer">License</a>. <br/> @@ -249,6 +247,7 @@ const config = { darkTheme: darkCodeTheme, }, }), + scripts: ['/script/matomo.js'], }; module.exports = config; diff --git a/docs/src/pages/community.tsx b/docs/src/pages/community.tsx index 1cd9830dbf261..52d8bb33064a5 100644 --- a/docs/src/pages/community.tsx +++ b/docs/src/pages/community.tsx @@ -23,7 +23,7 @@ import Layout from '@theme/Layout'; const links = [ [ - 'https://join.slack.com/t/apache-superset/shared_invite/zt-16jvzmoi8-sI7jKWp~xc2zYRe~NqiY9Q', + 'http://bit.ly/join-superset-slack', 'Slack', 'interact with other Superset users and community members', ], @@ -37,6 +37,11 @@ const links = [ 'dev@ Mailing List', 'participate in conversations with committers and contributors', ], + [ + 'https://calendar.google.com/calendar/u/2?cid=c3VwZXJzZXQuY29tbWl0dGVyc0BnbWFpbC5jb20', + 'Superset Community Calendar', + 'join us for working group sessions and other community gatherings', + ], [ 'https://stackoverflow.com/questions/tagged/superset+apache-superset', 'Stack Overflow', diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index d57225a0d797c..f3781a4039cca 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -249,6 +249,15 @@ const CarouselSection = styled('div')` } `; +const StyledCredits = styled.div` + width: 100%; + height: 60px; + padding: 18px; + background-color: #282E4A; + text-align: center; + color: #FFFFFF; +`; + const StyledDatabaseImg = styled.img` width: ${(props) => props.width}; height: ${(props) => props.height}; @@ -427,13 +436,13 @@ export default function Home(): JSX.Element { </div> <Carousel ref={slider} effect="scrollx" afterChange={onChange}> <div className="imageContainer"> - <img src="img/explorer5.jpg" alt="" /> + <img src="img/explore.jpg" alt="Explore (chart buider) UI" /> </div> <div className="imageContainer"> - <img src="img/dashboard3.png" alt="" /> + <img src="img/dashboard.jpg" alt="Superset Dashboard" /> </div> <div className="imageContainer"> - <img src="img/sqllab5.jpg" alt="" /> + <img src="img/sql_lab.jpg" alt="SQL Lab" /> </div> </Carousel> </div> @@ -461,8 +470,13 @@ export default function Home(): JSX.Element { </span> </StyledIntegrations> </CarouselSection> - </StyledMain> + <StyledCredits> + We use{' '} + <a href="https://applitools.com/" target="_blank" rel="nofollow"> + <img src="img/applitools.png" title="Applitools" /> + </a> + </StyledCredits> </Layout> ); } diff --git a/docs/src/resources/data.js b/docs/src/resources/data.js index 08d0781f86965..49bc554a4dfed 100644 --- a/docs/src/resources/data.js +++ b/docs/src/resources/data.js @@ -48,6 +48,11 @@ export const Databases = [ href: 'https://dremio.com/', imgName: 'dremio.png', }, + { + title: 'Databricks', + href: 'https://www.databricks.com', + imgName: 'databricks.png', + }, { title: 'Exasol', href: 'https://www.exasol.com/en/', @@ -138,6 +143,11 @@ export const Databases = [ href: "www.teradata.com", imgName: 'teradata.png' }, + { + title: 'TimescaleDB', + href: "www.timescale.com", + imgName: 'timescale.png' + }, { title: 'YugabyteDB', href: "www.yugabyte.com", diff --git a/docs/static/img/applitools.png b/docs/static/img/applitools.png new file mode 100644 index 0000000000000..66b7b1eb4f375 Binary files /dev/null and b/docs/static/img/applitools.png differ diff --git a/docs/static/img/dashboard.jpg b/docs/static/img/dashboard.jpg new file mode 100644 index 0000000000000..c1e539f76e3c9 Binary files /dev/null and b/docs/static/img/dashboard.jpg differ diff --git a/docs/static/img/dashboard3.png b/docs/static/img/dashboard3.png deleted file mode 100644 index e7d9092dede13..0000000000000 Binary files a/docs/static/img/dashboard3.png and /dev/null differ diff --git a/docs/static/img/databases/databricks.png b/docs/static/img/databases/databricks.png new file mode 100644 index 0000000000000..fa4a501011697 Binary files /dev/null and b/docs/static/img/databases/databricks.png differ diff --git a/docs/static/img/databases/timescale.png b/docs/static/img/databases/timescale.png new file mode 100644 index 0000000000000..86706ec445db4 Binary files /dev/null and b/docs/static/img/databases/timescale.png differ diff --git a/docs/static/img/explore.jpg b/docs/static/img/explore.jpg new file mode 100644 index 0000000000000..110b551492f86 Binary files /dev/null and b/docs/static/img/explore.jpg differ diff --git a/docs/static/img/explorer5.jpg b/docs/static/img/explorer5.jpg deleted file mode 100644 index 37c5e1b9c7fa5..0000000000000 Binary files a/docs/static/img/explorer5.jpg and /dev/null differ diff --git a/docs/static/img/sql_lab.jpg b/docs/static/img/sql_lab.jpg new file mode 100644 index 0000000000000..8278ee61381e4 Binary files /dev/null and b/docs/static/img/sql_lab.jpg differ diff --git a/docs/static/img/sqllab5.jpg b/docs/static/img/sqllab5.jpg deleted file mode 100644 index 7afb1ddc2ae1c..0000000000000 Binary files a/docs/static/img/sqllab5.jpg and /dev/null differ diff --git a/docs/static/resources/openapi.json b/docs/static/resources/openapi.json index 330c629063add..18ea7a47f8f19 100644 --- a/docs/static/resources/openapi.json +++ b/docs/static/resources/openapi.json @@ -61,6 +61,94 @@ }, "description": "Not found" }, + "410": { + "content": { + "application/json": { + "schema": { + "properties": { + "errors": { + "items": { + "properties": { + "error_type": { + "enum": [ + "FRONTEND_CSRF_ERROR", + "FRONTEND_NETWORK_ERROR", + "FRONTEND_TIMEOUT_ERROR", + "GENERIC_DB_ENGINE_ERROR", + "COLUMN_DOES_NOT_EXIST_ERROR", + "TABLE_DOES_NOT_EXIST_ERROR", + "SCHEMA_DOES_NOT_EXIST_ERROR", + "CONNECTION_INVALID_USERNAME_ERROR", + "CONNECTION_INVALID_PASSWORD_ERROR", + "CONNECTION_INVALID_HOSTNAME_ERROR", + "CONNECTION_PORT_CLOSED_ERROR", + "CONNECTION_INVALID_PORT_ERROR", + "CONNECTION_HOST_DOWN_ERROR", + "CONNECTION_ACCESS_DENIED_ERROR", + "CONNECTION_UNKNOWN_DATABASE_ERROR", + "CONNECTION_DATABASE_PERMISSIONS_ERROR", + "CONNECTION_MISSING_PARAMETERS_ERROR", + "OBJECT_DOES_NOT_EXIST_ERROR", + "SYNTAX_ERROR", + "CONNECTION_DATABASE_TIMEOUT", + "VIZ_GET_DF_ERROR", + "UNKNOWN_DATASOURCE_TYPE_ERROR", + "FAILED_FETCHING_DATASOURCE_INFO_ERROR", + "TABLE_SECURITY_ACCESS_ERROR", + "DATASOURCE_SECURITY_ACCESS_ERROR", + "DATABASE_SECURITY_ACCESS_ERROR", + "QUERY_SECURITY_ACCESS_ERROR", + "MISSING_OWNERSHIP_ERROR", + "USER_ACTIVITY_SECURITY_ACCESS_ERROR", + "BACKEND_TIMEOUT_ERROR", + "DATABASE_NOT_FOUND_ERROR", + "MISSING_TEMPLATE_PARAMS_ERROR", + "INVALID_TEMPLATE_PARAMS_ERROR", + "RESULTS_BACKEND_NOT_CONFIGURED_ERROR", + "DML_NOT_ALLOWED_ERROR", + "INVALID_CTAS_QUERY_ERROR", + "INVALID_CVAS_QUERY_ERROR", + "SQLLAB_TIMEOUT_ERROR", + "RESULTS_BACKEND_ERROR", + "ASYNC_WORKERS_ERROR", + "ADHOC_SUBQUERY_NOT_ALLOWED_ERROR", + "GENERIC_COMMAND_ERROR", + "GENERIC_BACKEND_ERROR", + "INVALID_PAYLOAD_FORMAT_ERROR", + "INVALID_PAYLOAD_SCHEMA_ERROR", + "REPORT_NOTIFICATION_ERROR" + ], + "type": "string" + }, + "extra": { + "type": "object" + }, + "level": { + "enum": [ + "info", + "warning", + "error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Gone" + }, "422": { "content": { "application/json": { @@ -93,6 +181,31 @@ } }, "schemas": { + "AdvancedDataTypeSchema": { + "properties": { + "display_value": { + "description": "The string representation of the parsed values", + "type": "string" + }, + "error_message": { + "type": "string" + }, + "valid_filter_operators": { + "items": { + "type": "string" + }, + "type": "array" + }, + "values": { + "items": { + "description": "parsed value (can be any value)", + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, "AnnotationLayer": { "properties": { "annotationType": { @@ -522,6 +635,17 @@ }, "type": "object" }, + "AvailableDomainsSchema": { + "properties": { + "domains": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, "CacheInvalidationRequestSchema": { "properties": { "datasource_uids": { @@ -780,8 +904,12 @@ "type": { "description": "Datasource type", "enum": [ - "druid", - "table" + "sl_table", + "table", + "dataset", + "query", + "saved_query", + "view" ], "type": "string" } @@ -793,17 +921,12 @@ }, "ChartDataExtras": { "properties": { - "druid_time_origin": { - "description": "Starting point for time grain counting on legacy Druid datasources. Used to change e.g. Monday/Sunday first-day-of-week.", - "nullable": true, - "type": "string" - }, "having": { "description": "HAVING clause to be added to aggregate queries using AND operator.", "type": "string" }, "having_druid": { - "description": "HAVING filters to be added to legacy Druid datasource queries.", + "description": "HAVING filters to be added to legacy Druid datasource queries. This field is deprecated", "items": { "$ref": "#/components/schemas/ChartDataFilter" }, @@ -891,18 +1014,20 @@ "NOT IN", "REGEX", "IS TRUE", - "IS FALSE" + "IS FALSE", + "TEMPORAL_RANGE" ], "example": "IN", "type": "string" }, "val": { - "description": "The value or values to compare against. Can be a string, integer, decimal or list, depending on the operator.", + "description": "The value or values to compare against. Can be a string, integer, decimal, None or list, depending on the operator.", "example": [ "China", "France", "Japan" - ] + ], + "nullable": true } }, "required": [ @@ -1033,20 +1158,23 @@ "enum": [ "aggregate", "boxplot", + "compare", "contribution", "cum", + "diff", + "escape_separator", + "flatten", "geodetic_parse", "geohash_decode", "geohash_encode", "pivot", "prophet", + "rename", + "resample", "rolling", "select", "sort", - "diff", - "compare", - "resample", - "flatten" + "unescape_separator" ], "example": "aggregate", "type": "string" @@ -1095,6 +1223,7 @@ "example": false }, "periods": { + "description": "Time periods (in units of `time_grain`) to predict into the future", "example": 7, "format": "int32", "type": "integer" @@ -1143,11 +1272,18 @@ }, "ChartDataQueryContextSchema": { "properties": { + "custom_cache_timeout": { + "description": "Override the default cache timeout", + "format": "int32", + "nullable": true, + "type": "integer" + }, "datasource": { "$ref": "#/components/schemas/ChartDataDatasource" }, "force": { "description": "Should the queries be forced to load from the source. Default: `false`", + "nullable": true, "type": "boolean" }, "form_data": { @@ -1405,7 +1541,7 @@ "type": "string" }, "cache_timeout": { - "description": "Cache timeout in following order: custom timeout, datasource timeout, default config timeout.", + "description": "Cache timeout in following order: custom timeout, datasource timeout, cache default timeout, config default cache timeout.", "format": "int32", "nullable": true, "type": "integer" @@ -1443,6 +1579,7 @@ "type": "string" }, "from_dttm": { + "description": "Start timestamp of time range", "format": "int32", "nullable": true, "type": "integer" @@ -1468,6 +1605,7 @@ "type": "integer" }, "stacktrace": { + "description": "Stacktrace if there was an error", "nullable": true, "type": "string" }, @@ -1485,6 +1623,7 @@ "type": "string" }, "to_dttm": { + "description": "End timestamp of time range", "format": "int32", "nullable": true, "type": "integer" @@ -1526,6 +1665,9 @@ "nullable": true, "type": "string" }, + "changed_on_delta_humanized": { + "readOnly": true + }, "dashboards": { "$ref": "#/components/schemas/ChartDataRestApi.get.Dashboard" }, @@ -1533,6 +1675,13 @@ "nullable": true, "type": "string" }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_managed_externally": { + "type": "boolean" + }, "owners": { "$ref": "#/components/schemas/ChartDataRestApi.get.User" }, @@ -1549,6 +1698,12 @@ "nullable": true, "type": "string" }, + "thumbnail_url": { + "readOnly": true + }, + "url": { + "readOnly": true + }, "viz_type": { "maxLength": 250, "nullable": true, @@ -1617,7 +1772,7 @@ "type": "string" }, "changed_by": { - "$ref": "#/components/schemas/ChartDataRestApi.get_list.User1" + "$ref": "#/components/schemas/ChartDataRestApi.get_list.User" }, "changed_by_name": { "readOnly": true @@ -1634,6 +1789,12 @@ "created_by": { "$ref": "#/components/schemas/ChartDataRestApi.get_list.User2" }, + "created_on_delta_humanized": { + "readOnly": true + }, + "dashboards": { + "$ref": "#/components/schemas/ChartDataRestApi.get_list.Dashboard" + }, "datasource_id": { "format": "int32", "nullable": true, @@ -1664,16 +1825,19 @@ "format": "int32", "type": "integer" }, + "is_managed_externally": { + "type": "boolean" + }, "last_saved_at": { "format": "date-time", "nullable": true, "type": "string" }, "last_saved_by": { - "$ref": "#/components/schemas/ChartDataRestApi.get_list.User" + "$ref": "#/components/schemas/ChartDataRestApi.get_list.User3" }, "owners": { - "$ref": "#/components/schemas/ChartDataRestApi.get_list.User3" + "$ref": "#/components/schemas/ChartDataRestApi.get_list.User1" }, "params": { "nullable": true, @@ -1701,6 +1865,20 @@ }, "type": "object" }, + "ChartDataRestApi.get_list.Dashboard": { + "properties": { + "dashboard_title": { + "maxLength": 500, + "nullable": true, + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, "ChartDataRestApi.get_list.SqlaTable": { "properties": { "default_endpoint": { @@ -1723,10 +1901,6 @@ "maxLength": 64, "type": "string" }, - "id": { - "format": "int32", - "type": "integer" - }, "last_name": { "maxLength": 64, "type": "string" @@ -1744,14 +1918,23 @@ "maxLength": 64, "type": "string" }, + "id": { + "format": "int32", + "type": "integer" + }, "last_name": { "maxLength": 64, "type": "string" + }, + "username": { + "maxLength": 64, + "type": "string" } }, "required": [ "first_name", - "last_name" + "last_name", + "username" ], "type": "object" }, @@ -1789,16 +1972,11 @@ "last_name": { "maxLength": 64, "type": "string" - }, - "username": { - "maxLength": 64, - "type": "string" } }, "required": [ "first_name", - "last_name", - "username" + "last_name" ], "type": "object" }, @@ -1841,8 +2019,11 @@ "datasource_type": { "description": "The type of dataset/datasource identified on `datasource_id`.", "enum": [ - "druid", + "sl_table", "table", + "dataset", + "query", + "saved_query", "view" ], "type": "string" @@ -1944,8 +2125,11 @@ "datasource_type": { "description": "The type of dataset/datasource identified on `datasource_id`.", "enum": [ - "druid", + "sl_table", "table", + "dataset", + "query", + "saved_query", "view" ], "nullable": true, @@ -2052,6 +2236,7 @@ "type": "string" }, "rolling_type_options": { + "description": "Optional options to pass to rolling method. Needed for e.g. quantile operation.", "example": {}, "type": "object" }, @@ -2188,10 +2373,8 @@ "description": "Form data from the Explore controls used to form the chart's data query.", "type": "object" }, - "modified": { - "type": "string" - }, - "slice_id": { + "id": { + "description": "The id of the chart.", "format": "int32", "type": "integer" }, @@ -2275,6 +2458,9 @@ "nullable": true, "type": "string" }, + "changed_on_delta_humanized": { + "readOnly": true + }, "dashboards": { "$ref": "#/components/schemas/ChartRestApi.get.Dashboard" }, @@ -2282,6 +2468,13 @@ "nullable": true, "type": "string" }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_managed_externally": { + "type": "boolean" + }, "owners": { "$ref": "#/components/schemas/ChartRestApi.get.User" }, @@ -2298,6 +2491,12 @@ "nullable": true, "type": "string" }, + "thumbnail_url": { + "readOnly": true + }, + "url": { + "readOnly": true + }, "viz_type": { "maxLength": 250, "nullable": true, @@ -2366,7 +2565,7 @@ "type": "string" }, "changed_by": { - "$ref": "#/components/schemas/ChartRestApi.get_list.User1" + "$ref": "#/components/schemas/ChartRestApi.get_list.User" }, "changed_by_name": { "readOnly": true @@ -2383,6 +2582,12 @@ "created_by": { "$ref": "#/components/schemas/ChartRestApi.get_list.User2" }, + "created_on_delta_humanized": { + "readOnly": true + }, + "dashboards": { + "$ref": "#/components/schemas/ChartRestApi.get_list.Dashboard" + }, "datasource_id": { "format": "int32", "nullable": true, @@ -2413,16 +2618,19 @@ "format": "int32", "type": "integer" }, + "is_managed_externally": { + "type": "boolean" + }, "last_saved_at": { "format": "date-time", "nullable": true, "type": "string" }, "last_saved_by": { - "$ref": "#/components/schemas/ChartRestApi.get_list.User" + "$ref": "#/components/schemas/ChartRestApi.get_list.User3" }, "owners": { - "$ref": "#/components/schemas/ChartRestApi.get_list.User3" + "$ref": "#/components/schemas/ChartRestApi.get_list.User1" }, "params": { "nullable": true, @@ -2450,6 +2658,20 @@ }, "type": "object" }, + "ChartRestApi.get_list.Dashboard": { + "properties": { + "dashboard_title": { + "maxLength": 500, + "nullable": true, + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, "ChartRestApi.get_list.SqlaTable": { "properties": { "default_endpoint": { @@ -2472,10 +2694,6 @@ "maxLength": 64, "type": "string" }, - "id": { - "format": "int32", - "type": "integer" - }, "last_name": { "maxLength": 64, "type": "string" @@ -2493,14 +2711,23 @@ "maxLength": 64, "type": "string" }, + "id": { + "format": "int32", + "type": "integer" + }, "last_name": { "maxLength": 64, "type": "string" + }, + "username": { + "maxLength": 64, + "type": "string" } }, "required": [ "first_name", - "last_name" + "last_name", + "username" ], "type": "object" }, @@ -2538,16 +2765,11 @@ "last_name": { "maxLength": 64, "type": "string" - }, - "username": { - "maxLength": 64, - "type": "string" } }, "required": [ "first_name", - "last_name", - "username" + "last_name" ], "type": "object" }, @@ -2590,8 +2812,11 @@ "datasource_type": { "description": "The type of dataset/datasource identified on `datasource_id`.", "enum": [ - "druid", + "sl_table", "table", + "dataset", + "query", + "saved_query", "view" ], "type": "string" @@ -2693,8 +2918,11 @@ "datasource_type": { "description": "The type of dataset/datasource identified on `datasource_id`.", "enum": [ - "druid", + "sl_table", "table", + "dataset", + "query", + "saved_query", "view" ], "nullable": true, @@ -2992,8 +3220,7 @@ }, "owners": { "items": { - "format": "int32", - "type": "integer" + "type": "object" }, "type": "array" }, @@ -3087,6 +3314,10 @@ "format": "int32", "type": "integer" }, + "is_managed_externally": { + "nullable": true, + "type": "boolean" + }, "json_metadata": { "description": "This JSON object is generated dynamically when clicking the save or overwrite button in the dashboard view. It is exposed here for reference and for power users who may want to alter specific parameters.", "type": "string" @@ -3124,15 +3355,24 @@ }, "DashboardPermalinkPostSchema": { "properties": { - "filterState": { - "description": "Native filter state", - "type": "object" + "activeTabs": { + "description": "Current active dashboard tabs", + "items": { + "type": "string" + }, + "nullable": true, + "type": "array" }, - "hash": { - "description": "Optional anchor link", + "anchor": { + "description": "Optional anchor link added to url hash", "nullable": true, "type": "string" }, + "dataMask": { + "description": "Data mask used for native filter state", + "nullable": true, + "type": "object" + }, "urlParams": { "description": "URL Parameters", "items": { @@ -3143,9 +3383,6 @@ "type": "array" } }, - "required": [ - "filterState" - ], "type": "object" }, "DashboardRestApi.get": { @@ -3183,7 +3420,10 @@ "readOnly": true }, "created_by": { - "$ref": "#/components/schemas/DashboardRestApi.get_list.User1" + "$ref": "#/components/schemas/DashboardRestApi.get_list.User2" + }, + "created_on_delta_humanized": { + "readOnly": true }, "css": { "nullable": true, @@ -3198,18 +3438,15 @@ "format": "int32", "type": "integer" }, + "is_managed_externally": { + "type": "boolean" + }, "json_metadata": { "nullable": true, "type": "string" }, "owners": { - "$ref": "#/components/schemas/DashboardRestApi.get_list.User2" - }, - "advanced_data_type": { - "maxLength": 255, - "minLength": 1, - "nullable": true, - "type": "string" + "$ref": "#/components/schemas/DashboardRestApi.get_list.User1" }, "position_json": { "nullable": true, @@ -3283,6 +3520,10 @@ }, "DashboardRestApi.get_list.User1": { "properties": { + "email": { + "maxLength": 64, + "type": "string" + }, "first_name": { "maxLength": 64, "type": "string" @@ -3294,20 +3535,22 @@ "last_name": { "maxLength": 64, "type": "string" + }, + "username": { + "maxLength": 64, + "type": "string" } }, "required": [ + "email", "first_name", - "last_name" + "last_name", + "username" ], "type": "object" }, "DashboardRestApi.get_list.User2": { "properties": { - "email": { - "maxLength": 64, - "type": "string" - }, "first_name": { "maxLength": 64, "type": "string" @@ -3319,17 +3562,11 @@ "last_name": { "maxLength": 64, "type": "string" - }, - "username": { - "maxLength": 64, - "type": "string" } }, "required": [ - "email", "first_name", - "last_name", - "username" + "last_name" ], "type": "object" }, @@ -3478,9 +3715,6 @@ }, "Database": { "properties": { - "allow_multi_schema_metadata_fetch": { - "type": "boolean" - }, "allows_cost_estimate": { "type": "boolean" }, @@ -3510,6 +3744,14 @@ }, "type": "object" }, + "Database1": { + "properties": { + "database_name": { + "type": "string" + } + }, + "type": "object" + }, "DatabaseFunctionNamesResponse": { "properties": { "function_names": { @@ -3617,10 +3859,6 @@ "nullable": true, "type": "boolean" }, - "allow_multi_schema_metadata_fetch": { - "nullable": true, - "type": "boolean" - }, "allow_run_async": { "nullable": true, "type": "boolean" @@ -3642,9 +3880,11 @@ "maxLength": 250, "type": "string" }, - "encrypted_extra": { - "nullable": true, - "type": "string" + "driver": { + "readOnly": true + }, + "engine_information": { + "readOnly": true }, "expose_in_sqllab": { "nullable": true, @@ -3667,6 +3907,12 @@ "nullable": true, "type": "boolean" }, + "is_managed_externally": { + "type": "boolean" + }, + "masked_encrypted_extra": { + "readOnly": true + }, "parameters": { "readOnly": true }, @@ -3680,6 +3926,11 @@ "sqlalchemy_uri": { "maxLength": 1024, "type": "string" + }, + "uuid": { + "format": "uuid", + "nullable": true, + "type": "string" } }, "required": [ @@ -3706,10 +3957,6 @@ "nullable": true, "type": "boolean" }, - "allow_multi_schema_metadata_fetch": { - "nullable": true, - "type": "boolean" - }, "allow_run_async": { "nullable": true, "type": "boolean" @@ -3744,6 +3991,9 @@ "disable_data_preview": { "readOnly": true }, + "engine_information": { + "readOnly": true + }, "explore_database_id": { "readOnly": true }, @@ -3763,6 +4013,11 @@ "id": { "format": "int32", "type": "integer" + }, + "uuid": { + "format": "uuid", + "nullable": true, + "type": "string" } }, "required": [ @@ -3805,12 +4060,8 @@ "description": "Allow to upload CSV file data into this databaseIf selected, please set the schemas allowed for csv upload in Extra.", "type": "boolean" }, - "allow_multi_schema_metadata_fetch": { - "description": "Allow SQL Lab to fetch a list of all tables and all views across all database schemas. For large data warehouse with thousands of tables, this can be expensive and put strain on the system.", - "type": "boolean" - }, "allow_run_async": { - "description": "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.", + "description": "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.", "type": "boolean" }, "cache_timeout": { @@ -3829,8 +4080,8 @@ "minLength": 1, "type": "string" }, - "encrypted_extra": { - "description": "<p>JSON string containing additional connection configuration.<br>This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.</p>", + "driver": { + "description": "SQLAlchemy driver to use", "nullable": true, "type": "string" }, @@ -3866,6 +4117,11 @@ "nullable": true, "type": "boolean" }, + "masked_encrypted_extra": { + "description": "<p>JSON string containing additional connection configuration.<br>This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.</p>", + "nullable": true, + "type": "string" + }, "parameters": { "additionalProperties": {}, "description": "DB-specific parameters for configuration", @@ -3881,6 +4137,17 @@ "maxLength": 1024, "minLength": 1, "type": "string" + }, + "ssh_tunnel": { + "allOf": [ + { + "$ref": "#/components/schemas/DatabaseSSHTunnel" + } + ], + "nullable": true + }, + "uuid": { + "type": "string" } }, "required": [ @@ -3906,12 +4173,8 @@ "description": "Allow to upload CSV file data into this databaseIf selected, please set the schemas allowed for csv upload in Extra.", "type": "boolean" }, - "allow_multi_schema_metadata_fetch": { - "description": "Allow SQL Lab to fetch a list of all tables and all views across all database schemas. For large data warehouse with thousands of tables, this can be expensive and put strain on the system.", - "type": "boolean" - }, "allow_run_async": { - "description": "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.", + "description": "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.", "type": "boolean" }, "cache_timeout": { @@ -3931,8 +4194,8 @@ "nullable": true, "type": "string" }, - "encrypted_extra": { - "description": "<p>JSON string containing additional connection configuration.<br>This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.</p>", + "driver": { + "description": "SQLAlchemy driver to use", "nullable": true, "type": "string" }, @@ -3968,6 +4231,11 @@ "nullable": true, "type": "boolean" }, + "masked_encrypted_extra": { + "description": "<p>JSON string containing additional connection configuration.<br>This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.</p>", + "nullable": true, + "type": "string" + }, "parameters": { "additionalProperties": {}, "description": "DB-specific parameters for configuration", @@ -3983,6 +4251,61 @@ "maxLength": 1024, "minLength": 0, "type": "string" + }, + "ssh_tunnel": { + "allOf": [ + { + "$ref": "#/components/schemas/DatabaseSSHTunnel" + } + ], + "nullable": true + } + }, + "type": "object" + }, + "DatabaseSSHTunnel": { + "properties": { + "id": { + "description": "SSH Tunnel ID (for updates)", + "format": "int32", + "nullable": true, + "type": "integer" + }, + "password": { + "type": "string" + }, + "private_key": { + "type": "string" + }, + "private_key_password": { + "type": "string" + }, + "server_address": { + "type": "string" + }, + "server_port": { + "format": "int32", + "type": "integer" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "DatabaseTablesResponse": { + "properties": { + "extra": { + "description": "Extra data used to specify column metadata", + "type": "object" + }, + "type": { + "description": "table or view", + "type": "string" + }, + "value": { + "description": "The table or view name", + "type": "string" } }, "type": "object" @@ -4000,8 +4323,8 @@ "nullable": true, "type": "string" }, - "encrypted_extra": { - "description": "<p>JSON string containing additional connection configuration.<br>This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.</p>", + "driver": { + "description": "SQLAlchemy driver to use", "nullable": true, "type": "string" }, @@ -4018,6 +4341,11 @@ "description": "If Presto, all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them.<br/>If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.", "type": "boolean" }, + "masked_encrypted_extra": { + "description": "<p>JSON string containing additional connection configuration.<br>This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.</p>", + "nullable": true, + "type": "string" + }, "parameters": { "additionalProperties": {}, "description": "DB-specific parameters for configuration", @@ -4033,12 +4361,27 @@ "maxLength": 1024, "minLength": 1, "type": "string" + }, + "ssh_tunnel": { + "allOf": [ + { + "$ref": "#/components/schemas/DatabaseSSHTunnel" + } + ], + "nullable": true } }, "type": "object" }, "DatabaseValidateParametersSchema": { "properties": { + "catalog": { + "additionalProperties": { + "nullable": true + }, + "description": "Gsheets specific column for managing label to sheet urls", + "type": "object" + }, "configuration_method": { "description": "Configuration_method is used on the frontend to inform the backend whether to explode parameters or to provide only a sqlalchemy_uri." }, @@ -4049,8 +4392,8 @@ "nullable": true, "type": "string" }, - "encrypted_extra": { - "description": "<p>JSON string containing additional connection configuration.<br>This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.</p>", + "driver": { + "description": "SQLAlchemy driver to use", "nullable": true, "type": "string" }, @@ -4062,10 +4405,21 @@ "description": "<p>JSON string containing extra configuration elements.<br>1. The <code>engine_params</code> object gets unpacked into the <a href=\"https://docs.sqlalchemy.org/en/latest/core/engines.html#sqlalchemy.create_engine\">sqlalchemy.create_engine</a> call, while the <code>metadata_params</code> gets unpacked into the <a href=\"https://docs.sqlalchemy.org/en/rel_1_0/core/metadata.html#sqlalchemy.schema.MetaData\">sqlalchemy.MetaData</a> call.<br>2. The <code>metadata_cache_timeout</code> is a cache timeout setting in seconds for metadata fetch of this database. Specify it as <strong>\"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}</strong>. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.<br>3. The <code>schemas_allowed_for_file_upload</code> is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as <strong>\"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]</strong>. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty<br>4. The <code>version</code> field is a string specifying the this db's version. This should be used with Presto DBs so that the syntax is correct<br>5. The <code>allows_virtual_table_explore</code> field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.<br>6. The <code>disable_data_preview</code> field is a boolean specifying whether or not data preview queries will be run when fetching table metadata in SQL Lab.</p>", "type": "string" }, + "id": { + "description": "Database ID (for updates)", + "format": "int32", + "nullable": true, + "type": "integer" + }, "impersonate_user": { "description": "If Presto, all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them.<br/>If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.", "type": "boolean" }, + "masked_encrypted_extra": { + "description": "<p>JSON string containing additional connection configuration.<br>This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.</p>", + "nullable": true, + "type": "string" + }, "parameters": { "additionalProperties": { "nullable": true @@ -4085,77 +4439,251 @@ ], "type": "object" }, - "DatasetColumnsPut": { + "Dataset": { "properties": { - "column_name": { - "maxLength": 255, - "minLength": 1, + "cache_timeout": { + "description": "Duration (in seconds) of the caching timeout for this dataset.", + "format": "int32", + "type": "integer" + }, + "column_formats": { + "description": "Column formats.", + "type": "object" + }, + "columns": { + "description": "Columns metadata.", + "items": { + "type": "object" + }, + "type": "array" + }, + "database": { + "description": "Database associated with the dataset.", + "type": "object" + }, + "datasource_name": { + "description": "Dataset name.", + "type": "string" + }, + "default_endpoint": { + "description": "Default endpoint for the dataset.", "type": "string" }, "description": { - "nullable": true, + "description": "Dataset description.", "type": "string" }, - "expression": { - "nullable": true, + "edit_url": { + "description": "The URL for editing the dataset.", "type": "string" }, "extra": { - "nullable": true, + "description": "JSON string containing extra configuration elements.", + "type": "object" + }, + "fetch_values_predicate": { + "description": "Predicate used when fetching values from the dataset.", "type": "string" }, - "filterable": { + "filter_select": { + "description": "SELECT filter applied to the dataset.", "type": "boolean" }, - "groupby": { + "filter_select_enabled": { + "description": "If the SELECT filter is enabled.", "type": "boolean" }, + "granularity_sqla": { + "description": "Name of temporal column used for time filtering for SQL datasources. This field is deprecated, use `granularity` instead.", + "items": { + "items": { + "type": "object" + }, + "type": "array" + }, + "type": "array" + }, + "health_check_message": { + "description": "Health check message.", + "type": "string" + }, "id": { + "description": "Dataset ID.", "format": "int32", "type": "integer" }, - "is_active": { + "is_sqllab_view": { + "description": "If the dataset is a SQL Lab view.", "type": "boolean" }, - "is_dttm": { - "type": "boolean" + "main_dttm_col": { + "description": "The main temporal column.", + "type": "string" }, - "python_date_format": { - "maxLength": 255, - "minLength": 1, - "nullable": true, + "metrics": { + "description": "Dataset metrics.", + "items": { + "type": "object" + }, + "type": "array" + }, + "name": { + "description": "Dataset name.", "type": "string" }, - "type": { - "nullable": true, + "offset": { + "description": "Dataset offset.", + "format": "int32", + "type": "integer" + }, + "order_by_choices": { + "description": "List of order by columns.", + "items": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "owners": { + "description": "List of owners identifiers", + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + }, + "params": { + "description": "Extra params for the dataset.", + "type": "object" + }, + "perm": { + "description": "Permission expression.", "type": "string" }, - "uuid": { - "format": "uuid", - "nullable": true, + "schema": { + "description": "Dataset schema.", "type": "string" }, - "verbose_name": { - "nullable": true, + "select_star": { + "description": "Select all clause.", "type": "string" - } - }, - "required": [ - "column_name" - ], - "type": "object" - }, - "DatasetColumnsRestApi.get": { - "properties": { - "id": { - "format": "int32", - "type": "integer" - } - }, - "type": "object" - }, - "DatasetColumnsRestApi.get_list": { - "properties": { + }, + "sql": { + "description": "A SQL statement that defines the dataset.", + "type": "string" + }, + "table_name": { + "description": "The name of the table associated with the dataset.", + "type": "string" + }, + "template_params": { + "description": "Table template params.", + "type": "object" + }, + "time_grain_sqla": { + "description": "List of temporal granularities supported by the dataset.", + "items": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "type": { + "description": "Dataset type.", + "type": "string" + }, + "uid": { + "description": "Dataset unique identifier.", + "type": "string" + }, + "verbose_map": { + "description": "Mapping from raw name to verbose name.", + "type": "object" + } + }, + "type": "object" + }, + "DatasetColumnsPut": { + "properties": { + "advanced_data_type": { + "maxLength": 255, + "minLength": 1, + "nullable": true, + "type": "string" + }, + "column_name": { + "maxLength": 255, + "minLength": 1, + "type": "string" + }, + "description": { + "nullable": true, + "type": "string" + }, + "expression": { + "nullable": true, + "type": "string" + }, + "extra": { + "nullable": true, + "type": "string" + }, + "filterable": { + "type": "boolean" + }, + "groupby": { + "type": "boolean" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "is_dttm": { + "type": "boolean" + }, + "python_date_format": { + "maxLength": 255, + "minLength": 1, + "nullable": true, + "type": "string" + }, + "type": { + "nullable": true, + "type": "string" + }, + "uuid": { + "format": "uuid", + "nullable": true, + "type": "string" + }, + "verbose_name": { + "nullable": true, + "type": "string" + } + }, + "required": [ + "column_name" + ], + "type": "object" + }, + "DatasetColumnsRestApi.get": { + "properties": { + "id": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "DatasetColumnsRestApi.get_list": { + "properties": { "id": { "format": "int32", "type": "integer" @@ -4181,6 +4709,24 @@ }, "type": "object" }, + "DatasetDuplicateSchema": { + "properties": { + "base_model_id": { + "format": "int32", + "type": "integer" + }, + "table_name": { + "maxLength": 250, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "base_model_id", + "table_name" + ], + "type": "object" + }, "DatasetMetricRestApi.get": { "properties": { "id": { @@ -4251,12 +4797,6 @@ "nullable": true, "type": "string" }, - "advanced_data_type": { - "maxLength": 255, - "minLength": 1, - "nullable": true, - "type": "string" - }, "uuid": { "format": "uuid", "nullable": true, @@ -4362,9 +4902,31 @@ "nullable": true, "type": "integer" }, + "changed_by": { + "$ref": "#/components/schemas/DatasetRestApi.get.User" + }, + "changed_on": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "changed_on_humanized": { + "readOnly": true + }, "columns": { "$ref": "#/components/schemas/DatasetRestApi.get.TableColumn" }, + "created_by": { + "$ref": "#/components/schemas/DatasetRestApi.get.User2" + }, + "created_on": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "created_on_humanized": { + "readOnly": true + }, "database": { "$ref": "#/components/schemas/DatasetRestApi.get.Database" }, @@ -4395,6 +4957,9 @@ "format": "int32", "type": "integer" }, + "is_managed_externally": { + "type": "boolean" + }, "is_sqllab_view": { "nullable": true, "type": "boolean" @@ -4416,13 +4981,16 @@ "type": "integer" }, "owners": { - "$ref": "#/components/schemas/DatasetRestApi.get.User" + "$ref": "#/components/schemas/DatasetRestApi.get.User1" }, "schema": { "maxLength": 255, "nullable": true, "type": "string" }, + "select_star": { + "readOnly": true + }, "sql": { "nullable": true, "type": "string" @@ -4507,11 +5075,6 @@ "nullable": true, "type": "string" }, - "uuid": { - "format": "uuid", - "nullable": true, - "type": "string" - }, "verbose_name": { "maxLength": 1024, "nullable": true, @@ -4530,6 +5093,11 @@ }, "DatasetRestApi.get.TableColumn": { "properties": { + "advanced_data_type": { + "maxLength": 255, + "nullable": true, + "type": "string" + }, "changed_on": { "format": "date-time", "nullable": true, @@ -4605,6 +5173,23 @@ "type": "object" }, "DatasetRestApi.get.User": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, + "DatasetRestApi.get.User1": { "properties": { "first_name": { "maxLength": 64, @@ -4630,6 +5215,23 @@ ], "type": "object" }, + "DatasetRestApi.get.User2": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, "DatasetRestApi.get_list": { "properties": { "changed_by": { @@ -4783,6 +5385,10 @@ "minLength": 0, "type": "string" }, + "sql": { + "nullable": true, + "type": "string" + }, "table_name": { "maxLength": 250, "minLength": 1, @@ -4904,8 +5510,11 @@ "datasource_type": { "description": "The type of dataset/datasource identified on `datasource_id`.", "enum": [ - "druid", + "sl_table", "table", + "dataset", + "query", + "saved_query", "view" ], "type": "string" @@ -4945,71 +5554,229 @@ }, "type": "object" }, - "ExplorePermalinkPostSchema": { + "EmbeddedDashboardConfig": { "properties": { - "formData": { - "description": "Chart form data", - "type": "object" - }, - "urlParams": { - "description": "URL Parameters", + "allowed_domains": { "items": { - "description": "URL Parameter key-value pair", - "nullable": true + "type": "string" }, - "nullable": true, "type": "array" } }, "required": [ - "formData" + "allowed_domains" ], "type": "object" }, - "FilterSetRestApi.get": { + "EmbeddedDashboardResponseSchema": { "properties": { - "dashboard_id": { - "format": "int32", - "nullable": true, - "type": "integer" - }, - "description": { - "nullable": true, - "type": "string" + "allowed_domains": { + "items": { + "type": "string" + }, + "type": "array" }, - "id": { - "format": "int32", - "type": "integer" + "changed_by": { + "$ref": "#/components/schemas/User" }, - "name": { - "maxLength": 500, + "changed_on": { + "format": "date-time", "type": "string" }, - "owner_id": { - "format": "int32", - "type": "integer" - }, - "owner_type": { - "maxLength": 255, + "dashboard_id": { "type": "string" }, - "params": { - "readOnly": true + "uuid": { + "type": "string" } }, - "required": [ - "name", - "owner_id", - "owner_type" - ], "type": "object" }, - "FilterSetRestApi.get_list": { + "EmbeddedDashboardRestApi.get": { "properties": { - "changed_by_fk": { - "format": "int32", - "nullable": true, - "type": "integer" + "uuid": { + "format": "uuid", + "type": "string" + } + }, + "type": "object" + }, + "EmbeddedDashboardRestApi.get_list": { + "properties": { + "uuid": { + "format": "uuid", + "type": "string" + } + }, + "type": "object" + }, + "EmbeddedDashboardRestApi.post": { + "properties": { + "uuid": { + "format": "uuid", + "type": "string" + } + }, + "type": "object" + }, + "EmbeddedDashboardRestApi.put": { + "properties": { + "uuid": { + "format": "uuid", + "type": "string" + } + }, + "type": "object" + }, + "ExecutePayloadSchema": { + "properties": { + "client_id": { + "nullable": true, + "type": "string" + }, + "ctas_method": { + "nullable": true, + "type": "string" + }, + "database_id": { + "format": "int32", + "type": "integer" + }, + "expand_data": { + "nullable": true, + "type": "boolean" + }, + "json": { + "nullable": true, + "type": "boolean" + }, + "queryLimit": { + "format": "int32", + "nullable": true, + "type": "integer" + }, + "runAsync": { + "nullable": true, + "type": "boolean" + }, + "schema": { + "nullable": true, + "type": "string" + }, + "select_as_cta": { + "nullable": true, + "type": "boolean" + }, + "sql": { + "type": "string" + }, + "sql_editor_id": { + "nullable": true, + "type": "string" + }, + "tab": { + "nullable": true, + "type": "string" + }, + "templateParams": { + "nullable": true, + "type": "string" + }, + "tmp_table_name": { + "nullable": true, + "type": "string" + } + }, + "required": [ + "database_id", + "sql" + ], + "type": "object" + }, + "ExploreContextSchema": { + "properties": { + "dataset": { + "$ref": "#/components/schemas/Dataset" + }, + "form_data": { + "description": "Form data from the Explore controls used to form the chart's data query.", + "type": "object" + }, + "message": { + "description": "Any message related to the processed request.", + "type": "string" + }, + "slice": { + "$ref": "#/components/schemas/Slice" + } + }, + "type": "object" + }, + "ExplorePermalinkPostSchema": { + "properties": { + "formData": { + "description": "Chart form data", + "type": "object" + }, + "urlParams": { + "description": "URL Parameters", + "items": { + "description": "URL Parameter key-value pair", + "nullable": true + }, + "nullable": true, + "type": "array" + } + }, + "required": [ + "formData" + ], + "type": "object" + }, + "FilterSetRestApi.get": { + "properties": { + "dashboard_id": { + "format": "int32", + "nullable": true, + "type": "integer" + }, + "description": { + "nullable": true, + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "maxLength": 500, + "type": "string" + }, + "owner_id": { + "format": "int32", + "type": "integer" + }, + "owner_type": { + "maxLength": 255, + "type": "string" + }, + "params": { + "readOnly": true + } + }, + "required": [ + "name", + "owner_id", + "owner_type" + ], + "type": "object" + }, + "FilterSetRestApi.get_list": { + "properties": { + "changed_by_fk": { + "format": "int32", + "nullable": true, + "type": "integer" }, "changed_on": { "format": "date-time", @@ -5128,18 +5895,31 @@ "format": "int32", "type": "integer" }, - "dataset_id": { - "description": "The dataset ID", + "datasource_id": { + "description": "The datasource ID", "format": "int32", "type": "integer" }, + "datasource_type": { + "description": "The datasource type", + "enum": [ + "sl_table", + "table", + "dataset", + "query", + "saved_query", + "view" + ], + "type": "string" + }, "form_data": { "description": "Any type of JSON supported text.", "type": "string" } }, "required": [ - "dataset_id", + "datasource_id", + "datasource_type", "form_data" ], "type": "object" @@ -5151,18 +5931,31 @@ "format": "int32", "type": "integer" }, - "dataset_id": { - "description": "The dataset ID", + "datasource_id": { + "description": "The datasource ID", "format": "int32", "type": "integer" }, + "datasource_type": { + "description": "The datasource type", + "enum": [ + "sl_table", + "table", + "dataset", + "query", + "saved_query", + "view" + ], + "type": "string" + }, "form_data": { "description": "Any type of JSON supported text.", "type": "string" } }, "required": [ - "dataset_id", + "datasource_id", + "datasource_type", "form_data" ], "type": "object" @@ -5352,6 +6145,45 @@ }, "type": "object" }, + "QueryExecutionResponseSchema": { + "properties": { + "columns": { + "items": { + "type": "object" + }, + "type": "array" + }, + "data": { + "items": { + "type": "object" + }, + "type": "array" + }, + "expanded_columns": { + "items": { + "type": "object" + }, + "type": "array" + }, + "query": { + "$ref": "#/components/schemas/QueryResult" + }, + "query_id": { + "format": "int32", + "type": "integer" + }, + "selected_columns": { + "items": { + "type": "object" + }, + "type": "array" + }, + "status": { + "type": "string" + } + }, + "type": "object" + }, "QueryRestApi.get": { "properties": { "changed_on": { @@ -5461,8 +6293,7 @@ "type": "string" }, "tracking_url": { - "nullable": true, - "type": "string" + "readOnly": true } }, "required": [ @@ -5484,18 +6315,16 @@ "properties": { "changed_on": { "format": "date-time", - "nullable": true, "type": "string" }, "database": { - "$ref": "#/components/schemas/QueryRestApi.get_list.Database" + "$ref": "#/components/schemas/Database1" }, "end_time": { - "nullable": true, + "format": "float", "type": "number" }, "executed_sql": { - "nullable": true, "type": "string" }, "id": { @@ -5504,105 +6333,228 @@ }, "rows": { "format": "int32", - "nullable": true, "type": "integer" }, "schema": { - "maxLength": 256, - "nullable": true, "type": "string" }, "sql": { - "nullable": true, "type": "string" }, "sql_tables": { "readOnly": true }, "start_time": { - "nullable": true, + "format": "float", "type": "number" }, "status": { - "maxLength": 16, - "nullable": true, "type": "string" }, "tab_name": { - "maxLength": 256, - "nullable": true, "type": "string" }, "tmp_table_name": { - "maxLength": 256, - "nullable": true, "type": "string" }, "tracking_url": { - "nullable": true, "type": "string" }, "user": { - "$ref": "#/components/schemas/QueryRestApi.get_list.User" + "$ref": "#/components/schemas/User" } }, - "required": [ - "database" - ], "type": "object" }, - "QueryRestApi.get_list.Database": { + "QueryRestApi.post": { "properties": { - "database_name": { - "maxLength": 250, - "type": "string" + "id": { + "format": "int32", + "type": "integer" } }, - "required": [ - "database_name" - ], "type": "object" }, - "QueryRestApi.get_list.User": { + "QueryRestApi.put": { "properties": { - "first_name": { - "maxLength": 64, + "id": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "QueryResult": { + "properties": { + "changedOn": { + "format": "date-time", + "type": "string" + }, + "changed_on": { + "type": "string" + }, + "ctas": { + "type": "boolean" + }, + "db": { + "type": "string" + }, + "dbId": { + "format": "int32", + "type": "integer" + }, + "endDttm": { + "format": "float", + "type": "number" + }, + "errorMessage": { + "nullable": true, + "type": "string" + }, + "executedSql": { "type": "string" }, + "extra": { + "type": "object" + }, "id": { + "type": "string" + }, + "limit": { "format": "int32", "type": "integer" }, - "last_name": { - "maxLength": 64, + "limitingFactor": { "type": "string" }, - "username": { - "maxLength": 64, + "progress": { + "format": "int32", + "type": "integer" + }, + "queryId": { + "format": "int32", + "type": "integer" + }, + "resultsKey": { + "type": "string" + }, + "rows": { + "format": "int32", + "type": "integer" + }, + "schema": { + "type": "string" + }, + "serverId": { + "format": "int32", + "type": "integer" + }, + "sql": { + "type": "string" + }, + "sqlEditorId": { + "type": "string" + }, + "startDttm": { + "format": "float", + "type": "number" + }, + "state": { + "type": "string" + }, + "tab": { + "type": "string" + }, + "tempSchema": { + "nullable": true, + "type": "string" + }, + "tempTable": { + "nullable": true, + "type": "string" + }, + "trackingUrl": { + "nullable": true, + "type": "string" + }, + "user": { "type": "string" + }, + "userId": { + "format": "int32", + "type": "integer" } }, - "required": [ - "first_name", - "last_name", - "username" - ], "type": "object" }, - "QueryRestApi.post": { + "RecentActivity": { "properties": { - "id": { - "format": "int32", - "type": "integer" + "action": { + "description": "Action taken describing type of activity", + "type": "string" + }, + "item_title": { + "description": "Title of item", + "type": "string" + }, + "item_type": { + "description": "Type of item, e.g. slice or dashboard", + "type": "string" + }, + "item_url": { + "description": "URL to item", + "type": "string" + }, + "time": { + "description": "Time of activity, in epoch milliseconds", + "format": "float", + "type": "number" + }, + "time_delta_humanized": { + "description": "Human-readable description of how long ago activity took place", + "type": "string" } }, "type": "object" }, - "QueryRestApi.put": { + "RecentActivityResponseSchema": { "properties": { - "id": { - "format": "int32", - "type": "integer" + "result": { + "description": "A list of recent activity objects", + "items": { + "$ref": "#/components/schemas/RecentActivity" + }, + "type": "array" + } + }, + "type": "object" + }, + "RecentActivitySchema": { + "properties": { + "action": { + "description": "Action taken describing type of activity", + "type": "string" + }, + "item_title": { + "description": "Title of item", + "type": "string" + }, + "item_type": { + "description": "Type of item, e.g. slice or dashboard", + "type": "string" + }, + "item_url": { + "description": "URL to item", + "type": "string" + }, + "time": { + "description": "Time of activity, in epoch milliseconds", + "format": "float", + "type": "number" + }, + "time_delta_humanized": { + "description": "Human-readable description of how long ago activity took place", + "type": "string" } }, "type": "object" @@ -5625,6 +6577,10 @@ }, "RelatedResultResponse": { "properties": { + "extra": { + "description": "The extra metadata for related item", + "type": "object" + }, "text": { "description": "The related item string representation", "type": "string" @@ -5812,6 +6768,9 @@ "nullable": true, "type": "string" }, + "extra": { + "readOnly": true + }, "force_screenshot": { "nullable": true, "type": "boolean" @@ -6006,8 +6965,13 @@ "changed_on_delta_humanized": { "readOnly": true }, + "chart_id": { + "format": "int32", + "nullable": true, + "type": "integer" + }, "created_by": { - "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User1" + "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User2" }, "created_on": { "format": "date-time", @@ -6026,10 +6990,18 @@ "crontab_humanized": { "readOnly": true }, + "dashboard_id": { + "format": "int32", + "nullable": true, + "type": "integer" + }, "description": { "nullable": true, "type": "string" }, + "extra": { + "readOnly": true + }, "id": { "format": "int32", "type": "integer" @@ -6049,7 +7021,7 @@ "type": "string" }, "owners": { - "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User2" + "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User1" }, "recipients": { "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.ReportRecipients" @@ -6110,6 +7082,10 @@ "maxLength": 64, "type": "string" }, + "id": { + "format": "int32", + "type": "integer" + }, "last_name": { "maxLength": 64, "type": "string" @@ -6127,10 +7103,6 @@ "maxLength": 64, "type": "string" }, - "id": { - "format": "int32", - "type": "integer" - }, "last_name": { "maxLength": 64, "type": "string" @@ -6790,6 +7762,7 @@ "Pacific/Guam", "Pacific/Honolulu", "Pacific/Johnston", + "Pacific/Kanton", "Pacific/Kiritimati", "Pacific/Kosrae", "Pacific/Kwajalein", @@ -6917,6 +7890,9 @@ "nullable": true, "type": "string" }, + "extra": { + "type": "object" + }, "force_screenshot": { "type": "boolean" }, @@ -7514,6 +8490,7 @@ "Pacific/Guam", "Pacific/Honolulu", "Pacific/Johnston", + "Pacific/Kanton", "Pacific/Kiritimati", "Pacific/Kosrae", "Pacific/Kwajalein", @@ -7640,6 +8617,9 @@ }, "SavedQueryRestApi.get": { "properties": { + "changed_on_delta_humanized": { + "readOnly": true + }, "created_by": { "$ref": "#/components/schemas/SavedQueryRestApi.get.User" }, @@ -7670,6 +8650,10 @@ }, "sql_tables": { "readOnly": true + }, + "template_parameters": { + "nullable": true, + "type": "string" } }, "type": "object" @@ -7832,6 +8816,10 @@ "sql": { "nullable": true, "type": "string" + }, + "template_parameters": { + "nullable": true, + "type": "string" } }, "type": "object" @@ -7860,6 +8848,10 @@ "sql": { "nullable": true, "type": "string" + }, + "template_parameters": { + "nullable": true, + "type": "string" } }, "type": "object" @@ -7885,6 +8877,107 @@ }, "type": "object" }, + "Slice": { + "properties": { + "cache_timeout": { + "description": "Duration (in seconds) of the caching timeout for this chart.", + "format": "int32", + "type": "integer" + }, + "certification_details": { + "description": "Details of the certification.", + "type": "string" + }, + "certified_by": { + "description": "Person or group that has certified this dashboard.", + "type": "string" + }, + "changed_on": { + "description": "Timestamp of the last modification.", + "type": "string" + }, + "changed_on_humanized": { + "description": "Timestamp of the last modification in human readable form.", + "type": "string" + }, + "datasource": { + "description": "Datasource identifier.", + "type": "string" + }, + "description": { + "description": "Slice description.", + "type": "string" + }, + "description_markeddown": { + "description": "Sanitized HTML version of the chart description.", + "type": "string" + }, + "edit_url": { + "description": "The URL for editing the slice.", + "type": "string" + }, + "form_data": { + "description": "Form data associated with the slice.", + "type": "object" + }, + "is_managed_externally": { + "description": "If the chart is managed outside externally.", + "type": "boolean" + }, + "modified": { + "description": "Last modification in human readable form.", + "type": "string" + }, + "owners": { + "description": "Owners identifiers.", + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + }, + "query_context": { + "description": "The context associated with the query.", + "type": "object" + }, + "slice_id": { + "description": "The slice ID.", + "format": "int32", + "type": "integer" + }, + "slice_name": { + "description": "The slice name.", + "type": "string" + }, + "slice_url": { + "description": "The slice URL.", + "type": "string" + } + }, + "type": "object" + }, + "StopQuerySchema": { + "properties": { + "client_id": { + "type": "string" + } + }, + "type": "object" + }, + "TableExtraMetadataResponseSchema": { + "properties": { + "clustering": { + "type": "object" + }, + "metadata": { + "type": "object" + }, + "partitions": { + "type": "object" + } + }, + "type": "object" + }, "TableMetadataColumnsResponse": { "properties": { "duplicates_constraint": { @@ -8110,6 +9203,46 @@ }, "type": "object" }, + "ValidateSQLRequest": { + "properties": { + "schema": { + "nullable": true, + "type": "string" + }, + "sql": { + "description": "SQL statement to validate", + "type": "string" + }, + "template_params": { + "nullable": true, + "type": "object" + } + }, + "required": [ + "sql" + ], + "type": "object" + }, + "ValidateSQLResponse": { + "properties": { + "end_column": { + "format": "int32", + "type": "integer" + }, + "line_number": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + }, + "start_column": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, "ValidatorConfigJSON": { "properties": { "op": { @@ -8131,6 +9264,26 @@ }, "type": "object" }, + "advanced_data_type_convert_schema": { + "properties": { + "type": { + "default": "port", + "type": "string" + }, + "values": { + "items": { + "default": "http" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "type", + "values" + ], + "type": "object" + }, "database_schemas_query_schema": { "properties": { "force": { @@ -8139,6 +9292,20 @@ }, "type": "object" }, + "database_tables_query_schema": { + "properties": { + "force": { + "type": "boolean" + }, + "schema_name": { + "type": "string" + } + }, + "required": [ + "schema_name" + ], + "type": "object" + }, "get_delete_ids_schema": { "items": { "type": "integer" @@ -8305,6 +9472,26 @@ }, "type": "object" }, + "get_recent_activity_schema": { + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "distinct": { + "type": "boolean" + }, + "page": { + "type": "number" + }, + "page_size": { + "type": "number" + } + }, + "type": "object" + }, "get_related_schema": { "properties": { "filter": { @@ -8325,6 +9512,17 @@ }, "type": "object" }, + "queries_get_updated_since_schema": { + "properties": { + "last_updated_ms": { + "type": "number" + } + }, + "required": [ + "last_updated_ms" + ], + "type": "object" + }, "screenshot_query_schema": { "properties": { "force": { @@ -8345,6 +9543,17 @@ }, "type": "object" }, + "sql_lab_get_results_schema": { + "properties": { + "key": { + "type": "string" + } + }, + "required": [ + "key" + ], + "type": "object" + }, "thumbnail_query_schema": { "properties": { "force": { @@ -8374,6 +9583,98 @@ }, "openapi": "3.0.2", "paths": { + "/api/v1/advanced_data_type/convert": { + "get": { + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/advanced_data_type_convert_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdvancedDataTypeSchema" + } + } + }, + "description": "AdvancedDataTypeResponse object has been returned." + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Returns a AdvancedDataTypeResponse object populated with the passed in args.", + "tags": [ + "Advanced Data Type" + ] + } + }, + "/api/v1/advanced_data_type/types": { + "get": { + "description": "Returns a list of available advanced data types.", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "a successful return of the available advanced data types has taken place." + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Advanced Data Type" + ] + } + }, "/api/v1/annotation_layer/": { "delete": { "description": "Deletes multiple annotation layers in a bulk operation.", @@ -9380,9 +10681,6 @@ }, "description": "ZIP file" }, - "400": { - "$ref": "#/components/responses/400" - }, "401": { "$ref": "#/components/responses/401" }, @@ -9440,7 +10738,7 @@ } } }, - "description": "Dashboard import result" + "description": "Assets import result" }, "400": { "$ref": "#/components/responses/400" @@ -9540,6 +10838,42 @@ ] } }, + "/api/v1/available_domains/": { + "get": { + "description": "Get all available domains", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/AvailableDomainsSchema" + } + }, + "type": "object" + } + } + }, + "description": "a list of available domains" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Available Domains" + ] + } + }, "/api/v1/cachekey/invalidate": { "post": { "description": "Takes a list of datasources, finds the associated cache records and invalidates them and removes the database records", @@ -10460,7 +11794,7 @@ } ], "responses": { - "200": { + "202": { "content": { "application/json": { "schema": { @@ -10470,9 +11804,6 @@ }, "description": "Chart async result" }, - "302": { - "description": "Redirects to the current digest" - }, "400": { "$ref": "#/components/responses/400" }, @@ -10524,6 +11855,14 @@ "schema": { "type": "string" } + }, + { + "description": "Should the queries be forced to load from the source", + "in": "query", + "name": "force", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -10600,9 +11939,6 @@ }, "description": "Chart thumbnail image" }, - "302": { - "description": "Redirects to the current digest" - }, "400": { "$ref": "#/components/responses/400" }, @@ -11453,9 +12789,6 @@ }, "description": "Dashboard added" }, - "302": { - "description": "Redirects to the current digest" - }, "400": { "$ref": "#/components/responses/400" }, @@ -12163,9 +13496,6 @@ }, "description": "Dashboard" }, - "302": { - "description": "Redirects to the current digest" - }, "400": { "$ref": "#/components/responses/400" }, @@ -12221,9 +13551,6 @@ }, "description": "Dashboard chart definitions" }, - "302": { - "description": "Redirects to the current digest" - }, "400": { "$ref": "#/components/responses/400" }, @@ -12280,9 +13607,6 @@ }, "description": "Dashboard dataset definitions" }, - "302": { - "description": "Redirects to the current digest" - }, "400": { "$ref": "#/components/responses/400" }, @@ -12306,16 +13630,17 @@ ] } }, - "/api/v1/dashboard/{pk}": { + "/api/v1/dashboard/{id_or_slug}/embedded": { "delete": { - "description": "Deletes a Dashboard.", + "description": "Removes a dashboard's embedded configuration.", "parameters": [ { + "description": "The dashboard id or slug", "in": "path", - "name": "pk", + "name": "id_or_slug", "required": true, "schema": { - "type": "integer" + "type": "string" } } ], @@ -12333,20 +13658,11 @@ } } }, - "description": "Dashboard deleted" + "description": "Successfully removed the configuration" }, "401": { "$ref": "#/components/responses/401" }, - "403": { - "$ref": "#/components/responses/403" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "422": { - "$ref": "#/components/responses/422" - }, "500": { "$ref": "#/components/responses/500" } @@ -12360,19 +13676,231 @@ "Dashboards" ] }, - "put": { - "description": "Changes a Dashboard.", + "get": { + "description": "Returns the dashboard's embedded configuration", "parameters": [ { + "description": "The dashboard id or slug", "in": "path", - "name": "pk", + "name": "id_or_slug", "required": true, "schema": { - "type": "integer" + "type": "string" } } ], - "requestBody": { + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/EmbeddedDashboardResponseSchema" + } + }, + "type": "object" + } + } + }, + "description": "Result contains the embedded dashboard config" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Dashboards" + ] + }, + "post": { + "description": "Sets a dashboard's embedded configuration.", + "parameters": [ + { + "description": "The dashboard id or slug", + "in": "path", + "name": "id_or_slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbeddedDashboardConfig" + } + } + }, + "description": "The embedded configuration to set", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/EmbeddedDashboardResponseSchema" + } + }, + "type": "object" + } + } + }, + "description": "Successfully set the configuration" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Dashboards" + ] + }, + "put": { + "description": "Sets a dashboard's embedded configuration.", + "parameters": [ + { + "description": "The dashboard id or slug", + "in": "path", + "name": "id_or_slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbeddedDashboardConfig" + } + } + }, + "description": "The embedded configuration to set", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/EmbeddedDashboardResponseSchema" + } + }, + "type": "object" + } + } + }, + "description": "Successfully set the configuration" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Dashboards" + ] + } + }, + "/api/v1/dashboard/{pk}": { + "delete": { + "description": "Deletes a Dashboard.", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Dashboard deleted" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Dashboards" + ] + }, + "put": { + "description": "Changes a Dashboard.", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { "content": { "application/json": { "schema": { @@ -12837,6 +14365,9 @@ }, "description": "Thumbnail does not exist on cache, fired async to compute" }, + "302": { + "description": "Redirects to the current digest" + }, "401": { "$ref": "#/components/responses/401" }, @@ -13000,9 +14531,6 @@ }, "description": "Database added" }, - "302": { - "description": "Redirects to the current digest" - }, "400": { "$ref": "#/components/responses/400" }, @@ -13137,6 +14665,20 @@ "description": "Name of the SQLAlchemy engine", "type": "string" }, + "engine_information": { + "description": "Dict with public properties form the DB Engine", + "properties": { + "disable_ssh_tunneling": { + "description": "Whether the engine supports SSH Tunnels", + "type": "boolean" + }, + "supports_file_upload": { + "description": "Whether the engine supports file uploads", + "type": "boolean" + } + }, + "type": "object" + }, "name": { "description": "Name of the database", "type": "string" @@ -13293,7 +14835,7 @@ ] } }, - "/api/v1/database/test_connection": { + "/api/v1/database/test_connection/": { "post": { "description": "Tests a database connection", "requestBody": { @@ -13343,7 +14885,7 @@ ] } }, - "/api/v1/database/validate_parameters": { + "/api/v1/database/validate_parameters/": { "post": { "description": "Validates parameters used to connect to a database", "requestBody": { @@ -13448,99 +14990,45 @@ ] }, "get": { - "description": "Get an item model", + "description": "Get a database", "parameters": [ { + "description": "The database id", "in": "path", "name": "pk", "required": true, "schema": { "type": "integer" } - }, - { + } + ], + "responses": { + "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_item_schema" + "type": "object" } } }, - "in": "query", - "name": "q" - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "properties": { - "description_columns": { - "properties": { - "column_name": { - "description": "The description for the column name. Will be translated by babel", - "example": "A Nice description for the column", - "type": "string" - } - }, - "type": "object" - }, - "id": { - "description": "The item id", - "type": "string" - }, - "label_columns": { - "properties": { - "column_name": { - "description": "The label for the column name. Will be translated by babel", - "example": "A Nice label for the column", - "type": "string" - } - }, - "type": "object" - }, - "result": { - "$ref": "#/components/schemas/DatabaseRestApi.get" - }, - "show_columns": { - "description": "A list of columns", - "items": { - "type": "string" - }, - "type": "array" - }, - "show_title": { - "description": "A title to render. Will be translated by babel", - "example": "Show Item Details", - "type": "string" - } - }, - "type": "object" - } - } - }, - "description": "Item from Model" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "422": { - "$ref": "#/components/responses/422" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] + "description": "Database" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] } ], "tags": [ @@ -13903,6 +15391,61 @@ ] } }, + "/api/v1/database/{pk}/ssh_tunnel/": { + "delete": { + "description": "Deletes a SSH Tunnel.", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "SSH Tunnel deleted" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Database" + ] + } + }, "/api/v1/database/{pk}/table/{table_name}/{schema_name}/": { "get": { "description": "Get database table metadata", @@ -13972,20 +15515,36 @@ ] } }, - "/api/v1/dataset/": { - "delete": { - "description": "Deletes multiple Datasets in a bulk operation.", + "/api/v1/database/{pk}/table_extra/{table_name}/{schema_name}/": { + "get": { + "description": "Response depends on each DB engine spec normally focused on partitions", "parameters": [ { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/get_delete_ids_schema" - } - } - }, - "in": "query", - "name": "q" + "description": "The database id", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "description": "Table name", + "in": "path", + "name": "table_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Table schema", + "in": "path", + "name": "schema_name", + "required": true, + "schema": { + "type": "string" + } } ], "responses": { @@ -13993,16 +15552,11 @@ "content": { "application/json": { "schema": { - "properties": { - "message": { - "type": "string" - } - }, - "type": "object" + "$ref": "#/components/schemas/TableExtraMetadataResponseSchema" } } }, - "description": "Dataset bulk delete" + "description": "Table extra metadata information" }, "400": { "$ref": "#/components/responses/400" @@ -14010,9 +15564,6 @@ "401": { "$ref": "#/components/responses/401" }, - "403": { - "$ref": "#/components/responses/403" - }, "404": { "$ref": "#/components/responses/404" }, @@ -14028,18 +15579,29 @@ "jwt": [] } ], + "summary": "Get table extra metadata", "tags": [ - "Datasets" + "Database" ] - }, + } + }, + "/api/v1/database/{pk}/tables/": { "get": { - "description": "Get a list of models", "parameters": [ + { + "description": "The database id", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_list_schema" + "$ref": "#/components/schemas/database_tables_query_schema" } } }, @@ -14054,59 +15616,12 @@ "schema": { "properties": { "count": { - "description": "The total record count on the backend", - "type": "number" - }, - "description_columns": { - "properties": { - "column_name": { - "description": "The description for the column name. Will be translated by babel", - "example": "A Nice description for the column", - "type": "string" - } - }, - "type": "object" - }, - "ids": { - "description": "A list of item ids, useful when you don't know the column id", - "items": { - "type": "string" - }, - "type": "array" - }, - "label_columns": { - "properties": { - "column_name": { - "description": "The label for the column name. Will be translated by babel", - "example": "A Nice label for the column", - "type": "string" - } - }, - "type": "object" - }, - "list_columns": { - "description": "A list of columns", - "items": { - "type": "string" - }, - "type": "array" - }, - "list_title": { - "description": "A title to render. Will be translated by babel", - "example": "List Items", - "type": "string" - }, - "order_columns": { - "description": "A list of allowed columns to sort", - "items": { - "type": "string" - }, - "type": "array" + "type": "integer" }, "result": { - "description": "The result from the get list query", + "description": "A List of tables for given database", "items": { - "$ref": "#/components/schemas/DatasetRestApi.get_list" + "$ref": "#/components/schemas/DatabaseTablesResponse" }, "type": "array" } @@ -14115,7 +15630,7 @@ } } }, - "description": "Items from Model" + "description": "Tables list" }, "400": { "$ref": "#/components/responses/400" @@ -14123,6 +15638,9 @@ "401": { "$ref": "#/components/responses/401" }, + "404": { + "$ref": "#/components/responses/404" + }, "422": { "$ref": "#/components/responses/422" }, @@ -14135,41 +15653,55 @@ "jwt": [] } ], + "summary": "Get a list of tables for given database", "tags": [ - "Datasets" + "Database" ] - }, + } + }, + "/api/v1/database/{pk}/validate_sql/": { "post": { - "description": "Create a new Dataset", + "description": "Validates arbitrary SQL.", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DatasetRestApi.post" + "$ref": "#/components/schemas/ValidateSQLRequest" } } }, - "description": "Dataset schema", + "description": "Validate SQL request", "required": true }, "responses": { - "201": { + "200": { "content": { "application/json": { "schema": { "properties": { - "id": { - "type": "number" - }, "result": { - "$ref": "#/components/schemas/DatasetRestApi.post" + "description": "A List of SQL errors found on the statement", + "items": { + "$ref": "#/components/schemas/ValidateSQLResponse" + }, + "type": "array" } }, "type": "object" } } }, - "description": "Dataset added" + "description": "Validation result" }, "400": { "$ref": "#/components/responses/400" @@ -14177,9 +15709,232 @@ "401": { "$ref": "#/components/responses/401" }, - "422": { - "$ref": "#/components/responses/422" - }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Validates that arbitrary sql is acceptable for the given database", + "tags": [ + "Database" + ] + } + }, + "/api/v1/dataset/": { + "delete": { + "description": "Deletes multiple Datasets in a bulk operation.", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_delete_ids_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Dataset bulk delete" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + }, + "get": { + "description": "Get a list of models", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_list_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "count": { + "description": "The total record count on the backend", + "type": "number" + }, + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "ids": { + "description": "A list of item ids, useful when you don't know the column id", + "items": { + "type": "string" + }, + "type": "array" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "list_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "list_title": { + "description": "A title to render. Will be translated by babel", + "example": "List Items", + "type": "string" + }, + "order_columns": { + "description": "A list of allowed columns to sort", + "items": { + "type": "string" + }, + "type": "array" + }, + "result": { + "description": "The result from the get list query", + "items": { + "$ref": "#/components/schemas/DatasetRestApi.get_list" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Items from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + }, + "post": { + "description": "Create a new Dataset", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatasetRestApi.post" + } + } + }, + "description": "Dataset schema", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "number" + }, + "result": { + "$ref": "#/components/schemas/DatasetRestApi.post" + } + }, + "type": "object" + } + } + }, + "description": "Dataset added" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, "500": { "$ref": "#/components/responses/500" } @@ -14337,6 +16092,68 @@ ] } }, + "/api/v1/dataset/duplicate": { + "post": { + "description": "Duplicates a Dataset", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatasetDuplicateSchema" + } + } + }, + "description": "Dataset schema", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "number" + }, + "result": { + "$ref": "#/components/schemas/DatasetDuplicateSchema" + } + }, + "type": "object" + } + } + }, + "description": "Dataset duplicated" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, "/api/v1/dataset/export/": { "get": { "description": "Exports multiple datasets and downloads them as YAML files", @@ -14406,6 +16223,14 @@ "passwords": { "description": "JSON map of passwords for each featured database in the ZIP file. If the ZIP includes a database config in the path `databases/MyDatabase.yaml`, the password should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_password\"}`.", "type": "string" + }, + "sync_columns": { + "description": "sync columns?", + "type": "boolean" + }, + "sync_metrics": { + "description": "sync metrics?", + "type": "boolean" } }, "type": "object" @@ -14637,14 +16462,221 @@ } } }, - "description": "Item from Model" - }, - "400": { - "$ref": "#/components/responses/400" + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + }, + "put": { + "description": "Changes a Dataset", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "in": "query", + "name": "override_columns", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatasetRestApi.put" + } + } + }, + "description": "Dataset schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "number" + }, + "result": { + "$ref": "#/components/schemas/DatasetRestApi.put" + } + }, + "type": "object" + } + } + }, + "description": "Dataset changed" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/{pk}/column/{column_id}": { + "delete": { + "description": "Delete a Dataset column", + "parameters": [ + { + "description": "The dataset pk for this column", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "description": "The column id for this dataset", + "in": "path", + "name": "column_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Column deleted" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/{pk}/metric/{metric_id}": { + "delete": { + "description": "Delete a Dataset metric", + "parameters": [ + { + "description": "The dataset pk for this column", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "description": "The metric id for this dataset", + "in": "path", + "name": "metric_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Metric deleted" }, "401": { "$ref": "#/components/responses/401" }, + "403": { + "$ref": "#/components/responses/403" + }, "404": { "$ref": "#/components/responses/404" }, @@ -14663,9 +16695,11 @@ "tags": [ "Datasets" ] - }, + } + }, + "/api/v1/dataset/{pk}/refresh": { "put": { - "description": "Changes a Dataset", + "description": "Refreshes and updates columns of a dataset", "parameters": [ { "in": "path", @@ -14674,47 +16708,23 @@ "schema": { "type": "integer" } - }, - { - "in": "query", - "name": "override_columns", - "schema": { - "type": "boolean" - } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DatasetRestApi.put" - } - } - }, - "description": "Dataset schema", - "required": true - }, "responses": { "200": { "content": { "application/json": { "schema": { "properties": { - "id": { - "type": "number" - }, - "result": { - "$ref": "#/components/schemas/DatasetRestApi.put" + "message": { + "type": "string" } }, "type": "object" } } }, - "description": "Dataset changed" - }, - "400": { - "$ref": "#/components/responses/400" + "description": "Dataset delete" }, "401": { "$ref": "#/components/responses/401" @@ -14742,27 +16752,17 @@ ] } }, - "/api/v1/dataset/{pk}/column/{column_id}": { - "delete": { - "description": "Delete a Dataset column", + "/api/v1/dataset/{pk}/related_objects": { + "get": { + "description": "Get charts and dashboards count associated to a dataset", "parameters": [ { - "description": "The dataset pk for this column", "in": "path", "name": "pk", "required": true, "schema": { "type": "integer" } - }, - { - "description": "The column id for this dataset", - "in": "path", - "name": "column_id", - "required": true, - "schema": { - "type": "integer" - } } ], "responses": { @@ -14770,29 +16770,18 @@ "content": { "application/json": { "schema": { - "properties": { - "message": { - "type": "string" - } - }, - "type": "object" + "$ref": "#/components/schemas/DatasetRelatedObjectsResponse" } } }, - "description": "Column deleted" + "description": "Query result" }, "401": { "$ref": "#/components/responses/401" }, - "403": { - "$ref": "#/components/responses/403" - }, "404": { "$ref": "#/components/responses/404" }, - "422": { - "$ref": "#/components/responses/422" - }, "500": { "$ref": "#/components/responses/500" } @@ -14807,27 +16796,35 @@ ] } }, - "/api/v1/dataset/{pk}/metric/{metric_id}": { - "delete": { - "description": "Delete a Dataset metric", + "/api/v1/datasource/{datasource_type}/{datasource_id}/column/{column_name}/values/": { + "get": { "parameters": [ { - "description": "The dataset pk for this column", + "description": "The type of datasource", "in": "path", - "name": "pk", + "name": "datasource_type", "required": true, "schema": { - "type": "integer" + "type": "string" } }, { - "description": "The metric id for this dataset", + "description": "The id of the datasource", "in": "path", - "name": "metric_id", + "name": "datasource_id", "required": true, "schema": { "type": "integer" } + }, + { + "description": "The name of the column to get values for", + "in": "path", + "name": "column_name", + "required": true, + "schema": { + "type": "string" + } } ], "responses": { @@ -14836,15 +16833,37 @@ "application/json": { "schema": { "properties": { - "message": { - "type": "string" + "result": { + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "object" + } + ] + }, + "type": "array" } }, "type": "object" } } }, - "description": "Metric deleted" + "description": "A List of distinct values for the column" + }, + "400": { + "$ref": "#/components/responses/400" }, "401": { "$ref": "#/components/responses/401" @@ -14855,9 +16874,6 @@ "404": { "$ref": "#/components/responses/404" }, - "422": { - "$ref": "#/components/responses/422" - }, "500": { "$ref": "#/components/responses/500" } @@ -14867,21 +16883,23 @@ "jwt": [] } ], + "summary": "Get possible values for a datasource column", "tags": [ - "Datasets" + "Datasources" ] } }, - "/api/v1/dataset/{pk}/refresh": { - "put": { - "description": "Refreshes and updates columns of a dataset", + "/api/v1/embedded_dashboard/{uuid}": { + "get": { + "description": "Get a report schedule log", "parameters": [ { + "description": "The embedded configuration uuid", "in": "path", - "name": "pk", + "name": "uuid", "required": true, "schema": { - "type": "integer" + "type": "string" } } ], @@ -14891,28 +16909,22 @@ "application/json": { "schema": { "properties": { - "message": { - "type": "string" + "result": { + "$ref": "#/components/schemas/EmbeddedDashboardResponseSchema" } }, "type": "object" } } }, - "description": "Dataset delete" + "description": "Result contains the embedded dashboard configuration" }, "401": { "$ref": "#/components/responses/401" }, - "403": { - "$ref": "#/components/responses/403" - }, "404": { "$ref": "#/components/responses/404" }, - "422": { - "$ref": "#/components/responses/422" - }, "500": { "$ref": "#/components/responses/500" } @@ -14923,21 +16935,48 @@ } ], "tags": [ - "Datasets" + "Embedded Dashboard" ] } }, - "/api/v1/dataset/{pk}/related_objects": { + "/api/v1/explore/": { "get": { - "description": "Get charts and dashboards count associated to a dataset", + "description": "Assembles Explore related information (form_data, slice, dataset)\\n in a single endpoint.<br/><br/>\\nThe information can be assembled from:<br/> - The cache using a form_data_key<br/> - The metadata database using a permalink_key<br/> - Build from scratch using dataset or slice identifiers.", "parameters": [ { - "in": "path", - "name": "pk", - "required": true, + "in": "query", + "name": "form_data_key", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "permalink_key", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "slice_id", + "schema": { + "type": "integer" + } + }, + { + "in": "query", + "name": "datasource_id", "schema": { "type": "integer" } + }, + { + "in": "query", + "name": "datasource_type", + "schema": { + "type": "string" + } } ], "responses": { @@ -14945,11 +16984,14 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DatasetRelatedObjectsResponse" + "$ref": "#/components/schemas/ExploreContextSchema" } } }, - "description": "Query result" + "description": "Returns the initial context." + }, + "400": { + "$ref": "#/components/responses/400" }, "401": { "$ref": "#/components/responses/401" @@ -14957,6 +16999,9 @@ "404": { "$ref": "#/components/responses/404" }, + "422": { + "$ref": "#/components/responses/422" + }, "500": { "$ref": "#/components/responses/500" } @@ -14966,8 +17011,9 @@ "jwt": [] } ], + "summary": "Assembles Explore related information (form_data, slice, dataset)\\n in a single endpoint.", "tags": [ - "Datasets" + "Explore" ] } }, @@ -15490,6 +17536,65 @@ ] } }, + "/api/v1/log/recent_activity/{user_id}/": { + "get": { + "parameters": [ + { + "description": "The id of the user", + "in": "path", + "name": "user_id", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_recent_activity_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RecentActivityResponseSchema" + } + } + }, + "description": "A List of recent activity objects" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Get recent activity data for a user", + "tags": [ + "LogRestApi" + ] + } + }, "/api/v1/log/{pk}": { "get": { "description": "Get an item model", @@ -15592,9 +17697,37 @@ ] } }, - "/api/v1/me/": { + "/api/v1/me/": { + "get": { + "description": "Returns the user object corresponding to the agent making the request, or returns a 401 error if the user is unauthenticated.", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/UserResponseSchema" + } + }, + "type": "object" + } + } + }, + "description": "The current user" + }, + "401": { + "$ref": "#/components/responses/401" + } + }, + "tags": [ + "Current User" + ] + } + }, + "/api/v1/me/roles/": { "get": { - "description": "Returns the user object corresponding to the agent making the request, or returns a 401 error if the user is unauthenticated.", + "description": "Returns the user roles corresponding to the agent making the request, or returns a 401 error if the user is unauthenticated.", "responses": { "200": { "content": { @@ -15904,6 +18037,118 @@ ] } }, + "/api/v1/query/stop": { + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StopQuerySchema" + } + } + }, + "description": "Stop query schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Query stopped" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Manually stop a query with client_id", + "tags": [ + "Queries" + ] + } + }, + "/api/v1/query/updated_since": { + "get": { + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/queries_get_updated_since_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "description": "A List of queries that changed after last_updated_ms", + "items": { + "$ref": "#/components/schemas/QueryRestApi.get" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Queries list" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Get a list of queries that changed after last_updated_ms", + "tags": [ + "Queries" + ] + } + }, "/api/v1/query/{pk}": { "get": { "description": "Get query detail information.", @@ -16211,6 +18456,9 @@ "404": { "$ref": "#/components/responses/404" }, + "422": { + "$ref": "#/components/responses/422" + }, "500": { "$ref": "#/components/responses/500" } @@ -16575,6 +18823,9 @@ "404": { "$ref": "#/components/responses/404" }, + "422": { + "$ref": "#/components/responses/422" + }, "500": { "$ref": "#/components/responses/500" } @@ -17560,6 +19811,9 @@ }, "description": "Result contains the guest token" }, + "400": { + "$ref": "#/components/responses/400" + }, "401": { "$ref": "#/components/responses/401" }, @@ -17687,6 +19941,174 @@ ] } }, + "/api/v1/sqllab/execute/": { + "post": { + "description": "Starts the execution of a SQL query", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecutePayloadSchema" + } + } + }, + "description": "SQL query and params", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryExecutionResponseSchema" + } + } + }, + "description": "Query execution result" + }, + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryExecutionResponseSchema" + } + } + }, + "description": "Query execution result, query still running" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "SQL Lab" + ] + } + }, + "/api/v1/sqllab/export/{client_id}/": { + "get": { + "parameters": [ + { + "description": "The SQL query result identifier", + "in": "path", + "name": "client_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "text/csv": { + "schema": { + "type": "string" + } + } + }, + "description": "SQL query results" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Exports the SQL query results to a CSV", + "tags": [ + "SQL Lab" + ] + } + }, + "/api/v1/sqllab/results/": { + "get": { + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/sql_lab_get_results_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryExecutionResponseSchema" + } + } + }, + "description": "SQL query execution result" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "410": { + "$ref": "#/components/responses/410" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Gets the result of a SQL query execution", + "tags": [ + "SQL Lab" + ] + } + }, "/api/{version}/_openapi": { "get": { "description": "Get the OpenAPI spec for a specific API version", diff --git a/docs/static/script/matomo.js b/docs/static/script/matomo.js new file mode 100644 index 0000000000000..4af7a4e85dac4 --- /dev/null +++ b/docs/static/script/matomo.js @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var _paq = (window._paq = window._paq || []); +/* tracker methods like "setCustomDimension" should be called before "trackPageView" */ +/* We explicitly disable cookie tracking to avoid privacy issues */ +_paq.push(['disableCookies']); +_paq.push(['trackPageView']); +_paq.push(['enableLinkTracking']); +(function () { + var u = 'https://analytics.apache.org/'; + _paq.push(['setTrackerUrl', u + 'matomo.php']); + _paq.push(['setSiteId', '22']); + var d = document, + g = d.createElement('script'), + s = d.getElementsByTagName('script')[0]; + g.async = true; + g.src = u + 'matomo.js'; + s.parentNode.insertBefore(g, s); +})(); diff --git a/docs/yarn.lock b/docs/yarn.lock index 5f0aa7a39e7f1..e7af9847d636e 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -3014,15 +3014,37 @@ dependencies: "@hapi/hoek" "^9.0.0" +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/resolve-uri@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" - integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.11" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" - integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== "@jridgewell/trace-mapping@^0.3.0": version "0.3.4" @@ -3032,6 +3054,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@mdx-js/mdx@^1.6.22": version "1.6.22" resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba" @@ -3822,13 +3852,13 @@ resolved "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" + mime-types "~2.1.34" + negotiator "0.6.3" acorn-import-assertions@^1.7.6: version "1.8.0" @@ -3840,15 +3870,10 @@ acorn-walk@^8.0.0: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^8.0.4, acorn@^8.4.1: - version "8.5.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz" - integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== - -acorn@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== +acorn@^8.0.4, acorn@^8.4.1, acorn@^8.5.0: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== address@^1.0.1, address@^1.1.2: version "1.1.2" @@ -4071,8 +4096,8 @@ argparse@^2.0.1: array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== array-flatten@^2.1.0: version "2.1.2" @@ -4298,7 +4323,7 @@ batch@0.6.1: big.js@^5.2.2: version "5.2.2" - resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== binary-extensions@^2.0.0: @@ -4311,21 +4336,23 @@ bluebird@^3.7.1: resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -body-parser@1.19.0: - version "1.19.0" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== dependencies: - bytes "3.1.0" + bytes "3.1.2" content-type "~1.0.4" debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" bonjour@^3.5.0: version "3.5.0" @@ -4438,7 +4465,7 @@ btoa@^1.2.1: buffer-from@^1.0.0: version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer-indexof@^1.0.0: @@ -4459,10 +4486,10 @@ bytes@3.0.0: resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== cacheable-request@^6.0.0: version "6.1.0" @@ -4479,7 +4506,7 @@ cacheable-request@^6.0.0: call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== dependencies: function-bind "^1.1.1" @@ -4790,7 +4817,7 @@ comma-separated-tokens@^1.0.0: commander@^2.20.0: version "2.20.3" - resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== commander@^5.1.0: @@ -4870,16 +4897,16 @@ content-disposition@0.5.2: resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz" integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== dependencies: - safe-buffer "5.1.2" + safe-buffer "5.2.1" content-type@~1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== convert-source-map@^1.5.0, convert-source-map@^1.7.0: @@ -4891,13 +4918,13 @@ convert-source-map@^1.5.0, convert-source-map@^1.7.0: cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz" - integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== cookie@~0.4.1: version "0.4.1" @@ -5419,15 +5446,20 @@ del@^6.0.0: rimraf "^3.0.2" slash "^3.0.0" +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + depd@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== detab@2.0.4: version "2.0.4" @@ -5612,8 +5644,8 @@ eastasianwidth@^0.2.0: ee-first@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.3.886: version "1.3.894" @@ -5652,7 +5684,7 @@ emoji-regex@^9.2.2: emojis-list@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== emoticon@^3.2.0: @@ -5671,8 +5703,8 @@ emotion-theming@^10.0.27: encodeurl@~1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== end-of-stream@^1.1.0: version "1.4.4" @@ -5869,8 +5901,8 @@ eta@^1.12.3: etag@~1.8.1: version "1.8.1" - resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== eval@0.1.6: version "0.1.6" @@ -5921,37 +5953,38 @@ execa@^5.0.0: strip-final-newline "^2.0.0" express@^4.17.1: - version "4.17.1" - resolved "https://registry.npmjs.org/express/-/express-4.17.1.tgz" - integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== dependencies: - accepts "~1.3.7" + accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" + body-parser "1.20.1" + content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.4.0" + cookie "0.5.0" cookie-signature "1.0.6" debug "2.6.9" - depd "~1.1.2" + depd "2.0.0" encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "~1.1.2" + finalhandler "1.2.0" fresh "0.5.2" + http-errors "2.0.0" merge-descriptors "1.0.1" methods "~1.1.2" - on-finished "~2.3.0" + on-finished "2.4.1" parseurl "~1.3.3" path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" + proxy-addr "~2.0.7" + qs "6.11.0" range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" - statuses "~1.5.0" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" type-is "~1.6.18" utils-merge "1.0.1" vary "~1.1.2" @@ -6003,9 +6036,9 @@ fast-glob@^3.2.7, fast-glob@^3.2.9: micromatch "^4.0.4" fast-json-patch@^3.0.0-1: - version "3.1.0" - resolved "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.0.tgz" - integrity sha512-IhpytlsVTRndz0hU5t0/MGzS/etxLlfrpG5V5M9mVbuj9TrJLWaMfsox9REM5rkuGX0T+5qjpe8XA1o0gZ42nA== + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-json-patch/-/fast-json-patch-3.1.1.tgz#85064ea1b1ebf97a3f7ad01e23f9337e72c66947" + integrity sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ== fast-json-stable-stringify@^2.0.0: version "2.1.0" @@ -6092,17 +6125,17 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== dependencies: debug "2.6.9" encodeurl "~1.0.2" escape-html "~1.0.3" - on-finished "~2.3.0" + on-finished "2.4.1" parseurl "~1.3.3" - statuses "~1.5.0" + statuses "2.0.1" unpipe "~1.0.0" find-cache-dir@^3.3.1: @@ -6199,7 +6232,7 @@ formdata-node@^4.0.0: forwarded@0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fraction.js@^4.1.1: @@ -6214,8 +6247,8 @@ fraction.js@^4.2.0: fresh@0.5.2: version "0.5.2" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== fs-extra@^10.0.1: version "10.0.1" @@ -6261,7 +6294,16 @@ gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: +get-intrinsic@^1.0.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" + integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz" integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== @@ -6476,6 +6518,11 @@ has-symbols@^1.0.1, has-symbols@^1.0.2: resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + has-tostringtag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" @@ -6698,25 +6745,25 @@ htmlparser2@^6.1.0: entities "^2.0.0" http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz" integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" http-errors@~1.6.2: version "1.6.3" @@ -6728,17 +6775,6 @@ http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" -http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - http-parser-js@>=0.5.1: version "0.5.3" resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz" @@ -6769,13 +6805,20 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -iconv-lite@0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24: version "0.4.24" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz" @@ -6806,7 +6849,7 @@ image-size@^1.0.1: image-size@~0.5.0: version "0.5.5" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" - integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= + integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ== immer@^9.0.7: version "9.0.12" @@ -6907,7 +6950,7 @@ ip@^1.1.0: ipaddr.js@1.9.1: version "1.9.1" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== ipaddr.js@^2.0.1: @@ -7335,17 +7378,10 @@ json2mq@^0.2.0: dependencies: string-convert "^0.2.0" -json5@^2.1.2: - 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" - -json5@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== +json5@^2.1.2, json5@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.2.tgz#64471c5bdcc564c18f7c1d4df2e2297f2457c5ab" + integrity sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ== jsonfile@^6.0.1: version "6.1.0" @@ -7386,16 +7422,16 @@ latest-version@^5.1.0: package-json "^6.3.0" less-loader@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-11.0.0.tgz#a31b2bc5cdfb62f1c7de9b2d01cd944c22b1a024" - integrity sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw== + version "11.1.0" + resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-11.1.0.tgz#a452384259bdf8e4f6d5fdcc39543609e6313f82" + integrity sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug== dependencies: klona "^2.0.4" less@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/less/-/less-4.1.2.tgz#6099ee584999750c2624b65f80145f8674e4b4b0" - integrity sha512-EoQp/Et7OSOVu0aJknJOtlXZsnr8XE8KwuzTHOLeVSEx8pVWUICc8Q0VYRHgzyjX78nMEyC/oztWFbgyhtNfDA== + version "4.1.3" + resolved "https://registry.yarnpkg.com/less/-/less-4.1.3.tgz#175be9ddcbf9b250173e0a00b4d6920a5b770246" + integrity sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA== dependencies: copy-anything "^2.0.1" parse-node-version "^1.0.1" @@ -7406,7 +7442,7 @@ less@^4.1.2: image-size "~0.5.0" make-dir "^2.1.0" mime "^1.4.1" - needle "^2.5.2" + needle "^3.1.0" source-map "~0.6.0" leven@^3.1.0: @@ -7430,9 +7466,9 @@ loader-runner@^4.2.0: integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== loader-utils@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz" - integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== dependencies: big.js "^5.2.2" emojis-list "^3.0.0" @@ -7671,8 +7707,8 @@ mdurl@^1.0.0: media-typer@0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== memfs@^3.1.2: version "3.3.0" @@ -7709,8 +7745,8 @@ memoizee@^0.4.15: merge-descriptors@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== merge-stream@^2.0.0: version "2.0.0" @@ -7724,8 +7760,8 @@ merge2@^1.3.0, merge2@^1.4.1: methods@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.4" @@ -7748,6 +7784,11 @@ mime-db@1.51.0, "mime-db@>= 1.43.0 < 2": resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz" integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + mime-db@~1.33.0: version "1.33.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz" @@ -7760,16 +7801,23 @@ mime-types@2.1.18: dependencies: mime-db "~1.33.0" -mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24: +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17: version "2.1.34" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz" integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== dependencies: mime-db "1.51.0" +mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime@1.6.0, mime@^1.4.1: version "1.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mime@^2.3.1: @@ -7834,28 +7882,23 @@ mkdirp@^0.5.5, mkdirp@~0.5.1: minimist "^1.2.5" moment@^2.24.0, moment@^2.25.3: - version "2.29.2" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.2.tgz#00910c60b20843bcba52d37d58c628b47b1f20e4" - integrity sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg== + version "2.29.4" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" + integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== ms@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== ms@2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@2.1.3, ms@^2.1.1: version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== multicast-dns-service-types@^1.1.0: @@ -7876,19 +7919,19 @@ nanoid@^3.1.30, nanoid@^3.3.1: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== -needle@^2.5.2: - version "2.9.1" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" - integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== +needle@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-3.2.0.tgz#07d240ebcabfd65c76c03afae7f6defe6469df44" + integrity sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ== dependencies: debug "^3.2.6" - iconv-lite "^0.4.4" + iconv-lite "^0.6.3" sax "^1.2.4" -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== neo-async@^2.6.2: version "2.6.2" @@ -7998,11 +8041,16 @@ object-assign@^4.1.0, object-assign@^4.1.1: resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -object-inspect@^1.11.0, object-inspect@^1.9.0: +object-inspect@^1.11.0: version "1.11.0" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz" integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== +object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + object-is@^1.0.1: version "1.1.5" resolved "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz" @@ -8049,10 +8097,10 @@ obuf@^1.0.0, obuf@^1.1.2: resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== dependencies: ee-first "1.1.1" @@ -8225,7 +8273,7 @@ parse5@^6.0.0, parse5@^6.0.1: parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== pascal-case@^3.1.2: @@ -8268,8 +8316,8 @@ path-parse@^1.0.6, path-parse@^1.0.7: path-to-regexp@0.1.7: version "0.1.7" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== path-to-regexp@2.2.1: version "2.2.1" @@ -8932,9 +8980,9 @@ property-information@^5.0.0, property-information@^5.3.0: dependencies: xtend "^4.0.0" -proxy-addr@~2.0.5: +proxy-addr@~2.0.7: version "2.0.7" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: forwarded "0.2.0" @@ -8943,7 +8991,7 @@ proxy-addr@~2.0.5: prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== pump@^3.0.0: version "3.0.0" @@ -8985,15 +9033,10 @@ q@^1.1.2: resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= -qs@6.7.0: - version "6.7.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - -qs@^6.9.4: - version "6.10.2" - resolved "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz" - integrity sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw== +qs@6.11.0, qs@^6.9.4: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: side-channel "^1.0.4" @@ -9038,16 +9081,16 @@ range-parser@1.2.0: range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== dependencies: - bytes "3.1.0" - http-errors "1.7.2" + bytes "3.1.2" + http-errors "2.0.0" iconv-lite "0.4.24" unpipe "1.0.0" @@ -10024,14 +10067,14 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sax@^1.2.4, sax@~1.2.4: @@ -10140,24 +10183,24 @@ semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: dependencies: lru-cache "^6.0.0" -send@0.17.1: - version "0.17.1" - resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== dependencies: debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" + depd "2.0.0" + destroy "1.2.0" encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" fresh "0.5.2" - http-errors "~1.7.2" + http-errors "2.0.0" mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" + ms "2.1.3" + on-finished "2.4.1" range-parser "~1.2.1" - statuses "~1.5.0" + statuses "2.0.1" serialize-error@^8.1.0: version "8.1.0" @@ -10200,15 +10243,15 @@ serve-index@^1.9.1: mime-types "~2.1.17" parseurl "~1.3.2" -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.17.1" + send "0.18.0" setimmediate@^1.0.5: version "1.0.5" @@ -10220,10 +10263,10 @@ setprototypeof@1.1.0: resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz" integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== sha.js@^2.4.11: version "2.4.11" @@ -10273,7 +10316,7 @@ shelljs@^0.8.5: side-channel@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== dependencies: call-bind "^1.0.0" @@ -10349,9 +10392,9 @@ source-map-js@^1.0.2: integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== source-map-support@~0.5.20: - version "0.5.20" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -10366,11 +10409,6 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@~0.7.2: - version "0.7.3" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - space-separated-tokens@^1.0.0: version "1.1.5" resolved "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz" @@ -10414,7 +10452,12 @@ state-toggle@^1.0.0: resolved "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz" integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== -"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= @@ -10703,23 +10746,14 @@ terser-webpack-plugin@^5.3.1: source-map "^0.6.1" terser "^5.7.2" -terser@^5.10.0: - version "5.12.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.1.tgz#4cf2ebed1f5bceef5c83b9f60104ac4a78b49e9c" - integrity sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ== +terser@^5.10.0, terser@^5.7.2: + version "5.14.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10" + integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA== dependencies: + "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.20" - -terser@^5.7.2: - version "5.9.0" - resolved "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz" - integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ== - dependencies: - commander "^2.20.0" - source-map "~0.7.2" source-map-support "~0.5.20" text-table@^0.2.0: @@ -10777,10 +10811,10 @@ toggle-selection@^1.0.6: resolved "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz" integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== totalist@^1.0.0: version "1.1.0" @@ -10828,9 +10862,9 @@ tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.1: integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== tslib@^2.3.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== type-fest@^0.20.2: version "0.20.2" @@ -10842,9 +10876,9 @@ type-fest@^2.5.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.1.tgz#d2be8f50bf5f8f0a5fd916d29bf3e98c17e960be" integrity sha512-AiknQSEqKVGDDjtZqeKrUoTlcj7FKhupmnVUgz6KoOKtvMwRGE6hUNJ/nVear+h7fnUPO1q/htSkYKb1pyntkQ== -type-is@~1.6.17, type-is@~1.6.18: +type-is@~1.6.18: version "1.6.18" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: media-typer "0.3.0" @@ -10873,9 +10907,9 @@ typescript@^4.3.5: integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== ua-parser-js@^0.7.30: - 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== + version "0.7.33" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" + integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw== unbox-primitive@^1.0.1: version "1.0.1" @@ -11018,8 +11052,8 @@ universalify@^2.0.0: unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unquote@~1.1.1: version "1.1.1" @@ -11131,8 +11165,8 @@ utility-types@^3.10.0: utils-merge@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== uuid@^3.4.0: version "3.4.0" @@ -11146,8 +11180,8 @@ value-equal@^1.0.1: vary@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== vendors@^1.0.3: version "1.0.4" diff --git a/helm/superset/Chart.lock b/helm/superset/Chart.lock new file mode 100644 index 0000000000000..d1bdc5115b957 --- /dev/null +++ b/helm/superset/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 12.1.6 +- name: redis + repository: https://charts.bitnami.com/bitnami + version: 17.3.17 +digest: sha256:3bfff146fa89077705c0bedea59bbe2c9f15715220f9ea84f493335f0413af6e +generated: "2023-01-04T12:50:49.567524-08:00" diff --git a/helm/superset/Chart.yaml b/helm/superset/Chart.yaml index 16c59869dfb46..7a3f2b1f83e83 100644 --- a/helm/superset/Chart.yaml +++ b/helm/superset/Chart.yaml @@ -15,20 +15,27 @@ # limitations under the License. # apiVersion: v2 -appVersion: "1.0" +appVersion: "2.0.1" description: Apache Superset is a modern, enterprise-ready business intelligence web application name: superset +icon: https://artifacthub.io/image/68c1d717-0e97-491f-b046-754e46f46922@2x +home: https://superset.apache.org/ +keywords: + - business intelligence + - data science +sources: + - https://github.com/apache/superset maintainers: - name: craig-rueda email: craig@craigrueda.com url: https://github.com/craig-rueda -version: 0.6.3 +version: 0.8.6 dependencies: -- name: postgresql - version: 11.1.22 - repository: https://charts.bitnami.com/bitnami - condition: postgresql.enabled -- name: redis - version: 16.3.1 - repository: https://charts.bitnami.com/bitnami - condition: redis.enabled + - name: postgresql + version: 12.1.6 + repository: https://charts.bitnami.com/bitnami + condition: postgresql.enabled + - name: redis + version: 17.3.17 + repository: https://charts.bitnami.com/bitnami + condition: redis.enabled diff --git a/helm/superset/README.md b/helm/superset/README.md new file mode 100644 index 0000000000000..5d56ead1be13f --- /dev/null +++ b/helm/superset/README.md @@ -0,0 +1,267 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> + +<!-- +NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs#installation +--> + +# superset + +![Version: 0.8.6](https://img.shields.io/badge/Version-0.8.6-informational?style=flat-square) + +Apache Superset is a modern, enterprise-ready business intelligence web application + +**Homepage:** <https://superset.apache.org/> + +## Source Code + +* <https://github.com/apache/superset> + +## TL;DR + +```console +helm repo add superset http://apache.github.io/superset/ +helm install my-superset superset/superset +``` + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| https://charts.bitnami.com/bitnami | postgresql | 12.1.6 | +| https://charts.bitnami.com/bitnami | redis | 17.3.17 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | | +| bootstrapScript | string | see `values.yaml` | Install additional packages and do any other bootstrap configuration in this script For production clusters it's recommended to build own image with this step done in CI | +| configFromSecret | string | `"{{ template \"superset.fullname\" . }}-config"` | The name of the secret which we will use to generate a superset_config.py file Note: this secret must have the key superset_config.py in it and can include other files as well | +| configMountPath | string | `"/app/pythonpath"` | | +| configOverrides | object | `{}` | A dictionary of overrides to append at the end of superset_config.py - the name does not matter WARNING: the order is not guaranteed Files can be passed as helm --set-file configOverrides.my-override=my-file.py | +| configOverridesFiles | object | `{}` | Same as above but the values are files | +| envFromSecret | string | `"{{ template \"superset.fullname\" . }}-env"` | The name of the secret which we will use to populate env vars in deployed pods This can be useful for secret keys, etc. | +| envFromSecrets | list | `[]` | This can be a list of templated strings | +| extraConfigMountPath | string | `"/app/configs"` | | +| extraConfigs | object | `{}` | Extra files to mount on `/app/pythonpath` | +| extraEnv | object | `{}` | Extra environment variables that will be passed into pods | +| extraEnvRaw | list | `[]` | Extra environment variables in RAW format that will be passed into pods | +| extraSecretEnv | object | `{}` | Extra environment variables to pass as secrets | +| extraSecrets | object | `{}` | Extra files to mount on `/app/pythonpath` as secrets | +| extraVolumeMounts | list | `[]` | | +| extraVolumes | list | `[]` | | +| hostAliases | list | `[]` | Custom hostAliases for all superset pods # https://kubernetes.io/docs/tasks/network/customize-hosts-file-for-pods/ | +| image.pullPolicy | string | `"IfNotPresent"` | | +| image.repository | string | `"apache/superset"` | | +| image.tag | string | `""` | | +| imagePullSecrets | list | `[]` | | +| ingress.annotations | object | `{}` | | +| ingress.enabled | bool | `false` | | +| ingress.hosts[0] | string | `"chart-example.local"` | | +| ingress.path | string | `"/"` | | +| ingress.pathType | string | `"ImplementationSpecific"` | | +| ingress.tls | list | `[]` | | +| init.adminUser.email | string | `"admin@superset.com"` | | +| init.adminUser.firstname | string | `"Superset"` | | +| init.adminUser.lastname | string | `"Admin"` | | +| init.adminUser.password | string | `"admin"` | | +| init.adminUser.username | string | `"admin"` | | +| init.command | list | a `superset_init.sh` command | Command | +| init.containerSecurityContext | object | `{}` | | +| init.createAdmin | bool | `true` | | +| init.enabled | bool | `true` | | +| init.initContainers | list | a container waiting for postgres | List of initContainers | +| init.initscript | string | a script to create admin user and initailize roles | A Superset init script | +| init.loadExamples | bool | `false` | | +| init.podAnnotations | object | `{}` | | +| init.podSecurityContext | object | `{}` | | +| init.resources | object | `{}` | | +| initImage.pullPolicy | string | `"IfNotPresent"` | | +| initImage.repository | string | `"jwilder/dockerize"` | | +| initImage.tag | string | `"latest"` | | +| nodeSelector | object | `{}` | | +| postgresql | object | see `values.yaml` | Configuration values for the postgresql dependency. ref: https://github.com/kubernetes/charts/blob/master/stable/postgresql/README.md | +| redis | object | see `values.yaml` | Configuration values for the Redis dependency. ref: https://github.com/bitnami/charts/blob/master/bitnami/redis More documentation can be found here: https://artifacthub.io/packages/helm/bitnami/redis | +| resources | object | `{}` | | +| runAsUser | int | `0` | User ID directive. This user must have enough permissions to run the bootstrap script Running containers as root is not recommended in production. Change this to another UID - e.g. 1000 to be more secure | +| service.annotations | object | `{}` | | +| service.loadBalancerIP | string | `nil` | | +| service.nodePort.http | int | `"nil"` | | +| service.port | int | `8088` | | +| service.type | string | `"ClusterIP"` | | +| serviceAccount.annotations | object | `{}` | | +| serviceAccount.create | bool | `false` | Create custom service account for Superset. If create: true and name is not provided, `superset.fullname` will be used. | +| supersetCeleryBeat.affinity | object | `{}` | Affinity to be added to supersetCeleryBeat deployment | +| supersetCeleryBeat.command | list | a `celery beat` command | Command | +| supersetCeleryBeat.containerSecurityContext | object | `{}` | | +| supersetCeleryBeat.deploymentAnnotations | object | `{}` | Annotations to be added to supersetCeleryBeat deployment | +| supersetCeleryBeat.enabled | bool | `false` | This is only required if you intend to use alerts and reports | +| supersetCeleryBeat.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade | +| supersetCeleryBeat.initContainers | list | a container waiting for postgres | List of init containers | +| supersetCeleryBeat.podAnnotations | object | `{}` | Annotations to be added to supersetCeleryBeat pods | +| supersetCeleryBeat.podLabels | object | `{}` | Labels to be added to supersetCeleryBeat pods | +| supersetCeleryBeat.podSecurityContext | object | `{}` | | +| supersetCeleryBeat.resources | object | `{}` | Resource settings for the CeleryBeat pods - these settings overwrite might existing values from the global resources object defined above. | +| supersetCeleryBeat.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetCeleryBeat deployments | +| supersetCeleryFlower.affinity | object | `{}` | Affinity to be added to supersetCeleryFlower deployment | +| supersetCeleryFlower.command | list | a `celery flower` command | Command | +| supersetCeleryFlower.containerSecurityContext | object | `{}` | | +| supersetCeleryFlower.deploymentAnnotations | object | `{}` | Annotations to be added to supersetCeleryFlower deployment | +| supersetCeleryFlower.enabled | bool | `false` | Enables a Celery flower deployment (management UI to monitor celery jobs) WARNING: on superset 1.x, this requires a Superset image that has `flower<1.0.0` installed (which is NOT the case of the default images) flower>=1.0.0 requires Celery 5+ which Superset 1.5 does not support | +| supersetCeleryFlower.initContainers | list | a container waiting for postgres and redis | List of init containers | +| supersetCeleryFlower.livenessProbe.failureThreshold | int | `3` | | +| supersetCeleryFlower.livenessProbe.httpGet.path | string | `"/api/workers"` | | +| supersetCeleryFlower.livenessProbe.httpGet.port | string | `"flower"` | | +| supersetCeleryFlower.livenessProbe.initialDelaySeconds | int | `5` | | +| supersetCeleryFlower.livenessProbe.periodSeconds | int | `5` | | +| supersetCeleryFlower.livenessProbe.successThreshold | int | `1` | | +| supersetCeleryFlower.livenessProbe.timeoutSeconds | int | `1` | | +| supersetCeleryFlower.podAnnotations | object | `{}` | Annotations to be added to supersetCeleryFlower pods | +| supersetCeleryFlower.podLabels | object | `{}` | Labels to be added to supersetCeleryFlower pods | +| supersetCeleryFlower.podSecurityContext | object | `{}` | | +| supersetCeleryFlower.readinessProbe.failureThreshold | int | `3` | | +| supersetCeleryFlower.readinessProbe.httpGet.path | string | `"/api/workers"` | | +| supersetCeleryFlower.readinessProbe.httpGet.port | string | `"flower"` | | +| supersetCeleryFlower.readinessProbe.initialDelaySeconds | int | `5` | | +| supersetCeleryFlower.readinessProbe.periodSeconds | int | `5` | | +| supersetCeleryFlower.readinessProbe.successThreshold | int | `1` | | +| supersetCeleryFlower.readinessProbe.timeoutSeconds | int | `1` | | +| supersetCeleryFlower.replicaCount | int | `1` | | +| supersetCeleryFlower.resources | object | `{}` | Resource settings for the CeleryBeat pods - these settings overwrite might existing values from the global resources object defined above. | +| supersetCeleryFlower.service.annotations | object | `{}` | | +| supersetCeleryFlower.service.nodePort.http | int | `"nil"` | | +| supersetCeleryFlower.service.port | int | `5555` | | +| supersetCeleryFlower.service.type | string | `"ClusterIP"` | | +| supersetCeleryFlower.startupProbe.failureThreshold | int | `60` | | +| supersetCeleryFlower.startupProbe.httpGet.path | string | `"/api/workers"` | | +| supersetCeleryFlower.startupProbe.httpGet.port | string | `"flower"` | | +| supersetCeleryFlower.startupProbe.initialDelaySeconds | int | `5` | | +| supersetCeleryFlower.startupProbe.periodSeconds | int | `5` | | +| supersetCeleryFlower.startupProbe.successThreshold | int | `1` | | +| supersetCeleryFlower.startupProbe.timeoutSeconds | int | `1` | | +| supersetCeleryFlower.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetCeleryFlower deployments | +| supersetNode.affinity | object | `{}` | Affinity to be added to supersetNode deployment | +| supersetNode.command | list | See `values.yaml` | Startup command | +| supersetNode.connections.db_host | string | `"{{ template \"superset.fullname\" . }}-postgresql"` | | +| supersetNode.connections.db_name | string | `"superset"` | | +| supersetNode.connections.db_pass | string | `"superset"` | | +| supersetNode.connections.db_port | string | `"5432"` | | +| supersetNode.connections.db_user | string | `"superset"` | | +| supersetNode.connections.redis_host | string | `"{{ template \"superset.fullname\" . }}-redis-headless"` | Change in case of bringing your own redis and then also set redis.enabled:false | +| supersetNode.connections.redis_port | string | `"6379"` | | +| supersetNode.containerSecurityContext | object | `{}` | | +| supersetNode.deploymentAnnotations | object | `{}` | Annotations to be added to supersetNode deployment | +| supersetNode.deploymentLabels | object | `{}` | Labels to be added to supersetNode deployment | +| supersetNode.env | object | `{}` | | +| supersetNode.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade | +| supersetNode.initContainers | list | a container waiting for postgres | Init containers | +| supersetNode.livenessProbe.failureThreshold | int | `3` | | +| supersetNode.livenessProbe.httpGet.path | string | `"/health"` | | +| supersetNode.livenessProbe.httpGet.port | string | `"http"` | | +| supersetNode.livenessProbe.initialDelaySeconds | int | `15` | | +| supersetNode.livenessProbe.periodSeconds | int | `15` | | +| supersetNode.livenessProbe.successThreshold | int | `1` | | +| supersetNode.livenessProbe.timeoutSeconds | int | `1` | | +| supersetNode.podAnnotations | object | `{}` | Annotations to be added to supersetNode pods | +| supersetNode.podLabels | object | `{}` | Labels to be added to supersetNode pods | +| supersetNode.podSecurityContext | object | `{}` | | +| supersetNode.readinessProbe.failureThreshold | int | `3` | | +| supersetNode.readinessProbe.httpGet.path | string | `"/health"` | | +| supersetNode.readinessProbe.httpGet.port | string | `"http"` | | +| supersetNode.readinessProbe.initialDelaySeconds | int | `15` | | +| supersetNode.readinessProbe.periodSeconds | int | `15` | | +| supersetNode.readinessProbe.successThreshold | int | `1` | | +| supersetNode.readinessProbe.timeoutSeconds | int | `1` | | +| supersetNode.replicaCount | int | `1` | | +| supersetNode.resources | object | `{}` | Resource settings for the supersetNode pods - these settings overwrite might existing values from the global resources object defined above. | +| supersetNode.startupProbe.failureThreshold | int | `60` | | +| supersetNode.startupProbe.httpGet.path | string | `"/health"` | | +| supersetNode.startupProbe.httpGet.port | string | `"http"` | | +| supersetNode.startupProbe.initialDelaySeconds | int | `15` | | +| supersetNode.startupProbe.periodSeconds | int | `5` | | +| supersetNode.startupProbe.successThreshold | int | `1` | | +| supersetNode.startupProbe.timeoutSeconds | int | `1` | | +| supersetNode.strategy | object | `{}` | | +| supersetNode.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetNode deployments | +| supersetWebsockets.affinity | object | `{}` | Affinity to be added to supersetWebsockets deployment | +| supersetWebsockets.command | list | `[]` | | +| supersetWebsockets.config | object | see `values.yaml` | The config.json to pass to the server, see https://github.com/apache/superset/tree/master/superset-websocket Note that the configuration can also read from environment variables (which will have priority), see https://github.com/apache/superset/blob/master/superset-websocket/src/config.ts for a list of supported variables | +| supersetWebsockets.containerSecurityContext | object | `{}` | | +| supersetWebsockets.deploymentAnnotations | object | `{}` | | +| supersetWebsockets.enabled | bool | `false` | This is only required if you intend to use `GLOBAL_ASYNC_QUERIES` in `ws` mode see https://github.com/apache/superset/blob/master/CONTRIBUTING.md#async-chart-queries | +| supersetWebsockets.image.pullPolicy | string | `"IfNotPresent"` | | +| supersetWebsockets.image.repository | string | `"oneacrefund/superset-websocket"` | There is no official image (yet), this one is community-supported | +| supersetWebsockets.image.tag | string | `"latest"` | | +| supersetWebsockets.ingress.path | string | `"/ws"` | | +| supersetWebsockets.ingress.pathType | string | `"Prefix"` | | +| supersetWebsockets.livenessProbe.failureThreshold | int | `3` | | +| supersetWebsockets.livenessProbe.httpGet.path | string | `"/health"` | | +| supersetWebsockets.livenessProbe.httpGet.port | string | `"ws"` | | +| supersetWebsockets.livenessProbe.initialDelaySeconds | int | `5` | | +| supersetWebsockets.livenessProbe.periodSeconds | int | `5` | | +| supersetWebsockets.livenessProbe.successThreshold | int | `1` | | +| supersetWebsockets.livenessProbe.timeoutSeconds | int | `1` | | +| supersetWebsockets.podAnnotations | object | `{}` | | +| supersetWebsockets.podLabels | object | `{}` | | +| supersetWebsockets.podSecurityContext | object | `{}` | | +| supersetWebsockets.readinessProbe.failureThreshold | int | `3` | | +| supersetWebsockets.readinessProbe.httpGet.path | string | `"/health"` | | +| supersetWebsockets.readinessProbe.httpGet.port | string | `"ws"` | | +| supersetWebsockets.readinessProbe.initialDelaySeconds | int | `5` | | +| supersetWebsockets.readinessProbe.periodSeconds | int | `5` | | +| supersetWebsockets.readinessProbe.successThreshold | int | `1` | | +| supersetWebsockets.readinessProbe.timeoutSeconds | int | `1` | | +| supersetWebsockets.replicaCount | int | `1` | | +| supersetWebsockets.resources | object | `{}` | | +| supersetWebsockets.service.annotations | object | `{}` | | +| supersetWebsockets.service.nodePort.http | int | `"nil"` | | +| supersetWebsockets.service.port | int | `8080` | | +| supersetWebsockets.service.type | string | `"ClusterIP"` | | +| supersetWebsockets.startupProbe.failureThreshold | int | `60` | | +| supersetWebsockets.startupProbe.httpGet.path | string | `"/health"` | | +| supersetWebsockets.startupProbe.httpGet.port | string | `"ws"` | | +| supersetWebsockets.startupProbe.initialDelaySeconds | int | `5` | | +| supersetWebsockets.startupProbe.periodSeconds | int | `5` | | +| supersetWebsockets.startupProbe.successThreshold | int | `1` | | +| supersetWebsockets.startupProbe.timeoutSeconds | int | `1` | | +| supersetWebsockets.strategy | object | `{}` | | +| supersetWebsockets.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetWebsockets deployments | +| supersetWorker.command | list | a `celery worker` command | Worker startup command | +| supersetWorker.containerSecurityContext | object | `{}` | | +| supersetWorker.deploymentAnnotations | object | `{}` | Annotations to be added to supersetWorker deployment | +| supersetWorker.deploymentLabels | object | `{}` | Labels to be added to supersetWorker deployment | +| supersetWorker.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade | +| supersetWorker.initContainers | list | a container waiting for postgres and redis | Init container | +| supersetWorker.livenessProbe.exec.command | list | a `celery inspect ping` command | Liveness probe command | +| supersetWorker.livenessProbe.failureThreshold | int | `3` | | +| supersetWorker.livenessProbe.initialDelaySeconds | int | `120` | | +| supersetWorker.livenessProbe.periodSeconds | int | `60` | | +| supersetWorker.livenessProbe.successThreshold | int | `1` | | +| supersetWorker.livenessProbe.timeoutSeconds | int | `60` | | +| supersetWorker.podAnnotations | object | `{}` | Annotations to be added to supersetWorker pods | +| supersetWorker.podLabels | object | `{}` | Labels to be added to supersetWorker pods | +| supersetWorker.podSecurityContext | object | `{}` | | +| supersetWorker.readinessProbe | object | `{}` | No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic) | +| supersetWorker.replicaCount | int | `1` | | +| supersetWorker.resources | object | `{}` | Resource settings for the supersetWorker pods - these settings overwrite might existing values from the global resources object defined above. | +| supersetWorker.startupProbe | object | `{}` | No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic) | +| supersetWorker.strategy | object | `{}` | | +| tolerations | list | `[]` | | +| topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to all deployments | diff --git a/helm/superset/README.md.gotmpl b/helm/superset/README.md.gotmpl new file mode 100644 index 0000000000000..c17a7e31a7372 --- /dev/null +++ b/helm/superset/README.md.gotmpl @@ -0,0 +1,44 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> + +<!-- +NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs#installation +--> + +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.versionBadge" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +{{ template "chart.sourcesSection" . }} + +## TL;DR + +```console +helm repo add superset http://apache.github.io/superset/ +helm install my-superset superset/superset +``` + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} diff --git a/helm/superset/templates/_helpers.tpl b/helm/superset/templates/_helpers.tpl index 593fd0319885d..d551fcf6e82c7 100644 --- a/helm/superset/templates/_helpers.tpl +++ b/helm/superset/templates/_helpers.tpl @@ -83,12 +83,6 @@ SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{env('DB_USER')}:{env('DB_PASS SQLALCHEMY_TRACK_MODIFICATIONS = True SECRET_KEY = env('SECRET_KEY', 'thisISaSECRET_1234') -# Flask-WTF flag for CSRF -WTF_CSRF_ENABLED = True -# Add endpoints that need to be exempt from CSRF protection -WTF_CSRF_EXEMPT_LIST = [] -# A CSRF token that expires in 1 year -WTF_CSRF_TIME_LIMIT = 60 * 60 * 24 * 365 class CeleryConfig(object): CELERY_IMPORTS = ('superset.sql_lab', ) CELERY_ANNOTATIONS = {'tasks.add': {'rate_limit': '10/s'}} diff --git a/helm/superset/templates/configmap-superset.yaml b/helm/superset/templates/configmap-superset.yaml index a7d7b09339a0a..eb8564619b187 100644 --- a/helm/superset/templates/configmap-superset.yaml +++ b/helm/superset/templates/configmap-superset.yaml @@ -24,6 +24,7 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + namespace: {{ .Release.Namespace }} data: {{- range $path, $config := .Values.extraConfigs }} {{ $path }}: | diff --git a/helm/superset/templates/deployment-beat.yaml b/helm/superset/templates/deployment-beat.yaml index 5587dcf343eb3..72de7ab204784 100644 --- a/helm/superset/templates/deployment-beat.yaml +++ b/helm/superset/templates/deployment-beat.yaml @@ -26,8 +26,9 @@ metadata: heritage: {{ .Release.Service }} {{- if .Values.supersetCeleryBeat.deploymentAnnotations }} annotations: - {{ toYaml .Values.supersetCeleryBeat.deploymentAnnotations | nindent 4 }} + {{- toYaml .Values.supersetCeleryBeat.deploymentAnnotations | nindent 4 }} {{- end }} + namespace: {{ .Release.Namespace }} spec: # This must be a singleton replicas: 1 @@ -50,13 +51,13 @@ spec: force-reload: {{ randAlphaNum 5 | quote }} {{ end }} {{- if .Values.supersetCeleryBeat.podAnnotations }} - {{ toYaml .Values.supersetCeleryBeat.podAnnotations | nindent 8 }} + {{- toYaml .Values.supersetCeleryBeat.podAnnotations | nindent 8 }} {{- end }} labels: - app: {{ template "superset.name" . }}-celerybeat + app: "{{ template "superset.name" . }}-celerybeat" release: {{ .Release.Name }} {{- if .Values.supersetCeleryBeat.podLabels }} - {{ toYaml .Values.supersetCeleryBeat.podLabels | nindent 8 }} + {{- toYaml .Values.supersetCeleryBeat.podLabels | nindent 8 }} {{- end }} spec: {{- if or (.Values.serviceAccount.create) (.Values.serviceAccountName) }} @@ -64,17 +65,23 @@ spec: {{- end }} securityContext: runAsUser: {{ .Values.runAsUser }} + {{- if .Values.supersetCeleryBeat.podSecurityContext }} + {{- toYaml .Values.supersetCeleryBeat.podSecurityContext | nindent 8 }} + {{- end }} {{- if .Values.supersetCeleryBeat.initContainers }} initContainers: {{- tpl (toYaml .Values.supersetCeleryBeat.initContainers) . | nindent 6 }} {{- end }} {{- with .Values.hostAliases }} - hostAliases: {{ toYaml . | nindent 6 }} + hostAliases: {{- toYaml . | nindent 6 }} {{- end }} containers: - - name: {{ .Chart.Name }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + - name: "{{ .Chart.Name }}-celerybeat" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.supersetCeleryBeat.containerSecurityContext }} + securityContext: {{- toYaml .Values.supersetCeleryBeat.containerSecurityContext | nindent 12 }} + {{- end }} command: {{ tpl (toJson .Values.supersetCeleryBeat.command) . }} env: - name: "SUPERSET_PORT" @@ -97,35 +104,59 @@ spec: - name: superset-config mountPath: {{ .Values.configMountPath | quote }} readOnly: true + {{- if .Values.extraConfigs }} + - name: superset-extra-config + mountPath: {{ .Values.extraConfigMountPath | quote }} + readOnly: true + {{- end }} {{- with .Values.extraVolumeMounts }} {{- tpl (toYaml .) $ | nindent 12 -}} {{- end }} resources: {{- if .Values.supersetCeleryBeat.resources }} -{{ toYaml .Values.supersetCeleryBeat.resources | indent 12 }} + {{- toYaml .Values.supersetCeleryBeat.resources | nindent 12 }} {{- else }} -{{ toYaml .Values.resources | indent 12 }} + {{- toYaml .Values.resources | nindent 12 }} {{- end }} - {{- with .Values.nodeSelector }} + {{- with .Values.nodeSelector }} nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.affinity .Values.supersetCeleryBeat.affinity }} affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.tolerations }} + {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetCeleryBeat.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.topologySpreadConstraints .Values.supersetCeleryBeat.topologySpreadConstraints }} + topologySpreadConstraints: + {{- with .Values.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetCeleryBeat.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- with .Values.tolerations }} tolerations: -{{ toYaml . | indent 8 }} - {{- end }} -{{- if .Values.imagePullSecrets }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.imagePullSecrets }} imagePullSecrets: -{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- toYaml .Values.imagePullSecrets | nindent 8 }} {{- end }} volumes: - name: superset-config secret: secretName: {{ tpl .Values.configFromSecret . }} + {{- if .Values.extraConfigs }} + - name: superset-extra-config + configMap: + name: {{ template "superset.fullname" . }}-extra-config + {{- end }} {{- with .Values.extraVolumes }} {{- tpl (toYaml .) $ | nindent 8 -}} {{- end }} diff --git a/helm/superset/templates/deployment-flower.yaml b/helm/superset/templates/deployment-flower.yaml new file mode 100644 index 0000000000000..aefdf0f7dec61 --- /dev/null +++ b/helm/superset/templates/deployment-flower.yaml @@ -0,0 +1,157 @@ +{{- if .Values.supersetCeleryFlower.enabled -}} +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "superset.fullname" . }}-flower + labels: + app: {{ template "superset.name" . }}-flower + chart: {{ template "superset.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + {{- if .Values.supersetCeleryFlower.deploymentAnnotations }} + annotations: + {{- toYaml .Values.supersetCeleryFlower.deploymentAnnotations | nindent 4 }} + {{- end }} + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.supersetCeleryFlower.replicaCount }} + selector: + matchLabels: + app: {{ template "superset.name" . }}-flower + release: {{ .Release.Name }} + template: + metadata: + annotations: + checksum/config: {{ include "superset-config" . | sha256sum }} + checksum/secrets: {{ tpl (toJson .Values.extraSecretEnv) . | sha256sum }} + {{- if .Values.supersetCeleryFlower.podAnnotations }} + {{- toYaml .Values.supersetCeleryFlower.podAnnotations | nindent 8 }} + {{- end }} + labels: + app: "{{ template "superset.name" . }}-flower" + release: {{ .Release.Name }} + {{- if .Values.supersetCeleryFlower.podLabels }} + {{- toYaml .Values.supersetCeleryFlower.podLabels | nindent 8 }} + {{- end }} + spec: + {{- if or (.Values.serviceAccount.create) (.Values.serviceAccountName) }} + serviceAccountName: {{ template "superset.serviceAccountName" . }} + {{- end }} + securityContext: + runAsUser: {{ .Values.runAsUser }} + {{- if .Values.supersetCeleryFlower.podSecurityContext }} + {{- toYaml .Values.supersetCeleryFlower.podSecurityContext | nindent 8 }} + {{- end }} + {{- if .Values.supersetCeleryFlower.initContainers }} + initContainers: + {{- tpl (toYaml .Values.supersetCeleryFlower.initContainers) . | nindent 6 }} + {{- end }} + {{- with .Values.hostAliases }} + hostAliases: {{- toYaml . | nindent 6 }} + {{- end }} + containers: + - name: "{{ .Chart.Name }}-flower" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.supersetCeleryFlower.containerSecurityContext }} + securityContext: {{- toYaml .Values.supersetCeleryFlower.containerSecurityContext | nindent 12 }} + {{- end }} + command: {{ tpl (toJson .Values.supersetCeleryFlower.command) . }} + env: + {{- range $key, $value := .Values.extraEnv }} + - name: {{ $key | quote}} + value: {{ $value | quote }} + {{- end }} + {{- if .Values.extraEnvRaw }} + {{- toYaml .Values.extraEnvRaw | nindent 12 }} + {{- end }} + envFrom: + - secretRef: + name: {{ tpl .Values.envFromSecret . | quote }} + {{- range .Values.envFromSecrets }} + - secretRef: + name: {{ tpl . $ | quote }} + {{- end }} + ports: + - name: flower + containerPort: 5555 + protocol: TCP + volumeMounts: + - name: superset-config + mountPath: {{ .Values.configMountPath | quote }} + readOnly: true + {{- with .Values.extraVolumeMounts }} + {{- tpl (toYaml .) $ | nindent 12 -}} + {{- end }} + {{- if .Values.supersetCeleryFlower.startupProbe }} + startupProbe: + {{- .Values.supersetCeleryFlower.startupProbe | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.supersetCeleryFlower.readinessProbe }} + readinessProbe: + {{- .Values.supersetCeleryFlower.readinessProbe | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.supersetCeleryFlower.livenessProbe }} + livenessProbe: + {{- .Values.supersetCeleryFlower.livenessProbe | toYaml | nindent 12 }} + {{- end }} + resources: + {{- if .Values.supersetCeleryFlower.resources }} + {{- toYaml .Values.supersetCeleryFlower.resources | nindent 12 }} + {{- else }} + {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.affinity .Values.supersetCeleryFlower.affinity }} + affinity: + {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetCeleryFlower.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.topologySpreadConstraints .Values.supersetCeleryFlower.topologySpreadConstraints }} + topologySpreadConstraints: + {{- with .Values.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetCeleryFlower.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml .Values.imagePullSecrets | nindent 8 }} + {{- end }} + volumes: + - name: superset-config + secret: + secretName: {{ tpl .Values.configFromSecret . }} + {{- with .Values.extraVolumes }} + {{- tpl (toYaml .) $ | nindent 8 -}} + {{- end }} +{{- end -}} diff --git a/helm/superset/templates/deployment-worker.yaml b/helm/superset/templates/deployment-worker.yaml index 54eb5d87517e4..2098064b00baa 100644 --- a/helm/superset/templates/deployment-worker.yaml +++ b/helm/superset/templates/deployment-worker.yaml @@ -23,16 +23,24 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} +{{- if .Values.supersetWorker.deploymentLabels }} + {{- toYaml .Values.supersetWorker.deploymentLabels | nindent 4 }} +{{- end }} {{- if .Values.supersetWorker.deploymentAnnotations }} annotations: - {{ toYaml .Values.supersetWorker.deploymentAnnotations | nindent 4 }} + {{- toYaml .Values.supersetWorker.deploymentAnnotations | nindent 4 }} {{- end }} + namespace: {{ .Release.Namespace }} spec: - replicas: {{ .Values.replicaCount }} + replicas: {{ .Values.supersetWorker.replicaCount }} selector: matchLabels: app: {{ template "superset.name" . }}-worker release: {{ .Release.Name }} + {{- if .Values.supersetWorker.strategy }} + strategy: + {{- toYaml .Values.supersetWorker.strategy | nindent 4 }} + {{- end }} template: metadata: annotations: @@ -48,13 +56,13 @@ spec: force-reload: {{ randAlphaNum 5 | quote }} {{ end }} {{- if .Values.supersetWorker.podAnnotations }} - {{ toYaml .Values.supersetWorker.podAnnotations | nindent 8 }} + {{- toYaml .Values.supersetWorker.podAnnotations | nindent 8 }} {{- end }} labels: app: {{ template "superset.name" . }}-worker release: {{ .Release.Name }} {{- if .Values.supersetWorker.podLabels }} - {{ toYaml .Values.supersetWorker.podLabels | nindent 8 }} + {{- toYaml .Values.supersetWorker.podLabels | nindent 8 }} {{- end }} spec: {{- if or (.Values.serviceAccount.create) (.Values.serviceAccountName) }} @@ -62,17 +70,23 @@ spec: {{- end }} securityContext: runAsUser: {{ .Values.runAsUser }} + {{- if .Values.supersetWorker.podSecurityContext }} + {{- toYaml .Values.supersetWorker.podSecurityContext | nindent 8 }} + {{- end }} {{- if .Values.supersetWorker.initContainers }} initContainers: {{- tpl (toYaml .Values.supersetWorker.initContainers) . | nindent 6 }} {{- end }} {{- with .Values.hostAliases }} - hostAliases: {{ toYaml . | nindent 6 }} + hostAliases: {{- toYaml . | nindent 6 }} {{- end }} containers: - name: {{ .Chart.Name }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.supersetWorker.containerSecurityContext }} + securityContext: {{- toYaml .Values.supersetWorker.containerSecurityContext | nindent 12 }} + {{- end }} command: {{ tpl (toJson .Values.supersetWorker.command) . }} env: - name: "SUPERSET_PORT" @@ -95,35 +109,71 @@ spec: - name: superset-config mountPath: {{ .Values.configMountPath | quote }} readOnly: true + {{- if .Values.extraConfigs }} + - name: superset-extra-config + mountPath: {{ .Values.extraConfigMountPath | quote }} + readOnly: true + {{- end }} {{- with .Values.extraVolumeMounts }} {{- tpl (toYaml .) $ | nindent 12 -}} {{- end }} + {{- if .Values.supersetWorker.startupProbe }} + startupProbe: + {{- .Values.supersetWorker.startupProbe | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.supersetWorker.readinessProbe }} + readinessProbe: + {{- .Values.supersetWorker.readinessProbe | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.supersetWorker.livenessProbe }} + livenessProbe: + {{- .Values.supersetWorker.livenessProbe | toYaml | nindent 12 }} + {{- end }} resources: {{- if .Values.supersetWorker.resources }} -{{ toYaml .Values.supersetWorker.resources | indent 12 }} + {{- toYaml .Values.supersetWorker.resources | nindent 12 }} {{- else }} -{{ toYaml .Values.resources | indent 12 }} + {{- toYaml .Values.resources | nindent 12 }} {{- end }} - {{- with .Values.nodeSelector }} + {{- with .Values.nodeSelector }} nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.affinity .Values.supersetWorker.affinity }} affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.tolerations }} + {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetWorker.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.topologySpreadConstraints .Values.supersetWorker.topologySpreadConstraints }} + topologySpreadConstraints: + {{- with .Values.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetWorker.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- with .Values.tolerations }} tolerations: -{{ toYaml . | indent 8 }} - {{- end }} -{{- if .Values.imagePullSecrets }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.imagePullSecrets }} imagePullSecrets: -{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- toYaml .Values.imagePullSecrets | nindent 8 }} {{- end }} volumes: - name: superset-config secret: secretName: {{ tpl .Values.configFromSecret . }} - {{- with .Values.extraVolumes }} - {{- tpl (toYaml .) $ | nindent 8 -}} - {{- end }} + {{- if .Values.extraConfigs }} + - name: superset-extra-config + configMap: + name: {{ template "superset.fullname" . }}-extra-config + {{- end }} + {{- with .Values.extraVolumes }} + {{- tpl (toYaml .) $ | nindent 8 -}} + {{- end }} diff --git a/helm/superset/templates/deployment-ws.yaml b/helm/superset/templates/deployment-ws.yaml new file mode 100644 index 0000000000000..0bbc822ef9150 --- /dev/null +++ b/helm/superset/templates/deployment-ws.yaml @@ -0,0 +1,153 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.supersetWebsockets.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "superset.fullname" . }}-ws" + labels: + app: "{{ template "superset.name" . }}-ws" + chart: {{ template "superset.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.supersetWebsockets.deploymentAnnotations }} + annotations: + {{- toYaml .Values.supersetWebsockets.deploymentAnnotations | nindent 4 }} +{{- end }} + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.supersetWebsockets.replicaCount }} + selector: + matchLabels: + app: "{{ template "superset.name" . }}-ws" + release: {{ .Release.Name }} + {{- if .Values.supersetWebsockets.strategy }} + strategy: + {{- toYaml .Values.supersetWebsockets.strategy | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + checksum/wsconfig: {{ tpl (toJson .Values.supersetWebsockets.config) . | sha256sum }} + checksum/secrets: {{ tpl (toJson .Values.extraSecretEnv) . | sha256sum }} + {{- if .Values.supersetWebsockets.podAnnotations }} + {{- toYaml .Values.supersetWebsockets.podAnnotations | nindent 8 }} + {{- end }} + labels: + app: "{{ template "superset.name" . }}-ws" + release: {{ .Release.Name }} + {{- if .Values.supersetWebsockets.podLabels }} + {{- toYaml .Values.supersetWebsockets.podLabels | nindent 8 }} + {{- end }} + spec: + {{- if or (.Values.serviceAccount.create) (.Values.serviceAccountName) }} + serviceAccountName: {{ template "superset.serviceAccountName" . }} + {{- end }} + securityContext: + runAsUser: {{ .Values.runAsUser }} + {{- if .Values.supersetWebsockets.podSecurityContext }} + {{- toYaml .Values.supersetWebsockets.podSecurityContext | nindent 8 }} + {{- end }} + {{- with .Values.hostAliases }} + hostAliases: {{- toYaml . | nindent 6 }} + {{- end }} + containers: + - name: "{{ .Chart.Name }}-ws" + image: "{{ .Values.supersetWebsockets.image.repository }}:{{ .Values.supersetWebsockets.image.tag }}" + imagePullPolicy: {{ .Values.supersetWebsockets.image.pullPolicy }} + {{- if .Values.supersetWebsockets.containerSecurityContext }} + securityContext: {{- toYaml .Values.supersetWebsockets.containerSecurityContext | nindent 12 }} + {{- end }} + command: {{ tpl (toJson .Values.supersetWebsockets.command) . }} + # Passing all the envs is a bit blunt... we only need a few (see https://github.com/apache/superset/blob/master/superset-websocket/src/config.ts)... + env: + {{- range $key, $value := .Values.extraEnv }} + - name: {{ $key | quote}} + value: {{ $value | quote }} + {{- end }} + {{- if .Values.extraEnvRaw }} + {{- toYaml .Values.extraEnvRaw | nindent 12 }} + {{- end }} + envFrom: + - secretRef: + name: {{ tpl .Values.envFromSecret . | quote }} + {{- range .Values.envFromSecrets }} + - secretRef: + name: {{ tpl . $ | quote }} + {{- end }} + ports: + - name: ws + containerPort: {{ .Values.supersetWebsockets.config.port }} + protocol: TCP + volumeMounts: + - name: superset-ws-config + mountPath: /home/superset-websocket/config.json + subPath: config.json + readOnly: true + resources: + {{- if .Values.supersetWebsockets.resources }} + {{- toYaml .Values.supersetWebsockets.resources | nindent 12 }} + {{- else }} + {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + {{- if .Values.supersetWebsockets.startupProbe }} + startupProbe: + {{- .Values.supersetWebsockets.startupProbe | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.supersetWebsockets.readinessProbe }} + readinessProbe: + {{- .Values.supersetWebsockets.readinessProbe | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.supersetWebsockets.livenessProbe }} + livenessProbe: + {{- .Values.supersetWebsockets.livenessProbe | toYaml | nindent 12 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.affinity .Values.supersetWebsockets.affinity }} + affinity: + {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetWebsockets.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.topologySpreadConstraints .Values.supersetWebsockets.topologySpreadConstraints }} + topologySpreadConstraints: + {{- with .Values.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetWebsockets.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml .Values.imagePullSecrets | nindent 8 }} + {{- end }} + volumes: + - name: superset-ws-config + secret: + secretName: "{{ template "superset.fullname" . }}-ws-config" +{{- end }} diff --git a/helm/superset/templates/deployment.yaml b/helm/superset/templates/deployment.yaml index 4d3a42e8e20a7..6b2a3933ea354 100644 --- a/helm/superset/templates/deployment.yaml +++ b/helm/superset/templates/deployment.yaml @@ -23,12 +23,20 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} +{{- if .Values.supersetNode.deploymentLabels }} + {{- toYaml .Values.supersetNode.deploymentLabels | nindent 4 }} +{{- end }} {{- if .Values.supersetNode.deploymentAnnotations }} annotations: - {{ toYaml .Values.supersetNode.deploymentAnnotations | nindent 4 }} + {{- toYaml .Values.supersetNode.deploymentAnnotations | nindent 4 }} {{- end }} + namespace: {{ .Release.Namespace }} spec: - replicas: {{ .Values.replicaCount }} + replicas: {{ .Values.supersetNode.replicaCount }} + {{- if .Values.supersetNode.strategy }} + strategy: + {{- toYaml .Values.supersetNode.strategy | nindent 4 }} + {{- end }} selector: matchLabels: app: {{ template "superset.name" . }} @@ -51,13 +59,13 @@ spec: force-reload: {{ randAlphaNum 5 | quote }} {{- end }} {{- if .Values.supersetNode.podAnnotations }} - {{ toYaml .Values.supersetNode.podAnnotations | nindent 8 }} + {{- toYaml .Values.supersetNode.podAnnotations | nindent 8 }} {{- end }} labels: app: {{ template "superset.name" . }} release: {{ .Release.Name }} {{- if .Values.supersetNode.podLabels }} - {{ toYaml .Values.supersetNode.podLabels | nindent 8 }} + {{- toYaml .Values.supersetNode.podLabels | nindent 8 }} {{- end }} spec: {{- if or (.Values.serviceAccount.create) (.Values.serviceAccountName) }} @@ -65,17 +73,23 @@ spec: {{- end }} securityContext: runAsUser: {{ .Values.runAsUser }} + {{- if .Values.supersetNode.podSecurityContext }} + {{- toYaml .Values.supersetNode.podSecurityContext | nindent 8 }} + {{- end }} {{- if .Values.supersetNode.initContainers }} initContainers: {{- tpl (toYaml .Values.supersetNode.initContainers) . | nindent 6 }} {{- end }} {{- with .Values.hostAliases }} - hostAliases: {{ toYaml . | nindent 6 }} + hostAliases: {{- toYaml . | nindent 6 }} {{- end }} containers: - name: {{ .Chart.Name }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.supersetNode.containerSecurityContext }} + securityContext: {{- toYaml .Values.supersetNode.containerSecurityContext | nindent 12 }} + {{- end }} command: {{ tpl (toJson .Values.supersetNode.command) . }} env: - name: "SUPERSET_PORT" @@ -114,27 +128,53 @@ spec: - name: http containerPort: {{ .Values.service.port }} protocol: TCP + {{- if .Values.supersetNode.startupProbe }} + startupProbe: + {{- .Values.supersetNode.startupProbe | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.supersetNode.readinessProbe }} + readinessProbe: + {{- .Values.supersetNode.readinessProbe | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.supersetNode.livenessProbe }} + livenessProbe: + {{- .Values.supersetNode.livenessProbe | toYaml | nindent 12 }} + {{- end }} resources: {{- if .Values.supersetNode.resources }} -{{ toYaml .Values.supersetNode.resources | indent 12 }} + {{- toYaml .Values.supersetNode.resources | nindent 12 }} {{- else }} -{{ toYaml .Values.resources | indent 12 }} + {{- toYaml .Values.resources | nindent 12 }} {{- end }} - {{- with .Values.nodeSelector }} + {{- with .Values.nodeSelector }} nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.affinity .Values.supersetNode.affinity }} affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.tolerations }} + {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetNode.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.topologySpreadConstraints .Values.supersetNode.topologySpreadConstraints }} + topologySpreadConstraints: + {{- with .Values.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetNode.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- with .Values.tolerations }} tolerations: -{{ toYaml . | indent 8 }} - {{- end }} -{{- if .Values.imagePullSecrets }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.imagePullSecrets }} imagePullSecrets: -{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- toYaml .Values.imagePullSecrets | nindent 8 }} {{- end }} volumes: diff --git a/helm/superset/templates/ingress.yaml b/helm/superset/templates/ingress.yaml index 2a151ccc2e3e9..d166149c00ba1 100644 --- a/helm/superset/templates/ingress.yaml +++ b/helm/superset/templates/ingress.yaml @@ -25,10 +25,11 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} -{{- with .Values.ingress.annotations }} + {{- with .Values.ingress.annotations }} annotations: -{{ toYaml . | indent 4 }} -{{- end }} + {{- toYaml . | nindent 4 }} + {{- end }} + namespace: {{ .Release.Namespace }} spec: {{- if .Values.ingress.ingressClassName }} ingressClassName: {{ .Values.ingress.ingressClassName }} @@ -55,5 +56,14 @@ spec: name: {{ $fullName }} port: name: http + {{- if $.Values.supersetWebsockets.enabled }} + - path: {{ $.Values.supersetWebsockets.ingress.path }} + pathType: {{ $.Values.supersetWebsockets.ingress.pathType }} + backend: + service: + name: "{{ template "superset.fullname" $ }}-ws" + port: + name: ws + {{- end }} {{- end }} {{- end }} diff --git a/helm/superset/templates/init-job.yaml b/helm/superset/templates/init-job.yaml index 483ced8d3702b..8555253881ab0 100644 --- a/helm/superset/templates/init-job.yaml +++ b/helm/superset/templates/init-job.yaml @@ -22,13 +22,14 @@ metadata: annotations: "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": "before-hook-creation" + namespace: {{ .Release.Namespace }} spec: template: metadata: name: {{ template "superset.name" . }}-init-db {{- if .Values.init.podAnnotations }} annotations: - {{ toYaml .Values.init.podAnnotations | nindent 8 }} + {{- toYaml .Values.init.podAnnotations | nindent 8 }} {{- end }} spec: {{- if or (.Values.serviceAccount.create) (.Values.serviceAccountName) }} @@ -36,13 +37,16 @@ spec: {{- end }} securityContext: runAsUser: {{ .Values.runAsUser }} + {{- if .Values.init.podSecurityContext }} + {{- toYaml .Values.init.podSecurityContext | nindent 8 }} + {{- end }} {{- if .Values.init.initContainers }} initContainers: {{- tpl (toYaml .Values.init.initContainers) . | nindent 6 }} {{- end }} containers: - name: {{ template "superset.name" . }}-init-db - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" {{- if or .Values.extraEnv .Values.extraEnvRaw }} env: {{- range $key, $value := .Values.extraEnv }} @@ -61,6 +65,9 @@ spec: name: {{ tpl . $ }} {{- end }} imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.init.containerSecurityContext }} + securityContext: {{- toYaml .Values.init.containerSecurityContext | nindent 12 }} + {{- end }} volumeMounts: - name: superset-config mountPath: {{ .Values.configMountPath | quote }} @@ -75,10 +82,10 @@ spec: {{- end }} command: {{ tpl (toJson .Values.init.command) . }} resources: -{{ toYaml .Values.init.resources | indent 10 }} -{{- if .Values.imagePullSecrets }} + {{- toYaml .Values.init.resources | nindent 10 }} + {{- if .Values.imagePullSecrets }} imagePullSecrets: -{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- toYaml .Values.imagePullSecrets | nindent 8 }} {{- end }} volumes: - name: superset-config diff --git a/helm/superset/templates/secret-env.yaml b/helm/superset/templates/secret-env.yaml index 4126507324439..0164d96a8c129 100644 --- a/helm/superset/templates/secret-env.yaml +++ b/helm/superset/templates/secret-env.yaml @@ -23,6 +23,7 @@ metadata: chart: {{ template "superset.chart" . }} release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" + namespace: {{ .Release.Namespace }} type: Opaque stringData: REDIS_HOST: {{ tpl .Values.supersetNode.connections.redis_host . | quote }} diff --git a/helm/superset/templates/secret-superset-config.yaml b/helm/superset/templates/secret-superset-config.yaml index ddf0befcd2f2b..c1f4102858d93 100644 --- a/helm/superset/templates/secret-superset-config.yaml +++ b/helm/superset/templates/secret-superset-config.yaml @@ -23,6 +23,7 @@ metadata: chart: {{ template "superset.chart" . }} release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" + namespace: {{ .Release.Namespace }} type: Opaque stringData: superset_config.py: | diff --git a/helm/superset/templates/secret-ws.yaml b/helm/superset/templates/secret-ws.yaml new file mode 100644 index 0000000000000..c3ac55d96cb07 --- /dev/null +++ b/helm/superset/templates/secret-ws.yaml @@ -0,0 +1,32 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.supersetWebsockets.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "superset.fullname" . }}-ws-config" + labels: + app: {{ template "superset.fullname" . }} + chart: {{ template "superset.chart" . }} + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + namespace: {{ .Release.Namespace }} +type: Opaque +stringData: + config.json: | + {{- tpl (toJson .Values.supersetWebsockets.config) . | nindent 6 }} +{{- end }} diff --git a/helm/superset/templates/service-account.yaml b/helm/superset/templates/service-account.yaml index 680b137370199..994ad8333afd8 100755 --- a/helm/superset/templates/service-account.yaml +++ b/helm/superset/templates/service-account.yaml @@ -28,4 +28,8 @@ metadata: kubernetes.io/cluster-service: "true" {{- end }} addonmanager.kubernetes.io/mode: Reconcile + {{- if .Values.serviceAccount.annotations }} + annotations: {{- toYaml .Values.serviceAccount.annotations | nindent 4 }} + {{- end }} + namespace: {{ .Release.Namespace }} {{- end -}} diff --git a/helm/superset/templates/service.yaml b/helm/superset/templates/service.yaml index 0124ad2a9d04a..97db594a23958 100644 --- a/helm/superset/templates/service.yaml +++ b/helm/superset/templates/service.yaml @@ -27,6 +27,7 @@ metadata: annotations: {{- toYaml . | nindent 4 }} {{- end }} + namespace: {{ .Release.Namespace }} spec: type: {{ .Values.service.type }} ports: @@ -34,9 +35,78 @@ spec: targetPort: http protocol: TCP name: http + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePort.http)) }} + nodePort: {{ .Values.service.nodePort.http }} + {{- end }} selector: app: {{ template "superset.name" . }} release: {{ .Release.Name }} {{- if .Values.service.loadBalancerIP }} loadBalancerIP: {{ .Values.service.loadBalancerIP }} {{- end }} +--- +{{- if .Values.supersetCeleryFlower.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "superset.fullname" . }}-flower" + labels: + app: {{ template "superset.name" . }} + chart: {{ template "superset.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + {{- with .Values.supersetCeleryFlower.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + namespace: {{ .Release.Namespace }} +spec: + type: {{ .Values.supersetCeleryFlower.service.type }} + ports: + - port: {{ .Values.supersetCeleryFlower.service.port }} + targetPort: flower + protocol: TCP + name: flower + {{- if and (or (eq .Values.supersetCeleryFlower.service.type "NodePort") (eq .Values.supersetCeleryFlower.service.type "LoadBalancer")) (not (empty .Values.supersetCeleryFlower.service.nodePort.http)) }} + nodePort: {{ .Values.supersetCeleryFlower.service.nodePort.http }} + {{- end }} + selector: + app: {{ template "superset.name" . }}-flower + release: {{ .Release.Name }} + {{- if .Values.supersetCeleryFlower.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.supersetCeleryFlower.service.loadBalancerIP }} + {{- end }} +{{- end }} +--- +{{- if .Values.supersetWebsockets.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "superset.fullname" . }}-ws" + labels: + app: {{ template "superset.name" . }} + chart: {{ template "superset.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + {{- with .Values.supersetWebsockets.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + namespace: {{ .Release.Namespace }} +spec: + type: {{ .Values.supersetWebsockets.service.type }} + ports: + - port: {{ .Values.supersetWebsockets.service.port }} + targetPort: ws + protocol: TCP + name: ws + {{- if and (or (eq .Values.supersetWebsockets.service.type "NodePort") (eq .Values.supersetWebsockets.service.type "LoadBalancer")) (not (empty .Values.supersetWebsockets.service.nodePort.http)) }} + nodePort: {{ .Values.supersetWebsockets.service.nodePort.http }} + {{- end }} + selector: + app: "{{ template "superset.name" . }}-ws" + release: {{ .Release.Name }} + {{- if .Values.supersetWebsockets.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.supersetWebsockets.service.loadBalancerIP }} + {{- end }} +{{- end }} diff --git a/helm/superset/values.schema.json b/helm/superset/values.schema.json deleted file mode 100644 index 6c4359a0ff940..0000000000000 --- a/helm/superset/values.schema.json +++ /dev/null @@ -1,607 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "additionalProperties": true, - "properties": { - "replicaCount": { - "type": "integer" - }, - "runAsUser": { - "type": "integer" - }, - "serviceAccount": { - "type": "object", - "additionalProperties": false, - "properties": { - "create": { - "type": "boolean" - } - }, - "required": [ - "create" - ] - }, - "bootstrapScript": { - "type": "string" - }, - "configFromSecret": { - "type": "string" - }, - "envFromSecret": { - "type": "string" - }, - "envFromSecrets": { - "type": "array" - }, - "extraEnv": { - "type": "object" - }, - "extraEnvRaw": { - "type": "array" - }, - "extraSecretEnv": { - "type": "object" - }, - "extraConfigs": { - "type": "object" - }, - "extraSecrets": { - "type": "object" - }, - "extraVolumes": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.apps.v1.PodSpec/properties/volumes" - }, - "extraVolumeMounts": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.apps.v1.PodSpec/properties/volumeMounts" - }, - "configOverrides": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "properties": { - "extend_timeout": { - "type": "string" - }, - "enable_oauth": { - "type": "string" - } - } - }, - "configOverridesFiles": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "properties": { - "extend_timeout": { - "type": "string" - }, - "enable_oauth": { - "type": "string" - } - } - }, - "configMountPath": { - "type": "string" - }, - "extraConfigMountPath": { - "type": "string" - }, - "image": { - "type": "object", - "additionalProperties": false, - "properties": { - "repository": { - "type": "string" - }, - "tag": { - "type": "string" - }, - "pullPolicy": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.Container/properties/imagePullPolicy" - } - }, - "required": [ - "repository", - "tag", - "pullPolicy" - ] - }, - "imagePullSecrets": { - "type": "array" - }, - "initImage": { - "type": "object", - "additionalProperties": false, - "properties": { - "repository": { - "type": "string" - }, - "tag": { - "type": "string" - }, - "pullPolicy": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.Container/properties/imagePullPolicy" - } - }, - "required": [ - "repository", - "tag", - "pullPolicy" - ] - }, - "service": { - "type": "object", - "additionalProperties": false, - "properties": { - "type": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.ServiceSpec/properties/type" - }, - "port": { - "type": "integer" - }, - "annotations": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" - }, - "loadBalancerIP": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.ServiceSpec/properties/loadBalancerIP" - } - }, - "required": [ - "type", - "port" - ] - }, - "ingress": { - "type": "object", - "additionalProperties": false, - "properties": { - "enabled": { - "type": "boolean" - }, - "annotations": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" - }, - "path": { - "type": "string" - }, - "pathType": { - "type": "string" - }, - "ingressClassName": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.networking.v1.IngressSpec/properties/ingressClassName" - }, - "hosts": { - "type": "array", - "items": { - "type": "string" - } - }, - "tls": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": false, - "properties": { - "secretName": { - "type": "string" - }, - "hosts": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - }, - "required": [ - "enabled", - "annotations", - "path", - "pathType", - "hosts", - "tls" - ] - }, - "resources": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.Container/properties/resources" - }, - "hostAliases": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.PodSpec/properties/hostAliases" - }, - "supersetNode": { - "type": "object", - "additionalProperties": false, - "properties": { - "command": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.Container/properties/command" - }, - "connections": { - "type": "object", - "additionalProperties": false, - "properties": { - "redis_host": { - "type": "string" - }, - "redis_password": { - "type": "string" - }, - "redis_port": { - "type": "string" - }, - "db_host": { - "type": "string" - }, - "db_port": { - "type": "string" - }, - "db_user": { - "type": "string" - }, - "db_pass": { - "type": "string" - }, - "db_name": { - "type": "string" - } - }, - "required": [ - "redis_host", - "redis_port", - "db_host", - "db_port", - "db_user", - "db_pass", - "db_name" - ] - }, - "env": { - "type": "object" - }, - "forceReload": { - "type": "boolean" - }, - "initContainers": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.PodSpec/properties/initContainers" - }, - "deploymentAnnotations": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" - }, - "podAnnotations": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" - }, - "podLabels": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/labels" - }, - "resources": { - "type": "object" - } - }, - "required": [ - "command", - "connections", - "env", - "forceReload" - ] - }, - "supersetWorker": { - "type": "object", - "additionalProperties": false, - "properties": { - "command": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.Container/properties/command" - }, - "forceReload": { - "type": "boolean" - }, - "initContainers": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.PodSpec/properties/initContainers" - }, - "deploymentAnnotations": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" - }, - "podAnnotations": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" - }, - "podLabels": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/labels" - }, - "resources": { - "type": "object" - } - }, - "required": [ - "command", - "forceReload" - ] - }, - "supersetCeleryBeat": { - "type": "object", - "additionalProperties": false, - "properties": { - "enabled": { - "type": "boolean" - }, - "command": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.Container/properties/command" - }, - "forceReload": { - "type": "boolean" - }, - "initContainers": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.PodSpec/properties/initContainers" - }, - "deploymentAnnotations": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" - }, - "podAnnotations": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" - }, - "podLabels": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/labels" - }, - "resources": { - "type": "object" - } - }, - "required": [ - "enabled", - "command", - "forceReload" - ] - }, - "init": { - "type": "object", - "additionalProperties": false, - "properties": { - "resources": { - "type": "object" - }, - "command": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.Container/properties/command" - }, - "enabled": { - "type": "boolean" - }, - "loadExamples": { - "type": "boolean" - }, - "createAdmin": { - "type": "boolean" - }, - "adminUser": { - "type": "object", - "additionalProperties": false, - "properties": { - "username": { - "type": "string" - }, - "firstname": { - "type": "string" - }, - "lastname": { - "type": "string" - }, - "email": { - "type": "string" - }, - "password": { - "type": "string" - } - }, - "required": [ - "username", - "firstname", - "lastname", - "email", - "password" - ] - }, - "initContainers": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.core.v1.PodSpec/properties/initContainers" - }, - "initscript": { - "type": "string" - }, - "podAnnotations": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" - } - }, - "required": [ - "resources", - "command", - "enabled", - "loadExamples", - "createAdmin", - "adminUser", - "initscript" - ] - }, - "postgresql": { - "type": "object", - "properties": { - "auth": { - "type": "object", - "properties": { - "database": { - "type": "string" - }, - "existingSecret": { - "type": [ - "string", - "null" - ] - }, - "password": { - "type": "string" - }, - "username": { - "type": "string" - } - } - }, - "enabled": { - "type": "boolean" - }, - "primary": { - "type": "object", - "properties": { - "persistence": { - "type": "object", - "properties": { - "accessModes": { - "type": "array", - "items": { - "type": "string" - } - }, - "enabled": { - "type": "boolean" - } - } - }, - "service": { - "type": "object", - "properties": { - "ports": { - "type": "object", - "properties": { - "postgresql": { - "type": "string" - } - } - } - } - } - } - } - } - }, - "redis": { - "type": "object", - "additionalProperties": true, - "properties": { - "enabled": { - "type": "boolean" - }, - "architecture": { - "type": "string" - }, - "auth": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - }, - "existingSecret": { - "type": "string" - }, - "existingSecretKey": { - "type": "string" - }, - "password": { - "type": "string" - } - }, - "required": [ - "enabled" - ] - }, - "master": { - "type": "object", - "additionalProperties": true, - "properties": { - "persistence": { - "type": "object", - "additionalProperties": true, - "properties": { - "enabled": { - "type": "boolean" - }, - "accessModes": { - "type": "array", - "items": [ - { - "type": "string" - } - ] - } - }, - "required": [ - "enabled", - "accessModes" - ] - } - }, - "required": [ - "persistence" - ] - }, - "cluster": { - "type": "object", - "additionalProperties": true, - "properties": { - "enabled": { - "type": "boolean" - } - }, - "required": [ - "enabled" - ] - } - }, - "required": [ - "enabled", - "architecture", - "master" - ] - }, - "nodeSelector": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.apps.v1.PodSpec/properties/nodeSelector" - }, - "tolerations": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json##/definitions/io.k8s.api.apps.v1.PodSpec/properties/tolerations" - }, - "affinity": { - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.23.0/_definitions.json#/definitions/io.k8s.api.core.v1.Affinity" - } - }, - "required": [ - "replicaCount", - "runAsUser", - "serviceAccount", - "bootstrapScript", - "configFromSecret", - "envFromSecret", - "envFromSecrets", - "extraEnv", - "extraEnvRaw", - "extraSecretEnv", - "extraConfigs", - "extraSecrets", - "extraVolumes", - "extraVolumeMounts", - "configOverrides", - "configOverridesFiles", - "configMountPath", - "extraConfigMountPath", - "image", - "imagePullSecrets", - "service", - "ingress", - "resources", - "hostAliases", - "supersetNode", - "supersetWorker", - "supersetCeleryBeat", - "init", - "postgresql", - "redis", - "nodeSelector", - "tolerations", - "affinity" - ] -} diff --git a/helm/superset/values.yaml b/helm/superset/values.yaml index 197ec4b3c6e70..a212754e39162 100644 --- a/helm/superset/values.yaml +++ b/helm/superset/values.yaml @@ -19,19 +19,22 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -replicaCount: 1 +# A README is automatically generated from this file to document it, using helm-docs (see https://github.com/norwoodj/helm-docs) +# To update it, install helm-docs and run helm-docs from the root of this chart -# User ID directive. This user must have enough permissions to run the bootstrap script -# Runn containers as root is not recommended in production. Change this to another UID - e.g. 1000 to be more secure +# -- User ID directive. This user must have enough permissions to run the bootstrap script +# Running containers as root is not recommended in production. Change this to another UID - e.g. 1000 to be more secure runAsUser: 0 -# Create custom service account for Superset. If create: true and name is not provided, superset.fullname will be used. # serviceAccountName: superset serviceAccount: + # -- Create custom service account for Superset. If create: true and name is not provided, `superset.fullname` will be used. create: false + annotations: {} -# Install additional packages and do any other bootstrap configuration in this script +# -- Install additional packages and do any other bootstrap configuration in this script # For production clusters it's recommended to build own image with this step done in CI +# @default -- see `values.yaml` bootstrapScript: | #!/bin/bash rm -rf /var/lib/apt/lists/* && \ @@ -40,33 +43,43 @@ bootstrapScript: | redis==3.5.3 && \ if [ ! -f ~/bootstrap ]; then echo "Running Superset with uid {{ .Values.runAsUser }}" > ~/bootstrap; fi -## The name of the secret which we will use to generate a superset_config.py file -## Note: this secret must have the key superset_config.py in it and can include other files as well -## +# -- The name of the secret which we will use to generate a superset_config.py file +# Note: this secret must have the key superset_config.py in it and can include other files as well configFromSecret: '{{ template "superset.fullname" . }}-config' -## The name of the secret which we will use to populate env vars in deployed pods -## This can be useful for secret keys, etc. -## +# -- The name of the secret which we will use to populate env vars in deployed pods +# This can be useful for secret keys, etc. envFromSecret: '{{ template "superset.fullname" . }}-env' -## This can be a list of template strings +# -- This can be a list of templated strings envFromSecrets: [] -## Extra environment variables that will be passed into pods -## -extraEnv: {} +# -- Extra environment variables that will be passed into pods +extraEnv: + {} + # Different gunicorn settings, refer to the gunicorn documentation + # https://docs.gunicorn.org/en/stable/settings.html# + # These variables are used as Flags at the gunicorn startup + # https://github.com/apache/superset/blob/master/docker/run-server.sh#L22 # Extend timeout to allow long running queries. # GUNICORN_TIMEOUT: 300 - + # Increase the gunicorn worker amount, can improve performance drastically + # See: https://docs.gunicorn.org/en/stable/design.html#how-many-workers + # SERVER_WORKER_AMOUNT: 4 + # WORKER_MAX_REQUESTS: 0 + # WORKER_MAX_REQUESTS_JITTER: 0 + # SERVER_THREADS_AMOUNT: 20 + # GUNICORN_KEEPALIVE: 2 + # SERVER_LIMIT_REQUEST_LINE: 0 + # SERVER_LIMIT_REQUEST_FIELD_SIZE: 0 # OAUTH_HOME_DOMAIN: .. # # If a whitelist is not set, any address that can use your OAuth2 endpoint will be able to login. # # this includes any random Gmail address if your OAuth2 Web App is set to External. # OAUTH_WHITELIST_REGEX: ... -## Extra environment variables in RAW format that will be passed into pods -## -extraEnvRaw: [] +# -- Extra environment variables in RAW format that will be passed into pods +extraEnvRaw: + [] # Load DB password from other secret (e.g. for zalando operator) # - name: DB_PASS # valueFrom: @@ -74,15 +87,17 @@ extraEnvRaw: [] # name: superset.superset-postgres.credentials.postgresql.acid.zalan.do # key: password -## Extra environment variables to pass as secrets -## -extraSecretEnv: {} +# -- Extra environment variables to pass as secrets +extraSecretEnv: + {} # MAPBOX_API_KEY: ... # # Google API Keys: https://console.cloud.google.com/apis/credentials # GOOGLE_KEY: ... # GOOGLE_SECRET: ... -extraConfigs: {} +# -- Extra files to mount on `/app/pythonpath` +extraConfigs: + {} # import_datasources.yaml: | # databases: # - allow_file_upload: true @@ -95,34 +110,38 @@ extraConfigs: {} # sqlalchemy_uri: example://example-db.local # tables: [] +# -- Extra files to mount on `/app/pythonpath` as secrets extraSecrets: {} -extraVolumes: [] - # - name: customConfig - # configMap: - # name: '{{ template "superset.fullname" . }}-custom-config' - # - name: additionalSecret - # secret: - # secretName: my-secret - # defaultMode: 0600 - -extraVolumeMounts: [] - # - name: customConfig - # mountPath: /mnt/config - # readOnly: true - # - name: additionalSecret: - # mountPath: /mnt/secret - -# A dictionary of overrides to append at the end of superset_config.py - the name does not matter +extraVolumes: + [] + # - name: customConfig + # configMap: + # name: '{{ template "superset.fullname" . }}-custom-config' + # - name: additionalSecret + # secret: + # secretName: my-secret + # defaultMode: 0600 + +extraVolumeMounts: + [] + # - name: customConfig + # mountPath: /mnt/config + # readOnly: true + # - name: additionalSecret: + # mountPath: /mnt/secret + +# -- A dictionary of overrides to append at the end of superset_config.py - the name does not matter # WARNING: the order is not guaranteed -configOverrides: {} - # extend_timeout: | +# Files can be passed as helm --set-file configOverrides.my-override=my-file.py +configOverrides: + {} + # extend_timeout: | # # Extend timeout to allow long running queries. # SUPERSET_WEBSERVER_TIMEOUT = ... # enable_oauth: | # from flask_appbuilder.security.manager import (AUTH_DB, AUTH_OAUTH) # AUTH_TYPE = AUTH_OAUTH - # OAUTH_PROVIDERS = [ # { # "name": "google", @@ -151,39 +170,45 @@ configOverrides: {} # secret: | # # Generate your own secret key for encryption. Use openssl rand -base64 42 to generate a good key # SECRET_KEY = 'YOUR_OWN_RANDOM_GENERATED_SECRET_KEY' -# Same as above but the values are files -configOverridesFiles: {} + +# -- Same as above but the values are files +configOverridesFiles: + {} # extend_timeout: extend_timeout.py # enable_oauth: enable_oauth.py - configMountPath: "/app/pythonpath" extraConfigMountPath: "/app/configs" image: repository: apache/superset - tag: latest + tag: "" pullPolicy: IfNotPresent imagePullSecrets: [] initImage: - repository: busybox + repository: jwilder/dockerize tag: latest pullPolicy: IfNotPresent service: type: ClusterIP port: 8088 - annotations: {} + annotations: + {} # cloud.google.com/load-balancer-type: "Internal" loadBalancerIP: null + nodePort: + # -- (int) + http: nil ingress: enabled: false # ingressClassName: nginx - annotations: {} + annotations: + {} # kubernetes.io/tls-acme: "true" ## Extend timeout to allow long running queries. # nginx.ingress.kubernetes.io/proxy-connect-timeout: "300" @@ -198,7 +223,8 @@ ingress: # hosts: # - chart-example.local -resources: {} +resources: + {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following @@ -212,24 +238,24 @@ resources: {} # cpu: 100m # memory: 128Mi -## -## Custom hostAliases for all superset pods +# -- Custom hostAliases for all superset pods ## https://kubernetes.io/docs/tasks/network/customize-hosts-file-for-pods/ hostAliases: [] # - hostnames: # - nodns.my.lan # ip: 18.27.36.45 - -## -## Superset node configuration +# Superset node configuration supersetNode: + replicaCount: 1 + # -- Startup command + # @default -- See `values.yaml` command: - "/bin/sh" - "-c" - ". {{ .Values.configMountPath }}/superset_bootstrap.sh; /usr/bin/run-server.sh" connections: - # Change in case of bringing your own redis and then also set redis.enabled:false + # -- Change in case of bringing your own redis and then also set redis.enabled:false redis_host: '{{ template "superset.fullname" . }}-redis-headless' # redis_password: superset redis_port: "6379" @@ -240,106 +266,372 @@ supersetNode: db_pass: superset db_name: superset env: {} - forceReload: false # If true, forces deployment to reload on each upgrade + # -- If true, forces deployment to reload on each upgrade + forceReload: false + # -- Init containers + # @default -- a container waiting for postgres initContainers: - name: wait-for-postgres image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}" imagePullPolicy: "{{ .Values.initImage.pullPolicy }}" envFrom: - secretRef: - name: '{{ tpl .Values.envFromSecret . }}' - command: [ "/bin/sh", "-c", "until nc -zv $DB_HOST $DB_PORT -w1; do echo 'waiting for db'; sleep 1; done" ] - ## Annotations to be added to supersetNode deployment + name: "{{ tpl .Values.envFromSecret . }}" + command: + - /bin/sh + - -c + - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -timeout 120s + + # -- Annotations to be added to supersetNode deployment deploymentAnnotations: {} - ## Annotations to be added to supersetNode pods + # -- Labels to be added to supersetNode deployment + deploymentLabels: {} + # -- Affinity to be added to supersetNode deployment + affinity: {} + # -- TopologySpreadConstrains to be added to supersetNode deployments + topologySpreadConstraints: [] + # -- Annotations to be added to supersetNode pods podAnnotations: {} - ## Labels to be added to supersetNode pods + # -- Labels to be added to supersetNode pods podLabels: {} - # Resource settings for the supersetNode pods - these settings overwrite might existing values from the global resources object defined above. - resources: {} + startupProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 15 + timeoutSeconds: 1 + failureThreshold: 60 + periodSeconds: 5 + successThreshold: 1 + livenessProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 15 + timeoutSeconds: 1 + failureThreshold: 3 + periodSeconds: 15 + successThreshold: 1 + readinessProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 15 + timeoutSeconds: 1 + failureThreshold: 3 + periodSeconds: 15 + successThreshold: 1 + # -- Resource settings for the supersetNode pods - these settings overwrite might existing values from the global resources object defined above. + resources: + {} # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi -## -## Superset worker configuration + podSecurityContext: {} + containerSecurityContext: {} + strategy: + {} + # type: RollingUpdate + # rollingUpdate: + # maxSurge: 25% + # maxUnavailable: 25% + +# Superset Celery worker configuration supersetWorker: + replicaCount: 1 + # -- Worker startup command + # @default -- a `celery worker` command command: - "/bin/sh" - "-c" - ". {{ .Values.configMountPath }}/superset_bootstrap.sh; celery --app=superset.tasks.celery_app:app worker" - forceReload: false # If true, forces deployment to reload on each upgrade + # -- If true, forces deployment to reload on each upgrade + forceReload: false + # -- Init container + # @default -- a container waiting for postgres and redis initContainers: - - name: wait-for-postgres + - name: wait-for-postgres-redis image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}" imagePullPolicy: "{{ .Values.initImage.pullPolicy }}" envFrom: - secretRef: - name: '{{ tpl .Values.envFromSecret . }}' - command: [ "/bin/sh", "-c", "until nc -zv $DB_HOST $DB_PORT -w1; do echo 'waiting for db'; sleep 1; done" ] - ## Annotations to be added to supersetWorker deployment + name: "{{ tpl .Values.envFromSecret . }}" + command: + - /bin/sh + - -c + - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -wait "tcp://$REDIS_HOST:$REDIS_PORT" -timeout 120s + # -- Annotations to be added to supersetWorker deployment deploymentAnnotations: {} - ## Annotations to be added to supersetWorker pods + # -- Labels to be added to supersetWorker deployment + deploymentLabels: {} + # -- Annotations to be added to supersetWorker pods podAnnotations: {} - ## Labels to be added to supersetWorker pods + # -- Labels to be added to supersetWorker pods podLabels: {} - # Resource settings for the supersetWorker pods - these settings overwrite might existing values from the global resources object defined above. - resources: {} + # -- Resource settings for the supersetWorker pods - these settings overwrite might existing values from the global resources object defined above. + resources: + {} # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi -## -## Superset beat configuration (to trigger scheduled jobs like reports) + podSecurityContext: {} + containerSecurityContext: {} + strategy: + {} + # type: RollingUpdate + # rollingUpdate: + # maxSurge: 25% + # maxUnavailable: 25% + livenessProbe: + exec: + # -- Liveness probe command + # @default -- a `celery inspect ping` command + command: + - sh + - -c + - celery -A superset.tasks.celery_app:app inspect ping -d celery@$HOSTNAME + initialDelaySeconds: 120 + timeoutSeconds: 60 + failureThreshold: 3 + periodSeconds: 60 + successThreshold: 1 + # -- No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic) + startupProbe: {} + # -- No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic) + readinessProbe: {} + +# Superset beat configuration (to trigger scheduled jobs like reports) supersetCeleryBeat: - # This is only required if you intend to use alerts and reports + # -- This is only required if you intend to use alerts and reports enabled: false + # -- Command + # @default -- a `celery beat` command command: - "/bin/sh" - "-c" - ". {{ .Values.configMountPath }}/superset_bootstrap.sh; celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid --schedule /tmp/celerybeat-schedule" - forceReload: false # If true, forces deployment to reload on each upgrade + # -- If true, forces deployment to reload on each upgrade + forceReload: false + # -- List of init containers + # @default -- a container waiting for postgres initContainers: - - name: wait-for-postgres + - name: wait-for-postgres-redis image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}" imagePullPolicy: "{{ .Values.initImage.pullPolicy }}" envFrom: - secretRef: - name: '{{ tpl .Values.envFromSecret . }}' - command: [ "/bin/sh", "-c", "until nc -zv $DB_HOST $DB_PORT -w1; do echo 'waiting for db'; sleep 1; done" ] - ## Annotations to be added to supersetCeleryBeat deployment + name: "{{ tpl .Values.envFromSecret . }}" + command: + - /bin/sh + - -c + - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -wait "tcp://$REDIS_HOST:$REDIS_PORT" -timeout 120s + # -- Annotations to be added to supersetCeleryBeat deployment deploymentAnnotations: {} - ## Annotations to be added to supersetCeleryBeat pods + # -- Affinity to be added to supersetCeleryBeat deployment + affinity: {} + # -- TopologySpreadConstrains to be added to supersetCeleryBeat deployments + topologySpreadConstraints: [] + # -- Annotations to be added to supersetCeleryBeat pods podAnnotations: {} - ## Labels to be added to supersetCeleryBeat pods + # -- Labels to be added to supersetCeleryBeat pods podLabels: {} - # Resource settings for the CeleryBeat pods - these settings overwrite might existing values from the global resources object defined above. - resources: {} + # -- Resource settings for the CeleryBeat pods - these settings overwrite might existing values from the global resources object defined above. + resources: + {} # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi -## -## Init job configuration + podSecurityContext: {} + containerSecurityContext: {} + +supersetCeleryFlower: + # -- Enables a Celery flower deployment (management UI to monitor celery jobs) + # WARNING: on superset 1.x, this requires a Superset image that has `flower<1.0.0` installed (which is NOT the case of the default images) + # flower>=1.0.0 requires Celery 5+ which Superset 1.5 does not support + enabled: false + replicaCount: 1 + # -- Command + # @default -- a `celery flower` command + command: + - "/bin/sh" + - "-c" + - "celery --app=superset.tasks.celery_app:app flower" + service: + type: ClusterIP + annotations: {} + port: 5555 + nodePort: + # -- (int) + http: nil + startupProbe: + httpGet: + path: /api/workers + port: flower + initialDelaySeconds: 5 + timeoutSeconds: 1 + failureThreshold: 60 + periodSeconds: 5 + successThreshold: 1 + livenessProbe: + httpGet: + path: /api/workers + port: flower + initialDelaySeconds: 5 + timeoutSeconds: 1 + failureThreshold: 3 + periodSeconds: 5 + successThreshold: 1 + readinessProbe: + httpGet: + path: /api/workers + port: flower + initialDelaySeconds: 5 + timeoutSeconds: 1 + failureThreshold: 3 + periodSeconds: 5 + successThreshold: 1 + # -- List of init containers + # @default -- a container waiting for postgres and redis + initContainers: + - name: wait-for-postgres-redis + image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}" + imagePullPolicy: "{{ .Values.initImage.pullPolicy }}" + envFrom: + - secretRef: + name: "{{ tpl .Values.envFromSecret . }}" + command: + - /bin/sh + - -c + - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -wait "tcp://$REDIS_HOST:$REDIS_PORT" -timeout 120s + # -- Annotations to be added to supersetCeleryFlower deployment + deploymentAnnotations: {} + # -- Affinity to be added to supersetCeleryFlower deployment + affinity: {} + # -- TopologySpreadConstrains to be added to supersetCeleryFlower deployments + topologySpreadConstraints: [] + # -- Annotations to be added to supersetCeleryFlower pods + podAnnotations: {} + # -- Labels to be added to supersetCeleryFlower pods + podLabels: {} + # -- Resource settings for the CeleryBeat pods - these settings overwrite might existing values from the global resources object defined above. + resources: + {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + podSecurityContext: {} + containerSecurityContext: {} + +supersetWebsockets: + # -- This is only required if you intend to use `GLOBAL_ASYNC_QUERIES` in `ws` mode + # see https://github.com/apache/superset/blob/master/CONTRIBUTING.md#async-chart-queries + enabled: false + replicaCount: 1 + ingress: + path: /ws + pathType: Prefix + image: + # -- There is no official image (yet), this one is community-supported + repository: oneacrefund/superset-websocket + tag: latest + pullPolicy: IfNotPresent + # -- The config.json to pass to the server, see https://github.com/apache/superset/tree/master/superset-websocket + # Note that the configuration can also read from environment variables (which will have priority), see https://github.com/apache/superset/blob/master/superset-websocket/src/config.ts for a list of supported variables + # @default -- see `values.yaml` + config: + { + "port": 8080, + "logLevel": "debug", + "logToFile": false, + "logFilename": "app.log", + "statsd": { "host": "127.0.0.1", "port": 8125, "globalTags": [] }, + "redis": + { + "port": 6379, + "host": "127.0.0.1", + "password": "", + "db": 0, + "ssl": false, + }, + "redisStreamPrefix": "async-events-", + "jwtSecret": "CHANGE-ME", + "jwtCookieName": "async-token", + } + service: + type: ClusterIP + annotations: {} + port: 8080 + nodePort: + # -- (int) + http: nil + command: [] + resources: {} + deploymentAnnotations: {} + # -- Affinity to be added to supersetWebsockets deployment + affinity: {} + # -- TopologySpreadConstrains to be added to supersetWebsockets deployments + topologySpreadConstraints: [] + podAnnotations: {} + podLabels: {} + strategy: {} + podSecurityContext: {} + containerSecurityContext: {} + startupProbe: + httpGet: + path: /health + port: ws + initialDelaySeconds: 5 + timeoutSeconds: 1 + failureThreshold: 60 + periodSeconds: 5 + successThreshold: 1 + livenessProbe: + httpGet: + path: /health + port: ws + initialDelaySeconds: 5 + timeoutSeconds: 1 + failureThreshold: 3 + periodSeconds: 5 + successThreshold: 1 + readinessProbe: + httpGet: + path: /health + port: ws + initialDelaySeconds: 5 + timeoutSeconds: 1 + failureThreshold: 3 + periodSeconds: 5 + successThreshold: 1 + init: # Configure resources # Warning: fab command consumes a lot of ram and can # cause the process to be killed due to OOM if it exceeds limit # Make sure you are giving a strong password for the admin user creation( else make sure you are changing after setup) # Also change the admin email to your own custom email. - resources: {} + resources: + {} # limits: # cpu: # memory: # requests: # cpu: # memory: + # -- Command + # @default -- a `superset_init.sh` command command: - "/bin/sh" - "-c" @@ -353,14 +645,21 @@ init: lastname: Admin email: admin@superset.com password: admin + # -- List of initContainers + # @default -- a container waiting for postgres initContainers: - name: wait-for-postgres image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}" imagePullPolicy: "{{ .Values.initImage.pullPolicy }}" envFrom: - secretRef: - name: '{{ tpl .Values.envFromSecret . }}' - command: [ "/bin/sh", "-c", "until nc -zv $DB_HOST $DB_PORT -w1; do echo 'waiting for db'; sleep 1; done" ] + name: "{{ tpl .Values.envFromSecret . }}" + command: + - /bin/sh + - -c + - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -timeout 120s + # -- A Superset init script + # @default -- a script to create admin user and initailize roles initscript: |- #!/bin/sh set -eu @@ -388,9 +687,12 @@ init: fi ## Annotations to be added to init job pods podAnnotations: {} -## -## Configuration values for the postgresql dependency. -## ref: https://github.com/kubernetes/charts/blob/master/stable/postgresql/README.md + podSecurityContext: {} + containerSecurityContext: {} + +# -- Configuration values for the postgresql dependency. +# ref: https://github.com/kubernetes/charts/blob/master/stable/postgresql/README.md +# @default -- see `values.yaml` postgresql: ## ## Use the PostgreSQL chart dependency. @@ -408,6 +710,8 @@ postgresql: ## PostgreSQL name for a custom database to create database: superset + image: + tag: "14.6.0-debian-11-r13" ## PostgreSQL Primary parameters primary: @@ -430,9 +734,10 @@ postgresql: ports: postgresql: "5432" -## Configuration values for the Redis dependency. -## ref: https://github.com/bitnami/charts/blob/master/bitnami/redis -## More documentation can be found here: https://artifacthub.io/packages/helm/bitnami/redis +# -- Configuration values for the Redis dependency. +# ref: https://github.com/bitnami/charts/blob/master/bitnami/redis +# More documentation can be found here: https://artifacthub.io/packages/helm/bitnami/redis +# @default -- see `values.yaml` redis: ## ## Use the redis chart dependency. @@ -463,9 +768,9 @@ redis: ## ## Image configuration # image: - ## - ## docker registry secret names (list) - # pullSecrets: nil + ## + ## docker registry secret names (list) + # pullSecrets: nil ## ## Configure persistance persistence: @@ -478,10 +783,13 @@ redis: ## ## Access mode: accessModes: - - ReadWriteOnce + - ReadWriteOnce nodeSelector: {} tolerations: [] affinity: {} + +# -- TopologySpreadConstrains to be added to all deployments +topologySpreadConstraints: [] diff --git a/lintconf.yaml b/lintconf.yaml index 7a62003d95079..5a7c114c6d18c 100644 --- a/lintconf.yaml +++ b/lintconf.yaml @@ -18,7 +18,7 @@ rules: braces: min-spaces-inside: 0 - max-spaces-inside: 0 + max-spaces-inside: 1 min-spaces-inside-empty: -1 max-spaces-inside-empty: -1 brackets: @@ -37,7 +37,7 @@ rules: require-starting-space: false min-spaces-from-content: -1 document-end: disable - document-start: disable # No --- to start a file + document-start: disable # No --- to start a file empty-lines: max: 2 max-start: 0 @@ -46,10 +46,10 @@ rules: max-spaces-after: 1 indentation: spaces: consistent - indent-sequences: whatever # - list indentation will handle both indentation and without + indent-sequences: whatever # - list indentation will handle both indentation and without check-multi-line-strings: false key-duplicates: enable - line-length: disable # Lines can be any length + line-length: disable # Lines can be any length new-line-at-end-of-file: enable new-lines: type: unix diff --git a/requirements/base.txt b/requirements/base.txt index a2f72d85bc041..d27bef99f6823 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,26 +7,20 @@ # -e file:. # via -r requirements/base.in -aiohttp==3.8.1 - # via slackclient -aiosignal==1.2.0 - # via aiohttp alembic==1.6.5 # via flask-migrate amqp==5.1.0 # via kombu apispec[yaml]==3.3.2 # via flask-appbuilder -async-timeout==4.0.2 - # via aiohttp attrs==21.2.0 - # via - # aiohttp - # jsonschema + # via jsonschema babel==2.9.1 # via flask-babel backoff==1.11.1 # via apache-superset +bcrypt==4.0.1 + # via paramiko billiard==3.6.4.0 # via celery bleach==3.3.1 @@ -37,10 +31,10 @@ cachelib==0.4.1 # via apache-superset celery==5.2.2 # via apache-superset -cffi==1.14.6 - # via cryptography -charset-normalizer==2.0.4 - # via aiohttp +cffi==1.15.1 + # via + # cryptography + # pynacl click==8.0.4 # via # apache-superset @@ -66,15 +60,17 @@ cron-descriptor==1.2.24 # via apache-superset croniter==1.0.15 # via apache-superset -cryptography==3.4.7 - # via apache-superset +cryptography==39.0.0 + # via + # apache-superset + # paramiko deprecation==2.1.0 # via apache-superset dnspython==2.1.0 # via email-validator email-validator==1.1.3 # via flask-appbuilder -flask==2.0.3 +flask==2.1.3 # via # apache-superset # flask-appbuilder @@ -86,34 +82,32 @@ flask==2.0.3 # flask-migrate # flask-sqlalchemy # flask-wtf -flask-appbuilder==4.1.3 +flask-appbuilder==4.2.0 # via apache-superset flask-babel==1.0.0 # via flask-appbuilder flask-caching==1.10.1 # via apache-superset -flask-compress==1.10.1 +flask-compress==1.13 # via apache-superset flask-jwt-extended==4.3.1 # via flask-appbuilder -flask-login==0.4.1 - # via flask-appbuilder +flask-login==0.6.0 + # via + # apache-superset + # flask-appbuilder flask-migrate==3.1.0 # via apache-superset flask-sqlalchemy==2.5.1 # via # flask-appbuilder # flask-migrate -flask-talisman==0.8.1 +flask-talisman==1.0.0 # via apache-superset -flask-wtf==0.14.3 +flask-wtf==1.0.1 # via # apache-superset # flask-appbuilder -frozenlist==1.3.0 - # via - # aiohttp - # aiosignal func-timeout==4.3.5 # via apache-superset geographiclib==1.52 @@ -126,14 +120,14 @@ gunicorn==20.1.0 # via apache-superset hashids==1.3.1 # via apache-superset -holidays==0.14.2 +hijri-converter==2.2.4 + # via holidays +holidays==0.17.2 # via apache-superset humanize==3.11.0 # via apache-superset idna==3.2 - # via - # email-validator - # yarl + # via email-validator isodate==0.6.0 # via apache-superset itsdangerous==2.1.1 @@ -154,7 +148,7 @@ mako==1.1.4 # via alembic markdown==3.3.4 # via apache-superset -markupsafe==2.0.1 +markupsafe==2.1.1 # via # jinja2 # mako @@ -170,11 +164,7 @@ marshmallow-sqlalchemy==0.23.1 # via flask-appbuilder msgpack==1.0.2 # via apache-superset -multidict==5.1.0 - # via - # aiohttp - # yarl -numpy==1.22.1 +numpy==1.23.5 # via # apache-superset # pandas @@ -183,8 +173,10 @@ packaging==21.3 # via # bleach # deprecation -pandas==1.3.4 +pandas==1.5.3 # via apache-superset +paramiko==2.11.0 + # via sshtunnel parsedatetime==2.6 # via apache-superset pgsanity==0.2.9 @@ -195,7 +187,7 @@ prison==0.2.1 # via flask-appbuilder prompt-toolkit==3.0.28 # via click-repl -pyarrow==5.0.0 +pyarrow==10.0.1 # via apache-superset pycparser==2.20 # via cffi @@ -206,6 +198,8 @@ pyjwt==2.4.0 # flask-jwt-extended pymeeus==0.5.11 # via convertdate +pynacl==1.5.0 + # via paramiko pyparsing==3.0.6 # via # apache-superset @@ -230,7 +224,6 @@ pytz==2021.3 # via # babel # celery - # convertdate # flask-babel # pandas pyyaml==5.4.1 @@ -247,19 +240,17 @@ six==1.16.0 # via # bleach # click-repl - # flask-talisman - # holidays # isodate # jsonschema + # paramiko # polyline # prison # pyrsistent # python-dateutil - # sqlalchemy-utils # wtforms-json -slackclient==2.5.0 +slack-sdk==3.18.3 # via apache-superset -sqlalchemy==1.3.24 +sqlalchemy==1.4.36 # via # alembic # apache-superset @@ -267,15 +258,17 @@ sqlalchemy==1.3.24 # flask-sqlalchemy # marshmallow-sqlalchemy # sqlalchemy-utils -sqlalchemy-utils==0.37.8 +sqlalchemy-utils==0.38.3 # via # apache-superset # flask-appbuilder -sqlparse==0.3.0 +sqlparse==0.4.3 + # via apache-superset +sshtunnel==0.4.0 # via apache-superset tabulate==0.8.9 # via apache-superset -typing-extensions==3.10.0.0 +typing-extensions==4.4.0 # via apache-superset urllib3==1.26.6 # via selenium @@ -288,19 +281,21 @@ wcwidth==0.2.5 # via prompt-toolkit webencodings==0.5.1 # via bleach -werkzeug==2.0.3 +werkzeug==2.1.2 # via # flask # flask-jwt-extended + # flask-login wtforms==2.3.3 # via + # apache-superset # flask-appbuilder # flask-wtf # wtforms-json wtforms-json==0.3.3 # via apache-superset -yarl==1.6.3 - # via aiohttp +xlsxwriter==3.0.7 + # via apache-superset # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/requirements/development.txt b/requirements/development.txt index 75af963cf8676..47fe7a17372dd 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -28,6 +28,8 @@ certifi==2021.10.8 # via requests chardet==4.0.0 # via tabulator +charset-normalizer==2.0.12 + # via requests decorator==5.1.1 # via ipython et-xmlfile==1.1.0 @@ -64,11 +66,11 @@ pexpect==4.8.0 # via ipython pickleshare==0.7.5 # via ipython -pillow==9.1.0 +pillow==9.3.0 # via apache-superset progress==1.6 # via -r requirements/development.in -psycopg2-binary==2.9.1 +psycopg2-binary==2.9.5 # via apache-superset ptyprocess==0.7.0 # via pexpect @@ -76,7 +78,7 @@ pure-eval==0.2.2 # via stack-data pure-sasl==0.6.2 # via thrift-sasl -pydruid==0.6.2 +pydruid==0.6.5 # via apache-superset pygments==2.12.0 # via ipython @@ -95,7 +97,7 @@ s3transfer==0.5.0 # via boto3 sasl==0.3.1 # via pyhive -sqloxide==0.1.17 +sqloxide==0.1.30 # via -r requirements/development.in stack-data==0.2.0 # via ipython @@ -103,7 +105,7 @@ tableschema==1.20.2 # via apache-superset tabulator==1.53.5 # via tableschema -thrift==0.13.0 +thrift==0.14.1 # via # apache-superset # pyhive diff --git a/requirements/docker.txt b/requirements/docker.txt index f9ea766f4e69f..0338f43fd8f88 100644 --- a/requirements/docker.txt +++ b/requirements/docker.txt @@ -12,9 +12,9 @@ # -r requirements/docker.in gevent==21.8.0 # via -r requirements/docker.in -greenlet==1.1.1 +greenlet==1.1.3.post0 # via gevent -psycopg2-binary==2.9.1 +psycopg2-binary==2.9.5 # via apache-superset zope-event==4.5.0 # via gevent diff --git a/requirements/integration.txt b/requirements/integration.txt index fb1d37cd53f91..a0243d6d0dd0c 100644 --- a/requirements/integration.txt +++ b/requirements/integration.txt @@ -5,17 +5,17 @@ # # pip-compile-multi # -backports-entry-points-selectable==1.1.0 - # via virtualenv +build==0.8.0 + # via pip-tools cfgv==3.3.0 # via pre-commit click==8.0.4 # via # pip-compile-multi # pip-tools -distlib==0.3.2 +distlib==0.3.6 # via virtualenv -filelock==3.0.12 +filelock==3.9.0 # via # tox # virtualenv @@ -24,19 +24,21 @@ identify==2.2.13 nodeenv==1.6.0 # via pre-commit packaging==21.3 - # via tox + # via + # build + # tox pep517==0.11.0 - # via pip-tools -pip-compile-multi==2.4.1 - # via -r requirements/integration.in -pip-tools==6.2.0 + # via build +pip-compile-multi==2.6.1 + # via -r integration.in +pip-tools==6.8.0 # via pip-compile-multi -platformdirs==2.2.0 +platformdirs==2.6.2 # via virtualenv pluggy==0.13.1 # via tox -pre-commit==2.14.0 - # via -r requirements/integration.in +pre-commit==3.0.4 + # via -r integration.in py==1.10.0 # via tox pyparsing==3.0.6 @@ -44,24 +46,20 @@ pyparsing==3.0.6 pyyaml==5.4.1 # via pre-commit six==1.16.0 - # via - # tox - # virtualenv + # via tox toml==0.10.2 - # via - # pre-commit - # tox + # via tox tomli==1.2.1 # via pep517 toposort==1.6 # via pip-compile-multi -tox==3.24.1 - # via -r requirements/integration.in -virtualenv==20.7.2 +tox==3.25.1 + # via -r integration.in +virtualenv==20.17.1 # via # pre-commit # tox -wheel==0.37.0 +wheel==0.38.1 # via pip-tools # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/testing.txt b/requirements/testing.txt index 5c1c2f7fce345..5312ea4f235b7 100644 --- a/requirements/testing.txt +++ b/requirements/testing.txt @@ -14,88 +14,91 @@ # -r requirements/testing.in astroid==2.6.6 # via pylint -cachetools==4.2.4 +cachetools==5.2.0 # via google-auth coverage==5.5 # via pytest-cov +db-dtypes==1.0.5 + # via pandas-gbq docker==5.0.0 # via -r requirements/testing.in flask-testing==0.8.1 # via -r requirements/testing.in freezegun==1.1.0 # via -r requirements/testing.in -google-api-core[grpc]==2.2.1 +google-api-core[grpc]==2.11.0 # via # google-cloud-bigquery # google-cloud-bigquery-storage # google-cloud-core - # pybigquery -google-auth==2.2.1 + # pandas-gbq + # sqlalchemy-bigquery +google-auth==2.14.1 # via # google-api-core # google-auth-oauthlib # google-cloud-core # pandas-gbq - # pybigquery # pydata-google-auth -google-auth-oauthlib==0.4.6 + # sqlalchemy-bigquery +google-auth-oauthlib==0.7.1 # via # pandas-gbq # pydata-google-auth -google-cloud-bigquery[bqstorage,pandas]==2.29.0 +google-cloud-bigquery[bqstorage,pandas]==3.4.0 # via # apache-superset # pandas-gbq - # pybigquery -google-cloud-bigquery-storage==2.9.1 - # via google-cloud-bigquery -google-cloud-core==2.1.0 + # sqlalchemy-bigquery +google-cloud-bigquery-storage==2.16.2 + # via + # google-cloud-bigquery + # pandas-gbq + # sqlalchemy-bigquery +google-cloud-core==2.3.2 # via google-cloud-bigquery -google-crc32c==1.3.0 +google-crc32c==1.5.0 # via google-resumable-media -google-resumable-media==2.1.0 +google-resumable-media==2.4.0 # via google-cloud-bigquery -googleapis-common-protos==1.53.0 +googleapis-common-protos==1.57.0 # via # google-api-core # grpcio-status -grpcio==1.41.1 +grpcio==1.51.1 # via # google-api-core # google-cloud-bigquery # grpcio-status -grpcio-status==1.41.1 +grpcio-status==1.51.1 # via google-api-core iniconfig==1.1.1 # via pytest -isort==5.9.3 +isort==5.12.0 # via pylint lazy-object-proxy==1.6.0 # via astroid -libcst==0.3.21 - # via google-cloud-bigquery-storage mccabe==0.6.1 # via pylint -mypy-extensions==0.4.3 - # via typing-inspect -oauthlib==3.1.1 +oauthlib==3.2.2 # via requests-oauthlib openapi-schema-validator==0.1.5 # via openapi-spec-validator openapi-spec-validator==0.3.1 # via -r requirements/testing.in -pandas-gbq==0.15.0 +pandas-gbq==0.18.1 # via apache-superset parameterized==0.8.1 # via -r requirements/testing.in -proto-plus==1.19.7 +proto-plus==1.22.1 # via # google-cloud-bigquery # google-cloud-bigquery-storage -protobuf==3.19.1 +protobuf==4.21.10 # via # google-api-core # google-cloud-bigquery + # google-cloud-bigquery-storage # googleapis-common-protos # grpcio-status # proto-plus @@ -105,12 +108,12 @@ pyasn1==0.4.8 # rsa pyasn1-modules==0.2.8 # via google-auth -pybigquery==0.10.2 - # via apache-superset -pydata-google-auth==1.2.0 +pydata-google-auth==1.4.0 # via pandas-gbq pyfakefs==4.5.6 # via -r requirements/testing.in +pyhive[presto]==0.6.5 + # via apache-superset pylint==2.9.6 # via -r requirements/testing.in pytest==6.2.4 @@ -122,16 +125,16 @@ pytest-cov==2.12.1 # via -r requirements/testing.in pytest-mock==3.6.1 # via -r requirements/testing.in -requests-oauthlib==1.3.0 +requests-oauthlib==1.3.1 # via google-auth-oauthlib -rsa==4.7.2 +rsa==4.9 # via google-auth +sqlalchemy-bigquery==1.5.0 + # via apache-superset statsd==3.3.0 # via -r requirements/testing.in -trino==0.313.0 +trino==0.319.0 # via apache-superset -typing-inspect==0.7.1 - # via libcst websocket-client==1.2.0 # via docker wrapt==1.12.1 diff --git a/scripts/babel_update.sh b/scripts/babel_update.sh index 2b971397a46da..e281599bf7a43 100755 --- a/scripts/babel_update.sh +++ b/scripts/babel_update.sh @@ -45,7 +45,7 @@ pybabel extract \ --sort-output \ --copyright-holder=Superset \ --project=Superset \ - -k _ -k __ -k t -k tn -k tct . + -k _ -k __ -k t -k tn:1,2 -k tct . cat $LICENSE_TMP superset/translations/messages.pot > messages.pot.tmp \ && mv messages.pot.tmp superset/translations/messages.pot diff --git a/scripts/cancel_github_workflows.py b/scripts/cancel_github_workflows.py index 720dc05cbef22..4d30d34adf405 100755 --- a/scripts/cancel_github_workflows.py +++ b/scripts/cancel_github_workflows.py @@ -143,7 +143,7 @@ def print_commit(commit: Dict[str, Any], branch: str) -> None: "--include-last/--skip-last", default=False, show_default=True, - help="Whether to also cancel the lastest run.", + help="Whether to also cancel the latest run.", ) @click.option( "--include-running/--skip-running", diff --git a/scripts/generate_frontend_ts_tasklist.js b/scripts/generate_frontend_ts_tasklist.js index b9c5c47fc9da8..7f23ad124aefd 100644 --- a/scripts/generate_frontend_ts_tasklist.js +++ b/scripts/generate_frontend_ts_tasklist.js @@ -48,10 +48,10 @@ while (directories.length) { // directory. const hasTypescriptFiles = getFilesByExtensions("./", [".ts", ".tsx"]).length > 0; - const hasJavascriptFiles = + const hasJavaScriptFiles = getFilesByExtensions("./", [".js", ".jsx"]).length > 0; - if (hasJavascriptFiles) { + if (hasJavaScriptFiles) { console.log( `${" ".repeat( curDirectory.split("/").length - 1 diff --git a/scripts/permissions_cleanup.py b/scripts/permissions_cleanup.py index 99d192919c6c4..5ca75e394cccf 100644 --- a/scripts/permissions_cleanup.py +++ b/scripts/permissions_cleanup.py @@ -24,7 +24,7 @@ def cleanup_permissions() -> None: pvms = security_manager.get_session.query( security_manager.permissionview_model ).all() - print("# of permission view menues is: {}".format(len(pvms))) + print("# of permission view menus is: {}".format(len(pvms))) pvms_dict = defaultdict(list) for pvm in pvms: pvms_dict[(pvm.permission, pvm.view_menu)].append(pvm) @@ -43,9 +43,9 @@ def cleanup_permissions() -> None: pvms = security_manager.get_session.query( security_manager.permissionview_model ).all() - print("Stage 1: # of permission view menues is: {}".format(len(pvms))) + print("Stage 1: # of permission view menus is: {}".format(len(pvms))) - # 2. Clean up None permissions or view menues + # 2. Clean up None permissions or view menus pvms = security_manager.get_session.query( security_manager.permissionview_model ).all() @@ -57,15 +57,15 @@ def cleanup_permissions() -> None: pvms = security_manager.get_session.query( security_manager.permissionview_model ).all() - print("Stage 2: # of permission view menues is: {}".format(len(pvms))) + print("Stage 2: # of permission view menus is: {}".format(len(pvms))) - # 3. Delete empty permission view menues from roles + # 3. Delete empty permission view menus from roles roles = security_manager.get_session.query(security_manager.role_model).all() for role in roles: role.permissions = [p for p in role.permissions if p] security_manager.get_session.commit() - # 4. Delete empty roles from permission view menues + # 4. Delete empty roles from permission view menus pvms = security_manager.get_session.query( security_manager.permissionview_model ).all() diff --git a/scripts/python_tests.sh b/scripts/python_tests.sh index 6491a3f6f9d46..c3f27d17f78c4 100755 --- a/scripts/python_tests.sh +++ b/scripts/python_tests.sh @@ -19,7 +19,7 @@ set -e # Temporary fix, probably related with https://bugs.launchpad.net/ubuntu/+source/opencv/+bug/1890170 -# MySQL was failling with: +# MySQL was failing with: # from . import _mysql # ImportError: /lib/x86_64-linux-gnu/libstdc++.so.6: cannot allocate memory in static TLS block export LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6 diff --git a/scripts/tests/run.sh b/scripts/tests/run.sh index 24233010107dd..2c3b5bf359733 100755 --- a/scripts/tests/run.sh +++ b/scripts/tests/run.sh @@ -24,7 +24,7 @@ set -e # function reset_db() { echo -------------------- - echo Reseting test DB + echo Resetting test DB echo -------------------- docker-compose stop superset-tests-worker superset || true RESET_DB_CMD="psql \"postgresql://${DB_USER}:${DB_PASSWORD}@127.0.0.1:5432\" <<-EOF diff --git a/setup.cfg b/setup.cfg index 6f667677ec810..a9470d51bd8b0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,9 +17,9 @@ [metadata] name = Superset summary = a data exploration platform -description-file = README.md +description_file = README.md author = Apache Superset Dev -author-email = dev@superset.apache.org +author_email = dev@superset.apache.org license = Apache License, Version 2.0 [files] @@ -30,7 +30,7 @@ combine_as_imports = true include_trailing_comma = true line_length = 88 known_first_party = superset -known_third_party =alembic,apispec,backoff,bleach,cachelib,celery,click,colorama,cron_descriptor,croniter,cryptography,dateutil,deprecation,flask,flask_appbuilder,flask_babel,flask_caching,flask_compress,flask_jwt_extended,flask_login,flask_migrate,flask_sqlalchemy,flask_talisman,flask_testing,flask_wtf,freezegun,geohash,geopy,graphlib,holidays,humanize,isodate,jinja2,jwt,markdown,markupsafe,marshmallow,marshmallow_enum,msgpack,numpy,pandas,parameterized,parsedatetime,pgsanity,pkg_resources,polyline,prison,progress,pyarrow,pybigquery,pyhive,pyparsing,pytest,pytest_mock,pytz,redis,requests,selenium,setuptools,simplejson,slack,sqlalchemy,sqlalchemy_utils,sqlparse,typing_extensions,urllib3,werkzeug,wtforms,wtforms_json,yaml +known_third_party =alembic,apispec,backoff,bleach,cachelib,celery,click,colorama,cron_descriptor,croniter,cryptography,dateutil,deprecation,flask,flask_appbuilder,flask_babel,flask_caching,flask_compress,flask_jwt_extended,flask_login,flask_migrate,flask_sqlalchemy,flask_talisman,flask_testing,flask_wtf,freezegun,geohash,geopy,graphlib,holidays,humanize,isodate,jinja2,jwt,markdown,markupsafe,marshmallow,marshmallow_enum,msgpack,numpy,pandas,parameterized,parsedatetime,pgsanity,pkg_resources,polyline,prison,progress,pyarrow,sqlalchemy_bigquery,pyhive,pyparsing,pytest,pytest_mock,pytz,redis,requests,selenium,setuptools,simplejson,slack,sqlalchemy,sqlalchemy_utils,sqlparse,typing_extensions,urllib3,werkzeug,wtforms,wtforms_json,yaml multi_line_output = 3 order_by_type = false @@ -41,7 +41,7 @@ disallow_untyped_calls = true disallow_untyped_defs = true ignore_missing_imports = true no_implicit_optional = true -warn_unused_ignores = false +warn_unused_ignores = true [mypy-superset.migrations.versions.*] ignore_errors = true diff --git a/setup.py b/setup.py index 4ffd66d8de2bf..f9b4a7d67f2b8 100644 --- a/setup.py +++ b/setup.py @@ -64,6 +64,12 @@ def get_git_sha() -> str: zip_safe=False, entry_points={ "console_scripts": ["superset=superset.cli.main:superset"], + # the `postgres` and `postgres+psycopg2://` schemes were removed in SQLAlchemy 1.4 + # add an alias here to prevent breaking existing databases + "sqlalchemy.dialects": [ + "postgres.psycopg2 = sqlalchemy.dialects.postgresql:dialect", + "postgres = sqlalchemy.dialects.postgresql:dialect", + ], }, install_requires=[ "backoff>=1.8.0", @@ -74,27 +80,28 @@ def get_git_sha() -> str: "colorama", "croniter>=0.3.28", "cron-descriptor", - "cryptography>=3.3.2", + "cryptography>=39.0.0,<40", "deprecation>=2.1.0, <2.2.0", - "flask>=2.0.0, <3.0.0", - "flask-appbuilder>=4.1.3, <5.0.0", - "flask-caching>=1.10.0", - "flask-compress", - "flask-talisman", - "flask-migrate", - "flask-wtf", + "flask>=2.1.3, <2.2", + "flask-appbuilder>=4.2.0, <5.0.0", + "flask-caching>=1.10.1, <1.11", + "flask-compress>=1.13, <2.0", + "flask-talisman>=1.0.0, <2.0", + "flask-login==0.6.0", + "flask-migrate>=3.1.0, <4.0", + "flask-wtf>=1.0.1, <1.1", "func_timeout", "geopy", "graphlib-backport", - "gunicorn>=20.1.0", + "gunicorn>=20.1.0; sys_platform != 'win32'", "hashids>=1.3.1, <2", - "holidays==0.14.2", + "holidays>=0.17.2, <0.18", "humanize", "isodate", "markdown>=3.0", "msgpack>=1.0.0, <1.1", - "numpy==1.22.1", - "pandas>=1.3.0, <1.4", + "numpy==1.23.5", + "pandas>=1.5.3, <1.6", "parsedatetime", "pgsanity", "polyline", @@ -102,31 +109,33 @@ def get_git_sha() -> str: "python-dateutil", "python-dotenv", "python-geohash", - "pyarrow>=5.0.0, <6.0", + "pyarrow>=10.0.1, <11", "pyyaml>=5.4", "PyJWT>=2.4.0, <3.0", "redis", "selenium>=3.141.0", + "sshtunnel>=0.4.0, <0.5", "simplejson>=3.15.0", - "slackclient==2.5.0", # PINNED! slack changes file upload api in the future versions - "sqlalchemy>=1.3.16, <1.4, !=1.3.21", - "sqlalchemy-utils>=0.37.8, <0.38", - "sqloxide>=0.1.15", - "sqlparse==0.3.0", # PINNED! see https://github.com/andialbrecht/sqlparse/issues/562 - "tabulate==0.8.9", - # needed to support Literal (3.8) and TypeGuard (3.10) - "typing-extensions>=3.10, <4", + "slack_sdk>=3.1.1, <4", + "sqlalchemy>=1.4, <2", + "sqlalchemy-utils>=0.38.3, <0.39", + "sqlparse>=0.4.3, <0.5", + "tabulate>=0.8.9, <0.9", + "typing-extensions>=4, <5", + "waitress; sys_platform == 'win32'", + "wtforms>=2.3.3, <2.4", "wtforms-json", + "xlsxwriter>=3.0.7, <3.1", ], extras_require={ - "athena": ["pyathena>=1.10.8, <1.11"], + "athena": ["pyathena[pandas]>=2, <3"], "aurora-data-api": ["preset-sqlalchemy-aurora-data-api>=0.2.8,<0.3"], "bigquery": [ - "pandas_gbq>=0.10.0", - "pybigquery>=0.4.10", - "google-cloud-bigquery>=2.4.0", + "pandas-gbq>=0.18.1", + "sqlalchemy-bigquery>=1.5.0", + "google-cloud-bigquery>=3.4.0", ], - "clickhouse": ["clickhouse-sqlalchemy>=0.1.4, <0.2"], + "clickhouse": ["clickhouse-connect>=0.4.6, <0.5"], "cockroachdb": ["cockroachdb>=0.3.5, <0.4"], "cors": ["flask-cors>=2.0.0"], "crate": ["crate[sqlalchemy]>=0.26.0, <0.27"], @@ -137,37 +146,37 @@ def get_git_sha() -> str: "db2": ["ibm-db-sa>=0.3.5, <0.4"], "dremio": ["sqlalchemy-dremio>=1.1.5, <1.3"], "drill": ["sqlalchemy-drill==0.1.dev"], - "druid": ["pydruid>=0.6.1,<0.7"], + "druid": ["pydruid>=0.6.5,<0.7"], + "dynamodb": ["pydynamodb>=0.4.2"], "solr": ["sqlalchemy-solr >= 0.2.0"], - "elasticsearch": ["elasticsearch-dbapi>=0.2.0, <0.3.0"], + "elasticsearch": ["elasticsearch-dbapi>=0.2.9, <0.3.0"], "exasol": ["sqlalchemy-exasol >= 2.4.0, <3.0"], "excel": ["xlrd>=1.2.0, <1.3"], "firebird": ["sqlalchemy-firebird>=0.7.0, <0.8"], "firebolt": ["firebolt-sqlalchemy>=0.0.1"], "gsheets": ["shillelagh[gsheetsapi]>=1.0.14, <2"], "hana": ["hdbcli==2.4.162", "sqlalchemy_hana==0.4.0"], - "hive": ["pyhive[hive]>=0.6.5", "tableschema", "thrift>=0.11.0, <1.0.0"], + "hive": ["pyhive[hive]>=0.6.5", "tableschema", "thrift>=0.14.1, <1.0.0"], "impala": ["impyla>0.16.2, <0.17"], - "kusto": ["sqlalchemy-kusto>=1.0.1, <2"], + "kusto": ["sqlalchemy-kusto>=2.0.0, <3"], "kylin": ["kylinpy>=2.8.1, <2.9"], "mssql": ["pymssql>=2.1.4, <2.2"], "mysql": ["mysqlclient>=2.1.0, <3"], "oracle": ["cx-Oracle>8.0.0, <8.1"], "pinot": ["pinotdb>=0.3.3, <0.4"], - "postgres": ["psycopg2-binary==2.9.1"], + "postgres": ["psycopg2-binary==2.9.5"], "presto": ["pyhive[presto]>=0.6.5"], - "trino": ["trino>=0.313.0"], + "trino": ["trino>=0.319.0"], "prophet": ["prophet>=1.0.1, <1.1", "pystan<3.0"], "redshift": ["sqlalchemy-redshift>=0.8.1, < 0.9"], "rockset": ["rockset>=0.8.10, <0.9"], "shillelagh": [ - "shillelagh[datasetteapi,gsheetsapi,socrata,weatherapi]>=1.0.3, <2" + "shillelagh[datasetteapi,gsheetsapi,socrata,weatherapi]>=1.1.1, <2" ], - "snowflake": [ - "snowflake-sqlalchemy==1.2.4" - ], # PINNED! 1.2.5 introduced breaking changes requiring sqlalchemy>=1.4.0 + "snowflake": ["snowflake-sqlalchemy>=1.2.4, <2"], + "spark": ["pyhive[hive]>=0.6.5", "tableschema", "thrift>=0.14.1, <1.0.0"], "teradata": ["teradatasql>=16.20.0.23"], - "thumbnails": ["Pillow>=9.0.1, <10.0.0"], + "thumbnails": ["Pillow>=9.3.0, <10.0.0"], "vertica": ["sqlalchemy-vertica-python>=0.5.9, < 0.6"], "netezza": ["nzalchemy>=11.0.2"], }, @@ -179,5 +188,7 @@ def get_git_sha() -> str: classifiers=[ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ], ) diff --git a/superset-embedded-sdk/README.md b/superset-embedded-sdk/README.md index 93b0aa4c09e63..7e05d94a6ce1d 100644 --- a/superset-embedded-sdk/README.md +++ b/superset-embedded-sdk/README.md @@ -40,7 +40,12 @@ embedDashboard({ supersetDomain: "https://superset.example.com", mountPoint: document.getElementById("my-superset-container"), // any html element that can contain an iframe fetchGuestToken: () => fetchGuestTokenFromBackend(), - dashboardUiConfig: { hideTitle: true }, // dashboard UI config: hideTitle, hideTab, hideChartControls (optional) + dashboardUiConfig: { // dashboard UI config: hideTitle, hideTab, hideChartControls, filters.visible, filters.expanded (optional) + hideTitle: true, + filters: { + expanded: true, + } + }, }); ``` diff --git a/superset-embedded-sdk/package-lock.json b/superset-embedded-sdk/package-lock.json index 55c2474f25c0f..826fb282c9e28 100644 --- a/superset-embedded-sdk/package-lock.json +++ b/superset-embedded-sdk/package-lock.json @@ -1,15 +1,16 @@ { "name": "@superset-ui/embedded-sdk", - "version": "0.1.0-alpha.7", + "version": "0.1.0-alpha.8", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@superset-ui/embedded-sdk", - "version": "0.1.0-alpha.7", + "version": "0.1.0-alpha.8", "license": "Apache-2.0", "dependencies": { - "@superset-ui/switchboard": "^0.18.26-0" + "@superset-ui/switchboard": "^0.18.26-0", + "jwt-decode": "^3.1.2" }, "devDependencies": { "@babel/cli": "^7.16.8", @@ -2376,6 +2377,64 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -6423,13 +6482,10 @@ "dev": 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==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, "bin": { "json5": "lib/cli.js" }, @@ -6437,6 +6493,11 @@ "node": ">=6" } }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -6493,9 +6554,9 @@ } }, "node_modules/loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -6507,9 +6568,9 @@ } }, "node_modules/loader-utils/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -6635,9 +6696,9 @@ } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -7497,13 +7558,14 @@ } }, "node_modules/terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -7511,14 +7573,6 @@ }, "engines": { "node": ">=10" - }, - "peerDependencies": { - "acorn": "^8.5.0" - }, - "peerDependenciesMeta": { - "acorn": { - "optional": true - } } }, "node_modules/terser-webpack-plugin": { @@ -7570,15 +7624,6 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -9833,6 +9878,55 @@ } } }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -12943,13 +13037,15 @@ "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==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" }, "kind-of": { "version": "6.0.3", @@ -12992,9 +13088,9 @@ "dev": true }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -13003,9 +13099,9 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -13108,9 +13204,9 @@ "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -13766,13 +13862,14 @@ } }, "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "dependencies": { @@ -13781,12 +13878,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true } } }, diff --git a/superset-embedded-sdk/package.json b/superset-embedded-sdk/package.json index 49debb4ad321f..055f44191a7e8 100644 --- a/superset-embedded-sdk/package.json +++ b/superset-embedded-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@superset-ui/embedded-sdk", - "version": "0.1.0-alpha.7", + "version": "0.1.0-alpha.8", "description": "SDK for embedding resources from Superset into your own application", "access": "public", "keywords": [ @@ -33,7 +33,8 @@ "last 3 edge versions" ], "dependencies": { - "@superset-ui/switchboard": "^0.18.26-0" + "@superset-ui/switchboard": "^0.18.26-0", + "jwt-decode": "^3.1.2" }, "devDependencies": { "@babel/cli": "^7.16.8", diff --git a/superset-embedded-sdk/src/const.ts b/superset-embedded-sdk/src/const.ts index e887974520359..72eba8525d758 100644 --- a/superset-embedded-sdk/src/const.ts +++ b/superset-embedded-sdk/src/const.ts @@ -18,3 +18,7 @@ */ export const IFRAME_COMMS_MESSAGE_TYPE = "__embedded_comms__"; +export const DASHBOARD_UI_FILTER_CONFIG_URL_PARAM_KEY: { [index: string]: any } = { + visible: "show_filters", + expanded: "expand_filters", +} diff --git a/superset-embedded-sdk/src/guestTokenRefresh.ts b/superset-embedded-sdk/src/guestTokenRefresh.ts index 214e91a1c33e4..101c4d9e93930 100644 --- a/superset-embedded-sdk/src/guestTokenRefresh.ts +++ b/superset-embedded-sdk/src/guestTokenRefresh.ts @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import jwt_decode from "jwt-decode"; export const REFRESH_TIMING_BUFFER_MS = 5000 // refresh guest token early to avoid failed superset requests export const MIN_REFRESH_WAIT_MS = 10000 // avoid blasting requests as fast as the cpu can handle @@ -23,7 +24,7 @@ export const DEFAULT_TOKEN_EXP_MS = 300000 // (5 min) used only when parsing gue // when do we refresh the guest token? export function getGuestTokenRefreshTiming(currentGuestToken: string) { - const parsedJwt = JSON.parse(Buffer.from(currentGuestToken.split('.')[1], 'base64').toString()); + const parsedJwt = jwt_decode<Record<string, any>>(currentGuestToken); // if exp is int, it is in seconds, but Date() takes milliseconds const exp = new Date(/[^0-9\.]/g.test(parsedJwt.exp) ? parsedJwt.exp : parseFloat(parsedJwt.exp) * 1000); const isValidDate = exp.toString() !== 'Invalid Date'; diff --git a/superset-embedded-sdk/src/index.ts b/superset-embedded-sdk/src/index.ts index 32b02641e00d2..56a07e5544c1d 100644 --- a/superset-embedded-sdk/src/index.ts +++ b/superset-embedded-sdk/src/index.ts @@ -17,7 +17,10 @@ * under the License. */ -import { IFRAME_COMMS_MESSAGE_TYPE } from './const'; +import { + DASHBOARD_UI_FILTER_CONFIG_URL_PARAM_KEY, + IFRAME_COMMS_MESSAGE_TYPE +} from './const'; // We can swap this out for the actual switchboard package once it gets published import { Switchboard } from '@superset-ui/switchboard'; @@ -34,6 +37,11 @@ export type UiConfigType = { hideTitle?: boolean hideTab?: boolean hideChartControls?: boolean + filters?: { + [key: string]: boolean | undefined + visible?: boolean + expanded?: boolean + } } export type EmbedDashboardParams = { @@ -45,7 +53,7 @@ export type EmbedDashboardParams = { mountPoint: HTMLElement /** A function to fetch a guest token from the Host App's backend server */ fetchGuestToken: GuestTokenFetchFn - /** The dashboard UI config: hideTitle, hideTab, hideChartControls **/ + /** The dashboard UI config: hideTitle, hideTab, hideChartControls, filters.visible, filters.expanded **/ dashboardUiConfig?: UiConfigType /** Are we in debug mode? */ debug?: boolean @@ -58,6 +66,8 @@ export type Size = { export type EmbeddedDashboard = { getScrollSize: () => Promise<Size> unmount: () => void + getDashboardPermalink: (anchor: string) => Promise<string> + getActiveTabs: () => Promise<string[]> } /** @@ -99,15 +109,23 @@ export async function embedDashboard({ return new Promise(resolve => { const iframe = document.createElement('iframe'); const dashboardConfig = dashboardUiConfig ? `?uiConfig=${calculateConfig()}` : "" - - // setup the iframe's sandbox configuration + const filterConfig = dashboardUiConfig?.filters || {} + const filterConfigKeys = Object.keys(filterConfig) + const filterConfigUrlParams = filterConfigKeys.length > 0 + ? "&" + + filterConfigKeys + .map(key => DASHBOARD_UI_FILTER_CONFIG_URL_PARAM_KEY[key] + '=' + filterConfig[key]).join('&') + : "" + + // set up the iframe's sandbox configuration iframe.sandbox.add("allow-same-origin"); // needed for postMessage to work iframe.sandbox.add("allow-scripts"); // obviously the iframe needs scripts iframe.sandbox.add("allow-presentation"); // for fullscreen charts iframe.sandbox.add("allow-downloads"); // for downloading charts as image - // add these ones if it turns out we need them: + iframe.sandbox.add("allow-forms"); // for forms to submit + iframe.sandbox.add("allow-popups"); // for exporting charts as csv + // add these if it turns out we need them: // iframe.sandbox.add("allow-top-navigation"); - // iframe.sandbox.add("allow-forms"); // add the event listener before setting src, to be 100% sure that we capture the load event iframe.addEventListener('load', () => { @@ -131,13 +149,13 @@ export async function embedDashboard({ resolve(new Switchboard({ port: ourPort, name: 'superset-embedded-sdk', debug })); }); - iframe.src = `${supersetDomain}/embedded/${id}${dashboardConfig}`; + iframe.src = `${supersetDomain}/embedded/${id}${dashboardConfig}${filterConfigUrlParams}`; mountPoint.replaceChildren(iframe); log('placed the iframe') }); } - const [guestToken, ourPort] = await Promise.all([ + const [guestToken, ourPort]: [string, Switchboard] = await Promise.all([ fetchGuestToken(), mountIframe(), ]); @@ -159,9 +177,14 @@ export async function embedDashboard({ } const getScrollSize = () => ourPort.get<Size>('getScrollSize'); + const getDashboardPermalink = (anchor: string) => + ourPort.get<string>('getDashboardPermalink', { anchor }); + const getActiveTabs = () => ourPort.get<string[]>('getActiveTabs') return { getScrollSize, unmount, + getDashboardPermalink, + getActiveTabs, }; } diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js index 01ef839966b13..6eebb0d2dfe29 100644 --- a/superset-frontend/.eslintrc.js +++ b/superset-frontend/.eslintrc.js @@ -96,6 +96,7 @@ module.exports = { '@typescript-eslint/no-non-null-assertion': 0, // disabled temporarily '@typescript-eslint/explicit-function-return-type': 0, '@typescript-eslint/explicit-module-boundary-types': 0, // re-enable up for discussion + '@typescript-eslint/prefer-optional-chain': 2, camelcase: 0, 'class-methods-use-this': 0, 'func-names': 0, @@ -115,6 +116,7 @@ module.exports = { 'jsx-a11y/anchor-is-valid': 1, 'jsx-a11y/click-events-have-key-events': 0, // re-enable up for discussion 'jsx-a11y/mouse-events-have-key-events': 0, // re-enable up for discussion + 'max-classes-per-file': 0, 'new-cap': 0, 'no-bitwise': 0, 'no-continue': 0, diff --git a/superset-frontend/.storybook/main.js b/superset-frontend/.storybook/main.js index caa68983579ab..35783dd85d286 100644 --- a/superset-frontend/.storybook/main.js +++ b/superset-frontend/.storybook/main.js @@ -24,7 +24,8 @@ module.exports = { builder: 'webpack5', }, stories: [ - '../src/@(components|common|filters|explore)/**/*.stories.@(t|j)sx', + '../src/@(components|common|filters|explore|views|dashboard)/**/*.stories.@(tsx|jsx)', + '../src/@(components|common|filters|explore|views|dashboard)/**/*.*.@(mdx)', ], addons: [ '@storybook/addon-essentials', @@ -47,6 +48,6 @@ module.exports = { plugins: [...config.plugins, ...customConfig.plugins], }), typescript: { - reactDocgen: 'none', + reactDocgen: 'react-docgen-typescript', }, }; diff --git a/superset-frontend/.storybook/preview.jsx b/superset-frontend/.storybook/preview.jsx index 7deb1e608c68b..967e96a40ddc3 100644 --- a/superset-frontend/.storybook/preview.jsx +++ b/superset-frontend/.storybook/preview.jsx @@ -26,6 +26,7 @@ import { combineReducers, createStore, applyMiddleware, compose } from 'redux'; import thunk from 'redux-thunk'; import { Provider } from 'react-redux'; import reducerIndex from 'spec/helpers/reducerIndex'; +import { GlobalStyles } from '../src/GlobalStyles'; import 'src/theme.ts'; import './storybook.css'; @@ -37,7 +38,12 @@ const store = createStore( ); const themeDecorator = Story => ( - <ThemeProvider theme={supersetTheme}>{<Story />}</ThemeProvider> + <ThemeProvider theme={supersetTheme}> + <> + <GlobalStyles /> + <Story /> + </> + </ThemeProvider> ); const providerDecorator = Story => ( @@ -63,7 +69,23 @@ addParameters({ }, options: { storySort: { - method: 'alphabetical', + order: [ + 'Superset Frontend', + ['Controls', 'Display', 'Feedback', 'Input', '*'], + ['Overview', 'Examples', '*'], + 'Design System', + [ + 'Introduction', + 'Foundations', + 'Components', + ['Overview', 'Examples', '*'], + 'Patterns', + '*', + ], + ['Overview', 'Examples', '*'], + '*', + ], }, }, + controls: { expanded: true, sort: 'alpha' }, }); diff --git a/superset-frontend/babel.config.js b/superset-frontend/babel.config.js index 11bed49eee23b..774e75e84b60a 100644 --- a/superset-frontend/babel.config.js +++ b/superset-frontend/babel.config.js @@ -90,17 +90,16 @@ module.exports = { ], }, production: { - plugins: [ - [ - 'babel-plugin-jsx-remove-data-test-id', - { - attributes: 'data-test', - }, - ], - ], + plugins: [], }, testableProduction: { plugins: [], }, }, + overrides: [ + { + test: './plugins/plugin-chart-handlebars/node_modules/just-handlebars-helpers/*', + sourceType: 'unambiguous', + }, + ], }; diff --git a/superset-frontend/cypress-base/applitools.config.js b/superset-frontend/cypress-base/applitools.config.js index fc963a1c81fa7..507bcea035782 100644 --- a/superset-frontend/cypress-base/applitools.config.js +++ b/superset-frontend/cypress-base/applitools.config.js @@ -20,9 +20,10 @@ module.exports = { apiKey: process.env.APPLITOOLS_API_KEY, batchId: process.env.APPLITOOLS_BATCH_ID, batchName: process.env.APPLITOOLS_BATCH_NAME, - browser: [{ width: 1000, height: 660, name: 'chrome' }], + browser: [{ width: 1920, height: 1080, name: 'chrome' }], failCypressOnDiff: false, isDisabled: false, showLogs: false, testConcurrency: 10, + ignoreCaret: true, }; diff --git a/superset-frontend/cypress-base/cypress.json b/superset-frontend/cypress-base/cypress.json index f9729be1c3c91..6894714ba66c2 100644 --- a/superset-frontend/cypress-base/cypress.json +++ b/superset-frontend/cypress-base/cypress.json @@ -5,7 +5,7 @@ "numTestsKeptInMemory": 0, "experimentalFetchPolyfill": true, "requestTimeout": 10000, - "ignoreTestFiles": ["**/!(*.test.js|*.test.ts)"], + "ignoreTestFiles": ["**/!(*.test.js|*.test.ts)", "*.applitools.test.ts"], "video": false, "videoUploadOnPasses": false, "viewportWidth": 1280, diff --git a/superset-frontend/cypress-base/cypress/fixtures/charts.json b/superset-frontend/cypress-base/cypress/fixtures/charts.json new file mode 100644 index 0000000000000..5781fce81e728 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/fixtures/charts.json @@ -0,0 +1,42 @@ +[ + { + "slice_name": "1 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 2, + "datasource_type": "table", + "params": "{\"viz_type\":\"line\",\"metrics\":[\"count\"]}" + }, + { + "slice_name": "2 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 2, + "datasource_type": "table", + "params": "{\"viz_type\":\"line\",\"metrics\":[\"count\"]}" + }, + { + "slice_name": "3 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 2, + "datasource_type": "table", + "params": "{\"viz_type\":\"line\",\"metrics\":[\"count\"]}" + }, + { + "slice_name": "4 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 2, + "datasource_type": "table", + "params": "{\"viz_type\":\"line\",\"metrics\":[\"count\"]}" + } +] diff --git a/superset-frontend/cypress-base/cypress/fixtures/dashboards.json b/superset-frontend/cypress-base/cypress/fixtures/dashboards.json new file mode 100644 index 0000000000000..e4bd57971aeef --- /dev/null +++ b/superset-frontend/cypress-base/cypress/fixtures/dashboards.json @@ -0,0 +1,46 @@ +[ + { + "dashboard_title": "1 - Sample dashboard", + "slug": "1-sample-dashboard" + }, + { + "dashboard_title": "2 - Sample dashboard", + "slug": "2-sample-dashboard" + }, + { + "dashboard_title": "3 - Sample dashboard", + "slug": "3-sample-dashboard" + }, + { + "dashboard_title": "4 - Sample dashboard", + "slug": "4-sample-dashboard" + }, + { + "dashboard_title": "5 - Sample dashboard", + "slug": "5-sample-dashboard" + }, + { + "dashboard_title": "6 - Sample dashboard", + "slug": "6-sample-dashboard" + }, + { + "dashboard_title": "7 - Sample dashboard", + "slug": "7-sample-dashboard" + }, + { + "dashboard_title": "8 - Sample dashboard", + "slug": "8-sample-dashboard" + }, + { + "dashboard_title": "9 - Sample dashboard", + "slug": "9-sample-dashboard" + }, + { + "dashboard_title": "10 - Sample dashboard", + "slug": "10-sample-dashboard" + }, + { + "dashboard_title": "11 - Sample dashboard", + "slug": "11-sample-dashboard" + } +] diff --git a/superset-frontend/cypress-base/cypress/fixtures/example.json b/superset-frontend/cypress-base/cypress/fixtures/example.json deleted file mode 100644 index 02e4254378e97..0000000000000 --- a/superset-frontend/cypress-base/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts index 97bf2cc9be854..a695541ceecd9 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts @@ -16,31 +16,24 @@ * specific language governing permissions and limitations * under the License. */ -import { ALERT_LIST } from './alert_report.helper'; +import { ALERT_LIST } from 'cypress/utils/urls'; -describe('alert list view', () => { - beforeEach(() => { - cy.login(); - }); - - afterEach(() => { - cy.eyesClose(); +describe('Alert list view', () => { + before(() => { + cy.visit(ALERT_LIST); }); it('should load alert lists', () => { - cy.visit(ALERT_LIST); - - cy.get('[data-test="listview-table"]').should('be.visible'); - // check alert list view header - cy.get('[data-test="sort-header"]').eq(1).contains('Last run'); - cy.get('[data-test="sort-header"]').eq(2).contains('Name'); - cy.get('[data-test="sort-header"]').eq(3).contains('Schedule'); - cy.get('[data-test="sort-header"]').eq(4).contains('Notification method'); - cy.get('[data-test="sort-header"]').eq(5).contains('Created by'); - cy.get('[data-test="sort-header"]').eq(6).contains('Owners'); - cy.get('[data-test="sort-header"]').eq(7).contains('Modified'); - // TODO: this assert is flaky, we need to find a way to make it work consistenly - // cy.get('[data-test="sort-header"]').eq(7).contains('Active'); - // cy.get('[data-test="sort-header"]').eq(8).contains('Actions'); + cy.getBySel('listview-table').should('be.visible'); + cy.getBySel('sort-header').eq(1).contains('Last run'); + cy.getBySel('sort-header').eq(2).contains('Name'); + cy.getBySel('sort-header').eq(3).contains('Schedule'); + cy.getBySel('sort-header').eq(4).contains('Notification method'); + cy.getBySel('sort-header').eq(5).contains('Created by'); + cy.getBySel('sort-header').eq(6).contains('Owners'); + cy.getBySel('sort-header').eq(7).contains('Modified'); + cy.getBySel('sort-header').eq(8).contains('Active'); + // TODO Cypress won't recognize the Actions column + // cy.getBySel('sort-header').eq(9).contains('Actions'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts index ea117c507a6d6..e267d76f6f7ed 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts @@ -16,31 +16,24 @@ * specific language governing permissions and limitations * under the License. */ -import { REPORT_LIST } from './alert_report.helper'; +import { REPORT_LIST } from 'cypress/utils/urls'; -describe('report list view', () => { - beforeEach(() => { - cy.login(); - }); - - afterEach(() => { - cy.eyesClose(); +describe('Report list view', () => { + before(() => { + cy.visit(REPORT_LIST); }); it('should load report lists', () => { - cy.visit(REPORT_LIST); - - cy.get('[data-test="listview-table"]').should('be.visible'); - // check report list view header - cy.get('[data-test="sort-header"]').eq(1).contains('Last run'); - cy.get('[data-test="sort-header"]').eq(2).contains('Name'); - cy.get('[data-test="sort-header"]').eq(3).contains('Schedule'); - cy.get('[data-test="sort-header"]').eq(4).contains('Notification method'); - cy.get('[data-test="sort-header"]').eq(5).contains('Created by'); - cy.get('[data-test="sort-header"]').eq(6).contains('Owners'); - cy.get('[data-test="sort-header"]').eq(7).contains('Modified'); - // TODO: this assert is flaky, we need to find a way to make it work consistenly - // cy.get('[data-test="sort-header"]').eq(7).contains('Active'); - // cy.get('[data-test="sort-header"]').eq(8).contains('Actions'); + cy.getBySel('listview-table').should('be.visible'); + cy.getBySel('sort-header').eq(1).contains('Last run'); + cy.getBySel('sort-header').eq(2).contains('Name'); + cy.getBySel('sort-header').eq(3).contains('Schedule'); + cy.getBySel('sort-header').eq(4).contains('Notification method'); + cy.getBySel('sort-header').eq(5).contains('Created by'); + cy.getBySel('sort-header').eq(6).contains('Owners'); + cy.getBySel('sort-header').eq(7).contains('Modified'); + cy.getBySel('sort-header').eq(8).contains('Active'); + // TODO Cypress won't recognize the Actions column + // cy.getBySel('sort-header').eq(9).contains('Actions'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/card_view.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/card_view.test.ts deleted file mode 100644 index 1335fcb422204..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/card_view.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { CHART_LIST } from './chart_list.helper'; - -describe('chart card view', () => { - beforeEach(() => { - cy.login(); - cy.visit(CHART_LIST); - cy.get('[aria-label="card-view"]').click(); - }); - - it('should load cards', () => { - cy.get('[data-test="chart-list-view"]'); - cy.get('[data-test="styled-card"]').should('be.visible'); - cy.get('[data-test="styled-card"]').should('have.length', 25); - }); - - it('should allow to favorite/unfavorite chart card', () => { - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('not.exist'); - cy.get("[data-test='card-actions']") - .find("[aria-label='favorite-unselected']") - .first() - .click(); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('be.visible'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('not.exist'); - - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('not.exist'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .click(); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('be.visible'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('not.exist'); - }); - - xit('should sort correctly', () => { - // sort Alphabetical - cy.get('.Select__control').last().should('be.visible'); - cy.get('.Select__control').last().click(); - cy.get('.Select__menu').contains('Alphabetical').click(); - cy.get('[data-test="chart-list-view"]').should('be.visible'); - cy.get('[data-test="styled-card"]').first().contains('% Rural'); - - // sort Recently Modified - cy.get('.Select__control').last().should('be.visible'); - cy.get('.Select__control').last().click(); - cy.get('.Select__menu').contains('Recently Modified').click(); - cy.get('[data-test="chart-list-view"]').should('be.visible'); - // TODO - next line is/was flaky - cy.get('[data-test="styled-card"]').first().contains('Unicode Cloud'); - cy.get('[data-test="styled-card"]') - .last() - .contains('Life Expectancy VS Rural %'); - }); - - // flaky - xit('should delete correctly', () => { - // show delete modal - cy.get('[data-test="more-horiz"]').last().trigger('mouseover'); - cy.get('[data-test="chart-list-delete-option"]') - .last() - .should('be.visible'); - cy.get('[data-test="chart-list-delete-option"]') - .last() - .contains('Delete') - .click(); - cy.get('[data-test="Please Confirm-modal"]').should('be.visible'); - cy.get('[data-test="modal-confirm-button"]').should( - 'have.attr', - 'disabled', - ); - cy.get('[data-test="Please Confirm-modal"]').should('be.visible'); - cy.get("[data-test='delete-modal-input']").type('DELETE'); - cy.get('[data-test="modal-confirm-button"]').should( - 'not.have.attr', - 'disabled', - ); - cy.get('[data-test="modal-cancel-button"]').click(); - }); - - // flaky - xit('should edit correctly', () => { - // show edit modal - cy.get('[data-test="more-horiz"]').last().trigger('mouseover'); - cy.get('[data-test="chart-list-edit-option"]').last().should('be.visible'); - cy.get('[data-test="chart-list-edit-option"]').last().click(); - cy.get('[data-test="properties-edit-modal"]').should('be.visible'); - cy.get('[data-test="properties-modal-name-input"]').should( - 'not.have.value', - ); - cy.get('[data-test="properties-modal-cancel-button"]') - .contains('Cancel') - .click(); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts index f858f03f5f4b3..92ad94bb7da69 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts @@ -16,11 +16,10 @@ * specific language governing permissions and limitations * under the License. */ -import { CHART_LIST } from './chart_list.helper'; +import { CHART_LIST } from 'cypress/utils/urls'; describe('charts list view', () => { beforeEach(() => { - cy.login(); cy.visit(CHART_LIST); }); @@ -33,7 +32,7 @@ describe('charts list view', () => { cy.eyesOpen({ testName: 'Charts list-view', }); - cy.eyesCheckWindow('Charts loaded'); + cy.eyesCheckWindow('Charts list-view loaded'); }); it('should load the Charts card list', () => { @@ -41,6 +40,6 @@ describe('charts list view', () => { cy.eyesOpen({ testName: 'Charts card-view', }); - cy.eyesCheckWindow('Charts loaded'); + cy.eyesCheckWindow('Charts card-view loaded'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts index 4466cc2ad5899..acd11669bea18 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts @@ -16,119 +16,42 @@ * specific language governing permissions and limitations * under the License. */ -import { CHART_LIST } from './chart_list.helper'; +import { CHART_LIST } from 'cypress/utils/urls'; +import { setGridMode, clearAllInputs } from 'cypress/utils'; +import { setFilter } from '../explore/utils'; -describe('chart card view filters', () => { - beforeEach(() => { - cy.login(); +describe('Charts filters', () => { + before(() => { cy.visit(CHART_LIST); - cy.get('[aria-label="card-view"]').click(); - }); - - it('should filter by owners correctly', () => { - // filter by owners - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="styled-card"]').should('not.exist'); - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="styled-card"]').should('not.exist'); + setGridMode('card'); }); - it('should filter by created by correctly', () => { - // filter by created by - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('.ant-card').should('not.exist'); - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="styled-card"]').should('not.exist'); - }); - - xit('should filter by viz type correctly', () => { - // filter by viz type - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('.rc-virtual-list').contains('area').click({ timeout: 5000 }); - cy.get('[data-test="styled-card"]').its('length').should('be.gt', 0); - cy.get('[data-test="styled-card"]') - .contains("World's Pop Growth") - .should('be.visible'); - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('[data-test="filters-select"]').eq(2).type('world_map{enter}'); - cy.get('[data-test="styled-card"]').should('have.length', 1); - cy.get('[data-test="styled-card"]') - .contains('% Rural') - .should('be.visible'); - }); - - it('should filter by datasource correctly', () => { - // filter by datasource - cy.get('[data-test="filters-select"]').eq(3).click(); - cy.get('.rc-virtual-list').contains('unicode_test').click(); - cy.get('[data-test="styled-card"]').should('have.length', 1); - cy.get('[data-test="styled-card"]') - .contains('Unicode Cloud') - .should('be.visible'); - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('[data-test="filters-select"]') - .eq(2) - .type('energy_usage{enter}{enter}'); - cy.get('[data-test="styled-card"]').its('length').should('be.gt', 0); + beforeEach(() => { + clearAllInputs(); }); -}); -describe('chart list view filters', () => { - beforeEach(() => { - cy.login(); - cy.visit(CHART_LIST); - cy.get('[aria-label="list-view"]').click(); + it('should allow filtering by "Owner"', () => { + setFilter('Owner', 'alpha user'); + setFilter('Owner', 'admin user'); }); - it('should filter by owners correctly', () => { - // filter by owners - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); + it('should allow filtering by "Created by" correctly', () => { + setFilter('Created by', 'alpha user'); + setFilter('Created by', 'admin user'); }); - it('should filter by created by correctly', () => { - // filter by created by - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); + it('should allow filtering by "Chart type" correctly', () => { + setFilter('Chart type', 'Area Chart (legacy)'); + setFilter('Chart type', 'Bubble Chart'); }); - // this is flaky, but seems to fail along with the card view test of the same name - xit('should filter by viz type correctly', () => { - // filter by viz type - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('.rc-virtual-list').contains('area').click({ timeout: 5000 }); - cy.get('[data-test="table-row"]').its('length').should('be.gt', 0); - cy.get('[data-test="table-row"]') - .contains("World's Pop Growth") - .should('exist'); - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('[data-test="filters-select"]').eq(2).type('world_map{enter}'); - cy.get('[data-test="table-row"]').should('have.length', 1); - cy.get('[data-test="table-row"]').contains('% Rural').should('exist'); + it('should allow filtering by "Dataset" correctly', () => { + setFilter('Dataset', 'energy_usage'); + setFilter('Dataset', 'unicode_test'); }); - it('should filter by datasource correctly', () => { - // filter by datasource - cy.get('[data-test="filters-select"]').eq(3).click(); - cy.get('.rc-virtual-list').contains('unicode_test').click(); - cy.get('[data-test="table-row"]').should('have.length', 1); - cy.get('[data-test="table-row"]').contains('Unicode Cloud').should('exist'); - cy.get('[data-test="filters-select"]').eq(3).click(); - cy.get('[data-test="filters-select"]') - .eq(3) - .type('energy_usage{enter}{enter}'); - cy.get('[data-test="table-row"]').its('length').should('be.gt', 0); + it('should allow filtering by "Dashboards" correctly', () => { + setFilter('Dashboards', 'Unicode Test'); + setFilter('Dashboards', 'Tabbed Dashboard'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts new file mode 100644 index 0000000000000..460b2cc02b468 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts @@ -0,0 +1,294 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { CHART_LIST } from 'cypress/utils/urls'; +import { setGridMode, toggleBulkSelect } from 'cypress/utils'; +import { + setFilter, + interceptBulkDelete, + interceptUpdate, + interceptDelete, + visitSampleChartFromList, + saveChartToDashboard, + interceptFiltering, +} from '../explore/utils'; +import { interceptGet as interceptDashboardGet } from '../dashboard/utils'; + +function orderAlphabetical() { + setFilter('Sort', 'Alphabetical'); +} + +function openProperties() { + cy.get('[aria-label="more-vert"]').eq(1).click(); + cy.getBySel('chart-list-edit-option').click(); +} + +function openMenu() { + cy.get('[aria-label="more-vert"]').eq(1).click(); +} + +function confirmDelete() { + cy.getBySel('delete-modal-input').type('DELETE'); + cy.getBySel('modal-confirm-button').click(); +} + +function visitChartList() { + interceptFiltering(); + cy.visit(CHART_LIST); + cy.wait('@filtering'); +} + +describe('Charts list', () => { + describe.skip('Cross-referenced dashboards', () => { + beforeEach(() => { + cy.createSampleDashboards([0, 1, 2, 3]); + cy.createSampleCharts([0]); + visitChartList(); + }); + + it('should show the cross-referenced dashboards in the table cell', () => { + interceptDashboardGet(); + cy.getBySel('table-row') + .first() + .find('[data-test="table-row-cell"]') + .find('[data-test="crosslinks"]') + .should('be.empty'); + cy.getBySel('table-row') + .eq(10) + .find('[data-test="table-row-cell"]') + .find('[data-test="crosslinks"]') + .contains('Supported Charts Dashboard') + .invoke('removeAttr', 'target') + .click(); + cy.wait('@get'); + }); + + it('should show the newly added dashboards in a tooltip', () => { + interceptDashboardGet(); + visitSampleChartFromList('1 - Sample chart'); + saveChartToDashboard('1 - Sample dashboard'); + saveChartToDashboard('2 - Sample dashboard'); + saveChartToDashboard('3 - Sample dashboard'); + visitChartList(); + cy.getBySel('count-crosslinks').should('be.visible'); + cy.getBySel('crosslinks') + .first() + .trigger('mouseover') + .then(() => { + cy.get('.ant-tooltip') + .contains('3 - Sample dashboard') + .invoke('removeAttr', 'target') + .click(); + cy.wait('@get'); + }); + }); + }); + + describe('list mode', () => { + before(() => { + cy.createSampleDashboards([0, 1, 2, 3]); + cy.createSampleCharts([0]); + visitChartList(); + setGridMode('list'); + }); + + it('should load rows in list mode', () => { + cy.getBySel('listview-table').should('be.visible'); + cy.getBySel('sort-header').eq(1).contains('Chart'); + cy.getBySel('sort-header').eq(2).contains('Visualization type'); + cy.getBySel('sort-header').eq(3).contains('Dataset'); + // cy.getBySel('sort-header').eq(4).contains('Dashboards added to'); + cy.getBySel('sort-header').eq(4).contains('Modified by'); + cy.getBySel('sort-header').eq(5).contains('Last modified'); + cy.getBySel('sort-header').eq(6).contains('Created by'); + cy.getBySel('sort-header').eq(7).contains('Actions'); + }); + + it('should sort correctly in list mode', () => { + cy.getBySel('sort-header').eq(1).click(); + cy.getBySel('table-row').first().contains('% Rural'); + cy.getBySel('sort-header').eq(1).click(); + cy.getBySel('table-row').first().contains("World's Population"); + cy.getBySel('sort-header').eq(1).click(); + }); + + it('should bulk select in list mode', () => { + toggleBulkSelect(); + cy.get('#header-toggle-all').click(); + cy.get('[aria-label="checkbox-on"]').should('have.length', 26); + cy.getBySel('bulk-select-copy').contains('25 Selected'); + cy.getBySel('bulk-select-action') + .should('have.length', 2) + .then($btns => { + expect($btns).to.contain('Delete'); + expect($btns).to.contain('Export'); + }); + cy.getBySel('bulk-select-deselect-all').click(); + cy.get('[aria-label="checkbox-on"]').should('have.length', 0); + cy.getBySel('bulk-select-copy').contains('0 Selected'); + cy.getBySel('bulk-select-action').should('not.exist'); + }); + }); + + describe('card mode', () => { + before(() => { + visitChartList(); + setGridMode('card'); + }); + + it('should load rows in card mode', () => { + cy.getBySel('listview-table').should('not.exist'); + cy.getBySel('styled-card').should('have.length', 25); + }); + + it('should bulk select in card mode', () => { + toggleBulkSelect(); + cy.getBySel('styled-card').click({ multiple: true }); + cy.getBySel('bulk-select-copy').contains('25 Selected'); + cy.getBySel('bulk-select-action') + .should('have.length', 2) + .then($btns => { + expect($btns).to.contain('Delete'); + expect($btns).to.contain('Export'); + }); + cy.getBySel('bulk-select-deselect-all').click(); + cy.getBySel('bulk-select-copy').contains('0 Selected'); + cy.getBySel('bulk-select-action').should('not.exist'); + }); + + it('should sort in card mode', () => { + orderAlphabetical(); + cy.getBySel('styled-card').first().contains('% Rural'); + }); + }); + + describe('common actions', () => { + beforeEach(() => { + cy.createSampleCharts([0, 1, 2, 3]); + visitChartList(); + }); + + it('should allow to favorite/unfavorite', () => { + cy.intercept(`/superset/favstar/slice/*/select/`).as('select'); + cy.intercept(`/superset/favstar/slice/*/unselect/`).as('unselect'); + + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel('styled-card').first().contains('% Rural'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-unselected']") + .click(); + cy.wait('@select'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-selected']") + .click(); + cy.wait('@unselect'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-selected']") + .should('not.exist'); + }); + + it('should bulk delete correctly', () => { + interceptBulkDelete(); + toggleBulkSelect(); + + // bulk deletes in card-view + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel('styled-card').eq(1).contains('1 - Sample chart').click(); + cy.getBySel('styled-card').eq(2).contains('2 - Sample chart').click(); + cy.getBySel('bulk-select-action').eq(0).contains('Delete').click(); + confirmDelete(); + cy.wait('@bulkDelete'); + cy.getBySel('styled-card') + .eq(1) + .should('not.contain', '1 - Sample chart'); + cy.getBySel('styled-card') + .eq(2) + .should('not.contain', '2 - Sample chart'); + + // bulk deletes in list-view + setGridMode('list'); + cy.getBySel('table-row').eq(1).contains('3 - Sample chart'); + cy.getBySel('table-row').eq(2).contains('4 - Sample chart'); + cy.get('[data-test="table-row"] input[type="checkbox"]').eq(1).click(); + cy.get('[data-test="table-row"] input[type="checkbox"]').eq(2).click(); + cy.getBySel('bulk-select-action').eq(0).contains('Delete').click(); + confirmDelete(); + cy.wait('@bulkDelete'); + cy.getBySel('table-row').eq(1).should('not.contain', '3 - Sample chart'); + cy.getBySel('table-row').eq(2).should('not.contain', '4 - Sample chart'); + }); + + it('should delete correctly', () => { + interceptDelete(); + + // deletes in card-view + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel('styled-card').eq(1).contains('1 - Sample chart'); + openMenu(); + cy.getBySel('chart-list-delete-option').click(); + confirmDelete(); + cy.wait('@delete'); + cy.getBySel('styled-card') + .eq(1) + .should('not.contain', '1 - Sample chart'); + + // deletes in list-view + setGridMode('list'); + cy.getBySel('table-row').eq(1).contains('2 - Sample chart'); + cy.getBySel('trash').eq(1).click(); + confirmDelete(); + cy.wait('@delete'); + cy.getBySel('table-row').eq(1).should('not.contain', '2 - Sample chart'); + }); + + it('should edit correctly', () => { + interceptUpdate(); + + // edits in card-view + setGridMode('card'); + orderAlphabetical(); + cy.getBySel('styled-card').eq(1).contains('1 - Sample chart'); + + // change title + openProperties(); + cy.getBySel('properties-modal-name-input').type(' | EDITED'); + cy.get('button:contains("Save")').click(); + cy.wait('@update'); + cy.getBySel('styled-card').eq(1).contains('1 - Sample chart | EDITED'); + + // edits in list-view + setGridMode('list'); + cy.getBySel('edit-alt').eq(1).click(); + cy.getBySel('properties-modal-name-input') + .clear() + .type('1 - Sample chart'); + cy.get('button:contains("Save")').click(); + cy.wait('@update'); + cy.getBySel('table-row').eq(1).contains('1 - Sample chart'); + }); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts deleted file mode 100644 index 42313d78495f4..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { CHART_LIST } from './chart_list.helper'; - -describe('chart list view', () => { - beforeEach(() => { - cy.login(); - }); - - it('should load rows', () => { - cy.visit(CHART_LIST); - cy.get('[aria-label="list-view"]').click(); - - cy.get('[data-test="listview-table"]').should('be.visible'); - // check chart list view header - cy.get('[data-test="sort-header"]').eq(1).contains('Chart'); - cy.get('[data-test="sort-header"]').eq(2).contains('Visualization type'); - cy.get('[data-test="sort-header"]').eq(3).contains('Dataset'); - cy.get('[data-test="sort-header"]').eq(4).contains('Modified by'); - cy.get('[data-test="sort-header"]').eq(5).contains('Last modified'); - cy.get('[data-test="sort-header"]').eq(6).contains('Created by'); - cy.get('[data-test="sort-header"]').eq(7).contains('Actions'); - cy.get('[data-test="table-row"]').should('have.length', 25); - }); - - xit('should sort correctly', () => { - cy.get('[data-test="sort-header"]').eq(2).click(); - cy.get('[data-test="sort-header"]').eq(2).click(); - cy.get('[data-test="table-row"]') - .first() - .find('[data-test="table-row-cell"]') - .find('[data-test="cell-text"]') - .contains('Location of Current Developers'); - }); - - it('should bulk delete correctly', () => { - // Load the chart list order by name asc. - // This will ensure the tests stay consistent, and the - // same charts get deleted every time - cy.visit(CHART_LIST, { - qs: { - sortColumn: 'slice_name', - sortOrder: 'asc', - }, - }); - cy.get('[aria-label="list-view"]').click(); - - cy.get('[data-test="listview-table"]').should('be.visible'); - cy.get('[data-test="bulk-select"]').eq(0).click(); - cy.get('[aria-label="checkbox-off"]').eq(1).siblings('input').click(); - cy.get('[aria-label="checkbox-off"]').eq(2).siblings('input').click(); - cy.get('[data-test="bulk-select-action"]').eq(0).click(); - cy.get('[data-test="delete-modal-input"]').eq(0).type('DELETE'); - cy.get('[data-test="modal-confirm-button"]').eq(0).click(); - cy.get('[aria-label="checkbox-on"]').should('not.exist'); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/controls.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.controls.test.ts similarity index 92% rename from superset-frontend/cypress-base/cypress/integration/dashboard/controls.test.ts rename to superset-frontend/cypress-base/cypress/integration/dashboard/_skip.controls.test.ts index 961e71bfd6397..4a65d68cf5883 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/controls.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.controls.test.ts @@ -17,22 +17,21 @@ * under the License. */ import { - WORLD_HEALTH_CHARTS, - WORLD_HEALTH_DASHBOARD, waitForChartLoad, ChartSpec, getChartAliasesBySpec, -} from './dashboard.helper'; +} from 'cypress/utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; +import { WORLD_HEALTH_CHARTS } from './utils'; import { isLegacyResponse } from '../../utils/vizPlugins'; -describe('Dashboard top-level controls', () => { +describe.skip('Dashboard top-level controls', () => { beforeEach(() => { - cy.login(); cy.visit(WORLD_HEALTH_DASHBOARD); }); // flaky test - xit('should allow chart level refresh', () => { + it('should allow chart level refresh', () => { const mapSpec = WORLD_HEALTH_CHARTS.find( ({ viz }) => viz === 'world_map', ) as ChartSpec; @@ -58,7 +57,7 @@ describe('Dashboard top-level controls', () => { }); }); - xit('should allow dashboard level force refresh', () => { + it('should allow dashboard level force refresh', () => { // when charts are not start loading, for example, under a secondary tab, // should allow force refresh WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.filter.test.ts similarity index 91% rename from superset-frontend/cypress-base/cypress/integration/dashboard/filter.test.ts rename to superset-frontend/cypress-base/cypress/integration/dashboard/_skip.filter.test.ts index e1dd45cf3c30c..6ae5d1e5d6fe9 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.filter.test.ts @@ -16,21 +16,21 @@ * specific language governing permissions and limitations * under the License. */ -import { isLegacyResponse, parsePostForm } from 'cypress/utils'; import { - WORLD_HEALTH_CHARTS, - WORLD_HEALTH_DASHBOARD, + isLegacyResponse, + parsePostForm, getChartAliasesBySpec, waitForChartLoad, -} from './dashboard.helper'; +} from 'cypress/utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; +import { WORLD_HEALTH_CHARTS } from './utils'; -describe('Dashboard filter', () => { +describe.skip('Dashboard filter', () => { before(() => { - cy.login(); cy.visit(WORLD_HEALTH_DASHBOARD); }); - xit('should apply filter', () => { + it('should apply filter', () => { WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); getChartAliasesBySpec( WORLD_HEALTH_CHARTS.filter(({ viz }) => viz !== 'filter_box'), diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/key_value.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.key_value.test.ts similarity index 90% rename from superset-frontend/cypress-base/cypress/integration/dashboard/key_value.test.ts rename to superset-frontend/cypress-base/cypress/integration/dashboard/_skip.key_value.test.ts index 1738ea5bd3d0d..2fc640e86165b 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/key_value.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.key_value.test.ts @@ -17,21 +17,16 @@ * under the License. */ import qs from 'querystringify'; -import { - WORLD_HEALTH_DASHBOARD, - WORLD_HEALTH_CHARTS, - waitForChartLoad, -} from './dashboard.helper'; +import { waitForChartLoad } from 'cypress/utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; +import { WORLD_HEALTH_CHARTS } from './utils'; interface QueryString { native_filters_key: string; } -xdescribe('nativefilter url param key', () => { +describe.skip('nativefilter url param key', () => { // const urlParams = { param1: '123', param2: 'abc' }; - before(() => { - cy.login(); - }); let initialFilterKey: string; it('should have cachekey in nativefilter param', () => { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.url_params.test.ts similarity index 83% rename from superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.ts rename to superset-frontend/cypress-base/cypress/integration/dashboard/_skip.url_params.test.ts index 5f9ad7382e15c..686c9e7536c99 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.url_params.test.ts @@ -16,22 +16,17 @@ * specific language governing permissions and limitations * under the License. */ -import { parsePostForm, JsonObject } from 'cypress/utils'; -import { - WORLD_HEALTH_DASHBOARD, - WORLD_HEALTH_CHARTS, - waitForChartLoad, -} from './dashboard.helper'; +import { parsePostForm, JsonObject, waitForChartLoad } from 'cypress/utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; +import { WORLD_HEALTH_CHARTS } from './utils'; -describe('Dashboard form data', () => { +describe.skip('Dashboard form data', () => { const urlParams = { param1: '123', param2: 'abc' }; before(() => { - cy.login(); - cy.visit(WORLD_HEALTH_DASHBOARD, { qs: urlParams }); }); - xit('should apply url params to slice requests', () => { + it('should apply url params to slice requests', () => { cy.intercept('/api/v1/chart/data?*', request => { // TODO: export url params to chart data API request.body.queries.forEach((query: { url_params: JsonObject }) => { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/actions.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/actions.test.js new file mode 100644 index 0000000000000..8d520d9729898 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/actions.test.js @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { SAMPLE_DASHBOARD_1 } from 'cypress/utils/urls'; +import { interceptFav, interceptUnfav } from './utils'; + +describe('Dashboard actions', () => { + beforeEach(() => { + cy.createSampleDashboards([0]); + cy.visit(SAMPLE_DASHBOARD_1); + }); + + it('should allow to favorite/unfavorite dashboard', () => { + interceptFav(); + interceptUnfav(); + + cy.getBySel('dashboard-header-container') + .find("[aria-label='favorite-unselected']") + .click(); + cy.wait('@select'); + cy.getBySel('dashboard-header-container') + .find("[aria-label='favorite-selected']") + .click(); + cy.wait('@unselect'); + cy.getBySel('dashboard-header-container') + .find("[aria-label='favorite-selected']") + .should('not.exist'); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts index d492175a5e3a6..297702bce2507 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts @@ -16,15 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import { - waitForChartLoad, - WORLD_HEALTH_CHARTS, - WORLD_HEALTH_DASHBOARD, -} from './dashboard.helper'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; +import { waitForChartLoad } from 'cypress/utils'; +import { WORLD_HEALTH_CHARTS } from './utils'; describe('Dashboard load', () => { beforeEach(() => { - cy.login(); cy.visit(WORLD_HEALTH_DASHBOARD); WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts deleted file mode 100644 index 24eab4284f490..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { getChartAlias, Slice } from 'cypress/utils/vizPlugins'; -import { dashboardView } from 'cypress/support/directories'; - -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -export const WORLD_HEALTH_DASHBOARD = '/superset/dashboard/world_health/'; -export const testDashboard = '/superset/dashboard/538/'; -export const TABBED_DASHBOARD = '/superset/dashboard/tabbed_dash/'; - -export const testItems = { - dashboard: 'Cypress test Dashboard', - dataset: 'Vehicle Sales', - datasetForNativeFilter: 'wb_health_population', - chart: 'Cypress chart', - newChart: 'New Cypress Chart', - createdDashboard: 'New Dashboard', - defaultNameDashboard: '[ untitled dashboard ]', - newDashboardTitle: `Test dashboard [NEW TEST]`, - bulkFirstNameDashboard: 'First Dash', - bulkSecondNameDashboard: 'Second Dash', - worldBanksDataCopy: `World Bank's Data [copy]`, - filterType: { - value: 'Value', - numerical: 'Numerical range', - timeColumn: 'Time column', - timeGrain: 'Time grain', - timeRange: 'Time range', - }, - topTenChart: { - name: 'Most Populated Countries', - filterColumn: 'country_name', - filterColumnYear: 'year', - filterColumnRegion: 'region', - filterColumnCountryCode: 'country_code', - }, - filterDefaultValue: 'United States', - filterOtherCountry: 'China', - filterTimeGrain: 'Month', - filterTimeColumn: 'created', - filterNumericalColumn: 'SP_RUR_TOTL_ZS', -}; - -export const CHECK_DASHBOARD_FAVORITE_ENDPOINT = - '/superset/favstar/Dashboard/*/count'; - -export const WORLD_HEALTH_CHARTS = [ - { name: '% Rural', viz: 'world_map' }, - { name: 'Most Populated Countries', viz: 'table' }, - { name: 'Region Filter', viz: 'filter_box' }, - { name: "World's Population", viz: 'big_number' }, - { name: 'Growth Rate', viz: 'line' }, - { name: 'Rural Breakdown', viz: 'sunburst' }, - { name: "World's Pop Growth", viz: 'area' }, - { name: 'Life Expectancy VS Rural %', viz: 'bubble' }, - { name: 'Treemap', viz: 'treemap' }, - { name: 'Box plot', viz: 'box_plot' }, -] as const; - -/** Used to specify charts expected by the test suite */ -export interface ChartSpec { - name: string; - viz: string; -} - -export function getChartGridComponent({ name, viz }: ChartSpec) { - return cy - .get(`[data-test="chart-grid-component"][data-test-chart-name="${name}"]`) - .should('have.attr', 'data-test-viz-type', viz); -} - -export function waitForChartLoad(chart: ChartSpec) { - return getChartGridComponent(chart).then(gridComponent => { - const chartId = gridComponent.attr('data-test-chart-id'); - // the chart should load in under half a minute - return ( - cy - // this id only becomes visible when the chart is loaded - .get(`[data-test="chart-grid-component"] #chart-id-${chartId}`, { - timeout: 30000, - }) - .should('be.visible') - // return the chart grid component - .then(() => gridComponent) - ); - }); -} - -const toSlicelike = ($chart: JQuery<HTMLElement>): Slice => ({ - slice_id: parseInt($chart.attr('data-test-chart-id')!, 10), - form_data: { - viz_type: $chart.attr('data-test-viz-type')!, - }, -}); - -export function getChartAliasBySpec(chart: ChartSpec) { - return getChartGridComponent(chart).then($chart => - cy.wrap(getChartAlias(toSlicelike($chart))), - ); -} - -export function getChartAliasesBySpec(charts: readonly ChartSpec[]) { - const aliases: string[] = []; - charts.forEach(chart => - getChartAliasBySpec(chart).then(alias => { - aliases.push(alias); - }), - ); - // Wrapping the aliases is key. - // That way callers can chain off this function - // and actually get the list of aliases. - return cy.wrap(aliases); -} - -/** - * Drag an element and drop it to another element. - * Usage: - * drag(source).to(target); - */ -export function drag(selector: string, content: string | number | RegExp) { - const dataTransfer = { data: {} }; - return { - to(target: string | Cypress.Chainable) { - cy.get('.dragdroppable') - .contains(selector, content) - .trigger('mousedown', { which: 1 }) - .trigger('dragstart', { dataTransfer }) - .trigger('drag', {}); - - (typeof target === 'string' ? cy.get(target) : target) - .trigger('dragover', { dataTransfer }) - .trigger('drop', { dataTransfer }) - .trigger('dragend', { dataTransfer }) - .trigger('mouseup', { which: 1 }); - }, - }; -} - -export function resize(selector: string) { - return { - to(cordX: number, cordY: number) { - cy.get(selector) - .trigger('mousedown', { which: 1, force: true }) - .trigger('mousemove', { which: 1, cordX, cordY, force: true }) - .trigger('mouseup', { which: 1, force: true }); - }, - }; -} - -export function cleanUp() { - cy.deleteDashboardByName(testItems.dashboard); - cy.deleteDashboardByName(testItems.defaultNameDashboard); - cy.deleteDashboardByName(''); - cy.deleteDashboardByName(testItems.newDashboardTitle); - cy.deleteDashboardByName(testItems.bulkFirstNameDashboard); - cy.deleteDashboardByName(testItems.bulkSecondNameDashboard); - cy.deleteDashboardByName(testItems.createdDashboard); - cy.deleteDashboardByName(testItems.worldBanksDataCopy); - cy.deleteChartByName(testItems.chart); - cy.deleteChartByName(testItems.newChart); -} - -/** ************************************************************************ - * Copy dashboard for testing purpose - * @returns {None} - * @summary helper for copy dashboard for testing purpose - ************************************************************************* */ -export function copyTestDashboard(dashboard: string) { - cy.intercept('POST', '**/copy_dash/**').as('copy'); - cy.intercept('GET', '**/api/v1/dataset/**').as('datasetLoad'); - cy.intercept('**/api/v1/dashboard/?q=**').as('dashboardsList'); - cy.intercept('**/api/v1/dashboard/**').as('dashboard'); - cy.visit('dashboard/list/'); - cy.contains('Actions'); - cy.wait('@dashboardsList').then(xhr => { - const dashboards = xhr.response?.body.result; - /* eslint-disable no-unused-expressions */ - expect(dashboards).not.to.be.undefined; - const testDashboard = dashboards.find( - (d: { dashboard_title: string }) => d.dashboard_title === `${dashboard}`, - ); - cy.visit(testDashboard.url); - }); - cy.get(dashboardView.threeDotsMenuIcon).should('be.visible').click(); - cy.get(dashboardView.saveAsMenuOption).click(); - cy.get(dashboardView.saveModal.dashboardNameInput) - .should('be.visible') - .clear() - .type(testItems.dashboard); - cy.get(dashboardView.saveModal.saveButton).click(); - cy.wait('@copy', { timeout: 45000 }) - .its('response.statusCode') - .should('eq', 200); -} diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts new file mode 100644 index 0000000000000..2ab4966d57d08 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts @@ -0,0 +1,612 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { waitForChartLoad } from 'cypress/utils'; +import { SUPPORTED_CHARTS_DASHBOARD } from 'cypress/utils/urls'; +import { SUPPORTED_TIER1_CHARTS, SUPPORTED_TIER2_CHARTS } from './utils'; + +function interceptSamples() { + cy.intercept(`/datasource/samples*`).as('samples'); +} + +function openModalFromMenu(chartType: string) { + interceptSamples(); + + cy.get( + `[data-test-viz-type='${chartType}'] [aria-label='More Options']`, + ).click(); + cy.get('.ant-dropdown') + .not('.ant-dropdown-hidden') + .find("[role='menu'] [role='menuitem']") + .eq(5) + .should('contain', 'Drill to detail') + .click(); + cy.wait('@samples'); +} + +function openModalFromChartContext(targetMenuItem: string) { + interceptSamples(); + + cy.wait(500); + if (targetMenuItem.startsWith('Drill to detail by')) { + cy.get('.ant-dropdown') + .not('.ant-dropdown-hidden') + .first() + .find("[role='menu'] [role='menuitem'] [title='Drill to detail by']") + .trigger('mouseover'); + cy.wait(500); + cy.get('[data-test="drill-to-detail-by-submenu"]') + .not('.ant-dropdown-menu-hidden [data-test="drill-to-detail-by-submenu"]') + .find('[role="menuitem"]') + .contains(new RegExp(`^${targetMenuItem}$`)) + .first() + .click(); + } else { + cy.get('.ant-dropdown') + .not('.ant-dropdown-hidden') + .first() + .find("[role='menu'] [role='menuitem']") + .contains(new RegExp(`^${targetMenuItem}$`)) + .first() + .click(); + } + cy.getBySel('metadata-bar').should('be.visible'); + cy.wait('@samples'); +} + +function closeModal() { + cy.get('body').then($body => { + if ($body.find('[data-test="close-drilltodetail-modal"]').length) { + cy.getBySel('close-drilltodetail-modal').click({ force: true }); + } + }); +} + +function setTopLevelTab(tabName: string) { + cy.get("div#TABS-TOP div[role='tab']").contains(tabName).click(); +} + +function testTimeChart(vizType: string) { + interceptSamples(); + + cy.get(`[data-test-viz-type='${vizType}'] canvas`).then($canvas => { + cy.wrap($canvas) + .scrollIntoView() + .trigger('mousemove', 70, 93) + .rightclick(70, 93); + + openModalFromChartContext('Drill to detail by 1965'); + cy.getBySel('filter-val').should('contain', '1965'); + closeModal(); + + cy.wrap($canvas) + .scrollIntoView() + .trigger('mousemove', 70, 93) + .rightclick(70, 93); + + openModalFromChartContext('Drill to detail by boy'); + cy.getBySel('filter-val').should('contain', 'boy'); + closeModal(); + + cy.wrap($canvas) + .scrollIntoView() + .trigger('mousemove', 70, 93) + .rightclick(70, 93); + + openModalFromChartContext('Drill to detail by all'); + cy.getBySel('filter-val').first().should('contain', '1965'); + cy.getBySel('filter-val').eq(1).should('contain', 'boy'); + closeModal(); + + cy.wrap($canvas) + .scrollIntoView() + .trigger('mousemove', 70, 145) + .rightclick(70, 145); + openModalFromChartContext('Drill to detail by girl'); + cy.getBySel('filter-val').should('contain', 'girl'); + closeModal(); + + cy.wrap($canvas) + .scrollIntoView() + .trigger('mousemove', 70, 145) + .rightclick(70, 145); + openModalFromChartContext('Drill to detail by all'); + cy.getBySel('filter-val').first().should('contain', '1965'); + cy.getBySel('filter-val').eq(1).should('contain', 'girl'); + }); +} + +describe('Drill to detail modal', () => { + beforeEach(() => { + closeModal(); + }); + + describe('Tier 1 charts', () => { + before(() => { + cy.visit(SUPPORTED_CHARTS_DASHBOARD); + setTopLevelTab('Tier 1'); + SUPPORTED_TIER1_CHARTS.forEach(waitForChartLoad); + }); + + describe('Modal actions', () => { + it('opens the modal from the context menu', () => { + openModalFromMenu('big_number_total'); + + cy.get("[role='dialog'] .draggable-trigger").should( + 'contain', + 'Drill to detail: Big Number', + ); + }); + + it('refreshes the data', () => { + openModalFromMenu('big_number_total'); + // move to the last page + cy.get('.ant-pagination-item').eq(5).click(); + // skips error on pagination + cy.on('uncaught:exception', () => false); + cy.wait('@samples'); + // reload + cy.get("[aria-label='reload']").click(); + cy.wait('@samples'); + // make sure it started back from first page + cy.get('.ant-pagination-item-active').should('contain', '1'); + }); + + it('paginates', () => { + openModalFromMenu('big_number_total'); + // checking the data + cy.getBySel('row-count-label').should('contain', '75.7k rows'); + cy.get('.virtual-table-cell').should($rows => { + expect($rows).to.contain('Amy'); + }); + // checking the paginated data + cy.get('.ant-pagination-item') + .should('have.length', 6) + .should($pages => { + expect($pages).to.contain('1'); + expect($pages).to.contain('1514'); + }); + cy.get('.ant-pagination-item').eq(4).click(); + // skips error on pagination + cy.on('uncaught:exception', () => false); + cy.wait('@samples'); + cy.get('.virtual-table-cell').should($rows => { + expect($rows).to.contain('Kelly'); + }); + + // verify scroll top on pagination + cy.getBySelLike('Number-modal').find('.virtual-grid').scrollTo(0, 200); + + cy.get('.virtual-grid').contains('Juan').should('not.be.visible'); + + cy.get('.ant-pagination-item').eq(0).click(); + + cy.get('.virtual-grid').contains('Aaron').should('be.visible'); + }); + }); + + describe('Big number total', () => { + it('opens the modal with no filters', () => { + interceptSamples(); + + // opens the modal by clicking on the number on the chart + cy.get("[data-test-viz-type='big_number_total'] .header-line") + .scrollIntoView() + .rightclick(); + + openModalFromChartContext('Drill to detail'); + + cy.getBySel('filter-val').should('not.exist'); + }); + }); + + describe('Big number with trendline', () => { + it('opens the modal with the correct data', () => { + interceptSamples(); + + // opens the modal by clicking on the number + cy.get("[data-test-viz-type='big_number'] .header-line") + .scrollIntoView() + .rightclick(); + + openModalFromChartContext('Drill to detail'); + + cy.getBySel('filter-val').should('not.exist'); + + closeModal(); + + // opens the modal by clicking on the trendline + cy.get("[data-test-viz-type='big_number'] canvas").then($canvas => { + cy.wrap($canvas) + .scrollIntoView() + .trigger('mousemove', 1, 14) + .rightclick(1, 14); + + openModalFromChartContext('Drill to detail by 1965'); + + // checking the filter + cy.getBySel('filter-val').should('contain', '1965'); + }); + }); + }); + + describe('Table', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='table']") + .scrollIntoView() + .contains('boy') + .rightclick(); + + openModalFromChartContext('Drill to detail by boy'); + + cy.getBySel('filter-val').should('contain', 'boy'); + + closeModal(); + + cy.get("[data-test-viz-type='table']") + .scrollIntoView() + .contains('girl') + .rightclick(); + + openModalFromChartContext('Drill to detail by girl'); + + cy.getBySel('filter-val').should('contain', 'girl'); + }); + }); + + describe('Pivot Table V2', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='pivot_table_v2']") + .scrollIntoView() + .find('[role="gridcell"]') + .first() + .rightclick(); + + openModalFromChartContext('Drill to detail by boy'); + + cy.getBySel('filter-val').should('contain', 'boy'); + closeModal(); + + cy.get("[data-test-viz-type='pivot_table_v2']") + .scrollIntoView() + .find('[role="gridcell"]') + .first() + .rightclick(); + + openModalFromChartContext('Drill to detail by CA'); + + cy.getBySel('filter-val').should('contain', 'CA'); + closeModal(); + + cy.get("[data-test-viz-type='pivot_table_v2']") + .scrollIntoView() + .find('[role="gridcell"]') + .eq(3) + .rightclick(); + + openModalFromChartContext('Drill to detail by girl'); + + cy.getBySel('filter-val').should('contain', 'girl'); + closeModal(); + + cy.get("[data-test-viz-type='pivot_table_v2']") + .scrollIntoView() + .find('[role="gridcell"]') + .eq(3) + .rightclick(); + + openModalFromChartContext('Drill to detail by FL'); + + cy.getBySel('filter-val').should('contain', 'FL'); + closeModal(); + + cy.get("[data-test-viz-type='pivot_table_v2']") + .scrollIntoView() + .find('[role="gridcell"]') + .eq(3) + .rightclick(); + + openModalFromChartContext('Drill to detail by all'); + + cy.getBySel('filter-val').first().should('contain', 'girl'); + cy.getBySel('filter-val').eq(1).should('contain', 'FL'); + }); + }); + + describe('Time-Series Line Chart', () => { + it('opens the modal with the correct filters', () => { + testTimeChart('echarts_timeseries_line'); + }); + }); + + describe('Time-series Bar Chart', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='echarts_timeseries_bar'] canvas").then( + $canvas => { + cy.wrap($canvas).scrollIntoView().rightclick(70, 100); + + openModalFromChartContext('Drill to detail by 1965'); + cy.getBySel('filter-val').should('contain', '1965'); + closeModal(); + + cy.wrap($canvas).scrollIntoView().rightclick(70, 100); + + openModalFromChartContext('Drill to detail by boy'); + cy.getBySel('filter-val').should('contain', 'boy'); + closeModal(); + + cy.wrap($canvas).scrollIntoView().rightclick(70, 100); + + openModalFromChartContext('Drill to detail by all'); + cy.getBySel('filter-val').first().should('contain', '1965'); + cy.getBySel('filter-val').eq(1).should('contain', 'boy'); + closeModal(); + + cy.wrap($canvas).scrollIntoView().rightclick(72, 200); + + openModalFromChartContext('Drill to detail by girl'); + cy.getBySel('filter-val').should('contain', 'girl'); + }, + ); + }); + }); + + describe('Time-Series Area Chart', () => { + it('opens the modal with the correct filters', () => { + testTimeChart('echarts_area'); + }); + }); + + describe('Time-Series Scatter Chart', () => { + it('opens the modal with the correct filters', () => { + testTimeChart('echarts_timeseries_scatter'); + }); + }); + + describe('Pie', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + // opens the modal by clicking on the slice of the Pie chart + cy.get("[data-test-viz-type='pie'] canvas").then($canvas => { + cy.wrap($canvas).scrollIntoView().rightclick(130, 150); + + openModalFromChartContext('Drill to detail by girl'); + cy.getBySel('filter-val').should('contain', 'girl'); + closeModal(); + + cy.wrap($canvas).scrollIntoView().rightclick(230, 190); + + openModalFromChartContext('Drill to detail by boy'); + cy.getBySel('filter-val').should('contain', 'boy'); + }); + }); + }); + + describe('World Map', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='world_map'] svg").then($canvas => { + cy.wrap($canvas).scrollIntoView().rightclick(70, 150); + openModalFromChartContext('Drill to detail by USA'); + cy.getBySel('filter-val').should('contain', 'USA'); + closeModal(); + }); + cy.get("[data-test-viz-type='world_map'] svg").then($canvas => { + cy.wrap($canvas).scrollIntoView().rightclick(200, 140); + openModalFromChartContext('Drill to detail by SVK'); + cy.getBySel('filter-val').should('contain', 'SVK'); + }); + }); + }); + + describe('Bar Chart', () => { + it('opens the modal for unsupported chart without filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='dist_bar'] svg").then($canvas => { + cy.wrap($canvas).scrollIntoView().rightclick(70, 150); + openModalFromChartContext('Drill to detail'); + cy.getBySel('filter-val').should('not.exist'); + }); + }); + }); + }); + + describe('Tier 2 charts', () => { + before(() => { + cy.visit(SUPPORTED_CHARTS_DASHBOARD); + setTopLevelTab('Tier 2'); + SUPPORTED_TIER2_CHARTS.forEach(waitForChartLoad); + }); + + describe('Modal actions', () => { + it('clears filters', () => { + interceptSamples(); + + // opens the modal by clicking on the box on the chart + cy.get("[data-test-viz-type='box_plot'] canvas").then($canvas => { + const canvasWidth = $canvas.width() || 0; + const canvasHeight = $canvas.height() || 0; + const canvasCenterX = canvasWidth / 3; + const canvasCenterY = (canvasHeight * 5) / 6; + + cy.wrap($canvas) + .scrollIntoView() + .rightclick(canvasCenterX, canvasCenterY, { force: true }); + + openModalFromChartContext('Drill to detail by boy'); + + // checking the filter + cy.getBySel('filter-val').should('contain', 'boy'); + cy.getBySel('row-count-label').should('contain', '39.2k rows'); + cy.get('.ant-pagination-item') + .should('have.length', 6) + .then($pages => { + expect($pages).to.contain('1'); + expect($pages).to.contain('785'); + }); + + // close the filter and test that data was reloaded + cy.getBySel('filter-col').find("[aria-label='close']").click(); + cy.wait('@samples'); + cy.getBySel('row-count-label').should('contain', '75.7k rows'); + cy.get('.ant-pagination-item-active').should('contain', '1'); + cy.get('.ant-pagination-item') + .should('have.length', 6) + .then($pages => { + expect($pages).to.contain('1'); + expect($pages).to.contain('1514'); + }); + }); + }); + }); + + describe('Box plot', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='box_plot'] canvas").then($canvas => { + cy.wrap($canvas) + .scrollIntoView() + .trigger('mousemove', 135, 275) + .rightclick(135, 275); + + openModalFromChartContext('Drill to detail by boy'); + cy.getBySel('filter-val').should('contain', 'boy'); + closeModal(); + + cy.wrap($canvas) + .scrollIntoView() + .trigger('mousemove', 270, 280) + .rightclick(270, 280); + + openModalFromChartContext('Drill to detail by girl'); + cy.getBySel('filter-val').should('contain', 'girl'); + }); + }); + }); + + describe('Time-Series Generic Chart', () => { + it('opens the modal with the correct filters', () => { + testTimeChart('echarts_timeseries'); + }); + }); + + describe('Time-Series Smooth Chart', () => { + it('opens the modal with the correct filters', () => { + testTimeChart('echarts_timeseries_smooth'); + }); + }); + + describe('Time-Series Step Line Chart', () => { + it('opens the modal with the correct filters', () => { + testTimeChart('echarts_timeseries_step'); + }); + }); + + describe('Funnel Chart', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='funnel'] canvas").then($canvas => { + cy.wrap($canvas).scrollIntoView().rightclick(170, 90); + + openModalFromChartContext('Drill to detail by boy'); + cy.getBySel('filter-val').should('contain', 'boy'); + closeModal(); + + cy.wrap($canvas).scrollIntoView().rightclick(190, 250); + + openModalFromChartContext('Drill to detail by girl'); + cy.getBySel('filter-val').should('contain', 'girl'); + }); + }); + }); + + describe('Gauge Chart', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='gauge_chart'] canvas").then($canvas => { + cy.wrap($canvas).scrollIntoView().rightclick(135, 95); + + openModalFromChartContext('Drill to detail by boy'); + cy.getBySel('filter-val').should('contain', 'boy'); + closeModal(); + + cy.wrap($canvas).scrollIntoView().rightclick(95, 135); + + openModalFromChartContext('Drill to detail by girl'); + cy.getBySel('filter-val').should('contain', 'girl'); + }); + }); + }); + + describe('Mixed Chart', () => { + it('opens the modal with the correct filters', () => { + testTimeChart('mixed_timeseries'); + }); + }); + + describe('Radar Chart', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='radar'] canvas").then($canvas => { + cy.wrap($canvas).scrollIntoView().rightclick(180, 45); + + openModalFromChartContext('Drill to detail by boy'); + cy.getBySel('filter-val').should('contain', 'boy'); + closeModal(); + + cy.wrap($canvas).scrollIntoView().rightclick(180, 85); + + openModalFromChartContext('Drill to detail by girl'); + cy.getBySel('filter-val').should('contain', 'girl'); + }); + }); + }); + + describe('Treemap', () => { + it('opens the modal with the correct filters', () => { + interceptSamples(); + + cy.get("[data-test-viz-type='treemap_v2'] canvas").then($canvas => { + cy.wrap($canvas).scrollIntoView().rightclick(100, 30); + + openModalFromChartContext('Drill to detail by boy'); + cy.getBySel('filter-val').should('contain', 'boy'); + closeModal(); + + cy.wrap($canvas).scrollIntoView().rightclick(150, 250); + + openModalFromChartContext('Drill to detail by girl'); + cy.getBySel('filter-val').should('contain', 'girl'); + }); + }); + }); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js deleted file mode 100644 index 10b8a4a40de1f..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { WORLD_HEALTH_DASHBOARD, drag } from './dashboard.helper'; - -describe('Dashboard edit mode', () => { - beforeEach(() => { - cy.login(); - cy.visit(WORLD_HEALTH_DASHBOARD); - cy.get('.header-with-actions') - .find('[aria-label="Edit dashboard"]') - .click(); - }); - - it('remove, and add chart flow', () => { - // wait for box plot to appear - cy.get('[data-test="grid-container"]').find('.box_plot', { - timeout: 10000, - }); - const elementsCount = 10; - - cy.get('[data-test="dashboard-component-chart-holder"]') - .find('[data-test="dashboard-delete-component-button"]') - .last() - .then($el => { - cy.wrap($el).invoke('show').click(); - // box plot should be gone - cy.get('[data-test="grid-container"]') - .find('.box_plot') - .should('not.exist'); - }); - - // find box plot is available from list - cy.get('[data-test="dashboard-charts-filter-search-input"]').type( - 'Box plot', - ); - cy.get('[data-test="card-title"]').should('have.length', 1); - - drag('[data-test="card-title"]', 'Box plot').to( - '.grid-row.background--transparent:last', - ); - - // add back to dashboard - cy.get('[data-test="grid-container"]') - .find('.box_plot') - .should('be.visible'); - - // should show Save changes button - cy.get('[data-test="header-save-button"]').should('be.visible'); - - // undo first step and expect deleted item - cy.get('[data-test="undo-action"]').click(); - cy.get('[data-test="grid-container"]') - .find('[data-test="chart-container"]') - .should('have.length', elementsCount - 1); - - // Box plot chart should be gone - cy.get('[data-test="grid-container"]') - .find('.box_plot') - .should('not.exist'); - - // undo second step and expect initial items count - cy.get('[data-test="undo-action"]').click(); - cy.get('[data-test="grid-container"]') - .find('[data-test="chart-container"]') - .should('have.length', elementsCount); - cy.get('[data-test="card-title"]').contains('Box plot', { timeout: 5000 }); - - // save changes button should be disabled - cy.get('[data-test="header-save-button"]').should('be.disabled'); - - // no changes, can switch to view mode - cy.get('[data-test="dashboard-edit-actions"]') - .find('[data-test="discard-changes-button"]') - .should('be.visible') - .click(); - cy.get('.header-with-actions').within(() => { - cy.get('[data-test="dashboard-edit-actions"]').should('not.be.visible'); - cy.get('[aria-label="Edit dashboard"]').should('be.visible'); - }); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts deleted file mode 100644 index b3061cdb7d40a..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -// eslint-disable-next-line import/no-extraneous-dependencies -import * as ace from 'brace'; -import * as shortid from 'shortid'; -import { WORLD_HEALTH_DASHBOARD } from './dashboard.helper'; - -function selectColorScheme(color: string) { - // open color scheme dropdown - cy.get('.ant-modal-body') - .contains('Color scheme') - .parents('.ControlHeader') - .next('.ant-select') - .click() - .then($colorSelect => { - // select a new color scheme - cy.wrap($colorSelect).find(`[data-test="${color}"]`).click(); - }); -} - -function assertMetadata(text: string) { - const regex = new RegExp(text); - cy.get('.ant-modal-body') - .find('#json_metadata') - .should('be.visible') - .then(() => { - const metadata = cy.$$('#json_metadata')[0]; - - // cypress can read this locally, but not in ci - // so we have to use the ace module directly to fetch the value - expect(ace.edit(metadata).getValue()).to.match(regex); - }); -} - -function typeMetadata(text: string) { - cy.get('.ant-modal-body') - .find('#json_metadata') - .should('be.visible') - .type(text); -} - -function openAdvancedProperties() { - return cy - .get('.ant-modal-body') - .contains('Advanced') - .should('be.visible') - .click(); -} - -function openDashboardEditProperties() { - // open dashboard properties edit modal - cy.get( - '.header-with-actions .right-button-panel .ant-dropdown-trigger', - ).trigger('click', { - force: true, - }); - cy.get('[data-test=header-actions-menu]') - .contains('Edit properties') - .click({ force: true }); -} - -describe('Dashboard edit action', () => { - beforeEach(() => { - cy.login(); - cy.visit(WORLD_HEALTH_DASHBOARD); - cy.intercept(`/api/v1/dashboard/1`).as('dashboardGet'); - cy.get('.dashboard-grid', { timeout: 50000 }) - .should('be.visible') // wait for 50 secs to load dashboard - .then(() => { - cy.get('.header-with-actions [aria-label="Edit dashboard"]') - .should('be.visible') - .click(); - openDashboardEditProperties(); - }); - }); - - it('should update the title', () => { - const dashboardTitle = `Test dashboard [${shortid.generate()}]`; - - // update title - cy.get('.ant-modal-body') - .should('be.visible') - .contains('Title') - .get('[data-test="dashboard-title-input"]') - .type(`{selectall}{backspace}${dashboardTitle}`); - - // save edit changes - cy.get('.ant-modal-footer') - .contains('Apply') - .click() - .then(() => { - // assert that modal edit window has closed - cy.get('.ant-modal-body').should('not.exist'); - - // assert title has been updated - cy.get('[data-test="editable-title-input"]').should( - 'have.value', - dashboardTitle, - ); - }); - }); - describe('the color picker is changed', () => { - describe('the metadata has a color scheme', () => { - describe('the advanced tab is open', () => { - // TODO test passes locally but not on ci - xit('should overwrite the color scheme', () => { - openAdvancedProperties(); - cy.wait('@dashboardGet').then(() => { - selectColorScheme('d3Category20b'); - assertMetadata('d3Category20b'); - }); - }); - }); - describe('the advanced tab is not open', () => { - // TODO test passes locally but not on ci - xit('should overwrite the color scheme', () => { - selectColorScheme('bnbColors'); - openAdvancedProperties(); - cy.wait('@dashboardGet').then(() => { - assertMetadata('bnbColors'); - }); - }); - }); - }); - }); - describe('a valid colorScheme is entered', () => { - // TODO test passes locally but not on ci - xit('should save json metadata color change to dropdown', () => { - // edit json metadata - openAdvancedProperties().then(() => { - typeMetadata( - '{selectall}{backspace}{{}"color_scheme":"d3Category20"{}}', - ); - }); - - // save edit changes - cy.get('.modal-footer') - .contains('Save') - .click() - .then(() => { - // assert that modal edit window has closed - cy.get('.ant-modal-body').should('not.exist'); - - // assert color has been updated - openDashboardEditProperties(); - openAdvancedProperties().then(() => { - assertMetadata('d3Category20'); - }); - cy.get('.color-scheme-container').should( - 'have.attr', - 'data-test', - 'd3Category20', - ); - }); - }); - }); - describe('an invalid colorScheme is entered', () => { - // TODO test passes locally but not on ci - xit('should throw an error', () => { - // edit json metadata - openAdvancedProperties().then(() => { - typeMetadata( - '{selectall}{backspace}{{}"color_scheme":"THIS_DOES_NOT_WORK"{}}', - ); - }); - - // save edit changes - cy.get('.modal-footer') - .contains('Save') - .click() - .then(() => { - // assert that modal edit window has closed - cy.get('.ant-modal-body') - .contains('A valid color scheme is required') - .should('be.visible'); - }); - - cy.on('uncaught:exception', err => { - expect(err.message).to.include('something about the error'); - - // return false to prevent the error from - // failing this test - return false; - }); - }); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts new file mode 100644 index 0000000000000..4251b6a7ae502 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts @@ -0,0 +1,803 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { SAMPLE_DASHBOARD_1, TABBED_DASHBOARD } from 'cypress/utils/urls'; +import { drag, resize, waitForChartLoad } from 'cypress/utils'; +import * as ace from 'brace'; +import { interceptGet, interceptUpdate, openTab } from './utils'; +import { + interceptExploreJson, + interceptFiltering as interceptCharts, +} from '../explore/utils'; + +function editDashboard() { + cy.getBySel('edit-dashboard-button').click(); +} + +function closeModal() { + cy.getBySel('properties-modal-cancel-button').click({ force: true }); +} + +function openProperties() { + cy.get('body').then($body => { + if ($body.find('[data-test="properties-modal-cancel-button"]').length) { + closeModal(); + } + cy.getBySel('actions-trigger').click({ force: true }); + cy.getBySel('header-actions-menu') + .contains('Edit properties') + .click({ force: true }); + cy.wait(500); + }); +} + +function openAdvancedProperties() { + cy.get('.ant-modal-body') + .contains('Advanced') + .should('be.visible') + .click({ force: true }); +} + +function dragComponent( + component = 'Unicode Cloud', + target = 'card-title', + withFiltering = true, +) { + if (withFiltering) { + cy.getBySel('dashboard-charts-filter-search-input').type(component); + cy.wait('@filtering'); + } + cy.wait(500); + drag(`[data-test="${target}"]`, component).to( + '[data-test="grid-content"] [data-test="dragdroppable-object"]', + ); +} + +function discardChanges() { + cy.getBySel('undo-action').click({ force: true }); +} + +function visitEdit(sampleDashboard = SAMPLE_DASHBOARD_1) { + interceptCharts(); + interceptGet(); + + if (sampleDashboard === SAMPLE_DASHBOARD_1) { + cy.createSampleDashboards([0]); + } + + cy.visit(sampleDashboard); + cy.wait('@get'); + editDashboard(); + cy.wait('@filtering'); + cy.wait(500); +} + +function resetTabbedDashboard(go = false) { + cy.getDashboard('tabbed_dash').then((r: Record<string, any>) => { + const jsonMetadata = r?.json_metadata || '{}'; + const metadata = JSON.parse(jsonMetadata); + const resetMetadata = JSON.stringify({ + ...metadata, + color_scheme: '', + label_colors: {}, + shared_label_colors: {}, + }); + cy.updateDashboard(r.id, { + certification_details: r.certification_details, + certified_by: r.certified_by, + css: r.css, + dashboard_title: r.dashboard_title, + json_metadata: resetMetadata, + owners: r.owners, + slug: r.slug, + }).then(() => { + if (go) { + visitEdit(TABBED_DASHBOARD); + } + }); + }); +} + +function visitResetTabbedDashboard() { + resetTabbedDashboard(true); +} + +function selectColorScheme(color: string) { + cy.get( + '[data-test="dashboard-edit-properties-form"] [aria-label="Select color scheme"]', + ) + .first() + .click(); + cy.getBySel(color).click(); +} + +function applyChanges() { + cy.getBySel('properties-modal-apply-button').click(); +} + +function saveChanges() { + interceptUpdate(); + cy.getBySel('header-save-button').click({ force: true }); + cy.wait('@update'); +} + +function assertMetadata(text: string) { + const regex = new RegExp(text); + cy.get('#json_metadata') + .should('be.visible') + .then(() => { + const metadata = cy.$$('#json_metadata')[0]; + + // cypress can read this locally, but not in ci + // so we have to use the ace module directly to fetch the value + expect(ace.edit(metadata).getValue()).to.match(regex); + }); +} +function clearMetadata() { + cy.get('#json_metadata').then($jsonmetadata => { + cy.wrap($jsonmetadata).find('.ace_content').click(); + cy.wrap($jsonmetadata) + .find('.ace_text-input') + .type('{selectall} {backspace}'); + }); +} + +function writeMetadata(metadata: string) { + cy.get('#json_metadata').then($jsonmetadata => + cy + .wrap($jsonmetadata) + .find('.ace_text-input') + .type(metadata, { parseSpecialCharSequences: false }), + ); +} + +function openExplore(chartName: string) { + interceptExploreJson(); + + cy.get( + `[data-test-chart-name='${chartName}'] [aria-label='More Options']`, + ).click(); + cy.get('.ant-dropdown') + .not('.ant-dropdown-hidden') + .find("[role='menu'] [role='menuitem']") + .eq(2) + .should('contain', 'Edit chart') + .click(); + cy.wait('@getJson'); +} + +describe('Dashboard edit', () => { + describe('Color consistency', () => { + beforeEach(() => { + visitResetTabbedDashboard(); + }); + + after(() => { + resetTabbedDashboard(); + }); + + it('should respect chart color scheme when none is set for the dashboard', () => { + openProperties(); + cy.get('[aria-label="Select color scheme"]').should('have.value', ''); + applyChanges(); + saveChanges(); + + // open nested tab + openTab(1, 1); + waitForChartLoad({ + name: 'Top 10 California Names Timeseries', + viz: 'line', + }); + + // label Anthony + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(31, 168, 201)'); + }); + + it('should apply same color to same labels with color scheme set', () => { + openProperties(); + selectColorScheme('lyftColors'); + applyChanges(); + saveChanges(); + + // open nested tab + openTab(1, 1); + waitForChartLoad({ + name: 'Top 10 California Names Timeseries', + viz: 'line', + }); + + // label Anthony + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + + // open 2nd main tab + openTab(0, 1); + waitForChartLoad({ name: 'Trends', viz: 'line' }); + + // label Anthony + cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol') + .eq(2) + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + }); + + it('should apply same color to same labels with no color scheme set', () => { + openProperties(); + cy.get('[aria-label="Select color scheme"]').should('have.value', ''); + applyChanges(); + saveChanges(); + + // open nested tab + openTab(1, 1); + waitForChartLoad({ + name: 'Top 10 California Names Timeseries', + viz: 'line', + }); + + // label Anthony + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(31, 168, 201)'); + + // open 2nd main tab + openTab(0, 1); + waitForChartLoad({ name: 'Trends', viz: 'line' }); + + // label Anthony + cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol') + .eq(2) + .should('have.css', 'fill', 'rgb(31, 168, 201)'); + }); + + it('custom label colors should take the precedence in nested tabs', () => { + openProperties(); + openAdvancedProperties(); + clearMetadata(); + writeMetadata( + '{"color_scheme":"lyftColors","label_colors":{"Anthony":"red","Bangladesh":"red"}}', + ); + applyChanges(); + saveChanges(); + + // open nested tab + openTab(1, 1); + waitForChartLoad({ + name: 'Top 10 California Names Timeseries', + viz: 'line', + }); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(255, 0, 0)'); + + // open another nested tab + openTab(2, 1); + waitForChartLoad({ name: 'Growth Rate', viz: 'line' }); + cy.get('[data-test-chart-name="Growth Rate"] .line .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(255, 0, 0)'); + }); + + it('label colors should take the precedence for rendered charts in nested tabs', () => { + // open the tab first time and let chart load + openTab(1, 1); + waitForChartLoad({ + name: 'Top 10 California Names Timeseries', + viz: 'line', + }); + + // go to previous tab + openTab(1, 0); + openProperties(); + openAdvancedProperties(); + clearMetadata(); + writeMetadata( + '{"color_scheme":"lyftColors","label_colors":{"Anthony":"red"}}', + ); + applyChanges(); + saveChanges(); + + // re-open the tab + openTab(1, 1); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(255, 0, 0)'); + }); + + it('should re-apply original color after removing custom label color with color scheme set', () => { + openProperties(); + openAdvancedProperties(); + clearMetadata(); + writeMetadata( + '{"color_scheme":"lyftColors","label_colors":{"Anthony":"red"}}', + ); + applyChanges(); + saveChanges(); + + openTab(1, 1); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(255, 0, 0)'); + + editDashboard(); + openProperties(); + openAdvancedProperties(); + clearMetadata(); + writeMetadata('{"color_scheme":"lyftColors","label_colors":{}}'); + applyChanges(); + saveChanges(); + + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .eq(1) + .should('have.css', 'fill', 'rgb(108, 131, 142)'); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .eq(2) + .should('have.css', 'fill', 'rgb(41, 171, 226)'); + }); + + it('should re-apply original color after removing custom label color with no color scheme set', () => { + // open nested tab + openTab(1, 1); + waitForChartLoad({ + name: 'Top 10 California Names Timeseries', + viz: 'line', + }); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(31, 168, 201)'); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .eq(1) + .should('have.css', 'fill', 'rgb(69, 78, 124)'); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .eq(2) + .should('have.css', 'fill', 'rgb(90, 193, 137)'); + + openProperties(); + cy.get('[aria-label="Select color scheme"]').should('have.value', ''); + openAdvancedProperties(); + clearMetadata(); + writeMetadata('{"color_scheme":"","label_colors":{"Anthony":"red"}}'); + applyChanges(); + saveChanges(); + + openTab(1, 1); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(255, 0, 0)'); + + editDashboard(); + openProperties(); + openAdvancedProperties(); + clearMetadata(); + writeMetadata('{"color_scheme":"","label_colors":{}}'); + applyChanges(); + saveChanges(); + + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(31, 168, 201)'); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .eq(1) + .should('have.css', 'fill', 'rgb(69, 78, 124)'); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .eq(2) + .should('have.css', 'fill', 'rgb(90, 193, 137)'); + }); + + it('should show the same colors in Explore', () => { + openProperties(); + openAdvancedProperties(); + clearMetadata(); + writeMetadata( + '{"color_scheme":"lyftColors","label_colors":{"Anthony":"red"}}', + ); + applyChanges(); + saveChanges(); + + // open nested tab + openTab(1, 1); + waitForChartLoad({ + name: 'Top 10 California Names Timeseries', + viz: 'line', + }); + + // label Anthony + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(255, 0, 0)'); + // label Christopher + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .eq(1) + .should('have.css', 'fill', 'rgb(108, 131, 142)'); + + openExplore('Top 10 California Names Timeseries'); + + // label Anthony + cy.get('[data-test="chart-container"] .line .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(255, 0, 0)'); + // label Christopher + cy.get('[data-test="chart-container"] .line .nv-legend-symbol') + .eq(1) + .should('have.css', 'fill', 'rgb(108, 131, 142)'); + }); + + it('should change color scheme multiple times', () => { + openProperties(); + selectColorScheme('lyftColors'); + applyChanges(); + saveChanges(); + + // open nested tab + openTab(1, 1); + waitForChartLoad({ + name: 'Top 10 California Names Timeseries', + viz: 'line', + }); + + // label Anthony + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + + // open 2nd main tab + openTab(0, 1); + waitForChartLoad({ name: 'Trends', viz: 'line' }); + + // label Anthony + cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol') + .eq(2) + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + + editDashboard(); + openProperties(); + selectColorScheme('bnbColors'); + applyChanges(); + saveChanges(); + + // label Anthony + cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol') + .eq(2) + .should('have.css', 'fill', 'rgb(0, 122, 135)'); + + // open main tab and nested tab + openTab(0, 0); + openTab(1, 1); + + // label Anthony + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(0, 122, 135)'); + }); + + it('should apply the color scheme across main tabs', () => { + openProperties(); + selectColorScheme('lyftColors'); + applyChanges(); + saveChanges(); + + cy.get('.treemap #rect-sum__SP_POP_TOTL').should( + 'have.css', + 'fill', + 'rgb(234, 11, 140)', + ); + + // go to second tab + openTab(0, 1); + waitForChartLoad({ name: 'Trends', viz: 'line' }); + + cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + }); + + it('should apply the color scheme across main tabs for rendered charts', () => { + waitForChartLoad({ name: 'Treemap', viz: 'treemap' }); + openProperties(); + selectColorScheme('bnbColors'); + applyChanges(); + saveChanges(); + + cy.get('.treemap #rect-sum__SP_POP_TOTL').should( + 'have.css', + 'fill', + 'rgb(255, 90, 95)', + ); + + // go to second tab + openTab(0, 1); + waitForChartLoad({ name: 'Trends', viz: 'line' }); + + cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(255, 90, 95)'); + + // go back to first tab + openTab(0, 0); + + // change scheme now that charts are rendered across the main tabs + editDashboard(); + openProperties(); + selectColorScheme('lyftColors'); + applyChanges(); + saveChanges(); + + cy.get('.treemap #rect-sum__SP_POP_TOTL').should( + 'have.css', + 'fill', + 'rgb(234, 11, 140)', + ); + + // go to second tab again + openTab(0, 1); + + cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + }); + + it('should apply the color scheme in nested tabs', () => { + openProperties(); + selectColorScheme('lyftColors'); + applyChanges(); + saveChanges(); + cy.get('.treemap #rect-sum__SP_POP_TOTL').should( + 'have.css', + 'fill', + 'rgb(234, 11, 140)', + ); + + // open nested tab + openTab(1, 1); + waitForChartLoad({ + name: 'Top 10 California Names Timeseries', + viz: 'line', + }); + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + + // open another nested tab + openTab(2, 1); + waitForChartLoad({ name: 'Growth Rate', viz: 'line' }); + cy.get('[data-test-chart-name="Growth Rate"] .line .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + }); + + it('should apply a valid color scheme for rendered charts in nested tabs', () => { + // open the tab first time and let chart load + openTab(1, 1); + waitForChartLoad({ + name: 'Top 10 California Names Timeseries', + viz: 'line', + }); + + // go to previous tab + openTab(1, 0); + openProperties(); + selectColorScheme('lyftColors'); + applyChanges(); + saveChanges(); + + // re-open the tab + openTab(1, 1); + + cy.get( + '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol', + ) + .first() + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + }); + }); + + describe('Edit properties', () => { + before(() => { + visitEdit(); + }); + + beforeEach(() => { + cy.createSampleDashboards([0]); + openProperties(); + }); + + it('should accept a valid color scheme', () => { + openAdvancedProperties(); + clearMetadata(); + writeMetadata('{"color_scheme":"lyftColors"}'); + applyChanges(); + openProperties(); + openAdvancedProperties(); + assertMetadata('lyftColors'); + applyChanges(); + }); + + it('should overwrite the color scheme when advanced is closed', () => { + selectColorScheme('d3Category20b'); + openAdvancedProperties(); + assertMetadata('d3Category20b'); + applyChanges(); + }); + + it('should overwrite the color scheme when advanced is open', () => { + openAdvancedProperties(); + selectColorScheme('googleCategory10c'); + assertMetadata('googleCategory10c'); + applyChanges(); + }); + + it('should not accept an invalid color scheme', () => { + openAdvancedProperties(); + clearMetadata(); + writeMetadata('{"color_scheme":"wrongcolorscheme"}'); + applyChanges(); + cy.get('.ant-modal-body') + .contains('A valid color scheme is required') + .should('be.visible'); + }); + + it('should edit the title', () => { + cy.getBySel('dashboard-title-input').clear().type('Edited title'); + applyChanges(); + cy.getBySel('editable-title-input').should('have.value', 'Edited title'); + }); + }); + + describe('Edit mode', () => { + before(() => { + visitEdit(); + }); + + beforeEach(() => { + cy.createSampleDashboards([0]); + discardChanges(); + }); + + it('should enable edit mode', () => { + cy.getBySel('dashboard-builder-sidepane').should('be.visible'); + }); + + it('should edit the title inline', () => { + cy.getBySel('editable-title-input').clear().type('Edited title{enter}'); + cy.getBySel('header-save-button').should('be.enabled'); + }); + + it('should filter charts', () => { + interceptCharts(); + cy.getBySel('dashboard-charts-filter-search-input').type('Unicode'); + cy.wait('@filtering'); + cy.getBySel('chart-card') + .should('have.length', 1) + .contains('Unicode Cloud'); + cy.getBySel('dashboard-charts-filter-search-input').clear(); + }); + + it('should disable the Save button when undoing', () => { + dragComponent('Unicode Cloud', 'card-title', false); + cy.getBySel('header-save-button').should('be.enabled'); + discardChanges(); + cy.getBySel('header-save-button').should('be.disabled'); + }); + }); + + describe('Components', () => { + beforeEach(() => { + visitEdit(); + }); + + it('should add charts', () => { + dragComponent(); + cy.getBySel('dashboard-component-chart-holder').should('have.length', 1); + }); + + it('should remove added charts', () => { + dragComponent('Pivot Table'); + cy.getBySel('dashboard-component-chart-holder').should('have.length', 1); + cy.getBySel('dashboard-delete-component-button').click(); + cy.getBySel('dashboard-component-chart-holder').should('have.length', 0); + }); + + it('should add markdown component to dashboard', () => { + cy.getBySel('dashboard-builder-component-pane-tabs-navigation') + .find('#tabs-tab-2') + .click(); + + // add new markdown component + dragComponent('Text', 'new-component', false); + + cy.getBySel('dashboard-markdown-editor') + .should( + 'have.text', + '✨Header 1\n✨Header 2\n✨Header 3\n\nClick here to learn more about markdown formatting', + ) + .click(10, 10); + + cy.getBySel('dashboard-component-chart-holder').contains( + 'Click here to learn more about [markdown formatting](https://bit.ly/1dQOfRK)', + ); + + cy.getBySel('dashboard-markdown-editor').click().type('Test resize'); + + resize( + '[data-test="dashboard-markdown-editor"] .resizable-container span div:last-child', + ).to(500, 600); + + cy.getBySel('dashboard-markdown-editor').contains('Test resize'); + }); + }); + + describe('Save', () => { + beforeEach(() => { + visitEdit(); + }); + + it('should save', () => { + dragComponent(); + cy.getBySel('header-save-button').should('be.enabled'); + saveChanges(); + cy.getBySel('dashboard-component-chart-holder').should('have.length', 1); + cy.getBySel('edit-dashboard-button').should('be.visible'); + }); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/fav_star.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/fav_star.test.js deleted file mode 100644 index a20b1eb3f5974..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/fav_star.test.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { - WORLD_HEALTH_DASHBOARD, - CHECK_DASHBOARD_FAVORITE_ENDPOINT, -} from './dashboard.helper'; - -describe('Dashboard add to favorite', () => { - let isFavoriteDashboard = false; - - beforeEach(() => { - cy.login(); - - cy.intercept(CHECK_DASHBOARD_FAVORITE_ENDPOINT).as('countFavStar'); - cy.visit(WORLD_HEALTH_DASHBOARD); - - cy.wait('@countFavStar').then(xhr => { - isFavoriteDashboard = xhr.response.body.count === 1; - }); - }); - - it('should allow favor/unfavor', () => { - if (!isFavoriteDashboard) { - cy.get('[data-test="fave-unfave-icon"]') - .find('span') - .should('have.attr', 'aria-label', 'favorite-unselected'); - cy.get('[data-test="fave-unfave-icon"]').trigger('click'); - cy.get('[data-test="fave-unfave-icon"]') - .find('span') - .should('have.attr', 'aria-label', 'favorite-selected') - .and('not.have.attr', 'aria-label', 'favorite-unselected'); - } else { - cy.get('[data-test="fave-unfave-icon"]') - .find('span') - .should('have.attr', 'aria-label', 'favorite-unselected') - .and('not.have.attr', 'aria-label', 'favorite-selected'); - cy.get('[data-test="fave-unfave-icon"]').trigger('click'); - cy.get('[data-test="fave-unfave-icon"]') - .find('span') - .should('have.attr', 'aria-label', 'favorite-unselected') - .and('not.have.attr', 'aria-label', 'favorite-selected'); - } - - // reset to original fav state - cy.get('[data-test="fave-unfave-icon"]').trigger('click'); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts index 9fb84f70c93d8..bf60c2bec1a7e 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts @@ -16,17 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import { - waitForChartLoad, - WORLD_HEALTH_CHARTS, - WORLD_HEALTH_DASHBOARD, -} from './dashboard.helper'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; +import { waitForChartLoad } from 'cypress/utils'; +import { WORLD_HEALTH_CHARTS, interceptLog } from './utils'; describe('Dashboard load', () => { - beforeEach(() => { - cy.login(); - }); - it('should load dashboard', () => { cy.visit(WORLD_HEALTH_DASHBOARD); WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); @@ -34,7 +28,7 @@ describe('Dashboard load', () => { it('should load in edit mode', () => { cy.visit(`${WORLD_HEALTH_DASHBOARD}?edit=true&standalone=true`); - cy.get('[data-test="discard-changes-button"]').should('be.visible'); + cy.getBySel('discard-changes-button').should('be.visible'); }); it('should load in standalone mode', () => { @@ -44,12 +38,13 @@ describe('Dashboard load', () => { it('should load in edit/standalone mode', () => { cy.visit(`${WORLD_HEALTH_DASHBOARD}?edit=true&standalone=true`); - cy.get('[data-test="discard-changes-button"]').should('be.visible'); + cy.getBySel('discard-changes-button').should('be.visible'); cy.get('#app-menu').should('not.exist'); }); it('should send log data', () => { + interceptLog(); cy.visit(WORLD_HEALTH_DASHBOARD); - cy.intercept('/superset/log/?explode=events&dashboard_id=*'); + cy.wait('@logs', { timeout: 15000 }); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/markdown.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/markdown.test.ts deleted file mode 100644 index 3a4b69c471f37..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/markdown.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { TABBED_DASHBOARD, drag, resize } from './dashboard.helper'; - -describe('Dashboard edit markdown', () => { - beforeEach(() => { - cy.login(); - cy.visit(TABBED_DASHBOARD); - }); - - it('should add markdown component to dashboard', () => { - cy.get('.header-with-actions') - .find('[aria-label="Edit dashboard"]') - .click(); - - cy.get('[data-test="dashboard-builder-component-pane-tabs-navigation"]') - .find('.ant-tabs-tab') - .last() - .click(); - - // lazy load - need to open dropdown for the scripts to load - cy.get('.header-with-actions').find('[aria-label="more-horiz"]').click(); - cy.get('[data-test="grid-row-background--transparent"]') - .first() - .as('component-background-first'); - // add new markdown component - drag('[data-test="new-component"]', 'Markdown').to( - '@component-background-first', - ); - cy.get('[data-test="dashboard-markdown-editor"]') - .should( - 'have.text', - '✨Markdown\n✨Markdown\n✨Markdown\n\nClick here to edit markdown', - ) - .click(); - - cy.get('[data-test="dashboard-component-chart-holder"]') - .find('.ace_content') - .contains('Click here to edit [markdown](https://bit.ly/1dQOfRK)'); - - cy.get('[data-test="dashboard-markdown-editor"]') - .click() - .type('Test resize'); - - resize( - '[data-test="dashboard-markdown-editor"] .resizable-container span div:last-child', - ).to(500, 600); - - cy.get('[data-test="dashboard-markdown-editor"]').contains('Test resize'); - - cy.get('[data-test="nav-list"]:first').click('right', { force: true }); - cy.get('[data-test="dashboard-component-chart-holder"]') - .find('.ace_content') - .should('not.exist'); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts index b409aa06d0a2e..e934a47bfb68f 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts @@ -23,25 +23,16 @@ import { exploreView, dataTestChartName, } from 'cypress/support/directories'; +import { SAMPLE_DASHBOARD_1 } from 'cypress/utils/urls'; + import { - cleanUp, - copyTestDashboard, - testItems, - waitForChartLoad, - WORLD_HEALTH_DASHBOARD, - WORLD_HEALTH_CHARTS, -} from './dashboard.helper'; -import { - addCountryCodeFilter, addCountryNameFilter, addParentFilterWithValue, - addRegionFilter, applyAdvancedTimeRangeFilterOnDashboard, applyNativeFilterValueWithIndex, cancelNativeFilterSettings, checkNativeFilterTooltip, clickOnAddFilterInModal, - closeDashboardToastMessage, collapseFilterOnLeftPanel, deleteNativeFilter, enterNativeFilterEditModal, @@ -55,734 +46,819 @@ import { validateFilterContentOnDashboard, valueNativeFilterOptions, validateFilterNameOnDashboard, -} from './nativeFilter.helper'; -import { DASHBOARD_LIST } from '../dashboard_list/dashboard_list.helper'; -import { CHART_LIST } from '../chart_list/chart_list.helper'; - -// TODO: fix flaky init logic and re-enable -const milliseconds = new Date().getTime(); -const dashboard = `Test Dashboard${milliseconds}`; - -describe('Nativefilters tests initial state required', () => { - beforeEach(() => { - cy.login(); - cleanUp(); - copyTestDashboard("World Bank's Data"); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - closeDashboardToastMessage(); - }); - afterEach(() => { - cleanUp(); - }); - - it('Verify that default value is respected after revisit', () => { - expandFilterOnLeftPanel(); - enterNativeFilterEditModal(); - addCountryNameFilter(); - inputNativeFilterDefaultValue(testItems.filterDefaultValue); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - cy.get(nativeFilters.filterItem) - .contains(testItems.filterDefaultValue) - .should('be.visible'); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('not.exist'); - }); - cy.request( - 'api/v1/dashboard/?q=(order_column:changed_on_delta_humanized,order_direction:desc,page:0,page_size:100)', - ).then(xhr => { - const dashboards = xhr.body.result; - const testDashboard = dashboards.find( - (d: { dashboard_title: string }) => - d.dashboard_title === testItems.dashboard, - ); - cy.visit(testDashboard.url); - }); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('not.exist'); + testItems, + WORLD_HEALTH_CHARTS, + interceptGet, + interceptCharts, + interceptDatasets, + interceptFilterState, +} from './utils'; + +const SAMPLE_CHART = { name: 'Most Populated Countries', viz: 'table' }; + +function visitDashboard(createSample = true) { + interceptCharts(); + interceptGet(); + interceptDatasets(); + + if (createSample) { + cy.createSampleDashboards([0]); + } + + cy.visit(SAMPLE_DASHBOARD_1); + cy.wait('@get'); + cy.wait('@getCharts'); + cy.wait('@getDatasets'); + cy.url().should('contain', 'native_filters_key'); +} + +function prepareDashboardFilters( + filters: { name: string; column: string; datasetId: number }[], +) { + cy.createSampleDashboards([0]); + cy.request({ + method: 'GET', + url: `api/v1/dashboard/1-sample-dashboard`, + }).then(res => { + const { body } = res; + const dashboardId = body.result.id; + const allFilters: Record<string, unknown>[] = []; + filters.forEach((f, i) => { + allFilters.push({ + id: `NATIVE_FILTER-fLH0pxFQ${i}`, + controlValues: { + enableEmptyFilter: false, + defaultToFirstItem: false, + multiSelect: true, + searchAllOptions: false, + inverseSelection: false, + }, + name: f.name, + filterType: 'filter_select', + targets: [ + { + datasetId: f.datasetId, + column: { name: f.column }, + }, + ], + defaultDataMask: { + extraFormData: {}, + filterState: {}, + ownState: {}, + }, + cascadeParentIds: [], + scope: { + rootPath: ['ROOT_ID'], + excluded: [], + }, + type: 'NATIVE_FILTER', + description: '', + chartsInScope: [6], + tabsInScope: [], + }); }); - validateFilterContentOnDashboard(testItems.filterDefaultValue); + if (dashboardId) { + const jsonMetadata = { + show_native_filters: true, + native_filter_configuration: allFilters, + timed_refresh_immune_slices: [], + expanded_slices: {}, + refresh_frequency: 0, + color_scheme: '', + label_colors: {}, + shared_label_colors: {}, + color_scheme_domain: [], + cross_filters_enabled: false, + positions: { + DASHBOARD_VERSION_KEY: 'v2', + ROOT_ID: { type: 'ROOT', id: 'ROOT_ID', children: ['GRID_ID'] }, + GRID_ID: { + type: 'GRID', + id: 'GRID_ID', + children: ['ROW-0rHnUz4nMA'], + parents: ['ROOT_ID'], + }, + HEADER_ID: { + id: 'HEADER_ID', + type: 'HEADER', + meta: { text: '1 - Sample dashboard' }, + }, + 'CHART-DF6EfI55F-': { + type: 'CHART', + id: 'CHART-DF6EfI55F-', + children: [], + parents: ['ROOT_ID', 'GRID_ID', 'ROW-0rHnUz4nMA'], + meta: { + width: 4, + height: 50, + chartId: 6, + sliceName: 'Most Populated Countries', + }, + }, + 'ROW-0rHnUz4nMA': { + type: 'ROW', + id: 'ROW-0rHnUz4nMA', + children: ['CHART-DF6EfI55F-'], + parents: ['ROOT_ID', 'GRID_ID'], + meta: { background: 'BACKGROUND_TRANSPARENT' }, + }, + }, + default_filters: '{}', + filter_scopes: {}, + chart_configuration: {}, + }; + + return cy + .request({ + method: 'PUT', + url: `api/v1/dashboard/${dashboardId}`, + body: { + json_metadata: JSON.stringify(jsonMetadata), + }, + }) + .then(() => visitDashboard(false)); + } + return cy; + }); +} + +function selectFilter(index: number) { + cy.get("[data-test='filter-title-container'] [draggable='true']") + .eq(index) + .click(); +} + +function closeFilterModal() { + cy.get('body').then($body => { + if ($body.find('[data-test="native-filter-modal-cancel-button"]').length) { + cy.getBySel('native-filter-modal-cancel-button').click(); + } + }); +} + +function openVerticalFilterBar() { + cy.getBySel('dashboard-filters-panel').should('exist'); + cy.getBySel('filter-bar__expand-button').click(); +} + +function setFilterBarOrientation(orientation: 'vertical' | 'horizontal') { + cy.getBySel('filterbar-orientation-icon').click(); + cy.wait(250); + cy.getBySel('dropdown-selectable-icon-submenu') + .contains('Orientation of filter bar') + .should('exist') + .trigger('mouseover'); + + if (orientation === 'vertical') { + cy.get('.ant-dropdown-menu-item-selected') + .contains('Horizontal (Top)') + .should('exist'); + cy.get('.ant-dropdown-menu-item').contains('Vertical (Left)').click(); + cy.getBySel('dashboard-filters-panel').should('exist'); + } else { + cy.get('.ant-dropdown-menu-item-selected') + .contains('Vertical (Left)') + .should('exist'); + cy.get('.ant-dropdown-menu-item').contains('Horizontal (Top)').click(); + cy.getBySel('loading-indicator').should('exist'); + cy.getBySel('filter-bar').should('exist'); + cy.getBySel('dashboard-filters-panel').should('not.exist'); + } +} + +function openMoreFilters(intercetFilterState = true) { + interceptFilterState(); + cy.getBySel('dropdown-container-btn').click(); + + if (intercetFilterState) { + cy.wait('@postFilterState'); + } +} + +describe('Horizontal FilterBar', () => { + it('should go from vertical to horizontal and the opposite', () => { + visitDashboard(); + openVerticalFilterBar(); + setFilterBarOrientation('horizontal'); + setFilterBarOrientation('vertical'); + }); + + it('should show all default actions in horizontal mode', () => { + visitDashboard(); + openVerticalFilterBar(); + setFilterBarOrientation('horizontal'); + cy.getBySel('horizontal-filterbar-empty') + .contains('No filters are currently added to this dashboard.') + .should('exist'); + cy.getBySel('filter-bar__create-filter').should('exist'); + cy.getBySel('filterbar-action-buttons').should('exist'); + }); + + it('should stay in horizontal mode when reloading', () => { + visitDashboard(); + openVerticalFilterBar(); + setFilterBarOrientation('horizontal'); + cy.reload(); + cy.getBySel('dashboard-filters-panel').should('not.exist'); + }); + + it('should show all filters in available space on load', () => { + prepareDashboardFilters([ + { name: 'test_1', column: 'country_name', datasetId: 2 }, + { name: 'test_2', column: 'country_code', datasetId: 2 }, + { name: 'test_3', column: 'region', datasetId: 2 }, + ]); + setFilterBarOrientation('horizontal'); + cy.get('.filter-item-wrapper').should('have.length', 3); + }); + + it('should show "more filters" on window resizing up and down', () => { + prepareDashboardFilters([ + { name: 'test_1', column: 'country_name', datasetId: 2 }, + { name: 'test_2', column: 'country_code', datasetId: 2 }, + { name: 'test_3', column: 'region', datasetId: 2 }, + ]); + setFilterBarOrientation('horizontal'); + + cy.getBySel('form-item-value').should('have.length', 3); + cy.viewport(768, 1024); + cy.getBySel('form-item-value').should('have.length', 0); + openMoreFilters(false); + cy.getBySel('form-item-value').should('have.length', 3); + + cy.getBySel('filter-bar').click(); + cy.viewport(1000, 1024); + openMoreFilters(false); + cy.getBySel('form-item-value').should('have.length', 3); + + cy.getBySel('filter-bar').click(); + cy.viewport(1300, 1024); + cy.getBySel('form-item-value').should('have.length', 3); + cy.getBySel('dropdown-container-btn').should('not.exist'); + }); + + it('should show "more filters" and scroll', () => { + prepareDashboardFilters([ + { name: 'test_1', column: 'country_name', datasetId: 2 }, + { name: 'test_2', column: 'country_code', datasetId: 2 }, + { name: 'test_3', column: 'region', datasetId: 2 }, + { name: 'test_4', column: 'year', datasetId: 2 }, + { name: 'test_5', column: 'country_name', datasetId: 2 }, + { name: 'test_6', column: 'country_code', datasetId: 2 }, + { name: 'test_7', column: 'region', datasetId: 2 }, + { name: 'test_8', column: 'year', datasetId: 2 }, + { name: 'test_9', column: 'country_name', datasetId: 2 }, + { name: 'test_10', column: 'country_code', datasetId: 2 }, + { name: 'test_11', column: 'region', datasetId: 2 }, + { name: 'test_12', column: 'year', datasetId: 2 }, + ]); + setFilterBarOrientation('horizontal'); + cy.get('.filter-item-wrapper').should('have.length', 3); + openMoreFilters(); + cy.getBySel('form-item-value').should('have.length', 12); + cy.getBySel('filter-control-name').contains('test_10').should('be.visible'); + cy.getBySel('filter-control-name') + .contains('test_12') + .should('not.be.visible'); + cy.get('.ant-popover-inner-content').scrollTo('bottom'); + cy.getBySel('filter-control-name').contains('test_12').should('be.visible'); + }); + + it('should display newly added filter', () => { + visitDashboard(); + openVerticalFilterBar(); + setFilterBarOrientation('horizontal'); + + enterNativeFilterEditModal(false); + addCountryNameFilter(); + saveNativeFilterSettings([]); + validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); }); - it('User can create parent filters using "Values are dependent on other filters"', () => { - enterNativeFilterEditModal(); - // Create parent filter 'region'. - addRegionFilter(); - // Create filter 'country_name' depend on region filter. - clickOnAddFilterInModal(); - addCountryNameFilter(); - cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( - () => { - cy.contains('Values are dependent on other filters') - .should('be.visible') - .click(); - }, + it('should spot changes in "more filters" and apply their values', () => { + cy.intercept(`/api/v1/chart/data?form_data=**`).as('chart'); + prepareDashboardFilters([ + { name: 'test_1', column: 'country_name', datasetId: 2 }, + { name: 'test_2', column: 'country_code', datasetId: 2 }, + { name: 'test_3', column: 'region', datasetId: 2 }, + { name: 'test_4', column: 'year', datasetId: 2 }, + { name: 'test_5', column: 'country_name', datasetId: 2 }, + { name: 'test_6', column: 'country_code', datasetId: 2 }, + { name: 'test_7', column: 'region', datasetId: 2 }, + { name: 'test_8', column: 'year', datasetId: 2 }, + { name: 'test_9', column: 'country_name', datasetId: 2 }, + { name: 'test_10', column: 'country_code', datasetId: 2 }, + { name: 'test_11', column: 'region', datasetId: 2 }, + { name: 'test_12', column: 'year', datasetId: 2 }, + ]); + setFilterBarOrientation('horizontal'); + openMoreFilters(); + applyNativeFilterValueWithIndex(8, testItems.filterDefaultValue); + cy.get(nativeFilters.applyFilter).click({ force: true }); + cy.wait('@chart'); + cy.get('.ant-scroll-number.ant-badge-count').should( + 'have.attr', + 'title', + '1', ); - addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); - cy.wait(1000); - saveNativeFilterSettings(); - // Validate both filter in dashboard view. - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - [ - testItems.topTenChart.filterColumnRegion, - testItems.topTenChart.filterColumn, - ].forEach(it => { - cy.get(nativeFilters.filterFromDashboardView.filterName) - .contains(it) - .should('be.visible'); - }); - getNativeFilterPlaceholderWithIndex(1) - .invoke('text') - .should('equal', '214 options', { timeout: 20000 }); - // apply first filter value and validate 2nd filter is depden on 1st filter. - applyNativeFilterValueWithIndex(0, 'North America'); - getNativeFilterPlaceholderWithIndex(0).should('have.text', '3 options', { - timeout: 20000, - }); }); - it('user can delete dependent filter', () => { - enterNativeFilterEditModal(); - addRegionFilter(); - clickOnAddFilterInModal(); - addCountryNameFilter(); - cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( - () => { - cy.contains('Values are dependent on other filters') - .should('be.visible') - .click(); - }, - ); - addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); - // remove year native filter to cause it disappears from parent filter input in global sales - cy.get(nativeFilters.modal.tabsList.removeTab) - .should('be.visible') - .first() - .click(); - // make sure you are seeing global sales filter which had parent filter - cy.get(nativeFilters.modal.tabsList.filterItemsContainer) - .children() - .last() - .click(); - // - cy.wait(1000); - cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( - () => { - cy.contains('Values are dependent on other filters').should( - 'not.exist', - ); - }, - ); + it('should focus filter and open "more filters" programmatically', () => { + prepareDashboardFilters([ + { name: 'test_1', column: 'country_name', datasetId: 2 }, + { name: 'test_2', column: 'country_code', datasetId: 2 }, + { name: 'test_3', column: 'region', datasetId: 2 }, + { name: 'test_4', column: 'year', datasetId: 2 }, + { name: 'test_5', column: 'country_name', datasetId: 2 }, + { name: 'test_6', column: 'country_code', datasetId: 2 }, + { name: 'test_7', column: 'region', datasetId: 2 }, + { name: 'test_8', column: 'year', datasetId: 2 }, + { name: 'test_9', column: 'country_name', datasetId: 2 }, + { name: 'test_10', column: 'country_code', datasetId: 2 }, + { name: 'test_11', column: 'region', datasetId: 2 }, + { name: 'test_12', column: 'year', datasetId: 2 }, + ]); + setFilterBarOrientation('horizontal'); + cy.getBySel('slice-header').within(() => { + cy.get('.filter-counts').click(); + }); + cy.get('.filterStatusPopover').contains('test_8').click(); + cy.getBySel('dropdown-content').should('be.visible'); + cy.get('.ant-select-focused').should('be.visible'); }); - it('User can create filter depend on 2 other filters', () => { + it('should show tag count and one plain tag on focus and only count on blur in select ', () => { + prepareDashboardFilters([ + { name: 'test_1', column: 'country_name', datasetId: 2 }, + ]); + setFilterBarOrientation('horizontal'); enterNativeFilterEditModal(); - // add first filter - addRegionFilter(); - // add second filter - clickOnAddFilterInModal(); - addCountryNameFilter(); - // add third filter - clickOnAddFilterInModal(); - addCountryCodeFilter(); - cy.wait(1000); - cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( - () => { - cy.contains('Values are dependent on other filters') - .should('be.visible') - .click(); - cy.get(exploreView.controlPanel.addFieldValue).click(); - }, - ); - // add value to the first input - addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); - // add value to the second input - addParentFilterWithValue(1, testItems.topTenChart.filterColumn); - saveNativeFilterSettings(); - // wait for charts load - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - // filters should be displayed in the left panel - [ - testItems.topTenChart.filterColumnRegion, - testItems.topTenChart.filterColumn, - testItems.topTenChart.filterColumnCountryCode, - ].forEach(it => { - validateFilterNameOnDashboard(it); + inputNativeFilterDefaultValue('Albania'); + inputNativeFilterDefaultValue('Algeria', true); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.getBySel('filter-bar').within(() => { + cy.get(nativeFilters.filterItem).contains('Albania').should('be.visible'); + cy.get(nativeFilters.filterItem).contains('+ 1 ...').should('be.visible'); + cy.get('.ant-select-selection-search-input').click(); + cy.get(nativeFilters.filterItem).contains('+ 2 ...').should('be.visible'); }); + }); +}); - // initially first filter shows 39 options - getNativeFilterPlaceholderWithIndex(0).should('have.text', '7 options'); - // initially second filter shows 409 options - getNativeFilterPlaceholderWithIndex(1).should('have.text', '214 options'); - // verify third filter shows 409 options - getNativeFilterPlaceholderWithIndex(2).should('have.text', '214 options'); - - // apply first filter value - applyNativeFilterValueWithIndex(0, 'North America'); - - // verify second filter shows 409 options available still - getNativeFilterPlaceholderWithIndex(0).should('have.text', '214 options'); - - // verify second filter shows 69 options available still - getNativeFilterPlaceholderWithIndex(1).should('have.text', '3 options'); - - // apply second filter value - applyNativeFilterValueWithIndex(1, 'United States'); +describe('Native filters', () => { + describe('Nativefilters tests initial state required', () => { + beforeEach(() => { + cy.createSampleDashboards([0]); + }); - // verify number of available options for third filter - should be decreased to only one - getNativeFilterPlaceholderWithIndex(0).should('have.text', '1 option'); - }); + it('Verify that default value is respected after revisit', () => { + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, + ]); + enterNativeFilterEditModal(); + inputNativeFilterDefaultValue(testItems.filterDefaultValue); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.get(nativeFilters.filterItem) + .contains(testItems.filterDefaultValue) + .should('be.visible'); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('not.exist'); + }); - it('User can remove parent filters', () => { - enterNativeFilterEditModal(); - addRegionFilter(); - clickOnAddFilterInModal(); - addCountryNameFilter(); - cy.wait(1000); - // Select dependdent option and auto use platform for genre - cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( - () => { - cy.contains('Values are dependent on other filters') - .should('be.visible') - .click(); - }, - ); - saveNativeFilterSettings(); - enterNativeFilterEditModal(); - cy.get(nativeFilters.modal.tabsList.removeTab) - .should('be.visible') - .first() - .click({ - force: true, + // reload dashboard + cy.reload(); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('not.exist'); }); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('be.visible'); + validateFilterContentOnDashboard(testItems.filterDefaultValue); }); - }); -}); -describe('Nativefilters initial state not required', () => { - beforeEach(() => { - cy.login(); - cy.visit(WORLD_HEALTH_DASHBOARD); - }); + it('User can create parent filters using "Values are dependent on other filters"', () => { + prepareDashboardFilters([ + { name: 'region', column: 'region', datasetId: 2 }, + { name: 'country_name', column: 'country_name', datasetId: 2 }, + ]); + enterNativeFilterEditModal(); + selectFilter(1); + cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( + () => { + cy.contains('Values are dependent on other filters') + .should('be.visible') + .click(); + }, + ); + addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); + saveNativeFilterSettings([SAMPLE_CHART]); + [ + testItems.topTenChart.filterColumnRegion, + testItems.topTenChart.filterColumn, + ].forEach(it => { + cy.get(nativeFilters.filterFromDashboardView.filterName) + .contains(it) + .should('be.visible'); + }); + getNativeFilterPlaceholderWithIndex(1) + .invoke('text') + .should('equal', '214 options', { timeout: 20000 }); + // apply first filter value and validate 2nd filter is depden on 1st filter. + applyNativeFilterValueWithIndex(0, 'North America'); + getNativeFilterPlaceholderWithIndex(0).should('have.text', '3 options', { + timeout: 20000, + }); + }); - after(() => { - enterNativeFilterEditModal(); - deleteNativeFilter(); - }); + it('user can delete dependent filter', () => { + prepareDashboardFilters([ + { name: 'region', column: 'region', datasetId: 2 }, + { name: 'country_name', column: 'country_name', datasetId: 2 }, + ]); + enterNativeFilterEditModal(); + selectFilter(1); + cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( + () => { + cy.contains('Values are dependent on other filters') + .should('be.visible') + .click(); + }, + ); + addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); + // remove year native filter to cause it disappears from parent filter input in global sales + cy.get(nativeFilters.modal.tabsList.removeTab) + .should('be.visible') + .first() + .click(); + // make sure you are seeing global sales filter which had parent filter + cy.get(nativeFilters.modal.tabsList.filterItemsContainer) + .children() + .last() + .click(); + // + cy.wait(1000); + cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( + () => { + cy.contains('Values are dependent on other filters').should( + 'not.exist', + ); + }, + ); + }); - it('User can expand / retract native filter sidebar on a dashboard', () => { - cy.get(nativeFilters.addFilterButton.button).should('not.exist'); - expandFilterOnLeftPanel(); - cy.get(nativeFilters.filterFromDashboardView.createFilterButton).should( - 'be.visible', - ); - cy.get(nativeFilters.filterFromDashboardView.expand).should( - 'not.be.visible', - ); - collapseFilterOnLeftPanel(); - }); + it('User can create filter depend on 2 other filters', () => { + prepareDashboardFilters([ + { name: 'region', column: 'region', datasetId: 2 }, + { name: 'country_name', column: 'country_name', datasetId: 2 }, + { name: 'country_code', column: 'country_code', datasetId: 2 }, + ]); + enterNativeFilterEditModal(); + selectFilter(2); + cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( + () => { + cy.contains('Values are dependent on other filters') + .should('be.visible') + .click(); + cy.get(exploreView.controlPanel.addFieldValue).click(); + }, + ); + // add value to the first input + addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); + // add value to the second input + addParentFilterWithValue(1, testItems.topTenChart.filterColumn); + saveNativeFilterSettings([SAMPLE_CHART]); + // filters should be displayed in the left panel + [ + testItems.topTenChart.filterColumnRegion, + testItems.topTenChart.filterColumn, + testItems.topTenChart.filterColumnCountryCode, + ].forEach(it => { + validateFilterNameOnDashboard(it); + }); - it('User can enter filter edit pop-up by clicking on native filter edit icon', () => { - enterNativeFilterEditModal(); - }); + // initially first filter shows 39 options + getNativeFilterPlaceholderWithIndex(0).should('have.text', '7 options'); + // initially second filter shows 409 options + getNativeFilterPlaceholderWithIndex(1).should('have.text', '214 options'); + // verify third filter shows 409 options + getNativeFilterPlaceholderWithIndex(2).should('have.text', '214 options'); - it('User can delete a native filter', () => { - enterNativeFilterEditModal(); - cy.get(nativeFilters.filtersList.removeIcon).first().click(); - cy.contains('Restore Filter').should('not.exist', { timeout: 10000 }); - saveNativeFilterSettings(); - }); + // apply first filter value + applyNativeFilterValueWithIndex(0, 'North America'); - it('User can cancel creating a new filter', () => { - enterNativeFilterEditModal(); - cancelNativeFilterSettings(); - }); + // verify second filter shows 409 options available still + getNativeFilterPlaceholderWithIndex(0).should('have.text', '214 options'); - it('Verify setting options and tooltips for value filter', () => { - enterNativeFilterEditModal(); - cy.contains('Filter value is required').should('be.visible').click(); - checkNativeFilterTooltip(0, nativeFilterTooltips.defaultValue); - cy.get(nativeFilters.modal.container).should('be.visible'); - valueNativeFilterOptions.forEach(el => { - cy.contains(el); - }); - cy.contains('Values are dependent on other filters').should('not.exist'); - cy.get(nativeFilters.filterConfigurationSections.checkedCheckbox).contains( - 'Can select multiple values', - ); - checkNativeFilterTooltip(1, nativeFilterTooltips.required); - checkNativeFilterTooltip(2, nativeFilterTooltips.defaultToFirstItem); - checkNativeFilterTooltip(3, nativeFilterTooltips.searchAllFilterOptions); - checkNativeFilterTooltip(4, nativeFilterTooltips.inverseSelection); - clickOnAddFilterInModal(); - cy.contains('Values are dependent on other filters').should('exist'); - }); + // verify second filter shows 69 options available still + getNativeFilterPlaceholderWithIndex(1).should('have.text', '3 options'); - it("User can check 'Filter has default value'", () => { - enterNativeFilterEditModal(); - addCountryNameFilter(); - inputNativeFilterDefaultValue(testItems.filterDefaultValue); - }); + // apply second filter value + applyNativeFilterValueWithIndex(1, 'United States'); - it('User can add a new native filter', () => { - let filterKey: string; - const removeFirstChar = (search: string) => - search.split('').slice(1, search.length).join(''); - cy.wait(3000); - cy.location().then(loc => { - const queryParams = qs.parse(removeFirstChar(loc.search)); - filterKey = queryParams.native_filters_key as string; - expect(typeof filterKey).eq('string'); - }); - enterNativeFilterEditModal(); - addCountryNameFilter(); - saveNativeFilterSettings(); - cy.wait(3000); - cy.location().then(loc => { - const queryParams = qs.parse(removeFirstChar(loc.search)); - const newfilterKey = queryParams.native_filters_key; - expect(newfilterKey).eq(filterKey); + // verify number of available options for third filter - should be decreased to only one + getNativeFilterPlaceholderWithIndex(0).should('have.text', '1 option'); }); - cy.wait(3000); - cy.get(nativeFilters.modal.container).should('not.exist'); - }); - it('User can undo deleting a native filter', () => { - enterNativeFilterEditModal(); - addCountryCodeFilter(); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - validateFilterNameOnDashboard( - testItems.topTenChart.filterColumnCountryCode, - ); - enterNativeFilterEditModal(); - cy.get(nativeFilters.filtersList.removeIcon).first().click(); - cy.get('[data-test="restore-filter-button"]').should('be.visible').click(); - cy.get(nativeFilters.modal.container) - .find(nativeFilters.filtersPanel.filterName) - .should( - 'have.attr', - 'value', - testItems.topTenChart.filterColumnCountryCode, + it('User can remove parent filters', () => { + prepareDashboardFilters([ + { name: 'region', column: 'region', datasetId: 2 }, + { name: 'country_name', column: 'country_name', datasetId: 2 }, + ]); + enterNativeFilterEditModal(); + selectFilter(1); + // Select dependdent option and auto use platform for genre + cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( + () => { + cy.contains('Values are dependent on other filters') + .should('be.visible') + .click(); + }, ); - }); - - it('User can create a time grain filter', () => { - enterNativeFilterEditModal(); - fillNativeFilterForm( - testItems.filterType.timeGrain, - testItems.filterType.timeGrain, - testItems.datasetForNativeFilter, - ); - saveNativeFilterSettings(); - applyNativeFilterValueWithIndex(0, testItems.filterTimeGrain); - cy.get(nativeFilters.applyFilter).click(); - cy.url().then(u => { - const ur = new URL(u); - expect(ur.search).to.include('native_filters'); + saveNativeFilterSettings([SAMPLE_CHART]); + enterNativeFilterEditModal(); + cy.get(nativeFilters.modal.tabsList.removeTab) + .should('be.visible') + .first() + .click({ + force: true, + }); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('be.visible'); + }); }); - validateFilterNameOnDashboard(testItems.filterType.timeGrain); - validateFilterContentOnDashboard(testItems.filterTimeGrain); }); - it('User can create a time range filter', () => { - enterNativeFilterEditModal(); - fillNativeFilterForm( - testItems.filterType.timeRange, - testItems.filterType.timeRange, - ); - saveNativeFilterSettings(); - cy.get(dashboardView.salesDashboardSpecific.vehicleSalesFilterTimeRange) - .should('be.visible') - .click(); - applyAdvancedTimeRangeFilterOnDashboard('2005-12-17', '2006-12-17'); - cy.url().then(u => { - const ur = new URL(u); - expect(ur.search).to.include('native_filters'); + describe('Nativefilters basic interactions', () => { + before(() => { + visitDashboard(); }); - validateFilterNameOnDashboard(testItems.filterType.timeRange); - cy.get(nativeFilters.filterFromDashboardView.timeRangeFilterContent) - .contains('2005-12-17') - .should('be.visible'); - }); - it('User can create a time column filter', () => { - enterNativeFilterEditModal(); - fillNativeFilterForm( - testItems.filterType.timeColumn, - testItems.filterType.timeColumn, - testItems.datasetForNativeFilter, - ); - saveNativeFilterSettings(); - cy.intercept(`/api/v1/chart/data?form_data=**`).as('chart'); - cy.get(nativeFilters.modal.container).should('not.exist'); - // assert that native filter is created - validateFilterNameOnDashboard(testItems.filterType.timeColumn); - applyNativeFilterValueWithIndex(0, testItems.topTenChart.filterColumnYear); - cy.get(nativeFilters.applyFilter).click({ force: true }); - cy.wait('@chart'); - validateFilterContentOnDashboard(testItems.topTenChart.filterColumnYear); - }); + beforeEach(() => { + cy.createSampleDashboards([0]); + closeFilterModal(); + }); - it('User can create a numerical range filter', () => { - enterNativeFilterEditModal(); - fillNativeFilterForm( - testItems.filterType.numerical, - testItems.filterNumericalColumn, - testItems.datasetForNativeFilter, - testItems.filterNumericalColumn, - ); - saveNativeFilterSettings(); - // assertions - cy.get(nativeFilters.slider.slider).should('be.visible').click('center'); - // cy.get(sqlLabView.tooltip).should('be.visible'); - cy.intercept(`/superset/explore_json/*`).as('slices'); - cy.get(nativeFilters.applyFilter).click(); - cy.wait('@slices'); - // assert that the url contains 'native_filters' in the url - cy.url().then(u => { - const ur = new URL(u); - expect(ur.search).to.include('native_filters'); - // assert that the start handle has a value - cy.get(nativeFilters.slider.startHandle) - .invoke('attr', 'aria-valuenow') - .should('exist'); - // assert that the end handle has a value - cy.get(nativeFilters.slider.endHandle) - .invoke('attr', 'aria-valuenow') - .should('exist'); - // assert slider text matches what we should have - cy.get(nativeFilters.slider.sliderText).should('have.text', '49'); + it('User can expand / retract native filter sidebar on a dashboard', () => { + cy.get(nativeFilters.addFilterButton.button).should('not.exist'); + expandFilterOnLeftPanel(); + cy.get(nativeFilters.filterFromDashboardView.createFilterButton).should( + 'be.visible', + ); + cy.get(nativeFilters.filterFromDashboardView.expand).should( + 'not.be.visible', + ); + collapseFilterOnLeftPanel(); }); - }); - it('User can undo deleting a native filter', () => { - enterNativeFilterEditModal(); - addCountryNameFilter(); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); - enterNativeFilterEditModal(); - undoDeleteNativeFilter(); - }); + it('User can enter filter edit pop-up by clicking on native filter edit icon', () => { + enterNativeFilterEditModal(false); + }); - it('User can cancel changes in native filter', () => { - enterNativeFilterEditModal(); - fillNativeFilterForm( - testItems.filterType.value, - 'suffix', - testItems.datasetForNativeFilter, - ); - cancelNativeFilterSettings(); - enterNativeFilterEditModal(); - cy.get(nativeFilters.filtersList.removeIcon).first().click(); - cy.contains('You have removed this filter.').should('be.visible'); - saveNativeFilterSettings(); - }); + it('User can delete a native filter', () => { + enterNativeFilterEditModal(false); + cy.get(nativeFilters.filtersList.removeIcon).first().click(); + cy.contains('Restore Filter').should('not.exist', { timeout: 10000 }); + }); - it('User can create a value filter', () => { - enterNativeFilterEditModal(); - addCountryNameFilter(); - cy.get(nativeFilters.filtersPanel.filterTypeInput) - .find(nativeFilters.filtersPanel.filterTypeItem) - .should('have.text', testItems.filterType.value); - saveNativeFilterSettings(); - validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); - }); + it('User can cancel creating a new filter', () => { + enterNativeFilterEditModal(false); + cancelNativeFilterSettings(); + }); - it('User can apply value filter with selected values', () => { - enterNativeFilterEditModal(); - addCountryNameFilter(); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - applyNativeFilterValueWithIndex(0, testItems.filterDefaultValue); - cy.get(nativeFilters.applyFilter).click(); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('not.exist'); + it('Verify setting options and tooltips for value filter', () => { + enterNativeFilterEditModal(false); + cy.contains('Filter value is required').should('be.visible').click(); + checkNativeFilterTooltip(0, nativeFilterTooltips.defaultValue); + cy.get(nativeFilters.modal.container).should('be.visible'); + valueNativeFilterOptions.forEach(el => { + cy.contains(el); + }); + cy.contains('Values are dependent on other filters').should('not.exist'); + cy.get( + nativeFilters.filterConfigurationSections.checkedCheckbox, + ).contains('Can select multiple values'); + checkNativeFilterTooltip(1, nativeFilterTooltips.required); + checkNativeFilterTooltip(2, nativeFilterTooltips.defaultToFirstItem); + checkNativeFilterTooltip(3, nativeFilterTooltips.searchAllFilterOptions); + checkNativeFilterTooltip(4, nativeFilterTooltips.inverseSelection); + clickOnAddFilterInModal(); + cy.contains('Values are dependent on other filters').should('exist'); }); }); - it('User can stop filtering when filter is removed', () => { - enterNativeFilterEditModal(); - addCountryNameFilter(); - inputNativeFilterDefaultValue(testItems.filterDefaultValue); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('not.exist'); - }); - cy.get(nativeFilters.filterItem) - .contains(testItems.filterDefaultValue) - .should('be.visible'); - validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); - enterNativeFilterEditModal(); - deleteNativeFilter(); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('be.visible'); + describe('Nativefilters initial state not required', () => { + it("User can check 'Filter has default value'", () => { + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, + ]); + enterNativeFilterEditModal(); + inputNativeFilterDefaultValue(testItems.filterDefaultValue); }); - }); -}); -xdescribe('Nativefilters', () => { - before(() => { - cy.login(); - cy.visit(DASHBOARD_LIST); - cy.get('[data-test="new-dropdown"]').click(); - cy.get('[data-test="menu-item-Dashboard"]').click({ force: true }); - cy.get('[data-test="editable-title-input"]') - .click() - .clear() - .type(`${dashboard}{enter}`); - cy.get('[data-test="header-save-button"]').click(); - cy.visit(CHART_LIST); - cy.get('[data-test="search-input"]').type('Treemap{enter}'); - cy.get('[data-test="Treemap-list-chart-title"]') - .should('be.visible', { timeout: 5000 }) - .click(); - cy.get('[data-test="query-save-button"]').click(); - cy.get('[data-test="save-chart-modal-select-dashboard-form"]') - .find('input[aria-label="Select a dashboard"]') - .type(`${dashboard}`, { force: true }); - cy.get('[data-test="btn-modal-save"]').click(); - }); - beforeEach(() => { - cy.login(); - cy.visit(DASHBOARD_LIST); - cy.get('[data-test="search-input"]').click().type(`${dashboard}{enter}`); - cy.contains('[data-test="cell-text"]', `${dashboard}`).click(); - }); + it('User can add a new native filter', () => { + prepareDashboardFilters([]); - it('should show filter bar and allow user to create filters ', () => { - cy.get('[data-test="filter-bar"]').should('be.visible'); - cy.get('[data-test="filter-bar__expand-button"]').click(); - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__name-input"]') - .click() - .type('Country name'); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__datasource-input"]') - .click() - .type('wb_health_population'); - - cy.get( - '.ant-modal [data-test="filters-config-modal__datasource-input"] .Select__menu', - ) - .contains('wb_health_population') - .click(); - - // hack for unclickable country_name - cy.get('.ant-modal').find('[data-test="field-input"]').type('country_name'); - cy.get('.ant-modal') - .find('[data-test="field-input"]') - .type('{downarrow}{downarrow}{enter}'); - cy.get('[data-test="apply-changes-instantly-checkbox"]').check(); - cy.get('.ant-modal-footer') - .find('[data-test="native-filter-modal-save-button"]') - .should('be.visible') - .click(); - }); + let filterKey: string; + const removeFirstChar = (search: string) => + search.split('').slice(1, search.length).join(''); - it('should show newly added filter in filter bar menu', () => { - cy.get('[data-test="filter-bar"]').should('be.visible'); - cy.get('[data-test="filter-control-name"]').should('be.visible'); - cy.get('[data-test="form-item-value"]').should('be.visible'); - }); - it('should filter dashboard with selected filter value', () => { - cy.get('[data-test="form-item-value"]').should('be.visible').click(); - cy.get('.ant-select-selection-search').type('Hong Kong{enter}'); - cy.get('[data-test="filter-bar__apply-button"]').click(); - cy.get('.treemap').within(() => { - cy.contains('HKG').should('be.visible'); - cy.contains('USA').should('not.exist'); - }); - }); - xit('default value is respected after revisit', () => { - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - // TODO: replace with proper wait for filter to finish loading - cy.wait(1000); - cy.get('[data-test="default-input"]').click(); - cy.get('.ant-modal') - .find('[data-test="default-input"]') - .type('Sweden{enter}'); - cy.get('[data-test="native-filter-modal-save-button"]') - .should('be.visible') - .click(); - cy.visit(DASHBOARD_LIST); - cy.get('[data-test="search-input"]').click().type(`${dashboard}{enter}`); - cy.contains('[data-test="cell-text"]', `${dashboard}`).click(); - cy.get('.treemap').within(() => { - cy.contains('SWE').should('be.visible'); - cy.contains('USA').should('not.exist'); - }); - cy.contains('Sweden'); - }); - it('should allow for deleted filter restore', () => { - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - cy.get('.ant-tabs-nav-list').within(() => { - cy.get('.ant-tabs-tab-remove').click(); + cy.location().then(loc => { + cy.url().should('contain', 'native_filters_key'); + const queryParams = qs.parse(removeFirstChar(loc.search)); + filterKey = queryParams.native_filters_key as string; + expect(typeof filterKey).eq('string'); + }); + enterNativeFilterEditModal(); + addCountryNameFilter(); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.location().then(loc => { + cy.url().should('contain', 'native_filters_key'); + const queryParams = qs.parse(removeFirstChar(loc.search)); + const newfilterKey = queryParams.native_filters_key; + expect(newfilterKey).eq(filterKey); + }); + cy.get(nativeFilters.modal.container).should('not.exist'); }); - cy.get('[data-test="undo-button"]').should('be.visible').click(); - cy.get('.ant-tabs-nav-list').within(() => { - cy.get('.ant-tabs-tab-remove').click(); + it('User can restore a deleted native filter', () => { + prepareDashboardFilters([ + { name: 'country_code', column: 'country_code', datasetId: 2 }, + ]); + enterNativeFilterEditModal(); + cy.get(nativeFilters.filtersList.removeIcon).first().click(); + cy.get('[data-test="restore-filter-button"]') + .should('be.visible') + .click(); + cy.get(nativeFilters.modal.container) + .find(nativeFilters.filtersPanel.filterName) + .should( + 'have.attr', + 'value', + testItems.topTenChart.filterColumnCountryCode, + ); }); - cy.get('[data-test="restore-filter-button"]').should('be.visible').click(); - }); - it('should stop filtering when filter is removed', () => { - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - cy.get('.ant-tabs-nav-list').within(() => { - cy.get('.ant-tabs-tab-remove').click(); - }); - cy.get('.ant-modal-footer') - .find('[data-test="native-filter-modal-save-button"]') - .should('be.visible') - .click(); - cy.get('.treemap').within(() => { - cy.contains('HKG').should('be.visible'); - cy.contains('USA').should('be.visible'); + it('User can create a time grain filter', () => { + prepareDashboardFilters([]); + enterNativeFilterEditModal(); + fillNativeFilterForm( + testItems.filterType.timeGrain, + testItems.filterType.timeGrain, + testItems.datasetForNativeFilter, + ); + saveNativeFilterSettings([SAMPLE_CHART]); + applyNativeFilterValueWithIndex(0, testItems.filterTimeGrain); + cy.get(nativeFilters.applyFilter).click(); + cy.url().then(u => { + const ur = new URL(u); + expect(ur.search).to.include('native_filters'); + }); + validateFilterNameOnDashboard(testItems.filterType.timeGrain); + validateFilterContentOnDashboard(testItems.filterTimeGrain); }); - }); - describe('Parent Filters', () => { - it('should allow for creating parent filters ', () => { - cy.get('[data-test="filter-bar"]').should('be.visible'); - cy.get('[data-test="filter-bar__expand-button"]').click(); - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__name-input"]') - .click() - .type('Country name'); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__datasource-input"]') - .click() - .type('wb_health_population'); - - cy.get( - '.ant-modal [data-test="filters-config-modal__datasource-input"] .Select__menu', - ) - .contains('wb_health_population') - .click(); - // hack for unclickable country_name - cy.get('.ant-modal') - .find('[data-test="field-input"]') - .type('country_name'); - cy.get('.ant-modal') - .find('[data-test="field-input"]') - .type('{downarrow}{downarrow}{enter}'); - cy.get('[data-test="apply-changes-instantly-checkbox"]').check(); - cy.get('.ant-modal-footer') - .find('[data-test="native-filter-modal-save-button"]') + it.skip('User can create a time range filter', () => { + enterNativeFilterEditModal(); + fillNativeFilterForm( + testItems.filterType.timeRange, + testItems.filterType.timeRange, + ); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); + cy.get(dashboardView.salesDashboardSpecific.vehicleSalesFilterTimeRange) .should('be.visible') .click(); + applyAdvancedTimeRangeFilterOnDashboard('2005-12-17', '2006-12-17'); + cy.url().then(u => { + const ur = new URL(u); + expect(ur.search).to.include('native_filters'); + }); + validateFilterNameOnDashboard(testItems.filterType.timeRange); + cy.get(nativeFilters.filterFromDashboardView.timeRangeFilterContent) + .contains('2005-12-17') + .should('be.visible'); + }); - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').first().should('be.visible'); - cy.get('[data-test=add-filter-button]').first().click(); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__name-input"]') - .last() - .click() - .type('Region Name'); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__datasource-input"]') - .last() - .click() - .type('wb_health_population'); + it.skip('User can create a time column filter', () => { + enterNativeFilterEditModal(); + fillNativeFilterForm( + testItems.filterType.timeColumn, + testItems.filterType.timeColumn, + testItems.datasetForNativeFilter, + ); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); + cy.intercept(`/api/v1/chart/data?form_data=**`).as('chart'); + cy.get(nativeFilters.modal.container).should('not.exist'); + // assert that native filter is created + validateFilterNameOnDashboard(testItems.filterType.timeColumn); + applyNativeFilterValueWithIndex( + 0, + testItems.topTenChart.filterColumnYear, + ); + cy.get(nativeFilters.applyFilter).click({ force: true }); + cy.wait('@chart'); + validateFilterContentOnDashboard(testItems.topTenChart.filterColumnYear); + }); - cy.get( - '.ant-modal [data-test="filters-config-modal__datasource-input"] .Select__menu', - ) - .last() - .contains('wb_health_population') - .click(); + it('User can create a numerical range filter', () => { + visitDashboard(); + enterNativeFilterEditModal(false); + fillNativeFilterForm( + testItems.filterType.numerical, + testItems.filterNumericalColumn, + testItems.datasetForNativeFilter, + testItems.filterNumericalColumn, + ); + saveNativeFilterSettings([]); + // assertions + cy.get(nativeFilters.slider.slider).should('be.visible').click('center'); + cy.get(nativeFilters.applyFilter).click(); + // assert that the url contains 'native_filters' in the url + cy.url().then(u => { + const ur = new URL(u); + expect(ur.search).to.include('native_filters'); + // assert that the start handle has a value + cy.get(nativeFilters.slider.startHandle) + .invoke('attr', 'aria-valuenow') + .should('exist'); + // assert that the end handle has a value + cy.get(nativeFilters.slider.endHandle) + .invoke('attr', 'aria-valuenow') + .should('exist'); + // assert slider text matches what we should have + cy.get(nativeFilters.slider.sliderText).should('have.text', '49'); + }); + }); - // hack for unclickable country_name - cy.get('.ant-modal') - .find('[data-test="field-input"]') - .last() - .type('region'); - cy.get('.ant-modal') - .find('[data-test="field-input"]') - .last() - .type('{downarrow}{downarrow}{downarrow}{downarrow}{enter}'); + it('User can undo deleting a native filter', () => { + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, + ]); + enterNativeFilterEditModal(); + undoDeleteNativeFilter(); + cy.get(nativeFilters.modal.container) + .find(nativeFilters.filtersPanel.filterName) + .should('have.attr', 'value', testItems.topTenChart.filterColumn); + }); - cy.get('[data-test="apply-changes-instantly-checkbox"]').last().check(); - cy.get('.ant-modal') - .find('[data-test="parent-filter-input"]') - .last() - .type('{downarrow}{enter}'); + it('User can cancel changes in native filter', () => { + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, + ]); + enterNativeFilterEditModal(); + cy.getBySel('filters-config-modal__name-input').type('|EDITED', { + force: true, + }); + cancelNativeFilterSettings(); + enterNativeFilterEditModal(); + cy.get(nativeFilters.filtersList.removeIcon).first().click(); + cy.contains('You have removed this filter.').should('be.visible'); + }); - cy.get('.ant-modal-footer') - .find('[data-test="native-filter-modal-save-button"]') - .first() - .should('be.visible') - .click(); - cy.get('[data-test="filter-icon"]').should('be.visible'); + it('User can create a value filter', () => { + visitDashboard(); + enterNativeFilterEditModal(false); + addCountryNameFilter(); + cy.get(nativeFilters.filtersPanel.filterTypeInput) + .find(nativeFilters.filtersPanel.filterTypeItem) + .should('have.text', testItems.filterType.value); + saveNativeFilterSettings([]); + validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); }); - xit('should parent filter be working', () => { - cy.get('.treemap').within(() => { - cy.contains('SMR').should('be.visible'); - cy.contains('Europe & Central Asia').should('be.visible'); - cy.contains('South Asia').should('be.visible'); - }); - cy.get('[data-test="form-item-value"]').should('be.visible').click(); - cy.get('.ant-popover-inner-content').within(() => { - cy.get('[data-test="form-item-value"]') - .should('be.visible') - .first() - .type('San Marino{enter}'); - cy.get('[data-test="form-item-value"]') - .should('be.visible') - .last() - .type('Europe & Central Asia{enter}'); - }); - cy.get('.treemap').within(() => { - cy.contains('SMR').should('be.visible'); - cy.contains('Europe & Central Asia').should('be.visible'); - cy.contains('South Asia').should('not.exist'); + it('User can apply value filter with selected values', () => { + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, + ]); + applyNativeFilterValueWithIndex(0, testItems.filterDefaultValue); + cy.get(nativeFilters.applyFilter).click(); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('not.exist'); }); }); - it('should stop filtering when parent filter is removed', () => { - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - cy.get('.ant-tabs-nav-list').within(() => { - cy.get('.ant-tabs-tab-remove').click({ multiple: true }); + it('User can stop filtering when filter is removed', () => { + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, + ]); + enterNativeFilterEditModal(); + inputNativeFilterDefaultValue(testItems.filterDefaultValue); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('not.exist'); }); - cy.get('.ant-modal-footer') - .find('[data-test="native-filter-modal-save-button"]') - .should('be.visible') - .click(); - cy.get('.treemap').within(() => { - cy.contains('HKG').should('be.visible'); - cy.contains('USA').should('be.visible'); + cy.get(nativeFilters.filterItem) + .contains(testItems.filterDefaultValue) + .should('be.visible'); + validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); + enterNativeFilterEditModal(); + deleteNativeFilter(); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('be.visible'); }); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js deleted file mode 100644 index 3c815a222ce1e..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import shortid from 'shortid'; -import { - waitForChartLoad, - WORLD_HEALTH_CHARTS, - WORLD_HEALTH_DASHBOARD, -} from './dashboard.helper'; - -function openDashboardEditProperties() { - cy.get('.header-with-actions [aria-label="Edit dashboard"]').click(); - cy.get( - '.header-with-actions .right-button-panel .ant-dropdown-trigger', - ).trigger('click', { force: true }); - cy.get('.dropdown-menu').contains('Edit properties').click(); -} - -describe('Dashboard save action', () => { - beforeEach(() => { - cy.login(); - cy.visit(WORLD_HEALTH_DASHBOARD); - cy.get('#app').then(() => { - cy.get('.dashboard-header-container').then(headerContainerElement => { - const dashboardId = headerContainerElement.attr('data-test-id'); - - cy.intercept('POST', `/superset/copy_dash/${dashboardId}/`).as( - 'copyRequest', - ); - - cy.get('[aria-label="more-horiz"]').trigger('click', { force: true }); - cy.get('[data-test="save-as-menu-item"]').trigger('click', { - force: true, - }); - cy.get('[data-test="modal-save-dashboard-button"]').trigger('click', { - force: true, - }); - }); - }); - }); - - // change to what the title should be - it('should save as new dashboard', () => { - cy.wait('@copyRequest').then(() => { - cy.get('[data-test="editable-title"]').then(element => { - const dashboardTitle = element.attr('title'); - expect(dashboardTitle).to.not.equal(`World Bank's Data`); - }); - }); - }); - - it('should save/overwrite dashboard', () => { - // should load chart - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - - // remove box_plot chart from dashboard - cy.get('[aria-label="Edit dashboard"]').click({ timeout: 5000 }); - cy.get('[data-test="dashboard-delete-component-button"]') - .last() - .trigger('mouseenter') - .click(); - - cy.get('[data-test="grid-container"]') - .find('.box_plot') - .should('not.exist'); - - cy.intercept('PUT', '/api/v1/dashboard/**').as('putDashboardRequest'); - cy.get('.header-with-actions') - .find('[data-test="header-save-button"]') - .contains('Save') - .click(); - - // go back to view mode - cy.wait('@putDashboardRequest'); - cy.get('.header-with-actions') - .find('[aria-label="Edit dashboard"]') - .click(); - - // deleted boxplot should still not exist - cy.get('[data-test="grid-container"]') - .find('.box_plot', { timeout: 20000 }) - .should('not.exist'); - }); - - // TODO: Fix broken test - xit('should save after edit', () => { - cy.get('.dashboard-grid', { timeout: 50000 }) // wait for 50 secs to load dashboard - .then(() => { - const dashboardTitle = `Test dashboard [${shortid.generate()}]`; - - openDashboardEditProperties(); - - // open color scheme dropdown - cy.get('.ant-modal-body') - .contains('Color scheme') - .parents('.ControlHeader') - .next('.Select') - .click() - .then($colorSelect => { - // select a new color scheme - cy.wrap($colorSelect) - .find('.Select__option') - .first() - .next() - .click(); - }); - - // remove json metadata - cy.get('.ant-modal-body') - .contains('Advanced') - .click() - .then(() => { - cy.get('#json_metadata').type('{selectall}{backspace}'); - }); - - // update title - cy.get('.ant-modal-body') - .contains('Title') - .siblings('input') - .type(`{selectall}{backspace}${dashboardTitle}`); - - // save edit changes - cy.get('.ant-modal-footer') - .contains('Save') - .click() - .then(() => { - // assert that modal edit window has closed - cy.get('.ant-modal-body').should('not.exist'); - - // save dashboard changes - cy.get('.header-with-actions').contains('Save').click(); - - // assert success flash - cy.contains('saved successfully').should('be.visible'); - - // assert title has been updated - cy.get('.editable-title [data-test="editable-title-input"]').should( - 'have.value', - dashboardTitle, - ); - }); - }); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts index 4dbb8c712bccf..ac076a2200f26 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts @@ -16,42 +16,48 @@ * specific language governing permissions and limitations * under the License. */ -import { parsePostForm } from 'cypress/utils'; import { - TABBED_DASHBOARD, + parsePostForm, waitForChartLoad, getChartAliasBySpec, -} from './dashboard.helper'; +} from 'cypress/utils'; +import { TABBED_DASHBOARD } from 'cypress/utils/urls'; +import { expandFilterOnLeftPanel } from './utils'; const TREEMAP = { name: 'Treemap', viz: 'treemap' }; const FILTER_BOX = { name: 'Region Filter', viz: 'filter_box' }; const LINE_CHART = { name: 'Growth Rate', viz: 'line' }; const BOX_PLOT = { name: 'Box plot', viz: 'box_plot' }; +const BIG_NUMBER = { name: 'Number of Girls', viz: 'big_number_total' }; +const TABLE = { name: 'Names Sorted by Num in California', viz: 'table' }; + +function topLevelTabs() { + cy.getBySel('dashboard-component-tabs') + .first() + .find('[data-test="nav-list"] .ant-tabs-nav-list > .ant-tabs-tab') + .as('top-level-tabs'); +} + +function resetTabs() { + topLevelTabs(); + cy.get('@top-level-tabs').first().click(); + waitForChartLoad(FILTER_BOX); + waitForChartLoad(TREEMAP); + waitForChartLoad(BIG_NUMBER); + waitForChartLoad(TABLE); +} describe('Dashboard tabs', () => { - // cypress can not handle window.scrollTo - // https://github.com/cypress-io/cypress/issues/2761 - // add this exception handler to pass test - const handleException = () => { - // return false to prevent the error from - // failing this test - cy.on('uncaught:exception', () => false); - }; - - beforeEach(() => { - cy.login(); - + before(() => { cy.visit(TABBED_DASHBOARD); }); - it('should switch active tab on click', () => { - waitForChartLoad(FILTER_BOX); - waitForChartLoad(TREEMAP); + beforeEach(() => { + resetTabs(); + }); - cy.get('[data-test="dashboard-component-tabs"]') - .first() - .find('[data-test="nav-list"] .ant-tabs-nav-list > .ant-tabs-tab') - .as('top-level-tabs'); + it('should switch tabs', () => { + topLevelTabs(); cy.get('@top-level-tabs') .first() @@ -61,6 +67,9 @@ describe('Dashboard tabs', () => { .last() .should('not.have.class', 'ant-tabs-tab-active'); + cy.getBySel('grid-container').find('.box_plot').should('not.exist'); + cy.getBySel('grid-container').find('.line').should('not.exist'); + cy.get('@top-level-tabs') .last() .click() @@ -68,42 +77,24 @@ describe('Dashboard tabs', () => { cy.get('@top-level-tabs') .first() .should('not.have.class', 'ant-tabs-tab-active'); - }); + waitForChartLoad(BOX_PLOT); + cy.getBySel('grid-container').find('.box_plot').should('be.visible'); - it('should load charts when tab is visible', () => { - // landing in first tab, should see 2 charts - waitForChartLoad(FILTER_BOX); - waitForChartLoad(TREEMAP); - cy.get('[data-test="grid-container"]') - .find('.box_plot') - .should('not.exist'); - cy.get('[data-test="grid-container"]').find('.line').should('not.exist'); + resetTabs(); // click row level tab, see 1 more chart - cy.get('[data-test="dashboard-component-tabs"]') - .last() + cy.getBySel('dashboard-component-tabs') + .eq(2) .find('[data-test="nav-list"] .ant-tabs-nav-list > .ant-tabs-tab') .as('row-level-tabs'); cy.get('@row-level-tabs').last().click(); - waitForChartLoad(LINE_CHART); - cy.get('[data-test="grid-container"]').find('.line').should('be.visible'); - - // click top level tab, see 1 more chart - handleException(); - cy.get('[data-test="dashboard-component-tabs"]') - .first() - .find('[data-test="nav-list"] .ant-tabs-nav-list > .ant-tabs-tab') - .as('top-level-tabs'); - - cy.get('@top-level-tabs').last().click(); - - // should exist a visible box_plot element - cy.get('[data-test="grid-container"]').find('.box_plot'); + cy.getBySel('grid-container').find('.line').should('be.visible'); + cy.get('@row-level-tabs').first().click(); }); - xit('should send new queries when tab becomes visible', () => { + it.skip('should send new queries when tab becomes visible', () => { // landing in first tab waitForChartLoad(FILTER_BOX); waitForChartLoad(TREEMAP); @@ -176,4 +167,30 @@ describe('Dashboard tabs', () => { }); }); }); + + it('should update size when switch tab', () => { + cy.get('@top-level-tabs') + .last() + .click() + .should('have.class', 'ant-tabs-tab-active'); + + expandFilterOnLeftPanel(); + + cy.wait(1000); + + cy.get('@top-level-tabs') + .first() + .click() + .should('have.class', 'ant-tabs-tab-active'); + + cy.wait(1000); + + cy.get("[data-test-viz-type='treemap'] .chart-container").then( + $chartContainer => { + expect($chartContainer.get(0).scrollWidth).eq( + $chartContainer.get(0).offsetWidth, + ); + }, + ); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilter.helper.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts similarity index 71% rename from superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilter.helper.ts rename to superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts index 5f43b330ceeac..29f1e1c2645b3 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilter.helper.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts @@ -16,8 +16,65 @@ * specific language governing permissions and limitations * under the License. */ + import { dashboardView, nativeFilters } from 'cypress/support/directories'; -import { testItems } from './dashboard.helper'; +import { ChartSpec, waitForChartLoad } from 'cypress/utils'; + +export const WORLD_HEALTH_CHARTS = [ + { name: '% Rural', viz: 'world_map' }, + { name: 'Most Populated Countries', viz: 'table' }, + { name: 'Region Filter', viz: 'filter_box' }, + { name: "World's Population", viz: 'big_number' }, + { name: 'Growth Rate', viz: 'line' }, + { name: 'Rural Breakdown', viz: 'sunburst' }, + { name: "World's Pop Growth", viz: 'area' }, + { name: 'Life Expectancy VS Rural %', viz: 'bubble' }, + { name: 'Treemap', viz: 'treemap' }, + { name: 'Box plot', viz: 'box_plot' }, +] as ChartSpec[]; + +export const SUPPORTED_TIER1_CHARTS = [ + { name: 'Big Number', viz: 'big_number_total' }, + { name: 'Big Number with Trendline', viz: 'big_number' }, + { name: 'Pie Chart', viz: 'pie' }, +] as ChartSpec[]; + +export const SUPPORTED_TIER2_CHARTS = [ + { name: 'Box Plot Chart', viz: 'box_plot' }, +] as ChartSpec[]; + +export const testItems = { + dashboard: 'Cypress test Dashboard', + dataset: 'Vehicle Sales', + datasetForNativeFilter: 'wb_health_population', + chart: 'Cypress chart', + newChart: 'New Cypress Chart', + createdDashboard: 'New Dashboard', + defaultNameDashboard: '[ untitled dashboard ]', + newDashboardTitle: `Test dashboard [NEW TEST]`, + bulkFirstNameDashboard: 'First Dash', + bulkSecondNameDashboard: 'Second Dash', + worldBanksDataCopy: `World Bank's Data [copy]`, + filterType: { + value: 'Value', + numerical: 'Numerical range', + timeColumn: 'Time column', + timeGrain: 'Time grain', + timeRange: 'Time range', + }, + topTenChart: { + name: 'Most Populated Countries', + filterColumn: 'country_name', + filterColumnYear: 'year', + filterColumnRegion: 'region', + filterColumnCountryCode: 'country_code', + }, + filterDefaultValue: 'United States', + filterOtherCountry: 'China', + filterTimeGrain: 'Month', + filterTimeColumn: 'created', + filterNumericalColumn: 'SP_RUR_TOTL_ZS', +}; export const nativeFilterTooltips = { searchAllFilterOptions: @@ -53,6 +110,73 @@ export const valueNativeFilterOptions = [ 'Filter value is required', ]; +export function interceptGet() { + cy.intercept('/api/v1/dashboard/*').as('get'); +} + +export function interceptFiltering() { + cy.intercept('GET', `/api/v1/dashboard/?q=*`).as('filtering'); +} + +export function interceptBulkDelete() { + cy.intercept('DELETE', `/api/v1/dashboard/?q=*`).as('bulkDelete'); +} + +export function interceptDelete() { + cy.intercept('DELETE', `/api/v1/dashboard/*`).as('delete'); +} + +export function interceptUpdate() { + cy.intercept('PUT', `/api/v1/dashboard/*`).as('update'); +} + +export function interceptPost() { + cy.intercept('POST', `/api/v1/dashboard/`).as('post'); +} + +export function interceptLog() { + cy.intercept('/superset/log/?explode=events&dashboard_id=*').as('logs'); +} + +export function interceptFav() { + cy.intercept(`/superset/favstar/Dashboard/*/select/`).as('select'); +} + +export function interceptUnfav() { + cy.intercept(`/superset/favstar/Dashboard/*/unselect/`).as('unselect'); +} + +export function interceptDataset() { + cy.intercept('GET', `/api/v1/dataset/*`).as('getDataset'); +} + +export function interceptCharts() { + cy.intercept('GET', `/api/v1/dashboard/*/charts`).as('getCharts'); +} + +export function interceptDatasets() { + cy.intercept('GET', `/api/v1/dashboard/*/datasets`).as('getDatasets'); +} + +export function interceptDashboardasync() { + cy.intercept('GET', `/dashboardasync/api/read*`).as('getDashboardasync'); +} + +export function interceptFilterState() { + cy.intercept('POST', `/api/v1/dashboard/*/filter_state*`).as( + 'postFilterState', + ); +} + +export function setFilter(filter: string, option: string) { + interceptFiltering(); + + cy.get(`[aria-label="${filter}"]`).first().click(); + cy.get(`[aria-label="${filter}"] [title="${option}"]`).click(); + + cy.wait('@filtering'); +} + /** ************************************************************************ * Expend Native filter from the left panel on dashboard * @returns {None} @@ -84,11 +208,15 @@ export function collapseFilterOnLeftPanel() { * @returns {None} * @summary helper for enter native filter edit modal ************************************************************************* */ -export function enterNativeFilterEditModal() { +export function enterNativeFilterEditModal(waitForDataset = true) { + interceptDataset(); cy.get(nativeFilters.filterFromDashboardView.createFilterButton).click({ force: true, }); cy.get(nativeFilters.modal.container).should('be.visible'); + if (waitForDataset) { + cy.wait('@getDataset'); + } } /** ************************************************************************ @@ -178,11 +306,12 @@ export function getNativeFilterPlaceholderWithIndex(index: number) { export function applyNativeFilterValueWithIndex(index: number, value: string) { cy.get(nativeFilters.filterFromDashboardView.filterValueInput) .eq(index) - .parent() - .should('be.visible', { timeout: 10000 }) + .should('exist', { timeout: 10000 }) .type(`${value}{enter}`); // click the title to dismiss shown options - cy.get(nativeFilters.filterFromDashboardView.filterName).eq(index).click(); + cy.get(nativeFilters.filterFromDashboardView.filterName) + .eq(index) + .click({ force: true }); } /** ************************************************************************ @@ -208,16 +337,17 @@ export function addParentFilterWithValue(index: number, value: string) { * @returns {None} * @summary helper for save native filters settings ************************************************************************* */ -export function saveNativeFilterSettings() { +export function saveNativeFilterSettings(charts: ChartSpec[]) { cy.get(nativeFilters.modal.footer) .contains('Save') .should('be.visible') .click(); cy.get(nativeFilters.modal.container).should('not.exist'); + charts.forEach(waitForChartLoad); } /** ************************************************************************ - * Cancel Native fitler settings + * Cancel Native filter settings * @returns {None} * @summary helper for cancel native filters settings ************************************************************************* */ @@ -227,39 +357,15 @@ export function cancelNativeFilterSettings() { .should('be.visible') .click(); cy.get(nativeFilters.modal.alertXUnsavedFilters) - .should('have.text', 'There are unsaved changes.') - .should('be.visible'); + .should('be.visible') + .should('have.text', 'There are unsaved changes.'); cy.get(nativeFilters.modal.footer) .find(nativeFilters.modal.yesCancelButton) .contains('cancel') - .should('be.visible') - .click(); + .click({ force: true }); cy.get(nativeFilters.modal.container).should('not.exist'); } -/** ************************************************************************ - * Close dashboard toast message - * @returns {None} - * @summary helper for close dashboard toast message in order to make test stable - ************************************************************************* */ -export function closeDashboardToastMessage() { - cy.get('body').then($body => { - if ($body.find(dashboardView.dashboardAlert.modal).length > 0) { - // evaluates as true if button exists at all - cy.get(dashboardView.dashboardAlert.modal).then($header => { - if ($header.is(':visible')) { - cy.get(dashboardView.dashboardAlert.closeButton).click({ - force: true, - }); - cy.get(dashboardView.dashboardAlert.closeButton).should('not.exist', { - timeout: 10000, - }); - } - }); - } - }); -} - /** ************************************************************************ * Validate filter name on dashboard * @param name: filter name to validate @@ -356,18 +462,34 @@ export function applyAdvancedTimeRangeFilterOnDashboard( * @return {null} * @summary helper for input default valule in Native filter in filter settings ************************************************************************* */ -export function inputNativeFilterDefaultValue(defaultValue: string) { - cy.contains('Filter has default value').click(); - cy.contains('Default value is required').should('be.visible'); - cy.get(nativeFilters.modal.container).within(() => { - cy.get(nativeFilters.filterConfigurationSections.filterPlaceholder) - .contains('options') - .should('be.visible'); - cy.get(nativeFilters.filterConfigurationSections.collapsedSectionContainer) - .first() - .get(nativeFilters.filtersPanel.columnEmptyInput) - .type(`${defaultValue}{enter}`); - }); +export function inputNativeFilterDefaultValue( + defaultValue: string, + multiple = false, +) { + if (!multiple) { + cy.contains('Filter has default value').click(); + cy.contains('Default value is required').should('be.visible'); + cy.get(nativeFilters.modal.container).within(() => { + cy.get( + nativeFilters.filterConfigurationSections.filterPlaceholder, + ).contains('options'); + cy.get( + nativeFilters.filterConfigurationSections.collapsedSectionContainer, + ) + .eq(1) + .within(() => { + cy.get('.ant-select-selection-search-input').type( + `${defaultValue}{enter}`, + { force: true }, + ); + }); + }); + } else { + cy.getBySel('default-input').within(() => { + cy.get('.ant-select-selection-search-input').click(); + cy.get('.ant-select-item-option-content').contains(defaultValue).click(); + }); + } } /** ************************************************************************ @@ -384,30 +506,11 @@ export function addCountryNameFilter() { ); } -/** ************************************************************************ - * add filter for test column 'Region' - * @return {null} - * @summary helper for add filter for test column 'Region' - ************************************************************************* */ -export function addRegionFilter() { - fillNativeFilterForm( - testItems.filterType.value, - testItems.topTenChart.filterColumnRegion, - testItems.datasetForNativeFilter, - testItems.topTenChart.filterColumnRegion, - ); -} - -/** ************************************************************************ - * add filter for test column 'Country Code' - * @return {null} - * @summary helper for add filter for test column 'Country Code' - ************************************************************************* */ -export function addCountryCodeFilter() { - fillNativeFilterForm( - testItems.filterType.value, - testItems.topTenChart.filterColumnCountryCode, - testItems.datasetForNativeFilter, - testItems.topTenChart.filterColumnCountryCode, - ); +export function openTab(tabComponentIndex: number, tabIndex: number) { + return cy + .getBySel('dashboard-component-tabs') + .eq(tabComponentIndex) + .find('[role="tab"]') + .eq(tabIndex) + .click(); } diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/card_view.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/card_view.test.ts deleted file mode 100644 index 8bfc35d71c846..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/card_view.test.ts +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { DASHBOARD_LIST } from './dashboard_list.helper'; - -describe('Dashboard card view', () => { - beforeEach(() => { - cy.login(); - cy.visit(DASHBOARD_LIST); - cy.get('[aria-label="card-view"]').click(); - }); - - xit('should load cards', () => { - cy.get('[data-test="dashboard-list-view"]'); - cy.get('[data-test="styled-card"]').should('be.visible'); - cy.get('[data-test="styled-card"]').should('have.length', 4); // failed, xit-ed - }); - - it('should allow to favorite/unfavorite dashboard card', () => { - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('not.exist'); - cy.get("[data-test='card-actions']") - .find("[aria-label='favorite-unselected']") - .first() - .click(); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('be.visible'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('not.exist'); - - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('not.exist'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .click(); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('be.visible'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('not.exist'); - }); - - xit('should sort correctly', () => { - // sort alphabetical - cy.get('.Select__control').last().should('be.visible'); - cy.get('.Select__control').last().click({ force: true }); - cy.get('.Select__menu').contains('Alphabetical').click(); - cy.get('[data-test="dashboard-list-view"]').should('be.visible'); - // TODO this line was flaky - cy.get('[data-test="styled-card"]').first().contains('Tabbed Dashboard'); - cy.get('[data-test="styled-card"]').last().contains("World Bank's Data"); - - // sort recently modified - cy.get('.Select__control').last().should('be.visible'); - cy.get('.Select__control').last().click({ force: true }); - cy.get('.Select__menu').contains('Recently Modified').click(); - cy.get('[data-test="dashboard-list-view"]').should('be.visible'); - cy.get('[data-test="styled-card"]').first().contains('Tabbed Dashboard'); - cy.get('[data-test="styled-card"]').last().contains("World Bank's Data"); - }); - - // real flaky - xit('should delete correctly', () => { - // show delete modal - cy.get('[data-test="more-horiz"]').last().trigger('mouseover'); - cy.get('[data-test="dashboard-card-option-delete-button"]') - .last() - .should('be.visible') - .click(); - cy.get('[data-test="modal-confirm-button"]').should( - 'have.attr', - 'disabled', - ); - cy.get('[data-test="Please Confirm-modal"]').should('be.visible'); - cy.get("[data-test='delete-modal-input']").type('DELETE'); - cy.get('[data-test="modal-confirm-button"]').should( - 'not.have.attr', - 'disabled', - ); - cy.get('[data-test="modal-cancel-button"]').click(); - }); - - // real flaky - xit('should edit correctly', () => { - // show edit modal - cy.get('[data-test="more-horiz"]').last().trigger('mouseover'); - cy.get('[data-test="dashboard-card-option-edit-button"]') - .last() - .should('be.visible') - .click(); - cy.get('[data-test="dashboard-edit-properties-form"]').should('be.visible'); - cy.get('[data-test="dashboard-title-input"]').should('not.have.value'); - cy.get('[data-test="properties-modal-cancel-button"]') - .contains('Cancel') - .click(); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts index dd95eefdb2ff2..4e9c84d6ea028 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts @@ -16,11 +16,10 @@ * specific language governing permissions and limitations * under the License. */ -import { DASHBOARD_LIST } from './dashboard_list.helper'; +import { DASHBOARD_LIST } from 'cypress/utils/urls'; describe('dashboard list view', () => { beforeEach(() => { - cy.login(); cy.visit(DASHBOARD_LIST); }); @@ -33,7 +32,7 @@ describe('dashboard list view', () => { cy.eyesOpen({ testName: 'Dashboards list-view', }); - cy.eyesCheckWindow('Dashboards loaded'); + cy.eyesCheckWindow('Dashboards list-view loaded'); }); it('should load the Dashboards card list', () => { @@ -41,6 +40,6 @@ describe('dashboard list view', () => { cy.eyesOpen({ testName: 'Dashboards card-view', }); - cy.eyesCheckWindow('Dashboards loaded'); + cy.eyesCheckWindow('Dashboards card-view loaded'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts index bf852fc62558f..4654b3b5c2634 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts @@ -16,86 +16,32 @@ * specific language governing permissions and limitations * under the License. */ -import { DASHBOARD_LIST } from './dashboard_list.helper'; +import { DASHBOARD_LIST } from 'cypress/utils/urls'; +import { setGridMode, clearAllInputs } from 'cypress/utils'; +import { setFilter } from '../dashboard/utils'; -describe('dashboard filters card view', () => { - beforeEach(() => { - cy.login(); +describe('Dashboards filters', () => { + before(() => { cy.visit(DASHBOARD_LIST); - cy.get('[aria-label="card-view"]').click(); - }); - - it('should filter by owners correctly', () => { - // filter by owners - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="styled-card"]').should('not.exist'); - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="styled-card"]').should('not.exist'); - }); - - it('should filter by created by correctly', () => { - // filter by created by - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('.ant-card').should('not.exist'); - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('.ant-card').should('not.exist'); + setGridMode('card'); }); - it('should filter by published correctly', () => { - // filter by published - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('.rc-virtual-list').contains('Published').click({ timeout: 5000 }); - cy.get('[data-test="styled-card"]').should('have.length', 3); - cy.get('[data-test="styled-card"]') - .contains('USA Births Names') - .should('be.visible'); - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('[data-test="filters-select"]').eq(1).type('unpub{enter}'); - cy.get('[data-test="styled-card"]').should('have.length', 3); - }); -}); - -describe('dashboard filters list view', () => { beforeEach(() => { - cy.login(); - cy.visit(DASHBOARD_LIST); - cy.get('[aria-label="list-view"]').click(); + clearAllInputs(); }); - it('should filter by owners correctly', () => { - // filter by owners - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); + it('should allow filtering by "Owner" correctly', () => { + setFilter('Owner', 'alpha user'); + setFilter('Owner', 'admin user'); }); - it('should filter by created by correctly', () => { - // filter by created by - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); + it('should allow filtering by "Created by" correctly', () => { + setFilter('Created by', 'alpha user'); + setFilter('Created by', 'admin user'); }); - it('should filter by published correctly', () => { - // filter by published - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('.rc-virtual-list').contains('Published').click(); - cy.get('[data-test="table-row"]').should('have.length', 3); - cy.get('[data-test="table-row"]') - .contains('USA Births Names') - .should('be.visible'); - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('[data-test="filters-select"]').eq(2).type('unpub{enter}'); - cy.get('[data-test="table-row"]').should('have.length', 3); + it('should allow filtering by "Status" correctly', () => { + setFilter('Status', 'Published'); + setFilter('Status', 'Draft'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts new file mode 100644 index 0000000000000..9bc6eed224578 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts @@ -0,0 +1,244 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { DASHBOARD_LIST } from 'cypress/utils/urls'; +import { setGridMode, toggleBulkSelect } from 'cypress/utils'; +import { + setFilter, + interceptBulkDelete, + interceptUpdate, + interceptDelete, + interceptFav, + interceptUnfav, +} from '../dashboard/utils'; + +function orderAlphabetical() { + setFilter('Sort', 'Alphabetical'); +} + +function openProperties() { + cy.get('[aria-label="more-vert"]').first().click(); + cy.getBySel('dashboard-card-option-edit-button').click(); +} + +function openMenu() { + cy.get('[aria-label="more-vert"]').first().click(); +} + +function confirmDelete() { + cy.getBySel('delete-modal-input').type('DELETE'); + cy.getBySel('modal-confirm-button').click(); +} + +describe('Dashboards list', () => { + describe('list mode', () => { + before(() => { + cy.visit(DASHBOARD_LIST); + setGridMode('list'); + }); + + it('should load rows in list mode', () => { + cy.getBySel('listview-table').should('be.visible'); + cy.getBySel('sort-header').eq(1).contains('Title'); + cy.getBySel('sort-header').eq(2).contains('Modified by'); + cy.getBySel('sort-header').eq(3).contains('Status'); + cy.getBySel('sort-header').eq(4).contains('Modified'); + cy.getBySel('sort-header').eq(5).contains('Created by'); + cy.getBySel('sort-header').eq(6).contains('Owners'); + cy.getBySel('sort-header').eq(7).contains('Actions'); + }); + + it('should sort correctly in list mode', () => { + cy.getBySel('sort-header').eq(1).click(); + cy.getBySel('table-row').first().contains('Supported Charts Dashboard'); + cy.getBySel('sort-header').eq(1).click(); + cy.getBySel('table-row').first().contains("World Bank's Data"); + cy.getBySel('sort-header').eq(1).click(); + }); + + it('should bulk select in list mode', () => { + toggleBulkSelect(); + cy.get('#header-toggle-all').click(); + cy.get('[aria-label="checkbox-on"]').should('have.length', 6); + cy.getBySel('bulk-select-copy').contains('5 Selected'); + cy.getBySel('bulk-select-action') + .should('have.length', 2) + .then($btns => { + expect($btns).to.contain('Delete'); + expect($btns).to.contain('Export'); + }); + cy.getBySel('bulk-select-deselect-all').click(); + cy.get('[aria-label="checkbox-on"]').should('have.length', 0); + cy.getBySel('bulk-select-copy').contains('0 Selected'); + cy.getBySel('bulk-select-action').should('not.exist'); + }); + }); + + describe('card mode', () => { + before(() => { + cy.visit(DASHBOARD_LIST); + setGridMode('card'); + }); + + it('should load rows in card mode', () => { + cy.getBySel('listview-table').should('not.exist'); + cy.getBySel('styled-card').should('have.length', 5); + }); + + it('should bulk select in card mode', () => { + toggleBulkSelect(); + cy.getBySel('styled-card').click({ multiple: true }); + cy.getBySel('bulk-select-copy').contains('5 Selected'); + cy.getBySel('bulk-select-action') + .should('have.length', 2) + .then($btns => { + expect($btns).to.contain('Delete'); + expect($btns).to.contain('Export'); + }); + cy.getBySel('bulk-select-deselect-all').click(); + cy.getBySel('bulk-select-copy').contains('0 Selected'); + cy.getBySel('bulk-select-action').should('not.exist'); + }); + + it('should sort in card mode', () => { + orderAlphabetical(); + cy.getBySel('styled-card').first().contains('Supported Charts Dashboard'); + }); + }); + + describe('common actions', () => { + beforeEach(() => { + cy.createSampleDashboards([0, 1, 2, 3]); + cy.visit(DASHBOARD_LIST); + }); + + it('should allow to favorite/unfavorite dashboard', () => { + interceptFav(); + interceptUnfav(); + + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel('styled-card').first().contains('1 - Sample dashboard'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-unselected']") + .click(); + cy.wait('@select'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-selected']") + .click(); + cy.wait('@unselect'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-selected']") + .should('not.exist'); + }); + + it('should bulk delete correctly', () => { + interceptBulkDelete(); + toggleBulkSelect(); + + // bulk deletes in card-view + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel('styled-card').eq(0).contains('1 - Sample dashboard').click(); + cy.getBySel('styled-card').eq(1).contains('2 - Sample dashboard').click(); + cy.getBySel('bulk-select-action').eq(0).contains('Delete').click(); + confirmDelete(); + cy.wait('@bulkDelete'); + cy.getBySel('styled-card') + .eq(0) + .should('not.contain', '1 - Sample dashboard'); + cy.getBySel('styled-card') + .eq(1) + .should('not.contain', '2 - Sample dashboard'); + + // bulk deletes in list-view + setGridMode('list'); + cy.getBySel('table-row').eq(0).contains('3 - Sample dashboard'); + cy.getBySel('table-row').eq(1).contains('4 - Sample dashboard'); + cy.get('[data-test="table-row"] input[type="checkbox"]').eq(0).click(); + cy.get('[data-test="table-row"] input[type="checkbox"]').eq(1).click(); + cy.getBySel('bulk-select-action').eq(0).contains('Delete').click(); + confirmDelete(); + cy.wait('@bulkDelete'); + cy.getBySel('table-row') + .eq(0) + .should('not.contain', '3 - Sample dashboard'); + cy.getBySel('table-row') + .eq(1) + .should('not.contain', '4 - Sample dashboard'); + }); + + it('should delete correctly', () => { + interceptDelete(); + + // deletes in card-view + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel('styled-card').eq(0).contains('1 - Sample dashboard'); + openMenu(); + cy.getBySel('dashboard-card-option-delete-button').click(); + confirmDelete(); + cy.wait('@delete'); + cy.getBySel('styled-card') + .eq(0) + .should('not.contain', '1 - Sample dashboard'); + + // deletes in list-view + setGridMode('list'); + cy.getBySel('table-row').eq(0).contains('2 - Sample dashboard'); + cy.getBySel('dashboard-list-trash-icon').eq(0).click(); + confirmDelete(); + cy.wait('@delete'); + cy.getBySel('table-row') + .eq(0) + .should('not.contain', '2 - Sample dashboard'); + }); + + it('should edit correctly', () => { + interceptUpdate(); + + // edits in card-view + setGridMode('card'); + orderAlphabetical(); + cy.getBySel('styled-card').eq(0).contains('1 - Sample dashboard'); + + // change title + openProperties(); + cy.getBySel('dashboard-title-input').type(' | EDITED'); + cy.get('button:contains("Save")').click(); + cy.wait('@update'); + cy.getBySel('styled-card') + .eq(0) + .contains('1 - Sample dashboard | EDITED'); + + // edits in list-view + setGridMode('list'); + cy.getBySel('edit-alt').eq(0).click(); + cy.getBySel('dashboard-title-input').clear().type('1 - Sample dashboard'); + cy.get('button:contains("Save")').click(); + cy.wait('@update'); + cy.getBySel('table-row').eq(0).contains('1 - Sample dashboard'); + }); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts deleted file mode 100644 index a758552481f90..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { DASHBOARD_LIST } from './dashboard_list.helper'; - -describe('dashboard list view', () => { - beforeEach(() => { - cy.login(); - cy.visit(DASHBOARD_LIST); - cy.get('[aria-label="list-view"]').click(); - }); - - xit('should load rows', () => { - cy.get('[data-test="listview-table"]').should('be.visible'); - // check dashboard list view header - cy.get('[data-test="sort-header"]').eq(1).contains('Title'); - cy.get('[data-test="sort-header"]').eq(2).contains('Modified by'); - cy.get('[data-test="sort-header"]').eq(3).contains('Status'); - cy.get('[data-test="sort-header"]').eq(4).contains('Modified'); - cy.get('[data-test="sort-header"]').eq(5).contains('Created by'); - cy.get('[data-test="sort-header"]').eq(6).contains('Owners'); - cy.get('[data-test="sort-header"]').eq(7).contains('Actions'); - cy.get('[data-test="table-row"]').should('have.length', 4); // failed, xit-ed - }); - - xit('should sort correctly', () => { - cy.get('[data-test="sort-header"]').eq(1).click(); - cy.get('[data-test="sort-header"]').eq(1).click(); - cy.get('[data-test="table-row"]') - .first() - .find('[data-test="table-row-cell"]') - .find('[data-test="cell-text"]') - .contains("World Bank's Data"); - }); - - it('should bulk delete correctly', () => { - cy.get('[data-test="listview-table"]').should('be.visible'); - cy.get('[data-test="bulk-select"]').eq(0).click(); - cy.get('[aria-label="checkbox-off"]').eq(1).siblings('input').click(); - cy.get('[aria-label="checkbox-off"]').eq(2).siblings('input').click(); - cy.get('[data-test="bulk-select-action"]').eq(0).click(); - cy.get('[data-test="delete-modal-input"]').eq(0).type('DELETE'); - cy.get('[data-test="modal-confirm-button"]').eq(0).click(); - cy.get('[aria-label="checkbox-on"]').should('not.exist'); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts b/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts index 2255021676560..a3260250aa47f 100644 --- a/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts @@ -16,14 +16,24 @@ * specific language governing permissions and limitations * under the License. */ -import { DATABASE_LIST } from './helper'; +import { DATABASE_LIST } from 'cypress/utils/urls'; + +function closeModal() { + cy.get('body').then($body => { + if ($body.find('[data-test="database-modal"]').length) { + cy.get('[aria-label="Close"]').eq(1).click(); + } + }); +} describe('Add database', () => { - beforeEach(() => { - cy.login(); + before(() => { cy.visit(DATABASE_LIST); - cy.wait(3000); - cy.get('[data-test="btn-create-database"]').click(); + }); + + beforeEach(() => { + closeModal(); + cy.getBySel('btn-create-database').click(); }); it('should open dynamic form', () => { @@ -42,11 +52,11 @@ describe('Add database', () => { // click postgres dynamic form cy.get('.preferred > :nth-child(1)').click(); - cy.get('[data-test="sqla-connect-btn"]').click(); + cy.getBySel('sqla-connect-btn').click(); // check if the sqlalchemy form is showing up - cy.get('[data-test=database-name-input]').should('be.visible'); - cy.get('[data-test="sqlalchemy-uri-input"]').should('be.visible'); + cy.getBySel('database-name-input').should('be.visible'); + cy.getBySel('sqlalchemy-uri-input').should('be.visible'); }); it('show error alerts on dynamic form for bad host', () => { diff --git a/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts b/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts new file mode 100644 index 0000000000000..e78c328ec5104 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { DATASET_LIST_PATH } from 'cypress/utils/urls'; + +describe('Dataset list', () => { + before(() => { + cy.visit(DATASET_LIST_PATH); + }); + + it('should open Explore on dataset name click', () => { + cy.intercept('**/api/v1/explore/**').as('explore'); + cy.get('[data-test="listview-table"] [data-test="internal-link"]') + .contains('birth_names') + .click(); + cy.wait('@explore'); + cy.get('[data-test="datasource-control"] .title-select').contains( + 'birth_names', + ); + cy.get('.metric-option-label').first().contains('COUNT(*)'); + cy.get('.column-option-label').first().contains('ds'); + cy.get('[data-test="fast-viz-switcher"] > div:not([role="button"]') + .contains('Table') + .should('be.visible'); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts index deb829a092dca..e97ac74c3f2a2 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts @@ -18,7 +18,6 @@ */ describe('AdhocMetrics', () => { beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('postJson'); cy.intercept('GET', '/superset/explore_json/**').as('getJson'); cy.visitChartByName('Num Births Trend'); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/AdhocFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/_skip.AdhocFilters.test.ts similarity index 92% rename from superset-frontend/cypress-base/cypress/integration/explore/AdhocFilters.test.ts rename to superset-frontend/cypress-base/cypress/integration/explore/_skip.AdhocFilters.test.ts index 6ae5aead2b0c3..a4e9c8fe46888 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/AdhocFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/_skip.AdhocFilters.test.ts @@ -16,10 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -describe('AdhocFilters', () => { +describe.skip('AdhocFilters', () => { beforeEach(() => { - cy.login(); - cy.intercept('GET', '/superset/filter/table/*/name').as('filterValues'); + cy.intercept('GET', '/api/v1/datasource/table/*/column/name/values').as( + 'filterValues', + ); cy.intercept('POST', '/superset/explore_json/**').as('postJson'); cy.intercept('GET', '/superset/explore_json/**').as('getJson'); cy.visitChartByName('Boys'); // a table chart @@ -28,7 +29,7 @@ describe('AdhocFilters', () => { let numScripts = 0; - xit('Should load AceEditor scripts when needed', () => { + it('Should load AceEditor scripts when needed', () => { cy.get('script').then(nodes => { numScripts = nodes.length; }); @@ -51,7 +52,7 @@ describe('AdhocFilters', () => { }); }); - xit('Set simple adhoc filter', () => { + it('Set simple adhoc filter', () => { cy.get('[aria-label="Comparator option"] .Select__control').click(); cy.get('[data-test=adhoc-filter-simple-value] input[type=text]') .focus() @@ -70,7 +71,7 @@ describe('AdhocFilters', () => { }); }); - xit('Set custom adhoc filter', () => { + it('Set custom adhoc filter', () => { const filterType = 'name'; const filterContent = "'Amy' OR name = 'Donald'"; diff --git a/superset-frontend/cypress-base/cypress/integration/explore/advanced_analytics.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/advanced_analytics.test.ts index 51fd2ce46bb39..fd207a64e3124 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/advanced_analytics.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/advanced_analytics.test.ts @@ -18,18 +18,19 @@ */ describe('Advanced analytics', () => { beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('postJson'); cy.intercept('GET', '/superset/explore_json/**').as('getJson'); cy.intercept('PUT', '/api/v1/explore/**').as('putExplore'); - cy.intercept('GET', '/superset/explore/**').as('getExplore'); + cy.intercept('GET', '/explore/**').as('getExplore'); }); it('Create custom time compare', () => { cy.visitChartByName('Num Births Trend'); cy.verifySliceSuccess({ waitAlias: '@postJson' }); - cy.get('.ant-collapse-header').contains('Advanced Analytics').click(); + cy.get('.ant-collapse-header') + .contains('Advanced Analytics') + .click({ force: true }); cy.get('[data-test=time_compare]').find('.ant-select').click(); cy.get('[data-test=time_compare]') @@ -43,13 +44,16 @@ describe('Advanced analytics', () => { cy.get('button[data-test="run-query-button"]').click(); cy.wait('@postJson'); cy.wait('@putExplore'); + cy.reload(); cy.verifySliceSuccess({ waitAlias: '@postJson', chartSelector: 'svg', }); cy.wait('@getExplore'); - cy.get('.ant-collapse-header').contains('Advanced Analytics').click(); + cy.get('.ant-collapse-header') + .contains('Advanced Analytics') + .click({ force: true }); cy.get('[data-test=time_compare]') .find('.ant-select-selector') .contains('28 days'); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/annotations.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/annotations.test.ts index 448a676f67307..a10295af964fe 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/annotations.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/annotations.test.ts @@ -18,7 +18,6 @@ */ describe('Annotations', () => { beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('postJson'); cy.intercept('GET', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js b/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js index c9f4a1c9f58bf..cade5fab24ad3 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js @@ -16,11 +16,114 @@ * specific language governing permissions and limitations * under the License. */ +import { CHART_LIST } from 'cypress/utils/urls'; +import { interceptGet as interceptDashboardGet } from 'cypress/integration/dashboard/utils'; import { FORM_DATA_DEFAULTS, NUM_METRIC } from './visualizations/shared.helper'; +import { + interceptFiltering, + saveChartToDashboard, + visitSampleChartFromList, +} from './utils'; + +// SEARCH_THRESHOLD is 10. We need to add at least 11 dashboards to show search +const SAMPLE_DASHBOARDS_INDEXES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + +function openDashboardsAddedTo() { + cy.getBySel('actions-trigger').click(); + cy.get('.ant-dropdown-menu-submenu-title') + .contains('Dashboards added to') + .trigger('mouseover'); +} + +function closeDashboardsAddedTo() { + cy.get('.ant-dropdown-menu-submenu-title') + .contains('Dashboards added to') + .trigger('mouseout'); + cy.getBySel('actions-trigger').click(); +} + +function verifyDashboardsSubmenuItem(dashboardName) { + cy.get('.ant-dropdown-menu-submenu-popup').contains(dashboardName); + closeDashboardsAddedTo(); +} + +function verifyDashboardSearch() { + openDashboardsAddedTo(); + cy.get('.ant-dropdown-menu-submenu-popup').trigger('mouseover'); + cy.get('.ant-dropdown-menu-submenu-popup') + .find('input[placeholder="Search"]') + .type('1'); + cy.get('.ant-dropdown-menu-submenu-popup').contains('1 - Sample dashboard'); + cy.get('.ant-dropdown-menu-submenu-popup') + .find('input[placeholder="Search"]') + .type('Blahblah'); + cy.get('.ant-dropdown-menu-submenu-popup').contains('No results found'); + cy.get('.ant-dropdown-menu-submenu-popup') + .find('[aria-label="close-circle"]') + .click(); + closeDashboardsAddedTo(); +} + +function verifyDashboardLink() { + interceptDashboardGet(); + openDashboardsAddedTo(); + cy.get('.ant-dropdown-menu-submenu-popup').trigger('mouseover'); + cy.get('.ant-dropdown-menu-submenu-popup a') + .first() + .invoke('removeAttr', 'target') + .click(); + cy.wait('@get'); +} + +function verifyMetabar(text) { + cy.getBySel('metadata-bar').contains(text); +} + +function saveAndVerifyDashboard(number) { + saveChartToDashboard(`${number} - Sample dashboard`); + verifyMetabar( + number > 1 ? `Added to ${number} dashboards` : 'Added to 1 dashboard', + ); + openDashboardsAddedTo(); + verifyDashboardsSubmenuItem(`${number} - Sample dashboard`); +} + +describe('Cross-referenced dashboards', () => { + beforeEach(() => { + interceptFiltering(); + + cy.createSampleDashboards(SAMPLE_DASHBOARDS_INDEXES); + cy.createSampleCharts([0]); + cy.visit(CHART_LIST); + cy.wait('@filtering'); + }); + + it('should show the cross-referenced dashboards', () => { + visitSampleChartFromList('1 - Sample chart'); + + cy.getBySel('metadata-bar').contains('Not added to any dashboard'); + openDashboardsAddedTo(); + verifyDashboardsSubmenuItem('None'); + + saveAndVerifyDashboard('1'); + saveAndVerifyDashboard('2'); + saveAndVerifyDashboard('3'); + saveAndVerifyDashboard('4'); + saveAndVerifyDashboard('5'); + saveAndVerifyDashboard('6'); + saveAndVerifyDashboard('7'); + saveAndVerifyDashboard('8'); + saveAndVerifyDashboard('9'); + saveAndVerifyDashboard('10'); + saveAndVerifyDashboard('11'); + + verifyDashboardSearch(); + verifyDashboardLink(); + }); +}); describe('No Results', () => { beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); @@ -41,7 +144,7 @@ describe('No Results', () => { ], }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.wait('@getJson').its('response.statusCode').should('eq', 200); cy.get('div.chart-container').contains( 'No results were returned for this query', diff --git a/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts index cd15af566f2dd..9fa966d9bb675 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts @@ -25,49 +25,46 @@ import { FORM_DATA_DEFAULTS, NUM_METRIC } from './visualizations/shared.helper'; describe('Datasource control', () => { const newMetricName = `abc${Date.now()}`; - // TODO: uncomment when adding metrics from dataset is fixed - xit('should allow edit dataset', () => { - let numScripts = 0; - - cy.login(); - interceptChart({ legacy: false }).as('chartData'); + it('should allow edit dataset', () => { + interceptChart({ legacy: true }).as('chartData'); cy.visitChartByName('Num Births Trend'); cy.verifySliceSuccess({ waitAlias: '@chartData' }); - cy.get('[data-test="open-datasource-tab').click({ force: true }); cy.get('[data-test="datasource-menu-trigger"]').click(); - cy.get('script').then(nodes => { - numScripts = nodes.length; - }); - cy.get('[data-test="edit-dataset"]').click(); - // should load additional scripts for the modal - cy.get('script').then(nodes => { - expect(nodes.length).to.greaterThan(numScripts); - }); cy.get('[data-test="edit-dataset-tabs"]').within(() => { cy.contains('Metrics').click(); }); // create new metric cy.get('[data-test="crud-add-table-item"]', { timeout: 10000 }).click(); - cy.get('[data-test="table-content-rows"]') - .find('input[value="<new metric>"]') + cy.wait(1000); + cy.get( + '[data-test="table-content-rows"] [data-test="editable-title-input"]', + ) + .first() .click(); - cy.get('[data-test="table-content-rows"]') - .find('input[value="<new metric>"]') + + cy.get( + '[data-test="table-content-rows"] [data-test="editable-title-input"]', + ) + .first() .focus() .clear() .type(`${newMetricName}{enter}`); + cy.get('[data-test="datasource-modal-save"]').click(); cy.get('.ant-modal-confirm-btns button').contains('OK').click(); // select new metric cy.get('[data-test=metrics]') - .find('.Select__control input') - .focus() - .type(newMetricName, { force: true }); + .contains('Drop columns/metrics here or click') + .click(); + + cy.get('input[aria-label="Select saved metrics"]').type( + `${newMetricName}{enter}`, + ); // delete metric cy.get('[data-test="datasource-menu-trigger"]').click(); cy.get('[data-test="edit-dataset"]').click(); @@ -78,19 +75,46 @@ describe('Datasource control', () => { }); cy.get(`input[value="${newMetricName}"]`) .closest('tr') - .find('.fa-trash') + .find('[data-test="crud-delete-icon"]') .click(); cy.get('[data-test="datasource-modal-save"]').click(); cy.get('.ant-modal-confirm-btns button').contains('OK').click(); - cy.get('.Select__multi-value__label') - .contains(newMetricName) - .should('not.exist'); + cy.get('[data-test="metrics"]').contains(newMetricName).should('not.exist'); }); }); +describe('Color scheme control', () => { + beforeEach(() => { + interceptChart({ legacy: true }).as('chartData'); + + cy.visitChartByName('Num Births Trend'); + cy.verifySliceSuccess({ waitAlias: '@chartData' }); + }); + + it('should show color options with and without tooltips', () => { + cy.get('#controlSections-tab-display').click(); + cy.get('.ant-select-selection-item .color-scheme-label').contains( + 'Superset Colors', + ); + cy.get('.ant-select-selection-item .color-scheme-label').trigger( + 'mouseover', + ); + cy.get('.color-scheme-tooltip').contains('Superset Colors'); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('lyftColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="lyftColors"]', + ).should('exist'); + cy.get('.ant-select-selection-item .color-scheme-label').trigger( + 'mouseover', + ); + cy.get('.color-scheme-tooltip').should('not.exist'); + }); +}); describe('VizType control', () => { beforeEach(() => { - cy.login(); interceptChart({ legacy: false }).as('tableChartData'); interceptChart({ legacy: true }).as('lineChartData'); }); @@ -117,7 +141,6 @@ describe('VizType control', () => { describe('Test datatable', () => { beforeEach(() => { - cy.login(); interceptChart({ legacy: false }).as('tableChartData'); interceptChart({ legacy: true }).as('lineChartData'); cy.visitChartByName('Daily Totals'); @@ -128,15 +151,22 @@ describe('Test datatable', () => { cy.get('.ant-empty-description').should('not.exist'); }); it('Datapane loads view samples', () => { - cy.contains('Samples').click(); - cy.get('[data-test="row-count-label"]').contains('1k rows'); - cy.get('.ant-empty-description').should('not.exist'); + cy.intercept( + 'datasource/samples?force=false&datasource_type=table&datasource_id=*', + ).as('Samples'); + cy.contains('Samples') + .click() + .then(() => { + cy.wait('@Samples'); + cy.get('.ant-tabs-tab-active').contains('Samples'); + cy.get('[data-test="row-count-label"]').contains('1k rows'); + cy.get('.ant-empty-description').should('not.exist'); + }); }); }); describe('Time range filter', () => { beforeEach(() => { - cy.login(); interceptChart({ legacy: true }).as('chartData'); }); @@ -148,7 +178,7 @@ describe('Time range filter', () => { metrics: [NUM_METRIC], }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@chartData' }); cy.get('[data-test=time-range-trigger]') @@ -160,7 +190,8 @@ describe('Time range filter', () => { cy.get('input[value="now"]'); }); cy.get('[data-test=cancel-button]').click(); - cy.get('.ant-popover').should('not.be.visible'); + cy.wait(500); + cy.get('.ant-popover').should('not.exist'); }); }); @@ -172,7 +203,7 @@ describe('Time range filter', () => { time_range: 'Last year', }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@chartData' }); cy.get('[data-test=time-range-trigger]') @@ -192,7 +223,7 @@ describe('Time range filter', () => { time_range: 'previous calendar month', }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@chartData' }); cy.get('[data-test=time-range-trigger]') @@ -212,7 +243,7 @@ describe('Time range filter', () => { time_range: 'DATEADD(DATETIME("today"), -7, day) : today', }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@chartData' }); cy.get('[data-test=time-range-trigger]') @@ -235,7 +266,7 @@ describe('Time range filter', () => { time_range: 'No filter', }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@chartData' }); cy.get('[data-test=time-range-trigger]') @@ -249,7 +280,6 @@ describe('Time range filter', () => { describe('Groupby control', () => { it('Set groupby', () => { - cy.login(); interceptChart({ legacy: true }).as('chartData'); cy.visitChartByName('Num Births Trend'); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/explore.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/explore.applitools.test.ts index 96b0d6684768a..4e951c2560e15 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/explore.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/explore.applitools.test.ts @@ -20,7 +20,6 @@ import { FORM_DATA_DEFAULTS, NUM_METRIC } from './visualizations/shared.helper'; describe('explore view', () => { beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); @@ -31,7 +30,7 @@ describe('explore view', () => { it('should load Explore', () => { const LINE_CHART_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'line' }; const formData = { ...LINE_CHART_DEFAULTS, metrics: [NUM_METRIC] }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); cy.eyesOpen({ testName: 'Explore page', diff --git a/superset-frontend/cypress-base/cypress/integration/explore/filter_box.test.js b/superset-frontend/cypress-base/cypress/integration/explore/filter_box.test.js index 921377c45fa4b..a4ca5ddcf2ef9 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/filter_box.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/filter_box.test.js @@ -22,12 +22,11 @@ describe('Edit FilterBox Chart', () => { const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'filter_box' }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson' }); } beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts index 9f07e9c10b859..1e13c7d7ed3fb 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts @@ -30,7 +30,6 @@ const apiURL = (endpoint: string, queryObject: Record<string, unknown>) => describe('Test explore links', () => { beforeEach(() => { - cy.login(); interceptChart({ legacy: true }).as('chartData'); }); @@ -74,7 +73,7 @@ describe('Test explore links', () => { }; const newChartName = `Test chart [${shortid.generate()}]`; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@tableChartData' }); cy.url().then(() => { cy.get('[data-test="query-save-button"]').click(); @@ -101,8 +100,8 @@ describe('Test explore links', () => { cy.request(apiURL('/api/v1/chart/', query)).then(response => { expect(response.body.count).equals(1); - cy.request('DELETE', `/api/v1/chart/${response.body.ids[0]}`); }); + cy.deleteChartByName(newChartName, true); }); }); @@ -183,5 +182,6 @@ describe('Test explore links', () => { cy.request(apiURL('/api/v1/dashboard/', query)).then(response => { expect(response.body.count).equals(1); }); + cy.deleteDashboardByName(dashboardTitle, true); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/utils.ts b/superset-frontend/cypress-base/cypress/integration/explore/utils.ts new file mode 100644 index 0000000000000..15e7dcba1b6f5 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/explore/utils.ts @@ -0,0 +1,91 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + interceptGet as interceptDashboardGet, + interceptDashboardasync, +} from '../dashboard/utils'; + +export function interceptFiltering() { + cy.intercept('GET', `/api/v1/chart/?q=*`).as('filtering'); +} + +export function interceptBulkDelete() { + cy.intercept('DELETE', `/api/v1/chart/?q=*`).as('bulkDelete'); +} + +export function interceptDelete() { + cy.intercept('DELETE', `/api/v1/chart/*`).as('delete'); +} + +export function interceptUpdate() { + cy.intercept('PUT', `/api/v1/chart/*`).as('update'); +} + +export function interceptPost() { + cy.intercept('POST', `/api/v1/chart/`).as('post'); +} + +export function interceptExploreJson() { + cy.intercept('POST', `/superset/explore_json/**`).as('getJson'); +} + +export function interceptExploreGet() { + cy.intercept('GET', `/api/v1/explore/?slice_id=**`).as('getExplore'); +} + +export function setFilter(filter: string, option: string) { + interceptFiltering(); + + cy.get(`[aria-label="${filter}"]`).first().click(); + cy.get(`[aria-label="${filter}"] [title="${option}"]`).click(); + + cy.wait('@filtering'); +} + +export function saveChartToDashboard(dashboardName: string) { + interceptDashboardGet(); + interceptDashboardasync(); + interceptUpdate(); + interceptExploreGet(); + + cy.getBySel('query-save-button').click(); + cy.wait('@getDashboardasync'); + cy.getBySelLike('chart-modal').should('be.visible'); + cy.get( + '[data-test="save-chart-modal-select-dashboard-form"] [aria-label="Select a dashboard"]', + ) + .first() + .click(); + cy.get( + '.ant-select-selection-search-input[aria-label="Select a dashboard"]', + ).type(dashboardName.slice(0, 3)); + cy.get(`.ant-select-item-option[title="${dashboardName}"]`).click(); + cy.getBySel('btn-modal-save').click(); + + cy.wait('@update'); + cy.wait('@get'); + cy.wait('@getExplore'); + cy.contains(`was added to dashboard [${dashboardName}]`); +} + +export function visitSampleChartFromList(chartName: string) { + cy.getBySel('table-row').contains(chartName).click(); + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); +} diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js index 86b5a789c2474..c95127dd1ebd5 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js @@ -17,6 +17,10 @@ * under the License. */ describe('Visualization > Area', () => { + beforeEach(() => { + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + }); + const AREA_FORM_DATA = { datasource: '2__table', viz_type: 'area', @@ -51,15 +55,10 @@ describe('Visualization > Area', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); - }); - it('should work without groupby', () => { verify(AREA_FORM_DATA); cy.get('.nv-area').should('have.length', 1); @@ -75,23 +74,21 @@ describe('Visualization > Area', () => { }); it('should work with groupby and filter', () => { - cy.visitChartByParams( - JSON.stringify({ - ...AREA_FORM_DATA, - groupby: ['region'], - adhoc_filters: [ - { - expressionType: 'SIMPLE', - subject: 'region', - operator: 'IN', - comparator: ['South Asia', 'North America'], - clause: 'WHERE', - sqlExpression: null, - filterOptionName: 'filter_txje2ikiv6_wxmn0qwd1xo', - }, - ], - }), - ); + cy.visitChartByParams({ + ...AREA_FORM_DATA, + groupby: ['region'], + adhoc_filters: [ + { + expressionType: 'SIMPLE', + subject: 'region', + operator: 'IN', + comparator: ['South Asia', 'North America'], + clause: 'WHERE', + sqlExpression: null, + filterOptionName: 'filter_txje2ikiv6_wxmn0qwd1xo', + }, + ], + }); cy.wait('@getJson').then(async ({ response }) => { const responseBody = response?.body; @@ -105,4 +102,20 @@ describe('Visualization > Area', () => { }); cy.get('.nv-area').should('have.length', 2); }); + + it('should allow type to search color schemes and apply the scheme', () => { + verify(AREA_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('supersetColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]', + ).should('exist'); + cy.get('.area .nv-legend .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(31, 168, 201)'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js index 30e7716b730c2..2882f6ab4af28 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js @@ -19,17 +19,21 @@ import { interceptChart } from 'cypress/utils'; describe('Visualization > Big Number with Trendline', () => { + beforeEach(() => { + interceptChart({ legacy: false }).as('chartData'); + }); + const BIG_NUMBER_FORM_DATA = { datasource: '2__table', viz_type: 'big_number', slice_id: 42, granularity_sqla: 'year', time_grain_sqla: 'P1D', - time_range: '2000+:+2014-01-02', + time_range: '2000 : 2014-01-02', metric: 'sum__SP_POP_TOTL', adhoc_filters: [], compare_lag: '10', - compare_suffix: 'over+10Y', + compare_suffix: 'over 10Y', y_axis_format: '.3s', show_trend_line: true, start_y_axis_at_zero: true, @@ -42,18 +46,13 @@ describe('Visualization > Big Number with Trendline', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: '.superset-legacy-chart-big-number', }); } - beforeEach(() => { - cy.login(); - interceptChart({ legacy: false }).as('chartData'); - }); - it('should work', () => { verify(BIG_NUMBER_FORM_DATA); cy.get('.chart-container .header-line'); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js index e2fcc5a1a1e32..d53436acd0317 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js @@ -20,16 +20,15 @@ import { interceptChart } from 'cypress/utils'; import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper'; describe('Visualization > Big Number Total', () => { + beforeEach(() => { + interceptChart({ legacy: false }).as('chartData'); + }); + const BIG_NUMBER_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'big_number_total', }; - beforeEach(() => { - cy.login(); - interceptChart({ legacy: false }).as('chartData'); - }); - it('Test big number chart with adhoc metric', () => { const formData = { ...BIG_NUMBER_DEFAULTS, metric: NUM_METRIC }; diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js index 432815b8692c1..323dc5c24e410 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js @@ -17,6 +17,10 @@ * under the License. */ describe('Visualization > Box Plot', () => { + beforeEach(() => { + cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); + }); + const BOX_PLOT_FORM_DATA = { datasource: '2__table', viz_type: 'box_plot', @@ -33,17 +37,25 @@ describe('Visualization > Box Plot', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); - }); - it('should work', () => { verify(BOX_PLOT_FORM_DATA); cy.get('.chart-container .box_plot canvas').should('have.length', 1); }); + + it('should allow type to search color schemes', () => { + verify(BOX_PLOT_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('supersetColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]', + ).should('exist'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js index 9bd91f37c5eed..f3a0dcd2d4eec 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js @@ -17,13 +17,17 @@ * under the License. */ describe('Visualization > Bubble', () => { + beforeEach(() => { + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + }); + const BUBBLE_FORM_DATA = { datasource: '2__table', viz_type: 'bubble', slice_id: 46, granularity_sqla: 'year', time_grain_sqla: 'P1D', - time_range: '2011-01-01+:+2011-01-02', + time_range: '2011-01-01 : 2011-01-02', series: 'region', entity: 'country_name', x: 'sum__SP_RUR_TOTL_ZS', @@ -47,37 +51,10 @@ describe('Visualization > Bubble', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); - }); - - // Number of circles are pretty unstable when there are a lot of circles - // Since main functionality is already covered in filter test below, - // skip this test until we find a solution. - it.skip('should work', () => { - cy.visitChartByParams(JSON.stringify(BUBBLE_FORM_DATA)).then(() => { - cy.wait('@getJson').then(xhr => { - let expectedBubblesNumber = 0; - xhr.responseBody.data.forEach(element => { - expectedBubblesNumber += element.values.length; - }); - cy.get('[data-test="chart-container"]') - .should('be.visible', { timeout: 15000 }) - .within(() => { - cy.get('svg') - .should('exist') - .find('.nv-point-clips circle') - .should('have.length', expectedBubblesNumber); - }); - }); - }); - }); - it('should work with filter', () => { verify({ ...BUBBLE_FORM_DATA, @@ -86,7 +63,7 @@ describe('Visualization > Bubble', () => { expressionType: 'SIMPLE', subject: 'region', operator: '==', - comparator: 'South+Asia', + comparator: 'South Asia', clause: 'WHERE', sqlExpression: null, filterOptionName: 'filter_b2tfg1rs8y_8kmrcyxvsqd', @@ -107,4 +84,22 @@ describe('Visualization > Bubble', () => { ); }); }); + + it('should allow type to search color schemes and apply the scheme', () => { + cy.visitChartByParams(BUBBLE_FORM_DATA); + + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('supersetColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]', + ).should('exist'); + cy.get('[data-test=run-query-button]').click(); + cy.get('.bubble .nv-legend .nv-legend-symbol').should( + 'have.css', + 'fill', + 'rgb(31, 168, 201)', + ); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js index 83b37f889f77c..136e48d5adec2 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js @@ -17,6 +17,10 @@ * under the License. */ describe('Visualization > Compare', () => { + beforeEach(() => { + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + }); + const COMPARE_FORM_DATA = { datasource: '3__table', viz_type: 'compare', @@ -47,15 +51,10 @@ describe('Visualization > Compare', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); - }); - it('should work without groupby', () => { verify(COMPARE_FORM_DATA); cy.get('.chart-container .nvd3 path.nv-line').should('have.length', 1); @@ -86,4 +85,20 @@ describe('Visualization > Compare', () => { }); cy.get('.chart-container .nvd3 path.nv-line').should('have.length', 1); }); + + it('should allow type to search color schemes and apply the scheme', () => { + verify(COMPARE_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('supersetColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]', + ).should('exist'); + cy.get('.compare .nv-legend .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(31, 168, 201)'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js index bec718367ef92..770e1e1c04d38 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js @@ -19,21 +19,19 @@ import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper'; describe('Visualization > Distribution bar chart', () => { - const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'dist_bar' }; - beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); - it('should work with adhoc metric', () => { - const formData = { - ...VIZ_DEFAULTS, - metrics: NUM_METRIC, - groupby: ['state'], - }; + const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'dist_bar' }; + const DISTBAR_FORM_DATA = { + ...VIZ_DEFAULTS, + metrics: NUM_METRIC, + groupby: ['state'], + }; - cy.visitChartByParams(JSON.stringify(formData)); + it('should work with adhoc metric', () => { + cy.visitChartByParams(DISTBAR_FORM_DATA); cy.verifySliceSuccess({ waitAlias: '@getJson', querySubstring: NUM_METRIC.label, @@ -49,7 +47,7 @@ describe('Visualization > Distribution bar chart', () => { columns: ['gender'], }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); @@ -61,7 +59,7 @@ describe('Visualization > Distribution bar chart', () => { row_limit: 10, }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); @@ -74,7 +72,23 @@ describe('Visualization > Distribution bar chart', () => { contribution: true, }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); + + it('should allow type to search color schemes and apply the scheme', () => { + cy.visitChartByParams(DISTBAR_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('bnbColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]', + ).should('exist'); + cy.get('.dist_bar .nv-legend .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(255, 90, 95)'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/download_chart.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/download_chart.test.js index ce4a871f8e2de..668e9c789f617 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/download_chart.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/download_chart.test.js @@ -22,7 +22,6 @@ describe('Download Chart > Distribution bar chart', () => { const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'dist_bar' }; beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); @@ -33,9 +32,9 @@ describe('Download Chart > Distribution bar chart', () => { groupby: ['state'], }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.get('.header-with-actions .ant-dropdown-trigger').click(); - cy.get(':nth-child(1) > .ant-dropdown-menu-submenu-title').click(); + cy.get(':nth-child(3) > .ant-dropdown-menu-submenu-title').click(); cy.get( '.ant-dropdown-menu-submenu > .ant-dropdown-menu li:nth-child(3)', ).click(); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js index 641b2925d77ec..d31196b9564b7 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js @@ -17,13 +17,17 @@ * under the License. */ describe('Visualization > Dual Line', () => { + beforeEach(() => { + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + }); + const DUAL_LINE_FORM_DATA = { datasource: '3__table', viz_type: 'dual_line', slice_id: 58, granularity_sqla: 'ds', time_grain_sqla: 'P1D', - time_range: '100+years+ago+:+now', + time_range: '100 years ago : now', color_scheme: 'bnbColors', x_axis_format: 'smart_date', metric: 'sum__num', @@ -35,15 +39,10 @@ describe('Visualization > Dual Line', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); - }); - it('should work', () => { verify(DUAL_LINE_FORM_DATA); cy.get('.chart-container svg path.nv-line').should('have.length', 2); @@ -66,4 +65,20 @@ describe('Visualization > Dual Line', () => { }); cy.get('.chart-container svg path.nv-line').should('have.length', 2); }); + + it('should allow type to search color schemes and apply the scheme', () => { + verify(DUAL_LINE_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('supersetColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]', + ).should('exist'); + cy.get('.dual_line .nv-legend .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(31, 168, 201)'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js index 8b5b2ffd0b72c..e704705c6a572 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js @@ -16,26 +16,26 @@ * specific language governing permissions and limitations * under the License. */ + describe('Visualization > Gauge', () => { + beforeEach(() => { + cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); + }); + const GAUGE_FORM_DATA = { - datasource: '2__table', + datasource: '3__table', viz_type: 'gauge_chart', metric: 'count', adhoc_filters: [], - slice_id: 49, + slice_id: 54, row_limit: 10, }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); - }); - it('should work', () => { verify(GAUGE_FORM_DATA); cy.get('.chart-container .gauge_chart canvas').should('have.length', 1); @@ -60,4 +60,17 @@ describe('Visualization > Gauge', () => { }); cy.get('.chart-container .gauge_chart canvas').should('have.length', 1); }); + + it('should allow type to search color schemes', () => { + verify(GAUGE_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('bnbColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]', + ).should('exist'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts index 47adb075bdd91..ff8eaa629ff48 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts @@ -27,6 +27,10 @@ type adhocFilter = { }; describe('Visualization > Graph', () => { + beforeEach(() => { + cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); + }); + const GRAPH_FORM_DATA = { datasource: '1__table', viz_type: 'graph_chart', @@ -46,15 +50,10 @@ describe('Visualization > Graph', () => { function verify(formData: { [name: string]: string | boolean | number | Array<adhocFilter>; }): void { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); - }); - it('should work with ad-hoc metric', () => { verify(GRAPH_FORM_DATA); cy.get('.chart-container .graph_chart canvas').should('have.length', 1); @@ -77,4 +76,17 @@ describe('Visualization > Graph', () => { }); cy.get('.chart-container .graph_chart canvas').should('have.length', 1); }); + + it('should allow type to search color schemes', () => { + verify(GRAPH_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('bnbColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]', + ).should('exist'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts index 67cbba3f9699d..ba197cf4cd543 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts @@ -19,6 +19,10 @@ import { QueryFormData } from '@superset-ui/core'; describe('Visualization > Histogram', () => { + beforeEach(() => { + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + }); + const HISTOGRAM_FORM_DATA: QueryFormData = { datasource: '3__table', viz_type: 'histogram', @@ -39,15 +43,10 @@ describe('Visualization > Histogram', () => { }; function verify(formData: QueryFormData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); - }); - it('should work without groupby', () => { verify(HISTOGRAM_FORM_DATA); cy.get('.chart-container svg .vx-bar').should( @@ -84,4 +83,21 @@ describe('Visualization > Histogram', () => { }); cy.get('.chart-container svg .vx-bar').should('have.length', numBins); }); + + it('should allow type to search color schemes and apply the scheme', () => { + verify(HISTOGRAM_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('supersetColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]', + ).should('exist'); + cy.get('.histogram .vx-legend .vx-legend-shape div') + .first() + .should('have.css', 'background') + .and('contains', 'rgb(31, 168, 201)'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts index e8998b4bef86e..5cc398c7f3ef7 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts @@ -19,16 +19,15 @@ import { FORM_DATA_DEFAULTS, NUM_METRIC, SIMPLE_FILTER } from './shared.helper'; describe('Visualization > Line', () => { - const LINE_CHART_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'line' }; - beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); + const LINE_CHART_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'line' }; + it('should show validator error when no metric', () => { const formData = { ...LINE_CHART_DEFAULTS, metrics: [] }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.get('.panel-body').contains( `Add required control values to preview chart`, ); @@ -36,11 +35,14 @@ describe('Visualization > Line', () => { it('should not show validator error when metric added', () => { const formData = { ...LINE_CHART_DEFAULTS, metrics: [] }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.get('.panel-body').contains( `Add required control values to preview chart`, ); - cy.get('.text-danger').contains('Metrics'); + cy.get('[data-test="metrics-header"]').contains('Metrics'); + cy.get('[data-test="metrics-header"] [data-test="error-tooltip"]').should( + 'exist', + ); cy.get('[data-test=metrics]') .contains('Drop columns/metrics here or click') @@ -55,33 +57,40 @@ describe('Visualization > Line', () => { .type('sum{enter}'); cy.get('[data-test="AdhocMetricEdit#save"]').contains('Save').click(); - cy.get('.text-danger').should('not.exist'); + cy.get('[data-test="metrics-header"]').contains('Metrics'); + cy.get('[data-test="metrics-header"] [data-test="error-tooltip"]').should( + 'not.exist', + ); + cy.get('.ant-alert-warning').should('not.exist'); }); it('should allow negative values in Y bounds', () => { const formData = { ...LINE_CHART_DEFAULTS, metrics: [NUM_METRIC] }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.get('#controlSections-tab-display').click(); cy.get('span').contains('Y Axis Bounds').scrollIntoView(); cy.get('input[placeholder="Min"]').type('-0.1', { delay: 100 }); cy.get('.ant-alert-warning').should('not.exist'); }); - it('should allow type to search color schemes', () => { + it('should allow type to search color schemes and apply the scheme', () => { cy.get('#controlSections-tab-display').click(); cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); cy.get('.Control[data-test="color_scheme"] input[type="search"]') .focus() .type('bnbColors{enter}'); cy.get( - '.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="bnbColors"]', + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]', ).should('exist'); + cy.get('.line .nv-legend .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(255, 90, 95)'); }); it('should work with adhoc metric', () => { const formData = { ...LINE_CHART_DEFAULTS, metrics: [NUM_METRIC] }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); @@ -89,7 +98,7 @@ describe('Visualization > Line', () => { const metrics = ['count']; const groupby = ['gender']; const formData = { ...LINE_CHART_DEFAULTS, metrics, groupby }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); @@ -101,7 +110,7 @@ describe('Visualization > Line', () => { metrics, adhoc_filters: filters, }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); @@ -113,7 +122,7 @@ describe('Visualization > Line', () => { groupby: ['name'], timeseries_limit_metric: NUM_METRIC, }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); @@ -126,7 +135,7 @@ describe('Visualization > Line', () => { timeseries_limit_metric: NUM_METRIC, order_desc: true, }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); @@ -138,7 +147,7 @@ describe('Visualization > Line', () => { rolling_type: 'mean', rolling_periods: 10, }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); @@ -147,12 +156,12 @@ describe('Visualization > Line', () => { const formData = { ...LINE_CHART_DEFAULTS, metrics, - time_compare: ['1+year'], + time_compare: ['1 year'], comparison_type: 'values', groupby: ['gender'], }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); // Offset color should match original line color @@ -190,10 +199,10 @@ describe('Visualization > Line', () => { const formData = { ...LINE_CHART_DEFAULTS, metrics, - time_compare: ['1+year'], + time_compare: ['1 year'], comparison_type: 'ratio', }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); @@ -202,10 +211,10 @@ describe('Visualization > Line', () => { const formData = { ...LINE_CHART_DEFAULTS, metrics, - time_compare: ['1+year'], + time_compare: ['1 year'], comparison_type: 'percentage', }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); }); @@ -214,7 +223,7 @@ describe('Visualization > Line', () => { ...LINE_CHART_DEFAULTS, metrics: ['count'], }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); cy.get('text.nv-legend-text').contains('COUNT(*)'); }); @@ -225,7 +234,7 @@ describe('Visualization > Line', () => { metrics: ['count'], annotation_layers: [ { - name: 'Goal+line', + name: 'Goal line', annotationType: 'FORMULA', sourceType: '', value: 'y=140000', @@ -245,7 +254,7 @@ describe('Visualization > Line', () => { }, ], }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); cy.get('.slice_container').within(() => { // Goal line annotation doesn't show up in legend @@ -281,7 +290,7 @@ describe('Visualization > Line', () => { }, ], }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); }, ); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js index fb083de615e9a..f853cf12848a8 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js @@ -17,6 +17,10 @@ * under the License. */ describe('Visualization > Pie', () => { + beforeEach(() => { + cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); + }); + const PIE_FORM_DATA = { datasource: '3__table', viz_type: 'pie', @@ -37,15 +41,10 @@ describe('Visualization > Pie', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); - }); - it('should work with ad-hoc metric', () => { verify(PIE_FORM_DATA); cy.get('.chart-container .pie canvas').should('have.length', 1); @@ -68,4 +67,17 @@ describe('Visualization > Pie', () => { }); cy.get('.chart-container .pie canvas').should('have.length', 1); }); + + it('should allow type to search color schemes', () => { + verify(PIE_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('supersetColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]', + ).should('exist'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pivot_table.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pivot_table.test.js index 14de08da79360..dfef462fc9e61 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pivot_table.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pivot_table.test.js @@ -17,13 +17,17 @@ * under the License. */ describe('Visualization > Pivot Table', () => { + beforeEach(() => { + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + }); + const PIVOT_TABLE_FORM_DATA = { datasource: '3__table', viz_type: 'pivot_table', slice_id: 61, granularity_sqla: 'ds', time_grain_sqla: 'P1D', - time_range: '100+years+ago+:+now', + time_range: '100 years ago : now', metrics: ['sum__num'], adhoc_filters: [], groupby: ['name'], @@ -54,15 +58,10 @@ describe('Visualization > Pivot Table', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'table' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); - }); - it('should work with single groupby', () => { verify(PIVOT_TABLE_FORM_DATA); cy.get('.chart-container tr:eq(0) th:eq(1)').contains('sum__num'); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js index 257ec00c1f05d..e5139bee1c01b 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js @@ -17,6 +17,10 @@ * under the License. */ describe('Visualization > Sankey', () => { + beforeEach(() => { + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + }); + const SANKEY_FORM_DATA = { datasource: '1__table', viz_type: 'sankey', @@ -24,7 +28,7 @@ describe('Visualization > Sankey', () => { url_params: {}, granularity_sqla: null, time_grain_sqla: 'P1D', - time_range: 'Last+week', + time_range: 'Last week', groupby: ['source', 'target'], metric: 'sum__value', adhoc_filters: [], @@ -33,15 +37,10 @@ describe('Visualization > Sankey', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); - }); - it('should work', () => { verify(SANKEY_FORM_DATA); cy.get('.chart-container svg g.node rect').should('have.length', 41); @@ -53,7 +52,7 @@ describe('Visualization > Sankey', () => { adhoc_filters: [ { expressionType: 'SQL', - sqlExpression: 'SUM(value)+>+0', + sqlExpression: 'SUM(value) > 0', clause: 'HAVING', subject: null, operator: null, @@ -73,4 +72,17 @@ describe('Visualization > Sankey', () => { }); cy.get('.chart-container svg g.node rect').should('have.length', 6); }); + + it('should allow type to search color schemes', () => { + verify(SANKEY_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('bnbColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]', + ).should('exist'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/shared.helper.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/shared.helper.js index 78a659fc91f31..bfd50e66d3df2 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/shared.helper.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/shared.helper.js @@ -24,7 +24,7 @@ export const FORM_DATA_DEFAULTS = { datasource: '3__table', granularity_sqla: 'ds', time_grain_sqla: null, - time_range: '100+years+ago+:+now', + time_range: '100 years ago : now', adhoc_filters: [], groupby: [], limit: null, @@ -37,7 +37,7 @@ export const HEALTH_POP_FORM_DATA_DEFAULTS = { datasource: '2__table', granularity_sqla: 'ds', time_grain_sqla: 'P1D', - time_range: '1960-01-01+:+2014-01-02', + time_range: '1960-01-01 : 2014-01-02', }; export const NUM_METRIC = { diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js index 99cbb1e407e4c..03090db9c4ed8 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js @@ -17,6 +17,10 @@ * under the License. */ describe('Visualization > Sunburst', () => { + beforeEach(() => { + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + }); + const SUNBURST_FORM_DATA = { datasource: '2__table', viz_type: 'sunburst', @@ -32,15 +36,10 @@ describe('Visualization > Sunburst', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); - }); - it('should work without secondary metric', () => { verify(SUNBURST_FORM_DATA); // There should be 7 visible arcs + 1 hidden @@ -80,4 +79,17 @@ describe('Visualization > Sunburst', () => { }); cy.get('.chart-container svg g#arcs path').should('have.length', 3); }); + + it('should allow type to search color schemes', () => { + verify(SUNBURST_FORM_DATA); + + cy.get('#controlSections-tab-display').click(); + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('supersetColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]', + ).should('exist'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/table.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/table.test.ts index 6361d93d1809a..46030bfb35949 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/table.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/table.test.ts @@ -27,6 +27,10 @@ import { // Table describe('Visualization > Table', () => { + beforeEach(() => { + interceptChart({ legacy: false }).as('chartData'); + }); + const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'table', @@ -43,11 +47,6 @@ describe('Visualization > Table', () => { optionName: 'metric_6qwzgc8bh2v_zox7hil1mzs', }; - beforeEach(() => { - cy.login(); - interceptChart({ legacy: false }).as('chartData'); - }); - it('Use default time column', () => { cy.visitChartByParams({ ...VIZ_DEFAULTS, @@ -174,7 +173,7 @@ describe('Visualization > Table', () => { groupby: ['name'], row_limit: limit, }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.wait('@chartData').then(({ response }) => { cy.verifySliceContainer('table'); expect(response?.body.result[0].data.length).to.eq(limit); @@ -219,7 +218,7 @@ describe('Visualization > Table', () => { order_by_cols: ['["num", false]'], }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.wait('@chartData').then(({ response }) => { cy.verifySliceContainer('table'); const records = response?.body.result[0].data; @@ -233,7 +232,7 @@ describe('Visualization > Table', () => { const formData = { ...VIZ_DEFAULTS, metrics, adhoc_filters: filters }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'table' }); }); @@ -244,7 +243,7 @@ describe('Visualization > Table', () => { groupby: ['state'], }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@chartData', querySubstring: /group by.*state/i, diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/time_table.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/time_table.js index 7da90027856f6..5c8672192a8e5 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/time_table.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/time_table.js @@ -19,13 +19,12 @@ import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper'; describe('Visualization > Time TableViz', () => { - const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'time_table' }; - beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); + const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'time_table' }; + it('Test time series table multiple metrics last year total', () => { const formData = { ...VIZ_DEFAULTS, @@ -33,7 +32,7 @@ describe('Visualization > Time TableViz', () => { column_collection: [ { key: '9g4K-B-YL', - label: 'Last+Year', + label: 'Last Year', colType: 'time', timeLag: '1', comparisonType: 'value', @@ -42,7 +41,7 @@ describe('Visualization > Time TableViz', () => { url: '', }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', querySubstring: NUM_METRIC.label, @@ -61,7 +60,7 @@ describe('Visualization > Time TableViz', () => { column_collection: [ { key: '9g4K-B-YL', - label: 'Last+Year', + label: 'Last Year', colType: 'time', timeLag: '1', comparisonType: 'value', @@ -70,7 +69,7 @@ describe('Visualization > Time TableViz', () => { url: '', }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', querySubstring: NUM_METRIC.label, @@ -107,7 +106,7 @@ describe('Visualization > Time TableViz', () => { url: '', }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', querySubstring: NUM_METRIC.label, diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js index 6ebe06274fbd5..158aa7b39b15e 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js @@ -17,6 +17,10 @@ * under the License. */ describe('Visualization > Treemap', () => { + beforeEach(() => { + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + }); + const TREEMAP_FORM_DATA = { datasource: '2__table', viz_type: 'treemap', @@ -38,15 +42,10 @@ describe('Visualization > Treemap', () => { const level2 = '.chart-container rect[style="fill: rgb(0, 122, 135);"]'; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); - }); - it('should work', () => { verify(TREEMAP_FORM_DATA); cy.get(level0).should('have.length', 1); @@ -80,4 +79,18 @@ describe('Visualization > Treemap', () => { }); cy.get(level1).should('have.length', 8); }); + + it('should allow type to search color schemes and apply the scheme', () => { + verify(TREEMAP_FORM_DATA); + + cy.get('.Control[data-test="color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="color_scheme"] input[type="search"]') + .focus() + .type('supersetColors{enter}'); + cy.get( + '.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]', + ).should('exist'); + cy.get('[data-test=run-query-button]').click(); + cy.get('#rect-IND').should('have.css', 'fill', 'rgb(69, 78, 124)'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js index ed9d3e4214987..f92fbf58efcc0 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js @@ -17,6 +17,10 @@ * under the License. */ describe('Visualization > World Map', () => { + beforeEach(() => { + cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + }); + const WORLD_MAP_FORM_DATA = { datasource: '2__table', viz_type: 'world_map', @@ -35,15 +39,10 @@ describe('Visualization > World Map', () => { }; function verify(formData) { - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); } - beforeEach(() => { - cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); - }); - it('should work with ad-hoc metric', () => { verify(WORLD_MAP_FORM_DATA); cy.get('.bubbles circle.datamaps-bubble').should('have.length', 206); @@ -80,4 +79,16 @@ describe('Visualization > World Map', () => { ).to.equal(0); }); }); + + it('should allow type to search color schemes', () => { + verify(WORLD_MAP_FORM_DATA); + + cy.get('.Control[data-test="linear_color_scheme"]').scrollIntoView(); + cy.get('.Control[data-test="linear_color_scheme"] input[type="search"]') + .focus() + .type('greens{enter}'); + cy.get( + '.Control[data-test="linear_color_scheme"] .ant-select-selection-item [data-test="greens"]', + ).should('exist'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/sqllab/sourcePanel.index.test.js b/superset-frontend/cypress-base/cypress/integration/sqllab/_skip.sourcePanel.index.test.js similarity index 94% rename from superset-frontend/cypress-base/cypress/integration/sqllab/sourcePanel.index.test.js rename to superset-frontend/cypress-base/cypress/integration/sqllab/_skip.sourcePanel.index.test.js index ec0db332afd94..be455a4a99b7f 100644 --- a/superset-frontend/cypress-base/cypress/integration/sqllab/sourcePanel.index.test.js +++ b/superset-frontend/cypress-base/cypress/integration/sqllab/_skip.sourcePanel.index.test.js @@ -18,15 +18,14 @@ */ import { selectResultsTab } from './sqllab.helper'; -describe('SqlLab datasource panel', () => { +describe.skip('SqlLab datasource panel', () => { beforeEach(() => { - cy.login(); cy.visit('/superset/sqllab'); }); // TODO the test bellow is flaky, and has been disabled for the time being // (notice the `it.skip`) - it.skip('creates a table preview when a database, schema, and table are selected', () => { + it('creates a table preview when a database, schema, and table are selected', () => { cy.intercept('/superset/table/**').as('tableMetadata'); // it should have dropdowns to select database, schema, and table diff --git a/superset-frontend/cypress-base/cypress/integration/sqllab/query.test.ts b/superset-frontend/cypress-base/cypress/integration/sqllab/query.test.ts index 33b7caf55144a..0d36692b2ad0c 100644 --- a/superset-frontend/cypress-base/cypress/integration/sqllab/query.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/sqllab/query.test.ts @@ -25,7 +25,6 @@ function parseClockStr(node: JQuery) { describe('SqlLab query panel', () => { beforeEach(() => { - cy.login(); cy.visit('/superset/sqllab'); }); @@ -34,19 +33,9 @@ describe('SqlLab query panel', () => { // are fetched below (because React _Virtualized_ does not render all rows) let clockTime = 0; - const sampleResponse = { - status: 'success', - data: [{ '?column?': 1 }], - columns: [{ name: '?column?', type: 'INT', is_dttm: false }], - selected_columns: [{ name: '?column?', type: 'INT', is_dttm: false }], - expanded_columns: [], - }; - cy.intercept({ method: 'POST', - url: '/superset/sql_json/', - delay: 1000, - response: () => sampleResponse, + url: '/api/v1/sqllab/execute/', }).as('mockSQLResponse'); cy.get('.TableSelector .Select:eq(0)').click(); @@ -92,7 +81,7 @@ describe('SqlLab query panel', () => { }); it.skip('successfully saves a query', () => { - cy.intercept('superset/tables/**').as('getTables'); + cy.intercept('api/v1/database/**/tables/**').as('getTables'); cy.intercept('savedqueryviewapi/**').as('getSavedQuery'); const query = @@ -157,4 +146,52 @@ describe('SqlLab query panel', () => { assertSQLLabResultsAreEqual(initialResultsTable, savedQueryResultsTable); }); }); + + it('Create a chart from a query', () => { + cy.intercept('/api/v1/sqllab/execute/').as('queryFinished'); + cy.intercept('**/api/v1/explore/**').as('explore'); + cy.intercept('**/api/v1/chart/**').as('chart'); + + // cypress doesn't handle opening a new tab, override window.open to open in the same tab + cy.window().then(win => { + cy.stub(win, 'open', url => { + // eslint-disable-next-line no-param-reassign + win.location.href = url; + }); + }); + + const query = 'SELECT gender, name FROM birth_names'; + + cy.get('.ace_text-input') + .focus() + .clear({ force: true }) + .type(`{selectall}{backspace}${query}`, { force: true }); + cy.get('.sql-toolbar button').contains('Run').click(); + cy.wait('@queryFinished'); + + cy.get( + '.SouthPane .ant-tabs-content > .ant-tabs-tabpane-active > div button:first', + { timeout: 10000 }, + ).click(); + + cy.wait('@explore'); + cy.get('[data-test="datasource-control"] .title-select').contains(query); + cy.get('.column-option-label').first().contains('gender'); + cy.get('.column-option-label').last().contains('name'); + + cy.get( + '[data-test="all_columns"] [data-test="dnd-labels-container"] > div:first-child', + ).contains('gender'); + cy.get( + '[data-test="all_columns"] [data-test="dnd-labels-container"] > div:nth-child(2)', + ).contains('name'); + + cy.wait('@chart'); + cy.get('[data-test="slice-container"] table > thead th') + .first() + .contains('gender'); + cy.get('[data-test="slice-container"] table > thead th') + .last() + .contains('name'); + }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/sqllab/sqllab.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/sqllab/sqllab.applitools.test.ts index 31b4472516f31..fdbaefb158f1d 100644 --- a/superset-frontend/cypress-base/cypress/integration/sqllab/sqllab.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/sqllab/sqllab.applitools.test.ts @@ -19,7 +19,6 @@ describe('SqlLab view', () => { beforeEach(() => { - cy.login(); cy.visit('/superset/sqllab'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/sqllab/tabs.test.ts b/superset-frontend/cypress-base/cypress/integration/sqllab/tabs.test.ts index 0e85664cb785a..b2c7a180ad836 100644 --- a/superset-frontend/cypress-base/cypress/integration/sqllab/tabs.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/sqllab/tabs.test.ts @@ -18,30 +18,32 @@ */ describe('SqlLab query tabs', () => { beforeEach(() => { - cy.login(); cy.visit('/superset/sqllab'); }); + const tablistSelector = '[data-test="sql-editor-tabs"] > [role="tablist"]'; + const tabSelector = `${tablistSelector} [role="tab"]`; + it('allows you to create and close a tab', () => { - const tablistSelector = '[data-test="sql-editor-tabs"] > [role="tablist"]'; - const tabSelector = `${tablistSelector} [role="tab"]`; cy.get(tabSelector).then(tabs => { const initialTabCount = tabs.length; const initialUntitledCount = Math.max( 0, ...tabs - .map((i, tabItem) => - Number(tabItem.textContent?.match(/Untitled Query (\d+)/)?.[1]), + .map( + (i, tabItem) => + Number(tabItem.textContent?.match(/Untitled Query (\d+)/)?.[1]) || + 0, ) .toArray(), ); // add two new tabs - cy.get('[data-test="add-tab-icon"]:visible:last').click(); + cy.get('[data-test="add-tab-icon"]:visible:last').click({ force: true }); cy.contains('[role="tab"]', `Untitled Query ${initialUntitledCount + 1}`); cy.get(tabSelector).should('have.length', initialTabCount + 1); - cy.get('[data-test="add-tab-icon"]:visible:last').click(); + cy.get('[data-test="add-tab-icon"]:visible:last').click({ force: true }); cy.contains('[role="tab"]', `Untitled Query ${initialUntitledCount + 2}`); cy.get(tabSelector).should('have.length', initialTabCount + 2); @@ -57,4 +59,55 @@ describe('SqlLab query tabs', () => { cy.get(tabSelector).should('have.length', initialTabCount); }); }); + + it('opens a new tab by a button and a shortcut', () => { + const editorContent = '#ace-editor .ace_content'; + const editorInput = '#ace-editor textarea'; + const queryLimitSelector = '#js-sql-toolbar .limitDropdown'; + cy.get(tabSelector).then(tabs => { + const initialTabCount = tabs.length; + const initialUntitledCount = Math.max( + 0, + ...tabs + .map( + (i, tabItem) => + Number(tabItem.textContent?.match(/Untitled Query (\d+)/)?.[1]) || + 0, + ) + .toArray(), + ); + + // configure some editor settings + cy.get(editorInput).type('some random query string', { force: true }); + cy.get(queryLimitSelector).parent().click({ force: true }); + cy.get('.ant-dropdown-menu') + .last() + .find('.ant-dropdown-menu-item') + .first() + .click({ force: true }); + + // open a new tab by a button + cy.get('[data-test="add-tab-icon"]:visible:last').click({ force: true }); + cy.contains('[role="tab"]', `Untitled Query ${initialUntitledCount + 1}`); + cy.get(tabSelector).should('have.length', initialTabCount + 1); + cy.get(editorContent).contains('SELECT ...'); + cy.get(queryLimitSelector).contains('10'); + + // close the tab + cy.get(`${tabSelector}:last [data-test="dropdown-trigger"]`).click({ + force: true, + }); + cy.get(`${tablistSelector} [aria-label="remove"]:last`).click({ + force: true, + }); + cy.get(tabSelector).should('have.length', initialTabCount); + + // open a new tab by a shortcut + cy.get('body').type('{ctrl}t'); + cy.get(tabSelector).should('have.length', initialTabCount + 1); + cy.contains('[role="tab"]', `Untitled Query ${initialUntitledCount + 1}`); + cy.get(editorContent).contains('SELECT ...'); + cy.get(queryLimitSelector).contains('10'); + }); + }); }); diff --git a/superset-frontend/cypress-base/cypress/support/directories.ts b/superset-frontend/cypress-base/cypress/support/directories.ts index fde9ee0cdeacf..b0eb024d2f483 100644 --- a/superset-frontend/cypress-base/cypress/support/directories.ts +++ b/superset-frontend/cypress-base/cypress/support/directories.ts @@ -84,11 +84,11 @@ export const databasesPage = { step: '.helper-top', selectDbStepTitle: '.select-db > h4', preferredBlockBigQuery: '.preferred > :nth-child(1)', - prefferedBlockPostgreSQL: '.preferred > :nth-child(2)', - prefferedBlockSnowflake: '.preferred > :nth-child(3)', - prefferedBlockMySQL: '.preferred > :nth-child(4)', - prefferedBlockAthena: '.preferred > :nth-child(5)', - prefferedBlockSheets: '.preferred > :nth-child(6)', + preferredBlockPostgreSQL: '.preferred > :nth-child(2)', + preferredBlockSnowflake: '.preferred > :nth-child(3)', + preferredBlockMySQL: '.preferred > :nth-child(4)', + preferredBlockAthena: '.preferred > :nth-child(5)', + preferredBlockSheets: '.preferred > :nth-child(6)', supportedDatabasesText: '.control-label', orChoose: '.available-label', dbDropdown: '[class="ant-select-selection-search-input"]', @@ -127,10 +127,11 @@ export const databasesPage = { export const sqlLabView = { sqlEditorLeftBar: { - sqlEditorLeftBar: '[class="SqlEditorLeftBar"]', - databaseSchemaTableSection: '[class="SqlEditorLeftBar"] > :nth-child(1)', + sqlEditorLeftBar: '[data-test="sql-editor-left-bar"]', + databaseSchemaTableSection: + '[data-test="sql-editor-left-bar"] > :nth-child(1)', tableSchemaSection: - '[class="SqlEditorLeftBar"] > :nth-child(1) > :nth-child(3) > :nth-child(1)', + '[data-test="sql-editor-left-bar"] > :nth-child(1) > :nth-child(3) > :nth-child(1)', tableSchemaInputEmpty: '[aria-label="Select table or type table name"]', }, databaseInput: '[data-test=DatabaseSelector] > :nth-child(1)', @@ -589,7 +590,7 @@ export const exploreView = { okButton: '.ant-modal-confirm-btns .ant-btn-primary', }, }, - vizualizationTypeModal: { + visualizationTypeModal: { vizTypeButton: dataTestLocator('viztype-selector-container'), }, }; diff --git a/superset-frontend/cypress-base/cypress/support/index.d.ts b/superset-frontend/cypress-base/cypress/support/index.d.ts index eca68a7ced7fe..124d72bddd006 100644 --- a/superset-frontend/cypress-base/cypress/support/index.d.ts +++ b/superset-frontend/cypress-base/cypress/support/index.d.ts @@ -30,6 +30,18 @@ declare namespace Cypress { */ login(): void; + /** + * + * Utils + */ + + getBySel(selector: string): cy; + getBySelLike(selector: string): cy; + cleanCharts(): cy; + cleanDashboards(): cy; + loadChartFixtures(): cy; + loadDashboardFixtures(): cy; + visitChartByParams(params: string | Record<string, unknown>): cy; visitChartByName(name: string): cy; visitChartById(id: number): cy; @@ -52,15 +64,27 @@ declare namespace Cypress { * Get */ getDashboards(): cy; + getDashboard(dashboardId: string | number): Record<string, any>; getCharts(): cy; + /** + * Create + */ + createSampleDashboards(indexes?: number[]): void; + createSampleCharts(indexes?: number[]): void; + /** * Delete */ - deleteDashboard(id: number): cy; - deleteDashboardByName(name: string): cy; - deleteChartByName(name: string): cy; - deleteChart(id: number): cy; + deleteDashboard(id: number, failOnStatusCode: boolean): cy; + deleteDashboardByName(dashboardName: string, failOnStatusCode: boolean): cy; + deleteChartByName(name: string, failOnStatusCode: boolean): cy; + deleteChart(id: number, failOnStatusCode: boolean): cy; + + /** + * Update + */ + updateDashboard(dashboardId: number, body: Record<string, any>): cy; } } diff --git a/superset-frontend/cypress-base/cypress/support/index.ts b/superset-frontend/cypress-base/cypress/support/index.ts index 0affa97e7c9fc..456ca7ebc5c77 100644 --- a/superset-frontend/cypress-base/cypress/support/index.ts +++ b/superset-frontend/cypress-base/cypress/support/index.ts @@ -19,13 +19,103 @@ import '@cypress/code-coverage/support'; import '@applitools/eyes-cypress/commands'; -const BASE_EXPLORE_URL = '/superset/explore/?form_data='; -const TokenName = Cypress.env('TOKEN_NAME'); -<<<<<<< HEAD -======= - require('cy-verify-downloads').addCustomCommand(); ->>>>>>> 16654034849505109b638fd2a784dfb377238a0e + +const BASE_EXPLORE_URL = '/explore/?form_data='; +let DASHBOARD_FIXTURES: Record<string, any>[] = []; +let CHART_FIXTURES: Record<string, any>[] = []; + +Cypress.Commands.add('loadChartFixtures', () => + cy.fixture('charts.json').then(charts => { + CHART_FIXTURES = charts; + }), +); + +Cypress.Commands.add('loadDashboardFixtures', () => + cy.fixture('dashboards.json').then(dashboards => { + DASHBOARD_FIXTURES = dashboards; + }), +); + +before(() => { + cy.login(); + Cypress.Cookies.defaults({ preserve: 'session' }); + cy.loadChartFixtures(); + cy.loadDashboardFixtures(); +}); + +beforeEach(() => { + cy.cleanDashboards(); + cy.cleanCharts(); +}); + +Cypress.Commands.add('cleanDashboards', () => { + cy.getDashboards().then((sampleDashboards?: Record<string, any>[]) => { + const deletableDashboards = []; + for (let i = 0; i < DASHBOARD_FIXTURES.length; i += 1) { + const fixture = DASHBOARD_FIXTURES[i]; + const isInDb = sampleDashboards?.find( + d => d.dashboard_title === fixture.dashboard_title, + ); + if (isInDb) { + deletableDashboards.push(isInDb.id); + } + } + if (deletableDashboards.length) { + cy.request({ + failOnStatusCode: false, + method: 'DELETE', + url: `api/v1/dashboard/?q=!(${deletableDashboards.join(',')})`, + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }).then(resp => resp); + } + }); +}); + +Cypress.Commands.add('cleanCharts', () => { + cy.getCharts().then((sampleCharts?: Record<string, any>[]) => { + const deletableCharts = []; + for (let i = 0; i < CHART_FIXTURES.length; i += 1) { + const fixture = CHART_FIXTURES[i]; + const isInDb = sampleCharts?.find( + c => c.slice_name === fixture.slice_name, + ); + if (isInDb) { + deletableCharts.push(isInDb.id); + } + } + if (deletableCharts.length) { + cy.request({ + failOnStatusCode: false, + method: 'DELETE', + url: `api/v1/chart/?q=!(${deletableCharts.join(',')})`, + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }).then(resp => resp); + } + }); +}); + +Cypress.Commands.add('getBySel', (selector, ...args) => + cy.get(`[data-test=${selector}]`, ...args), +); + +Cypress.Commands.add('getBySelLike', (selector, ...args) => + cy.get(`[data-test*=${selector}]`, ...args), +); /* eslint-disable consistent-return */ Cypress.on('uncaught:exception', err => { @@ -35,6 +125,8 @@ Cypress.on('uncaught:exception', err => { // returning false here prevents Cypress from failing the test return false; } + + return false; // TODO:@geido remove }); /* eslint-enable consistent-return */ @@ -58,12 +150,45 @@ Cypress.Commands.add('visitChartById', chartId => cy.visit(`${BASE_EXPLORE_URL}{"slice_id": ${chartId}}`), ); -Cypress.Commands.add('visitChartByParams', params => { - const queryString = - typeof params === 'string' ? params : JSON.stringify(params); - const url = `${BASE_EXPLORE_URL}${queryString}`; - return cy.visit(url); -}); +Cypress.Commands.add( + 'visitChartByParams', + (formData: { + datasource?: string; + datasource_id?: number; + datasource_type?: string; + [key: string]: unknown; + }) => { + let datasource_id; + let datasource_type; + if (formData.datasource_id && formData.datasource_type) { + ({ datasource_id, datasource_type } = formData); + } else { + [datasource_id, datasource_type] = formData.datasource?.split('__') || []; + } + const accessToken = window.localStorage.getItem('access_token'); + cy.request({ + method: 'POST', + url: 'api/v1/explore/form_data', + body: { + datasource_id, + datasource_type, + form_data: JSON.stringify(formData), + }, + headers: { + ...(accessToken && { + Cookie: `csrf_access_token=${accessToken}`, + 'X-CSRFToken': accessToken, + }), + 'Content-Type': 'application/json', + Referer: `${Cypress.config().baseUrl}/`, + }, + }).then(response => { + const formDataKey = response.body.key; + const url = `/explore/?form_data_key=${formDataKey}`; + cy.visit(url); + }); + }, +); Cypress.Commands.add('verifySliceContainer', chartSelector => { // After a wait response check for valid slice container @@ -110,51 +235,126 @@ Cypress.Commands.add( }, ); -Cypress.Commands.add('deleteDashboardByName', (name: string) => - cy.getDashboards().then((dashboards: any) => { - dashboards?.forEach((element: any) => { - if (element.dashboard_title === name) { - const elementId = element.id; - cy.deleteDashboard(elementId); +Cypress.Commands.add('createSampleDashboards', (indexes?: number[]) => + cy.cleanDashboards().then(() => { + for (let i = 0; i < DASHBOARD_FIXTURES.length; i += 1) { + if (indexes?.includes(i) || !indexes) { + cy.request({ + method: 'POST', + url: `/api/v1/dashboard/`, + body: DASHBOARD_FIXTURES[i], + failOnStatusCode: false, + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }); } - }); + } }), ); -Cypress.Commands.add('deleteDashboard', (id: number) => - cy - .request({ - method: 'DELETE', - url: `api/v1/dashboard/${id}`, - headers: { - Cookie: `csrf_access_token=${window.localStorage.getItem( - 'access_token', - )}`, - 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, - 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, - Referer: `${Cypress.config().baseUrl}/`, - }, - }) - .then(resp => resp), +Cypress.Commands.add('createSampleCharts', (indexes?: number[]) => + cy.cleanCharts().then(() => { + for (let i = 0; i < CHART_FIXTURES.length; i += 1) { + if (indexes?.includes(i) || !indexes) { + cy.request({ + method: 'POST', + url: `/api/v1/chart/`, + body: CHART_FIXTURES[i], + failOnStatusCode: false, + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }); + } + } + }), +); + +Cypress.Commands.add( + 'deleteDashboardByName', + (dashboardName: string, failOnStatusCode = false) => + cy.getDashboards().then((sampleDashboards?: Record<string, any>[]) => { + const dashboard = sampleDashboards?.find( + d => d.dashboard_title === dashboardName, + ); + if (dashboard) { + cy.deleteDashboard(dashboard.id, failOnStatusCode); + } + }), ); -Cypress.Commands.add('getDashboards', () => +Cypress.Commands.add( + 'deleteDashboard', + (id: number, failOnStatusCode = false) => + cy + .request({ + failOnStatusCode, + method: 'DELETE', + url: `api/v1/dashboard/${id}`, + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }) + .then(resp => resp), +); + +Cypress.Commands.add('getDashboards', () => { + cy.request({ + method: 'GET', + url: `api/v1/dashboard/`, + headers: { + 'Content-Type': 'application/json', + }, + }).then(resp => resp.body.result); +}); + +Cypress.Commands.add('getDashboard', (dashboardId: string | number) => cy .request({ method: 'GET', - url: `api/v1/dashboard/`, + url: `api/v1/dashboard/${dashboardId}`, headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, }, }) .then(resp => resp.body.result), ); -Cypress.Commands.add('deleteChart', (id: number) => +Cypress.Commands.add( + 'updateDashboard', + (dashboardId: number, body: Record<string, any>) => + cy + .request({ + method: 'PUT', + url: `api/v1/dashboard/${dashboardId}`, + body, + headers: { + 'Content-Type': 'application/json', + }, + }) + .then(resp => resp.body.result), +); + +Cypress.Commands.add('deleteChart', (id: number, failOnStatusCode = false) => cy .request({ + failOnStatusCode, method: 'DELETE', url: `api/v1/chart/${id}`, headers: { @@ -162,11 +362,9 @@ Cypress.Commands.add('deleteChart', (id: number) => 'access_token', )}`, 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, Referer: `${Cypress.config().baseUrl}/`, }, - failOnStatusCode: false, }) .then(resp => resp), ); @@ -178,19 +376,18 @@ Cypress.Commands.add('getCharts', () => url: `api/v1/chart/`, headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, }, }) .then(resp => resp.body.result), ); -Cypress.Commands.add('deleteChartByName', (name: string) => - cy.getCharts().then((slices: any) => { - slices?.forEach((element: any) => { - if (element.slice_name === name) { - const elementId = element.id; - cy.deleteChart(elementId); +Cypress.Commands.add( + 'deleteChartByName', + (sliceName: string, failOnStatusCode = false) => + cy.getCharts().then((sampleCharts?: Record<string, any>[]) => { + const chart = sampleCharts?.find(c => c.slice_name === sliceName); + if (chart) { + cy.deleteChart(chart.id, failOnStatusCode); } - }); - }), + }), ); diff --git a/superset-frontend/cypress-base/cypress/utils/index.ts b/superset-frontend/cypress-base/cypress/utils/index.ts index ea0bbdcf437b3..2f06efc22c25e 100644 --- a/superset-frontend/cypress-base/cypress/utils/index.ts +++ b/superset-frontend/cypress-base/cypress/utils/index.ts @@ -16,5 +16,111 @@ * specific language governing permissions and limitations * under the License. */ +import { getChartAlias, Slice } from 'cypress/utils/vizPlugins'; + export * from './vizPlugins'; export { default as parsePostForm } from './parsePostForm'; +export interface ChartSpec { + name: string; + viz: string; +} + +export function setGridMode(type: 'card' | 'list') { + cy.get(`[aria-label="${type}-view"]`).click(); +} + +export function toggleBulkSelect() { + cy.getBySel('bulk-select').click(); +} + +export function clearAllInputs() { + cy.get('body').then($body => { + if ($body.find('.ant-select-clear').length) { + cy.get('.ant-select-clear').click({ multiple: true, force: true }); + } + }); +} + +const toSlicelike = ($chart: JQuery<HTMLElement>): Slice => ({ + slice_id: parseInt($chart.attr('data-test-chart-id')!, 10), + form_data: { + viz_type: $chart.attr('data-test-viz-type')!, + }, +}); + +export function getChartAliasBySpec(chart: ChartSpec) { + return getChartGridComponent(chart).then($chart => + cy.wrap(getChartAlias(toSlicelike($chart))), + ); +} + +export function getChartAliasesBySpec(charts: readonly ChartSpec[]) { + const aliases: string[] = []; + charts.forEach(chart => + getChartAliasBySpec(chart).then(alias => { + aliases.push(alias); + }), + ); + // Wrapping the aliases is key. + // That way callers can chain off this function + // and actually get the list of aliases. + return cy.wrap(aliases); +} + +export function getChartGridComponent({ name, viz }: ChartSpec) { + return cy + .get(`[data-test-chart-name="${name}"]`) + .should('have.attr', 'data-test-viz-type', viz); +} + +export function waitForChartLoad(chart: ChartSpec) { + return getChartGridComponent(chart).then(gridComponent => { + const chartId = gridComponent.attr('data-test-chart-id'); + // the chart should load in under half a minute + return ( + cy + // this id only becomes visible when the chart is loaded + .get(`#chart-id-${chartId}`, { + timeout: 30000, + }) + .should('be.visible') + // return the chart grid component + .then(() => gridComponent) + ); + }); +} + +/** + * Drag an element and drop it to another element. + * Usage: + * drag(source).to(target); + */ +export function drag(selector: string, content: string | number | RegExp) { + const dataTransfer = { data: {} }; + return { + to(target: string | Cypress.Chainable) { + cy.get('.dragdroppable') + .contains(selector, content) + .trigger('mousedown', { which: 1, force: true }) + .trigger('dragstart', { dataTransfer, force: true }) + .trigger('drag', { force: true }); + + (typeof target === 'string' ? cy.get(target) : target) + .trigger('dragover', { dataTransfer, force: true }) + .trigger('drop', { dataTransfer, force: true }) + .trigger('dragend', { dataTransfer, force: true }) + .trigger('mouseup', { which: 1, force: true }); + }, + }; +} + +export function resize(selector: string) { + return { + to(cordX: number, cordY: number) { + cy.get(selector) + .trigger('mousedown', { which: 1, force: true }) + .trigger('mousemove', { which: 1, cordX, cordY, force: true }) + .trigger('mouseup', { which: 1, force: true }); + }, + }; +} diff --git a/superset-frontend/cypress-base/cypress/utils/urls.ts b/superset-frontend/cypress-base/cypress/utils/urls.ts new file mode 100644 index 0000000000000..ee35c3088c0fd --- /dev/null +++ b/superset-frontend/cypress-base/cypress/utils/urls.ts @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const DASHBOARD_LIST = '/dashboard/list/'; +export const CHART_LIST = '/chart/list/'; +export const WORLD_HEALTH_DASHBOARD = '/superset/dashboard/world_health/'; +export const SAMPLE_DASHBOARD_1 = '/superset/dashboard/1-sample-dashboard/'; +export const SUPPORTED_CHARTS_DASHBOARD = + '/superset/dashboard/supported_charts_dash/'; +export const TABBED_DASHBOARD = '/superset/dashboard/tabbed_dash/'; +export const DATABASE_LIST = '/databaseview/list'; +export const DATASET_LIST_PATH = 'tablemodelview/list'; +export const ALERT_LIST = '/alert/list/'; +export const REPORT_LIST = '/report/list/'; diff --git a/superset-frontend/cypress-base/package-lock.json b/superset-frontend/cypress-base/package-lock.json index 1936f68ea7fe7..d312898441d39 100644 --- a/superset-frontend/cypress-base/package-lock.json +++ b/superset-frontend/cypress-base/package-lock.json @@ -12,6 +12,7 @@ "@applitools/eyes-cypress": "^3.25.3", "@cypress/code-coverage": "^3.9.11", "@superset-ui/core": "^0.18.8", + "brace": "^0.11.1", "cy-verify-downloads": "^0.1.6", "querystringify": "^2.2.0", "react-dom": "^16.13.0", @@ -3577,6 +3578,11 @@ "node": ">=0.6" } }, + "node_modules/brace": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/brace/-/brace-0.11.1.tgz", + "integrity": "sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -6203,9 +6209,9 @@ } }, "node_modules/got": { - "version": "11.8.3", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", - "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", "dependencies": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", @@ -6441,9 +6447,9 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, "node_modules/http-errors": { "version": "1.7.2", @@ -7279,12 +7285,9 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "node_modules/json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dependencies": { - "minimist": "^1.2.5" - }, + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -7786,9 +7789,9 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -8535,9 +8538,9 @@ } }, "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "engines": { "node": ">=0.6" } @@ -13216,6 +13219,11 @@ } } }, + "brace": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/brace/-/brace-0.11.1.tgz", + "integrity": "sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -15284,9 +15292,9 @@ } }, "got": { - "version": "11.8.3", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", - "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", "requires": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", @@ -15456,9 +15464,9 @@ } }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, "http-errors": { "version": "1.7.2", @@ -16064,12 +16072,9 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" }, "jsonfile": { "version": "6.1.0", @@ -16454,9 +16459,9 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "requires": { "brace-expansion": "^1.1.7" } @@ -17033,9 +17038,9 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" }, "querystring": { "version": "0.2.0", diff --git a/superset-frontend/cypress-base/package.json b/superset-frontend/cypress-base/package.json index 02c126406cb2c..b28c684544a54 100644 --- a/superset-frontend/cypress-base/package.json +++ b/superset-frontend/cypress-base/package.json @@ -13,6 +13,7 @@ "@applitools/eyes-cypress": "^3.25.3", "@cypress/code-coverage": "^3.9.11", "@superset-ui/core": "^0.18.8", + "brace": "^0.11.1", "cy-verify-downloads": "^0.1.6", "querystringify": "^2.2.0", "react-dom": "^16.13.0", diff --git a/superset-frontend/jest.config.js b/superset-frontend/jest.config.js index 0d66ade8b366b..d537b2993b218 100644 --- a/superset-frontend/jest.config.js +++ b/superset-frontend/jest.config.js @@ -26,7 +26,7 @@ module.exports = { '\\.svg$': '<rootDir>/spec/__mocks__/svgrMock.tsx', '^src/(.*)$': '<rootDir>/src/$1', '^spec/(.*)$': '<rootDir>/spec/$1', - // mapping plugins of superset-ui to souce code + // mapping plugins of superset-ui to source code '@superset-ui/(.*)$': '<rootDir>/node_modules/@superset-ui/$1/src', }, testEnvironment: 'jsdom', diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 55e37e16cf1eb..83c5c8d6ed90a 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "superset", - "version": "2.0.1", + "version": "0.0.0-dev", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "superset", - "version": "2.0.1", + "version": "0.0.0-dev", "license": "Apache-2.0", "workspaces": [ "packages/*", @@ -15,7 +15,7 @@ "dependencies": { "@ag-grid-community/react": "^26.0.0", "@ag-grid-enterprise/all-modules": "^26.0.0", - "@ant-design/icons": "^4.2.2", + "@ant-design/icons": "^4.8.0", "@babel/runtime-corejs3": "^7.12.5", "@data-ui/sparkline": "^0.0.84", "@emotion/babel-preset-css-prop": "^11.2.0", @@ -52,10 +52,10 @@ "@superset-ui/plugin-chart-word-cloud": "file:./plugins/plugin-chart-word-cloud", "@superset-ui/preset-chart-xy": "file:./plugins/preset-chart-xy", "@superset-ui/switchboard": "file:./packages/superset-ui-switchboard", - "@vx/responsive": "^0.0.195", + "@visx/responsive": "^3.0.0", "abortcontroller-polyfill": "^1.1.9", "ace-builds": "^1.4.14", - "antd": "^4.9.4", + "antd": "4.10.3", "array-move": "^2.2.1", "babel-plugin-typescript-to-proptypes": "^2.0.0", "bootstrap": "^3.4.1", @@ -65,6 +65,7 @@ "chrono-node": "^2.2.6", "classnames": "^2.2.5", "core-js": "^3.6.5", + "currencyformatter.js": "^2.2.0", "d3-array": "^1.2.4", "d3-color": "^1.2.0", "d3-scale": "^2.1.2", @@ -78,7 +79,7 @@ "global-box": "^1.2.0", "html-webpack-plugin": "^5.3.2", "immer": "^9.0.6", - "interweave": "^11.2.0", + "interweave": "^13.0.0", "jquery": "^3.5.1", "js-levenshtein": "^1.1.6", "js-yaml-loader": "^1.2.2", @@ -86,11 +87,11 @@ "json-stringify-pretty-compact": "^2.0.0", "lodash": "^4.17.21", "lodash-es": "^4.17.21", - "mapbox-gl": "^2.8.2", + "mapbox-gl": "^2.10.0", "match-sorter": "^6.1.0", "memoize-one": "^5.1.1", "moment": "^2.26.0", - "moment-timezone": "^0.5.33", + "moment-timezone": "^0.5.37", "mousetrap": "^1.6.1", "mustache": "^2.2.1", "polished": "^3.7.2", @@ -98,39 +99,39 @@ "query-string": "^6.13.7", "re-resizable": "^6.6.1", "react": "^16.13.1", - "react-ace": "^9.4.4", - "react-checkbox-tree": "^1.5.1", + "react-ace": "^10.1.0", + "react-checkbox-tree": "^1.8.0", "react-color": "^2.13.8", - "react-datetime": "^3.0.4", + "react-datetime": "^3.2.0", + "react-diff-viewer-continued": "^3.2.5", "react-dnd": "^11.1.3", "react-dnd-html5-backend": "^11.1.3", "react-dom": "^16.13.0", "react-draggable": "^4.4.3", "react-gravatar": "^2.6.1", - "react-hot-loader": "^4.12.20", - "react-icons": "^4.2.0", + "react-hot-loader": "^4.13.1", + "react-intersection-observer": "^9.4.1", "react-js-cron": "^1.2.0", - "react-json-tree": "^0.11.2", - "react-jsonschema-form": "^1.2.0", + "react-json-tree": "^0.17.0", + "react-jsonschema-form": "^1.8.1", "react-lines-ellipsis": "^0.15.0", "react-loadable": "^5.5.0", - "react-redux": "^7.2.0", - "react-resize-detector": "^6.7.6", - "react-reverse-portal": "^2.0.1", - "react-router-dom": "^5.1.2", + "react-query": "^3.39.2", + "react-redux": "^7.2.8", + "react-resize-detector": "^7.1.2", + "react-reverse-portal": "^2.1.1", + "react-router-dom": "^5.3.4", "react-search-input": "^0.11.3", - "react-select": "^3.1.0", - "react-sortable-hoc": "^1.11.0", + "react-select": "^3.2.0", + "react-sortable-hoc": "^2.0.0", "react-split": "^2.0.9", - "react-sticky": "^6.0.3", "react-syntax-highlighter": "^15.4.5", - "react-table": "^7.6.3", + "react-table": "^7.8.0", "react-transition-group": "^2.5.3", - "react-ultimate-pagination": "^1.2.0", + "react-ultimate-pagination": "^1.3.0", "react-virtualized": "9.19.1", - "react-virtualized-auto-sizer": "^1.0.2", - "react-virtualized-select": "^3.1.3", - "react-window": "^1.8.5", + "react-virtualized-auto-sizer": "^1.0.7", + "react-window": "^1.8.8", "redux": "^4.0.5", "redux-localstorage": "^0.4.1", "redux-thunk": "^2.1.0", @@ -142,30 +143,31 @@ "shortid": "^2.2.6", "tinycolor2": "^1.4.2", "urijs": "^1.19.8", - "use-immer": "^0.6.0", + "use-immer": "^0.8.1", "use-query-params": "^1.1.9", "yargs": "^15.4.1" }, "devDependencies": { "@ag-grid-community/react": "^26.0.0", "@ag-grid-enterprise/all-modules": "^26.0.0", - "@applitools/eyes-storybook": "^3.27.6", - "@babel/cli": "^7.16.0", - "@babel/compat-data": "^7.15.0", - "@babel/core": "^7.15.5", - "@babel/eslint-parser": "^7.15.7", - "@babel/node": "^7.15.4", - "@babel/plugin-proposal-class-properties": "^7.14.5", - "@babel/plugin-proposal-optional-chaining": "^7.14.5", + "@applitools/eyes-storybook": "^3.30.1", + "@babel/cli": "^7.18.10", + "@babel/compat-data": "^7.18.8", + "@babel/core": "^7.18.10", + "@babel/eslint-parser": "^7.18.9", + "@babel/node": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.15.0", - "@babel/preset-env": "^7.15.6", - "@babel/preset-react": "^7.14.5", - "@babel/register": "^7.15.3", + "@babel/plugin-transform-runtime": "^7.18.10", + "@babel/preset-env": "^7.18.10", + "@babel/preset-react": "^7.18.6", + "@babel/register": "^7.18.9", "@emotion/jest": "^11.3.0", "@hot-loader/react-dom": "^16.13.0", "@istanbuljs/nyc-config-typescript": "^1.0.1", "@storybook/addon-actions": "^6.4.22", + "@storybook/addon-docs": "^6.5.10", "@storybook/addon-essentials": "^6.4.22", "@storybook/addon-knobs": "^6.3.1", "@storybook/addon-links": "^6.4.22", @@ -187,7 +189,7 @@ "@types/jest": "^26.0.3", "@types/jquery": "^3.5.8", "@types/js-levenshtein": "^1.1.0", - "@types/json-bigint": "^1.0.0", + "@types/json-bigint": "^1.0.1", "@types/react": "^16.9.43", "@types/react-dom": "^16.9.8", "@types/react-gravatar": "^2.6.8", @@ -195,13 +197,12 @@ "@types/react-jsonschema-form": "^1.7.4", "@types/react-loadable": "^5.5.6", "@types/react-redux": "^7.1.10", - "@types/react-router-dom": "^5.1.5", + "@types/react-router-dom": "^5.3.3", "@types/react-select": "^3.0.19", - "@types/react-sticky": "^6.0.3", "@types/react-table": "^7.0.19", "@types/react-ultimate-pagination": "^1.2.0", "@types/react-virtualized": "^9.21.10", - "@types/react-window": "^1.8.2", + "@types/react-window": "^1.8.5", "@types/redux-localstorage": "^1.0.8", "@types/redux-mock-store": "^1.0.2", "@types/rison": "0.0.6", @@ -216,12 +217,13 @@ "babel-plugin-dynamic-import-node": "^2.3.3", "babel-plugin-jsx-remove-data-test-id": "^2.1.3", "babel-plugin-lodash": "^3.3.4", + "chromatic": "^6.7.4", "copy-webpack-plugin": "^9.0.1", "cross-env": "^5.2.0", "css-loader": "^6.2.0", "css-minimizer-webpack-plugin": "^3.0.2", - "enzyme": "^3.10.0", - "enzyme-adapter-react-16": "^1.14.0", + "enzyme": "^3.11.0", + "enzyme-adapter-react-16": "^1.15.7", "eslint": "^7.32.0", "eslint-config-airbnb": "^18.2.1", "eslint-config-prettier": "^7.1.0", @@ -242,14 +244,15 @@ "exports-loader": "^0.7.0", "fetch-mock": "^7.7.3", "fork-ts-checker-webpack-plugin": "^6.3.3", + "history": "^4.10.1", "ignore-styles": "^5.0.1", "imports-loader": "^3.0.0", "jest": "^26.6.3", "jest-environment-enzyme": "^7.1.2", "jest-enzyme": "^7.1.2", "jest-websocket-mock": "^2.2.0", - "jsdom": "^16.4.0", - "lerna": "^4.0.0", + "jsdom": "^20.0.0", + "lerna": "^6.1.0", "less": "^3.12.2", "less-loader": "^10.2.0", "mini-css-extract-plugin": "^2.3.0", @@ -275,7 +278,7 @@ "webpack": "^5.52.1", "webpack-bundle-analyzer": "^4.4.2", "webpack-cli": "^4.8.0", - "webpack-dev-server": "^4.2.0", + "webpack-dev-server": "^4.10.1", "webpack-manifest-plugin": "^4.0.2", "webpack-sources": "^3.2.0" }, @@ -285,35 +288,43 @@ } }, "node_modules/@actions/core": { - "version": "1.6.0", - "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", + "version": "1.9.1", + "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "dev": true, "dependencies": { - "@actions/http-client": "^1.0.11" + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + } + }, + "node_modules/@actions/core/node_modules/uuid": { + "version": "8.3.2", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" } }, "node_modules/@actions/github": { - "version": "5.0.0", - "integrity": "sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ==", + "version": "5.0.3", + "integrity": "sha512-myjA/pdLQfhUGLtRZC/J4L1RXOG4o6aYdiEq+zr5wVVKljzbFld+xv10k1FX6IkIJtNxbAq44BdwSNpQ015P0A==", "dev": true, "dependencies": { - "@actions/http-client": "^1.0.11", - "@octokit/core": "^3.4.0", - "@octokit/plugin-paginate-rest": "^2.13.3", - "@octokit/plugin-rest-endpoint-methods": "^5.1.1" + "@actions/http-client": "^2.0.1", + "@octokit/core": "^3.6.0", + "@octokit/plugin-paginate-rest": "^2.17.0", + "@octokit/plugin-rest-endpoint-methods": "^5.13.0" } }, "node_modules/@actions/http-client": { - "version": "1.0.11", - "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", + "version": "2.0.1", + "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", "dev": true, "dependencies": { - "tunnel": "0.0.6" + "tunnel": "^0.0.6" } }, "node_modules/@ag-grid-community/all-modules": { "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@ag-grid-community/all-modules/-/all-modules-26.2.1.tgz", "integrity": "sha512-zO8PFBSiChQEmJLmWe/gaKhDOPvOR+4yWlTmfIBTWZ/j/zhJSeCNHor6WQGakgfONrNOq0P6yQjVu0d7JFi7mA==", "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, @@ -326,7 +337,6 @@ }, "node_modules/@ag-grid-community/client-side-row-model": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-community/client-side-row-model/-/client-side-row-model-26.2.0.tgz", "integrity": "sha512-kW5lMsK5WEXaqZMfHbLRj+EvxLhPW6qtDv61PyDcv+/91lwm2p5dT/iUBppavSwJDiNul+wntpyIlTulZgokwA==", "dev": true, "dependencies": { @@ -335,13 +345,11 @@ }, "node_modules/@ag-grid-community/core": { "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@ag-grid-community/core/-/core-26.2.1.tgz", "integrity": "sha512-E2e3rZoZ90QtgO320kmlrm7kFbzFkCyrvCWYUQshJJU/UzCqr6DffVAXTaeehPNLzHBybANxWbSbFab9LQLIwQ==", "dev": true }, "node_modules/@ag-grid-community/csv-export": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-community/csv-export/-/csv-export-26.2.0.tgz", "integrity": "sha512-2QqzmYIqqXpPwvIiIpWXV9VWKVK5mLdZI3RVnZdgWGCyTD0OAqWPgqY5LapVpyxGfE/oUm7s9O7ux7EFiTdEcA==", "dev": true, "dependencies": { @@ -350,7 +358,6 @@ }, "node_modules/@ag-grid-community/infinite-row-model": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-community/infinite-row-model/-/infinite-row-model-26.2.0.tgz", "integrity": "sha512-wA4qSYD/XdvrjVQ6gdENaX++QlQufndWJonl7oVCPzxw7fO3H1i8DFpfr2fe/BXwrcDM1LeJ5HM6jzIuKIrddg==", "dev": true, "dependencies": { @@ -359,7 +366,6 @@ }, "node_modules/@ag-grid-community/react": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-community/react/-/react-26.2.0.tgz", "integrity": "sha512-IWNSuyoiRkIbRpoz+Nvagyz8MsoQbTVQ25ixj75VNAyShK/xWus92FMQQFFQBR11Pb3paZeEttrmF0D8WEFLTQ==", "dev": true, "dependencies": { @@ -373,7 +379,6 @@ }, "node_modules/@ag-grid-enterprise/all-modules": { "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/all-modules/-/all-modules-26.2.1.tgz", "integrity": "sha512-UhpdeQwgYQqYtCv7Mm5qncsnbwqDohZGjTtCBcbq5tQ5NkURgmoiJbVAQzF0myK5K2BxxOejVytONj18uCSSrg==", "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, @@ -401,7 +406,6 @@ }, "node_modules/@ag-grid-enterprise/charts": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/charts/-/charts-26.2.0.tgz", "integrity": "sha512-Y3G2PzyjypR5o1c+1A1VEhTxEvhIvyYWMMTn2KexGtTOBhDqZPB1LyAS8+L7RBhRdtvydXnj3IQBPdQFmhK4Fw==", "dev": true, "dependencies": { @@ -413,7 +417,6 @@ }, "node_modules/@ag-grid-enterprise/clipboard": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/clipboard/-/clipboard-26.2.0.tgz", "integrity": "sha512-24y+IgJrNz6f3WIWxBHzyP32rW932YMagiX0MbJqRfepu32N71DGlXqjuGawXDRLYTbgpQ1196X2otqTQkJK5Q==", "dev": true, "dependencies": { @@ -424,7 +427,6 @@ }, "node_modules/@ag-grid-enterprise/column-tool-panel": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/column-tool-panel/-/column-tool-panel-26.2.0.tgz", "integrity": "sha512-jdYT5cpgkoah0P0Bz3uiiqgakcj9EKS074r5pdMNZc944enFzD+vcYI0qnH/3Ugm1cBgYVB41UeIxBdubfGUYw==", "dev": true, "dependencies": { @@ -436,7 +438,6 @@ }, "node_modules/@ag-grid-enterprise/core": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/core/-/core-26.2.0.tgz", "integrity": "sha512-meYGtrgkEG/OvR02Z5ndSXV85ZbD2hxoUQ84rZx6/lr/U1QOmEIhzWJS3c1iqkzQrWWlDxk8JA7aHv1F+w4ysQ==", "dev": true, "dependencies": { @@ -445,7 +446,6 @@ }, "node_modules/@ag-grid-enterprise/excel-export": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/excel-export/-/excel-export-26.2.0.tgz", "integrity": "sha512-UVIau2DSh0H3gp3yzQUIdsIOrx2peDUXx9/Av69WH5H5qOb6C0c3oUAqQ80HUUy6rdWrW1nwVXGkKF4meJFupg==", "dev": true, "dependencies": { @@ -456,7 +456,6 @@ }, "node_modules/@ag-grid-enterprise/filter-tool-panel": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/filter-tool-panel/-/filter-tool-panel-26.2.0.tgz", "integrity": "sha512-1xONvJdoXeA1Hgmkt/evvHiAdjrvRNswLW3cLIdUifGSZOQ/vpQRleUsa0BEsYemrP0VU5ouIDrdypz42w2egA==", "dev": true, "dependencies": { @@ -467,7 +466,6 @@ }, "node_modules/@ag-grid-enterprise/master-detail": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/master-detail/-/master-detail-26.2.0.tgz", "integrity": "sha512-nTOJ92IGXY/hK693JHO2wvFUjLxkg8fjcH6augp99LaVI5tyA9i/WSjfuiPdiCRY3nYnwiRm1i9vtHbFDs3aRw==", "dev": true, "dependencies": { @@ -477,7 +475,6 @@ }, "node_modules/@ag-grid-enterprise/menu": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/menu/-/menu-26.2.0.tgz", "integrity": "sha512-EVBzLtRQe/kfW7l6DyRmFVbo10/yxf72X0h+afGVVp5VMjM5sTdSyvGvScRlzEGQXvptknnqjVNk6WfY9KbSNg==", "dev": true, "dependencies": { @@ -488,7 +485,6 @@ }, "node_modules/@ag-grid-enterprise/multi-filter": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/multi-filter/-/multi-filter-26.2.0.tgz", "integrity": "sha512-CH5bS0MktZhFifbGgOVicXXWOELeZ6cRDLFpZj9smznB7Ct24Ni8/ormTyBbQP7xhmlVOPe/mE9h3YC1HH18pw==", "dev": true, "dependencies": { @@ -499,7 +495,6 @@ }, "node_modules/@ag-grid-enterprise/range-selection": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/range-selection/-/range-selection-26.2.0.tgz", "integrity": "sha512-AUQsWsPH9F2PEbcUMbAldcCZQf4k2L8AU45bPKANph9dCH1/JFb7qlQAHxroOzkpvjTqyT6PjaD8vYm8Cfdvvg==", "dev": true, "dependencies": { @@ -509,7 +504,6 @@ }, "node_modules/@ag-grid-enterprise/rich-select": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/rich-select/-/rich-select-26.2.0.tgz", "integrity": "sha512-qVOHIzElUJowehZylUBO2zyNFd+3DN5m3o29WFgEM6hDsflJqdnAR/BkUYinYIi5kLXt+t00O9N2HB5XkMd+bQ==", "dev": true, "dependencies": { @@ -519,7 +513,6 @@ }, "node_modules/@ag-grid-enterprise/row-grouping": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/row-grouping/-/row-grouping-26.2.0.tgz", "integrity": "sha512-uZF65ZzXGWEfNUjQYD0SPUW1aIS6etKN7SD5wmoM6PFIVFEZNiUpQCC9nO3Jz+rSyQ+VQ89SFJCiXvoeH9F3MA==", "dev": true, "dependencies": { @@ -529,7 +522,6 @@ }, "node_modules/@ag-grid-enterprise/server-side-row-model": { "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/server-side-row-model/-/server-side-row-model-26.2.1.tgz", "integrity": "sha512-0WielbIJ8mm4tcTbDWqvVnc+E+s4IHLEy7dzgC7xhCDJR4LUJenT6xoBKThID5arXmitsgB7C574wXP0/IEdpQ==", "dev": true, "dependencies": { @@ -539,7 +531,6 @@ }, "node_modules/@ag-grid-enterprise/set-filter": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/set-filter/-/set-filter-26.2.0.tgz", "integrity": "sha512-YbqwhnnaI3J72NrJOS9dzrMDnc6O2NAEUeoybU/abbjqjYGrSXkE3SuYPP7tfMic7p6Y4/yCYqFLxo98UmiLfQ==", "dev": true, "dependencies": { @@ -549,7 +540,6 @@ }, "node_modules/@ag-grid-enterprise/side-bar": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/side-bar/-/side-bar-26.2.0.tgz", "integrity": "sha512-OzxBDazfyXqMSlttwsi5PfSas4YCIfB5xqrtzT7nKn/231mZJTIDuywIPddrWzY3ml6F0fntLl4CQtBlIIkEMA==", "dev": true, "dependencies": { @@ -559,7 +549,6 @@ }, "node_modules/@ag-grid-enterprise/sparklines": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/sparklines/-/sparklines-26.2.0.tgz", "integrity": "sha512-nbgxvpFDk2cldFikozmfw+ThRxTzH1jN6Tem2uxRRRz2QVvF8zmYAxT/reQHOUq5r8K3MAnjV6Lrf84mcWTwSg==", "dev": true, "dependencies": { @@ -569,7 +558,6 @@ }, "node_modules/@ag-grid-enterprise/status-bar": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/status-bar/-/status-bar-26.2.0.tgz", "integrity": "sha512-UTpZaDMdb+uVZSxKOvRQk9TWXwbMNWX5brTpDkdqrJiVtQToN9SLbenee9CEvXHm9I8OAo0Zb9ulbfBaBAUbNQ==", "dev": true, "dependencies": { @@ -579,7 +567,6 @@ }, "node_modules/@ag-grid-enterprise/viewport-row-model": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/viewport-row-model/-/viewport-row-model-26.2.0.tgz", "integrity": "sha512-9uyZc7Cc9a+4bW7Jzkbcv4QIGHD2m6BPReaTkL6MJS3TyXLewsQGKSnbpi3jL3Ca8XCJo2rZe14lRN981KaaZg==", "dev": true, "dependencies": { @@ -587,53 +574,107 @@ "@ag-grid-enterprise/core": "~26.2.0" } }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ampproject/remapping/node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@ant-design/colors": { - "version": "3.2.2", - "integrity": "sha512-YKgNbG2dlzqMhA9NtI3/pbY16m3Yl/EeWBRa+lB1X1YaYxHrxNexiQYCLTWO/uDvAjLFMEDU+zR901waBtMtjQ==", + "version": "6.0.0", + "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==", "dependencies": { - "tinycolor2": "^1.4.1" + "@ctrl/tinycolor": "^3.4.0" } }, "node_modules/@ant-design/icons": { - "version": "4.2.2", - "integrity": "sha512-DrVV+wcupnHS7PehJ6KiTcJtAR5c25UMgjGECCc6pUT9rsvw0AuYG+a4HDjfxEQuDqKTHwW+oX/nIvCymyLE8Q==", + "version": "4.8.0", + "integrity": "sha512-T89P2jG2vM7OJ0IfGx2+9FC5sQjtTzRSz+mCHTXkFn/ELZc2YpfStmYHmqzq2Jx55J0F7+O6i5/ZKFSVNWCKNg==", "dependencies": { - "@ant-design/colors": "^3.1.0", - "@ant-design/icons-svg": "^4.0.0", - "@babel/runtime": "^7.10.4", + "@ant-design/colors": "^6.0.0", + "@ant-design/icons-svg": "^4.2.1", + "@babel/runtime": "^7.11.2", "classnames": "^2.2.6", - "insert-css": "^2.0.0", - "rc-util": "^5.0.1" + "rc-util": "^5.9.4" }, "engines": { "node": ">=8" }, "peerDependencies": { - "react": "16.x" + "react": ">=16.0.0", + "react-dom": ">=16.0.0" } }, "node_modules/@ant-design/icons-svg": { - "version": "4.1.0", - "integrity": "sha512-Fi03PfuUqRs76aI3UWYpP864lkrfPo0hluwGqh7NJdLhvH4iRDc3jbJqZIvRDLHKbXrvAfPPV3+zjUccfFvWOQ==" + "version": "4.2.1", + "integrity": "sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==" }, - "node_modules/@ant-design/react-slick": { - "version": "0.27.14", - "integrity": "sha512-s6JVexqFmU5rs5Pm828ojtm5rCp8jDXyrc5OxEtCE2z58SIyQlkpnU9BJh98LEeBZyj02WFkGN8CWpSaD+G4PA==", + "node_modules/@applitools/core": { + "version": "1.3.7", + "integrity": "sha512-ZMJlZXw0pKFdRgXT+2OiPUQIrq8gjdqF1Z8AQGwuMrUftejIZjtweCnfXB54WCx3moA3vSJR7hlCgBV4MQ2bcg==", + "dev": true, + "dependencies": { + "@applitools/core-base": "1.1.24", + "@applitools/dom-capture": "11.2.0", + "@applitools/dom-snapshot": "4.7.3", + "@applitools/driver": "1.11.21", + "@applitools/logger": "1.1.36", + "@applitools/nml-client": "1.3.22", + "@applitools/req": "1.1.23", + "@applitools/screenshoter": "3.7.20", + "@applitools/snippets": "2.4.12", + "@applitools/ufg-client": "1.1.12", + "@applitools/utils": "1.3.22", + "abort-controller": "3.0.0", + "chalk": "4.1.2", + "node-fetch": "2.6.7", + "throat": "6.0.1" + }, + "bin": { + "eyes-check-network": "dist/troubleshoot/check-network.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@applitools/core-base": { + "version": "1.1.24", + "integrity": "sha512-LvJLP9EpxidadtcXJivH0AIgWJqLNqsxrPyEv+Jb8nLRl+8YOjoo+06wk3leD0lATS2awlEDa267uz4GNEbrRQ==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.10.4", - "classnames": "^2.2.5", - "json2mq": "^0.2.0", - "lodash": "^4.17.15", - "resize-observer-polyfill": "^1.5.0" + "@applitools/image": "1.0.17", + "@applitools/logger": "1.1.36", + "@applitools/req": "1.1.23", + "@applitools/utils": "1.3.22" }, - "peerDependencies": { - "react": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0", - "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0" + "engines": { + "node": ">=12.13.0" } }, + "node_modules/@applitools/core/node_modules/throat": { + "version": "6.0.1", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, "node_modules/@applitools/dom-capture": { - "version": "11.1.0", - "integrity": "sha512-99NdLnHuoTT0EBDMixp19QLAZV704ztQjJfcvJZNmi5FnFzsnVpgTwRhgH5SA1JobQ09yMS9wvy0ekrpdX8lIw==", + "version": "11.2.0", + "integrity": "sha512-zFfYgvdXq5oTpLuYvOJdkh7jsbAxajOpD67pVoKc27lKwE0CGaM9I0Uf+qGh7GYtY93qyzMWBzqC7C8JlSK1gA==", "dev": true, "dependencies": { "@applitools/dom-shared": "1.0.5", @@ -652,13 +693,13 @@ } }, "node_modules/@applitools/dom-snapshot": { - "version": "4.5.12", - "integrity": "sha512-YeuAOQ0+AB7HCMPAHqpnOq5xCOXfIyC/2/h3XurOuzE+qFekK9SPMBRaJn4jDYyAFK/Eeu4v7CGW+LPAUGiZfA==", + "version": "4.7.3", + "integrity": "sha512-bovKLsjR6peaTurR35d2Ik6N+NOVeMW4FTjI6I6ZSLjzJ9XtzNGXCQ7vkTKaSe6406vDMXdcAfIu7+s6C640xg==", "dev": true, "dependencies": { - "@applitools/dom-shared": "1.0.8", + "@applitools/dom-shared": "1.0.9", "@applitools/functional-commons": "1.6.0", - "css-tree": "1.0.0-alpha.39", + "css-tree": "2.3.1", "pako": "1.0.11" }, "engines": { @@ -666,185 +707,97 @@ } }, "node_modules/@applitools/dom-snapshot/node_modules/@applitools/dom-shared": { - "version": "1.0.8", - "integrity": "sha512-HQtYfFvtlPuE9ZShBamtW1LGW2Qq4HxjQx5nF7KiNvrRTlf5/e+AWpZhXCTVEhVkAcSNs/7xR2WvumOUd+usxg==", + "version": "1.0.9", + "integrity": "sha512-u6nRHBklRAaODILm0HRluE0IAwrnjs8AMNRBFxHThKGt4qpbkhnwazGMr4zDu3WCBjr/sA31kekUqNl0Jx3YeQ==", "dev": true, "engines": { "node": ">=8.9.0" } }, "node_modules/@applitools/dom-snapshot/node_modules/css-tree": { - "version": "1.0.0-alpha.39", - "integrity": "sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA==", + "version": "2.3.1", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, "dependencies": { - "mdn-data": "2.0.6", - "source-map": "^0.6.1" + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" }, "engines": { - "node": ">=8.0.0" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, "node_modules/@applitools/dom-snapshot/node_modules/mdn-data": { - "version": "2.0.6", - "integrity": "sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA==", + "version": "2.0.30", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "dev": true }, - "node_modules/@applitools/dom-snapshot/node_modules/source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/@applitools/dom-snapshot/node_modules/source-map-js": { + "version": "1.0.2", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/@applitools/driver": { - "version": "1.6.0", - "integrity": "sha512-oKssjHF01lpI71CJd98mhBbphcOoFE9YVxZGOuPdcnfPbM83txj3MrVmH/yVRF3cDiBBVHJL8cuskjygMPhbHw==", - "dev": true, - "dependencies": { - "@applitools/snippets": "2.2.2", - "@applitools/types": "1.3.0", - "@applitools/utils": "1.2.13" - }, - "engines": { - "node": ">= 8.9.0" - } - }, - "node_modules/@applitools/eyes-sdk-core": { - "version": "13.2.5", - "integrity": "sha512-TTPg0IaByB5gMRJIcC9yQsCNqXe3EK5yORLUnSzxwk4KQTFEj2C5/2DJFtcHx+rxEuvu40BZ6dHT0avmHboqnw==", - "dev": true, - "dependencies": { - "@applitools/dom-capture": "11.1.0", - "@applitools/dom-snapshot": "4.5.12", - "@applitools/driver": "1.6.0", - "@applitools/isomorphic-fetch": "3.0.0", - "@applitools/logger": "1.0.11", - "@applitools/screenshoter": "3.3.14", - "@applitools/snippets": "2.2.2", - "@applitools/types": "1.3.0", - "@applitools/utils": "1.2.13", - "axios": "0.26.0", - "chalk": "3.0.0", - "cosmiconfig": "6.0.0", - "dateformat": "3.0.3", - "debug": "4.3.3", - "deepmerge": "4.2.2", - "stack-trace": "0.0.10", - "tunnel": "0.0.6" - }, - "bin": { - "eyes-check-network": "bin/runCheckNetwork.js" - }, - "engines": { - "node": ">= 8.9.0" - } - }, - "node_modules/@applitools/eyes-sdk-core/node_modules/axios": { - "version": "0.26.0", - "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.14.8" - } - }, - "node_modules/@applitools/eyes-sdk-core/node_modules/chalk": { - "version": "3.0.0", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "version": "1.11.21", + "integrity": "sha512-TsIVCThE3kn+/IBi2dDQ0/siXGecmXnkOND6dPW07W5WOR/e0T0EBgyD+O0QLiFQfv2ZijqlX/olS5EdXwin6g==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@applitools/logger": "1.1.36", + "@applitools/snippets": "2.4.12", + "@applitools/utils": "1.3.22", + "semver": "7.3.7" }, "engines": { - "node": ">=8" + "node": ">=12.13.0" } }, - "node_modules/@applitools/eyes-sdk-core/node_modules/cosmiconfig": { + "node_modules/@applitools/driver/node_modules/lru-cache": { "version": "6.0.0", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" + "yallist": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/@applitools/eyes-sdk-core/node_modules/debug": { - "version": "4.3.3", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "node_modules/@applitools/driver/node_modules/semver": { + "version": "7.3.7", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" + "lru-cache": "^6.0.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@applitools/eyes-sdk-core/node_modules/deepmerge": { - "version": "4.2.2", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@applitools/eyes-sdk-core/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@applitools/eyes-sdk-core/node_modules/parse-json": { - "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10" } }, - "node_modules/@applitools/eyes-sdk-core/node_modules/path-type": { + "node_modules/@applitools/driver/node_modules/yallist": { "version": "4.0.0", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/@applitools/eyes-storybook": { - "version": "3.27.6", - "integrity": "sha512-4vOMGqiF5HxbQhLPKLDwE7S+qr5W22J/C8GJ3fD0NLPXj8Nk5VMdmSp9vXz7AfB9iphGMvYfGjTNE37qz29bag==", + "version": "3.30.1", + "integrity": "sha512-lehBp+0qLI4PTshNg1LVueq82/Cx7+r8DPThbnP+pPrrfu0ERw/B8w5YRmwAHlBAsQB9IqRb3qqHu8nC2ktdpQ==", "dev": true, "hasInstallScript": true, "dependencies": { - "@applitools/driver": "1.6.0", - "@applitools/eyes-sdk-core": "13.2.5", + "@applitools/core": "1.3.7", + "@applitools/driver": "1.11.21", "@applitools/functional-commons": "1.6.0", - "@applitools/logger": "1.0.11", + "@applitools/logger": "1.1.36", "@applitools/monitoring-commons": "1.0.19", - "@applitools/spec-driver-puppeteer": "1.1.1", - "@applitools/test-server": "1.0.8", - "@applitools/utils": "1.2.13", - "@applitools/visual-grid-client": "15.11.2", + "@applitools/spec-driver-puppeteer": "1.1.31", + "@applitools/test-server": "1.1.16", + "@applitools/ufg-client": "1.1.12", + "@applitools/utils": "1.3.22", "boxen": "4.2.0", "chalk": "3.0.0", "detect-port": "1.3.0", @@ -853,13 +806,14 @@ "ora": "3.4.0", "puppeteer": "10.2.0", "strip-ansi": "6.0.0", + "throat": "6.0.1", "yargs": "15.4.1" }, "bin": { "eyes-storybook": "bin/eyes-storybook.js" }, "engines": { - "node": ">=8.6.0" + "node": ">=12.13.0" } }, "node_modules/@applitools/eyes-storybook/node_modules/ansi-regex": { @@ -1104,6 +1058,11 @@ "node": ">=8" } }, + "node_modules/@applitools/eyes-storybook/node_modules/throat": { + "version": "6.0.1", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, "node_modules/@applitools/functional-commons": { "version": "1.6.0", "integrity": "sha512-fwiF0CbeYHDEOTD/NKaFgaI8LvRcGYG2GaJJiRwcedKko16sQ8F3TK5wXfj2Ytjf+8gjwHwsEEX550z3yvDWxA==", @@ -1112,50 +1071,18 @@ "node": ">=8.0.0" } }, - "node_modules/@applitools/http-commons": { - "version": "2.4.5", - "integrity": "sha512-w1lP9aljD6FLp/wgifj/oyj/bTCiAH2PuwDJci5QKJAeymqPoRGrKvykoKOegpa5OjdmZSPD/kW40ZTHSsST5Q==", - "dev": true, - "dependencies": { - "@applitools/functional-commons": "^1.5.5", - "@applitools/monitoring-commons": "^1.0.19", - "agentkeepalive": "^4.1.0", - "debug": "^4.1.1", - "lodash.merge": "^4.6.2", - "node-fetch": "^2.6.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@applitools/http-commons/node_modules/debug": { - "version": "4.3.4", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@applitools/image": { + "version": "1.0.17", + "integrity": "sha512-ftkyDvpO2X8WVosXtt/EUAuow3SqAs+G1TMe1EQ3NEb/zpGlYFsq/5gzyJRTzNAll7bfJGqWgNBKlTioeTcT+g==", "dev": true, "dependencies": { - "ms": "2.1.2" + "@applitools/utils": "1.3.22", + "bmpimagejs": "1.0.4", + "jpeg-js": "0.4.4", + "png-async": "0.9.4" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@applitools/http-commons/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@applitools/isomorphic-fetch": { - "version": "3.0.0", - "integrity": "sha512-7rutaN/2M5wYjOIOTKS/Zuc1Na90fJNEAqvo/jCxt7nSD1kYscHV3aCk9t7RD59gmzLMvUTIxFbjl4RUMV8qfg==", - "dev": true, - "dependencies": { - "node-fetch": "^2.3.0", - "whatwg-fetch": ">=0.10.0" + "node": ">=12.13.0" } }, "node_modules/@applitools/jsdom": { @@ -1203,36 +1130,6 @@ "node": ">= 10" } }, - "node_modules/@applitools/jsdom/node_modules/cssom": { - "version": "0.5.0", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "node_modules/@applitools/jsdom/node_modules/data-urls": { - "version": "3.0.2", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@applitools/jsdom/node_modules/data-urls/node_modules/whatwg-url": { - "version": "11.0.0", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@applitools/jsdom/node_modules/debug": { "version": "4.3.4", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", @@ -1249,17 +1146,6 @@ } } }, - "node_modules/@applitools/jsdom/node_modules/domexception": { - "version": "4.0.0", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@applitools/jsdom/node_modules/escodegen": { "version": "2.0.0", "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", @@ -1314,17 +1200,6 @@ "node": ">= 6" } }, - "node_modules/@applitools/jsdom/node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@applitools/jsdom/node_modules/http-proxy-agent": { "version": "5.0.0", "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", @@ -1369,13 +1244,14 @@ } }, "node_modules/@applitools/jsdom/node_modules/tough-cookie": { - "version": "4.0.0", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "version": "4.1.2", + "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", "dev": true, "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", - "universalify": "^0.1.2" + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "engines": { "node": ">=6" @@ -1393,24 +1269,13 @@ } }, "node_modules/@applitools/jsdom/node_modules/universalify": { - "version": "0.1.2", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "0.2.0", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, "engines": { "node": ">= 4.0.0" } }, - "node_modules/@applitools/jsdom/node_modules/w3c-xmlserializer": { - "version": "3.0.0", - "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", - "dev": true, - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@applitools/jsdom/node_modules/webidl-conversions": { "version": "7.0.0", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", @@ -1451,15 +1316,15 @@ } }, "node_modules/@applitools/jsdom/node_modules/ws": { - "version": "8.5.0", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "version": "8.12.0", + "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -1479,27 +1344,15 @@ } }, "node_modules/@applitools/logger": { - "version": "1.0.11", - "integrity": "sha512-AcTTpLfUggo4/TISBk5+X4PdSZuMDEK0+gzsf+b9BCFzPDc7p4yrAHeftHdjOV/AE3yLQEWnupUmlsttdMayXQ==", - "dev": true, - "dependencies": { - "@applitools/utils": "1.2.13", - "chalk": "3.0.0" - }, - "engines": { - "node": ">= 8.9.0" - } - }, - "node_modules/@applitools/logger/node_modules/chalk": { - "version": "3.0.0", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "version": "1.1.36", + "integrity": "sha512-Ul2b96Cz5XBZa5mZkszRs4WXtfsrXwM4HD0q7BLbBJ91B9gGzZrbn9bI837BlpcHAw0O4h8i+D9migeTmFrxaA==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@applitools/utils": "1.3.22", + "chalk": "4.1.2" }, "engines": { - "node": ">=8" + "node": ">=12.13.0" } }, "node_modules/@applitools/monitoring-commons": { @@ -1534,68 +1387,99 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@applitools/nml-client": { + "version": "1.3.22", + "integrity": "sha512-QTGejQtd8fCkE2PxGbhGg+/bbTdPKWsLGO/KT8LxybvUO+SehW5YQbPiTcuo95/z9tAywWPXwtdTIzxiImeiGA==", + "dev": true, + "dependencies": { + "@applitools/logger": "1.1.36", + "@applitools/req": "1.1.23", + "@applitools/utils": "1.3.22" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@applitools/req": { + "version": "1.1.23", + "integrity": "sha512-iy2XEtUXNM5YQJbS3pXijiBC+tKpIJjU8nQNHBlGaVbd4r/cxYCEmKPC0lLKVYRbxk7Qi4Lfbh2cmAEQ6Ncf3A==", + "dev": true, + "dependencies": { + "@applitools/utils": "1.3.22", + "@types/node-fetch": "2.6.2", + "abort-controller": "3.0.0", + "node-fetch": "2.6.7", + "proxy-agent": "5.0.0" + }, + "engines": { + "node": ">=12.13.0" + } + }, "node_modules/@applitools/screenshoter": { - "version": "3.3.14", - "integrity": "sha512-DwZFJiBIgEkyzEaESnl3A87KeSVnUmHKad9vg+iwgtAFQf492ZI7t+PKhjGVM9ekZ8q5Sz4xnO+Bsmk8qEu0+A==", + "version": "3.7.20", + "integrity": "sha512-GFJFjytmXm3TXo/h6gXAF8BIZ5A9oxSFjJmNWv2WiJn64xXFd/3hlW6U4ejrnWiFEo3TV8JNUIZmGRF/DvG1Yw==", "dev": true, "dependencies": { - "@applitools/snippets": "2.2.2", - "@applitools/utils": "1.2.13", + "@applitools/image": "1.0.17", + "@applitools/logger": "1.1.36", + "@applitools/snippets": "2.4.12", + "@applitools/utils": "1.3.22", + "jpeg-js": "0.4.4", "png-async": "0.9.4" }, "engines": { - "node": ">= 10.0.0" + "node": ">=12.13.0" } }, "node_modules/@applitools/snippets": { - "version": "2.2.2", - "integrity": "sha512-XOxdrsWgcEu6h6QTVL/S8/dJHoPGir1GKQLyWORbRfbjll15/mUj3Mzzi9MqL6lSN3KWp07ncLvMuhSETpi7Mg==", + "version": "2.4.12", + "integrity": "sha512-+B1jseyCYrwhweX27j92GQkgU30G+V1TrmUVzkA/Wl6HIqVFUAgX9QHh4dmTcgsKCcgQ8el+LX2VBhz7nJmCGw==", "dev": true, "engines": { - "node": ">=8.9.0" + "node": ">=12.13.0" } }, "node_modules/@applitools/spec-driver-puppeteer": { - "version": "1.1.1", - "integrity": "sha512-64TvcOc8vHYz1IXftOJzNqy0lLTMMnnjvKhcqMwIct5PJY8QYdVZagBRwGF9L9wYhs8ULtpmSa/SmpPaIbMNUQ==", + "version": "1.1.31", + "integrity": "sha512-GYXbAh8tgZa/eqqkwYaRa/TKKK+VNqXy8UbewpBgWY+qh+1uCe+qpm1hscKDqPZDVIzBFAHgqvwpWRMUrd+DGw==", "dev": true, "dependencies": { - "@applitools/types": "1.3.0", - "@applitools/utils": "1.2.13" + "@applitools/driver": "1.11.21", + "@applitools/utils": "1.3.22" + }, + "engines": { + "node": ">=12.13.0" }, "peerDependencies": { "puppeteer": ">=5.3.0" } }, "node_modules/@applitools/test-server": { - "version": "1.0.8", - "integrity": "sha512-KP1A8aySLoU532zCG6mwk2Mair56gQ5xp75ZnV4/CvefCzeD2f/nqUBYmoiTN940QOrQVWAXeXvuwMj1BUJD0Q==", + "version": "1.1.16", + "integrity": "sha512-o76pc9LG45PGDWFZDbo9uc/ojSeYMEVPvQZbw3jWX5DuiJ+Md2HE8H5+lf1krIKW8/91hqucYU0X+EZ0akzB/A==", "dev": true, "dependencies": { - "@applitools/utils": "1.2.4", + "@applitools/logger": "1.1.36", + "@applitools/utils": "1.3.22", + "body-parser": "1.20.0", "chalk": "3.0.0", "cookie-parser": "1.4.5", "cors": "2.8.5", - "express": "4.17.1", + "express": "4.17.3", "handlebars": "4.7.7", + "http-proxy": "1.18.1", "morgan": "1.10.0", + "node-forge": "1.3.1", "yargs": "17.0.1" }, "bin": { - "test-server": "cli/test-server.js" + "proxy-server": "dist/cli/proxy-server.js", + "test-server": "dist/cli/test-server.js" }, "engines": { "node": ">=12.0.0" } }, - "node_modules/@applitools/test-server/node_modules/@applitools/utils": { - "version": "1.2.4", - "integrity": "sha512-w7ma6FFGyqhdP6LEcuHFWOcH7EzBjnoAX3UfbFWcTHA3QXnXPX37Y2ENYRodfwkorP1cUKyUHwNXJB/BMIj/hg==", - "dev": true, - "engines": { - "node": ">= 8.9.0" - } - }, "node_modules/@applitools/test-server/node_modules/ansi-regex": { "version": "5.0.1", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", @@ -1604,6 +1488,37 @@ "node": ">=8" } }, + "node_modules/@applitools/test-server/node_modules/body-parser": { + "version": "1.20.0", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/@applitools/test-server/node_modules/bytes": { + "version": "3.1.2", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/@applitools/test-server/node_modules/chalk": { "version": "3.0.0", "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", @@ -1626,6 +1541,43 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/@applitools/test-server/node_modules/depd": { + "version": "2.0.0", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@applitools/test-server/node_modules/destroy": { + "version": "1.2.0", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/@applitools/test-server/node_modules/http-errors": { + "version": "2.0.0", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@applitools/test-server/node_modules/inherits": { + "version": "2.0.4", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, "node_modules/@applitools/test-server/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", @@ -1634,6 +1586,58 @@ "node": ">=8" } }, + "node_modules/@applitools/test-server/node_modules/on-finished": { + "version": "2.4.1", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@applitools/test-server/node_modules/qs": { + "version": "6.10.3", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@applitools/test-server/node_modules/raw-body": { + "version": "2.5.1", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@applitools/test-server/node_modules/setprototypeof": { + "version": "1.2.0", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/@applitools/test-server/node_modules/statuses": { + "version": "2.0.1", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/@applitools/test-server/node_modules/string-width": { "version": "4.2.3", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", @@ -1707,66 +1711,48 @@ "node": ">=10" } }, - "node_modules/@applitools/types": { - "version": "1.3.0", - "integrity": "sha512-aLLm5FVtg/iDnrNvIDFKZrHQ2Nh64dSuy5VairQroMoCwK90Pft75Dy6CQC5g4IUEN04Wub9sx2kmthjQiwkZA==", - "dev": true, - "engines": { - "node": ">= 8.9.0" - } - }, - "node_modules/@applitools/utils": { - "version": "1.2.13", - "integrity": "sha512-yZ333Y/bAH/A05UMBllEdqBAwkFQknih2arIRSfN+QBpiFrfuLtQEdCwXAdnvU/MbAzZ/Tje7iv93FMzs5gFZA==", - "dev": true, - "engines": { - "node": ">= 8.9.0" - } - }, - "node_modules/@applitools/visual-grid-client": { - "version": "15.11.2", - "integrity": "sha512-PVnyVBlVjocnFjtXAbjH1UmAHz01/6GmaBV9fTFAjnpzCHDEbZ4Uz+pNi7hhMKy/hzRoe8LuRLZVBbagkhx9Aw==", + "node_modules/@applitools/ufg-client": { + "version": "1.1.12", + "integrity": "sha512-JHTKxCiqjzjpAsMdwqe9SW5ZokJzaLA6llRw78ohPdDu8NwrNE1x/0D0OGpBB+RPnoeTMPjvgJ81bfyjKcTf8A==", "dev": true, "dependencies": { - "@applitools/eyes-sdk-core": "13.2.5", - "@applitools/functional-commons": "1.6.0", - "@applitools/http-commons": "2.4.5", - "@applitools/isomorphic-fetch": "3.0.0", "@applitools/jsdom": "1.0.4", - "@applitools/logger": "1.0.11", + "@applitools/logger": "1.1.36", + "@applitools/req": "1.1.23", + "@applitools/utils": "1.3.22", "abort-controller": "3.0.0", - "chalk": "3.0.0", - "postcss-value-parser": "4.1.0", - "throat": "5.0.0" + "postcss-value-parser": "4.2.0", + "throat": "6.0.1" }, "engines": { - "node": ">=8.9.0" + "node": ">=12.13.0" } }, - "node_modules/@applitools/visual-grid-client/node_modules/chalk": { - "version": "3.0.0", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "node_modules/@applitools/ufg-client/node_modules/throat": { + "version": "6.0.1", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "node_modules/@applitools/utils": { + "version": "1.3.22", + "integrity": "sha512-2hRcD8YMsiHiN82YWoWHv6Vt0kp0GRaf4+aI+UlUgAfNO5qgJFerXntT499MkulOSUmtd8VnujYk4jqKUEt00g==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=8" + "node": ">=12.13.0" } }, "node_modules/@babel/cli": { - "version": "7.16.0", - "integrity": "sha512-WLrM42vKX/4atIoQB+eb0ovUof53UUvecb4qGjU2PDDWRiZr50ZpiV8NpcLo7iSxeGYrRG0Mqembsa+UrTAV6Q==", + "version": "7.18.10", + "integrity": "sha512-dLvWH+ZDFAkd2jPBSghrsFBuXrREvFwjpDycXbmUoeochqKYe4zNSLEJYErpLg8dvxvZYe79/MkN461XCwpnGw==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.8", "commander": "^4.0.1", "convert-source-map": "^1.1.0", "fs-readdir-recursive": "^1.1.0", - "glob": "^7.0.0", + "glob": "^7.2.0", "make-dir": "^2.1.0", - "slash": "^2.0.0", - "source-map": "^0.5.0" + "slash": "^2.0.0" }, "bin": { "babel": "bin/babel.js", @@ -1792,41 +1778,41 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.14.5", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.18.6", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.15.0", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "version": "7.18.8", + "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.15.5", - "integrity": "sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg==", - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.5", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.18.10", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "json5": "^2.2.1", + "semver": "^6.3.0" }, "engines": { "node": ">=6.9.0" @@ -1852,11 +1838,8 @@ } }, "node_modules/@babel/core/node_modules/json5": { - "version": "2.1.3", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dependencies": { - "minimist": "^1.2.5" - }, + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -1876,8 +1859,8 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.15.7", - "integrity": "sha512-yJkHyomClm6A2Xzb8pdAo4HzYMSXFn1O5zrCYvbFP0yQFvHueLedV8WiEno8yJOKStjUXzBZzJFeWQ7b3YMsqQ==", + "version": "7.18.9", + "integrity": "sha512-KzSGpMBggz4fKbRbWLNyPVTuQr6cmCcBhOyXTw/fieOVaw5oYAwcAj4a7UKcDYCPxQq+CG1NCDZH9e2JTXquiQ==", "dev": true, "dependencies": { "eslint-scope": "^5.1.1", @@ -1889,7 +1872,7 @@ }, "peerDependencies": { "@babel/core": ">=7.11.0", - "eslint": ">=7.5.0" + "eslint": "^7.5.0 || ^8.0.0" } }, "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { @@ -1909,45 +1892,45 @@ } }, "node_modules/@babel/generator": { - "version": "7.15.4", - "integrity": "sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw==", + "version": "7.18.12", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", "dependencies": { - "@babel/types": "^7.15.4", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.15.4", - "integrity": "sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==", + "version": "7.18.6", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.15.4", - "integrity": "sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q==", + "version": "7.18.9", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.15.4", - "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "version": "7.18.9", + "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", + "@babel/compat-data": "^7.18.8", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", "semver": "^6.3.0" }, "engines": { @@ -1965,15 +1948,16 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.15.4", - "integrity": "sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw==", + "version": "7.18.9", + "integrity": "sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1983,11 +1967,11 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", + "version": "7.18.6", + "integrity": "sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "regexpu-core": "^4.7.1" + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" }, "engines": { "node": ">=6.9.0" @@ -2039,201 +2023,209 @@ "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.15.4", - "integrity": "sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g==", - "dependencies": { - "@babel/types": "^7.15.4" - }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.15.4", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", "dependencies": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.15.4", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "node_modules/@babel/helper-function-name": { + "version": "7.18.9", + "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/template": "^7.18.6", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.15.4", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "version": "7.18.6", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.15.4", - "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "version": "7.18.9", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.15.4", - "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "version": "7.18.6", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.15.7", - "integrity": "sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==", + "version": "7.18.9", + "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", "dependencies": { - "@babel/helper-module-imports": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-simple-access": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.15.4", - "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", + "version": "7.18.6", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.14.5", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "version": "7.18.9", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.15.4", - "integrity": "sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ==", + "version": "7.18.9", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-wrap-function": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.15.4", - "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", + "version": "7.18.9", + "integrity": "sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.15.4", - "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "version": "7.18.6", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.15.4", - "integrity": "sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A==", + "version": "7.18.9", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.15.4", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "version": "7.18.6", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.18.10", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.18.6", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.14.5", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "version": "7.18.6", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.15.4", - "integrity": "sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw==", + "version": "7.18.11", + "integrity": "sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w==", "dependencies": { - "@babel/helper-function-name": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-function-name": "^7.18.9", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.11", + "@babel/types": "^7.18.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.15.4", - "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "version": "7.18.9", + "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", "dependencies": { - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.14.5", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.18.6", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -2274,13 +2266,13 @@ } }, "node_modules/@babel/node": { - "version": "7.15.4", - "integrity": "sha512-UZue+j8p5aKTaVjvy5psYmqLHqmz+9cIboAFoa97S1xeZyUr0gT6KzXB8ZkfBIsP/u79biOdjGHVXBXnW3rVfw==", + "version": "7.18.10", + "integrity": "sha512-VbqzK6QXfQVi4Bpk6J7XqHXKFNbG2j3rdIdx68+/14GDU7jXDOSyUU/cwqCM1fDwCdxp37pNV/ToSCXsNChcyA==", "dev": true, "dependencies": { - "@babel/register": "^7.15.3", + "@babel/register": "^7.18.9", "commander": "^4.0.1", - "core-js": "^3.16.0", + "core-js": "^3.22.1", "node-environment-flags": "^1.0.5", "regenerator-runtime": "^0.13.4", "v8flags": "^3.1.1" @@ -2304,8 +2296,8 @@ } }, "node_modules/@babel/parser": { - "version": "7.15.7", - "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==", + "version": "7.18.11", + "integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -2313,13 +2305,26 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.15.4", - "integrity": "sha512-eBnpsl9tlhPhpI10kU06JHnrYXwg3+V6CaP2idsCXNef0aeslpqyITXQ74Vfk5uHgY7IG7XP0yIH8b42KSzHog==", + "version": "7.18.9", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4", - "@babel/plugin-proposal-optional-chaining": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -2329,11 +2334,12 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.15.4", - "integrity": "sha512-2zt2g5vTXpMC3OmK6uyjvdXptbhBXfA77XGrd3gh93zwG8lZYBLOBImiGBEG0RANu3JqKEACCz5CGk73OJROBw==", + "version": "7.18.10", + "integrity": "sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.15.4", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -2344,11 +2350,11 @@ } }, "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.14.5", - "integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==", + "version": "7.18.6", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2358,11 +2364,11 @@ } }, "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.15.4", - "integrity": "sha512-M682XWrrLNk3chXCjoPUQWOyYsB93B9z3mRyjtqqYJWDf2mfCdIYgDrA11cgNVhAQieaq6F2fn2f3wI0U4aTjA==", + "version": "7.18.6", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -2388,10 +2394,10 @@ } }, "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.14.5", - "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", + "version": "7.18.6", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -2416,10 +2422,10 @@ } }, "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.14.5", - "integrity": "sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==", + "version": "7.18.9", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -2430,10 +2436,10 @@ } }, "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.14.5", - "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", + "version": "7.18.6", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -2444,10 +2450,10 @@ } }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.14.5", - "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", + "version": "7.18.9", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -2458,10 +2464,10 @@ } }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.14.5", - "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", + "version": "7.18.6", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -2472,10 +2478,10 @@ } }, "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.14.5", - "integrity": "sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==", + "version": "7.18.6", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -2498,10 +2504,10 @@ } }, "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.14.5", - "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", + "version": "7.18.6", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -2512,11 +2518,11 @@ } }, "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.14.5", - "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", + "version": "7.18.9", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -2527,11 +2533,11 @@ } }, "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.14.5", - "integrity": "sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==", + "version": "7.18.6", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2541,12 +2547,12 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.15.4", - "integrity": "sha512-X0UTixkLf0PCCffxgu5/1RQyGGbgZuKoI+vXP4iSbJSYwPb7hu06omsFGBvQ9lJEvwgrxHdS8B5nbfcd8GyUNA==", + "version": "7.18.6", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-create-class-features-plugin": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -2557,11 +2563,11 @@ } }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.14.5", - "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", + "version": "7.18.6", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=4" @@ -2673,6 +2679,19 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.1", "integrity": "sha512-ypC4jwfIVF72og0dgvEcFRdOM2V9Qm1tu7RGmdZOlhsccyK0wisXmMObGuWEOd5jQ+K9wcIgSNftCpk2vkjUfQ==", @@ -2695,10 +2714,10 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.14.5", - "integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==", + "version": "7.18.6", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2807,10 +2826,10 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.14.5", - "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", + "version": "7.18.6", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2820,12 +2839,12 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.14.5", - "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", + "version": "7.18.6", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5" + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2835,10 +2854,10 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.14.5", - "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", + "version": "7.18.6", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2848,10 +2867,10 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.15.3", - "integrity": "sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q==", + "version": "7.18.9", + "integrity": "sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -2861,15 +2880,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.15.4", - "integrity": "sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", + "version": "7.18.9", + "integrity": "sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", "globals": "^11.1.0" }, "engines": { @@ -2880,10 +2900,10 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.14.5", - "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", + "version": "7.18.9", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -2893,10 +2913,10 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.14.7", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", + "version": "7.18.9", + "integrity": "sha512-p5VCYNddPLkZTq4XymQIaIfZNJwT9YsjkPOhkVEqt6QIpQFZVM9IltqqYpOEkJoN1DPznmxUDyZ5CTZs/ZCuHA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -2906,11 +2926,11 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.14.5", - "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", + "version": "7.18.6", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2920,10 +2940,10 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.14.5", - "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", + "version": "7.18.9", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -2933,11 +2953,11 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.14.5", - "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", + "version": "7.18.6", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2961,10 +2981,10 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.15.4", - "integrity": "sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA==", + "version": "7.18.8", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2974,11 +2994,12 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.14.5", - "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", + "version": "7.18.9", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "dependencies": { - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -2988,10 +3009,10 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.14.5", - "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", + "version": "7.18.9", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -3001,10 +3022,10 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.14.5", - "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", + "version": "7.18.6", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3014,11 +3035,11 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.14.5", - "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", + "version": "7.18.6", + "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", "dependencies": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -3029,12 +3050,12 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.15.4", - "integrity": "sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA==", + "version": "7.18.6", + "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", "dependencies": { - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -3045,13 +3066,13 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.15.4", - "integrity": "sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw==", + "version": "7.18.9", + "integrity": "sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A==", "dependencies": { - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-identifier": "^7.18.6", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -3062,11 +3083,11 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.14.5", - "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", + "version": "7.18.6", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", "dependencies": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3076,10 +3097,11 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.14.9", - "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", + "version": "7.18.6", + "integrity": "sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3089,10 +3111,10 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.14.5", - "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", + "version": "7.18.6", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3102,11 +3124,11 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.14.5", - "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", + "version": "7.18.6", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3116,10 +3138,10 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.15.4", - "integrity": "sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ==", + "version": "7.18.8", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3129,10 +3151,10 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.14.5", - "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", + "version": "7.18.6", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3156,10 +3178,10 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.15.1", - "integrity": "sha512-yQZ/i/pUCJAHI/LbtZr413S3VT26qNrEm0M5RRxQJA947/YNYwbZbBaXGDrq6CG5QsZycI1VIP6d7pQaBfP+8Q==", + "version": "7.18.6", + "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3169,14 +3191,14 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.14.9", - "integrity": "sha512-30PeETvS+AeD1f58i1OVyoDlVYQhap/K20ZrMjLmmzmC2AYR/G43D4sdJAaDAqCD3MYpSWbmrz3kES158QSLjw==", + "version": "7.18.10", + "integrity": "sha512-gCy7Iikrpu3IZjYZolFE4M1Sm+nrh1/6za2Ewj77Z+XirT4TsbJcvOFOyF+fRPwU6AKKK136CZxx6L8AbSFG6A==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-jsx": "^7.14.5", - "@babel/types": "^7.14.9" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.18.10" }, "engines": { "node": ">=6.9.0" @@ -3186,10 +3208,10 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.14.5", - "integrity": "sha512-rdwG/9jC6QybWxVe2UVOa7q6cnTpw8JRRHOxntG/h6g/guAOe6AhtQHJuJh5FwmnXIT1bdm5vC2/5huV8ZOorQ==", + "version": "7.18.6", + "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.14.5" + "@babel/plugin-transform-react-jsx": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3199,11 +3221,11 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.14.5", - "integrity": "sha512-3X4HpBJimNxW4rhUy/SONPyNQHp5YRr0HhJdT2OH1BRp0of7u3Dkirc7x9FRJMKMqTBI079VZ1hzv7Ouuz///g==", + "version": "7.18.6", + "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3213,10 +3235,11 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.14.5", - "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", + "version": "7.18.6", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", "dependencies": { - "regenerator-transform": "^0.14.2" + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" }, "engines": { "node": ">=6.9.0" @@ -3226,10 +3249,10 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.14.5", - "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", + "version": "7.18.6", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3239,15 +3262,15 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.15.0", - "integrity": "sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw==", + "version": "7.18.10", + "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", - "babel-plugin-polyfill-regenerator": "^0.2.2", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", "semver": "^6.3.0" }, "engines": { @@ -3258,14 +3281,12 @@ } }, "node_modules/@babel/plugin-transform-runtime/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.2", + "integrity": "sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -3276,20 +3297,20 @@ } }, "node_modules/@babel/plugin-transform-runtime/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.2.5", - "integrity": "sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw==", + "version": "0.5.3", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.16.2" + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-runtime/node_modules/debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -3317,10 +3338,10 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.14.5", - "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", + "version": "7.18.6", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3330,11 +3351,11 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.14.6", - "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", + "version": "7.18.9", + "integrity": "sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -3344,10 +3365,10 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.14.5", - "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", + "version": "7.18.6", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3357,10 +3378,10 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.14.5", - "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", + "version": "7.18.9", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -3370,10 +3391,10 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.14.5", - "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", + "version": "7.18.9", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -3398,10 +3419,10 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.14.5", - "integrity": "sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==", + "version": "7.18.10", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -3411,11 +3432,11 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.14.5", - "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", + "version": "7.18.6", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3440,34 +3461,36 @@ "hasInstallScript": true }, "node_modules/@babel/preset-env": { - "version": "7.15.6", - "integrity": "sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw==", - "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.15.4", - "@babel/plugin-proposal-async-generator-functions": "^7.15.4", - "@babel/plugin-proposal-class-properties": "^7.14.5", - "@babel/plugin-proposal-class-static-block": "^7.15.4", - "@babel/plugin-proposal-dynamic-import": "^7.14.5", - "@babel/plugin-proposal-export-namespace-from": "^7.14.5", - "@babel/plugin-proposal-json-strings": "^7.14.5", - "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", - "@babel/plugin-proposal-numeric-separator": "^7.14.5", - "@babel/plugin-proposal-object-rest-spread": "^7.15.6", - "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", - "@babel/plugin-proposal-optional-chaining": "^7.14.5", - "@babel/plugin-proposal-private-methods": "^7.14.5", - "@babel/plugin-proposal-private-property-in-object": "^7.15.4", - "@babel/plugin-proposal-unicode-property-regex": "^7.14.5", + "version": "7.18.10", + "integrity": "sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==", + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -3477,44 +3500,44 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.14.5", - "@babel/plugin-transform-async-to-generator": "^7.14.5", - "@babel/plugin-transform-block-scoped-functions": "^7.14.5", - "@babel/plugin-transform-block-scoping": "^7.15.3", - "@babel/plugin-transform-classes": "^7.15.4", - "@babel/plugin-transform-computed-properties": "^7.14.5", - "@babel/plugin-transform-destructuring": "^7.14.7", - "@babel/plugin-transform-dotall-regex": "^7.14.5", - "@babel/plugin-transform-duplicate-keys": "^7.14.5", - "@babel/plugin-transform-exponentiation-operator": "^7.14.5", - "@babel/plugin-transform-for-of": "^7.15.4", - "@babel/plugin-transform-function-name": "^7.14.5", - "@babel/plugin-transform-literals": "^7.14.5", - "@babel/plugin-transform-member-expression-literals": "^7.14.5", - "@babel/plugin-transform-modules-amd": "^7.14.5", - "@babel/plugin-transform-modules-commonjs": "^7.15.4", - "@babel/plugin-transform-modules-systemjs": "^7.15.4", - "@babel/plugin-transform-modules-umd": "^7.14.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.9", - "@babel/plugin-transform-new-target": "^7.14.5", - "@babel/plugin-transform-object-super": "^7.14.5", - "@babel/plugin-transform-parameters": "^7.15.4", - "@babel/plugin-transform-property-literals": "^7.14.5", - "@babel/plugin-transform-regenerator": "^7.14.5", - "@babel/plugin-transform-reserved-words": "^7.14.5", - "@babel/plugin-transform-shorthand-properties": "^7.14.5", - "@babel/plugin-transform-spread": "^7.14.6", - "@babel/plugin-transform-sticky-regex": "^7.14.5", - "@babel/plugin-transform-template-literals": "^7.14.5", - "@babel/plugin-transform-typeof-symbol": "^7.14.5", - "@babel/plugin-transform-unicode-escapes": "^7.14.5", - "@babel/plugin-transform-unicode-regex": "^7.14.5", - "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.15.6", - "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", - "babel-plugin-polyfill-regenerator": "^0.2.2", - "core-js-compat": "^3.16.0", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.10", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "core-js-compat": "^3.22.1", "semver": "^6.3.0" }, "engines": { @@ -3525,13 +3548,11 @@ } }, "node_modules/@babel/preset-env/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.2", + "integrity": "sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==", "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -3542,14 +3563,14 @@ } }, "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.15.6", - "integrity": "sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg==", + "version": "7.18.9", + "integrity": "sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==", "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.15.4" + "@babel/plugin-transform-parameters": "^7.18.8" }, "engines": { "node": ">=6.9.0" @@ -3559,19 +3580,19 @@ } }, "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.2.5", - "integrity": "sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw==", + "version": "0.5.3", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.16.2" + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/preset-env/node_modules/debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -3611,8 +3632,8 @@ } }, "node_modules/@babel/preset-modules": { - "version": "0.1.4", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "version": "0.1.5", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", @@ -3625,15 +3646,15 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.14.5", - "integrity": "sha512-XFxBkjyObLvBaAvkx1Ie95Iaq4S/GUEIrejyrntQ/VCMKUYvKLoyKxOBzJ2kjA3b6rC9/KL6KXfDC2GqvLiNqQ==", + "version": "7.18.6", + "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-transform-react-display-name": "^7.14.5", - "@babel/plugin-transform-react-jsx": "^7.14.5", - "@babel/plugin-transform-react-jsx-development": "^7.14.5", - "@babel/plugin-transform-react-pure-annotations": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-react-display-name": "^7.18.6", + "@babel/plugin-transform-react-jsx": "^7.18.6", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-pure-annotations": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3658,13 +3679,13 @@ } }, "node_modules/@babel/register": { - "version": "7.15.3", - "integrity": "sha512-mj4IY1ZJkorClxKTImccn4T81+UKTo4Ux0+OFSV9hME1ooqS9UV+pJ6BjD0qXPK4T3XW/KNa79XByjeEMZz+fw==", + "version": "7.18.9", + "integrity": "sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==", "dependencies": { "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", "make-dir": "^2.1.0", - "pirates": "^4.0.0", + "pirates": "^4.0.5", "source-map-support": "^0.5.16" }, "engines": { @@ -3675,10 +3696,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.17.9", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.20.1", + "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", "dependencies": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.13.10" }, "engines": { "node": ">=6.9.0" @@ -3710,28 +3731,29 @@ } }, "node_modules/@babel/template": { - "version": "7.15.4", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "version": "7.18.10", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.15.4", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.18.11", + "integrity": "sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.18.11", + "@babel/types": "^7.18.10", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -3752,10 +3774,11 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@babel/types": { - "version": "7.15.6", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "version": "7.18.10", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", "to-fast-properties": "^2.0.0" }, "engines": { @@ -3923,8 +3946,8 @@ } }, "node_modules/@ctrl/tinycolor": { - "version": "3.3.1", - "integrity": "sha512-jUJrjU62MUgHDSu5JfONfgRM2V7GfN5KknsygfIbxwRZXGeayIzxk4O9GiYgEAr9DG5HJThTF5+a5x3wtrOKzQ==", + "version": "3.4.1", + "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==", "engines": { "node": ">=10" } @@ -4852,8 +4875,8 @@ } }, "node_modules/@discoveryjs/json-ext": { - "version": "0.5.3", - "integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==", + "version": "0.5.7", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "engines": { "node": ">=10.0.0" } @@ -5350,8 +5373,8 @@ "integrity": "sha512-zc9DDGEz0cgftT6VbHPrdBBVaBQrK4P6UDuuNrib1KNnbDCY1zHTMwYiN2XH6SFDufRKnsjUR5cEeWDANDDaYw==" }, "node_modules/@gar/promisify": { - "version": "1.1.2", - "integrity": "sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==" + "version": "1.1.3", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, "node_modules/@hot-loader/react-dom": { "version": "16.13.0", @@ -5423,6 +5446,11 @@ "node": ">=6.9.0" } }, + "node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", + "dev": true + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", @@ -6177,227 +6205,253 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.14", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, "node_modules/@lerna/add": { - "version": "4.0.0", - "integrity": "sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng==", + "version": "6.1.0", + "integrity": "sha512-f2cAeS1mE/p7QvSRn5TCgdUXw6QVbu8PeRxaTOxTThhTdJIWdXZfY00QjAsU6jw1PdYXK1qGUSwWOPkdR16mBg==", "dev": true, "dependencies": { - "@lerna/bootstrap": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/npm-conf": "4.0.0", - "@lerna/validation-error": "4.0.0", + "@lerna/bootstrap": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/npm-conf": "6.1.0", + "@lerna/validation-error": "6.1.0", "dedent": "^0.7.0", - "npm-package-arg": "^8.1.0", + "npm-package-arg": "8.1.1", "p-map": "^4.0.0", - "pacote": "^11.2.6", + "pacote": "^13.6.1", "semver": "^7.3.4" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/add/node_modules/@npmcli/run-script": { - "version": "1.8.6", - "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "node_modules/@lerna/add/node_modules/@npmcli/fs": { + "version": "2.1.2", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", "dev": true, "dependencies": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^7.1.0", - "read-package-json-fast": "^2.0.1" + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/add/node_modules/cacache": { - "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "node_modules/@lerna/add/node_modules/@npmcli/git": { + "version": "3.0.2", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", "dev": true, "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" }, "engines": { - "node": ">= 10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/add/node_modules/chownr": { - "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "node_modules/@lerna/add/node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/@lerna/add/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@lerna/add/node_modules/@npmcli/move-file": { + "version": "2.0.1", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/add/node_modules/mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/@lerna/add/node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/add/node_modules/@npmcli/promise-spawn": { + "version": "3.0.0", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "dependencies": { + "infer-owner": "^1.0.4" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/add/node_modules/node-gyp": { - "version": "7.1.2", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "node_modules/@lerna/add/node_modules/@npmcli/run-script": { + "version": "4.2.1", + "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", "dev": true, "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", "which": "^2.0.2" }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, "engines": { - "node": ">= 10.12.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/add/node_modules/pacote": { - "version": "11.3.5", - "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "node_modules/@lerna/add/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.8.2", - "cacache": "^15.0.5", + "balanced-match": "^1.0.0" + } + }, + "node_modules/@lerna/add/node_modules/builtins": { + "version": "5.0.1", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/@lerna/add/node_modules/cacache": { + "version": "16.1.3", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", "chownr": "^2.0.0", "fs-minipass": "^2.1.0", + "glob": "^8.0.1", "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^11.0.0", - "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", + "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.0" - }, - "bin": { - "pacote": "lib/bin.js" + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/add/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/add/node_modules/cacache/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/@lerna/add/node_modules/ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "node_modules/@lerna/add/node_modules/chownr": { + "version": "2.0.0", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, "engines": { - "node": ">= 8" + "node": ">=10" } }, - "node_modules/@lerna/add/node_modules/which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/@lerna/add/node_modules/glob": { + "version": "8.0.3", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", "dev": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": ">= 8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@lerna/add/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@lerna/bootstrap": { - "version": "4.0.0", - "integrity": "sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw==", - "dev": true, - "dependencies": { - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/has-npm-version": "4.0.0", - "@lerna/npm-install": "4.0.0", - "@lerna/package-graph": "4.0.0", - "@lerna/pulse-till-done": "4.0.0", - "@lerna/rimraf-dir": "4.0.0", - "@lerna/run-lifecycle": "4.0.0", - "@lerna/run-topologically": "4.0.0", - "@lerna/symlink-binary": "4.0.0", - "@lerna/symlink-dependencies": "4.0.0", - "@lerna/validation-error": "4.0.0", - "dedent": "^0.7.0", - "get-port": "^5.1.1", - "multimatch": "^5.0.0", - "npm-package-arg": "^8.1.0", - "npmlog": "^4.1.2", - "p-map": "^4.0.0", - "p-map-series": "^2.1.0", - "p-waterfall": "^2.1.1", - "read-package-tree": "^5.3.1", - "semver": "^7.3.4" + "node_modules/@lerna/add/node_modules/hosted-git-info": { + "version": "3.0.8", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": ">=10" } }, - "node_modules/@lerna/bootstrap/node_modules/lru-cache": { + "node_modules/@lerna/add/node_modules/lru-cache": { "version": "6.0.0", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, @@ -6408,668 +6462,626 @@ "node": ">=10" } }, - "node_modules/@lerna/bootstrap/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/add/node_modules/minimatch": { + "version": "5.1.2", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" } }, - "node_modules/@lerna/bootstrap/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@lerna/changed": { - "version": "4.0.0", - "integrity": "sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ==", + "node_modules/@lerna/add/node_modules/minipass-fetch": { + "version": "2.1.2", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", "dev": true, "dependencies": { - "@lerna/collect-updates": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/listable": "4.0.0", - "@lerna/output": "4.0.0" + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" } }, - "node_modules/@lerna/check-working-tree": { - "version": "4.0.0", - "integrity": "sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q==", + "node_modules/@lerna/add/node_modules/mkdirp": { + "version": "1.0.4", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "dependencies": { - "@lerna/collect-uncommitted": "4.0.0", - "@lerna/describe-ref": "4.0.0", - "@lerna/validation-error": "4.0.0" + "bin": { + "mkdirp": "bin/cmd.js" }, "engines": { - "node": ">= 10.18.0" + "node": ">=10" } }, - "node_modules/@lerna/child-process": { - "version": "4.0.0", - "integrity": "sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q==", + "node_modules/@lerna/add/node_modules/npm-install-checks": { + "version": "5.0.0", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", "dev": true, "dependencies": { - "chalk": "^4.1.0", - "execa": "^5.0.0", - "strong-log-transformer": "^2.1.0" + "semver": "^7.1.1" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/child-process/node_modules/cross-spawn": { - "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/@lerna/add/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/child-process/node_modules/execa": { - "version": "5.1.1", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/@lerna/add/node_modules/npm-package-arg": { + "version": "8.1.1", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", "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" + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/@lerna/child-process/node_modules/get-stream": { - "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/@lerna/add/node_modules/npm-pick-manifest": { + "version": "7.0.2", + "integrity": "sha512-gk37SyRmlIjvTfcYl6RzDbSmS9Y4TOBXfsPnoYqTHARNgWbyDiCSMLUpmALDj4jjcTZpURiEfsSHJj9k7EV4Rw==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^2.0.0", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/child-process/node_modules/human-signals": { - "version": "2.1.0", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/@lerna/add/node_modules/npm-pick-manifest/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, "engines": { - "node": ">=10.17.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/child-process/node_modules/is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/@lerna/add/node_modules/npm-pick-manifest/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/@lerna/child-process/node_modules/npm-run-path": { - "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/@lerna/add/node_modules/npm-pick-manifest/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/child-process/node_modules/path-key": { - "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/@lerna/add/node_modules/npm-pick-manifest/node_modules/validate-npm-package-name": { + "version": "4.0.0", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/child-process/node_modules/shebang-command": { - "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/@lerna/add/node_modules/npm-registry-fetch": { + "version": "13.3.1", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", "dev": true, "dependencies": { - "shebang-regex": "^3.0.0" + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/child-process/node_modules/shebang-regex": { - "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/@lerna/add/node_modules/npm-registry-fetch/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/child-process/node_modules/which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/@lerna/add/node_modules/npm-registry-fetch/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, "engines": { - "node": ">= 8" + "node": ">=12" } }, - "node_modules/@lerna/clean": { - "version": "4.0.0", - "integrity": "sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA==", + "node_modules/@lerna/add/node_modules/npm-registry-fetch/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, "dependencies": { - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/prompt": "4.0.0", - "@lerna/pulse-till-done": "4.0.0", - "@lerna/rimraf-dir": "4.0.0", - "p-map": "^4.0.0", - "p-map-series": "^2.1.0", - "p-waterfall": "^2.1.1" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/cli": { + "node_modules/@lerna/add/node_modules/npm-registry-fetch/node_modules/validate-npm-package-name": { "version": "4.0.0", - "integrity": "sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA==", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "@lerna/global-options": "4.0.0", - "dedent": "^0.7.0", - "npmlog": "^4.1.2", - "yargs": "^16.2.0" + "builtins": "^5.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/cli/node_modules/ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@lerna/add/node_modules/pacote": { + "version": "13.6.2", + "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", "dev": true, + "dependencies": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/cli/node_modules/cliui": { - "version": "7.0.4", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/@lerna/add/node_modules/pacote/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/cli/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/@lerna/add/node_modules/pacote/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@lerna/cli/node_modules/string-width": { - "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/@lerna/add/node_modules/pacote/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/cli/node_modules/strip-ansi": { - "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/@lerna/add/node_modules/pacote/node_modules/validate-npm-package-name": { + "version": "4.0.0", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "builtins": "^5.0.0" }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/cli/node_modules/wrap-ansi": { - "version": "7.0.0", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/@lerna/add/node_modules/proc-log": { + "version": "2.0.1", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/cli/node_modules/y18n": { - "version": "5.0.8", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "node_modules/@lerna/add/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, "engines": { "node": ">=10" } }, - "node_modules/@lerna/cli/node_modules/yargs": { - "version": "16.2.0", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "node_modules/@lerna/add/node_modules/ssri": { + "version": "9.0.1", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", "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" + "minipass": "^3.1.1" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/cli/node_modules/yargs-parser": { - "version": "20.2.9", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "node_modules/@lerna/add/node_modules/unique-filename": { + "version": "2.0.1", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", "dev": true, + "dependencies": { + "unique-slug": "^3.0.0" + }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/collect-uncommitted": { - "version": "4.0.0", - "integrity": "sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g==", + "node_modules/@lerna/add/node_modules/unique-slug": { + "version": "3.0.0", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "chalk": "^4.1.0", - "npmlog": "^4.1.2" + "imurmurhash": "^0.1.4" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/collect-updates": { - "version": "4.0.0", - "integrity": "sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw==", - "dev": true, + "node_modules/@lerna/add/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "@lerna/describe-ref": "4.0.0", - "minimatch": "^3.0.4", - "npmlog": "^4.1.2", - "slash": "^3.0.0" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">= 10.18.0" - } - }, - "node_modules/@lerna/collect-updates/node_modules/slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/@lerna/command": { + "node_modules/@lerna/add/node_modules/yallist": { "version": "4.0.0", - "integrity": "sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A==", - "dev": true, - "dependencies": { - "@lerna/child-process": "4.0.0", - "@lerna/package-graph": "4.0.0", - "@lerna/project": "4.0.0", - "@lerna/validation-error": "4.0.0", - "@lerna/write-log-file": "4.0.0", - "clone-deep": "^4.0.1", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@lerna/bootstrap": { + "version": "6.1.0", + "integrity": "sha512-aDxKqgxexVj/Z0B1aPu7P1iPbPqhk1FPkl/iayCmPlkAh90pYEH0uVytGzi1hFB5iXEfG7Pa6azGQywUodx/1g==", + "dev": true, + "dependencies": { + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/has-npm-version": "6.1.0", + "@lerna/npm-install": "6.1.0", + "@lerna/package-graph": "6.1.0", + "@lerna/pulse-till-done": "6.1.0", + "@lerna/rimraf-dir": "6.1.0", + "@lerna/run-lifecycle": "6.1.0", + "@lerna/run-topologically": "6.1.0", + "@lerna/symlink-binary": "6.1.0", + "@lerna/symlink-dependencies": "6.1.0", + "@lerna/validation-error": "6.1.0", + "@npmcli/arborist": "5.3.0", "dedent": "^0.7.0", - "execa": "^5.0.0", - "is-ci": "^2.0.0", - "npmlog": "^4.1.2" + "get-port": "^5.1.1", + "multimatch": "^5.0.0", + "npm-package-arg": "8.1.1", + "npmlog": "^6.0.2", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0", + "p-waterfall": "^2.1.1", + "semver": "^7.3.4" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/command/node_modules/cross-spawn": { - "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "node_modules/@lerna/bootstrap/node_modules/@npmcli/arborist": { + "version": "5.3.0", + "integrity": "sha512-+rZ9zgL1lnbl8Xbb1NQdMjveOMwj4lIYfcDtyJHHi5x4X8jtR6m8SXooJMZy5vmFVZ8w7A2Bnd/oX9eTuU8w5A==", + "dev": true, + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/map-workspaces": "^2.0.3", + "@npmcli/metavuln-calculator": "^3.0.1", + "@npmcli/move-file": "^2.0.0", + "@npmcli/name-from-folder": "^1.0.1", + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/package-json": "^2.0.0", + "@npmcli/run-script": "^4.1.3", + "bin-links": "^3.0.0", + "cacache": "^16.0.6", + "common-ancestor-path": "^1.0.1", + "json-parse-even-better-errors": "^2.3.1", + "json-stringify-nice": "^1.1.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "nopt": "^5.0.0", + "npm-install-checks": "^5.0.0", + "npm-package-arg": "^9.0.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.0", + "npmlog": "^6.0.2", + "pacote": "^13.6.1", + "parse-conflict-json": "^2.0.1", + "proc-log": "^2.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.1", + "read-package-json-fast": "^2.0.2", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^9.0.0", + "treeverse": "^2.0.0", + "walk-up-path": "^1.0.0" + }, + "bin": { + "arborist": "bin/index.js" }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/command/node_modules/execa": { - "version": "5.1.1", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/arborist/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "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" + "lru-cache": "^7.5.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/command/node_modules/get-stream": { - "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/arborist/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@lerna/command/node_modules/human-signals": { - "version": "2.1.0", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/@lerna/command/node_modules/is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/command/node_modules/npm-run-path": { - "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/arborist/node_modules/validate-npm-package-name": { + "version": "4.0.0", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "builtins": "^5.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/@lerna/command/node_modules/path-key": { - "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/command/node_modules/shebang-command": { - "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/fs": { + "version": "2.1.2", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", "dev": true, "dependencies": { - "shebang-regex": "^3.0.0" + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" }, "engines": { - "node": ">=8" - } - }, - "node_modules/@lerna/command/node_modules/shebang-regex": { - "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/command/node_modules/which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/git": { + "version": "3.0.2", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", "dev": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/conventional-commits": { - "version": "4.0.0", - "integrity": "sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/metavuln-calculator": { + "version": "3.1.1", + "integrity": "sha512-n69ygIaqAedecLeVH3KnO39M6ZHiJ2dEv5A7DGvcqCB8q17BGUgW8QaanIkbWUo2aYGZqJaOORTLAlIvKjNDKA==", "dev": true, "dependencies": { - "@lerna/validation-error": "4.0.0", - "conventional-changelog-angular": "^5.0.12", - "conventional-changelog-core": "^4.2.2", - "conventional-recommended-bump": "^6.1.0", - "fs-extra": "^9.1.0", - "get-stream": "^6.0.0", - "lodash.template": "^4.5.0", - "npm-package-arg": "^8.1.0", - "npmlog": "^4.1.2", - "pify": "^5.0.0", - "semver": "^7.3.4" + "cacache": "^16.0.0", + "json-parse-even-better-errors": "^2.3.1", + "pacote": "^13.0.3", + "semver": "^7.3.5" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/conventional-commits/node_modules/fs-extra": { - "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/move-file": { + "version": "2.0.1", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/conventional-commits/node_modules/get-stream": { - "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/conventional-commits/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/package-json": { + "version": "2.0.0", + "integrity": "sha512-42jnZ6yl16GzjWSH7vtrmWyJDGVa/LXPdpN2rcUWolFjc9ON2N3uz0qdBbQACfmhuJZ2lbKYtmK5qx68ZPLHMA==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "json-parse-even-better-errors": "^2.3.1" }, "engines": { - "node": ">=10" - } - }, - "node_modules/@lerna/conventional-commits/node_modules/pify": { - "version": "5.0.0", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/conventional-commits/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/promise-spawn": { + "version": "3.0.0", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "infer-owner": "^1.0.4" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/conventional-commits/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@lerna/create": { - "version": "4.0.0", - "integrity": "sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag==", + "node_modules/@lerna/bootstrap/node_modules/@npmcli/run-script": { + "version": "4.2.1", + "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/npm-conf": "4.0.0", - "@lerna/validation-error": "4.0.0", - "dedent": "^0.7.0", - "fs-extra": "^9.1.0", - "globby": "^11.0.2", - "init-package-json": "^2.0.2", - "npm-package-arg": "^8.1.0", - "p-reduce": "^2.1.0", - "pacote": "^11.2.6", - "pify": "^5.0.0", - "semver": "^7.3.4", - "slash": "^3.0.0", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^3.0.0", - "whatwg-url": "^8.4.0", - "yargs-parser": "20.2.4" + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/create-symlink": { - "version": "4.0.0", - "integrity": "sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig==", + "node_modules/@lerna/bootstrap/node_modules/bin-links": { + "version": "3.0.3", + "integrity": "sha512-zKdnMPWEdh4F5INR07/eBrodC7QrF5JKvqskjz/ZZRXg5YSAZIbn8zGhbhUrElzHBZ2fvEQdOU59RHcTG3GiwA==", "dev": true, "dependencies": { - "cmd-shim": "^4.1.0", - "fs-extra": "^9.1.0", - "npmlog": "^4.1.2" + "cmd-shim": "^5.0.0", + "mkdirp-infer-owner": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0", + "read-cmd-shim": "^3.0.0", + "rimraf": "^3.0.0", + "write-file-atomic": "^4.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/create-symlink/node_modules/fs-extra": { - "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@lerna/bootstrap/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" + "balanced-match": "^1.0.0" } }, - "node_modules/@lerna/create/node_modules/@npmcli/run-script": { - "version": "1.8.6", - "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "node_modules/@lerna/bootstrap/node_modules/builtins": { + "version": "5.0.1", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", "dev": true, "dependencies": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^7.1.0", - "read-package-json-fast": "^2.0.1" + "semver": "^7.0.0" } }, - "node_modules/@lerna/create/node_modules/cacache": { - "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "node_modules/@lerna/bootstrap/node_modules/cacache": { + "version": "16.1.3", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", "dev": true, "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", + "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.0.2", - "unique-filename": "^1.1.1" + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" }, "engines": { - "node": ">= 10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/create/node_modules/chownr": { + "node_modules/@lerna/bootstrap/node_modules/chownr": { "version": "2.0.0", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, @@ -7077,846 +7089,846 @@ "node": ">=10" } }, - "node_modules/@lerna/create/node_modules/fs-extra": { - "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@lerna/bootstrap/node_modules/cmd-shim": { + "version": "5.0.0", + "integrity": "sha512-qkCtZ59BidfEwHltnJwkyVZn+XQojdAySM1D1gSeh11Z4pW1Kpolkyo53L5noc0nrxmIvyFwTmJRo4xs7FFLPw==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "mkdirp-infer-owner": "^2.0.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/create/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@lerna/bootstrap/node_modules/glob": { + "version": "8.0.3", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/@lerna/create/node_modules/mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" + "node": ">=12" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@lerna/create/node_modules/node-gyp": { - "version": "7.1.2", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "node_modules/@lerna/bootstrap/node_modules/hosted-git-info": { + "version": "3.0.8", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", "dev": true, "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" + "lru-cache": "^6.0.0" }, "engines": { - "node": ">= 10.12.0" + "node": ">=10" } }, - "node_modules/@lerna/create/node_modules/pacote": { - "version": "11.3.5", - "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "node_modules/@lerna/bootstrap/node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.8.2", - "cacache": "^15.0.5", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^11.0.0", - "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" - }, - "bin": { - "pacote": "lib/bin.js" + "yallist": "^4.0.0" }, "engines": { "node": ">=10" } }, - "node_modules/@lerna/create/node_modules/pify": { - "version": "5.0.0", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "node_modules/@lerna/bootstrap/node_modules/just-diff": { + "version": "5.2.0", + "integrity": "sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw==", + "dev": true + }, + "node_modules/@lerna/bootstrap/node_modules/just-diff-apply": { + "version": "5.5.0", + "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", + "dev": true + }, + "node_modules/@lerna/bootstrap/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/@lerna/create/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/bootstrap/node_modules/minimatch": { + "version": "5.1.2", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" } }, - "node_modules/@lerna/create/node_modules/slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/@lerna/bootstrap/node_modules/minipass-fetch": { + "version": "2.1.2", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" } }, - "node_modules/@lerna/create/node_modules/ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "node_modules/@lerna/bootstrap/node_modules/mkdirp": { + "version": "1.0.4", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "dependencies": { - "minipass": "^3.1.1" + "bin": { + "mkdirp": "bin/cmd.js" }, "engines": { - "node": ">= 8" + "node": ">=10" } }, - "node_modules/@lerna/create/node_modules/tr46": { - "version": "2.1.0", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "node_modules/@lerna/bootstrap/node_modules/npm-install-checks": { + "version": "5.0.0", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", "dev": true, "dependencies": { - "punycode": "^2.1.1" + "semver": "^7.1.1" }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/create/node_modules/webidl-conversions": { - "version": "6.1.0", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "node_modules/@lerna/bootstrap/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", "dev": true, "engines": { - "node": ">=10.4" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/create/node_modules/whatwg-url": { - "version": "8.7.0", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "node_modules/@lerna/bootstrap/node_modules/npm-package-arg": { + "version": "8.1.1", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", "dev": true, "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" }, "engines": { "node": ">=10" } }, - "node_modules/@lerna/create/node_modules/which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/@lerna/bootstrap/node_modules/npm-pick-manifest": { + "version": "7.0.2", + "integrity": "sha512-gk37SyRmlIjvTfcYl6RzDbSmS9Y4TOBXfsPnoYqTHARNgWbyDiCSMLUpmALDj4jjcTZpURiEfsSHJj9k7EV4Rw==", "dev": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^2.0.0", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/create/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@lerna/create/node_modules/yargs-parser": { - "version": "20.2.4", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "node_modules/@lerna/bootstrap/node_modules/npm-pick-manifest/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/describe-ref": { - "version": "4.0.0", - "integrity": "sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ==", + "node_modules/@lerna/bootstrap/node_modules/npm-pick-manifest/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "npmlog": "^4.1.2" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/diff": { + "node_modules/@lerna/bootstrap/node_modules/npm-pick-manifest/node_modules/validate-npm-package-name": { "version": "4.0.0", - "integrity": "sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag==", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/validation-error": "4.0.0", - "npmlog": "^4.1.2" + "builtins": "^5.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/exec": { - "version": "4.0.0", - "integrity": "sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw==", + "node_modules/@lerna/bootstrap/node_modules/npm-registry-fetch": { + "version": "13.3.1", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/profiler": "4.0.0", - "@lerna/run-topologically": "4.0.0", - "@lerna/validation-error": "4.0.0", - "p-map": "^4.0.0" + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/filter-options": { - "version": "4.0.0", - "integrity": "sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw==", + "node_modules/@lerna/bootstrap/node_modules/npm-registry-fetch/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, "dependencies": { - "@lerna/collect-updates": "4.0.0", - "@lerna/filter-packages": "4.0.0", - "dedent": "^0.7.0", - "npmlog": "^4.1.2" + "lru-cache": "^7.5.1" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/filter-packages": { - "version": "4.0.0", - "integrity": "sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA==", + "node_modules/@lerna/bootstrap/node_modules/npm-registry-fetch/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, "dependencies": { - "@lerna/validation-error": "4.0.0", - "multimatch": "^5.0.0", - "npmlog": "^4.1.2" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/get-npm-exec-opts": { + "node_modules/@lerna/bootstrap/node_modules/npm-registry-fetch/node_modules/validate-npm-package-name": { "version": "4.0.0", - "integrity": "sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ==", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "npmlog": "^4.1.2" + "builtins": "^5.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/get-packed": { - "version": "4.0.0", - "integrity": "sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w==", + "node_modules/@lerna/bootstrap/node_modules/pacote": { + "version": "13.6.2", + "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", "dev": true, "dependencies": { - "fs-extra": "^9.1.0", - "ssri": "^8.0.1", - "tar": "^6.1.0" + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/get-packed/node_modules/fs-extra": { - "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@lerna/bootstrap/node_modules/pacote/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "lru-cache": "^7.5.1" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/get-packed/node_modules/ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "node_modules/@lerna/bootstrap/node_modules/pacote/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, "dependencies": { - "minipass": "^3.1.1" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/github-client": { + "node_modules/@lerna/bootstrap/node_modules/pacote/node_modules/validate-npm-package-name": { "version": "4.0.0", - "integrity": "sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw==", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "@octokit/plugin-enterprise-rest": "^6.0.1", - "@octokit/rest": "^18.1.0", - "git-url-parse": "^11.4.4", - "npmlog": "^4.1.2" + "builtins": "^5.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/gitlab-client": { - "version": "4.0.0", - "integrity": "sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA==", + "node_modules/@lerna/bootstrap/node_modules/parse-conflict-json": { + "version": "2.0.2", + "integrity": "sha512-jDbRGb00TAPFsKWCpZZOT93SxVP9nONOSgES3AevqRq/CHvavEBvKAjxX9p5Y5F0RZLxH9Ufd9+RwtCsa+lFDA==", "dev": true, "dependencies": { - "node-fetch": "^2.6.1", - "npmlog": "^4.1.2", - "whatwg-url": "^8.4.0" + "json-parse-even-better-errors": "^2.3.1", + "just-diff": "^5.0.1", + "just-diff-apply": "^5.2.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/gitlab-client/node_modules/tr46": { - "version": "2.1.0", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "node_modules/@lerna/bootstrap/node_modules/proc-log": { + "version": "2.0.1", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/bootstrap/node_modules/read-cmd-shim": { + "version": "3.0.1", + "integrity": "sha512-kEmDUoYf/CDy8yZbLTmhB1X9kkjf9Q80PCNsDMb7ufrGd6zZSQA1+UyjrO+pZm5K/S4OXCWJeiIt1JA8kAsa6g==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/bootstrap/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { - "punycode": "^2.1.1" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/@lerna/gitlab-client/node_modules/webidl-conversions": { - "version": "6.1.0", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "node_modules/@lerna/bootstrap/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=10.4" + "node": ">=10" } }, - "node_modules/@lerna/gitlab-client/node_modules/whatwg-url": { - "version": "8.7.0", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "node_modules/@lerna/bootstrap/node_modules/ssri": { + "version": "9.0.1", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", "dev": true, "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "minipass": "^3.1.1" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/global-options": { - "version": "4.0.0", - "integrity": "sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ==", + "node_modules/@lerna/bootstrap/node_modules/treeverse": { + "version": "2.0.0", + "integrity": "sha512-N5gJCkLu1aXccpOTtqV6ddSEi6ZmGkh3hjmbu1IjcavJK4qyOVQmi0myQKM7z5jVGmD68SJoliaVrMmVObhj6A==", "dev": true, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/has-npm-version": { - "version": "4.0.0", - "integrity": "sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg==", + "node_modules/@lerna/bootstrap/node_modules/unique-filename": { + "version": "2.0.1", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "semver": "^7.3.4" + "unique-slug": "^3.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/has-npm-version/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@lerna/bootstrap/node_modules/unique-slug": { + "version": "3.0.0", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "imurmurhash": "^0.1.4" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/has-npm-version/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/bootstrap/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "isexe": "^2.0.0" }, "bin": { - "semver": "bin/semver.js" + "node-which": "bin/node-which" }, "engines": { - "node": ">=10" + "node": ">= 8" } }, - "node_modules/@lerna/has-npm-version/node_modules/yallist": { + "node_modules/@lerna/bootstrap/node_modules/write-file-atomic": { + "version": "4.0.2", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/bootstrap/node_modules/yallist": { "version": "4.0.0", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/@lerna/import": { - "version": "4.0.0", - "integrity": "sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg==", + "node_modules/@lerna/changed": { + "version": "6.1.0", + "integrity": "sha512-p7C2tf1scmvoUC1Osck/XIKVKXAQ8m8neL8/rfgKSYsvUVjsOB1LbF5HH1VUZntE6S4OxkRxUQGkAHVf5xrGqw==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/prompt": "4.0.0", - "@lerna/pulse-till-done": "4.0.0", - "@lerna/validation-error": "4.0.0", - "dedent": "^0.7.0", - "fs-extra": "^9.1.0", - "p-map-series": "^2.1.0" + "@lerna/collect-updates": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/listable": "6.1.0", + "@lerna/output": "6.1.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/import/node_modules/fs-extra": { - "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@lerna/check-working-tree": { + "version": "6.1.0", + "integrity": "sha512-hSciDmRqsNPevMhAD+SYbnhjatdb7UUu9W8vTyGtUXkrq2xtRZU0vAOgqovV8meirRkbC41pZePYKqyQtF0y3w==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@lerna/collect-uncommitted": "6.1.0", + "@lerna/describe-ref": "6.1.0", + "@lerna/validation-error": "6.1.0" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/info": { - "version": "4.0.0", - "integrity": "sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q==", + "node_modules/@lerna/child-process": { + "version": "6.1.0", + "integrity": "sha512-jhr3sCFeps6Y15SCrWEPvqE64i+QLOTSh+OzxlziCBf7ZEUu7sF0yA4n5bAqw8j43yCKhhjkf/ZLYxZe+pnl3Q==", "dev": true, "dependencies": { - "@lerna/command": "4.0.0", - "@lerna/output": "4.0.0", - "envinfo": "^7.7.4" + "chalk": "^4.1.0", + "execa": "^5.0.0", + "strong-log-transformer": "^2.1.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/init": { - "version": "4.0.0", - "integrity": "sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ==", + "node_modules/@lerna/child-process/node_modules/cross-spawn": { + "version": "7.0.3", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "@lerna/command": "4.0.0", - "fs-extra": "^9.1.0", - "p-map": "^4.0.0", - "write-json-file": "^4.3.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">= 10.18.0" + "node": ">= 8" } }, - "node_modules/@lerna/init/node_modules/fs-extra": { - "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@lerna/child-process/node_modules/execa": { + "version": "5.1.1", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "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/@lerna/link": { - "version": "4.0.0", - "integrity": "sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w==", + "node_modules/@lerna/child-process/node_modules/get-stream": { + "version": "6.0.1", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "dependencies": { - "@lerna/command": "4.0.0", - "@lerna/package-graph": "4.0.0", - "@lerna/symlink-dependencies": "4.0.0", - "p-map": "^4.0.0", - "slash": "^3.0.0" - }, "engines": { - "node": ">= 10.18.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@lerna/link/node_modules/slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/@lerna/child-process/node_modules/human-signals": { + "version": "2.1.0", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10.17.0" } }, - "node_modules/@lerna/list": { - "version": "4.0.0", - "integrity": "sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg==", + "node_modules/@lerna/child-process/node_modules/is-stream": { + "version": "2.0.1", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "dependencies": { - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/listable": "4.0.0", - "@lerna/output": "4.0.0" - }, "engines": { - "node": ">= 10.18.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@lerna/listable": { - "version": "4.0.0", - "integrity": "sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ==", + "node_modules/@lerna/child-process/node_modules/npm-run-path": { + "version": "4.0.1", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "@lerna/query-graph": "4.0.0", - "chalk": "^4.1.0", - "columnify": "^1.5.4" + "path-key": "^3.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": ">=8" } }, - "node_modules/@lerna/log-packed": { - "version": "4.0.0", - "integrity": "sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ==", + "node_modules/@lerna/child-process/node_modules/path-key": { + "version": "3.1.1", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "dependencies": { - "byte-size": "^7.0.0", - "columnify": "^1.5.4", - "has-unicode": "^2.0.1", - "npmlog": "^4.1.2" - }, "engines": { - "node": ">= 10.18.0" + "node": ">=8" } }, - "node_modules/@lerna/npm-conf": { - "version": "4.0.0", - "integrity": "sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw==", + "node_modules/@lerna/child-process/node_modules/shebang-command": { + "version": "2.0.0", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "dependencies": { - "config-chain": "^1.1.12", - "pify": "^5.0.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": ">=8" } }, - "node_modules/@lerna/npm-conf/node_modules/pify": { - "version": "5.0.0", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "node_modules/@lerna/child-process/node_modules/shebang-regex": { + "version": "3.0.0", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/@lerna/npm-dist-tag": { - "version": "4.0.0", - "integrity": "sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw==", + "node_modules/@lerna/child-process/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { - "@lerna/otplease": "4.0.0", - "npm-package-arg": "^8.1.0", - "npm-registry-fetch": "^9.0.0", - "npmlog": "^4.1.2" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">= 10.18.0" + "node": ">= 8" } }, - "node_modules/@lerna/npm-dist-tag/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@lerna/clean": { + "version": "6.1.0", + "integrity": "sha512-LRK2hiNUiBhPe5tmJiefOVpkaX2Yob0rp15IFNIbuteRWUJg0oERFQo62WvnxwElfzKSOhr8OGuEq/vN4bMrRA==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/prompt": "6.1.0", + "@lerna/pulse-till-done": "6.1.0", + "@lerna/rimraf-dir": "6.1.0", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0", + "p-waterfall": "^2.1.1" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/npm-dist-tag/node_modules/npm-registry-fetch": { - "version": "9.0.0", - "integrity": "sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==", + "node_modules/@lerna/cli": { + "version": "6.1.0", + "integrity": "sha512-p4G/OSPIrHiNkEl8bXrQdFOh4ORAZp2+ljvbXmAxpdf2qmopaUdr+bZYtIAxd+Z42SxRnDNz9IEyR0kOsARRQQ==", "dev": true, "dependencies": { - "@npmcli/ci-detect": "^1.0.0", - "lru-cache": "^6.0.0", - "make-fetch-happen": "^8.0.9", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "@lerna/global-options": "6.1.0", + "dedent": "^0.7.0", + "npmlog": "^6.0.2", + "yargs": "^16.2.0" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/npm-dist-tag/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "node_modules/@lerna/cli/node_modules/ansi-regex": { + "version": "5.0.1", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/@lerna/npm-install": { - "version": "4.0.0", - "integrity": "sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg==", + "node_modules/@lerna/cli/node_modules/cliui": { + "version": "7.0.4", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "@lerna/get-npm-exec-opts": "4.0.0", - "fs-extra": "^9.1.0", - "npm-package-arg": "^8.1.0", - "npmlog": "^4.1.2", - "signal-exit": "^3.0.3", - "write-pkg": "^4.0.0" - }, + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/@lerna/cli/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { - "node": ">= 10.18.0" + "node": ">=8" } }, - "node_modules/@lerna/npm-install/node_modules/fs-extra": { - "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@lerna/cli/node_modules/string-width": { + "version": "4.2.3", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/@lerna/npm-publish": { - "version": "4.0.0", - "integrity": "sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w==", + "node_modules/@lerna/cli/node_modules/strip-ansi": { + "version": "6.0.1", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "@lerna/otplease": "4.0.0", - "@lerna/run-lifecycle": "4.0.0", - "fs-extra": "^9.1.0", - "libnpmpublish": "^4.0.0", - "npm-package-arg": "^8.1.0", - "npmlog": "^4.1.2", - "pify": "^5.0.0", - "read-package-json": "^3.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">= 10.18.0" + "node": ">=8" } }, - "node_modules/@lerna/npm-publish/node_modules/fs-extra": { - "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@lerna/cli/node_modules/wrap-ansi": { + "version": "7.0.0", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@lerna/npm-publish/node_modules/pify": { - "version": "5.0.0", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "node_modules/@lerna/cli/node_modules/y18n": { + "version": "5.0.8", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@lerna/npm-run-script": { - "version": "4.0.0", - "integrity": "sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA==", + "node_modules/@lerna/cli/node_modules/yargs": { + "version": "16.2.0", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "dependencies": { - "@lerna/child-process": "4.0.0", - "@lerna/get-npm-exec-opts": "4.0.0", - "npmlog": "^4.1.2" + "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.18.0" + "node": ">=10" } }, - "node_modules/@lerna/otplease": { - "version": "4.0.0", - "integrity": "sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw==", + "node_modules/@lerna/cli/node_modules/yargs-parser": { + "version": "20.2.9", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, - "dependencies": { - "@lerna/prompt": "4.0.0" - }, "engines": { - "node": ">= 10.18.0" + "node": ">=10" } }, - "node_modules/@lerna/output": { - "version": "4.0.0", - "integrity": "sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w==", + "node_modules/@lerna/collect-uncommitted": { + "version": "6.1.0", + "integrity": "sha512-VvWvqDZG+OiF4PwV4Ro695r3+8ty4w+11Bnq8tbsbu5gq8qZiam8Fkc/TQLuNNqP0SPi4qmMPaIzWvSze3SmDg==", "dev": true, "dependencies": { - "npmlog": "^4.1.2" + "@lerna/child-process": "6.1.0", + "chalk": "^4.1.0", + "npmlog": "^6.0.2" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/pack-directory": { - "version": "4.0.0", - "integrity": "sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ==", + "node_modules/@lerna/collect-updates": { + "version": "6.1.0", + "integrity": "sha512-dgH7kgstwCXFctylQ4cxuCmhwSIE6VJZfHdh2bOaLuncs6ATMErKWN/mVuFHuUWEqPDRyy5Ky40Cu9S40nUq5w==", "dev": true, "dependencies": { - "@lerna/get-packed": "4.0.0", - "@lerna/package": "4.0.0", - "@lerna/run-lifecycle": "4.0.0", - "npm-packlist": "^2.1.4", - "npmlog": "^4.1.2", - "tar": "^6.1.0", - "temp-write": "^4.0.0" + "@lerna/child-process": "6.1.0", + "@lerna/describe-ref": "6.1.0", + "minimatch": "^3.0.4", + "npmlog": "^6.0.2", + "slash": "^3.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/package": { - "version": "4.0.0", - "integrity": "sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q==", + "node_modules/@lerna/collect-updates/node_modules/slash": { + "version": "3.0.0", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "load-json-file": "^6.2.0", - "npm-package-arg": "^8.1.0", - "write-pkg": "^4.0.0" - }, "engines": { - "node": ">= 10.18.0" + "node": ">=8" } }, - "node_modules/@lerna/package-graph": { - "version": "4.0.0", - "integrity": "sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw==", + "node_modules/@lerna/command": { + "version": "6.1.0", + "integrity": "sha512-OnMqBDaEBY0C8v9CXIWFbGGKgsiUtZrnKVvQRbupMSZDKMpVGWIUd3X98Is9j9MAmk1ynhBMWE9Fwai5ML/mcA==", "dev": true, "dependencies": { - "@lerna/prerelease-id-from-version": "4.0.0", - "@lerna/validation-error": "4.0.0", - "npm-package-arg": "^8.1.0", - "npmlog": "^4.1.2", - "semver": "^7.3.4" + "@lerna/child-process": "6.1.0", + "@lerna/package-graph": "6.1.0", + "@lerna/project": "6.1.0", + "@lerna/validation-error": "6.1.0", + "@lerna/write-log-file": "6.1.0", + "clone-deep": "^4.0.1", + "dedent": "^0.7.0", + "execa": "^5.0.0", + "is-ci": "^2.0.0", + "npmlog": "^6.0.2" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/package-graph/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@lerna/command/node_modules/cross-spawn": { + "version": "7.0.3", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">= 8" } }, - "node_modules/@lerna/package-graph/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/command/node_modules/execa": { + "version": "5.1.1", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "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/@lerna/package-graph/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@lerna/package/node_modules/load-json-file": { - "version": "6.2.0", - "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "node_modules/@lerna/command/node_modules/get-stream": { + "version": "6.0.1", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "parse-json": "^5.0.0", - "strip-bom": "^4.0.0", - "type-fest": "^0.6.0" + "engines": { + "node": ">=10" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/command/node_modules/human-signals": { + "version": "2.1.0", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=10.17.0" } }, - "node_modules/@lerna/package/node_modules/parse-json": { - "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/@lerna/command/node_modules/is-stream": { + "version": "2.0.1", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, "engines": { "node": ">=8" }, @@ -7924,77 +7936,79 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@lerna/package/node_modules/strip-bom": { - "version": "4.0.0", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "node_modules/@lerna/command/node_modules/npm-run-path": { + "version": "4.0.1", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/@lerna/package/node_modules/type-fest": { - "version": "0.6.0", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "node_modules/@lerna/command/node_modules/path-key": { + "version": "3.1.1", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/@lerna/prerelease-id-from-version": { - "version": "4.0.0", - "integrity": "sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg==", + "node_modules/@lerna/command/node_modules/shebang-command": { + "version": "2.0.0", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "dependencies": { - "semver": "^7.3.4" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": ">=8" } }, - "node_modules/@lerna/prerelease-id-from-version/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@lerna/command/node_modules/shebang-regex": { + "version": "3.0.0", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/@lerna/prerelease-id-from-version/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/command/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "isexe": "^2.0.0" }, "bin": { - "semver": "bin/semver.js" + "node-which": "bin/node-which" }, "engines": { - "node": ">=10" + "node": ">= 8" } }, - "node_modules/@lerna/prerelease-id-from-version/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@lerna/profiler": { - "version": "4.0.0", - "integrity": "sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q==", + "node_modules/@lerna/conventional-commits": { + "version": "6.1.0", + "integrity": "sha512-Tipo3cVr8mNVca4btzrCIzct59ZJWERT8/ZCZ/TQWuI4huUJZs6LRofLtB0xsGJAVZ7Vz2WRXAeH4XYgeUxutQ==", "dev": true, "dependencies": { + "@lerna/validation-error": "6.1.0", + "conventional-changelog-angular": "^5.0.12", + "conventional-changelog-core": "^4.2.4", + "conventional-recommended-bump": "^6.1.0", "fs-extra": "^9.1.0", - "npmlog": "^4.1.2", - "upath": "^2.0.1" + "get-stream": "^6.0.0", + "npm-package-arg": "8.1.1", + "npmlog": "^6.0.2", + "pify": "^5.0.0", + "semver": "^7.3.4" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/profiler/node_modules/fs-extra": { + "node_modules/@lerna/conventional-commits/node_modules/fs-extra": { "version": "9.1.0", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, @@ -8008,206 +8022,285 @@ "node": ">=10" } }, - "node_modules/@lerna/profiler/node_modules/upath": { - "version": "2.0.1", - "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "node_modules/@lerna/conventional-commits/node_modules/get-stream": { + "version": "6.0.1", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "engines": { - "node": ">=4", - "yarn": "*" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@lerna/project": { - "version": "4.0.0", - "integrity": "sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg==", + "node_modules/@lerna/conventional-commits/node_modules/hosted-git-info": { + "version": "3.0.8", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", "dev": true, "dependencies": { - "@lerna/package": "4.0.0", - "@lerna/validation-error": "4.0.0", - "cosmiconfig": "^7.0.0", - "dedent": "^0.7.0", - "dot-prop": "^6.0.1", - "glob-parent": "^5.1.1", - "globby": "^11.0.2", - "load-json-file": "^6.2.0", - "npmlog": "^4.1.2", - "p-map": "^4.0.0", - "resolve-from": "^5.0.0", - "write-json-file": "^4.3.0" + "lru-cache": "^6.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": ">=10" } }, - "node_modules/@lerna/project/node_modules/load-json-file": { - "version": "6.2.0", - "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "node_modules/@lerna/conventional-commits/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.15", - "parse-json": "^5.0.0", - "strip-bom": "^4.0.0", - "type-fest": "^0.6.0" + "yallist": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/@lerna/project/node_modules/parse-json": { - "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/@lerna/conventional-commits/node_modules/npm-package-arg": { + "version": "8.1.1", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10" } }, - "node_modules/@lerna/project/node_modules/resolve-from": { + "node_modules/@lerna/conventional-commits/node_modules/pify": { "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@lerna/project/node_modules/strip-bom": { - "version": "4.0.0", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "node_modules/@lerna/conventional-commits/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/@lerna/project/node_modules/type-fest": { - "version": "0.6.0", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "node_modules/@lerna/conventional-commits/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@lerna/create": { + "version": "6.1.0", + "integrity": "sha512-ZqlknXu0L29cV5mcfNgBLl+1RbKTWmNk8mj545zgXc7qQDgmrY+EVvrs8Cirey8C7bBpVkzP7Brzze0MSoB4rQ==", "dev": true, + "dependencies": { + "@lerna/child-process": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/npm-conf": "6.1.0", + "@lerna/validation-error": "6.1.0", + "dedent": "^0.7.0", + "fs-extra": "^9.1.0", + "init-package-json": "^3.0.2", + "npm-package-arg": "8.1.1", + "p-reduce": "^2.1.0", + "pacote": "^13.6.1", + "pify": "^5.0.0", + "semver": "^7.3.4", + "slash": "^3.0.0", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^4.0.0", + "yargs-parser": "20.2.4" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/prompt": { - "version": "4.0.0", - "integrity": "sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ==", + "node_modules/@lerna/create-symlink": { + "version": "6.1.0", + "integrity": "sha512-ulMa5OUJEwEWBHSgCUNGxrcsJllq1YMYWqhufvIigmMPJ0Zv3TV1Hha5i2MsqLJAakxtW0pNuwdutkUTtUdgxQ==", "dev": true, "dependencies": { - "inquirer": "^7.3.3", - "npmlog": "^4.1.2" + "cmd-shim": "^5.0.0", + "fs-extra": "^9.1.0", + "npmlog": "^6.0.2" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/publish": { - "version": "4.0.0", - "integrity": "sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg==", - "dev": true, - "dependencies": { - "@lerna/check-working-tree": "4.0.0", - "@lerna/child-process": "4.0.0", - "@lerna/collect-updates": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/describe-ref": "4.0.0", - "@lerna/log-packed": "4.0.0", - "@lerna/npm-conf": "4.0.0", - "@lerna/npm-dist-tag": "4.0.0", - "@lerna/npm-publish": "4.0.0", - "@lerna/otplease": "4.0.0", - "@lerna/output": "4.0.0", - "@lerna/pack-directory": "4.0.0", - "@lerna/prerelease-id-from-version": "4.0.0", - "@lerna/prompt": "4.0.0", - "@lerna/pulse-till-done": "4.0.0", - "@lerna/run-lifecycle": "4.0.0", - "@lerna/run-topologically": "4.0.0", - "@lerna/validation-error": "4.0.0", - "@lerna/version": "4.0.0", - "fs-extra": "^9.1.0", - "libnpmaccess": "^4.0.1", - "npm-package-arg": "^8.1.0", - "npm-registry-fetch": "^9.0.0", - "npmlog": "^4.1.2", - "p-map": "^4.0.0", - "p-pipe": "^3.1.0", - "pacote": "^11.2.6", - "semver": "^7.3.4" + "node_modules/@lerna/create-symlink/node_modules/cmd-shim": { + "version": "5.0.0", + "integrity": "sha512-qkCtZ59BidfEwHltnJwkyVZn+XQojdAySM1D1gSeh11Z4pW1Kpolkyo53L5noc0nrxmIvyFwTmJRo4xs7FFLPw==", + "dev": true, + "dependencies": { + "mkdirp-infer-owner": "^2.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/publish/node_modules/@npmcli/run-script": { - "version": "1.8.6", - "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "node_modules/@lerna/create-symlink/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "dependencies": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^7.1.0", - "read-package-json-fast": "^2.0.1" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@lerna/publish/node_modules/cacache": { - "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "node_modules/@lerna/create/node_modules/@npmcli/fs": { + "version": "2.1.2", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", "dev": true, "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/@npmcli/git": { + "version": "3.0.2", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@lerna/create/node_modules/@npmcli/move-file": { + "version": "2.0.1", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/@npmcli/promise-spawn": { + "version": "3.0.0", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "dependencies": { + "infer-owner": "^1.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/@npmcli/run-script": { + "version": "4.2.1", + "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@lerna/create/node_modules/cacache": { + "version": "16.1.3", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", + "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.0.2", - "unique-filename": "^1.1.1" + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" }, "engines": { - "node": ">= 10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/publish/node_modules/chownr": { - "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "node_modules/@lerna/create/node_modules/cacache/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/@lerna/publish/node_modules/debug": { - "version": "4.3.3", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "node_modules/@lerna/create/node_modules/chownr": { + "version": "2.0.0", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, - "dependencies": { - "ms": "2.1.2" - }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=10" } }, - "node_modules/@lerna/publish/node_modules/fs-extra": { + "node_modules/@lerna/create/node_modules/fs-extra": { "version": "9.1.0", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, @@ -8221,7 +8314,36 @@ "node": ">=10" } }, - "node_modules/@lerna/publish/node_modules/lru-cache": { + "node_modules/@lerna/create/node_modules/glob": { + "version": "8.0.3", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@lerna/create/node_modules/hosted-git-info": { + "version": "3.0.8", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/create/node_modules/lru-cache": { "version": "6.0.0", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, @@ -8232,7 +8354,34 @@ "node": ">=10" } }, - "node_modules/@lerna/publish/node_modules/mkdirp": { + "node_modules/@lerna/create/node_modules/minimatch": { + "version": "5.1.2", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/create/node_modules/minipass-fetch": { + "version": "2.1.2", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@lerna/create/node_modules/mkdirp": { "version": "1.0.4", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, @@ -8243,137 +8392,232 @@ "node": ">=10" } }, - "node_modules/@lerna/publish/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/@lerna/create/node_modules/npm-install-checks": { + "version": "5.0.0", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } }, - "node_modules/@lerna/publish/node_modules/negotiator": { - "version": "0.6.2", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "node_modules/@lerna/create/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", "dev": true, "engines": { - "node": ">= 0.6" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/publish/node_modules/node-gyp": { - "version": "7.1.2", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "node_modules/@lerna/create/node_modules/npm-package-arg": { + "version": "8.1.1", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", "dev": true, "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" }, - "bin": { - "node-gyp": "bin/node-gyp.js" + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/create/node_modules/npm-package-arg/node_modules/validate-npm-package-name": { + "version": "3.0.0", + "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", + "dev": true, + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/@lerna/create/node_modules/npm-pick-manifest": { + "version": "7.0.2", + "integrity": "sha512-gk37SyRmlIjvTfcYl6RzDbSmS9Y4TOBXfsPnoYqTHARNgWbyDiCSMLUpmALDj4jjcTZpURiEfsSHJj9k7EV4Rw==", + "dev": true, + "dependencies": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^2.0.0", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" }, "engines": { - "node": ">= 10.12.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/publish/node_modules/npm-registry-fetch": { - "version": "9.0.0", - "integrity": "sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==", + "node_modules/@lerna/create/node_modules/npm-pick-manifest/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, "dependencies": { - "@npmcli/ci-detect": "^1.0.0", - "lru-cache": "^6.0.0", - "make-fetch-happen": "^8.0.9", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/npm-pick-manifest/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@lerna/create/node_modules/npm-pick-manifest/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/npm-registry-fetch": { + "version": "13.3.1", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/publish/node_modules/pacote": { - "version": "11.3.5", - "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "node_modules/@lerna/create/node_modules/npm-registry-fetch/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, "dependencies": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.8.2", - "cacache": "^15.0.5", + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/npm-registry-fetch/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@lerna/create/node_modules/npm-registry-fetch/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/pacote": { + "version": "13.6.2", + "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", + "dev": true, + "dependencies": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", "chownr": "^2.0.0", "fs-minipass": "^2.1.0", "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^11.0.0", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" + "ssri": "^9.0.0", + "tar": "^6.1.11" }, "bin": { "pacote": "lib/bin.js" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/publish/node_modules/pacote/node_modules/make-fetch-happen": { - "version": "9.1.0", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "node_modules/@lerna/create/node_modules/pacote/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" + "lru-cache": "^7.5.1" }, "engines": { - "node": ">= 10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/publish/node_modules/pacote/node_modules/npm-registry-fetch": { - "version": "11.0.0", - "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "node_modules/@lerna/create/node_modules/pacote/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@lerna/create/node_modules/pacote/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, "dependencies": { - "make-fetch-happen": "^9.0.1", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/pify": { + "version": "5.0.0", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@lerna/publish/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/create/node_modules/proc-log": { + "version": "2.0.1", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/create/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -8385,209 +8629,188 @@ "node": ">=10" } }, - "node_modules/@lerna/publish/node_modules/socks-proxy-agent": { - "version": "6.1.1", - "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "node_modules/@lerna/create/node_modules/slash": { + "version": "3.0.0", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" - }, "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/@lerna/publish/node_modules/ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "node_modules/@lerna/create/node_modules/ssri": { + "version": "9.0.1", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", "dev": true, "dependencies": { "minipass": "^3.1.1" }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/publish/node_modules/which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/@lerna/create/node_modules/unique-filename": { + "version": "2.0.1", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", "dev": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "unique-slug": "^3.0.0" }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/publish/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@lerna/pulse-till-done": { - "version": "4.0.0", - "integrity": "sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg==", + "node_modules/@lerna/create/node_modules/unique-slug": { + "version": "3.0.0", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", "dev": true, "dependencies": { - "npmlog": "^4.1.2" + "imurmurhash": "^0.1.4" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/query-graph": { + "node_modules/@lerna/create/node_modules/validate-npm-package-name": { "version": "4.0.0", - "integrity": "sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg==", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "@lerna/package-graph": "4.0.0" + "builtins": "^5.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/resolve-symlink": { - "version": "4.0.0", - "integrity": "sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA==", + "node_modules/@lerna/create/node_modules/validate-npm-package-name/node_modules/builtins": { + "version": "5.0.1", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", "dev": true, "dependencies": { - "fs-extra": "^9.1.0", - "npmlog": "^4.1.2", - "read-cmd-shim": "^2.0.0" - }, - "engines": { - "node": ">= 10.18.0" + "semver": "^7.0.0" } }, - "node_modules/@lerna/resolve-symlink/node_modules/fs-extra": { - "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@lerna/create/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">=10" + "node": ">= 8" } }, - "node_modules/@lerna/rimraf-dir": { + "node_modules/@lerna/create/node_modules/yallist": { "version": "4.0.0", - "integrity": "sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg==", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@lerna/create/node_modules/yargs-parser": { + "version": "20.2.4", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", "dev": true, - "dependencies": { - "@lerna/child-process": "4.0.0", - "npmlog": "^4.1.2", - "path-exists": "^4.0.0", - "rimraf": "^3.0.2" - }, "engines": { - "node": ">= 10.18.0" + "node": ">=10" } }, - "node_modules/@lerna/rimraf-dir/node_modules/path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/@lerna/describe-ref": { + "version": "6.1.0", + "integrity": "sha512-0RQAYnxBaMz1SrEb/rhfR+8VeZx5tvCNYKRee5oXIDZdQ2c6/EPyrKCp3WcqiuOWY50SfGOVfxJEcxpK8Y3FNA==", "dev": true, + "dependencies": { + "@lerna/child-process": "6.1.0", + "npmlog": "^6.0.2" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/run": { - "version": "4.0.0", - "integrity": "sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ==", + "node_modules/@lerna/diff": { + "version": "6.1.0", + "integrity": "sha512-GhP+jPDbcp9QcAMSAjFn4lzM8MKpLR1yt5jll+zUD831U1sL0I5t8HUosFroe5MoRNffEL/jHuI3SbC3jjqWjQ==", "dev": true, "dependencies": { - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/npm-run-script": "4.0.0", - "@lerna/output": "4.0.0", - "@lerna/profiler": "4.0.0", - "@lerna/run-topologically": "4.0.0", - "@lerna/timer": "4.0.0", - "@lerna/validation-error": "4.0.0", - "p-map": "^4.0.0" + "@lerna/child-process": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/validation-error": "6.1.0", + "npmlog": "^6.0.2" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/run-lifecycle": { - "version": "4.0.0", - "integrity": "sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ==", + "node_modules/@lerna/exec": { + "version": "6.1.0", + "integrity": "sha512-Ej6WlPHXLF6hZHsfD+J/dxeuTrnc0HIfIXR1DU//msHW5RNCdi9+I7StwreCAQH/dLEsdBjPg5chNmuj2JLQRg==", "dev": true, "dependencies": { - "@lerna/npm-conf": "4.0.0", - "npm-lifecycle": "^3.1.5", - "npmlog": "^4.1.2" + "@lerna/child-process": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/profiler": "6.1.0", + "@lerna/run-topologically": "6.1.0", + "@lerna/validation-error": "6.1.0", + "p-map": "^4.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/run-topologically": { - "version": "4.0.0", - "integrity": "sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA==", + "node_modules/@lerna/filter-options": { + "version": "6.1.0", + "integrity": "sha512-kPf92Z7uLsR6MUiXnyXWebaUWArLa15wLfpfTwIp5H3MNk1lTbuG7QnrxE7OxQj+ozFmBvXeV9fuwfLsYTfmOw==", "dev": true, "dependencies": { - "@lerna/query-graph": "4.0.0", - "p-queue": "^6.6.2" + "@lerna/collect-updates": "6.1.0", + "@lerna/filter-packages": "6.1.0", + "dedent": "^0.7.0", + "npmlog": "^6.0.2" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/symlink-binary": { - "version": "4.0.0", - "integrity": "sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA==", + "node_modules/@lerna/filter-packages": { + "version": "6.1.0", + "integrity": "sha512-zW2avsZHs/ITE/37AEMhegGVHjiD0rgNk9bguNDfz6zaPa90UaW6PWDH6Tf4ThPRlbkl2Go48N3bFYHYSJKbcw==", "dev": true, "dependencies": { - "@lerna/create-symlink": "4.0.0", - "@lerna/package": "4.0.0", - "fs-extra": "^9.1.0", - "p-map": "^4.0.0" + "@lerna/validation-error": "6.1.0", + "multimatch": "^5.0.0", + "npmlog": "^6.0.2" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/symlink-binary/node_modules/fs-extra": { - "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@lerna/get-npm-exec-opts": { + "version": "6.1.0", + "integrity": "sha512-10Pdf+W0z7RT34o0SWlf+WVzz2/WbnTIJ1tQqXvXx6soj2L/xGLhOPvhJiKNtl4WlvUiO/zQ91yb83ESP4TZaA==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "npmlog": "^6.0.2" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/symlink-dependencies": { - "version": "4.0.0", - "integrity": "sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw==", + "node_modules/@lerna/get-packed": { + "version": "6.1.0", + "integrity": "sha512-lg0wPpV0wPekcD0mebJp619hMxsOgbZDOH5AkL/bCR217391eha0iPhQ0dU/G0Smd2vv6Cg443+J5QdI4LGRTg==", "dev": true, "dependencies": { - "@lerna/create-symlink": "4.0.0", - "@lerna/resolve-symlink": "4.0.0", - "@lerna/symlink-binary": "4.0.0", "fs-extra": "^9.1.0", - "p-map": "^4.0.0", - "p-map-series": "^2.1.0" + "ssri": "^9.0.1", + "tar": "^6.1.0" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/symlink-dependencies/node_modules/fs-extra": { + "node_modules/@lerna/get-packed/node_modules/fs-extra": { "version": "9.1.0", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, @@ -8601,909 +8824,829 @@ "node": ">=10" } }, - "node_modules/@lerna/timer": { - "version": "4.0.0", - "integrity": "sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg==", + "node_modules/@lerna/get-packed/node_modules/ssri": { + "version": "9.0.1", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, "engines": { - "node": ">= 10.18.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/validation-error": { - "version": "4.0.0", - "integrity": "sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw==", + "node_modules/@lerna/github-client": { + "version": "6.1.0", + "integrity": "sha512-+/4PtDgsjt0VRRZtOCN2Piyu0asU/16gSZZy/opVb8dlT44lTrH/ZghrJLE4tSL8Nuv688kx0kSgbUG8BY54jQ==", "dev": true, "dependencies": { - "npmlog": "^4.1.2" + "@lerna/child-process": "6.1.0", + "@octokit/plugin-enterprise-rest": "^6.0.1", + "@octokit/rest": "^19.0.3", + "git-url-parse": "^13.1.0", + "npmlog": "^6.0.2" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@lerna/version": { - "version": "4.0.0", - "integrity": "sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA==", - "dev": true, - "dependencies": { - "@lerna/check-working-tree": "4.0.0", - "@lerna/child-process": "4.0.0", - "@lerna/collect-updates": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/conventional-commits": "4.0.0", - "@lerna/github-client": "4.0.0", - "@lerna/gitlab-client": "4.0.0", - "@lerna/output": "4.0.0", - "@lerna/prerelease-id-from-version": "4.0.0", - "@lerna/prompt": "4.0.0", - "@lerna/run-lifecycle": "4.0.0", - "@lerna/run-topologically": "4.0.0", - "@lerna/validation-error": "4.0.0", - "chalk": "^4.1.0", - "dedent": "^0.7.0", - "load-json-file": "^6.2.0", - "minimatch": "^3.0.4", - "npmlog": "^4.1.2", - "p-map": "^4.0.0", - "p-pipe": "^3.1.0", - "p-reduce": "^2.1.0", - "p-waterfall": "^2.1.1", - "semver": "^7.3.4", - "slash": "^3.0.0", - "temp-write": "^4.0.0", - "write-json-file": "^4.3.0" + "node_modules/@lerna/github-client/node_modules/@octokit/auth-token": { + "version": "3.0.2", + "integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==", + "dev": true, + "dependencies": { + "@octokit/types": "^8.0.0" }, "engines": { - "node": ">= 10.18.0" + "node": ">= 14" } }, - "node_modules/@lerna/version/node_modules/load-json-file": { - "version": "6.2.0", - "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "node_modules/@lerna/github-client/node_modules/@octokit/core": { + "version": "4.1.0", + "integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.15", - "parse-json": "^5.0.0", - "strip-bom": "^4.0.0", - "type-fest": "^0.6.0" + "@octokit/auth-token": "^3.0.0", + "@octokit/graphql": "^5.0.0", + "@octokit/request": "^6.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^8.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">= 14" } }, - "node_modules/@lerna/version/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@lerna/github-client/node_modules/@octokit/endpoint": { + "version": "7.0.3", + "integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "@octokit/types": "^8.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" }, "engines": { - "node": ">=10" + "node": ">= 14" } }, - "node_modules/@lerna/version/node_modules/parse-json": { - "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/@lerna/github-client/node_modules/@octokit/graphql": { + "version": "5.0.4", + "integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "@octokit/request": "^6.0.0", + "@octokit/types": "^8.0.0", + "universal-user-agent": "^6.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 14" } }, - "node_modules/@lerna/version/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/github-client/node_modules/@octokit/openapi-types": { + "version": "14.0.0", + "integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==", + "dev": true + }, + "node_modules/@lerna/github-client/node_modules/@octokit/plugin-paginate-rest": { + "version": "5.0.1", + "integrity": "sha512-7A+rEkS70pH36Z6JivSlR7Zqepz3KVucEFVDnSrgHXzG7WLAzYwcHZbKdfTXHwuTHbkT1vKvz7dHl1+HNf6Qyw==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@octokit/types": "^8.0.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/@lerna/version/node_modules/slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">= 14" + }, + "peerDependencies": { + "@octokit/core": ">=4" } }, - "node_modules/@lerna/version/node_modules/strip-bom": { - "version": "4.0.0", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "node_modules/@lerna/github-client/node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "6.7.0", + "integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==", "dev": true, + "dependencies": { + "@octokit/types": "^8.0.0", + "deprecation": "^2.3.1" + }, "engines": { - "node": ">=8" + "node": ">= 14" + }, + "peerDependencies": { + "@octokit/core": ">=3" } }, - "node_modules/@lerna/version/node_modules/type-fest": { - "version": "0.6.0", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "node_modules/@lerna/github-client/node_modules/@octokit/request": { + "version": "6.2.2", + "integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==", "dev": true, + "dependencies": { + "@octokit/endpoint": "^7.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^8.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 14" } }, - "node_modules/@lerna/version/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@lerna/write-log-file": { - "version": "4.0.0", - "integrity": "sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg==", + "node_modules/@lerna/github-client/node_modules/@octokit/rest": { + "version": "19.0.5", + "integrity": "sha512-+4qdrUFq2lk7Va+Qff3ofREQWGBeoTKNqlJO+FGjFP35ZahP+nBenhZiGdu8USSgmq4Ky3IJ/i4u0xbLqHaeow==", "dev": true, "dependencies": { - "npmlog": "^4.1.2", - "write-file-atomic": "^3.0.3" + "@octokit/core": "^4.1.0", + "@octokit/plugin-paginate-rest": "^5.0.0", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^6.7.0" }, "engines": { - "node": ">= 10.18.0" + "node": ">= 14" } }, - "node_modules/@loaders.gl/3d-tiles": { - "version": "3.0.8", - "integrity": "sha512-jZeOyDPGD2wEkTLW4Do9A4UUQ+OGjhhNXztB0AsttZ69OpkmsxJXb76xxwevf+eThrsTgSTjZ06eC5DHX0kyXA==", + "node_modules/@lerna/github-client/node_modules/@octokit/types": { + "version": "8.0.0", + "integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==", + "dev": true, "dependencies": { - "@loaders.gl/core": "3.0.8", - "@loaders.gl/draco": "3.0.8", - "@loaders.gl/gltf": "3.0.8", - "@loaders.gl/loader-utils": "3.0.8", - "@loaders.gl/math": "3.0.8", - "@loaders.gl/tiles": "3.0.8", - "@math.gl/core": "^3.5.1", - "@math.gl/geospatial": "^3.5.1" + "@octokit/openapi-types": "^14.0.0" } }, - "node_modules/@loaders.gl/core": { - "version": "3.0.8", - "integrity": "sha512-FIfbhMkoRX2JonEHXHgClC7jwOSsEwvvmjlaTMRAY+gFKvJPGmegkp4VgUZquLFf6GedJt/1TuMMvAX6gdq1pg==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "@loaders.gl/loader-utils": "3.0.8", - "@loaders.gl/worker-utils": "3.0.8", - "probe.gl": "^3.4.0" + "node_modules/@lerna/github-client/node_modules/is-plain-object": { + "version": "5.0.0", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@loaders.gl/draco": { - "version": "3.0.8", - "integrity": "sha512-ZCXzXNHWQ7H0qk/kC+rWzjMWjLzZGzQcDbdpIuy8xJdp4rTpmMkLUseFPby8vhkmIaqxWPwPB6mx/vM7L6JENg==", + "node_modules/@lerna/gitlab-client": { + "version": "6.1.0", + "integrity": "sha512-fUI/ppXzxJafN9ceSl+FDgsYvu3iTsO6UW0WTD63pS32CfM+PiCryLQHzuc4RkyVW8WQH3aCR/GbaKCqbu52bw==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.3.1", - "@loaders.gl/loader-utils": "3.0.8", - "@loaders.gl/schema": "3.0.8", - "@loaders.gl/worker-utils": "3.0.8", - "draco3d": "1.4.1" + "node-fetch": "^2.6.1", + "npmlog": "^6.0.2" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@loaders.gl/gis": { - "version": "3.0.8", - "integrity": "sha512-7NL+lIb7NezlMupYskVil6M3RZunXJl+TyaVAW82GLbzPSOq+m/G7h3+z0GBa8iv/U/I+cB5BhSN+GZmvFwqEA==", - "dependencies": { - "@loaders.gl/loader-utils": "3.0.8", - "@loaders.gl/schema": "3.0.8", - "@mapbox/vector-tile": "^1.3.1", - "pbf": "^3.2.1" + "node_modules/@lerna/global-options": { + "version": "6.1.0", + "integrity": "sha512-1OyJ/N1XJh3ZAy8S20c6th9C4yBm/k3bRIdC+z0XxpDaHwfNt8mT9kUIDt6AIFCUvVKjSwnIsMHwhzXqBnwYSA==", + "dev": true, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@loaders.gl/gltf": { - "version": "3.0.8", - "integrity": "sha512-4PXWTlqyvlbZE2Vp4iQ+Y87ZO1WuRvSlbImDhygd0hoINfmJ9ObxrFS3yJcpJTu007nWxXorNVEOKyuoo+4Iyw==", + "node_modules/@lerna/has-npm-version": { + "version": "6.1.0", + "integrity": "sha512-up5PVuP6BmKQ5/UgH/t2c5B1q4HhjwW3/bqbNayX6V0qNz8OijnMYvEUbxFk8fOdeN41qVnhAk0Tb5kbdtYh2A==", + "dev": true, "dependencies": { - "@loaders.gl/core": "3.0.8", - "@loaders.gl/draco": "3.0.8", - "@loaders.gl/images": "3.0.8", - "@loaders.gl/loader-utils": "3.0.8" + "@lerna/child-process": "6.1.0", + "semver": "^7.3.4" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@loaders.gl/images": { - "version": "3.0.8", - "integrity": "sha512-rO2cIYJYlMs/uO9YSoF4/BEA4p/9xQ3gHZ1sIJkPYVnDqzpbu8nvUjWTQqIdL/MkQBTW8tz3twCdM+B6G9Fa2w==", + "node_modules/@lerna/has-npm-version/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { - "@loaders.gl/loader-utils": "3.0.8" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@loaders.gl/loader-utils": { - "version": "3.0.8", - "integrity": "sha512-PW1WyyQ+LXkqoGHBZHsmfNQkKiLAYf1gok+kHnHvY9fCzhJeA1iTNEUKPXGXKgS00m/k5cBTkOWAaOG9KRvBCQ==", + "node_modules/@lerna/has-npm-version/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.3.1", - "@loaders.gl/worker-utils": "3.0.8", - "@probe.gl/stats": "^3.4.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@loaders.gl/math": { - "version": "3.0.8", - "integrity": "sha512-jfFpxxr4Bq5JfOPqLVJc4JJGoGGvVTOCWiJhnTtSAKhaNSwldmNWaZ0w8E2nlgPKPMAHiTRKOQnd9sSY5m66Cw==", - "dependencies": { - "@loaders.gl/images": "3.0.8", - "@loaders.gl/loader-utils": "3.0.8", - "@math.gl/core": "^3.5.1" - } + "node_modules/@lerna/has-npm-version/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, - "node_modules/@loaders.gl/mvt": { - "version": "3.0.8", - "integrity": "sha512-Jk1QTHgpxMsUT01w5IJJ2en9qq0yOZcL2wGXVc7CFp2h6inB22rC3drUwq1mUNGe6iy3EWIo7EeJVd9B+5JyTQ==", + "node_modules/@lerna/import": { + "version": "6.1.0", + "integrity": "sha512-xsBhiKLUavATR32dAFL+WFY0yuab0hsM1eztKtRKk4wy7lSyxRfA5EIUcNCsLXx2xaDOKoMncCTXgNcpeYuqcQ==", + "dev": true, "dependencies": { - "@loaders.gl/gis": "3.0.8", - "@loaders.gl/loader-utils": "3.0.8", - "@math.gl/polygon": "^3.5.1", - "pbf": "^3.2.1" + "@lerna/child-process": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/prompt": "6.1.0", + "@lerna/pulse-till-done": "6.1.0", + "@lerna/validation-error": "6.1.0", + "dedent": "^0.7.0", + "fs-extra": "^9.1.0", + "p-map-series": "^2.1.0" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@loaders.gl/schema": { - "version": "3.0.8", - "integrity": "sha512-yne5WE7fZZWFl2zF8fzDlYhPVJua6h6mTCSmlQ5pryaMXTZS9mfzXXIFWRL3kswqnQTu/QNFdyFj1mP0haF24w==", + "node_modules/@lerna/import/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, "dependencies": { - "@types/geojson": "^7946.0.7", - "apache-arrow": "^4.0.0", - "d3-dsv": "^1.2.0" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@loaders.gl/terrain": { - "version": "3.0.8", - "integrity": "sha512-MtOAYEB/xJB4CN4B0YNPkO4v1ZY332joxiOHQI1x37x4sWVAqOrKLr9jB42sZCB8aINi2WMWGiErtf9wh9L5Pg==", + "node_modules/@lerna/info": { + "version": "6.1.0", + "integrity": "sha512-CsrWdW/Wyb4kcvHSnrsm7KYWFvjUNItu+ryeyWBZJtWYQOv45jNmWix6j2L4/w1+mMlWMjsfLmBscg82UBrF5w==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.3.1", - "@loaders.gl/loader-utils": "3.0.8", - "@loaders.gl/schema": "3.0.8", - "@mapbox/martini": "^0.2.0" + "@lerna/command": "6.1.0", + "@lerna/output": "6.1.0", + "envinfo": "^7.7.4" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@loaders.gl/tiles": { - "version": "3.0.8", - "integrity": "sha512-Rc+yHFdQg2sYmcYkwvszukFWdm9EW354F9HUR7y/oauos6tsdo4YTj31zgytaYR63/EqWQ7kwI29/eePEcutzg==", + "node_modules/@lerna/init": { + "version": "6.1.0", + "integrity": "sha512-z8oUeVjn+FQYAtepAw6G47cGodLyBAyNoEjO3IsJjQLWE1yH3r83L2sjyD/EckgR3o2VTEzrKo4ArhxLp2mNmg==", + "dev": true, "dependencies": { - "@loaders.gl/core": "3.0.8", - "@loaders.gl/loader-utils": "3.0.8", - "@loaders.gl/math": "3.0.8", - "@math.gl/core": "^3.5.1", - "@math.gl/culling": "^3.5.1", - "@math.gl/geospatial": "^3.5.1", - "@math.gl/web-mercator": "^3.5.1", - "@probe.gl/stats": "^3.4.0" + "@lerna/child-process": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/project": "6.1.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0", + "write-json-file": "^4.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@loaders.gl/worker-utils": { - "version": "3.0.8", - "integrity": "sha512-Pg72HuXPcL725TrOlOr83xloVUHj6OMWmno1dI8ccuqfOBsgoRjxNZrcSvwBzfK8tFCzuN2X30I+mHl3BkuYLw==", + "node_modules/@lerna/init/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.3.1" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@luma.gl/constants": { - "version": "8.5.4", - "integrity": "sha512-lrA4ja92om/gDHYOvM9itL5S7FVzjKulyknDz6S+Y7gmgHgXk2ln1Xar5zUCsLnhAYx4glHITXGH5Y5rdWgT1Q==" - }, - "node_modules/@luma.gl/core": { - "version": "8.5.4", - "integrity": "sha512-+saDz1D3mcPd53vgbG60ryg1w5CF9Z2wdakKHzR810VoJLw97t4aNdg/eNgyWOvbOHxaKJBPm8K0sGjej67+jw==", + "node_modules/@lerna/link": { + "version": "6.1.0", + "integrity": "sha512-7OD2lYNQHl6Kl1KYmplt8KoWjVHdiaqpYqwD38AwcB09YN58nGmo4aJgC12Fdx8DSNjkumgM0ROg/JOjMCTIzQ==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.0.0", - "@luma.gl/constants": "8.5.4", - "@luma.gl/engine": "8.5.4", - "@luma.gl/gltools": "8.5.4", - "@luma.gl/shadertools": "8.5.4", - "@luma.gl/webgl": "8.5.4" + "@lerna/command": "6.1.0", + "@lerna/package-graph": "6.1.0", + "@lerna/symlink-dependencies": "6.1.0", + "@lerna/validation-error": "6.1.0", + "p-map": "^4.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@luma.gl/engine": { - "version": "8.5.4", - "integrity": "sha512-Sfv972IzvR9s9kKWugs67XQUh9jC0e/PpBrzvyGVnPU4XvFq42RZVF73pzEklVU6AlpR8Zg5CPtxGdhyOHtT7w==", - "dependencies": { - "@babel/runtime": "^7.0.0", - "@luma.gl/constants": "8.5.4", - "@luma.gl/gltools": "8.5.4", - "@luma.gl/shadertools": "8.5.4", - "@luma.gl/webgl": "8.5.4", - "@math.gl/core": "^3.5.0", - "probe.gl": "^3.4.0" + "node_modules/@lerna/link/node_modules/slash": { + "version": "3.0.0", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" } }, - "node_modules/@luma.gl/experimental": { - "version": "8.5.4", - "integrity": "sha512-09waqRhgIrw+Sq0/in4tw4jPag5YsFfV1nEHJaLAg5RFv92S53IEubSJgkuG02HoOBkPxQ7KYvs9VNmriisnYg==", + "node_modules/@lerna/list": { + "version": "6.1.0", + "integrity": "sha512-7/g2hjizkvVnBGpVm+qC7lUFGhZ/0GIMUbGQwnE6yXDGm8yP9aEcNVkU4JGrDWW+uIklf9oodnMHaLXd/FJe6Q==", + "dev": true, "dependencies": { - "@luma.gl/constants": "8.5.4", - "@math.gl/core": "^3.5.0", - "earcut": "^2.0.6" + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/listable": "6.1.0", + "@lerna/output": "6.1.0" }, - "peerDependencies": { - "@loaders.gl/gltf": "^3.0.0", - "@loaders.gl/images": "^3.0.0", - "@luma.gl/engine": "^8.4.0", - "@luma.gl/gltools": "^8.4.0", - "@luma.gl/shadertools": "^8.4.0", - "@luma.gl/webgl": "^8.4.0" + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@luma.gl/gltools": { - "version": "8.5.4", - "integrity": "sha512-JotiPuymQz2Xc41AYlS2moJC/EHxU+OX/OMKi0+/MeOlEFLsdochgTA0I64j8yofLTXdeiGCneGtD1Ao8fk+bw==", + "node_modules/@lerna/listable": { + "version": "6.1.0", + "integrity": "sha512-3KZ9lQ9AtNfGNH/mYJYaMKCiF2EQvLLBGYkWHeIzIs6foegcZNXe0Cyv3LNXuo5WslMNr5RT4wIgy3BOoAxdtg==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.0.0", - "@luma.gl/constants": "8.5.4", - "probe.gl": "^3.4.0" + "@lerna/query-graph": "6.1.0", + "chalk": "^4.1.0", + "columnify": "^1.6.0" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@luma.gl/shadertools": { - "version": "8.5.4", - "integrity": "sha512-rwLBLrACi75aWnuJm8rVKCQnJR2sMTCxHuexfjHJ7Uecl0vVcVJZT7c9EnCFaz5LUTNbdupvuhq0SKNckKiKmw==", + "node_modules/@lerna/log-packed": { + "version": "6.1.0", + "integrity": "sha512-Sq2HZJAcPuoNeEHeIutcPYQCyWBxLyVGvEhgsP3xTe6XkBGQCG8piCp9wX+sc2zT+idPdpI6qLqdh85yYIMMhA==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.0.0", - "@math.gl/core": "^3.5.0" + "byte-size": "^7.0.0", + "columnify": "^1.6.0", + "has-unicode": "^2.0.1", + "npmlog": "^6.0.2" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@luma.gl/webgl": { - "version": "8.5.4", - "integrity": "sha512-dWy4dhTbtvDO9zQBdx1Yb+DxNx/1JWV9rhhJxJUtTKbGZSX0RjkASTT6GBWMl5jrH1JYJefS1wswHmmPVXjK0Q==", + "node_modules/@lerna/npm-conf": { + "version": "6.1.0", + "integrity": "sha512-+RD3mmJe9XSQj7Diibs0+UafAHPcrFCd29ODpDI+tzYl4MmYZblfrlL6mbSCiVYCZQneQ8Uku3P0r+DlbYBaFw==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.0.0", - "@luma.gl/constants": "8.5.4", - "@luma.gl/gltools": "8.5.4", - "probe.gl": "^3.4.0" + "config-chain": "^1.1.12", + "pify": "^5.0.0" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@mapbox/extent": { - "version": "0.4.0", - "integrity": "sha512-MSoKw3qPceGuupn04sdaJrFeLKvcSETVLZCGS8JA9x6zXQL3FWiKaIXYIZEDXd5jpXpWlRxinCZIN49yRy0C9A==" + "node_modules/@lerna/npm-conf/node_modules/pify": { + "version": "5.0.0", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@mapbox/geojson-area": { - "version": "0.2.2", - "integrity": "sha512-bBqqFn1kIbLBfn7Yq1PzzwVkPYQr9lVUeT8Dhd0NL5n76PBuXzOcuLV7GOSbEB1ia8qWxH4COCvFpziEu/yReA==", + "node_modules/@lerna/npm-dist-tag": { + "version": "6.1.0", + "integrity": "sha512-1zo+Yww/lvWJWZnEXpke9dZSb5poDzhUM/pQNqAQYSlbZ96o18SuCR6TEi5isMPiw63Aq1MMzbUqttQfJ11EOA==", + "dev": true, "dependencies": { - "wgs84": "0.0.0" + "@lerna/otplease": "6.1.0", + "npm-package-arg": "8.1.1", + "npm-registry-fetch": "^13.3.0", + "npmlog": "^6.0.2" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@mapbox/geojson-coords": { - "version": "0.0.2", - "integrity": "sha512-YuVzpseee/P1T5BWyeVVPppyfmuXYHFwZHmybkqaMfu4BWlOf2cmMGKj2Rr92MwfSTOCSUA0PAsVGRG8akY0rg==", + "node_modules/@lerna/npm-dist-tag/node_modules/builtins": { + "version": "5.0.1", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, "dependencies": { - "@mapbox/geojson-normalize": "0.0.1", - "geojson-flatten": "^1.0.4" + "semver": "^7.0.0" } }, - "node_modules/@mapbox/geojson-extent": { - "version": "1.0.1", - "integrity": "sha512-hh8LEO3djT4fqfr8sSC6wKt+p0TMiu+KOLMBUiFOyj+zGq7+IXwQGl0ppCVDkyzCewyd9LoGe9zAvDxXrLfhLw==", + "node_modules/@lerna/npm-dist-tag/node_modules/hosted-git-info": { + "version": "3.0.8", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, "dependencies": { - "@mapbox/extent": "0.4.0", - "@mapbox/geojson-coords": "0.0.2", - "rw": "~0.1.4", - "traverse": "~0.6.6" + "lru-cache": "^6.0.0" }, - "bin": { - "geojson-extent": "bin/geojson-extent" - } - }, - "node_modules/@mapbox/geojson-extent/node_modules/rw": { - "version": "0.1.4", - "integrity": "sha512-vSj3D96kMcjNyqPcp65wBRIDImGSrUuMxngNNxvw8MQaO+aQ6llzRPH7XcJy5zrpb3wU++045+Uz/IDIM684iw==" - }, - "node_modules/@mapbox/geojson-normalize": { - "version": "0.0.1", - "integrity": "sha512-82V7YHcle8lhgIGqEWwtXYN5cy0QM/OHq3ypGhQTbvHR57DF0vMHMjjVSQKFfVXBe/yWCBZTyOuzvK7DFFnx5Q==", - "bin": { - "geojson-normalize": "geojson-normalize" + "engines": { + "node": ">=10" } }, - "node_modules/@mapbox/geojson-rewind": { - "version": "0.4.1", - "integrity": "sha512-mxo2MEr7izA1uOXcDsw99Kgg6xW3P4H2j4n1lmldsgviIelpssvP+jQDivFKOHrOVJDpTTi5oZJvRcHtU9Uufw==", + "node_modules/@lerna/npm-dist-tag/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { - "@mapbox/geojson-area": "0.2.2", - "concat-stream": "~1.6.0", - "minimist": "^1.2.5", - "sharkdown": "^0.1.0" + "yallist": "^4.0.0" }, - "bin": { - "geojson-rewind": "geojson-rewind" - } - }, - "node_modules/@mapbox/geojson-types": { - "version": "1.0.2", - "integrity": "sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==" - }, - "node_modules/@mapbox/jsonlint-lines-primitives": { - "version": "2.0.2", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@mapbox/mapbox-gl-supported": { - "version": "1.5.0", - "integrity": "sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==", - "peerDependencies": { - "mapbox-gl": ">=0.32.1 <2.0.0" + "node": ">=10" } }, - "node_modules/@mapbox/martini": { - "version": "0.2.0", - "integrity": "sha512-7hFhtkb0KTLEls+TRw/rWayq5EeHtTaErgm/NskVoXmtgAQu/9D299aeyj6mzAR/6XUnYRp2lU+4IcrYRFjVsQ==" - }, - "node_modules/@mapbox/point-geometry": { - "version": "0.1.0", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" - }, - "node_modules/@mapbox/tiny-sdf": { - "version": "1.2.5", - "integrity": "sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==" - }, - "node_modules/@mapbox/unitbezier": { - "version": "0.0.0", - "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==" - }, - "node_modules/@mapbox/vector-tile": { - "version": "1.3.1", - "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "node_modules/@lerna/npm-dist-tag/node_modules/minipass-fetch": { + "version": "2.1.2", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, "dependencies": { - "@mapbox/point-geometry": "~0.1.0" - } - }, - "node_modules/@mapbox/whoots-js": { - "version": "3.1.0", - "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, "engines": { - "node": ">=6.0.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" } }, - "node_modules/@math.gl/core": { - "version": "3.5.3", - "integrity": "sha512-TaSnvG0qFh1VxeNW5L58jSx0nJUMWMpUl6zo6Z3ScQzFySG5cicGOBzk/D40RkIZWPazCKCZ+ZThg5npSK9y3g==", + "node_modules/@lerna/npm-dist-tag/node_modules/npm-package-arg": { + "version": "8.1.1", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.12.0", - "gl-matrix": "^3.0.0" + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@math.gl/culling": { - "version": "3.5.3", - "integrity": "sha512-ABpAcrvoIOLSm1EUkwgDem4RfO28HWPBs/+taZ/ZSpJG6KiVPklpKU1NCK+05HuJStkpFZ+XlWtehWU6FAMCyA==", + "node_modules/@lerna/npm-dist-tag/node_modules/npm-registry-fetch": { + "version": "13.3.1", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.12.0", - "@math.gl/core": "3.5.3", - "gl-matrix": "^3.0.0" + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@math.gl/geospatial": { - "version": "3.5.3", - "integrity": "sha512-cnc8VMQrt30JmlG200VDJmmvSjaGW57gY9KEZ+raapxyyFyfDNuAuIrIxe+zbK66FbvFWTbJlDaNmKqVG+ohyw==", + "node_modules/@lerna/npm-dist-tag/node_modules/npm-registry-fetch/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.12.0", - "@math.gl/core": "3.5.3", - "gl-matrix": "^3.0.0" + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@math.gl/polygon": { - "version": "3.5.3", - "integrity": "sha512-VktscmyQg/Rd56nJk0Nj/UyvnPDbsnZNMWCdl3G5AYenYzLWy6h4FEWhLx8pD+Xw7VuFot8LR4WAK2TPzXzrWw==", - "dependencies": { - "@math.gl/core": "3.5.3" + "node_modules/@lerna/npm-dist-tag/node_modules/npm-registry-fetch/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" } }, - "node_modules/@math.gl/web-mercator": { - "version": "3.5.6", - "integrity": "sha512-siWHLJGp9o8fDEM1t0Rby+JXftl6il0z3927liWGzkHqFftXPHY858ShPy45ThDU8q5lyCftg8aVgrv4nfD+Zw==", + "node_modules/@lerna/npm-dist-tag/node_modules/npm-registry-fetch/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.12.0", - "gl-matrix": "~3.3.0" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@mdx-js/loader": { - "version": "1.6.22", - "integrity": "sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q==", + "node_modules/@lerna/npm-dist-tag/node_modules/npm-registry-fetch/node_modules/validate-npm-package-name": { + "version": "4.0.0", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "@mdx-js/mdx": "1.6.22", - "@mdx-js/react": "1.6.22", - "loader-utils": "2.0.0" + "builtins": "^5.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@mdx-js/loader/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "node_modules/@lerna/npm-dist-tag/node_modules/proc-log": { + "version": "2.0.1", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", "dev": true, - "bin": { - "json5": "lib/cli.js" - }, "engines": { - "node": ">=6" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@mdx-js/loader/node_modules/loader-utils": { - "version": "2.0.0", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "node_modules/@lerna/npm-dist-tag/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8.9.0" + "node": ">=10" } }, - "node_modules/@mdx-js/mdx": { - "version": "1.6.22", - "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", - "dependencies": { - "@babel/core": "7.12.9", - "@babel/plugin-syntax-jsx": "7.12.1", - "@babel/plugin-syntax-object-rest-spread": "7.8.3", - "@mdx-js/util": "1.6.22", - "babel-plugin-apply-mdx-type-prop": "1.6.22", - "babel-plugin-extract-import-names": "1.6.22", - "camelcase-css": "2.0.1", - "detab": "2.0.4", - "hast-util-raw": "6.0.1", - "lodash.uniq": "4.5.0", - "mdast-util-to-hast": "10.0.1", - "remark-footnotes": "2.0.0", - "remark-mdx": "1.6.22", - "remark-parse": "8.0.3", - "remark-squeeze-paragraphs": "4.0.0", - "style-to-object": "0.3.0", - "unified": "9.2.0", - "unist-builder": "2.0.3", - "unist-util-visit": "2.0.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "node_modules/@lerna/npm-dist-tag/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, - "node_modules/@mdx-js/mdx/node_modules/@babel/core": { - "version": "7.12.9", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "node_modules/@lerna/npm-install": { + "version": "6.1.0", + "integrity": "sha512-1SHmOHZA1YJuUctLQBRjA2+yMp+UNYdOBsFb3xUVT7MjWnd1Zl0toT3jxGu96RNErD9JKkk/cGo/Aq+DU3s9pg==", + "dev": true, "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "@lerna/child-process": "6.1.0", + "@lerna/get-npm-exec-opts": "6.1.0", + "fs-extra": "^9.1.0", + "npm-package-arg": "8.1.1", + "npmlog": "^6.0.2", + "signal-exit": "^3.0.3", + "write-pkg": "^4.0.0" }, "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@mdx-js/mdx/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "node_modules/@lerna/npm-install/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=10" } }, - "node_modules/@mdx-js/mdx/node_modules/debug": { - "version": "4.3.4", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@lerna/npm-install/node_modules/hosted-git-info": { + "version": "3.0.8", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, "dependencies": { - "ms": "2.1.2" + "lru-cache": "^6.0.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=10" } }, - "node_modules/@mdx-js/mdx/node_modules/is-buffer": { - "version": "2.0.5", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/@lerna/npm-install/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/@mdx-js/mdx/node_modules/is-plain-obj": { - "version": "2.1.0", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "node_modules/@lerna/npm-install/node_modules/npm-package-arg": { + "version": "8.1.1", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/@mdx-js/mdx/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "node_modules/@lerna/npm-install/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "json5": "lib/cli.js" + "semver": "bin/semver.js" }, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/@mdx-js/mdx/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "node_modules/@lerna/npm-install/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, - "node_modules/@mdx-js/mdx/node_modules/parse-entities": { - "version": "2.0.0", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "node_modules/@lerna/npm-publish": { + "version": "6.1.0", + "integrity": "sha512-N0LdR1ImZQw1r4cYaKtVbBhBPtj4Zu9NbvygzizEP5HuTfxZmE1Ans3w93Kks9VTXZXob8twNbXnzBwzTyEpEA==", + "dev": true, "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" + "@lerna/otplease": "6.1.0", + "@lerna/run-lifecycle": "6.1.0", + "fs-extra": "^9.1.0", + "libnpmpublish": "^6.0.4", + "npm-package-arg": "8.1.1", + "npmlog": "^6.0.2", + "pify": "^5.0.0", + "read-package-json": "^5.0.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@mdx-js/mdx/node_modules/remark-parse": { - "version": "8.0.3", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", + "node_modules/@lerna/npm-publish/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, "dependencies": { - "ccount": "^1.0.0", - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^2.0.0", - "vfile-location": "^3.0.0", - "xtend": "^4.0.1" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" } }, - "node_modules/@mdx-js/mdx/node_modules/unified": { - "version": "9.2.0", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "node_modules/@lerna/npm-publish/node_modules/hosted-git-info": { + "version": "3.0.8", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" + "lru-cache": "^6.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/mdx/node_modules/unist-util-is": { - "version": "4.1.0", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" } }, - "node_modules/@mdx-js/mdx/node_modules/unist-util-remove-position": { - "version": "2.0.1", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", + "node_modules/@lerna/npm-publish/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { - "unist-util-visit": "^2.0.0" + "yallist": "^4.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" } }, - "node_modules/@mdx-js/mdx/node_modules/unist-util-stringify-position": { - "version": "2.0.3", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "node_modules/@lerna/npm-publish/node_modules/npm-package-arg": { + "version": "8.1.1", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", + "dev": true, "dependencies": { - "@types/unist": "^2.0.2" + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" } }, - "node_modules/@mdx-js/mdx/node_modules/unist-util-visit": { - "version": "2.0.3", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit-parents": "^3.0.0" + "node_modules/@lerna/npm-publish/node_modules/pify": { + "version": "5.0.0", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@mdx-js/mdx/node_modules/unist-util-visit-parents": { - "version": "3.1.1", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "node_modules/@lerna/npm-publish/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0" + "lru-cache": "^6.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mdx-js/mdx/node_modules/vfile": { - "version": "4.2.1", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" + "bin": { + "semver": "bin/semver.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=10" } }, - "node_modules/@mdx-js/mdx/node_modules/vfile-location": { - "version": "3.2.0", - "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "node_modules/@lerna/npm-publish/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, - "node_modules/@mdx-js/mdx/node_modules/vfile-message": { - "version": "2.0.4", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "node_modules/@lerna/npm-run-script": { + "version": "6.1.0", + "integrity": "sha512-7p13mvdxdY5+VqWvvtMsMDeyCRs0PrrTmSHRO+FKuLQuGhBvUo05vevcMEOQNDvEvl/tXPrOVbeGCiGubYTCLg==", + "dev": true, "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" + "@lerna/child-process": "6.1.0", + "@lerna/get-npm-exec-opts": "6.1.0", + "npmlog": "^6.0.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@mdx-js/react": { - "version": "1.6.22", - "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", + "node_modules/@lerna/otplease": { + "version": "6.1.0", + "integrity": "sha512-gqSE6IbaD4IeNJePkaDLaFLoGp0Ceu35sn7z0AHAOoHiQGGorOmvM+h1Md3xZZRSXQmY9LyJVhG5eRa38SoG4g==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0" - } - }, - "node_modules/@mdx-js/util": { - "version": "1.6.22", - "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dependencies": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" + "@lerna/prompt": "6.1.0" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@mrmlnc/readdir-enhanced/node_modules/glob-to-regexp": { - "version": "0.3.0", - "integrity": "sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==" - }, - "node_modules/@nicolo-ribaudo/chokidar-2": { - "version": "2.1.8-no-fsevents.3", - "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", + "node_modules/@lerna/output": { + "version": "6.1.0", + "integrity": "sha512-mgCIzLKIuroytXuxjTB689ERtpfgyNXW0rMv9WHOa6ufQc+QJPjh3L4jVsOA0l+/OxZyi97PUXotduNj+0cbnA==", "dev": true, - "optional": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.3", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", "dependencies": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" + "npmlog": "^6.0.2" }, "engines": { - "node": ">= 8" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@nodelib/fs.scandir/node_modules/@nodelib/fs.stat": { - "version": "2.0.3", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "node_modules/@lerna/pack-directory": { + "version": "6.1.0", + "integrity": "sha512-Xsixqm2nkGXs9hvq08ClbGpRlCYnlBV4TwSrLttIDL712RlyXoPe2maJzTUqo9OXBbOumFSahUEInCMT2OS05g==", + "dev": true, + "dependencies": { + "@lerna/get-packed": "6.1.0", + "@lerna/package": "6.1.0", + "@lerna/run-lifecycle": "6.1.0", + "@lerna/temp-write": "6.1.0", + "npm-packlist": "^5.1.1", + "npmlog": "^6.0.2", + "tar": "^6.1.0" + }, "engines": { - "node": ">= 8" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@lerna/package": { + "version": "6.1.0", + "integrity": "sha512-PyNFtdH2IcLasp/nyMDshmeXotriOSlhbeFIxhdl1XuGj5v1so3utMSOrJMO5kzZJQg5zyx8qQoxL+WH/hkrVQ==", + "dev": true, + "dependencies": { + "load-json-file": "^6.2.0", + "npm-package-arg": "8.1.1", + "write-pkg": "^4.0.0" + }, "engines": { - "node": ">= 8" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.4", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "node_modules/@lerna/package-graph": { + "version": "6.1.0", + "integrity": "sha512-yGyxd/eHTDjkpnBbDhTV0hwKF+i01qZc+6/ko65wOsh8xtgqpQeE6mtdgbvsLKcuMcIQ7PDy1ntyIv9phg14gQ==", + "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" + "@lerna/prerelease-id-from-version": "6.1.0", + "@lerna/validation-error": "6.1.0", + "npm-package-arg": "8.1.1", + "npmlog": "^6.0.2", + "semver": "^7.3.4" }, "engines": { - "node": ">= 8" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@npmcli/ci-detect": { - "version": "1.4.0", - "integrity": "sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q==", - "dev": true - }, - "node_modules/@npmcli/fs": { - "version": "1.0.0", - "integrity": "sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ==", + "node_modules/@lerna/package-graph/node_modules/hosted-git-info": { + "version": "3.0.8", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@npmcli/fs/node_modules/lru-cache": { + "node_modules/@lerna/package-graph/node_modules/lru-cache": { "version": "6.0.0", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -9511,9 +9654,23 @@ "node": ">=10" } }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/package-graph/node_modules/npm-package-arg": { + "version": "8.1.1", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/package-graph/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -9524,26 +9681,37 @@ "node": ">=10" } }, - "node_modules/@npmcli/fs/node_modules/yallist": { + "node_modules/@lerna/package-graph/node_modules/yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, - "node_modules/@npmcli/git": { - "version": "2.1.0", - "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", + "node_modules/@lerna/package/node_modules/hosted-git-info": { + "version": "3.0.8", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", "dev": true, "dependencies": { - "@npmcli/promise-spawn": "^1.3.2", - "lru-cache": "^6.0.0", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^6.1.1", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/package/node_modules/load-json-file": { + "version": "6.2.0", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@npmcli/git/node_modules/lru-cache": { + "node_modules/@lerna/package/node_modules/lru-cache": { "version": "6.0.0", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, @@ -9554,20 +9722,39 @@ "node": ">=10" } }, - "node_modules/@npmcli/git/node_modules/mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/@lerna/package/node_modules/npm-package-arg": { + "version": "8.1.1", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" + "dependencies": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" }, "engines": { "node": ">=10" } }, - "node_modules/@npmcli/git/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@lerna/package/node_modules/parse-json": { + "version": "5.2.0", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/package/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -9579,1430 +9766,4363 @@ "node": ">=10" } }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/@lerna/package/node_modules/strip-bom": { + "version": "4.0.0", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, "engines": { - "node": ">= 8" + "node": ">=8" + } + }, + "node_modules/@lerna/package/node_modules/type-fest": { + "version": "0.6.0", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" } }, - "node_modules/@npmcli/git/node_modules/yallist": { + "node_modules/@lerna/package/node_modules/yallist": { "version": "4.0.0", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/@npmcli/installed-package-contents": { - "version": "1.0.7", - "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "node_modules/@lerna/prerelease-id-from-version": { + "version": "6.1.0", + "integrity": "sha512-ngC4I6evvZztB6aOaSDEnhUgRTlqX3TyBXwWwLGTOXCPaCQBTPaLNokhmRdJ+ZVdZ4iHFbzEDSL07ubZrYUcmQ==", "dev": true, "dependencies": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "installed-package-contents": "index.js" + "semver": "^7.3.4" }, "engines": { - "node": ">= 10" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@npmcli/move-file": { - "version": "1.1.2", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", + "node_modules/@lerna/prerelease-id-from-version/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "yallist": "^4.0.0" }, "engines": { "node": ">=10" } }, - "node_modules/@npmcli/move-file/node_modules/mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, + "node_modules/@lerna/prerelease-id-from-version/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, "engines": { "node": ">=10" } }, - "node_modules/@npmcli/node-gyp": { - "version": "1.0.3", - "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", + "node_modules/@lerna/prerelease-id-from-version/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/@npmcli/promise-spawn": { - "version": "1.3.2", - "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "node_modules/@lerna/profiler": { + "version": "6.1.0", + "integrity": "sha512-WFDQNpuqPqMJLg8llvrBHF8Ib5Asgp23lMeNUe89T62NUX6gkjVBTYdjsduxM0tZH6Pa0GAGaQcha97P6fxfdQ==", "dev": true, "dependencies": { - "infer-owner": "^1.0.4" + "fs-extra": "^9.1.0", + "npmlog": "^6.0.2", + "upath": "^2.0.1" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@octokit/auth-token": { - "version": "2.5.0", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "node_modules/@lerna/profiler/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "dependencies": { - "@octokit/types": "^6.0.3" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@octokit/core": { - "version": "3.5.1", - "integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==", + "node_modules/@lerna/profiler/node_modules/upath": { + "version": "2.0.1", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", "dev": true, - "dependencies": { - "@octokit/auth-token": "^2.4.4", - "@octokit/graphql": "^4.5.8", - "@octokit/request": "^5.6.0", - "@octokit/request-error": "^2.0.5", - "@octokit/types": "^6.0.3", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" + "engines": { + "node": ">=4", + "yarn": "*" } }, - "node_modules/@octokit/core/node_modules/@octokit/request-error": { - "version": "2.1.0", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "node_modules/@lerna/project": { + "version": "6.1.0", + "integrity": "sha512-EOkfjjrTM16c3GUxGqcfYD2stV35p9mBEmkF41NPmyjfbzjol/irDF1r6Q7BsQSRsdClMJRCeZ168xdSxC2X0A==", "dev": true, "dependencies": { - "@octokit/types": "^6.0.3", - "deprecation": "^2.0.0", - "once": "^1.4.0" + "@lerna/package": "6.1.0", + "@lerna/validation-error": "6.1.0", + "cosmiconfig": "^7.0.0", + "dedent": "^0.7.0", + "dot-prop": "^6.0.1", + "glob-parent": "^5.1.1", + "globby": "^11.0.2", + "js-yaml": "^4.1.0", + "load-json-file": "^6.2.0", + "npmlog": "^6.0.2", + "p-map": "^4.0.0", + "resolve-from": "^5.0.0", + "write-json-file": "^4.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@octokit/core/node_modules/universal-user-agent": { - "version": "6.0.0", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "node_modules/@lerna/project/node_modules/argparse": { + "version": "2.0.1", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/@octokit/endpoint": { - "version": "6.0.12", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "node_modules/@lerna/project/node_modules/js-yaml": { + "version": "4.1.0", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "@octokit/types": "^6.0.3", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@octokit/endpoint/node_modules/is-plain-object": { - "version": "5.0.0", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "node_modules/@lerna/project/node_modules/load-json-file": { + "version": "6.2.0", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/@octokit/endpoint/node_modules/universal-user-agent": { - "version": "6.0.0", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true - }, - "node_modules/@octokit/graphql": { - "version": "4.8.0", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "node_modules/@lerna/project/node_modules/parse-json": { + "version": "5.2.0", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "dependencies": { - "@octokit/request": "^5.6.0", - "@octokit/types": "^6.0.3", - "universal-user-agent": "^6.0.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@octokit/graphql/node_modules/universal-user-agent": { - "version": "6.0.0", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true + "node_modules/@lerna/project/node_modules/resolve-from": { + "version": "5.0.0", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/@octokit/openapi-types": { - "version": "11.2.0", - "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==", - "dev": true + "node_modules/@lerna/project/node_modules/strip-bom": { + "version": "4.0.0", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/@octokit/plugin-enterprise-rest": { - "version": "6.0.1", - "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", - "dev": true + "node_modules/@lerna/project/node_modules/type-fest": { + "version": "0.6.0", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "2.17.0", - "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", + "node_modules/@lerna/prompt": { + "version": "6.1.0", + "integrity": "sha512-981J/C53TZ2l2mFVlWJN7zynSzf5GEHKvKQa12Td9iknhASZOuwTAWb6eq46246Ant6W5tWwb0NSPu3I5qtcrA==", "dev": true, "dependencies": { - "@octokit/types": "^6.34.0" + "inquirer": "^8.2.4", + "npmlog": "^6.0.2" }, - "peerDependencies": { - "@octokit/core": ">=2" + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@octokit/plugin-request-log": { - "version": "1.0.4", - "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", - "dev": true, - "peerDependencies": { - "@octokit/core": ">=3" + "node_modules/@lerna/publish": { + "version": "6.1.0", + "integrity": "sha512-XtvuydtU0IptbAapLRgoN1AZj/WJR+e3UKnx9BQ1Dwc+Fpg2oqPxR/vi+6hxAsr95pdQ5CnWBdgS+dg2wEUJ7Q==", + "dev": true, + "dependencies": { + "@lerna/check-working-tree": "6.1.0", + "@lerna/child-process": "6.1.0", + "@lerna/collect-updates": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/describe-ref": "6.1.0", + "@lerna/log-packed": "6.1.0", + "@lerna/npm-conf": "6.1.0", + "@lerna/npm-dist-tag": "6.1.0", + "@lerna/npm-publish": "6.1.0", + "@lerna/otplease": "6.1.0", + "@lerna/output": "6.1.0", + "@lerna/pack-directory": "6.1.0", + "@lerna/prerelease-id-from-version": "6.1.0", + "@lerna/prompt": "6.1.0", + "@lerna/pulse-till-done": "6.1.0", + "@lerna/run-lifecycle": "6.1.0", + "@lerna/run-topologically": "6.1.0", + "@lerna/validation-error": "6.1.0", + "@lerna/version": "6.1.0", + "fs-extra": "^9.1.0", + "libnpmaccess": "^6.0.3", + "npm-package-arg": "8.1.1", + "npm-registry-fetch": "^13.3.0", + "npmlog": "^6.0.2", + "p-map": "^4.0.0", + "p-pipe": "^3.1.0", + "pacote": "^13.6.1", + "semver": "^7.3.4" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "5.13.0", - "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", + "node_modules/@lerna/publish/node_modules/@npmcli/fs": { + "version": "2.1.2", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", "dev": true, "dependencies": { - "@octokit/types": "^6.34.0", - "deprecation": "^2.3.1" + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" }, - "peerDependencies": { - "@octokit/core": ">=3" + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@octokit/request": { - "version": "5.6.2", - "integrity": "sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA==", + "node_modules/@lerna/publish/node_modules/@npmcli/git": { + "version": "3.0.2", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", "dev": true, "dependencies": { - "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.1.0", - "@octokit/types": "^6.16.1", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.1", - "universal-user-agent": "^6.0.0" + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@octokit/request/node_modules/@octokit/request-error": { - "version": "2.1.0", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "node_modules/@lerna/publish/node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, - "dependencies": { - "@octokit/types": "^6.0.3", - "deprecation": "^2.0.0", - "once": "^1.4.0" + "engines": { + "node": ">=12" } }, - "node_modules/@octokit/request/node_modules/is-plain-object": { - "version": "5.0.0", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "node_modules/@lerna/publish/node_modules/@npmcli/move-file": { + "version": "2.0.1", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@octokit/request/node_modules/universal-user-agent": { - "version": "6.0.0", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true + "node_modules/@lerna/publish/node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } }, - "node_modules/@octokit/rest": { - "version": "18.12.0", - "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", + "node_modules/@lerna/publish/node_modules/@npmcli/promise-spawn": { + "version": "3.0.0", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", "dev": true, "dependencies": { - "@octokit/core": "^3.5.1", - "@octokit/plugin-paginate-rest": "^2.16.8", - "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^5.12.0" + "infer-owner": "^1.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@octokit/types": { - "version": "6.34.0", - "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", + "node_modules/@lerna/publish/node_modules/@npmcli/run-script": { + "version": "4.2.1", + "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", "dev": true, "dependencies": { - "@octokit/openapi-types": "^11.2.0" + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@polka/url": { - "version": "1.0.0-next.20", - "integrity": "sha512-88p7+M0QGxKpmnkfXjS4V26AnoC/eiqZutE8GLdaI5X12NY75bXSdTY9NkmYb2Xyk1O+MmkuO6Frmsj84V6I8Q==", - "dev": true - }, - "node_modules/@popperjs/core": { - "version": "2.10.1", - "integrity": "sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" + "node_modules/@lerna/publish/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/@probe.gl/stats": { - "version": "3.4.0", - "integrity": "sha512-Gl37r9qGuiKadIvTZdSZvzCNOttJYw6RcY1oT0oDuB8r2uhuZAdSMQRQTy9FTinp6MY6O9wngGnV6EpQ8wSBAw==", + "node_modules/@lerna/publish/node_modules/builtins": { + "version": "5.0.1", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.0.0" + "semver": "^7.0.0" } }, - "node_modules/@react-dnd/asap": { - "version": "4.0.0", - "integrity": "sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ==" + "node_modules/@lerna/publish/node_modules/cacache": { + "version": "16.1.3", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "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": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } }, - "node_modules/@react-dnd/invariant": { - "version": "2.0.0", - "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" + "node_modules/@lerna/publish/node_modules/cacache/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } }, - "node_modules/@react-dnd/shallowequal": { + "node_modules/@lerna/publish/node_modules/chownr": { "version": "2.0.0", - "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } }, - "node_modules/@react-icons/all-files": { - "version": "4.1.0", - "integrity": "sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==", - "peerDependencies": { - "react": "*" + "node_modules/@lerna/publish/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@samverschueren/stream-to-observable": { - "version": "0.3.1", - "integrity": "sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ==", + "node_modules/@lerna/publish/node_modules/glob": { + "version": "8.0.3", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", "dev": true, "dependencies": { - "any-observable": "^0.3.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": ">=6" + "node": ">=12" }, - "peerDependenciesMeta": { - "rxjs": { - "optional": true - }, - "zen-observable": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "node_modules/@lerna/publish/node_modules/hosted-git-info": { + "version": "3.0.8", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", "dev": true, "dependencies": { - "type-detect": "4.0.8" + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "node_modules/@lerna/publish/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@sinonjs/formatio": { - "version": "5.0.1", - "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "node_modules/@lerna/publish/node_modules/minimatch": { + "version": "5.1.2", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^5.0.2" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@sinonjs/samsam": { - "version": "5.3.1", - "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", + "node_modules/@lerna/publish/node_modules/minipass-fetch": { + "version": "2.1.2", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" } }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.1", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true + "node_modules/@lerna/publish/node_modules/mkdirp": { + "version": "1.0.4", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } }, - "node_modules/@storybook/addon-actions": { - "version": "6.4.22", - "integrity": "sha512-t2w3iLXFul+R/1ekYxIEzUOZZmvEa7EzUAVAuCHP4i6x0jBnTTZ7sAIUVRaxVREPguH5IqI/2OklYhKanty2Yw==", + "node_modules/@lerna/publish/node_modules/npm-install-checks": { + "version": "5.0.0", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, "dependencies": { - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/theming": "6.4.22", - "core-js": "^3.8.2", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "lodash": "^4.17.21", - "polished": "^4.0.5", - "prop-types": "^15.7.2", - "react-inspector": "^5.1.0", - "regenerator-runtime": "^0.13.7", - "telejson": "^5.3.2", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2", - "uuid-browser": "^3.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "semver": "^7.1.1" }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-actions/node_modules/polished": { - "version": "4.2.2", - "integrity": "sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==", + "node_modules/@lerna/publish/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/publish/node_modules/npm-package-arg": { + "version": "8.1.1", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.17.8" + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" }, "engines": { "node": ">=10" } }, - "node_modules/@storybook/addon-backgrounds": { - "version": "6.4.22", - "integrity": "sha512-xQIV1SsjjRXP7P5tUoGKv+pul1EY8lsV7iBXQb5eGbp4AffBj3qoYBSZbX4uiazl21o0MQiQoeIhhaPVaFIIGg==", + "node_modules/@lerna/publish/node_modules/npm-pick-manifest": { + "version": "7.0.2", + "integrity": "sha512-gk37SyRmlIjvTfcYl6RzDbSmS9Y4TOBXfsPnoYqTHARNgWbyDiCSMLUpmALDj4jjcTZpURiEfsSHJj9k7EV4Rw==", "dev": true, "dependencies": { - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/theming": "6.4.22", - "core-js": "^3.8.2", - "global": "^4.4.0", - "memoizerific": "^1.11.3", - "regenerator-runtime": "^0.13.7", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^2.0.0", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-controls": { - "version": "6.4.22", - "integrity": "sha512-f/M/W+7UTEUnr/L6scBMvksq+ZA8GTfh3bomE5FtWyOyaFppq9k8daKAvdYNlzXAOrUUsoZVJDgpb20Z2VBiSQ==", + "node_modules/@lerna/publish/node_modules/npm-pick-manifest/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, "dependencies": { - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core-common": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/node-logger": "6.4.22", - "@storybook/store": "6.4.22", - "@storybook/theming": "6.4.22", - "core-js": "^3.8.2", - "lodash": "^4.17.21", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "lru-cache": "^7.5.1" }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-essentials": { - "version": "6.4.22", - "integrity": "sha512-GTv291fqvWq2wzm7MruBvCGuWaCUiuf7Ca3kzbQ/WqWtve7Y/1PDsqRNQLGZrQxkXU0clXCqY1XtkTrtA3WGFQ==", + "node_modules/@lerna/publish/node_modules/npm-pick-manifest/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, - "dependencies": { - "@storybook/addon-actions": "6.4.22", - "@storybook/addon-backgrounds": "6.4.22", - "@storybook/addon-controls": "6.4.22", - "@storybook/addon-docs": "6.4.22", - "@storybook/addon-measure": "6.4.22", - "@storybook/addon-outline": "6.4.22", - "@storybook/addon-toolbars": "6.4.22", - "@storybook/addon-viewport": "6.4.22", - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/node-logger": "6.4.22", - "core-js": "^3.8.2", - "regenerator-runtime": "^0.13.7", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "@babel/core": "^7.9.6", - "@storybook/vue": "6.4.22", - "@storybook/web-components": "6.4.22", - "babel-loader": "^8.0.0", - "lit-html": "^1.4.1 || ^2.0.0-rc.3", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0", - "webpack": "*" - }, - "peerDependenciesMeta": { - "@storybook/vue": { - "optional": true - }, - "@storybook/web-components": { - "optional": true - }, - "lit-html": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "webpack": { - "optional": true - } + "engines": { + "node": ">=12" } }, - "node_modules/@storybook/addon-essentials/node_modules/@storybook/addon-docs": { - "version": "6.4.22", - "integrity": "sha512-9j+i+W+BGHJuRe4jUrqk6ubCzP4fc1xgFS2o8pakRiZgPn5kUQPdkticmsyh1XeEJifwhqjKJvkEDrcsleytDA==", + "node_modules/@lerna/publish/node_modules/npm-pick-manifest/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, "dependencies": { - "@babel/core": "^7.12.10", - "@babel/generator": "^7.12.11", - "@babel/parser": "^7.12.11", - "@babel/plugin-transform-react-jsx": "^7.12.12", - "@babel/preset-env": "^7.12.11", - "@jest/transform": "^26.6.2", - "@mdx-js/loader": "^1.6.22", - "@mdx-js/mdx": "^1.6.22", - "@mdx-js/react": "^1.6.22", - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/builder-webpack4": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/csf-tools": "6.4.22", - "@storybook/node-logger": "6.4.22", - "@storybook/postinstall": "6.4.22", - "@storybook/preview-web": "6.4.22", - "@storybook/source-loader": "6.4.22", - "@storybook/store": "6.4.22", - "@storybook/theming": "6.4.22", - "acorn": "^7.4.1", - "acorn-jsx": "^5.3.1", - "acorn-walk": "^7.2.0", - "core-js": "^3.8.2", - "doctrine": "^3.0.0", - "escodegen": "^2.0.0", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "html-tags": "^3.1.0", - "js-string-escape": "^1.0.1", - "loader-utils": "^2.0.0", - "lodash": "^4.17.21", - "nanoid": "^3.1.23", - "p-limit": "^3.1.0", - "prettier": ">=2.2.1 <=2.3.0", - "prop-types": "^15.7.2", - "react-element-to-jsx-string": "^14.3.4", - "regenerator-runtime": "^0.13.7", - "remark-external-links": "^8.0.0", - "remark-slug": "^6.0.0", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "@storybook/angular": "6.4.22", - "@storybook/html": "6.4.22", - "@storybook/react": "6.4.22", - "@storybook/vue": "6.4.22", - "@storybook/vue3": "6.4.22", - "@storybook/web-components": "6.4.22", - "lit": "^2.0.0", - "lit-html": "^1.4.1 || ^2.0.0", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0", - "svelte": "^3.31.2", - "sveltedoc-parser": "^4.1.0", - "vue": "^2.6.10 || ^3.0.0", - "webpack": "*" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, - "peerDependenciesMeta": { - "@storybook/angular": { - "optional": true - }, - "@storybook/html": { - "optional": true - }, - "@storybook/react": { - "optional": true - }, - "@storybook/vue": { - "optional": true - }, - "@storybook/vue3": { - "optional": true - }, - "@storybook/web-components": { - "optional": true - }, - "lit": { - "optional": true - }, - "lit-html": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "svelte": { - "optional": true - }, - "sveltedoc-parser": { - "optional": true - }, - "vue": { - "optional": true - }, - "webpack": { - "optional": true - } + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-essentials/node_modules/acorn": { - "version": "7.4.1", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/@lerna/publish/node_modules/npm-pick-manifest/node_modules/validate-npm-package-name": { + "version": "4.0.0", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "builtins": "^5.0.0" }, "engines": { - "node": ">=0.4.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-essentials/node_modules/escodegen": { - "version": "2.0.0", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "node_modules/@lerna/publish/node_modules/npm-registry-fetch": { + "version": "13.3.1", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", "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" + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" }, "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-essentials/node_modules/esprima": { - "version": "4.0.1", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/@lerna/publish/node_modules/npm-registry-fetch/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "dependencies": { + "lru-cache": "^7.5.1" }, "engines": { - "node": ">=4" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-essentials/node_modules/estraverse": { - "version": "5.3.0", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/@lerna/publish/node_modules/npm-registry-fetch/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, "engines": { - "node": ">=4.0" + "node": ">=12" } }, - "node_modules/@storybook/addon-essentials/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "node_modules/@lerna/publish/node_modules/npm-registry-fetch/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, - "bin": { - "json5": "lib/cli.js" + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, "engines": { - "node": ">=6" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-essentials/node_modules/loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "node_modules/@lerna/publish/node_modules/npm-registry-fetch/node_modules/validate-npm-package-name": { + "version": "4.0.0", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "builtins": "^5.0.0" }, "engines": { - "node": ">=8.9.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-essentials/node_modules/nanoid": { - "version": "3.3.4", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "node_modules/@lerna/publish/node_modules/pacote": { + "version": "13.6.2", + "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", "dev": true, + "dependencies": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, "bin": { - "nanoid": "bin/nanoid.cjs" + "pacote": "lib/bin.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-essentials/node_modules/p-limit": { - "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/@lerna/publish/node_modules/pacote/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" + "lru-cache": "^7.5.1" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/publish/node_modules/pacote/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@lerna/publish/node_modules/pacote/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-essentials/node_modules/prettier": { - "version": "2.3.0", - "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", + "node_modules/@lerna/publish/node_modules/pacote/node_modules/validate-npm-package-name": { + "version": "4.0.0", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", "dev": true, - "bin": { - "prettier": "bin-prettier.js" + "dependencies": { + "builtins": "^5.0.0" }, "engines": { - "node": ">=10.13.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-essentials/node_modules/source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/@lerna/publish/node_modules/proc-log": { + "version": "2.0.1", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", "dev": true, - "optional": true, "engines": { - "node": ">=0.10.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-knobs": { - "version": "6.3.1", - "integrity": "sha512-2GGGnQSPXXUhHHYv4IW6pkyQlCPYXKYiyGzfhV7Zhs95M2Ban08OA6KLmliMptWCt7U9tqTO8dB5u0C2cWmCTw==", - "deprecated": "deprecating @storybook/addon-knobs in favor of @storybook/addon-controls", + "node_modules/@lerna/publish/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, "dependencies": { - "copy-to-clipboard": "^3.3.1", - "core-js": "^3.8.2", - "escape-html": "^1.0.3", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "lodash": "^4.17.20", - "prop-types": "^15.7.2", - "qs": "^6.10.0", - "react-colorful": "^5.1.2", - "react-lifecycles-compat": "^3.0.4", - "react-select": "^3.2.0" + "lru-cache": "^6.0.0" }, - "peerDependencies": { - "@storybook/addons": "^6.3.0", - "@storybook/api": "^6.3.0", - "@storybook/components": "^6.3.0", - "@storybook/core-events": "^6.3.0", - "@storybook/theming": "^6.3.0", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "bin": { + "semver": "bin/semver.js" }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": ">=10" } }, - "node_modules/@storybook/addon-knobs/node_modules/@emotion/cache": { - "version": "10.0.29", - "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", + "node_modules/@lerna/publish/node_modules/ssri": { + "version": "9.0.1", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, "dependencies": { - "@emotion/sheet": "0.9.4", - "@emotion/stylis": "0.8.5", - "@emotion/utils": "0.11.3", - "@emotion/weak-memoize": "0.2.5" + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-knobs/node_modules/csstype": { - "version": "3.0.9", - "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==" - }, - "node_modules/@storybook/addon-knobs/node_modules/dom-helpers": { - "version": "5.2.1", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "node_modules/@lerna/publish/node_modules/unique-filename": { + "version": "2.0.1", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-knobs/node_modules/qs": { - "version": "6.10.1", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "node_modules/@lerna/publish/node_modules/unique-slug": { + "version": "3.0.0", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "imurmurhash": "^0.1.4" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-knobs/node_modules/react-input-autosize": { - "version": "3.0.0", - "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==", + "node_modules/@lerna/publish/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { - "prop-types": "^15.5.8" + "isexe": "^2.0.0" }, - "peerDependencies": { - "react": "^16.3.0 || ^17.0.0" + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@storybook/addon-knobs/node_modules/react-select": { - "version": "3.2.0", - "integrity": "sha512-B/q3TnCZXEKItO0fFN/I0tWOX3WJvi/X2wtdffmwSQVRwg5BpValScTO1vdic9AxlUgmeSzib2hAZAwIUQUZGQ==", + "node_modules/@lerna/publish/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@lerna/pulse-till-done": { + "version": "6.1.0", + "integrity": "sha512-a2RVT82E4R9nVXtehzp2TQL6iXp0QfEM3bu8tBAR/SfI1A9ggZWQhuuUqtRyhhVCajdQDOo7rS0UG7R5JzK58w==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.4.4", - "@emotion/cache": "^10.0.9", - "@emotion/core": "^10.0.9", - "@emotion/css": "^10.0.9", - "memoize-one": "^5.0.0", - "prop-types": "^15.6.0", - "react-input-autosize": "^3.0.0", - "react-transition-group": "^4.3.0" + "npmlog": "^6.0.2" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-knobs/node_modules/react-transition-group": { - "version": "4.4.2", - "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "node_modules/@lerna/query-graph": { + "version": "6.1.0", + "integrity": "sha512-YkyCc+6aR7GlCOcZXEKPcl5o5L2v+0YUNs59JrfAS0mctFosZ/2tP7pkdu2SI4qXIi5D0PMNsh/0fRni56znsQ==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" + "@lerna/package-graph": "6.1.0" }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-links": { - "version": "6.4.22", - "integrity": "sha512-OSOyDnTXnmcplJHlXTYUTMkrfpLqxtHp2R69IXfAyI1e8WNDb79mXflrEXDA/RSNEliLkqYwCyYby7gDMGds5Q==", + "node_modules/@lerna/resolve-symlink": { + "version": "6.1.0", + "integrity": "sha512-8ILO+h5fsE0q8MSLfdL+MT1GEsNhAB1fDyMkSsYgLRCsssN/cViZbffpclZyT/EfAhpyKfBCHZ0CmT1ZGofU1A==", + "dev": true, "dependencies": { - "@storybook/addons": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/router": "6.4.22", - "@types/qs": "^6.9.5", - "core-js": "^3.8.2", - "global": "^4.4.0", - "prop-types": "^15.7.2", - "qs": "^6.10.0", - "regenerator-runtime": "^0.13.7", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "fs-extra": "^9.1.0", + "npmlog": "^6.0.2", + "read-cmd-shim": "^3.0.0" }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-links/node_modules/qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "node_modules/@lerna/resolve-symlink/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/@storybook/addon-measure": { - "version": "6.4.22", - "integrity": "sha512-CjDXoCNIXxNfXfgyJXPc0McjCcwN1scVNtHa9Ckr+zMjiQ8pPHY7wDZCQsG69KTqcWHiVfxKilI82456bcHYhQ==", + "node_modules/@lerna/resolve-symlink/node_modules/read-cmd-shim": { + "version": "3.0.1", + "integrity": "sha512-kEmDUoYf/CDy8yZbLTmhB1X9kkjf9Q80PCNsDMb7ufrGd6zZSQA1+UyjrO+pZm5K/S4OXCWJeiIt1JA8kAsa6g==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/rimraf-dir": { + "version": "6.1.0", + "integrity": "sha512-J9YeGHkCCeAIzsnKURYeGECBexiIii6HA+Bbd+rAgoKPsNCOj6ql4+qJE8Jbd7fQEFNDPQeBCYvM7JcdMc0WSA==", "dev": true, "dependencies": { - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "core-js": "^3.8.2", - "global": "^4.4.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "@lerna/child-process": "6.1.0", + "npmlog": "^6.0.2", + "path-exists": "^4.0.0", + "rimraf": "^3.0.2" }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-outline": { - "version": "6.4.22", - "integrity": "sha512-VIMEzvBBRbNnupGU7NV0ahpFFb6nKVRGYWGREjtABdFn2fdKr1YicOHFe/3U7hRGjb5gd+VazSvyUvhaKX9T7Q==", + "node_modules/@lerna/rimraf-dir/node_modules/path-exists": { + "version": "4.0.0", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/run": { + "version": "6.1.0", + "integrity": "sha512-vlEEKPcTloiob6EK7gxrjEdB6fQQ/LNfWhSJCGxJlvNVbrMpoWIu0Kpp20b0nE+lzX7rRJ4seWr7Wdo/Fjub4Q==", "dev": true, "dependencies": { - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "core-js": "^3.8.2", - "global": "^4.4.0", - "regenerator-runtime": "^0.13.7", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/npm-run-script": "6.1.0", + "@lerna/output": "6.1.0", + "@lerna/profiler": "6.1.0", + "@lerna/run-topologically": "6.1.0", + "@lerna/timer": "6.1.0", + "@lerna/validation-error": "6.1.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0" }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-toolbars": { - "version": "6.4.22", - "integrity": "sha512-FFyj6XDYpBBjcUu6Eyng7R805LUbVclEfydZjNiByAoDVyCde9Hb4sngFxn/T4fKAfBz/32HKVXd5iq4AHYtLg==", + "node_modules/@lerna/run-lifecycle": { + "version": "6.1.0", + "integrity": "sha512-GbTdKxL+hWHEPgyBEKtqY9Nf+jFlt6YLtP5VjEVc5SdLkm+FeRquar9/YcZVUbzr3c+NJwWNgVjHuePfowdpUA==", "dev": true, "dependencies": { - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/theming": "6.4.22", - "core-js": "^3.8.2", - "regenerator-runtime": "^0.13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "@lerna/npm-conf": "6.1.0", + "@npmcli/run-script": "^4.1.7", + "npmlog": "^6.0.2", + "p-queue": "^6.6.2" }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addon-viewport": { - "version": "6.4.22", - "integrity": "sha512-6jk0z49LemeTblez5u2bYXYr6U+xIdLbywe3G283+PZCBbEDE6eNYy2d2HDL+LbCLbezJBLYPHPalElphjJIcw==", + "node_modules/@lerna/run-lifecycle/node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", "dev": true, - "dependencies": { - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/theming": "6.4.22", - "core-js": "^3.8.2", - "global": "^4.4.0", - "memoizerific": "^1.11.3", - "prop-types": "^15.7.2", - "regenerator-runtime": "^0.13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/addons": { - "version": "6.4.22", - "integrity": "sha512-P/R+Jsxh7pawKLYo8MtE3QU/ilRFKbtCewV/T1o5U/gm8v7hKQdFz3YdRMAra4QuCY8bQIp7MKd2HrB5aH5a1A==", + "node_modules/@lerna/run-lifecycle/node_modules/@npmcli/promise-spawn": { + "version": "3.0.0", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, "dependencies": { - "@storybook/api": "6.4.22", - "@storybook/channels": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/router": "6.4.22", - "@storybook/theming": "6.4.22", - "@types/webpack-env": "^1.16.0", - "core-js": "^3.8.2", - "global": "^4.4.0", - "regenerator-runtime": "^0.13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "infer-owner": "^1.0.4" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/api": { - "version": "6.4.22", - "integrity": "sha512-lAVI3o2hKupYHXFTt+1nqFct942up5dHH6YD7SZZJGyW21dwKC3HK1IzCsTawq3fZAKkgWFgmOO649hKk60yKg==", + "node_modules/@lerna/run-lifecycle/node_modules/@npmcli/run-script": { + "version": "4.2.1", + "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", + "dev": true, "dependencies": { - "@storybook/channels": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/router": "6.4.22", - "@storybook/semver": "^7.3.2", - "@storybook/theming": "6.4.22", - "core-js": "^3.8.2", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "lodash": "^4.17.21", - "memoizerific": "^1.11.3", - "regenerator-runtime": "^0.13.7", - "store2": "^2.12.0", - "telejson": "^5.3.2", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/builder-webpack4": { - "version": "6.4.22", - "integrity": "sha512-A+GgGtKGnBneRFSFkDarUIgUTI8pYFdLmUVKEAGdh2hL+vLXAz9A46sEY7C8LQ85XWa8TKy3OTDxqR4+4iWj3A==", + "node_modules/@lerna/run-lifecycle/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { - "@babel/core": "^7.12.10", - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/plugin-proposal-decorators": "^7.12.12", - "@babel/plugin-proposal-export-default-from": "^7.12.1", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", - "@babel/plugin-proposal-object-rest-spread": "^7.12.1", - "@babel/plugin-proposal-optional-chaining": "^7.12.7", - "@babel/plugin-proposal-private-methods": "^7.12.1", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-arrow-functions": "^7.12.1", - "@babel/plugin-transform-block-scoping": "^7.12.12", - "@babel/plugin-transform-classes": "^7.12.1", - "@babel/plugin-transform-destructuring": "^7.12.1", - "@babel/plugin-transform-for-of": "^7.12.1", - "@babel/plugin-transform-parameters": "^7.12.1", - "@babel/plugin-transform-shorthand-properties": "^7.12.1", - "@babel/plugin-transform-spread": "^7.12.1", - "@babel/plugin-transform-template-literals": "^7.12.1", - "@babel/preset-env": "^7.12.11", - "@babel/preset-react": "^7.12.10", - "@babel/preset-typescript": "^7.12.7", - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/channel-postmessage": "6.4.22", - "@storybook/channels": "6.4.22", - "@storybook/client-api": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core-common": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/node-logger": "6.4.22", - "@storybook/preview-web": "6.4.22", - "@storybook/router": "6.4.22", - "@storybook/semver": "^7.3.2", - "@storybook/store": "6.4.22", - "@storybook/theming": "6.4.22", - "@storybook/ui": "6.4.22", - "@types/node": "^14.0.10", - "@types/webpack": "^4.41.26", - "autoprefixer": "^9.8.6", - "babel-loader": "^8.0.0", - "babel-plugin-macros": "^2.8.0", - "babel-plugin-polyfill-corejs3": "^0.1.0", - "case-sensitive-paths-webpack-plugin": "^2.3.0", - "core-js": "^3.8.2", - "css-loader": "^3.6.0", - "file-loader": "^6.2.0", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^4.1.6", - "glob": "^7.1.6", - "glob-promise": "^3.4.0", - "global": "^4.4.0", - "html-webpack-plugin": "^4.0.0", - "pnp-webpack-plugin": "1.6.4", - "postcss": "^7.0.36", - "postcss-flexbugs-fixes": "^4.2.1", - "postcss-loader": "^4.2.0", - "raw-loader": "^4.0.2", - "stable": "^0.1.8", - "style-loader": "^1.3.0", - "terser-webpack-plugin": "^4.2.3", - "ts-dedent": "^2.0.0", - "url-loader": "^4.1.1", - "util-deprecate": "^1.0.2", - "webpack": "4", - "webpack-dev-middleware": "^3.7.3", - "webpack-filter-warnings-plugin": "^1.2.1", - "webpack-hot-middleware": "^2.25.1", - "webpack-virtual-modules": "^0.2.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "isexe": "^2.0.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@storybook/builder-webpack4/node_modules/@types/node": { - "version": "14.18.16", - "integrity": "sha512-X3bUMdK/VmvrWdoTkz+VCn6nwKwrKCFTHtqwBIaQJNx4RUIBBUFXM00bqPz/DsDd+Icjmzm6/tyYZzeGVqb6/Q==" - }, - "node_modules/@storybook/builder-webpack4/node_modules/acorn": { - "version": "6.4.2", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "bin": { - "acorn": "bin/acorn" + "node-which": "bin/node-which" }, "engines": { - "node": ">=0.4.0" + "node": ">= 8" } }, - "node_modules/@storybook/builder-webpack4/node_modules/ansi-styles": { - "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@lerna/run-topologically": { + "version": "6.1.0", + "integrity": "sha512-kpTaSBKdKjtf61be8Z1e7TIaMt/aksfxswQtpFxEuKDsPsdHfR8htSkADO4d/3SZFtmcAHIHNCQj9CaNj4O4Xw==", + "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@lerna/query-graph": "6.1.0", + "p-queue": "^6.6.2" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/builder-webpack4/node_modules/chalk": { - "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@lerna/run/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/@storybook/builder-webpack4/node_modules/css-loader": { - "version": "3.6.0", - "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "node_modules/@lerna/symlink-binary": { + "version": "6.1.0", + "integrity": "sha512-DaiRNZk/dvomNxgEaTW145PyL7vIGP7rvnfXV2FO+rjX8UUSNUOjmVmHlYfs64gV9Eqx/dLfQClIbKcwYMD83A==", + "dev": true, "dependencies": { - "camelcase": "^5.3.1", - "cssesc": "^3.0.0", - "icss-utils": "^4.1.1", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^2.7.0", - "semver": "^6.3.0" + "@lerna/create-symlink": "6.1.0", + "@lerna/package": "6.1.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0" }, "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/builder-webpack4/node_modules/css-loader/node_modules/semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" + "node_modules/@lerna/symlink-binary/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@storybook/builder-webpack4/node_modules/eslint-scope": { - "version": "4.0.3", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "node_modules/@lerna/symlink-dependencies": { + "version": "6.1.0", + "integrity": "sha512-hrTvtY1Ek+fLA4JjXsKsvwPjuJD0rwB/+K4WY57t00owj//BpCsJ37w3kkkS7f/PcW/5uRjCuHcY67LOEwsRxw==", + "dev": true, "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "@lerna/create-symlink": "6.1.0", + "@lerna/resolve-symlink": "6.1.0", + "@lerna/symlink-binary": "6.1.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0" }, "engines": { - "node": ">=4.0.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/builder-webpack4/node_modules/find-up": { - "version": "5.0.0", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/@lerna/symlink-dependencies/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { "node": ">=10" + } + }, + "node_modules/@lerna/temp-write": { + "version": "6.1.0", + "integrity": "sha512-ZcQl88H9HbQ/TeWUOVt+vDYwptm7kwprGvj9KkZXr9S5Bn6SiKRQOeydCCfCrQT+9Q3dm7QZXV6rWzLsACcAlQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "is-stream": "^2.0.0", + "make-dir": "^3.0.0", + "temp-dir": "^1.0.0", + "uuid": "^8.3.2" + } + }, + "node_modules/@lerna/temp-write/node_modules/is-stream": { + "version": "2.0.1", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@storybook/builder-webpack4/node_modules/fork-ts-checker-webpack-plugin": { - "version": "4.1.6", - "integrity": "sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==", + "node_modules/@lerna/temp-write/node_modules/make-dir": { + "version": "3.1.0", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, "dependencies": { - "@babel/code-frame": "^7.5.5", - "chalk": "^2.4.1", - "micromatch": "^3.1.10", - "minimatch": "^3.0.4", - "semver": "^5.6.0", - "tapable": "^1.0.0", - "worker-rpc": "^0.1.0" + "semver": "^6.0.0" }, "engines": { - "node": ">=6.11.5", - "yarn": ">=1.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@storybook/builder-webpack4/node_modules/html-webpack-plugin": { - "version": "4.5.2", - "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", - "dependencies": { - "@types/html-minifier-terser": "^5.0.0", - "@types/tapable": "^1.0.5", - "@types/webpack": "^4.41.8", - "html-minifier-terser": "^5.0.1", - "loader-utils": "^1.2.3", - "lodash": "^4.17.20", - "pretty-error": "^2.1.1", - "tapable": "^1.1.3", - "util.promisify": "1.0.0" - }, + "node_modules/@lerna/temp-write/node_modules/semver": { + "version": "6.3.0", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@lerna/temp-write/node_modules/uuid": { + "version": "8.3.2", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@lerna/timer": { + "version": "6.1.0", + "integrity": "sha512-du+NQ9q7uO4d2nVU4AD2DSPuAZqUapA/bZKuVpFVxvY9Qhzb8dQKLsFISe4A9TjyoNAk8ZeWK0aBc/6N+Qer9A==", + "dev": true, "engines": { - "node": ">=6.9" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/builder-webpack4/node_modules/icss-utils": { - "version": "4.1.1", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "node_modules/@lerna/validation-error": { + "version": "6.1.0", + "integrity": "sha512-q0c3XCi5OpyTr8AcfbisS6e3svZaJF/riCvBDqRMaQUT4A8QOPzB4fVF3/+J2u54nidBuTlIk0JZu9aOdWTUkQ==", + "dev": true, "dependencies": { - "postcss": "^7.0.14" + "npmlog": "^6.0.2" }, "engines": { - "node": ">= 6" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/builder-webpack4/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "bin": { - "json5": "lib/cli.js" + "node_modules/@lerna/version": { + "version": "6.1.0", + "integrity": "sha512-RUxVFdzHt0739lRNMrAbo6HWcFrcyG7atM1pn+Eo61fUoA5R/9N4bCk4m9xUGkJ/mOcROjuwAGe+wT1uOs58Bg==", + "dev": true, + "dependencies": { + "@lerna/check-working-tree": "6.1.0", + "@lerna/child-process": "6.1.0", + "@lerna/collect-updates": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/conventional-commits": "6.1.0", + "@lerna/github-client": "6.1.0", + "@lerna/gitlab-client": "6.1.0", + "@lerna/output": "6.1.0", + "@lerna/prerelease-id-from-version": "6.1.0", + "@lerna/prompt": "6.1.0", + "@lerna/run-lifecycle": "6.1.0", + "@lerna/run-topologically": "6.1.0", + "@lerna/temp-write": "6.1.0", + "@lerna/validation-error": "6.1.0", + "@nrwl/devkit": ">=14.8.6 < 16", + "chalk": "^4.1.0", + "dedent": "^0.7.0", + "load-json-file": "^6.2.0", + "minimatch": "^3.0.4", + "npmlog": "^6.0.2", + "p-map": "^4.0.0", + "p-pipe": "^3.1.0", + "p-reduce": "^2.1.0", + "p-waterfall": "^2.1.1", + "semver": "^7.3.4", + "slash": "^3.0.0", + "write-json-file": "^4.3.0" }, "engines": { - "node": ">=6" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/builder-webpack4/node_modules/loader-runner": { - "version": "2.4.0", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "node_modules/@lerna/version/node_modules/load-json-file": { + "version": "6.2.0", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" + "node": ">=8" } }, - "node_modules/@storybook/builder-webpack4/node_modules/locate-path": { + "node_modules/@lerna/version/node_modules/lru-cache": { "version": "6.0.0", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { - "p-locate": "^5.0.0" + "yallist": "^4.0.0" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@storybook/builder-webpack4/node_modules/normalize-path": { - "version": "3.0.0", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" } }, - "node_modules/@storybook/builder-webpack4/node_modules/p-limit": { - "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/@lerna/version/node_modules/parse-json": { + "version": "5.2.0", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@storybook/builder-webpack4/node_modules/p-locate": { - "version": "5.0.0", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/@lerna/version/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, "dependencies": { - "p-limit": "^3.0.2" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@storybook/builder-webpack4/node_modules/path-exists": { + "node_modules/@lerna/version/node_modules/slash": { + "version": "3.0.0", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/version/node_modules/strip-bom": { "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, "engines": { "node": ">=8" } }, - "node_modules/@storybook/builder-webpack4/node_modules/postcss": { - "version": "7.0.39", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/@lerna/version/node_modules/type-fest": { + "version": "0.6.0", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/version/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@lerna/write-log-file": { + "version": "6.1.0", + "integrity": "sha512-09omu2w4NCt8mJH/X9ZMuToQQ3xu/KpC7EU4yDl2Qy8nxKf8HiG8Oe+YYNprngmkdsq60F5eUZvoiFDZ5JeGIg==", + "dev": true, "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "npmlog": "^6.0.2", + "write-file-atomic": "^4.0.1" }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": "^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/builder-webpack4/node_modules/postcss-modules-extract-imports": { - "version": "2.0.0", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "node_modules/@lerna/write-log-file/node_modules/write-file-atomic": { + "version": "4.0.2", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, "dependencies": { - "postcss": "^7.0.5" + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" }, "engines": { - "node": ">= 6" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@storybook/builder-webpack4/node_modules/postcss-modules-local-by-default": { - "version": "3.0.3", + "node_modules/@loaders.gl/3d-tiles": { + "version": "3.0.8", + "integrity": "sha512-jZeOyDPGD2wEkTLW4Do9A4UUQ+OGjhhNXztB0AsttZ69OpkmsxJXb76xxwevf+eThrsTgSTjZ06eC5DHX0kyXA==", + "dependencies": { + "@loaders.gl/core": "3.0.8", + "@loaders.gl/draco": "3.0.8", + "@loaders.gl/gltf": "3.0.8", + "@loaders.gl/loader-utils": "3.0.8", + "@loaders.gl/math": "3.0.8", + "@loaders.gl/tiles": "3.0.8", + "@math.gl/core": "^3.5.1", + "@math.gl/geospatial": "^3.5.1" + } + }, + "node_modules/@loaders.gl/core": { + "version": "3.0.8", + "integrity": "sha512-FIfbhMkoRX2JonEHXHgClC7jwOSsEwvvmjlaTMRAY+gFKvJPGmegkp4VgUZquLFf6GedJt/1TuMMvAX6gdq1pg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "@loaders.gl/loader-utils": "3.0.8", + "@loaders.gl/worker-utils": "3.0.8", + "probe.gl": "^3.4.0" + } + }, + "node_modules/@loaders.gl/draco": { + "version": "3.0.8", + "integrity": "sha512-ZCXzXNHWQ7H0qk/kC+rWzjMWjLzZGzQcDbdpIuy8xJdp4rTpmMkLUseFPby8vhkmIaqxWPwPB6mx/vM7L6JENg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "@loaders.gl/loader-utils": "3.0.8", + "@loaders.gl/schema": "3.0.8", + "@loaders.gl/worker-utils": "3.0.8", + "draco3d": "1.4.1" + } + }, + "node_modules/@loaders.gl/gis": { + "version": "3.0.8", + "integrity": "sha512-7NL+lIb7NezlMupYskVil6M3RZunXJl+TyaVAW82GLbzPSOq+m/G7h3+z0GBa8iv/U/I+cB5BhSN+GZmvFwqEA==", + "dependencies": { + "@loaders.gl/loader-utils": "3.0.8", + "@loaders.gl/schema": "3.0.8", + "@mapbox/vector-tile": "^1.3.1", + "pbf": "^3.2.1" + } + }, + "node_modules/@loaders.gl/gltf": { + "version": "3.0.8", + "integrity": "sha512-4PXWTlqyvlbZE2Vp4iQ+Y87ZO1WuRvSlbImDhygd0hoINfmJ9ObxrFS3yJcpJTu007nWxXorNVEOKyuoo+4Iyw==", + "dependencies": { + "@loaders.gl/core": "3.0.8", + "@loaders.gl/draco": "3.0.8", + "@loaders.gl/images": "3.0.8", + "@loaders.gl/loader-utils": "3.0.8" + } + }, + "node_modules/@loaders.gl/images": { + "version": "3.0.8", + "integrity": "sha512-rO2cIYJYlMs/uO9YSoF4/BEA4p/9xQ3gHZ1sIJkPYVnDqzpbu8nvUjWTQqIdL/MkQBTW8tz3twCdM+B6G9Fa2w==", + "dependencies": { + "@loaders.gl/loader-utils": "3.0.8" + } + }, + "node_modules/@loaders.gl/loader-utils": { + "version": "3.0.8", + "integrity": "sha512-PW1WyyQ+LXkqoGHBZHsmfNQkKiLAYf1gok+kHnHvY9fCzhJeA1iTNEUKPXGXKgS00m/k5cBTkOWAaOG9KRvBCQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "@loaders.gl/worker-utils": "3.0.8", + "@probe.gl/stats": "^3.4.0" + } + }, + "node_modules/@loaders.gl/math": { + "version": "3.0.8", + "integrity": "sha512-jfFpxxr4Bq5JfOPqLVJc4JJGoGGvVTOCWiJhnTtSAKhaNSwldmNWaZ0w8E2nlgPKPMAHiTRKOQnd9sSY5m66Cw==", + "dependencies": { + "@loaders.gl/images": "3.0.8", + "@loaders.gl/loader-utils": "3.0.8", + "@math.gl/core": "^3.5.1" + } + }, + "node_modules/@loaders.gl/mvt": { + "version": "3.0.8", + "integrity": "sha512-Jk1QTHgpxMsUT01w5IJJ2en9qq0yOZcL2wGXVc7CFp2h6inB22rC3drUwq1mUNGe6iy3EWIo7EeJVd9B+5JyTQ==", + "dependencies": { + "@loaders.gl/gis": "3.0.8", + "@loaders.gl/loader-utils": "3.0.8", + "@math.gl/polygon": "^3.5.1", + "pbf": "^3.2.1" + } + }, + "node_modules/@loaders.gl/schema": { + "version": "3.0.8", + "integrity": "sha512-yne5WE7fZZWFl2zF8fzDlYhPVJua6h6mTCSmlQ5pryaMXTZS9mfzXXIFWRL3kswqnQTu/QNFdyFj1mP0haF24w==", + "dependencies": { + "@types/geojson": "^7946.0.7", + "apache-arrow": "^4.0.0", + "d3-dsv": "^1.2.0" + } + }, + "node_modules/@loaders.gl/terrain": { + "version": "3.0.8", + "integrity": "sha512-MtOAYEB/xJB4CN4B0YNPkO4v1ZY332joxiOHQI1x37x4sWVAqOrKLr9jB42sZCB8aINi2WMWGiErtf9wh9L5Pg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "@loaders.gl/loader-utils": "3.0.8", + "@loaders.gl/schema": "3.0.8", + "@mapbox/martini": "^0.2.0" + } + }, + "node_modules/@loaders.gl/tiles": { + "version": "3.0.8", + "integrity": "sha512-Rc+yHFdQg2sYmcYkwvszukFWdm9EW354F9HUR7y/oauos6tsdo4YTj31zgytaYR63/EqWQ7kwI29/eePEcutzg==", + "dependencies": { + "@loaders.gl/core": "3.0.8", + "@loaders.gl/loader-utils": "3.0.8", + "@loaders.gl/math": "3.0.8", + "@math.gl/core": "^3.5.1", + "@math.gl/culling": "^3.5.1", + "@math.gl/geospatial": "^3.5.1", + "@math.gl/web-mercator": "^3.5.1", + "@probe.gl/stats": "^3.4.0" + } + }, + "node_modules/@loaders.gl/worker-utils": { + "version": "3.0.8", + "integrity": "sha512-Pg72HuXPcL725TrOlOr83xloVUHj6OMWmno1dI8ccuqfOBsgoRjxNZrcSvwBzfK8tFCzuN2X30I+mHl3BkuYLw==", + "dependencies": { + "@babel/runtime": "^7.3.1" + } + }, + "node_modules/@luma.gl/constants": { + "version": "8.5.4", + "integrity": "sha512-lrA4ja92om/gDHYOvM9itL5S7FVzjKulyknDz6S+Y7gmgHgXk2ln1Xar5zUCsLnhAYx4glHITXGH5Y5rdWgT1Q==" + }, + "node_modules/@luma.gl/core": { + "version": "8.5.4", + "integrity": "sha512-+saDz1D3mcPd53vgbG60ryg1w5CF9Z2wdakKHzR810VoJLw97t4aNdg/eNgyWOvbOHxaKJBPm8K0sGjej67+jw==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "@luma.gl/constants": "8.5.4", + "@luma.gl/engine": "8.5.4", + "@luma.gl/gltools": "8.5.4", + "@luma.gl/shadertools": "8.5.4", + "@luma.gl/webgl": "8.5.4" + } + }, + "node_modules/@luma.gl/engine": { + "version": "8.5.4", + "integrity": "sha512-Sfv972IzvR9s9kKWugs67XQUh9jC0e/PpBrzvyGVnPU4XvFq42RZVF73pzEklVU6AlpR8Zg5CPtxGdhyOHtT7w==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "@luma.gl/constants": "8.5.4", + "@luma.gl/gltools": "8.5.4", + "@luma.gl/shadertools": "8.5.4", + "@luma.gl/webgl": "8.5.4", + "@math.gl/core": "^3.5.0", + "probe.gl": "^3.4.0" + } + }, + "node_modules/@luma.gl/experimental": { + "version": "8.5.4", + "integrity": "sha512-09waqRhgIrw+Sq0/in4tw4jPag5YsFfV1nEHJaLAg5RFv92S53IEubSJgkuG02HoOBkPxQ7KYvs9VNmriisnYg==", + "dependencies": { + "@luma.gl/constants": "8.5.4", + "@math.gl/core": "^3.5.0", + "earcut": "^2.0.6" + }, + "peerDependencies": { + "@loaders.gl/gltf": "^3.0.0", + "@loaders.gl/images": "^3.0.0", + "@luma.gl/engine": "^8.4.0", + "@luma.gl/gltools": "^8.4.0", + "@luma.gl/shadertools": "^8.4.0", + "@luma.gl/webgl": "^8.4.0" + } + }, + "node_modules/@luma.gl/gltools": { + "version": "8.5.4", + "integrity": "sha512-JotiPuymQz2Xc41AYlS2moJC/EHxU+OX/OMKi0+/MeOlEFLsdochgTA0I64j8yofLTXdeiGCneGtD1Ao8fk+bw==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "@luma.gl/constants": "8.5.4", + "probe.gl": "^3.4.0" + } + }, + "node_modules/@luma.gl/shadertools": { + "version": "8.5.4", + "integrity": "sha512-rwLBLrACi75aWnuJm8rVKCQnJR2sMTCxHuexfjHJ7Uecl0vVcVJZT7c9EnCFaz5LUTNbdupvuhq0SKNckKiKmw==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "@math.gl/core": "^3.5.0" + } + }, + "node_modules/@luma.gl/webgl": { + "version": "8.5.4", + "integrity": "sha512-dWy4dhTbtvDO9zQBdx1Yb+DxNx/1JWV9rhhJxJUtTKbGZSX0RjkASTT6GBWMl5jrH1JYJefS1wswHmmPVXjK0Q==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "@luma.gl/constants": "8.5.4", + "@luma.gl/gltools": "8.5.4", + "probe.gl": "^3.4.0" + } + }, + "node_modules/@mapbox/extent": { + "version": "0.4.0", + "integrity": "sha512-MSoKw3qPceGuupn04sdaJrFeLKvcSETVLZCGS8JA9x6zXQL3FWiKaIXYIZEDXd5jpXpWlRxinCZIN49yRy0C9A==" + }, + "node_modules/@mapbox/geojson-coords": { + "version": "0.0.2", + "integrity": "sha512-YuVzpseee/P1T5BWyeVVPppyfmuXYHFwZHmybkqaMfu4BWlOf2cmMGKj2Rr92MwfSTOCSUA0PAsVGRG8akY0rg==", + "dependencies": { + "@mapbox/geojson-normalize": "0.0.1", + "geojson-flatten": "^1.0.4" + } + }, + "node_modules/@mapbox/geojson-extent": { + "version": "1.0.1", + "integrity": "sha512-hh8LEO3djT4fqfr8sSC6wKt+p0TMiu+KOLMBUiFOyj+zGq7+IXwQGl0ppCVDkyzCewyd9LoGe9zAvDxXrLfhLw==", + "dependencies": { + "@mapbox/extent": "0.4.0", + "@mapbox/geojson-coords": "0.0.2", + "rw": "~0.1.4", + "traverse": "~0.6.6" + }, + "bin": { + "geojson-extent": "bin/geojson-extent" + } + }, + "node_modules/@mapbox/geojson-extent/node_modules/rw": { + "version": "0.1.4", + "integrity": "sha512-vSj3D96kMcjNyqPcp65wBRIDImGSrUuMxngNNxvw8MQaO+aQ6llzRPH7XcJy5zrpb3wU++045+Uz/IDIM684iw==" + }, + "node_modules/@mapbox/geojson-normalize": { + "version": "0.0.1", + "integrity": "sha512-82V7YHcle8lhgIGqEWwtXYN5cy0QM/OHq3ypGhQTbvHR57DF0vMHMjjVSQKFfVXBe/yWCBZTyOuzvK7DFFnx5Q==", + "bin": { + "geojson-normalize": "geojson-normalize" + } + }, + "node_modules/@mapbox/geojson-rewind": { + "version": "0.5.2", + "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", + "dependencies": { + "get-stream": "^6.0.1", + "minimist": "^1.2.6" + }, + "bin": { + "geojson-rewind": "geojson-rewind" + } + }, + "node_modules/@mapbox/geojson-rewind/node_modules/get-stream": { + "version": "6.0.1", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mapbox/geojson-types": { + "version": "1.0.2", + "integrity": "sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==" + }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mapbox/mapbox-gl-supported": { + "version": "2.0.1", + "integrity": "sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==" + }, + "node_modules/@mapbox/martini": { + "version": "0.2.0", + "integrity": "sha512-7hFhtkb0KTLEls+TRw/rWayq5EeHtTaErgm/NskVoXmtgAQu/9D299aeyj6mzAR/6XUnYRp2lU+4IcrYRFjVsQ==" + }, + "node_modules/@mapbox/point-geometry": { + "version": "0.1.0", + "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "1.2.5", + "integrity": "sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.0", + "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==" + }, + "node_modules/@mapbox/vector-tile": { + "version": "1.3.1", + "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "dependencies": { + "@mapbox/point-geometry": "~0.1.0" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@math.gl/core": { + "version": "3.5.3", + "integrity": "sha512-TaSnvG0qFh1VxeNW5L58jSx0nJUMWMpUl6zo6Z3ScQzFySG5cicGOBzk/D40RkIZWPazCKCZ+ZThg5npSK9y3g==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "gl-matrix": "^3.0.0" + } + }, + "node_modules/@math.gl/culling": { + "version": "3.5.3", + "integrity": "sha512-ABpAcrvoIOLSm1EUkwgDem4RfO28HWPBs/+taZ/ZSpJG6KiVPklpKU1NCK+05HuJStkpFZ+XlWtehWU6FAMCyA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@math.gl/core": "3.5.3", + "gl-matrix": "^3.0.0" + } + }, + "node_modules/@math.gl/geospatial": { + "version": "3.5.3", + "integrity": "sha512-cnc8VMQrt30JmlG200VDJmmvSjaGW57gY9KEZ+raapxyyFyfDNuAuIrIxe+zbK66FbvFWTbJlDaNmKqVG+ohyw==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@math.gl/core": "3.5.3", + "gl-matrix": "^3.0.0" + } + }, + "node_modules/@math.gl/polygon": { + "version": "3.5.3", + "integrity": "sha512-VktscmyQg/Rd56nJk0Nj/UyvnPDbsnZNMWCdl3G5AYenYzLWy6h4FEWhLx8pD+Xw7VuFot8LR4WAK2TPzXzrWw==", + "dependencies": { + "@math.gl/core": "3.5.3" + } + }, + "node_modules/@math.gl/web-mercator": { + "version": "3.5.6", + "integrity": "sha512-siWHLJGp9o8fDEM1t0Rby+JXftl6il0z3927liWGzkHqFftXPHY858ShPy45ThDU8q5lyCftg8aVgrv4nfD+Zw==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "gl-matrix": "~3.3.0" + } + }, + "node_modules/@mdx-js/loader": { + "version": "1.6.22", + "integrity": "sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q==", + "dev": true, + "dependencies": { + "@mdx-js/mdx": "1.6.22", + "@mdx-js/react": "1.6.22", + "loader-utils": "2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/loader/node_modules/json5": { + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@mdx-js/loader/node_modules/loader-utils": { + "version": "2.0.0", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@mdx-js/mdx": { + "version": "1.6.22", + "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", + "dependencies": { + "@babel/core": "7.12.9", + "@babel/plugin-syntax-jsx": "7.12.1", + "@babel/plugin-syntax-object-rest-spread": "7.8.3", + "@mdx-js/util": "1.6.22", + "babel-plugin-apply-mdx-type-prop": "1.6.22", + "babel-plugin-extract-import-names": "1.6.22", + "camelcase-css": "2.0.1", + "detab": "2.0.4", + "hast-util-raw": "6.0.1", + "lodash.uniq": "4.5.0", + "mdast-util-to-hast": "10.0.1", + "remark-footnotes": "2.0.0", + "remark-mdx": "1.6.22", + "remark-parse": "8.0.3", + "remark-squeeze-paragraphs": "4.0.0", + "style-to-object": "0.3.0", + "unified": "9.2.0", + "unist-builder": "2.0.3", + "unist-util-visit": "2.0.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/@babel/core": { + "version": "7.12.9", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@mdx-js/mdx/node_modules/@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@mdx-js/mdx/node_modules/debug": { + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@mdx-js/mdx/node_modules/is-buffer": { + "version": "2.0.5", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/@mdx-js/mdx/node_modules/is-plain-obj": { + "version": "2.1.0", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@mdx-js/mdx/node_modules/json5": { + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@mdx-js/mdx/node_modules/ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@mdx-js/mdx/node_modules/parse-entities": { + "version": "2.0.0", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@mdx-js/mdx/node_modules/remark-parse": { + "version": "8.0.3", + "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", + "dependencies": { + "ccount": "^1.0.0", + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^2.0.0", + "vfile-location": "^3.0.0", + "xtend": "^4.0.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unified": { + "version": "9.2.0", + "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-is": { + "version": "4.1.0", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-remove-position": { + "version": "2.0.1", + "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", + "dependencies": { + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dependencies": { + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-visit": { + "version": "2.0.3", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/vfile": { + "version": "4.2.1", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/vfile-location": { + "version": "3.2.0", + "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/vfile-message": { + "version": "2.0.4", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "1.6.22", + "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + } + }, + "node_modules/@mdx-js/util": { + "version": "1.6.22", + "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dependencies": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@mrmlnc/readdir-enhanced/node_modules/glob-to-regexp": { + "version": "0.3.0", + "integrity": "sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==" + }, + "node_modules/@nicolo-ribaudo/chokidar-2": { + "version": "2.1.8-no-fsevents.3", + "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", + "dev": true, + "optional": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.3", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dependencies": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.scandir/node_modules/@nodelib/fs.stat": { + "version": "2.0.3", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.4", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "1.0.0", + "integrity": "sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ==", + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/fs/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.3.5", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/fs/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "1.0.7", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/map-workspaces": { + "version": "2.0.4", + "integrity": "sha512-bMo0aAfwhVwqoVM5UzX1DJnlvVvzDCHae821jv48L1EsrYwfOZChlqWYXEtto/+BkBXetPbEWgau++/brh4oVg==", + "dev": true, + "dependencies": { + "@npmcli/name-from-folder": "^1.0.1", + "glob": "^8.0.1", + "minimatch": "^5.0.1", + "read-package-json-fast": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/glob": { + "version": "8.0.3", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/minimatch": { + "version": "5.1.2", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/name-from-folder": { + "version": "1.0.1", + "integrity": "sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA==", + "dev": true + }, + "node_modules/@nrwl/cli": { + "version": "15.3.3", + "integrity": "sha512-ZWTmVP9H3ukppWWGaS/s3Nym2nOYgnt6eHtuUFNsroz8LesG5oFAJviOz9jDEM/b+pLIrvYfU5aAGZqrtM3Z2A==", + "dev": true, + "dependencies": { + "nx": "15.3.3" + } + }, + "node_modules/@nrwl/devkit": { + "version": "15.3.3", + "integrity": "sha512-48R9HAp6r6umWNXTlVTMsH94YYjU/XUPLDTtXBgKESMVbdq8Fk+HDHuN0thXG5dL6DFkXgD0MICLm3jSQU6xMw==", + "dev": true, + "dependencies": { + "@phenomnomnominal/tsquery": "4.1.1", + "ejs": "^3.1.7", + "ignore": "^5.0.4", + "semver": "7.3.4", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "nx": ">= 14 <= 16" + } + }, + "node_modules/@nrwl/devkit/node_modules/ignore": { + "version": "5.2.4", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@nrwl/devkit/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nrwl/devkit/node_modules/semver": { + "version": "7.3.4", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nrwl/devkit/node_modules/tslib": { + "version": "2.4.1", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true + }, + "node_modules/@nrwl/devkit/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@nrwl/tao": { + "version": "15.3.3", + "integrity": "sha512-f9+VwhlJ/7TWpjHSgoUOAA067uP9DmzABMY9HC5OREEDaCx+rzYEvbLAPv6cXzWw+6IYM6cyKw0zWSQrdEVrWg==", + "dev": true, + "dependencies": { + "nx": "15.3.3" + }, + "bin": { + "tao": "index.js" + } + }, + "node_modules/@octokit/auth-token": { + "version": "2.5.0", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "dependencies": { + "@octokit/types": "^6.0.3" + } + }, + "node_modules/@octokit/core": { + "version": "3.6.0", + "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "dependencies": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/core/node_modules/@octokit/request-error": { + "version": "2.1.0", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "dependencies": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "node_modules/@octokit/endpoint": { + "version": "6.0.12", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "dependencies": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/endpoint/node_modules/is-plain-object": { + "version": "5.0.0", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@octokit/graphql": { + "version": "4.8.0", + "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "dependencies": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "11.2.0", + "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==" + }, + "node_modules/@octokit/plugin-enterprise-rest": { + "version": "6.0.1", + "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", + "dev": true + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "2.17.0", + "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", + "dependencies": { + "@octokit/types": "^6.34.0" + }, + "peerDependencies": { + "@octokit/core": ">=2" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "1.0.4", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "5.13.0", + "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", + "dependencies": { + "@octokit/types": "^6.34.0", + "deprecation": "^2.3.1" + }, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/request": { + "version": "5.6.3", + "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "dependencies": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/request-error": { + "version": "3.0.2", + "integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==", + "dev": true, + "dependencies": { + "@octokit/types": "^8.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": { + "version": "14.0.0", + "integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==", + "dev": true + }, + "node_modules/@octokit/request-error/node_modules/@octokit/types": { + "version": "8.0.0", + "integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^14.0.0" + } + }, + "node_modules/@octokit/request/node_modules/@octokit/request-error": { + "version": "2.1.0", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "dependencies": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "node_modules/@octokit/request/node_modules/is-plain-object": { + "version": "5.0.0", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@octokit/rest": { + "version": "18.12.0", + "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", + "dependencies": { + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" + } + }, + "node_modules/@octokit/types": { + "version": "6.34.0", + "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", + "dependencies": { + "@octokit/openapi-types": "^11.2.0" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.0.4", + "integrity": "sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^3.2.1", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@phenomnomnominal/tsquery": { + "version": "4.1.1", + "integrity": "sha512-jjMmK1tnZbm1Jq5a7fBliM4gQwjxMU7TFoRNwIyzwlO+eHPRCFv/Nv+H/Gi1jc3WR7QURG8D5d0Tn12YGrUqBQ==", + "dev": true, + "dependencies": { + "esquery": "^1.0.1" + }, + "peerDependencies": { + "typescript": "^3 || ^4" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.20", + "integrity": "sha512-88p7+M0QGxKpmnkfXjS4V26AnoC/eiqZutE8GLdaI5X12NY75bXSdTY9NkmYb2Xyk1O+MmkuO6Frmsj84V6I8Q==", + "dev": true + }, + "node_modules/@popperjs/core": { + "version": "2.10.1", + "integrity": "sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@probe.gl/stats": { + "version": "3.4.0", + "integrity": "sha512-Gl37r9qGuiKadIvTZdSZvzCNOttJYw6RcY1oT0oDuB8r2uhuZAdSMQRQTy9FTinp6MY6O9wngGnV6EpQ8wSBAw==", + "dependencies": { + "@babel/runtime": "^7.0.0" + } + }, + "node_modules/@react-dnd/asap": { + "version": "4.0.0", + "integrity": "sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ==" + }, + "node_modules/@react-dnd/invariant": { + "version": "2.0.0", + "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "2.0.0", + "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" + }, + "node_modules/@react-icons/all-files": { + "version": "4.1.0", + "integrity": "sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/@samverschueren/stream-to-observable": { + "version": "0.3.1", + "integrity": "sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ==", + "dev": true, + "dependencies": { + "any-observable": "^0.3.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependenciesMeta": { + "rxjs": { + "optional": true + }, + "zen-observable": { + "optional": true + } + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "6.0.1", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@sinonjs/formatio": { + "version": "5.0.1", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "5.3.1", + "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.1", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "node_modules/@storybook/addon-actions": { + "version": "6.4.22", + "integrity": "sha512-t2w3iLXFul+R/1ekYxIEzUOZZmvEa7EzUAVAuCHP4i6x0jBnTTZ7sAIUVRaxVREPguH5IqI/2OklYhKanty2Yw==", + "dependencies": { + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/theming": "6.4.22", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "polished": "^4.0.5", + "prop-types": "^15.7.2", + "react-inspector": "^5.1.0", + "regenerator-runtime": "^0.13.7", + "telejson": "^5.3.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2", + "uuid-browser": "^3.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-actions/node_modules/polished": { + "version": "4.2.2", + "integrity": "sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==", + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/addon-backgrounds": { + "version": "6.4.22", + "integrity": "sha512-xQIV1SsjjRXP7P5tUoGKv+pul1EY8lsV7iBXQb5eGbp4AffBj3qoYBSZbX4uiazl21o0MQiQoeIhhaPVaFIIGg==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/theming": "6.4.22", + "core-js": "^3.8.2", + "global": "^4.4.0", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-controls": { + "version": "6.4.22", + "integrity": "sha512-f/M/W+7UTEUnr/L6scBMvksq+ZA8GTfh3bomE5FtWyOyaFppq9k8daKAvdYNlzXAOrUUsoZVJDgpb20Z2VBiSQ==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core-common": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/node-logger": "6.4.22", + "@storybook/store": "6.4.22", + "@storybook/theming": "6.4.22", + "core-js": "^3.8.2", + "lodash": "^4.17.21", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-docs": { + "version": "6.5.10", + "integrity": "sha512-1kgjo3f0vL6GN8fTwLL05M/q/kDdzvuqwhxPY/v5hubFb3aQZGr2yk9pRBaLAbs4bez0yG0ASXcwhYnrEZUppg==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.12.12", + "@babel/preset-env": "^7.12.11", + "@jest/transform": "^26.6.2", + "@mdx-js/react": "^1.6.22", + "@storybook/addons": "6.5.10", + "@storybook/api": "6.5.10", + "@storybook/components": "6.5.10", + "@storybook/core-common": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/docs-tools": "6.5.10", + "@storybook/mdx1-csf": "^0.0.1", + "@storybook/node-logger": "6.5.10", + "@storybook/postinstall": "6.5.10", + "@storybook/preview-web": "6.5.10", + "@storybook/source-loader": "6.5.10", + "@storybook/store": "6.5.10", + "@storybook/theming": "6.5.10", + "babel-loader": "^8.0.0", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "regenerator-runtime": "^0.13.7", + "remark-external-links": "^8.0.0", + "remark-slug": "^6.0.0", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@storybook/mdx2-csf": "^0.0.3", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@storybook/mdx2-csf": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/addons": { + "version": "6.5.10", + "integrity": "sha512-VD4tBCQ23PkSeDoxuHcKy0RfhIs3oMYjBacOZx7d0bvOzK9WjPyvE2ysDAh7r/ceqnwmWHAScIpE+I1RU7gl+g==", + "dev": true, + "dependencies": { + "@storybook/api": "6.5.10", + "@storybook/channels": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.10", + "@storybook/theming": "6.5.10", + "@types/webpack-env": "^1.16.0", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/api": { + "version": "6.5.10", + "integrity": "sha512-AkmgSPNEGdKp4oZA4KQ+RJsacw7GwfvjsVDnCkcXqS9zmSr/RNL0fhpcd60KKkmx/hGKPTDFpK3ZayxDrJ/h4A==", + "dev": true, + "dependencies": { + "@storybook/channels": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.10", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.5.10", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.12.0", + "telejson": "^6.0.8", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/channel-postmessage": { + "version": "6.5.10", + "integrity": "sha512-t9PTA0UzFvYa3IlOfpBOolfrRMPTjUMIeCQ6FNyM0aj5GqLKSvoQzP8NeoRpIrvyf6ljFKKdaMaZ3fiCvh45ag==", + "dev": true, + "dependencies": { + "@storybook/channels": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "core-js": "^3.8.2", + "global": "^4.4.0", + "qs": "^6.10.0", + "telejson": "^6.0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/channels": { + "version": "6.5.10", + "integrity": "sha512-lo26YZ6kWpHXLhuHJF4P/bICY7jD/rXEZqReKtGOSk1Lv99/xvG6pqmcy3hWLf3v3Dy/8otjRPSR7izFVIIZgQ==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/client-logger": { + "version": "6.5.10", + "integrity": "sha512-/xA0MHOevXev68hyLMQw8Qo8KczSIdXOxliAgrycMTkDmw5eKeA8TP7B8zP3wGuq/e3MrdD9/8MWhb/IQBNC3w==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2", + "global": "^4.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/components": { + "version": "6.5.10", + "integrity": "sha512-9OhgB8YQfGwOKjo/N96N5mrtJ6qDVVoEM1zuhea32tJUd2eYf0aSWpryA9VnOM0V1q/8DAoCg5rPBMYWMBU5uw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/theming": "6.5.10", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/core-common": { + "version": "6.5.10", + "integrity": "sha512-Bx+VKkfWdrAmD8T51Sjq/mMhRaiapBHcpG4cU5bc3DMbg+LF2/yrgqv/cjVu+m5gHAzYCac5D7gqzBgvG7Myww==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.10", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-decorators": "^7.12.12", + "@babel/plugin-proposal-export-default-from": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.7", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-proposal-private-property-in-object": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.12", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/preset-env": "^7.12.11", + "@babel/preset-react": "^7.12.10", + "@babel/preset-typescript": "^7.12.7", + "@babel/register": "^7.12.1", + "@storybook/node-logger": "6.5.10", + "@storybook/semver": "^7.3.2", + "@types/node": "^14.0.10 || ^16.0.0", + "@types/pretty-hrtime": "^1.0.0", + "babel-loader": "^8.0.0", + "babel-plugin-macros": "^3.0.1", + "babel-plugin-polyfill-corejs3": "^0.1.0", + "chalk": "^4.1.0", + "core-js": "^3.8.2", + "express": "^4.17.1", + "file-system-cache": "^1.0.5", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.0.4", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "handlebars": "^4.7.7", + "interpret": "^2.2.0", + "json5": "^2.1.3", + "lazy-universal-dotenv": "^3.0.1", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "slash": "^3.0.0", + "telejson": "^6.0.8", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2", + "webpack": "4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/core-events": { + "version": "6.5.10", + "integrity": "sha512-EVb1gO1172klVIAABLOoigFMx0V88uctY0K/qVCO8n6v+wd2+0Ccn63kl+gTxsAC3WZ8XhXh9q2w5ImHklVECw==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/csf": { + "version": "0.0.2--canary.4566f4d.1", + "integrity": "sha512-9OVvMVh3t9znYZwb0Svf/YQoxX2gVOeQTGe2bses2yj+a3+OJnCrUF3/hGv6Em7KujtOdL2LL+JnG49oMVGFgQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/node-logger": { + "version": "6.5.10", + "integrity": "sha512-bYswXIKV7Stru8vYfkjUMNN8UhF7Qg7NRsUvG5Djt5lLIae1XmUIgnH40mU/nW4X4BSfcR9MKxsSsngvn2WmQg==", + "dev": true, + "dependencies": { + "@types/npmlog": "^4.1.2", + "chalk": "^4.1.0", + "core-js": "^3.8.2", + "npmlog": "^5.0.1", + "pretty-hrtime": "^1.0.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/postinstall": { + "version": "6.5.10", + "integrity": "sha512-xqUdpnFHYkn8MgtV+QztvIsRWa6jQUk7QT1Mu17Y0S7PbslNGsuskRPHenHhACXBJF+TM86R+4BaAhnVYTmElw==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/preview-web": { + "version": "6.5.10", + "integrity": "sha512-sTC/o5gkvALOtcNgtApGKGN9EavvSxRHBeBh+5BQjV2qQ8ap+26RsfUizNBECAa2Jrn4osaDYn9HRhJLFL69WA==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.5.10", + "@storybook/channel-postmessage": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/store": "6.5.10", + "ansi-to-html": "^0.6.11", + "core-js": "^3.8.2", + "global": "^4.4.0", + "lodash": "^4.17.21", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7", + "synchronous-promise": "^2.0.15", + "ts-dedent": "^2.0.0", + "unfetch": "^4.2.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/router": { + "version": "6.5.10", + "integrity": "sha512-O+vNW/eEpYFF8eCg5jZjNQ6q2DKQVxqDRPCy9pJdEbvavMDZn6AFYgVK+VJe5F4211WW2yncOu922xObCxXJYg==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "6.5.10", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/source-loader": { + "version": "6.5.10", + "integrity": "sha512-1RxxRumpjs8VUUwES9LId+cuNQnixhZAcwCxd6jaKkTZbjiQCtAhXX6DBTjJGV1u/JnCsqEp5b1wB8j/EioNHw==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "core-js": "^3.8.2", + "estraverse": "^5.2.0", + "global": "^4.4.0", + "loader-utils": "^2.0.0", + "lodash": "^4.17.21", + "prettier": ">=2.2.1 <=2.3.0", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/source-loader/node_modules/loader-utils": { + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/store": { + "version": "6.5.10", + "integrity": "sha512-RswrSYh2IiKkytFPxP9AvP+hekjrvHK2ILvyDk2ZgduCN4n5ivsekOb+N3M2t+dq1eLuW9or5n2T4OWwAwjxxQ==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "slash": "^3.0.0", + "stable": "^0.1.8", + "synchronous-promise": "^2.0.15", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@storybook/theming": { + "version": "6.5.10", + "integrity": "sha512-BvTQBBcSEwKKcsVmF+Ol6v0RIQUr+bxP7gb10wtfBd23mZTEFA0C1N5FnZr/dDeiBKG1pvf1UKvoYA731y0BsA==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "6.5.10", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/@types/node": { + "version": "16.11.48", + "integrity": "sha512-Z9r9UWlNeNkYnxybm+1fc0jxUNjZqRekTAr1pG0qdXe9apT9yCiqk1c4VvKQJsFpnchU4+fLl25MabSLA2wxIw==", + "dev": true + }, + "node_modules/@storybook/addon-docs/node_modules/acorn": { + "version": "6.4.2", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/ansi-regex": { + "version": "5.0.1", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/addon-docs/node_modules/are-we-there-yet": { + "version": "2.0.0", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/addon-docs/node_modules/babel-plugin-macros": { + "version": "3.1.0", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/@storybook/addon-docs/node_modules/eslint-scope": { + "version": "4.0.3", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/estraverse": { + "version": "5.3.0", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/find-up": { + "version": "5.0.0", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/addon-docs/node_modules/fs-extra": { + "version": "9.1.0", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/addon-docs/node_modules/gauge": { + "version": "3.0.2", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/addon-docs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/addon-docs/node_modules/isobject": { + "version": "4.0.0", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/json5": { + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/addon-docs/node_modules/loader-runner": { + "version": "2.4.0", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/@storybook/addon-docs/node_modules/locate-path": { + "version": "6.0.0", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/addon-docs/node_modules/npmlog": { + "version": "5.0.1", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/p-limit": { + "version": "3.1.0", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/addon-docs/node_modules/p-locate": { + "version": "5.0.0", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/addon-docs/node_modules/path-exists": { + "version": "4.0.0", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/addon-docs/node_modules/pkg-dir": { + "version": "5.0.0", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/addon-docs/node_modules/prettier": { + "version": "2.3.0", + "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/qs": { + "version": "6.11.0", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@storybook/addon-docs/node_modules/readable-stream": { + "version": "3.6.0", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@storybook/addon-docs/node_modules/resolve-from": { + "version": "5.0.0", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/addon-docs/node_modules/schema-utils": { + "version": "1.0.0", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@storybook/addon-docs/node_modules/slash": { + "version": "3.0.0", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/addon-docs/node_modules/source-map": { + "version": "0.6.1", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/string-width": { + "version": "4.2.3", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/addon-docs/node_modules/strip-ansi": { + "version": "6.0.1", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/addon-docs/node_modules/telejson": { + "version": "6.0.8", + "integrity": "sha512-nerNXi+j8NK1QEfBHtZUN/aLdDcyupA//9kAboYLrtzZlPLpUfqbVGWb9zz91f/mIjRbAYhbgtnJHY8I1b5MBg==", + "dev": true, + "dependencies": { + "@types/is-function": "^1.0.0", + "global": "^4.4.0", + "is-function": "^1.0.2", + "is-regex": "^1.1.2", + "is-symbol": "^1.0.3", + "isobject": "^4.0.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3" + } + }, + "node_modules/@storybook/addon-docs/node_modules/terser-webpack-plugin": { + "version": "1.4.5", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "dependencies": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/@storybook/addon-docs/node_modules/webpack": { + "version": "4.46.0", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + }, + "webpack-command": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-docs/node_modules/webpack-sources": { + "version": "1.4.3", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/@storybook/addon-essentials": { + "version": "6.4.22", + "integrity": "sha512-GTv291fqvWq2wzm7MruBvCGuWaCUiuf7Ca3kzbQ/WqWtve7Y/1PDsqRNQLGZrQxkXU0clXCqY1XtkTrtA3WGFQ==", + "dev": true, + "dependencies": { + "@storybook/addon-actions": "6.4.22", + "@storybook/addon-backgrounds": "6.4.22", + "@storybook/addon-controls": "6.4.22", + "@storybook/addon-docs": "6.4.22", + "@storybook/addon-measure": "6.4.22", + "@storybook/addon-outline": "6.4.22", + "@storybook/addon-toolbars": "6.4.22", + "@storybook/addon-viewport": "6.4.22", + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/node-logger": "6.4.22", + "core-js": "^3.8.2", + "regenerator-runtime": "^0.13.7", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@babel/core": "^7.9.6", + "@storybook/vue": "6.4.22", + "@storybook/web-components": "6.4.22", + "babel-loader": "^8.0.0", + "lit-html": "^1.4.1 || ^2.0.0-rc.3", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0", + "webpack": "*" + }, + "peerDependenciesMeta": { + "@storybook/vue": { + "optional": true + }, + "@storybook/web-components": { + "optional": true + }, + "lit-html": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-essentials/node_modules/@storybook/addon-docs": { + "version": "6.4.22", + "integrity": "sha512-9j+i+W+BGHJuRe4jUrqk6ubCzP4fc1xgFS2o8pakRiZgPn5kUQPdkticmsyh1XeEJifwhqjKJvkEDrcsleytDA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.10", + "@babel/generator": "^7.12.11", + "@babel/parser": "^7.12.11", + "@babel/plugin-transform-react-jsx": "^7.12.12", + "@babel/preset-env": "^7.12.11", + "@jest/transform": "^26.6.2", + "@mdx-js/loader": "^1.6.22", + "@mdx-js/mdx": "^1.6.22", + "@mdx-js/react": "^1.6.22", + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/builder-webpack4": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/csf-tools": "6.4.22", + "@storybook/node-logger": "6.4.22", + "@storybook/postinstall": "6.4.22", + "@storybook/preview-web": "6.4.22", + "@storybook/source-loader": "6.4.22", + "@storybook/store": "6.4.22", + "@storybook/theming": "6.4.22", + "acorn": "^7.4.1", + "acorn-jsx": "^5.3.1", + "acorn-walk": "^7.2.0", + "core-js": "^3.8.2", + "doctrine": "^3.0.0", + "escodegen": "^2.0.0", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "html-tags": "^3.1.0", + "js-string-escape": "^1.0.1", + "loader-utils": "^2.0.0", + "lodash": "^4.17.21", + "nanoid": "^3.1.23", + "p-limit": "^3.1.0", + "prettier": ">=2.2.1 <=2.3.0", + "prop-types": "^15.7.2", + "react-element-to-jsx-string": "^14.3.4", + "regenerator-runtime": "^0.13.7", + "remark-external-links": "^8.0.0", + "remark-slug": "^6.0.0", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@storybook/angular": "6.4.22", + "@storybook/html": "6.4.22", + "@storybook/react": "6.4.22", + "@storybook/vue": "6.4.22", + "@storybook/vue3": "6.4.22", + "@storybook/web-components": "6.4.22", + "lit": "^2.0.0", + "lit-html": "^1.4.1 || ^2.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0", + "svelte": "^3.31.2", + "sveltedoc-parser": "^4.1.0", + "vue": "^2.6.10 || ^3.0.0", + "webpack": "*" + }, + "peerDependenciesMeta": { + "@storybook/angular": { + "optional": true + }, + "@storybook/html": { + "optional": true + }, + "@storybook/react": { + "optional": true + }, + "@storybook/vue": { + "optional": true + }, + "@storybook/vue3": { + "optional": true + }, + "@storybook/web-components": { + "optional": true + }, + "lit": { + "optional": true + }, + "lit-html": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "svelte": { + "optional": true + }, + "sveltedoc-parser": { + "optional": true + }, + "vue": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-essentials/node_modules/acorn": { + "version": "7.4.1", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@storybook/addon-essentials/node_modules/escodegen": { + "version": "2.0.0", + "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/@storybook/addon-essentials/node_modules/esprima": { + "version": "4.0.1", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@storybook/addon-essentials/node_modules/estraverse": { + "version": "5.3.0", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@storybook/addon-essentials/node_modules/json5": { + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/addon-essentials/node_modules/loader-utils": { + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@storybook/addon-essentials/node_modules/nanoid": { + "version": "3.3.4", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/@storybook/addon-essentials/node_modules/p-limit": { + "version": "3.1.0", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/addon-essentials/node_modules/prettier": { + "version": "2.3.0", + "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@storybook/addon-essentials/node_modules/source-map": { + "version": "0.6.1", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@storybook/addon-knobs": { + "version": "6.3.1", + "integrity": "sha512-2GGGnQSPXXUhHHYv4IW6pkyQlCPYXKYiyGzfhV7Zhs95M2Ban08OA6KLmliMptWCt7U9tqTO8dB5u0C2cWmCTw==", + "deprecated": "deprecating @storybook/addon-knobs in favor of @storybook/addon-controls", + "dependencies": { + "copy-to-clipboard": "^3.3.1", + "core-js": "^3.8.2", + "escape-html": "^1.0.3", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.20", + "prop-types": "^15.7.2", + "qs": "^6.10.0", + "react-colorful": "^5.1.2", + "react-lifecycles-compat": "^3.0.4", + "react-select": "^3.2.0" + }, + "peerDependencies": { + "@storybook/addons": "^6.3.0", + "@storybook/api": "^6.3.0", + "@storybook/components": "^6.3.0", + "@storybook/core-events": "^6.3.0", + "@storybook/theming": "^6.3.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-knobs/node_modules/qs": { + "version": "6.11.0", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@storybook/addon-links": { + "version": "6.4.22", + "integrity": "sha512-OSOyDnTXnmcplJHlXTYUTMkrfpLqxtHp2R69IXfAyI1e8WNDb79mXflrEXDA/RSNEliLkqYwCyYby7gDMGds5Q==", + "dependencies": { + "@storybook/addons": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/router": "6.4.22", + "@types/qs": "^6.9.5", + "core-js": "^3.8.2", + "global": "^4.4.0", + "prop-types": "^15.7.2", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-links/node_modules/qs": { + "version": "6.11.0", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@storybook/addon-measure": { + "version": "6.4.22", + "integrity": "sha512-CjDXoCNIXxNfXfgyJXPc0McjCcwN1scVNtHa9Ckr+zMjiQ8pPHY7wDZCQsG69KTqcWHiVfxKilI82456bcHYhQ==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "core-js": "^3.8.2", + "global": "^4.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-outline": { + "version": "6.4.22", + "integrity": "sha512-VIMEzvBBRbNnupGU7NV0ahpFFb6nKVRGYWGREjtABdFn2fdKr1YicOHFe/3U7hRGjb5gd+VazSvyUvhaKX9T7Q==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-toolbars": { + "version": "6.4.22", + "integrity": "sha512-FFyj6XDYpBBjcUu6Eyng7R805LUbVclEfydZjNiByAoDVyCde9Hb4sngFxn/T4fKAfBz/32HKVXd5iq4AHYtLg==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/theming": "6.4.22", + "core-js": "^3.8.2", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-viewport": { + "version": "6.4.22", + "integrity": "sha512-6jk0z49LemeTblez5u2bYXYr6U+xIdLbywe3G283+PZCBbEDE6eNYy2d2HDL+LbCLbezJBLYPHPalElphjJIcw==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/theming": "6.4.22", + "core-js": "^3.8.2", + "global": "^4.4.0", + "memoizerific": "^1.11.3", + "prop-types": "^15.7.2", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addons": { + "version": "6.4.22", + "integrity": "sha512-P/R+Jsxh7pawKLYo8MtE3QU/ilRFKbtCewV/T1o5U/gm8v7hKQdFz3YdRMAra4QuCY8bQIp7MKd2HrB5aH5a1A==", + "dependencies": { + "@storybook/api": "6.4.22", + "@storybook/channels": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/router": "6.4.22", + "@storybook/theming": "6.4.22", + "@types/webpack-env": "^1.16.0", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/api": { + "version": "6.4.22", + "integrity": "sha512-lAVI3o2hKupYHXFTt+1nqFct942up5dHH6YD7SZZJGyW21dwKC3HK1IzCsTawq3fZAKkgWFgmOO649hKk60yKg==", + "dependencies": { + "@storybook/channels": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/router": "6.4.22", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.4.22", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.12.0", + "telejson": "^5.3.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/builder-webpack4": { + "version": "6.4.22", + "integrity": "sha512-A+GgGtKGnBneRFSFkDarUIgUTI8pYFdLmUVKEAGdh2hL+vLXAz9A46sEY7C8LQ85XWa8TKy3OTDxqR4+4iWj3A==", + "dependencies": { + "@babel/core": "^7.12.10", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-decorators": "^7.12.12", + "@babel/plugin-proposal-export-default-from": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.7", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.12", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/plugin-transform-template-literals": "^7.12.1", + "@babel/preset-env": "^7.12.11", + "@babel/preset-react": "^7.12.10", + "@babel/preset-typescript": "^7.12.7", + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/channel-postmessage": "6.4.22", + "@storybook/channels": "6.4.22", + "@storybook/client-api": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core-common": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/node-logger": "6.4.22", + "@storybook/preview-web": "6.4.22", + "@storybook/router": "6.4.22", + "@storybook/semver": "^7.3.2", + "@storybook/store": "6.4.22", + "@storybook/theming": "6.4.22", + "@storybook/ui": "6.4.22", + "@types/node": "^14.0.10", + "@types/webpack": "^4.41.26", + "autoprefixer": "^9.8.6", + "babel-loader": "^8.0.0", + "babel-plugin-macros": "^2.8.0", + "babel-plugin-polyfill-corejs3": "^0.1.0", + "case-sensitive-paths-webpack-plugin": "^2.3.0", + "core-js": "^3.8.2", + "css-loader": "^3.6.0", + "file-loader": "^6.2.0", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^4.1.6", + "glob": "^7.1.6", + "glob-promise": "^3.4.0", + "global": "^4.4.0", + "html-webpack-plugin": "^4.0.0", + "pnp-webpack-plugin": "1.6.4", + "postcss": "^7.0.36", + "postcss-flexbugs-fixes": "^4.2.1", + "postcss-loader": "^4.2.0", + "raw-loader": "^4.0.2", + "stable": "^0.1.8", + "style-loader": "^1.3.0", + "terser-webpack-plugin": "^4.2.3", + "ts-dedent": "^2.0.0", + "url-loader": "^4.1.1", + "util-deprecate": "^1.0.2", + "webpack": "4", + "webpack-dev-middleware": "^3.7.3", + "webpack-filter-warnings-plugin": "^1.2.1", + "webpack-hot-middleware": "^2.25.1", + "webpack-virtual-modules": "^0.2.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/@types/node": { + "version": "14.18.16", + "integrity": "sha512-X3bUMdK/VmvrWdoTkz+VCn6nwKwrKCFTHtqwBIaQJNx4RUIBBUFXM00bqPz/DsDd+Icjmzm6/tyYZzeGVqb6/Q==" + }, + "node_modules/@storybook/builder-webpack4/node_modules/acorn": { + "version": "6.4.2", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/ansi-styles": { + "version": "3.2.1", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/chalk": { + "version": "2.4.2", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/css-loader": { + "version": "3.6.0", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "dependencies": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/css-loader/node_modules/semver": { + "version": "6.3.0", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/eslint-scope": { + "version": "4.0.3", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/find-up": { + "version": "5.0.0", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/fork-ts-checker-webpack-plugin": { + "version": "4.1.6", + "integrity": "sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==", + "dependencies": { + "@babel/code-frame": "^7.5.5", + "chalk": "^2.4.1", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "engines": { + "node": ">=6.11.5", + "yarn": ">=1.0.0" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/html-webpack-plugin": { + "version": "4.5.2", + "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", + "dependencies": { + "@types/html-minifier-terser": "^5.0.0", + "@types/tapable": "^1.0.5", + "@types/webpack": "^4.41.8", + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.20", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + }, + "engines": { + "node": ">=6.9" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/icss-utils": { + "version": "4.1.1", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dependencies": { + "postcss": "^7.0.14" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/json5": { + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/loader-runner": { + "version": "2.4.0", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/locate-path": { + "version": "6.0.0", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/normalize-path": { + "version": "3.0.0", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/p-limit": { + "version": "3.1.0", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/p-locate": { + "version": "5.0.0", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/path-exists": { + "version": "4.0.0", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/postcss": { + "version": "7.0.39", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/postcss-modules-extract-imports": { + "version": "2.0.0", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dependencies": { + "postcss": "^7.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@storybook/builder-webpack4/node_modules/postcss-modules-local-by-default": { + "version": "3.0.3", "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", "dependencies": { "icss-utils": "^4.1.1", @@ -11083,8 +14203,8 @@ } }, "node_modules/@storybook/builder-webpack4/node_modules/style-loader/node_modules/loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -11361,12 +14481,9 @@ } }, "node_modules/@storybook/builder-webpack5/node_modules/json5": { - "version": "2.2.0", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, "bin": { "json5": "lib/cli.js" }, @@ -11375,8 +14492,8 @@ } }, "node_modules/@storybook/builder-webpack5/node_modules/loader-utils": { - "version": "2.0.0", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -11462,12 +14579,13 @@ } }, "node_modules/@storybook/builder-webpack5/node_modules/terser": { - "version": "5.9.0", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "version": "5.14.2", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -11511,14 +14629,6 @@ } } }, - "node_modules/@storybook/builder-webpack5/node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware": { "version": "4.3.0", "integrity": "sha512-PjwyVY95/bhBh6VUqt6z4THplYcsvQ8YNNBTBM873xLVmw8FLeALn0qurHbs9EmcfhzQis/eoqypSnZeuUz26w==", @@ -11570,8 +14680,8 @@ } }, "node_modules/@storybook/channel-postmessage/node_modules/qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -11645,8 +14755,8 @@ } }, "node_modules/@storybook/client-api/node_modules/qs": { - "version": "6.10.1", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "version": "6.11.0", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -11812,8 +14922,8 @@ } }, "node_modules/@storybook/core-client/node_modules/qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -11958,8 +15068,8 @@ } }, "node_modules/@storybook/core-common/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -12472,6 +15582,243 @@ "node": ">=10.13.0" } }, + "node_modules/@storybook/docs-tools": { + "version": "6.5.10", + "integrity": "sha512-/bvYgOO+CxMEcHifkjJg0A60OTGOhcjGxnsB1h0gJuxMrqA/7Qwc108bFmPiX0eiD1BovFkZLJV4O6OY7zP5Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/store": "6.5.10", + "core-js": "^3.8.2", + "doctrine": "^3.0.0", + "lodash": "^4.17.21", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/docs-tools/node_modules/@storybook/addons": { + "version": "6.5.10", + "integrity": "sha512-VD4tBCQ23PkSeDoxuHcKy0RfhIs3oMYjBacOZx7d0bvOzK9WjPyvE2ysDAh7r/ceqnwmWHAScIpE+I1RU7gl+g==", + "dev": true, + "dependencies": { + "@storybook/api": "6.5.10", + "@storybook/channels": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.10", + "@storybook/theming": "6.5.10", + "@types/webpack-env": "^1.16.0", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/docs-tools/node_modules/@storybook/api": { + "version": "6.5.10", + "integrity": "sha512-AkmgSPNEGdKp4oZA4KQ+RJsacw7GwfvjsVDnCkcXqS9zmSr/RNL0fhpcd60KKkmx/hGKPTDFpK3ZayxDrJ/h4A==", + "dev": true, + "dependencies": { + "@storybook/channels": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.10", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.5.10", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.12.0", + "telejson": "^6.0.8", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/docs-tools/node_modules/@storybook/channels": { + "version": "6.5.10", + "integrity": "sha512-lo26YZ6kWpHXLhuHJF4P/bICY7jD/rXEZqReKtGOSk1Lv99/xvG6pqmcy3hWLf3v3Dy/8otjRPSR7izFVIIZgQ==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/docs-tools/node_modules/@storybook/client-logger": { + "version": "6.5.10", + "integrity": "sha512-/xA0MHOevXev68hyLMQw8Qo8KczSIdXOxliAgrycMTkDmw5eKeA8TP7B8zP3wGuq/e3MrdD9/8MWhb/IQBNC3w==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2", + "global": "^4.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/docs-tools/node_modules/@storybook/core-events": { + "version": "6.5.10", + "integrity": "sha512-EVb1gO1172klVIAABLOoigFMx0V88uctY0K/qVCO8n6v+wd2+0Ccn63kl+gTxsAC3WZ8XhXh9q2w5ImHklVECw==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/docs-tools/node_modules/@storybook/csf": { + "version": "0.0.2--canary.4566f4d.1", + "integrity": "sha512-9OVvMVh3t9znYZwb0Svf/YQoxX2gVOeQTGe2bses2yj+a3+OJnCrUF3/hGv6Em7KujtOdL2LL+JnG49oMVGFgQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/@storybook/docs-tools/node_modules/@storybook/router": { + "version": "6.5.10", + "integrity": "sha512-O+vNW/eEpYFF8eCg5jZjNQ6q2DKQVxqDRPCy9pJdEbvavMDZn6AFYgVK+VJe5F4211WW2yncOu922xObCxXJYg==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "6.5.10", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/docs-tools/node_modules/@storybook/store": { + "version": "6.5.10", + "integrity": "sha512-RswrSYh2IiKkytFPxP9AvP+hekjrvHK2ILvyDk2ZgduCN4n5ivsekOb+N3M2t+dq1eLuW9or5n2T4OWwAwjxxQ==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "slash": "^3.0.0", + "stable": "^0.1.8", + "synchronous-promise": "^2.0.15", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/docs-tools/node_modules/@storybook/theming": { + "version": "6.5.10", + "integrity": "sha512-BvTQBBcSEwKKcsVmF+Ol6v0RIQUr+bxP7gb10wtfBd23mZTEFA0C1N5FnZr/dDeiBKG1pvf1UKvoYA731y0BsA==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "6.5.10", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/docs-tools/node_modules/isobject": { + "version": "4.0.0", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@storybook/docs-tools/node_modules/qs": { + "version": "6.11.0", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@storybook/docs-tools/node_modules/slash": { + "version": "3.0.0", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/docs-tools/node_modules/telejson": { + "version": "6.0.8", + "integrity": "sha512-nerNXi+j8NK1QEfBHtZUN/aLdDcyupA//9kAboYLrtzZlPLpUfqbVGWb9zz91f/mIjRbAYhbgtnJHY8I1b5MBg==", + "dev": true, + "dependencies": { + "@types/is-function": "^1.0.0", + "global": "^4.4.0", + "is-function": "^1.0.2", + "is-regex": "^1.1.2", + "is-symbol": "^1.0.3", + "isobject": "^4.0.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3" + } + }, "node_modules/@storybook/manager-webpack4": { "version": "6.4.22", "integrity": "sha512-nzhDMJYg0vXdcG0ctwE6YFZBX71+5NYaTGkxg3xT7gbgnP1YFXn9gVODvgq3tPb3gcRapjyOIxUa20rV+r8edA==", @@ -12640,8 +15987,8 @@ } }, "node_modules/@storybook/manager-webpack4/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -12830,8 +16177,8 @@ } }, "node_modules/@storybook/manager-webpack4/node_modules/style-loader/node_modules/loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -13065,12 +16412,9 @@ } }, "node_modules/@storybook/manager-webpack5/node_modules/json5": { - "version": "2.2.0", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, "bin": { "json5": "lib/cli.js" }, @@ -13079,8 +16423,8 @@ } }, "node_modules/@storybook/manager-webpack5/node_modules/loader-utils": { - "version": "2.0.0", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -13224,12 +16568,13 @@ } }, "node_modules/@storybook/manager-webpack5/node_modules/terser": { - "version": "5.9.0", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "version": "5.14.2", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -13273,14 +16618,6 @@ } } }, - "node_modules/@storybook/manager-webpack5/node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/@storybook/manager-webpack5/node_modules/webpack-dev-middleware": { "version": "4.3.0", "integrity": "sha512-PjwyVY95/bhBh6VUqt6z4THplYcsvQ8YNNBTBM873xLVmw8FLeALn0qurHbs9EmcfhzQis/eoqypSnZeuUz26w==", @@ -13314,6 +16651,59 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/@storybook/mdx1-csf": { + "version": "0.0.1", + "integrity": "sha512-4biZIWWzoWlCarMZmTpqcJNgo/RBesYZwGFbQeXiGYsswuvfWARZnW9RE9aUEMZ4XPn7B1N3EKkWcdcWe/K2tg==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.12.11", + "@babel/parser": "^7.12.11", + "@babel/preset-env": "^7.12.11", + "@babel/types": "^7.12.11", + "@mdx-js/mdx": "^1.6.22", + "@types/lodash": "^4.14.167", + "js-string-escape": "^1.0.1", + "loader-utils": "^2.0.0", + "lodash": "^4.17.21", + "prettier": ">=2.2.1 <=2.3.0", + "ts-dedent": "^2.0.0" + } + }, + "node_modules/@storybook/mdx1-csf/node_modules/json5": { + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/mdx1-csf/node_modules/loader-utils": { + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@storybook/mdx1-csf/node_modules/prettier": { + "version": "2.3.0", + "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@storybook/node-logger": { "version": "6.4.22", "integrity": "sha512-sUXYFqPxiqM7gGH7gBXvO89YEO42nA4gBicJKZjj9e+W4QQLrftjF9l+mAw2K0mVE10Bn7r4pfs5oEZ0aruyyA==", @@ -13459,8 +16849,8 @@ } }, "node_modules/@storybook/preview-web/node_modules/qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -13766,8 +17156,8 @@ } }, "node_modules/@storybook/react/node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -13813,11 +17203,8 @@ } }, "node_modules/@storybook/react/node_modules/json5": { - "version": "2.2.0", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dependencies": { - "minimist": "^1.2.5" - }, + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -14032,8 +17419,8 @@ } }, "node_modules/@storybook/router/node_modules/qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -14186,8 +17573,8 @@ } }, "node_modules/@storybook/source-loader/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -14197,8 +17584,8 @@ } }, "node_modules/@storybook/source-loader/node_modules/loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -14371,8 +17758,8 @@ } }, "node_modules/@storybook/ui/node_modules/qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -14741,12 +18128,9 @@ } }, "node_modules/@svgr/webpack/node_modules/json5": { - "version": "2.1.3", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, "bin": { "json5": "lib/cli.js" }, @@ -14755,8 +18139,8 @@ } }, "node_modules/@svgr/webpack/node_modules/loader-utils": { - "version": "2.0.0", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -14947,6 +18331,27 @@ "@babel/types": "^7.3.0" } }, + "node_modules/@types/base16": { + "version": "1.0.2", + "integrity": "sha512-oYO/U4VD1DavwrKuCSQWdLG+5K22SLPem2OQaHmFcQuwHoVeGC+JGVRji2MUqZUAIQZHEonOeVfAX09hYiLsdg==" + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/cheerio": { "version": "0.22.21", "integrity": "sha512-aGI3DfswwqgKPiEOTaiHV2ZPC9KEhprpgEbJnv0fZl3SGX0cGgEva1126dGrMC6AJM6v/aihlUgJn9M5DbDZ/Q==", @@ -14969,6 +18374,23 @@ "version": "1.1.1", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, + "node_modules/@types/connect": { + "version": "3.4.35", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.3.5", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, "node_modules/@types/d3": { "version": "3.5.38", "integrity": "sha512-O/gRkjWULp3xVX8K85V0H3tsSGole0WYt77KVpGZO2xTGLuVFuvE6JIsIli3fvFHCYBhGFn/8OHEEyMYF+QehA==" @@ -15075,6 +18497,27 @@ "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", "dev": true }, + "node_modules/@types/express": { + "version": "4.17.13", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.30", + "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, "node_modules/@types/fetch-mock": { "version": "7.3.5", "integrity": "sha512-sLecm9ohBdGIpYUP9rWk5/XIKY2xHMYTBJIcJuBBM8IJWnYoQ1DAj8F4OVjnfD0API1drlkWEV0LPNk+ACuhsg==" @@ -15111,8 +18554,8 @@ } }, "node_modules/@types/history": { - "version": "4.7.6", - "integrity": "sha512-GRTZLeLJ8ia00ZH8mxMO8t0aC9M1N9bN461Z2eaRurJo6Fpa+utgCwLzI4jQHcrdzuzp5WPN9jRwpsCQ1VhJ5w==", + "version": "4.7.11", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", "dev": true }, "node_modules/@types/hoist-non-react-statics": { @@ -15128,8 +18571,8 @@ "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==" }, "node_modules/@types/http-proxy": { - "version": "1.17.7", - "integrity": "sha512-9hdj6iXH64tHSLTY+Vt2eYOGzSogC+JQ2H7bdPWkuh7KXP5qLllWx++t+K9Wk556c3dkDdPws/SpMRi0sdCT1w==", + "version": "1.17.9", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", "dev": true, "dependencies": { "@types/node": "*" @@ -15183,9 +18626,8 @@ "dev": true }, "node_modules/@types/json-bigint": { - "version": "1.0.0", - "integrity": "sha512-WW+0cfH3ovFN6ROV+p/Xfw36dT6s16hbXBYIG49PYw6+j6e+AkpqYccctgxwyicBmC8CZDBnPhOH94shFhXgHQ==", - "dev": true + "version": "1.0.1", + "integrity": "sha512-zpchZLNsNuzJHi6v64UBoFWAvQlPhch7XAi36FkH6tL1bbbmimIF+cS7vwkzY4u5RaSWMoflQfu+TshMPPw8uw==" }, "node_modules/@types/json-schema": { "version": "7.0.9", @@ -15197,8 +18639,8 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.14.149", - "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==" + "version": "4.14.182", + "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==" }, "node_modules/@types/lodash.get": { "version": "4.4.6", @@ -15207,6 +18649,13 @@ "@types/lodash": "*" } }, + "node_modules/@types/mapbox-gl": { + "version": "2.7.6", + "integrity": "sha512-EPIfNO7WApXaFM7DuJBj+kpXmqffqJHMJ3Q9gbV/nNL23XHR0PC5CCDYbAFa4tKErm0xJd9C5kPLF6KvA/cRcA==", + "dependencies": { + "@types/geojson": "*" + } + }, "node_modules/@types/math-expression-evaluator": { "version": "1.2.1", "integrity": "sha512-H6IG9R0jU16nR3N24UpL7X40aDcUl5eTncBSd/itwz6rWI4nNzMcNYreHj0MnKlHSga1Iq1AqjSuY67EhiN+Zw==" @@ -15218,6 +18667,11 @@ "@types/unist": "*" } }, + "node_modules/@types/mime": { + "version": "3.0.1", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, "node_modules/@types/minimatch": { "version": "3.0.5", "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" @@ -15236,8 +18690,8 @@ "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==" }, "node_modules/@types/node-fetch": { - "version": "2.6.1", - "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", + "version": "2.6.2", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", "dependencies": { "@types/node": "*", "form-data": "^3.0.0" @@ -15285,8 +18739,8 @@ "integrity": "sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==" }, "node_modules/@types/prop-types": { - "version": "15.7.4", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + "version": "15.7.5", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/q": { "version": "1.5.2", @@ -15297,6 +18751,11 @@ "version": "6.9.7", "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, "node_modules/@types/react": { "version": "16.9.43", "integrity": "sha512-PxshAFcnJqIWYpJbLPriClH53Z2WlJcVZE+NP2etUtWQs2s7yIMj3/LDKZT/5CHJ/F62iyjVCDu2H3jHEXIxSg==", @@ -15347,9 +18806,8 @@ } }, "node_modules/@types/react-redux": { - "version": "7.1.10", - "integrity": "sha512-lmt2BPf0fFuYrXg1JM4udUd4sCmqnTlNUIxC7B6RIBTzmMuv/MxOfumGNUx1UyzVZieEZ2ttCQvFfh/3eUHvrQ==", - "dev": true, + "version": "7.1.25", + "integrity": "sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -15367,11 +18825,11 @@ } }, "node_modules/@types/react-router-dom": { - "version": "5.1.5", - "integrity": "sha512-ArBM4B1g3BWLGbaGvwBGO75GNFbLDUthrDojV2vHLih/Tq8M+tgvY1DSwkuNrPSwdp/GUL93WSEpTZs8nVyJLw==", + "version": "5.3.3", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", "dev": true, "dependencies": { - "@types/history": "*", + "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router": "*" } @@ -15386,14 +18844,6 @@ "@types/react-transition-group": "*" } }, - "node_modules/@types/react-sticky": { - "version": "6.0.3", - "integrity": "sha512-tW0Y1hTr2Tao4yX58iKl0i7BaqrdObGXAzsyzd8VGVrWVEgbQuV6P6QKVd/kFC7FroXyelftiVNJ09pnfkcjww==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/react-syntax-highlighter": { "version": "11.0.5", "integrity": "sha512-VIOi9i2Oj5XsmWWoB72p3KlZoEbdRAcechJa8Ztebw7bDl2YmR+odxIqhtJGp1q2EozHs02US+gzxJ9nuf56qg==", @@ -15442,8 +18892,8 @@ } }, "node_modules/@types/react-window": { - "version": "1.8.2", - "integrity": "sha512-gP1xam68Wc4ZTAee++zx6pTdDAH08rAkQrWm4B4F/y6hhmlT9Mgx2q8lTCXnrPHXsr15XjRN9+K2DLKcz44qEQ==", + "version": "1.8.5", + "integrity": "sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==", "dev": true, "dependencies": { "@types/react": "*" @@ -15476,10 +18926,6 @@ "redux": "^4.0.5" } }, - "node_modules/@types/resize-observer-browser": { - "version": "0.1.6", - "integrity": "sha512-61IfTac0s9jvNtBCpyo86QeaN8qqpMGHdK0uGKCCIy2dt5/Yk84VduHIdWAcmkC5QvdkPL0p5eWYgUZtHKKUVg==" - }, "node_modules/@types/retry": { "version": "0.12.1", "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", @@ -15493,6 +18939,23 @@ "version": "2.4.30", "integrity": "sha512-AnxLHewubLVzoF/A4qdxBGHCKifw8cY32iro3DQX9TPcetE95zBeVt3jnsvtvAUf1vwzMfwzp4t/L2yqPlnjkQ==" }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, "node_modules/@types/shortid": { "version": "0.0.29", "integrity": "sha512-9BCYD9btg2CY4kPcpMQ+vCR8U6V8f/KvixYD5ZbxoWlkhddNF5IeZMVL3p+QFUkg+Hb+kPAG9Jgk4bnnF1v/Fw==", @@ -15516,6 +18979,14 @@ "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", "dev": true }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/source-list-map": { "version": "0.1.2", "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==" @@ -15577,8 +19048,8 @@ } }, "node_modules/@types/webpack-env": { - "version": "1.16.2", - "integrity": "sha512-vKx7WNQNZDyJveYcHAm9ZxhqSGLYwoyLhrHjLBOkw3a7cT76sTdjgtwyijhk1MaHyRIuSztcVwrUOO/NEu68Dw==" + "version": "1.18.0", + "integrity": "sha512-56/MAlX5WMsPVbOg7tAxnYvNYMMWr/QJiIp6BxVSW3JJXUVzzOn64qW8TzQyMSqSUFM2+PVI4aUHcHOzIz/1tg==" }, "node_modules/@types/webpack-sources": { "version": "0.1.5", @@ -15621,6 +19092,14 @@ "node": ">=0.10.0" } }, + "node_modules/@types/ws": { + "version": "8.5.3", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "15.0.13", "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", @@ -16143,6 +19622,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@visx/responsive": { + "version": "3.0.0", + "integrity": "sha512-immnxQwOWlrxbnlCIqJWuDpPfrM6tglgMTN1WsyXyGluLMJqhuuxqxllfXaRPkQFS4fcvs66KCEELdazh96U2w==", + "dependencies": { + "@types/lodash": "^4.14.172", + "@types/react": "*", + "lodash": "^4.17.21", + "prop-types": "^15.6.1" + }, + "peerDependencies": { + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" + } + }, "node_modules/@vx/axis": { "version": "0.0.140", "integrity": "sha512-lxMgWySkSh7ew8XS25Kpn95HH4d8dpL2vLv1UvASJY2VxdczQayTUUvQLecesJI4bbJV2R7Fasm64EBlJAezTw==", @@ -16271,8 +19763,8 @@ "integrity": "sha512-x5y5eQJ0koZCGS0AK2juiJ2hLsZhgAOzQ2MuMushikEfQ1azLtrDIh4l2WesLQrp//o9+u2sWJ3mPgEGdBIvfA==" }, "node_modules/@vx/responsive": { - "version": "0.0.195", - "integrity": "sha512-3zjkjqg8V3Kr1moSI7EAzlW7MLR87p2CXc+qh0zZg/zLrc3C89JnxyMYFfS7jM4PlHr26n634YddQDVydwARBA==", + "version": "0.0.199", + "integrity": "sha512-ONrmLUAG+8wzD3cn/EmsuZh6JHeyejqup3ZsV25t04VaVJAVQAJukAfNdH8YiwSJu0zSo+txkBTfrnOmFyQLOw==", "dependencies": { "@types/lodash": "^4.14.146", "@types/react": "*", @@ -16655,6 +20147,44 @@ "version": "4.2.2", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/@yarnpkg/parsers": { + "version": "3.0.0-rc.33", + "integrity": "sha512-az35wEPH00kW6eZDqHC0BumzAB4XD+YJb1b5tHEfsy73viCN7uGy8kvutwig5bgVwt1Hx7GuU09G50Sc5osBlA==", + "dev": true, + "dependencies": { + "js-yaml": "^3.10.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.15.0" + } + }, + "node_modules/@yarnpkg/parsers/node_modules/tslib": { + "version": "2.4.1", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true + }, + "node_modules/@zkochan/js-yaml": { + "version": "0.0.6", + "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@zkochan/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/abab": { "version": "2.0.6", "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", @@ -16680,11 +20210,11 @@ "integrity": "sha512-9jN7+BijYKWO8fxfcG7QZh7js6V+g3OjkxMRHfKWNjjs85048VY4cd27Uoe6yk55P66L/z7Dflu5+YEApgMzkA==" }, "node_modules/accepts": { - "version": "1.3.5", - "integrity": "sha512-pt4oTticGUEOZCvli0I7ekmpXopaX+Xvb/TQRaTKnvZNIH9Srs0VWi2NGBfsRscAgwtIEtxW5JOB9sI0oN3cjw==", + "version": "1.3.8", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dependencies": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" @@ -16695,8 +20225,8 @@ "integrity": "sha512-NBOQlm9+7RBqRqZwimpgquaLeTJFayqb9UEPtTkpC3TkkwDnlsT/TwsCC0svjt9kEZ6G9mH5AEOHSz6Q/HrzQQ==" }, "node_modules/acorn": { - "version": "8.7.0", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.7.1", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "bin": { "acorn": "bin/acorn" }, @@ -16762,7 +20292,6 @@ }, "node_modules/ag-charts-community": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ag-charts-community/-/ag-charts-community-4.2.0.tgz", "integrity": "sha512-9vZSwlcpGwkb6KwEzTgxw5BuzdZgRhrbbiQS5wIfSa74cNsyYt76MTBPudqfHnc+SoWDGGxof3rteU6kXSc07w==", "dev": true }, @@ -16799,8 +20328,8 @@ "dev": true }, "node_modules/agentkeepalive": { - "version": "4.2.0", - "integrity": "sha512-0PhAp58jZNw13UJv7NVdTGb0ZcghHUb3DrZ046JiiJY/BOaTTpbwdHq2VObPCBV8M2GPh7sgrJ3AQ8Ey468LJw==", + "version": "4.2.1", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", "dev": true, "dependencies": { "debug": "^4.1.0", @@ -16867,30 +20396,27 @@ } }, "node_modules/airbnb-prop-types": { - "version": "2.15.0", - "integrity": "sha512-jUh2/hfKsRjNFC4XONQrxo/n/3GG4Tn6Hl0WlFQN5PY9OMC9loSCoAYKnZsWaP8wEfd5xcrPloK0Zg6iS1xwVA==", + "version": "2.16.0", + "integrity": "sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg==", "dev": true, "dependencies": { - "array.prototype.find": "^2.1.0", - "function.prototype.name": "^1.1.1", - "has": "^1.0.3", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", + "array.prototype.find": "^2.1.1", + "function.prototype.name": "^1.1.2", + "is-regex": "^1.1.0", + "object-is": "^1.1.2", "object.assign": "^4.1.0", - "object.entries": "^1.1.0", + "object.entries": "^1.1.2", "prop-types": "^15.7.2", "prop-types-exact": "^1.2.0", - "react-is": "^16.9.0" + "react-is": "^16.13.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" }, "peerDependencies": { "react": "^0.14 || ^15.0.0 || ^16.0.0-alpha" } }, - "node_modules/airbnb-prop-types/node_modules/react-is": { - "version": "16.9.0", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", - "dev": true - }, "node_modules/ajv": { "version": "6.12.6", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", @@ -17013,7 +20539,7 @@ "node_modules/ansi-escapes": { "version": "4.3.1", "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "devOptional": true, + "dev": true, "dependencies": { "type-fest": "^0.11.0" }, @@ -17027,7 +20553,7 @@ "node_modules/ansi-escapes/node_modules/type-fest": { "version": "0.11.0", "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "devOptional": true, + "dev": true, "engines": { "node": ">=8" }, @@ -17099,54 +20625,49 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/ansicolors": { - "version": "0.2.1", - "integrity": "sha512-tOIuy1/SK/dr94ZA0ckDohKXNeBNqZ4us6PjMVLs5h1w2GBB6uPtOknp2+VF4F/zcy9LI70W+Z+pE2Soajky1w==" - }, "node_modules/antd": { - "version": "4.9.4", - "integrity": "sha512-kieGi1Isb/ddnn9E/AJVFCUgSZIqDv6HtFg7r5WWI0s6zf+nfCOtpes0oX8TdHO6mE/dL39pJG52aHNe8MwkJg==", + "version": "4.10.3", + "integrity": "sha512-J/IZvW15MwTmUxK/AWFkSU51T1Hyn4e0GchJWlIe7+FrPpLoTgLf9/Cx3mgxiooHfE9OfvnYvvRli1VxHH6H0Q==", "dependencies": { "@ant-design/colors": "^5.0.0", "@ant-design/icons": "^4.3.0", - "@ant-design/react-slick": "~0.27.0", + "@ant-design/react-slick": "~0.28.1", "@babel/runtime": "^7.11.2", "array-tree-filter": "^2.1.0", "classnames": "^2.2.6", "copy-to-clipboard": "^3.2.0", "lodash": "^4.17.20", "moment": "^2.25.3", - "omit.js": "^2.0.2", "rc-cascader": "~1.4.0", "rc-checkbox": "~2.3.0", "rc-collapse": "~3.1.0", - "rc-dialog": "~8.4.0", - "rc-drawer": "~4.1.0", + "rc-dialog": "~8.5.1", + "rc-drawer": "~4.2.0", "rc-dropdown": "~3.2.0", - "rc-field-form": "~1.17.0", - "rc-image": "~4.2.0", + "rc-field-form": "~1.17.3", + "rc-image": "~5.0.2", "rc-input-number": "~6.1.0", "rc-mentions": "~1.5.0", "rc-menu": "~8.10.0", "rc-motion": "^2.4.0", "rc-notification": "~4.5.2", "rc-pagination": "~3.1.2", - "rc-picker": "~2.4.1", + "rc-picker": "~2.5.1", "rc-progress": "~3.1.0", "rc-rate": "~2.9.0", - "rc-resize-observer": "^0.2.3", - "rc-select": "~11.5.3", - "rc-slider": "~9.6.1", + "rc-resize-observer": "^1.0.0", + "rc-select": "~12.1.0", + "rc-slider": "~9.7.1", "rc-steps": "~4.1.0", "rc-switch": "~3.2.0", - "rc-table": "~7.11.0", + "rc-table": "~7.12.0", "rc-tabs": "~11.7.0", "rc-textarea": "~0.3.0", "rc-tooltip": "~5.0.0", - "rc-tree": "~4.0.0", - "rc-tree-select": "~4.2.0", - "rc-upload": "~3.3.1", - "rc-util": "^5.1.0", + "rc-tree": "~4.1.0", + "rc-tree-select": "~4.3.0", + "rc-upload": "~3.3.4", + "rc-util": "^5.7.0", "scroll-into-view-if-needed": "^2.2.25", "warning": "^4.0.3" }, @@ -17166,39 +20687,244 @@ "@ctrl/tinycolor": "^3.3.1" } }, - "node_modules/antd/node_modules/@ant-design/icons": { - "version": "4.3.0", - "integrity": "sha512-UoIbw4oz/L/msbkgqs2nls2KP7XNKScOxVR54wRrWwnXOzJaGNwwSdYjHQz+5ETf8C53YPpzMOnRX99LFCdeIQ==", + "node_modules/antd/node_modules/@ant-design/react-slick": { + "version": "0.28.4", + "integrity": "sha512-j9eAHTn7GxbXUFNknJoHS2ceAsqrQi2j8XykjZE1IXCD8kJF+t28EvhBLniDpbOsBk/3kjalnhriTfZcjBHNqg==", + "dependencies": { + "@babel/runtime": "^7.10.4", + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "lodash": "^4.17.21", + "resize-observer-polyfill": "^1.5.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-dialog": { + "version": "8.5.3", + "integrity": "sha512-zoamT8L6+rBwnwjPlrZRxiHCHQXrTcWZD3a6ruoqEdUKP1KgO0eSjMDH9WlF3WEPYMVnb2G5SrjHrhnwgPDu5w==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-motion": "^2.3.0", + "rc-util": "^5.6.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-drawer": { + "version": "4.2.2", + "integrity": "sha512-zw48FATkAmJrEnfeRWiMqvKAzqGzUDLN1UXlluB7q7GgbR6mJFvc+QsmNrgxsFuMz86Lh9mKSIi7rXlPINmuzw==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.7.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-image": { + "version": "5.0.2", + "integrity": "sha512-bNCOGxo9ICe2S+MuVQtxVjk2esL0QJX4YcUB10S98z8CWO1sswySH6inH69YU778aCXs8/nKhtZMUmiU1To0bQ==", "dependencies": { - "@ant-design/colors": "^5.0.0", - "@ant-design/icons-svg": "^4.0.0", "@babel/runtime": "^7.11.2", "classnames": "^2.2.6", - "insert-css": "^2.0.0", - "rc-util": "^5.0.1" + "rc-dialog": "~8.5.1", + "rc-util": "^5.0.6" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-picker": { + "version": "2.5.19", + "integrity": "sha512-u6myoCu/qiQ0vLbNzSzNrzTQhs7mldArCpPHrEI6OUiifs+IPXmbesqSm0zilJjfzrZJLgYeyyOMSznSlh0GKA==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "date-fns": "2.x", + "dayjs": "1.x", + "moment": "^2.24.0", + "rc-trigger": "^5.0.4", + "rc-util": "^5.4.0", + "shallowequal": "^1.1.0" }, "engines": { - "node": ">=8" + "node": ">=8.x" }, "peerDependencies": { - "react": ">=16.0.0" + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "node_modules/antd/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", + "node_modules/antd/node_modules/rc-resize-observer": { + "version": "1.2.0", + "integrity": "sha512-6W+UzT3PyDM0wVCEHfoW3qTHPTvbdSgiA43buiy8PzmeMnfgnDeb9NjdimMXMl3/TcrvvWl5RRVdp+NqcR47pQ==", "dependencies": { - "react-is": "^16.12.0", + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-util": "^5.15.0", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-select": { + "version": "12.1.13", + "integrity": "sha512-cPI+aesP6dgCAaey4t4upDbEukJe+XN0DK6oO/6flcCX5o28o7KNZD7JAiVtC/6fCwqwI/kSs7S/43dvHmBl+A==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-overflow": "^1.0.0", + "rc-trigger": "^5.0.4", + "rc-util": "^5.9.8", + "rc-virtual-list": "^3.2.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/antd/node_modules/rc-select/node_modules/rc-overflow": { + "version": "1.2.8", + "integrity": "sha512-QJ0UItckWPQ37ZL1dMEBAdY1dhfTXFL9k6oTTcyydVwoUNMnMqCGqnRNA98axSr/OeDKqR6DVFyi8eA5RQI/uQ==", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.19.2" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-select/node_modules/rc-virtual-list": { + "version": "3.4.11", + "integrity": "sha512-BvUUH60kkeTBPigN5F89HtGaA5jSP4y2aM6cJ4dk9Y42I9yY+h6i08wF6UKeDcxdfOU8j3I5HxkSS/xA77J3wA==", + "dependencies": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.15.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/antd/node_modules/rc-slider": { + "version": "9.7.5", + "integrity": "sha512-LV/MWcXFjco1epPbdw1JlLXlTgmWpB9/Y/P2yinf8Pg3wElHxA9uajN21lJiWtZjf5SCUekfSP6QMJfDo4t1hg==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-tooltip": "^5.0.1", + "rc-util": "^5.16.1", "shallowequal": "^1.1.0" }, + "engines": { + "node": ">=8.x" + }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, - "node_modules/antd/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "node_modules/antd/node_modules/rc-table": { + "version": "7.12.5", + "integrity": "sha512-XV4m5h0W+NjGkNzvp5ahOhYHyNG8oPNV9pTLre2EsfmyStXUJBICyfkNID7WZulMdCehv/Wa3MdqXwZ4EsJchw==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.4.0", + "shallowequal": "^1.1.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-tooltip": { + "version": "5.0.2", + "integrity": "sha512-A4FejSG56PzYtSNUU4H1pVzfhtkV/+qMT2clK0CsSj+9mbc4USEtpWeX6A/jjVL+goBOMKj8qlH7BCZmZWh/Nw==", + "dependencies": { + "@babel/runtime": "^7.11.2", + "rc-trigger": "^5.0.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-tree": { + "version": "4.1.5", + "integrity": "sha512-q2vjcmnBDylGZ9/ZW4F9oZMKMJdbFWC7um+DAQhZG1nqyg1iwoowbBggUDUaUOEryJP+08bpliEAYnzJXbI5xQ==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-util": "^5.0.0", + "rc-virtual-list": "^3.0.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/antd/node_modules/rc-tree-select": { + "version": "4.3.3", + "integrity": "sha512-0tilOHLJA6p+TNg4kD559XnDX3PTEYuoSF7m7ryzFLAYvdEEPtjn0QZc5z6L0sMKBiBlj8a2kf0auw8XyHU3lA==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-select": "^12.0.0", + "rc-tree": "^4.0.0", + "rc-util": "^5.0.5" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/antd/node_modules/rc-tree/node_modules/rc-virtual-list": { + "version": "3.4.11", + "integrity": "sha512-BvUUH60kkeTBPigN5F89HtGaA5jSP4y2aM6cJ4dk9Y42I9yY+h6i08wF6UKeDcxdfOU8j3I5HxkSS/xA77J3wA==", + "dependencies": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.15.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } }, "node_modules/any-observable": { "version": "0.3.0", @@ -17262,12 +20988,28 @@ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "node_modules/are-we-there-yet": { - "version": "1.1.7", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "version": "3.0.1", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", "dev": true, "dependencies": { "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.0", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/argparse": { @@ -17320,6 +21062,7 @@ "node_modules/array-differ": { "version": "3.0.0", "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true, "engines": { "node": ">=8" } @@ -17329,11 +21072,6 @@ "integrity": "sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==", "dev": true }, - "node_modules/array-filter": { - "version": "1.0.0", - "integrity": "sha512-Ene1hbrinPZ1qPoZp7NSx4jQnh4nr7MtY78pHNb+yr8yHbxmTS7ChGW0a55JKA7TkRDeoQxK4GcJaCvBYplSKA==", - "dev": true - }, "node_modules/array-flatten": { "version": "2.1.2", "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" @@ -17395,25 +21133,52 @@ "node": ">=0.10.0" } }, + "node_modules/array.prototype.filter": { + "version": "1.0.2", + "integrity": "sha512-us+UrmGOilqttSOgoWZTpOvHu68vZT2YCjc/H4vhu56vzZpaDFBhB+Se2UwqWzMKbDv7Myq5M5pcZLAtUvTQdQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.find": { - "version": "2.1.0", - "integrity": "sha512-Wn41+K1yuO5p7wRZDl7890c3xvv5UBrfVXTVIe28rSQb6LS0fZMDrQB6PAcxQFRFy6vJTLDc3A2+3CjQdzVKRg==", + "version": "2.2.1", + "integrity": "sha512-I2ri5Z9uMpMvnsNrHre9l3PaX+z9D0/z6F7Yt2u15q7wt0I62g5kX6xUKR1SJiefgG+u2/gJUmM8B47XRvQR6w==", "dev": true, "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.13.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array.prototype.flat": { - "version": "1.2.1", - "integrity": "sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw==", + "version": "1.3.1", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dependencies": { - "define-properties": "^1.1.2", - "es-abstract": "^1.10.0", - "function-bind": "^1.1.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array.prototype.flatmap": { @@ -17543,6 +21308,11 @@ "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.4", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, "node_modules/async-each": { "version": "1.0.3", "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", @@ -17628,6 +21398,16 @@ "node": ">=0.10.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", @@ -17652,7 +21432,7 @@ "node_modules/axios": { "version": "0.21.4", "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "devOptional": true, + "dev": true, "dependencies": { "follow-redirects": "^1.14.0" } @@ -17735,8 +21515,8 @@ } }, "node_modules/babel-loader/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -17745,8 +21525,8 @@ } }, "node_modules/babel-loader/node_modules/loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -18009,11 +21789,11 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.2.2", - "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", + "version": "0.3.2", + "integrity": "sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q==", "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.2", + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.2", "semver": "^6.1.1" }, "peerDependencies": { @@ -18021,13 +21801,11 @@ } }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.2", + "integrity": "sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==", "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -18038,8 +21816,8 @@ } }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -18075,23 +21853,21 @@ } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.2.2", - "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", + "version": "0.4.0", + "integrity": "sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.2.2" + "@babel/helper-define-polyfill-provider": "^0.3.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.2", + "integrity": "sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==", "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -18102,8 +21878,8 @@ } }, "node_modules/babel-plugin-polyfill-regenerator/node_modules/debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -18362,8 +22138,7 @@ }, "node_modules/before-after-hook": { "version": "2.2.2", - "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", - "dev": true + "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" }, "node_modules/better-opn": { "version": "2.1.1", @@ -18470,79 +22245,82 @@ "version": "3.7.2", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "node_modules/bmpimagejs": { + "version": "1.0.4", + "integrity": "sha512-21oKU7kbRt2OgOOj7rdiNr/yznDNUQ585plxR00rsmECcZr+6O1oCwB8OIoSHk/bDhbG8mFXIdeQuCPHgZ6QBw==", + "dev": true + }, "node_modules/bn.js": { "version": "5.2.0", "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" }, "node_modules/body-parser": { - "version": "1.19.0", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.2", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", "dependencies": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" }, "engines": { "node": ">= 0.8" } }, "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.0", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.2", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "engines": { "node": ">= 0.8" } }, "node_modules/body-parser/node_modules/http-errors": { - "version": "1.7.2", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dependencies": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" } }, + "node_modules/body-parser/node_modules/inherits": { + "version": "2.0.4", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, "node_modules/body-parser/node_modules/qs": { - "version": "6.7.0", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.9.7", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/body-parser/node_modules/setprototypeof": { - "version": "1.1.1", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "node_modules/body-parser/node_modules/statuses": { - "version": "1.5.0", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } + "version": "1.2.0", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "node_modules/bonjour": { - "version": "3.5.0", - "integrity": "sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==", + "node_modules/bonjour-service": { + "version": "1.0.14", + "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", "dev": true, "dependencies": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", + "array-flatten": "^2.1.2", "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" } }, "node_modules/boolbase": { @@ -18818,24 +22596,29 @@ } }, "node_modules/browserslist": { - "version": "4.17.0", - "integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==", + "version": "4.21.3", + "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "caniuse-lite": "^1.0.30001254", - "colorette": "^1.3.0", - "electron-to-chromium": "^1.3.830", - "escalade": "^3.1.1", - "node-releases": "^1.1.75" + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.5" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/bser": { @@ -18874,11 +22657,6 @@ "version": "1.1.1", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, - "node_modules/buffer-indexof": { - "version": "1.1.1", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, "node_modules/buffer-xor": { "version": "1.0.3", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" @@ -18892,14 +22670,6 @@ "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", "dev": true }, - "node_modules/byline": { - "version": "5.0.0", - "integrity": "sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/byte-size": { "version": "7.0.1", "integrity": "sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A==", @@ -19233,12 +23003,18 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001312", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "version": "1.0.30001378", + "integrity": "sha512-JVQnfoO7FK7WvU4ZkBRbPjaot4+YqxogSDosHv0Hv5mWpUESmN+UubMU6L/hGz8QlQ2aY5U0vR6MOs6j/CXpNA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] }, "node_modules/capture-exit": { "version": "2.0.0", @@ -19251,24 +23027,6 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/capture-stack-trace": { - "version": "1.0.1", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cardinal": { - "version": "0.4.4", - "integrity": "sha512-3MxV0o9wOpQcobrcSrRpaSxlYkohCcZu0ytOjJUww/Yo/223q4Ecloo7odT+M0SI5kPgb1JhvSaF4EEuVXOLAQ==", - "dependencies": { - "ansicolors": "~0.2.1", - "redeyed": "~0.4.0" - }, - "bin": { - "cdl": "bin/cdl.js" - } - }, "node_modules/cartocolor": { "version": "4.0.2", "integrity": "sha512-+Gh9mb6lFxsDOLQlBLPxAHCnWXlg2W8q3AcVwqRcy95TdBbcOU89Wrb6h2Hd/6Ww1Kc1pzXmUdpnWD+xeCG0dg==", @@ -19337,7 +23095,7 @@ "node_modules/chardet": { "version": "0.7.0", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "devOptional": true + "dev": true }, "node_modules/charenc": { "version": "0.0.2", @@ -19372,8 +23130,14 @@ } }, "node_modules/chokidar": { - "version": "3.5.2", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -19477,367 +23241,19 @@ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "node_modules/chromatic": { - "version": "5.10.2", - "integrity": "sha512-JHFtZ16VanQX0X9qjacIJOrH9rVUJACilPs8dBwwQgJTZzgCZAdwgmE+WwLcxe/LuK7vM56BDTHbxC+XcnTsjw==", - "dev": true, - "dependencies": { - "@actions/core": "^1.5.0", - "@actions/github": "^5.0.0", - "@babel/preset-typescript": "^7.15.0", - "@babel/runtime": "^7.15.3", - "@chromaui/localtunnel": "^2.0.3", - "async-retry": "^1.3.3", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "dotenv": "^8.2.0", - "env-ci": "^5.0.2", - "esm": "^3.2.25", - "execa": "^5.0.0", - "fake-tag": "^2.0.0", - "fs-extra": "^10.0.0", - "https-proxy-agent": "^5.0.0", - "jsonfile": "^6.0.1", - "junit-report-builder": "2.1.0", - "listr": "0.14.3", - "meow": "^8.0.0", - "no-proxy": "^1.0.3", - "node-ask": "^1.0.1", - "node-fetch": "2.6.0", - "node-loggly-bulk": "^2.2.4", - "p-limit": "3.1.0", - "picomatch": "2.2.2", - "pkg-up": "^3.1.0", - "pluralize": "^8.0.0", - "progress-stream": "^2.0.0", - "semver": "^7.3.5", - "slash": "^3.0.0", - "string-argv": "^0.3.1", - "strip-ansi": "6.0.0", - "tmp-promise": "3.0.2", - "tree-kill": "^1.2.2", - "ts-dedent": "^1.0.0", - "util-deprecate": "^1.0.2", - "uuid": "^8.3.2", - "yarn-or-npm": "^3.0.1" - }, - "bin": { - "chroma": "bin/register.js", - "chromatic": "bin/register.js", - "chromatic-cli": "bin/register.js" - } - }, - "node_modules/chromatic/node_modules/ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/chromatic/node_modules/cross-spawn": { - "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/chromatic/node_modules/debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/chromatic/node_modules/execa": { - "version": "5.1.1", - "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/chromatic/node_modules/find-up": { - "version": "3.0.0", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/chromatic/node_modules/get-stream": { - "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chromatic/node_modules/human-signals": { - "version": "2.1.0", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/chromatic/node_modules/is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chromatic/node_modules/locate-path": { - "version": "3.0.0", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/chromatic/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/chromatic/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/chromatic/node_modules/node-fetch": { - "version": "2.6.0", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", - "dev": true, - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/chromatic/node_modules/npm-run-path": { - "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chromatic/node_modules/p-limit": { - "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chromatic/node_modules/p-locate": { - "version": "3.0.0", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/chromatic/node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chromatic/node_modules/p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chromatic/node_modules/path-key": { - "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/chromatic/node_modules/picomatch": { - "version": "2.2.2", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/chromatic/node_modules/pkg-up": { - "version": "3.1.0", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "version": "6.7.4", + "integrity": "sha512-QW4i8RQsON0JVnFnRf+8y70aIJptvC0Oi/26YJ669Dl03WmJRpobNO5qWFPTiv3KFKMc1Qf6/qFsRVZCtn+bfA==", "dev": true, "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chromatic/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" + "@discoveryjs/json-ext": "^0.5.7", + "@types/webpack-env": "^1.17.0" }, "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/chromatic/node_modules/shebang-command": { - "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chromatic/node_modules/shebang-regex": { - "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" + "chroma": "bin/main.cjs", + "chromatic": "bin/main.cjs", + "chromatic-cli": "bin/main.cjs" } }, - "node_modules/chromatic/node_modules/slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/chromatic/node_modules/strip-ansi": { - "version": "6.0.0", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chromatic/node_modules/ts-dedent": { - "version": "1.2.0", - "integrity": "sha512-6zSJp23uQI+Txyz5LlXMXAHpUhY4Hi0oluXny0OgIR7g/Cromq4vDBnhtbBdyIV34g0pgwxUvnvg+jLJe4c1NA==", - "dev": true, - "engines": { - "node": ">=6.10" - } - }, - "node_modules/chromatic/node_modules/uuid": { - "version": "8.3.2", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/chromatic/node_modules/which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/chromatic/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/chrome-trace-event": { "version": "1.0.2", "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", @@ -19902,8 +23318,8 @@ } }, "node_modules/classnames": { - "version": "2.2.6", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + "version": "2.3.2", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" }, "node_modules/clean-css": { "version": "4.2.3", @@ -19942,7 +23358,7 @@ "node_modules/cli-cursor": { "version": "3.1.0", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "devOptional": true, + "dev": true, "dependencies": { "restore-cursor": "^3.1.0" }, @@ -19961,38 +23377,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-table": { - "version": "0.3.9", - "integrity": "sha512-7eA6hFtAZwVx3dWAGoaBqTrzWko5jRUFKpHT64ZHkJpaA3y5wf5NlLjguqTRmqycatJZiwftODYYyGNLbQ7MuA==", - "dependencies": { - "colors": "1.0.3", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/cli-table/node_modules/ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-table/node_modules/colors": { - "version": "1.0.3", - "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/cli-table/node_modules/strip-ansi": { - "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/cli-table3": { "version": "0.6.1", "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", @@ -20045,7 +23429,7 @@ "node_modules/cli-width": { "version": "3.0.0", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "devOptional": true, + "dev": true, "engines": { "node": ">= 10" } @@ -20095,20 +23479,6 @@ "node": ">=8" } }, - "node_modules/clone": { - "version": "2.1.2", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-buffer": { - "version": "1.0.0", - "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/clone-deep": { "version": "4.0.1", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", @@ -20128,33 +23498,10 @@ "node": ">=0.10.0" } }, - "node_modules/clone-stats": { - "version": "1.0.0", - "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==" - }, - "node_modules/cloneable-readable": { - "version": "1.1.3", - "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", - "dependencies": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" - } - }, - "node_modules/cmd-shim": { - "version": "4.1.0", - "integrity": "sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw==", - "dev": true, - "dependencies": { - "mkdirp-infer-owner": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/co": { "version": "4.6.0", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -20239,6 +23586,14 @@ "node": ">=0.10.0" } }, + "node_modules/color": { + "version": "3.2.1", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "1.9.3", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", @@ -20250,6 +23605,14 @@ "version": "1.1.3", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/color-string": { + "version": "1.9.1", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/color-support": { "version": "1.1.3", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", @@ -20268,7 +23631,8 @@ }, "node_modules/colorette": { "version": "1.4.0", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==" + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true }, "node_modules/colors": { "version": "1.4.0", @@ -20279,12 +23643,34 @@ } }, "node_modules/columnify": { - "version": "1.5.4", - "integrity": "sha512-rFl+iXVT1nhLQPfGDw+3WcS8rmm7XsLKUmhsGE3ihzzpIikeGrTaZPIRKYWeLsLBypsHzjXIvYEltVUZS84XxQ==", + "version": "1.6.0", + "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", "dev": true, "dependencies": { - "strip-ansi": "^3.0.0", + "strip-ansi": "^6.0.1", "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/columnify/node_modules/ansi-regex": { + "version": "5.0.1", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/columnify/node_modules/strip-ansi": { + "version": "6.0.1", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/combined-stream": { @@ -20380,6 +23766,11 @@ "version": "2.20.3", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "node_modules/common-ancestor-path": { + "version": "1.0.1", + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", + "dev": true + }, "node_modules/common-path-prefix": { "version": "3.0.0", "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" @@ -20473,8 +23864,8 @@ "dev": true }, "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "version": "2.0.0", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, "engines": { "node": ">=0.8" @@ -20493,15 +23884,33 @@ "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==" }, "node_modules/content-disposition": { - "version": "0.5.3", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dependencies": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" }, "engines": { "node": ">= 0.6" } }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/content-type": { "version": "1.0.4", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", @@ -20644,8 +24053,8 @@ } }, "node_modules/conventional-changelog-core/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -20721,17 +24130,6 @@ "semver": "bin/semver.js" } }, - "node_modules/conventional-changelog-writer/node_modules/split": { - "version": "1.0.1", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, "node_modules/conventional-changelog-writer/node_modules/through2": { "version": "4.0.2", "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", @@ -20850,6 +24248,7 @@ "node_modules/cookie": { "version": "0.4.0", "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -20972,9 +24371,8 @@ } }, "node_modules/core-js": { - "version": "3.18.1", - "integrity": "sha512-vJlUi/7YdlCZeL6fXvWNaLUPh/id12WXj3MbkMw5uOyF0PfWPBNOCNbs53YqgrvtujLNlt9JQpruyIKkUZ+PKA==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "version": "3.24.1", + "integrity": "sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -20982,10 +24380,10 @@ } }, "node_modules/core-js-compat": { - "version": "3.18.1", - "integrity": "sha512-XJMYx58zo4W0kLPmIingVZA10+7TuKrMLPt83+EzDmxFJQUMcTVVmQ+n5JP4r6Z14qSzhQBRi3NSWoeVyKKXUg==", + "version": "3.24.1", + "integrity": "sha512-XhdNAGeRnTpp8xbD+sR/HFDK9CbeeeqXT6TuofXh3urqEevzkWmLRgrVoykodsw8okqo2pu1BOmuCKrHx63zdw==", "dependencies": { - "browserslist": "^4.17.1", + "browserslist": "^4.21.3", "semver": "7.0.0" }, "funding": { @@ -20993,35 +24391,6 @@ "url": "https://opencollective.com/core-js" } }, - "node_modules/core-js-compat/node_modules/browserslist": { - "version": "4.17.1", - "integrity": "sha512-aLD0ZMDSnF4lUt4ZDNgqi5BUn9BZ7YdQdI/cYlILrhdSSZJLU9aNZoD5/NBmM4SK34APB2e83MOsRt1EnkuyaQ==", - "dependencies": { - "caniuse-lite": "^1.0.30001259", - "electron-to-chromium": "^1.3.846", - "escalade": "^3.1.1", - "nanocolors": "^0.1.5", - "node-releases": "^1.1.76" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/core-js-compat/node_modules/electron-to-chromium": { - "version": "1.3.853", - "integrity": "sha512-W4U8n+U8I5/SUaFcqZgbKRmYZwcyEIQVBDf+j5QQK6xChjXnQD+wj248eGR9X4u+dDmDR//8vIfbu4PrdBBIoQ==" - }, - "node_modules/core-js-compat/node_modules/node-releases": { - "version": "1.1.76", - "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==" - }, "node_modules/core-js-compat/node_modules/semver": { "version": "7.0.0", "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", @@ -21259,14 +24628,24 @@ "version": "4.12.0", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, - "node_modules/create-error-class": { - "version": "3.0.2", - "integrity": "sha512-gYTKKexFO3kh200H1Nit76sRwRtOY32vQd3jpAQKpLtZqyNsSQNfI4N7o3eP2wUjV35pTWKRYqFUDBvUha/Pkw==", + "node_modules/create-emotion": { + "version": "10.0.27", + "integrity": "sha512-fIK73w82HPPn/RsAij7+Zt8eCE8SptcJ3WoRMfxMtjteYxud8GDTKKld7MYwAX2TVhrw29uR1N/bVGxeStHILg==", "dependencies": { - "capture-stack-trace": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "@emotion/cache": "^10.0.27", + "@emotion/serialize": "^0.11.15", + "@emotion/sheet": "0.9.4", + "@emotion/utils": "0.11.3" + } + }, + "node_modules/create-emotion/node_modules/@emotion/cache": { + "version": "10.0.29", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", + "dependencies": { + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" } }, "node_modules/create-hash": { @@ -21311,6 +24690,7 @@ "node_modules/cross-spawn": { "version": "6.0.5", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -21512,8 +24892,8 @@ } }, "node_modules/css-minimizer-webpack-plugin/node_modules/css-what": { - "version": "5.0.1", - "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", + "version": "5.1.0", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", "dev": true, "engines": { "node": ">= 6" @@ -22186,8 +25566,8 @@ } }, "node_modules/css-what": { - "version": "2.1.2", - "integrity": "sha512-wan8dMWQ0GUeF7DGEPVjhHemVW/vy6xUYmFzRY8RYqgA0JtXC9rJmbScBjqSu6dg9q0lwPQy6ZAmJVr3PPTvqQ==", + "version": "2.1.3", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", "dev": true, "engines": { "node": "*" @@ -22282,8 +25662,8 @@ } }, "node_modules/cssom": { - "version": "0.4.4", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "version": "0.5.0", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", "dev": true }, "node_modules/cssstyle": { @@ -22306,6 +25686,10 @@ "version": "2.6.9", "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==" }, + "node_modules/currencyformatter.js": { + "version": "2.2.0", + "integrity": "sha512-kfMfQBOsK9vnzqUT7pQY+I6ZTM7VWkICwiFUOLPLpOzR5Ir+AUoa1kO7I1clsiHXYe1FPyX91BRWBgHOUEH/NQ==" + }, "node_modules/cyclist": { "version": "1.0.1", "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==" @@ -22525,7 +25909,6 @@ "node_modules/dargs": { "version": "7.0.0", "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true, "engines": { "node": ">=8" } @@ -22541,49 +25924,64 @@ "node": ">=0.10" } }, + "node_modules/data-uri-to-buffer": { + "version": "3.0.1", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/data-urls": { - "version": "2.0.0", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "version": "3.0.2", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", "dev": true, "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/data-urls/node_modules/tr46": { - "version": "2.0.2", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "version": "3.0.0", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, "dependencies": { "punycode": "^2.1.1" }, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/data-urls/node_modules/webidl-conversions": { - "version": "6.1.0", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "version": "7.0.0", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, "engines": { - "node": ">=10.4" + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-mimetype": { + "version": "3.0.0", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" } }, "node_modules/data-urls/node_modules/whatwg-url": { - "version": "8.4.0", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "11.0.0", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^6.1.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/datamaps": { @@ -22611,8 +26009,8 @@ } }, "node_modules/date-fns": { - "version": "2.16.1", - "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==", + "version": "2.29.3", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", "engines": { "node": ">=0.11" }, @@ -22630,6 +26028,7 @@ "node_modules/dateformat": { "version": "3.0.3", "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, "engines": { "node": "*" } @@ -22722,8 +26121,8 @@ } }, "node_modules/decode-uri-component": { - "version": "0.2.0", - "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", + "version": "0.2.2", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "engines": { "node": ">=0.10" } @@ -22732,22 +26131,6 @@ "version": "0.7.0", "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==" }, - "node_modules/deep-equal": { - "version": "1.1.1", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, - "dependencies": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/deep-equal-ident": { "version": "1.1.1", "integrity": "sha512-aWv7VhTl/Lju1zenOD3E1w8PpUVrTDbwXCHtbSNr+p/uadr49Y1P1ld0W3Pl6gbvIbiRjoCVsqw70UupCNGh6g==", @@ -22940,13 +26323,17 @@ } }, "node_modules/define-properties": { - "version": "1.1.3", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dependencies": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-property": { @@ -22999,6 +26386,48 @@ "node": ">=0.10.0" } }, + "node_modules/degenerator": { + "version": "3.0.2", + "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/degenerator/node_modules/ast-types": { + "version": "0.13.4", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/degenerator/node_modules/esprima": { + "version": "4.0.1", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/degenerator/node_modules/tslib": { + "version": "2.4.1", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true + }, "node_modules/delayed-stream": { "version": "1.0.0", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", @@ -23019,8 +26448,7 @@ }, "node_modules/deprecation": { "version": "2.3.1", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" }, "node_modules/dequal": { "version": "2.0.3", @@ -23104,6 +26532,7 @@ "node_modules/diff": { "version": "4.0.2", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, "engines": { "node": ">=0.3.1" } @@ -23177,20 +26606,14 @@ "dev": true }, "node_modules/dns-packet": { - "version": "1.3.4", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dev": true, - "dependencies": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/dns-txt": { - "version": "2.0.2", - "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", + "version": "5.4.0", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", "dev": true, "dependencies": { - "buffer-indexof": "^1.0.0" + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" } }, "node_modules/doctrine": { @@ -23262,22 +26685,22 @@ "dev": true }, "node_modules/domexception": { - "version": "2.0.1", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "version": "4.0.0", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", "dev": true, "dependencies": { - "webidl-conversions": "^5.0.0" + "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "version": "7.0.0", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/domhandler": { @@ -23338,19 +26761,6 @@ "version": "5.1.0", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, - "node_modules/download-stats": { - "version": "0.3.4", - "integrity": "sha512-ic2BigbyUWx7/CBbsfGjf71zUNZB4edBGC3oRliSzsoNmvyVx3Ycfp1w3vp2Y78Ee0eIIkjIEO5KzW0zThDGaA==", - "optional": true, - "dependencies": { - "JSONStream": "^1.2.1", - "lazy-cache": "^2.0.1", - "moment": "^2.15.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/downshift": { "version": "6.1.7", "integrity": "sha512-cVprZg/9Lvj/uhYRxELzlu1aezRcgPWBjTvspiGTVEU64gF5pRdSRKFVLcxqsZC637cLAGMbL40JavEfWnqgNg==", @@ -23389,10 +26799,6 @@ "readable-stream": "^2.0.2" } }, - "node_modules/duplexer3": { - "version": "0.1.4", - "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==" - }, "node_modules/duplexify": { "version": "3.7.1", "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", @@ -23405,7 +26811,6 @@ }, "node_modules/earcut": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" }, "node_modules/ecc-jsbn": { @@ -23418,38 +26823,17 @@ } }, "node_modules/echarts": { - "version": "5.3.2", - "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==", + "version": "5.4.1", + "integrity": "sha512-9ltS3M2JB0w2EhcYjCdmtrJ+6haZcW6acBolMGIuf01Hql1yrIV01L1aRj7jsaaIULJslEP9Z3vKlEmnJaWJVQ==", "dependencies": { "tslib": "2.3.0", - "zrender": "5.3.1" + "zrender": "5.4.1" } }, "node_modules/echarts/node_modules/tslib": { "version": "2.3.0", "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" }, - "node_modules/editions": { - "version": "2.3.1", - "integrity": "sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA==", - "dependencies": { - "errlop": "^2.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=0.8" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, - "node_modules/editions/node_modules/semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/editorconfig": { "version": "0.15.3", "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", @@ -23480,10 +26864,11 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/ejs": { - "version": "3.1.6", - "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "version": "3.1.8", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "dev": true, "dependencies": { - "jake": "^10.6.1" + "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" @@ -23493,8 +26878,8 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.3.836", - "integrity": "sha512-Ney3pHOJBWkG/AqYjrW0hr2AUCsao+2uvq9HUlRP8OlpSdk/zOHOUJP7eu0icDvePC9DlgffuelP4TnOJmMRUg==" + "version": "1.4.224", + "integrity": "sha512-dOujC5Yzj0nOVE23iD5HKqrRSDj2SD7RazpZS/b/WX85MtO6/LzKDF4TlYZTBteB+7fvSg5JpWh0sN7fImNF8w==" }, "node_modules/elegant-spinner": { "version": "1.0.1", @@ -23558,6 +26943,14 @@ "node": ">= 4" } }, + "node_modules/emotion": { + "version": "10.0.27", + "integrity": "sha512-2xdDzdWWzue8R8lu4G76uWX5WhyQuzATon9LmNeCy/2BHVC6dsEpfhN1a0qhELgtDVdjyEA6J8Y/VlI5ZnaH0g==", + "dependencies": { + "babel-plugin-emotion": "^10.0.27", + "create-emotion": "^10.0.27" + } + }, "node_modules/emotion-rgba": { "version": "0.0.9", "integrity": "sha512-fSt51Lh4a1fppXY3nQrMUC00p1jIYMSaRRkUhPiOJ3s9oumae1tY41AJytRK9d4YmJDP9njJBndgdDn9j7CbsA==" @@ -23637,10 +27030,20 @@ } }, "node_modules/encoding": { - "version": "0.1.12", - "integrity": "sha512-bl1LAgiQc4ZWr++pNYUdRe/alecaHFeHxIJ/pNciqGdKXghaTCOwKkbKp6ye7pKZGu/GcaSXFk8PBVhgs+dJdA==", + "version": "0.1.13", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "dependencies": { - "iconv-lite": "~0.4.13" + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/end-of-stream": { @@ -23707,8 +27110,8 @@ "dev": true }, "node_modules/env-ci": { - "version": "5.4.1", - "integrity": "sha512-xyuCtyFZLpnW5aH0JstETKTSMwHHQX4m42juzEZzvbUCJX7RiPVlhASKM0f/cJ4vvI/+txMkZ7F5To6dCdPYhg==", + "version": "5.5.0", + "integrity": "sha512-o0JdWIbOLP+WJKIUt36hz1ImQQFuN92nhsfTkHHap+J8CiI8WgGpH/a9jEGHh4/TU5BUUGjlnKXNoDb57+ne+A==", "dev": true, "dependencies": { "execa": "^5.0.0", @@ -23856,77 +27259,76 @@ } }, "node_modules/enzyme": { - "version": "3.10.0", - "integrity": "sha512-p2yy9Y7t/PFbPoTvrWde7JIYB2ZyGC+NgTNbVEGvZ5/EyoYSr9aG/2rSbVvyNvMHEhw9/dmGUJHWtfQIEiX9pg==", + "version": "3.11.0", + "integrity": "sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==", "dev": true, "dependencies": { - "array.prototype.flat": "^1.2.1", - "cheerio": "^1.0.0-rc.2", - "function.prototype.name": "^1.1.0", + "array.prototype.flat": "^1.2.3", + "cheerio": "^1.0.0-rc.3", + "enzyme-shallow-equal": "^1.0.1", + "function.prototype.name": "^1.1.2", "has": "^1.0.3", - "html-element-map": "^1.0.0", - "is-boolean-object": "^1.0.0", - "is-callable": "^1.1.4", - "is-number-object": "^1.0.3", - "is-regex": "^1.0.4", - "is-string": "^1.0.4", + "html-element-map": "^1.2.0", + "is-boolean-object": "^1.0.1", + "is-callable": "^1.1.5", + "is-number-object": "^1.0.4", + "is-regex": "^1.0.5", + "is-string": "^1.0.5", "is-subset": "^0.1.1", "lodash.escape": "^4.0.1", "lodash.isequal": "^4.5.0", - "object-inspect": "^1.6.0", - "object-is": "^1.0.1", + "object-inspect": "^1.7.0", + "object-is": "^1.0.2", "object.assign": "^4.1.0", - "object.entries": "^1.0.4", - "object.values": "^1.0.4", - "raf": "^3.4.0", + "object.entries": "^1.1.1", + "object.values": "^1.1.1", + "raf": "^3.4.1", "rst-selector-parser": "^2.2.3", - "string.prototype.trim": "^1.1.2" + "string.prototype.trim": "^1.2.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/enzyme-adapter-react-16": { - "version": "1.14.0", - "integrity": "sha512-7PcOF7pb4hJUvjY7oAuPGpq3BmlCig3kxXGi2kFx0YzJHppqX1K8IIV9skT1IirxXlu8W7bneKi+oQ10QRnhcA==", + "version": "1.15.7", + "integrity": "sha512-LtjKgvlTc/H7adyQcj+aq0P0H07LDL480WQl1gU512IUyaDo/sbOaNDdZsJXYW2XaoPqrLLE9KbZS+X2z6BASw==", "dev": true, "dependencies": { - "enzyme-adapter-utils": "^1.12.0", + "enzyme-adapter-utils": "^1.14.1", + "enzyme-shallow-equal": "^1.0.5", "has": "^1.0.3", - "object.assign": "^4.1.0", - "object.values": "^1.1.0", - "prop-types": "^15.7.2", - "react-is": "^16.8.6", + "object.assign": "^4.1.4", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "react-is": "^16.13.1", "react-test-renderer": "^16.0.0-0", "semver": "^5.7.0" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + }, "peerDependencies": { "enzyme": "^3.0.0", "react": "^16.0.0-0", "react-dom": "^16.0.0-0" } }, - "node_modules/enzyme-adapter-react-16/node_modules/react-is": { - "version": "16.9.0", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", - "dev": true - }, - "node_modules/enzyme-adapter-react-16/node_modules/semver": { - "version": "5.7.1", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/enzyme-adapter-utils": { - "version": "1.12.0", - "integrity": "sha512-wkZvE0VxcFx/8ZsBw0iAbk3gR1d9hK447ebnSYBf95+r32ezBq+XDSAvRErkc4LZosgH8J7et7H7/7CtUuQfBA==", + "version": "1.14.1", + "integrity": "sha512-JZgMPF1QOI7IzBj24EZoDpaeG/p8Os7WeBZWTJydpsH7JRStc7jYbHE4CmNQaLqazaGFyLM8ALWA3IIZvxW3PQ==", "dev": true, "dependencies": { - "airbnb-prop-types": "^2.13.2", - "function.prototype.name": "^1.1.0", - "object.assign": "^4.1.0", - "object.fromentries": "^2.0.0", - "prop-types": "^15.7.2", - "semver": "^5.6.0" + "airbnb-prop-types": "^2.16.0", + "function.prototype.name": "^1.1.5", + "has": "^1.0.3", + "object.assign": "^4.1.4", + "object.fromentries": "^2.0.5", + "prop-types": "^15.8.1", + "semver": "^5.7.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" }, "peerDependencies": { "react": "0.13.x || 0.14.x || ^15.0.0-0 || ^16.0.0-0" @@ -23944,6 +27346,18 @@ "enzyme": ">=3.4.0" } }, + "node_modules/enzyme-shallow-equal": { + "version": "1.0.5", + "integrity": "sha512-i6cwm7hN630JXenxxJFBKzgLC3hMTafFQXflvzHgPmDhOBhxUWDe8AeRv1qp2/uWJ2Y8z5yLWMzmAfkTOiOCZg==", + "dev": true, + "dependencies": { + "has": "^1.0.3", + "object-is": "^1.1.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/enzyme-to-json": { "version": "3.5.0", "integrity": "sha512-clusXRsiaQhG7+wtyc4t7MU8N3zCOgf4eY9+CeSenYzKlFST4lxerfOvnWd4SNaToKhkuba+w6m242YpQOS7eA==", @@ -23959,31 +27373,19 @@ "enzyme": "^3.4.0" } }, - "node_modules/enzyme-to-json/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, "node_modules/enzyme/node_modules/object-inspect": { - "version": "1.6.0", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true + "version": "1.12.3", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/err-code": { "version": "2.0.3", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "dev": true }, - "node_modules/errlop": { - "version": "2.2.0", - "integrity": "sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==", - "engines": { - "node": ">=0.8" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, "node_modules/errno": { "version": "0.1.7", "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", @@ -24009,29 +27411,42 @@ } }, "node_modules/es-abstract": { - "version": "1.19.1", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.21.1", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", "dependencies": { + "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" }, "engines": { "node": ">= 0.4" @@ -24041,8 +27456,8 @@ } }, "node_modules/es-abstract/node_modules/object-inspect": { - "version": "1.11.0", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "version": "1.12.3", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -24077,6 +27492,25 @@ "integrity": "sha512-MgtWFl5No+4S3TmhDmCz2ObFGm6lEpTnzbQi+Dd+pw4mlTIZTmM2iAs5gRlmx5zS9luzobCSBSI90JM/1/JgOw==", "dev": true }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dependencies": { + "has": "^1.0.3" + } + }, "node_modules/es-to-primitive": { "version": "1.2.1", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", @@ -24246,34 +27680,6 @@ "eslint-plugin-import": "^2.22.1" } }, - "node_modules/eslint-config-airbnb-base/node_modules/object.entries": { - "version": "1.1.3", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eslint-config-airbnb/node_modules/object.entries": { - "version": "1.1.3", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/eslint-config-prettier": { "version": "7.1.0", "integrity": "sha512-9sm5/PxaFG7qNJvJzTROMM1Bk1ozXVTKI0buKOyb0Bsr1hrwi0H/TzxF/COtf1uxikIK8SwhX7K6zg78jAzbeA==", @@ -24434,22 +27840,6 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" } }, - "node_modules/eslint-plugin-import/node_modules/array.prototype.flat": { - "version": "1.2.4", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", @@ -24622,37 +28012,6 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/object.entries": { - "version": "1.1.3", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eslint-plugin-react/node_modules/object.fromentries": { - "version": "2.0.3", - "integrity": "sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/eslint-plugin-testing-library": { "version": "3.10.1", "integrity": "sha512-nQIFe2muIFv2oR2zIuXE4vTbcFNx8hZKRzgHZqJg8rfopIWwoTwtlbCCNELT/jXzVe1uZF68ALGYoDXjLczKiQ==", @@ -25297,15 +28656,15 @@ } }, "node_modules/express": { - "version": "4.17.1", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.3", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", "dependencies": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -25319,13 +28678,13 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", @@ -25335,56 +28694,52 @@ "node": ">= 0.10.0" } }, - "node_modules/express/node_modules/accepts": { - "version": "1.3.7", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/express/node_modules/array-flatten": { "version": "1.1.1", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, - "node_modules/express/node_modules/negotiator": { - "version": "0.6.2", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "node_modules/express/node_modules/cookie": { + "version": "0.4.2", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "engines": { "node": ">= 0.6" } }, - "node_modules/express/node_modules/parseurl": { - "version": "1.3.3", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/express/node_modules/path-to-regexp": { "version": "0.1.7", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "node_modules/express/node_modules/qs": { - "version": "6.7.0", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.9.7", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/express/node_modules/setprototypeof": { - "version": "1.1.1", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "node_modules/express/node_modules/statuses": { - "version": "1.5.0", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } + "node_modules/express/node_modules/setprototypeof": { + "version": "1.2.0", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/expression-eval": { "version": "2.1.0", @@ -25410,7 +28765,7 @@ "node_modules/external-editor": { "version": "3.1.0", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "devOptional": true, + "dev": true, "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -25423,7 +28778,7 @@ "node_modules/external-editor/node_modules/tmp": { "version": "0.0.33", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "devOptional": true, + "dev": true, "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -25795,7 +29150,7 @@ "node_modules/figures": { "version": "3.2.0", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "devOptional": true, + "dev": true, "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -25836,8 +29191,8 @@ } }, "node_modules/file-loader/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -25846,8 +29201,8 @@ } }, "node_modules/file-loader/node_modules/loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -25899,10 +29254,30 @@ } }, "node_modules/filelist": { - "version": "1.0.2", - "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "version": "1.0.4", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, "dependencies": { - "minimatch": "^3.0.4" + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.0", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/filename-reserved-regex": { @@ -25971,20 +29346,6 @@ "node": ">= 0.8" } }, - "node_modules/finalhandler/node_modules/parseurl": { - "version": "1.3.3", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/statuses": { - "version": "1.5.0", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/find-cache-dir": { "version": "2.1.0", "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", @@ -26022,15 +29383,12 @@ "node": ">=4" } }, - "node_modules/first-chunk-stream": { - "version": "2.0.0", - "integrity": "sha512-X8Z+b/0L4lToKYq+lwnKqi9X/Zek0NibLpsJgVsSxpoYq7JtiCtRb5HqKVEjEw/qAb/4AKKRLOwwKHlWNpm2Eg==", - "optional": true, - "dependencies": { - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" + "node_modules/flat": { + "version": "5.0.2", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" } }, "node_modules/flat-cache": { @@ -26061,9 +29419,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.8", - "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", - "devOptional": true, + "version": "1.15.2", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, "funding": [ { "type": "individual", @@ -26084,6 +29442,13 @@ "integrity": "sha512-qKVeWWNvkPP22FUkea2qVgZHiPBIRk9HFGIFmEUbqEV7Wcu/Dxrva4t7d1XPa2+0cnJgD0kHAiDZ514KjHYQKA==", "deprecated": "Package relocated. Please install and migrate to @fontsource/fira-code." }, + "node_modules/for-each": { + "version": "0.3.3", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/for-in": { "version": "1.0.2", "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", @@ -26356,8 +29721,8 @@ "dev": true }, "node_modules/fs-extra": { - "version": "10.0.0", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "version": "10.1.0", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -26400,21 +29765,57 @@ "version": "1.0.0", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/ftp": { + "version": "0.3.10", + "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==", + "dev": true, + "dependencies": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ftp/node_modules/isarray": { + "version": "0.0.1", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/ftp/node_modules/readable-stream": { + "version": "1.1.14", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/ftp/node_modules/string_decoder": { + "version": "0.10.31", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, "node_modules/function-bind": { "version": "1.1.1", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/function.prototype.name": { - "version": "1.1.1", - "integrity": "sha512-e1NzkiJuw6xqVH7YSdiW/qDHebcmMhPNe6w+4ZYYEg0VA+LaLzx37RimbPLuonHhYGFGPx1ME2nSi74JiaCr/Q==", + "version": "1.1.5", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", "dependencies": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "function-bind": "^1.1.1", - "functions-have-names": "^1.1.1", - "is-callable": "^1.1.4" + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/functional-red-black-tree": { @@ -26423,8 +29824,11 @@ "dev": true }, "node_modules/functions-have-names": { - "version": "1.1.1", - "integrity": "sha512-U0kNHUoxwPNPWOJaMG7Z00d4a/qZVrFtzWJRaK8V9goaVOCXBSQSJpt3MYGNtkScKEBKovxLjnNdC9MlXwo5Pw==" + "version": "1.2.3", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/fuse.js": { "version": "6.4.6", @@ -26434,42 +29838,61 @@ } }, "node_modules/gauge": { - "version": "2.7.4", - "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", + "version": "4.0.4", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", "dev": true, "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" } }, "node_modules/gauge/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "version": "3.0.0", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "number-is-nan": "^1.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/gauge/node_modules/string-width": { - "version": "1.0.2", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/gensync": { @@ -26513,12 +29936,12 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.0", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -26718,6 +30141,80 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-uri": { + "version": "3.0.2", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/get-uri/node_modules/debug": { + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/get-uri/node_modules/file-uri-to-path": { + "version": "2.0.0", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "8.1.0", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/get-uri/node_modules/jsonfile": { + "version": "4.0.0", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/node_modules/ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/get-uri/node_modules/universalify": { + "version": "0.1.2", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/get-value": { "version": "2.0.6", "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", @@ -26733,17 +30230,6 @@ "assert-plus": "^1.0.0" } }, - "node_modules/gh-got": { - "version": "5.0.0", - "integrity": "sha512-B9bWm0vDR7CSbFPxt528dbMTWd9CUc4h9U3Ji7e781Jy9Xm0p6QWKVndA4ETEzDCd3/GqVCjVfqqpl2kR1j3nA==", - "dependencies": { - "got": "^6.2.0", - "is-plain-obj": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/gh-pages": { "version": "3.2.3", "integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==", @@ -26775,8 +30261,8 @@ } }, "node_modules/gh-pages/node_modules/async": { - "version": "2.6.3", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dependencies": { "lodash": "^4.17.14" } @@ -27022,20 +30508,20 @@ } }, "node_modules/git-up": { - "version": "4.0.5", - "integrity": "sha512-YUvVDg/vX3d0syBsk/CKUTib0srcQME0JyHkL5BaYdwLsiCslPWmDSi8PUMo9pXYjrryMcmsCoCgsTpSCJEQaA==", + "version": "7.0.0", + "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", "dev": true, "dependencies": { - "is-ssh": "^1.3.0", - "parse-url": "^6.0.0" + "is-ssh": "^1.4.0", + "parse-url": "^8.1.0" } }, "node_modules/git-url-parse": { - "version": "11.6.0", - "integrity": "sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g==", + "version": "13.1.0", + "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==", "dev": true, "dependencies": { - "git-up": "^4.0.0" + "git-up": "^7.0.0" } }, "node_modules/gitconfiglocal": { @@ -27052,13 +30538,16 @@ "dev": true }, "node_modules/github-username": { - "version": "3.0.0", - "integrity": "sha512-pbA1zobA7urImyNixOkCb/eO2fRadF7+RZgdjzT3/k/KukA8CY7QZ7BNCdCetH1kB0YqeBmY+Hn76XaC3rmmzQ==", + "version": "6.0.0", + "integrity": "sha512-7TTrRjxblSI5l6adk9zd+cV5d6i1OrJSo3Vr9xdGqFLBQo0mz5P9eIfKCDJ7eekVGGFLbce0qbPSnktXV2BjDQ==", "dependencies": { - "gh-got": "^5.0.0" + "@octokit/rest": "^18.0.6" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/gl-matrix": { @@ -27066,13 +30555,13 @@ "integrity": "sha512-COb7LDz+SXaHtl/h4LeaFcNdJdAQSDeVqjiIihSXNrkWObZLhDI4hIkZC11Aeqp7bcE72clzB0BnDXr2SmslRA==" }, "node_modules/glob": { - "version": "7.1.7", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "version": "7.2.3", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -27185,31 +30674,14 @@ "node": ">=8" } }, - "node_modules/got": { - "version": "6.7.1", - "integrity": "sha512-Y/K3EDuiQN9rTZhBvPRWMLXIKdeD1Rj0nzunfoi0Yyn5WBEbzxXKU9Ub2X41oZBagVWOBU3MuDonFMgPWQFnwg==", + "node_modules/gopd": { + "version": "1.0.1", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dependencies": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" + "get-intrinsic": "^1.1.3" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/got/node_modules/get-stream": { - "version": "3.0.0", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/graceful-fs": { @@ -27233,10 +30705,6 @@ "dev": true, "optional": true }, - "node_modules/gud": { - "version": "1.0.0", - "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" - }, "node_modules/h3-js": { "version": "3.7.2", "integrity": "sha512-LPjlHSwB9zQZrMqKloCZmmmt3yZzIK7nqPcXqwU93zT3TtYG6jP4tZBzAPouxut7lLjdFbMQ75wRBiKfpsnY7w==", @@ -27334,8 +30802,8 @@ } }, "node_modules/has-bigints": { - "version": "1.0.1", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -27367,9 +30835,29 @@ "node": ">=0.10.0" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { - "version": "1.0.2", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "engines": { "node": ">= 0.4" }, @@ -27765,10 +31253,6 @@ "react-is": "^16.7.0" } }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/homedir-polyfill": { "version": "1.0.3", "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", @@ -27796,22 +31280,48 @@ } }, "node_modules/html-element-map": { - "version": "1.1.0", - "integrity": "sha512-iqiG3dTZmy+uUaTmHarTL+3/A2VW9ox/9uasKEZC+R/wAtUrTcRlXPSaPqsnWPfIu8wqn09jQNwMRqzL54jSYA==", + "version": "1.3.1", + "integrity": "sha512-6XMlxrAFX4UEEGxctfFnmrFaaZFNf9i5fNuV5wZ3WWQ4FVaNP1aX1LkX9j2mfEx1NpjeE/rL3nmgEn23GdFmrg==", "dev": true, "dependencies": { - "array-filter": "^1.0.0" + "array.prototype.filter": "^1.0.0", + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "version": "3.0.0", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", "dev": true, "dependencies": { - "whatwg-encoding": "^1.0.5" + "whatwg-encoding": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" + } + }, + "node_modules/html-encoding-sniffer/node_modules/iconv-lite": { + "version": "0.6.3", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/html-encoding-sniffer/node_modules/whatwg-encoding": { + "version": "2.0.0", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" } }, "node_modules/html-entities": { @@ -27922,8 +31432,8 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-deceiver": { @@ -27946,8 +31456,8 @@ } }, "node_modules/http-parser-js": { - "version": "0.5.3", - "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", + "version": "0.5.8", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "node_modules/http-proxy": { @@ -27998,11 +31508,11 @@ "dev": true }, "node_modules/http-proxy-middleware": { - "version": "2.0.1", - "integrity": "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==", + "version": "2.0.6", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, "dependencies": { - "@types/http-proxy": "^1.17.5", + "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", @@ -28010,6 +31520,14 @@ }, "engines": { "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } } }, "node_modules/http-proxy-middleware/node_modules/braces": { @@ -28054,12 +31572,12 @@ } }, "node_modules/http-proxy-middleware/node_modules/micromatch": { - "version": "4.0.4", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "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" @@ -28130,7 +31648,7 @@ "node_modules/human-signals": { "version": "1.1.1", "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "devOptional": true, + "dev": true, "engines": { "node": ">=8.12.0" } @@ -28203,11 +31721,33 @@ "dev": true }, "node_modules/ignore-walk": { - "version": "3.0.4", - "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "version": "5.0.1", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", "dev": true, "dependencies": { - "minimatch": "^3.0.4" + "minimatch": "^5.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "5.1.2", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/image-size": { @@ -28403,75 +31943,74 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/init-package-json": { - "version": "2.0.5", - "integrity": "sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA==", + "version": "3.0.2", + "integrity": "sha512-YhlQPEjNFqlGdzrBfDNRLhvoSgX7iQRgSxgsNknRQ9ITXFT7UMfVMWhBTOh2Y+25lRnGrv5Xz8yZwQ3ACR6T3A==", "dev": true, "dependencies": { - "npm-package-arg": "^8.1.5", + "npm-package-arg": "^9.0.1", "promzard": "^0.3.0", - "read": "~1.0.1", - "read-package-json": "^4.1.1", + "read": "^1.0.7", + "read-package-json": "^5.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^3.0.0" + "validate-npm-package-name": "^4.0.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/init-package-json/node_modules/builtins": { + "version": "5.0.1", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" } }, "node_modules/init-package-json/node_modules/hosted-git-info": { - "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "lru-cache": "^7.5.1" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/init-package-json/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/init-package-json/node_modules/normalize-package-data": { - "version": "3.0.3", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "node_modules/init-package-json/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "dev": true, "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/init-package-json/node_modules/read-package-json": { - "version": "4.1.1", - "integrity": "sha512-P82sbZJ3ldDrWCOSKxJT0r/CXMWR0OR3KRh55SgKo3p91GSIEEC32v3lSHAvO/UcH3/IoL7uqhOFBduAnwdldw==", + "node_modules/init-package-json/node_modules/proc-log": { + "version": "2.0.1", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", "dev": true, - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^3.0.0", - "npm-normalize-package-bin": "^1.0.0" - }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/init-package-json/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -28483,6 +32022,28 @@ "node": ">=10" } }, + "node_modules/init-package-json/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/init-package-json/node_modules/validate-npm-package-name": { + "version": "4.0.0", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/init-package-json/node_modules/yallist": { "version": "4.0.0", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", @@ -28501,32 +32062,34 @@ } }, "node_modules/inquirer": { - "version": "7.3.3", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "devOptional": true, + "version": "8.2.5", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, "dependencies": { "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", + "chalk": "^4.1.1", "cli-cursor": "^3.1.0", "cli-width": "^3.0.0", "external-editor": "^3.0.3", "figures": "^3.0.0", - "lodash": "^4.17.19", + "lodash": "^4.17.21", "mute-stream": "0.0.8", + "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^6.6.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=12.0.0" } }, "node_modules/inquirer/node_modules/ansi-regex": { "version": "5.0.1", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "devOptional": true, + "dev": true, "engines": { "node": ">=8" } @@ -28534,15 +32097,23 @@ "node_modules/inquirer/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "devOptional": true, + "dev": true, "engines": { "node": ">=8" } }, + "node_modules/inquirer/node_modules/rxjs": { + "version": "7.8.0", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/inquirer/node_modules/string-width": { "version": "4.2.3", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "devOptional": true, + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -28555,7 +32126,7 @@ "node_modules/inquirer/node_modules/strip-ansi": { "version": "6.0.1", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -28563,40 +32134,32 @@ "node": ">=8" } }, - "node_modules/insert-css": { - "version": "2.0.0", - "integrity": "sha512-xGq5ISgcUP5cvGkS2MMFLtPDBtrtQPSFfC6gA6U8wHKqfjTIMZLZNxOItQnoSjdOzlXOLU/yD32RKC4SvjNbtA==" + "node_modules/inquirer/node_modules/tslib": { + "version": "2.4.1", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true }, - "node_modules/internal-ip": { - "version": "6.2.0", - "integrity": "sha512-D8WGsR6yDt8uq7vDMu7mjcR+yRMm3dW8yufyChmszWRjcSHuxLBkR3GdS2HZAjodsaGuCvXeEJpueisXJULghg==", + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "7.0.0", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { - "default-gateway": "^6.0.0", - "ipaddr.js": "^1.9.1", - "is-ip": "^3.1.0", - "p-event": "^4.2.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sindresorhus/internal-ip?sponsor=1" - } - }, - "node_modules/internal-ip/node_modules/ipaddr.js": { - "version": "1.9.1", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/internal-slot": { - "version": "1.0.3", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.4", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", "dependencies": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.1.3", "has": "^1.0.3", "side-channel": "^1.0.4" }, @@ -28616,15 +32179,17 @@ } }, "node_modules/interweave": { - "version": "11.2.0", - "integrity": "sha512-33h9LOXbT52tMin3IyLBPcd5RbiwroP/Sxr0OamnJJU7A/jh0XtZKGvdcSNKYRC7sLZuDk+ZJ2XVrmkcMU5i6w==", + "version": "13.0.0", + "integrity": "sha512-Mckwj+ix/VtrZu1bRBIIohwrsXj12ZTvJCoYUMZlJmgtvIaQCj0i77eSZ63ckbA1TsPrz2VOvLW9/kTgm5d+mw==", "dependencies": { - "@types/react": "*", - "escape-html": "^1.0.3", - "prop-types": "^15.7.2" + "escape-html": "^1.0.3" + }, + "funding": { + "type": "ko-fi", + "url": "https://ko-fi.com/milesjohnson" }, "peerDependencies": { - "react": "^16.3.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/invariant": { @@ -28638,14 +32203,6 @@ "version": "1.1.5", "integrity": "sha512-rBtCAQAJm8A110nbwn6YdveUnuZH3WrC36IwkRXxDnq53JvXA2NVQvB7IHyKomxK1MJ4VDNw3UtFDdXQ+AvLYA==" }, - "node_modules/ip-regex": { - "version": "2.1.0", - "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/ipaddr.js": { "version": "2.0.1", "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", @@ -28712,6 +32269,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-array-buffer": { + "version": "3.0.1", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" @@ -28756,8 +32325,8 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "node_modules/is-callable": { - "version": "1.2.4", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "engines": { "node": ">= 0.4" }, @@ -28777,8 +32346,8 @@ } }, "node_modules/is-core-module": { - "version": "2.8.0", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.11.0", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dependencies": { "has": "^1.0.3" }, @@ -28905,25 +32474,6 @@ "node": ">=8" } }, - "node_modules/is-ip": { - "version": "3.1.0", - "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==", - "dev": true, - "dependencies": { - "ip-regex": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-ip/node_modules/ip-regex": { - "version": "4.3.0", - "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-lambda": { "version": "1.0.1", "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", @@ -28937,8 +32487,8 @@ } }, "node_modules/is-negative-zero": { - "version": "2.0.1", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "version": "2.0.2", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "engines": { "node": ">= 0.4" }, @@ -29005,25 +32555,10 @@ "node": ">=4" } }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "1.1.0", "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -29048,13 +32583,6 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, - "node_modules/is-redirect": { - "version": "1.0.0", - "integrity": "sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-regex": { "version": "1.1.4", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", @@ -29078,13 +32606,6 @@ "version": "1.0.3", "integrity": "sha512-/tCmbIETZwCd8uHWO+GvbRa7jxwHFHdfetHfiwoP0aN9UDf3prUJMtKn7iBFYipYhqY1bSTjur8hC/Dakt8eyw==" }, - "node_modules/is-retry-allowed": { - "version": "1.2.0", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-set": { "version": "2.0.2", "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", @@ -29093,18 +32614,21 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "version": "1.0.2", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-ssh": { - "version": "1.3.3", - "integrity": "sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ==", + "version": "1.4.0", + "integrity": "sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==", "dev": true, "dependencies": { - "protocols": "^1.1.0" + "protocols": "^2.0.1" } }, "node_modules/is-stream": { @@ -29156,6 +32680,23 @@ "node": ">=0.10.0" } }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", @@ -29172,16 +32713,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-utf8": { - "version": "0.2.1", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", - "optional": true - }, "node_modules/is-weakref": { - "version": "1.0.1", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "version": "1.0.2", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dependencies": { - "call-bind": "^1.0.0" + "call-bind": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -29228,6 +32764,7 @@ "node_modules/isbinaryfile": { "version": "4.0.8", "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "dev": true, "engines": { "node": ">= 8.0.0" }, @@ -29381,41 +32918,6 @@ "node": ">=8" } }, - "node_modules/istextorbinary": { - "version": "2.6.0", - "integrity": "sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==", - "dependencies": { - "binaryextensions": "^2.1.2", - "editions": "^2.2.0", - "textextensions": "^2.5.0" - }, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, - "node_modules/istextorbinary/node_modules/binaryextensions": { - "version": "2.3.0", - "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", - "engines": { - "node": ">=0.8" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, - "node_modules/istextorbinary/node_modules/textextensions": { - "version": "2.6.0", - "integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==", - "engines": { - "node": ">=0.8" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, "node_modules/iterate-iterator": { "version": "1.0.2", "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", @@ -29435,11 +32937,12 @@ } }, "node_modules/jake": { - "version": "10.8.2", - "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "version": "10.8.5", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "dev": true, "dependencies": { - "async": "0.9.x", - "chalk": "^2.4.2", + "async": "^3.2.3", + "chalk": "^4.0.2", "filelist": "^1.0.1", "minimatch": "^3.0.4" }, @@ -29447,43 +32950,7 @@ "jake": "bin/cli.js" }, "engines": { - "node": "*" - } - }, - "node_modules/jake/node_modules/ansi-styles": { - "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/jake/node_modules/async": { - "version": "0.9.2", - "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==" - }, - "node_modules/jake/node_modules/chalk": { - "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/jake/node_modules/supports-color": { - "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" + "node": ">=10" } }, "node_modules/java-properties": { @@ -30479,6 +33946,84 @@ "node": ">=8" } }, + "node_modules/jest-environment-jsdom/node_modules/cssom": { + "version": "0.4.4", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/jest-environment-jsdom/node_modules/data-urls": { + "version": "2.0.0", + "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/jest-environment-jsdom/node_modules/domexception": { + "version": "2.0.1", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom/node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom/node_modules/escodegen": { + "version": "2.0.0", + "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/jest-environment-jsdom/node_modules/esprima": { + "version": "4.0.1", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-environment-jsdom/node_modules/estraverse": { + "version": "5.3.0", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/jest-environment-jsdom/node_modules/fill-range": { "version": "7.0.1", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", @@ -30490,6 +34035,30 @@ "node": ">=8" } }, + "node_modules/jest-environment-jsdom/node_modules/form-data": { + "version": "3.0.1", + "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/jest-environment-jsdom/node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest-environment-jsdom/node_modules/is-number": { "version": "7.0.0", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", @@ -30514,6 +34083,51 @@ "node": ">= 10.14.2" } }, + "node_modules/jest-environment-jsdom/node_modules/jsdom": { + "version": "16.7.0", + "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/jest-environment-jsdom/node_modules/micromatch": { "version": "4.0.2", "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", @@ -30526,6 +34140,20 @@ "node": ">=8" } }, + "node_modules/jest-environment-jsdom/node_modules/parse5": { + "version": "6.0.1", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/jest-environment-jsdom/node_modules/source-map": { + "version": "0.6.1", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jest-environment-jsdom/node_modules/to-regex-range": { "version": "5.0.1", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", @@ -30537,6 +34165,70 @@ "node": ">=8.0" } }, + "node_modules/jest-environment-jsdom/node_modules/tough-cookie": { + "version": "4.0.0", + "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/jest-environment-jsdom/node_modules/tr46": { + "version": "2.1.0", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom/node_modules/universalify": { + "version": "0.1.2", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/jest-environment-jsdom/node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-environment-jsdom/node_modules/webidl-conversions": { + "version": "6.1.0", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/jest-environment-jsdom/node_modules/whatwg-url": { + "version": "8.7.0", + "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/jest-environment-node": { "version": "26.6.2", "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", @@ -31612,6 +35304,11 @@ "node": ">=8.0" } }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", + "dev": true + }, "node_modules/jquery": { "version": "3.6.0", "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" @@ -31641,6 +35338,10 @@ "node": ">=0.10.0" } }, + "node_modules/js-sha3": { + "version": "0.8.0", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, "node_modules/js-string-escape": { "version": "1.0.1", "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", @@ -31689,39 +35390,40 @@ "dev": true }, "node_modules/jsdom": { - "version": "16.4.0", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "version": "20.0.0", + "integrity": "sha512-x4a6CKCgx00uCmP+QakBDFXwjAJ69IkkIWHmtmjd3wvXPcdOS44hfX2vqkOQrVrq8l9DhNNADZRXaCEWvgXtVA==", "dev": true, "dependencies": { - "abab": "^2.0.3", - "acorn": "^7.1.1", + "abab": "^2.0.6", + "acorn": "^8.7.1", "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.2.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", - "domexception": "^2.0.1", - "escodegen": "^1.14.1", - "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.3.1", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.0", - "parse5": "5.1.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", + "parse5": "^7.0.0", + "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", + "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.0.0", - "ws": "^7.2.3", - "xml-name-validator": "^3.0.0" + "w3c-xmlserializer": "^3.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.8.0", + "xml-name-validator": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" }, "peerDependencies": { "canvas": "^2.5.0" @@ -31732,24 +35434,48 @@ } } }, - "node_modules/jsdom/node_modules/acorn": { - "version": "7.4.1", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/jsdom/node_modules/@tootallnate/once": { + "version": "2.0.0", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "engines": { + "node": ">= 10" + } + }, + "node_modules/jsdom/node_modules/debug": { + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" }, "engines": { - "node": ">=0.4.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/entities": { + "version": "4.3.1", + "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/jsdom/node_modules/escodegen": { - "version": "1.14.3", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.0.0", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "dependencies": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", + "estraverse": "^5.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1" }, @@ -31758,7 +35484,7 @@ "esgenerate": "bin/esgenerate.js" }, "engines": { - "node": ">=4.0" + "node": ">=6.0" }, "optionalDependencies": { "source-map": "~0.6.1" @@ -31776,11 +35502,90 @@ "node": ">=4" } }, - "node_modules/jsdom/node_modules/parse5": { - "version": "5.1.1", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "node_modules/jsdom/node_modules/estraverse": { + "version": "5.3.0", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/jsdom/node_modules/form-data": { + "version": "4.0.0", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/http-proxy-agent": { + "version": "5.0.0", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "5.0.1", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/iconv-lite": { + "version": "0.6.3", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsdom/node_modules/ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/jsdom/node_modules/parse5": { + "version": "7.0.0", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "dev": true, + "dependencies": { + "entities": "^4.3.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/jsdom/node_modules/saxes": { + "version": "6.0.0", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/jsdom/node_modules/source-map": { "version": "0.6.1", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", @@ -31791,48 +35596,102 @@ } }, "node_modules/jsdom/node_modules/tough-cookie": { - "version": "3.0.1", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "version": "4.0.0", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", "dev": true, "dependencies": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" }, "engines": { "node": ">=6" } }, "node_modules/jsdom/node_modules/tr46": { - "version": "2.0.2", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "version": "3.0.0", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, "dependencies": { "punycode": "^2.1.1" }, "engines": { - "node": ">=8" + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/universalify": { + "version": "0.1.2", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" } }, "node_modules/jsdom/node_modules/webidl-conversions": { - "version": "6.1.0", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "version": "7.0.0", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, "engines": { - "node": ">=10.4" + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-encoding": { + "version": "2.0.0", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-mimetype": { + "version": "3.0.0", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" } }, "node_modules/jsdom/node_modules/whatwg-url": { - "version": "8.4.0", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "11.0.0", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^6.1.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "8.8.0", + "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==", + "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/jsdom/node_modules/xml-name-validator": { + "version": "4.0.0", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" } }, "node_modules/jsep": { @@ -31875,8 +35734,8 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema": { - "version": "0.2.3", - "integrity": "sha512-a3xHnILGMtk+hDOqNwHzF6e2fNbiMrXZvxKQiEv2MlgQP+pjIOzqAmKYD2mDpXYE/44M7g+n9p2bKkYWDUcXCQ==", + "version": "0.4.0", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "dev": true }, "node_modules/json-schema-traverse": { @@ -31888,6 +35747,14 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json-stringify-nice": { + "version": "1.1.4", + "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/json-stringify-pretty-compact": { "version": "2.0.0", "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==" @@ -31905,8 +35772,8 @@ } }, "node_modules/json5": { - "version": "1.0.1", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dependencies": { "minimist": "^1.2.0" }, @@ -31914,6 +35781,11 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/jsonfile": { "version": "6.1.0", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", @@ -31927,7 +35799,7 @@ "node_modules/jsonparse": { "version": "1.3.1", "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "devOptional": true, + "dev": true, "engines": [ "node >= 0.2.0" ] @@ -31935,7 +35807,7 @@ "node_modules/JSONStream": { "version": "1.3.5", "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "devOptional": true, + "dev": true, "dependencies": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" @@ -31948,17 +35820,17 @@ } }, "node_modules/jsprim": { - "version": "1.4.1", - "integrity": "sha512-4Dj8Rf+fQ+/Pn7C5qeEX02op1WfOss3PKTE9Nsop3Dx+6UPxlm1dr/og7o2cRa5hNN07CACr4NFzRLtj/rjWog==", + "version": "1.4.2", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, - "engines": [ - "node >=0.6.0" - ], "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" } }, "node_modules/jsx-ast-utils": { @@ -32055,17 +35927,6 @@ "language-subtag-registry": "~0.3.2" } }, - "node_modules/lazy-cache": { - "version": "2.0.2", - "integrity": "sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==", - "optional": true, - "dependencies": { - "set-getter": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/lazy-universal-dotenv": { "version": "3.0.1", "integrity": "sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==", @@ -32089,34 +35950,39 @@ "dev": true }, "node_modules/lerna": { - "version": "4.0.0", - "integrity": "sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg==", - "dev": true, - "dependencies": { - "@lerna/add": "4.0.0", - "@lerna/bootstrap": "4.0.0", - "@lerna/changed": "4.0.0", - "@lerna/clean": "4.0.0", - "@lerna/cli": "4.0.0", - "@lerna/create": "4.0.0", - "@lerna/diff": "4.0.0", - "@lerna/exec": "4.0.0", - "@lerna/import": "4.0.0", - "@lerna/info": "4.0.0", - "@lerna/init": "4.0.0", - "@lerna/link": "4.0.0", - "@lerna/list": "4.0.0", - "@lerna/publish": "4.0.0", - "@lerna/run": "4.0.0", - "@lerna/version": "4.0.0", + "version": "6.1.0", + "integrity": "sha512-3qAjIj8dgBwHtCAiLbq4VU/C1V9D1tvTLm2owZubdGAN72aB5TxuCu2mcw+yeEorOcXuR9YWx7EXIkAf+G0N2w==", + "dev": true, + "dependencies": { + "@lerna/add": "6.1.0", + "@lerna/bootstrap": "6.1.0", + "@lerna/changed": "6.1.0", + "@lerna/clean": "6.1.0", + "@lerna/cli": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/create": "6.1.0", + "@lerna/diff": "6.1.0", + "@lerna/exec": "6.1.0", + "@lerna/import": "6.1.0", + "@lerna/info": "6.1.0", + "@lerna/init": "6.1.0", + "@lerna/link": "6.1.0", + "@lerna/list": "6.1.0", + "@lerna/publish": "6.1.0", + "@lerna/run": "6.1.0", + "@lerna/version": "6.1.0", + "@nrwl/devkit": ">=14.8.6 < 16", "import-local": "^3.0.2", - "npmlog": "^4.1.2" + "inquirer": "^8.2.4", + "npmlog": "^6.0.2", + "nx": ">=14.8.6 < 16", + "typescript": "^3 || ^4" }, "bin": { "lerna": "cli.js" }, "engines": { - "node": ">= 10.18.0" + "node": "^14.15.0 || >=16.0.0" } }, "node_modules/less": { @@ -32190,17 +36056,17 @@ } }, "node_modules/libnpmaccess": { - "version": "4.0.3", - "integrity": "sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ==", + "version": "6.0.4", + "integrity": "sha512-qZ3wcfIyUoW0+qSFkMBovcTrSGJ3ZeyvpR7d5N9pEYv/kXs8sHP2wiqEIXBKLFrZlmM0kR0RJD7mtfLngtlLag==", "dev": true, "dependencies": { "aproba": "^2.0.0", "minipass": "^3.1.1", - "npm-package-arg": "^8.1.2", - "npm-registry-fetch": "^11.0.0" + "npm-package-arg": "^9.0.1", + "npm-registry-fetch": "^13.0.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/libnpmaccess/node_modules/aproba": { @@ -32208,33 +36074,103 @@ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, - "node_modules/libnpmpublish": { - "version": "4.0.2", - "integrity": "sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw==", + "node_modules/libnpmaccess/node_modules/builtins": { + "version": "5.0.1", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", "dev": true, "dependencies": { - "normalize-package-data": "^3.0.2", - "npm-package-arg": "^8.1.2", - "npm-registry-fetch": "^11.0.0", - "semver": "^7.1.3", - "ssri": "^8.0.1" + "semver": "^7.0.0" + } + }, + "node_modules/libnpmaccess/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/libnpmpublish/node_modules/hosted-git-info": { - "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "node_modules/libnpmaccess/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/libnpmaccess/node_modules/minipass-fetch": { + "version": "2.1.2", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/libnpmaccess/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/libnpmaccess/node_modules/npm-registry-fetch": { + "version": "13.3.1", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/libnpmaccess/node_modules/proc-log": { + "version": "2.0.1", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/libnpmaccess/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, + "bin": { + "semver": "bin/semver.js" + }, "engines": { "node": ">=10" } }, - "node_modules/libnpmpublish/node_modules/lru-cache": { + "node_modules/libnpmaccess/node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, @@ -32245,23 +36181,136 @@ "node": ">=10" } }, + "node_modules/libnpmaccess/node_modules/validate-npm-package-name": { + "version": "4.0.0", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/libnpmaccess/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/libnpmpublish": { + "version": "6.0.5", + "integrity": "sha512-LUR08JKSviZiqrYTDfywvtnsnxr+tOvBU0BF8H+9frt7HMvc6Qn6F8Ubm72g5hDTHbq8qupKfDvDAln2TVPvFg==", + "dev": true, + "dependencies": { + "normalize-package-data": "^4.0.0", + "npm-package-arg": "^9.0.1", + "npm-registry-fetch": "^13.0.0", + "semver": "^7.3.7", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/libnpmpublish/node_modules/builtins": { + "version": "5.0.1", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/libnpmpublish/node_modules/hosted-git-info": { + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/libnpmpublish/node_modules/lru-cache": { + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/libnpmpublish/node_modules/minipass-fetch": { + "version": "2.1.2", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, "node_modules/libnpmpublish/node_modules/normalize-package-data": { - "version": "3.0.3", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "version": "4.0.1", + "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", "dev": true, "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/libnpmpublish/node_modules/npm-package-arg": { + "version": "9.1.2", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/libnpmpublish/node_modules/npm-registry-fetch": { + "version": "13.3.1", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/libnpmpublish/node_modules/proc-log": { + "version": "2.0.1", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/libnpmpublish/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -32273,15 +36322,37 @@ "node": ">=10" } }, + "node_modules/libnpmpublish/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/libnpmpublish/node_modules/ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "version": "9.0.1", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", "dev": true, "dependencies": { "minipass": "^3.1.1" }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/libnpmpublish/node_modules/validate-npm-package-name": { + "version": "4.0.0", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/libnpmpublish/node_modules/yallist": { @@ -32358,8 +36429,8 @@ } }, "node_modules/listr-update-renderer/node_modules/ansi-regex": { - "version": "3.0.0", - "integrity": "sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==", + "version": "3.0.1", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", "dev": true, "engines": { "node": ">=4" @@ -32707,8 +36778,8 @@ } }, "node_modules/loader-utils": { - "version": "1.4.0", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -32758,11 +36829,6 @@ "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", "dev": true }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", - "dev": true - }, "node_modules/lodash.camelcase": { "version": "4.3.0", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" @@ -32790,10 +36856,6 @@ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, - "node_modules/lodash.flow": { - "version": "3.5.0", - "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" - }, "node_modules/lodash.get": { "version": "4.4.2", "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" @@ -32854,32 +36916,8 @@ }, "node_modules/lodash.sortby": { "version": "4.7.0", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" - }, - "node_modules/lodash.template": { - "version": "4.5.0", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "node_modules/lodash.templatesettings": { - "version": "4.2.0", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "node_modules/lodash.throttle": { - "version": "4.1.1", - "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" - }, - "node_modules/lodash.topath": { - "version": "4.5.2", - "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg==" + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true }, "node_modules/lodash.truncate": { "version": "4.4.2", @@ -32933,13 +36971,6 @@ "version": "2.1.0", "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/lowlight": { "version": "1.20.0", "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", @@ -32993,56 +37024,98 @@ } }, "node_modules/make-fetch-happen": { - "version": "8.0.14", - "integrity": "sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==", + "version": "10.2.1", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", "dev": true, "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.0.5", + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", + "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", + "minipass-fetch": "^2.0.3", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", "promise-retry": "^2.0.1", - "socks-proxy-agent": "^5.0.0", - "ssri": "^8.0.0" + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/@npmcli/fs": { + "version": "2.1.2", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "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/make-fetch-happen/node_modules/@npmcli/move-file": { + "version": "2.0.1", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/@tootallnate/once": { + "version": "2.0.0", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, "engines": { "node": ">= 10" } }, + "node_modules/make-fetch-happen/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/make-fetch-happen/node_modules/cacache": { - "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "version": "16.1.3", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", "dev": true, "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", + "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.0.2", - "unique-filename": "^1.1.1" + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" }, "engines": { - "node": ">= 10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/make-fetch-happen/node_modules/chownr": { @@ -33053,17 +37126,88 @@ "node": ">=10" } }, + "node_modules/make-fetch-happen/node_modules/debug": { + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/make-fetch-happen/node_modules/glob": { + "version": "8.0.3", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { + "version": "5.0.0", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-fetch-happen/node_modules/minimatch": { + "version": "5.1.2", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" } }, + "node_modules/make-fetch-happen/node_modules/minipass-fetch": { + "version": "2.1.2", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, "node_modules/make-fetch-happen/node_modules/mkdirp": { "version": "1.0.4", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", @@ -33075,15 +37219,67 @@ "node": ">=10" } }, + "node_modules/make-fetch-happen/node_modules/ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/make-fetch-happen/node_modules/semver": { + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/make-fetch-happen/node_modules/ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "version": "9.0.1", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", "dev": true, "dependencies": { "minipass": "^3.1.1" }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/unique-filename": { + "version": "2.0.1", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/unique-slug": { + "version": "3.0.0", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/make-fetch-happen/node_modules/yallist": { @@ -33143,16 +37339,16 @@ } }, "node_modules/mapbox-gl": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-2.12.1.tgz", - "integrity": "sha512-45LVQauimFGX/fkCJzK3O2KpQQrIB0fGlg8sERu4NH0xWiBw9JsLOLYD2xAgD5SPramQvsjzM7vYWIkGxpGYNQ==", + "version": "2.10.0", + "integrity": "sha512-ZAlCe55LXlbg60l15okSBs70NQAPLw3yRO3SSJMTB1uU7uj2QQbLCQPy1Ds+3B4wlaa5W3ewv8FNOZPQOoSSPA==", "dependencies": { - "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/geojson-rewind": "^0.5.1", + "@mapbox/geojson-types": "^1.0.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", "@mapbox/mapbox-gl-supported": "^2.0.1", "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^2.0.6", - "@mapbox/unitbezier": "^0.0.1", + "@mapbox/tiny-sdf": "^2.0.5", + "@mapbox/unitbezier": "^0.0.0", "@mapbox/vector-tile": "^1.3.1", "@mapbox/whoots-js": "^3.1.0", "csscolorparser": "~1.0.3", @@ -33162,65 +37358,24 @@ "grid-index": "^1.1.0", "murmurhash-js": "^1.0.0", "pbf": "^3.2.1", - "potpack": "^2.0.0", + "potpack": "^1.0.2", "quickselect": "^2.0.0", "rw": "^1.3.3", - "supercluster": "^7.1.5", + "supercluster": "^7.1.4", "tinyqueue": "^2.0.3", "vt-pbf": "^3.1.3" } }, - "node_modules/mapbox-gl/node_modules/@mapbox/geojson-rewind": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", - "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", - "dependencies": { - "get-stream": "^6.0.1", - "minimist": "^1.2.6" - }, - "bin": { - "geojson-rewind": "geojson-rewind" - } - }, - "node_modules/mapbox-gl/node_modules/@mapbox/mapbox-gl-supported": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-2.0.1.tgz", - "integrity": "sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==" - }, "node_modules/mapbox-gl/node_modules/@mapbox/tiny-sdf": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", - "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==" - }, - "node_modules/mapbox-gl/node_modules/@mapbox/unitbezier": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", - "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==" - }, - "node_modules/mapbox-gl/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==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "version": "2.0.5", + "integrity": "sha512-OhXt2lS//WpLdkqrzo/KwB7SRD8AiNTFFzuo9n14IBupzIMa67yGItcK7I2W9D8Ghpa4T04Sw9FWsKCJG50Bxw==" }, "node_modules/mapbox-gl/node_modules/gl-matrix": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" }, - "node_modules/mapbox-gl/node_modules/potpack": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", - "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==" - }, "node_modules/mapbox-gl/node_modules/supercluster": { "version": "7.1.5", - "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz", "integrity": "sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==", "dependencies": { "kdbush": "^3.0.0" @@ -33511,10 +37666,10 @@ } }, "node_modules/memfs": { - "version": "3.2.4", - "integrity": "sha512-2mDCPhuduRPOxlfgsXF9V+uqC6Jgz8zt/bNe4d4W7d5f6pCzHrWkxLNr17jKGXd4+j2kQNsAG2HARPnt74sqVQ==", + "version": "3.4.7", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", "dependencies": { - "fs-monkey": "1.0.3" + "fs-monkey": "^1.0.3" }, "engines": { "node": ">= 4.0.0" @@ -34170,17 +38325,17 @@ } }, "node_modules/mime-db": { - "version": "1.49.0", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", + "version": "1.52.0", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.32", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", + "version": "2.1.35", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.49.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -34189,7 +38344,6 @@ "node_modules/mimic-fn": { "version": "2.1.0", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "devOptional": true, "engines": { "node": ">=6" } @@ -34208,20 +38362,6 @@ "node": ">=4" } }, - "node_modules/mini-create-react-context": { - "version": "0.3.2", - "integrity": "sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dependencies": { - "@babel/runtime": "^7.4.0", - "gud": "^1.0.0", - "tiny-warning": "^1.0.2" - }, - "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0" - } - }, "node_modules/mini-css-extract-plugin": { "version": "2.4.5", "integrity": "sha512-oEIhRucyn1JbT/1tU2BhnwO6ft1jjH1iCX9Gc59WFMg0n5773rQU0oyQ0zzeYFFuBfONaRbQJyGoPtuNseMxjA==", @@ -34310,8 +38450,8 @@ "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" }, "node_modules/minimatch": { - "version": "3.0.4", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -34320,12 +38460,8 @@ } }, "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "version": "1.2.6", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/minimist-options": { "version": "4.1.0", @@ -34368,22 +38504,6 @@ "node": ">= 8" } }, - "node_modules/minipass-fetch": { - "version": "1.4.1", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "dev": true, - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, "node_modules/minipass-flush": { "version": "1.0.5", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", @@ -34557,15 +38677,15 @@ } }, "node_modules/moment": { - "version": "2.29.2", - "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==", + "version": "2.29.4", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", "engines": { "node": "*" } }, "node_modules/moment-timezone": { - "version": "0.5.33", - "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", + "version": "0.5.37", + "integrity": "sha512-uEDzDNFhfaywRl+vwXxffjjq1q0Vzr+fcQpQ1bU0kbzorfS7zVtZnCnGc8mhWmF39d4g4YriF6kwA75mJKE/Zg==", "dependencies": { "moment": ">= 2.9.0" }, @@ -34639,22 +38759,17 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/multicast-dns": { - "version": "6.2.3", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "version": "7.2.5", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, "dependencies": { - "dns-packet": "^1.3.1", + "dns-packet": "^5.2.2", "thunky": "^1.0.2" }, "bin": { "multicast-dns": "cli.js" } }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", - "dev": true - }, "node_modules/multimatch": { "version": "5.0.0", "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", @@ -34698,7 +38813,7 @@ "node_modules/mute-stream": { "version": "0.0.8", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "devOptional": true + "dev": true }, "node_modules/nano-time": { "version": "1.0.0", @@ -34707,10 +38822,6 @@ "big-integer": "^1.6.16" } }, - "node_modules/nanocolors": { - "version": "0.1.12", - "integrity": "sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ==" - }, "node_modules/nanoid": { "version": "2.0.0", "integrity": "sha512-SG2qscLE3iM4C0CNzGrsAojJHSVHMS1J8NnvJ31P1lH8P0hGHOiafmniNJz6w6q7vuoDlV7RdySlJgtqkFEVtQ==" @@ -34793,8 +38904,8 @@ } }, "node_modules/negotiator": { - "version": "0.6.1", - "integrity": "sha512-qTxkr1RoLw5Pz+1+PTJ/66hWuyi2LEOeOuIDJDlx6JF8x75bmD5C7qXTg2UlX5W9rLfkqKP+r8q6Vy6NWdWrbw==", + "version": "0.6.3", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { "node": ">= 0.6" } @@ -34807,9 +38918,18 @@ "version": "2.1.1", "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" }, + "node_modules/netmask": { + "version": "2.0.2", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/nice-try": { "version": "1.0.5", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true }, "node_modules/nise": { "version": "4.1.0", @@ -34864,6 +38984,11 @@ "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==", "dev": true }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true + }, "node_modules/node-ask": { "version": "1.0.1", "integrity": "sha512-+0eqgEdgPiixrNysGDTPo3T2qyEHGVgs4ONlc5tTfcluvC/Rgq1x2ELdANUMwhR2CYLwaQnMS32O/h7adasnFQ==", @@ -34888,14 +39013,6 @@ "semver": "^5.7.0" } }, - "node_modules/node-environment-flags/node_modules/semver": { - "version": "5.7.1", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/node-fetch": { "version": "2.6.7", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", @@ -34931,129 +39048,104 @@ } }, "node_modules/node-forge": { - "version": "0.10.0", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "version": "1.3.1", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, "engines": { - "node": ">= 6.0.0" + "node": ">= 6.13.0" } }, "node_modules/node-gyp": { - "version": "5.1.1", - "integrity": "sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw==", + "version": "9.3.1", + "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", "dev": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "npmlog": "^4.1.2", - "request": "^2.88.0", - "rimraf": "^2.6.3", - "semver": "^5.7.1", - "tar": "^4.4.12", - "which": "^1.3.1" + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" }, "bin": { "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": ">= 6.0.0" + "node": "^12.13 || ^14.13 || >=16" } }, - "node_modules/node-gyp/node_modules/fs-minipass": { - "version": "1.2.7", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "dev": true, - "dependencies": { - "minipass": "^2.6.0" - } - }, - "node_modules/node-gyp/node_modules/minipass": { - "version": "2.9.0", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "node_modules/node-gyp-build": { + "version": "4.5.0", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", "dev": true, - "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" } }, - "node_modules/node-gyp/node_modules/minizlib": { - "version": "1.3.3", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "node_modules/node-gyp/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "minipass": "^2.9.0" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, "node_modules/node-gyp/node_modules/nopt": { - "version": "4.0.3", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "version": "6.0.0", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", "dev": true, "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" + "abbrev": "^1.0.0" }, "bin": { "nopt": "bin/nopt.js" - } - }, - "node_modules/node-gyp/node_modules/rimraf": { - "version": "2.7.1", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/node-gyp/node_modules/safe-buffer": { - "version": "5.2.1", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/node-gyp/node_modules/semver": { - "version": "5.7.1", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/node-gyp/node_modules/tar": { - "version": "4.4.19", - "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "node_modules/node-gyp/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { - "chownr": "^1.1.4", - "fs-minipass": "^1.2.7", - "minipass": "^2.9.0", - "minizlib": "^1.3.3", - "mkdirp": "^0.5.5", - "safe-buffer": "^5.2.1", - "yallist": "^3.1.1" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">=4.5" + "node": ">= 8" } }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/node-int64": { "version": "0.4.0", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", @@ -35109,13 +39201,6 @@ "node": ">= 0.8.0" } }, - "node_modules/node-modules-regexp": { - "version": "1.0.0", - "integrity": "sha512-JMaRS9L4wSRIR+6PTVEikTrq/lMGEZR43a48ETeilY0Q0iMwVnccMFrUM1k+tNzmYuIU0Vh710bCUqHX+/+ctQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/node-notifier": { "version": "8.0.0", "integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==", @@ -35163,245 +39248,446 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/node-notifier/node_modules/which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/node-notifier/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "optional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/node-releases": { + "version": "2.0.6", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "node_modules/nopt": { + "version": "5.0.0", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-path": { + "version": "2.1.1", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "devOptional": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.2", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-packlist": { + "version": "5.1.3", + "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm-packlist/node_modules/glob": { + "version": "8.0.3", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm-packlist/node_modules/minimatch": { + "version": "5.1.2", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-packlist/node_modules/npm-bundled": { + "version": "2.0.1", + "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/nth-check": { + "version": "1.0.2", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/num2fraction": { + "version": "1.2.2", + "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==" + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nvd3-fork": { + "version": "2.0.5", + "integrity": "sha512-Sq3q2rvR/9FJ35LVmqdQJAnfmD15BaIHSBg5wZZL/WLcq/nthff8ukabwFdbW0zeE1c/yPq+DKl6MxnUTR45DA==", + "peerDependencies": { + "d3": "^3.4.4" + } + }, + "node_modules/nwsapi": { + "version": "2.2.0", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "node_modules/nx": { + "version": "15.3.3", + "integrity": "sha512-yR102AlVW5Sb7X1e9cyR+0h44RD6c3eLJbAZ0yVFKPCKw+zQTdGvAqITtB6ZeFnPkg6Qq6f1oWu6G0n6f2cTpw==", "dev": true, - "optional": true, + "hasInstallScript": true, "dependencies": { - "isexe": "^2.0.0" + "@nrwl/cli": "15.3.3", + "@nrwl/tao": "15.3.3", + "@parcel/watcher": "2.0.4", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "^3.0.0-rc.18", + "@zkochan/js-yaml": "0.0.6", + "axios": "^1.0.0", + "chalk": "4.1.0", + "chokidar": "^3.5.1", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^7.0.2", + "dotenv": "~10.0.0", + "enquirer": "~2.3.6", + "fast-glob": "3.2.7", + "figures": "3.2.0", + "flat": "^5.0.2", + "fs-extra": "^10.1.0", + "glob": "7.1.4", + "ignore": "^5.0.4", + "js-yaml": "4.1.0", + "jsonc-parser": "3.2.0", + "minimatch": "3.0.5", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "semver": "7.3.4", + "string-width": "^4.2.3", + "strong-log-transformer": "^2.1.0", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tsconfig-paths": "^3.9.0", + "tslib": "^2.3.0", + "v8-compile-cache": "2.3.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" }, "bin": { - "node-which": "bin/node-which" + "nx": "bin/nx.js" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "@swc-node/register": "^1.4.2", + "@swc/core": "^1.2.173" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } } }, - "node_modules/node-releases": { - "version": "1.1.75", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==" - }, - "node_modules/nopt": { - "version": "5.0.0", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, + "node_modules/nx/node_modules/ansi-regex": { + "version": "5.0.1", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/nx/node_modules/argparse": { + "version": "2.0.1", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/nx/node_modules/axios": { + "version": "1.2.1", + "integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==", + "dev": true, "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, - "node_modules/normalize-path": { - "version": "2.1.1", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "devOptional": true, + "node_modules/nx/node_modules/braces": { + "version": "3.0.2", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "dependencies": { - "remove-trailing-separator": "^1.0.1" + "fill-range": "^7.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/normalize-url": { - "version": "6.1.0", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "node_modules/nx/node_modules/chalk": { + "version": "4.1.0", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-api": { - "version": "1.0.1", - "integrity": "sha512-4sITrrzEbPcr0aNV28QyOmgn6C9yKiF8k92jn4buYAK8wmA5xo1qL3II5/gT1r7wxbXBflSduZ2K3FbtOrtGkA==", - "optional": true, - "dependencies": { - "clone-deep": "^4.0.1", - "download-stats": "^0.3.4", - "JSONStream": "^1.3.5", - "moment": "^2.24.0", - "node-fetch": "^2.6.0", - "paged-request": "^2.0.1" - }, - "engines": { - "node": ">=10.0" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/npm-bundled": { - "version": "1.1.2", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "node_modules/nx/node_modules/cliui": { + "version": "7.0.4", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "dependencies": { - "npm-normalize-package-bin": "^1.0.1" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/npm-install-checks": { - "version": "4.0.0", - "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", + "node_modules/nx/node_modules/dotenv": { + "version": "10.0.0", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", "dev": true, - "dependencies": { - "semver": "^7.1.1" - }, "engines": { "node": ">=10" } }, - "node_modules/npm-install-checks/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/nx/node_modules/fast-glob": { + "version": "3.2.7", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/npm-install-checks/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/nx/node_modules/fill-range": { + "version": "7.0.1", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/npm-install-checks/node_modules/yallist": { + "node_modules/nx/node_modules/form-data": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/npm-lifecycle": { - "version": "3.1.5", - "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "dependencies": { - "byline": "^5.0.0", - "graceful-fs": "^4.1.15", - "node-gyp": "^5.0.2", - "resolve-from": "^4.0.0", - "slide": "^1.1.6", - "uid-number": "0.0.6", - "umask": "^1.1.0", - "which": "^1.3.1" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true - }, - "node_modules/npm-package-arg": { - "version": "8.1.5", - "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", + "node_modules/nx/node_modules/glob": { + "version": "7.1.4", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "dependencies": { - "hosted-git-info": "^4.0.1", - "semver": "^7.3.4", - "validate-npm-package-name": "^3.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=10" + "node": "*" } }, - "node_modules/npm-package-arg/node_modules/hosted-git-info": { - "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "node_modules/nx/node_modules/ignore": { + "version": "5.2.4", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "engines": { - "node": ">=10" + "node": ">= 4" } }, - "node_modules/npm-package-arg/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/nx/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/npm-package-arg/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/nx/node_modules/is-number": { + "version": "7.0.0", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, "engines": { - "node": ">=10" + "node": ">=0.12.0" } }, - "node_modules/npm-package-arg/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/npm-packlist": { - "version": "2.2.2", - "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==", + "node_modules/nx/node_modules/is-wsl": { + "version": "2.2.0", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "dependencies": { - "glob": "^7.1.6", - "ignore-walk": "^3.0.3", - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "npm-packlist": "bin/index.js" + "is-docker": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/npm-pick-manifest": { - "version": "6.1.1", - "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", + "node_modules/nx/node_modules/js-yaml": { + "version": "4.1.0", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "npm-install-checks": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^8.1.2", - "semver": "^7.3.4" + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/npm-pick-manifest/node_modules/lru-cache": { + "node_modules/nx/node_modules/lru-cache": { "version": "6.0.0", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, @@ -35412,236 +39698,190 @@ "node": ">=10" } }, - "node_modules/npm-pick-manifest/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/nx/node_modules/micromatch": { + "version": "4.0.5", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=10" + "node": ">=8.6" } }, - "node_modules/npm-pick-manifest/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/npm-registry-fetch": { - "version": "11.0.0", - "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "node_modules/nx/node_modules/minimatch": { + "version": "3.0.5", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", "dev": true, "dependencies": { - "make-fetch-happen": "^9.0.1", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=10" + "node": "*" } }, - "node_modules/npm-registry-fetch/node_modules/cacache": { - "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "node_modules/nx/node_modules/npm-run-path": { + "version": "4.0.1", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" + "path-key": "^3.0.0" }, "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/npm-registry-fetch/node_modules/chownr": { - "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "node_modules/nx/node_modules/open": { + "version": "8.4.0", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm-registry-fetch/node_modules/debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "node_modules/nx/node_modules/path-key": { + "version": "3.1.1", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "dependencies": { - "ms": "2.1.2" - }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=8" } }, - "node_modules/npm-registry-fetch/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/nx/node_modules/proxy-from-env": { + "version": "1.1.0", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/nx/node_modules/semver": { + "version": "7.3.4", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { "node": ">=10" } }, - "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { - "version": "9.1.0", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "node_modules/nx/node_modules/string-width": { + "version": "4.2.3", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/npm-registry-fetch/node_modules/mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/nx/node_modules/strip-ansi": { + "version": "6.0.1", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" + "dependencies": { + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/npm-registry-fetch/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/npm-registry-fetch/node_modules/negotiator": { - "version": "0.6.2", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "node_modules/nx/node_modules/to-regex-range": { + "version": "5.0.1", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=8.0" } }, - "node_modules/npm-registry-fetch/node_modules/socks-proxy-agent": { - "version": "6.1.1", - "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "node_modules/nx/node_modules/tslib": { + "version": "2.4.1", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true + }, + "node_modules/nx/node_modules/wrap-ansi": { + "version": "7.0.0", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">= 10" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/npm-registry-fetch/node_modules/ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "node_modules/nx/node_modules/y18n": { + "version": "5.0.8", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, "engines": { - "node": ">= 8" + "node": ">=10" } }, - "node_modules/npm-registry-fetch/node_modules/yallist": { + "node_modules/nx/node_modules/yallist": { "version": "4.0.0", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "node_modules/nx/node_modules/yargs": { + "version": "17.6.2", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "dev": true, "dependencies": { - "path-key": "^2.0.0" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/npmlog": { - "version": "4.1.2", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "node_modules/nx/node_modules/yargs-parser": { + "version": "21.1.1", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "engines": { + "node": ">=12" } }, - "node_modules/nth-check": { - "version": "1.0.2", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "node_modules/nx/node_modules/yargs/node_modules/cliui": { + "version": "8.0.1", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { - "boolbase": "~1.0.0" - } - }, - "node_modules/num2fraction": { - "version": "1.2.2", - "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==" - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nvd3-fork": { - "version": "2.0.5", - "integrity": "sha512-Sq3q2rvR/9FJ35LVmqdQJAnfmD15BaIHSBg5wZZL/WLcq/nthff8ukabwFdbW0zeE1c/yPq+DKl6MxnUTR45DA==", - "peerDependencies": { - "d3": "^3.4.4" + "node": ">=12" } }, - "node_modules/nwsapi": { - "version": "2.2.0", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, "node_modules/oauth-sign": { "version": "0.9.0", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", @@ -35694,11 +39934,18 @@ "integrity": "sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw==" }, "node_modules/object-is": { - "version": "1.0.1", - "integrity": "sha512-WY2d4Y9s39AGFRtDlJDyNHFHOTQ5MbFzYWt9dHNYn4P9zCR+wpCo1IqWd+xJVEX5aNhCFXzTptJ8H2kRIHWF3Q==", + "version": "1.1.5", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object-keys": { @@ -35719,12 +39966,12 @@ } }, "node_modules/object.assign": { - "version": "4.1.2", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.4", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -35735,29 +39982,30 @@ } }, "node_modules/object.entries": { - "version": "1.1.0", - "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "version": "1.1.6", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.0", - "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", + "version": "2.0.6", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", "dependencies": { - "define-properties": "^1.1.2", - "es-abstract": "^1.11.0", - "function-bind": "^1.1.1", - "has": "^1.0.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object.getownpropertydescriptors": { @@ -35786,12 +40034,12 @@ } }, "node_modules/object.values": { - "version": "1.1.4", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "version": "1.1.6", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" @@ -35844,7 +40092,6 @@ "node_modules/onetime": { "version": "5.1.2", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "devOptional": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -35966,31 +40213,14 @@ "version": "0.3.0", "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==" }, - "node_modules/os-homedir": { - "version": "1.0.2", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/os-tmpdir": { "version": "1.0.2", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/osenv": { - "version": "0.1.5", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "node_modules/overlayscrollbars": { "version": "1.13.1", "integrity": "sha512-gIQfzgGgu1wy80EB4/6DaJGHMEGmizq27xHIESrzXq0Y/J0Ay1P3DWk6tuVmEPIZH15zaBlxeEJOqdJKmowHCQ==" @@ -36188,6 +40418,72 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pac-proxy-agent": { + "version": "5.0.0", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/pac-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/pac-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/pac-proxy-agent/node_modules/socks-proxy-agent": { + "version": "5.0.1", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pac-resolver": { + "version": "5.0.1", + "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==", + "dev": true, + "dependencies": { + "degenerator": "^3.0.2", + "ip": "^1.1.5", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/pad-component": { "version": "0.0.1", "integrity": "sha512-8EKVBxCRSvLnsX1p2LlSFSH3c2/wuhY9/BXXWu8boL78FbVKqn2L5SpURt1x5iw6Gq8PTqJ7MdPoe5nCtX3I+g==" @@ -36202,17 +40498,6 @@ "node": ">=0.10.0" } }, - "node_modules/paged-request": { - "version": "2.0.2", - "integrity": "sha512-NWrGqneZImDdcMU/7vMcAOo1bIi5h/pmpJqe7/jdsy85BA/s5MSaU/KlpxwW/IVPmIwBcq2uKPrBWWhEWhtxag==", - "optional": true, - "dependencies": { - "axios": "^0.21.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/pako": { "version": "1.0.11", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" @@ -36287,39 +40572,19 @@ } }, "node_modules/parse-path": { - "version": "4.0.3", - "integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==", + "version": "7.0.0", + "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==", "dev": true, "dependencies": { - "is-ssh": "^1.3.0", - "protocols": "^1.4.0", - "qs": "^6.9.4", - "query-string": "^6.13.8" - } - }, - "node_modules/parse-path/node_modules/qs": { - "version": "6.10.2", - "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "protocols": "^2.0.0" } }, "node_modules/parse-url": { - "version": "6.0.0", - "integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==", + "version": "8.1.0", + "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", "dev": true, "dependencies": { - "is-ssh": "^1.3.0", - "normalize-url": "^6.1.0", - "parse-path": "^4.0.0", - "protocols": "^1.4.0" + "parse-path": "^7.0.0" } }, "node_modules/parse5": { @@ -36331,8 +40596,8 @@ } }, "node_modules/parseurl": { - "version": "1.3.2", - "integrity": "sha512-DjIMrEiCuzD/Xsr69WhcPCTeb6iZP5JgL/DZ3cYz0zMnyiXiscoqC6LLV2dYwQHfy9O+twCDVVPiFWb7xZhaOw==", + "version": "1.3.3", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "engines": { "node": ">= 0.8" } @@ -36382,6 +40647,7 @@ "node_modules/path-key": { "version": "2.0.1", "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, "engines": { "node": ">=4" } @@ -36437,15 +40703,16 @@ }, "node_modules/performance-now": { "version": "2.1.0", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true }, "node_modules/picocolors": { "version": "0.2.1", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" }, "node_modules/picomatch": { - "version": "2.3.0", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "engines": { "node": ">=8.6" }, @@ -36478,11 +40745,8 @@ } }, "node_modules/pirates": { - "version": "4.0.1", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dependencies": { - "node-modules-regexp": "^1.0.0" - }, + "version": "4.0.5", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "engines": { "node": ">= 6" } @@ -36597,41 +40861,6 @@ "node": ">=10" } }, - "node_modules/portfinder": { - "version": "1.0.28", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "dependencies": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/portfinder/node_modules/async": { - "version": "2.6.3", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/portfinder/node_modules/debug": { - "version": "3.2.6", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/portfinder/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/posix-character-classes": { "version": "0.1.1", "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", @@ -36708,8 +40937,8 @@ } }, "node_modules/postcss-loader/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -36718,8 +40947,8 @@ } }, "node_modules/postcss-loader/node_modules/loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -36823,8 +41052,8 @@ } }, "node_modules/postcss-value-parser": { - "version": "4.1.0", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" + "version": "4.2.0", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/postcss/node_modules/nanoid": { "version": "3.1.25", @@ -36838,8 +41067,8 @@ } }, "node_modules/potpack": { - "version": "1.0.1", - "integrity": "sha512-15vItUAbViaYrmaB/Pbw7z6qX2xENbFSTA7Ii4tgbPtasxm5v6ryKhKtL91tpWovDJzTiZqdwzhcFBCwiMVdVw==" + "version": "1.0.2", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==" }, "node_modules/prelude-ls": { "version": "1.1.2", @@ -36848,13 +41077,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prepend-http": { - "version": "1.0.4", - "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/prettier": { "version": "2.4.1", "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", @@ -36888,16 +41110,6 @@ "prettier": ">= 1.16.0" } }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/pretty-error": { "version": "3.0.4", "integrity": "sha512-ytLFLfv1So4AO1UkoBF6GXQgJRaKbiSiGFICaOPNwQ3CMvBvXpLRubeQWyPGnsbV/t9ml9qto6IeCsho0aEvwQ==", @@ -37003,6 +41215,22 @@ "asap": "~2.0.3" } }, + "node_modules/promise-all-reject-late": { + "version": "1.0.1", + "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/promise-call-limit": { + "version": "1.0.1", + "integrity": "sha512-3+hgaa19jzCGLuSCbieeRsu5C2joKfYn8pY6JAuXFRVfF4IO+L7UPpFWNTeWT9pM7uhskvbPPd/oEOktCn317Q==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/promise-inflight": { "version": "1.0.1", "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" @@ -37080,12 +41308,12 @@ } }, "node_modules/prop-types": { - "version": "15.7.2", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, "node_modules/prop-types-exact": { @@ -37098,10 +41326,6 @@ "reflect.ownkeys": "^0.2.0" } }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/property-information": { "version": "5.6.0", "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", @@ -37122,8 +41346,8 @@ "integrity": "sha512-G/2kcamPF2S49W5yaMGdIpkG6+5wZF0fzBteLKgEHjbNzqjZQ85aAs1iJGto31EJaSTkNvHs5IXuHSaTLWBAiA==" }, "node_modules/protocols": { - "version": "1.4.8", - "integrity": "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg==", + "version": "2.0.1", + "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==", "dev": true }, "node_modules/proxy-addr": { @@ -37151,6 +41375,63 @@ "node": ">= 0.10" } }, + "node_modules/proxy-agent": { + "version": "5.0.0", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/proxy-agent/node_modules/debug": { + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/proxy-agent/node_modules/ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/proxy-agent/node_modules/socks-proxy-agent": { + "version": "5.0.1", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.0.0", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", + "dev": true + }, "node_modules/prr": { "version": "1.0.1", "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==" @@ -37215,7 +41496,7 @@ "node_modules/puppeteer": { "version": "10.2.0", "integrity": "sha512-OR2CCHRashF+f30+LBOtAjK6sNtz2HEyTr5FqAvhf8lR/qB3uBRoIZOwQKgwoyZnMBsxX7ZdazlyBgGjpnkiMw==", - "deprecated": "< 18.1.0 is no longer supported", + "deprecated": "< 19.4.0 is no longer supported", "dev": true, "hasInstallScript": true, "dependencies": { @@ -37373,10 +41654,6 @@ } } }, - "node_modules/pure-color": { - "version": "1.3.0", - "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" - }, "node_modules/q": { "version": "1.5.1", "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", @@ -37387,8 +41664,8 @@ } }, "node_modules/qs": { - "version": "6.5.2", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.5.3", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, "engines": { "node": ">=0.6" @@ -37457,6 +41734,7 @@ "node_modules/raf": { "version": "3.4.1", "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dev": true, "dependencies": { "performance-now": "^2.1.0" } @@ -37501,11 +41779,11 @@ } }, "node_modules/raw-body": { - "version": "2.4.0", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.3", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -37514,36 +41792,33 @@ } }, "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.0", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.2", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "engines": { "node": ">= 0.8" } }, "node_modules/raw-body/node_modules/http-errors": { - "version": "1.7.2", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dependencies": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" } }, - "node_modules/raw-body/node_modules/setprototypeof": { - "version": "1.1.1", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "node_modules/raw-body/node_modules/inherits": { + "version": "2.0.4", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/raw-body/node_modules/statuses": { - "version": "1.5.0", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } + "node_modules/raw-body/node_modules/setprototypeof": { + "version": "1.2.0", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/raw-loader": { "version": "4.0.2", @@ -37564,8 +41839,8 @@ } }, "node_modules/raw-loader/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -37574,8 +41849,8 @@ } }, "node_modules/raw-loader/node_modules/loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -37600,22 +41875,6 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-align/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "dependencies": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-align/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/rc-cascader": { "version": "1.4.0", "integrity": "sha512-6kgQljDQEKjVAVRkZtvvoi+2qv4u42M6oLuvt4ZDBa16r3X9ZN8TAq3atVyC840ivbGKlHT50OcdVx/iwiHc1w==", @@ -37653,48 +41912,6 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-collapse/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "dependencies": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-collapse/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/rc-dialog": { - "version": "8.4.5", - "integrity": "sha512-0a1Uuy1BRBTdIkfR1VE91kis6dBui7tAIPaQQLj28vBdGg9IqVkiLguCdaDW+4E4vZediePz49PKFbLkx2PL5Q==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.6", - "rc-motion": "^2.3.0", - "rc-util": "^5.0.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-drawer": { - "version": "4.1.0", - "integrity": "sha512-kjeQFngPjdzAFahNIV0EvEBoIKMOnvUsAxpkSPELoD/1DuR4nLafom5ryma+TIxGwkFJ92W6yjsMi1U9aiOTeQ==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.6", - "rc-util": "^5.0.1" - }, - "peerDependencies": { - "react": "*" - } - }, "node_modules/rc-dropdown": { "version": "3.2.0", "integrity": "sha512-j1HSw+/QqlhxyTEF6BArVZnTmezw2LnSmRk6I9W7BCqNCKaRwleRmMMs1PHbuaG8dKHVqP6e21RQ7vPBLVnnNw==", @@ -37723,21 +41940,6 @@ "react": ">= 16.9.0" } }, - "node_modules/rc-image": { - "version": "4.2.0", - "integrity": "sha512-yGqq6wPrIn86hMfC1Hl7M3NNS6zqnl9dvFWJg/StuI86jZBU0rm9rePTfKs+4uiwU3HXxpfsXlaG2p8GWRDLiw==", - "dependencies": { - "@ant-design/icons": "^4.2.2", - "@babel/runtime": "^7.11.2", - "classnames": "^2.2.6", - "rc-dialog": "~8.4.0", - "rc-util": "^5.0.6" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, "node_modules/rc-input-number": { "version": "6.1.2", "integrity": "sha512-UvP0tpOUeGetx6caS8RzBs3Du+NwPUn9ijQ3LeR1jOmzjXNuXvv58U6hvIXSHx/4ulPleQ5BAQP/aLTsFB4yGw==", @@ -37785,22 +41987,6 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-menu/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "dependencies": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-menu/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/rc-motion": { "version": "2.4.1", "integrity": "sha512-TWLvymfMu8SngPx5MDH8dQ0D2RYbluNTfam4hY/dNNx9RQ3WtGuZ/GXHi2ymLMzH+UNd6EEFYkOuR5JTTtm8Xg==", @@ -37814,22 +42000,6 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-motion/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "dependencies": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-motion/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/rc-notification": { "version": "4.5.4", "integrity": "sha512-VsN0ouF4uglE5g3C9oDsXLNYX0Sz++ZNUFYCswkxhpImYJ9u6nJOpyA71uOYDVCu6bAF54Y5Hi/b+EcnMzkepg==", @@ -37859,43 +42029,6 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-picker": { - "version": "2.4.3", - "integrity": "sha512-tOIHslTQKpoGNmbpp6YOBwS39dQSvtAuhOm3bWCkkc4jCqUqeR/velCwqefZX1BX4+t1gUMc1dIia9XvOKrEkg==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.1", - "date-fns": "^2.15.0", - "dayjs": "^1.8.30", - "moment": "^2.24.0", - "rc-trigger": "^5.0.4", - "rc-util": "^5.4.0", - "shallowequal": "^1.1.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-picker/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "dependencies": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-picker/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/rc-progress": { "version": "3.1.1", "integrity": "sha512-1ns3pW7ll9bHfdXtlVLF+vngdvlxiCDtiqwXnZFEdurst11JTiPxVdeqnCNbhWx5hP4kCKkAPqG1N0FVfTSUGA==", @@ -37938,44 +42071,6 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-select": { - "version": "11.5.3", - "integrity": "sha512-ASSO4J/ayfbQQ+KOEounIMGhySDHpQtrIuH1WEABOBy8HgKec8kOLmyLH+YIXSUDnTf/gtxmflgFtl7sQ9pkSw==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-motion": "^2.0.1", - "rc-trigger": "^5.0.4", - "rc-util": "^5.0.1", - "rc-virtual-list": "^3.2.0", - "warning": "^4.0.3" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/rc-slider": { - "version": "9.6.5", - "integrity": "sha512-XRUJDK668hy8MwGnHzZlXCQXXIOUnEs4m2vwk1jgDILVBxI0GwGOlC6T499pYY+NEWg8YgdCOAucFs/+X5WHpg==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.5", - "rc-tooltip": "^5.0.1", - "rc-util": "^5.0.0", - "shallowequal": "^1.1.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, "node_modules/rc-steps": { "version": "4.1.3", "integrity": "sha512-GXrMfWQOhN3sVze3JnzNboHpQdNHcdFubOETUHyDpa/U3HEKBZC3xJ8XK4paBgF4OJ3bdUVLC+uBPc6dCxvDYA==", @@ -38005,40 +42100,6 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-table": { - "version": "7.11.3", - "integrity": "sha512-YyZry1CdqUrcH7MmWtLQZVvVZWbmTEbI5m650AZ+zYw4D5VF701samkMYl5z/H9yQFr+ugvDtXcya+e3vwRkMQ==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.5", - "rc-resize-observer": "^0.2.0", - "rc-util": "^5.4.0", - "shallowequal": "^1.1.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-table/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "dependencies": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-table/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/rc-tabs": { "version": "11.7.2", "integrity": "sha512-2M/XE4TdecnjsDylJSs49OmjJuDuix3VmSiNaPd50PMqFc+dc4fEof3J8/ad12enicVOcsH4BEQEms//Kn4DBw==", @@ -38058,22 +42119,6 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-tabs/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "dependencies": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-tabs/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/rc-textarea": { "version": "0.3.2", "integrity": "sha512-569hiqCtkZFCcxBpKLM+IdnjZDQCFoy7RlQ4bkked0wp9uh+ofgk5zuQNJPiPyMYzpKYRlYeZgJ1bnK/8Po0Sg==", @@ -38088,47 +42133,6 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-tooltip": { - "version": "5.0.1", - "integrity": "sha512-3AnxhUS0j74xAV3khrKw8o6rg+Ima3nw09DJBezMPnX3ImQUAnayWsPSlN1mEnihjA43rcFkGM1emiKE+CXyMQ==", - "dependencies": { - "@babel/runtime": "^7.11.2", - "rc-trigger": "^5.0.0" - } - }, - "node_modules/rc-tree": { - "version": "4.0.0", - "integrity": "sha512-C2xlkA+/IypkHBPzbpAJGVWJh2HjeRbYCusA/m5k09WT6hQT0nC7LtLVmnb7QZecdBQPhoOgQh8gPwBR+xEMjQ==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-motion": "^2.0.1", - "rc-util": "^5.0.0", - "rc-virtual-list": "^3.0.1" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/rc-tree-select": { - "version": "4.2.0", - "integrity": "sha512-VrrvBiOov6WR44RTGMqSw1Dmodg6Y++EH6a6R0ew43qsV4Ob0FGYRgoX811kImtt2Z+oAPJ6zZXN4WKtsQd3Gw==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-select": "^11.1.1", - "rc-tree": "^4.0.0", - "rc-util": "^5.0.5" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, "node_modules/rc-trigger": { "version": "5.2.0", "integrity": "sha512-fpC1ZkM/IgIIDfF6XHx3Hb2zXy9wvdI5eMh+6DdLygk6Z3HGmkri6ZCXg9a0wfF9AFuzlYTeBLS1uRASZRsnMQ==", @@ -38143,22 +42147,6 @@ "node": ">=8.x" } }, - "node_modules/rc-trigger/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "dependencies": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-trigger/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/rc-upload": { "version": "3.3.4", "integrity": "sha512-v2sirR4JL31UTHD/f0LGUdd+tpFaOVUTPeIEjAXRP9kRN8TFhqOgcXl5ixtyqj90FmtRUmKmafCv0EmhBQUHqQ==", @@ -38172,54 +42160,11 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-upload/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "dependencies": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-upload/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/rc-util": { - "version": "5.0.6", - "integrity": "sha512-uLGxF9WjbpJSjd6iDnIjl8ZeMUglpcuh1DwO26aaXh++yAmlB6eIAJMUwwJCuqJvo4quCvsDPg1VkqHILc4U0A==", - "dependencies": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "node_modules/rc-util/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/rc-virtual-list": { - "version": "3.2.3", - "integrity": "sha512-uEeYDQWwQhxR97SekPeGRbzPtHSbSpw/mYb6QpZZ9bA43kf7s1socV3fD3ySYhQVzo0I+/IUD9jFGit6FbM0WA==", - "dependencies": { - "classnames": "^2.2.6", - "rc-resize-observer": "^0.2.3", - "rc-util": "^5.0.7" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/rc-virtual-list/node_modules/rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", + "version": "5.24.4", + "integrity": "sha512-2a4RQnycV9eV7lVZPEJ7QwJRPlZNc06J7CwcwZo4vIHr3PfUqtYgl1EkUV9ETAc6VRRi8XZOMFhYG63whlIC9Q==", "dependencies": { + "@babel/runtime": "^7.18.3", "react-is": "^16.12.0", "shallowequal": "^1.1.0" }, @@ -38228,10 +42173,6 @@ "react-dom": ">=16.9.0" } }, - "node_modules/rc-virtual-list/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/re-resizable": { "version": "6.6.1", "integrity": "sha512-ttWVasZ9X7c0ir0+4YK47tkmm9EAFssW07YLkeLzG5HCOuFgFAlSVzMlzAH0h3i6hDShQCHHJecVx5rk+snoFA==", @@ -38252,33 +42193,41 @@ } }, "node_modules/react-ace": { - "version": "9.5.0", - "integrity": "sha512-4l5FgwGh6K7A0yWVMQlPIXDItM4Q9zzXRqOae8KkCl6MkOob7sC1CzHxZdOGvV+QioKWbX2p5HcdOVUv6cAdSg==", + "version": "10.1.0", + "integrity": "sha512-VkvUjZNhdYTuKOKQpMIZi7uzZZVgzCjM7cLYu6F64V0mejY8a2XTyPUIMszC6A4trbeMIHbK5fYFcT/wkP/8VA==", "dependencies": { - "ace-builds": "^1.4.13", + "ace-builds": "^1.4.14", "diff-match-patch": "^1.0.5", "lodash.get": "^4.4.2", "lodash.isequal": "^4.5.0", "prop-types": "^15.7.2" }, "peerDependencies": { - "react": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0", - "react-dom": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0" + "react": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-base16-styling": { - "version": "0.5.3", - "integrity": "sha512-EPuchwVvYPSFFIjGpH0k6wM0HQsmJ0vCk7BSl5ryxMVFIWW4hX4Kksu4PNtxfgOxDebTLkJQ8iC7zwAql0eusg==", + "version": "0.9.1", + "integrity": "sha512-1s0CY1zRBOQ5M3T61wetEpvQmsYSNtWEcdYzyZNxKa8t7oDvaOn9d21xrGezGAHFWLM7SHcktPuPTrvoqxSfKw==", "dependencies": { + "@babel/runtime": "^7.16.7", + "@types/base16": "^1.0.2", + "@types/lodash": "^4.14.178", "base16": "^1.0.0", - "lodash.curry": "^4.0.1", - "lodash.flow": "^3.3.0", - "pure-color": "^1.2.0" + "color": "^3.2.1", + "csstype": "^3.0.10", + "lodash.curry": "^4.1.1" } }, + "node_modules/react-base16-styling/node_modules/csstype": { + "version": "3.1.1", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, "node_modules/react-bootstrap-slider": { "version": "2.1.5", "integrity": "sha512-7rO3JlCVIpr+XtwiSfg8r+MPqyl9KdLI61pNuSMBYYQZ42IWBC+kk/UDyYevp76aGAMtd9SCW8erxOvq+VpekQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dependencies": { "bootstrap-slider": "9.9.0", "es6bindall": "^0.0.9" @@ -38295,16 +42244,26 @@ "integrity": "sha512-3U8owtxLBekUu6qn+evqlI9S2Q4bTrY5cJqDhg4CzyQJzKSwdUhztE40Hvg+1azpylQgMDUK38uvKGpgcK27fA==" }, "node_modules/react-checkbox-tree": { - "version": "1.5.1", - "integrity": "sha512-fBLMVpd7/YXavzIBz+3OMS5eo2oZLW9PlTY4M1zrJ3TdZRzgILicSzRj6V5VKKm80y8uQXn60skn98pwn3i3Ig==", + "version": "1.8.0", + "integrity": "sha512-ufC4aorihOvjLpvY1beab2hjVLGZbDTFRzw62foG0+th+KX7e/sdmWu/nD1ZS/U5Yr0rWGwedGH5GOtR0IkUXw==", "dependencies": { "classnames": "^2.2.5", "lodash": "^4.17.10", - "nanoid": "^2.0.0", + "nanoid": "^3.0.0", "prop-types": "^15.5.8" }, "peerDependencies": { - "react": "^15.3.0 || ^16.0.0" + "react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-checkbox-tree/node_modules/nanoid": { + "version": "3.3.4", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/react-color": { @@ -38327,16 +42286,45 @@ } }, "node_modules/react-datetime": { - "version": "3.0.4", - "integrity": "sha512-v6MVwCve+DRaLN2f22LTO5TlrPpkUXumPkp1zfrbhaFtSYGl2grZ2JtwJfLxRj/T4ACyePAV4srCR6cMSiQ/Iw==", + "version": "3.2.0", + "integrity": "sha512-w5XdeNIGzBht9CadaZIJhKUhEcDTgH0XokKxGPCxeeJRYL7B3HIKA8CM6Q0xej2JFJt0n5d+zi3maMwaY3262A==", "dependencies": { "prop-types": "^15.5.7" }, "peerDependencies": { "moment": "^2.16.0", - "react": "^16.5.0" + "react": "^16.5.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-diff-viewer-continued": { + "version": "3.2.5", + "integrity": "sha512-oqRzPl37ixHQNhARUCX782DT1Ae1Di4oNN2csq4WyFZLWGRR+sw7A5jcuhDEh6IyIEIRtWyd5BBfubSjur98tQ==", + "dependencies": { + "classnames": "^2.3.1", + "diff": "^5.1.0", + "emotion": "^10.0.27", + "memoize-one": "^6.0.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 8" + }, + "peerDependencies": { + "react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-diff-viewer-continued/node_modules/diff": { + "version": "5.1.0", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/react-diff-viewer-continued/node_modules/memoize-one": { + "version": "6.0.0", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/react-dnd": { "version": "11.1.3", "integrity": "sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==", @@ -38497,13 +42485,13 @@ } }, "node_modules/react-hot-loader": { - "version": "4.13.0", - "integrity": "sha512-JrLlvUPqh6wIkrK2hZDfOyq/Uh/WeVEr8nc7hkn2/3Ul0sx1Kr5y4kOGNacNRoj7RhwLNcQ3Udf1KJXrqc0ZtA==", + "version": "4.13.1", + "integrity": "sha512-ZlqCfVRqDJmMXTulUGic4lN7Ic1SXgHAFw7y/Jb7t25GBgTR0fYAJ8uY4mrpxjRyWGWmqw77qJQGnYbzCvBU7g==", "dependencies": { "fast-levenshtein": "^2.0.6", "global": "^4.3.0", "hoist-non-react-statics": "^3.3.0", - "loader-utils": "^1.1.0", + "loader-utils": "^2.0.3", "prop-types": "^15.6.1", "react-lifecycles-compat": "^3.0.4", "shallowequal": "^1.1.0", @@ -38513,9 +42501,9 @@ "node": ">= 6" }, "peerDependencies": { - "@types/react": "^15.0.0 || ^16.0.0 || ^17.0.0 ", - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 ", - "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 " + "@types/react": "^15.0.0 || ^16.0.0 || ^17.0.0", + "react": "^15.0.0 || ^16.0.0 || ^17.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -38523,6 +42511,28 @@ } } }, + "node_modules/react-hot-loader/node_modules/json5": { + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-hot-loader/node_modules/loader-utils": { + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/react-hot-loader/node_modules/source-map": { "version": "0.7.3", "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", @@ -38530,14 +42540,6 @@ "node": ">= 8" } }, - "node_modules/react-icons": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.7.1.tgz", - "integrity": "sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==", - "peerDependencies": { - "react": "*" - } - }, "node_modules/react-input-autosize": { "version": "2.2.2", "integrity": "sha512-jQJgYCA3S0j+cuOwzuCd1OjmBmnZLdqQdiLKRYrsMMzbjUrVDS5RvJUDwJqA7sKuksDuzFtm6hZGKFu7Mjk5aw==", @@ -38560,9 +42562,16 @@ "react": "^16.8.4 || ^17.0.0" } }, + "node_modules/react-intersection-observer": { + "version": "9.4.1", + "integrity": "sha512-IXpIsPe6BleFOEHKzKh5UjwRUaz/JYS0lT/HPsupWEQou2hDqjhLMStc5zyE3eQVT4Fk3FufM8Fw33qW1uyeiw==", + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-is": { - "version": "16.6.3", - "integrity": "sha512-u7FDWtthB4rWibG/+mFbVd5FvdI20yde86qKGx4lVUTWmPlSWQ4QxbBIrrs+HnXGbxOUlUzTAP/VDmvCwaP2yA==" + "version": "16.13.1", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-js-cron": { "version": "1.2.0", @@ -38574,27 +42583,33 @@ } }, "node_modules/react-json-tree": { - "version": "0.11.2", - "integrity": "sha512-aYhUPj1y5jR3ZQ+G3N7aL8FbTyO03iLwnVvvEikLcNFqNTyabdljo9xDftZndUBFyyyL0aK3qGO9+8EilILHUw==", + "version": "0.17.0", + "integrity": "sha512-hcWjibI/fAvsKnfYk+lka5OrE1Lvb1jH5pSnFhIU5T8cCCxB85r6h/NOzDPggSSgErjmx4rl3+2EkeclIKBOhg==", "dependencies": { - "babel-runtime": "^6.6.1", - "prop-types": "^15.5.8", - "react-base16-styling": "^0.5.1" + "@babel/runtime": "^7.18.3", + "@types/lodash": "^4.14.182", + "@types/prop-types": "^15.7.5", + "prop-types": "^15.8.1", + "react-base16-styling": "^0.9.1" }, "peerDependencies": { - "react": "^15.0.0 || ^16.0.0", - "react-dom": "^15.0.0 || ^16.0.0" + "@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0", + "react": "^16.3.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-jsonschema-form": { - "version": "1.2.0", - "integrity": "sha512-rR77qoFiQ5TxDYwsJz8UWmDner4jQ4xMnDqeV6Nvg7GtoEyOUoTVkI/SBMEzfXuF/piWZXYjquP96Hy/2L7C+Q==", + "version": "1.8.1", + "integrity": "sha512-aaDloxNAcGXOOOcdKOxxqEEn5oDlPUZgWcs8unXXB9vjBRgCF8rCm/wVSv1u2G5ih0j/BX6Ewd/WjI2g00lPdg==", + "deprecated": "react-jsonschema-form has been moved to @rjsf/core", "dependencies": { - "ajv": "^5.2.3", - "babel-runtime": "^6.26.0", + "@babel/runtime-corejs2": "^7.4.5", + "ajv": "^6.7.0", "core-js": "^2.5.7", - "lodash.topath": "^4.5.2", - "prop-types": "^15.5.8" + "lodash": "^4.17.15", + "prop-types": "^15.5.8", + "react-is": "^16.8.4", + "react-lifecycles-compat": "^3.0.4", + "shortid": "^2.2.14" }, "engines": { "node": ">=6", @@ -38604,30 +42619,12 @@ "react": ">=15" } }, - "node_modules/react-jsonschema-form/node_modules/ajv": { - "version": "5.5.2", - "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", - "dependencies": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, "node_modules/react-jsonschema-form/node_modules/core-js": { "version": "2.6.9", "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", "hasInstallScript": true }, - "node_modules/react-jsonschema-form/node_modules/fast-deep-equal": { - "version": "1.1.0", - "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==" - }, - "node_modules/react-jsonschema-form/node_modules/json-schema-traverse": { - "version": "0.3.1", - "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==" - }, "node_modules/react-lifecycles-compat": { "version": "3.0.4", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" @@ -38651,15 +42648,17 @@ } }, "node_modules/react-map-gl": { - "version": "4.1.16", - "integrity": "sha512-EtiHCeqM69wKR9RDyLvtk6pTPS5+OFeAPIsYw6afnlGTauFAq3iD40SHuAOElgoJmm7J+cjPfHqu7m7tB4/FfA==", + "version": "6.1.19", + "integrity": "sha512-rrDoRyEIGzVLUB5QfgsZ5xCw7jeUtmmYzHUv86xDx8oGp90VTV2KTQJ4RPQiSAmpfIFh6/pPqI28Pguf1u/mOg==", "dependencies": { "@babel/runtime": "^7.0.0", - "mapbox-gl": "~0.54.0", - "mjolnir.js": "^2.2.0", + "@types/geojson": "^7946.0.7", + "@types/mapbox-gl": "^2.0.3", + "mapbox-gl": "^2.3.0", + "mjolnir.js": "^2.5.0", "prop-types": "^15.7.2", - "react-virtualized-auto-sizer": "^1.0.2", - "viewport-mercator-project": "^6.2.1" + "resize-observer-polyfill": "^1.5.1", + "viewport-mercator-project": "^7.0.4" }, "engines": { "node": ">= 4", @@ -38669,60 +42668,16 @@ "react": ">=16.3.0" } }, - "node_modules/react-map-gl/node_modules/esm": { - "version": "3.0.84", - "integrity": "sha512-SzSGoZc17S7P+12R9cg21Bdb7eybX25RnIeRZ80xZs+VZ3kdQKzqTp2k4hZJjR7p9l0186TTXSgrxzlMDBktlw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/react-map-gl/node_modules/mapbox-gl": { - "version": "0.54.1", - "integrity": "sha512-HtY+HobYTHTsFOJ3buTHtNvZv/Tjfp0vararhEWCjI7wQq8XxK16sEpsXucokrAhuu94js4KJylo13bKJx6l0Q==", - "dependencies": { - "@mapbox/geojson-rewind": "^0.4.0", - "@mapbox/geojson-types": "^1.0.2", - "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/mapbox-gl-supported": "^1.4.0", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^1.1.0", - "@mapbox/unitbezier": "^0.0.0", - "@mapbox/vector-tile": "^1.3.1", - "@mapbox/whoots-js": "^3.1.0", - "csscolorparser": "~1.0.2", - "earcut": "^2.1.5", - "esm": "~3.0.84", - "geojson-vt": "^3.2.1", - "gl-matrix": "^3.0.0", - "grid-index": "^1.1.0", - "minimist": "0.0.8", - "murmurhash-js": "^1.0.0", - "pbf": "^3.0.5", - "potpack": "^1.0.1", - "quickselect": "^2.0.0", - "rw": "^1.3.3", - "supercluster": "^6.0.1", - "tinyqueue": "^2.0.0", - "vt-pbf": "^3.1.1" - }, - "engines": { - "node": ">=6.4.0" - } - }, - "node_modules/react-map-gl/node_modules/minimist": { - "version": "0.0.8", - "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==" - }, - "node_modules/react-map-gl/node_modules/supercluster": { - "version": "6.0.2", - "integrity": "sha512-aa0v2HURjBTOpbcknilcfxGDuArM8khklKSmZ/T8ZXL0BuRwb5aRw95lz+2bmWpFvCXDX/+FzqHxmg0TIaJErw==", + "node_modules/react-map-gl/node_modules/viewport-mercator-project": { + "version": "7.0.4", + "integrity": "sha512-0jzpL6pIMocCKWg1C3mqi/N4UPgZC3FzwghEm1H+XsUo8hNZAyJc3QR7YqC816ibOR8aWT5pCsV+gCu8/BMJgg==", "dependencies": { - "kdbush": "^3.0.0" + "@math.gl/web-mercator": "^3.5.5" } }, "node_modules/react-markdown": { - "version": "8.0.4", - "integrity": "sha512-2oxHa6oDxc1apg/Gnc1Goh06t3B617xeywqI/92wmDV9FELI6ayRkwge7w7DoEqM0gRpZGTNU6xQG+YpJISnVg==", + "version": "8.0.3", + "integrity": "sha512-We36SfqaKoVNpN1QqsZwWSv/OZt5J15LNgTLWynwAN5b265hrQrsjMtlRNwUvS+YyR3yDM8HpTNc4pK9H/Gc0A==", "dependencies": { "@types/hast": "^2.0.0", "@types/prop-types": "^15.0.0", @@ -38750,16 +42705,16 @@ } }, "node_modules/react-markdown/node_modules/comma-separated-tokens": { - "version": "2.0.3", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "version": "2.0.2", + "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/react-markdown/node_modules/property-information": { - "version": "6.2.0", - "integrity": "sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==", + "version": "6.1.1", + "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -38770,8 +42725,8 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/react-markdown/node_modules/space-separated-tokens": { - "version": "2.0.2", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "version": "2.0.1", + "integrity": "sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -38816,19 +42771,65 @@ "react-dom": "^16.6.0 || ^17.0.0" } }, - "node_modules/react-redux": { - "version": "7.2.0", - "integrity": "sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA==", + "node_modules/react-query": { + "version": "3.39.2", + "integrity": "sha512-F6hYDKyNgDQfQOuR1Rsp3VRzJnWHx6aRnnIZHMNGGgbL3SBgpZTDg8MQwmxOgpCAoqZJA+JSNCydF1xGJqKOCA==", "dependencies": { "@babel/runtime": "^7.5.5", - "hoist-non-react-statics": "^3.3.0", + "broadcast-channel": "^3.4.1", + "match-sorter": "^6.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-query/node_modules/broadcast-channel": { + "version": "3.7.0", + "integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "detect-node": "^2.1.0", + "js-sha3": "0.8.0", + "microseconds": "0.2.0", + "nano-time": "1.0.0", + "oblivious-set": "1.0.0", + "rimraf": "3.0.2", + "unload": "2.2.0" + } + }, + "node_modules/react-query/node_modules/unload": { + "version": "2.2.0", + "integrity": "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==", + "dependencies": { + "@babel/runtime": "^7.6.2", + "detect-node": "^2.0.4" + } + }, + "node_modules/react-redux": { + "version": "7.2.8", + "integrity": "sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", "loose-envify": "^1.4.0", "prop-types": "^15.7.2", - "react-is": "^16.9.0" + "react-is": "^17.0.2" }, "peerDependencies": { - "react": "^16.8.3", - "redux": "^2.0.0 || ^3.0.0 || ^4.0.0-0" + "react": "^16.8.3 || ^17 || ^18" }, "peerDependenciesMeta": { "react-dom": { @@ -38840,8 +42841,8 @@ } }, "node_modules/react-redux/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "version": "17.0.2", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-refresh": { "version": "0.11.0", @@ -38862,36 +42863,32 @@ } }, "node_modules/react-resize-detector": { - "version": "6.7.6", - "integrity": "sha512-/6RZlul1yePSoYJxWxmmgjO320moeLC/khrwpEVIL+D2EjLKhqOwzFv+H8laMbImVj7Zu4FlMa0oA7au3/ChjQ==", + "version": "7.1.2", + "integrity": "sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw==", "dependencies": { - "@types/resize-observer-browser": "^0.1.6", - "lodash.debounce": "^4.0.8", - "lodash.throttle": "^4.1.1", - "resize-observer-polyfill": "^1.5.1" + "lodash": "^4.17.21" }, "peerDependencies": { - "react": "^16.0.0 || ^17.0.0", - "react-dom": "^16.0.0 || ^17.0.0" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-reverse-portal": { - "version": "2.0.1", - "integrity": "sha512-sj/D9nSHspqV8i8hWkTSZ5Ohnrqk2A5fkDKw4Xe/zV4OfF1UYwmbzrxLdmNRdKkWgQwnXIxaa2E3FC7QYdZAeA==", + "version": "2.1.1", + "integrity": "sha512-FzuVLYEigKPB0NuMNLWymCgVp+P1h1MY57fQxhmY22idzz6El1rsXK5+bQ+wXvEa0smUtqTDcpM77epnXDV9wg==", "peerDependencies": { - "react": "^16.0.0", - "react-dom": "^16.0.0" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-router": { - "version": "5.1.2", - "integrity": "sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A==", + "version": "5.3.4", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", "dependencies": { - "@babel/runtime": "^7.1.2", + "@babel/runtime": "^7.12.13", "history": "^4.9.0", "hoist-non-react-statics": "^3.1.0", "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.3.0", "path-to-regexp": "^1.7.0", "prop-types": "^15.6.2", "react-is": "^16.6.0", @@ -38903,14 +42900,14 @@ } }, "node_modules/react-router-dom": { - "version": "5.1.2", - "integrity": "sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew==", + "version": "5.3.4", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", "dependencies": { - "@babel/runtime": "^7.1.2", + "@babel/runtime": "^7.12.13", "history": "^4.9.0", "loose-envify": "^1.3.1", "prop-types": "^15.6.2", - "react-router": "5.1.2", + "react-router": "5.3.4", "tiny-invariant": "^1.0.2", "tiny-warning": "^1.0.0" }, @@ -38945,8 +42942,8 @@ } }, "node_modules/react-select": { - "version": "3.1.0", - "integrity": "sha512-wBFVblBH1iuCBprtpyGtd1dGMadsG36W5/t2Aj8OE6WbByDg5jIFyT7X5gT+l0qmT5TqWhxX+VsKJvCEl2uL9g==", + "version": "3.2.0", + "integrity": "sha512-B/q3TnCZXEKItO0fFN/I0tWOX3WJvi/X2wtdffmwSQVRwg5BpValScTO1vdic9AxlUgmeSzib2hAZAwIUQUZGQ==", "dependencies": { "@babel/runtime": "^7.4.4", "@emotion/cache": "^10.0.9", @@ -38954,12 +42951,12 @@ "@emotion/css": "^10.0.9", "memoize-one": "^5.0.0", "prop-types": "^15.6.0", - "react-input-autosize": "^2.2.2", + "react-input-autosize": "^3.0.0", "react-transition-group": "^4.3.0" }, "peerDependencies": { - "react": "^16.8.0", - "react-dom": "^16.8.0" + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" } }, "node_modules/react-select/node_modules/@emotion/cache": { @@ -38980,6 +42977,16 @@ "csstype": "^2.6.7" } }, + "node_modules/react-select/node_modules/react-input-autosize": { + "version": "3.0.0", + "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==", + "dependencies": { + "prop-types": "^15.5.8" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0" + } + }, "node_modules/react-select/node_modules/react-transition-group": { "version": "4.4.1", "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", @@ -39005,8 +43012,8 @@ } }, "node_modules/react-sortable-hoc": { - "version": "1.11.0", - "integrity": "sha512-v1CDCvdfoR3zLGNp6qsBa4J1BWMEVH25+UKxF/RvQRh+mrB+emqtVHMgZ+WreUiKJoEaiwYoScaueIKhMVBHUg==", + "version": "2.0.0", + "integrity": "sha512-JZUw7hBsAHXK7PTyErJyI7SopSBFRcFHDjWW5SWjcugY0i6iH7f+eJkY8cJmGMlZ1C9xz1J3Vjz0plFpavVeRg==", "dependencies": { "@babel/runtime": "^7.2.0", "invariant": "^2.2.4", @@ -39014,8 +43021,8 @@ }, "peerDependencies": { "prop-types": "^15.5.7", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0", - "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0" + "react": "^16.3.0 || ^17.0.0", + "react-dom": "^16.3.0 || ^17.0.0" } }, "node_modules/react-split": { @@ -39046,18 +43053,6 @@ "version": "1.6.2", "integrity": "sha512-72C7zcQePzlmWqPOKkB2Ro0sUmnWSx+qEWXjLJKk6Qp4jAkFRz1hJgJb+ay6ZQyz/Aw9r8N/PZiCEKbPVpFoDQ==" }, - "node_modules/react-sticky": { - "version": "6.0.3", - "integrity": "sha512-LNH4UJlRatOqo29/VHxDZOf6fwbgfgcHO4mkEFvrie5FuaZCSTGtug5R8NGqJ0kSnX8gHw8qZN37FcvnFBJpTQ==", - "dependencies": { - "prop-types": "^15.5.8", - "raf": "^3.3.0" - }, - "peerDependencies": { - "react": ">=15", - "react-dom": ">=15" - } - }, "node_modules/react-style-proptype": { "version": "3.2.2", "integrity": "sha512-ywYLSjNkxKHiZOqNlso9PZByNEY+FTyh3C+7uuziK0xFXu9xzdyfHwg4S9iyiRRoPCR4k2LqaBBsWVmSBwCWYQ==", @@ -39087,14 +43082,14 @@ } }, "node_modules/react-table": { - "version": "7.6.3", - "integrity": "sha512-hfPF13zDLxPMpLKzIKCE8RZud9T/XrRTsaCIf8zXpWZIZ2juCl7qrGpo3AQw9eAetXV5DP7s2GDm+hht7qq5Dw==", + "version": "7.8.0", + "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "react": "^16.8.3 || ^17.0.0-0" + "react": "^16.8.3 || ^17.0.0-0 || ^18.0.0" } }, "node_modules/react-test-renderer": { @@ -39111,11 +43106,6 @@ "react": "^16.0.0" } }, - "node_modules/react-test-renderer/node_modules/react-is": { - "version": "16.9.0", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", - "dev": true - }, "node_modules/react-textarea-autosize": { "version": "8.3.3", "integrity": "sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==", @@ -39146,15 +43136,15 @@ } }, "node_modules/react-ultimate-pagination": { - "version": "1.2.0", - "integrity": "sha512-tBLzzskuBqsziQDUI98hA7FTBy2/Q5olRsvu3GdLYykfGUgDvYQOI7hLi9o5pD5zJeuAsVn3OoAUw0CaJi0WoQ==", + "version": "1.3.0", + "integrity": "sha512-Nvf+PjncTqBW/wHgO4FM3EX7VzrUf13CnpElREUgZloG2BiEQkGseDS2r5p3h/TIvLfLb602IeaihQFJbUSt0A==", "dependencies": { "prop-types": "^15.0.0", "ultimate-pagination": "1.0.0" }, "peerDependencies": { - "react": "^0.14.0 || ^15.0.0 || ^16.0.0", - "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0" + "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", + "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/react-virtualized": { @@ -39174,46 +43164,19 @@ } }, "node_modules/react-virtualized-auto-sizer": { - "version": "1.0.6", - "integrity": "sha512-7tQ0BmZqfVF6YYEWcIGuoR3OdYe8I/ZFbNclFlGOC3pMqunkYF/oL30NCjSGl9sMEb17AnzixDz98Kqc3N76HQ==", + "version": "1.0.7", + "integrity": "sha512-Mxi6lwOmjwIjC1X4gABXMJcKHsOo0xWl3E3ugOgufB8GJU+MqrtY35aBuvCYv/razQ1Vbp7h1gWJjGjoNN5pmA==", "engines": { "node": ">8.0.0" }, "peerDependencies": { - "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0", - "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0" - } - }, - "node_modules/react-virtualized-select": { - "version": "3.1.3", - "integrity": "sha512-u6j/EfynCB9s4Lz5GGZhNUCZHvFQdtLZws7W/Tcd/v03l19OjpQs3eYjK82iYS0FgD2+lDIBpqS8LpD/hjqDRQ==", - "dependencies": { - "babel-runtime": "^6.11.6", - "prop-types": "^15.5.8", - "react-select": "^1.0.0-rc.2", - "react-virtualized": "^9.0.0" - }, - "peerDependencies": { - "react": "^15.3.0 || ^16.0.0-alpha", - "react-dom": "^15.3.0 || ^16.0.0-alpha" - } - }, - "node_modules/react-virtualized-select/node_modules/react-select": { - "version": "1.3.0", - "integrity": "sha512-g/QAU1HZrzSfxkwMAo/wzi6/ezdWye302RGZevsATec07hI/iSxcpB1hejFIp7V63DJ8mwuign6KmB3VjdlinQ==", - "dependencies": { - "classnames": "^2.2.4", - "prop-types": "^15.5.8", - "react-input-autosize": "^2.1.2" - }, - "peerDependencies": { - "react": "^0.14.9 || ^15.3.0 || ^16.0.0-rc || ^16.0", - "react-dom": "^0.14.9 || ^15.3.0 || ^16.0.0-rc || ^16.0" + "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc", + "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc" } }, "node_modules/react-window": { - "version": "1.8.5", - "integrity": "sha512-HeTwlNa37AFa8MDZFZOKcNEkuF2YflA0hpGPiTT9vR7OawEt+GZbfM6wqkBahD3D3pUjIabQYzsnY/BSJbgq6Q==", + "version": "1.8.8", + "integrity": "sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==", "dependencies": { "@babel/runtime": "^7.0.0", "memoize-one": ">=3.1.1 <6" @@ -39222,8 +43185,8 @@ "node": ">8.0.0" }, "peerDependencies": { - "react": "^15.0.0 || ^16.0.0", - "react-dom": "^15.0.0 || ^16.0.0" + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-with-styles": { @@ -39279,41 +43242,18 @@ "node": ">=0.8" } }, - "node_modules/read-chunk": { - "version": "3.2.0", - "integrity": "sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==", - "dependencies": { - "pify": "^4.0.1", - "with-open-file": "^0.1.6" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-chunk/node_modules/pify": { - "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "engines": { - "node": ">=6" - } - }, - "node_modules/read-cmd-shim": { - "version": "2.0.0", - "integrity": "sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw==", - "dev": true - }, "node_modules/read-package-json": { - "version": "3.0.1", - "integrity": "sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng==", + "version": "5.0.2", + "integrity": "sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q==", "dev": true, "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^3.0.0", - "npm-normalize-package-bin": "^1.0.0" + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^2.0.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/read-package-json-fast": { @@ -39328,45 +43268,87 @@ "node": ">=10" } }, + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "8.0.3", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/read-package-json/node_modules/hosted-git-info": { - "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "version": "5.2.1", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "lru-cache": "^7.5.1" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/read-package-json/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "7.14.1", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "5.1.2", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" } }, "node_modules/read-package-json/node_modules/normalize-package-data": { - "version": "3.0.3", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "version": "4.0.1", + "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", "dev": true, "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/read-package-json/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/read-package-json/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -39378,32 +43360,21 @@ "node": ">=10" } }, - "node_modules/read-package-json/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/read-package-tree": { - "version": "5.3.1", - "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", - "deprecated": "The functionality that this package provided is now in @npmcli/arborist", + "node_modules/read-package-json/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "util-promisify": "^2.1.0" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/read-package-tree/node_modules/read-package-json": { - "version": "2.1.2", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "dev": true, - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } + "node_modules/read-package-json/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/read-pkg": { "version": "5.2.0", @@ -39602,24 +43573,6 @@ "node": ">=8" } }, - "node_modules/redeyed": { - "version": "0.4.4", - "integrity": "sha512-pnk1vsaNLu1UAAClKsImKz9HjBvg9i8cbRqTRzJbiCjGF0fZSMqpdcA5W3juO3c4etFvTrabECkq9wjC45ZyxA==", - "dependencies": { - "esprima": "~1.0.4" - } - }, - "node_modules/redeyed/node_modules/esprima": { - "version": "1.0.4", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/reduce-css-calc": { "version": "1.3.0", "integrity": "sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==", @@ -39714,8 +43667,8 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { - "version": "9.0.0", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", + "version": "10.0.1", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "dependencies": { "regenerate": "^1.4.2" }, @@ -39724,12 +43677,12 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.7", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.13.10", + "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" }, "node_modules/regenerator-transform": { - "version": "0.14.5", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "dependencies": { "@babel/runtime": "^7.8.4" } @@ -39767,11 +43720,12 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.3.0", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "version": "1.4.3", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dependencies": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" + "functions-have-names": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -39792,13 +43746,13 @@ } }, "node_modules/regexpu-core": { - "version": "4.8.0", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "version": "5.1.0", + "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==", "dependencies": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" }, @@ -39807,12 +43761,12 @@ } }, "node_modules/regjsgen": { - "version": "0.5.2", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + "version": "0.6.0", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" }, "node_modules/regjsparser": { - "version": "0.7.0", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", + "version": "0.8.4", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "dependencies": { "jsesc": "~0.5.0" }, @@ -40190,8 +44144,8 @@ } }, "node_modules/remark-mdx/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -40506,7 +44460,8 @@ }, "node_modules/remove-trailing-separator": { "version": "1.1.0", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==" + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "devOptional": true }, "node_modules/renderkid": { "version": "2.0.7", @@ -40534,8 +44489,8 @@ } }, "node_modules/renderkid/node_modules/css-what": { - "version": "5.0.1", - "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", + "version": "5.1.0", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", "engines": { "node": ">= 6" }, @@ -40638,13 +44593,6 @@ "node": ">=0.10" } }, - "node_modules/replace-ext": { - "version": "1.0.0", - "integrity": "sha512-vuNYXC7gG7IeVNBC1xUllqCcZKRbJoSPOBhnTEcAIiKCsbuef6zO3F0Rve3isPMMoNoQRWjQwbAgAjHUHniyEA==", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/request": { "version": "2.88.2", "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", @@ -40807,7 +44755,7 @@ "node_modules/restore-cursor": { "version": "3.1.0", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "devOptional": true, + "dev": true, "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -40906,7 +44854,7 @@ "node_modules/rxjs": { "version": "6.6.7", "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "devOptional": true, + "dev": true, "dependencies": { "tslib": "^1.9.0" }, @@ -40935,6 +44883,18 @@ "ret": "~0.1.10" } }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" @@ -41020,23 +44980,26 @@ "dev": true }, "node_modules/selfsigned": { - "version": "1.10.11", - "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", + "version": "2.0.1", + "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", "dev": true, "dependencies": { - "node-forge": "^0.10.0" + "node-forge": "^1" + }, + "engines": { + "node": ">=10" } }, "node_modules/semver": { - "version": "5.6.0", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.1", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "bin": { "semver": "bin/semver" } }, "node_modules/send": { - "version": "0.17.1", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "dependencies": { "debug": "2.6.9", "depd": "~1.1.2", @@ -41045,9 +45008,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -41057,14 +45020,14 @@ } }, "node_modules/send/node_modules/http-errors": { - "version": "1.7.3", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "version": "1.8.1", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", - "setprototypeof": "1.1.1", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" @@ -41075,19 +45038,12 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/send/node_modules/setprototypeof": { - "version": "1.1.1", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "node_modules/send/node_modules/statuses": { - "version": "1.5.0", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } + "version": "1.2.0", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/serialize-javascript": { "version": "4.0.0", @@ -41143,40 +45099,22 @@ } }, "node_modules/serve-static": { - "version": "1.14.1", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/serve-static/node_modules/parseurl": { - "version": "1.3.3", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/set-blocking": { "version": "2.0.0", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, - "node_modules/set-getter": { - "version": "0.1.1", - "integrity": "sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==", - "optional": true, - "dependencies": { - "to-object-path": "^0.3.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/set-value": { "version": "2.0.1", "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", @@ -41260,25 +45198,10 @@ "node": ">=0.4.0" } }, - "node_modules/sharkdown": { - "version": "0.1.1", - "integrity": "sha512-exwooSpmo5s45lrexgz6Q0rFQM574wYIX3iDZ7RLLqOb7IAoQZu9nxlZODU972g19sR69OIpKP2cpHTzU+PHIg==", - "dependencies": { - "cardinal": "~0.4.2", - "minimist": "0.0.5", - "split": "~0.2.10" - }, - "bin": { - "sharkdown": "sharkdown" - } - }, - "node_modules/sharkdown/node_modules/minimist": { - "version": "0.0.5", - "integrity": "sha512-rSJ0cdmCj3qmKdObcnMcWgPVOyaOWlazLhZAJW0s6G6lx1ZEuFkraWmEH5LTvX90btkfHPclQBjvjU7A/kYRFg==" - }, "node_modules/shebang-command": { "version": "1.2.0", "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, "dependencies": { "shebang-regex": "^1.0.0" }, @@ -41289,6 +45212,7 @@ "node_modules/shebang-regex": { "version": "1.0.0", "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -41352,8 +45276,19 @@ "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==" }, "node_modules/signal-exit": { - "version": "3.0.3", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + "version": "3.0.7", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, "node_modules/sinon": { "version": "9.0.2", @@ -41432,14 +45367,6 @@ "node": ">=8" } }, - "node_modules/slide": { - "version": "1.1.6", - "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", @@ -41558,22 +45485,30 @@ } }, "node_modules/sockjs": { - "version": "0.3.21", - "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", + "version": "0.3.24", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, "dependencies": { "faye-websocket": "^0.11.3", - "uuid": "^3.4.0", + "uuid": "^8.3.2", "websocket-driver": "^0.7.4" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/socks": { - "version": "2.6.1", - "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==", + "version": "2.7.1", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dev": true, "dependencies": { - "ip": "^1.1.5", - "smart-buffer": "^4.1.0" + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" }, "engines": { "node": ">= 10.13.0", @@ -41581,21 +45516,21 @@ } }, "node_modules/socks-proxy-agent": { - "version": "5.0.1", - "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "version": "7.0.0", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", "dev": true, "dependencies": { "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" + "debug": "^4.3.3", + "socks": "^2.6.2" }, "engines": { - "node": ">= 6" + "node": ">= 10" } }, "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -41614,10 +45549,14 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/socks/node_modules/ip": { + "version": "2.0.0", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, "node_modules/sort-keys": { "version": "4.2.0", "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", - "dev": true, "dependencies": { "is-plain-obj": "^2.0.0" }, @@ -41631,7 +45570,6 @@ "node_modules/sort-keys/node_modules/is-plain-obj": { "version": "2.1.0", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, "engines": { "node": ">=8" } @@ -41878,8 +45816,9 @@ "dev": true }, "node_modules/split": { - "version": "0.2.10", - "integrity": "sha512-e0pKq+UUH2Xq/sXbYpZBZc3BawsfDZ7dgv+JtRTUPNcvF5CMR4Y9cvJqkMY0MoxWzTHvZuz1beg6pNEKlszPiQ==", + "version": "1.0.1", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, "dependencies": { "through": "2" }, @@ -41986,14 +45925,6 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" }, - "node_modules/stack-trace": { - "version": "0.0.10", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/stack-utils": { "version": "2.0.3", "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", @@ -42113,9 +46044,8 @@ } }, "node_modules/statuses": { - "version": "1.4.0", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true, + "version": "1.5.0", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "engines": { "node": ">= 0.6" } @@ -42275,10 +46205,6 @@ "node": ">=8" } }, - "node_modules/string-template": { - "version": "0.2.1", - "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==" - }, "node_modules/string-width": { "version": "2.1.1", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", @@ -42353,35 +46279,40 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.0", - "integrity": "sha512-9EIjYD/WdlvLpn987+ctkLf0FfvBefOCuiEr2henD8X+7jfwPnyvTdmW8OJhj5p+M0/96mBdynLWkxUr+rHlpg==", + "version": "1.2.7", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", "dev": true, "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.13.0", - "function-bind": "^1.1.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.6", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.6", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -42405,40 +46336,6 @@ "node": ">=4" } }, - "node_modules/strip-bom-buf": { - "version": "1.0.0", - "integrity": "sha512-1sUIL1jck0T1mhOLP2c696BIznzT525Lkub+n4jjMHjhjhoAQA6Ye659DxdlZBr0aLDMQoTxKIpnlqxgtwjsuQ==", - "optional": true, - "dependencies": { - "is-utf8": "^0.2.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-bom-stream": { - "version": "2.0.0", - "integrity": "sha512-yH0+mD8oahBZWnY43vxs4pSinn8SMKAdml/EOGBewoe1Y0Eitd0h2Mg3ZRiXruUW6L4P+lvZiEgbh0NgUGia1w==", - "optional": true, - "dependencies": { - "first-chunk-stream": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-bom-stream/node_modules/strip-bom": { - "version": "2.0.0", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", - "optional": true, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/strip-comments": { "version": "2.0.1", "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", @@ -42458,7 +46355,6 @@ "node_modules/strip-final-newline": { "version": "2.0.0", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "devOptional": true, "engines": { "node": ">=6" } @@ -42652,11 +46548,14 @@ } }, "node_modules/svgo/node_modules/css-what": { - "version": "3.2.1", - "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==", + "version": "3.4.2", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", "dev": true, "engines": { "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, "node_modules/svgo/node_modules/domutils": { @@ -42932,54 +46831,6 @@ "node": ">=4" } }, - "node_modules/temp-write": { - "version": "4.0.0", - "integrity": "sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "is-stream": "^2.0.0", - "make-dir": "^3.0.0", - "temp-dir": "^1.0.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/temp-write/node_modules/is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/temp-write/node_modules/make-dir": { - "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/temp-write/node_modules/semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/term-size": { "version": "2.2.1", "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", @@ -43007,8 +46858,8 @@ } }, "node_modules/terser": { - "version": "4.6.3", - "integrity": "sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==", + "version": "4.8.1", + "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", "dependencies": { "commander": "^2.20.0", "source-map": "~0.6.1", @@ -43241,12 +47092,12 @@ } }, "node_modules/terser-webpack-plugin/node_modules/terser": { - "version": "5.13.1", - "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", + "version": "5.14.2", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dependencies": { + "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.8.0-beta.0", "source-map-support": "~0.5.20" }, "bin": { @@ -43256,16 +47107,6 @@ "node": ">=10" } }, - "node_modules/terser-webpack-plugin/node_modules/terser/node_modules/source-map": { - "version": "0.8.0-beta.0", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/terser-webpack-plugin/node_modules/webpack-sources": { "version": "1.4.3", "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", @@ -43274,15 +47115,6 @@ "source-map": "~0.6.1" } }, - "node_modules/terser-webpack-plugin/node_modules/whatwg-url": { - "version": "7.1.0", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, "node_modules/terser-webpack-plugin/node_modules/yallist": { "version": "4.0.0", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" @@ -43356,12 +47188,9 @@ } }, "node_modules/thread-loader/node_modules/json5": { - "version": "2.2.0", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, "bin": { "json5": "lib/cli.js" }, @@ -43370,8 +47199,8 @@ } }, "node_modules/thread-loader/node_modules/loader-utils": { - "version": "2.0.0", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -43396,7 +47225,8 @@ }, "node_modules/through": { "version": "2.3.8", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true }, "node_modules/through2": { "version": "2.0.5", @@ -43411,13 +47241,6 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, - "node_modules/timed-out": { - "version": "4.0.1", - "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/timers-browserify": { "version": "2.0.12", "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", @@ -43557,8 +47380,8 @@ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" }, "node_modules/toidentifier": { - "version": "1.0.0", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "engines": { "node": ">=0.6" } @@ -43606,6 +47429,7 @@ "node_modules/tr46": { "version": "1.0.1", "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -43632,7 +47456,8 @@ }, "node_modules/trim": { "version": "0.0.1", - "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==" + "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==", + "deprecated": "Use String.prototype.trim() instead" }, "node_modules/trim-lines": { "version": "3.0.1", @@ -43913,6 +47738,18 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typedarray": { "version": "0.0.6", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" @@ -43972,34 +47809,21 @@ "node": ">=0.8.0" } }, - "node_modules/uid-number": { - "version": "0.0.6", - "integrity": "sha512-c461FXIljswCuscZn67xq9PpszkPT6RjheWFQTgCyabJrTUozElanb0YEqv2UGgk247YpcJkFBuSGNvBlpXM9w==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/ultimate-pagination": { "version": "1.0.0", "integrity": "sha512-bJNroO5GM11McB9RJ1rHZGiXV/jU89Qwc6U5wR8jZuk0uFVajIvUDGPiROVvNMApvh7Ij3cPoeG5V3UlF4GvOA==" }, - "node_modules/umask": { - "version": "1.1.0", - "integrity": "sha512-lE/rxOhmiScJu9L6RTNVgB/zZbF+vGC0/p6D3xnkAePI2o0sMyFG966iR5Ki50OI/0mNi2yaRnxfLsPmEZF/JA==", - "dev": true - }, "node_modules/un-eval": { "version": "1.2.0", "integrity": "sha512-Wlj/pum6dQtGTPD/lclDtoVPkSfpjPfy1dwnnKw/sZP5DpBH9fLhBgQfsqNhe5/gS1D+vkZUuB771NRMUPA5CA==" }, "node_modules/unbox-primitive": { - "version": "1.0.1", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" }, "funding": { @@ -44039,8 +47863,8 @@ } }, "node_modules/underscore": { - "version": "1.12.0", - "integrity": "sha512-21rQzss/XPMjolTiIezSu3JAjgagXKROtNrYFEOWK109qY1Uv2tVjPTZ1ci2HgvQDA16gHYSthQIJfB+XId/rQ==" + "version": "1.13.6", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" }, "node_modules/unfetch": { "version": "4.2.0", @@ -44273,6 +48097,10 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/universal-user-agent": { + "version": "6.0.0", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + }, "node_modules/universalify": { "version": "2.0.0", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", @@ -44340,13 +48168,6 @@ "node": ">=0.10.0" } }, - "node_modules/unzip-response": { - "version": "2.0.1", - "integrity": "sha512-N0XH6lqDtFH84JxptQoZYmloF4nzrQqqrAymNj+/gW60AO2AZgOcf4O/nUXJcYfyQkqvMo9lSupBZmmgvuVXlw==", - "engines": { - "node": ">=4" - } - }, "node_modules/upath": { "version": "1.2.0", "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", @@ -44356,6 +48177,34 @@ "yarn": "*" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.5", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-browserslist-db/node_modules/picocolors": { + "version": "1.0.0", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, "node_modules/uri-js": { "version": "4.2.2", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", @@ -44406,8 +48255,8 @@ } }, "node_modules/url-loader/node_modules/json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -44416,8 +48265,8 @@ } }, "node_modules/url-loader/node_modules/loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -44436,16 +48285,6 @@ "requires-port": "^1.0.0" } }, - "node_modules/url-parse-lax": { - "version": "1.0.0", - "integrity": "sha512-BVA4lR5PIviy2PMseNd2jbFQ+jwSwQGdJejf5ctd1rEXt0Ypd7yanUK9+lYechVlN5VaTJGsu2U/3MDDu6KgBA==", - "dependencies": { - "prepend-http": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/url/node_modules/punycode": { "version": "1.3.2", "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" @@ -44468,11 +48307,11 @@ } }, "node_modules/use-immer": { - "version": "0.6.0", - "integrity": "sha512-dFGRfvWCqPDTOt/S431ETYTg6+uxbpb7A1pptufwXVzGJY3RlXr38+3wyLNpc6SbbmAKjWl6+EP6uW74fkEsXQ==", + "version": "0.8.1", + "integrity": "sha512-OfTFf1pL+ICjjcLPn9+ZnaJO/Yg4MBzYZtACEe2mZ/W2A5col28PNUnwowOAaBuOogACOK/37TU17KgsIhUpOw==", "peerDependencies": { "immer": ">=2.0.0", - "react": "^16.8.0 || ^17.0.1" + "react": "^16.8.0 || ^17.0.1 || ^18.0.0" } }, "node_modules/use-isomorphic-layout-effect": { @@ -44524,14 +48363,6 @@ "version": "1.0.2", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "node_modules/util-promisify": { - "version": "2.1.0", - "integrity": "sha512-K+5eQPYs14b3+E+hmE2J6gCZ4JmMl9DbYS6BeP2CHq6WMuNxErxf5B/n0fz85L8zUuoO6rIzNNmIQDu/j+1OcA==", - "dev": true, - "dependencies": { - "object.getownpropertydescriptors": "^2.0.3" - } - }, "node_modules/util.promisify": { "version": "1.0.0", "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", @@ -44680,8 +48511,8 @@ } }, "node_modules/vfile": { - "version": "5.3.6", - "integrity": "sha512-ADBsmerdGBs2WYckrLBEmuETSPyTD4TuLxTrw0DvjirxW1ra4ZwkbzG8ndsv3Q57smvHxo677MHaQrY9yxH8cA==", + "version": "5.3.5", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", "dependencies": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", @@ -44706,8 +48537,8 @@ } }, "node_modules/vfile-message": { - "version": "3.1.3", - "integrity": "sha512-0yaU+rj2gKAyEk12ffdSbBfjnnj+b1zqTBv3OQCTn8yEB02bsPizwdBPrLJjHnK+cU9EMMcUnNv938XcZIkmdA==", + "version": "3.1.2", + "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", "dependencies": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^3.0.0" @@ -44746,52 +48577,37 @@ "gl-matrix": "^3.0.0" } }, - "node_modules/vinyl": { - "version": "2.2.1", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dependencies": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } + "node_modules/vlq": { + "version": "0.2.3", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" }, - "node_modules/vinyl-file": { - "version": "3.0.0", - "integrity": "sha512-BoJDj+ca3D9xOuPEM6RWVtWQtvEPQiQYn82LvdxhLWplfQsBzBqtgK0yhCP0s1BNTi6dH9BO+dzybvyQIacifg==", - "optional": true, + "node_modules/vm-browserify": { + "version": "1.1.2", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "node_modules/vm2": { + "version": "3.9.13", + "integrity": "sha512-0rvxpB8P8Shm4wX2EKOiMp7H2zq+HUE/UwodY0pCZXs9IffIKZq6vUti5OgkVCTakKo9e/fgO4X1fkwfjWxE3Q==", + "dev": true, "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.3.0", - "strip-bom-buf": "^1.0.0", - "strip-bom-stream": "^2.0.0", - "vinyl": "^2.0.1" + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + }, + "bin": { + "vm2": "bin/vm2" }, "engines": { - "node": ">=4" + "node": ">=6.0" } }, - "node_modules/vinyl-file/node_modules/pify": { - "version": "2.3.0", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "optional": true, + "node_modules/vm2/node_modules/acorn-walk": { + "version": "8.2.0", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.4.0" } }, - "node_modules/vlq": { - "version": "0.2.3", - "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" - }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" - }, "node_modules/vt-pbf": { "version": "3.1.3", "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", @@ -44811,16 +48627,29 @@ } }, "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "version": "3.0.0", + "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", "dev": true, "dependencies": { - "xml-name-validator": "^3.0.0" + "xml-name-validator": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" + } + }, + "node_modules/w3c-xmlserializer/node_modules/xml-name-validator": { + "version": "4.0.0", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" } }, + "node_modules/walk-up-path": { + "version": "1.0.0", + "integrity": "sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg==", + "dev": true + }, "node_modules/walker": { "version": "1.0.7", "integrity": "sha512-cF4je9Fgt6sj1PKfuFt9jpQPeHosM+Ryma/hfY9U7uXGKM7pJCsF0v2r55o+Il54+i77SyYWetB4tD1dEygRkw==", @@ -44932,7 +48761,8 @@ }, "node_modules/webidl-conversions": { "version": "4.0.2", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true }, "node_modules/webpack": { "version": "5.52.1", @@ -45239,35 +49069,39 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.2.0", - "integrity": "sha512-iBaDkHBLfW3cEITeJWNkjZBrm+b5A3YLg8XVdNOdjUNABdXJwcsJv4dzKSnVf1q4Ch489+6epWVW6OcOyVfG7w==", + "version": "4.10.1", + "integrity": "sha512-FIzMq3jbBarz3ld9l7rbM7m6Rj1lOsgq/DyLGMX/fPEB1UBUPtf5iL/4eNfhx8YYJTRlzfv107UfWSWcBK5Odw==", "dev": true, "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", "ansi-html-community": "^0.0.8", - "bonjour": "^3.5.0", - "chokidar": "^3.5.1", - "colorette": "^1.2.2", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "del": "^6.0.0", - "express": "^4.17.1", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", "graceful-fs": "^4.2.6", "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.0", - "internal-ip": "^6.2.0", + "http-proxy-middleware": "^2.0.3", "ipaddr.js": "^2.0.1", "open": "^8.0.9", "p-retry": "^4.5.0", - "portfinder": "^1.0.28", - "schema-utils": "^3.1.0", - "selfsigned": "^1.10.11", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", "serve-index": "^1.9.1", - "sockjs": "^0.3.21", + "sockjs": "^0.3.24", "spdy": "^4.0.2", - "strip-ansi": "^7.0.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^5.1.0", - "ws": "^8.1.0" + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" @@ -45275,6 +49109,10 @@ "engines": { "node": ">= 12.13.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, "peerDependencies": { "webpack": "^4.37.0 || ^5.0.0" }, @@ -45284,38 +49122,176 @@ } } }, - "node_modules/webpack-dev-server/node_modules/ansi-regex": { - "version": "6.0.1", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.11.0", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, - "engines": { - "node": ">=12" + "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": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/webpack-dev-server/node_modules/del": { - "version": "6.0.0", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "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" + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/array-flatten": { + "version": "1.1.1", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/body-parser": { + "version": "1.20.0", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/webpack-dev-server/node_modules/bytes": { + "version": "3.1.2", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webpack-dev-server/node_modules/colorette": { + "version": "2.0.19", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/cookie": { + "version": "0.5.0", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-server/node_modules/depd": { + "version": "2.0.0", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webpack-dev-server/node_modules/destroy": { + "version": "1.2.0", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/webpack-dev-server/node_modules/express": { + "version": "4.18.1", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/finalhandler": { + "version": "1.2.0", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webpack-dev-server/node_modules/http-errors": { + "version": "2.0.0", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" } }, + "node_modules/webpack-dev-server/node_modules/inherits": { + "version": "2.0.4", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, "node_modules/webpack-dev-server/node_modules/is-wsl": { "version": "2.2.0", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", @@ -45327,6 +49303,27 @@ "node": ">=8" } }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/ms": { + "version": "2.1.3", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/on-finished": { + "version": "2.4.1", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/webpack-dev-server/node_modules/open": { "version": "8.2.1", "integrity": "sha512-rXILpcQlkF/QuFez2BJDf3GsqpjGKbkUUToAIGo9A0Q6ZkoSGogZJulrUdwRkrAsoQvoZsrjCYt8+zblOk7JQQ==", @@ -45343,38 +49340,136 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-dev-server/node_modules/slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/webpack-dev-server/node_modules/path-to-regexp": { + "version": "0.1.7", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/qs": { + "version": "6.10.3", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { - "node": ">=8" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/webpack-dev-server/node_modules/strip-ansi": { - "version": "7.0.1", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "node_modules/webpack-dev-server/node_modules/raw-body": { + "version": "2.5.1", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dev": true, "dependencies": { - "ansi-regex": "^6.0.1" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" }, "engines": { - "node": ">=12" + "node": ">= 0.8" + } + }, + "node_modules/webpack-dev-server/node_modules/safe-buffer": { + "version": "5.2.1", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.0.0", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/send": { + "version": "0.18.0", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/webpack-dev-server/node_modules/serve-static": { + "version": "1.15.0", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/webpack-dev-server/node_modules/setprototypeof": { + "version": "1.2.0", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/statuses": { + "version": "2.0.1", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" } }, "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { - "version": "5.1.0", - "integrity": "sha512-oT660AR1gOnU/NTdUQi3EiGR0iXG7CFxmKsj3ylWCBA2khJ8LFHK+sKv3BZEsC11gl1eChsltRhzUq7nWj7XIQ==", + "version": "5.3.3", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", "dev": true, "dependencies": { - "colorette": "^1.2.2", - "memfs": "^3.2.2", + "colorette": "^2.0.10", + "memfs": "^3.4.3", "mime-types": "^2.1.31", "range-parser": "^1.2.1", - "schema-utils": "^3.1.0" + "schema-utils": "^4.0.0" }, "engines": { "node": ">= 12.13.0" @@ -45728,12 +49823,13 @@ } }, "node_modules/webpack/node_modules/terser": { - "version": "5.8.0", - "integrity": "sha512-f0JH+6yMpneYcRJN314lZrSwu9eKkUFEHLN/kNy8ceh8gaRiLgFPJqrB9HsXjhEGdv4e/ekjTOFxIlL6xlma8A==", + "version": "5.14.2", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -45777,14 +49873,6 @@ } } }, - "node_modules/webpack/node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/webpack/node_modules/watchpack": { "version": "2.2.0", "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", @@ -45818,10 +49906,6 @@ "node": ">=0.8.0" } }, - "node_modules/wgs84": { - "version": "0.0.0", - "integrity": "sha512-ANHlY4Rb5kHw40D0NJ6moaVfOCMrp9Gpd1R/AIQYg2ko4/jzcJ+TVXYYF6kXJqQwITvEZP4yEthjM7U6rYlljQ==" - }, "node_modules/whatwg-encoding": { "version": "1.0.5", "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", @@ -45852,6 +49936,7 @@ "node_modules/which": { "version": "1.3.1", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -45877,6 +49962,24 @@ "version": "2.0.0", "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.5", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", @@ -45935,32 +50038,6 @@ "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", "dev": true }, - "node_modules/with-open-file": { - "version": "0.1.7", - "integrity": "sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==", - "dependencies": { - "p-finally": "^1.0.0", - "p-try": "^2.1.0", - "pify": "^4.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/with-open-file/node_modules/p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/with-open-file/node_modules/pify": { - "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "engines": { - "node": ">=6" - } - }, "node_modules/word-wrap": { "version": "1.2.3", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", @@ -46229,6 +50306,14 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, + "node_modules/xregexp": { + "version": "2.0.0", + "integrity": "sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/xss": { "version": "1.0.10", "integrity": "sha512-qmoqrRksmzqSKvgqzN0055UFWY7OKx1/9JWeRswwEVX9fCG5jcYRxa/A2DHcmZX6VJvjzHRQ2STeeVcQkrmLSw==", @@ -46403,519 +50488,36 @@ "yon": "bin/index.js" }, "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/yarn-or-npm/node_modules/find-up": { - "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yarn-or-npm/node_modules/locate-path": { - "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yarn-or-npm/node_modules/p-limit": { - "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yarn-or-npm/node_modules/p-locate": { - "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yarn-or-npm/node_modules/p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yarn-or-npm/node_modules/path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yarn-or-npm/node_modules/pkg-dir": { - "version": "4.2.0", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yeoman-assert": { - "version": "3.1.1", - "integrity": "sha512-bCuLb/j/WzpvrJZCTdJJLFzm7KK8IYQJ3+dF9dYtNs2CUYyezFJDuULiZ2neM4eqjf45GN1KH/MzCTT3i90wUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/yeoman-generator": { - "version": "4.13.0", - "integrity": "sha512-f2/5N5IR3M2Ozm+QocvZQudlQITv2DwI6Mcxfy7R7gTTzaKgvUpgo/pQMJ+WQKm0KN0YMWCFOZpj0xFGxevc1w==", - "dependencies": { - "async": "^2.6.2", - "chalk": "^2.4.2", - "cli-table": "^0.3.1", - "cross-spawn": "^6.0.5", - "dargs": "^6.1.0", - "dateformat": "^3.0.3", - "debug": "^4.1.1", - "diff": "^4.0.1", - "error": "^7.0.2", - "find-up": "^3.0.0", - "github-username": "^3.0.0", - "istextorbinary": "^2.5.1", - "lodash": "^4.17.11", - "make-dir": "^3.0.0", - "mem-fs-editor": "^7.0.1", - "minimist": "^1.2.5", - "pretty-bytes": "^5.2.0", - "read-chunk": "^3.2.0", - "read-pkg-up": "^5.0.0", - "rimraf": "^2.6.3", - "run-async": "^2.0.0", - "semver": "^7.2.1", - "shelljs": "^0.8.4", - "text-table": "^0.2.0", - "through2": "^3.0.1" - }, - "engines": { - "node": ">=10" - }, - "optionalDependencies": { - "grouped-queue": "^1.1.0", - "yeoman-environment": "^2.9.5" - } - }, - "node_modules/yeoman-generator/node_modules/@nodelib/fs.stat": { - "version": "1.1.3", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/yeoman-generator/node_modules/ansi-regex": { - "version": "3.0.0", - "integrity": "sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==", - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/yeoman-generator/node_modules/ansi-styles": { - "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/yeoman-generator/node_modules/arrify": { - "version": "2.0.1", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "engines": { - "node": ">=8" - } - }, - "node_modules/yeoman-generator/node_modules/async": { - "version": "2.6.3", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/yeoman-generator/node_modules/chalk": { - "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/yeoman-generator/node_modules/dargs": { - "version": "6.1.0", - "integrity": "sha512-5dVBvpBLBnPwSsYXqfybFyehMmC/EenKEcf23AhCTgTf48JFBbmJKqoZBsERDnjL0FyiVTYWdFsRfTLHxLyKdQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/yeoman-generator/node_modules/debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/yeoman-generator/node_modules/dir-glob": { - "version": "2.2.2", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "dependencies": { - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/yeoman-generator/node_modules/error": { - "version": "7.2.1", - "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", - "dependencies": { - "string-template": "~0.2.1" - } - }, - "node_modules/yeoman-generator/node_modules/execa": { - "version": "4.1.0", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "optional": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/yeoman-generator/node_modules/execa/node_modules/cross-spawn": { - "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "optional": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/yeoman-generator/node_modules/fast-glob": { - "version": "2.2.7", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "dependencies": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/yeoman-generator/node_modules/find-up": { - "version": "3.0.0", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yeoman-generator/node_modules/get-stream": { - "version": "5.2.0", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "optional": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yeoman-generator/node_modules/glob-parent": { - "version": "3.1.0", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/yeoman-generator/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yeoman-generator/node_modules/globby": { - "version": "9.2.0", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yeoman-generator/node_modules/globby/node_modules/array-union": { - "version": "1.0.2", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yeoman-generator/node_modules/grouped-queue": { - "version": "1.1.0", - "integrity": "sha512-rZOFKfCqLhsu5VqjBjEWiwrYqJR07KxIkH4mLZlNlGDfntbb4FbMyGFP14TlvRPrU9S3Hnn/sgxbC5ZeN0no3Q==", - "optional": true, - "dependencies": { - "lodash": "^4.17.15" - } - }, - "node_modules/yeoman-generator/node_modules/inherits": { - "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/yeoman-generator/node_modules/is-scoped": { - "version": "1.0.0", - "integrity": "sha512-iT1y0qJcdqXnHe6SCtN9cOBPRiarw8Cy1EZkawW50dxO/7oHC6AYvs1tH4QbBbi7UC/vYY3BnRmbE0bFLwvUog==", - "optional": true, - "dependencies": { - "scoped-regex": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/yeoman-generator/node_modules/is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yeoman-generator/node_modules/locate-path": { - "version": "3.0.0", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yeoman-generator/node_modules/log-symbols": { - "version": "2.2.0", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "optional": true, - "dependencies": { - "chalk": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/yeoman-generator/node_modules/lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yeoman-generator/node_modules/make-dir": { - "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yeoman-generator/node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/yeoman-generator/node_modules/mem-fs": { - "version": "1.2.0", - "integrity": "sha512-b8g0jWKdl8pM0LqAPdK9i8ERL7nYrzmJfRhxMiWH2uYdfYnb7uXnmwVb0ZGe7xyEl4lj+nLIU3yf4zPUT+XsVQ==", - "optional": true, - "dependencies": { - "through2": "^3.0.0", - "vinyl": "^2.0.1", - "vinyl-file": "^3.0.0" - } - }, - "node_modules/yeoman-generator/node_modules/mem-fs-editor": { - "version": "7.1.0", - "integrity": "sha512-BH6QEqCXSqGeX48V7zu+e3cMwHU7x640NB8Zk8VNvVZniz+p4FK60pMx/3yfkzo6miI6G3a8pH6z7FeuIzqrzA==", - "dependencies": { - "commondir": "^1.0.1", - "deep-extend": "^0.6.0", - "ejs": "^3.1.5", - "glob": "^7.1.4", - "globby": "^9.2.0", - "isbinaryfile": "^4.0.0", - "mkdirp": "^1.0.0", - "multimatch": "^4.0.0", - "rimraf": "^3.0.0", - "through2": "^3.0.2", - "vinyl": "^2.2.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/yeoman-generator/node_modules/mem-fs-editor/node_modules/rimraf": { - "version": "3.0.2", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/yeoman-generator/node_modules/mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" + "node": ">=8.6.0" } }, - "node_modules/yeoman-generator/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/yeoman-generator/node_modules/multimatch": { - "version": "4.0.0", - "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", + "node_modules/yarn-or-npm/node_modules/find-up": { + "version": "4.1.0", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "dependencies": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/yeoman-generator/node_modules/npm-run-path": { - "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "optional": true, + "node_modules/yarn-or-npm/node_modules/locate-path": { + "version": "5.0.0", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "dependencies": { - "path-key": "^3.0.0" + "p-locate": "^4.1.0" }, "engines": { "node": ">=8" } }, - "node_modules/yeoman-generator/node_modules/p-limit": { + "node_modules/yarn-or-npm/node_modules/p-limit": { "version": "2.3.0", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "dependencies": { "p-try": "^2.0.0" }, @@ -46926,355 +50528,243 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yeoman-generator/node_modules/p-locate": { - "version": "3.0.0", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "node_modules/yarn-or-npm/node_modules/p-locate": { + "version": "4.1.0", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, "dependencies": { - "p-limit": "^2.0.0" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/yeoman-generator/node_modules/p-try": { + "node_modules/yarn-or-npm/node_modules/p-try": { "version": "2.2.0", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, "engines": { "node": ">=6" } }, - "node_modules/yeoman-generator/node_modules/path-key": { - "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "optional": true, + "node_modules/yarn-or-npm/node_modules/path-exists": { + "version": "4.0.0", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, "engines": { "node": ">=8" } }, - "node_modules/yeoman-generator/node_modules/pify": { - "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "engines": { - "node": ">=6" - } - }, - "node_modules/yeoman-generator/node_modules/read-pkg-up": { - "version": "5.0.0", - "integrity": "sha512-XBQjqOBtTzyol2CpsQOw8LHV0XbDZVG7xMMjmXAJomlVY03WOBRmYgDJETlvcg0H63AJvPRwT7GFi5rvOzUOKg==", + "node_modules/yarn-or-npm/node_modules/pkg-dir": { + "version": "4.2.0", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, "dependencies": { - "find-up": "^3.0.0", - "read-pkg": "^5.0.0" + "find-up": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/yeoman-generator/node_modules/rimraf": { - "version": "2.7.1", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "node_modules/yauzl": { + "version": "2.10.0", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } }, - "node_modules/yeoman-generator/node_modules/scoped-regex": { - "version": "1.0.0", - "integrity": "sha512-90/gFvaP4jXL0rXPD8FS7tWgmkQDlxCjs9cs3r3G5hAnrODt94kIh4SDbH/gm3HosGTik0omdSPOh0KQyGqjlg==", - "optional": true, + "node_modules/yeoman-assert": { + "version": "3.1.1", + "integrity": "sha512-bCuLb/j/WzpvrJZCTdJJLFzm7KK8IYQJ3+dF9dYtNs2CUYyezFJDuULiZ2neM4eqjf45GN1KH/MzCTT3i90wUQ==", + "dev": true, "engines": { "node": ">=4" } }, - "node_modules/yeoman-generator/node_modules/semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/yeoman-generator": { + "version": "5.7.0", + "integrity": "sha512-z9ZwgKoDOd+llPDCwn8Ax2l4In5FMhlslxdeByW4AMxhT+HbTExXKEAahsClHSbwZz1i5OzRwLwRIUdOJBr5Bw==", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "chalk": "^4.1.0", + "dargs": "^7.0.0", + "debug": "^4.1.1", + "execa": "^5.1.1", + "github-username": "^6.0.0", + "lodash": "^4.17.11", + "minimist": "^1.2.5", + "read-pkg-up": "^7.0.1", + "run-async": "^2.0.0", + "semver": "^7.2.1", + "shelljs": "^0.8.5", + "sort-keys": "^4.2.0", + "text-table": "^0.2.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/yeoman-generator/node_modules/shebang-command": { - "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "optional": true, - "dependencies": { - "shebang-regex": "^3.0.0" + "node": ">=12.10.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yeoman-generator/node_modules/shebang-regex": { - "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yeoman-generator/node_modules/strip-ansi": { - "version": "4.0.0", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "optional": true, - "dependencies": { - "ansi-regex": "^3.0.0" + "peerDependencies": { + "yeoman-environment": "^3.2.0" }, - "engines": { - "node": ">=4" + "peerDependenciesMeta": { + "yeoman-environment": { + "optional": true + } } }, - "node_modules/yeoman-generator/node_modules/supports-color": { - "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/yeoman-generator/node_modules/cross-spawn": { + "version": "7.0.3", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dependencies": { - "has-flag": "^3.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=4" - } - }, - "node_modules/yeoman-generator/node_modules/through2": { - "version": "3.0.2", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, - "node_modules/yeoman-generator/node_modules/untildify": { - "version": "3.0.3", - "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", - "optional": true, - "engines": { - "node": ">=4" + "node": ">= 8" } }, - "node_modules/yeoman-generator/node_modules/which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "optional": true, + "node_modules/yeoman-generator/node_modules/debug": { + "version": "4.3.2", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "ms": "2.1.2" }, "engines": { - "node": ">= 8" - } - }, - "node_modules/yeoman-generator/node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yeoman-generator/node_modules/yeoman-environment": { - "version": "2.10.3", - "integrity": "sha512-pLIhhU9z/G+kjOXmJ2bPFm3nejfbH+f1fjYRSOteEXDBrv1EoJE/e+kuHixSXfCYfTkxjYsvRaDX+1QykLCnpQ==", - "optional": true, - "dependencies": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "diff": "^3.5.0", - "escape-string-regexp": "^1.0.2", - "execa": "^4.0.0", - "globby": "^8.0.1", - "grouped-queue": "^1.1.0", - "inquirer": "^7.1.0", - "is-scoped": "^1.0.0", - "lodash": "^4.17.10", - "log-symbols": "^2.2.0", - "mem-fs": "^1.1.0", - "mem-fs-editor": "^6.0.0", - "npm-api": "^1.0.0", - "semver": "^7.1.3", - "strip-ansi": "^4.0.0", - "text-table": "^0.2.0", - "untildify": "^3.0.3", - "yeoman-generator": "^4.8.2" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/array-union": { - "version": "1.0.2", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", - "optional": true, + "node_modules/yeoman-generator/node_modules/execa": { + "version": "5.1.1", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dependencies": { - "array-uniq": "^1.0.1" + "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": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/arrify": { - "version": "1.0.1", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "optional": true, + "node_modules/yeoman-generator/node_modules/get-stream": { + "version": "6.0.1", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/debug": { - "version": "3.2.7", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "optional": true, - "dependencies": { - "ms": "^2.1.1" + "node_modules/yeoman-generator/node_modules/human-signals": { + "version": "2.1.0", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/diff": { - "version": "3.5.0", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "optional": true, + "node_modules/yeoman-generator/node_modules/is-stream": { + "version": "2.0.1", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "engines": { - "node": ">=0.3.1" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/dir-glob": { - "version": "2.0.0", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", - "optional": true, + "node_modules/yeoman-generator/node_modules/lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dependencies": { - "arrify": "^1.0.1", - "path-type": "^3.0.0" + "yallist": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/ejs": { - "version": "2.7.4", - "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", - "hasInstallScript": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/yeoman-generator/node_modules/ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/globby": { - "version": "8.0.2", - "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", - "optional": true, + "node_modules/yeoman-generator/node_modules/npm-run-path": { + "version": "4.0.1", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dependencies": { - "array-union": "^1.0.1", - "dir-glob": "2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" + "path-key": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/ignore": { - "version": "3.3.10", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "optional": true - }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/mem-fs-editor": { - "version": "6.0.0", - "integrity": "sha512-e0WfJAMm8Gv1mP5fEq/Blzy6Lt1VbLg7gNnZmZak7nhrBTibs+c6nQ4SKs/ZyJYHS1mFgDJeopsLAv7Ow0FMFg==", - "optional": true, - "dependencies": { - "commondir": "^1.0.1", - "deep-extend": "^0.6.0", - "ejs": "^2.6.1", - "glob": "^7.1.4", - "globby": "^9.2.0", - "isbinaryfile": "^4.0.0", - "mkdirp": "^0.5.0", - "multimatch": "^4.0.0", - "rimraf": "^2.6.3", - "through2": "^3.0.1", - "vinyl": "^2.2.0" + "node_modules/yeoman-generator/node_modules/path-key": { + "version": "3.1.1", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/mem-fs-editor/node_modules/dir-glob": { - "version": "2.2.2", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "optional": true, + "node_modules/yeoman-generator/node_modules/semver": { + "version": "7.3.7", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { - "path-type": "^3.0.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/mem-fs-editor/node_modules/globby": { - "version": "9.2.0", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "optional": true, + "node_modules/yeoman-generator/node_modules/shebang-command": { + "version": "2.0.0", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/mem-fs-editor/node_modules/ignore": { - "version": "4.0.6", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "optional": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/mem-fs-editor/node_modules/pify": { - "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "optional": true, - "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/mem-fs-editor/node_modules/slash": { - "version": "2.0.0", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "optional": true, + "node_modules/yeoman-generator/node_modules/shebang-regex": { + "version": "3.0.0", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/mkdirp": { - "version": "0.5.5", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "optional": true, + "node_modules/yeoman-generator/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dependencies": { - "minimist": "^1.2.5" + "isexe": "^2.0.0" }, "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/pify": { - "version": "3.0.0", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "optional": true, + "node-which": "bin/node-which" + }, "engines": { - "node": ">=4" + "node": ">= 8" } }, - "node_modules/yeoman-generator/node_modules/yeoman-environment/node_modules/slash": { - "version": "1.0.0", - "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/yeoman-generator/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yeoman-test": { "version": "6.2.0", @@ -47296,54 +50786,6 @@ "yeoman-generator": "*" } }, - "node_modules/yeoman-test/node_modules/ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yeoman-test/node_modules/inquirer": { - "version": "8.2.0", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.2.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/yeoman-test/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yeoman-test/node_modules/rxjs": { - "version": "7.4.0", - "integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==", - "dev": true, - "dependencies": { - "tslib": "~2.1.0" - } - }, "node_modules/yeoman-test/node_modules/sinon": { "version": "10.0.0", "integrity": "sha512-XAn5DxtGVJBlBWYrcYKEhWCz7FLwZGdyvANRyK06419hyEpdT0dMc5A8Vcxg5SCGHc40CsqoKsc1bt1CbJPfNw==", @@ -47361,30 +50803,6 @@ "url": "https://opencollective.com/sinon" } }, - "node_modules/yeoman-test/node_modules/string-width": { - "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yeoman-test/node_modules/strip-ansi": { - "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/yeoman-test/node_modules/temp-dir": { "version": "2.0.0", "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", @@ -47393,11 +50811,6 @@ "node": ">=8" } }, - "node_modules/yeoman-test/node_modules/tslib": { - "version": "2.1.0", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", - "dev": true - }, "node_modules/yocto-queue": { "version": "0.1.0", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", @@ -47508,8 +50921,8 @@ } }, "node_modules/zrender": { - "version": "5.3.1", - "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==", + "version": "5.4.1", + "integrity": "sha512-M4Z05BHWtajY2241EmMPHglDQAJ1UyHQcYsxDNzD9XLSkPDqMq4bB28v9Pb4mvHnVQ0GxyTklZ/69xCFP6RXBA==", "dependencies": { "tslib": "2.3.0" } @@ -47533,7 +50946,7 @@ "dependencies": { "chalk": "^4.0.0", "lodash": "^4.17.11", - "yeoman-generator": "^4.0.0", + "yeoman-generator": "^5.7.0", "yosay": "^2.0.2" }, "devDependencies": { @@ -47566,11 +50979,11 @@ "@testing-library/react-hooks": "^5.0.3", "@testing-library/user-event": "^12.7.0", "ace-builds": "^1.4.14", - "antd": "^4.9.4", + "antd": "4.10.3", "brace": "^0.11.1", "memoize-one": "^5.1.1", "react": "^16.13.1", - "react-ace": "^9.4.4", + "react-ace": "^10.1.0", "react-dom": "^16.13.1" } }, @@ -47587,6 +51000,7 @@ "@types/d3-time-format": "^2.1.0", "@types/enzyme": "^3.10.5", "@types/fetch-mock": "^7.3.3", + "@types/json-bigint": "^1.0.1", "@types/lodash": "^4.14.149", "@types/math-expression-evaluator": "^1.2.1", "@types/node": "^18.0.0", @@ -47636,20 +51050,6 @@ "version": "3.0.0", "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==" }, - "packages/superset-ui-core/node_modules/@vx/responsive": { - "version": "0.0.199", - "integrity": "sha512-ONrmLUAG+8wzD3cn/EmsuZh6JHeyejqup3ZsV25t04VaVJAVQAJukAfNdH8YiwSJu0zSo+txkBTfrnOmFyQLOw==", - "dependencies": { - "@types/lodash": "^4.14.146", - "@types/react": "*", - "lodash": "^4.17.10", - "prop-types": "^15.6.1", - "resize-observer-polyfill": "1.5.1" - }, - "peerDependencies": { - "react": "^15.0.0-0 || ^16.0.0-0" - } - }, "packages/superset-ui-core/node_modules/d3-array": { "version": "2.12.1", "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", @@ -47713,7 +51113,7 @@ "@storybook/addons": "^6.3.12", "@storybook/react": "^6.3.12", "@types/react-loadable": "^5.5.3", - "antd": "^4.9.4", + "antd": "4.10.3", "bootstrap": "^3.4.1", "core-js": "3.8.3", "gh-pages": "^3.0.0", @@ -47764,6 +51164,14 @@ "@superset-ui/preset-chart-xy": "*" } }, + "packages/superset-ui-demo/node_modules/ansi-regex": { + "version": "5.0.1", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "packages/superset-ui-demo/node_modules/ansi-styles": { "version": "3.2.1", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", @@ -47786,6 +51194,81 @@ "node": ">=8" } }, + "packages/superset-ui-demo/node_modules/chromatic": { + "version": "5.10.2", + "integrity": "sha512-JHFtZ16VanQX0X9qjacIJOrH9rVUJACilPs8dBwwQgJTZzgCZAdwgmE+WwLcxe/LuK7vM56BDTHbxC+XcnTsjw==", + "dev": true, + "dependencies": { + "@actions/core": "^1.5.0", + "@actions/github": "^5.0.0", + "@babel/preset-typescript": "^7.15.0", + "@babel/runtime": "^7.15.3", + "@chromaui/localtunnel": "^2.0.3", + "async-retry": "^1.3.3", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "dotenv": "^8.2.0", + "env-ci": "^5.0.2", + "esm": "^3.2.25", + "execa": "^5.0.0", + "fake-tag": "^2.0.0", + "fs-extra": "^10.0.0", + "https-proxy-agent": "^5.0.0", + "jsonfile": "^6.0.1", + "junit-report-builder": "2.1.0", + "listr": "0.14.3", + "meow": "^8.0.0", + "no-proxy": "^1.0.3", + "node-ask": "^1.0.1", + "node-fetch": "2.6.0", + "node-loggly-bulk": "^2.2.4", + "p-limit": "3.1.0", + "picomatch": "2.2.2", + "pkg-up": "^3.1.0", + "pluralize": "^8.0.0", + "progress-stream": "^2.0.0", + "semver": "^7.3.5", + "slash": "^3.0.0", + "string-argv": "^0.3.1", + "strip-ansi": "6.0.0", + "tmp-promise": "3.0.2", + "tree-kill": "^1.2.2", + "ts-dedent": "^1.0.0", + "util-deprecate": "^1.0.2", + "uuid": "^8.3.2", + "yarn-or-npm": "^3.0.1" + }, + "bin": { + "chroma": "bin/register.js", + "chromatic": "bin/register.js", + "chromatic-cli": "bin/register.js" + } + }, + "packages/superset-ui-demo/node_modules/chromatic/node_modules/fs-extra": { + "version": "10.1.0", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "packages/superset-ui-demo/node_modules/chromatic/node_modules/picomatch": { + "version": "2.2.2", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "packages/superset-ui-demo/node_modules/core-js": { "version": "3.8.3", "integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q==", @@ -47811,6 +51294,35 @@ "node": ">=8" } }, + "packages/superset-ui-demo/node_modules/cross-spawn": { + "version": "7.0.3", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/superset-ui-demo/node_modules/debug": { + "version": "4.3.4", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "packages/superset-ui-demo/node_modules/deepmerge": { "version": "4.2.2", "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", @@ -47819,6 +51331,28 @@ "node": ">=0.10.0" } }, + "packages/superset-ui-demo/node_modules/execa": { + "version": "5.1.1", + "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" + } + }, "packages/superset-ui-demo/node_modules/fill-range": { "version": "7.0.1", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", @@ -47830,6 +51364,17 @@ "node": ">=8" } }, + "packages/superset-ui-demo/node_modules/find-up": { + "version": "3.0.0", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "packages/superset-ui-demo/node_modules/fork-ts-checker-webpack-plugin": { "version": "5.2.1", "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", @@ -47866,6 +51411,25 @@ "node": ">=10" } }, + "packages/superset-ui-demo/node_modules/get-stream": { + "version": "6.0.1", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/superset-ui-demo/node_modules/human-signals": { + "version": "2.1.0", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, "packages/superset-ui-demo/node_modules/is-number": { "version": "7.0.0", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", @@ -47874,6 +51438,29 @@ "node": ">=0.12.0" } }, + "packages/superset-ui-demo/node_modules/is-stream": { + "version": "2.0.1", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/superset-ui-demo/node_modules/locate-path": { + "version": "3.0.0", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "packages/superset-ui-demo/node_modules/lru-cache": { "version": "6.0.0", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", @@ -47897,6 +51484,77 @@ "node": ">=8.6" } }, + "packages/superset-ui-demo/node_modules/ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "packages/superset-ui-demo/node_modules/node-fetch": { + "version": "2.6.0", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", + "dev": true, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "packages/superset-ui-demo/node_modules/npm-run-path": { + "version": "4.0.1", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/superset-ui-demo/node_modules/p-limit": { + "version": "3.1.0", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/superset-ui-demo/node_modules/p-locate": { + "version": "3.0.0", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "packages/superset-ui-demo/node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/superset-ui-demo/node_modules/p-try": { + "version": "2.2.0", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "packages/superset-ui-demo/node_modules/parse-json": { "version": "5.2.0", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", @@ -47914,6 +51572,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/superset-ui-demo/node_modules/path-key": { + "version": "3.1.1", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "packages/superset-ui-demo/node_modules/path-type": { "version": "4.0.0", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", @@ -47922,6 +51588,17 @@ "node": ">=8" } }, + "packages/superset-ui-demo/node_modules/pkg-up": { + "version": "3.1.0", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "packages/superset-ui-demo/node_modules/schema-utils": { "version": "2.7.0", "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", @@ -47953,6 +51630,44 @@ "node": ">=10" } }, + "packages/superset-ui-demo/node_modules/shebang-command": { + "version": "2.0.0", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/superset-ui-demo/node_modules/shebang-regex": { + "version": "3.0.0", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "packages/superset-ui-demo/node_modules/slash": { + "version": "3.0.0", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "packages/superset-ui-demo/node_modules/strip-ansi": { + "version": "6.0.0", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, "packages/superset-ui-demo/node_modules/supports-color": { "version": "5.5.0", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", @@ -47975,6 +51690,14 @@ "node": ">=8.0" } }, + "packages/superset-ui-demo/node_modules/ts-dedent": { + "version": "1.2.0", + "integrity": "sha512-6zSJp23uQI+Txyz5LlXMXAHpUhY4Hi0oluXny0OgIR7g/Cromq4vDBnhtbBdyIV34g0pgwxUvnvg+jLJe4c1NA==", + "dev": true, + "engines": { + "node": ">=6.10" + } + }, "packages/superset-ui-demo/node_modules/ts-loader": { "version": "7.0.5", "integrity": "sha512-zXypEIT6k3oTc+OZNx/cqElrsbBtYqDknf48OZos0NQ3RTt045fBIU8RRSu+suObBzYB355aIPGOe/3kj9h7Ig==", @@ -48014,6 +51737,28 @@ "semver": "bin/semver.js" } }, + "packages/superset-ui-demo/node_modules/uuid": { + "version": "8.3.2", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "packages/superset-ui-demo/node_modules/which": { + "version": "2.0.2", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "packages/superset-ui-demo/node_modules/yallist": { "version": "4.0.0", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", @@ -48021,7 +51766,7 @@ }, "packages/superset-ui-switchboard": { "name": "@superset-ui/switchboard", - "version": "0.18.26-0", + "version": "0.18.26-1", "license": "Apache-2.0" }, "plugins/legacy-plugin-chart-calendar": { @@ -48161,20 +51906,6 @@ "react": "^16.3.0-0" } }, - "plugins/legacy-plugin-chart-histogram/node_modules/@vx/responsive": { - "version": "0.0.199", - "integrity": "sha512-ONrmLUAG+8wzD3cn/EmsuZh6JHeyejqup3ZsV25t04VaVJAVQAJukAfNdH8YiwSJu0zSo+txkBTfrnOmFyQLOw==", - "dependencies": { - "@types/lodash": "^4.14.146", - "@types/react": "*", - "lodash": "^4.17.10", - "prop-types": "^15.6.1", - "resize-observer-polyfill": "1.5.1" - }, - "peerDependencies": { - "react": "^15.0.0-0 || ^16.0.0-0" - } - }, "plugins/legacy-plugin-chart-histogram/node_modules/@vx/scale": { "version": "0.0.197", "integrity": "sha512-FF0POm9rh66I3Om5DsuxynwWU+Q645aTF47vgP2dVDeOOq3Oet7CZzmXLDh3W6nVcxvzq1UdPwu94dto2PUfhg==", @@ -48229,7 +51960,7 @@ "license": "Apache-2.0", "dependencies": { "prop-types": "^15.6.2", - "react-map-gl": "^4.0.10", + "react-map-gl": "^6.1.19", "supercluster": "^4.1.1", "viewport-mercator-project": "^6.1.1" }, @@ -48417,7 +52148,7 @@ "mousetrap": "^1.6.1", "prop-types": "^15.6.0", "react-bootstrap-slider": "2.1.5", - "underscore": "^1.8.3", + "underscore": "^1.12.1", "urijs": "^1.19.8", "xss": "^1.0.10" }, @@ -48427,7 +52158,7 @@ "mapbox-gl": "*", "react": "^16.13.1", "react-dom": "^16.13.1", - "react-map-gl": "^4.0.10" + "react-map-gl": "^6.1.19" } }, "plugins/legacy-preset-chart-deckgl/node_modules/d3-scale": { @@ -48490,7 +52221,7 @@ "license": "Apache-2.0", "dependencies": { "d3-array": "^1.2.0", - "echarts": "^5.3.2", + "echarts": "^5.4.1", "lodash": "^4.17.15", "moment": "^2.26.0" }, @@ -48502,10 +52233,11 @@ }, "plugins/plugin-chart-handlebars": { "name": "@superset-ui/plugin-chart-handlebars", - "version": "0.0.0", + "version": "0.18.25", "license": "Apache-2.0", "dependencies": { - "handlebars": "^4.7.7" + "handlebars": "^4.7.7", + "just-handlebars-helpers": "^1.0.19" }, "devDependencies": { "@types/jest": "^26.0.0", @@ -48519,10 +52251,20 @@ "lodash": "^4.17.11", "moment": "^2.26.0", "react": "^16.13.1", - "react-ace": "^9.4.4", + "react-ace": "^10.1.0", "react-dom": "^16.13.1" } }, + "plugins/plugin-chart-handlebars/node_modules/just-handlebars-helpers": { + "version": "1.0.19", + "integrity": "sha512-E+0eUn5xKfBAoU6mF3QbGZ939PZDw7RYI6AMTpRQtesRH2lZXjXaOqHzJ2nbHnDVmxNQM453sXFnMpd/uaLkKg==", + "peerDependencies": { + "currencyformatter.js": ">= 1.0.4 < 2", + "handlebars": ">= 3.*", + "moment": ">= 2.22.0 < 3", + "sprintf-js": ">= 1.1.1 < 2" + } + }, "plugins/plugin-chart-pivot-table": { "name": "@superset-ui/plugin-chart-pivot-table", "version": "0.18.25", @@ -48536,6 +52278,7 @@ "@ant-design/icons": "^4.2.2", "@superset-ui/chart-controls": "*", "@superset-ui/core": "*", + "lodash": "^4.17.11", "prop-types": "*", "react": "^16.13.1", "react-dom": "^16.13.1" @@ -48550,6 +52293,7 @@ "@types/d3-array": "^2.9.0", "@types/enzyme": "^3.10.5", "@types/react-table": "^7.0.29", + "classnames": "^2.3.2", "d3-array": "^2.4.0", "match-sorter": "^6.3.0", "memoize-one": "^5.1.1", @@ -48557,9 +52301,13 @@ "regenerator-runtime": "^0.13.7", "xss": "^1.0.10" }, + "devDependencies": { + "@testing-library/react": "^11.2.0" + }, "peerDependencies": { "@superset-ui/chart-controls": "*", "@superset-ui/core": "*", + "@types/classnames": "*", "@types/react": "*", "react": "^16.13.1", "react-dom": "^16.13.1" @@ -48586,6 +52334,7 @@ "peerDependencies": { "@superset-ui/chart-controls": "*", "@superset-ui/core": "*", + "@types/lodash": "*", "@types/react": "*", "react": "^16.13.1" } @@ -48752,36 +52501,38 @@ }, "dependencies": { "@actions/core": { - "version": "1.6.0", - "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", + "version": "1.9.1", "dev": true, "requires": { - "@actions/http-client": "^1.0.11" + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "dev": true + } } }, "@actions/github": { - "version": "5.0.0", - "integrity": "sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ==", + "version": "5.0.3", "dev": true, "requires": { - "@actions/http-client": "^1.0.11", - "@octokit/core": "^3.4.0", - "@octokit/plugin-paginate-rest": "^2.13.3", - "@octokit/plugin-rest-endpoint-methods": "^5.1.1" + "@actions/http-client": "^2.0.1", + "@octokit/core": "^3.6.0", + "@octokit/plugin-paginate-rest": "^2.17.0", + "@octokit/plugin-rest-endpoint-methods": "^5.13.0" } }, "@actions/http-client": { - "version": "1.0.11", - "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", + "version": "2.0.1", "dev": true, "requires": { - "tunnel": "0.0.6" + "tunnel": "^0.0.6" } }, "@ag-grid-community/all-modules": { "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@ag-grid-community/all-modules/-/all-modules-26.2.1.tgz", - "integrity": "sha512-zO8PFBSiChQEmJLmWe/gaKhDOPvOR+4yWlTmfIBTWZ/j/zhJSeCNHor6WQGakgfONrNOq0P6yQjVu0d7JFi7mA==", "dev": true, "requires": { "@ag-grid-community/client-side-row-model": "~26.2.0", @@ -48792,8 +52543,6 @@ }, "@ag-grid-community/client-side-row-model": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-community/client-side-row-model/-/client-side-row-model-26.2.0.tgz", - "integrity": "sha512-kW5lMsK5WEXaqZMfHbLRj+EvxLhPW6qtDv61PyDcv+/91lwm2p5dT/iUBppavSwJDiNul+wntpyIlTulZgokwA==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0" @@ -48801,14 +52550,10 @@ }, "@ag-grid-community/core": { "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@ag-grid-community/core/-/core-26.2.1.tgz", - "integrity": "sha512-E2e3rZoZ90QtgO320kmlrm7kFbzFkCyrvCWYUQshJJU/UzCqr6DffVAXTaeehPNLzHBybANxWbSbFab9LQLIwQ==", "dev": true }, "@ag-grid-community/csv-export": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-community/csv-export/-/csv-export-26.2.0.tgz", - "integrity": "sha512-2QqzmYIqqXpPwvIiIpWXV9VWKVK5mLdZI3RVnZdgWGCyTD0OAqWPgqY5LapVpyxGfE/oUm7s9O7ux7EFiTdEcA==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0" @@ -48816,8 +52561,6 @@ }, "@ag-grid-community/infinite-row-model": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-community/infinite-row-model/-/infinite-row-model-26.2.0.tgz", - "integrity": "sha512-wA4qSYD/XdvrjVQ6gdENaX++QlQufndWJonl7oVCPzxw7fO3H1i8DFpfr2fe/BXwrcDM1LeJ5HM6jzIuKIrddg==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0" @@ -48825,8 +52568,6 @@ }, "@ag-grid-community/react": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-community/react/-/react-26.2.0.tgz", - "integrity": "sha512-IWNSuyoiRkIbRpoz+Nvagyz8MsoQbTVQ25ixj75VNAyShK/xWus92FMQQFFQBR11Pb3paZeEttrmF0D8WEFLTQ==", "dev": true, "requires": { "prop-types": "^15.6.2" @@ -48834,8 +52575,6 @@ }, "@ag-grid-enterprise/all-modules": { "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/all-modules/-/all-modules-26.2.1.tgz", - "integrity": "sha512-UhpdeQwgYQqYtCv7Mm5qncsnbwqDohZGjTtCBcbq5tQ5NkURgmoiJbVAQzF0myK5K2BxxOejVytONj18uCSSrg==", "dev": true, "requires": { "@ag-grid-community/all-modules": "~26.2.0", @@ -48861,8 +52600,6 @@ }, "@ag-grid-enterprise/charts": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/charts/-/charts-26.2.0.tgz", - "integrity": "sha512-Y3G2PzyjypR5o1c+1A1VEhTxEvhIvyYWMMTn2KexGtTOBhDqZPB1LyAS8+L7RBhRdtvydXnj3IQBPdQFmhK4Fw==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48873,8 +52610,6 @@ }, "@ag-grid-enterprise/clipboard": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/clipboard/-/clipboard-26.2.0.tgz", - "integrity": "sha512-24y+IgJrNz6f3WIWxBHzyP32rW932YMagiX0MbJqRfepu32N71DGlXqjuGawXDRLYTbgpQ1196X2otqTQkJK5Q==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48884,8 +52619,6 @@ }, "@ag-grid-enterprise/column-tool-panel": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/column-tool-panel/-/column-tool-panel-26.2.0.tgz", - "integrity": "sha512-jdYT5cpgkoah0P0Bz3uiiqgakcj9EKS074r5pdMNZc944enFzD+vcYI0qnH/3Ugm1cBgYVB41UeIxBdubfGUYw==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48896,8 +52629,6 @@ }, "@ag-grid-enterprise/core": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/core/-/core-26.2.0.tgz", - "integrity": "sha512-meYGtrgkEG/OvR02Z5ndSXV85ZbD2hxoUQ84rZx6/lr/U1QOmEIhzWJS3c1iqkzQrWWlDxk8JA7aHv1F+w4ysQ==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0" @@ -48905,8 +52636,6 @@ }, "@ag-grid-enterprise/excel-export": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/excel-export/-/excel-export-26.2.0.tgz", - "integrity": "sha512-UVIau2DSh0H3gp3yzQUIdsIOrx2peDUXx9/Av69WH5H5qOb6C0c3oUAqQ80HUUy6rdWrW1nwVXGkKF4meJFupg==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48916,8 +52645,6 @@ }, "@ag-grid-enterprise/filter-tool-panel": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/filter-tool-panel/-/filter-tool-panel-26.2.0.tgz", - "integrity": "sha512-1xONvJdoXeA1Hgmkt/evvHiAdjrvRNswLW3cLIdUifGSZOQ/vpQRleUsa0BEsYemrP0VU5ouIDrdypz42w2egA==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48927,8 +52654,6 @@ }, "@ag-grid-enterprise/master-detail": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/master-detail/-/master-detail-26.2.0.tgz", - "integrity": "sha512-nTOJ92IGXY/hK693JHO2wvFUjLxkg8fjcH6augp99LaVI5tyA9i/WSjfuiPdiCRY3nYnwiRm1i9vtHbFDs3aRw==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48937,8 +52662,6 @@ }, "@ag-grid-enterprise/menu": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/menu/-/menu-26.2.0.tgz", - "integrity": "sha512-EVBzLtRQe/kfW7l6DyRmFVbo10/yxf72X0h+afGVVp5VMjM5sTdSyvGvScRlzEGQXvptknnqjVNk6WfY9KbSNg==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48948,8 +52671,6 @@ }, "@ag-grid-enterprise/multi-filter": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/multi-filter/-/multi-filter-26.2.0.tgz", - "integrity": "sha512-CH5bS0MktZhFifbGgOVicXXWOELeZ6cRDLFpZj9smznB7Ct24Ni8/ormTyBbQP7xhmlVOPe/mE9h3YC1HH18pw==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48959,8 +52680,6 @@ }, "@ag-grid-enterprise/range-selection": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/range-selection/-/range-selection-26.2.0.tgz", - "integrity": "sha512-AUQsWsPH9F2PEbcUMbAldcCZQf4k2L8AU45bPKANph9dCH1/JFb7qlQAHxroOzkpvjTqyT6PjaD8vYm8Cfdvvg==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48969,8 +52688,6 @@ }, "@ag-grid-enterprise/rich-select": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/rich-select/-/rich-select-26.2.0.tgz", - "integrity": "sha512-qVOHIzElUJowehZylUBO2zyNFd+3DN5m3o29WFgEM6hDsflJqdnAR/BkUYinYIi5kLXt+t00O9N2HB5XkMd+bQ==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48979,8 +52696,6 @@ }, "@ag-grid-enterprise/row-grouping": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/row-grouping/-/row-grouping-26.2.0.tgz", - "integrity": "sha512-uZF65ZzXGWEfNUjQYD0SPUW1aIS6etKN7SD5wmoM6PFIVFEZNiUpQCC9nO3Jz+rSyQ+VQ89SFJCiXvoeH9F3MA==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48989,8 +52704,6 @@ }, "@ag-grid-enterprise/server-side-row-model": { "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/server-side-row-model/-/server-side-row-model-26.2.1.tgz", - "integrity": "sha512-0WielbIJ8mm4tcTbDWqvVnc+E+s4IHLEy7dzgC7xhCDJR4LUJenT6xoBKThID5arXmitsgB7C574wXP0/IEdpQ==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -48999,8 +52712,6 @@ }, "@ag-grid-enterprise/set-filter": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/set-filter/-/set-filter-26.2.0.tgz", - "integrity": "sha512-YbqwhnnaI3J72NrJOS9dzrMDnc6O2NAEUeoybU/abbjqjYGrSXkE3SuYPP7tfMic7p6Y4/yCYqFLxo98UmiLfQ==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -49009,8 +52720,6 @@ }, "@ag-grid-enterprise/side-bar": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/side-bar/-/side-bar-26.2.0.tgz", - "integrity": "sha512-OzxBDazfyXqMSlttwsi5PfSas4YCIfB5xqrtzT7nKn/231mZJTIDuywIPddrWzY3ml6F0fntLl4CQtBlIIkEMA==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -49019,8 +52728,6 @@ }, "@ag-grid-enterprise/sparklines": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/sparklines/-/sparklines-26.2.0.tgz", - "integrity": "sha512-nbgxvpFDk2cldFikozmfw+ThRxTzH1jN6Tem2uxRRRz2QVvF8zmYAxT/reQHOUq5r8K3MAnjV6Lrf84mcWTwSg==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -49029,8 +52736,6 @@ }, "@ag-grid-enterprise/status-bar": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/status-bar/-/status-bar-26.2.0.tgz", - "integrity": "sha512-UTpZaDMdb+uVZSxKOvRQk9TWXwbMNWX5brTpDkdqrJiVtQToN9SLbenee9CEvXHm9I8OAo0Zb9ulbfBaBAUbNQ==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", @@ -49039,51 +52744,86 @@ }, "@ag-grid-enterprise/viewport-row-model": { "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@ag-grid-enterprise/viewport-row-model/-/viewport-row-model-26.2.0.tgz", - "integrity": "sha512-9uyZc7Cc9a+4bW7Jzkbcv4QIGHD2m6BPReaTkL6MJS3TyXLewsQGKSnbpi3jL3Ca8XCJo2rZe14lRN981KaaZg==", "dev": true, "requires": { "@ag-grid-community/core": "~26.2.0", "@ag-grid-enterprise/core": "~26.2.0" } }, + "@ampproject/remapping": { + "version": "2.2.0", + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@ant-design/colors": { - "version": "3.2.2", - "integrity": "sha512-YKgNbG2dlzqMhA9NtI3/pbY16m3Yl/EeWBRa+lB1X1YaYxHrxNexiQYCLTWO/uDvAjLFMEDU+zR901waBtMtjQ==", + "version": "6.0.0", "requires": { - "tinycolor2": "^1.4.1" + "@ctrl/tinycolor": "^3.4.0" } }, "@ant-design/icons": { - "version": "4.2.2", - "integrity": "sha512-DrVV+wcupnHS7PehJ6KiTcJtAR5c25UMgjGECCc6pUT9rsvw0AuYG+a4HDjfxEQuDqKTHwW+oX/nIvCymyLE8Q==", + "version": "4.8.0", "requires": { - "@ant-design/colors": "^3.1.0", - "@ant-design/icons-svg": "^4.0.0", - "@babel/runtime": "^7.10.4", + "@ant-design/colors": "^6.0.0", + "@ant-design/icons-svg": "^4.2.1", + "@babel/runtime": "^7.11.2", "classnames": "^2.2.6", - "insert-css": "^2.0.0", - "rc-util": "^5.0.1" + "rc-util": "^5.9.4" } }, "@ant-design/icons-svg": { - "version": "4.1.0", - "integrity": "sha512-Fi03PfuUqRs76aI3UWYpP864lkrfPo0hluwGqh7NJdLhvH4iRDc3jbJqZIvRDLHKbXrvAfPPV3+zjUccfFvWOQ==" + "version": "4.2.1" }, - "@ant-design/react-slick": { - "version": "0.27.14", - "integrity": "sha512-s6JVexqFmU5rs5Pm828ojtm5rCp8jDXyrc5OxEtCE2z58SIyQlkpnU9BJh98LEeBZyj02WFkGN8CWpSaD+G4PA==", + "@applitools/core": { + "version": "1.3.7", + "dev": true, "requires": { - "@babel/runtime": "^7.10.4", - "classnames": "^2.2.5", - "json2mq": "^0.2.0", - "lodash": "^4.17.15", - "resize-observer-polyfill": "^1.5.0" + "@applitools/core-base": "1.1.24", + "@applitools/dom-capture": "11.2.0", + "@applitools/dom-snapshot": "4.7.3", + "@applitools/driver": "1.11.21", + "@applitools/logger": "1.1.36", + "@applitools/nml-client": "1.3.22", + "@applitools/req": "1.1.23", + "@applitools/screenshoter": "3.7.20", + "@applitools/snippets": "2.4.12", + "@applitools/ufg-client": "1.1.12", + "@applitools/utils": "1.3.22", + "abort-controller": "3.0.0", + "chalk": "4.1.2", + "node-fetch": "2.6.7", + "throat": "6.0.1" + }, + "dependencies": { + "throat": { + "version": "6.0.1", + "dev": true + } + } + }, + "@applitools/core-base": { + "version": "1.1.24", + "dev": true, + "requires": { + "@applitools/image": "1.0.17", + "@applitools/logger": "1.1.36", + "@applitools/req": "1.1.23", + "@applitools/utils": "1.3.22" } }, "@applitools/dom-capture": { - "version": "11.1.0", - "integrity": "sha512-99NdLnHuoTT0EBDMixp19QLAZV704ztQjJfcvJZNmi5FnFzsnVpgTwRhgH5SA1JobQ09yMS9wvy0ekrpdX8lIw==", + "version": "11.2.0", "dev": true, "requires": { "@applitools/dom-shared": "1.0.5", @@ -49092,159 +52832,83 @@ }, "@applitools/dom-shared": { "version": "1.0.5", - "integrity": "sha512-O2zgnnqVi3/Atq7EQjURLa73XNaDFJCj8wHht6WQtxIv1EWYnPutNTmnJSKwK7FnbJAg65OVjZylcz4EezyYZA==", "dev": true }, "@applitools/dom-snapshot": { - "version": "4.5.12", - "integrity": "sha512-YeuAOQ0+AB7HCMPAHqpnOq5xCOXfIyC/2/h3XurOuzE+qFekK9SPMBRaJn4jDYyAFK/Eeu4v7CGW+LPAUGiZfA==", + "version": "4.7.3", "dev": true, "requires": { - "@applitools/dom-shared": "1.0.8", + "@applitools/dom-shared": "1.0.9", "@applitools/functional-commons": "1.6.0", - "css-tree": "1.0.0-alpha.39", + "css-tree": "2.3.1", "pako": "1.0.11" }, "dependencies": { "@applitools/dom-shared": { - "version": "1.0.8", - "integrity": "sha512-HQtYfFvtlPuE9ZShBamtW1LGW2Qq4HxjQx5nF7KiNvrRTlf5/e+AWpZhXCTVEhVkAcSNs/7xR2WvumOUd+usxg==", + "version": "1.0.9", "dev": true }, "css-tree": { - "version": "1.0.0-alpha.39", - "integrity": "sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA==", + "version": "2.3.1", "dev": true, "requires": { - "mdn-data": "2.0.6", - "source-map": "^0.6.1" + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" } }, "mdn-data": { - "version": "2.0.6", - "integrity": "sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA==", + "version": "2.0.30", "dev": true }, - "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "source-map-js": { + "version": "1.0.2", "dev": true } } }, "@applitools/driver": { - "version": "1.6.0", - "integrity": "sha512-oKssjHF01lpI71CJd98mhBbphcOoFE9YVxZGOuPdcnfPbM83txj3MrVmH/yVRF3cDiBBVHJL8cuskjygMPhbHw==", - "dev": true, - "requires": { - "@applitools/snippets": "2.2.2", - "@applitools/types": "1.3.0", - "@applitools/utils": "1.2.13" - } - }, - "@applitools/eyes-sdk-core": { - "version": "13.2.5", - "integrity": "sha512-TTPg0IaByB5gMRJIcC9yQsCNqXe3EK5yORLUnSzxwk4KQTFEj2C5/2DJFtcHx+rxEuvu40BZ6dHT0avmHboqnw==", + "version": "1.11.21", "dev": true, "requires": { - "@applitools/dom-capture": "11.1.0", - "@applitools/dom-snapshot": "4.5.12", - "@applitools/driver": "1.6.0", - "@applitools/isomorphic-fetch": "3.0.0", - "@applitools/logger": "1.0.11", - "@applitools/screenshoter": "3.3.14", - "@applitools/snippets": "2.2.2", - "@applitools/types": "1.3.0", - "@applitools/utils": "1.2.13", - "axios": "0.26.0", - "chalk": "3.0.0", - "cosmiconfig": "6.0.0", - "dateformat": "3.0.3", - "debug": "4.3.3", - "deepmerge": "4.2.2", - "stack-trace": "0.0.10", - "tunnel": "0.0.6" + "@applitools/logger": "1.1.36", + "@applitools/snippets": "2.4.12", + "@applitools/utils": "1.3.22", + "semver": "7.3.7" }, "dependencies": { - "axios": { - "version": "0.26.0", - "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==", - "dev": true, - "requires": { - "follow-redirects": "^1.14.8" - } - }, - "chalk": { - "version": "3.0.0", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cosmiconfig": { + "lru-cache": { "version": "6.0.0", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", "dev": true, "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, - "debug": { - "version": "4.3.3", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" + "yallist": "^4.0.0" } }, - "deepmerge": { - "version": "4.2.2", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "parse-json": { - "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "semver": { + "version": "7.3.7", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "lru-cache": "^6.0.0" } }, - "path-type": { + "yallist": { "version": "4.0.0", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true } } }, "@applitools/eyes-storybook": { - "version": "3.27.6", - "integrity": "sha512-4vOMGqiF5HxbQhLPKLDwE7S+qr5W22J/C8GJ3fD0NLPXj8Nk5VMdmSp9vXz7AfB9iphGMvYfGjTNE37qz29bag==", + "version": "3.30.1", "dev": true, "requires": { - "@applitools/driver": "1.6.0", - "@applitools/eyes-sdk-core": "13.2.5", + "@applitools/core": "1.3.7", + "@applitools/driver": "1.11.21", "@applitools/functional-commons": "1.6.0", - "@applitools/logger": "1.0.11", + "@applitools/logger": "1.1.36", "@applitools/monitoring-commons": "1.0.19", - "@applitools/spec-driver-puppeteer": "1.1.1", - "@applitools/test-server": "1.0.8", - "@applitools/utils": "1.2.13", - "@applitools/visual-grid-client": "15.11.2", + "@applitools/spec-driver-puppeteer": "1.1.31", + "@applitools/test-server": "1.1.16", + "@applitools/ufg-client": "1.1.12", + "@applitools/utils": "1.3.22", "boxen": "4.2.0", "chalk": "3.0.0", "detect-port": "1.3.0", @@ -49253,17 +52917,16 @@ "ora": "3.4.0", "puppeteer": "10.2.0", "strip-ansi": "6.0.0", + "throat": "6.0.1", "yargs": "15.4.1" }, "dependencies": { "ansi-regex": { "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "boxen": { "version": "4.2.0", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", "dev": true, "requires": { "ansi-align": "^3.0.0", @@ -49278,7 +52941,6 @@ }, "chalk": { "version": "3.0.0", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -49287,7 +52949,6 @@ }, "cli-cursor": { "version": "2.1.0", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", "dev": true, "requires": { "restore-cursor": "^2.0.0" @@ -49295,12 +52956,10 @@ }, "is-fullwidth-code-point": { "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "log-symbols": { "version": "2.2.0", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "dev": true, "requires": { "chalk": "^2.0.1" @@ -49308,7 +52967,6 @@ "dependencies": { "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -49316,7 +52974,6 @@ }, "chalk": { "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -49326,7 +52983,6 @@ }, "supports-color": { "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -49336,12 +52992,10 @@ }, "mimic-fn": { "version": "1.2.0", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "onetime": { "version": "2.0.1", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", "dev": true, "requires": { "mimic-fn": "^1.0.0" @@ -49349,7 +53003,6 @@ }, "ora": { "version": "3.4.0", - "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -49362,12 +53015,10 @@ "dependencies": { "ansi-regex": { "version": "4.1.1", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -49375,7 +53026,6 @@ }, "chalk": { "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -49385,7 +53035,6 @@ }, "strip-ansi": { "version": "5.2.0", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { "ansi-regex": "^4.1.0" @@ -49393,7 +53042,6 @@ }, "supports-color": { "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -49403,7 +53051,6 @@ }, "restore-cursor": { "version": "2.0.0", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", "dev": true, "requires": { "onetime": "^2.0.0", @@ -49412,7 +53059,6 @@ }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", @@ -49422,7 +53068,6 @@ "dependencies": { "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { "ansi-regex": "^5.0.1" @@ -49432,59 +53077,33 @@ }, "strip-ansi": { "version": "6.0.0", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { "ansi-regex": "^5.0.0" } + }, + "throat": { + "version": "6.0.1", + "dev": true } } }, "@applitools/functional-commons": { "version": "1.6.0", - "integrity": "sha512-fwiF0CbeYHDEOTD/NKaFgaI8LvRcGYG2GaJJiRwcedKko16sQ8F3TK5wXfj2Ytjf+8gjwHwsEEX550z3yvDWxA==", "dev": true }, - "@applitools/http-commons": { - "version": "2.4.5", - "integrity": "sha512-w1lP9aljD6FLp/wgifj/oyj/bTCiAH2PuwDJci5QKJAeymqPoRGrKvykoKOegpa5OjdmZSPD/kW40ZTHSsST5Q==", - "dev": true, - "requires": { - "@applitools/functional-commons": "^1.5.5", - "@applitools/monitoring-commons": "^1.0.19", - "agentkeepalive": "^4.1.0", - "debug": "^4.1.1", - "lodash.merge": "^4.6.2", - "node-fetch": "^2.6.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@applitools/isomorphic-fetch": { - "version": "3.0.0", - "integrity": "sha512-7rutaN/2M5wYjOIOTKS/Zuc1Na90fJNEAqvo/jCxt7nSD1kYscHV3aCk9t7RD59gmzLMvUTIxFbjl4RUMV8qfg==", + "@applitools/image": { + "version": "1.0.17", "dev": true, "requires": { - "node-fetch": "^2.3.0", - "whatwg-fetch": ">=0.10.0" + "@applitools/utils": "1.3.22", + "bmpimagejs": "1.0.4", + "jpeg-js": "0.4.4", + "png-async": "0.9.4" } }, "@applitools/jsdom": { "version": "1.0.4", - "integrity": "sha512-JtjNfTJtphJYHEkicW4xlwtYuRP3TRvjoszfkrcpxTNMCbGkbop8ed9MuUfR83dAZj5NY9begbmEqJohLJco6w==", "dev": true, "requires": { "abab": "^2.0.5", @@ -49518,54 +53137,17 @@ "dependencies": { "@tootallnate/once": { "version": "2.0.0", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true - }, - "cssom": { - "version": "0.5.0", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", "dev": true }, - "data-urls": { - "version": "3.0.2", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "requires": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - }, - "dependencies": { - "whatwg-url": { - "version": "11.0.0", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "requires": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - } - } - } - }, "debug": { "version": "4.3.4", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" } }, - "domexception": { - "version": "4.0.0", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "requires": { - "webidl-conversions": "^7.0.0" - } - }, "escodegen": { "version": "2.0.0", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "requires": { "esprima": "^4.0.1", @@ -49577,17 +53159,14 @@ }, "esprima": { "version": "4.0.1", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "estraverse": { "version": "5.3.0", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "form-data": { "version": "4.0.0", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "requires": { "asynckit": "^0.4.0", @@ -49595,17 +53174,8 @@ "mime-types": "^2.1.12" } }, - "html-encoding-sniffer": { - "version": "3.0.0", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "requires": { - "whatwg-encoding": "^2.0.0" - } - }, "http-proxy-agent": { "version": "5.0.0", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, "requires": { "@tootallnate/once": "2", @@ -49615,7 +53185,6 @@ }, "iconv-lite": { "version": "0.6.3", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -49623,59 +53192,44 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "parse5": { "version": "6.0.1", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true }, "tough-cookie": { - "version": "4.0.0", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "version": "4.1.2", "dev": true, "requires": { "psl": "^1.1.33", "punycode": "^2.1.1", - "universalify": "^0.1.2" + "universalify": "^0.2.0", + "url-parse": "^1.5.3" } }, "tr46": { "version": "3.0.0", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, "requires": { "punycode": "^2.1.1" } }, "universalify": { - "version": "0.1.2", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "0.2.0", "dev": true }, - "w3c-xmlserializer": { - "version": "3.0.0", - "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", - "dev": true, - "requires": { - "xml-name-validator": "^4.0.0" - } - }, "webidl-conversions": { "version": "7.0.0", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true }, "whatwg-encoding": { "version": "2.0.0", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, "requires": { "iconv-lite": "0.6.3" @@ -49683,12 +53237,10 @@ }, "whatwg-mimetype": { "version": "3.0.0", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", "dev": true }, "whatwg-url": { "version": "10.0.0", - "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", "dev": true, "requires": { "tr46": "^3.0.0", @@ -49696,40 +53248,25 @@ } }, "ws": { - "version": "8.5.0", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "version": "8.12.0", "dev": true }, "xml-name-validator": { "version": "4.0.0", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true } } }, "@applitools/logger": { - "version": "1.0.11", - "integrity": "sha512-AcTTpLfUggo4/TISBk5+X4PdSZuMDEK0+gzsf+b9BCFzPDc7p4yrAHeftHdjOV/AE3yLQEWnupUmlsttdMayXQ==", + "version": "1.1.36", "dev": true, "requires": { - "@applitools/utils": "1.2.13", - "chalk": "3.0.0" - }, - "dependencies": { - "chalk": { - "version": "3.0.0", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - } + "@applitools/utils": "1.3.22", + "chalk": "4.1.2" } }, "@applitools/monitoring-commons": { "version": "1.0.19", - "integrity": "sha512-rzEOvGoiEF4KnK0PJ9I0btdwnaNlIPLYhjF1vTEG15PoucbbKpix9fYusxWlDG7kMiZya8ZycVPc0woVlNaHRQ==", "dev": true, "requires": { "debug": "^4.1.0" @@ -49737,7 +53274,6 @@ "dependencies": { "debug": { "version": "4.3.4", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -49745,63 +53281,100 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, + "@applitools/nml-client": { + "version": "1.3.22", + "dev": true, + "requires": { + "@applitools/logger": "1.1.36", + "@applitools/req": "1.1.23", + "@applitools/utils": "1.3.22" + } + }, + "@applitools/req": { + "version": "1.1.23", + "dev": true, + "requires": { + "@applitools/utils": "1.3.22", + "@types/node-fetch": "2.6.2", + "abort-controller": "3.0.0", + "node-fetch": "2.6.7", + "proxy-agent": "5.0.0" + } + }, "@applitools/screenshoter": { - "version": "3.3.14", - "integrity": "sha512-DwZFJiBIgEkyzEaESnl3A87KeSVnUmHKad9vg+iwgtAFQf492ZI7t+PKhjGVM9ekZ8q5Sz4xnO+Bsmk8qEu0+A==", + "version": "3.7.20", "dev": true, "requires": { - "@applitools/snippets": "2.2.2", - "@applitools/utils": "1.2.13", + "@applitools/image": "1.0.17", + "@applitools/logger": "1.1.36", + "@applitools/snippets": "2.4.12", + "@applitools/utils": "1.3.22", + "jpeg-js": "0.4.4", "png-async": "0.9.4" } }, "@applitools/snippets": { - "version": "2.2.2", - "integrity": "sha512-XOxdrsWgcEu6h6QTVL/S8/dJHoPGir1GKQLyWORbRfbjll15/mUj3Mzzi9MqL6lSN3KWp07ncLvMuhSETpi7Mg==", + "version": "2.4.12", "dev": true }, "@applitools/spec-driver-puppeteer": { - "version": "1.1.1", - "integrity": "sha512-64TvcOc8vHYz1IXftOJzNqy0lLTMMnnjvKhcqMwIct5PJY8QYdVZagBRwGF9L9wYhs8ULtpmSa/SmpPaIbMNUQ==", + "version": "1.1.31", "dev": true, "requires": { - "@applitools/types": "1.3.0", - "@applitools/utils": "1.2.13" + "@applitools/driver": "1.11.21", + "@applitools/utils": "1.3.22" } }, "@applitools/test-server": { - "version": "1.0.8", - "integrity": "sha512-KP1A8aySLoU532zCG6mwk2Mair56gQ5xp75ZnV4/CvefCzeD2f/nqUBYmoiTN940QOrQVWAXeXvuwMj1BUJD0Q==", + "version": "1.1.16", "dev": true, "requires": { - "@applitools/utils": "1.2.4", + "@applitools/logger": "1.1.36", + "@applitools/utils": "1.3.22", + "body-parser": "1.20.0", "chalk": "3.0.0", "cookie-parser": "1.4.5", "cors": "2.8.5", - "express": "4.17.1", + "express": "4.17.3", "handlebars": "4.7.7", + "http-proxy": "1.18.1", "morgan": "1.10.0", + "node-forge": "1.3.1", "yargs": "17.0.1" }, "dependencies": { - "@applitools/utils": { - "version": "1.2.4", - "integrity": "sha512-w7ma6FFGyqhdP6LEcuHFWOcH7EzBjnoAX3UfbFWcTHA3QXnXPX37Y2ENYRodfwkorP1cUKyUHwNXJB/BMIj/hg==", - "dev": true - }, "ansi-regex": { "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "body-parser": { + "version": "1.20.0", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "bytes": { + "version": "3.1.2", "dev": true }, "chalk": { "version": "3.0.0", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -49810,7 +53383,6 @@ }, "cliui": { "version": "7.0.4", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { "string-width": "^4.2.0", @@ -49818,14 +53390,67 @@ "wrap-ansi": "^7.0.0" } }, + "depd": { + "version": "2.0.0", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "inherits": { + "version": "2.0.4", + "dev": true + }, "is-fullwidth-code-point": { "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "qs": { + "version": "6.10.3", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "raw-body": { + "version": "2.5.1", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "dev": true + }, + "statuses": { + "version": "2.0.1", "dev": true }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", @@ -49835,7 +53460,6 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { "ansi-regex": "^5.0.1" @@ -49843,7 +53467,6 @@ }, "wrap-ansi": { "version": "7.0.0", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { "ansi-styles": "^4.0.0", @@ -49853,12 +53476,10 @@ }, "y18n": { "version": "5.0.8", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yargs": { "version": "17.0.1", - "integrity": "sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -49872,131 +53493,102 @@ }, "yargs-parser": { "version": "20.2.9", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true } } }, - "@applitools/types": { - "version": "1.3.0", - "integrity": "sha512-aLLm5FVtg/iDnrNvIDFKZrHQ2Nh64dSuy5VairQroMoCwK90Pft75Dy6CQC5g4IUEN04Wub9sx2kmthjQiwkZA==", - "dev": true - }, - "@applitools/utils": { - "version": "1.2.13", - "integrity": "sha512-yZ333Y/bAH/A05UMBllEdqBAwkFQknih2arIRSfN+QBpiFrfuLtQEdCwXAdnvU/MbAzZ/Tje7iv93FMzs5gFZA==", - "dev": true - }, - "@applitools/visual-grid-client": { - "version": "15.11.2", - "integrity": "sha512-PVnyVBlVjocnFjtXAbjH1UmAHz01/6GmaBV9fTFAjnpzCHDEbZ4Uz+pNi7hhMKy/hzRoe8LuRLZVBbagkhx9Aw==", + "@applitools/ufg-client": { + "version": "1.1.12", "dev": true, "requires": { - "@applitools/eyes-sdk-core": "13.2.5", - "@applitools/functional-commons": "1.6.0", - "@applitools/http-commons": "2.4.5", - "@applitools/isomorphic-fetch": "3.0.0", "@applitools/jsdom": "1.0.4", - "@applitools/logger": "1.0.11", + "@applitools/logger": "1.1.36", + "@applitools/req": "1.1.23", + "@applitools/utils": "1.3.22", "abort-controller": "3.0.0", - "chalk": "3.0.0", - "postcss-value-parser": "4.1.0", - "throat": "5.0.0" + "postcss-value-parser": "4.2.0", + "throat": "6.0.1" }, "dependencies": { - "chalk": { - "version": "3.0.0", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "throat": { + "version": "6.0.1", + "dev": true } } }, + "@applitools/utils": { + "version": "1.3.22", + "dev": true + }, "@babel/cli": { - "version": "7.16.0", - "integrity": "sha512-WLrM42vKX/4atIoQB+eb0ovUof53UUvecb4qGjU2PDDWRiZr50ZpiV8NpcLo7iSxeGYrRG0Mqembsa+UrTAV6Q==", + "version": "7.18.10", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.8", "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", "chokidar": "^3.4.0", "commander": "^4.0.1", "convert-source-map": "^1.1.0", "fs-readdir-recursive": "^1.1.0", - "glob": "^7.0.0", + "glob": "^7.2.0", "make-dir": "^2.1.0", - "slash": "^2.0.0", - "source-map": "^0.5.0" + "slash": "^2.0.0" }, "dependencies": { "commander": { "version": "4.1.1", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true } } }, "@babel/code-frame": { - "version": "7.14.5", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.18.6", "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.18.6" } }, "@babel/compat-data": { - "version": "7.15.0", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==" + "version": "7.18.8" }, "@babel/core": { - "version": "7.15.5", - "integrity": "sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg==", - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.5", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.18.10", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "json5": "^2.2.1", + "semver": "^6.3.0" }, "dependencies": { "debug": { "version": "4.3.1", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "requires": { "ms": "2.1.2" } }, "json5": { - "version": "2.1.3", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3" }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" } } }, "@babel/eslint-parser": { - "version": "7.15.7", - "integrity": "sha512-yJkHyomClm6A2Xzb8pdAo4HzYMSXFn1O5zrCYvbFP0yQFvHueLedV8WiEno8yJOKStjUXzBZzJFeWQ7b3YMsqQ==", + "version": "7.18.9", "dev": true, "requires": { "eslint-scope": "^5.1.1", @@ -50006,79 +53598,70 @@ "dependencies": { "eslint-visitor-keys": { "version": "2.1.0", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true }, "semver": { "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "@babel/generator": { - "version": "7.15.4", - "integrity": "sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw==", + "version": "7.18.12", "requires": { - "@babel/types": "^7.15.4", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" } }, "@babel/helper-annotate-as-pure": { - "version": "7.15.4", - "integrity": "sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==", + "version": "7.18.6", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.15.4", - "integrity": "sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q==", + "version": "7.18.9", "requires": { - "@babel/helper-explode-assignable-expression": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" } }, "@babel/helper-compilation-targets": { - "version": "7.15.4", - "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "version": "7.18.9", "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", + "@babel/compat-data": "^7.18.8", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", "semver": "^6.3.0" }, "dependencies": { "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" } } }, "@babel/helper-create-class-features-plugin": { - "version": "7.15.4", - "integrity": "sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw==", + "version": "7.18.9", "requires": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", + "version": "7.18.6", "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "regexpu-core": "^4.7.1" + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" } }, "@babel/helper-define-polyfill-provider": { "version": "0.1.5", - "integrity": "sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==", "requires": { "@babel/helper-compilation-targets": "^7.13.0", "@babel/helper-module-imports": "^7.12.13", @@ -50092,176 +53675,153 @@ "dependencies": { "debug": { "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "requires": { "ms": "2.1.2" } }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" } } }, + "@babel/helper-environment-visitor": { + "version": "7.18.9" + }, "@babel/helper-explode-assignable-expression": { - "version": "7.15.4", - "integrity": "sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g==", + "version": "7.18.6", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" } }, "@babel/helper-function-name": { - "version": "7.15.4", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "version": "7.18.9", "requires": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.15.4", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", - "requires": { - "@babel/types": "^7.15.4" + "@babel/template": "^7.18.6", + "@babel/types": "^7.18.9" } }, "@babel/helper-hoist-variables": { - "version": "7.15.4", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "version": "7.18.6", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.15.4", - "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "version": "7.18.9", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.9" } }, "@babel/helper-module-imports": { - "version": "7.15.4", - "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "version": "7.18.6", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" } }, "@babel/helper-module-transforms": { - "version": "7.15.7", - "integrity": "sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==", + "version": "7.18.9", "requires": { - "@babel/helper-module-imports": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-simple-access": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" } }, "@babel/helper-optimise-call-expression": { - "version": "7.15.4", - "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", + "version": "7.18.6", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" } }, "@babel/helper-plugin-utils": { - "version": "7.14.5", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==" + "version": "7.18.9" }, "@babel/helper-remap-async-to-generator": { - "version": "7.15.4", - "integrity": "sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ==", + "version": "7.18.9", "requires": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-wrap-function": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" } }, "@babel/helper-replace-supers": { - "version": "7.15.4", - "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", + "version": "7.18.9", "requires": { - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" } }, "@babel/helper-simple-access": { - "version": "7.15.4", - "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "version": "7.18.6", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.15.4", - "integrity": "sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A==", + "version": "7.18.9", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.9" } }, "@babel/helper-split-export-declaration": { - "version": "7.15.4", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "version": "7.18.6", "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.18.6" } }, + "@babel/helper-string-parser": { + "version": "7.18.10" + }, "@babel/helper-validator-identifier": { - "version": "7.15.7", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" + "version": "7.18.6" }, "@babel/helper-validator-option": { - "version": "7.14.5", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==" + "version": "7.18.6" }, "@babel/helper-wrap-function": { - "version": "7.15.4", - "integrity": "sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw==", + "version": "7.18.11", "requires": { - "@babel/helper-function-name": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/helper-function-name": "^7.18.9", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.11", + "@babel/types": "^7.18.10" } }, "@babel/helpers": { - "version": "7.15.4", - "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "version": "7.18.9", "requires": { - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" } }, "@babel/highlight": { - "version": "7.14.5", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.18.6", "requires": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, "dependencies": { "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { "color-convert": "^1.9.0" } }, "chalk": { "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -50270,7 +53830,6 @@ }, "supports-color": { "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { "has-flag": "^3.0.0" } @@ -50278,13 +53837,12 @@ } }, "@babel/node": { - "version": "7.15.4", - "integrity": "sha512-UZue+j8p5aKTaVjvy5psYmqLHqmz+9cIboAFoa97S1xeZyUr0gT6KzXB8ZkfBIsP/u79biOdjGHVXBXnW3rVfw==", + "version": "7.18.10", "dev": true, "requires": { - "@babel/register": "^7.15.3", + "@babel/register": "^7.18.9", "commander": "^4.0.1", - "core-js": "^3.16.0", + "core-js": "^3.22.1", "node-environment-flags": "^1.0.5", "regenerator-runtime": "^0.13.4", "v8flags": "^3.1.1" @@ -50292,53 +53850,53 @@ "dependencies": { "commander": { "version": "4.1.1", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true } } }, "@babel/parser": { - "version": "7.15.7", - "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==" + "version": "7.18.11" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.15.4", - "integrity": "sha512-eBnpsl9tlhPhpI10kU06JHnrYXwg3+V6CaP2idsCXNef0aeslpqyITXQ74Vfk5uHgY7IG7XP0yIH8b42KSzHog==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4", - "@babel/plugin-proposal-optional-chaining": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.15.4", - "integrity": "sha512-2zt2g5vTXpMC3OmK6uyjvdXptbhBXfA77XGrd3gh93zwG8lZYBLOBImiGBEG0RANu3JqKEACCz5CGk73OJROBw==", + "version": "7.18.10", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.15.4", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.14.5", - "integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==", + "version": "7.18.6", "requires": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-proposal-class-static-block": { - "version": "7.15.4", - "integrity": "sha512-M682XWrrLNk3chXCjoPUQWOyYsB93B9z3mRyjtqqYJWDf2mfCdIYgDrA11cgNVhAQieaq6F2fn2f3wI0U4aTjA==", + "version": "7.18.6", "requires": { - "@babel/helper-create-class-features-plugin": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-decorators": { "version": "7.15.4", - "integrity": "sha512-WNER+YLs7avvRukEddhu5PSfSaMMimX2xBFgLQS7Bw16yrUxJGWidO9nQp+yLy9MVybg5Ba3BlhAw+BkdhpDmg==", "requires": { "@babel/helper-create-class-features-plugin": "^7.15.4", "@babel/helper-plugin-utils": "^7.14.5", @@ -50346,64 +53904,56 @@ } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.14.5", - "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-default-from": { "version": "7.14.5", - "integrity": "sha512-T8KZ5abXvKMjF6JcoXjgac3ElmXf0AWzJwi2O/42Jk+HmCky3D9+i1B7NPP1FblyceqTevKeV/9szeikFoaMDg==", "requires": { "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-export-default-from": "^7.14.5" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.14.5", - "integrity": "sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.14.5", - "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.14.5", - "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.14.5", - "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.14.5", - "integrity": "sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { "version": "7.12.1", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.0", @@ -50411,58 +53961,51 @@ } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.14.5", - "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.14.5", - "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.14.5", - "integrity": "sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==", + "version": "7.18.6", "requires": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.15.4", - "integrity": "sha512-X0UTixkLf0PCCffxgu5/1RQyGGbgZuKoI+vXP4iSbJSYwPb7hu06omsFGBvQ9lJEvwgrxHdS8B5nbfcd8GyUNA==", + "version": "7.18.6", "requires": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-create-class-features-plugin": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.14.5", - "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", + "version": "7.18.6", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "requires": { "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-bigint": { "version": "7.8.3", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" @@ -50470,56 +54013,54 @@ }, "@babel/plugin-syntax-class-properties": { "version": "7.12.13", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "requires": { "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-syntax-class-static-block": { "version": "7.14.5", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-decorators": { "version": "7.14.5", - "integrity": "sha512-c4sZMRWL4GSvP1EXy0woIP7m4jkVcEuG8R1TOZxPBPtp4FSM/kiPZub9UIs/Jrb5ZAOzvTUSGYrWsrSu1JvoPw==", "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "requires": { "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-export-default-from": { "version": "7.14.5", - "integrity": "sha512-snWDxjuaPEobRBnhpqEfZ8RMxDbHt8+87fiEioGuE+Uc0xAKgSD8QiuL3lF93hPVQfZFAcYwrrf+H5qUhike3Q==", "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", "requires": { "@babel/helper-plugin-utils": "^7.8.3" } }, "@babel/plugin-syntax-flow": { "version": "7.14.5", - "integrity": "sha512-9WK5ZwKCdWHxVuU13XNT6X73FGmutAXeor5lGFq6qhOFtMFUF4jkbijuyUdZZlpYq6E2hZeZf/u3959X9wsv0Q==", "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, "@babel/plugin-syntax-import-meta": { "version": "7.10.1", - "integrity": "sha512-ypC4jwfIVF72og0dgvEcFRdOM2V9Qm1tu7RGmdZOlhsccyK0wisXmMObGuWEOd5jQ+K9wcIgSNftCpk2vkjUfQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.1" @@ -50527,349 +54068,307 @@ }, "@babel/plugin-syntax-json-strings": { "version": "7.8.3", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "requires": { "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-jsx": { - "version": "7.14.5", - "integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "requires": { "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "requires": { "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "requires": { "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "requires": { "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "requires": { "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "requires": { "@babel/helper-plugin-utils": "^7.8.0" } }, "@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-top-level-await": { "version": "7.14.5", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-typescript": { "version": "7.14.5", - "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.14.5", - "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.14.5", - "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", + "version": "7.18.6", "requires": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5" + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.14.5", - "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.15.3", - "integrity": "sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-classes": { - "version": "7.15.4", - "integrity": "sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", + "version": "7.18.9", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.14.5", - "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-destructuring": { - "version": "7.14.7", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.14.5", - "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", + "version": "7.18.6", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.14.5", - "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.14.5", - "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", + "version": "7.18.6", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-flow-strip-types": { "version": "7.14.5", - "integrity": "sha512-KhcolBKfXbvjwI3TV7r7TkYm8oNXHNBqGOy6JDVwtecFaRoKYsUUqJdS10q0YDKW1c6aZQgO+Ys3LfGkox8pXA==", "requires": { "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-flow": "^7.14.5" } }, "@babel/plugin-transform-for-of": { - "version": "7.15.4", - "integrity": "sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA==", + "version": "7.18.8", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-function-name": { - "version": "7.14.5", - "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", + "version": "7.18.9", "requires": { - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-literals": { - "version": "7.14.5", - "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.14.5", - "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.14.5", - "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", + "version": "7.18.6", "requires": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.15.4", - "integrity": "sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA==", + "version": "7.18.6", "requires": { - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.15.4", - "integrity": "sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw==", + "version": "7.18.9", "requires": { - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-identifier": "^7.18.6", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.14.5", - "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", + "version": "7.18.6", "requires": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.14.9", - "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", + "version": "7.18.6", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-new-target": { - "version": "7.14.5", - "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-object-super": { - "version": "7.14.5", - "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" } }, "@babel/plugin-transform-parameters": { - "version": "7.15.4", - "integrity": "sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ==", + "version": "7.18.8", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-property-literals": { - "version": "7.14.5", - "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-react-constant-elements": { "version": "7.14.5", - "integrity": "sha512-NBqLEx1GxllIOXJInJAQbrnwwYJsV3WaMHIcOwD8rhYS0AabTWn7kHdHgPgu5RmHLU0q4DMxhAMu8ue/KampgQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-react-display-name": { - "version": "7.15.1", - "integrity": "sha512-yQZ/i/pUCJAHI/LbtZr413S3VT26qNrEm0M5RRxQJA947/YNYwbZbBaXGDrq6CG5QsZycI1VIP6d7pQaBfP+8Q==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-react-jsx": { - "version": "7.14.9", - "integrity": "sha512-30PeETvS+AeD1f58i1OVyoDlVYQhap/K20ZrMjLmmzmC2AYR/G43D4sdJAaDAqCD3MYpSWbmrz3kES158QSLjw==", + "version": "7.18.10", "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-jsx": "^7.14.5", - "@babel/types": "^7.14.9" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.18.10" } }, "@babel/plugin-transform-react-jsx-development": { - "version": "7.14.5", - "integrity": "sha512-rdwG/9jC6QybWxVe2UVOa7q6cnTpw8JRRHOxntG/h6g/guAOe6AhtQHJuJh5FwmnXIT1bdm5vC2/5huV8ZOorQ==", + "version": "7.18.6", "requires": { - "@babel/plugin-transform-react-jsx": "^7.14.5" + "@babel/plugin-transform-react-jsx": "^7.18.6" } }, "@babel/plugin-transform-react-pure-annotations": { - "version": "7.14.5", - "integrity": "sha512-3X4HpBJimNxW4rhUy/SONPyNQHp5YRr0HhJdT2OH1BRp0of7u3Dkirc7x9FRJMKMqTBI079VZ1hzv7Ouuz///g==", + "version": "7.18.6", "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-regenerator": { - "version": "7.14.5", - "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", + "version": "7.18.6", "requires": { - "regenerator-transform": "^0.14.2" + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.14.5", - "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-runtime": { - "version": "7.15.0", - "integrity": "sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw==", + "version": "7.18.10", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", - "babel-plugin-polyfill-regenerator": "^0.2.2", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", "semver": "^6.3.0" }, "dependencies": { "@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.2", "dev": true, "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -50877,17 +54376,15 @@ } }, "babel-plugin-polyfill-corejs3": { - "version": "0.2.5", - "integrity": "sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw==", + "version": "0.5.3", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.16.2" + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" } }, "debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", "dev": true, "requires": { "ms": "2.1.2" @@ -50895,55 +54392,47 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "semver": { "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.14.5", - "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-spread": { - "version": "7.14.6", - "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.14.5", - "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-template-literals": { - "version": "7.14.5", - "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.14.5", - "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", + "version": "7.18.9", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-typescript": { "version": "7.15.4", - "integrity": "sha512-sM1/FEjwYjXvMwu1PJStH11kJ154zd/lpY56NQJ5qH2D0mabMv1CAy/kdvS9RP4Xgfj9fBBA3JiSLdDHgXdzOA==", "requires": { "@babel/helper-create-class-features-plugin": "^7.15.4", "@babel/helper-plugin-utils": "^7.14.5", @@ -50951,63 +54440,60 @@ } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.14.5", - "integrity": "sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==", + "version": "7.18.10", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.14.5", - "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", + "version": "7.18.6", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/polyfill": { "version": "7.12.1", - "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==", "requires": { "core-js": "^2.6.5", "regenerator-runtime": "^0.13.4" }, "dependencies": { "core-js": { - "version": "2.6.12", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + "version": "2.6.12" } } }, "@babel/preset-env": { - "version": "7.15.6", - "integrity": "sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw==", - "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.15.4", - "@babel/plugin-proposal-async-generator-functions": "^7.15.4", - "@babel/plugin-proposal-class-properties": "^7.14.5", - "@babel/plugin-proposal-class-static-block": "^7.15.4", - "@babel/plugin-proposal-dynamic-import": "^7.14.5", - "@babel/plugin-proposal-export-namespace-from": "^7.14.5", - "@babel/plugin-proposal-json-strings": "^7.14.5", - "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", - "@babel/plugin-proposal-numeric-separator": "^7.14.5", - "@babel/plugin-proposal-object-rest-spread": "^7.15.6", - "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", - "@babel/plugin-proposal-optional-chaining": "^7.14.5", - "@babel/plugin-proposal-private-methods": "^7.14.5", - "@babel/plugin-proposal-private-property-in-object": "^7.15.4", - "@babel/plugin-proposal-unicode-property-regex": "^7.14.5", + "version": "7.18.10", + "requires": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -51017,55 +54503,52 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.14.5", - "@babel/plugin-transform-async-to-generator": "^7.14.5", - "@babel/plugin-transform-block-scoped-functions": "^7.14.5", - "@babel/plugin-transform-block-scoping": "^7.15.3", - "@babel/plugin-transform-classes": "^7.15.4", - "@babel/plugin-transform-computed-properties": "^7.14.5", - "@babel/plugin-transform-destructuring": "^7.14.7", - "@babel/plugin-transform-dotall-regex": "^7.14.5", - "@babel/plugin-transform-duplicate-keys": "^7.14.5", - "@babel/plugin-transform-exponentiation-operator": "^7.14.5", - "@babel/plugin-transform-for-of": "^7.15.4", - "@babel/plugin-transform-function-name": "^7.14.5", - "@babel/plugin-transform-literals": "^7.14.5", - "@babel/plugin-transform-member-expression-literals": "^7.14.5", - "@babel/plugin-transform-modules-amd": "^7.14.5", - "@babel/plugin-transform-modules-commonjs": "^7.15.4", - "@babel/plugin-transform-modules-systemjs": "^7.15.4", - "@babel/plugin-transform-modules-umd": "^7.14.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.9", - "@babel/plugin-transform-new-target": "^7.14.5", - "@babel/plugin-transform-object-super": "^7.14.5", - "@babel/plugin-transform-parameters": "^7.15.4", - "@babel/plugin-transform-property-literals": "^7.14.5", - "@babel/plugin-transform-regenerator": "^7.14.5", - "@babel/plugin-transform-reserved-words": "^7.14.5", - "@babel/plugin-transform-shorthand-properties": "^7.14.5", - "@babel/plugin-transform-spread": "^7.14.6", - "@babel/plugin-transform-sticky-regex": "^7.14.5", - "@babel/plugin-transform-template-literals": "^7.14.5", - "@babel/plugin-transform-typeof-symbol": "^7.14.5", - "@babel/plugin-transform-unicode-escapes": "^7.14.5", - "@babel/plugin-transform-unicode-regex": "^7.14.5", - "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.15.6", - "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", - "babel-plugin-polyfill-regenerator": "^0.2.2", - "core-js-compat": "^3.16.0", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.10", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "core-js-compat": "^3.22.1", "semver": "^6.3.0" }, "dependencies": { "@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.2", "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -51073,44 +54556,38 @@ } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.15.6", - "integrity": "sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg==", + "version": "7.18.9", "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.15.4" + "@babel/plugin-transform-parameters": "^7.18.8" } }, "babel-plugin-polyfill-corejs3": { - "version": "0.2.5", - "integrity": "sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw==", + "version": "0.5.3", "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.16.2" + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" } }, "debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", "requires": { "ms": "2.1.2" } }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" } } }, "@babel/preset-flow": { "version": "7.14.5", - "integrity": "sha512-pP5QEb4qRUSVGzzKx9xqRuHUrM/jEzMqdrZpdMA+oUCRgd5zM1qGr5y5+ZgAL/1tVv1H0dyk5t4SKJntqyiVtg==", "requires": { "@babel/helper-plugin-utils": "^7.14.5", "@babel/helper-validator-option": "^7.14.5", @@ -51118,8 +54595,7 @@ } }, "@babel/preset-modules": { - "version": "0.1.4", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "version": "0.1.5", "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", @@ -51129,20 +54605,18 @@ } }, "@babel/preset-react": { - "version": "7.14.5", - "integrity": "sha512-XFxBkjyObLvBaAvkx1Ie95Iaq4S/GUEIrejyrntQ/VCMKUYvKLoyKxOBzJ2kjA3b6rC9/KL6KXfDC2GqvLiNqQ==", + "version": "7.18.6", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-transform-react-display-name": "^7.14.5", - "@babel/plugin-transform-react-jsx": "^7.14.5", - "@babel/plugin-transform-react-jsx-development": "^7.14.5", - "@babel/plugin-transform-react-pure-annotations": "^7.14.5" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-react-display-name": "^7.18.6", + "@babel/plugin-transform-react-jsx": "^7.18.6", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-pure-annotations": "^7.18.6" } }, "@babel/preset-typescript": { "version": "7.15.0", - "integrity": "sha512-lt0Y/8V3y06Wq/8H/u0WakrqciZ7Fz7mwPDHWUJAXlABL5hiUG42BNlRXiELNjeWjO5rWmnNKlx+yzJvxezHow==", "requires": { "@babel/helper-plugin-utils": "^7.14.5", "@babel/helper-validator-option": "^7.14.5", @@ -51150,101 +54624,90 @@ } }, "@babel/register": { - "version": "7.15.3", - "integrity": "sha512-mj4IY1ZJkorClxKTImccn4T81+UKTo4Ux0+OFSV9hME1ooqS9UV+pJ6BjD0qXPK4T3XW/KNa79XByjeEMZz+fw==", + "version": "7.18.9", "requires": { "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", "make-dir": "^2.1.0", - "pirates": "^4.0.0", + "pirates": "^4.0.5", "source-map-support": "^0.5.16" } }, "@babel/runtime": { - "version": "7.17.9", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.20.1", "requires": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.13.10" } }, "@babel/runtime-corejs2": { "version": "7.15.4", - "integrity": "sha512-TmuTI+n5HsMesW6Ah2WjvBwix9fBMXwbMxQV3c0ETLAzlmwN4OeRVbYMYwp9P4LEOlAxwGKdd9e8pMiLMAg/Mg==", "requires": { "core-js": "^2.6.5", "regenerator-runtime": "^0.13.4" }, "dependencies": { "core-js": { - "version": "2.6.12", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + "version": "2.6.12" } } }, "@babel/runtime-corejs3": { "version": "7.12.5", - "integrity": "sha512-roGr54CsTmNPPzZoCP1AmDXuBoNao7tnSA83TXTwt+UK5QVyh1DIJnrgYRPWKCF2flqZQXwa7Yr8v7VmLzF0YQ==", "requires": { "core-js-pure": "^3.0.0", "regenerator-runtime": "^0.13.4" } }, "@babel/template": { - "version": "7.15.4", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "version": "7.18.10", "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" } }, "@babel/traverse": { - "version": "7.15.4", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.18.11", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.18.11", + "@babel/types": "^7.18.10", "debug": "^4.1.0", "globals": "^11.1.0" }, "dependencies": { "debug": { "version": "4.1.1", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { "ms": "^2.1.1" } }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" } } }, "@babel/types": { - "version": "7.15.6", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "version": "7.18.10", "requires": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", "to-fast-properties": "^2.0.0" } }, "@base2/pretty-print-object": { - "version": "1.0.1", - "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==" + "version": "1.0.1" }, "@bcoe/v8-coverage": { - "version": "0.2.3", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + "version": "0.2.3" }, "@chromaui/localtunnel": { "version": "2.0.4", - "integrity": "sha512-92AI1cIzI8XmKnsuKhIOysdZ+ecc8iCqRnoUnZ4/6Nr9PEd/CStJtK6OBAanw1QYPiojzegfeAW3uBSVFxLm4g==", "dev": true, "requires": { "axios": "0.21.4", @@ -51255,12 +54718,10 @@ "dependencies": { "ansi-regex": { "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "cliui": { "version": "7.0.4", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { "string-width": "^4.2.0", @@ -51270,7 +54731,6 @@ }, "debug": { "version": "4.3.1", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -51278,17 +54738,14 @@ }, "is-fullwidth-code-point": { "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", @@ -51298,7 +54755,6 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { "ansi-regex": "^5.0.1" @@ -51306,7 +54762,6 @@ }, "wrap-ansi": { "version": "7.0.0", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { "ansi-styles": "^4.0.0", @@ -51316,12 +54771,10 @@ }, "y18n": { "version": "5.0.8", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yargs": { "version": "16.2.0", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -51335,14 +54788,12 @@ }, "yargs-parser": { "version": "20.2.9", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true } } }, "@cnakazawa/watch": { "version": "1.0.4", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", "dev": true, "requires": { "exec-sh": "^0.3.2", @@ -51350,12 +54801,10 @@ } }, "@ctrl/tinycolor": { - "version": "3.3.1", - "integrity": "sha512-jUJrjU62MUgHDSu5JfONfgRM2V7GfN5KknsygfIbxwRZXGeayIzxk4O9GiYgEAr9DG5HJThTF5+a5x3wtrOKzQ==" + "version": "3.4.1" }, "@data-ui/event-flow": { "version": "0.0.84", - "integrity": "sha512-XOOYvpRMAT1r66dnGsrnQ+VEZVtY56np/wxzHcW7iqvvvxefvbkjGMUe0rAbMeSg17hjUfDQTBIBvf3uiVIQTA==", "requires": { "@babel/polyfill": "^7.0.0", "@babel/runtime-corejs2": "^7.1.5", @@ -51391,7 +54840,6 @@ "dependencies": { "@vx/responsive": { "version": "0.0.140", - "integrity": "sha512-qKp2urp7TB3p03xNpzAIoyOGCMoYckLqw9ZV3chVLGbg5yrvsRuot0ghcgSgT3fd1dvqFw1ur2aHeUw7p9q5zQ==", "requires": { "lodash": "^4.0.8" } @@ -51400,7 +54848,6 @@ }, "@data-ui/forms": { "version": "0.0.84", - "integrity": "sha512-c6AEV4XDsIGT0+gwe8MNfRldtZfZaCs+ge2R1p9fkRwQd/nu8dJFVspuu0/EyHBtjm1F9y+6Drs3yyLFK3M+ug==", "requires": { "prop-types": "^15.5.10", "react-select": "^1.2.1" @@ -51408,7 +54855,6 @@ "dependencies": { "react-select": { "version": "1.3.0", - "integrity": "sha512-g/QAU1HZrzSfxkwMAo/wzi6/ezdWye302RGZevsATec07hI/iSxcpB1hejFIp7V63DJ8mwuign6KmB3VjdlinQ==", "requires": { "classnames": "^2.2.4", "prop-types": "^15.5.8", @@ -51419,7 +54865,6 @@ }, "@data-ui/histogram": { "version": "0.0.84", - "integrity": "sha512-JuAUd3cgbDvXd1PKddB3L3SvZj5VFXTLG9za0RlqgbEsddR2dgUfJJQ5GacJ7a3o/SpmJ0zRGJVXb5VZozjj2Q==", "requires": { "@data-ui/shared": "^0.0.84", "@data-ui/theme": "^0.0.84", @@ -51442,7 +54887,6 @@ "dependencies": { "@vx/axis": { "version": "0.0.179", - "integrity": "sha512-FtUcdJxejYn5jgixSgSk9AdA96VwP9sCRATVfGvugEL0gtTKWYDbJEgSgqXfKqpeUdsDdf/JT7NVbLMc1hzrZg==", "requires": { "@vx/group": "0.0.170", "@vx/point": "0.0.165", @@ -51454,21 +54898,18 @@ }, "@vx/bounds": { "version": "0.0.165", - "integrity": "sha512-ZvRb72/4QNs1ZrytZTZxd0hfAb/KKfhsdkcYtIQkmdF6dTsjigMQZ+h2bLvLnbZb/RxyCCoxdiZSGXd+T1c//Q==", "requires": { "prop-types": "^15.5.10" } }, "@vx/event": { "version": "0.0.179", - "integrity": "sha512-wEwqKsxrzoRV/A9Va/f/CHPmV9asrTH/kW/f88jCydsVXd5W/nrJZiVpozN2Zr1Ernv0i1gW5896FWo/LHRg0A==", "requires": { "@vx/point": "0.0.165" } }, "@vx/glyph": { "version": "0.0.179", - "integrity": "sha512-RO7adwyG+9gGzjFdfmplrojgWCT+gsOnIFcRgJNJjx41+P6hWdI9X4OpsLx8VVqNhp7g+hxBDZWte8AxTvLQGw==", "requires": { "@vx/group": "0.0.170", "classnames": "^2.2.5", @@ -51478,7 +54919,6 @@ }, "@vx/gradient": { "version": "0.0.165", - "integrity": "sha512-FjRXMTmcy7k0TWsfDzWWXw6T9WXKP+6LS/GRgnguq271pab/P+AdOJThsVxtBgUc8ZOAPbub3/2Gggz9d8tocg==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.5.7" @@ -51486,26 +54926,22 @@ }, "@vx/group": { "version": "0.0.170", - "integrity": "sha512-RnDdRoy0YI5hokk+YWXc8t39Kp51i4BdCpiwkDJU4YypGycTYnDFjicam6jigUmZ/6wyMirDf/aQboWviFLt2Q==", "requires": { "classnames": "^2.2.5" } }, "@vx/pattern": { "version": "0.0.179", - "integrity": "sha512-qvJsK07oUnSbuzj9jo7b/1Up13DknIeTlj9FDIhg0UNmz90ikVN2CZIWtdJyc2I1AFDEg0odOqYXzUx9aEBRfg==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.5.10" } }, "@vx/point": { - "version": "0.0.165", - "integrity": "sha512-spoHilhjcWNgccrSzBUPw+PXV81tYxeyEWBkgr35aGVU4m7YT86Ywvfemwp7AVVGPn+XJHrhB0ujAhDoyqFPoA==" + "version": "0.0.165" }, "@vx/responsive": { "version": "0.0.192", - "integrity": "sha512-HaXVwhSJXUfRbzRV+glxsX0ki2Hi1mdpz42iuGArVQgDPJEmBHjkXyoiXU8U6v66M7FAH+OyKgtc5j2bfhyYzA==", "requires": { "lodash": "^4.17.10", "prop-types": "^15.6.1", @@ -51514,14 +54950,12 @@ }, "@vx/scale": { "version": "0.0.179", - "integrity": "sha512-j40WiGu4VcHZdaSQAl12ig2w5c4Q9EVn7qqYf9PX7uoS5PbxRYNnHeKZ7e5Bf8O6b57iv5jFTfUV7HkpNF4vvg==", "requires": { "d3-scale": "^2.0.0" }, "dependencies": { "d3-scale": { "version": "2.2.2", - "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", "requires": { "d3-array": "^1.2.0", "d3-collection": "1", @@ -51535,7 +54969,6 @@ }, "@vx/shape": { "version": "0.0.179", - "integrity": "sha512-YHVNx4xGpbjolkW3Lb5pEgJB0+u349vfnLI976DJlinY0hRNa4TZbWXOB4ywLIrYzQEXXPMUR8WtdubNxg6g0w==", "requires": { "@vx/curve": "0.0.165", "@vx/group": "0.0.170", @@ -51548,7 +54981,6 @@ }, "@vx/tooltip": { "version": "0.0.179", - "integrity": "sha512-BjMURtNpc1g3Li00iHt4bA9lbhk1FnsxCemYI1OF5tSSKHHal2ZAdxRS7o1sR9+jIa3RyD9flfIa1ibtrJh2Ew==", "requires": { "@vx/bounds": "0.0.165", "classnames": "^2.2.5", @@ -51557,7 +54989,6 @@ }, "d3-scale": { "version": "1.0.7", - "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", "requires": { "d3-array": "^1.2.0", "d3-collection": "1", @@ -51569,14 +55000,12 @@ } }, "resize-observer-polyfill": { - "version": "1.5.0", - "integrity": "sha512-M2AelyJDVR/oLnToJLtuDJRBBWUGUvvGigj1411hXhAdyFWqMaqHp7TixW3FpiLuVaikIcR1QL+zqoJoZlOgpg==" + "version": "1.5.0" } } }, "@data-ui/radial-chart": { "version": "0.0.84", - "integrity": "sha512-YKvcrtXD+RnZIngB398exuGICIwbQeVbV3Sbqg6txd4dVN9ixsvOFHCaNO5ugqMcyVeFGpMZAtGeau5kUZa73Q==", "requires": { "@data-ui/shared": "^0.0.84", "@data-ui/theme": "^0.0.84", @@ -51590,7 +55019,6 @@ }, "@data-ui/shared": { "version": "0.0.84", - "integrity": "sha512-MsDLsFzBHFEREr/eF2/RX1o/cXioEg+VQTsM8gViW5ywGQ7Xo5+EqUOaBSrwqKAkvp3e8PaEZVkchPC54IBhrA==", "requires": { "@data-ui/theme": "^0.0.84", "@vx/event": "^0.0.165", @@ -51603,32 +55031,27 @@ "dependencies": { "@vx/bounds": { "version": "0.0.165", - "integrity": "sha512-ZvRb72/4QNs1ZrytZTZxd0hfAb/KKfhsdkcYtIQkmdF6dTsjigMQZ+h2bLvLnbZb/RxyCCoxdiZSGXd+T1c//Q==", "requires": { "prop-types": "^15.5.10" } }, "@vx/event": { "version": "0.0.165", - "integrity": "sha512-FsQiw0f3s5DQB6aBQmBcoWk9e4q65LcDobHIyV8qrmpW2QgV2NvQFM1w0Q300ohpRMgJDzGk68HHHQgFOJvApw==", "requires": { "@vx/point": "0.0.165" } }, "@vx/group": { "version": "0.0.165", - "integrity": "sha512-gi1DSg8AAaVRseyWiq8y4bzyvKiQIXT6vDUYBVRmv2LBcpHocBGaxNiNK0X602RgLG0XmNyRv6qSCWLOaBs3Mg==", "requires": { "classnames": "^2.2.5" } }, "@vx/point": { - "version": "0.0.165", - "integrity": "sha512-spoHilhjcWNgccrSzBUPw+PXV81tYxeyEWBkgr35aGVU4m7YT86Ywvfemwp7AVVGPn+XJHrhB0ujAhDoyqFPoA==" + "version": "0.0.165" }, "@vx/shape": { "version": "0.0.168", - "integrity": "sha512-urKZkwSafMpPQ0wI/L5FJmufRiAR4UsgYUCKxROjfE1Cf4jWNlK6mlVIIASxCdHlh9CGBbIrRMdl5Yv5lzqhjA==", "requires": { "@vx/curve": "0.0.165", "@vx/group": "0.0.165", @@ -51641,7 +55064,6 @@ }, "@vx/tooltip": { "version": "0.0.165", - "integrity": "sha512-/x1NZc67QGQ4e/WNT7Ks5LYRyeLSqp8lG04gX5J6leUS0zscAVzo3aE5u65Qqbc0cnMyMPRZ2Qtb4klWTLg+eQ==", "requires": { "@vx/bounds": "0.0.165", "classnames": "^2.2.5", @@ -51652,7 +55074,6 @@ }, "@data-ui/sparkline": { "version": "0.0.84", - "integrity": "sha512-Ja7T2JjioZtnoy0PEXF72qv/J8xIotu+oS1Z+ygVGZni6aN/DUY35eGpg/DDeemEFDMoifcx+kYa5LU7hQCnJg==", "requires": { "@data-ui/shared": "^0.0.84", "@data-ui/theme": "^0.0.8", @@ -51672,12 +55093,10 @@ }, "dependencies": { "@data-ui/theme": { - "version": "0.0.8", - "integrity": "sha512-mK80ALqWVQkefstoBY9dsKd6GvQmyMsoxFC+ma/IX6aPphWYuVmtSEA6mcn9Snh/dK9QU0qR0oiEklImyfzwBg==" + "version": "0.0.8" }, "@vx/axis": { "version": "0.0.179", - "integrity": "sha512-FtUcdJxejYn5jgixSgSk9AdA96VwP9sCRATVfGvugEL0gtTKWYDbJEgSgqXfKqpeUdsDdf/JT7NVbLMc1hzrZg==", "requires": { "@vx/group": "0.0.170", "@vx/point": "0.0.165", @@ -51689,14 +55108,12 @@ }, "@vx/event": { "version": "0.0.179", - "integrity": "sha512-wEwqKsxrzoRV/A9Va/f/CHPmV9asrTH/kW/f88jCydsVXd5W/nrJZiVpozN2Zr1Ernv0i1gW5896FWo/LHRg0A==", "requires": { "@vx/point": "0.0.165" } }, "@vx/glyph": { "version": "0.0.179", - "integrity": "sha512-RO7adwyG+9gGzjFdfmplrojgWCT+gsOnIFcRgJNJjx41+P6hWdI9X4OpsLx8VVqNhp7g+hxBDZWte8AxTvLQGw==", "requires": { "@vx/group": "0.0.170", "classnames": "^2.2.5", @@ -51706,7 +55123,6 @@ }, "@vx/gradient": { "version": "0.0.165", - "integrity": "sha512-FjRXMTmcy7k0TWsfDzWWXw6T9WXKP+6LS/GRgnguq271pab/P+AdOJThsVxtBgUc8ZOAPbub3/2Gggz9d8tocg==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.5.7" @@ -51714,26 +55130,22 @@ }, "@vx/group": { "version": "0.0.170", - "integrity": "sha512-RnDdRoy0YI5hokk+YWXc8t39Kp51i4BdCpiwkDJU4YypGycTYnDFjicam6jigUmZ/6wyMirDf/aQboWviFLt2Q==", "requires": { "classnames": "^2.2.5" } }, "@vx/pattern": { "version": "0.0.179", - "integrity": "sha512-qvJsK07oUnSbuzj9jo7b/1Up13DknIeTlj9FDIhg0UNmz90ikVN2CZIWtdJyc2I1AFDEg0odOqYXzUx9aEBRfg==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.5.10" } }, "@vx/point": { - "version": "0.0.165", - "integrity": "sha512-spoHilhjcWNgccrSzBUPw+PXV81tYxeyEWBkgr35aGVU4m7YT86Ywvfemwp7AVVGPn+XJHrhB0ujAhDoyqFPoA==" + "version": "0.0.165" }, "@vx/responsive": { "version": "0.0.192", - "integrity": "sha512-HaXVwhSJXUfRbzRV+glxsX0ki2Hi1mdpz42iuGArVQgDPJEmBHjkXyoiXU8U6v66M7FAH+OyKgtc5j2bfhyYzA==", "requires": { "lodash": "^4.17.10", "prop-types": "^15.6.1", @@ -51742,14 +55154,12 @@ }, "@vx/scale": { "version": "0.0.179", - "integrity": "sha512-j40WiGu4VcHZdaSQAl12ig2w5c4Q9EVn7qqYf9PX7uoS5PbxRYNnHeKZ7e5Bf8O6b57iv5jFTfUV7HkpNF4vvg==", "requires": { "d3-scale": "^2.0.0" } }, "@vx/shape": { "version": "0.0.179", - "integrity": "sha512-YHVNx4xGpbjolkW3Lb5pEgJB0+u349vfnLI976DJlinY0hRNa4TZbWXOB4ywLIrYzQEXXPMUR8WtdubNxg6g0w==", "requires": { "@vx/curve": "0.0.165", "@vx/group": "0.0.170", @@ -51761,18 +55171,15 @@ } }, "resize-observer-polyfill": { - "version": "1.5.0", - "integrity": "sha512-M2AelyJDVR/oLnToJLtuDJRBBWUGUvvGigj1411hXhAdyFWqMaqHp7TixW3FpiLuVaikIcR1QL+zqoJoZlOgpg==" + "version": "1.5.0" } } }, "@data-ui/theme": { - "version": "0.0.84", - "integrity": "sha512-jIoHftC/5c/LVJYF4VSBjjVjrjc0yj4mLkGe8p0eVO7qUYKVvlWx7PrpM7ucyefvuAaKIwlr+Nh2xPGPdADjaA==" + "version": "0.0.84" }, "@data-ui/xy-chart": { "version": "0.0.84", - "integrity": "sha512-4mRWEGfeQJ2kFXmQ81k1gDPx2zdkty6lt0+srui4zleSyhnBv1dmm9J03dq+qwr7+bpzjfq77nINV5HXWb31Bg==", "requires": { "@data-ui/shared": "^0.0.84", "@data-ui/theme": "^0.0.84", @@ -51799,7 +55206,6 @@ "dependencies": { "@vx/axis": { "version": "0.0.175", - "integrity": "sha512-qVRIHurnbPnRF4p0KQITArOUSF564tWW1pc48giLz+DJGlcJ4H9RfOSTpV6rnnP15xto6pQdQehBgBAvFRmoig==", "requires": { "@vx/group": "0.0.170", "@vx/point": "0.0.165", @@ -51811,14 +55217,12 @@ "dependencies": { "@vx/group": { "version": "0.0.170", - "integrity": "sha512-RnDdRoy0YI5hokk+YWXc8t39Kp51i4BdCpiwkDJU4YypGycTYnDFjicam6jigUmZ/6wyMirDf/aQboWviFLt2Q==", "requires": { "classnames": "^2.2.5" } }, "@vx/shape": { "version": "0.0.175", - "integrity": "sha512-bjAJoIIpKjUEPDV2xmTYGUvSvwRztv+6rd1c6NPZG/nIuqsMHFnFig/2xTcQJEQhRg6aKzvxIUo43zPSSq3fWA==", "requires": { "@vx/curve": "0.0.165", "@vx/group": "0.0.170", @@ -51831,7 +55235,6 @@ }, "@vx/text": { "version": "0.0.175", - "integrity": "sha512-SOBhctXXAGhhpCOiTjxOM/8NDaDqGRk3OGfsJ714Mt1UJX6VQaKxFocZJwn6IMw3mNG6/p7O4Eao/gGDcoM6+A==", "requires": { "babel-plugin-lodash": "^3.3.2", "classnames": "^2.2.5", @@ -51843,21 +55246,18 @@ }, "@vx/bounds": { "version": "0.0.165", - "integrity": "sha512-ZvRb72/4QNs1ZrytZTZxd0hfAb/KKfhsdkcYtIQkmdF6dTsjigMQZ+h2bLvLnbZb/RxyCCoxdiZSGXd+T1c//Q==", "requires": { "prop-types": "^15.5.10" } }, "@vx/event": { "version": "0.0.165", - "integrity": "sha512-FsQiw0f3s5DQB6aBQmBcoWk9e4q65LcDobHIyV8qrmpW2QgV2NvQFM1w0Q300ohpRMgJDzGk68HHHQgFOJvApw==", "requires": { "@vx/point": "0.0.165" } }, "@vx/glyph": { "version": "0.0.165", - "integrity": "sha512-kccUm40e/VCtayxqvcwc2K2M6oNXO7IafwIfw1RRv6Fj4Iutto9ZpI+PGOf/zPnYVueoLnWBXT/HE7IRS+C2gw==", "requires": { "@vx/group": "0.0.165", "classnames": "^2.2.5", @@ -51866,7 +55266,6 @@ }, "@vx/gradient": { "version": "0.0.165", - "integrity": "sha512-FjRXMTmcy7k0TWsfDzWWXw6T9WXKP+6LS/GRgnguq271pab/P+AdOJThsVxtBgUc8ZOAPbub3/2Gggz9d8tocg==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.5.7" @@ -51874,7 +55273,6 @@ }, "@vx/grid": { "version": "0.0.180", - "integrity": "sha512-+ugS0c6GbwHr6pFU0znnOG3/zTwRRadvWwj3E4ZOHmKUSz6ZEN6JNo+rD3WSZckYwLis6UivmYfJ5cV6AM4ufg==", "requires": { "@vx/group": "0.0.170", "@vx/point": "0.0.165", @@ -51885,14 +55283,12 @@ "dependencies": { "@vx/group": { "version": "0.0.170", - "integrity": "sha512-RnDdRoy0YI5hokk+YWXc8t39Kp51i4BdCpiwkDJU4YypGycTYnDFjicam6jigUmZ/6wyMirDf/aQboWviFLt2Q==", "requires": { "classnames": "^2.2.5" } }, "@vx/shape": { "version": "0.0.179", - "integrity": "sha512-YHVNx4xGpbjolkW3Lb5pEgJB0+u349vfnLI976DJlinY0hRNa4TZbWXOB4ywLIrYzQEXXPMUR8WtdubNxg6g0w==", "requires": { "@vx/curve": "0.0.165", "@vx/group": "0.0.170", @@ -51907,26 +55303,22 @@ }, "@vx/group": { "version": "0.0.165", - "integrity": "sha512-gi1DSg8AAaVRseyWiq8y4bzyvKiQIXT6vDUYBVRmv2LBcpHocBGaxNiNK0X602RgLG0XmNyRv6qSCWLOaBs3Mg==", "requires": { "classnames": "^2.2.5" } }, "@vx/pattern": { "version": "0.0.165", - "integrity": "sha512-h5nmfcYlQYYzNhlhqaYUvVnkmGnC0yWv5yU1snjHweGmIHTovV3RAbKgVFAP7kB3i2rbEtC3O8WkJN++cZdLzA==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.5.10" } }, "@vx/point": { - "version": "0.0.165", - "integrity": "sha512-spoHilhjcWNgccrSzBUPw+PXV81tYxeyEWBkgr35aGVU4m7YT86Ywvfemwp7AVVGPn+XJHrhB0ujAhDoyqFPoA==" + "version": "0.0.165" }, "@vx/responsive": { "version": "0.0.192", - "integrity": "sha512-HaXVwhSJXUfRbzRV+glxsX0ki2Hi1mdpz42iuGArVQgDPJEmBHjkXyoiXU8U6v66M7FAH+OyKgtc5j2bfhyYzA==", "requires": { "lodash": "^4.17.10", "prop-types": "^15.6.1", @@ -51935,14 +55327,12 @@ }, "@vx/scale": { "version": "0.0.165", - "integrity": "sha512-5jSgXJDU6J/KWIyCbpjHqysPCddp7tG3LbTV7UmtB1Qleb4m4slShTVSE7+EKU+zgiQPDGm0+E2ht4cet+7F7A==", "requires": { "d3-scale": "^2.0.0" } }, "@vx/shape": { "version": "0.0.165", - "integrity": "sha512-D9naH/glDtw8J8IcdumpRz1ihaoCAYMwFNh2KTv73HiTKrLQSXvIjwYFv9C0b8BCPNOXkDZS8s+AlgMSqGlZNQ==", "requires": { "@vx/curve": "0.0.165", "@vx/group": "0.0.165", @@ -51955,7 +55345,6 @@ }, "@vx/text": { "version": "0.0.192", - "integrity": "sha512-lyy7eXfmQ8SJF7Qx+bCRcaEgvVSa18Lp6eRMo3GMANumUh9kSe7LwgqRFSdBJ85WkPqX+UOkJVyCH7AOlt0IWA==", "requires": { "classnames": "^2.2.5", "lodash": "^4.17.15", @@ -51965,7 +55354,6 @@ }, "@vx/tooltip": { "version": "0.0.165", - "integrity": "sha512-/x1NZc67QGQ4e/WNT7Ks5LYRyeLSqp8lG04gX5J6leUS0zscAVzo3aE5u65Qqbc0cnMyMPRZ2Qtb4klWTLg+eQ==", "requires": { "@vx/bounds": "0.0.165", "classnames": "^2.2.5", @@ -51973,14 +55361,12 @@ } }, "resize-observer-polyfill": { - "version": "1.5.0", - "integrity": "sha512-M2AelyJDVR/oLnToJLtuDJRBBWUGUvvGigj1411hXhAdyFWqMaqHp7TixW3FpiLuVaikIcR1QL+zqoJoZlOgpg==" + "version": "1.5.0" } } }, "@deck.gl/aggregation-layers": { "version": "8.5.2", - "integrity": "sha512-oiqXPmyn2v0lX9tWCvgmWs29stHSLS3tje71Ff2FVXDNmvP5FoZItFa8y7O7KSTkej2/rSwZeSte/a9pri6Njg==", "requires": { "@luma.gl/shadertools": "^8.5.4", "@math.gl/web-mercator": "^3.5.3", @@ -51989,7 +55375,6 @@ }, "@deck.gl/carto": { "version": "8.5.2", - "integrity": "sha512-Kw/3NUM+2NcHjxH6b7IOUYXEwmJ4SNQujFzAVFW5amG4Lut8074NGSF5XHi+4M/zgk7vXDFsGRxLqspsA/dg8w==", "requires": { "@loaders.gl/loader-utils": "^3.0.6", "@loaders.gl/mvt": "^3.0.6", @@ -52001,14 +55386,12 @@ "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } }, "d3-scale": { "version": "3.3.0", - "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", "requires": { "d3-array": "^2.3.0", "d3-format": "1 - 2", @@ -52019,7 +55402,6 @@ }, "d3-time": { "version": "2.1.1", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", "requires": { "d3-array": "2" } @@ -52028,7 +55410,6 @@ }, "@deck.gl/core": { "version": "8.5.2", - "integrity": "sha512-SAFv7fKx6k1Rj8R4qTMQO2wEhEfixROzbcoSS6RivxrfES00KYYj6jJ7iNEnq3dFn6qc37LPpxqtYYHO4BcvYA==", "requires": { "@loaders.gl/core": "^3.0.6", "@loaders.gl/images": "^3.0.6", @@ -52042,14 +55423,12 @@ }, "@deck.gl/extensions": { "version": "8.5.2", - "integrity": "sha512-VhbQsMNPM7RCR/ERwb1u1x0rEWAxgXfcCWttW+gYvbiagW/LrAJ22jhOghlRW/wilEmupHYbXQlWkW2V/mYfsg==", "requires": { "@luma.gl/shadertools": "^8.5.4" } }, "@deck.gl/geo-layers": { "version": "8.5.2", - "integrity": "sha512-t6+TgAdbKWDw8g9UX1y6D+5twcdJuKaXw4qSib/0yVurWi/Mil5Plihybt1l9uBZuwkr+UcpxPR73zzo+qd9MA==", "requires": { "@loaders.gl/3d-tiles": "^3.0.6", "@loaders.gl/gis": "^3.0.6", @@ -52066,12 +55445,10 @@ } }, "@deck.gl/google-maps": { - "version": "8.5.2", - "integrity": "sha512-Dk3ozenBWgt9nFSYOT4N82urNW/JhiMszfFq6zLt3jUp0N7EJ9d2XO81hclM59BhjIdGWb6drTe96NvtbabVLQ==" + "version": "8.5.2" }, "@deck.gl/json": { "version": "8.5.2", - "integrity": "sha512-lVS16bvPfLUSidgBURZvGbWEjgK8GjLWlp1iGuLvua2W6TnWIyiKa6a3XoebgeXd8kqwSbQxhNnuSVPX+Di6Rg==", "requires": { "d3-dsv": "^1.0.8", "expression-eval": "^2.0.0" @@ -52079,7 +55456,6 @@ }, "@deck.gl/layers": { "version": "8.5.2", - "integrity": "sha512-HmpE3qf9CI7sU/xa2DMCNg31pzpzK5XuUHyC70dsLq8AV7Sm3vZQz17KMU/CWSZpVr7yQ8uxTeSQARiv/zeOFQ==", "requires": { "@loaders.gl/images": "^3.0.6", "@mapbox/tiny-sdf": "^1.1.0", @@ -52088,12 +55464,10 @@ } }, "@deck.gl/mapbox": { - "version": "8.5.2", - "integrity": "sha512-nMpzfdPFBVthT+EMgIcKo4YO6bZCqADQtqnxIFtfofZIiKS6R5OSuJ3sXPSNZ9ReCJGzdmndEz7/Qtm9Sia/bA==" + "version": "8.5.2" }, "@deck.gl/mesh-layers": { "version": "8.5.2", - "integrity": "sha512-dUfQyGjm5CYQg9AQdRsGtEEXGSGHxifPlws0zWWoj1r757wjqM0aZ663TUJEsJQDTLNOvbBLGTiuFeCBUoKO4Q==", "requires": { "@loaders.gl/gltf": "^3.0.6", "@luma.gl/experimental": "^8.5.4", @@ -52102,18 +55476,15 @@ }, "@deck.gl/react": { "version": "8.5.2", - "integrity": "sha512-h7AJ9nPY1PTjrAVP7T1fvWDChWZrVOsEfYIoEP4W6ILSjvDqEQfVL0+9RhjUwQV2nKrg0QmpqCmbfOrgKQQbYw==", "requires": { "prop-types": "^15.6.0" } }, "@discoveryjs/json-ext": { - "version": "0.5.3", - "integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==" + "version": "0.5.7" }, "@emotion/babel-plugin": { "version": "11.3.0", - "integrity": "sha512-UZKwBV2rADuhRp+ZOGgNWg2eYgbzKzQXfQPtJbu/PLy8onurxlNCLvxMQEvlr1/GudguPI5IU9qIY1+2z1M5bA==", "requires": { "@babel/helper-module-imports": "^7.12.13", "@babel/plugin-syntax-jsx": "^7.12.13", @@ -52130,12 +55501,10 @@ }, "dependencies": { "@emotion/memoize": { - "version": "0.7.5", - "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + "version": "0.7.5" }, "@emotion/serialize": { "version": "1.0.2", - "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==", "requires": { "@emotion/hash": "^0.8.0", "@emotion/memoize": "^0.7.4", @@ -52145,29 +55514,24 @@ } }, "@emotion/utils": { - "version": "1.0.0", - "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==" + "version": "1.0.0" }, "csstype": { - "version": "3.0.8", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" + "version": "3.0.8" }, "escape-string-regexp": { - "version": "4.0.0", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + "version": "4.0.0" } } }, "@emotion/babel-plugin-jsx-pragmatic": { "version": "0.1.5", - "integrity": "sha512-y+3AJ0SItMDaAgGPVkQBC/S/BaqaPACkQ6MyCI2CUlrjTxKttTVfD3TMtcs7vLEcLxqzZ1xiG0vzwCXjhopawQ==", "requires": { "@babel/plugin-syntax-jsx": "^7.2.0" } }, "@emotion/babel-preset-css-prop": { "version": "11.2.0", - "integrity": "sha512-9XLQm2eLPYTho+Cx1LQTDA1rATjoAaB4O+ds55XDvoAa+Z16Hhg8y5Vihj3C8E6+ilDM8SV5A9Z6z+yj0YIRBg==", "requires": { "@babel/plugin-transform-react-jsx": "^7.12.1", "@babel/runtime": "^7.7.2", @@ -52177,7 +55541,6 @@ }, "@emotion/cache": { "version": "11.4.0", - "integrity": "sha512-Zx70bjE7LErRO9OaZrhf22Qye1y4F7iDl+ITjet0J+i+B88PrAOBkKvaAWhxsZf72tDLajwCgfCjJ2dvH77C3g==", "requires": { "@emotion/memoize": "^0.7.4", "@emotion/sheet": "^1.0.0", @@ -52187,18 +55550,15 @@ }, "dependencies": { "@emotion/sheet": { - "version": "1.0.2", - "integrity": "sha512-QQPB1B70JEVUHuNtzjHftMGv6eC3Y9wqavyarj4x4lg47RACkeSfNo5pxIOKizwS9AEFLohsqoaxGQj4p0vSIw==" + "version": "1.0.2" }, "@emotion/utils": { - "version": "1.0.0", - "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==" + "version": "1.0.0" } } }, "@emotion/core": { "version": "10.1.1", - "integrity": "sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA==", "requires": { "@babel/runtime": "^7.5.5", "@emotion/cache": "^10.0.27", @@ -52210,7 +55570,6 @@ "dependencies": { "@emotion/cache": { "version": "10.0.29", - "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", "requires": { "@emotion/sheet": "0.9.4", "@emotion/stylis": "0.8.5", @@ -52222,7 +55581,6 @@ }, "@emotion/css": { "version": "10.0.27", - "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", "requires": { "@emotion/serialize": "^0.11.15", "@emotion/utils": "0.11.3", @@ -52231,7 +55589,6 @@ }, "@emotion/css-prettifier": { "version": "1.0.0", - "integrity": "sha512-efxSrRTiTqHTQVKW15Gz5H4pNAw8OqcG8NaiwkJIkqIdNXTD4Qr1zC1Ou6r2acd1oJJ2s56nb1ClnXMiWoj6gQ==", "dev": true, "requires": { "@emotion/memoize": "^0.7.4", @@ -52239,19 +55596,16 @@ } }, "@emotion/hash": { - "version": "0.8.0", - "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + "version": "0.8.0" }, "@emotion/is-prop-valid": { "version": "0.8.8", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", "requires": { "@emotion/memoize": "0.7.4" } }, "@emotion/jest": { "version": "11.3.0", - "integrity": "sha512-LZqYc3yerhic1IvAcEwBLRs1DsUt3oY7Oz6n+e+HU32iYOK/vpfzlhgmQURE94BHfv6eCOj6DV38f3jSnIkBkQ==", "dev": true, "requires": { "@babel/runtime": "^7.13.10", @@ -52262,12 +55616,10 @@ } }, "@emotion/memoize": { - "version": "0.7.4", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + "version": "0.7.4" }, "@emotion/react": { "version": "11.4.1", - "integrity": "sha512-pRegcsuGYj4FCdZN6j5vqCALkNytdrKw3TZMekTzNXixRg4wkLsU5QEaBG5LC6l01Vppxlp7FE3aTHpIG5phLg==", "requires": { "@babel/runtime": "^7.13.10", "@emotion/cache": "^11.4.0", @@ -52280,7 +55632,6 @@ "dependencies": { "@emotion/serialize": { "version": "1.0.2", - "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==", "requires": { "@emotion/hash": "^0.8.0", "@emotion/memoize": "^0.7.4", @@ -52290,22 +55641,18 @@ } }, "@emotion/sheet": { - "version": "1.0.2", - "integrity": "sha512-QQPB1B70JEVUHuNtzjHftMGv6eC3Y9wqavyarj4x4lg47RACkeSfNo5pxIOKizwS9AEFLohsqoaxGQj4p0vSIw==" + "version": "1.0.2" }, "@emotion/utils": { - "version": "1.0.0", - "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==" + "version": "1.0.0" }, "csstype": { - "version": "3.0.8", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" + "version": "3.0.8" } } }, "@emotion/serialize": { "version": "0.11.16", - "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", "requires": { "@emotion/hash": "0.8.0", "@emotion/memoize": "0.7.4", @@ -52315,12 +55662,10 @@ } }, "@emotion/sheet": { - "version": "0.9.4", - "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==" + "version": "0.9.4" }, "@emotion/styled": { "version": "11.3.0", - "integrity": "sha512-fUoLcN3BfMiLlRhJ8CuPUMEyKkLEoM+n+UyAbnqGEsCd5IzKQ7VQFLtzpJOaCD2/VR2+1hXQTnSZXVJeiTNltA==", "requires": { "@babel/runtime": "^7.13.10", "@emotion/babel-plugin": "^11.3.0", @@ -52331,14 +55676,12 @@ "dependencies": { "@emotion/is-prop-valid": { "version": "1.1.0", - "integrity": "sha512-9RkilvXAufQHsSsjQ3PIzSns+pxuX4EW8EbGeSPjZMHuMx6z/MOzb9LpqNieQX4F3mre3NWS2+X3JNRHTQztUQ==", "requires": { "@emotion/memoize": "^0.7.4" } }, "@emotion/serialize": { "version": "1.0.2", - "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==", "requires": { "@emotion/hash": "^0.8.0", "@emotion/memoize": "^0.7.4", @@ -52348,18 +55691,15 @@ } }, "@emotion/utils": { - "version": "1.0.0", - "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==" + "version": "1.0.0" }, "csstype": { - "version": "3.0.8", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" + "version": "3.0.8" } } }, "@emotion/styled-base": { "version": "10.3.0", - "integrity": "sha512-PBRqsVKR7QRNkmfH78hTSSwHWcwDpecH9W6heujWAcyp2wdz/64PP73s7fWS1dIPm8/Exc8JAzYS8dEWXjv60w==", "requires": { "@babel/runtime": "^7.5.5", "@emotion/is-prop-valid": "0.8.8", @@ -52368,24 +55708,19 @@ } }, "@emotion/stylis": { - "version": "0.8.5", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + "version": "0.8.5" }, "@emotion/unitless": { - "version": "0.7.5", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + "version": "0.7.5" }, "@emotion/utils": { - "version": "0.11.3", - "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + "version": "0.11.3" }, - "@emotion/weak-memoize": { - "version": "0.2.5", - "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" + "@emotion/weak-memoize": { + "version": "0.2.5" }, "@encodable/color": { "version": "1.1.1", - "integrity": "sha512-3QlHqsaD+D4W4T6E4Wq4mp7MBpt5yCkCmgTh6AfsoUfJeAEogA92d8r3Y67Zuppcs/eepHW0ip8zfehS2jZNkQ==", "requires": { "@encodable/registry": "^1.0.3", "@types/d3-interpolate": "^1.3.1", @@ -52398,32 +55733,27 @@ "dependencies": { "@types/d3-scale": { "version": "3.3.2", - "integrity": "sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ==", "requires": { "@types/d3-time": "^2" } }, "@types/d3-time": { - "version": "2.1.1", - "integrity": "sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg==" + "version": "2.1.1" }, "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } }, "d3-interpolate": { "version": "2.0.1", - "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", "requires": { "d3-color": "1 - 2" } }, "d3-scale": { "version": "3.3.0", - "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", "requires": { "d3-array": "^2.3.0", "d3-format": "1 - 2", @@ -52434,7 +55764,6 @@ }, "d3-time": { "version": "2.1.1", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", "requires": { "d3-array": "2" } @@ -52443,7 +55772,6 @@ }, "@encodable/format": { "version": "1.0.6", - "integrity": "sha512-gtzLMQyw4AJ7m3TIANm2z2QfzZJLGLdhVmKbizRRu9MRMlYIVXhk+46zPm10RNxGv4ybpsfcCfkCd4nL3RlZRg==", "requires": { "@encodable/registry": "^1.0.3", "@types/d3-format": "^1.3.1", @@ -52456,25 +55784,21 @@ "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } }, "d3-format": { - "version": "2.0.0", - "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" + "version": "2.0.0" }, "d3-time": { "version": "2.1.1", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", "requires": { "d3-array": "2" } }, "d3-time-format": { "version": "3.0.0", - "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", "requires": { "d3-time": "1 - 2" } @@ -52482,12 +55806,10 @@ } }, "@encodable/registry": { - "version": "1.0.3", - "integrity": "sha512-YH2nSBZJKgbH/9MkQXzAEE9UwTaVcWiKgVFyEU/gvrfmNWqecYaHMTyObo+ADSTGF4kk0cZZkr7VqZgIQbvrUw==" + "version": "1.0.3" }, "@eslint/eslintrc": { "version": "0.4.3", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -52503,7 +55825,6 @@ "dependencies": { "debug": { "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -52511,7 +55832,6 @@ }, "globals": { "version": "13.12.0", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -52519,27 +55839,22 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "type-fest": { "version": "0.20.2", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true } } }, "@fontsource/inter": { - "version": "4.0.0", - "integrity": "sha512-zc9DDGEz0cgftT6VbHPrdBBVaBQrK4P6UDuuNrib1KNnbDCY1zHTMwYiN2XH6SFDufRKnsjUR5cEeWDANDDaYw==" + "version": "4.0.0" }, "@gar/promisify": { - "version": "1.1.2", - "integrity": "sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==" + "version": "1.1.3" }, "@hot-loader/react-dom": { "version": "16.13.0", - "integrity": "sha512-lJZrmkucz2MrQJTQtJobx5MICXcfQvKihszqv655p557HPi0hMOWxrNpiHv3DWD8ugNWjtWcVWqRnFvwsHq1mQ==", "dev": true, "requires": { "loose-envify": "^1.1.0", @@ -52550,7 +55865,6 @@ "dependencies": { "scheduler": { "version": "0.19.0", - "integrity": "sha512-xowbVaTPe9r7y7RUejcK73/j8tt2jfiyTednOvHbA8JoClvMYCp+r8QegLwK/n8zWQAtZb1fFnER4XLBZXrCxA==", "dev": true, "requires": { "loose-envify": "^1.1.0", @@ -52561,7 +55875,6 @@ }, "@humanwhocodes/config-array": { "version": "0.5.0", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.0", @@ -52571,7 +55884,6 @@ "dependencies": { "debug": { "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -52579,24 +55891,24 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "@humanwhocodes/object-schema": { "version": "1.2.1", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "@hutson/parse-repository-url": { "version": "3.0.2", - "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", + "dev": true + }, + "@isaacs/string-locale-compare": { + "version": "1.1.0", "dev": true }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "requires": { "camelcase": "^5.3.1", @@ -52608,7 +55920,6 @@ "dependencies": { "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { "locate-path": "^5.0.0", @@ -52617,7 +55928,6 @@ }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { "p-locate": "^4.1.0" @@ -52625,7 +55935,6 @@ }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -52633,7 +55942,6 @@ }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { "p-limit": "^2.2.0" @@ -52641,36 +55949,30 @@ }, "p-try": { "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "path-exists": { "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "resolve-from": { "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true } } }, "@istanbuljs/nyc-config-typescript": { "version": "1.0.1", - "integrity": "sha512-/gz6LgVpky205LuoOfwEZmnUtaSmdk0QIMcNFj9OvxhiMhPpKftMgZmGN7jNj7jR+lr8IB1Yks3QSSSNSxfoaQ==", "dev": true, "requires": { "@istanbuljs/schema": "^0.1.2" } }, "@istanbuljs/schema": { - "version": "0.1.2", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==" + "version": "0.1.2" }, "@jest/console": { "version": "26.6.2", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -52683,7 +55985,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -52691,7 +55992,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -52699,12 +55999,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -52717,7 +56015,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -52726,12 +56023,10 @@ }, "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -52741,7 +56036,6 @@ }, "@jest/core": { "version": "26.6.3", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", "dev": true, "requires": { "@jest/console": "^26.6.2", @@ -52776,12 +56070,10 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -52789,7 +56081,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -52797,12 +56088,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -52815,7 +56104,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -52824,12 +56112,10 @@ }, "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "strip-ansi": { "version": "6.0.0", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { "ansi-regex": "^5.0.0" @@ -52837,7 +56123,6 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -52847,7 +56132,6 @@ }, "@jest/environment": { "version": "26.6.2", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", "dev": true, "requires": { "@jest/fake-timers": "^26.6.2", @@ -52858,7 +56142,6 @@ }, "@jest/fake-timers": { "version": "26.6.2", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -52871,7 +56154,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -52879,7 +56161,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -52887,12 +56168,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -52905,7 +56184,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -52914,7 +56192,6 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -52924,7 +56201,6 @@ }, "@jest/globals": { "version": "26.6.2", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", "dev": true, "requires": { "@jest/environment": "^26.6.2", @@ -52934,7 +56210,6 @@ }, "@jest/reporters": { "version": "26.6.2", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", @@ -52966,7 +56241,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -52974,7 +56248,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -52982,12 +56255,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -53000,7 +56271,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -53009,17 +56279,14 @@ }, "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -53029,7 +56296,6 @@ }, "@jest/source-map": { "version": "26.6.2", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", "dev": true, "requires": { "callsites": "^3.0.0", @@ -53039,14 +56305,12 @@ "dependencies": { "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, "@jest/test-result": { "version": "26.6.2", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", "dev": true, "requires": { "@jest/console": "^26.6.2", @@ -53057,7 +56321,6 @@ }, "@jest/test-sequencer": { "version": "26.6.3", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", "dev": true, "requires": { "@jest/test-result": "^26.6.2", @@ -53069,7 +56332,6 @@ }, "@jest/transform": { "version": "26.6.2", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", "dev": true, "requires": { "@babel/core": "^7.1.0", @@ -53091,7 +56353,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -53099,7 +56360,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -53107,12 +56367,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -53125,7 +56383,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -53134,17 +56391,14 @@ }, "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -53154,7 +56408,6 @@ }, "@jest/types": { "version": "26.6.2", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -53166,7 +56419,6 @@ "dependencies": { "@types/istanbul-reports": { "version": "3.0.0", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", "dev": true, "requires": { "@types/istanbul-lib-report": "*" @@ -53174,139 +56426,404 @@ } } }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0" + }, + "@jridgewell/set-array": { + "version": "1.1.2" + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "dev": true + }, "@lerna/add": { - "version": "4.0.0", - "integrity": "sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/bootstrap": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/npm-conf": "4.0.0", - "@lerna/validation-error": "4.0.0", + "@lerna/bootstrap": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/npm-conf": "6.1.0", + "@lerna/validation-error": "6.1.0", "dedent": "^0.7.0", - "npm-package-arg": "^8.1.0", + "npm-package-arg": "8.1.1", "p-map": "^4.0.0", - "pacote": "^11.2.6", + "pacote": "^13.6.1", "semver": "^7.3.4" }, "dependencies": { + "@npmcli/fs": { + "version": "2.1.2", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "3.0.2", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "dependencies": { + "lru-cache": { + "version": "7.14.1", + "dev": true + } + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/node-gyp": { + "version": "2.0.0", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "3.0.0", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, "@npmcli/run-script": { - "version": "1.8.6", - "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "version": "4.2.1", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + } + }, + "brace-expansion": { + "version": "2.0.1", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "builtins": { + "version": "5.0.1", "dev": true, "requires": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^7.1.0", - "read-package-json-fast": "^2.0.1" + "semver": "^7.0.0" } }, "cacache": { - "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "version": "16.1.3", "dev": true, "requires": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", + "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.0.2", - "unique-filename": "^1.1.1" + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.14.1", + "dev": true + } } }, "chownr": { "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true }, + "glob": { + "version": "8.0.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "hosted-git-info": { + "version": "3.0.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, + "minimatch": { + "version": "5.1.2", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass-fetch": { + "version": "2.1.2", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, "mkdirp": { "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, - "node-gyp": { - "version": "7.1.2", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "npm-install-checks": { + "version": "5.0.0", "dev": true, "requires": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "2.0.0", + "dev": true + }, + "npm-package-arg": { + "version": "8.1.1", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-pick-manifest": { + "version": "7.0.2", + "dev": true, + "requires": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^2.0.0", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + } + } + }, + "npm-registry-fetch": { + "version": "13.3.1", + "dev": true, + "requires": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + } } }, "pacote": { - "version": "11.3.5", - "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "version": "13.6.2", "dev": true, "requires": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.8.2", - "cacache": "^15.0.5", + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", "chownr": "^2.0.0", "fs-minipass": "^2.1.0", "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^11.0.0", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + } } }, + "proc-log": { + "version": "2.0.1", + "dev": true + }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, "ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "version": "9.0.1", "dev": true, "requires": { "minipass": "^3.1.1" } }, + "unique-filename": { + "version": "2.0.1", + "dev": true, + "requires": { + "unique-slug": "^3.0.0" + } + }, + "unique-slug": { + "version": "3.0.0", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -53314,87 +56831,543 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@lerna/bootstrap": { - "version": "4.0.0", - "integrity": "sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw==", - "dev": true, - "requires": { - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/has-npm-version": "4.0.0", - "@lerna/npm-install": "4.0.0", - "@lerna/package-graph": "4.0.0", - "@lerna/pulse-till-done": "4.0.0", - "@lerna/rimraf-dir": "4.0.0", - "@lerna/run-lifecycle": "4.0.0", - "@lerna/run-topologically": "4.0.0", - "@lerna/symlink-binary": "4.0.0", - "@lerna/symlink-dependencies": "4.0.0", - "@lerna/validation-error": "4.0.0", + "version": "6.1.0", + "dev": true, + "requires": { + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/has-npm-version": "6.1.0", + "@lerna/npm-install": "6.1.0", + "@lerna/package-graph": "6.1.0", + "@lerna/pulse-till-done": "6.1.0", + "@lerna/rimraf-dir": "6.1.0", + "@lerna/run-lifecycle": "6.1.0", + "@lerna/run-topologically": "6.1.0", + "@lerna/symlink-binary": "6.1.0", + "@lerna/symlink-dependencies": "6.1.0", + "@lerna/validation-error": "6.1.0", + "@npmcli/arborist": "5.3.0", "dedent": "^0.7.0", "get-port": "^5.1.1", "multimatch": "^5.0.0", - "npm-package-arg": "^8.1.0", - "npmlog": "^4.1.2", + "npm-package-arg": "8.1.1", + "npmlog": "^6.0.2", "p-map": "^4.0.0", "p-map-series": "^2.1.0", "p-waterfall": "^2.1.1", - "read-package-tree": "^5.3.1", "semver": "^7.3.4" }, "dependencies": { + "@npmcli/arborist": { + "version": "5.3.0", + "dev": true, + "requires": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/map-workspaces": "^2.0.3", + "@npmcli/metavuln-calculator": "^3.0.1", + "@npmcli/move-file": "^2.0.0", + "@npmcli/name-from-folder": "^1.0.1", + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/package-json": "^2.0.0", + "@npmcli/run-script": "^4.1.3", + "bin-links": "^3.0.0", + "cacache": "^16.0.6", + "common-ancestor-path": "^1.0.1", + "json-parse-even-better-errors": "^2.3.1", + "json-stringify-nice": "^1.1.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "nopt": "^5.0.0", + "npm-install-checks": "^5.0.0", + "npm-package-arg": "^9.0.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.0", + "npmlog": "^6.0.2", + "pacote": "^13.6.1", + "parse-conflict-json": "^2.0.1", + "proc-log": "^2.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.1", + "read-package-json-fast": "^2.0.2", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^9.0.0", + "treeverse": "^2.0.0", + "walk-up-path": "^1.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + } + } + }, + "@npmcli/fs": { + "version": "2.1.2", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "3.0.2", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "@npmcli/metavuln-calculator": { + "version": "3.1.1", + "dev": true, + "requires": { + "cacache": "^16.0.0", + "json-parse-even-better-errors": "^2.3.1", + "pacote": "^13.0.3", + "semver": "^7.3.5" + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/node-gyp": { + "version": "2.0.0", + "dev": true + }, + "@npmcli/package-json": { + "version": "2.0.0", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.1" + } + }, + "@npmcli/promise-spawn": { + "version": "3.0.0", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "4.2.1", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + } + }, + "bin-links": { + "version": "3.0.3", + "dev": true, + "requires": { + "cmd-shim": "^5.0.0", + "mkdirp-infer-owner": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0", + "read-cmd-shim": "^3.0.0", + "rimraf": "^3.0.0", + "write-file-atomic": "^4.0.0" + } + }, + "brace-expansion": { + "version": "2.0.1", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "builtins": { + "version": "5.0.1", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "cacache": { + "version": "16.1.3", + "dev": true, + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "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": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + } + }, + "chownr": { + "version": "2.0.0", + "dev": true + }, + "cmd-shim": { + "version": "5.0.0", + "dev": true, + "requires": { + "mkdirp-infer-owner": "^2.0.0" + } + }, + "glob": { + "version": "8.0.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "hosted-git-info": { + "version": "3.0.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "just-diff": { + "version": "5.2.0", + "dev": true + }, + "just-diff-apply": { + "version": "5.5.0", + "dev": true + }, "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "7.14.1", + "dev": true + }, + "minimatch": { + "version": "5.1.2", "dev": true, "requires": { - "yallist": "^4.0.0" + "brace-expansion": "^2.0.1" + } + }, + "minipass-fetch": { + "version": "2.1.2", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "mkdirp": { + "version": "1.0.4", + "dev": true + }, + "npm-install-checks": { + "version": "5.0.0", + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "2.0.0", + "dev": true + }, + "npm-package-arg": { + "version": "8.1.1", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-pick-manifest": { + "version": "7.0.2", + "dev": true, + "requires": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^2.0.0", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + } + } + }, + "npm-registry-fetch": { + "version": "13.3.1", + "dev": true, + "requires": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + } + } + }, + "pacote": { + "version": "13.6.2", + "dev": true, + "requires": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + } + } + }, + "parse-conflict-json": { + "version": "2.0.2", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.1", + "just-diff": "^5.0.1", + "just-diff-apply": "^5.2.0" + } + }, + "proc-log": { + "version": "2.0.1", + "dev": true + }, + "read-cmd-shim": { + "version": "3.0.1", + "dev": true + }, + "semver": { + "version": "7.3.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "ssri": { + "version": "9.0.1", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "treeverse": { + "version": "2.0.0", + "dev": true + }, + "unique-filename": { + "version": "2.0.1", + "dev": true, + "requires": { + "unique-slug": "^3.0.0" + } + }, + "unique-slug": { + "version": "3.0.0", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "which": { + "version": "2.0.2", + "dev": true, + "requires": { + "isexe": "^2.0.0" } }, - "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "write-file-atomic": { + "version": "4.0.2", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" } }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@lerna/changed": { - "version": "4.0.0", - "integrity": "sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/collect-updates": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/listable": "4.0.0", - "@lerna/output": "4.0.0" + "@lerna/collect-updates": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/listable": "6.1.0", + "@lerna/output": "6.1.0" } }, "@lerna/check-working-tree": { - "version": "4.0.0", - "integrity": "sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/collect-uncommitted": "4.0.0", - "@lerna/describe-ref": "4.0.0", - "@lerna/validation-error": "4.0.0" + "@lerna/collect-uncommitted": "6.1.0", + "@lerna/describe-ref": "6.1.0", + "@lerna/validation-error": "6.1.0" } }, "@lerna/child-process": { - "version": "4.0.0", - "integrity": "sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q==", + "version": "6.1.0", "dev": true, "requires": { "chalk": "^4.1.0", @@ -53404,7 +57377,6 @@ "dependencies": { "cross-spawn": { "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -53414,7 +57386,6 @@ }, "execa": { "version": "5.1.1", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { "cross-spawn": "^7.0.3", @@ -53430,22 +57401,18 @@ }, "get-stream": { "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, "human-signals": { "version": "2.1.0", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "is-stream": { "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, "npm-run-path": { "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { "path-key": "^3.0.0" @@ -53453,12 +57420,10 @@ }, "path-key": { "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "shebang-command": { "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" @@ -53466,12 +57431,10 @@ }, "shebang-regex": { "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -53480,39 +57443,35 @@ } }, "@lerna/clean": { - "version": "4.0.0", - "integrity": "sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/prompt": "4.0.0", - "@lerna/pulse-till-done": "4.0.0", - "@lerna/rimraf-dir": "4.0.0", + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/prompt": "6.1.0", + "@lerna/pulse-till-done": "6.1.0", + "@lerna/rimraf-dir": "6.1.0", "p-map": "^4.0.0", "p-map-series": "^2.1.0", "p-waterfall": "^2.1.1" } }, "@lerna/cli": { - "version": "4.0.0", - "integrity": "sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/global-options": "4.0.0", + "@lerna/global-options": "6.1.0", "dedent": "^0.7.0", - "npmlog": "^4.1.2", + "npmlog": "^6.0.2", "yargs": "^16.2.0" }, "dependencies": { "ansi-regex": { "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "cliui": { "version": "7.0.4", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { "string-width": "^4.2.0", @@ -53522,12 +57481,10 @@ }, "is-fullwidth-code-point": { "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", @@ -53537,7 +57494,6 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { "ansi-regex": "^5.0.1" @@ -53545,7 +57501,6 @@ }, "wrap-ansi": { "version": "7.0.0", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { "ansi-styles": "^4.0.0", @@ -53555,12 +57510,10 @@ }, "y18n": { "version": "5.0.8", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yargs": { "version": "16.2.0", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -53574,60 +57527,54 @@ }, "yargs-parser": { "version": "20.2.9", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true } } }, "@lerna/collect-uncommitted": { - "version": "4.0.0", - "integrity": "sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", + "@lerna/child-process": "6.1.0", "chalk": "^4.1.0", - "npmlog": "^4.1.2" + "npmlog": "^6.0.2" } }, "@lerna/collect-updates": { - "version": "4.0.0", - "integrity": "sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "@lerna/describe-ref": "4.0.0", + "@lerna/child-process": "6.1.0", + "@lerna/describe-ref": "6.1.0", "minimatch": "^3.0.4", - "npmlog": "^4.1.2", + "npmlog": "^6.0.2", "slash": "^3.0.0" }, "dependencies": { "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true } } }, "@lerna/command": { - "version": "4.0.0", - "integrity": "sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "@lerna/package-graph": "4.0.0", - "@lerna/project": "4.0.0", - "@lerna/validation-error": "4.0.0", - "@lerna/write-log-file": "4.0.0", + "@lerna/child-process": "6.1.0", + "@lerna/package-graph": "6.1.0", + "@lerna/project": "6.1.0", + "@lerna/validation-error": "6.1.0", + "@lerna/write-log-file": "6.1.0", "clone-deep": "^4.0.1", "dedent": "^0.7.0", "execa": "^5.0.0", "is-ci": "^2.0.0", - "npmlog": "^4.1.2" + "npmlog": "^6.0.2" }, "dependencies": { "cross-spawn": { "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -53637,7 +57584,6 @@ }, "execa": { "version": "5.1.1", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { "cross-spawn": "^7.0.3", @@ -53653,22 +57599,18 @@ }, "get-stream": { "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, "human-signals": { "version": "2.1.0", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "is-stream": { "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, "npm-run-path": { "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { "path-key": "^3.0.0" @@ -53676,12 +57618,10 @@ }, "path-key": { "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "shebang-command": { "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" @@ -53689,12 +57629,10 @@ }, "shebang-regex": { "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -53703,26 +57641,23 @@ } }, "@lerna/conventional-commits": { - "version": "4.0.0", - "integrity": "sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/validation-error": "4.0.0", + "@lerna/validation-error": "6.1.0", "conventional-changelog-angular": "^5.0.12", - "conventional-changelog-core": "^4.2.2", + "conventional-changelog-core": "^4.2.4", "conventional-recommended-bump": "^6.1.0", "fs-extra": "^9.1.0", "get-stream": "^6.0.0", - "lodash.template": "^4.5.0", - "npm-package-arg": "^8.1.0", - "npmlog": "^4.1.2", + "npm-package-arg": "8.1.1", + "npmlog": "^6.0.2", "pify": "^5.0.0", "semver": "^7.3.4" }, "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -53733,25 +57668,37 @@ }, "get-stream": { "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, + "hosted-git-info": { + "version": "3.0.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, + "npm-package-arg": { + "version": "8.1.1", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + } + }, "pify": { "version": "5.0.0", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", "dev": true }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -53759,80 +57706,134 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@lerna/create": { - "version": "4.0.0", - "integrity": "sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/npm-conf": "4.0.0", - "@lerna/validation-error": "4.0.0", + "@lerna/child-process": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/npm-conf": "6.1.0", + "@lerna/validation-error": "6.1.0", "dedent": "^0.7.0", "fs-extra": "^9.1.0", - "globby": "^11.0.2", - "init-package-json": "^2.0.2", - "npm-package-arg": "^8.1.0", + "init-package-json": "^3.0.2", + "npm-package-arg": "8.1.1", "p-reduce": "^2.1.0", - "pacote": "^11.2.6", + "pacote": "^13.6.1", "pify": "^5.0.0", "semver": "^7.3.4", "slash": "^3.0.0", "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^3.0.0", - "whatwg-url": "^8.4.0", + "validate-npm-package-name": "^4.0.0", "yargs-parser": "20.2.4" }, "dependencies": { + "@npmcli/fs": { + "version": "2.1.2", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "3.0.2", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "dependencies": { + "lru-cache": { + "version": "7.14.1", + "dev": true + } + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/node-gyp": { + "version": "2.0.0", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "3.0.0", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, "@npmcli/run-script": { - "version": "1.8.6", - "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "version": "4.2.1", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + } + }, + "brace-expansion": { + "version": "2.0.1", "dev": true, "requires": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^7.1.0", - "read-package-json-fast": "^2.0.1" + "balanced-match": "^1.0.0" } }, "cacache": { - "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "version": "16.1.3", "dev": true, "requires": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", + "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.0.2", - "unique-filename": "^1.1.1" + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.14.1", + "dev": true + } } }, "chownr": { "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true }, "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -53841,70 +57842,210 @@ "universalify": "^2.0.0" } }, + "glob": { + "version": "8.0.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "hosted-git-info": { + "version": "3.0.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, + "minimatch": { + "version": "5.1.2", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass-fetch": { + "version": "2.1.2", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, "mkdirp": { "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, - "node-gyp": { - "version": "7.1.2", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "npm-install-checks": { + "version": "5.0.0", "dev": true, "requires": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "2.0.0", + "dev": true + }, + "npm-package-arg": { + "version": "8.1.1", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "validate-npm-package-name": { + "version": "3.0.0", + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + } + } + }, + "npm-pick-manifest": { + "version": "7.0.2", + "dev": true, + "requires": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^2.0.0", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + } + } + }, + "npm-registry-fetch": { + "version": "13.3.1", + "dev": true, + "requires": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + } } }, "pacote": { - "version": "11.3.5", - "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "version": "13.6.2", "dev": true, "requires": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.8.2", - "cacache": "^15.0.5", + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", "chownr": "^2.0.0", "fs-minipass": "^2.1.0", "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^11.0.0", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + } } }, "pify": { "version": "5.0.0", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true + }, + "proc-log": { + "version": "2.0.1", "dev": true }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -53912,43 +58053,47 @@ }, "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "version": "9.0.1", "dev": true, "requires": { "minipass": "^3.1.1" } }, - "tr46": { - "version": "2.1.0", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "unique-filename": { + "version": "2.0.1", "dev": true, "requires": { - "punycode": "^2.1.1" + "unique-slug": "^3.0.0" } }, - "webidl-conversions": { - "version": "6.1.0", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true + "unique-slug": { + "version": "3.0.0", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } }, - "whatwg-url": { - "version": "8.7.0", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "validate-npm-package-name": { + "version": "4.0.0", "dev": true, "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "builtins": "^5.0.0" + }, + "dependencies": { + "builtins": { + "version": "5.0.1", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + } } }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -53956,29 +58101,32 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "yargs-parser": { "version": "20.2.4", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", "dev": true } } }, "@lerna/create-symlink": { - "version": "4.0.0", - "integrity": "sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig==", + "version": "6.1.0", "dev": true, "requires": { - "cmd-shim": "^4.1.0", + "cmd-shim": "^5.0.0", "fs-extra": "^9.1.0", - "npmlog": "^4.1.2" + "npmlog": "^6.0.2" }, "dependencies": { + "cmd-shim": { + "version": "5.0.0", + "dev": true, + "requires": { + "mkdirp-infer-owner": "^2.0.0" + } + }, "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -53990,81 +58138,73 @@ } }, "@lerna/describe-ref": { - "version": "4.0.0", - "integrity": "sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "npmlog": "^4.1.2" + "@lerna/child-process": "6.1.0", + "npmlog": "^6.0.2" } }, "@lerna/diff": { - "version": "4.0.0", - "integrity": "sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/validation-error": "4.0.0", - "npmlog": "^4.1.2" + "@lerna/child-process": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/validation-error": "6.1.0", + "npmlog": "^6.0.2" } }, "@lerna/exec": { - "version": "4.0.0", - "integrity": "sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/profiler": "4.0.0", - "@lerna/run-topologically": "4.0.0", - "@lerna/validation-error": "4.0.0", + "@lerna/child-process": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/profiler": "6.1.0", + "@lerna/run-topologically": "6.1.0", + "@lerna/validation-error": "6.1.0", "p-map": "^4.0.0" } }, "@lerna/filter-options": { - "version": "4.0.0", - "integrity": "sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/collect-updates": "4.0.0", - "@lerna/filter-packages": "4.0.0", + "@lerna/collect-updates": "6.1.0", + "@lerna/filter-packages": "6.1.0", "dedent": "^0.7.0", - "npmlog": "^4.1.2" + "npmlog": "^6.0.2" } }, "@lerna/filter-packages": { - "version": "4.0.0", - "integrity": "sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/validation-error": "4.0.0", + "@lerna/validation-error": "6.1.0", "multimatch": "^5.0.0", - "npmlog": "^4.1.2" + "npmlog": "^6.0.2" } }, "@lerna/get-npm-exec-opts": { - "version": "4.0.0", - "integrity": "sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ==", + "version": "6.1.0", "dev": true, "requires": { - "npmlog": "^4.1.2" + "npmlog": "^6.0.2" } }, "@lerna/get-packed": { - "version": "4.0.0", - "integrity": "sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w==", + "version": "6.1.0", "dev": true, "requires": { "fs-extra": "^9.1.0", - "ssri": "^8.0.1", + "ssri": "^9.0.1", "tar": "^6.1.0" }, "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -54074,8 +58214,7 @@ } }, "ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "version": "9.0.1", "dev": true, "requires": { "minipass": "^3.1.1" @@ -54084,77 +58223,137 @@ } }, "@lerna/github-client": { - "version": "4.0.0", - "integrity": "sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", + "@lerna/child-process": "6.1.0", "@octokit/plugin-enterprise-rest": "^6.0.1", - "@octokit/rest": "^18.1.0", - "git-url-parse": "^11.4.4", - "npmlog": "^4.1.2" - } - }, - "@lerna/gitlab-client": { - "version": "4.0.0", - "integrity": "sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA==", - "dev": true, - "requires": { - "node-fetch": "^2.6.1", - "npmlog": "^4.1.2", - "whatwg-url": "^8.4.0" + "@octokit/rest": "^19.0.3", + "git-url-parse": "^13.1.0", + "npmlog": "^6.0.2" }, "dependencies": { - "tr46": { - "version": "2.1.0", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "@octokit/auth-token": { + "version": "3.0.2", "dev": true, "requires": { - "punycode": "^2.1.1" + "@octokit/types": "^8.0.0" } }, - "webidl-conversions": { - "version": "6.1.0", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "@octokit/core": { + "version": "4.1.0", + "dev": true, + "requires": { + "@octokit/auth-token": "^3.0.0", + "@octokit/graphql": "^5.0.0", + "@octokit/request": "^6.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^8.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "7.0.3", + "dev": true, + "requires": { + "@octokit/types": "^8.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "5.0.4", + "dev": true, + "requires": { + "@octokit/request": "^6.0.0", + "@octokit/types": "^8.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "14.0.0", "dev": true }, - "whatwg-url": { - "version": "8.7.0", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "@octokit/plugin-paginate-rest": { + "version": "5.0.1", "dev": true, "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "@octokit/types": "^8.0.0" + } + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "6.7.0", + "dev": true, + "requires": { + "@octokit/types": "^8.0.0", + "deprecation": "^2.3.1" + } + }, + "@octokit/request": { + "version": "6.2.2", + "dev": true, + "requires": { + "@octokit/endpoint": "^7.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^8.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/rest": { + "version": "19.0.5", + "dev": true, + "requires": { + "@octokit/core": "^4.1.0", + "@octokit/plugin-paginate-rest": "^5.0.0", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^6.7.0" + } + }, + "@octokit/types": { + "version": "8.0.0", + "dev": true, + "requires": { + "@octokit/openapi-types": "^14.0.0" } + }, + "is-plain-object": { + "version": "5.0.0", + "dev": true } } }, + "@lerna/gitlab-client": { + "version": "6.1.0", + "dev": true, + "requires": { + "node-fetch": "^2.6.1", + "npmlog": "^6.0.2" + } + }, "@lerna/global-options": { - "version": "4.0.0", - "integrity": "sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ==", + "version": "6.1.0", "dev": true }, "@lerna/has-npm-version": { - "version": "4.0.0", - "integrity": "sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", + "@lerna/child-process": "6.1.0", "semver": "^7.3.4" }, "dependencies": { "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -54162,21 +58361,19 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@lerna/import": { - "version": "4.0.0", - "integrity": "sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/prompt": "4.0.0", - "@lerna/pulse-till-done": "4.0.0", - "@lerna/validation-error": "4.0.0", + "@lerna/child-process": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/prompt": "6.1.0", + "@lerna/pulse-till-done": "6.1.0", + "@lerna/validation-error": "6.1.0", "dedent": "^0.7.0", "fs-extra": "^9.1.0", "p-map-series": "^2.1.0" @@ -54184,7 +58381,6 @@ "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -54196,22 +58392,21 @@ } }, "@lerna/info": { - "version": "4.0.0", - "integrity": "sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/command": "4.0.0", - "@lerna/output": "4.0.0", + "@lerna/command": "6.1.0", + "@lerna/output": "6.1.0", "envinfo": "^7.7.4" } }, "@lerna/init": { - "version": "4.0.0", - "integrity": "sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "@lerna/command": "4.0.0", + "@lerna/child-process": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/project": "6.1.0", "fs-extra": "^9.1.0", "p-map": "^4.0.0", "write-json-file": "^4.3.0" @@ -54219,7 +58414,6 @@ "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -54231,59 +58425,54 @@ } }, "@lerna/link": { - "version": "4.0.0", - "integrity": "sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/command": "4.0.0", - "@lerna/package-graph": "4.0.0", - "@lerna/symlink-dependencies": "4.0.0", + "@lerna/command": "6.1.0", + "@lerna/package-graph": "6.1.0", + "@lerna/symlink-dependencies": "6.1.0", + "@lerna/validation-error": "6.1.0", "p-map": "^4.0.0", "slash": "^3.0.0" }, "dependencies": { "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true } } }, "@lerna/list": { - "version": "4.0.0", - "integrity": "sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/listable": "4.0.0", - "@lerna/output": "4.0.0" + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/listable": "6.1.0", + "@lerna/output": "6.1.0" } }, "@lerna/listable": { - "version": "4.0.0", - "integrity": "sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/query-graph": "4.0.0", + "@lerna/query-graph": "6.1.0", "chalk": "^4.1.0", - "columnify": "^1.5.4" + "columnify": "^1.6.0" } }, "@lerna/log-packed": { - "version": "4.0.0", - "integrity": "sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ==", + "version": "6.1.0", "dev": true, "requires": { "byte-size": "^7.0.0", - "columnify": "^1.5.4", + "columnify": "^1.6.0", "has-unicode": "^2.0.1", - "npmlog": "^4.1.2" + "npmlog": "^6.0.2" } }, "@lerna/npm-conf": { - "version": "4.0.0", - "integrity": "sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw==", + "version": "6.1.0", "dev": true, "requires": { "config-chain": "^1.1.12", @@ -54292,69 +58481,135 @@ "dependencies": { "pify": { "version": "5.0.0", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", "dev": true } } }, "@lerna/npm-dist-tag": { - "version": "4.0.0", - "integrity": "sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/otplease": "4.0.0", - "npm-package-arg": "^8.1.0", - "npm-registry-fetch": "^9.0.0", - "npmlog": "^4.1.2" + "@lerna/otplease": "6.1.0", + "npm-package-arg": "8.1.1", + "npm-registry-fetch": "^13.3.0", + "npmlog": "^6.0.2" }, "dependencies": { + "builtins": { + "version": "5.0.1", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "hosted-git-info": { + "version": "3.0.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, + "minipass-fetch": { + "version": "2.1.2", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "npm-package-arg": { + "version": "8.1.1", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + } + }, "npm-registry-fetch": { - "version": "9.0.0", - "integrity": "sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==", + "version": "13.3.1", "dev": true, "requires": { - "@npmcli/ci-detect": "^1.0.0", - "lru-cache": "^6.0.0", - "make-fetch-happen": "^8.0.9", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + } + } + }, + "proc-log": { + "version": "2.0.1", + "dev": true + }, + "semver": { + "version": "7.3.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" } }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@lerna/npm-install": { - "version": "4.0.0", - "integrity": "sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "@lerna/get-npm-exec-opts": "4.0.0", + "@lerna/child-process": "6.1.0", + "@lerna/get-npm-exec-opts": "6.1.0", "fs-extra": "^9.1.0", - "npm-package-arg": "^8.1.0", - "npmlog": "^4.1.2", + "npm-package-arg": "8.1.1", + "npmlog": "^6.0.2", "signal-exit": "^3.0.3", "write-pkg": "^4.0.0" }, "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -54362,27 +58617,59 @@ "jsonfile": "^6.0.1", "universalify": "^2.0.0" } + }, + "hosted-git-info": { + "version": "3.0.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "npm-package-arg": { + "version": "8.1.1", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "semver": { + "version": "7.3.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "dev": true } } }, "@lerna/npm-publish": { - "version": "4.0.0", - "integrity": "sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/otplease": "4.0.0", - "@lerna/run-lifecycle": "4.0.0", + "@lerna/otplease": "6.1.0", + "@lerna/run-lifecycle": "6.1.0", "fs-extra": "^9.1.0", - "libnpmpublish": "^4.0.0", - "npm-package-arg": "^8.1.0", - "npmlog": "^4.1.2", + "libnpmpublish": "^6.0.4", + "npm-package-arg": "8.1.1", + "npmlog": "^6.0.2", "pify": "^5.0.0", - "read-package-json": "^3.0.0" + "read-package-json": "^5.0.1" }, "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -54391,66 +58678,100 @@ "universalify": "^2.0.0" } }, + "hosted-git-info": { + "version": "3.0.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "npm-package-arg": { + "version": "8.1.1", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + } + }, "pify": { "version": "5.0.0", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true + }, + "semver": { + "version": "7.3.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", "dev": true } } }, "@lerna/npm-run-script": { - "version": "4.0.0", - "integrity": "sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "@lerna/get-npm-exec-opts": "4.0.0", - "npmlog": "^4.1.2" + "@lerna/child-process": "6.1.0", + "@lerna/get-npm-exec-opts": "6.1.0", + "npmlog": "^6.0.2" } }, "@lerna/otplease": { - "version": "4.0.0", - "integrity": "sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/prompt": "4.0.0" + "@lerna/prompt": "6.1.0" } }, "@lerna/output": { - "version": "4.0.0", - "integrity": "sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w==", + "version": "6.1.0", "dev": true, "requires": { - "npmlog": "^4.1.2" + "npmlog": "^6.0.2" } }, "@lerna/pack-directory": { - "version": "4.0.0", - "integrity": "sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/get-packed": "4.0.0", - "@lerna/package": "4.0.0", - "@lerna/run-lifecycle": "4.0.0", - "npm-packlist": "^2.1.4", - "npmlog": "^4.1.2", - "tar": "^6.1.0", - "temp-write": "^4.0.0" + "@lerna/get-packed": "6.1.0", + "@lerna/package": "6.1.0", + "@lerna/run-lifecycle": "6.1.0", + "@lerna/temp-write": "6.1.0", + "npm-packlist": "^5.1.1", + "npmlog": "^6.0.2", + "tar": "^6.1.0" } }, "@lerna/package": { - "version": "4.0.0", - "integrity": "sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q==", + "version": "6.1.0", "dev": true, "requires": { "load-json-file": "^6.2.0", - "npm-package-arg": "^8.1.0", + "npm-package-arg": "8.1.1", "write-pkg": "^4.0.0" }, "dependencies": { + "hosted-git-info": { + "version": "3.0.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "load-json-file": { "version": "6.2.0", - "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", "dev": true, "requires": { "graceful-fs": "^4.1.15", @@ -54459,9 +58780,24 @@ "type-fest": "^0.6.0" } }, + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "npm-package-arg": { + "version": "8.1.1", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + } + }, "parse-json": { "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -54470,41 +58806,63 @@ "lines-and-columns": "^1.1.6" } }, + "semver": { + "version": "7.3.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "strip-bom": { "version": "4.0.0", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, "type-fest": { "version": "0.6.0", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + }, + "yallist": { + "version": "4.0.0", "dev": true } } }, "@lerna/package-graph": { - "version": "4.0.0", - "integrity": "sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/prerelease-id-from-version": "4.0.0", - "@lerna/validation-error": "4.0.0", - "npm-package-arg": "^8.1.0", - "npmlog": "^4.1.2", + "@lerna/prerelease-id-from-version": "6.1.0", + "@lerna/validation-error": "6.1.0", + "npm-package-arg": "8.1.1", + "npmlog": "^6.0.2", "semver": "^7.3.4" }, "dependencies": { + "hosted-git-info": { + "version": "3.0.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, + "npm-package-arg": { + "version": "8.1.1", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + } + }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -54512,14 +58870,12 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@lerna/prerelease-id-from-version": { - "version": "4.0.0", - "integrity": "sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg==", + "version": "6.1.0", "dev": true, "requires": { "semver": "^7.3.4" @@ -54527,15 +58883,13 @@ "dependencies": { "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -54543,24 +58897,21 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@lerna/profiler": { - "version": "4.0.0", - "integrity": "sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q==", + "version": "6.1.0", "dev": true, "requires": { "fs-extra": "^9.1.0", - "npmlog": "^4.1.2", + "npmlog": "^6.0.2", "upath": "^2.0.1" }, "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -54571,33 +58922,42 @@ }, "upath": { "version": "2.0.1", - "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", "dev": true } } }, "@lerna/project": { - "version": "4.0.0", - "integrity": "sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/package": "4.0.0", - "@lerna/validation-error": "4.0.0", + "@lerna/package": "6.1.0", + "@lerna/validation-error": "6.1.0", "cosmiconfig": "^7.0.0", "dedent": "^0.7.0", "dot-prop": "^6.0.1", "glob-parent": "^5.1.1", "globby": "^11.0.2", + "js-yaml": "^4.1.0", "load-json-file": "^6.2.0", - "npmlog": "^4.1.2", + "npmlog": "^6.0.2", "p-map": "^4.0.0", "resolve-from": "^5.0.0", "write-json-file": "^4.3.0" }, "dependencies": { + "argparse": { + "version": "2.0.1", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, "load-json-file": { "version": "6.2.0", - "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", "dev": true, "requires": { "graceful-fs": "^4.1.15", @@ -54608,7 +58968,6 @@ }, "parse-json": { "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -54619,117 +58978,169 @@ }, "resolve-from": { "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, "strip-bom": { "version": "4.0.0", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, "type-fest": { "version": "0.6.0", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true } } }, "@lerna/prompt": { - "version": "4.0.0", - "integrity": "sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ==", + "version": "6.1.0", "dev": true, "requires": { - "inquirer": "^7.3.3", - "npmlog": "^4.1.2" + "inquirer": "^8.2.4", + "npmlog": "^6.0.2" } }, "@lerna/publish": { - "version": "4.0.0", - "integrity": "sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg==", - "dev": true, - "requires": { - "@lerna/check-working-tree": "4.0.0", - "@lerna/child-process": "4.0.0", - "@lerna/collect-updates": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/describe-ref": "4.0.0", - "@lerna/log-packed": "4.0.0", - "@lerna/npm-conf": "4.0.0", - "@lerna/npm-dist-tag": "4.0.0", - "@lerna/npm-publish": "4.0.0", - "@lerna/otplease": "4.0.0", - "@lerna/output": "4.0.0", - "@lerna/pack-directory": "4.0.0", - "@lerna/prerelease-id-from-version": "4.0.0", - "@lerna/prompt": "4.0.0", - "@lerna/pulse-till-done": "4.0.0", - "@lerna/run-lifecycle": "4.0.0", - "@lerna/run-topologically": "4.0.0", - "@lerna/validation-error": "4.0.0", - "@lerna/version": "4.0.0", + "version": "6.1.0", + "dev": true, + "requires": { + "@lerna/check-working-tree": "6.1.0", + "@lerna/child-process": "6.1.0", + "@lerna/collect-updates": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/describe-ref": "6.1.0", + "@lerna/log-packed": "6.1.0", + "@lerna/npm-conf": "6.1.0", + "@lerna/npm-dist-tag": "6.1.0", + "@lerna/npm-publish": "6.1.0", + "@lerna/otplease": "6.1.0", + "@lerna/output": "6.1.0", + "@lerna/pack-directory": "6.1.0", + "@lerna/prerelease-id-from-version": "6.1.0", + "@lerna/prompt": "6.1.0", + "@lerna/pulse-till-done": "6.1.0", + "@lerna/run-lifecycle": "6.1.0", + "@lerna/run-topologically": "6.1.0", + "@lerna/validation-error": "6.1.0", + "@lerna/version": "6.1.0", "fs-extra": "^9.1.0", - "libnpmaccess": "^4.0.1", - "npm-package-arg": "^8.1.0", - "npm-registry-fetch": "^9.0.0", - "npmlog": "^4.1.2", + "libnpmaccess": "^6.0.3", + "npm-package-arg": "8.1.1", + "npm-registry-fetch": "^13.3.0", + "npmlog": "^6.0.2", "p-map": "^4.0.0", "p-pipe": "^3.1.0", - "pacote": "^11.2.6", + "pacote": "^13.6.1", "semver": "^7.3.4" }, "dependencies": { + "@npmcli/fs": { + "version": "2.1.2", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "3.0.2", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "dependencies": { + "lru-cache": { + "version": "7.14.1", + "dev": true + } + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/node-gyp": { + "version": "2.0.0", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "3.0.0", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, "@npmcli/run-script": { - "version": "1.8.6", - "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "version": "4.2.1", "dev": true, "requires": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^7.1.0", - "read-package-json-fast": "^2.0.1" + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + } + }, + "brace-expansion": { + "version": "2.0.1", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "builtins": { + "version": "5.0.1", + "dev": true, + "requires": { + "semver": "^7.0.0" } }, "cacache": { - "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "version": "16.1.3", "dev": true, "requires": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", + "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.0.2", - "unique-filename": "^1.1.1" + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.14.1", + "dev": true + } } }, "chownr": { "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true }, - "debug": { - "version": "4.3.3", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -54738,154 +59149,246 @@ "universalify": "^2.0.0" } }, + "glob": { + "version": "8.0.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "hosted-git-info": { + "version": "3.0.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, + "minimatch": { + "version": "5.1.2", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass-fetch": { + "version": "2.1.2", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, "mkdirp": { "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "npm-install-checks": { + "version": "5.0.0", + "dev": true, + "requires": { + "semver": "^7.1.1" + } }, - "negotiator": { - "version": "0.6.2", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "npm-normalize-package-bin": { + "version": "2.0.0", "dev": true }, - "node-gyp": { - "version": "7.1.2", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "npm-package-arg": { + "version": "8.1.1", "dev": true, "requires": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-pick-manifest": { + "version": "7.0.2", + "dev": true, + "requires": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^2.0.0", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + } } }, "npm-registry-fetch": { - "version": "9.0.0", - "integrity": "sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==", + "version": "13.3.1", "dev": true, "requires": { - "@npmcli/ci-detect": "^1.0.0", - "lru-cache": "^6.0.0", - "make-fetch-happen": "^8.0.9", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + } } }, "pacote": { - "version": "11.3.5", - "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "version": "13.6.2", "dev": true, "requires": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.8.2", - "cacache": "^15.0.5", + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", "chownr": "^2.0.0", "fs-minipass": "^2.1.0", "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^11.0.0", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" + "ssri": "^9.0.0", + "tar": "^6.1.11" }, "dependencies": { - "make-fetch-happen": { - "version": "9.1.0", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", "dev": true, "requires": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" } }, - "npm-registry-fetch": { - "version": "11.0.0", - "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "validate-npm-package-name": { + "version": "4.0.0", "dev": true, "requires": { - "make-fetch-happen": "^9.0.1", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "builtins": "^5.0.0" } } } }, + "proc-log": { + "version": "2.0.1", + "dev": true + }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, - "socks-proxy-agent": { - "version": "6.1.1", - "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "ssri": { + "version": "9.0.1", "dev": true, "requires": { - "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" + "minipass": "^3.1.1" } }, - "ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "unique-filename": { + "version": "2.0.1", "dev": true, "requires": { - "minipass": "^3.1.1" + "unique-slug": "^3.0.0" + } + }, + "unique-slug": { + "version": "3.0.0", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" } }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -54893,40 +59396,35 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@lerna/pulse-till-done": { - "version": "4.0.0", - "integrity": "sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg==", + "version": "6.1.0", "dev": true, "requires": { - "npmlog": "^4.1.2" + "npmlog": "^6.0.2" } }, "@lerna/query-graph": { - "version": "4.0.0", - "integrity": "sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/package-graph": "4.0.0" + "@lerna/package-graph": "6.1.0" } }, "@lerna/resolve-symlink": { - "version": "4.0.0", - "integrity": "sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA==", + "version": "6.1.0", "dev": true, "requires": { "fs-extra": "^9.1.0", - "npmlog": "^4.1.2", - "read-cmd-shim": "^2.0.0" + "npmlog": "^6.0.2", + "read-cmd-shim": "^3.0.0" }, "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -54934,76 +59432,118 @@ "jsonfile": "^6.0.1", "universalify": "^2.0.0" } + }, + "read-cmd-shim": { + "version": "3.0.1", + "dev": true } } }, "@lerna/rimraf-dir": { - "version": "4.0.0", - "integrity": "sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/child-process": "4.0.0", - "npmlog": "^4.1.2", + "@lerna/child-process": "6.1.0", + "npmlog": "^6.0.2", "path-exists": "^4.0.0", "rimraf": "^3.0.2" }, "dependencies": { "path-exists": { "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true } } }, "@lerna/run": { - "version": "4.0.0", - "integrity": "sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/command": "4.0.0", - "@lerna/filter-options": "4.0.0", - "@lerna/npm-run-script": "4.0.0", - "@lerna/output": "4.0.0", - "@lerna/profiler": "4.0.0", - "@lerna/run-topologically": "4.0.0", - "@lerna/timer": "4.0.0", - "@lerna/validation-error": "4.0.0", + "@lerna/command": "6.1.0", + "@lerna/filter-options": "6.1.0", + "@lerna/npm-run-script": "6.1.0", + "@lerna/output": "6.1.0", + "@lerna/profiler": "6.1.0", + "@lerna/run-topologically": "6.1.0", + "@lerna/timer": "6.1.0", + "@lerna/validation-error": "6.1.0", + "fs-extra": "^9.1.0", "p-map": "^4.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } } }, "@lerna/run-lifecycle": { - "version": "4.0.0", - "integrity": "sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/npm-conf": "4.0.0", - "npm-lifecycle": "^3.1.5", - "npmlog": "^4.1.2" + "@lerna/npm-conf": "6.1.0", + "@npmcli/run-script": "^4.1.7", + "npmlog": "^6.0.2", + "p-queue": "^6.6.2" + }, + "dependencies": { + "@npmcli/node-gyp": { + "version": "2.0.0", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "3.0.0", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "4.2.1", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + } + }, + "which": { + "version": "2.0.2", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, "@lerna/run-topologically": { - "version": "4.0.0", - "integrity": "sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/query-graph": "4.0.0", + "@lerna/query-graph": "6.1.0", "p-queue": "^6.6.2" } }, "@lerna/symlink-binary": { - "version": "4.0.0", - "integrity": "sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/create-symlink": "4.0.0", - "@lerna/package": "4.0.0", + "@lerna/create-symlink": "6.1.0", + "@lerna/package": "6.1.0", "fs-extra": "^9.1.0", "p-map": "^4.0.0" }, "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -55015,13 +59555,12 @@ } }, "@lerna/symlink-dependencies": { - "version": "4.0.0", - "integrity": "sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw==", + "version": "6.1.0", "dev": true, "requires": { - "@lerna/create-symlink": "4.0.0", - "@lerna/resolve-symlink": "4.0.0", - "@lerna/symlink-binary": "4.0.0", + "@lerna/create-symlink": "6.1.0", + "@lerna/resolve-symlink": "6.1.0", + "@lerna/symlink-binary": "6.1.0", "fs-extra": "^9.1.0", "p-map": "^4.0.0", "p-map-series": "^2.1.0" @@ -55029,7 +59568,6 @@ "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -55040,55 +59578,84 @@ } } }, + "@lerna/temp-write": { + "version": "6.1.0", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "is-stream": "^2.0.0", + "make-dir": "^3.0.0", + "temp-dir": "^1.0.0", + "uuid": "^8.3.2" + }, + "dependencies": { + "is-stream": { + "version": "2.0.1", + "dev": true + }, + "make-dir": { + "version": "3.1.0", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "dev": true + } + } + }, "@lerna/timer": { - "version": "4.0.0", - "integrity": "sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg==", + "version": "6.1.0", "dev": true }, "@lerna/validation-error": { - "version": "4.0.0", - "integrity": "sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw==", + "version": "6.1.0", "dev": true, "requires": { - "npmlog": "^4.1.2" + "npmlog": "^6.0.2" } }, "@lerna/version": { - "version": "4.0.0", - "integrity": "sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA==", - "dev": true, - "requires": { - "@lerna/check-working-tree": "4.0.0", - "@lerna/child-process": "4.0.0", - "@lerna/collect-updates": "4.0.0", - "@lerna/command": "4.0.0", - "@lerna/conventional-commits": "4.0.0", - "@lerna/github-client": "4.0.0", - "@lerna/gitlab-client": "4.0.0", - "@lerna/output": "4.0.0", - "@lerna/prerelease-id-from-version": "4.0.0", - "@lerna/prompt": "4.0.0", - "@lerna/run-lifecycle": "4.0.0", - "@lerna/run-topologically": "4.0.0", - "@lerna/validation-error": "4.0.0", + "version": "6.1.0", + "dev": true, + "requires": { + "@lerna/check-working-tree": "6.1.0", + "@lerna/child-process": "6.1.0", + "@lerna/collect-updates": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/conventional-commits": "6.1.0", + "@lerna/github-client": "6.1.0", + "@lerna/gitlab-client": "6.1.0", + "@lerna/output": "6.1.0", + "@lerna/prerelease-id-from-version": "6.1.0", + "@lerna/prompt": "6.1.0", + "@lerna/run-lifecycle": "6.1.0", + "@lerna/run-topologically": "6.1.0", + "@lerna/temp-write": "6.1.0", + "@lerna/validation-error": "6.1.0", + "@nrwl/devkit": ">=14.8.6 < 16", "chalk": "^4.1.0", "dedent": "^0.7.0", "load-json-file": "^6.2.0", "minimatch": "^3.0.4", - "npmlog": "^4.1.2", + "npmlog": "^6.0.2", "p-map": "^4.0.0", "p-pipe": "^3.1.0", "p-reduce": "^2.1.0", "p-waterfall": "^2.1.1", "semver": "^7.3.4", "slash": "^3.0.0", - "temp-write": "^4.0.0", "write-json-file": "^4.3.0" }, "dependencies": { "load-json-file": { "version": "6.2.0", - "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", "dev": true, "requires": { "graceful-fs": "^4.1.15", @@ -55099,7 +59666,6 @@ }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -55107,7 +59673,6 @@ }, "parse-json": { "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -55117,8 +59682,7 @@ } }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -55126,38 +59690,42 @@ }, "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "strip-bom": { "version": "4.0.0", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, "type-fest": { "version": "0.6.0", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@lerna/write-log-file": { - "version": "4.0.0", - "integrity": "sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg==", + "version": "6.1.0", "dev": true, "requires": { - "npmlog": "^4.1.2", - "write-file-atomic": "^3.0.3" + "npmlog": "^6.0.2", + "write-file-atomic": "^4.0.1" + }, + "dependencies": { + "write-file-atomic": { + "version": "4.0.2", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } } }, "@loaders.gl/3d-tiles": { "version": "3.0.8", - "integrity": "sha512-jZeOyDPGD2wEkTLW4Do9A4UUQ+OGjhhNXztB0AsttZ69OpkmsxJXb76xxwevf+eThrsTgSTjZ06eC5DHX0kyXA==", "requires": { "@loaders.gl/core": "3.0.8", "@loaders.gl/draco": "3.0.8", @@ -55171,7 +59739,6 @@ }, "@loaders.gl/core": { "version": "3.0.8", - "integrity": "sha512-FIfbhMkoRX2JonEHXHgClC7jwOSsEwvvmjlaTMRAY+gFKvJPGmegkp4VgUZquLFf6GedJt/1TuMMvAX6gdq1pg==", "requires": { "@babel/runtime": "^7.3.1", "@loaders.gl/loader-utils": "3.0.8", @@ -55181,7 +59748,6 @@ }, "@loaders.gl/draco": { "version": "3.0.8", - "integrity": "sha512-ZCXzXNHWQ7H0qk/kC+rWzjMWjLzZGzQcDbdpIuy8xJdp4rTpmMkLUseFPby8vhkmIaqxWPwPB6mx/vM7L6JENg==", "requires": { "@babel/runtime": "^7.3.1", "@loaders.gl/loader-utils": "3.0.8", @@ -55192,7 +59758,6 @@ }, "@loaders.gl/gis": { "version": "3.0.8", - "integrity": "sha512-7NL+lIb7NezlMupYskVil6M3RZunXJl+TyaVAW82GLbzPSOq+m/G7h3+z0GBa8iv/U/I+cB5BhSN+GZmvFwqEA==", "requires": { "@loaders.gl/loader-utils": "3.0.8", "@loaders.gl/schema": "3.0.8", @@ -55202,7 +59767,6 @@ }, "@loaders.gl/gltf": { "version": "3.0.8", - "integrity": "sha512-4PXWTlqyvlbZE2Vp4iQ+Y87ZO1WuRvSlbImDhygd0hoINfmJ9ObxrFS3yJcpJTu007nWxXorNVEOKyuoo+4Iyw==", "requires": { "@loaders.gl/core": "3.0.8", "@loaders.gl/draco": "3.0.8", @@ -55212,14 +59776,12 @@ }, "@loaders.gl/images": { "version": "3.0.8", - "integrity": "sha512-rO2cIYJYlMs/uO9YSoF4/BEA4p/9xQ3gHZ1sIJkPYVnDqzpbu8nvUjWTQqIdL/MkQBTW8tz3twCdM+B6G9Fa2w==", "requires": { "@loaders.gl/loader-utils": "3.0.8" } }, "@loaders.gl/loader-utils": { "version": "3.0.8", - "integrity": "sha512-PW1WyyQ+LXkqoGHBZHsmfNQkKiLAYf1gok+kHnHvY9fCzhJeA1iTNEUKPXGXKgS00m/k5cBTkOWAaOG9KRvBCQ==", "requires": { "@babel/runtime": "^7.3.1", "@loaders.gl/worker-utils": "3.0.8", @@ -55228,7 +59790,6 @@ }, "@loaders.gl/math": { "version": "3.0.8", - "integrity": "sha512-jfFpxxr4Bq5JfOPqLVJc4JJGoGGvVTOCWiJhnTtSAKhaNSwldmNWaZ0w8E2nlgPKPMAHiTRKOQnd9sSY5m66Cw==", "requires": { "@loaders.gl/images": "3.0.8", "@loaders.gl/loader-utils": "3.0.8", @@ -55237,7 +59798,6 @@ }, "@loaders.gl/mvt": { "version": "3.0.8", - "integrity": "sha512-Jk1QTHgpxMsUT01w5IJJ2en9qq0yOZcL2wGXVc7CFp2h6inB22rC3drUwq1mUNGe6iy3EWIo7EeJVd9B+5JyTQ==", "requires": { "@loaders.gl/gis": "3.0.8", "@loaders.gl/loader-utils": "3.0.8", @@ -55247,7 +59807,6 @@ }, "@loaders.gl/schema": { "version": "3.0.8", - "integrity": "sha512-yne5WE7fZZWFl2zF8fzDlYhPVJua6h6mTCSmlQ5pryaMXTZS9mfzXXIFWRL3kswqnQTu/QNFdyFj1mP0haF24w==", "requires": { "@types/geojson": "^7946.0.7", "apache-arrow": "^4.0.0", @@ -55256,7 +59815,6 @@ }, "@loaders.gl/terrain": { "version": "3.0.8", - "integrity": "sha512-MtOAYEB/xJB4CN4B0YNPkO4v1ZY332joxiOHQI1x37x4sWVAqOrKLr9jB42sZCB8aINi2WMWGiErtf9wh9L5Pg==", "requires": { "@babel/runtime": "^7.3.1", "@loaders.gl/loader-utils": "3.0.8", @@ -55266,7 +59824,6 @@ }, "@loaders.gl/tiles": { "version": "3.0.8", - "integrity": "sha512-Rc+yHFdQg2sYmcYkwvszukFWdm9EW354F9HUR7y/oauos6tsdo4YTj31zgytaYR63/EqWQ7kwI29/eePEcutzg==", "requires": { "@loaders.gl/core": "3.0.8", "@loaders.gl/loader-utils": "3.0.8", @@ -55280,18 +59837,15 @@ }, "@loaders.gl/worker-utils": { "version": "3.0.8", - "integrity": "sha512-Pg72HuXPcL725TrOlOr83xloVUHj6OMWmno1dI8ccuqfOBsgoRjxNZrcSvwBzfK8tFCzuN2X30I+mHl3BkuYLw==", "requires": { "@babel/runtime": "^7.3.1" } }, "@luma.gl/constants": { - "version": "8.5.4", - "integrity": "sha512-lrA4ja92om/gDHYOvM9itL5S7FVzjKulyknDz6S+Y7gmgHgXk2ln1Xar5zUCsLnhAYx4glHITXGH5Y5rdWgT1Q==" + "version": "8.5.4" }, "@luma.gl/core": { "version": "8.5.4", - "integrity": "sha512-+saDz1D3mcPd53vgbG60ryg1w5CF9Z2wdakKHzR810VoJLw97t4aNdg/eNgyWOvbOHxaKJBPm8K0sGjej67+jw==", "requires": { "@babel/runtime": "^7.0.0", "@luma.gl/constants": "8.5.4", @@ -55303,7 +59857,6 @@ }, "@luma.gl/engine": { "version": "8.5.4", - "integrity": "sha512-Sfv972IzvR9s9kKWugs67XQUh9jC0e/PpBrzvyGVnPU4XvFq42RZVF73pzEklVU6AlpR8Zg5CPtxGdhyOHtT7w==", "requires": { "@babel/runtime": "^7.0.0", "@luma.gl/constants": "8.5.4", @@ -55316,7 +59869,6 @@ }, "@luma.gl/experimental": { "version": "8.5.4", - "integrity": "sha512-09waqRhgIrw+Sq0/in4tw4jPag5YsFfV1nEHJaLAg5RFv92S53IEubSJgkuG02HoOBkPxQ7KYvs9VNmriisnYg==", "requires": { "@luma.gl/constants": "8.5.4", "@math.gl/core": "^3.5.0", @@ -55325,7 +59877,6 @@ }, "@luma.gl/gltools": { "version": "8.5.4", - "integrity": "sha512-JotiPuymQz2Xc41AYlS2moJC/EHxU+OX/OMKi0+/MeOlEFLsdochgTA0I64j8yofLTXdeiGCneGtD1Ao8fk+bw==", "requires": { "@babel/runtime": "^7.0.0", "@luma.gl/constants": "8.5.4", @@ -55334,7 +59885,6 @@ }, "@luma.gl/shadertools": { "version": "8.5.4", - "integrity": "sha512-rwLBLrACi75aWnuJm8rVKCQnJR2sMTCxHuexfjHJ7Uecl0vVcVJZT7c9EnCFaz5LUTNbdupvuhq0SKNckKiKmw==", "requires": { "@babel/runtime": "^7.0.0", "@math.gl/core": "^3.5.0" @@ -55342,7 +59892,6 @@ }, "@luma.gl/webgl": { "version": "8.5.4", - "integrity": "sha512-dWy4dhTbtvDO9zQBdx1Yb+DxNx/1JWV9rhhJxJUtTKbGZSX0RjkASTT6GBWMl5jrH1JYJefS1wswHmmPVXjK0Q==", "requires": { "@babel/runtime": "^7.0.0", "@luma.gl/constants": "8.5.4", @@ -55351,19 +59900,10 @@ } }, "@mapbox/extent": { - "version": "0.4.0", - "integrity": "sha512-MSoKw3qPceGuupn04sdaJrFeLKvcSETVLZCGS8JA9x6zXQL3FWiKaIXYIZEDXd5jpXpWlRxinCZIN49yRy0C9A==" - }, - "@mapbox/geojson-area": { - "version": "0.2.2", - "integrity": "sha512-bBqqFn1kIbLBfn7Yq1PzzwVkPYQr9lVUeT8Dhd0NL5n76PBuXzOcuLV7GOSbEB1ia8qWxH4COCvFpziEu/yReA==", - "requires": { - "wgs84": "0.0.0" - } + "version": "0.4.0" }, "@mapbox/geojson-coords": { "version": "0.0.2", - "integrity": "sha512-YuVzpseee/P1T5BWyeVVPppyfmuXYHFwZHmybkqaMfu4BWlOf2cmMGKj2Rr92MwfSTOCSUA0PAsVGRG8akY0rg==", "requires": { "@mapbox/geojson-normalize": "0.0.1", "geojson-flatten": "^1.0.4" @@ -55371,7 +59911,6 @@ }, "@mapbox/geojson-extent": { "version": "1.0.1", - "integrity": "sha512-hh8LEO3djT4fqfr8sSC6wKt+p0TMiu+KOLMBUiFOyj+zGq7+IXwQGl0ppCVDkyzCewyd9LoGe9zAvDxXrLfhLw==", "requires": { "@mapbox/extent": "0.4.0", "@mapbox/geojson-coords": "0.0.2", @@ -55380,67 +59919,57 @@ }, "dependencies": { "rw": { - "version": "0.1.4", - "integrity": "sha512-vSj3D96kMcjNyqPcp65wBRIDImGSrUuMxngNNxvw8MQaO+aQ6llzRPH7XcJy5zrpb3wU++045+Uz/IDIM684iw==" + "version": "0.1.4" } } }, "@mapbox/geojson-normalize": { - "version": "0.0.1", - "integrity": "sha512-82V7YHcle8lhgIGqEWwtXYN5cy0QM/OHq3ypGhQTbvHR57DF0vMHMjjVSQKFfVXBe/yWCBZTyOuzvK7DFFnx5Q==" + "version": "0.0.1" }, "@mapbox/geojson-rewind": { - "version": "0.4.1", - "integrity": "sha512-mxo2MEr7izA1uOXcDsw99Kgg6xW3P4H2j4n1lmldsgviIelpssvP+jQDivFKOHrOVJDpTTi5oZJvRcHtU9Uufw==", + "version": "0.5.2", "requires": { - "@mapbox/geojson-area": "0.2.2", - "concat-stream": "~1.6.0", - "minimist": "^1.2.5", - "sharkdown": "^0.1.0" + "get-stream": "^6.0.1", + "minimist": "^1.2.6" + }, + "dependencies": { + "get-stream": { + "version": "6.0.1" + } } }, "@mapbox/geojson-types": { - "version": "1.0.2", - "integrity": "sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==" + "version": "1.0.2" }, "@mapbox/jsonlint-lines-primitives": { - "version": "2.0.2", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==" + "version": "2.0.2" }, "@mapbox/mapbox-gl-supported": { - "version": "1.5.0", - "integrity": "sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==" + "version": "2.0.1" }, "@mapbox/martini": { - "version": "0.2.0", - "integrity": "sha512-7hFhtkb0KTLEls+TRw/rWayq5EeHtTaErgm/NskVoXmtgAQu/9D299aeyj6mzAR/6XUnYRp2lU+4IcrYRFjVsQ==" + "version": "0.2.0" }, "@mapbox/point-geometry": { - "version": "0.1.0", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" + "version": "0.1.0" }, "@mapbox/tiny-sdf": { - "version": "1.2.5", - "integrity": "sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==" + "version": "1.2.5" }, "@mapbox/unitbezier": { - "version": "0.0.0", - "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==" + "version": "0.0.0" }, "@mapbox/vector-tile": { "version": "1.3.1", - "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", "requires": { "@mapbox/point-geometry": "~0.1.0" } }, "@mapbox/whoots-js": { - "version": "3.1.0", - "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==" + "version": "3.1.0" }, "@math.gl/core": { "version": "3.5.3", - "integrity": "sha512-TaSnvG0qFh1VxeNW5L58jSx0nJUMWMpUl6zo6Z3ScQzFySG5cicGOBzk/D40RkIZWPazCKCZ+ZThg5npSK9y3g==", "requires": { "@babel/runtime": "^7.12.0", "gl-matrix": "^3.0.0" @@ -55448,7 +59977,6 @@ }, "@math.gl/culling": { "version": "3.5.3", - "integrity": "sha512-ABpAcrvoIOLSm1EUkwgDem4RfO28HWPBs/+taZ/ZSpJG6KiVPklpKU1NCK+05HuJStkpFZ+XlWtehWU6FAMCyA==", "requires": { "@babel/runtime": "^7.12.0", "@math.gl/core": "3.5.3", @@ -55457,7 +59985,6 @@ }, "@math.gl/geospatial": { "version": "3.5.3", - "integrity": "sha512-cnc8VMQrt30JmlG200VDJmmvSjaGW57gY9KEZ+raapxyyFyfDNuAuIrIxe+zbK66FbvFWTbJlDaNmKqVG+ohyw==", "requires": { "@babel/runtime": "^7.12.0", "@math.gl/core": "3.5.3", @@ -55466,14 +59993,12 @@ }, "@math.gl/polygon": { "version": "3.5.3", - "integrity": "sha512-VktscmyQg/Rd56nJk0Nj/UyvnPDbsnZNMWCdl3G5AYenYzLWy6h4FEWhLx8pD+Xw7VuFot8LR4WAK2TPzXzrWw==", "requires": { "@math.gl/core": "3.5.3" } }, "@math.gl/web-mercator": { "version": "3.5.6", - "integrity": "sha512-siWHLJGp9o8fDEM1t0Rby+JXftl6il0z3927liWGzkHqFftXPHY858ShPy45ThDU8q5lyCftg8aVgrv4nfD+Zw==", "requires": { "@babel/runtime": "^7.12.0", "gl-matrix": "~3.3.0" @@ -55481,7 +60006,6 @@ }, "@mdx-js/loader": { "version": "1.6.22", - "integrity": "sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q==", "dev": true, "requires": { "@mdx-js/mdx": "1.6.22", @@ -55490,13 +60014,11 @@ }, "dependencies": { "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", "dev": true }, "loader-utils": { "version": "2.0.0", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -55508,7 +60030,6 @@ }, "@mdx-js/mdx": { "version": "1.6.22", - "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", "requires": { "@babel/core": "7.12.9", "@babel/plugin-syntax-jsx": "7.12.1", @@ -55533,7 +60054,6 @@ "dependencies": { "@babel/core": { "version": "7.12.9", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", "requires": { "@babel/code-frame": "^7.10.4", "@babel/generator": "^7.12.5", @@ -55555,37 +60075,30 @@ }, "@babel/plugin-syntax-jsx": { "version": "7.12.1", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", "requires": { "@babel/helper-plugin-utils": "^7.10.4" } }, "debug": { "version": "4.3.4", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } }, "is-buffer": { - "version": "2.0.5", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + "version": "2.0.5" }, "is-plain-obj": { - "version": "2.1.0", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + "version": "2.1.0" }, "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3" }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" }, "parse-entities": { "version": "2.0.0", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", "requires": { "character-entities": "^1.0.0", "character-entities-legacy": "^1.0.0", @@ -55597,7 +60110,6 @@ }, "remark-parse": { "version": "8.0.3", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", "requires": { "ccount": "^1.0.0", "collapse-white-space": "^1.0.2", @@ -55619,7 +60131,6 @@ }, "unified": { "version": "9.2.0", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", "requires": { "bail": "^1.0.0", "extend": "^3.0.0", @@ -55630,26 +60141,22 @@ } }, "unist-util-is": { - "version": "4.1.0", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" + "version": "4.1.0" }, "unist-util-remove-position": { "version": "2.0.1", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", "requires": { "unist-util-visit": "^2.0.0" } }, "unist-util-stringify-position": { "version": "2.0.3", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", "requires": { "@types/unist": "^2.0.2" } }, "unist-util-visit": { "version": "2.0.3", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0", @@ -55658,7 +60165,6 @@ }, "unist-util-visit-parents": { "version": "3.1.1", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0" @@ -55666,7 +60172,6 @@ }, "vfile": { "version": "4.2.1", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", "requires": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", @@ -55675,12 +60180,10 @@ } }, "vfile-location": { - "version": "3.2.0", - "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==" + "version": "3.2.0" }, "vfile-message": { "version": "2.0.4", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", "requires": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^2.0.0" @@ -55690,67 +60193,52 @@ }, "@mdx-js/react": { "version": "1.6.22", - "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", "dev": true }, "@mdx-js/util": { - "version": "1.6.22", - "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==" + "version": "1.6.22" }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "requires": { "call-me-maybe": "^1.0.1", "glob-to-regexp": "^0.3.0" }, "dependencies": { "glob-to-regexp": { - "version": "0.3.0", - "integrity": "sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==" + "version": "0.3.0" } } }, "@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", - "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", "dev": true, "optional": true }, "@nodelib/fs.scandir": { "version": "2.1.3", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", "requires": { "@nodelib/fs.stat": "2.0.3", "run-parallel": "^1.1.9" }, "dependencies": { "@nodelib/fs.stat": { - "version": "2.0.3", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" + "version": "2.0.3" } } }, "@nodelib/fs.stat": { - "version": "2.0.5", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + "version": "2.0.5" }, "@nodelib/fs.walk": { "version": "1.2.4", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", "requires": { "@nodelib/fs.scandir": "2.1.3", "fastq": "^1.6.0" } }, - "@npmcli/ci-detect": { - "version": "1.4.0", - "integrity": "sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q==", - "dev": true - }, "@npmcli/fs": { "version": "1.0.0", - "integrity": "sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ==", "requires": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" @@ -55758,127 +60246,147 @@ "dependencies": { "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "requires": { "yallist": "^4.0.0" } }, "semver": { "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "requires": { "lru-cache": "^6.0.0" } }, "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "4.0.0" } } }, - "@npmcli/git": { - "version": "2.1.0", - "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", + "@npmcli/installed-package-contents": { + "version": "1.0.7", "dev": true, "requires": { - "@npmcli/promise-spawn": "^1.3.2", - "lru-cache": "^6.0.0", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/map-workspaces": { + "version": "2.0.4", + "dev": true, + "requires": { + "@npmcli/name-from-folder": "^1.0.1", + "glob": "^8.0.1", + "minimatch": "^5.0.1", + "read-package-json-fast": "^2.0.3" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.2", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "requires": { "mkdirp": "^1.0.4", - "npm-pick-manifest": "^6.1.1", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" + "rimraf": "^3.0.2" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4" + } + } + }, + "@npmcli/name-from-folder": { + "version": "1.0.1", + "dev": true + }, + "@nrwl/cli": { + "version": "15.3.3", + "dev": true, + "requires": { + "nx": "15.3.3" + } + }, + "@nrwl/devkit": { + "version": "15.3.3", + "dev": true, + "requires": { + "@phenomnomnominal/tsquery": "4.1.1", + "ejs": "^3.1.7", + "ignore": "^5.0.4", + "semver": "7.3.4", + "tslib": "^2.3.0" }, "dependencies": { + "ignore": { + "version": "5.2.4", + "dev": true + }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, - "mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.4", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, - "which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } + "tslib": { + "version": "2.4.1", + "dev": true }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, - "@npmcli/installed-package-contents": { - "version": "1.0.7", - "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", - "dev": true, - "requires": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "@npmcli/move-file": { - "version": "1.1.2", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "requires": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - } - } - }, - "@npmcli/node-gyp": { - "version": "1.0.3", - "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", - "dev": true - }, - "@npmcli/promise-spawn": { - "version": "1.3.2", - "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "@nrwl/tao": { + "version": "15.3.3", "dev": true, "requires": { - "infer-owner": "^1.0.4" + "nx": "15.3.3" } }, "@octokit/auth-token": { "version": "2.5.0", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", - "dev": true, "requires": { "@octokit/types": "^6.0.3" } }, "@octokit/core": { - "version": "3.5.1", - "integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==", - "dev": true, + "version": "3.6.0", "requires": { "@octokit/auth-token": "^2.4.4", "@octokit/graphql": "^4.5.8", - "@octokit/request": "^5.6.0", + "@octokit/request": "^5.6.3", "@octokit/request-error": "^2.0.5", "@octokit/types": "^6.0.3", "before-after-hook": "^2.2.0", @@ -55887,25 +60395,16 @@ "dependencies": { "@octokit/request-error": { "version": "2.1.0", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", - "dev": true, "requires": { "@octokit/types": "^6.0.3", "deprecation": "^2.0.0", "once": "^1.4.0" } - }, - "universal-user-agent": { - "version": "6.0.0", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true } } }, "@octokit/endpoint": { "version": "6.0.12", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", - "dev": true, "requires": { "@octokit/types": "^6.0.3", "is-plain-object": "^5.0.0", @@ -55913,275 +60412,814 @@ }, "dependencies": { "is-plain-object": { - "version": "5.0.0", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true - }, - "universal-user-agent": { - "version": "6.0.0", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true + "version": "5.0.0" } } }, "@octokit/graphql": { "version": "4.8.0", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", - "dev": true, "requires": { "@octokit/request": "^5.6.0", "@octokit/types": "^6.0.3", "universal-user-agent": "^6.0.0" - }, - "dependencies": { - "universal-user-agent": { - "version": "6.0.0", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true - } } }, "@octokit/openapi-types": { - "version": "11.2.0", - "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==", - "dev": true + "version": "11.2.0" }, "@octokit/plugin-enterprise-rest": { "version": "6.0.1", - "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", "dev": true }, "@octokit/plugin-paginate-rest": { "version": "2.17.0", - "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", - "dev": true, "requires": { "@octokit/types": "^6.34.0" } }, "@octokit/plugin-request-log": { - "version": "1.0.4", - "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", - "dev": true + "version": "1.0.4" }, "@octokit/plugin-rest-endpoint-methods": { "version": "5.13.0", - "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", - "dev": true, "requires": { "@octokit/types": "^6.34.0", "deprecation": "^2.3.1" } }, "@octokit/request": { - "version": "5.6.2", - "integrity": "sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA==", - "dev": true, + "version": "5.6.3", "requires": { "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.1.0", "@octokit/types": "^6.16.1", "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.1", + "node-fetch": "^2.6.7", "universal-user-agent": "^6.0.0" }, "dependencies": { "@octokit/request-error": { "version": "2.1.0", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "requires": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "is-plain-object": { + "version": "5.0.0" + } + } + }, + "@octokit/request-error": { + "version": "3.0.2", + "dev": true, + "requires": { + "@octokit/types": "^8.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "dependencies": { + "@octokit/openapi-types": { + "version": "14.0.0", + "dev": true + }, + "@octokit/types": { + "version": "8.0.0", + "dev": true, + "requires": { + "@octokit/openapi-types": "^14.0.0" + } + } + } + }, + "@octokit/rest": { + "version": "18.12.0", + "requires": { + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" + } + }, + "@octokit/types": { + "version": "6.34.0", + "requires": { + "@octokit/openapi-types": "^11.2.0" + } + }, + "@parcel/watcher": { + "version": "2.0.4", + "dev": true, + "requires": { + "node-addon-api": "^3.2.1", + "node-gyp-build": "^4.3.0" + } + }, + "@phenomnomnominal/tsquery": { + "version": "4.1.1", + "dev": true, + "requires": { + "esquery": "^1.0.1" + } + }, + "@polka/url": { + "version": "1.0.0-next.20", + "dev": true + }, + "@popperjs/core": { + "version": "2.10.1" + }, + "@probe.gl/stats": { + "version": "3.4.0", + "requires": { + "@babel/runtime": "^7.0.0" + } + }, + "@react-dnd/asap": { + "version": "4.0.0" + }, + "@react-dnd/invariant": { + "version": "2.0.0" + }, + "@react-dnd/shallowequal": { + "version": "2.0.0" + }, + "@react-icons/all-files": { + "version": "4.1.0" + }, + "@samverschueren/stream-to-observable": { + "version": "0.3.1", + "dev": true, + "requires": { + "any-observable": "^0.3.0" + } + }, + "@sinonjs/commons": { + "version": "1.8.3", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/formatio": { + "version": "5.0.1", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.3.1", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "dev": true + }, + "@storybook/addon-actions": { + "version": "6.4.22", + "requires": { + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/theming": "6.4.22", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "polished": "^4.0.5", + "prop-types": "^15.7.2", + "react-inspector": "^5.1.0", + "regenerator-runtime": "^0.13.7", + "telejson": "^5.3.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2", + "uuid-browser": "^3.1.0" + }, + "dependencies": { + "polished": { + "version": "4.2.2", + "requires": { + "@babel/runtime": "^7.17.8" + } + } + } + }, + "@storybook/addon-backgrounds": { + "version": "6.4.22", + "dev": true, + "requires": { + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core-events": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/theming": "6.4.22", + "core-js": "^3.8.2", + "global": "^4.4.0", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/addon-controls": { + "version": "6.4.22", + "dev": true, + "requires": { + "@storybook/addons": "6.4.22", + "@storybook/api": "6.4.22", + "@storybook/client-logger": "6.4.22", + "@storybook/components": "6.4.22", + "@storybook/core-common": "6.4.22", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/node-logger": "6.4.22", + "@storybook/store": "6.4.22", + "@storybook/theming": "6.4.22", + "core-js": "^3.8.2", + "lodash": "^4.17.21", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/addon-docs": { + "version": "6.5.10", + "dev": true, + "requires": { + "@babel/plugin-transform-react-jsx": "^7.12.12", + "@babel/preset-env": "^7.12.11", + "@jest/transform": "^26.6.2", + "@mdx-js/react": "^1.6.22", + "@storybook/addons": "6.5.10", + "@storybook/api": "6.5.10", + "@storybook/components": "6.5.10", + "@storybook/core-common": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/docs-tools": "6.5.10", + "@storybook/mdx1-csf": "^0.0.1", + "@storybook/node-logger": "6.5.10", + "@storybook/postinstall": "6.5.10", + "@storybook/preview-web": "6.5.10", + "@storybook/source-loader": "6.5.10", + "@storybook/store": "6.5.10", + "@storybook/theming": "6.5.10", + "babel-loader": "^8.0.0", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "regenerator-runtime": "^0.13.7", + "remark-external-links": "^8.0.0", + "remark-slug": "^6.0.0", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "dependencies": { + "@storybook/addons": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/api": "6.5.10", + "@storybook/channels": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.10", + "@storybook/theming": "6.5.10", + "@types/webpack-env": "^1.16.0", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7" + } + }, + "@storybook/api": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/channels": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.10", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.5.10", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.12.0", + "telejson": "^6.0.8", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/channel-postmessage": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/channels": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "core-js": "^3.8.2", + "global": "^4.4.0", + "qs": "^6.10.0", + "telejson": "^6.0.8" + } + }, + "@storybook/channels": { + "version": "6.5.10", + "dev": true, + "requires": { + "core-js": "^3.8.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/client-logger": { + "version": "6.5.10", + "dev": true, + "requires": { + "core-js": "^3.8.2", + "global": "^4.4.0" + } + }, + "@storybook/components": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/client-logger": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/theming": "6.5.10", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/core-common": { + "version": "6.5.10", + "dev": true, + "requires": { + "@babel/core": "^7.12.10", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-decorators": "^7.12.12", + "@babel/plugin-proposal-export-default-from": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.7", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-proposal-private-property-in-object": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.12", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/preset-env": "^7.12.11", + "@babel/preset-react": "^7.12.10", + "@babel/preset-typescript": "^7.12.7", + "@babel/register": "^7.12.1", + "@storybook/node-logger": "6.5.10", + "@storybook/semver": "^7.3.2", + "@types/node": "^14.0.10 || ^16.0.0", + "@types/pretty-hrtime": "^1.0.0", + "babel-loader": "^8.0.0", + "babel-plugin-macros": "^3.0.1", + "babel-plugin-polyfill-corejs3": "^0.1.0", + "chalk": "^4.1.0", + "core-js": "^3.8.2", + "express": "^4.17.1", + "file-system-cache": "^1.0.5", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.0.4", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "handlebars": "^4.7.7", + "interpret": "^2.2.0", + "json5": "^2.1.3", + "lazy-universal-dotenv": "^3.0.1", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "slash": "^3.0.0", + "telejson": "^6.0.8", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2", + "webpack": "4" + } + }, + "@storybook/core-events": { + "version": "6.5.10", + "dev": true, + "requires": { + "core-js": "^3.8.2" + } + }, + "@storybook/csf": { + "version": "0.0.2--canary.4566f4d.1", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "@storybook/node-logger": { + "version": "6.5.10", + "dev": true, + "requires": { + "@types/npmlog": "^4.1.2", + "chalk": "^4.1.0", + "core-js": "^3.8.2", + "npmlog": "^5.0.1", + "pretty-hrtime": "^1.0.3" + } + }, + "@storybook/postinstall": { + "version": "6.5.10", + "dev": true, + "requires": { + "core-js": "^3.8.2" + } + }, + "@storybook/preview-web": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/addons": "6.5.10", + "@storybook/channel-postmessage": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/store": "6.5.10", + "ansi-to-html": "^0.6.11", + "core-js": "^3.8.2", + "global": "^4.4.0", + "lodash": "^4.17.21", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7", + "synchronous-promise": "^2.0.15", + "ts-dedent": "^2.0.0", + "unfetch": "^4.2.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/router": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/client-logger": "6.5.10", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7" + } + }, + "@storybook/source-loader": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/addons": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "core-js": "^3.8.2", + "estraverse": "^5.2.0", + "global": "^4.4.0", + "loader-utils": "^2.0.0", + "lodash": "^4.17.21", + "prettier": ">=2.2.1 <=2.3.0", + "regenerator-runtime": "^0.13.7" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "@storybook/store": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/addons": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "slash": "^3.0.0", + "stable": "^0.1.8", + "synchronous-promise": "^2.0.15", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/theming": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/client-logger": "6.5.10", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7" + } + }, + "@types/node": { + "version": "16.11.48", + "dev": true + }, + "acorn": { + "version": "6.4.2", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "dev": true + }, + "are-we-there-yet": { + "version": "2.0.0", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "babel-plugin-macros": { + "version": "3.1.0", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + } + }, + "eslint-scope": { + "version": "4.0.3", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "dev": true + } + } + }, + "estraverse": { + "version": "5.3.0", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "fs-extra": { + "version": "9.1.0", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "gauge": { + "version": "3.0.2", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true + }, + "isobject": { + "version": "4.0.0", + "dev": true + }, + "json5": { + "version": "2.2.3", + "dev": true + }, + "loader-runner": { + "version": "2.4.0", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "npmlog": { + "version": "5.0.1", + "dev": true, + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "p-limit": { + "version": "3.1.0", "dev": true, "requires": { - "@octokit/types": "^6.0.3", - "deprecation": "^2.0.0", - "once": "^1.4.0" + "yocto-queue": "^0.1.0" } }, - "is-plain-object": { + "p-locate": { "version": "5.0.0", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", "dev": true }, - "universal-user-agent": { - "version": "6.0.0", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "pkg-dir": { + "version": "5.0.0", + "dev": true, + "requires": { + "find-up": "^5.0.0" + } + }, + "prettier": { + "version": "2.3.0", "dev": true - } - } - }, - "@octokit/rest": { - "version": "18.12.0", - "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", - "dev": true, - "requires": { - "@octokit/core": "^3.5.1", - "@octokit/plugin-paginate-rest": "^2.16.8", - "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^5.12.0" - } - }, - "@octokit/types": { - "version": "6.34.0", - "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", - "dev": true, - "requires": { - "@octokit/openapi-types": "^11.2.0" - } - }, - "@polka/url": { - "version": "1.0.0-next.20", - "integrity": "sha512-88p7+M0QGxKpmnkfXjS4V26AnoC/eiqZutE8GLdaI5X12NY75bXSdTY9NkmYb2Xyk1O+MmkuO6Frmsj84V6I8Q==", - "dev": true - }, - "@popperjs/core": { - "version": "2.10.1", - "integrity": "sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw==" - }, - "@probe.gl/stats": { - "version": "3.4.0", - "integrity": "sha512-Gl37r9qGuiKadIvTZdSZvzCNOttJYw6RcY1oT0oDuB8r2uhuZAdSMQRQTy9FTinp6MY6O9wngGnV6EpQ8wSBAw==", - "requires": { - "@babel/runtime": "^7.0.0" - } - }, - "@react-dnd/asap": { - "version": "4.0.0", - "integrity": "sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ==" - }, - "@react-dnd/invariant": { - "version": "2.0.0", - "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" - }, - "@react-dnd/shallowequal": { - "version": "2.0.0", - "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" - }, - "@react-icons/all-files": { - "version": "4.1.0", - "integrity": "sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==" - }, - "@samverschueren/stream-to-observable": { - "version": "0.3.1", - "integrity": "sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ==", - "dev": true, - "requires": { - "any-observable": "^0.3.0" - } - }, - "@sinonjs/commons": { - "version": "1.8.3", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "6.0.1", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@sinonjs/formatio": { - "version": "5.0.1", - "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^5.0.2" - } - }, - "@sinonjs/samsam": { - "version": "5.3.1", - "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "@sinonjs/text-encoding": { - "version": "0.7.1", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true - }, - "@storybook/addon-actions": { - "version": "6.4.22", - "integrity": "sha512-t2w3iLXFul+R/1ekYxIEzUOZZmvEa7EzUAVAuCHP4i6x0jBnTTZ7sAIUVRaxVREPguH5IqI/2OklYhKanty2Yw==", - "requires": { - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/theming": "6.4.22", - "core-js": "^3.8.2", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "lodash": "^4.17.21", - "polished": "^4.0.5", - "prop-types": "^15.7.2", - "react-inspector": "^5.1.0", - "regenerator-runtime": "^0.13.7", - "telejson": "^5.3.2", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2", - "uuid-browser": "^3.1.0" - }, - "dependencies": { - "polished": { - "version": "4.2.2", - "integrity": "sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==", + }, + "qs": { + "version": "6.11.0", + "dev": true, "requires": { - "@babel/runtime": "^7.17.8" + "side-channel": "^1.0.4" + } + }, + "readable-stream": { + "version": "3.6.0", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "resolve-from": { + "version": "5.0.0", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "slash": { + "version": "3.0.0", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "telejson": { + "version": "6.0.8", + "dev": true, + "requires": { + "@types/is-function": "^1.0.0", + "global": "^4.4.0", + "is-function": "^1.0.2", + "is-regex": "^1.1.2", + "is-symbol": "^1.0.3", + "isobject": "^4.0.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3" + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + }, + "webpack": { + "version": "4.46.0", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + } + }, + "webpack-sources": { + "version": "1.4.3", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" } } } }, - "@storybook/addon-backgrounds": { - "version": "6.4.22", - "integrity": "sha512-xQIV1SsjjRXP7P5tUoGKv+pul1EY8lsV7iBXQb5eGbp4AffBj3qoYBSZbX4uiazl21o0MQiQoeIhhaPVaFIIGg==", - "dev": true, - "requires": { - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core-events": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/theming": "6.4.22", - "core-js": "^3.8.2", - "global": "^4.4.0", - "memoizerific": "^1.11.3", - "regenerator-runtime": "^0.13.7", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - } - }, - "@storybook/addon-controls": { - "version": "6.4.22", - "integrity": "sha512-f/M/W+7UTEUnr/L6scBMvksq+ZA8GTfh3bomE5FtWyOyaFppq9k8daKAvdYNlzXAOrUUsoZVJDgpb20Z2VBiSQ==", - "dev": true, - "requires": { - "@storybook/addons": "6.4.22", - "@storybook/api": "6.4.22", - "@storybook/client-logger": "6.4.22", - "@storybook/components": "6.4.22", - "@storybook/core-common": "6.4.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/node-logger": "6.4.22", - "@storybook/store": "6.4.22", - "@storybook/theming": "6.4.22", - "core-js": "^3.8.2", - "lodash": "^4.17.21", - "ts-dedent": "^2.0.0" - } - }, "@storybook/addon-essentials": { "version": "6.4.22", - "integrity": "sha512-GTv291fqvWq2wzm7MruBvCGuWaCUiuf7Ca3kzbQ/WqWtve7Y/1PDsqRNQLGZrQxkXU0clXCqY1XtkTrtA3WGFQ==", "dev": true, "requires": { "@storybook/addon-actions": "6.4.22", @@ -56202,7 +61240,6 @@ "dependencies": { "@storybook/addon-docs": { "version": "6.4.22", - "integrity": "sha512-9j+i+W+BGHJuRe4jUrqk6ubCzP4fc1xgFS2o8pakRiZgPn5kUQPdkticmsyh1XeEJifwhqjKJvkEDrcsleytDA==", "dev": true, "requires": { "@babel/core": "^7.12.10", @@ -56255,12 +61292,10 @@ }, "acorn": { "version": "7.4.1", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, "escodegen": { "version": "2.0.0", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "requires": { "esprima": "^4.0.1", @@ -56272,22 +61307,18 @@ }, "esprima": { "version": "4.0.1", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "estraverse": { "version": "5.3.0", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", "dev": true }, "loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", "dev": true, "requires": { "big.js": "^5.2.2", @@ -56297,12 +61328,10 @@ }, "nanoid": { "version": "3.3.4", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "dev": true }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { "yocto-queue": "^0.1.0" @@ -56310,12 +61339,10 @@ }, "prettier": { "version": "2.3.0", - "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", "dev": true }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -56323,7 +61350,6 @@ }, "@storybook/addon-knobs": { "version": "6.3.1", - "integrity": "sha512-2GGGnQSPXXUhHHYv4IW6pkyQlCPYXKYiyGzfhV7Zhs95M2Ban08OA6KLmliMptWCt7U9tqTO8dB5u0C2cWmCTw==", "requires": { "copy-to-clipboard": "^3.3.1", "core-js": "^3.8.2", @@ -56338,71 +61364,16 @@ "react-select": "^3.2.0" }, "dependencies": { - "@emotion/cache": { - "version": "10.0.29", - "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", - "requires": { - "@emotion/sheet": "0.9.4", - "@emotion/stylis": "0.8.5", - "@emotion/utils": "0.11.3", - "@emotion/weak-memoize": "0.2.5" - } - }, - "csstype": { - "version": "3.0.9", - "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==" - }, - "dom-helpers": { - "version": "5.2.1", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "requires": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, "qs": { - "version": "6.10.1", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "version": "6.11.0", "requires": { "side-channel": "^1.0.4" } - }, - "react-input-autosize": { - "version": "3.0.0", - "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==", - "requires": { - "prop-types": "^15.5.8" - } - }, - "react-select": { - "version": "3.2.0", - "integrity": "sha512-B/q3TnCZXEKItO0fFN/I0tWOX3WJvi/X2wtdffmwSQVRwg5BpValScTO1vdic9AxlUgmeSzib2hAZAwIUQUZGQ==", - "requires": { - "@babel/runtime": "^7.4.4", - "@emotion/cache": "^10.0.9", - "@emotion/core": "^10.0.9", - "@emotion/css": "^10.0.9", - "memoize-one": "^5.0.0", - "prop-types": "^15.6.0", - "react-input-autosize": "^3.0.0", - "react-transition-group": "^4.3.0" - } - }, - "react-transition-group": { - "version": "4.4.2", - "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", - "requires": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - } } } }, "@storybook/addon-links": { "version": "6.4.22", - "integrity": "sha512-OSOyDnTXnmcplJHlXTYUTMkrfpLqxtHp2R69IXfAyI1e8WNDb79mXflrEXDA/RSNEliLkqYwCyYby7gDMGds5Q==", "requires": { "@storybook/addons": "6.4.22", "@storybook/client-logger": "6.4.22", @@ -56419,8 +61390,7 @@ }, "dependencies": { "qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", "requires": { "side-channel": "^1.0.4" } @@ -56429,7 +61399,6 @@ }, "@storybook/addon-measure": { "version": "6.4.22", - "integrity": "sha512-CjDXoCNIXxNfXfgyJXPc0McjCcwN1scVNtHa9Ckr+zMjiQ8pPHY7wDZCQsG69KTqcWHiVfxKilI82456bcHYhQ==", "dev": true, "requires": { "@storybook/addons": "6.4.22", @@ -56444,7 +61413,6 @@ }, "@storybook/addon-outline": { "version": "6.4.22", - "integrity": "sha512-VIMEzvBBRbNnupGU7NV0ahpFFb6nKVRGYWGREjtABdFn2fdKr1YicOHFe/3U7hRGjb5gd+VazSvyUvhaKX9T7Q==", "dev": true, "requires": { "@storybook/addons": "6.4.22", @@ -56461,7 +61429,6 @@ }, "@storybook/addon-toolbars": { "version": "6.4.22", - "integrity": "sha512-FFyj6XDYpBBjcUu6Eyng7R805LUbVclEfydZjNiByAoDVyCde9Hb4sngFxn/T4fKAfBz/32HKVXd5iq4AHYtLg==", "dev": true, "requires": { "@storybook/addons": "6.4.22", @@ -56474,7 +61441,6 @@ }, "@storybook/addon-viewport": { "version": "6.4.22", - "integrity": "sha512-6jk0z49LemeTblez5u2bYXYr6U+xIdLbywe3G283+PZCBbEDE6eNYy2d2HDL+LbCLbezJBLYPHPalElphjJIcw==", "dev": true, "requires": { "@storybook/addons": "6.4.22", @@ -56492,7 +61458,6 @@ }, "@storybook/addons": { "version": "6.4.22", - "integrity": "sha512-P/R+Jsxh7pawKLYo8MtE3QU/ilRFKbtCewV/T1o5U/gm8v7hKQdFz3YdRMAra4QuCY8bQIp7MKd2HrB5aH5a1A==", "requires": { "@storybook/api": "6.4.22", "@storybook/channels": "6.4.22", @@ -56509,7 +61474,6 @@ }, "@storybook/api": { "version": "6.4.22", - "integrity": "sha512-lAVI3o2hKupYHXFTt+1nqFct942up5dHH6YD7SZZJGyW21dwKC3HK1IzCsTawq3fZAKkgWFgmOO649hKk60yKg==", "requires": { "@storybook/channels": "6.4.22", "@storybook/client-logger": "6.4.22", @@ -56532,7 +61496,6 @@ }, "@storybook/builder-webpack4": { "version": "6.4.22", - "integrity": "sha512-A+GgGtKGnBneRFSFkDarUIgUTI8pYFdLmUVKEAGdh2hL+vLXAz9A46sEY7C8LQ85XWa8TKy3OTDxqR4+4iWj3A==", "requires": { "@babel/core": "^7.12.10", "@babel/plugin-proposal-class-properties": "^7.12.1", @@ -56606,23 +61569,19 @@ }, "dependencies": { "@types/node": { - "version": "14.18.16", - "integrity": "sha512-X3bUMdK/VmvrWdoTkz+VCn6nwKwrKCFTHtqwBIaQJNx4RUIBBUFXM00bqPz/DsDd+Icjmzm6/tyYZzeGVqb6/Q==" + "version": "14.18.16" }, "acorn": { - "version": "6.4.2", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + "version": "6.4.2" }, "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { "color-convert": "^1.9.0" } }, "chalk": { "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -56631,7 +61590,6 @@ }, "css-loader": { "version": "3.6.0", - "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", "requires": { "camelcase": "^5.3.1", "cssesc": "^3.0.0", @@ -56649,14 +61607,12 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" } } }, "eslint-scope": { "version": "4.0.3", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -56664,7 +61620,6 @@ }, "find-up": { "version": "5.0.0", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "requires": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -56672,7 +61627,6 @@ }, "fork-ts-checker-webpack-plugin": { "version": "4.1.6", - "integrity": "sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==", "requires": { "@babel/code-frame": "^7.5.5", "chalk": "^2.4.1", @@ -56685,7 +61639,6 @@ }, "html-webpack-plugin": { "version": "4.5.2", - "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", "requires": { "@types/html-minifier-terser": "^5.0.0", "@types/tapable": "^1.0.5", @@ -56700,51 +61653,42 @@ }, "icss-utils": { "version": "4.1.1", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", "requires": { "postcss": "^7.0.14" } }, "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3" }, "loader-runner": { - "version": "2.4.0", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + "version": "2.4.0" }, "locate-path": { "version": "6.0.0", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "requires": { "p-locate": "^5.0.0" } }, "normalize-path": { - "version": "3.0.0", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "version": "3.0.0" }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "requires": { "yocto-queue": "^0.1.0" } }, "p-locate": { "version": "5.0.0", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "requires": { "p-limit": "^3.0.2" } }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" }, "postcss": { "version": "7.0.39", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "requires": { "picocolors": "^0.2.1", "source-map": "^0.6.1" @@ -56752,14 +61696,12 @@ }, "postcss-modules-extract-imports": { "version": "2.0.0", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", "requires": { "postcss": "^7.0.5" } }, "postcss-modules-local-by-default": { "version": "3.0.3", - "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", "requires": { "icss-utils": "^4.1.1", "postcss": "^7.0.32", @@ -56769,7 +61711,6 @@ }, "postcss-modules-scope": { "version": "2.2.0", - "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", "requires": { "postcss": "^7.0.6", "postcss-selector-parser": "^6.0.0" @@ -56777,7 +61718,6 @@ }, "postcss-modules-values": { "version": "3.0.0", - "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", "requires": { "icss-utils": "^4.0.0", "postcss": "^7.0.6" @@ -56785,7 +61725,6 @@ }, "pretty-error": { "version": "2.1.2", - "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", "requires": { "lodash": "^4.17.20", "renderkid": "^2.0.4" @@ -56793,7 +61732,6 @@ }, "schema-utils": { "version": "2.7.1", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", "requires": { "@types/json-schema": "^7.0.5", "ajv": "^6.12.4", @@ -56801,20 +61739,17 @@ } }, "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" }, "style-loader": { "version": "1.3.0", - "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==", "requires": { "loader-utils": "^2.0.0", "schema-utils": "^2.7.0" }, "dependencies": { "loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -56825,14 +61760,12 @@ }, "supports-color": { "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { "has-flag": "^3.0.0" } }, "webpack": { "version": "4.46.0", - "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-module-context": "1.9.0", @@ -56861,7 +61794,6 @@ "dependencies": { "schema-utils": { "version": "1.0.0", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", @@ -56870,7 +61802,6 @@ }, "terser-webpack-plugin": { "version": "1.4.5", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", "requires": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", @@ -56886,12 +61817,10 @@ } }, "webpack-filter-warnings-plugin": { - "version": "1.2.1", - "integrity": "sha512-Ez6ytc9IseDMLPo0qCuNNYzgtUl8NovOqjIq4uAU8LTD4uoa1w1KpZyyzFtLTEMZpkkOkLfL9eN+KGYdk1Qtwg==" + "version": "1.2.1" }, "webpack-sources": { "version": "1.4.3", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" @@ -56901,7 +61830,6 @@ }, "@storybook/builder-webpack5": { "version": "6.4.22", - "integrity": "sha512-vvQ0HgkIIVz+cmaCXIRor0UFZbGZqh4aV0ISSof60BjdW5ld+R+XCr/bdTU6Zg8b2fL9CXh7/LE6fImnIMpRIA==", "dev": true, "requires": { "@babel/core": "^7.12.10", @@ -56965,12 +61893,10 @@ "dependencies": { "@types/node": { "version": "14.17.19", - "integrity": "sha512-jjYI6NkyfXykucU6ELEoT64QyKOdvaA6enOqKtP4xUsGY0X0ZUZz29fUmrTRo+7v7c6TgDu82q3GHHaCEkqZwA==", "dev": true }, "babel-plugin-macros": { "version": "3.1.0", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", @@ -56980,7 +61906,6 @@ }, "css-loader": { "version": "5.2.7", - "integrity": "sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==", "dev": true, "requires": { "icss-utils": "^5.1.0", @@ -56997,7 +61922,6 @@ "dependencies": { "semver": { "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -57007,12 +61931,10 @@ }, "has-flag": { "version": "4.0.0", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "jest-worker": { "version": "27.2.3", - "integrity": "sha512-ZwOvv4GCIPviL+Ie4pVguz4N5w/6IGbTaHBYOl3ZcsZZktaL7d8JOU0rmovoED7AJZKA8fvmLbBg8yg80u/tGA==", "dev": true, "requires": { "@types/node": "*", @@ -57021,16 +61943,11 @@ } }, "json5": { - "version": "2.2.0", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3", + "dev": true }, "loader-utils": { - "version": "2.0.0", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "version": "2.0.4", "dev": true, "requires": { "big.js": "^5.2.2", @@ -57040,7 +61957,6 @@ }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -57048,7 +61964,6 @@ }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { "yocto-queue": "^0.1.0" @@ -57056,7 +61971,6 @@ }, "serialize-javascript": { "version": "6.0.0", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -57064,12 +61978,10 @@ }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "style-loader": { "version": "2.0.0", - "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==", "dev": true, "requires": { "loader-utils": "^2.0.0", @@ -57078,32 +61990,23 @@ }, "supports-color": { "version": "8.1.1", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" } }, "terser": { - "version": "5.9.0", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "version": "5.14.2", "dev": true, "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } } }, "terser-webpack-plugin": { "version": "5.2.4", - "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", "dev": true, "requires": { "jest-worker": "^27.0.6", @@ -57116,7 +62019,6 @@ }, "webpack-dev-middleware": { "version": "4.3.0", - "integrity": "sha512-PjwyVY95/bhBh6VUqt6z4THplYcsvQ8YNNBTBM873xLVmw8FLeALn0qurHbs9EmcfhzQis/eoqypSnZeuUz26w==", "dev": true, "requires": { "colorette": "^1.2.2", @@ -57129,19 +62031,16 @@ }, "webpack-virtual-modules": { "version": "0.4.3", - "integrity": "sha512-5NUqC2JquIL2pBAAo/VfBP6KuGkHIZQXW/lNKupLPfhViwh8wNsu0BObtl09yuKZszeEUfbXz8xhrHvSG16Nqw==", "dev": true }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@storybook/channel-postmessage": { "version": "6.4.22", - "integrity": "sha512-gt+0VZLszt2XZyQMh8E94TqjHZ8ZFXZ+Lv/Mmzl0Yogsc2H+6VzTTQO4sv0IIx6xLbpgG72g5cr8VHsxW5kuDQ==", "requires": { "@storybook/channels": "6.4.22", "@storybook/client-logger": "6.4.22", @@ -57153,8 +62052,7 @@ }, "dependencies": { "qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", "requires": { "side-channel": "^1.0.4" } @@ -57163,7 +62061,6 @@ }, "@storybook/channel-websocket": { "version": "6.4.22", - "integrity": "sha512-Bm/FcZ4Su4SAK5DmhyKKfHkr7HiHBui6PNutmFkASJInrL9wBduBfN8YQYaV7ztr8ezoHqnYRx8sj28jpwa6NA==", "requires": { "@storybook/channels": "6.4.22", "@storybook/client-logger": "6.4.22", @@ -57174,7 +62071,6 @@ }, "@storybook/channels": { "version": "6.4.22", - "integrity": "sha512-cfR74tu7MLah1A8Rru5sak71I+kH2e/sY6gkpVmlvBj4hEmdZp4Puj9PTeaKcMXh9DgIDPNA5mb8yvQH6VcyxQ==", "requires": { "core-js": "^3.8.2", "ts-dedent": "^2.0.0", @@ -57183,7 +62079,6 @@ }, "@storybook/client-api": { "version": "6.4.22", - "integrity": "sha512-sO6HJNtrrdit7dNXQcZMdlmmZG1k6TswH3gAyP/DoYajycrTwSJ6ovkarzkO+0QcJ+etgra4TEdTIXiGHBMe/A==", "requires": { "@storybook/addons": "6.4.22", "@storybook/channel-postmessage": "6.4.22", @@ -57208,8 +62103,7 @@ }, "dependencies": { "qs": { - "version": "6.10.1", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "version": "6.11.0", "requires": { "side-channel": "^1.0.4" } @@ -57218,7 +62112,6 @@ }, "@storybook/client-logger": { "version": "6.4.22", - "integrity": "sha512-LXhxh/lcDsdGnK8kimqfhu3C0+D2ylCSPPQNbU0IsLRmTfbpQYMdyl0XBjPdHiRVwlL7Gkw5OMjYemQgJ02zlw==", "requires": { "core-js": "^3.8.2", "global": "^4.4.0" @@ -57226,7 +62119,6 @@ }, "@storybook/components": { "version": "6.4.22", - "integrity": "sha512-dCbXIJF9orMvH72VtAfCQsYbe57OP7fAADtR6YTwfCw9Sm1jFuZr8JbblQ1HcrXEoJG21nOyad3Hm5EYVb/sBw==", "requires": { "@popperjs/core": "^2.6.0", "@storybook/client-logger": "6.4.22", @@ -57256,25 +62148,21 @@ "dependencies": { "color-convert": { "version": "2.0.1", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "version": "1.1.4" }, "polished": { "version": "4.1.3", - "integrity": "sha512-ocPAcVBUOryJEKe0z2KLd1l9EBa1r5mSwlKpExmrLzsnIzJo4axsoU9O2BjOTkDGDT4mZ0WFE5XKTlR3nLnZOA==", "requires": { "@babel/runtime": "^7.14.0" } }, "react-syntax-highlighter": { "version": "13.5.3", - "integrity": "sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg==", "requires": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.1.1", @@ -57287,7 +62175,6 @@ }, "@storybook/core": { "version": "6.4.22", - "integrity": "sha512-KZYJt7GM5NgKFXbPRZZZPEONZ5u/tE/cRbMdkn/zWN3He8+VP+65/tz8hbriI/6m91AWVWkBKrODSkeq59NgRA==", "requires": { "@storybook/core-client": "6.4.22", "@storybook/core-server": "6.4.22" @@ -57295,7 +62182,6 @@ }, "@storybook/core-client": { "version": "6.4.22", - "integrity": "sha512-uHg4yfCBeM6eASSVxStWRVTZrAnb4FT6X6v/xDqr4uXCpCttZLlBzrSDwPBLNNLtCa7ntRicHM8eGKIOD5lMYQ==", "requires": { "@storybook/addons": "6.4.22", "@storybook/channel-postmessage": "6.4.22", @@ -57320,8 +62206,7 @@ }, "dependencies": { "qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", "requires": { "side-channel": "^1.0.4" } @@ -57330,7 +62215,6 @@ }, "@storybook/core-common": { "version": "6.4.22", - "integrity": "sha512-PD3N/FJXPNRHeQS2zdgzYFtqPLdi3MLwAicbnw+U3SokcsspfsAuyYHZOYZgwO8IAEKy6iCc7TpBdiSJZ/vAKQ==", "requires": { "@babel/core": "^7.12.10", "@babel/plugin-proposal-class-properties": "^7.12.1", @@ -57384,16 +62268,13 @@ }, "dependencies": { "@types/node": { - "version": "14.18.16", - "integrity": "sha512-X3bUMdK/VmvrWdoTkz+VCn6nwKwrKCFTHtqwBIaQJNx4RUIBBUFXM00bqPz/DsDd+Icjmzm6/tyYZzeGVqb6/Q==" + "version": "14.18.16" }, "acorn": { - "version": "6.4.2", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + "version": "6.4.2" }, "babel-plugin-macros": { "version": "3.1.0", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", "requires": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -57402,7 +62283,6 @@ }, "eslint-scope": { "version": "4.0.3", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -57410,7 +62290,6 @@ }, "find-up": { "version": "5.0.0", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "requires": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -57418,7 +62297,6 @@ }, "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -57427,52 +62305,43 @@ } }, "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3" }, "loader-runner": { - "version": "2.4.0", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + "version": "2.4.0" }, "locate-path": { "version": "6.0.0", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "requires": { "p-locate": "^5.0.0" } }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "requires": { "yocto-queue": "^0.1.0" } }, "p-locate": { "version": "5.0.0", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "requires": { "p-limit": "^3.0.2" } }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" }, "pkg-dir": { "version": "5.0.0", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", "requires": { "find-up": "^5.0.0" } }, "resolve-from": { - "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + "version": "5.0.0" }, "schema-utils": { "version": "1.0.0", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", @@ -57480,16 +62349,13 @@ } }, "slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + "version": "3.0.0" }, "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" }, "terser-webpack-plugin": { "version": "1.4.5", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", "requires": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", @@ -57504,7 +62370,6 @@ }, "webpack": { "version": "4.46.0", - "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-module-context": "1.9.0", @@ -57533,7 +62398,6 @@ }, "webpack-sources": { "version": "1.4.3", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" @@ -57543,14 +62407,12 @@ }, "@storybook/core-events": { "version": "6.4.22", - "integrity": "sha512-5GYY5+1gd58Gxjqex27RVaX6qbfIQmJxcbzbNpXGNSqwqAuIIepcV1rdCVm6I4C3Yb7/AQ3cN5dVbf33QxRIwA==", "requires": { "core-js": "^3.8.2" } }, "@storybook/core-server": { "version": "6.4.22", - "integrity": "sha512-wFh3e2fa0un1d4+BJP+nd3FVWUO7uHTqv3OGBfOmzQMKp4NU1zaBNdSQG7Hz6mw0fYPBPZgBjPfsJRwIYLLZyw==", "requires": { "@discoveryjs/json-ext": "^0.5.3", "@storybook/builder-webpack4": "6.4.22", @@ -57597,20 +62459,16 @@ }, "dependencies": { "@types/node": { - "version": "14.18.16", - "integrity": "sha512-X3bUMdK/VmvrWdoTkz+VCn6nwKwrKCFTHtqwBIaQJNx4RUIBBUFXM00bqPz/DsDd+Icjmzm6/tyYZzeGVqb6/Q==" + "version": "14.18.16" }, "acorn": { - "version": "6.4.2", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + "version": "6.4.2" }, "commander": { - "version": "6.2.1", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==" + "version": "6.2.1" }, "eslint-scope": { "version": "4.0.3", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -57618,7 +62476,6 @@ }, "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -57627,12 +62484,10 @@ } }, "loader-runner": { - "version": "2.4.0", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + "version": "2.4.0" }, "schema-utils": { "version": "1.0.0", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", @@ -57640,16 +62495,13 @@ } }, "slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + "version": "3.0.0" }, "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" }, "terser-webpack-plugin": { "version": "1.4.5", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", "requires": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", @@ -57664,7 +62516,6 @@ }, "watchpack": { "version": "2.3.1", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", "requires": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -57672,7 +62523,6 @@ }, "webpack": { "version": "4.46.0", - "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-module-context": "1.9.0", @@ -57701,7 +62551,6 @@ "dependencies": { "watchpack": { "version": "1.7.5", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", "requires": { "chokidar": "^3.4.1", "graceful-fs": "^4.1.2", @@ -57713,28 +62562,24 @@ }, "webpack-sources": { "version": "1.4.3", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" } }, "ws": { - "version": "8.6.0", - "integrity": "sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==" + "version": "8.6.0" } } }, "@storybook/csf": { "version": "0.0.2--canary.87bc651.0", - "integrity": "sha512-ajk1Uxa+rBpFQHKrCcTmJyQBXZ5slfwHVEaKlkuFaW77it8RgbPJp/ccna3sgoi8oZ7FkkOyvv1Ve4SmwFqRqw==", "requires": { "lodash": "^4.17.15" } }, "@storybook/csf-tools": { "version": "6.4.22", - "integrity": "sha512-LMu8MZAiQspJAtMBLU2zitsIkqQv7jOwX7ih5JrXlyaDticH7l2j6Q+1mCZNWUOiMTizj0ivulmUsSaYbpToSw==", "requires": { "@babel/core": "^7.12.10", "@babel/generator": "^7.12.11", @@ -57757,7 +62602,6 @@ "dependencies": { "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -57766,14 +62610,169 @@ } }, "prettier": { - "version": "2.3.0", - "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==" + "version": "2.3.0" + } + } + }, + "@storybook/docs-tools": { + "version": "6.5.10", + "dev": true, + "requires": { + "@babel/core": "^7.12.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/store": "6.5.10", + "core-js": "^3.8.2", + "doctrine": "^3.0.0", + "lodash": "^4.17.21", + "regenerator-runtime": "^0.13.7" + }, + "dependencies": { + "@storybook/addons": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/api": "6.5.10", + "@storybook/channels": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.10", + "@storybook/theming": "6.5.10", + "@types/webpack-env": "^1.16.0", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7" + } + }, + "@storybook/api": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/channels": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.10", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.5.10", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.12.0", + "telejson": "^6.0.8", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/channels": { + "version": "6.5.10", + "dev": true, + "requires": { + "core-js": "^3.8.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/client-logger": { + "version": "6.5.10", + "dev": true, + "requires": { + "core-js": "^3.8.2", + "global": "^4.4.0" + } + }, + "@storybook/core-events": { + "version": "6.5.10", + "dev": true, + "requires": { + "core-js": "^3.8.2" + } + }, + "@storybook/csf": { + "version": "0.0.2--canary.4566f4d.1", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "@storybook/router": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/client-logger": "6.5.10", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7" + } + }, + "@storybook/store": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/addons": "6.5.10", + "@storybook/client-logger": "6.5.10", + "@storybook/core-events": "6.5.10", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "slash": "^3.0.0", + "stable": "^0.1.8", + "synchronous-promise": "^2.0.15", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/theming": { + "version": "6.5.10", + "dev": true, + "requires": { + "@storybook/client-logger": "6.5.10", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7" + } + }, + "isobject": { + "version": "4.0.0", + "dev": true + }, + "qs": { + "version": "6.11.0", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "slash": { + "version": "3.0.0", + "dev": true + }, + "telejson": { + "version": "6.0.8", + "dev": true, + "requires": { + "@types/is-function": "^1.0.0", + "global": "^4.4.0", + "is-function": "^1.0.2", + "is-regex": "^1.1.2", + "is-symbol": "^1.0.3", + "isobject": "^4.0.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3" + } } } }, "@storybook/manager-webpack4": { "version": "6.4.22", - "integrity": "sha512-nzhDMJYg0vXdcG0ctwE6YFZBX71+5NYaTGkxg3xT7gbgnP1YFXn9gVODvgq3tPb3gcRapjyOIxUa20rV+r8edA==", "requires": { "@babel/core": "^7.12.10", "@babel/plugin-transform-template-literals": "^7.12.1", @@ -57814,16 +62813,13 @@ }, "dependencies": { "@types/node": { - "version": "14.18.16", - "integrity": "sha512-X3bUMdK/VmvrWdoTkz+VCn6nwKwrKCFTHtqwBIaQJNx4RUIBBUFXM00bqPz/DsDd+Icjmzm6/tyYZzeGVqb6/Q==" + "version": "14.18.16" }, "acorn": { - "version": "6.4.2", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + "version": "6.4.2" }, "css-loader": { "version": "3.6.0", - "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", "requires": { "camelcase": "^5.3.1", "cssesc": "^3.0.0", @@ -57842,7 +62838,6 @@ }, "eslint-scope": { "version": "4.0.3", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -57850,7 +62845,6 @@ }, "find-up": { "version": "5.0.0", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "requires": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -57858,7 +62852,6 @@ }, "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -57868,7 +62861,6 @@ }, "html-webpack-plugin": { "version": "4.5.2", - "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", "requires": { "@types/html-minifier-terser": "^5.0.0", "@types/tapable": "^1.0.5", @@ -57883,51 +62875,42 @@ }, "icss-utils": { "version": "4.1.1", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", "requires": { "postcss": "^7.0.14" } }, "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3" }, "loader-runner": { - "version": "2.4.0", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + "version": "2.4.0" }, "locate-path": { "version": "6.0.0", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "requires": { "p-locate": "^5.0.0" } }, "normalize-path": { - "version": "3.0.0", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "version": "3.0.0" }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "requires": { "yocto-queue": "^0.1.0" } }, "p-locate": { "version": "5.0.0", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "requires": { "p-limit": "^3.0.2" } }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" }, "postcss": { "version": "7.0.39", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "requires": { "picocolors": "^0.2.1", "source-map": "^0.6.1" @@ -57935,14 +62918,12 @@ }, "postcss-modules-extract-imports": { "version": "2.0.0", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", "requires": { "postcss": "^7.0.5" } }, "postcss-modules-local-by-default": { "version": "3.0.3", - "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", "requires": { "icss-utils": "^4.1.1", "postcss": "^7.0.32", @@ -57952,7 +62933,6 @@ }, "postcss-modules-scope": { "version": "2.2.0", - "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", "requires": { "postcss": "^7.0.6", "postcss-selector-parser": "^6.0.0" @@ -57960,7 +62940,6 @@ }, "postcss-modules-values": { "version": "3.0.0", - "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", "requires": { "icss-utils": "^4.0.0", "postcss": "^7.0.6" @@ -57968,19 +62947,16 @@ }, "pretty-error": { "version": "2.1.2", - "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", "requires": { "lodash": "^4.17.20", "renderkid": "^2.0.4" } }, "resolve-from": { - "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + "version": "5.0.0" }, "schema-utils": { "version": "2.7.1", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", "requires": { "@types/json-schema": "^7.0.5", "ajv": "^6.12.4", @@ -57988,24 +62964,20 @@ } }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" }, "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" }, "style-loader": { "version": "1.3.0", - "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==", "requires": { "loader-utils": "^2.0.0", "schema-utils": "^2.7.0" }, "dependencies": { "loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -58016,7 +62988,6 @@ }, "webpack": { "version": "4.46.0", - "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-module-context": "1.9.0", @@ -58045,7 +63016,6 @@ "dependencies": { "schema-utils": { "version": "1.0.0", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", @@ -58054,7 +63024,6 @@ }, "terser-webpack-plugin": { "version": "1.4.5", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", "requires": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", @@ -58071,7 +63040,6 @@ }, "webpack-sources": { "version": "1.4.3", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" @@ -58081,7 +63049,6 @@ }, "@storybook/manager-webpack5": { "version": "6.4.22", - "integrity": "sha512-BMkOMselT4jOn7EQGt748FurM5ewtDfZtOQPCVK8MZX+HYE2AgjNOzm562TYODIxk12Fkhgj3EIz7GGMe1U3RA==", "dev": true, "requires": { "@babel/core": "^7.12.10", @@ -58121,12 +63088,10 @@ "dependencies": { "@types/node": { "version": "14.17.19", - "integrity": "sha512-jjYI6NkyfXykucU6ELEoT64QyKOdvaA6enOqKtP4xUsGY0X0ZUZz29fUmrTRo+7v7c6TgDu82q3GHHaCEkqZwA==", "dev": true }, "css-loader": { "version": "5.2.7", - "integrity": "sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==", "dev": true, "requires": { "icss-utils": "^5.1.0", @@ -58143,7 +63108,6 @@ }, "find-up": { "version": "5.0.0", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { "locate-path": "^6.0.0", @@ -58152,7 +63116,6 @@ }, "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -58163,12 +63126,10 @@ }, "has-flag": { "version": "4.0.0", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "jest-worker": { "version": "27.2.3", - "integrity": "sha512-ZwOvv4GCIPviL+Ie4pVguz4N5w/6IGbTaHBYOl3ZcsZZktaL7d8JOU0rmovoED7AJZKA8fvmLbBg8yg80u/tGA==", "dev": true, "requires": { "@types/node": "*", @@ -58177,16 +63138,11 @@ } }, "json5": { - "version": "2.2.0", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3", + "dev": true }, "loader-utils": { - "version": "2.0.0", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "version": "2.0.4", "dev": true, "requires": { "big.js": "^5.2.2", @@ -58196,7 +63152,6 @@ }, "locate-path": { "version": "6.0.0", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { "p-locate": "^5.0.0" @@ -58204,7 +63159,6 @@ }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -58212,7 +63166,6 @@ }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { "yocto-queue": "^0.1.0" @@ -58220,7 +63173,6 @@ }, "p-locate": { "version": "5.0.0", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { "p-limit": "^3.0.2" @@ -58228,17 +63180,14 @@ }, "path-exists": { "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "resolve-from": { "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, "semver": { "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -58246,7 +63195,6 @@ }, "serialize-javascript": { "version": "6.0.0", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -58254,12 +63202,10 @@ }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "style-loader": { "version": "2.0.0", - "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==", "dev": true, "requires": { "loader-utils": "^2.0.0", @@ -58268,32 +63214,23 @@ }, "supports-color": { "version": "8.1.1", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" } }, "terser": { - "version": "5.9.0", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "version": "5.14.2", "dev": true, "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } } }, "terser-webpack-plugin": { "version": "5.2.4", - "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", "dev": true, "requires": { "jest-worker": "^27.0.6", @@ -58306,7 +63243,6 @@ }, "webpack-dev-middleware": { "version": "4.3.0", - "integrity": "sha512-PjwyVY95/bhBh6VUqt6z4THplYcsvQ8YNNBTBM873xLVmw8FLeALn0qurHbs9EmcfhzQis/eoqypSnZeuUz26w==", "dev": true, "requires": { "colorette": "^1.2.2", @@ -58319,19 +63255,52 @@ }, "webpack-virtual-modules": { "version": "0.4.3", - "integrity": "sha512-5NUqC2JquIL2pBAAo/VfBP6KuGkHIZQXW/lNKupLPfhViwh8wNsu0BObtl09yuKZszeEUfbXz8xhrHvSG16Nqw==", "dev": true }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@storybook/mdx1-csf": { + "version": "0.0.1", + "dev": true, + "requires": { + "@babel/generator": "^7.12.11", + "@babel/parser": "^7.12.11", + "@babel/preset-env": "^7.12.11", + "@babel/types": "^7.12.11", + "@mdx-js/mdx": "^1.6.22", + "@types/lodash": "^4.14.167", + "js-string-escape": "^1.0.1", + "loader-utils": "^2.0.0", + "lodash": "^4.17.21", + "prettier": ">=2.2.1 <=2.3.0", + "ts-dedent": "^2.0.0" + }, + "dependencies": { + "json5": { + "version": "2.2.3", + "dev": true + }, + "loader-utils": { + "version": "2.0.4", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "prettier": { + "version": "2.3.0", "dev": true } } }, "@storybook/node-logger": { "version": "6.4.22", - "integrity": "sha512-sUXYFqPxiqM7gGH7gBXvO89YEO42nA4gBicJKZjj9e+W4QQLrftjF9l+mAw2K0mVE10Bn7r4pfs5oEZ0aruyyA==", "requires": { "@types/npmlog": "^4.1.2", "chalk": "^4.1.0", @@ -58341,12 +63310,10 @@ }, "dependencies": { "ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "version": "5.0.1" }, "are-we-there-yet": { "version": "2.0.0", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "requires": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -58354,7 +63321,6 @@ }, "gauge": { "version": "3.0.2", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "requires": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", @@ -58368,12 +63334,10 @@ } }, "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "version": "3.0.0" }, "npmlog": { "version": "5.0.1", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "requires": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", @@ -58383,7 +63347,6 @@ }, "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -58392,7 +63355,6 @@ }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -58401,7 +63363,6 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { "ansi-regex": "^5.0.1" } @@ -58410,7 +63371,6 @@ }, "@storybook/postinstall": { "version": "6.4.22", - "integrity": "sha512-LdIvA+l70Mp5FSkawOC16uKocefc+MZLYRHqjTjgr7anubdi6y7W4n9A7/Yw4IstZHoknfL88qDj/uK5N+Ahzw==", "dev": true, "requires": { "core-js": "^3.8.2" @@ -58418,7 +63378,6 @@ }, "@storybook/preview-web": { "version": "6.4.22", - "integrity": "sha512-sWS+sgvwSvcNY83hDtWUUL75O2l2LY/GTAS0Zp2dh3WkObhtuJ/UehftzPZlZmmv7PCwhb4Q3+tZDKzMlFxnKQ==", "requires": { "@storybook/addons": "6.4.22", "@storybook/channel-postmessage": "6.4.22", @@ -58439,8 +63398,7 @@ }, "dependencies": { "qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", "requires": { "side-channel": "^1.0.4" } @@ -58449,7 +63407,6 @@ }, "@storybook/react": { "version": "6.4.22", - "integrity": "sha512-5BFxtiguOcePS5Ty/UoH7C6odmvBYIZutfiy4R3Ua6FYmtxac5vP9r5KjCz1IzZKT8mCf4X+PuK1YvDrPPROgQ==", "requires": { "@babel/preset-flow": "^7.12.1", "@babel/preset-react": "^7.12.10", @@ -58479,7 +63436,6 @@ "dependencies": { "@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.4", - "integrity": "sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw==", "requires": { "ansi-html-community": "^0.0.8", "common-path-prefix": "^3.0.0", @@ -58493,8 +63449,7 @@ }, "dependencies": { "loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -58504,12 +63459,10 @@ } }, "acorn": { - "version": "6.4.2", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + "version": "6.4.2" }, "eslint-scope": { "version": "4.0.3", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -58517,55 +63470,43 @@ }, "find-up": { "version": "5.0.0", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "requires": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "json5": { - "version": "2.2.0", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3" }, "loader-runner": { - "version": "2.4.0", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + "version": "2.4.0" }, "locate-path": { "version": "6.0.0", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "requires": { "p-locate": "^5.0.0" } }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "requires": { "yocto-queue": "^0.1.0" } }, "p-locate": { "version": "5.0.0", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "requires": { "p-limit": "^3.0.2" } }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" }, "source-map": { - "version": "0.7.3", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + "version": "0.7.3" }, "terser-webpack-plugin": { "version": "1.4.5", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", "requires": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", @@ -58580,7 +63521,6 @@ "dependencies": { "schema-utils": { "version": "1.0.0", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", @@ -58588,14 +63528,12 @@ } }, "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } }, "webpack": { "version": "4.46.0", - "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-module-context": "1.9.0", @@ -58624,7 +63562,6 @@ "dependencies": { "schema-utils": { "version": "1.0.0", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", @@ -58635,15 +63572,13 @@ }, "webpack-sources": { "version": "1.4.3", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" }, "dependencies": { "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } } @@ -58651,7 +63586,6 @@ }, "@storybook/react-docgen-typescript-plugin": { "version": "1.0.2-canary.253f8c1.0", - "integrity": "sha512-mmoRG/rNzAiTbh+vGP8d57dfcR2aP+5/Ll03KKFyfy5FqWFm/Gh7u27ikx1I3LmVMI8n6jh5SdWMkMKon7/tDw==", "requires": { "debug": "^4.1.1", "endent": "^2.0.1", @@ -58664,28 +63598,24 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "requires": { "fill-range": "^7.0.1" } }, "debug": { "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "requires": { "ms": "2.1.2" } }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "requires": { "to-regex-range": "^5.0.1" } }, "find-cache-dir": { "version": "3.3.2", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "requires": { "commondir": "^1.0.1", "make-dir": "^3.0.2", @@ -58694,91 +63624,76 @@ }, "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "is-number": { - "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "version": "7.0.0" }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { "p-locate": "^4.1.0" } }, "make-dir": { "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "requires": { "semver": "^6.0.0" } }, "micromatch": { "version": "4.0.4", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "requires": { "braces": "^3.0.1", "picomatch": "^2.2.3" } }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "requires": { "p-limit": "^2.2.0" } }, "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "version": "2.2.0" }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" }, "pkg-dir": { "version": "4.2.0", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "requires": { "find-up": "^4.0.0" } }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "requires": { "is-number": "^7.0.0" } }, "tslib": { - "version": "2.3.1", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.3.1" } } }, "@storybook/router": { "version": "6.4.22", - "integrity": "sha512-zeuE8ZgFhNerQX8sICQYNYL65QEi3okyzw7ynF58Ud6nRw4fMxSOHcj2T+nZCIU5ufozRL4QWD/Rg9P2s/HtLw==", "requires": { "@storybook/client-logger": "6.4.22", "core-js": "^3.8.2", @@ -58795,28 +63710,24 @@ "dependencies": { "history": { "version": "5.0.0", - "integrity": "sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==", "requires": { "@babel/runtime": "^7.7.6" } }, "qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", "requires": { "side-channel": "^1.0.4" } }, "react-router": { "version": "6.3.0", - "integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==", "requires": { "history": "^5.2.0" }, "dependencies": { "history": { "version": "5.3.0", - "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", "requires": { "@babel/runtime": "^7.7.6" } @@ -58825,7 +63736,6 @@ }, "react-router-dom": { "version": "6.3.0", - "integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==", "requires": { "history": "^5.2.0", "react-router": "6.3.0" @@ -58833,7 +63743,6 @@ "dependencies": { "history": { "version": "5.3.0", - "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", "requires": { "@babel/runtime": "^7.7.6" } @@ -58844,7 +63753,6 @@ }, "@storybook/semver": { "version": "7.3.2", - "integrity": "sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==", "requires": { "core-js": "^3.6.5", "find-up": "^4.1.0" @@ -58852,7 +63760,6 @@ "dependencies": { "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -58860,38 +63767,32 @@ }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { "p-locate": "^4.1.0" } }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "requires": { "p-limit": "^2.2.0" } }, "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "version": "2.2.0" }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" } } }, "@storybook/source-loader": { "version": "6.4.22", - "integrity": "sha512-O4RxqPgRyOgAhssS6q1Rtc8LiOvPBpC1EqhCYWRV3K+D2EjFarfQMpjgPj18hC+QzpUSfzoBZYqsMECewEuLNw==", "dev": true, "requires": { "@storybook/addons": "6.4.22", @@ -58908,17 +63809,14 @@ "dependencies": { "estraverse": { "version": "5.3.0", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", "dev": true }, "loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", "dev": true, "requires": { "big.js": "^5.2.2", @@ -58928,14 +63826,12 @@ }, "prettier": { "version": "2.3.0", - "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", "dev": true } } }, "@storybook/store": { "version": "6.4.22", - "integrity": "sha512-lrmcZtYJLc2emO+1l6AG4Txm9445K6Pyv9cGAuhOJ9Kks0aYe0YtvMkZVVry0RNNAIv6Ypz72zyKc/QK+tZLAQ==", "requires": { "@storybook/addons": "6.4.22", "@storybook/client-logger": "6.4.22", @@ -58955,14 +63851,12 @@ }, "dependencies": { "slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + "version": "3.0.0" } } }, "@storybook/theming": { "version": "6.4.22", - "integrity": "sha512-NVMKH/jxSPtnMTO4VCN1k47uztq+u9fWv4GSnzq/eezxdGg9ceGL4/lCrNGoNajht9xbrsZ4QvsJ/V2sVGM8wA==", "requires": { "@emotion/core": "^10.1.1", "@emotion/is-prop-valid": "^0.8.6", @@ -58980,7 +63874,6 @@ "dependencies": { "@emotion/styled": { "version": "10.0.27", - "integrity": "sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==", "requires": { "@emotion/styled-base": "^10.0.27", "babel-plugin-emotion": "^10.0.27" @@ -58988,20 +63881,17 @@ }, "polished": { "version": "4.1.3", - "integrity": "sha512-ocPAcVBUOryJEKe0z2KLd1l9EBa1r5mSwlKpExmrLzsnIzJo4axsoU9O2BjOTkDGDT4mZ0WFE5XKTlR3nLnZOA==", "requires": { "@babel/runtime": "^7.14.0" } }, "resolve-from": { - "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + "version": "5.0.0" } } }, "@storybook/ui": { "version": "6.4.22", - "integrity": "sha512-UVjMoyVsqPr+mkS1L7m30O/xrdIEgZ5SCWsvqhmyMUok3F3tRB+6M+OA5Yy+cIVfvObpA7MhxirUT1elCGXsWQ==", "requires": { "@emotion/core": "^10.1.1", "@storybook/addons": "6.4.22", @@ -59034,26 +63924,22 @@ }, "dependencies": { "fuse.js": { - "version": "3.6.1", - "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==" + "version": "3.6.1" }, "polished": { "version": "4.2.2", - "integrity": "sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==", "requires": { "@babel/runtime": "^7.17.8" } }, "qs": { - "version": "6.10.3", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", "requires": { "side-channel": "^1.0.4" } }, "resolve-from": { - "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + "version": "5.0.0" } } }, @@ -59079,6 +63965,7 @@ "@types/d3-time-format": "^2.1.0", "@types/enzyme": "^3.10.5", "@types/fetch-mock": "^7.3.3", + "@types/json-bigint": "^1.0.1", "@types/lodash": "^4.14.149", "@types/math-expression-evaluator": "^1.2.1", "@types/node": "^18.0.0", @@ -59111,30 +63998,16 @@ }, "dependencies": { "@types/d3-time": { - "version": "3.0.0", - "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==" - }, - "@vx/responsive": { - "version": "0.0.199", - "integrity": "sha512-ONrmLUAG+8wzD3cn/EmsuZh6JHeyejqup3ZsV25t04VaVJAVQAJukAfNdH8YiwSJu0zSo+txkBTfrnOmFyQLOw==", - "requires": { - "@types/lodash": "^4.14.146", - "@types/react": "*", - "lodash": "^4.17.10", - "prop-types": "^15.6.1", - "resize-observer-polyfill": "1.5.1" - } + "version": "3.0.0" }, "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } }, "d3-scale": { "version": "3.3.0", - "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", "requires": { "d3-array": "^2.3.0", "d3-format": "1 - 2", @@ -59145,7 +64018,6 @@ "dependencies": { "d3-time": { "version": "2.1.1", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", "requires": { "d3-array": "2" } @@ -59154,7 +64026,6 @@ }, "fetch-mock": { "version": "6.5.2", - "integrity": "sha512-EIvbpCLBTYyDLu4HJiqD7wC8psDwTUaPaWXNKZbhNO/peUYKiNp5PkZGKRJtnTxaPQu71ivqafvjpM7aL+MofQ==", "dev": true, "requires": { "babel-polyfill": "^6.26.0", @@ -59164,7 +64035,6 @@ }, "jest-mock-console": { "version": "1.2.3", - "integrity": "sha512-q4jfuHW3V3tYzwtKTF6nxjRNriUC2/D2SVfxW88lNeG1qO1mVarBUqgOAvZjTEmxuTsjzGlHQsDIgvlOZaLccg==", "dev": true } } @@ -59184,7 +64054,7 @@ "@storybook/addons": "^6.3.12", "@storybook/react": "^6.3.12", "@types/react-loadable": "^5.5.3", - "antd": "^4.9.4", + "antd": "4.10.3", "babel-loader": "^8.1.0", "bootstrap": "^3.4.1", "chromatic": "^5.4.0", @@ -59203,9 +64073,12 @@ "typescript": "^4.5.4" }, "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "dev": true + }, "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -59213,19 +64086,76 @@ }, "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" } }, + "chromatic": { + "version": "5.10.2", + "dev": true, + "requires": { + "@actions/core": "^1.5.0", + "@actions/github": "^5.0.0", + "@babel/preset-typescript": "^7.15.0", + "@babel/runtime": "^7.15.3", + "@chromaui/localtunnel": "^2.0.3", + "async-retry": "^1.3.3", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "dotenv": "^8.2.0", + "env-ci": "^5.0.2", + "esm": "^3.2.25", + "execa": "^5.0.0", + "fake-tag": "^2.0.0", + "fs-extra": "^10.0.0", + "https-proxy-agent": "^5.0.0", + "jsonfile": "^6.0.1", + "junit-report-builder": "2.1.0", + "listr": "0.14.3", + "meow": "^8.0.0", + "no-proxy": "^1.0.3", + "node-ask": "^1.0.1", + "node-fetch": "2.6.0", + "node-loggly-bulk": "^2.2.4", + "p-limit": "3.1.0", + "picomatch": "2.2.2", + "pkg-up": "^3.1.0", + "pluralize": "^8.0.0", + "progress-stream": "^2.0.0", + "semver": "^7.3.5", + "slash": "^3.0.0", + "string-argv": "^0.3.1", + "strip-ansi": "6.0.0", + "tmp-promise": "3.0.2", + "tree-kill": "^1.2.2", + "ts-dedent": "^1.0.0", + "util-deprecate": "^1.0.2", + "uuid": "^8.3.2", + "yarn-or-npm": "^3.0.1" + }, + "dependencies": { + "fs-extra": { + "version": "10.1.0", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "picomatch": { + "version": "2.2.2", + "dev": true + } + } + }, "core-js": { - "version": "3.8.3", - "integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q==" + "version": "3.8.3" }, "cosmiconfig": { "version": "6.0.0", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", "dev": true, "requires": { "@types/parse-json": "^4.0.0", @@ -59235,22 +64165,57 @@ "yaml": "^1.7.2" } }, + "cross-spawn": { + "version": "7.0.3", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, "deepmerge": { "version": "4.2.2", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true }, + "execa": { + "version": "5.1.1", + "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" + } + }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" } }, + "find-up": { + "version": "3.0.0", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, "fork-ts-checker-webpack-plugin": { "version": "5.2.1", - "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", @@ -59268,7 +64233,6 @@ }, "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -59277,14 +64241,32 @@ "universalify": "^2.0.0" } }, + "get-stream": { + "version": "6.0.1", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "dev": true + }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-stream": { + "version": "2.0.1", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -59292,16 +64274,56 @@ }, "micromatch": { "version": "4.0.4", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.2.3" } }, + "ms": { + "version": "2.1.2", + "dev": true + }, + "node-fetch": { + "version": "2.6.0", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "3.0.0", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + } + } + }, + "p-try": { + "version": "2.2.0", + "dev": true + }, "parse-json": { "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -59310,14 +64332,23 @@ "lines-and-columns": "^1.1.6" } }, + "path-key": { + "version": "3.1.1", + "dev": true + }, "path-type": { "version": "4.0.0", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pkg-up": { + "version": "3.1.0", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, "schema-utils": { "version": "2.7.0", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", "dev": true, "requires": { "@types/json-schema": "^7.0.4", @@ -59327,15 +64358,35 @@ }, "semver": { "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, + "shebang-command": { + "version": "2.0.0", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "dev": true + }, + "slash": { + "version": "3.0.0", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, "supports-color": { "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -59343,15 +64394,17 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" } }, + "ts-dedent": { + "version": "1.2.0", + "dev": true + }, "ts-loader": { "version": "7.0.5", - "integrity": "sha512-zXypEIT6k3oTc+OZNx/cqElrsbBtYqDknf48OZos0NQ3RTt045fBIU8RRSu+suObBzYB355aIPGOe/3kj9h7Ig==", "dev": true, "requires": { "chalk": "^2.3.0", @@ -59363,7 +64416,6 @@ "dependencies": { "chalk": { "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -59373,14 +64425,23 @@ }, "semver": { "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, + "uuid": { + "version": "8.3.2", + "dev": true + }, + "which": { + "version": "2.0.2", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } @@ -59392,7 +64453,7 @@ "fs-extra": "^10.0.0", "lodash": "^4.17.11", "yeoman-assert": "^3.1.0", - "yeoman-generator": "^4.0.0", + "yeoman-generator": "^5.7.0", "yeoman-test": "^6.2.0", "yosay": "^2.0.2" } @@ -59408,7 +64469,6 @@ "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } @@ -59433,7 +64493,6 @@ "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } @@ -59469,7 +64528,6 @@ "dependencies": { "@vx/group": { "version": "0.0.198", - "integrity": "sha512-0PivE+fWZlPkSzFO/is5m4VSSv3pg+sS1yxYAZHbNffUvn472WDWptriHvoUIPQe0lOXhTSrc73UQzew9GtW/g==", "requires": { "@types/classnames": "^2.2.9", "@types/react": "*", @@ -59479,7 +64537,6 @@ }, "@vx/legend": { "version": "0.0.198", - "integrity": "sha512-3S2/yP6IvkkhUlTj6In5M1OrzY1OaT1D06hRxuiOLAbaXTerhbUGwIjGSNoovQM6JebFlbWnnA5xH1SKgw5GGA==", "requires": { "@types/classnames": "^2.2.9", "@types/d3-scale": "^2.1.1", @@ -59489,20 +64546,8 @@ "prop-types": "^15.5.10" } }, - "@vx/responsive": { - "version": "0.0.199", - "integrity": "sha512-ONrmLUAG+8wzD3cn/EmsuZh6JHeyejqup3ZsV25t04VaVJAVQAJukAfNdH8YiwSJu0zSo+txkBTfrnOmFyQLOw==", - "requires": { - "@types/lodash": "^4.14.146", - "@types/react": "*", - "lodash": "^4.17.10", - "prop-types": "^15.6.1", - "resize-observer-polyfill": "1.5.1" - } - }, "@vx/scale": { "version": "0.0.197", - "integrity": "sha512-FF0POm9rh66I3Om5DsuxynwWU+Q645aTF47vgP2dVDeOOq3Oet7CZzmXLDh3W6nVcxvzq1UdPwu94dto2PUfhg==", "requires": { "@types/d3-scale": "^2.1.1", "d3-scale": "^2.2.2" @@ -59520,14 +64565,12 @@ "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } }, "d3-scale": { "version": "3.3.0", - "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", "requires": { "d3-array": "^2.3.0", "d3-format": "1 - 2", @@ -59538,7 +64581,6 @@ }, "d3-time": { "version": "2.1.1", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", "requires": { "d3-array": "2" } @@ -59549,7 +64591,7 @@ "version": "file:plugins/legacy-plugin-chart-map-box", "requires": { "prop-types": "^15.6.2", - "react-map-gl": "^4.0.10", + "react-map-gl": "^6.1.19", "supercluster": "^4.1.1", "viewport-mercator-project": "^6.1.1" } @@ -59636,7 +64678,6 @@ "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } @@ -59660,14 +64701,13 @@ "mousetrap": "^1.6.1", "prop-types": "^15.6.0", "react-bootstrap-slider": "2.1.5", - "underscore": "^1.8.3", + "underscore": "^1.12.1", "urijs": "^1.19.8", "xss": "^1.0.10" }, "dependencies": { "d3-scale": { "version": "3.3.0", - "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", "requires": { "d3-array": "^2.3.0", "d3-format": "1 - 2", @@ -59678,7 +64718,6 @@ "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } @@ -59687,14 +64726,12 @@ }, "d3-time": { "version": "2.1.1", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", "requires": { "d3-array": "2" }, "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } @@ -59722,7 +64759,7 @@ "version": "file:plugins/plugin-chart-echarts", "requires": { "d3-array": "^1.2.0", - "echarts": "^5.3.2", + "echarts": "^5.4.1", "lodash": "^4.17.15", "moment": "^2.26.0" } @@ -59733,7 +64770,13 @@ "@types/jest": "^26.0.0", "@types/lodash": "^4.14.149", "handlebars": "^4.7.7", - "jest": "^26.0.1" + "jest": "^26.0.1", + "just-handlebars-helpers": "^1.0.19" + }, + "dependencies": { + "just-handlebars-helpers": { + "version": "1.0.19" + } } }, "@superset-ui/plugin-chart-pivot-table": { @@ -59748,9 +64791,11 @@ "version": "file:plugins/plugin-chart-table", "requires": { "@react-icons/all-files": "^4.1.0", + "@testing-library/react": "^11.2.0", "@types/d3-array": "^2.9.0", "@types/enzyme": "^3.10.5", "@types/react-table": "^7.0.29", + "classnames": "^2.3.2", "d3-array": "^2.4.0", "match-sorter": "^6.3.0", "memoize-one": "^5.1.1", @@ -59761,7 +64806,6 @@ "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } @@ -59780,14 +64824,12 @@ "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } }, "d3-scale": { "version": "3.3.0", - "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", "requires": { "d3-array": "^2.3.0", "d3-format": "1 - 2", @@ -59798,7 +64840,6 @@ }, "d3-time": { "version": "2.1.1", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", "requires": { "d3-array": "2" } @@ -59821,7 +64862,6 @@ "dependencies": { "@vx/axis": { "version": "0.0.198", - "integrity": "sha512-XqHzGOBgkJD8gR1g9F7uOhT4Sjlwpl/H3xLehtDooRmKf3J0hy8C7L5rCgh7n8ARi+vYg+3A1zUo0JBIO5k4PQ==", "requires": { "@types/classnames": "^2.2.9", "@types/react": "*", @@ -59835,7 +64875,6 @@ }, "@vx/curve": { "version": "0.0.198", - "integrity": "sha512-ZINtD0t5eLu3bEeaOWZxGXrHK5WCbGoxDdou7yPWD6xg8kpTD4/Vq0adRFNCxS1TZUlUjCJ2KqY2PmewO+Hdcw==", "requires": { "@types/d3-shape": "^1.3.1", "d3-shape": "^1.0.6" @@ -59843,7 +64882,6 @@ }, "@vx/group": { "version": "0.0.198", - "integrity": "sha512-0PivE+fWZlPkSzFO/is5m4VSSv3pg+sS1yxYAZHbNffUvn472WDWptriHvoUIPQe0lOXhTSrc73UQzew9GtW/g==", "requires": { "@types/classnames": "^2.2.9", "@types/react": "*", @@ -59853,7 +64891,6 @@ }, "@vx/legend": { "version": "0.0.198", - "integrity": "sha512-3S2/yP6IvkkhUlTj6In5M1OrzY1OaT1D06hRxuiOLAbaXTerhbUGwIjGSNoovQM6JebFlbWnnA5xH1SKgw5GGA==", "requires": { "@types/classnames": "^2.2.9", "@types/d3-scale": "^2.1.1", @@ -59864,12 +64901,10 @@ } }, "@vx/point": { - "version": "0.0.198", - "integrity": "sha512-oFlw8uBLf4JDX7OJc+7eQXcnlLszdQgEs531u0t6HNpARQY/jTeeMLVUlp8sNF0XBOC+iVHU8Qe8TJdz/ONBAA==" + "version": "0.0.198" }, "@vx/scale": { "version": "0.0.197", - "integrity": "sha512-FF0POm9rh66I3Om5DsuxynwWU+Q645aTF47vgP2dVDeOOq3Oet7CZzmXLDh3W6nVcxvzq1UdPwu94dto2PUfhg==", "requires": { "@types/d3-scale": "^2.1.1", "d3-scale": "^2.2.2" @@ -59877,7 +64912,6 @@ }, "@vx/shape": { "version": "0.0.198", - "integrity": "sha512-3Ky2PlSXYmh/Wt+tT4OBmsLpTe8Vu5pZ1EwbMQ0H/NNl6d4BsNqBUzr++0WC/kLsuNs5NENDvG77N9u2ztMrYA==", "requires": { "@types/classnames": "^2.2.9", "@types/d3-path": "^1.0.8", @@ -59893,7 +64927,6 @@ }, "@vx/text": { "version": "0.0.198", - "integrity": "sha512-MZhLeIhjbPlAeq+heUFXzrAztkjpfhAjeg+RXDg1dTJTtkbBD0w1bwadSPHuC7Rzj6yNQChzVDYl51dO/k4ExQ==", "requires": { "@types/classnames": "^2.2.9", "@types/lodash": "^4.14.146", @@ -59911,47 +64944,38 @@ }, "@svgr/babel-plugin-add-jsx-attribute": { "version": "5.4.0", - "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", "dev": true }, "@svgr/babel-plugin-remove-jsx-attribute": { "version": "5.4.0", - "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", "dev": true }, "@svgr/babel-plugin-remove-jsx-empty-expression": { "version": "5.0.1", - "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", "dev": true }, "@svgr/babel-plugin-replace-jsx-attribute-value": { "version": "5.0.1", - "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", "dev": true }, "@svgr/babel-plugin-svg-dynamic-title": { "version": "5.4.0", - "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", "dev": true }, "@svgr/babel-plugin-svg-em-dimensions": { "version": "5.4.0", - "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", "dev": true }, "@svgr/babel-plugin-transform-react-native-svg": { "version": "5.4.0", - "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", "dev": true }, "@svgr/babel-plugin-transform-svg-component": { "version": "5.5.0", - "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", "dev": true }, "@svgr/babel-preset": { "version": "5.5.0", - "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", "dev": true, "requires": { "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", @@ -59966,7 +64990,6 @@ }, "@svgr/core": { "version": "5.5.0", - "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", "dev": true, "requires": { "@svgr/plugin-jsx": "^5.5.0", @@ -59976,14 +64999,12 @@ "dependencies": { "camelcase": { "version": "6.2.0", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true } } }, "@svgr/hast-util-to-babel-ast": { "version": "5.5.0", - "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", "dev": true, "requires": { "@babel/types": "^7.12.6" @@ -59991,7 +65012,6 @@ }, "@svgr/plugin-jsx": { "version": "5.5.0", - "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", "dev": true, "requires": { "@babel/core": "^7.12.3", @@ -60002,7 +65022,6 @@ }, "@svgr/plugin-svgo": { "version": "5.5.0", - "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", "dev": true, "requires": { "cosmiconfig": "^7.0.0", @@ -60012,14 +65031,12 @@ "dependencies": { "deepmerge": { "version": "4.2.2", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true } } }, "@svgr/webpack": { "version": "5.5.0", - "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", "dev": true, "requires": { "@babel/core": "^7.12.3", @@ -60033,16 +65050,11 @@ }, "dependencies": { "json5": { - "version": "2.1.3", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3", + "dev": true }, "loader-utils": { - "version": "2.0.0", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "version": "2.0.4", "dev": true, "requires": { "big.js": "^5.2.2", @@ -60054,7 +65066,6 @@ }, "@testing-library/dom": { "version": "7.29.4", - "integrity": "sha512-CtrJRiSYEfbtNGtEsd78mk1n1v2TUbeABlNIcOCJdDfkN5/JTOwQEbbQpoSRxGqzcWPgStMvJ4mNolSuBRv1NA==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", @@ -60069,7 +65080,6 @@ }, "@testing-library/jest-dom": { "version": "5.11.6", - "integrity": "sha512-cVZyUNRWwUKI0++yepYpYX7uhrP398I+tGz4zOlLVlUYnZS+Svuxv4fwLeCIy7TnBYKXUaOlQr3vopxL8ZfEnA==", "dev": true, "requires": { "@babel/runtime": "^7.9.2", @@ -60084,7 +65094,6 @@ "dependencies": { "chalk": { "version": "3.0.0", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -60095,7 +65104,6 @@ }, "@testing-library/react": { "version": "11.2.0", - "integrity": "sha512-90xKYJzskZ7q/AoSuWraQL4EGZlr75uZvDt3nrO4M+rugN02zjO45tmOBq/JBOgDiMIL1tkhHioKXjJsVaSINA==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", @@ -60104,7 +65112,6 @@ }, "@testing-library/react-hooks": { "version": "5.0.3", - "integrity": "sha512-UrnnRc5II7LMH14xsYNm/WRch/67cBafmrSQcyFh0v+UUmSf1uzfB7zn5jQXSettGwOSxJwdQUN7PgkT0w22Lg==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", @@ -60117,7 +65124,6 @@ "dependencies": { "react-error-boundary": { "version": "3.1.0", - "integrity": "sha512-lmPrdi5SLRJR+AeJkqdkGlW/CRkAUvZnETahK58J4xb5wpbfDngasEGu+w0T1iXEhVrYBJZeW+c4V1hILCnMWQ==", "dev": true, "requires": { "@babel/runtime": "^7.12.5" @@ -60127,7 +65133,6 @@ }, "@testing-library/user-event": { "version": "12.7.0", - "integrity": "sha512-KzRM1KNDoW8pJ2HTenrUhTjV6wJMHvWAagDs8DDrYSWz6y4PN+K2jSvlm2bMHWNRk5LTJPo9jqIjNjJ3FlqXNw==", "dev": true, "requires": { "@babel/runtime": "^7.12.5" @@ -60135,22 +65140,18 @@ }, "@tootallnate/once": { "version": "1.1.2", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, "@trysound/sax": { "version": "0.1.1", - "integrity": "sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==", "dev": true }, "@types/aria-query": { "version": "4.2.0", - "integrity": "sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A==", "dev": true }, "@types/babel__core": { "version": "7.1.9", - "integrity": "sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -60162,7 +65163,6 @@ }, "@types/babel__generator": { "version": "7.6.1", - "integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==", "dev": true, "requires": { "@babel/types": "^7.0.0" @@ -60170,7 +65170,6 @@ }, "@types/babel__template": { "version": "7.0.2", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -60179,104 +65178,118 @@ }, "@types/babel__traverse": { "version": "7.0.12", - "integrity": "sha512-t4CoEokHTfcyfb4hUaF9oOHu9RmmNWnm1CP0YmMqOOfClKascOmvlEM736vlqeScuGvBDsHkf8R2INd4DWreQA==", "dev": true, "requires": { "@babel/types": "^7.3.0" } }, + "@types/base16": { + "version": "1.0.2" + }, + "@types/body-parser": { + "version": "1.19.2", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/cheerio": { "version": "0.22.21", - "integrity": "sha512-aGI3DfswwqgKPiEOTaiHV2ZPC9KEhprpgEbJnv0fZl3SGX0cGgEva1126dGrMC6AJM6v/aihlUgJn9M5DbDZ/Q==", "requires": { "@types/node": "*" } }, "@types/classnames": { - "version": "2.2.10", - "integrity": "sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ==" + "version": "2.2.10" }, "@types/color-convert": { "version": "2.0.0", - "integrity": "sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==", "requires": { "@types/color-name": "*" } }, "@types/color-name": { - "version": "1.1.1", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + "version": "1.1.1" + }, + "@types/connect": { + "version": "3.4.35", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.5", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } }, "@types/d3": { - "version": "3.5.38", - "integrity": "sha512-O/gRkjWULp3xVX8K85V0H3tsSGole0WYt77KVpGZO2xTGLuVFuvE6JIsIli3fvFHCYBhGFn/8OHEEyMYF+QehA==" + "version": "3.5.38" }, "@types/d3-array": { - "version": "2.9.0", - "integrity": "sha512-sdBMGfNvLUkBypPMEhOcKcblTQfgHbqbYrUqRE31jOwdDHBJBxz4co2MDAq93S4Cp++phk4UiwoEg/1hK3xXAQ==" + "version": "2.9.0" }, "@types/d3-cloud": { "version": "1.2.5", - "integrity": "sha512-vEIER9DsEBUOdpRiwCh3n1qE+cV6h4e1LhxhY2sLt+m8LPNAIkOOhTlqk0JDiBwD+ZPM8ynFAOU3AuPuVYBFBA==", "requires": { "@types/d3": "^3" } }, "@types/d3-color": { - "version": "1.4.2", - "integrity": "sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA==" + "version": "1.4.2" }, "@types/d3-format": { - "version": "1.4.2", - "integrity": "sha512-WeGCHAs7PHdZYq6lwl/+jsl+Nfc1J2W1kNcMeIMYzQsT6mtBDBgtJ/rcdjZ0k0rVIvqEZqhhuD5TK/v3P2gFHQ==" + "version": "1.4.2" }, "@types/d3-interpolate": { "version": "1.4.2", - "integrity": "sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg==", "requires": { "@types/d3-color": "^1" } }, "@types/d3-path": { - "version": "1.0.9", - "integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==" + "version": "1.0.9" }, "@types/d3-scale": { "version": "2.2.6", - "integrity": "sha512-CHu34T5bGrJOeuhGxyiz9Xvaa9PlsIaQoOqjDg7zqeGj2x0rwPhGquiy03unigvcMxmvY0hEaAouT0LOFTLpIw==", "requires": { "@types/d3-time": "^1" } }, "@types/d3-scale-chromatic": { - "version": "1.5.1", - "integrity": "sha512-7FtJYrmXTEWLykShjYhoGuDNR/Bda0+tstZMkFj4RRxUEryv16AGh3be21tqg84B6KfEwiZyEpBcTyPyU+GWjg==" + "version": "1.5.1" }, "@types/d3-shape": { "version": "1.3.8", - "integrity": "sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==", "requires": { "@types/d3-path": "^1" } }, "@types/d3-time": { - "version": "1.1.1", - "integrity": "sha512-ULX7LoqXTCYtM+tLYOaeAJK7IwCT+4Gxlm2MaH0ErKLi07R5lh8NHCAyWcDkCCmx1AfRcBEV6H9QE9R25uP7jw==" + "version": "1.1.1" }, "@types/d3-time-format": { - "version": "2.3.1", - "integrity": "sha512-fck0Z9RGfIQn3GJIEKVrp15h9m6Vlg0d5XXeiE/6+CQiBmMDZxfR21XtjEPuDeg7gC3bBM0SdieA5XF3GW1wKA==" + "version": "2.3.1" }, "@types/debug": { "version": "4.1.7", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", "requires": { "@types/ms": "*" } }, "@types/enzyme": { "version": "3.10.10", - "integrity": "sha512-/D4wFhiEjUDfPu+j5FVK0g/jf7rqeEIpNfAI+kyxzLpw5CKO0drnW3W5NC38alIjsWgnyQ8pbuPF5+UD+vhVyg==", "requires": { "@types/cheerio": "*", "@types/react": "*" @@ -60284,7 +65297,6 @@ }, "@types/enzyme-adapter-react-16": { "version": "1.0.6", - "integrity": "sha512-VonDkZ15jzqDWL8mPFIQnnLtjwebuL9YnDkqeCDYnB4IVgwUm0mwKkqhrxLL6mb05xm7qqa3IE95m8CZE9imCg==", "dev": true, "requires": { "@types/enzyme": "*" @@ -60292,7 +65304,6 @@ }, "@types/eslint": { "version": "7.28.0", - "integrity": "sha512-07XlgzX0YJUn4iG1ocY4IX9DzKSmMGUs6ESKlxWhZRaa0fatIWaHWUVapcuGa8r5HFnTqzj+4OCjd5f7EZ/i/A==", "dev": true, "requires": { "@types/estree": "*", @@ -60301,7 +65312,6 @@ }, "@types/eslint-scope": { "version": "3.7.1", - "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", "dev": true, "requires": { "@types/eslint": "*", @@ -60310,24 +65320,38 @@ }, "@types/estree": { "version": "0.0.50", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", "dev": true }, + "@types/express": { + "version": "4.17.13", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.30", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, "@types/fetch-mock": { - "version": "7.3.5", - "integrity": "sha512-sLecm9ohBdGIpYUP9rWk5/XIKY2xHMYTBJIcJuBBM8IJWnYoQ1DAj8F4OVjnfD0API1drlkWEV0LPNk+ACuhsg==" + "version": "7.3.5" }, "@types/flatbuffers": { - "version": "1.10.0", - "integrity": "sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==" + "version": "1.10.0" }, "@types/geojson": { - "version": "7946.0.8", - "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==" + "version": "7946.0.8" }, "@types/glob": { "version": "7.1.4", - "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", "requires": { "@types/minimatch": "*", "@types/node": "*" @@ -60335,7 +65359,6 @@ }, "@types/graceful-fs": { "version": "4.1.3", - "integrity": "sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ==", "dev": true, "requires": { "@types/node": "*" @@ -60343,47 +65366,39 @@ }, "@types/hast": { "version": "2.3.1", - "integrity": "sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q==", "requires": { "@types/unist": "*" } }, "@types/history": { - "version": "4.7.6", - "integrity": "sha512-GRTZLeLJ8ia00ZH8mxMO8t0aC9M1N9bN461Z2eaRurJo6Fpa+utgCwLzI4jQHcrdzuzp5WPN9jRwpsCQ1VhJ5w==", + "version": "4.7.11", "dev": true }, "@types/hoist-non-react-statics": { "version": "3.3.1", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", "requires": { "@types/react": "*", "hoist-non-react-statics": "^3.3.0" } }, "@types/html-minifier-terser": { - "version": "5.1.1", - "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==" + "version": "5.1.1" }, "@types/http-proxy": { - "version": "1.17.7", - "integrity": "sha512-9hdj6iXH64tHSLTY+Vt2eYOGzSogC+JQ2H7bdPWkuh7KXP5qLllWx++t+K9Wk556c3dkDdPws/SpMRi0sdCT1w==", + "version": "1.17.9", "dev": true, "requires": { "@types/node": "*" } }, "@types/is-function": { - "version": "1.0.1", - "integrity": "sha512-A79HEEiwXTFtfY+Bcbo58M2GRYzCr9itHWzbzHVFNEYCcoU/MMGwYYf721gBrnhpj1s6RGVVha/IgNFnR0Iw/Q==" + "version": "1.0.1" }, "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==" + "version": "2.0.3" }, "@types/istanbul-lib-report": { "version": "3.0.0", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "*" @@ -60391,7 +65406,6 @@ }, "@types/istanbul-reports": { "version": "1.1.2", - "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "*", @@ -60400,7 +65414,6 @@ }, "@types/jest": { "version": "26.0.23", - "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==", "dev": true, "requires": { "jest-diff": "^26.0.0", @@ -60409,7 +65422,6 @@ }, "@types/jquery": { "version": "3.5.9", - "integrity": "sha512-B8pDk+sH/tSv/HKdx6EQER6BfUOb2GtKs0LOmozziS4h7cbe8u/eYySfUAeTwD+J09SqV3man7AMWIA5mgzCBA==", "dev": true, "requires": { "@types/sizzle": "*" @@ -60417,65 +65429,61 @@ }, "@types/js-levenshtein": { "version": "1.1.0", - "integrity": "sha512-14t0v1ICYRtRVcHASzes0v/O+TIeASb8aD55cWF1PidtInhFWSXcmhzhHqGjUWf9SUq1w70cvd1cWKUULubAfQ==", "dev": true }, "@types/json-bigint": { - "version": "1.0.0", - "integrity": "sha512-WW+0cfH3ovFN6ROV+p/Xfw36dT6s16hbXBYIG49PYw6+j6e+AkpqYccctgxwyicBmC8CZDBnPhOH94shFhXgHQ==", - "dev": true + "version": "1.0.1" }, "@types/json-schema": { - "version": "7.0.9", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" + "version": "7.0.9" }, "@types/json5": { "version": "0.0.29", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "@types/lodash": { - "version": "4.14.149", - "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==" + "version": "4.14.182" }, "@types/lodash.get": { "version": "4.4.6", - "integrity": "sha512-E6zzjR3GtNig8UJG/yodBeJeIOtgPkMgsLjDU3CbgCAPC++vJ0eCMnJhVpRZb/ENqEFlov1+3K9TKtY4UdWKtQ==", "requires": { "@types/lodash": "*" } }, + "@types/mapbox-gl": { + "version": "2.7.6", + "requires": { + "@types/geojson": "*" + } + }, "@types/math-expression-evaluator": { - "version": "1.2.1", - "integrity": "sha512-H6IG9R0jU16nR3N24UpL7X40aDcUl5eTncBSd/itwz6rWI4nNzMcNYreHj0MnKlHSga1Iq1AqjSuY67EhiN+Zw==" + "version": "1.2.1" }, "@types/mdast": { "version": "3.0.10", - "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", "requires": { "@types/unist": "*" } }, + "@types/mime": { + "version": "3.0.1", + "dev": true + }, "@types/minimatch": { - "version": "3.0.5", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" + "version": "3.0.5" }, "@types/minimist": { "version": "1.2.2", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, "@types/ms": { - "version": "0.7.31", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + "version": "0.7.31" }, "@types/node": { - "version": "18.0.0", - "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==" + "version": "18.0.0" }, "@types/node-fetch": { - "version": "2.6.1", - "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", + "version": "2.6.2", "requires": { "@types/node": "*", "form-data": "^3.0.0" @@ -60483,7 +65491,6 @@ "dependencies": { "form-data": { "version": "3.0.1", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -60493,50 +65500,43 @@ } }, "@types/normalize-package-data": { - "version": "2.4.0", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==" + "version": "2.4.0" }, "@types/npmlog": { - "version": "4.1.4", - "integrity": "sha512-WKG4gTr8przEZBiJ5r3s8ZIAoMXNbOgQ+j/d5O4X3x6kZJRLNvyUJuUK/KoG3+8BaOHPhp2m7WC6JKKeovDSzQ==" + "version": "4.1.4" }, "@types/overlayscrollbars": { - "version": "1.12.1", - "integrity": "sha512-V25YHbSoKQN35UasHf0EKD9U2vcmexRSp78qa8UglxFH8H3D+adEa9zGZwrqpH4TdvqeMrgMqVqsLB4woAryrQ==" + "version": "1.12.1" }, "@types/parse-json": { - "version": "4.0.0", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + "version": "4.0.0" }, "@types/parse5": { - "version": "5.0.3", - "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" + "version": "5.0.3" }, "@types/prettier": { "version": "2.1.5", - "integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==", "dev": true }, "@types/pretty-hrtime": { - "version": "1.0.1", - "integrity": "sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==" + "version": "1.0.1" }, "@types/prop-types": { - "version": "15.7.4", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + "version": "15.7.5" }, "@types/q": { "version": "1.5.2", - "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", "dev": true }, "@types/qs": { - "version": "6.9.7", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + "version": "6.9.7" + }, + "@types/range-parser": { + "version": "1.2.4", + "dev": true }, "@types/react": { "version": "16.9.43", - "integrity": "sha512-PxshAFcnJqIWYpJbLPriClH53Z2WlJcVZE+NP2etUtWQs2s7yIMj3/LDKZT/5CHJ/F62iyjVCDu2H3jHEXIxSg==", "requires": { "@types/prop-types": "*", "csstype": "^2.2.0" @@ -60544,7 +65544,6 @@ }, "@types/react-dom": { "version": "16.9.8", - "integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==", "dev": true, "requires": { "@types/react": "*" @@ -60552,7 +65551,6 @@ }, "@types/react-gravatar": { "version": "2.6.8", - "integrity": "sha512-VMk0bF0w72l+opBm+EqLs0JqUG+hPowMBWCVGrbTwUWm/oDncvwNrf7P/ImwYwkTCKiLnU8Rc+/lyhehaIE/Rw==", "dev": true, "requires": { "@types/react": "*" @@ -60560,7 +65558,6 @@ }, "@types/react-json-tree": { "version": "0.6.11", - "integrity": "sha512-HP0Sf0ZHjCi1FHLJxh/pLaxaevEW6ILlV2C5Dn3EZFTkLjWkv+EVf/l/zvtmoU9ZwuO/3TKVeWK/700UDxunTw==", "dev": true, "requires": { "@types/react": "*" @@ -60568,7 +65565,6 @@ }, "@types/react-jsonschema-form": { "version": "1.7.4", - "integrity": "sha512-TSsntIuB8bfheC/ZpjUmgB6+m5cLR4Gbh8rnqpSYB6T4e2TwzNICuKC5AykZI0XTxqLJmShyVsJxuo4aih64Gw==", "dev": true, "requires": { "@types/json-schema": "*", @@ -60577,16 +65573,13 @@ }, "@types/react-loadable": { "version": "5.5.6", - "integrity": "sha512-2M7xH/wawZxNybbs/a76JkpUsMk4z6AxBh92cUtIBy2vK7EYYuitQbC4laY0hGz0e05R+mQ44YeHMtH2U+gMsw==", "requires": { "@types/react": "*", "@types/webpack": "^4" } }, "@types/react-redux": { - "version": "7.1.10", - "integrity": "sha512-lmt2BPf0fFuYrXg1JM4udUd4sCmqnTlNUIxC7B6RIBTzmMuv/MxOfumGNUx1UyzVZieEZ2ttCQvFfh/3eUHvrQ==", - "dev": true, + "version": "7.1.25", "requires": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -60596,7 +65589,6 @@ }, "@types/react-router": { "version": "5.1.8", - "integrity": "sha512-HzOyJb+wFmyEhyfp4D4NYrumi+LQgQL/68HvJO+q6XtuHSDvw6Aqov7sCAhjbNq3bUPgPqbdvjXC5HeB2oEAPg==", "dev": true, "requires": { "@types/history": "*", @@ -60604,18 +65596,16 @@ } }, "@types/react-router-dom": { - "version": "5.1.5", - "integrity": "sha512-ArBM4B1g3BWLGbaGvwBGO75GNFbLDUthrDojV2vHLih/Tq8M+tgvY1DSwkuNrPSwdp/GUL93WSEpTZs8nVyJLw==", + "version": "5.3.3", "dev": true, "requires": { - "@types/history": "*", + "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router": "*" } }, "@types/react-select": { "version": "3.0.19", - "integrity": "sha512-d+6qtfFXZeIOAABlVL1e50RZn8ctOABE4tFDxM6KW4lKuXgTTgLVrSik5AX9XjBjV7N80FtS6GTN/WeoXL9Jww==", "dev": true, "requires": { "@types/react": "*", @@ -60623,31 +65613,20 @@ "@types/react-transition-group": "*" } }, - "@types/react-sticky": { - "version": "6.0.3", - "integrity": "sha512-tW0Y1hTr2Tao4yX58iKl0i7BaqrdObGXAzsyzd8VGVrWVEgbQuV6P6QKVd/kFC7FroXyelftiVNJ09pnfkcjww==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, "@types/react-syntax-highlighter": { "version": "11.0.5", - "integrity": "sha512-VIOi9i2Oj5XsmWWoB72p3KlZoEbdRAcechJa8Ztebw7bDl2YmR+odxIqhtJGp1q2EozHs02US+gzxJ9nuf56qg==", "requires": { "@types/react": "*" } }, "@types/react-table": { "version": "7.0.29", - "integrity": "sha512-RCGVKGlTDv3jbj37WJ5HhN3sPb0W/2rqlvyGUtvawnnyrxgI2BGgASvU93rq2jwanVp5J9l1NYAeiGlNhdaBGw==", "requires": { "@types/react": "*" } }, "@types/react-test-renderer": { "version": "17.0.1", - "integrity": "sha512-3Fi2O6Zzq/f3QR9dRnlnHso9bMl7weKCviFmfF6B4LS1Uat6Hkm15k0ZAQuDz+UBq6B3+g+NM6IT2nr5QgPzCw==", "dev": true, "requires": { "@types/react": "*" @@ -60655,7 +65634,6 @@ }, "@types/react-transition-group": { "version": "4.4.0", - "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==", "dev": true, "requires": { "@types/react": "*" @@ -60663,7 +65641,6 @@ }, "@types/react-ultimate-pagination": { "version": "1.2.0", - "integrity": "sha512-xFyJn6Jl26Q0bi+QTnLo4W5tCDKOGNU5Gn9iCg+Y6J+VqtuKuJ1wcP1Ax+nXAu5HF9qTgApI/hRn7ceCDC6TAA==", "dev": true, "requires": { "@types/react": "*" @@ -60671,7 +65648,6 @@ }, "@types/react-virtualized": { "version": "9.21.10", - "integrity": "sha512-f5Ti3A7gGdLkPPFNHTrvKblpsPNBiQoSorOEOD+JPx72g/Ng2lOt4MYfhvQFQNgyIrAro+Z643jbcKafsMW2ag==", "dev": true, "requires": { "@types/prop-types": "*", @@ -60679,8 +65655,7 @@ } }, "@types/react-window": { - "version": "1.8.2", - "integrity": "sha512-gP1xam68Wc4ZTAee++zx6pTdDAH08rAkQrWm4B4F/y6hhmlT9Mgx2q8lTCXnrPHXsr15XjRN9+K2DLKcz44qEQ==", + "version": "1.8.5", "dev": true, "requires": { "@types/react": "*" @@ -60688,7 +65663,6 @@ }, "@types/redux-localstorage": { "version": "1.0.8", - "integrity": "sha512-pt+w3Y2K4Xwx79exTFZO356buBCgCM6NnyMv/EmASWb03a81g/EMEhNgH6w9dOnhTs1Clnmf2ykaia0FWXjsbQ==", "dev": true, "requires": { "redux": "^3.6.0" @@ -60696,7 +65670,6 @@ "dependencies": { "redux": { "version": "3.7.2", - "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", "dev": true, "requires": { "lodash": "^4.2.1", @@ -60709,37 +65682,42 @@ }, "@types/redux-mock-store": { "version": "1.0.2", - "integrity": "sha512-6LBtAQBN34i7SI5X+Qs4zpTEZO1tTDZ6sZ9fzFjYwTl3nLQXaBtwYdoV44CzNnyKu438xJ1lSIYyw0YMvunESw==", "dev": true, "requires": { "redux": "^4.0.5" } }, - "@types/resize-observer-browser": { - "version": "0.1.6", - "integrity": "sha512-61IfTac0s9jvNtBCpyo86QeaN8qqpMGHdK0uGKCCIy2dt5/Yk84VduHIdWAcmkC5QvdkPL0p5eWYgUZtHKKUVg==" - }, "@types/retry": { "version": "0.12.1", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", "dev": true }, "@types/rison": { - "version": "0.0.6", - "integrity": "sha512-mE3eRK0fpTN/GnNBOIg2tGq2cFhchQXF6fCbrLxus75TgnoOECbdHikr948FGO/UAml7/ZhLMa5FbGkF5PKvmw==" + "version": "0.0.6" }, "@types/seedrandom": { - "version": "2.4.30", - "integrity": "sha512-AnxLHewubLVzoF/A4qdxBGHCKifw8cY32iro3DQX9TPcetE95zBeVt3jnsvtvAUf1vwzMfwzp4t/L2yqPlnjkQ==" + "version": "2.4.30" + }, + "@types/serve-index": { + "version": "1.9.1", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.0", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } }, "@types/shortid": { "version": "0.0.29", - "integrity": "sha512-9BCYD9btg2CY4kPcpMQ+vCR8U6V8f/KvixYD5ZbxoWlkhddNF5IeZMVL3p+QFUkg+Hb+kPAG9Jgk4bnnF1v/Fw==", "dev": true }, "@types/sinon": { "version": "9.0.5", - "integrity": "sha512-4CnkGdM/5/FXDGqL32JQ1ttVrGvhOoesLLF7VnTh4KdjK5N5VQOtxaylFqqTjnHx55MnD9O02Nbk5c1ELC8wlQ==", "dev": true, "requires": { "@types/sinonjs__fake-timers": "*" @@ -60747,64 +65725,59 @@ }, "@types/sinonjs__fake-timers": { "version": "6.0.4", - "integrity": "sha512-IFQTJARgMUBF+xVd2b+hIgXWrZEjND3vJtRCvIelcFB5SIXfjV4bOHbHJ0eXKh+0COrBRc8MqteKAz/j88rE0A==", "dev": true }, "@types/sizzle": { "version": "2.3.2", - "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", "dev": true }, + "@types/sockjs": { + "version": "0.3.33", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/source-list-map": { - "version": "0.1.2", - "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==" + "version": "0.1.2" }, "@types/stack-utils": { "version": "1.0.1", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", "dev": true }, "@types/tapable": { - "version": "1.0.8", - "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==" + "version": "1.0.8" }, "@types/testing-library__jest-dom": { "version": "5.9.5", - "integrity": "sha512-ggn3ws+yRbOHog9GxnXiEZ/35Mow6YtPZpd7Z5mKDeZS/o7zx3yAle0ov/wjhVB5QT4N2Dt+GNoGCdqkBGCajQ==", "dev": true, "requires": { "@types/jest": "*" } }, "@types/text-encoding-utf-8": { - "version": "1.0.2", - "integrity": "sha512-AQ6zewa0ucLJvtUi5HsErbOFKAcQfRLt9zFLlUOvcXBy2G36a+ZDpCHSGdzJVUD8aNURtIjh9aSjCStNMRCcRQ==" + "version": "1.0.2" }, "@types/tinycolor2": { "version": "1.4.3", - "integrity": "sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==", "dev": true }, "@types/uglify-js": { "version": "3.0.4", - "integrity": "sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==", "requires": { "source-map": "^0.6.1" }, "dependencies": { "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } }, "@types/unist": { - "version": "2.0.3", - "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==" + "version": "2.0.3" }, "@types/webpack": { "version": "4.41.31", - "integrity": "sha512-/i0J7sepXFIp1ZT7FjUGi1eXMCg8HCCzLJEQkKsOtbJFontsJLolBcDC+3qxn5pPwiCt1G0ZdRmYRzNBtvpuGQ==", "requires": { "@types/node": "*", "@types/tapable": "^1", @@ -60816,29 +65789,24 @@ "dependencies": { "anymatch": { "version": "3.1.2", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "normalize-path": { - "version": "3.0.0", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "version": "3.0.0" }, "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } }, "@types/webpack-env": { - "version": "1.16.2", - "integrity": "sha512-vKx7WNQNZDyJveYcHAm9ZxhqSGLYwoyLhrHjLBOkw3a7cT76sTdjgtwyijhk1MaHyRIuSztcVwrUOO/NEu68Dw==" + "version": "1.18.0" }, "@types/webpack-sources": { "version": "0.1.5", - "integrity": "sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w==", "requires": { "@types/node": "*", "@types/source-list-map": "*", @@ -60846,14 +65814,19 @@ }, "dependencies": { "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } }, + "@types/ws": { + "version": "8.5.3", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/yargs": { "version": "15.0.13", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -60861,12 +65834,10 @@ }, "@types/yargs-parser": { "version": "15.0.0", - "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", "dev": true }, "@types/yauzl": { "version": "2.9.2", - "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", "dev": true, "optional": true, "requires": { @@ -60875,7 +65846,6 @@ }, "@typescript-eslint/eslint-plugin": { "version": "5.3.1", - "integrity": "sha512-cFImaoIr5Ojj358xI/SDhjog57OK2NqlpxwdcgyxDA3bJlZcJq5CPzUXtpD7CxI2Hm6ATU7w5fQnnkVnmwpHqw==", "dev": true, "requires": { "@typescript-eslint/experimental-utils": "5.3.1", @@ -60890,7 +65860,6 @@ "dependencies": { "@typescript-eslint/experimental-utils": { "version": "5.3.1", - "integrity": "sha512-RgFn5asjZ5daUhbK5Sp0peq0SSMytqcrkNfU4pnDma2D8P3ElZ6JbYjY8IMSFfZAJ0f3x3tnO3vXHweYg0g59w==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", @@ -60903,7 +65872,6 @@ "dependencies": { "eslint-utils": { "version": "3.0.0", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { "eslint-visitor-keys": "^2.0.0" @@ -60913,7 +65881,6 @@ }, "@typescript-eslint/typescript-estree": { "version": "5.3.1", - "integrity": "sha512-PwFbh/PKDVo/Wct6N3w+E4rLZxUDgsoII/GrWM2A62ETOzJd4M6s0Mu7w4CWsZraTbaC5UQI+dLeyOIFF1PquQ==", "dev": true, "requires": { "@typescript-eslint/types": "5.3.1", @@ -60927,7 +65894,6 @@ }, "debug": { "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -60935,17 +65901,14 @@ }, "eslint-visitor-keys": { "version": "2.1.0", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true }, "ignore": { "version": "5.1.9", - "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", "dev": true }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -60953,12 +65916,10 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "semver": { "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -60966,14 +65927,12 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@typescript-eslint/experimental-utils": { "version": "4.12.0", - "integrity": "sha512-MpXZXUAvHt99c9ScXijx7i061o5HEjXltO+sbYfZAAHxv3XankQkPaNi5myy0Yh0Tyea3Hdq1pi7Vsh0GJb0fA==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", @@ -60986,7 +65945,6 @@ "dependencies": { "@typescript-eslint/scope-manager": { "version": "4.12.0", - "integrity": "sha512-QVf9oCSVLte/8jvOsxmgBdOaoe2J0wtEmBr13Yz0rkBNkl5D8bfnf6G4Vhox9qqMIoG7QQoVwd2eG9DM/ge4Qg==", "dev": true, "requires": { "@typescript-eslint/types": "4.12.0", @@ -60995,12 +65953,10 @@ }, "@typescript-eslint/types": { "version": "4.12.0", - "integrity": "sha512-N2RhGeheVLGtyy+CxRmxdsniB7sMSCfsnbh8K/+RUIXYYq3Ub5+sukRCjVE80QerrUBvuEvs4fDhz5AW/pcL6g==", "dev": true }, "@typescript-eslint/visitor-keys": { "version": "4.12.0", - "integrity": "sha512-hVpsLARbDh4B9TKYz5cLbcdMIOAoBYgFPCSP9FFS/liSF+b33gVNq8JHY3QGhHNVz85hObvL7BEYLlgx553WCw==", "dev": true, "requires": { "@typescript-eslint/types": "4.12.0", @@ -61009,14 +65965,12 @@ }, "eslint-visitor-keys": { "version": "2.0.0", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", "dev": true } } }, "@typescript-eslint/parser": { "version": "5.3.1", - "integrity": "sha512-TD+ONlx5c+Qhk21x9gsJAMRohWAUMavSOmJgv3JGy9dgPhuBd5Wok0lmMClZDyJNLLZK1JRKiATzCKZNUmoyfw==", "dev": true, "requires": { "@typescript-eslint/scope-manager": "5.3.1", @@ -61027,7 +65981,6 @@ "dependencies": { "@typescript-eslint/typescript-estree": { "version": "5.3.1", - "integrity": "sha512-PwFbh/PKDVo/Wct6N3w+E4rLZxUDgsoII/GrWM2A62ETOzJd4M6s0Mu7w4CWsZraTbaC5UQI+dLeyOIFF1PquQ==", "dev": true, "requires": { "@typescript-eslint/types": "5.3.1", @@ -61041,7 +65994,6 @@ }, "debug": { "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -61049,7 +66001,6 @@ }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -61057,12 +66008,10 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "semver": { "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -61070,14 +66019,12 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@typescript-eslint/scope-manager": { "version": "5.3.1", - "integrity": "sha512-XksFVBgAq0Y9H40BDbuPOTUIp7dn4u8oOuhcgGq7EoDP50eqcafkMVGrypyVGvDYHzjhdUCUwuwVUK4JhkMAMg==", "dev": true, "requires": { "@typescript-eslint/types": "5.3.1", @@ -61086,12 +66033,10 @@ }, "@typescript-eslint/types": { "version": "5.3.1", - "integrity": "sha512-bG7HeBLolxKHtdHG54Uac750eXuQQPpdJfCYuw4ZI3bZ7+GgKClMWM8jExBtp7NSP4m8PmLRM8+lhzkYnSmSxQ==", "dev": true }, "@typescript-eslint/typescript-estree": { "version": "4.12.0", - "integrity": "sha512-gZkFcmmp/CnzqD2RKMich2/FjBTsYopjiwJCroxqHZIY11IIoN0l5lKqcgoAPKHt33H2mAkSfvzj8i44Jm7F4w==", "dev": true, "requires": { "@typescript-eslint/types": "4.12.0", @@ -61106,12 +66051,10 @@ "dependencies": { "@typescript-eslint/types": { "version": "4.12.0", - "integrity": "sha512-N2RhGeheVLGtyy+CxRmxdsniB7sMSCfsnbh8K/+RUIXYYq3Ub5+sukRCjVE80QerrUBvuEvs4fDhz5AW/pcL6g==", "dev": true }, "@typescript-eslint/visitor-keys": { "version": "4.12.0", - "integrity": "sha512-hVpsLARbDh4B9TKYz5cLbcdMIOAoBYgFPCSP9FFS/liSF+b33gVNq8JHY3QGhHNVz85hObvL7BEYLlgx553WCw==", "dev": true, "requires": { "@typescript-eslint/types": "4.12.0", @@ -61120,7 +66063,6 @@ }, "debug": { "version": "4.3.1", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -61128,12 +66070,10 @@ }, "eslint-visitor-keys": { "version": "2.0.0", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", "dev": true }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -61141,12 +66081,10 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "semver": { "version": "7.3.4", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -61154,23 +66092,29 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "@typescript-eslint/visitor-keys": { "version": "5.3.1", - "integrity": "sha512-3cHUzUuVTuNHx0Gjjt5pEHa87+lzyqOiHXy/Gz+SJOCW1mpw9xQHIIEwnKn+Thph1mgWyZ90nboOcSuZr/jTTQ==", "dev": true, "requires": { "@typescript-eslint/types": "5.3.1", "eslint-visitor-keys": "^3.0.0" } }, + "@visx/responsive": { + "version": "3.0.0", + "requires": { + "@types/lodash": "^4.14.172", + "@types/react": "*", + "lodash": "^4.17.21", + "prop-types": "^15.6.1" + } + }, "@vx/axis": { "version": "0.0.140", - "integrity": "sha512-lxMgWySkSh7ew8XS25Kpn95HH4d8dpL2vLv1UvASJY2VxdczQayTUUvQLecesJI4bbJV2R7Fasm64EBlJAezTw==", "requires": { "@vx/group": "0.0.140", "@vx/point": "0.0.136", @@ -61181,7 +66125,6 @@ "dependencies": { "prop-types": { "version": "15.5.10", - "integrity": "sha512-vCFzoUFaZkVNeFkhK1KbSq4cn97GDrpfBt9K2qLkGnPAEFhEv3M61Lk5t+B7c0QfMLWo0fPkowk/4SuXerh26Q==", "requires": { "fbjs": "^0.8.9", "loose-envify": "^1.3.1" @@ -61191,32 +66134,27 @@ }, "@vx/bounds": { "version": "0.0.140", - "integrity": "sha512-6TLF2KsSW3aqeBhTnouFhSLGT//zgrDz2uThYfrmL2oVkkXRtjNBKXW/BR+E3ugI+gSH6VfoL85s2bSAkAJo7w==", "requires": { "prop-types": "^15.5.10" } }, "@vx/clip-path": { - "version": "0.0.140", - "integrity": "sha512-Un/9v5Pvu6rEHmQzkN5nPnPsmiSRVl4xhcdelK01xxWAnkFJoXvQiTGdOvF0JOtntVOPDwKUimx+iUiCxBZjoA==" + "version": "0.0.140" }, "@vx/curve": { "version": "0.0.165", - "integrity": "sha512-fiQAGrKNGjJbL+eixUckJqIZDWXH/1NtIyyDbSz3J7ksk0QpYr5BgWcNJN76HLNt7wfcLwNzCHeNs4iVYyFGTg==", "requires": { "d3-shape": "^1.0.6" } }, "@vx/event": { "version": "0.0.140", - "integrity": "sha512-m51d8rz4Uu8Vyvu50dulKcrBt6/y4+ZDvgBjs5QNfhNHIa8T+Uqcs6m3jWNw2mpsnC8MtEavi5S3SUDuWlwl7A==", "requires": { "@vx/point": "0.0.136" } }, "@vx/glyph": { "version": "0.0.140", - "integrity": "sha512-ev/DCvE3a8YyDC8bQhoZ5WILzeQMqI2mKeAVARsJpX1mmwvi5Hn8S35TZcV9yaIZ36LC8cbhtQY5wjsQU6FGcA==", "requires": { "@vx/group": "0.0.140", "classnames": "^2.2.5", @@ -61225,7 +66163,6 @@ }, "@vx/gradient": { "version": "0.0.140", - "integrity": "sha512-VHaZ6YIjRj3l26LGWg3Bz82vAyp0Te890W3tMABGZC+pwU3lpZJzN89UBJ8vT+42Jcc1o3B7vS67mBjITFTHVQ==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.5.7" @@ -61233,7 +66170,6 @@ }, "@vx/grid": { "version": "0.0.140", - "integrity": "sha512-QtAEzdR4gtQtuqkiP3BAXlyU7Fsuwom0HHY1lEdO/wyIijYhpHf3fG1GgPVJsr7YXY1ieUQ6k1A9EEmdEIlBxw==", "requires": { "@vx/group": "0.0.140", "@vx/point": "0.0.136", @@ -61243,14 +66179,12 @@ }, "@vx/group": { "version": "0.0.140", - "integrity": "sha512-es87IDOWhXSW++gajslK7bl9FTdp1kkVMH8AKAhSoDjh0DSZan5yYpS3OvMgJHh1Tlgl3KZzh/RJ1Qfh/FKLCg==", "requires": { "classnames": "^2.2.5" } }, "@vx/legend": { "version": "0.0.140", - "integrity": "sha512-fpt2XUDQcKKfZc5DedRWfMWm+BUIKePkv+M6y0zpWaw/k63LIZUr9oCnGdTk9yCBfSxLBvwfcxY7jhUCJIT84Q==", "requires": { "@vx/group": "0.0.140", "classnames": "^2.2.5", @@ -61259,19 +66193,16 @@ }, "@vx/pattern": { "version": "0.0.140", - "integrity": "sha512-TRP/i2C4TW1rwp3AzcrxTP0Zk0XalgSKOzUuTFasceEUkyVFTZ+MrwWIEG2YYs6S7d5M/VqvIQdI3KGRRyKysA==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.5.10" } }, "@vx/point": { - "version": "0.0.136", - "integrity": "sha512-x5y5eQJ0koZCGS0AK2juiJ2hLsZhgAOzQ2MuMushikEfQ1azLtrDIh4l2WesLQrp//o9+u2sWJ3mPgEGdBIvfA==" + "version": "0.0.136" }, "@vx/responsive": { - "version": "0.0.195", - "integrity": "sha512-3zjkjqg8V3Kr1moSI7EAzlW7MLR87p2CXc+qh0zZg/zLrc3C89JnxyMYFfS7jM4PlHr26n634YddQDVydwARBA==", + "version": "0.0.199", "requires": { "@types/lodash": "^4.14.146", "@types/react": "*", @@ -61282,14 +66213,12 @@ }, "@vx/scale": { "version": "0.0.140", - "integrity": "sha512-JlxEKtBsJyfltcImPA2BPWvHjzvNTGZmRYywzR63W9usWGPUjVC9AGXOsRQn7lea764xlZI83mPGQI7lNkz4Tw==", "requires": { "d3-scale": "^1.0.5" }, "dependencies": { "d3-scale": { "version": "1.0.7", - "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", "requires": { "d3-array": "^1.2.0", "d3-collection": "1", @@ -61304,7 +66233,6 @@ }, "@vx/shape": { "version": "0.0.140", - "integrity": "sha512-njU9Fby0+Fykr3cOla95Brn7Yh/oRMX2DXh65yn2Rx8hUWLrLwsQW46mWBaxO+Dq85UQ6BKTJxa+l1vrc2u8nw==", "requires": { "@vx/curve": "0.0.140", "@vx/group": "0.0.140", @@ -61316,7 +66244,6 @@ "dependencies": { "@vx/curve": { "version": "0.0.140", - "integrity": "sha512-rVjxj6Vi9taGLxjzzilfNdoh3kUfYnc8G8rZ/l+0caNPBIY3OQW3HDGhITc2bh72daCfFsylQXwpc/YxLfbSWA==", "requires": { "d3-shape": "^1.0.6" } @@ -61325,7 +66252,6 @@ }, "@vx/stats": { "version": "0.0.165", - "integrity": "sha512-FRW5N+7pXLZrQxT8JA8OH28PGKq7YfiycmnSG7jzXOnvw+sPm9MRKCoyRDTpFrCiggcOhHhvqhE8RiO2qF7d3Q==", "requires": { "@vx/group": "0.0.165", "@vx/scale": "0.0.165", @@ -61335,14 +66261,12 @@ "dependencies": { "@vx/group": { "version": "0.0.165", - "integrity": "sha512-gi1DSg8AAaVRseyWiq8y4bzyvKiQIXT6vDUYBVRmv2LBcpHocBGaxNiNK0X602RgLG0XmNyRv6qSCWLOaBs3Mg==", "requires": { "classnames": "^2.2.5" } }, "@vx/scale": { "version": "0.0.165", - "integrity": "sha512-5jSgXJDU6J/KWIyCbpjHqysPCddp7tG3LbTV7UmtB1Qleb4m4slShTVSE7+EKU+zgiQPDGm0+E2ht4cet+7F7A==", "requires": { "d3-scale": "^2.0.0" } @@ -61351,7 +66275,6 @@ }, "@vx/text": { "version": "0.0.179", - "integrity": "sha512-UD3/8o15+AQfjDI8LQ1Zj3EdQCwA3cfuQMR/M2F/Le4+JXQNMheeWz4xGyF4ZDs6r7c5cUI9Cd1RaPmGhYsX9g==", "requires": { "babel-plugin-lodash": "^3.3.2", "classnames": "^2.2.5", @@ -61362,7 +66285,6 @@ }, "@vx/threshold": { "version": "0.0.170", - "integrity": "sha512-A3yWJrFqckbleXg3Q3iSsU6mdtHbMxEnE4jGZd8og4m9r2RDVTvFVP6ZRo4vunlfWj5YuMnNsKhx4ZSWKVMtXg==", "requires": { "@vx/clip-path": "0.0.165", "@vx/shape": "0.0.170", @@ -61371,23 +66293,19 @@ }, "dependencies": { "@vx/clip-path": { - "version": "0.0.165", - "integrity": "sha512-mBCbgguLMVyGvar5FbxqyyY4NQFlnXoSLF0TrhgWYkF/FCXdE1CzBC+Y4iXIJOY0ZTtluqL9XrNdIDpx49AmuA==" + "version": "0.0.165" }, "@vx/group": { "version": "0.0.170", - "integrity": "sha512-RnDdRoy0YI5hokk+YWXc8t39Kp51i4BdCpiwkDJU4YypGycTYnDFjicam6jigUmZ/6wyMirDf/aQboWviFLt2Q==", "requires": { "classnames": "^2.2.5" } }, "@vx/point": { - "version": "0.0.165", - "integrity": "sha512-spoHilhjcWNgccrSzBUPw+PXV81tYxeyEWBkgr35aGVU4m7YT86Ywvfemwp7AVVGPn+XJHrhB0ujAhDoyqFPoA==" + "version": "0.0.165" }, "@vx/shape": { "version": "0.0.170", - "integrity": "sha512-rm8oVRP0ejgwGhQTVhqP5awqphWX60FgbnRt9X+YBUqgv7Qyedfgs/CHd/5QFZX3aPp8d4F+b4+lghbIYiMgmQ==", "requires": { "@vx/curve": "0.0.165", "@vx/group": "0.0.170", @@ -61402,7 +66320,6 @@ }, "@vx/tooltip": { "version": "0.0.140", - "integrity": "sha512-D6D6b6Pm5ZR39CWi250OV2Ub1P9Zk/199a6smUygBAXVVXhBHMe+wz9WuGllJQkMcRvIi+DMhgMHDNihDwjTVA==", "requires": { "@vx/bounds": "0.0.140", "classnames": "^2.2.5", @@ -61411,7 +66328,6 @@ }, "@vx/voronoi": { "version": "0.0.165", - "integrity": "sha512-oZT9KBAjDLCEcOrrqW01TPz8pLtrNNAFPa7mB9ignXvgntqEd3yVXCBkxXScfZLS+O8UQc+7/pawu0PPkE2eMw==", "requires": { "@vx/group": "0.0.165", "classnames": "^2.2.5", @@ -61421,7 +66337,6 @@ "dependencies": { "@vx/group": { "version": "0.0.165", - "integrity": "sha512-gi1DSg8AAaVRseyWiq8y4bzyvKiQIXT6vDUYBVRmv2LBcpHocBGaxNiNK0X602RgLG0XmNyRv6qSCWLOaBs3Mg==", "requires": { "classnames": "^2.2.5" } @@ -61430,7 +66345,6 @@ }, "@webassemblyjs/ast": { "version": "1.9.0", - "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", "requires": { "@webassemblyjs/helper-module-context": "1.9.0", "@webassemblyjs/helper-wasm-bytecode": "1.9.0", @@ -61438,38 +66352,31 @@ } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.9.0", - "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + "version": "1.9.0" }, "@webassemblyjs/helper-api-error": { - "version": "1.9.0", - "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + "version": "1.9.0" }, "@webassemblyjs/helper-buffer": { - "version": "1.9.0", - "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + "version": "1.9.0" }, "@webassemblyjs/helper-code-frame": { "version": "1.9.0", - "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", "requires": { "@webassemblyjs/wast-printer": "1.9.0" } }, "@webassemblyjs/helper-fsm": { - "version": "1.9.0", - "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + "version": "1.9.0" }, "@webassemblyjs/helper-module-context": { "version": "1.9.0", - "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", "requires": { "@webassemblyjs/ast": "1.9.0" } }, "@webassemblyjs/helper-numbers": { "version": "1.11.1", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", "dev": true, "requires": { "@webassemblyjs/floating-point-hex-parser": "1.11.1", @@ -61479,23 +66386,19 @@ "dependencies": { "@webassemblyjs/floating-point-hex-parser": { "version": "1.11.1", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", "dev": true }, "@webassemblyjs/helper-api-error": { "version": "1.11.1", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", "dev": true } } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.9.0", - "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + "version": "1.9.0" }, "@webassemblyjs/helper-wasm-section": { "version": "1.9.0", - "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-buffer": "1.9.0", @@ -61505,25 +66408,21 @@ }, "@webassemblyjs/ieee754": { "version": "1.9.0", - "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { "version": "1.9.0", - "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.9.0", - "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + "version": "1.9.0" }, "@webassemblyjs/wasm-edit": { "version": "1.9.0", - "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-buffer": "1.9.0", @@ -61537,7 +66436,6 @@ }, "@webassemblyjs/wasm-gen": { "version": "1.9.0", - "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-wasm-bytecode": "1.9.0", @@ -61548,7 +66446,6 @@ }, "@webassemblyjs/wasm-opt": { "version": "1.9.0", - "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-buffer": "1.9.0", @@ -61558,7 +66455,6 @@ }, "@webassemblyjs/wasm-parser": { "version": "1.9.0", - "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-api-error": "1.9.0", @@ -61570,7 +66466,6 @@ }, "@webassemblyjs/wast-parser": { "version": "1.9.0", - "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/floating-point-hex-parser": "1.9.0", @@ -61582,7 +66477,6 @@ }, "@webassemblyjs/wast-printer": { "version": "1.9.0", - "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", "requires": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/wast-parser": "1.9.0", @@ -61591,12 +66485,10 @@ }, "@webpack-cli/configtest": { "version": "1.0.4", - "integrity": "sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==", "dev": true }, "@webpack-cli/info": { "version": "1.3.0", - "integrity": "sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w==", "dev": true, "requires": { "envinfo": "^7.7.3" @@ -61604,57 +66496,77 @@ }, "@webpack-cli/serve": { "version": "1.5.2", - "integrity": "sha512-vgJ5OLWadI8aKjDlOH3rb+dYyPd2GTZuQC/Tihjct6F9GpXGZINo3Y/IVuZVTM1eDQB+/AOsjPUWH/WySDaXvw==", "dev": true }, "@xtuc/ieee754": { - "version": "1.2.0", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + "version": "1.2.0" }, "@xtuc/long": { - "version": "4.2.2", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + "version": "4.2.2" + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "dev": true + }, + "@yarnpkg/parsers": { + "version": "3.0.0-rc.33", + "dev": true, + "requires": { + "js-yaml": "^3.10.0", + "tslib": "^2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.1", + "dev": true + } + } + }, + "@zkochan/js-yaml": { + "version": "0.0.6", + "dev": true, + "requires": { + "argparse": "^2.0.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "dev": true + } + } }, "abab": { "version": "2.0.6", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "dev": true }, "abbrev": { - "version": "1.1.1", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "version": "1.1.1" }, "abort-controller": { "version": "3.0.0", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "dev": true, "requires": { "event-target-shim": "^5.0.0" } }, "abortcontroller-polyfill": { - "version": "1.2.1", - "integrity": "sha512-9jN7+BijYKWO8fxfcG7QZh7js6V+g3OjkxMRHfKWNjjs85048VY4cd27Uoe6yk55P66L/z7Dflu5+YEApgMzkA==" + "version": "1.2.1" }, "accepts": { - "version": "1.3.5", - "integrity": "sha512-pt4oTticGUEOZCvli0I7ekmpXopaX+Xvb/TQRaTKnvZNIH9Srs0VWi2NGBfsRscAgwtIEtxW5JOB9sI0oN3cjw==", + "version": "1.3.8", "requires": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, "ace-builds": { - "version": "1.4.14", - "integrity": "sha512-NBOQlm9+7RBqRqZwimpgquaLeTJFayqb9UEPtTkpC3TkkwDnlsT/TwsCC0svjt9kEZ6G9mH5AEOHSz6Q/HrzQQ==" + "version": "1.4.14" }, "acorn": { - "version": "8.7.0", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" + "version": "8.7.1" }, "acorn-globals": { "version": "6.0.0", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", "dev": true, "requires": { "acorn": "^7.1.1", @@ -61663,44 +66575,35 @@ "dependencies": { "acorn": { "version": "7.4.1", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true } } }, "acorn-import-assertions": { "version": "1.7.6", - "integrity": "sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==", "dev": true }, "acorn-jsx": { "version": "5.3.1", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", "dev": true }, "acorn-walk": { "version": "7.2.0", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, "add-stream": { "version": "1.0.0", - "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", "dev": true }, "address": { - "version": "1.1.2", - "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==" + "version": "1.1.2" }, "ag-charts-community": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ag-charts-community/-/ag-charts-community-4.2.0.tgz", - "integrity": "sha512-9vZSwlcpGwkb6KwEzTgxw5BuzdZgRhrbbiQS5wIfSa74cNsyYt76MTBPudqfHnc+SoWDGGxof3rteU6kXSc07w==", "dev": true }, "agent-base": { "version": "6.0.2", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, "requires": { "debug": "4" @@ -61708,7 +66611,6 @@ "dependencies": { "debug": { "version": "4.3.3", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "requires": { "ms": "2.1.2" @@ -61716,14 +66618,12 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "agentkeepalive": { - "version": "4.2.0", - "integrity": "sha512-0PhAp58jZNw13UJv7NVdTGb0ZcghHUb3DrZ046JiiJY/BOaTTpbwdHq2VObPCBV8M2GPh7sgrJ3AQ8Ey468LJw==", + "version": "4.2.1", "dev": true, "requires": { "debug": "^4.1.0", @@ -61733,7 +66633,6 @@ "dependencies": { "debug": { "version": "4.3.3", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "requires": { "ms": "2.1.2" @@ -61741,14 +66640,12 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "aggregate-error": { "version": "3.0.1", - "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -61756,7 +66653,6 @@ }, "airbnb-js-shims": { "version": "2.2.1", - "integrity": "sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==", "requires": { "array-includes": "^3.0.3", "array.prototype.flat": "^1.2.1", @@ -61778,32 +66674,22 @@ } }, "airbnb-prop-types": { - "version": "2.15.0", - "integrity": "sha512-jUh2/hfKsRjNFC4XONQrxo/n/3GG4Tn6Hl0WlFQN5PY9OMC9loSCoAYKnZsWaP8wEfd5xcrPloK0Zg6iS1xwVA==", + "version": "2.16.0", "dev": true, "requires": { - "array.prototype.find": "^2.1.0", - "function.prototype.name": "^1.1.1", - "has": "^1.0.3", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", + "array.prototype.find": "^2.1.1", + "function.prototype.name": "^1.1.2", + "is-regex": "^1.1.0", + "object-is": "^1.1.2", "object.assign": "^4.1.0", - "object.entries": "^1.1.0", + "object.entries": "^1.1.2", "prop-types": "^15.7.2", "prop-types-exact": "^1.2.0", - "react-is": "^16.9.0" - }, - "dependencies": { - "react-is": { - "version": "16.9.0", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", - "dev": true - } + "react-is": "^16.13.1" } }, "ajv": { "version": "6.12.6", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -61812,12 +66698,10 @@ } }, "ajv-errors": { - "version": "1.0.1", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" + "version": "1.0.1" }, "ajv-formats": { "version": "2.1.1", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, "requires": { "ajv": "^8.0.0" @@ -61825,7 +66709,6 @@ "dependencies": { "ajv": { "version": "8.8.2", - "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -61836,38 +66719,31 @@ }, "json-schema-traverse": { "version": "1.0.0", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true } } }, "ajv-keywords": { - "version": "3.5.2", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" + "version": "3.5.2" }, "alphanum-sort": { "version": "1.0.2", - "integrity": "sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==", "dev": true }, "ansi-align": { "version": "3.0.1", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", "requires": { "string-width": "^4.1.0" }, "dependencies": { "ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "version": "5.0.1" }, "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "version": "3.0.0" }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -61876,7 +66752,6 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { "ansi-regex": "^5.0.1" } @@ -61884,158 +66759,263 @@ } }, "ansi-colors": { - "version": "3.2.4", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" + "version": "3.2.4" }, "ansi-escapes": { "version": "4.3.1", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "devOptional": true, + "dev": true, "requires": { "type-fest": "^0.11.0" }, "dependencies": { "type-fest": { "version": "0.11.0", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "devOptional": true + "dev": true } } }, "ansi-html-community": { - "version": "0.0.8", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" + "version": "0.0.8" }, "ansi-regex": { - "version": "2.1.1", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" + "version": "2.1.1" }, "ansi-styles": { "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { "color-convert": "^2.0.1" }, "dependencies": { "color-convert": { "version": "2.0.1", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "version": "1.1.4" } } }, "ansi-to-html": { "version": "0.6.15", - "integrity": "sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ==", "requires": { "entities": "^2.0.0" }, "dependencies": { "entities": { - "version": "2.2.0", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + "version": "2.2.0" } } }, - "ansicolors": { - "version": "0.2.1", - "integrity": "sha512-tOIuy1/SK/dr94ZA0ckDohKXNeBNqZ4us6PjMVLs5h1w2GBB6uPtOknp2+VF4F/zcy9LI70W+Z+pE2Soajky1w==" - }, "antd": { - "version": "4.9.4", - "integrity": "sha512-kieGi1Isb/ddnn9E/AJVFCUgSZIqDv6HtFg7r5WWI0s6zf+nfCOtpes0oX8TdHO6mE/dL39pJG52aHNe8MwkJg==", + "version": "4.10.3", "requires": { "@ant-design/colors": "^5.0.0", "@ant-design/icons": "^4.3.0", - "@ant-design/react-slick": "~0.27.0", + "@ant-design/react-slick": "~0.28.1", "@babel/runtime": "^7.11.2", "array-tree-filter": "^2.1.0", "classnames": "^2.2.6", "copy-to-clipboard": "^3.2.0", "lodash": "^4.17.20", "moment": "^2.25.3", - "omit.js": "^2.0.2", "rc-cascader": "~1.4.0", "rc-checkbox": "~2.3.0", "rc-collapse": "~3.1.0", - "rc-dialog": "~8.4.0", - "rc-drawer": "~4.1.0", + "rc-dialog": "~8.5.1", + "rc-drawer": "~4.2.0", "rc-dropdown": "~3.2.0", - "rc-field-form": "~1.17.0", - "rc-image": "~4.2.0", + "rc-field-form": "~1.17.3", + "rc-image": "~5.0.2", "rc-input-number": "~6.1.0", "rc-mentions": "~1.5.0", "rc-menu": "~8.10.0", "rc-motion": "^2.4.0", "rc-notification": "~4.5.2", "rc-pagination": "~3.1.2", - "rc-picker": "~2.4.1", + "rc-picker": "~2.5.1", "rc-progress": "~3.1.0", "rc-rate": "~2.9.0", - "rc-resize-observer": "^0.2.3", - "rc-select": "~11.5.3", - "rc-slider": "~9.6.1", + "rc-resize-observer": "^1.0.0", + "rc-select": "~12.1.0", + "rc-slider": "~9.7.1", "rc-steps": "~4.1.0", "rc-switch": "~3.2.0", - "rc-table": "~7.11.0", + "rc-table": "~7.12.0", "rc-tabs": "~11.7.0", "rc-textarea": "~0.3.0", "rc-tooltip": "~5.0.0", - "rc-tree": "~4.0.0", - "rc-tree-select": "~4.2.0", - "rc-upload": "~3.3.1", - "rc-util": "^5.1.0", + "rc-tree": "~4.1.0", + "rc-tree-select": "~4.3.0", + "rc-upload": "~3.3.4", + "rc-util": "^5.7.0", "scroll-into-view-if-needed": "^2.2.25", "warning": "^4.0.3" }, "dependencies": { "@ant-design/colors": { "version": "5.0.1", - "integrity": "sha512-x1TUaRILaqy3zgFNo+kIqOa3eTYPt81H1/3E4dCjDP4Qvk/xaPEizLDFdRUcIx0cWwyu2LklwfyLHWpbYK8v6A==", "requires": { "@ctrl/tinycolor": "^3.3.1" } }, - "@ant-design/icons": { - "version": "4.3.0", - "integrity": "sha512-UoIbw4oz/L/msbkgqs2nls2KP7XNKScOxVR54wRrWwnXOzJaGNwwSdYjHQz+5ETf8C53YPpzMOnRX99LFCdeIQ==", + "@ant-design/react-slick": { + "version": "0.28.4", + "requires": { + "@babel/runtime": "^7.10.4", + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "lodash": "^4.17.21", + "resize-observer-polyfill": "^1.5.0" + } + }, + "rc-dialog": { + "version": "8.5.3", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-motion": "^2.3.0", + "rc-util": "^5.6.1" + } + }, + "rc-drawer": { + "version": "4.2.2", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.7.0" + } + }, + "rc-image": { + "version": "5.0.2", "requires": { - "@ant-design/colors": "^5.0.0", - "@ant-design/icons-svg": "^4.0.0", "@babel/runtime": "^7.11.2", "classnames": "^2.2.6", - "insert-css": "^2.0.0", - "rc-util": "^5.0.1" + "rc-dialog": "~8.5.1", + "rc-util": "^5.0.6" } }, - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", + "rc-picker": { + "version": "2.5.19", "requires": { - "react-is": "^16.12.0", + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "date-fns": "2.x", + "dayjs": "1.x", + "moment": "^2.24.0", + "rc-trigger": "^5.0.4", + "rc-util": "^5.4.0", "shallowequal": "^1.1.0" } }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "rc-resize-observer": { + "version": "1.2.0", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-util": "^5.15.0", + "resize-observer-polyfill": "^1.5.1" + } + }, + "rc-select": { + "version": "12.1.13", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-overflow": "^1.0.0", + "rc-trigger": "^5.0.4", + "rc-util": "^5.9.8", + "rc-virtual-list": "^3.2.0" + }, + "dependencies": { + "rc-overflow": { + "version": "1.2.8", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.19.2" + } + }, + "rc-virtual-list": { + "version": "3.4.11", + "requires": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.15.0" + } + } + } + }, + "rc-slider": { + "version": "9.7.5", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-tooltip": "^5.0.1", + "rc-util": "^5.16.1", + "shallowequal": "^1.1.0" + } + }, + "rc-table": { + "version": "7.12.5", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.4.0", + "shallowequal": "^1.1.0" + } + }, + "rc-tooltip": { + "version": "5.0.2", + "requires": { + "@babel/runtime": "^7.11.2", + "rc-trigger": "^5.0.0" + } + }, + "rc-tree": { + "version": "4.1.5", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-util": "^5.0.0", + "rc-virtual-list": "^3.0.1" + }, + "dependencies": { + "rc-virtual-list": { + "version": "3.4.11", + "requires": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.15.0" + } + } + } + }, + "rc-tree-select": { + "version": "4.3.3", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-select": "^12.0.0", + "rc-tree": "^4.0.0", + "rc-util": "^5.0.5" + } } } }, "any-observable": { "version": "0.3.0", - "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", "dev": true }, "anymatch": { "version": "2.0.0", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "devOptional": true, "requires": { "micromatch": "^3.1.4", @@ -62044,7 +67024,6 @@ }, "apache-arrow": { "version": "4.0.1", - "integrity": "sha512-DyF7GXCbSjsw4P5C8b+qW7OnJKa6w9mJI0mhV0+EfZbVZCmhfiF6ffqcnrI/kzBrRqn9hH/Ft9n5+m4DTbBJpg==", "requires": { "@types/flatbuffers": "^1.10.0", "@types/node": "^14.14.37", @@ -62059,18 +67038,15 @@ }, "dependencies": { "@types/node": { - "version": "14.17.9", - "integrity": "sha512-CMjgRNsks27IDwI785YMY0KLt3co/c0cQ5foxHYv/shC2w8oOnVwz5Ubq1QG5KzrcW+AXk6gzdnxIkDnTvzu3g==" + "version": "14.17.9" }, "tslib": { - "version": "2.3.0", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + "version": "2.3.0" } } }, "aphrodite": { "version": "1.2.5", - "integrity": "sha512-vbhTGgXORXnHNnQF7ReckeB3LAow8l4svWwf4R6zBdbBQEswi6+HVIWQX914jWYOJoD/h+AjWDvbIAvyhWnBmQ==", "requires": { "asap": "^2.0.3", "inline-style-prefixer": "^3.0.1", @@ -62078,32 +67054,38 @@ } }, "app-root-dir": { - "version": "1.0.2", - "integrity": "sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==" + "version": "1.0.2" }, "aproba": { - "version": "1.2.0", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "version": "1.2.0" }, "are-we-there-yet": { - "version": "1.1.7", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "version": "3.0.1", "dev": true, "requires": { "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "readable-stream": "^3.6.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "argparse": { "version": "1.0.10", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "requires": { "sprintf-js": "~1.0.2" } }, "aria-query": { "version": "4.2.2", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", "dev": true, "requires": { "@babel/runtime": "^7.10.2", @@ -62111,47 +67093,34 @@ } }, "arr-diff": { - "version": "4.0.0", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==" + "version": "4.0.0" }, "arr-flatten": { - "version": "1.1.0", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + "version": "1.1.0" }, "arr-union": { - "version": "3.1.0", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==" + "version": "3.1.0" }, "array-back": { - "version": "3.1.0", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" + "version": "3.1.0" }, "array-differ": { "version": "3.0.0", - "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==" - }, - "array-equal": { - "version": "1.0.0", - "integrity": "sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==", "dev": true }, - "array-filter": { + "array-equal": { "version": "1.0.0", - "integrity": "sha512-Ene1hbrinPZ1qPoZp7NSx4jQnh4nr7MtY78pHNb+yr8yHbxmTS7ChGW0a55JKA7TkRDeoQxK4GcJaCvBYplSKA==", "dev": true }, "array-flatten": { - "version": "2.1.2", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + "version": "2.1.2" }, "array-ify": { "version": "1.0.0", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", "dev": true }, "array-includes": { "version": "3.1.4", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -62161,46 +67130,52 @@ } }, "array-move": { - "version": "2.2.1", - "integrity": "sha512-qQpEHBnVT6HAFgEVUwRdHVd8TYJThrZIT5wSXpEUTPwBaYhPLclw12mEpyUvRWVdl1VwPOqnIy6LqTFN3cSeUQ==" + "version": "2.2.1" }, "array-tree-filter": { - "version": "2.1.0", - "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" + "version": "2.1.0" }, "array-union": { - "version": "2.1.0", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + "version": "2.1.0" }, "array-uniq": { - "version": "1.0.3", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==" + "version": "1.0.3" }, "array-unique": { - "version": "0.3.2", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" + "version": "0.3.2" + }, + "array.prototype.filter": { + "version": "1.0.2", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + } }, "array.prototype.find": { - "version": "2.1.0", - "integrity": "sha512-Wn41+K1yuO5p7wRZDl7890c3xvv5UBrfVXTVIe28rSQb6LS0fZMDrQB6PAcxQFRFy6vJTLDc3A2+3CjQdzVKRg==", + "version": "2.2.1", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.13.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" } }, "array.prototype.flat": { - "version": "1.2.1", - "integrity": "sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw==", + "version": "1.3.1", "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.10.0", - "function-bind": "^1.1.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" } }, "array.prototype.flatmap": { "version": "1.2.3", - "integrity": "sha512-OOEk+lkePcg+ODXIpvuU9PAryCikCJyo7GlDG1upleEpQRx6mzL9puEBkozQ5iAx20KV0l3DbyQwqciJtqe5Pg==", "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1", @@ -62209,7 +67184,6 @@ }, "array.prototype.map": { "version": "1.0.4", - "integrity": "sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -62220,16 +67194,13 @@ }, "arrify": { "version": "1.0.1", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true }, "asap": { - "version": "2.0.6", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + "version": "2.0.6" }, "asn1": { "version": "0.2.4", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "dev": true, "requires": { "safer-buffer": "~2.1.0" @@ -62237,7 +67208,6 @@ }, "asn1.js": { "version": "5.4.1", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -62246,26 +67216,22 @@ }, "dependencies": { "bn.js": { - "version": "4.12.0", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.0" } } }, "assert": { "version": "1.5.0", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "requires": { "object-assign": "^4.1.1", "util": "0.10.3" }, "dependencies": { "inherits": { - "version": "2.0.1", - "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==" + "version": "2.0.1" }, "util": { "version": "0.10.3", - "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", "requires": { "inherits": "2.0.1" } @@ -62274,73 +67240,63 @@ }, "assert-plus": { "version": "1.0.0", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true }, "assign-symbols": { - "version": "1.0.0", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==" + "version": "1.0.0" }, "ast-types": { "version": "0.14.2", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", "requires": { "tslib": "^2.0.1" }, "dependencies": { "tslib": { - "version": "2.3.1", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.3.1" } } }, "ast-types-flow": { "version": "0.0.7", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", "dev": true }, "astral-regex": { "version": "2.0.0", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.4", "dev": true }, "async-each": { "version": "1.0.3", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "optional": true }, "async-limiter": { "version": "1.0.0", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "dev": true }, "async-retry": { "version": "1.3.3", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", "dev": true, "requires": { "retry": "0.13.1" } }, "async-validator": { - "version": "3.5.1", - "integrity": "sha512-DDmKA7sdSAJtTVeNZHrnr2yojfFaoeW8MfQN8CeuXg8DDQHTqKk9Fdv38dSvnesHoO8MUwMI2HphOeSyIF+wmQ==" + "version": "3.5.1" }, "asynckit": { - "version": "0.4.0", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "version": "0.4.0" }, "at-least-node": { - "version": "1.0.0", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + "version": "1.0.0" }, "atob": { - "version": "2.1.2", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + "version": "2.1.2" }, "autoprefixer": { "version": "9.8.8", - "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", "requires": { "browserslist": "^4.12.0", "caniuse-lite": "^1.0.30001109", @@ -62353,49 +67309,44 @@ "dependencies": { "postcss": { "version": "7.0.39", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "requires": { "picocolors": "^0.2.1", "source-map": "^0.6.1" } }, "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } }, + "available-typed-arrays": { + "version": "1.0.5" + }, "aws-sign2": { "version": "0.7.0", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true }, "aws4": { "version": "1.8.0", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, "axe-core": { "version": "4.4.1", - "integrity": "sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==", "dev": true }, "axios": { "version": "0.21.4", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "devOptional": true, + "dev": true, "requires": { "follow-redirects": "^1.14.0" } }, "axobject-query": { "version": "2.2.0", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", "dev": true }, "babel-jest": { "version": "26.6.3", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", "dev": true, "requires": { "@jest/transform": "^26.6.2", @@ -62410,14 +67361,12 @@ "dependencies": { "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true } } }, "babel-loader": { "version": "8.2.5", - "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", "requires": { "find-cache-dir": "^3.3.1", "loader-utils": "^2.0.0", @@ -62427,7 +67376,6 @@ "dependencies": { "find-cache-dir": { "version": "3.3.1", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", "requires": { "commondir": "^1.0.1", "make-dir": "^3.0.2", @@ -62436,19 +67384,16 @@ }, "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3" }, "loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -62457,50 +67402,42 @@ }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { "p-locate": "^4.1.0" } }, "make-dir": { "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "requires": { "semver": "^6.0.0" } }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "requires": { "p-limit": "^2.2.0" } }, "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "version": "2.2.0" }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" }, "pkg-dir": { "version": "4.2.0", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "requires": { "find-up": "^4.0.0" } }, "schema-utils": { "version": "2.7.1", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", "requires": { "@types/json-schema": "^7.0.5", "ajv": "^6.12.4", @@ -62508,39 +67445,33 @@ } }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" } } }, "babel-plugin-add-react-displayname": { - "version": "0.0.5", - "integrity": "sha512-LY3+Y0XVDYcShHHorshrDbt4KFWL4bSeniCtl4SYZbask+Syngk1uMPCeN9+nSiZo6zX5s0RTq/J9Pnaaf/KHw==" + "version": "0.0.5" }, "babel-plugin-apply-mdx-type-prop": { "version": "1.6.22", - "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", "requires": { "@babel/helper-plugin-utils": "7.10.4", "@mdx-js/util": "1.6.22" }, "dependencies": { "@babel/helper-plugin-utils": { - "version": "7.10.4", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + "version": "7.10.4" } } }, "babel-plugin-dynamic-import-node": { "version": "2.3.3", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", "requires": { "object.assign": "^4.1.0" } }, "babel-plugin-emotion": { "version": "10.0.33", - "integrity": "sha512-bxZbTTGz0AJQDHm8k6Rf3RQJ8tX2scsfsRyKVgAbiUPUNIRtlK+7JxP+TAd1kRLABFxe0CFm2VdK4ePkoA9FxQ==", "requires": { "@babel/helper-module-imports": "^7.0.0", "@emotion/hash": "0.8.0", @@ -62556,20 +67487,17 @@ }, "babel-plugin-extract-import-names": { "version": "1.6.22", - "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", "requires": { "@babel/helper-plugin-utils": "7.10.4" }, "dependencies": { "@babel/helper-plugin-utils": { - "version": "7.10.4", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + "version": "7.10.4" } } }, "babel-plugin-istanbul": { "version": "6.0.0", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -62581,7 +67509,6 @@ }, "babel-plugin-jest-hoist": { "version": "26.6.2", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -62592,12 +67519,10 @@ }, "babel-plugin-jsx-remove-data-test-id": { "version": "2.1.3", - "integrity": "sha512-FTpcmzr3avLVStllCT4BceTTZNEb+1mJVtLpsicvXDqjojEkyrga1GGOxWj768Ra3tev6KWgNOhZ/Lrucb+MuQ==", "dev": true }, "babel-plugin-lodash": { "version": "3.3.4", - "integrity": "sha512-yDZLjK7TCkWl1gpBeBGmuaDIFhZKmkoL+Cu2MUUjv5VxUZx/z7tBGBCBcQs5RI1Bkz5LLmNdjx7paOyQtMovyg==", "requires": { "@babel/helper-module-imports": "^7.0.0-beta.49", "@babel/types": "^7.0.0-beta.49", @@ -62608,7 +67533,6 @@ }, "babel-plugin-macros": { "version": "2.8.0", - "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", "requires": { "@babel/runtime": "^7.7.2", "cosmiconfig": "^6.0.0", @@ -62617,7 +67541,6 @@ "dependencies": { "cosmiconfig": { "version": "6.0.0", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", "requires": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.1.0", @@ -62628,7 +67551,6 @@ }, "parse-json": { "version": "5.0.0", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -62637,32 +67559,26 @@ } }, "path-type": { - "version": "4.0.0", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "version": "4.0.0" } } }, "babel-plugin-named-asset-import": { - "version": "0.3.7", - "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==" + "version": "0.3.7" }, "babel-plugin-polyfill-corejs2": { - "version": "0.2.2", - "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", + "version": "0.3.2", "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.2", + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.2", "semver": "^6.1.1" }, "dependencies": { "@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.2", "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -62670,45 +67586,37 @@ } }, "debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", "requires": { "ms": "2.1.2" } }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" } } }, "babel-plugin-polyfill-corejs3": { "version": "0.1.7", - "integrity": "sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==", "requires": { "@babel/helper-define-polyfill-provider": "^0.1.5", "core-js-compat": "^3.8.1" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.2.2", - "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", + "version": "0.4.0", "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.2" + "@babel/helper-define-polyfill-provider": "^0.3.2" }, "dependencies": { "@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.2", "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -62716,25 +67624,21 @@ } }, "debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", "requires": { "ms": "2.1.2" } }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" } } }, "babel-plugin-react-docgen": { "version": "4.2.1", - "integrity": "sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==", "requires": { "ast-types": "^0.14.2", "lodash": "^4.17.15", @@ -62742,12 +67646,10 @@ } }, "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==" + "version": "6.18.0" }, "babel-plugin-typescript-to-proptypes": { "version": "2.0.0", - "integrity": "sha512-LmXrkeqg4bzq0CiCOV/zN3hrvAvJOvoP9sEw0YgtkU6lIbqA5/RAY0bA6C6+i5/e5Wp/taJ68XKp2i8pkU+Qmw==", "requires": { "@babel/helper-module-imports": "^7.12.5", "@babel/plugin-syntax-typescript": "^7.12.1", @@ -62756,7 +67658,6 @@ }, "babel-polyfill": { "version": "6.26.0", - "integrity": "sha512-F2rZGQnAdaHWQ8YAoeRbukc7HS9QgdgeyJ0rQDd485v9opwuPvjpPFcOOT/WmkKTdgy9ESgSPXDcTNpzrGr6iQ==", "dev": true, "requires": { "babel-runtime": "^6.26.0", @@ -62766,19 +67667,16 @@ "dependencies": { "core-js": { "version": "2.6.11", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", "dev": true }, "regenerator-runtime": { "version": "0.10.5", - "integrity": "sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==", "dev": true } } }, "babel-preset-current-node-syntax": { "version": "1.0.1", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, "requires": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -62797,7 +67695,6 @@ }, "babel-preset-jest": { "version": "26.6.2", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", "dev": true, "requires": { "babel-plugin-jest-hoist": "^26.6.2", @@ -62806,33 +67703,27 @@ }, "babel-runtime": { "version": "6.26.0", - "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" }, "dependencies": { "core-js": { - "version": "2.6.0", - "integrity": "sha512-kLRC6ncVpuEW/1kwrOXYX6KQASCVtrh1gQr/UiaVgFlf9WE5Vp+lNe5+h3LuMr5PAucWnnEXwH0nQHRH/gpGtw==" + "version": "2.6.0" }, "regenerator-runtime": { - "version": "0.11.1", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + "version": "0.11.1" } } }, "bail": { - "version": "1.0.5", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==" + "version": "1.0.5" }, "balanced-match": { - "version": "1.0.0", - "integrity": "sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==" + "version": "1.0.0" }, "base": { "version": "0.11.2", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "requires": { "cache-base": "^1.0.1", "class-utils": "^0.3.5", @@ -62845,28 +67736,24 @@ "dependencies": { "define-property": { "version": "1.0.0", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "requires": { "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { "version": "1.0.0", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -62874,22 +67761,18 @@ } }, "kind-of": { - "version": "6.0.2", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "version": "6.0.2" } } }, "base16": { - "version": "1.0.0", - "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" + "version": "1.0.0" }, "base64-js": { - "version": "1.5.1", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + "version": "1.5.1" }, "basic-auth": { "version": "2.0.1", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "dev": true, "requires": { "safe-buffer": "5.1.2" @@ -62897,58 +67780,46 @@ }, "batch": { "version": "0.6.1", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, "batch-processor": { - "version": "1.0.0", - "integrity": "sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==" + "version": "1.0.0" }, "bcrypt-pbkdf": { "version": "1.0.2", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, "requires": { "tweetnacl": "^0.14.3" } }, "before-after-hook": { - "version": "2.2.2", - "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", - "dev": true + "version": "2.2.2" }, "better-opn": { "version": "2.1.1", - "integrity": "sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==", "requires": { "open": "^7.0.3" } }, "big-integer": { - "version": "1.6.51", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" + "version": "1.6.51" }, "big.js": { - "version": "5.2.2", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + "version": "5.2.2" }, "bignumber.js": { - "version": "9.0.0", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + "version": "9.0.0" }, "binary-extensions": { "version": "1.13.1", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "optional": true }, "binaryextensions": { "version": "4.18.0", - "integrity": "sha512-PQu3Kyv9dM4FnwB7XGj1+HucW+ShvJzJqjuw1JkKVs1mWdwOKVcRjOi+pV9X52A0tNvrPCsPkbFFQb+wE1EAXw==", "dev": true }, "bl": { "version": "4.1.0", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "requires": { "buffer": "^5.5.0", @@ -62958,7 +67829,6 @@ "dependencies": { "buffer": { "version": "5.7.1", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "requires": { "base64-js": "^1.3.1", @@ -62967,12 +67837,10 @@ }, "inherits": { "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -62983,90 +67851,78 @@ } }, "bluebird": { - "version": "3.7.2", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + "version": "3.7.2" + }, + "bmpimagejs": { + "version": "1.0.4", + "dev": true }, "bn.js": { - "version": "5.2.0", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + "version": "5.2.0" }, "body-parser": { - "version": "1.19.0", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.2", "requires": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" }, "dependencies": { "bytes": { - "version": "3.1.0", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "version": "3.1.2" }, "http-errors": { - "version": "1.7.2", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", "requires": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" } }, + "inherits": { + "version": "2.0.4" + }, "qs": { - "version": "6.7.0", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "version": "6.9.7" }, "setprototypeof": { - "version": "1.1.1", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "statuses": { - "version": "1.5.0", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + "version": "1.2.0" } } }, - "bonjour": { - "version": "3.5.0", - "integrity": "sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==", + "bonjour-service": { + "version": "1.0.14", "dev": true, "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", + "array-flatten": "^2.1.2", "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" } }, "boolbase": { - "version": "1.0.0", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + "version": "1.0.0" }, "bootstrap": { - "version": "3.4.1", - "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" + "version": "3.4.1" }, "bootstrap-slider": { - "version": "10.4.0", - "integrity": "sha512-ONP9SGV17pr2l3RJHhoX+3qAUDF3ltByQD5rP7Dw2QytOYAL6JjRVOvyFKv/CR+Xq2T7hJtq3NZyDzfX9CZPFw==" + "version": "10.4.0" }, "bowser": { - "version": "1.9.4", - "integrity": "sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==" + "version": "1.9.4" }, "boxen": { "version": "5.1.2", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", "requires": { "ansi-align": "^3.0.0", "camelcase": "^6.2.0", @@ -63079,20 +67935,16 @@ }, "dependencies": { "ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "version": "5.0.1" }, "camelcase": { - "version": "6.3.0", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + "version": "6.3.0" }, "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "version": "3.0.0" }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -63101,18 +67953,15 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { "ansi-regex": "^5.0.1" } }, "type-fest": { - "version": "0.20.2", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + "version": "0.20.2" }, "wrap-ansi": { "version": "7.0.0", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -63122,12 +67971,10 @@ } }, "brace": { - "version": "0.11.1", - "integrity": "sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q==" + "version": "0.11.1" }, "brace-expansion": { "version": "1.1.11", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -63135,7 +67982,6 @@ }, "braces": { "version": "2.3.2", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", @@ -63151,7 +67997,6 @@ }, "brfs": { "version": "1.6.1", - "integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==", "requires": { "quote-stream": "^1.0.1", "resolve": "^1.1.5", @@ -63161,7 +68006,6 @@ }, "broadcast-channel": { "version": "4.10.0", - "integrity": "sha512-hOUh312XyHk6JTVyX9cyXaH1UYs+2gHVtnW16oQAu9FL7ALcXGXc/YoJWqlkV8vUn14URQPMmRi4A9q4UrwVEQ==", "requires": { "@babel/runtime": "^7.16.0", "detect-node": "^2.1.0", @@ -63174,17 +68018,14 @@ } }, "brorand": { - "version": "1.1.0", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + "version": "1.1.0" }, "browser-process-hrtime": { "version": "1.0.0", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, "browserify-aes": { "version": "1.2.0", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -63196,7 +68037,6 @@ }, "browserify-cipher": { "version": "1.0.1", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "requires": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -63205,7 +68045,6 @@ }, "browserify-des": { "version": "1.0.2", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "requires": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -63215,7 +68054,6 @@ }, "browserify-rsa": { "version": "4.1.0", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", "requires": { "bn.js": "^5.0.0", "randombytes": "^2.0.1" @@ -63223,7 +68061,6 @@ }, "browserify-sign": { "version": "4.2.1", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", "requires": { "bn.js": "^5.1.1", "browserify-rsa": "^4.0.1", @@ -63237,12 +68074,10 @@ }, "dependencies": { "inherits": { - "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "version": "2.0.4" }, "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -63250,32 +68085,27 @@ } }, "safe-buffer": { - "version": "5.2.1", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "version": "5.2.1" } } }, "browserify-zlib": { "version": "0.2.0", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "requires": { "pako": "~1.0.5" } }, "browserslist": { - "version": "4.17.0", - "integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==", + "version": "4.21.3", "requires": { - "caniuse-lite": "^1.0.30001254", - "colorette": "^1.3.0", - "electron-to-chromium": "^1.3.830", - "escalade": "^3.1.1", - "node-releases": "^1.1.75" + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.5" } }, "bser": { "version": "2.1.1", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, "requires": { "node-int64": "^0.4.0" @@ -63283,7 +68113,6 @@ }, "buffer": { "version": "4.9.2", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -63292,52 +68121,33 @@ }, "buffer-crc32": { "version": "0.2.13", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, "buffer-equal": { - "version": "0.0.1", - "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==" + "version": "0.0.1" }, "buffer-from": { - "version": "1.1.1", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "buffer-indexof": { - "version": "1.1.1", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true + "version": "1.1.1" }, "buffer-xor": { - "version": "1.0.3", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + "version": "1.0.3" }, "builtin-status-codes": { - "version": "3.0.0", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==" + "version": "3.0.0" }, "builtins": { "version": "1.0.3", - "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", - "dev": true - }, - "byline": { - "version": "5.0.0", - "integrity": "sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==", "dev": true }, "byte-size": { "version": "7.0.1", - "integrity": "sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A==", "dev": true }, "bytes": { - "version": "3.0.0", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + "version": "3.0.0" }, "c8": { "version": "7.9.0", - "integrity": "sha512-aQ7dC8gASnKdBwHUuYuzsdKCEDrKnWr7ZuZUnf4CNAL81oyKloKrs7H7zYvcrmCtIrMToudBSUhq2q+LLBMvgg==", "requires": { "@bcoe/v8-coverage": "^0.2.3", "@istanbuljs/schema": "^0.1.2", @@ -63354,12 +68164,10 @@ }, "dependencies": { "ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "version": "5.0.1" }, "cliui": { "version": "7.0.4", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -63368,48 +68176,40 @@ }, "find-up": { "version": "5.0.0", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "requires": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "version": "3.0.0" }, "locate-path": { "version": "6.0.0", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "requires": { "p-locate": "^5.0.0" } }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "requires": { "yocto-queue": "^0.1.0" } }, "p-locate": { "version": "5.0.0", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "requires": { "p-limit": "^3.0.2" } }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" }, "source-map": { - "version": "0.7.3", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + "version": "0.7.3" }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -63418,14 +68218,12 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { "ansi-regex": "^5.0.1" } }, "v8-to-istanbul": { "version": "8.1.0", - "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", "requires": { "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^1.6.0", @@ -63434,7 +68232,6 @@ }, "wrap-ansi": { "version": "7.0.0", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -63442,12 +68239,10 @@ } }, "y18n": { - "version": "5.0.8", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + "version": "5.0.8" }, "yargs": { "version": "16.2.0", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -63459,14 +68254,12 @@ } }, "yargs-parser": { - "version": "20.2.9", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + "version": "20.2.9" } } }, "cacache": { "version": "12.0.4", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", "requires": { "bluebird": "^3.5.5", "chownr": "^1.1.1", @@ -63487,7 +68280,6 @@ "dependencies": { "rimraf": { "version": "2.7.1", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" } @@ -63496,7 +68288,6 @@ }, "cache-base": { "version": "1.0.1", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "requires": { "collection-visit": "^1.0.0", "component-emitter": "^1.2.1", @@ -63511,45 +68302,37 @@ }, "call-bind": { "version": "1.0.2", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" } }, "call-me-maybe": { - "version": "1.0.1", - "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==" + "version": "1.0.1" }, "callsites": { - "version": "3.1.0", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + "version": "3.1.0" }, "camel-case": { "version": "4.1.2", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "requires": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" }, "dependencies": { "tslib": { - "version": "2.1.0", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + "version": "2.1.0" } } }, "camelcase": { - "version": "5.3.1", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "version": "5.3.1" }, "camelcase-css": { - "version": "2.0.1", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" + "version": "2.0.1" }, "camelcase-keys": { "version": "6.2.2", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, "requires": { "camelcase": "^5.3.1", @@ -63559,7 +68342,6 @@ }, "caniuse-api": { "version": "3.0.0", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -63569,90 +68351,63 @@ } }, "caniuse-lite": { - "version": "1.0.30001312", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==" + "version": "1.0.30001378" }, "capture-exit": { "version": "2.0.0", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", "dev": true, "requires": { "rsvp": "^4.8.4" } }, - "capture-stack-trace": { - "version": "1.0.1", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==" - }, - "cardinal": { - "version": "0.4.4", - "integrity": "sha512-3MxV0o9wOpQcobrcSrRpaSxlYkohCcZu0ytOjJUww/Yo/223q4Ecloo7odT+M0SI5kPgb1JhvSaF4EEuVXOLAQ==", - "requires": { - "ansicolors": "~0.2.1", - "redeyed": "~0.4.0" - } - }, "cartocolor": { "version": "4.0.2", - "integrity": "sha512-+Gh9mb6lFxsDOLQlBLPxAHCnWXlg2W8q3AcVwqRcy95TdBbcOU89Wrb6h2Hd/6Ww1Kc1pzXmUdpnWD+xeCG0dg==", "requires": { "colorbrewer": "1.0.0" } }, "case-sensitive-paths-webpack-plugin": { - "version": "2.4.0", - "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==" + "version": "2.4.0" }, "caseless": { "version": "0.12.0", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "ccount": { - "version": "1.1.0", - "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==" + "version": "1.1.0" }, "chalk": { "version": "4.1.2", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "change-emitter": { - "version": "0.1.6", - "integrity": "sha512-YXzt1cQ4a2jqazhcuSWEOc1K2q8g9H6eWNsyZgi640LDzRWVQ2eDe+Y/kVdftH+vYdPF2rgDb3dLdpxE1jvAxw==" + "version": "0.1.6" }, "char-regex": { "version": "1.0.2", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, "character-entities": { - "version": "1.2.2", - "integrity": "sha512-sMoHX6/nBiy3KKfC78dnEalnpn0Az0oSNvqUWYTtYrhRI5iUIYsROU48G+E+kMFQzqXaJ8kHJZ85n7y6/PHgwQ==" + "version": "1.2.2" }, "character-entities-legacy": { - "version": "1.1.2", - "integrity": "sha512-9NB2VbXtXYWdXzqrvAHykE/f0QJxzaKIpZ5QzNZrrgQ7Iyxr2vnfS8fCBNVW9nUEZE0lo57nxKRqnzY/dKrwlA==" + "version": "1.1.2" }, "character-reference-invalid": { - "version": "1.1.2", - "integrity": "sha512-7I/xceXfKyUJmSAn/jw8ve/9DyOP7XxufNYLI9Px7CmsKgEUaZLUTax6nZxGQtaoiZCjpu6cHPj20xC/vqRReQ==" + "version": "1.1.2" }, "chardet": { "version": "0.7.0", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "devOptional": true + "dev": true }, "charenc": { - "version": "0.0.2", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==" + "version": "0.0.2" }, "cheerio": { "version": "1.0.0-rc.3", - "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==", "dev": true, "requires": { "css-select": "~1.2.0", @@ -63665,7 +68420,6 @@ "dependencies": { "dom-serializer": { "version": "0.1.1", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", "dev": true, "requires": { "domelementtype": "^1.3.0", @@ -63675,8 +68429,7 @@ } }, "chokidar": { - "version": "3.5.2", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -63690,55 +68443,46 @@ "dependencies": { "anymatch": { "version": "3.1.2", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "binary-extensions": { - "version": "2.2.0", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + "version": "2.2.0" }, "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "requires": { "fill-range": "^7.0.1" } }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "requires": { "to-regex-range": "^5.0.1" } }, "is-binary-path": { "version": "2.1.0", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "requires": { "binary-extensions": "^2.0.0" } }, "is-number": { - "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "version": "7.0.0" }, "normalize-path": { - "version": "3.0.0", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "version": "3.0.0" }, "readdirp": { "version": "3.6.0", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "requires": { "picomatch": "^2.2.1" } }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "requires": { "is-number": "^7.0.0" } @@ -63746,282 +68490,34 @@ } }, "chownr": { - "version": "1.1.4", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + "version": "1.1.4" }, "chromatic": { - "version": "5.10.2", - "integrity": "sha512-JHFtZ16VanQX0X9qjacIJOrH9rVUJACilPs8dBwwQgJTZzgCZAdwgmE+WwLcxe/LuK7vM56BDTHbxC+XcnTsjw==", + "version": "6.7.4", "dev": true, "requires": { - "@actions/core": "^1.5.0", - "@actions/github": "^5.0.0", - "@babel/preset-typescript": "^7.15.0", - "@babel/runtime": "^7.15.3", - "@chromaui/localtunnel": "^2.0.3", - "async-retry": "^1.3.3", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "dotenv": "^8.2.0", - "env-ci": "^5.0.2", - "esm": "^3.2.25", - "execa": "^5.0.0", - "fake-tag": "^2.0.0", - "fs-extra": "^10.0.0", - "https-proxy-agent": "^5.0.0", - "jsonfile": "^6.0.1", - "junit-report-builder": "2.1.0", - "listr": "0.14.3", - "meow": "^8.0.0", - "no-proxy": "^1.0.3", - "node-ask": "^1.0.1", - "node-fetch": "2.6.0", - "node-loggly-bulk": "^2.2.4", - "p-limit": "3.1.0", - "picomatch": "2.2.2", - "pkg-up": "^3.1.0", - "pluralize": "^8.0.0", - "progress-stream": "^2.0.0", - "semver": "^7.3.5", - "slash": "^3.0.0", - "string-argv": "^0.3.1", - "strip-ansi": "6.0.0", - "tmp-promise": "3.0.2", - "tree-kill": "^1.2.2", - "ts-dedent": "^1.0.0", - "util-deprecate": "^1.0.2", - "uuid": "^8.3.2", - "yarn-or-npm": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "execa": { - "version": "5.1.1", - "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" - } - }, - "find-up": { - "version": "3.0.0", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "get-stream": { - "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "human-signals": { - "version": "2.1.0", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "locate-path": { - "version": "3.0.0", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node-fetch": { - "version": "2.6.0", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "3.0.0", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - } - } - }, - "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "picomatch": { - "version": "2.2.2", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true - }, - "pkg-up": { - "version": "3.1.0", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "ts-dedent": { - "version": "1.2.0", - "integrity": "sha512-6zSJp23uQI+Txyz5LlXMXAHpUhY4Hi0oluXny0OgIR7g/Cromq4vDBnhtbBdyIV34g0pgwxUvnvg+jLJe4c1NA==", - "dev": true - }, - "uuid": { - "version": "8.3.2", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - }, - "which": { - "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } + "@discoveryjs/json-ext": "^0.5.7", + "@types/webpack-env": "^1.17.0" } }, "chrome-trace-event": { "version": "1.0.2", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", "requires": { "tslib": "^1.9.0" } }, "chrono-node": { "version": "2.2.6", - "integrity": "sha512-ahgxpY4ihg3frV5t7pZYrS0Iap5MErTQ7whVNBxbiLjplc2HhGwj3zgr0dEnJos/FAuZVjrHoky8J9YiNc5ZKQ==", "requires": { "dayjs": "^1.10.0" } }, "ci-info": { "version": "2.0.0", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, "cipher-base": { "version": "1.0.4", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -64029,17 +68525,14 @@ }, "circular-json-es6": { "version": "2.0.2", - "integrity": "sha512-ODYONMMNb3p658Zv+Pp+/XPa5s6q7afhz3Tzyvo+VRh9WIrJ64J76ZC4GQxnlye/NesTn09jvOiuE8+xxfpwhQ==", "dev": true }, "cjs-module-lexer": { "version": "0.6.0", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", "dev": true }, "class-utils": { "version": "0.3.6", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "requires": { "arr-union": "^3.1.0", "define-property": "^0.2.5", @@ -64049,7 +68542,6 @@ "dependencies": { "define-property": { "version": "0.2.5", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -64057,87 +68549,51 @@ } }, "classnames": { - "version": "2.2.6", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + "version": "2.3.2" }, "clean-css": { "version": "4.2.3", - "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", "requires": { "source-map": "~0.6.0" }, "dependencies": { "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } }, "clean-stack": { - "version": "2.2.0", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + "version": "2.2.0" }, "cli-boxes": { - "version": "2.2.1", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" + "version": "2.2.1" }, "cli-cursor": { "version": "3.1.0", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "devOptional": true, + "dev": true, "requires": { "restore-cursor": "^3.1.0" } }, "cli-spinners": { "version": "2.6.1", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", "dev": true }, - "cli-table": { - "version": "0.3.9", - "integrity": "sha512-7eA6hFtAZwVx3dWAGoaBqTrzWko5jRUFKpHT64ZHkJpaA3y5wf5NlLjguqTRmqycatJZiwftODYYyGNLbQ7MuA==", - "requires": { - "colors": "1.0.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "colors": { - "version": "1.0.3", - "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==" - }, - "strip-ansi": { - "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, "cli-table3": { "version": "0.6.1", - "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", "requires": { "colors": "1.4.0", "string-width": "^4.2.0" }, "dependencies": { "ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "version": "5.0.1" }, "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "version": "3.0.0" }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -64146,7 +68602,6 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { "ansi-regex": "^5.0.1" } @@ -64155,12 +68610,10 @@ }, "cli-width": { "version": "3.0.0", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "devOptional": true + "dev": true }, "cliui": { "version": "6.0.0", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -64168,16 +68621,13 @@ }, "dependencies": { "ansi-regex": { - "version": "5.0.0", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.0" }, "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "version": "3.0.0" }, "string-width": { "version": "4.2.0", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -64186,24 +68636,14 @@ }, "strip-ansi": { "version": "6.0.0", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "requires": { "ansi-regex": "^5.0.0" } } } }, - "clone": { - "version": "2.1.2", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" - }, - "clone-buffer": { - "version": "1.0.0", - "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==" - }, "clone-deep": { "version": "4.0.1", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "requires": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -64211,39 +68651,16 @@ }, "dependencies": { "kind-of": { - "version": "6.0.3", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "version": "6.0.3" } } }, - "clone-stats": { - "version": "1.0.0", - "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==" - }, - "cloneable-readable": { - "version": "1.1.3", - "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", - "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" - } - }, - "cmd-shim": { - "version": "4.1.0", - "integrity": "sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw==", - "dev": true, - "requires": { - "mkdirp-infer-owner": "^2.0.0" - } - }, "co": { "version": "4.6.0", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==" + "dev": true }, "coa": { "version": "2.0.2", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", "dev": true, "requires": { "@types/q": "^1.5.1", @@ -64253,7 +68670,6 @@ "dependencies": { "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -64261,7 +68677,6 @@ }, "chalk": { "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -64271,7 +68686,6 @@ }, "supports-color": { "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -64280,85 +68694,98 @@ } }, "code-point-at": { - "version": "1.1.0", - "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==" + "version": "1.1.0" }, "collapse-white-space": { - "version": "1.0.6", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==" + "version": "1.0.6" }, "collect-v8-coverage": { "version": "1.0.1", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", "dev": true }, "collection-visit": { "version": "1.0.0", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "requires": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" } }, + "color": { + "version": "3.2.1", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "color-convert": { "version": "1.9.3", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "requires": { "color-name": "1.1.3" } }, "color-name": { - "version": "1.1.3", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "version": "1.1.3" + }, + "color-string": { + "version": "1.9.1", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } }, "color-support": { - "version": "1.1.3", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + "version": "1.1.3" }, "colorbrewer": { - "version": "1.0.0", - "integrity": "sha512-NZuIOVdErK/C6jDH3jWT/roxWJbJAinMiqEpbuWniKvQAoWdg6lGra3pPrSHvaIf8PlX8wLs/RAC6nULFJbgmg==" + "version": "1.0.0" }, "colord": { "version": "2.7.0", - "integrity": "sha512-pZJBqsHz+pYyw3zpX6ZRXWoCHM1/cvFikY9TV8G3zcejCaKE0lhankoj8iScyrrePA8C7yJ5FStfA9zbcOnw7Q==", "dev": true }, "colorette": { "version": "1.4.0", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==" + "dev": true }, "colors": { "version": "1.4.0", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "optional": true }, "columnify": { - "version": "1.5.4", - "integrity": "sha512-rFl+iXVT1nhLQPfGDw+3WcS8rmm7XsLKUmhsGE3ihzzpIikeGrTaZPIRKYWeLsLBypsHzjXIvYEltVUZS84XxQ==", + "version": "1.6.0", "dev": true, "requires": { - "strip-ansi": "^3.0.0", + "strip-ansi": "^6.0.1", "wcwidth": "^1.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } } }, "combined-stream": { "version": "1.0.8", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "requires": { "delayed-stream": "~1.0.0" } }, "comma-separated-tokens": { "version": "1.0.5", - "integrity": "sha512-Cg90/fcK93n0ecgYTAz1jaA3zvnQ0ExlmKY1rdbyHqAx6BHxwoJc+J7HDu0iuQ7ixEs1qaa+WyQ6oeuBpYP1iA==", "requires": { "trim": "0.0.1" } }, "command-line-args": { "version": "5.1.1", - "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", "requires": { "array-back": "^3.0.1", "find-replace": "^3.0.0", @@ -64368,7 +68795,6 @@ }, "command-line-usage": { "version": "6.1.1", - "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", "requires": { "array-back": "^4.0.1", "chalk": "^2.4.2", @@ -64378,18 +68804,15 @@ "dependencies": { "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { "color-convert": "^1.9.0" } }, "array-back": { - "version": "4.0.2", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + "version": "4.0.2" }, "chalk": { "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -64398,32 +68821,30 @@ }, "supports-color": { "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { "has-flag": "^3.0.0" } }, "typical": { - "version": "5.2.0", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + "version": "5.2.0" } } }, "commander": { - "version": "2.20.3", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "version": "2.20.3" + }, + "common-ancestor-path": { + "version": "1.0.1", + "dev": true }, "common-path-prefix": { - "version": "3.0.0", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + "version": "3.0.0" }, "commondir": { - "version": "1.0.1", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + "version": "1.0.1" }, "compare-func": { "version": "2.0.0", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", "dev": true, "requires": { "array-ify": "^1.0.0", @@ -64432,7 +68853,6 @@ "dependencies": { "dot-prop": { "version": "5.3.0", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, "requires": { "is-obj": "^2.0.0" @@ -64441,19 +68861,16 @@ } }, "component-emitter": { - "version": "1.2.1", - "integrity": "sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA==" + "version": "1.2.1" }, "compressible": { "version": "2.0.18", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "requires": { "mime-db": ">= 1.43.0 < 2" } }, "compression": { "version": "1.7.4", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "requires": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -64465,16 +68882,13 @@ } }, "compute-scroll-into-view": { - "version": "1.0.17", - "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==" + "version": "1.0.17" }, "concat-map": { - "version": "0.0.1", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "version": "0.0.1" }, "concat-stream": { "version": "1.6.2", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -64484,7 +68898,6 @@ }, "config-chain": { "version": "1.1.13", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -64492,40 +68905,37 @@ }, "confusing-browser-globals": { "version": "1.0.10", - "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", "dev": true }, "connect-history-api-fallback": { - "version": "1.6.0", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "version": "2.0.0", "dev": true }, "console-browserify": { - "version": "1.2.0", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + "version": "1.2.0" }, "console-control-strings": { - "version": "1.1.0", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + "version": "1.1.0" }, "constants-browserify": { - "version": "1.0.0", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==" + "version": "1.0.0" }, "content-disposition": { - "version": "0.5.3", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1" + } } }, "content-type": { - "version": "1.0.4", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + "version": "1.0.4" }, "conventional-changelog-angular": { "version": "5.0.13", - "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", "dev": true, "requires": { "compare-func": "^2.0.0", @@ -64534,7 +68944,6 @@ }, "conventional-changelog-core": { "version": "4.2.4", - "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==", "dev": true, "requires": { "add-stream": "^1.0.0", @@ -64555,7 +68964,6 @@ "dependencies": { "hosted-git-info": { "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -64563,7 +68971,6 @@ }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -64571,7 +68978,6 @@ }, "normalize-package-data": { "version": "3.0.3", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, "requires": { "hosted-git-info": "^4.0.1", @@ -64582,7 +68988,6 @@ }, "read-pkg": { "version": "3.0.0", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, "requires": { "load-json-file": "^4.0.0", @@ -64592,12 +68997,10 @@ "dependencies": { "hosted-git-info": { "version": "2.8.9", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "normalize-package-data": { "version": "2.5.0", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", @@ -64608,14 +69011,12 @@ }, "semver": { "version": "5.7.1", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } }, "read-pkg-up": { "version": "3.0.0", - "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", "dev": true, "requires": { "find-up": "^2.0.0", @@ -64624,7 +69025,6 @@ }, "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -64633,8 +69033,7 @@ } }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -64642,7 +69041,6 @@ }, "through2": { "version": "4.0.2", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, "requires": { "readable-stream": "3" @@ -64650,19 +69048,16 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "conventional-changelog-preset-loader": { "version": "2.3.4", - "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", "dev": true }, "conventional-changelog-writer": { "version": "5.0.1", - "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==", "dev": true, "requires": { "conventional-commits-filter": "^2.0.7", @@ -64678,7 +69073,6 @@ "dependencies": { "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -64688,20 +69082,10 @@ }, "semver": { "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, - "split": { - "version": "1.0.1", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "requires": { - "through": "2" - } - }, "through2": { "version": "4.0.2", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, "requires": { "readable-stream": "3" @@ -64711,7 +69095,6 @@ }, "conventional-commits-filter": { "version": "2.0.7", - "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", "dev": true, "requires": { "lodash.ismatch": "^4.4.0", @@ -64720,7 +69103,6 @@ }, "conventional-commits-parser": { "version": "3.2.4", - "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", "dev": true, "requires": { "is-text-path": "^1.0.1", @@ -64733,7 +69115,6 @@ "dependencies": { "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -64743,7 +69124,6 @@ }, "through2": { "version": "4.0.2", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, "requires": { "readable-stream": "3" @@ -64753,7 +69133,6 @@ }, "conventional-recommended-bump": { "version": "6.1.0", - "integrity": "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw==", "dev": true, "requires": { "concat-stream": "^2.0.0", @@ -64768,7 +69147,6 @@ "dependencies": { "concat-stream": { "version": "2.0.0", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -64779,7 +69157,6 @@ }, "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -64791,18 +69168,16 @@ }, "convert-source-map": { "version": "1.8.0", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "requires": { "safe-buffer": "~5.1.1" } }, "cookie": { "version": "0.4.0", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + "dev": true }, "cookie-parser": { "version": "1.4.5", - "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", "dev": true, "requires": { "cookie": "0.4.0", @@ -64810,12 +69185,10 @@ } }, "cookie-signature": { - "version": "1.0.6", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "version": "1.0.6" }, "copy-concurrently": { "version": "1.0.5", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "requires": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", @@ -64827,7 +69200,6 @@ "dependencies": { "rimraf": { "version": "2.7.1", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" } @@ -64835,19 +69207,16 @@ } }, "copy-descriptor": { - "version": "0.1.1", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" + "version": "0.1.1" }, "copy-to-clipboard": { "version": "3.3.1", - "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==", "requires": { "toggle-selection": "^1.0.6" } }, "copy-webpack-plugin": { "version": "9.0.1", - "integrity": "sha512-14gHKKdYIxF84jCEgPgYXCPpldbwpxxLbCmA7LReY7gvbaT555DgeBWBgBZM116tv/fO6RRJrsivBqRyRlukhw==", "dev": true, "requires": { "fast-glob": "^3.2.5", @@ -64861,7 +69230,6 @@ "dependencies": { "glob-parent": { "version": "6.0.1", - "integrity": "sha512-kEVjS71mQazDBHKcsq4E9u/vUzaLcw1A8EtUeydawvIWQCJM0qQ08G1H7/XTjFUulla6XQiDOG6MXSaG0HDKog==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -64869,12 +69237,10 @@ }, "normalize-path": { "version": "3.0.0", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { "yocto-queue": "^0.1.0" @@ -64882,7 +69248,6 @@ }, "serialize-javascript": { "version": "6.0.0", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -64891,53 +69256,28 @@ } }, "core-js": { - "version": "3.18.1", - "integrity": "sha512-vJlUi/7YdlCZeL6fXvWNaLUPh/id12WXj3MbkMw5uOyF0PfWPBNOCNbs53YqgrvtujLNlt9JQpruyIKkUZ+PKA==" + "version": "3.24.1" }, "core-js-compat": { - "version": "3.18.1", - "integrity": "sha512-XJMYx58zo4W0kLPmIingVZA10+7TuKrMLPt83+EzDmxFJQUMcTVVmQ+n5JP4r6Z14qSzhQBRi3NSWoeVyKKXUg==", + "version": "3.24.1", "requires": { - "browserslist": "^4.17.1", + "browserslist": "^4.21.3", "semver": "7.0.0" }, "dependencies": { - "browserslist": { - "version": "4.17.1", - "integrity": "sha512-aLD0ZMDSnF4lUt4ZDNgqi5BUn9BZ7YdQdI/cYlILrhdSSZJLU9aNZoD5/NBmM4SK34APB2e83MOsRt1EnkuyaQ==", - "requires": { - "caniuse-lite": "^1.0.30001259", - "electron-to-chromium": "^1.3.846", - "escalade": "^3.1.1", - "nanocolors": "^0.1.5", - "node-releases": "^1.1.76" - } - }, - "electron-to-chromium": { - "version": "1.3.853", - "integrity": "sha512-W4U8n+U8I5/SUaFcqZgbKRmYZwcyEIQVBDf+j5QQK6xChjXnQD+wj248eGR9X4u+dDmDR//8vIfbu4PrdBBIoQ==" - }, - "node-releases": { - "version": "1.1.76", - "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==" - }, "semver": { - "version": "7.0.0", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + "version": "7.0.0" } } }, "core-js-pure": { - "version": "3.19.1", - "integrity": "sha512-Q0Knr8Es84vtv62ei6/6jXH/7izKmOrtrxH9WJTHLCMAVeU+8TF8z8Nr08CsH4Ot0oJKzBzJJL9SJBYIv7WlfQ==" + "version": "3.19.1" }, "core-util-is": { - "version": "1.0.2", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + "version": "1.0.2" }, "cors": { "version": "2.8.5", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, "requires": { "object-assign": "^4", @@ -64946,7 +69286,6 @@ }, "cosmiconfig": { "version": "7.0.1", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", "requires": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -64957,7 +69296,6 @@ "dependencies": { "parse-json": { "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -64966,14 +69304,12 @@ } }, "path-type": { - "version": "4.0.0", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "version": "4.0.0" } } }, "cp-file": { "version": "7.0.0", - "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==", "requires": { "graceful-fs": "^4.1.2", "make-dir": "^3.0.0", @@ -64983,20 +69319,17 @@ "dependencies": { "make-dir": { "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "requires": { "semver": "^6.0.0" } }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" } } }, "cpy": { "version": "8.1.2", - "integrity": "sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==", "requires": { "arrify": "^2.0.1", "cp-file": "^7.0.0", @@ -65010,30 +69343,25 @@ }, "dependencies": { "@nodelib/fs.stat": { - "version": "1.1.3", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" + "version": "1.1.3" }, "array-union": { "version": "1.0.2", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", "requires": { "array-uniq": "^1.0.1" } }, "arrify": { - "version": "2.0.1", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + "version": "2.0.1" }, "dir-glob": { "version": "2.2.2", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", "requires": { "path-type": "^3.0.0" } }, "fast-glob": { "version": "2.2.7", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", "requires": { "@mrmlnc/readdir-enhanced": "^2.2.1", "@nodelib/fs.stat": "^1.1.2", @@ -65045,7 +69373,6 @@ }, "glob-parent": { "version": "3.1.0", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", "requires": { "is-glob": "^3.1.0", "path-dirname": "^1.0.0" @@ -65053,7 +69380,6 @@ "dependencies": { "is-glob": { "version": "3.1.0", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "requires": { "is-extglob": "^2.1.0" } @@ -65062,7 +69388,6 @@ }, "globby": { "version": "9.2.0", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", "requires": { "@types/glob": "^7.1.1", "array-union": "^1.0.2", @@ -65076,41 +69401,49 @@ }, "p-map": { "version": "3.0.0", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", "requires": { "aggregate-error": "^3.0.0" } }, "pify": { - "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "version": "4.0.1" } } }, "create-ecdh": { "version": "4.0.4", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "requires": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" }, "dependencies": { "bn.js": { - "version": "4.12.0", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.0" } } }, - "create-error-class": { - "version": "3.0.2", - "integrity": "sha512-gYTKKexFO3kh200H1Nit76sRwRtOY32vQd3jpAQKpLtZqyNsSQNfI4N7o3eP2wUjV35pTWKRYqFUDBvUha/Pkw==", + "create-emotion": { + "version": "10.0.27", "requires": { - "capture-stack-trace": "^1.0.0" + "@emotion/cache": "^10.0.27", + "@emotion/serialize": "^0.11.15", + "@emotion/sheet": "0.9.4", + "@emotion/utils": "0.11.3" + }, + "dependencies": { + "@emotion/cache": { + "version": "10.0.29", + "requires": { + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" + } + } } }, "create-hash": { "version": "1.2.0", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -65121,7 +69454,6 @@ }, "create-hmac": { "version": "1.1.7", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -65133,7 +69465,6 @@ }, "cross-env": { "version": "5.2.0", - "integrity": "sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==", "dev": true, "requires": { "cross-spawn": "^6.0.5", @@ -65142,7 +69473,7 @@ }, "cross-spawn": { "version": "6.0.5", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -65152,12 +69483,10 @@ } }, "crypt": { - "version": "0.0.2", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==" + "version": "0.0.2" }, "crypto-browserify": { "version": "3.12.0", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "requires": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", @@ -65174,7 +69503,6 @@ }, "css": { "version": "3.0.0", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", "dev": true, "requires": { "inherits": "^2.0.4", @@ -65184,17 +69512,14 @@ "dependencies": { "inherits": { "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "source-map-resolve": { "version": "0.6.0", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", "dev": true, "requires": { "atob": "^2.1.2", @@ -65205,7 +69530,6 @@ }, "css-in-js-utils": { "version": "2.0.1", - "integrity": "sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA==", "requires": { "hyphenate-style-name": "^1.0.2", "isobject": "^3.0.1" @@ -65213,7 +69537,6 @@ }, "css-loader": { "version": "6.5.1", - "integrity": "sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ==", "dev": true, "requires": { "icss-utils": "^5.1.0", @@ -65228,7 +69551,6 @@ "dependencies": { "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -65236,7 +69558,6 @@ }, "semver": { "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -65244,14 +69565,12 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "css-minimizer-webpack-plugin": { "version": "3.0.2", - "integrity": "sha512-B3I5e17RwvKPJwsxjjWcdgpU/zqylzK1bPVghcmpFHRL48DXiBgrtqz1BJsn68+t/zzaLp9kYAaEDvQ7GyanFQ==", "dev": true, "requires": { "cssnano": "^5.0.6", @@ -65265,17 +69584,14 @@ "dependencies": { "commander": { "version": "7.2.0", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true }, "css-color-names": { "version": "1.0.1", - "integrity": "sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA==", "dev": true }, "css-declaration-sorter": { "version": "6.1.3", - "integrity": "sha512-SvjQjNRZgh4ULK1LDJ2AduPKUKxIqmtU7ZAyi47BTV+M90Qvxr9AB6lKlLbDUfXqI9IQeYA8LbAsCZPpJEV3aA==", "dev": true, "requires": { "timsort": "^0.3.0" @@ -65283,7 +69599,6 @@ }, "css-select": { "version": "4.1.3", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", "dev": true, "requires": { "boolbase": "^1.0.0", @@ -65295,7 +69610,6 @@ }, "css-tree": { "version": "1.1.3", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", "dev": true, "requires": { "mdn-data": "2.0.14", @@ -65303,13 +69617,11 @@ } }, "css-what": { - "version": "5.0.1", - "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", + "version": "5.1.0", "dev": true }, "cssnano": { "version": "5.0.8", - "integrity": "sha512-Lda7geZU0Yu+RZi2SGpjYuQz4HI4/1Y+BhdD0jL7NXAQ5larCzVn+PUGuZbDMYz904AXXCOgO5L1teSvgu7aFg==", "dev": true, "requires": { "cssnano-preset-default": "^5.1.4", @@ -65320,7 +69632,6 @@ }, "cssnano-preset-default": { "version": "5.1.4", - "integrity": "sha512-sPpQNDQBI3R/QsYxQvfB4mXeEcWuw0wGtKtmS5eg8wudyStYMgKOQT39G07EbW1LB56AOYrinRS9f0ig4Y3MhQ==", "dev": true, "requires": { "css-declaration-sorter": "^6.0.3", @@ -65356,7 +69667,6 @@ }, "dom-serializer": { "version": "1.3.2", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", "dev": true, "requires": { "domelementtype": "^2.0.1", @@ -65366,12 +69676,10 @@ }, "domelementtype": { "version": "2.2.0", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", "dev": true }, "domhandler": { "version": "4.2.2", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", "dev": true, "requires": { "domelementtype": "^2.2.0" @@ -65379,7 +69687,6 @@ }, "domutils": { "version": "2.8.0", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, "requires": { "dom-serializer": "^1.0.1", @@ -65389,17 +69696,14 @@ }, "entities": { "version": "2.2.0", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true }, "has-flag": { "version": "4.0.0", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "jest-worker": { "version": "27.2.0", - "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", "dev": true, "requires": { "@types/node": "*", @@ -65409,7 +69713,6 @@ }, "nth-check": { "version": "2.0.0", - "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", "dev": true, "requires": { "boolbase": "^1.0.0" @@ -65417,7 +69720,6 @@ }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { "yocto-queue": "^0.1.0" @@ -65425,7 +69727,6 @@ }, "postcss-calc": { "version": "8.0.0", - "integrity": "sha512-5NglwDrcbiy8XXfPM11F3HeC6hoT9W7GUH/Zi5U/p7u3Irv4rHhdDcIZwG0llHXV4ftsBjpfWMXAnXNl4lnt8g==", "dev": true, "requires": { "postcss-selector-parser": "^6.0.2", @@ -65434,7 +69735,6 @@ }, "postcss-colormin": { "version": "5.2.0", - "integrity": "sha512-+HC6GfWU3upe5/mqmxuqYZ9B2Wl4lcoUUNkoaX59nEWV4EtADCMiBqui111Bu8R8IvaZTmqmxrqOAqjbHIwXPw==", "dev": true, "requires": { "browserslist": "^4.16.6", @@ -65445,7 +69745,6 @@ }, "postcss-convert-values": { "version": "5.0.1", - "integrity": "sha512-C3zR1Do2BkKkCgC0g3sF8TS0koF2G+mN8xxayZx3f10cIRmTaAnpgpRQZjNekTZxM2ciSPoh2IWJm0VZx8NoQg==", "dev": true, "requires": { "postcss-value-parser": "^4.1.0" @@ -65453,27 +69752,22 @@ }, "postcss-discard-comments": { "version": "5.0.1", - "integrity": "sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg==", "dev": true }, "postcss-discard-duplicates": { "version": "5.0.1", - "integrity": "sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA==", "dev": true }, "postcss-discard-empty": { "version": "5.0.1", - "integrity": "sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw==", "dev": true }, "postcss-discard-overridden": { "version": "5.0.1", - "integrity": "sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q==", "dev": true }, "postcss-merge-longhand": { "version": "5.0.2", - "integrity": "sha512-BMlg9AXSI5G9TBT0Lo/H3PfUy63P84rVz3BjCFE9e9Y9RXQZD3+h3YO1kgTNsNJy7bBc1YQp8DmSnwLIW5VPcw==", "dev": true, "requires": { "css-color-names": "^1.0.1", @@ -65483,7 +69777,6 @@ }, "postcss-merge-rules": { "version": "5.0.2", - "integrity": "sha512-5K+Md7S3GwBewfB4rjDeol6V/RZ8S+v4B66Zk2gChRqLTCC8yjnHQ601omj9TKftS19OPGqZ/XzoqpzNQQLwbg==", "dev": true, "requires": { "browserslist": "^4.16.6", @@ -65495,7 +69788,6 @@ }, "postcss-minify-font-values": { "version": "5.0.1", - "integrity": "sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA==", "dev": true, "requires": { "postcss-value-parser": "^4.1.0" @@ -65503,7 +69795,6 @@ }, "postcss-minify-gradients": { "version": "5.0.2", - "integrity": "sha512-7Do9JP+wqSD6Prittitt2zDLrfzP9pqKs2EcLX7HJYxsxCOwrrcLt4x/ctQTsiOw+/8HYotAoqNkrzItL19SdQ==", "dev": true, "requires": { "colord": "^2.6", @@ -65513,7 +69804,6 @@ }, "postcss-minify-params": { "version": "5.0.1", - "integrity": "sha512-4RUC4k2A/Q9mGco1Z8ODc7h+A0z7L7X2ypO1B6V8057eVK6mZ6xwz6QN64nHuHLbqbclkX1wyzRnIrdZehTEHw==", "dev": true, "requires": { "alphanum-sort": "^1.0.2", @@ -65525,7 +69815,6 @@ }, "postcss-minify-selectors": { "version": "5.1.0", - "integrity": "sha512-NzGBXDa7aPsAcijXZeagnJBKBPMYLaJJzB8CQh6ncvyl2sIndLVWfbcDi0SBjRWk5VqEjXvf8tYwzoKf4Z07og==", "dev": true, "requires": { "alphanum-sort": "^1.0.2", @@ -65534,12 +69823,10 @@ }, "postcss-normalize-charset": { "version": "5.0.1", - "integrity": "sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg==", "dev": true }, "postcss-normalize-display-values": { "version": "5.0.1", - "integrity": "sha512-uupdvWk88kLDXi5HEyI9IaAJTE3/Djbcrqq8YgjvAVuzgVuqIk3SuJWUisT2gaJbZm1H9g5k2w1xXilM3x8DjQ==", "dev": true, "requires": { "cssnano-utils": "^2.0.1", @@ -65548,7 +69835,6 @@ }, "postcss-normalize-positions": { "version": "5.0.1", - "integrity": "sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg==", "dev": true, "requires": { "postcss-value-parser": "^4.1.0" @@ -65556,7 +69842,6 @@ }, "postcss-normalize-repeat-style": { "version": "5.0.1", - "integrity": "sha512-syZ2itq0HTQjj4QtXZOeefomckiV5TaUO6ReIEabCh3wgDs4Mr01pkif0MeVwKyU/LHEkPJnpwFKRxqWA/7O3w==", "dev": true, "requires": { "cssnano-utils": "^2.0.1", @@ -65565,7 +69850,6 @@ }, "postcss-normalize-string": { "version": "5.0.1", - "integrity": "sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA==", "dev": true, "requires": { "postcss-value-parser": "^4.1.0" @@ -65573,7 +69857,6 @@ }, "postcss-normalize-timing-functions": { "version": "5.0.1", - "integrity": "sha512-cPcBdVN5OsWCNEo5hiXfLUnXfTGtSFiBU9SK8k7ii8UD7OLuznzgNRYkLZow11BkQiiqMcgPyh4ZqXEEUrtQ1Q==", "dev": true, "requires": { "cssnano-utils": "^2.0.1", @@ -65582,7 +69865,6 @@ }, "postcss-normalize-unicode": { "version": "5.0.1", - "integrity": "sha512-kAtYD6V3pK0beqrU90gpCQB7g6AOfP/2KIPCVBKJM2EheVsBQmx/Iof+9zR9NFKLAx4Pr9mDhogB27pmn354nA==", "dev": true, "requires": { "browserslist": "^4.16.0", @@ -65591,7 +69873,6 @@ }, "postcss-normalize-url": { "version": "5.0.2", - "integrity": "sha512-k4jLTPUxREQ5bpajFQZpx8bCF2UrlqOTzP9kEqcEnOfwsRshWs2+oAFIHfDQB8GO2PaUaSE0NlTAYtbluZTlHQ==", "dev": true, "requires": { "is-absolute-url": "^3.0.3", @@ -65601,7 +69882,6 @@ }, "postcss-normalize-whitespace": { "version": "5.0.1", - "integrity": "sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA==", "dev": true, "requires": { "postcss-value-parser": "^4.1.0" @@ -65609,7 +69889,6 @@ }, "postcss-ordered-values": { "version": "5.0.2", - "integrity": "sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ==", "dev": true, "requires": { "cssnano-utils": "^2.0.1", @@ -65618,7 +69897,6 @@ }, "postcss-reduce-initial": { "version": "5.0.1", - "integrity": "sha512-zlCZPKLLTMAqA3ZWH57HlbCjkD55LX9dsRyxlls+wfuRfqCi5mSlZVan0heX5cHr154Dq9AfbH70LyhrSAezJw==", "dev": true, "requires": { "browserslist": "^4.16.0", @@ -65627,7 +69905,6 @@ }, "postcss-reduce-transforms": { "version": "5.0.1", - "integrity": "sha512-a//FjoPeFkRuAguPscTVmRQUODP+f3ke2HqFNgGPwdYnpeC29RZdCBvGRGTsKpMURb/I3p6jdKoBQ2zI+9Q7kA==", "dev": true, "requires": { "cssnano-utils": "^2.0.1", @@ -65636,7 +69913,6 @@ }, "postcss-svgo": { "version": "5.0.2", - "integrity": "sha512-YzQuFLZu3U3aheizD+B1joQ94vzPfE6BNUcSYuceNxlVnKKsOtdo6hL9/zyC168Q8EwfLSgaDSalsUGa9f2C0A==", "dev": true, "requires": { "postcss-value-parser": "^4.1.0", @@ -65645,7 +69921,6 @@ }, "postcss-unique-selectors": { "version": "5.0.1", - "integrity": "sha512-gwi1NhHV4FMmPn+qwBNuot1sG1t2OmacLQ/AX29lzyggnjd+MnVD5uqQmpXO3J17KGL2WAxQruj1qTd3H0gG/w==", "dev": true, "requires": { "alphanum-sort": "^1.0.2", @@ -65655,7 +69930,6 @@ }, "serialize-javascript": { "version": "6.0.0", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -65663,12 +69937,10 @@ }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "stylehacks": { "version": "5.0.1", - "integrity": "sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA==", "dev": true, "requires": { "browserslist": "^4.16.0", @@ -65677,7 +69949,6 @@ }, "supports-color": { "version": "8.1.1", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -65685,7 +69956,6 @@ }, "svgo": { "version": "2.5.0", - "integrity": "sha512-FSdBOOo271VyF/qZnOn1PgwCdt1v4Dx0Sey+U1jgqm1vqRYjPGdip0RGrFW6ItwtkBB8rHgHk26dlVr0uCs82Q==", "dev": true, "requires": { "@trysound/sax": "0.1.1", @@ -65701,7 +69971,6 @@ }, "css-select": { "version": "1.2.0", - "integrity": "sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==", "dev": true, "requires": { "boolbase": "~1.0.0", @@ -65712,12 +69981,10 @@ }, "css-select-base-adapter": { "version": "0.1.1", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", "dev": true }, "css-tree": { "version": "1.0.0-alpha.37", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", "dev": true, "requires": { "mdn-data": "2.0.4", @@ -65726,46 +69993,37 @@ "dependencies": { "mdn-data": { "version": "2.0.4", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", "dev": true }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, "css-what": { - "version": "2.1.2", - "integrity": "sha512-wan8dMWQ0GUeF7DGEPVjhHemVW/vy6xUYmFzRY8RYqgA0JtXC9rJmbScBjqSu6dg9q0lwPQy6ZAmJVr3PPTvqQ==", + "version": "2.1.3", "dev": true }, "css.escape": { "version": "1.5.1", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", "dev": true }, "csscolorparser": { - "version": "1.0.3", - "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==" + "version": "1.0.3" }, "cssesc": { - "version": "3.0.0", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + "version": "3.0.0" }, "cssfilter": { - "version": "0.0.10", - "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==" + "version": "0.0.10" }, "cssnano-utils": { "version": "2.0.1", - "integrity": "sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ==", "dev": true }, "csso": { "version": "4.2.0", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", "dev": true, "requires": { "css-tree": "^1.1.2" @@ -65773,7 +70031,6 @@ "dependencies": { "css-tree": { "version": "1.1.3", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", "dev": true, "requires": { "mdn-data": "2.0.14", @@ -65782,19 +70039,16 @@ }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, "cssom": { - "version": "0.4.4", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "version": "0.5.0", "dev": true }, "cssstyle": { "version": "2.3.0", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, "requires": { "cssom": "~0.3.6" @@ -65802,49 +70056,42 @@ "dependencies": { "cssom": { "version": "0.3.8", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true } } }, "csstype": { - "version": "2.6.9", - "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==" + "version": "2.6.9" + }, + "currencyformatter.js": { + "version": "2.2.0" }, "cyclist": { - "version": "1.0.1", - "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==" + "version": "1.0.1" }, "d3": { - "version": "3.5.17", - "integrity": "sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==" + "version": "3.5.17" }, "d3-array": { - "version": "1.2.4", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" + "version": "1.2.4" }, "d3-cloud": { "version": "1.2.5", - "integrity": "sha512-4s2hXZgvs0CoUIw31oBAGrHt9Kt/7P9Ik5HIVzISFiWkD0Ga2VLAuO/emO/z1tYIpE7KG2smB4PhMPfFMJpahw==", "requires": { "d3-dispatch": "^1.0.3" } }, "d3-collection": { - "version": "1.0.7", - "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" + "version": "1.0.7" }, "d3-color": { - "version": "1.4.1", - "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" + "version": "1.4.1" }, "d3-dispatch": { - "version": "1.0.6", - "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" + "version": "1.0.6" }, "d3-drag": { "version": "1.2.5", - "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", "requires": { "d3-dispatch": "1", "d3-selection": "1" @@ -65852,7 +70099,6 @@ }, "d3-dsv": { "version": "1.2.0", - "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==", "requires": { "commander": "2", "iconv-lite": "0.4", @@ -65860,46 +70106,37 @@ } }, "d3-ease": { - "version": "1.0.7", - "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" + "version": "1.0.7" }, "d3-format": { - "version": "1.3.2", - "integrity": "sha512-Z18Dprj96ExragQ0DeGi+SYPQ7pPfRMtUXtsg/ChVIKNBCzjO8XYJvRTC1usblx52lqge56V5ect+frYTQc8WQ==" + "version": "1.3.2" }, "d3-geo-projection": { "version": "0.2.16", - "integrity": "sha512-NB4/NRMnfJnpodvRbNY/nOzuoU17P229ASYf2l1GwjZyfD7l5aIuMylDMbIBF4y42BGZZvGdUwFW8iFM/5UBzg==", "requires": { "brfs": "^1.3.0" } }, "d3-hexbin": { - "version": "0.2.2", - "integrity": "sha512-KS3fUT2ReD4RlGCjvCEm1RgMtp2NFZumdMu4DBzQK8AZv3fXRM6Xm8I4fSU07UXvH4xxg03NwWKWdvxfS/yc4w==" + "version": "0.2.2" }, "d3-hierarchy": { - "version": "1.1.9", - "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==" + "version": "1.1.9" }, "d3-interpolate": { "version": "1.4.0", - "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", "requires": { "d3-color": "1" } }, "d3-path": { - "version": "1.0.7", - "integrity": "sha512-q0cW1RpvA5c5ma2rch62mX8AYaiLX0+bdaSM2wxSU9tXjU4DNvkx9qiUvjkuWCj3p22UO/hlPivujqMiR9PDzA==" + "version": "1.0.7" }, "d3-queue": { - "version": "2.0.3", - "integrity": "sha512-ejbdHqZYEmk9ns/ljSbEcD6VRiuNwAkZMdFf6rsUb3vHROK5iMFd8xewDQnUVr6m/ba2BG63KmR/LySfsluxbg==" + "version": "2.0.3" }, "d3-sankey": { "version": "0.4.2", - "integrity": "sha512-+EQUnk4yFS7kvLmNce7DbjVQqsK7oAd7Cwe2MkNnPssZbELXQvTFRMCKa0Vq9rw6Csrg0ASVJRBBTFaZz2fq8A==", "requires": { "d3-array": "1", "d3-collection": "1", @@ -65908,7 +70145,6 @@ }, "d3-sankey-diagram": { "version": "0.7.3", - "integrity": "sha512-k9DOe7MaLWhWV6J/aqY/CGw88Briu8drTQ+uGGyQg55MIR2WXjKUXryLs0ONFmRQkOSH1F+TSz5XiMc4KwKtuA==", "requires": { "d3-array": "^1.0.2", "d3-collection": "^1.0.2", @@ -65922,7 +70158,6 @@ }, "d3-scale": { "version": "2.2.2", - "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", "requires": { "d3-array": "^1.2.0", "d3-collection": "1", @@ -65934,45 +70169,37 @@ }, "d3-scale-chromatic": { "version": "2.0.0", - "integrity": "sha512-LLqy7dJSL8yDy7NRmf6xSlsFZ6zYvJ4BcWFE4zBrOPnQERv9zj24ohnXKRbyi9YHnYV+HN1oEO3iFK971/gkzA==", "requires": { "d3-color": "1 - 2", "d3-interpolate": "1 - 2" } }, "d3-selection": { - "version": "1.4.2", - "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" + "version": "1.4.2" }, "d3-shape": { "version": "1.2.2", - "integrity": "sha512-hUGEozlKecFZ2bOSNt7ENex+4Tk9uc/m0TtTEHBvitCBxUNjhzm5hS2GrrVRD/ae4IylSmxGeqX5tWC2rASMlQ==", "requires": { "d3-path": "1" } }, "d3-svg-legend": { - "version": "1.13.0", - "integrity": "sha512-0tMqbamHBfps/GwUO8v1ZXlPKneu0vJLj9R94I1h5/uhDKaYXfbEcqV/1c8NxVHgHEp/UoRLvrGBl9j0s7Hk9Q==" + "version": "1.13.0" }, "d3-time": { - "version": "1.0.10", - "integrity": "sha512-hF+NTLCaJHF/JqHN5hE8HVGAXPStEq6/omumPE/SxyHVrR7/qQxusFDo0t0c/44+sCGHthC7yNGFZIEgju0P8g==" + "version": "1.0.10" }, "d3-time-format": { "version": "2.3.0", - "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", "requires": { "d3-time": "1" } }, "d3-timer": { - "version": "1.0.10", - "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" + "version": "1.0.10" }, "d3-tip": { "version": "0.9.1", - "integrity": "sha512-EVBfG9d+HnjIoyVXfhpytWxlF59JaobwizqMX9EBXtsFmJytjwHeYiUs74ldHQjE7S9vzfKTx2LCtvUrIbuFYg==", "requires": { "d3-collection": "^1.0.4", "d3-selection": "^1.3.0" @@ -65980,7 +70207,6 @@ }, "d3-transition": { "version": "1.3.2", - "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", "requires": { "d3-color": "1", "d3-dispatch": "1", @@ -65991,12 +70217,10 @@ } }, "d3-voronoi": { - "version": "1.1.4", - "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==" + "version": "1.1.4" }, "d3-zoom": { "version": "1.8.3", - "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==", "requires": { "d3-dispatch": "1", "d3-drag": "1", @@ -66007,60 +70231,58 @@ }, "damerau-levenshtein": { "version": "1.0.8", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, "dargs": { - "version": "7.0.0", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true + "version": "7.0.0" }, "dashdash": { "version": "1.14.1", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, + "data-uri-to-buffer": { + "version": "3.0.1", + "dev": true + }, "data-urls": { - "version": "2.0.0", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "version": "3.0.2", "dev": true, "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" }, "dependencies": { "tr46": { - "version": "2.0.2", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "version": "3.0.0", "dev": true, "requires": { "punycode": "^2.1.1" } }, "webidl-conversions": { - "version": "6.1.0", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "version": "7.0.0", + "dev": true + }, + "whatwg-mimetype": { + "version": "3.0.0", "dev": true }, "whatwg-url": { - "version": "8.4.0", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "11.0.0", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^6.1.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" } } } }, "datamaps": { "version": "0.5.9", - "integrity": "sha512-GUXpO713URNzaExVUgBtqA5fr2UuxUG/fVitI04zEFHVL2FHSjd672alHq8E16oQqRNzF0m1bmx8WlTnDrGSqQ==", "requires": { "@types/d3": "3.5.38", "d3": "^3.5.6", @@ -66069,55 +70291,46 @@ }, "datatables.net": { "version": "1.11.3", - "integrity": "sha512-VMj5qEaTebpNurySkM6jy6sGpl+s6onPK8xJhYr296R/vUBnz1+id16NVqNf9z5aR076OGcpGHCuiTuy4E05oQ==", "requires": { "jquery": ">=1.7" } }, "datatables.net-bs": { "version": "1.11.3", - "integrity": "sha512-Db1YwAhO0QAWQbZTsKriUrOInT66+xaA+fV616KTKpQt5Zt+p6OsEKK+xv8LxLgG8qu5dPwMBlkhqSiS/hV2sg==", "requires": { "datatables.net": ">=1.10.25", "jquery": ">=1.7" } }, "date-fns": { - "version": "2.16.1", - "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==" + "version": "2.29.3" }, "date-format": { "version": "0.0.2", - "integrity": "sha512-M4obuJx8jU5T91lcbwi0+QPNVaWOY1DQYz5xUuKYWO93osVzB2ZPqyDUc5T+mDjbA1X8VOb4JDZ+8r2MrSOp7Q==", "dev": true }, "dateformat": { "version": "3.0.3", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" + "dev": true }, "dayjs": { - "version": "1.10.7", - "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==" + "version": "1.10.7" }, "debug": { "version": "2.6.9", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" } }, "debuglog": { "version": "1.0.1", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", "dev": true }, "decamelize": { - "version": "1.2.0", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" + "version": "1.2.0" }, "decamelize-keys": { "version": "1.1.0", - "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==", "dev": true, "requires": { "decamelize": "^1.1.0", @@ -66126,19 +70339,16 @@ "dependencies": { "map-obj": { "version": "1.0.1", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", "dev": true } } }, "decimal.js": { "version": "10.3.1", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, "deck.gl": { "version": "8.5.2", - "integrity": "sha512-tsEyv62Zzc+GT3By0Y1R2gqEJ8K3tGBDaLprAoeAsg7fvIa5ikFBdWEBFHa1UDbgE2UEmYbcBK/yK4GAL8Ia4A==", "requires": { "@deck.gl/aggregation-layers": "8.5.2", "@deck.gl/carto": "8.5.2", @@ -66155,41 +70365,23 @@ }, "decode-named-character-reference": { "version": "1.0.2", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", "requires": { "character-entities": "^2.0.0" }, "dependencies": { "character-entities": { - "version": "2.0.2", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==" + "version": "2.0.2" } } }, "decode-uri-component": { - "version": "0.2.0", - "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==" + "version": "0.2.2" }, "dedent": { - "version": "0.7.0", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==" - }, - "deep-equal": { - "version": "1.1.1", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } + "version": "0.7.0" }, "deep-equal-ident": { "version": "1.1.1", - "integrity": "sha512-aWv7VhTl/Lju1zenOD3E1w8PpUVrTDbwXCHtbSNr+p/uadr49Y1P1ld0W3Pl6gbvIbiRjoCVsqw70UupCNGh6g==", "dev": true, "requires": { "lodash.isequal": "^3.0" @@ -66197,7 +70389,6 @@ "dependencies": { "lodash.isequal": { "version": "3.0.4", - "integrity": "sha512-Bsu5fP9Omd+HBk2Dz8qp4BHbC+83DBykZ87Lz1JmPKTVNy4Q0XQVtUrbfXVAK/udQrWNcGStcKSA9yj/Zkm3TQ==", "dev": true, "requires": { "lodash._baseisequal": "^3.0.0", @@ -66207,24 +70398,19 @@ } }, "deep-extend": { - "version": "0.6.0", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + "version": "0.6.0" }, "deep-is": { - "version": "0.1.3", - "integrity": "sha512-GtxAN4HvBachZzm4OnWqc45ESpUCMwkYcsjnsPs23FwJbsO+k4t0k9bQCgOmzIlpHO28+WPK/KRbRk0DDHuuDw==" + "version": "0.1.3" }, "deep-object-diff": { - "version": "1.1.0", - "integrity": "sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw==" + "version": "1.1.0" }, "deepmerge": { - "version": "1.5.2", - "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==" + "version": "1.5.2" }, "default-gateway": { "version": "6.0.3", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, "requires": { "execa": "^5.0.0" @@ -66232,7 +70418,6 @@ "dependencies": { "cross-spawn": { "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -66242,7 +70427,6 @@ }, "execa": { "version": "5.1.1", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { "cross-spawn": "^7.0.3", @@ -66258,22 +70442,18 @@ }, "get-stream": { "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, "human-signals": { "version": "2.1.0", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "is-stream": { "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, "npm-run-path": { "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { "path-key": "^3.0.0" @@ -66281,12 +70461,10 @@ }, "path-key": { "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "shebang-command": { "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" @@ -66294,12 +70472,10 @@ }, "shebang-regex": { "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -66309,7 +70485,6 @@ }, "defaults": { "version": "1.0.3", - "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", "dev": true, "requires": { "clone": "^1.0.2" @@ -66317,26 +70492,23 @@ "dependencies": { "clone": { "version": "1.0.4", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true } } }, "define-lazy-prop": { "version": "2.0.0", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true }, "define-properties": { - "version": "1.1.3", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", "requires": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, "define-property": { "version": "2.0.2", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" @@ -66344,21 +70516,18 @@ "dependencies": { "is-accessor-descriptor": { "version": "1.0.0", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -66366,68 +70535,81 @@ } }, "kind-of": { - "version": "6.0.3", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "version": "6.0.3" + } + } + }, + "degenerator": { + "version": "3.0.2", + "dev": true, + "requires": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + }, + "dependencies": { + "ast-types": { + "version": "0.13.4", + "dev": true, + "requires": { + "tslib": "^2.0.1" + } + }, + "esprima": { + "version": "4.0.1", + "dev": true + }, + "tslib": { + "version": "2.4.1", + "dev": true } } }, "delayed-stream": { - "version": "1.0.0", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + "version": "1.0.0" }, "delegates": { - "version": "1.0.0", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + "version": "1.0.0" }, "depd": { - "version": "1.1.2", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + "version": "1.1.2" }, "deprecation": { - "version": "2.3.1", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true + "version": "2.3.1" }, "dequal": { - "version": "2.0.3", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" + "version": "2.0.3" }, "des.js": { "version": "1.0.1", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "requires": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, "destroy": { - "version": "1.0.4", - "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + "version": "1.0.4" }, "detab": { "version": "2.0.4", - "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", "requires": { "repeat-string": "^1.5.4" } }, "detect-indent": { "version": "6.1.0", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true }, "detect-newline": { "version": "3.1.0", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, "detect-node": { - "version": "2.1.0", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + "version": "2.1.0" }, "detect-port": { "version": "1.3.0", - "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", "requires": { "address": "^1.0.1", "debug": "^2.6.0" @@ -66435,12 +70617,10 @@ }, "devtools-protocol": { "version": "0.0.901419", - "integrity": "sha512-4INMPwNm9XRpBukhNbF7OB6fNTTCaI8pzy/fXg0xQzAy5h3zL1P8xT3QazgKqBrb/hAYwIBizqDBZ7GtJE74QQ==", "dev": true }, "dezalgo": { "version": "1.0.3", - "integrity": "sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==", "dev": true, "requires": { "asap": "^2.0.0", @@ -66449,20 +70629,17 @@ }, "diff": { "version": "4.0.2", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + "dev": true }, "diff-match-patch": { - "version": "1.0.5", - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" + "version": "1.0.5" }, "diff-sequences": { "version": "26.6.2", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true }, "diffie-hellman": { "version": "5.0.3", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -66470,39 +70647,33 @@ }, "dependencies": { "bn.js": { - "version": "4.12.0", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.0" } } }, "dir-glob": { "version": "3.0.1", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "requires": { "path-type": "^4.0.0" }, "dependencies": { "path-type": { - "version": "4.0.0", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "version": "4.0.0" } } }, "discontinuous-range": { "version": "1.0.0", - "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==", "dev": true }, "distributions": { "version": "1.1.0", - "integrity": "sha512-mufW9T1kRlzLVAaekUhgdfcMgX2r/zYQmJx3sGdUAwe0/JSQWey0XgqiDtfUUqYcr/QWHCnBd2M/v45tS/+YAQ==", "requires": { "mathfn": "^1.0.0" } }, "dnd-core": { "version": "11.1.3", - "integrity": "sha512-QugF55dNW+h+vzxVJ/LSJeTeUw9MCJ2cllhmVThVPEtF16ooBkxj0WBE5RB+AceFxMFo1rO6bJKXtqKl+JNnyA==", "requires": { "@react-dnd/asap": "^4.0.0", "@react-dnd/invariant": "^2.0.0", @@ -66511,59 +70682,42 @@ }, "dns-equal": { "version": "1.0.0", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", "dev": true }, "dns-packet": { - "version": "1.3.4", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dev": true, - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", + "version": "5.4.0", "dev": true, "requires": { - "buffer-indexof": "^1.0.0" + "@leichtgewicht/ip-codec": "^2.0.1" } }, "doctrine": { "version": "3.0.0", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "requires": { "esutils": "^2.0.2" } }, "dom-accessibility-api": { "version": "0.5.4", - "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==", "dev": true }, "dom-align": { - "version": "1.12.0", - "integrity": "sha512-YkoezQuhp3SLFGdOlr5xkqZ640iXrnHAwVYcDg8ZKRUtO7mSzSC2BA5V0VuyAwPSJA4CLIc6EDDJh4bEsD2+zA==" + "version": "1.12.0" }, "dom-converter": { "version": "0.2.0", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "requires": { "utila": "~0.4" } }, "dom-helpers": { "version": "3.4.0", - "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", "requires": { "@babel/runtime": "^7.1.2" } }, "dom-serializer": { "version": "0.1.0", - "integrity": "sha512-Fql7PX6CmQNVmoLfp7DlmvFMIL5cwLbm302SycA2iAMr95t1ITX4ilIsUG75rYtMiVLb4EMC5b2o7ApEpIXROg==", "dev": true, "requires": { "domelementtype": "~1.1.1", @@ -66572,58 +70726,48 @@ "dependencies": { "domelementtype": { "version": "1.1.3", - "integrity": "sha512-zEvAAsFY0DeHkrqWBRkSsmgaE7yADgpez40JUFjISb+uzSinl2F6QbG4lMEBE4P06gCGF6VnsykmbNgu7ZIHzA==", "dev": true } } }, "dom-to-image-more": { - "version": "2.10.1", - "integrity": "sha512-gMG28V47WGj5/xvrsbSPJAWSaV7CBh4teLErn1iGD1sa29HsFsHxvnoLj8VxVvfqnjPgsiUGs2IV2VAxLJGb+A==" + "version": "2.10.1" }, "dom-walk": { - "version": "0.1.1", - "integrity": "sha512-8CGZnLAdYN/o0SHjlP3nLvliHpi2f/prVU63/Hc4DTDpBgsNVAJekegjFtxfZ7NTUEDzHUByjX1gT3eYakIKqg==" + "version": "0.1.1" }, "domain-browser": { - "version": "1.2.0", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + "version": "1.2.0" }, "domelementtype": { "version": "1.3.1", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true }, "domexception": { - "version": "2.0.1", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "version": "4.0.0", "dev": true, "requires": { - "webidl-conversions": "^5.0.0" + "webidl-conversions": "^7.0.0" }, "dependencies": { "webidl-conversions": { - "version": "5.0.0", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "version": "7.0.0", "dev": true } } }, "domhandler": { "version": "2.4.2", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "dev": true, "requires": { "domelementtype": "1" } }, "dompurify": { - "version": "2.3.3", - "integrity": "sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg==" + "version": "2.3.3" }, "domutils": { "version": "1.5.1", - "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", "dev": true, "requires": { "dom-serializer": "0", @@ -66632,47 +70776,31 @@ }, "dot-case": { "version": "3.0.4", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3" }, "dependencies": { "tslib": { - "version": "2.1.0", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + "version": "2.1.0" } } }, "dot-prop": { "version": "6.0.1", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", "dev": true, "requires": { "is-obj": "^2.0.0" } }, "dotenv": { - "version": "8.6.0", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==" + "version": "8.6.0" }, "dotenv-expand": { - "version": "5.1.0", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" - }, - "download-stats": { - "version": "0.3.4", - "integrity": "sha512-ic2BigbyUWx7/CBbsfGjf71zUNZB4edBGC3oRliSzsoNmvyVx3Ycfp1w3vp2Y78Ee0eIIkjIEO5KzW0zThDGaA==", - "optional": true, - "requires": { - "JSONStream": "^1.2.1", - "lazy-cache": "^2.0.1", - "moment": "^2.15.1" - } + "version": "5.1.0" }, "downshift": { "version": "6.1.7", - "integrity": "sha512-cVprZg/9Lvj/uhYRxELzlu1aezRcgPWBjTvspiGTVEU64gF5pRdSRKFVLcxqsZC637cLAGMbL40JavEfWnqgNg==", "requires": { "@babel/runtime": "^7.14.8", "compute-scroll-into-view": "^1.0.17", @@ -66682,38 +70810,28 @@ }, "dependencies": { "react-is": { - "version": "17.0.2", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + "version": "17.0.2" }, "tslib": { - "version": "2.4.0", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "version": "2.4.0" } } }, "draco3d": { - "version": "1.4.1", - "integrity": "sha512-9Rxonc70xiovBC+Bq1h57SNZIHzWTibU1VfIGp5z3Xx8dPtv4yT5uGhiH7P5uvJRR2jkrvHafRxR7bTANkvfpg==" + "version": "1.4.1" }, "duplexer": { "version": "0.1.2", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, "duplexer2": { "version": "0.1.4", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", "requires": { "readable-stream": "^2.0.2" } }, - "duplexer3": { - "version": "0.1.4", - "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==" - }, "duplexify": { "version": "3.7.1", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -66722,13 +70840,10 @@ } }, "earcut": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + "version": "2.2.4" }, "ecc-jsbn": { "version": "0.1.2", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "requires": { "jsbn": "~0.1.0", @@ -66736,36 +70851,19 @@ } }, "echarts": { - "version": "5.3.2", - "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==", + "version": "5.4.1", "requires": { "tslib": "2.3.0", - "zrender": "5.3.1" + "zrender": "5.4.1" }, "dependencies": { "tslib": { - "version": "2.3.0", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" - } - } - }, - "editions": { - "version": "2.3.1", - "integrity": "sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA==", - "requires": { - "errlop": "^2.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "2.3.0" } } }, "editorconfig": { "version": "0.15.3", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", "requires": { "commander": "^2.19.0", "lru-cache": "^4.1.5", @@ -66775,48 +70873,41 @@ "dependencies": { "lru-cache": { "version": "4.1.5", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" } }, "yallist": { - "version": "2.1.2", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + "version": "2.1.2" } } }, "ee-first": { - "version": "1.1.1", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "version": "1.1.1" }, "ejs": { - "version": "3.1.6", - "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "version": "3.1.8", + "dev": true, "requires": { - "jake": "^10.6.1" + "jake": "^10.8.5" } }, "electron-to-chromium": { - "version": "1.3.836", - "integrity": "sha512-Ney3pHOJBWkG/AqYjrW0hr2AUCsao+2uvq9HUlRP8OlpSdk/zOHOUJP7eu0icDvePC9DlgffuelP4TnOJmMRUg==" + "version": "1.4.224" }, "elegant-spinner": { "version": "1.0.1", - "integrity": "sha512-B+ZM+RXvRqQaAmkMlO/oSe5nMUOaUnyfGYCEHoR8wrXsZR2mA0XVibsxV1bvTwxdRWah1PkQqso2EzhILGHtEQ==", "dev": true }, "element-resize-detector": { "version": "1.2.4", - "integrity": "sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==", "requires": { "batch-processor": "1.0.0" } }, "elliptic": { "version": "6.5.4", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "requires": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -66828,39 +70919,38 @@ }, "dependencies": { "bn.js": { - "version": "4.12.0", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.0" }, "inherits": { - "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "version": "2.0.4" } } }, "email-addresses": { - "version": "3.1.0", - "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==" + "version": "3.1.0" }, "emittery": { "version": "0.7.2", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", "dev": true }, "emoji-regex": { - "version": "8.0.0", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "version": "8.0.0" }, "emojis-list": { - "version": "3.0.0", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + "version": "3.0.0" + }, + "emotion": { + "version": "10.0.27", + "requires": { + "babel-plugin-emotion": "^10.0.27", + "create-emotion": "^10.0.27" + } }, "emotion-rgba": { - "version": "0.0.9", - "integrity": "sha512-fSt51Lh4a1fppXY3nQrMUC00p1jIYMSaRRkUhPiOJ3s9oumae1tY41AJytRK9d4YmJDP9njJBndgdDn9j7CbsA==" + "version": "0.0.9" }, "emotion-theming": { "version": "10.0.27", - "integrity": "sha512-MlF1yu/gYh8u+sLUqA0YuA9JX0P4Hb69WlKc/9OLo+WCXuX6sy/KoIa+qJimgmr2dWqnypYKYPX37esjDBbhdw==", "requires": { "@babel/runtime": "^7.5.5", "@emotion/weak-memoize": "0.2.5", @@ -66869,7 +70959,6 @@ }, "encodable": { "version": "0.7.8", - "integrity": "sha512-rh5isin1c3ZJuultMyJZGBRbGIh8IrVHQuwlEG3lPMGZQ5yQUb2STIbXGGEbSifxT4POnojKjTxhm3ITTSdriw==", "requires": { "@encodable/color": "^1.1.0", "@encodable/format": "^1.0.5", @@ -66888,21 +70977,18 @@ "dependencies": { "d3-array": { "version": "2.12.1", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } }, "d3-interpolate": { "version": "2.0.1", - "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", "requires": { "d3-color": "1 - 2" } }, "d3-scale": { "version": "3.3.0", - "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", "requires": { "d3-array": "^2.3.0", "d3-format": "1 - 2", @@ -66913,7 +70999,6 @@ }, "d3-time": { "version": "2.1.1", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", "requires": { "d3-array": "2" } @@ -66921,26 +71006,30 @@ } }, "encodeurl": { - "version": "1.0.2", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + "version": "1.0.2" }, "encoding": { - "version": "0.1.12", - "integrity": "sha512-bl1LAgiQc4ZWr++pNYUdRe/alecaHFeHxIJ/pNciqGdKXghaTCOwKkbKp6ye7pKZGu/GcaSXFk8PBVhgs+dJdA==", + "version": "0.1.13", "requires": { - "iconv-lite": "~0.4.13" + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } } }, "end-of-stream": { "version": "1.4.1", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "requires": { "once": "^1.4.0" } }, "endent": { "version": "2.1.0", - "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", "requires": { "dedent": "^0.7.0", "fast-json-parse": "^1.0.3", @@ -66949,7 +71038,6 @@ }, "enhanced-resolve": { "version": "4.5.0", - "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", "requires": { "graceful-fs": "^4.1.2", "memory-fs": "^0.5.0", @@ -66958,7 +71046,6 @@ "dependencies": { "memory-fs": { "version": "0.5.0", - "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", "requires": { "errno": "^0.1.3", "readable-stream": "^2.0.1" @@ -66968,7 +71055,6 @@ }, "enquirer": { "version": "2.3.6", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "dev": true, "requires": { "ansi-colors": "^4.1.1" @@ -66976,19 +71062,16 @@ "dependencies": { "ansi-colors": { "version": "4.1.1", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true } } }, "entities": { "version": "1.1.2", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", "dev": true }, "env-ci": { - "version": "5.4.1", - "integrity": "sha512-xyuCtyFZLpnW5aH0JstETKTSMwHHQX4m42juzEZzvbUCJX7RiPVlhASKM0f/cJ4vvI/+txMkZ7F5To6dCdPYhg==", + "version": "5.5.0", "dev": true, "requires": { "execa": "^5.0.0", @@ -66998,7 +71081,6 @@ "dependencies": { "cross-spawn": { "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -67008,7 +71090,6 @@ }, "execa": { "version": "5.1.1", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { "cross-spawn": "^7.0.3", @@ -67024,22 +71105,18 @@ }, "get-stream": { "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, "human-signals": { "version": "2.1.0", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "is-stream": { "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, "npm-run-path": { "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { "path-key": "^3.0.0" @@ -67047,12 +71124,10 @@ }, "path-key": { "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "shebang-command": { "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" @@ -67060,12 +71135,10 @@ }, "shebang-regex": { "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -67075,183 +71148,168 @@ }, "env-paths": { "version": "2.2.1", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true }, "envinfo": { "version": "7.8.1", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", "dev": true }, "enzyme": { - "version": "3.10.0", - "integrity": "sha512-p2yy9Y7t/PFbPoTvrWde7JIYB2ZyGC+NgTNbVEGvZ5/EyoYSr9aG/2rSbVvyNvMHEhw9/dmGUJHWtfQIEiX9pg==", + "version": "3.11.0", "dev": true, "requires": { - "array.prototype.flat": "^1.2.1", - "cheerio": "^1.0.0-rc.2", - "function.prototype.name": "^1.1.0", + "array.prototype.flat": "^1.2.3", + "cheerio": "^1.0.0-rc.3", + "enzyme-shallow-equal": "^1.0.1", + "function.prototype.name": "^1.1.2", "has": "^1.0.3", - "html-element-map": "^1.0.0", - "is-boolean-object": "^1.0.0", - "is-callable": "^1.1.4", - "is-number-object": "^1.0.3", - "is-regex": "^1.0.4", - "is-string": "^1.0.4", + "html-element-map": "^1.2.0", + "is-boolean-object": "^1.0.1", + "is-callable": "^1.1.5", + "is-number-object": "^1.0.4", + "is-regex": "^1.0.5", + "is-string": "^1.0.5", "is-subset": "^0.1.1", "lodash.escape": "^4.0.1", "lodash.isequal": "^4.5.0", - "object-inspect": "^1.6.0", - "object-is": "^1.0.1", + "object-inspect": "^1.7.0", + "object-is": "^1.0.2", "object.assign": "^4.1.0", - "object.entries": "^1.0.4", - "object.values": "^1.0.4", - "raf": "^3.4.0", + "object.entries": "^1.1.1", + "object.values": "^1.1.1", + "raf": "^3.4.1", "rst-selector-parser": "^2.2.3", - "string.prototype.trim": "^1.1.2" + "string.prototype.trim": "^1.2.1" }, "dependencies": { "object-inspect": { - "version": "1.6.0", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "version": "1.12.3", "dev": true } } }, "enzyme-adapter-react-16": { - "version": "1.14.0", - "integrity": "sha512-7PcOF7pb4hJUvjY7oAuPGpq3BmlCig3kxXGi2kFx0YzJHppqX1K8IIV9skT1IirxXlu8W7bneKi+oQ10QRnhcA==", + "version": "1.15.7", "dev": true, "requires": { - "enzyme-adapter-utils": "^1.12.0", + "enzyme-adapter-utils": "^1.14.1", + "enzyme-shallow-equal": "^1.0.5", "has": "^1.0.3", - "object.assign": "^4.1.0", - "object.values": "^1.1.0", - "prop-types": "^15.7.2", - "react-is": "^16.8.6", + "object.assign": "^4.1.4", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "react-is": "^16.13.1", "react-test-renderer": "^16.0.0-0", "semver": "^5.7.0" - }, - "dependencies": { - "react-is": { - "version": "16.9.0", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, "enzyme-adapter-utils": { - "version": "1.12.0", - "integrity": "sha512-wkZvE0VxcFx/8ZsBw0iAbk3gR1d9hK447ebnSYBf95+r32ezBq+XDSAvRErkc4LZosgH8J7et7H7/7CtUuQfBA==", + "version": "1.14.1", "dev": true, "requires": { - "airbnb-prop-types": "^2.13.2", - "function.prototype.name": "^1.1.0", - "object.assign": "^4.1.0", - "object.fromentries": "^2.0.0", - "prop-types": "^15.7.2", - "semver": "^5.6.0" + "airbnb-prop-types": "^2.16.0", + "function.prototype.name": "^1.1.5", + "has": "^1.0.3", + "object.assign": "^4.1.4", + "object.fromentries": "^2.0.5", + "prop-types": "^15.8.1", + "semver": "^5.7.1" } }, "enzyme-matchers": { "version": "7.1.2", - "integrity": "sha512-03WqAg2XDl7id9rARIO97HQ1JIw9F2heJ3R4meGu/13hx0ULTDEgl0E67MGl2Uq1jq1DyRnJfto1/VSzskdV5A==", "dev": true, "requires": { "circular-json-es6": "^2.0.1", "deep-equal-ident": "^1.1.1" } }, + "enzyme-shallow-equal": { + "version": "1.0.5", + "dev": true, + "requires": { + "has": "^1.0.3", + "object-is": "^1.1.5" + } + }, "enzyme-to-json": { "version": "3.5.0", - "integrity": "sha512-clusXRsiaQhG7+wtyc4t7MU8N3zCOgf4eY9+CeSenYzKlFST4lxerfOvnWd4SNaToKhkuba+w6m242YpQOS7eA==", "dev": true, "requires": { "lodash": "^4.17.15", "react-is": "^16.12.0" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - } } }, "err-code": { "version": "2.0.3", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "dev": true }, - "errlop": { - "version": "2.2.0", - "integrity": "sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==" - }, "errno": { "version": "0.1.7", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "requires": { "prr": "~1.0.1" } }, "error-ex": { "version": "1.3.2", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "requires": { "is-arrayish": "^0.2.1" } }, "error-stack-parser": { "version": "2.0.7", - "integrity": "sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA==", "requires": { "stackframe": "^1.1.1" } }, "es-abstract": { - "version": "1.19.1", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.21.1", "requires": { + "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" }, "dependencies": { "object-inspect": { - "version": "1.11.0", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + "version": "1.12.3" } } }, "es-array-method-boxes-properly": { - "version": "1.0.0", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + "version": "1.0.0" }, "es-get-iterator": { "version": "1.1.2", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.0", @@ -67264,19 +71322,30 @@ }, "dependencies": { "isarray": { - "version": "2.0.5", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "version": "2.0.5" } } }, "es-module-lexer": { "version": "0.7.1", - "integrity": "sha512-MgtWFl5No+4S3TmhDmCz2ObFGm6lEpTnzbQi+Dd+pw4mlTIZTmM2iAs5gRlmx5zS9luzobCSBSI90JM/1/JgOw==", "dev": true }, + "es-set-tostringtag": { + "version": "2.0.1", + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "requires": { + "has": "^1.0.3" + } + }, "es-to-primitive": { "version": "1.2.1", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -67284,32 +71353,25 @@ } }, "es5-shim": { - "version": "4.6.7", - "integrity": "sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==" + "version": "4.6.7" }, "es6-shim": { - "version": "0.35.6", - "integrity": "sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA==" + "version": "0.35.6" }, "es6bindall": { - "version": "0.0.9", - "integrity": "sha512-n3nKINzEmlCjzXhxwaJh5hGT/X9LuvvSlWwJevgwUu3PAiUqhlvk1M+zPAzrlRhTPkvoywOeJGgnT5dv+ugCYw==" + "version": "0.0.9" }, "escalade": { - "version": "3.1.1", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "version": "3.1.1" }, "escape-html": { - "version": "1.0.3", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "version": "1.0.3" }, "escape-string-regexp": { - "version": "1.0.5", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + "version": "1.0.5" }, "escodegen": { "version": "1.9.1", - "integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==", "requires": { "esprima": "^3.1.3", "estraverse": "^4.2.0", @@ -67320,14 +71382,12 @@ "dependencies": { "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "optional": true } } }, "eslint": { "version": "7.32.0", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "dev": true, "requires": { "@babel/code-frame": "7.12.11", @@ -67374,7 +71434,6 @@ "dependencies": { "@babel/code-frame": { "version": "7.12.11", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { "@babel/highlight": "^7.10.4" @@ -67382,12 +71441,10 @@ }, "ansi-regex": { "version": "5.0.0", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, "cross-spawn": { "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -67397,7 +71454,6 @@ }, "debug": { "version": "4.3.1", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -67405,17 +71461,14 @@ }, "escape-string-regexp": { "version": "4.0.0", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "eslint-visitor-keys": { "version": "2.0.0", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", "dev": true }, "globals": { "version": "13.12.0", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -67423,7 +71476,6 @@ }, "levn": { "version": "0.4.1", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { "prelude-ls": "^1.2.1", @@ -67432,7 +71484,6 @@ }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -67440,12 +71491,10 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "optionator": { "version": "0.9.1", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "requires": { "deep-is": "^0.1.3", @@ -67458,17 +71507,14 @@ }, "path-key": { "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "prelude-ls": { "version": "1.2.1", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, "semver": { "version": "7.3.4", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -67476,7 +71522,6 @@ }, "shebang-command": { "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" @@ -67484,12 +71529,10 @@ }, "shebang-regex": { "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "strip-ansi": { "version": "6.0.0", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { "ansi-regex": "^5.0.0" @@ -67497,7 +71540,6 @@ }, "type-check": { "version": "0.4.0", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "requires": { "prelude-ls": "^1.2.1" @@ -67505,12 +71547,10 @@ }, "type-fest": { "version": "0.20.2", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -67518,65 +71558,34 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "eslint-config-airbnb": { "version": "18.2.1", - "integrity": "sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg==", "dev": true, "requires": { "eslint-config-airbnb-base": "^14.2.1", "object.assign": "^4.1.2", "object.entries": "^1.1.2" - }, - "dependencies": { - "object.entries": { - "version": "1.1.3", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" - } - } } }, "eslint-config-airbnb-base": { "version": "14.2.1", - "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", "dev": true, "requires": { "confusing-browser-globals": "^1.0.10", "object.assign": "^4.1.2", "object.entries": "^1.1.2" - }, - "dependencies": { - "object.entries": { - "version": "1.1.3", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" - } - } } }, "eslint-config-prettier": { "version": "7.1.0", - "integrity": "sha512-9sm5/PxaFG7qNJvJzTROMM1Bk1ozXVTKI0buKOyb0Bsr1hrwi0H/TzxF/COtf1uxikIK8SwhX7K6zg78jAzbeA==", "dev": true }, "eslint-import-resolver-node": { "version": "0.3.6", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, "requires": { "debug": "^3.2.7", @@ -67585,7 +71594,6 @@ "dependencies": { "debug": { "version": "3.2.7", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -67593,14 +71601,12 @@ }, "ms": { "version": "2.1.3", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true } } }, "eslint-import-resolver-typescript": { "version": "2.5.0", - "integrity": "sha512-qZ6e5CFr+I7K4VVhQu3M/9xGv9/YmwsEXrsm3nimw8vWaVHRDrQRp26BgCypTxBp3vUp4o5aVEJRiy0F2DFddQ==", "dev": true, "requires": { "debug": "^4.3.1", @@ -67612,7 +71618,6 @@ "dependencies": { "debug": { "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -67620,14 +71625,12 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "eslint-module-utils": { "version": "2.6.2", - "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", "dev": true, "requires": { "debug": "^3.2.7", @@ -67636,7 +71639,6 @@ "dependencies": { "debug": { "version": "3.2.7", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -67644,12 +71646,10 @@ }, "ms": { "version": "2.1.3", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "pkg-dir": { "version": "2.0.0", - "integrity": "sha512-ojakdnUgL5pzJYWw2AIDEupaQCX5OPbM688ZevubICjdIX01PRSYKqm33fJoCOJBRseYCTUlQRnBNX+Pchaejw==", "dev": true, "requires": { "find-up": "^2.1.0" @@ -67659,7 +71659,6 @@ }, "eslint-plugin-cypress": { "version": "2.11.2", - "integrity": "sha512-1SergF1sGbVhsf7MYfOLiBhdOg6wqyeV9pXUAIDIffYTGMN3dTBQS9nFAzhLsHhO+Bn0GaVM1Ecm71XUidQ7VA==", "dev": true, "requires": { "globals": "^11.12.0" @@ -67667,7 +71666,6 @@ }, "eslint-plugin-file-progress": { "version": "1.2.0", - "integrity": "sha512-A2qwYqFI+w0XVHm0DUZ7gH+2/0SBbfoLWHtN+85jcl7tXalyi8qDGouuQ4PZ3H4VsD/4rER18J0sZMuoP0yPSQ==", "dev": true, "requires": { "chalk": "^4.1.2", @@ -67676,7 +71674,6 @@ }, "eslint-plugin-import": { "version": "2.24.2", - "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", "dev": true, "requires": { "array-includes": "^3.1.3", @@ -67696,19 +71693,8 @@ "tsconfig-paths": "^3.11.0" }, "dependencies": { - "array.prototype.flat": { - "version": "1.2.4", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - } - }, "doctrine": { "version": "2.1.0", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -67716,7 +71702,6 @@ }, "read-pkg": { "version": "3.0.0", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, "requires": { "load-json-file": "^4.0.0", @@ -67726,7 +71711,6 @@ }, "read-pkg-up": { "version": "3.0.0", - "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", "dev": true, "requires": { "find-up": "^2.0.0", @@ -67737,7 +71721,6 @@ }, "eslint-plugin-jest": { "version": "24.1.3", - "integrity": "sha512-dNGGjzuEzCE3d5EPZQ/QGtmlMotqnYWD/QpCZ1UuZlrMAdhG5rldh0N0haCvhGnUkSeuORS5VNROwF9Hrgn3Lg==", "dev": true, "requires": { "@typescript-eslint/experimental-utils": "^4.0.1" @@ -67745,7 +71728,6 @@ }, "eslint-plugin-jest-dom": { "version": "3.6.5", - "integrity": "sha512-iaJ5aSQghp9u2ciLAseWIVu7X5tW+WwNJwMBDToK4GBfwGXXQJDLt5IBNtm6fHvC3FRzCGwvyNMIG1g5gF+icQ==", "dev": true, "requires": { "@babel/runtime": "^7.9.6", @@ -67755,7 +71737,6 @@ }, "eslint-plugin-jsx-a11y": { "version": "6.5.1", - "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==", "dev": true, "requires": { "@babel/runtime": "^7.16.3", @@ -67774,19 +71755,16 @@ "dependencies": { "emoji-regex": { "version": "9.2.2", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true } } }, "eslint-plugin-no-only-tests": { "version": "2.4.0", - "integrity": "sha512-azP9PwQYfGtXJjW273nIxQH9Ygr+5/UyeW2wEjYoDtVYPI+WPKwbj0+qcAKYUXFZLRumq4HKkFaoDBAwBoXImQ==", "dev": true }, "eslint-plugin-prettier": { "version": "4.0.0", - "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -67794,7 +71772,6 @@ }, "eslint-plugin-react": { "version": "7.22.0", - "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==", "dev": true, "requires": { "array-includes": "^3.1.1", @@ -67812,44 +71789,19 @@ "dependencies": { "doctrine": { "version": "2.1.0", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { "esutils": "^2.0.2" } - }, - "object.entries": { - "version": "1.1.3", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" - } - }, - "object.fromentries": { - "version": "2.0.3", - "integrity": "sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" - } } } }, "eslint-plugin-react-hooks": { "version": "4.2.0", - "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", "dev": true }, "eslint-plugin-testing-library": { "version": "3.10.1", - "integrity": "sha512-nQIFe2muIFv2oR2zIuXE4vTbcFNx8hZKRzgHZqJg8rfopIWwoTwtlbCCNELT/jXzVe1uZF68ALGYoDXjLczKiQ==", "dev": true, "requires": { "@typescript-eslint/experimental-utils": "^3.10.1" @@ -67857,7 +71809,6 @@ "dependencies": { "@typescript-eslint/experimental-utils": { "version": "3.10.1", - "integrity": "sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", @@ -67869,12 +71820,10 @@ }, "@typescript-eslint/types": { "version": "3.10.1", - "integrity": "sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ==", "dev": true }, "@typescript-eslint/typescript-estree": { "version": "3.10.1", - "integrity": "sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w==", "dev": true, "requires": { "@typescript-eslint/types": "3.10.1", @@ -67889,7 +71838,6 @@ }, "@typescript-eslint/visitor-keys": { "version": "3.10.1", - "integrity": "sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ==", "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" @@ -67897,7 +71845,6 @@ }, "debug": { "version": "4.3.1", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -67905,17 +71852,14 @@ }, "eslint-visitor-keys": { "version": "1.3.0", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "semver": { "version": "7.3.2", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true } } @@ -67928,7 +71872,6 @@ }, "eslint-scope": { "version": "5.1.1", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { "esrecurse": "^4.3.0", @@ -67937,7 +71880,6 @@ }, "eslint-utils": { "version": "2.1.0", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" @@ -67945,24 +71887,20 @@ "dependencies": { "eslint-visitor-keys": { "version": "1.3.0", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true } } }, "eslint-visitor-keys": { "version": "3.1.0", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", "dev": true }, "esm": { "version": "3.2.25", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", "dev": true }, "espree": { "version": "7.3.1", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "requires": { "acorn": "^7.4.0", @@ -67972,23 +71910,19 @@ "dependencies": { "acorn": { "version": "7.4.1", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, "eslint-visitor-keys": { "version": "1.3.0", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true } } }, "esprima": { - "version": "3.1.3", - "integrity": "sha512-AWwVMNxwhN8+NIPQzAQZCm7RkLC4RbM3B1OobMuyp3i+w73X57KCKaVIxaRZb+DYCojq7rspo+fmuQfAboyhFg==" + "version": "3.1.3" }, "esquery": { "version": "1.4.0", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -67996,31 +71930,26 @@ "dependencies": { "estraverse": { "version": "5.3.0", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } }, "esrecurse": { "version": "4.3.0", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "requires": { "estraverse": "^5.2.0" }, "dependencies": { "estraverse": { - "version": "5.2.0", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + "version": "5.2.0" } } }, "estraverse": { - "version": "4.2.0", - "integrity": "sha512-VHvyaGnJy+FuGfcfaM7W7OZw4mQiKW73jPHwQXx2VnMSUBajYmytOT5sKEfsBvNPtGX6YDwcrGDz2eocoHg0JA==" + "version": "4.2.0" }, "estree-to-babel": { "version": "3.2.1", - "integrity": "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==", "requires": { "@babel/traverse": "^7.1.6", "@babel/types": "^7.2.0", @@ -68028,29 +71957,23 @@ } }, "esutils": { - "version": "2.0.2", - "integrity": "sha512-UUPPULqkyAV+M3Shodis7l8D+IyX6V8SbaBnTb449jf3fMTd8+UOZI1Q70NbZVOQkcR91yYgdHsJiMMMVmYshg==" + "version": "2.0.2" }, "etag": { - "version": "1.8.1", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + "version": "1.8.1" }, "event-target-shim": { "version": "5.0.1", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "dev": true }, "eventemitter3": { - "version": "4.0.7", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + "version": "4.0.7" }, "events": { - "version": "3.2.0", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" + "version": "3.2.0" }, "evp_bytestokey": { "version": "1.0.3", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -68058,12 +71981,10 @@ }, "exec-sh": { "version": "0.3.4", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", "dev": true }, "execa": { "version": "1.0.0", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { "cross-spawn": "^6.0.0", @@ -68077,12 +71998,10 @@ }, "exit": { "version": "0.1.2", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true }, "expand-brackets": { "version": "2.1.4", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "requires": { "debug": "^2.3.3", "define-property": "^0.2.5", @@ -68095,7 +72014,6 @@ "dependencies": { "define-property": { "version": "0.2.5", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -68104,7 +72022,6 @@ }, "expect": { "version": "26.6.2", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -68117,7 +72034,6 @@ }, "exports-loader": { "version": "0.7.0", - "integrity": "sha512-RKwCrO4A6IiKm0pG3c9V46JxIHcDplwwGJn6+JJ1RcVnh/WSGJa0xkmk5cRVtgOPzCAtTMGj2F7nluh9L0vpSA==", "dev": true, "requires": { "loader-utils": "^1.1.0", @@ -68126,21 +72042,19 @@ "dependencies": { "source-map": { "version": "0.5.0", - "integrity": "sha512-gjGnxNN0K+/Pr4Mi4fs/pOtda10dKB6Wn9QvjOrH6v5TWsI7ghHuJUHoIgyM6DkUL5kr2GtPFGererzKpMBWfA==", "dev": true } } }, "express": { - "version": "4.17.1", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.3", "requires": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -68154,79 +72068,57 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "dependencies": { - "accepts": { - "version": "1.3.7", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, "array-flatten": { - "version": "1.1.1", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "negotiator": { - "version": "0.6.2", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "version": "1.1.1" }, - "parseurl": { - "version": "1.3.3", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + "cookie": { + "version": "0.4.2" }, "path-to-regexp": { - "version": "0.1.7", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.7" }, "qs": { - "version": "6.7.0", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "version": "6.9.7" }, - "setprototypeof": { - "version": "1.1.1", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "safe-buffer": { + "version": "5.2.1" }, - "statuses": { - "version": "1.5.0", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + "setprototypeof": { + "version": "1.2.0" } } }, "expression-eval": { "version": "2.1.0", - "integrity": "sha512-FUJO/Akvl/JOWkvlqZaqbkhsEWlCJWDeZG4tzX96UH68D9FeRgYgtb55C2qtqbORC0Q6x5419EDjWu4IT9kQfg==", "requires": { "jsep": "^0.3.0" } }, "extend": { - "version": "3.0.2", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "version": "3.0.2" }, "extend-shallow": { "version": "2.0.1", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { "is-extendable": "^0.1.0" } }, "external-editor": { "version": "3.1.0", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "devOptional": true, + "dev": true, "requires": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -68235,8 +72127,7 @@ "dependencies": { "tmp": { "version": "0.0.33", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "devOptional": true, + "dev": true, "requires": { "os-tmpdir": "~1.0.2" } @@ -68245,7 +72136,6 @@ }, "extglob": { "version": "2.0.4", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { "array-unique": "^0.3.2", "define-property": "^1.0.0", @@ -68259,28 +72149,24 @@ "dependencies": { "define-property": { "version": "1.0.0", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "requires": { "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { "version": "1.0.0", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -68288,14 +72174,12 @@ } }, "kind-of": { - "version": "6.0.2", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "version": "6.0.2" } } }, "extract-zip": { "version": "2.0.1", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, "requires": { "@types/yauzl": "^2.9.1", @@ -68306,7 +72190,6 @@ "dependencies": { "debug": { "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -68314,7 +72197,6 @@ }, "get-stream": { "version": "5.2.0", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "requires": { "pump": "^3.0.0" @@ -68322,24 +72204,20 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "extsprintf": { "version": "1.3.0", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true }, "fake-tag": { "version": "2.0.0", - "integrity": "sha512-QDz+8qiNQ9AfBZ31EXlID5JIbUkU3e1nXDWk4tidFzd2gy8XJaEUW1HCuDY6DUy6t2Y0nvhD6PsUc+2WYy5w0w==", "dev": true }, "falafel": { "version": "2.2.4", - "integrity": "sha512-0HXjo8XASWRmsS0X1EkhwEMZaD3Qvp7FfURwjLKjG1ghfRm/MGZl2r4cWUTv41KdNghTw4OUMmVtdGQp3+H+uQ==", "requires": { "acorn": "^7.1.1", "foreach": "^2.0.5", @@ -68348,27 +72226,22 @@ }, "dependencies": { "acorn": { - "version": "7.4.1", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + "version": "7.4.1" }, "isarray": { - "version": "2.0.5", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "version": "2.0.5" } } }, "fast-deep-equal": { - "version": "3.1.3", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "version": "3.1.3" }, "fast-diff": { "version": "1.2.0", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, "fast-glob": { "version": "3.2.10", - "integrity": "sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==", "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -68379,25 +72252,21 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "requires": { "fill-range": "^7.0.1" } }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "requires": { "to-regex-range": "^5.0.1" } }, "is-number": { - "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "version": "7.0.0" }, "micromatch": { "version": "4.0.4", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "requires": { "braces": "^3.0.1", "picomatch": "^2.2.3" @@ -68405,7 +72274,6 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "requires": { "is-number": "^7.0.0" } @@ -68413,47 +72281,38 @@ } }, "fast-json-parse": { - "version": "1.0.3", - "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==" + "version": "1.0.3" }, "fast-json-stable-stringify": { - "version": "2.0.0", - "integrity": "sha512-eIgZvM9C3P05kg0qxfqaVU6Tma4QedCPIByQOcemV0vju8ot3cS2DpHi4m2G2JvbSMI152rjfLX0p1pkSdyPlQ==" + "version": "2.0.0" }, "fast-levenshtein": { - "version": "2.0.6", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + "version": "2.0.6" }, "fast-memoize": { - "version": "2.5.2", - "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==" + "version": "2.5.2" }, "fast-safe-stringify": { - "version": "2.1.1", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + "version": "2.1.1" }, "fastest-levenshtein": { "version": "1.0.12", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", "dev": true }, "fastq": { "version": "1.8.0", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", "requires": { "reusify": "^1.0.4" } }, "fault": { "version": "1.0.2", - "integrity": "sha512-o2eo/X2syzzERAtN5LcGbiVQ0WwZSlN3qLtadwAz3X8Bu+XWD16dja/KMsjZLiQr+BLGPDnHGkc4yUJf1Xpkpw==", "requires": { "format": "^0.2.2" } }, "faye-websocket": { "version": "0.11.4", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, "requires": { "websocket-driver": ">=0.5.1" @@ -68461,7 +72320,6 @@ }, "fb-watchman": { "version": "2.0.1", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", "dev": true, "requires": { "bser": "2.1.1" @@ -68469,7 +72327,6 @@ }, "fbjs": { "version": "0.8.17", - "integrity": "sha512-Q1MvLM+cllhk7lv9Pci7dIdpC5W8MS6W0slOWizKG66+te0m9/YqjfIt41rKmH+Nqz+mMiGgdEVonDadPyKnug==", "requires": { "core-js": "^1.0.0", "isomorphic-fetch": "^2.1.1", @@ -68481,14 +72338,12 @@ }, "dependencies": { "core-js": { - "version": "1.2.7", - "integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==" + "version": "1.2.7" } } }, "fd-slicer": { "version": "1.1.0", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "requires": { "pend": "~1.2.0" @@ -68496,7 +72351,6 @@ }, "fetch-mock": { "version": "7.7.3", - "integrity": "sha512-I4OkK90JFQnjH8/n3HDtWxH/I6D1wrxoAM2ri+nb444jpuH3RTcgvXx2el+G20KO873W727/66T7QhOvFxNHPg==", "dev": true, "requires": { "babel-polyfill": "^6.26.0", @@ -68509,30 +72363,25 @@ "dependencies": { "core-js": { "version": "2.6.11", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", "dev": true } } }, "fetch-retry": { - "version": "4.1.1", - "integrity": "sha512-e6eB7zN6UBSwGVwrbWVH+gdLnkW9WwHhmq2YDK1Sh30pzx1onRVGBvogTlUeWxwTa+L86NYdo4hFkh7O8ZjSnA==" + "version": "4.1.1" }, "figgy-pudding": { - "version": "3.5.2", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + "version": "3.5.2" }, "figures": { "version": "3.2.0", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "devOptional": true, + "dev": true, "requires": { "escape-string-regexp": "^1.0.5" } }, "file-entry-cache": { "version": "6.0.1", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { "flat-cache": "^3.0.4" @@ -68540,19 +72389,16 @@ }, "file-loader": { "version": "6.2.0", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", "requires": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" }, "dependencies": { "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3" }, "loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -68563,7 +72409,6 @@ }, "file-system-cache": { "version": "1.0.5", - "integrity": "sha512-w9jqeQdOeVaXBCgl4c90XJ6zI8MguJgSiC5LsLdhUu6eSCzcRHPPXUF3lkKMagpzHi+6GnDkjv9BtxMmXdvptA==", "requires": { "bluebird": "^3.3.5", "fs-extra": "^0.30.0", @@ -68572,7 +72417,6 @@ "dependencies": { "fs-extra": { "version": "0.30.0", - "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0", @@ -68583,18 +72427,15 @@ }, "jsonfile": { "version": "2.4.0", - "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", "requires": { "graceful-fs": "^4.1.6" } }, "ramda": { - "version": "0.21.0", - "integrity": "sha512-HGd5aczYKQXGILB+abY290V7Xz62eFajpa6AtMdwEmQSakJmgSO7ks4eI3HdR34j+X2Vz4Thp9VAJbrCAMbO2w==" + "version": "0.21.0" }, "rimraf": { "version": "2.7.1", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" } @@ -68602,19 +72443,33 @@ } }, "filelist": { - "version": "1.0.2", - "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "version": "1.0.4", + "dev": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.0", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "filename-reserved-regex": { - "version": "2.0.0", - "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==" + "version": "2.0.0" }, "filenamify": { "version": "4.3.0", - "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", "requires": { "filename-reserved-regex": "^2.0.0", "strip-outer": "^1.0.1", @@ -68623,7 +72478,6 @@ }, "fill-range": { "version": "4.0.0", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "requires": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", @@ -68633,16 +72487,13 @@ }, "filter-console": { "version": "0.1.1", - "integrity": "sha512-zrXoV1Uaz52DqPs+qEwNJWJFAWZpYJ47UNmpN9q4j+/EYsz85uV0DC9k8tRND5kYmoVzL0W+Y75q4Rg8sRJCdg==", "dev": true }, "filter-obj": { - "version": "1.1.0", - "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==" + "version": "1.1.0" }, "finalhandler": { "version": "1.1.2", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -68651,21 +72502,10 @@ "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" - }, - "dependencies": { - "parseurl": { - "version": "1.3.3", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "statuses": { - "version": "1.5.0", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" - } } }, "find-cache-dir": { "version": "2.1.0", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "requires": { "commondir": "^1.0.1", "make-dir": "^2.0.0", @@ -68674,75 +72514,65 @@ }, "find-replace": { "version": "3.0.0", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", "requires": { "array-back": "^3.0.1" } }, "find-root": { - "version": "1.1.0", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + "version": "1.1.0" }, "find-up": { "version": "2.1.0", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", "dev": true, "requires": { "locate-path": "^2.0.0" } }, - "first-chunk-stream": { - "version": "2.0.0", - "integrity": "sha512-X8Z+b/0L4lToKYq+lwnKqi9X/Zek0NibLpsJgVsSxpoYq7JtiCtRb5HqKVEjEw/qAb/4AKKRLOwwKHlWNpm2Eg==", - "optional": true, - "requires": { - "readable-stream": "^2.0.2" - } + "flat": { + "version": "5.0.2", + "dev": true }, "flat-cache": { "version": "3.0.4", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "requires": { "flatted": "^3.1.0", "rimraf": "^3.0.2" } }, "flatbuffers": { - "version": "1.12.0", - "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==" + "version": "1.12.0" }, "flatted": { - "version": "3.1.0", - "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==" + "version": "3.1.0" }, "flush-write-stream": { "version": "1.1.1", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "requires": { "inherits": "^2.0.3", "readable-stream": "^2.3.6" } }, "follow-redirects": { - "version": "1.14.8", - "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", - "devOptional": true + "version": "1.15.2", + "dev": true }, "fontsource-fira-code": { - "version": "4.0.0", - "integrity": "sha512-qKVeWWNvkPP22FUkea2qVgZHiPBIRk9HFGIFmEUbqEV7Wcu/Dxrva4t7d1XPa2+0cnJgD0kHAiDZ514KjHYQKA==" + "version": "4.0.0" + }, + "for-each": { + "version": "0.3.3", + "requires": { + "is-callable": "^1.1.3" + } }, "for-in": { - "version": "1.0.2", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==" + "version": "1.0.2" }, "foreach": { - "version": "2.0.5", - "integrity": "sha512-ZBbtRiapkZYLsqoPyZOR+uPfto0GRMNQN1GwzZtZt7iZvPPbDDQV0JF5Hx4o/QFQ5c0vyuoZ98T8RSBbopzWtA==" + "version": "2.0.5" }, "foreground-child": { "version": "2.0.0", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "requires": { "cross-spawn": "^7.0.0", "signal-exit": "^3.0.2" @@ -68750,7 +72580,6 @@ "dependencies": { "cross-spawn": { "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -68758,23 +72587,19 @@ } }, "path-key": { - "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "version": "3.1.1" }, "shebang-command": { "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "requires": { "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "version": "3.0.0" }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "requires": { "isexe": "^2.0.0" } @@ -68783,12 +72608,10 @@ }, "forever-agent": { "version": "0.6.1", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true }, "fork-ts-checker-webpack-plugin": { "version": "6.3.3", - "integrity": "sha512-S3uMSg8IsIvs0H6VAfojtbf6RcnEXxEpDMT2Q41M2l0m20JO8eA1t4cCJybvrasC8SvvPEtK4B8ztxxfLljhNg==", "requires": { "@babel/code-frame": "^7.8.3", "@types/json-schema": "^7.0.5", @@ -68807,7 +72630,6 @@ "dependencies": { "cosmiconfig": { "version": "6.0.0", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", "requires": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.1.0", @@ -68817,12 +72639,10 @@ } }, "deepmerge": { - "version": "4.2.2", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + "version": "4.2.2" }, "fs-extra": { "version": "9.1.0", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -68832,14 +72652,12 @@ }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "requires": { "yallist": "^4.0.0" } }, "parse-json": { "version": "5.2.0", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -68848,12 +72666,10 @@ } }, "path-type": { - "version": "4.0.0", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "version": "4.0.0" }, "schema-utils": { "version": "2.7.0", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", "requires": { "@types/json-schema": "^7.0.4", "ajv": "^6.12.2", @@ -68862,20 +72678,17 @@ }, "semver": { "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "requires": { "lru-cache": "^6.0.0" } }, "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "4.0.0" } } }, "form-data": { "version": "2.3.3", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, "requires": { "asynckit": "^0.4.0", @@ -68884,23 +72697,19 @@ } }, "format": { - "version": "0.2.2", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==" + "version": "0.2.2" }, "fragment-cache": { "version": "0.2.1", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "requires": { "map-cache": "^0.2.2" } }, "fresh": { - "version": "0.5.2", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + "version": "0.5.2" }, "from2": { "version": "2.3.0", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" @@ -68908,17 +72717,14 @@ }, "fromentries": { "version": "1.3.2", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", "dev": true }, "fs-constants": { "version": "1.0.0", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, "fs-extra": { - "version": "10.0.0", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "version": "10.1.0", "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -68927,23 +72733,19 @@ }, "fs-minipass": { "version": "2.1.0", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "requires": { "minipass": "^3.0.0" } }, "fs-monkey": { - "version": "1.0.3", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" + "version": "1.0.3" }, "fs-readdir-recursive": { "version": "1.1.0", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", "dev": true }, "fs-write-stream-atomic": { "version": "1.0.10", - "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", "requires": { "graceful-fs": "^4.1.2", "iferr": "^0.1.5", @@ -68952,118 +72754,136 @@ } }, "fs.realpath": { - "version": "1.0.0", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "version": "1.0.0" + }, + "ftp": { + "version": "0.3.10", + "dev": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "dev": true + } + } }, "function-bind": { - "version": "1.1.1", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.1" }, "function.prototype.name": { - "version": "1.1.1", - "integrity": "sha512-e1NzkiJuw6xqVH7YSdiW/qDHebcmMhPNe6w+4ZYYEg0VA+LaLzx37RimbPLuonHhYGFGPx1ME2nSi74JiaCr/Q==", + "version": "1.1.5", "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "function-bind": "^1.1.1", - "functions-have-names": "^1.1.1", - "is-callable": "^1.1.4" + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" } }, "functional-red-black-tree": { "version": "1.0.1", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "dev": true }, "functions-have-names": { - "version": "1.1.1", - "integrity": "sha512-U0kNHUoxwPNPWOJaMG7Z00d4a/qZVrFtzWJRaK8V9goaVOCXBSQSJpt3MYGNtkScKEBKovxLjnNdC9MlXwo5Pw==" + "version": "1.2.3" }, "fuse.js": { - "version": "6.4.6", - "integrity": "sha512-/gYxR/0VpXmWSfZOIPS3rWwU8SHgsRTwWuXhyb2O6s7aRuVtHtxCkR33bNYu3wyLyNx/Wpv0vU7FZy8Vj53VNw==" + "version": "6.4.6" }, "gauge": { - "version": "2.7.4", - "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", + "version": "4.0.4", "dev": true, "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" }, "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "dev": true + }, "is-fullwidth-code-point": { - "version": "1.0.0", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "version": "3.0.0", + "dev": true + }, + "string-width": { + "version": "4.2.3", "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, - "string-width": { - "version": "1.0.2", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "strip-ansi": { + "version": "6.0.1", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "ansi-regex": "^5.0.1" } } } }, "gensync": { - "version": "1.0.0-beta.2", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "version": "1.0.0-beta.2" }, "geojson-flatten": { "version": "1.0.4", - "integrity": "sha512-PpscUXxO6dvvhZxtwuqiI5v+1C/IQYPJRMWoQeaF2oohJgfGYSHKVAe8L+yUqF34PH/hmq9JlwmO+juPw+95/Q==", "requires": { "get-stdin": "^7.0.0", "minimist": "^1.2.5" }, "dependencies": { "get-stdin": { - "version": "7.0.0", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==" + "version": "7.0.0" } } }, "geojson-vt": { - "version": "3.2.1", - "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==" + "version": "3.2.1" }, "geolib": { - "version": "2.0.24", - "integrity": "sha512-NR0AyYyEnGrFS9JvSFmmotQDxVCORJgDHdvBwSatxl5aHarOLMh3KuGI83bCvCfObjfoEiDe8Ung8GGLGAtthw==" + "version": "2.0.24" }, "get-caller-file": { - "version": "2.0.5", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "version": "2.0.5" }, "get-intrinsic": { - "version": "1.1.1", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.0", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" } }, "get-package-type": { "version": "0.1.0", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, "get-pkg-repo": { "version": "4.2.1", - "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", "dev": true, "requires": { "@hutson/parse-repository-url": "^3.0.0", @@ -69074,12 +72894,10 @@ "dependencies": { "ansi-regex": { "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "cliui": { "version": "7.0.4", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { "string-width": "^4.2.0", @@ -69089,7 +72907,6 @@ }, "hosted-git-info": { "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -69097,12 +72914,10 @@ }, "is-fullwidth-code-point": { "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -69110,7 +72925,6 @@ }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", @@ -69120,7 +72934,6 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { "ansi-regex": "^5.0.1" @@ -69128,7 +72941,6 @@ }, "wrap-ansi": { "version": "7.0.0", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { "ansi-styles": "^4.0.0", @@ -69138,17 +72950,14 @@ }, "y18n": { "version": "5.0.8", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "yargs": { "version": "16.2.0", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -69162,23 +72971,19 @@ }, "yargs-parser": { "version": "20.2.9", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true } } }, "get-port": { "version": "5.1.1", - "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", "dev": true }, "get-stdin": { - "version": "4.0.1", - "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==" + "version": "4.0.1" }, "get-stream": { "version": "4.1.0", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { "pump": "^3.0.0" @@ -69186,35 +72991,72 @@ }, "get-symbol-description": { "version": "1.0.0", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" } }, + "get-uri": { + "version": "3.0.2", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "file-uri-to-path": { + "version": "2.0.0", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "ms": { + "version": "2.1.2", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "dev": true + } + } + }, "get-value": { - "version": "2.0.6", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==" + "version": "2.0.6" }, "getpass": { "version": "0.1.7", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, - "gh-got": { - "version": "5.0.0", - "integrity": "sha512-B9bWm0vDR7CSbFPxt528dbMTWd9CUc4h9U3Ji7e781Jy9Xm0p6QWKVndA4ETEzDCd3/GqVCjVfqqpl2kR1j3nA==", - "requires": { - "got": "^6.2.0", - "is-plain-obj": "^1.1.0" - } - }, "gh-pages": { "version": "3.2.3", - "integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==", "requires": { "async": "^2.6.1", "commander": "^2.18.0", @@ -69227,21 +73069,18 @@ "dependencies": { "array-union": { "version": "1.0.2", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", "requires": { "array-uniq": "^1.0.1" } }, "async": { - "version": "2.6.3", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", "requires": { "lodash": "^4.17.14" } }, "find-cache-dir": { "version": "3.3.2", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "requires": { "commondir": "^1.0.1", "make-dir": "^3.0.2", @@ -69250,7 +73089,6 @@ }, "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -69258,7 +73096,6 @@ }, "fs-extra": { "version": "8.1.0", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -69267,7 +73104,6 @@ }, "globby": { "version": "6.1.0", - "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", "requires": { "array-union": "^1.0.1", "glob": "^7.0.3", @@ -69278,76 +73114,63 @@ }, "jsonfile": { "version": "4.0.0", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "requires": { "graceful-fs": "^4.1.6" } }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { "p-locate": "^4.1.0" } }, "make-dir": { "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "requires": { "semver": "^6.0.0" } }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "requires": { "p-limit": "^2.2.0" } }, "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "version": "2.2.0" }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" }, "pify": { - "version": "2.3.0", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" + "version": "2.3.0" }, "pkg-dir": { "version": "4.2.0", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "requires": { "find-up": "^4.0.0" } }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" }, "universalify": { - "version": "0.1.2", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + "version": "0.1.2" } } }, "git-hooks-list": { "version": "1.0.3", - "integrity": "sha512-Y7wLWcrLUXwk2noSka166byGCvhMtDRpgHdzCno1UQv/n/Hegp++a2xBWJL1lJarnKD3SWaljD+0z1ztqxuKyQ==", "dev": true }, "git-raw-commits": { "version": "2.0.11", - "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", "dev": true, "requires": { "dargs": "^7.0.0", @@ -69359,7 +73182,6 @@ "dependencies": { "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -69369,7 +73191,6 @@ }, "through2": { "version": "4.0.2", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, "requires": { "readable-stream": "3" @@ -69379,7 +73200,6 @@ }, "git-remote-origin-url": { "version": "2.0.0", - "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", "dev": true, "requires": { "gitconfiglocal": "^1.0.0", @@ -69388,14 +73208,12 @@ "dependencies": { "pify": { "version": "2.3.0", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true } } }, "git-semver-tags": { "version": "4.1.1", - "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", "dev": true, "requires": { "meow": "^8.0.0", @@ -69404,31 +73222,27 @@ "dependencies": { "semver": { "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "git-up": { - "version": "4.0.5", - "integrity": "sha512-YUvVDg/vX3d0syBsk/CKUTib0srcQME0JyHkL5BaYdwLsiCslPWmDSi8PUMo9pXYjrryMcmsCoCgsTpSCJEQaA==", + "version": "7.0.0", "dev": true, "requires": { - "is-ssh": "^1.3.0", - "parse-url": "^6.0.0" + "is-ssh": "^1.4.0", + "parse-url": "^8.1.0" } }, "git-url-parse": { - "version": "11.6.0", - "integrity": "sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g==", + "version": "13.1.0", "dev": true, "requires": { - "git-up": "^4.0.0" + "git-up": "^7.0.0" } }, "gitconfiglocal": { "version": "1.0.0", - "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", "dev": true, "requires": { "ini": "^1.3.2" @@ -69436,84 +73250,71 @@ }, "github-slugger": { "version": "1.4.0", - "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==", "dev": true }, "github-username": { - "version": "3.0.0", - "integrity": "sha512-pbA1zobA7urImyNixOkCb/eO2fRadF7+RZgdjzT3/k/KukA8CY7QZ7BNCdCetH1kB0YqeBmY+Hn76XaC3rmmzQ==", + "version": "6.0.0", "requires": { - "gh-got": "^5.0.0" + "@octokit/rest": "^18.0.6" } }, "gl-matrix": { - "version": "3.3.0", - "integrity": "sha512-COb7LDz+SXaHtl/h4LeaFcNdJdAQSDeVqjiIihSXNrkWObZLhDI4hIkZC11Aeqp7bcE72clzB0BnDXr2SmslRA==" + "version": "3.3.0" }, "glob": { - "version": "7.1.7", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "version": "7.2.3", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "glob-parent": { "version": "5.1.2", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "requires": { "is-glob": "^4.0.1" } }, "glob-promise": { "version": "3.4.0", - "integrity": "sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==", "requires": { "@types/glob": "*" } }, "glob-to-regexp": { - "version": "0.4.1", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + "version": "0.4.1" }, "global": { "version": "4.4.0", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", "requires": { "min-document": "^2.19.0", "process": "^0.11.10" } }, "global-box": { - "version": "1.2.0", - "integrity": "sha512-IgpqqAYWNG3eluK1tsCkI8Uxff16+OYWLEhDS/QrfkfmbRQ/tVlBXZfURn5tSoPPT6wtmeJp7VKhXrcc5jl/1A==" + "version": "1.2.0" }, "global-cache": { "version": "1.2.1", - "integrity": "sha512-EOeUaup5DgWKlCMhA9YFqNRIlZwoxt731jCh47WBV9fQqHgXhr3Fa55hfgIUqilIcPsfdNKN7LHjrNY+Km40KA==", "requires": { "define-properties": "^1.1.2", "is-symbol": "^1.0.1" } }, "globals": { - "version": "11.12.0", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "version": "11.12.0" }, "globalthis": { "version": "1.0.3", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "requires": { "define-properties": "^1.1.3" } }, "globby": { "version": "11.1.0", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -69524,79 +73325,48 @@ }, "dependencies": { "ignore": { - "version": "5.2.0", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + "version": "5.2.0" }, "slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + "version": "3.0.0" } } }, - "got": { - "version": "6.7.1", - "integrity": "sha512-Y/K3EDuiQN9rTZhBvPRWMLXIKdeD1Rj0nzunfoi0Yyn5WBEbzxXKU9Ub2X41oZBagVWOBU3MuDonFMgPWQFnwg==", + "gopd": { + "version": "1.0.1", "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==" - } + "get-intrinsic": "^1.1.3" } }, "graceful-fs": { - "version": "4.2.8", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "version": "4.2.8" }, "graphlib": { "version": "2.1.8", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", "requires": { "lodash": "^4.17.15" } }, "grid-index": { - "version": "1.1.0", - "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==" + "version": "1.1.0" }, "growly": { "version": "1.3.0", - "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==", "dev": true, "optional": true }, - "gud": { - "version": "1.0.0", - "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" - }, "h3-js": { - "version": "3.7.2", - "integrity": "sha512-LPjlHSwB9zQZrMqKloCZmmmt3yZzIK7nqPcXqwU93zT3TtYG6jP4tZBzAPouxut7lLjdFbMQ75wRBiKfpsnY7w==" + "version": "3.7.2" }, "hammerjs": { - "version": "2.0.8", - "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==" + "version": "2.0.8" }, "handle-thing": { "version": "2.0.1", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true }, "handlebars": { "version": "4.7.7", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "requires": { "minimist": "^1.2.5", "neo-async": "^2.6.0", @@ -69606,19 +73376,16 @@ }, "dependencies": { "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } }, "har-schema": { "version": "2.0.0", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true }, "har-validator": { "version": "5.1.3", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "dev": true, "requires": { "ajv": "^6.5.5", @@ -69627,65 +73394,63 @@ }, "hard-rejection": { "version": "2.1.0", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", "dev": true }, "has": { "version": "1.0.3", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { "function-bind": "^1.1.1" } }, "has-ansi": { "version": "2.0.0", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "requires": { "ansi-regex": "^2.0.0" } }, "has-bigints": { - "version": "1.0.1", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + "version": "1.0.2" }, "has-flag": { - "version": "3.0.0", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + "version": "3.0.0" }, "has-glob": { "version": "1.0.0", - "integrity": "sha512-D+8A457fBShSEI3tFCj65PAbT++5sKiFtdCdOam0gnfBgw9D277OERk+HM9qYJXmdVLZ/znez10SqHN0BBQ50g==", "requires": { "is-glob": "^3.0.0" }, "dependencies": { "is-glob": { "version": "3.1.0", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "requires": { "is-extglob": "^2.1.0" } } } }, + "has-property-descriptors": { + "version": "1.0.0", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1" + }, "has-symbols": { - "version": "1.0.2", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + "version": "1.0.3" }, "has-tostringtag": { "version": "1.0.0", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "requires": { "has-symbols": "^1.0.2" } }, "has-unicode": { - "version": "2.0.1", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + "version": "2.0.1" }, "has-value": { "version": "1.0.0", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "requires": { "get-value": "^2.0.6", "has-values": "^1.0.0", @@ -69694,7 +73459,6 @@ }, "has-values": { "version": "1.0.0", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "requires": { "is-number": "^3.0.0", "kind-of": "^4.0.0" @@ -69702,7 +73466,6 @@ "dependencies": { "kind-of": { "version": "4.0.0", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "requires": { "is-buffer": "^1.1.5" } @@ -69711,7 +73474,6 @@ }, "hash-base": { "version": "3.1.0", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "requires": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", @@ -69719,12 +73481,10 @@ }, "dependencies": { "inherits": { - "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "version": "2.0.4" }, "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -69732,14 +73492,12 @@ } }, "safe-buffer": { - "version": "5.2.1", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "version": "5.2.1" } } }, "hash.js": { "version": "1.1.7", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -69747,7 +73505,6 @@ }, "hast-to-hyperscript": { "version": "9.0.1", - "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", "requires": { "@types/unist": "^2.0.3", "comma-separated-tokens": "^1.0.0", @@ -69759,14 +73516,12 @@ }, "dependencies": { "unist-util-is": { - "version": "4.1.0", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" + "version": "4.1.0" } } }, "hast-util-from-parse5": { "version": "6.0.1", - "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", "requires": { "@types/parse5": "^5.0.0", "hastscript": "^6.0.0", @@ -69777,19 +73532,16 @@ }, "dependencies": { "is-buffer": { - "version": "2.0.5", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + "version": "2.0.5" }, "unist-util-stringify-position": { "version": "2.0.3", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", "requires": { "@types/unist": "^2.0.2" } }, "vfile": { "version": "4.2.1", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", "requires": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", @@ -69798,12 +73550,10 @@ } }, "vfile-location": { - "version": "3.2.0", - "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==" + "version": "3.2.0" }, "vfile-message": { "version": "2.0.4", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", "requires": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^2.0.0" @@ -69812,12 +73562,10 @@ } }, "hast-util-parse-selector": { - "version": "2.2.1", - "integrity": "sha512-Xyh0v+nHmQvrOqop2Jqd8gOdyQtE8sIP9IQf7mlVDqp924W4w/8Liuguk2L2qei9hARnQSG2m+wAOCxM7npJVw==" + "version": "2.2.1" }, "hast-util-raw": { "version": "6.0.1", - "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", "requires": { "@types/hast": "^2.0.0", "hast-util-from-parse5": "^6.0.0", @@ -69832,23 +73580,19 @@ }, "dependencies": { "is-buffer": { - "version": "2.0.5", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + "version": "2.0.5" }, "parse5": { - "version": "6.0.1", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + "version": "6.0.1" }, "unist-util-stringify-position": { "version": "2.0.3", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", "requires": { "@types/unist": "^2.0.2" } }, "vfile": { "version": "4.2.1", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", "requires": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", @@ -69858,7 +73602,6 @@ }, "vfile-message": { "version": "2.0.4", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", "requires": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^2.0.0" @@ -69868,14 +73611,12 @@ }, "hast-util-sanitize": { "version": "4.0.0", - "integrity": "sha512-pw56+69jq+QSr/coADNvWTmBPDy+XsmwaF5KnUys4/wM1jt/fZdl7GPxhXXXYdXnz3Gj3qMkbUCH2uKjvX0MgQ==", "requires": { "@types/hast": "^2.0.0" } }, "hast-util-to-parse5": { "version": "6.0.0", - "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", "requires": { "hast-to-hyperscript": "^9.0.0", "property-information": "^5.0.0", @@ -69885,12 +73626,10 @@ } }, "hast-util-whitespace": { - "version": "2.0.0", - "integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==" + "version": "2.0.0" }, "hastscript": { "version": "6.0.0", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", "requires": { "@types/hast": "^2.0.0", "comma-separated-tokens": "^1.0.0", @@ -69900,16 +73639,13 @@ } }, "he": { - "version": "1.2.0", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + "version": "1.2.0" }, "highlight.js": { - "version": "10.7.3", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" + "version": "10.7.3" }, "history": { "version": "4.10.1", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", "requires": { "@babel/runtime": "^7.1.2", "loose-envify": "^1.2.0", @@ -69921,7 +73657,6 @@ }, "hmac-drbg": { "version": "1.0.1", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -69930,32 +73665,22 @@ }, "hoist-non-react-statics": { "version": "3.3.2", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", "requires": { "react-is": "^16.7.0" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } } }, "homedir-polyfill": { "version": "1.0.3", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, "requires": { "parse-passwd": "^1.0.0" } }, "hosted-git-info": { - "version": "2.8.9", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + "version": "2.8.9" }, "hpack.js": { "version": "2.1.6", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -69965,32 +73690,44 @@ } }, "html-element-map": { - "version": "1.1.0", - "integrity": "sha512-iqiG3dTZmy+uUaTmHarTL+3/A2VW9ox/9uasKEZC+R/wAtUrTcRlXPSaPqsnWPfIu8wqn09jQNwMRqzL54jSYA==", + "version": "1.3.1", "dev": true, "requires": { - "array-filter": "^1.0.0" + "array.prototype.filter": "^1.0.0", + "call-bind": "^1.0.2" } }, "html-encoding-sniffer": { - "version": "2.0.1", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "version": "3.0.0", "dev": true, "requires": { - "whatwg-encoding": "^1.0.5" + "whatwg-encoding": "^2.0.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "whatwg-encoding": { + "version": "2.0.0", + "dev": true, + "requires": { + "iconv-lite": "0.6.3" + } + } } }, "html-entities": { - "version": "2.3.2", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==" + "version": "2.3.2" }, "html-escaper": { - "version": "2.0.2", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + "version": "2.0.2" }, "html-minifier-terser": { "version": "5.1.1", - "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", "requires": { "camel-case": "^4.1.1", "clean-css": "^4.2.3", @@ -70002,23 +73739,19 @@ }, "dependencies": { "commander": { - "version": "4.1.1", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" + "version": "4.1.1" } } }, "html-tags": { "version": "3.2.0", - "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", "dev": true }, "html-void-elements": { - "version": "1.0.5", - "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==" + "version": "1.0.5" }, "html-webpack-plugin": { "version": "5.3.2", - "integrity": "sha512-HvB33boVNCz2lTyBsSiMffsJ+m0YLIQ+pskblXgN9fnjS1BgEcuAfdInfXfGrkdXV406k9FiDi86eVCDBgJOyQ==", "requires": { "@types/html-minifier-terser": "^5.0.0", "html-minifier-terser": "^5.0.1", @@ -70028,14 +73761,12 @@ }, "dependencies": { "tapable": { - "version": "2.2.1", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + "version": "2.2.1" } } }, "htmlparser2": { "version": "3.10.1", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", "dev": true, "requires": { "domelementtype": "^1.3.1", @@ -70048,7 +73779,6 @@ "dependencies": { "readable-stream": { "version": "3.4.0", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -70059,18 +73789,15 @@ } }, "http-cache-semantics": { - "version": "4.1.0", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", "dev": true }, "http-deceiver": { "version": "1.2.7", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", "dev": true }, "http-errors": { "version": "1.6.3", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "requires": { "depd": "~1.1.2", @@ -70080,13 +73807,11 @@ } }, "http-parser-js": { - "version": "0.5.3", - "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", + "version": "0.5.8", "dev": true }, "http-proxy": { "version": "1.18.1", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "requires": { "eventemitter3": "^4.0.0", @@ -70096,7 +73821,6 @@ }, "http-proxy-agent": { "version": "4.0.1", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "dev": true, "requires": { "@tootallnate/once": "1", @@ -70106,7 +73830,6 @@ "dependencies": { "debug": { "version": "4.3.3", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "requires": { "ms": "2.1.2" @@ -70114,17 +73837,15 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "http-proxy-middleware": { - "version": "2.0.1", - "integrity": "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==", + "version": "2.0.6", "dev": true, "requires": { - "@types/http-proxy": "^1.17.5", + "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", @@ -70133,7 +73854,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -70141,7 +73861,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -70149,26 +73868,22 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "is-plain-obj": { "version": "3.0.0", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true }, "micromatch": { - "version": "4.0.4", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -70178,7 +73893,6 @@ }, "http-signature": { "version": "1.2.0", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -70187,12 +73901,10 @@ } }, "https-browserify": { - "version": "1.0.0", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" + "version": "1.0.0" }, "https-proxy-agent": { "version": "5.0.0", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", "dev": true, "requires": { "agent-base": "6", @@ -70201,7 +73913,6 @@ "dependencies": { "debug": { "version": "4.3.3", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "requires": { "ms": "2.1.2" @@ -70209,82 +73920,83 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "human-signals": { "version": "1.1.1", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "devOptional": true + "dev": true }, "humanize-ms": { "version": "1.2.1", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", "dev": true, "requires": { "ms": "^2.0.0" } }, "hyphenate-style-name": { - "version": "1.0.4", - "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + "version": "1.0.4" }, "iconv-lite": { "version": "0.4.24", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "icss-utils": { "version": "5.1.0", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true }, "ieee754": { - "version": "1.2.1", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + "version": "1.2.1" }, "iferr": { - "version": "0.1.5", - "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==" + "version": "0.1.5" }, "ignore": { - "version": "4.0.6", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + "version": "4.0.6" }, "ignore-styles": { "version": "5.0.1", - "integrity": "sha512-gQQmIznCETPLEzfg1UH4Cs2oRq+HBPl8quroEUNXT8oybEG7/0lqI3dGgDSRry6B9HcCXw3PVkFFS0FF3CMddg==", "dev": true }, "ignore-walk": { - "version": "3.0.4", - "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "version": "5.0.1", "dev": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.2", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "image-size": { "version": "0.5.5", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, "optional": true }, "immer": { - "version": "9.0.6", - "integrity": "sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ==" + "version": "9.0.6" }, "immutable": { - "version": "3.8.2", - "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==" + "version": "3.8.2" }, "import-fresh": { "version": "3.3.0", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -70292,7 +74004,6 @@ }, "import-local": { "version": "3.0.2", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", "dev": true, "requires": { "pkg-dir": "^4.2.0", @@ -70301,7 +74012,6 @@ "dependencies": { "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { "locate-path": "^5.0.0", @@ -70310,7 +74020,6 @@ }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { "p-locate": "^4.1.0" @@ -70318,7 +74027,6 @@ }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -70326,7 +74034,6 @@ }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { "p-limit": "^2.2.0" @@ -70334,17 +74041,14 @@ }, "p-try": { "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "path-exists": { "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "pkg-dir": { "version": "4.2.0", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { "find-up": "^4.0.0" @@ -70354,7 +74058,6 @@ }, "imports-loader": { "version": "3.0.0", - "integrity": "sha512-PhDB+rxpc95/1cM8ehxWAcuDIDi3eXhqHhax09iyUeAYBJ2bT6QbBp7aDj8IfU9Ns+2l1K226GhoWVAU823CTA==", "dev": true, "requires": { "source-map": "^0.6.1", @@ -70363,152 +74066,155 @@ "dependencies": { "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, "imurmurhash": { - "version": "0.1.4", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + "version": "0.1.4" }, "indent-string": { - "version": "4.0.0", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + "version": "4.0.0" }, "infer-owner": { - "version": "1.0.4", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + "version": "1.0.4" }, "inflight": { "version": "1.0.6", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" } }, "inherits": { - "version": "2.0.3", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + "version": "2.0.3" }, "ini": { - "version": "1.3.8", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "version": "1.3.8" }, "init-package-json": { - "version": "2.0.5", - "integrity": "sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA==", + "version": "3.0.2", "dev": true, "requires": { - "npm-package-arg": "^8.1.5", + "npm-package-arg": "^9.0.1", "promzard": "^0.3.0", - "read": "~1.0.1", - "read-package-json": "^4.1.1", + "read": "^1.0.7", + "read-package-json": "^5.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^3.0.0" + "validate-npm-package-name": "^4.0.0" }, "dependencies": { - "hosted-git-info": { - "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "builtins": { + "version": "5.0.1", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "semver": "^7.0.0" } }, - "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "hosted-git-info": { + "version": "5.2.1", "dev": true, "requires": { - "yallist": "^4.0.0" + "lru-cache": "^7.5.1" } }, - "normalize-package-data": { - "version": "3.0.3", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "npm-package-arg": { + "version": "9.1.2", "dev": true, "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" } }, - "read-package-json": { - "version": "4.1.1", - "integrity": "sha512-P82sbZJ3ldDrWCOSKxJT0r/CXMWR0OR3KRh55SgKo3p91GSIEEC32v3lSHAvO/UcH3/IoL7uqhOFBduAnwdldw==", + "proc-log": { + "version": "2.0.1", + "dev": true + }, + "semver": { + "version": "7.3.8", "dev": true, "requires": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^3.0.0", - "npm-normalize-package-bin": "^1.0.0" + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } } }, - "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "validate-npm-package-name": { + "version": "4.0.0", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "builtins": "^5.0.0" } }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "inline-style-parser": { - "version": "0.1.1", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + "version": "0.1.1" }, "inline-style-prefixer": { "version": "3.0.8", - "integrity": "sha512-ne8XIyyqkRaNJ1JfL1NYzNdCNxq+MCBQhC8NgOQlzNm2vv3XxlP0VSLQUbSRCF6KPEoveCVEpayHoHzcMyZsMQ==", "requires": { "bowser": "^1.7.3", "css-in-js-utils": "^2.0.0" } }, "inquirer": { - "version": "7.3.3", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "devOptional": true, + "version": "8.2.5", + "dev": true, "requires": { "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", + "chalk": "^4.1.1", "cli-cursor": "^3.1.0", "cli-width": "^3.0.0", "external-editor": "^3.0.3", "figures": "^3.0.0", - "lodash": "^4.17.19", + "lodash": "^4.17.21", "mute-stream": "0.0.8", + "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^6.6.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" }, "dependencies": { "ansi-regex": { "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "devOptional": true + "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "devOptional": true + "dev": true + }, + "rxjs": { + "version": "7.8.0", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "devOptional": true, + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -70517,98 +74223,71 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, + "dev": true, "requires": { "ansi-regex": "^5.0.1" } - } - } - }, - "insert-css": { - "version": "2.0.0", - "integrity": "sha512-xGq5ISgcUP5cvGkS2MMFLtPDBtrtQPSFfC6gA6U8wHKqfjTIMZLZNxOItQnoSjdOzlXOLU/yD32RKC4SvjNbtA==" - }, - "internal-ip": { - "version": "6.2.0", - "integrity": "sha512-D8WGsR6yDt8uq7vDMu7mjcR+yRMm3dW8yufyChmszWRjcSHuxLBkR3GdS2HZAjodsaGuCvXeEJpueisXJULghg==", - "dev": true, - "requires": { - "default-gateway": "^6.0.0", - "ipaddr.js": "^1.9.1", - "is-ip": "^3.1.0", - "p-event": "^4.2.0" - }, - "dependencies": { - "ipaddr.js": { - "version": "1.9.1", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + }, + "tslib": { + "version": "2.4.1", "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } } } }, "internal-slot": { - "version": "1.0.3", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.4", "requires": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.1.3", "has": "^1.0.3", "side-channel": "^1.0.4" } }, "internmap": { - "version": "1.0.1", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + "version": "1.0.1" }, "interpret": { - "version": "2.2.0", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" + "version": "2.2.0" }, "interweave": { - "version": "11.2.0", - "integrity": "sha512-33h9LOXbT52tMin3IyLBPcd5RbiwroP/Sxr0OamnJJU7A/jh0XtZKGvdcSNKYRC7sLZuDk+ZJ2XVrmkcMU5i6w==", + "version": "13.0.0", "requires": { - "@types/react": "*", - "escape-html": "^1.0.3", - "prop-types": "^15.7.2" + "escape-html": "^1.0.3" } }, "invariant": { "version": "2.2.4", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "requires": { "loose-envify": "^1.0.0" } }, "ip": { - "version": "1.1.5", - "integrity": "sha512-rBtCAQAJm8A110nbwn6YdveUnuZH3WrC36IwkRXxDnq53JvXA2NVQvB7IHyKomxK1MJ4VDNw3UtFDdXQ+AvLYA==" - }, - "ip-regex": { - "version": "2.1.0", - "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", - "dev": true + "version": "1.1.5" }, "ipaddr.js": { "version": "2.0.1", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", "dev": true }, "is-absolute-url": { "version": "3.0.3", - "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", "dev": true }, "is-accessor-descriptor": { "version": "0.1.6", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -70616,12 +74295,10 @@ } }, "is-alphabetical": { - "version": "1.0.4", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==" + "version": "1.0.4" }, "is-alphanumerical": { "version": "1.0.2", - "integrity": "sha512-pyfU/0kHdISIgslFfZN9nfY1Gk3MquQgUm1mJTjdkEPpkAKNWuBTSqFwewOpR7N351VkErCiyV71zX7mlQQqsg==", "requires": { "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0" @@ -70629,26 +74306,30 @@ }, "is-arguments": { "version": "1.1.1", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" } }, + "is-array-buffer": { + "version": "3.0.1", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + } + }, "is-arrayish": { - "version": "0.2.1", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + "version": "0.2.1" }, "is-bigint": { "version": "1.0.4", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "requires": { "has-bigints": "^1.0.1" } }, "is-binary-path": { "version": "1.0.1", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", "optional": true, "requires": { "binary-extensions": "^1.0.0" @@ -70656,45 +74337,38 @@ }, "is-boolean-object": { "version": "1.1.2", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" } }, "is-buffer": { - "version": "1.1.6", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "version": "1.1.6" }, "is-callable": { - "version": "1.2.4", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + "version": "1.2.7" }, "is-ci": { "version": "2.0.0", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", "dev": true, "requires": { "ci-info": "^2.0.0" } }, "is-core-module": { - "version": "2.8.0", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.11.0", "requires": { "has": "^1.0.3" } }, "is-data-descriptor": { "version": "0.1.4", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -70702,16 +74376,13 @@ } }, "is-date-object": { - "version": "1.0.1", - "integrity": "sha512-P5rExV1phPi42ppoMWy7V63N3i173RY921l4JJ7zonMSxK+OWGPj76GD+cUKUb68l4vQXcJp2SsG+r/A4ABVzg==" + "version": "1.0.1" }, "is-decimal": { - "version": "1.0.2", - "integrity": "sha512-TRzl7mOCchnhchN+f3ICUCzYvL9ul7R+TYOsZ8xia++knyZAJfv/uA1FvQXsAnYIl1T3B2X5E/J7Wb1QXiIBXg==" + "version": "1.0.2" }, "is-descriptor": { "version": "0.1.6", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", @@ -70719,92 +74390,62 @@ } }, "is-docker": { - "version": "2.2.1", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + "version": "2.2.1" }, "is-dom": { "version": "1.1.0", - "integrity": "sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ==", "requires": { "is-object": "^1.0.1", "is-window": "^1.0.2" } }, "is-extendable": { - "version": "0.1.1", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + "version": "0.1.1" }, "is-extglob": { - "version": "2.1.1", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + "version": "2.1.1" }, "is-fullwidth-code-point": { - "version": "2.0.0", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" + "version": "2.0.0" }, "is-function": { - "version": "1.0.2", - "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" + "version": "1.0.2" }, "is-generator-fn": { "version": "2.1.0", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true }, "is-glob": { "version": "4.0.3", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "requires": { "is-extglob": "^2.1.1" } }, "is-hexadecimal": { - "version": "1.0.2", - "integrity": "sha512-but/G3sapV3MNyqiDBLrOi4x8uCIw0RY3o/Vb5GT0sMFHrVV7731wFSVy41T5FO1og7G0gXLJh0MkgPRouko/A==" + "version": "1.0.2" }, "is-interactive": { "version": "1.0.0", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true }, - "is-ip": { - "version": "3.1.0", - "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==", - "dev": true, - "requires": { - "ip-regex": "^4.0.0" - }, - "dependencies": { - "ip-regex": { - "version": "4.3.0", - "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", - "dev": true - } - } - }, "is-lambda": { "version": "1.0.1", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, "is-map": { - "version": "2.0.2", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" + "version": "2.0.2" }, "is-negative-zero": { - "version": "2.0.1", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + "version": "2.0.2" }, "is-number": { "version": "3.0.0", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -70813,66 +74454,44 @@ }, "is-number-object": { "version": "1.0.6", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", "requires": { "has-tostringtag": "^1.0.0" } }, "is-obj": { "version": "2.0.0", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true }, "is-object": { - "version": "1.0.2", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==" + "version": "1.0.2" }, "is-observable": { "version": "1.1.0", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", "dev": true, "requires": { "symbol-observable": "^1.1.0" } }, - "is-path-cwd": { - "version": "2.2.0", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, "is-plain-obj": { "version": "1.1.0", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==" + "dev": true }, "is-plain-object": { "version": "2.0.4", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "requires": { "isobject": "^3.0.1" } }, "is-potential-custom-element-name": { "version": "1.0.1", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "is-promise": { "version": "2.2.2", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, - "is-redirect": { - "version": "1.0.0", - "integrity": "sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==" - }, "is-regex": { "version": "1.1.4", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -70880,125 +74499,107 @@ }, "is-resolvable": { "version": "1.1.0", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, "is-retina": { - "version": "1.0.3", - "integrity": "sha512-/tCmbIETZwCd8uHWO+GvbRa7jxwHFHdfetHfiwoP0aN9UDf3prUJMtKn7iBFYipYhqY1bSTjur8hC/Dakt8eyw==" - }, - "is-retry-allowed": { - "version": "1.2.0", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" + "version": "1.0.3" }, "is-set": { - "version": "2.0.2", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" + "version": "2.0.2" }, "is-shared-array-buffer": { - "version": "1.0.1", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" + "version": "1.0.2", + "requires": { + "call-bind": "^1.0.2" + } }, "is-ssh": { - "version": "1.3.3", - "integrity": "sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ==", + "version": "1.4.0", "dev": true, "requires": { - "protocols": "^1.1.0" + "protocols": "^2.0.1" } }, "is-stream": { - "version": "1.1.0", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==" + "version": "1.1.0" }, "is-string": { "version": "1.0.7", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "requires": { "has-tostringtag": "^1.0.0" } }, "is-subset": { "version": "0.1.1", - "integrity": "sha512-6Ybun0IkarhmEqxXCNw/C0bna6Zb/TkfUX9UbwJtK6ObwAVCxmAP308WWTHviM/zAqXk05cdhYsUsZeGQh99iw==", "dev": true }, "is-symbol": { "version": "1.0.4", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "requires": { "has-symbols": "^1.0.2" } }, "is-text-path": { "version": "1.0.1", - "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", "dev": true, "requires": { "text-extensions": "^1.0.0" } }, + "is-typed-array": { + "version": "1.1.10", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "is-unicode-supported": { "version": "0.1.0", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, - "is-utf8": { - "version": "0.2.1", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", - "optional": true - }, "is-weakref": { - "version": "1.0.1", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "version": "1.0.2", "requires": { - "call-bind": "^1.0.0" + "call-bind": "^1.0.2" } }, "is-whitespace-character": { - "version": "1.0.4", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==" + "version": "1.0.4" }, "is-window": { - "version": "1.0.2", - "integrity": "sha512-uj00kdXyZb9t9RcAUAwMZAnkBUwdYGhYlt7djMXhfyhUCzwNba50tIiBKR7q0l7tdoBtFVw/3JmLY6fI3rmZmg==" + "version": "1.0.2" }, "is-windows": { - "version": "1.0.2", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + "version": "1.0.2" }, "is-word-character": { - "version": "1.0.4", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==" + "version": "1.0.4" }, "is-wsl": { - "version": "1.1.0", - "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==" + "version": "1.1.0" }, "isarray": { - "version": "1.0.0", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "version": "1.0.0" }, "isbinaryfile": { "version": "4.0.8", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==" + "dev": true }, "isexe": { - "version": "2.0.0", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "version": "2.0.0" }, "isobject": { - "version": "3.0.1", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + "version": "3.0.1" }, "isomorphic-fetch": { "version": "2.2.1", - "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==", "requires": { "node-fetch": "^1.0.1", "whatwg-fetch": ">=0.10.0" @@ -71006,7 +74607,6 @@ "dependencies": { "node-fetch": { "version": "1.7.3", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { "encoding": "^0.1.11", "is-stream": "^1.0.1" @@ -71016,16 +74616,13 @@ }, "isstream": { "version": "0.1.2", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "istanbul-lib-coverage": { - "version": "3.0.0", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==" + "version": "3.0.0" }, "istanbul-lib-instrument": { "version": "4.0.3", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", "dev": true, "requires": { "@babel/core": "^7.7.5", @@ -71036,14 +74633,12 @@ "dependencies": { "semver": { "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "istanbul-lib-report": { "version": "3.0.0", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "requires": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", @@ -71052,20 +74647,17 @@ "dependencies": { "make-dir": { "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "requires": { "semver": "^6.0.0" } }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" } } }, "istanbul-lib-source-maps": { "version": "4.0.0", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", "dev": true, "requires": { "debug": "^4.1.1", @@ -71075,7 +74667,6 @@ "dependencies": { "debug": { "version": "4.3.1", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -71083,106 +74674,50 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, "istanbul-reports": { "version": "3.0.2", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", "requires": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, - "istextorbinary": { - "version": "2.6.0", - "integrity": "sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==", - "requires": { - "binaryextensions": "^2.1.2", - "editions": "^2.2.0", - "textextensions": "^2.5.0" - }, - "dependencies": { - "binaryextensions": { - "version": "2.3.0", - "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==" - }, - "textextensions": { - "version": "2.6.0", - "integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==" - } - } - }, "iterate-iterator": { - "version": "1.0.2", - "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==" + "version": "1.0.2" }, "iterate-value": { "version": "1.0.2", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", "requires": { "es-get-iterator": "^1.0.2", "iterate-iterator": "^1.0.1" } }, "jake": { - "version": "10.8.2", - "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "version": "10.8.5", + "dev": true, "requires": { - "async": "0.9.x", - "chalk": "^2.4.2", + "async": "^3.2.3", + "chalk": "^4.0.2", "filelist": "^1.0.1", "minimatch": "^3.0.4" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "async": { - "version": "0.9.2", - "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==" - }, - "chalk": { - "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } } }, "java-properties": { "version": "1.0.2", - "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", "dev": true }, "jed": { - "version": "1.1.1", - "integrity": "sha512-z35ZSEcXHxLW4yumw0dF6L464NT36vmx3wxJw8MDpraBcWuNVgUPZgPJKcu1HekNgwlMFNqol7i/IpSbjhqwqA==" + "version": "1.1.1" }, "jest": { "version": "26.6.3", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", "dev": true, "requires": { "@jest/core": "^26.6.3", @@ -71192,7 +74727,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -71200,7 +74734,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -71208,12 +74741,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-cli": { "version": "26.6.3", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", "dev": true, "requires": { "@jest/core": "^26.6.3", @@ -71233,7 +74764,6 @@ }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -71246,7 +74776,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -71255,7 +74784,6 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -71265,7 +74793,6 @@ }, "jest-changed-files": { "version": "26.6.2", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -71275,7 +74802,6 @@ "dependencies": { "cross-spawn": { "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -71285,7 +74811,6 @@ }, "execa": { "version": "4.1.0", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, "requires": { "cross-spawn": "^7.0.0", @@ -71301,7 +74826,6 @@ }, "get-stream": { "version": "5.2.0", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "requires": { "pump": "^3.0.0" @@ -71309,12 +74833,10 @@ }, "is-stream": { "version": "2.0.0", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, "npm-run-path": { "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { "path-key": "^3.0.0" @@ -71322,12 +74844,10 @@ }, "path-key": { "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "shebang-command": { "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" @@ -71335,12 +74855,10 @@ }, "shebang-regex": { "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -71350,7 +74868,6 @@ }, "jest-config": { "version": "26.6.3", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", "dev": true, "requires": { "@babel/core": "^7.1.0", @@ -71375,7 +74892,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -71383,12 +74899,10 @@ }, "deepmerge": { "version": "4.2.2", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -71396,12 +74910,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -71414,7 +74926,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -71423,7 +74934,6 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -71433,7 +74943,6 @@ }, "jest-diff": { "version": "26.6.2", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", "dev": true, "requires": { "chalk": "^4.0.0", @@ -71444,7 +74953,6 @@ }, "jest-docblock": { "version": "26.0.0", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", "dev": true, "requires": { "detect-newline": "^3.0.0" @@ -71452,7 +74960,6 @@ }, "jest-each": { "version": "26.6.2", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -71464,7 +74971,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -71472,7 +74978,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -71480,12 +74985,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -71498,7 +75001,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -71507,7 +75009,6 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -71517,7 +75018,6 @@ }, "jest-environment-enzyme": { "version": "7.1.2", - "integrity": "sha512-3tfaYAzO7qZSRrv+srQnfK16Vu5XwH/pHi8FpoqSHjKKngbHzXf7aBCBuWh8y3w0OtknHRfDMFrC60Khj+g1hA==", "dev": true, "requires": { "jest-environment-jsdom": "^24.0.0" @@ -71525,7 +75025,6 @@ "dependencies": { "@jest/console": { "version": "24.9.0", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", "dev": true, "requires": { "@jest/source-map": "^24.9.0", @@ -71535,7 +75034,6 @@ }, "@jest/environment": { "version": "24.9.0", - "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", "dev": true, "requires": { "@jest/fake-timers": "^24.9.0", @@ -71546,7 +75044,6 @@ }, "@jest/fake-timers": { "version": "24.9.0", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", "dev": true, "requires": { "@jest/types": "^24.9.0", @@ -71556,7 +75053,6 @@ }, "@jest/source-map": { "version": "24.9.0", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", "dev": true, "requires": { "callsites": "^3.0.0", @@ -71566,7 +75062,6 @@ }, "@jest/test-result": { "version": "24.9.0", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", "dev": true, "requires": { "@jest/console": "^24.9.0", @@ -71576,7 +75071,6 @@ }, "@jest/transform": { "version": "24.9.0", - "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", "dev": true, "requires": { "@babel/core": "^7.1.0", @@ -71599,7 +75093,6 @@ }, "@jest/types": { "version": "24.9.0", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -71609,7 +75102,6 @@ }, "@types/yargs": { "version": "13.0.9", - "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -71617,12 +75109,10 @@ }, "acorn": { "version": "5.7.4", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", "dev": true }, "acorn-globals": { "version": "4.3.4", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", "dev": true, "requires": { "acorn": "^6.0.1", @@ -71631,19 +75121,16 @@ "dependencies": { "acorn": { "version": "6.4.1", - "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", "dev": true } } }, "acorn-walk": { "version": "6.2.0", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", "dev": true }, "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -71651,7 +75138,6 @@ }, "babel-plugin-istanbul": { "version": "5.2.0", - "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -71662,7 +75148,6 @@ }, "chalk": { "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -71672,12 +75157,10 @@ }, "cssom": { "version": "0.3.8", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, "cssstyle": { "version": "1.4.0", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", "dev": true, "requires": { "cssom": "0.3.x" @@ -71685,7 +75168,6 @@ }, "data-urls": { "version": "1.1.0", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", "dev": true, "requires": { "abab": "^2.0.0", @@ -71695,7 +75177,6 @@ "dependencies": { "whatwg-url": { "version": "7.1.0", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", "dev": true, "requires": { "lodash.sortby": "^4.7.0", @@ -71707,7 +75188,6 @@ }, "domexception": { "version": "1.0.1", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", "dev": true, "requires": { "webidl-conversions": "^4.0.2" @@ -71715,7 +75195,6 @@ }, "find-up": { "version": "3.0.0", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { "locate-path": "^3.0.0" @@ -71723,7 +75202,6 @@ }, "html-encoding-sniffer": { "version": "1.0.2", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", "dev": true, "requires": { "whatwg-encoding": "^1.0.1" @@ -71731,12 +75209,10 @@ }, "istanbul-lib-coverage": { "version": "2.0.5", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", "dev": true }, "istanbul-lib-instrument": { "version": "3.3.0", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", "dev": true, "requires": { "@babel/generator": "^7.4.0", @@ -71750,7 +75226,6 @@ }, "jest-environment-jsdom": { "version": "24.9.0", - "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", "dev": true, "requires": { "@jest/environment": "^24.9.0", @@ -71763,7 +75238,6 @@ }, "jest-haste-map": { "version": "24.9.0", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", "dev": true, "requires": { "@jest/types": "^24.9.0", @@ -71782,7 +75256,6 @@ }, "jest-message-util": { "version": "24.9.0", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -71797,7 +75270,6 @@ }, "jest-mock": { "version": "24.9.0", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", "dev": true, "requires": { "@jest/types": "^24.9.0" @@ -71805,17 +75277,14 @@ }, "jest-regex-util": { "version": "24.9.0", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", "dev": true }, "jest-serializer": { "version": "24.9.0", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", "dev": true }, "jest-util": { "version": "24.9.0", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", "dev": true, "requires": { "@jest/console": "^24.9.0", @@ -71834,7 +75303,6 @@ }, "jest-worker": { "version": "24.9.0", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", "dev": true, "requires": { "merge-stream": "^2.0.0", @@ -71843,7 +75311,6 @@ "dependencies": { "supports-color": { "version": "6.1.0", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -71853,7 +75320,6 @@ }, "jsdom": { "version": "11.12.0", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", "dev": true, "requires": { "abab": "^2.0.0", @@ -71886,7 +75352,6 @@ }, "locate-path": { "version": "3.0.0", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { "p-locate": "^3.0.0", @@ -71895,7 +75360,6 @@ }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -71903,7 +75367,6 @@ }, "p-locate": { "version": "3.0.0", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { "p-limit": "^2.0.0" @@ -71911,17 +75374,14 @@ }, "p-try": { "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "parse5": { "version": "4.0.0", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", "dev": true }, "read-pkg": { "version": "3.0.0", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, "requires": { "load-json-file": "^4.0.0", @@ -71931,7 +75391,6 @@ }, "read-pkg-up": { "version": "4.0.0", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", "dev": true, "requires": { "find-up": "^3.0.0", @@ -71940,22 +75399,18 @@ }, "semver": { "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "stack-utils": { "version": "1.0.2", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", "dev": true }, "supports-color": { "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -71963,7 +75418,6 @@ }, "test-exclude": { "version": "5.2.3", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", "dev": true, "requires": { "glob": "^7.1.3", @@ -71974,7 +75428,6 @@ }, "write-file-atomic": { "version": "2.4.1", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -71984,7 +75437,6 @@ }, "ws": { "version": "5.2.3", - "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", "dev": true, "requires": { "async-limiter": "~1.0.0" @@ -71994,7 +75446,6 @@ }, "jest-environment-jsdom": { "version": "26.6.2", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", "dev": true, "requires": { "@jest/environment": "^26.6.2", @@ -72008,28 +75459,85 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" } }, + "cssom": { + "version": "0.4.4", + "dev": true + }, + "data-urls": { + "version": "2.0.0", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "domexception": { + "version": "2.0.1", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "dev": true + } + } + }, + "escodegen": { + "version": "2.0.0", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "4.0.1", + "dev": true + }, + "estraverse": { + "version": "5.3.0", + "dev": true + }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" } }, + "form-data": { + "version": "3.0.1", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "html-encoding-sniffer": { + "version": "2.0.1", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72040,28 +75548,107 @@ "micromatch": "^4.0.2" } }, + "jsdom": { + "version": "16.7.0", + "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" + } + }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.0.5" } }, + "parse5": { + "version": "6.0.1", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "dev": true, + "optional": true + }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" } + }, + "tough-cookie": { + "version": "4.0.0", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + } + }, + "tr46": { + "version": "2.1.0", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "universalify": { + "version": "0.1.2", + "dev": true + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } } } }, "jest-environment-node": { "version": "26.6.2", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", "dev": true, "requires": { "@jest/environment": "^26.6.2", @@ -72074,7 +75661,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -72082,7 +75668,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -72090,12 +75675,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72108,7 +75691,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -72117,7 +75699,6 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -72127,7 +75708,6 @@ }, "jest-enzyme": { "version": "7.1.2", - "integrity": "sha512-j+jkph3t5hGBS12eOldpfsnERYRCHi4c/0KWPMnqRPoJJXvCpLIc5th1MHl0xDznQDXVU0AHUXg3rqMrf8vGpA==", "dev": true, "requires": { "enzyme-matchers": "^7.1.2", @@ -72137,12 +75717,10 @@ }, "jest-get-type": { "version": "26.3.0", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", "dev": true }, "jest-haste-map": { "version": "26.6.2", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72163,7 +75741,6 @@ "dependencies": { "anymatch": { "version": "3.1.1", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -72172,7 +75749,6 @@ }, "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -72180,7 +75756,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -72188,12 +75763,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72206,7 +75779,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -72215,12 +75787,10 @@ }, "normalize-path": { "version": "3.0.0", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -72230,7 +75800,6 @@ }, "jest-jasmine2": { "version": "26.6.3", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", "dev": true, "requires": { "@babel/traverse": "^7.1.0", @@ -72255,7 +75824,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -72263,7 +75831,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -72271,12 +75838,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72289,7 +75854,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -72298,7 +75862,6 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -72308,7 +75871,6 @@ }, "jest-leak-detector": { "version": "26.6.2", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", "dev": true, "requires": { "jest-get-type": "^26.3.0", @@ -72317,7 +75879,6 @@ }, "jest-matcher-utils": { "version": "26.6.2", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", "dev": true, "requires": { "chalk": "^4.0.0", @@ -72328,7 +75889,6 @@ }, "jest-message-util": { "version": "26.6.2", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -72344,12 +75904,10 @@ "dependencies": { "@types/stack-utils": { "version": "2.0.0", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", "dev": true }, "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -72357,7 +75915,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -72365,12 +75922,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -72379,12 +75934,10 @@ }, "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -72394,7 +75947,6 @@ }, "jest-mock": { "version": "26.6.2", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72403,17 +75955,14 @@ }, "jest-pnp-resolver": { "version": "1.2.2", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", "dev": true }, "jest-regex-util": { "version": "26.0.0", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", "dev": true }, "jest-resolve": { "version": "26.6.2", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72428,7 +75977,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -72436,7 +75984,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -72444,12 +75991,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72462,7 +76007,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -72471,12 +76015,10 @@ }, "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -72486,7 +76028,6 @@ }, "jest-resolve-dependencies": { "version": "26.6.3", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72496,7 +76037,6 @@ }, "jest-runner": { "version": "26.6.3", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", "dev": true, "requires": { "@jest/console": "^26.6.2", @@ -72523,7 +76063,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -72531,7 +76070,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -72539,12 +76077,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72557,7 +76093,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -72566,7 +76101,6 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -72576,7 +76110,6 @@ }, "jest-runtime": { "version": "26.6.3", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", "dev": true, "requires": { "@jest/console": "^26.6.2", @@ -72610,7 +76143,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -72618,7 +76150,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -72626,12 +76157,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72644,7 +76173,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -72653,17 +76181,14 @@ }, "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "strip-bom": { "version": "4.0.0", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -72673,7 +76198,6 @@ }, "jest-serializer": { "version": "26.6.2", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", "dev": true, "requires": { "@types/node": "*", @@ -72682,7 +76206,6 @@ }, "jest-snapshot": { "version": "26.6.2", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", "dev": true, "requires": { "@babel/types": "^7.0.0", @@ -72705,14 +76228,12 @@ "dependencies": { "semver": { "version": "7.3.2", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true } } }, "jest-validate": { "version": "26.6.2", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72725,14 +76246,12 @@ "dependencies": { "camelcase": { "version": "6.2.0", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true } } }, "jest-watcher": { "version": "26.6.2", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", "dev": true, "requires": { "@jest/test-result": "^26.6.2", @@ -72746,7 +76265,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -72754,7 +76272,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -72762,12 +76279,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "jest-util": { "version": "26.6.2", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -72780,7 +76295,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -72789,7 +76303,6 @@ }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -72799,25 +76312,25 @@ }, "jest-websocket-mock": { "version": "2.2.0", - "integrity": "sha512-lc3wwXOEyNa4ZpcgJtUG3mmKMAq5FAsKYiZph0p/+PAJrAPuX4JCIfJMdJ/urRsLBG51fwm/wlVPNbR6s2nzNw==", "dev": true }, "jest-worker": { "version": "26.6.2", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "requires": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^7.0.0" } }, + "jpeg-js": { + "version": "0.4.4", + "dev": true + }, "jquery": { - "version": "3.6.0", - "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + "version": "3.6.0" }, "js-beautify": { "version": "1.14.0", - "integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==", "requires": { "config-chain": "^1.1.12", "editorconfig": "^0.15.3", @@ -72826,34 +76339,31 @@ } }, "js-levenshtein": { - "version": "1.1.6", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==" + "version": "1.1.6" + }, + "js-sha3": { + "version": "0.8.0" }, "js-string-escape": { - "version": "1.0.1", - "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==" + "version": "1.0.1" }, "js-tokens": { - "version": "4.0.0", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "version": "4.0.0" }, "js-yaml": { "version": "3.13.1", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "dependencies": { "esprima": { - "version": "4.0.1", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "version": "4.0.1" } } }, "js-yaml-loader": { "version": "1.2.2", - "integrity": "sha512-H+NeuNrG6uOs/WMjna2SjkaCw13rMWiT/D7l9+9x5n8aq88BDsh2sRmdfxckWPIHtViYHWRG6XiCKYvS1dfyLg==", "requires": { "js-yaml": "^3.13.1", "loader-utils": "^1.2.3", @@ -72862,54 +76372,62 @@ }, "jsbn": { "version": "0.1.1", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "jsdom": { - "version": "16.4.0", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "version": "20.0.0", "dev": true, "requires": { - "abab": "^2.0.3", - "acorn": "^7.1.1", + "abab": "^2.0.6", + "acorn": "^8.7.1", "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.2.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", - "domexception": "^2.0.1", - "escodegen": "^1.14.1", - "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.3.1", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.0", - "parse5": "5.1.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", + "parse5": "^7.0.0", + "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", + "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.0.0", - "ws": "^7.2.3", - "xml-name-validator": "^3.0.0" + "w3c-xmlserializer": "^3.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.8.0", + "xml-name-validator": "^4.0.0" }, "dependencies": { - "acorn": { - "version": "7.4.1", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "@tootallnate/once": { + "version": "2.0.0", + "dev": true + }, + "debug": { + "version": "4.3.4", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "entities": { + "version": "4.3.1", "dev": true }, "escodegen": { - "version": "1.14.3", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.0.0", "dev": true, "requires": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", + "estraverse": "^5.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1", "source-map": "~0.6.1" @@ -72917,122 +76435,182 @@ }, "esprima": { "version": "4.0.1", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "parse5": { - "version": "5.1.1", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "estraverse": { + "version": "5.3.0", + "dev": true + }, + "form-data": { + "version": "4.0.0", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.6.3", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ms": { + "version": "2.1.2", "dev": true }, + "parse5": { + "version": "7.0.0", + "dev": true, + "requires": { + "entities": "^4.3.0" + } + }, + "saxes": { + "version": "6.0.0", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true }, "tough-cookie": { - "version": "3.0.1", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "version": "4.0.0", "dev": true, "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" } }, "tr46": { - "version": "2.0.2", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "version": "3.0.0", "dev": true, "requires": { "punycode": "^2.1.1" } }, + "universalify": { + "version": "0.1.2", + "dev": true + }, "webidl-conversions": { - "version": "6.1.0", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "version": "7.0.0", + "dev": true + }, + "whatwg-encoding": { + "version": "2.0.0", + "dev": true, + "requires": { + "iconv-lite": "0.6.3" + } + }, + "whatwg-mimetype": { + "version": "3.0.0", "dev": true }, "whatwg-url": { - "version": "8.4.0", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "11.0.0", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^6.1.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" } + }, + "ws": { + "version": "8.8.0", + "dev": true + }, + "xml-name-validator": { + "version": "4.0.0", + "dev": true } } }, "jsep": { - "version": "0.3.5", - "integrity": "sha512-AoRLBDc6JNnKjNcmonituEABS5bcfqDhQAWWXNTFrqu6nVXBpBAGfcoTGZMFlIrh9FjmE1CQyX9CTNwZrXMMDA==" + "version": "0.3.5" }, "jsesc": { - "version": "2.5.2", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "version": "2.5.2" }, "json-bigint": { "version": "1.0.0", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "requires": { "bignumber.js": "^9.0.0" } }, "json-bignum": { - "version": "0.0.3", - "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==" + "version": "0.0.3" }, "json-parse-better-errors": { - "version": "1.0.2", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + "version": "1.0.2" }, "json-parse-even-better-errors": { - "version": "2.3.1", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + "version": "2.3.1" }, "json-schema": { - "version": "0.2.3", - "integrity": "sha512-a3xHnILGMtk+hDOqNwHzF6e2fNbiMrXZvxKQiEv2MlgQP+pjIOzqAmKYD2mDpXYE/44M7g+n9p2bKkYWDUcXCQ==", + "version": "0.4.0", "dev": true }, "json-schema-traverse": { - "version": "0.4.1", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "version": "0.4.1" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json-stringify-nice": { + "version": "1.1.4", "dev": true }, "json-stringify-pretty-compact": { - "version": "2.0.0", - "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==" + "version": "2.0.0" }, "json-stringify-safe": { "version": "5.0.1", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, "json2mq": { "version": "0.2.0", - "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", "requires": { "string-convert": "^0.2.0" } }, "json5": { - "version": "1.0.1", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", "requires": { "minimist": "^1.2.0" } }, + "jsonc-parser": { + "version": "3.2.0", + "dev": true + }, "jsonfile": { "version": "6.1.0", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" @@ -73040,32 +76618,28 @@ }, "jsonparse": { "version": "1.3.1", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "devOptional": true + "dev": true }, "JSONStream": { "version": "1.3.5", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "devOptional": true, + "dev": true, "requires": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" } }, "jsprim": { - "version": "1.4.1", - "integrity": "sha512-4Dj8Rf+fQ+/Pn7C5qeEX02op1WfOss3PKTE9Nsop3Dx+6UPxlm1dr/og7o2cRa5hNN07CACr4NFzRLtj/rjWog==", + "version": "1.4.2", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" } }, "jsx-ast-utils": { "version": "3.2.2", - "integrity": "sha512-HDAyJ4MNQBboGpUnHAVUNJs6X0lh058s6FuixsFGP7MgJYpD6Vasd6nzSG5iIfXu1zAYlHJ/zsOKNlrenTUBnw==", "dev": true, "requires": { "array-includes": "^3.1.4", @@ -73074,7 +76648,6 @@ }, "junit-report-builder": { "version": "2.1.0", - "integrity": "sha512-Ioj5I4w18ZcHFaaisqCKdh1z+ipzN7sA2JB+h+WOlGcOMWm0FFN1dfxkgc2I4EXfhSP/mOfM3W43uFzEdz4sTw==", "dev": true, "requires": { "date-format": "0.0.2", @@ -73085,7 +76658,6 @@ "dependencies": { "make-dir": { "version": "1.3.0", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { "pify": "^3.0.0" @@ -73094,61 +76666,43 @@ } }, "junk": { - "version": "3.1.0", - "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==" + "version": "3.1.0" }, "just-extend": { "version": "4.1.0", - "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", "dev": true }, "kdbush": { - "version": "3.0.0", - "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==" + "version": "3.0.0" }, "kind-of": { - "version": "5.1.0", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + "version": "5.1.0" }, "klaw": { "version": "1.3.1", - "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", "requires": { "graceful-fs": "^4.1.9" } }, "kleur": { - "version": "3.0.3", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + "version": "3.0.3" }, "klona": { - "version": "2.0.5", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==" + "version": "2.0.5" }, "language-subtag-registry": { "version": "0.3.21", - "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", "dev": true }, "language-tags": { "version": "1.0.5", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", "dev": true, "requires": { "language-subtag-registry": "~0.3.2" } }, - "lazy-cache": { - "version": "2.0.2", - "integrity": "sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==", - "optional": true, - "requires": { - "set-getter": "^0.1.0" - } - }, "lazy-universal-dotenv": { "version": "3.0.1", - "integrity": "sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==", "requires": { "@babel/runtime": "^7.5.0", "app-root-dir": "^1.0.2", @@ -73159,37 +76713,39 @@ }, "left-pad": { "version": "1.3.0", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", "dev": true }, "lerna": { - "version": "4.0.0", - "integrity": "sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg==", - "dev": true, - "requires": { - "@lerna/add": "4.0.0", - "@lerna/bootstrap": "4.0.0", - "@lerna/changed": "4.0.0", - "@lerna/clean": "4.0.0", - "@lerna/cli": "4.0.0", - "@lerna/create": "4.0.0", - "@lerna/diff": "4.0.0", - "@lerna/exec": "4.0.0", - "@lerna/import": "4.0.0", - "@lerna/info": "4.0.0", - "@lerna/init": "4.0.0", - "@lerna/link": "4.0.0", - "@lerna/list": "4.0.0", - "@lerna/publish": "4.0.0", - "@lerna/run": "4.0.0", - "@lerna/version": "4.0.0", + "version": "6.1.0", + "dev": true, + "requires": { + "@lerna/add": "6.1.0", + "@lerna/bootstrap": "6.1.0", + "@lerna/changed": "6.1.0", + "@lerna/clean": "6.1.0", + "@lerna/cli": "6.1.0", + "@lerna/command": "6.1.0", + "@lerna/create": "6.1.0", + "@lerna/diff": "6.1.0", + "@lerna/exec": "6.1.0", + "@lerna/import": "6.1.0", + "@lerna/info": "6.1.0", + "@lerna/init": "6.1.0", + "@lerna/link": "6.1.0", + "@lerna/list": "6.1.0", + "@lerna/publish": "6.1.0", + "@lerna/run": "6.1.0", + "@lerna/version": "6.1.0", + "@nrwl/devkit": ">=14.8.6 < 16", "import-local": "^3.0.2", - "npmlog": "^4.1.2" + "inquirer": "^8.2.4", + "npmlog": "^6.0.2", + "nx": ">=14.8.6 < 16", + "typescript": "^3 || ^4" } }, "less": { "version": "3.12.2", - "integrity": "sha512-+1V2PCMFkL+OIj2/HrtrvZw0BC0sYLMICJfbQjuj/K8CEnlrFX6R5cKKgzzttsZDHyxQNL1jqMREjKN3ja/E3Q==", "dev": true, "requires": { "errno": "^0.1.1", @@ -73204,7 +76760,6 @@ "dependencies": { "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -73212,7 +76767,6 @@ }, "less-loader": { "version": "10.2.0", - "integrity": "sha512-AV5KHWvCezW27GT90WATaDnfXBv99llDbtaj4bshq6DvAihMdNjaPDcUMa6EXKLRF+P2opFenJp89BXg91XLYg==", "dev": true, "requires": { "klona": "^2.0.4" @@ -73220,109 +76774,234 @@ }, "leven": { "version": "3.1.0", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true }, "levn": { "version": "0.3.0", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" } }, "libnpmaccess": { - "version": "4.0.3", - "integrity": "sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ==", + "version": "6.0.4", "dev": true, "requires": { "aproba": "^2.0.0", "minipass": "^3.1.1", - "npm-package-arg": "^8.1.2", - "npm-registry-fetch": "^11.0.0" + "npm-package-arg": "^9.0.1", + "npm-registry-fetch": "^13.0.0" }, "dependencies": { "aproba": { "version": "2.0.0", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "builtins": { + "version": "5.0.1", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "hosted-git-info": { + "version": "5.2.1", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "lru-cache": { + "version": "7.14.1", + "dev": true + }, + "minipass-fetch": { + "version": "2.1.2", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "npm-registry-fetch": { + "version": "13.3.1", + "dev": true, + "requires": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + } + }, + "proc-log": { + "version": "2.0.1", + "dev": true + }, + "semver": { + "version": "7.3.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + }, + "yallist": { + "version": "4.0.0", "dev": true } } }, "libnpmpublish": { - "version": "4.0.2", - "integrity": "sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw==", + "version": "6.0.5", "dev": true, "requires": { - "normalize-package-data": "^3.0.2", - "npm-package-arg": "^8.1.2", - "npm-registry-fetch": "^11.0.0", - "semver": "^7.1.3", - "ssri": "^8.0.1" + "normalize-package-data": "^4.0.0", + "npm-package-arg": "^9.0.1", + "npm-registry-fetch": "^13.0.0", + "semver": "^7.3.7", + "ssri": "^9.0.0" }, "dependencies": { + "builtins": { + "version": "5.0.1", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, "hosted-git-info": { - "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "version": "5.2.1", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "lru-cache": "^7.5.1" } }, "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "7.14.1", + "dev": true + }, + "minipass-fetch": { + "version": "2.1.2", "dev": true, "requires": { - "yallist": "^4.0.0" + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" } }, "normalize-package-data": { - "version": "3.0.3", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "version": "4.0.1", "dev": true, "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" } }, + "npm-package-arg": { + "version": "9.1.2", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "npm-registry-fetch": { + "version": "13.3.1", + "dev": true, + "requires": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + } + }, + "proc-log": { + "version": "2.0.1", + "dev": true + }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } } }, "ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "version": "9.0.1", "dev": true, "requires": { "minipass": "^3.1.1" } }, + "validate-npm-package-name": { + "version": "4.0.0", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "lilconfig": { "version": "2.0.3", - "integrity": "sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg==", "dev": true }, "lines-and-columns": { - "version": "1.1.6", - "integrity": "sha512-8ZmlJFVK9iCmtLz19HpSsR8HaAMWBT284VMNednLwlIMDP2hJDCIhUp0IZ2xUcZ+Ob6BM0VvCSJwzASDM45NLQ==" + "version": "1.1.6" }, "listr": { "version": "0.14.3", - "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", "dev": true, "requires": { "@samverschueren/stream-to-observable": "^0.3.0", @@ -73338,19 +77017,16 @@ "dependencies": { "p-map": { "version": "2.1.0", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", "dev": true } } }, "listr-silent-renderer": { "version": "1.1.1", - "integrity": "sha512-L26cIFm7/oZeSNVhWB6faeorXhMg4HNlb/dS/7jHhr708jxlXrtrBWo4YUxZQkc6dGoxEAe6J/D3juTRBUzjtA==", "dev": true }, "listr-update-renderer": { "version": "0.5.0", - "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -73365,22 +77041,18 @@ "dependencies": { "ansi-escapes": { "version": "3.2.0", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, "ansi-regex": { - "version": "3.0.0", - "integrity": "sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==", + "version": "3.0.1", "dev": true }, "ansi-styles": { "version": "2.2.1", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { "version": "1.1.3", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -73392,7 +77064,6 @@ }, "cli-cursor": { "version": "2.1.0", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", "dev": true, "requires": { "restore-cursor": "^2.0.0" @@ -73400,7 +77071,6 @@ }, "cli-truncate": { "version": "0.2.1", - "integrity": "sha512-f4r4yJnbT++qUPI9NR4XLDLq41gQ+uqnPItWG0F5ZkehuNiTTa3EY0S4AqTSUOeJ7/zU41oWPQSNkW5BqPL9bg==", "dev": true, "requires": { "slice-ansi": "0.0.4", @@ -73409,7 +77079,6 @@ }, "figures": { "version": "1.7.0", - "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", "dev": true, "requires": { "escape-string-regexp": "^1.0.5", @@ -73418,12 +77087,10 @@ }, "indent-string": { "version": "3.2.0", - "integrity": "sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ==", "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "dev": true, "requires": { "number-is-nan": "^1.0.0" @@ -73431,7 +77098,6 @@ }, "log-symbols": { "version": "1.0.2", - "integrity": "sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ==", "dev": true, "requires": { "chalk": "^1.0.0" @@ -73439,7 +77105,6 @@ }, "log-update": { "version": "2.3.0", - "integrity": "sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg==", "dev": true, "requires": { "ansi-escapes": "^3.0.0", @@ -73449,12 +77114,10 @@ }, "mimic-fn": { "version": "1.2.0", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "onetime": { "version": "2.0.1", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", "dev": true, "requires": { "mimic-fn": "^1.0.0" @@ -73462,7 +77125,6 @@ }, "restore-cursor": { "version": "2.0.0", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", "dev": true, "requires": { "onetime": "^2.0.0", @@ -73471,12 +77133,10 @@ }, "slice-ansi": { "version": "0.0.4", - "integrity": "sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw==", "dev": true }, "string-width": { "version": "1.0.2", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -73486,12 +77146,10 @@ }, "supports-color": { "version": "2.0.0", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true }, "wrap-ansi": { "version": "3.0.1", - "integrity": "sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ==", "dev": true, "requires": { "string-width": "^2.1.1", @@ -73500,12 +77158,10 @@ "dependencies": { "is-fullwidth-code-point": { "version": "2.0.0", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", "dev": true }, "string-width": { "version": "2.1.1", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -73514,7 +77170,6 @@ }, "strip-ansi": { "version": "4.0.0", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "dev": true, "requires": { "ansi-regex": "^3.0.0" @@ -73526,7 +77181,6 @@ }, "listr-verbose-renderer": { "version": "0.5.0", - "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", "dev": true, "requires": { "chalk": "^2.4.1", @@ -73537,7 +77191,6 @@ "dependencies": { "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -73545,7 +77198,6 @@ }, "chalk": { "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -73555,7 +77207,6 @@ }, "cli-cursor": { "version": "2.1.0", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", "dev": true, "requires": { "restore-cursor": "^2.0.0" @@ -73563,12 +77214,10 @@ }, "date-fns": { "version": "1.30.1", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", "dev": true }, "figures": { "version": "2.0.0", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" @@ -73576,12 +77225,10 @@ }, "mimic-fn": { "version": "1.2.0", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "onetime": { "version": "2.0.1", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", "dev": true, "requires": { "mimic-fn": "^1.0.0" @@ -73589,7 +77236,6 @@ }, "restore-cursor": { "version": "2.0.0", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", "dev": true, "requires": { "onetime": "^2.0.0", @@ -73598,7 +77244,6 @@ }, "supports-color": { "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -73608,7 +77253,6 @@ }, "load-json-file": { "version": "4.0.0", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -73619,12 +77263,10 @@ }, "loader-runner": { "version": "4.2.0", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", "dev": true }, "loader-utils": { - "version": "1.4.0", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -73633,7 +77275,6 @@ }, "locate-path": { "version": "2.0.0", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", "dev": true, "requires": { "p-locate": "^2.0.0", @@ -73641,16 +77282,13 @@ } }, "lodash": { - "version": "4.17.21", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "version": "4.17.21" }, "lodash-es": { - "version": "4.17.21", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "version": "4.17.21" }, "lodash._baseisequal": { "version": "3.0.7", - "integrity": "sha512-U+3GsNEZj9ebI03ncLC2pLmYVjgtYZEwdkAPO7UGgtGvAz36JVFPAQUufpSaVL93Cz5arc6JGRKZRhaOhyVJYA==", "dev": true, "requires": { "lodash.isarray": "^3.0.0", @@ -73660,86 +77298,61 @@ }, "lodash._bindcallback": { "version": "3.0.1", - "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==", "dev": true }, "lodash._getnative": { "version": "3.9.1", - "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", "dev": true }, "lodash.camelcase": { - "version": "4.3.0", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + "version": "4.3.0" }, "lodash.curry": { - "version": "4.1.1", - "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" + "version": "4.1.1" }, "lodash.debounce": { - "version": "4.0.8", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + "version": "4.0.8" }, "lodash.escape": { "version": "4.0.1", - "integrity": "sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==", "dev": true }, "lodash.flatten": { "version": "4.4.0", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "dev": true }, "lodash.flattendeep": { "version": "4.4.0", - "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, - "lodash.flow": { - "version": "3.5.0", - "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" - }, "lodash.get": { - "version": "4.4.2", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + "version": "4.4.2" }, "lodash.isarguments": { "version": "3.1.0", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", "dev": true }, "lodash.isarray": { "version": "3.0.4", - "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", "dev": true }, "lodash.isequal": { - "version": "4.5.0", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + "version": "4.5.0" }, "lodash.ismatch": { "version": "4.4.0", - "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", "dev": true }, "lodash.isplainobject": { "version": "4.0.6", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, "lodash.istypedarray": { "version": "3.0.6", - "integrity": "sha512-lGWJ6N8AA3KSv+ZZxlTdn4f6A7kMfpJboeyvbFdE7IU9YAgweODqmOgdUHOA+c6lVWeVLysdaxciFXi+foVsWw==", "dev": true }, "lodash.keys": { "version": "3.1.2", - "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", "dev": true, "requires": { "lodash._getnative": "^3.0.0", @@ -73749,60 +77362,29 @@ }, "lodash.memoize": { "version": "4.1.2", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "dev": true }, "lodash.merge": { "version": "4.6.2", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "lodash.pick": { "version": "4.4.0", - "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==", "dev": true }, "lodash.sortby": { "version": "4.7.0", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" - }, - "lodash.template": { - "version": "4.5.0", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "lodash.templatesettings": { - "version": "4.2.0", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "lodash.throttle": { - "version": "4.1.1", - "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" - }, - "lodash.topath": { - "version": "4.5.2", - "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg==" + "dev": true }, "lodash.truncate": { "version": "4.4.2", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true }, "lodash.uniq": { - "version": "4.5.0", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + "version": "4.5.0" }, "log-symbols": { "version": "4.1.0", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -73810,36 +77392,27 @@ } }, "long": { - "version": "3.2.0", - "integrity": "sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg==" + "version": "3.2.0" }, "loose-envify": { "version": "1.4.0", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } }, "lower-case": { "version": "2.0.2", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "requires": { "tslib": "^2.0.3" }, "dependencies": { "tslib": { - "version": "2.1.0", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + "version": "2.1.0" } } }, - "lowercase-keys": { - "version": "1.0.1", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, "lowlight": { "version": "1.20.0", - "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", "requires": { "fault": "^1.0.0", "highlight.js": "~10.7.0" @@ -73847,120 +77420,210 @@ }, "lru-cache": { "version": "5.1.1", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "requires": { "yallist": "^3.0.2" } }, "lz-string": { "version": "1.4.4", - "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", "dev": true }, "magic-string": { "version": "0.22.5", - "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", "requires": { "vlq": "^0.2.2" } }, "make-dir": { "version": "2.1.0", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "requires": { "pify": "^4.0.1", "semver": "^5.6.0" }, "dependencies": { "pify": { - "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "version": "4.0.1" } } }, "make-fetch-happen": { - "version": "8.0.14", - "integrity": "sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==", + "version": "10.2.1", "dev": true, "requires": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.0.5", + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", + "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", + "minipass-fetch": "^2.0.3", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", "promise-retry": "^2.0.1", - "socks-proxy-agent": "^5.0.0", - "ssri": "^8.0.0" + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" }, "dependencies": { + "@npmcli/fs": { + "version": "2.1.2", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@tootallnate/once": { + "version": "2.0.0", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, "cacache": { - "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "version": "16.1.3", "dev": true, "requires": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", + "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.0.2", - "unique-filename": "^1.1.1" + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" } }, "chownr": { "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true }, + "debug": { + "version": "4.3.4", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "glob": { + "version": "8.0.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "7.14.1", + "dev": true + }, + "minimatch": { + "version": "5.1.2", "dev": true, "requires": { - "yallist": "^4.0.0" + "brace-expansion": "^2.0.1" + } + }, + "minipass-fetch": { + "version": "2.1.2", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" } }, "mkdirp": { "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, + "ms": { + "version": "2.1.2", + "dev": true + }, + "semver": { + "version": "7.3.8", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, "ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "version": "9.0.1", "dev": true, "requires": { "minipass": "^3.1.1" } }, + "unique-filename": { + "version": "2.0.1", + "dev": true, + "requires": { + "unique-slug": "^3.0.0" + } + }, + "unique-slug": { + "version": "3.0.0", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "makeerror": { "version": "1.0.11", - "integrity": "sha512-M/XvMZ6oK4edXjvg/ZYyzByg8kjpVrF/m0x3wbhOlzJfsQgFkqP1rJnLnJExOcslmLSSeLiN6NmF+cBoKJHGTg==", "dev": true, "requires": { "tmpl": "1.0.x" @@ -73968,43 +77631,37 @@ }, "map-age-cleaner": { "version": "0.1.3", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "dev": true, "requires": { "p-defer": "^1.0.0" } }, "map-cache": { - "version": "0.2.2", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==" + "version": "0.2.2" }, "map-obj": { "version": "4.3.0", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true }, "map-or-similar": { - "version": "1.5.0", - "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==" + "version": "1.5.0" }, "map-visit": { "version": "1.0.0", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "requires": { "object-visit": "^1.0.0" } }, "mapbox-gl": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-2.12.1.tgz", - "integrity": "sha512-45LVQauimFGX/fkCJzK3O2KpQQrIB0fGlg8sERu4NH0xWiBw9JsLOLYD2xAgD5SPramQvsjzM7vYWIkGxpGYNQ==", + "version": "2.10.0", "requires": { - "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/geojson-rewind": "^0.5.1", + "@mapbox/geojson-types": "^1.0.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", "@mapbox/mapbox-gl-supported": "^2.0.1", "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^2.0.6", - "@mapbox/unitbezier": "^0.0.1", + "@mapbox/tiny-sdf": "^2.0.5", + "@mapbox/unitbezier": "^0.0.0", "@mapbox/vector-tile": "^1.3.1", "@mapbox/whoots-js": "^3.1.0", "csscolorparser": "~1.0.3", @@ -74014,57 +77671,22 @@ "grid-index": "^1.1.0", "murmurhash-js": "^1.0.0", "pbf": "^3.2.1", - "potpack": "^2.0.0", + "potpack": "^1.0.2", "quickselect": "^2.0.0", "rw": "^1.3.3", - "supercluster": "^7.1.5", + "supercluster": "^7.1.4", "tinyqueue": "^2.0.3", "vt-pbf": "^3.1.3" }, "dependencies": { - "@mapbox/geojson-rewind": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", - "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", - "requires": { - "get-stream": "^6.0.1", - "minimist": "^1.2.6" - } - }, - "@mapbox/mapbox-gl-supported": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-2.0.1.tgz", - "integrity": "sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==" - }, "@mapbox/tiny-sdf": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", - "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==" - }, - "@mapbox/unitbezier": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", - "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==" - }, - "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==" + "version": "2.0.5" }, "gl-matrix": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", - "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" - }, - "potpack": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", - "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==" + "version": "3.4.3" }, "supercluster": { "version": "7.1.5", - "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz", - "integrity": "sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==", "requires": { "kdbush": "^3.0.0" } @@ -74072,43 +77694,35 @@ } }, "markdown-escapes": { - "version": "1.0.4", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==" + "version": "1.0.4" }, "markdown-to-jsx": { - "version": "7.1.3", - "integrity": "sha512-jtQ6VyT7rMT5tPV0g2EJakEnXLiPksnvlYtwQsVVZ611JsWGN8bQ1tVSDX4s6JllfEH6wmsYxNjTUAMrPmNA8w==" + "version": "7.1.3" }, "match-sorter": { "version": "6.3.0", - "integrity": "sha512-efYOf/wUpNb8FgNY+cOD2EIJI1S5I7YPKsw0LBp7wqPh5pmMS6i/wr3ZWwfwrAw1NvqTA2KUReVRWDX84lUcOQ==", "requires": { "@babel/runtime": "^7.12.5", "remove-accents": "0.4.2" } }, "material-colors": { - "version": "1.2.6", - "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" + "version": "1.2.6" }, "math-expression-evaluator": { - "version": "1.3.8", - "integrity": "sha512-9FbRY3i6U+CbHgrdNbAUaisjWTozkm1ZfupYQJiZ87NtYHk2Zh9DvxMgp/fifxVhqTLpd5fCCLossUbpZxGeKw==" + "version": "1.3.8" }, "math.gl": { "version": "3.5.3", - "integrity": "sha512-cRQRZlc+XvNHd3bIfu3kdPPPAW0vwDelZJmkjn2TDvCyPcmyDtAiZ2Poo1aFoINP7HzN6oHYxapc/0wV3q6Opg==", "requires": { "@math.gl/core": "3.5.3" } }, "mathfn": { - "version": "1.2.0", - "integrity": "sha512-QBcepxkFxuGk12q4G0KuNbuU3UCXhDROxWZllaNZSpBivkHl2z8qNvi7UGE/WLJt+c7GTC4jigYtur+JDL+40A==" + "version": "1.2.0" }, "md5": { "version": "2.2.1", - "integrity": "sha512-PlGG4z5mBANDGCKsYQe0CaUYHdZYZt8ZPZLmEt+Urf0W4GlpTX4HescwHU+dc9+Z/G/vZKYZYFrwgm9VxK6QOQ==", "requires": { "charenc": "~0.0.1", "crypt": "~0.0.1", @@ -74117,7 +77731,6 @@ }, "md5.js": { "version": "1.3.5", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -74126,25 +77739,21 @@ }, "mdast-squeeze-paragraphs": { "version": "4.0.0", - "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", "requires": { "unist-util-remove": "^2.0.0" } }, "mdast-util-definitions": { "version": "4.0.0", - "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", "requires": { "unist-util-visit": "^2.0.0" }, "dependencies": { "unist-util-is": { - "version": "4.1.0", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" + "version": "4.1.0" }, "unist-util-visit": { "version": "2.0.3", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0", @@ -74153,7 +77762,6 @@ }, "unist-util-visit-parents": { "version": "3.1.1", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0" @@ -74163,7 +77771,6 @@ }, "mdast-util-from-markdown": { "version": "1.2.0", - "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", "requires": { "@types/mdast": "^3.0.0", "@types/unist": "^2.0.0", @@ -74180,14 +77787,12 @@ }, "dependencies": { "mdast-util-to-string": { - "version": "3.1.0", - "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==" + "version": "3.1.0" } } }, "mdast-util-to-hast": { "version": "10.0.1", - "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", "requires": { "@types/mdast": "^3.0.0", "@types/unist": "^2.0.0", @@ -74200,12 +77805,10 @@ }, "dependencies": { "unist-util-is": { - "version": "4.1.0", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" + "version": "4.1.0" }, "unist-util-visit": { "version": "2.0.3", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0", @@ -74214,7 +77817,6 @@ }, "unist-util-visit-parents": { "version": "3.1.1", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0" @@ -74224,25 +77826,20 @@ }, "mdast-util-to-string": { "version": "1.1.0", - "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==", "dev": true }, "mdn-data": { "version": "2.0.14", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true }, "mdurl": { - "version": "1.0.1", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" + "version": "1.0.1" }, "media-typer": { - "version": "0.3.0", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + "version": "0.3.0" }, "mem": { "version": "8.1.1", - "integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==", "dev": true, "requires": { "map-age-cleaner": "^0.1.3", @@ -74251,14 +77848,12 @@ "dependencies": { "mimic-fn": { "version": "3.1.0", - "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", "dev": true } } }, "mem-fs-editor": { "version": "9.3.0", - "integrity": "sha512-QKFbPwGCh1ypmc2H8BUYpbapwT/x2AOCYZQogzSui4rUNes7WVMagQXsirPIfp18EarX0SSY9Fpg426nSjew4Q==", "dev": true, "requires": { "binaryextensions": "^4.16.0", @@ -74275,32 +77870,27 @@ "dependencies": { "normalize-path": { "version": "3.0.0", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true } } }, "memfs": { - "version": "3.2.4", - "integrity": "sha512-2mDCPhuduRPOxlfgsXF9V+uqC6Jgz8zt/bNe4d4W7d5f6pCzHrWkxLNr17jKGXd4+j2kQNsAG2HARPnt74sqVQ==", + "version": "3.4.7", "requires": { - "fs-monkey": "1.0.3" + "fs-monkey": "^1.0.3" } }, "memoize-one": { - "version": "5.1.1", - "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==" + "version": "5.1.1" }, "memoizerific": { "version": "1.11.3", - "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", "requires": { "map-or-similar": "^1.5.0" } }, "memory-fs": { "version": "0.4.1", - "integrity": "sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==", "requires": { "errno": "^0.1.3", "readable-stream": "^2.0.1" @@ -74308,7 +77898,6 @@ }, "meow": { "version": "8.1.2", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", "dev": true, "requires": { "@types/minimist": "^1.2.0", @@ -74326,7 +77915,6 @@ "dependencies": { "hosted-git-info": { "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -74334,7 +77922,6 @@ }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -74342,7 +77929,6 @@ }, "normalize-package-data": { "version": "3.0.3", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, "requires": { "hosted-git-info": "^4.0.1", @@ -74353,7 +77939,6 @@ }, "semver": { "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -74361,51 +77946,41 @@ }, "type-fest": { "version": "0.18.1", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", "dev": true }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "yargs-parser": { "version": "20.2.9", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true } } }, "merge-descriptors": { - "version": "1.0.1", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.1" }, "merge-source-map": { "version": "1.0.4", - "integrity": "sha512-PGSmS0kfnTnMJCzJ16BLLCEe6oeYCamKFFdQKshi4BmM6FUwipjVOcBFGxqtQtirtAG4iZvHlqST9CpZKqlRjA==", "requires": { "source-map": "^0.5.6" } }, "merge-stream": { - "version": "2.0.0", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "version": "2.0.0" }, "merge2": { - "version": "1.4.1", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + "version": "1.4.1" }, "methods": { - "version": "1.1.2", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + "version": "1.1.2" }, "microevent.ts": { - "version": "0.1.1", - "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==" + "version": "0.1.1" }, "micromark": { "version": "3.1.0", - "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", "requires": { "@types/debug": "^4.0.0", "debug": "^4.0.0", @@ -74428,20 +78003,17 @@ "dependencies": { "debug": { "version": "4.3.4", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" } } }, "micromark-core-commonmark": { "version": "1.0.6", - "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", "requires": { "decode-named-character-reference": "^1.0.0", "micromark-factory-destination": "^1.0.0", @@ -74463,7 +78035,6 @@ }, "micromark-factory-destination": { "version": "1.0.0", - "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", "requires": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", @@ -74472,7 +78043,6 @@ }, "micromark-factory-label": { "version": "1.0.2", - "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", "requires": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", @@ -74482,7 +78052,6 @@ }, "micromark-factory-space": { "version": "1.0.0", - "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", "requires": { "micromark-util-character": "^1.0.0", "micromark-util-types": "^1.0.0" @@ -74490,7 +78059,6 @@ }, "micromark-factory-title": { "version": "1.0.2", - "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", "requires": { "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", @@ -74501,7 +78069,6 @@ }, "micromark-factory-whitespace": { "version": "1.0.0", - "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", "requires": { "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", @@ -74511,7 +78078,6 @@ }, "micromark-util-character": { "version": "1.1.0", - "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", "requires": { "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" @@ -74519,14 +78085,12 @@ }, "micromark-util-chunked": { "version": "1.0.0", - "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", "requires": { "micromark-util-symbol": "^1.0.0" } }, "micromark-util-classify-character": { "version": "1.0.0", - "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", "requires": { "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", @@ -74535,7 +78099,6 @@ }, "micromark-util-combine-extensions": { "version": "1.0.0", - "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", "requires": { "micromark-util-chunked": "^1.0.0", "micromark-util-types": "^1.0.0" @@ -74543,14 +78106,12 @@ }, "micromark-util-decode-numeric-character-reference": { "version": "1.0.0", - "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", "requires": { "micromark-util-symbol": "^1.0.0" } }, "micromark-util-decode-string": { "version": "1.0.2", - "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", "requires": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^1.0.0", @@ -74559,30 +78120,25 @@ } }, "micromark-util-encode": { - "version": "1.0.1", - "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==" + "version": "1.0.1" }, "micromark-util-html-tag-name": { - "version": "1.1.0", - "integrity": "sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==" + "version": "1.1.0" }, "micromark-util-normalize-identifier": { "version": "1.0.0", - "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", "requires": { "micromark-util-symbol": "^1.0.0" } }, "micromark-util-resolve-all": { "version": "1.0.0", - "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", "requires": { "micromark-util-types": "^1.0.0" } }, "micromark-util-sanitize-uri": { "version": "1.1.0", - "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", "requires": { "micromark-util-character": "^1.0.0", "micromark-util-encode": "^1.0.0", @@ -74591,7 +78147,6 @@ }, "micromark-util-subtokenize": { "version": "1.0.2", - "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", "requires": { "micromark-util-chunked": "^1.0.0", "micromark-util-symbol": "^1.0.0", @@ -74600,16 +78155,13 @@ } }, "micromark-util-symbol": { - "version": "1.0.1", - "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==" + "version": "1.0.1" }, "micromark-util-types": { - "version": "1.0.2", - "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==" + "version": "1.0.2" }, "micromatch": { "version": "3.1.10", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -74628,7 +78180,6 @@ "dependencies": { "extend-shallow": { "version": "3.0.2", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -74636,78 +78187,56 @@ }, "is-extendable": { "version": "1.0.1", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { "is-plain-object": "^2.0.4" } }, "kind-of": { - "version": "6.0.3", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "version": "6.0.3" } } }, "microseconds": { - "version": "0.2.0", - "integrity": "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==" + "version": "0.2.0" }, "miller-rabin": { "version": "4.0.1", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "requires": { "bn.js": "^4.0.0", "brorand": "^1.0.1" }, "dependencies": { "bn.js": { - "version": "4.12.0", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.0" } } }, "mime": { - "version": "1.6.0", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + "version": "1.6.0" }, "mime-db": { - "version": "1.49.0", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==" + "version": "1.52.0" }, "mime-types": { - "version": "2.1.32", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", + "version": "2.1.35", "requires": { - "mime-db": "1.49.0" + "mime-db": "1.52.0" } }, "mimic-fn": { - "version": "2.1.0", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "devOptional": true + "version": "2.1.0" }, "min-document": { "version": "2.19.0", - "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", "requires": { "dom-walk": "^0.1.0" } }, "min-indent": { - "version": "1.0.1", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" - }, - "mini-create-react-context": { - "version": "0.3.2", - "integrity": "sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==", - "requires": { - "@babel/runtime": "^7.4.0", - "gud": "^1.0.0", - "tiny-warning": "^1.0.2" - } + "version": "1.0.1" }, "mini-css-extract-plugin": { "version": "2.4.5", - "integrity": "sha512-oEIhRucyn1JbT/1tU2BhnwO6ft1jjH1iCX9Gc59WFMg0n5773rQU0oyQ0zzeYFFuBfONaRbQJyGoPtuNseMxjA==", "dev": true, "requires": { "schema-utils": "^4.0.0" @@ -74715,7 +78244,6 @@ "dependencies": { "ajv": { "version": "8.8.2", - "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -74726,7 +78254,6 @@ }, "ajv-keywords": { "version": "5.1.0", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, "requires": { "fast-deep-equal": "^3.1.3" @@ -74734,12 +78261,10 @@ }, "json-schema-traverse": { "version": "1.0.0", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "schema-utils": { "version": "4.0.0", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", @@ -74752,35 +78277,28 @@ }, "mini-store": { "version": "3.0.6", - "integrity": "sha512-YzffKHbYsMQGUWQRKdsearR79QsMzzJcDDmZKlJBqt5JNkqpyJHYlK6gP61O36X+sLf76sO9G6mhKBe83gIZIQ==", "requires": { "hoist-non-react-statics": "^3.3.2", "shallowequal": "^1.0.2" } }, "minimalistic-assert": { - "version": "1.0.1", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "version": "1.0.1" }, "minimalistic-crypto-utils": { - "version": "1.0.1", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + "version": "1.0.1" }, "minimatch": { - "version": "3.0.4", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" + "version": "1.2.6" }, "minimist-options": { "version": "4.1.0", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, "requires": { "arrify": "^1.0.1", @@ -74790,52 +78308,35 @@ "dependencies": { "kind-of": { "version": "6.0.3", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true } } }, "minipass": { "version": "3.1.6", - "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", "requires": { "yallist": "^4.0.0" }, "dependencies": { "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "4.0.0" } } }, "minipass-collect": { "version": "1.0.2", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", "requires": { "minipass": "^3.0.0" } }, - "minipass-fetch": { - "version": "1.4.1", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "dev": true, - "requires": { - "encoding": "^0.1.12", - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - } - }, "minipass-flush": { "version": "1.0.5", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "requires": { "minipass": "^3.0.0" } }, "minipass-json-stream": { "version": "1.0.1", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", "dev": true, "requires": { "jsonparse": "^1.3.1", @@ -74844,14 +78345,12 @@ }, "minipass-pipeline": { "version": "1.2.4", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "requires": { "minipass": "^3.0.0" } }, "minipass-sized": { "version": "1.0.3", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "dev": true, "requires": { "minipass": "^3.0.0" @@ -74859,21 +78358,18 @@ }, "minizlib": { "version": "2.1.2", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "requires": { "minipass": "^3.0.0", "yallist": "^4.0.0" }, "dependencies": { "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "4.0.0" } } }, "mississippi": { "version": "3.0.0", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "requires": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", @@ -74889,7 +78385,6 @@ }, "mixin-deep": { "version": "1.3.2", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -74897,7 +78392,6 @@ "dependencies": { "is-extendable": { "version": "1.0.1", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { "is-plain-object": "^2.0.4" } @@ -74906,7 +78400,6 @@ }, "mjolnir.js": { "version": "2.5.0", - "integrity": "sha512-YkVoyKs7qm9xvAgRgjx3Md/7eYqmq7VXOgTKQNnmuzcBJzMebjdIWa7FdTd0RZBrw3UL6V6TTktsxJwBMLXUNA==", "requires": { "@babel/runtime": "^7.0.0", "hammerjs": "^2.0.8" @@ -74914,14 +78407,12 @@ }, "mkdirp": { "version": "0.5.5", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "requires": { "minimist": "^1.2.5" } }, "mkdirp-infer-owner": { "version": "2.0.0", - "integrity": "sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw==", "dev": true, "requires": { "chownr": "^2.0.0", @@ -74931,19 +78422,16 @@ "dependencies": { "chownr": { "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true }, "mkdirp": { "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true } } }, "mock-socket": { "version": "9.0.3", - "integrity": "sha512-SxIiD2yE/By79p3cNAAXyLQWTvEFNEzcAO7PH+DzRqKSFaplAPFjiQLmw8ofmpCsZf+Rhfn2/xCJagpdGmYdTw==", "dev": true, "requires": { "url-parse": "^1.4.4" @@ -74951,28 +78439,23 @@ }, "modify-values": { "version": "1.0.1", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", "dev": true }, "moment": { - "version": "2.29.2", - "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==" + "version": "2.29.4" }, "moment-timezone": { - "version": "0.5.33", - "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", + "version": "0.5.37", "requires": { "moment": ">= 2.9.0" } }, "moo": { "version": "0.4.3", - "integrity": "sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==", "dev": true }, "morgan": { "version": "1.10.0", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", "dev": true, "requires": { "basic-auth": "~2.0.1", @@ -74984,18 +78467,15 @@ "dependencies": { "depd": { "version": "2.0.0", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true } } }, "mousetrap": { - "version": "1.6.2", - "integrity": "sha512-jDjhi7wlHwdO6q6DS7YRmSHcuI+RVxadBkLt3KHrhd3C2b+w5pKefg3oj5beTcHZyVFA9Aksf+yEE1y5jxUjVA==" + "version": "1.6.2" }, "move-concurrently": { "version": "1.0.1", - "integrity": "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==", "requires": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", @@ -75007,7 +78487,6 @@ "dependencies": { "rimraf": { "version": "2.7.1", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" } @@ -75015,30 +78494,21 @@ } }, "mri": { - "version": "1.2.0", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" + "version": "1.2.0" }, "ms": { - "version": "2.0.0", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "version": "2.0.0" }, "multicast-dns": { - "version": "6.2.3", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "version": "7.2.5", "dev": true, "requires": { - "dns-packet": "^1.3.1", + "dns-packet": "^5.2.2", "thunky": "^1.0.2" } }, - "multicast-dns-service-types": { - "version": "1.1.0", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", - "dev": true - }, "multimatch": { "version": "5.0.0", - "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", "dev": true, "requires": { "@types/minimatch": "^3.0.3", @@ -75050,42 +78520,31 @@ "dependencies": { "arrify": { "version": "2.0.1", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", "dev": true } } }, "murmurhash-js": { - "version": "1.0.0", - "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==" + "version": "1.0.0" }, "mustache": { - "version": "2.3.2", - "integrity": "sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ==" + "version": "2.3.2" }, "mute-stream": { "version": "0.0.8", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "devOptional": true + "dev": true }, "nano-time": { "version": "1.0.0", - "integrity": "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==", "requires": { "big-integer": "^1.6.16" } }, - "nanocolors": { - "version": "0.1.12", - "integrity": "sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ==" - }, "nanoid": { - "version": "2.0.0", - "integrity": "sha512-SG2qscLE3iM4C0CNzGrsAojJHSVHMS1J8NnvJ31P1lH8P0hGHOiafmniNJz6w6q7vuoDlV7RdySlJgtqkFEVtQ==" + "version": "2.0.0" }, "nanomatch": { "version": "1.2.13", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -75102,7 +78561,6 @@ "dependencies": { "extend-shallow": { "version": "3.0.2", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -75110,31 +78568,26 @@ }, "is-extendable": { "version": "1.0.1", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { "is-plain-object": "^2.0.4" } }, "kind-of": { - "version": "6.0.3", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "version": "6.0.3" } } }, "native-request": { "version": "1.0.8", - "integrity": "sha512-vU2JojJVelUGp6jRcLwToPoWGxSx23z/0iX+I77J3Ht17rf2INGjrhOoQnjVo60nQd8wVsgzKkPfRXBiVdD2ag==", "dev": true, "optional": true }, "natural-compare": { "version": "1.4.0", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "nearley": { "version": "2.18.0", - "integrity": "sha512-/zQOMCeJcioI0xJtd5RpBiWw2WP7wLe6vq8/3Yu0rEwgus/G/+pViX80oA87JdVgjRt2895mZSv2VfZmy4W1uw==", "dev": true, "requires": { "commander": "^2.19.0", @@ -75145,24 +78598,24 @@ } }, "negotiator": { - "version": "0.6.1", - "integrity": "sha512-qTxkr1RoLw5Pz+1+PTJ/66hWuyi2LEOeOuIDJDlx6JF8x75bmD5C7qXTg2UlX5W9rLfkqKP+r8q6Vy6NWdWrbw==" + "version": "0.6.3" }, "neo-async": { - "version": "2.6.2", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + "version": "2.6.2" }, "nested-error-stacks": { - "version": "2.1.1", - "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" + "version": "2.1.1" + }, + "netmask": { + "version": "2.0.2", + "dev": true }, "nice-try": { "version": "1.0.5", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + "dev": true }, "nise": { "version": "4.1.0", - "integrity": "sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0", @@ -75174,12 +78627,10 @@ "dependencies": { "isarray": { "version": "0.0.1", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "path-to-regexp": { "version": "1.8.0", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", "dev": true, "requires": { "isarray": "0.0.1" @@ -75189,21 +78640,18 @@ }, "no-case": { "version": "3.0.4", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "requires": { "lower-case": "^2.0.2", "tslib": "^2.0.3" }, "dependencies": { "tslib": { - "version": "2.1.0", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + "version": "2.1.0" } } }, "no-proxy": { "version": "1.0.3", - "integrity": "sha512-JPr13PIb/cENY5+WjuxzhQH74guHYPpyfk+7f7lR7SIpDE1kH0BL9jO7yztANg3jFT8jf58UEimbCBflW5UiTw==", "dev": true, "requires": { "url-parse": "^1.2.0", @@ -75212,57 +78660,46 @@ "dependencies": { "wildcard": { "version": "1.1.2", - "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==", "dev": true } } }, + "node-addon-api": { + "version": "3.2.1", + "dev": true + }, "node-ask": { "version": "1.0.1", - "integrity": "sha512-+0eqgEdgPiixrNysGDTPo3T2qyEHGVgs4ONlc5tTfcluvC/Rgq1x2ELdANUMwhR2CYLwaQnMS32O/h7adasnFQ==", "dev": true }, "node-dir": { "version": "0.1.17", - "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", "requires": { "minimatch": "^3.0.2" } }, "node-environment-flags": { "version": "1.0.6", - "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", "dev": true, "requires": { "object.getownpropertydescriptors": "^2.0.3", "semver": "^5.7.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, "node-fetch": { "version": "2.6.7", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "requires": { "whatwg-url": "^5.0.0" }, "dependencies": { "tr46": { - "version": "0.0.3", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "version": "0.0.3" }, "webidl-conversions": { - "version": "3.0.1", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "version": "3.0.1" }, "whatwg-url": { "version": "5.0.0", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -75271,104 +78708,69 @@ } }, "node-forge": { - "version": "0.10.0", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "version": "1.3.1", "dev": true }, "node-gyp": { - "version": "5.1.1", - "integrity": "sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw==", + "version": "9.3.1", "dev": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "npmlog": "^4.1.2", - "request": "^2.88.0", - "rimraf": "^2.6.3", - "semver": "^5.7.1", - "tar": "^4.4.12", - "which": "^1.3.1" + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" }, "dependencies": { - "fs-minipass": { - "version": "1.2.7", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "dev": true, - "requires": { - "minipass": "^2.6.0" - } - }, - "minipass": { - "version": "2.9.0", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "lru-cache": { + "version": "6.0.0", "dev": true, "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "yallist": "^4.0.0" } }, - "minizlib": { - "version": "1.3.3", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "nopt": { + "version": "6.0.0", "dev": true, "requires": { - "minipass": "^2.9.0" + "abbrev": "^1.0.0" } }, - "nopt": { - "version": "4.0.3", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "semver": { + "version": "7.3.8", "dev": true, "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "lru-cache": "^6.0.0" } }, - "rimraf": { - "version": "2.7.1", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "which": { + "version": "2.0.2", "dev": true, "requires": { - "glob": "^7.1.3" + "isexe": "^2.0.0" } }, - "safe-buffer": { - "version": "5.2.1", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "yallist": { + "version": "4.0.0", "dev": true - }, - "tar": { - "version": "4.4.19", - "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", - "dev": true, - "requires": { - "chownr": "^1.1.4", - "fs-minipass": "^1.2.7", - "minipass": "^2.9.0", - "minizlib": "^1.3.3", - "mkdirp": "^0.5.5", - "safe-buffer": "^5.2.1", - "yallist": "^3.1.1" - } } } }, + "node-gyp-build": { + "version": "4.5.0", + "dev": true + }, "node-int64": { "version": "0.4.0", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, "node-libs-browser": { "version": "2.2.1", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "requires": { "assert": "^1.1.1", "browserify-zlib": "^0.2.0", @@ -75396,18 +78798,15 @@ }, "dependencies": { "path-browserify": { - "version": "0.0.1", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + "version": "0.0.1" }, "punycode": { - "version": "1.4.1", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + "version": "1.4.1" } } }, "node-loggly-bulk": { "version": "2.2.5", - "integrity": "sha512-N6RjZfjqwhAYwT9nM8PFKXpWfaGFaDHnzwj2JBgsNq04xsEZNGMlI+rds90p5/TTkYAS8Ya6tbJChXFRqTSmiA==", "dev": true, "requires": { "json-stringify-safe": "5.0.x", @@ -75415,13 +78814,8 @@ "request": ">=2.76.0 <3.0.0" } }, - "node-modules-regexp": { - "version": "1.0.0", - "integrity": "sha512-JMaRS9L4wSRIR+6PTVEikTrq/lMGEZR43a48ETeilY0Q0iMwVnccMFrUM1k+tNzmYuIU0Vh710bCUqHX+/+ctQ==" - }, "node-notifier": { "version": "8.0.0", - "integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==", "dev": true, "optional": true, "requires": { @@ -75435,7 +78829,6 @@ "dependencies": { "is-wsl": { "version": "2.2.0", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "optional": true, "requires": { @@ -75444,19 +78837,16 @@ }, "semver": { "version": "7.3.2", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true, "optional": true }, "uuid": { "version": "8.3.1", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", "dev": true, "optional": true }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "optional": true, "requires": { @@ -75466,19 +78856,16 @@ } }, "node-releases": { - "version": "1.1.75", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==" + "version": "2.0.6" }, "nopt": { "version": "5.0.0", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "requires": { "abbrev": "1" } }, "normalize-package-data": { "version": "2.5.0", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "requires": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -75488,357 +78875,401 @@ }, "normalize-path": { "version": "2.1.1", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "devOptional": true, "requires": { "remove-trailing-separator": "^1.0.1" } }, "normalize-range": { - "version": "0.1.2", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" + "version": "0.1.2" }, "normalize-url": { "version": "6.1.0", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", "dev": true }, - "npm-api": { - "version": "1.0.1", - "integrity": "sha512-4sITrrzEbPcr0aNV28QyOmgn6C9yKiF8k92jn4buYAK8wmA5xo1qL3II5/gT1r7wxbXBflSduZ2K3FbtOrtGkA==", - "optional": true, - "requires": { - "clone-deep": "^4.0.1", - "download-stats": "^0.3.4", - "JSONStream": "^1.3.5", - "moment": "^2.24.0", - "node-fetch": "^2.6.0", - "paged-request": "^2.0.1" - } - }, "npm-bundled": { "version": "1.1.2", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", "dev": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } }, - "npm-install-checks": { - "version": "4.0.0", - "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", + "npm-normalize-package-bin": { + "version": "1.0.1", + "dev": true + }, + "npm-packlist": { + "version": "5.1.3", "dev": true, "requires": { - "semver": "^7.1.1" + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0" }, "dependencies": { - "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "brace-expansion": { + "version": "2.0.1", "dev": true, "requires": { - "yallist": "^4.0.0" + "balanced-match": "^1.0.0" } }, - "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "glob": { + "version": "8.0.3", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" } }, - "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "minimatch": { + "version": "5.1.2", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "npm-bundled": { + "version": "2.0.1", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^2.0.0" + } + }, + "npm-normalize-package-bin": { + "version": "2.0.0", "dev": true } } }, - "npm-lifecycle": { - "version": "3.1.5", - "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==", + "npm-run-path": { + "version": "2.0.2", "dev": true, "requires": { - "byline": "^5.0.0", - "graceful-fs": "^4.1.15", - "node-gyp": "^5.0.2", - "resolve-from": "^4.0.0", - "slide": "^1.1.6", - "uid-number": "0.0.6", - "umask": "^1.1.0", - "which": "^1.3.1" + "path-key": "^2.0.0" } }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "npmlog": { + "version": "6.0.2", + "dev": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2" + }, + "number-is-nan": { + "version": "1.0.1" + }, + "nvd3-fork": { + "version": "2.0.5" + }, + "nwsapi": { + "version": "2.2.0", "dev": true }, - "npm-package-arg": { - "version": "8.1.5", - "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", + "nx": { + "version": "15.3.3", "dev": true, "requires": { - "hosted-git-info": "^4.0.1", - "semver": "^7.3.4", - "validate-npm-package-name": "^3.0.0" + "@nrwl/cli": "15.3.3", + "@nrwl/tao": "15.3.3", + "@parcel/watcher": "2.0.4", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "^3.0.0-rc.18", + "@zkochan/js-yaml": "0.0.6", + "axios": "^1.0.0", + "chalk": "4.1.0", + "chokidar": "^3.5.1", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^7.0.2", + "dotenv": "~10.0.0", + "enquirer": "~2.3.6", + "fast-glob": "3.2.7", + "figures": "3.2.0", + "flat": "^5.0.2", + "fs-extra": "^10.1.0", + "glob": "7.1.4", + "ignore": "^5.0.4", + "js-yaml": "4.1.0", + "jsonc-parser": "3.2.0", + "minimatch": "3.0.5", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "semver": "7.3.4", + "string-width": "^4.2.3", + "strong-log-transformer": "^2.1.0", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tsconfig-paths": "^3.9.0", + "tslib": "^2.3.0", + "v8-compile-cache": "2.3.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" }, "dependencies": { - "hosted-git-info": { - "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "ansi-regex": { + "version": "5.0.1", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "dev": true + }, + "axios": { + "version": "1.2.1", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, - "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "braces": { + "version": "3.0.2", "dev": true, "requires": { - "yallist": "^4.0.0" + "fill-range": "^7.0.1" } }, - "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "chalk": { + "version": "4.1.0", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "cliui": { + "version": "7.0.4", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "dotenv": { + "version": "10.0.0", "dev": true - } - } - }, - "npm-packlist": { - "version": "2.2.2", - "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==", - "dev": true, - "requires": { - "glob": "^7.1.6", - "ignore-walk": "^3.0.3", - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-pick-manifest": { - "version": "6.1.1", - "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", - "dev": true, - "requires": { - "npm-install-checks": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^8.1.2", - "semver": "^7.3.4" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + }, + "fast-glob": { + "version": "3.2.7", "dev": true, "requires": { - "yallist": "^4.0.0" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" } }, - "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "fill-range": { + "version": "7.0.1", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "to-regex-range": "^5.0.1" } }, - "yallist": { + "form-data": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "npm-registry-fetch": { - "version": "11.0.0", - "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", - "dev": true, - "requires": { - "make-fetch-happen": "^9.0.1", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" - }, - "dependencies": { - "cacache": { - "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", "dev": true, "requires": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" } }, - "chownr": { - "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "glob": { + "version": "7.1.4", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "ignore": { + "version": "5.2.4", "dev": true }, - "debug": { - "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", "dev": true, "requires": { - "ms": "2.1.2" + "is-docker": "^2.0.0" + } + }, + "js-yaml": { + "version": "4.1.0", + "dev": true, + "requires": { + "argparse": "^2.0.1" } }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" } }, - "make-fetch-happen": { - "version": "9.1.0", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "micromatch": { + "version": "4.0.5", "dev": true, "requires": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, - "mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true + "minimatch": { + "version": "3.0.5", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "npm-run-path": { + "version": "4.0.1", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "open": { + "version": "8.4.0", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "path-key": { + "version": "3.1.1", "dev": true }, - "negotiator": { - "version": "0.6.2", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "proxy-from-env": { + "version": "1.1.0", "dev": true }, - "socks-proxy-agent": { - "version": "6.1.1", - "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "semver": { + "version": "7.3.4", "dev": true, "requires": { - "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" + "lru-cache": "^6.0.0" } }, - "ssri": { - "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "string-width": { + "version": "4.2.3", "dev": true, "requires": { - "minipass": "^3.1.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tslib": { + "version": "2.4.1", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, + "y18n": { + "version": "5.0.8", + "dev": true + }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "17.6.2", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "cliui": { + "version": "8.0.1", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + } + } + }, + "yargs-parser": { + "version": "21.1.1", "dev": true } } }, - "npm-run-path": { - "version": "2.0.2", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "npmlog": { - "version": "4.1.2", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "nth-check": { - "version": "1.0.2", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "requires": { - "boolbase": "~1.0.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==" - }, - "number-is-nan": { - "version": "1.0.1", - "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==" - }, - "nvd3-fork": { - "version": "2.0.5", - "integrity": "sha512-Sq3q2rvR/9FJ35LVmqdQJAnfmD15BaIHSBg5wZZL/WLcq/nthff8ukabwFdbW0zeE1c/yPq+DKl6MxnUTR45DA==" - }, - "nwsapi": { - "version": "2.2.0", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, "oauth-sign": { "version": "0.9.0", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, "object-assign": { - "version": "4.1.1", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + "version": "4.1.1" }, "object-copy": { "version": "0.1.0", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "requires": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -75847,14 +79278,12 @@ "dependencies": { "define-property": { "version": "0.2.5", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } }, "kind-of": { "version": "3.2.2", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -75862,58 +79291,52 @@ } }, "object-inspect": { - "version": "1.4.1", - "integrity": "sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw==" + "version": "1.4.1" }, "object-is": { - "version": "1.0.1", - "integrity": "sha512-WY2d4Y9s39AGFRtDlJDyNHFHOTQ5MbFzYWt9dHNYn4P9zCR+wpCo1IqWd+xJVEX5aNhCFXzTptJ8H2kRIHWF3Q==", - "dev": true + "version": "1.1.5", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } }, "object-keys": { - "version": "1.1.1", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "version": "1.1.1" }, "object-visit": { "version": "1.0.1", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "requires": { "isobject": "^3.0.0" } }, "object.assign": { - "version": "4.1.2", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.4", "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" } }, "object.entries": { - "version": "1.1.0", - "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "version": "1.1.6", "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" } }, "object.fromentries": { - "version": "2.0.0", - "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", + "version": "2.0.6", "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.11.0", - "function-bind": "^1.1.1", - "has": "^1.0.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" } }, "object.getownpropertydescriptors": { "version": "2.1.3", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -75922,66 +79345,54 @@ }, "object.pick": { "version": "1.3.0", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "requires": { "isobject": "^3.0.1" } }, "object.values": { - "version": "1.1.4", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "version": "1.1.6", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" } }, "objectorarray": { - "version": "1.0.5", - "integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==" + "version": "1.0.5" }, "oblivious-set": { - "version": "1.0.0", - "integrity": "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==" + "version": "1.0.0" }, "obuf": { "version": "1.1.2", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "dev": true }, "omit.js": { - "version": "2.0.2", - "integrity": "sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg==" + "version": "2.0.2" }, "on-finished": { "version": "2.3.0", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "requires": { "ee-first": "1.1.1" } }, "on-headers": { - "version": "1.0.2", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + "version": "1.0.2" }, "once": { "version": "1.4.0", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } }, "onetime": { "version": "5.1.2", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "devOptional": true, "requires": { "mimic-fn": "^2.1.0" } }, "open": { "version": "7.4.2", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "requires": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" @@ -75989,7 +79400,6 @@ "dependencies": { "is-wsl": { "version": "2.2.0", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "requires": { "is-docker": "^2.0.0" } @@ -75998,30 +79408,25 @@ }, "opener": { "version": "1.5.2", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "dev": true }, "openurl": { "version": "1.1.1", - "integrity": "sha512-d/gTkTb1i1GKz5k3XE3XFV/PxQ1k45zDqGP2OA7YhgsaLoqm6qRvARAZOFer1fcXritWlGBRCu/UgeS4HAnXAA==", "dev": true }, "optimist": { "version": "0.3.7", - "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", "requires": { "wordwrap": "~0.0.2" }, "dependencies": { "wordwrap": { - "version": "0.0.3", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==" + "version": "0.0.3" } } }, "optionator": { "version": "0.8.2", - "integrity": "sha512-oCOQ8AIC2ciLy/sE2ehafRBleBgDLvzGhBRRev87sP7ovnbvQfqpc3XFI0DhHey2OfVoNV91W+GPC6B3540/5Q==", "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", @@ -76033,7 +79438,6 @@ }, "ora": { "version": "5.4.1", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, "requires": { "bl": "^4.1.0", @@ -76049,12 +79453,10 @@ "dependencies": { "ansi-regex": { "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { "ansi-regex": "^5.0.1" @@ -76063,82 +79465,56 @@ } }, "os-browserify": { - "version": "0.3.0", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==" - }, - "os-homedir": { - "version": "1.0.2", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true + "version": "0.3.0" }, "os-tmpdir": { "version": "1.0.2", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "devOptional": true - }, - "osenv": { - "version": "0.1.5", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } + "dev": true }, "overlayscrollbars": { - "version": "1.13.1", - "integrity": "sha512-gIQfzgGgu1wy80EB4/6DaJGHMEGmizq27xHIESrzXq0Y/J0Ay1P3DWk6tuVmEPIZH15zaBlxeEJOqdJKmowHCQ==" + "version": "1.13.1" }, "p-all": { "version": "2.1.0", - "integrity": "sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==", "requires": { "p-map": "^2.0.0" }, "dependencies": { "p-map": { - "version": "2.1.0", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + "version": "2.1.0" } } }, "p-defer": { "version": "1.0.0", - "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", "dev": true }, "p-each-series": { "version": "2.2.0", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", "dev": true }, "p-event": { "version": "4.2.0", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", "requires": { "p-timeout": "^3.1.0" } }, "p-filter": { "version": "2.1.0", - "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", "requires": { "p-map": "^2.0.0" }, "dependencies": { "p-map": { - "version": "2.1.0", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + "version": "2.1.0" } } }, "p-finally": { - "version": "1.0.0", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==" + "version": "1.0.0" }, "p-limit": { "version": "1.3.0", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { "p-try": "^1.0.0" @@ -76146,7 +79522,6 @@ }, "p-locate": { "version": "2.0.0", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", "dev": true, "requires": { "p-limit": "^1.1.0" @@ -76154,24 +79529,20 @@ }, "p-map": { "version": "4.0.0", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "requires": { "aggregate-error": "^3.0.0" } }, "p-map-series": { "version": "2.1.0", - "integrity": "sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==", "dev": true }, "p-pipe": { "version": "3.1.0", - "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==", "dev": true }, "p-queue": { "version": "6.6.2", - "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", "requires": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" @@ -76179,12 +79550,10 @@ }, "p-reduce": { "version": "2.1.0", - "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", "dev": true }, "p-retry": { "version": "4.6.1", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", "dev": true, "requires": { "@types/retry": "^0.12.0", @@ -76193,50 +79562,81 @@ }, "p-timeout": { "version": "3.2.0", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", "requires": { "p-finally": "^1.0.0" } }, "p-try": { "version": "1.0.0", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", "dev": true }, "p-waterfall": { "version": "2.1.1", - "integrity": "sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==", "dev": true, "requires": { "p-reduce": "^2.0.0" } }, + "pac-proxy-agent": { + "version": "5.0.0", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "dev": true + }, + "socks-proxy-agent": { + "version": "5.0.1", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + } + } + } + }, + "pac-resolver": { + "version": "5.0.1", + "dev": true, + "requires": { + "degenerator": "^3.0.2", + "ip": "^1.1.5", + "netmask": "^2.0.2" + } + }, "pad-component": { - "version": "0.0.1", - "integrity": "sha512-8EKVBxCRSvLnsX1p2LlSFSH3c2/wuhY9/BXXWu8boL78FbVKqn2L5SpURt1x5iw6Gq8PTqJ7MdPoe5nCtX3I+g==" + "version": "0.0.1" }, "pad-left": { "version": "2.1.0", - "integrity": "sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==", "requires": { "repeat-string": "^1.5.4" } }, - "paged-request": { - "version": "2.0.2", - "integrity": "sha512-NWrGqneZImDdcMU/7vMcAOo1bIi5h/pmpJqe7/jdsy85BA/s5MSaU/KlpxwW/IVPmIwBcq2uKPrBWWhEWhtxag==", - "optional": true, - "requires": { - "axios": "^0.21.1" - } - }, "pako": { - "version": "1.0.11", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + "version": "1.0.11" }, "parallel-transform": { "version": "1.2.0", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "requires": { "cyclist": "^1.0.1", "inherits": "^2.0.3", @@ -76245,28 +79645,24 @@ }, "param-case": { "version": "3.0.4", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", "requires": { "dot-case": "^3.0.4", "tslib": "^2.0.3" }, "dependencies": { "tslib": { - "version": "2.1.0", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + "version": "2.1.0" } } }, "parent-module": { "version": "1.0.1", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "requires": { "callsites": "^3.0.0" } }, "parse-asn1": { "version": "5.1.6", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", "requires": { "asn1.js": "^5.2.0", "browserify-aes": "^1.0.0", @@ -76277,7 +79673,6 @@ }, "parse-json": { "version": "4.0.0", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, "requires": { "error-ex": "^1.3.1", @@ -76285,116 +79680,83 @@ } }, "parse-ms": { - "version": "2.1.0", - "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==" + "version": "2.1.0" }, "parse-passwd": { "version": "1.0.0", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true }, "parse-path": { - "version": "4.0.3", - "integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==", + "version": "7.0.0", "dev": true, "requires": { - "is-ssh": "^1.3.0", - "protocols": "^1.4.0", - "qs": "^6.9.4", - "query-string": "^6.13.8" - }, - "dependencies": { - "qs": { - "version": "6.10.2", - "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - } + "protocols": "^2.0.0" } }, "parse-url": { - "version": "6.0.0", - "integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==", + "version": "8.1.0", "dev": true, "requires": { - "is-ssh": "^1.3.0", - "normalize-url": "^6.1.0", - "parse-path": "^4.0.0", - "protocols": "^1.4.0" + "parse-path": "^7.0.0" } }, "parse5": { "version": "3.0.3", - "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", "dev": true, "requires": { "@types/node": "*" } }, "parseurl": { - "version": "1.3.2", - "integrity": "sha512-DjIMrEiCuzD/Xsr69WhcPCTeb6iZP5JgL/DZ3cYz0zMnyiXiscoqC6LLV2dYwQHfy9O+twCDVVPiFWb7xZhaOw==" + "version": "1.3.3" }, "pascal-case": { "version": "3.1.2", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3" }, "dependencies": { "tslib": { - "version": "2.1.0", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + "version": "2.1.0" } } }, "pascalcase": { - "version": "0.1.1", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==" + "version": "0.1.1" }, "path-browserify": { "version": "1.0.1", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "dev": true }, "path-dirname": { - "version": "1.0.2", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==" + "version": "1.0.2" }, "path-exists": { - "version": "3.0.0", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" + "version": "3.0.0" }, "path-is-absolute": { - "version": "1.0.1", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + "version": "1.0.1" }, "path-key": { "version": "2.0.1", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" + "dev": true }, "path-parse": { - "version": "1.0.7", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "version": "1.0.7" }, "path-to-regexp": { "version": "2.4.0", - "integrity": "sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==", "dev": true }, "path-type": { "version": "3.0.0", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "requires": { "pify": "^3.0.0" } }, "pbf": { "version": "3.2.1", - "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", "requires": { "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" @@ -76402,7 +79764,6 @@ }, "pbkdf2": { "version": "3.1.2", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -76413,60 +79774,47 @@ }, "pend": { "version": "1.2.0", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, "performance-now": { "version": "2.1.0", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + "dev": true }, "picocolors": { - "version": "0.2.1", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + "version": "0.2.1" }, "picomatch": { - "version": "2.3.0", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + "version": "2.3.1" }, "pify": { - "version": "3.0.0", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==" + "version": "3.0.0" }, "pinkie": { - "version": "2.0.4", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==" + "version": "2.0.4" }, "pinkie-promise": { "version": "2.0.1", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "requires": { "pinkie": "^2.0.0" } }, "pirates": { - "version": "4.0.1", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "requires": { - "node-modules-regexp": "^1.0.0" - } + "version": "4.0.5" }, "pkg-dir": { "version": "3.0.0", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "requires": { "find-up": "^3.0.0" }, "dependencies": { "find-up": { "version": "3.0.0", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { "locate-path": "^3.0.0" } }, "locate-path": { "version": "3.0.0", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -76474,27 +79822,23 @@ }, "p-limit": { "version": "2.2.2", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "3.0.0", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { "p-limit": "^2.0.0" } }, "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "version": "2.2.0" } } }, "pkg-up": { "version": "2.0.0", - "integrity": "sha512-fjAPuiws93rm7mPUu21RdBnkeZNrbfCFCwfAhPWY+rR3zG0ubpe5cEReHOw5fIbfmsxEV/g2kSxGTATY3Bpnwg==", "dev": true, "requires": { "find-up": "^2.1.0" @@ -76502,73 +79846,33 @@ }, "pluralize": { "version": "8.0.0", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true }, "pn": { "version": "1.1.0", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", "dev": true }, "png-async": { "version": "0.9.4", - "integrity": "sha512-B//AXX9TkneKfgtOpT1mdUnnhk2BImGD+a98vImsMU8uo1dBeHyW/kM2erWZ/CsYteTPU/xKG+t6T62heHkC3A==", "dev": true }, "pnp-webpack-plugin": { "version": "1.6.4", - "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==", "requires": { "ts-pnp": "^1.1.6" } }, "polished": { "version": "3.7.2", - "integrity": "sha512-pQKtpZGmsZrW8UUpQMAnR7s3ppHeMQVNyMDKtUyKwuvDmklzcEyM5Kllb3JyE/sE/x7arDmyd35i+4vp99H6sQ==", "requires": { "@babel/runtime": "^7.12.5" } }, - "portfinder": { - "version": "1.0.28", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "dependencies": { - "async": { - "version": "2.6.3", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, - "debug": { - "version": "3.2.6", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, "posix-character-classes": { - "version": "0.1.1", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==" + "version": "0.1.1" }, "postcss": { "version": "8.3.6", - "integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==", "dev": true, "requires": { "colorette": "^1.2.2", @@ -76578,35 +79882,30 @@ "dependencies": { "nanoid": { "version": "3.1.25", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", "dev": true } } }, "postcss-flexbugs-fixes": { "version": "4.2.1", - "integrity": "sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==", "requires": { "postcss": "^7.0.26" }, "dependencies": { "postcss": { "version": "7.0.39", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "requires": { "picocolors": "^0.2.1", "source-map": "^0.6.1" } }, "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } }, "postcss-loader": { "version": "4.3.0", - "integrity": "sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==", "requires": { "cosmiconfig": "^7.0.0", "klona": "^2.0.4", @@ -76616,12 +79915,10 @@ }, "dependencies": { "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3" }, "loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -76630,32 +79927,27 @@ }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "requires": { "yallist": "^4.0.0" } }, "semver": { "version": "7.3.7", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } }, "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "4.0.0" } } }, "postcss-modules-extract-imports": { "version": "3.0.0", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", "dev": true }, "postcss-modules-local-by-default": { "version": "4.0.0", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", "dev": true, "requires": { "icss-utils": "^5.0.0", @@ -76665,7 +79957,6 @@ }, "postcss-modules-scope": { "version": "3.0.0", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", "dev": true, "requires": { "postcss-selector-parser": "^6.0.4" @@ -76673,7 +79964,6 @@ }, "postcss-modules-values": { "version": "4.0.0", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, "requires": { "icss-utils": "^5.0.0" @@ -76681,36 +79971,26 @@ }, "postcss-selector-parser": { "version": "6.0.6", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "postcss-value-parser": { - "version": "4.1.0", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" + "version": "4.2.0" }, "potpack": { - "version": "1.0.1", - "integrity": "sha512-15vItUAbViaYrmaB/Pbw7z6qX2xENbFSTA7Ii4tgbPtasxm5v6ryKhKtL91tpWovDJzTiZqdwzhcFBCwiMVdVw==" + "version": "1.0.2" }, "prelude-ls": { - "version": "1.1.2", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==" - }, - "prepend-http": { - "version": "1.0.4", - "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==" + "version": "1.1.2" }, "prettier": { "version": "2.4.1", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", "dev": true }, "prettier-linter-helpers": { "version": "1.0.0", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "requires": { "fast-diff": "^1.1.2" @@ -76718,19 +79998,13 @@ }, "prettier-plugin-packagejson": { "version": "2.2.15", - "integrity": "sha512-r3WKxw0ALyD3gr3RlIFK3o7mUejCVkqwVKtUuPQaB3+aNiZYKxmad+GpZ6WFWTm6Zq2jX0wvSdlkGccQ2pEnCg==", "dev": true, "requires": { "sort-package-json": "1.53.1" } }, - "pretty-bytes": { - "version": "5.6.0", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==" - }, "pretty-error": { "version": "3.0.4", - "integrity": "sha512-ytLFLfv1So4AO1UkoBF6GXQgJRaKbiSiGFICaOPNwQ3CMvBvXpLRubeQWyPGnsbV/t9ml9qto6IeCsho0aEvwQ==", "requires": { "lodash": "^4.17.20", "renderkid": "^2.0.6" @@ -76738,7 +80012,6 @@ }, "pretty-format": { "version": "26.6.2", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, "requires": { "@jest/types": "^26.6.2", @@ -76749,55 +80022,45 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, "react-is": { "version": "17.0.2", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true } } }, "pretty-hrtime": { - "version": "1.0.3", - "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==" + "version": "1.0.3" }, "pretty-ms": { "version": "7.0.1", - "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", "requires": { "parse-ms": "^2.1.0" } }, "prismjs": { - "version": "1.27.0", - "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==" + "version": "1.27.0" }, "probe.gl": { "version": "3.4.0", - "integrity": "sha512-9CLByZATuhuG/Viq3ckfWU+dAhb7dMmjzsyCy4s7ds9ueTejcVRENxL197/XacOK/AN61YrEERB0QnouB0Qc0Q==", "requires": { "@babel/runtime": "^7.0.0", "@probe.gl/stats": "3.4.0" } }, "process": { - "version": "0.11.10", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" + "version": "0.11.10" }, "process-nextick-args": { - "version": "2.0.0", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "version": "2.0.0" }, "progress": { "version": "2.0.3", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "progress-stream": { "version": "2.0.0", - "integrity": "sha512-xJwOWR46jcXUq6EH9yYyqp+I52skPySOeHfkxOZ2IY1AiBi/sFJhbhAKHoV3OTw/omQ45KTio9215dRJ2Yxd3Q==", "dev": true, "requires": { "speedometer": "~1.0.0", @@ -76806,18 +80069,23 @@ }, "promise": { "version": "7.3.1", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "requires": { "asap": "~2.0.3" } }, - "promise-inflight": { + "promise-all-reject-late": { "version": "1.0.1", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + "dev": true + }, + "promise-call-limit": { + "version": "1.0.1", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1" }, "promise-retry": { "version": "2.0.1", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "dev": true, "requires": { "err-code": "^2.0.2", @@ -76826,14 +80094,12 @@ "dependencies": { "retry": { "version": "0.12.0", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "dev": true } } }, "promise.allsettled": { "version": "1.0.5", - "integrity": "sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ==", "requires": { "array.prototype.map": "^1.0.4", "call-bind": "^1.0.2", @@ -76845,7 +80111,6 @@ }, "promise.prototype.finally": { "version": "3.1.3", - "integrity": "sha512-EXRF3fC9/0gz4qkt/f5EP5iW4kj9oFpBICNpCNOb/52+8nlHIX07FPLbi/q4qYBQ1xZqivMzTpNQSnArVASolQ==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -76854,7 +80119,6 @@ }, "prompts": { "version": "2.4.0", - "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", "requires": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -76862,30 +80126,21 @@ }, "promzard": { "version": "0.3.0", - "integrity": "sha512-JZeYqd7UAcHCwI+sTOeUDYkvEU+1bQ7iE0UT1MgB/tERkAPkesW46MrpIySzODi+owTjZtiF8Ay5j9m60KmMBw==", "dev": true, "requires": { "read": "1" } }, "prop-types": { - "version": "15.7.2", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } + "react-is": "^16.13.1" } }, "prop-types-exact": { "version": "1.2.0", - "integrity": "sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA==", "dev": true, "requires": { "has": "^1.0.3", @@ -76895,58 +80150,87 @@ }, "property-information": { "version": "5.6.0", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", "requires": { "xtend": "^4.0.0" } }, "proto-list": { - "version": "1.2.4", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" + "version": "1.2.4" }, "protocol-buffers-schema": { - "version": "3.4.0", - "integrity": "sha512-G/2kcamPF2S49W5yaMGdIpkG6+5wZF0fzBteLKgEHjbNzqjZQ85aAs1iJGto31EJaSTkNvHs5IXuHSaTLWBAiA==" + "version": "3.4.0" }, "protocols": { - "version": "1.4.8", - "integrity": "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg==", + "version": "2.0.1", "dev": true }, "proxy-addr": { "version": "2.0.7", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "requires": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" }, "dependencies": { "forwarded": { - "version": "0.2.0", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + "version": "0.2.0" }, "ipaddr.js": { - "version": "1.9.1", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + "version": "1.9.1" + } + } + }, + "proxy-agent": { + "version": "5.0.0", + "dev": true, + "requires": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "dev": true + }, + "socks-proxy-agent": { + "version": "5.0.1", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + } } } }, + "proxy-from-env": { + "version": "1.0.0", + "dev": true + }, "prr": { - "version": "1.0.1", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==" + "version": "1.0.1" }, "pseudomap": { - "version": "1.0.2", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + "version": "1.0.2" }, "psl": { "version": "1.8.0", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, "public-encrypt": { "version": "4.0.3", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "requires": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", @@ -76957,14 +80241,12 @@ }, "dependencies": { "bn.js": { - "version": "4.12.0", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.0" } } }, "pump": { "version": "3.0.0", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -76972,7 +80254,6 @@ }, "pumpify": { "version": "1.5.1", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "requires": { "duplexify": "^3.6.0", "inherits": "^2.0.3", @@ -76981,7 +80262,6 @@ "dependencies": { "pump": { "version": "2.0.1", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -76990,12 +80270,10 @@ } }, "punycode": { - "version": "2.1.1", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "version": "2.1.1" }, "puppeteer": { "version": "10.2.0", - "integrity": "sha512-OR2CCHRashF+f30+LBOtAjK6sNtz2HEyTr5FqAvhf8lR/qB3uBRoIZOwQKgwoyZnMBsxX7ZdazlyBgGjpnkiMw==", "dev": true, "requires": { "debug": "4.3.1", @@ -77014,7 +80292,6 @@ "dependencies": { "debug": { "version": "4.3.1", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -77022,7 +80299,6 @@ }, "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { "locate-path": "^5.0.0", @@ -77031,7 +80307,6 @@ }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { "p-locate": "^4.1.0" @@ -77039,17 +80314,14 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "node-fetch": { "version": "2.6.1", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", "dev": true }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -77057,7 +80329,6 @@ }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { "p-limit": "^2.2.0" @@ -77065,17 +80336,14 @@ }, "p-try": { "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "path-exists": { "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "pkg-dir": { "version": "4.2.0", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { "find-up": "^4.0.0" @@ -77083,38 +80351,28 @@ }, "progress": { "version": "2.0.1", - "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", "dev": true }, "proxy-from-env": { "version": "1.1.0", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, "ws": { "version": "7.4.6", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", "dev": true } } }, - "pure-color": { - "version": "1.3.0", - "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" - }, "q": { "version": "1.5.1", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", "dev": true }, "qs": { - "version": "6.5.2", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.5.3", "dev": true }, "query-string": { "version": "6.14.1", - "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==", "requires": { "decode-uri-component": "^0.2.0", "filter-obj": "^1.1.0", @@ -77123,30 +80381,24 @@ } }, "querystring": { - "version": "0.2.0", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" + "version": "0.2.0" }, "querystring-es3": { - "version": "0.2.1", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==" + "version": "0.2.1" }, "querystringify": { "version": "2.2.0", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, "quick-lru": { "version": "4.0.1", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, "quickselect": { - "version": "2.0.0", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + "version": "2.0.0" }, "quote-stream": { "version": "1.0.2", - "integrity": "sha512-kKr2uQ2AokadPjvTyKJQad9xELbZwYzWlNfI3Uz2j/ib5u6H9lDP7fUUR//rMycd0gv4Z5P1qXMfXR8YpIxrjQ==", "requires": { "buffer-equal": "0.0.1", "minimist": "^1.1.3", @@ -77155,19 +80407,17 @@ }, "raf": { "version": "3.4.1", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dev": true, "requires": { "performance-now": "^2.1.0" } }, "railroad-diagrams": { "version": "1.0.0", - "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", "dev": true }, "randexp": { "version": "0.4.6", - "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", "dev": true, "requires": { "discontinuous-range": "1.0.0", @@ -77176,73 +80426,62 @@ }, "randombytes": { "version": "2.1.0", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { "safe-buffer": "^5.1.0" } }, "randomfill": { "version": "1.0.4", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "requires": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" } }, "range-parser": { - "version": "1.2.1", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + "version": "1.2.1" }, "raw-body": { - "version": "2.4.0", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.3", "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "dependencies": { "bytes": { - "version": "3.1.0", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "version": "3.1.2" }, "http-errors": { - "version": "1.7.2", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", "requires": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" } }, - "setprototypeof": { - "version": "1.1.1", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "inherits": { + "version": "2.0.4" }, - "statuses": { - "version": "1.5.0", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + "setprototypeof": { + "version": "1.2.0" } } }, "raw-loader": { "version": "4.0.2", - "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", "requires": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" }, "dependencies": { "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3" }, "loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -77253,32 +80492,16 @@ }, "rc-align": { "version": "4.0.9", - "integrity": "sha512-myAM2R4qoB6LqBul0leaqY8gFaiECDJ3MtQDmzDo9xM9NRT/04TvWOYd2YHU9zvGzqk9QXF6S9/MifzSKDZeMw==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "2.x", "dom-align": "^1.7.0", "rc-util": "^5.3.0", "resize-observer-polyfill": "^1.5.1" - }, - "dependencies": { - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "requires": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } } }, "rc-cascader": { "version": "1.4.0", - "integrity": "sha512-6kgQljDQEKjVAVRkZtvvoi+2qv4u42M6oLuvt4ZDBa16r3X9ZN8TAq3atVyC840ivbGKlHT50OcdVx/iwiHc1w==", "requires": { "array-tree-filter": "^2.1.0", "rc-trigger": "^5.0.4", @@ -77288,7 +80511,6 @@ }, "rc-checkbox": { "version": "2.3.2", - "integrity": "sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1" @@ -77296,51 +80518,16 @@ }, "rc-collapse": { "version": "3.1.0", - "integrity": "sha512-EwpNPJcLe7b+5JfyaxM9ZNnkCgqArt3QQO0Cr5p5plwz/C9h8liAmjYY5I4+hl9lAjBqb7ZwLu94+z+rt5g1WQ==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "2.x", "rc-motion": "^2.3.4", "rc-util": "^5.2.1", "shallowequal": "^1.1.0" - }, - "dependencies": { - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "requires": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } - } - }, - "rc-dialog": { - "version": "8.4.5", - "integrity": "sha512-0a1Uuy1BRBTdIkfR1VE91kis6dBui7tAIPaQQLj28vBdGg9IqVkiLguCdaDW+4E4vZediePz49PKFbLkx2PL5Q==", - "requires": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.6", - "rc-motion": "^2.3.0", - "rc-util": "^5.0.1" - } - }, - "rc-drawer": { - "version": "4.1.0", - "integrity": "sha512-kjeQFngPjdzAFahNIV0EvEBoIKMOnvUsAxpkSPELoD/1DuR4nLafom5ryma+TIxGwkFJ92W6yjsMi1U9aiOTeQ==", - "requires": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.6", - "rc-util": "^5.0.1" } }, "rc-dropdown": { "version": "3.2.0", - "integrity": "sha512-j1HSw+/QqlhxyTEF6BArVZnTmezw2LnSmRk6I9W7BCqNCKaRwleRmMMs1PHbuaG8dKHVqP6e21RQ7vPBLVnnNw==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6", @@ -77349,27 +80536,14 @@ }, "rc-field-form": { "version": "1.17.3", - "integrity": "sha512-EocLncL7uDkxAGywqbtDXe6r8xbru9Yz94JHY7X6XsIdc8sAIGzafMYFaX0hHuwBGbvo7mv7L74cGCuD7xK5Fw==", "requires": { "@babel/runtime": "^7.8.4", "async-validator": "^3.0.3", "rc-util": "^5.0.0" } }, - "rc-image": { - "version": "4.2.0", - "integrity": "sha512-yGqq6wPrIn86hMfC1Hl7M3NNS6zqnl9dvFWJg/StuI86jZBU0rm9rePTfKs+4uiwU3HXxpfsXlaG2p8GWRDLiw==", - "requires": { - "@ant-design/icons": "^4.2.2", - "@babel/runtime": "^7.11.2", - "classnames": "^2.2.6", - "rc-dialog": "~8.4.0", - "rc-util": "^5.0.6" - } - }, "rc-input-number": { "version": "6.1.2", - "integrity": "sha512-UvP0tpOUeGetx6caS8RzBs3Du+NwPUn9ijQ3LeR1jOmzjXNuXvv58U6hvIXSHx/4ulPleQ5BAQP/aLTsFB4yGw==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.5", @@ -77378,7 +80552,6 @@ }, "rc-mentions": { "version": "1.5.2", - "integrity": "sha512-GqV0tOtHY3pLpOsFCxJ2i6Ad8AVfxFmz0NlD/8rb8IG8pMpthJKcdfnXlNZRx3Fa9O4YEgJpdSY1WEbmlx2DWQ==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6", @@ -77390,7 +80563,6 @@ }, "rc-menu": { "version": "8.10.1", - "integrity": "sha512-HmTOLPkSrz5RcdDopD4+nI95YXR2DzdSq9ek3NX2EVgD1UHknlp1QAEJ5MompYdAqdtOspJUqgM/zNt0iQALOw==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "2.x", @@ -77401,48 +80573,18 @@ "rc-util": "^5.5.0", "resize-observer-polyfill": "^1.5.0", "shallowequal": "^1.1.0" - }, - "dependencies": { - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "requires": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } } }, "rc-motion": { "version": "2.4.1", - "integrity": "sha512-TWLvymfMu8SngPx5MDH8dQ0D2RYbluNTfam4hY/dNNx9RQ3WtGuZ/GXHi2ymLMzH+UNd6EEFYkOuR5JTTtm8Xg==", "requires": { "@babel/runtime": "^7.11.1", "classnames": "^2.2.1", "rc-util": "^5.2.1" - }, - "dependencies": { - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "requires": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } } }, "rc-notification": { "version": "4.5.4", - "integrity": "sha512-VsN0ouF4uglE5g3C9oDsXLNYX0Sz++ZNUFYCswkxhpImYJ9u6nJOpyA71uOYDVCu6bAF54Y5Hi/b+EcnMzkepg==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "2.x", @@ -77452,43 +80594,13 @@ }, "rc-pagination": { "version": "3.1.2", - "integrity": "sha512-KbJvkTvRiD51vTIAi0oTARPUHNb0iV6njbDBe8yLkc3PWYDJaszASfuss6YJ98EIxEeGzuEk6xsUAEKWRJgz2g==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1" } }, - "rc-picker": { - "version": "2.4.3", - "integrity": "sha512-tOIHslTQKpoGNmbpp6YOBwS39dQSvtAuhOm3bWCkkc4jCqUqeR/velCwqefZX1BX4+t1gUMc1dIia9XvOKrEkg==", - "requires": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.1", - "date-fns": "^2.15.0", - "dayjs": "^1.8.30", - "moment": "^2.24.0", - "rc-trigger": "^5.0.4", - "rc-util": "^5.4.0", - "shallowequal": "^1.1.0" - }, - "dependencies": { - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "requires": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } - } - }, "rc-progress": { "version": "3.1.1", - "integrity": "sha512-1ns3pW7ll9bHfdXtlVLF+vngdvlxiCDtiqwXnZFEdurst11JTiPxVdeqnCNbhWx5hP4kCKkAPqG1N0FVfTSUGA==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6" @@ -77496,7 +80608,6 @@ }, "rc-rate": { "version": "2.9.1", - "integrity": "sha512-MmIU7FT8W4LYRRHJD1sgG366qKtSaKb67D0/vVvJYR0lrCuRrCiVQ5qhfT5ghVO4wuVIORGpZs7ZKaYu+KMUzA==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.5", @@ -77505,7 +80616,6 @@ }, "rc-resize-observer": { "version": "0.2.6", - "integrity": "sha512-YX6nYnd6fk7zbuvT6oSDMKiZjyngjHoy+fz+vL3Tez38d/G5iGdaDJa2yE7345G6sc4Mm1IGRUIwclvltddhmA==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1", @@ -77513,33 +80623,8 @@ "resize-observer-polyfill": "^1.5.1" } }, - "rc-select": { - "version": "11.5.3", - "integrity": "sha512-ASSO4J/ayfbQQ+KOEounIMGhySDHpQtrIuH1WEABOBy8HgKec8kOLmyLH+YIXSUDnTf/gtxmflgFtl7sQ9pkSw==", - "requires": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-motion": "^2.0.1", - "rc-trigger": "^5.0.4", - "rc-util": "^5.0.1", - "rc-virtual-list": "^3.2.0", - "warning": "^4.0.3" - } - }, - "rc-slider": { - "version": "9.6.5", - "integrity": "sha512-XRUJDK668hy8MwGnHzZlXCQXXIOUnEs4m2vwk1jgDILVBxI0GwGOlC6T499pYY+NEWg8YgdCOAucFs/+X5WHpg==", - "requires": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.5", - "rc-tooltip": "^5.0.1", - "rc-util": "^5.0.0", - "shallowequal": "^1.1.0" - } - }, "rc-steps": { "version": "4.1.3", - "integrity": "sha512-GXrMfWQOhN3sVze3JnzNboHpQdNHcdFubOETUHyDpa/U3HEKBZC3xJ8XK4paBgF4OJ3bdUVLC+uBPc6dCxvDYA==", "requires": { "@babel/runtime": "^7.10.2", "classnames": "^2.2.3", @@ -77548,41 +80633,14 @@ }, "rc-switch": { "version": "3.2.2", - "integrity": "sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1", "rc-util": "^5.0.1" } }, - "rc-table": { - "version": "7.11.3", - "integrity": "sha512-YyZry1CdqUrcH7MmWtLQZVvVZWbmTEbI5m650AZ+zYw4D5VF701samkMYl5z/H9yQFr+ugvDtXcya+e3vwRkMQ==", - "requires": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.5", - "rc-resize-observer": "^0.2.0", - "rc-util": "^5.4.0", - "shallowequal": "^1.1.0" - }, - "dependencies": { - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "requires": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } - } - }, "rc-tabs": { "version": "11.7.2", - "integrity": "sha512-2M/XE4TdecnjsDylJSs49OmjJuDuix3VmSiNaPd50PMqFc+dc4fEof3J8/ad12enicVOcsH4BEQEms//Kn4DBw==", "requires": { "@babel/runtime": "^7.11.2", "classnames": "2.x", @@ -77590,157 +80648,51 @@ "rc-menu": "^8.6.1", "rc-resize-observer": "^0.2.1", "rc-util": "^5.5.0" - }, - "dependencies": { - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "requires": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } } }, "rc-textarea": { "version": "0.3.2", - "integrity": "sha512-569hiqCtkZFCcxBpKLM+IdnjZDQCFoy7RlQ4bkked0wp9uh+ofgk5zuQNJPiPyMYzpKYRlYeZgJ1bnK/8Po0Sg==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1", "omit.js": "^2.0.0", - "rc-resize-observer": "^0.2.3" - } - }, - "rc-tooltip": { - "version": "5.0.1", - "integrity": "sha512-3AnxhUS0j74xAV3khrKw8o6rg+Ima3nw09DJBezMPnX3ImQUAnayWsPSlN1mEnihjA43rcFkGM1emiKE+CXyMQ==", - "requires": { - "@babel/runtime": "^7.11.2", - "rc-trigger": "^5.0.0" - } - }, - "rc-tree": { - "version": "4.0.0", - "integrity": "sha512-C2xlkA+/IypkHBPzbpAJGVWJh2HjeRbYCusA/m5k09WT6hQT0nC7LtLVmnb7QZecdBQPhoOgQh8gPwBR+xEMjQ==", - "requires": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-motion": "^2.0.1", - "rc-util": "^5.0.0", - "rc-virtual-list": "^3.0.1" - } - }, - "rc-tree-select": { - "version": "4.2.0", - "integrity": "sha512-VrrvBiOov6WR44RTGMqSw1Dmodg6Y++EH6a6R0ew43qsV4Ob0FGYRgoX811kImtt2Z+oAPJ6zZXN4WKtsQd3Gw==", - "requires": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-select": "^11.1.1", - "rc-tree": "^4.0.0", - "rc-util": "^5.0.5" + "rc-resize-observer": "^0.2.3" } }, "rc-trigger": { "version": "5.2.0", - "integrity": "sha512-fpC1ZkM/IgIIDfF6XHx3Hb2zXy9wvdI5eMh+6DdLygk6Z3HGmkri6ZCXg9a0wfF9AFuzlYTeBLS1uRASZRsnMQ==", "requires": { "@babel/runtime": "^7.11.2", "classnames": "^2.2.6", "rc-align": "^4.0.0", "rc-motion": "^2.0.0", "rc-util": "^5.5.0" - }, - "dependencies": { - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "requires": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } } }, "rc-upload": { "version": "3.3.4", - "integrity": "sha512-v2sirR4JL31UTHD/f0LGUdd+tpFaOVUTPeIEjAXRP9kRN8TFhqOgcXl5ixtyqj90FmtRUmKmafCv0EmhBQUHqQ==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.5", "rc-util": "^5.2.0" - }, - "dependencies": { - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "requires": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } } }, "rc-util": { - "version": "5.0.6", - "integrity": "sha512-uLGxF9WjbpJSjd6iDnIjl8ZeMUglpcuh1DwO26aaXh++yAmlB6eIAJMUwwJCuqJvo4quCvsDPg1VkqHILc4U0A==", + "version": "5.24.4", "requires": { + "@babel/runtime": "^7.18.3", "react-is": "^16.12.0", "shallowequal": "^1.1.0" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } - } - }, - "rc-virtual-list": { - "version": "3.2.3", - "integrity": "sha512-uEeYDQWwQhxR97SekPeGRbzPtHSbSpw/mYb6QpZZ9bA43kf7s1socV3fD3ySYhQVzo0I+/IUD9jFGit6FbM0WA==", - "requires": { - "classnames": "^2.2.6", - "rc-resize-observer": "^0.2.3", - "rc-util": "^5.0.7" - }, - "dependencies": { - "rc-util": { - "version": "5.5.1", - "integrity": "sha512-lnkBptu1RX65GO6jf28scbDMM/9MVl/hYI0uMEVM+cQ0ALLhFChDzgv7ciNpjayCH88wSDHTp6582es4tzJHhA==", - "requires": { - "react-is": "^16.12.0", - "shallowequal": "^1.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } } }, "re-resizable": { "version": "6.6.1", - "integrity": "sha512-ttWVasZ9X7c0ir0+4YK47tkmm9EAFssW07YLkeLzG5HCOuFgFAlSVzMlzAH0h3i6hDShQCHHJecVx5rk+snoFA==", "requires": { "fast-memoize": "^2.5.1" } }, "react": { "version": "16.14.0", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -77748,10 +80700,9 @@ } }, "react-ace": { - "version": "9.5.0", - "integrity": "sha512-4l5FgwGh6K7A0yWVMQlPIXDItM4Q9zzXRqOae8KkCl6MkOob7sC1CzHxZdOGvV+QioKWbX2p5HcdOVUv6cAdSg==", + "version": "10.1.0", "requires": { - "ace-builds": "^1.4.13", + "ace-builds": "^1.4.14", "diff-match-patch": "^1.0.5", "lodash.get": "^4.4.2", "lodash.isequal": "^4.5.0", @@ -77759,42 +80710,50 @@ } }, "react-base16-styling": { - "version": "0.5.3", - "integrity": "sha512-EPuchwVvYPSFFIjGpH0k6wM0HQsmJ0vCk7BSl5ryxMVFIWW4hX4Kksu4PNtxfgOxDebTLkJQ8iC7zwAql0eusg==", + "version": "0.9.1", "requires": { + "@babel/runtime": "^7.16.7", + "@types/base16": "^1.0.2", + "@types/lodash": "^4.14.178", "base16": "^1.0.0", - "lodash.curry": "^4.0.1", - "lodash.flow": "^3.3.0", - "pure-color": "^1.2.0" + "color": "^3.2.1", + "csstype": "^3.0.10", + "lodash.curry": "^4.1.1" + }, + "dependencies": { + "csstype": { + "version": "3.1.1" + } } }, "react-bootstrap-slider": { "version": "2.1.5", - "integrity": "sha512-7rO3JlCVIpr+XtwiSfg8r+MPqyl9KdLI61pNuSMBYYQZ42IWBC+kk/UDyYevp76aGAMtd9SCW8erxOvq+VpekQ==", "requires": { "bootstrap-slider": "9.9.0", "es6bindall": "^0.0.9" }, "dependencies": { "bootstrap-slider": { - "version": "9.9.0", - "integrity": "sha512-3U8owtxLBekUu6qn+evqlI9S2Q4bTrY5cJqDhg4CzyQJzKSwdUhztE40Hvg+1azpylQgMDUK38uvKGpgcK27fA==" + "version": "9.9.0" } } }, "react-checkbox-tree": { - "version": "1.5.1", - "integrity": "sha512-fBLMVpd7/YXavzIBz+3OMS5eo2oZLW9PlTY4M1zrJ3TdZRzgILicSzRj6V5VKKm80y8uQXn60skn98pwn3i3Ig==", + "version": "1.8.0", "requires": { "classnames": "^2.2.5", "lodash": "^4.17.10", - "nanoid": "^2.0.0", + "nanoid": "^3.0.0", "prop-types": "^15.5.8" + }, + "dependencies": { + "nanoid": { + "version": "3.3.4" + } } }, "react-color": { "version": "2.14.1", - "integrity": "sha512-ssv2ArSZdhTbIs29hyfw8JW+s3G4BCx/ILkwCajWZzrcx/2ZQfRpsaLVt38LAPbxe50LLszlmGtRerA14JzzRw==", "requires": { "lodash": "^4.0.1", "material-colors": "^1.2.1", @@ -77804,19 +80763,34 @@ } }, "react-colorful": { - "version": "5.5.0", - "integrity": "sha512-BuzrlrM0ylg7coPkXOrRqlf2BgHLw5L44sybbr9Lg4xy7w9e5N7fGYbojOO0s8J0nvrM3PERN2rVFkvSa24lnQ==" + "version": "5.5.0" }, "react-datetime": { - "version": "3.0.4", - "integrity": "sha512-v6MVwCve+DRaLN2f22LTO5TlrPpkUXumPkp1zfrbhaFtSYGl2grZ2JtwJfLxRj/T4ACyePAV4srCR6cMSiQ/Iw==", + "version": "3.2.0", "requires": { "prop-types": "^15.5.7" } }, + "react-diff-viewer-continued": { + "version": "3.2.5", + "requires": { + "classnames": "^2.3.1", + "diff": "^5.1.0", + "emotion": "^10.0.27", + "memoize-one": "^6.0.0", + "prop-types": "^15.8.1" + }, + "dependencies": { + "diff": { + "version": "5.1.0" + }, + "memoize-one": { + "version": "6.0.0" + } + } + }, "react-dnd": { "version": "11.1.3", - "integrity": "sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==", "requires": { "@react-dnd/shallowequal": "^2.0.0", "@types/hoist-non-react-statics": "^3.3.1", @@ -77826,14 +80800,12 @@ }, "react-dnd-html5-backend": { "version": "11.1.3", - "integrity": "sha512-/1FjNlJbW/ivkUxlxQd7o3trA5DE33QiRZgxent3zKme8DwF4Nbw3OFVhTRFGaYhHFNL1rZt6Rdj1D78BjnNLw==", "requires": { "dnd-core": "^11.1.3" } }, "react-docgen": { "version": "5.4.0", - "integrity": "sha512-JBjVQ9cahmNlfjMGxWUxJg919xBBKAoy3hgDgKERbR+BcF4ANpDuzWAScC7j27hZfd8sJNmMPOLWo9+vB/XJEQ==", "requires": { "@babel/core": "^7.7.5", "@babel/generator": "^7.12.11", @@ -77848,12 +80820,10 @@ } }, "react-docgen-typescript": { - "version": "2.1.0", - "integrity": "sha512-7kpzLsYzVxff//HUVz1sPWLCdoSNvHD3M8b/iQLdF8fgf7zp26eVysRrAUSxiAT4yQv2zl09zHjJEYSYNxQ8Jw==" + "version": "2.1.0" }, "react-dom": { "version": "16.14.0", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -77863,7 +80833,6 @@ "dependencies": { "scheduler": { "version": "0.19.1", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -77873,7 +80842,6 @@ }, "react-draggable": { "version": "4.4.3", - "integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.6.0" @@ -77881,7 +80849,6 @@ }, "react-element-to-jsx-string": { "version": "14.3.4", - "integrity": "sha512-t4ZwvV6vwNxzujDQ+37bspnLwA4JlgUPWhLjBJWsNIDceAf6ZKUTCjdm08cN6WeZ5pTMKiCJkmAYnpmR4Bm+dg==", "requires": { "@base2/pretty-print-object": "1.0.1", "is-plain-object": "5.0.0", @@ -77889,26 +80856,21 @@ }, "dependencies": { "is-plain-object": { - "version": "5.0.0", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + "version": "5.0.0" }, "react-is": { - "version": "17.0.2", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + "version": "17.0.2" } } }, "react-error-boundary": { - "version": "1.2.5", - "integrity": "sha512-5CPSeLJA2igJNppAgFRwnTL9aK3ojenk65enNzhVyoxYNbHpIJXnChUO7+4vPhkncRA9wvQMXq6Azp2XeXd+iQ==" + "version": "1.2.5" }, "react-fast-compare": { - "version": "3.2.0", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + "version": "3.2.0" }, "react-gravatar": { "version": "2.6.3", - "integrity": "sha512-yITonigS2LmG7Fw0gWfZfcVwy1mpiBHNVmoFyetitQjXu7JCYoE6jtub0GIfq+ydpnQSYyJT3kwpX6zj1wXR4w==", "requires": { "is-retina": "^1.0.3", "md5": "^2.1.0", @@ -77917,21 +80879,18 @@ "dependencies": { "query-string": { "version": "4.3.4", - "integrity": "sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==", "requires": { "object-assign": "^4.1.0", "strict-uri-encode": "^1.0.0" } }, "strict-uri-encode": { - "version": "1.1.0", - "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==" + "version": "1.1.0" } } }, "react-helmet-async": { "version": "1.3.0", - "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", "requires": { "@babel/runtime": "^7.12.5", "invariant": "^2.2.4", @@ -77941,175 +80900,120 @@ } }, "react-hot-loader": { - "version": "4.13.0", - "integrity": "sha512-JrLlvUPqh6wIkrK2hZDfOyq/Uh/WeVEr8nc7hkn2/3Ul0sx1Kr5y4kOGNacNRoj7RhwLNcQ3Udf1KJXrqc0ZtA==", + "version": "4.13.1", "requires": { "fast-levenshtein": "^2.0.6", "global": "^4.3.0", "hoist-non-react-statics": "^3.3.0", - "loader-utils": "^1.1.0", + "loader-utils": "^2.0.3", "prop-types": "^15.6.1", "react-lifecycles-compat": "^3.0.4", "shallowequal": "^1.1.0", "source-map": "^0.7.3" }, "dependencies": { + "json5": { + "version": "2.2.3" + }, + "loader-utils": { + "version": "2.0.4", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, "source-map": { - "version": "0.7.3", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + "version": "0.7.3" } } }, - "react-icons": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.7.1.tgz", - "integrity": "sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==" - }, "react-input-autosize": { "version": "2.2.2", - "integrity": "sha512-jQJgYCA3S0j+cuOwzuCd1OjmBmnZLdqQdiLKRYrsMMzbjUrVDS5RvJUDwJqA7sKuksDuzFtm6hZGKFu7Mjk5aw==", "requires": { "prop-types": "^15.5.8" } }, "react-inspector": { "version": "5.1.1", - "integrity": "sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg==", "requires": { "@babel/runtime": "^7.0.0", "is-dom": "^1.0.0", "prop-types": "^15.0.0" } }, + "react-intersection-observer": { + "version": "9.4.1" + }, "react-is": { - "version": "16.6.3", - "integrity": "sha512-u7FDWtthB4rWibG/+mFbVd5FvdI20yde86qKGx4lVUTWmPlSWQ4QxbBIrrs+HnXGbxOUlUzTAP/VDmvCwaP2yA==" + "version": "16.13.1" }, "react-js-cron": { - "version": "1.2.0", - "integrity": "sha512-mWxTmXkqP58ughdziS3qjEUVl1O03XEo8WDvr45/kTQfbd0C6ITniAsG5wZzwmTOgmrOKQheHog7L0TP683WUA==" + "version": "1.2.0" }, "react-json-tree": { - "version": "0.11.2", - "integrity": "sha512-aYhUPj1y5jR3ZQ+G3N7aL8FbTyO03iLwnVvvEikLcNFqNTyabdljo9xDftZndUBFyyyL0aK3qGO9+8EilILHUw==", + "version": "0.17.0", "requires": { - "babel-runtime": "^6.6.1", - "prop-types": "^15.5.8", - "react-base16-styling": "^0.5.1" + "@babel/runtime": "^7.18.3", + "@types/lodash": "^4.14.182", + "@types/prop-types": "^15.7.5", + "prop-types": "^15.8.1", + "react-base16-styling": "^0.9.1" } }, "react-jsonschema-form": { - "version": "1.2.0", - "integrity": "sha512-rR77qoFiQ5TxDYwsJz8UWmDner4jQ4xMnDqeV6Nvg7GtoEyOUoTVkI/SBMEzfXuF/piWZXYjquP96Hy/2L7C+Q==", + "version": "1.8.1", "requires": { - "ajv": "^5.2.3", - "babel-runtime": "^6.26.0", + "@babel/runtime-corejs2": "^7.4.5", + "ajv": "^6.7.0", "core-js": "^2.5.7", - "lodash.topath": "^4.5.2", - "prop-types": "^15.5.8" + "lodash": "^4.17.15", + "prop-types": "^15.5.8", + "react-is": "^16.8.4", + "react-lifecycles-compat": "^3.0.4", + "shortid": "^2.2.14" }, "dependencies": { - "ajv": { - "version": "5.5.2", - "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, "core-js": { - "version": "2.6.9", - "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==" - }, - "fast-deep-equal": { - "version": "1.1.0", - "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==" - }, - "json-schema-traverse": { - "version": "0.3.1", - "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==" + "version": "2.6.9" } } }, "react-lifecycles-compat": { - "version": "3.0.4", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + "version": "3.0.4" }, "react-lines-ellipsis": { - "version": "0.15.0", - "integrity": "sha512-8kWpEmu7ijmB6Gz5t+eSjNux2SpVXZBsmfeFE8LjMS7tU3H8ai475CyNc0dH0RDTwt4Esr7c06Xq4SB7Gpl9yQ==" + "version": "0.15.0" }, "react-loadable": { "version": "5.5.0", - "integrity": "sha512-C8Aui0ZpMd4KokxRdVAm2bQtI03k2RMRNzOB+IipV3yxFTSVICv7WoUr5L9ALB5BmKO1iHgZtWM8EvYG83otdg==", "requires": { "prop-types": "^15.5.0" } }, "react-map-gl": { - "version": "4.1.16", - "integrity": "sha512-EtiHCeqM69wKR9RDyLvtk6pTPS5+OFeAPIsYw6afnlGTauFAq3iD40SHuAOElgoJmm7J+cjPfHqu7m7tB4/FfA==", + "version": "6.1.19", "requires": { "@babel/runtime": "^7.0.0", - "mapbox-gl": "~0.54.0", - "mjolnir.js": "^2.2.0", + "@types/geojson": "^7946.0.7", + "@types/mapbox-gl": "^2.0.3", + "mapbox-gl": "^2.3.0", + "mjolnir.js": "^2.5.0", "prop-types": "^15.7.2", - "react-virtualized-auto-sizer": "^1.0.2", - "viewport-mercator-project": "^6.2.1" - }, - "dependencies": { - "esm": { - "version": "3.0.84", - "integrity": "sha512-SzSGoZc17S7P+12R9cg21Bdb7eybX25RnIeRZ80xZs+VZ3kdQKzqTp2k4hZJjR7p9l0186TTXSgrxzlMDBktlw==" - }, - "mapbox-gl": { - "version": "0.54.1", - "integrity": "sha512-HtY+HobYTHTsFOJ3buTHtNvZv/Tjfp0vararhEWCjI7wQq8XxK16sEpsXucokrAhuu94js4KJylo13bKJx6l0Q==", - "requires": { - "@mapbox/geojson-rewind": "^0.4.0", - "@mapbox/geojson-types": "^1.0.2", - "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/mapbox-gl-supported": "^1.4.0", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^1.1.0", - "@mapbox/unitbezier": "^0.0.0", - "@mapbox/vector-tile": "^1.3.1", - "@mapbox/whoots-js": "^3.1.0", - "csscolorparser": "~1.0.2", - "earcut": "^2.1.5", - "esm": "~3.0.84", - "geojson-vt": "^3.2.1", - "gl-matrix": "^3.0.0", - "grid-index": "^1.1.0", - "minimist": "0.0.8", - "murmurhash-js": "^1.0.0", - "pbf": "^3.0.5", - "potpack": "^1.0.1", - "quickselect": "^2.0.0", - "rw": "^1.3.3", - "supercluster": "^6.0.1", - "tinyqueue": "^2.0.0", - "vt-pbf": "^3.1.1" - } - }, - "minimist": { - "version": "0.0.8", - "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==" - }, - "supercluster": { - "version": "6.0.2", - "integrity": "sha512-aa0v2HURjBTOpbcknilcfxGDuArM8khklKSmZ/T8ZXL0BuRwb5aRw95lz+2bmWpFvCXDX/+FzqHxmg0TIaJErw==", + "resize-observer-polyfill": "^1.5.1", + "viewport-mercator-project": "^7.0.4" + }, + "dependencies": { + "viewport-mercator-project": { + "version": "7.0.4", "requires": { - "kdbush": "^3.0.0" + "@math.gl/web-mercator": "^3.5.5" } } } }, "react-markdown": { - "version": "8.0.4", - "integrity": "sha512-2oxHa6oDxc1apg/Gnc1Goh06t3B617xeywqI/92wmDV9FELI6ayRkwge7w7DoEqM0gRpZGTNU6xQG+YpJISnVg==", + "version": "8.0.3", "requires": { "@types/hast": "^2.0.0", "@types/prop-types": "^15.0.0", @@ -78129,26 +81033,21 @@ }, "dependencies": { "comma-separated-tokens": { - "version": "2.0.3", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" + "version": "2.0.2" }, "property-information": { - "version": "6.2.0", - "integrity": "sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==" + "version": "6.1.1" }, "react-is": { - "version": "18.2.0", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "version": "18.2.0" }, "space-separated-tokens": { - "version": "2.0.2", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" + "version": "2.0.1" } } }, "react-move": { "version": "2.9.1", - "integrity": "sha512-5qKYsJrKKpSypEaaYyR2HBbBgX65htRqKDa8o5OGDkq2VfklmTCbLawtYFpdmcJRqbz4jCYpzo2Rrsazq9HA8Q==", "requires": { "@babel/runtime": "^7.2.0", "d3-interpolate": "^1.3.2", @@ -78159,7 +81058,6 @@ }, "react-popper": { "version": "2.2.5", - "integrity": "sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==", "requires": { "react-fast-compare": "^3.0.1", "warning": "^4.0.2" @@ -78167,65 +81065,84 @@ }, "react-popper-tooltip": { "version": "3.1.1", - "integrity": "sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ==", "requires": { "@babel/runtime": "^7.12.5", "@popperjs/core": "^2.5.4", "react-popper": "^2.2.4" } }, - "react-redux": { - "version": "7.2.0", - "integrity": "sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA==", + "react-query": { + "version": "3.39.2", "requires": { "@babel/runtime": "^7.5.5", - "hoist-non-react-statics": "^3.3.0", + "broadcast-channel": "^3.4.1", + "match-sorter": "^6.0.2" + }, + "dependencies": { + "broadcast-channel": { + "version": "3.7.0", + "requires": { + "@babel/runtime": "^7.7.2", + "detect-node": "^2.1.0", + "js-sha3": "0.8.0", + "microseconds": "0.2.0", + "nano-time": "1.0.0", + "oblivious-set": "1.0.0", + "rimraf": "3.0.2", + "unload": "2.2.0" + } + }, + "unload": { + "version": "2.2.0", + "requires": { + "@babel/runtime": "^7.6.2", + "detect-node": "^2.0.4" + } + } + } + }, + "react-redux": { + "version": "7.2.8", + "requires": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", "loose-envify": "^1.4.0", "prop-types": "^15.7.2", - "react-is": "^16.9.0" + "react-is": "^17.0.2" }, "dependencies": { "react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "version": "17.0.2" } } }, "react-refresh": { - "version": "0.11.0", - "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" + "version": "0.11.0" }, "react-resizable": { "version": "3.0.4", - "integrity": "sha512-StnwmiESiamNzdRHbSSvA65b0ZQJ7eVQpPusrSmcpyGKzC0gojhtO62xxH6YOBmepk9dQTBi9yxidL3W4s3EBA==", "requires": { "prop-types": "15.x", "react-draggable": "^4.0.3" } }, "react-resize-detector": { - "version": "6.7.6", - "integrity": "sha512-/6RZlul1yePSoYJxWxmmgjO320moeLC/khrwpEVIL+D2EjLKhqOwzFv+H8laMbImVj7Zu4FlMa0oA7au3/ChjQ==", + "version": "7.1.2", "requires": { - "@types/resize-observer-browser": "^0.1.6", - "lodash.debounce": "^4.0.8", - "lodash.throttle": "^4.1.1", - "resize-observer-polyfill": "^1.5.1" + "lodash": "^4.17.21" } }, "react-reverse-portal": { - "version": "2.0.1", - "integrity": "sha512-sj/D9nSHspqV8i8hWkTSZ5Ohnrqk2A5fkDKw4Xe/zV4OfF1UYwmbzrxLdmNRdKkWgQwnXIxaa2E3FC7QYdZAeA==" + "version": "2.1.1" }, "react-router": { - "version": "5.1.2", - "integrity": "sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A==", + "version": "5.3.4", "requires": { - "@babel/runtime": "^7.1.2", + "@babel/runtime": "^7.12.13", "history": "^4.9.0", "hoist-non-react-statics": "^3.1.0", "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.3.0", "path-to-regexp": "^1.7.0", "prop-types": "^15.6.2", "react-is": "^16.6.0", @@ -78234,12 +81151,10 @@ }, "dependencies": { "isarray": { - "version": "0.0.1", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + "version": "0.0.1" }, "path-to-regexp": { "version": "1.8.0", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", "requires": { "isarray": "0.0.1" } @@ -78247,35 +81162,31 @@ } }, "react-router-dom": { - "version": "5.1.2", - "integrity": "sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew==", + "version": "5.3.4", "requires": { - "@babel/runtime": "^7.1.2", + "@babel/runtime": "^7.12.13", "history": "^4.9.0", "loose-envify": "^1.3.1", "prop-types": "^15.6.2", - "react-router": "5.1.2", + "react-router": "5.3.4", "tiny-invariant": "^1.0.2", "tiny-warning": "^1.0.0" } }, "react-search-input": { "version": "0.11.3", - "integrity": "sha512-Yo05lNR5YLeIY+mTEk0lMkYHX0qkTlElJmxMTw5JlZPu92EP8YWwIY3QSbEFULvX4wiTfyDdUovTUpp2VockpA==", "requires": { "fuse.js": "^3.0.0", "prop-types": "^15.5.8" }, "dependencies": { "fuse.js": { - "version": "3.6.1", - "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==" + "version": "3.6.1" } } }, "react-select": { - "version": "3.1.0", - "integrity": "sha512-wBFVblBH1iuCBprtpyGtd1dGMadsG36W5/t2Aj8OE6WbByDg5jIFyT7X5gT+l0qmT5TqWhxX+VsKJvCEl2uL9g==", + "version": "3.2.0", "requires": { "@babel/runtime": "^7.4.4", "@emotion/cache": "^10.0.9", @@ -78283,13 +81194,12 @@ "@emotion/css": "^10.0.9", "memoize-one": "^5.0.0", "prop-types": "^15.6.0", - "react-input-autosize": "^2.2.2", + "react-input-autosize": "^3.0.0", "react-transition-group": "^4.3.0" }, "dependencies": { "@emotion/cache": { "version": "10.0.29", - "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", "requires": { "@emotion/sheet": "0.9.4", "@emotion/stylis": "0.8.5", @@ -78299,15 +81209,19 @@ }, "dom-helpers": { "version": "5.1.4", - "integrity": "sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A==", "requires": { "@babel/runtime": "^7.8.7", "csstype": "^2.6.7" } }, + "react-input-autosize": { + "version": "3.0.0", + "requires": { + "prop-types": "^15.5.8" + } + }, "react-transition-group": { "version": "4.4.1", - "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", "requires": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -78319,7 +81233,6 @@ }, "react-sizeme": { "version": "3.0.2", - "integrity": "sha512-xOIAOqqSSmKlKFJLO3inBQBdymzDuXx4iuwkNcJmC96jeiOg5ojByvL+g3MW9LPEsojLbC6pf68zOfobK8IPlw==", "requires": { "element-resize-detector": "^1.2.2", "invariant": "^2.2.4", @@ -78328,8 +81241,7 @@ } }, "react-sortable-hoc": { - "version": "1.11.0", - "integrity": "sha512-v1CDCvdfoR3zLGNp6qsBa4J1BWMEVH25+UKxF/RvQRh+mrB+emqtVHMgZ+WreUiKJoEaiwYoScaueIKhMVBHUg==", + "version": "2.0.0", "requires": { "@babel/runtime": "^7.2.0", "invariant": "^2.2.4", @@ -78338,45 +81250,32 @@ }, "react-split": { "version": "2.0.14", - "integrity": "sha512-bKWydgMgaKTg/2JGQnaJPg51T6dmumTWZppFgEbbY0Fbme0F5TuatAScCLaqommbGQQf/ZT1zaejuPDriscISA==", "requires": { "prop-types": "^15.5.7", "split.js": "^1.6.0" }, "dependencies": { "split.js": { - "version": "1.6.2", - "integrity": "sha512-72C7zcQePzlmWqPOKkB2Ro0sUmnWSx+qEWXjLJKk6Qp4jAkFRz1hJgJb+ay6ZQyz/Aw9r8N/PZiCEKbPVpFoDQ==" + "version": "1.6.2" } } }, "react-split-pane": { "version": "0.1.92", - "integrity": "sha512-GfXP1xSzLMcLJI5BM36Vh7GgZBpy+U/X0no+VM3fxayv+p1Jly5HpMofZJraeaMl73b3hvlr+N9zJKvLB/uz9w==", "requires": { "prop-types": "^15.7.2", "react-lifecycles-compat": "^3.0.4", "react-style-proptype": "^3.2.2" } }, - "react-sticky": { - "version": "6.0.3", - "integrity": "sha512-LNH4UJlRatOqo29/VHxDZOf6fwbgfgcHO4mkEFvrie5FuaZCSTGtug5R8NGqJ0kSnX8gHw8qZN37FcvnFBJpTQ==", - "requires": { - "prop-types": "^15.5.8", - "raf": "^3.3.0" - } - }, "react-style-proptype": { "version": "3.2.2", - "integrity": "sha512-ywYLSjNkxKHiZOqNlso9PZByNEY+FTyh3C+7uuziK0xFXu9xzdyfHwg4S9iyiRRoPCR4k2LqaBBsWVmSBwCWYQ==", "requires": { "prop-types": "^15.5.4" } }, "react-syntax-highlighter": { "version": "15.5.0", - "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", "requires": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.4.1", @@ -78386,36 +81285,25 @@ }, "dependencies": { "prismjs": { - "version": "1.28.0", - "integrity": "sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==" + "version": "1.28.0" } } }, "react-table": { - "version": "7.6.3", - "integrity": "sha512-hfPF13zDLxPMpLKzIKCE8RZud9T/XrRTsaCIf8zXpWZIZ2juCl7qrGpo3AQw9eAetXV5DP7s2GDm+hht7qq5Dw==" + "version": "7.8.0" }, "react-test-renderer": { "version": "16.9.0", - "integrity": "sha512-R62stB73qZyhrJo7wmCW9jgl/07ai+YzvouvCXIJLBkRlRqLx4j9RqcLEAfNfU3OxTGucqR2Whmn3/Aad6L3hQ==", "dev": true, "requires": { "object-assign": "^4.1.1", "prop-types": "^15.6.2", "react-is": "^16.9.0", "scheduler": "^0.15.0" - }, - "dependencies": { - "react-is": { - "version": "16.9.0", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", - "dev": true - } } }, "react-textarea-autosize": { "version": "8.3.3", - "integrity": "sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==", "requires": { "@babel/runtime": "^7.10.2", "use-composed-ref": "^1.0.0", @@ -78424,7 +81312,6 @@ }, "react-transition-group": { "version": "2.5.3", - "integrity": "sha512-2DGFck6h99kLNr8pOFk+z4Soq3iISydwOFeeEVPjTN6+Y01CmvbWmnN02VuTWyFdnRtIDPe+wy2q6Ui8snBPZg==", "requires": { "dom-helpers": "^3.3.1", "loose-envify": "^1.4.0", @@ -78433,8 +81320,7 @@ } }, "react-ultimate-pagination": { - "version": "1.2.0", - "integrity": "sha512-tBLzzskuBqsziQDUI98hA7FTBy2/Q5olRsvu3GdLYykfGUgDvYQOI7hLi9o5pD5zJeuAsVn3OoAUw0CaJi0WoQ==", + "version": "1.3.0", "requires": { "prop-types": "^15.0.0", "ultimate-pagination": "1.0.0" @@ -78442,7 +81328,6 @@ }, "react-virtualized": { "version": "9.19.1", - "integrity": "sha512-2l6uFicZKZ3x4rdnS0W+1TfyLmPO/+hfZKsCtoChoSmH5aEezGLpSuHc7oplekNIOaEwChfCk30zjx+Zw6B8YQ==", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.3", @@ -78453,33 +81338,10 @@ } }, "react-virtualized-auto-sizer": { - "version": "1.0.6", - "integrity": "sha512-7tQ0BmZqfVF6YYEWcIGuoR3OdYe8I/ZFbNclFlGOC3pMqunkYF/oL30NCjSGl9sMEb17AnzixDz98Kqc3N76HQ==" - }, - "react-virtualized-select": { - "version": "3.1.3", - "integrity": "sha512-u6j/EfynCB9s4Lz5GGZhNUCZHvFQdtLZws7W/Tcd/v03l19OjpQs3eYjK82iYS0FgD2+lDIBpqS8LpD/hjqDRQ==", - "requires": { - "babel-runtime": "^6.11.6", - "prop-types": "^15.5.8", - "react-select": "^1.0.0-rc.2", - "react-virtualized": "^9.0.0" - }, - "dependencies": { - "react-select": { - "version": "1.3.0", - "integrity": "sha512-g/QAU1HZrzSfxkwMAo/wzi6/ezdWye302RGZevsATec07hI/iSxcpB1hejFIp7V63DJ8mwuign6KmB3VjdlinQ==", - "requires": { - "classnames": "^2.2.4", - "prop-types": "^15.5.8", - "react-input-autosize": "^2.1.2" - } - } - } + "version": "1.0.7" }, "react-window": { - "version": "1.8.5", - "integrity": "sha512-HeTwlNa37AFa8MDZFZOKcNEkuF2YflA0hpGPiTT9vR7OawEt+GZbfM6wqkBahD3D3pUjIabQYzsnY/BSJbgq6Q==", + "version": "1.8.8", "requires": { "@babel/runtime": "^7.0.0", "memoize-one": ">=3.1.1 <6" @@ -78487,7 +81349,6 @@ }, "react-with-styles": { "version": "1.4.0", - "integrity": "sha512-KE+EkYXots4HPbe9V4FRFfkANrpfy/zOBIR2jGaylcOxp4f+17qAaVp0PzCFvhNDoSsH8hSoT7XuK2DQtWn9kQ==", "requires": { "deepmerge": "^1.3.2", "global-cache": "^1.2.0", @@ -78496,145 +81357,125 @@ }, "dependencies": { "hoist-non-react-statics": { - "version": "1.2.0", - "integrity": "sha512-r8huvKK+m+VraiRipdZYc+U4XW43j6OFG/oIafe7GfDbRpCduRoX9JI/DRxqgtBSCeL+et6N6ibZoedHS2NyOQ==" + "version": "1.2.0" } } }, "react-with-styles-interface-aphrodite": { "version": "1.2.0", - "integrity": "sha512-JMo9NaGj77pn1IApVHxkPJC6pQeAC75Yeq3X/HjGp66we9HyzcH9qUpAw9zY1RQNyp6Nwg0mNJA/THU6wDgrkQ==", "requires": { "array-flatten": "^2.1.0", "has": "^1.0.1" } }, "reactable": { - "version": "1.1.0", - "integrity": "sha512-SnvZ3CXyFFxGotw9cqNiVUGb2oW16UlIypGQZRJGgPiJuFqW22jO7A+Y/Tvv8no8F/bZoLdZ+QJP7eZfcc9kCw==" + "version": "1.1.0" }, "reactcss": { "version": "1.2.3", - "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", "requires": { "lodash": "^4.0.1" } }, "read": { "version": "1.0.7", - "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", "dev": true, "requires": { "mute-stream": "~0.0.4" } }, - "read-chunk": { - "version": "3.2.0", - "integrity": "sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==", - "requires": { - "pify": "^4.0.1", - "with-open-file": "^0.1.6" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - } - } - }, - "read-cmd-shim": { - "version": "2.0.0", - "integrity": "sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw==", - "dev": true - }, "read-package-json": { - "version": "3.0.1", - "integrity": "sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng==", + "version": "5.0.2", "dev": true, "requires": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^3.0.0", - "npm-normalize-package-bin": "^1.0.0" + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^2.0.0" }, "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, "hosted-git-info": { - "version": "4.1.0", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "version": "5.2.1", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "lru-cache": "^7.5.1" } }, "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "7.14.1", + "dev": true + }, + "minimatch": { + "version": "5.1.2", "dev": true, "requires": { - "yallist": "^4.0.0" + "brace-expansion": "^2.0.1" } }, "normalize-package-data": { - "version": "3.0.3", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "version": "4.0.1", "dev": true, "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" } }, + "npm-normalize-package-bin": { + "version": "2.0.0", + "dev": true + }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", "dev": true, "requires": { "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } } }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "read-package-json-fast": { "version": "2.0.3", - "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.0", "npm-normalize-package-bin": "^1.0.1" } }, - "read-package-tree": { - "version": "5.3.1", - "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", - "dev": true, - "requires": { - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "util-promisify": "^2.1.0" - }, - "dependencies": { - "read-package-json": { - "version": "2.1.2", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "dev": true, - "requires": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - } - } - }, "read-pkg": { "version": "5.2.0", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "requires": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", @@ -78644,7 +81485,6 @@ "dependencies": { "parse-json": { "version": "5.1.0", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -78653,14 +81493,12 @@ } }, "type-fest": { - "version": "0.6.0", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + "version": "0.6.0" } } }, "read-pkg-up": { "version": "7.0.1", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "requires": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", @@ -78669,7 +81507,6 @@ "dependencies": { "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -78677,38 +81514,32 @@ }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { "p-locate": "^4.1.0" } }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "requires": { "p-limit": "^2.2.0" } }, "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "version": "2.2.0" }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" } } }, "readable-stream": { "version": "2.3.6", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -78721,7 +81552,6 @@ }, "readdir-scoped-modules": { "version": "1.1.0", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", "dev": true, "requires": { "debuglog": "^1.0.1", @@ -78732,7 +81562,6 @@ }, "readdirp": { "version": "2.2.1", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "optional": true, "requires": { "graceful-fs": "^4.1.11", @@ -78742,7 +81571,6 @@ }, "realpath-native": { "version": "1.1.0", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", "dev": true, "requires": { "util.promisify": "^1.0.0" @@ -78750,14 +81578,12 @@ }, "rechoir": { "version": "0.6.2", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "requires": { "resolve": "^1.1.6" } }, "recompose": { "version": "0.23.5", - "integrity": "sha512-QFM1/k05FtmoFgZj6m5lw0PUMXKLU5/iOEicv1lEQJ7LFUrrxpaPe2U54P8lIdiPeVcTsSHu5t5eeKSHCRXK+Q==", "requires": { "change-emitter": "^0.1.2", "fbjs": "^0.8.1", @@ -78766,36 +81592,20 @@ }, "dependencies": { "hoist-non-react-statics": { - "version": "1.2.0", - "integrity": "sha512-r8huvKK+m+VraiRipdZYc+U4XW43j6OFG/oIafe7GfDbRpCduRoX9JI/DRxqgtBSCeL+et6N6ibZoedHS2NyOQ==" + "version": "1.2.0" } } }, "redent": { "version": "3.0.0", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, "requires": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, - "redeyed": { - "version": "0.4.4", - "integrity": "sha512-pnk1vsaNLu1UAAClKsImKz9HjBvg9i8cbRqTRzJbiCjGF0fZSMqpdcA5W3juO3c4etFvTrabECkq9wjC45ZyxA==", - "requires": { - "esprima": "~1.0.4" - }, - "dependencies": { - "esprima": { - "version": "1.0.4", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==" - } - } - }, "reduce-css-calc": { "version": "1.3.0", - "integrity": "sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==", "requires": { "balanced-match": "^0.4.2", "math-expression-evaluator": "^1.2.14", @@ -78803,58 +81613,48 @@ }, "dependencies": { "balanced-match": { - "version": "0.4.2", - "integrity": "sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg==" + "version": "0.4.2" } } }, "reduce-flatten": { - "version": "2.0.0", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==" + "version": "2.0.0" }, "reduce-function-call": { "version": "1.0.3", - "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", "requires": { "balanced-match": "^1.0.0" } }, "redux": { "version": "4.0.5", - "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", "requires": { "loose-envify": "^1.4.0", "symbol-observable": "^1.2.0" } }, "redux-localstorage": { - "version": "0.4.1", - "integrity": "sha512-dUha0YoH+BSZ2q15pakB+JWeqiuXUf3Ir4rObOpNrZ96HEdciGAjkL10k3KGdLI7qvQw/c096asw/SQ6TPjU/A==" + "version": "0.4.1" }, "redux-mock-store": { "version": "1.5.4", - "integrity": "sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA==", "dev": true, "requires": { "lodash.isplainobject": "^4.0.6" } }, "redux-thunk": { - "version": "2.3.0", - "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" + "version": "2.3.0" }, "redux-undo": { - "version": "1.0.0-beta9-9-7", - "integrity": "sha512-TTo1X0rkWJaHB4NOnMWXuuyZ3XOHzqplAPUtKFfuAxsSnrLN+ft+CsQy3vuT5+/n02DKWRpkj5hpxsLgmTPPBQ==" + "version": "1.0.0-beta9-9-7" }, "reflect.ownkeys": { "version": "0.2.0", - "integrity": "sha512-qOLsBKHCpSOFKK1NUOCGC5VyeufB6lEsFe92AL2bhIJsacZS1qdoOZSbPk3MYKuT2cFlRDnulKXuuElIrMjGUg==", "dev": true }, "refractor": { "version": "3.6.0", - "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", "requires": { "hastscript": "^6.0.0", "parse-entities": "^2.0.0", @@ -78863,7 +81663,6 @@ "dependencies": { "parse-entities": { "version": "2.0.0", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", "requires": { "character-entities": "^1.0.0", "character-entities-legacy": "^1.0.0", @@ -78876,30 +81675,25 @@ } }, "regenerate": { - "version": "1.4.2", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + "version": "1.4.2" }, "regenerate-unicode-properties": { - "version": "9.0.0", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", + "version": "10.0.1", "requires": { "regenerate": "^1.4.2" } }, "regenerator-runtime": { - "version": "0.13.7", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.13.10" }, "regenerator-transform": { - "version": "0.14.5", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", "requires": { "@babel/runtime": "^7.8.4" } }, "regex-not": { "version": "1.0.2", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" @@ -78907,7 +81701,6 @@ "dependencies": { "extend-shallow": { "version": "3.0.2", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -78915,7 +81708,6 @@ }, "is-extendable": { "version": "1.0.1", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { "is-plain-object": "^2.0.4" } @@ -78923,50 +81715,44 @@ } }, "regexp.prototype.flags": { - "version": "1.3.0", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "version": "1.4.3", "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" + "functions-have-names": "^1.2.2" } }, "regexpp": { "version": "3.2.0", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "regexpu-core": { - "version": "4.8.0", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "version": "5.1.0", "requires": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" } }, "regjsgen": { - "version": "0.5.2", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + "version": "0.6.0" }, "regjsparser": { - "version": "0.7.0", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", + "version": "0.8.4", "requires": { "jsesc": "~0.5.0" }, "dependencies": { "jsesc": { - "version": "0.5.0", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + "version": "0.5.0" } } }, "rehype-raw": { "version": "6.1.1", - "integrity": "sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ==", "requires": { "@types/hast": "^2.0.0", "hast-util-raw": "^7.2.0", @@ -78974,16 +81760,13 @@ }, "dependencies": { "@types/parse5": { - "version": "6.0.3", - "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" + "version": "6.0.3" }, "comma-separated-tokens": { - "version": "2.0.3", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" + "version": "2.0.3" }, "hast-to-hyperscript": { "version": "10.0.1", - "integrity": "sha512-dhIVGoKCQVewFi+vz3Vt567E4ejMppS1haBRL6TEmeLeJVB1i/FJIIg/e6s1Bwn0g5qtYojHEKvyGA+OZuyifw==", "requires": { "@types/unist": "^2.0.0", "comma-separated-tokens": "^2.0.0", @@ -78996,7 +81779,6 @@ }, "hast-util-from-parse5": { "version": "7.1.0", - "integrity": "sha512-m8yhANIAccpU4K6+121KpPP55sSl9/samzQSQGpb0mTExcNh2WlvjtMwSWFhg6uqD4Rr6Nfa8N6TMypQM51rzQ==", "requires": { "@types/hast": "^2.0.0", "@types/parse5": "^6.0.0", @@ -79010,14 +81792,12 @@ }, "hast-util-parse-selector": { "version": "3.1.0", - "integrity": "sha512-AyjlI2pTAZEOeu7GeBPZhROx0RHBnydkQIXlhnFzDi0qfXTmGUWoCYZtomHbrdrheV4VFUlPcfJ6LMF5T6sQzg==", "requires": { "@types/hast": "^2.0.0" } }, "hast-util-raw": { "version": "7.2.2", - "integrity": "sha512-0x3BhhdlBcqRIKyc095lBSDvmQNMY3Eulj2PLsT5XCyKYrxssI5yr3P4Kv/PBo1s/DMkZy2voGkMXECnFCZRLQ==", "requires": { "@types/hast": "^2.0.0", "@types/parse5": "^6.0.0", @@ -79034,7 +81814,6 @@ }, "hast-util-to-parse5": { "version": "7.0.0", - "integrity": "sha512-YHiS6aTaZ3N0Q3nxaY/Tj98D6kM8QX5Q8xqgg8G45zR7PvWnPGPP0vcKCgb/moIydEJ/QWczVrX0JODCVeoV7A==", "requires": { "@types/hast": "^2.0.0", "@types/parse5": "^6.0.0", @@ -79046,7 +81825,6 @@ }, "hastscript": { "version": "7.1.0", - "integrity": "sha512-uBjaTTLN0MkCZxY/R2fWUOcu7FRtUVzKRO5P/RAfgsu3yFiMB1JWCO4AjeVkgHxAira1f2UecHK5WfS9QurlWA==", "requires": { "@types/hast": "^2.0.0", "comma-separated-tokens": "^2.0.0", @@ -79056,41 +81834,33 @@ } }, "html-void-elements": { - "version": "2.0.1", - "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==" + "version": "2.0.1" }, "parse5": { - "version": "6.0.1", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + "version": "6.0.1" }, "property-information": { - "version": "6.2.0", - "integrity": "sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==" + "version": "6.2.0" }, "space-separated-tokens": { - "version": "2.0.2", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" + "version": "2.0.2" }, "unist-util-position": { "version": "4.0.3", - "integrity": "sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==", "requires": { "@types/unist": "^2.0.0" } }, "web-namespaces": { - "version": "2.0.1", - "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==" + "version": "2.0.1" }, "zwitch": { - "version": "2.0.4", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" + "version": "2.0.4" } } }, "rehype-sanitize": { "version": "5.0.1", - "integrity": "sha512-da/jIOjq8eYt/1r9GN6GwxIR3gde7OZ+WV8pheu1tL8K0D9KxM2AyMh+UEfke+FfdM3PvGHeYJU0Td5OWa7L5A==", "requires": { "@types/hast": "^2.0.0", "hast-util-sanitize": "^4.0.0", @@ -79098,12 +81868,10 @@ } }, "relateurl": { - "version": "0.2.7", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" + "version": "0.2.7" }, "remark-external-links": { "version": "8.0.0", - "integrity": "sha512-5vPSX0kHoSsqtdftSHhIYofVINC8qmp0nctkeU9YoJwV3YfiBRiI6cbFRJ0oI/1F9xS+bopXG0m2KS8VFscuKA==", "dev": true, "requires": { "extend": "^3.0.0", @@ -79115,12 +81883,10 @@ "dependencies": { "unist-util-is": { "version": "4.1.0", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", "dev": true }, "unist-util-visit": { "version": "2.0.3", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", "dev": true, "requires": { "@types/unist": "^2.0.0", @@ -79130,7 +81896,6 @@ }, "unist-util-visit-parents": { "version": "3.1.1", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", "dev": true, "requires": { "@types/unist": "^2.0.0", @@ -79140,12 +81905,10 @@ } }, "remark-footnotes": { - "version": "2.0.0", - "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==" + "version": "2.0.0" }, "remark-mdx": { "version": "1.6.22", - "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", "requires": { "@babel/core": "7.12.9", "@babel/helper-plugin-utils": "7.10.4", @@ -79159,7 +81922,6 @@ "dependencies": { "@babel/core": { "version": "7.12.9", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", "requires": { "@babel/code-frame": "^7.10.4", "@babel/generator": "^7.12.5", @@ -79180,42 +81942,34 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.10.4", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + "version": "7.10.4" }, "@babel/plugin-syntax-jsx": { "version": "7.12.1", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", "requires": { "@babel/helper-plugin-utils": "^7.10.4" } }, "debug": { "version": "4.3.4", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } }, "is-buffer": { - "version": "2.0.5", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + "version": "2.0.5" }, "is-plain-obj": { - "version": "2.1.0", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + "version": "2.1.0" }, "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3" }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" }, "parse-entities": { "version": "2.0.0", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", "requires": { "character-entities": "^1.0.0", "character-entities-legacy": "^1.0.0", @@ -79227,7 +81981,6 @@ }, "remark-parse": { "version": "8.0.3", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", "requires": { "ccount": "^1.0.0", "collapse-white-space": "^1.0.2", @@ -79249,7 +82002,6 @@ }, "unified": { "version": "9.2.0", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", "requires": { "bail": "^1.0.0", "extend": "^3.0.0", @@ -79260,26 +82012,22 @@ } }, "unist-util-is": { - "version": "4.1.0", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" + "version": "4.1.0" }, "unist-util-remove-position": { "version": "2.0.1", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", "requires": { "unist-util-visit": "^2.0.0" } }, "unist-util-stringify-position": { "version": "2.0.3", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", "requires": { "@types/unist": "^2.0.2" } }, "unist-util-visit": { "version": "2.0.3", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0", @@ -79288,7 +82036,6 @@ }, "unist-util-visit-parents": { "version": "3.1.1", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0" @@ -79296,7 +82043,6 @@ }, "vfile": { "version": "4.2.1", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", "requires": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", @@ -79305,12 +82051,10 @@ } }, "vfile-location": { - "version": "3.2.0", - "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==" + "version": "3.2.0" }, "vfile-message": { "version": "2.0.4", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", "requires": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^2.0.0" @@ -79320,7 +82064,6 @@ }, "remark-parse": { "version": "10.0.1", - "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", "requires": { "@types/mdast": "^3.0.0", "mdast-util-from-markdown": "^1.0.0", @@ -79329,7 +82072,6 @@ }, "remark-rehype": { "version": "10.1.0", - "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", "requires": { "@types/hast": "^2.0.0", "@types/mdast": "^3.0.0", @@ -79339,7 +82081,6 @@ "dependencies": { "mdast-util-definitions": { "version": "5.1.1", - "integrity": "sha512-rQ+Gv7mHttxHOBx2dkF4HWTg+EE+UR78ptQWDylzPKaQuVGdG4HIoY3SrS/pCp80nZ04greFvXbVFHT+uf0JVQ==", "requires": { "@types/mdast": "^3.0.0", "@types/unist": "^2.0.0", @@ -79348,7 +82089,6 @@ }, "mdast-util-to-hast": { "version": "12.2.4", - "integrity": "sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==", "requires": { "@types/hast": "^2.0.0", "@types/mdast": "^3.0.0", @@ -79363,18 +82103,15 @@ }, "unist-builder": { "version": "3.0.0", - "integrity": "sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==", "requires": { "@types/unist": "^2.0.0" } }, "unist-util-generated": { - "version": "2.0.0", - "integrity": "sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw==" + "version": "2.0.0" }, "unist-util-position": { "version": "4.0.3", - "integrity": "sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==", "requires": { "@types/unist": "^2.0.0" } @@ -79383,7 +82120,6 @@ }, "remark-slug": { "version": "6.1.0", - "integrity": "sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ==", "dev": true, "requires": { "github-slugger": "^1.0.0", @@ -79393,12 +82129,10 @@ "dependencies": { "unist-util-is": { "version": "4.1.0", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", "dev": true }, "unist-util-visit": { "version": "2.0.3", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", "dev": true, "requires": { "@types/unist": "^2.0.0", @@ -79408,7 +82142,6 @@ }, "unist-util-visit-parents": { "version": "3.1.1", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", "dev": true, "requires": { "@types/unist": "^2.0.0", @@ -79419,22 +82152,19 @@ }, "remark-squeeze-paragraphs": { "version": "4.0.0", - "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", "requires": { "mdast-squeeze-paragraphs": "^4.0.0" } }, "remove-accents": { - "version": "0.4.2", - "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==" + "version": "0.4.2" }, "remove-trailing-separator": { "version": "1.1.0", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==" + "devOptional": true }, "renderkid": { "version": "2.0.7", - "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", "requires": { "css-select": "^4.1.3", "dom-converter": "^0.2.0", @@ -79445,7 +82175,6 @@ "dependencies": { "css-select": { "version": "4.1.3", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", "requires": { "boolbase": "^1.0.0", "css-what": "^5.0.0", @@ -79455,12 +82184,10 @@ } }, "css-what": { - "version": "5.0.1", - "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==" + "version": "5.1.0" }, "dom-serializer": { "version": "1.3.2", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -79468,19 +82195,16 @@ } }, "domelementtype": { - "version": "2.2.0", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + "version": "2.2.0" }, "domhandler": { "version": "4.2.2", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", "requires": { "domelementtype": "^2.2.0" } }, "domutils": { "version": "2.8.0", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "requires": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -79488,12 +82212,10 @@ } }, "entities": { - "version": "2.2.0", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + "version": "2.2.0" }, "htmlparser2": { "version": "6.1.0", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", @@ -79503,7 +82225,6 @@ }, "nth-check": { "version": "2.0.0", - "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", "requires": { "boolbase": "^1.0.0" } @@ -79511,20 +82232,13 @@ } }, "repeat-element": { - "version": "1.1.3", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + "version": "1.1.3" }, "repeat-string": { - "version": "1.6.1", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" - }, - "replace-ext": { - "version": "1.0.0", - "integrity": "sha512-vuNYXC7gG7IeVNBC1xUllqCcZKRbJoSPOBhnTEcAIiKCsbuef6zO3F0Rve3isPMMoNoQRWjQwbAgAjHUHniyEA==" + "version": "1.6.1" }, "request": { "version": "2.88.2", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -79551,7 +82265,6 @@ }, "request-promise-core": { "version": "1.1.3", - "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", "dev": true, "requires": { "lodash": "^4.17.15" @@ -79559,7 +82272,6 @@ }, "request-promise-native": { "version": "1.0.8", - "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", "dev": true, "requires": { "request-promise-core": "1.1.3", @@ -79568,43 +82280,34 @@ } }, "require-directory": { - "version": "2.1.1", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + "version": "2.1.1" }, "require-from-string": { "version": "2.0.2", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, "require-main-filename": { - "version": "2.0.0", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + "version": "2.0.0" }, "require-package-name": { - "version": "2.0.1", - "integrity": "sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==" + "version": "2.0.1" }, "requireindex": { "version": "1.2.0", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", "dev": true }, "requires-port": { "version": "1.0.0", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, "reselect": { - "version": "4.0.0", - "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" + "version": "4.0.0" }, "resize-observer-polyfill": { - "version": "1.5.1", - "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + "version": "1.5.1" }, "resolve": { "version": "1.20.0", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "requires": { "is-core-module": "^2.2.0", "path-parse": "^1.0.6" @@ -79612,7 +82315,6 @@ }, "resolve-cwd": { "version": "3.0.0", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "requires": { "resolve-from": "^5.0.0" @@ -79620,74 +82322,61 @@ "dependencies": { "resolve-from": { "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true } } }, "resolve-from": { - "version": "4.0.0", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "version": "4.0.0" }, "resolve-pathname": { - "version": "3.0.0", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + "version": "3.0.0" }, "resolve-protobuf-schema": { "version": "2.1.0", - "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", "requires": { "protocol-buffers-schema": "^3.3.1" } }, "resolve-url": { - "version": "0.2.1", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==" + "version": "0.2.1" }, "restore-cursor": { "version": "3.1.0", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "devOptional": true, + "dev": true, "requires": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "ret": { - "version": "0.1.15", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + "version": "0.1.15" }, "retry": { "version": "0.13.1", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true }, "reusify": { - "version": "1.0.4", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + "version": "1.0.4" }, "rimraf": { "version": "3.0.2", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "requires": { "glob": "^7.1.3" } }, "ripemd160": { "version": "2.0.2", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, "rison": { - "version": "0.1.1", - "integrity": "sha512-8C+/PKKTaAYE2quDtOUwny/eQpNn9YGby7T80wntbVWSGvw0aUT9M0YgLdLkUgIQzQwaB1ZTr80rwLVKyohHig==" + "version": "0.1.1" }, "rst-selector-parser": { "version": "2.2.3", - "integrity": "sha512-nDG1rZeP6oFTLN6yNDV/uiAvs1+FS/KlrEwh7+y7dpuApDBy6bI2HTBcc0/V8lv9OTqfyD34eF7au2pm8aBbhA==", "dev": true, "requires": { "lodash.flattendeep": "^4.4.0", @@ -79696,61 +82385,58 @@ }, "rsvp": { "version": "4.8.5", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", "dev": true }, "run-async": { - "version": "2.4.1", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + "version": "2.4.1" }, "run-parallel": { - "version": "1.1.9", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" + "version": "1.1.9" }, "run-queue": { "version": "1.0.3", - "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==", "requires": { "aproba": "^1.1.1" } }, "rw": { - "version": "1.3.3", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + "version": "1.3.3" }, "rxjs": { "version": "6.6.7", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "devOptional": true, + "dev": true, "requires": { "tslib": "^1.9.0" } }, "sade": { "version": "1.8.1", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "requires": { "mri": "^1.1.0" } }, "safe-buffer": { - "version": "5.1.2", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.1.2" }, "safe-regex": { "version": "1.1.0", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "requires": { "ret": "~0.1.10" } }, + "safe-regex-test": { + "version": "1.0.0", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "safer-buffer": { - "version": "2.1.2", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "version": "2.1.2" }, "sane": { "version": "4.1.0", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", "dev": true, "requires": { "@cnakazawa/watch": "^1.0.3", @@ -79766,12 +82452,10 @@ }, "sax": { "version": "1.2.4", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, "saxes": { "version": "5.0.1", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", "dev": true, "requires": { "xmlchars": "^2.2.0" @@ -79779,7 +82463,6 @@ }, "scheduler": { "version": "0.15.0", - "integrity": "sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg==", "dev": true, "requires": { "loose-envify": "^1.1.0", @@ -79788,7 +82471,6 @@ }, "schema-utils": { "version": "3.1.1", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", "requires": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -79797,35 +82479,29 @@ }, "scroll-into-view-if-needed": { "version": "2.2.28", - "integrity": "sha512-8LuxJSuFVc92+0AdNv4QOxRL4Abeo1DgLnGNkn1XlaujPH/3cCFz3QI60r2VNu4obJJROzgnIUw5TKQkZvZI1w==", "requires": { "compute-scroll-into-view": "^1.0.17" } }, "seedrandom": { - "version": "3.0.5", - "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + "version": "3.0.5" }, "select-hose": { "version": "2.0.0", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "dev": true }, "selfsigned": { - "version": "1.10.11", - "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", + "version": "2.0.1", "dev": true, "requires": { - "node-forge": "^0.10.0" + "node-forge": "^1" } }, "semver": { - "version": "5.6.0", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" + "version": "5.7.1" }, "send": { - "version": "0.17.1", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -79834,57 +82510,46 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" }, "dependencies": { "http-errors": { - "version": "1.7.3", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "version": "1.8.1", "requires": { "depd": "~1.1.2", "inherits": "2.0.4", - "setprototypeof": "1.1.1", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" } }, "inherits": { - "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "version": "2.0.4" }, "ms": { - "version": "2.1.1", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3" }, "setprototypeof": { - "version": "1.1.1", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "statuses": { - "version": "1.5.0", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + "version": "1.2.0" } } }, "serialize-javascript": { "version": "4.0.0", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "requires": { "randombytes": "^2.1.0" } }, "serialize-query-params": { - "version": "1.2.4", - "integrity": "sha512-m4hGkOY5y+ksPDSEkw12cNxt3HRUJv5G6oF9/4yq+GCw4LznudxC73qnz++VTHqXa0j1x1/iaBIpoiMBxr6w2w==" + "version": "1.2.4" }, "serve-favicon": { "version": "2.5.0", - "integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==", "requires": { "etag": "~1.8.1", "fresh": "0.5.2", @@ -79894,18 +82559,15 @@ }, "dependencies": { "ms": { - "version": "2.1.1", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.1" }, "safe-buffer": { - "version": "5.1.1", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "version": "5.1.1" } } }, "serve-index": { "version": "1.9.1", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, "requires": { "accepts": "~1.3.4", @@ -79918,36 +82580,19 @@ } }, "serve-static": { - "version": "1.14.1", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" - }, - "dependencies": { - "parseurl": { - "version": "1.3.3", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - } + "send": "0.17.2" } }, "set-blocking": { - "version": "2.0.0", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "set-getter": { - "version": "0.1.1", - "integrity": "sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==", - "optional": true, - "requires": { - "to-object-path": "^0.3.0" - } + "version": "2.0.0" }, "set-value": { "version": "2.0.1", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -79956,17 +82601,14 @@ } }, "setimmediate": { - "version": "1.0.5", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + "version": "1.0.5" }, "setprototypeof": { "version": "1.1.0", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true }, "sha.js": { "version": "2.4.11", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -79974,28 +82616,23 @@ }, "shallow-clone": { "version": "3.0.1", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "requires": { "kind-of": "^6.0.2" }, "dependencies": { "kind-of": { - "version": "6.0.3", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "version": "6.0.3" } } }, "shallow-copy": { - "version": "0.0.1", - "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==" + "version": "0.0.1" }, "shallowequal": { - "version": "1.1.0", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + "version": "1.1.0" }, "shapefile": { "version": "0.3.1", - "integrity": "sha512-BZoPvnq4ULce0pyKiZUU4D8CdPl0Z1fpE73AeCkwyMbD2hpUeVA0s7jIE/wX8uWNruVeJV6e+rznPHBwuH5J6g==", "requires": { "d3-queue": "1", "iconv-lite": "0.2", @@ -80003,44 +82640,26 @@ }, "dependencies": { "d3-queue": { - "version": "1.2.3", - "integrity": "sha512-m6KtxX4V5pmVf1PqhH4SkQVMshSJfyCLM2vf2oFPi9FWFVT3+rtbCGerk766b/JXymHQDU3oqXHaZoiQ/e8yUQ==" + "version": "1.2.3" }, "iconv-lite": { - "version": "0.2.11", - "integrity": "sha512-KhmFWgaQZY83Cbhi+ADInoUQ8Etn6BG5fikM9syeOjQltvR45h7cRKJ/9uvQEuD61I3Uju77yYce0/LhKVClQw==" - } - } - }, - "sharkdown": { - "version": "0.1.1", - "integrity": "sha512-exwooSpmo5s45lrexgz6Q0rFQM574wYIX3iDZ7RLLqOb7IAoQZu9nxlZODU972g19sR69OIpKP2cpHTzU+PHIg==", - "requires": { - "cardinal": "~0.4.2", - "minimist": "0.0.5", - "split": "~0.2.10" - }, - "dependencies": { - "minimist": { - "version": "0.0.5", - "integrity": "sha512-rSJ0cdmCj3qmKdObcnMcWgPVOyaOWlazLhZAJW0s6G6lx1ZEuFkraWmEH5LTvX90btkfHPclQBjvjU7A/kYRFg==" + "version": "0.2.11" } } }, "shebang-command": { "version": "1.2.0", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, "requires": { "shebang-regex": "^1.0.0" } }, "shebang-regex": { "version": "1.0.0", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" + "dev": true }, "shelljs": { "version": "0.8.5", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", "requires": { "glob": "^7.0.0", "interpret": "^1.0.0", @@ -80048,27 +82667,23 @@ }, "dependencies": { "interpret": { - "version": "1.4.0", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + "version": "1.4.0" } } }, "shellwords": { "version": "0.1.1", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true, "optional": true }, "shortid": { "version": "2.2.14", - "integrity": "sha512-4UnZgr9gDdA1kaKj/38IiudfC3KHKhDc1zi/HSxd9FQDR0VLwH3/y79tZJLsVYPsJgIjeHjqIWaWVRJUj9qZOQ==", "requires": { "nanoid": "^2.0.0" } }, "side-channel": { "version": "1.0.4", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -80076,22 +82691,29 @@ }, "dependencies": { "object-inspect": { - "version": "1.11.0", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + "version": "1.11.0" } } }, "sigmund": { - "version": "1.0.1", - "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==" + "version": "1.0.1" }, "signal-exit": { - "version": "3.0.3", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + "version": "3.0.7" + }, + "simple-swizzle": { + "version": "0.2.2", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2" + } + } }, "sinon": { "version": "9.0.2", - "integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.2", @@ -80105,7 +82727,6 @@ }, "sirv": { "version": "1.0.17", - "integrity": "sha512-qx9go5yraB7ekT7bCMqUHJ5jEaOC/GXBxUWv+jeWnb7WzHUFdcQPGWk7YmAwFBaQBrogpuSqd/azbC2lZRqqmw==", "dev": true, "requires": { "@polka/url": "^1.0.0-next.20", @@ -80115,22 +82736,18 @@ "dependencies": { "mime": { "version": "2.5.2", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", "dev": true } } }, "sisteransi": { - "version": "1.0.5", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + "version": "1.0.5" }, "slash": { - "version": "2.0.0", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + "version": "2.0.0" }, "slice-ansi": { "version": "4.0.0", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { "ansi-styles": "^4.0.0", @@ -80140,24 +82757,16 @@ "dependencies": { "is-fullwidth-code-point": { "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true } } }, - "slide": { - "version": "1.1.6", - "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", - "dev": true - }, "smart-buffer": { "version": "4.2.0", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true }, "snapdragon": { "version": "0.8.2", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "requires": { "base": "^0.11.1", "debug": "^2.2.0", @@ -80171,7 +82780,6 @@ "dependencies": { "define-property": { "version": "0.2.5", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -80180,7 +82788,6 @@ }, "snapdragon-node": { "version": "2.1.1", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "requires": { "define-property": "^1.0.0", "isobject": "^3.0.0", @@ -80189,28 +82796,24 @@ "dependencies": { "define-property": { "version": "1.0.0", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "requires": { "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { "version": "1.0.0", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -80218,21 +82821,18 @@ } }, "kind-of": { - "version": "6.0.2", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "version": "6.0.2" } } }, "snapdragon-util": { "version": "3.0.1", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "requires": { "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { "version": "3.2.2", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -80240,37 +82840,45 @@ } }, "sockjs": { - "version": "0.3.21", - "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", + "version": "0.3.24", "dev": true, "requires": { "faye-websocket": "^0.11.3", - "uuid": "^3.4.0", + "uuid": "^8.3.2", "websocket-driver": "^0.7.4" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "dev": true + } } }, "socks": { - "version": "2.6.1", - "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==", + "version": "2.7.1", "dev": true, "requires": { - "ip": "^1.1.5", - "smart-buffer": "^4.1.0" + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "dependencies": { + "ip": { + "version": "2.0.0", + "dev": true + } } }, "socks-proxy-agent": { - "version": "5.0.1", - "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "version": "7.0.0", "dev": true, "requires": { "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" + "debug": "^4.3.3", + "socks": "^2.6.2" }, "dependencies": { "debug": { - "version": "4.3.3", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", "dev": true, "requires": { "ms": "2.1.2" @@ -80278,34 +82886,27 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "sort-keys": { "version": "4.2.0", - "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", - "dev": true, "requires": { "is-plain-obj": "^2.0.0" }, "dependencies": { "is-plain-obj": { - "version": "2.1.0", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true + "version": "2.1.0" } } }, "sort-object-keys": { "version": "1.1.3", - "integrity": "sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==", "dev": true }, "sort-package-json": { "version": "1.53.1", - "integrity": "sha512-ltLORrQuuPMpy23YkWCA8fO7zBOxM4P1j9LcGxci4K2Fk8jmSyCA/ATU6CFyy8qR2HQRx4RBYWzoi78FU/Anuw==", "dev": true, "requires": { "detect-indent": "^6.0.0", @@ -80318,7 +82919,6 @@ "dependencies": { "globby": { "version": "10.0.0", - "integrity": "sha512-3LifW9M4joGZasyYPz2A1U74zbC/45fvpXUvO/9KbSa+VV0aGZarWkfdgKyR9sExNP0t0x0ss/UMJpNpcaTspw==", "dev": true, "requires": { "@types/glob": "^7.1.1", @@ -80333,37 +82933,30 @@ }, "ignore": { "version": "5.1.9", - "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", "dev": true }, "is-plain-obj": { "version": "2.1.0", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, "slash": { "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true } } }, "source-list-map": { - "version": "2.0.1", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + "version": "2.0.1" }, "source-map": { - "version": "0.5.7", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + "version": "0.5.7" }, "source-map-js": { "version": "0.6.2", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", "dev": true }, "source-map-resolve": { "version": "0.5.2", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "requires": { "atob": "^2.1.1", "decode-uri-component": "^0.2.0", @@ -80374,56 +82967,47 @@ }, "source-map-support": { "version": "0.5.20", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" }, "dependencies": { "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } }, "source-map-url": { - "version": "0.4.0", - "integrity": "sha512-liJwHPI9x9d9w5WSIjM58MqGmmb7XzNqwdUA3kSBQ4lmDngexlKwawGzK3J1mKXi6+sysoMDlpVyZh9sv5vRfw==" + "version": "0.4.0" }, "space-separated-tokens": { "version": "1.1.2", - "integrity": "sha512-G3jprCEw+xFEs0ORweLmblJ3XLymGGr6hxZYTYZjIlvDti9vOBUjRQa1Rzjt012aRrocKstHwdNi+F7HguPsEA==", "requires": { "trim": "0.0.1" } }, "spdx-correct": { "version": "3.1.0", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { - "version": "2.2.0", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==" + "version": "2.2.0" }, "spdx-expression-parse": { "version": "3.0.0", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { - "version": "3.0.2", - "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==" + "version": "3.0.2" }, "spdy": { "version": "4.0.2", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, "requires": { "debug": "^4.1.0", @@ -80435,7 +83019,6 @@ "dependencies": { "debug": { "version": "4.1.1", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" @@ -80443,14 +83026,12 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "spdy-transport": { "version": "3.0.0", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, "requires": { "debug": "^4.1.0", @@ -80463,7 +83044,6 @@ "dependencies": { "debug": { "version": "4.1.1", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" @@ -80471,12 +83051,10 @@ }, "ms": { "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -80488,12 +83066,10 @@ }, "specificity": { "version": "0.4.1", - "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==", "dev": true }, "speed-measure-webpack-plugin": { "version": "1.5.0", - "integrity": "sha512-Re0wX5CtM6gW7bZA64ONOfEPEhwbiSF/vz6e2GvadjuaPrQcHTQdRGsD8+BE7iUOysXH8tIenkPCQBEcspXsNg==", "dev": true, "requires": { "chalk": "^4.1.0" @@ -80501,30 +83077,26 @@ }, "speedometer": { "version": "1.0.0", - "integrity": "sha512-lgxErLl/7A5+vgIIXsh9MbeukOaCb2axgQ+bKCdIE+ibNT4XNYGNCR1qFEGq6F+YDASXK3Fh/c5FgtZchFolxw==", "dev": true }, "split": { - "version": "0.2.10", - "integrity": "sha512-e0pKq+UUH2Xq/sXbYpZBZc3BawsfDZ7dgv+JtRTUPNcvF5CMR4Y9cvJqkMY0MoxWzTHvZuz1beg6pNEKlszPiQ==", + "version": "1.0.1", + "dev": true, "requires": { "through": "2" } }, "split-on-first": { - "version": "1.1.0", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" + "version": "1.1.0" }, "split-string": { "version": "3.1.0", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "requires": { "extend-shallow": "^3.0.0" }, "dependencies": { "extend-shallow": { "version": "3.0.2", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -80532,7 +83104,6 @@ }, "is-extendable": { "version": "1.0.1", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { "is-plain-object": "^2.0.4" } @@ -80541,7 +83112,6 @@ }, "split2": { "version": "3.2.2", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", "dev": true, "requires": { "readable-stream": "^3.0.0" @@ -80549,7 +83119,6 @@ "dependencies": { "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -80560,12 +83129,10 @@ } }, "sprintf-js": { - "version": "1.0.3", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + "version": "1.0.3" }, "sshpk": { "version": "1.15.2", - "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -80581,23 +83148,15 @@ }, "ssri": { "version": "6.0.2", - "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", "requires": { "figgy-pudding": "^3.5.1" } }, "stable": { - "version": "0.1.8", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" - }, - "stack-trace": { - "version": "0.0.10", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "dev": true + "version": "0.1.8" }, "stack-utils": { "version": "2.0.3", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", "dev": true, "requires": { "escape-string-regexp": "^2.0.0" @@ -80605,29 +83164,24 @@ "dependencies": { "escape-string-regexp": { "version": "2.0.0", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true } } }, "stackframe": { - "version": "1.2.1", - "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==" + "version": "1.2.1" }, "state-toggle": { - "version": "1.0.3", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==" + "version": "1.0.3" }, "static-eval": { "version": "2.1.0", - "integrity": "sha512-agtxZ/kWSsCkI5E4QifRwsaPs0P0JmZV6dkLz6ILYfFYQGn+5plctanRN+IC8dJRiFkyXHrwEE3W9Wmx67uDbw==", "requires": { "escodegen": "^1.11.1" }, "dependencies": { "escodegen": { "version": "1.14.3", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", "requires": { "esprima": "^4.0.1", "estraverse": "^4.2.0", @@ -80637,19 +83191,16 @@ } }, "esprima": { - "version": "4.0.1", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "version": "4.0.1" }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "optional": true } } }, "static-extend": { "version": "0.1.2", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -80657,7 +83208,6 @@ "dependencies": { "define-property": { "version": "0.2.5", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -80666,7 +83216,6 @@ }, "static-module": { "version": "2.2.5", - "integrity": "sha512-D8vv82E/Kpmz3TXHKG8PPsCPg+RAX6cbCOyvjM6x04qZtQ47EtJFVwRsdov3n5d6/6ynrOY9XB4JkaZwB2xoRQ==", "requires": { "concat-stream": "~1.6.0", "convert-source-map": "^1.5.1", @@ -80685,22 +83234,17 @@ } }, "statuses": { - "version": "1.4.0", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true + "version": "1.5.0" }, "stealthy-require": { "version": "1.1.1", - "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", "dev": true }, "store2": { - "version": "2.12.0", - "integrity": "sha512-7t+/wpKLanLzSnQPX8WAcuLCCeuSHoWdQuh9SB3xD0kNOM38DNf+0Oa+wmvxmYueRzkmh6IcdKFtvTa+ecgPDw==" + "version": "2.12.0" }, "storybook-addon-jsx": { "version": "7.3.14", - "integrity": "sha512-ierjcn0nxjjOuNcnLkorXQnfXlYmyQxFXvmWV88T9V8VAnsWd4yclTtSOV/gPtB83FefmyO/8dm1qQBG0f+2pA==", "requires": { "copy-to-clipboard": "^3.0.8", "js-beautify": "^1.8.8", @@ -80710,7 +83254,6 @@ }, "storybook-addon-paddings": { "version": "4.3.0", - "integrity": "sha512-AgIhxVBMbBInjxwBOb4MhbMjE61HOB9aS63lF1Ycd+wA6u1BBkVlMUGrwLeT+yZNf/Fmz1lxJ6gvKdaB5qHw1A==", "dev": true, "requires": { "@storybook/addons": "^6.2.0", @@ -80722,12 +83265,10 @@ } }, "storybook-pretty-props": { - "version": "1.2.1", - "integrity": "sha512-3dUtu0UbBA6idA3Qo0i+CYGGz8GiqlXzhgCJdT065jnuJ3y9intKxZpv05ZbnQXCPnsPVSDos+hgOZ444hf6xA==" + "version": "1.2.1" }, "stream-browserify": { "version": "2.0.2", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "requires": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" @@ -80735,7 +83276,6 @@ }, "stream-each": { "version": "1.2.3", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", "requires": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" @@ -80743,7 +83283,6 @@ }, "stream-http": { "version": "2.8.3", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "requires": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.1", @@ -80753,36 +83292,29 @@ } }, "stream-shift": { - "version": "1.0.1", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + "version": "1.0.1" }, "strict-uri-encode": { - "version": "2.0.0", - "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==" + "version": "2.0.0" }, "string_decoder": { "version": "1.1.1", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } }, "string-argv": { "version": "0.3.1", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", "dev": true }, "string-convert": { - "version": "0.2.1", - "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" + "version": "0.2.1" }, "string-hash": { - "version": "1.1.3", - "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==" + "version": "1.1.3" }, "string-length": { "version": "4.0.1", - "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", "dev": true, "requires": { "char-regex": "^1.0.2", @@ -80791,12 +83323,10 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, "strip-ansi": { "version": "6.0.0", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { "ansi-regex": "^5.0.0" @@ -80804,25 +83334,18 @@ } } }, - "string-template": { - "version": "0.2.1", - "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==" - }, "string-width": { "version": "2.1.1", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "integrity": "sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==" + "version": "3.0.0" }, "strip-ansi": { "version": "4.0.0", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "requires": { "ansi-regex": "^3.0.0" } @@ -80831,7 +83354,6 @@ }, "string.prototype.matchall": { "version": "4.0.2", - "integrity": "sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==", "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0", @@ -80843,7 +83365,6 @@ }, "string.prototype.padend": { "version": "3.1.3", - "integrity": "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -80852,7 +83373,6 @@ }, "string.prototype.padstart": { "version": "3.1.3", - "integrity": "sha512-NZydyOMtYxpTjGqp0VN5PYUF/tsU15yDMZnUdj16qRUIUiMJkHHSDElYyQFrMu+/WloTpA7MQSiADhBicDfaoA==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -80860,107 +83380,69 @@ } }, "string.prototype.trim": { - "version": "1.2.0", - "integrity": "sha512-9EIjYD/WdlvLpn987+ctkLf0FfvBefOCuiEr2henD8X+7jfwPnyvTdmW8OJhj5p+M0/96mBdynLWkxUr+rHlpg==", + "version": "1.2.7", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.13.0", - "function-bind": "^1.1.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" } }, "string.prototype.trimend": { - "version": "1.0.4", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.6", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" } }, "string.prototype.trimstart": { - "version": "1.0.4", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.6", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" } }, "strip-ansi": { "version": "3.0.1", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "requires": { "ansi-regex": "^2.0.0" } }, "strip-bom": { "version": "3.0.0", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true }, - "strip-bom-buf": { - "version": "1.0.0", - "integrity": "sha512-1sUIL1jck0T1mhOLP2c696BIznzT525Lkub+n4jjMHjhjhoAQA6Ye659DxdlZBr0aLDMQoTxKIpnlqxgtwjsuQ==", - "optional": true, - "requires": { - "is-utf8": "^0.2.1" - } - }, - "strip-bom-stream": { - "version": "2.0.0", - "integrity": "sha512-yH0+mD8oahBZWnY43vxs4pSinn8SMKAdml/EOGBewoe1Y0Eitd0h2Mg3ZRiXruUW6L4P+lvZiEgbh0NgUGia1w==", - "optional": true, - "requires": { - "first-chunk-stream": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "2.0.0", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", - "optional": true, - "requires": { - "is-utf8": "^0.2.0" - } - } - } - }, "strip-comments": { "version": "2.0.1", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", "dev": true }, "strip-eof": { "version": "1.0.0", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", "dev": true }, "strip-final-newline": { - "version": "2.0.0", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "devOptional": true + "version": "2.0.0" }, "strip-indent": { "version": "3.0.0", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "requires": { "min-indent": "^1.0.0" } }, "strip-json-comments": { "version": "3.1.1", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "strip-outer": { "version": "1.0.1", - "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", "requires": { "escape-string-regexp": "^1.0.2" } }, "strong-log-transformer": { "version": "2.1.0", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", "dev": true, "requires": { "duplexer": "^0.1.1", @@ -80970,49 +83452,41 @@ }, "style-loader": { "version": "3.2.1", - "integrity": "sha512-1k9ZosJCRFaRbY6hH49JFlRB0fVSbmnyq1iTPjNxUmGVjBNEmwrrHPenhlp+Lgo51BojHSf6pl2FcqYaN3PfVg==", "dev": true }, "style-to-object": { "version": "0.3.0", - "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", "requires": { "inline-style-parser": "0.1.1" } }, "stylis": { - "version": "4.0.9", - "integrity": "sha512-ci7pEFNVW3YJiWEzqPOMsAjY6kgraZ3ZgBfQ5HYbNtLJEsQ0G46ejWZpfSSCp/FaSiCSGGhzL9O2lN+2cB6ong==" + "version": "4.0.9" }, "supercluster": { "version": "4.1.1", - "integrity": "sha512-sF0FfUOPFp96DKzwWFLeQOEqqKu2PpcesxAFeFsknA/q7g7igVVn/p3NI2XHEghNSyDAqunKNKqAbqNO8+7NDQ==", "requires": { "kdbush": "^2.0.1" }, "dependencies": { "kdbush": { - "version": "2.0.1", - "integrity": "sha512-9KqSdmWCkBIisFIGclT0FRagKhI7IVbMyUjsxCFG0Ly1Dg6whlxJ7b9lrq8ifk3X/fGeJzok1R75LQfZTfA5zQ==" + "version": "2.0.1" } } }, "supports-color": { "version": "7.2.0", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { "has-flag": "^4.0.0" }, "dependencies": { "has-flag": { - "version": "4.0.0", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "version": "4.0.0" } } }, "supports-hyperlinks": { "version": "2.1.0", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -81021,19 +83495,16 @@ "dependencies": { "has-flag": { "version": "4.0.0", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true } } }, "svg-parser": { "version": "2.0.4", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", "dev": true }, "svgo": { "version": "1.3.2", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", "dev": true, "requires": { "chalk": "^2.4.1", @@ -81053,7 +83524,6 @@ "dependencies": { "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -81061,7 +83531,6 @@ }, "chalk": { "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -81071,7 +83540,6 @@ }, "css-select": { "version": "2.1.0", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", "dev": true, "requires": { "boolbase": "^1.0.0", @@ -81081,13 +83549,11 @@ } }, "css-what": { - "version": "3.2.1", - "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==", + "version": "3.4.2", "dev": true }, "domutils": { "version": "1.7.0", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", "dev": true, "requires": { "dom-serializer": "0", @@ -81096,7 +83562,6 @@ }, "supports-color": { "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -81105,17 +83570,14 @@ } }, "symbol-observable": { - "version": "1.2.0", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + "version": "1.2.0" }, "symbol-tree": { "version": "3.2.4", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, "symbol.prototype.description": { "version": "1.0.5", - "integrity": "sha512-x738iXRYsrAt9WBhRCVG5BtIC3B7CUkFwbHW2zOvGtwM33s7JjrCDyq8V0zgMYVb5ymsL8+qkzzpANH63CPQaQ==", "requires": { "call-bind": "^1.0.2", "get-symbol-description": "^1.0.0", @@ -81124,12 +83586,10 @@ } }, "synchronous-promise": { - "version": "2.0.15", - "integrity": "sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg==" + "version": "2.0.15" }, "table": { "version": "6.7.3", - "integrity": "sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw==", "dev": true, "requires": { "ajv": "^8.0.1", @@ -81141,7 +83601,6 @@ "dependencies": { "ajv": { "version": "8.8.0", - "integrity": "sha512-L+cJ/+pkdICMueKR6wIx3VP2fjIx3yAhuvadUv/osv9yFD7OVZy442xFF+Oeu3ZvmhBGQzoF6mTSt+LUWBmGQg==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -81152,22 +83611,18 @@ }, "ansi-regex": { "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "json-schema-traverse": { "version": "1.0.0", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", @@ -81177,7 +83632,6 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { "ansi-regex": "^5.0.1" @@ -81187,7 +83641,6 @@ }, "table-layout": { "version": "1.0.2", - "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", "requires": { "array-back": "^4.0.1", "deep-extend": "~0.6.0", @@ -81196,30 +83649,25 @@ }, "dependencies": { "array-back": { - "version": "4.0.2", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + "version": "4.0.2" }, "typical": { - "version": "5.2.0", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + "version": "5.2.0" } } }, "taketalk": { "version": "1.0.0", - "integrity": "sha512-kS7E53It6HA8S1FVFBWP7HDwgTiJtkmYk7TsowGlizzVrivR1Mf9mgjXHY1k7rOfozRVMZSfwjB3bevO4QEqpg==", "requires": { "get-stdin": "^4.0.1", "minimist": "^1.1.0" } }, "tapable": { - "version": "1.1.3", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + "version": "1.1.3" }, "tar": { "version": "6.1.11", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -81230,22 +83678,18 @@ }, "dependencies": { "chownr": { - "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + "version": "2.0.0" }, "mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + "version": "1.0.4" }, "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "4.0.0" } } }, "tar-fs": { "version": "2.0.0", - "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", "dev": true, "requires": { "chownr": "^1.1.1", @@ -81256,7 +83700,6 @@ }, "tar-stream": { "version": "2.2.0", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "requires": { "bl": "^4.0.3", @@ -81268,7 +83711,6 @@ "dependencies": { "readable-stream": { "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -81280,7 +83722,6 @@ }, "telejson": { "version": "5.3.3", - "integrity": "sha512-PjqkJZpzEggA9TBpVtJi1LVptP7tYtXB6rEubwlHap76AMjzvOdKX41CxyaW7ahhzDU1aftXnMCx5kAPDZTQBA==", "requires": { "@types/is-function": "^1.0.0", "global": "^4.4.0", @@ -81293,56 +83734,20 @@ }, "dependencies": { "isobject": { - "version": "4.0.0", - "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==" + "version": "4.0.0" } } }, "temp-dir": { "version": "1.0.0", - "integrity": "sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==", "dev": true }, - "temp-write": { - "version": "4.0.0", - "integrity": "sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "is-stream": "^2.0.0", - "make-dir": "^3.0.0", - "temp-dir": "^1.0.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "make-dir": { - "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "term-size": { "version": "2.2.1", - "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", "dev": true }, "terminal-link": { "version": "2.1.1", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", "dev": true, "requires": { "ansi-escapes": "^4.2.1", @@ -81350,8 +83755,7 @@ } }, "terser": { - "version": "4.6.3", - "integrity": "sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==", + "version": "4.8.1", "requires": { "commander": "^2.20.0", "source-map": "~0.6.1", @@ -81359,14 +83763,12 @@ }, "dependencies": { "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" } } }, "terser-webpack-plugin": { "version": "4.2.3", - "integrity": "sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==", "requires": { "cacache": "^15.0.5", "find-cache-dir": "^3.3.1", @@ -81381,7 +83783,6 @@ "dependencies": { "cacache": { "version": "15.3.0", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", "requires": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", @@ -81404,12 +83805,10 @@ } }, "chownr": { - "version": "2.0.0", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + "version": "2.0.0" }, "find-cache-dir": { "version": "3.3.2", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "requires": { "commondir": "^1.0.1", "make-dir": "^3.0.2", @@ -81418,7 +83817,6 @@ }, "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -81426,46 +83824,39 @@ }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { "p-locate": "^4.1.0" } }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "requires": { "yallist": "^4.0.0" } }, "make-dir": { "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "requires": { "semver": "^6.0.0" } }, "mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + "version": "1.0.4" }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "requires": { "yocto-queue": "^0.1.0" } }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "requires": { "p-limit": "^2.2.0" }, "dependencies": { "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } @@ -81473,87 +83864,58 @@ } }, "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "version": "2.2.0" }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" }, "pkg-dir": { "version": "4.2.0", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "requires": { "find-up": "^4.0.0" } }, "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.0" }, "serialize-javascript": { "version": "5.0.1", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", "requires": { "randombytes": "^2.1.0" } }, "source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.6.1" }, "ssri": { "version": "8.0.1", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", "requires": { "minipass": "^3.1.1" } }, "terser": { - "version": "5.13.1", - "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", + "version": "5.14.2", "requires": { + "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.8.0-beta.0", "source-map-support": "~0.5.20" - }, - "dependencies": { - "source-map": { - "version": "0.8.0-beta.0", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "requires": { - "whatwg-url": "^7.0.0" - } - } } }, "webpack-sources": { "version": "1.4.3", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" } }, - "whatwg-url": { - "version": "7.1.0", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "version": "4.0.0" } } }, "test-exclude": { "version": "6.0.0", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "requires": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -81561,26 +83923,21 @@ } }, "text-encoding-utf-8": { - "version": "1.0.2", - "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + "version": "1.0.2" }, "text-extensions": { "version": "1.9.0", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true }, "text-table": { - "version": "0.2.0", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + "version": "0.2.0" }, "textextensions": { "version": "5.14.0", - "integrity": "sha512-4cAYwNFNYlIAHBUo7p6zw8POUvWbZor+/R0Tanv+rIhsauEyV9QSrEXL40pI+GfTQxKX8k6Tyw6CmdSDSmASrg==", "dev": true }, "thread-loader": { "version": "3.0.4", - "integrity": "sha512-ByaL2TPb+m6yArpqQUZvP+5S1mZtXsEP7nWKKlAUTm7fCml8kB5s1uI3+eHRP2bk5mVYfRSBI7FFf+tWEyLZwA==", "dev": true, "requires": { "json-parse-better-errors": "^1.0.2", @@ -81591,16 +83948,11 @@ }, "dependencies": { "json5": { - "version": "2.2.0", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3", + "dev": true }, "loader-utils": { - "version": "2.0.0", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "version": "2.0.4", "dev": true, "requires": { "big.js": "^5.2.2", @@ -81612,20 +83964,17 @@ }, "throat": { "version": "5.0.0", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", "dev": true }, "throttle-debounce": { - "version": "3.0.1", - "integrity": "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==" + "version": "3.0.1" }, "through": { "version": "2.3.8", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + "dev": true }, "through2": { "version": "2.0.5", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" @@ -81633,44 +83982,32 @@ }, "thunky": { "version": "1.1.0", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, - "timed-out": { - "version": "4.0.1", - "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==" - }, "timers-browserify": { "version": "2.0.12", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", "requires": { "setimmediate": "^1.0.4" } }, "timsort": { "version": "0.3.0", - "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==", "dev": true }, "tiny-invariant": { - "version": "1.1.0", - "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + "version": "1.1.0" }, "tiny-warning": { - "version": "1.0.3", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + "version": "1.0.3" }, "tinycolor2": { - "version": "1.4.2", - "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==" + "version": "1.4.2" }, "tinyqueue": { - "version": "2.0.3", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" + "version": "2.0.3" }, "tmp": { "version": "0.2.1", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", "dev": true, "requires": { "rimraf": "^3.0.0" @@ -81678,7 +84015,6 @@ }, "tmp-promise": { "version": "3.0.2", - "integrity": "sha512-OyCLAKU1HzBjL6Ev3gxUeraJNlbNingmi8IrHHEsYH8LTmEuhvYfqvhn2F/je+mjf4N58UmZ96OMEy1JanSCpA==", "dev": true, "requires": { "tmp": "^0.2.0" @@ -81686,27 +84022,22 @@ }, "tmpl": { "version": "1.0.5", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, "to-arraybuffer": { - "version": "1.0.1", - "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==" + "version": "1.0.1" }, "to-fast-properties": { - "version": "2.0.0", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + "version": "2.0.0" }, "to-object-path": { "version": "0.3.0", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -81715,7 +84046,6 @@ }, "to-regex": { "version": "3.0.2", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "requires": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", @@ -81725,7 +84055,6 @@ "dependencies": { "extend-shallow": { "version": "3.0.2", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -81733,7 +84062,6 @@ }, "is-extendable": { "version": "1.0.1", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { "is-plain-object": "^2.0.4" } @@ -81742,23 +84070,19 @@ }, "to-regex-range": { "version": "2.1.1", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "requires": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" } }, "toggle-selection": { - "version": "1.0.6", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + "version": "1.0.6" }, "toidentifier": { - "version": "1.0.0", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + "version": "1.0.1" }, "topojson": { "version": "1.6.27", - "integrity": "sha512-JLFtrhClUH/k/yvsiCXqcWcXaOfO3DgFvHnYb+gS2xlDbjbvkKh6YB1CPilmEV++tH33xw6wCxoYA5g6YLZw/Q==", "requires": { "d3": "3", "d3-geo-projection": "0.2", @@ -81770,12 +84094,10 @@ }, "totalist": { "version": "1.1.0", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", "dev": true }, "tough-cookie": { "version": "2.5.0", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, "requires": { "psl": "^1.1.28", @@ -81784,67 +84106,55 @@ }, "tr46": { "version": "1.0.1", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, "requires": { "punycode": "^2.1.0" } }, "transform-loader": { "version": "0.2.4", - "integrity": "sha512-zdeb90cBkXoAwGvMRMYqS8lNNdZ9dYnEKxtXCi0ZmQ8OL1XF1b4BvuqjcVcm8ZJRsXSQCrSnGgd5gfaKTlGpcw==", "dev": true, "requires": { "loader-utils": "^1.0.2" } }, "traverse": { - "version": "0.6.6", - "integrity": "sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==" + "version": "0.6.6" }, "tree-kill": { "version": "1.2.2", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true }, "trim": { - "version": "0.0.1", - "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==" + "version": "0.0.1" }, "trim-lines": { - "version": "3.0.1", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==" + "version": "3.0.1" }, "trim-newlines": { "version": "3.0.1", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, "trim-repeated": { "version": "1.0.0", - "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", "requires": { "escape-string-regexp": "^1.0.2" } }, "trim-trailing-lines": { - "version": "1.1.3", - "integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA==" + "version": "1.1.3" }, "trough": { - "version": "1.0.5", - "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==" + "version": "1.0.5" }, "ts-dedent": { - "version": "2.2.0", - "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==" + "version": "2.2.0" }, "ts-essentials": { - "version": "2.0.12", - "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==" + "version": "2.0.12" }, "ts-loader": { "version": "9.2.5", - "integrity": "sha512-al/ATFEffybdRMUIr5zMEWQdVnCGMUA9d3fXJ8dBVvBlzytPvIszoG9kZoR+94k6/i293RnVOXwMaWbXhNy9pQ==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -81855,7 +84165,6 @@ "dependencies": { "braces": { "version": "3.0.2", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -81863,7 +84172,6 @@ }, "enhanced-resolve": { "version": "5.8.2", - "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -81872,7 +84180,6 @@ }, "fill-range": { "version": "7.0.1", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -81880,12 +84187,10 @@ }, "is-number": { "version": "7.0.0", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -81893,7 +84198,6 @@ }, "micromatch": { "version": "4.0.2", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -81902,7 +84206,6 @@ }, "semver": { "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -81910,12 +84213,10 @@ }, "tapable": { "version": "2.2.1", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, "to-regex-range": { "version": "5.0.1", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -81923,18 +84224,15 @@ }, "yallist": { "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, "ts-pnp": { - "version": "1.2.0", - "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==" + "version": "1.2.0" }, "tsconfig-paths": { "version": "3.11.0", - "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", "dev": true, "requires": { "@types/json5": "^0.0.29", @@ -81944,29 +84242,24 @@ } }, "tslib": { - "version": "1.11.1", - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + "version": "1.11.1" }, "tsutils": { "version": "3.21.0", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "requires": { "tslib": "^1.8.1" } }, "tty-browserify": { - "version": "0.0.0", - "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==" + "version": "0.0.0" }, "tunnel": { "version": "0.0.6", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", "dev": true }, "tunnel-agent": { "version": "0.6.0", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "requires": { "safe-buffer": "^5.0.1" @@ -81974,40 +84267,41 @@ }, "tweetnacl": { "version": "0.14.5", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, "type-check": { "version": "0.3.2", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "requires": { "prelude-ls": "~1.1.2" } }, "type-detect": { "version": "4.0.8", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, "type-fest": { - "version": "0.8.1", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + "version": "0.8.1" }, "type-is": { "version": "1.6.18", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "requires": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, + "typed-array-length": { + "version": "1.0.4", + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, "typedarray": { - "version": "0.0.6", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + "version": "0.0.6" }, "typedarray-to-buffer": { "version": "3.1.5", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, "requires": { "is-typedarray": "^1.0.0" @@ -82015,53 +84309,35 @@ }, "typescript": { "version": "4.5.4", - "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", "dev": true }, "typical": { - "version": "4.0.0", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" + "version": "4.0.0" }, "ua-parser-js": { - "version": "0.7.28", - "integrity": "sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==" + "version": "0.7.28" }, "uglify-js": { "version": "3.14.5", - "integrity": "sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ==", "optional": true }, - "uid-number": { - "version": "0.0.6", - "integrity": "sha512-c461FXIljswCuscZn67xq9PpszkPT6RjheWFQTgCyabJrTUozElanb0YEqv2UGgk247YpcJkFBuSGNvBlpXM9w==", - "dev": true - }, "ultimate-pagination": { - "version": "1.0.0", - "integrity": "sha512-bJNroO5GM11McB9RJ1rHZGiXV/jU89Qwc6U5wR8jZuk0uFVajIvUDGPiROVvNMApvh7Ij3cPoeG5V3UlF4GvOA==" - }, - "umask": { - "version": "1.1.0", - "integrity": "sha512-lE/rxOhmiScJu9L6RTNVgB/zZbF+vGC0/p6D3xnkAePI2o0sMyFG966iR5Ki50OI/0mNi2yaRnxfLsPmEZF/JA==", - "dev": true + "version": "1.0.0" }, "un-eval": { - "version": "1.2.0", - "integrity": "sha512-Wlj/pum6dQtGTPD/lclDtoVPkSfpjPfy1dwnnKw/sZP5DpBH9fLhBgQfsqNhe5/gS1D+vkZUuB771NRMUPA5CA==" + "version": "1.2.0" }, "unbox-primitive": { - "version": "1.0.1", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" } }, "unbzip2-stream": { "version": "1.3.3", - "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", "dev": true, "requires": { "buffer": "^5.2.1", @@ -82070,7 +84346,6 @@ "dependencies": { "buffer": { "version": "5.7.1", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "requires": { "base64-js": "^1.3.1", @@ -82080,44 +84355,36 @@ } }, "underscore": { - "version": "1.12.0", - "integrity": "sha512-21rQzss/XPMjolTiIezSu3JAjgagXKROtNrYFEOWK109qY1Uv2tVjPTZ1ci2HgvQDA16gHYSthQIJfB+XId/rQ==" + "version": "1.13.6" }, "unfetch": { - "version": "4.2.0", - "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==" + "version": "4.2.0" }, "unherit": { "version": "1.1.3", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", "requires": { "inherits": "^2.0.0", "xtend": "^4.0.0" } }, "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" + "version": "2.0.0" }, "unicode-match-property-ecmascript": { "version": "2.0.0", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "requires": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" } }, "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" + "version": "2.0.0" }, "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" + "version": "2.0.0" }, "unified": { "version": "10.1.2", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", "requires": { "@types/unist": "^2.0.0", "bail": "^2.0.0", @@ -82129,26 +84396,21 @@ }, "dependencies": { "bail": { - "version": "2.0.2", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + "version": "2.0.2" }, "is-buffer": { - "version": "2.0.5", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + "version": "2.0.5" }, "is-plain-obj": { - "version": "4.1.0", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + "version": "4.1.0" }, "trough": { - "version": "2.1.0", - "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + "version": "2.1.0" } } }, "union-value": { "version": "1.0.1", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", @@ -82158,62 +84420,51 @@ }, "uniqs": { "version": "2.0.0", - "integrity": "sha512-mZdDpf3vBV5Efh29kMw5tXoup/buMgxLzOt/XKFKcVmi+15ManNQWr6HfZ2aiZTYlYixbdNJ0KFmIZIv52tHSQ==", "dev": true }, "unique-filename": { "version": "1.1.1", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "requires": { "unique-slug": "^2.0.0" } }, "unique-slug": { "version": "2.0.2", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "requires": { "imurmurhash": "^0.1.4" } }, "unist-builder": { - "version": "2.0.3", - "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==" + "version": "2.0.3" }, "unist-util-generated": { - "version": "1.1.6", - "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==" + "version": "1.1.6" }, "unist-util-is": { - "version": "5.1.1", - "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==" + "version": "5.1.1" }, "unist-util-position": { - "version": "3.1.0", - "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==" + "version": "3.1.0" }, "unist-util-remove": { "version": "2.1.0", - "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", "requires": { "unist-util-is": "^4.0.0" }, "dependencies": { "unist-util-is": { - "version": "4.1.0", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" + "version": "4.1.0" } } }, "unist-util-stringify-position": { "version": "3.0.2", - "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", "requires": { "@types/unist": "^2.0.0" } }, "unist-util-visit": { "version": "4.1.1", - "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", @@ -82222,36 +84473,33 @@ }, "unist-util-visit-parents": { "version": "5.1.1", - "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" } }, + "universal-user-agent": { + "version": "6.0.0" + }, "universalify": { - "version": "2.0.0", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + "version": "2.0.0" }, "unload": { "version": "2.3.1", - "integrity": "sha512-MUZEiDqvAN9AIDRbbBnVYVvfcR6DrjCqeU2YQMmliFZl9uaBUjTkhuDQkBiyAy8ad5bx1TXVbqZ3gg7namsWjA==", "requires": { "@babel/runtime": "^7.6.2", "detect-node": "2.1.0" } }, "unpipe": { - "version": "1.0.0", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + "version": "1.0.0" }, "unquote": { "version": "1.1.1", - "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==", "dev": true }, "unset-value": { "version": "1.0.0", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "requires": { "has-value": "^0.3.1", "isobject": "^3.0.0" @@ -82259,7 +84507,6 @@ "dependencies": { "has-value": { "version": "0.3.1", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "requires": { "get-value": "^2.0.3", "has-values": "^0.1.4", @@ -82268,7 +84515,6 @@ "dependencies": { "isobject": { "version": "2.1.0", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "requires": { "isarray": "1.0.0" } @@ -82276,52 +84522,52 @@ } }, "has-values": { - "version": "0.1.4", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==" + "version": "0.1.4" } } }, - "unzip-response": { - "version": "2.0.1", - "integrity": "sha512-N0XH6lqDtFH84JxptQoZYmloF4nzrQqqrAymNj+/gW60AO2AZgOcf4O/nUXJcYfyQkqvMo9lSupBZmmgvuVXlw==" - }, "upath": { "version": "1.2.0", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "optional": true }, + "update-browserslist-db": { + "version": "1.0.5", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "dependencies": { + "picocolors": { + "version": "1.0.0" + } + } + }, "uri-js": { "version": "4.2.2", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "requires": { "punycode": "^2.1.0" } }, "urijs": { - "version": "1.19.11", - "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" + "version": "1.19.11" }, "urix": { - "version": "0.1.0", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==" + "version": "0.1.0" }, "url": { "version": "0.11.0", - "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", "requires": { "punycode": "1.3.2", "querystring": "0.2.0" }, "dependencies": { "punycode": { - "version": "1.3.2", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + "version": "1.3.2" } } }, "url-loader": { "version": "4.1.1", - "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", "requires": { "loader-utils": "^2.0.0", "mime-types": "^2.1.27", @@ -82329,12 +84575,10 @@ }, "dependencies": { "json5": { - "version": "2.2.1", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.3" }, "loader-utils": { - "version": "2.0.2", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -82345,99 +84589,69 @@ }, "url-parse": { "version": "1.5.10", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, - "url-parse-lax": { - "version": "1.0.0", - "integrity": "sha512-BVA4lR5PIviy2PMseNd2jbFQ+jwSwQGdJejf5ctd1rEXt0Ypd7yanUK9+lYechVlN5VaTJGsu2U/3MDDu6KgBA==", - "requires": { - "prepend-http": "^1.0.1" - } - }, "use": { - "version": "3.1.1", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + "version": "3.1.1" }, "use-composed-ref": { "version": "1.1.0", - "integrity": "sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==", "requires": { "ts-essentials": "^2.0.3" } }, "use-immer": { - "version": "0.6.0", - "integrity": "sha512-dFGRfvWCqPDTOt/S431ETYTg6+uxbpb7A1pptufwXVzGJY3RlXr38+3wyLNpc6SbbmAKjWl6+EP6uW74fkEsXQ==" + "version": "0.8.1" }, "use-isomorphic-layout-effect": { - "version": "1.1.1", - "integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==" + "version": "1.1.1" }, "use-latest": { "version": "1.2.0", - "integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==", "requires": { "use-isomorphic-layout-effect": "^1.0.0" } }, "use-query-params": { "version": "1.1.9", - "integrity": "sha512-WAJ1GrKbFWv1TBn1RQpHqAwC7yyJsLaJjBhIfefrbY/h6mFSngzBQKirJndYwCS1ry77EwhpR/tQi5iovXWvuw==", "requires": { "serialize-query-params": "^1.2.3" } }, "util": { "version": "0.11.1", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", "requires": { "inherits": "2.0.3" } }, "util-deprecate": { - "version": "1.0.2", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "util-promisify": { - "version": "2.1.0", - "integrity": "sha512-K+5eQPYs14b3+E+hmE2J6gCZ4JmMl9DbYS6BeP2CHq6WMuNxErxf5B/n0fz85L8zUuoO6rIzNNmIQDu/j+1OcA==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3" - } + "version": "1.0.2" }, "util.promisify": { "version": "1.0.0", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", "requires": { "define-properties": "^1.1.2", "object.getownpropertydescriptors": "^2.0.3" } }, "utila": { - "version": "0.4.0", - "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + "version": "0.4.0" }, "utils-merge": { - "version": "1.0.1", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + "version": "1.0.1" }, "uuid": { - "version": "3.4.0", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "3.4.0" }, "uuid-browser": { - "version": "3.1.0", - "integrity": "sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==" + "version": "3.1.0" }, "uvu": { "version": "0.5.6", - "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", "requires": { "dequal": "^2.0.0", "diff": "^5.0.0", @@ -82446,23 +84660,19 @@ }, "dependencies": { "diff": { - "version": "5.1.0", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==" + "version": "5.1.0" }, "kleur": { - "version": "4.1.5", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" + "version": "4.1.5" } } }, "v8-compile-cache": { "version": "2.3.0", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, "v8-to-istanbul": { "version": "7.0.0", - "integrity": "sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -82472,14 +84682,12 @@ "dependencies": { "source-map": { "version": "0.7.3", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "dev": true } } }, "v8flags": { "version": "3.2.0", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" @@ -82487,7 +84695,6 @@ }, "validate-npm-package-license": { "version": "3.0.4", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -82495,28 +84702,23 @@ }, "validate-npm-package-name": { "version": "3.0.0", - "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", "dev": true, "requires": { "builtins": "^1.0.3" } }, "value-equal": { - "version": "1.0.1", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + "version": "1.0.1" }, "vary": { - "version": "1.1.2", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + "version": "1.1.2" }, "vendors": { "version": "1.0.4", - "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", "dev": true }, "verror": { "version": "1.10.0", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -82525,8 +84727,7 @@ } }, "vfile": { - "version": "5.3.6", - "integrity": "sha512-ADBsmerdGBs2WYckrLBEmuETSPyTD4TuLxTrw0DvjirxW1ra4ZwkbzG8ndsv3Q57smvHxo677MHaQrY9yxH8cA==", + "version": "5.3.5", "requires": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", @@ -82535,22 +84736,19 @@ }, "dependencies": { "is-buffer": { - "version": "2.0.5", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + "version": "2.0.5" } } }, "vfile-location": { "version": "4.0.1", - "integrity": "sha512-JDxPlTbZrZCQXogGheBHjbRWjESSPEak770XwWPfw5mTc1v1nWGLB/apzZxsx8a0SJVfF8HK8ql8RD308vXRUw==", "requires": { "@types/unist": "^2.0.0", "vfile": "^5.0.0" } }, "vfile-message": { - "version": "3.1.3", - "integrity": "sha512-0yaU+rj2gKAyEk12ffdSbBfjnnj+b1zqTBv3OQCTn8yEB02bsPizwdBPrLJjHnK+cU9EMMcUnNv938XcZIkmdA==", + "version": "3.1.2", "requires": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^3.0.0" @@ -82558,54 +84756,33 @@ }, "viewport-mercator-project": { "version": "6.2.3", - "integrity": "sha512-QQb0/qCLlP4DdfbHHSWVYXpghB2wkLIiiZQnoelOB59mXKQSyZVxjreq1S+gaBJFpcGkWEcyVtre0+2y2DTl/Q==", "requires": { "@babel/runtime": "^7.0.0", "gl-matrix": "^3.0.0" } }, - "vinyl": { - "version": "2.2.1", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } + "vlq": { + "version": "0.2.3" }, - "vinyl-file": { - "version": "3.0.0", - "integrity": "sha512-BoJDj+ca3D9xOuPEM6RWVtWQtvEPQiQYn82LvdxhLWplfQsBzBqtgK0yhCP0s1BNTi6dH9BO+dzybvyQIacifg==", - "optional": true, + "vm-browserify": { + "version": "1.1.2" + }, + "vm2": { + "version": "3.9.13", + "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.3.0", - "strip-bom-buf": "^1.0.0", - "strip-bom-stream": "^2.0.0", - "vinyl": "^2.0.1" + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" }, "dependencies": { - "pify": { - "version": "2.3.0", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "optional": true + "acorn-walk": { + "version": "8.2.0", + "dev": true } } }, - "vlq": { - "version": "0.2.3", - "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" - }, - "vm-browserify": { - "version": "1.1.2", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" - }, "vt-pbf": { "version": "3.1.3", - "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", "requires": { "@mapbox/point-geometry": "0.1.0", "@mapbox/vector-tile": "^1.3.1", @@ -82614,23 +84791,30 @@ }, "w3c-hr-time": { "version": "1.0.2", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", "dev": true, "requires": { "browser-process-hrtime": "^1.0.0" } }, "w3c-xmlserializer": { - "version": "2.0.0", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "version": "3.0.0", "dev": true, "requires": { - "xml-name-validator": "^3.0.0" + "xml-name-validator": "^4.0.0" + }, + "dependencies": { + "xml-name-validator": { + "version": "4.0.0", + "dev": true + } } }, + "walk-up-path": { + "version": "1.0.0", + "dev": true + }, "walker": { "version": "1.0.7", - "integrity": "sha512-cF4je9Fgt6sj1PKfuFt9jpQPeHosM+Ryma/hfY9U7uXGKM7pJCsF0v2r55o+Il54+i77SyYWetB4tD1dEygRkw==", "dev": true, "requires": { "makeerror": "1.0.x" @@ -82638,14 +84822,12 @@ }, "warning": { "version": "4.0.3", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", "requires": { "loose-envify": "^1.0.0" } }, "watchpack": { "version": "1.7.5", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", "requires": { "chokidar": "^3.4.1", "graceful-fs": "^4.1.2", @@ -82655,7 +84837,6 @@ }, "watchpack-chokidar2": { "version": "2.0.1", - "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", "optional": true, "requires": { "chokidar": "^2.1.8" @@ -82663,7 +84844,6 @@ "dependencies": { "chokidar": { "version": "2.1.8", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "optional": true, "requires": { "anymatch": "^2.0.0", @@ -82682,7 +84862,6 @@ }, "glob-parent": { "version": "3.1.0", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", "optional": true, "requires": { "is-glob": "^3.1.0", @@ -82691,7 +84870,6 @@ "dependencies": { "is-glob": { "version": "3.1.0", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "optional": true, "requires": { "is-extglob": "^2.1.0" @@ -82701,14 +84879,12 @@ }, "normalize-path": { "version": "3.0.0", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "optional": true } } }, "wbuf": { "version": "1.7.3", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, "requires": { "minimalistic-assert": "^1.0.0" @@ -82716,23 +84892,20 @@ }, "wcwidth": { "version": "1.0.1", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, "requires": { "defaults": "^1.0.3" } }, "web-namespaces": { - "version": "1.1.4", - "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==" + "version": "1.1.4" }, "webidl-conversions": { "version": "4.0.2", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + "dev": true }, "webpack": { "version": "5.52.1", - "integrity": "sha512-wkGb0hLfrS7ML3n2xIKfUIwHbjB6gxwQHyLmVHoAqEQBw+nWo+G6LoHL098FEXqahqximsntjBLuewStrnJk0g==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.0", @@ -82763,7 +84936,6 @@ "dependencies": { "@webassemblyjs/ast": { "version": "1.11.1", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", "dev": true, "requires": { "@webassemblyjs/helper-numbers": "1.11.1", @@ -82772,22 +84944,18 @@ }, "@webassemblyjs/helper-api-error": { "version": "1.11.1", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", "dev": true }, "@webassemblyjs/helper-buffer": { "version": "1.11.1", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", "dev": true }, "@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.1", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", "dev": true }, "@webassemblyjs/helper-wasm-section": { "version": "1.11.1", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", "dev": true, "requires": { "@webassemblyjs/ast": "1.11.1", @@ -82798,7 +84966,6 @@ }, "@webassemblyjs/ieee754": { "version": "1.11.1", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" @@ -82806,7 +84973,6 @@ }, "@webassemblyjs/leb128": { "version": "1.11.1", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", "dev": true, "requires": { "@xtuc/long": "4.2.2" @@ -82814,12 +84980,10 @@ }, "@webassemblyjs/utf8": { "version": "1.11.1", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", "dev": true }, "@webassemblyjs/wasm-edit": { "version": "1.11.1", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", "dev": true, "requires": { "@webassemblyjs/ast": "1.11.1", @@ -82834,7 +84998,6 @@ }, "@webassemblyjs/wasm-gen": { "version": "1.11.1", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", "dev": true, "requires": { "@webassemblyjs/ast": "1.11.1", @@ -82846,7 +85009,6 @@ }, "@webassemblyjs/wasm-opt": { "version": "1.11.1", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", "dev": true, "requires": { "@webassemblyjs/ast": "1.11.1", @@ -82857,7 +85019,6 @@ }, "@webassemblyjs/wasm-parser": { "version": "1.11.1", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", "dev": true, "requires": { "@webassemblyjs/ast": "1.11.1", @@ -82870,7 +85031,6 @@ }, "@webassemblyjs/wast-printer": { "version": "1.11.1", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", "dev": true, "requires": { "@webassemblyjs/ast": "1.11.1", @@ -82879,7 +85039,6 @@ }, "enhanced-resolve": { "version": "5.8.2", - "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -82888,12 +85047,10 @@ }, "has-flag": { "version": "4.0.0", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "jest-worker": { "version": "27.2.0", - "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", "dev": true, "requires": { "@types/node": "*", @@ -82903,7 +85060,6 @@ }, "p-limit": { "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { "yocto-queue": "^0.1.0" @@ -82911,7 +85067,6 @@ }, "serialize-javascript": { "version": "6.0.0", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -82919,12 +85074,10 @@ }, "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "supports-color": { "version": "8.1.1", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -82932,29 +85085,20 @@ }, "tapable": { "version": "2.2.1", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, "terser": { - "version": "5.8.0", - "integrity": "sha512-f0JH+6yMpneYcRJN314lZrSwu9eKkUFEHLN/kNy8ceh8gaRiLgFPJqrB9HsXjhEGdv4e/ekjTOFxIlL6xlma8A==", + "version": "5.14.2", "dev": true, "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } } }, "terser-webpack-plugin": { "version": "5.2.4", - "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", "dev": true, "requires": { "jest-worker": "^27.0.6", @@ -82967,7 +85111,6 @@ }, "watchpack": { "version": "2.2.0", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -82978,7 +85121,6 @@ }, "webpack-bundle-analyzer": { "version": "4.4.2", - "integrity": "sha512-PIagMYhlEzFfhMYOzs5gFT55DkUdkyrJi/SxJp8EF3YMWhS+T9vvs2EoTetpk5qb6VsCq02eXTlRDOydRhDFAQ==", "dev": true, "requires": { "acorn": "^8.0.4", @@ -82994,17 +85136,14 @@ "dependencies": { "acorn-walk": { "version": "8.2.0", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true }, "commander": { "version": "6.2.1", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true }, "gzip-size": { "version": "6.0.0", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", "dev": true, "requires": { "duplexer": "^0.1.2" @@ -83014,7 +85153,6 @@ }, "webpack-cli": { "version": "4.8.0", - "integrity": "sha512-+iBSWsX16uVna5aAYN6/wjhJy1q/GKk4KjKvfg90/6hykCTSgozbfz5iRgDTSJt/LgSbYxdBX3KBHeobIs+ZEw==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", @@ -83034,12 +85172,10 @@ "dependencies": { "commander": { "version": "7.2.0", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true }, "cross-spawn": { "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -83049,7 +85185,6 @@ }, "execa": { "version": "5.1.1", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { "cross-spawn": "^7.0.3", @@ -83065,22 +85200,18 @@ }, "get-stream": { "version": "6.0.1", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, "human-signals": { "version": "2.1.0", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "is-stream": { "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, "npm-run-path": { "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { "path-key": "^3.0.0" @@ -83088,12 +85219,10 @@ }, "path-key": { "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "rechoir": { "version": "0.7.1", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, "requires": { "resolve": "^1.9.0" @@ -83101,7 +85230,6 @@ }, "shebang-command": { "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" @@ -83109,12 +85237,10 @@ }, "shebang-regex": { "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -83124,7 +85250,6 @@ }, "webpack-dev-middleware": { "version": "3.7.3", - "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", "requires": { "memory-fs": "^0.4.1", "mime": "^2.4.4", @@ -83134,74 +85259,193 @@ }, "dependencies": { "mime": { - "version": "2.6.0", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" + "version": "2.6.0" } } }, "webpack-dev-server": { - "version": "4.2.0", - "integrity": "sha512-iBaDkHBLfW3cEITeJWNkjZBrm+b5A3YLg8XVdNOdjUNABdXJwcsJv4dzKSnVf1q4Ch489+6epWVW6OcOyVfG7w==", + "version": "4.10.1", "dev": true, "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", "ansi-html-community": "^0.0.8", - "bonjour": "^3.5.0", - "chokidar": "^3.5.1", - "colorette": "^1.2.2", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "del": "^6.0.0", - "express": "^4.17.1", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", "graceful-fs": "^4.2.6", "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.0", - "internal-ip": "^6.2.0", + "http-proxy-middleware": "^2.0.3", "ipaddr.js": "^2.0.1", "open": "^8.0.9", "p-retry": "^4.5.0", - "portfinder": "^1.0.28", - "schema-utils": "^3.1.0", - "selfsigned": "^1.10.11", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", "serve-index": "^1.9.1", - "sockjs": "^0.3.21", + "sockjs": "^0.3.24", "spdy": "^4.0.2", - "strip-ansi": "^7.0.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^5.1.0", - "ws": "^8.1.0" + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" }, "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "ajv": { + "version": "8.11.0", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "array-flatten": { + "version": "1.1.1", + "dev": true + }, + "body-parser": { + "version": "1.20.0", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "dev": true + }, + "colorette": { + "version": "2.0.19", "dev": true }, - "del": { - "version": "6.0.0", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", + "cookie": { + "version": "0.5.0", + "dev": true + }, + "depd": { + "version": "2.0.0", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "dev": true + }, + "express": { + "version": "4.18.1", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.2.0", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "http-errors": { + "version": "2.0.0", "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" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" } }, + "inherits": { + "version": "2.0.4", + "dev": true + }, "is-wsl": { "version": "2.2.0", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "requires": { "is-docker": "^2.0.0" } }, + "json-schema-traverse": { + "version": "1.0.0", + "dev": true + }, + "ms": { + "version": "2.1.3", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, "open": { "version": "8.2.1", - "integrity": "sha512-rXILpcQlkF/QuFez2BJDf3GsqpjGKbkUUToAIGo9A0Q6ZkoSGogZJulrUdwRkrAsoQvoZsrjCYt8+zblOk7JQQ==", "dev": true, "requires": { "define-lazy-prop": "^2.0.0", @@ -83209,41 +85453,97 @@ "is-wsl": "^2.2.0" } }, - "slash": { - "version": "3.0.0", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "path-to-regexp": { + "version": "0.1.7", "dev": true }, - "strip-ansi": { - "version": "7.0.1", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "qs": { + "version": "6.10.3", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "raw-body": { + "version": "2.5.1", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "dev": true + }, + "schema-utils": { + "version": "4.0.0", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "send": { + "version": "0.18.0", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + } + }, + "serve-static": { + "version": "1.15.0", "dev": true, "requires": { - "ansi-regex": "^6.0.1" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" } }, + "setprototypeof": { + "version": "1.2.0", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "dev": true + }, "webpack-dev-middleware": { - "version": "5.1.0", - "integrity": "sha512-oT660AR1gOnU/NTdUQi3EiGR0iXG7CFxmKsj3ylWCBA2khJ8LFHK+sKv3BZEsC11gl1eChsltRhzUq7nWj7XIQ==", + "version": "5.3.3", "dev": true, "requires": { - "colorette": "^1.2.2", - "memfs": "^3.2.2", + "colorette": "^2.0.10", + "memfs": "^3.4.3", "mime-types": "^2.1.31", "range-parser": "^1.2.1", - "schema-utils": "^3.1.0" + "schema-utils": "^4.0.0" } }, "ws": { "version": "8.5.0", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", "dev": true } } }, "webpack-hot-middleware": { "version": "2.25.1", - "integrity": "sha512-Koh0KyU/RPYwel/khxbsDz9ibDivmUbrRuKSSQvW42KSDdO4w23WI3SkHpSUKHE76LrFnnM/L7JCrpBwu8AXYw==", "requires": { "ansi-html-community": "0.0.8", "html-entities": "^2.1.0", @@ -83252,12 +85552,10 @@ }, "dependencies": { "ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "version": "5.0.1" }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { "ansi-regex": "^5.0.1" } @@ -83266,7 +85564,6 @@ }, "webpack-log": { "version": "2.0.0", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", "requires": { "ansi-colors": "^3.0.0", "uuid": "^3.3.2" @@ -83274,7 +85571,6 @@ }, "webpack-manifest-plugin": { "version": "4.0.2", - "integrity": "sha512-Ld6j05pRblXAVoX8xdXFDsc/s97cFnR1FOmQawhTSlp6F6aeU1Jia5aqTmDpkueaAz8g9sXpgSOqmEgVAR61Xw==", "dev": true, "requires": { "tapable": "^2.0.0", @@ -83283,17 +85579,14 @@ "dependencies": { "source-map": { "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "tapable": { "version": "2.2.1", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, "webpack-sources": { "version": "2.3.1", - "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", "dev": true, "requires": { "source-list-map": "^2.0.1", @@ -83304,7 +85597,6 @@ }, "webpack-merge": { "version": "5.8.0", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", "dev": true, "requires": { "clone-deep": "^4.0.1", @@ -83313,32 +85605,27 @@ }, "webpack-sources": { "version": "3.2.0", - "integrity": "sha512-fahN08Et7P9trej8xz/Z7eRu8ltyiygEo/hnRi9KqBUs80KeDcnf96ZJo++ewWd84fEf3xSX9bp4ZS9hbw0OBw==", "dev": true }, "webpack-virtual-modules": { "version": "0.2.2", - "integrity": "sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA==", "requires": { "debug": "^3.0.0" }, "dependencies": { "debug": { "version": "3.2.7", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { "ms": "^2.1.1" } }, "ms": { - "version": "2.1.3", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "version": "2.1.3" } } }, "websocket-driver": { "version": "0.7.4", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, "requires": { "http-parser-js": ">=0.5.1", @@ -83348,33 +85635,24 @@ }, "websocket-extensions": { "version": "0.1.4", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, - "wgs84": { - "version": "0.0.0", - "integrity": "sha512-ANHlY4Rb5kHw40D0NJ6moaVfOCMrp9Gpd1R/AIQYg2ko4/jzcJ+TVXYYF6kXJqQwITvEZP4yEthjM7U6rYlljQ==" - }, "whatwg-encoding": { "version": "1.0.5", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", "dev": true, "requires": { "iconv-lite": "0.4.24" } }, "whatwg-fetch": { - "version": "3.6.2", - "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + "version": "3.6.2" }, "whatwg-mimetype": { "version": "2.3.0", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", "dev": true }, "whatwg-url": { "version": "6.5.0", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", "dev": true, "requires": { "lodash.sortby": "^4.7.0", @@ -83384,14 +85662,13 @@ }, "which": { "version": "1.3.1", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "requires": { "isexe": "^2.0.0" } }, "which-boxed-primitive": { "version": "1.0.2", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -83401,34 +85678,39 @@ } }, "which-module": { - "version": "2.0.0", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" + "version": "2.0.0" + }, + "which-typed-array": { + "version": "1.1.9", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } }, "wide-align": { "version": "1.1.5", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "requires": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "widest-line": { "version": "3.1.0", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", "requires": { "string-width": "^4.0.0" }, "dependencies": { "ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "version": "5.0.1" }, "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "version": "3.0.0" }, "string-width": { "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -83437,7 +85719,6 @@ }, "strip-ansi": { "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { "ansi-regex": "^5.0.1" } @@ -83446,68 +85727,41 @@ }, "wildcard": { "version": "2.0.0", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", "dev": true }, - "with-open-file": { - "version": "0.1.7", - "integrity": "sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==", - "requires": { - "p-finally": "^1.0.0", - "p-try": "^2.1.0", - "pify": "^4.0.1" - }, - "dependencies": { - "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pify": { - "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - } - } - }, "word-wrap": { "version": "1.2.3", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, "wordwrap": { - "version": "1.0.0", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" + "version": "1.0.0" }, "wordwrapjs": { "version": "4.0.1", - "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", "requires": { "reduce-flatten": "^2.0.0", "typical": "^5.2.0" }, "dependencies": { "typical": { - "version": "5.2.0", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + "version": "5.2.0" } } }, "worker-farm": { "version": "1.7.0", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "requires": { "errno": "~0.1.7" } }, "worker-rpc": { "version": "0.1.1", - "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==", "requires": { "microevent.ts": "~0.1.1" } }, "wrap-ansi": { "version": "6.2.0", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -83515,16 +85769,13 @@ }, "dependencies": { "ansi-regex": { - "version": "5.0.0", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.0" }, "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "version": "3.0.0" }, "string-width": { "version": "4.2.0", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -83533,7 +85784,6 @@ }, "strip-ansi": { "version": "6.0.0", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "requires": { "ansi-regex": "^5.0.0" } @@ -83541,12 +85791,10 @@ } }, "wrappy": { - "version": "1.0.2", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "version": "1.0.2" }, "write-file-atomic": { "version": "3.0.3", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "requires": { "imurmurhash": "^0.1.4", @@ -83557,7 +85805,6 @@ }, "write-json-file": { "version": "4.3.0", - "integrity": "sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ==", "dev": true, "requires": { "detect-indent": "^6.0.0", @@ -83570,12 +85817,10 @@ "dependencies": { "is-plain-obj": { "version": "2.1.0", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, "make-dir": { "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, "requires": { "semver": "^6.0.0" @@ -83583,14 +85828,12 @@ }, "semver": { "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "write-pkg": { "version": "4.0.0", - "integrity": "sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==", "dev": true, "requires": { "sort-keys": "^2.0.0", @@ -83600,17 +85843,14 @@ "dependencies": { "detect-indent": { "version": "5.0.0", - "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", "dev": true }, "pify": { "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, "sort-keys": { "version": "2.0.0", - "integrity": "sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==", "dev": true, "requires": { "is-plain-obj": "^1.0.0" @@ -83618,12 +85858,10 @@ }, "type-fest": { "version": "0.4.1", - "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", "dev": true }, "write-file-atomic": { "version": "2.4.3", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -83633,7 +85871,6 @@ }, "write-json-file": { "version": "3.2.0", - "integrity": "sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==", "dev": true, "requires": { "detect-indent": "^5.0.0", @@ -83648,51 +85885,45 @@ }, "ws": { "version": "7.5.7", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "dev": true }, "xml-name-validator": { "version": "3.0.0", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", "dev": true }, "xmlbuilder": { "version": "10.1.1", - "integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==", "dev": true }, "xmlchars": { "version": "2.2.0", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "xregexp": { + "version": "2.0.0", "dev": true }, "xss": { "version": "1.0.10", - "integrity": "sha512-qmoqrRksmzqSKvgqzN0055UFWY7OKx1/9JWeRswwEVX9fCG5jcYRxa/A2DHcmZX6VJvjzHRQ2STeeVcQkrmLSw==", "requires": { "commander": "^2.20.3", "cssfilter": "0.0.10" } }, "xtend": { - "version": "4.0.1", - "integrity": "sha512-iTwvhNBRetXWe81+VcIw5YeadVSWyze7uA7nVnpP13ulrpnJ3UfQm5ApGnrkmxDJFdrblRdZs0EvaTCIfei5oQ==" + "version": "4.0.1" }, "y18n": { - "version": "4.0.3", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + "version": "4.0.3" }, "yallist": { - "version": "3.1.1", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "version": "3.1.1" }, "yaml": { - "version": "1.10.2", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + "version": "1.10.2" }, "yargs": { "version": "15.4.1", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "requires": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -83708,53 +85939,44 @@ }, "dependencies": { "ansi-regex": { - "version": "5.0.0", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.0" }, "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "version": "3.0.0" }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { "p-locate": "^4.1.0" } }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "requires": { "p-limit": "^2.2.0" } }, "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "version": "2.2.0" }, "path-exists": { - "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "version": "4.0.0" }, "string-width": { "version": "4.2.0", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -83763,7 +85985,6 @@ }, "strip-ansi": { "version": "6.0.0", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "requires": { "ansi-regex": "^5.0.0" } @@ -83772,7 +85993,6 @@ }, "yargs-parser": { "version": "18.1.3", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -83780,7 +86000,6 @@ }, "yarn-or-npm": { "version": "3.0.1", - "integrity": "sha512-fTiQP6WbDAh5QZAVdbMQkecZoahnbOjClTQhzv74WX5h2Uaidj1isf9FDes11TKtsZ0/ZVfZsqZ+O3x6aLERHQ==", "dev": true, "requires": { "cross-spawn": "^6.0.5", @@ -83789,7 +86008,6 @@ "dependencies": { "find-up": { "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { "locate-path": "^5.0.0", @@ -83798,7 +86016,6 @@ }, "locate-path": { "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { "p-locate": "^4.1.0" @@ -83806,7 +86023,6 @@ }, "p-limit": { "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -83814,7 +86030,6 @@ }, "p-locate": { "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { "p-limit": "^2.2.0" @@ -83822,17 +86037,14 @@ }, "p-try": { "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "path-exists": { "version": "4.0.0", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "pkg-dir": { "version": "4.2.0", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { "find-up": "^4.0.0" @@ -83842,7 +86054,6 @@ }, "yauzl": { "version": "2.10.0", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "requires": { "buffer-crc32": "~0.2.3", @@ -83851,597 +86062,109 @@ }, "yeoman-assert": { "version": "3.1.1", - "integrity": "sha512-bCuLb/j/WzpvrJZCTdJJLFzm7KK8IYQJ3+dF9dYtNs2CUYyezFJDuULiZ2neM4eqjf45GN1KH/MzCTT3i90wUQ==", "dev": true }, "yeoman-generator": { - "version": "4.13.0", - "integrity": "sha512-f2/5N5IR3M2Ozm+QocvZQudlQITv2DwI6Mcxfy7R7gTTzaKgvUpgo/pQMJ+WQKm0KN0YMWCFOZpj0xFGxevc1w==", + "version": "5.7.0", "requires": { - "async": "^2.6.2", - "chalk": "^2.4.2", - "cli-table": "^0.3.1", - "cross-spawn": "^6.0.5", - "dargs": "^6.1.0", - "dateformat": "^3.0.3", + "chalk": "^4.1.0", + "dargs": "^7.0.0", "debug": "^4.1.1", - "diff": "^4.0.1", - "error": "^7.0.2", - "find-up": "^3.0.0", - "github-username": "^3.0.0", - "grouped-queue": "^1.1.0", - "istextorbinary": "^2.5.1", + "execa": "^5.1.1", + "github-username": "^6.0.0", "lodash": "^4.17.11", - "make-dir": "^3.0.0", - "mem-fs-editor": "^7.0.1", "minimist": "^1.2.5", - "pretty-bytes": "^5.2.0", - "read-chunk": "^3.2.0", - "read-pkg-up": "^5.0.0", - "rimraf": "^2.6.3", + "read-pkg-up": "^7.0.1", "run-async": "^2.0.0", "semver": "^7.2.1", - "shelljs": "^0.8.4", - "text-table": "^0.2.0", - "through2": "^3.0.1", - "yeoman-environment": "^2.9.5" + "shelljs": "^0.8.5", + "sort-keys": "^4.2.0", + "text-table": "^0.2.0" }, "dependencies": { - "@nodelib/fs.stat": { - "version": "1.1.3", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" - }, - "ansi-regex": { - "version": "3.0.0", - "integrity": "sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==", - "optional": true - }, - "ansi-styles": { - "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "arrify": { - "version": "2.0.1", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" - }, - "async": { - "version": "2.6.3", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "requires": { - "lodash": "^4.17.14" - } - }, - "chalk": { - "version": "2.4.2", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "cross-spawn": { + "version": "7.0.3", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "dargs": { - "version": "6.1.0", - "integrity": "sha512-5dVBvpBLBnPwSsYXqfybFyehMmC/EenKEcf23AhCTgTf48JFBbmJKqoZBsERDnjL0FyiVTYWdFsRfTLHxLyKdQ==" - }, "debug": { "version": "4.3.2", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "requires": { "ms": "2.1.2" } }, - "dir-glob": { - "version": "2.2.2", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "requires": { - "path-type": "^3.0.0" - } - }, - "error": { - "version": "7.2.1", - "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", - "requires": { - "string-template": "~0.2.1" - } - }, "execa": { - "version": "4.1.0", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "optional": true, + "version": "5.1.1", "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", + "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.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "optional": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - } - } - }, - "fast-glob": { - "version": "2.2.7", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - } - }, - "find-up": { - "version": "3.0.0", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" } }, "get-stream": { - "version": "5.2.0", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "optional": true, - "requires": { - "pump": "^3.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "globby": { - "version": "9.2.0", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - }, - "dependencies": { - "array-union": { - "version": "1.0.2", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", - "requires": { - "array-uniq": "^1.0.1" - } - } - } - }, - "grouped-queue": { - "version": "1.1.0", - "integrity": "sha512-rZOFKfCqLhsu5VqjBjEWiwrYqJR07KxIkH4mLZlNlGDfntbb4FbMyGFP14TlvRPrU9S3Hnn/sgxbC5ZeN0no3Q==", - "optional": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "inherits": { - "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "version": "6.0.1" }, - "is-scoped": { - "version": "1.0.0", - "integrity": "sha512-iT1y0qJcdqXnHe6SCtN9cOBPRiarw8Cy1EZkawW50dxO/7oHC6AYvs1tH4QbBbi7UC/vYY3BnRmbE0bFLwvUog==", - "optional": true, - "requires": { - "scoped-regex": "^1.0.0" - } + "human-signals": { + "version": "2.1.0" }, "is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "optional": true - }, - "locate-path": { - "version": "3.0.0", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "log-symbols": { - "version": "2.2.0", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "optional": true, - "requires": { - "chalk": "^2.0.1" - } + "version": "2.0.1" }, "lru-cache": { "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "requires": { "yallist": "^4.0.0" } }, - "make-dir": { - "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "mem-fs": { - "version": "1.2.0", - "integrity": "sha512-b8g0jWKdl8pM0LqAPdK9i8ERL7nYrzmJfRhxMiWH2uYdfYnb7uXnmwVb0ZGe7xyEl4lj+nLIU3yf4zPUT+XsVQ==", - "optional": true, - "requires": { - "through2": "^3.0.0", - "vinyl": "^2.0.1", - "vinyl-file": "^3.0.0" - } - }, - "mem-fs-editor": { - "version": "7.1.0", - "integrity": "sha512-BH6QEqCXSqGeX48V7zu+e3cMwHU7x640NB8Zk8VNvVZniz+p4FK60pMx/3yfkzo6miI6G3a8pH6z7FeuIzqrzA==", - "requires": { - "commondir": "^1.0.1", - "deep-extend": "^0.6.0", - "ejs": "^3.1.5", - "glob": "^7.1.4", - "globby": "^9.2.0", - "isbinaryfile": "^4.0.0", - "mkdirp": "^1.0.0", - "multimatch": "^4.0.0", - "rimraf": "^3.0.0", - "through2": "^3.0.2", - "vinyl": "^2.2.1" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "mkdirp": { - "version": "1.0.4", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - }, "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "multimatch": { - "version": "4.0.0", - "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", - "requires": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - } + "version": "2.1.2" }, "npm-run-path": { "version": "4.0.1", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "optional": true, "requires": { "path-key": "^3.0.0" } }, - "p-limit": { - "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, "path-key": { - "version": "3.1.1", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "optional": true - }, - "pify": { - "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - }, - "read-pkg-up": { - "version": "5.0.0", - "integrity": "sha512-XBQjqOBtTzyol2CpsQOw8LHV0XbDZVG7xMMjmXAJomlVY03WOBRmYgDJETlvcg0H63AJvPRwT7GFi5rvOzUOKg==", - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^5.0.0" - } - }, - "rimraf": { - "version": "2.7.1", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, - "scoped-regex": { - "version": "1.0.0", - "integrity": "sha512-90/gFvaP4jXL0rXPD8FS7tWgmkQDlxCjs9cs3r3G5hAnrODt94kIh4SDbH/gm3HosGTik0omdSPOh0KQyGqjlg==", - "optional": true + "version": "3.1.1" }, "semver": { - "version": "7.3.5", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", "requires": { "lru-cache": "^6.0.0" } }, "shebang-command": { "version": "2.0.0", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "optional": true, "requires": { "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "3.0.0", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "optional": true - }, - "strip-ansi": { - "version": "4.0.0", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "optional": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "through2": { - "version": "3.0.2", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, - "untildify": { - "version": "3.0.3", - "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", - "optional": true + "version": "3.0.0" }, "which": { "version": "2.0.2", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "optional": true, "requires": { "isexe": "^2.0.0" } }, "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yeoman-environment": { - "version": "2.10.3", - "integrity": "sha512-pLIhhU9z/G+kjOXmJ2bPFm3nejfbH+f1fjYRSOteEXDBrv1EoJE/e+kuHixSXfCYfTkxjYsvRaDX+1QykLCnpQ==", - "optional": true, - "requires": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "diff": "^3.5.0", - "escape-string-regexp": "^1.0.2", - "execa": "^4.0.0", - "globby": "^8.0.1", - "grouped-queue": "^1.1.0", - "inquirer": "^7.1.0", - "is-scoped": "^1.0.0", - "lodash": "^4.17.10", - "log-symbols": "^2.2.0", - "mem-fs": "^1.1.0", - "mem-fs-editor": "^6.0.0", - "npm-api": "^1.0.0", - "semver": "^7.1.3", - "strip-ansi": "^4.0.0", - "text-table": "^0.2.0", - "untildify": "^3.0.3", - "yeoman-generator": "^4.8.2" - }, - "dependencies": { - "array-union": { - "version": "1.0.2", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", - "optional": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "arrify": { - "version": "1.0.1", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "optional": true - }, - "debug": { - "version": "3.2.7", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "diff": { - "version": "3.5.0", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "optional": true - }, - "dir-glob": { - "version": "2.0.0", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", - "optional": true, - "requires": { - "arrify": "^1.0.1", - "path-type": "^3.0.0" - } - }, - "ejs": { - "version": "2.7.4", - "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", - "optional": true - }, - "globby": { - "version": "8.0.2", - "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", - "optional": true, - "requires": { - "array-union": "^1.0.1", - "dir-glob": "2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - } - }, - "ignore": { - "version": "3.3.10", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "optional": true - }, - "mem-fs-editor": { - "version": "6.0.0", - "integrity": "sha512-e0WfJAMm8Gv1mP5fEq/Blzy6Lt1VbLg7gNnZmZak7nhrBTibs+c6nQ4SKs/ZyJYHS1mFgDJeopsLAv7Ow0FMFg==", - "optional": true, - "requires": { - "commondir": "^1.0.1", - "deep-extend": "^0.6.0", - "ejs": "^2.6.1", - "glob": "^7.1.4", - "globby": "^9.2.0", - "isbinaryfile": "^4.0.0", - "mkdirp": "^0.5.0", - "multimatch": "^4.0.0", - "rimraf": "^2.6.3", - "through2": "^3.0.1", - "vinyl": "^2.2.0" - }, - "dependencies": { - "dir-glob": { - "version": "2.2.2", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "optional": true, - "requires": { - "path-type": "^3.0.0" - } - }, - "globby": { - "version": "9.2.0", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "optional": true, - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - } - }, - "ignore": { - "version": "4.0.6", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "optional": true - }, - "pify": { - "version": "4.0.1", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "optional": true - }, - "slash": { - "version": "2.0.0", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "optional": true - } - } - }, - "mkdirp": { - "version": "0.5.5", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "optional": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "pify": { - "version": "3.0.0", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "optional": true - }, - "slash": { - "version": "1.0.0", - "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", - "optional": true - } - } + "version": "4.0.0" } } }, "yeoman-test": { "version": "6.2.0", - "integrity": "sha512-KsCxwx4vPG2IwP7hG3U67WV04ymjbAmmy+BU06CrCku7U3sFFFq7LRoeGqrMRTsAqk/ff7gQJoc8sD43AgMX6Q==", "dev": true, "requires": { "inquirer": "^8.0.0", @@ -84451,48 +86174,8 @@ "temp-dir": "^2.0.0" }, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "inquirer": { - "version": "8.2.0", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.2.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "rxjs": { - "version": "7.4.0", - "integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==", - "dev": true, - "requires": { - "tslib": "~2.1.0" - } - }, "sinon": { "version": "10.0.0", - "integrity": "sha512-XAn5DxtGVJBlBWYrcYKEhWCz7FLwZGdyvANRyK06419hyEpdT0dMc5A8Vcxg5SCGHc40CsqoKsc1bt1CbJPfNw==", "dev": true, "requires": { "@sinonjs/commons": "^1.8.1", @@ -84503,43 +86186,17 @@ "supports-color": "^7.1.0" } }, - "string-width": { - "version": "4.2.3", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, "temp-dir": { "version": "2.0.0", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "dev": true - }, - "tslib": { - "version": "2.1.0", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", "dev": true } } }, "yocto-queue": { - "version": "0.1.0", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + "version": "0.1.0" }, "yosay": { "version": "2.0.2", - "integrity": "sha512-avX6nz2esp7IMXGag4gu6OyQBsMh/SEn+ZybGu3yKPlOTE6z9qJrzG/0X5vCq/e0rPFy0CUYCze0G5hL310ibA==", "requires": { "ansi-regex": "^2.0.0", "ansi-styles": "^3.0.0", @@ -84554,14 +86211,12 @@ "dependencies": { "ansi-styles": { "version": "3.2.1", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { "color-convert": "^1.9.0" } }, "chalk": { "version": "1.1.3", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -84571,29 +86226,24 @@ }, "dependencies": { "ansi-styles": { - "version": "2.2.1", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==" + "version": "2.2.1" } } }, "cli-boxes": { - "version": "1.0.0", - "integrity": "sha512-3Fo5wu8Ytle8q9iCzS4D2MWVL2X7JVWRiS1BnXbTFDhS9c/REkM9vd1AmabsoZoY5/dGi5TT9iKL8Kb6DeBRQg==" + "version": "1.0.0" }, "is-fullwidth-code-point": { "version": "1.0.0", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "requires": { "number-is-nan": "^1.0.0" } }, "supports-color": { - "version": "2.0.0", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==" + "version": "2.0.0" }, "wrap-ansi": { "version": "2.1.0", - "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" @@ -84601,7 +86251,6 @@ "dependencies": { "string-width": { "version": "1.0.2", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -84613,21 +86262,18 @@ } }, "zrender": { - "version": "5.3.1", - "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==", + "version": "5.4.1", "requires": { "tslib": "2.3.0" }, "dependencies": { "tslib": { - "version": "2.3.0", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + "version": "2.3.0" } } }, "zwitch": { - "version": "1.0.5", - "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==" + "version": "1.0.5" } } } diff --git a/superset-frontend/package.json b/superset-frontend/package.json index aae61e9040850..b058068dfb607 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -1,6 +1,6 @@ { "name": "superset", - "version": "2.0.1", + "version": "2.1.0", "description": "Superset is a data exploration platform designed to be visual, intuitive, and interactive.", "keywords": [ "big", @@ -23,7 +23,9 @@ "url": "git+https://github.com/apache/superset.git" }, "license": "Apache-2.0", - "author": "Apache", + "author": { + "name": "Apache" + }, "directories": { "doc": "docs", "test": "spec" @@ -40,7 +42,9 @@ "build-instrumented": "cross-env NODE_ENV=production BABEL_ENV=instrumented webpack --mode=production --color", "build-storybook": "build-storybook", "check-translation": "prettier --check ../superset/translations/**/LC_MESSAGES/*.json", + "chromatic": "npx chromatic --skip 'dependabot/**' --only-changed", "clean-translation": "prettier --write ../superset/translations/**/LC_MESSAGES/*.json", + "core:cover": "cross-env NODE_ENV=test jest --coverage --coverageThreshold='{\"global\":{\"statements\":100,\"branches\":100,\"functions\":100,\"lines\":100}}' --collectCoverageFrom='[\"packages/**/src/**/*.{js,ts}\", \"!packages/superset-ui-demo/**/*\"]' packages", "cover": "cross-env NODE_ENV=test jest --coverage", "dev": "webpack --mode=development --color --watch", "dev-server": "cross-env NODE_ENV=development BABEL_ENV=development node --max_old_space_size=4096 ./node_modules/webpack-dev-server/bin/webpack-dev-server.js --mode=development", @@ -75,7 +79,7 @@ "dependencies": { "@ag-grid-community/react": "^26.0.0", "@ag-grid-enterprise/all-modules": "^26.0.0", - "@ant-design/icons": "^4.2.2", + "@ant-design/icons": "^4.8.0", "@babel/runtime-corejs3": "^7.12.5", "@data-ui/sparkline": "^0.0.84", "@emotion/babel-preset-css-prop": "^11.2.0", @@ -112,10 +116,10 @@ "@superset-ui/plugin-chart-word-cloud": "file:./plugins/plugin-chart-word-cloud", "@superset-ui/preset-chart-xy": "file:./plugins/preset-chart-xy", "@superset-ui/switchboard": "file:./packages/superset-ui-switchboard", - "@vx/responsive": "^0.0.195", + "@visx/responsive": "^3.0.0", "abortcontroller-polyfill": "^1.1.9", "ace-builds": "^1.4.14", - "antd": "^4.9.4", + "antd": "4.10.3", "array-move": "^2.2.1", "babel-plugin-typescript-to-proptypes": "^2.0.0", "bootstrap": "^3.4.1", @@ -125,6 +129,7 @@ "chrono-node": "^2.2.6", "classnames": "^2.2.5", "core-js": "^3.6.5", + "currencyformatter.js": "^2.2.0", "d3-array": "^1.2.4", "d3-color": "^1.2.0", "d3-scale": "^2.1.2", @@ -138,7 +143,7 @@ "global-box": "^1.2.0", "html-webpack-plugin": "^5.3.2", "immer": "^9.0.6", - "interweave": "^11.2.0", + "interweave": "^13.0.0", "jquery": "^3.5.1", "js-levenshtein": "^1.1.6", "js-yaml-loader": "^1.2.2", @@ -146,11 +151,11 @@ "json-stringify-pretty-compact": "^2.0.0", "lodash": "^4.17.21", "lodash-es": "^4.17.21", - "mapbox-gl": "^2.8.2", + "mapbox-gl": "^2.10.0", "match-sorter": "^6.1.0", "memoize-one": "^5.1.1", "moment": "^2.26.0", - "moment-timezone": "^0.5.33", + "moment-timezone": "^0.5.37", "mousetrap": "^1.6.1", "mustache": "^2.2.1", "polished": "^3.7.2", @@ -158,39 +163,39 @@ "query-string": "^6.13.7", "re-resizable": "^6.6.1", "react": "^16.13.1", - "react-ace": "^9.4.4", - "react-checkbox-tree": "^1.5.1", + "react-ace": "^10.1.0", + "react-checkbox-tree": "^1.8.0", "react-color": "^2.13.8", - "react-datetime": "^3.0.4", + "react-datetime": "^3.2.0", + "react-diff-viewer-continued": "^3.2.5", "react-dnd": "^11.1.3", "react-dnd-html5-backend": "^11.1.3", "react-dom": "^16.13.0", "react-draggable": "^4.4.3", "react-gravatar": "^2.6.1", - "react-hot-loader": "^4.12.20", - "react-icons": "^4.2.0", + "react-hot-loader": "^4.13.1", + "react-intersection-observer": "^9.4.1", "react-js-cron": "^1.2.0", - "react-json-tree": "^0.11.2", - "react-jsonschema-form": "^1.2.0", + "react-json-tree": "^0.17.0", + "react-jsonschema-form": "^1.8.1", "react-lines-ellipsis": "^0.15.0", "react-loadable": "^5.5.0", - "react-redux": "^7.2.0", - "react-resize-detector": "^6.7.6", - "react-reverse-portal": "^2.0.1", - "react-router-dom": "^5.1.2", + "react-query": "^3.39.2", + "react-redux": "^7.2.8", + "react-resize-detector": "^7.1.2", + "react-reverse-portal": "^2.1.1", + "react-router-dom": "^5.3.4", "react-search-input": "^0.11.3", - "react-select": "^3.1.0", - "react-sortable-hoc": "^1.11.0", + "react-select": "^3.2.0", + "react-sortable-hoc": "^2.0.0", "react-split": "^2.0.9", - "react-sticky": "^6.0.3", "react-syntax-highlighter": "^15.4.5", - "react-table": "^7.6.3", + "react-table": "^7.8.0", "react-transition-group": "^2.5.3", - "react-ultimate-pagination": "^1.2.0", + "react-ultimate-pagination": "^1.3.0", "react-virtualized": "9.19.1", - "react-virtualized-auto-sizer": "^1.0.2", - "react-virtualized-select": "^3.1.3", - "react-window": "^1.8.5", + "react-virtualized-auto-sizer": "^1.0.7", + "react-window": "^1.8.8", "redux": "^4.0.5", "redux-localstorage": "^0.4.1", "redux-thunk": "^2.1.0", @@ -202,30 +207,31 @@ "shortid": "^2.2.6", "tinycolor2": "^1.4.2", "urijs": "^1.19.8", - "use-immer": "^0.6.0", + "use-immer": "^0.8.1", "use-query-params": "^1.1.9", "yargs": "^15.4.1" }, "devDependencies": { - "@applitools/eyes-storybook": "^3.27.6", "@ag-grid-community/react": "^26.0.0", "@ag-grid-enterprise/all-modules": "^26.0.0", - "@babel/cli": "^7.16.0", - "@babel/compat-data": "^7.15.0", - "@babel/core": "^7.15.5", - "@babel/eslint-parser": "^7.15.7", - "@babel/node": "^7.15.4", - "@babel/plugin-proposal-class-properties": "^7.14.5", - "@babel/plugin-proposal-optional-chaining": "^7.14.5", + "@applitools/eyes-storybook": "^3.30.1", + "@babel/cli": "^7.18.10", + "@babel/compat-data": "^7.18.8", + "@babel/core": "^7.18.10", + "@babel/eslint-parser": "^7.18.9", + "@babel/node": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.15.0", - "@babel/preset-env": "^7.15.6", - "@babel/preset-react": "^7.14.5", - "@babel/register": "^7.15.3", + "@babel/plugin-transform-runtime": "^7.18.10", + "@babel/preset-env": "^7.18.10", + "@babel/preset-react": "^7.18.6", + "@babel/register": "^7.18.9", "@emotion/jest": "^11.3.0", "@hot-loader/react-dom": "^16.13.0", "@istanbuljs/nyc-config-typescript": "^1.0.1", "@storybook/addon-actions": "^6.4.22", + "@storybook/addon-docs": "^6.5.10", "@storybook/addon-essentials": "^6.4.22", "@storybook/addon-knobs": "^6.3.1", "@storybook/addon-links": "^6.4.22", @@ -247,7 +253,7 @@ "@types/jest": "^26.0.3", "@types/jquery": "^3.5.8", "@types/js-levenshtein": "^1.1.0", - "@types/json-bigint": "^1.0.0", + "@types/json-bigint": "^1.0.1", "@types/react": "^16.9.43", "@types/react-dom": "^16.9.8", "@types/react-gravatar": "^2.6.8", @@ -255,13 +261,12 @@ "@types/react-jsonschema-form": "^1.7.4", "@types/react-loadable": "^5.5.6", "@types/react-redux": "^7.1.10", - "@types/react-router-dom": "^5.1.5", + "@types/react-router-dom": "^5.3.3", "@types/react-select": "^3.0.19", - "@types/react-sticky": "^6.0.3", "@types/react-table": "^7.0.19", "@types/react-ultimate-pagination": "^1.2.0", "@types/react-virtualized": "^9.21.10", - "@types/react-window": "^1.8.2", + "@types/react-window": "^1.8.5", "@types/redux-localstorage": "^1.0.8", "@types/redux-mock-store": "^1.0.2", "@types/rison": "0.0.6", @@ -276,12 +281,13 @@ "babel-plugin-dynamic-import-node": "^2.3.3", "babel-plugin-jsx-remove-data-test-id": "^2.1.3", "babel-plugin-lodash": "^3.3.4", + "chromatic": "^6.7.4", "copy-webpack-plugin": "^9.0.1", "cross-env": "^5.2.0", "css-loader": "^6.2.0", "css-minimizer-webpack-plugin": "^3.0.2", - "enzyme": "^3.10.0", - "enzyme-adapter-react-16": "^1.14.0", + "enzyme": "^3.11.0", + "enzyme-adapter-react-16": "^1.15.7", "eslint": "^7.32.0", "eslint-config-airbnb": "^18.2.1", "eslint-config-prettier": "^7.1.0", @@ -302,14 +308,15 @@ "exports-loader": "^0.7.0", "fetch-mock": "^7.7.3", "fork-ts-checker-webpack-plugin": "^6.3.3", + "history": "^4.10.1", "ignore-styles": "^5.0.1", "imports-loader": "^3.0.0", "jest": "^26.6.3", "jest-environment-enzyme": "^7.1.2", "jest-enzyme": "^7.1.2", "jest-websocket-mock": "^2.2.0", - "jsdom": "^16.4.0", - "lerna": "^4.0.0", + "jsdom": "^20.0.0", + "lerna": "^6.1.0", "less": "^3.12.2", "less-loader": "^10.2.0", "mini-css-extract-plugin": "^2.3.0", @@ -335,12 +342,14 @@ "webpack": "^5.52.1", "webpack-bundle-analyzer": "^4.4.2", "webpack-cli": "^4.8.0", - "webpack-dev-server": "^4.2.0", + "webpack-dev-server": "^4.10.1", "webpack-manifest-plugin": "^4.0.2", "webpack-sources": "^3.2.0" }, "engines": { "node": "^16.9.1", "npm": "^7.5.4 || ^8.1.2" - } + }, + "readme": "ERROR: No README data found!", + "_id": "superset@0.0.0-dev" } diff --git a/superset-frontend/packages/generator-superset/generators/plugin-chart/templates/src/MyChart.erb b/superset-frontend/packages/generator-superset/generators/plugin-chart/templates/src/MyChart.erb index 63e400b3746f8..1b9a2b4a9df38 100644 --- a/superset-frontend/packages/generator-superset/generators/plugin-chart/templates/src/MyChart.erb +++ b/superset-frontend/packages/generator-superset/generators/plugin-chart/templates/src/MyChart.erb @@ -64,7 +64,7 @@ export default function <%= packageLabel %>(props: <%= packageLabel %>Props) { const rootElem = createRef<HTMLDivElement>(); - // Often, you just want to get a hold of the DOM and go nuts. + // Often, you just want to access the DOM and do whatever you want. // Here, you can do that with createRef, and the useEffect hook. useEffect(() => { const root = rootElem.current as HTMLElement; diff --git a/superset-frontend/packages/generator-superset/generators/plugin-chart/templates/src/plugin/controlPanel.erb b/superset-frontend/packages/generator-superset/generators/plugin-chart/templates/src/plugin/controlPanel.erb index 92e644a2ab523..998e68b685899 100644 --- a/superset-frontend/packages/generator-superset/generators/plugin-chart/templates/src/plugin/controlPanel.erb +++ b/superset-frontend/packages/generator-superset/generators/plugin-chart/templates/src/plugin/controlPanel.erb @@ -30,7 +30,7 @@ const config: ControlPanelConfig = { * * There are several predefined controls that can be used. * Some examples: - * - groupby: columns to group by (tranlated to GROUP BY statement) + * - groupby: columns to group by (translated to GROUP BY statement) * - series: same as groupby, but single selection. * - metrics: multiple metrics (translated to aggregate expression) * - metric: sane as metrics, but single selection @@ -91,7 +91,7 @@ const config: ControlPanelConfig = { * by the `@superset-ui/core/lib/validator`: * - validateNonEmpty: must have at least one value * - validateInteger: must be an integer value - * - validateNumber: must be an intger or decimal value + * - validateNumber: must be an integer or decimal value */ // For control input types, see: superset-frontend/src/explore/components/controls/index.js diff --git a/superset-frontend/packages/generator-superset/package.json b/superset-frontend/packages/generator-superset/package.json index 2011a1b22e863..36a622f3f939f 100644 --- a/superset-frontend/packages/generator-superset/package.json +++ b/superset-frontend/packages/generator-superset/package.json @@ -2,40 +2,40 @@ "name": "@superset-ui/generator-superset", "version": "0.18.25", "description": "Scaffolder for Superset", + "keywords": [ + "yeoman", + "generator", + "superset", + "yeoman-generator" + ], + "homepage": "https://github.com/apache/superset#readme", "bugs": { - "url": "https://github.com/apache-superset/superset-ui/issues" + "url": "https://github.com/apache/superset/issues" }, - "homepage": "https://github.com/apache-superset/superset-ui#readme", "repository": { "type": "git", - "url": "git+https://github.com/apache-superset/superset-ui.git" + "url": "git+https://github.com/apache/superset.git" }, + "license": "Apache-2.0", "author": "Superset", + "main": "generators/index.js", "files": [ "generators" ], - "main": "generators/index.js", - "keywords": [ - "yeoman", - "generator", - "superset", - "yeoman-generator" - ], + "dependencies": { + "chalk": "^4.0.0", + "lodash": "^4.17.11", + "yeoman-generator": "^5.7.0", + "yosay": "^2.0.2" + }, "devDependencies": { + "fs-extra": "^10.0.0", "yeoman-assert": "^3.1.0", - "yeoman-test": "^6.2.0", - "fs-extra": "^10.0.0" + "yeoman-test": "^6.2.0" }, "engines": { "npm": ">= 4.0.0" }, - "dependencies": { - "chalk": "^4.0.0", - "lodash": "^4.17.11", - "yeoman-generator": "^4.0.0", - "yosay": "^2.0.2" - }, - "license": "Apache-2.0", "publishConfig": { "access": "public" } diff --git a/superset-frontend/packages/superset-ui-chart-controls/package.json b/superset-frontend/packages/superset-ui-chart-controls/package.json index 93019ad457f50..4773f8c078cbe 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/package.json +++ b/superset-frontend/packages/superset-ui-chart-controls/package.json @@ -39,11 +39,11 @@ "@testing-library/react-hooks": "^5.0.3", "@testing-library/user-event": "^12.7.0", "ace-builds": "^1.4.14", - "antd": "^4.9.4", + "antd": "4.10.3", "brace": "^0.11.1", "memoize-one": "^5.1.1", "react": "^16.13.1", - "react-ace": "^9.4.4", + "react-ace": "^10.1.0", "react-dom": "^16.13.1" }, "publishConfig": { diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx index c132b0918d694..649aeaf3dc724 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx @@ -54,11 +54,7 @@ const TooltipSection = ({ ); export const isLabelTruncated = (labelRef?: React.RefObject<any>): boolean => - !!( - labelRef && - labelRef.current && - labelRef.current.scrollWidth > labelRef.current.clientWidth - ); + !!(labelRef?.current?.scrollWidth > labelRef?.current?.clientWidth); export const getColumnLabelText = (column: ColumnMeta): string => column.verbose_name || column.column_name; @@ -68,7 +64,7 @@ export const getColumnTooltipNode = ( labelRef?: React.RefObject<any>, ): ReactNode => { if ( - !column.verbose_name && + (!column.column_name || !column.verbose_name) && !column.description && !isLabelTruncated(labelRef) ) { @@ -77,7 +73,9 @@ export const getColumnTooltipNode = ( return ( <> - <TooltipSection label={t('Column name')} text={column.column_name} /> + {column.column_name && ( + <TooltipSection label={t('Column name')} text={column.column_name} /> + )} {column.verbose_name && ( <TooltipSection label={t('Label')} text={column.verbose_name} /> )} diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts b/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts index 265874f5e6661..f410c4479a35b 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts @@ -31,7 +31,6 @@ export const TIME_FILTER_LABELS = { time_range: t('Time Range'), granularity_sqla: t('Time Column'), time_grain_sqla: t('Time Grain'), - druid_time_origin: t('Origin'), granularity: t('Time Granularity'), }; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/fixtures.ts b/superset-frontend/packages/superset-ui-chart-controls/src/fixtures.ts new file mode 100644 index 0000000000000..71c4dd31189ba --- /dev/null +++ b/superset-frontend/packages/superset-ui-chart-controls/src/fixtures.ts @@ -0,0 +1,149 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { DatasourceType } from '@superset-ui/core'; +import { Dataset } from './types'; + +export const TestDataset: Dataset = { + column_format: {}, + columns: [ + { + advanced_data_type: undefined, + certification_details: null, + certified_by: null, + column_name: 'num', + description: null, + expression: '', + filterable: true, + groupby: true, + id: 332, + is_certified: false, + is_dttm: false, + python_date_format: null, + type: 'BIGINT', + type_generic: 0, + verbose_name: null, + warning_markdown: null, + }, + { + advanced_data_type: undefined, + certification_details: null, + certified_by: null, + column_name: 'gender', + description: null, + expression: '', + filterable: true, + groupby: true, + id: 330, + is_certified: false, + is_dttm: false, + python_date_format: null, + type: 'VARCHAR(16)', + type_generic: 1, + verbose_name: '', + warning_markdown: null, + }, + { + advanced_data_type: undefined, + certification_details: null, + certified_by: null, + column_name: 'state', + description: null, + expression: '', + filterable: true, + groupby: true, + id: 333, + is_certified: false, + is_dttm: false, + python_date_format: null, + type: 'VARCHAR(10)', + type_generic: 1, + verbose_name: null, + warning_markdown: null, + }, + { + advanced_data_type: undefined, + certification_details: null, + certified_by: null, + column_name: 'ds', + description: null, + expression: '', + filterable: true, + groupby: true, + id: 329, + is_certified: false, + is_dttm: true, + python_date_format: null, + type: 'TIMESTAMP WITHOUT TIME ZONE', + type_generic: 2, + verbose_name: null, + warning_markdown: null, + }, + { + advanced_data_type: undefined, + certification_details: null, + certified_by: null, + column_name: 'name', + description: null, + expression: '', + filterable: true, + groupby: true, + id: 331, + is_certified: false, + is_dttm: false, + python_date_format: null, + type: 'VARCHAR(255)', + type_generic: 1, + verbose_name: null, + warning_markdown: null, + }, + ], + datasource_name: 'birth_names', + description: null, + granularity_sqla: 'ds', + id: 2, + main_dttm_col: 'ds', + metrics: [ + { + certification_details: null, + certified_by: null, + d3format: null, + description: null, + expression: 'COUNT(*)', + id: 7, + is_certified: false, + metric_name: 'count', + verbose_name: 'COUNT(*)', + warning_markdown: '', + warning_text: null, + }, + ], + name: 'public.birth_names', + order_by_choices: [], + owners: [ + { + first_name: 'admin', + id: 1, + last_name: 'user', + username: 'admin', + }, + ], + type: DatasourceType.Dataset, + uid: '2__table', + verbose_map: {}, +}; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/index.ts b/superset-frontend/packages/superset-ui-chart-controls/src/index.ts index 8a151d10e2a4f..7c57a3e1709ad 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/index.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/index.ts @@ -30,14 +30,6 @@ export * from './components/ColumnOption'; export * from './components/ColumnTypeLabel/ColumnTypeLabel'; export * from './components/MetricOption'; -// React control components -export { - sharedControls, - dndEntity, - dndColumnsControl, -} from './shared-controls'; -export { default as sharedControlComponents } from './shared-controls/components'; -export { legacySortBy } from './shared-controls/legacySortBy'; -export * from './shared-controls/emitFilterControl'; -export * from './shared-controls/components'; +export * from './shared-controls'; export * from './types'; +export * from './fixtures'; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/pivotOperator.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/pivotOperator.ts index f8e9f025b0b69..3adec29fecec5 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/pivotOperator.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/pivotOperator.ts @@ -17,11 +17,11 @@ * under the License. */ import { - DTTM_ALIAS, ensureIsArray, getColumnLabel, getMetricLabel, PostProcessingPivot, + getXAxisLabel, } from '@superset-ui/core'; import { PostProcessingFactory } from './types'; @@ -30,23 +30,21 @@ export const pivotOperator: PostProcessingFactory<PostProcessingPivot> = ( queryObject, ) => { const metricLabels = ensureIsArray(queryObject.metrics).map(getMetricLabel); - const { x_axis: xAxis } = formData; + const xAxisLabel = getXAxisLabel(formData); + const columns = queryObject.series_columns || queryObject.columns; - if ((xAxis || queryObject.is_timeseries) && metricLabels.length) { - const index = [getColumnLabel(xAxis || DTTM_ALIAS)]; + if (xAxisLabel && metricLabels.length) { return { operation: 'pivot', options: { - index, - columns: ensureIsArray(queryObject.columns).map(getColumnLabel), + index: [xAxisLabel], + columns: ensureIsArray(columns).map(getColumnLabel), // Create 'dummy' mean aggregates to assign cell values in pivot table // use the 'mean' aggregates to avoid drop NaN. PR: https://github.com/apache-superset/superset-ui/pull/1231 aggregates: Object.fromEntries( metricLabels.map(metric => [metric, { operator: 'mean' }]), ), - drop_missing_columns: false, - flatten_columns: false, - reset_index: false, + drop_missing_columns: !formData?.show_empty_columns, }, }; } diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/prophetOperator.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/prophetOperator.ts index ff0fa0fb6544c..269dc1e80169a 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/prophetOperator.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/prophetOperator.ts @@ -16,11 +16,7 @@ * specific language governing permissions and limitationsxw * under the License. */ -import { - DTTM_ALIAS, - getColumnLabel, - PostProcessingProphet, -} from '@superset-ui/core'; +import { PostProcessingProphet, getXAxisLabel } from '@superset-ui/core'; import { PostProcessingFactory } from './types'; /* eslint-disable @typescript-eslint/no-unused-vars */ @@ -28,8 +24,8 @@ export const prophetOperator: PostProcessingFactory<PostProcessingProphet> = ( formData, queryObject, ) => { - const index = getColumnLabel(formData.x_axis || DTTM_ALIAS); - if (formData.forecastEnabled) { + const xAxisLabel = getXAxisLabel(formData); + if (formData.forecastEnabled && xAxisLabel) { return { operation: 'prophet', options: { @@ -39,7 +35,7 @@ export const prophetOperator: PostProcessingFactory<PostProcessingProphet> = ( yearly_seasonality: formData.forecastSeasonalityYearly, weekly_seasonality: formData.forecastSeasonalityWeekly, daily_seasonality: formData.forecastSeasonalityDaily, - index, + index: xAxisLabel, }, }; } diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/renameOperator.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/renameOperator.ts index 84cbbce8c5fdb..04f3b7ac327fd 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/renameOperator.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/renameOperator.ts @@ -21,7 +21,8 @@ import { PostProcessingRename, ensureIsArray, getMetricLabel, - ComparisionType, + ComparisonType, + getXAxisLabel, } from '@superset-ui/core'; import { PostProcessingFactory } from './types'; import { getMetricOffsetsMap, isTimeComparison } from './utils'; @@ -31,26 +32,29 @@ export const renameOperator: PostProcessingFactory<PostProcessingRename> = ( queryObject, ) => { const metrics = ensureIsArray(queryObject.metrics); - const columns = ensureIsArray(queryObject.columns); - const { x_axis: xAxis, truncate_metric } = formData; + const columns = ensureIsArray( + queryObject.series_columns || queryObject.columns, + ); + const { truncate_metric } = formData; + const xAxisLabel = getXAxisLabel(formData); // remove or rename top level of column name(metric name) in the MultiIndex when // 1) only 1 metric - // 2) exist dimentsion - // 3) exist xAxis - // 4) exist time comparison, and comparison type is "actual values" + // 2) dimension exist + // 3) xAxis exist + // 4) time comparison exist, and comparison type is "actual values" // 5) truncate_metric in form_data and truncate_metric is true if ( metrics.length === 1 && columns.length > 0 && - (xAxis || queryObject.is_timeseries) && + xAxisLabel && !( // todo: we should provide an approach to handle derived metrics ( isTimeComparison(formData, queryObject) && [ - ComparisionType.Difference, - ComparisionType.Ratio, - ComparisionType.Percentage, + ComparisonType.Difference, + ComparisonType.Ratio, + ComparisonType.Percentage, ].includes(formData.comparison_type) ) ) && @@ -64,7 +68,7 @@ export const renameOperator: PostProcessingFactory<PostProcessingRename> = ( // we will rename the "metric" from the metricWithOffset label // for example: "count__1 year ago" => "1 year ago" isTimeComparison(formData, queryObject) && - formData.comparison_type === ComparisionType.Values + formData.comparison_type === ComparisonType.Values ) { const metricOffsetMap = getMetricOffsetsMap(formData, queryObject); const timeOffsets = ensureIsArray(formData.time_compare); diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/sortOperator.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/sortOperator.ts index 277d2df559ced..0650c8b577851 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/sortOperator.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/sortOperator.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -17,25 +16,50 @@ * specific language governing permissions and limitationsxw * under the License. */ -import { DTTM_ALIAS, PostProcessingSort, RollingType } from '@superset-ui/core'; +import { isEmpty } from 'lodash'; +import { + ensureIsArray, + getMetricLabel, + getXAxisLabel, + hasGenericChartAxes, + isDefined, + PostProcessingSort, +} from '@superset-ui/core'; import { PostProcessingFactory } from './types'; export const sortOperator: PostProcessingFactory<PostProcessingSort> = ( formData, queryObject, ) => { - const { x_axis: xAxis } = formData; + // the sortOperator only used in the barchart v2 + const sortableLabels = [ + getXAxisLabel(formData), + ...ensureIsArray(formData.metrics).map(metric => getMetricLabel(metric)), + ].filter(Boolean); + if ( - (xAxis || queryObject.is_timeseries) && - Object.values(RollingType).includes(formData.rolling_type) + hasGenericChartAxes && + isDefined(formData?.x_axis_sort) && + isDefined(formData?.x_axis_sort_asc) && + sortableLabels.includes(formData.x_axis_sort) && + // the sort operator doesn't support sort-by multiple series. + isEmpty(formData.groupby) ) { - const index = xAxis || DTTM_ALIAS; + if (formData.x_axis_sort === getXAxisLabel(formData)) { + return { + operation: 'sort', + options: { + is_sort_index: true, + ascending: formData.x_axis_sort_asc, + }, + }; + } + return { operation: 'sort', options: { - columns: { - [index]: true, - }, + by: formData.x_axis_sort, + ascending: formData.x_axis_sort_asc, }, }; } diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeCompareOperator.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeCompareOperator.ts index 3fe253edfdfd1..da72c664c9a4c 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeCompareOperator.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeCompareOperator.ts @@ -17,7 +17,7 @@ * specific language governing permissions and limitationsxw * under the License. */ -import { ComparisionType, PostProcessingCompare } from '@superset-ui/core'; +import { ComparisonType, PostProcessingCompare } from '@superset-ui/core'; import { getMetricOffsetsMap, isTimeComparison } from './utils'; import { PostProcessingFactory } from './types'; @@ -28,7 +28,7 @@ export const timeCompareOperator: PostProcessingFactory<PostProcessingCompare> = if ( isTimeComparison(formData, queryObject) && - comparisonType !== ComparisionType.Values + comparisonType !== ComparisonType.Values ) { return { operation: 'compare', diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeComparePivotOperator.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeComparePivotOperator.ts index 3851d62a36350..a6214901aa074 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeComparePivotOperator.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeComparePivotOperator.ts @@ -18,11 +18,11 @@ * under the License. */ import { - DTTM_ALIAS, ensureIsArray, getColumnLabel, NumpyFunction, PostProcessingPivot, + getXAxisLabel, } from '@superset-ui/core'; import { getMetricOffsetsMap, isTimeComparison } from './utils'; import { PostProcessingFactory } from './types'; @@ -30,8 +30,10 @@ import { PostProcessingFactory } from './types'; export const timeComparePivotOperator: PostProcessingFactory<PostProcessingPivot> = (formData, queryObject) => { const metricOffsetMap = getMetricOffsetsMap(formData, queryObject); + const xAxisLabel = getXAxisLabel(formData); + const columns = queryObject.series_columns || queryObject.columns; - if (isTimeComparison(formData, queryObject)) { + if (isTimeComparison(formData, queryObject) && xAxisLabel) { const aggregates = Object.fromEntries( [...metricOffsetMap.values(), ...metricOffsetMap.keys()].map(metric => [ metric, @@ -39,16 +41,13 @@ export const timeComparePivotOperator: PostProcessingFactory<PostProcessingPivot { operator: 'mean' as NumpyFunction }, ]), ); - const index = [getColumnLabel(formData.x_axis || DTTM_ALIAS)]; return { operation: 'pivot', options: { - index, - columns: ensureIsArray(queryObject.columns).map(getColumnLabel), - drop_missing_columns: false, - flatten_columns: false, - reset_index: false, + index: [xAxisLabel], + columns: ensureIsArray(columns).map(getColumnLabel), + drop_missing_columns: !formData?.show_empty_columns, aggregates, }, }; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/utils/isDerivedSeries.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/utils/isDerivedSeries.ts index 24623e5570f38..67815756f842b 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/utils/isDerivedSeries.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/utils/isDerivedSeries.ts @@ -21,7 +21,7 @@ import { ensureIsArray, JsonObject, QueryFormData, - ComparisionType, + ComparisonType, } from '@superset-ui/core'; import { isString } from 'lodash'; @@ -30,7 +30,7 @@ export const isDerivedSeries = ( formData: QueryFormData, ): boolean => { const comparisonType = formData.comparison_type; - if (comparisonType !== ComparisionType.Values) { + if (comparisonType !== ComparisonType.Values) { return false; } diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/utils/isTimeComparison.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/utils/isTimeComparison.ts index 4430b9541cdbb..674e26333e41f 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/utils/isTimeComparison.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/utils/isTimeComparison.ts @@ -17,7 +17,7 @@ * specific language governing permissions and limitationsxw * under the License. */ -import { ComparisionType } from '@superset-ui/core'; +import { ComparisonType } from '@superset-ui/core'; import { getMetricOffsetsMap } from './getMetricOffsetsMap'; import { PostProcessingFactory } from '../types'; @@ -29,7 +29,7 @@ export const isTimeComparison: PostProcessingFactory<boolean> = ( const metricOffsetMap = getMetricOffsetsMap(formData, queryObject); return ( - Object.values(ComparisionType).includes(comparisonType) && + Object.values(ComparisonType).includes(comparisonType) && metricOffsetMap.size > 0 ); }; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx index 1ed664b7de62a..f17139cf1051c 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx @@ -17,7 +17,7 @@ * under the License. */ import React from 'react'; -import { t, RollingType, ComparisionType } from '@superset-ui/core'; +import { t, RollingType, ComparisonType } from '@superset-ui/core'; import { ControlPanelSectionConfig } from '../types'; import { formatSelectOptions } from '../utils'; @@ -108,18 +108,18 @@ export const advancedAnalyticsControls: ControlPanelSectionConfig = { multi: true, freeForm: true, label: t('Time shift'), - choices: formatSelectOptions([ - '1 day ago', - '1 week ago', - '28 days ago', - '30 days ago', - '52 weeks ago', - '1 year ago', - '104 weeks ago', - '2 years ago', - '156 weeks ago', - '3 years ago', - ]), + choices: [ + ['1 day ago', t('1 day ago')], + ['1 week ago', t('1 week ago')], + ['28 days ago', t('28 days ago')], + ['30 days ago', t('30 days ago')], + ['52 weeks ago', t('52 weeks ago')], + ['1 year ago', t('1 year ago')], + ['104 weeks ago', t('104 weeks ago')], + ['2 years ago', t('2 years ago')], + ['156 weeks ago', t('156 weeks ago')], + ['3 years ago', t('3 years ago')], + ], description: t( 'Overlay one or more timeseries from a ' + 'relative time period. Expects relative time deltas ' + @@ -137,10 +137,10 @@ export const advancedAnalyticsControls: ControlPanelSectionConfig = { label: t('Calculation type'), default: 'values', choices: [ - [ComparisionType.Values, 'Actual values'], - [ComparisionType.Difference, 'Difference'], - [ComparisionType.Percentage, 'Percentage change'], - [ComparisionType.Ratio, 'Ratio'], + [ComparisonType.Values, t('Actual values')], + [ComparisonType.Difference, t('Difference')], + [ComparisonType.Percentage, t('Percentage change')], + [ComparisonType.Ratio, t('Ratio')], ], description: t( 'How to display time shifts: as individual lines; as the ' + @@ -160,14 +160,14 @@ export const advancedAnalyticsControls: ControlPanelSectionConfig = { label: t('Rule'), default: null, choices: [ - ['1T', '1 minutely frequency'], - ['1H', '1 hourly frequency'], - ['1D', '1 calendar day frequency'], - ['7D', '7 calendar day frequency'], - ['1MS', '1 month start frequency'], - ['1M', '1 month end frequency'], - ['1AS', '1 year start frequency'], - ['1A', '1 year end frequency'], + ['1T', t('1 minutely frequency')], + ['1H', t('1 hourly frequency')], + ['1D', t('1 calendar day frequency')], + ['7D', t('7 calendar day frequency')], + ['1MS', t('1 month start frequency')], + ['1M', t('1 month end frequency')], + ['1AS', t('1 year start frequency')], + ['1A', t('1 year end frequency')], ], description: t('Pandas resample rule'), }, @@ -178,18 +178,17 @@ export const advancedAnalyticsControls: ControlPanelSectionConfig = { name: 'resample_method', config: { type: 'SelectControl', - freeForm: true, label: t('Fill method'), default: null, choices: [ - ['asfreq', 'Null imputation'], - ['zerofill', 'Zero imputation'], - ['linear', 'Linear interpolation'], - ['ffill', 'Forward values'], - ['bfill', 'Backward values'], - ['median', 'Median values'], - ['mean', 'Mean values'], - ['sum', 'Sum values'], + ['asfreq', t('Null imputation')], + ['zerofill', t('Zero imputation')], + ['linear', t('Linear interpolation')], + ['ffill', t('Forward values')], + ['bfill', t('Backward values')], + ['median', t('Median values')], + ['mean', t('Mean values')], + ['sum', t('Sum values')], ], description: t('Pandas resample method'), }, diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx index eda3ac33152d4..5e010c27e2f5d 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx @@ -24,7 +24,10 @@ import { formatSelectOptions } from '../utils'; export const TITLE_MARGIN_OPTIONS: number[] = [ 15, 30, 50, 75, 100, 125, 150, 200, ]; -export const TITLE_POSITION_OPTIONS: string[] = ['Left', 'Top']; +export const TITLE_POSITION_OPTIONS: [string, string][] = [ + ['Left', t('Left')], + ['Top', t('Top')], +]; export const titleControls: ControlPanelSectionConfig = { label: t('Chart Title'), tabOverride: 'customize', @@ -95,8 +98,8 @@ export const titleControls: ControlPanelSectionConfig = { clearable: false, label: t('Y AXIS TITLE POSITION'), renderTrigger: true, - default: TITLE_POSITION_OPTIONS[0], - choices: formatSelectOptions(TITLE_POSITION_OPTIONS), + default: TITLE_POSITION_OPTIONS[0][0], + choices: TITLE_POSITION_OPTIONS, description: t('Changing this control takes effect instantly'), }, }, diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/sections/echartsTimeSeriesQuery.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/sections/echartsTimeSeriesQuery.tsx new file mode 100644 index 0000000000000..cd58780d892d2 --- /dev/null +++ b/superset-frontend/packages/superset-ui-chart-controls/src/sections/echartsTimeSeriesQuery.tsx @@ -0,0 +1,60 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { hasGenericChartAxes, t } from '@superset-ui/core'; +import { ControlPanelSectionConfig, ControlSetRow } from '../types'; +import { + contributionModeControl, + xAxisSortControl, + xAxisSortAscControl, +} from '../shared-controls'; + +const controlsWithoutXAxis: ControlSetRow[] = [ + ['metrics'], + ['groupby'], + [contributionModeControl], + ['adhoc_filters'], + ['limit'], + ['timeseries_limit_metric'], + ['order_desc'], + ['row_limit'], + ['truncate_metric'], + ['show_empty_columns'], +]; + +export const echartsTimeSeriesQuery: ControlPanelSectionConfig = { + label: t('Query'), + expanded: true, + controlSetRows: [ + [hasGenericChartAxes ? 'x_axis' : null], + [hasGenericChartAxes ? 'time_grain_sqla' : null], + ...controlsWithoutXAxis, + ], +}; + +export const echartsTimeSeriesQueryWithXAxisSort: ControlPanelSectionConfig = { + label: t('Query'), + expanded: true, + controlSetRows: [ + [hasGenericChartAxes ? 'x_axis' : null], + [hasGenericChartAxes ? 'time_grain_sqla' : null], + [hasGenericChartAxes ? xAxisSortControl : null], + [hasGenericChartAxes ? xAxisSortAscControl : null], + ...controlsWithoutXAxis, + ], +}; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx index 527bd3854005c..1dff19b83c410 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx @@ -82,11 +82,11 @@ export const forecastIntervalControls: ControlPanelSectionConfig = { config: { type: 'SelectControl', freeForm: true, - label: 'Yearly seasonality', + label: t('Yearly seasonality'), choices: [ - [null, 'default'], - [true, 'Yes'], - [false, 'No'], + [null, t('default')], + [true, t('Yes')], + [false, t('No')], ], default: FORECAST_DEFAULT_DATA.forecastSeasonalityYearly, description: t( @@ -101,11 +101,11 @@ export const forecastIntervalControls: ControlPanelSectionConfig = { config: { type: 'SelectControl', freeForm: true, - label: 'Weekly seasonality', + label: t('Weekly seasonality'), choices: [ - [null, 'default'], - [true, 'Yes'], - [false, 'No'], + [null, t('default')], + [true, t('Yes')], + [false, t('No')], ], default: FORECAST_DEFAULT_DATA.forecastSeasonalityWeekly, description: t( @@ -120,11 +120,11 @@ export const forecastIntervalControls: ControlPanelSectionConfig = { config: { type: 'SelectControl', freeForm: true, - label: 'Daily seasonality', + label: t('Daily seasonality'), choices: [ - [null, 'default'], - [true, 'Yes'], - [false, 'No'], + [null, t('default')], + [true, t('Yes')], + [false, t('No')], ], default: FORECAST_DEFAULT_DATA.forecastSeasonalityDaily, description: t( diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/sections/index.ts b/superset-frontend/packages/superset-ui-chart-controls/src/sections/index.ts index 2f6496e67ab7b..c0113b189fd8e 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/sections/index.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/sections/index.ts @@ -22,3 +22,4 @@ export * from './advancedAnalytics'; export * from './annotationsAndLayers'; export * from './forecastInterval'; export * from './chartTitle'; +export * from './echartsTimeSeriesQuery'; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx index 17c9e50423852..4535f1996dd72 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { t } from '@superset-ui/core'; +import { hasGenericChartAxes, t } from '@superset-ui/core'; import { ControlPanelSectionConfig } from '../types'; // A few standard controls sections that are used internally. @@ -32,17 +32,29 @@ export const legacyTimeseriesTime: ControlPanelSectionConfig = { ...baseTimeSection, controlSetRows: [ ['granularity'], - ['druid_time_origin'], ['granularity_sqla'], ['time_grain_sqla'], ['time_range'], ], }; -export const legacyRegularTime: ControlPanelSectionConfig = { - ...baseTimeSection, - controlSetRows: [['granularity_sqla'], ['time_range']], -}; +export const genericTime: ControlPanelSectionConfig = hasGenericChartAxes + ? { controlSetRows: [] } + : { + ...baseTimeSection, + controlSetRows: [ + ['granularity_sqla'], + ['time_grain_sqla'], + ['time_range'], + ], + }; + +export const legacyRegularTime: ControlPanelSectionConfig = hasGenericChartAxes + ? { controlSetRows: [] } + : { + ...baseTimeSection, + controlSetRows: [['granularity_sqla'], ['time_range']], + }; export const datasourceAndVizType: ControlPanelSectionConfig = { label: t('Datasource & Chart Type'), diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx index 55c560cb7935e..548dd4ae4d7fe 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx @@ -40,7 +40,6 @@ export type ColumnConfigControlProps<T extends ColumnConfig> = queryResponse?: ChartDataResponseResult; configFormLayout?: ColumnConfigFormLayout; appliedColumnNames?: string[]; - emitFilter: boolean; }; /** @@ -57,24 +56,8 @@ export default function ColumnConfigControl<T extends ColumnConfig>({ value, onChange, configFormLayout = DEFAULT_CONFIG_FORM_LAYOUT, - emitFilter, ...props }: ColumnConfigControlProps<T>) { - if (emitFilter) { - Object.values(configFormLayout).forEach(array_of_array => { - if (!array_of_array.some(arr => arr.includes('emitTarget'))) { - array_of_array.push(['emitTarget']); - } - }); - } else { - Object.values(configFormLayout).forEach(array_of_array => { - const index = array_of_array.findIndex(arr => arr.includes('emitTarget')); - if (index > -1) { - array_of_array.splice(index, 1); - } - }); - } - const { colnames: _colnames, coltypes: _coltypes } = queryResponse || {}; let colnames: string[] = []; let coltypes: GenericDataType[] = []; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx index 150f1e91f0bbe..7bf6c95c7401f 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx @@ -35,24 +35,13 @@ export type SharedColumnConfigProp = | 'colorPositiveNegative' | 'columnWidth' | 'fractionDigits' - | 'emitTarget' | 'd3NumberFormat' | 'd3SmallNumberFormat' | 'd3TimeFormat' | 'horizontalAlign' + | 'truncateLongCells' | 'showCellBars'; -const emitTarget: ControlFormItemSpec<'Input'> = { - controlType: 'Input', - label: t('Emit Target'), - description: t( - 'If you wish to specify a different target column than the original column, it can be entered here', - ), - defaultValue: '', - debounceDelay: 500, - validators: undefined, -}; - const d3NumberFormat: ControlFormItemSpec<'Select'> = { controlType: 'Select', label: t('D3 format'), @@ -92,7 +81,7 @@ const columnWidth: ControlFormItemSpec<'InputNumber'> = { "Default minimal column width in pixels, actual width may still be larger than this if other columns don't need much space", ), width: 120, - placeholder: 'auto', + placeholder: t('auto'), debounceDelay: 400, validators: [validateNumber], }; @@ -142,23 +131,31 @@ const colorPositiveNegative: ControlFormItemSpec<'Checkbox'> = { debounceDelay: 200, }; +const truncateLongCells: ControlFormItemSpec<'Checkbox'> = { + controlType: 'Checkbox', + label: t('Truncate Cells'), + description: t('Truncate long cells to the "min width" set above'), + defaultValue: false, + debounceDelay: 400, +}; + /** * All configurable column formatting properties. */ export const SHARED_COLUMN_CONFIG_PROPS = { d3NumberFormat, - emitTarget, d3SmallNumberFormat: { ...d3NumberFormat, label: t('Small number format'), description: t( 'D3 number format for numbers between -1.0 and 1.0, ' + - 'useful when you want to have different siginificant digits for small and large numbers', + 'useful when you want to have different significant digits for small and large numbers', ), }, d3TimeFormat, fractionDigits, columnWidth, + truncateLongCells, horizontalAlign, showCellBars, alignPositiveNegative, @@ -175,6 +172,7 @@ export const DEFAULT_CONFIG_FORM_LAYOUT: ColumnConfigFormLayout = { 'columnWidth', { name: 'horizontalAlign', override: { defaultValue: 'left' } }, ], + ['truncateLongCells'], ], [GenericDataType.NUMERIC]: [ [ diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx new file mode 100644 index 0000000000000..979912e58f1da --- /dev/null +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx @@ -0,0 +1,122 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + ContributionType, + ensureIsArray, + getColumnLabel, + getMetricLabel, + isDefined, + isEqualArray, + QueryFormColumn, + QueryFormMetric, + t, +} from '@superset-ui/core'; +import { ControlPanelState, ControlState, ControlStateMapping } from '../types'; +import { isTemporalColumn } from '../utils'; + +export const contributionModeControl = { + name: 'contributionMode', + config: { + type: 'SelectControl', + label: t('Contribution Mode'), + default: null, + choices: [ + [null, t('None')], + [ContributionType.Row, t('Row')], + [ContributionType.Column, t('Series')], + ], + description: t('Calculate contribution per series or row'), + }, +}; + +const xAxisSortVisibility = ({ controls }: { controls: ControlStateMapping }) => + isDefined(controls?.x_axis?.value) && + !isTemporalColumn( + getColumnLabel(controls?.x_axis?.value as QueryFormColumn), + controls?.datasource?.datasource, + ) && + Array.isArray(controls?.groupby?.value) && + controls.groupby.value.length === 0; + +export const xAxisSortControl = { + name: 'x_axis_sort', + config: { + type: 'XAxisSortControl', + label: t('X-Axis Sort By'), + description: t('Whether to sort descending or ascending on the X-Axis.'), + shouldMapStateToProps: ( + prevState: ControlPanelState, + state: ControlPanelState, + ) => { + const prevOptions = [ + getColumnLabel(prevState?.controls?.x_axis?.value as QueryFormColumn), + ...ensureIsArray(prevState?.controls?.metrics?.value).map(metric => + getMetricLabel(metric as QueryFormMetric), + ), + ]; + const currOptions = [ + getColumnLabel(state?.controls?.x_axis?.value as QueryFormColumn), + ...ensureIsArray(state?.controls?.metrics?.value).map(metric => + getMetricLabel(metric as QueryFormMetric), + ), + ]; + return !isEqualArray(prevOptions, currOptions); + }, + mapStateToProps: ( + { controls }: { controls: ControlStateMapping }, + controlState: ControlState, + ) => { + const choices = [ + getColumnLabel(controls?.x_axis?.value as QueryFormColumn), + ...ensureIsArray(controls?.metrics?.value).map(metric => + getMetricLabel(metric as QueryFormMetric), + ), + ].filter(Boolean); + const shouldReset = !( + typeof controlState.value === 'string' && + choices.includes(controlState.value) && + !isTemporalColumn( + getColumnLabel(controls?.x_axis?.value as QueryFormColumn), + controls?.datasource?.datasource, + ) + ); + + return { + shouldReset, + options: choices.map(entry => ({ + value: entry, + label: entry, + })), + }; + }, + visibility: xAxisSortVisibility, + }, +}; + +export const xAxisSortAscControl = { + name: 'x_axis_sort_asc', + config: { + type: 'CheckboxControl', + label: t('X-Axis Sort Ascending'), + default: true, + description: t('Whether to sort descending or ascending on the X-Axis.'), + visibility: xAxisSortVisibility, + }, +}; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx index ce63590f740bb..840c5c3611a89 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx @@ -17,50 +17,92 @@ * specific language governing permissions and limitations * under the License. */ +import React, { useMemo } from 'react'; import { FeatureFlag, isFeatureEnabled, QueryColumn, - QueryResponse, t, validateNonEmpty, } from '@superset-ui/core'; -import { ExtraControlProps, SharedControlConfig, Dataset } from '../types'; +import { + ExtraControlProps, + SharedControlConfig, + Dataset, + Metric, + isDataset, +} from '../types'; import { DATASET_TIME_COLUMN_OPTION, TIME_FILTER_LABELS } from '../constants'; -import { QUERY_TIME_COLUMN_OPTION, defineSavedMetrics } from '..'; +import { + QUERY_TIME_COLUMN_OPTION, + defineSavedMetrics, + ColumnOption, + ColumnMeta, + FilterOption, + temporalColumnMixin, + datePickerInAdhocFilterMixin, + xAxisMixin, +} from '..'; + +type Control = { + savedMetrics?: Metric[] | null; + default?: unknown; +}; + +/* + * Note: Previous to the commit that introduced this comment, the shared controls module + * would check feature flags at module execution time and expose a different control + * configuration (component + props) depending on the status of drag-and-drop feature + * flags. This commit combines those configs, merging the required props for both the + * drag-and-drop and non-drag-and-drop components, and renders a wrapper component that + * checks feature flags at component render time to avoid race conditions between when + * feature flags are set and when they're checked. + */ -export const dndGroupByControl: SharedControlConfig<'DndColumnSelect'> = { +export const dndGroupByControl: SharedControlConfig< + 'DndColumnSelect' | 'SelectControl', + ColumnMeta +> = { type: 'DndColumnSelect', label: t('Dimensions'), + multi: true, + freeForm: true, + clearable: true, default: [], + includeTime: false, description: t( - 'One or many columns to group by. High cardinality groupings should include a series limit ' + - 'to limit the number of fetched and rendered series.', + 'One or many columns to group by. High cardinality groupings should include a sort by metric ' + + 'and series limit to limit the number of fetched and rendered series.', ), - mapStateToProps(state, { includeTime }) { + optionRenderer: (c: ColumnMeta) => <ColumnOption showType column={c} />, + valueRenderer: (c: ColumnMeta) => <ColumnOption column={c} />, + valueKey: 'column_name', + allowAll: true, + filterOption: ({ data: opt }: FilterOption<ColumnMeta>, text: string) => + opt.column_name?.toLowerCase().includes(text.toLowerCase()) || + opt.verbose_name?.toLowerCase().includes(text.toLowerCase()) || + false, + promptTextCreator: (label: unknown) => label, + mapStateToProps(state, controlState) { const newState: ExtraControlProps = {}; const { datasource } = state; if (datasource?.columns[0]?.hasOwnProperty('groupby')) { const options = (datasource as Dataset).columns.filter(c => c.groupby); - if (includeTime) { + if (controlState?.includeTime) { options.unshift(DATASET_TIME_COLUMN_OPTION); } - newState.options = Object.fromEntries( - options.map(option => [option.column_name, option]), - ); + newState.options = options; newState.savedMetrics = (datasource as Dataset).metrics || []; } else { - const options = datasource?.columns; - if (includeTime) { - (options as QueryColumn[])?.unshift(QUERY_TIME_COLUMN_OPTION); + const options = (datasource?.columns as QueryColumn[]) || []; + if (controlState?.includeTime) { + options.unshift(QUERY_TIME_COLUMN_OPTION); } - newState.options = Object.fromEntries( - (options as QueryColumn[])?.map(option => [option.name, option]), - ); - newState.options = datasource?.columns; + newState.options = options; } return newState; }, + commaChoosesOption: false, }; export const dndColumnsControl: typeof dndGroupByControl = { @@ -69,9 +111,9 @@ export const dndColumnsControl: typeof dndGroupByControl = { description: t('One or many columns to pivot as columns'), }; -export const dndSeries: typeof dndGroupByControl = { +export const dndSeriesControl: typeof dndGroupByControl = { ...dndGroupByControl, - label: t('Dimensions'), + label: t('Dimension'), multi: false, default: null, description: t( @@ -81,7 +123,7 @@ export const dndSeries: typeof dndGroupByControl = { ), }; -export const dndEntity: typeof dndGroupByControl = { +export const dndEntityControl: typeof dndGroupByControl = { ...dndGroupByControl, label: t('Entity'), default: null, @@ -90,14 +132,16 @@ export const dndEntity: typeof dndGroupByControl = { description: t('This defines the element to be plotted on the chart'), }; -export const dnd_adhoc_filters: SharedControlConfig<'DndFilterSelect'> = { +export const dndAdhocFilterControl: SharedControlConfig< + 'DndFilterSelect' | 'AdhocFilterControl' +> = { type: 'DndFilterSelect', label: t('Filters'), default: [], description: '', mapStateToProps: ({ datasource, form_data }) => ({ - columns: datasource?.columns[0]?.hasOwnProperty('filterable') - ? (datasource as Dataset)?.columns.filter(c => c.filterable) + columns: isDataset(datasource) + ? datasource.columns.filter(c => c.filterable) : datasource?.columns || [], savedMetrics: defineSavedMetrics(datasource), // current active adhoc metrics @@ -106,9 +150,12 @@ export const dnd_adhoc_filters: SharedControlConfig<'DndFilterSelect'> = { datasource, }), provideFormDataToProps: true, + ...datePickerInAdhocFilterMixin, }; -export const dnd_adhoc_metrics: SharedControlConfig<'DndMetricSelect'> = { +export const dndAdhocMetricsControl: SharedControlConfig< + 'DndMetricSelect' | 'MetricsControl' +> = { type: 'DndMetricSelect', multi: true, label: t('Metrics'), @@ -122,20 +169,23 @@ export const dnd_adhoc_metrics: SharedControlConfig<'DndMetricSelect'> = { description: t('One or many metrics to display'), }; -export const dnd_adhoc_metric: SharedControlConfig<'DndMetricSelect'> = { - ...dnd_adhoc_metrics, +export const dndAdhocMetricControl: typeof dndAdhocMetricsControl = { + ...dndAdhocMetricsControl, multi: false, label: t('Metric'), description: t('Metric'), }; -export const dnd_adhoc_metric_2: SharedControlConfig<'DndMetricSelect'> = { - ...dnd_adhoc_metric, +export const dndAdhocMetricControl2: typeof dndAdhocMetricControl = { + ...dndAdhocMetricControl, label: t('Right Axis Metric'), + clearable: true, description: t('Choose a metric for right axis'), }; -export const dnd_sort_by: SharedControlConfig<'DndMetricSelect'> = { +export const dndSortByControl: SharedControlConfig< + 'DndMetricSelect' | 'MetricsControl' +> = { type: 'DndMetricSelect', label: t('Sort by'), default: null, @@ -151,33 +201,38 @@ export const dnd_sort_by: SharedControlConfig<'DndMetricSelect'> = { }), }; -export const dnd_size: SharedControlConfig<'DndMetricSelect'> = { - ...dnd_adhoc_metric, +export const dndSizeControl: typeof dndAdhocMetricControl = { + ...dndAdhocMetricControl, label: t('Bubble Size'), description: t('Metric used to calculate bubble size'), + default: null, }; -export const dnd_x: SharedControlConfig<'DndMetricSelect'> = { - ...dnd_adhoc_metric, +export const dndXControl: typeof dndAdhocMetricControl = { + ...dndAdhocMetricControl, label: t('X Axis'), description: t('Metric assigned to the [X] axis'), + default: null, }; -export const dnd_y: SharedControlConfig<'DndMetricSelect'> = { - ...dnd_adhoc_metric, +export const dndYControl: typeof dndAdhocMetricControl = { + ...dndAdhocMetricControl, label: t('Y Axis'), description: t('Metric assigned to the [Y] axis'), + default: null, }; -export const dnd_secondary_metric: SharedControlConfig<'DndMetricSelect'> = { - ...dnd_adhoc_metric, +export const dndSecondaryMetricControl: typeof dndAdhocMetricControl = { + ...dndAdhocMetricControl, label: t('Color Metric'), + default: null, validators: [], description: t('A metric to use for color'), }; -export const dnd_granularity_sqla: typeof dndGroupByControl = { - ...dndSeries, +export const dndGranularitySqlaControl: typeof dndSeriesControl = { + ...dndSeriesControl, + ...temporalColumnMixin, label: TIME_FILTER_LABELS.granularity_sqla, description: t( 'The time column for the visualization. Note that you ' + @@ -186,39 +241,35 @@ export const dnd_granularity_sqla: typeof dndGroupByControl = { 'filter below is applied against this column or ' + 'expression', ), + default: (c: Control) => c.default, + clearable: false, canDelete: false, - ghostButtonText: t( - isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX) - ? 'Drop a temporal column here or click' - : 'Drop temporal column here', - ), - mapStateToProps: ({ datasource }) => { - if (datasource?.columns[0]?.hasOwnProperty('column_name')) { - const temporalColumns = - (datasource as Dataset)?.columns?.filter(c => c.is_dttm) ?? []; - const options = Object.fromEntries( - temporalColumns.map(option => [option.column_name, option]), - ); - return { - options, - default: - (datasource as Dataset)?.main_dttm_col || - temporalColumns[0]?.column_name || - null, - isTemporal: true, - }; - } + ghostButtonText: t('Drop temporal column here'), + clickEnabledGhostButtonText: t('Drop a temporal column here or click'), + optionRenderer: (c: ColumnMeta) => <ColumnOption showType column={c} />, + valueRenderer: (c: ColumnMeta) => <ColumnOption column={c} />, + valueKey: 'column_name', +}; + +export const dndXAxisControl: typeof dndGroupByControl = { + ...dndGroupByControl, + ...xAxisMixin, +}; - const sortedQueryColumns = (datasource as QueryResponse)?.columns?.sort( - query => (query?.is_dttm ? -1 : 1), +export function withDndFallback( + DndComponent: React.ComponentType<any>, + FallbackComponent: React.ComponentType<any>, +) { + return function DndControl(props: any) { + const enableExploreDnd = useMemo( + () => isFeatureEnabled(FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP), + [], ); - const options = Object.fromEntries( - sortedQueryColumns.map(option => [option.name, option]), + + return enableExploreDnd ? ( + <DndComponent {...props} /> + ) : ( + <FallbackComponent {...props} /> ); - return { - options, - default: sortedQueryColumns[0]?.name || null, - isTemporal: true, - }; - }, -}; + }; +} diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.ts b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.ts new file mode 100644 index 0000000000000..acf3f3e8fdd51 --- /dev/null +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.ts @@ -0,0 +1,25 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +export { default as sharedControls } from './sharedControls'; +export { withDndFallback } from './dndControls'; +// React control components +export { default as sharedControlComponents } from './components'; +export * from './components'; +export * from './customControls'; +export * from './mixins'; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx deleted file mode 100644 index 5e8c64c6f96ee..0000000000000 --- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx +++ /dev/null @@ -1,603 +0,0 @@ -/* eslint-disable camelcase */ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This file exports all controls available for use in chart plugins internal to Superset. - * It is not recommended to use the controls here for any third-party plugins. - * - * While the React components located in `controls/components` represent different - * types of controls (CheckboxControl, SelectControl, TextControl, ...), the controls here - * represent instances of control types, that can be reused across visualization types. - * - * When controls are reused across viz types, their values are carried over as a user - * changes the chart types. - * - * While the keys defined in the control itself get passed to the controlType as props, - * here's a list of the keys that are common to all controls, and as a result define the - * control interface. - */ -import React from 'react'; -import { isEmpty } from 'lodash'; -import { - FeatureFlag, - t, - getCategoricalSchemeRegistry, - getSequentialSchemeRegistry, - isFeatureEnabled, - SequentialScheme, - legacyValidateInteger, - validateNonEmpty, - ComparisionType, - QueryResponse, - QueryColumn, -} from '@superset-ui/core'; - -import { - formatSelectOptions, - D3_FORMAT_OPTIONS, - D3_FORMAT_DOCS, - D3_TIME_FORMAT_OPTIONS, - D3_TIME_FORMAT_DOCS, - DEFAULT_TIME_FORMAT, - DEFAULT_NUMBER_FORMAT, - defineSavedMetrics, -} from '../utils'; -import { TIME_FILTER_LABELS, DATASET_TIME_COLUMN_OPTION } from '../constants'; -import { - Metric, - SharedControlConfig, - ColumnMeta, - ExtraControlProps, - SelectControlConfig, - Dataset, -} from '../types'; -import { ColumnOption } from '../components/ColumnOption'; - -import { - dnd_adhoc_filters, - dnd_adhoc_metric, - dnd_adhoc_metrics, - dnd_granularity_sqla, - dnd_sort_by, - dnd_secondary_metric, - dnd_size, - dnd_x, - dnd_y, - dndColumnsControl, - dndEntity, - dndGroupByControl, - dndSeries, - dnd_adhoc_metric_2, -} from './dndControls'; -import { QUERY_TIME_COLUMN_OPTION } from '..'; - -const categoricalSchemeRegistry = getCategoricalSchemeRegistry(); -const sequentialSchemeRegistry = getSequentialSchemeRegistry(); - -export const PRIMARY_COLOR = { r: 0, g: 122, b: 135, a: 1 }; - -const ROW_LIMIT_OPTIONS = [10, 50, 100, 250, 500, 1000, 5000, 10000, 50000]; -const SERIES_LIMITS = [5, 10, 25, 50, 100, 500]; - -const appContainer = document.getElementById('app'); -const { user } = JSON.parse( - appContainer?.getAttribute('data-bootstrap') || '{}', -); - -type Control = { - savedMetrics?: Metric[] | null; - default?: unknown; -}; - -type SelectDefaultOption = { - label: string; - value: string; -}; - -const groupByControl: SharedControlConfig<'SelectControl', ColumnMeta> = { - type: 'SelectControl', - label: t('Dimensions'), - multi: true, - freeForm: true, - clearable: true, - default: [], - includeTime: false, - description: t( - 'One or many columns to group by. High cardinality groupings should include a sort by metric ' + - 'and series limit to limit the number of fetched and rendered series.', - ), - optionRenderer: c => <ColumnOption showType column={c} />, - valueRenderer: c => <ColumnOption column={c} />, - valueKey: 'column_name', - allowAll: true, - filterOption: ({ data: opt }, text: string) => - (opt.column_name && - opt.column_name.toLowerCase().includes(text.toLowerCase())) || - (opt.verbose_name && - opt.verbose_name.toLowerCase().includes(text.toLowerCase())) || - false, - promptTextCreator: (label: unknown) => label, - mapStateToProps(state, { includeTime }) { - const newState: ExtraControlProps = {}; - const { datasource } = state; - if (datasource?.columns[0]?.hasOwnProperty('groupby')) { - const options = (datasource as Dataset).columns.filter(c => c.groupby); - if (includeTime) options.unshift(DATASET_TIME_COLUMN_OPTION); - newState.options = options; - } else { - const options = (datasource as QueryResponse).columns; - if (includeTime) options.unshift(QUERY_TIME_COLUMN_OPTION); - newState.options = options; - } - return newState; - }, - commaChoosesOption: false, -}; - -const metrics: SharedControlConfig<'MetricsControl'> = { - type: 'MetricsControl', - multi: true, - label: t('Metrics'), - validators: [validateNonEmpty], - mapStateToProps: ({ datasource }) => ({ - columns: datasource?.columns || [], - savedMetrics: defineSavedMetrics(datasource), - datasource, - datasourceType: datasource?.type, - }), - description: t('One or many metrics to display'), -}; - -const metric: SharedControlConfig<'MetricsControl'> = { - ...metrics, - multi: false, - label: t('Metric'), - description: t('Metric'), -}; - -const datasourceControl: SharedControlConfig<'DatasourceControl'> = { - type: 'DatasourceControl', - label: t('Datasource'), - default: null, - description: null, - mapStateToProps: ({ datasource, form_data }) => ({ - datasource, - form_data, - user, - }), -}; - -const viz_type: SharedControlConfig<'VizTypeControl'> = { - type: 'VizTypeControl', - label: t('Visualization Type'), - default: 'table', - description: t('The type of visualization to display'), -}; - -const color_picker: SharedControlConfig<'ColorPickerControl'> = { - type: 'ColorPickerControl', - label: t('Fixed Color'), - description: t('Use this to define a static color for all circles'), - default: PRIMARY_COLOR, - renderTrigger: true, -}; - -const metric_2: SharedControlConfig<'MetricsControl'> = { - ...metric, - label: t('Right Axis Metric'), - clearable: true, - description: t('Choose a metric for right axis'), -}; - -const linear_color_scheme: SharedControlConfig<'ColorSchemeControl'> = { - type: 'ColorSchemeControl', - label: t('Linear Color Scheme'), - choices: () => - (sequentialSchemeRegistry.values() as SequentialScheme[]).map(value => [ - value.id, - value.label, - ]), - default: sequentialSchemeRegistry.getDefaultKey(), - clearable: false, - description: '', - renderTrigger: true, - schemes: () => sequentialSchemeRegistry.getMap(), - isLinear: true, - mapStateToProps: state => ({ - dashboardId: state?.form_data?.dashboardId, - }), -}; - -const secondary_metric: SharedControlConfig<'MetricsControl'> = { - ...metric, - label: t('Color Metric'), - default: null, - validators: [], - description: t('A metric to use for color'), -}; - -const columnsControl: typeof groupByControl = { - ...groupByControl, - label: t('Columns'), - description: t('One or many columns to pivot as columns'), -}; - -const druid_time_origin: SharedControlConfig<'SelectControl'> = { - type: 'SelectControl', - freeForm: true, - label: TIME_FILTER_LABELS.druid_time_origin, - choices: [ - ['', 'default'], - ['now', 'now'], - ], - default: null, - description: t( - 'Defines the origin where time buckets start, ' + - 'accepts natural dates as in `now`, `sunday` or `1970-01-01`', - ), -}; - -const granularity: SharedControlConfig<'SelectControl'> = { - type: 'SelectControl', - freeForm: true, - label: TIME_FILTER_LABELS.granularity, - default: 'one day', - choices: [ - [null, 'all'], - ['PT5S', '5 seconds'], - ['PT30S', '30 seconds'], - ['PT1M', '1 minute'], - ['PT5M', '5 minutes'], - ['PT30M', '30 minutes'], - ['PT1H', '1 hour'], - ['PT6H', '6 hour'], - ['P1D', '1 day'], - ['P7D', '7 days'], - ['P1W', 'week'], - ['week_starting_sunday', 'week starting Sunday'], - ['week_ending_saturday', 'week ending Saturday'], - ['P1M', 'month'], - ['P3M', 'quarter'], - ['P1Y', 'year'], - ], - description: t( - 'The time granularity for the visualization. Note that you ' + - 'can type and use simple natural language as in `10 seconds`, ' + - '`1 day` or `56 weeks`', - ), -}; - -const granularity_sqla: SharedControlConfig<'SelectControl', ColumnMeta> = { - type: 'SelectControl', - label: TIME_FILTER_LABELS.granularity_sqla, - description: t( - 'The time column for the visualization. Note that you ' + - 'can define arbitrary expression that return a DATETIME ' + - 'column in the table. Also note that the ' + - 'filter below is applied against this column or ' + - 'expression', - ), - default: (c: Control) => c.default, - clearable: false, - optionRenderer: c => <ColumnOption showType column={c} />, - valueRenderer: c => <ColumnOption column={c} />, - valueKey: 'column_name', - mapStateToProps: state => { - const props: Partial<SelectControlConfig<ColumnMeta | QueryColumn>> = {}; - const { datasource } = state; - - if (datasource?.hasOwnProperty('main_dttm_col')) { - const dataset = datasource as Dataset; - props.options = dataset.columns.filter((c: ColumnMeta) => c.is_dttm); - props.default = null; - if (dataset.main_dttm_col !== null) { - if (dataset.main_dttm_col) { - props.default = dataset.main_dttm_col; - } else if (props?.options.length > 0) { - props.default = (props.options[0] as ColumnMeta).column_name; - } - } else { - const sortedQueryColumns = (datasource as QueryResponse)?.columns - ?.filter(query => query?.is_dttm === true) - .sort(); - props.options = sortedQueryColumns; - if (props?.options.length > 0) { - props.default = - 'column_name' in props.options[0] - ? props.options[0]?.column_name - : props.options[0]?.name; - } - } - } else { - const sortedQueryColumns = (datasource as QueryResponse)?.columns - ?.filter(query => query?.is_dttm === true) - .sort(); - props.options = sortedQueryColumns; - if (props?.options.length > 0) { - props.default = - 'column_name' in props.options[0] - ? props.options[0]?.column_name - : props.options[0]?.name; - } - } - return props; - }, -}; - -const time_grain_sqla: SharedControlConfig<'SelectControl'> = { - type: 'SelectControl', - label: TIME_FILTER_LABELS.time_grain_sqla, - default: 'P1D', - description: t( - 'The time granularity for the visualization. This ' + - 'applies a date transformation to alter ' + - 'your time column and defines a new time granularity. ' + - 'The options here are defined on a per database ' + - 'engine basis in the Superset source code.', - ), - mapStateToProps: ({ datasource }) => ({ - choices: (datasource as Dataset)?.time_grain_sqla || null, - }), -}; - -const time_range: SharedControlConfig<'DateFilterControl'> = { - type: 'DateFilterControl', - freeForm: true, - label: TIME_FILTER_LABELS.time_range, - default: t('No filter'), // this value is translated, but the backend wouldn't understand a translated value? - description: t( - 'The time range for the visualization. All relative times, e.g. "Last month", ' + - '"Last 7 days", "now", etc. are evaluated on the server using the server\'s ' + - 'local time (sans timezone). All tooltips and placeholder times are expressed ' + - 'in UTC (sans timezone). The timestamps are then evaluated by the database ' + - "using the engine's local timezone. Note one can explicitly set the timezone " + - 'per the ISO 8601 format if specifying either the start and/or end time.', - ), - mapStateToProps: ({ datasource }) => ({ - datasource, - }), -}; - -const row_limit: SharedControlConfig<'SelectControl'> = { - type: 'SelectControl', - freeForm: true, - label: t('Row limit'), - validators: [legacyValidateInteger], - default: 10000, - choices: formatSelectOptions(ROW_LIMIT_OPTIONS), - description: t('Limits the number of rows that get displayed.'), -}; - -const order_desc: SharedControlConfig<'CheckboxControl'> = { - type: 'CheckboxControl', - label: t('Sort Descending'), - default: true, - description: t('Whether to sort descending or ascending'), - visibility: ({ controls }) => - Boolean( - controls?.timeseries_limit_metric.value && - !isEmpty(controls?.timeseries_limit_metric.value), - ), -}; - -const limit: SharedControlConfig<'SelectControl'> = { - type: 'SelectControl', - freeForm: true, - label: t('Series limit'), - validators: [legacyValidateInteger], - choices: formatSelectOptions(SERIES_LIMITS), - clearable: true, - description: t( - 'Limits the number of series that get displayed. A joined subquery (or an extra phase ' + - 'where subqueries are not supported) is applied to limit the number of series that get ' + - 'fetched and rendered. This feature is useful when grouping by high cardinality ' + - 'column(s) though does increase the query complexity and cost.', - ), -}; - -const series_limit: SharedControlConfig<'SelectControl'> = { - type: 'SelectControl', - freeForm: true, - label: t('Series limit'), - validators: [legacyValidateInteger], - choices: formatSelectOptions(SERIES_LIMITS), - description: t( - 'Limits the number of series that get displayed. A joined subquery (or an extra phase ' + - 'where subqueries are not supported) is applied to limit the number of series that get ' + - 'fetched and rendered. This feature is useful when grouping by high cardinality ' + - 'column(s) though does increase the query complexity and cost.', - ), -}; - -const sort_by: SharedControlConfig<'MetricsControl'> = { - type: 'MetricsControl', - label: t('Sort by'), - default: null, - description: t( - 'Metric used to define how the top series are sorted if a series or row limit is present. ' + - 'If undefined reverts to the first metric (where appropriate).', - ), - mapStateToProps: ({ datasource }) => ({ - columns: datasource?.columns || [], - savedMetrics: defineSavedMetrics(datasource), - datasource, - datasourceType: datasource?.type, - }), -}; - -const series: typeof groupByControl = { - ...groupByControl, - label: t('Dimensions'), - multi: false, - default: null, - description: t( - 'Defines the grouping of entities. ' + - 'Each series is shown as a specific color on the chart and ' + - 'has a legend toggle', - ), -}; - -const entity: typeof groupByControl = { - ...groupByControl, - label: t('Entity'), - default: null, - multi: false, - validators: [validateNonEmpty], - description: t('This defines the element to be plotted on the chart'), -}; - -const x: SharedControlConfig<'MetricsControl'> = { - ...metric, - label: t('X Axis'), - description: t('Metric assigned to the [X] axis'), - default: null, -}; - -const y: SharedControlConfig<'MetricsControl'> = { - ...metric, - label: t('Y Axis'), - default: null, - description: t('Metric assigned to the [Y] axis'), -}; - -const size: SharedControlConfig<'MetricsControl'> = { - ...metric, - label: t('Bubble Size'), - description: t('Metric used to calculate bubble size'), - default: null, -}; - -const y_axis_format: SharedControlConfig<'SelectControl', SelectDefaultOption> = - { - type: 'SelectControl', - freeForm: true, - label: t('Y Axis Format'), - renderTrigger: true, - default: DEFAULT_NUMBER_FORMAT, - choices: D3_FORMAT_OPTIONS, - description: D3_FORMAT_DOCS, - tokenSeparators: ['\n', '\t', ';'], - filterOption: ({ data: option }, search) => - option.label.includes(search) || option.value.includes(search), - mapStateToProps: state => { - const isPercentage = - state.controls?.comparison_type?.value === ComparisionType.Percentage; - return { - choices: isPercentage - ? D3_FORMAT_OPTIONS.filter(option => option[0].includes('%')) - : D3_FORMAT_OPTIONS, - }; - }, - }; - -const x_axis_time_format: SharedControlConfig< - 'SelectControl', - SelectDefaultOption -> = { - type: 'SelectControl', - freeForm: true, - label: t('Time format'), - renderTrigger: true, - default: DEFAULT_TIME_FORMAT, - choices: D3_TIME_FORMAT_OPTIONS, - description: D3_TIME_FORMAT_DOCS, - filterOption: ({ data: option }, search) => - option.label.includes(search) || option.value.includes(search), -}; - -const adhoc_filters: SharedControlConfig<'AdhocFilterControl'> = { - type: 'AdhocFilterControl', - label: t('Filters'), - default: [], - description: '', - mapStateToProps: ({ datasource, form_data }) => ({ - columns: datasource?.columns[0]?.hasOwnProperty('filterable') - ? (datasource as Dataset)?.columns.filter(c => c.filterable) - : datasource?.columns || [], - savedMetrics: defineSavedMetrics(datasource), - // current active adhoc metrics - selectedMetrics: - form_data.metrics || (form_data.metric ? [form_data.metric] : []), - datasource, - }), -}; - -const color_scheme: SharedControlConfig<'ColorSchemeControl'> = { - type: 'ColorSchemeControl', - label: t('Color Scheme'), - default: categoricalSchemeRegistry.getDefaultKey(), - renderTrigger: true, - choices: () => categoricalSchemeRegistry.keys().map(s => [s, s]), - description: t('The color scheme for rendering chart'), - schemes: () => categoricalSchemeRegistry.getMap(), - mapStateToProps: state => ({ - dashboardId: state?.form_data?.dashboardId, - }), -}; - -const truncate_metric: SharedControlConfig<'CheckboxControl'> = { - type: 'CheckboxControl', - label: t('Truncate Metric'), - default: true, - description: t('Whether to truncate metrics'), -}; - -const enableExploreDnd = isFeatureEnabled( - FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP, -); - -const sharedControls = { - metrics: enableExploreDnd ? dnd_adhoc_metrics : metrics, - metric: enableExploreDnd ? dnd_adhoc_metric : metric, - datasource: datasourceControl, - viz_type, - color_picker, - metric_2: enableExploreDnd ? dnd_adhoc_metric_2 : metric_2, - linear_color_scheme, - secondary_metric: enableExploreDnd ? dnd_secondary_metric : secondary_metric, - groupby: enableExploreDnd ? dndGroupByControl : groupByControl, - columns: enableExploreDnd ? dndColumnsControl : columnsControl, - druid_time_origin, - granularity, - granularity_sqla: enableExploreDnd ? dnd_granularity_sqla : granularity_sqla, - time_grain_sqla, - time_range, - row_limit, - limit, - timeseries_limit_metric: enableExploreDnd ? dnd_sort_by : sort_by, - orderby: enableExploreDnd ? dnd_sort_by : sort_by, - order_desc, - series: enableExploreDnd ? dndSeries : series, - entity: enableExploreDnd ? dndEntity : entity, - x: enableExploreDnd ? dnd_x : x, - y: enableExploreDnd ? dnd_y : y, - size: enableExploreDnd ? dnd_size : size, - y_axis_format, - x_axis_time_format, - adhoc_filters: enableExploreDnd ? dnd_adhoc_filters : adhoc_filters, - color_scheme, - series_columns: enableExploreDnd ? dndColumnsControl : columnsControl, - series_limit, - series_limit_metric: enableExploreDnd ? dnd_sort_by : sort_by, - legacy_order_by: enableExploreDnd ? dnd_sort_by : sort_by, - truncate_metric, -}; - -export { sharedControls, dndEntity, dndColumnsControl }; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/mixins.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/mixins.tsx new file mode 100644 index 0000000000000..0b19b96c7f6cf --- /dev/null +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/mixins.tsx @@ -0,0 +1,121 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + ensureIsArray, + hasGenericChartAxes, + NO_TIME_RANGE, + QueryFormData, + t, + validateNonEmpty, +} from '@superset-ui/core'; +import { BaseControlConfig, ControlPanelState, ControlState } from '../types'; +import { getTemporalColumns } from '../utils'; + +const getAxisLabel = ( + formData: QueryFormData, +): Record<'label' | 'description', string> => + formData?.orientation === 'horizontal' + ? { label: t('Y-axis'), description: t('Dimension to use on y-axis.') } + : { label: t('X-axis'), description: t('Dimension to use on x-axis.') }; + +export const xAxisMixin = { + label: (state: ControlPanelState) => getAxisLabel(state?.form_data).label, + multi: false, + description: (state: ControlPanelState) => + getAxisLabel(state?.form_data).description, + validators: [validateNonEmpty], + initialValue: (control: ControlState, state: ControlPanelState | null) => { + if ( + hasGenericChartAxes && + state?.form_data?.granularity_sqla && + !state.form_data?.x_axis && + !control?.value + ) { + return state.form_data.granularity_sqla; + } + return undefined; + }, + default: undefined, +}; + +export const temporalColumnMixin: Pick<BaseControlConfig, 'mapStateToProps'> = { + mapStateToProps: ({ datasource }) => { + const payload = getTemporalColumns(datasource); + + return { + options: payload.temporalColumns, + default: payload.defaultTemporalColumn, + isTemporal: true, + }; + }, +}; + +export const datePickerInAdhocFilterMixin: Pick< + BaseControlConfig, + 'initialValue' +> = { + initialValue: (control: ControlState, state: ControlPanelState | null) => { + // skip initialValue if + // 1) GENERIC_CHART_AXES is disabled + // 2) there was a time filter in adhoc filters + if ( + !hasGenericChartAxes || + ensureIsArray(control.value).findIndex( + (flt: any) => flt?.operator === 'TEMPORAL_RANGE', + ) > -1 + ) { + return undefined; + } + + // should migrate original granularity_sqla and time_range into adhoc filter + // 1) granularity_sqla and time_range are existed + if (state?.form_data?.granularity_sqla && state?.form_data?.time_range) { + return [ + ...ensureIsArray(control.value), + { + clause: 'WHERE', + subject: state.form_data.granularity_sqla, + operator: 'TEMPORAL_RANGE', + comparator: state.form_data.time_range, + expressionType: 'SIMPLE', + }, + ]; + } + + // should apply the default time filter into adhoc filter + // 1) temporal column is existed in current datasource + const temporalColumn = + state?.datasource && + getTemporalColumns(state.datasource).defaultTemporalColumn; + if (hasGenericChartAxes && temporalColumn) { + return [ + ...ensureIsArray(control.value), + { + clause: 'WHERE', + subject: temporalColumn, + operator: 'TEMPORAL_RANGE', + comparator: state?.common?.conf?.DEFAULT_TIME_FILTER || NO_TIME_RANGE, + expressionType: 'SIMPLE', + }, + ]; + } + + return undefined; + }, +}; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx new file mode 100644 index 0000000000000..a4af8bcbf23f3 --- /dev/null +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx @@ -0,0 +1,409 @@ +/* eslint-disable camelcase */ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * This file exports all controls available for use in chart plugins internal to Superset. + * It is not recommended to use the controls here for any third-party plugins. + * + * While the React components located in `controls/components` represent different + * types of controls (CheckboxControl, SelectControl, TextControl, ...), the controls here + * represent instances of control types, that can be reused across visualization types. + * + * When controls are reused across viz types, their values are carried over as a user + * changes the chart types. + * + * While the keys defined in the control itself get passed to the controlType as props, + * here's a list of the keys that are common to all controls, and as a result define the + * control interface. + */ +import { isEmpty } from 'lodash'; +import { + t, + getCategoricalSchemeRegistry, + getSequentialSchemeRegistry, + SequentialScheme, + legacyValidateInteger, + ComparisonType, + isAdhocColumn, + isPhysicalColumn, + ensureIsArray, + isDefined, + hasGenericChartAxes, + NO_TIME_RANGE, +} from '@superset-ui/core'; + +import { + formatSelectOptions, + D3_FORMAT_OPTIONS, + D3_FORMAT_DOCS, + D3_TIME_FORMAT_OPTIONS, + D3_TIME_FORMAT_DOCS, + DEFAULT_TIME_FORMAT, + DEFAULT_NUMBER_FORMAT, +} from '../utils'; +import { TIME_FILTER_LABELS } from '../constants'; +import { + SharedControlConfig, + Dataset, + ColumnMeta, + ControlState, + ControlPanelState, +} from '../types'; + +import { + dndAdhocFilterControl, + dndAdhocMetricControl, + dndAdhocMetricsControl, + dndGranularitySqlaControl, + dndSortByControl, + dndSecondaryMetricControl, + dndSizeControl, + dndXControl, + dndYControl, + dndColumnsControl, + dndEntityControl, + dndGroupByControl, + dndSeriesControl, + dndAdhocMetricControl2, + dndXAxisControl, +} from './dndControls'; + +export { withDndFallback } from './dndControls'; + +const categoricalSchemeRegistry = getCategoricalSchemeRegistry(); +const sequentialSchemeRegistry = getSequentialSchemeRegistry(); + +export const PRIMARY_COLOR = { r: 0, g: 122, b: 135, a: 1 }; + +const ROW_LIMIT_OPTIONS = [10, 50, 100, 250, 500, 1000, 5000, 10000, 50000]; +const SERIES_LIMITS = [5, 10, 25, 50, 100, 500]; + +const appContainer = document.getElementById('app'); +const { user } = JSON.parse( + appContainer?.getAttribute('data-bootstrap') || '{}', +); + +type SelectDefaultOption = { + label: string; + value: string; +}; + +const datasourceControl: SharedControlConfig<'DatasourceControl'> = { + type: 'DatasourceControl', + label: t('Datasource'), + default: null, + description: null, + mapStateToProps: ({ datasource, form_data }) => ({ + datasource, + form_data, + user, + }), +}; + +const viz_type: SharedControlConfig<'VizTypeControl'> = { + type: 'VizTypeControl', + label: t('Visualization Type'), + default: 'table', + description: t('The type of visualization to display'), +}; + +const color_picker: SharedControlConfig<'ColorPickerControl'> = { + type: 'ColorPickerControl', + label: t('Fixed Color'), + description: t('Use this to define a static color for all circles'), + default: PRIMARY_COLOR, + renderTrigger: true, +}; + +const linear_color_scheme: SharedControlConfig<'ColorSchemeControl'> = { + type: 'ColorSchemeControl', + label: t('Linear Color Scheme'), + choices: () => + (sequentialSchemeRegistry.values() as SequentialScheme[]).map(value => [ + value.id, + value.label, + ]), + default: sequentialSchemeRegistry.getDefaultKey(), + clearable: false, + description: '', + renderTrigger: true, + schemes: () => sequentialSchemeRegistry.getMap(), + isLinear: true, + mapStateToProps: state => ({ + dashboardId: state?.form_data?.dashboardId, + }), +}; + +const granularity: SharedControlConfig<'SelectControl'> = { + type: 'SelectControl', + freeForm: true, + label: TIME_FILTER_LABELS.granularity, + default: 'one day', + choices: [ + [null, t('all')], + ['PT5S', t('5 seconds')], + ['PT30S', t('30 seconds')], + ['PT1M', t('1 minute')], + ['PT5M', t('5 minutes')], + ['PT30M', t('30 minutes')], + ['PT1H', t('1 hour')], + ['PT6H', t('6 hour')], + ['P1D', t('1 day')], + ['P7D', t('7 days')], + ['P1W', t('week')], + ['week_starting_sunday', t('week starting Sunday')], + ['week_ending_saturday', t('week ending Saturday')], + ['P1M', t('month')], + ['P3M', t('quarter')], + ['P1Y', t('year')], + ], + description: t( + 'The time granularity for the visualization. Note that you ' + + 'can type and use simple natural language as in `10 seconds`, ' + + '`1 day` or `56 weeks`', + ), +}; + +const time_grain_sqla: SharedControlConfig<'SelectControl'> = { + type: 'SelectControl', + label: TIME_FILTER_LABELS.time_grain_sqla, + placeholder: t('None'), + initialValue: (control: ControlState, state: ControlPanelState) => { + if (!isDefined(state)) { + // If a chart is in a Dashboard, the ControlPanelState is empty. + return control.value; + } + // If a chart is a new one that isn't saved, metadata is null. In this + // case we want to default P1D. If the chart has been saved, we want + // to use whichever value was chosen, either nothing or valid a time grain. + return state?.metadata || 'time_grain_sqla' in (state?.form_data ?? {}) + ? state?.form_data?.time_grain_sqla + : 'P1D'; + }, + description: t( + 'The time granularity for the visualization. This ' + + 'applies a date transformation to alter ' + + 'your time column and defines a new time granularity. ' + + 'The options here are defined on a per database ' + + 'engine basis in the Superset source code.', + ), + mapStateToProps: ({ datasource }) => ({ + choices: (datasource as Dataset)?.time_grain_sqla || [], + }), + visibility: ({ controls }) => { + if (!hasGenericChartAxes) { + return true; + } + + const xAxis = controls?.x_axis; + const xAxisValue = xAxis?.value; + if (isAdhocColumn(xAxisValue)) { + return true; + } + if (isPhysicalColumn(xAxisValue)) { + return !!(xAxis?.options ?? []).find( + (col: ColumnMeta) => col?.column_name === xAxisValue, + )?.is_dttm; + } + return false; + }, +}; + +const time_range: SharedControlConfig<'DateFilterControl'> = { + type: 'DateFilterControl', + freeForm: true, + label: TIME_FILTER_LABELS.time_range, + default: NO_TIME_RANGE, // this value is an empty filter constant so shouldn't translate it. + description: t( + 'The time range for the visualization. All relative times, e.g. "Last month", ' + + '"Last 7 days", "now", etc. are evaluated on the server using the server\'s ' + + 'local time (sans timezone). All tooltips and placeholder times are expressed ' + + 'in UTC (sans timezone). The timestamps are then evaluated by the database ' + + "using the engine's local timezone. Note one can explicitly set the timezone " + + 'per the ISO 8601 format if specifying either the start and/or end time.', + ), +}; + +const row_limit: SharedControlConfig<'SelectControl'> = { + type: 'SelectControl', + freeForm: true, + label: t('Row limit'), + validators: [legacyValidateInteger], + default: 10000, + choices: formatSelectOptions(ROW_LIMIT_OPTIONS), + description: t('Limits the number of rows that get displayed.'), +}; + +const order_desc: SharedControlConfig<'CheckboxControl'> = { + type: 'CheckboxControl', + label: t('Sort Descending'), + default: true, + description: t('Whether to sort descending or ascending'), + visibility: ({ controls }) => + Boolean( + controls?.timeseries_limit_metric.value && + !isEmpty(controls?.timeseries_limit_metric.value), + ), +}; + +const limit: SharedControlConfig<'SelectControl'> = { + type: 'SelectControl', + freeForm: true, + label: t('Series limit'), + placeholder: t('None'), + validators: [legacyValidateInteger], + choices: formatSelectOptions(SERIES_LIMITS), + clearable: true, + description: t( + 'Limits the number of series that get displayed. A joined subquery (or an extra phase ' + + 'where subqueries are not supported) is applied to limit the number of series that get ' + + 'fetched and rendered. This feature is useful when grouping by high cardinality ' + + 'column(s) though does increase the query complexity and cost.', + ), +}; + +const series_limit: SharedControlConfig<'SelectControl'> = { + type: 'SelectControl', + freeForm: true, + label: t('Series limit'), + placeholder: t('None'), + validators: [legacyValidateInteger], + choices: formatSelectOptions(SERIES_LIMITS), + description: t( + 'Limits the number of series that get displayed. A joined subquery (or an extra phase ' + + 'where subqueries are not supported) is applied to limit the number of series that get ' + + 'fetched and rendered. This feature is useful when grouping by high cardinality ' + + 'column(s) though does increase the query complexity and cost.', + ), +}; + +const y_axis_format: SharedControlConfig<'SelectControl', SelectDefaultOption> = + { + type: 'SelectControl', + freeForm: true, + label: t('Y Axis Format'), + renderTrigger: true, + default: DEFAULT_NUMBER_FORMAT, + choices: D3_FORMAT_OPTIONS, + description: D3_FORMAT_DOCS, + tokenSeparators: ['\n', '\t', ';'], + filterOption: ({ data: option }, search) => + option.label.includes(search) || option.value.includes(search), + mapStateToProps: state => { + const isPercentage = + state.controls?.comparison_type?.value === ComparisonType.Percentage; + return { + choices: isPercentage + ? D3_FORMAT_OPTIONS.filter(option => option[0].includes('%')) + : D3_FORMAT_OPTIONS, + }; + }, + }; + +const x_axis_time_format: SharedControlConfig< + 'SelectControl', + SelectDefaultOption +> = { + type: 'SelectControl', + freeForm: true, + label: t('Time format'), + renderTrigger: true, + default: DEFAULT_TIME_FORMAT, + choices: D3_TIME_FORMAT_OPTIONS, + description: D3_TIME_FORMAT_DOCS, + filterOption: ({ data: option }, search) => + option.label.includes(search) || option.value.includes(search), +}; + +const color_scheme: SharedControlConfig<'ColorSchemeControl'> = { + type: 'ColorSchemeControl', + label: t('Color Scheme'), + default: categoricalSchemeRegistry.getDefaultKey(), + renderTrigger: true, + choices: () => categoricalSchemeRegistry.keys().map(s => [s, s]), + description: t('The color scheme for rendering chart'), + schemes: () => categoricalSchemeRegistry.getMap(), + mapStateToProps: state => ({ + dashboardId: state?.form_data?.dashboardId, + }), +}; + +const truncate_metric: SharedControlConfig<'CheckboxControl'> = { + type: 'CheckboxControl', + label: t('Truncate Metric'), + default: true, + description: t('Whether to truncate metrics'), +}; + +const show_empty_columns: SharedControlConfig<'CheckboxControl'> = { + type: 'CheckboxControl', + label: t('Show empty columns'), + default: true, + description: t('Show empty columns'), +}; + +const temporal_columns_lookup: SharedControlConfig<'HiddenControl'> = { + type: 'HiddenControl', + initialValue: (control: ControlState, state: ControlPanelState | null) => + Object.fromEntries( + ensureIsArray<Record<string, any>>(state?.datasource?.columns) + .filter(option => option.is_dttm) + .map(option => [option.column_name ?? option.name, option.is_dttm]), + ), +}; + +export default { + metrics: dndAdhocMetricsControl, + metric: dndAdhocMetricControl, + datasource: datasourceControl, + viz_type, + color_picker, + metric_2: dndAdhocMetricControl2, + linear_color_scheme, + secondary_metric: dndSecondaryMetricControl, + groupby: dndGroupByControl, + columns: dndColumnsControl, + granularity, + granularity_sqla: dndGranularitySqlaControl, + time_grain_sqla, + time_range, + row_limit, + limit, + timeseries_limit_metric: dndSortByControl, + orderby: dndSortByControl, + order_desc, + series: dndSeriesControl, + entity: dndEntityControl, + x: dndXControl, + y: dndYControl, + size: dndSizeControl, + y_axis_format, + x_axis_time_format, + adhoc_filters: dndAdhocFilterControl, + color_scheme, + series_columns: dndColumnsControl, + series_limit, + series_limit_metric: dndSortByControl, + legacy_order_by: dndSortByControl, + truncate_metric, + x_axis: dndXAxisControl, + show_empty_columns, + temporal_columns_lookup, +}; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/types.ts b/superset-frontend/packages/superset-ui-chart-controls/src/types.ts index fac5548851d97..d4e91246ab11b 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/types.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/types.ts @@ -22,6 +22,7 @@ import type { AdhocColumn, Column, DatasourceType, + JsonObject, JsonValue, Metric, QueryFormColumn, @@ -29,8 +30,7 @@ import type { QueryFormMetric, QueryResponse, } from '@superset-ui/core'; -import { sharedControls } from './shared-controls'; -import sharedControlComponents from './shared-controls/components'; +import { sharedControls, sharedControlComponents } from './shared-controls'; export type { Metric } from '@superset-ui/core'; export type { ControlFormItemSpec } from './components/ControlForm'; @@ -50,6 +50,14 @@ export type SharedControlComponents = typeof sharedControlComponents; /** ---------------------------------------------- * Input data/props while rendering * ---------------------------------------------*/ +export interface Owner { + first_name: string; + id: number; + last_name: string; + username: string; + email?: string; +} + export type ColumnMeta = Omit<Column, 'id'> & { id?: number; } & AnyDict; @@ -67,17 +75,24 @@ export interface Dataset { time_grain_sqla?: string; granularity_sqla?: string; datasource_name: string | null; + name?: string; description: string | null; + uid?: string; + owners?: Owner[]; + filter_select?: boolean; + filter_select_enabled?: boolean; } export interface ControlPanelState { form_data: QueryFormData; datasource: Dataset | QueryResponse | null; controls: ControlStateMapping; + common: JsonObject; + metadata?: JsonObject | null; } /** - * The action dispather will call Redux `dispatch` internally and return what's + * The action dispatcher will call Redux `dispatch` internally and return what's * returned from `dispatch`, which by default is the original or another action. */ export interface ActionDispatcher< @@ -185,7 +200,7 @@ export type TabOverride = 'data' | 'customize' | boolean; tab, or 'customize' if you want it to show up on that tam. Otherwise sections with ALL `renderTrigger: true` components will show up on the `Customize` tab. * - visibility: a function that uses control panel props to check whether a control should - * be visibile. + * be visible. */ export interface BaseControlConfig< T extends ControlType = ControlType, @@ -193,9 +208,24 @@ export interface BaseControlConfig< V = JsonValue, > extends AnyDict { type: T; - label?: ReactNode; - description?: ReactNode; + label?: + | ReactNode + | (( + state: ControlPanelState, + controlState: ControlState, + // TODO: add strict `chartState` typing (see superset-frontend/src/explore/types) + chartState?: AnyDict, + ) => ReactNode); + description?: + | ReactNode + | (( + state: ControlPanelState, + controlState: ControlState, + // TODO: add strict `chartState` typing (see superset-frontend/src/explore/types) + chartState?: AnyDict, + ) => ReactNode); default?: V; + initialValue?: V; renderTrigger?: boolean; validators?: ControlValueValidator<T, O, V>[]; warning?: ReactNode; @@ -336,37 +366,43 @@ export type ControlSetRow = ControlSetItem[]; // - superset-frontend/src/explore/components/ControlPanelsContainer.jsx // - superset-frontend/src/explore/components/ControlPanelSection.jsx export interface ControlPanelSectionConfig { - label: ReactNode; + label?: ReactNode; description?: ReactNode; expanded?: boolean; tabOverride?: TabOverride; controlSetRows: ControlSetRow[]; } -export interface StandardizedState { +export interface StandardizedControls { metrics: QueryFormMetric[]; columns: QueryFormColumn[]; } export interface StandardizedFormDataInterface { - standardizedState: StandardizedState; + // Controls not used in the current viz + controls: StandardizedControls; + // Transformation history memorizedFormData: Map<string, QueryFormData>; } +export type QueryStandardizedFormData = QueryFormData & { + standardizedFormData: StandardizedFormDataInterface; +}; + +export const isStandardizedFormData = ( + formData: QueryFormData, +): formData is QueryStandardizedFormData => + formData?.standardizedFormData?.controls && + formData?.standardizedFormData?.memorizedFormData && + Array.isArray(formData.standardizedFormData.controls.metrics) && + Array.isArray(formData.standardizedFormData.controls.columns); + export interface ControlPanelConfig { controlPanelSections: (ControlPanelSectionConfig | null)[]; controlOverrides?: ControlOverrides; sectionOverrides?: SectionOverrides; onInit?: (state: ControlStateMapping) => void; - denormalizeFormData?: ( - formData: QueryFormData & { - standardizedFormData: StandardizedFormDataInterface; - }, - ) => QueryFormData; - updateStandardizedState?: ( - prevState: StandardizedState, - currState: StandardizedState, - ) => StandardizedState; + formDataOverrides?: (formData: QueryFormData) => QueryFormData; } export type ControlOverrides = { @@ -416,10 +452,8 @@ export type ColorFormatters = { export default {}; -export function isColumnMeta( - column: AdhocColumn | ColumnMeta, -): column is ColumnMeta { - return 'column_name' in column; +export function isColumnMeta(column: AnyDict): column is ColumnMeta { + return !!column && 'column_name' in column; } export function isSavedExpression( @@ -430,12 +464,6 @@ export function isSavedExpression( ); } -export function isAdhocColumn( - column: AdhocColumn | ColumnMeta, -): column is AdhocColumn { - return 'label' in column && 'sqlExpression' in column; -} - export function isControlPanelSectionConfig( section: ControlPanelSectionConfig | null, ): section is ControlPanelSectionConfig { @@ -451,9 +479,5 @@ export function isDataset( export function isQueryResponse( datasource: Dataset | QueryResponse | null | undefined, ): datasource is QueryResponse { - return ( - !!datasource && - ('results' in datasource || - datasource?.type === ('query' as DatasourceType.Query)) - ); + return !!datasource && 'results' in datasource && 'sql' in datasource; } diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts b/superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts index 0e30f82d7b44e..be703f9734fbf 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts @@ -23,6 +23,13 @@ export const D3_FORMAT_DOCS = t( 'D3 format syntax: https://github.com/d3/d3-format', ); +export const D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT = t( + 'Only applies when "Label Type" is set to show values.', +); +export const D3_NUMBER_FORMAT_DESCRIPTION_PERCENTAGE_TEXT = t( + 'Only applies when "Label Type" is not set to a percentage.', +); + // input choices & options export const D3_FORMAT_OPTIONS: [string, string][] = [ [NumberFormats.SMART_NUMBER, t('Adaptive formatting')], diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/utils/expandControlConfig.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/utils/expandControlConfig.tsx index d06ad0d5127da..3ff734984145d 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/utils/expandControlConfig.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/utils/expandControlConfig.tsx @@ -17,8 +17,7 @@ * under the License. */ import React, { ReactElement } from 'react'; -import { sharedControls } from '../shared-controls'; -import sharedControlComponents from '../shared-controls/components'; +import { sharedControls, sharedControlComponents } from '../shared-controls'; import { ControlType, ControlSetItem, @@ -75,7 +74,7 @@ export function expandControlConfig( // { // name: 'metric', // config: { - // type: 'SelectControl' | SelectComonent + // type: 'SelectControl' | SelectComponent // } // } if ('name' in control && 'config' in control) { diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/utils/getStandardizedControls.ts b/superset-frontend/packages/superset-ui-chart-controls/src/utils/getStandardizedControls.ts new file mode 100644 index 0000000000000..42ff874c588d4 --- /dev/null +++ b/superset-frontend/packages/superset-ui-chart-controls/src/utils/getStandardizedControls.ts @@ -0,0 +1,68 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { makeSingleton, QueryFormData } from '@superset-ui/core'; +import { isStandardizedFormData, StandardizedControls } from '../types'; + +class StandardizedControlsManager { + controls: StandardizedControls; + + constructor() { + this.controls = { + metrics: [], + columns: [], + }; + } + + setStandardizedControls(formData: QueryFormData) { + if (isStandardizedFormData(formData)) { + const { controls } = formData.standardizedFormData; + this.controls = { + metrics: controls.metrics, + columns: controls.columns, + }; + } + } + + shiftMetric() { + return this.controls.metrics.shift(); + } + + shiftColumn() { + return this.controls.columns.shift(); + } + + popAllMetrics() { + return this.controls.metrics.splice(0, this.controls.metrics.length); + } + + popAllColumns() { + return this.controls.columns.splice(0, this.controls.columns.length); + } + + clear() { + this.controls = { + metrics: [], + columns: [], + }; + } +} + +export const getStandardizedControls = makeSingleton( + StandardizedControlsManager, +); diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/utils/getTemporalColumns.ts b/superset-frontend/packages/superset-ui-chart-controls/src/utils/getTemporalColumns.ts new file mode 100644 index 0000000000000..718308d241a6e --- /dev/null +++ b/superset-frontend/packages/superset-ui-chart-controls/src/utils/getTemporalColumns.ts @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + ensureIsArray, + isDefined, + QueryColumn, + ValueOf, +} from '@superset-ui/core'; +import { + ColumnMeta, + ControlPanelState, + isDataset, + isQueryResponse, +} from '@superset-ui/chart-controls'; + +export function getTemporalColumns( + datasource: ValueOf<Pick<ControlPanelState, 'datasource'>>, +) { + const rv: { + temporalColumns: ColumnMeta[] | QueryColumn[]; + defaultTemporalColumn: string | null | undefined; + } = { + temporalColumns: [], + defaultTemporalColumn: undefined, + }; + + if (isDataset(datasource)) { + rv.temporalColumns = ensureIsArray(datasource.columns).filter( + c => c.is_dttm, + ); + } + if (isQueryResponse(datasource)) { + rv.temporalColumns = ensureIsArray(datasource.columns).filter( + c => c.is_dttm, + ); + } + + if (isDataset(datasource)) { + rv.defaultTemporalColumn = datasource.main_dttm_col; + } + if (!isDefined(rv.defaultTemporalColumn)) { + rv.defaultTemporalColumn = + (rv.temporalColumns[0] as ColumnMeta)?.column_name ?? + (rv.temporalColumns[0] as QueryColumn)?.name; + } + + return rv; +} + +export function isTemporalColumn( + columnName: string, + datasource: ValueOf<Pick<ControlPanelState, 'datasource'>>, +): boolean { + const columns = getTemporalColumns(datasource).temporalColumns; + for (let i = 0; i < columns.length; i += 1) { + if (columns[i].column_name === columnName) { + return true; + } + } + return false; +} diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/utils/index.ts b/superset-frontend/packages/superset-ui-chart-controls/src/utils/index.ts index 11c03e4ca1fac..4fa4243c1e850 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/utils/index.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/utils/index.ts @@ -23,3 +23,5 @@ export * from './getColorFormatters'; export { default as mainMetric } from './mainMetric'; export { default as columnChoices } from './columnChoices'; export * from './defineSavedMetrics'; +export * from './getStandardizedControls'; +export * from './getTemporalColumns'; diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/operators/pivotOperator.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/operators/pivotOperator.test.ts index 326b7edd85730..2a527a04fe544 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/operators/pivotOperator.test.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/test/operators/pivotOperator.test.ts @@ -28,6 +28,7 @@ const formData: SqlaFormData = { granularity: 'month', datasource: 'foo', viz_type: 'table', + show_empty_columns: true, }; const queryObject: QueryObject = { metrics: [ @@ -55,21 +56,20 @@ const queryObject: QueryObject = { test('skip pivot', () => { expect(pivotOperator(formData, queryObject)).toEqual(undefined); - expect( - pivotOperator(formData, { ...queryObject, is_timeseries: false }), - ).toEqual(undefined); expect( pivotOperator(formData, { ...queryObject, - is_timeseries: true, metrics: [], }), ).toEqual(undefined); }); -test('pivot by __timestamp without groupby', () => { +test('pivot by __timestamp without columns', () => { expect( - pivotOperator(formData, { ...queryObject, is_timeseries: true }), + pivotOperator( + { ...formData, granularity_sqla: 'time_column' }, + queryObject, + ), ).toEqual({ operation: 'pivot', options: { @@ -80,19 +80,42 @@ test('pivot by __timestamp without groupby', () => { 'sum(val)': { operator: 'mean' }, }, drop_missing_columns: false, - flatten_columns: false, - reset_index: false, }, }); }); -test('pivot by __timestamp with groupby', () => { +test('pivot by __timestamp with columns', () => { expect( - pivotOperator(formData, { - ...queryObject, + pivotOperator( + { ...formData, granularity_sqla: 'time_column' }, + { + ...queryObject, + columns: ['foo', 'bar'], + }, + ), + ).toEqual({ + operation: 'pivot', + options: { + index: ['__timestamp'], columns: ['foo', 'bar'], - is_timeseries: true, - }), + aggregates: { + 'count(*)': { operator: 'mean' }, + 'sum(val)': { operator: 'mean' }, + }, + drop_missing_columns: false, + }, + }); +}); + +test('pivot by __timestamp with series_columns', () => { + expect( + pivotOperator( + { ...formData, granularity_sqla: 'time_column' }, + { + ...queryObject, + series_columns: ['foo', 'bar'], + }, + ), ).toEqual({ operation: 'pivot', options: { @@ -103,8 +126,6 @@ test('pivot by __timestamp with groupby', () => { 'sum(val)': { operator: 'mean' }, }, drop_missing_columns: false, - flatten_columns: false, - reset_index: false, }, }); }); @@ -118,7 +139,7 @@ test('pivot by x_axis with groupby', () => { }, { ...queryObject, - columns: ['foo', 'bar'], + series_columns: ['foo', 'bar'], }, ), ).toEqual({ @@ -131,8 +152,6 @@ test('pivot by x_axis with groupby', () => { 'sum(val)': { operator: 'mean' }, }, drop_missing_columns: false, - flatten_columns: false, - reset_index: false, }, }); }); @@ -145,12 +164,12 @@ test('pivot by adhoc x_axis', () => { x_axis: { label: 'my_case_expr', expressionType: 'SQL', - expression: 'case when a = 1 then 1 else 0 end', + sqlExpression: 'case when a = 1 then 1 else 0 end', }, }, { ...queryObject, - columns: ['foo', 'bar'], + series_columns: ['foo', 'bar'], }, ), ).toEqual({ @@ -163,8 +182,6 @@ test('pivot by adhoc x_axis', () => { 'sum(val)': { operator: 'mean' }, }, drop_missing_columns: false, - flatten_columns: false, - reset_index: false, }, }); }); diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/operators/prophetOperator.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/operators/prophetOperator.test.ts index 824efe5c15cc5..9613584f8e7b6 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/operators/prophetOperator.test.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/test/operators/prophetOperator.test.ts @@ -47,6 +47,7 @@ test('should do prophetOperator with default index', () => { prophetOperator( { ...formData, + granularity_sqla: 'time_column', forecastEnabled: true, forecastPeriods: '3', forecastInterval: '5', @@ -107,7 +108,7 @@ test('should do prophetOperator over adhoc column', () => { x_axis: { label: 'my_case_expr', expressionType: 'SQL', - expression: 'case when a = 1 then 1 else 0 end', + sqlExpression: 'case when a = 1 then 1 else 0 end', }, forecastEnabled: true, forecastPeriods: '3', diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/operators/renameOperator.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/operators/renameOperator.test.ts index 26bbe9e3695cc..af9ebfebb3f00 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/operators/renameOperator.test.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/test/operators/renameOperator.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { ComparisionType, QueryObject, SqlaFormData } from '@superset-ui/core'; +import { ComparisonType, QueryObject, SqlaFormData } from '@superset-ui/core'; import { renameOperator } from '@superset-ui/chart-controls'; const formData: SqlaFormData = { @@ -49,7 +49,7 @@ test('should skip renameOperator if exists multiple metrics', () => { ).toEqual(undefined); }); -test('should skip renameOperator if does not exist series', () => { +test('should skip renameOperator if series does not exist', () => { expect( renameOperator(formData, { ...queryObject, @@ -74,9 +74,9 @@ test('should skip renameOperator if does not exist x_axis and is_timeseries', () test('should skip renameOperator if exists derived metrics', () => { [ - ComparisionType.Difference, - ComparisionType.Ratio, - ComparisionType.Percentage, + ComparisonType.Difference, + ComparisonType.Ratio, + ComparisonType.Percentage, ].forEach(type => { expect( renameOperator( @@ -105,12 +105,12 @@ test('should add renameOperator', () => { }); }); -test('should add renameOperator if does not exist x_axis', () => { +test('should add renameOperator if x_axis does not exist', () => { expect( renameOperator( { ...formData, - ...{ x_axis: null }, + ...{ x_axis: null, granularity_sqla: 'time column' }, }, queryObject, ), @@ -120,13 +120,32 @@ test('should add renameOperator if does not exist x_axis', () => { }); }); +test('should add renameOperator if based on series_columns', () => { + expect( + renameOperator( + { + ...formData, + ...{ x_axis: null, granularity_sqla: 'time column' }, + }, + { + ...queryObject, + columns: [], + series_columns: ['gender', 'dttm'], + }, + ), + ).toEqual({ + operation: 'rename', + options: { columns: { 'count(*)': null }, inplace: true, level: 0 }, + }); +}); + test('should add renameOperator if exist "actual value" time comparison', () => { expect( renameOperator( { ...formData, ...{ - comparison_type: ComparisionType.Values, + comparison_type: ComparisonType.Values, time_compare: ['1 year ago', '1 year later'], }, }, diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/operators/rollingWindowOperator.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/operators/rollingWindowOperator.test.ts index 5bd37a4d9c763..374f5c620208c 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/operators/rollingWindowOperator.test.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/test/operators/rollingWindowOperator.test.ts @@ -107,8 +107,8 @@ test('rolling_type: sum/mean/std', () => { }); test('should append compared metrics when sets time compare type', () => { - const comparisionTypes = ['values', 'difference', 'percentage', 'ratio']; - comparisionTypes.forEach(cType => { + const comparisonTypes = ['values', 'difference', 'percentage', 'ratio']; + comparisonTypes.forEach(cType => { expect( rollingWindowOperator( { diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/operators/sortOperator.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/operators/sortOperator.test.ts index 6f0267d91305e..750d726c902af 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/operators/sortOperator.test.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/test/operators/sortOperator.test.ts @@ -18,6 +18,7 @@ */ import { QueryObject, SqlaFormData } from '@superset-ui/core'; import { sortOperator } from '@superset-ui/chart-controls'; +import * as supersetCoreModule from '@superset-ui/core'; const formData: SqlaFormData = { metrics: [ @@ -52,92 +53,96 @@ const queryObject: QueryObject = { ], }; -test('skip sort', () => { +test('should ignore the sortOperator', () => { + // FF is disabled + Object.defineProperty(supersetCoreModule, 'hasGenericChartAxes', { + value: false, + }); expect(sortOperator(formData, queryObject)).toEqual(undefined); - expect( - sortOperator(formData, { ...queryObject, is_timeseries: false }), - ).toEqual(undefined); + + // FF is enabled + Object.defineProperty(supersetCoreModule, 'hasGenericChartAxes', { + value: true, + }); expect( sortOperator( - { ...formData, rolling_type: 'xxxx' }, - { ...queryObject, is_timeseries: true }, + { + ...formData, + ...{ + x_axis_sort: undefined, + x_axis_sort_asc: true, + }, + }, + queryObject, ), ).toEqual(undefined); - expect( - sortOperator(formData, { ...queryObject, is_timeseries: true }), - ).toEqual(undefined); -}); -test('sort by __timestamp', () => { - expect( - sortOperator( - { ...formData, rolling_type: 'cumsum' }, - { ...queryObject, is_timeseries: true }, - ), - ).toEqual({ - operation: 'sort', - options: { - columns: { - __timestamp: true, - }, - }, + // sortOperator doesn't support multiple series + Object.defineProperty(supersetCoreModule, 'hasGenericChartAxes', { + value: true, }); - expect( sortOperator( - { ...formData, rolling_type: 'sum' }, - { ...queryObject, is_timeseries: true }, - ), - ).toEqual({ - operation: 'sort', - options: { - columns: { - __timestamp: true, + { + ...formData, + ...{ + x_axis_sort: 'metric label', + x_axis_sort_asc: true, + groupby: ['col1'], + x_axis: 'axis column', + }, }, - }, - }); - - expect( - sortOperator( - { ...formData, rolling_type: 'mean' }, - { ...queryObject, is_timeseries: true }, + queryObject, ), - ).toEqual({ - operation: 'sort', - options: { - columns: { - __timestamp: true, - }, - }, - }); + ).toEqual(undefined); +}); +test('should sort by metric', () => { + Object.defineProperty(supersetCoreModule, 'hasGenericChartAxes', { + value: true, + }); expect( sortOperator( - { ...formData, rolling_type: 'std' }, - { ...queryObject, is_timeseries: true }, + { + ...formData, + ...{ + metrics: ['a metric label'], + x_axis_sort: 'a metric label', + x_axis_sort_asc: true, + }, + }, + queryObject, ), ).toEqual({ operation: 'sort', options: { - columns: { - __timestamp: true, - }, + by: 'a metric label', + ascending: true, }, }); }); -test('sort by named x-axis', () => { +test('should sort by axis', () => { + Object.defineProperty(supersetCoreModule, 'hasGenericChartAxes', { + value: true, + }); expect( sortOperator( - { ...formData, x_axis: 'ds', rolling_type: 'cumsum' }, - { ...queryObject }, + { + ...formData, + ...{ + x_axis_sort: 'Categorical Column', + x_axis_sort_asc: true, + x_axis: 'Categorical Column', + }, + }, + queryObject, ), ).toEqual({ operation: 'sort', options: { - columns: { - ds: true, - }, + is_sort_index: true, + ascending: true, }, }); }); diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/operators/timeCompareOperator.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/operators/timeCompareOperator.test.ts index a2e6b313801d3..e775780b3ee75 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/operators/timeCompareOperator.test.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/test/operators/timeCompareOperator.test.ts @@ -51,8 +51,6 @@ const queryObject: QueryObject = { }, }, drop_missing_columns: false, - flatten_columns: false, - reset_index: false, }, }, { @@ -92,8 +90,8 @@ test('should skip CompareOperator', () => { }); test('should generate difference/percentage/ratio CompareOperator', () => { - const comparisionTypes = ['difference', 'percentage', 'ratio']; - comparisionTypes.forEach(cType => { + const comparisonTypes = ['difference', 'percentage', 'ratio']; + comparisonTypes.forEach(cType => { expect( timeCompareOperator( { diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/operators/timeComparePivotOperator.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/operators/timeComparePivotOperator.test.ts index 4ce88cb9c1245..c41bcdd208ea5 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/operators/timeComparePivotOperator.test.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/test/operators/timeComparePivotOperator.test.ts @@ -31,6 +31,7 @@ const formData: SqlaFormData = { granularity: 'month', datasource: 'foo', viz_type: 'table', + show_empty_columns: true, }; const queryObject: QueryObject = { metrics: [ @@ -71,10 +72,10 @@ test('should pivot on any type of timeCompare', () => { ...formData, comparison_type: cType, time_compare: ['1 year ago', '1 year later'], + granularity_sqla: 'time_column', }, { ...queryObject, - is_timeseries: true, }, ), ).toEqual({ @@ -93,8 +94,6 @@ test('should pivot on any type of timeCompare', () => { }, }, drop_missing_columns: false, - flatten_columns: false, - reset_index: false, columns: ['foo', 'bar'], index: ['__timestamp'], }, @@ -133,8 +132,45 @@ test('should pivot on x-axis', () => { drop_missing_columns: false, columns: ['foo', 'bar'], index: ['ds'], - flatten_columns: false, - reset_index: false, + }, + }); +}); + +test('should pivot on x-axis with series_columns', () => { + expect( + timeComparePivotOperator( + { + ...formData, + comparison_type: 'values', + time_compare: ['1 year ago', '1 year later'], + x_axis: 'ds', + }, + { + ...queryObject, + columns: ['ds', 'foo', 'bar'], + series_columns: ['foo', 'bar'], + }, + ), + ).toEqual({ + operation: 'pivot', + options: { + aggregates: { + 'count(*)': { operator: 'mean' }, + 'count(*)__1 year ago': { operator: 'mean' }, + 'count(*)__1 year later': { operator: 'mean' }, + 'sum(val)': { + operator: 'mean', + }, + 'sum(val)__1 year ago': { + operator: 'mean', + }, + 'sum(val)__1 year later': { + operator: 'mean', + }, + }, + drop_missing_columns: false, + columns: ['foo', 'bar'], + index: ['ds'], }, }); }); @@ -149,7 +185,7 @@ test('should pivot on adhoc x-axis', () => { x_axis: { label: 'my_case_expr', expressionType: 'SQL', - expression: 'case when a = 1 then 1 else 0 end', + sqlExpression: 'case when a = 1 then 1 else 0 end', }, }, queryObject, @@ -174,8 +210,6 @@ test('should pivot on adhoc x-axis', () => { drop_missing_columns: false, columns: ['foo', 'bar'], index: ['my_case_expr'], - flatten_columns: false, - reset_index: false, }, }); }); diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/operators/utils/isDerivedSeries.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/operators/utils/isDerivedSeries.test.ts index 05a1d738abc89..29c8c658672ec 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/operators/utils/isDerivedSeries.test.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/test/operators/utils/isDerivedSeries.test.ts @@ -17,7 +17,7 @@ * under the License. */ import { isDerivedSeries } from '@superset-ui/chart-controls'; -import { SqlaFormData, ComparisionType } from '@superset-ui/core'; +import { SqlaFormData, ComparisonType } from '@superset-ui/core'; const formData: SqlaFormData = { datasource: 'foo', @@ -31,15 +31,15 @@ const series = { test('should be false if comparison type is not actual values', () => { expect(isDerivedSeries(series, formData)).toEqual(false); - Object.keys(ComparisionType) - .filter(type => type === ComparisionType.Values) + Object.keys(ComparisonType) + .filter(type => type === ComparisonType.Values) .forEach(type => { - const formDataWithComparisionType = { + const formDataWithComparisonType = { ...formData, comparison_type: type, time_compare: ['1 month ago'], }; - expect(isDerivedSeries(series, formDataWithComparisionType)).toEqual( + expect(isDerivedSeries(series, formDataWithComparisonType)).toEqual( false, ); }); @@ -48,7 +48,7 @@ test('should be false if comparison type is not actual values', () => { test('should be true if comparison type is values', () => { const formDataWithActualTypes = { ...formData, - comparison_type: ComparisionType.Values, + comparison_type: ComparisonType.Values, time_compare: ['1 month ago', '1 month later'], }; expect(isDerivedSeries(series, formDataWithActualTypes)).toEqual(true); @@ -62,7 +62,7 @@ test('should be false if series name does not match time_compare', () => { }; const formDataWithActualTypes = { ...formData, - comparison_type: ComparisionType.Values, + comparison_type: ComparisonType.Values, time_compare: ['1 month ago', '1 month later'], }; expect(isDerivedSeries(arbitrary_series, formDataWithActualTypes)).toEqual( @@ -78,7 +78,7 @@ test('should be false if time compare is not suffix', () => { }; const formDataWithActualTypes = { ...formData, - comparison_type: ComparisionType.Values, + comparison_type: ComparisonType.Values, time_compare: ['1 month ago', '1 month later'], }; expect(isDerivedSeries(series, formDataWithActualTypes)).toEqual(false); @@ -92,7 +92,7 @@ test('should be false if series name invalid', () => { }; const formDataWithActualTypes = { ...formData, - comparison_type: ComparisionType.Values, + comparison_type: ComparisonType.Values, time_compare: ['1 month ago', '1 month later'], }; expect(isDerivedSeries(series, formDataWithActualTypes)).toEqual(false); diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/types.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/types.test.ts index 5c53fbcf10c60..4a298645efc63 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/types.test.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/test/types.test.ts @@ -20,7 +20,6 @@ import { AdhocColumn } from '@superset-ui/core'; import { ColumnMeta, ControlPanelSectionConfig, - isAdhocColumn, isColumnMeta, isControlPanelSectionConfig, isSavedExpression, @@ -53,14 +52,6 @@ test('isColumnMeta returns true for ColumnMeta', () => { expect(isColumnMeta(COLUMN_META)).toEqual(true); }); -test('isAdhocColumn returns true for AdhocColumn', () => { - expect(isAdhocColumn(ADHOC_COLUMN)).toEqual(true); -}); - -test('isAdhocColumn returns false for ColumnMeta', () => { - expect(isAdhocColumn(COLUMN_META)).toEqual(false); -}); - test('isSavedExpression returns false for AdhocColumn', () => { expect(isSavedExpression(ADHOC_COLUMN)).toEqual(false); }); diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/utils/columnChoices.test.tsx b/superset-frontend/packages/superset-ui-chart-controls/test/utils/columnChoices.test.tsx index 3224bbcc26d5c..59f4796a44d21 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/utils/columnChoices.test.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/test/utils/columnChoices.test.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { DatasourceType, QueryResponse, testQuery } from '@superset-ui/core'; +import { DatasourceType, testQueryResponse } from '@superset-ui/core'; import { columnChoices } from '../../src'; describe('columnChoices()', () => { @@ -58,7 +58,7 @@ describe('columnChoices()', () => { }); it('should convert columns to choices when source is a Query', () => { - expect(columnChoices(testQuery as QueryResponse)).toEqual([ + expect(columnChoices(testQueryResponse)).toEqual([ ['Column 1', 'Column 1'], ['Column 2', 'Column 2'], ['Column 3', 'Column 3'], diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/utils/getStandardizedControls.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/utils/getStandardizedControls.test.ts new file mode 100644 index 0000000000000..8aaed01d7dd6c --- /dev/null +++ b/superset-frontend/packages/superset-ui-chart-controls/test/utils/getStandardizedControls.test.ts @@ -0,0 +1,82 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { QueryFormData } from '@superset-ui/core'; +import { getStandardizedControls } from '../../src'; + +const formData: QueryFormData = { + datasource: '30__table', + viz_type: 'table', + standardizedFormData: { + controls: { + metrics: ['count(*)', 'sum(sales)'], + columns: ['gender', 'gender'], + }, + memorizedFormData: [], + }, +}; + +test('without standardizedFormData', () => { + getStandardizedControls().setStandardizedControls({ + datasource: '30__table', + viz_type: 'table', + }); + expect(getStandardizedControls().controls).toEqual({ + metrics: [], + columns: [], + }); +}); + +test('getStandardizedControls', () => { + expect(getStandardizedControls().controls).toEqual({ + metrics: [], + columns: [], + }); + getStandardizedControls().setStandardizedControls(formData); + expect(getStandardizedControls().controls).toEqual({ + metrics: ['count(*)', 'sum(sales)'], + columns: ['gender', 'gender'], + }); + expect(getStandardizedControls().shiftMetric()).toEqual('count(*)'); + expect(getStandardizedControls().controls).toEqual({ + metrics: ['sum(sales)'], + columns: ['gender', 'gender'], + }); + expect(getStandardizedControls().popAllMetrics()).toEqual(['sum(sales)']); + expect(getStandardizedControls().controls).toEqual({ + metrics: [], + columns: ['gender', 'gender'], + }); + expect(getStandardizedControls().shiftColumn()).toEqual('gender'); + expect(getStandardizedControls().controls).toEqual({ + metrics: [], + columns: ['gender'], + }); + expect(getStandardizedControls().popAllColumns()).toEqual(['gender']); + expect(getStandardizedControls().controls).toEqual({ + metrics: [], + columns: [], + }); + + getStandardizedControls().setStandardizedControls(formData); + getStandardizedControls().clear(); + expect(getStandardizedControls().controls).toEqual({ + metrics: [], + columns: [], + }); +}); diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/utils/getTemporalColumns.test.ts b/superset-frontend/packages/superset-ui-chart-controls/test/utils/getTemporalColumns.test.ts new file mode 100644 index 0000000000000..1921540ea6046 --- /dev/null +++ b/superset-frontend/packages/superset-ui-chart-controls/test/utils/getTemporalColumns.test.ts @@ -0,0 +1,104 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { testQueryResponse, testQueryResults } from '@superset-ui/core'; +import { + Dataset, + getTemporalColumns, + isTemporalColumn, + TestDataset, +} from '../../src'; + +test('get temporal columns from a Dataset', () => { + expect(getTemporalColumns(TestDataset)).toEqual({ + temporalColumns: [ + { + advanced_data_type: undefined, + certification_details: null, + certified_by: null, + column_name: 'ds', + description: null, + expression: '', + filterable: true, + groupby: true, + id: 329, + is_certified: false, + is_dttm: true, + python_date_format: null, + type: 'TIMESTAMP WITHOUT TIME ZONE', + type_generic: 2, + verbose_name: null, + warning_markdown: null, + }, + ], + defaultTemporalColumn: 'ds', + }); +}); + +test('get temporal columns from a QueryResponse', () => { + expect(getTemporalColumns(testQueryResponse)).toEqual({ + temporalColumns: [ + { + name: 'Column 2', + type: 'TIMESTAMP', + is_dttm: true, + }, + ], + defaultTemporalColumn: 'Column 2', + }); +}); + +test('get temporal columns from null', () => { + expect(getTemporalColumns(null)).toEqual({ + temporalColumns: [], + defaultTemporalColumn: undefined, + }); +}); + +test('should accept empty Dataset or queryResponse', () => { + expect( + getTemporalColumns({ + ...TestDataset, + ...{ + columns: [], + main_dttm_col: undefined, + }, + } as any as Dataset), + ).toEqual({ + temporalColumns: [], + defaultTemporalColumn: undefined, + }); + + expect( + getTemporalColumns({ + ...testQueryResponse, + ...{ + columns: [], + results: { ...testQueryResults.results, ...{ columns: [] } }, + }, + }), + ).toEqual({ + temporalColumns: [], + defaultTemporalColumn: undefined, + }); +}); + +test('should determine temporal columns in a Dataset', () => { + expect(isTemporalColumn('ds', TestDataset)).toBeTruthy(); + expect(isTemporalColumn('num', TestDataset)).toBeFalsy(); +}); diff --git a/superset-frontend/packages/superset-ui-core/package.json b/superset-frontend/packages/superset-ui-core/package.json index 2d8df251619ca..2ccb9877fdf7a 100644 --- a/superset-frontend/packages/superset-ui-core/package.json +++ b/superset-frontend/packages/superset-ui-core/package.json @@ -31,6 +31,7 @@ "@types/d3-time-format": "^2.1.0", "@types/enzyme": "^3.10.5", "@types/fetch-mock": "^7.3.3", + "@types/json-bigint": "^1.0.1", "@types/lodash": "^4.14.149", "@types/math-expression-evaluator": "^1.2.1", "@types/node": "^18.0.0", diff --git a/superset-frontend/packages/superset-ui-core/src/api/types/core.ts b/superset-frontend/packages/superset-ui-core/src/api/types/core.ts new file mode 100644 index 0000000000000..9aeba85accc95 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/api/types/core.ts @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// /superset/sqllab_viz +interface SqlLabPostRequest { + data: { + schema: string; + sql: string; + dbId: number; + templateParams?: string | undefined; + datasourceName: string; + metrics?: string[]; + columns?: string[]; + }; +} diff --git a/superset-frontend/packages/superset-ui-core/src/chart/components/FallbackComponent.tsx b/superset-frontend/packages/superset-ui-core/src/chart/components/FallbackComponent.tsx index 5c22f920824e8..f7dcd8306e649 100644 --- a/superset-frontend/packages/superset-ui-core/src/chart/components/FallbackComponent.tsx +++ b/superset-frontend/packages/superset-ui-core/src/chart/components/FallbackComponent.tsx @@ -18,6 +18,7 @@ */ import React from 'react'; +import { t } from '@superset-ui/core'; import { SupersetTheme } from '../../style'; import { FallbackPropsWithDimension } from './SuperChart'; @@ -41,13 +42,13 @@ export default function FallbackComponent({ > <div> <div> - <b>Oops! An error occurred!</b> + <b>{t('Oops! An error occurred!')}</b> </div> <code>{error ? error.toString() : 'Unknown Error'}</code> </div> {componentStack && ( <div> - <b>Stack Trace:</b> + <b>{t('Stack Trace:')}</b> <code> {componentStack.split('\n').map((row: string) => ( <div key={row}>{row}</div> diff --git a/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx b/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx index 9a6240daff713..99d7b6dbec7aa 100644 --- a/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx +++ b/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx @@ -26,6 +26,7 @@ import { ParentSize } from '@vx/responsive'; import { createSelector } from 'reselect'; import { withTheme } from '@emotion/react'; import { parseLength, Dimension } from '../../dimension'; +import getChartMetadataRegistry from '../registries/ChartMetadataRegistrySingleton'; import SuperChartCore, { Props as SuperChartCoreProps } from './SuperChartCore'; import DefaultFallbackComponent from './FallbackComponent'; import ChartProps, { ChartPropsConfig } from '../models/ChartProps'; @@ -60,7 +61,7 @@ export type Props = Omit<SuperChartCoreProps, 'chartProps'> & FallbackComponent?: React.ComponentType<FallbackPropsWithDimension>; /** Event listener for unexpected errors from chart */ onErrorBoundary?: ErrorBoundaryProps['onError']; - /** Prop for form plugins uisng superchart */ + /** Prop for form plugins using superchart */ showOverflow?: boolean; /** Prop for popovercontainer ref */ parentRef?: RefObject<any>; @@ -140,6 +141,9 @@ class SuperChart extends React.PureComponent<Props, {}> { this.core = core; }; + private getQueryCount = () => + getChartMetadataRegistry().get(this.props.chartType)?.queryObjectCount ?? 1; + renderChart(width: number, height: number) { const { id, @@ -174,9 +178,11 @@ class SuperChart extends React.PureComponent<Props, {}> { const noResultQueries = enableNoResults && (!queriesData || - queriesData.every( - ({ data }) => !data || (Array.isArray(data) && data.length === 0), - )); + queriesData + .slice(0, this.getQueryCount()) + .every( + ({ data }) => !data || (Array.isArray(data) && data.length === 0), + )); if (noResultQueries) { chart = noResults || ( <NoResultsComponent diff --git a/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChartCore.tsx b/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChartCore.tsx index 10e4cd18e6827..d818890aa552a 100644 --- a/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChartCore.tsx +++ b/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChartCore.tsx @@ -19,6 +19,7 @@ /* eslint-disable react/jsx-sort-default-props */ import * as React from 'react'; +import { t } from '@superset-ui/core'; import { createSelector } from 'reselect'; import getChartComponentRegistry from '../registries/ChartComponentRegistrySingleton'; import getChartTransformPropsRegistry from '../registries/ChartTransformPropsRegistrySingleton'; @@ -167,7 +168,7 @@ export default class SuperChartCore extends React.PureComponent<Props, {}> { if (error) { return ( <div className="alert alert-warning" role="alert"> - <strong>ERROR</strong>  + <strong>{t('ERROR')}</strong>  <code>chartType="{chartType}"</code> — {error.toString()} </div> diff --git a/superset-frontend/packages/superset-ui-core/src/chart/models/ChartMetadata.ts b/superset-frontend/packages/superset-ui-core/src/chart/models/ChartMetadata.ts index 7a25fe86208d1..1d55d2a9859f0 100644 --- a/superset-frontend/packages/superset-ui-core/src/chart/models/ChartMetadata.ts +++ b/superset-frontend/packages/superset-ui-core/src/chart/models/ChartMetadata.ts @@ -48,6 +48,7 @@ export interface ChartMetadataConfig { // label: ChartLabel.DEPRECATED which will display a "deprecated" label on the chart. label?: ChartLabel | null; labelExplanation?: string | null; + queryObjectCount?: number; } export default class ChartMetadata { @@ -87,6 +88,8 @@ export default class ChartMetadata { labelExplanation?: string | null; + queryObjectCount: number; + constructor(config: ChartMetadataConfig) { const { name, @@ -106,6 +109,7 @@ export default class ChartMetadata { deprecated = false, label = null, labelExplanation = null, + queryObjectCount = 1, } = config; this.name = name; @@ -134,6 +138,7 @@ export default class ChartMetadata { this.deprecated = deprecated; this.label = label; this.labelExplanation = labelExplanation; + this.queryObjectCount = queryObjectCount; } canBeAnnotationType(type: string): boolean { diff --git a/superset-frontend/packages/superset-ui-core/src/chart/models/ChartProps.ts b/superset-frontend/packages/superset-ui-core/src/chart/models/ChartProps.ts index e673817118102..e02aeca4f54de 100644 --- a/superset-frontend/packages/superset-ui-core/src/chart/models/ChartProps.ts +++ b/superset-frontend/packages/superset-ui-core/src/chart/models/ChartProps.ts @@ -50,6 +50,8 @@ type Hooks = { * also handles "change" and "remove". */ onAddFilter?: (newFilters: DataRecordFilters, merge?: boolean) => void; + /** handle right click */ + onContextMenu?: HandlerFunction; /** handle errors */ onError?: HandlerFunction; /** use the vis as control to update state */ @@ -88,6 +90,8 @@ export interface ChartPropsConfig { filterState?: FilterState; /** Set of actual behaviors that this instance of chart should use */ behaviors?: Behavior[]; + /** Chart display settings related to current view context */ + displaySettings?: JsonObject; /** Application section of the chart on the screen (in what components/screen it placed) */ appSection?: AppSection; /** is the chart refreshing its contents */ @@ -130,12 +134,18 @@ export default class ChartProps<FormData extends RawFormData = RawFormData> { behaviors: Behavior[]; + displaySettings?: JsonObject; + appSection?: AppSection; isRefreshing?: boolean; inputRef?: RefObject<any>; + inContextMenu?: boolean; + + emitCrossFilters?: boolean; + theme: SupersetTheme; constructor(config: ChartPropsConfig & { formData?: FormData } = {}) { @@ -149,11 +159,14 @@ export default class ChartProps<FormData extends RawFormData = RawFormData> { initialValues = {}, queriesData = [], behaviors = [], + displaySettings = {}, width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT, appSection, isRefreshing, inputRef, + inContextMenu = false, + emitCrossFilters = false, theme, } = config; this.width = width; @@ -169,9 +182,12 @@ export default class ChartProps<FormData extends RawFormData = RawFormData> { this.ownState = ownState; this.filterState = filterState; this.behaviors = behaviors; + this.displaySettings = displaySettings; this.appSection = appSection; this.isRefreshing = isRefreshing; this.inputRef = inputRef; + this.inContextMenu = inContextMenu; + this.emitCrossFilters = emitCrossFilters; this.theme = theme; } } @@ -190,9 +206,12 @@ ChartProps.createSelector = function create(): ChartPropsSelector { input => input.ownState, input => input.filterState, input => input.behaviors, + input => input.displaySettings, input => input.appSection, input => input.isRefreshing, input => input.inputRef, + input => input.inContextMenu, + input => input.emitCrossFilters, input => input.theme, ( annotationData, @@ -206,9 +225,12 @@ ChartProps.createSelector = function create(): ChartPropsSelector { ownState, filterState, behaviors, + displaySettings, appSection, isRefreshing, inputRef, + inContextMenu, + emitCrossFilters, theme, ) => new ChartProps({ @@ -223,9 +245,12 @@ ChartProps.createSelector = function create(): ChartPropsSelector { filterState, width, behaviors, + displaySettings, appSection, isRefreshing, inputRef, + inContextMenu, + emitCrossFilters, theme, }), ); diff --git a/superset-frontend/packages/superset-ui-core/src/chart/types/Base.ts b/superset-frontend/packages/superset-ui-core/src/chart/types/Base.ts index 0bfae7777e7df..f9f1a360b6273 100644 --- a/superset-frontend/packages/superset-ui-core/src/chart/types/Base.ts +++ b/superset-frontend/packages/superset-ui-core/src/chart/types/Base.ts @@ -25,6 +25,12 @@ export type HandlerFunction = (...args: unknown[]) => void; export enum Behavior { INTERACTIVE_CHART = 'INTERACTIVE_CHART', NATIVE_FILTER = 'NATIVE_FILTER', + + /** + * Include `DRILL_TO_DETAIL` behavior if plugin handles `contextmenu` event + * when dimensions are right-clicked on. + */ + DRILL_TO_DETAIL = 'DRILL_TO_DETAIL', } export enum AppSection { @@ -73,4 +79,11 @@ export const chartLabelWeight: Record<ChartLabel, { weight: number }> = { }, }; +export enum AxisType { + category = 'category', + value = 'value', + time = 'time', + log = 'log', +} + export default {}; diff --git a/superset-frontend/packages/superset-ui-core/src/color/CategoricalColorScale.ts b/superset-frontend/packages/superset-ui-core/src/color/CategoricalColorScale.ts index 2a6a4d63a0473..5f29ad4775996 100644 --- a/superset-frontend/packages/superset-ui-core/src/color/CategoricalColorScale.ts +++ b/superset-frontend/packages/superset-ui-core/src/color/CategoricalColorScale.ts @@ -51,7 +51,7 @@ class CategoricalColorScale extends ExtensibleFunction { * @param {*} parentForcedColors optional parameter that comes from parent * (usually CategoricalColorNamespace) and supersede this.forcedColors */ - constructor(colors: string[], parentForcedColors?: ColorsLookup) { + constructor(colors: string[], parentForcedColors: ColorsLookup = {}) { super((value: string, sliceId?: number) => this.getColor(value, sliceId)); this.originColors = colors; @@ -67,18 +67,11 @@ class CategoricalColorScale extends ExtensibleFunction { const cleanedValue = stringifyAndTrim(value); const sharedLabelColor = getSharedLabelColor(); - const parentColor = - this.parentForcedColors && this.parentForcedColors[cleanedValue]; - if (parentColor) { - sharedLabelColor.addSlice(cleanedValue, parentColor, sliceId); - return parentColor; - } - - const forcedColor = this.forcedColors[cleanedValue]; - if (forcedColor) { - sharedLabelColor.addSlice(cleanedValue, forcedColor, sliceId); - return forcedColor; - } + // priority: parentForcedColors > forcedColors > labelColors + let color = + this.parentForcedColors?.[cleanedValue] || + this.forcedColors?.[cleanedValue] || + sharedLabelColor.getColorMap().get(cleanedValue); if (isFeatureEnabled(FeatureFlag.USE_ANALAGOUS_COLORS)) { const multiple = Math.floor( @@ -90,8 +83,10 @@ class CategoricalColorScale extends ExtensibleFunction { this.range(this.originColors.concat(newRange)); } } - - const color = this.scale(cleanedValue); + const newColor = this.scale(cleanedValue); + if (!color) { + color = newColor; + } sharedLabelColor.addSlice(cleanedValue, color, sliceId); return color; diff --git a/superset-frontend/packages/superset-ui-core/src/color/ColorSchemeRegistry.ts b/superset-frontend/packages/superset-ui-core/src/color/ColorSchemeRegistry.ts index d36b598bcd0c3..e270ff6f0ef9d 100644 --- a/superset-frontend/packages/superset-ui-core/src/color/ColorSchemeRegistry.ts +++ b/superset-frontend/packages/superset-ui-core/src/color/ColorSchemeRegistry.ts @@ -28,7 +28,16 @@ export default class ColorSchemeRegistry<T> extends RegistryWithDefaultKey<T> { }); } - get(key?: string) { - return super.get(key) as T | undefined; + get(key?: string, strict = false) { + const target = super.get(key) as T | undefined; + + // fallsback to default scheme if any + if (!strict && !target) { + const defaultKey = super.getDefaultKey(); + if (defaultKey) { + return super.get(defaultKey) as T | undefined; + } + } + return target; } } diff --git a/superset-frontend/packages/superset-ui-core/src/color/SharedLabelColorSingleton.ts b/superset-frontend/packages/superset-ui-core/src/color/SharedLabelColorSingleton.ts index 10a14df075910..bc417e6036a51 100644 --- a/superset-frontend/packages/superset-ui-core/src/color/SharedLabelColorSingleton.ts +++ b/superset-frontend/packages/superset-ui-core/src/color/SharedLabelColorSingleton.ts @@ -18,113 +18,81 @@ */ import { CategoricalColorNamespace } from '.'; -import { FeatureFlag, isFeatureEnabled, makeSingleton } from '../utils'; -import { getAnalogousColors } from './utils'; +import { makeSingleton } from '../utils'; +export enum SharedLabelColorSource { + dashboard, + explore, +} export class SharedLabelColor { - sliceLabelColorMap: Record<number, Record<string, string | undefined>>; + sliceLabelMap: Map<number, string[]>; - constructor() { - // { sliceId1: { label1: color1 }, sliceId2: { label2: color2 } } - this.sliceLabelColorMap = {}; - } + colorMap: Map<string, string>; - getColorMap( - colorNamespace?: string, - colorScheme?: string, - updateColorScheme?: boolean, - ) { - if (colorScheme) { - const categoricalNamespace = - CategoricalColorNamespace.getNamespace(colorNamespace); - const sharedLabels = this.getSharedLabels(); - let generatedColors: string[] = []; - let sharedLabelMap; + source: SharedLabelColorSource; - if (sharedLabels.length) { - const colorScale = categoricalNamespace.getScale(colorScheme); - const colors = colorScale.range(); - if (isFeatureEnabled(FeatureFlag.USE_ANALAGOUS_COLORS)) { - const multiple = Math.ceil(sharedLabels.length / colors.length); - generatedColors = getAnalogousColors(colors, multiple); - sharedLabelMap = sharedLabels.reduce( - (res, label, index) => ({ - ...res, - [label.toString()]: generatedColors[index], - }), - {}, - ); - } else { - // reverse colors to reduce color conflicts - colorScale.range(colors.reverse()); - sharedLabelMap = sharedLabels.reduce( - (res, label) => ({ - ...res, - [label.toString()]: colorScale(label), - }), - {}, - ); - } - } + constructor() { + // { sliceId1: [label1, label2, ...], sliceId2: [label1, label2, ...] } + this.sliceLabelMap = new Map(); + this.colorMap = new Map(); + this.source = SharedLabelColorSource.dashboard; + } - const labelMap = Object.keys(this.sliceLabelColorMap).reduce( - (res, sliceId) => { - // get new color scale instance - const colorScale = categoricalNamespace.getScale(colorScheme); - return { - ...res, - ...Object.keys(this.sliceLabelColorMap[sliceId]).reduce( - (res, label) => ({ - ...res, - [label]: updateColorScheme - ? colorScale(label) - : this.sliceLabelColorMap[sliceId][label], - }), - {}, - ), - }; - }, - {}, - ); + updateColorMap(colorNamespace?: string, colorScheme?: string) { + const categoricalNamespace = + CategoricalColorNamespace.getNamespace(colorNamespace); + const newColorMap = new Map(); + this.colorMap.clear(); + this.sliceLabelMap.forEach(labels => { + const colorScale = categoricalNamespace.getScale(colorScheme); + labels.forEach(label => { + const newColor = colorScale(label); + newColorMap.set(label, newColor); + }); + }); + this.colorMap = newColorMap; + } - return { - ...labelMap, - ...sharedLabelMap, - }; - } - return undefined; + getColorMap() { + return this.colorMap; } addSlice(label: string, color: string, sliceId?: number) { - if (!sliceId) return; - this.sliceLabelColorMap[sliceId] = { - ...this.sliceLabelColorMap[sliceId], - [label]: color, - }; + if ( + this.source !== SharedLabelColorSource.dashboard || + sliceId === undefined + ) + return; + const labels = this.sliceLabelMap.get(sliceId) || []; + if (!labels.includes(label)) { + labels.push(label); + this.sliceLabelMap.set(sliceId, labels); + } + this.colorMap.set(label, color); } removeSlice(sliceId: number) { - delete this.sliceLabelColorMap[sliceId]; + if (this.source !== SharedLabelColorSource.dashboard) return; + this.sliceLabelMap.delete(sliceId); + const newColorMap = new Map(); + this.sliceLabelMap.forEach(labels => { + labels.forEach(label => { + newColorMap.set(label, this.colorMap.get(label)); + }); + }); + this.colorMap = newColorMap; } - clear() { - this.sliceLabelColorMap = {}; + reset() { + const copyColorMap = new Map(this.colorMap); + copyColorMap.forEach((_, label) => { + this.colorMap.set(label, ''); + }); } - getSharedLabels() { - const tempLabels = new Set<string>(); - const result = new Set<string>(); - Object.keys(this.sliceLabelColorMap).forEach(sliceId => { - const colorMap = this.sliceLabelColorMap[sliceId]; - Object.keys(colorMap).forEach(label => { - if (tempLabels.has(label) && !result.has(label)) { - result.add(label); - } else { - tempLabels.add(label); - } - }); - }); - return [...result]; + clear() { + this.sliceLabelMap.clear(); + this.colorMap.clear(); } } diff --git a/superset-frontend/packages/superset-ui-core/src/color/index.ts b/superset-frontend/packages/superset-ui-core/src/color/index.ts index e1cde3ba3e2d5..3bbdb5d0dc578 100644 --- a/superset-frontend/packages/superset-ui-core/src/color/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/color/index.ts @@ -35,6 +35,7 @@ export * from './utils'; export { default as getSharedLabelColor, SharedLabelColor, + SharedLabelColorSource, } from './SharedLabelColorSingleton'; export const BRAND_COLOR = '#00A699'; diff --git a/superset-frontend/packages/superset-ui-core/src/connection/SupersetClient.ts b/superset-frontend/packages/superset-ui-core/src/connection/SupersetClient.ts index 530c710809068..f102cd197dabd 100644 --- a/superset-frontend/packages/superset-ui-core/src/connection/SupersetClient.ts +++ b/superset-frontend/packages/superset-ui-core/src/connection/SupersetClient.ts @@ -44,6 +44,7 @@ const SupersetClient: SupersetClientInterface = { get: request => getInstance().get(request), init: force => getInstance().init(force), isAuthenticated: () => getInstance().isAuthenticated(), + getGuestToken: () => getInstance().getGuestToken(), post: request => getInstance().post(request), postForm: (...args) => getInstance().postForm(...args), put: request => getInstance().put(request), diff --git a/superset-frontend/packages/superset-ui-core/src/connection/SupersetClientClass.ts b/superset-frontend/packages/superset-ui-core/src/connection/SupersetClientClass.ts index b7281d025903c..fd040faed0423 100644 --- a/superset-frontend/packages/superset-ui-core/src/connection/SupersetClientClass.ts +++ b/superset-frontend/packages/superset-ui-core/src/connection/SupersetClientClass.ts @@ -158,6 +158,10 @@ export default class SupersetClientClass { return this.csrfToken !== null && this.csrfToken !== undefined; } + getGuestToken() { + return this.guestToken; + } + async get<T extends ParseMethod = 'json'>( requestConfig: RequestConfig & { parseMethod?: T }, ) { diff --git a/superset-frontend/packages/superset-ui-core/src/connection/callApi/callApi.ts b/superset-frontend/packages/superset-ui-core/src/connection/callApi/callApi.ts index 7c3fe21fdb8a4..c682e5b7300df 100644 --- a/superset-frontend/packages/superset-ui-core/src/connection/callApi/callApi.ts +++ b/superset-frontend/packages/superset-ui-core/src/connection/callApi/callApi.ts @@ -94,7 +94,7 @@ export default async function callApi({ cache !== 'no-store' && cache !== 'reload' && CACHE_AVAILABLE && - (window.location && window.location.protocol) === 'https:' + window.location?.protocol === 'https:' ) { let supersetCache: Cache | null = null; try { @@ -146,10 +146,23 @@ export default async function callApi({ Object.keys(payload).forEach(key => { const value = (payload as JsonObject)[key] as JsonValue; if (typeof value !== 'undefined') { - formData.append( - key, - stringify ? JSON.stringify(value) : String(value), - ); + let valueString; + try { + // We have seen instances where casting to String() throws error + // This check allows all valid attributes to be appended to the formData + // while logging error to console for any attribute that fails the cast to String + valueString = stringify ? JSON.stringify(value) : String(value); + } catch (e) { + // eslint-disable-next-line no-console + console.error( + `Unable to convert attribute '${key}' to a String(). '${key}' was not added to the formData in request.body for call to ${url}`, + value, + e, + ); + } + if (valueString !== undefined) { + formData.append(key, valueString); + } } }); request.body = formData; diff --git a/superset-frontend/packages/superset-ui-core/src/connection/callApi/parseResponse.ts b/superset-frontend/packages/superset-ui-core/src/connection/callApi/parseResponse.ts index a0b9f149113a4..15beca6e150ad 100644 --- a/superset-frontend/packages/superset-ui-core/src/connection/callApi/parseResponse.ts +++ b/superset-frontend/packages/superset-ui-core/src/connection/callApi/parseResponse.ts @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ +import JSONbig from 'json-bigint'; +import { cloneDeepWith } from 'lodash'; import { ParseMethod, TextResponse, JsonResponse } from '../types'; @@ -25,7 +27,7 @@ export default async function parseResponse<T extends ParseMethod = 'json'>( ) { type ReturnType = T extends 'raw' | null ? Response - : T extends 'json' | undefined + : T extends 'json' | 'json-bigint' | undefined ? JsonResponse : T extends 'text' ? TextResponse @@ -46,6 +48,19 @@ export default async function parseResponse<T extends ParseMethod = 'json'>( }; return result as ReturnType; } + if (parseMethod === 'json-bigint') { + const rawData = await response.text(); + const json = JSONbig.parse(rawData); + const result: JsonResponse = { + response, + // `json-bigint` could not handle floats well, see sidorares/json-bigint#62 + // TODO: clean up after json-bigint>1.0.1 is released + json: cloneDeepWith(json, (value: any) => + value?.isInteger?.() === false ? Number(value) : undefined, + ), + }; + return result as ReturnType; + } // by default treat this as json if (parseMethod === undefined || parseMethod === 'json') { const json = await response.json(); @@ -56,6 +71,6 @@ export default async function parseResponse<T extends ParseMethod = 'json'>( return result as ReturnType; } throw new Error( - `Expected parseResponse=json|text|raw|null, got '${parseMethod}'.`, + `Expected parseResponse=json|json-bigint|text|raw|null, got '${parseMethod}'.`, ); } diff --git a/superset-frontend/packages/superset-ui-core/src/connection/types.ts b/superset-frontend/packages/superset-ui-core/src/connection/types.ts index 06025956754dd..a63ffd8b68a08 100644 --- a/superset-frontend/packages/superset-ui-core/src/connection/types.ts +++ b/superset-frontend/packages/superset-ui-core/src/connection/types.ts @@ -70,7 +70,13 @@ export type Method = RequestInit['method']; export type Mode = RequestInit['mode']; export type Redirect = RequestInit['redirect']; export type ClientTimeout = number | undefined; -export type ParseMethod = 'json' | 'text' | 'raw' | null | undefined; +export type ParseMethod = + | 'json' + | 'json-bigint' + | 'text' + | 'raw' + | null + | undefined; export type Signal = RequestInit['signal']; export type Stringify = boolean; export type Url = string; @@ -152,6 +158,7 @@ export interface SupersetClientInterface | 'init' | 'isAuthenticated' | 'reAuthenticate' + | 'getGuestToken' > { configure: (config?: ClientConfig) => SupersetClientInterface; reset: () => void; diff --git a/superset-frontend/packages/superset-ui-core/src/math-expression/index.ts b/superset-frontend/packages/superset-ui-core/src/math-expression/index.ts index ae3db1f069a94..8ee4d272d8bb0 100644 --- a/superset-frontend/packages/superset-ui-core/src/math-expression/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/math-expression/index.ts @@ -106,7 +106,7 @@ export function evalExpression(expression: string, value: number): number { const subExpressions = String(parsedExpression).split('='); parsedExpression = subExpressions[1] ?? subExpressions[0]; // we can ignore the type requirement on `TOKENS`, as value is always `number` - // and doesn't need to consider `number | underfined`. + // and doesn't need to consider `number | undefined`. // @ts-ignore return Number(mexp.eval(parsedExpression, TOKENS, { x: value })); } diff --git a/superset-frontend/packages/superset-ui-core/src/models/Registry.ts b/superset-frontend/packages/superset-ui-core/src/models/Registry.ts index 90a8065e29ac2..e876bc2b50f59 100644 --- a/superset-frontend/packages/superset-ui-core/src/models/Registry.ts +++ b/superset-frontend/packages/superset-ui-core/src/models/Registry.ts @@ -169,7 +169,7 @@ export default class Registry< const item = this.items[key]; if (item !== undefined) { if ('loader' in item) { - return item.loader && item.loader(); + return item.loader?.(); } return item.value; diff --git a/superset-frontend/packages/superset-ui-core/src/number-format/NumberFormats.ts b/superset-frontend/packages/superset-ui-core/src/number-format/NumberFormats.ts index 11701586c0340..605da5d30e7b7 100644 --- a/superset-frontend/packages/superset-ui-core/src/number-format/NumberFormats.ts +++ b/superset-frontend/packages/superset-ui-core/src/number-format/NumberFormats.ts @@ -52,6 +52,7 @@ const SI = SI_3_DIGIT; const SMART_NUMBER = 'SMART_NUMBER'; const SMART_NUMBER_SIGNED = 'SMART_NUMBER_SIGNED'; +const OVER_MAX_HIDDEN = 'OVER_MAX_HIDDEN'; const NumberFormats = { DOLLAR, @@ -82,6 +83,7 @@ const NumberFormats = { SI_3_DIGIT, SMART_NUMBER, SMART_NUMBER_SIGNED, + OVER_MAX_HIDDEN, }; export default NumberFormats; diff --git a/superset-frontend/packages/superset-ui-core/src/query/DatasourceKey.ts b/superset-frontend/packages/superset-ui-core/src/query/DatasourceKey.ts index 2fe4bcf139059..38a38e10b13a0 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/DatasourceKey.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/DatasourceKey.ts @@ -27,8 +27,8 @@ export default class DatasourceKey { constructor(key: string) { const [idStr, typeStr] = key.split('__'); this.id = parseInt(idStr, 10); - this.type = - typeStr === 'table' ? DatasourceType.Table : DatasourceType.Druid; + this.type = DatasourceType.Table; // default to SqlaTable model + this.type = typeStr === 'query' ? DatasourceType.Query : this.type; } public toString() { diff --git a/superset-frontend/packages/superset-ui-core/src/query/buildQueryContext.ts b/superset-frontend/packages/superset-ui-core/src/query/buildQueryContext.ts index c805811e5faf5..aa1f470ba8f61 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/buildQueryContext.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/buildQueryContext.ts @@ -23,6 +23,8 @@ import { QueryFieldAliases, QueryFormData } from './types/QueryFormData'; import { QueryContext, QueryObject } from './types/Query'; import { SetDataMaskHook } from '../chart'; import { JsonObject } from '../connection'; +import { normalizeTimeColumn } from './normalizeTimeColumn'; +import { isXAxisSet } from './getXAxis'; const WRAP_IN_ARRAY = (baseQueryObject: QueryObject) => [baseQueryObject]; @@ -45,13 +47,19 @@ export default function buildQueryContext( typeof options === 'function' ? { buildQuery: options, queryFields: {} } : options || {}; - const queries = buildQuery(buildQueryObject(formData, queryFields)); + let queries = buildQuery(buildQueryObject(formData, queryFields)); + // --- query mutator begin --- + // todo(Yongjie): move the query mutator into buildQueryObject instead of buildQueryContext queries.forEach(query => { if (Array.isArray(query.post_processing)) { // eslint-disable-next-line no-param-reassign query.post_processing = query.post_processing.filter(Boolean); } }); + if (isXAxisSet(formData)) { + queries = queries.map(query => normalizeTimeColumn(formData, query)); + } + // --- query mutator end --- return { datasource: new DatasourceKey(formData.datasource).toObject(), force: formData.force || false, diff --git a/superset-frontend/packages/superset-ui-core/src/query/buildQueryObject.ts b/superset-frontend/packages/superset-ui-core/src/query/buildQueryObject.ts index 52fa1ffed0c2e..cf434f138577c 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/buildQueryObject.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/buildQueryObject.ts @@ -20,18 +20,20 @@ /* eslint-disable camelcase */ import { AdhocFilter, - QueryFieldAliases, - QueryFormColumn, - QueryFormData, QueryObject, QueryObjectFilterClause, - isPhysicalColumn, - isAdhocColumn, + isQueryFormMetric, } from './types'; +import { + QueryFieldAliases, + QueryFormMetric, + QueryFormData, +} from './types/QueryFormData'; import processFilters from './processFilters'; import extractExtras from './extractExtras'; import extractQueryFields from './extractQueryFields'; import { overrideExtraFormData } from './processExtraFormData'; +import { isDefined } from '../utils'; /** * Build the common segments of all query objects (e.g. the granularity field derived from @@ -92,16 +94,16 @@ export default function buildQueryObject<T extends QueryFormData>( ...extras, ...filterFormData, }); - const normalizeSeriesLimitMetric = (column: QueryFormColumn | undefined) => { - if (isAdhocColumn(column) || isPhysicalColumn(column)) { - return column; + const normalizeSeriesLimitMetric = (metric: QueryFormMetric | undefined) => { + if (isQueryFormMetric(metric)) { + return metric; } return undefined; }; let queryObject: QueryObject = { // fallback `null` to `undefined` so they won't be sent to the backend - // (JSON.strinify will ignore `undefined`.) + // (JSON.stringify will ignore `undefined`.) time_range: time_range || undefined, since: since || undefined, until: until || undefined, @@ -121,10 +123,11 @@ export default function buildQueryObject<T extends QueryFormData>( ? undefined : numericRowOffset, series_columns, - series_limit, - series_limit_metric: normalizeSeriesLimitMetric(series_limit_metric), - timeseries_limit: limit ? Number(limit) : 0, - timeseries_limit_metric: timeseries_limit_metric || undefined, + series_limit: series_limit ?? (isDefined(limit) ? Number(limit) : 0), + series_limit_metric: + normalizeSeriesLimitMetric(series_limit_metric) ?? + timeseries_limit_metric ?? + undefined, order_desc: typeof order_desc === 'undefined' ? true : order_desc, url_params: url_params || undefined, custom_params, diff --git a/superset-frontend/packages/superset-ui-core/src/query/constants.ts b/superset-frontend/packages/superset-ui-core/src/query/constants.ts index 4a3fe5ff5474d..7976e87a4a281 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/constants.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/constants.ts @@ -1,11 +1,3 @@ -import { - ExtraFormDataAppend, - ExtraFormDataOverrideExtras, - ExtraFormDataOverrideRegular, - ExtraFormDataOverride, - QueryObject, -} from './types'; - /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -24,10 +16,19 @@ import { * specific language governing permissions and limitations * under the License. */ +import { + ExtraFormDataAppend, + ExtraFormDataOverrideExtras, + ExtraFormDataOverrideRegular, + ExtraFormDataOverride, + QueryObject, +} from './types'; + export const DTTM_ALIAS = '__timestamp'; +export const NO_TIME_RANGE = 'No filter'; export const EXTRA_FORM_DATA_OVERRIDE_EXTRA_KEYS: (keyof ExtraFormDataOverrideExtras)[] = - ['druid_time_origin', 'relative_start', 'relative_end', 'time_grain_sqla']; + ['relative_start', 'relative_end', 'time_grain_sqla']; export const EXTRA_FORM_DATA_APPEND_KEYS: (keyof ExtraFormDataAppend)[] = [ 'adhoc_filters', diff --git a/superset-frontend/packages/superset-ui-core/src/query/extractExtras.ts b/superset-frontend/packages/superset-ui-core/src/query/extractExtras.ts index aea2881b25dce..39a4b4b2d8030 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/extractExtras.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/extractExtras.ts @@ -18,10 +18,9 @@ */ /* eslint-disable camelcase */ +import { TimeGranularity, QueryFormData } from '@superset-ui/core'; import { AppliedTimeExtras, - isDruidFormData, - QueryFormData, QueryObjectExtras, QueryObjectFilterClause, TimeColumnConfigKey, @@ -30,8 +29,7 @@ import { type ExtraFilterQueryField = { time_range?: string; granularity_sqla?: string; - time_grain_sqla?: string; - druid_time_origin?: string; + time_grain_sqla?: TimeGranularity; granularity?: string; }; @@ -58,7 +56,6 @@ export default function extractExtras(formData: QueryFormData): ExtractedExtra { __time_range: 'time_range', __time_col: 'granularity_sqla', __time_grain: 'time_grain_sqla', - __time_origin: 'druid_time_origin', __granularity: 'granularity', }; @@ -66,28 +63,21 @@ export default function extractExtras(formData: QueryFormData): ExtractedExtra { if (filter.col in reservedColumnsToQueryField) { const key = filter.col as TimeColumnConfigKey; const queryField = reservedColumnsToQueryField[key]; - extract[queryField] = filter.val as string; + extract[queryField] = filter.val as TimeGranularity; applied_time_extras[key] = filter.val as string; } else { filters.push(filter); } }); - // map to undeprecated names and remove deprecated fields - if (isDruidFormData(formData) && !extract.druid_time_origin) { - extras.druid_time_origin = formData.druid_time_origin; - delete extract.druid_time_origin; - } else { - // SQL - extras.time_grain_sqla = - extract.time_grain_sqla || formData.time_grain_sqla; - extract.granularity = - extract.granularity_sqla || - formData.granularity || - formData.granularity_sqla; - delete extract.granularity_sqla; - delete extract.time_grain_sqla; - } + // SQL + extras.time_grain_sqla = extract.time_grain_sqla || formData.time_grain_sqla; + extract.granularity = + extract.granularity_sqla || + formData.granularity || + formData.granularity_sqla; + delete extract.granularity_sqla; + delete extract.time_grain_sqla; return extract; } diff --git a/superset-frontend/packages/superset-ui-core/src/query/extractTimegrain.ts b/superset-frontend/packages/superset-ui-core/src/query/extractTimegrain.ts index e98ec5db4ec1b..b5b3f9617bd8a 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/extractTimegrain.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/extractTimegrain.ts @@ -18,7 +18,7 @@ */ /* eslint-disable no-underscore-dangle */ -import { QueryFormData } from './types'; +import { QueryFormData } from '@superset-ui/core'; import { TimeGranularity } from '../time-format'; export default function extractTimegrain( diff --git a/superset-frontend/packages/superset-ui-core/src/query/getColumnLabel.ts b/superset-frontend/packages/superset-ui-core/src/query/getColumnLabel.ts index f449a44cb2702..f1b4e6ffa7308 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/getColumnLabel.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/getColumnLabel.ts @@ -23,8 +23,8 @@ export default function getColumnLabel(column: QueryFormColumn): string { if (isPhysicalColumn(column)) { return column; } - if (column.label) { + if (column?.label) { return column.label; } - return column.sqlExpression; + return column?.sqlExpression; } diff --git a/superset-frontend/packages/superset-ui-core/src/query/getMetricLabel.ts b/superset-frontend/packages/superset-ui-core/src/query/getMetricLabel.ts index 3f6f31af7b9f9..7ac7930c6a564 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/getMetricLabel.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/getMetricLabel.ts @@ -17,7 +17,7 @@ * under the License. */ -import { isAdhocMetricSimple, isSavedMetric, QueryFormMetric } from './types'; +import { QueryFormMetric, isSavedMetric, isAdhocMetricSimple } from './types'; export default function getMetricLabel(metric: QueryFormMetric): string { if (isSavedMetric(metric)) { diff --git a/superset-frontend/packages/superset-ui-core/src/query/getXAxis.ts b/superset-frontend/packages/superset-ui-core/src/query/getXAxis.ts new file mode 100644 index 0000000000000..7c329c2a8bdff --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/query/getXAxis.ts @@ -0,0 +1,57 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + DTTM_ALIAS, + FeatureFlag, + isFeatureEnabled, + getColumnLabel, + isQueryFormColumn, + QueryFormData, + QueryFormColumn, + Optional, +} from '@superset-ui/core'; + +export const isXAxisSet = (formData: QueryFormData) => + isQueryFormColumn(formData.x_axis); + +export const hasGenericChartAxes = isFeatureEnabled( + FeatureFlag.GENERIC_CHART_AXES, +); + +export const getXAxisColumn = ( + formData: QueryFormData, +): Optional<QueryFormColumn> => { + // The formData should be "raw form_data" -- the snake_case version of formData rather than camelCase. + if (!(formData.granularity_sqla || formData.x_axis)) { + return undefined; + } + + if (isXAxisSet(formData)) { + return formData.x_axis; + } + return DTTM_ALIAS; +}; + +export const getXAxisLabel = (formData: QueryFormData): Optional<string> => { + const col = getXAxisColumn(formData); + if (col) { + return getColumnLabel(col); + } + return undefined; +}; diff --git a/superset-frontend/packages/superset-ui-core/src/query/index.ts b/superset-frontend/packages/superset-ui-core/src/query/index.ts index 9bbfbc59fba86..bb83e3d340fd2 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/index.ts @@ -28,6 +28,9 @@ export { default as getColumnLabel } from './getColumnLabel'; export { default as getMetricLabel } from './getMetricLabel'; export { default as DatasourceKey } from './DatasourceKey'; export { default as normalizeOrderBy } from './normalizeOrderBy'; +export { normalizeTimeColumn } from './normalizeTimeColumn'; +export { default as extractQueryFields } from './extractQueryFields'; +export * from './getXAxis'; export * from './types/AnnotationLayer'; export * from './types/QueryFormData'; diff --git a/superset-frontend/packages/superset-ui-core/src/query/normalizeOrderBy.ts b/superset-frontend/packages/superset-ui-core/src/query/normalizeOrderBy.ts index 3df72b58d2ba5..e38e682abbdfa 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/normalizeOrderBy.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/normalizeOrderBy.ts @@ -39,24 +39,24 @@ export default function normalizeOrderBy( // ensure that remove invalid orderby clause const cloneQueryObject = { ...queryObject }; - delete cloneQueryObject.timeseries_limit_metric; + delete cloneQueryObject.series_limit_metric; delete cloneQueryObject.legacy_order_by; delete cloneQueryObject.order_desc; delete cloneQueryObject.orderby; const isAsc = !queryObject.order_desc; if ( - queryObject.timeseries_limit_metric !== undefined && - queryObject.timeseries_limit_metric !== null && - !isEmpty(queryObject.timeseries_limit_metric) + queryObject.series_limit_metric !== undefined && + queryObject.series_limit_metric !== null && + !isEmpty(queryObject.series_limit_metric) ) { return { ...cloneQueryObject, - orderby: [[queryObject.timeseries_limit_metric, isAsc]], + orderby: [[queryObject.series_limit_metric, isAsc]], }; } - // todo: Removed `legacy_ordery_by` after refactoring + // todo: Removed `legacy_order_by` after refactoring if ( queryObject.legacy_order_by !== undefined && queryObject.legacy_order_by !== null && diff --git a/superset-frontend/packages/superset-ui-core/src/query/normalizeTimeColumn.ts b/superset-frontend/packages/superset-ui-core/src/query/normalizeTimeColumn.ts new file mode 100644 index 0000000000000..f7ea0d0e60061 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/query/normalizeTimeColumn.ts @@ -0,0 +1,84 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import omit from 'lodash/omit'; + +import { + AdhocColumn, + isAdhocColumn, + isPhysicalColumn, + QueryFormColumn, + QueryFormData, + QueryObject, +} from './types'; +import { isXAxisSet } from './getXAxis'; + +export function normalizeTimeColumn( + formData: QueryFormData, + queryObject: QueryObject, +): QueryObject { + // The formData should be "raw form_data" -- the snake_case version of formData rather than camelCase. + if (!isXAxisSet(formData)) { + return queryObject; + } + + const { columns: _columns, extras: _extras } = queryObject; + const mutatedColumns: QueryFormColumn[] = [...(_columns || [])]; + const axisIdx = _columns?.findIndex( + col => + (isPhysicalColumn(col) && + isPhysicalColumn(formData.x_axis) && + col === formData.x_axis) || + (isAdhocColumn(col) && + isAdhocColumn(formData.x_axis) && + col.sqlExpression === formData.x_axis.sqlExpression), + ); + if ( + axisIdx !== undefined && + axisIdx > -1 && + formData.x_axis && + Array.isArray(_columns) + ) { + if (isAdhocColumn(_columns[axisIdx])) { + mutatedColumns[axisIdx] = { + timeGrain: _extras?.time_grain_sqla, + columnType: 'BASE_AXIS', + ...(_columns[axisIdx] as AdhocColumn), + }; + } else { + mutatedColumns[axisIdx] = { + timeGrain: _extras?.time_grain_sqla, + columnType: 'BASE_AXIS', + sqlExpression: formData.x_axis, + label: formData.x_axis, + expressionType: 'SQL', + }; + } + + const newQueryObject = omit(queryObject, [ + 'extras.time_grain_sqla', + 'is_timeseries', + ]); + newQueryObject.columns = mutatedColumns; + + return newQueryObject; + } + + // fallback, return original queryObject + return queryObject; +} diff --git a/superset-frontend/packages/superset-ui-core/src/query/processFilters.ts b/superset-frontend/packages/superset-ui-core/src/query/processFilters.ts index 239f1c49afbe5..8ad1f8b620db4 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/processFilters.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/processFilters.ts @@ -43,7 +43,6 @@ export default function processFilters( const { adhoc_filters, extras = {}, filters = [], where } = formData; const simpleWhere: QueryObjectFilterClause[] = filters; - const simpleHaving: QueryObjectFilterClause[] = []; const freeformWhere: string[] = []; if (where) freeformWhere.push(where); const freeformHaving: string[] = []; @@ -54,8 +53,6 @@ export default function processFilters( const filterClause = convertFilter(filter); if (clause === 'WHERE') { simpleWhere.push(filterClause); - } else { - simpleHaving.push(filterClause); } } else { const { sqlExpression } = filter; @@ -69,7 +66,6 @@ export default function processFilters( // some filter-related fields need to go in `extras` extras.having = freeformHaving.map(sanitizeClause).join(' AND '); - extras.having_druid = simpleHaving; extras.where = freeformWhere.map(sanitizeClause).join(' AND '); return { diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/AdvancedAnalytics.ts b/superset-frontend/packages/superset-ui-core/src/query/types/AdvancedAnalytics.ts index 463b07c1dcc5a..ea270e2d12ecc 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/AdvancedAnalytics.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/AdvancedAnalytics.ts @@ -29,7 +29,7 @@ export interface RollingWindow { min_periods?: number; } -export enum ComparisionType { +export enum ComparisonType { Values = 'values', Difference = 'difference', Percentage = 'percentage', @@ -37,7 +37,7 @@ export enum ComparisionType { } export interface TimeCompare { time_compare?: string; - comparison_type?: ComparisionType; + comparison_type?: ComparisonType; } export default {}; diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/AnnotationLayer.ts b/superset-frontend/packages/superset-ui-core/src/query/types/AnnotationLayer.ts index 6dfe0cfc78c47..bac743cb25c53 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/AnnotationLayer.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/AnnotationLayer.ts @@ -125,7 +125,8 @@ export type AnnotationLayer = | EventAnnotationLayer | IntervalAnnotationLayer | FormulaAnnotationLayer - | TimeseriesAnnotationLayer; + | TimeseriesAnnotationLayer + | TableAnnotationLayer; export function isFormulaAnnotationLayer( layer: AnnotationLayer, diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/Column.ts b/superset-frontend/packages/superset-ui-core/src/query/types/Column.ts index 4e9a13651e4ab..a009515363400 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/Column.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/Column.ts @@ -19,6 +19,7 @@ */ import { GenericDataType } from './QueryResponse'; +import { QueryFormColumn } from './QueryFormData'; export interface AdhocColumn { hasCustomLabel?: boolean; @@ -26,6 +27,9 @@ export interface AdhocColumn { optionName?: string; sqlExpression: string; expressionType: 'SQL'; + columnType?: 'BASE_AXIS' | 'SERIES'; + timeGrain?: string; + datasourceWarning?: boolean; } /** @@ -37,8 +41,7 @@ export type PhysicalColumn = string; * Column information defined in datasource. */ export interface Column { - advanced_data_type?: string; - id: number; + id?: number; type?: string; type_generic?: GenericDataType; column_name: string; @@ -50,16 +53,29 @@ export interface Column { expression?: string | null; database_expression?: string | null; python_date_format?: string | null; -} -export default {}; + // used for advanced_data_type + optionName?: string; + filterBy?: string; + value?: string; + advanced_data_type?: string; +} -export function isPhysicalColumn( - column?: AdhocColumn | PhysicalColumn, -): column is PhysicalColumn { +export function isPhysicalColumn(column?: any): column is PhysicalColumn { return typeof column === 'string'; } -export function isAdhocColumn(column?: AdhocColumn | PhysicalColumn) { - return (column as AdhocColumn)?.sqlExpression !== undefined; +export function isAdhocColumn(column?: any): column is AdhocColumn { + return ( + typeof column !== 'string' && + column?.sqlExpression !== undefined && + column?.label !== undefined && + (column?.expressionType === undefined || column?.expressionType === 'SQL') + ); +} + +export function isQueryFormColumn(column: any): column is QueryFormColumn { + return isPhysicalColumn(column) || isAdhocColumn(column); } + +export default {}; diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/Dashboard.ts b/superset-frontend/packages/superset-ui-core/src/query/types/Dashboard.ts index 4089512de4973..b916e27a394e8 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/Dashboard.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/Dashboard.ts @@ -82,7 +82,6 @@ export type Filter = { adhoc_filters?: AdhocFilter[]; granularity_sqla?: string; granularity?: string; - druid_time_origin?: string; time_grain_sqla?: string; time_range?: string; requiredFirst?: boolean; @@ -92,6 +91,8 @@ export type Filter = { description: string; }; +export type FilterWithDataMask = Filter & { dataMask: DataMaskWithId }; + export type Divider = Partial<Omit<Filter, 'id' | 'type'>> & { id: string; title: string; @@ -105,6 +106,15 @@ export function isNativeFilter( return filterElement.type === NativeFilterType.NATIVE_FILTER; } +export function isNativeFilterWithDataMask( + filterElement: Filter | Divider, +): filterElement is FilterWithDataMask { + return ( + isNativeFilter(filterElement) && + (filterElement as FilterWithDataMask).dataMask?.filterState?.value + ); +} + export function isFilterDivider( filterElement: Filter | Divider, ): filterElement is Divider { @@ -117,10 +127,15 @@ export type Filters = { [filterId: string]: Filter | Divider; }; +export type PartialFilters = { + [filterId: string]: Partial<Filters[keyof Filters]>; +}; + export type NativeFiltersState = { filters: Filters; filterSets: FilterSets; focusedFilterId?: string; + hoveredFilterId?: string; }; export type DashboardComponentMetadata = { diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/Datasource.ts b/superset-frontend/packages/superset-ui-core/src/query/types/Datasource.ts index 03916dee5ebb6..9639a000d0151 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/Datasource.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/Datasource.ts @@ -21,7 +21,6 @@ import { Metric } from './Metric'; export enum DatasourceType { Table = 'table', - Druid = 'druid', Query = 'query', Dataset = 'dataset', SlTable = 'sl_table', @@ -47,7 +46,7 @@ export interface Datasource { }; } -export const DEFAULT_METRICS = [ +export const DEFAULT_METRICS: Metric[] = [ { metric_name: 'COUNT(*)', expression: 'COUNT(*)', diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/Filter.ts b/superset-frontend/packages/superset-ui-core/src/query/types/Filter.ts index be420b41a207b..e113a843d468b 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/Filter.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/Filter.ts @@ -72,6 +72,12 @@ export function isSimpleAdhocFilter( return filter.expressionType === 'SIMPLE'; } +export function isFreeFormAdhocFilter( + filter: AdhocFilter, +): filter is FreeFormAdhocFilter { + return filter.expressionType === 'SQL'; +} + export function isUnaryAdhocFilter( filter: SimpleAdhocFilter, ): filter is UnaryAdhocFilter { diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/Metric.ts b/superset-frontend/packages/superset-ui-core/src/query/types/Metric.ts index 396ccd4c5b5a1..c0f770f9041d4 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/Metric.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/Metric.ts @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. */ -import { Maybe } from '../../types'; +import { Maybe, QueryFormMetric } from '../../types'; import { Column } from './Column'; export type Aggregate = @@ -72,10 +72,24 @@ export interface Metric { warning_text?: Maybe<string>; } -export default {}; +export function isSavedMetric(metric: any): metric is SavedMetric { + return typeof metric === 'string'; +} + +export function isAdhocMetricSimple(metric: any): metric is AdhocMetricSimple { + return typeof metric !== 'string' && metric?.expressionType === 'SIMPLE'; +} -export function isAdhocMetricSimple( - metric: AdhocMetric, -): metric is AdhocMetricSimple { - return metric.expressionType === 'SIMPLE'; +export function isAdhocMetricSQL(metric: any): metric is AdhocMetricSQL { + return typeof metric !== 'string' && metric?.expressionType === 'SQL'; } + +export function isQueryFormMetric(metric: any): metric is QueryFormMetric { + return ( + isSavedMetric(metric) || + isAdhocMetricSimple(metric) || + isAdhocMetricSQL(metric) + ); +} + +export default {}; diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/Operator.ts b/superset-frontend/packages/superset-ui-core/src/query/types/Operator.ts index 754766bef262d..10385767614e6 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/Operator.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/Operator.ts @@ -31,6 +31,7 @@ const BINARY_OPERATORS = [ 'ILIKE', 'LIKE', 'REGEX', + 'TEMPORAL_RANGE', ] as const; /** List of operators that require another operand that is a set */ diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/PostProcessing.ts b/superset-frontend/packages/superset-ui-core/src/query/types/PostProcessing.ts index 315cdb8456cda..e32eda6a90ac7 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/PostProcessing.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/PostProcessing.ts @@ -18,7 +18,7 @@ */ import { JsonObject } from '../../connection'; import { TimeGranularity } from '../../time-format'; -import { RollingType, ComparisionType } from './AdvancedAnalytics'; +import { RollingType, ComparisonType } from './AdvancedAnalytics'; export type NumpyFunction = | 'average' @@ -57,7 +57,7 @@ export interface Aggregates { [colname: string]: { operator: NumpyFunction; /** - * the name of the column to generate aggrates from. + * the name of the column to generate aggregates from. */ column?: string; options?: JsonObject; @@ -111,12 +111,10 @@ interface _PostProcessingPivot { columns: string[]; combine_value_with_metric?: boolean; drop_missing_columns?: boolean; - flatten_columns?: boolean; index: string[]; marginal_distribution_name?: string; marginal_distributions?: boolean; metric_fill_value?: any; - reset_index?: boolean; }; } export type PostProcessingPivot = _PostProcessingPivot | DefaultPostProcessing; @@ -124,7 +122,7 @@ export type PostProcessingPivot = _PostProcessingPivot | DefaultPostProcessing; interface _PostProcessingProphet { operation: 'prophet'; options: { - time_grain: TimeGranularity; + time_grain: TimeGranularity | undefined; periods: number; confidence_interval: number; yearly_seasonality?: boolean | number; @@ -173,7 +171,7 @@ export interface _PostProcessingCompare { options: { source_columns: string[]; compare_columns: string[]; - compare_type: Omit<ComparisionType, ComparisionType.Values>; + compare_type: Omit<ComparisonType, ComparisonType.Values>; drop_original_columns: boolean; }; } @@ -184,7 +182,9 @@ export type PostProcessingCompare = interface _PostProcessingSort { operation: 'sort'; options: { - columns: Record<string, boolean>; + is_sort_index?: boolean; + by?: string[] | string; + ascending?: boolean[] | boolean; }; } export type PostProcessingSort = _PostProcessingSort | DefaultPostProcessing; diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts b/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts index 9354326b1d29e..57377ebb7297c 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts @@ -32,28 +32,36 @@ import { PostProcessingRule } from './PostProcessing'; import { JsonObject } from '../../connection'; import { TimeGranularity } from '../../time-format'; -export type QueryObjectFilterClause = { +export type BaseQueryObjectFilterClause = { col: QueryFormColumn; grain?: TimeGranularity; isExtra?: boolean; -} & ( - | { - op: BinaryOperator; - val: string | number | boolean; - } - | { - op: SetOperator; - val: (string | number | boolean)[]; - } - | { - op: UnaryOperator; - } -); +}; + +export type BinaryQueryObjectFilterClause = BaseQueryObjectFilterClause & { + op: BinaryOperator; + val: string | number | boolean; + formattedVal?: string; +}; + +export type SetQueryObjectFilterClause = BaseQueryObjectFilterClause & { + op: SetOperator; + val: (string | number | boolean)[]; + formattedVal?: string[]; +}; + +export type UnaryQueryObjectFilterClause = BaseQueryObjectFilterClause & { + op: UnaryOperator; + formattedVal?: string; +}; + +export type QueryObjectFilterClause = + | BinaryQueryObjectFilterClause + | SetQueryObjectFilterClause + | UnaryQueryObjectFilterClause; export type QueryObjectExtras = Partial<{ /** HAVING condition for Druid */ - having_druid?: string; - druid_time_origin?: string; /** HAVING condition for SQLAlchemy */ having?: string; relative_start?: string; @@ -128,12 +136,6 @@ export interface QueryObject /** The size of bucket by which to group timeseries data (forthcoming) */ time_grain?: string; - /** Maximum number of timeseries */ - timeseries_limit?: number; - - /** The metric used to sort the returned result. */ - timeseries_limit_metric?: Maybe<QueryFormMetric>; - /** Direction to ordered by */ order_desc?: boolean; @@ -251,19 +253,40 @@ export const CtasEnum = { export type QueryColumn = { name: string; + column_name?: string; type: string | null; is_dttm: boolean; }; -export type QueryState = - | 'stopped' - | 'failed' - | 'pending' - | 'running' - | 'scheduled' - | 'success' - | 'fetching' - | 'timed_out'; +// Possible states of a query object for processing on the server +export enum QueryState { + STARTED = 'started', + STOPPED = 'stopped', + FAILED = 'failed', + PENDING = 'pending', + RUNNING = 'running', + SCHEDULED = 'scheduled', + SUCCESS = 'success', + FETCHING = 'fetching', + TIMED_OUT = 'timed_out', +} + +// Inidcates a Query's state is still processing +export const runningQueryStateList: QueryState[] = [ + QueryState.RUNNING, + QueryState.STARTED, + QueryState.PENDING, + QueryState.FETCHING, + QueryState.SCHEDULED, +]; + +// Indicates a Query's state has completed processing regardless of success / failure +export const concludedQueryStateList: QueryState[] = [ + QueryState.STOPPED, + QueryState.FAILED, + QueryState.SUCCESS, + QueryState.TIMED_OUT, +]; export type Query = { cached: boolean; @@ -274,6 +297,7 @@ export type Query = { errorMessage: string | null; extra: { progress: string | null; + errors?: SupersetError[]; }; id: string; isDataPreview: boolean; @@ -305,7 +329,7 @@ export type Query = { executedSql: string; output: string | Record<string, any>; actions: Record<string, any>; - type: DatasourceType.Query; + type: DatasourceType; columns: QueryColumn[]; }; @@ -317,11 +341,13 @@ export type QueryResults = { expanded_columns: QueryColumn[]; selected_columns: QueryColumn[]; query: { limit: number }; + query_id?: number; }; }; export type QueryResponse = Query & QueryResults; +// todo: move out from typing export const testQuery: Query = { id: 'clientId2353', dbId: 1, @@ -336,7 +362,7 @@ export const testQuery: Query = { isDataPreview: false, progress: 0, resultsKey: null, - state: 'success', + state: QueryState.SUCCESS, tempSchema: null, trackingUrl: null, templateParams: null, @@ -360,20 +386,76 @@ export const testQuery: Query = { columns: [ { name: 'Column 1', - type: DatasourceType.Query, + type: 'STRING', is_dttm: false, }, { name: 'Column 3', - type: DatasourceType.Query, + type: 'STRING', is_dttm: false, }, { name: 'Column 2', - type: DatasourceType.Query, + type: 'TIMESTAMP', is_dttm: true, }, ], }; +export const testQueryResults = { + results: { + displayLimitReached: false, + columns: [ + { + name: 'Column 1', + type: 'STRING', + is_dttm: false, + }, + { + name: 'Column 3', + type: 'STRING', + is_dttm: false, + }, + { + name: 'Column 2', + type: 'TIMESTAMP', + is_dttm: true, + }, + ], + data: [ + { 'Column 1': 'a', 'Column 2': 'b', 'Column 3': '2014-11-11T00:00:00' }, + ], + expanded_columns: [], + selected_columns: [ + { + name: 'Column 1', + type: 'STRING', + is_dttm: false, + }, + { + name: 'Column 3', + type: 'STRING', + is_dttm: false, + }, + { + name: 'Column 2', + type: 'TIMESTAMP', + is_dttm: true, + }, + ], + query: { limit: 6 }, + }, +}; + +export const testQueryResponse = { ...testQuery, ...testQueryResults }; + +export enum ContributionType { + Row = 'row', + Column = 'column', +} + +export type DatasourceSamplesQuery = { + filters?: QueryObjectFilterClause[]; +}; + export default {}; diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/QueryFormData.ts b/superset-frontend/packages/superset-ui-core/src/query/types/QueryFormData.ts index ac57561d5d2ba..1806f567ec5a4 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/QueryFormData.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/QueryFormData.ts @@ -122,14 +122,14 @@ export type ExtraFormDataAppend = { * filter clauses can't be overridden */ export type ExtraFormDataOverrideExtras = Pick< QueryObjectExtras, - 'druid_time_origin' | 'relative_start' | 'relative_end' | 'time_grain_sqla' + 'relative_start' | 'relative_end' | 'time_grain_sqla' >; /** These parameters override those already present in the form data/query object */ export type ExtraFormDataOverrideRegular = Partial< Pick<SqlaFormData, 'granularity_sqla'> > & - Partial<Pick<DruidFormData, 'granularity'>> & + Partial<Pick<SqlaFormData, 'granularity'>> & Partial<Pick<BaseFormData, 'time_range'>> & Partial<Pick<QueryObject, 'time_column' | 'time_grain'>>; @@ -166,13 +166,15 @@ export interface BaseFormData extends TimeRange, FormDataResidual { extra_form_data?: ExtraFormData; /** order descending */ order_desc?: boolean; - /** limit number of time series */ + /** limit number of time series + * deprecated - use series_limit instead */ limit?: number; /** limit number of row in the results */ row_limit?: string | number | null; /** row offset for server side pagination */ row_offset?: string | number | null; - /** The metric used to order timeseries for limiting */ + /** The metric used to order timeseries for limiting + * deprecated - use series_limit_metric instead */ timeseries_limit_metric?: QueryFormMetric; /** Force refresh */ force?: boolean; @@ -184,7 +186,7 @@ export interface BaseFormData extends TimeRange, FormDataResidual { /** limit number of series */ series_columns?: QueryFormColumn[]; series_limit?: number; - series_limit_metric?: QueryFormColumn; + series_limit_metric?: QueryFormMetric; } /** @@ -194,34 +196,16 @@ export interface SqlaFormData extends BaseFormData { /** * Name of the Time Column. Time column is optional. */ + granularity?: string; granularity_sqla?: string; time_grain_sqla?: TimeGranularity; having?: string; } -/** - * Form data for Druid datasources. - */ -export interface DruidFormData extends BaseFormData { - granularity?: string; - having_druid?: string; - druid_time_origin?: string; -} - -export type QueryFormData = DruidFormData | SqlaFormData; +export type QueryFormData = SqlaFormData; //--------------------------------------------------- // Type guards //--------------------------------------------------- -export function isDruidFormData( - formData: QueryFormData, -): formData is DruidFormData { - return 'granularity' in formData; -} - -export function isSavedMetric(metric: QueryFormMetric): metric is SavedMetric { - return typeof metric === 'string'; -} - export default {}; diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts b/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts index 74d33f6e944b6..e4869805f819d 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts @@ -83,6 +83,7 @@ export interface ChartDataResponseResult { export interface TimeseriesChartDataResponseResult extends ChartDataResponseResult { data: TimeseriesDataRecord[]; + label_map: Record<string, string[]>; } /** diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/Time.ts b/superset-frontend/packages/superset-ui-core/src/query/types/Time.ts index 820c3f1a3c819..56156166feb76 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/Time.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/Time.ts @@ -30,7 +30,6 @@ export type TimeColumnConfigKey = | '__time_col' | '__time_grain' | '__time_range' - | '__time_origin' | '__granularity'; export type AppliedTimeExtras = Partial< diff --git a/superset-frontend/packages/superset-ui-core/src/style/index.tsx b/superset-frontend/packages/superset-ui-core/src/style/index.tsx index b20dbc5aa9f5e..ee0b6e10ac419 100644 --- a/superset-frontend/packages/superset-ui-core/src/style/index.tsx +++ b/superset-frontend/packages/superset-ui-core/src/style/index.tsx @@ -22,6 +22,7 @@ import createCache from '@emotion/cache'; export { css, + keyframes, jsx, ThemeProvider, CacheProvider as EmotionCacheProvider, @@ -160,6 +161,7 @@ const defaultTheme = { }, transitionTiming: 0.3, gridUnit: 4, + brandIconMaxWidth: 37, }; export type SupersetTheme = typeof defaultTheme; diff --git a/superset-frontend/packages/superset-ui-core/src/translation/index.ts b/superset-frontend/packages/superset-ui-core/src/translation/index.ts index 71cb8acbe0ea4..216bf5847595a 100644 --- a/superset-frontend/packages/superset-ui-core/src/translation/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/translation/index.ts @@ -22,4 +22,4 @@ export * from './types'; export default {}; -export { default as __hack_reexport_trasnslation } from './types'; +export { default as __hack_reexport_translation } from './types'; diff --git a/superset-frontend/packages/superset-ui-core/src/types/index.ts b/superset-frontend/packages/superset-ui-core/src/types/index.ts index eaab5c0b49dc7..a1c527afd6f06 100644 --- a/superset-frontend/packages/superset-ui-core/src/types/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/types/index.ts @@ -19,3 +19,7 @@ export * from '../query/types'; export type Maybe<T> = T | null; + +export type Optional<T> = T | undefined; + +export type ValueOf<T> = T[keyof T]; diff --git a/superset-frontend/packages/superset-ui-core/src/ui-overrides/ExtensionsRegistry.ts b/superset-frontend/packages/superset-ui-core/src/ui-overrides/ExtensionsRegistry.ts new file mode 100644 index 0000000000000..a411c41d08af8 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/ui-overrides/ExtensionsRegistry.ts @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { TypedRegistry } from '../models'; +import { makeSingleton } from '../utils'; + +/** + * A function which returns text (or marked-up text) + * If what you want is a react component, don't use this. Use React.ComponentType instead. + */ +type ReturningDisplayable<P = void> = (props: P) => string | React.ReactElement; + +/** + * This type defines all available extensions of Superset's default UI. + * Namespace the keys here to follow the form of 'some_domain.functonality.item'. + * Take care to name your keys well, as the name describes what this extension point's role is in Superset. + * + * When defining a new option here, take care to keep any parameters to functions (or components) minimal. + * Any removal or alteration to a parameter will be considered a breaking change. + */ + +// from src/views/components/Menu, not imported since this is a separate package +interface MenuObjectChildProps { + label: string; + name?: string; + icon?: string; + index?: number; + url?: string; + isFrontendRoute?: boolean; + perm?: string | boolean; + view?: string; + disable?: boolean; +} + +export interface SwitchProps { + isEditMode: boolean; + dbFetched: any; + disableSSHTunnelingForEngine?: boolean; + useSSHTunneling: boolean; + setUseSSHTunneling: React.Dispatch<React.SetStateAction<boolean>>; + setDB: React.Dispatch<any>; + isSSHTunneling: boolean; +} + +type ConfigDetailsProps = { + embeddedId: string; +}; +type RightMenuItemIconProps = { + menuChild: MenuObjectChildProps; +}; + +export type Extensions = Partial<{ + 'alertsreports.header.icon': React.ComponentType; + 'embedded.documentation.configuration_details': React.ComponentType<ConfigDetailsProps>; + 'embedded.documentation.description': ReturningDisplayable; + 'embedded.documentation.url': string; + 'dashboard.nav.right': React.ComponentType; + 'navbar.right-menu.item.icon': React.ComponentType<RightMenuItemIconProps>; + 'navbar.right': React.ComponentType; + 'report-modal.dropdown.item.icon': React.ComponentType; + 'root.context.provider': React.ComponentType; + 'welcome.message': React.ComponentType; + 'welcome.banner': React.ComponentType; + 'welcome.main.replacement': React.ComponentType; + 'ssh_tunnel.form.switch': React.ComponentType<SwitchProps>; +}>; + +/** + * A registry containing extensions which can alter Superset's UI at specific points defined by Superset. + * See SIP-87: https://github.com/apache/superset/issues/20615 + */ +class ExtensionsRegistry extends TypedRegistry<Extensions> { + name = 'ExtensionsRegistry'; +} + +export const getExtensionsRegistry = makeSingleton(ExtensionsRegistry, {}); + +// Exporting this under the old name for backwards compatibility. +// After downstream folks have migrated to `getExtensionsRegistry`, we should remove this. +export const getUiOverrideRegistry = getExtensionsRegistry; diff --git a/superset-frontend/packages/superset-ui-core/src/ui-overrides/UiOverrideRegistry.ts b/superset-frontend/packages/superset-ui-core/src/ui-overrides/UiOverrideRegistry.ts deleted file mode 100644 index fb74ae1ece493..0000000000000 --- a/superset-frontend/packages/superset-ui-core/src/ui-overrides/UiOverrideRegistry.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import React from 'react'; -import { TypedRegistry } from '../models'; -import { makeSingleton } from '../utils'; - -/** A function (or component) which returns text (or marked-up text) */ -type UiGeneratorText<P = void> = (props: P) => string | React.ReactElement; - -/** - * This type defines all the UI override options which replace elements of Superset's default UI. - * Idea with the keys here is generally to namespace following the form of 'domain.functonality.item' - * - * When defining a new option here, take care to keep any parameters to functions (or components) minimal. - * Any removal or alteration to a parameter will be considered a breaking change. - */ -export type UiOverrides = Partial<{ - 'embedded.documentation.description': UiGeneratorText; - 'embedded.documentation.url': string; -}>; - -/** - * A registry containing UI customizations to replace elements of Superset's default UI. - */ -class UiOverrideRegistry extends TypedRegistry<UiOverrides> { - name = 'UiOverrideRegistry'; -} - -export const getUiOverrideRegistry = makeSingleton(UiOverrideRegistry, {}); diff --git a/superset-frontend/packages/superset-ui-core/src/ui-overrides/index.tsx b/superset-frontend/packages/superset-ui-core/src/ui-overrides/index.tsx index d59afc216fb8b..4796ae0fe322d 100644 --- a/superset-frontend/packages/superset-ui-core/src/ui-overrides/index.tsx +++ b/superset-frontend/packages/superset-ui-core/src/ui-overrides/index.tsx @@ -17,4 +17,4 @@ * under the License. */ -export * from './UiOverrideRegistry'; +export * from './ExtensionsRegistry'; diff --git a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts index d6a1f2097f94f..524d5a6d1c14f 100644 --- a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts +++ b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts @@ -19,42 +19,51 @@ // We can codegen the enum definition based on a list of supported flags that we // check into source control. We're hardcoding the supported flags for now. export enum FeatureFlag { - ALLOW_DASHBOARD_DOMAIN_SHARDING = 'ALLOW_DASHBOARD_DOMAIN_SHARDING', + // PLEASE KEEP THE LIST SORTED ALPHABETICALLY + ALERTS_ATTACH_REPORTS = 'ALERTS_ATTACH_REPORTS', ALERT_REPORTS = 'ALERT_REPORTS', + ALLOW_DASHBOARD_DOMAIN_SHARDING = 'ALLOW_DASHBOARD_DOMAIN_SHARDING', + ALLOW_FULL_CSV_EXPORT = 'ALLOW_FULL_CSV_EXPORT', CLIENT_CACHE = 'CLIENT_CACHE', - DYNAMIC_PLUGINS = 'DYNAMIC_PLUGINS', - ENABLE_ADVANCED_DATA_TYPES = 'ENABLE_ADVANCED_DATA_TYPES', - SCHEDULED_QUERIES = 'SCHEDULED_QUERIES', - SQL_VALIDATORS_BY_ENGINE = 'SQL_VALIDATORS_BY_ENGINE', - ESTIMATE_QUERY_COST = 'ESTIMATE_QUERY_COST', - SHARE_QUERIES_VIA_KV_STORE = 'SHARE_QUERIES_VIA_KV_STORE', - SQLLAB_BACKEND_PERSISTENCE = 'SQLLAB_BACKEND_PERSISTENCE', - THUMBNAILS = 'THUMBNAILS', - LISTVIEWS_DEFAULT_CARD_VIEW = 'LISTVIEWS_DEFAULT_CARD_VIEW', - DISABLE_LEGACY_DATASOURCE_EDITOR = 'DISABLE_LEGACY_DATASOURCE_EDITOR', - DISABLE_DATASET_SOURCE_EDIT = 'DISABLE_DATASET_SOURCE_EDIT', - DISPLAY_MARKDOWN_HTML = 'DISPLAY_MARKDOWN_HTML', - ESCAPE_MARKDOWN_HTML = 'ESCAPE_MARKDOWN_HTML', - DASHBOARD_NATIVE_FILTERS = 'DASHBOARD_NATIVE_FILTERS', DASHBOARD_CROSS_FILTERS = 'DASHBOARD_CROSS_FILTERS', - DASHBOARD_NATIVE_FILTERS_SET = 'DASHBOARD_NATIVE_FILTERS_SET', + DASHBOARD_EDIT_CHART_IN_NEW_TAB = 'DASHBOARD_EDIT_CHART_IN_NEW_TAB', DASHBOARD_FILTERS_EXPERIMENTAL = 'DASHBOARD_FILTERS_EXPERIMENTAL', + CONFIRM_DASHBOARD_DIFF = 'CONFIRM_DASHBOARD_DIFF', + DASHBOARD_NATIVE_FILTERS = 'DASHBOARD_NATIVE_FILTERS', + DASHBOARD_NATIVE_FILTERS_SET = 'DASHBOARD_NATIVE_FILTERS_SET', + DASHBOARD_VIRTUALIZATION = 'DASHBOARD_VIRTUALIZATION', + DASHBOARD_RBAC = 'DASHBOARD_RBAC', + DATAPANEL_CLOSED_BY_DEFAULT = 'DATAPANEL_CLOSED_BY_DEFAULT', + DISABLE_DATASET_SOURCE_EDIT = 'DISABLE_DATASET_SOURCE_EDIT', + DISABLE_LEGACY_DATASOURCE_EDITOR = 'DISABLE_LEGACY_DATASOURCE_EDITOR', + DISPLAY_MARKDOWN_HTML = 'DISPLAY_MARKDOWN_HTML', + DRILL_TO_DETAIL = 'DRILL_TO_DETAIL', + DYNAMIC_PLUGINS = 'DYNAMIC_PLUGINS', + EMBEDDABLE_CHARTS = 'EMBEDDABLE_CHARTS', EMBEDDED_SUPERSET = 'EMBEDDED_SUPERSET', + ENABLE_ADVANCED_DATA_TYPES = 'ENABLE_ADVANCED_DATA_TYPES', + ENABLE_DND_WITH_CLICK_UX = 'ENABLE_DND_WITH_CLICK_UX', + ENABLE_EXPLORE_DRAG_AND_DROP = 'ENABLE_EXPLORE_DRAG_AND_DROP', ENABLE_FILTER_BOX_MIGRATION = 'ENABLE_FILTER_BOX_MIGRATION', - VERSIONED_EXPORT = 'VERSIONED_EXPORT', - GLOBAL_ASYNC_QUERIES = 'GLOBAL_ASYNC_QUERIES', + ENABLE_JAVASCRIPT_CONTROLS = 'ENABLE_JAVASCRIPT_CONTROLS', ENABLE_TEMPLATE_PROCESSING = 'ENABLE_TEMPLATE_PROCESSING', - ENABLE_EXPLORE_DRAG_AND_DROP = 'ENABLE_EXPLORE_DRAG_AND_DROP', - ENABLE_DND_WITH_CLICK_UX = 'ENABLE_DND_WITH_CLICK_UX', - FORCE_DATABASE_CONNECTIONS_SSL = 'FORCE_DATABASE_CONNECTIONS_SSL', ENABLE_TEMPLATE_REMOVE_FILTERS = 'ENABLE_TEMPLATE_REMOVE_FILTERS', - ENABLE_JAVASCRIPT_CONTROLS = 'ENABLE_JAVASCRIPT_CONTROLS', - DASHBOARD_RBAC = 'DASHBOARD_RBAC', - ALERTS_ATTACH_REPORTS = 'ALERTS_ATTACH_REPORTS', - ALLOW_FULL_CSV_EXPORT = 'ALLOW_FULL_CSV_EXPORT', - UX_BETA = 'UX_BETA', + ESCAPE_MARKDOWN_HTML = 'ESCAPE_MARKDOWN_HTML', + ESTIMATE_QUERY_COST = 'ESTIMATE_QUERY_COST', + FORCE_DATABASE_CONNECTIONS_SSL = 'FORCE_DATABASE_CONNECTIONS_SSL', GENERIC_CHART_AXES = 'GENERIC_CHART_AXES', + GLOBAL_ASYNC_QUERIES = 'GLOBAL_ASYNC_QUERIES', + HORIZONTAL_FILTER_BAR = 'HORIZONTAL_FILTER_BAR', + LISTVIEWS_DEFAULT_CARD_VIEW = 'LISTVIEWS_DEFAULT_CARD_VIEW', + SCHEDULED_QUERIES = 'SCHEDULED_QUERIES', + SHARE_QUERIES_VIA_KV_STORE = 'SHARE_QUERIES_VIA_KV_STORE', + SQLLAB_BACKEND_PERSISTENCE = 'SQLLAB_BACKEND_PERSISTENCE', + SQL_VALIDATORS_BY_ENGINE = 'SQL_VALIDATORS_BY_ENGINE', + THUMBNAILS = 'THUMBNAILS', USE_ANALAGOUS_COLORS = 'USE_ANALAGOUS_COLORS', + UX_BETA = 'UX_BETA', + VERSIONED_EXPORT = 'VERSIONED_EXPORT', + SSH_TUNNELING = 'SSH_TUNNELING', } export type ScheduleQueriesProps = { JSONSCHEMA: { @@ -80,6 +89,11 @@ declare global { } } -export function isFeatureEnabled(feature: FeatureFlag) { - return window && window.featureFlags && !!window.featureFlags[feature]; +export function isFeatureEnabled(feature: FeatureFlag): boolean { + try { + return !!window.featureFlags[feature]; + } catch (error) { + console.error(`Failed to query feature flag ${feature}`); + } + return false; } diff --git a/superset-frontend/packages/superset-ui-core/src/utils/index.ts b/superset-frontend/packages/superset-ui-core/src/utils/index.ts index 1c43663e28ef9..19c5ed586145a 100644 --- a/superset-frontend/packages/superset-ui-core/src/utils/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/utils/index.ts @@ -26,6 +26,7 @@ export { default as makeSingleton } from './makeSingleton'; export { default as promiseTimeout } from './promiseTimeout'; export { default as logging } from './logging'; export { default as removeDuplicates } from './removeDuplicates'; +export { lruCache } from './lruCache'; export * from './featureFlags'; export * from './random'; export * from './typedMemo'; diff --git a/superset-frontend/packages/superset-ui-core/src/utils/isDefined.ts b/superset-frontend/packages/superset-ui-core/src/utils/isDefined.ts index 097115e11c1c2..0cdba14eb6fd3 100644 --- a/superset-frontend/packages/superset-ui-core/src/utils/isDefined.ts +++ b/superset-frontend/packages/superset-ui-core/src/utils/isDefined.ts @@ -17,6 +17,6 @@ * under the License. */ -export default function isDefined(x: unknown) { +export default function isDefined<T>(x: T): x is NonNullable<T> { return x !== null && x !== undefined; } diff --git a/superset-frontend/packages/superset-ui-core/src/utils/lruCache.ts b/superset-frontend/packages/superset-ui-core/src/utils/lruCache.ts new file mode 100644 index 0000000000000..f6785850c22af --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/utils/lruCache.ts @@ -0,0 +1,74 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +class LRUCache<T> { + private cache: Map<string, T>; + + readonly capacity: number; + + constructor(capacity: number) { + if (capacity < 1) { + throw new Error('The capacity in LRU must be greater than 0.'); + } + this.capacity = capacity; + this.cache = new Map<string, T>(); + } + + public has(key: string): boolean { + return this.cache.has(key); + } + + public get(key: string): T | undefined { + // Prevent runtime errors + if (typeof key !== 'string') { + throw new TypeError('The LRUCache key must be string.'); + } + + if (this.cache.has(key)) { + const tmp = this.cache.get(key) as T; + this.cache.delete(key); + this.cache.set(key, tmp); + return tmp; + } + return undefined; + } + + public set(key: string, value: T) { + // Prevent runtime errors + if (typeof key !== 'string') { + throw new TypeError('The LRUCache key must be string.'); + } + if (this.cache.size >= this.capacity) { + this.cache.delete(this.cache.keys().next().value); + } + this.cache.set(key, value); + } + + public clear() { + this.cache.clear(); + } + + public get size() { + return this.cache.size; + } +} + +export function lruCache<T>(capacity = 100) { + return new LRUCache<T>(capacity); +} diff --git a/superset-frontend/packages/superset-ui-core/test/__mocks__/resize-observer-polyfill.ts b/superset-frontend/packages/superset-ui-core/test/__mocks__/resize-observer-polyfill.ts index 238e14ab23360..719ad1119f1f4 100644 --- a/superset-frontend/packages/superset-ui-core/test/__mocks__/resize-observer-polyfill.ts +++ b/superset-frontend/packages/superset-ui-core/test/__mocks__/resize-observer-polyfill.ts @@ -37,6 +37,11 @@ export default function ResizeObserver(callback: ObserveCallback) { allCallbacks.push(callback); } }, + unobserve() { + if (callback) { + allCallbacks.splice(allCallbacks.indexOf(callback), 1); + } + }, }; } diff --git a/superset-frontend/packages/superset-ui-core/test/chart/fixtures/formData.ts b/superset-frontend/packages/superset-ui-core/test/chart/fixtures/formData.ts index 25d27f5e2d0c6..9d926f46131bd 100644 --- a/superset-frontend/packages/superset-ui-core/test/chart/fixtures/formData.ts +++ b/superset-frontend/packages/superset-ui-core/test/chart/fixtures/formData.ts @@ -19,13 +19,14 @@ /* eslint sort-keys: 'off' */ /** The form data defined here is based on default visualizations packaged with Apache Superset */ +import { TimeGranularity } from '@superset-ui/core'; export const bigNumberFormData = { datasource: '3__table', viz_type: 'big_number', slice_id: 54, granularity_sqla: 'ds', - time_grain_sqla: 'P1D', + time_grain_sqla: TimeGranularity.DAY, time_range: '100 years ago : now', metric: 'sum__num', adhoc_filters: [], diff --git a/superset-frontend/packages/superset-ui-core/test/color/CategoricalColorScale.test.ts b/superset-frontend/packages/superset-ui-core/test/color/CategoricalColorScale.test.ts index 91a8f4a3185a7..9e83aaba9a871 100644 --- a/superset-frontend/packages/superset-ui-core/test/color/CategoricalColorScale.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/color/CategoricalColorScale.test.ts @@ -140,7 +140,7 @@ describe('CategoricalColorScale', () => { expect(scale2.getColorMap()).toEqual({ cow: 'black', pig: 'pink', - horse: 'blue', + horse: 'green', }); }); }); diff --git a/superset-frontend/packages/superset-ui-core/test/color/ColorSchemeRegistry.test.ts b/superset-frontend/packages/superset-ui-core/test/color/ColorSchemeRegistry.test.ts index 4629828474904..13aa49922f452 100644 --- a/superset-frontend/packages/superset-ui-core/test/color/ColorSchemeRegistry.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/color/ColorSchemeRegistry.test.ts @@ -18,10 +18,26 @@ */ import ColorSchemeRegistry from '../../src/color/ColorSchemeRegistry'; +import schemes from '../../src/color/colorSchemes/categorical/d3'; +import CategoricalScheme from '../../src/color/CategoricalScheme'; describe('ColorSchemeRegistry', () => { it('exists', () => { expect(ColorSchemeRegistry).toBeDefined(); expect(ColorSchemeRegistry).toBeInstanceOf(Function); }); + it('returns undefined', () => { + const registry = new ColorSchemeRegistry(); + expect(registry.get('something')).toBeUndefined(); + }); + it('returns default', () => { + const registry = new ColorSchemeRegistry(); + registry.registerValue('SUPERSET_DEFAULT', schemes[0]); + expect(registry.get('something')).toBeInstanceOf(CategoricalScheme); + }); + it('returns undefined in strict mode', () => { + const registry = new ColorSchemeRegistry(); + registry.registerValue('SUPERSET_DEFAULT', schemes[0]); + expect(registry.get('something', true)).toBeUndefined(); + }); }); diff --git a/superset-frontend/packages/superset-ui-core/test/color/SharedLabelColorSingleton.test.ts b/superset-frontend/packages/superset-ui-core/test/color/SharedLabelColorSingleton.test.ts index 86d3ba9c409e1..88610874dbd74 100644 --- a/superset-frontend/packages/superset-ui-core/test/color/SharedLabelColorSingleton.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/color/SharedLabelColorSingleton.test.ts @@ -23,6 +23,7 @@ import { getCategoricalSchemeRegistry, getSharedLabelColor, SharedLabelColor, + SharedLabelColorSource, } from '@superset-ui/core'; import { getAnalogousColors } from '../../src/color/utils'; @@ -52,6 +53,7 @@ describe('SharedLabelColor', () => { }); beforeEach(() => { + getSharedLabelColor().source = SharedLabelColorSource.dashboard; getSharedLabelColor().clear(); }); @@ -60,18 +62,48 @@ describe('SharedLabelColor', () => { }); describe('.addSlice(value, color, sliceId)', () => { - it('should add to valueSliceMap when first adding label', () => { + it('should add to sliceLabelColorMap when first adding label', () => { const sharedLabelColor = getSharedLabelColor(); sharedLabelColor.addSlice('a', 'red', 1); - expect(sharedLabelColor.sliceLabelColorMap).toHaveProperty('1', { - a: 'red', - }); + expect(sharedLabelColor.sliceLabelMap.has(1)).toEqual(true); + const labels = sharedLabelColor.sliceLabelMap.get(1); + expect(labels?.includes('a')).toEqual(true); + const colorMap = sharedLabelColor.getColorMap(); + expect(Object.fromEntries(colorMap)).toEqual({ a: 'red' }); + }); + + it('should add to sliceLabelColorMap when slice exist', () => { + const sharedLabelColor = getSharedLabelColor(); + sharedLabelColor.addSlice('a', 'red', 1); + sharedLabelColor.addSlice('b', 'blue', 1); + const labels = sharedLabelColor.sliceLabelMap.get(1); + expect(labels?.includes('b')).toEqual(true); + const colorMap = sharedLabelColor.getColorMap(); + expect(Object.fromEntries(colorMap)).toEqual({ a: 'red', b: 'blue' }); + }); + + it('should use last color if adding label repeatedly', () => { + const sharedLabelColor = getSharedLabelColor(); + sharedLabelColor.addSlice('b', 'blue', 1); + sharedLabelColor.addSlice('b', 'green', 1); + const labels = sharedLabelColor.sliceLabelMap.get(1); + expect(labels?.includes('b')).toEqual(true); + expect(labels?.length).toEqual(1); + const colorMap = sharedLabelColor.getColorMap(); + expect(Object.fromEntries(colorMap)).toEqual({ b: 'green' }); + }); + + it('should do nothing when source is not dashboard', () => { + const sharedLabelColor = getSharedLabelColor(); + sharedLabelColor.source = SharedLabelColorSource.explore; + sharedLabelColor.addSlice('a', 'red'); + expect(Object.fromEntries(sharedLabelColor.sliceLabelMap)).toEqual({}); }); it('should do nothing when sliceId is undefined', () => { const sharedLabelColor = getSharedLabelColor(); sharedLabelColor.addSlice('a', 'red'); - expect(sharedLabelColor.sliceLabelColorMap).toEqual({}); + expect(Object.fromEntries(sharedLabelColor.sliceLabelMap)).toEqual({}); }); }); @@ -80,55 +112,92 @@ describe('SharedLabelColor', () => { const sharedLabelColor = getSharedLabelColor(); sharedLabelColor.addSlice('a', 'red', 1); sharedLabelColor.removeSlice(1); - expect(sharedLabelColor.sliceLabelColorMap).toEqual({}); + expect(sharedLabelColor.sliceLabelMap.has(1)).toEqual(false); }); - }); - describe('.getColorMap(namespace, scheme, updateColorScheme)', () => { - it('should be undefined when scheme is undefined', () => { + it('should update colorMap', () => { const sharedLabelColor = getSharedLabelColor(); + sharedLabelColor.addSlice('a', 'red', 1); + sharedLabelColor.addSlice('b', 'blue', 2); + sharedLabelColor.removeSlice(1); const colorMap = sharedLabelColor.getColorMap(); - expect(colorMap).toBeUndefined(); + expect(Object.fromEntries(colorMap)).toEqual({ b: 'blue' }); }); - it('should update color value if passing updateColorScheme', () => { + it('should do nothing when source is not dashboard', () => { const sharedLabelColor = getSharedLabelColor(); sharedLabelColor.addSlice('a', 'red', 1); - sharedLabelColor.addSlice('b', 'blue', 2); - const colorMap = sharedLabelColor.getColorMap('', 'testColors2', true); - expect(colorMap).toEqual({ a: 'yellow', b: 'yellow' }); + sharedLabelColor.source = SharedLabelColorSource.explore; + sharedLabelColor.removeSlice(1); + expect(sharedLabelColor.sliceLabelMap.has(1)).toEqual(true); }); + }); - it('should get origin color value if not pass updateColorScheme', () => { + describe('.updateColorMap(namespace, scheme)', () => { + it('should update color map', () => { const sharedLabelColor = getSharedLabelColor(); sharedLabelColor.addSlice('a', 'red', 1); - sharedLabelColor.addSlice('b', 'blue', 2); - const colorMap = sharedLabelColor.getColorMap('', 'testColors'); - expect(colorMap).toEqual({ a: 'red', b: 'blue' }); + sharedLabelColor.addSlice('b', 'pink', 1); + sharedLabelColor.addSlice('b', 'green', 2); + sharedLabelColor.addSlice('c', 'blue', 2); + sharedLabelColor.updateColorMap('', 'testColors2'); + const colorMap = sharedLabelColor.getColorMap(); + expect(Object.fromEntries(colorMap)).toEqual({ + a: 'yellow', + b: 'yellow', + c: 'green', + }); }); - it('should use recycle colors if shared label exit', () => { + it('should use recycle colors', () => { window.featureFlags = { [FeatureFlag.USE_ANALAGOUS_COLORS]: false, }; const sharedLabelColor = getSharedLabelColor(); sharedLabelColor.addSlice('a', 'red', 1); - sharedLabelColor.addSlice('a', 'blue', 2); - const colorMap = sharedLabelColor.getColorMap('', 'testColors'); - expect(colorMap).not.toEqual({}); + sharedLabelColor.addSlice('b', 'blue', 2); + sharedLabelColor.addSlice('c', 'green', 3); + sharedLabelColor.addSlice('d', 'red', 4); + sharedLabelColor.updateColorMap('', 'testColors'); + const colorMap = sharedLabelColor.getColorMap(); + expect(Object.fromEntries(colorMap)).not.toEqual({}); expect(getAnalogousColors).not.toBeCalled(); }); - it('should use analagous colors if shared label exit', () => { + it('should use analagous colors', () => { window.featureFlags = { [FeatureFlag.USE_ANALAGOUS_COLORS]: true, }; const sharedLabelColor = getSharedLabelColor(); sharedLabelColor.addSlice('a', 'red', 1); - sharedLabelColor.addSlice('a', 'blue', 2); - const colorMap = sharedLabelColor.getColorMap('', 'testColors'); - expect(colorMap).not.toEqual({}); + sharedLabelColor.addSlice('b', 'blue', 1); + sharedLabelColor.addSlice('c', 'green', 1); + sharedLabelColor.addSlice('d', 'red', 1); + sharedLabelColor.updateColorMap('', 'testColors'); + const colorMap = sharedLabelColor.getColorMap(); + expect(Object.fromEntries(colorMap)).not.toEqual({}); expect(getAnalogousColors).toBeCalled(); }); }); + + describe('.getColorMap()', () => { + it('should get color map', () => { + const sharedLabelColor = getSharedLabelColor(); + sharedLabelColor.addSlice('a', 'red', 1); + sharedLabelColor.addSlice('b', 'blue', 2); + const colorMap = sharedLabelColor.getColorMap(); + expect(Object.fromEntries(colorMap)).toEqual({ a: 'red', b: 'blue' }); + }); + }); + + describe('.reset()', () => { + it('should reset color map', () => { + const sharedLabelColor = getSharedLabelColor(); + sharedLabelColor.addSlice('a', 'red', 1); + sharedLabelColor.addSlice('b', 'blue', 2); + sharedLabelColor.reset(); + const colorMap = sharedLabelColor.getColorMap(); + expect(Object.fromEntries(colorMap)).toEqual({ a: '', b: '' }); + }); + }); }); diff --git a/superset-frontend/packages/superset-ui-core/test/connection/SupersetClient.test.ts b/superset-frontend/packages/superset-ui-core/test/connection/SupersetClient.test.ts index 17a07f3c727e6..caba59f563722 100644 --- a/superset-frontend/packages/superset-ui-core/test/connection/SupersetClient.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/connection/SupersetClient.test.ts @@ -38,6 +38,7 @@ describe('SupersetClient', () => { expect(typeof SupersetClient.postForm).toBe('function'); expect(typeof SupersetClient.isAuthenticated).toBe('function'); expect(typeof SupersetClient.reAuthenticate).toBe('function'); + expect(typeof SupersetClient.getGuestToken).toBe('function'); expect(typeof SupersetClient.request).toBe('function'); expect(typeof SupersetClient.reset).toBe('function'); }); @@ -55,7 +56,7 @@ describe('SupersetClient', () => { // this also tests that the ^above doesn't throw if configure is called appropriately it('calls appropriate SupersetClient methods when configured', async () => { - expect.assertions(15); + expect.assertions(16); const mockGetUrl = '/mock/get/url'; const mockPostUrl = '/mock/post/url'; const mockRequestUrl = '/mock/request/url'; @@ -82,6 +83,10 @@ describe('SupersetClient', () => { ); const csrfSpy = jest.spyOn(SupersetClientClass.prototype, 'getCSRFToken'); const requestSpy = jest.spyOn(SupersetClientClass.prototype, 'request'); + const getGuestTokenSpy = jest.spyOn( + SupersetClientClass.prototype, + 'getGuestToken', + ); SupersetClient.configure({}); await SupersetClient.init(); @@ -114,6 +119,9 @@ describe('SupersetClient', () => { SupersetClient.isAuthenticated(); await SupersetClient.reAuthenticate(); + SupersetClient.getGuestToken(); + expect(getGuestTokenSpy).toHaveBeenCalledTimes(1); + expect(initSpy).toHaveBeenCalledTimes(2); expect(deleteSpy).toHaveBeenCalledTimes(1); expect(putSpy).toHaveBeenCalledTimes(1); diff --git a/superset-frontend/packages/superset-ui-core/test/connection/SupersetClientClass.test.ts b/superset-frontend/packages/superset-ui-core/test/connection/SupersetClientClass.test.ts index 4db26b05b4151..56ab3f1baea07 100644 --- a/superset-frontend/packages/superset-ui-core/test/connection/SupersetClientClass.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/connection/SupersetClientClass.test.ts @@ -329,7 +329,7 @@ describe('SupersetClientClass', () => { }); it('uses a guest token when provided', async () => { - expect.assertions(1); + expect.assertions(2); const client = new SupersetClientClass({ protocol, @@ -337,6 +337,7 @@ describe('SupersetClientClass', () => { guestToken: 'abc123', guestTokenHeaderName: 'guestTokenHeader', }); + expect(client.getGuestToken()).toBe('abc123'); await client.init(); await client.get({ url: mockGetUrl }); diff --git a/superset-frontend/packages/superset-ui-core/test/connection/callApi/callApi.test.ts b/superset-frontend/packages/superset-ui-core/test/connection/callApi/callApi.test.ts index 81467ce2393a9..81c8e2d150522 100644 --- a/superset-frontend/packages/superset-ui-core/test/connection/callApi/callApi.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/connection/callApi/callApi.test.ts @@ -23,6 +23,12 @@ import callApi from '../../../src/connection/callApi/callApi'; import { LOGIN_GLOB } from '../fixtures/constants'; +// missing the toString function causing method to error out when casting to String +class BadObject {} +const corruptObject = new BadObject(); +/* @ts-expect-error */ +BadObject.prototype.toString = undefined; + describe('callApi()', () => { beforeAll(() => { fetchMock.get(LOGIN_GLOB, { result: '1234' }); @@ -178,6 +184,44 @@ describe('callApi()', () => { expect(jsonRequestBody[key]).toEqual(value); }); }); + + it('removes corrupt value when building formData with stringify = false', async () => { + /* + There has been a case when 'stringify' is false an object value on one of the + attributes was missing a toString function making the cast to String() fail + and causing entire method call to fail. The new logic skips corrupt values that fail cast to String() + and allows all valid attributes to be added as key / value pairs to the formData + instance. This test case replicates a corrupt object missing the .toString method + representing a real bug report. + */ + const postPayload = { + string: 'value', + number: 1237, + array: [1, 2, 3], + object: { a: 'a', 1: 1 }, + null: null, + emptyString: '', + // corruptObject has no toString method and will fail cast to String() + corrupt: [corruptObject], + }; + jest.spyOn(console, 'error').mockImplementation(); + + await callApi({ + url: mockPostUrl, + method: 'POST', + postPayload, + stringify: false, + }); + + const calls = fetchMock.calls(mockPostUrl); + expect(calls).toHaveLength(1); + const unstringified = (calls[0][1] as RequestInit).body as FormData; + const hasCorruptKey = unstringified.has('corrupt'); + expect(hasCorruptKey).toBeFalsy(); + // When a corrupt attribute is encountred, a console.error call is made with info about the corrupt attribute + // eslint-disable-next-line no-console + expect(console.error).toHaveBeenCalledTimes(1); + }); }); describe('PUT requests', () => { diff --git a/superset-frontend/packages/superset-ui-core/test/connection/callApi/parseResponse.test.ts b/superset-frontend/packages/superset-ui-core/test/connection/callApi/parseResponse.test.ts index d54be27e9c8f1..e13964ecf7300 100644 --- a/superset-frontend/packages/superset-ui-core/test/connection/callApi/parseResponse.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/connection/callApi/parseResponse.test.ts @@ -137,6 +137,38 @@ describe('parseResponse()', () => { expect(responseRaw.bodyUsed).toBe(false); }); + it('resolves to big number value if `parseMethod=json-bigint`', async () => { + const mockBigIntUrl = '/mock/get/bigInt'; + const mockGetBigIntPayload = + '{ "value": 9223372036854775807, "minus": { "value": -483729382918228373892, "str": "something" }, "number": 1234, "floatValue": { "plus": 0.3452211361231223, "minus": -0.3452211361231223 } }'; + fetchMock.get(mockBigIntUrl, mockGetBigIntPayload); + const responseBigNumber = await parseResponse( + callApi({ url: mockBigIntUrl, method: 'GET' }), + 'json-bigint', + ); + expect(`${responseBigNumber.json.value}`).toEqual('9223372036854775807'); + expect(`${responseBigNumber.json.minus.value}`).toEqual( + '-483729382918228373892', + ); + expect(responseBigNumber.json.number).toEqual(1234); + expect(responseBigNumber.json.floatValue.plus).toEqual(0.3452211361231223); + expect(responseBigNumber.json.floatValue.minus).toEqual( + -0.3452211361231223, + ); + expect( + responseBigNumber.json.floatValue.plus + + responseBigNumber.json.floatValue.minus, + ).toEqual(0); + expect( + responseBigNumber.json.floatValue.plus / + responseBigNumber.json.floatValue.minus, + ).toEqual(-1); + expect(Math.min(responseBigNumber.json.floatValue.plus, 0)).toEqual(0); + expect(Math.abs(responseBigNumber.json.floatValue.minus)).toEqual( + responseBigNumber.json.floatValue.plus, + ); + }); + it('rejects if request.ok=false', async () => { expect.assertions(3); const mockNotOkayUrl = '/mock/notokay/url'; diff --git a/superset-frontend/packages/superset-ui-core/test/models/Registry.test.ts b/superset-frontend/packages/superset-ui-core/test/models/Registry.test.ts index 1c85dc242c90c..11c2e65eb51f4 100644 --- a/superset-frontend/packages/superset-ui-core/test/models/Registry.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/models/Registry.test.ts @@ -404,7 +404,7 @@ describe('Registry', () => { expect(listener).toBeCalledWith(['foo']); }); - it('calls the listener when a value is overriden', () => { + it('calls the listener when a value is overridden', () => { registry.registerValue('foo', 'bar'); listener.mockClear(); registry.registerValue('foo', 'baz'); diff --git a/superset-frontend/packages/superset-ui-core/test/number-format/factories/createD3NumberFormatter.test.ts b/superset-frontend/packages/superset-ui-core/test/number-format/factories/createD3NumberFormatter.test.ts index c80c72c30868c..951ab039c5a9a 100644 --- a/superset-frontend/packages/superset-ui-core/test/number-format/factories/createD3NumberFormatter.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/number-format/factories/createD3NumberFormatter.test.ts @@ -62,7 +62,7 @@ describe('createD3NumberFormatter(config)', () => { }); }); describe('config.description', () => { - it('set decription if specified', () => { + it('set description if specified', () => { const formatter = createD3NumberFormatter({ description: 'lorem ipsum', formatString: '.2f', diff --git a/superset-frontend/packages/superset-ui-core/test/query/DatasourceKey.test.ts b/superset-frontend/packages/superset-ui-core/test/query/DatasourceKey.test.ts index 6b1d62e6aa135..4a3c8772c372d 100644 --- a/superset-frontend/packages/superset-ui-core/test/query/DatasourceKey.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/query/DatasourceKey.test.ts @@ -19,18 +19,15 @@ import { DatasourceKey } from '@superset-ui/core'; describe('DatasourceKey', () => { - const tableKey = '5__table'; - const druidKey = '5__druid'; - it('should handle table data sources', () => { - const datasourceKey = new DatasourceKey(tableKey); - expect(datasourceKey.toString()).toBe(tableKey); + const datasourceKey = new DatasourceKey('5__table'); + expect(datasourceKey.toString()).toBe('5__table'); expect(datasourceKey.toObject()).toEqual({ id: 5, type: 'table' }); }); - it('should handle druid data sources', () => { - const datasourceKey = new DatasourceKey(druidKey); - expect(datasourceKey.toString()).toBe(druidKey); - expect(datasourceKey.toObject()).toEqual({ id: 5, type: 'druid' }); + it('should handle query data sources', () => { + const datasourceKey = new DatasourceKey('5__query'); + expect(datasourceKey.toString()).toBe('5__query'); + expect(datasourceKey.toObject()).toEqual({ id: 5, type: 'query' }); }); }); diff --git a/superset-frontend/packages/superset-ui-core/test/query/buildQueryContext.test.ts b/superset-frontend/packages/superset-ui-core/test/query/buildQueryContext.test.ts index 366feeff7a2e1..9d47361e8fdd4 100644 --- a/superset-frontend/packages/superset-ui-core/test/query/buildQueryContext.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/query/buildQueryContext.test.ts @@ -17,6 +17,8 @@ * under the License. */ import { buildQueryContext } from '@superset-ui/core'; +import * as queryModule from '../../src/query/normalizeTimeColumn'; +import * as getXAxisModule from '../../src/query/getXAxis'; describe('buildQueryContext', () => { it('should build datasource for table sources and apply defaults', () => { @@ -31,17 +33,6 @@ describe('buildQueryContext', () => { expect(queryContext.result_format).toBe('json'); expect(queryContext.result_type).toBe('full'); }); - it('should build datasource for druid sources and set force to true', () => { - const queryContext = buildQueryContext({ - datasource: '5__druid', - granularity: 'ds', - viz_type: 'table', - force: true, - }); - expect(queryContext.datasource.id).toBe(5); - expect(queryContext.datasource.type).toBe('druid'); - expect(queryContext.force).toBe(true); - }); it('should build datasource for table sources with columns', () => { const queryContext = buildQueryContext( { @@ -108,6 +99,7 @@ describe('buildQueryContext', () => { ]), ); }); + // todo(Yongjie): move these test case into buildQueryObject.test.ts it('should remove undefined value in post_processing', () => { const queryContext = buildQueryContext( { @@ -133,4 +125,43 @@ describe('buildQueryContext', () => { }, ]); }); + it('should call normalizeTimeColumn if GENERIC_CHART_AXES is enabled and has x_axis', () => { + Object.defineProperty(getXAxisModule, 'hasGenericChartAxes', { + value: true, + }); + const spyNormalizeTimeColumn = jest.spyOn( + queryModule, + 'normalizeTimeColumn', + ); + + buildQueryContext( + { + datasource: '5__table', + viz_type: 'table', + x_axis: 'axis', + }, + () => [{}], + ); + expect(spyNormalizeTimeColumn).toBeCalled(); + spyNormalizeTimeColumn.mockRestore(); + }); + it("shouldn't call normalizeTimeColumn if GENERIC_CHART_AXES is disabled", () => { + Object.defineProperty(getXAxisModule, 'hasGenericChartAxes', { + value: false, + }); + const spyNormalizeTimeColumn = jest.spyOn( + queryModule, + 'normalizeTimeColumn', + ); + + buildQueryContext( + { + datasource: '5__table', + viz_type: 'table', + }, + () => [{}], + ); + expect(spyNormalizeTimeColumn).not.toBeCalled(); + spyNormalizeTimeColumn.mockRestore(); + }); }); diff --git a/superset-frontend/packages/superset-ui-core/test/query/buildQueryObject.test.ts b/superset-frontend/packages/superset-ui-core/test/query/buildQueryObject.test.ts index 321e2a8401776..cdabcff57e0b8 100644 --- a/superset-frontend/packages/superset-ui-core/test/query/buildQueryObject.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/query/buildQueryObject.test.ts @@ -119,15 +119,26 @@ describe('buildQueryObject', () => { expect(query.metrics).toEqual(['sum__num', 'avg__num']); }); - it('should build limit', () => { - const limit = 2; + it('should build series_limit from legacy control', () => { + const series_limit = 2; query = buildQueryObject({ datasource: '5__table', granularity_sqla: 'ds', viz_type: 'table', - limit, + limit: series_limit, }); - expect(query.timeseries_limit).toEqual(limit); + expect(query.series_limit).toEqual(series_limit); + }); + + it('should build series_limit', () => { + const series_limit = 2; + query = buildQueryObject({ + datasource: '5__table', + granularity_sqla: 'ds', + viz_type: 'table', + series_limit, + }); + expect(query.series_limit).toEqual(series_limit); }); it('should build order_desc', () => { @@ -141,7 +152,7 @@ describe('buildQueryObject', () => { expect(query.order_desc).toEqual(orderDesc); }); - it('should build timeseries_limit_metric', () => { + it('should build series_limit_metric from legacy control', () => { const metric = 'country'; query = buildQueryObject({ datasource: '5__table', @@ -149,7 +160,7 @@ describe('buildQueryObject', () => { viz_type: 'table', timeseries_limit_metric: metric, }); - expect(query.timeseries_limit_metric).toEqual(metric); + expect(query.series_limit_metric).toEqual(metric); }); it('should build series_limit_metric', () => { @@ -291,6 +302,26 @@ describe('buildQueryObject', () => { ).toBeUndefined(); }); + it('should populate granularity', () => { + const granularity = 'ds'; + query = buildQueryObject({ + datasource: '5__table', + granularity, + viz_type: 'table', + }); + expect(query.granularity).toEqual(granularity); + }); + + it('should populate granularity from legacy field', () => { + const granularity = 'ds'; + query = buildQueryObject({ + datasource: '5__table', + granularity_sqla: granularity, + viz_type: 'table', + }); + expect(query.granularity).toEqual(granularity); + }); + it('should populate custom_params', () => { const customParams: JsonObject = { customObject: { id: 137, name: 'C-137' }, diff --git a/superset-frontend/packages/superset-ui-core/test/query/extractExtras.test.ts b/superset-frontend/packages/superset-ui-core/test/query/extractExtras.test.ts index ca6ab730d1af5..35174f72bd35f 100644 --- a/superset-frontend/packages/superset-ui-core/test/query/extractExtras.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/query/extractExtras.test.ts @@ -16,13 +16,14 @@ * specific language governing permissions and limitations * under the License. */ +import { TimeGranularity } from '@superset-ui/core'; import extractExtras from '../../src/query/extractExtras'; describe('extractExtras', () => { const baseQueryFormData = { datasource: '1__table', granularity_sqla: 'ds', - time_grain_sqla: 'PT1M', + time_grain_sqla: TimeGranularity.MINUTE, viz_type: 'my_viz', }; diff --git a/superset-frontend/packages/superset-ui-core/test/query/getAxis.test.ts b/superset-frontend/packages/superset-ui-core/test/query/getAxis.test.ts new file mode 100644 index 0000000000000..010bd9fc67591 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/test/query/getAxis.test.ts @@ -0,0 +1,26 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { isXAxisSet } from '@superset-ui/core'; + +test('isXAxisSet', () => { + expect(isXAxisSet({ datasource: '123', viz_type: 'table' })).not.toBeTruthy(); + expect( + isXAxisSet({ datasource: '123', viz_type: 'table', x_axis: 'axis' }), + ).toBeTruthy(); +}); diff --git a/superset-frontend/packages/superset-ui-core/test/query/normalizeOrderBy.test.ts b/superset-frontend/packages/superset-ui-core/test/query/normalizeOrderBy.test.ts index 57b186a1297ee..564d4aa815bbd 100644 --- a/superset-frontend/packages/superset-ui-core/test/query/normalizeOrderBy.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/query/normalizeOrderBy.test.ts @@ -29,13 +29,13 @@ describe('normalizeOrderBy', () => { expect(normalizeOrderBy(query)).toEqual(query); }); - it('has timeseries_limit_metric in queryObject', () => { + it('has series_limit_metric in queryObject', () => { const query: QueryObject = { datasource: '5__table', viz_type: 'table', time_range: '1 year ago : 2013', metrics: ['count(*)'], - timeseries_limit_metric: { + series_limit_metric: { expressionType: 'SIMPLE', column: { id: 1, @@ -46,7 +46,7 @@ describe('normalizeOrderBy', () => { order_desc: true, }; const expectedQueryObject = normalizeOrderBy(query); - expect(expectedQueryObject).not.toHaveProperty('timeseries_limit_metric'); + expect(expectedQueryObject).not.toHaveProperty('series_limit_metric'); expect(expectedQueryObject).not.toHaveProperty('order_desc'); expect(expectedQueryObject).toEqual({ datasource: '5__table', @@ -118,7 +118,7 @@ describe('normalizeOrderBy', () => { order_desc: true, }; const expectedQueryObject = normalizeOrderBy(query); - expect(expectedQueryObject).not.toHaveProperty('timeseries_limit_metric'); + expect(expectedQueryObject).not.toHaveProperty('series_limit_metric'); expect(expectedQueryObject).not.toHaveProperty('order_desc'); expect(expectedQueryObject).toEqual({ datasource: '5__table', diff --git a/superset-frontend/packages/superset-ui-core/test/query/normalizeTimeColumn.test.ts b/superset-frontend/packages/superset-ui-core/test/query/normalizeTimeColumn.test.ts new file mode 100644 index 0000000000000..22189b90551c1 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/test/query/normalizeTimeColumn.test.ts @@ -0,0 +1,291 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + normalizeTimeColumn, + QueryObject, + SqlaFormData, +} from '@superset-ui/core'; + +describe('GENERIC_CHART_AXES is disabled', () => { + let windowSpy: any; + + beforeAll(() => { + // @ts-ignore + windowSpy = jest.spyOn(window, 'window', 'get').mockImplementation(() => ({ + featureFlags: { + GENERIC_CHART_AXES: false, + }, + })); + }); + + afterAll(() => { + windowSpy.mockRestore(); + }); + + it('should return original QueryObject if disabled GENERIC_CHART_AXES', () => { + const formData: SqlaFormData = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + time_grain_sqla: 'P1Y', + time_range: '1 year ago : 2013', + columns: ['col1'], + metrics: ['count(*)'], + }; + const query: QueryObject = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + extras: { + time_grain_sqla: 'P1Y', + }, + time_range: '1 year ago : 2013', + orderby: [['count(*)', true]], + columns: ['col1'], + metrics: ['count(*)'], + is_timeseries: true, + }; + expect(normalizeTimeColumn(formData, query)).toEqual(query); + }); + + it('should return converted QueryObject even though disabled GENERIC_CHART_AXES (x_axis in formData)', () => { + const formData: SqlaFormData = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + time_grain_sqla: 'P1Y', + time_range: '1 year ago : 2013', + columns: ['col1'], + metrics: ['count(*)'], + x_axis: 'time_column', + }; + const query: QueryObject = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + extras: { + time_grain_sqla: 'P1Y', + }, + time_range: '1 year ago : 2013', + orderby: [['count(*)', true]], + columns: ['time_column', 'col1'], + metrics: ['count(*)'], + is_timeseries: true, + }; + expect(normalizeTimeColumn(formData, query)).toEqual({ + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + extras: {}, + time_range: '1 year ago : 2013', + orderby: [['count(*)', true]], + columns: [ + { + timeGrain: 'P1Y', + columnType: 'BASE_AXIS', + sqlExpression: 'time_column', + label: 'time_column', + expressionType: 'SQL', + }, + 'col1', + ], + metrics: ['count(*)'], + }); + }); +}); + +describe('GENERIC_CHART_AXES is enabled', () => { + let windowSpy: any; + + beforeAll(() => { + // @ts-ignore + windowSpy = jest.spyOn(window, 'window', 'get').mockImplementation(() => ({ + featureFlags: { + GENERIC_CHART_AXES: true, + }, + })); + }); + + afterAll(() => { + windowSpy.mockRestore(); + }); + + it('should return original QueryObject if x_axis is empty', () => { + const formData: SqlaFormData = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + time_grain_sqla: 'P1Y', + time_range: '1 year ago : 2013', + columns: ['col1'], + metrics: ['count(*)'], + }; + const query: QueryObject = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + extras: { + time_grain_sqla: 'P1Y', + }, + time_range: '1 year ago : 2013', + orderby: [['count(*)', true]], + columns: ['col1'], + metrics: ['count(*)'], + is_timeseries: true, + }; + expect(normalizeTimeColumn(formData, query)).toEqual(query); + }); + + it('should support different columns for x-axis and granularity', () => { + const formData: SqlaFormData = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + time_grain_sqla: 'P1Y', + time_range: '1 year ago : 2013', + x_axis: 'time_column_in_x_axis', + columns: ['col1'], + metrics: ['count(*)'], + }; + const query: QueryObject = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + extras: { + time_grain_sqla: 'P1Y', + where: '', + having: '', + }, + time_range: '1 year ago : 2013', + orderby: [['count(*)', true]], + columns: ['time_column_in_x_axis', 'col1'], + metrics: ['count(*)'], + is_timeseries: true, + }; + expect(normalizeTimeColumn(formData, query)).toEqual({ + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + extras: { where: '', having: '' }, + time_range: '1 year ago : 2013', + orderby: [['count(*)', true]], + columns: [ + { + timeGrain: 'P1Y', + columnType: 'BASE_AXIS', + sqlExpression: 'time_column_in_x_axis', + label: 'time_column_in_x_axis', + expressionType: 'SQL', + }, + 'col1', + ], + metrics: ['count(*)'], + }); + }); + + it('should support custom SQL in x-axis', () => { + const formData: SqlaFormData = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + time_grain_sqla: 'P1Y', + time_range: '1 year ago : 2013', + x_axis: { + expressionType: 'SQL', + label: 'Order Data + 1 year', + sqlExpression: '"Order Date" + interval \'1 year\'', + }, + columns: ['col1'], + metrics: ['count(*)'], + }; + const query: QueryObject = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + extras: { + time_grain_sqla: 'P1Y', + where: '', + having: '', + }, + time_range: '1 year ago : 2013', + orderby: [['count(*)', true]], + columns: [ + { + expressionType: 'SQL', + label: 'Order Data + 1 year', + sqlExpression: '"Order Date" + interval \'1 year\'', + }, + 'col1', + ], + metrics: ['count(*)'], + is_timeseries: true, + }; + expect(normalizeTimeColumn(formData, query)).toEqual({ + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + extras: { where: '', having: '' }, + time_range: '1 year ago : 2013', + orderby: [['count(*)', true]], + columns: [ + { + timeGrain: 'P1Y', + columnType: 'BASE_AXIS', + expressionType: 'SQL', + label: 'Order Data + 1 year', + sqlExpression: `"Order Date" + interval '1 year'`, + }, + 'col1', + ], + metrics: ['count(*)'], + }); + }); + + it('fallback and invalid columns value', () => { + const formData: SqlaFormData = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + time_grain_sqla: 'P1Y', + time_range: '1 year ago : 2013', + x_axis: { + expressionType: 'SQL', + label: 'Order Data + 1 year', + sqlExpression: '"Order Date" + interval \'1 year\'', + }, + columns: ['col1'], + metrics: ['count(*)'], + }; + const query: QueryObject = { + datasource: '5__table', + viz_type: 'table', + granularity: 'time_column', + extras: { + time_grain_sqla: 'P1Y', + where: '', + having: '', + }, + time_range: '1 year ago : 2013', + orderby: [['count(*)', true]], + metrics: ['count(*)'], + is_timeseries: true, + }; + expect(normalizeTimeColumn(formData, query)).toEqual(query); + }); +}); diff --git a/superset-frontend/packages/superset-ui-core/test/query/processFilters.test.ts b/superset-frontend/packages/superset-ui-core/test/query/processFilters.test.ts index 151c0363f16f0..0d4fc4cd9f7c7 100644 --- a/superset-frontend/packages/superset-ui-core/test/query/processFilters.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/query/processFilters.test.ts @@ -28,7 +28,7 @@ describe('processFilters', () => { }), ).toEqual( expect.objectContaining({ - extras: { having: '', having_druid: [], where: '' }, + extras: { having: '', where: '' }, filters: [], }), ); @@ -54,12 +54,19 @@ describe('processFilters', () => { subject: 'gender', operator: 'IS NOT NULL', }, + // ignore simple having filter + { + expressionType: 'SIMPLE', + clause: 'HAVING', + subject: 'sum(sales)', + operator: '>', + comparator: '100', + }, ], }), ).toEqual({ extras: { having: '', - having_druid: [], where: '', }, filters: [ @@ -89,7 +96,6 @@ describe('processFilters', () => { filters: [], extras: { having: '', - having_druid: [], where: '(1 = 1)', }, }); @@ -115,20 +121,6 @@ describe('processFilters', () => { operator: '==', comparator: 'almond', }, - { - expressionType: 'SIMPLE', - clause: 'HAVING', - subject: 'sweetness', - operator: '>', - comparator: '0', - }, - { - expressionType: 'SIMPLE', - clause: 'HAVING', - subject: 'sweetness', - operator: '<=', - comparator: '50', - }, { expressionType: 'SQL', clause: 'WHERE', @@ -154,18 +146,6 @@ describe('processFilters', () => { ).toEqual({ extras: { having: '(ice = 25 OR ice = 50) AND (waitTime <= 180 -- comment\n)', - having_druid: [ - { - col: 'sweetness', - op: '>', - val: '0', - }, - { - col: 'sweetness', - op: '<=', - val: '50', - }, - ], where: "(tea = 'jasmine') AND (cup = 'large' -- comment\n)", }, filters: [ diff --git a/superset-frontend/packages/superset-ui-core/test/query/types/Column.test.ts b/superset-frontend/packages/superset-ui-core/test/query/types/Column.test.ts new file mode 100644 index 0000000000000..d4391cfd01945 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/test/query/types/Column.test.ts @@ -0,0 +1,63 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + isAdhocColumn, + isPhysicalColumn, + isQueryFormColumn, +} from '@superset-ui/core'; + +const adhocColumn = { + expressionType: 'SQL', + label: 'country', + optionName: 'country', + sqlExpression: 'country', +}; + +test('isPhysicalColumn returns true', () => { + expect(isPhysicalColumn('gender')).toEqual(true); +}); + +test('isPhysicalColumn returns false', () => { + expect(isPhysicalColumn(adhocColumn)).toEqual(false); +}); + +test('isAdhocColumn returns true', () => { + expect(isAdhocColumn(adhocColumn)).toEqual(true); +}); + +test('isAdhocColumn returns false', () => { + expect(isAdhocColumn('hello')).toEqual(false); + expect(isAdhocColumn({})).toEqual(false); + expect( + isAdhocColumn({ + expressionType: 'SQL', + label: 'country', + optionName: 'country', + }), + ).toEqual(false); +}); + +test('isQueryFormColumn returns true', () => { + expect(isQueryFormColumn('gender')).toEqual(true); + expect(isQueryFormColumn(adhocColumn)).toEqual(true); +}); + +test('isQueryFormColumn returns false', () => { + expect(isQueryFormColumn({})).toEqual(false); +}); diff --git a/superset-frontend/packages/superset-ui-core/test/query/types/Dashboard.test.ts b/superset-frontend/packages/superset-ui-core/test/query/types/Dashboard.test.ts index ea6236338c765..f72bff490f116 100644 --- a/superset-frontend/packages/superset-ui-core/test/query/types/Dashboard.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/query/types/Dashboard.test.ts @@ -21,27 +21,50 @@ import { isFilterDivider, Filter, NativeFilterType, + FilterWithDataMask, + Divider, + isNativeFilterWithDataMask, } from '@superset-ui/core'; -test('should do native filter type guard', () => { - const dummyFilter: Filter = { - cascadeParentIds: [], - defaultDataMask: {}, - id: 'dummyID', - name: 'dummyName', - scope: { rootPath: [], excluded: [] }, - filterType: 'dummyType', - targets: [{}], - controlValues: {}, - type: NativeFilterType.NATIVE_FILTER, - description: 'dummyDesc', - }; - expect(isNativeFilter(dummyFilter)).toBeTruthy(); - expect( - isFilterDivider({ - ...dummyFilter, - type: NativeFilterType.DIVIDER, - title: 'dummyTitle', - }), - ).toBeTruthy(); +const filter: Filter = { + cascadeParentIds: [], + defaultDataMask: {}, + id: 'filter_id', + name: 'Filter Name', + scope: { rootPath: [], excluded: [] }, + filterType: 'filter_type', + targets: [{}], + controlValues: {}, + type: NativeFilterType.NATIVE_FILTER, + description: 'Filter description.', +}; + +const filterWithDataMask: FilterWithDataMask = { + ...filter, + dataMask: { id: 'data_mask_id', filterState: { value: 'Filter value' } }, +}; + +const filterDivider: Divider = { + id: 'divider_id', + type: NativeFilterType.DIVIDER, + title: 'Divider title', + description: 'Divider description.', +}; + +test('filter type guard', () => { + expect(isNativeFilter(filter)).toBeTruthy(); + expect(isNativeFilter(filterWithDataMask)).toBeTruthy(); + expect(isNativeFilter(filterDivider)).toBeFalsy(); +}); + +test('filter with dataMask type guard', () => { + expect(isNativeFilterWithDataMask(filter)).toBeFalsy(); + expect(isNativeFilterWithDataMask(filterWithDataMask)).toBeTruthy(); + expect(isNativeFilterWithDataMask(filterDivider)).toBeFalsy(); +}); + +test('filter divider type guard', () => { + expect(isFilterDivider(filter)).toBeFalsy(); + expect(isFilterDivider(filterWithDataMask)).toBeFalsy(); + expect(isFilterDivider(filterDivider)).toBeTruthy(); }); diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/legacySortBy.tsx b/superset-frontend/packages/superset-ui-core/test/query/types/Datasource.test.ts similarity index 60% rename from superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/legacySortBy.tsx rename to superset-frontend/packages/superset-ui-core/test/query/types/Datasource.test.ts index 3cb882d29ece6..c80f3d6950017 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/legacySortBy.tsx +++ b/superset-frontend/packages/superset-ui-core/test/query/types/Datasource.test.ts @@ -16,22 +16,22 @@ * specific language governing permissions and limitations * under the License. */ -import { t } from '@superset-ui/core'; -import { ControlSetRow } from '../types'; +import { DatasourceType, DEFAULT_METRICS } from '@superset-ui/core'; -export const legacySortBy: ControlSetRow[] = [ - ['legacy_order_by'], - [ +test('DEFAULT_METRICS', () => { + expect(DEFAULT_METRICS).toEqual([ { - name: 'order_desc', - config: { - type: 'CheckboxControl', - label: t('Sort descending'), - default: true, - description: t( - 'Whether to sort descending or ascending. Takes effect only when "Sort by" is set', - ), - }, + metric_name: 'COUNT(*)', + expression: 'COUNT(*)', }, - ], -]; + ]); +}); + +test('DatasourceType', () => { + expect(Object.keys(DatasourceType).length).toBe(5); + expect(DatasourceType.Table).toBe('table'); + expect(DatasourceType.Query).toBe('query'); + expect(DatasourceType.Dataset).toBe('dataset'); + expect(DatasourceType.SlTable).toBe('sl_table'); + expect(DatasourceType.SavedQuery).toBe('saved_query'); +}); diff --git a/superset-frontend/packages/superset-ui-core/test/query/types/Filter.test.ts b/superset-frontend/packages/superset-ui-core/test/query/types/Filter.test.ts index 3861bb0085b51..4aa4a474159b0 100644 --- a/superset-frontend/packages/superset-ui-core/test/query/types/Filter.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/query/types/Filter.test.ts @@ -21,6 +21,7 @@ import { isUnaryAdhocFilter, isBinaryAdhocFilter, isSetAdhocFilter, + isFreeFormAdhocFilter, } from '@superset-ui/core'; describe('Filter type guards', () => { @@ -95,4 +96,26 @@ describe('Filter type guards', () => { ).toEqual(false); }); }); + describe('isFreeFormAdhocFilter', () => { + it('should return true when it is the correct type', () => { + expect( + isFreeFormAdhocFilter({ + expressionType: 'SQL', + clause: 'WHERE', + sqlExpression: 'gender = "boy"', + }), + ).toEqual(true); + }); + it('should return false otherwise', () => { + expect( + isFreeFormAdhocFilter({ + expressionType: 'SIMPLE', + clause: 'WHERE', + subject: 'tea', + operator: '==', + comparator: 'matcha', + }), + ).toEqual(false); + }); + }); }); diff --git a/superset-frontend/packages/superset-ui-core/test/query/types/Metric.test.ts b/superset-frontend/packages/superset-ui-core/test/query/types/Metric.test.ts new file mode 100644 index 0000000000000..041e913409583 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/test/query/types/Metric.test.ts @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + isSavedMetric, + isAdhocMetricSimple, + isAdhocMetricSQL, + isQueryFormMetric, +} from '@superset-ui/core'; + +const adhocMetricSimple = { + expressionType: 'SIMPLE', + column: { + id: 1, + column_name: 'sales', + columnName: 'sales', + verbose_name: 'sales', + }, + aggregate: 'SUM', + label: 'count', + optionName: 'count', +}; + +const adhocMetricSQL = { + expressionType: 'SQL', + label: 'count', + optionName: 'count', + sqlExpression: 'count(*)', +}; + +const savedMetric = 'count(*)'; + +test('isSavedMetric returns true', () => { + expect(isSavedMetric(savedMetric)).toEqual(true); +}); + +test('isSavedMetric returns false', () => { + expect(isSavedMetric(adhocMetricSQL)).toEqual(false); + expect(isSavedMetric(null)).toEqual(false); + expect(isSavedMetric(undefined)).toEqual(false); +}); + +test('isAdhocMetricSimple returns true', () => { + expect(isAdhocMetricSimple(adhocMetricSimple)).toEqual(true); +}); + +test('isAdhocMetricSimple returns false', () => { + expect(isAdhocMetricSimple('hello')).toEqual(false); + expect(isAdhocMetricSimple({})).toEqual(false); + expect(isAdhocMetricSimple(adhocMetricSQL)).toEqual(false); +}); + +test('isAdhocMetricSQL returns true', () => { + expect(isAdhocMetricSQL(adhocMetricSQL)).toEqual(true); +}); + +test('isAdhocMetricSQL returns false', () => { + expect(isAdhocMetricSQL('hello')).toEqual(false); + expect(isAdhocMetricSQL({})).toEqual(false); + expect(isAdhocMetricSQL(adhocMetricSimple)).toEqual(false); +}); + +test('isQueryFormMetric returns true', () => { + expect(isQueryFormMetric(adhocMetricSQL)).toEqual(true); + expect(isQueryFormMetric(adhocMetricSimple)).toEqual(true); + expect(isQueryFormMetric(savedMetric)).toEqual(true); +}); + +test('isQueryFormMetric returns false', () => { + expect(isQueryFormMetric({})).toEqual(false); + expect(isQueryFormMetric(undefined)).toEqual(false); + expect(isQueryFormMetric(null)).toEqual(false); +}); diff --git a/superset-frontend/packages/superset-ui-core/test/query/types/PostProcessing.test.ts b/superset-frontend/packages/superset-ui-core/test/query/types/PostProcessing.test.ts index 1d7d9f044e5d3..047699fa57415 100644 --- a/superset-frontend/packages/superset-ui-core/test/query/types/PostProcessing.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/query/types/PostProcessing.test.ts @@ -42,7 +42,7 @@ import { PostProcessingRolling, PostProcessingSort, } from '@superset-ui/core'; -import { ComparisionType, RollingType, TimeGranularity } from '../../../src'; +import { ComparisonType, RollingType, TimeGranularity } from '../../../src'; const AGGREGATES_OPTION: Aggregates = { bar: { @@ -74,7 +74,7 @@ const COMPARE_RULE: PostProcessingCompare = { options: { source_columns: ['foo'], compare_columns: ['bar'], - compare_type: ComparisionType.Percentage, + compare_type: ComparisonType.Percentage, drop_original_columns: false, }, }; @@ -110,8 +110,6 @@ const PIVOT_RULE: PostProcessingPivot = { index: ['foo'], columns: ['bar'], aggregates: AGGREGATES_OPTION, - flatten_columns: true, - reset_index: true, }, }; @@ -149,7 +147,7 @@ const ROLLING_RULE: PostProcessingRolling = { const SORT_RULE: PostProcessingSort = { operation: 'sort', options: { - columns: { foo: true }, + by: 'foo', }, }; diff --git a/superset-frontend/packages/superset-ui-core/test/ui-overrides/UiOverrideRegistry.test.ts b/superset-frontend/packages/superset-ui-core/test/ui-overrides/ExtensionsRegistry.test.ts similarity index 81% rename from superset-frontend/packages/superset-ui-core/test/ui-overrides/UiOverrideRegistry.test.ts rename to superset-frontend/packages/superset-ui-core/test/ui-overrides/ExtensionsRegistry.test.ts index 6e440551416dc..e80a3baad4221 100644 --- a/superset-frontend/packages/superset-ui-core/test/ui-overrides/UiOverrideRegistry.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/ui-overrides/ExtensionsRegistry.test.ts @@ -16,8 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import { getUiOverrideRegistry } from '@superset-ui/core'; +import { getExtensionsRegistry } from '@superset-ui/core'; -test('should get instance of getUiOverrideRegistry', () => { - expect(getUiOverrideRegistry().name).toBe('UiOverrideRegistry'); +test('should get instance of getExtensionsRegistry', () => { + expect(getExtensionsRegistry().name).toBe('ExtensionsRegistry'); }); diff --git a/superset-frontend/packages/superset-ui-core/test/utils/featureFlag.test.ts b/superset-frontend/packages/superset-ui-core/test/utils/featureFlag.test.ts index 52a57909aa386..66c58e79af567 100644 --- a/superset-frontend/packages/superset-ui-core/test/utils/featureFlag.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/utils/featureFlag.test.ts @@ -16,20 +16,41 @@ * specific language governing permissions and limitations * under the License. */ +import mockConsole from 'jest-mock-console'; +import { isFeatureEnabled, FeatureFlag } from '@superset-ui/core'; -import { FeatureFlag, isFeatureEnabled } from '@superset-ui/core'; +it('returns false and raises console error if feature flags have not been initialized', () => { + mockConsole(); + Object.defineProperty(window, 'featureFlags', { + value: undefined, + }); + + expect(isFeatureEnabled(FeatureFlag.ALLOW_DASHBOARD_DOMAIN_SHARDING)).toEqual( + false, + ); + expect(console.error).toHaveBeenCalled(); + // @ts-expect-error + expect(console.error.mock.calls[0][0]).toEqual( + 'Failed to query feature flag ALLOW_DASHBOARD_DOMAIN_SHARDING', + ); +}); -describe('isFeatureFlagEnabled', () => { - window.featureFlags = { - [FeatureFlag.CLIENT_CACHE]: true, - }; - it('returns false for unset feature flag', () => { - expect( - isFeatureEnabled(FeatureFlag.ALLOW_DASHBOARD_DOMAIN_SHARDING), - ).toEqual(false); +it('returns false for unset feature flag', () => { + Object.defineProperty(window, 'featureFlags', { + value: {}, }); - it('returns true for set feature flag', () => { - expect(isFeatureEnabled(FeatureFlag.CLIENT_CACHE)).toEqual(true); + expect(isFeatureEnabled(FeatureFlag.ALLOW_DASHBOARD_DOMAIN_SHARDING)).toEqual( + false, + ); +}); + +it('returns true for set feature flag', () => { + Object.defineProperty(window, 'featureFlags', { + value: { + CLIENT_CACHE: true, + }, }); + + expect(isFeatureEnabled(FeatureFlag.CLIENT_CACHE)).toEqual(true); }); diff --git a/superset-frontend/packages/superset-ui-core/test/utils/lruCache.test.ts b/superset-frontend/packages/superset-ui-core/test/utils/lruCache.test.ts new file mode 100644 index 0000000000000..f8a077eba0318 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/test/utils/lruCache.test.ts @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { lruCache } from '@superset-ui/core'; + +test('initial LRU', () => { + expect(lruCache().capacity).toBe(100); + expect(lruCache(10).capacity).toBe(10); + expect(lruCache(10).size).toBe(0); + expect(() => lruCache(0)).toThrow(Error); +}); + +test('LRU operations', () => { + const cache = lruCache<string>(3); + cache.set('1', 'a'); + cache.set('2', 'b'); + cache.set('3', 'c'); + cache.set('4', 'd'); + expect(cache.size).toBe(3); + expect(cache.has('1')).toBeFalsy(); + expect(cache.get('1')).toBeUndefined(); + cache.get('2'); + cache.set('5', 'e'); + expect(cache.has('2')).toBeTruthy(); + expect(cache.has('3')).toBeFalsy(); + // @ts-expect-error + expect(() => cache.set(0)).toThrow(TypeError); + // @ts-expect-error + expect(() => cache.get(0)).toThrow(TypeError); + expect(cache.size).toBe(3); + cache.clear(); + expect(cache.size).toBe(0); + expect(cache.capacity).toBe(3); +}); + +test('LRU handle null and undefined', () => { + const cache = lruCache(); + cache.set('a', null); + cache.set('b', undefined); + expect(cache.has('a')).toBeTruthy(); + expect(cache.has('b')).toBeTruthy(); + expect(cache.get('a')).toBeNull(); + expect(cache.get('b')).toBeUndefined(); +}); diff --git a/superset-frontend/packages/superset-ui-core/types/external.d.ts b/superset-frontend/packages/superset-ui-core/types/external.d.ts index 31b0250bf4455..dcce5fa8823f8 100644 --- a/superset-frontend/packages/superset-ui-core/types/external.d.ts +++ b/superset-frontend/packages/superset-ui-core/types/external.d.ts @@ -17,6 +17,6 @@ * under the License. */ /** - * Stub for the untypped jed module. + * Stub for the untyped jed module. */ declare module 'jed'; diff --git a/superset-frontend/packages/superset-ui-demo/package.json b/superset-frontend/packages/superset-ui-demo/package.json index bf3da61c12583..a2ff398662dc1 100644 --- a/superset-frontend/packages/superset-ui-demo/package.json +++ b/superset-frontend/packages/superset-ui-demo/package.json @@ -41,7 +41,7 @@ "@storybook/addons": "^6.3.12", "@storybook/react": "^6.3.12", "@types/react-loadable": "^5.5.3", - "antd": "^4.9.4", + "antd": "4.10.3", "bootstrap": "^3.4.1", "core-js": "3.8.3", "gh-pages": "^3.0.0", diff --git a/superset-frontend/packages/superset-ui-demo/storybook/shared/components/VerifyCORS.tsx b/superset-frontend/packages/superset-ui-demo/storybook/shared/components/VerifyCORS.tsx index de0b2ef8aba05..3aa082186981d 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/shared/components/VerifyCORS.tsx +++ b/superset-frontend/packages/superset-ui-demo/storybook/shared/components/VerifyCORS.tsx @@ -23,6 +23,7 @@ import { Method, makeApi, SupersetApiError, + t, } from '@superset-ui/core'; import ErrorMessage from './ErrorMessage'; @@ -121,7 +122,7 @@ export default class VerifyCORS extends React.Component<Props, State> { className="btn btn-primary btn-sm" onClick={this.handleVerify} > - Verify + {t('Verify')} </button> <br /> <br /> diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/controlsShown.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/controlsShown.tsx index fac198e826e84..603ef83b0f5b5 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/controlsShown.tsx +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/controlsShown.tsx @@ -31,7 +31,7 @@ export const controlsShown = () => ( queriesData={[{ data }]} formData={{ bottomMargin: 'auto', - colorCcheme: 'd3Category10', + colorScheme: 'd3Category10', contribution: false, groupby: ['region'], lineInterpolation: 'linear', diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/expanded.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/expanded.tsx index 8f71fb5289f73..b26e7dfa6dba5 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/expanded.tsx +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/expanded.tsx @@ -31,7 +31,7 @@ export const expanded = () => ( queriesData={[{ data }]} formData={{ bottomMargin: 'auto', - colorCcheme: 'd3Category10', + colorScheme: 'd3Category10', contribution: false, groupby: ['region'], lineInterpolation: 'linear', diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/stackedWithBounds.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/stackedWithBounds.tsx index d3dccc63d4f67..6f7a19825a2d1 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/stackedWithBounds.tsx +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-nvd3/Area/stories/stackedWithBounds.tsx @@ -31,7 +31,7 @@ export const stackedWithYAxisBounds = () => ( queriesData={[{ data }]} formData={{ bottomMargin: 'auto', - colorCcheme: 'd3Category10', + colorScheme: 'd3Category10', contribution: false, groupby: ['region'], lineInterpolation: 'linear', @@ -66,7 +66,7 @@ export const stackedWithYAxisBoundsMinOnly = () => ( queriesData={[{ data }]} formData={{ bottomMargin: 'auto', - colorCcheme: 'd3Category10', + colorScheme: 'd3Category10', contribution: false, groupby: ['region'], lineInterpolation: 'linear', diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/AreaTimeseries/Stories.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/AreaTimeseries/Stories.tsx new file mode 100644 index 0000000000000..4cffeabd38a9e --- /dev/null +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/AreaTimeseries/Stories.tsx @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { SuperChart, getChartTransformPropsRegistry } from '@superset-ui/core'; +import { boolean, number, select, withKnobs } from '@storybook/addon-knobs'; +import { + EchartsAreaChartPlugin, + TimeseriesTransformProps, +} from '@superset-ui/plugin-chart-echarts'; +import data from './data'; +import { withResizableChartDemo } from '../../../../shared/components/ResizableChartDemo'; + +new EchartsAreaChartPlugin().configure({ key: 'echarts_area' }).register(); + +getChartTransformPropsRegistry().registerValue( + 'echarts_area', + TimeseriesTransformProps, +); + +export default { + title: 'Chart Plugins/plugin-chart-echarts/Timeseries Area', + decorators: [withKnobs, withResizableChartDemo], +}; + +export const Timeseries = ({ width, height }) => { + const forecastEnabled = boolean('Enable forecast', true); + const queryData = data + .map(row => + forecastEnabled + ? row + : { + // eslint-disable-next-line no-underscore-dangle + __timestamp: row.__timestamp, + Boston: row.Boston, + California: row.California, + WestTexNewMexico: row.WestTexNewMexico, + }, + ) + .filter(row => forecastEnabled || !!row.Boston); + return ( + <SuperChart + chartType="echarts_area" + width={width} + height={height} + queriesData={[{ data: queryData }]} + formData={{ + area: true, + contributionMode: undefined, + forecastEnabled, + colorScheme: 'supersetColors', + seriesType: select( + 'Line type', + ['line', 'scatter', 'smooth', 'bar', 'start', 'middle', 'end'], + 'line', + ), + show_extra_controls: boolean('Extra Controls', false), + logAxis: boolean('Log axis', false), + yAxisFormat: 'SMART_NUMBER', + stack: boolean('Stack', false), + showValue: boolean('Show Values', false), + onlyTotal: boolean('Only Total', false), + percentageThreshold: number('Percentage Threshold', 0), + markerEnabled: boolean('Enable markers', false), + markerSize: number('Marker Size', 6), + minorSplitLine: boolean('Minor splitline', false), + opacity: number('Opacity', 0.2), + zoomable: boolean('Zoomable', false), + }} + /> + ); +}; diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/AreaTimeseries/data.ts b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/AreaTimeseries/data.ts new file mode 100644 index 0000000000000..ac6b5d0a5463e --- /dev/null +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/AreaTimeseries/data.ts @@ -0,0 +1,771 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export default [ + { + __timestamp: 1419811200000, + Boston__yhat: 1.5348466045278903, + Boston__yhat_lower: 1.4108696830290821, + Boston__yhat_upper: 1.65406759478647, + Boston: 1.425, + California__yhat: 1.1428578093572317, + California__yhat_lower: 0.9954265301846809, + California__yhat_upper: 1.285336837473888, + California: 1.085, + WestTexNewMexico__yhat: 1.2189159706952082, + WestTexNewMexico__yhat_lower: 1.04104376708674, + WestTexNewMexico__yhat_upper: 1.3729774938431487, + WestTexNewMexico: 1.195, + }, + { + __timestamp: 1420416000000, + Boston__yhat: 1.5183086928032201, + Boston__yhat_lower: 1.4051623626305831, + Boston__yhat_upper: 1.6373864508998999, + Boston: 1.52, + California__yhat: 1.1473836815806109, + California__yhat_lower: 0.9896908958316125, + California__yhat_upper: 1.3074486619072236, + California: 1.01, + WestTexNewMexico__yhat: 1.2101876636102695, + WestTexNewMexico__yhat_lower: 1.0531768381015862, + WestTexNewMexico__yhat_upper: 1.3798811980337082, + WestTexNewMexico: 1.305, + }, + { + __timestamp: 1421020800000, + Boston__yhat: 1.5008792239446107, + Boston__yhat_lower: 1.3900408734935294, + Boston__yhat_upper: 1.6209717523914786, + Boston: 1.615, + California__yhat: 1.1257411477192287, + California__yhat_lower: 0.9647179126679808, + California__yhat_upper: 1.2856214776337003, + California: 1.13, + WestTexNewMexico__yhat: 1.211700721257458, + WestTexNewMexico__yhat_lower: 1.0512509758817796, + WestTexNewMexico__yhat_upper: 1.3838299538827643, + WestTexNewMexico: 1.255, + }, + { + __timestamp: 1421625600000, + Boston__yhat: 1.493895763520492, + Boston__yhat_lower: 1.3819463100452443, + Boston__yhat_upper: 1.614560073797367, + Boston: 1.59, + California__yhat: 1.0914497359848156, + California__yhat_lower: 0.9309999613012108, + California__yhat_upper: 1.2413000315404008, + California: 1.18, + WestTexNewMexico__yhat: 1.208627046579019, + WestTexNewMexico__yhat_lower: 1.0443728779662684, + WestTexNewMexico__yhat_upper: 1.3675637830491076, + WestTexNewMexico: 1.215, + }, + { + __timestamp: 1422230400000, + Boston__yhat: 1.5016078116606606, + Boston__yhat_lower: 1.3867245804741557, + Boston__yhat_upper: 1.614234955854214, + Boston: 1.5, + California__yhat: 1.0697859033873383, + California__yhat_lower: 0.9250294445931526, + California__yhat_upper: 1.227180419756037, + California: 0.98, + WestTexNewMexico__yhat: 1.1903524073209464, + WestTexNewMexico__yhat_lower: 1.0158621722285877, + WestTexNewMexico__yhat_upper: 1.3552685059028697, + WestTexNewMexico: 1.24, + }, + { + __timestamp: 1422835200000, + Boston__yhat: 1.5159923617934186, + Boston__yhat_lower: 1.3970137282601371, + Boston__yhat_upper: 1.6308844178549995, + Boston: 1.475, + California__yhat: 1.0746946690720922, + California__yhat_lower: 0.9113788241318873, + California__yhat_upper: 1.2273689220316724, + California: 1.13, + WestTexNewMexico__yhat: 1.162418169193016, + WestTexNewMexico__yhat_lower: 0.984399666972796, + WestTexNewMexico__yhat_upper: 1.3286127921414361, + WestTexNewMexico: 1.19, + }, + { + __timestamp: 1423440000000, + Boston__yhat: 1.525604106275286, + Boston__yhat_lower: 1.4091552054110317, + Boston__yhat_upper: 1.6398544651033324, + Boston: 1.555, + California__yhat: 1.0983484232374483, + California__yhat_lower: 0.9499667479813172, + California__yhat_upper: 1.2604622036877084, + California: 1.24, + WestTexNewMexico__yhat: 1.1407497573494716, + WestTexNewMexico__yhat_lower: 0.9682090338277108, + WestTexNewMexico__yhat_upper: 1.3110751375528853, + WestTexNewMexico: 1.24, + }, + { + __timestamp: 1424044800000, + Boston__yhat: 1.5285159859188788, + Boston__yhat_lower: 1.4151325345500827, + Boston__yhat_upper: 1.63898403722097, + Boston: 1.485, + California__yhat: 1.1215587530856748, + California__yhat_lower: 0.9680608180357422, + California__yhat_upper: 1.282442960930767, + California: 1.185, + WestTexNewMexico__yhat: 1.1360040254613264, + WestTexNewMexico__yhat_lower: 0.963307750313048, + WestTexNewMexico__yhat_upper: 1.2986544671046583, + WestTexNewMexico: 1.28, + }, + { + __timestamp: 1424649600000, + Boston__yhat: 1.5334822003771225, + Boston__yhat_lower: 1.4176345632105387, + Boston__yhat_upper: 1.6496071238192505, + Boston: 1.48, + California__yhat: 1.1336412205342397, + California__yhat_lower: 0.9743289540694136, + California__yhat_upper: 1.2898768461219847, + California: 0.995, + WestTexNewMexico__yhat: 1.1446754348884136, + WestTexNewMexico__yhat_lower: 0.986235125109336, + WestTexNewMexico__yhat_upper: 1.307986287217312, + WestTexNewMexico: 1.24, + }, + { + __timestamp: 1425254400000, + Boston__yhat: 1.547848654545939, + Boston__yhat_lower: 1.4328177356803633, + Boston__yhat_upper: 1.673661661344583, + Boston: 1.54, + California__yhat: 1.1421270972002817, + California__yhat_lower: 0.9880212170643778, + California__yhat_upper: 1.298074311825913, + California: 1.22, + WestTexNewMexico__yhat: 1.1538926041448758, + WestTexNewMexico__yhat_lower: 1.0019767923899103, + WestTexNewMexico__yhat_upper: 1.3221026377048228, + WestTexNewMexico: 1.16, + }, + { + __timestamp: 1425859200000, + Boston__yhat: 1.5675203083502125, + Boston__yhat_lower: 1.4543946077807537, + Boston__yhat_upper: 1.6864674764386627, + Boston: 1.62, + California__yhat: 1.1632572393543539, + California__yhat_lower: 0.9970086508003331, + California__yhat_upper: 1.3209871054747437, + California: 1.29, + WestTexNewMexico__yhat: 1.1530029605889838, + WestTexNewMexico__yhat_lower: 0.9729319698723828, + WestTexNewMexico__yhat_upper: 1.3054475293729533, + WestTexNewMexico: 1.285, + }, + { + __timestamp: 1426464000000, + Boston__yhat: 1.581607931619551, + Boston__yhat_lower: 1.4723154031359578, + Boston__yhat_upper: 1.7069606387126863, + Boston: 1.56, + California__yhat: 1.2030769562029524, + California__yhat_lower: 1.04933598570031, + California__yhat_upper: 1.3591487662881023, + California: 1.18, + WestTexNewMexico__yhat: 1.1414541767825306, + WestTexNewMexico__yhat_lower: 0.9717441065782068, + WestTexNewMexico__yhat_upper: 1.312661843170456, + WestTexNewMexico: 1.345, + }, + { + __timestamp: 1427068800000, + Boston__yhat: 1.5853316979769883, + Boston__yhat_lower: 1.4708451743058149, + Boston__yhat_upper: 1.7117728705026014, + Boston: 1.585, + California__yhat: 1.2479444775684796, + California__yhat_lower: 1.0837411336417548, + California__yhat_upper: 1.3998890149965297, + California: 1.315, + WestTexNewMexico__yhat: 1.1283059431234486, + WestTexNewMexico__yhat_lower: 0.9778619797162577, + WestTexNewMexico__yhat_upper: 1.2954488963192434, + WestTexNewMexico: 1.255, + }, + { + __timestamp: 1427673600000, + Boston__yhat: 1.5841383828593085, + Boston__yhat_lower: 1.4654575751911438, + Boston__yhat_upper: 1.6946343035808373, + Boston: 1.59, + California__yhat: 1.2739437360014318, + California__yhat_lower: 1.1100282969104833, + California__yhat_upper: 1.428117476226516, + California: 1.32, + WestTexNewMexico__yhat: 1.1249371539002126, + WestTexNewMexico__yhat_lower: 0.9695967792994402, + WestTexNewMexico__yhat_upper: 1.287869970682996, + WestTexNewMexico: 1.28, + }, + { + __timestamp: 1428278400000, + Boston__yhat: 1.5839751550296846, + Boston__yhat_lower: 1.4658964846078435, + Boston__yhat_upper: 1.710402200124056, + Boston: 1.56, + California__yhat: 1.2665706718822929, + California__yhat_lower: 1.1158333765771138, + California__yhat_upper: 1.4320483959058965, + California: 1.28, + WestTexNewMexico__yhat: 1.1355965911503207, + WestTexNewMexico__yhat_lower: 0.964066677858961, + WestTexNewMexico__yhat_upper: 1.3022575299852956, + WestTexNewMexico: 1.21, + }, + { + __timestamp: 1428883200000, + Boston__yhat: 1.5816178634356794, + Boston__yhat_lower: 1.4715929905435854, + Boston__yhat_upper: 1.7003122219671367, + Boston: 1.545, + California__yhat: 1.232881524770783, + California__yhat_lower: 1.0767786935430315, + California__yhat_upper: 1.3959964303961667, + California: 1.285, + WestTexNewMexico__yhat: 1.1523828742682716, + WestTexNewMexico__yhat_lower: 0.9811195853500172, + WestTexNewMexico__yhat_upper: 1.3138046554765905, + WestTexNewMexico: 1.15, + }, + { + __timestamp: 1429488000000, + Boston__yhat: 1.5693505553611033, + Boston__yhat_lower: 1.454366551073654, + Boston__yhat_upper: 1.672997430777775, + Boston: 1.57, + California__yhat: 1.1961960021745208, + California__yhat_lower: 1.0574856955397094, + California__yhat_upper: 1.3527191406913728, + California: 1.325, + WestTexNewMexico__yhat: 1.1605683040698191, + WestTexNewMexico__yhat_lower: 1.0031473604785308, + WestTexNewMexico__yhat_upper: 1.3131490159580719, + WestTexNewMexico: 1.33, + }, + { + __timestamp: 1430092800000, + Boston__yhat: 1.548687090028952, + Boston__yhat_lower: 1.4345338808929986, + Boston__yhat_upper: 1.674291034018414, + Boston: 1.495, + California__yhat: 1.17944168965866, + California__yhat_lower: 1.0208437159576145, + California__yhat_upper: 1.3437648164186333, + California: 1.18, + WestTexNewMexico__yhat: 1.152452251304891, + WestTexNewMexico__yhat_lower: 0.9925163021235553, + WestTexNewMexico__yhat_upper: 1.33370469389031, + WestTexNewMexico: 1.125, + }, + { + __timestamp: 1430697600000, + Boston__yhat: 1.5339945463021136, + Boston__yhat_lower: 1.4131803310322042, + Boston__yhat_upper: 1.6534068731295286, + Boston: 1.58, + California__yhat: 1.1914708975476587, + California__yhat_lower: 1.0346943811155895, + California__yhat_upper: 1.346918284211045, + California: 1.165, + WestTexNewMexico__yhat: 1.136951442350726, + WestTexNewMexico__yhat_lower: 0.9785853981941628, + WestTexNewMexico__yhat_upper: 1.305120499270747, + WestTexNewMexico: 1.07, + }, + { + __timestamp: 1431302400000, + Boston__yhat: 1.538494530655746, + Boston__yhat_lower: 1.417157877783077, + Boston__yhat_upper: 1.6657402419552576, + Boston: 1.585, + California__yhat: 1.2250425993396363, + California__yhat_lower: 1.0694624006721893, + California__yhat_upper: 1.3779793141537178, + California: 1.285, + WestTexNewMexico__yhat: 1.131850140196041, + WestTexNewMexico__yhat_lower: 0.9693152036413223, + WestTexNewMexico__yhat_upper: 1.2969371429211514, + WestTexNewMexico: 1.06, + }, + { + __timestamp: 1431907200000, + Boston__yhat: 1.5586586605892516, + Boston__yhat_lower: 1.4437718674345732, + Boston__yhat_upper: 1.678444300307212, + Boston: 1.54, + California__yhat: 1.2640228484312774, + California__yhat_lower: 1.105695580617842, + California__yhat_upper: 1.4262751320209555, + California: 1.3, + WestTexNewMexico__yhat: 1.14279691969869, + WestTexNewMexico__yhat_lower: 0.9744635833347896, + WestTexNewMexico__yhat_upper: 1.309843116203469, + WestTexNewMexico: 1.065, + }, + { + __timestamp: 1432512000000, + Boston__yhat: 1.5775197465059267, + Boston__yhat_lower: 1.4598708798261923, + Boston__yhat_upper: 1.6911276338952719, + Boston: 1.6, + California__yhat: 1.292475578711032, + California__yhat_lower: 1.1228796890918014, + California__yhat_upper: 1.4471391733217347, + California: 1.24, + WestTexNewMexico__yhat: 1.151946670246945, + WestTexNewMexico__yhat_lower: 0.9787075088274869, + WestTexNewMexico__yhat_upper: 1.3257344034341332, + WestTexNewMexico: 1.065, + }, + { + __timestamp: 1433116800000, + Boston__yhat: 1.5847361491556036, + Boston__yhat_lower: 1.469478725883583, + Boston__yhat_upper: 1.698200477547973, + Boston: 1.625, + California__yhat: 1.301640708602741, + California__yhat_lower: 1.1448194258091566, + California__yhat_upper: 1.4657411831360765, + California: 1.325, + WestTexNewMexico__yhat: 1.1344270549760207, + WestTexNewMexico__yhat_lower: 0.9628949633601395, + WestTexNewMexico__yhat_upper: 1.2999364461809975, + WestTexNewMexico: 1.08, + }, + { + __timestamp: 1433721600000, + Boston__yhat: 1.588841301654564, + Boston__yhat_lower: 1.4701868286368829, + Boston__yhat_upper: 1.708276878629705, + Boston: 1.555, + California__yhat: 1.2945568932951903, + California__yhat_lower: 1.1357913193434988, + California__yhat_upper: 1.441658100122194, + California: 1.325, + WestTexNewMexico__yhat: 1.090609476160724, + WestTexNewMexico__yhat_lower: 0.9171628023326979, + WestTexNewMexico__yhat_upper: 1.2519104172461586, + WestTexNewMexico: 1.125, + }, + { + __timestamp: 1434326400000, + Boston__yhat: 1.60467809761448, + Boston__yhat_lower: 1.4872087156545453, + Boston__yhat_upper: 1.7206390174307566, + Boston: 1.65, + California__yhat: 1.2866911289244536, + California__yhat_lower: 1.1223304657283866, + California__yhat_upper: 1.4489712765550424, + California: 1.38, + WestTexNewMexico__yhat: 1.058286202137859, + WestTexNewMexico__yhat_lower: 0.8983319008178635, + WestTexNewMexico__yhat_upper: 1.2230688588329341, + WestTexNewMexico: 1.2, + }, + { + __timestamp: 1434931200000, + Boston__yhat: 1.6296561292532252, + Boston__yhat_lower: 1.5147117985377605, + Boston__yhat_upper: 1.7484553862428687, + Boston: 1.64, + California__yhat: 1.298704180420278, + California__yhat_lower: 1.143996831592798, + California__yhat_upper: 1.4569530963291766, + California: 1.385, + WestTexNewMexico__yhat: 1.0837741118769433, + WestTexNewMexico__yhat_lower: 0.9165400527844431, + WestTexNewMexico__yhat_upper: 1.2633713277285281, + WestTexNewMexico: 1.145, + }, + { + __timestamp: 1435536000000, + Boston__yhat: 1.6387330700540754, + Boston__yhat_lower: 1.5214382052884348, + Boston__yhat_upper: 1.7593446818133576, + Boston: 1.7, + California__yhat: 1.3419159537936654, + California__yhat_lower: 1.1824389777530346, + California__yhat_upper: 1.5077615808876883, + California: 1.395, + WestTexNewMexico__yhat: 1.1753283438356257, + WestTexNewMexico__yhat_lower: 1.0084515427055218, + WestTexNewMexico__yhat_upper: 1.3411968014102083, + WestTexNewMexico: 1.18, + }, + { + __timestamp: 1436140800000, + Boston__yhat: 1.6078378110129543, + Boston__yhat_lower: 1.4858780410049368, + Boston__yhat_upper: 1.7333942938670541, + Boston: 1.665, + California__yhat: 1.4064610022347392, + California__yhat_lower: 1.2518481325894115, + California__yhat_upper: 1.5631376401498112, + California: 1.465, + WestTexNewMexico__yhat: 1.2876812690769497, + WestTexNewMexico__yhat_lower: 1.118277996711148, + WestTexNewMexico__yhat_upper: 1.453601368173299, + WestTexNewMexico: 1.365, + }, + { + __timestamp: 1436745600000, + Boston__yhat: 1.54126454151401, + Boston__yhat_lower: 1.4242640278872807, + Boston__yhat_upper: 1.658820938407199, + Boston: 1.615, + California__yhat: 1.4648637533773619, + California__yhat_lower: 1.3165708549095063, + California__yhat_upper: 1.6123722518242183, + California: 1.535, + WestTexNewMexico__yhat: 1.359084635413718, + WestTexNewMexico__yhat_lower: 1.1923924916510695, + WestTexNewMexico__yhat_upper: 1.5397046826260015, + WestTexNewMexico: 1.25, + }, + { + __timestamp: 1437350400000, + Boston__yhat: 1.4716975989229104, + Boston__yhat_lower: 1.3478802335545248, + Boston__yhat_upper: 1.5897005348114144, + Boston: 1.65, + California__yhat: 1.492196708250474, + California__yhat_lower: 1.3281011466171584, + California__yhat_upper: 1.6482617063876424, + California: 1.53, + WestTexNewMexico__yhat: 1.3665720856468249, + WestTexNewMexico__yhat_lower: 1.1985870084342607, + WestTexNewMexico__yhat_upper: 1.540444302838635, + WestTexNewMexico: 1.325, + }, + { + __timestamp: 1437955200000, + Boston__yhat: 1.4316465654883939, + Boston__yhat_lower: 1.3151590237205186, + Boston__yhat_upper: 1.5502363732881383, + Boston: 1.645, + California__yhat: 1.486878703643501, + California__yhat_lower: 1.3387136764087475, + California__yhat_upper: 1.6406538496379224, + California: 1.575, + WestTexNewMexico__yhat: 1.3430004296140337, + WestTexNewMexico__yhat_lower: 1.1696134333274417, + WestTexNewMexico__yhat_upper: 1.5143254675484394, + WestTexNewMexico: 1.345, + }, + { + __timestamp: 1438560000000, + Boston__yhat: 1.4271527274427822, + Boston__yhat_lower: 1.3009869979033386, + Boston__yhat_upper: 1.5444571765505344, + Boston: 1.545, + California__yhat: 1.4721251850161223, + California__yhat_lower: 1.3130424764080704, + California__yhat_upper: 1.6322300582937983, + California: 1.565, + WestTexNewMexico__yhat: 1.3385023304664054, + WestTexNewMexico__yhat_lower: 1.169557000507694, + WestTexNewMexico__yhat_upper: 1.501423586440048, + WestTexNewMexico: 1.3, + }, + { + __timestamp: 1439164800000, + Boston__yhat: 1.4407299749907534, + Boston__yhat_lower: 1.323436292855159, + Boston__yhat_upper: 1.5636100946562665, + Boston: 1.62, + California__yhat: 1.4747274927843579, + California__yhat_lower: 1.3090246017944651, + California__yhat_upper: 1.6212028571910875, + California: 1.535, + WestTexNewMexico__yhat: 1.369033029466056, + WestTexNewMexico__yhat_lower: 1.2063418855681307, + WestTexNewMexico__yhat_upper: 1.5410908830393701, + WestTexNewMexico: 1.215, + }, + { + __timestamp: 1439769600000, + Boston__yhat: 1.4558141240561584, + Boston__yhat_lower: 1.3384500860436346, + Boston__yhat_upper: 1.5593449899412495, + Boston: 1.535, + California__yhat: 1.5004588541583503, + California__yhat_lower: 1.3525771130800601, + California__yhat_upper: 1.6557709189818204, + California: 1.515, + WestTexNewMexico__yhat: 1.4078705349829708, + WestTexNewMexico__yhat_lower: 1.2465576754469605, + WestTexNewMexico__yhat_upper: 1.5765990094113416, + WestTexNewMexico: 1.205, + }, + { + __timestamp: 1440374400000, + Boston__yhat: 1.4714837581619955, + Boston__yhat_lower: 1.3542849882799493, + Boston__yhat_upper: 1.587250053083524, + Boston: 1.58, + California__yhat: 1.5302322554730527, + California__yhat_lower: 1.3712263333300627, + California__yhat_upper: 1.6766472256899916, + California: 1.53, + WestTexNewMexico__yhat: 1.425931627994101, + WestTexNewMexico__yhat_lower: 1.2620778981321579, + WestTexNewMexico__yhat_upper: 1.5920830784029816, + WestTexNewMexico: 1.255, + }, + { + __timestamp: 1440979200000, + Boston__yhat: 1.491444403016728, + Boston__yhat_lower: 1.3719274262306433, + Boston__yhat_upper: 1.6081603165448515, + Boston: 1.54, + California__yhat: 1.5411777460499874, + California__yhat_lower: 1.3904365117687372, + California__yhat_upper: 1.694546785101698, + California: 1.54, + WestTexNewMexico__yhat: 1.4320134472163049, + WestTexNewMexico__yhat_lower: 1.273365593253299, + WestTexNewMexico__yhat_upper: 1.5931974288222444, + WestTexNewMexico: 1.29, + }, + { + __timestamp: 1441584000000, + Boston__yhat: 1.5051820756139245, + Boston__yhat_lower: 1.3835553327078385, + Boston__yhat_upper: 1.6240589221993718, + Boston: 1.515, + California__yhat: 1.5313765368007273, + California__yhat_lower: 1.3681294180618269, + California__yhat_upper: 1.6892153479755334, + California: 1.55, + WestTexNewMexico__yhat: 1.4638751687570226, + WestTexNewMexico__yhat_lower: 1.2864210645323784, + WestTexNewMexico__yhat_upper: 1.6187694320540935, + WestTexNewMexico: 1.37, + }, + { + __timestamp: 1442188800000, + Boston__yhat: 1.4894325587299742, + Boston__yhat_lower: 1.3727869467332703, + Boston__yhat_upper: 1.6084226338870418, + Boston: 1.58, + California__yhat: 1.522640140138669, + California__yhat_lower: 1.3734557489282102, + California__yhat_upper: 1.6743091049728624, + California: 1.53, + WestTexNewMexico__yhat: 1.5400751405380166, + WestTexNewMexico__yhat_lower: 1.3774375535282375, + WestTexNewMexico__yhat_upper: 1.723050870346822, + WestTexNewMexico: 1.485, + }, + { + __timestamp: 1442793600000, + Boston__yhat: 1.4322083667601824, + Boston__yhat_lower: 1.3101390870258312, + Boston__yhat_upper: 1.5571183048764867, + Boston: 1.535, + California__yhat: 1.5378925480202739, + California__yhat_lower: 1.3886019658089772, + California__yhat_upper: 1.6978496884233474, + California: 1.445, + WestTexNewMexico__yhat: 1.6287478669084643, + WestTexNewMexico__yhat_lower: 1.478287058860101, + WestTexNewMexico__yhat_upper: 1.795633152002224, + WestTexNewMexico: 1.275, + }, + { + __timestamp: 1443398400000, + Boston__yhat: 1.351816621968265, + Boston__yhat_lower: 1.2376540378452352, + Boston__yhat_upper: 1.4729299390946764, + Boston: 1.175, + California__yhat: 1.5759661525657334, + California__yhat_lower: 1.4231456717732236, + California__yhat_upper: 1.733586091013307, + California: 1.51, + WestTexNewMexico__yhat: 1.6721603417638533, + WestTexNewMexico__yhat_lower: 1.508503941330916, + WestTexNewMexico__yhat_upper: 1.8462459308936394, + WestTexNewMexico: 1.43, + }, + { + __timestamp: 1444003200000, + Boston__yhat: 1.286486461072129, + Boston__yhat_lower: 1.1680220690052265, + Boston__yhat_upper: 1.4035977590666622, + Boston: 1.2, + California__yhat: 1.6097139361369517, + California__yhat_lower: 1.4449082988736466, + California__yhat_upper: 1.7603053272180196, + California: 1.575, + WestTexNewMexico__yhat: 1.639290251177639, + WestTexNewMexico__yhat_lower: 1.473164681029519, + WestTexNewMexico__yhat_upper: 1.8064957246654998, + WestTexNewMexico: 1.47, + }, + { + __timestamp: 1444608000000, + Boston__yhat: 1.2630051620190224, + Boston__yhat_lower: 1.1467376145041555, + Boston__yhat_upper: 1.377446221614078, + Boston: 1.1, + California__yhat: 1.6098713751752662, + California__yhat_lower: 1.4600843147210683, + California__yhat_upper: 1.763955521152191, + California: 1.54, + WestTexNewMexico__yhat: 1.5551952931382806, + WestTexNewMexico__yhat_lower: 1.3962129897996904, + WestTexNewMexico__yhat_upper: 1.726357454658797, + WestTexNewMexico: 1.415, + }, + { + __timestamp: 1445212800000, + Boston__yhat: 1.276278781347193, + Boston__yhat_lower: 1.1580450205542776, + Boston__yhat_upper: 1.3920651070329326, + Boston: 1.145, + California__yhat: 1.571148844853862, + California__yhat_lower: 1.4083378535887405, + California__yhat_upper: 1.733966017882931, + California: 1.38, + WestTexNewMexico__yhat: 1.4722932415830279, + WestTexNewMexico__yhat_lower: 1.3050378331324088, + WestTexNewMexico__yhat_upper: 1.6418924805303612, + WestTexNewMexico: 1.41, + }, + { + __timestamp: 1445817600000, + Boston__yhat: 1.2991073481696098, + Boston__yhat_lower: 1.1878452793959065, + Boston__yhat_upper: 1.424293199867907, + Boston: 1.18, + California__yhat: 1.5150187954091354, + California__yhat_lower: 1.3476318997481405, + California__yhat_upper: 1.677657858675358, + California: 1.275, + WestTexNewMexico__yhat: 1.4199561158957161, + WestTexNewMexico__yhat_lower: 1.263080331712721, + WestTexNewMexico__yhat_upper: 1.5718996342613911, + WestTexNewMexico: 1.36, + }, + { + __timestamp: 1446422400000, + Boston__yhat: 1.308880887797368, + Boston__yhat_lower: 1.1862924735231104, + Boston__yhat_upper: 1.4168025454442827, + Boston: 1.13, + California__yhat: 1.467196455991084, + California__yhat_lower: 1.31469058277437, + California__yhat_upper: 1.6266140472626818, + California: 1.32, + WestTexNewMexico__yhat: 1.385809818488925, + WestTexNewMexico__yhat_lower: 1.2178231659097734, + WestTexNewMexico__yhat_upper: 1.5529990050614997, + WestTexNewMexico: 1.37, + }, + { + __timestamp: 1447027200000, + Boston__yhat: 1.3030202507313675, + Boston__yhat_lower: 1.1871331759675903, + Boston__yhat_upper: 1.4220034213332513, + Boston: 1.1, + California__yhat: 1.432710953584346, + California__yhat_lower: 1.2824951329265597, + California__yhat_upper: 1.586661603708675, + California: 1.21, + WestTexNewMexico__yhat: 1.3404954026443072, + WestTexNewMexico__yhat_lower: 1.1821733202392815, + WestTexNewMexico__yhat_upper: 1.5011656305912942, + WestTexNewMexico: 1.315, + }, + { + __timestamp: 1447632000000, + Boston__yhat: 1.2921088188147662, + Boston__yhat_lower: 1.1728345442847379, + Boston__yhat_upper: 1.4033407585022522, + Boston: 1.17, + California__yhat: 1.3931387239731783, + California__yhat_lower: 1.2432214745880616, + California__yhat_upper: 1.5498822030297323, + California: 1.26, + WestTexNewMexico__yhat: 1.276766317307663, + WestTexNewMexico__yhat_lower: 1.0999844956570386, + WestTexNewMexico__yhat_upper: 1.446687228788756, + WestTexNewMexico: 1.375, + }, + { + __timestamp: 1448236800000, + Boston__yhat: 1.2844900175902454, + Boston__yhat_lower: 1.1751725419028316, + Boston__yhat_upper: 1.4071918419152338, + Boston: 1.235, + California__yhat: 1.3280733170736323, + California__yhat_lower: 1.168686173676362, + California__yhat_upper: 1.4828349526176714, + California: 1.33, + WestTexNewMexico__yhat: 1.2150153206911025, + WestTexNewMexico__yhat_lower: 1.0575514264315589, + WestTexNewMexico__yhat_upper: 1.3738174939464802, + WestTexNewMexico: 1.445, + }, + { + __timestamp: 1448841600000, + Boston__yhat: 1.2805251906155837, + Boston__yhat_lower: 1.1707757707707065, + Boston__yhat_upper: 1.3999312395395147, + Boston: 1.155, + California__yhat: 1.2392981370779044, + California__yhat_lower: 1.0733806154601595, + California__yhat_upper: 1.4014509402239486, + California: 1.13, + WestTexNewMexico__yhat: 1.1770436607980383, + WestTexNewMexico__yhat_lower: 0.993583553273554, + WestTexNewMexico__yhat_upper: 1.333422820891247, + WestTexNewMexico: 0.74, + }, + { + __timestamp: 1449446400000, + Boston__yhat: 1.279267142574869, + Boston__yhat_lower: 1.1585705827510129, + Boston__yhat_upper: 1.3983536869495787, + Boston: 1.28, + California__yhat: 1.1539951545645342, + California__yhat_lower: 0.9889501465743559, + California__yhat_upper: 1.3053289212843744, + California: 1.13, + WestTexNewMexico__yhat: 1.162380614252356, + WestTexNewMexico__yhat_lower: 0.9965272411245537, + WestTexNewMexico__yhat_upper: 1.3253180367221955, + WestTexNewMexico: 1.29, + }, +]; diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Sunburst/Stories.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Sunburst/Stories.tsx new file mode 100644 index 0000000000000..7742f1ecfe537 --- /dev/null +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Sunburst/Stories.tsx @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { SuperChart, getChartTransformPropsRegistry } from '@superset-ui/core'; +import { boolean, withKnobs } from '@storybook/addon-knobs'; +import { + EchartsSunburstChartPlugin, + SunburstTransformProps, +} from '@superset-ui/plugin-chart-echarts'; +import { withResizableChartDemo } from '../../../../shared/components/ResizableChartDemo'; +import data from './data'; + +new EchartsSunburstChartPlugin() + .configure({ key: 'echarts-sunburst' }) + .register(); + +getChartTransformPropsRegistry().registerValue( + 'echarts-sunburst', + SunburstTransformProps, +); + +export default { + title: 'Chart Plugins/plugin-chart-echarts/Sunburst', + decorators: [withKnobs, withResizableChartDemo], +}; + +export const Sunburst = ({ width, height }) => ( + <SuperChart + chartType="echarts-sunburst" + width={width} + height={height} + queriesData={[{ data }]} + formData={{ + columns: ['genre', 'platform'], + metric: 'count', + showLabels: boolean('Show labels', true), + showTotal: boolean('Show total', true), + }} + /> +); diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Sunburst/data.ts b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Sunburst/data.ts new file mode 100644 index 0000000000000..35675465dfddb --- /dev/null +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Sunburst/data.ts @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +export default [ + { genre: 'Adventure', platform: 'Wii', count: 84 }, + { genre: 'Adventure', platform: 'N64', count: 14 }, + { genre: 'Adventure', platform: 'XOne', count: 12 }, + { genre: 'Adventure', platform: 'PS4', count: 19 }, + { genre: 'Strategy', platform: 'Wii', count: 25 }, + { genre: 'Strategy', platform: 'PS4', count: 15 }, + { genre: 'Strategy', platform: 'N64', count: 29 }, + { genre: 'Strategy', platform: 'XOne', count: 23 }, + { genre: 'Simulation', platform: 'PS4', count: 15 }, + { genre: 'Simulation', platform: 'XOne', count: 36 }, + { genre: 'Simulation', platform: 'N64', count: 20 }, + { genre: 'Simulation', platform: 'Wii', count: 50 }, +]; diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Timeseries/Stories.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Timeseries/Stories.tsx index b44ba252ea5d4..342db6f5bad41 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Timeseries/Stories.tsx +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Timeseries/Stories.tsx @@ -26,6 +26,8 @@ import { } from '@superset-ui/plugin-chart-echarts'; import data from './data'; import negativeNumData from './negativeNumData'; +import confbandData from './confbandData'; +import stackWithNullsData from './stackWithNulls'; import { withResizableChartDemo } from '../../../../shared/components/ResizableChartDemo'; new EchartsTimeseriesChartPlugin() @@ -66,26 +68,26 @@ export const Timeseries = ({ width, height }) => { { data: queryData, colnames: ['__timestamp'], coltypes: [2] }, ]} formData={{ - contributionMode: undefined, forecastEnabled, - colorScheme: 'supersetColors', + color_scheme: 'supersetColors', seriesType: select( 'Line type', ['line', 'scatter', 'smooth', 'bar', 'start', 'middle', 'end'], 'line', ), logAxis: boolean('Log axis', false), - yAxisFormat: 'SMART_NUMBER', + y_axis_format: 'SMART_NUMBER', stack: boolean('Stack', false), - showValue: boolean('Show Values', false), - onlyTotal: boolean('Only Total', false), - percentageThreshold: number('Percentage Threshold', 0), + show_value: boolean('Show Values', false), + only_total: boolean('Only Total', false), + percentage_threshold: number('Percentage Threshold', 0), area: boolean('Area chart', false), markerEnabled: boolean('Enable markers', false), markerSize: number('Marker Size', 6), minorSplitLine: boolean('Minor splitline', false), opacity: number('Opacity', 0.2), zoomable: boolean('Zoomable', false), + x_axis: '__timestamp', }} /> ); @@ -100,23 +102,71 @@ export const WithNegativeNumbers = ({ width, height }) => ( { data: negativeNumData, colnames: ['__timestamp'], coltypes: [2] }, ]} formData={{ - contributionMode: undefined, - colorScheme: 'supersetColors', + color_scheme: 'supersetColors', seriesType: select( 'Line type', ['line', 'scatter', 'smooth', 'bar', 'start', 'middle', 'end'], 'line', ), - yAxisFormat: '$,.2f', + y_axis_format: '$,.2f', stack: boolean('Stack', true), - showValue: true, - showLegend: true, - onlyTotal: boolean('Only Total', true), + show_value: true, + show_legend: true, + only_total: boolean('Only Total', true), orientation: select( 'Orientation', ['vertical', 'horizontal'], 'vertical', ), + x_axis: '__timestamp', + }} + /> +); + +export const ConfidenceBand = ({ width, height }) => ( + <SuperChart + chartType="echarts-timeseries" + width={width} + height={height} + queriesData={[ + { + data: confbandData, + colnames: [ + 'ds', + 'SUM(num)', + 'SUM(num)__yhat_lower', + 'SUM(num)__yhat_upper', + ], + coltypes: [2, 0, 0, 0], + }, + ]} + formData={{ + color_scheme: 'supersetColors', + series_type: 'line', + x_axis_time_format: 'smart_date', + x_axis: 'ds', + }} + /> +); + +export const StackWithNulls = ({ width, height }) => ( + <SuperChart + chartType="echarts-timeseries" + width={width} + height={height} + queriesData={[ + { + data: stackWithNullsData, + colnames: ['ds', '1', '2'], + coltypes: [2, 0, 0], + }, + ]} + formData={{ + color_scheme: 'supersetColors', + series_type: 'bar', + stack: true, + x_axis_time_format: 'smart_date', + x_axis: 'ds', }} /> ); diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Timeseries/confbandData.ts b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Timeseries/confbandData.ts new file mode 100644 index 0000000000000..46529e59b1eee --- /dev/null +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Timeseries/confbandData.ts @@ -0,0 +1,329 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export default [ + { + ds: -157766400000, + 'SUM(num)': 173161, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: -126230400000, + 'SUM(num)': 173777, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: -94694400000, + 'SUM(num)': 178221, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: -63158400000, + 'SUM(num)': 176779, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: -31536000000, + 'SUM(num)': 184113, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 0, + 'SUM(num)': 188343, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 31536000000, + 'SUM(num)': 178441, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 63072000000, + 'SUM(num)': 169507, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 94694400000, + 'SUM(num)': 156783, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 126230400000, + 'SUM(num)': 157434, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 157766400000, + 'SUM(num)': 153606, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 189302400000, + 'SUM(num)': 150937, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 220924800000, + 'SUM(num)': 154361, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 252460800000, + 'SUM(num)': 154515, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 283996800000, + 'SUM(num)': 159885, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 315532800000, + 'SUM(num)': 159087, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 347155200000, + 'SUM(num)': 159061, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 378691200000, + 'SUM(num)': 167242, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 410227200000, + 'SUM(num)': 165944, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 441763200000, + 'SUM(num)': 165662, + 'SUM(num)__yhat': null, + 'SUM(num)__yhat_lower': null, + 'SUM(num)__yhat_upper': null, + }, + { + ds: 473385600000, + 'SUM(num)': 162578, + 'SUM(num)__yhat': 162578, + 'SUM(num)__yhat_lower': 162578, + 'SUM(num)__yhat_upper': 162578, + }, + { + ds: 504921600000, + 'SUM(num)': null, + 'SUM(num)__yhat': 157613, + 'SUM(num)__yhat_lower': 147613, + 'SUM(num)__yhat_upper': 167613, + }, + { + ds: 536457600000, + 'SUM(num)': null, + 'SUM(num)__yhat': 154580, + 'SUM(num)__yhat_lower': 134580, + 'SUM(num)__yhat_upper': 174580, + }, + { + ds: 567993600000, + 'SUM(num)': null, + 'SUM(num)__yhat': 152134, + 'SUM(num)__yhat_lower': 122134, + 'SUM(num)__yhat_upper': 182134, + }, + { + ds: 599616000000, + 'SUM(num)': null, + 'SUM(num)__yhat': 153577, + 'SUM(num)__yhat_lower': 113577, + 'SUM(num)__yhat_upper': 193577, + }, + { + ds: 631152000000, + 'SUM(num)': null, + 'SUM(num)__yhat': 151121, + 'SUM(num)__yhat_lower': 101121, + 'SUM(num)__yhat_upper': 201121, + }, + { + ds: 662688000000, + 'SUM(num)': null, + 'SUM(num)__yhat': 138102, + 'SUM(num)__yhat_lower': 78102, + 'SUM(num)__yhat_upper': 208102, + }, + { + ds: 694224000000, + 'SUM(num)': null, + 'SUM(num)__yhat': 125030, + 'SUM(num)__yhat_lower': 45030, + 'SUM(num)__yhat_upper': 205030, + }, + { + ds: 725846400000, + 'SUM(num)': null, + 'SUM(num)__yhat': 114647, + 'SUM(num)__yhat_lower': 24647, + 'SUM(num)__yhat_upper': 204647, + }, + { + ds: 757382400000, + 'SUM(num)': null, + 'SUM(num)__yhat': 103968, + 'SUM(num)__yhat_lower': 13968, + 'SUM(num)__yhat_upper': 193968, + }, + { + ds: 788918400000, + 'SUM(num)': null, + 'SUM(num)__yhat': 97006, + 'SUM(num)__yhat_lower': 7006, + 'SUM(num)__yhat_upper': 187006, + }, + { + ds: 820454400000, + 'SUM(num)': null, + 'SUM(num)__yhat': 92213, + 'SUM(num)__yhat_lower': 2213, + 'SUM(num)__yhat_upper': 182213, + }, + { + ds: 852076800000, + 'SUM(num)': null, + 'SUM(num)__yhat': 88462, + 'SUM(num)__yhat_lower': -1538, + 'SUM(num)__yhat_upper': 178462, + }, + { + ds: 883612800000, + 'SUM(num)': null, + 'SUM(num)__yhat': 84424, + 'SUM(num)__yhat_lower': -5576, + 'SUM(num)__yhat_upper': 174424, + }, + { + ds: 915148800000, + 'SUM(num)': null, + 'SUM(num)__yhat': 79787, + 'SUM(num)__yhat_lower': -10213, + 'SUM(num)__yhat_upper': 169787, + }, + { + ds: 946684800000, + 'SUM(num)': null, + 'SUM(num)__yhat': 76610, + 'SUM(num)__yhat_lower': -13390, + 'SUM(num)__yhat_upper': 166610, + }, + { + ds: 978307200000, + 'SUM(num)': null, + 'SUM(num)__yhat': 72073, + 'SUM(num)__yhat_lower': -17927, + 'SUM(num)__yhat_upper': 162073, + }, + { + ds: 1009843200000, + 'SUM(num)': null, + 'SUM(num)__yhat': 68487, + 'SUM(num)__yhat_lower': -21513, + 'SUM(num)__yhat_upper': 158487, + }, + { + ds: 1041379200000, + 'SUM(num)': null, + 'SUM(num)__yhat': 66381, + 'SUM(num)__yhat_lower': -23619, + 'SUM(num)__yhat_upper': 156381, + }, + { + ds: 1072915200000, + 'SUM(num)': null, + 'SUM(num)__yhat': 63472, + 'SUM(num)__yhat_lower': -26528, + 'SUM(num)__yhat_upper': 153472, + }, + { + ds: 1104537600000, + 'SUM(num)': null, + 'SUM(num)__yhat': 60885, + 'SUM(num)__yhat_lower': -29115, + 'SUM(num)__yhat_upper': 150885, + }, + { + ds: 1136073600000, + 'SUM(num)': null, + 'SUM(num)__yhat': 59682, + 'SUM(num)__yhat_lower': -30318, + 'SUM(num)__yhat_upper': 149682, + }, + { + ds: 1167609600000, + 'SUM(num)': null, + 'SUM(num)__yhat': 59191, + 'SUM(num)__yhat_lower': -30809, + 'SUM(num)__yhat_upper': 149191, + }, + { + ds: 1199145600000, + 'SUM(num)': null, + 'SUM(num)__yhat': 54091, + 'SUM(num)__yhat_lower': -35909, + 'SUM(num)__yhat_upper': 144091, + }, +]; diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Timeseries/stackWithNulls.ts b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Timeseries/stackWithNulls.ts new file mode 100644 index 0000000000000..8416fa09def21 --- /dev/null +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-echarts/Timeseries/stackWithNulls.ts @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export default [ + { + ds: 1293840000000, + '1': 2, + '2': 1, + }, + { + ds: 1325376000000, + '1': null, + '2': null, + }, + { + ds: 1356998400000, + '1': null, + '2': 1, + }, +]; diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-pivot-table/PivotTableStories.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-pivot-table/PivotTableStories.tsx new file mode 100644 index 0000000000000..54903c013aa25 --- /dev/null +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-pivot-table/PivotTableStories.tsx @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { withKnobs } from '@storybook/addon-knobs'; +import { SuperChart } from '@superset-ui/core'; +import { PivotTableChartPlugin } from '@superset-ui/plugin-chart-pivot-table'; +import { basicFormData, basicData } from './testData'; +import { withResizableChartDemo } from '../../../shared/components/ResizableChartDemo'; + +export default { + title: 'Chart Plugins/plugin-chart-pivot-table', + decorators: [withKnobs, withResizableChartDemo], +}; + +new PivotTableChartPlugin().configure({ key: 'pivot_table_v2' }).register(); + +export const basic = ({ width, height }) => ( + <SuperChart + chartType="pivot_table_v2" + datasource={{ + columnFormats: {}, + }} + width={width} + height={height} + queriesData={[basicData]} + formData={basicFormData} + /> +); +basic.story = { + parameters: { + initialSize: { + width: 680, + height: 420, + }, + }, +}; + +export const MaximumAggregation = ({ width, height }) => ( + <SuperChart + chartType="pivot_table_v2" + datasource={{ + columnFormats: {}, + }} + width={width} + height={height} + queriesData={[basicData]} + formData={{ ...basicFormData, aggregateFunction: 'Maximum' }} + /> +); +basic.story = { + parameters: { + initialSize: { + width: 680, + height: 420, + }, + }, +}; diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-pivot-table/testData.ts b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-pivot-table/testData.ts new file mode 100644 index 0000000000000..0e6457d0c122e --- /dev/null +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-pivot-table/testData.ts @@ -0,0 +1,126 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +export const basicFormData = { + datasource: '1__table', + viz_type: 'pivot_table_v2', + granularity_sqla: 'ts', + groupbyColumns: ['location'], + groupbyRows: ['program_language'], + metrics: [ + { + expressionType: 'SIMPLE', + column: { + id: 1, + column_name: 'count', + description: null, + expression: null, + groupby: true, + is_dttm: false, + python_date_format: null, + type: 'BIGINT', + type_generic: 0, + }, + aggregate: 'SUM', + sqlExpression: null, + isNew: false, + hasCustomLabel: true, + label: 'Count', + }, + { + expressionType: 'SIMPLE', + column: { + id: 2, + column_name: 'ts', + description: null, + expression: "DATE_PARSE(ds || ' ' || hr, '%Y-%m-%d %H')", + groupby: true, + is_dttm: true, + type: 'TIMESTAMP', + type_generic: 2, + python_date_format: null, + }, + aggregate: 'MAX', + sqlExpression: null, + isNew: false, + hasCustomLabel: true, + label: 'Most Recent Data', + }, + ], + metricsLayout: 'COLUMNS', + order_desc: true, + aggregateFunction: 'Sum', + valueFormat: '~g', + date_format: 'smart_date', + rowOrder: 'key_a_to_z', + colOrder: 'key_a_to_z', +}; + +export const basicData = { + cache_key: 'f2cd2a37b6977e3619ce6c07d0027972', + cached_dttm: '2022-07-27T17:42:39', + cache_timeout: 129600, + applied_template_filters: [], + annotation_data: {}, + error: null, + is_cached: true, + query: 'SELECT \nFROM\nWHERE', + status: 'success', + stacktrace: null, + rowcount: 5, + from_dttm: 1658426268000, + to_dttm: 1659031068000, + colnames: ['location', 'program_language', 'Count', 'Most Recent Data'], + indexnames: [0, 1, 2, 3, 4], + coltypes: [1, 1, 0, 1], + data: [ + { + location: 'AMEA', + program_language: 'Javscript', + Count: 134, + 'Most Recent Data': '2022-07-25 13:00:00.000', + }, + { + location: 'ASIA', + program_language: 'python', + Count: 19, + 'Most Recent Data': '2022-07-25 16:00:00.000', + }, + { + location: 'ASIA', + program_language: 'Java', + Count: 7, + 'Most Recent Data': '2022-07-25 15:00:00.000', + }, + { + location: 'ASIA', + program_language: 'C++', + Count: 1, + 'Most Recent Data': '2022-07-25 02:00:00.000', + }, + { + location: 'ASIA', + program_language: 'PHP', + Count: 1, + 'Most Recent Data': '2022-07-24 00:00:00.000', + }, + ], + result_format: 'json', + applied_filters: [], + rejected_filters: [], +}; diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-table/birthNames.json b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-table/birthNames.json index cecb37e02627e..c35d3a80665fc 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-table/birthNames.json +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/plugin-chart-table/birthNames.json @@ -13,7 +13,6 @@ "id": 1, "name": "examples", "backend": "postgresql", - "allow_multi_schema_metadata_fetch": false, "allows_subquery": true, "allows_cost_estimate": null, "allows_virtual_table_explore": true, diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/SuperChartStories.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/SuperChartStories.tsx index 490f498ec1370..d2eb5dae4445c 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/SuperChartStories.tsx +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/SuperChartStories.tsx @@ -110,7 +110,7 @@ export const fixedHeight100Width = () => { }; fixedHeight100Width.story = { name: 'fixed height, 100% width' }; -export const withErrorBoundar = () => { +export const withErrorBoundary = () => { const width = text('Vis width', '500'); const height = text('Vis height', '300'); diff --git a/superset-frontend/packages/superset-ui-switchboard/package.json b/superset-frontend/packages/superset-ui-switchboard/package.json index f7e6c69a1b508..1e49d7eb9cde0 100644 --- a/superset-frontend/packages/superset-ui-switchboard/package.json +++ b/superset-frontend/packages/superset-ui-switchboard/package.json @@ -1,6 +1,6 @@ { "name": "@superset-ui/switchboard", - "version": "0.18.26-0", + "version": "0.18.26-1", "description": "Switchboard is a library to make it easier to communicate across browser windows using the MessageChannel API", "sideEffects": false, "main": "lib/index.js", diff --git a/superset-frontend/packages/superset-ui-switchboard/src/index.ts b/superset-frontend/packages/superset-ui-switchboard/src/index.ts index adbd7450fc035..8e6bef5ff7e4f 100644 --- a/superset-frontend/packages/superset-ui-switchboard/src/index.ts +++ b/superset-frontend/packages/superset-ui-switchboard/src/index.ts @@ -17,4 +17,7 @@ * under the License. */ +import Switchboard from './switchboard'; + export * from './switchboard'; +export default Switchboard; diff --git a/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts b/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts index fb77ab90f8a42..9e36f541e1cd9 100644 --- a/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts +++ b/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Switchboard } from './switchboard'; +import SingletonSwitchboard, { Switchboard } from './switchboard'; type EventHandler = (event: MessageEvent) => void; @@ -105,13 +105,16 @@ describe('comms', () => { let originalConsoleError: any = null; beforeAll(() => { - global.MessageChannel = FakeMessageChannel; // yolo + Object.defineProperty(global, 'MessageChannel', { + value: FakeMessageChannel, + }); originalConsoleDebug = console.debug; originalConsoleError = console.error; }); beforeEach(() => { console.debug = jest.fn(); // silencio bruno + console.error = jest.fn(); }); afterEach(() => { @@ -126,6 +129,30 @@ describe('comms', () => { expect(sb).toHaveProperty('debugMode'); }); + it('singleton', async () => { + SingletonSwitchboard.start(); + expect(console.error).toHaveBeenCalledWith( + '[]', + 'Switchboard not initialised', + ); + SingletonSwitchboard.emit('someEvent', 42); + expect(console.error).toHaveBeenCalledWith( + '[]', + 'Switchboard not initialised', + ); + await expect(SingletonSwitchboard.get('failing')).rejects.toThrow( + 'Switchboard not initialised', + ); + SingletonSwitchboard.init({ port: new MessageChannel().port1 }); + expect(SingletonSwitchboard).toHaveProperty('name'); + expect(SingletonSwitchboard).toHaveProperty('debugMode'); + SingletonSwitchboard.init({ port: new MessageChannel().port1 }); + expect(console.error).toHaveBeenCalledWith( + '[switchboard]', + 'already initialized', + ); + }); + describe('emit', () => { it('triggers the method', async () => { const channel = new MessageChannel(); diff --git a/superset-frontend/packages/superset-ui-switchboard/src/switchboard.ts b/superset-frontend/packages/superset-ui-switchboard/src/switchboard.ts index f12c9b6482c3d..ab19d462f1b23 100644 --- a/superset-frontend/packages/superset-ui-switchboard/src/switchboard.ts +++ b/superset-frontend/packages/superset-ui-switchboard/src/switchboard.ts @@ -90,7 +90,7 @@ function isError(message: Message): message is ErrorMessage { export class Switchboard { port: MessagePort; - name: string; + name = ''; methods: Record<string, Method<any, unknown>> = {}; @@ -99,7 +99,23 @@ export class Switchboard { debugMode: boolean; - constructor({ port, name = 'switchboard', debug = false }: Params) { + private isInitialised: boolean; + + constructor(params?: Params) { + if (!params) { + return; + } + this.init(params); + } + + init(params: Params) { + if (this.isInitialised) { + this.logError('already initialized'); + return; + } + + const { port, name = 'switchboard', debug = false } = params; + this.port = port; this.name = name; this.debugMode = debug; @@ -122,6 +138,8 @@ export class Switchboard { } } }); + + this.isInitialised = true; } private async getMethodResult({ @@ -173,11 +191,15 @@ export class Switchboard { * Instead of an arguments list, arguments are supplied as a map. * * @param method the name of the method to call - * @param args arguments that will be supplied. Must be serializable, no functions or other nonense. + * @param args arguments that will be supplied. Must be serializable, no functions or other nonsense. * @returns whatever is returned from the method */ get<T = unknown>(method: string, args: unknown = undefined): Promise<T> { return new Promise((resolve, reject) => { + if (!this.isInitialised) { + reject(new Error('Switchboard not initialised')); + return; + } // In order to "call a method" on the other side of the port, // we will send a message with a unique id const messageId = this.getNewMessageId(); @@ -215,6 +237,10 @@ export class Switchboard { * @param args */ emit(method: string, args: unknown = undefined) { + if (!this.isInitialised) { + this.logError('Switchboard not initialised'); + return; + } const message: EmitMessage = { switchboardAction: Actions.EMIT, method, @@ -224,6 +250,10 @@ export class Switchboard { } start() { + if (!this.isInitialised) { + this.logError('Switchboard not initialised'); + return; + } this.port.start(); } @@ -242,3 +272,5 @@ export class Switchboard { return `m_${this.name}_${this.incrementor++}`; } } + +export default new Switchboard(); diff --git a/superset-frontend/plugins/legacy-plugin-chart-calendar/src/Calendar.js b/superset-frontend/plugins/legacy-plugin-chart-calendar/src/Calendar.js index 0417ea3e8b5af..d97557a77b506 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-calendar/src/Calendar.js +++ b/superset-frontend/plugins/legacy-plugin-chart-calendar/src/Calendar.js @@ -19,7 +19,7 @@ import PropTypes from 'prop-types'; import { extent as d3Extent, range as d3Range } from 'd3-array'; import { select as d3Select } from 'd3-selection'; -import { getSequentialSchemeRegistry } from '@superset-ui/core'; +import { getSequentialSchemeRegistry, t } from '@superset-ui/core'; import CalHeatMap from './vendor/cal-heatmap'; const propTypes = { @@ -85,10 +85,12 @@ function Calendar(element, props) { const metricsData = data.data; + const METRIC_TEXT = t('Metric'); + Object.keys(metricsData).forEach(metric => { const calContainer = div.append('div'); if (showMetricName) { - calContainer.text(`Metric: ${verboseMap[metric] || metric}`); + calContainer.text(`${METRIC_TEXT}: ${verboseMap[metric] || metric}`); } const timestamps = metricsData[metric]; const extents = d3Extent(Object.keys(timestamps), key => timestamps[key]); diff --git a/superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts index 2787687b06159..9071a278eebae 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts @@ -21,7 +21,7 @@ import { ControlPanelConfig, D3_FORMAT_DOCS, D3_TIME_FORMAT_OPTIONS, - formatSelectOptions, + getStandardizedControls, sections, } from '@superset-ui/chart-controls'; @@ -39,13 +39,13 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Domain'), default: 'month', - choices: formatSelectOptions([ - 'hour', - 'day', - 'week', - 'month', - 'year', - ]), + choices: [ + ['hour', t('hour')], + ['day', t('day')], + ['week', t('week')], + ['month', t('month')], + ['year', t('year')], + ], description: t('The time unit used for the grouping of blocks'), }, }, @@ -55,13 +55,13 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Subdomain'), default: 'day', - choices: formatSelectOptions([ - 'min', - 'hour', - 'day', - 'week', - 'month', - ]), + choices: [ + ['min', t('min')], + ['hour', t('hour')], + ['day', t('day')], + ['week', t('week')], + ['month', t('month')], + ], description: t( 'The time unit for each block. Should be a smaller unit than ' + 'domain_granularity. Should be larger or equal to Time Grain', @@ -191,6 +191,10 @@ const config: ControlPanelConfig = { label: t('Number Format'), }, }, + formDataOverrides: formData => ({ + ...formData, + metrics: getStandardizedControls().popAllMetrics(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-calendar/src/images/example.jpg b/superset-frontend/plugins/legacy-plugin-chart-calendar/src/images/example.jpg new file mode 100644 index 0000000000000..0bbf24ae6ffa8 Binary files /dev/null and b/superset-frontend/plugins/legacy-plugin-chart-calendar/src/images/example.jpg differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js b/superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js index 5c0a9425ef126..926d98421d31a 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js +++ b/superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js @@ -18,6 +18,7 @@ */ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from './transformProps'; +import example from './images/example.jpg'; import controlPanel from './controlPanel'; import thumbnail from './images/thumbnail.png'; @@ -27,6 +28,7 @@ const metadata = new ChartMetadata({ description: t( "Visualizes how a metric has changed over a time using a color scale and a calendar view. Gray values are used to indicate missing values and the linear color scheme is used to encode the magnitude of each day's value.", ), + exampleGallery: [{ url: example }], name: t('Calendar Heatmap'), tags: [ t('Business'), diff --git a/superset-frontend/plugins/legacy-plugin-chart-calendar/src/vendor/cal-heatmap.js b/superset-frontend/plugins/legacy-plugin-chart-calendar/src/vendor/cal-heatmap.js index 3320693f5cc63..760bf0ce2b0c4 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-calendar/src/vendor/cal-heatmap.js +++ b/superset-frontend/plugins/legacy-plugin-chart-calendar/src/vendor/cal-heatmap.js @@ -9,7 +9,7 @@ /* eslint-disable */ import d3tip from 'd3-tip'; -import { getContrastingColor } from '@superset-ui/core'; +import { getContrastingColor, t } from '@superset-ui/core'; var d3 = typeof require === 'function' ? require('d3') : window.d3; @@ -256,9 +256,9 @@ var CalHeatMap = function () { // Formatting of the title displayed when hovering a legend cell legendTitleFormat: { - lower: 'less than {min} {name}', - inner: 'between {down} and {up} {name}', - upper: 'more than {max} {name}', + lower: t('less than {min} {name}'), + inner: t('between {down} and {up} {name}'), + upper: t('more than {max} {name}'), }, // Animation duration, in ms diff --git a/superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts index c2559a7b0d57f..5a58b567a7a32 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts @@ -16,8 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import { t, validateNonEmpty } from '@superset-ui/core'; -import { ControlPanelConfig, sections } from '@superset-ui/chart-controls'; +import { ensureIsArray, t, validateNonEmpty } from '@superset-ui/core'; +import { + ControlPanelConfig, + getStandardizedControls, + sections, +} from '@superset-ui/chart-controls'; const config: ControlPanelConfig = { controlPanelSections: [ @@ -69,6 +73,16 @@ const config: ControlPanelConfig = { description: t('Choose a target'), }, }, + formDataOverrides: formData => { + const groupby = getStandardizedControls() + .popAllColumns() + .filter(col => !ensureIsArray(formData.columns).includes(col)); + return { + ...formData, + groupby, + metric: getStandardizedControls().shiftMetric(), + }; + }, }; export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb b/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb index e91d20ed6a3c7..4908a5e6d4571 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb @@ -34,7 +34,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 35, "metadata": {}, "outputs": [ { @@ -93,7 +93,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 36, "metadata": {}, "outputs": [], "source": [ @@ -109,7 +109,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 37, "metadata": {}, "outputs": [ { @@ -118,12 +118,12 @@ "Index(['featurecla', 'scalerank', 'adm1_code', 'diss_me', 'iso_3166_2',\n", " 'wikipedia', 'iso_a2', 'adm0_sr', 'name', 'name_alt',\n", " ...\n", - " 'FCLASS_TR', 'FCLASS_ID', 'FCLASS_PL', 'FCLASS_GR', 'FCLASS_IT',\n", - " 'FCLASS_NL', 'FCLASS_SE', 'FCLASS_BD', 'FCLASS_UA', 'geometry'],\n", - " dtype='object', length=121)" + " 'FCLASS_ID', 'FCLASS_PL', 'FCLASS_GR', 'FCLASS_IT', 'FCLASS_NL',\n", + " 'FCLASS_SE', 'FCLASS_BD', 'FCLASS_UA', 'FCLASS_TLC', 'geometry'],\n", + " dtype='object', length=122)" ] }, - "execution_count": 3, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } @@ -134,21 +134,21 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['featurecla', 'scalerank', 'labelrank', 'sovereignt', 'sov_a3',\n", - " 'adm0_dif', 'level', 'type', 'admin', 'adm0_a3',\n", + " 'adm0_dif', 'level', 'type', 'tlc', 'admin',\n", " ...\n", " 'fclass_tr', 'fclass_id', 'fclass_pl', 'fclass_gr', 'fclass_it',\n", " 'fclass_nl', 'fclass_se', 'fclass_bd', 'fclass_ua', 'geometry'],\n", - " dtype='object', length=162)" + " dtype='object', length=169)" ] }, - "execution_count": 4, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } @@ -160,7 +160,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 39, "metadata": {}, "outputs": [ { @@ -195,7 +195,6 @@ " <th>name</th>\n", " <th>name_alt</th>\n", " <th>...</th>\n", - " <th>FCLASS_TR</th>\n", " <th>FCLASS_ID</th>\n", " <th>FCLASS_PL</th>\n", " <th>FCLASS_GR</th>\n", @@ -204,6 +203,7 @@ " <th>FCLASS_SE</th>\n", " <th>FCLASS_BD</th>\n", " <th>FCLASS_UA</th>\n", + " <th>FCLASS_TLC</th>\n", " <th>geometry</th>\n", " </tr>\n", " <tr>\n", @@ -450,7 +450,7 @@ " </tr>\n", " </tbody>\n", "</table>\n", - "<p>9 rows × 120 columns</p>\n", + "<p>9 rows × 121 columns</p>\n", "</div>" ], "text/plain": [ @@ -478,7 +478,7 @@ "South Africa 9 0 9 9 9 \n", "United States of America 51 51 51 51 51 \n", "\n", - " name_alt ... FCLASS_TR FCLASS_ID FCLASS_PL \\\n", + " name_alt ... FCLASS_ID FCLASS_PL FCLASS_GR \\\n", "admin ... \n", "Australia 0 ... 0 0 0 \n", "Brazil 13 ... 0 0 0 \n", @@ -490,7 +490,7 @@ "South Africa 9 ... 0 0 0 \n", "United States of America 51 ... 0 0 0 \n", "\n", - " FCLASS_GR FCLASS_IT FCLASS_NL FCLASS_SE \\\n", + " FCLASS_IT FCLASS_NL FCLASS_SE FCLASS_BD \\\n", "admin \n", "Australia 0 0 0 0 \n", "Brazil 0 0 0 0 \n", @@ -502,22 +502,22 @@ "South Africa 0 0 0 0 \n", "United States of America 0 0 0 0 \n", "\n", - " FCLASS_BD FCLASS_UA geometry \n", - "admin \n", - "Australia 0 0 9 \n", - "Brazil 0 0 27 \n", - "Canada 0 0 13 \n", - "China 0 0 31 \n", - "India 0 0 36 \n", - "Indonesia 0 0 33 \n", - "Russia 0 0 85 \n", - "South Africa 0 0 9 \n", - "United States of America 0 0 51 \n", + " FCLASS_UA FCLASS_TLC geometry \n", + "admin \n", + "Australia 0 0 9 \n", + "Brazil 0 0 27 \n", + "Canada 0 0 13 \n", + "China 0 0 31 \n", + "India 0 0 36 \n", + "Indonesia 0 0 33 \n", + "Russia 0 0 85 \n", + "South Africa 0 0 9 \n", + "United States of America 0 0 51 \n", "\n", - "[9 rows x 120 columns]" + "[9 rows x 121 columns]" ] }, - "execution_count": 5, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -528,7 +528,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 40, "metadata": {}, "outputs": [ { @@ -537,20 +537,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 6, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA04AAAI/CAYAAABAqYlRAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAACnzklEQVR4nOzdd3gc1bkG8Hdme99V79VFLnKV5YINptcAoV4IgZBACCE9uemk3PRCElIhAZIQCL33AMHGGFwk9yI39V52V1ptL3P/WFlYVpe2Su/vSR6s3dmZb2XLnnfPOd8RJEkCERERERERjU6MdwFERERERESJjsGJiIiIiIhoHAxORERERERE42BwIiIiIiIiGgeDExERERER0TgYnIiIiIiIiMYhj+XF0tLSpKKiolhekoiIiIiIaEKqq6u7JUlKH+m5mAanoqIiVFVVxfKSREREREREEyIIQsNoz3GqHhERERER0TgYnIiIiIiIiMbB4ERERERERDQOBiciIiIiIqJxMDgRERERERGNg8GJiIiIiIhoHAxORERERERE42BwIiIiIiIiGgeDExERERER0TgYnIiIiIiIiMbB4ERERERERDQOBiciIiIiIqJxMDgRERERERGNg8GJiIiIiIhoHAxORERERERE42BwIiIiIiIiGgeDExERERER0TgYnIiIiIiIiMbB4ERERERERDQOBiciIiIiIqJxMDgRERERERGNg8GJiIiIiIhoHAxORFMUCknwBULxLoOIiIiIYoDBiWiSet1+/Omd4/jO8/sRCDE4EREREc0G8ngXQJRMth7vxlee3IOOPi8A4O3DnVhRYMGKQjNWFFiwONcEtUIW5yqJiIiIKNIYnIgm6MmdTfj2c/sRCEmDj3U6vHj9YDteP9g++FhlUQqe/Mza8PN9HkgA0vQqyEQh1iUTERERUYQwOBGNY39zL+558wg2Heka8zhBANYUp+KbF5cBADYf7cKnH66CNxBCplGFz58zFzetKYxFyUREREQUYQxONKuEQhJ63X5YdMoxj/MFQvhvTQce29GEzUfHDkwAsDTfjAdvqUCaXoVOhwffeHofnqhqGny+o8+LAy29w14XCIbQYHWhp98HAKjr7sfhNgfyLBqUZRlRmKpFr9uPdIMKmUb1JN8tEREREUWKIEnS+EdFSEVFhVRVVRWz6xGdVN/txJNVTXhh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", + "image/png": "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wKo0X5fheBKLyjLXX2pVtROVThM21BfArNcAAGoLLRk7P1E2UdcrHBERERERKaa20IJffWgTvvHXY/iPl04qXQ7NUJ8/onQJowosevT4Zr/k9PyZRnqNCI0oIHTeboN72z1YUGLF8b5hWeqciCcUw7o6F0RBQCIpIZZIIhRLIBBJwBeKwR+Jy3auUCyBTk8InZ4QDFoBlU4T4pI6djckUhsGV0RERERENEqrEfHP1zbBrNfgW88cU7ocmsbicjsOdfuULmOUOxCFQSsiEp9dCKMVzwVXWxqLsabWhQefOjJ6WywpwZLmmWUtAwG0TLFJgVYEHCY9bEYtLAYtDNqRgE0UBCSkkaArHE1iOBofCbrCkwdd5698jMQldHpCeGp/D+5cWyPnp0SUExhcERERERHROPde3oDf7O6c8o08Kc9i0Chdwjgrqhxobp1dM3Wt5lySc9H8QlzWWDImuAIAw5lZWYIAVDhMWFhqxQtH+1MveIbiydk1sNcIgMOsh92ohcWggV6rwXA4juN9wzDrx78VP9XP7zWiiTC4IiIiIiKicTSigHdsrMWX/nhI6VJoCnLsJii3N08PodJlQudQaMaPOX/G1ZJKB3Sa8c3Yz36q5XYjnrrvEvR4w2OCK71WxPs218Og1cCoE/GLHe04pWDwmpBGZqC5zwu61te5AACxxPgZaZ2eEGKJJHRzaG5PlMv4HUFERERERBO6dXXlhAECqcfQDGf/pNOFjdWTElDlNE14bKFFj49smY+3rqses1OgeObfogA0ltlQ7jDhumVlYx579nO976qFePXEAD772wMosuqxvq4Ad2+swZ8+thn3bV0Il0WHHa1uzC+xyvlpysIbiqHQosep/vG9uhJJCV2emYd9RPmCM66IiIiIiGhCTrMely4oxnNH+pQuhSZxfgNzJayuceIXH9yE04NBvP+nb44uLfWGYqPHbF1Ugg31hVhQasXGeYUw6kaWN957eQNCsQRcZj2cJi38kQQSSQl2ow4A8NVbluGvB3sRT0r41xsW4a8He/HOTbW4enEp9rR78IO3r0ah1TCuprdvqEVDiRW/erMDoqCuWWlHe6duLn96MMjdBYkuMKsZVz/4wQ+wfPly2O122O12bNq0CU899dTo/eFwGPfeey8KCwthtVqxfft29Pb2yl40ERERERFlxltWVihdAk2hzGFU7NyC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ERERTcNm1OGu9TX4vw9fhHnFFvzjVQtx4IvbUFOYWo8iooffvgq3rqqc02NNegZXlPsESZIkpYs4n8/ng8PhgNfrhd2e2npfIiIiIiIiuSWSEiRJglbDeQAkn+O9fvz7X47g2cN9Mzp+dY0Tj75rHVwWzvij7DOb7IevtERERERERLOgEQWGViS7BaU2vG1DzYyP37akjKEV5QW+2hIRERERERGpwEXzi1Axg90qjToRt62pykBFRMpjcEVERERERESkAkadBp+8pnHa465bWo5CqyEDFREpj8EVERERERERkUq8ZUUlSu1Th1K1hZYMVUOkPAZXRERERERERCqhEQXcPM0ugyXTBFtEuYTBFREREREREZGK3La6ChpRmPT+JRVT78JGlEsYXBERERERERGpiCAAX755KeYXj18SuLrGicPdPkiSpEBlRJnH4IqIiIiIiIhIRf64rxsP/vkwKpym0dvsRi22r67C9966ClaDDoIw+YwsolyiVboAIiIiIiIiIjrnqsWl+J832mDQavC5GxZjYDiC926uR5HVgG88fRT3Xt6gdIlEGcPgioiIiIiIiEhFllQ4sOMzW8fdfqDTi6WVdpj0GgWqIlIGlwoSERERERERZYE+fxjXLC1XugyijGJwRURERERERKRy/f4wNjcUK10GUcYxuCIiIiIiIiJSqUAkjmRSQqHFAL2Wb+Ep//CqJyIiIiIiIlKhRFKCNxSDIACiyF0EKT8xuCIiIiIiIiJSUDIpAQB++WY7gJFZVv+7ox19/jAqnCYIAkMryl8MroiIiIiIiIgU9KudHUgmJZQ5jJAkCRaDFnesq0a5w6R0aUSKY3BFREREREREpIADnV7EEklcs6wMoijgkgXFnF1FdAGt0gUQERERERER5aOllQ4AgE7DOSVEk+F3BxERERERERERqRKDKyIiIiIiIiIiUiUGV0REREREREREpEoMroiIiIiIiIiISJUYXBERERERERERkSoxuCIiIiIiIiIiIlVicEVERERERERERKrE4IqIiIiIiIiIiFSJwRUREREREREREakSgysiIiIiIiIiIlIlBldERERERERERKRKDK6IiIiIiIiIiEiVGFwREREREREREZEqMbgiIiIiIiIiIiJVYnBFRERERERERESqxOCKiIiIiIiIiIhUicEVERERERERERGpEoMrIiIiIiIiIiJSJQZXRERERERERESkSgyuiIiIiIiIiIhIlRhcERERERERERGRKjG4IiIiIiIiIiIiVWJwRUREREREREREqsTgioiIiIiIiIiIVInBFRERERERERERqRKDKyIiIiIiIiIiUiUGV0REREREREREpEoMroiIiIiIiIiISJUYXBERERERERERkSpplS6AiNRrcDiC9qEQ9BoRi8ptEARB6ZKIiIiIiIgojzC4IqIJ7Tw9hA89sRP9/ggA4Bcf2IgN8woVroqIiIiIiIjyCZcKEtE48UQS//Dz3aOhFQAMBaMKVkRERERERET5iMEVEQEAOj0hdHlCAIBAJAFfODbm/g31nG1FREREREREmcXgiogQTyTxyV/uHf3YYdbhufsvw4pqJwBgXZ0LTrNOoeqIiIiIiIgoX7HHFRHhD/u6cN2ycpQ7jKO3ldiN+O1HLsKRHj+qXCY2ZiciIiIiIqKMY3BFRFhc7kBDiXVcOCUIAhaV2xWqioiIiIiIiPIdlwoSERrLbNCI8s6o6vSEEEskZR2TiIiIiIiI8guDKyKSXbs7iOu++3f8ameH0qUQERERERFRFmNwRUSy+vSv9uG67/4d3lAM3332OBJJSemSiIiIiIiIKEsxuCIiWVmNWvgjcQBAjy+MNncQksTwioiIiIiIiGaPwRURyeqDl82D3Xhu34erv/0SnjrQo2BFRERERERElK0YXBGRrEpsRrz/knm4ZVUlNjcUIZaQ8PirrUhyySARERERERHNknb6Q4iIZudjVy4AACSSEn7W3IZiqwGCvJsWEhERERERUR5gcEVEaaMRBbxjY+242/+8vxu/3tWJxeU2FFoNWFPrQnWBGQ6TToEqiYiIiIiISK0YXBFRxnlDMQgC8PKJARzo9CGaSOKT2xpx7+UNSpdGREREREREKsLgiogy7q71NbhrfQ0AwBuMoXUwgBXVTuw87caicjvMer40EREREREREZuzE5HCHGYdVlQ7EYzGcfd/NuPf/ngIiaSEIz0+xBNJpcsjIiIiIiIiBTG4IiLF7Ovw4OKvPY+/HeuHRhRgMWjw8+Z2bHzwOVzznb/jrh+/jqFAVOkyiYiIiIiISCEMrohIMcsqHRBF4LFXW2HQavCtO1aisdSGfn8EALCjdQgffGInwysiIiIiIqI8xeCKiBQjCAI+c91ifO6GxQCASxcW4y/3XYJSu2H0mOYWN363p1OpEomIiIiIiEhB7IBMRIq6ZmnZmI8FQUBDiRW9vgg0ooAtC4vx1jON3ImIiIiIiCi/MLgiItX5+JULcdOKAG5YUc4dBomIiIiIiPIY3xESkeqsry/A+voCpcsgIiIiIiIihbHHFRERERERERERqRKDKyIiIiIiIiIiUiUGV0SUFQKROAKRuNJlEBERERERUQbNKrh68MEHsW7dOthsNpSUlODmm2/G0aNHxxwTDodx7733orCwEFarFdu3b0dvb6+sRRNR/vl5cxtuevgVHO/1K10KERERERERZcisgquXXnoJ9957L15//XU888wziMViuPrqqxEIBEaP+cQnPoE//OEP+OUvf4mXXnoJXV1duPXWW2UvnIjyiygIONE3jLd8/xX88KWTiMQTSpdEREREREREaSZIkiTN9cH9/f0oKSnBSy+9hEsvvRRerxfFxcX42c9+httuuw0AcOTIESxatAivvfYaNm7cOG6MSCSCSCQy+rHP50N1dTW8Xi/sdvtcSyOiHNPpCeHirz0/+nFNgRkPXNuEa5aWQRAEBSsjIiIiIiKi2fD5fHA4HDPKflLqceX1egEABQUj29bv3LkTsVgMW7duHT2mqakJNTU1eO211yYc48EHH4TD4Rj9U11dnUpJRJSjbEYtTDrN6Mdt7iA+/D+7cOePXocnGFWwMiIiIiIiIkqXOQdXyWQS9913Hy6++GIsXboUANDT0wO9Xg+n0znm2NLSUvT09Ew4zgMPPACv1zv6p729fa4lEVEO+/HfTiEUG788sLnFjS/8/qACFREREREREVG6zTm4uvfee3HgwAE8+eSTKRVgMBhgt9vH/CEiOt/fj/fjkRdPTnr/b/d0oc8fzmBFRERERERElAlzCq4++tGP4o9//CNeeOEFVFVVjd5eVlaGaDQKj8cz5vje3l6UlZWlVCgR5SdJkvDFPxxCIjl1O75jPcMZqoiIiIiIiIgyZVbBlSRJ+OhHP4rf/OY3eP7551FfXz/m/jVr1kCn0+G5554bve3o0aNoa2vDpk2b5KmYiPKKIAgosuqnPe7uR99Aj5ezroiIiIiIiHLJrIKre++9F0888QR+9rOfwWazoaenBz09PQiFQgAAh8OBe+65B/fffz9eeOEF7Ny5E+95z3uwadOmCXcUJCKaiVtXV01/EICvP31k2plZRERERERElD20szn4Bz/4AQBgy5YtY27/yU9+gne/+90AgG9/+9sQRRHbt29HJBLBtm3b8Mgjj8hSLBHlpyuaSmZ03K93daKmwIz7ti5Mc0VERERERESUCbMKriRp+pkMRqMRDz/8MB5++OE5F0VEdL4iqwGNpTYc7fVPe2xdoSUDFREREREREVEmzHlXQSKiTFpX75r2mAeubcLNqyozUA0RERERERFlwqxmXBERKcWg1Ux636JyO95/Sf2Me2ERERERERFRdmBwRURZIRhNjLvtkgVF+NJNS1FfxOWBREREREREuYjBFRFlhXBsbHC1bUkpvnfXqilnYhEREREREVF2Y3BFRFmh1G4c/feySgcefttqaDVs00dERERERJTL+K6PiLLC/VctxIcumw8AuH1tFUMrIiIiIiKiPMAZV0SUFfRaEf98bRNuXlWB+cVWpcshIiIiIiKiDGBwRURZpanMrnQJRERERERElCFca0NERERERERERKrE4IqIiIiIiIiIiFSJwRUREREREREREakSgysiIiIiIiIiIlIlBldERERERERERKRKDK6IiIiIiIiIiEiVGFwREREREREREZEqMbgiIiIiIiIiIiJVYnBFRERERERERESqxOCKiIiIiIiIiIhUicEVERERERERERGpEoMrIiIiIiIiIiJSJQZXRERERERERESkSgyuiIiIiIiIiIhIlRhcERERERERERGRKjG4IiIiIiIiIiIiVWJwRUREREREREREqsTgioiIiIiIiIiIVInBFRERERERERERqRKDKyIiIiIiIiIiUiUGV0REREREREREpEoMroiIiIiIiIiISJUYXBERERERERERkSoxuCIiIiIiIiIiIlVicEVERERERERERKrE4IqIiIiIiIiIiFSJwRUREREREREREakSgysiIiIiIiIiIlIlBldERERERERERKRKDK6IiIiIiIiIiEiVGFwREREREREREZEqMbgiIiIiIiIiIiJV0ipdwIUkSQIA+Hw+hSshIiIiIiIiIiK5nc18zmZAU1FdcOX3+wEA1dXVCldCRERERERERETp4vf74XA4pjxGkGYSb2VQMplEV1cXbDYbBEFQuhz4fD5UV1ejvb0ddrtd6XKI0orXO+UTXu+UT3i9Uz7h9U75hNc7ZStJkuD3+1FRUQFRnLqLlepmXImiiKqqKqXL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", "text/plain": [ - "<Figure size 1440x720 with 1 Axes>" + "<Figure size 2000x1000 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -567,7 +565,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 41, "metadata": {}, "outputs": [ { @@ -578,7 +576,7 @@ " dtype=object)" ] }, - "execution_count": 7, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" } @@ -589,7 +587,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 42, "metadata": {}, "outputs": [], "source": [ @@ -609,27 +607,39 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "# Country names used in file names\n", "countries = [\n", " 'aland',\n", + " 'argentina',\n", " 'australia',\n", " 'belgium',\n", + " 'bolivia',\n", " 'brazil',\n", " 'bulgaria',\n", " 'burundi',\n", " 'canada',\n", + " 'chile',\n", " 'china',\n", + " 'colombia',\n", + " 'costa rica',\n", + " 'cuba',\n", " 'denmark',\n", + " 'dominican republic',\n", + " 'ecuador',\n", " 'egypt',\n", + " 'el salvador',\n", " 'estonia',\n", " 'ethiopia',\n", " 'france',\n", " 'finland',\n", " 'germany',\n", + " 'guatemala',\n", + " 'haiti',\n", + " 'honduras',\n", " 'iceland',\n", " 'india',\n", " 'indonesia',\n", @@ -638,18 +648,25 @@ " 'japan',\n", " 'kenya',\n", " 'korea',\n", + " 'latvia',\n", " 'liechtenstein',\n", " 'malaysia',\n", " 'mexico',\n", " 'morocco',\n", " 'myanmar',\n", " 'netherlands',\n", + " 'nicaragua',\n", " 'nigeria',\n", " 'norway',\n", + " 'panama',\n", + " 'paraguay',\n", " 'portugal',\n", " 'poland',\n", + " 'puerto rico',\n", " 'russia',\n", " 'rwanda',\n", + " 'saint barthelemy',\n", + " 'saint martin',\n", " 'singapore',\n", " 'slovenia',\n", " 'spain',\n", @@ -664,6 +681,7 @@ " 'ukraine',\n", " 'uruguay',\n", " 'usa',\n", + " 'venezuela',\n", " 'zambia',\n", "]\n", "\n", @@ -691,21 +709,19 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 44, "metadata": { "scrolled": false }, "outputs": [ { "data": { - "image/png": "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xI/dpsUIcaX0d+lwcaUypzFcTInPl18B73PO/XU6YulrzvdcBn5qZgVABHhL4izhp4lfkvA64DDxZMOsZmY/AK4ACi1eR/AjxOsIDrWdvyZef3of0EF89PZZaZjtbiB+2W8R8Csz2+6ce55zbpeZ/Yj4h1EP8ffDjCgGP9sN8zq8n/gl0Pcnesk94px7Y8qCHIdxbs9lwMfMLEK8BtkbU1CfalTj2SbnXKOZfZ74D1AH/No596vURD68CbzvLgOOOudmYpJkrrmYeD3bHRavLQjwr8AbgC8lDg67gKmqoVkG3JVIkHmAHznnfmlmu4G7zewTwONMXVmO4drvIf59/PfE+/NnzrmPTVf7U9DOuNo3s4eB75nZPwNtxOsfT3cMbyB+bBgDGonXZj8rmdlNDHG8xAz7Xhsuzhl+XPf/zGwt8e/QQ0zzpakjcc71mNlbif9g9wLfdM7NiMGIBigB7kl8VvqA7zvn5vSVBlNsuO/lW2bqe3UIqf5un6zh4v+TmRUBRryM56z4vZTwXmbHc58q3wS+aWY7iQ+Qd3uiF3Mqv7+G+376b+BbZraL+HvxW865J6cppmHjmgG/S2fi9/lwMb2V+FWKHzazDyemXeOmcADtvmzwFcMiIiIiIiIiIiIiIiOb82UxRERERERERERERCT5lFwWERERERERERERkXFTcllERERERERERERExk3JZREREREREREREREZNyWXRURERERERERERGTclFwWERERERERERERkXFTcllERERERERERERExk3JZREREREREREREREZNyWXRURERERERERERGTclFwWERERERERERERkXFTcllERERERERERERExk3JZREREREREREREREZNyWXRUTmGDN7tZk9PMLjvzGz26czJhERERERERGZe3ypDkBERKaXc+75qY5BRERERERERGY/9VwWERERERERERERkXFTcvksYWbOzBb3uf9tM/tE4nahmf3SzJrMrMHMHjIzT+Kx95nZfjNrNbPdZnZTqrZBZC4ws5vNrK3PX7eZPWBm15vZ42bWYmZHzeyjfZapSuzDr0k81mhmbzSzDWb2ZGLf/fLgpuzLZtZsZnvM7Mo+DzxgZq9P3F5kZn8ys9NmVm9m3zOz3Gl5MkRERERERERkVlNyWQDeBRwDioAS4F8Bl3hsP3ApkAP8G/BdMytLRZAic4Fz7ofOuUznXCYwDzgA/ABoB14F5ALXA28ysxcNWHwTsAS4Gfgi8AHgKmAl8HIzu3zAvPuBQuAjwM/MLH+IkAz490Qsy4EK4KOT3EwREREREREROQsouSwAEaAMWOCcizjnHnLOOQDn3I+dcyecczHn3A+BvcDGVAYrMhckrg74PvCAc+5rzrkHnHM7Evvak8QTzpcPWOzjzrku59zviSejf+Ccq3XOHQceAs7rM28t8MXEPv1D4GniSet+nHP7nHP3O+e6nXN1wOeHaFdEREREREREZBAllwXgP4B9wO/N7ICZve/MA2b2KjPbnrjsvglYRbwnpIhMzieBLOBtAGa2ycz+bGZ1ZtYMvJHB+9qpPrc7h7if2ef+8TMniRIOE++d3I+ZlZjZ3WZ23MxagO8O0a6IiIiIiIiIyCBKLp89OoBQn/ulZ24451qdc+9yzi0EXgi808yuNLMFwNeBtwIFzrlcYCfxy+hFZILM7BXALcBLnXORxOTvA/cBFc65HOCrTG5fKzezvstXAieGmO9TxMvgrHbOZQP/MMl2RUREREREROQsoeTy2WM78Eoz85rZtfS57N3MbjCzxYlEVDMQBWJABvGkU11ivtcQ77ksIhNkZucB/wW8KFGG4owsoME512VmG4FXTrKpYuBtZuY3s5cRr6f86yHmywLagGYzKwf+ZZLtioiIiIiIiMhZQsnls8fbgRcATcCtwL19HlsC/IF4gunvwP845/7snNsNfC4x7RSwGvjr9IUsMifdCOQBD5tZW+LvN8CbgY+ZWSvwYeBHk2xnM/F9u554CY6XOudODzHfvwHnEz+x9CvgZ5NsV0RERERERETOEta/JKeIiIiIiIiIiIiIyOjUc1lERERERERERERExk3JZREREREREREREREZNyWXRURERERERERERGTclFwWERERERERERERkXFTcllERERERERERERExs2X6gAGKiwsdFVVVakOQ2Tabdu2rd45V5TqOCZK+66crWb7visiIiIiIiIyUTMuuVxVVcXWrVtTHYbItDOzw6mOYTK078rZarbvuyIiIiIiIiITpbIYIiIiIiIiIiIiIjJuSi6LiIiIiIiIiIiIyLjNuLIYIiIys0RjjhNNneyvayPg83DRosJUhyQiIiIiIiIiM4CSyyIiAkBzR4T99W0crGvnQH0bB+raOVDX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o/f9PJKA18ONa+dx9YoSLlhUQHba4DrkIiIiIiIiIiIjsVQlW4azfv16t3Xr1lSHIdOkKxLlvu0nyErz8fzVZQCcbO7i+v98iNPtgwfiO+Ol55fziZtWD7pUv727hweermNBQYiTzV1sqMofVCd6oCeONnHr/26mrTteeuAP77w8JSUAzGybc279tDecJLNh373ycw+wv649JW0vLcnkmVNtU96O12PMz0vnVEsXy8uyOVDXRnNn/8E2r1pewqdevIriLPVGTobZvu+KiIiIiIiITNSs7bns3LM1fWX2SvN7efmGin7TSnPSeM+15/Den/YvmRHwenjblYt4zrISVs7LGXJ9GUEf16+JJ6lXlQ89z0Br5ueQk+6nrbuHY42d/HVfPVcuL5nA1shMl8pTabmhwLS0E405Dp+Ol8h4/EgTAIuLMynICFCUFeSckize+tzF+vwUERERERERkUmbtcllJUbmtps3VPJUTSvf/tuh3mn/cs0SXn/ZoqS/9l2RGHkZ/t5SHH/aU6vk8hyVyk+NmHP4PUZksqNYTsC+2jb2AY+8/0pKc9RbWURERERERESSw5PqAESG855rzyHoi79Fs4I+rj+3fEpOKqQHvGyqLsCXGHTt3sePc7pt9Jq1MvsUZQVT1raH1CSWzwgFvBRmTk/vaRERERERERE5Oyi5LDNWKODjvdcuI93vpbW7h7rWrilr633PO4eNVXkAtIejHKxPTV1emVovWlueknZLc9LYfWLyg/lNRmbQh0dXfIiIiIiIiIhIEim5LDPaay+p5tEPXsVdr91IODp1vT79fi//ev0KynPTCXg9VBdmTFlbkjrXriqlPDd9WttcvyCPlo4wbeHotLY7kAM8HiWXRURERERERCR5Zm3NZTl7ZAZ9XL60aMrbWVWewydetIo9NS0UZKaufIJMndxQoF997am2al422w43pnQgwTNec3FVqkMQERERERERkTlGyWWRhEhPjAsX5nP50sJUhyJT6EPXr+BV39xCd09syttK83tTmliuKgjxsvUVXLy4kHPn56QwEhERERERERGZi5RcFknw+zz4VSlmztu0sIA/v/sKfr2jhk/9+immcoy9rYcbWVWejQE7jrdMXUMDXL+6jNsvqmJDVd6UDIIpIiIiIiIiIgJKLovIWWhebjqvv3QhneEon7v/mSlta+fxFjZW509pG2cUZgb4wPXLuem8+dPSnoiIiIiIiIic3ZRcFpGz1h2XL2Tr4UYefKZuStsJT3EJjmWlWbzpikVcu6qUoM87pW2JiIiIiIiIiJyRtBoAZlZhZn82s91mtsvM3p6Ynm9m95vZ3sT/vGS1OV0a2rv56776VIchIkkW9Hm581Xr+MgLVkxZG0tLMtlX2zpl6185L5t733IxN64tV2JZRERERERERKZVMgvM9gDvcs6tAC4A3mJmK4D3AX90zi0B/pi4P6vkZwS5eHF8kLf7d5+isT1MXWt3iqMSGZqZvSxxgidmZuv7TL/VzLb3+YuZ2dohlv+omR3vM99107oB0yzo8/Kai6u5clnxlKw/5qCtOzol6w74PHzh5rWk+ZVUFhEREREREZHpl7TksnOuxjn3WOJ2K/AUUA7cCNyVmO0u4EXJajMVrl5RQl5GgOaOMH986lSqwxEZyk7gxcBf+k50zn3PObfWObcWuA046JzbPsw6vnBmXufcr6c02hniv155HrddsIDMYPKqBeWk+zlU35a09Q30D5sWsLQka8rWLyIiIiIiIiIykmT2XO5lZlXAecBmoMQ5V5N46CRQMhVtTrfFJVlsqM7ns797ms7w1PRKFJkI59xTzrmnR5ntFuDu6YhntggFfHz8Rav487uvIDstOQnmpSWZTFW55YDXw0vWlU/NykVERERERERExiDpyWUzywR+CrzDOdfS9zHnnAPcEMvcYWZbzWxrXd3UDqyVTKeau/jWXw/y4DO1qQ5FZLxuBn4wwuNvNbMnzeybs7FO+mQUZQX5yj+sozAzOOJ8HoMlxZmsW5DHpUsKyU7zkeb39FuuoT08JTFmBn186zUbWDkvZ0rWLyIiIiIiIiIyFsm7/hswMz/xxPL3nHM/S0w+ZWZlzrkaMysDBmVinXN3AncCrF+/flDyeaaqLszg9++8nPLc9FSHImcZM/sDUDrEQx9wzv18lGU3AR3OuZ3DzPIV4OPETwR9HPgc8Nph1nUHcAdAZWXl2IKfBS5eXMg3X72ePTWtfPDenUSdY0lxJqvKc1g1L5tV5TmsmJdNKPDsR2h3T5TTbWHm5aZzqqWLRw6c5ot/2Jv02LLSfHzv9ZtYMz836esWERERERERERmPpCWXzcyAbwBPOec+3+eh+4DbgU8n/o+Y+JpNfF6PEsuSEs65qyax+CsYodeyc663mLiZfR345QjzzsoTQ2OxZn4ua+bnsq4qj/Lc9FEHzQv6vMxLfB6UZKdx49pyrlxewm3f2MzjR5qSEpMSyyIiIiIiIiIykySzLMbFxAcJe66ZbU/8XUc8qXy1me0FrkrcF5EUMDMP8HJGqLecuMLgjJuIDxB41lpUlDlqYnk4mUEf337NRl59UVW/6QUZgQmt787b1iuxLCIiIiIiIiIzRtJ6LjvnHgZsmIevTFY7IjIyM7sJ+C+gCPiVmW13zj0v8fBlwFHn3IEBy/wv8FXn3Fbg/5nZWuJlMQ4B/zhdsc9FOel+PvrClbzx8kUcaehgfl46pdlp3Lv9OO/72Q7CPTFy0v1cvLiALQcbqG8buk7zhQsLWLfgrCp/LSIiIiIiIiIzXFJrLotI6jnn7gHuGeaxB4ALhpj++j63b5uy4M5ipTlplOak9d5/8fnzaevuIdwT48Xnzyc/0Zt5f10bP9h8hG/97RCFmQFuWDOPK84pYlN1AQFf0sdgFRERERERERGZMCWXRURS5FUXVg2atqgokw/esII7LltIdrp/wiU5RERERERERESmmpLLIiIzUHF22ugziYiIiIiIiIikkK6xFhEREREREREREZFxU3JZRERERERERERERMZNyWURERERERERERERGTdzzqU6hn7MrA44PIFFC4H6JIeTLIptYs622BY454qSvM5pM4l9dyxm8nthJLM1bpi9saci7lm974qIiIiIiIhM1IxLLk+UmW11zq1PdRxDUWwTo9jkjNn6fM/WuGH2xj5b4xYRERERERGZjVQWQ0RERERERERERETGTcllERERERERERERERm3uZRcvjPVAYxAsU2MYpMzZuvzPVvjhtkb+2yNW0RERERERGTWmTM1l0VERERERERERERk+sylnssiIiIiIiIiIiIiMk1mXXLZzF5mZrvMLGZm6/tMv9XMtvf5i5nZ2sRjD5jZ030eK05BfFVm1tknhq/2eWydme0ws31m9p9mZtMY19Vmti3R/jYze26fx1L+vCUee3/iuXnazJ7XZ/q1iWn7zOx9UxXbgFh+2Of5OGRm2xPTh319ZezMrMLM/mxmuxPvh7cnpueb2f1mtjfxPy/VsQ40QuwfNbPjfd4b16U61r7MLM3MtpjZE4m4/y0xvdrMNif2rx+aWSDVsfY1QtzfNrODfZ7vtSkOVURERERERGTO8qU6gAnYCbwY+Frfic657wHfAzCz1cC9zrntfWa51Tm3NVXxJex3zq0dYvpXgDcAm4FfA9cCv5mmuOqBFzjnTpjZKuB3QHmfx1P6vJnZCuAVwEpgHvAHM1uaePi/gauBY8CjZnafc273VAbpnLu5T2yfA5r7PDzc6ytj1wO8yzn3mJllAdvM7H7g1cAfnXOfTpxIeB/w3hTGOZThYgf4gnPusymMbSTdwHOdc21m5gceNrPfAO8kHvfdiZMlryP+WTVTDBc3wL84536SwthEREREREREzgqzrueyc+4p59zTo8x2C3D3dMQz0Bjj62VmZUC2c+4RFy+A/R3gRdMVl3PucefcicTdXUC6mQWT3f5oRnjebgTuds51O+cOAvuAjYm/fc65A865MPHX+8bpijfRu/zlwA+mq82zgXOuxjn3WOJ2K/AU8ZMdNwJ3JWa7iynYRyZrhNhnNBfXlrjrT/w54LnAmQTtjHvOR4hbRERERERERKbJrEsuj9HNDE76fStxifSHpqLsxBhVm9njZvagmV2amFZOvOftGcdIXULqJcBjzrnuPtNS/byVA0f73D/z/Aw3fbpcCpxyzu3tM22o11cmyMyqgPOI9+gvcc7VJB46CZSkKq6xGBA7wFvN7Ekz++YMLenhTZR4qQXuB/YDTc65nsQsqfxcGtbAuJ1zZ57vTyae7y+k4mSZiIiIiIiIyNliRpbFMLM/AKVDPPQB59zPR1l2E9DhnNvZZ/KtzrnjiUvVfwrcRryH8HTGVwNUOudOm9k64F4zWznRGJIY15llVwKfAa7pM3kmPG/Tboxx3kL/ExhDvr7OuZYpDndOMrNM4u+5dzjnWvqe13DOOTObsT1Uh4j9K8DHifeq/TjwOeC1KQxxEOdcFFhrZrnAPcCy1EY0NgPjTpT2eT/xExAB4E7i5VM+lrIgRUREREREROawGZlcds5dNYnFX8GAXsvOueOJ/61m9n3iJRUmnCSdSHyJ3sDdidvbzGw/sBQ4DszvM+v8xLRpiQvAzOYTTyi9yjm3v8/6Uv68EX8uKvrc7/v8DDd9UkaL08x8xOtDr+uzzHCv73TUq55TEvVzfwp8zzn3s8TkU2ZW5pyrSZSSqU1dhMMbKnbn3Kk+j38d+GWKwhuVc67JzP4MXAjkmpkv0Xs5afvXVOgT97V9alt3m9m3gHenMDQRERERERGROW1OlcUwMw/xOrh395nmM7PCxG0/cAPxweOmO7YiM/Mmbi8ElgAHEpf6t5jZBYmyE68Cpq0Xb6LH36+A9znn/tpn+ox43oD7gFeYWdDMqok/b1uAR4ElZlZtZgHiJxXum6aYrgL2OOd6y5kM9/pOUzxzRmIf+AbwlHPu830eug+4PXH7dqZxHxmr4WJPJMPPuInU7EfDSrx3cxO304kPkvkU8GfgpYnZZtxzPkzce84834nX40XMsOdbREREREREZC6ZkT2XR2JmNwH/BRQBvzKz7c655yUevgw46pzrm9QLAr9LJEi9wB+Ar6cgvsuAj5lZBIgBb3TONSQWezPwbSAd+E3ib7rieiuwGPiwmX04Mfs1QDsz4Hlzzu0ysx8Bu4Ee4C2JS+Exs7cCv0vE903n3K6pim+AQb3jGfn1lbG7mHj5lR2JWroA/wp8GviRmb0OOEz8JNJMM1zst5jZWuJlMQ4B/5iK4EZQBtyVODniAX7knPulme0G7jazTwCPE0+czyTDxf0nMysCDNgOvDGFMYqIiIiIiIjMaebcjC1dKiIiIiIiIiIiIiIz1JwqiyEiIiIiIiIiIiIi00PJZREREREREREREREZNyWXRURERERERERERGTclFwWERERERERERERkXFTcllERERERERERERExk3JZREREREREREREREZNyWXRURERERERERERGTclFwWERERERERERERkXH7/6uwjKg+H2K6AAAAAElFTkSuQmCC", + "image/png": "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Cy9www03cP7553PBBRcAMGLECPc9HA4HM2bM4KSTTuKxxx5zt6E1Y9TmHDp0iE8++YRZs2aRkpJCYWEhL730EieffDK7d+8mLi6uVfcTQhy/LrroIpKTk3n44YdZu3YtzzzzDOXl5bzxxhsAPPjgg9x9991cdNFFXHfddRQXF/Pss88ydepUtmzZ0qAEzhEul4uzzz6b9evXc8MNNzBo0CA+/fTTTnuOvvjiixk8eDD/+c9/+PLLL3nggQcICwvjpZde4tRTT+WRRx5hxYoVLFy4kHHjxjF16tROaYcQ4vjVXH963XXX8frrr/O3v/2N2267jXXr1vHwww+zZ88eVq5c2arPuf3223n//ffdC9KPeP/995k+fTqhoaGNXv/0009zzjnncPnll2Oz2Xj33XeZNWsWX3zxBWeeeWbbvrwQQrRTc30owI8//sj777/P/PnziYiIcC/waUm/9ve//53TTz/d4zO/+eYbVqxYQVRUVJd9T9GNKEL4SE1NTYNja9asUQDljTfecB/76aefFED56aefmrz24YcfVlQqlZKZmek+Nnv2bAVQ7rvvPo9zR48erYwZM8b9+pNPPlEA5b///a/7mMPhUKZMmaIAyrJly9ryFYUQQlGUlvd3y5YtUwDlpJNOUhwOh/u41WpVwsPDlXHjxil2u919fPny5QqgnHzyye5jb775pqJWq5XVq1d7fN6LL76oAMrvv//uPgYoer1eSUtLcx/btm2bAijPPvus+9ijjz6qAEp6enqD75GUlKTMnj27wXc4/fTTFZfL5T5+6623KhqNRjGbzU3+XP7+978r/v7+Sl1dXYP3hBDHp5b2oUuWLFG8Pd4c6ZeO9GErV65UAGXDhg2NfmZxcbECKEuWLGnw3pHx5aJFi1rUVm9jVG9tPbY/raurU5xOp8c56enpisFgaDC2FUIIb470Neecc47H8RtvvFEBlG3btikZGRmKRqNRHnzwQY9zduzYoWi1Wo/js2fPVpKSktyvP/roIwVQnnrqKfcxp9OpnHrqqQ2eo4/t99LT0xt91j62/z1y7fXXX+8+5nA4lPj4eEWlUin/+c9/3MfLy8sVPz8/j/5UCCHaqyX96datWxVAue666zzOWbhwoQIoP/74o/vYySef7PEc761PnDhxosfcpaIoyvr16xuMgY/tmxWl4ZjUZrMpw4YNU0499dTWfG0hhOgQLelDFaV+DKhWq5Vdu3Y1uEdb+rUDBw4oJpNJ+ctf/uKeZ/XW3zY2lyB6PkmBLnzGz8/P/Xe73U5paSn9+vUjJCSEzZs3t/hai8VCSUkJkyZNQlEUtmzZ0uD8f/zjHx6vp0yZwqFDh9yvv/rqK7RarXtHOIBGo+Gmm25q9fcSQohjtba/mzt3rkctmo0bN1JaWsrcuXPRav9M3nL55Zc3WPX9wQcfMHjwYAYNGkRJSYn7z6mnngrATz/95HH+6aefTmpqqvv1iBEjCA4O9ugj2+L666/3SHM5ZcoUnE6nRwq3o38uVVVVlJSUMGXKFGpqati7d2+7Pl8I0Xu0Z8zozZGdjF988QV2u73N7Tp63OitrS0ZozbFYDCgVtc/rjmdTkpLSwkMDGTgwIFt+t5CiOPXvHnzPF4fec796quv+Pjjj3G5XFx00UUeY8eYmBj69+/fYOx4tG+++QadTsfcuXPdx9RqdYPP6yjXXXed++8ajYaxY8eiKArXXnut+3hISAgDBw5s91hWCCG8aao//eqrrwBYsGCBxzm33XYbAF9++WWrPuviiy9m06ZNHDx40H3svffew2AwcO655zZ57dFj0vLycioqKpgyZYqMIYUQPtVUH3rEySefzJAhQxpc29p+zWKxcP755xMaGso777wjNb+PUxIAFz5TW1vLPffcQ0JCAgaDgYiICCIjIzGbzVRUVDR5bVZWFnPmzCEsLMxd1/vkk08GaHCt0WhskKo3NDTUXSsH6mtLxsbGEhgY6HHewIED2/MVhRACaH1/l5KS4vH6SNC4X79+Hse1Wm2DWl8HDhxg165dREZGevwZMGAAUJ/692iJiYkNPv/YPrItjr3vkUD90ffdtWsX559/PiaTieDgYCIjI7niiiuAhn25EOL41Z4xozcnn3wyF154IUuXLiUiIoJzzz2XZcuWNVub8Whardaj/MQRrRmjNsflcvHkk0/Sv39/j++9fft26SOFEK3Sv39/j9epqamo1WoyMjI4cOAAiqLQv3//BuPHPXv2NBg7Hu3Ic/SxpSiOHbN2lGPHlyaTCaPR6C7Rc/Tx9o5lhRDCm6b608zMTNRqdYM+MCYmhpCQEK/1vJsya9Ys1Gq1u4yYoih88MEHnHHGGQQHBzd57RdffMGJJ56I0WgkLCzMXeJHxpBCCF9qqg894tg50SNa26/NnTuXgwcPsnLlSsLDwzvsO4ieRWqAC5+56aabWLZsGbfccgsTJ07EZDKhUqm45JJLcLlcjV7ndDr5y1/+QllZGXfccQeDBg0iICCA3Nxc5syZ0+BaWd0jhPC11vZ3R69qbC2Xy8Xw4cN54oknvL6fkJDg8bqxPlJRlDa3oSX3NZvNnHzyyQQHB3PfffeRmpqK0Whk8+bN3HHHHU3+HhBCHF9a2ocenXXiaE6n0+O1SqXiww8/ZO3atXz++ed8++23XHPNNTz++OOsXbu2wYJIb47enX3057RmjNqchx56iLvvvptrrrmG+++/n7CwMNRqNbfccov0kUKIdjm6v3S5XKhUKr7++muv47eW9IntbcPRju2zj+atfZ01lhVCiJbw1pc11r+1VlxcHFOmTOH999/nzjvvZO3atWRlZfHII480ed3q1as555xzmDp1Ks8//zyxsbHodDqWLVvG22+/3SFtE0KIjuCtv/Q2J9rafu3pp5/mnXfe4a233mLUqFGd0XTRQ0gAXPjMhx9+yOzZs3n88cfdx+rq6jCbzU1et2PHDvbv38/rr7/OVVdd5T7+/ffft7ktSUlJ/PDDD1RXV3s84O/bt6/N9xRCiCPa2t8dkZSUBEBaWhrTpk1zH3c4HGRkZDBixAj3sdTUVLZt28Zpp53WYQ/eHXWfo/3888+Ulpby8ccfM3XqVPfx9PT0Dv8sIUTP1tI+9EimCbPZ7E5zDjS62+bEE0/kxBNP5MEHH+Ttt9/m8ssv59133+W6665rU7/X0WPUDz/8kGnTpvHqq696HDebzQ12OwohRFMOHDjgsZsmLS0Nl8tFcnIyGo0GRVFISUlxZwxqqaSkJH766Sdqamo8doGnpaU1e+3RffbRWrtDUgghulJT/amiKLhcLg4cOMDgwYPd5xQWFmI2m93P9a1x8cUXc+ONN7Jv3z7ee+89/P39Ofvss5u85qOPPsJoNPLtt99iMBjcx5ctW9bqzxdCiI7UVB/alNb0a6tXr2bhwoXccsstXH755R3WdtEzSQp04TNHHrSP9uyzzza54vvIdeC5oltRFJ5++uk2t+Wvf/0rDoeDF154wX3M6XTy7LPPtvmeQghxRFv7uyPGjh1LeHg4r7zyCg6Hw318xYoVDdI7XnTRReTm5vLKK680uE9tbS0Wi6XV7Q8ICAAaTlC2h7e+3Gaz8fzzz3fYZwgheoeW9qGpqakA/Prrr+5jFouF119/3eO88vLyBvc7sir8SBr0I4Gc1vR7HT1G9fa9P/jgA3Jzc9t0PyHE8eu5557zeH3kOfeMM87gggsuQKPRsHTp0gZ9jqIolJaWNnrfGTNmYLfbPcadLperwed5ExwcTEREhEefDchYUAjRrTXVn/71r38F4KmnnvI450h2tjPPPLPVn3fhhRei0Wh45513+OCDDzjrrLPcz+eN0Wg0qFQqj7FyRkYGn3zySas/XwghOlJTfWhTWtqv5efnc9FFF3HSSSfx6KOPdkyjRY8mO8CFz5x11lm8+eabmEwmhgwZwpo1a1i1alWzNRkGDRpEamoqCxcuJDc3l+DgYD766KN21fg6++yzmTx5MosWLSIjI4MhQ4bw8ccfS20cIUSHaGt/d4Rer+fee+/lpptu4tRTT+Wiiy4iIyOD5cuXk5qa6rFT8corr+T999/nH//4Bz/99BOTJ0/G6XSyd+9e3n//fb799lvGjh3bqvaPGTMGgH//+99ccskl6HQ6zj777GYfvJsyadIkQkNDmT17NjfffDMqlYo333xT0lUKIRpoaR86ffp0EhMTufbaa/nXv/6FRqPhtddeIzIykqysLPd5r7/+Os8//zznn38+qampVFVV8corrxAcHOyeuPTz82PIkCG89957DBgwgLCwMIYNG8awYcMabWdHj1HPOuss7rvvPq6++momTZrEjh07WLFiBX379m3T/YQQx6/09HTOOeccZs6cyZo1a3jrrbe47LLLGDlyJAAPPPAAixcvJiMjg/POO4+goCDS09NZuXIl119/PQsXLvR63/POO4/x48dz2223kZaWxqBBg/jss88oKysDms8idN111/Gf//yH6667jrFjx/Lrr7+yf//+jv3yQgjRgZrrT2fPns3LL7/sLvm1fv16Xn/9dc477zyPbG4tFRUVxbRp03jiiSeoqqri4osvbvaaM888kyeeeIKZM2dy2WWXUVRUxHPPPUe/fv3Yvn17q9sghBAdpbk+tDEt7dduvvlmiouLuf3223n33Xc97jFixAiPDJri+CABcOEzTz/9NBqNhhUrVlBXV8fkyZNZtWoVM2bMaPI6nU7H559/zs0338zDDz+M0Wjk/PPPZ/78+c12lo1Rq9V89tln3HLLLbz11luoVCrOOeccHn/8cUaPHt2mewohxBFt7e+ONn/+fBRF4fHHH2fhwoWMHDmSzz77jJtvvhmj0eg+T61W88knn/Dkk0/yxhtvsHLlSvz9/enbty///Oc/W53aEmDcuHHcf//9vPjii3zzzTe4XC7S09PbFQAPDw/niy++4LbbbuOuu+4iNDSUK664gtNOO61VPxchRO/X0j5Up9OxcuVKbrzxRu6++25iYmK45ZZbCA0N5eqrr3afd2Qy8t1336WwsBCTycT48eNZsWKFRzq2//3vf9x0003ceuut2Gw2lixZ0mQAvKPHqHfeeScWi4W3336b9957jxNOOIEvv/ySRYsWtfpeQojj23vvvcc999zDokWL0Gq1zJ8/32NXzKJFixgwYABPPvkkS5cuBSAhIYHp06dzzjnnNHpfjUbDl19+yT//+U9ef/111Go1559/PkuWLGHy5MkeY1Rv7rnnHoqLi/nwww95//33OeOMM/j666+JiorqmC8uhBAdrLn+9H//+x99+/Zl+fLlrFy5kpiYGBYvXsySJUva/JkXX3wxq1atIigoyL1Ysymnnnoqr776Kv/5z3+45ZZbSElJ4ZFHHiEjI0MC4EIIn2quD21MS/u14uJinE4nCxYsaHCPJUuWSAD8OKRSZKuVEEII0SO5XC4iIyO54IILvKY8F0IIIYQQoqt98sknnH/++fz2229MnjzZ180RQgghhBBCHIekBrgQQgjRA9TV1TVID/7GG29QVlbGKaec4ptGCSGEEEKI41ptba3Ha6fTybPPPktwcDAnnHCCj1olhBBCCCGEON5JCnQhhBCiB1i7di233nors2bNIjw8nM2bN/Pqq68ybNgwZs2a5evmCSGEEEKI49BNN91EbW0tEydOxGq18vHHH/PHH3/w0EMP4efn5+vmCSGEEEIIIY5TEgAXQggheoDk5GQSEhJ45plnKCsrIywsjKuuuor//Oc/6PV6XzdPCCGEEEIch0499VQef/xxvvjiC+rq6ujXrx/PPvss8+fP93XThBBCCCGEEMcxqQEuhBBCCCGEEEIIIYQQQgghhBCiV5Aa4EIIIYQQQgghhBBCCCGEEEIIIXoFCYALIYQQQgghhBBCCCGEEEIIIYToFVpdAzw3N5c77riDr7/+mpqaGvr168eyZcsYO3YsAIqisGTJEl555RXMZjOTJ0/mhRdeoH///o3e895772Xp0qUexwYOHMje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GVlZWYiJibFaZmhoKHx8fLBv3z7zg1W1Wo1jx45h4cKFdm1PW7HH52JNdnY2SkpKLB5Id2ZNfS4tIRKJEBUVhX379mHGjBkAakfH79u3D08++WSryycdR6lUQqlUtklZMTExeOutt1BYWGhOCbt3717IZDLzzVtMTAx+++03i/P27t3brN9JW9naturqagCol0mEx+OZR1/b0jZ7srUtUVFREIvFSE5OxqhRowDUBqIyMjIQHBwMoOPbAtjeng8//BBvvvmm+XVubi5iY2PxzTffIDo6GkBte1566SXo9XoIhUIAte2JiIgwpwi0p+b8DuXk5GD8+PHmUfw3fuc6ui2k49hyXRYTEwOVSoVTp06Z13/cv38/TCaT+fehM6gLfl+6dAkHDhyAh4eHxf6u0o6HHnrI6tpvDz30kHl9ta7QFpFIhGHDhiE5Odlie0pKivnvQltdM9ubXq+HXq+v13fy+Xzz3+uu0pbuyB73KN3dhAkTcO7cOYttc+fORe/evbF06VIKfrfAyJEjG+0vCWkNR7o/bYnmPntgjGHbtm14+OGHzfdGdbrifZOj3dO3RGuePyUkJIDH45nb2xW/A6RlHPm55fXaso+0JiEhocNiG476u9+WzwOt6cifmS3sGi9iDqyiooLFx8ez+Ph4BoCtXbuWxcfHs8zMTMYYY99++y07cOAAu3z5Mvvxxx9ZcHAwu/POOy3KeOihh9iyZcvMr1977TX2559/ssuXL7NTp06x++67j0kkEnbhwoV2bVtLLVy4kMnlcnbw4EGWl5dn/q+6utp8zOOPP86CgoLY/v372cmTJ1lMTAyLiYmxKCciIoL98MMP5terV69mbm5u7KeffmJnz55l06dPZ6Ghoaympqbd2tYa9vhcKioq2PPPP8/i4uJYeno6++uvv9iQIUNYeHg402g07dq+lrLlc8nLy2Px8fHs448/ZgDY4cOHWXx8PCspKTEfc/PNN7MNGzaYX3/99ddMLBaz7du3s8TERLZgwQLm5ubG8vPz27V9pONkZmay+Ph49tprrzEXFxdzX11RUcEYY8xgMLD+/fuzSZMmsYSEBPbHH38wpVLJli9fbi4jLS2NSaVS9p///IclJSWxjRs3Mj6fz/7444+OahYrKipiHh4e7M4772QJCQksOTmZPf/880woFLKEhATGmG1t6ywWL17M/P392Z9/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n3/+aVGdfX19MWjQIOzYscMi5c/evXsbXN+HEEJai8fjYcaMGfjll19w8uTJevsZY21+LWjrdWBz+kU+nw+O4yyycGRkZODHH39sUR0JIaS1bOlf25KXlxfGjRuHLVu2IC8vr97+669ZCSGkM2jvfrIh9IySENJebOn3br31Vhw/fhxxcXHm7VVVVdi6dStCQkLQt29fq2Vff/98/aSf8+fPY8+ePbj11lvbvD2fffYZKioqzK+/++475OXlYcqUKQ2eQ/fuXQ/NACd2k56ejmnTpmHy5MmIi4vD559/jlmzZmHgwIEAgEcffRSrV6/Go48+iqFDh+Lw4cNISUlpslxvb28sXrwY77//vrn8M2fO4Pfff4enp6dFiuDbbrsNr7/+OubOnYsRI0bg3Llz+OKLL8wjzFuid+/e6NGjB55//nnk5ORAJpPh+++/b9YaZ4QQ0hB79Z3Xe+SRR7B27VrExsZi3rx5KCwsxObNm9GvXz+o1eoW1XvVqlWYOnUqRo0ahUceeQSlpaXYsGED+vXrh8rKyhaVSQghTXn77bexZ88ejB07FgsWLECfPn2Ql5eHnTt34u+//27za8HmXAfa2i9OnToVa9euxeTJkzFr1iwUFhZi48aN6NmzJ86ePdviz4YQQlqjqf61rW3cuBGjRo3CgAEDMH/+fISFhaGgoABxcXHIzs7GmTNn2vw9CSGkNdq7n7SGnlESQtpTU/3esmXL8NVXX2HKlCl4+umnoVAosGPHDqSnp+P7778Hj9fwfNx3330XU6ZMQUxMDObNm4eamhps2LABcrkcr776apu3RaFQYNSoUZg7dy4KCgqwbt069OzZE/Pnz2/wHLp373poBjixm2+++QZisRjLli3D7t278eSTT1qkn3zllVcwb948fPfdd3jhhRdgNBrx+++/21T2mjVrsGLFCpw4cQLPP/88UlNTsWfPHjDGIJFIzMe9+OKLeO655/Dnn39i8eLFOH36NHbv3o3AwMAWt0soFOKXX37BoEGDsGrVKrz22msIDw/HZ5991uIyCSGkjj37zjp9+vTBZ599hvLycixZsgQ///wz/ve//2HIkCEtrvfkyZOxc+dOGI1GLF++HD/88AO2bduGoUOHtrhMQghpir+/P44dO4a7774bX3zxBZ5++ml89tlnGDduHKRSaZtfCzbnOtDWfvHmm2/GJ598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SL3brV69Gjk5ObZ/NS9SUlNTMXnyZIwZMwaJiYl48skncf/992Pnzp2t3HrnGjqmhIQE+Pr64ocffsDZs2fx4osvYunSpfjkk08ctk1OTrY7bl9f39ZuvlMNHZPFYsHkyZNhNBpx6NAhrF27FmvWrMGyZcts23S096m2YcOG2b3WOTk5uP/++xEREYFBgwbZbbt792677WJiYtqp1a557bXX7Nr72GOP2dZptVqMHz8eYWFhSEhIwMqVK/Hqq6/iq6++ascWk47IHWNbtRshxlVz51hXjWIe6WyOHTtm95ndtWsXAGDWrFm2bR544AG7bTpTxw2dTod+/frh008/dbr+3XffxX//+1988cUXOHr0KGQyGSZMmAC9Xm/b5q677sLZs2exa9cu/P777zhw4AAefPDBtjqERqnveCsqKnDixAm8/PLLOHHiBDZv3ozk5GTcdtttDtvWF8s6kobeXwCYOHGi3bH89NNPdus70/tLSHNNmTIFZrMZe/fuRUJCAvr164cpU6bYOoS6ct5JmmbTpk245557cO+99+LUqVP4999/ceedd9rW3/CvPSNNlp+fzwCwv//+u85tfvnlFyYUCpnJZGrDlrWcuo7x5MmTLCgoiOXk5DAAbMuWLe3TwGZydnyxsbHspZdeasdWtSxnxyiTydj3339vt52npyf7+uuv27p5hLQI+pw3j1qtZt988w0rLS1lAoGAbdiwwbbu/PnzDAA7fPhwO7aw46p+7Zzp7OcApPlWr17NVCqV03UNnT/93//9H+vVq5fdsjlz5rAJEya0YAsbr75jqu3RRx9lY8aMsf29b98+BoCVlJS0TuOaqK5j+uOPPxiXy2W5ubm2ZZ9//jlTKpXMYDAwxjru+1QXo9HIfHx82GuvvWZblpqaygCwkydPtl/DGiksLIytWrWqzvWfffYZU6vVtveJMcaef/55Fh0d3QatI52RO8a2ajdSjKvmLrGuGsU84g6eeOIJFhUVxaxWK2OMsVGjRrEnnniifRvVQmqf11utVubv789WrlxpW1ZaWspEIhH76aefGGOMnTt3jgFgx44ds23z559/Mg6Hw7Kystqs7U3hyn3g+Ph4BoClp6fbljUUyzoqZ8c7f/58Nm3atDof05nfX0Iaq6CggAFgBw4csC3TarUMANu1axdjzLXzTtJ4JpOJBQUF1XlfkjF67TvH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S01NZadPn2ZLlixhHA6H/fXXX4wxxh5++GEWGhrK9u7dy44fP87i4uJYXFxcO7e6Y6jvtXOHcwDSctLT09nJkyfZ8uXLmVwuZydPnmQnT55kZWVljDHGtm3bxr7++mt25swZdunSJfbZZ58xqVTKli1bZtvHlStXmFQqZc899xw7f/48+/TTTxmPx2M7duzokMd05swZ5uPjw+6++267z39+fr5tH6tWrWJbt25lly5dYmfOnGFPPPEE43K5bPfu3R3ymMxmM+vduzcbP348S0xMZDt27GA+Pj5s6dKltn10tPepLrt372YA2Pnz5x3WrVmzhq1bt46dP3+enT9/nr355puMy+Wy7777rh1a2rBDhw6xVatWscTERJaSksJ++OEH5uPjw+bNm2fbprS0lPn5+bF77rmHJSUlsfXr1zOpVMq+/PLLdmw56YjcMbZVu5FiXDV3inXVKOaRzsxisbDQ0FD2/PPP2y2/fPkye+2119jx48dZamoq+/XXX1lkZCQbOXJkO7W08crKymxxFQD74IMP2MmTJ1l6ejpjjLG3336beXh4sF9//ZWdPn2aTZs2jUVERLDKykrbPiZOnMgGDBjAjh49yv755x/WtWtXNnfu3PY6pHrVd7xGo5HddtttLDg4mCUmJtr9XhoMBsaYa7GsI6nveMvKytizzz7LDh8+zFJTU9nu3bvZwIEDWdeuXZler7ftozO9v4Q0R0FBAfPy8mIzZsxgiYmJLDk5mT377LNMIBCwxMRExphr552kaZ544gkWFBTEdu7cyS5cuMAWLlzIfH19WXFxMWOMXntKgDcCAKf/Vq9ezRhjbN++fXVuk5qa2q5td1VDx1jXYzpLAtzV41uxYgULDg5mUqmUxcXFsYMHD7ZPg5vAlWO8ePEimzFjBvP19WVSqZT17duXff/99+3XaEIaiT7nTXffffexsLAwJhQKmY+PD7v55pttyW/GGKusrGSPPvooU6vVTCqVsv/85z8sJyenHVvccdT32rnDOQBpOfPnz3f6Wdi3bx9jjLE///yT9e/fn8nlciaTyVi/fv3YF198wSwWi91+9u3bx/r378+EQiGLjIys93ystTV0TK+88orT9WFhYbZ9vPPOOywqKoqJxWLm6enJRo8ezfbu3ds+B8QaPibGGEtLS2OTJk1iEomEeXt7s2eeeYaZTCa7/XSk96ku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iHd8umXLlnbv87///Q/z589HbGwshEIh0tLS8Mwzz7ToM6dNm4YhQ4a0O4YFgLKyMixYsABSqRSRkZG4//77W/zeJ4SQzti5cydGjx4NkUiEtLQ0vP322632i4GM35r6tYMHD2LKlCmQSCR47LHHvL/F//3vf+P1119HamoqJBIJZs2ahdLSUrAsi2eeeQbx8fEQi8W44ooroNVqfa4dzL7VZDJBKpXi3nvvbfF5lJWVgcvlYs2aNV39aEk3oBTopF3V1dUYP368dzAXERGBzZs345ZbboHBYMB9993Xoes9/fTTWLNmDW699VaMHTsWBoMBBw4cwKFDh3DJJZcAAH755RcUFBTgpptuQnR0NE6cOIF33nkHJ06cwJ49e1p0qE2uvfZa3Hjjjdi/f7934hMAiouLsWfPHrz00kveY2+++SYGDx6Myy+/HDweD99//z3uvvtueDwe/OMf//Ce9+STT+LZZ5/FvHnzMG/ePBw6dAizZs2Cw+Fo8TlNnDgRFosFy5cvR1hYGDZu3IjLL78cX331Fa688kqf85955hkIBAKsWLECdrudUgcTQgAE1ue+++67WL58Of72t795gylZWVnYu3cv/v73v+Oqq67C6dOn8emnn+KVV15BeHg4ACAiIgIAcOutt2Ljxo3429/+hgcffBB79+7FmjVrcOrUKWzatMmnPXl5efjb3/6GW265BUuWLMEHH3yApUuXYtSoURg8eLDf9/Hll1/CYrHgrrvuQlhYGPbt24d169ahrKwMX375Zfd9gISQPq+9fnLRokVYvXo1nnzySdx+++2YPHkyAGDixIneazQ0NGDOnDm46qqrcM011+Crr77CI488gqFDh2Lu3Ll+771t2zbMnTsXqampePrpp2G1WrFu3TpcdNFFOHToEJKTk33Ov+aaa5CcnIw1a9Zgz549eO2119DQ0NBiIVFzBQUF+Pbbb3H11VcjJSUF1dXVePvttzF16lScPHkSsbGxXfsACSEXvDvuuANxcXF47rnnsHz5cowZMwZRUVH4+OOP4XK5MHv2bEyaNAn//ve/IZFIAHRsbOd2uzF79myMGzcO//73v7Ft2zb83//9H9LS0nDXXXd5z7vllluwYcMGzJ07F7feeitcLhd27dqFPXv2eBev/+tf/8ITTzyBa665Brfeeitqa2uxbt06TJkyBYcPH+72Uj+E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r68v0dHRTJkyhczMTKd9tJW6isY5l86D1krOT89r6Dw41V133YVKpeLdd991Wt5S34EEwBuQmZnJuHHj6NSpE+vXr+eXX35h9+7d3HLLLbW2nT9/PllZWY5/V155Zb37vummm9i9ezfLli3jhx9+YPXq1dxxxx3NU5ET3KnP5s2bCQ8P55NPPmH37t089dRTTJ8+nffff7/B/b/44otOx+C+++5rxtq4Vx+bzcbEiRMxm82sWbOGhQsXsmDBAp599tl69+2J7wfg0ksvxWq1smLFCjZv3kzfvn259NJLyc7OBuD66693OsZZWVmMHz+eUaNGER4eXu++W/r7cac+NdrC+XOuGD58eK3f2N///ncSExMZNGiQY7sHHniAjz76iDfffJN9+/axZMkShgwZ4sGStz7uHkuovkibNGkSI0eO9FBpWy93juOaNWvo06cPX3/9NTt27GDatGlMmTKFH374wcOlF6L1a87rKeGe5rpeEu5p6PjL77/x9u3bh91uZ/bs2ezevZt33nmHDz/8kH/+85+1tl2+fLnT73rgwIF17tcT34U7dTmb65CWOq/dqUdJSQkXXXQRCQkJbN68mTfeeIPnn3+eOXPm1LlfT3wnZrOZa6+9lrvvvtvl+rZ0z9xQXWrI/bJoqwoLCxkxYgReXl78/PPP7Nmzh7feeougoCDHNq+//jr//ve/+fDDD1m/fj2+vr6MHz+eqqoqD5a88V577TVmzZrF+++/z969e3nttdd4/fXXmTlzpmObtlzX8vJy+vbty//93/+5XO9O3dpK21RfXSsqKtiyZQvPPPMMW7Zs4ZtvvmH//v1cfvnlTtu1lbqKxjmXzoPWSs5Pz2voPKjx7bffsm7dOqKjo2uta7HvQBH1mj17thIeHq7YbDbHsh07diiAcvDgQccyQPn222/d3u+ePXsUQNm4caNj2c8//6yoVColIyOjScruirv1Od0999yjXHDBBfXuOyEhQXnnnXeaqqhucac+P/30k6JWq5Xs7GzHNrNmzVKMRqNiMplc7tdT38/x48cVQFm9erVjWUlJiQIoy5Ytc/me3NxcxcvLS/n444/r3bcnvh9369NWzp9zldlsVsLCwpQXX3zRsWzPnj2KVqtV9u3b58GStT2ujmWNxx9/XLn55puV+fPnKwEBAS1fuDakvuN4qksuuUSZNm1aC5VKiLar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6CP69etXZ3r0+rTE99PY+pxatpY8f84VjTmvasyfP5+QkJBao3CioqLQarV06dLFsax79+4ApKWlNfo31dY05bFcsWIFS5YscYy+URQFu92OVqtlzpw53HrrrU1a9takKY9jjd9//53LLruMd955hylTpjRVUYVokzx9PXWu8/T10rmuKY+//P5Pauzf7szMTC644AKGDx/OnDlzGtx/cnIyy5Ytq3N9U34XzVGXs70OOZPzuinrERkZ6TieNdy5d26K7+RMrgvd4Yl75uaqy6nlkvtl0VZERUXRo0cPp2Xdu3fn66+/Bk62Ezk5OURFRTm2ycnJoV+/fi1Wzqbw2GOP8eSTT3LDDTcA0Lt3b44ePcqMGTOYOnVqu6rr6dypW3trm2qCa0ePHmXFihVOGf3aW12Fe87F86C1kvPTc/744w9yc3OJj493LLPZbDzyyCO8++67pKamtuh3cM4GwMPCwggLC2vUe2rSV/znP//B29ubCy+8sM5tt23bRlBQUJ03rcOGDaOoqIjNmzc7bsRWrFiB3W4nOTm5UeWCpq/P7t27GTNmDFOnTuXll19udHmg+hjUpBBsrKasz7Bhw3j55ZfJzc11lGXZsmUYjcZaF+E1PPX9VFRUANQabaVWq7Hb7U7LysrK+PLLL5kxY0ajywMt8/00pj6nl60lz59zRWPPK0VRmD9/PlOmTMHLy8tp3YgRI7BarRw+fJiOHTsCOOa5SkhIaLpCt1JNeSzXrl2LzWZzvP7uu+947bXXWLNmDTExMU1W5taoKY8jwKpVq7j00kt57bXXuOOOO5qyqEK0SZ6+njrXefp66VzXlMdffv8nNaZdycjI4IILLmDgwIHMnz/frYwS27Ztc3pgeLqm/C6aui5NcR1yJud1U9Zj2LBhPPXUU1gsFse11rJly+jatWudU3I11XdyJn+zGuKpe+bmqMup5H5ZtCUjRoyolSXuwIEDjucGiYmJREZG8ttvvzkCRCUlJaxfv5677767pYt7VioqKmq1qxqNxnE90Z7qejp36tae2qaa4NrBgwdZuXIlISEhTuvbU12F+86186C1kvPTsyZPnsy4ceOclo0fP57Jkyczbdo0oIW/A0U0aObMmcrmzZuV/fv3K++//77i4+OjvPfee471S5YsUebOnavs3LlTOXjwoPLBBx8oBoNBefbZZx3brF+/Xuna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TwuWSgghWpeG2kohhDhXSfsohBBCCCHamqqqKnQ6HWq1jFsTQjQvnU7n6SK0W1qtFq1Wwq+eJn9JRat1+pwUNXNGLF26lEGDBuHj48Ps2bMBmD9/PmPGjCE8PBy9Xk+PHj2YNWtWrX3W7OPPP/9kyJAheHt7k5SUxMcff9ySVRNCiCZzalvZoUMHdu/eze+//45KpUKlUjnm8ikoKODRRx+ld+/e+Pn5YTQamTBhAtu3b693//Pnz0elUrF169Za61555RU0Gg0ZGRnNUTUhhDgrp19Lfvfdd0ycOJHo6Gj0ej0dO3bkpZdewmazOb1v9OjR9OrVi82bNzN8+HB8fHxITEzkww8/dNrObDbz7LPPMnDgQAICAvD19WXkyJGsXLnSabvU1FRUKhVvvvkmc+bMoWPHjuj1egYPHszGjRub9RgIIcSZOHr0KJ06daJXr17k5ORQVFTEgw8+SFxcHHq9nk6dOvHaa69ht9sd73G3rWvMteUff/zBtddeS3x8PHq9nri4OB566CEZTSOEaJVObzuPHDnCtddeS3BwMAaDgaFDh/Ljjz86vWfVqlWoVCo+//xznn76aWJiYjAYDJSUlACwfv16Lr74YgICAjAYDIwaNYq//vqr1ufec889dO3aFR8fH0JCQrj22mtbzUhKIUTr5WoOcJPJxHPPPUenTp0c11+PP/44JpOp1vs/+eQThgwZgsFgICgoiPPPP9/liPL6YjELFizg2muvBeCCCy5wPM9ctWqVY5uff/6ZkSNH4uvri7+/PxMnTmT37t1On3HLLbfg5+dHRkYGV155JX5+foSFhfHoo4/Wuuf//PPPGThwIP7+/hiNRnr37s17773XpOVxNQe4SqXiH//4B4sXL6ZXr17o9Xp69uzJL7/8UuuYiaYhXRBEm7J//34mTZrEnXfeye23307Xrl0BmDVrFj179uTyyy9Hq9Xy/fffc88992C327n33nud9nHo0CGuueYabrvtNqZOncp//vMfbrnlFgYOHEjPnj09US0hhGgS7777Lvfddx9+fn489dRTAERERABw5MgRFi9ezLXXXktiYiI5OTnMnj2bUaNGsWfPHqKjo13u85prruHee+/l008/pX///k7rPv30U0aPHk1MTEzzVkwIIZrAggUL8PPz4+GHH8bPz48VK1bw7LPPUlJSwhtvvOG0bWFhIZdc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jaZWb8JFixaRkZHh1n779OlDnz59+Oijj/j666+54YYb3OrZKIQQrYGr60Wz2cwHH3zgcnur1crs2bOdtp09ezZhYWEMHDiwzn2uX7+etWvXNnn5hRCiualUKubMmcM111zD1KlTWbJkCQDXXXcda9euZenSpbXeU1RUhNVqPaPPa+ja0lUbqygK77333hl9nhBCNIe62s5LLrmEDRs2OF0XlpeXM2fOHDp06NBg2uCBAwfSsWNH3nzzTcrKymqtP378uOP/Xd3rz5w502naMyGEcMd1111HRkYGc+fOrbWusrKS8vJyAK688krUajUvvvhirUwTZzKSuabj+enPM8ePH4/RaOSVV15xmnKsxqltobvy8/OdXqvVavr06QOAyWRq8fKI5iVPrkWbd9FFFzl67dx5552UlZUxd+5cwsPDycrK8nTxhBCiRQ0cOJBZs2bxr3/9i06dOhEeHs6YMWO49NJLefHFF5k2bRrDhw9n586dfPrppyQlJbm97ylTpvDoo48CSPpzIUSbMnz4cIKCgpg6dSr3338/KpWK//73v3XenEdHR/Paa6+RmppKly5d+OKLL9i2bRtz5szBy8sLgEsvvZRvvvmGv/3tb0ycOJGUlBQ+/PBDevTo4fJBpRBCtHZqtZpPPvmEK6+8kuuuu46ffvqJxx57jCVLlnDppZdyyy23MHDgQMrLy9m5cydfffUVqampbmUTcqW+a8tu3brRsWNHHn30UTIyMjAajXz99dcyP6IQotVx1XY++eST/O9//2PChAncf//9BAcHs3DhQlJSUvj6669Rq+sfk6ZWq/noo4+YMGECPXv2ZNq0acTExJCRkcHKlSsxGo18//33QPU16X//+18CAgLo0aMHa9euZfny5YSEhLRE9YUQ7cjkyZP58ssvueuuu1i5ciUjRozAZrOxb98+vvzyS5YuXcqgQYPo1KkTTz31FC+99BIjR47kqquuQq/Xs3HjRqKjo5kxY0ajPrdfv35oNBpee+01iouL0ev1jBkzhvDwcGbNmsXkyZMZMGAAN9xwA2FhYaSlpfHjjz8yYsQI3n///UZ91t///ncKCgoYM2YMsbGxHD16lJkzZ9KvXz+6d+/e4uURzUsC4KLN69q1K1999RVPP/00jz76KJGRkdx9992EhYVx6623erp4QgjRop599lmOHj3K66+/TmlpKaNG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fdY333yD5cuXY8+ePeByuXj99dfx5Zdf4l//+hfi4+O7bNeOHTtwzTXXIC4uDitXrkRsbCxOnDiBTz/91D94+tVXX2HhwoVIS0vDU089BZvNhr/97W+YNWsWDh482OmGkRBCQtWXvtFms+GSSy5BeXk5HnroIaSmpuLDDz/EXXfdBb1e3ynw8/bbb8Nut+NnP/sZhEIhNBpNyP1afX098vPzodfr8bOf/QxZWVmoq6vDli1bYLVaIRAIYDabMWfOHJw4cQJ33303pk2bhtbWVnzyySeora3F/7N33+FRVekfwL93+mT6pPeEEAIJhBKqSBERbCiKnRVU1oquyrqr7G/tq1jWtorYARUsKCBWFKVJJxBIKIGE9J7MZCbT2/39MWTIJDOTSQ/h/TxPnse599w7Z4I5c+99z3nfsLCwDveZEEKAzo2R1113Hb766iu8/vrr4HK5nnN98cUXYFkW8+fPB+CeWL5x40bceOONSE5ORk1NDd5//31MmzYNx48fb3P9+NJLL4HD4eCxxx6DTqfDK6+8gvnz52Pfvn1e7bRaLa6++mrccsstuPHGG7FixQrccsstWLNmDR555BHcd999uO222/Dqq6/ihhtuQFlZGWQyGYDgnge09MADDyA8PBxPPfUUrawkZAC76aabkJycjGXLluHQoUP46KOPEBERgZdffhkA8MILL+DJJ5/ETTfdhL/+9a+oq6vD22+/jalTp+Lw4cNQKpX4v//7P+h0OpSXl3sW1EilUq/3CWac++OPP3DFFVcgKysLTz/9NDgcjid4vXPnTowfP97rnDfeeCNSU1Px4osvgmVZv59xxYoVyMjIwDXXXAMej4fvv/8eDzzwAFwuFxYvXuzVtqCgADfccAMWLVqEhQsX4pNPPsEdd9yBrKwsZGRkAACqq6txySWXwOFw4IknnoBEIsEHH3wAsVjsda7a2lrMmjUL4eHheOKJJ6BUKlFcXIz169d38F+JEHI+aW9cbS2Ye96OxoR83acHew6Xy4U5c+Zg//79uP/++zF06FB89913WLhwYZd+LxQTOg+whHSDp59+mgXA3nPPPZ5tDoeDjYuLYxmGYV966SXPdq1Wy4rFYnbhwoWedlar1et8Wq2WjYyMZO+66y6v7QDYp59+2vPaZDK16cuePXtYAOynn37q2fb++++zANgTJ054ttlsNjYsLMzT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JyfjzTffbPNgsXksjo6OxqhRo7B69WqvNnl5efj1119x5ZVXdu1DEkJIB1155ZWorq7GV1995dnmcDjw9ttvQyqVYtq0aQGPD3Zc43A4mDt3Lr7//nscPHiwzXmax8l58+bhyJEj2LBhg982Xe0zIYR01O23345ff/0Vb775JkJDQ9tMAPd1771u3TpUVFT0Zje9dOR5ACGEAMD1118PLpeLZ599ts34wbIsGhoaPK8lEkmX0thmZWUhJSUF//3vf2EwGNrsr6ur69R5fT1H1el0XQq6XHnlldi7dy/279/v1b81a9Z4tdNqtW1+b82r2ykNOiGkWTD3vF2JCTUL9hyzZ8+G3W73el7qcrmwfPnyNudMSUnByZMnvcboI0eOYNeuXW3em2JC/R+tACd97uqrr8b69etx3XXX4aqrrkJRURHee+89pKen+7xAbH3sZ599BoVCgfT0dOzZswdbtmxBaGioz/YLFizA//73P2zduhUvv/yy176mpibExcXhhhtuwMiRIyGVSrFlyxYcOHDAa0Z5a1dddRVef/11XH755bjttttQW1uL5cuXY/DgwTh69GjHfyGEENJJt99+O77++mvcd9992Lp1KyZPngyn04mTJ0/i66+/xubNmzF27Fj88ccfePfdd/H0009jzJgxANwzFKdPn44nn3wSr7zyis/zczgcrFixAnPmzMGoUaNw5513Ijo6GidPnsSxY8ewefNmAO4Ub1dccQUmTZqERYsWwWw24+2334ZCocAzzzzTW78OQggBANxzzz14//33cccddyA7OxtJSUn45ptvsGvXLrz55puQyWTtniPYce3FF1/Er7/+imnTpuGee+7BsGHDUFVVhXXr1uHPP/+EUqnEP/7xD3zzzTe48cYbcddddyErKwsajQabNm3Ce++9h5EjR3ZLnwkhpCNuu+02/POf/8SGDRtw//33g8/ne+2/+uqr8dxzz+HOO+/ERRddhNzcXKxZswaDBg3qox53/HkAIYSkpKTgP//5D5YuXYri4mLMnTsXMpkMRUVF2LBhA+655x489thjANwB7K+++gpLlizBuHHjIJVKMWfOnKDfi8Ph4KOPPsIVV1yBjIwM3HnnnYiNjUVFRQW2bt0KuVyO77//vsOfYdasWRAIBJgzZw7uvfdeGAwGfPjhh4iIiEBVVVWHzwcA//znP/HZZ5/h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JiZixYoVqKiowOrVqzF69GgcOXLEpRFps9mQmJiI0aNH4/XXX4dUKq23zO+88w5uuOEGzJo1CxaLBd988w1uueUW/Prrr5g6dWqL3xNCCKmtsbry3nvvxbp163DzzTfjiSeewP79+5GUlIQzZ87UaaClpKRg5syZuP/++3Hfffehd+/eYIzhp59+gl6vh1KpBGMMe/bsAZfLxb///osbbrgBAPDvv/+Cy+XiyiuvBABcvHgRmzdvxi233ILY2FgUFBTgo48+wlVXXYXTp08jLCwMcrkc06dPx7fffos333wTPB7PWZavv/4ajDHnoCNCCGmuW2+9FTExMUhKSsK+ffvw7rvvoqyszBm4Xr16Nfr164cbbrgBfD4fv/zyCx566CE4HA7Mnz/f5Vypqam4+eabcc8992D27Nn4/PPPMWfOHAwbNgz9+vUD4Fn9V1NSUhIkEgmeeeYZpKamYtWqVRAIBOByuSgrK8OyZcuwb98+rF27FrGxsXj++eedP9uUshNCSG3erB/dtSObco7Fixdj5cqVuP7665GYmIhjx44hMTGxRcHntWvXQi6XY+HChZDL5fj777/x/PPPQ6/X47XXXgMA3HnnnXjhhRfw7bff4uGHH3b+rMViwQ8//IAZM2ZALBY3uwyEkM6rsTq0pc/iX3zxBe69916MHDkS8+bNAwB07969yeWcM2cOvvvuO9x555244oorsHPnTrd9lAcPHsR///2H22+/HREREUhPT8fq1asxbtw4nD59usH+UEIIaQlv1qc16fV6fPrpp5g5cybuu+8+GAwGfPbZZ0hMTMSBAwcwePBgl+O/+uorGAwG3H///eBwOFi5ciVuuukmXLx40ZmJ+M8//8SMGTPQt29fJCUloaSkBHPnzkVERESrvT+kjTBC2sDSpUsZAHb33Xe7bJ8+fTrz9/d3vo6OjmazZ892vn7kkUcYh8NhR44ccW4rKSlhGo2GAWBpaWmMMcYMBgNTq9Xsvvvuczl/fn4+U6lULttnz57NALBnnnmmTjlnz57NoqOjXbZVVFS4vLZYLKx///5swoQJntw6IYR4zJO68ujRowwAu/fee12OefLJJxkA9vfffzu3RUdHMwBs69atLscePHiQAWC//fYbY4yx48ePMwDslltuYfHx8c7jbrjhBjZkyBDna5PJxOx2u8u50tLSmEgkYi+88IJz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LIZQKMT111+P+++/H+Xl5fjkk08QFBSEvLy8Zl2vqfVfc11zzTVeLzshpGtp7frR03oqODgYCxYswBtvvOEsz7Fjx/D7778jICDAZcbONddcg6ioKNxzzz146qmnwOPx8Pnnnzuf6auNGjUKfn5+mD17Nh599FFwOBx88cUX9aawFAgEuP322/Hee++Bx+Nh5syZzXxXCSFdRUN1KACvPIsPGzYMf/31F958802EhYUhNjYW8fHxuP3227Fo0SJMnz4djz76KCoqKrB69Wr06tULhw8fdvn5GTNm4O2330ZJSQmuuOIK7Ny5E+fOnQPgOsP8uuuuwxdffAGVSoW+ffti7969+Ouvv+Dv7+/Fd40QQupqrfr0uuuuw8aNGzF9+nRMnToVaWlp+PDDD9G3b1+Ul5c3q6xJSUmYOnUqRo8ejbvvvhulpaVYtWoV+vXr1+xzkvaBZoCTdi0yMhI7duxAnz598Morr+Dtt9/G7NmzcffddwMAxGKx89g77rgD27dvR3h4OF577TUsWLAA33zzDQYPHoy5c+c26/oTJkzAZ599hvz8fDz22GP4+uuvsWLFCkyfPt0r90cIIc3x6aefYvny5Th48CAee+wx/P3331i8eDG++eabJp2nOsA9evRo57aQkBD06NHDZX+1//u//8MTTzyBP/74AwsWLMDhw4exZcsWREZGuj1/cHAwrrnmGgBVs8EJIcRbvv32W4hEIjzzzDPYsmULHn74YWd68t69e+OHH34Ah8PBk08+iQ8//BDz5s3DggULmn29ptZ/zdUaZSeEdC2tXT825RwrVqzAkiVLcPDgQTz55JNITU3Fn3/+CcaYy7O8QCDApk2b0L17dyxZsgTvvvsu7r33Xjz88MMu5/P398evv/6K0NBQPPfcc3j99ddx9dVXY+XKlfWW96677gJQNSM9NDTU4/skhHRNDdWhgHeexd98800MGzYMzz33HGbOnOnMlOHv749NmzZBKpXi6aefxrp165CUlITrr7++zjnWr1+P+fPnY8uWLVi0aBEsFgu+/fZbAK59pe+88w7uuusubNiwAU888QTy8vLw119/QS6XN/ctIoQQj7RWfTpnzhy88sorOHbsGB599FH88ccf+PLLLzF8+PBml3Xy5Mn4/vvvYbfbsXjxYmzcuBFr1qxp0TlJ+8BhtNo76YAee+wxfPTRRygv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DMTLL7/cia1u2s8//4z4+HhIpVJoNBrMmjXL6nl7+7pt27bOaWwzmtuX7tTHhYSE2Bz3devWWZ5PTU21+//m4MGDndhq+5rbF6B7fWdIzzFjxgwEBQVBIpHA19cXd955J7Kzs63W6Y2fzdTUVCxatAihoaGQSqUIDw/HypUrYTAYrNbrjcfGVfdvCOlNmrsndtddd9mcJ0ydOrVzGtsJKEbRPGeO0fjx420+R/fee28ntbhtKADeRX3xxRdYtmwZVq5ciePHj2PQoEGYMmUK8vPzO7tp3VJlZSUGDRqEd955x+7zL7/8Mt5++228++67OHToEORyOaZMmYKampoObmn3tHfvXtx///04ePAgdu7cidraWkyePBmVlZWWdR599FH8+OOP2L59O/bu3Yvs7GzceOONndhq0hMZDAbMmTMH9913n93nTSYTpk+fDoPBgP3792PLli3YvHkzVqxYYVknJSUF06dPx4QJE5CYmIhHHnkEd999N3bs2NFRu+ESPfV3xBX9+e23344zZ85g586d+Omnn/DXX39hyZIlHbULreKKftaZzz8hzrruuutgNBrxxx9/4NixYxg0aBCuu+465ObmAgCOHTsGLy8vfPrppzhz5gyeffZZLF++HP/3f//XyS13jeb2vyd/30aNGoWcnByrv7vvvhuhoaEYNmwYgLrf0pkzZ2LixIlITEzEjh07UFhYSOd+xIozn6WysjJMnjwZwcHBOHbsGF555RWsWrUK77//fie33tbXX3+NO++8EwsWLMCJEyewb98+3HbbbTbrbdq0yWqfGweWu4Lm9qU79nFr1qyxOu4PPvigzTq7du2yWic2NrYTWtq8pvalO31nSM8yYcIEfPnll0hKSsLXX3+NS5cu4aabbrI831s/m+fPn4fZbMZ7772HM2fO4I033sC7776LZ555xrJObz02rrh/Q0hv09w9MQCYOnWq1XnC559/3oEt7FwUo2ieM8cIABYvXmz1Oeq2A7MY6ZLi4uLY/fffb3lsMpmYn58fW7t2bSe2qmcAwL799lvLY7PZzHx8fNgrr7xiWVZaWsrEYjH7/PPPO6GF3V9+fj4DwPbu3csYqzueQqGQbd++3bLOuXPnGAB24MCBzmom6cE2bdrEVCqVzfJffvmF8Xg8lpuba1m2ceNGplQqmV6vZ4wx9uSTT7KYmBir191yyy1s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P/wwampqLOulpqaC4zhs3rzZZhscx2HVqlVWy7KysrBw4UJ4e3tDLBYjJiYGH330kdU6e/bsAcdx2LZtG5577jn4+/tDJpPh7bffxpw5cwAAEyZMAMdx4DgOe/bssbx2w4YNiImJgVgshp+fH+6//36nRmDW7+/Zs2dx2223QaPRYPTo0VbPNfbpp58iLi4OMpkMGo0GY8eOxe+//261TmvbQwghjvql8ePHY/z48Tbr26vBs23bNsTGxkKhUECpVGLAgAF46623LM/X1tZi9erV6NOnDyQSCTw8PDB69Gjs3LnTph0Nbdq0CRMnToSXlxfEYjGio6OxceNGl+4/IYTY46hv5DgOJ0+etKz39ddfg+M43HjjjVav79evH2655RbLY2f7s5CQEFx33XX4559/EBcXB4lEgrCwMHz88cc26545cwYTJ06EVCpFQEAA/vOf/9gdyPn9999j+vTp8PPzg1gsRnh4OF544QWYTKa2HCJCSAcqLy/HI488gpCQEIjFYnh5eeGaa67B8ePHLev8/fffmDNnDoKCgiAWixEYGIhHH33UZqahvXMujuPwwAMP4LvvvkP//v0t19C//fab1eueeOIJAEBoaKjlOtmZrGnHjh3DqFGjIJVKERoainfffdfqeYPBgBUrViA2NhYqlQpyuRxjxozBn3/+abVe/X2BV199FW+++SbCw8MhFouxYcMGDB8+HACwYMECS9sa3z84e/YsJkyYAJlMBn9/f7z88ss2bdXr9Vi5ciUiIiIsx/HJJ5+EXq9vdj9LS0vxyCOPIDAwEGKxGBEREXjppZes+uaG+/DOO+8gLCwMMpkMkydPRkZGBhhjeOGFFxAQEACpVIqZM2eiuLjY8vr58+fD09MTtbW1Nu8/efJkREZGNttOQkjLdNc+ePz48ejfvz9OnjyJcePGQSaTISIiAl999RUAYO/evYiPj4dUKkVkZCR27dpl9fq0tDQsXboUkZGRkEql8PDwwJw5c2zec/PmzeA4Dnv37sXSpUvh5eWFgICAZtvcuAZ4/Xb27duHZcuWQavVQi6X44YbbkBBQYHj/0GEkG6pub618f3HhudQ77//vuU8cPjw4Thy5IjN9rdv347o6GhIJBL0798f3377rd17mq+++ipGjRoFDw8PSKVSxMbGWvrJhur76q1btyIyMhISiQSxsbH466+/bNZNSEjAtGnToFQq4ebmhquvvhoHDx60WsdR31nv119/xZgxYyCXy6FQKDB9+nScOXOmJYeYtDNBZzeAdB8333wzQkJCsHbtWhw8eBBvv/02SkpK7N7sa05eXh5GjBhh6ZS0Wi1+/fVXLFq0CGVlZXjkkUes1n/hhRcgEonw+OOPQ6/XY/LkyXjooYfw9ttv45lnnkG/fv0AwPLfVatWYfXq1Zg0aRLuu+8+JCUlYePGjThy5Aj27dvn1OjFOXPmoE+fPvjvf/8LxpjD9VavXo1Vq1Zh1KhRWLNmDUQiEQ4dOoQ//vgDkydPdll7CCGkcb/05ZdfOvW6nTt3Yu7cubj66qvx0ksvAQDOnTuHffv24eGHHwZQ10+tXbsWd999N+Li4lBWVoajR4/i+PHjuOaaaxxue+PGjYiJicGMGTMgEAjw448/YunSpTCbzbj//vvbvtOEENKMhn1jSUkJTpw4gb/++gsDBw4EUHezk8fj4Z9//rG8pqCgAOfPn8cDDzxgWdaS/iw5ORk33XQTFi1ahPnz5+Ojjz7CXXfdhdjYWMTExAAAcnNzMWHCBBiNRjz99NOQy+V4//33IZVKbfZh8+bNcHNzw7Jly+Dm5oY//vgDK1asQFlZGV555ZX2OGyEEBe799578dVXX+GBBx5AdHQ0ioqK8M8//+DcuXMYOnQogLqbfFVVVbjvvvvg4eGBw4cPY/369cjMzMT27dubfY9//vkH33zzDZYuXQqFQoG3334bs2fPRnp6Ojw8PHDjjTfiwoUL+Pzzz/HGG2/A09MTAKDVapvcbklJCa699lrcfPPNmDt3Lr788kvcd999EIlEWLhwIQCgrKwM//vf/zB37lwsXrwY5eXl+PDDDzFlyhQcPnwYgwcPttrmpk2bUFNTgyVLlkAsFuOGG25AeXk5VqxYgSVLlmDMmDEAgFGjRlm1Y+rUqbjxxhtx880346uvvsJTTz2FAQMGYNq0aQAAs9mMGTNm4J9//sGSJUvQr18/nDp1Cm+88QYuXLiA7777zuF+VlVVYdy4ccjKysI999yDoKAg7N+/H8uXL0dOTg7efPNNq/W3bt0Kg8GABx98EMXFxXj55Zdx8803Y+LEidizZw+eeuopJCcnY/369Xj88cctA/rvvPNOfPzxx9ixYweuu+46y/Zyc3Pxxx9/YOXKlU3+/yCEtFx374Ovu+463HrrrZgzZw42btyIW2+9FVu3bsUjjzyCe++9F7fddhteeeUV3HTTTcjIyIBCoQAAHDlyBPv378ett96KgIAApKamYuPGjRg/fjzOnj0LmUxm9V5Lly6FVqvFihUrUFlZiWnTprWqzQ8++CA0Gg1WrlyJ1NRUvPnmm3jggQfwxRdfNHscCSHdhzN9qz2fffYZysvLcc8994DjOLz88su48cYbcfnyZUsc5Oeff8Ytt9yCAQMGYO3atSgpKcGiRYvg7+9vs7233noLM2bMwO233w6DwYBt27Zhzpw5+OmnnzB9+nSrdffu3YsvvvgCDz30kGUQ5tSpU3H48GH0798fQN1A9TFjxkCpVOLJJ5+EUCjEe++9h/Hjx1sGHjXUuO8EgE8++QTz58/HlClT8NJLL6GqqgobN27E6NGjkZCQYBPEJ52EEdKMlStXMgBsxowZVsuXLl3KALATJ04wxhhLSUlhANimTZtstgGArVy50vJ40aJFzNfXlxUWFlqtd+uttzKVSsWqqqoYY4z9+eefDAALCwuzLKu3fft2BoD9+eefVsvz8/OZSCRikydPZiaTybL8//7v/xgA9tFHHzm1v3PnznX4XL2LFy8yHo/HbrjhBqv3Yowxs9nskvYQQoijfmncuHFs3LhxNuvPnz+fBQcHWx4//PDDTKlUMqPR6PA9Bg0axKZPn+5UOxpq3DczxtiUKVNYWFhYk9sihJC2ctQ3xsTEsJtvvtnyeOjQoWzOnDkMADt37hxjjLFvvvnG6jyWMef7s+DgYAaA/fXXX5Zl+fn5TCwWs8cee8yy7JFHHmEA2KFDh6zWU6lUDABLSUlp8r3vueceJpPJWE1NTXOHghDSBahUKnb//fc3uY697/ratWsZx3EsLS3NsszeORcAJhKJWHJysmXZiRMnGAC2fv16y7JXXnnFpo9pyrhx4xgA9tprr1mW6fV6NnjwYObl5cUMBgNjjDGj0cj0er3Va0tKSpi3tzdbuHChZVn9fQGlUsny8/Ot1j9y5IjDewb17fj444+t2uHj48Nmz55tWfbJJ58wHo/H/v77b6vXv/vuuwwA27dvn2VZcHAwmz9/vuXxCy+8wORyObtw4YLVa59++mnG5/NZenq61T5otVpWWlpqWW/58uUMABs0aBCrra21LJ87dy4TiUSW/tpkMrGAgAB2yy23WL3P66+/zjiOY5cvX7bZf0JI23T3Pvizzz6zLDt//jwDwHg8Hjt48KBl+Y4dO2z6UHv7dODAAZv+dNOmTQwAGz16tM19gaba3Lgfrd/OpEmTLPc9GWPs0UcfZXw+36rPJIR0f831rY3vP9afQ3l4eLDi4mLL8u+//54BYD/++KNl2YABA1hAQAArLy+3LNuzZw8DYLVNxmz7OoPBwPr3788mTpxotRwAA8COHj1qWZaWlsYkEgm74YYbLMtmzZrFRCIRu3TpkmVZdnY2UygUbOzYsZZljvrO8vJyplar2eLFi63ePzc3l6lUKpvlpPNQCnTitMYzXx588EEAwC+//NKi7TDG8PXXX+P6668HYwyFhYWWvylTpkCn01mlKALqUojZmy1jz65du2AwGPDII4+Ax/v3I7548WIolUr8/PPPTm3n3nvvbXad7777DmazGStWrLB6LwCWdEmuag8hhDjTL9mjVqtRWVlplc7c3jpnzpzBxYsXW7Tthn2zTqdDYWEhxo0bh8uXL0On07WqvYQQ0hKN+8YxY8bg77//BlCXsu3EiRNYsmQJPD09Lcv//vtvqNVqywhwoGX9WXR0tGX2IlA3SyYyMhKXL1+2LPvll18wYsQIxMXFWa13++232+xDw/cuLy9HYWEhxowZg6qqKpw/f75Fx4MQ0jnUajUOHTqE7Oxsh+s0/K5XVlaisLAQo0aNAmMMCQkJzb7HpEmTEB4ebnk8cOBAKJVKq76nNQQCAe655x7LY5FIhHvuuQf5+fk4duwYAIDP50MkEgGom4VdXFwMo9GIYcOG2Vy/A8Ds2bObnUHYmJubG+644w6rdsTFxVnt3/bt29GvXz9ERUVZ3UuYOHEiANikZG9o+/btGDNmDDQajdVrJ02aBJPJZJMec86cOVCpVJbH9bOB7rjjDggEAqvlBoMBWVlZAAAej4fbb78dP/zwA8rLyy3rbd26FaNGjUJoaGiLjgshpHnduQ92c3PDrbfeankcGRkJtVqNfv36Wc1CrP93w/druE+1tbUoKipCREQE1Gq13b558eLF4PP5bWovACxZssQqTfyYMWNgMpmQlpbW5m0TQroOZ/pWe2655RZoNBrL4/pr5/r+Kzs7G6dOncK8efPg5uZmWW/cuHEYMGCAzfYa9nUlJSXQ6XQYM2aM3X5u5MiRiI2NtTwOCgrCzJkzsWPHDphMJphMJvz++++YNWsWwsLCLOv5+vritttuwz///IOysjKrbTbuO3fu3InS0lLMnTvX6pySz+cjPj6+yfNR0rEoAE6c1qdPH6vH4eHh4PF4TtUTa6igoAClpaV4//33odVqrf4WLFgAAMjPz7d6TUsuEOtPthrX1RKJRAgLC3P6ZMyZ97x06RJ4PB6io6PbvT2EENLam2VLly5F3759MW3aNAQEBGDhwoVWtcoAYM2aNSgtLUXfvn0xYMAAPPHEE1Y1dB3Zt28fJk2aBLlcDrVaDa1Wi2eeeQYAKABOCOkQjfvGMWPGICcnB8nJydi/fz84jsPIkSOtAuN///03rrrqKqvBiS3pz4KCgmzaodFoUFJSYnmclpZmc/4M2J4TAnUp2G644QaoVCoolUpotVpLEIj6UkK6h5dffhmnT59GYGAg4uLisGrVKpugSHp6Ou666y64u7vDzc0NWq0W48aNA+Dcd92Zvqc1/Pz8IJfLrZb17dsXAKyu97ds2YKBAwdCIpHAw8MDWq0WP//8s922t+a8NSAgwKbubuP9u3jxIs6cOWNzL6G+vY3vJTR08eJF/PbbbzavnTRpkt3XNj7e9cHwwMBAu8sbtnPevHmorq7Gt99+CwBISkrCsWPHcOeddzZ/IAghLdad+2B7fZ9KpXKqr6mursaKFSsQGBgIsVgMT09PaLValJaWuqxvtqfxsagPdLX1WBBCuhZn+lZ7musj6uMhERERNq+1t+ynn37CiBEjIJFI4O7uDq1Wi40bN9rt5+xdg/ft2xdVVVUoKChAQUEBqqqq7F6X9+vXD2azGRkZGVbLG/ed9ZOHJk6caHNe+fvvvzd5Pko6FtUAJ63W+OSs8eN6JpPJ6rHZbAZQN2p6/vz5dl9TX7OxnrOzv12pM96TEEKa0rhf4jgOjDGb9Rr3u15eXkhMTMSOHTvw66+/4tdff8WmTZswb948bNmyBQAwduxYXLp0Cd9//z1+//13/O9//8Mbb7yBd999F3fffbfd9ly6dAlXX301oqKi8PrrryMwMBAikQi//PIL3njjDUt/Twgh7alx3zh69GgAwF9//YXLly9j6NChkMvlGDNmDN5++21UVFQgISEBL774ouU1Le3PHM2csdcnN6e0tBTjxo2DUqnEmjVrEB4eDolEguPHj+Opp56ivpSQbuLmm2/GmDFj8O233+L333/HK6+8gpdeegnffPMNpk2bBpPJhGuuuQbFxcV46qmnEBUVBblcjqysLNx1111Ofddd2fe01Keffoq77roLs2bNwhNPPAEvLy/w+XysXbsWly5dslm/NdfTzuyf2WzGgAED8Prrr9tdt3HAqCGz2YxrrrkGTz75pN3n64PozbXHmXZGR0cjNjYWn376KebNm4dPP/0UIpEIN998s8P2EUJarzv3wW3pax588EFs2rQJjzzyCEaOHAmVSgWO43Drrbfa3SdX3evszN8jQkjHaa5vdcSVfcTff/+NGTNmYOzYsdiwYQN8fX0hFAqxadMmfPbZZy3eXms07jvr+9dPPvkEPj4+Nus3zBREOhf9nyBOu3jxotVol+TkZJjNZoSEhAD4dyRPaWmp1esaz3DWarVQKBQwmUyWkdat4SjgHhwcDKBuhHXDNBYGgwEpKSltes/GwsPDYTabcfbsWQwePLjT20MI6V00Go3dkZf2MkuIRCJcf/31uP7662E2m7F06VK89957eP755y2jK93d3bFgwQIsWLAAFRUVGDt2LFatWuUwAP7jjz9Cr9fjhx9+sBrdSal+CCGdKSgoCEFBQfj7779x+fJlS7q1sWPHYtmyZdi+fTtMJhPGjh1reU179GfBwcF2y0okJSVZPd6zZw+KiorwzTffWLUpJSWl1e9NCOkcvr6+WLp0KZYuXYr8/HwMHToUL774IqZNm4ZTp07hwoUL2LJlC+bNm2d5TVMlalrD0XVyU7Kzs1FZWWk1C/zChQsAYLne/+qrrxAWFoZvvvnG6j1WrlzZrm1rLDw8HCdOnMDVV1/d4u2Fh4ejoqKiw67B582bh2XLliEnJwefffYZpk+fbpUOlBDiWt21D26Lr776CvPnz8drr71mWVZTU2Nzb7YpHd1mQkj30lTf2lr18ZLk5GSb5xov+/rrryGRSLBjxw6IxWLL8k2bNtndtr1r8AsXLkAmk1nK88hkMpvrcgA4f/48eDxekwMqAVjKYXh5eVFsp4ujFOjEae+8847V4/Xr1wOApbNTKpXw9PS0qZu1YcMGq8d8Ph+zZ8/G119/jdOnT9u8T0FBgVPtqb84b3xSN2nSJIhEIrz99ttWo4o+/PBD6HQ6TJ8+3antO2PWrFng8XhYs2aNzcjK+vfuyPYQQnqX8PBwnD9/3qrfPHHiBPbt22e1XlFRkdVjHo9nybSh1+vtruPm5oaIiAjL8/bUj+hs2LfpdDqHJ6GEENJRxowZgz/++AOHDx+2BMAHDx4MhUKBdevWQSqVWtUFa4/+7Nprr8XBgwdx+PBhy7KCggJs3brVaj17720wGGzOoQkhXZfJZLJJwejl5QU/Pz/LuZS97zpjDG+99ZZL2+LoOrkpRqMR7733nuWxwWDAe++9B61Wa+kr7bX/0KFDOHDgQLu2rbGbb74ZWVlZ+OCDD2yeq66uRmVlZZOvPXDgAHbs2GHzXGlpKYxGY6vbZc/cuXPBcRwefvhhXL582aq+OSHEdbp7H9wWfD7fZkbl+vXrbbLCNaWj20wI6R6c6Vtby8/PD/3798fHH3+MiooKy/K9e/fi1KlTVuvy+XxwHGfVr6WmpuK7776zu+0DBw5Y1QbPyMjA999/j8mTJ4PP54PP52Py5Mn4/vvvrUr95OXl4bPPPsPo0aOhVCqbbP+UKVOgVCrx3//+F7W1tTbPOxvfIu2PZoATp6WkpGDGjBmYOnUqDhw4gE8//RS33XYbBg0aZFnn7rvvxrp163D33Xdj2LBh+Ouvvywjxxtat24d/vzzT8THx2Px4sWIjo5GcXExjh8/jl27dqG4uLjZ9gwePBh8Ph8vvfQSdDodxGIxJk6cCC8vLyxfvhyrV6/G1KlTMWPGDCQlJWHDhg0YPny4Sy86IyIi8Oyzz+KFF17AmDFjcOONN0IsFuPIkSPw8/PD2rVrodVqO6w9hJDeZeHChXj99dcxZcoULFq0CPn5+Xj33XcRExODsrIyy3p33303iouLMXHiRAQEBCAtLQ3r16/H4MGD0a9fPwB1aRrHjx+P2NhYuLu74+jRo/jqq6/wwAMPOHz/yZMnW2aW33PPPaioqMAHH3wALy8v5OTktPv+E0KII2PGjMHWrVvBcZwlJTqfz8eoUaOwY8cOjB8/HiKRyLJ+e/RnTz75JD755BNMnToVDz/8MORyOd5//30EBwfj5MmTlvVGjRoFjUaD+fPn46GHHgLHcfjkk08ohSQh3Uh5eTkCAgJw0003/T979x3fVL3+AfyTnTSrTXe6S4FSSguUDTIEGRcRBBWRqwgoonC9yr0qqKhcUa6KE/2Bk3kVRGW4QESmlNGWskcp3btN2zRps8/vj0KkdLdZTZ7368ULkpzxnEPz7Tnn+X6/DxITEyGRSPD777/j1KlT1lF5sbGx6NatG/7973+joKAAMpkM33//vc3rpd5MWL/00kt48MEHwePxMGXKlEY1vm+lVCrx1ltvITs7Gz169MC2bduQnp6Ozz77DDweDwBw991344cffsC9996LyZMnIysrC+vWrUNcXFyDB5ct6datG7y9vbFu3TpIpVKIxWIMHjy4XTVpH374YXz77bdYuHAhDhw4gOHDh8NsNuPy5cv49ttvsXfvXgwYMKDJdZ977jns3r0bd999Nx599FEkJSVBq9Xi3Llz+O6775CdnQ0/P782x9Iaf39/TJw4Edu3b4e3tzd1fifETrp6G9wZd999NzZv3gy5XI64uDgkJyfj999/h6+vr8vGTAjpGtrStnbGm2++ialTp2L48OGYO3cuKisr8fHHHyM+Pr7BteXkyZPx3nvvYeLEiXjooYdQWlqKTz75BDExMQ3uq2+Kj4/HhAkT8PTTT0MgEFg7lq9YscK6zMqVK7Fv3z6MGDECTz31FLhcLj799FPo9Xq8/fbbrcYuk8mwdu1aPPzww+jfvz8efPBB+Pv7Izc3Fz///DOGDx+Ojz/+uNPniNgAQ0grXn31VQYAc/HiRea+++5jpFIp4+PjwyxevJipq6trsGxtbS0zf/58Ri6XM1KplHnggQeY0tJSBgDz6quvNli2pKSEWbRoERMWFsbweDwmKCiIGTt2LPPZZ59Zlzlw4AADgNm+fXuTsX3++edMdHQ0w+FwGADMgQMHrJ99/PHHTGxsLMPj8ZjAwEDmySefZCorK9t8vGVlZc1+druvvvqK6devHyMQCBgfHx9m1KhRzL59+xos09F4CCGkpXZpy5YtTHR0NMPn85m+ffsye/fuZebMmcNERERYl/nuu++Y8ePHMwEBAQyfz2fCw8OZJ554gikqKrIus3LlSmbQoEGMt7c3IxKJmNjYWOaNN95gDAZDozhutXv3biYhIYERCoVMZGQk89ZbbzFfffUVA4DJysqy+bkghJCbWmobL1y4wABgevXq1eD9lStXMgCY5cuXN1qnre1ZREQEM3ny5Ebrjxo1ihk1alSD986ePcuMGjWKEQqFTEhICPP6668zX375ZaNt/vnnn8yQIUMYkUjEKJVK5vnnn2f27t3b6PqWEOKa9Ho989xzzzGJiYmMVCplxGIxk5iYyPzf//1fg+UuXrzIjBs3jpFIJIyfnx/z+OOPM2fOnGEAMOvXr7cu19Q1FwBm0aJFjfYdERHBzJkzp8F7r7/+OhMSEsKw2exWr8lGjRrF9O7dm0lJSWGGDh3KCIVCJiIigvn4448bLGexWJg333yTiYiIYAQCAdOvXz/mp59+anTdmZWVxQBg3nnnnSb3t2vXLiYuLo7hcrkNjvtmHLe7ffsMwzAGg4F56623mN69e1vvwZOSkpgVK1Yw1dXVLZ6bmpoaZtmyZUxMTAzD5/MZPz8/ZtiwYczq1aut173NHUNzzyfWr1/PAGBOnTrVKP5vv/2WAcAsWLCgyfNBCOk8d2iDm9puU9ebt8dRWVnJzJ07l/Hz82MkEgkzYcIE5vLly43iaqmdainmtm7nZvtI162EuI+2tK3tuQ5sKj+0detWJjY2lhEIBEx8fDyze/duZsaMGUxsbGyD5b788kume/fujEAgYGJjY5n169e32FZv2bLFuny/fv2abJvS0tKYCRMmMBKJhPHy8mLGjBnDHDt2rMEyrbWdBw4cYCZMmMDI5XJGKBQy3bp1Yx599FEmJSWlyeWJ47EYhoYWkJa99tprWLFiBcrKymzaG5oQQgghhBBCCCHEXe3atQvTpk3D4cOHrSU5CCGEEEJI0/r27Qt/f3/s27ev3euyWCwsWrSIRl8TK6oBTgghhBBCCCGEEEKIjX3++eeIjo62luMghBBCCCGA0WiEyWRq8N7Bgwdx5swZjB492jlBEbdDNcAJIYQQQgghhBBCCLGRrVu34uzZs/j555/x4YcfgsViOTskQgghhBCXUVBQgHHjxuHvf/87lEolLl++jHXr1iEoKAgLFy50dnjETVACnBBCCCGEEEIIIYQQG5k1axYkEgnmz5+Pp556ytnhEEIIIYS4FB8fHyQlJeGLL75AWVkZxGIxJk+ejP/+97/w9fV1dnjETVANcEIIIYQQQgghhBBCCCGEEEIIIW6BaoATQgghhBCP9cYbb2DYsGHw8vKCt7e3s8MhhBBCCCGEEEIIIYR0EiXACSGEEEKIxzIYDLj//vvx5JNPOjsUQgghhBBCCCGEEEKIDXhMDXCLxYLCwkJIpVKwWCxnh0MI6QSGYVBTUwOlUgk2m/rx2AO1mYS4D2ozW7ZixQoAwIYNGzq8DWozCXEv1G7aF7WZhLgXajPti9pMQtwLtZn2RW0mIe6ls22mxyTACwsLERYW5uwwCCE2lJeXh9DQUGeH4ZaozSTE/VCbaT/UZhLinqjdtA9qMwlxT9Rm2ge1mYS4J2oz7YPaTELcU0fbTI9JgEulUgD1J0omkzk5GkJIZ6jVaoSFhVm/18T2qM0kxH1Qm2l7er0eer3e+pphGADUZhLiLqjdtC+6ziTEvVCbaV/UZhLiXqjNtC9qMwlxL51tMz0mAX5zyguZTEaNHyFugqaysR9qMwlxP57UZi5duhRvvfVWi8tcunQJsbGxHdr+qlWrrFOn34raTELciye1m45E15mEuCdqM+2D2kxC3BO1mfZBbSYh7qmjbabHJMAJIYQQQohn+Ne//oVHH320xWWio6M7vP1ly5ZhyZIl1tc3e6QSQgghhBBCCCGEEEKcjxLghBBCCCHErfj7+8Pf399u2xcIBBAIBHbbPvE8ap0RR66WI8LXC3HBMpRp9NhzvhjBciHGxAaAx2E7O0RCSDuk5qgQGySDWECPXAghhLgns4XB5WI1VFoDTGYGJgsDk9lS/7fF0vi9G695HBYeu6PjnZEJIe6NYRhcKanBn9cqAABSIRcyIRcSAQ9SIffGn/p/C3kcJ0dLXB3djRFCCCGEEI+Vm5sLlUqF3NxcmM1mpKenAwBiYmIgkUicGxzxGCt/uohvU/IBAHwOGwazBQDwtz5BuCsu0JmhEUI64P19GThXUI05wyLx6LBIKMR8Z4dECCGEdIrRbMG5gmqczFLhxPUKpGRXokZvavd2fMV8SoATQhqoM5hxLLMcf1wuxcErZSioqmvTenwO25oUl4l46B/ug7/1CUZShA84bCozQCgBTgghhBBCPNgrr7yCjRs3Wl/369cPAHDgwAGMHj3aSVERT5OWW2X9983kNwDcFRdI9QEJ6YKyK7SorjPio/0Z+PzwdTw4KAyP3xENpbfI2aERQgghbaIzmnEmrwonslQ4maVCak4l6ozmTm+XTUkpQgjqO9XsSi/ET2cLkZxZAb3J0vpKtzGYLajQGlChNQAAzuZXY8OxbPhLBZjYOwiT4oMwKEoBLs2o5rEoAU4IIYQQQjzWhg0bsGHDBmeHQTxYncGMnAptk58t33kB/cN9EOErdnBUhJCOMpgsKLxl1Eqd0Yz1f2Zjy/EcTOsbgoWju6GbP80wQgghxLVo9Sak5VbeGOGtQnpeVYOOmbbCoc6dhHg0ndGMbafy8Nnh620e6d1eZTV6bD6eg83Hc6AQ8zGhdyAmxgdjWDdfKi/mYSgBTgghhBBCCCFOoNIa8N6+KzCamSY/N5gtVNeMkC4mv7IWlia+0kYzg+2p+fguLR8TewfhqdEx6BMqd3yAhBBCCIDqOiNSc+qT3SeyVDhfUA1TU7/AbIymJSbEM9XojNhyPBdfHr2Oco3BYftVaQ345mQevjmZB7mIh7viAjEpPggjuvtBwKV7bXdHCXBCCCGEEEIIcYK560/iTH51s58bzRas/PkSuGwW3rkvgaZuI6QLyKmobfFzhgF+PV+MX88X447ufnhydDcMjfalcgeEEELsymxhrDV2T2apcLFIDcb++e5GKAFOiGdRaQ3Y8GcWNhzLhlpncmos1XVGfJeaj+9S8yETcjFvRBTmDo+CXMRzalzEfigBTgghhBBCCCEOVqLW4UKhusVlGAb48UwhAGDRmG6ICZA6IjRCSCdkN1PSoClHMspxJKMcfcO88eTobrirVyDVRiWEEGJTl4vV2JFWgJ3pBShR650dDiXACfEQxdU6fH7kOr4+kYs6o9nZ4TSi1pnwwe8Z+PJoFuYNj8K8EZQId0eUACeEEEIIIYQQB2IYBq/sOt+uaSaPZVZQApyQLqC1EeBNSc+rwhObU9E9QIKFo7phckIwlT8ghBDSYaU1OuxOL8T3aQW4VNRyh0tHowQ4Ie4tt6IWaw9l4vvUfBjMFmeH06oanQkf7s/AV39SItwdUQKcEEIIIYQQQhyEYRis/PkS9l4oadd6a/64hnv7hUAqpJtxQlxZTjtGgN8uo1SDf20/g39/dwbBMiGi/MWI9BUjyu/G3/5ihPl4gc+lcgiEEEIaqjOY8dvFYnyfVoCjGWVwQDnvDuFQyQ9CnEpnNCOzTIP8yjr4SwUIV3jBV8zvcDkerd6EvMpaFFbWYfeZQuw+U+iy7U9LKBHunigBTgghhBBCCCEOYLYweHnnOXxzMq/d65bV6LEpOQeLxsTYITJCiK10ZAT47RgGKKzWobBahz+vVTT4jM0CQn28EOknRpSvV31y3K8+SR7iLQKXQ8lxQgjxFGYLg+PXK/BDWgH2nC+C1uB60wzfjkaAE+J4h66WYcvxHGSU1CBXVdsoQS3icRCmECFc4YVQHy+EK7wQpvBCmEKEIJkQ5Ro98irrkK+qRX5lHfIqb/ytqkVlrREA0D1AjIzSjncEdRWUCHcvlAAnhBBCCCGEEDuqqjUgJbsSG45l4+i18g5v59uUPDw6LBJiAd3GEeKKzBYGeZWdT4C3xMIAuapa5Kpqcfi2z3gcFsIUXojyrU+KR/qJEX3j72CZkOqLE0KIm7haUoMf0gqw83QBitU6Z4fTLpQAJ8RxCqvq8PpPF/Hr+eIWl6szmnG1RIOrJZoO70viZveo1kT40SwsHN0Nfx8cAbkXJcK7Gvf6qSSEEEIIIYQQFzNvwymk5VZ1ejs5FbVQaQ2UACfERRVW1cFodt6cj0Yzg+tlWlwvazz6RsBlI8LXyzqV+s0keZSfGAFSQYenvSSEEOIYZTV67D5TiB/S8nGh0LXqercHdcYixP6MZgu+OpqFD/dnoNZBM0Pw3LREj8FswQ9p+Vh3MBNzR0Rh/vAoSoR3IfTkhBBCCCGEEELsRGc0Iz2vyibb4rJZ8KabbUJcli2mP7cXvcnS7MgeLz7nr1rjfvVJ8ugb9ccVnagJSQghpPP0JjNW772Cr/7MhrkrFta9DZcS4ITY1fHrFVi+8zwySjs+mrsjmK7fPDUpLliK03nVAICP9mdg/dEsSoR3Ie7ZLYMQQgghhBBCOimjpAYPf3kCnxy41uFtXCvVNKqx1lEmC4O560/hWGY5GHd9wkDa5PDhw5gyZQqUSiVYLBZ27tzZ4HMWi9Xkn3feeafZbdbU1OCZZ55BREQERCIRhg0bhlOnTlk/NxqNeOGFF9CnTx+IxWIolUo88sgjKCwstNdhdjnZFV2z7mGtwYyLRWr8fK4InxzIxHPfncWMtclIWvk7Elb8hns+Pop/bj2N9/ddxc7TBUjPq0L1jXqPhBBC7OdqSQ2mfXIMnx/JcovkNwBwqFMVIXbz2eFMPPjZcYcnvwGgzkEjzR1pcJTCmvy+qUZvwkf7MzDirT/w3r6rdE3s4mgEOCGEEEIIIcTjMQyDA1dKkZpTiXilHBPjg7B813kcv67CkYxy9AyUYlxcYLu2WV1nxJo/MmwaZ0pOJR76/ASGRvti3cNJkIuo17kn0mq1SExMxLx58zB9+vRGnxcVFTV4/euvv2L+/PmYMWNGs9t87LHHcP78eWzevBlKpRJbtmzBuHHjcPHiRYSEhKC2thZpaWlYvnw5EhMTUVlZiX/+85+45557kJKSYvNj7IpyVa47AryjanQmnM2vxtn86kafKcR8RPp61U+lfmNq9ZsjyalUAyGEdBzDMNh4LBurfr0Mvcni7HBsimqAE2IfXx7Nwpu/XHba/ovVOqftuy2EPDa8+FwYTBZoDaYmR6zLhFwoxHxIhTyI+BycyFI1u72biXAaEe7a6I6EEEJczOHDh/HOO+8gNTUVRUVF2LFjB6ZNm2b9nGEYvPrqq/j8889RVVWF4cOHY+3atejevbt1GZVKhX/84x/48ccfwWazMWPGDHz44YeQSCROOCJCCCHEteVUaLHsh3M4lllhfS8mQIJrt/ScX/rDOST39AeP0/okWleKa7DuUCZ+OVdkt4eWydcrMPXjo5g3IgpTEpTwEfPtsh/imiZNmoRJkyY1+3lQUFCD17t27cKYMWMQHR3d5PJ1dXX4/vvvsWvXLowcORIA8Nprr+HHH3/E2rVrsXLlSsjlcuzbt6/Beh9//DEGDRqE3NxchIeHd/Kour7s8q45AryjVFoDVFoD0nKrGn3mLxXUJ8X9btYar0+UR/qKIeRxHB8sIYR0EaU1Ojz/3VkcvFLm7FDsghLghNjexmPZeP2ni07bv1TIRbnG4LT9N8VPwoevWIByjR5qnRE6owU6418xCrlseAm4EN24Lq3Q6KHWmaDWmdq1H0qEuzabJ8BbS9xoNBosXboUO3fuREVFBaKiovD0009j4cKFzW5zw4YNmDt3boP3BAIBdDrX7lVCCCEd0dqInrfffhsfffQRNm7ciKioKCxfvhwTJkzAxYsXIRQKAQCzZ89GUVER9u3bB6PRiLlz52LBggX4+uuvHX04hBBCiMuorjXil/NFSMmuhFjAAZvFQnaFFn9eK4fR3LAL+LXbpo0r1+hxvUyLnkHSZrdvtjB485dL+O1CMfIq6+xyDLfKrqjFK7su4PWfLmJsbCBGdPfD+N6BCJAK7b5v0nWUlJTg559/xsaNG5tdxmQywWw2W68lbxKJRDh69Giz61VXV4PFYsHb27vZZfR6PfR6vfW1Wq1ue/BdDM3q+peyGj3KavQ4md145IxSLqxPhvuJEX0jKR7pJ0a4wgt8LlXqI4R4rt8vluD5789CpXWtRJItsSkBTohNbTmeg1d3X3BqDKHeIlwqrnFqDLfyk/DB57JxpaT5mHQmC3Qm27W1lAh3TTZPgLeWuFmyZAn++OMPbNmyBZGRkfjtt9/w1FNPQalU4p577ml2uzKZDFeuXLG+ZtGdJSHETbU0oodhGHzwwQd4+eWXMXXqVADApk2bEBgYiJ07d+LBBx/EpUuXsGfPHpw6dQoDBgwAAKxZswZ/+9vfsHr1aiiVSocdCyGEEOIKGIbB9tR8vLb7Amo7UZussrblG+TvUvPw5dEs9FbKwKmqg9lBpRqNZgZ7LhRjz4VivL3nMk69PA4CLo2wJPU2btwIqVTa5P35TVKpFEOHDsXrr7+OXr16ITAwEN988w2Sk5MRExPT5Do6nQ4vvPACZs2aBZlM1uy2V61ahRUrVnT6OLqC+5PCsPdCibPDcHmF1ToUVusazLoBAGwWEOIjQpSfBFE3pla/mSQP8RaB24YZOAhpij0G61y4cAGvvPIKUlNTkZOTg/fffx/PPPNMo+U++eQTvPPOOyguLkZiYiLWrFmDQYMG2eEoSVf3yq7z2JSc4+ww7I5LCXBCbGbryVy8vPO8s8OAVOg6E03fTH4XVjln8OzNRPjp3Er0C/PG/BHRlAh3Ipv/ZLY2FduxY8cwZ84cjB49GgCwYMECfPrppzh58mSLCXAWi9VoGjdifwaTBak5lTicUYYLhWrw2CwIeGwIuBxIBFxMSVRiYKQPdUggxEGysrJQXFyMcePGWd+Ty+UYPHgwkpOT8eCDDyI5ORne3t7W5DcAjBs3Dmw2GydOnMC9997baLueNDKHEEKIZzGZLXj++7P4Ia2g09sqrGp6VHe5Ro+P9mdY93GhUI1BUQqcbKFmmL2odSZcL9OiV3DzCUniWb766ivMnj270eju223evBnz5s1DSEgIOBwO+vfvj1mzZiE1NbXRskajEQ888AAYhsHatWtb3O6yZcuwZMkS62u1Wo2wsLCOHYyLG93TH8FyIYqqaba6jrAwQJ6qDnmqOhy+7TMum4VwxV/TqEf519cdj/TzglIuohGFpEX2GKxTW1uL6Oho3H///Xj22WebXGbbtm1YsmQJ1q1bh8GDB+ODDz7AhAkTcOXKFQQEBNj0GEnXlltR6xHJbwBg0zNkQmziSEYZlu045+wwbnCN77WPF8+pye+bEkLlOJJRjiMZ5Vj/ZzbmDo/EvBFR8PaismWO5vCuGcOGDcPu3bsxb948KJVKHDx4EFevXsX777/f4noajQYRERGwWCzo378/3nzzTfTu3bvZ5SmZ0zmVWgOe//4s/rxW3uIomc3Hc9ArWIbZg8MxOEqBaH8J1XIhxI6Ki4sBAIGBgQ3eDwwMtH5WXFzc6Gaay+VCoVBYl7mdJ43MIYQQ4jksFgbPf3cWP5zufPIbAL44koXxvYMgEdTfRtUZzPjqzyysPZgJjb5hrbAzeVUIlgtQVK1valN25cWn0d+k3pEjR3DlyhVs27at1WW7deuGQ4cOQavVQq1WIzg4GDNnzmxUN/xm8jsnJwd//PFHi6O/gfryZQKBoFPH0VVwOWzMHBiGD37PcHYobsdkYXC9XIvrTdRZ53PZiPT1qk+M3xg1HukrRrS/GAFSAXXYJ3YZrDNw4EAMHDgQALB06dIml3nvvffw+OOPW8s6rlu3Dj///DO++uqrZtchnunAlVJnh+AwNJmH52ht9o2W/Pnnnxg1ahTi4+ORnp5u1zi7qo/2Z4Bx0IxjrTFZLM4OAQDQPVDqlE7otwqSCZBV9tf1ao3ehI/+uEaJcCdxeAJ8zZo1WLBgAUJDQ8HlcsFms/H5559j5MiRza7Ts2dPfPXVV0hISEB1dTVWr16NYcOG4cKFCwgNDW1yHUrmdJzZwuDpradxJKO8TctfKlJbp9oQ8TjoFSxFfIgc8Uo54pQy9AiUNqrjpdGbUFBZh/zKWuTf8reQx0H/cG9MiA9qVLuQYRjkV9ahRK1DuUaPco0B5Ro99CYLlHIhuvlLMDBKAV4nr6QsFgblWj38JXSjTDyHJ43MIYQQ4jnWHsq0WfIbAC4WqTH146MY3zsIlVoDfrtY0myNRr3JgmC5yOEJcKVciDAfL4fuk7iuL7/8EklJSUhMTGzzOmKxGGKxGJWVldi7dy/efvtt62c3k98ZGRk4cOAAfH197RF2lzZzYBg+2p8Bi4s8kPQEBpMFV0s0uFqiafSZF5+DCF8xovy86pPjtyTJfcV8uucnADo+WKclBoMBqampWLZsmfU9NpuNcePGITk52RZhEzfyx2XPSYBz2ZQB9xStzb7RnKqqKjzyyCMYO3YsSkqotExTUnNUOJVd6ewwrAwm10iAV9canR0CQny8kJrT+P/mZiL8qxuJ8PmUCHcIpyTAjx8/jt27dyMiIgKHDx/GokWLoFQqG0zpe6uhQ4di6NCh1tfDhg1Dr1698Omnn+L1119vch1K5nTcvovFbU5+367OaEZabhXScqus7/E5bPQIkiBYLkJxtQ75lbWobKEx2nG6AK/svoBBkQoMiPQBCyycL6zGmbyqFtcDAIWYjzE9A1BVa0CF1gA2q35qHTabBTar/vM7uvtjZA9/hHiLYDBZkFFagwuFaly8+adIDY3eBKVciNGxARjdwx/DY/wgFjT8uhhMFqTnVSFYLkSYgh4yEse4WQqipKQEwcHB1vdLSkrQt29f6zKlpQ1vnkwmE1QqVbOlJDxpZA4hhBDPcL1Mg4//uGbz7WaWabH2YGablj2TXw0/CR/lmpZrh9tSkVqHlJxKDIpSOGyfxPE0Gg2uXfvr5zsrKwvp6elQKBQIDw8HUH8PvH37drz77rtNbmPs2LG49957sXjxYgDA3r17wTAMevbsiWvXruG5555DbGysdeSi0WjEfffdh7S0NPz0008wm83W2YUUCgX4fHqAAwDBchHujA3E75foga0rqDWYcalIjUtFjWcFlAq51qR4pN/NJLkEUb5iqtXoYToyWKc15eXlMJvNTc7edvny5WbXoxktPU+dwYzk6xXODsNhquucn6AijtHa7BvNWbhwIR566CFwOBzs3LnT9oG5gbUHrzs7hAZqjc3PIOwo3l48XCmpcWoMUgEH5wqqW1xGozdhzS0jwikRbl8OTYDX1dXhxRdfxI4dOzB58mQAQEJCAtLT07F69epmE+C34/F46NevX4Mb/ttRMqfjbF2LxWC24HyBGucL2n7RzjDAiSwVTrRzygqV1oDv0/JbXOaXc/UPaZRyIco0ehjNTXfNL6zW4esTufj6RC74HDYGRSkwuqc/BFw2Dl0tR3JmObQ3poePDZJiXK9AjIsLRK3ehJ3pBZg9OAKJYd4AgGulNejmL8Gf1yrA47CQFOEDLs35QzogKioKQUFB2L9/vzXhrVarceLECTz55JMA6jsNVVVVITU1FUlJSQCAP/74AxaLBYMHD3ZW6IQQQojd5FRo8eruC8hT1aLOYEad0YwanQlJET7tvp60JbOFQbSfBFF+DNJyKtHMZadNMQyw+Os0fP/kMOqk6cZSUlIwZswY6+ubnb/nzJmDDRs2AAC2bt0KhmEwa9asJreRmZmJ8vK/Oj5XV1dj2bJlyM/Ph0KhwIwZM/DGG2+Ax6tPBBYUFGD37t0AYL0OvenAgQPWqYMJMHtwOCXAu4AanQln86txNr/xg0ofL96NpPjNWuN/jRyXCBw+loTYWUcG69gLzWjpeY5llrvM6ElHSM+rgtnCUAlN0qT169fj+vXr2LJlC1auXNnq8p7YaehqSY3LXWcaXaANC1d4oaq25eSzvfVSyts8BfutifCHBofj3n4h6BXccmkp0n4OvWo3Go0wGo1g3zbVCYfDgaUddQLMZjPOnTuHv/3tb7YOkQCI8hODxYLL1JCwl8JqXZuXNZgtOHqtHEevNT0y/nJxDS4X1+DjA391yjhwpQz/e2ww9p4vxqbjOTj54lgMiPTBU/9LQ2pOJUb39MfYXoEY1d2/Ue/ytNxKfPh7BhJC5RgS7YukCB8IefW1HDV6E6rrjAjxFnXgqElX0NqInmeeeQYrV65E9+7dERUVheXLl0OpVFrr6PTq1QsTJ07E448/jnXr1sFoNGLx4sV48MEHoVQqnXRUhBBCiH0wDIN/bz/T5BRwJ7NU6BMiw7l2dMS0tZPZKvQP93ZI8vum0ho9/rvnMj55qL/jdkocavTo0WBauWFbsGABFixY0Ozn2dnZDV4/8MADeOCBB5pdPjIystV9kno3ZxwrqKpzdiikgyprjajMrcLpW2a3u8lfKriRFPdCpJ8Y0bfUHb953066DlsN1rmdn58fOBxOo+l7S0pKmp2ZDaAZLT2RJ9X/Buqfa14prkGckhI9pKGMjAwsXboUR44cAZfbtrSVJ3Ya+uZkrrNDcEln86vRP9y7wczEjlbcjnzTTRq9CZ8dvo7PDl9Hz0Ap7umrxD2JSurMbiM2T4C3lrgZNWoUnnvuOYhEIkRERODQoUPYtGkT3nvvPes6jzzyCEJCQrBq1SoAwH/+8x8MGTIEMTExqKqqwjvvvIOcnBw89thjtg6fAOgeKMWDA8Pwzck8Z4fSpZXV6DH+/cMAAC6bhZd2nsczY7tj3d+T8Paey9h8PAe70gsBAN38xbijuz/6hXtDXWfEJwcyUazW4dDVMqz54xqEPDYGR/miX7g3tp3KQ1G1DtP7hWDeiCjEBklpNLmbaW1Ez/PPPw+tVosFCxagqqoKI0aMwJ49eyAUCq3r/O9//8PixYsxduxYsNlszJgxAx999JHDj4UQQgixt+TrFc3WP2MAZJZqMChSgevlGlRoDU7p5MlzwrXa0YxyGl1DiJNw2Cw8ODAM7+676uxQiB2U1ehRVqPHyezGI3yC5cL6OuP+t44c90KYwgsCLiXH9y1lfAABAABJREFUXZGtBuvcjs/nIykpCfv377d2VrdYLNi/f7+19ERTaEZLz8IwDA5cLnN2GA6XmqOiBDhpwGw246GHHsKKFSvQo0ePNq/niZ2GTjVx/UHqnc2vRm+lDBcKHd8BPspPjKxybae2caWkBu/svYJ39l7BgAgfTO2rxOQEJRRimiK9o2yeAG8tcbN161YsW7YMs2fPhkqlQkREBN544w0sXLjQuk5ubm6DC8/Kyko8/vjjKC4uho+PD5KSknDs2DHExcXZOnxyQ49AqbNDcCsmC4OvT+SCBeCNe/vg5bvj8OTobrhQqMYz29KRWaZFZpkWG441vb7OaMGhq2U4dPWvi+IfThfgh9MFEPLYSIrwwZOjYjA8xhcsG09hTxyvtRE9LBYL//nPf/Cf//yn2WUUCgW+/vpre4RHCCGEuJQ1+1uu811rtFiTFDwOCz2DpDCZGZRr9NAbLajRm+weY2Wt42qA31RdZ8Thq2UYExvg8H0TQoAHBobhg/0ZMFto1LwnKarWoaha16ieL5sFbJ4/GMNj/JwUmWezx2Adg8GAixcvWv9dUFCA9PR0SCQSxMTEAKh/JjpnzhwMGDAAgwYNwgcffACtVou5c+c68OiJK8so1XjkbCEpOZV4eGiks8MgLqSmpgYpKSk4ffq0tZOQxWIBwzDgcrn47bffcOeddzZaz9M6DWn1Jlwqcm6da1dmsjC4XqZFjL8Y18o6l4xuLz8Jv9MJ8Ful5FQiJacSK368iDu6+2FavxCM6xUIMZXiaRebn63WEjdBQUFYv359i9s4ePBgg9fvv/8+3n//fVuER9ooV1Xr7BDc0nep+bijux84bDaOZZbjwOVSqLSdeyCqM1rw57UK/HmtAk+O7obnJ/RETkUtUnIqcV9SqI0iJ4QQQghxPRv+zGqUZGiJ0czg/C3ToUcoRA5JgF8t0aB7gAQZpRq77+tWL+88jznDIiAV8jBrULhD902IpwuUCTGuVwD2XnCtGo3EOSbFB1Py24nsMVinsLAQ/fr1s75evXo1Vq9ejVGjRlmfa86cORNlZWV45ZVXUFxcjL59+2LPnj0IDAy08xGTruLAZc+a/vym1JymZ28inksmk+HcuXMN3vu///s//PHHH/juu+8QFRXlpMhcy5m8Kupc2Yo6oxkGR9Yfs7LPoESThcGBK2U4cKUMIh4Hd8UFYlo/Je7o7u+Umea6GuouQBrQm8xY+dMlbD6e4+xQ3JLeZMHCLWl22/7ag5nIqdDidG4Vnp/YE6/sOo+Hh0SgO43oJ4QQQogbMVsYrPrlEr44mtWp7ZRrHDcyu0ZvgsKLD5UDR4MXVNXhzV8uY0CEDyXACXGChwZHUAKcQCHmY8XU3s4Ow6PZY7BOZGRki9u8afHixS1OeU482x8emgDPr6xDiVqHQJmw9YVJl9Xa7BvLli1DQUEBNm3aBDabjfj4+AbrBwQEQCgUNnrfk7lq5xGZiAdUus5sFrmqWvQL98ZpB9YDr66z/31+ndGM3WcKsftMIaQCLvqGe2NkDz/EBsnQN8wbUiHP7jF0NZQAJ1apOSq8vPMCLhU5vkYCsZ1fzhUDAJ7ddgYAcDJLhZ2LhkPIo3pjhBBCCOn6zBYGT2xOwe+XOv/AsM5otkFEbVNcrUNskBRVdQY4utO+iE/XgYQ4wx0xfgj1ESHfhR4IEsf7z9Te8JN4zvSshJC2UeuMSHHRZJYjpGRXYnJCsLPDIHbU2uwbRUVFyM3NdVZ4XVJqrmu2GeU1ekgEXGgcMLtaW1U4sLM7AOSpHHu9X6M34UhGOSo0BlwsugwWC+gZKEVShA+SInwwIEKBMIXI48vlUgLcw9UZzPjxTCG+PpmL9LwqZ4dD7OBycQ0e/Ow4nhzdDbvSCzA+LgjT+oU0Wq6gqg5Lvz+Lp0bHYGg3XydESgghhBDSuq9P5Ngk+Q0AFgZgsYA2DOCyicvFNRgUqbDWJHeUKD+xQ/dHCKnHZrMwa1A43tl7xdmhECeZFB+EyX0owUMIaezI1XKPnso4JUdFCXA319rsGxs2bGhx/ddeew2vvfaabYPqwiwWBmku2mmmpEaPfmFynM6rdnYoVrmqWiSEyHG2wL4xxQZJoRDzcSyz7aXZbKVXsBQXbwxmZZj65w2Xi2vwvxP1HUv8JAIkRXgjKcIHd8UFeeRzAUqAe6DqOiOOZpTj8NUy/Hq+CGqd6/TMIfaRnleFJzanAqgfIX78egXmj4hCmMILQh4HB6+U4rnvzqKsRo9n7+rh5GgJIZ7CaLaAx2GDYRhU1hqRV6GFSMBFmI8IAAsmiwV6k6XDI2bMFgZagwkSPhfVdUZU1RkR6evl8b0fCenKtHoTPtyfYdNtOir5fdPJbBUGRvrgVLbjHl50D5A4bF+EkIbuHxCK9/ddhcmDkxyeyseLh/9MjadrT0JIkw5c8czpz29y1amcCXFV18o0Lp3HOZ1X7fD73NbYayY0uYiL2CAZ8lS1uFxcg9ggx5ef5bJZsFhaXqZco8feCyXYe6EEb/5yGUkRPpjRPxSTE4IhF3nGdOmUAPdA//31Mr45SdOLeLKtp/Kw9VQeAMBfKkBZjR4AwGGzEBcsc2ZohBA3V67RI7tcC53RDKOZwYAIb2j0JpRpDCjXGuDHAtJyKxEkE4LNZsO7hQuyWoMJQi4HNToT5F6Nl+OwWTCZLfj0cCZScyqhN1nQK0iKHkFSTOsbAgYAj8O249ESQmzt08PXbVq3m89hwWB2fFKqstbo0P11owQ4IU4TIBXirrhA/Hq+2NmhEAd77Z7e8JfS1OeEkMYsFgYHr5Q5OwynulCoRq3BBC8+pScIaYuu0GkkJbsS/cO9kebA2tst0ZtsW/LsZuL7bH41TmT9Naubl4NLjsmEXCi9RbhcXNOu9VJzKpGaU4nXfryA8XGBmNE/FHd09wPXjZ+N0m8YDzS1r5IS4MTqZvIbAGL8JVQrnBBiV34SQaMR3VIRH8HeXu3e1s0b5aaS3zcpxAI8OToGap0ROeW1KFbrwDAM1h3KREapBnHBMtzbLwRefC4kQrosIsSVXSvVYN3BTJtu02BmMChSgdIaHdQ6E1Rax9QJ82mh3bKH0A60sYQQ23locDglwD3M+LhA3JOodHYYhBAXdb6wGuUafesLujGzhcGZvGoqw0hIG+iMZqz/M8vZYbSKAXA6t8plkuC27DzfJ0SGa6XaBonvmxw5uCbMRwQzw7Q7+X0rg8mCn84W4aezRXhocDjevLePDSN0LfSk1wMNjlJgQu9A7L1Q4uxQiIvpHWLf0d8Mw+Df28+itEYHXzEfvZVyDI5WICHU2677JYR0PaVqHYwWBoVVdUjJrkSkrxcmtbN+4s0p1gFAwufCT8JHd38xymsNqDWY8dPZIuy9UIyj18pxd4IS9ZfqQISvFwZEKDrcA9JsYcBCfV3hW6e8ZBgGBrMFAi4HFgsDNpumwySkrRiGwUs7zsFgbmWOrw44ma1Cb6UMxdU6DIpSwGS24HJxDWoNtu0tfiut3rFT1/1wOh/PjKMyN4Q4y/BufghXeCFXVevsUIgDyEU8rLyXpj4nhDStUmvAO3uvODsMl5Cao6IEOCFt8N9fL+NqicbZYbSJqyTBWSxA6S1EfmVdp7fVJ0SGy8U1MDYze5zFQXXV+oZ541pJDTQ2fFbx9Ylc3NsvBAMjFTbbpiuhBLgHYrFYeH1aPI5klNv1wR7pekK8RXbdPovFwjPjumPOVydxJKMcO9MLAQCDIhV4aXIvJIZ523X/hBDXVVVrwJbjOTh0tQxCHgcjYvzQzV+CUIUIc4ZFtDotms5oBp/DBosFlNbosO9iKS4UVqOwSoei6jpcL9OCd+NzndGMW8twHskox5GMcgD1NXTilDK8+LdeGBLdvhtxi4VBZZ0BL3x3DiaLBQoxHwkhcoT4eCEhRIb0/GoIuGwkRfhAIqBLMELaY3tqfpM9rW1FIuBCZ7Lg5I19DI5S2HV/V0s0EPM50DroWrywqvM3/YSQjmOzWZg1KBxv7bns7FCIA7x2TxwCpEJnh0EIcUEp2So8/c1pFFbrnB2KS0jpAlM6E+Jsh66WYcOxbGeH0S4MgLTcKrvfVzfHi89BjL8EJ7M638a0lvwGABbs1+lRzOegt1KOgqpapOdV2WUfS78/i9+eHQWOGw7UoaevHipAKsTjd0Tjw/0Zzg6FuBBHJGTCFF747slhmL/xFE7nVmFYN18cy6zA45tSsPeZkfAR8+0eAyHEdTAMgwOXy/DNyVyIBRy8e39fhPs2PVVvdrkWfA4LSh8v1NQZweOwwOdyUGswYVtKPlRaPYxmBpVaA34+V9Sok5fJ0nSiSSrkItpfglAfEUK8RajUGnAmrwrHr1eAx2GjZ6AUCaFySIRcHL9egYuFagTKhFB6izA8xq/BtsR8Lr6YMwDqOiMOXy2DtxcfI7rXLzNBbt9ORoS4qwqNHm/+csmu+7i9x3ZKtgrRfmJcL9d2aruhPiIEyYW4WlIDdd1fo75NFga9AyQ4k1/dqe231V1xQQ7ZDyGkefcPCMV7+660+PCMdH3jegVgWt8QZ4dBCHExFguDdYcz8e5vV2G20O+Bm9JyKml2NEJaUKHR49/bzzg7jA47kaVC/3BvnC9Uw2Cy/WxuTQmSCSHgsnG2oPP32jH+4laT30D9rHKDohQ4la2CLQeDD4j0wcWCapzMtm8ngpgAiVsmvwFKgHu0x0dGIy23EinZlagz0khwAogdNCJRIebj68eGYMHmFIQrvNAzSIpwhRf4XMfVyyC2lVNRP7pWaedZBIj72XgsG6t/u4oRMX54f2bfJqeKNJgs+CEtH0t/OAeZkIv/m52E3y4UYUqiEjtOF4DPZaOy1ojrZVqc68AFrkZvwpm8KpzJq4JUyEWkrxe+T8tHa88lwhVe+O7JoZAIuLhQqEagVAi1zgAvPhe/ni/GV0ezwGazEOYjQp8QOcq1BsQr5Zg5MAyKTnb2MVsY1BpMkAodW0eYEGdYezATVbVGu+7j9ptUM1Pfa13AZUPfwRt1hRcfQTIhUrIroRDzkBgmx5m8v9ooAY/TiYjb53KRGnfFBTpsf4SQxvwkAozvHYSfzxY5OxRiJzIhF2/c24emPieENFCu0WPJt2dw+GqZs0NxOWqdCdfKNOgRKHV2KIS4HIZhsPSHcyir0Ts7lE5Jy61CN38xquuMNq3JfTsum4X+ET64VFiNYrVtcl0yEa/NnVdPZtWXVsuvrEN1nY2eXzBArdG+HQeEPDaW3x1n1304EyXAPZhEwMXm+YNhMltwvVyLTcnZ2HI819lhESdyVE8sABDxOXh/Zl88/c1pfP34EIftl9gHmx7yeDyGYVBnNEOrN8NfKmjzeg8PjcSQaF9cKlbjUlENhDw2dEYz/CQCyL14EHA5OHC5FEt/OAeg/gaZxQK2pxbgm1N5kAl5iPT1wvlCNUb18O9QAvxm4itcIYKfRIDCKl2ryW8AyFXVYvJHRyETcpFZ9tcoURarYTKtrEZvrXv089kivLXnMhLDvKE3mlFZawALLHQPlGDt7P4QcNkwWerbyDqDGfmVtWCzWajUGuDtxQOLxYJSLkKN3ggumzoNEfen1ZuwLSXP7vtpqrdzVrm2Q3XLkiJ8kFOhRbnGAFVO/Q2+SmuESluNpAgfXClSg8VmQaOzb1L/Vh1pGwkhtjd7UDglwN3YK1N6I1BGU58TQv5y/HoFnv7mNEq7eALLnlKyKykBTkgTtp7Kw76LJc4OwyYyy7RQePHQM0iKK8U1Nt9+3zA5Smv01pJmtiAXcdt9H32hUI0AqQB9w7xxobC6S8z89I87uyPUp+mZON0BJcAJuBw2egRKsXRSL/x0tsjuI2yI67pcrHbo/vwkAqydneTQfRL7SMlRwVcsgELMh9CBI9qIazBbGCzYlIKDV8sgF/EQpvCCt4iHYd18MTE+COEKL7BYLFwprkFhVR1G9fDHT+eKEOXrhYIqHdQ6I/wkfJwvqEaOSguGAf7vYCY4LGB6/1DIRFzMGRqBjck5AICCyjpMig/CxSI1WCwWMsu1CPMRIauDUxWzWUC0vwTXSjXIVbWvTm5Zjb5Rb9y2THd05ra6PSaLBY9vSgVYDJIzVdYZMQZG+MBXIsDuM4UNlg9TiLDq3gTr9OqEuKsjGeWo0ZlaX7CTTJamOwGm5VZhYKQPCqt1KKisg4jPgUTAbfS9jwuWQSzggAXgVE5ls+1Aak4l+Fw2BoZ548/MChsfRfPc+YaWkK5kaDdfRPmJO3zNQlzXmJ7+mNGfpj4nhNQzWxh8cuAaPvj9aps6V3uylBwVHhoc7uwwCHEp18s0+M+PF50dhk2pao2orjNiYKQPTmV3vjY3UD8zoxefg/Q823f4jg2Sdah+eWmNHqU1ekj4HCSGylBnNONikdqmU6PbSpSfGI/dEeXsMOyKEuDESiLgYmqi0ppgIJ6Hy2GDYRhUaA3wk7R9BGdnyL1o+l538PvFUvx8rggCLhvLJsVCxOcgzMcLQ7v50hSAHoDDZmFoN1/sv1wKPocNrd6Ec/lVOHS1DKt+vYwHBoTitSm9rWU3itU6fHLgGjR6E7r5S3DrT8jN68FBUT6oqjUiq0KLM3lVMJoZ9AyUIEzhBS6HhVM5KuSp6qAQ81FVa4S6zoj4EHmH4leI+VDbanqiDvCT1E+Hnnz9r2TYzRk5mkuQ5anqkF9Za//gCHGy7ArHJIk4LcyocPPmXMRjo85gRp3BjHCFCEIeB1dLNO0eJW4wWXClxPa93psj5nPwjztjHLY/QkjzWCwWZg0Kw5u/XHZ2KMSGpEIuVk1PoPseQggAoLRGh2e3pePPa47r7NiVpebYJhFGiLswmi14dlu6W5asNTP199cDInxwJr+qUyOkhTw2jGYzLhfb59lYflX7BsjcTmMwI+VG+6YQ8xETIMH1Mk27poHX6O07GODVKXEQcN17IBslwEkDf+sTTAlwD/b1iVwcvFyKYTF+WH1/orPDIV3Io8Mj0TtEhlK1Hit/vgQeh405wyIRJBci2l/i7PCIA8QpZQCAYrUOE8IC8cOTw3A6txL+UiE+/iMDfVb8BjGfA7mIh4ySGgTLRLhUrG7yZjdAKkC3AAnKNXpcLdFY379SokF2RS1+v1RqfU+lrb9wtDD1PWQTQuU4m9++np9Gs8Xh0xKF+YggFnBRozdByGVDxOcgSCbEpSI1RHwONPqmb3TYLNSvpzNBxHfvi1RCAMeVZzG2YT91t9TeylXVgcdhIS5Y1qGe3NV1RoT6iJBf2bmb6raQi3iQiajDISGu4r6kMKzeexUGs+PKTxH7Wj45DkFymvqcEAIczSjHM9vSUa6hKc/bKqeiFmU1+naVUiPEnX20PwNn2vlcq6tJyanEoEgfnOzESPCEEHmn1m8Jj8NCgQ3v1VVaA05mqcBhAUnhPlDV6pFV3nLiXiLg4qodO85P7B2E0T0D7LZ9V0EJcNLAgEgF/CQCulDzYIXVOvxyrghPjIxGd6rBQ9poYKQCAyMVAIClk2KRUaJBfIiMRkF4kP7hPojw9UJORS32XyrFm79cQkFVHVKyK629VtU6E7gcNoLkbFTXNd/j0WxhkJxZgZgACWTC+jrgXnwODGYLdEYzVFoDKpso16HRm3E2vxrd/MUNanK3xmJhMDBSgeo6g12mTQKAQVEKmMwWVNYa4MXnoqi6DnlNXEyH+ohQotZBxOPAXypAkFzYoIaRhQG4bBZemBiLexKVdonV02RnZ+P111/HH3/8geLiYiiVSvz973/HSy+9BD6f7+zwPJ7cQYnbm2UH2sNoZnClWI3hMe0vRWA0M1DKhQ5JgN/Tl6bkJcSVKMR8TIwPalTehHRNI3v44/4Boc4OgxDiZCazBR/uz8DHB6655DS3ri41pxIT44OcHQYhTncqW4VPDlxzdhgO0ZkR7rFBUrslv+3JzACpufVx91ZKwWKxcL6g6ZK03QMlON2OmebaQ8hjY/mUOLts29VQApw0wGGzcHdCMDYcy3Z2KMQJZg0Kx+ViNdLzqnA8S0UJcNIhQh4HfUI7NhU16bosDINh3XyRU1ELk4XBjrR8JIR5N7qgVWkNCJAKIBfxGozuvokDwNuLB7XOiGuljT+/ic9lQ8TjINpPDMONxLK/RABvLz5OZLVvqjkRn4vkzHLwOGyI+RxoDZ2fZipYLkS4wgtavQlsNlCh0TeblA/xFkEu4iG7QoswhQhjYwPwvxO5yFXVQqM3YlCUDwAWxHwOJEIeRnb3g85ohtHMgM+lTiaddfnyZVgsFnz66aeIiYnB+fPn8fjjj0Or1WL16tXODs/jRfg6pna13tixkZhmBkjJVsHbi4eqJjrmtMgBX18Blw0Lw6BYrUOIt8j+OySEtMmsQeGUAHcDEgEX/53ehzr9EuKBDCYLzhVUIyVbhVPZlUjNUTXZSZu0TWqOihLgxOOpdUY8uy0dFg/pRNPczIdtIRZ0/bTmhcL60d0JIXJklGoaPT9tfxf9tvvHnd095vlA1/9JITa3dFIsiqt12HOh2NmhEAebOTAMfhI+Nh7LxsNDIpwdDiGki6jRGfHiD+dQUF2HQVEKlNXoIbpRG3dwlAIMAIZhYLYwMJotkIt4MFkYsFnAwAgFWCxAazDjSkkNxHwOMsu0EPM5iPITNUiSs/BXjXCDyQKFmA8ehw0+lw2JgAszU79NLpsNoG3JLDGfAw4bMJgZGMxm9AiUWPfZJ0QOldaAgnbW/emtlOJqiQZF1Trre0nhPgAaJsBlQi6W3NUDc4ZFAgB+SMuH3mTBtlN5iPD1QqBMiEg/Ma6VavDwkAhMig8Cl2PPS2DPNHHiREycONH6Ojo6GleuXMHatWspAe4CejioMx63E51Jao0W9An1xolbZmtoiZDHRkKoNy4U2H9aO73Jgs8OX0efELnH3OAS0hUMiVZgYKQPTnXBkSvkLy9N7gUlta2EeAS1zoi0nEqkZFfiVLYK6XlV0DuoVI8nSKE64ITgtV0XHDJDmKtQiHnIKu/YurmqWnjx2KjtYEd2V3K2oH4my8paA1Ta+o5ULBaQWd72mS3bI9pfjMfuiLLLtl0RJcBJI0IeB+/cn4A/LpdSXTI3JhVyMaN/KEb19MfvF0uwO70QP58txEuT4/DSZM+YAoMQYhvbU/JwvVwLqYALg9mCACkfZguDELkIBpMFepMJYgEPHDYLHBYbBhODInUdpEIeLhZVo7dSjnM3EkE9AiSorDVCazCjtEaPQVEK6I1mgAWcL1AjxFuEQJkAOqMFNTojTmY3nXBKivDB6dzKFnvO9gvzBosF6w2GmM+BjxcfAyN9oK4z4lxBNXy8eBgSrcDx680ntlion+LcwjDQGc3Iq6yD0cygm78Yj98RDR8xH3UGEx4dHolu/hIUVdfhZJYKCaHemBgfBBaLhaslNfjyaDZ4HBbefSAR0X4SsNk0mshZqquroVAonB0GQf1sClIBFzV6k122Hxcsg1TIRVYnby7b00m/e4C0QWkDR6DatIS4FhaLhXfv74tJHx62ycwzxPFGxPjhwYFhzg6DEGInxdU6nMpWWUd4Xy5We8yoTGc4X1ANndEMIY/j7FAIcYofzxTih9MFzg7DYXoGSnG2E3XOy2r0du1Mar4xaMdR7X5mmRYSPgdBMgGA+v2W1ti+RLFUyMVnDw+AgOs5bS0lwEmT9l4ooeS3G5IJuRgXF4gBEQpMSQyGVFhfV3NMzwCsnBbv5OgIIV1VdkUtcipqERMgBo/DRkapBiqtEf3CvXG9tAb9IhSoNZjA53BQUFkLpbcIciEP5WodAuQiVOvqeziK+Bywb5lCsqrWCBaAi0VqGM0MvL14EAs4yC6vhc5kQlyQDDIRD8XVukYXhpcLqxGmqK9JfquEUDlMZgYsFoPTeVUNPtMazMgu14LPYyNPVYdufmIIeWxcLq5Br2Apiqt1TU5rlxTp02Dkp4jHwdN3xmDRnTFNXlTGKWUY2yvwxjEa8My2dBy+WgYLA9zR3Y+S30527do1rFmzpsXR33q9Hnr9Xz9zanXTNZtI57FYLHQPlCDNTrWv+Fx2m0du23KfjsTjsNAnhEqTEOJqwn298MqUOLzw/Tlnh0LaKdpfjA8f7EtTnxPiBhiGgcnCILtci1PZlUjJVuFktsqjRmG6AqOZwbmCagyMpE7IxPMUVtXhpR2ecz0YrhChWK2D0dy57HJKTiUiFF7IUdW2vnA7WRjYbdvN0RjM0NixYyybBayZ1Q8xARK77cMVUQKcNPLjmUI8/90ZZ4dBbGz+iCj8a3wPePGb/trTzTshpK1qdEaI+VxrknbRmBgEyoS4VqZBnqoW3fwl6BHAQpFah55BMhRX6+Ar4ePotXLEBkqg0ZvA47DhKxXCXyKAVMiFVm+Cr1gAsYCLuGAZZEIuLhRWI6tcg75h3mAAaHQm5FbUQmswI0gmQGa5FuUaA3gcFkJ8RPAW8eAvFeBioRoqrR5e/MbJZ7OFwcWippOVg6IU1lGZbBagN1tQWqNHjd6EAKkAAVIBxHwuQnxEMFkYWCwMuBwWBDwOJAIuNHoTRvXwx7/G90BCqHebzuVbey7j4JUy6+uxsQEwWiywmOo7BJCOW7p0Kd56660Wl7l06RJiY2OtrwsKCjBx4kTcf//9ePzxx5tdb9WqVVixYoXNYiUt6xEotVsC3GCjqSsL2vGQlOvgDi4KMR9fHs3ClAQlwh1UU50Q0jYPDAjDvosl+P1SqbNDIW0UJBNi8/zB8JUInB0KIW7JZLbgoz+uoarWAKOZgdligclSX07LZGFgNjMw3fqe+eZn9e/d+vrmOibzjXVv25bJbKFR3S4kJbuSEuDE41gsDP717RmodfaZ8czVhCtEUOtMqK5rPLikvRgGkInsl970kwgcmgC3t5cnx2F0zwBnh+FwlAAnjaz+7QpdALqZp8d2x7Pjuts1yc0wDErUemSWaXC9TIOciloEyAQY0zMA3R1Uv5MQYn95qlokX69A/3BvxATUf7cDZUIsGhODoxnleGXXeSi9RSir0YHPYYPLYSNPVQulXIDhMb5gGAZVtUZIhTyE+3iBx2FBZzAjV1WHqjojegZKUaLWITbYH3f08EeojwjdA6SI9hdDyOPg6xO52HuhGFq9Eb2CZdiZXohwhRe8+Bxo9WboTRYEygQordGjzmDGgAgfaz2x3koZcso1zR6b+ZZfft4iHkK8RTBbGNToTbhaosGQaAXyKquRf0tNcB6bhTilDHVGM+QiHoJkQhRW6ZCcmYm/DwlHiVqPaP/me1fKRDzrv9++LwFjegZAwOXAZLZAZzBBwONQB6UO+te//oVHH320xWWio6Ot/y4sLMSYMWMwbNgwfPbZZy2ut2zZMixZssT6Wq1WIyyMpkG1F3teR1TVGjq9DR8vHphmJkEX8ThICJWjtEYPHoeFqyUah8+yVKLW4529V/DZ4evYumAIegXLHLp/QkjzWCwWVk1PwOkPDqNC2/n2iNiXXMTD5vmDEEJ1vwmxmzd+uYT1f2Y7OwziBKk5KgDdnB0GIQ71+ZHrSL5e4ewwHCZYLkKuyrEzsHUUl+M+z+JmDQrD3OGRzg7DKSgBThrIqdA2mi6WdG3DuvnimbH2SX4fySjD96n5yCzT4nqZpsn6dW/+chkxARKM6xUIf6kAIh4HQh4bIh4H/cJ9qCYlIV1MmMILYYqmRxCGK7zQO0SOApUWYj4HXnwu8itrEerjhfxKHaRCLjhsFnzEfFgsQFa5BjIvPq4U12BAhA+yyrVgsYCeQRI8PyG2yfbhocHheGhwuPX1xPhgzF1/qkFCKUIhwpAoBUprdBDyOBDzOYgNkiE1txI8Dgt39Qq8Md2SGZeLNQjxFiJAJkTqjUR590AJvEW8BtMiD432xYZ5A8HnsHG1RIN/fJOGqyUaGC0Mrpdp0DdUDoOZwbaUPGxLyQMA5FTUIq+yFpvnD272fI7q4Y/PDl/H5nmDMaybr3VUPfdG5wHScf7+/vD392/TsgUFBRgzZgySkpKwfv16sNktn3uBQACBgEZ+OUqPQPtN0VVpg57nZoaBxVI/1Xj/cB+odUbwOGwIeRyUVOusbUmwXAA/CR/XSpvviGNP1XVGvPD9WexePMIp+yeENM1fKsCq6X2wYHOqs0MhLRDxOFg/dyB17ibEjr45mUvJbw+WmlMJhmGoAzjxGOcLqrH6tyvODsOhssq1Dq2t3RkavXuMyh8cpcCKe+I9tm2lBDhp4HBGubNDIDYkEXDx9n0JNq8lqzOa8faeK/jqz6w2LX+tVNPkw14WC/hgZl9M7Rti0/gIIc4R7uuFNbP64UJBNT49fB3F1XXg8zjIr6xFb6UMDACzBSir0sFPwscns/vDRyxAel4l/rhchpE9/FFVa0C5xgCTpW0jJIfH+OHjh/rhQqEaVbUGFFTV4cCVMtTozOgVLEWOSos7evjjQmE1gPrepuv+3h/lWgM++P0qBFwOquuMOJ9fjf7h3sivrENGiQZsVn0bxTAAh83CS5N7Wet59wyS4tUpvTH7ixMAgDCFGKlNTM88d3gkHv7yJExmS7PJ7GCpANsWDMWgKJrqzVkKCgowevRoREREYPXq1Sgr+2tK+qCgICdGRm6KUIjttu24YJm180tHqetMUNeZkBTu3WI98aJqPeQiLmqcOL3d2fxqVGj0NHWvGzh8+DDeeecdpKamoqioCDt27MC0adOsnzf3gOPtt9/Gc8891+RnNTU1WL58OXbs2IHS0lL069cPH374IQYOHGhdhmEYvPrqq/j8889RVVWF4cOHY+3atejevbtNj8/TjO8dhPuTQrE9Nd/ZoZAmcNksrP17f/QP93F2KIS4reTMCizfed7ZYRAnqqw1IruiFlF+9rv2J8RV1BnMeGZbeqfrYHc1pTV69FbKIORycKWkxqWTzNfLNFCI+VB14VmawhVeWPv3JPC5njvAhhLgpIEKjd7ZIRAbWn53L4T62K7WY43OiF/OFeGj/ddQUNX2Wpe3kgq4ePauHogNlkJdZ4LSm0aAE+JueofI8dGsfqg1mJCeW4U3f7kECwOk5FRCJuLi3fsSkRSpgELMBwBE+Ylxb7/QDu9vfO8gjO9dn6isrjVi36USnC+oxuie/hjVwx8sFgs6oxnF1TqYLBZwOGwEyoRYNT3B2sO8XKPHluM5KK3RI8pXjMkJweCyWbhWqoFYwEV8iLzBPofH+OG9BxLx+8US1BrM4LLluFJSA/2NesJefA6C5EIEewtxvVyLHk2MFtIZzAj3kyAqwDN7YbqKffv24dq1a7h27RpCQxv+HDKMZ92Muip71vXKLLPdaOy2TG1eXefcG3w/CR/eXnynxkBsQ6vVIjExEfPmzcP06dMbfV5UVNTg9a+//or58+djxowZzW7zsccew/nz57F582YolUps2bIF48aNw8WLFxESUt9h9e2338ZHH32EjRs3IioqCsuXL8eECRNw8eJFCIV0Xd8Zr0yJQ/L1CuRXduw+i9jPuw8kemTNREIcad/FEpi6wpBAYle2qAtMSFfw318vOW1mMGe7UKgGAHDZQGKoHAVVdSjXtD/JLOJzUFlrvzajzmhBXLBXl02ASwRcfDFngPXZq6eiBHgLjGYLKmsNMJgs9X/MFjAM0D1A4rbTknJtPFKYOM/onv54YEDn6pGW1eix5Nt0AEBVrREZpTXQGdtet5LDZmFMzwDcFReAS0U1uFioxoez+iJYTjXTCPEEfA4b6flVOF+oRp8QGUZ294PeZMHuM0WICZTa5SJM7sXDfUmhuC+pYSJTyOMgsome5DdHyPlJBHhmXI9GnwfImn+YP71/KO7tF4IPfs9Ar2AZfjpbiH0XS9Av3BtzhkaCx2HjvqTQJpPfZrMFQj6nvYdH7ODRRx9ttVY4ca6mSqzYQlywDBeL1DbZlhefg6JqnU22ZU9jYwPBoet9tzBp0iRMmjSp2c9vn8Fi165dGDNmDKKjo5tcvq6uDt9//z127dqFkSNHAgBee+01/Pjjj1i7di1WrlwJhmHwwQcf4OWXX8bUqVMBAJs2bUJgYCB27tyJBx980EZH55mkQh7ee6AvZn6WDOp/5TpemxJHM5YR4gBPju6GradyUWun6z7SNZipEwTxACnZKmxMznF2GE5nsgBn8qvhK+YjJkDSrg4BIj4H4T4iXCmxbyeC1NwqxAZJcbm4xq77sTUWC/hoVt8mn0d6GkqAN+NqSQ3mfHWyyQdZY3r644s5A93y4VFBles/uCNtc39SWKdrO/hLBZCJePj5bFHrC6O+9mVvpRxJET7oH+6DgVE+CJDSSBBCPElBVR32XSjGvf1DkVFSgw1/ZuOO7n5goX468VPZKoyI8cPFQrVbTG3GYrHwzLjuuFCoxv5LJeCwgIm9gzCpTzCqag3oHvDXxabZwkCtM0LC54DTSo1pQshfciq0dtmuLTt+RvuJcb7QNsl0e7orLtDZIRAnKCkpwc8//4yNGzc2u4zJZILZbG40ilskEuHo0aMAgKysLBQXF2PcuHHWz+VyOQYPHozk5ORmE+B6vR56/V8zjanVrv9dcZZBUQosGBmNTw9dd3YoBMDTd8bg0eFRzg6DEI/gLxVg3vAofHzgmrNDIU5ECXDiCfacL3Z2CC6lQmtAjc6IfuHeON1EecHbOSr5fVOdwQwOm9Wl2qcXJ/XCnbF07w9QArxZW0/mNTuKI6ei9saUmO6VAE/NUeGbk7nODoPYSJDcNonn5yf0hN5oRq6qFiqtAQFSIYLlQuRX1uFKSQ36h3tjUnww+kd4o7dSDiGPRjQS4sn8JXxwOSyU1+hQVqNHj0ApdEYzdCYzSqr1GNXDD2N7BWFyQrCzQ7WZRV+n4cjVchjMDD56sJ/12Ly9+Nba3uU1OpgZILCFEeWEkKadbKGudmcIebbpiNJVkt8iHgcjuvs5OwziBBs3boRUKm1yqvSbpFIphg4ditdffx29evVCYGAgvvnmGyQnJyMmJgYAUFxc/7AuMLDhw5TAwEDrZ01ZtWoVVqxYYYMj8QxL7uqBQ1fKutxIE3cze3A4nr2r8exAhBD7WTAqGltO5KDKjlPatkWwXIi4YBl6K2VIvl6BU9mVTo3Hk3SlBBMhHXUko9zZIbgcg5nB6dwqDIpStHj/7+jkNwDkqGpbjctVsFjAv8f3xGN3UAfOmygB3oy/9QnC/07kWGt53uq/MxLccgr0mABpl+vNQprWM1CKuGCZTbYV4SvGF3MGNvmZSmvw+DoShJCG+FwO/j4kEgDQLUCKcXGByFPV4nqZFucKqpBRqsG3KXmYOTAMPDf4XaozmjElQYkwhRf+Fh+MxDDvJpfzFnHB5dJlFyEd8cu5ts1E0x48DstmdSY7OeGOw4zs4UcdFT3UV199hdmzZ7dao3vz5s2YN28eQkJCwOFw0L9/f8yaNQupqamd2v+yZcuwZMkS62u1Wo2wsM6VanJnAi4H78/si6kf/wmDue3lp4jt/K1PEP4zNb7TM6oRQtpHJuThyVHdsOrXyw7bZ4SvFxJCvdFbWZ/wjguWwVcisH7+3PYzlAB3IAvVACFurkStw5US6uTYnJNZKgyI9EFKE+2uTMhFsFzo0OT3TWfzqhAoE6BErW99YSeRCbn4aFY/jO4Z4OxQXAo9iW3GgEgFDj03Bh/9kYFtp/KsSeGHh0RYR3O5GwGXjSg/cbvqLRDXwmIBvYJk+L/Z/SFyQG1ZSn4TQlrD47AR7S9BtL8E4+ICYTRb8OOZQqjrjA0eLHRVQh4Hk/oEY1Kflke0U/KbkI5JzqzAVRve4HYPkEAm5CGvshZpbZherS26SlmkYd1o9LcnOnLkCK5cuYJt27a1umy3bt1w6NAhaLVaqNVqBAcHY+bMmda64TfripeUlCA4+K/feyUlJejbt2+z2xUIBBAIuv7vfEfqFSzDv8b3cGgSiNQbEeOH92f27TJtOyHuZs6wSBy8Uobk6xV220e0vxh3Jyhxd0Iw1Ud1MTQoi7g7Gv3dupTsSvQL88bpvCrrezEBEqjrjE5JfgOAzmRBjMR1E+A9A6X47JEkRPh2/VKTtkZPY1sQJBfizXv7IDFUjhd3nIcXj4PnJ/Z0dlh2wTAMHtuYQsnvLuzJ0d3w1OhukAp5zg6FEEKaxeOwMb1/qLPDIIR0ATqjGS/uOGeTbbFYwMAIH6TmVMJs4+dqYkHXuKWKD5E7OwTiBF9++SWSkpKQmJjY5nXEYjHEYjEqKyuxd+9evP322wCAqKgoBAUFYf/+/daEt1qtxokTJ/Dkk0/aI3yP9tgd0dh/qRQns11/ukV3kRAqx7qHkyDg0mwZhDiLkMfB148PxoErpVj1y2Vk2Og5ZaSvF+5OUGJyQjBig6Q0w4OLMtMIcOLmjmSUOTuELuFsfhXilTKcL1RjYKQPTudWoomJmh3qfKEaSTeeKbiSyQnBeHtGQpd5LuFoNp979PDhw5gyZQqUSiVYLBZ27tzZ4HONRoPFixcjNDQUIpEIcXFxWLduXavb3b59O2JjYyEUCtGnTx/88ssvtg69WTMHhuPqykk4+9p4t00u1hrMOHqNeiB1ZWwW3PbnkxBCCCGepbrOiKf+l4ascm2nt+XjxUPPQClOZts++Q0A/C5SziFI3vL016Rr0Wg0SE9PR3p6OgAgKysL6enpyM3NtS6jVquxfft2PPbYY01uY+zYsfj444+tr/fu3Ys9e/YgKysL+/btw5gxYxAbG4u5c+cCAFgsFp555hmsXLkSu3fvxrlz5/DII49AqVRi2rRpdjtWT8Vhs/DuA4mQ0MMsh4j2F2P9owPpfBPiAlgsFu6MDcSv/7wDb83ogwBpx2YRCVd44cnR3fDTP0bgwL9H498TeqJXsIyS3y7MQiPAiRuzWBgcpRHgbWJmgIzSGgzrpsCpbOcnv2+6WlIDhdg18i9sFrB0Uiw+ntWPkt8tsPmZ0Wq1SExMxLx58zB9+vRGny9ZsgR//PEHtmzZgsjISPz222946qmnoFQqcc899zS5zWPHjmHWrFlYtWoV7r77bnz99deYNm0a0tLSEB8fb+tDaJK7T3/FYbMwKT4IJWodStR6FFTVOTsk0k4/ninCv8f3pAt5QgghhHQ5epMZLLCQq9LiaEY5NhzLRnZFbYe3F+nrBbmIBzaLhdIaHS4X26/OWolaZ7dt25JGZ3J2CMSGUlJSMGbMGOvrmzW258yZgw0bNgAAtm7dCoZhMGvWrCa3kZmZifLyvx7CVVdXY9myZcjPz4dCocCMGTPwxhtvgMf76yHP888/D61WiwULFqCqqgojRozAnj17Wq0vTjomTOGFV6bE4fnvzjo7FLcWJBNi8/zBblGehxB3wuWwMXNgOKYkKvHV0SysO3QdGn3L1zMh3iLcnRCMuxOUiA/pfLL7zel9sGBkNK6WaHClpAZXi2twtaQG2RVaUK7W9mgKdOLOMko1qNAanB1Gl6E3Mag1uEjm+4YanQn9wr2h0lY5NQ65iIc1s/phZA9/p8bRFbAYxn5zi7BYLOzYsaNBb/D4+HjMnDkTy5cvt76XlJSESZMmYeXKlU1uZ+bMmdBqtfjpp5+s7w0ZMgR9+/Zt0+hxoL73u1wuR3V1NWQyWccOyEPojGYMfON31NBDsi5lUnwQ1szqB24XGYXUGfR9tj86x4S4D/o+2x+d485JyVZh9hcnoO9kt+4egRIIuBzwOWyk5jpmWjI/CR/lmq7xEGP7wqEYGKlwdhhdAn2n7YvOb/swDIMFm1Ox72KJs0NxS3IRD98tHIruVAe4w+g7bV90fv9SrtFjzf4M/O9ELkw3EqUsFhDtJ8aYngG4O1GJxFC5QwaG6IxmZJZpcLWkBleK6/++WlKD/EoaUNQZ6/7eHxPjg50dhl3Rd9q+XPn8GkwWjHvvEHJVHe/o7WkGRSlwMsv1ygH1CZHhXIHaKfuODZLis4cHINzXyyn7d7TOfqcdPjZ+2LBh2L17N+bNmwelUomDBw/i6tWreP/995tdJzk52dqj/aYJEyY0ml79Vnq9Hnr9X0Xp1Wrn/EB2JQzD4MCVUnx7Kp+S310Ih83CgpHReG58T7DdfKYCQgghhLif79PyO538HhSpcHidXA6bhUCZ0GYJ8Gg/MeaNiMK1Ug1OZKlwqci29y8GV5k3jhDSLiwWC6um98Hp3Mou0+GmqxDxOFg/dyAlvwnpIvwkAqyYGo9Hh0fhwOVS9FbK0DtE7pTSBUIeB72VcvRWyhu8r9GbkHEjGX6lWIOM0hpcKa5BaY2+mS2RW5npcpW4MT6XjWfv6o5nt51xdiikk8o1evC5bIfeY0sEXExJVGL53b3gxacpz9vK4WdqzZo1WLBgAUJDQ8HlcsFms/H5559j5MiRza5TXFyMwMDABu8FBgaiuLi42XVWrVqFFStW2Cxud8YwDL5NycMXR7KQUapxaiy9gmV4/I4oiHgcPPm/NKfG0hUM6+aL1+7pjR50w04IIYSQLuhaqQbfpeZ3ejtlGsc/VPzzhTvxQ1o+LhR2PlEdKBNg47xBCFPU9+LWGc0Yumo/KmuNnd42UJ/k6a10rREQhJC285MI8N/pCXhsU4qzQ3EbXDYLa//eH/3DfZwdCiGknaL8xIgaEeXsMJokEXDRL9wH/W5rWyq1BlwtqcHFIjV+OVeEU9mOma2oqzFZKANO3Ns9iSFYezATV0ucm4PpKswu2iYUVesxOEqBE3YenR7lJ8adsQG4MzYAAyMV4HPdf+ZfW3NKAvz48ePYvXs3IiIicPjwYSxatAhKpRLjxo2z2X6WLVvWYNS4Wq1GWFiYzbbvTvQmC174/pyzwwAAPDAgFBPjg8BlszE54a8pbyo0epzIUqEzE/b7ivm4t18I+oZ7IzZICpmQh9d/voQfzxTaIHLHEXDZGN3TH/clhWFcrwCq+U0IIYSQLqm4Wocnt6TCaO58RSY/CR9Z5VobRNU2fA4bAVIBnhoTg0FRCpRrDPjqz6xWp2d7f2Yi+BwOPjucicwyLSJ8vTCmZwDmDIuEv/Sv2rNCHgeb5g3Ggs0pKKpuvcZ4oEyAkd39ceBKaaMRohIBF/+Z2hveXvyOHSwhxCWMiwvEgwPDsPVUnrNDcQvvPpCI0T0DnB0GIcRD+Ij5GBzti8HRvpg7PAo5FVrsOF2AH9IKaDrkW1jsV6mVEJfAYbPwr/E98cTmVGeH0iXojK6ZAAeAtJxKhPiIUGDD0hdcNguDoxUY07M+6R3tL7HZtj2VQxPgdXV1ePHFF7Fjxw5MnjwZAJCQkID09HSsXr262QR4UFAQSkoa1rsqKSlBUFBQs/sSCAQQCATNfk7+crNuTluJeBz0CZEjLbcSLBZgtjBo5yaadaW4xjqFwycP9W/wWWFVHXacLsDp3CoEyAQI8/FCqI8IZguDjcnZyCzVgGGAGr0J3l48LB4TgyHRvpAKuZAJefD24jVKFn/0YF9IhVx8fSK3yXh4HBbigmUIlAlRWWuwaw/NEG8RZvQPQVKkAiazBYXVOlwsrEZmqRZ6swVKuRCT+gTjztgAp0zvRAghhBDSWUazBX9eK8feC8XYnV4IrcFsk+06ukNgiI/IWnpmwI262qN7+mP2FyeQmtP09WK0nxjjegVCKuQ16OjZnD6hcuxaPBxPbE7F6dyqZpdjs4DN8wejR6AUdQYzvj6Zi08PZULAY+PefqF47I4oyIS89h8kIcTlvHx3HP7MLEeeimrMdsZrU+IwtW+Is8MghHiwCF8xnhnXA/8c2x2pOZX4Pq0AP50t9PiSlDQFOvEE4+MCkRjmjTN5Vc4OxeXV2uh5gT0YLQy8RVwUdCJd5CvmI0guRK9gGcbGBmBEdz9I6d7dphyaRTMajTAajWCzGw7V53A4sLQwncHQoUOxf/9+PPPMM9b39u3bh6FDh9orVI8i4nEQ7SdGrqoWK6b2RlaZFpuO5zRZw6C3Uoa370toUOPGaLYgp6IW+ZW1qK4zYtUvl1Gsbn2kyq0SQ+V4cnQ3TOjdfKcGpbcIi8bENPnZ4GgFBFwOOCwWTmRVYECkAgpx66NcWCwWXp8aDzYL2HL8ryS4XMTD8rvjcHdCMIQ8jvX9s/lVmLv+FCq0TddeY7HQ6ij1fuHeuCPGD5F+YpgsDExmBlF+YgyOUlANb0IIIYS4LaPZghlrj+FsfrVNtysTcnEmz7HTSHrxOY3eE/I4+PThJNy39hiyKxqO5BHzOfjskaR238wGSIXYumAI/nc8F+uPZaGkWo9eShlG9fDHxcJqZJRqMKN/qLUcjojPwfwRUXh0WCRYAF1bEuJmJAIu3n+gLx74NNlmndA9zdN3xuDR4a45dTIhxPOwWCwMiFRgQKQCr06Jw/5LpfghLR8Hr5bB7IENvcUDj5l4HhaLhecn9MTsL044OxSXJ3DxKb8vFNagb5g30pvozOAnqU9uB8tFCJYLESQXQikX3XhPiECZsEHeidiHzRPgGo0G165ds77OyspCeno6FAoFwsPDMWrUKDz33HMQiUSIiIjAoUOHsGnTJrz33nvWdR555BGEhIRg1apVAIB//vOfGDVqFN59911MnjwZW7duRUpKCj777DNbh++ROGwW3ri3D2Z/cRx3xQUiQCrEojExyFXVokStQ0mNHuo6I/qGeWNYN99GI2x4HDZiAiSICaifkqFPiBwPfnYcpTX1tRij/cS4OyEYBjMDhZgHk4WBzmiBF78+8Z4U4QNfSedG6wfLRdZ/j28hid7c8a+c1gcjYvxx4HIpWCxgyfgeCJAKGy2bEOqNN+6Nx7PbzqDO2LAHklIuxJePDsSPZwrxfwczG607KFKBZ+/qgaHdfNsVHyGEEEKIOzidW2Xz5DcAaPQmcBw8Ary8mZrjfhIBvntyGJZ8ewaHr5YBqO8g+e4DfRETIO3QvgRcDuaNiMK8dtS65FDimxC3NSBSgSdGdcPaJu45SctmDw7Hs3f1cHYYxAkOHz6Md955B6mpqSgqKsKOHTswbdo06+cajQZLly7Fzp07UVFRgaioKDz99NNYuHBhi9vdvn07li9fjuzsbHTv3h1vvfUW/va3v1k/f/TRR7Fx48YG60yYMAF79uyx6fER9yDkcTA5IRiTE4JRVqPH7jOF+CEtHxcK1c4OzWHMNAW6W2mt7b3d0aNH8cILL+Dy5cuora1FREQEnnjiCTz77LOOC9pBhsf4YeuCITh+vQIns1RIy6106em+nUXIc+0EOAAUV9eBx2HBeGOQ4/0DQjGjfygCZY1zS8TxbJ4AT0lJwZgxY6yvb9bhnjNnDjZs2ICtW7di2bJlmD17NlQqFSIiIvDGG280uKjMzc1tMEp82LBh+Prrr/Hyyy/jxRdfRPfu3bFz507Ex8fbOnyPNbSbL5ZOikVmqRYBUiF8xHz4tGEEdVOi/SXYvnAonv7mNM7kV+OhweF47I5oG0dsexPjgzAxvvXk+cT4YIzrFYgyjR6laj2ultSgqtaIaf1CYGEYZJRqGizfP9wb/xrfs8nOA4QQQgghnuL2zoO2EOojgkLMt0tivSXlGgMsFqbJEdZ+EgE2zh1440FGFQZG+linSSeEEFt4dlwPHLxShktFnpMU6azJfYLxn6nxdE/uobRaLRITEzFv3jxMnz690edLlizBH3/8gS1btiAyMhK//fYbnnrqKSiVStxzzz1NbvPYsWOYNWsWVq1ahbvvvhtff/01pk2bhrS0tAbPKydOnIj169dbX1O5RtIW/lIB5o+IwvwRUbhcrMaOtALsOF1gHWzkrjxx1Ls7a63tvZ1YLMbixYuRkJAAsViMo0eP4oknnoBYLMaCBQscELFjDYn2xZDo+oFyBpMF5wqqcPy6CieyVEjNVjVbLozPZYPPYVv/5nFZN15zbrzHarAM78bfFguDErUexWodiqrrukTCncdx/QR4dZ0J80dEYWyvQAyI8KFrTRfDYhjP6FqlVqshl8tRXV0NmUzm7HA8gtnCoLRGByGX0+FkeldTZzDjkwPXMDCq/iGnr5iP3koZNXw2Rt9n+6NzTIj7oO+z/dE5bpuCqjoM/+8fNtteQogc5wqq4aybmdSXx3V6FiPimug7bV90fm3jSnENpqw5CgMVTG2RkMfGv8f3xNzhUTQ7hp10te80i8VqNAoxPj4eM2fOxPLly63vJSUlYdKkSVi5cmWT25k5cya0Wi1++ukn63tDhgxB3759sW7dOgD1I8Crqqqwc+fODsfb1c4vsR+zhcGf18rxQ1o+9lwo7hLJq/b6z9TeeGRopLPDsCtP/U431fa2xfTp0yEWi7F58+Y2Le8u59dktqCoWndLkvvG3xyWTfIMDMOgus6IomoditU6FFfr6v9dXYfMMi3O5Ve7xDXmwEgfnMp2bLmztkqK8MEDA0IxOUEJicChlaY9Sme/0/Q/Q+yGw2Y1mJrcE4j4HPx7Qk9nh0EIIYQQ4nJCvEUY1ysAv18qtcn2eFy205LfCjEf3l6e0cGTEOKaegZJ8dyEnnjjl0vODsVlDYpS4K0ZCYjyEzs7FOLihg0bht27d2PevHlQKpU4ePAgrl69ivfff7/ZdZKTk62zXt40YcKERsnugwcPIiAgAD4+PrjzzjuxcuVK+PpSaTzSfhw2CyN7+GNkD3/U6Iz49XwxfkjLx/HrKmeHZjM0Apzc6vTp0zh27FizHZEAQK/XQ6//a2YEtdo9ZsfhctgIU3jZbfssFgveXvX3tL2CGycVdUYzzhVU41S2CqnZlUjJqUR1ndFu8TSnTO16s17M6B+KJ0dHd7jEGXEsSoATQgghhBBC7M5gsth0Vpy03Er0CpaCYYDLxTU2225bjOzuRyMJCSFON39EFPZfLnGr5IctePE5eGFiLB4eEtFkqQpCbrdmzRosWLAAoaGh4HK5YLPZ+PzzzzFy5Mhm1ykuLkZgYGCD9wIDA1FcXGx9PXHiREyfPh1RUVHIzMzEiy++iEmTJiE5ORkcDqfJ7bprMofYllTIwwMDwvDAgDDkV9Zi5+kCfJ9WgKxyrbND6xRKgBMACA0NRVlZGUwmE1577TU89thjzS67atUqrFixwoHReQYhj4OBkQoMvFHKy2JhkFmmwansSqTkqJCSXYlcVa3d48hW1UIh5kGldXzy/XZ+EgH+O70PxsUFtr4wcRmUACeEEEIIIYTY3d4Lxdh3scRm22MY4FJRDQJljp+GfExsgMP3SQght2OzWfjowX54eutpSoLfMDzGF/+dnmDXUVPE/axZswbHjx/H7t27ERERgcOHD2PRokVQKpUYN25ch7f74IMPWv/dp08fJCQkoFu3bjh48CDGjh3b5DqUzCHtFerjhcV3dseiMTFIz6vCD2kF2H2m0CmjNTuLEuAEAI4cOQKNRoPjx49j6dKliImJwaxZs5pcdtmyZQ1m41Cr1QgLC3NUqB6DzWahe6AU3QOleGhwOACgVK1D8vUK/O94Lk5m2+86NNJXDJW2ym7bb4u/9QnCyml9oPCQMr/uhBLghBBCCCGEELsbHK3AHd39cCSj3KbbLVHrERcsxcUix40CHxJNU5cSQlxDgEyIrx8bgi+OXsc7e6/AaPbM5IFEwMWLf+uFWYPCbDrbCHF/dXV1ePHFF7Fjxw5MnjwZAJCQkID09HSsXr262QR4UFAQSkoaduwrKSlBUFBQs/uKjo6Gn58frl271mwCnJI5pKNYLBb6hfugX7gPXr67Fw5cLsX3aQU4cLkUpi6SWDYzXSNOYl9RUVEA6jsOlZSU4LXXXms2AS4QCCAQOL5DNKm/Bp3aNwRT+4YgLbcSnx26jr0Xi2Hrr7Ezr+pkQi5enxaPexKVdH3ZRbGdHQAhhBBCCCHE/QVIhdg4dxAG3ZhGzZaqdSabb7MlchHPofsjhJCWsNksLBjZDbsWjUCPQImzw3G4UT388duzI/HQ4HB6OEnazWg0wmg0gs1u+IiUw+HAYrE0u97QoUOxf//+Bu/t27cPQ4cObXad/Px8VFRUIDg4uNllBAIBZDJZgz+EtJeAy8HE+GB8/sgAnHxpHFbc0xuJoXJnh9UqSxdJ1BPHsVgsDcpCENfUP9wH6x5Owv4lo/DQ4HDwubZLO6blVqFvmOPbr5E9/PHbs6MwtW8IXV92YTQCnBBCCCGEEOIQbDYLw2P8bD5FmsaBCXAWCxDY8IaeEEJsJU4pw+7FI/DO3iv48miWs8OxO5mQi+V3x+G+pFB6MElapNFocO3aNevrrKwspKenQ6FQIDw8HKNGjcJzzz0HkUiEiIgIHDp0CJs2bcJ7771nXeeRRx5BSEgIVq1aBQD45z//iVGjRuHdd9/F5MmTsXXrVqSkpOCzzz6z7nPFihWYMWMGgoKCkJmZieeffx4xMTGYMGGCY08A8WgKMR9zhkVizrBIXCutwQ9pBdhxugBF1Tpnh9aIufk+J6QLaq3tXbZsGQoKCrBp0yYAwCeffILw8HDExsYCAA4fPozVq1fj6aefdkr8pP2i/SV4894+eHZcD2xKzsam5JxOl2NgAJwvqEZvpQwXCtW2CbQFXnwOXprcCw8Noo6V7oAS4IQQQgghhBCH0eibvwH28eJh3vAoeIv5kAm5qKo14vu0fJzNr25xm9V1RsSHyHC+wAE3xDwO3QgTQlyWkMfB8rvjMKZnAP69/QyK1a6X4LCFcb0C8ca98QiUCZ0dCukCUlJSMGbMGOvrm1OMz5kzBxs2bMDWrVuxbNkyzJ49GyqVChEREXjjjTewcOFC6zq5ubkNRokPGzYMX3/9NV5++WW8+OKL6N69O3bu3In4+HgA9SPIz549i40bN6KqqgpKpRLjx4/H66+/TtP1EqeJCZDi+Ymx+Nf4njh+vQLfp+Vjz/li1BrMzg4NAE2B7m5aa3uLioqQm5tr/dxisWDZsmXIysoCl8tFt27d8NZbb+GJJ55weOykc/ylAvxrfE8sHNUN36bk4cP9Gaiq7Xgi3GQBrpXWoEegBFdLNDaMtKEBET5494FERPiK7bYP4lgshvGM3yxqtRpyuRzV1dU0fRAhXRx9n+2PzjEh7oO+z/ZH57h9lmxLxw+nCxq9z2IBv/7zDsQGNTyHDMMgLbcSG47lYP+lkmYf0CWEyHG2oOVEuS34SfhIefkuu++HOA99p+2Lzq/jVNUa8NLO8/j5bJGzQ7EZby8eVtzTm2oxuhD6TtsXnV9ib1q9CXsvFOOHtAL8mVlu8/q97bF4TAz+PaGn8wJwAPpO2xedX9f045lC/OOb053ejkTAgb9UgKzyWhtE9Rc+h41/je+Bx+6IBodN15eupLPfaRoBTgghhBBCCHGYMk3TNdwifcWNkt8AwGKxkBShQFKEAkazBUVVOuSqapGaU4mNydlQaQ0AAJ6DpiUX8jgO2Q8hhHSWtxcfH8/qh3G9AvDKzguo0TuuXIQ9/K1PEFbcEw9/KY2eJYQQWxELuJjePxTT+4eiqLoOO08X4vu0fFwrtd8oy+bQCHBC3NPdCcHYnpqPw1fLOrUdjd4MHseIaH8xrpdpbRJbXLAM781MbPJZBOn6qHgdIYS4sU8++QSRkZEQCoUYPHgwTp486eyQCCGEeLh7+4VA1EQSuUegpNV1eRw2wn29MKK7H/45rjt+XzIKSnn99Ld1Dpq6sZt/63ESQoirYLFYuLdfKH595g4MjlI4O5wO8RXz8X+z++P/ZidR8psQQuwoWC7Ck6O7Yd+zI/Hj4hF4dFgkFGK+w/ZvsVACnBB3xGKxsHJqPAQ26LReWWvE9TItBkT4QCHmdXg7bBbwjztjsHPRcEp+uzFKgBNCiJvatm0blixZgldffRVpaWlITEzEhAkTUFpa6uzQCCGEeLDp/UPx27MjcVdcIPi33AD3DJS2e1sKMR99w72RGCrHxSL71/8GgCmJSofshxBCbCnUxwtfPz4EyybFgsfpOlM7Tu2rxL4lo/C3PsHODoUQQjwGi8VCn1A5XrunN44vG4vPHxmASfFB4HPsm0roFUxJKELcVbivF54e291m20vJqYTeaMHgKEW7r22j/cT4/slh+Nf4ng2eSRD3Q/+7hBDipt577z08/vjjmDt3LuLi4rBu3Tp4eXnhq6++cnZohBBCPFyYwgufPzIAV16fiCPPj8HkPsHoEdT+BDgA/OPO7iioqrNxhE2L9hPjHkqAE0K6KA6bhSdGdcPORcPbNOuGMwVIBfj8kQH48MF+Dh19SAghpCE+l4274gKx9u9JOPnSWKycFo/+4d4238+z43pgWr8Qm2+XEOI6Hr8j2qbXoFqDGSeyVJAKeRgcpYDSW9jqOg8MCMXPT9+BfuE+NouDuC5KgBNCiBsyGAxITU3FuHHjrO+x2WyMGzcOycnJjZbX6/VQq9UN/hBCCCH2xmKxEKbwwocP9sUdMf4d2kavYBkWj4mxcWSNcdgsvHN/AvUQJ4R0eb2VcuxePALzhkc5O5Qm3ZcUin3PjsJdcYHODoUQQsgtvL34+PuQCPzw1HAc+Pdo/OPOGIR4izq93TlDI/D0WPtfzxNCnIvPZePNe/vYfLsqrQEnslQorNKhV5AU/cO9m5xu/anR3fDWjASI+I1LshH3RE9vCCHEDZWXl8NsNiMwsOFDo8DAQBQXFzdaftWqVZDL5dY/YWFhjgqVEEIIAZfDhtyrY/W7DCYLfjpbZOOIGuKwWfjwwb5Iiuia9XMJIeR2Qh4Hr0yJw5b5gxEka320jCMEy4XYMHcgVt+f2OHfCYQQQhwjyk+Mf43viSPPj8HWBUPwwIBQSATcdm/nnkQlXp3SGyxW1ynPQQjpuAGRCptOhX67S8U1SMutAo/NQt8wOQZF+iDUR4Rlk2Lx/MRYams8TPt/KxFCCHE7y5Ytw5IlS6yv1Wo1JcEJIYR0CZeK1EjJqbTZ9sR8Dj54sB+ultQgv7IWMhEP0/uFomcHp2gnhBBXNqK7H/Y8cwde2nkeP9u5M1FLZg0Kx4t/i4VUSIlvQgjpSthsFoZE+2JItC9W3BOP3y4W44e0AhzJKIOFaXndkT38sfr+RLDZlJAixJM8O647ciq02JVeaLd9aAxmpOdVAwCeHtsdT4zqZrd9EddFCXBCCHFDfn5+4HA4KCkpafB+SUkJgoKCGi0vEAggEAgcFR4hhBBiM72CZQiSCVGs1rVrvSg/MeJD5PjzWjlUWoP1/YRQb9wVF0hT7xJCPIa3Fx8fz+qHcb0C8MrOC6jRm2y2bT6XDT8xHwoJH75iAXzFfPhK+FCIBfCV8OEr5iNM4YUegdTJiBBCujoRn4OpfUMwtW8IStU67EovxPdp+bhcXNNo2X7h3lj39/5UXogQD8RisfD2fQmorDXi8NUyu+1HyGPj74Mj8IwdR5wT10YJcEIIcUN8Ph9JSUnYv38/pk2bBgCwWCzYv38/Fi9e7NzgCCGEEBvic9kY0d0P36Xmg80CxscFYWQPf1TXGXGpSI3TeZXIU9UBAO5OCEbPQCn6hntjRIwfWCwWTGYLTmapcCyzAgAwJVHpzMMhhBCnYLFYuLdfKAZGKrDk2zM4maVqcjk+hw2FNYnNh59EAIX45r8bJrZ9JQKI+RyaapIQQjxQgEyIx0dG47E7onCxSI0f0gqwK70A5RoDugdIsP7RgfDiU2qCEE8l4HKwad4glNXocfx6BY5lViA5sxzZFbUd3iaPw0K4wgvR/hIMiPDBAwPC4CPm2zBq0tXQbxlCCHFTS5YswZw5czBgwAAMGjQIH3zwAbRaLebOnevs0AghhBCbenJ0NwyI8MHwGD+EKbwafGa2MNhzvhhRfmLEKWWN1uVy2BgW44dhMX6OCpeQTjt8+DDeeecdpKamoqioCDt27LB2egTQbMLx7bffxnPPPdfkZ2azGa+99hq2bNmC4uJiKJVKPProo3j55Zet29NoNFi6dCl27tyJiooKREVF4emnn8bChQttfozEOUJ9vPDN40Ow43QBjGaLdcS2r1gAhYQPqYBLCW1CCCFtxmKx0FspR2+lHMsmxeJIRjlig6Xw9qKkFCEE8JcKMCVRae2IXlhVh6xyLYxmC0xmBiaLBQYzA9ON10bLjb/NFpgsDHgcNqL8vBDlJ0GYjwhcDs0qQf5CCXBCCHFTM2fORFlZGV555RUUFxejb9++2LNnDwIDaUpXQggh7qWbvwTd/CVNfsZhszA5IdjBERFiX1qtFomJiZg3bx6mT5/e6POiooa1nH/99VfMnz8fM2bMaHabb731FtauXYuNGzeid+/eSElJwdy5cyGXy/H0008DqO9g+ccff2DLli2IjIzEb7/9hqeeegpKpRL33HOPbQ+SOA2HzcJ9SaHODoMQQoib4XLYGBMb4OwwCCEuTOktgtJb5OwwiJugBDghhLixxYsX05TnhBBCCCFuZtKkSZg0aVKznwcFBTV4vWvXLowZMwbR0dHNrnPs2DFMnToVkydPBgBERkbim2++wcmTJxssM2fOHIwePRoAsGDBAnz66ac4efIkJcAJIYQQQgghhLgMmg+AEEIIIYQQQghxUyUlJfj5558xf/78FpcbNmwY9u/fj6tXrwIAzpw5g6NHjzZItA8bNgy7d+9GQUEBGIbBgQMHcPXqVYwfP77Z7er1eqjV6gZ/CCGEEEIIIYQQe/KYEeAMwwAA3WwT4gZufo9vfq+J7VGbSYj7oDbT/qjNJMS9uFu7uXHjRkil0ianSr/V0qVLoVarERsbCw6HA7PZjDfeeAOzZ8+2LrNmzRosWLAAoaGh4HK5YLPZ+PzzzzFy5Mhmt7tq1SqsWLGi0fvUZhLiHtytzXQ1dJ1JiHuhNtO+qM0kxL10ts30mAR4TU0NACAsLMzJkRBCbKWmpgZyudzZYbglajMJcT/UZtoPtZmEuCd3aTe/+uorzJ49G0KhsMXlvv32W/zvf//D119/jd69eyM9PR3PPPMMlEol5syZA6A+AX78+HHs3r0bEREROHz4MBYtWgSlUolx48Y1ud1ly5ZhyZIl1tcFBQWIi4ujNpMQN+MubaaroetMQtwTtZn2QW0mIe6po20mi/GQ7kYWiwWFhYWQSqVgsVjW99VqNcLCwpCXlweZTObECLs+Ope2QeexdQzDoKamBkqlEmw2VXKwh+baTHfmid89TzxmwPOOm9pM+3N2m+lpP9OuiP4PnMvW57+rtZssFgs7duzAtGnTGn125MgRjBw5Eunp6UhMTGxxO2FhYVi6dCkWLVpkfW/lypXYsmULLl++jLq6OsjlcuzYscNaJxwAHnvsMeTn52PPnj1titfZbaY7ojbIcehcN9bV2syuhp5nuiY6/87Vlc8/tZn2ZevrzK78s9YV0fl2rK5wvjvbZnrMCHA2m43Q0NBmP5fJZC77n9zV0Lm0DTqPLaNekvbVWpvpzjzxu+eJxwx41nFTm2lfrtJmetLPtKui/wPnsuX5d5d288svv0RSUlKryW8AqK2tbfRQgcPhwGKxAACMRiOMRmOLy7SFq7SZ7ojaIMehc92Qu7SZroieZ7o2Ov/O1VXPP7WZ9mOv68yu+rPWVdH5dixXP9+daTM9JgFOCCGEEEIIIYS4A41Gg2vXrllfZ2VlIT09HQqFAuHh4QDqe/Rv374d7777bpPbGDt2LO69914sXrwYADBlyhS88cYbCA8PR+/evXH69Gm89957mDdvHoD6ByOjRo3Cc889B5FIhIiICBw6dAibNm3Ce++9Z+cjJoQQQgghhBBC2o4S4IQQQgghhBBCSBeSkpKCMWPGWF/frLE9Z84cbNiwAQCwdetWMAyDWbNmNbmNzMxMlJeXW1+vWbMGy5cvx1NPPYXS0lIolUo88cQTeOWVV6zLbN26FcuWLcPs2bOhUqkQERGBN954AwsXLrTDURJCCCGEEEIIIR3j8QlwgUCAV199FQKBwNmhdHl0Lm2DziMhzuGJ3z1PPGbAc4+buC/6mXY++j9wLk88/6NHjwbDMC0us2DBAixYsKDZz7Ozsxu8lkql+OCDD/DBBx80u05QUBDWr1/fnlCJA3jid8BZ6FwTV0E/i85F59+56PwTR6GfNcei8+1YnnC+WUxrd82EEEIIIYQQQgghhBBCCCGEEEJIF8B2dgCEEEIIIYQQQgghhBBCCCGEEEKILVACnBBCCCGEEEIIIYQQQgghhBBCiFugBDghhBBCCCGEEEIIIYQQQgghhBC3QAlwQgghhBBCCCGEEEIIIYQQQgghbsHjE+A///wzBg8eDJFIBB8fH0ybNq3B56dOncLYsWPh7e0NHx8fTJgwAWfOnHFOsC6spfO4YcMGsFisJv+UlpY6L2gX1drPJFB/ThMSEiAUChEQEIBFixY5PlBCuqg33ngDw4YNg5eXF7y9vZtcJjc3F5MnT4aXlxcCAgLw3HPPwWQyNVjm4MGD6N+/PwQCAWJiYrBhwwb7B29jn3zyCSIjIyEUCjF48GCcPHnS2SF12OHDhzFlyhQolUqwWCzs3LmzwecMw+CVV15BcHAwRCIRxo0bh4yMjAbLqFQqzJ49GzKZDN7e3pg/fz40Go0Dj4KQlq1atQoDBw6EVCpFQEAApk2bhitXrjRYpri4GA8//DCCgoIgFovRv39/fP/9906K2L2sXbsWCQkJkMlkkMlkGDp0KH799Vfr5zqdDosWLYKvry8kEglmzJiBkpISJ0bsXlo6/yqVCv/4xz/Qs2dPiEQihIeH4+mnn0Z1dbWToyak41q6Lzxz5gxmzZqFsLAwiEQi9OrVCx9++GGr27x69SqmTp0KPz8/yGQyjBgxAgcOHGiwTFP37Vu3brX14bkMZ53nttxvEAK0/DNaUVGBiRMnQqlUQiAQICwsDIsXL4ZarW52e9nZ2Zg/fz6ioqIgEonQrVs3vPrqqzAYDA44mq7F1uceaNvzCFLPHuef7vk9iy2eE91zzz0IDw+HUChEcHAwHn74YRQWFra67+TkZNx5550Qi8WQyWQYOXIk6urqbHl4LsdZ59tTn4HY4nzfpNfr0bdvX7BYLKSnp7e436723MOjE+Dff/89Hn74YcydOxdnzpzBn3/+iYceesj6uUajwcSJExEeHo4TJ07g6NGjkEqlmDBhAoxGoxMjdy2tnceZM2eiqKiowZ8JEyZg1KhRCAgIcGLkrqe1cwkA7733Hl566SUsXboUFy5cwO+//44JEyY4KWJCuh6DwYD7778fTz75ZJOfm81mTJ48GQaDAceOHcPGjRuxYcMGvPLKK9ZlsrKyMHnyZIwZMwbp6el45pln8Nhjj2Hv3r2OOoxO27ZtG5YsWYJXX30VaWlpSExMxIQJE7psxyStVovExER88sknTX7+9ttv46OPPsK6detw4sQJiMViTJgwATqdzrrM7NmzceHCBezbtw8//fQTDh8+jAULFjjqEAhp1aFDh7Bo0SIcP34c+/btg9FoxPjx46HVaq3LPPLII7hy5Qp2796Nc+fOYfr06XjggQdw+vRpJ0buHkJDQ/Hf//4XqampSElJwZ133ompU6fiwoULAIBnn30WP/74I7Zv345Dhw6hsLAQ06dPd3LU7qOl819YWIjCwkKsXr0a58+fx4YNG7Bnzx7Mnz/f2WET0iGt3RempqYiICAAW7ZswYULF/DSSy9h2bJl+Pjjj1vc7t133w2TyYQ//vgDqampSExMxN13343i4uIGy61fv77B/XtTnbLdgbPOc1vuNwgBWv8ZZbPZmDp1Knbv3o2rV69iw4YN+P3337Fw4cJmt3n58mVYLBZ8+umnuHDhAt5//32sW7cOL774oiMOqcuwx7kHWn8eQerZ6/zTPb9nscVzojFjxuDbb7/FlStX8P333yMzMxP33Xdfi/tNTk7GxIkTMX78eJw8eRKnTp3C4sWLwWa7dyrOWefbU5+B2OJ83/T8889DqVS2ab9d7rkH46GMRiMTEhLCfPHFF80uc+rUKQYAk5uba33v7NmzDAAmIyPDEWG6vLacx9uVlpYyPB6P2bRpkx0j63raci5VKhUjEomY33//3YGREeKe1q9fz8jl8kbv//LLLwybzWaKi4ut761du5aRyWSMXq9nGIZhnn/+eaZ3794N1ps5cyYzYcIEu8ZsS4MGDWIWLVpkfW02mxmlUsmsWrXKiVHZBgBmx44d1tcWi4UJCgpi3nnnHet7VVVVjEAgYL755huGYRjm4sWLDADm1KlT1mV+/fVXhsViMQUFBQ6LnZD2KC0tZQAwhw4dsr4nFosbXWMpFArm888/d3R4HsHHx4f54osvmKqqKobH4zHbt2+3fnbp0iUGAJOcnOzECN3bzfPflG+//Zbh8/mM0Wh0cFSEdE5H7rEZhmGeeuopZsyYMc1+XlZWxgBgDh8+bH1PrVYzAJh9+/ZZ37v9OspdOfM8t+V+g5CO/ox++OGHTGhoaLvWefvtt5moqKh2rePOHHHum3seQex3/ume37N15DlRU3bt2sWwWCzGYDA0u8zgwYOZl19+2SZxd1WOPN/0DKRz5/uXX35hYmNjmQsXLjAAmNOnTze7n6743MO9u520IC0tDQUFBWCz2ejXrx+Cg4MxadIknD9/3rpMz5494evriy+//BIGgwF1dXX48ssv0atXL0RGRjoveBfSlvN4u02bNsHLy6vV3juepi3nct++fbBYLCgoKECvXr0QGhqKBx54AHl5eU6MnBD3kpycjD59+iAwMND63oQJE6BWq62j/JKTkzFu3LgG602YMAHJyckOjbWjDAYDUlNTGxwDm83GuHHjuswxtEdWVhaKi4sbHK9cLsfgwYOtx5ucnAxvb28MGDDAusy4cePAZrNx4sQJh8dMSFvcnN5ZoVBY3xs2bBi2bdsGlUoFi8WCrVu3QqfTYfTo0U6K0j2ZzWZs3boVWq0WQ4cORWpqKoxGY4N2JjY2FuHh4W7Zrjrb7ee/KdXV1ZDJZOByuQ6OjpDO6cg9NlD/M3/r74Pb+fr6omfPnti0aRO0Wi1MJhM+/fRTBAQEICkpqcGyixYtgp+fHwYNGoSvvvoKDMPY5NhciTPPc1vuNwjpyM9oYWEhfvjhB4waNapd+2rt59rTOPLck8bsdf7pnp/cqi3PiW6nUqnwv//9D8OGDQOPx2tymdLSUpw4cQIBAQEYNmwYAgMDMWrUKBw9etQux9FV2Ot8A/QMpCltPd8lJSV4/PHHsXnzZnh5ebW63a743MNjE+DXr18HALz22mt4+eWX8dNPP8HHxwejR4+GSqUCAEilUhw8eBBbtmyBSCSCRCLBnj178Ouvv9KDlBvach5v9+WXX+Khhx6CSCRyZKgury3n8vr167BYLHjzzTfxwQcf4LvvvoNKpcJdd91F9ZoIsZHi4uIGD6MAWF/fnLawuWXUanWXqOlTXl4Os9nc5DHcPgWmO7h5TC0db3FxcaOyHFwuFwqFwi3PCen6LBYLnnnmGQwfPhzx8fHW97/99lsYjUb4+vpCIBDgiSeewI4dOxATE+PEaN3HuXPnIJFIIBAIsHDhQuzYsQNxcXEoLi4Gn89vVMvRXdtVZ2nu/N+uvLwcr7/+Ok1pSbqkjtxjHzt2DNu2bWvxZ57FYuH333/H6dOnIZVKIRQK8d5772HPnj3w8fGxLvef//wH3377Lfbt24cZM2bgqaeewpo1a2x7kC7Amee5LfcbhLTnZ3TWrFnw8vJCSEgIZDIZvvjiizbv59q1a1izZg2eeOIJm8bflTnq3JOm2ev80z0/uVVbnhPd9MILL0AsFsPX1xe5ubnYtWtXs9u99ef38ccfx549e9C/f3+MHTu22frLnsBe5xugZyBNacv5ZhgGjz76KBYuXNigY1Br2+1qzz3cLgG+dOlSsFisFv/crHcDAC+99BJmzJiBpKQkrF+/HiwWC9u3bwcA1NXVYf78+Rg+fDiOHz+OP//8E/Hx8Zg8eXKXSHB0hi3P462Sk5Nx6dIlj6rHZ8tzabFYYDQa8dFHH2HChAkYMmQIvvnmG2RkZODAgQPOPExCnKqt3zNCCHEXixYtwvnz57F169YG7y9fvhxVVVX4/fffkZKSgiVLluCBBx7AuXPnnBSpe+nZsyfS09Nx4sQJPPnkk5gzZw4uXrzo7LA8RlvOv1qtxuTJkxEXF4fXXnvNOYES0gR73WOfP38eU6dOxauvvorx48c3u3+GYbBo0SIEBATgyJEjOHnyJKZNm4YpU6agqKjIutzy5csxfPhw9OvXDy+88AKef/55vPPOO7Y/IXbSVc4z8Vz2+Bl9//33kZaWhl27diEzMxNLlixpUywFBQWYOHEi7r//fjz++OM2P1ZX40rn3hPR+Sdd1XPPPYfTp0/jt99+A4fDwSOPPNLs7Dg3f36feOIJzJ07F/369cP777+Pnj174quvvvp/9u47vK3y+gP4996rvSVb3tvOJtMZJCFQIOzQFsosK9AfZZQ9WqAto9AGSlug7Bl2gaTMMsIKkL33cGLHe9vae9z394dsxbJkW3bsOHHO53l4WktXV1eK8+a97znvOYfzso9a/fm+AVoDGainn34aTqcT995773BfypAacduY77zzTixcuLDXY4qKiqI3Hl13DMjlchQVFaGmpgYA8O6776Kqqgpr1qwBz/PRx4xGIz755BNccsklQ/MhjgCD+T129corr2DKlClxJdZGssH8LjMzM+OOMZvNSE1NTfh9E3KsSPbvWTIyMjKwfv36mMeam5ujz3X+b+djXY/R6XRHRXWL1NRUCIKQ8DN0fsaRpPMzNTc3R8fRzp+nTJkSPaalpSXmdaFQCBaLZUR+J+TodtNNN+F///sffvrpJ+Tk5EQfr6iowDPPPIOdO3diwoQJAIDJkydjxYoVePbZZ/HCCy8M1yWPGDKZLJpJXlpaig0bNuCpp57CxRdfjEAgAJvNFpMNPVLH1eHS0/f/4osvAgCcTifOPPNMaLVafPTRR72WyiPkcBuKe+zdu3fj1FNPxW9/+1v86U9/6vXc33//Pf73v//BarVCp9MBAJ577jl88803eOONN3DPPfckfN2sWbPw8MMPw+/3Qy6X9/Uxh93R8D0nc79BRq6h+B3NyMhARkYGxo4dC5PJhHnz5uHPf/5zzL1Pdw0NDTj55JMxZ84cvPTSSwP/QEeRI+W7P1YN9/dP9/ykq2TWiTqlpqYiNTUVo0ePxrhx45Cbm4u1a9cmbMWUaO0eAMaNG3dMr90P1fdNayCJJfN9f//991izZk3c/H769Om47LLL8MYbbyQ879G27jHiAuBmsxlms7nP40pLSyGXy1FWVoYTTjgBABAMBlFVVYX8/HwAgMfjAc/z4Dgu+rrOnzuzeUaqwfweO7lcLnzwwQdYtGjRkFzzkWowv8u5c+cCAMrKyqIL3haLBW1tbXHfNyHHkmT/niVj9uzZ+Otf/4qWlpZoeaxvvvkGOp0uOoGdPXs2vvjii5jXffPNNz32IT3SyGQylJaW4rvvvsMvf/lLAJEs1e+++w433XTT8F7cECgsLERGRga+++676ETP4XBEdxACkT9Tm82GTZs2RZO0vv/+e4iiiFmzZg3XpRMSgzGGm2++GR999BF++OEHFBYWxjzv8XgAIJq42UkQhBE/dx0uoijC7/ejtLQUUqkU3333HX71q18BiMzXampqjpp/G45Gnd8/EBnXzzjjDMjlcnz66adQKBTDfHWExBrse+xdu3bhlFNOwVVXXYW//vWvfZ63p38jeJ7v9d+IrVu3wmg0HhXBb+Do+J6Tud8gI9dQrLd11fl71vnvYyL19fU4+eSToztru/++jlRHwnd/LBvu75/u+UlXyawTJdLX71lBQQGysrJQVlYW8/i+fftw1llnDc7FH4WG6vumNZDEkvm+//3vf+ORRx6JvqahoQFnnHEG3n///R7HxKNy3YMdw2699VaWnZ3Nli1bxvbu3ct+85vfsLS0NGaxWBhjjO3Zs4fJ5XJ2ww03sN27d7OdO3eyyy+/nOn1etbQ0DDMV3/k6Ot77PTKK68whULBrFbr8FzoUSCZ7/IXv/gFmzBhAlu1ahXbsWMHW7BgARs/fjwLBALDeOWEHD2qq6vZli1b2EMPPcQ0Gg3bsmUL27JlC3M6nYwxxkKhEDvuuOPY6aefzrZu3cq++uorZjab2b333hs9x4EDB5hKpWJ3330327NnD3v22WeZIAjsq6++Gq6P1W/vvfcek8vl7PXXX2e7d+9mv/3tb5nBYGBNTU3DfWkD4nQ6o3+WANi//vUvtmXLFlZdXc0YY+zRRx9lBoOBffLJJ2z79u3sF7/4BSssLGRerzd6jjPPPJNNnTqVrVu3jq1cuZKNGjWKXXrppcP1kQiJc8MNNzC9Xs9++OEH1tjYGP3P4/EwxhgLBAKspKSEzZs3j61bt46Vl5ezf/zjH4zjOPb5558P89Uf/e655x72448/ssrKSrZ9+3Z2zz33MI7j2Ndff80YY+z6669neXl57Pvvv2cbN25ks2fPZrNnzx7mqx45evv+7XY7mzVrFps4cSIrLy+P+fsRCoWG+9IJ6be+7gt37NjBzGYzu/zyy2N+31taWqLnWLduHRszZgyrq6tjjDHW2trKUlJS2Pnnn8+2bt3KysrK2F133cWkUinbunUrY4yxTz/9lL388stsx44dbP/+/ey5555jKpWK3X///Yf/SzgMhut7TuZ+gxDG+v4d/fzzz9lrr73GduzYwSorK9n//vc/Nm7cODZ37tzoObr/jtbV1bGSkhJ26qmnsrq6upjfbXLQUHz3jPW9HkEihur7p3v+Y8uhrhOtXbuWPf3002zLli2sqqqKfffdd2zOnDmsuLiY+Xw+xlhkTB0zZgxbt25d9H2feOIJptPp2JIlS9j+/fvZn/70J6ZQKFh5efnh/xIOo+H4vo/lNZDBWAftqrKykgFgW7ZsiT6W6Pf7aFv3OKYD4IFAgN15550sLS2NabVaNn/+fLZz586YY77++ms2d+5cptfrmdFoZKeccgpbs2bNMF3xkSmZ75ExxmbPns1+/etfD8MVHj2S+S7tdju75pprmMFgYCaTiZ133nmspqZmmK6YkKPPVVddxQDE/bd8+fLoMVVVVeyss85iSqWSpaamsjvvvJMFg8GY8yxfvpxNmTKFyWQyVlRUxBYvXnx4P8ggePrpp1leXh6TyWRs5syZbO3atcN9SQO2fPnyhH+uV111FWOMMVEU2Z///GeWnp7O5HI5O/XUU1lZWVnMOdrb29mll17KNBoN0+l07Oqrr6aFCHJESfQ7DiBm/Nm3bx87//zzWVpaGlOpVGzSpEnszTffHL6LHkGuueYalp+fz2QyGTObzezUU0+NBr8ZY8zr9bIbb7yRGY1GplKp2HnnnUeLyYOot++/p38DALDKysrhvXBCBqCv+8IHHngg4e97fn5+9JjOvxdd/w5s2LCBnX766cxkMjGtVsuOP/549sUXX0Sf//LLL9mUKVOYRqNharWaTZ48mb3wwgssHA4fjo992A3X98xYcvcbhPT1O/r999+z2bNnM71ezxQKBRs1ahT7wx/+ELPxpPvv6OLFi3v8N5McNBTfPWPJrUeQofv+6Z7/2HKo60Tbt29nJ598MjOZTEwul7OCggJ2/fXXxyRVdAYNu/8dXrRoEcvJyWEqlYrNnj2brVix4nB85GE1XN/3sboGMhjroF0lCoAn+r6PtnUPjrFeOsgTQgghhBBCCCGEEEIIIYQQQgghR4ljo8kLIYQQQgghhBBCCCGEEEIIIYSQEY8C4IQQQgghhBBCCCGEEEIIIYQQQkYECoATQgghhBBCCCGEEEIIIYQQQggZESgATgghhBBCCCGEEEIIIYQQQgghZESgADghhBBCCCGEEEIIIYQQQgghhJARgQLghBBCCCGEEEIIIYQQQgghhBBCRgQKgBNCCCGEEEIIIYQQQgghhBBCCBkRKABOCCGEEEIIIYQQQgghhBBCCCFkRKAAOCGEEEIIIYQQQgghhBBCCCGEkBGBAuCEEEIIIYQQQgghhBBCCCGEEEJGBAqAE0IIIYQQQgghhBBCCCGEEEIIGREoAE4IIYQQQgghhBBCCCGEEEIIIWREoAA4IYQQQgghhBBCCCGEEEIIIYSQEYEC4IQQQgghhBBCCCGEEEIIIYQQQkYECoATQgghhBBCCCGEEEIIIYQQQggZESgATgghhBBCCCGEEEIIIYQQQgghZESgADghhBBCCCGEEEIIIYQQQgghhJARgQLg5LBbuHAhCgoKhvsy+uWHH34Ax3H44YcfhvtSCCHksOM4Dg8++OBwXwYhhBzxCgoKsHDhwuG+DEIISdqROM8bzmuicZwQciSisYkQQg4PGm9HFgqAE0IIIYQQQgghhBCsXr0aDz74IGw223BfCiGEEEIIOcLQXJEcTSTDfQGEHA1OPPFEeL1eyGSy4b4UQgg57LxeLyQSmjIQQgghhIw03ed5q1evxkMPPYSFCxfCYDAM34URQgiJKisrA8/TPjZCyPAb6XNFGm9HFlrNJiQJPM9DoVAM92UQQsiwoPGPEEIIIWRkOlLmeaIoIhAIHDHXQwghw40xBp/PB6VSCblcPtyXQwghxwQab0cWSmUgg87pdOK2225DQUEB5HI50tLScNppp2Hz5s09vsbtduPOO+9Ebm4u5HI5xowZg3/84x9gjEWPOe6443DyySfHvVYURWRnZ+OCCy6IeezJJ5/EhAkToFAokJ6ejuuuuw5WqzXmtQUFBViwYAFWrlyJmTNnQqFQoKioCG+++WbMcYl6gK9YsQIXXngh8vLyIJfLkZubi9tvvx1er7e/XxkhhCStrzH2Zz/7GY477jhs2rQJc+bMgVKpRGFhIV544YWY8wQCAdx///0oLS2FXq+HWq3GvHnzsHz58rj37N6H8cEHHwTHcSgvL49mfOr1elx99dXweDxD+vkJIQTofSz897//DUEQYkqy/fOf/wTHcbjjjjuij4XDYWi1WvzhD3+IPpbsHJIxhkceeQQ5OTlQqVQ4+eSTsWvXroTXarPZcNttt0XnuSUlJXjssccgimL0mKqqKnAch3/84x946aWXUFxcDLlcjhkzZmDDhg2D9K0RQo5mQzXudZ3nPfjgg7j77rsBAIWFheA4DhzHoaqqCgsXLoz+3P2/rvNEv9+PBx54ACUlJdH75N///vfw+/0xn4fjONx000145513MGHCBMjlcnz11VcJP3t1dTVuvPFGjBkzBkqlEikpKbjwwgtRVVUVc9zrr78OjuOwatUq3HHHHTCbzVCr1TjvvPPQ2toac2x/xnFCCOlNb+PzAw88AKlUGjcGAcBvf/tbGAwG+Hw+AAfXKJctW4bp06dDqVTixRdfjD7XtSetxWLBXXfdhYkTJ0Kj0UCn0+Gss87Ctm3bDstnJoQcm3qbKy5evBinnHIK0tLSIJfLMX78eDz//PNx50g2HtPTvLPz/QBg+/btWLhwIYqKiqBQKJCRkYFrrrkG7e3tcded7DomjbcjC+0AJ4Pu+uuvx9KlS3HTTTdh/PjxaG9vx8qVK7Fnzx5MmzYt7njGGH7+859j+fLl+M1vfoMpU6Zg2bJluPvuu1FfX48nnngCAHDxxRfjwQcfRFNTEzIyMqKvX7lyJRoaGnDJJZdEH7vuuuvw+uuv4+qrr8Ytt9yCyspKPPPMM9iyZQtWrVoFqVQaPba8vBwXXHABfvOb3+Cqq67Ca6+9hoULF6K0tBQTJkzo8XMuWbIEHo8HN9xwA1JSUrB+/Xo8/fTTqKurw5IlSwbjqySEkDjJjLFWqxVnn302LrroIlx66aX44IMPcMMNN0Amk+Gaa64BADgcDrzyyiu49NJLce2118LpdOLVV1/FGWecgfXr12PKlCl9XstFF12EwsJCLFq0CJs3b8Yrr7yCtLQ0PPbYY0P5FRBCSK9j4bx58yCKIlauXIkFCxYAiCQu8jyPFStWRM+xZcsWuFwunHjiidHHkp1D3n///XjkkUdw9tln4+yzz8bmzZtx+umnIxAIxFynx+PBSSedhPr6elx33XXIy8vD6tWrce+996KxsRFPPvlkzPHvvvsunE4nrrvuOnAch7///e84//zzceDAgZj5KyHk2DNU415X559/Pvbt24f//Oc/eOKJJ5CamgoAMJvNuO666zB//vyY47/66iu88847SEtLAxBJIvr5z3+OlStX4re//S3GjRuHHTt24IknnsC+ffvw8ccfx7z++++/xwcffICbbroJqampKCgoSHhdGzZswOrVq3HJJZcgJycHVVVVeP755/Gzn/0Mu3fvhkqlijn+5ptvhtFoxAMPPICqqio8+eSTuOmmm/D+++9Hj0l2HCeEkL70Nj5fccUV+Mtf/oL3338fN910U/Q1gUAAS5cuxa9+9auYyhdlZWW49NJLcd111+Haa6/FmDFjEr7ngQMH8PHHH+PCCy9EYWEhmpub8eKLL+Kkk07C7t27kZWVNeSfmxBy7Oltrvj8889jwoQJ+PnPfw6JRILPPvsMN954I0RRxO9+97uY8yQTj3nrrbfi3v9Pf/oTWlpaoNFoAADffPMNDhw4gKuvvhoZGRnYtWsXXnrpJezatQtr164Fx3Exrx/IOiaNt0c5Rsgg0+v17He/+12Pz1911VUsPz8/+vPHH3/MALBHHnkk5rgLLriAcRzHysvLGWOMlZWVMQDs6aefjjnuxhtvZBqNhnk8HsYYYytWrGAA2DvvvBNz3FdffRX3eH5+PgPAfvrpp+hjLS0tTC6XszvvvDP62PLlyxkAtnz58uhjne/X1aJFixjHcay6urrHz08IIYeirzH2pJNOYgDYP//5z+hjfr+fTZkyhaWlpbFAIMAYYywUCjG/3x/zWqvVytLT09k111wT8zgA9sADD0R/fuCBBxiAuOPOO+88lpKSMtCPRgghSettLAyHw0yn07Hf//73jDHGRFFkKSkp7MILL2SCIDCn08kYY+xf//oX43meWa1Wxljyc8iWlhYmk8nYOeecw0RRjB533333MQDsqquuij728MMPM7Vazfbt2xdzznvuuYcJgsBqamoYY4xV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odPp8N///peyxQkhQyrZMTYrKwuPPfYYqqqqMHr0aLz//vvYunUrXnrpJUilUgDAggUL8OGHH+K8887DOeecg8rKSrzwwgsYP348XC7XcH1EQgjpU7Jj4bx58/Doo49Cr9dj4sSJACILkmPGjEFZWRkWLlwYc95k55Bmsxl33XUXFi1ahAULFuDss8/Gli1b8OWXX8ZlgN9999349NNPsWDBAixcuBClpaVwu93YsWMHli5diqqqKsoaJ4T0aajGvUQ6kyX/+Mc/4pJLLoFUKsW5556LW265Ba2trfj973+P9957L+Y1kyZNwqRJk3DFFVfggw8+wPXXX4/ly5dj7ty5CIfD2Lt3Lz744AMsW7YM06dP7/fnX7BgAd566y3o9XqMHz8ea9aswbfffhvTf7w/+jOOE0JIb5Idn6VSKS655BI888wzEAQBl1566SG974IFC/CXv/wFV199NebMmYMdO3bgnXfeialqQQghQyHRXPHEE0+ETCbDueeei+uuuw4ulwsvv/wy0tLS0NjY2O/3aGtrw4033ojx48dDLpfj7bffjnn+vPPOg06nw4knnoi///3vCAaDyM7Oxtdff43KyspB+ZydaLw9ulEAnAwqlUqFG2+8EV9//TU+/PBDiKKIkpISPPfcc7jhhhsSvobneXz66ae4//778f7772Px4sUoKCjA448/jjvvvDPu+JycHMyZMwerVq3C//3f/0WDOV298MILKC0txYsvvoj77rsPEokEBQUFuPzyyzF37txD/pxSqRSfffYZbrnlFixatAgKhQLnnXcebrrpJkyePPmQz08IIYkkO8YajUa88cYbuPnmm/Hyyy8jPT0dzzzzDK699troMQsXLkRTUxNefPFFLFu2DOPHj8fbb7+NJUuW4IcffhiGT0cIIclJdizsDATNmTMHPM/HPF5WVpawD26yc8hHHnkECoUCL7zwApYvX45Zs2bh66+/xjnnnBN3rT/++CP+9re/YcmSJXjzzTeh0+kwevRoPPTQQ9Dr9UPwDRFCRpqhHPe6mzFjBh5++GG88MIL+OqrryCKIiorK9Ha2opwOIw77rgj7jUPPPAAJk2aBJ7n8fHHH+OJJ57Am2++iY8++ggqlQpFRUW49dZbMXr06AF9/qeeegqCIOCdd96Bz+fD3Llz8e233+KMM84Y0PmA5MdxQgjpTX/WQa+8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4u655x488cQTA+5z4MABFBYWAgDuuusu3HDDDaivr8e6detwzTXX4OOPPx43142hHg8ANDc3Y/ny5bjkkktw4403jnYTh2w4x0QIIWT8ueWWW7B3796wGlaTWUFBASorK2E2m/Hee+9h1apV+O677+LdLDKFBQIBlJeX47HHHgMAzJ49G3v37sVLL71EAfAT8I9//ANvvfUW3n77bRQVFaGyshJ33HEHDAYDnVdCSETR+ggzZszATTfdFNqvuLgYer0eS5YsQU1NDXJzc+PY6vGpsbERt99+O7788kuIxeJ4N2dSiOWc0ud04plqY7GRQOO54aHr8vD1zSBVUlKCiooKZGZm4h//+AckEsmIvQ8FwPuQyWTIy8tDXl4e5s+fj/z8fLz22mtYu3ZtvJs2ov773/+io6MDGRkZoW1+vx933nknnnnmGdTV1cWvcWMkJycHOp0O1dXVkyoArtPpwOfzQ7Npe02fPp3+6BPceeeduPbaawfcJycnJ/R/nU4HnU6HadOmYfr06UhPT8fmzZuxYMECpKSkoL29Pey5vT+npKSMeNsjGerxtLS04LTTTsPChQvxyiuvhO03Ho4HGPoxDSQlJQVbt24N2xaPY4qFTqcDj8eL+DsYb20djt5jaG9vh16vD21vb29HaWlpnFpF4mGyf9ZjNdm/E7feeis+/vhjfP/990hLSwttT0lJgcfjgclkCpvJPBl+/0KhEHl5eQCAsrIybNu2DX/4wx9w2WWXTdpjJuObXq+POCb65z//GacWTQ533XUX7rnnntAE8+LiYtTX12P9+vUUAB8hk/1vJJl6ovURXn755X77VlRUAAhmbaPAYn87duxAR0cH5syZE9rm9/vx/fff4/nnn8fnn39O/a4hGuycut3ufplD6XM6vk3FsdhIoPHc8NB1eeSo1WpMmzYN1dXVOOOMM0bsvFEN8AEEAgG43e54N2PEXX311di9ezcqKytD/wwGA+666y58/vnn8W7emGhqakJ3d3fYgHIyEAqFmDt3LqqqqsK2Hzp0CJmZmXFqFRkvEhMTUVhYOOC/vjWw++rNLtB7TVywYAG+//57eL3e0D5ffvklCgoKxixd+FCOp7m5GaeeeirKysrw+uuvg2XD//yNh+MZ6jENZsGCBdizZw86OjpC27788ksolcp+N4TjTSgUoqysDF9//XVoWyAQwNdf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ESNGoNVqycjI4Fe/+hWNjY3xc7766itkMhnvvvtuu8/56quvIpPJ+P777w/7XQlDSznUDRCOLBdccAF79uzhtdde47HHHiMlJQWA1NRUoDlw/M477/C73/0Ok8nE//3f/3HhhRdSVlZGcnIyAGvXrmXlypVccskl5OTkUFJSwrPPPstJJ53Ejh070Ov1PWrTE088wbnnnssvfvELQqEQr7/+Oj/96U/54IMPOOussxLO7U77tm7dymmnnUZqair3338/kUiE++67j/T09L5+fYIgHEEO1x925IYbbiAjI4OFCxeyatUqXnjhBSwWCytXriQvL4+HH36Yjz76iL/+9a9MnDiRBQsWAM0BlnPPPZevvvqKq666imOOOYZPP/2U2267jcrKSh577LGE+3z55Ze8+eabXH/99aSkpHQ4aAWora1lzpw58QFramoqH3/8MVdddRVut5ubbroJgH/+85/ceOONXHTRRfz+978nEAiwZcsWVq9ezaWXXnrY7+LPf/4z9957LxdffDG//vWvqa+v58knn+SEE05g48aNWCyWPvw/IQjC0e6KK67gzTff5Je//CVz5sxhxYoV7caA0PMx6A033IDVauW+++6jpKSExx9/nOuvv5433ngjfs6f/vQnHnroIc4880zOPPNMNmzYwGmnnUYoFEq41oEDB3jvvff46U9/SmFhIbW1tTz//POceOKJ7Nixg6ysrIH5cgRBEIbAPffcw8MPP8zzzz/P1VdfPdTNEQRB6Bdd9W0PPvggarWaW2+9lWAwiFqtZseOHX0a/0WjUebPn8/s2bP529/+xrJly/j73/9OUVERv/3tb+PnXXvttSxZsoQrr7ySG2+8keLiYp566ik2btzId999N2yy0wmCcGTqaA6yJ+URP/zwQ372s58xadIkFi1ahMPh4KqrriI7O7vXbfr88885cOAAV155JRkZGWzfvp0XXniB7du3s2rVKmQyGSeddBK5ubksXbqU888/P+H9S5cupaioiLlz5/a6DcIgkQShn/31r3+VAKm4uDjhOCCp1Wpp37598WObN2+WAOnJJ5+MH/P5fO2u+f3330uA9PLLL8ePffXVVxIgffXVV/Fjl19+uZSfn5/w3kOvFwqFpIkTJ0qnnHJKr9p33nnnSVqtViotLY0f27Fjh6RQKCTxT0oQhLY66w/z8/Olyy+/PP56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yiuZN28eW7duZenSpQk7xwVBEIab7vTDh5ozZw7vv/8+Z555JhdddBHvvfceKpVqkFsuCILQucHq2wZj/HfiiSdy7bXXsmjRIjZt2sRpp52GSqVi7969vPXWWzzxxBNcdNFF/XY/QRCODr3pJ9sym8389Kc/5cknn0Qmk1FUVMQHH3zQrh43NJeL+MlPfsKxxx7LlVdeicPh4KmnnmLixIkJQfHuXjMpKYkTTjiBv/zlL4TDYbKzs/nss88oLi7utL0LFiyI95UdLSgShi8RABf63cyZM3nwwQd57rnn+OSTT+JpJ7vriSeeQKFQsHTpUgKBAMceeyzLli2L7+DpiVNOOYUXX3yRRx55hJtuuonCwkIeffRRSkpKeh2snjx5Mp9++ik333wzf/rTn8jJyWHhwoVUV1eLALggCAn62h92l1wu57///S9/+tOfeOONN1i8eDEFBQX89a9/5ZZbbun1ddPT01mzZg0PPPAA77zzDs888wzJyclMmDCBRx99NH7etddey9KlS/nHP/6B1+slJyeHG2+8kXvuuSd+TmffhcFg4M4772T06NE89thj8Zrhubm5nHbaaZx77rm9/2IEQTiiJScn8+6773LzzTdz++23U1hYyKJFi9i7d2/CQ/fLL79MRkYGr732Gu+++y6nnnoqb7zxBmPGjEGr1cbP688xaKuHHnoIrVbLc889F19Q9Nlnn3HWWWclnHf33XfT1NTEq6++yhtvvMG0adP48MMPufPOO3t9b0EQhIHW3X74UKeccgpvvvkmF154Ib/85S959dVXkctFgkJBEIaH/uzbujJY47/nnnuO6dOn8/zzz3P33XejVCopKCjgsssu49hjj+3XewmCcHTobT/Z1pNPPkk4HOa5555Do9Fw8cUX89e//pWJEycmnHfOOefw2muvcf/993PnnXcyatQolixZwksvvcT27dt7dc1XX32VG264gaeffhpJkjjttNP4+OOPycrK6rCt55xzDlarlVgsJuYpf2Bk0qF7/QVBEARBEARBEI5gmzZtYurUqbzyyiv84he/GOrmCIIgCIIgCIIgCILQTccccwypqal8/vnnA36vSCRCVlYW55xzDi+++OKA30/oP2KJrSAIgiAIgiAIR6yO6jA+/vjjyOVyTjjhhCFokSAIgiAIgiAIgiAIhxMOh4lEIgnHli9fzubNmznp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CdGvDdWx7lAct8oYVMaSoncc6R6ajN8650j3YPPy8lq9r7dy5co+bPXA0JH72311vSYB8AHm2muvZdmyZbz++uts3ryZ0047jblz51JQUADAI488whNPPMFzzz3HqlWriIqKYt68eTQ0NPRxy9vm8XiYOHEiTz/9dKvPd+ScLr/8crZu3cqyZcv46KOP+Prrr7n++ut76xSO6Ejn6PF4mD17Ng8//HCbx7j11lv517/+xbvvvsvy5cspLCzkggsu6Kkmd0p751lXV8e6deu49957WbduHe+//z47duzg3HPPjdivv/8uRcd0x3ehyZ133klycnJPN/moddc53n///RQVFYX/+8UvftEbze+Q7jjHv//971xxxRVcffXVbNy4kW+//ZbLLrust06hQ7p6nrNmzYr4HRYVFXHttdeSlZXFtGnTevNURD+0fPlybrjhBlauXMmyZcvw+/2cdtppeDyeiP2uu+66iO/QUAzepKam8tBDD7F27Vq+//57TjnlFH70ox+xdetWYGCMhXrDkT4nkO9Ta9asWcPzzz/PhAkTIrbL96p/2759O8FgkOeff56tW7fyxz/+keeee45f/vKX4X3cbjennXYaGRkZrF27lkcffZTf/OY3vPDCC33Y8r7n8/m46KKL+PnPf97q84FAgLPOOgufz8d3333Hq6++yiuvvMKvf/3rXm5p//HOO++waNEilixZwrp165g4cSLz5s2jtLS0r5smRL81VMe6Q3HcOtTHoDKWFL3hSPfQZPzWNR25B/vZZ59F7DN16tQ+aOnA095n26fXa4oYMOrq6hSNRqN89NFHEdunTJmi/OpXv1KCwaCSmJioPProo+HnXC6XYjAYlLfeequ3m9spgPLBBx+EH3fknLZt26YAypo1a8L7/Oc//1FUKpVSUFDQa23vqMPPsbnc3FwFUNavXx+x3eVyKTqdTnn33XfD23744QcFUFasWNGDre289s6zyerVqxVA2bdvn6IoA+93KTqmM9+FJv/+97+VnJwcZevWra3+bfQXnT3HjIwM5Y9//GPPNq6bdOYc/X6/kpKSorz44ou90MLu0ZXvaxOfz6fExcUp999/fw+0UAx0paWlCqAsX748vO3EE09Ubr755r5rVD/mdDqVF198cUCOhXpT0+ekKPJ9ak1NTY0yYsQIZdmyZRGfj3yvBqZHHnlEycrK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9PR0vvvuOxYvXkxRURGPP/54m69ds2YN3333HZdeeimpqank5eXx7LPPctJJJ7Ft2zbMZvNRt0cIMfjFxcW16Mf8fj+33npreJX1u+++S11dHT//+c+JiYlh9erVPPnkkxw4cIB333034rWBQIAzzjiDE044gUceeYQ33niDG2+8kaioKH71q19x+eWXc8EFF/Dcc89x5ZVXMnPmTLKysiKOceONN+JwOPjNb37Djh07ePbZZ9m3b1940lFrZJwqhBBCCCGEEEII0b0kAC4GvGXLluHz+fjPf/5DbGxsq/s4nU7y8vIiUk5ed9115OTk8OSTT/KXv/ylt5orhBgiTCYT55xzDu+99x5PPPEEGo0GgOLiYpYvXx5eVX3zzTeTnp7OmjVrMBgMAPzf//0fs2fP5q677moRAI+JieG///1vOJASDAZ54oknqK6uxm63U1tby0033cS1117LCy+8EH7dVVddxahRo3jwwQd54YUXSEhI4Mc//nH4eUVROPfcczEYDLzyyitHfb6PPfYYe/bsYf369YwYMQKAn/70pyQnJ/Poo49y2223kZaW1uprzzrrLC688MKIbeeccw4zZ87k73//O1dcccVRt0cIMfhFRUVF9GMAN9xwA7W1tSxbtgyAhx9+GJPJFH7++uuvZ/jw4fzyl78kPz+f9PT08HMNDQ38+Mc/ZvHixQBcdtllJCcn85Of/IS33nqLSy65BIBTTz2VnJwcXn311RYZMvR6PZ9//jk6nQ6AjIwM7rzzTv71r39x7rnntnoeMk4VQgghhBBCCCGE6F6SAl0MeA6HA4B//OMfbabZ1Wg04ZuKwWCQyspKGhsbmTZtGuvWreutpgohhphLLrmE0tJSvvrqq/C29957j2AwyCWXXEJlZSVffPEFF198MTU1NZSXl1NeXk5FRQXz5s1j165dFBQURBzz+uuvj1hFePzxxxMIBNi3bx8QmhTkcrlYsGBB+Hjl5eVoNBpmzJjRZkrd3/72t3z00Ue88sorjBkz5qjP9d133+X444/H6XRGvO/cuXMJBAJ8/fXXbb62eXDK7/dTUVHB8OHDcTgc0kcLITrstdde45lnnuGRRx7h5JNPBiL7F4/HQ3l5ObNmzUJRFNavX9/iGNdee234Z4fDwahRo4iKiuLiiy8Obx81ahQOh4O9e/e2eP31118fDn4D/PznP0er1fLvf/+7zXbLOFUIIYQQQgghhBCie8kKcDHgXXLJJbz44otce+213H333cyZM4cLLriACy+8ELX60ByPV199lT/84Q9s374dv98f3n546kohhOgup59+Ona7nXfeeYc5c+YAofTnkyZNYuTIkaxevRpFUbj33nu59957Wz1GaWkpKSkp4cfNVytCaOUgEK4xu2vXLgBOOeWUVo9ns9labPvkk0+47777WLx4MfPnzz/KsyT8vps2bSIuLq7V50tLS9t8bX19PUuXLuXll1+moKAARVHCz1VXV3eqPUKIoWXDhg387Gc/Y8GCBSxatCi8PT8/n1//+tf885//bFGL+/D+xWg0tujD7HY7qampLdKX2+32FscDwhkwmlgsFpKSksjLy2u3/TJOFUIIIYQQQgghhOg+EgAX/VpbtRIDgUD4Z5PJxNdff82XX37Jxx9/zCeffMI777zDKaecwn//+180Gg1//etfWbhwIeeddx533HEH8fHxaDQali5dyp49e3rrdIQQQ4zBYOC8887jgw8+4JlnnqGkpIRvv/2WBx98ECCcteL2229n3rx5rR5j+PDhEY+bUqkfrilo3HTM119/ncTExBb7abWR//Tn5uZy+eWXc+qpp/LAAw90+Nya98NN73vqqady5513trr/yJEj2zzWL37xC15++WVuueUWZs6cid1uR6VScemll7aZ2UMIIZpUVVUxf/58Ro4cyYsvvhjeHggEOPXUU6msrOSuu+4iJyeHqKgoCgoKWLhwYYv+pa3+9Uj9blfJOFUIIYQQQgghhBCie0kAXPRrTqcTl8vVYntTqt8marWaOXPmMGfOHB577DEefPBBfvWrX/Hll18yd+5c3nvvPbKzs3n//fcjgupLlizp6VMQQgxxl1xyCa+++iqff/45P/zwA4qihOvIZmdnA6DT6Zg7d263vN+wYcMAiI+PP+Ix6+vrueCCC3A4HLz11lsRWTOatNYP+3w+ioqKWrxvbW1tp87jvffe46qrruIPf/hDeFtDQ0Or/b8QQjQXDAa5/PLLcblcfPbZZ5jN5vBzmzdvZufOnbz66qtceeWV4e1N9cF7wq5du8Lp1wFqa2spKirizDPPbPM1Mk4VQgghhBBCCCGE6F5SA1z0a8OGDaO6uppNmzaFtxUVFfHBBx+EH1dWVrZ43aRJkwDwer3AoZU7zVfqrFq1ihUrVvREs4UQImzu3LlER0fzzjvv8M477zB9+vRwStv4+HhOOukknn/++RYBZYCysrKjfr958+Zhs9l48MEHI9LotnbMn/3sZ+zcuZMPPvggnEr9cMOGDWtRv/uFF15osQL84osvZsWKFXz66actjuFyuWhsbGyzzRqNpsVKyieffLLFewghxOHuu+8+Pv30U956660W6cJbG/8pisKf/vSnHmvPCy+8ENH3PvvsszQ2NnLGGWe0+RoZpwohhBBCCCGEEEJ0L1kBLvq1Sy+9lLvuuovzzz+fm266ibq6Op599llGjhzJunXrALj//vv5+uuvOeuss8jIyKC0tJRnnnmG1NRUZs+eDcDZZ5/N+++/z/nnn89ZZ51Fbm4uzz33HGPGjKG2trYvT1EIMcjpdDouuOAC3n77bTweD7///e8jnn/66aeZPXs248eP57rrriM7O5uSkhJWrFjBgQMH2Lhx41G9n81m49lnn+WKK65gypQpXHrppcTFxZGfn8/HH3/Mcccdx1NPPcXHH3/Ma6+9xvz589m0aVPERCOLxcJ5550HwLXXXsvPfvYz5s+fz6mnnsrGjRv59NNPiY2NjXjfO+64g3/+85+cffbZLFy4kKlTp+LxeNi8eTPvvfceeXl5LV7T5Oyzz+b111/HbrczZswYVqxYwWeffUZMTMxRnbsQYmjZvHkzv/3tbznhhBMoLS3lr3/9a8Tzl1xyCcOGDeP222+noKAAm83G3//+91Zrd3cXn8/HnDlzuPjii9mxYwfPPPMMs2fP5txzz23zNTJOFUIIIYQQQgghhOheEgAX/VpMTAwffPABixYt4s477yQrK4ulS5eya9eucAD83HPPJS8vj5deeony8nJiY2M58cQTue+++7Db7QAsXLiQ4uJinn/+eT799FPGjBnDX//6V959912++uqrPjxDIcRQcMkll/Diiy+iUqm4+OKLI54bM2YM33//Pffddx+vvPIKFRUVxMfHM3nyZH7961936v0uu+wykpOTeeihh3j00Ufxer2kpKRw/PHHc/XVVwOHVoL//e9/5+9//3vE6zMyMsIB8Ouuu47c3Fz+8pe/8Mknn3D88cezbNky5syZE/Eas9nM8uXLefDBB3n33Xd57bXXsNlsjBw5MqI/bs2f/vQnNBoNb7zxBg0NDRx33HF89tlnbdZFF0IIgIqKChRF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egUD4BSVUqnEY4891iIlMnUdjyn1h7vuuitqyvOhbKh/14b6+wOG/nsc6u+Phhb+vvYOHtfeweNKRERERERERAAgiB0pwE1ERERERERERERERERERDTASfp7AERERERERERERERERERERD2BAXAiIiIiIiIiIiIiIiIiIhoSGAAnIiIiIiIiIiIiIiIiIqIhgQFwIiIiIiIiIiIiIiIiIiIaEhgAP8M99dRTmD59OjQaDUwmU9Q2giC0+Fm5cmVEmzVr1mDixIlQKpXIysrCihUren/wA1RHjmlpaSnmzZsHjUaD+Ph4/PKXv0QgEIhow2NK1Hn79u3D/PnzERsbC4PBgJkzZ+Lbb7+NaNOR799AtGbNmqjnY0EQsGnTpnC77du346yzzoJKpUJqaiqeffbZfhx1533++eeYOnUq1Go1zGYzFixYELF+sH5+J2RkZLT4/J555pmINoP9M6TBZ9myZZg8eTL0ej3i4+OxYMECFBcXR7TxeDxYtGgRYmJioNPpcMUVV6C6urqfRjw4vPLKKxg3bhwMBgMMBgMKCgrw73//O7yex7RnPPPMMxAEAffdd194GY8tERERERER0ZmNAfAznM/nw5VXXomf//znbbZbvnw5Kisrwz+nBiRKSkowb948nHfeeSgqKsJ9992HW2+9FV999VUvj35gau+YBoNBzJs3Dz6fDz/88APefvttrFixAo8++mi4DY8pUddccsklCAQC+Oabb1BYWIjx48fjkksuQVVVFYCOff8GqunTp0echysrK3HrrbciMzMTkyZNAgA4HA7Mnj0b6enpKCwsxHPPPYff/OY3eP311/t59B3z4Ycf4oYbbsBNN92Ebdu24fvvv8e1114bXj+YP79TPfHEExGf49133x1eN9g/Qxqc1q5di0WLFuHHH3/EqlWr4Pf7MXv2bLhcrnCbxYsX49NPP8X777+PtWvXoqKiApdffnk/jnrgS0lJwTPPPIPCwkJs3rwZ559/PubPn49du3YB4DHtCZs2bcJrr72GcePGRSznsSUiIiIiIiI6w4lEoiguX75cNBqNUdcBED/66KNWt33ggQfEMWPGRCy7+uqrxTlz5vTgCAef1o7pF198IUokErGqqiq87JVXXhENBoPo9XpFUeQxJeqK2tpaEYC4bt268DKHwyECEFetWiWKYse+f4OFz+cT4+LixCeeeCK87OWXXxbNZnPEe3nwwQfFUaNG9ccQO8Xv94vJycniX//611bbDIXPLz09XfzjH//Y6vrB/BnS0FFTUyMCENeuXSuKoijabDZRLpeL77//frjNnj17RADi+vXr+2uYg5LZbBb/+te/8pj2gMbGRnHEiBHiqlWrxHPOOUe89957RVHk7ysRERERERERiSJngFOHLFq0CLGxsZgyZQreeustiKIYXrd+/XrMmjUrov2cOXOwfv36vh7moLB+/XqMHTsWCQkJ4WVz5syBw+EIzwjiMSXqvJiYGIwaNQrvvPMOXC4XAoEAXnvtNcTHxyM/Px9Ax75/g8W//vUvHDt2DDfddFN42fr163H22WdDoVCEl82ZMwfFxcVoaGjoj2F22JYtW1BeXg6JRIK8vDwkJiZi7ty52LlzZ7jNUPn8nnnmGcTExCAvLw/PPfdcRAr3wfwZ0tBht9sBABaLBQBQWFgIv98fcW2SnZ2NtLQ0Xpt0UDAYxMqVK+FyuVBQUMBj2gMWLVqEefPmtbhm5rElIiIiIiIiIll/D4AGvieeeALnn38+NBoNvv76a9x5551wOp245557AABVVVURwQgASEhIgMPhgNvthlqt7o9hD1itHa8T69pqw2NK1DpBEPCf//wHCxYsgF6vh0QiQXx8PL788kuYzWYAHfv+DRZvvvkm5syZg5SUlPCyqqoqZGZmRrQ79f2dOA4D0aFDhwAAv/nNb/D8888jIyMDf/jDH3Duuedi3759sFgsQ+Lzu+eeezBx4kRYLBb88MMPWLp0KSorK/H8888DGNyfIQ0NoVAI9913H2bMmIHc3FwAzb97CoUCJpMpom1CQsKg+e71lx07dqCgoAAejwc6nQ4fffQRcnJyUFRUxGPaDStXrsSWLVuwadOmFuv4+0pEREREREREnAE+BD300EMQBKHNn71793a4v0ceeQQzZsxAXl4eHnzwQTzwwAN47rnnevEdDDw9fUyJqOM6+v0TRRGLFi1CfHw8/vvf/2Ljxo1YsGABLr30UlRWVvb322hVV84vR48exVdffYVbbrmln0bdcR19f6FQCADw61//GldccQXy8/OxfPlyCIKA999/v5/fRds68xkuWbIE5557LsaNG4c77rgDf/jDH/CXv/wFXq+3n98FUbNFixZh586dWLlyZX8PZUgYNWoUioqKsGHDBvz85z/H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", "text/plain": [ - "<Figure size 1440x1440 with 50 Axes>" + "<Figure size 2000x2000 with 69 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -754,7 +770,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 45, "metadata": {}, "outputs": [ { @@ -763,20 +779,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 11, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "<Figure size 432x288 with 1 Axes>" + "<Figure size 640x480 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -787,7 +801,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 46, "metadata": {}, "outputs": [ { @@ -796,20 +810,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 12, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "<Figure size 576x576 with 1 Axes>" + "<Figure size 800x800 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -848,7 +860,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 47, "metadata": {}, "outputs": [ { @@ -1002,7 +1014,7 @@ "[3 rows x 51 columns]" ] }, - "execution_count": 13, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -1025,7 +1037,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 48, "metadata": { "scrolled": false }, @@ -1034,7 +1046,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/var/folders/yk/yj8t31wd1sd_9w0f9cfg5jv80000gn/T/ipykernel_82121/3440732423.py:2: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.\n", + "C:\\Users\\bryan\\AppData\\Local\\Temp\\ipykernel_31064\\3440732423.py:2: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.\n", " china_copy = china.append(china_sars)\n" ] }, @@ -1044,20 +1056,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 14, + "execution_count": 48, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9EAAALDCAYAAAASWYNXAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd5hkZZU/8O+tnFPn3D0550AWBERRDKCygDnHVdTVZdVV0FV3/a24RtR1xQCCKCAZyWlCT+7pyd3TOXdXzun+/uiZZno6Vb4Vvp/n4WGmq+reMzPdVffc97znCKIoiiAiIiIiIiKiBcmkDoCIiIiIiIioUDCJJiIiIiIiIkoQk2giIiIiIiKiBDGJJiIiIiIiIkoQk2giIiIiIiKiBDGJJiIiIiIiIkoQk2giIiIiIiKiBDGJJiIiIiIiIkqQQuoAzhePxzE4OAij0QhBEKQOh4iIiIiIiIqcKIrweDyora2FTDb/WnPeJdGDg4NoaGiQOgwiIiIiIiIqMX19faivr5/3OUkl0d/+9rdx++23T/va8uXLcfz4cQDA5Zdfjpdeemna45/85Cdx1113JXwOo9EIYDJ4k8mUTHhERERERERESXO73WhoaJjKR+eT9Er06tWr8eyzz75+AMX0Q3z84x/HHXfcMfV7nU6X1PHPlnCbTCYm0URERERERJQziWwpTjqJVigUqK6unvNxnU437+NEREREREREhSrp7tynTp1CbW0tFi1ahFtuuQW9vb3THr/nnntQXl6ONWvW4LbbboPf75/3eKFQCG63e9p/RERERERERPkoqZXo7du34+6778by5csxNDSE22+/HZdeeina29thNBpx8803o6mpCbW1tWhra8PXvvY1nDhxAg8++OCcx/z+978/Y581ERERERERUT4SRFEUU32x0+lEU1MTfvSjH+GjH/3ojMeff/55XHnllejo6MDixYtnPUYoFEIoFJr6/dkN3S6Xi3uiiYiIiIiIKOvcbjfMZnNCeWhaI64sFguWLVuGjo6OWR/fvn07AMybRKvVaqjV6nTCICIiIiIiIsqJpPdEn8vr9aKzsxM1NTWzPn7w4EEAmPNxIiIiIiIiokKS1Er0V77yFVx33XVoamrC4OAgvvWtb0Eul+Omm25CZ2cn7r33Xlx77bUoKytDW1sbbr31Vlx22WVYt25dtuInIiIiIiIiypmkkuj+/n7cdNNNmJiYQEVFBS655BLs2rULFRUVCAaDePbZZ/HjH/8YPp8PDQ0NuOGGG/CNb3wjW7ETERERERER5VRajcWyIZkN3URERERERETpSiYPTWtPNBEREREREVEpYRJNRERERERElCAm0UREREREREQJYhJNRERERERElCAm0UREREREREQJYhJNRERERERElCAm0UREREREREQJYhJNRERERERElCAm0UREREREREQJYhJNRERERERElCAm0UREREREREQJYhJNRERERERElCAm0UREREREREQJYhJNRERERERElCAm0UREREREREQJYhJNRERERERElCAm0UREREREREQJYhJNRERERERElCCF1AEQEREREVFmiaKIkyNePHd8BK+cHMeAMwCHP4zlVUasq7fAoFGgz+6HWiHD29bV4uIlZRAEQeqwiQqCIIqiKHUQ53K73TCbzXC5XDCZTFKHQ0REREQkuSFXAO0Dbpwa9eDUiBcapQzbW8qgVysQisbgDkThDkbQ7/Dj5IgXp0Y8cPgjCR9/Xb0Zt169DJcvq2AyTSUpmTyUSTQRERERUR4RRRE9E360dtmxu8uO1u4J9NkDOTn3pkYLPvWGxbh8eSVUCu78pNKRTB7Kcm4iIiIiIgnF4yI6xryTCXOXHa1dExhxhySJZX+vE5/44z5YdUpsa7EBAP7lmuVYUmmUJB6ifMQkmoiIiIgoy0RRxKsd4zg14sWYN4RRd+jM/4OIxkRYdEoc6nciEsuPIlGHP4Knj4wAmEys//api9BYppM4KqL8wCSaiIiIiChL4nERzxwbwU+eO4Ujg+55n1umV6HSpMaxIU+OokvMmCeEa378Mj5wYRO2NNvQVKZDS7keSjnLvak0cU80EREREVEW7OycwO2PHsHx4cSTYptehVhchCuQeFMwKTSX6fDVN6/AW9ZUo9fux9f+1oaTI16YtUpcvaoK12+qw4pqXstT4WBjMSIiIiIiCT10oB//8kAbovHkL7XX1ZnRNuDKQlSZt7TSgGhcRNe4b8Zjb11bg1uvXsr91FQQmEQTEREREUlAFEXc9dJp/OdTx9M6zrZmK1q7HRmKSjqCAFy6tAJvWVMNuSDguvW10KrkUodFNAO7cxMRERER5VgsLuKOR4/g9zt7MnC04pjVLIrAyyfH8PLJMQBA24AT333nWomj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", "text/plain": [ - "<Figure size 864x864 with 1 Axes>" + "<Figure size 1200x1200 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1087,7 +1097,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 49, "metadata": {}, "outputs": [], "source": [ @@ -1106,14 +1116,14 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 50, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/var/folders/yk/yj8t31wd1sd_9w0f9cfg5jv80000gn/T/ipykernel_82121/642512976.py:2: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.\n", + "C:\\Users\\bryan\\AppData\\Local\\Temp\\ipykernel_31064\\642512976.py:2: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.\n", " finland_copy = finland.append(finland_aland)\n" ] }, @@ -1123,20 +1133,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 16, + "execution_count": 50, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAdUAAAPHCAYAAAB+ONNOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAADpCklEQVR4nOzdd5xkVZk+8KdyV+6uzrl78vTkLAxZFBBFgqAIhkVdQRRBf7om1t11BXFhRUVB0CVIFGHIOYfJOfdMz3TOoWJXrrq/P3popmd6pqu6q+rcW/V8PzuflZ7qqnc63KfOuee8RyVJkgQiIiKaMrXoAoiIiLIFQ5WIiChFGKpEREQpwlAlIiJKEYYqERFRijBUiYiIUoShSkRElCJa0QUcKx6Po6urC1arFSqVSnQ5RESUYyRJgtfrRUVFBdTq5MaesgvVrq4uVFdXiy6DiIhyXHt7O6qqqpL6HNmFqtVqBTDyj7HZbIKrISKiXOPxeFBdXT2aR8mQXah+NOVrs9kYqkREJMxkbkFyoRIREVGKMFSJiIhShKFKRESUIgxVIiKiFGGoEhERpQhDlYiIKEUYqkRERCnCUCUiIkoRhioREVGKMFSJiIhShKFKRESUIgxVIiKiFGGoEhERpQhDlYiIKEUYqkRERCnCUCUiIkoRhioREVGKMFSJiIhShKFKRESUIgxVIiKiFGGoEhERpQhDlYiIKEUYqkRERCnCUCUiIkoRhioREVGKMFSJiIhShKFKRESUIgxVIiKiFGGoEhERpQhDlYiIKEUYqkRERCnCUCUiIkoRhioREVGKMFSJiIhShKFKRESUIgxVIiKiFGGoEhERpQhDlYiIKEUYqkRERCnCUCUiRZAkCX3eIKKx+HF/t6PdhR//cwfe2t8roDKij2lFF0BENJF/bG7HH986iPahAPRaNWaWWDC71IpZZVZsbXXitb0jYbpmWyeevm41FlTZBVdMuUolSZIkuoijeTwe2O12uN1u2Gw20eUQkWDvHejH1+/fiHiCV6q55Ta8+L3ToFar0lsYZa2p5FBS0791dXVQqVTH/bn++usBAMFgENdffz0KCwthsVhw2WWXobeX0zFENHm/fnFfwoEKAPu6PXhpd3f6CiI6iaRCddOmTeju7h798/rrrwMALr/8cgDATTfdhOeffx5PPvkk3n33XXR1deHSSy9NfdVElPVicQlv7e9FU78v6c/939cOjHvvlSjdpjT9e+ONN+KFF17AwYMH4fF4UFxcjEcffRRf+MIXAAD79+/H3LlzsW7dOnziE58Y9zlCoRBCodDof3s8HlRXV3P6lyhH9XmD+Memdjy2sR2drsCkn+fWSxfgypU1KayMckXGpn+PFg6H8fDDD+Oaa66BSqXCli1bEIlEcO65544+Zs6cOaipqcG6detO+Dy33nor7Hb76J/q6urJlkRECvf39a049da3cPtrB6YUqABwy0v70O2e2nMQJWvSofrMM8/A5XLh61//OgCgp6cHer0e+fn5Yx5XWlqKnp6eEz7PT3/6U7jd7tE/7e3tky2JiBRszbYO3PzMbkSTuYF6Et5gFD/+507IbC0mZblJb6n529/+hgsuuAAVFRVTKsBgMMBgMEzpOYhIuQ73+/BOYz9+/dK+lD/3+wcH8PCGNnzlE7Upf26i8UwqVFtbW/HGG2/g6aefHv1YWVkZwuEwXC7XmNFqb28vysrKplwoEWWfw/0+nHPHu2l9jVte3IfTZxShrsic1tchAiY5/Xv//fejpKQEF1544ejHli1bBp1OhzfffHP0Y42NjWhra8Mpp5wy9UqJKOvUF5lx2dKqtL5GIBLDD5/cgViKppWJTibpkWo8Hsf999+Pr33ta9BqP/50u92Ob3zjG/jBD34Ah8MBm82G733vezjllFNOuPKXiOQvHI2jyxWAPxzDrFILtBo14nEJ+3u82NI6hGqHCWfMLJ5Us4WDfT68vvfEay5SZUurE/e+dxjXnTU97a9FuS3pUH3jjTfQ1taGa6655ri/+93vfge1Wo3LLrsMoVAI5513Hv785z+npFAiSr9+bwhrtnXgcP8w2ob8aBvyo8sVGG2+YDFoMbfcigO9PrgDkdHPW1Sdj/+8aB7UKiAuAYuq7FCpxg/ZaCyOza1OvL63F89s64QnGM3EPw2/e/0Azp5TjDll3KpH6cM2hUQEAHAHIjjttrfgTUHInT6zCP998XzUFo7cx/SHo3jvwABe39uLt/b3wumPTPAM6TG33IZnr18NvZZnidCJTSWH2FCfiAAAD69vTUmgAiOrbj/9u/dwyZJKDPhCeP/gAEJR8R2O9nV78Ps3D+BH580RXQplKYYqEWHdoUH87vUDKX3OUDSOxzfJb9/53e8cQrHFgKs+UQudhiNWSi1O/xLluHA0jlN/8xYGfKGJH5xFHGY9LlpUgcuWVmF+pe2E94Ap93D6l4gmTadRwZCD9xiHhsN4YG0LHljbgpklFly6tAoXL6lAud0oujRSsNz7TSKiMaJxKSdD9WgH+3y47ZX9OPU3b+Gdxj7R5ZCC5fZvEhHh/g+bcXhgWHQZsiBJkMWCKlIuhipRDnt2eydue6VRdBmyotPw3ipNHkOVKEc9uqENNz6xne37jvFh06DoEkjBGKpEOeje9w7hZ2t2QV5r/+Xh7+tbsa/bI7oMUiiGKlGOWbOtA7e8tF90GbIVjsbx+bs+xO2vNqJt0C+6HFIY7lMlyiH+cBRn3/4Oej25tSd1Kk6dXoirVtXiUw2lbG+YI7hPlYgScu97hxmoSVp7aBBrDw2iyKLHFcurceXKGlQ7TKLLIpniSJUoRxzq9+Gzf/gAgUhMdCmKplIBZ8wsxlWranDOnBJo2eow63CkSkQnFYrGcMNj2xioKSBJwLsH+vHugX6U2fLwpZXV+NKKGpTZ80SXRjLAt1hEOeDONw5iTxdXtKZajyeIO984iNW3vYVvPbQZ7zT2Ic4tSjmNI1WiLLeldQh/e79ZdBlZLRaX8PreXry+txfVDiO+tKIGVyyvRrHVILo0yjDeUyXKMj3uIDa3DmFzixNbWp3Y3eXmflQBtGoVzptXhqtW1eCU6YU8BUdBeE+VKMfF4hLuefcQHt3Qhk5XQHQ5hJGDCl7c1Y0Xd3VjWpEZX15Vg8uWVqHArBddGqURR6pEWeDudw7htlfY0EHu9Fo1LlxQji+vqsHy2gKOXmVqKjnEhUpECjfgC+HONw6ILoMSEI7GsWZbJy6/Zx3+/dk9osuhNGCoEincS7u6eVyZAj26sQ0uf1h0GZRiDFUihZPXDRxKVCwu4Z3GftFlUIoxVIkU7sqVNZhZYhFdBk3C6/t6RZdAKcZQJVI4vVaNb50xTXQZNAnvNvYjzKn7rMJQJcoCFy4oF10CTYIvFMXG5iHRZVAKMVSJiAR6g1PAWYWhSpQFutjwQbFGVm/zoINswVAlygLP7+wWXQJNUp83hH9u6RBdBqUIQ5VI4QZ9ITy8vlV0GTQFf377EBcsZQmGKpGC9XmD+N5j2zA0zCYCStbpCmDNNo5WswFDlUihXtzZjU/973tYe2hQdCmUAne93YRIjKNVpWOoEimQPxzFD5/cDncgIroUSpH2oQCe3d4lugyaIoYqkQIZdRosrSkQXQal2F1vHUSUo1VFY6gSKZBKpUK53Si6DEqxlkE/nt/J0aqSMVSJFMgfjuKZ7Z2iy6A0+ONbTYjFeUqCUjFUiRSo2x3khTdLHe4fxou7uO9YqRiqRAqkVatEl0BptK3NKboEmiSGKpECbWrhRTdbmfUaXHfWdNFl0CQxVIkUxheK4r+e3yO6DEqTa8+cjhJrnugyaJIYqkQK849N7fAEo6LLoDQos+Xhm6fzbFwlY6gSKUwnT6TJWj86bzaMeo3oMmgKGKpECvPZhTyQPBvNq7DhkiWVosugKWKoEinM4up8VBWw8UO2+fmFc6Hmqm7FY6gSKYxKpcKnG8pEl0EpdOmSSpw6vUh0GZQCDFUihYnE4lh/mCfTZItPNZTiti8sFF0GpQhDlUhh7nnnEPZ2e0SXQSlwxqxi3PXlJdBpeCnOFvxOEinI/h4P/vDWQdFlUAp8YpoDf7l6GQxarvbNJgxVIoWIxOL4f0/uQCTGnr9Kt7QmH3/72gpun8lCDFUihfjbB83Y3clpX6VbUGnHA9eshNmgFV0KpQFDlUgB4nEJD65tEV0GTdGcMiseumYlbHk60aVQmvCt0hR0ugJ4YlM7iq0G1BeaUV9sRrktj3vNKOVah/zodgdFl0FTML3YjL9/YxUKzHrRpVAaMVQnYTgUxV/ePYS/vHcYoWh8zN8ZtGrUFppQX2RGXZEZ9YUj/39akRnFVgNUKgYuJW9Xp1t0CTQFNQ4THvnmJ1BsNYguhdKMoZqEeFzCmm2d+O2r+9HrCY37mFA0jgO9Phzo9R33d0UWPf705aVYNa0w3aVSltnDUFWsCnseHv3WKpTZefJMLuA91QRtbhnCxX/+ED98cscJA3UiA74wbnh8G3whnjBCydndxVBVohKrAY9+6xOoKjCJLoUyhKE6AedwGN99dCu+cM867OyY+oWt1xPCna8fSEFllCskSeKqXwUqNOvx6LdWoa7ILLoUyiCG6gRueHwbXtjZndLnvH9tC/b38CJJielwBuAORESXQUmwG3X4+zdWYUaJVXQplGEM1ZPY0urE+wcHUv68sbiEm5/ZDUniJn6a2IFer+gSKAkqFfDAv6xAQ4VNdCkkAEP1JB7f2Ja2597U4sRTWzvT9vyUPThKVZbV04uwpKZAdBkkCEP1BALhGF7aldpp32Pd+tI+uP28YNLJhY/ZtkXytrDKLroEEoihegL7ezwYDsfS+hqDw2H8z2v70/oapHzzK3mRVhIuTMptDNUTWFydj1X1jrS/ziMb2rCzw5X21yHlaii3ocDEtnZKUWrjftRcxlA9AZVKhZ9fODftryNJwC+e2Y1YnIuWaHxqtQrnzy8XXQYlqIRdk3IaQ/UkFlbl4+LFFWl/nZ0dbjyWxkVRpHyfnlcqugRKEEM1tzFUJ/D/zpsNvTb9X6bfvrIfA77JdWqi7FfNjjyKoFWrUGBiw/xcxlCdQFWBCdesrk/763iCUfzmZS5aovFtahkSXQIloNhq4ClVOS7nQrV1cBjxJO9ffufs6XBk4Limf27p4MWTxtXpDIgugRJQaOEoNdflVKj+/o2DOPN/3sGFf/wAb+ztTbijkS1PhxvPnZnm6kb8Ys1uRGLcl0hjReL8mVACfpsoZ0K1sceLP751EACwr9uDbz60GZfevRYfNiXWhrDcbkxneaMae714cG1LRl6LlIMNIJRhf48HTX3HH/tIuSMnQjUWl/CTp3ciesy077Y2F6766wZcee96bGl1nvDzo7E4fvPyvnSXOep3rx9AjzuYsdcj+dvfzf6/ShCXgG8+uAn9Xi46zFU5EaqPbGjFtjbXCf9+3eFBXHb3WlzzwCbsGefcysc3teNQ/3AaKxxrOBzDr17cm7HXI/njGbzK0TLox9fv3whvkC1Ic1HWh2q3O4DfvtKY0GPf2t+HC//wAa5/ZCsOHjkZpNcTxJ1vZP780xd3duP9g/0Zf12Sp89nYL80pc6eLg++9dBmBCPpbXVK8qMVXUC6NfX5EE5y4c+Lu7rx4q5u1BeZ0e8NCRsl/Puze/DKjafDoNUIeX2Sj2oH96kqzfrDQ/j+49vw56uWQcNtNjkj60eqp88sxj++fQrmVdiQp0vun9s8MCx02q15YBj3vXdY2OuTfJw9uwSfbmBXJaUxG7SIcklwTlFJMjsp2+PxwG63w+12w2ZL7SG/kiSh3xtC65AfHxwcwB/eOgh5/euPZ9Cq8fA3V2FFXfqb+5O8eYMRLPiP10SXQQlQqYAfnzcH1545DSoVR6lKM5UcyvqR6tFUKhVKbHlYUefATZ+ahb9cvQxGnbynVkPROL76t4344GBiW38oe7UO+kWXQAkw6jS45+pluO6s6QzUHJRToXqsT88rwz+vOwVXrqxGkYw7oQQiMVzz4Ca8tb9XdCkkyO5ON7710GbRZdBJ6DQqnDmrGP+87hScN69MdDkkSE5N/55MU58Xn/3jBwhG5Hv/Q6tW4Q9XLsFnFvAYsFwSi0s47ba30M29y7Kj16hx1uxiXLCgDOfMKYXdyHNvs8FUcijrV/8makaJFQ3lNmw9yX5W0aJxCd99dCvuuGIRLllSJbocypD9PR4GqgydNqMI/33xfNQVmUWXQjLCUD1CkiS4A/LfrB2XgJ89vRtnzSpBQQaa/JN4vJ8uL4VmPW7+bAM+v7iC90zpODl9T/Vo7x0cyGjXpKkIRGJ49wAbQ+SCQ/0+3PVWk+gy6IgrV1bjzR+eiYuXVDJQaVwcqQJ4dnsnvv/4dtFlJGVD8xAuXlIpugxKo2gsjusf2QovWxQKN7PEglsuXcCtbTQhjlQBdCjwrMqXd3ezH2yWe3FXN/b3sJG+SAatGj86bzZevOF0BiolhKEK4HMLKxS3as/lj+D2VxPraUzK9PTWTtEl5KwzZxXjB5+ahdduOgPXnz0Dei0vlZQYTv8CqCk0Ye1PzsFre3vwzLYufNA0gFhcVjuNxvXguhZctLgCS2sKRJdCSYrE4lh3aBB7ujyoKzTh9FnFsBg+/nU81O/DezxQQZhPzyvFVatqRZdBCsR9quPo94bwws4uPLO9CzvaXUJqSNSsUgte+N7pfCetEJIk4cktHfj9GwfR6fr4toNeo8YnphfiU3NLYDPq8NtXGsf8PWXWuXNLcO9XlkN9VCP8SCwOTyACVyCCQDiGacVmmPQcl2SjqeQQQ3UCT23pwE/X7EI4Kt+mEDedOwvfP3em6DJoAsFIDL94Zjf+uaVDdCmUgJklFug0argDEbgDkePWMKhUQH2RGRctqsD3PzmTq4GzCEM1zba3u/Dtv29GryckupRxqVTAdWdOx02fmgWdhiNWOWof8uO6R7Zgd6dHdCmUBletqsGvPj9/zMiWlIsN9dNscXU+nv/uaZhbLo+QP5YkAX9+5xC++Jd16HCy6brcvHegH5+76wMGahZ7ZEMbfrZml+gySAYYqgkqseXhiW9/Ap+YJt9l9VvbXPj6/ZsUscgqF8TjEv70dhO+dv9GuPzy79ZFU+MJ8ntMXP2bFFueDg/8y0pc/KcPZbt/sKnPhx5PEJX5RtGlTNmuDjf+9HYTwrE41CoVltcV4KpVNbDmyX/7Uywu4fpHtuKVPT2iS6EMOXcuD5EnhmrS8nQa/PqS+bjs7nWiSzmhLldA8aH6qxf24v8+bB5ziPwb+3rxp7eb8JVP1OJfVtej2GoQV+AEntjUzkDNIWoVcPbsEtFlkAxw+ncSltU68KUV1aLLOKFOBXaIOpo3GMHfPhgbqB//XRR/fucQVt/2Fn7xzC60yfDgbncggttfY2OOXLK8zsEDLggAQ3XS/u38OSiR6UhJ6fsbE5laD0fjeHh9G866/W1877FtcMvonuWru3swNBwWXQZl0Kc49UtHMFQnqcCsx+++uFh0GePqUnio7u1KfJVsXAKe39GFX7+0N40VJefDQzyqLdd8ci6nfmkE76lOwanTC3HH5YvgD0cRjUt4emsndnW6RZel+FDd3OpM+nP+sbkDZ80uwWcWlKehouQo/etPyVlcnY9pxRbRZZBMMFSnQKVS4bJlVaP/fcr0Qpx/5/sCKxqh5OlffziKN/b2Tupzv//4Nuzv8eK6M6fDqNekuLLEOWU0FU3pd9WqGtElkIxw+jeFZpdaZXGftXXQj2AkNuZjzQPDeGFnF9YdGkQ0Jt+Wi2/u60PgmNoTFYlJ+MObB/HJO97BCzu7IKpZmJy/vpRaDrMen11YIboMkhGOVFNIpVLh8uVV+NPbh4TWEYrG8freXjRU2PDSzu7jzuWsKjDimtX1+OKKapgN8vkRGBoO4+/rWqf8PF3uIL776DY8VN+KX36uAfMq7CmoLnGRGJtv5Iofnzdb6KwIyQ97/6ZYh9OPM377NpTQ1MiWp8VVn6jF10+tQ6ktT1gdnmAEf33vMP72QTOGw5MbpZ6IWgWsnlGETzWU4ty5pajIwP7dT9zyJno8wbS/Dom1oNKOZ65fDQ37/WYdNtSXmRsf34ZntneJLiNhOo0Kn19ciW+dPg2zy6zjPkaSJISiceTpJv+uPBqLo8sVROvQMFoH/WgdHPn/G5qH4A5k5j7k/Eobzp1bik81lKKh3Jbyk0VC0RgW/sdrCMn4VCNKjaeuOwXLauXbtpQmbyo5JJ+5vyxyy6ULEJOAF3d2KWLEGolJ+OeWDvxzSwfOmFWMr51Si1hcwqH+YRzq9+Fwvw+H+ofhDkQwp8yKa1bX44okml9EYnE8sr4Vv3/zoPBFPLs7Pdjd6cGdbxxEuT0P58wpwblzS3HK9MIpvWH4yM4ONwM1B1yypJKBSuPiSDWNvMEINrc4s7Jl3e++uAiXLKk66WMkScKb+/pwy0v7cHhgOEOVTY5Rp8HqGUW4ZEklPrOgbNIj2GgsjsX/9fpxZ29S9jDpNXj7/50l9JYJpRePfpMpa54OZ88pwZ+vWopvnzFNdDkp9e/P7kG3+8Rbd/Z0uXHVXzfgmw9tln2gAkAgEsMb+3px/aNbceMT2+Gd5IkjPZ4gAzXLfe+cmQxUOiGGagao1Sr89DNz8e+fbUCKb+EJ4w1G8eN/7jxu20qvJ4gf/3MHPvvHD7D20KCg6qbm2e1d+OwfP8CujuQbeTy+sT0NFZFc1BWacM1pdaLLIBljqGbQNafV429fW44Ke3a8y33/4AAeOxIi/nAUv3/jIM76n3fwj80d4zbDV5LWQT+u+uv6hA59D0VjuOfdQ7js7rW46+2mDFRHovz75xpg0HILDZ0Y76kK4A9H8e2/b8H7B5XfI9ao0+ALy6rw+t7erNxGsry2AI//6yeg1Rz//rN1cBgHe32KuGdMU3fW7GI88C8rRZdBGcDVvwpj0mtxyZLKrAjVQCSGv6+fesMGudrc6sTv3zyIH3569piPP7u9Ez/4xw7ElLC8m6ZMp1Hh5s82iC6DFIDTv4KcNqNIdAmUoLvebsK2to+b/EvSSDtEBmruuGZ1PaazaT4lgKEqSIktDx/829n4ny8sxKVLK1GeJfdZs5EkAfe+d3j0v1sH/TjUz+neXFFsNeC758wQXQYpBKd/BaoqMOHy5SZcvrwakiShddCPdYcH8cSmdmxvd4kuj47y6p4edDj9qCow4aXd3aLLoQz6yflzYM3TiS6DFIIjVZlQqVSoKzLjypU1ePibqzCvIjsXaSlVXAL+35M78Pf1rfj9GwdFl0MZsqQmH5csqRRdBikIQ1WGLAYt7v/6CuTp+O2Rk/WHh3DzM7vZhjCH/Mfn5kHNhvmUBF61ZarElodfX7xAdBlEOWt5bQEWVeeLLoMUhqEqY5ctq+LUE5EgVQXpPyaQsg9DVeZ+dfF8vlsmEqDLlX3NTCj9GKoyZzFosaK2QHQZRDlne4cLwUhMdBmkMAxVBbhkaSUq8zkVRZRJ4Wgcm1qGRJdBCsN9qgowr8KON394JrzBKCRJQlwC4pKEWFyCdOR/R2JxbG934YOmAby4sxtRdvshmrI39/Xh9JnFossgBWGoKkSeToM83clPx5hZasXly6uxp8uDpj5fhiojyl5v7u/FLz/XMOlD6yn3MFSz0Os3nYFgJA6nP4x3D/Tjrrea0Ok68YHiRDS+9qEAmvp8mFlqFV0KKQRDNQupVCoY9RoY9UZcubIGly2twrrDg2gf8uOv7x9Gy+DEZ4QS0Yg39/cxVClhDNUcoNeqceaskftCX1hWhXca+1BbaMZre3rxuzcOCK6OSN7e3NeLa8+cLroMUgiGao7J02lw/vxyAMDcchv6fUE8vL5NcFVE8rWl1QnncBgFZr3oUkgBuKUmx/30grmYVTpyTqROo4JJf/LFUES5Ji4B7xzoE10GKQRHqjnObNDi4W+swit7evDZhRXo9QTxhbvXYjjMTe9EH3ljXx8uWVIlugxSAI5UCSW2PHz1lDo4zHrMLbfhm6dPE10Skay819iPME8nogQwVOk43zy9HgUmHspM9BFvKIrN7K5ECWCo0nGseTr85II5ossgkpU39vG+Kk2MoUrj+uKKGnzvnBlgIxmiEW/u74Uksf0nnRxDlU7oh5+ejWevX42FVXbRpRAJ1zrox6H+YdFlkMwxVOmkFlblY813VuNXF8+HNY+LxSm3vbmvV3QJJHMMVZqQRq3CVz5Ri7d+eBY+s6BMdDlEwrzJ+6o0AYYqJazYasAfvrRktFkEUa7Z3DoElz8sugySMYYqJUWrUeO0GTxfknJTXALeaewXXQbJGEOVknb2HIYq5a43eF+VToKhSkk7bUYRLlvKlm2Um9490I9IjN2VaHwMVUqaSqXCby5bMHqcHFEu8Qaj2MTuSnQCDFWaFJ1Gjf++eD6bQ1BO4ipgOhGGKk1atcOE+iKz6DKIMu6t/QxVGh9DlabEOcztBZR7mgeGsbvTLboMkiGGKk1JvkkvugQiIW5/rVF0CSRDDFWakoZym+gSiIR4p7Efv3x2N/zhqOhSSEbYzJWmxBXg9C/lrgfXteKZ7V34/OIKXL6sGvMrbVBx9V5OY6jSlPS4g6JLIBLKHYjgoXWteGhdK2aXWvGFZVX4/JIKlFjzRJdGAnD6l6akddA/+r9Pn1mER765Cr+6eL7AiojEaez14tcv7cMpt76Fbz64Ca/s7kY4ykYRuYQjVZqSWaVW9HiCuPmzc3Hx4kqoVCqcOr0Q/9zcjh0dXB1JuSkWl/DGvj68sa8PBSYdPr+4El9YVoV5FZweznYqSWZH2Xs8HtjtdrjdbthsXAQjd55gBBqVCmbD2Pdnf36nCb99hasjiY42p2xkevjiJZUoshhEl0MnMJUcYqhSWuzr9uCC378vugwiWdKqVThrdgm+sKwK58wpgV7LO3FyMpUc4vQvpcWcMivKbHno8XAhE9GxonEJb+zrxRv7ekenhy9fXoV5FXbRpdEU8e0RpYVKpcJZs9lwn2giTn8ED6xtwYV/+AAX/P59vLSrW3RJNAUMVUqbM3iKDVFS9nV78J1HtuJ3rx8QXQpNEkOV0mZlvQNaNVc6EiXr928exNqmAdFl0CQkHaqdnZ24+uqrUVhYCKPRiAULFmDz5s2jf+/z+fDd734XVVVVMBqNaGhowD333JPSokkZiiwG3Pe15TDrNaJLIVKcX7+0D/G4rNaRUgKSClWn04nVq1dDp9Ph5Zdfxt69e3HHHXegoKBg9DE/+MEP8Morr+Dhhx/Gvn37cOONN+K73/0unnvuuZQXT/J39uwSPHntqSi3s7sMUTL2dHnwAu+vKk5SW2p+8pOf4MMPP8T77594q8T8+fPxxS9+ETfffPPox5YtW4YLLrgA//3f/z3ha3BLTXbq8wZx0xPb8WHToOhSiBSjttCEN35wJnQa3qnLpKnkUFLfqeeeew7Lly/H5ZdfjpKSEixZsgT33XffmMeceuqpeO6559DZ2QlJkvD222/jwIED+PSnPz3uc4ZCIXg8njF/KPuUWPPwf19fgVX1DtGlEClG66AfT2xqF10GJSGpUD18+DDuvvtuzJw5E6+++iquu+463HDDDXjwwQdHH/PHP/4RDQ0NqKqqgl6vx/nnn48//elPOOOMM8Z9zltvvRV2u330T3V19dT+RSRbBq0G9351OWaVWkSXQqQYv3/zII+XU5Ckpn/1ej2WL1+OtWvXjn7shhtuwKZNm7Bu3ToAwO2334777rsPt99+O2pra/Hee+/hpz/9KdasWYNzzz33uOcMhUIIhUKj/+3xeFBdXc3p3yzW5Qrgkj9/iF5PaOIHExF+dN5sXH/2DNFl5IyMdVQqLy9HQ0PDmI/NnTsXTz31FAAgEAjgZz/7GdasWYMLL7wQALBw4UJs374dt99++7ihajAYYDCwB2Yuqcg34vF/PQUPfNiMF3d1Y8DHM1mJTuYv7x7C1atqYTfpRJdCE0hq+nf16tVobBzbJP3AgQOora0FAEQiEUQiEajVY59Wo9EgHufxR/Sx+iIz/vPz87H+p5/EhQvKRZdDJGueYBT3vHdIdBmUgKRC9aabbsL69etxyy23oKmpCY8++ijuvfdeXH/99QAAm82GM888Ez/60Y/wzjvvoLm5GQ888AAeeughXHLJJWn5B5CyaTVqfOWUWtFlEMneAx+2oM/LXtpyl1SorlixAmvWrMFjjz2G+fPn41e/+hXuvPNOXHXVVaOPefzxx7FixQpcddVVaGhowG9+8xv8+te/xrXXXpvy4ik7DIe4CINoIoFIDHe91SS6DJoAj34joSRJwpfuXY8NzUOiSyGSPZ1Ghbd+eBaqHSbRpWS1jO1TJUqlaCyO215pZKASJSgSk9hsX+Z4nipl3K4ON17Y2YUXd3WjwxkQXQ6RoqzZ3olvnzkds8usokuhcTBUKaNue2U/7n6HqxiJJkuSgNtfa8R9X10uuhQaB6d/KWN2drgYqEQp8PreXmxtc4oug8bBUKWMeW1Pr+gSiLLG7a82TvwgyjiGKmXMgI9tCYlSZe2hQXxwkAeZyw1DlTImHGVXLaJU+p9X90NmuyJzHkOVMsZk0IgugSir7Ohw47kdXaLLoKMwVCljCkx60SUQZZ2fPLULuzrcosugIxiqlDElVp5GRJRqgUgM33hwE7pc3PMtBwxVyhiDjtO/ROnQ5w3hqr9uQPPAsOhSch5DlYgoCzQPDOOSP3+IDYcHRZeS0xiqRERZwuWP4Oq/bcBTWzpEl5KzGKpERFkkEpPwwyd34I7XGhGPc7tNpjFUKWPUKpXoEohyxh/fasINj29DMBITXUpOYahSxlTY80SXQJRTXtjZjSvvW89uZhnEUKWMWVpbgDwdf+SIMmlbmwsX/+lDHOj1ii4lJ/AKRxmTp9NgZgnPgCTKtA5nAJf9eS3eO9AvupSsx1CljKrI5xQwkQjeUBT/8sAmPLm5XXQpWY2hShlVmW8SXQJRzorFJVjzdKLLyGoMVcqo+mKz6BKIctaiKjvOn18muoysxlCljFpWUyC6BKKctYS/f2nHUKWMmltuxexSLlYiEqHQzJOi0o2hShmlUqnwhWVVossgyknWPK3oErIeQ5Uy7hPTCkWXQJSTuEgp/RiqlHFVBUbRJRDlJAtHqmnHUKWMMxv4i00kAqd/04+hShn3tw+aRZdAlJNKrAbRJWQ9vm2hjAlGYvi3p3bi2e1dokshyjlGnQa1hdwnnm4cqVLG/OqFvQxUIkGW1xVAp+ElP934FaaMKefRb0TCcNV9ZjBUKWPeOzAgugSinLWq3iG6hJzAUKWM2N3pxsaWIdFlEOWkynwjWxRmCEOVMuL21xpFl0CUs649azo0apXoMnICQ5XSzhOM4P2DnPolEuGSJZW4elWN6DJyBkOV0q7XHUQsLokugyjnzK+04dZLF0Cl4ig1UxiqlHbTii0w6zWiyyDKKQ6zHvdcvQx5Ov7uZRJDldJOo1bhihXVYz5WYNLBwWOoiNJCo1bhri8vQVWBSXQpOYcdlSgjfvaZuaMbzy9aVIH5lXaEojHc995h3PV2E4KRuOAKibLHzz4zF6dOLxJdRk5SSZIkq5tdHo8HdrsdbrcbNptNdDmUAV2uAD5sGsDBPh/ePziAfd0e0SURKdYlSyrxv1cs4n3UKZhKDnGkSsJV5Btx+fKR6eF4XMKld6/F9naX2KKIFGhehQ23XMKFSSLxnirJilqtQpGFJ2kQJcth1uMvX1kGIxcFCsVQJdnxBCOiSyBSFC5Mkg+GKsmKJEk42OsVXQaRovz0gjlcmCQTDFWSlX5fCE4/R6pEibp4cQW+cVq96DLoCIYqyUogHBNdApFizKuw4dZLF3JhkowwVElWTHot8k060WUQyV6BSYd7rubCJLlhqJKsFFsNeOmG00WXQSRrGrUKf/ryUlQ7uDBJbhiqJDt7utj8gehkfnrBHJw6gwuT5IihSrLz+t4e0SUQyRYXJskbQ5VkZXenG2u2dYoug0iWphebuTBJ5timkGTBH45izbZO/OmtJkRismpHTSQb3zp9GhcmyRxDlYTqcPrx93WteGxjGzzBqOhyiGTtrNklokugCTBUSZimPh8u/tOH8IUYpkQTOWNWMcrseaLLoAnwnioJ8+qeHgYqUQLqCk343ysWiS6DEsBQJWHaBv2iSyCSvSKLAQ9ds4qnNykEQ5WECcfioksgkr1ffX4eagrZ5EEpGKokzA8+NQt5Ov4IEp3IJ6Y5cP78MtFlUBJ4RSNhQtE4ghGOVonGo1YB//7ZedyTqjAMVRLmyS3toksgkq0rV9agocImugxKEkOVhOhyBfDQ2lbRZRDJkjVPix98apboMmgSGKokhDcYRSDCs1OJxnPjubNQyNW+isRQJSHqikwo4LmpRMeZXmzGV0+pFV0GTRJDlYQwaDX42Wfmii6DSHZu/mwDdBpempWK3zkS5vLl1bhsaZXoMohk45w5Jezvq3AMVRLq3y6YDRNP3SCCVq3Czy/k7I3SMVRJqBJrHv7zonmiyyAS7uun1mF6sUV0GTRFDFUS7pIlldCqucGdclehWY/vfXKm6DIoBRiqJJxWo4ZRxylgyl3/77zZsBu5Gj4bMFRJFgrMetElEAnRUG7DFcurRZdBKcJQJVk4ZVqh6BKIhPjl5xqg4e2PrMFQJVn4Cje7Uw66cEE5VvENZVZhqJIszK+04/SZRaLLIMoYg1aNn1wwR3QZlGIMVZKN753D1Y+UO759xjRUO3j4eLZhqJJsrKx34NIllaLLIEq7Mlserj1ruugyKA0YqiQrt1y6ANeeOR1Wg1Z0KURp8//Omw2Tnj/j2YihSrKSp9PgJxfMwX1fW84VkZSV1Crg0/NKRZdBacJQJVn6xLRCTgVTVmqosMGWx0YP2YqhSrJ17VnToeJglbLMqnpuoclmDFWSrenFFpw/r0x0GUQptareIboESiOGKsnad86aIboEopRRqUZWuVP2YqiSrC2osuOL7ItKWWJ2qRX5Jva5zmYMVZK9//z8PDSU20SXQTRlDRX8Oc52DFWSvTydBv9z+UJwhw0pXVOfT3QJlGYMVVKEeRV2XLSoQnQZRFOyp8sDfzgqugxKI4YqKca/rK4XXQLRlMTiEna0u0WXQWnEUCXFWFSdjwWVdtFlEE3J1jan6BIojRiqpCicAial29LKUM1mDFVSlM8uKhddAtGUbDg8iD5vUHQZlCYMVVKUcrsRK+u4eZ6Uazgcw389v1d0GZQmDFVSnHMbSkSXQDQlL+zsxtuNfaLLoDRgqJJihKIxtA/5cbCXe/1I+W5+Zje312QhnpJLinHlveuxtc0lugyilOhwBvD7Nw/ipxfMFV0KpRBHqqQIh/p9DFTKOn99vxl7uzyiy6AUYqiS7EmShP94bo/oMohSLhaX8LM1uxCLS6JLoRRhqJLsbWt34f2DA6LLIEqL7e0uPLKhVXQZlCIMVZI9nZo/ppTdfvtKI3o93LuaDXi1ItmrdhhFl0CUVr5QlLc4sgRDlWTPbtTBauBCdcpuL+/uwRt7e0WXQVPEUCXZU6lUsBl1ossgSrtfPrcHwyHuXVUyhioRkUx0ugL43esHRJdBU8BQJUVw+sOiSyDKiPvXtmDQFxJdBk0SQ5Vkzx2IwB+OiS6DKCNicQlv7OO9VaViqJLsHez1ii6BKKNe3cNQVSqGKsneZh7qTDnmg4MD8AYjosugSWCokuw5h3k/lXJLOBbnFLBCMVRJ9maUWESXQJRxd7x2AAGuJVAchirJXpk9T3QJRBnX4Qzg6W0dosugJDFUSfYMWo3oEoiE6HaxH7DSMFRJ9oaGuWePctMBrnxXHIYqyd47jf2iSyAS4u3GPhzq94kug5LAUCXZisbiuPONA3h8U7voUoiEiMQk/HzNLkgSDzFXCoYqydLQcBiX3b0Wd75xUHQpREKtPzyEJ7dwwZJSMFRJlja1DGFHh1t0GUSycMtL+zDAfsCKwFAlWYnHJTy7vRM/fXqX6FKIZMPlj+C/X9grugxKAEOVZOUnT+/E9x/fjiF2USIa45ntXXj/IBftyR1DlWRDkiT2+SU6iZ+v2Y14nIuW5EwrugAiANjT5cZPntqFw/3DokshStiMEjOMOi1Meg263AG0DwXS+nptQ34c6PNiTpktra9Dk8dQJeE6XQF86S/r4Q1FRZdClLBCsx6H+odx9G6X+iIziq0GNPcPoz9NC4v2dzNU5YyhSsLd9VYTA5UUp9SWh8Fj7v03DwyjeWAYKhUwt9wKs16Lxh4PvKHUNcbvdKV3NExTw1Al4XZ2uESXQJQ0g+7ES1IkCdjXPdJiUKdRYVGVHWoVsLvLg0hsavdEO5z+KX0+pRdDlYQb5iiVFEirViX0uEhMGt1zbdZrsLDKhmAkhr1dHhwbrw6TDnVFZmjUKow8u+qj/xulQmKvS2IwVEm402YWoWWwTXQZREmZTOfA4XAMW46scHeY9ZhebD4SkhJ8oRj293iwtc110udgEwh5Y6iScF89pQ4Pr2eokvxZ9BrUF5vhDkSnvP1raDg8qf3YrYN+BCMx5Ol4JKIccZ8qCTezxAIjLxCkADPLrNjV6UHbkLj7mtG4hN2dbOEpVwxVEk6lUsFm5KQJydv0YjO2TTA1mylb29gkRa4YqiQL5Xaj6BKITsph1osuYdR7BwZEl0AnwFAlWbDmcaRK8tbrkc8CofWHB+EORESXQeNgqJIseILcVkPypYK89odG4xLe3NcrugwaB0OVhAtGYmjs8Ygug+iEJIzc+5eTRzZwxbwcMVRJuJbBYQQjcdFlEJ2UWS+vFepbWp1cBSxDDFUSzqzn/VSSv2KrQXQJx3loXYvoEugYDFUSrqrAiBIZXrCIjlZgks/q3488u70LLn/yDSQofRiqJJxKpcJpM4pEl0F0UjvaXZhWZBZdxhihaBwPrG0RXQYdhaFKsjCz1Cq6BKKTisQlDAyHMLPEIrqUMf7y7mH0eoKiy6AjGKokC/VFJtElEE3IE4jiYJ8PK+sc0KpVmF9hQ0O52APDA5EY7nitUWgN9DGGKsnCijoHZLZjgeiE2p3DsOXpsLvLg73dHug0Yn94n9zSgb1d3JYmBwxVkoVCiwGLq/NFl0GUkG53CENHLRBaUlMgsJqRY+hueWkfpMmcR0cpxVAl2Th7donoEogmZTJHuKXaB00DeKexX3QZOY+hSrJxzhyGKilPrcOIpj6f6DIAAL9+aR+iMTZSEYmhSrIxr8KGTzeUii6DKCnRuCSbAyGa+nx4bFO76DJyGkOVZEOlUuHXlyzAXMGrKYmS0ekKYm6ZfH5m73z9ADxBnmAjCkOVZKXYasCT156CG8+diXqZbbQnGk+BSYdOV0B0GaMGh8P4r+f3ii4jZzFUSXYsBi1uPHcW3vrhmXj2+tX4wrIq0SURnVC1wySrUAWAf27pwFNbOkSXkZPkcSOAaBwqlQqLqvOxsMqOfm8I7x7gykaSFxWAxh6v6DLG9YtndmNRdT5myKwDVLbjSJVkT6VS4Wun1ooug+g48yptCEXludo2EInhu49uRTASE11KTmGokiKcNqMYdqNOdBlEmFVqwap6BxZX52NftzxHqR/Z3+PFs9s7RZeRUxiqpAh6rRrnzysTXQYRLAYtNjQPYXu7C7G4/DsYPby+TXQJOYWhSorxuUUVoksgQjQm/yA92q5ON3rcPMUmUxiqpBifmOZAoVl+B0VTbtnZ6Zbd8W8T2d7uFF1CzmCokmJoNWpcxu01JAM6jbIundvaXKJLyBnK+smgnPfdc2YobpRA2ccTiKCywCi6jITt6nSLLiFnMFRJUWx5Ovz9G6tgNXCLNYnT4QrA7Q9jaU2+6FIScrh/WHQJOSPpUO3s7MTVV1+NwsJCGI1GLFiwAJs3bx7zmH379uGiiy6C3W6H2WzGihUr0NbGFWiUGmX2PJw3nyuBSSxfKIatbS7km3RokHm/6h5PEL5QVHQZOSGpUHU6nVi9ejV0Oh1efvll7N27F3fccQcKCj4+oPfQoUM47bTTMGfOHLzzzjvYuXMnbr75ZuTl5aW8eMpdp04vFF0CEQDA5Y/AoJP/pN/hfnkcT5ftkppDu+2221BdXY37779/9GP19fVjHvPzn/8cn/nMZ/Db3/529GPTp0+fYplEYy2uzhddAtEoORxSPpFD/T4srMoXXUbWS+rt1XPPPYfly5fj8ssvR0lJCZYsWYL77rtv9O/j8ThefPFFzJo1C+eddx5KSkqwatUqPPPMMyd8zlAoBI/HM+YP0UTqi8zssERpMa3IjHkVY6dz1SrAbhx/DLK8tgCtg/5MlDYlvK+aGUmF6uHDh3H33Xdj5syZePXVV3HdddfhhhtuwIMPPggA6Ovrg8/nw29+8xucf/75eO2113DJJZfg0ksvxbvvvjvuc956662w2+2jf6qrq6f+r6Ksp1KpOFqltLDl6aDXqlFfZMbSmnwsqcmHWa+FOxCFUadBjcOEhVV2LKstQLk9D5tblbEH9ECvvFsqZguVJEkJtwfR6/VYvnw51q5dO/qxG264AZs2bcK6devQ1dWFyspKXHnllXj00UdHH3PRRRfBbDbjscceO+45Q6EQQqHQ6H97PB5UV1fD7XbDZpP3zX8S6+ZnduPv61tFl0FZZmapBQd7s+/+Y7HVgI0/+yRUKpXoUmTP4/HAbrdPKoeSGqmWl5ejoaFhzMfmzp07urK3qKgIWq32pI85lsFggM1mG/OHKBFK24BPypCt27X6vSFsbVPGqFrJkroqrV69Go2NjWM+duDAAdTWjhzLpdfrsWLFipM+hihVAjzSKus4TOO3oZxRbEZDuTUjNbQO+lGZr5zGDsl4bGO76BKyXlKhetNNN2H9+vW45ZZb0NTUhEcffRT33nsvrr/++tHH/OhHP8ITTzyB++67D01NTbjrrrvw/PPP4zvf+U7Ki6fcNqcsMxdZyoxV9Q44A2Esry2Aw/TxIrRFVXY09Q/jQK8PdYWmtNcxOByGBAlGvSbtr5VpL+zsgicYEV1GVksqVFesWIE1a9bgsccew/z58/GrX/0Kd955J6666qrRx1xyySW455578Nvf/hYLFizAX//6Vzz11FM47bTTUl485bbLl1ehwMQVwNlgTpkFG5qHIEnA5lYnQtE4VtU7UGYzYMA3sl0lGpegUqmgzsAtwS5XMGMj40wKRuJ4YUe36DKyWlILlTJhKjeIKfc8tK4F//7sHtFl0BRoVEBlgQltQ4ltS1lcbcf29sz0sl1ak4+tWdaM/oxZxXjompWiy5C1jC1UIpKbL6+sgSPFx8FdtrQK5iyc+pOrZXWOhAMVQEZXr+7v9qDMnl3d4DY2DyIcjYsuI2sxVEnRtBo1ltcWTPzACWjUKny6oRS/+vw8mA0aDIe5CCoTyu0G7Gh3JfU5+7o9MGaoLaA/EketI/33cTMpGIljZ4dLdBlZi6FKirey3jHl55hRbMGtly7Aba804qF13PuaKYVmA0JJjpqCkTjmZrCB/YAvNPGDFGZD85DoErIWQ5UU77SZRVN+DpNBg9f29vIkjwxaUpOP3V2Ta0vqCWbu+xSKZN9U6bpDg6JLyFoMVVK8OWU2XLqkctKfn2/S4beXLcQz2zpTWBWdjEWvQdsU+uU29fmwsNKewopOTEmHkSdq/eFBOBVwCIASMVQpK/zkgjkw6ia3uOjqVbXwh2OcEsuguRU2DE7xot7m9Kf93ursUgs2tWTfz0U0LuHFXdxakw4MVcoKJbY8lNgMSX+eSgV8aWU17n3vcBqqovHMKDGnpAm9yx9Bmd0IvSa1q4GteVrUOkxYWV+AtqEA4rLadJg6z27nzEw6ZGeTS8pJH+24LjDpkG/So3lg4qOuzp5dgngceHk337VnggpAPP7x92qqPvoeO8x6FFv0sORpoVWrEYtL8IWiGBoOo8978oVGBq0KC6ryMegLo9MVgDcYhTcYRWsS23yUaFOLEwO+EIosyb8ZpRNjqFLWWFZbgLYhP5z+CNZ8ZzUeXNeCJzd3nHDxkVoFfPuMabh/bXNWjUaKLQbUFZnQPhRAsVWPXZ3yOaN4RZ0DG9MwnTo0HD7hQeE6jQqltjzkm3Qw6jRQq1QIReLQqEe2Uu3v8WJzS242mt/d6cZZs0tEl5FVGKqUNb5+ah3WHFlsFI3H8cvPzcO/nFqPC//wPrxHgrXcnodrz5yOAV8Is8usWF7nwHcf2yay7JRxmPWYXmzG9nYXNrWMjM6qZLTIpsRqwK6uzHRCOlokJqHDGUCHM5Dx15a75oFhnDVbdBXZhaFKWWNRdT4uXVKJdw/0o/rIhv2aQhNu/lwDfvzPnQCAWy5ZgLPnfPzO/ECvF/0TTA/KXYFJh5mlVuxod2HTMSOuuIy6kJbaDOjrVPbXOtu0D/GNRqoxVCmr3H75IrgDERi0H68EvmJ5NRrKbXh2eydOnVE45vFKPozaZtRibpkNOzvc2HiClcvRmDxCdVW9g6urZajdmd33jUVgqFJWUatVKBinF/D8Sjvmj7Ov0RVQ1l49jQqYWWqFzajD7k73hEElQXyorqgrYKDKVHuWL8YSgaFKOa3CLuaeowpAQ4UVRp0WB3q9CMfisBi0MOm1yNOpkafTQKdWQ6P+uIG8PxxDU78P+3u8QmpOVn2RGUUWfdad8pJNOpwBSJKU0UMKsh1DlXLaKdMLYc3TwpvBtncr6xxo6vdiT9fYcAxGwgBSO3I+eho8E3RqFRZW5cMbiuBAry+hbU0kji8UhcsfGXd2hyaHzR8op+XpNPj6qXUZe72VR7aUDA1HMvJ6rkAEs0otqMzPg8OkT1sHojKbAavqHTAZtNjS5sQBBd+rzjW8r5paHKlSzvv2mdOx7tBgSrr8nMzy2oK07NE8maa+48NNpQKMOg1Meg0MOg3ytGrotWroNGpo1Sqo1SpoVKqRu7HSyH3ZWFxCNCYhHIsjEosjFIkjEImhssAISQJ2d7nR4+HKXiXqdAawsCpfdBlZg6FKOc9i0OLJa0/B63t78euX9qF1Co3eT2RxdT62tsmjwYAkjdyf9afgzNip9u8l8Yb8/B6mEqd/iTCyGOjT88rwb+fPSflzz6+0YU+XO6u6NlH28GVwPUEu4EiV6ChGfWoX9swutaCpz4eITPaLUm7SqFVYWefAJ+eWYH6lHX948yDWHjlTNW+SpzvR+BiqREfRHLO14OzZxVhYlY/hUBQfNA0ktZ2lvsiMTlcQwSw85JrkL9+kw9mzS3DOnBKcMasYdqNu9O9W1Tvw7PYu/H19K1ZNcwisMvswVImOolGPhKpBq8b/fX0FVs8oGv27eFzCoxvb8Itndk/4POX2PDj94RM28ydKB71Gja+dWovz5pVhSU3B6M/zsVQqFS5eUomLl1RmuMLsx1AlOsq0YjNqHCb89II5YwIVGOnWdNWqGjy3veukq3jVKsBs0KLbHUx3uUSjZpRY8IcvLUFDhU10KTmNoUp0lHK7Ee/9+OwT/r1KpcItly7APe8eQo3DhGAkhj+/c2jMY1bUsc8tZd63Tq9noMqASpJkdIwFAI/HA7vdDrfbDZuNPyAkf5tahtDjDuJ7j23D7FIrDvZ5udKXMq7IosfrN53J7kgpMJUc4pYaoilaUefA5xZV4MyZxRgcDjFQSYgBXxgX/ekD7OxwiS4lpzFUiVJkeokFAz5upCdx2ocC+MLd6/DIhlbRpeQshipRipw7t2TiBxGlWTgWx8/X7Mb6w4OiS8lJDFWiFDl1RhG+fmodFlfn44vLq1HtEHOsHBGA4xbQUWZw9S9RCv3HRfNG//dwKIqv378Rm1rk0fOXcsuXVlSLLiEncaRKlCZmgxb3/8tKLK3JF10K5Zhrz5yOzywoF11GTmKoEqWRxaDFg9esxIJKu+hSSObyTTpMLzZDM34TpIR9uqEUPz5vdmqKoqQxVInSzJqnwx+uXAIjG5fTCWjVI32nD/UPw6jXYmlNPmaVWpJ+ntmlVvzui4uhPkF7Qko/hipRBtQXmXHDJ2eKLoNkalFV/ujZtL5QFFvbXDjQ68PCKjtmlCQert//5AyYDVwqIxK/+kQZ8vVT6/B/Hzaj3xsSXQrJzJA/Mu7Hd3a4AQDWPC3qi8zQqFWIxiREYnGEonGEojEEI3EEwjGoVMCn5pVlsmwaB0OVKEOMeg0+3VCKRza0iS6FZGR+hQ27uzwnfYw3GB0N2BOpKzRBp+Hko2gMVaIMqizg3lUaYc3TYm65DdvaUrPlqshiSMnz0NQwVIkyqMsVEF0CCVBk0cNh1sOs10KvVSMuSdjf7cXGFJ5mlG/STfwgSjuGKlEGNfX5RJdAGTK33AqdRo29XR4M+MJp7wvtD8fS+vyUGIYqUQZ1cqSa1dQqYHF1PlyBCPZ1ezP62t5gNKOvR+NjqBJl0MKqfLQPMVizjUWvQUOlHc0Dw9ja5hJSgzc4/gpiyiyGKlGGRGNx7JtglScpS6nVgNpCE3Z3eVJ6f3QyOFKVB4YqUYa8uKsbhweGRZdBKaBWActrC7C51Ylemew7ZqjKA0OVKM3WNg3g+Z3deGFHl+hSKEVmlFiwUWanD4VjcQQjMeSxHaZQ3ClMlGYzSix4t7EP3hBHEtlCrZJnb10ff8aEY6gSpVmJLQ9/+/oKWNiTNWtoZNiwXqUCbHncqyoaQ5UoA+aW2/D/Pj1LdBmUAnPKLNgjwwVnpdY86LW8pIvG7wBRBniDETy2sV10GTRFahUQikqiyxhXfZFZdAkEhipRRlgMWgQi7HijdIuq7OjzBEWXcRy9Vo2bP9sgugwCQ5UoIzzBKPq88rsYU3K2tbsxu8wquozj/PJzDWiosIkug8BQJcqITc1DCEbiosugKZpRYsHQcHp7+CbrswvL8eWVNaLLoCO4HJEoA/Z2y29hC03MatCgptAMi0ELlz+Cxt7M9vOdSF2hCbdeugAqmW7xyUUMVaIMWH94UHQJNAGNCqgrMsNh1iMeB3q8QXQ6A7Jc6fuRP165FFZuo5EVhipRmoWjcZw6vRBrDzFY5aTMZkC53QidRgVXIIKWQT8O9Q/jUL8yWkmeM6cEC6rsosugYzBUidJMr1Xj9JnFuP21A6JLyVlGnRrTii0jq7DDMbQ5/ejxhNDjkUff3sn4l9V1okugcTBUiTIgGInBqNNwW02GWQ0azC23YXeXR9bTuMnSqlWocZhEl0Hj4OpfojQbDkXR4wmi1GYQXUpOMenUKLUbsbHFCX84u97MROMSvnzfBnQ4/YjG4vCFouj3htA+5MegT7mj72zAkSpRmmnUKtz4xHZI8mzEk7VmlVmxvd0tuoy06XQFcNptbx/3cY1ahQvml+HaM6djfiXvuWYaR6pEaaZSgYGaYVUFxqwO1JOJxSW8sLMb//s67+GLwFAlSrONzUOiS8g5ZfY80SUI5/LLq0lFrmCoEqXRcCiKX7+4T3QZOUWnVmF3Z26OUo/mCkREl5CTGKpEaRKLS7j24S3Y3yOvLjzZblqxmS0hAayqd4guIScxVInSZHu7E+8fHBBdRs6xm/SiSxDObtThZ5+ZK7qMnMRQJUqTxh6f6BJyUjTGUWqBSQeLgZs7RGCoEqVJmd2AhnIex5Vp3W4esdcy6Me1D2/hcYMC8K0MUZqcM6cU58wpRY87iHca+/DYpnbsaHeJLitr5Jt08AQiiB+1XanUamCoHvHqnl784kIeXJ5pDFWiCUiShOFwbNLTaWX2PHxpZQ0+v7gSX7t/I7fYJMhq0KDYmgerUQuDRgMJEoKRODyBCPq8Ibj8ERRbDZhWZMb+Hg/cgShqCk3o9bKjEAB8/dQ6VLOVYcapJEle29I9Hg/sdjvcbjdsNk6dUeb5w1EM+sJo6vfhnf19eLuxHx1OP86cVYzbvrAQJdbJ74E83O/DOXe8m8Jqlc9m1GJOqQ2AhFA0Dk8wgn5vGL5QNOHn0GlUqCowoWVwOGcbbVTmG7FqmgOr6h1YWV+IukITz1mdpKnkEEeqREe8e6Af33l4C4ZP0Cf27cZ+vLanF1d/onbSrzGt2IIyWx56PJyiBICGciv6vCFsbJna6D0Sk9A8oIwj21LtokUV+PH5s1FVwFGpHHChEhGATS1D+PbfN58wUIGRe3g1DhPWNg2g0xWAJEmQJAmRJFebVhYYp1puVqgqMGJ/jxcDPnb+maxLllTizi8uZqDKCEeqlPP2dXtwzf2bJmwYEAjH8NX/2zj63xaDFrG4hHkVNjzyrVUwaDUJvd4Xl1djS6tzSjVngxKrAR3OgOgyFEutAn746VlQqznFKycMVcppkiThuoe3wHuS+3enTi/EX7+2HCa9Ft3uAN7e34+3G/vQ6wlCkoCFVfmIxiQkuo7p8uVVeOdAH17a1ZOif4UyDYey6zi2TDtvXhlHqDLEUKWcplKpkKc78QhTr1HjX8+YBpN+5Fel3G7El1fV4Muraqb0mtOLLZP+/GwRy9UVRSmypCZfdAk0Dt5TpZy3ekbRuB8/ZVohXr7xdJw1uyTlr7mijn1Z84060SUoWqmNJ/HIEUOVct6XVlQf97GzZhfj0W+tStuIcmiYi3O2tTkxr4Lb5iZrKlu7KH0YqpTzZpZaceHCcgBAkcWAG86ZgQ2Hh+AJJL5PcjzPbu/EXW8dxCu7e9DU5xvTk3ZhlR25vr4kJgGH+nyoYYOCSdFrefmWI95TJQLws8/MxZv7evG1U2px5aoa3P3uIfzyud2oyDfCF4ri5xfOTXh1LzCyAOqJTe1Ye2hw9GNzy214+BsrUWgxYFqxBefMKcUb+3rT8c9RjGA0DhVGAiIcZSP8ZOxod2FZbYHoMugYfKtDhJFuNG/+8Cx895wZAEaaCTyzvQs2ow7nzy+DXpPcr0qfNzQmUIGRrTvffGgzAkf2wk4vMaemeIVrHfJjcVW+6DIUh9uy5IkjVaIjKvNHmjIYdRpctaoGs0qt+NqpdZN6rlJbHi6YX4aXd4/dNrOtzYUv3bsO3z93JtYdE7q5bG+XGyoVcrbF4GRsbh2CJElsRSgz7P1LlCb7uj347B8/QCwuq18xWarIz8OgL4wQp4CT8sG/nc29qmkwlRzi9C9Rmswtt+F/r1iEaUWc5p1IlyuIRdV20WUoDqeA5YehSjRFsbiEf27pwC+f3Q1/eOyK4c8vrsRrN52B02eO7IWd7PFxuWCiNpF0PIaq/PA3nGgKNjYP4T+f34M9XR4AwLwKO644Zt+rVqPGPVcvw4bmQdiNelx291oRpcoe+wAn770D/byvKjMcqRJNQvuQH9c/shVX/GXdaKACwJNb2uHyh8fsSQUAs0GLc+aUwpbH97HjsRo0bIgxCS2Dfqw7zAVvcsJQJUrCcCiK219txCf/9128uKv7uL/f1OLEqb95C8/t6Br3848OYPpYEbsDTdojG9pEl0BH4dtmohMIRmJYs60TTX0+tA4Oo3XQj9Yh/4RNCvzhGA73j39g9s4OdzpKVbxQlCfWTNZre3ow4AuhyGIQXQqBoUo0rmgsjs/98QMc7PNN6vOf3dGJ731yxnFdmNqd/lSUl3W6XUHuU52kSEzCk5s7cN1Z00WXQuD0L9G4BofDkw5UAGgfCuCnT+/C8DHntM4q5ZFv41lSk89AnYLHNrYddx+fxGCoEh2lqc+LC//wPs6/870pP9fTWztxzQOb4PKPLMDpcPrR7w1N+XmVpsRqQG2hEVUFRpxojao6108XmKK2IT9++2qj6DIInP4lGuPNfX0pXUxUWWDEIxva8NqeHuzIsfupRp0aCyrzsal1aHQUajVoMa3EDL1GjS5XAJ5ABNUOE/ZyAdeU3fveYcyvtOOiRRWiS8lpDFXKaX988yA6XQFcf/YMVDtMKLamdrHH01s7U/p8SrGw0o4eTxAbW4bGfNwbimJH+9g3F3u7vZksLav9+J87MKPYggaeUysMp38ppy2vc+CZ7Z345P++i9te2Y+KI031aXL0GhWW1ORjZ6cbfTk41S1aMBLHNx/chLvfOYQd7S72nRaADfUp5/3fB834rxf2ii5D8XQaFWaVWrkXV0aseVrMLrVCo1ZBo1ZBrVJBpQI0ahXMei2+ekotVk0rFF2m7Ewlhzj9Szntld3d+M3L+0WXoXhqFTCnzIZdnbl131juvMEoNp+kP/CLu7px22UL8MUVNRmsKrtx+pdyViQWx8/X7EaYWxGmbHmdg4GqUJ2uoOgSsgpDlXKWJAFR3nOaMrUKaOzhYiOlmsdFTSnFUKWcpdeqsaKuQHQZildg0sOk10z8QJIltjdMLYYq5aw+TxDvHRwQXYbiDQ6HYTfqRJdBkxTh7Y+UYqhSTtrZ4cKV962fsDk+TUytGglWUqa/r2sVXUJWYahSznlmWycu/tOHOHSCk2QocSoAS2sKcrL9YrZ4cVc3ntmWm01K0oGhSjmlsceLXzyzG1yflBor6gtOumWDlOHH/9yJHe0u0WVkBYYq5YxYXMIX710H3zEnx9DkLKnOx8ZmBmo2CMfiuPe9w6LLyAps/kA543C/Dy5/RHQZiqdVAwuq8rGvm52TssmmY/o00+QwVClnPLu9S3QJirSyzoGYJCEYicEXjKLfF8K2NpfosijFahwm0SVkBYYq5QR3IIIH17aILkORBodDXNSVA65YXi26hKzAe6qUE17d0wMv76UmTasGhkMx0WVQmp0+swiXLq0UXUZW4EiVcgJXNiZvYaUd4Vgc+9mCMGsVmvW49szp+MoptdBqOMZKBYYq5YQeN5uGJ8OkU2NfjweRGPceZaN8kw7fPmM6vnpKLcwGxkAq8atJOaG20Cy6BEWZW2HHFu4/zTq2PC3+9Yxp+NqpdbDmsbVkOjBUKev1eYJ4cRdX/iZqfoUNzQNcmJRt9Fo13vzhWSi2soF+OnESnbKePxxDr4dt9BLhMOlgMmgxxF6+WSccjWN/D/cWpxtDlbIe35mfXJ5WjVX1DtQ4jBjyR7CxmU0AslWHMyC6hKzH6V/Kei/v7hFdgmzp1CrUF5uxgUGaE9qG/KJLyHoMVcpakVgcT2/twG9e3i+6FNmaV2nHdm43yhl7ujj9m24MVcpa//bPnXiaR1qNS6dRYVFVPk+YyTF7Ot3ocQdRZs8TXUrW4j1VykrxuIQ39vWKLkOWNCrAlqdjoOagweEw7n3vMIIRdslKF45UKatEjhxhFYrG4QmyLeF4FlTmY3uHS3QZJMj/fdiMDc2DePLaU2DSMwJSjSNVyiqNPV78z6uN+MObB0WXIlsajUp0CSTYni4P/vO5vaLLyEoMVcoq4VhcdAmyt7PdhUVVdtFlkGD7uGc1LTj2p6zg8ofxwNoWHOz1iS5F9iJxCbs63Vhak4+tPBc1Z/H81PRgqJLivX+wHz/8xw70edk1KVFxCdja5sKKugJsauGCpVz0ybklokvISpz+JUW79aV9+NeHtjBQJ2lTixOLq/NFl0EZZtRpcN68MtFlZCWGKilay+AwAtweMCUdTj+Meo3oMiiD5pZbufI3TRiqpEitg8P45bO78eoe7kWdqgFfGAsruXApl/AoxPThWxVSnC2tQ7jqrxsQjHClb6psaR2CVq1CNM5DyXPBwT4vJEmCSsXtVanGkSopzv992MJATbFoHCix8TSfXLG708ODJtKEoUqKs7+b++vSwWzgxFUuufHx7XhrP2+fpBpDlRQlFI2hZZDHV6WDQcvLQS4Jx+L4xoOb8Z/P78FwiC09U4W/RaQo7zT2I8b7fmnR5eLpJblGkoD7P2zBp3/3Hv6xqR3eYER0SYqnkiRJVlcoj8cDu90Ot9sNm80muhySkXA0jov/9CH2cvo3bcrteYjE4hjwhUWXQgLk6dT4dEMZLllaidNnFEGryc1x11RyiDdRSDHuefcQAzXNut1B2IxarKx3IB6XoFIBKpUK3a4A2p0B0eVRmgUjcTy3owvP7ehCkcWAK1dW43vnzISetwYSxlAlxXhiU7voEnKCJxDFxuahMR9bUm1nqOaYAV8If3yrCRsOD+Huq5ei0MLV4Yng2w9SBF8oik4XL+qi5Oo0IAEbW4Zw4xPbIbM7hbLF3xRShCBbERIJ8/7BAfxzS4foMhSBoUqydqDXix3tLuQbdcjT8cdVlD2dbqyqd2BehQ06HnKek+584yBCUb65nQivUiRrD69vxef/9CFufnY3Flbliy4nZ/kjcWxoHsKeLg/mV7BPcC7qdAVw60v7OQ08AS5UIln7sGkAAPDYxnaOkGRCy+9DznpgbQte39uLs2YX49ozp6OaB50fhyNVkq3mgWEc6h8e/e9IjO+Q5YC9N3JbpyuARza04bw738PuTrfocmSHoUqy8lFHl/09Hlz38BbB1dB4OP1HAOAPx/C/rx8QXYbscPqXZGNoOIyzb38HK+oK8DbbEcoWQ5U+km/UiS5BdhiqJBvNAz64AxG8sa9PdCl0EnyvQx9ZXucQXYLscPqXZMMb5EkZShDnSJUA6LVqfHZRuegyZIehSrKxtdUpugRKAEeqBAB2ow62PE7/HouhSrLwj03tuO/9ZiyrLRBdCk2A97oJANz+CM9hHQdDlYRrGRjGL57djUAkhi2tTqyoK4BOzb2QcsXZXwJGDjl/u5HrH47FUCXhPmgaQDgaH/3vTS1O1BSaUGrlqRhyFJfiEz+IcsKTm9kP+FgMVRJqOBTFXW81HffxQ/3DCERimF/Bg+rlhk046CPvH+yHj1PAYzBUSYhOVwDrDw/iz+80occTHPcxnmAUu7s8WFnvgN3I3V9y4Q+zqTqNiEtcYHgsXqlIiBd2dOHWl/cn9NiNzUMw6jVYWe/A/h4PPAG+MxZpaDgkugSSkY3NQzhjVrHoMmSDI1US4pKllTBoE//xC4Rj2Ng8hEhMwqp6B2wcuQoTjQO2PH79acSODpfoEmSFoUpClFjzcOnSyqQ/LxCOYUPzEFRQodyel4bKKBFVBUbRJZBMJPPmOBfwq0Fp5Q5E4A+PP1171araKT2vXquGkQeXC5Gn04gugWQi36QXXYKs8IpEaSNJEi7+04c47ba38ez2zuP+fl6FDYXmyf9Ctg76MY8HZguxtc2FFXUF4HZiml5sEV2CrCQdqp2dnbj66qtRWFgIo9GIBQsWYPPmzeM+9tprr4VKpcKdd9451TpJgbyhKJoHhjE0HMaP/rkTd7zWiCvuWYedHS7E4hIkCSiYQqgCI6uISYxNLU4srSlAmY37iXOVVq3CZcuSv42TzZJabeB0OrF69WqcffbZePnll1FcXIyDBw+ioOD41nJr1qzB+vXrUVFRkbJiSVl63B9vlQlH4/jjkf2oF931IfQaNUpsBnQ4pxaKvZ4gdGoVImydlzEaFTC/cmSGYHu7C9G4hMp8Iyry8xCKxnGgx4tglA0icsH588tQYuXahqMlFaq33XYbqqurcf/9949+rL6+/rjHdXZ24nvf+x5effVVXHjhhSd9zlAohFDo4yX6Ho8nmZJIxrpOMooMx+JTDlRgZJ/czBILGnu9U34uOrnpxWY4zHoc6PVhR4d7zN91ugKjswY6jQoN5TZY87To9QTRMugXUS6lmV6rxo/Omy26DNlJavr3ueeew/Lly3H55ZejpKQES5YswX333TfmMfF4HF/5ylfwox/9CPPmzZvwOW+99VbY7fbRP9XV1cn9C0i2ut3jN3VINbuJJ2Wkk1oFLKstwKH+YWxqccIdiJz08ZGYhL3dHmxoHkLLoB+FZj2W1RZgSXU+t0Jlke+cNR21hWbRZchOUqF6+PBh3H333Zg5cyZeffVVXHfddbjhhhvw4IMPjj7mtttug1arxQ033JDQc/70pz+F2+0e/dPe3p7cv4BkayqLkJIRjLDDT7oYtCrMq7BhyxS65gwOh7Gl1Ylt7S54g1HMKLFgVb0Ds0ut4DonZZpXYcO1Z04XXYYsJfW2MR6PY/ny5bjlllsAAEuWLMHu3btxzz334Gtf+xq2bNmC3//+99i6dStUqsR+XQwGAwwGLnTIRgur8jPyOof6fDBoVQhFeV81lWxGLUqtedjVmbpbMpIENPX58FG3Z4tBixklFmjVKmxrc4JtheXPYdbjL19Zxm1VJ5DUSLW8vBwNDQ1jPjZ37ly0tbUBAN5//3309fWhpqYGWq0WWq0Wra2t+OEPf4i6urqUFU3K4PSHM/I6w+EYFlTmZ+S1ckWJ1QB7ng4H+3xpfR1fKIrt7S5sbnVye5QCaNQq/OnLS1FVYBJdimwlFaqrV69GY2PjmI8dOHAAtbUjm/i/8pWvYOfOndi+ffvon4qKCvzoRz/Cq6++mrqqSRFaM7hApbHHi2oHu/ykQq3DiLgkoT0FC8mSsbPTjWU1BdCogJV1Dpj0GiyrLYCVLRFl4xcXzsUp0wtFlyFrSf203nTTTTj11FNxyy234IorrsDGjRtx77334t577wUAFBYWorBw7Bdcp9OhrKwMs2dzlViuOWt2MeZX2rA7hdOHJ+INRWHUa1BsMaDfx4bvkzWnzIJOZxBeQcd5bWlzQqUCNrYMjfx3qxNFFj0qy6zY38MV3iJdurQSXz+1TnQZspfUSHXFihVYs2YNHnvsMcyfPx+/+tWvcOedd+Kqq65KV32kYHk6DR66ZlXGmq/3eUOISRJ7Ak/Soio7Dg/4hQXqR6Rj7qsO+MJo7PViZb0DBVzpLcTCKjtuuWRBwmtlcplKko79ERbL4/HAbrfD7XbDZuMB1UoVCMdg1Gvw7PZOfP/x7Rl97RV1BdjUwjMek7GirgBbWp2Qew8NjXpkNbIKwO5ONxc2ZUCRRY/nvnsaKvJz5/bKVHKINyso5TYcHsSdbxzEJUsr8e/P7s7468fkngwys6regQ3NQ6LLSEgsLmHnkcYTc8qsaBkYZvemNNIeWZiUS4E6VQxVmpI9XW68ursHoVgcVoMWgUgM/9jcgX5vCOsODwqpqdfLe6qJWlFXoJhAPdb+Hi/mlFnROjiMQITBmg4XL6nEqmlcmJQMhipN2uF+Hy7+04eIyGwOrtMZwKIq+3Gt9OhjOrUK8yrtip8m39/jxexSK9qHhuFPQ7CW2QyodpjRPODDcCiGYqsBZbY8BCJRNPX5hIe5Ra+BXqvGkP/kXa4m6+pPTP54xlzFUKVJM+nl++PT1OfDyvoCbG9zISyz0BfNotegymHC9naX6FJSorHXi1mlFnQ6AxgOp7a7liVPh00tH4/k24b8aBsa2SqmVaswp8wKu1GHweEwDvX5kKqfNJ1GhSKLAXajFka9Fjq1GioVEInF4Q/H4A1GMTQchi8cgyYax5wyC/b3pHZP8bwKGxZVce9wsuR7VSRZcvnDuPGJ7ThrVjH2dHlkN0r9yHA4ho3NTjjMeswoNmOzAhbhZIJGBZTY8rJue8qBXh9mlljQ5UptsPqCJ14JHY1LY76OVoMW00vM0GnU6HAGxu19rQJQaNGjwKSDSa+FXquGWqVCLC4hEInBF4rCORyGJxhFtzuI7gQmW2JxKS1vcK/+RC1X+04CQ5USJkkSfvPyfrzT2I93GvtFl5OQoeEwNg6HMbvUCqc/jL4cv9+6rLYAGxU+5XsiB/tGgrXbFYAvBcFaajWgx5P4oRDeUBTb2z9OwTJ7HirseYjFJfhCUbj8EQz5wxjwjfxJJWeKp38tBi0uWsRjOyeDoUoJ+/2bB/H4JmUeeNDY60WJ1QCLQQNfKDcb8Jv1GhxIc9tB0Q72+TCjxIIed2DK3+faIvOUFr31uINjzhROp05XACogZdPP/7K6DmYD42Eykmr+QLnrpV3duPONg6LLmJI+bwgzS62iyxBmfqUdrjQtaJGTpj4fSm15sBom3/Bdp1HhkILegISjcVTkp6bpycIqO753zsyUPFcuYqjSCYWj8dEjv3yCu+ykyrY2F+aU5WawfrTAJhcc6h9GsTVv0n2DF1fnY3A4MwdCpEqhZeqnfRl1Gtz5xcXQaxkNk8WvHCESi+PZ7Z1oGRge8/HfvrIfl929Fu8f7IfryIkz2bBuIVcvGGU51r7x8MAw8nQaLKspSOrztOrMHgaRKsYpHsVWV2jCH69cgmnFlhRVlJs4aZ7jwtE4vvK3DdjQPIQzZhXjswvLccXyagAjYQsA/9zSgcuWVWFWqQVGnQZ7u+W76jcROzvcqC4wZvwUFtH0mtx7M9HvDaHfG0qqdeWSGmW2ufzo9zVZy2oL8K3Tp+FTDaXQqLPgXbNgufdbRqN8oSiuf3TraEed9w70Y1vbxxeT731yJhrKbXhldw+Gg1Ec6PVhR4cbM0osMOmTf1e8oq4A8yrk0c+51JZbozZg8hfdbLCpxYmlNfkTPk6tAtqHlPlmK9n75Z9qKMVT152Cp647FefPL2OgpghHqjksGotjbdPAmI8tPWqqrMhiwJxyK/Z2e3DdI1tHP76v24vpxWYMDofH/UW25Wkxt9yGWFxCOBbHzg43ahym0Xf/K+oKsLPDjZDAnq07OlxwmPQYytBB6nIQiOTmquePdLmC0KlViJxkw/LSmgJsblXeKBUYWQF8MmoVUJFvhGs4jFsuW8gtM2nCkWoOyzfpcW5D6eh/nzu3FKfNLAIAtA/58e6Bfuw6Qau/Q/3DMOu1KLGOXRxhNWjhMOuxoXkIm1ud2NnhxvRiMwxH3cfc1OJEscWAukJTGv5ViYnEJMwsza17R96TNDLIBT2eIJZMcH81EIlhRV1y92DlIhSNj3vsYZnNMHL4u1qF4VAUz99wGgM1jRiqOe7bZ0yHQatGkUWP//r8PJTbjejzBqHVqPDfL+zFwZNsK+h0BSBJQI1jJBzVKqC+2IyWYxZ5HOofPu55OlwBDPpCmFZsTv0/KkH7uj3Iy6FFS06FrWZNh/09HlhOsNXGYdJhf48X29pcQt/wTcXRoeow6bGirgCDw2FsaXMiEpPgDkRgy+OZtOmUO1cUGldDhQ0vf/90vHTD6aPHO/W6Q/jXh7acNFA/0u8LoccdwOxSK6YXW0aP5UqENxRDvyeI6YKC1ROMYmF1vpDXFmE4HJvyClGl8wSjqCs0wzHOYeczSq2IxSVE4xJUqpGWjkrT6wmhvsiMVfUOBCIxbGpxjllUGJeAl3b3CKww+zFUc0y3O4BQNIZBXwh7uzwAgGnFFpQctXBnQZUda75zKhYm2Ew7HJPQ2OtNKISP5Q3F0OsJYkaJmKnYtkE/cml9RoGZo5TdXR7EgTHN4jUqjNlS1jzgx7I6h4DqpqbTFUDzwDA2NA+d8B76Ha81osOpvC1DSsFQzTHrDw/iJ0/twr3vHcYX/7IO3e7jFzdIkoQXd3WPhm66+UIx9LgCmCkgWHs8QaxQ4MVzsjj1N8Llj2BHh3u0EcjS2oLj+kJvbB7CzBILltcWYGW9I2uahrj8EVz/6DaEebh7WjBUc4zFoMMz2zvx1NYOeENRPLbx+F6+d797CN9/fDuiGTzWxReOIRwVszp1W7sLlSlq8SZ3k9kKlc08wQhW1jmwq3P82xYH+3zY3OrExuYh7O/xYnF1dhyFtqPdhVte2ie6jKzEUM0x/nAUkoTRUzI6xmld98CHLWl57SKL/qT9WDucgeNWE2dCOBqHNUdGcNocbABxMl2uIDa2DCGY4GHjB3t9MOqy42v4wNoWPL+jS3QZWSc7fjpoQhubh7CxeQivHLNIQXfMRVaSpLQ1Xa92mDC9ZOwU2oxiM1bWObCoOh9Wo07Y0Wz7e7xYVZ/908A5dPs4LeZW2BBIMICV4CdP7USTgg4OUAKGao5490AfrvjLOrx8TKg+s70T7iMhGo9LeHBtC8Jp6ryjU6ugOdI8uNphxJwyK5r6h7GxZQg72l3CT1DZ0DyElVkerLncVSkVQlkUqMDIivDvPLIF/nBu72FOJYZqDmjq8+Iv7x4e9+9C0Tie3tYBSZJw5xsH8B/P701LDSadGsPhGLa0OVFfZEK3K4j9Pd60vNZUbGwewnKFbv5PRKLTnDS+lsHhiR+kMAd6ffj5mt2QJOX285YThmoOeH1v30kXHf3xrSZ88o538Ye3mtJWQ75Zjz1HVhM3D/gzuggqWZtbnFhSnY9s7AuR660Kp8objKLyyH7ubLJmW+e4ixYpeVl42aBjXbG86qSb/oeGwzg8kN534BV2ZV2ItrW7MLvMBoM2u+5CapXY0UBmHFm61/c/nttzwraklDiGag4otBhw1aoaoTVsbnWi3J6HhnIbFlbaUe2Qf8ju6fKgoXxyWyjmlFmxsMqOWaUWrKp3YF6FVRaLhHLx+LdUM+qy8xyScCyO7zy6ZXSNBU0Of8NywN/Xt+IT0wpFl4FudxB7uz3Y2elGuUJGrtvaXUmvCi6356HTFcDODjcO9PqwoXkIe7q8qCgwjunik2kzSy1cqJQC3lD2hk77UAA/+Md2/pxMAUM1y0VjcTzwYTO+88hWqOQwVDpCSd1cNjQPJdyyEQAKzfpxT4TpdAaws9ONxVX5KawuMSvqCtDU58OBXm6fmKp93V5MKxJ3EES6vbm/D1+/fyNHrJPEUM1y//NaIw71DyMci0NOi/sGfGL2o05WU58voSlrm1GLfSdZ1SxJwJ5uN+aWZ67lnTVPiz1dHll9/5XOFQjDbszOaWAA+LBpEJfc/eGYfsiUGIZqFpMkCU9t6RRdxrg6nAEsq8mHNU8ZFyZ/OIZYXDppRygAmFUyctLJyURiEtoG/ajP0GhndqkV/jBX/aZStcOEYkvmu39l0uH+YVz85w+x4fCg6FIUhaGaJeLjXMh7PEFZjwi3tLlQYc+T1bT0yXS5gqgpNJ90wVGiW4WGwzF0uwNYVe9AZb4xrceMKeXrqxSr6h3Y0e5GU3/2j+Jc/giu/tsGPLNNnm/O5YihmgUO9nox/z9exQ+e2D7m4zvaXULqSUZjrw/TFXR/ak+XBytOsnCp1xNM+LmCkTg2NA+h0xVAHECpzYCGciuW142cirKkJh8zS8wTjo4nwr2pqRXPsXn0SEzCj5/aiWZOBSeEoZoFtrY54Q/H0NQ/dhHKh03KmLZxmJU1jbaxeQjLavOP+7hFr0G3O/FQPZokjRwwvbfbi80tI6eibGtz4WDfMAKROFbVOyZ97qtzmAtOUinHMhXAyMLCnz29i12XEsBQzQJVBSYAQJlt7PFl6xRyL0SC8n5Rd3a4jztYvS5NI+5oXMKG5iEsqEx+O45GldzomSaWqw3o1x0exFNbOQ08EYZqFphTZkWeTo3X9/XiB09sx5bWIQCAOyBuhLKkOh+Lq+1oKLdiaU0+VtY7UHWC9m6RmPJCNRKT4BwOo8D0cXedvJN0rUqFHR1urEzyQPWZpRZZt4RUIlcgcsKf5Wx32yv7ERJ07rFSMFQVrMsVQKcrgEKLAdefNQOSBDy9rRM3PLYdsbiEUlvmp1X1GhUaym3Y1u7C9nY39nZ7sbXNhY3NQ+hwBTCvwoYii37M5wyHlHlCxuBwGDNLR7bGWA2ajBwQsK3dienFiY+I87K0+49oxQJ+t+Sg3xvC4+wRfFIMVYUaGg7jors+xJm/fRsfHBzAt86YNuZie9/7h7G705PxuhZXF2Bv94lfd0+XB9G4BMdRIzzRR75Nxd4uN1bWFUCjUcOXgTcHkZiEQDgGs37iUXFdoQnbFbBYTYlyud3jfzy/B3959xCi7Lo0rtz9yVC4fm8IA74QonEJNzy+Df5wDPd9dTlseVr0+0L47Sv7M15TfZEZG1uGJnycyx/BjKMOKx8cDk16EY5IDpMedYVmbGxxZvSNQZc7iKoCE0y68X99C0w6rKp3wB+OYXapZdzH0NSIvLUimiQBt768Hxfd9SG2tTlFlyM7DFWFOvpe3tBwGD95aiccZj3+fNUyxOISRNxGc5j1Ez/oiF1dbliOjLbiElCosBXAC6vsiEkSdndlfjYAABp7vSjPN2JJtR0GrQp6jQozSsxYWVeA4XAMG5qH0OcNwWrMzhNVRGvq8ymmcUm67O324NK71+Jna3axpeFRVJLM1kh7PB7Y7Xa43W7YbDbR5chWPC7hrNvfQduQf/Rjeq0as0utyDfp8P7BgYzWU2jWwx2IJLUoZmW9AxubR0a2s0otiuhLa9CqsKAqH5tb5PMOXadRIRqXxt3q0VBuxd5u+R0Gnw2O/vnNdYVmPX72mbm4dGklVFnQbWQqOcSRqkKp1Sr86ctL8fnFFaMfC0fj2NXpznigAsCMkuRXmW5rc2LGkfvABabER7miWPQaVBWYZBWowMh91vECdX6FjYGaRltanZhXkbkeznI2OBzGD5/cgSvvW4+mvtz+mWOoKtiCKjvu/OJinDOnRGgdeVr1SRcnnUgkJqHfF0a1w4h2p1/W91WNOjUqCow4pKDWdMPs95tWsbiE5gE/5lVwRu0j6w8P4YLfv4/fvrIfgRz9+WOoypgkSdjd6ca6Q4N4u7Fv3K0nKpUK/3nRPBjTvEfyZBZW54971Fki3IEIXMMRFJr1WCjgSLRE6DQq1BeZFTE9/ZGlNflsK5cB/nAMjT3ZfRRcsiIxCX9+5xA+9bt38db+XtHlZBxDVcZe3dOLz/7xA1x533r860Obx9w/PVq1w4QffnpWhqsbMbPEgs0JrPg9GW8oit1dnoxsSZmMJTUFippGVbGLUkZF4xKKrPK/fZFpHc4ArnlgM679+xYEc6j/NEN1ioKRGNanoR1gPC7hzjcO4JRphbhyZQ0KzYaTHhX2jdPqccXyqpTX8ZEZJRYYtGrMKbNiVb0DC6vsWFnngNMfTslKY0lKbvVwpug0KjRmoKlDKhVZDOh0MVQzKarArmCZ8sqeHvzn83tEl5Exub0mfIrah/y4+m8b0Dbkx0PXrMTpM4tT9tzrDw9if48Xr954BmaXWSFJ0klX1Y1MA8/HW/v7MOALJ/VahWY9JAAalQqWPA1Mei3Mei08wQj293ihU6tG+52ms2vQgV4v9BoVwjK6QDWU27Cjwy26jKT0e0MoNOsxOJzczwFNXjjKRggn89jGdqyqL8TFSypFl5J2HKlOQiQWxzuNfbjyvvVoHfRDkoBdnam98L64qxs3njsTs8tGVheOF6hdrgC6XIHR/zbqNfj0vLKkX2t6sQXeYAT9vhCaB/zY0+XBxpYh7O/xoiI/D4tr8if970iGyx/BourMvFaiNHJePXUS1Q6T6BJyCvsrT+xna3blxGEEDNVJWLOtE1+/fxM6nB8H2tzy1K4A/LcL5uD7n5yJg71ehKNxSJKEDw4O4LGNbaPHLz21pQMbmsdOPV+2NPEp4Kp8I2aVWrCxZeiETe27XEFsyuAWkkP9vtGmEHKg1Evlrk43HArYppQthjgrMCF/OIbrH9ma9auCOf07CZctrcLzO7pG94NWFRhx+oyilL6GLU+HYCSGDmcA//dhC86cVYxrH94CYGR6T60CPmgawFmzx26nMeo0UKsw4X1Ok06NgeEQgi55TVsNDUewvLYAm1vlsRdUkteXJ2GxuIQZJWZsbOHFPt1mllhwMAdGYKnQ2OvFvz+7G/9z+SLRpaQNQ3USNGoVfvfFxbj7nUM43O/Dl1fVQpuGBtsPrG3B/75+AJIk4epVNbDmaeENRvG/rx8YfUxdoRl93iCsBh2Meg1+++r+hBYO+SNxzK+0CWm6P5HNrU6srHMk1Ec43bwh5bZfC7PhedqpVcqdzRDlyS0dWDWtEF9Ylr6FlSJx+ncCJ1oKXmQx4ObPNuCmT83CpxpK0/LaW1udqCoYObfRbtLBlqeDWa/B7NKPu7hcsaIK/9zSgVf2dONQvw/vNPZP+LwWgwYr6grQ45bvCtGNLUNYUVeQ0Gks6dQ2JO+mFCfTNhSY+EE0JctqC3LiPmGq3fzMbuzscIkuIy04Up3Ab19pxJdWVqO6wIT1zYN4fkcX9Bo1fnPZQgBIa8OCzy+uhFajgjcYxeYWJzpdAZw9uxjfPWcG7nn3MALhGBZU2nHjE9vhMBsQj7dM+Jwzis3o9YQyep90sja1OGHL02J5bQHikoSWQX/G713F4xIKLQb0e0MZfd1UGBoOo9xuQLdbebVTdgtEYvjCPetw82cbcPWqmqzoF/wRhuoE7EYdzr/zvdEpVZ1GhVdvPGPMY+JxCdG4BK1aBfUUhzVHb525cGH56McjsTh++vQuvN3Yj+FwDP/49ikAgEc2tKJ9KID2BEYlWjUw5A/DK9MmC+PxBKNj7q9WFRhRbs9DNCZhZ4cL6dx9Y9FrUGrPU1RrwmNV2I0M1TSxG3Vw8nSWSQtH47j5md1Yd2gAv7lsIWx52XGiEqd/J7CgyjbmHuVZs0swrfjjMyrfbuzDp373Lmb94mXc+MR2TPbQn05XAF+4ey2e3d417t/rNGq8+cMzceXKGnzjtHoAQJ83iNteTvzcVIfZgKFhZV8EOpwBbGpxYlu7C7PLrLAY0jc9XGQxKDpQAUCl1LlrmSu2GmAxaDj1mwIv7erBhX94HzvaXaJLSQmG6gQWVeXj6JmJC+Z/vA90W5sT33pw8+iF9/mdXQk3MZckCS/u7MZTWzrwtw+aceEf3sfmVudx+zSjsTh+9cJeBMIxVOQb8S+r63DOnBL89f3DuOmJ7fAk0XO3zxvCirqChB8vd3u7vSgw61FqTc9ZrP4saK3WfoLWljQ1Oo2KXatSqH0ogC/csxZ/+6B50gMTueD07wQKLQZcML8ML+3qATC2GUCvJzhm03eJ1QCL4eMvaZ8niD+8dRDfPmP6mM34wUgMNz2xHS/v7pnw9d9u7MffPmhGvlEHjUaF377SiDllVgz4whjwJT+tl23t1NqHAqguMMKs16T8VBZ/WDnT5CfS6wnxvmoaVOab0MVQTalITMKvXtiLdYcGccfli2A3KXM6mCPVBPznRfNRZBnZSP/L5/bgi39Zhx88sR2hY1qThY40aQAAXyiKy+5Zi4fXt+EbD26CNzgy7bru0CA8wQiCkdi4q0qPXRDT2DOy5eWO1w/gt680AhhpFTiZQAWALFoPMKrdGcC04tSfElJkSc8IOJMcZh2iyh9wy0q+SYf93cpqXakkb+zrxdcf2KjYJhEM1QQUWw2484tLAIy00tvQPISnt3Xi+49vBzCyeObs2cVw+SOjx23t6XSPLh460OvDdx7Zij5PEP/1wl58++9bcMMnZ46uID7asaG6oTm1ezWVtEgpGbs6PVhV70jpcyrh4PSJlFjz0D/JN2A0vkKzHoEsuDUgZ9vaXLjn3UOiy5gUTv8m6LGNbSiy6BGLS2NW/M0sseDv31iFv69vQUOFDYVHRjc1hSZo1arR6eH3Dw5g9W1vjbYDvOTPa8d9nY+mHCVJwsu7e0a7NqVKwZEpFZNeg0gsfsL2hEq0oXkIS6rzsS1FCx50WuW/58ylI7cy5VD/MBZU2tE84IMvxK9vuvzfB834/idnTnlHRaYp/6qRIdedNR1rvrMaf7hyyejHZpda8Y9vn4Iyex5+dN4c/Oi8ObAbR0Kr3G7Ew99chZV1H4+eEgmwMnseAGBbuwvfeWRriv8VI/cgTTo1/OEYFsuseX0qtAwOp6xhhC+o7JXSAKBV2AVJKXZ1ulFszYNJx0tounhDUfQo8Fxg/kQkaH6lHdUOE1ZPL0Jt4ciio3AsftJv+os7u+EOJHdh/srfNuIv7x7Coqp8FKdhVWu3Owh/ZORecDYerFFVYEI0npr2fMkeoSdHeTr5HE6QbZoHhlFfbIGG71vSRokHFTBUk6RWq/C9c2bCmqdFscWAQsv4993icQnb211o7E3+/NFbX96PP7/dhFOnF0613JPKtmuBw6wfOTQ9gUy16DVYWe/A0pp8rKwrwKIqOwzasV8RpS6UOFo2TGHL2Z4uD5bXpfZePn1sWIFrQHhPdRK+sKxqwmbQarUKy2oLJn3O6h2vH0BNms/EzLaVwEPDYQwNj2xtqnYYsaXVddxjVACW1xXgYJ8PG49ZBGbQqrGoygadRo2Dfd6saJ2WDW8M5G5rmxNV+UZ0uNhrOdW63Mr7mjJU0+joPauT0ZbGjft1hSZ0y7ih/lT0eUPo84ZQV2iCxaDF7q6RbUnzKqwYDsVO2Pc4FI1jR8fIm6BEjs9Tgv09Xtmc+JOtIjEJljxeStPhUJ/yOprxJyGNvrSyGkP+MJ7f0QVvEp2PMqHElnfcSC3btAyOvClpKLdBq1ZhZxKzBtkQqB/Z2+2BUadGIMKj4NJlf49XVucAZ4sdCjzJhjdc0qiqwITPL6qQXaDmmrgkJRWo2cYXimJBZb7oMrJeY48XDrPy9zbLycbmIfgUdl+VoZpm04otyJPhsvtoDh1gnS2nX0xFm1O558IqhTcUTfs6iFwTisZx33uHRZeRFPld7bNMsdWAX1+8QHQZo2xGLUw6dVrv18qJUafBXraUQ487iGW12XOYglxtb3dhUZVddBlZ5a63m/DG3l7RZSSMoZom29qc6POOLAS6bFkVfn3JfMEVASvqCuALRhGJS1mxBzMRDRVWdr05onlgGHpuqky7TlcgZQ1ICIjFJXzr75vx1/cPK+IEG4Zqmvzv6wfw+bs+xOCRvqtXrarFf31+nrB6DFoVdnd5EJcS6+ykdNUFRpRaDeNuq8lVA74wFlbliy4j6w34wphZaoWO8+0pI0nAf7+4D7e/1ii6lAkxVFMsFpdw9zuH0DroR7c7iBuf2I7YkaWkXz2lDhcuKBdS16Kq/JxqWecORNDrZSP5Y+3ocGFpTb7oMrLe9nYX6ovNcCj0+DK5+tPbh/Dizm7RZZwUQzXFGnu8uO2V/aP3LN8/OIDz73wP6w4NAgD+46J5o/2BM2VBpQ0bW5w5tQrZE4xm1YHsU6XTqFBXaEIkJuHAJLp8UfIO9Pqg1ahRX5T6Ywlz2X+9sEfWnZYYqimm1x4/GjzY58NX/rYBd7zWiA+bBjK+CjOYo/sTWwdzYzFWIlQq1ei+Xd5jzpw+bwjd7kBWHl4hSq8nhD++1SS6jBNiqCbo1T09iCfUEWD8xIzGJfzxrSbc+MT2MUfHpdu0IjMO9vky9npyEs2mDg5TFI7GMafMKrqMnBSMxLG93YWVKT7vN5f97YPDONwvz+saQzVB/+8fO3DB799H+wRbUawya1eWy5vRXf4w2E/+Y95g9LhDAyhzNjYPYRWDNSUiMQk3PrEdXhkez8hLToI+s6Acjb1e/OqFvSd9XKFZD51Mti1Y9Brs7srdPZpxCZhezNHZRzpdAVQ7zJhRYhFdSs7yh+V7L1Bpdna48Y0HNyc4g5g5DNUE/fj82QCAtxv7EIyc+J6UVqPGbJlMszVU2HP2fupH8vT8ET9aU59vwtkWSo8ah4n3s1NsY/MQ/rmlQ3QZY/CKk6D/fnEfgJFphw7nyS9K8yvk0VGl26O8Y5NSbUe7G4uq5fH9kIs6rkbNuJX1DnS5/GgeUN6pK3Int1CV1w1AGbvp3FkosRlQbDHAdpItMbs73bLYslBg0qF9iKEKAHna3OtuY8vTYlapFaFoDL2eEApMethNWngCUQxzCjKjqh3GrD8RSqTtHS6EojEYZPJ7zlBNUE2hCT+9YO5JHyNJEq7+2wa4Mri690QKLYaMrjImecjTqTG92Ix93d4xx5D1sRGGEIVmPdqHAlhYZcfOjtxd35BO4WgcW1qcOHVGkehSAHD6N6U6nAFZBCoA5Ge4wYScdThzZ8Q+o8SCPV3erDoPVsmmF1swp8yKoRzptS3K6/vk03CfoZpCm1rkM8XDa+rHOl0BWAxaLK3Jl92Wp1RrHwrAJMOjBnNVY68XA74QOly588ZOhL+va5VN+0L+9qXQewf6RZcwqp/TfWP4QlFsbXNhVqk8VmanizsQwYxS6wlakFCmuQMjM1d1hTxnNZ2icQnvHugTXQYAhmpKyalzkcSx6rh2tLuy/viznR1uLKiyw27M7lG5Ugz4wrBk+QyJaCoV8O0zp4suAwBDdVIkSTruXL+tbU7s7fYIquh4sRw43m0yjHoNwjnwtdnZ4YZGrca8iuwemSvF7k4P5pbze5EuF8wvw/RieTQ1YahOwpObOzD7F6/gB//YjgNH7plc+/ctkMv5ufkmHbrcQdFlyMrKegcWVNpgMchj2X0mDA2H0dQ3jBKrQXQphJEFc7Oz/PaDKNedOUN0CaM4JzEJL+zqRjgWx9NbO/H01k4YtGqEopPrXDS/0gaNSoUdKVxuX+MwweXn8v2jdTr96HTl3huN+iIz9veI3zdNI72XG4NerKx3cN9qCp0+swgLquTT4IUj1Ulw+ccuj59soE4vNmN3pwcH+3yoLjCmojSsqCvgfrhxlNryRJcgBO/lyZBMZrSyxXVnyeNe6kcYqpOQqr2oBUdOkPGHY4hjpAH+VJRYDdjTJZ/7unLS5Q7m5Ik1O9pdWFyVL7qMrFdiNWBlfQHK7Sd/87astkBWW++UblGVHadMKxRdxhg5eJmZGncgMmHv30QdfR5gpzOA+mLLlFamltry4A+zYfd4etxBLK3JvWO3IjEJOztdWFabL7qUrFZfZMbGZifc/jDmVdjGfczKOge2tDo5UE2hb50xDSqVvFbzM1ST9MSmtpR0qyk06zE0PHbEu6vTjSqHacJ3u+NZVlOAXZ2c9j2ZfT0eWHNoodJH4hKwpdWFFXUFokvJWp1Hmjv4I3G0Dgyj6pjbOSvrHdjIEWpKVeYbcf68MtFlHIehmoD2IT+++n8bcbDXi3vePZyS5zxRZ5/D/cPo94awsq4g4QPGqx1GWTTxlztvMIq5MjlBSIRNLU4ekp0G8ypsY1ph+sIxBCMxzK+0wZqnxfLaAi5MSoOvnlILrUZ+EcZVDAn48ztNeO9AP85vGkAsRU1VjSe5fxqNS9jY4oRBq8aCShtMei36vSEcHufYqDKbAcFIHN4QTx5JREeOnyW6oXlozOpTvUaF+ZV2+MMxrhKehIZyG/o8x3cvG/CFMeALw6BVjTnYgFLnwoXloksYF0M1AT1H9nymKlABQJVAI7lQNI5dnR8vPLLmaTGtyAyDVgNfKAqLQYt93R4GahK63EE0lNtk1agj0zY2D2FFXQE2tTixuGZkFKXTqDCvwsaFbklYVe/AhglGoKEo76Cmw9xyG6oK5Nn6kaGagIYKG95uTG1fX3cg+VMrvMFoSvez5ioDG85jU4sTM0osoyPWSExC+5AfpVYDetk3ekKlNgM28x6pMJ9qKBVdwgnx6pKAL62ogVGX2gUuna5gyp+TErO70w0b++Ki6Zhe1Z5gFBX5qdkvne3K7UbkQLdL2Vo9XV7baI7GUE1AtcOEf3z7FOSleIQzu4wty0SIxCTMYbu4cfG+amJ2dbrZ/lEQtQqy6qB0LIZqgmaWWhCfXOOkExoaDkEtry1WOaNnnMUlBAQiMVQ7OFqdSCwuob7ILLqMnDSr1AqTXr4zTQzVBL2xrxfhWGpTtW0ogGW13DsoQtuQH4uq5ftuV6TyHG3pmKxdne4pd0Gj5C2uzhddwkkxVBPQPuTHL5/dk5bnTvXolxI36AtzpmAcu7s8KOXU5oT84RhqOVrNuEUMVWV7emsHPv+nDzE4nPxq3Yk4TDocGpDPwea5psMZwPI6NkM4lj8cQx3DYkJLavK5BUmARTLvZc1QncAru3swlIZABYDyfGPKmvPT5GxtdcLOlcDH4c/lxHzcH55xeTo1ZpXK4zDyE2GoTkCTpvnBVfUOvsuVgVJbHuIpbOqRLQ72eWHkft4TMmhVGA7yjUemza+wy7I14dHkXZ0MHLuXLxXmlFl5/JMM2PK0ACR4QzzZ51hxCahyyLNjjRzMKrWiyx3C7FIrVtY5kG/SiS4pJ5w5q1h0CRPivNdJRGJxNI/Tb3cqZpZY0DbkT8lJNzQ1M0us2NLGvqwnkm9kUJzIR6OlxiMHWWjUKsyvtCESjaOxl+sk0uX8+fI7leZYHKmeRKczgKW1BTh3bmpaYs0qtaDbHeSZpzKhUo2ccblE5qsJSV4q843YeUy70Fhcwu5ODw4PDGNeBRuLpMNFiyowUwFNWzhSPQlfKIpffX4+bEYtFlTa8e6BPmxvd01qlLmyrgDb2l2IsLeZbGxudaLGYYJuCgfDZ7M+T1B0CbJUkZ83en7qsSIxCYcH/JhebMah/tTOcuUyvVaNH58/W3QZCeFI9SRmlFgwu8yKcrsR3z93Jp7+zmpcsbx6Us+1qdXJQJUhdyDCi98JJHqeby5QAXCY9JhWZJ5wpikQjmHAF0YV+yinzJdX1sj2VJpjMVRPIu+YhvebWoYmfY/VIuO2WrmsxGqAlr8Fxymy6NkHGIBRp8bMEgugAob8YRweGE5o1b47EEEoFseMEnlv/1CKS5ZUii4hYbycJKjPG8S/PrR5wvMTT8TO1YGyNDQcRpRdrcZQqYAiiwGBSO5+YVbWOzCvwgYVgEP9PqyYRJOQfm8Ig74QHPzdn5JiqwELZdxA/1gM1QREYnF85+GtcE5hQzxPtJCfGocJksQp+WOtrHPk/ChVkiTs6fIgGI2jvsiM2CRv3Tj9EUznaHVKllTnQ6VSzroHhmoCtGoV1FP8poY4HJIdg1aNIXYOGmNOmXX04PJcFoiM3DeNS8Ch/uEpbb3a1OLEshoenDFZcu/1eyyGagJUKhX+9YxpU3oOM++pys6x98xznd2ow4AvBI7dkfLWpFvanFhVzz7TkyH3U2mOxVBN0Eu7u6f0+ZEUHxtHU2fksV1jzCq1YMCXnj7XJ1PrMGGajBr4l1oN6HKlfjtRvzfE7VtJ0mvVHKlmo92dbjy9tXNKz9E8yG0bcuNM00EJStU66EexJfP3/vN0arQN+bGq3gE5RE5lQXq2wlgMWuQbuU0pGafPKILFoKxZPoZqAj5sGpjS59cVmnjqhyBqFbCsNh/Lagswp2ykG0uhWY+VdQVo5rF7Y/R5Q9BoVCizZS5YVQDMBi2icQkbmoewor5AeLD2eUNped6dnW64AmGsrCtgr+AEmPQa/Pj8OaLLSBpDNQH9U/wlK7XlpaiS3PLRPagax+RHDiW2PGxpdWFLqxMtA8OYXmyGSgVsbHFyK804etxBxKSRVnyTMaPYDNNRp9uUWg1YUpOPlXWO46Y+dWoVltTkY2uba/RjG5udmFZshkXg1HxZGn9fIzEJG1ucmF7MFcEns6DSjue+expml8m/LeGxGKoJmOrxbz1utnubjE5XADNLLOhwBkZHmROZXmwes+G+3xsabe4QjMZxqH9YyH1DJen3hhCIRDE7gT6rK+scWFX/cWD2eUOASoXltQVYWpMPdzCCbW0ubGwZwpIjK2AXVtqxuDofVqN2TKB+5FD/MBwWA4osmZsqPfrfmolzUkWPxuXsrNnFePo7pyq2cYayJqsFmVlqxeXLqvDklo6kP7eqwIjWIX8aqspelfl5cJgN2N/jgd2oQ1xCQmd7rqp3jDbnqHWYUGIzQJJGevxScoaGIxgajqDGYYLdqIVRr8XW1qExo/sl1fnYeOQIw2qHEXqNGrG4hJZB/7hf821tThRZ9NjZ6T7u747VNuTHrFILnMNhpLu7pwqAPxxFqc2AukIzhjMQqm28JpzQv3+2ATqZn5l6MgzVBHxhWRWMOs2kQrXUZkCHc/zm23S8eRU2HB4YRueR1ZcfjSo9wZNf6FbWFYzpdtU65OebmRQ4+uJ/1qxi7OxwY8g/8j3RH9XfsX1o4p/xSExKapbgQK8Py2oLsCXNb4okACXWPGxpc6LXk577qUdzmHVpu2+rdCvrHJim8Klx5b4dyLDJ/mJr1fwSJ2p+pQ0Her0IjNOw/GRT8HPKrNjYwtFoug0OhwDVyAh1foUN7c70v2nZ0urEykm0CEzGkpp8bG3P3M8P11ic2JdWTu7AEjnhFT9B6w8P4uLFFahKcrl9NAdPIzfq1ChIYnWjTqPCqnoHGnu8JzzJJ980/v01s16T8o36NL5OZxBDw2Fsa3dhd5cnLXs5x7OxZQgr09g4YdAXRia7VbIz5vguXVKpqMb5J8JQTdAVy6vwuy8uhi1vJCwSPxYrt36D8rRqVBaY4PRHsKLu+NZs8yttWFydjzllVtQVmkYXo2xoHjrp0XjjjV4BYE6ZjVNpGVBXaBqd9hVhY/PQuD9PqRCLZ3YZ+P4eL1bWf/xvWVZTgOnFZswuVfa051TMq7DhlksXKKrH74kwVBP0tVPrMOALo7F3pNH4zZ+dC3MCy/5zbfp3YVU+mvpG9n9ubnWirnDsGYhmvRbb213Y3+NFy6AfA75wQufM7u5yH7cCeHF1/pR6slLiTDJos7m51Ykl1ak/raTTFcz4gRcf5fjcciu2tDlxqH8Y3lAUU9xooEgFJh3uuXpZ1rQNza0r/hSoVCoUWw24alUNGsptqC4wYXiCw4oBZOS+k5x0uj9esCJJgEGrQd5RC1rik5z7kiRgwBdCrWMkpPVaNdrYpSpj9nZ7sLxWbFN4SQJ2dLixoNKW8ueuLjCNWXiVbvt7vFhV7xgzFdzlCo5uO8oVahVw15eXotqhjAPIE8FQTVLbkB8/uWAOdiWwLQAYWVWYK+ZV2NB5zErnxl4vtBo16gpNmF9pS2hUeiIDvjAGh8NoKLdiUZWdJ8xk2JY2J5bV5gutIS6NvMGdX5HaYN3S5sTiNIyCT8QXimJD89BxR+yFohO/Uc8mP71gLlbPKBJdRkqJn9NRmOoCE86YVZzwdo1+bwjVBUZU5BsRjMSg06qxOUtXqp7odogvFE3ZhnpfKIoDvT7UF2fPO1ulkCRga5sLM0stONgrrsXjzo6RN7TzKmzY0+VJyXNa9JqMbKeZSFOfDzq1CpEcWOB44cJyfPP0etFlpBxDNUkfNds+a1YxVtQV4NKlVbjvvcM4PDD+VGSna2Tk1n7UCG5WqQUHBF6U0mFFXQE2ZejNQjQuQc1JloxrKLfBpNdgb1diszTpNpVG6/VFZmjUKvS4g8g36dDjDqJ1UPytmmAkjrnlVuzrzu5D4vVaNX75uYasWJh0LIZqkqx5I1+yaocJT157KgDglpf2Jfz5ZTYDgpHsajo7o8SM7e2ujL6mlkdoZdTK+gJsbJbXDEtoks2bV9Y5sK3dOXorIhNtCZPx0Q6DbHbGzKKsvTXGUE3SVatqj/tYPImpmkKLHnu6suddqNWggS8Ym9K90skwZslKQSXQaVTYKsNWj8n83gGA3ahFrcM82lpRrno82d8r/Lx5ZaJLSBvOoaVAMr/aB3p8U27QLxczSixwWAxCLgLcQJ85kZiEGSXyOy1kZ2dyK4HzTYn1HRatddCP6imczCR3Zr0Gn2ooFV1G2jBUUyCZbSKRuJTxPXFHW1xtx5Ka/IRPfRmPSafGyjoHDvX7hN2H2tXlzui5n7nKlqfFqnrHcatU5aJlwI9y+8TTiHWFJlncM01UhT17Q/WmT806YYe0bMBQnaJILJ70vR2RI9VoTMK2tpHmC4uq7KgtTHwVbbk9DyvrHDDn6bCxZUjoaDEcjUOv1cCRxb+ccjCnzDbmoAK58YaiMGjVo3uhbcbx72gprd9uU58P2bhs4IZzZuAbp2Xfit+j8Z7qFPW4g0mHi8h+wB2uj1ch7ziyNaHIokd1gQk6rRpDw2H0eYKw5mlhNmiRp9XAqNegxzOyOrJbRmfDtg354TDr0VBuxd4sXy0piqSANpstg35UH1mV3+MJYnltAXZ0uDCvwo5eTxCRWFzWbwzGMzgcxsq6gqw5KMKgVeP2yxfhc4sqRJeSdgzVKWrs8eL0mUWIxOJYfzixX9wSq0HIweU1DiPaxjmia8AXHnMkl5K2/AwNhzE0HMa8Cht0ajWaB31wB+S1mlPJvBMcuScXR29Z297uwsIqO7zBqKzeBCarsdcHi0EDX0jZDSFKbQbc99XlWFiVL7qUjOD07xTt7/Hgpk/NSuqklEN9PiyvK0iod3AqldkSu0+jxIVUe7o82N7hgjsQRW2hCRX5yprukwO1amS/8YwSy+gCIH8CrTjlJhqXsLXNhYN9ynhjeCLuQARzylLfkjGTpheb8dx3T8uZQAUYqlOWbxqZOk1mZDccjmFzixMzSzO7orLfl1jHGKUfAtA66EexhYuYklVfZMamFiea+nw40OvFtGIzejwjzRFIjM2tTlQq9A1iqc2AB69Zqbj72VOl7KunDFy5sgYatSqhFYjH2tnhytipFMtqC9B8gq5PxzJksLF4uuzocGNGsVl0GbJn0mvgMI+Epk7z8fc9FJXQ7QpgSXW+Yi/q2SLxYyblw2rQ4oF/WYmqgtxrJ6r8q6dgGrUKDrMed1yxKKnPW1KTj3kVNmRizVK+SYeDfYkv5FHi9O94CjlaPakKex6sBi38oRhW1BVg4JiZjEBkZIFPNjUrUSKNwmaO9Bo1/vLVZZhbruyp68niQqUUmVeR+AkXi6rs2NbmSl8xR9FpVCi1GtCYxPS0/Nd7JmYwifvcuaau0ARPIDp68Him+jZT8nxB5ZzGNL/ShtsvX6T4e8FTwVBNkVd2dyf0OLNeM7qVJRPmVyYf4JEsOX6qqc+HhVX20VNNPqJRAUtrCxCXgH5vcNwV0dnMqNfAH46NBirJm0ohM0cN5Tb849unyOJAe5GUNa8gU//Y3I6fr9md0GOHw7GMrUxdVe+Y1IhYiSs+T8QdiIzZRF9fZEaZ3YhNLU5saXViwBce3eOYKxZU2NHnFX/MGSXGqFVGn+sbz52Z84EKMFSnbNAXwi+e2Z1UQ4fK/PRfxJfXFkx6w7spw1t90mmkj6pptDVkgUk3ehwfMPIGIptbph1rWpEZm2TeUJ7G0mnlP1LNN+lw1uwS0WXIAkN1iox6DcJJtin0h9O7ob66wIhtbcndIzPrNZhZYoHDrMO2dvk3HU9Gy6AfEkbeaAyPs5F+V6cbtY7sX6WoUgFqdfbcM88VStjidtGiCuizYNdAKnCsPkXJthxcWedAy2BiW1smw6BVw6BTI9mT2OqLzNjd5UlPUTLQ7w2h/yRTnkVWA1qHlNNwfTKW12buIHlKHY/MFyrZjTp875yZosuQDb61mII+bxC7kzhKyqhTY2PLUFrvZzWUW9HUl3xoqxWyGCJdtrQ60ZDlWwCSnVEheWgeGM7YfvbJ+PmFc1Es8OQtuWGoTsE/NrXjue1dCT++Ik33UlUqYEl1PuqLzJOeunVy+wkO9nkxq9Qiuoy0UatkfGWmEwpG4rL9uTx1eiEuX1YlugxZ4fTvFHhDUfxjc3vCj7cYUv/lXlZbgF53ENvaXVN6HhEN/uUmEpNgNWRvSz45j3bo5OxG+S2mM2jVuPXSBVDxzdoYDNUpCIRjSXVESmWnIr1WjXnlVmxpTc09MpHH0cmJKovnbiL8HitWu1N+9/t/8KlZqC1kK9BjZfElJP2S3c+Zquk3lWpka0QqV+lqOYwBAGTzV2FnhxtzyjJ7iAOlRpcriLnl8vnezauwZf1h45PFUJ2CY3ulTiRVsyQr6gqwvye1/Vgtedqs6fk7FckeOK80nJFQLqNOHvvHdRoVbrtsIbQaxsd4+FWZgrbB5KZkVCkYB1UWGLE9xX2Diy0GFFoMiPGCC6c/fMLvUn2R8qe6mvp8WFKTL7oMmoRdnW5UZaBxzET+/XPzML8y8V7nuSbpUO3s7MTVV1+NwsJCGI1GLFiwAJs3bwYARCIR/Nu//RsWLFgAs9mMiooKfPWrX0VXV+IrZJXCE4wkvd90qiNVlQqw6LUIJ7sJ9RhGnRor6x2w5Wmh06jQ7wuhSeEHOqfKof5hNFTYUG7/eIvAwko76gpN6HEHYTMqfxlCjzsI7tNXnkhMgs0odiHdZUurcPWqGqE1yF1Sv1pOpxOrV6+GTqfDyy+/jL179+KOO+5AQUEBAMDv92Pr1q24+eabsXXrVjz99NNobGzERRddlJbiRdp4eCjpY9umOvW2orYAjb1Tm/bNN+lQnm/ExuYheIJRRKYY0NloT5cHTn8ES2ryMaPEgp2dbrQM+hGIxDCjWJ5bG5LR7Q5iaU2B6DJoEvZ2e7BU0EzDvAobfn3JfK72nUBSb7tvu+02VFdX4/777x/9WH39xzer7XY7Xn/99TGfc9ddd2HlypVoa2tDTU32vMNZe2jwhH+3vLYA/nAMrkAYapUKFoMWRr0GWrUKy2rz0dQ3DHcguS4pFfl52NHhmlLNKgDl9jzs6+b5mBMJRuLjHkaghJZxidjf44XFoIFvnLaNJG8H+3yoKjCiw5m505XyTTrcc/Uy5Mnkvq6cJRWqzz33HM477zxcfvnlePfdd1FZWYnvfOc7+Na3vnXCz3G73VCpVMjPzx/370OhEEKhjxf8eDzKaJW39tDAcR/TqFWYU2bB5gS2ucwqtaDApMeAL4RD/SefRrYbdTDqNAhFpzaqXFnvmHSTfRoxOJwdp7t4glGs4s+DInmDUZj1WjhMOgz9//buO76t8uoD+O9e7T28t53Y8YqdeIYsCCQkgTBD2IWwKbNAWwoUXjp4CW2hUN62UKCF0kJZLZSWQksIBAohey/HxHvbsoatLd33DzlKHNuxZV3pSvb5fj75fLCWH19sHT3Pc55z7JEvYcgwwLNXVCBrGtTH5kNIH7uPHj2K5557DgUFBfj3v/+N2267DXfffTf++Mc/jvp4p9OJH/zgB7jyyiuh1Y5eAm7dunXQ6XTBf1lZWaH/FFHWN+AaNfu2KseA/e0TmwXWdQ1gc4MJ3/QMwqiUoirHgIosPVQndIiRilkUpWqgkYnHDbwTEersmIx0tHcQ6inSxWdniznYvYfEl06rE3qlFAmqyBeFuG/ZLJw+Kyni32eqYDhu4ocIpFIpqqur8dVXXwVvu/vuu7F161Zs2rRp2GM9Hg8uueQStLa24rPPPhszqI42U83KyoLFYhnzOULrsDjw9Md1+HBvJ2yuQMcZiYiBRiYO+5OjiAEKUjTw+v1o6BkMuTD+qegUYuQn81cwYroqz9BhTwg1n2NZWYYWe9viY3WIjJSskcHu9kZsGb84TYt/3rVo2h23s1qt0Ol0k4pDIc1U09LSUFJSMuy24uJiNDc3D7vN4/HgsssuQ1NTEz7++ONTDkomk0Gr1Q77F+vSdAr8fM0c3L+yMHhbZbaBl6UYHxfY76rv5jegAoDF4cX2pn6UpmtohhIGxRSZqQKAO8wtBSKsbpsLRamRe8/80fkl0y6ghiukoLpw4UIcPnx42G11dXXIyckJfn0soB45cgTr169HQkICPyONQVuG2miVpmtD6lYjtP3tNmQYhD/vFq9CLfoRq2pzjagLM5ucCEspFeFQR2RWGlaVp2HejKn7/h0pIQXVe++9F19//TUef/xx1NfX4/XXX8cLL7yAO+64A0AgoK5Zswbbtm3Da6+9Bp/Ph87OTnR2dsLtnnpdUFaUpmBmkgqHO60YDLFkodD2tpqpNOEkHe0dhCjOL51ExGB/u4Ualse54jQtBiLw3iOXsHjo3GLeX3c6CGlPFQD++c9/4sEHH8SRI0eQl5eH++67L5j929jYOOyIzYk+/fRTLFmyZNzXD2ctWwit/XaY7R609jvw7T9vF3o4IZmdocU+2k+blFStDJ3W+J2xZhkVaDFF70gGiYyKLH3YHapGc8+yAtyzbBbvrxsvwolDIZeHOe+883DeeeeNel9ubi5CjNFxL9OgRKYBKEzVQMQycVXqzzToRmGKJuyCEtORXimN66AqmSLnbac7q5P/jP4MvQK3nj6T99edLugviycSEYtvnzFD6GGEpN3sxOEuG2rzjEIPJe7Ee8PvqZRsNZ1FomzhQ+cW0+9HGCio8qgkLT6LTLdFsTLLVOHyxtce+slU0vivYUyADrMTRiV/gXVenhHnlqXy9nrTEQVVHr25rUXoIUxKm9mBOZnx+YFAKA5PfAdVj9+PkrTYz1kgp9ZpdcKolkEmDn/lhGWAR88vpdq+YaKgyqOzS1KEHsKk7W61oDSd3mQnanCo6Ee82tlsRoeFViimgvruAZRn6sN+nStrs1FC7wFho6DKo0urMpGmkws9jJBJRAwKUzQ4EKHzblONiGVgccR3UCVTS7i9mrVyMb67vHD8B5JxUVDlkVwiwqPnlwo9jJB5fByUUhG0cmF7NcYLYxTqrUaDWkb7qlOF2+cP6fEyMYPaXCPm5RlRk2vED1cVT5nfa6FRUOXZ2SUpcVlUYWeLGQkqKSTxXtUgCnQCN4rmC2V4Th2eEILq3Cw9dAoptjSasLnBBIvDjUsqMyM4uumFgirPPD4/EtTx+YnvaO8gKqh59bji8DMTmeK8Ezgfn2lQoDRdi10tZnTbjp+xfvT8UohFFAr4QleSZ3KJCBu+uwTlcZpN6/aGtow0HZmj0MMyGrqsLvqAMEVo5WMv5SskLGrzjOi0OLG/fXjexIrSFCzMT4z08KYVCqoRoJKJ4zaoiiidfly9Ay5kCtiQgAGgkYW/dGtxeFCTS4U/4p1CKsL+MRp6VGTpoZKJsaXBNGI2KxWzeHhVyajPI5NHQTVC6roGhB7CpHj9NFMdj58D7G4vcozCBNbSdC2K0wMf2sKdaW5pNKEsg45RxLPSdC3snuF/t9lGBUrSNNjZYkbvwOjNTG5ZPANZRmU0hjitUPpfBAy6vNjZHH+NwMszp07z7UgzDXoEWypXysQAOGTo5VDJxGg12Ue8qU4UxwENvXZk6hVoNdO51XijlonR0DMY/FolFWF2hg7bmvpPWYc8RSvDbUuovm8k0Ew1Alr7HfDw3WE8wuZm6VHXZcM064cQlkg2hz6VLqsTDBik6xWo6xpAXpI6rNcbcHnBMIE3ZBJfitM06BsMzEQrs/WQSUTY3GAat7HHg+cUQ0VHqiKCrmoE5CQooZGLYXPGR4GAmlwDtjbG38xaaBZH9BOW0vVyNPXZ0dRnD962v92KolQNDnVOvttQS78DtXlGbGkw8TFMEgVFqRpsbexHboIScokIO5rNE3peVY4BF85Nj+zgpjGaqUaAXCLCpVVZQg9jQiigTo5SKkKzyT7+A3mWaRh9D4yPs7N72yxQ02w1LkjFLLx+P2rzjGg22Sf8gYphgB9Rfd+IoqAaIQ+vKsbdSwuEHsa4GvuiHxji3YwkFcBxmJOlj/r3bu0f/f9X+1Ad36JUzaRf2+H2oSQ9PrPWp5t5eUb0DbixpcGEUFo4X7cgF2VxejIhXlBQjRCWZXDjojz87pqqmK2wlJugRI8tfhttCyVRJYPd44/6UmlFlg7tZueo97WYHEhUS3Go04bClMnvsbaa6UNWrBOxDPa2WdAf4nnpxQWJ+OG5xREaFTmGgmoEvbm1GRvrenD7mflCD2VUydr4K/4fC6KxcpafrEJFlh5FqRrMzdIhx6gct4j/saMT4TSubjc7kUA1YGNaUaom5AIk+clq/PqqSqqcFAWUqBRBF1VkYMG6DUIPY1QMgGZa+p2UtggfPZmbqcfuNvOwTOwsgwJNvRP7/zVe5ud4pGJ6441lCklo+94GpQR/WFszZWpWxzr664mgZI0c82cmTKguZ7Sl6eXotDqpU8kktPY7UJ3DX41kBoEjTYGOIQbs77CMONrU0j/xQN5hGX2JeKKsAmQ1k4mpzNZje9PEEwulIhYvXFuN7AQq8hAt9I4aYXa3T+ghjMo86EaGQYFBlxdSMUs1f0NU1zX54ysnm5Gkwq4WMy+vlaSRhRVUtXIxrHFyFGy6qc41YFuImfrrVpdRKcooo5lqhHWGOWuIFLvHD6/XD7PdQ3to42CZwAzhxAb0Yh5b5PF5/XtsLtTkjj6LTtHIMCdTB6My8P3S9XLU5BqQoT9ebjFJI+NtLIQfUjGLmkkE1JWlqbikilq6RRsF1Qj5+mgf3F4/Hjy3CMoYPfvXZXPBoJQEK7KQ0VXlGLCj2YwOixNV2XokqqXITVDx+B34zXza2tiPnARlMHjmGJWoyNKje8CF3a0W5A9lB2fqFdja2I8uqwPz8oxQSEW07xZjZiapkKKRTeos+e1nUhlCIVBQjYDP63pwxQtf4yf/3I/zytPxt9sXxGTz70S1FAlqGS39jmP3CUuz25vNsDk9w24Ll8vL/xZBU58d6QY5qnMMaDLZsbPFPGKf1jy0d+r1A5sbTFBIRDjC47I2mTwRy2BenhENvYMh7acfk6yRoSyDzqMKgfZUI2BhfiJ+d00V5uUF9jKKUrUoSdfx+kbMB7lEhPru+OymEy0GpWTEeUCXl9/Es0iVs9zXZh31dr+fQ7pejo6TsphNtGIRMyqy9NgcxjnoM2YlUdUkgdBMNQJELIMVpanQK4/vlVVm64Ub0BhitCZFTOm3e5AS4X3G3oHoFuBoNtnRP+iGzRWbSXTTXUGyGttCyPAdzepK2ksVCgXVKKnM5u8IBl/SdMI12o4nuYl87p8Op5CwUc+2dfv8cEyyVRyJLIYB/GG2ilpckIjTZlDGr1AoqEbJksKkmMqyTdXKcKBj9OVBMtw3PYEl8uocA2p5Pp4Q7WxbrVwMeYjFA0j0VGUb8M0J/VFDlaiW4qlL59DSr4AoqEZAa78d6/51EL/5tB42Z2A/TiOX4LvLCwUeWYBaJoJEzMZNazqh9Q64UZahw/bmfmxpNEHKY9JZtLNtC1I06LXF5jGv6S7LqMDhzsl/0GUY4OnL51L5UYFRUI2A/+zvwu8+P4pf/PswFv3sU/zfJ0dgdXpweU0WzixMEnp4yDaq0GKKbKm9qWZvW6DKUW6CEm4eG9ArpdHNFewbcIGSvWOLTMyiNteIAac3rH3u25fMxOIC4d9fpjsKqhFw3py0YPk/i8ODpz6uw6InNuDdnW349VWVKEnTCjY2lgEt+4aBYYAkNX9Ltl4eA/REDLhodSKSpGJ23NKfDAPkJapQm2tARZYOcgmLLY2mkLvOnKgm14B7l82a9PMJf+hITQQka+T43vJZ+NE/DgRvszq9+N7bu7Gn1YzfXVOFNc9/hS6rMG3XdAoJLFTfdVIaeu2oyTWgh6eM3b7B6P4OhFtsn5zanEwdtjb2Iy9RBZ1cAg4cOA7gwMHPBZKQWk12NPQOoqF38nunJzIoJXj2ygrqQBMjKKhGyDXzc9FtcyEnQYlfrT+C9qFyha9uasLGuh7BOoH4uUDrqHDOwE13fC2dG5QSNJmi2ykoN0GFfrs5qt9zOuIrYE7EU5fNoUz+GEIfbSJExDK4f2URLq/JxkUVGcPua+qzC7qnubO5H4nq2MlEjjddPCX6zExSj6hyFEkGpQQ7Y6wASSwTswwqs/Uoy5j4dk20FwJ+dH4JzipKie43JadEQTUKzi6JrV96t49DilYOMVV/mBSOA/TK8LJ2JSyDdkt0P1jZnF6k6ahg/kRVDtV83ttmnVDJv7lZOhyOUr5CZbYeb9xyGq5bmBeV70cmjpZ/efb3XW1o6rOjKFWD4jQtMvQKHOqMvXqq+9utKE3Xwu72RXWpaqpIVMtgDiGxhAGQaVAgUS2DVMyizexA6yRquobD6+eQZVSiwyLMXn48SdLIsPOEqkYurw8SEQPPSYllLAPMStFAIWGxs8US8XGJWAZPXToHF85Np7OoMYqCKs9WlKbiN5/W486/7ITb64dMzMIVo2cY9rdbIWEZZBkVdMRmAmpyDeC4wPK5UTn28rlRKUGaXgGVVAwfx8Fsd6Ol3xH8Jyx6I56I3AQlttqOf/io6xpAlkGBZK0cIoYBwwQqU9V32aL6ofnbZ8wYsZ1EYgsFVZ7JJSJ8d3kh1lRl4s7Xd2JvW+Q/vYbDQ9mgIdnW1I9kjQxKmQgSEYNsoxIGpRQsy2DQ5UW72QGT3QNTGMcjIqndLHRQjw8Oz8jzokJ/KBKxDK6n5d6YR0E1QnISVPj9ddW46NdfBjN/Y5VcTGXrJuLYikO3zYXuwz1gGQyVlIuP5fNMgyLqS87xqDBVM2aHHyGdNsOIRB7PSJPIoESlCErWyPHYxbOFHsYppevlEFHC0oTsb7PAqDqeoBRvk3xKTBtfskaGHmtsfgheWZoq9BDIBFBQjbAzC5ORn6wWehijqs0zot3sjMlEqljk44CCZI3Qw5i0xj47ClJi83cxFmhkYqhk4phcuhexDM4tSxN6GGQCaPk3AjYc6sL7u9qRplfAbHcHu5zEGqquE7p4r0RlGnBjRqIKRwXO+GaZ2Jrpl2fq0G52xGwm/E2L85BAS79xgYJqBDg9fhzosOK9Xe1CD2UYiYjBrBQN6jptqMwxUFWlSfD6YzOTe6L6Bt1I1QnTxSRRLUWWQYFvegcx4PQiTSdHpkGBHpsLjX3RrSx1jEYmxqxUNbY3mQX5/hNxxqwk3L+iSOhhkAmi5d8IOLcsDf+8a3HMNQpO1cmxv90KnVKCPa2xnZUcq9gpcDZQJkCJzLlZeri8fuxsscDq8MLPAR0WJ7Y29qOxz478ZDWqcwyQS6I3trIMLWQSNqYD6oxEFZ69soLyHuIIzVQjRCpmccPCPHx9NHZmgy0mBzQyMXoH3EIPJW4JEZD41tgbuVmhRMSgItsAt9cPqYgFGMDj9Y9bHrG+O7BFopaKAg0LJjF7VUhEUEhFkItZyCQiSMUsJCIGEpYFyzIQMQgWTHB5/NjVeuoxCU0jE+OFa6uj3nOXhIeCagTlJaqEHsIIeUkqmqWGQczGf1DVKSXwgwupItREVWQbsCWMbYUBtw9bGwOVjGalqKFXSsFxgU4vPo6D1+eHx8fB7fXD7fPD4fbB4fbC7vHD4fGNer40HjEM8OyVFTGb5EjGRkE1gvSnqLojFLmEzqSGwxfNCvgR0tA7iMJUDQacHt4blvv9HBgAfFyluq7YTPCLhvtXFOHMomShh0EmgYLqNCJiAJszvrNXhdbHUx9VoR3utKEyW49dLWZes3C3NfVDIREhN1EJrVwCp8eHFpM9Jo+pxKozZiXh22fMEHoYZJIoqEZQkkaGs4qSseFQt9BDARA4Z9lujs2D7fGizexEYaoGh6fA2d4dzWYUpWrAMMDBDv5+HofHN+L19EoJ/H4OLq8fIpaBQiJC3yDt7Z+MZYCHVxVTsfw4Fv8bRDFOH2NJBoUp8Vu8IJokIgYy8cg3tqocQyABZ4o41GnDwQ4b0nVyVGTpI/Z9zHYPrE4vXF4/ZmfoKKCO4YI56Sigv9G4NnXeHWLUgMsr9BCG2dZkQrZRKfQwYkaWUYF0/chzm2UZOpSmj95DUyKaerOIdosTBzqsMIbZJ3YidjT1Y3b6xBt/Tyc3LaZl33hHQTXCYi0xyM8BallsjUkIaToZZiap0GJyoN3sRGm6FjOTjmdre3wcvCf1zlRLRei2OtE34EJNrmHKBVeX14/coYx1hUSEimw9StLGDn4KqQg5CUqEeoTS6+dwpHsAOfThbpgzZiVh9gSaoZPYRkE1Qvx+DvPXfYKP9ncKPZQRDnTYUDqNZwql6RoMunxDHWYC9rdb8U3PIErTtZibpcfeNgsOdFiRqVdAKWExL88IhmHQ0u9Ak8mBrY39kIpYVOXohftBeCaXsNDIxZiTqYPP78fOZjMOdVqRrBlZHq86xwCfz4+mPjvKJhEIXF4/JFPgzC9fWAb44apioYdBeEC/1RFyqNOGvgE33DHaoFwtm545arW5RhzssMHqHH1Zfn+7FbuGChV4/Rw6rE74OGBzgwm2k5byB90+NPc5pkS1m9o8IxgAG+t6sbvVAvfQLN3PjTxvrVNIsLO5P/gY2SRXY+q7B1CbF1tVx4RyZW02ZtFe6pQwPd9Zo+DuN3bC7YvNgAoEeoKKWQbeWKpqHkESEYOyDB22NIZWmMDn507ZeKBnwIVsowJKqRhauQSDbi/qumzw+OLnuhYkq09ZsKHbNvwYUUGyGtua+oNft/bbJ10gfypkUYdLIxPj3rNnCT0MwhMKqhHy3NWV+OkHB/F5XY/QQxlVQ+8gjCoplFIR7C4vtAoJkjVyuLw+HO0dhG2MmVy8EDFAZY4BLMOA44CjvQPY0WyOyPdqNg1v/C0XsyjP0WP7CYEnlunHSU5KUsuC3Vs0MjE6LMN/3nazExXZeuycxPWdKhWQJksmZvG7a6uo+fgUQkE1QgpSNPjD2mpc+eLXwbJrscY06IZpaFvRZPcMq7Vama3H/nYrXDG6fD2ewlStYNfd6fVje1M/yjK02NtmFWQMoRivSFS3LXC2WSMXI10nx+FRKh1NttFAolo6bc9OS0QMnv9WFRbMTBR6KIRHtKfKk/UHukYsE4pFLNZUZQo0ovDsaDYj06AYdxYTq/yc8B8GYi3zezQSETNuD9FEjQzVOQZo5OJRAyoAOCc542w3OzE3S4+qbP2knh+vlFIR/u/KSipFOAVRUOXBNz0D+O7bu0ccLdjfbsEXR3qFGRQPvukZRH5SfBb0rusaELwY+e4WMwpivCB6RbZ+3EIM2xr7sa2p/5QzSpd38su4u1rMGHBPn2Xg8kwd/nX3YqycnSr0UEgE0PIvD17f3AyLw4Otjf3BbMYjXTZc8OsvT5nkEg+OdMdnIomfA4wCNzRw+zj0DsRuQtjsDC228bREbhoIr7avJ063GULBMMC3z5iJe5fNgpSOE01ZFFR5sKw4Bel6BQ60W5Cmk+OjfZ042jsQ9wEVAApTtNje3B93P0tpugY7moXfy+63e5BhUKCt3zH+g6NoZpIK9V0DvBXTN9ndmJ2hxb5J7CFnGhRoN8fW9eFbqlaOX14+h/ZPpwEKqjyYPzMB82cmAAC8Pj9e+aoRbVPkTWJnS/wF1LxEFRp67TExO2QAmGKsKXy6Xg7ToBtOnmeHrf0OFKVqcGiMYzIJKimMKinUMjGkYhZ+joPd7UV99wBcXuH/X0XKvDwjnv9WFQyq2GsFSfhHQZVnbp8fBpVkygTVZI08rn6WmlwDDnXYYI+RPbqSdA32t0d/CV3MMkjXK9Bssg+7fW6WHh1mB/oj0IrNbPfA6vAEt0C8Pj/sbh/Mdjd6B1zoG3RDLGJwpHv69Em9YE46fnFpOWTi2E9aI/ygoMqzTosT33SfOpsynqTr4yOo1uQa0Gyyx9zxJZU0+tnTyRoZNHIxWvvtKE3XYn+7FXOydLDYPcFqUZHi53DKQhKKOMiI5suy4mQ8ffncKVFxi0wcBVWe5SWqoFdK4LDExkwpXC0me6BARIzM/E40K0UNvVIKjuNgGnSjyxp7DcSFaIuZpJFhf3tgb3N/uxVSEYPdLZboD2QUKVr5sPPQU1VJmha/uqKCAuo0REGVZwzDYE6mHh2W2CukPxmdVheqcwzDytIJLT9JBbePQ90YZyZjSWu/Y2iPNzqrFzOTVMGAeow7hkomHu6Kz2zyUGToFfj9ddVQTdP62tMd5XVHwMxk1fgPihNGpWTEvpxQJCyD2jwjjvYOxsyYxtNmdqDf7oZSGp1lT608tot15CepoVVM3WBz9bxsfHjPYqTpFEIPhQiEgmoE/DeOCz7olRIUntAtIydBNaKgerQla2SozTMiVS/HlgYTb8dAosVs90StulK3zQV1lAL4ZLT026GZojO4+1cW4n8vLov5DzYksqbmb7fAdAIXHQiHVi5BQ+9A8GiEWBSYHYJDyB1ewpGhVyDToECPzYWjvYOCB/ZwRetYUpvZgZwEJfxWJ+ye2CqokJ+sRpfVGffNGkaTbVTi5sUzhB4GiQE0U+XJ/nYLfrX+CAZdXty+ZOaIkoXxotlkR5JGhua+QeQnq7G1sR+7mvvDKkMXqvxkFXoGXNjcYMLRKO1FRlKGXg6Lg/8jLGNp6rOjLFMfte83ESwDWB2eKRlQAeA7SwsgEdHbKaGgGpZumxMLn9iA7U390Cul2NtmwVlPfYY/f9006a4dQmMZYMDlhd3jR5fViTlZOsxK0WB3a/SyR1mGQW6CMmrfL9IyDdH/WWJtZl+Uqo25MfFlSWESLq7IEHoYJEZQUA1DgirQA/HKF77Gm1uaYVBJoJSK8M89HSOq+ZRn6jA3Sy/AKENTmq6FxRGYTdicXuxuscDi9ES1W01d1wA0U2hfyhyBQgvjaTM7EEvlZTnE2Ub4BKXr5Hj6srlg43VpivAuhv7s4o+IZfDS2mrIxCye3VCPt7e1jtlsmOM4+EfZV5udrkWyRibIecbRiNiRvxItJgcS1VLU5BpQm2dEUaoGc7P0Ee/AUptnRJZBgUR1/O5RG5VS1AnQlMDt9WNOpiHq33csTVPwbKqIZfDrqyup/CAZhhKVwuTy+mFzHd8n2tdmgU4hGbGH5vT64XAN35eUilkc7rQhJ1EJu9uHAZfw+01jjaG+exDA8P1NhYRFllGBFlOg4lKyRobcBBXquwdgsodX73b70LlYnUIMbwydswyFhGWQn6LClgZhav8yMfSRuSBFHTMFKPhySWUGKrNj54MLiQ0x9GcXn1K18mGzU4fHD5YBanONQzM7A2alqHGkawCtZgdqcw2QiVnIxCzmZunh8XOo7x6EVMTGxD6iMYRP3Q6PHxwH5CUqMS/PCKvTgy2NJthcHlTnGiCZ4JJYXqIK8/IC1+vE5yRrZDCqZBiMwWpOE1Gczl9rtcnotIzd/zTaTANu1OQaptQZ1esW5Ak9BBKDGI7jYmoaYLVaodPpYLFYoNVqhR7OhPzy4zo8+8mRCT/+WNw4eTVYIxcjWSPDNz3Rz3hVy8QoTddi8ynqto7FoJTAz2HE7Lw4TYPmPvuYQTFBJUVuogo7mvtx7LdQKxejKE2LLQ0mVOXosb3JHPJ4YkltrjGqR5GOSVRL0Rtj3XEAIDdBOSXKFM5KUePf95wOJlb2bQivwolDFFR50G52YNHPNvBSlEAtFaEkQ4cdTf28ti5jGKAiS49uqwtSMQupmIFYJIKIBXw+DvXdA2G1AqvM1mNHs3nE7TMSVUMVhcRgGcDHcWDAAAzQN+CCc4yzlBVZeuxsMZ+ylVg8UErYqJ4Xrc0zDnWH8eJQZ2yWcYz3/6cA8Py3KrFydprQwyAREk4cmjprMVHWYXHgsQ8O4t5ls5CfrMZZRclYf7A77NcdcPuwpcGE2lwDtvC4dJipV4wa9Piyo9k8ao3go72DSNfLkaKVYVeLecIfPNotDkhEDFSy2K0ONB4RAxSn64L7w9Hg8fmxM4L/n/kQb/15T1aTa8CK0lShh0FiFAXVSeA4Dve/swdfHOmFiGHw7JUVuKw6i5egegzfuTkt/Q7eA/XJtjX1Y16eccQScrvZiXZzaPt7XVYXavOMGIyB5K3JKs/SRzWgAkCsnlzJTVAiWSuHx+uH2xdblZ4mQipisTA/ActLU7GiNJWWfcmYKKhO0uMXl+HmV7fh/d3tWFqcjCWzkiFiGd4+hYt4/Js1qiRI0siBKLwPbGkwQSERweEJP7loZ3P/mEeUYl2kP8CMpclkR6pWhs4Ya4OXrJGdss9qLJubpceL11YjSROfv4skumhPNQwH2q04/9f/BQC8ectpcHv9uOqlzby8tlLCwqCWoa1/Yg3CjSopkjUyqGVisCwDj9cPs8ODLosjqnt6ElHgg0Wcr/CFRasQg/Nj2FGraJKJWRSmaCARs9GfKZ/CnExdVCtz8WFRfiJevLYaihhuUkD4R3uqAilM1SDbqMTMJDUKUtQQsyzkEnbM5JtQ2D1+FGtOHVS1cjFmJqlxuNMK06AbpkFhsz1ZBpiTqY+p3qtCKE6dXBY1X1xeP/a0BYLXjERVzNRPru8eQIZegTbzxD4oCm1Gogq/ubqSAioJCQXVMHxysAt2txfPXjkX9725G5KhGQJfn8bbLY5TLimn6xXY2WLm5XvxIcugmPYBVcwiZjJb03VyNPbFRkAFgEG3D0Y1kKKRoSvG6wBr5WK8tLYaOsXUKZdJooOCaoi6rU6s+/AQrqzNhsPjg0EphdfP4ctvennvwNFhcaEoVQOdQoIBlxdNffZgxaPaPGNM7FElqqXITVDB5fVhwOUDy4w8fzudlKTrsCdGljgzDAq0x1ABCCBQ8lIrF6Mm14A9rWa4vLH3yyJiGfz26irMSIpsGU4yNVFQDZHb54dcwuKNrc3otrqwKD8RWrkEj55fio8PdGL9wW5ejwycPOvJ1CugVYixTYCCAicTs4Cf46b97PREohgqrN4co0UWrE4vtjb2Q6eQYG6WBvvbLRhwxU7VrEfPL8GigkShh0HiFCUqhcnu9qJvwI0soxIWhwfnPPN5zM0OIqU8M3ZmZbFAIWHBAbzsqYdLp5BgwOnh/WhWJKikIsFLOh5z9bxsPHbRbDoyM81RolKUcByHO17fgYdXlSBdrwAAbD5qwvWvbEWqVg6n1ydImy+hxGvP2EgpTtNGtMDGRMnELORiFpY4CKhAYK91W2M/KrL1ghauqMjW40cXlFJAJWGhgvohYBgGNblG/PSfB/DYPw8AABYXJEIjF6PT6pxWARUYWet3uouFLkMAMCNJFfOJQKM52jMIjUAVtBgG+OmFsyER0VsiCQ/9BoXo+oV5uH1JfnDvrMPi5D1BKV409A6iOseAgmR1zPSDFdKJBewlfFbvCJHN6RUsOIXD4vCgKE2YLZ9LqzIxO0MnyPcmUwsF1Ukoy9ThwXOLAQDJWhn0yumbdr+tqR9Hugci3rA8HhQkq1Gba0RpeiAw1OYaBRlHa78DNpcPyRoZanPjq9/n9qZ+zExSRfV7qmVifG9FYVS/J5m6KKiGSSYW4cPvLMay4mShhyKYuZl61HXFZkeUaNrcYMLhLiv2t1vh8XHosjoEncF321zY0tiPwpT4+cDj5wCn1w91FGfad5yZj2SNPGrfj0xtlKjEgzSdAstLU3ktqB8vJCyD5v7YKTAgtMJUbfD8cJPJMWqDgWOidaZXJYuvP/O2fgdStDKUpAeWYxkE+gQc+3xidXpwsIOfAhvZRiVuWJTLy2sRAlBQ5Y1jjEbcU11Zpi4mMl5jxfam/mH9Qnc09SPbqESzafiZ0SyjAoNOLxRSEXoG3HCH0ct2PPFSFvBEXVYXusZoCpColkIhYeEI8+hSllGBl9ZWQyaOv/1nErto+ZcnV9RmYXVFhtDDiDomGq1v4ojPz0F7Qmk7j5+DiGWgkBx/4840KDDo9MFk96DN7ER5hBNkuqyuqC6nRlrvgBvlmfqwXqM214i/37EIs1I0/AyKkCE0U+WJTCzCmqpMvLerbVqV6dvXbkZeohINvbFZvSea0nVyGFTSEeUjG3oHUZSqAcsAarkE9V0DMNmPZwo7vZFf5UjRyjHQM3WW6fe3WwNJWAwDjuNgc3onXHP5kspMrFtdBqmY5hSEfxRUeeL3c/jFfw5Pq4AKAC4vB9OgGzkJSjSdoixeilYGjgskz0xFCqkIHDjsb7eOev+p3vAbohDskjVyeH0cxCIG3VYnbDFUFnAyBlzeEf1qi1LVONR56oS5sgwdfnZJGcR0HpVECP1m8YRlGbxyfS1WV2QMW+qbDiwOb+CMYerIpbTSdC1mZ+jQZXWBZQBNnCXNTFR5hg69NjdyE5QhP3fQ7UOqNrTsU6NKEtK19HMcmkx2fNMzGEwAmmp0Cukp7xezDH6+ppwCKomoqfkOJxCdQoLqXCMkIhZvbmsRejhRZbZ7YHV4UJmtB8syEDEMuqzOYTO3TqsLVdl6bJ+CiU0+P4dUvRyNffahRBoRWibYYB4I/O50Wk9dM5plECxQsK/NAqVUhCSNDD0TmP37Tyjx3TFFa1P3jdNP+PYz81EsUHEJMn1QUOVZk2lw2gXUY/wcxs0E3tFsRmGqBodjpOcoX3a3muHxcZidroXV6UGzKbSMW/EpKjCl6+XINChR3z0wrIHBgMuHGYlqONy+U5ZIVElFaDxhz7vZZEeOUYGmEMcY677pGUCSWoaegZEfMgpTNLjzzHwBRkWmGwqqPLtgTjp+t/Go0MOIWRyAb7ptqMk1oK5rYMrUD/b4uLB63IpZBmqZOBgcZWIWs9N1GHQHEnDazaPPLve0WcAygEEpgdfnR4pOgQSVFH2DbnRZnEjWyiATi3CgY/he71RcAuU4IEkjhc3pgfOEI0osA/x8TTklJpGooKDKgzazAxsP92Dl7FSopHRJx+P1A1uHkkyyjQqkahXYEgP9YcMVzuGi3a0WpGplKEnTws9xONRhxfbmibVC83NA/1AzB1v3AOpPuM/WM/oMdqoWjj/QYUNeogqDLm8wKe7mxTMwJ0sv7MDItEERgAd9Ay489O5ePPL3fSEnnEx3zSYHmk2OuOvNWpmth8fnh8fnh04hxb42Cxye8DJqO60udI5R8IBvcsnUDKpA4AhTZbYe3TYX8hJVuPfsWUIPiUwjFFR5UJKmDS65xWP1mlhwtCdQlP9ItzA1hBPVUsjEIvQNukY0GVdIREjXy6FTSCARseiyOkfsHWvkYgjYmCZku1osqMjSo75nYEp2WTraO4g5mXr8cFUx5NMsG58Ii4LqJLm9/uAejVjE4up52Xh2Q/04zyJjGXD5cKR7AGk6OTINCrAMAz/Hwefn4PVzkIhYiFgGbq8fhzttYc8KT5SskcHicKPXG8geVUtFMKplUEhY9Ns96La58M04Z0ltTi92tsTPTBsAdraYkaCSoiBFjSNjNERQSEQ4pywV/9nfFTP9YifCbPfgorl61OYJ0ymITF8UVCfpnjd34rdXVwW/vuWMmfjrjjaaqYapw+IcceSjJtcQ3IMFAKmIQXmmDhIRiyNdNljDnGnlJqqwpeH4suuA24cB0/SoENU36IbH50eGXjHidzdDr8Df71yIRLUMLSY7Lnnuq7gp3lGTa8BDQ+0ZCYmmqbuxEkF/29GK/+zvGpa5qpaJ8f6dC7EoP3FSr5mXGN0ekvHEe1KZKrePw55WC7Y39WPA5UVJmhY1uQYkaWSTen27O35mYJFgdXpH7Qn82MWzkagOXNMsoxK3L5kZ7aFNSoZegee+VUXZvkQQ9FsXIrfXj++9vRteP4c/f9007L4EtQwvra3G4oKJB1Yxy+AXa8onVYlnumAwdmatnwMOdFixtbEfPTYXKrL10MpDW4AZmIJ7iqHa324NNlcHgKJUDZbMSoLXd3x/+Yra7GCQjVVKqQgvXlsd8+MkUxcF1RBJxSzmDqXnn5zp6/X5se5fB0PKAP7t1ZW4tDoLvmlWMzgUO5rNqMwxTOixO5vN0MglwVKRKqkIldl6FCSP3ahbxMZRhlEEdVmdyDYqAAA3LMrD3jYLav53PRY+sQGfHOyCXCLCovwEgUd5aj9fU46SdKqaRIRDQXUSnrikHIsLEpF/0ht1t82FTw514+3trRN6nesW5GJ5aSr8fg41Ewwa05U/hE4FbebAER0ASNLIsKPZjCPdA6gY46wiw1BQBQIt1ZpNDhSlajAnU4+rX9yMfrsHbWYHbn51G17b3ITq3NhN/FlTlYnzytOFHgaZ5iioTsKsFA1+sWYOjvYOz5h0ewPnFgEgTSeHUSUdMQuSiVnccvoMvHRtNR49vwQA8N6uNjz1cV10Bh+HFBIRDnWO3v1lLE19g2AYDOucM9oem1omRo9tatbCnaxzZqfh7W0tsJ2Q7evngB++uw8b63om/boyMYt/3rUIczL5Keh/aVUmso2BbZMsoyL490SIkCj7d5JSdXLIxIElRovDA47jkJOgxGs3zUPfgBu1eUZsOtqH3S0WHOiw4h+72wEAd5yZj7uXFgx7rX1toQWM6aY8U4fNIZb/G614f4/NBZmYhWuohJ1ExCDToJhwH87pQCpmcfVp2Xjy34dHvf/jA12Tfu3FBYnISVDiIE/Xe/7MBJw/Jx3XvbwFT182Fxr5yGQrQqKNguokvPTFUVgcHnx3eSFcXh8W/2wDrE4vfrGmHJdWZyE/OfC48kw97np957DuGb5RljG9fv+I20hAeUboAfWYk7vhHO0dhFEpxdwsNbx+P9rNTgqoJ1ldkYFEtQzqCLToazbZoZCIcMPCPDy/8ZuwXksqZrEwPxEpWjneuGV+TC9Lk+mFln8nYcHMRDz32Tc42GFFY689eE7y/zbU49cbjmDnUM1WtUw8YlY62jlWD2UpjUkh5bcajsnuxuYGE7Y3madsC7Rw3LAoD8Cpm6pPxKqyNPzskjIwDPD05XMAAHVdA2jss+OBc4rw+7XV0CkmP7OUiVgkDx2hogIPJJZQUJ2EknQtFhck4tef1kMpFaE4TQulVIRmkx1P/qcOt/15BwaH9qOurM1GpkERfO5ZRcnB/97XFqjAc+yxF81Nx61nzAhmFxPA5eWvchI5tcUFiZiVokFj7yD+W98b1mudPycdl1Zl4a6zCnBxRSaumpeN4jQt9raZcbjThqM9g1i7IBeTzRGzubzDevUSEisoqE5SYaoW/9rbAaVUhD9eXzOs+fFtS2ZCNbR8JhWzOGd2avC+Y4kVnx7uxnUvbwEQSKqZkajC05fPxYPnFOPd2xcMC77Tmd1NQTVablo8AwDw8pcNYb+WRi4GyzK4b6iY/eMXl+H7K2Zh/oxE/GtvB/73Xwfx7CdHwI2xSCMVs8OK/sslLN67YyHW33c6so1KsAzQGkITeEKihfZUJ+lAhxUcBxzssGFRQSJOL0jC9qbAsq9RJR322OyEQLUkqYhFhl4Bv5/Dj9/fj9MLAofrD3XaoJGLwXEAwwSOeDRPkzJ5pyJiGejDWCIkE6dXSrA4PwGvfNmAP25qGv8Jp1CRrcfCUSqLnVWUAgD49hkzMTdLD6vTA9OgGx/u7RzW+o9hgFeuqwHDMLj+lS1wevxYWpyCdL0ct/95R/BvIxL7voSEi2aqk3R2cTLyElXBZbK1C3KglYtRlKpBuv74cq/H58c/drWjKFWDn68ph0ElxZff9KLZZMftZ85Es8kOl9eP3gE3Nh4JHFfw+TksLU7G/BmxfdA+ElgGKE3XojrHAJVMhC2NE+spSsKTZVDiD1824kf/OBD2a50xK+mU9yukIpxZlIwL52bg+oV5eOvb8/H8tyohHerxynHA4S4b5s9MwIvXVgePQjX12cEhkLV9wZx0LJg5/f4+SOxjOG6sBRhhWK1W6HQ6WCwWaLWxXxnlUKcVRamBcX71TS92Nptxx5n5p3zOD97ZA7fPj6cvn4umvkF4/RwsDg/a+h04f87xw+u/+bQevxjjaMNUpJGJkayVjdsRhgTIJSz+cvNpWH+wCy9+3gC3b/JZ5CtLUyEVs3h/6OjXqdy7bBbOKUvF8qc/H3b791cUYlF+IsoydGAnUaXqq296cfMft8Hj4/D1Q0uDKz6fHurGD/66B+u/ewa0cgmcHh9kYpaKdpCICScO0Uw1TMcCKhDICr5+Ye64zznQYcUtpwf2r3ISVDjYYcWGg904rzxt2ONuPX3GtDrQXpKupYAaAqfHj5v+uA2ZBiVevr4mWJpxMhr7BidUlOGy6kx8Z1kBGnoD/59yE5R49PwS/OnGWry6qRFFaZpJBVQg8Pfzl1tOg04pwbp/HQzefmZRMj6//0ywQ0FULhFRQCUxi4Iqz5TS8fd5Hj2/ZFhi07s72vDrT+tx5+s7h/WsFItYLCtOgWSo+/WtQ4F4qnJ4fFDLqKF0KPoG3Xjwb3vh83P44aqxW50xTKB5w1gOddpQlKZBmu543eq8RFUwse6YwqEPkYlqKV69oRYbvrsE1y/Mw+KCJFxalRV2Rm55ph6bHjgLV87LxomLaHKJiPZQSVygoCqAkw+qH1u2+2BvB37yj/3D7ssyKnHPslkoTtPi3rNnQcXzuc1YsqfVggGXDwqpCEoJ/WqG4sn/HMaaqkzMzhh9qaosQ4eX1laf8jU+P9KL31xdCbmERUmaBmcVJePPN87DvBPOgbqHqlFV5Rhx+qykYbPSe8+ehZK08LdsxCIWldkGmo2SuETvXDHgJxfODgbLjXU9cHqGHyO548x8vHfHAsglInz6/SV469b5WFGaIsRQo8Lh9iE/WSP0MOLKnlYLrnjhazx3dRXKMkYu4zb0DmJeXgIumDN2wfkVpamozDbg43vPwE8vnI3f/7cBF//2S9y4KA9ilkG2UTnseNjJRCwDeRhL0IRMBRRUY0BeogqPXlAKAOiyunDOr74Y1scSQLDOcLJGjto8I567umpKLwfTJCV0u1rMELEM3r19AVadtD9vc3rxp68b8djFs4dVMhKxDPISVbhhYR4qswOdkuQSET7c1wkgsCSfZVTil5fPxWs3zUNuoip6PxAhcYg2KWLAV/W9+PuutuDXjX2D+OJIL848RQEIlmXw4LnFSNLI8NgHB8d8HMNgzAP2sWyQij6EjGECy7NiEYsn18xBU98gZqfrcPqsJOxuNWNLQz8ur8nG0uJk/G1H4PftW/OyMX9mAlbODgTh5zd+gyc+PITCFA2evnwOlpekQiUTD8sBIISMjYJqmEyD7hHFHkLRN+DC9a9sDXZOqc014vlrqmC2u8d5ZsBNi2fgQLsVf9t5PCgblBKcWZiMs4qTwTIMbn9tx7DnrKnKxDsT7PkqlN4Bl9BDiFnz8ozITVDhzW0tw27/7HtLkDNUaEQhFeG3V1UhVSeHVMzi3LLjM9flJSl4b2cbHl5Vgmvm56D9hHrUuUPP/83VlSP6BRNCxkfLv2EwDbpx+s8/DRbQn4xOqzMYUAFgS6MJN/5xK7RjVBJyenz4aF8H/rSpEfXdgX6uP7loNu5dNgv3LpuFv942H9sePhu/vHwuzitPH1HDdXFBIh67aPakxxsNFdl6mO0eoYcRszY3mHBmUTIursgYdvtrm5uHZcxmJyhH7SG7pDAZC/MTccOiPEhEbDAQA8DZJSlYVZ6GmUm0zEvIZFDxhzDsbjHjhle2omZodjkZHMfh+le24rPDw5s/37goD8tLUjDvpKpKD/x1D97e3oorarJQk2vEF0d6sbfNjO+vKMLZJSOTl7qsTnRanOgdcEGrkKAsQ4en19fhdxuPTmq8kVaQrEaXzQmrwzv+g6cxnUKC12+eh4ff24edzWZkG5VoNtlxeXUWnrikbNzMWZ+fg2iS50kJmeqo+INA5mTpse3hZXCG0UmFYRg8/60q3L20ALkJx88E/v6/DbjlT9uH9V81290w2z14/OLZeG9nG+55cxf+uqMVIpYNdsLhOA7f9AwEn5eilWNOlh5Li1NQk2vEi58fDSugpmhlvBybGItRJaWAikA3o52PnD3mjNHi8OCeN3bhd9dU4dyyVPzPeYEiIW9ua8GX9X3jvj4FVEIig4JqmBiGwR/W1oT1GnKJCPedPQvr7zsDF809fuTh3mXDe7HqlVI8f00VFhUkoThNi8urs/DeHQvxr7sXoThNC6fHh7Uvb8XSpzaif5Q92e1N/XjmkyOTHqeYZfDStTW4dn7OpF9jPDYnLfsuzE/Ak5fOgdPrQ8VQRu5oZiapkayR47dXV2FRQSIyhmpOP/XxYVgcdB0JEQIFVR5MtizbycQiFpdWZ+HMwiRo5GK8uqlp1H6iGXoF3rltAX62phxzs/TBpb6n19fh87rAMvLVL27Gbz6tD/Zs5TgO9721a9jMN1SXVmdBJRPhqY/rJv0a4+m2Tc8EJZmYxaryNLxwTRX+eH0tmvoGcdaTG0+ZUHbhCR/A5BIRvrci0GZtZ7MZv/8iNpf3CZnqKPs3xtTmGYPdN0bbF+M4bsz9soMdNgCBEnKHu2z4xb8Po8vqxOwMHbptLjT1hd5O7sQjObecPgP3v7MbPREKfBqZGL0DE8t6nmpuXjwD31tRGPw626iEXMLCMVQIJD9ZHUxMAwIfrJaXDi/EcOGcDDzx4SF0WV1jJroRQiKLgmoMsTk9eOo/deiwOODw+PHo+SWYmXT8WMMbW5rx038eAMswMKqlSFBJkaiW4fw56Ti3LA1/vL4GHRYnnllfh7e2tWJWihr3LJsFjuPww3f3hTye88rT8IOVRegZcGH9gS5k6BXY2Wzm8SceLj9ZjZ0tkXv9WPbcxm9w51n5wYpE25v60T+UAV2YosHfbl+As3+5Ee0WJwAgVScfsS/Ksgx0CgnEbKBmNCEk+iioxhCJiMVftjQHj9hYHR4c7LCiOE0Lj8+PR9/fH7zP5vIGZ57/OdCFp/5zGI+vLsO8vAQ09dlx6+kzcNfSAqhlYry1rQXrD3ZNeBxilsFvr65EZY4BX9YHilBUZhuwq8UMbxjLx6dSm2fElgbT+A+conx+Dh6fH21mB2YmqYdVPWo22eH2+vE/55fgttd2gOOAui4bvL5AoYcTvXhtNbKNSqqbS4hAaE81hsglIry0thosA9TkGmBxeJA11CWkrd8RDKi5CcpgUsoxjX12PPi3vRCxDN68dT4ePLcYapkYPTYXngyhJyvLAL+6ogKnzUzAJc99he+8sQtHugLLym9saebpJz1OxDKYm6Wf1gEVANQyMRxuH8751Rf44kgPavOMwd66Do8Pq5/7CjOT1Pj8+2fi55eUw+Pzj/pBKSdBRQGVEAFRUI2CQZd3wvuQiwuSsPWHy/Dy9bVYUpgcbHelkYuxMD8BeqUELf0OrFtdFnzTlYpY1OYaR7TpAoD73toVTP6RiVncv7IQ1y/MhV45+p7bzy4px6ryNLz4+VE09dnBMIE36i0NJvx1B/9VmMoytNg1TZZ8T5+VBKlo9D+5e4Z6lLq9ftz1l51o7Xfg8YtnI2fomFVD7yDO+dUXeHVTI84pS8V55el4buNRxNgxc0KmPQqqUfD8xm+G1fYdT4JaNqJ3ZIJahtduOg0f3L0Y9y4rwKL8RBiUEuQmKPHzNeX4yy2n4ZXra0e81t6h7F+1TIxXb6iFVi7By182jlqx6McXlOLS6iwMurx4+ctGAMDa+bmwOjy45U/b4PHx+wZenqGbVpWTHjq3CP978ejVrFaUpgYrG5ntHtz86jaIWAb/d2VFsJ8uAFgd3sAKhkGJ3S1mNE4i+YwQEjm0pxoFH+zpwNHeQawoTQ0u505Whl6BO88KnF/9/opC3Hf2LDz6/n6cNiMBqSc0mAYAi92D6hwjUrQyXL8wDzOTVHjk76MnLH1/RSHWLsgFAPxzTzsGXF6cW5aKO8+aiTXPbYpI8Gvpt0/ZxtMyMYu5WXqIRQzELIvcBCUS1TLkJapw2gwjxCwLEctAzDJI1cmRaVCAYRhcUpmJv+5oxaFOG/7n7/vx5KVz8NMLZ+NH/9iP126ah6qcQG/T28+cCYvDg74BF/KocwwhMWNqvqPFEI7j0NA3iAUzE4JVj/iikUvwg3f24O+72rG0OGVEr0ydUjKsMTXHccEWckDguMz8GQlYU5WJ1ZWZAIBumxPPrD+CDL0CT146Bw+/uy9is6F+uyesZgSxSsQymJOlx5u3zh9xX6JahjduGXn7MT9fU45UnQyvbmrCsuJAl6IrarNxwdx0KKXH/1wlIhb/c34J/4MnhISFgmqEMQyD6xfkYcHMBN4TSNrMDrwztM9pGaWCUrvZgfruAZw+KwlAoJF1j82F8kwdLq7IwKqyNOiVUtR12fDW1hbsa7dgY10POixO3LAwD0d7Bod1v4mEb3oGkWNUosk0dZYxl8xKwqXVmZN6rohlsKfVgl+smYOVJzQEPzGg2t1eKCQiSkgiJAZRUA3DgMuL9Qe6wIHDxRVjv4mGO6P49/5OFKdqkZ0wfOl4w8Eu+PwcxCyDs0Y5l/jnr5tQnqkHAGxtNOG7b+3Gg+cWQSpi8dnhHvx1RysOd9pG3Ss9bYYRv/2sPqxxT5ReKUFTHCb/SkUsrpqXjVe+ahx2+yeHuuH2+bGsOGXEkZeJyNArUJiqGfW+X284gif/U4cXrqkaUfyBECI8CqqTxHEc1v5hC7Y3Bdq+ZRqUqMk1hvw6PTYX6rps8Pk5zMnUQ3dSVu4/drfjrr/sxO1LZuL+lUXD7jvW1uviigxk6BVoMdnx+/824LQZRqycnYY9rRZ8Z6h+cFGqBh9+ZzEe++AA/rJleB/Ok/3mqkrkJarw4b7OkH+eiajM1qPf7kGCSgo/x6GhdzAi34dPYpYZcUb3nLJU/HBVMf64qXFEI3i72wePj8MJq+0T9sQl5WOWk0zXK3DTojwspeIOhMQkCqqT5PNzuHFRHnYPFUS4/HebsLwkFdkJStx39qxgZZyx1HXZcM8bu3Cgwxq8rSBZjddvPg1JGhl6B1x49atGvPDFURQkq3HjorwRr7G6MhN2tw/XnJaDz+t6cP0rW+Hzc1heGnjD7bQ68UVdLw532bCjqR87mo9X6TmVRQWJ+N8PDowIFBNVmq7F/nbrqPfNzdJjx1BVpngIpgCwujIDP76gFJc89xXquo6XCqzNM8Js94DjAtnVFdl6fHGkFywDFKZqoJBOIqIOGauLzOrKTKyunPTLEkIijILqJIlFLM4tS0OiWob/1vfijS3NePDcomENn4/pH3RDJRMPaxj9vbd3DwuoEhGDNVWZ8Pk5eH1+nP3Ljei3e5CToMRrN81Dglo24nUlIhbXLwwE2y0NJvj8HM4rT8P8GQlwuH2o7x7ATa9uC/lna+t34MzCZLy1LfRzqXOz9GjtH31/tDJbj72tlpBfU2i7WszQyCW4YWEeHvjb3uDtczL1+OqbXsjELN67YyEsDjfWVGXi9IIkGKZgAhYhZHwUVMNUm2dEbZ4RS4uSRxRfGHB58eP39+Pt7a0QsQx+sLIQNy+eAa9/5JKnx8ehPFMfPBaTopWj3+6BdYItvHa1mPHDc4tx0+I8MAyDg52jzxTHMyNJhYIUNdhJnGBO1clR32XDgNuHsgwtZBIRPF4/ZBIRem2u4Aw13lgdXvQNuIYlU0nFLApTNXjk7/vg9XPosDiwuCAJVZHrikcIiQMUVHkyJ0s/4ranP67D20Otu3x+Dus+PIRLq7JgUElxcUUGXt3UBABYlJ+Ipy+fC5Xs+HLhGbOScKjTBovDgw6LE8la+YjXP9GMJBXazI5gRqjPz2FlaSp6BlzosbnQbXPC6fGP+3Mc7RnEwQ4rjvaEtjQrETFQy0ToHCr4vrdtckE92s4uScH8GQn4+b8PjXp9EtVSvHXraXhvVzue++yb4O21uUZIRCy+fcZMAIH/h4QQQkE1Qix2D3psLmToFWgzOwAAty+ZCYNKir4BVzCgAsAlVRlI0gxf3j1tRgI6rA5U5xhHDdgn+8mFwyv11OQaUZNrhN/PYX+7FQMuLwZdXnRYHHjk7/tP+VopWjlmp+vw9vYWfFnfF7xdKmLh9o0emCuy9NjS2D/uOGPNxroeXD0vG/+6ezFuf20HDnXakKKV4ZLKTJRl6FCTZ0SiWoYMgwI5RiXkEhESNVJkGgKrEisoA5cQcgIKqhEil7K45fQZ2Nncj0f+vh9SEYuC5MAxCcsJS7oV2XqcMztt2HPru224/pWtSNPJcX55xqTHYHN6cMfrO4ONyyfqYIcVKYXJuH9FEf6d2Yl3d7ahw+LEd5YV4B+723Go0zbs8XOzdHEZUAHA7fXjupe3YscjZ+Oxi2bj7r/sxIbvLRmRaCYTi7CshDJuCSGnRkE1Qn61/gh+e8Jyodvnh3moQEOWUYkfnV8CrUKCC+akjzjLmJeoxvULc9FldSJBPbmElwGXF+c++wVaTI6Qn3ukawAeH4db/7QNfg649fQZ+N3nR1GWocMLnx8d9tjqHAN2NMdnQD2mNtcIo0oKqViLJI1s3MxtQggZCwXVCLn19JnY02rBt07LRmGqFl/W92JNVaBAhETE4rqFI4/IHCNiGTx6fmlY318tE+OuMwvw6Pv74fD4Jvw8hgHOLErCLa9ux7Gjkr0DLjx4ThHe392OE4v4zMszYnOct2xbVpyCdavLUN9tQ36yBlefRplGhJDJoy41EaJTSvDnm+Zh5ew05CWq8K3TcqI6A3J6fLisJgv3DBV/mKjzy9PR2GvH0d7BQEu5PCNWzk5FRbYB72xvBQsGNbkGZOjlcR9QgcCHiJXPfI4ua6A93mXVWQKPiBASz2imOsV8tK8DSRoZHn1/P+5fURRSwfqcBCUeOrcYUjGLj+5ZDINSipShrOMXh5Z9TXY3TI0j6wyHQikVwe6e+Ox5smRiFqfPSoLX58fmBtOo3/PjA124cG46FlL2LiGEBzRTnWLe2taKHU1mcBzwyleN6B2YWADMNirxl5tPQ6pODoNSgg/3duLO13egZehsZrgt64755WVzcMvpM3h5rfH8+IJSvHhtNX6/tgaiUxSf/+RgN2zO6dPXlRASORRUpxiX14fP6rphd/tgd3uhU0jGfU6mQYG/3HIa0vWB1nRWpxc7mvuxu9WCjKHbzi5JweKC0WdzGXoFlBMoyTcnU4fVlZlojlArObmEHbbneywBzOn1webyBm8/sQIgywA/WFkIjXz860QIIeMJefm3ra0NP/jBD/Dhhx/CbrcjPz8fL7/8MqqrA307OY7Do48+ihdffBFmsxkLFy7Ec889h4KC0Pb2yOToFBL8a2+gEH6KdmRpw/kzErDpaN+w2wpTNNCfEHyPVXE6vzwd7FAEErEMXr6uBu9sb8XuoVKDFdl6zJ+RgCyjEha7B4/8fR/e390+5tgWDC2x5obZVHt2hhZNvfZhgVLMMtj84DIwLPD65mboFBJcUhk4juQ6oajDD88txpZGEz4+0AWFRIRfX1VBxekJIbwJaaba39+PhQsXQiKR4MMPP8SBAwfw1FNPwWAwBB/z85//HM8++yyef/55bN68GSqVCitWrIDT6eR98GSkvBMCFgMGTabjlZEurcoMthQry9BBNlSL+JND3ajrOn72tK7Lhs1HTfjxhcMzkMUiFlfUZmPd6jKsW12Gy6qzgsvCMgmLz48EzsNKRWxwhnvMytJUfPfsWfD5OXRaJ/+7IBExeGJ1Obx+DkqpCCtKU/CH66qRaVDgja3N0Mol+PYZM3FlbXawutTzGwNHm5YWJWNVeRrWH+wCANy/spACKiGEVyHNVH/2s58hKysLL7/8cvC2vLzjR0M4jsMzzzyDhx9+GBdeeCEA4NVXX0VKSgree+89XHHFFTwNm4xlYX4ifvNpIIgopCK4vYFZWpZRgccuno0VT38OAHjw3CL8ZUsL/rG7HTOTVKjIPv7BaFaKBnOz9VDLJv7r8cGeDpiHOuBcXpOFPa3mYCUpAFhSmITGPju+9dLmsILqeeXpaDc7UJ1rwK+uqIBBKQHDMDhtRsKwGekxH+3rQKvZgVVlafjhqmK8u7MNHAfMGMrIJoQQPoUUVN9//32sWLECl156KTZu3IiMjAzcfvvtuPnmmwEADQ0N6OzsxLJly4LP0el0mDdvHjZt2jRqUHW5XHC5XMGvrdb4qBkbq2pyjajM1uMnF87GR/s6IZewuOusfKypyoRMLMLL19fi9c1NWDAzEf2DHizKT0B+snrYa2QZlfj1VRUT/p4+P4cXvzheFOKiigy8s314h5ucBBWe+PBgWAF1TqYOD68qRoJahrOKkocVzVBKxVCOkujcaXFi3eoy+HwcDCop3t/VDjHL4LGLZkMyiQbihBByKiEF1aNHj+K5557Dfffdh4ceeghbt27F3XffDalUirVr16Kzc2gvL2X4klpKSkrwvpOtW7cOP/7xjyc5fHIyiYjFr6+qRLpegZI0LRgGwWVQIJDle3lN4CzmuWWpw+47UbLm1AX8AcDj8+Nfezvw4hdHg6ULC1M0YBgMKziRl6iCRi7G+oPdIf88qVo5fnJhKSpzDEg8of3dyVWoxrJ2QW7wZ/T4/FhVnoYlhUkoz9SHPBZCCBlPSEHV7/ejuroajz/+OACgoqIC+/btw/PPP4+1a9dOagAPPvgg7rvvvuDXVqsVWVl0AD8cx7J42VEaXbMMgj1fxwqoE9E74MKlz28a0cLu0upMbPrmeCJUhl6BN289Db/46HDwNqNKitkZunFrEiulIvz+umpoZBIoJlk448SfUSJicfdSSpgjhEROSOtfaWlpKCkpGXZbcXExmpubAQCpqYGOHV1dXcMe09XVFbzvZDKZDFqtdtg/EjkMw/Cy7LnhUPeIgCpmGVxUkRFMBAKA762YBaVUjL/vaseCmQn404212PLQUrx6Qy2qc47v46qkIszJ0mNNVSauW5ALMcvg/66sQIvJjtN/8Slue21H2GMmhJBIC2mmunDhQhw+fHjYbXV1dcjJCSR85OXlITU1FZ988gnmzp0LIDDz3Lx5M2677TZ+RkxiQuMJAVUiYuDxcTizKBk2pxc7h5qR5yYocX55OvrtHvz+umosyk8cNnP85WVz0dA3iIJkNdJ08mH3XbcgF7mJKjz4t73QyMXB4zGEEBLLQgqq9957LxYsWIDHH38cl112GbZs2YIXXngBL7zwAoDALOiee+7BY489hoKCAuTl5eGRRx5Beno6LrrookiMnwikpd+BMwuTIJeI8MQl5ah5bD1uXzITL3x+vDPPA+cUQyxikaSRIUmTNOI1shOUyE4YvVLTsbOsP72wFN9bPgsJ6pFnbgkhJNaEFFRramrw7rvv4sEHH8RPfvIT5OXl4ZlnnsHVV18dfMz999+PwcFB3HLLLTCbzVi0aBE++ugjyOXjJ76Q+JGuk+O7l86BRMTA6fHj4fOKIROL8Pa2QNbvVfOysXJ2+A28xSKWAiohJG4wHMdxQg/iRFarFTqdDhaLhfZXY5jL64NMLMLuFjN6bC6YHR48/XEd2i0O3LQoD99dXkh9SQkhcSmcOERdasikyMSBgPnB3o5g4/KZSSq88+0FqDohAYkQQqYTCqokLGm6wLJ+boISH9y9mGanhJBpjYLqFMdxHHoH3EjS8Lcv6fb68eqmRrzw+VF02wLVsFbMTqWASgiZ9iioTlE2pwd/+roJb21tQVWOEU9dNifs1+Q4Dp8e7sZj/zyIoyedUY2tnXlCCBEGBdUp6u1trXjh86P48QWluGBOetivd6TLhsc+OIiNY1RB2tpoAsdxYVVpIoSQeEfZv1OUx+eHz8+FvST70b4OrPvwEJrGaSzOMMBPL5xNnV8IIXGPsn/JCBIRi3C3OJ0eHx5+bz96B1zDbmcZoCBZg9IMLcoydJidoUNJmhaqEFrFEULIVETvgmRMr25qhNXpwdKiZNy1tABauRh72yyYmaTG7Ayd0MMjhJCYQ0GVjIrjOMzLS8Du/1kOhfT4lHdGkvoUzyKEkOmNgioZFcMwmJOlF3oYhBASV8LvAUYIIYQQABRUCSGEEN5QUCWEEEJ4QkGVEEII4QkFVUIIIYQnFFQJIYQQnlBQJYQQQnhCQZUQQgjhCQVVQgghhCcUVAkhhBCeUFAlhBBCeEJBlRBCCOEJBVVCCCGEJxRUCSGEEJ5QUCWEEEJ4QkGVEEII4QkFVUIIIYQnFFQJIYQQnlBQJYQQQnhCQZUQQgjhCQVVQgghhCcUVAkhhBCeUFAlhBBCeEJBlRBCCOEJBVVCCCGEJxRUCSGEEJ5QUCWEEEJ4QkGVEEII4QkFVUIIIYQnFFQJIYQQnlBQJYQQQnhCQZUQQgjhCQVVQgghhCcUVAkhhBCeUFAlhBBCeEJBlRBCCOEJBVVCCCGEJxRUCSGEEJ5QUCWEEEJ4IhZ6ACfjOA4AYLVaBR4JIYSQ6ehY/DkWj0IRc0HVZrMBALKysgQeCSGEkOnMZrNBp9OF9ByGm0wojiC/34/29nZoNBowDCP0cARltVqRlZWFlpYWaLVaoYcTE+iajI6uy0h0TUaiazK6k68Lx3Gw2WxIT08Hy4a2SxpzM1WWZZGZmSn0MGKKVqulP4CT0DUZHV2XkeiajETXZHQnXpdQZ6jHUKISIYQQwhMKqoQQQghPKKjGMJlMhkcffRQymUzoocQMuiajo+syEl2TkeiajI7P6xJziUqEEEJIvKKZKiGEEMITCqqEEEIITyioEkIIITyhoEoIIYTwhIIqIYQQwhMKqgJbt24dampqoNFokJycjIsuugiHDx8O3m8ymXDXXXehsLAQCoUC2dnZuPvuu2GxWAQcdeSNd11OxHEczjnnHDAMg/feey+6A42iiV6TTZs24ayzzoJKpYJWq8Xpp58Oh8MhwIgjbyLXpLOzE9dccw1SU1OhUqlQWVmJv/71rwKNODqee+45lJeXBysEzZ8/Hx9++GHwfqfTiTvuuAMJCQlQq9W45JJL0NXVJeCII+9U14TP91kKqgLbuHEj7rjjDnz99df4+OOP4fF4sHz5cgwODgIA2tvb0d7ejieffBL79u3DK6+8go8++gg33nijwCOPrPGuy4meeeaZaVEneiLXZNOmTVi5ciWWL1+OLVu2YOvWrbjzzjtDrl8aLyZyTa699locPnwY77//Pvbu3YvVq1fjsssuw86dOwUceWRlZmbiiSeewPbt27Ft2zacddZZuPDCC7F//34AwL333ot//OMfePvtt7Fx40a0t7dj9erVAo86sk51TXh9n+VITOnu7uYAcBs3bhzzMW+99RYnlUo5j8cTxZEJa6zrsnPnTi4jI4Pr6OjgAHDvvvuuMAMUwGjXZN68edzDDz8s4KiENdo1UalU3KuvvjrscUajkXvxxRejPTxBGQwG7qWXXuLMZjMnkUi4t99+O3jfwYMHOQDcpk2bBBxh9B27JqOZ7Pvs1Pz4GseOLTcYjcZTPkar1UIsjrl+CBEz2nWx2+246qqr8Jvf/AapqalCDU0wJ1+T7u5ubN68GcnJyViwYAFSUlJwxhln4L///a+Qw4yq0X5PFixYgDfffBMmkwl+vx9vvPEGnE4nlixZItAoo8vn8+GNN97A4OAg5s+fj+3bt8Pj8WDZsmXBxxQVFSE7OxubNm0ScKTRc/I1Gc2k32f5iPaEHz6fj1u1ahW3cOHCMR/T09PDZWdncw899FAURyassa7LLbfcwt14443BrzGNZqqjXZNNmzZxADij0cj94Q9/4Hbs2MHdc889nFQq5erq6gQcbXSM9XvS39/PLV++nAPAicViTqvVcv/+978FGmX07Nmzh1OpVJxIJOJ0Oh33wQcfcBzHca+99honlUpHPL6mpoa7//77oz3MqBrrmpwsnPfZ6TPViQN33HEH9u3bN+bMwmq1YtWqVSgpKcGPfvSj6A5OQKNdl/fffx8bNmyY0vtipzLaNfH7/QCAW2+9Fddffz0AoKKiAp988gn+8Ic/YN26dYKMNVrG+vt55JFHYDabsX79eiQmJuK9997DZZddhi+++AJlZWUCjTbyCgsLsWvXLlgsFrzzzjtYu3YtNm7cKPSwBDXWNSkpKQk+Juz32XAjP+HHHXfcwWVmZnJHjx4d9X6r1crNnz+fW7p0KedwOKI8OuGMdV2+853vcAzDcCKRKPgPAMeyLHfGGWcIM9goGeuaHD16lAPA/elPfxp2+2WXXcZdddVV0Rxi1I11Terr6zkA3L59+4bdvnTpUu7WW2+N5hAFt3TpUu6WW27hPvnkEw4A19/fP+z+7Oxs7pe//KUwgxPIsWtyDB/vs7SnKjCO43DnnXfi3XffxYYNG5CXlzfiMVarFcuXL4dUKsX7778PuVwuwEija7zr8sADD2DPnj3YtWtX8B8APP3003j55ZcFGHHkjXdNcnNzkZ6ePuJISV1dHXJycqI51KgZ75rY7XYAGJH9LBKJgjP76cLv98PlcqGqqgoSiQSffPJJ8L7Dhw+jubl5zP3FqerYNQF4fJ/lI9qTybvttts4nU7HffbZZ1xHR0fwn91u5ziO4ywWCzdv3jyurKyMq6+vH/YYr9cr8OgjZ7zrMhpM8T3ViVyTp59+mtNqtdzbb7/NHTlyhHv44Yc5uVzO1dfXCzjyyBnvmrjdbi4/P59bvHgxt3nzZq6+vp578sknOYZhxtxPmwoeeOABbuPGjVxDQwO3Z88e7oEHHuAYhuH+85//cBzHcd/+9re57OxsbsOGDdy2bdu4+fPnc/Pnzxd41JF1qmvC5/ssBVWBARj138svv8xxHMd9+umnYz6moaFB0LFH0njXZaznTOWgOtFrsm7dOi4zM5NTKpXc/PnzuS+++EKYAUfBRK5JXV0dt3r1ai45OZlTKpVceXn5iCM2U80NN9zA5eTkcFKplEtKSuKWLl0aDKgcx3EOh4O7/fbbOYPBwCmVSu7iiy/mOjo6BBxx5J3qmvD5Pkv9VAkhhBCe0J4qIYQQwhMKqoQQQghPKKgSQgghPKGgSgghhPCEgiohhBDCEwqqhBBCCE8oqBJCCCE8oaBKCCGE8ISCKiGEEMITCqqEEEIITyioEkIIITz5f5jv2OpmxcxdAAAAAElFTkSuQmCC", "text/plain": [ - "<Figure size 864x864 with 1 Axes>" + "<Figure size 1200x1200 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1159,7 +1167,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 51, "metadata": {}, "outputs": [ { @@ -1168,20 +1176,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 17, + "execution_count": 51, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "<Figure size 432x288 with 1 Axes>" + "<Figure size 640x480 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1192,7 +1198,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 52, "metadata": {}, "outputs": [ { @@ -1201,20 +1207,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 18, + "execution_count": 52, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "<Figure size 432x288 with 1 Axes>" + "<Figure size 640x480 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1236,7 +1240,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 53, "metadata": {}, "outputs": [ { @@ -1245,20 +1249,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 19, + "execution_count": 53, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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w/avv/4a2dnZob4MERERDSJB9aCsWrUK8+fPR1ZWFmw2GzZu3Ihdu3Zhx44dkEgk+M1vfoOHH34YY8aMwdixY7FhwwYcP34cW7Zs6av6iYiIKAoFFVAaGhqwePFi1NbWwmAwoKioCDt27MDs2bMBAPfddx8cDgfuv/9+mM1mjBkzBjt37sTQoUP7pHgiIiKKTiHPgxJunAeFiIgo8ohmHhQiIiKivsKAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiE1RAWb9+PYqKiqDX66HX61FcXIzt27dftp8gCJg/fz4kEgnefPPNcNVKREREg0RQASUzMxNr165FaWkpDhw4gJkzZ2LhwoU4evRoh/3+/Oc/QyKRhLVQIiIiGjzkwex83XXXdXj82GOPYf369di7dy9GjhwJACgrK8Of/vQnHDhwAGlpaeGrlIiIiAaNoALKpbxeLzZv3gy73Y7i4mIAQGtrK2655RY8++yzSE1NDagdp9MJp9Ppf2y1WntbEhEREUWJoAfJlpeXQ6vVQqVSYenSpdi6dSsKCwsBAPfffz+mTZuGhQsXBtzemjVrYDAY/D8mkynYkoiIiCjKBN2Dkp+fj7KyMlgsFmzZsgV33HEHdu/ejVOnTuHjjz/GoUOHgmpv1apVWLFihf+x1WplSCEiIhrkJIIgCKE0MGvWLAwdOhQxMTH47//+b0il33XKeL1eSKVSXHnlldi1a1dA7VmtVhgMBlgsFuj1+lBKIyIion4S7u/vXo9Bucjn88HpdOKRRx7Bz3/+8w7bRo8ejXXr1l02uJaIiIioO0EFlFWrVmH+/PnIysqCzWbDxo0bsWvXLuzYsQOpqamdDozNyspCbm5u2AomIiKi6BdUQGloaMDixYtRW1sLg8GAoqIi7NixA7Nnz+6r+oiIiGgQCiqgvPzyy0E1HuLwFiIiIhqkuBYPERERiQ4DChEREYkOAwoRERGJDgMKERERiQ4DChEREYkOAwoRERGJDgMKERERiQ4DChEREYkOAwoRERGJDgMKERERiQ4DChEREYkOAwoRERGJDgMKERERiQ4DChFRF/7rgxN453DNQJdBNCgxoBARdeKb8y1odXlRkKof6FKIBiX5QBdARCRGQ5O0+P0PCwe6DKJBiz0oREREJDoMKERERCQ6DChEFLU8Xh/+UVIJr08Y6FKIKEgcg0JEUevx947jlc8r8P6ROtx11VC0OD3YfKAKCVoVHpxfAEOMYqBLJKIuMKAQUdSyOdwAgE9OnMcnJ8532Pavk+fxhx8WYkSaHglaJWKV/N8hkZjwEg8RRa3f/7AQk3LiO912rqkNd/2tFP9vzxm0ODz9XBkR9YQBhYiiliFGgf+9cyr+76LRyE/RXbZ94dh0/G5BIZL16gGojoi6wz5NIopqcpkUN0/Kwk0TTdjzzQV8cKweTa0uGDVK3H3V0IEuj4i6wIBCRIOCRCLBtLxETMtLHOhSiCgAvMRDRPQtn0/A56caB7oMIgIDChGRn1Qq4a3HRCLBgEJEdIlRGYaBLoGIwIBCREREIsSAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiE1RAWb9+PYqKiqDX66HX61FcXIzt27cDAMxmM5YvX478/HzExMQgKysL9957LywWS58UTkRERNErqKnuMzMzsXbtWgwbNgyCIGDDhg1YuHAhDh06BEEQUFNTg6eeegqFhYU4e/Ysli5dipqaGmzZsqWv6iciIqIoJBEEQQilAaPRiCeffBJLliy5bNvmzZtx2223wW63Qy4PLAtZrVYYDAZYLBbo9fpQSiMiIqJ+Eu7v714vFuj1erF582bY7XYUFxd3us/FIrsLJ06nE06n0//YarX2tiQiIiKKEkEPki0vL4dWq4VKpcLSpUuxdetWFBYWXrZfY2MjVq9ejbvuuqvb9tasWQODweD/MZlMwZZEREREUSboSzwulwuVlZWwWCzYsmULXnrpJezevbtDSLFarZg9ezaMRiO2bdsGhaLrxbc660ExmUy8xENERBRBwn2JJ+QxKLNmzcLQoUPxwgsvAABsNhvmzp2L2NhYvPPOO1Cr1UG1xzEoREREkSfc398hz4Pi8/n8PSBWqxVz5syBUqnEtm3bgg4nRERERECQg2RXrVqF+fPnIysrCzabDRs3bsSuXbuwY8cOfzhpbW3Fa6+9BqvV6h/wmpSUBJlM1idvgIiIiKJPUAGloaEBixcvRm1tLQwGA4qKirBjxw7Mnj0bu3btwr59+wAAeXl5HY6rqKhATk5O2IomIiKi6BbyGJRw4xgUIiKiyCO6MShERERE4caAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiw4BCREREosOAQkRERKLDgEJERESiE1RAWb9+PYqKiqDX66HX61FcXIzt27f7tzscDixbtgwJCQnQarVYtGgR6uvrw140ERERRbegAkpmZibWrl2L0tJSHDhwADNnzsTChQtx9OhRAMD999+Pt99+G5s3b8bu3btRU1ODH/3oR31SOBHRQBMEAQ1Wx0CXQRSVJIIgCKE0YDQa8eSTT+LGG29EUlISNm7ciBtvvBEAcPz4cYwYMQJ79uzB1KlTA2rParXCYDDAYrFAr9eHUhoRERH1k3B/f/d6DIrX68WmTZtgt9tRXFyM0tJSuN1uzJo1y79PQUEBsrKysGfPni7bcTqdsFqtHX6IiMTM5wvp7zoiCkDQAaW8vBxarRYqlQpLly7F1q1bUVhYiLq6OiiVSsTFxXXYPyUlBXV1dV22t2bNGhgMBv+PyWQK+k0QEfUnqVQy0CUQRb2gA0p+fj7Kysqwb98+3HPPPbjjjjtw7NixXhewatUqWCwW/09VVVWv2yIiIqLoIA/2AKVSiby8PADAhAkTUFJSgqeffho333wzXC4XmpubO/Si1NfXIzU1tcv2VCoVVCpV8JUTERFR1Ap5HhSfzwen04kJEyZAoVDgo48+8m87ceIEKisrUVxcHOrLEBER0SASVA/KqlWrMH/+fGRlZcFms2Hjxo3YtWsXduzYAYPBgCVLlmDFihUwGo3Q6/VYvnw5iouLA76Dh4iIiAgIMqA0NDRg8eLF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", "text/plain": [ - "<Figure size 432x288 with 1 Axes>" + "<Figure size 640x480 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1269,7 +1271,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 54, "metadata": {}, "outputs": [ { @@ -1278,20 +1280,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 20, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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Uumo/X0RilDv36xZs6BSqVBdXY3zzjsPAODz+VBbWyvK74uzPmyGqqGhARdddBEKCwvxhz/8Aa2trb2vnfxX57e//W088MADuOmmm3DXXXdhz549ePjhh/HHP/4xUWUnlbq6OnR0dKCurg6BQAA7d+4EAJSUlECn02HRokX4+c9/jpUrV+InP/kJgsEg1qxZA7lcjosvvjixxSeB4e7f+PHjsXz5ctx222144oknYDAYsGrVKkyYMIH3D8PfvzMDZVtbGwBg4sSJw67LeTYY7v7t2bMHCxYswJIlS3DnnXf2jjOUyWQxDbQj1XD3b/HixZg0aRKuv/56/P73v0dzczPuvfderFy5EiqVKrHFJ6Hy8nKYzWbccMMN+OUvfwmNRoMnn3wSNTU1WLZsWaLLS3oGgwG33HIL7rvvPuTn56OwsBBr164FAFxzzTWxv2Bc5ryPAs8884wAYMCv0+3atUs477zzBJVKJeTm5gpr1qxJUMXJ54Ybbhjw/n388ce957z33nvCueeeKxiNRsFsNgsLFiwQNm/enLiik0go989mswnf+973BJPJJFgsFuHKK6/ss5TU2SyU+3e6jz/+mEsfnWa4+3ffffcN+HphYWFC604Wofz9q62tFZYuXSpoNBohLS1N+OlPfyr4fL7EFZ3kKioqhMWLFwsWi0XQ6/XCvHnzhLfffjvRZY0YXq9X+OlPfypkZGQIer1eWLhwobBnzx5RriURhBMDk4iIiIiIYuysn41OREREROJh2CQiIiIi0TBsEhEREZFoGDaJiIiISDQMm0REREQkGoZNIiIiIhINwyYRERERiYZhk4iIiIhEw7BJRERERKJh2CQiIiIi0TBsEhEREZFo/j/Leu2X4KxGVQAAAABJRU5ErkJggg==", "text/plain": [ - "<Figure size 576x576 with 1 Axes>" + "<Figure size 800x800 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1311,7 +1311,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 55, "metadata": {}, "outputs": [ { @@ -1320,20 +1320,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 21, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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69L4tYyJ0oEjUSIiIokYRImIiCRiECUiIpKIQZSIiEgiBlEiIiKJGESJiIgkYhAlIiKSiEGUiIhIIgZRIiIiiRhEiYiIJGIQJSIikohBlIiISCIGUSIiIokYRImIiCRiECUiIpKIQZSIiEgiBlEiIiKJGESJiIgkYhAlIiKSiEGUiIhIIgZRIiIiiZIKoo899hiqq6thMplgMplQW1uLV199ddh1oihi/fr1EAQBL730Urr6SkRENKUkFUQLCwvx4IMPoq6uDrt378Yll1yCq6++GgcPHhxy3SOPPAJBENLaUSIioqlGkczFV1111ZDvH3jgATz22GN4//33sXDhQgDAvn378MMf/hC7d+9GXl5e+npKREQ0xSQVRM8WDofxwgsvwO12o7a2FgDg8Xjwuc99Do8++ihyc3MTasfv98Pv98e+dzqdUrtEREQ0oZLeWFRfXw+DwQC1Wo3bbrsNW7duRVVVFQDgnnvuwZo1a3D11Vcn3N6WLVtgNptjX0VFRcl2iYiIaFIkPRKtqKjAvn374HA48OKLL2LDhg146623cOLECfz973/H3r17k2pv8+bN2LRpU+x7p9PJQEpERNOCIIqimEoDa9euxdy5c6HVavGTn/wEMtmHg9twOAyZTIYLLrgA27ZtS6g9p9MJs9kMh8MBk8mUSteIiIiSlkwckrwmOigSicDv9+P+++/Hv/3bvw352eLFi/Hwww8P25BEREQ0EyQVRDdv3oz169ejuLgYLpcLzzzzDLZt24bXXnsNubm5cTcTFRcXo6ysLG0dJiIimiqSCqJdXV246aab0N7eDrPZjOrqarz22mu47LLLxqt/REREU1ZSQfTJJ59MqvEUl1uJiIimNObOJSIikohBlIiISCIGUSIiIokYRImIiCRiECUiIpKIQZSIiEgiBlEiIiKJGESJiIgkYhAlIiKSiEGUiIhIIgZRIiIiiRhEiYiIJGIQJSIikohBlIiISCIGUSIiIokYRImIiCRiECUiIpKIQZSIiEgiBlEiIiKJGESJiIgkYhAlIiKSiEGUiIhIIgZRIiIiiRhEiYiIJGIQJSIikohBlIiISCIGUSIiIokYRImIiCRiECUiIpKIQZSIiEgiBlEiIiKJkgqijz32GKqrq2EymWAymVBbW4tXX30VANDX14c777wTFRUV0Gq1KC4uxl133QWHwzEuHSciIppsimQuLiwsxIMPPoh58+ZBFEU8/fTTuPrqq7F3716Iooi2tjb84Ac/QFVVFRobG3Hbbbehra0NL7744nj1n4iIaNIIoiiKqTRgs9nw0EMP4dZbbx32sxdeeAGf//zn4Xa7oVAkFq+dTifMZjMcDgdMJlMqXSMiIkpaMnEoqZHo2cLhMF544QW43W7U1tbGvWawA6MFUL/fD7/fH/ve6XRK7RIREdGESnpjUX19PQwGA9RqNW677TZs3boVVVVVw67r6enBd77zHXzhC18Ytb0tW7bAbDbHvoqKipLtEhER0aRIejo3EAigqakJDocDL774In75y1/irbfeGhJInU4nLrvsMthsNrz88stQKpUjthdvJFpUVMTpXCIimhTJTOemvCa6du1azJ07F0888QQAwOVyYd26ddDpdPjzn/8MjUaTVHtcEyUiosmUTBxK+ZxoJBKJjSSdTicuv/xyqFQqvPzyy0kHUCIioukkqY1Fmzdvxvr161FcXAyXy4VnnnkG27Ztw2uvvRYLoB6PB7/73e/gdDpjm4SysrIgl8vH5QUQERFNlqSCaFdXF2666Sa0t7fDbDajuroar732Gi677DJs27YNO3bsAACUl5cPed7p06dRWlqatk4TERFNBSmviaYb10SJiGgyTeiaKBER0WzFIEpERCQRgygREZFEDKJEREQSMYgSERFJxCBKREQkEYMoERGRRAyiREREEjGIEhERScQgSkREJBGDKBERkUQMokRERBIxiBIREUnEIEpERCQRgygREZFEDKJEREQSMYgSERFJxCBKREQkEYMoERGRRAyiREREEjGIEhERScQgSkREJBGDKBERkUQMokRERBIxiBIREUnEIEpERCQRgygREZFEDKJEREQSMYgSERFJxCBKREQkUVJB9LHHHkN1dTVMJhNMJhNqa2vx6quvxn7u8/mwceNGZGRkwGAw4Nprr0VnZ2faO01ERDQVJBVECwsL8eCDD6Kurg67d+/GJZdcgquvvhoHDx4EANxzzz3405/+hBdeeAFvvfUW2tra8KlPfWpcOk5ERDTZBFEUxVQasNlseOihh/DpT38aWVlZeOaZZ/DpT38aAHDkyBEsWLAA27dvx3nnnZdQe06nE2azGQ6HAyaTKZWuERERJS2ZOCR5TTQcDuPZZ5+F2+1GbW0t6urqEAwGsXbt2tg1lZWV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xn42W6XyHq9evRqhUAgNDQ2oqKgYh97NHJmZmZDL5bHfuUGdnZ2z+vcvXSwWC+bPn48TJ05IboNBdArIyspCVlbWuLW/b98+WK3WWRFAgfS+n7W1tXjggQfQ1dUV2wn5+uuvw2QyoaqqKi33mI5SeY/37dsHmUzGnaUJUKlUWLFiBd58801cc801AIBIJII333wTd9xxx+R2bgYYGBjAyZMnceONN0pug0F0mmlqakJfXx+ampoQDoexb98+AEB5eTkMBgP+9Kc/obOzE+eddx40Gg1ef/11fO9738O99947uR2fosZ6Py+//HJUVVXhxhtvxPe//310dHTgG9/4BjZu3DhrPpSkYvv27dixYwc++tGPwmg0Yvv27bjnnnvw+c9/HlardbK7Ny1s2rQJGzZswMqVK1FTU4NHHnkEbrcbt9xyy2R3bdq59957cdVVV6GkpARtbW341re+Bblcjs9+9rPSG03rXl8adxs2bBABDPv6xz/+IYqiKL766qvi0qVLRYPBIOr1enHJkiXi448/LobD4cnt+BQ11vspiqLY0NAgrl+/XtRqtWJmZqb45S9/WQwGg5PX6Wmkrq5OXL16tWg2m0WNRiMuWLBA/N73vif6fL7J7tq08tOf/lQsLi4WVSqVWFNTI77//vuT3aVp6frrrxfz8vJElUolFhQUiNdff7144sSJlNpkKTQiIiKJuDuXiIhIIgZRIiIiiRhEiYiIJGIQJSIikohBlIiISCIGUSIiIokYRImIiCRiECUiIpKIQZSIiEgiBlEiIiKJGESJiIgkYhAlIiKS6P8DsWpGF3/Z9tIAAAAASUVORK5CYII=", "text/plain": [ - "<Figure size 432x288 with 1 Axes>" + "<Figure size 640x480 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1344,7 +1342,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 56, "metadata": {}, "outputs": [ { @@ -1353,20 +1351,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 22, + "execution_count": 56, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "<Figure size 576x576 with 1 Axes>" + "<Figure size 800x800 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1385,7 +1381,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 57, "metadata": {}, "outputs": [ { @@ -1394,20 +1390,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 23, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "<Figure size 432x288 with 1 Axes>" + "<Figure size 640x480 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1425,14 +1419,14 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 58, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/var/folders/yk/yj8t31wd1sd_9w0f9cfg5jv80000gn/T/ipykernel_82121/127064943.py:6: ShapelyDeprecationWarning: Iteration over multi-part geometries is deprecated and will be removed in Shapely 2.0. Use the `geoms` property to access the constituent parts of a multi-part geometry.\n", + "C:\\Users\\bryan\\AppData\\Local\\Temp\\ipykernel_31064\\127064943.py:6: ShapelyDeprecationWarning: Iteration over multi-part geometries is deprecated and will be removed in Shapely 2.0. Use the `geoms` property to access the constituent parts of a multi-part geometry.\n", " for item in splitted_geom:\n" ] }, @@ -1442,20 +1436,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 24, + "execution_count": 58, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAABj0AAAMyCAYAAAA2aQPiAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzddXhk5fUH8O+4zySZuMsmm9WsuwKLu7v9sBZaKC0tFCm0SCkUt0JxpzgLLLDCuls2nmzcfTTj9/dHlkDYZGMzmcj38zw82czc+94z7CaT3POec0SCIAggIiIiIiIiIiIiIiIa5cTBDoCIiIiIiIiIiIiIiMgfmPQgIiIiIiIiIiIiIqIxgUkPIiIiIiIiIiIiIiIaE5j0ICIiIiIiIiIiIiKiMYFJDyIiIiIiIiIiIiIiGhOY9CAiIiIiIiIiIiIiojGBSQ8iIiIiIiIiIiIiIhoTmPQgIiIiIiIiIiIiIqIxQRrsAH7N5/OhtrYWOp0OIpEo2OEQEREREREREREREVEQCYIAi8WC2NhYiMXHruUYcUmP2tpaJCQkBDsMIiIiIiIiIiIiIiIaQaqqqhAfH3/MY0Zc0kOn0wHoDF6v1wc5GiIiIiIiIiIiIiIiCiaz2YyEhISu/MGxjLikx08trfR6PZMeREREREREREREREQEAP0aicFB5kRERERERERERERENCYw6UFERERERERERERERGMCkx5ERERERERERERERDQmMOlBRERERERERERERERjApMeREREREREREREREQ0JjDpQUREREREREREREREYwKTHkRERERERERERERENCYw6UFERERERERERERERGMCkx5ERERERERERERERDQmMOlBRERERERERERERERjApMeREREREREREREREQ0JjDpQUREREREREREREREYwKTHkRERERERERERERENCYw6UFERERERERERERERGMCkx5ERERERERERERERDQmMOlBRERERERERERERERjApMeREREREREREREREQ0JjDpQUREREREREREREREYwKTHkRERERERERERERENCYw6UFERERERERERERERGMCkx5ERERERERERERERDQmMOlBRERERERERERERERjApMeREREREREREREREQ0JjDpQUREREREREREREREYwKTHkRERERERERERERENCYw6UFERERERERERERERGMCkx5ERERERERERERERDQmMOlBRERERERERERERERjApMeREREREREREREREQ0JjDpQUREREREREREREREYwKTHkRERERERERERERENCYw6UFERERERERERERERGOCNNgBEBER9cTl8eHrQ7U4WGWCzemBzeWBzek98ufOj3aXB1anB+FaBV66fDamxhmCHTYREREREREREQURkx5ERDQiPbu+GM+uL+n1eaVMjHCtAnGhaoRr5JgQqR3G6IiIiIiIiIiIaCRi0oOIiEakNrsL586KQ3yoGjEGJcK1Chi1coRrFAjXyaGWD89bmM8n4EB1O/aUt8Lq8MB6pNrE5fVBr5TCoJYjVC1DqFoOw5GPoWoZEsPUEIlEwxIjERERERERERF1YtKDiIhGpAfPnhbsEAAAPkFAtF6JOclhaDQ78O7OSuwsbYXL6zvmea9eNQfHT4oapiiJiIiIiIiIiAhg0oOIiOiYpBIxYkNUiA1RAQBOnhoDj9eHylY7atsdsLs86HB74XB7YXd5IQjA/NQwTInlfBEiIiIiIiIiouHGpAcREQXF4SYrPtpdBalEBJlEjIoWOwrqLWiyOPHQOVNx0pToYIfYK6lEjNQILVIjOEeEiIiIiIiIiGgkYdKDiIiGlc8n4NUtZfjXdwVwe4Uej7nlvX1YkGrE1DgDInUKROqUmByrR0q4ZpijJSIiIiIiIiKi0YRJDyIiGha17R3YVdaK/+2twtaSlmMe6/YK2FzcjM3FzV2PJRvVeOe6+YgPVR85xocOtxd6pSygcRMRERERERER0ejBpAcREQVUWbMNf/zoAPZVtvf7nGSjGreekI5QtRxhGjlC1XLEhajg8vrwwFe52FzcjJJGKwAgI0qLaxen4OJ5iQF6BURERERERERENFow6UFEREPm9Qm485NsFDVY0Gx1ITZEiZRwDULVcry9owJ2l3dA61W3dWB6fAjSfjUzQyES46Qp0YjWK1Hb3oGadgeUMjHqTA64PD7IpWJ/viwiIr/zeH1wenxQyyUQiUTBDoeIiIiIiGjMYdKDiIiGTCIWYVKMHv/bWw0AqGnvwO7yNsgkoqPmduiVUkTqlV2VGj3x+AQ89HU+Xrt6brfHRSIRFqQasSDV6P8XQUQUAPd9kYMvD9bC5elMdnh9nd8Ts+INeOv/5sOgYos+IiIiIiIi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", "text/plain": [ - "<Figure size 1440x1440 with 1 Axes>" + "<Figure size 2000x2000 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1496,7 +1488,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 59, "metadata": {}, "outputs": [ { @@ -1505,20 +1497,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 25, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXsAAAD0CAYAAAB6r4ayAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAZ1ElEQVR4nO3de3Bc5Znn8e/TrbutqyXbsmVbMjZ2zGBuQpg4IRNgAglsTFLZrKlJ1plh15ssk2V2spXhsn/sTE1qyc5UEqaS2R1XIOOtIQsUE8cMEyDmkplAwEbGXHwBW/gu32Td763ufvaPPhCNLduou+WWdH6fKkp93nPU7/P6oJ9evX1Ot7k7IiIyvUVyXYCIiEw8hb2ISAgo7EVEQkBhLyISAgp7EZEQyMt1AaNVV1d7fX19rssQEZlStm/fftrda853zKQK+/r6epqbm3NdhojIlGJmhy50jJZxRERCQGEvIhICCnsRkRBQ2IuIhIDCXkQkBBT2IiIhoLAXEQkBhb2ISAhk5aYqMzsI9AIJIO7ujWZWBTwO1AMHgS+7e2c2+hOZ7F4/2MHTbx/jwOl+Nny1kcK8CGaW67IkxLI5s/+0u1/p7o3B9r3AC+6+FHgh2BYJhZ9uPczG3xyitXOQb/z9dr72k9d570RvrsuSEJvIZZw1wMbg8UbgjgnsS2TSGIzFOd03zDWLKqgsKeDto92c7h3izg2vcsePXqZ3aISjnQO5LlNCJlvvjePAL83Mgb919w3AHHc/Huw/AcwZ6xvNbD2wHmDhwoVZKkdk4nT0xwCoKM4nEkktzfQNx9m0o5Xmgx28+n47DdUlHOkYpHMghuHUV8+gY2CEWKKf//r4mxzrGuJ/fvFyVtaVa3lHLopshf0n3L3VzGYDW8zs3dE73d2DXwRnCX4xbABobGzUB+LKpPfLXSe4f9M7/J+vXMPc8iJqy4vZsvskz7xznJM9Q1SWFFCUF+VU7zCFeREK8qKMJJLkRWBFbSk7W7s50TPMd/5pNwuqSlhQWULCna+sWsScsqJcD0+mqayEvbu3Bl9PmdkmoAk4aWa17n7czGqBU9noSyTX/t21C3j45QM8+My77D/dD0BRXoRlc0t5vy21XVtewCeWzMKA4YRjwPK5ZWw7mLpGoaIkn/b+GNsOdrJqcRVvH+3mH986xg2X1lBWnM+yOaWsWjyLmtLCHI1SppuMw97MZgARd+8NHn8G+HPgKWAd8GDwdXOmfYlcDO7OztYe3m7tIpl0fv7mMeZVFPPtW5ax/3Q/iWSSeRXFHOkY4PrFVRzrHuJUzzAH2wf45JJZ9McSDMScoZEEs2bm8+uWdgCuWVjBktkzKMyL0N4X+/AFs2NdQ5QW5jG7tIhX32+nvX+YBVUzuK6hKnf/CDLtZGNmPwfYFKw75gE/dfdnzex14Akzuws4BHw5C32JTLj+4TiPNx9m845j9A7HqZpRwK5jqZn37NJCSgqidA+OsLy2lONdQwyPJFg2t5SCaIR4Et443EV+1PjEkmrcIWJwbX0VsXiSllOpmf81iyrYcbiL1Utm0TMYp6C0kMGROBUl+QzE4nz7lmXM1pKOZFHGYe/u+4ErxmhvB27K9PlFLraZRfl88eo6tu7voNYgkXA6+mPMqyhiTlkRO4IwH44lOdg+QFNDFdsOdABw/eIqmuqrKMgzXmk5jZNa4jnWNcjRrkGaGqrIMyMSMfIixist7dywtJqheIKkp/oC4+OXzMrpv4FMP5Pqk6pEJourF1ay5U8+hbuz53gPz+48we7jPbT3DbN8bil7T/YSjRoVJfmc7h3m45fMIpZIEosn2X28l8oZ+Vw2r5zC/AjuMDiSwMzYcbiTeeVFHOoY5Iq6csqL83m55TTVMwtZXDOD8uJ8KmcU6AodyTqFvch5mBlLZpfynz41g3jCefjl/fzklYNEDLoHR+geGKEgGiFq0By8+Lp6ySxi8ST50Qi/eb+dsuI8EgmnP5agvqoECy7XfOtoNzcsraapvorXD3aQdOex9dezZPbMXA5ZpimFvcgFFORFKMhLvZz6havm80pLOz1DI7R29NNYX8nrBzupLClg6eyZzJpZwLYDHYwknMvnlwFQUVxAeXE+J3oGqS4tZPvhTlbUljEUT/B+Wx/RSITFNTP56X9cpatvZMLojdBExqGhZib337acipJ8CgvycU/dGlKUH2HfqT5aTvVx+bwyLp9fRnF+lNWXzOJwxwDvtHbT2RcjnnTcoaWtj+qZhZQV5dM7NMJ/v+1jbD3QnuPRyXRmH/zPOhk0NjZ6c3NzrssQuaDD7f089Pxe3m7toaw4n5KCCMMjTkGesXV/B7PLimjtGmT2zAJmlxVRXBBNXXWTZ1SWFBBLJHltfwcRg9WXVHOkc4D2/hi/+C+fZEFVSa6HJ1OMmW0f9b5kY9Iyjkga6ipLiEZTs/nrGqr49b525pUXUVtRzEjSKS/OZ2FVCYV5EX61tw2A4oIoJflR8qIR9p/q44ZLq4nFkwzEEswuK6KmtJCheCLHI5PpSss4ImmIRIyIwe0ra4klkiyunkEskWT7oU5WL5nF7uM9vLq/naF4gmvrK/nkkllcPq+cFbWl5EWMpoYqTnYP8dr+DgZHEhzrHOT1g538/auHcj00maY0sxdJ06v7O+gaGAGc5XPLONCeumFq97EemuorKcqP8i/7TlNXWUzVjALaeofoG4qzdE4p753so2dohCvqytl5rIfrF8/i2oZK7rn50twOSqYtzexF0rSgsoT+4Tjdg3GSSefy+eU0NVRRW17ItoOdDI0kWFlXTmffMN2DIxzvHmbFvHLeONzF3LJCugZG6B2Ks7CyhL0ne9l1rIeDwS8MkWxT2IukoWsgxsstp8mLGNfVV9IzFOed1m6S7hTn53FdQxUF0SitnYP0jySpKS1k2ZxSDFg5v5zSwtQxdZXFqRuz+oZJOjy38wSvvt/OQCye6yHKNKOwF0nD1uDtEYbiSY51D2E4BVHD3MEgP2q8/H7q7RIWzSrBHcqK8kg67DzWzVAiydBIgvb+GCe6B7lk9kxmlxby8Mv7eeSVAxTmRXM7QJl2tGYvMk4d/TGe23mCa+srGUk4I4kElSUFnOgdpmcowaneIZLuXL+4isGRJD2DMbYf6mROWSHrb1hMU0Mlv9rbRklBHjsPdjCzKI/jPcMMxhI8tPYqbls5L9dDlGlIYS8yThXF+dz4sdn84Pl97G/ro66yiIOnB6ivnsHxriEWzZpB79AIJ3qGOXC6n/yo8T/+zQruvG7hhzP2/3bLcgBeff80L77bBuZ84co6VswrG7PP7sERyovzL9oYZfpR2IuMUyRi3L5yHrevnMe7J3poOdnHr/edprw4n6bFVbyw5yS/aTnNouoZVM3Ip613mI9fUj3m0sz1l1Rz/SXV5+wrmXRe29/OP+9t477PfWwihyXTnMJeJAPL55axfG4Zt1/x26WXmz82h56hETa/eYzugRhzgjto07H5rVb+6rm9tPUOc+9nl+vdMCVtCnuRCVBWlM9XVy3K+HnmV5TQMzTC7y6ryUJVEma6GkdkErt8fjmLZpXQ1FClWb1kRDN7kUmsuCDKpv+8mkRy8rxhoUxNWZvZm1nUzHaY2dPBdoOZbTWzFjN73MwKstWXSJjkRyMU5eu6e8lMNpdx7gH2jNr+LvB9d18CdAJ3ZbEvEREZh6yEvZnVAbcBPw62DbgReDI4ZCNwRzb6EhGR8cvWzP4HwLeBZLA9C+hy9w/e4OMoMH+sbzSz9WbWbGbNbW1tWSpHRERGyzjszex24JS7b0/n+919g7s3untjTY0uLxMRmQjZuBpnNfB5M/scUASUAQ8BFWaWF8zu64DWLPQlIiJpyHhm7+73uXudu9cDa4EX3f33gZeALwWHrQM2Z9qXiIikZyJvqvpT4E/MrIXUGv7DE9iXiIicR1ZvqnL3XwG/Ch7vB5qy+fwiIpIevV2CiEgIKOxFREJAYS8iEgIKexGREFDYi4iEgMJeRCQEFPYiIiGgsBcRCQGFvYhICCjsRURCQGEvIhICCnsRkRBQ2IuIhIDCXkQkBBT2IiIhoLAXEQkBhb2ISAhkHPZmVmRm28zsLTPbZWZ/FrQ3mNlWM2sxs8fNrCDzckVEJB3ZmNkPAze6+xXAlcCtZrYK+C7wfXdfAnQCd2WhLxERSUPGYe8pfcFmfvCfAzcCTwbtG4E7Mu1LRETSk5U1ezOLmtmbwClgC/A+0OXu8eCQo8D8bPQlIiLjl5Wwd/eEu18J1AFNwPKP+r1mtt7Mms2sua2tLRvliIjIGbJ6NY67dwEvAdcDFWaWF+yqA1rP8T0b3L3R3RtramqyWY6IiASycTVOjZlVBI+Lgd8D9pAK/S8Fh60DNmfal4iIpCfvwodcUC2w0cyipH55POHuT5vZbuAxM/sLYAfwcBb6EhGRNGQc9u7+NnDVGO37Sa3fi4hIjukOWhGREFDYi4iEgMJeRCQEFPYiIiGgsBcRCQGFvYhICCjsRURCQGEvIhICCnsRkRBQ2IuIhIDCXkQkBBT2IiIhoLAXEQkBhb2ISAgo7EVEQkBhLyISAgp7EZEQUNiLiIRANj5wfIGZvWRmu81sl5ndE7RXmdkWM9sXfK3MvFwREUlHNmb2ceBb7r4CWAXcbWYrgHuBF9x9KfBCsC0iIjmQcdi7+3F3fyN43AvsAeYDa4CNwWEbgTsy7UtERNKT1TV7M6sHrgK2AnPc/Xiw6wQw5xzfs97Mms2sua2tLZvliIhIIGthb2YzgX8A/tjde0bvc3cHfKzvc/cN7t7o7o01NTXZKkdEREbJStibWT6poH/U3X8WNJ80s9pgfy1wKht9iYjI+GXjahwDHgb2uPv3Ru16ClgXPF4HbM60LxERSU9eFp5jNfBV4B0zezNoux94EHjCzO4CDgFfzkJfIiKShozD3t1fBuwcu2/K9PlFRCRzuoNWRCQEFPYiIiGgsBcRCYFpFfbtfcO5LkFEZFKaNmH/d68cYPuhTkbiiVyXIiIy6WTj0stJ4QtXzWNoJEl+XjTXpYiITDrTJuzLSwopz3URIiKT1LRZxhERkXObVmEfiyf54Yv7cl2GiMikM63CviAvwu0r5+W6DBGRSWdahT1AffWMXJcgIjLpTLuwFxGRsynsRURCQGEvIhICCnsRkRBQ2IuIhIDCXkQkBBT2IiIhkJWwN7NHzOyUme0c1VZlZlvMbF/wtTIbfYmIyPhla2b/d8CtZ7TdC7zg7kuBF4JtERHJgayEvbv/C9BxRvMaYGPweCNwRzb6EhGR8ZvINfs57n48eHwCmDPWQWa23syazay5ra1tAssREQmvi/ICrbs74OfYt8HdG929saam5mKUIyISOhMZ9ifNrBYg+HpqAvsSEZHzmMiwfwpYFzxeB2yewL5EROQ8snXp5f8DXgWWmdlRM7sLeBD4PTPbB9wcbIuISA5k5TNo3f3Oc+y6KRvPLyIimdEdtCIiIaCwFxEJAYW9iEgIKOxFREJAYS8iEgIK+3N470Qvbx7pynUZIiJZkZVLL6ebgVicP396F6+0tDO7tJA/WN3A1z+1GDPLdWkiImnRzH4MP3yxhVda2gE41TvMd599l/s3vcNALJ7jykRE0qOwH8NALHFW2+OvH+E/bGxm17HuHFQkIpIZhf0YFlSVnNWWdGg+2Mlj247koCIRkcwo7Mdw2+W11JQWntXuOGuunJeDikREMqOwH8Pc8iK+9vH6s9q/smoRjfVVF78gEZEMKezP4ec7Wv/Vdm15Ed/6zLIcVSMikhmF/Ri6BmIc6xr8V213Ni1kZqGuVBWRqUnpNYYHn3kXgGsWVXK6b5ioGWuvXZDjqkRE0mepj4edHBobG725uTnXZdA3HGdoJEH1zEKSSWckmaQwL5rrskRExmRm29298XzHaGY/hpmFeR8u2UQiRmFEQS8iU5vW7EVEQmDCw97MbjWz98ysxczunej+RETkbBMa9mYWBX4EfBZYAdxpZismsk8RETnbRM/sm4AWd9/v7jHgMWDNBPcpIiJnmOiwnw+MfjOZo0Hbh8xsvZk1m1lzW1vbBJcjIhJOOX+B1t03uHujuzfW1NTkuhwRkWlposO+FRh9N1Jd0CYiIhfRRIf968BSM2swswJgLfDUBPcpIiJnmNCbqtw9bmZ/BDwHRIFH3H3XRPYpIiJnm/A7aN39F8AvJrofERE5t5y/QCsiIhNPYS8iEgIKexGREFDYi4iEgMJeRCQEFPYiIiGgsBcRCQGFvYhICCjsRURCQGEvIhICCnsRkRBQ2IuIhIDCXkQkBBT2IiIhoLAXEQkBhb2ISAgo7EVEQiCjsDezf2tmu8wsaWaNZ+y7z8xazOw9M7slszJFRCQTmX4s4U7gi8Dfjm40sxWkPlz8MmAe8LyZXeruiQz7ExGRNGQ0s3f3Pe7+3hi71gCPufuwux8AWoCmTPoSEZH0TdSa/XzgyKjto0GbiIjkwAWXcczseWDuGLsecPfNmRZgZuuB9QALFy7M9OlERGQMFwx7d785jedtBRaM2q4L2sZ6/g3ABoDGxkZPoy8REbmAiVrGeQpYa2aFZtYALAW2TVBfIiJyAZleevkFMzsKXA/8k5k9B+Duu4AngN3As8DduhJHRCR3Mrr00t03AZvOse87wHcyeX4REckO3UErIhICCnsRkTMMjSSIJ5K5LiOrFPYiImdwhyMdA7kuI6sU9iIiZyguiNJQMzPXZWSVwl5EJAQU9iIiIaCwFxEJAYW9iEgIKOxFREJAYS8iEgIKexGREFDYi4iEgMJeRCQEFPYiIiGgsBcRCQGFvYhICCjsRURCQGEvIhICmX4G7V+a2btm9raZbTKzilH77jOzFjN7z8xuybhSERFJW6Yz+y3A77j7SmAvcB+Ama0A1gKXAbcCf2Nm0Qz7EhGRNGUU9u7+S3ePB5uvAXXB4zXAY+4+7O4HgBagKZO+REQkfdlcs/9D4Jng8XzgyKh9R4O2s5jZejNrNrPmtra2LJYjIiIfyLvQAWb2PDB3jF0PuPvm4JgHgDjw6HgLcPcNwAaAxsZGH+/3i4jIhV0w7N395vPtN7OvAbcDN7n7B2HdCiwYdVhd0CYiIqPsb+tj1oxCykvyJ7SfTK/GuRX4NvB5dx/9UexPAWvNrNDMGoClwLZM+hIRmY6+t2Uvf/aPuya8nwvO7C/gh0AhsMXMAF5z96+7+y4zewLYTWp55253T2TYl4jItPPXa6+iPxa/8IEZyijs3X3JefZ9B/hOJs8vIjLdRSJGadHELuGA7qAVEQkFhb2ISAgo7EVEQkBhLyISAgp7EZEQUNiLiISAwl5EJAQU9iIiIWC/fTub3DOzNuBQFp+yGjidxefLNY1n8ppOYwGNZ7I7czyL3L3mfN8wqcI+28ys2d0bc11Htmg8k9d0GgtoPJNdOuPRMo6ISAgo7EVEQmC6h/2GXBeQZRrP5DWdxgIaz2Q37vFM6zV7ERFJme4zexERQWEvIhIK0zbszeybZvaume0ys/81qv0+M2sxs/fM7JZc1jgeZvYtM3Mzqw62zcz+OhjL22Z2da5r/CjM7C+D8/K2mW0ys4pR+6bqubk1qLnFzO7NdT3jYWYLzOwlM9sd/KzcE7RXmdkWM9sXfK3Mda3jYWZRM9thZk8H2w1mtjU4R4+bWUGua/yozKzCzJ4Mfm72mNn16ZyfaRn2ZvZpYA1whbtfBvxV0L4CWAtcBtwK/I2ZRXNW6EdkZguAzwCHRzV/ltRn+y4F1gP/OwelpWML8DvuvhLYC9wHU/rcRIEfkTofK4A7g7FMFXHgW+6+AlgF3B3Ufy/wgrsvBV4ItqeSe4A9o7a/C3w/+HS9TuCunFSVnoeAZ919OXAFqXGN+/xMy7AHvgE86O7DAO5+KmhfAzzm7sPufgBoAZpyVON4fJ/UB7uPfjV9DfB/PeU1oMLManNS3Ti4+y/d/YMP3HwNqAseT9Vz0wS0uPt+d48Bj5Eay5Tg7sfd/Y3gcS+pIJlPagwbg8M2AnfkpMA0mFkdcBvw42DbgBuBJ4NDpsx4zKwcuAF4GMDdY+7eRRrnZ7qG/aXAJ4M/2/7ZzK4N2ucDR0YddzRom7TMbA3Q6u5vnbFryo1lDH8IPBM8nqrjmap1n8XM6oGrgK3AHHc/Huw6AczJVV1p+AGpyVEy2J4FdI2aZEylc9QAtAE/CZalfmxmM0jj/GT0geO5ZGbPA3PH2PUAqXFVkfqz9FrgCTNbfBHLG5cLjOV+Uks4U8b5xuPum4NjHiC1hPDoxaxNxmZmM4F/AP7Y3XtSk+EUd3czmxLXaJvZ7cApd99uZr+b43KyIQ+4Gvimu281s4c4Y8nmo56fKRv27n7zufaZ2TeAn3nqJoJtZpYk9cZBrcCCUYfWBW05da6xmNnlpH6zvxX88NUBb5hZE5N0LHD+cwNgZl8Dbgdu8t/e6DFpx3MBU7XuD5lZPqmgf9TdfxY0nzSzWnc/HiwPnjr3M0wqq4HPm9nngCKgjNSad4WZ5QWz+6l0jo4CR919a7D9JKmwH/f5ma7LOD8HPg1gZpcCBaTeIe4pYK2ZFZpZA6kXN7flqsgLcfd33H22u9e7ez2pE3+1u58gNZZ/H1yVswroHvVn3aRlZreS+hP78+4+MGrXlDo3o7wOLA2u9igg9SLzUzmu6SML1rMfBva4+/dG7XoKWBc8Xgdsvti1pcPd73P3uuDnZS3worv/PvAS8KXgsKk0nhPAETNbFjTdBOwmjfMzZWf2F/AI8IiZ7QRiwLpgBrnLzJ4g9Y8VB+5290QO68zEL4DPkXohcwD4g9yW85H9ECgEtgR/rbzm7l939yl5btw9bmZ/BDwHRIFH3H1Xjssaj9XAV4F3zOzNoO1+4EFSy593kXrb8S/nprys+VPgMTP7C2AHwQueU8Q3gUeDycR+Uj/rEcZ5fvR2CSIiITBdl3FERGQUhb2ISAgo7EVEQkBhLyISAgp7EZEQUNiLiISAwl5EJAT+P9XzG/DLJ27KAAAAAElFTkSuQmCC", + "image/png": "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QoEumlioA10hvdfcqe5wRFdOL012eQAAJBWhZRg5e1yezv7EOi2+VJfGfspMIgAARhJ+HgIAAJZAaAEAAJZAaAEAAJYwLELLb37zG40ZM0YpKSmaOXOm1q5dm+ySAADAMJP00PLMM89o4cKFuuuuu/T2229r6tSpmjVrllpbW5NdGgAAGEaSHlp+8YtfaP78+br22ms1adIkPfLII0pLS9Mf/vCHZJcGAACGkaSGlnA4rNraWlVVVcXb7Ha7qqqqVFNTc9j3hEIhBYPBARsAAPj8S2po2b9/v6LRqAoLCwe0FxYWyu/3H/Y9S5Yskc/ni29lZWVDUSoAAEiypP88NFiLFy9WIBCIbw0NDckuCQAADIGkroibl5cnh8OhlpaWAe0tLS0qKio67Hs8Ho88Hs9QlAcAAIaRpN5pcbvdmj59ulatWhVvi8ViWrVqlSorK5NYGQAAGG6S/uyhhQsX6pprrtHpp5+uGTNm6Je//KW6u7t17bXXJrs0AAAwjCQ9tHzjG9/Qvn37dOedd8rv9+vUU0/Vq6++esjgXAAAMLLZjDEm2UV8FsFgUD6fT4FAQF6vN9nlAACAo3As39+Wmz0EAABGJkILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwhISFlnvuuUdnnXWW0tLSlJWVddhj6uvrdckllygtLU0FBQX68Y9/rEgkkqiSAACAhTkTdeJwOKwrr7xSlZWVeuyxxw7ZH41Gdckll6ioqEhvvvmmmpub9d3vflcul0s/+9nPElUWAACwKJsxxiTyAo8//rgWLFigjo6OAe2vvPKKvvKVr6ipqUmFhYWSpEceeUS33nqr9u3bJ7fbfVTnDwaD8vl8CgQC8nq9x7t8AACQAMfy/Z20MS01NTU65ZRT4oFFkmbNmqVgMKgtW7Yc8X2hUEjBYHDABgAAPv+SFlr8fv+AwCIp/trv9x/xfUuWLJHP54tvZWVlCa0TAAAMD4MKLbfddptsNtunblu3bk1UrZKkxYsXKxAIxLeGhoaEXg8AAAwPgxqIu2jRIs2dO/dTjxk7duxRnauoqEhr164d0NbS0hLfdyQej0cej+eorgEAAD4/BhVa8vPzlZ+ff1wuXFlZqXvuuUetra0qKCiQJL322mvyer2aNGnScbkGAAD4/EjYlOf6+nq1tbWpvr5e0WhUGzZskCSNGzdOGRkZuvjiizVp0iR95zvf0b333iu/36877rhD1dXV3EkBAACHSNiU57lz5+qJJ544pP2vf/2rzj//fEnSnj17dMMNN+hvf/ub0tPTdc0112jp0qVyOo8+SzHlGQAA6zmW7++Er9OSaIQWAACsx1LrtAAAAAwGoQUAAFgCoQUAAFgCoQUAgCQwxuiN9/cluwxLIbQAAJAENptN6R5HssuwFEILAABJMn10TrJLsBRCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsARCCwAAsISEhZbdu3dr3rx5qqioUGpqqk444QTdddddCofDA47btGmTzj33XKWkpKisrEz33ntvokoCAAAW5kzUibdu3apYLKZHH31U48aNU11dnebPn6/u7m7dd999kqRgMKiLL75YVVVVeuSRR7R582Z973vfU1ZWlq677rpElQYAACzIZowxQ3Wxn//853r44Ye1c+dOSdLDDz+s22+/XX6/X263W5J022236fnnn9fWrVsPe45QKKRQKBR/HQwGVVZWpkAgIK/Xm/gPAQAAPrNgMCifzzeo7+8hHdMSCASUk5MTf11TU6PzzjsvHlgkadasWdq2bZva29sPe44lS5bI5/PFt7KysoTXDQAAkm/IQsuOHTv04IMP6vvf/368ze/3q7CwcMBxH732+/2HPc/ixYsVCATiW0NDQ+KKBgAAw8agQ8ttt90mm832qdv//mln7969+tKXvqQrr7xS8+fP/0wFezweeb3eARsAAPj8G/RA3EWLFmnu3LmfeszYsWPjf25qatIFF1ygs846S7/97W8HHFdUVKSWlpYBbR+9LioqGmxpAADgODkYjspulzxOR7JLiRt0aMnPz1d+fv5RHbt3715dcMEFmj59upYtWya7feCNncrKSt1+++3q6+uTy+WSJL322ms66aSTlJ2dPdjSAADAcfLVX/9DHT19WrXwC/KluZJdjqQEjmnZu3evzj//fJWXl+u+++7Tvn375Pf7B4xV+da3viW326158+Zpy5YteuaZZ/SrX/1KCxcuTFRZAADgKHzv7AqluOx6p+HwE2OSIWFTnh9//HFde+21h933yUtu2rRJ1dXVWrdunfLy8nTTTTfp1ltvPerrHMuUKQAAkFzH8v09pOu0JAKhBQAA6xn267QAAAAcK0ILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBEILAACwBGeyC/isPnp0UjAYTHIlAADgaH30vT2YRyBaPrR0dnZKksrKypJcCQAAGKzOzk75fL6jOtbyT3mOxWJqampSZmambDbbkFwzGAyqrKxMDQ0NPFn6KNFng0efDQ79NXj02eDRZ4Pzaf1ljFFnZ6dKSkpktx/daBXL32mx2+0qLS1NyrW9Xi9/aQeJPhs8+mxw6K/Bo88Gjz4bnCP119HeYfkIA3EBAIAlEFoAAIAlEFqOgcfj0V133SWPx5PsUiyDPhs8+mxw6K/Bo88Gjz4bnOPdX5YfiAsAAEYG7rQAAABLILQAAABLILQAAABLILQAAABLILQAAABLILQcg7/85S+aOXOmUlNTlZ2drcsuu2zA/vr6el1yySVKS0tTQUGBfvzjHysSiSSn2GEkFArp1FNPlc1m04YNGwbs27Rpk84991ylpKSorKxM9957b3KKHAZ2796tefPmqaKiQqmpqTrhhBN01113KRwODziOPhvoN7/5jcaMGaOUlBTNnDlTa9euTXZJw8KSJUt0xhlnKDMzUwUFBbrsssu0bdu2Acf09vaqurpaubm5ysjI0Jw5c9TS0pKkioefpUuXymazacGCBfE2+uxQe/fu1be//W3l5uYqNTVVp5xyitavXx/fb4zRnXfeqeLiYqWmpqqqqkrbt28f3EUMBuXZZ5812dnZ5uGHHzbbtm0zW7ZsMc8880x8fyQSMZMnTzZVVVXmnXfeMS+//LLJy8szixcvTmLVw8MPf/hDM3v2bCPJvPPOO/H2QCBgCgsLzdVXX23q6urM008/bVJTU82jjz6avGKT6JVXXjFz5841K1euNB988IF5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", "text/plain": [ - "<Figure size 432x288 with 1 Axes>" + "<Figure size 640x480 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1536,7 +1526,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 60, "metadata": {}, "outputs": [ { @@ -1545,20 +1535,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 26, + "execution_count": 60, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "<Figure size 576x576 with 1 Axes>" + "<Figure size 800x800 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1583,7 +1571,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 61, "metadata": {}, "outputs": [ { @@ -1592,20 +1580,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 27, + "execution_count": 61, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD0CAYAAACLpN0/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAASsElEQVR4nO3dfZBd9X3f8fcHPYJ4kGQtqozAwgTHpfEgmEVxhtStce04xAM4k3rcug4dM6MkE7fO1LUNptM647oTp7FJOnWdyg+xmpBgYpviMHkwwdCMPQ32goUQBoyMYSxZ1i5YAoFgQdpv/7hH9UbZ1b272rt7dXi/Zu7sOb9zzt6PpKvPnvu75+5NVSFJOvGdtNABJElzw0KXpJaw0CWpJSx0SWoJC12SWsJCl6SW6KnQkzyW5P4k25KMNGMfSrK7GduW5PL+RpUkHcviGez7+qp64qixG6rqd+YykCRpdmZS6MdtzZo1tWHDhvm8S0k64d1zzz1PVNVQt/16LfQCvpKkgP9ZVVua8Xcn+WVgBHhvVe071jfZsGEDIyMjPd6lJAkgyeO97Nfri6I/W1UXAz8P/HqS1wGfBM4DNgJ7gI9NE2RzkpEkI2NjYz3enSRppnoq9Kra3XwdBW4BNlXV3qo6XFUTwKeATdMcu6WqhqtqeGio6zMGSdIsdS30JCuSnHZkGXgTsCPJukm7vRXY0Z+IkqRe9DKHvha4JcmR/f+4qv4yyR8m2Uhnfv0x4Ff6FVKS1F3XQq+qR4ELpxh/Z18SSZJmxXeKSlJLWOiS1BIWuiTNoariqede5NDhiXm/73l9p6gktc2B519k79PPc8rSRXx955N8Z+8Bli0+iW/vOcDogef5L299Da856wyaC0v6ykKXpFm6f9dTnL/2VFaespSrPvF1du17DoB/tO40Fi8+iR27n+aK//51Pv62C/nFi9f3PY+FLkmzsGvfQXbvP8iz44f4D7fu+P9lDjD2zAs898IhXrZiKUOnLeUH+587xneaOxa6JM3CQ3sO8L4/3c6B8UP8zHmrOX35SpYuPomJiWLv0+OMHhiH8cMsWXwS7/jpV8xLJgtdkmbhbx4Z48D4Ic5edTKjT4/z3bFnWXPqUk5KWL/qZNaesZxzVp/CuWtWsGrF0nnJZKFL0gxVFXc/+iMAzjx9Gfc8vp8li8L5Z57GoYkJvvlY5xfPrj19Oa9ae9q85bLQJWmGbvnWbk5ZuohNG1az/+A4/+RVQ+x56jn+76NP8vIzlnPh+jPY89Tz/Nl9P2D/wRd44wVr5yWXhS5JPZqYKO58eJRrv3g/Lxye4ML1Z/C9Jw/yndFnuejsMwD4wVPP84OnngfgXZdu4H0/9+p5y2ehS1KPvrbzCa7Z+uMP6dn/3IsMn7OKh0cP8NRzhwAYfsUqVp6yhNOWL+Gic1Zx8tJF85bPQpekHuzYvZ/tu/azacMqCqiCkcf3cXiiWLFsMY8+8SyvHFrBv/zpc+blmvOp+NZ/SeriS/fu4l2fG+GRvc9w6XlrGDswzq59zzF02jIOvnCY7/+oc515VfE/7vwuu/YdXJCcnqFL0jE8O36IPx3ZxRUbX8727z/FP/3JIT599SWcN7SCfQdf5K6HR/nEnTtJwqpTlrBz9BmWLFqYc+VU1bzd2fDwcPkh0ZJORM+/eJiDLxxm9TTXlO/ad5Abbn+EZUtO4iNX/dSc/u6WJPdU1XC3/ZxykaQeLF+yaNoyB1hz6jKefHac150/NC+/iGsqFrokzYHxFye4YN3pvHzl8gXL0NMcepLHgAPAYeBQVQ0nWQ18HthA5zNF31ZV+/oTU5IG2xmnLOH9b56/a86nMpMz9NdX1cZJ8zjXAndU1fnAHc26JGmBHM+Uy5XA1mZ5K3DVcaeRJM1ar4VewFeS3JNkczO2tqr2NMs/BObnlxVIkqbU63XoP1tVu5OcCdye5KHJG6uqkkx5/WPzA2AzwDnnnHNcYSVJ0+vpDL2qdjdfR4FbgE3A3iTrAJqvo9Mcu6WqhqtqeGhoaG5SS5L+nq6FnmRFktOOLANvAnYAXwaubna7Gri1XyElSd31MuWyFriluVB+MfDHVfWXSb4J3JzkGuBx4G39iylJ6qZroVfVo8CFU4w/CbyhH6EkSTPnO0UlqSUsdElqCQtdklrCQpeklrDQJaklLHRJagkLXZJawkKXpJaw0CWpJSx0SWoJC12SWsJCl6SWsNAlqSUsdElqCQtdklrCQpeklrDQJaklei70JIuSfCvJbc3655J8L8m25raxbyklSV318pmiR7wHeBA4fdLY+6rqC3MbSZI0Gz2doSdZD/wC8On+xpEkzVavUy6/C7wfmDhq/CNJtie5IcmyOU0mSZqRroWe5C3AaFXdc9Sm64BXA5cAq4EPTHP85iQjSUbGxsaON68kaRq9nKFfClyR5DHgJuCyJH9UVXuqYxz4A2DTVAdX1ZaqGq6q4aGhoTkLLkn6u7oWelVdV1Xrq2oD8Hbgq1X1r5KsA0gS4CpgRz+DSpKObSZXuRztxiRDQIBtwK/OSSJJ0qzMqNCr6i7grmb5sj7kkSTNku8UlaSWsNAlqSUsdElqCQtdklrCQpeklrDQJaklLHRJagkLXZJawkKXpJaw0CWpJSx0SWoJC12SWsJCl6SWsNAlqSUsdElqCQtdklrCQpeklrDQJaklei70JIuSfCvJbc36uUnuTrIzyeeTLO1fTElSNzM5Q38P8OCk9Y8CN1TVTwD7gGvmMpgkaWZ6KvQk64FfAD7drAe4DPhCs8tW4Ko+5JMk9ajXM/TfBd4PTDTrLwP2V9WhZn0XcNbcRpMkzUTXQk/yFmC0qu6ZzR0k2ZxkJMnI2NjYbL6FJKkHvZyhXwpckeQx4CY6Uy2/B6xMsrjZZz2we6qDq2pLVQ1X1fDQ0NAcRJYkTaVroVfVdVW1vqo2AG8HvlpV7wDuBH6p2e1q4Na+pZQkdXU816F/APh3SXbSmVP/zNxEkiTNxuLuu/xYVd0F3NUsPwpsmvtIkqTZ8J2iktQSFroktYSFLkktYaFLUktY6JLUEha6JLWEhS5JLWGhS1JLWOiS1BIWuiS1hIUuSS1hoUtSS1joktQSFroktYSFLkktYaFLUktY6JLUEl0LPcnyJN9Icl+SB5L8ZjP+uSTfS7KtuW3se1pJ0rR6+Qi6ceCyqnomyRLga0n+otn2vqr6Qv/iSZJ61bXQq6qAZ5rVJc2t+hlKkjRzPc2hJ1mUZBswCtxeVXc3mz6SZHuSG5Is61dISVJ3PRV6VR2uqo3AemBTkp8CrgNeDVwCrAY+MNWxSTYnGUkyMjY2NjepJUl/z4yucqmq/cCdwJurak91jAN/AGya5pgtVTVcVcNDQ0PHHViSNLVernIZSrKyWT4ZeCPwUJJ1zViAq4Ad/YspSeqml6tc1gFbkyyi8wPg5qq6LclXkwwBAbYBv9q/mJKkbnq5ymU7cNEU45f1JZEkaVZ8p6gktYSFLkktYaFLUktY6JLUEha6JLWEhS5JLWGhS1JLWOiS1BIWuiS1hIUuSS1hoUtSS1joktQSFroktYSFLkktYaFLUktY6JLUEha6JLWEhS5JLdHLh0QvT/KNJPcleSDJbzbj5ya5O8nOJJ9PsrT/cSVJ0+nlDH0cuKyqLgQ2Am9O8lrgo8ANVfUTwD7gmr6llCR11bXQq+OZZnVJcyvgMuALzfhW4Kp+BJQk9aanOfQki5JsA0aB24HvAvur6lCzyy7grL4klCT1pKdCr6rDVbURWA9sAl7d6x0k2ZxkJMnI2NjY7FJKkrqa0VUuVbUfuBP4GWBlksXNpvXA7mmO2VJVw1U1PDQ0dDxZJUnH0MtVLkNJVjbLJwNvBB6kU+y/1Ox2NXBrnzJKknqwuPsurAO2JllE5wfAzVV1W5JvAzcl+c/At4DP9DGnJKmLroVeVduBi6YYf5TOfLokaQD4TlFJagkLXZJawkKXpJaw0CWpJSx0SWoJC12SWsJCl6SWsNAlqSUsdElqCQtdklrCQpeklrDQJaklLHRJagkLXZJawkKXpJaw0CWpJSx0SWqJXj5T9Owkdyb5dpIHkrynGf9Qkt1JtjW3y/sfV5I0nV4+U/QQ8N6qujfJacA9SW5vtt1QVb/Tv3iSpF718pmie4A9zfKBJA8CZ/U7mCRpZmY0h55kA50PjL67GXp3ku1JPptk1VyHkyT1rudCT3Iq8EXgN6rqaeCTwHnARjpn8B+b5rjNSUaSjIyNjR1/YknSlHoq9CRL6JT5jVX1JYCq2ltVh6tqAvgUsGmqY6tqS1UNV9Xw0NDQXOWWJB2ll6tcAnwGeLCqPj5pfN2k3d4K7Jj7eJKkXvVylculwDuB+5Nsa8Y+CPyLJBuBAh4DfqUP+SRJPerlKpevAZli05/PfRxJ0mz5TlFJagkLXZJawkKXpJaw0CWpJSx0SWoJC12SWsJCl6SWsNAlqSUsdElqCQtdklrCQpeklrDQJaklLHRJagkLXZJawkKXpJaw0CWpJSx0SWoJC12SWqKXD4k+O8mdSb6d5IEk72nGVye5PckjzddV/Y8rSZpOL2foh4D3VtUFwGuBX09yAXAtcEdVnQ/c0axLkhZI10Kvqj1VdW+zfAB4EDgLuBLY2uy2FbiqTxklST2Y0Rx6kg3ARcDdwNqq2tNs+iGwdm6jSZJmoudCT3Iq8EXgN6rq6cnbqqqAmua4zUlGkoyMjY0dV1hJ0vR6KvQkS+iU+Y1V9aVmeG+Sdc32dcDoVMdW1ZaqGq6q4aGhobnILEmaQi9XuQT4DPBgVX180qYvA1c3y1cDt859PElSrxb3sM+lwDuB+5Nsa8Y+CPwWcHOSa4DHgbf1JaEkqSddC72qvgZkms1vmNs4kqTZ8p2iktQSFroktYSFLkktYaFLUktY6JLUEha6JLWEhS5JLXHCFPqhwxNMTEz562IkSZxAhb540Um8cHhioWNI0sA6YQodYPmSRQsdQZIG1glV6JKk6VnoktQSFroktYSFLkktYaFLUktY6JLUEha6JLWEhS5JLZGq+Xs7fZIxOp8/Op/WAE/M833O1omUFU6svGbtD7P2z+S8r6iqoW4HzGuhL4QkI1U1vNA5enEiZYUTK69Z+8Os/TObvE65SFJLWOiS1BIvhULfstABZuBEygonVl6z9odZ+2fGeVs/hy5JLxUvhTN0SXpJaHWhJ/k3SR5K8kCS3540fl2SnUkeTvJzC5mxyfOhJLuTbGtul0/aNlBZj0jy3iSVZE2zniT/rcm6PcnFA5Dxw02WbUm+kuTlg5oVIMl/bR6v25PckmTlpG0D9ThI8s+b/1cTSYaP2jZQWQGSvLnJszPJtQudZ7Ikn00ymmTHpLHVSW5P8kjzdVVP36yqWnkDXg/8NbCsWT+z+XoBcB+wDDgX+C6waIGzfgj491OMD1zWJtfZwF/ReU/BmmbscuAvgACvBe4egJynT1r+t8DvD2rWJtebgMXN8keBjw7q4wD4h8BPAncBw5PGBzHroibHK4GlTb4LFvrfe1K+1wEXAzsmjf02cG2zfO2Rx0K3W5vP0H8N+K2qGgeoqtFm/Ergpqoar6rvATuBTQuUsZtBzXoD8H5g8gswVwL/qzr+FliZZN2CpGtU1dOTVlfw47wDlxWgqr5SVYea1b8F1jfLA/c4qKoHq+rhKTYNXNbm/ndW1aNV9QJwE52cA6Gq/gb40VHDVwJbm+WtwFW9fK82F/qrgH+c5O4k/yfJJc34WcD3J+23qxlbaO9unmp/dtLTq4HLmuRKYHdV3XfUpoHLCpDkI0m+D7wD+I/N8EBmPcq76DyLgBMj7xGDmHUQM3Wztqr2NMs/BNb2ctDi/uXpvyR/DfyDKTZdT+fPtprOU+pLgJuTvHIe4/0dXbJ+EvgwnTPIDwMfo/MfekF0yfpBOlMDA+FYWavq1qq6Hrg+yXXAu4H/NK8Bj9Itb7PP9cAh4Mb5zHa0XrKq/6qqkvR0OeIJXehV9c+m25bk14AvVWcS6htJJuj8boTddOaAj1jfjPXVsbJOluRTwG3N6kBlTfIaOvOi9yU5kufeJJsYsKxTuBH4czqFviBZoXveJP8aeAvwhuaxC4P/dzvZgv3dHsMgZupmb5J1VbWnmQ4c7XoE7Z5y+d90XhglyavovBjyBPBl4O1JliU5Fzgf+MZChWzyTZ6/fStw5NXugcpaVfdX1ZlVtaGqNtB56npxVf2wyfrLzRUkrwWemvSUcUEkOX/S6pXAQ83ywGWFzpUYdF6buKKqDk7aNFCPgy4GMes3gfOTnJtkKfB2OjkH2ZeBq5vlq4HenhEt9Cu8fXzleCnwR3TK8V7gsknbrqfzqvfDwM8PQNY/BO4Htjf/kOsGNetRuR/jx1e5BPhEk/V+Jl35sID5vtj8+28H/gw4a1CzNrl20pnr3dbcfn9QHwd0Tjx2AePAXuCvBjVrk+ly4DtNrusXOs9R2f4E2AO82PydXgO8DLgDeITO1Xqre/levlNUklqizVMukvSSYqFLUktY6JLUEha6JLWEhS5JLWGhS1JLWOiS1BIWuiS1xP8Dz7ylUJyiG8sAAAAASUVORK5CYII=", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAFmCAYAAAC/V5rzAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAlV0lEQVR4nO3df3RU9Z3/8dfk15CQzOT3L5kExApomq+KNYw/WJRUFlyqa9zTo1TFL8uKJ2IF2mXzlVbhuzZ89RRc2YW6tYuelUhLD5T1J0XQeKyJ0pgYwJIKBRIMCVXMTAhkEsjn+4dlykhQJgl8yOT5OOeew3w+937m/Zlo7uvc+dwbhzHGCAAAwJIo2wUAAIChjTACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArIoJZ+fHHntMixcvDmkbM2aMdu3aJUmaNGmSKisrQ/rvv/9+/exnPzvr9+jp6VFzc7OSkpLkcDjCKQ8AAFhijFF7e7tyc3MVFRXetY6wwogkXX755XrjjTf+OkBM6BCzZ8/WkiVLgq8TEhLCGr+5uVkejyfcsgAAwAWgqalJI0aMCOuYsMNITEyMsrOzz9ifkJDwlf1fJykpSdIXk3G5XH0eBwAAnD9+v18ejyd4Hg9H2GHk448/Vm5uroYNGyav16vy8nLl5eUF+9esWaMXXnhB2dnZmj59un70ox995dWRQCCgQCAQfN3e3i5JcrlchBEAAAaZviyxCCuMFBUV6bnnntOYMWN08OBBLV68WDfccIN27NihpKQk3XXXXcrPz1dubq7q6+u1cOFCNTQ0aP369Wccs7y8/LR1KAAAYOhwGGNMXw9ua2tTfn6+li1bplmzZp3Wv3XrVk2ePFm7d+/W6NGjex3jy1dGTl7m8fl8XBkBAGCQ8Pv9crvdfTp/h/01zamSk5N16aWXavfu3b32FxUVSdJXhhGn0ymn09mfMgAAwCDWr+eMHDlyRHv27FFOTk6v/XV1dZJ0xn4AAICwroz84Ac/0PTp05Wfn6/m5mY9+uijio6O1p133qk9e/aooqJC06ZNU1pamurr6zVv3jxNnDhRhYWF56p+AAAwyIUVRg4cOKA777xTn332mTIyMnT99derurpaGRkZ6uzs1BtvvKGnnnpKHR0d8ng8Kikp0aJFi85V7QAAIAL0awHrudCfBTAAAMCO/py/+ds0AADAKsIIAACwijACAACsIowAAACrCCMAAEQAY4y6jvcocPyEOrtPaMcnPnV2HVfX8R7bpX2tfj2BFQAA2PPZkYB2tbQrOSFW7vhYNbcd085P/Gr2HVOiM0arf3dMHx3065C/U39XmKPFtxbYLrlXhBEAAAaZ7hM9+qjZr3E5Ll13Sbr2ftqhJS99pDf+0Kqevzyw4+r8FP1+/+fBY56v2q8/HGzXor8bp8IRyXYKPwO+pgEAYBDp6TFaseVjFeS6FBcTpZ4eo/m/qtNvP/prEJG+CCxFo1J1hSdZo9KHS5Le33dYa7c1War8zAgjAAAMIvs/61DisBhFR0fp9/sP68afvqXaxrbT9vvwgE89xqiuqU17P+3Q1fkpiomSAt0X3hoSvqYBAGAQ8Xce12s7WvTq9hZ92NSmkX+56iFJ0Q7JSHLHx+qSzEQd7ugK9v1+/+cqGpWqGRPyLFT91QgjAAAMIhvrmkOuhLQf69L/8rh1yB9QjzHypMTro4N+/enPHfrslDAiSVEOh67KSznPFX89wggAAINIzf7DwX+PTEtQbHSUPmzySZIcDik/LUFHu3qU447V6MzhknEoN3mYRqQkKD8twVbZX4kwAgDAIHGs64QaWtuDrzNdTr2/9/OQfaLk0KVZifpj6xHt+XOHJOmhyd/QvOJvnNdaw8ECVgAABolXtjer85QFqA45gv++PNelcdlJqt57WAlx0SHHPb3lY131fzfr8Vf+cN5qDQdXRgAAGAT+3B7Q8+/u1yWZiRrujJYzOkrv7T2sCaNSFRPtUM3+z3XsL0HFd6xbBRe5JCPtaPZLkj4/2q2U4XE2p3BGhBEAAC5w/s5u/e/ntmn7J1+sDblmVKpqGz9XZpJT1XsP6wpPsswpzxjZ++nR4L9zk4dpTFaSrh2drvuuG3meKz87fE0DAMAF7J2PP9V3n6kOBhHpiwefjUofrotS4nVpVqJ6jNGl2Um9Ht/c1qnO7h599xqPYqIvzNM+V0YAALhAHfJ36n8+/ER/OOgPaa9p/Fx5qQmKjT6hP7YeUaIzWlFRX6wfiYuJ0k1jMpWcEKuG1nbdcEm6rsxLUZLzwj3lX7iVAQAwhL2+o0UNLX5dlBKvuJgoRTmkhLgYjUxL0N5PO9Tq71TWiGRdMypV7+89rNhoh67KS9almUl67NbLNSw2+uvf5AJBGAEA4AJyosfovT99ps+PdikzaZj+9OkRTR6TqboDbTro6wx5qur7e//6zJHuE0YfNLbpj61HNCpjuO7/m9E2yu8TwggAABeQVn+nlrz8kQ58fkzxcdG646oRmvbNbL2377DGZifpWPcJJcfH6tMjXTroOxbyx/EkaVhslP7f67vkHZ12wf113jMhjAAAcAH56W//KHd8rG4pzFHX8R593HpEqcPjNOdvLtbdE0bKyOjA58fkGharmavf166WLx6C5nBI38hMVFx0lD7r6NKJL6eUCxhhBACAC8i4nCQ9MOli1TX59OL7jZpakK07r8nT8FMWoF6a9cWdM688dIP+58NPlOuO1wvV+/XK9oPqMdI/Xj9KV3iSLc0gfA5jzAUVnfx+v9xut3w+n1wul+1yAAAYNGr2f64Zz1br/0wbp3u8I8/re/fn/H1h3nAMAADC9nJ9s/7x+ov1vaJ826WEha9pAACIAHVNbap4r1GB4z26cWyGxuen2i7prBFGAACIAFd4kvWz741XR9fxQRVEJMIIAAAR48axmbZL6JOw1ow89thjcjgcIdvYsWOD/Z2dnSotLVVaWpoSExNVUlKi1tbWAS8aAABEjrAXsF5++eU6ePBgcHvnnXeCffPmzdNLL72kdevWqbKyUs3Nzbr99tsHtGAAABBZwv6aJiYmRtnZ2ae1+3w+/eIXv1BFRYVuuukmSdLq1as1btw4VVdXa8KECf2vFgAARJywr4x8/PHHys3N1cUXX6wZM2aosbFRklRTU6Pu7m4VFxcH9x07dqzy8vJUVVV1xvECgYD8fn/IBgAAho6wwkhRUZGee+45vf7661q1apX27t2rG264Qe3t7WppaVFcXJySk5NDjsnKylJLS8sZxywvL5fb7Q5uHo+nTxMBAACDU1hf00ydOjX478LCQhUVFSk/P1+/+tWvFB8f36cCysrKNH/+/OBrv99PIAEAYAjp1xNYk5OTdemll2r37t3Kzs5WV1eX2traQvZpbW3tdY3JSU6nUy6XK2QDAABDR7/CyJEjR7Rnzx7l5ORo/Pjxio2N1ZYtW4L9DQ0NamxslNfr7XehAAAgMoX1Nc0PfvADTZ8+Xfn5+Wpubtajjz6q6Oho3XnnnXK73Zo1a5bmz5+v1NRUuVwuzZ07V16vlztpAADAGYUVRg4cOKA777xTn332mTIyMnT99derurpaGRkZkqTly5crKipKJSUlCgQCmjJlilauXHlOCgcAAJHBYYwxtos4VX/+BDEAALCjP+fvfq0ZAQAA6C/CCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAqn6FkaVLl8rhcOjhhx8Otk2aNEkOhyNkmzNnTn/rBAAAESqmrwdu27ZNzzzzjAoLC0/rmz17tpYsWRJ8nZCQ0Ne3AQAAEa5PV0aOHDmiGTNm6Oc//7lSUlJO609ISFB2dnZwc7lc/S4UAABEpj6FkdLSUt1yyy0qLi7utX/NmjVKT09XQUGBysrKdPTo0TOOFQgE5Pf7QzYAADB0hP01zdq1a/XBBx9o27Ztvfbfddddys/PV25ururr67Vw4UI1NDRo/fr1ve5fXl6uxYsXh1sGAACIEA5jjDnbnZuamnT11Vdr8+bNwbUikyZN0hVXXKGnnnqq12O2bt2qyZMna/fu3Ro9evRp/YFAQIFAIPja7/fL4/HI5/Px9Q4AAIOE3++X2+3u0/k7rCsjNTU1OnTokK666qpg24kTJ/T222/r3//93xUIBBQdHR1yTFFRkSSdMYw4nU45nc6wigYAAJEjrDAyefJkbd++PaTtvvvu09ixY7Vw4cLTgogk1dXVSZJycnL6XiUAAIhYYYWRpKQkFRQUhLQNHz5caWlpKigo0J49e1RRUaFp06YpLS1N9fX1mjdvniZOnNjrLcAAAAB9fs5Ib+Li4vTGG2/oqaeeUkdHhzwej0pKSrRo0aKBfBsAABBBwlrAej70ZwEMAACwoz/nb/42DQAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAqn6FkaVLl8rhcOjhhx8OtnV2dqq0tFRpaWlKTExUSUmJWltb+1snAACIUH0OI9u2bdMzzzyjwsLCkPZ58+bppZde0rp161RZWanm5mbdfvvt/S4UAABEpj6FkSNHjmjGjBn6+c9/rpSUlGC7z+fTL37xCy1btkw33XSTxo8fr9WrV+vdd99VdXX1gBUNAAAiR5/CSGlpqW655RYVFxeHtNfU1Ki7uzukfezYscrLy1NVVVWvYwUCAfn9/pANAAAMHTHhHrB27Vp98MEH2rZt22l9LS0tiouLU3Jyckh7VlaWWlpaeh2vvLxcixcvDrcMAAAQIcK6MtLU1KTvf//7WrNmjYYNGzYgBZSVlcnn8wW3pqamARkXAAAMDmGFkZqaGh06dEhXXXWVYmJiFBMTo8rKSj399NOKiYlRVlaWurq61NbWFnJca2ursrOzex3T6XTK5XKFbAAAYOgI62uayZMna/v27SFt9913n8aOHauFCxfK4/EoNjZWW7ZsUUlJiSSpoaFBjY2N8nq9A1c1AACIGGGFkaSkJBUUFIS0DR8+XGlpacH2WbNmaf78+UpNTZXL5dLcuXPl9Xo1YcKEgasaAABEjLAXsH6d5cuXKyoqSiUlJQoEApoyZYpWrlw50G8DAAAihMMYY2wXcSq/3y+32y2fz8f6EQAABon+nL/52zQAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKvCCiOrVq1SYWGhXC6XXC6XvF6vXnvttWD/pEmT5HA4QrY5c+YMeNEAACByxISz84gRI7R06VJ94xvfkDFGzz//vG699VbV1tbq8ssvlyTNnj1bS5YsCR6TkJAwsBUDAICIElYYmT59esjrxx9/XKtWrVJ1dXUwjCQkJCg7O3vgKgQAABGtz2tGTpw4obVr16qjo0NerzfYvmbNGqWnp6ugoEBlZWU6evToV44TCATk9/tDNgAAMHSEdWVEkrZv3y6v16vOzk4lJiZqw4YNuuyyyyRJd911l/Lz85Wbm6v6+notXLhQDQ0NWr9+/RnHKy8v1+LFi/s+AwAAMKg5jDEmnAO6urrU2Ngon8+nX//613r22WdVWVkZDCSn2rp1qyZPnqzdu3dr9OjRvY4XCAQUCASCr/1+vzwej3w+n1wuV5jTAQAANvj9frnd7j6dv8MOI19WXFys0aNH65lnnjmtr6OjQ4mJiXr99dc1ZcqUsxqvP5MBAAB29Of83e/njPT09IRc2ThVXV2dJCknJ6e/bwMAACJUWGtGysrKNHXqVOXl5am9vV0VFRV66623tGnTJu3Zs0cVFRWaNm2a0tLSVF9fr3nz5mnixIkqLCw8V/UDAIBBLqwwcujQId1zzz06ePCg3G63CgsLtWnTJn37299WU1OT3njjDT311FPq6OiQx+NRSUmJFi1adK5qBwAAEaDfa0YGGmtGAAAYfKyuGQEAAOgPwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwKqwwsiqVatUWFgol8sll8slr9er1157Ldjf2dmp0tJSpaWlKTExUSUlJWptbR3wogEAQOQIK4yMGDFCS5cuVU1NjX7/+9/rpptu0q233qqdO3dKkubNm6eXXnpJ69atU2VlpZqbm3X77befk8IBAEBkcBhjTH8GSE1N1ZNPPqk77rhDGRkZqqio0B133CFJ2rVrl8aNG6eqqipNmDDhrMbz+/1yu93y+XxyuVz9KQ0AAJwn/Tl/93nNyIkTJ7R27Vp1dHTI6/WqpqZG3d3dKi4uDu4zduxY5eXlqaqq6ozjBAIB+f3+kA0AAAwdYYeR7du3KzExUU6nU3PmzNGGDRt02WWXqaWlRXFxcUpOTg7ZPysrSy0tLWccr7y8XG63O7h5PJ6wJwEAAAavsMPImDFjVFdXp/fee08PPPCA7r33Xn300Ud9LqCsrEw+ny+4NTU19XksAAAw+MSEe0BcXJwuueQSSdL48eO1bds2/du//Zu++93vqqurS21tbSFXR1pbW5WdnX3G8ZxOp5xOZ/iVAwCAiNDv54z09PQoEAho/Pjxio2N1ZYtW4J9DQ0NamxslNfr7e/bAACACBXWlZGysjJNnTpVeXl5am9vV0VFhd566y1t2rRJbrdbs2bN0vz585WamiqXy6W5c+fK6/We9Z00AABg6AkrjBw6dEj33HOPDh48KLfbrcLCQm3atEnf/va3JUnLly9XVFSUSkpKFAgENGXKFK1cufKcFA4AACJDv58zMtB4zggAAIOPleeMAAAADATCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAq8IKI+Xl5frWt76lpKQkZWZm6rbbblNDQ0PIPpMmTZLD4QjZ5syZM6BFAwCAyBFWGKmsrFRpaamqq6u1efNmdXd36+abb1ZHR0fIfrNnz9bBgweD2xNPPDGgRQMAgMgRE87Or7/+esjr5557TpmZmaqpqdHEiROD7QkJCcrOzh6YCgEAQETr15oRn88nSUpNTQ1pX7NmjdLT01VQUKCysjIdPXr0jGMEAgH5/f6QDQAADB1hXRk5VU9Pjx5++GFdd911KigoCLbfddddys/PV25ururr67Vw4UI1NDRo/fr1vY5TXl6uxYsX97UMAAAwyDmMMaYvBz7wwAN67bXX9M4772jEiBFn3G/r1q2aPHmydu/erdGjR5/WHwgEFAgEgq/9fr88Ho98Pp9cLldfSgMAAOeZ3++X2+3u0/m7T1dGHnzwQb388st6++23vzKISFJRUZEknTGMOJ1OOZ3OvpQBAAAiQFhhxBijuXPnasOGDXrrrbc0atSorz2mrq5OkpSTk9OnAgEAQGQLK4yUlpaqoqJCGzduVFJSklpaWiRJbrdb8fHx2rNnjyoqKjRt2jSlpaWpvr5e8+bN08SJE1VYWHhOJgAAAAa3sNaMOByOXttXr16tmTNnqqmpSd/73ve0Y8cOdXR0yOPx6O///u+1aNGis/7+qD/fOQEAADvO25qRr8stHo9HlZWVYRUAAACGNv42DQAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAqrDCSHl5ub71rW8pKSlJmZmZuu2229TQ0BCyT2dnp0pLS5WWlqbExESVlJSotbV1QIsGAACRI6wwUllZqdLSUlVXV2vz5s3q7u7WzTffrI6OjuA+8+bN00svvaR169apsrJSzc3Nuv322we8cAAAEBkcxhjT14P//Oc/KzMzU5WVlZo4caJ8Pp8yMjJUUVGhO+64Q5K0a9cujRs3TlVVVZowYcLXjun3++V2u+Xz+eRyufpaGgAAOI/6c/7u15oRn88nSUpNTZUk1dTUqLu7W8XFxcF9xo4dq7y8PFVVVfU6RiAQkN/vD9kAAMDQ0ecw0tPTo4cffljXXXedCgoKJEktLS2Ki4tTcnJyyL5ZWVlqaWnpdZzy8nK53e7g5vF4+loSAAAYhPocRkpLS7Vjxw6tXbu2XwWUlZXJ5/MFt6ampn6NBwAABpeYvhz04IMP6uWXX9bbb7+tESNGBNuzs7PV1dWltra2kKsjra2tys7O7nUsp9Mpp9PZlzIAAEAECOvKiDFGDz74oDZs2KCtW7dq1KhRIf3jx49XbGystmzZEmxraGhQY2OjvF7vwFQMAAAiSlhXRkpLS1VRUaGNGzcqKSkpuA7E7XYrPj5ebrdbs2bN0vz585WamiqXy6W5c+fK6/We1Z00AABg6Anr1l6Hw9Fr++rVqzVz5kxJXzz0bMGCBXrxxRcVCAQ0ZcoUrVy58oxf03wZt/YCADD49Of83a/njJwLhBEAAAYfa88ZAQAA6C/CCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwaUmGks/uE7RIAAMCXDKkwMiw2WpLkO9ptuRIAAHDSkAojJw13RtsuAQAA/MWQDCMx0UNy2gAAXJA4KwMAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALAqxnYBX2aMkST5/X7LlQAAgLN18rx98jwejgsujLS3t0uSPB6P5UoAAEC42tvb5Xa7wzrGYfoSYc6hnp4eNTc3KykpSQ6Hw3Y5X8vv98vj8aipqUkul8t2Oecd82f+zJ/5M3/m73K5ZIxRe3u7cnNzFRUV3iqQC+7KSFRUlEaMGGG7jLC5XK4h+R/jScyf+TN/5j9UMf+/zj/cKyInsYAVAABYRRgBAABWEUb6yel06tFHH5XT6bRdihXMn/kzf+bP/Jl/f11wC1gBAMDQwpURAABgFWEEAABYRRgBAABWEUYAAIBVhBEAAGAVYaQfXnnlFRUVFSk+Pl4pKSm67bbbQvobGxt1yy23KCEhQZmZmfrhD3+o48eP2yl2gI0cOVIOhyNkW7p0acg+9fX1uuGGGzRs2DB5PB498cQTlqo9dwKBgK644go5HA7V1dWF9EXy/L/zne8oLy9Pw4YNU05Oju6++241NzeH7BPJ89+3b59mzZqlUaNGKT4+XqNHj9ajjz6qrq6ukP0i9TN4/PHHde211yohIUHJycm97hPJv/8k6T/+4z80cuRIDRs2TEVFRXr//fdtl3ROvP3225o+fbpyc3PlcDj0m9/8JqTfGKMf//jHysnJUXx8vIqLi/Xxxx+H/0YGffLrX//apKSkmFWrVpmGhgazc+dO88tf/jLYf/z4cVNQUGCKi4tNbW2tefXVV016eropKyuzWPXAyc/PN0uWLDEHDx4MbkeOHAn2+3w+k5WVZWbMmGF27NhhXnzxRRMfH2+eeeYZi1UPvIceeshMnTrVSDK1tbXB9kif/7Jly0xVVZXZt2+f+d3vfme8Xq/xer3B/kif/2uvvWZmzpxpNm3aZPbs2WM2btxoMjMzzYIFC4L7RPJn8OMf/9gsW7bMzJ8/37jd7tP6I/3339q1a01cXJz5r//6L7Nz504ze/Zsk5ycbFpbW22XNuBeffVV88gjj5j169cbSWbDhg0h/UuXLjVut9v85je/MR9++KH5zne+Y0aNGmWOHTsW1vsQRvqgu7vbXHTRRebZZ5894z6vvvqqiYqKMi0tLcG2VatWGZfLZQKBwPko85zKz883y5cvP2P/ypUrTUpKSshcFy5caMaMGXMeqjs/Xn31VTN27Fizc+fO08LIUJj/qTZu3GgcDofp6uoyxgy9+RtjzBNPPGFGjRoVfD0UPoPVq1f3GkYi/fffNddcY0pLS4OvT5w4YXJzc015ebnFqs69L4eRnp4ek52dbZ588slgW1tbm3E6nebFF18Ma2y+pumDDz74QJ988omioqJ05ZVXKicnR1OnTtWOHTuC+1RVVemb3/ymsrKygm1TpkyR3+/Xzp07bZQ94JYuXaq0tDRdeeWVevLJJ0MuwVZVVWnixImKi4sLtk2ZMkUNDQ36/PPPbZQ7oFpbWzV79mz993//txISEk7rj/T5n+rw4cNas2aNrr32WsXGxkoaWvM/yefzKTU1Nfh6KH4GJ0Xy77+uri7V1NSouLg42BYVFaXi4mJVVVVZrOz827t3r1paWkI+C7fbraKiorA/C8JIH/zpT3+SJD322GNatGiRXn75ZaWkpGjSpEk6fPiwJKmlpSXkf0RJwdctLS3nt+Bz4KGHHtLatWv15ptv6v7779dPfvIT/fM//3OwP5Lnb4zRzJkzNWfOHF199dW97hPJ8z9p4cKFGj58uNLS0tTY2KiNGzcG+4bC/E+1e/durVixQvfff3+wbah9BqeK5Ll/+umnOnHiRK/zG+xzC9fJ+Q7EZ0EYOcW//Mu/nLYo88vbrl271NPTI0l65JFHVFJSovHjx2v16tVyOBxat26d5Vn03dnOX5Lmz5+vSZMmqbCwUHPmzNFPf/pTrVixQoFAwPIs+u5s579ixQq1t7errKzMdskDKpyfvyT98Ic/VG1trX77298qOjpa99xzj8wg/+sS4X4GkvTJJ5/ob//2b/UP//APmj17tqXK+68vcwcGSoztAi4kCxYs0MyZM79yn4svvlgHDx6UJF122WXBdqfTqYsvvliNjY2SpOzs7NNWV7e2tgb7LkRnO//eFBUV6fjx49q3b5/GjBmj7Ozs4HxPipT5b926VVVVVaf9cairr75aM2bM0PPPPx/R8z8pPT1d6enpuvTSSzVu3Dh5PB5VV1fL6/UOyvlL4X8Gzc3NuvHGG3XttdfqP//zP0P2G2yfQX/+//+ywfj772ylp6crOjq615/tYJ9buE7Ot7W1VTk5OcH21tZWXXHFFWGNRRg5RUZGhjIyMr52v/Hjx8vpdKqhoUHXX3+9JKm7u1v79u1Tfn6+JMnr9erxxx/XoUOHlJmZKUnavHmzXC5XSIi5kJzt/HtTV1enqKio4Fy9Xq8eeeQRdXd3B9cRbN68WWPGjFFKSsqA1TyQznb+Tz/9tP71X/81+Lq5uVlTpkzRL3/5SxUVFUmK7Pn35uTVwpNXxgbj/KXwPoNPPvlEN954Y/DKaFRU6IXmwfYZ9Ofn/2WD8fff2YqLi9P48eO1ZcuW4OMcenp6tGXLFj344IN2izvPRo0apezsbG3ZsiUYPvx+v9577z098MAD4Q02MGtsh57vf//75qKLLjKbNm0yu3btMrNmzTKZmZnm8OHDxpi/3tp28803m7q6OvP666+bjIyMiLi17d133zXLly83dXV1Zs+ePeaFF14wGRkZ5p577gnu09bWZrKysszdd99tduzYYdauXWsSEhIi4rbGL9u7d+9pd9NE8vyrq6vNihUrTG1trdm3b5/ZsmWLufbaa83o0aNNZ2enMSay52+MMQcOHDCXXHKJmTx5sjlw4EDILe4nRfJnsH//flNbW2sWL15sEhMTTW1tramtrTXt7e3GmMj+/WfMF7f2Op1O89xzz5mPPvrI/NM//ZNJTk4OuXsoUrS3twd/vpLMsmXLTG1trdm/f78x5otbe5OTk83GjRtNfX29ufXWW7m193zq6uoyCxYsMJmZmSYpKckUFxebHTt2hOyzb98+M3XqVBMfH2/S09PNggULTHd3t6WKB05NTY0pKioybrfbDBs2zIwbN8785Cc/CZ6ITvrwww/N9ddfb5xOp7nooovM0qVLLVV8bvUWRoyJ3PnX19ebG2+80aSmphqn02lGjhxp5syZYw4cOBCyX6TO35gvbmmV1Ot2qkj9DO69995e5/7mm28G94nU338nrVixwuTl5Zm4uDhzzTXXmOrqatslnRNvvvlmrz/re++91xjzxe29P/rRj0xWVpZxOp1m8uTJpqGhIez3cRgzyFecAQCAQY27aQAAgFWEEQAAYBVhBAAAWEUYAQAAVhFGAACAVYQRAABgFWEEAABYRRgBAABWEUYAAIBVhBEAAGAVYQQAAFj1/wEMSXMPAGpn4gAAAABJRU5ErkJggg==", "text/plain": [ - "<Figure size 432x288 with 1 Axes>" + "<Figure size 640x480 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1616,7 +1602,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 62, "metadata": {}, "outputs": [ { @@ -1625,20 +1611,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 28, + "execution_count": 62, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "<Figure size 576x576 with 1 Axes>" + "<Figure size 800x800 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1656,7 +1640,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 63, "metadata": {}, "outputs": [ { @@ -1665,20 +1649,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 29, + "execution_count": 63, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "<Figure size 432x288 with 1 Axes>" + "<Figure size 640x480 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1689,7 +1671,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 64, "metadata": {}, "outputs": [ { @@ -1698,20 +1680,18 @@ "<AxesSubplot:>" ] }, - "execution_count": 30, + "execution_count": 64, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAASoAAAHSCAYAAABb+4ZbAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAC2wklEQVR4nOyddXhj17W33yNmMrM9nvEweMbjyYQ5TZM0STFlTtv0lrm3vYVbbtp+5SbtbVOGtGnTcNIwTIaZx8wki1k63x+yNZIFltmeOe/z5IklHdjyWEt7r73W7yeIooiEhITEYka20AOQkJCQmAwpUElISCx6pEAlISGx6JEClYSExKJHClQSEhKLHilQSUhILHoU83mzwsJCsba2dj5vKSEhsYTYu3fvsCiKRROfn9dAVVtby549e+bzlhISEksIQRA6Mj0vLf0kJCQWPVKgkpCQWPRIgUpCQmLRIwUqCQmJRY8UqCQkJBY9UqCSkJBY9EiBSkJCYtEjBSoJCYlFjxSoJCQkFj1SoJKQkFj0SIFKQkJi0SMFKgkJiUWPFKgkJCQWPVKgkpCQWPRIgUpCQmLRIwUqCQmJRY8UqCQkJBY9UqCSWFR4gxEGXIGFHobEIkMKVBKLgh6Hn35ngP/60z5OD3gWejgSiwwpUEksCvyhKG+4ewftIz5GvEFcgfCk50SiscTPL7eOzOXwJBYYKVBJLAqWFxu4bWs1Q+4gTx4f5LofPEcgHM147IgnyMf/eoA/vNzBvs5Rfvzkab7/+Kl5HrHEfDKvLjQSErl407ZqlHKBt22vZW/HKD968jTvuriOQoM65bioKNLr9COTCXzv8VPc+4HtfOiqFQs0aon5QJpRSSwazFol77lkGSqFjO31BZi1SkQRfvlcK112HwD9zgDvvmcP7kCElSVGbmuuYlWpaYFHLjHXSDMqiUXLey9ZhkwmcKDLwXOnh/juazfykb/s5ydvasSmV2FQKwhHxYUepsQ8IM2oJBYcpy/MPS+24fSHCUaixGLx4COTCRzrdTHqC/GZV6xiwBXgt+9qpqZAj1GjRBAEVArpT/h8QJpRSSw433viJL/b0cFPnm4hEI7y9w9sTyznWoY87GkfpaZAh1GjBEAURQRBWMghS8wz0teRxLxzot/FX3d38rfdXXTZfVy/rgy1QsawJ0ihQZWSc7ppYzm3NVfxzMkhAHa323nD3S9zZtC9UMOXWACkGZXEvPK9x0/y46fOJB4b1Aref9kyvn7rOmIiFBvVaed89eZ1iZ+31tqoK9BzvM+NKMKKEuO8jFtiYZFmVBLzRveoj58+fSblOU8wwp2Pn+KXz7Xxui2VXL6yOOv50ZjI1x86xqZqCx/6834eOtw310OWWCRIMyqJecMXihLLskl3csDNm3+1kx+/sZECQ/qsCiAmirxyfRnrKswMuoJcvKJgDkcrsZiQApXEvKGUZ5/AW3RKqm06chUbKOUyGqutAHzkaqnA83xCWvpJzBtPHh9I/Hzb1qqU1z513Uq+9ZoNaVXoEhIgzagk5pEhTxCAVaVGPnHtSl5sGabL7uf9l9XzpuZqvvXICdQKGSqFjIuWF7K+woxcJpUhSEiBSmIeuayhiLuebaV71M+RHidddj8Av3i2hXv3dDHiDSWO/eGTp/nhGzbxx52dbK628PFrVy7UsCUWAdLST2LeuLC+kA9ftYL/vmE1B7sdKa+NB6mbN5UDEIrE+MAf91Fp1VJp1XHBN57khdPD8z1kiUWCNKOSmDe67D7edVEtFp2KR5JKCyosWt5+YQ0X1heyrsKM0x9OFHgCnB500+8KEIxkln2ROPcRRHH+mjqbmprEPXv2zNv9JBYPH//rAe7b30O5WcP/u62RrbVW9nc5KNCrUCvklJo1iWOP97m45acvEozEhfHeekEN77iolvoiw0INX2KeEARhryiKTWnPS4FKYq5pGfJw1feeTXnuPRfX8YUb12Q9Z9Ad4P79vRzvc/HN16xHrZDP9TAlFgFSoJJYMGIxkWFvkFf9+EX6k4wbfveuZi5tKFrAkUksNrIFKimZLjHnyGQCxUYNr1hXmvL8i2eGSf6i9AQj3H+ghx88cYo/7exM0USXOL+RApXEvPE/N67hylXxXr4Ki5YKq5aWIU8iWLUNeWkZ8vLjp06zo3VEknKRSCAFKol5QyYTeM/FdUDczOGhQ33cu7c7EZDWV5oJhuP9gO+4sEYq9pRIIJUnSMwr2+sLOPW16wGQy4S0YLSpygLk7guUOP+QApXEvBKXD84+U7pgWQGbqiw4/ZP7+kmcP0iBSmJRYdWr+OcdF0r5KYkUpPm1xKJDClISE5EClcS8cLDLwS+fa008FkWRaDYVPQmJCUhLP4l54b593Tx4qA93IMzBbie72uwUGFR84YbVWHUqTg24qS8ycOHywoUeqsQiRApU5xDdoz5+8WwL68rNrK80s7LEiGIed8+cvjCPHu3jeJ8bjVLOp65biVwmEInG+Oz1q3EHI/woydihe9TP+/+wL/H4NZsrpUAlkREpUJ1DPHqknz+83Jl4XF+k5973X8iBrlGuWFk8o9xPJBrD4Q9nVOAURZG/7+3mqw8cwx2MJJ7vdfjpHvVxrM/F9evK6HX4c97jHRfWTnt8Euc2UqA6h+gY8aU8bhny8sKZYb76wFFu2ljOp69bhVYlZ8gd5MdPnaamQM/Nm8pzyv8GwlFkgsDf9nTx7wO9vOviWkrNWiqtWvqdAU4Puvnb7m52tI6knfvvg72Jn/+5vyfn2JtqrKwtN+U8RuL8RQpU5xAtQ5605545MciwJ8RvXmzn0SP9PPWJy3nwUC+/29EBwA+eOMXXb13HzZsqEEWRE/1uVhQb2NsxyqA7yGf/cYhwLJ74jsZEdrXbZ33cOpWcL9y4BplUiS6RBSlQnQP0OPx899ETvNSSPqvZ3+VI/Ly82IBKIeORI/2J5zzBCE8eH2RjpYWP/vUAB7ocXLS8gPZhHz2TLNVmi6/dsi5RkS4hkQkpUJ0DfP6+wzx7aijja23DXgA2V1u483UbufmnL3Ckx5V4XauU88bmat5w9w4GXHHzhRfPpAe8uWRrrW1e7yex9JDqqM4BbthQhmKSZdMdly/n24+eSAlSADduKOP+Az2JILUQ3Pn4SX7zYtuC3V9i8SMFqnOA122p5OPXNqBXZVbBXF5s4OHDfdy3Lz2hHY7G+MvurrkeYk7uP9DL40cHJj9Q4rxFWvqdA/xpVyffefRkVlmUM4MezgymJ9oB/nWgN+Pz8837L69f6CFILGKkGdUS55fPtWJQK/jCDauXbEuKXiVnQ4V5oYchsYiRZlRLmFAkxi+fb2XEG+KV68swa5VLUh7lA5fXY9WrFnoYEosYKVAtYQZcAYY9QWIiPHBwcSzhpsqqUiPvuWTZQg9DYpEjLf2WMA5fmCW62gPihZ4/edNmNErJCksiN1KgWsKsrzRzy5gF+lJDq5Tzy7c1sbxYMhWVmBxp6bfE+dqt6znY7UwUdi52GkoMvGJdGW/ZVk2xSTP5CRISSIFqyfDSmWFqCvVUWLREYyI7W0cot2j52TNnePfFdRzocrCh0owowq9eaKXLPj/tL/lSW6Dje6/fyJYaqQpdYupIgWqJ8PTJQf7w207e2FzN7nY7h3ucyASIifC3Pd3Y9CqeOjHIJSsKGfUurp2/FcUG/vTeCygyZldpkJDIhRSolggfu6aB/xwf5NdJrSbJiXS7NwTEq7zVisWVevz4NQ1SkJKYEYvrL1oiKzqVgl+/Y2texwYji8cKvbnOxrVrSyc/UEIiB1KgWkLU2HS8bXvNQg8jb5rrbPzf25skx2OJGSMt/ZYQMpnAR65agVYl565nWyc/YQF5/2X1fPLahnnVbJc4d5EC1RJDJgj89qX2hR5GVsxaJd9//UauWl2y0EOROIeQvu6WAI8e6aPLHtdDt+iUKGSL85+tsdrCwx+5RApSErNOXjMqQRDaATcQBSKiKDYJgrAJ+AWgASLAHaIo7pqjcZ7X3PNSO6FIjFsbK/CGonhDkclPmkc0ShnvvKiOj13dgGqR7ThKnBtMZel3hSiKw0mPvwN8RRTFRwRBeOXY48tnc3AScd53aT3vvGc3+zodCz2UNF67pZLPXb+KghxONhISM2UmX38iMO5vZAaWZvv+EmBZkZ6737qFQsPikkIxaRR849b1UpCSmHPynVGJwOOCIIjAXaIo3g18FHhMEIQ7iQe8C+dmiBI1BXpqCvQUGNS893d7EsWdC4lcJnD7pcukpZ7EvCCI4uQ6IYIgVIii2CMIQjHwBPAh4LXAs6Io/kMQhNcDt4uieHWGc28Hbgeorq7e0tHRMatv4HzjSI+THz55miePDyyIxItKLuNDVy7nnRfXYVBLm8YSs4sgCHtFUWxKez6fQDXhQl8GPMAXAYsoiqIQ9wp3iqKY0+q2qalJ3LNnz5TuJxFHFMUUS/Z+Z4BLv/M0oejcV6FrlDK+dNNa/r63m6+8ai3rJNlgiTkiW6CadN4uCIJeEATj+M/AtcAR4jmpy8YOuxI4PXvDPX9xB8I4fOlLux8+eZov//to4vGgO4BCPj8V34FwjF+/0Ea1TSfZrkssCPkkGEqAFwRBOAjsAh4SRfFR4L3A98ae/wZjyzuJmfH5fx7hyu89y717zlpY/Wt/D2atEk8wwkf+sp/X/eIljva6+PR1Kyf188uXUpMmZ+Pw6UEP/9zfk9E2XkJirpk0UImi2CqK4sax/9aKovj1sedfEEVxy9jz20RR3Dv3wz038QYjeIPx2qhjvU7s3hDH+uJGoaIo8vWHj/OVB45RbFRz04ZyDvc4+dx9h9ndPsqP39hIwSwYI/S7Arzrojq0Y7LAEz0CrTolG6ssLC82zvheEhJTZco5qpkg5ajSeeBgL5/420FERH7whk1oFHL+68/7CIRjvGZzJStLDXzj4ROJ47fV2bhxQxl3PddK96gftULGey9Zxk+ePjPjsVh0Su64vJ71FRY6RrzUFOj5z/EBPIEIX791Ha5ABNuEoHj/gR6KjGourC+c8f0lJLLlqKRtmwXmnpfaEwnxLrufD1xez0evbuBbj5zgH/u6047f2WZnZ5s98TgYifHAodkpYXP4wilBscys4c3bqikxxZeEo74Qn/77Id60rYorV5VwoMvB5+87zF9u3z4r95eQyIYUqBaY5BnKuJvxVIXvOkZ8szqmcfqcAe58/BQAP3+mhUA4hj8cBWB/p4NfPd/GR69ewfpKaRdQYm6RAtUCY9OdDVTPnBzkSI+TR4/0L+CIMjPqOytv/J/jA/zn+AC3NlZw+6WSJ5/E3CMFqgXGHTwbAEa8Id79290MuYMLOKL82Fhl4ZuvXp9S2yUhMVdI/Q8LzJu31fD27TUsK9QDMOAKLkpT0U1VlsTuYoVFy91v3SIZh0rMG9KMaoG5aHkhDSVGPn7NSl5310ucGlhcdUqCAP/9ytW8++I67nz8JH/e1cU/77gwb0++504NcWbQw/0HelDIZehUcuqLDHzkqhVYZ6GsIh8i0RhRUUQll0kzwCWKFKhmkS//+ygbq8zc2liZ9zn7Okd5w107uGh5IYHw4jBlEASotunYVGXh1sYKLl9ZjCiKlJo0/Om926ZkHPrlfx+ldYI56vOnh7n/QA/vuqiO69eXpbgl+0IRvvPoSf6+t5toTGRzjYV9HQ5etbGcUrOGTruPzdUWLl9ZTJFRTTQmoh/rOQxFYgy6A/z06TO8qbmG9ZVmnjw+wGf+cYhhTwhBgBvWl3Hn6zaikAmSTPISQgpUs8TeDju/29GOuCPuGHNdns4r/z7QSzgq8szJoTkeYX5csqKQX76tif97oY1jvS6sOhU9Dj+fv+8wMVHkrdtrs54riiK9zgCj3hCRMZPUiUFqnFFfmO89cYrvPXGK5cUGLqovICbCk8cH6HUGEseFoyL+cJS/JlXq/3N/D3CU1WUmTg+42bbMRrFRw0stw4giDLqD/HlXFxUWLT2Os0asoggPHupjV5udNzZX87FrGmb8+5KYH6RANQs8eKiXD/15P+O1s/9z/xE2V1vz8rLTqeToVXK8oegcj3JyttZa+cS1K/nQn/fzxLEBAB463AdAkVHNP+/IruRzZtDNx/92EKc/zAcuq+ez9x3O+75nBj2J0oypcHysev/FMyMZX08OUskMuoP88MnTVNt0vGZL/rNfiYVDmvvOAhsrLSQX+A+4gtz44+fz+vB9+hWr+OmbN8/h6PLjsoYivnTTWt7xm12JIDVOhUXLgx+6mEqrLu28WEzkNy+08s579nCo20nHiG9KQWoy5nIH9FN/P7goS0Ek0pEC1RT5rz/tS2vMLTVruHZNqqHBgCvIZ/5xKK9rXtZQxJqyhVMlKNCr+OrNa/nMPw7h8KXbwX/+lavRqeScGfTwxLEBHj/az77OUXa12Xn7b3bxlQePU27OP281FdqGvWyqsszJtWMi/OLZljm5tsTsIi39psigO8h7f7uHpz55eeI5pVzGlhorj0+YiZzsd6ed/8DBXm7aWA7AP/Z285fdnfzszVv46/su4FU/eZG2LDmduSQqilz1vWeJTKiLKDdr+PwNq9laa+WpE4N89K8HyNYaerDLgVYpT1SuzyYtg26WFxumtTyc9NpDnjStL4nFhzSjmgK+UIS6Aj3tI15++J/T+JLcYJL778bxBCOEkuzVvcEIvUl5k3/s62Z3e3zXr8vu5ws3rOb+D17E4S9fy/0fvIjagvSl1lzg8IVTglSRUc3Nm8r59ms3cOOGcnRqBQe6HChz2HQFIzEisbnZtXQHozh8oTRFh1m5diDC86eHJz9QYkGRZlR5Eo2J6FQKvv3aDTSUGvnfB49x/4Ee/vTeCwhHY7zzolpebh3BNyEpbveGKB1bFonAmiThuX5XfHerddjLDT9+nm/eup6fPdPC3o5RtEr5nH3wJ2PIHWTYE+SSFUW0Dnn4ygPHePZU7l1JkXi1+p720VkZQ5lZQ7lFiyiKtA/7GPaEaKyysL/LMSvXT6bTPje9khKzhzSjyoMdLSPc8tMXCUai3PnYSf7wclz3vXXYy4XfepL/e6GNOx8/xeeuX5V27vhyxR0I87fdXVw0JodypMdJ69DZZZ4owmfvO8zejvgH3R+OEo4uXIn6K9aWsqNlhFf//KVJg9Q4Ln96fms6NNVaGfGG2Nsxyr5OB85AmLpCPYd6nLNy/YnEG64XftdVIjvSjCoPOu1eDvc4+d7jp7hpQzk/feas9lNMhN/taCcmglGtQCETUpZRA2OzpkhUjBc5XlwHxIsqFzNfvP/o5AdNYKqqD5lorrOxa8IyOhoT5zR3F42J+EJRqSVoESMFqkk43ufimZNDCAL85sU2rDpVWkJ5PC69cCY911FpjS9fPv63A2xPEpdbXWri2jUlPHlikOhibO6bBuPWWVqlnDXlJmRCfKa4pyP/5WCmDYi55q3ba9IEASUWF9LSbxKqbTr84SiiGK+S/vajJyY/aQxBgFVlJhy+ME+fHKKpxpp4TSYT+MrNa4lNorBabZufhPpMMajluAMRmmqsFBlV7O0YZXf7KHs6Rmmus1Jh1U56DbVCwDlLy8d8ecXaUu64vH5e7ykxdaRANQl6tYK739qEakJf2DsvqqXKpkWew1xhbbmJP+3sxD7mKlMyoUfOolVhTPLGk8sEfvzGRpRj7jKN1RbueuuW2Xorc4pWqSAQjrKnY5ROe2pF+K62UUyaySfvwYg4K/rvU+Hj1zZIpQlLAClQ5YFKIeOC+oLE4w2VZr54wxr++O4LKMtR6Hikx4VaIUsUUY63fIwjCKQ0In/xhtWsLDWikMko0Kv42i3r+NI0ckULwZAnmBagkrF78nN3Xlakn60hTcqnX7GSFUkN0RKLFylQ5ckPXr+RN2+rxqZXcWbQE1cYKNBx+6XLaK61ZT1PEEjMJv68uzPlNY1Szmu2VLKlxspnr1/FTRvLKTNr+MN7tnFpQxG33fUyu9rT67OWGgoZmLTKvI7d1zHKLDmAZUUpF/jhbZu44/Ll0mxqiSC50EyRSDRG16ifujGhu1FviD/t6mTIHeQPL3ekVXcr5QJPfvxyvvPYCd5xUS0rS4wYNekf2vZhL7fd/TJymUC/K5BIsGuUskUj/zJdttXZMhbEZmOu3/OP3tjIq8a6AyQWF9N2SpZIRSGXJYJULCbyqp++wHcfO8mDh/oyyoZcv66MP+zs4NbGCu7f38vWr/+Hw93p9UB3P99KvytAj8OfCFLFRjXffs2GlDzWUmNztWVKQWpFiWFOg9SWGqsUpJYgS/cTsAiQyQRu2lDOz55pYdgT5LuPnUw75t8Heyk0qLDqVKwsNfLJa1diTloGRWMiHSNe1pQZ+dar18ftrw72snXMv+9VP3lxSZcvHOlxsr7CzOEcxZoWnTKRx5u4aTHbvKm5ek6vLzE3SIFqhtxxxXKeODbA6RwNs8OeUKKsocqmZcgd5H2X1bO/c5TvP3GKo70urlhZRKFBzX/fsJohd5CnTw7SXGfj2jUlPLKEpUhCUTGxizmRKpsWs0bJkV4XFVYtaoWMo72ujMfOBiaNghs2lM3Z9SXmDilHNQv0Of08f2qY/33oGO5AJOMxSrmQaIlRyARqCnS0DKVWW68tN9FcZ+M3L7YD8VzNd1+7kdODHn705Ok5fQ9zSVOtNa0H0KJTIhcERrz57QZOhTVlJnQqOTKZwK42O5urLSjlMprrbHzi2pWzfj+J2UNySp5DysxaEMgapAAaq+PFnrva7ERiYlqQAjCoFSmqoIFwjA/9eT+Kud4Gm2NaM8w2q6y6nMvBmeAPRzk2VgpSZdWyr9MBwCevk4LUUkVKps8Sr26s4Gdv3szPk9Q6P3zVCj79iviHo2XQw0euWpF4zahJDUrFRjUfvXoFv3yuNe3aE3cSlxq1hWdro4waBU211jkLUhD/XY7TNRqv7dKr5HMmwCcx90gzqllCIZdx5apifvb0Ge566xaaa21Y9aqEq8pbLqihuc7G85++gp1tdv66u5Pd7aOUmzW899Jl3LihnJ89cybFkXips7XWStuwNzGjUchAgFmTgsnG6YH0fsH1lWaUkuvMkkUKVLOIRinn4xNyIDqVghXFBt5yQQ1KuYwnjw/w5QeOJV7fUGnhnRfFFRXevr0Wg1rB40cHOJnhw7ZUEIirIEwsS1DKZXOiAJrM8mI9BXp12r0FBEnJcwkjBap54OGPXIJSLmPEE+TOx08lnq+0annfZcsA+NXzrRztdXG4x8mXb1rLPS+1MegOsq7CjCjCv/b3zPmHfDaoL9Jj0igz1k75wzE2VZk50DU3y75414CXM6Tm/woNKlqG4k43K0qMc3JviblFClTzwPiS47GjA3iC8YR7qUnDgx+6GItOxQMHe/naQ8cTx7/l/3ayqcqCTiXnaI+TgxkKRBcbAtBUY2XQE8yowqlTyii3aOdUHcETCGPUKDBplFRYtQTDUbpH/Qx7QlyzulgKUksYKVBNg5YhDw8c7OWV68toSPrjz7W0iMZE/jZmoimXCfz4TY1YdCp6HX4+9feDaccfmAPJ3blkc7WV3WO6UzKBlN+DKIr4wjHOZNjpnE1CUZFQNII7EEnx9DOqFXz1lnVzem+JuUXKLk4RURQ53O3EplclZkqBcJSP/GU/a7/0GF978FhGWVt3IMyBLgdymcBXXrWWrWONzCatkldtLOe6tSUpFetLDV/4bGlGTIwH5vH/FnrT8r9vWB0vIZFYskgzqikiCAK3NFYkHkeisRRn4V+90MalDUVc2lCUcp5Fp+KRj1xCuVmLWXc2IJ3sdyOXCdx+aT3RGPzneKrl1lIhkx/gYmD7sgLesLVqoYchMUOkQDVD+l0BTk3YoXvgYG9aoAJYPcFkdG+Hndf9YgcxEV5utfONW9cjCHFbLotOxdMnBtNcbRYri3Xr/5PXrZR2+s4BFudf1xKi0qrj3vdv57KkwLS1Lrs+VTL37etJLIvahr188t6DGDUKAuEYjxzuWzJBal25ia7RmVlOyQVYX2GiscrCxkozTTVWlhXpWVc+fQfpZYV6tiTJP0ssXaQZ1SxQbNTwpZvW8IE/7GNtuYlbNlVMfhLwcutIyuMeh5/79vXMxRBnlQqLhh5HIPHYG4pmdVDOlzXlmRUWlHKBapuOEpOa3VMsFF1ZKu3ynStIgWqWWFZk4LGPXZr38bvb7Rn7/RY7cgFGvCGaaqzIZALeYASFXGBbnQ2nP4xZq0QERjzBrO9vc7UFVyDMmcH460aNImtLTTgq0mn3MewJsrHSPKVSjb1TcL+RWNxIgWoBcAXC9Dr8lJo0lFs0REU4uAjLEbbWxpdN3mAUtVIW9yyMiuzvckxqgdVcZ0sLVHIBVpQYGfaE6LT7WF5soECvIhIV2duZ+3q+ULzR2KZTYs8zcX/JivQ8ocTSRApUC4BJo2T7sgKe/8wVKGQCX/r3UTpGvKwqNfJy6+LRSHf6w5wayK6zlYvjvS5KTGqKjRp0KjlqhYw+Z4ATSb59ZwY9nMlxjYmEoyLLS4xpBqXZeM8ldVMctcRiRQpUC0TxmHVWMBKlxKThbdtrefhw3wKPClRygVWlJqKiOCMRO3cwgjsYYcAVBGBliTGnuGC+uPyT61fJBPj8K1en7bJKLF2kQLWAfPvREzxyuI/uUf+CS7mML8sADs2BBEv7iBeDSo5nhjuZKsXktusfvbqB91yybEb3kVhcSOUJC8iqUiMOf3jaQUouE7hyVfG0719t06JVxv8ENlZZONHvTlmazSbBSIw1FeYZX8cfipKrKqqhxMAHJOfjcw4pUM0jw54gP336DO5AmBfPDNM9Gk+oZ9MUn4zPXb+K1qHpLacMajmeYIT6YgPb6mwJzai5JBqbubvM6UEPW2qslJnVaf5/V68u4bfval60xacS00da+s0RsZjIUycG6XH4GXAF6HcFePbkECPeEA8c7OWOK5bzx5c76HUGJr9YBr5+6zru3dNN+8j0Ci1XlZrY0zGK3Tt/rS+ztbwd33GssGhxB8O4/BE+84pV0kzqHEYKVHNAJBrj58+08L0nTmV8/US/mw//ef+0r19oUPH0iaEZKSy0j8x/DVfrkBeFDCKzZNvX4/Bj0ijYVmfj/ZdJOalzGWmOPAf4wlF+8J/MQWoiJo2Cd11Ux2s2V+Zl4nDR8gJ+dFsjGyvNWHVKBIF4q0mFiZoCXV733FBpZtgz++4vk+EORNhSk197Ub64AhFKTBqpn+8cR5pRTZNYTORPuzoTMi3JmDRKvnHren7zYjt3XFFPXaGel1tHGHAFMWoU/PtgL6PeEK9vqkKlkPGr59soMal56/Yaeh1+ZILAvs7RxNb+OB++agUfvnI5cpnAmSEPH7xiOWqFjF8820prnlXuJq0CtWLhvp92t9tZUWyYlVKFcZpqpX6+cx3J128anOh38aX7j7Kzzc79H7yIjTncTQLhKBplfEtdFEWc/jDC2L7V2369M++WkEtWFPKbd2zli/cf4eHD/TmVMusKdXiDUQbdwXg1eUzEqFFg0SnpcwQWvBTCqFGwqtRIJCpysNsxI72qhhIDj3zkUuRL3FJMIo7k6zdLdNl9vPbnO/AEI1zWUJQ1SD16pJ9vPXKc9hEfl6wo5Puv38RvXmzjZ8+0AHBhfUEigE3Gd1+7gVsaK1DIZVi0SlYUG/CHo4x4QvS7zibjm+tseIMRjva6kAvxZHOvw8/KEiNmnQIQ0CjldI74CM5WomgauAORRIPx1lrrlJuNkyk2aqQgdR4gBaopIIoin//nYTzBCB+4vJ5PTXCcCUVitA572Nsxyu93dCR25J4/PczXHjrGNWtKUCtkBCMxXmoZyXSLFBQygf+5aQ2v3VKJIAjc+dhJfv7sWd8/AdhWZ8MVCGNQK1JaS6IiCTneZEebQoOKAr1q2ruNs83xPjdba60c6nYQjEx9arW+cua1WRKLHylQ5cmQO8hPnjrN86eHefO2aj5xTQOyCd/k7kCYt/xqF8OeYNr59x/opcqq4x8fuJD3/X5viqZ3Nj52TQNv214LwJ52Oz95OrUzToSMbi+5GPaEMGsVGNUK3MHszs7zhScYIRIVUcpkBJla1XqhQcUHr1g+RyOTWExIu355Eo7G2Fxj5R8f2M7Xb12PIkNRoU6lYH1F9v6yP+7sYHmxgQc/dDGXrChMPL8tg9DeJSsKef9lZ+uC7kpyUDZpUr9ftEo5qjyLHBtKDCwvNlJhXRwa4ssK9Rzsdky5teaCZTb+9cGLMKil79rzAelfOQetQx4ePtyHPxzlU9et4uZJBPGO9Do5lCM5PuoL8/DhPl69uZJ73tnMf44PMOQOsqc9dVa0qtTIz968OZF7GXQHaBv2cllDEY3VFu7d040rcHY2tKbclJf2UnOdLafywPJiA23DXqLzmGy36VW0Dk+tputDVy7nY1enz2glzl2kQDWBLruPUwNuHjjYy78O9LKpysKF9QV5nbu11sbOz19F59g1fvl8W1oA+dkzLTx9cgiAi5cXUG3TccGyAtQKOffu7WJLjZWfvnkzRs1ZA4jP33eYyxuKsPtC/L//nE65nlGjoD/PfNOuNjsrS42cHOvnW1lqJBSJUWhQ4Q1GONbnprnWxq6xwCmXCZi1Suzeuau5GnCnj72uUI9NH3//h7udhKJnA+eVq4r50JUrpCB1niEFqiQOdzu56ScvJB5XWLTc886tWHSqvK+hkMs41ufi2ZND/Pi2Rq76/rPERJE3batmyB3kwUN9nBmrIXrgYC8AP7xtEx+5egWvWFfKxSsKU3rVWoY81BXq+b8X2tK28W16FdetLeHPu7ryGtuyQj0n+92sLTehVsjoHvUz6A7SljSj6XP60ShlrC030+vwMeQOUleoTzlmNik1aeiy+9lYZcY+tovZNuylbTj++sYqMwfHnJW/89oNvL5JcpQ5H5ECVRKry4wYNQrcgQhfvHEN77qodloVz1qlHFcgzEutI/z+3c2srzSjkMn42F8PZDz+I385gFWn5D8fvyytodbhC/PpV6zicI+T+iIDLUMeDnY5CUVjvHlbNXcl7QJOxpAnyKXLC3nuzHDWY7pG/SjlQspMsMionrNAtbt9lJoCHQaVgoOj8YCkkAlUWrXUFOhprLLwqo0V9Iz6eXVjflr0EuceUsHnBM4MevjdjnbeeVEddYX6GV/v4cN9HOx28PDhPrrsuXf6Ll9ZxE/etDklQez0hfndjnZahjzYfWGKDGourC8gKop859GTGXcYMzGdeqWmGit2XyjvqvfpYtIoeM8ldWyqslJboEcug4/97SAbKsy85YIaamfh30FiaSAVfObJ8mIDX715duy/ozGRrz5wLKUoMxOCADJBoMysRTtWBBoIR4nGRD573yEeOdKfcvw/9nXnPQaFTKCx2jKtBma5TJjzINVQYuDX79hKpVVHLCbyyJF+vv/ESVqGvOxqs/O7HR0c/sq1qPMQzJM4d5EC1RzhD0X56oOTBymIJ4/feWEtu9tHkcsEukd93Pqzl7htaxVPnhic0Ti21FinXGs1X6wqNfLH92zDrFXyr/09/OTpM4n83TiCQKLlSOL8RQpUc8SxPhd/3tUJxBUPrl5dwtceOp629a9TyblkeSF9zgA/emMjAIUGNU987FKu+t6zhGbQ6mLWKjnePz3d8w0V5hmbiuZifYWZb79mPQ8c7OWel9qz6mq9sbka1QI2UUssDqS/gFmk1+FPJJ231Fj5+/u3853XbGBDpYVvPnwiEaRUChnffPV6io1qfKEof9ndxbIiQ+I6GqWcA10OXr25gtduqZz2eDzBCKtLTaimoSCqVMjodcx+m02lVcu1q0viRq0/fYkvP3Asp/jfP/Z2410EFfQSC4s0o5oluuw+rvzeM8hlAr971zbufq6VHoef431nZzRymcCrNpZzS2MFRQY1Q54gzbU2vvWa9YlA1ef0M+oNc8cf983Y0j0aE9nZZmdDpRmVXEYoEuP0oBt/ePJZ2pA7kFBemE26R/04vCEiokgoOvk43MEIl9/5DNetLcGqU3FZQxFNtbOraSWx+JF2/WaJAVeA7d98kpgY38UarxxXygX0agXrK8x8/Zb1VCeJ2416Q1j1qTVa7/zNLhqrrXw/izroTLDpVXiD4bybfzdWmrF7Q3SNTt6XOBU2VcadkqdakQ5xK6z/uXENb79weqUjEosbaddvjikxafjc9av51qMnaCgx8urN8SXb1lor5RYtSrksLdcyMUgBXLyiiJGxkgNBgOl8j4zXgk1EJsRNPPNlXCtra60VUYST/e4ZNTIbVHLWVJg53ufKOL58iInw5QeOUWhUc+OG8slPkDgnkALVLPLeS5dx48YyFDIZRUb1tK7h9IdRyWX88T3b8AYj3P77vVM6f2utFZtexWNHB9JeW1aon5YEcXL91ZYaC4d7XNNK8q8oMeTtcpyLNzZX88p1ZTO+jsTSQUqmzzJlZu20g9SgO8DjR/v56DUNvNQyPKUg9f7L6rnzdRtRK+QZgxQwK0ulvR0OTBoF68qn7kJ8ZtBDc62NlaXGad9/U5WFr968Vur1O8+QZlSLBFEU8QYjXL6yGFEUOdKTf1lBhUVLlU3LJ+89mPH1UpOGfleA2cpGDntCeIMRVpUaaRv2sqnKQp8zQKc9dzmDOxhlV7udkhyBXCbAm7ZVo1crePzoQGIX9R0X1vKeS+qosGil3NR5iBSoFgGRaIyP/vUA25YV8P7LlvHimRH6nH42Vprz0lR/XVMlP5iQfFcp4rt8WqWcd19cx9cfPj6r2/z+cIwT/W7WlhvZ2WanyqalqcbKsCeIyx9meYmBXW3pLTsCUGxSM+BOb/1RyAQ+/8rVvOviOgA+de1Knjk5RKlZw7pZcFmWWLpIS79FwLAnxPb6Al63pRKLTsVjR/v56Zs2T1rVrlPJ+erNa7HqVCm5p3Kzhm/euh6AmzeVc/fz8cbl430uigzTW5ZmQq+SJyRjuux+9nSM4vSHWVZk4HCGALuh0symKkvGsgutUs5f33dBIkhBXIni6jUlUpCSkGZUi4EnTwzw1QeOce2aUjRKOR+6cjm/eqEtzS4rme3LCvjKzWt5/Gg/P5igUdXrDBCIRNEoZQx7QgyNzV5iYtwDcCjPRubJWFthTkuOmzQKnP4w1TY9cpmATAYquQylXEaX3ZdRq12nkvOzN2+edc8/iXMHKVDNEb5QhK8/dJxr1pRw+crirMfd82IbX37gGGqFLFG5XmzSEMlRRrCsSM/tly3jNT97KWu5wJA7yAcuW55mhNoxSR5pKkSiMa5dU8Ljx84m7/VqBcf63DnOSsWsVfLspy6fkuaXxPmHtPSbA2Ixkdt/t5e9HaNcvLww63G/eLaFLz9wDIAv3LiGUrMGgJ2tI4x4M896ZAJ8+zUb+MZDx3PWNIWjMSKx9BKCfmeAVTPYdUtmX6eDHoefmzeVs7zYQF2hjhP9+QcpiGufS0FKYjLymlEJgtAOuIEoEBmvHBUE4UPAB8eef0gUxU/P0TiXFC+3jfDCmWG+evPajCYQZwY9/Pip09x/IK7wefHyQt56QQ0QV134738dSVMRGOcDl9dzqNs5qdNwmVlLvzPAyhJjil0WxJ2cS80aKixa7N7QjETxjva6GPGEeMv2an72dEveZqJmrRKTVsFtzdU5jzve52JvxygWnRKzVolFq6K+WI9OJS0Gziem8q99hSiKCWlIQRCuAG4GNoqiGBQEIfv65jzjkcP9FBnVrM1Qa9Tj8POGu3YwkqRD/tbtNYmfv/Hw8TSXmXG+eOMaXrWxnCvvfGbSMWyoNPOr51vZWmtLC1Qg0u8M0O8MIBPiAnl78jCHGKfUpKbcokUhlxGLiQy6g3gDUfb899UMe0LI5QKDrgDPnhri6ZNDHOp2JCrsKyxavnjjGq5bWzJpmcGxXhdvuHtHWhV7fZGeBz50sRSsziNm8i/9AeBboigGAURRnJlw0jnE/96yjv+9JV18TxRFPvuPQylBqsqm5apV8Rj/cusIQ+4g77usnveNFXsKAly9uoQXTg9z7ZoSvvXIiZQln1wmZHSN8QQjeENRep1+agt0qQoFSQFiQ6UlLUg119oQBIjEROQyAV8wgi8cpcigxh2IcKzPRf+ERP/Pn23hXwd6+MmbGjk14EEll3Hb1mo+enUDI54gJ/rd6FRy1leYM84yM/HEsYGMrTYtQ15++ORpPnf9akKRmCQDcx6Qb6ASgccFQRCBu0RRvBtoAC4RBOHrQAD4pCiKuyeeKAjC7cDtANXVuaf55zotQx6eP52qV/6RqxpQyGWIoshdz7bwsWsa+PjfzhZuGlQKfvm2JqIxkd3t9jR1z+vWlrC3YzSxQ6iQCVy+sohQJMaF9QX8+2AvL37mSh442Ms3HzmRNqbDPc4U55lxxsX2lHIh0R/YPuxlVakJrVKWUYGhzxngNT/fQYVFg0Wn4q97OnH4wty0sZzlRQbs3hAyQWBjlWXS39U/93enbQQk89iRfna32QlHRb7/+o2sKJmdvJvE4iTfQHWxKIo9Y8u7JwRBODF2rg24ANgK/E0QhGXiBDmGsaB2N8TVE2Zv6EuPCouOD1+5HJ1awU+fOkOxSc2tY4YFQ54ga8vNPHqkPyU/Nd64LJcJ1BakaoebtUoePdLPN25dz+f+eRhRjM+ChjwhLl9ZzGUNRXz/9ZuQywTed1k9A64gv36xLeUa0ZjIrnY7m6st6NWKMVmas/9M4aiIUS3HHYwSE+OCgI3VFvZ3OjK+xwK9iqgYz12N8+TxQb73eDzoaJVyNlaZKdCrseqV2HQqLl5RRPOYCWswEuXfB3r58r+P5vxdto/4ErPEa37wHJc1FPH/3rApY6O3xNInr0AlimLP2P8HBUH4J9AMdAP3jQWmXYIgxIBCYGiuBrvUEEWRAVeQUrOGSDTGD588zUOHexMmD9+6ZkPCZLRjxIdMJvDzp1tSrjHoDvDk8QGuWl2COxBOPK9Vynnb9hp+/NQZ+pwBVhQbODUQD3AquUAkGuN7T5zi3j3drK8w8Y6L6njXxbVsrrGwt32UnlF/iq38vk4HK0uMjPrC7JpgAqFWyhNJcm8oyv5OR3yHUhRTloBFBjUyGTl9Bv3hKC+3ps7efvNiO/91xXJODXp49tRQ3oYVyTx7aohP/v0gb9tey6UrCqU2m3OMSQOVIAh6QCaKonvs52uBrwIe4ArgaUEQGgAVkN2H6Tyjc8THnY+fxOEP86PbNvHRvx7gmZNnY3htgY7r15UmHm+ptvLFfx0BUh2NA+EYf9vTxVWrS1LaaRqrzWyrs9G5sZyHD/exstSYCFRfftVaHjnSz8+fiQe9p0/Gk9pymUB9kZ6aAj03bCjDqlPx/OkhXmoZAeJtN9GYiEEtxxM8Wz0+7AlRoFel5Nb8oSg1Nl0iUDXXWtMC3DjySRqI3cEIDx/pY9QXnlaQgniSfk+7nSePD2LTq1hbbmJNmYk15SZesa5UModY4uQzoyoB/jn2DaUA/iSK4qOCIKiAXwuCcAQIAW+fuOw73wiEo2iUcjpHfLzznl20DHlprLbwwMHelCAFcMOGshQFAEEAtULGJ65t4DuPnkw59lC3E18oQoVFi0yIV5h/7vo13PzTF9hcY+XLN62hc9TPg4f6KDKqWVNm4t9j5qbJRGMipwY8GDVKnkgq0txSY+FQtxOrTsm2OhunBtxsrjbS6wggCCKhiEggnNr24vSHOdTj5OLlhTj96bOwZHodfjZUmjPa3csFKDCoGXQHcQfCbKqanmOOUSNPzBDt3hDPnx5O5AN//Y4mrlxVMuVrSiweJg1Uoii2AhszPB8C3jIXg1pqBCNRHjzYx54OO69cX8Z7fruH4Jhe06AriH/Ch/zN26r55LUrU54TBIF/ffAi7vjjvrTr97sCeIIRttcXcPnKYp46MUiH3culDUU8c3KIrz18gr+/fzsHuxxsry9AEAQMKgUbKs3IBOh1BBhMagJ2+lI1qfZ2xJd9oWgskUQfHctBrS03EYrG6Mqia94x4qXcomVztYXDPc6Mwnx9zgCmJIt6AKNazvJiI0d6nSljO9DlYGutlcM9TgJ5SCaPY1Ars772X3/az49ua+TqNVKwWqpI+7ozpHvUxw0/eoFP3HuQMrOWj//tYCJIAfQ6/diSErzFRjVfu2VdxhzKf44Ppnn4KWQCogg/e7oFURR57yXL2Fxt4fc7OvjY1Q2UmzUc73Px3KkhvvWaDdy8KZ6c16sVHOp2cqDLSSwmsrXWSkOJgTKzBrMu/UN9csCdsczhaK+L0wMeKm3ajO+/a9TPzjY7oijmVA9VKc6+3zVlJnRqBfu7HBnP2d0+SrFRTbVNl/K8XCYktKx0KjnNdTbWlhuRC+SsA/OFovzP/UfSZoUSSwcpUM2QZ04OJXbpDnU7UhLeEJcSLkgKVPVFhqyJ3onnGjUKbtwQV7K856V2fvNiO9vrC/jHBy7k069YycYqC28eq2j/9N8Ppci4FBjO3nPYGyIcjS/7+pwB9nY4Mt5/YsjYWmulqcZKc501Z4M0gEzI/ackl8mw6pRsrbVyrM816fU67X4GXH4uXl5IXaGezdUWCvQqTva72VxtocysYVebnaO9bvJRV+51BvjTzs7JD5RYlEiBagaIosihbkfi8X+OD2ZcrujVSj5+TQPLiw28fmt2+6uapPIDlULGd16zIaXu6gf/OUU0JiIIQkJpYOuYI4s7GOGFM2ePvWBZQXJdJ50jPsrHegknolHIaKq1IhcEbHoVW2qsaBQCAgJ7OkbZ1TZKgV5FhSXz+QCBSJRCg4rGKgvNdTbM2rNZhRKTms4RL4UGFR1JS8jyDNcrNWlYOVYTtanKygtnhmkb9rKv05FYIu7rdNAyRQdng1rO86eH8IUk662liBSoZogxKffyvsuWcc87t7JpQkHjtx89wdu31/Kfj1/GrY3ZA9WWGis/f/Nmio1qvnnreu5+vjVlp80diOCZUKm9pcbKFSuLgHjLyTglJg3l5rPLNbsvRDQmUmU9+5xaIcSDik7JnvZRdrbZsXtD7O0YZU25mRNJ5qXtIz4cvjAbK9O1oQxqOVadCqc/zP4uB7va7MgEgTVlJrbUWKgt0GP3hTk96GXQHaS5zkZTjRWHN0Rd4dng3FBiIBCJ0jLkZn2FaVYdnteWm3n65BD/++CxWbumxPwhNUvNgGAkxnOn4rt5VTYtn7luFfft7+Fg0iwLYG/HKDtaR3hFUjlCNl6xrpRQNMZn/nEoZXZ2xcoiPnTVirT8klwmcPfbmvjIX/bTWG1JPJ9pA3bAHUQmxPNkSrnAqlIjL7WMpFWZ23TKjIlxbyjKwW5nonxCJsDmaiuddl/KbA5g1Bdm1Bdfyk7seUzWsCoyqmkb9tJYZeFIj5PwWJ7s8BSkmCdDq5TRN1bb9eddXayvsPCmbed3l8RSQ5pRzYC/7OpMqBi8fXstPQ4/n/3HoYwWV8+eyq8VMhoT+c6jJ1OC1GUNRdz9tiY2V1txB8IMulMLKpVyGV+8cU1KRfu/DvSkFHSOExNh0B1EBJ45NYxcJqO5zkap6azyp90XTpsVJrOrzc76CjNlZi17OkZTdu0yocrR2+fyhxAEONp7NkjNJjU2LTaDOkXP/Uv/PsLeKTRhSyw8UqCaAaqxIsKPXr2Cd19ch02v4pPXrUSRocBxYjV2Nna12VMCjEmj4Ee3NaKUyxh0Bfj6Q8fZ/s2n+OS9BxP+fxCXdXnPJcuAeB3RZ/5xOOs9ZAJYdSqiMRFPMMKuNjsD7iCbqsxUje3uBSexwzrc48wYCDNxYsBNU40182v9HmoL9ISm4Dc4FQRBoGeCgWo4KnLHH/emBXyJxYsUqGZAvyvA1auL+fCVKxCEuCPy+y+rT5QIJBONiUQmsTDf0TLCBybUUV2+shizTok7EOY1v3iJv+zuIhoT+fvebj74p30Zl3g2vYr/vXltxoAJccup5F48iO9OHuhy0jPqZ0OFaVa38kuMao72ZjepmIkeVi6a62ypqhFJDLiC/OjJ0xlfk1h8SIFqBnz8mgZ+9fatKRXm0ZhIoSG1MXZ1mYm/vu+CSeVNjvQ4cfpTSxRWFBsA+O1L7YkewXFebrVnrPYGeMPWah740MXUF6U2MssFkAkCjdWWjLuAMREO9bgw5iignApWnRJfKJpRbWEuqbRoU3ZkM/Gv/b2cStPqkliMSIFqFgmEo7zhrh3c9VwrlVZtvByhqZI/vLuZMnPmgslkMrnOjCtgZtsBm5jETmZ1mYl3XVyXUCYAiIrx4sj9nY6cjbvdo76sAn5TodyinTSHNZtsqbFSbFQz4A5MWtnuCUb4rz/t4/W/2MHLrSPzNEKJ6SDt+s0ipwbciQrpb756PZesKMr73GhM5OHDfWnPd9p9FBnVWZdi+ztzJ4XfvK2GN2+rYV/nKO/7/d6EI02hQYVJq6DHkfm8AXeQteWmtCXiVCg3a9Cp5rcZuG3Yi0ouy1kln8x4I/cDB3t56sQg77mkjmJj9noxiYVBmlHNIsuLDawtN/GJaxpymjpk4olj/Ykt9GR+OJZHSZ4VJeMPRzO2vkxkc7WVL920BoDVpQZKzRqOT+IWM9Mgo1Mr2J2jWXkusHtDlOUoTM3GH3d2cvdzrVz//56fdMkoMf9IgWoW0akUPPThS/jQVSumrIc0UflznO++dgMAt19ST6kp/QP44pkRfv7Mmbzu0VBsYGutlZMDHo70uGissmDWZs5FyYVU8bv6Ij3LCvU01WbevcvEmUFPRt34ueZYr3PaQXbEG5qyk47E3CMFqkXC+gxuwEVGdSKQmHVKagt1aceYtUrWV1ryuoc7GGHUF06I4O3vcuAPRdhYlX7vqEiKo3HLkJfWYS8n+qa2FNQvgAFDMCLOyF35xBR8CSXmBylQLRIOZti9e92WSjTKszMDZYZdQ28wwtHeuELCZGypsXH3W7ekPBeKilP6I8hljJoJMa3VeX443O3AkkElIh/+uLODYERSWlhMSIFq0ZD+gS4yqlMeryhONzCIxERO9btTSiRyUVeoT3NtyfdcgOqC9FldNmx6FQeyaKvPNf5wLE1jPl+CkRgPHkzf2JBYOKRAtUgoMqQGpQK9ijdvq0l57o4r6tmSocJ73xSCwdFeF6GkqvNSk5peR/4V2sUTgmcuKq3aOWmLyZd+p5/pSqefGcpt8Coxv0jlCYuEiTt+77q4Lm3mU2hQ87f3becfe7u5/2APHSM+bHoVr25Mr4SfiCiKPHNyiP99KFU9oNKmY0+eO3NGtYIXzoxg1SmJiSLFRg0apZzDPZmLTtUZ/PYMKjme0PwsqwoMqjT/wXwJTdJCJDG/SIFqEXD/gR7u3XvWr6/EpOaiLOUNcpnA67dW8fqtVXlf3x+K8r4/7E0oPSQzUTYmGxsrzYx4Q4mEPIDT70ElF2goOeuAk8yoL4wMiBGv21LIBAwaJb5gBJ1akdW2fqZUWrWUmTUZ8375IgWqxYW09FtgXjg9zMf+eiDluQFXkE/eezBjH990eOhwX1qQ2lxtYUOFOa+eviqblkPdTrpH05uQQ1GRYIYKcINagUWrRC4XKDaqGfaE6HcFOTPoodCgnrMgtaXGitMfZnf76IyCTYkp/yWuxNwjBaoF5kS/i0xpnDODnhnNCJJ5+mS6xEwwEuNQjzNr024yFq0q595dh91HU401JR+0ptzEno5RwlExpYWmQK/iUI8Tm07F6rLZcTc2aRUU6FXolDLODHoy2sBPFe0ClFVIZEcKVAuMLYuz75oy06x8kH/4n9M8dCh9BysQjqKU55dpHsrDa29PxyiF+qRZSJbIplLI2FJtIRCJcrzPTWOVZUpFpBPZUGkmGI7hCUbQa5RpTd3TZUeL1Pu3mJAC1QJTX2RIe67crOGnb948Y9PMIz1OfvCfUxlfaxnyUl9kyNp4bFQrEoGsxpZfSULx2HKptkBHvyuzVlWfM8DeTkeimHR/l4Ojva6EDtZUaKq1cqTHSTASIxiJJfoYZ4P/HB+gY2Ru5Gckpo40v51lAuEoP3jiFD0OP7c2VnDV6txecmvLTbxpWzU6pZzbmqs52e/m0obCFC326eKaZHZxot9NbYEOfziaaOJdXWYkEhNx+sLxQCWQItCXi2O9rniVu5i5gDUb/lAUdyCCXiXHm+eOYGOVJe/dyukgCKTtukosHFKgmmU0Sjmfe+Vq3IFwxp2wiSjkMr5x6/rE4+XF6TOs6ZJsDJGN9hFfQiVBKY97CJ5OGrdRLedMno4vInCwa3p5NYcvzLY6G9GYyJAnSLFRzakBN05/er5pRYmB4/2zp6meCb1KkVbbJrFwSF8ZM+Bkv5v+sfqnAVcgpY3FoFZkLM6cT/65vyev48aVQBurLWkNue7g/LWS7Gyzs6djlI4RX6IEIhMmjXJKLsrTwROM8KKUp1o0SDOqafL7He188f6j6FVyttbZePbUEGvLTXzxhjVsWxa3Ve91+DFplRjU8/9r9gYj7Gmfmt3UiGfyGdh80efws7bczK4J70Ehg/A81Th95u+HeOmzV06pxUhibpAC1QSCkWjGJHY0JvLY0X6eODbAkDuIYyz/4w1FeeZkvEbpSI+LN9z9MhcvL8QTjHCgy4FCJvClV63lrRfUpF1zrojFRN7/h7248tymj8REKq3aKZt6ziXeUJThDLmxVaUmDmWphJ9t7N4QLUMeVpTMThmFxPSRAtUEXveLHVywrIAb1pcRikRxBSJ0jPj47Y72FJffibroySTLA0diIl/81xGsOiU3biif07GP84vnWrLqW01Ep5Qx7AlSZdNlLOhcKAQBWieYPjTVWGmfx524UDQ2a+UOEjNDClQT6HX4ufu5Vu5+rpXlxYasFdSeQIQKi4ZeRyAvIZP79vXMeaCKRGPc+fgp7n6uJedxSrlAY1W8QFMhg0gMnP7Fs+yDeJ/geB7KqJazutzMnnY7TTVWhudxiTobu68SM0cKVEn0OwPYx3bKLDolLVk66EuManRqOe0jPmoKdBQZ1QiCkOIAPBGtcu61w//wcge/eDZ3kCq3aBBFUnI/OqUM3zy7xExGIBxja60VATjU40z8bnscAVaWGDk5T+4xdz3Xwvdfv2le7iWRHSlQJfHF+48k2lkcvjBNNdaEWUMy5VYt+8ekVdpHfIk2lK21VmSCgMMfxu4JpVR0m7JI/s4mx/JQ3ywyqNNqnBZbkBrHG4xwasBDJGk3ddz0tNqmpdM+90vVxZS3O5+RAtUY0ZjIsydTG3cn5kgANApZ1mbXcSMDmRBXOUjm8pX5O9JMB1EU8zJSWCpFjDa9Cl8omhKkknEFImypsRIMRzkyA6ecyTja4+RIj3NG0sYSM2dp/NXOIif6XexsHeGlluFEDRTEl02hCU7Gdm8obckWjsb7ynIRE2FZYWrh5r/29/D9x0/inYWG2Uzs6RjNy3G4dciLWrE4t9vH67lKTRrcgXDOhmmHL8zejlH0s1j6UWHRUleo56LlBWypjtfACQL8+sW2WbuHxPQ4b2ZUjxzu48+7uzjU7cAxVkx4YX0BerUCUYSnTgyknSMX4nZUyUTF+AepYxLVgUgsNeg9dWKAYU+QZUUGbslD6C5fRFEkGInRNmGJYtMrWVFsJBSJolLIiURjuAIRTs+RvMpssKXGijsQIRyNZTRjnWu0Khl2bwiVQkbPqA+FTEApl3Hfvh4+cFm9VKawgJwXgap1yMNH/nogbcnm9Id5KUf1cVSML+Em+ublMjhQygXWVZgZ9YbYWmtld/soArC23Mzu9lG+cMOaGb2XZDpGvPzs6RZsBhUXLCtAIROoKdDRPuKjvsiQ1V15sRKNiXnl2SBuFV9i0szae1xZYuDkWOuQ3Rum2qYjJoqJko0HD/XxsWukQLVQnBdLv0eO9GfMKx3tdbG52oIxx/KhsdqS9lwwEk3LQQFsqbYQiYns73TQPuLjSK+L9RUmLqovYF+nA7VCxrKi6RkOZOKxo/38dU8Xv36hjdWlRpYX62kZ8mJQy+fd+HMi168rpdSk4S0XVFNh0U6666mUC1Oq46ou0M2a/55WKSMYidFYbUkI5nXafQx7glywzMa2OhuPHe3n2BzmwiRyc17MqII5Wi72dTooNKjIphAynOGFI70u1pSZONbnwqZTsqLEyIArwOlBD8minP5QlMM9LgoNKqw6JaO+MJv/9wk+enUDH7xi+UzfVmIJG4zEONHv5qLlRZzo92Rs5J1v3ndZPesrzCkBPRCO4vCFGfWFGPWFEj+Xm7V02L38a39v3ks+VQbrsOlSU6DnRL+b9hEfSrnAxsr4uDtGfPQ5/HSM7S5+/G8HePSjl87afSXy55yfUQ24AvQ6cueTtDlcdUsmuBOrxjSaNCoZZq2ScDRG+4iX9hFf1paVYU8Iw5juUzgq8t3HTvL0iXTVzamSHARE4H2XLZvVD/BMONbrSpt1apRySkxqXmoZ4asPHOP3OzpYVWqiwqrFH4rhDuRfBX560MNstOCZtIqUmqxwVORgt5N9nQ58oQi9SRsu3tDCfwGcr5zzM6qHD/fx9709NNdZAQFE2NNhT5H/tepUDLiCGZeHoUiMLdVWomIMmSBwot/N6jID7cM+GqsseIKRvPIqfRMsqf6xr5srVhXP6L0VJKmD/uKZFu64on7BDD8nkq31pHXYy6+eb0247rzm5y9N6/rhSIxCgzpF5ng61Bca2N/lyPja+koLoihi94aw6lRoVXIC4WiKKazE/HDOB6px5YJdbfGcTV2hHptexYgnlPhIH+p2JjSZJtI96k+T4h0vmPSGIhkLQjOxosTA8SSr8AcP9bFtWceMmpW3LStI/LyjdYQdrdOTJdGr5PzhPdu49WdTDxoygYya75XWVMXOcDTGp/9+iCtWFXP7pcv4ygPH0k+aAmvKTbOSh4uIMVaUGDBrlMhkAuOTNAF4OSVRH99V7bL7pN2/BeCcD1QTa4vGH2+psbC3w5F4PpsUi1WvzKoZPhUnlUzLwm8+fJybN5WjU8pRTGPJtqrUyMYqCwczzAg0ShkX1hfSMeKdtLp6TbmJxmorlzUU8eyYW41SLiCXCTl1n4yauOZWz6ifTVUWvn7relyBMKPeUJoA4AMHe/nn/p68NbImY6rW8uPYdCrsvniblEBc2iabAevyIn2KaGCVVcvejlEpUC0AiyOhMUc4fCH+ursr42veYJRtdbbE44l/9ltrrTTX2XJKpbj84bwNEnpG/dQX6WmuPXtPXyjKL55p4aJvP8XxPLflkxEEgS/ftCZtDGVmDY985FJ+/Y6t/OE92ybN5Zwe9BCNifzf25v44W2b2Fxt4c7XbUQ3iRPLmjITP35jI098/DK++7qNqBQyCg1qVpQYESZYFN+7pzvLVabHxPq29RWmrMcKxGvittXZcAfD1BboWFlioLnOltMl2pak8CkT4j6Fjx7tn/HYJabOORuoItEYH/rz/qxyvCf63exssycCh9Mfl8LdWmtle52N/Z0OdrXZU6rXJxIVodSsyfr6RHQqRZrFeDQmsn1ZAZ+892De10mmsdrK125Zl/LcD29rpK4wXgZRZtbyq7c3ccP6sqz25g5fmM/dd4heR4CbN1Vw3x0X8aqN5YlKcZkAH7+mIe28Pmcg547qOCOeIDvbZlct0xUIY1TLUcoEmuusHO5x0ZRBUVWjkFFfbMCsU7KzzU44KtI+4uPkgGfSGqzd7Xa0yvhHxKRV4glGeLl1hGBk/lRPJeKcs0u/7z1xKi9Npl3tdoqNak4m1eQ019my9pglo5QJiW9krVJOkVGNLxRBKZchEFdg0KkUY9ZUMuQyIe3DcddzrawsMRKIRHH6wph1U29efsPWak70u/nNi+0Y1Qqak2aKAFeuKuHKVSUc6HLw+fsOZ0z+/21PN+GoyA/esAmIz9b+56Y1/Nef9tNQYuTq1SV8/4m4o41SLvDZ61fz9u01eS1ZX261Z8xjzYReRwCrTolNrUjkH4/2uthYaaZ1yEMgHKPUrEEpl03b7FQUYW1Sj9+e9lEC4Rh72kezOllLzA3nbKD6+978lxqD7iClJjXVBXq8wTDk6VAcjoljuugio95woolZrRAwapQcG0ueywTYUGnB6Q+PSZcIhKOxeEAT4nkzg1pBODp9FYP/fuVqNEo5P3+mhZYhT0Ybrk1VFv79Xxdx13OtfPexk2mvrypNzb3cuKGcYqOGHS0jFBhUbK62YNOr+OAVy2mszl8P3qSdmz+zibrq/nCU430ulHJZvOQkg/jeVMnkdPPEsQEpUM0z51SgGnAFUCtkRGJiYtmSiQqLhkpr3KtuvE2izxmg3xVkXbmJXVPYTeoY8aYJuQUjIsGk52JifNdrvM9OIRPQKGR4xqyhCg0qBAEKcqiGToZCLuMDl9fz82da+PYjJ7j7bU1Zj/vgFcuJRMU0z7++DMvc5jpbYoZ23x0XTWts9+2bnQR6PtQV6hOtMPlKMU+Vfx3o4RPXNkiievPIkg1UL7UM0zHi443N1QA8d2qI9/5uD8FILOuWeZVVi1Wnom3Yy05Hen5ic7UFfyjK5moL0ZjIqQEPNQU6jBpF2lb4qlIjCpmQt8RIctyMiiJC0hNVNh1fv2V9WgJ6qpg0Sv7nxjV87/GT+EPRnIWsd1xRz6NH+1OS+FPJt+WDPxTlqw8em7Wdvnyw6KYf7PPF4Qtz52Mn+eKNa6a1WysxdZZcoIrFRP7fk6e5+7kWAuEY/9zXg0Gj4KmkSu9MQWp9hQl3IJLTGEAU4fiE/rET/W5kAjTX2vCGIniDEYbcQU70u9laY83YtJwJbdIOmgBU23RsX1bAuy+po8w8dZfgbNzSWMHXHjrGr19sy9mmo5TL+P7rN/LrF9p46sQgI954W8ts8uChXv68q3NWrzkZk6lazAbNdTZ+u6OD508P873Xb5zSMlhieiy5QCWTCZzqdyfqeybaKWVic7WFfWOKnLnIVmoQEzPfZ3fHaEIhYTKSg1lMhJs2lPP+y+uJRGP8ZVcnW2qsaFVyTg96ODPg5g1bq6elCtrvDBAT4buPneQ9l9TltIVfXWbiu6/byJA7yEOHerl50+zJz0D+voKzhQBU2rQMeYJ5fXlMhxqbjn1jRb6tw16MmiX3EVqSLMnf8tu219A27M2pmy0TYFmhnsBYw24+HOlxopQLCXvzfNjdPsqmKgsHsrRhjKOUC9QXxaviDWoF77q4joNdDr764DH2Tqhu31hlZkernV+/Y2ve4xhnWZGeK1YWsbdjNO++vyKjmndcVDfle+XiZL87p4TOXCAST3431VrnzO69yKimw3521vbvg3189CqD5P03xyzJQHXh8kJ+/pbNHOtz8cvn2zgz4CYmxqvLbXoVKoWM7lEfZ4a8qBWyvGp9IK4dvqrUOGX5kFyJewCDWo4vGKVlKF4l/tYLanD6Q7zjN7sY9cWLRsvMGjrtfpYX6znW6yImMq2+Mo1Szm/e2cyRHieeYGTBEr6PHlm4wkh/aG7qnLYvs7Gj9ezMelmhnlsby/nqg8e44/J6ik2zm+OTOMuSDFQAy4oMLCsycPXqEtqGvfz06dM8f3okbZaVb5AaxzyN5dZ4Y6xcJlBq0uALRdCp5FRadRzuceIJpia2nzoxyKkBN+FIjHXlJoxaJS+3jqBTyTkzeHY7fU/7KBevmN42+EJrfB+eJ5PQTMzFsm9FiZ79XQ4aSgxYtEoEQUCtlPH6u17G7g1xz0vtVNm0/Pcr13Dd2pIZb4xIpLLktyxePDPMzT99kadPDFFbqMu505UPsqQ/MI0yv19PKBqjudaGTiWnzKShyBjv6t/ZZsc39u3eNnxWq7zP6UcEis0ajvW5CIajqOSyNEmZu55rIRBemlXQR3sXLlAJAuim+XewqcqCRadMEUxsKDHgDUSJRGOcGvCwq32UXocffyjKkPtsPqzL7uf9f9jLxd9+mq88cJQdLSNEZlAbJ3EWQcyzuHE2aGpqEvfs2TNr13v4cB8f/vP+lCrySquWEpMabzA6LQXIYoMK3ViDco/Dz7JCA6FoDJVclihcdPkjnBxwo1fJWVth5lhvfNYEsKrUwIn+zJXQtQU6QCQcFekZq2hfU2bkWJ8bo0bBoS9dy8+fbeE7j54txvzDu7dNe1a1UHSP+rj4208v6BiqbFrCUTFnC1Qmqm06OsdyUAqZQFQUEcV43vBgVzz4lls0DLqCbKyypOUXJ2LVKXnFulLuuLyeKtvsqbueqwiCsFcUxbQiwCWz9DvR7+I7j55kc7WF6gI9Bzod3PNSW1opQveoH61KTn+OZtNslJo1eAJhBpOKNbMl7C9tKOTAWD9gMi2D2Suh20d8FBpULCs00OMIIBPijsAQ99sbcge54/LlaJXyhAzKkGf+TQ5mynwWeGajy+5ndZmRSDSWl7NytU2LVqnAoJEnAlXyF2AwSUWiyqqj1xEglseXvAi83DrCv/b38snrVvKOC2szylhL5GZJLP2iMZGP/PkAT50Y5M7HT/HhP+/n1y+mB6lxbDoV7kksrSayodKM2x9OzIxysbLEwI6WkYyVz+GYSFNt9rqaYU+Ig92jqBUy9CoF+8e+pVuHvbzmFy+xr3OUd15Ux0XL41pTL52Z352zmRKOxvjtS+0LPQwAjve5WZahlSgZrVKGWiEw5AlxcsDN3g4H2+ps1BXqUo4zZChDGHAGWDZ2nFmryKhSsbzIQNuwD384yv8+eIxX/+zFaSllnO8s+kAVCEf51iPHp2ThPRWVS0GIL9cOdTvx5rlbNOQO5ixhCE+SwA9GRDZVWVhTbqLEeLaSusvuT+gsXd4QV/+8d283h7odeY1rMaCUy/jUdSuzKjXMN8k5It2EnKMAmLUq1pVbUnYKd7bZUcnlaJQybHoVzXU2DCrFmEosHOga5dKGQnqdAVqHfWiUMlyBCMUmDfVFegoN8XPWlpsSOcpxDnY7uenHL3DnYyeXbP5xIVi0Sz9RFPnyv4/ytz3dadpDk+HNYza1tdaKLxQZy2Xl112/vNjAsCdIgUGFeawVJxNDniAGtSKnUWk4GmNfp4PlxQaqC/Tsbh/FpFXQOuShuc6W0veXTdZ3sXJbczVtw17ueq51oYeCTICVJUZC0SjtIz42Vpqxe0NYdEqc/giddl9GQ4mTA25WFBvoGfURE0WeOTWETilja62VYU+I506dVeYYLz5OzocNe7IXIkdiIj95+gx7Ouz88T0XSEvBPFi0gUoQBFQK2ZSDFMR92ZJpKDHgC0UpNqqRywRGvaEpy9iuKDbQYfchiiIOX5i15dmF2nodAS5rKMQXijLsCaUFtLXlpkSl/LgESalJw4A7wOEeJ7dBooB0RbGB7UmSw0uFj1/bwPOnh/P26ZtNio1qSkxq/OEYezocKW1O4zLSXXlYc403kTvHVBp84dis2pC93GrnULdDasHJg0W99PvYNQ2sy6HcmI0+Z4BtdTbWV5ioK9RzasCDSi7jeL+b3e2jKfKy41zWUERphoK9FSUGio1qbHoVoUgsseQ72utK031KptcRYHd73Ga9udaW0p6Tacrf7woginG34D6nn9/t6ACgvsiwJBtf1Qo5P7xtU2KzYD6pKdBxuMeV+BKYaV3VXLpL59PaJbHIA5VOpeCHtzXmXc+UzM42O4d7XInZTOuwl4bizInVj13dwG/f1czTn7ycG9aXpbw24gklaqImcrjbgVmrZF25ibXlJpprbTTVWNlQaU75497VbqfCoh17T3I8WeRHlHKBK1cVo1XIKRxb+ln1S1dKZEWJkZ+/ZfNCD2NR878PHuMnT51e6GEsehZ1oIL4jOLHb9xMYZJ+9XRRyGWsn1CxvarUyB1X1ANxf78fv7GRGzaUJV5z5FAU8IdjgMiZQTdD7iC72u3s6RjlUHd6sWP7iI8CvYqYKCbMBZJRKWR89vrV/Pe/jrD1G//h9U1VALz/svrpvt1FwZWrSnLOPGebGlvc0n4p8YP/nKbLvrTGPN8s+kAFcM2aEvZ84WpetbF8RtfZ2zFKy6AbrUqOTiVnZYmRH97WiDJpaSWTCXz8mgZWlhgxaZWTSug6/RECEZGaAl3uA4ERb4iNlZaMO4YC8LWHjvHQoT7CUZE+p583batOzMSWMt9+zYY0+6y5wqBRMDRDr7/5JhoT+ce+2TW/ONdYEoFqnLdfWDvja/jCMeoKdGyotPDYxy5lZWm69VF9kYEPXF6fVsyZC1me+/HZOgGCkViKAnIoIvKNW9cvyfzUROoK9VwyT9X1ZwbdeTsDLSZ25yFXdD6zpD4FW2qs/ORNjdzaWDGjOp1jfW42V1uyBg0g567eTMhXHvfqNTNzUV5sDLlnV5QvG8GIiEK2pP6sAei0+2akmX+us+T+RW/cUM4P3rCJjZWWGV3nZ8+00GXPvkXdaffl1dhq1ipoqrEiFwRWlhix6VUZg+h4qUw+QmuvWFvKLbMsYrfQTMwNzhUyIbsA4mKmy+7ngYO9Cz2MRcuiraOajAL9zLWxv/3oCX765sy7UletLuGtF9TkLFqstGiJiGKarXuRQU1dkR5EEWcgglmrQC7IiMTS+842VJrZUhN3ptnbYaex2srnXrnqnJMJef/ly3jqxECijumSFYXYvSGOTqI5Lwjxlqhs/ozJbKw0E4zEMppULAV+9kwL2+sLZlWa+lxhyQaqillIztZnKVcY59WbK/nVC20pdTgKGSwvNiII8Yrk7gzV6UOeYIoNvEouYNapUpK8hQY1D3zoopQ/yhFPEJkg5JQPXqqoFXK+fut6bvzxCwBcsKyAx48NpBxzyYrCNC/GV6wtZV9n9iLL5jobaoUMdyDMga6Fk5aZDc4Metj+zae4bWsVX7xxDXr1kv14zjpL9jfxiWtWUleop88ZQKuUc7jHmWLwkIs3bavmE9c0UDBJycPKUiPfevV6PnvfYZprbeztsLOm3Dyp7PBEQlGRcrOGIXcwoThq0SnTvjknG89SZ12FmfdfVk/HiJcqm47ghMLXz12/mudPPw/E683ed2n82AFX6i7exkozMpmALxTlzKAbRLD7llabUS7+sruLzdVWXr+1aqGHsmhYsoHKrFPyziSdb1EU+c2L7Xz94eOTViLfuL4s76DwuqYqttUVUGnV8nLrCG/79a5pjTcSi7GpysLJfheN1Rb0qiX7q58Rn71+FQD3H+ihNalDwKxVUm7RJDTrv3jjGm7YUMZbf7UTs1ZJpVXLmUE3q0vNHEhq0l5bbpp0+bhUMGoUuMc2W15sGeZ1TZXnXApguiy5ZHo2BEHgXRfXceWq1N0yi06JYWwK/cbmarbWWlldNrUdveoCHTKZwIXLC2koSS9nyIejvW4OdDnwh2Ps73QQiZ3fOzzDnhChpF2ut19Yi0Wn4gdv2MQXbljNzZvKMWmUXNpQhNMf5mivC6NGSbfjbGFkc53tnAlSK4oNBMJRNlVZ0Kvk3H+glzv+uI8Xzwzl3J0+Xzjnvtb/3xs2sbvdzu52OwOuIJ+6biUvnhnmB/85hSDA1atLsOim15bS4/DTMjQ7fV8bZrhrudRxB84u1WoLdHzkqhVAfFc3mfdeuox7XmrHHYikbUT0jJ471dwGtYJwVORAlwObXsWyIgNtw17e/KtdLCvU88Wb1nDFynOrZGUqnHOBSq9WcPnKYi5P+kd99eZKbm2sYMAVnJEb8O42e1aziDKzhouXFxIVRUa9IVqHvVnNMOUygZs3zazKfqmzqtRETYEObzDCd167MavUyYAzkFgOTaTCoktIOi9llhfpU3pD7d4Q9qRdzq5RHztb7VzeUHTeLgXzClSCILQDbiAKRJI1jQVB+ARwJ1AkiuJw5issPIIgzNiyfNCd/UOxqtTId1+3MfFYFEU+/JcDabUxDSUGvnbLetaWL6xLzELzinWlXLW6mB8/eTprL+ALp4f5n/uPZL3GrnY7K0uMDHuCeZUvLCZqbDqsehUCcKDbQbbV3apSI794yxZqC89vvfWpzKiumBiIBEGoAq4F5te3e4FYX2FBKRdYXmykyqrldU1V1BTouP9AD9evS1VdEASBH7+xkQ9eUc87f7ObPmeAdRUmfvOOZoqM5/buXr4o5TI+eGVm23lXIMyH/7I/ZWaRiZMDbhqrLUsqUDXX2jjc40wxMs2EIMBdb91CTcH5HaRg5ku/HwCfBu6fhbEserbXF3D/By9mdZkxZQr+qetWZT2nvsjAHVcsRyETuLWxYsqGouc62WrGvvivI5MGqXEGXUFWlhoZ8QRx+sKE58jOPRtbaiwEIzFiMYjGYpwcyJ7HVCsEvKFIXoKQF9QVSEFqjHwDlQg8LgiCCNwliuLdgiDcDPSIonjwfFo3r5liD6BSLuOtF9TM0WjOXS6sL8DuDTHgCnAqxwcf4psc41RZtXmpd84WNTYdezscicfNtWeXsZuqLKjkAt5QlAFXgHKzFo1KnnezuzsYRhTF8zYvlUy+gepiURR7BEEoBp4QBOEE8Hniy76cCIJwO3A7QHV19bQHKnF+8Yat1ZSatbz7nt1TOs+gUbCsUI83GGFgjuVeTFoFxSZ1yhJuXL11Q2V6YXA+tl3JHOlxcazPdd7nMyHPOipRFHvG/j8I/BO4DKgDDo4l2iuBfYIglGY4925RFJtEUWwqKiqatYFLnLvEYiJOf5i/7+1O8dbLh+N9buy+ECPeEI1jM5qJ2HRKGkoMY4aw00eMkaahfqjHiVGtQDtLS/wdLUvLLm2umHRGJQiCHpCJouge+/la4KuiKBYnHdMONC3mXT+Jxc+QO8CfdnZy795uRjyhaRl7ADjG2mn2dznYXG1J0yWvLzawu32UNWVGmutsCJBRarrIoE70bBo1ClaXmQhHY3SM+LB7Q8izqDRM1VMyFy+3jvCeS5bN2vWWKvks/UqAf46tkxXAn0RRfHRORyVx3hEIR3nVT16k0qqlexZzTPs6HWyoNKfIQ48HsmN9Z70im2tt7Gq3Y1TL0SgVDHmCVFq11BXpGXIH0SplidxSc52NXW12VowFvIzvJzI7nn0vnhnBF4qgO09brsaZ9N2LotgKbJzkmNrZGpDE+YlcJuD0hxlyB7HpVBl15afLoW4nJUZ1ImelzaAztqvdTlONlT0do7iDUZRygf1Zms/HfSNPDrgxa5UZfRcHXbOTH/OHo/xpZ+d5P6s6Z3r9JJY2SrkMs1ZJJCam2anPBgUGNQoZNNdas7oAtY94E27K2ZywS02ahBKnyx+hyKBiRXHcUq1Ar2J9hYmmGuusqnV+/4lTKTub5yNSoJJYFIiiyMjYrph8DnTij/W52FprY1f7KKosXoPDnhDLinJrlJm1ypRyiTNDXk4Pehh0x6vjD/e40oQUZ4ovFOVL9x85r5uTpUAlsShwBSIJNYW5+EBuqDQnbLRO9LvZUGmmscqSdtxkJUvjVu+TUTvLhZr/OT7IY0cHJj/wHEUKVBKLgthYGYJRo6Bllp2JN1TEk+nJEsWHup3s73Kk9RlqVQrKJukJzdZAncx0ajSrbVqqbNmVa7/07yO4AueOQOBUkAKVxKLAolNSZFSzssQ4JbXOMrOa5jobJTn6JzU5TDp2tdnZlhSszgy6UUwSiPIx6MiUYM/F1lornXY/vY4ADSWZZ2wDriDffPj4lK57riAFKolFgSAIfP/1G+kZ9eU1Y4G46YM7EGVXm51KW/YEvHeSuqa9HXYuWGajwqLF7g1TNonp62SzpXXlpknbfibSOyZXE42JVFi0qLLk6f68q4uXzpx/5YrCfCbompqaxD179szb/SSWJq5AmA//eT/PnBzKedzGSnPC1UajlCEjbjCbzPoKE4d7JlcB3VZnSxR96lVytCp5xpaXVaVGOu0+VpQYaBn04Amm10tZdUoUcllGx+bXbankrRfUYPeF+OL9R/AGo6jlAlaDmqtWFXPThjIqrDrC0Rh3/HEfL2WoTK+yaXnso5eek7VVgiDsTZaRGufce6cSS5pgJMpX/n100iAFqe7UgXCMLdVW9k5wrJHLZMgFyFJtAIAAKXpQ3lCUTdUW5IMeIlGRCqsWpVxGJBpLBMaDXc5E3RVAU62V8dF0jfrpz2DZddXqYopNal7985fYUGnmnnc0U2HV8PDhfo70uNjdbue3L7XjDUX5v7c38bM3b+aGH72QVprQZfdz52On+J+b1kz6OzpXkAKVxKLimw+fyFsHfWLsGdeh1yhkKOUCK0qM7Ot0sKrUiEmrJBZL9WCUCXEhw0gsXvCZcq2omHC/yaR1VVugS7nWgCuQ09BWp4zPsJ48HndK2tfp4A13v0yxUc2xvvT3+9UHj/HIRy7hx29q5PW/2JHW8/ibl9q4YUMZW2qsWe95LiHlqCQWDU+dGOCel9pRK/P7sxzPPSlkoFXKEEUoMalZXmxgZakp0eN3ot/NrjY74WiMSouW5lorGyrNaJRyTvR7ODNhl7HKpp1UG9+sixvgyoT4f7U2HdvqbKwsNbKyxEBznQ39WBK/2KjGZlCntPEADHuCGYMUQOuQl18808rmaiufe+XqlNcaSgwoZTI+849DBGepVWexI82oJBYFgXCUL/37KI1VFoY9+bWftA97uHCZDX84xuEeJzqVnAFXEIVMRrExPeN9csBNLCbSPUmVt1mjzDk7gvgMaludlV3to5SYNDx/Jj2XZNYqKTbKkQnClPsXC/QqdrQOc11fCe++uI6GEgNPnxhi2zIb164p4eSAm0/de4gdLSMp/gDnKlKgklgU/Or5VobdQYLhGINZdKRMWgWrS01EYiKxWAxfOMZLrWeXbNGxRFOPw49pQgmBUi6wrjxu+X64J7ejstMfpr5Ij16toNfhx6pXEQrH0ChlnB70EBNBKRPY2RZf+mXKR41fp9KioXuKBhSFBhU1BXpebrXzqp+8yGevX8W7Lq7jkhVnZZJWlZr4939dxCNH+qd07aWKFKgkFhxXIMzPnmlBr1ZkDVIQl3VOlmPZXG1JeT15ly5Z4nhLjZX2YW8ip5S8w5eJrlE/DSWGxFIt+bqXNxThD0c5nGSCmo2mWisHp+iqDXGV0r0do2yttbK7fZSvPngMbzDCNWtLWFV6VmG2Zcgz6xXwixUpRyWx4PQ6/PhCUerGnFaylVEpZal/rv2uADIh7pZs1SlpG/ZiHfNsHO/n21prZW/HaEpCfGebnQ0VqaqZGoWMzdUWGqssrK8wZ62D8gQj7Gyzp5VBZCNbc3MyOqWMxioL68pNNNfZEvfe1+mguS6eLP/eE6e48UcvsCcp6V9ToJ+yNPZSRQpUEgvOimIjNQU6uuw+1pabWFlqpL7o7EyhxqZDJU+3K+t1BFhRbOBorwtvMMLmagsrS4w0lBg40GWnudaW2LmbiD8cpbnOhlmrYFudDaNWyb5OB/u7HDmXhsf7XBToVZO+p/UVJuR59tFUF+hRKWR4ghF2tdnxhuIJ8mhMTJGLicRE7vjjPk72xxPwyjlo3l6snD/vVGLRIpcJvPPCWvpdQY72ujg94KbAoKbEqKahxECPw09zXUGiqTgZgzo+gwpFRfZ1Ojg14CYaEwlF4+0wnXYfywr1bKg0p8zUbHoVu9rsBEMREOLlBs11NjZWmqm26VBmUe/0hqJ5eewFI7GU5aVBLWdTlYXmOivNtVaUSYMZdAez+vpZk4Jic50Vi07Ja3+xg2dPTV5ndi4h5agkFgWva6riieMDhKMibn+YfoePAXcQo1ZBJCayo2WEjZVmhjzBRLsJgHxCG5/dF0Y/lkivL9KzXCZwoMtJKBKjyKimQK9EFIVEEAlE42oNE5U615YbOdrrZiLVNh3tk5QuQNw5u23Ym1j6rSgxsn+sXEIQwKCSEx6ral9eZEir40owFsDUCoHjve6EzPG77tnNuy6q5Q1bq1meh5rDUkcKVBKLAr1awdpyM3c/1wrE806MBjgz6EWjlBEIn60KN6rlyGQyio3qRNK8QK+itkBPKBpL1EV12P0pyfkhdxB/KIpnQu9fl91HhVVLT1IJwdFeNxUWLVqlDJtBza42eyK5DWfliDOxrc7GC2dG2FxtwR2IoJAJnEiSPTaoFNj0Ssosciw6FSey1FJBfAfTplNRZtGkFMJGYyK/fL6Nv+3pZu8XrkZxji8Dz+13J5EXgXA0YfO0UJzojwvbjTckJ2/5l5jOyq5sq7PRUGpkY5WZQXeQ508Ps77ChE4lZ2/nKO0jXiKxGAqZQJVVh2ZC8ejqMmPavfucQWKx9OR4j8PPmSEvDl+ICos2ZdY17A5mTfoPuAJEY/FZ2ol+N3q1IsWowh2M0GH3c2rAw642O64siqMQXxaWmOPKEJnu5/SH+c/xc1+nSppRnaeEIjGeOzXE/Qd7eeJYP6FIjGqbjouWF/KZ61dh0ijnfAyiKPLEsQH2dozyux0dKOQCV68u5rGjA1RatYmduonWU8mGnwAquSxhOqpVyvEEI5SZNeztHKXYqGZ9hY5YDAQZWXNBgXCMmgIdHRnyYKcGPFyyvDCl56512MuGSjPHe12EYyKlJg3VBbqMy8i2YS8yAaZr4Hy8L30Jmsz7/7CPB/7rYtZXnrv+f1KgOk/57H2HuG9fT8pz7SM+2kc6qSvUz4uZwP4uB7f/fu/ZJ8LxQsYnjg1wsNvJ6jJj4kO6qcqMOxDJGGhkMgGtUo4/HE90D7qDVFl19DoCDLqDKcu/jVWZP8yjvjACsK7CxJEMagsvtAyjV8kTO3IQF9+rtukwaxU4fOGsS8FBdxCjWo47g9LCbPHJew/y6EcvOWddlaWl33lKRQ7NpQcO9jLomlo19XRoKDFSNEHwbkfrCB+9ugGINwZDvJTgYJeTliEv3lD6MmnEEyIWi7GtzoZ2LGd1etCd2LmrsmlZW25iS42VoRzuMHZfmPYhb0a9KVGM59Em0mn3MewJTWojX5PHTuFMODng5vQsK6MuJqRAdZ7izpEXOdjtnLQ1QxTjO3GxPNYzdm+Ibz58nDfevYNX/vD5RNGiQa3gB6/flHLsrjY7t2wq5ws3rEalkKFSyNhSY+X2y5ZRadXSOuRJkQ/eWGlm1BciGBXZ2Wbn2dNDrCs3oZDJkAlQV6hDIZNxtNfF3o5RKnNI/QJ4QlHWlptYliGwZJurVOcQ7RtnYrHqXPDYOdxOIwWq84g/vNzBx/92gJYhz6TJ858+fQZRFHH4Qjx6pD9NYUAQBHa2jXDbL1/mv/95OOP1HL4Qdz52kku+/RR3PdfK8X43x/pcvOd3e2gd2+K/eEUhlzYUpZz306dbePfFdfzl9gv4zTua+NjVDRzodNA96scfjrGrzc4lKwrZWmtFLhMYnSBdfKTXxaA7SDAi4g9FaRv2nh131nBzlvZhb6JvEOKzz4YSAxXWeJBLllax6JR02r1p15jIxJ3GueD+g73nrFONlKM6jxh0BXj6xCAn+tw5TQQgnld55z27OdLjYtgT5MYNZfzkTZsTr3uCERpKjPzkqTPsarMTjYm8amM5wUgMfzjKgS4HO9tGONh1tsq7wqLF4Qvj8IW54Ucv8LlXruIt22r4yFUrGHAGMGgUCMT99T7+1wNcurKIX7/QjkWnQASaaqwIQryY8vnTcTneFVn0xcfpn4YRqCcYBTHI1lor0ZjI4W4n4ZiIRiGjrlDPoW4HW2utCIKATinnmTyKL215VLPPlDODHo73uc/JthpJivg8IxCOctX3nmVrrZV/HejN6xyVQsZzn7qCUrOGXoefXz3fxr17uhLFh9lYVWrkRP/ZHSuVQkYokloGcGF9Ad9//Sbeec+uSXe3srGlxsqhbkdefXXJtVCzwdpyU15CfytLDJycoo76dHj/ZfV89vpVc36fuSKbFLG09DvP0CjlfO/1G7lkRSGGDMnhiayvMPO1m9dh0Sm5d08XH/rzfn79YtukQQriebDk0oJMPXIvtYxw++/3YNQo2FJtwaydelnE3o5RNlZa8jrWP8v1YpM51ozj9IcpTHJVniseONibV95wqSHNqM5jfvV8K197KLv90oevXM5TJwY50uvCqFbgDkaw6pRolPIUj7xcJFdwG9QKwtEowUj2v7kysxq5TDZlobl8TRwAyi2alDac6SKXCSCKOfXYx1ErZCjlMoKRKIUGdd6/v+mwlGuqpBmVRBrvvrgOdRZ784uWF/DAoT6OjC1rxmdQo77wlGYE3uDZRLcnGGFTVW6N7z5nkFAkNqWZVbVNm3eQ2lBpxhOITJrbyofYFL7kg5EYdYU6agr0cxqkAPZ1zt7SdrEgBarzGEEQ+OKNa1hTZuLDVy5PPF9XqGdztTVltywZjTK7oWeGu6Q82t/lyCuRX1Mw+ZY/xHNOE3f9JrKl2kJdoZ41ZUYOdTtxBSKcHvBQX6SfUcAqMWmQ5bn0M2uVHO5xpe2ezgUjeUo5LyWkXb/znLdcUMMbm6vZ8OXHgHgv3YYKMz9+6kzG4zUK2aTGB8lM1GQKRWL4glGaaq2IopjWDmNUy1lXYWFHa7oGeSYEQchZE9ZQYqBr1J9RObRlyItaIaPSqp3SUrOpxkpUFBNqCPng9IfZUGlOM3iYC87F6nQpUEkglwnc/18XJ6rR3/SrnVmP3VBpyS5JMoFskr8j3hAj3hBKuZDSWrKyxEiv00+v049BLc9o7jnOimIDcpmQtW0FoNKipdcRyFnDFIzEKNSrpxSoBty5rbGyMZWl4kzI1Hi91JGWfhIALC82EBVFPvX3Q1mPKTaq8w5STTXWnLrkEJfpXVMeT/purDTTNuLFHYjQMeJjWVHmJZlBJaex2sLpQU9K6cNE9Co5dYX6vAoto1MMIKVJag5TYb72rTafg15/UqCSSOANRtNceZMZ8QSpsubOL43j9IdprrWhU+XOZ53od9NcZ+VQjzOlxupQtzNjLmtthTnnksuiU7KtzsbmGiuHe515JeU77emKCXOBd46r09eUmfjTe7ZRbJxeIF3MSIFKIsFks4+omCqNm4vTgx52tdtZWZJ7GeIKhDnS7cw42yg3pweqaI4aoeVFeooMana22Tnc48ThC1NpnfxDO5XaqhXFhmkXjA66g3nprU+HlSVG/viebVy4vHBOrr/QSIFKAoBgJMpjRydvap1YWT4ZHZPMVoqN6qyOLpmUEk72u1hTlrlFxKZXJxQEHL4wBpWco71uNlVZco4hFImxviK/tpNMY8qH2gIdMjLbw8+UukI9v393c95fIksRKVBJ0GX3cfNPXuSJY5MrRZq0SmoLdCmNucloVfJETx6Ay5/7g5nsvzeR431uVpWmzsjcwSgGdZZzJmx2lZrjs6l8llz5llwMe0J5L3/HUStkcQnk0OzrUV3aUMQjH7mE4mnmzZYKUqA6z/GHonz674dyJqaT2dVmp33Ex8l+V1oLzoYKMwoBDnY70I198GUyGWty7EJ12n1ZxeyiMZFRX4htdTYKDSqMajlbqq2o5HKME5yQt9Za09pZLLr4DOP0oCcRtDJhVCtwB3LXYo0TisQS915TZkKrkrNxkipwtUKWt039VDCoFXz7NevzCrKiKNJl93G428n/3H+EBw/1crLfzakBN6NJszxXnr+H+UYqTziP6XH4uf13e/Jqqp2IJxhlU6WFo31OdCoFK0sM7ErK3Vi0injVuyCgyjFrKjVrUCUZEzSUGOhz+BMlCwOuIAOuIDa9kkAkxt6xquuttVZc/ghmnRIB2Ndhp7HGlnLt5JybPkdSX6uSc6I//9qw8ZyWXCbgD0Xpn0RksNyiRaUQONQ99d9zLj73ylWUZcjjTeSRw318+9ETKXZjv9vRkfhZEOCqVSW848JaFHKB7z9ximWFerbXF7B9WcGimK1JvX7nIacG3Ny7p4u/7enG6Z/8G1QhExDJnMgut8T/iLP1zpVbNAy5gwllg+XFBgr0KkTAF4wkWnQ0ChlrK8zs7RilvkhPgV6NNxRhxBNMSLUUGlQp9urJbKw0J1xqkqkp0KFXKTiWxeml1KxJMZKYSNw4QsGxXmcieOpVcdnjuJpE/NxKi5buDDumMiGuGrGyxJhxfNPl6tUl3P3WLZNWxj99YpB3/Xb3jEojlhXp2b6sgIuWF3LNmpI5NT7N1usnzajOM/qdAd78q50MZajUhvgH+w1bq7iovpA+ZwCTRsGIN8R3HzuZcRt/subeQVeA2kIDZwY9VNt09I760tpI5AIUGtXs7YjPllqGvLQMxdt3ys0a6gr1FOhVidnURFaXZQ8CmcwakikzqbMGKpteRduwD08wQrVNhzsYv5Y3FKXEqMaoVgIBlhXq6R7NfJ9NVRb2dTpm9cP9hRtW8+6L6/KqQP/RU6dnXL/VOuSldcjLH3fG9fQ/dd1Krl9XOq8V8FKgOo8IhKPc/vs9aUHqsoaisT982FprS+Q8NlbFA827v/vMtOVRDBplIjApZELGHb7Gait7OjIHod6xIJKt7xBAp1Jg1iopNqqnrBue68O2vNiQqHzvdwUQSPiBUmbRIooiRUY17kCEUAYJhWKjOjH+fHsC82HUF+IL/zpCgV7FR69uyHrtLrtvSm0++dA27OWOP+5jc7WFH72xkUprfj2ZM0UKVOcJoijymX8cSus121pr5Zdva0KVRUVBLhMIRKa/W6VXKagt0KFWyLMGG980t/zHOdztQCWXTWt7fl+ng+XFBixaZVqwbB/2JiRh1pSZONDlQKeSs67cjEoh8MKZkaw2WBsqzPS7AonZ2sl+N41VFvZ3OabzFlP46dMtiZ//c3yQP7xnW0YF0Zfz7JecDvs6HbzqJy/y0zdtZnt9wZzdZxxp1+884a7nWrl/gqKnIMCnrluVNUgBFBjU1ORhXpCJFcUGyi0aDnQ52dlmH3NDTt0BXFFi4NQMlS9DURFPKJpXvi0TZwY97O0cZVWpkcZqC8218aT8oDuIyx9mQ4WZPocfm16FWatkV7udIXc8V5YpSMX7FCMpjdBOf5jBOdj5O9bn4tuPnMj42sFux6zfLxm7N8Rb/m8nv32pfc612qVAdR4w4Arw/cdPJR6/++I6Skxq9CoFGybZWr/nxbaU3aJ8WVVq5PSgJ6WKu23Yy9FeN5urLYnnTBolkRkqUpYY1TTVWmekbCmK8Xae/Z0OdrXbqR2TmfEEoxzqcTLgDrKi2JCkJZV6r1WlBgoNKsrMGmoL9bRmmD32jPrnpGH4r3u6eKllGJc/nDDZeOH0MH/e1TXr95pINCbypX8f5VN/PzSnbtvS0u88oM8Z4MuvWstNG8sIRWIUGNR86rqV/H5HB7JJEqLjTcNTocysyVmX5fSHselUrCgxEI7GWFdhon3Ym1MtIRMrig1jOk9OBtpHaZqlZtz1FWYO96QukRtKDJweOPueNEo5AlBp1VJs1KQk+nMJ4+lUc/ORu+OP+1hVamR3+yg/fVMj333sZM52o9nm73u7OT3g5hdv3ZJXycRUkcoTJHIiiiKf+NtB7tvfM/nBY8gEKDSoM2pAZWN5sQGjRsHRHmfGxPQ4KrnAmjIzImLaTp9NpwJBxO6dftFiXaEOEFLyaVU2LT2j/rRlXolJjS8UzamHNZFqm27OmqDHZZ/HG7GnuxSeCWVmDf/64EWUTLP2SpIilpgWgiDw9VvXs6rUiEImJNyHcxET40WOU+HMoIf9nQ7WVZhR5tgh21Rl5UC3I2M5gt0XYl25OaPTcT6oFDJc/kgiSDVWWVhdZiQaEzPmogZcwSkFKQCNUkZTjYXmWmtieTkbrCwx0jK24+n0hxckSEF8Nvml+4/O+nWlpZ/EpGhVcn75tiYePzbAdx49wcT8TCYcvuk13wYjMTRKGeEsy8ATAy4qLNqMcjQyAQ53O9Ep5Xin0VdnUCswjtWNQTz/Ml0Lr2RqCnTxGYYIu9vtid+eQiawosTA6WluJtQW6LDpVcREkSM9rhnn+maLR4/2Y/eGZtXLUApUEnlxqNvJ1x46lrN4UC4T4v1vSnneAnvJrCs3JSrVs+HyR1AIsoxLqDVlcY89ZY5dzFzYvSHs3hDLi/UEwzGCMyjLSKbIoM6oRBqJibQPe9lcbcEXikypjWfcMzESE6fs2DMf7O0Y5Zo1JbN2PWnpJzEp/c4A33j4eMYgVWnV0lxno7HKTLlFw+Ee57SCFIA+D59BiC/xXIEw1RPKJlQKGSJg1SrZWps9sa5WCGiV2f/0zwx6qSvST7l4NBu5ij3DUZH9XQ5MmrOzj1xjG2d89iSXCZTMoU/gdHnqxORKHFNBmlFJTMr3nziZVfnTpFHk1C3PF71KPqW8isMXRoaQMGYwqhUcGdupG3AHCUez62atKDbiCUayll1sqrKwo2WErbWZNd+T2Vprpd8VoMig5kCXI2MuK9dKeWWJAb1azrFeJ6tKDYgIdNp9bK214g9H0SrluAMRjBoFKrmMQDiGXAa7x4pTO0Z8NNVYGZjCxsV88PDhfr5+y/pZq8iXApXEpDyeQ6dqtpK2q8tN7JmicqbdF0IQVFRYtVRatClBRa9RYB+z0VpVasSgVjDkCVBq0nK4x0kkJqa0xCSjUsgIR8W8tNRD0Rhddj9ddj8N0yheNWiUiGK8YDV56ZdJRXRTlZkDXembCJGYiFIu5GVpP184/WF6HH6qplksPBFp6ScxKdkaaktM6llxHDZpFLj902ujGfGGGPUEOTjWmqKUC6wqNRIc6ylcUxbP5RzoclBijAczXyhKKBKjsdqCUiYwcSMzOFa4OFmNGZwV/lPKBRxZ/AWzXWZ5sYG9HaMoZPl9DLON50CXI29L+/lEO4le/lSQApXEpHz2FavSnltXYUI+Jv8yU6psOk4OuNEoZDlLE7LhC8cIjEkkh6MiwUiMYCRGhUVL55itVSQmEonFUsT1QpEYBUY1dUUGmmqsNNfZaK6z0Tqm3DDqDVFqyp3/cfnD1BXqWFFsyFo35puwAykQr3nqG19OC6SJ/o2jVcrZVmejocTAiSxSNTD9Xda5pG8WvsTGkZZ+EpPy6s0V7Gwbocfh5/p1Zbxwepghd4BKq25WZlQGtYIKixatSp6xOXiqtA17qbJp6bL72VJjRauUIYow6AmiVshQiiIbqyw4fOFE0/CaMiPHJpQinB70UGXT5jQOzUcZ9eSAO+FfWF+kR4SUvN6+Djs2vYqaAn3Kkm9duYkhd3DSPBmAZhZnLzNFLsSNQMRZ+RqLIwUqiUkRBIFXb65k0B3kL7s6eanlbFd+qUmdELabLu5ABIR40ee2OtvkJ+SBRauiCz97O+LNxnKZkKhXMqoVhCNiSpDJtuM4nn9aU2bKKr43GaFIjMYqG4e6HbgDkbSZVyQGg+4QGoWc1WVGjve5qS/S02H35V1QOp8dJpNRMqba6ptiS1QupKWfRF7sabfz4T/vTwlScDb/Ul+kn/a1zwx5iEZFtlRPblqaD43VFo70xmdAzXU2Tg96UnrsVpebUnrz1GPJ81wc63PRVGOdUhFjbYGO5lobzbU2RFGk1KzJ2VZUZtHS7wywtdbKgCswpap3lUJOiVHN1lprvJVogZALICDQPuLj6VODs3ZdKVBJ5EW2omeTVsXKEiOFhqnX8qgUMppqrKgVMvpdgawKnlMlFIml1HxFx/JTGyriDdYTVRbGm5An1mVNZE/HKP5QNGeNVjJFY87S8f9GaRvO3eO3s83OipJ4Y/FUG7QPdDnwh6Psbh9N6MjPN+NLvpgoxv9NczRnTxVp6SeRFw8e6s34/Ml+N2atkn7X1Kuj64v0M85HZSLZyGG8nmp/p4MVxQY2VVnS5In3dIxi1CjSnG0y4Q9HOdDloMysyaiSsKHSjCiK6FSKaUkAB6cplSKK4BqbgbUNexMNyuMoZQLh8SLRsYAyUzZVWVDJBWJivH3peJ+b1eUmWgY9BCMx3ra9ZuY3GUMKVBKT4gqEc9YHRaIxKqxanP6p1RANzOI37jjNdTacvnCi9CA2tuSqturQKGWcGvAwlEHALhCOcrTXxbY6G2qFjL0doxg0CnQqBXqVnJMD7sTyMByNSxD3OwOJdLFSLqBTxdUfphsEZAL4ZknTaVebncsbivCFo3iDEY72urBolagU8fajmXxBCEBTrRW7N5TQtk++L4BZq5zVkgkpUElMSuckwnneUJQuux+dUpbV9TgTtYV6fL2uRGnBbDDqDWVsfRlfhqwqNabYW2mVcpYV6ROWYTvb7Gyrs+ENRccam+NBbeKmwaFuJ5ur48YNW2qstA97qS8yTLt9SBBgS4112nbxE2mus/HMqaGU5xxjxbnT1b8fp6l28nGuLDWimEVDCylQSUzKRNeYTPjDUbbUWNjb4cj7uvs6HTSUGBhyBxmdUCxZbFRTatKgVso40OWYNNltUMlZU2Ge1BXZqFGwrc5GaGxJaNEqefpk6gc6HI0hlwkJ4bls0jYHu51srrFwasCNOxBhxDu9ICUbM9WYjY2EBDnWnQV6FatKjYQjInK5gDcYb9HxBCM51SJqC3QUGzWcGZr876GxyjKdUWdFClQSk5KvaJ59rEByKuUKpwY8FBvVaZ59tYX6xDKiuc7GmQF3oiVmIltrrQQjsbx6DpNnAsVGNR0j3oT3oE0fH4NWJcemU1FbqBsTxgsnCkeTicZEFDLZlDWpJrKi2Di7QQpoHfaiVcrwZ5jhto/4MvY5CgI01VjpGvWhkMsoMqhRKWR4AhF0ajlHe115y1Lf0lgx4/eQjBSoJHJyqNvBcxOWEJmQywSKDBq6HVNXrxx0B9Gr5FTbdBjUcqx6FS+eOVsGsavNzsYqM3afk4YSA70OP55glM3VFkY8QY72utKqv/Ohyqplb6cDgyoWNxMd9aNTyRP3zpTLSmZduQlnluA5FfJJ4k+VYU+IpprsNmSZEEVSju+ZpnzMyhIjq8tM0zo3G1KgkshKJBrjv/95JK9jN1aap52fgXiey2v3sbnaws7W9OsMuYOsKTMSjMSoLtATi4mcGvCk2LZPlUPdTowaBe5ABM/YjMmdZ1lAlVWLPxxNSyZPFbVChkohm7WduGREyLo7OZe886LaWb+mVEclkZW7n29NMznIxulBT1pz73SIiWJGpcpeR4BjfW5ahrwIxFtXZhKkADbXWKe9bOsa9U+rdmwia8pNvNQywuZZMqYAqLBq0Srl7O0YJRoTMWvnbz6yqtTIa7ZUzvp1pUAlkZE/7+rkzsdO5n18kVGdMBWYCZ5glHJzbmOA5HaXTVVmlhcbpnyfphprQr9quuQjA5OJFcUGmutsKOUCA2M7kLvbRxMFqTOl0qKlocRAmVlDtU1HZB7lX26/dNms2tePIwUqiRREUeSnT5/hc/cdzlqNngmLVpk12Z0vzbU2zgx6Ejbo2RhyB9lWZ6Op1sqBLieWaQTImChOS1d9nAqrNqusy2RYdEp2tdmpsGhTmrqP97vQ5aHuORkDrgDH+1zY9Eo67b4Zvc+pkq9K61SRclQSQDwftbPNzgMHe/nL7qkbVwZnWAu1qtSYd46rbdibYmfVOuSZsl36TAX/ysyaKQv9jTOuKzVxBy0cjVe0bywxZnTZyZf2ER/FRjVHe90o5QIbKswcmuHsMV9Cs1gTl4wUqCQQRZHP/OMw/9jXPe1ruAPT/+ALMCMHFbsvTH3x1BJkphksU606ZT5GPBkpNWsY9WbXjnL6w3SP+rl0RSHPnR6e5ghJND+Ho2Ki0HM+mItlH0hLv/MeTzDCVx88NqMgBeT88E3GugpTXkWluRCmYOanUcimbVGlVcoIR2NTbkEpNqppqrHi9odzVmwXGdWM+kLsaB2ZsQqCUi5QZdPOmeFpJhqrLXNyXWlGdZ7R4/DjDUbQKuONu6/9xUsMzFBPCuK5iXy39ifSNepnRbFhRq4vucwcJhKIxGiutCAiZuxXy8X6SguxmDilQBXPvbkT5whC9ulYjU3HkDtILCpSV6jH3jn9L4DGKgu7ZqklJx9WlRqn7ZA8GVKgOk9w+EIc73Xx5v/bOaUk+UQUMoHGaktiBuMLRTjW66K2UI/dG8ppx56NhuL881PZ2N/pYGsePWjjJN9vQ6WZ432uSdt0ysyasaZjMaEgmotSs4ZKizbtvR3tdaepG4yTPIKD3Q5KTRrKLRr2dTomfU/JmLVKTs2S3Ve+rJ+lXctMSIHqPMAfivKqn7xIlU07rSAVN8iMYtYq8QYjacGg0KDi5VY7Vp2S0DR2wqZrwT6R3e2jCELONreMeIMRttba2NE6kvHcYqMapUJGuVnDEX+YQDhGkUE9aaCKRGOc6M+sCjroCmQMdsnS6ZGYSL8rQPU0rN8bSgyz1uCcL9vrC+bs2nkFKkEQ2gE3EAUioig2CYLwXeAmIAS0AO8URdExR+OUmAE/fuo0nXYfZq0yUYmdDzIBGquskwrajffombVKVHLZlD3mogtkRa5SyFhfbqbf5eellpGMsxy9Sk40JjI46k+0lGyry95AbNIoqCvS0zHiY9gTyrgbqVfJcQUiOH2hhAifgAACGWdZ8kki+cYqM5GoiC8UxaJVcrDbQSgSQ6eUUWzSJHYXG0oMWLQqRMRZDWIFehVv2147q87IE5nKjOoKURSTtyGeAD4nimJEEIRvA58DPjOro5OYEW3DXj533yFeHmtJOdzjpMSopr7IQMuQZ9KA1VRjm9KSrH3ER3OdbcqB6mB3diG6qaCSC2lLT6NagVIhw54h2a+UCTgDIXrGapk6hr1p/ngrSowcyKPsYW25CZ1Kzu72UQ52ORPBLNOO27IiQ6Lif7KAsaXGmmItv3ksWX2018WaMhOhaIxwREzRc2+utSEI4I/E6B7101xnY9gdTNEUs+lmXvcG8OrGCr70qrWzUuybi2kv/URRfDzp4cvAa2c+HInp4A6E+cETp6kt1HHb1moc/hBPnxikrtCQCFLjDLiDDLiDVNu0uAORuJyKWYNaISMmigTCcRlflz88vbzRNKq1w1ERm1417UA1roOVad5RW6hDJZcnApVNr2J5kZ7omCpl8mxuwB1kfYUJreqs+7Mqww7dRCmZTDOx02NGFT0ZmrTHNzImQ6WQsb9zlJgYV4joGPElclVba62IIhztSl9a7mq3J8xVI6KYcZamVyvyClQquYxbGsv52570XWGrTsmnXrFyzoMU5B+oROBxIb5dcZcoindPeP1dwF9ndWQSeTPqDfPHnR0EIzF++XwrCpkspSAyE512P8uL9JwZ8uY0HJgK6yvM095lyvfDm4kSsxanL0yhUYVVp0pZlinkMhRygXUVJnQqBWcG3CljLDGm9usd7nGltLKEY+m7iScH3Cmzt3A0RlONlbZhLyNjAdHuDbGzzU65WUORQZ2ixBCbpAhLIROIxEQaqyyJ9zJx5uXwhXOWdEz2dRHKc5c0FI0x4gnxndds4CdPn0kpdfjSTWspM2vzus5MyTdQXSyKYo8gCMXAE4IgnBBF8TkAQRD+G4gAf8x0oiAItwO3A1RXV8/CkCUm8nLrSKIyfLIEbzKyaZh95kKtmH5ZXvuwlxqblo4pjB/iEim9Dj/BSAy7L4RZq6B8zO2l1KzhcLeDXMXSE5eplRYNTn8IpUxgc42V3RlmleGoSFOtNS4dHIpysMuBSiFLcboZp9cZoNysSdHpymZ6UGxUU23T0ev0Y5sQcCfSPepnTbmRo72T+wpmYsAVZF2FiSM9Z2dkChkZf1dPnhjk+TPDXLOmBHcgzKgvzPsuXTbrmlO5yCtQiaLYM/b/QUEQ/gk0A88JgvAO4EbgKjGLsdjY7OtugKampsVjPrbEEUWR/V0Onjw+wC+fb5vWNdQKGTIhu8PMVJlJ4LPoVQTCUWw6FfYpuP7KhHgSf3xW6PRHcPojWHVKuqehp+QJRakt0IEg5AwUE9tnqm062rLUY/U6A1h0ShqrLXgC4axyzZVWLf5whF5HYFJjV384mrCTny5OX5jmOhuhSIxOuxeHL0x9kR6bXkUkGuPKVSXc0lhB+4iXk/1uVpUauXljOX/c2clnMrhnzyXCZMaFgiDoAZkoiu6xn58Avjr28veBy0RRnFxZjXig2rNnz0zGK0F8qfH1h45zz/9v78zDG7/Ke/852ndLsrzvy+wzmc3xTDaSISGBcCHQhLCVkCYQAmUpvW0htPe23JYWKLS9lAstgRACDSlboEAICUsK2SYzk5nMPpNZ7PG+W7IlWeu5f0jWWLZsS7I8tsfn8zx5Yv9GP+mVx/rOOe953+/7fFte9xeZ9TSXWnOyDc6GaqeZztH8zNYaPNa06SlldiNOi55TWVSQz3UKlw9zTUaeDZ1G0FhinXMIBjBnrdekB3u2uCz6GRbOi4EQ4DDp2Vbj5Fv3tBKNxQvqh57+WuKAlLJl+vVsVlRlwOPJAj8d8KiU8kkhxBnASGIrCPCilPL+AsasyMCzrw7y3m++lPORvlmvZWOFg4lolPMD/oKLlN2oy1ukIHFCWe4wsa9tmB21Tl7tH2d4MMzWmiJe6ZhbNA4WaB7gJEPjuVeDN5fashrvnokr6130+0KM5LCSBBgJRLAatIvujiBlYvX9d2/ZDLBoIjUX8wqVlPIcsDXD9eZFiUgxJ92jQWJxSbnDlDZNZT7WldkLNuAzE9kmZ2dDI8Bm0tHrI21VcWTKtJdM7Kxz4QtGFtR+M5XmEisX8tgy9vkmsBm0jM8jGvvaRtjV4KbHO5FKTEfjkvbk15srHRztzn50fEOJFYNWk3Pleq587a4W7CYdkVh80RqP50I1Ja8wWupdPPuJPbzwwGt59hN7+MD1jVndp9ct7uzcbQucOrKtxpnxFCsuE/Vfde6Lp0t2k46NFXaurHdxoH2kYCIF4LQY8rIqGQlEqJ5n0vLkYcPe88MM+0PUuGeemJkMueWdjnb50GkW/2N878P7eNeDe5esOFcJ1QqjscRGtcuCEIJql4VP3LIe0zxma9tqnJwb8FPuWLh1biZK7cZ5c0TmOWL02AxzFp9GYpKoTNQrVTtNWA06TvWNL0qLSD4z79aU2thS5cA2j2nc5koHrQ2JSvTxUAxX0h0hEotTajeyqdLBRB7buJN92a/A5mO2oQzDgTB/dE09pgWUkSwE1eu3wtFoBMVWI11z5IdO9Pgw6bUM+cM5Ne7Oh1GnIRpPdPnPVotV6TRRYjUyHAxjNeg42TuWqpyOS4lZn6jmHhyfe1XUlWxhKXTifDr5rBhGgxEG+uevRQvHJAOjifcwNhElFImxsy6xKgTyqmezG3U4zXp8wYX5xwPsbnTz+du38k9Pn+LHh7pT1816LZ+9fQu3bbt05QjTUUJ1GTB93FKx1cDmqiI6hgN0jAQIReOpOqvZDnn1WkF9sTXrbZTDpMM3EaWpxMqxrtGLsRi1KbuXKqeJMocpWWekJWCIcU1zMbG4TKuYv7LeRTQmOdXrm3fS8mwlBya9hokcpjRnotplTuWKcmFgLJRVfupIl7egQlvuMFHlMhXkYOQt2yr54p3b0GoEf3bLOn57agCnJXHS95HXrsnLl76QKKFawbx4bojv7e+Ycdo05A/zztYa7v/OyzPuydTf+k93bsWg0/D1eeqxzHotW6qLMGgFYxNRXun0cnbAz846F1ohGPSHODfgZ2t1ERqN4Gz/OF2jo7gtBjSaRPNyOBpnf9tI2sBRgeBgx0ja6mI2Zquxun1HNfvbRjjVl9/JGyRKDIJ5nqDZTPqUUM1VNuANRmYdDJot22uddI0E6fVN5HSgMhfvaK1Fm6yDq3ZZeOWvby7I8xYKJVQrkHhc8tTxXj762KFZE7/D/ggWg3bGYM5Su5GPvLYZk15L26CfYCRGeZGJq5s8XBgO0Oud/Zd/S3XRxenF9e7U9eni8kqnl1q3BV8y7xSKxlKm/+FoooGkxmWm1G7keM9YyvROm0XBqNtioCt8cVV14/pS7r6mnt+c7F+QSEGiqTrX09RJen0T1Lot9HiDjAQibK0u4miXd8asvpO9Y5gNWuqKLXisRk72+nIqLzAn/94WWj9V5TTz1u1VeIMRqlxmtBrBN549z73XNizoeRcLJVQrEI1GsKbMzvpyO2/eWknHcIDzQwE6hwN4bEZ2N7qpKDKxpszOK1M6/29YV8KX3rkjoyCEojF+frhnzlqejuGLldf724fZVOng2CxH6eVFptTxuz8coz6ZxzrdN45eKziYrI1qqXOltqMH2kdorZ/dscGs19A/dlFE7EYd917XwL0P788rCZ4Jt9WQ9yplah/cK51eWutdGXsfg+EY7UMBHCZ9zjVQ1S7zgk859VrB3VfX8/bWGn5yqJsXzg7yhV+e4qqmYiVUisLSVGLjYzeuYc+6Ul7tH8dm0vHLo70AfOWZs3zpN2dm3LNnXemsqxajTssDb9jA+x7ZByTqmtxWI4PJZtrpohSXiXyRUScIRWcmvqZ3PBzr9qWqzrfXOjmYrPvZ3z7CpkoHpXYj/WOhNCGaTjASZ2OFg+M9PjZXOfjc7VfwwI+OLFikttU4U1YusbjMy3wvE/M9RbZxb65yEI7G6fVOzHuymA2RmOQzT5zgkRfb0npDl6r0IBuUUK1gbtxQRjwueXRvOz873JPq3M+EWa/ljVdUzPl8167x8PTHr2fYH6ap1IZGwCMvtNM1EqR7NDhj9VTjNqc1tU4l0wf9pfPDXFFdNKNg8Fi3L1GdPRaac6inTnPxKP/b9+7is0+czDqnpBFQ6TTTORLEaUnYkqwtsxOJxfGHolQ7TRRZDATDsYKI1MYKx7yTddqH/LNW3tsMWppKbZgNWvaeG06JXiH7yKc3sE/+XJYjSqhWOBqN4NO3beaOnTW86cvPpq6X2I186IYmdBqBSa/l5o3lFGXxi1jjtlDjttA5EqDaZeHuq+t58dwQ9z1yYMZjM4nEmlIb0bhkIpn7mu4UcKZvLGNR4+Ssu8HxcKpRelOlHY0Q9HgnGBwPE40nKuC/8u4dvHh2iP/c30Gl08SV9S6EEJzo8c1aj9VSl9iGba0uwqTXcrBjlGF/OFVkOikYLXUuzs1jkZMNOq1IrRpnIxKTxDOIWVOplWKLkZfahjHoNGycspoVGkGV0zxnOUq+XCrLlnxQQnWZUOUy89r1pTxzqh+9VsPn77iCPetK83quT//0GL8+0Z+y9Eh7HaeZ16wtodFjwWHW87c/O8H4FCO5cCxG+1DiQ2QzaFlfbk87lQxE4mysLGLYn5678YeiFJn1rC+30zEcwGLUcax7jIoiE1MtoT54fRNbqov4yKMHAdKcBiabiVvqXWnuBqV2YyqGqYM9J0VqbZkttaqZfviQL31ZmgAGI3HWlNow6jVogDjQNhigP3l/OBpPcwmVcWgutTIWiuAyGygvMiGlZMgfpm3QPyN5nwv5Tn6+FCihukxwWw08dPeV9I9NcGEoQMuUU7lceepY36z/Yn///quodF78l3fIH+bzT54CEoneC0MX7xsPxxjxh9FqRFr+Y3yaQ6bTosdi1KHXpFur2I2J3rLhQBgh4F2ttbz9yhq+8NQpnjreNyM2nUagSViPA7CzzgmQzH3NXkw5dTtVqFajGrclK0tmg1bQMRJkbCLKztqL/vTXr/Xw36cTzt9VThOBUJSKIjOn+nysr3CgEYIhf5hat4Xfn0k8bqHFvFuqMlelLweUUF1mlNpNlNrzn63mDUbSZuQZdRrqi61MRGOEInFeODvE7TurU3/+oRuauTAU4LF9HXSOBGfkXPrHQkz3CD7ZO0ad25IqrnSY9BzpHCUYiaeJmj8cZWOlm1u32PnT163FaTHQ55vgG89mrveabMw91TuWaMLOohByerxGrTaj93quTD+0mPTNmr5CPd4zRn2xhbGJKDKZiWqpc/HcmUGqXWbGJyKEo5LmUhtWg47jPT40gH8iSiQuiUuJw6zDF4yyv33+WrQ1ZTYcJj1xKTnR7WMiWd5y77UNvPfq+gW958VECZUiDbtRx+fvuIJvv9COw6znzdsq2bOulLGJCBohUvVQU3nfdY08tq8DAP20BlnXLEMEqt1mPHYDcZmYXNw1khCtr7x7B8++OshwIIzHauDWLRXsarw4hulffvXqvBXovokoDnN2LSXT432pbZhdDW5O942xpswOwPkBP7F4HJtJh92kx2rUZfQhn8q+tmGuX+vBH4oRl5L2oQBD/jBNJdYZA09L7EbahgKMBMK01rsIhKNE4zAWjFDpMtM+5Meo0+INRnjNGg9do0F21DmRUvDc2aFUSYeUifmNlUUmyopM6LUCfyjGqV5fyrnTbtSlhMxi0HLdGg9v3lrJHTurc5o2falRQqVIQ6MR3LCulBum5bfsptkT8c2lNq5t9uAPRWZ4QzktBsIxmdruCQH1xVYOto+k2mWEgN0Nxdy8qYxbNpVzy6byjK9zpn+cY93ZGdqV2I1ZOXzGMxzxnejxsa3Gye9eTWypDDoN4Wg8KbjB1PNXOk0YtVr6xyZSI6kuPi8Ew3E0AvYnV3ZajWAk6aoJ0OsNcmE4mCraLbGbeOn8ME6Lnh21ThxmPRORGHajLjXmrMsb5OxAouDToNWg1wqOd3sxG7RsrnRwsneMsYko3VNyZFdUF+ELRmjwWHng1g00eKx0jQTpHEkIXiYL5eXG8o9QsSIIx+KpIs5JqlxmEBKB5Mp6F5GoJBCJ4jDp0oZPXFHt5LO3b6Gu2JrxucdDUQ51jPCZn5/gRM8YO2tdtA/7Uy04UzHrNTR4bPOeuE2SaRXhm3ZymKn6f2AsxEAyB9VcakvzRJ9EItOahTUikccz6jQc7/alnFYnt4NaISi1G9FpBBORGEP+MG6Lnj7vBA0lidPU0fEw1zZ76BwJ0Oix4p0wc6rHx7rSmQNH64stPPr+3dhMOqKxOG7rRfeMeo+Vek/mn/dyZF4r4kKirIgvX9qH/HzzuTaOdnnZn9xazJYvWV9up38sRDQeJxqTPPeJ1+KyGjI+78sXRrj34X2MBCLsrHNxuneMsVAUk07D5qqi1GtN4jDrWFtqn3F9NrQawRXVRSlhW1NmQytE4jBBylSD9XxsrS7CH47R55tgbCLKlioH5wcDuK16AuHYDFGdnAC0Z10Jz58dxKDVotMmVlybKx1YjDp0GoFBp2EsGCFOwuO8ymnm+XNDxOIy1eBc5kis7g5e8KY1R3/sxmY6R4I8caSXYCRGZZGJplIbGyscfPx1a5fMsmUuFmJFrFDMS12xlb958yYmIjE++t2DPHW8b9YJv5OlAlaDli++beusIjU2EeEjjx5MrTgOtI9Q5TQTlZJgOMbZgZmtJL5gNKchE7G45OCFUYqtBqxGHa9O8TyfPqVlLjQawZn+cWrdFnbUOlMndoFwFLNeS5ndSL3HmjrVHPKHMGgTJ3fVLgulDhNHOkbZ1eDmaJeXaFyi1wjGwzFaG9x4x0OMBsKcG0w0fb/S6eXlpBg7THoOd3hxWvQIYGuZDbfFwG9PDmA2aFMV8N3eCWJSsvfcMDvrXBTbjBkLcJcjSqgUBcWk1/LPb9/GB79zYN7CSX84NqeofPqnx2eUSXSNBmn0WDk36J/VMDCflPCQPzyjsj8YjqEVZFWbNDweRq8VjATChHoursLiEiqcZs70j9M3FkqJTIPHxrlBP2f6xwmEYzjMemqKLRzu8lJVZKLYZiQQjmHSa5BxiTcYYVOlg/3tI2g0gqsbizncNYpeJjzeY/JiHdRI4OIW3KLXUF9sYWAsxOs3V/CZt25GJwRHur289SvP47EZeev2St7RWktTydJaucyFEipFwbEadXz8dWv5258dJx6XDIyH0sakQ6K/rsppZmeda8b9bYN+fnmslx8cmDmdFy720FU5LdS4rKnevJiUnB/0Ewgv3EQOEkn+bKsU2ocDXNtczIH2Efqm5bhCyRWNRa9JtdXEZXqB5cELozgtetaX2dAm68kmp/o0FFsZD8XoHwuh02g40plYcRWZ9VxR6eD5s0OzxhWTCZF7W0sNf/PmTUBiruA3n0uUeAyOh3jw9+f51vPtPPr+XQuqv1tMlFApFoXttS5+9KFrgIQtzUggnCq8tJt0bK9xZkxkh6Nxbv/q83P2LVY5kxYx3T7GQjNFqamkMElio06b5h1lN+mIxiWxuCQSi6f1BK4rszMajMzwmZpsogaoLbYiSEyUPjTF1WKS0UCEgwEvuxvd6DTQ4LFQYjcSl5KOkTj9YyEcZn3qPXuzGGqxpcrJ/vYRHn6+jR8e6MSo11JiN+ANRLj/+ka+9Xw7wUiMcCzOD1/uSgmVlJKzA+NcGA7Q7wvR5wvRNzZBvy/RON7nm6DKaU79HS82SqgUi45GIyi2GSm2Gdkwd180R7u9aS0jU6koMhGLS55NVmJnojlDnVK+HOv2sb3GycGOUVrqXDMS9JVOE2V2Ewadhr3nh9lc6aClzoVGCCSSUDSOw5RIioNEpxFZTZiJxSWbq5yEookhs5A4wWsbCtBYYkvbDk9u6zJR4zZzsGM05X46FopS5TJzoieRI3zyaC/XrfFQ6jBSZDawvtzO3nNDPHtmkJ8f7pl36147zzCLQqKESrFsiMUlvz89kNZuU2TWU2I34g0mjABn+1BO0uubYEOFg+E5VmTZkmjo1rCrwc25DOI3faLxbCLU6LFS7Tbzu9OzC+xUhBAc6hhhXZmd1gY3UspU6YEGUqu8YqthzpmG/oko5Y6Efc72GidHuryYp5z0tQ0FZtR/Zct1azzcdVV9XvfmgxIqxbIhEI7y25P9qZyT3aQjHpdEojEGxkJohaSxxJbaNk11MDXpNRSZ9dQVW9IM7BZCNC7Z3zZCZIE+TecGE5Xt2fpcTVa9n+obQyMSW92mEitxCfvaR1IJ+Uqnac4t8nAgAsk82MGOUaqd5tQKbaG896p6btpYVpDnyoblfy6pWDXYTXouDCfsgJtLrISjMRDQnvRN6vWFOZQ8wt9U6SAYjrGrwU2x1UCjx0afL8RL50fo9YZorZ+ZpM+VNaW2BYvUJO3DQdaW2nO+Ly4hFI0zGoikimR7fRO8Zo0nrWg2GxYyyXo62dapFQq1olIsK8IxyXDg4nYqFJ2ZLJ/qsHCxLil9ZbFQt8o1pbasPNxzQafN7/mmOz/0+UJ4bEbGsyxGXQyePNrDJ9+w/pK9nhIqRc6c6h3jdN8YEjjW7eXHB7vYXuPimuZirl9bii05+rvUbsy50bXeY8m6yHIuQnlMOy4y61lXZgeR2H4ZC2D5otcKdtS6iMbjnO4t3ETnpS7SvDAcuKTj3ZVQKWalf2yCJw730DUaTBxPJ8cztWdIwB7t8vLksV7gWOpasdXArkY3168t4c6Wmhmi1T82Qc/oBFajlmF/hLYhP0MZ+vdyRSvIK0nsD0U52DGSqvnK5AWfK5urihZlYOrp3sJNR86HuEyUkiihUhScI51etlQXZfXY357q5wOPHCAcy25lYjHO7Bsb8od54kgvTxzp5YWzQ7Q2FBMIR/EFI/z+zOCMxuEyh5E+X+7Tgqezoy4/A7loXM45BScfxmYptVgoVS7LgqfRLITJlqNLhRKqVUQ4ln1OY2edKyuR2lzpYMgfznh8P5UfH+pOGxOeiUKIlFEn5o1lLrq9hfUi7x9f2HtqKrHSNhSYkXMzztI+dKm4acOlO/EDJVSrip112bVHhKIx3v3g3qweq9Nq6MnSH/xSsK3GtaCtlrfAvuG+YJTtNUUzLHDmo9RupNxh4nCXlx21TiQJ76xocltabDXQUu8iFIlxpAA5vVywm3R8aE/TJX1NJVSKGRh1Wm7eWMaRrvk/XO1D/pxcBhYTQcL0biFMRGNsq3ZyqHO0IDEBHExOt5nvSN9i0LKhwoFOIzjSOcrh5Gnfy9O2yK0N7pQ7Q0u9i10NbiSJHJvNqFuUnBgkvO3/7OZ1vGlrJUXmSztaSwmVIiO7m4rh6fkfNxJITKpprXdzqHN01hHzlwJJos3GN5F/7iYSkxgWYVslp4wj1WlEqjl5bZkNp8VANBbndO/YnH7nkOgTPDMlN7U/Qy5uZ52LC0MBBha47ZzEYtDyyD2trCmzX3KBmkQJlSIjYxO5bYEmE9C7GtyzngxeCoosBsodRmqLrRzp8mY9oHQqhayeclr0FFsNHLowyvpyO3aTjpO9Y3hsRvyhKKf7chNVk14zb3vQgfYRql1misw6vMH8nCQaPFY+deuGpCmfGY/NOP9Ni4gSKsUMBsZC/NXjR/O6d+/5YdxTBp1OXT1cCgTQ6wvR6wuljY7PhULFqxFgNehSTdJT5xvONih1PiZFaD4/+M6RIJakj3o2jdBTqXVb+M/7dlPqyH+aUaFRLTSrmDP94xzuHKVtSitGOBrng985kDYcIFfqPAmPqKaShK3JmlIbuxrcGHSL++tWX2zh8JTc0sELozSX5m4Gd6LHV5Dx5luqigo+0XhtmT2roRVAygK5tSFhGwNgz1BGMp3P33HFshIpUCuqVc3HHjvIsW4fQsBtWytpLLHxwtmhBfdxHbwwilZA92iQSFym6n3Wltly3urMxZX1LrzBSOo5i8x6+n3pAmvOkG9q9FgpthmIxiSReBxvMELH8MUPf12xJWWFshCyrUHLljKHEbMhN5/z3mSR7ppSG3EpOTvgZ1tNwn44HI2nTY4GuH1HNbunjCdbLiihWsVUFJk41u1DSuatccqVmGSGiVw4Gqe13s2+9uGsXARmQwjYVJEYDVVk1mMxaKlymjHptTOq3490+WhtcPPS+WE2VNjRazW0DfrpH5tI65Vr9Fjx2I283D7C6b5xTDpNajhnPpTajZzqXbjYTdJa7+Z4t5cLeeb+phaHHppSKtHgsaY1N79+c+ZRZUuNEqpVSjgazyt/sxAm/Y+21zqJRONoNILB8VCap1M2OM36VN5lbCLKmlLbnFXa+9uGafBY01ZJk+I1yblBP+cG/WyudBCNy7R8EkBFkRG31Zg2zHMu6j3WOcfI54oQMB6OpSbMFAqHWceWKkeqFmvYX7iYC4kSqlXKiR4vNW4L5clV1aVkqkCW2nM/TSpzmNJGo8/XShKXzLBEeel8YiJyMBLjwnAg5V+eKfFc7jDRPxaixxuixm3GF4zMe5pWyDF0GkHadJxCYDFo+dd3bmdHrYsnj/XyowOd7GsfKZiXV6FRQrVKOTfo51DHKEIk/lX15XmMvVAaPFYaPFaCkRhdI8E5jeAmKVSP2d7zwzSVWOftx7OZtOxuquBnr/TQMRxkfbkdb3D2bZ1Rp6GjgB/4GreloOUeBp2Gr9/VwtXNHgDe2VrLO1tr6fVO4LFlHl221CihWqVMtmJICRvKHYtWzTwfU193Xbl9VqEy6DQ0eqzoNIKukcJ9aIuthnk91s/0J6Yyf/29LXzxqdMzEvbT0WoEObrbZKSu2EK5w0QwEsNjM2ScDJ0rBq2GL79ze0qkplJetLxO+qaihGqVYpzinT1YoArmhRKLxdlW7eT8UGLkVa3bgsdmJBiJcbjTOyNvVAheahthfbl93uceDUT47C9O8uBdLdzx1edT1w1aDevK7VQWJWyBzQYt7UMBKopM9HgX9nP12IwpIS+2GthUaedYd+4/g8m+wJY6N/9jawUVReYFxbUUKKFapRin1DQ5LQagMJNbFsKZ5Mrm+rUlvHhukLMD/oJNlJmLbOu7TvaO8bknT/Lzj13H139/nn/777MIAX9681pKbEb+8Bt72fupG9l7bpjOkQCdI8G86qjWl9vZXusiFo+zpaqIJ4/20uubYDQYYVuNM+OorenctKGMmzeW0VLvosFjzdnAcLmhhGqVMlkZrdMIvIGFbykKyUvnh9la42Lf+WEuRU17V5YFlAC/Oz1AkVnPJ9+wnt2Nbv7o4X088nwbZoOW3Q3FHO708q+/eZXv3381TSU23v61FzM+j8dmYEtVUZqAlBeZuLOlhq3V6df/6o0beObUAN996QIvXxjBotcQiMx+9Pi3b9nMe3bXZf2eVgJKqFYh8bjk2y+0AXBFdVHaCdpyQK8VhKPxSyJSALVuM2aDds6K79Z6N1/9wx04zXomks6WN6wr5cH3tBCKJibMVBSZ8AYj3LCulAvDAe566KXU/R6bEd9EhJs3lnH7jmquW+NBl6U7pk6r4aaNZdy0sYzu0SA/O9zNK51enjnZj39aucKH9zTzrtba/H4QyxhRyGPU+WhpaZH79++/ZK+nmEkoGuPDjx7k6eN9qWt2o46mUmtaIeBSsqHCXpDK8Exsq3HS4w1SbjcxGozQPhxAqxEYdRrWlNroGA4ynFxhljmMvL2lhls2l7OxwoGU8JHHDvLk0V7euKWC91/XOKdj6hNHevjU40cYDUR47L7dbKp0YDcVzn3gWLeXl84P89yZIZ451U9LvYtH37cbTYGHUlxKhBAHpJQtM64roVpdfO13Z/n7J07OuJ4YTClnVJMvBTesK8Fm1GE36XjiSC/eAtn53ra1kl8c6yUcjbOmNDFxeGeti2M9XgSCD97QRK3bzCudXh5/uYv7XtPI3dc0EIrG6POG+MmhLr749Om059zd6Oa160t5y7aqjP1xfb4JvvTrV/nAa5qoLV68ycJSyhWfhwIlVApg2B/mLf/vuVmL+vI9VSoEb2+pQSJZW2bnnmsaUquCiUiMn77SzXf2XuCVBQzPbKlzcf8NTdQXW/jFkV7OD/n56zdtosisJxCOohEC05ST0IlIDCESq6J/fPIU3mBkxjZrKnfsrOYLb9uad3yKBEqoVjl9vgn+8Ot756ziLvRgg0kyWb2UO0y8/coaqlxmtEJw+87qeZ/nQPsIH/3uwbwdCYSAB9/TwvoKOy7L/MMJvvnceT790+NZPbfdpON3f74Hl3V5FkyuFJRQrWJO9vq47cvPzTvrLpt6olwx6jS8eWsl3z/Qmbp204YyHrxrZ15blYGxEPd9e/+C+hRft7GMB++a8VlIIxaX/OpEH1VOM5//5Sl+d3pg1sf++S3ruPfahrQVmSI/ZhMq5Ue1Chj2h7MayNk25GdNHv5NcxGKxnFa9KlK7bpiC3/x+nV551NK7Ea++/7dvGlrZdq1L75tK1959w621zrndaO8MBQgPo85nlYjuGVTOZurivjae3byB9urMj7uujUe/nhPsxKpRUaVJ6wCHn6uLavHTUTieU0Yno9hf4Tv3LsLbzBxPJ/tsfxsmPRavvSObTSVWPmXX73Kfdc1praOt26pABI5pq7RIOcG/HzzufM8f3Yodf9HbmzO6WTMpNfyxTu3sr3Oxf/56bHUgFJINPcqFh8lVJchA2MhjnZ58U1EON7t46kppQjzUejBtwadhg/taaKppLArNSEEf3LTWiqdZmrdM0/TTHotTSU2mkpsvG5jGS9fGKHPO4Feq+Hq5tyN4YQQvGd3HZsqHXz2FydxmPTcuqWcGy/xfLvVihKqy4xgOMar/WP80cP78rr//GCA7TVODi7ghG0qb9tZXXCRmv78D/zoCNtqnHNuv3bUugryejtqXXzvA1cV5LkU2aNyVJcRvz3Vzx3/9jxn+sfZ3ZjdsNHZqHQWppP+LbPkdgqFEAKPzZjWu6i4/FB/u5cR//z0aY51+3h07wV21rnYXOXI63kOdozS7wtRZM5/wW3QCnSaxMj3xeaP9zRfFsWOitlRW7/LiMGk9e3J3rEFlxm4rQYqneasOvWnM9XmNxCOYTYs7q9ZrgMPFCsPtaK6TIjHZUGM1Sap91jyEqlqpznNi3yhE20UClBCddlwYThQ0PFMbYMBvvruHei1uW2pJl0iLQYtP7j/KvasKy1YTIrVixKqy4DB8RCfeeJEQZ/z2mYPXaNBLAYd22udWQ2uhIuj4F0WA9trXYs+dFSxOlC/RSucT//0GHu+8EyabctCuW6Nh+YyGw6THm8wwsELozjMBkxZiM6pvnG2VTuJxuNs/fRT/ORQV8HiUqxelFCtcE71jqXcOheCWa/liuoiXBY9XSNBnn11kGuai7mmuZhSuxGnRY8uy2ruQ52jjAbCvH5zGa/bqAoiFQtHnfqtYAbGQgzkMORSrxVp7R+TXNVYzBfu3EqV00wsLjnUMcr//slRXmob5j/et5uPP3aQx3OcpHxlfTHbalxYFvnET7E6UL9FK5Qz/WO868G9WU3j3Vzl4K/euJHj3T6ePNaLy6KnyJz4b2edi5s3lqd637Qawc46F39564bUpJp3tNbycsco7UMBHCYd4ViciTkM9vasK+Ef/uCKZT1+SbGyUEK1AhkYC3H3N/dlPTK8zm1ld2MxV9a7uefahqzumTr3bVdjMfdf38TvXx3g796yhfODfu76xt6MRnJlDiMP3X2lKsBUFBSVo1phTERivP+R/XMOIpjOR29cAyRWS/nyztZavvLunbitBnbWuXj4ntaMpQu7GoqVSCkKjhKqFUQgHOVjjx3MuRBTl2MtVDZcWe/mz29ZN+P6unJ7wV9LoVBbvxXCX/34CE8e7c26+tyk13DvtQ3EJYvmXvC+axvZ3zbCb072p6yGx0MLP4FUKKajhGoZEo9Lnjndz6d/epz3XdvA7sZiHnupY4bv+FSEgElX6Z11Lj5+01quXeOZ9fGFQKMR/Ou7tjMaiHB2YBytSCTiFYpCo4RqmXGs28snfniYo10+AP7XT46h184cjjCde65poNc7QSQW59/fk58feT4YdVrKHFrKMoyKUigKhRKqZYKUkgd+dITvH+gkNk2UMtU+TWddmR2LQctt2ypVMltx2aGEapnw8oURHtvXkXbNYdJhNmjp881dhmDWa6kttnDb9kqMOmV5orj8UEK1TJhufNBcauO/PnwNOo2Gbz53nqeP981qmbKjzsnuxtx9wBWKlYIqT1gmlNrTRzzptRosBh0GnYYPXN/EDz54NY++f9eMQQZCQEWROadWGoVipZGVUAkh2oQQR4QQh4QQ+5PX3EKIp4UQryb/r457FsDBjourJa1GcGfLzMnBVzd5eOjuK9MKLaWEHxzo5Lkzg5ckToViKchl67dHSjn10/BJ4NdSys8KIT6Z/P4TBY1uFfGGzRUIBBLJNc0eSu2ZT9GaS228e1cdDz/flrqm0wi21zovTaAKxRKwkBzVbcANya+/BTyDEqq8Mem1WU9suX5tSUqorm4q5qYNZdQVWxcxOoViaclWqCTwlBBCAv8upfwaUCal7En+eS+Q0XhICHEfcB9AbW3tAsNVAKwtt2PQathaU8S37921oB4+hWIlkK1QXSul7BJClAJPCyFOTv1DKaVMitgMkqL2NYCWlpb5C4JWMKOBME6LYdFfp8pp5u//YAtmvVaJlGJVkJVQSSm7kv/vF0I8DrQCfUKICilljxCiAuhfxDhXBMd7fFzVeGncA+7YOTPZrlBcrsx76ieEsAoh7JNfAzcDR4H/At6bfNh7gZ8sVpArhaubPDz0XNtSh6FQXHZks6IqAx5PrhJ0wKNSyieFEPuA7wkh7gXagTsXL8yVwz3X1C91CArFZce8QiWlPAdszXB9CLhxMYJayag+O4Wi8KjKdIVCsexRQqVQKJY9SqgUCsWyRwmVQqFY9iihUigUyx4lVAqFYtmjhEqhUCx7lFApFIpljxIqhUKx7FFCpVAolj1KqBQKxbJHCZVCoVj2KKFSKBTLHiVUCoVi2aOESqFQLHuUUCkUimWPEiqFQrHsUUKlUCiWPULKSzfBSggxQMJfPV88wEqfXb7S34OKf+lZ6e9hrvjrpJQl0y9eUqFaKEKI/VLKlqWOYyGs9Peg4l96Vvp7yCd+tfVTKBTLHiVUCoVi2bPShOprSx1AAVjp70HFv/Ss9PeQc/wrKkelUChWJyttRaVQKFYhK06ohBDbhBAvCiEOCSH2CyFalzqmXBFCfEQIcVIIcUwI8fmljidfhBD/UwghhRCepY4lF4QQ/5j8+R8WQjwuhHAudUzZIIR4vRDilBDijBDik0sdT64IIWqEEL8VQhxP/u5/LOubpZQr6j/gKeANya9vBZ5Z6phyjH8P8CvAmPy+dKljyvN91AC/JFEX51nqeHKM/WZAl/z6c8DnljqmLGLWAmeBRsAAvAJsXOq4cnwPFcCO5Nd24HS272HFragACTiSXxcB3UsYSz58EPislDIEIKXsX+J48uWfgb8g8fexopBSPiWljCa/fRGoXsp4sqQVOCOlPCelDAOPAbctcUw5IaXskVK+nPx6DDgBVGVz70oUqj8B/lEI0QF8AXhgacPJmbXAdUKIvUKI/xZCXLnUAeWKEOI2oEtK+cpSx1IA7gF+sdRBZEEV0DHl+06y/JAvR4QQ9cB2YG82j9ctajR5IoT4FVCe4Y/+ErgR+LiU8odCiDuBbwA3Xcr45mOe+HWAG9gNXAl8TwjRKJPr4eXCPO/hUyS2T8uWueKXUv4k+Zi/BKLAf1zK2FY7Qggb8EPgT6SUvqzuWWafj3kRQngBp5RSCiEE4JVSOua7b7kghHiSRE7kt8nvzwK7pZQDSxtZdgghtgC/BgLJS9Uktt+tUsreJQssR4QQdwMfAG6UUgbmefiSI4S4CvgbKeUtye8fAJBS/sOSBpYjQgg98DPgl1LKf8r2vpW49esGrk9+/Vrg1SWMJR9+TCKhjhBiLYnE6IppMJVSHpFSlkop66WU9SS2IDtWmEi9nkR+7c0rQaSS7APWCCEahBAG4B3Afy1xTDmRXFh8AziRi0jBMt36zcP7gf8rhNABE8B9SxxPrjwEPCSEOAqEgfcut23fKuDLgBF4OvHZ4UUp5f1LG9LcSCmjQogPkzhp1QIPSSmPLXFYuXIN8B7giBDiUPLap6SUT8x344rb+ikUitXHStz6KRSKVYYSKoVCsexRQqVQKJY9SqgUCsWyRwmVQqFY9iihUigUyx4lVAqFYtmjhEqhUCx7/j+DExp/pMVvAgAAAABJRU5ErkJggg==", + "image/png": "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JavFkKpAIEAEJkGehGNJTo/4sn7v3de2cuvGOvZ2O/nSn88WZJP+gZes4CWrqwBwGDUlWatAILi0EYFJkBd6jZJmh4FeZ+Yczw2rq7jvtg1AyrL8ts31PH12jN8cHqSzyznnNavNWq5ZUVG2NQsEgksTUWUW5IUsy2xrts36ujMQzfh7c0XKXuJnH7iK7757Fy0VhpzXXFVjosc5e2BVIBBc2YjAJMiLI/0e/i+LCGudNfuMkSRJ3Limml995FrqczzmuXMT/OXPDxGICP8igUBwkYIC0/33348kSRl/1q5dm/5+OBzmnnvuoaKiApPJxF133cXIyEjJFy1YfNbUmjFqlOm/69VK3rSziX9/45Y5n+cwavj716zP+f1YQubCWKBk6xQIBJc+BdeYNmzYwGOPPXbxAqqLl/jkJz/Jww8/zIMPPojVauWjH/0od955J88991xpVitYMnRqJc9/5uU8e3acSpOGjQ1WjNr8fn1u3VjL1iYbh6YN406xqcHKxgYxSC0QCC5ScGBSqVTU1tbO+rrH4+Fb3/oWP/7xj3nZy14GwHe+8x3WrVvHiy++yFVXXbXw1QqWFKteneGJlC+SJHHblvqsgen+124Qjq8CgSCDggPT2bNnqa+vR6fTcfXVV/PAAw/Q3NzM/v37icVi3HTTTenHrl27lubmZl544YWcgSkSiRCJRNJ/93oLk7MRXBqYp52uzDoVv/rINVj1mrS9uUAgEExRUI1p9+7dfPe73+X3v/89X/va1+jq6uL666/H5/MxPDyMRqPBZrNlPKempobh4eGc13zggQewWq3pP01NTUW9EcHy5oY1VWn18Qfu3MTKarMISgKBICsFBaZbb72VN7zhDWzevJlbbrmFRx55BLfbzc9//vOiF/CZz3wGj8eT/tPX11f0tQTLlxqLji++aStWvZpXbpidChYIBIIpFtQubrPZWL16NefOnaO2tpZoNIrb7c54zMjISNaa1BRarRaLxZLxR1A8sizzb384tdTLyMpN62v47UevQ6UUUwoCgSA3C9oh/H4/58+fp66ujh07dqBWq/nzn/+c/v7p06fp7e3l6quvXvBCBfkhSRJv3tWMN1y4yvdi0DzHwK1AIBBAgYHp3nvv5amnnqK7u5vnn3+e173udSiVSu6++26sVivvfe97+dSnPsUTTzzB/v37efe7383VV18t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", "text/plain": [ - "<Figure size 576x576 with 1 Axes>" + "<Figure size 800x800 with 1 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1729,7 +1709,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 65, "metadata": {}, "outputs": [], "source": [ @@ -1749,19 +1729,17 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 66, "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABZcAAAUZCAYAAAAfSj80AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAEAAElEQVR4nOydd3ijV5m376NeLUvu3Z7e+zgJ6SSkkRAIIYRQA/mS0HeBQEJf2FCXpS8bYEmAhBJCGiSk9za9d4/LuHfJRV063x+SHXss25It93Nfl6+x9LYjj877nvM7z/N7hJQShUKhUCgUCoVCoVAoFAqFQqFQKFJBM9MNUCgUCoVCoVAoFAqFQqFQKBQKxdxDicsKhUKhUCgUCoVCoVAoFAqFQqFIGSUuKxQKhUKhUCgUCoVCoVAoFAqFImWUuKxQKBQKhUKhUCgUCoVCoVAoFIqUUeKyQqFQKBQKhUKhUCgUCoVCoVAoUkaJywqFQqFQKBQKhUKhUCgUCoVCoUgZJS4vIIQQHxFCvDJF575HCPGfU3FuhUKRfoQQ5UIIKYTQxV//Swjx4Zlul0Ix2xBC1AohLp7K44QQh4QQF6R6DYVCMTEm2q9TvMaXhRC/jf8+7JmrUChGMonn7ZTNQ4UQpUKIPiGEdirOr1DMF6bjuToR1Jx3+lADHIVCoZhjCCE+AtwkpTwnXeeUUl6ernMpFIrUkFKunuk2KBSK9CKl/M5Mt0GhUEwOKeUpwDbT7VAoFOlBzXmnDhW5rFAoFPMQFWGhUCgUCsXkUJHGCsXCRfV/hWL6UXPYuYsSl+chQojbhRAnhRC9QojDQoh3jbLfT4UQ9UKIHiHELiHEuUO2fVMIcb8Q4g/x8xwSQmwZsn2jEGJ3fNtfAdM0fDSFYk4yWp+M97N7h+x3etrOR4QQ1fHjaoQQ7xdCrAT+Fzgrnqbnju97jxDiV0KIx4UQ/cCFQoi3CyH2xPt4vRDim2O08QUhxE3x3xcLIZ4TQnQKITqEEPcJITKn6u+jUMwBtsb7brcQ4m4hhAlACHGlEGKvEMIthHhNCLEu0cFCCLMQ4vfx448IIb4ohGgYsn0wlfD09F4hxAUJ9r1NCLFfCNEvhPg/IURePM2vVwjxjBDCOXV/CoVi3jCiXw/0NyHEl4QQLcDdQginEOKfQoj2+L7/FEIUAwghBp7FAz9+IURtfNuwZ7xCoUiKRP1yhLVjfLy8JNEJ4s/YZiFEkxDipqH7jjU2HjIO/5gQ4hTwXIKx+Y3x53hvfIx+y9T9KRSKOUfK/XeUOezgvDS+z7BzxI+/VQhxIj4G/6UQQsS3aYUQ/xWfw1YDbz/t2sPOrUgfSlyen5wEzgUcwH8A9wohChLstwPYALiAPwF/G5gwx3kH8BcgE3gU+AWAEMIAPAz8MX7s34B3p/9jKBTzhmT75CBCCCvwM+ByKaUdeAuwV0p5BLgVeF1KaZNSZg457AbgTsAOvAL0Ax8i1offDnxcCPHOJNorgO8ChcBKoAT4ZhLHKRTzlfcDlwKLgWXAV4UQG4HfAbcAWcBdwKNCCGOC478BlAOLgLcBH5hke94dP88y4CrgX8CXgRxiY7vPTPL8CsVCYES/jr+fT2x8WwbcTKxP3R1/XQr4iI+JpZQDz2Ib4AS2AX+exs+gUMw3RuuXSSGEuAz4HHAxsAS44LRdkhkbn09s/Htpgku0AVcCGcCNwI+FEJtSaaNCMY+ZaP89fQ6bDFcCW4F1wHW82V//X3zbRmALcG2S51NMEiUuz0OklH+TUjZJKaNSyr8CJ4DKBPvdK6XslFKGpZQ/AozA8iG7vCKlfFxKGSEmJK+Pv38moAd+IqUMSSkfICZUKxSKBCTbJxMQBdYIIcxSymYp5aFx9n9ESvlq/Dp+KeULUsoD8df7iU14z0+ivVVSyqellAEpZTvw38kcp1DMY34hpayXUnYRG/y+j5jodJeUcpuUMiKl/D0QIPaMPJ3rgO9IKbullA3EFo4mw8+llK1SykbgZWCblHKPlNIPPERsQK1QKMYmUb+G2LP3G/FnoC8+Vv67lNIrpeyN75vomfgzoBf4yrS0XqGYn4zWL5PlOuBuKeUhKaWX04Ijkhwbf1NK2S+l9J1+cinlY1LKkzLGi8BTxAJIFArFxPvvsDlsksd8T0rpjvuiP08saBJi94CfDGnHd1P5AIqJo8TleYgQ4kND0nTdwBogO8F+X4in9Xji+zlO269lyO9ewBRPCSoEGqWUcsj2unR/DoVivpBsnxyKlLIfeC+xKOVmIcRjQogV41yq/rTrniGEeD6eyuuJn2vM68aPyxNC/EUI0SiE6AHuTeY4hWIeM7Rv1RF7DpYBnx/o1/G+XRLfdjqFp52jPsE+qdA65Hdfgteq+JBCMT6J+jVA+9DJrRDCIoS4SwhRF38mvgRkiiG+kPHU+AuAG6SU0alvukIxbxmtXybLmM/bJMfGoz6jhRCXCyHeEEJ0xZ/7VyQ4XqFYqEy0/05kXHy6VjUw9j39HqB0qmlCicvzDCFEGfAb4FNAVjxl/iCxNPeh+50LfJHYyo4zvp/n9P1GoRkoGvC1iVM66cYrFPOQcfpkP2AZsnv+0GOllE9KKd8GFABH4+cBGLqwM+yQ017/iZilTYmU0kHMqzmZPv6d+LnWSikziKXwJ3OcQjFfKRnyeynQRGzgeqeUMnPIj0VKmSglvhkoHuV8pzPmfUGhUKSNRP0aRj5LP08ss++M+DPxvPj7A/6O5wLfBq6WUvZMXXMVigVBon457LkohBjruTje8zaZsXHCcXbc9urvwH8BefEx/eMJjlcoFioT7b+n97nJjIWbE7RDMQ0ocXn+YSXWOdshVnSAWJTk6diBcHw/nRDi68S8o5Lh9fixnxFC6IUQ15Bcir9CsRAZq0/uBc4TQpQKIRzAHQMHxaOHr457LweAPmKpuhCLUiyO+5+PhR3oklL6hRCVxPysksEev55HCFEE3JbkcQrFfOWTQohiIYSLWMr7X4kt9twaj4ISQgiriBUKsic4/n7gDhErDFZEbLFpNPYCVwghXPEB+L+l96MoFIo4ifp1IuzEMgLc8X2/MbBBCFFCrH9/SEp5fKobrFAsABL1y33AaiHEhnh9oG+Ocfz9wI1CiJVCCAvwtdO2T3RsDGAgZiPZDoSFEJcDl6RwvEIx35ls/x1gL3BNPHNoCfCxFNpwPzGdqljEClzfntInUEwYJS7PM6SUh4EfEROAW4G1wKsJdn0SeAI4TixVwE+S6QhSyiBwDfARoItY6v6Dk2y6QjEvGatPSimfJvbQ3Q/sAv455FANsYIkTcT62fnAx+PbngMOAS1CiI4xLv8J4FtCiF7g68QetsnwH8AmYtkMj6H6t0LxJ2K+itXECnT+p5RyJ7GiIb8AuoEqYs/FRHwLaABqgGeAB4gtGiXij8QG4rXxa44meCkUiskxol+Pst9PADPQAbxBbPw8wEVAHvCAEKIv/jNefQSFQjE6iZ63x4k9R58hVrdk1IJfUsp/EfM/f57Yc/mN+KaBZ+5Ex8bEPdc/Ez+mm5gw/WiyxysUC4BJ9d8h/BgIEps7/x64L4U2/IaY1rUP2I2ax04bYrhtrkKhUCgUCoViKhFCfBy4XkqpCmUqFAqFQjFFCCFWErOjM0opwzPdHoVCoZivqMhlhUKhUCgUiilECFEghDhbCKERQiwn5uH60Ey3S6FQKBSK+YYQ4l1CCGM8Jf77wD+UsKxQKBRTixKXFQqFQqFQKKYWA3AX0EvM1uYR4H9mtEUKhUKhUMxPbgHaiKXlR3jTVk6hUCgUU4SyxVAoFAqFQqFQKBQKhUKhUCgUCkXKqMhlhUKhUCgUCoVCoVAoFAqFQqFQpIwSlxUKhUKhUCgUCoVCoVAoFAqFQpEyupluwOlkZ2fL8vLymW6GQjHt7Nq1q0NKmTPT7Zgoqu8qFiqq7yoUcw/VbxWKuYnquwrF3EP1W4VibpJK35114nJ5eTk7d+6c6WYoFNOOEKJumq/3HuCbwEqgUkq5c8i2O4CPESuC8Rkp5ZPjnU/1XcVCJd19VwhRS6zwWwQISym3jNVfxzt2vOupvqtYiEz3MzfdqH6rWKiovqtQzD1Uv1Uo5iap9N2kxGUhRCbwW2ANIIGPAseAvwLlQC1wnZSyO8GxpfFjS+LHXiGlrE22gQqFYso4CFwD3DX0TSHEKuB6YDVQCDwjhFgmpYxMfxMVigXLhVLKjiGvE/bXJI9VKBQKhUKhUCgUCoViSkjWc/mnwBNSyhXAeuAIcDvwrJRyKfBs/HUi/gD8UEq5EqgE2ibXZIVCkQ6klEeklMcSbLoa+IuUMiClrAGqiPVdhUIxQ4zRXxUKhUKhUCgUCoVCoZgxxhWXhRAO4Dzg/wCklEEppZuYAPX7+G6/B96Z4NhVgE5K+XT82D4ppTctLVcoFFNFEVA/5HVD/L0RCCFuFkLsFELsbG9vn5bGKaafrv4gwXB0ppuxkJDAU0KIXUKIm6fxWIVCoVgQeLwhnj3SSo8/NNNNUSgUCoVCMQ24vUGeOtRCW48fKeVMN2fekUzkcgXQDtwthNgjhPitEMIK5Ekpm+P7tAB5CY5dBriFEA/Gj/2hEEKbnqYrFIrxEEI8I4Q4mODn6nScX0r5aynlFinllpycOVujQTEONqMOIWa6FQuKc6SUm4DLgU8KIc5L97FqYWhu0t0f5L5tddzx4AF+/1ot3f3BmW6SQjEn2d/o5mO/38lrVZ0z3RSFQqFQKBRj8NNnTvC7V2omJQj3+EN8+cED3PzHXVR+51n+98XqNLZQAcl5LuuATcCnpZTbhBA/5TQLDCmlFEIk+p/WAecCG4FTxDyaP0I8CnqAeHTVzQClpaUpfgSFQjEaUsqLJ3BYIzGP9AGK4+8pFihtPX721ru5cn3hTDdlQSClbIz/2yaEeIiYLc1L6TxWSvlr4NcAW7ZsUUv304yUkuOtfeys62LPKTeN3T62ljv53CXLRz1me00Xn/rTbtp6A4Pv/faVal7+4lvHvM6XHzqAy2rgg2eWk+8wpfVzKBSzkWA4ikGXOH6mye3j589V8ffdDQC8cKyNt63KQ6tJzwqqxxfCYdan5VwKhUKhUChgX4Ob54628fyxNooyzXzigiWUZlkS7iul5L13vcEVa/N5+7pC+gJhXjvZwW9frqGmo58luTaq2vr42bMnqMi2ctma/Gn+NPOXZMTlBqBBSrkt/voBYuJyqxCiQErZLIQoILGXcgOwV0pZDSCEeBg4k9PEZTXJVShmFY8CfxJC/Dexgn5Lge0z26SFTWdfgCybEbc3iFGnpcsbJByJ0tUXZGOZM6lzNHt85GeYEBMIQT7S0sun/ryHiJRcvSGhQ4oiTcQzgzRSyt7475cA35rqYxXTgz8U4a4Xq3loTwO1ncNdwgoyEwu/Ukp+83I133/iGJHo8CFSjs045vUe3dfEn7fHXI7+uqOBRz51NkWZ5kl8AoVi9vPbV6o52dbPOzYUkmU1sDjHxr/9dQ9d/UH2nHITHtKP/rKjnms3F7Ol3DXp6+5vcHPj3Tt45nPn47QaJn0+hUKhUCgU0NAdGzO/fCJWr/yl4+08/Mmzyc0YOXZ+aE8j22u72F7bxTf/cXjE9iyrgSrAF4pw6727+NzblvHpty6Z0BxZMZxxbTGklC1AvRBiIJzmIuAwMQHqw/H3Pgw8kuDwHUCmEGIgX/6t8WMVCsUMI4R4lxCiATgLeEwI8SSAlPIQcD+xvvoE8EkpZWTmWrqwiUYlP3jyGBf/94uc8Z1n+d2rNVgNWh7d28RLJ9r58kMHiEbHXpPr7Atg1Gom/NA82OgB4I3qrgkdr0iJPOAVIcQ+Yos6j0kpnxitvwohCoUQj4917Ax8BsUoaDWCBxMIywAmvZZDTR5eO9nBjtoumj0+9je4ufmPu/jO40eHCctvX1vAW1fksqbIMeq1njjYwm1/2z/4uqMvwPGW3vR+IIViFnLreYvx+IJ8+HfbueoXr/DFv+/nyUOt7KjtHiYsA1RkW1lRkDHpa/pDET5+7246+4O8Xq2sNhRTi/IKVSgUC4nTgyuaPH5u+sNO3N7h9nAHGz3c8eCBMc+1p96NzfimU+9/P32cq37xCn/bWc/OWjXXnQzJRC4DfBq4TwhhAKqBG4kJ0/cLIT4G1AHXAQghtgC3SilvklJGhBBfAJ4VMVVjF/CbdH8IhUKROlLKh4CHRtl2J3Dn9LZIkYhGt48zKlxsLXfR1uvn5nMXodNq+PRFS3n+WBs33r2DN0528pYlWawrzuRdG4uISolRpyUYjnKyvY9luTY8/vCErh+ORHnxeMyT93CTh/ouLyWuxGlIiskTz/RZn+D9hP1VStkEXDHWsYrZQyQqMekSl57407ZT/GnbqaTOU9vZz/J8O95ghK8+fACHWc+mUidnLc4iGI7y8+eq+N2rNQzVH9YWObhgufLGV8x/NBrB6kIHzxxpQ0r4x76mUfc9b2k2NmOy06HR+fHTx2l0+wCo6eif9PkUitH4y/ZT/Py5KsqzLXz6rUs5c1HWTDdJoZgVCCF+CFwFBIGTwI1SSneC/WqBXiAChKWUW6axmYoJkGM3crJ9+LN1f4OHK3/+Ct+4ajVvXZFLbWc/t/xxF4FxitAHw1FW5DvY3+AZfO9gYw+3PbCfX96waUrav1BIajQlpdwLJOp0FyXYdydw05DXTwPrJtg+hUKhWNCUuCyUuCxEopL/e6Wae9+ow2bS4/YGeSmeGlTd0U91Rz9wiq89fBCLQcu1m4t56nArm8ucXLW+kJ88c4I737lmzEjHRPxlRz17690A7Gvw8Hp1pxKXFTNKOBKlPxDBYZl7vqYmvZaHPvkWPnrPjkllAhxq6uFQU8+I93UaMSIycwDlA6tYSFy9oZCfPnti3P2W5tmTPmckKolE5Qg/Z483xB/fqBt8/Y99TXzywiXJN1ahSJInD7Vwezwqr9Ht49WqTiorXPzbRUs5a3GWSuuew/T6Q7i9sZ+azn7c3iDv3lSMNQ2LXwuIp4E7pJRhIcT3gTuAL42y74VSyo7pa5piMmSPYgPX0O3j//1hJwadhlAkSrJJHVVtfRRmmmhy+wff+9g5Fbx9XUE6mrtgUXcrhUKhmOU0uX3c8eCBwQjisQiEowTCUX7zcg0AdZ1enjzYQrHTQrEzda/VsiwLQjD4sP7BE8e4cl0BFoN6fCimnkhUcrK9j/0NHg40uNnf6OFwUw+Xr8nnJ9dvnOnmJeSFY2209vi5eGUe//bXvWSY9Fy2Jp9VhRnYjDrCUYleO64r2YQYTVgGeKWqgw/fvYMfXruOvAQedQrFXCIalWjGKMJX4rLwwK1ncfcrtTx2sHnU/f6xr4kPnFk25rUe29/MPa/VcLK9n40lmdx83iIiUUlVex+Lc2z8ZUc93uCb7mFHW3o53NTDinz7mG1UzD2EEFpgJ9AopbxyyPs/Az4qpbRN5fVfqxqphW2v6eKG325jc5mTT791CectzVHfuzlCOBLlqcOt3PNqLdsTpOP/15PHuHBFLhXZViqyrWwuc5JjN2IcJQNqoSOlfGrIyzeAa2eqLYr0Eh1HNQ6OE618Ot5ghGW59kFxOdtm5AtjFNVWJIdSBxQKhWIW4wtG+Og9Ozg6Ca/U/mCED5xZSqYl9QJDj+xtGrYK3NEX4NWqTt62Km/C7VEoRqO2o5+99e6YmNzo5lBTzzDRZoAjzbPTO1hKyb1vnOKZI6088zkX79xQxOf/to/HDowubk0nLx1v5zN/3sNfbzlrppuiUCRNi8ePJLYoE5WS10928sfX6/jgWWWjFpnt7Avy7X8eZl+Dh2V5No639iXcb88pN+29AXLsb0ZFBcNRfvdqDU1uH3qtBqdFz47abgCaPX4++9e9tHj8Cc83wDf/cZAvXroiLYUCFbOKzwJHgEGj7rglZHLVlSfJWOneu+q6+cjdO8jLMLI8P4OVBXY+dFa5KuI6S/AFI+xvcHOg0cOO2i4C4SgHGz109AVHPabHH+aRvcNtfc5Zks29N50x1c2dD3wU+Oso2yTwlBBCAndJKX89fc1SpEo4EuXVqvTWMjDrtRxuftMW432VJZgNatFmsihxWaFQKGYxoWh00MdxIqzIt/OLGzaRM0o60XhUt4+ckB9q8ihxWZE2AuEITxxs4Y+v17GzrjupY3IzJvZ9nkqC4ShfffgAzxxpBeDGe7bzgTPKhkX+zwa21XTxxzfqOGdJNv2BMBaDlkU5Uxpsp0gCIcRlwE8BLfBbKeX3ZrhJs4Zb/riTfUO8EQfItOgTisv76t389NkTg8c0dvvIshro7B8p4gQjUa7939f45Q2bKMw08/VHDvLc0baEi1oAh5tjdjSV5U5aegKc6hpZnBNge0031/7v6+z52ttwWlNf2FXMPoQQxcDbidUk+Vz8PS3wQ+AG4F1Tde3DTT3sPtU9+P0bi9aeAK097bx0vB27Ucen3rp0qpqliBONSk609dLs8dPa46fFE6Clx0+Lx0dLT4DWHj9dCe4/E+GVqg4+99e9XLOpmLOXLDwrFCHEM0B+gk1fkVI+Et/nK0AYuG+U05wjpWwUQuQCTwshjkopX0pwrZuBmwFKS0vT0n5F6uytd+PxhdJ6zkA4Qo7NSGtvAI2A91Wq/990oMRlhUKhmCG6+oN4g2GKnYk9jHv8Ic76zrP0jzLJTQabUYdRp+F4Wy/L8+1kmJL3Xe3sC7D7lHvE+30TLA6oUAylvsvLn7af4v4d9QlFn7Ew6ceOLgiEI3i8Ieq6vLT2+NEIQbHTzPJ8+5Skk+6q6+Z7/zoyGN0IUN/l47v/OsptlyzjcHPvrIleBvjawweHvf7Re9bz7s3FSR3b1uunvsvH8nx7WgqhKQYFql8CbwMagB1CiEellIdntmWzg4+cXc4Lx9pHRPC9frKTz9+/j+9es5ZmT2wR9s7HjvDU4dZh+/UHI6wudNDZn9jnvK7Ty6337qK9NzBuIaABttd2U541dv2B85flYDGqSKh5xE+ALwJDjbo/BTwqpWxOt8jnD0Vo6PbS5PbzqT/tpieFsVe2zciWMifv2VKS1jYpYkSikpqOPg419fBGdRdPH26lqz/AhpJM9tW7iUzxgvKDexp5cE8jt5y/iA+fVY4kJnBDzD6gxxdmT303FdlWzl06vwr5SikvHmu7EOIjwJXARVImXtqXUjbG/20TQjwEVAIjxOV4RPOvAbZs2TKLwgQWFq+fTG/UMkBUQmmWhdbeAG9dkUehyvBIC2pWoFAoFNPMqU4vzxxppaHbx33b6vjgmWXcdtnyEaLXL5+rmpSwDJDnMJHvMHHJj1/i+S9ckJK4bNJrsRt19AaGT2hePqHqXygmRjQqefFEO/e+Xsdzx9omHNH74vF26jr7Kcuyjtj2k2eO89NnTyQ8t14rWFmQwbpiB+uLM9lQksmSXNuEIn96/CGeP9rG33Y28EoCH0wAjYgV3Hz6SGvC7bOF2s5YBe5wJEp/MIJRp8Gg1Qz6doYjUbbXdvG7V2p59mgrUoLVoOVLl6/gQ2eVz2DL5w2VQJWUshpACPEX4GpgwYvLjW4fBxt7CIRGir79wQh/393Aq1UddPUHcVj0tPcGEp9onC7u8QaTFpYHqO30UlnuSuiVuq7YwS3nVShv1HmCEOJKoE1KuUsIcUH8vULgPcAFSRyfUgRkfZeXy3/6Mn2B1Bbzv/r2lVy+toBCh2nBRbROF3/f1cD3nzhKW4J7ze5T7jFteNLNXS9Wc9eL1aNu31iSSZbVyKrCQRcX6jr7B8fx7z+jdF59T+IZQF8EzpdSJkwrEUJYAY2Usjf++yXAt6axmYoU6fGnN2p5gIFxxbVJBlcoxkeJywqFQjFNNLm9PHukjUA4yn8+dmTw/d++UkO3N8QPr103KOb0+kM8uq9ptFMlRa7dyLevXoNOI3jxixdg1KY2ybUYtAkLhB1r7eWnz5zgyUMtXF9ZosQlxbi09fh5cE8j922ro75r4jYvAwTDUd71P6/x1bev5PxlOWTFbV+C4Si1Hf2jitahiGR/g4f9DR7u5RSQmn9he2+Apw+38uShFl472UFonPAkq0HL4wdbUi40Mt38/rVaXjrezuHmnmGfSacR6LUaIlKO+Az9wQhff+QQFyzLpXScCE7FuBQB9UNeNwDKVBM42tzD/71SM+Y+LT0x/+NRhWUgMkpfPaPCFSsUJCV76j1jFsVMhC80UvzbWJrJOzcU8trJTlp7YlFRDkvyC7uKWcnZwDuEEFcAJmKey4eAAFAVF+gsQogqKeWS0w9ONQLyVJc3ZWG51GXhY+dUzCuxcLbxm5equfPxI2Puk59hxGbU0d4boL7bh1mvwZdgcWyqsRq0HG3t5X2/eYOvX7mKlh4/b1R3DgsQsRl1vHNjYt/6OcovACMxqwuAN6SUt8YXgn4rpbwCyAMeim/XAX+SUj4xUw2ezUSiEu0sKA46mk3VRFmcYyXLZmRnbRc6jeCsxVlpPf9CRonLCoVCMU3c81odv34pcYTB33c3sDzfhlGnpSjTzMrCDD570VJuf/DAhK/3+UuW4Yp7PebaTSkfL4QgL8NIbefIxf8fP3McgK8/cogTrX18+YqVqhCCYhj+UISnD7fy990NvHS8nRQ1m3FZnGPl83/bh5SxCZJOK3B7U49uONzcQzgSRafVJNwupeS1k5388vkqXq/uTCnaujcQobLCxfaaxOn4s4XCTHNCT9twVBKOjj2o31HbpcTlaWIh+j+WZVlxmPWT9lvUJOje60scbBvSNydynSPNPawvdgz2nzMXubjlvEUcaIwtYjV0+3jpeAcZZh0XrMjlwuW5k/ociplBSnkHcAdAPHL5C1LKK4fuI4ToSyQsT4QnDrakfMzla/KVsDxFeLwhfvXiSf7vldGjhAG2ljt5vbqLUESi0wjWFTuobu9nRb51UoW5U2FjSSZ1nf1kWg1Ut/fjI8Ln/7Yv4b73vlE3r8Tl0fqflLIJuCL+ezWwfjrbNZeoauvj4/fuotnjpy8QpsBh4obKUm44o3QwkGO68YXSJy6vLcrgQGMPJ9tjGXufunAxDrNa/E0XSlxWKKaQzr4AESknJOwp5g/+UJjnj7azt9495n6vnezkhWPtLMm10d0fnPRq8Q+eOIYQgvdsLp7whGM0wW0of3yjjndtKmJT6bQUS1fMYqSU7Krr5u+7G/jn/mZ6p9Cf2xuMDAq9qUZ4DaWrP8i7f/UaZy3ORiKRMmbfEZXgD0fYV+/mUNP4RZRGb2cYnUakHBE5nXT1B1lX7GB/AoF5PL709/28dKKdjSWZrC5ysKEkE30S9w3FMBqBoeaoxfH3hrEQ/R+X5Nr4zYe2cN1dr0/qPAN+tXl2I5lWAxa9ZsTzbUW+fZjYnAzhKIOFumxGHdlWI2dUZPGFv+0f4SW/ujCD54+2DRbpfduqPPIy1PhQMZJtNal7jA61PhiLRrePXXXdtPX46ewPotcITAYtZn3s54xFWVRkj7ScWoj4QxHufrWWX71QNa7n9RkVrmH3j3BUDj5Tj7b0UlnuZHttckWLJ0pFtpU98blGVxKL7TvrujnR2svSPPu4+yoWBt/+52FOtL1p69Ls8fOjp4/z8+eruGhFLhtKMilxWVhfkknRNPkUawXoNYLQJMfRG0oyOdT05jj3/51bwb+/bdlkm6cYghKXFYopwBeM8MW/7+ef+2O2Bv9zwyYuX1sww61SzBT/83w1f9tVn9CfbSgvHGsf/D3VAmeJ6OwP8sUH9vNGdSdfvDTm6ZxK1fq6zn6q2pLzjUt3FV/F3KK+y8tDexp5cHdDwkj3qcDtDbKpNDNh0clU2dfgSRi5mw4ONvaM6ss6W2jrDdDWG2BzmZNddalNfsNRySN7mwaLrZW6LNxy/iJ0GkFjt4++QISr1hewUS0+jcUOYKkQooKYqHw9cMPMNmn2sKk0k0XZVqo7+id8jur2PjaXOZFSjnrP2FbTxcaSzEFxJlnqu31UlrvIdxjxh6L86sWTI4qOlmVZsBp13HjPjsH3fvjkMa7eUMg1m4rYUOKcNSnIirGRUr4AvJDgfVs6zn+yvW9Cnr2/eK6KHLuRsiwrvf4QPb4wvf4Q3d4QPb4QVe197K7r5lhr77gZOG9ZnMX1laVsKXOiEYKqtj6aPD62lrsWjPAspeT2v+/n4b1jW9QZtIL1JZnjPju313ZT4DBR5DSjQXC0tYceX5jFOdbBKMqJsDTXhlmvpb7bS47dSE2K98kfPXWcH7xnXUo1WRTzl+OtiSPsg+Eo/zrYwr/iWRVCwA2VpfznO9dMecZEbacXBKwqsGPSayc07j89i1CnEdx26QqEEESjkheOt2HUaTl7SXYaW77wUOKyQjEFPHOklX8M8cvdUdutxOUFjBCxld+Z4sHdjbx8ooMb31LOB88qw57kADKVKMbtNV0q3XcBsquui/95/iTPHm2b9ms3uv109QexGXWTilyeDvzh9PrFTRW6NAhbp7q8fOWhg8Pe+8PrtdxxxUo2lGTS6PZx1qIscuwzk145G5FShoUQnwKeBLTA76SUh2a4WbMGnVYz6cj/UESyt95N/jiRwnvq3Wwtd3K0uXdEMdvRMGg1rCrMwB+O8PzRJp472sbmMieNbh96reC9W0tYkZfB33cPD0b3+EI8d7SNP7xex9UbCtlQksmHzyofrL2gWJg8tr95QsedaOvjht9sG/ZeRbY1ZbERYpl0r53sJMdmpL1veGDEOUuy2VzmZGVBBisL7JQ4LRP6znb3B2nt9VPmss46WzV/KMJXHz44rrAMsKbIwY4kI5KbPf7B+cDSXBslTg1HmntSXih3WQx0eYOUuSzDokwnYsH1xKEWXqnq4KKVuVy+poALlueMWBxTLAw8vlDS81Up4U/bT/GNq1Zj0E3dM6ujL8C+eg+hiORwcy9CvGltMR4uq54luXYiUZmwb9y3rQ5fKMLfdzUghOD+W86aio+woFDiskIxBVy8Mm9wJdpu0nHj2eUz3STFDPDQngZsRj2tPX60GkFkBtPi23sD/ODJY/z2lRpuOW8Rt5y/eNj2RJ6zqUxIko1wVsx9pJS8fKKDXz5flXIKebpZVeBg16mpTTOdLHl246wu6Lck10qW1YiUclKRoWMRjkq+/c/Dg6+/d81arq9cGJ7BySKlfBx4fKbbMRvp9Yc41TX5jIhIVA5aUozFjtputGJkmvtoBCNR7nmtdth7VoOOazcXEY7ErNF+8uwJOvpGZi9l2Qw0dPsGo//rOr188x2rk/5MivnH1RsKuW9bHa09Y2e7jYVJp2FdiQOPd3ILr4kKVr5S1cErVW8WhbMatKwoyGBFvj0uOGewPN+OzThSZghHopzq8vLz56p4eG8jUsYWZ7aUOzlnaTbnLc1hVUHGjC6wPHWohdsfPDBodzMex1p62VzmRAg41ekdN0txgKGi8O5T7qTrMwxkGG0sycSg01CXhntjXyA8eA+yGLS8dUUuV6wt4Jyl2SqieQFxYpSo5dGQMmaj8R/vWD1lffauF08SjLw5hpYSTnX5sBm09I1S6M9lNVCRbeVYS8+ofSoclfzHP2Lj0lKXhb/deuZgnSLFxFHiskIxBZgNWp7+9/PZWdfN0lxbSlYEirlNo9vHP/Y1cf3WEu587AgdfZO3t0gnXf1Bvvuvo4QiUW44owynRc+rVZ00ur28d+ubYk8kKlOKntnf4Ka7P6i+6/OYaFTy1OEWfvn8SQ40To2FRLIUZZoocJjZmaKFw1SzIt+OXivo8oaQUtIfiNDaG6A1ycnmdLGlzAkCZBQOt/RQ1TY1onIi9FrB0ry0ZI8rFgjTVQhrKBEZs8mYqPXOc8di2RxGXSyqOZGwDMBpa85VbX00e3yY9VpeONbO4hwba4sdKV9fMXcpy7Lyns0l/OL5qgmfwx+O4vGGiEwypiHHbqIvMPbzoT8YYVdd9whbiKJMM0KAPxQlEIrgC0XYVJo5wnc4GIkORkr/4IljuKwGzlqcxeJsK0a9lv5AmP5AmL5AJPZ7MEyJy8LZi7M5a3FW2gShSFTy1KEWPv3nPSllSgx8foBCx8Q91Gs6+tlc6qSmo29Uv+ShAnSq9j3J4g1G+Of+Zv4ZnwM4zHqKneb4j4Vip5kMkx5vKIIvGMYXjHLzeYtmXfS5InUmEgM1lXV3dtZ28btXa0e87/GFWFuUQVVbH77Qm8KzTiNYU+Rgb7076cWhbJuB+246Q9U/SBNKXFYopgiNRlBZ4ZrpZiimkd2nuvm3v+ylLxDmui0lvK+ylJ8/N/HJwVTy/LE2/uup45RlWfjuu9by1hV5w7bf/WoNx1JYwW7tCfDB323jH586R1Urn2c8c7iV379ey/4Gz6zw1rboNRRmmidUfG6qaXT7prSI4WRxmHUsybXPqCj/8QuWoFH3CEUKHG2eeEHNyTJZqxgpYc8o4nSZy8z+0xbqVhXYuen3Ozna0juY7XT+shw2l2ayKNdGUaaZhm4frT1+1hVnqnHmPCUdCwrHWvtiC4mTINtmmJCtBjAiS8Ci1ySVct/VH0wquOFP204BMUHXbtJjM+mwGXWUZ1m4Ym0BlRWuMcejA1lYP3r6OB29AXr8oUk9v8tclknVS2nvDdDeG6DQYeKcJRk0un04zAYaur2DgSqB0PRbbHl8ITy+0JiFjW85f9E0tkgxFfiCEZ4/1oZRpyGQQrZdZbmLdUWTv19FoxIhGOyzO2u7+Njvd46a9XugsYcNJZnsHbLIkoz3+enceHYFJS7LhNutGE5S4rIQIhP4LbCG2Br7R4FjwF+BcqAWuE5KmfB/UwiRARwGHpZSfmqyjVYoFIrZyL/9Ze9g6u6PnjrGn7efmuEWjU9dp5dvxVOaBjxQvcEwf5pA2w829vBKVQfnLs1JdzMXFEKIWqAXiABhKeUWIcR7gG8CK4FKKeXOUY69DPgpMd/W30opvzfZ9oSjsQnYbMEbirKjthuHWceGkkyOt/bSnURV9Olgaa4tLQUG00llhYu2Hj/tvQE8vnDKA+90YtRpePemIsqyFkZBKEV6ONw8/ZHLAJkW/aQLfQ5N5z2dPIeZuq7hAtzjB5tp6B4uwL14vJ0+f5j/fubEiOJf5y7N5vbLV7C6UEU3zycuWZXHN65axf++eHJC9hh5diNOq2FS0a06DTS501MvpNRlxmbUc3gKFoqaPH4YIlq3F9h5/lg7xU4zH79gMZvLnARCUV443kaz2483GKHZ4+f1kx2xYyeIy2qgxxdkVaGDSFTS3htIS/2HJo+fEpeFmg4v4CXLaogtIkmJSa8Z9/iZQK+dne1SJM/9O+v51QsnUz5uRYF9hK3iRLjxnh2caO1lSZ4djy/EviTuXXvr3ZxR4aIvEMZm1HFoAlmVKmI5vSQbufxT4Akp5bVCCANgAb4MPCul/J4Q4nbgduBLoxz/beClSbdWoVAoZjFDB333bZv9wvIAR1t6ee+v3+DsJVmsyM/gyUMtNHSP70uZiN11biUup4cLpZRDFd2DwDXAXaMdIITQAr8E3gY0ADuEEI9KKQ+PdkwyXLIqD7tJN+sicj2+MNtqumJ+j/n2GUmdPx2dVoNeK3CY9Bj0Gsx6La0e/6i+cFOB06KnxGXBGwjjsOjZXdfFQBDKmsIMzAYt0ahk1zSL4N9511ouXpVLrl0N5BWpcWSGIpeX59mnzFe+wGFM6AV5urAMsKogY9Bb3h8aLla/fKKDbdWv8ZmLlnDL+YuVyDNPEEJw49kVnFGRxRU/eznl461G3aSfiasKHZPKEMq1G8m2GWjvC3KqywdMbFyZKq09ATr7g5zq8vLayc5h25bk2tJWIyRWTC+a9iyqytO83jv7g3TGX2s1gspy5whrkZlEqxFoVRHSOU9b78QWWh7Z28R/vGP1YMRxa48frYDs08Z6/lCEhm4f975Rx556N+cvzeayNQUsz7dT3+VlZ20X/cFIygs+22q6WF/sYHtN1+kuU+NS4DBx0QpVjD6djCsuCyEcwHnARwCklEEgKIS4GrggvtvvgRdIIC4LITYDecATwJY0tFmhUChmJZUVLo63zt3Cdq9WdfJqVef4O45BaZZKLZoKpJRHgPEsRyqBKilldXzfvwBXE8scmjAajWBzmZMXjrVP5jRThj8UQa+dHRObHTVdZJh1lGZZBiOYNQKW5dkw6bVEpeRgEhWuB3CYdRQ6zBj0Go639LIox4rVoMcfiiCBA42emIdxrg2DVkswEuFwcy/dXg9CxFL6N5Q4iUhJV18QnVbDjtpuluTaki4elC5Otvdxg10V8VMkhz8UYXddN5vKnBybgYUjk04zpaJ2rt1Es2f8iNTT036LnKYRdgPBSJT/euo41e39/Nd71s9oMTRFelmSa8Ok14xYVBiL/AzjpIuzZlkNtPZMPKq3ItuKxxea9qyDLWXOMW2frGn0Be72BtMSqQywtdxJOCLRacWYz+VIfGF4a7kTKWOWFU6rnu01Myc2R6XE4w3hsKjCf3OZj7ylggyTnqMtvTyytzFp/2WPL8QDuxow6DTct+3U4Pf3rStycZj1vGNDIQ/sahhhdVPf5eVnz1UhRMw+ajLsa/CwvtiRcqbRne9ao2oFpZlkIpcrgHbgbiHEemAX8FkgT0o58C1pISYgD0MIoQF+BHwAuDgtLVYoFIpZhpSS7z1xlHvfmDvRylPFg7sauGhFLhlmNcicBBJ4SgghgbuklL9O8rgioH7I6wbgjHQ06P+du4hXqzoITbY60BQQiU+w0jFAnSwSsBi0w8SgqGRw0cmg01BZ7iIQiWDSaYlEJX2BMA6znpqOfoqdZk609eGIF8vp6g/i8cUm5+VZFg41DZ+o59qNuEeZwEsJoYgcNtGu6/Ji0seiq6dTWAY4Z2n2tF5PMfcIRaI8sKuBffVuttd0Ud3Rj82owzcDPqNrix3smILoQL1GsLHUyfba5PqfUTc8Ejk6hsb44J5G+gJhfnDtOjItasI8H9BrBTajHn8oeWuMjr7ApBcPO/uDrC92EAxHJ2Q71d7rn5H6G2NF0Lqs6bXlsBh0mPUaolISCE9s8JFtM1DgMKV0r4lEJTtquynPspCXYcIXDLO+2EGPPzxhf+zJICXc+fhhfnDt+mm/tiJ95NiN3HL+YiBmh/ePfU1JH3vbA/tHvNfZH+C5o208tKdxxDaXVc9AT03HuN1i0HKyPbXgLiHgnCUq0zbdJCMu64BNwKellNuEED8lZoExiJRSxifBp/MJ4HEpZcNYDxghxM3AzQClpSqqRaGYDoQQPwSuAoLASeBGKaU7vu0O4GPEPF8/I6V8cqbaORd45kgbd71YPdPNmBW8XNWRUpVtRULOkVI2CiFygaeFEEellGm1lkr1uXv2kmwe/uTZfObPe4b5fc4WDDrtjArLS/NsaIXAZtLR7PaPGvERDEfHFJXaegPoNIJQJDoiUq2205tw/1TYUuZkX4ObI9McTfa9a9Zy4XKVeqgYnSPNPXzmz3s4cVrKeroiA1NBI2L1CNJNjs2Iw6JPWliGWFTgUOQ4ib/bajr5zJ/3cOmafN62Ko9IVJJh0mM1qhruc5GYPUY5P3zy2Lj72k06XFY9mWYDoTG8vpNFoxEszrFNqABsXyDC1nLnlCzQjMXp/WUoXf0hluTa8IcieANhulIUzbUCVhc50Gs1SCkJhqOEIrEeuaYog3BEpmxFYjHoOJBCNtMAK/LttPX4h40LXFY9GgFOi4FFOVaEmL5F5Nlmm6aYHB86qywlcTkR1W19CYsDOsx6cmymlIrGj8fqwgz2N7jZVJqJXquhpqN/3PGxlPCTZ47zxctWpK0dCkjGmKsBaJBSbou/foCY2NwqhCgAiP/bluDYs4BPxYsT/RfwISHEiOJCUspfSym3SCm35OSoFQSFYpp4GlgjpVwHHAfuABBCrAKuB1YDlwH/E/dyVSTAH4rwwyePznQzZhU33rODR/c1EQhPf7TZfEBK2Rj/tw14iJjdRTI0AiVDXhfH30t0jZSfu6sLHfz9428h2za7IuIKM03oZjgN3BFPJdxZ2z0iZT1VwlGZUgp0spRnWej2Bqc9+nxZno1DTT34ptF3WjG38IcivP1nL48QlmeKjaXOlBduxkMAy/Nt2I06yidhH3WirW/M1P6leXZeOtHBVx46SOWdz3LWd59j7Tef5KXjs9PWSDE+79lSPGYhN6dFT0W2hV5/mLpOH/saPOyZgKf+mqIMyrMsrCnMYHVhBntOuSckLA+w95SbygonS3JtEz5HKmwuc45bULeqrY/WHj+LJ9CmDaWZ7G/wsKuum92n3Bxs6iEclUSiMburoy29VJa7kjpXqcvCkhzrYBHwVDna0kuxc/h9pKs/RKZFT5c3yI7abrbXdLG+xMGibCu6KbZi/3/nLZraCyimla3lLq5aXzipc/QGIqwvzhzxvscX4lhrL5UVLraWO7HFn2elLjN58cLyqSAEaISg1GVl9yk322q6KHWZkzr2f144yb1v1BGJR4RIKWdkQXs+Me6tRkrZAtQLIZbH37qImH/jo8CH4+99GHgkwbHvl1KWSinLgS8Af5BS3n76fgqFYvqRUj4lpRy4g75BTIiCmEfrX6SUASllDVBF8uLWgqK+y8vHfr9jTvssTwX76t185s97OOf7z3PvG3Uz3Zw5hRDCKoSwD/wOXEKsmF8y7ACWCiEq4sV3ryf2rE4bvlAEwywrGNXk9iOlxDEDViwDg+L9De5pv3Yq5NiN1Hd5ZyTq/HhrH8vy7ZjT6HWpmF88e6QtaX/H6aCzL73CMsQsc7bXdHG0tXdEJNdYnJ7m3uMLU+RMPHEucZrZmSBSNCpRz+I5TK7dxFP/dj4fPqss4fZFOTZqOiYXae+y6DnW0kttp5eDTT0capq8fUQoKtle0412Guwx8jOMdPcHkxqfhCIy5ftNltVAe29w3P2S/agOs46qST6PjQkWHLr6Q8OyuPbVe6ju6CffYSZzCjyR9VrBFy5ZxqZSZ9rPPRGEEN8WQuwXQuwVQjwlhEiokAohPiyEOBH/+XCifRY6leWT/z/tC4TIHUUw3l7TxY7abvpDEfIzTJzq8tHWF2BFfmoLP1LGivoNLE4vy7Oxr8GD3aRjU2kmi3OsYx7/1YcP8uuXqgmGo3z47h1s/NZTfP+Jo3iDSmSeCMnmSH0auC8+Wa0GbiQmTN8vhPgYUAdcByCE2ALcKqW8aQraq1CMy29equalE+1UZFu5dnMx6xKsmilG8FHgr/Hfi4iJzQM0xN9b0LT1+GnrDdDeG+BYay+vnezk5RPtM+7xOptp7w3wjUcPsauum09euIQluTYiUamqSo9NHvBQ3EpKB/xJSvmEEOJdwM+BHOAxIcReKeWl8YHzb6WUV0gpw0KITwFPAlrgd1LKQ+lqWG1HP1f+/JVZt6pf4DDS5PHjn2ZfVpNOg82kpyDTjMcXSjrSsTzLgmRq0u5Ho703wOrCDMx6LULEPBt1Wg2RiGRvfTdTFcxsM+r44FllfOAMZXmmGJ1nj7bOdBMGWVuUMaE09WRYXehgT72bcAqWBRXZVjr6hotaiWoaFGea8IejrC3KwKTXsqO2G7tRiy8UIRyFXXXdBMNRDFMdwqiYEkqzLPzH1Wv4yNkV7Kjp4ot/j3mcFmWaaeie/LNEr9VMWVaL2zu+KDtZWnoCQIDNZU52JRFtvauum63lTtp7A5j1WrQawcFRBPUzKlwcbPTQ2T/+59hW04VGgMtqoCjTzOGmHkKnKdkr8u1kmvUsz7NP2BpgQ0lmUp9zgIZuH4tzrGhgXDsQIWKRqw6znkA4yqJsK5eszkOv1XC0uYf/fbGaRnfsfD9/3yZWFWZM6DNMET+UUn4NQAjxGeDrwK1DdxBCuIBvAFuIrfvtEkI8KqWcuaqIs5D3bi3FqNPyu1drUrZ7WZprw2U1cLDRQ7HTMub4WEpoiRcPlRIyTBPPjlyeZ6e9z08oIglFwoOZDCUuM/Vdo2cV/vL5E9R3ewczfH71wkke3tPIbZcu5+oNRWremgJJictSyr3EOuDpXJRg353ACGFZSnkPcE9KrVMoUmRHbRfff+Io4ajk5RMd3L+znle+9FaybamnWcwHhBDPAPkJNn1FSvlIfJ+vAGHgvgmcf177pUeikp21Xew61c3/vnCSHuUpljKRqOShPY08vLeRd28q5kuXLSfHbprpZs1apJTVwIiqKFLKh4hZZJz+fhNwxZDXjwOPT0Xb8h0mjDoNUxDUNyk6eoM4LHpMOi2d/YFpi4BcV5LJ9pouWsbQoQYmaR29AQLhKHaTluOtfWiFYGmubVptABJFoum1AqNOgzfNNhw6jeDf37aMW85bhG6WRborZhfbqjs5kGKF96lkqrxDK7KtHI0LSS6LgdYxJts6DSzOsdHk9iUsiuYNhMkw6YaNSXIzTHT1BznY1ENluYviTDMFmSZOtPWh12rIsRk51ORh4yyJMFRMjIpsKxXZVi5elUddRz8/fOoYr53snPR5i12WMb+Tk6HQaZ6yc59Ok9uLRpDUOOB0P+hVBRkYdBr6AiG6+oI4LAYcZj3BSJRip4Xjbb1JBZREJXT0BXF7QyNqkCzNs6HVCF6uiv2flbks1KVojZFp0bOv3j2O+/pITrb3k5dhpLLcSUuPn9wMEw1dPkpdFnbWdRGVsSynP36skhX5iQXjreUu3rOlhMcPNLMszz7bhGWklEMHOlZI+Ge6FHhaStkFIIR4mpgN5J+nvoVzB4NOw3VbS3j7ugK2/Ocz4xbW3Vru5ERbH/kZpmFi9LHWXiqyrUkXm+yawGKUVsCWchfba7sS9tH8DNOY4vKyPDt/2nZq2HvNHj+fu38fOXYjZy3Kwh+OYlO1C8ZF/YUU84a99W4++H/bhj3Ip8K3ci4hpbx4rO1CiI8AVwIXSTl4O07JtxX4NcCWLVvmZAxvW6+f3LjY2dbj59F9TVgMOnRawR9fr+NA4+yZ9M5lpIQmt48s68Jc6JkPmPRarttawq9eODnTTRlGKCrp6AtSWeGifZqUb5NOQ38SEdxbypwJC+oYdWLMwkPTQWW5i25vMO0C96JsKz+5foPKGlKMSyAU4bN/2TsYtTQbcFoMCYtnTobFOdZhljRlWdZRxTabQcvi3FhaL5Dw/nG4uZcSp3mYuKzTagbbvS1+TDgqccejFNt7A7xR3aXE5XmCy2rAZTXwh49W8tNnT/CL56smnEm3OMea9rGuWa9BAGaDLrG8lwa2ljvxBsMcanpTyGrrCcR8h/tTK9YHcLh5+AJslzeEEJBrM9LaG2BJro2qFJ6X4ahkXbEDrUZg0GoIhCPsrX/z73xGhWuwr6aCNxhh0Wn3lGRp7QnQ2hO795yKi20tPX5KXRZMeg23XbJ8VGF5AJNeyzWbisfcZyYRQtwJfAjwABcm2KUIqB/yWmXojoHVqGNjaeaYi1gFDhPNHj9ub2jwmTOUbJshaXG5rrOfreVOev0hjraM3t8KHCZKXBYC4SidfYEx+9Joi02ZFj2FDvOYXu2f+fMeNELg8YX42DkVXLe1hO7+IK+d7GRnXTdfe/tKlubZk/psCwElLivmBf2BMJ+8b/cIMfncpdkLNmp5PIQQlwFfBM6XUg6dST0K/EkI8d9AIbAU2D4DTZwWMkx6QpEoP3v2BL95uXrBL0hMJa+d7ORLf9/PD98zIjBXMUeobp+9/uI7arrYWu7kZHs/XUmkr04Uu0lHfoYpKU/KyCgjWl8oSm1HP5UVrmmr5j4Us0HL/gY3/hS8X5Mh22bgn585B4tBDS8V4/PMkTa6vQE2lmbiD0U43to3ap+ZLvQ6DXajlt5A+mx2sm3GYUJQlzeAViOGfdZMi55luXYaur2DwvJo5NmN5NiNZFoMWAxattW8Ga1V6DDhtOpx+8I0dsfEowyTjmV5dnTK9nzeodNq+Pwly+kLhLn71dqUj8/PMNLtDRGc5LMg06Jnadz6TErY2+BGSvCGgknZSSRiWZ6NTIsBpEQCQgiaun2xeZ2IRR5n2wwUOIw0e2LibzQqqU5SxEoGKaGjP0iJ04xZr2VdkYP9KQjx+8foy4cmKOiXuiyY0mxvc6rLy7piBxevykvreaeC8bJypZRfAb4ihLgD+BQxC4yJXmteZ+gmy+2Xr+CXz1ext949uDgBMYsX3RiWMgOkMrcOReRgVsGSXBsdfYERgvWKfBvHWvto9iS3MD1a0e/yLMuwBZ9EdA+59l0vVXPXS9WDrz90Vtm0FSydK6jRv2Je8GpVB43u4ekOG0oy+cG162aoRXOCXwBG4Ol42uUbUspbpZSHhBD3EyvcGQY+KaWcXjPTaaQ/EObTf96TlrRCxfj8bVcD7z+zjA0lmTPdFMUE+OUNm7jxnh28fKJjppsyAklssjnVgm2vP0yGKYJJrxl1wKzTCEpcljGjISIyli1hMWjxBqf3FlueZeFI88S8Hseixx+mrtPLyoLZlSqrmJ1ctDIXh9nAnng/Mek0rMi3YzPq8PhCnGzvm5QPrBCxdNdQJEp1klF+vmCElYWOtN5DTvepr2rrZ0u5EyQcau7BF4ywKNvK9trkrun2BekNhAfvG4tzrBxp9rAi305dZz/+cJRef4jNZU7CkSjV7X3srOvm0tWJ9BjFfOBDZ5Xz3NG2lL38zQYdhfFCb5NZlM2xGUfYTCRiaZ4Nu1FHJCpHXURZkmsl02xg5yiewg1D5nsdfUEsBi1LcqycbO+bkjookaikvttHfbePzaWZaTvvqqKJ3WdMOs24Yt5EuO3S5QlteGYb42XlDuE+YjZxp4vLjcAFQ14XAy+Mcq05n6GbDtYVZ3LXB7cQiUrufOwIv3u1BogFaCXz3DrQ6KHMZaZuDGuKRFS19WE9rRi03ailLxBJqa+frhEBOC36cYXlsaiscPGNq1bPiT4znShxWTEvGBhgZ1r0vHNDEdduLmZNkWOGWzW7kVIuGWPbncCd09icaSMYjhKORvH4Qvzk6RP8Y3/TtAs7C53fvFzNL2/YNNPNUEwAnVbDPTdWUt/lRYjYxO7mP+xMOjJpaZ4Nl8VAfzCMlHJYOmu6ONDgJtduTLrA3kQwG7T43aNHYoSjkia3j1UFGVgM2lEnyXkZJtrHaKfTokev1dDWG8CgFawpcqARAq1G0Oj20dCd2kB9gM6+IOVZlrSn/wfDUW76/U6uWJvPBctz2VTqxGxQ4ZKKxJj0Wj791iV87ZFY3VF/ODosI0CvFWwpc1LX5R2zn4zGptI3i3slu+jUFwjh8aWeUj8WiXwad9Z2U5FtBRmzyUk2xV2ngfXFzmET+oFjB3wufaEga4oy2FffzdCA1HXFalw8X6nItvLgx9/CR+7ekZLFRU1HPzXx39cWZdDk9qccaWzRa9BrNeg0ggxzLIK52eMny2rAELeQMhu0BCPRWIG7iMSo07C13EmT2z9M+FlblMHRll6qIslHH3uDEbr6Q9NSYDsUkei1Ii3FDxMJXqNR5DTjtOjxeENJZU2lgsWg5X2VpZyzJDut550JhBBLpZQn4i+vBo4m2O1J4DtCiAGPoEuAO6ajfXMdrUZw26XLB8XlvfXdSY+38x2pi8sAqwoz2FnbjSRWsM8bDFOfwth3XbFjRAZBmctCts3IrlMTr+G4ptChCv0lQInLinnBZWvyecB5FmuLHRhV3p9iDH7zcjWXrcnnC3/bNxgtpZhedtd10+ML4vGFycswqer1cwytRlCebQVi3qH33FjJ7Q/uT2rC47QYBn3RNpZmohGwNNfOmiIHJS4zBxs9PHOkbULt0mlgQ4mTJo+PJvfoqXL5DhMui4Hqjj4W59jGbfeSnJg/qsuixxuMUpZtSSoKMhCODno4Vla42FnbNej75rIYWJJrxe0N0T/G4tayPDvbarqwGrSEo3JYJLTNqGNdkYO6rn48vuSLkFVkW2nv8addfHeY9SzNs3G0uYffvFzDb16u4YFbz2JLuYtQJIpOIxZ0hIcQ4j3AN4GVQGW8APbAtjuAjwER4DNSyidnpJEzwAfOLGN7bTf/2Nc0YlsoItlZ141OA5vLnLT1+scsyjOUJbk29g6ZOG6v6eKMChdaDTHBVcYimweQQ/Yz6DQjfJInSlGmicMJ7jGCWOaULxShstzJ9iSiPvVawZmLsgYnyvkZJqxGLVlWA93eECfa+jDqNATCUQ42xq5pNmjJzzBiMejYUu6a9OdRzF6ybEYe/uTZHGj0cKjRwx/fqMMbjHAqiYJxS3KtCMSEiml5Q7Fnnd2oxReMDD7jx7puIBwdjHQ267VYjVoKHeakLSeW5dkw6rQ0dntZkmtnZ9302Evtb/SwtdyZVJT2WFgMWuwpFAfTCkF3fyglQXo8BjJ8F+fY5pNI9j0hxHIgCtQBtwIIIbYAt0opb5JSdgkhvg3siB/zrYHiforxMRu0ZNuMdPQF0GkEliQDCMITWJAZ8CU/e3EWgXCUhm5fyjUaPAnuaU6rYVLCMsA9r9WwssDOe7aUjL/zAkKJy4p5gUmvVYNmxbhIKfnLjlO8eLxdCcszSLPHz1cePsS+ejdvX1vATedWkKW80ecsa4sdPPqpc/jqwwf48/Y3a6SYdBrWFDmQQCgSxRuMcKDBwzs3FLKpzMnqwgxWFThGRLY+sreR7zx+hDKXBV8ogsWgo7XHj0GnwR+KDBahGcCs17CuOBO3N4RGCEqcFgod5oTRwqsKMjjS3ENbjx+NgENNPWwqzeRQUw8ajcAXF3oHIpNybEZqOr0YdRqaPH5CETmhooHba7pwWQ0UZprwBSNUd/SzvTbI0lwbm8vejK6EWBTj6kIHu0+5qW7vx2rQJhSg+wJh9jd6WJRtpcBhxheKkJ9hYltNF0tzbRh0GrQaQV8gfJoYLulLIVtDI0YvhrKpNJNwRNLs8dPeF2DnkAm3Wa+lLxDmlap2vvLgQRblWLnt0hXYjDpC0SiRqEQrYgsUOu2bC0xSyvkqQh8ErgHuGvqmEGIVcD2wmlidg2eEEMvmsx3VUIQQvHtTUUJxeYBwlME+sq7YMejPfDpGnYbybCsdvYGEhbe21XQl5ZkaDEep6/SO6JupkmHW4Q9F6U1Q/NNq1GIz6WKLPAm+7xoRuw8FwhK9RrCyIAOPP8TLJzqorHDh8YXo84c42d4/KIKfuzSb2s5+Mkw6gmGJWa+lyxukpsPLd69ZO58EJMUoaDWCDSWZlLosfOXhg5h0moSRe6dTlGmhPxDGok/8vEmG3kAEp0WPL5Ta8b5QBF8oQkdf8sJ2e29g0AvV4wuO+oxKN6sKMlIq6pcIm1HHqoKMpG1wICbUG3QaSlzmpBfYxmNvvZtnj7SxbB4VI5NSvnuU93cCNw15/Tvgd9PVrvnG2UuyaHb7UyoKrdMKluXZsBp0NLl99AXCY95rtpY7BxeqvMEIe+rdKbezxJk4WjoddVmiEr780AGuWFuANYWFovmO+ksoFIoFhVmvnZECWorhDAgJv3rxJOcvz1Hi8hxHqxF8/crVHGrqGZzE2kw69jW4B9NHz1uWw19vPnPc/+urNxTR0O3jh08eG7FNrxUsybFSFRdTNpVmcrK9P2GV6E2lmUQlSCStPQEEUN/tRRIr0jMwGR2IBjbrNSzJtdLq8WPWa7Gb9XiDYdYVOcYd1NpNOnr9o0cPD6YNSihymthc6qTHH+J4ax96raCywkU0KvH4QjR7/Bxp7mV1YQbd/cFxJ/pDixc1uX2UuMyDg32NgC1lTjLN+sHPqddqMOs1+Ebxi9ZrBVEJm8tign1NRz9rCzIG/TFXFtip7/JR7DTT2uOncZQocV8owkfujgUGmXQa6ru99AcjI+6/Zy7KYl+9G51WoNMI8jJM/PT6jSzPnz8TXgAp5REgkXB+NfAXKWUAqBFCVAGVwOvT28KZY2u5ixdvu4AfPHmMx/Y3A1DsNLO6MIMnD7UO23fg/rIi34Zeq6W9N4DNqMWo1+IPRjjZ1stYtckCSRYuC0clu+q6KXCYcMXT+3UagUaI+D1EEo5KwpEowbDEHwrjC0XpHzJhXpFvZ3tNYnG6LxBhoHRWODKyTVvLXexv9LAi30IoEh0miB9p8hCOyhF9eFt1B5tKXRxq7hl2P7rpnAqu36qiq9KBEEIL7AQapZRXCiH+D9hCLBj9OPARKeWMV779y45TQMxq5kCDh8oKF209fnyhCMFwlIpsK3qthoiU+IMRXjzezvri2GLvRMTlRdlWolKm3WopERtLM4cFiNR2elmRbx+0hZlKLAbtsAJfqaLXCow6TUrCMsTqOGRZDWkTlge4cEVOWs+nmP+8drKDpw+3pmwp2drjH3Z/KHaa6Q+O/n0eOlaq757YfaW+20dlhYsdNV3kxMfhS3Jtk14gGsCk0xKdDj+eOYQSlxXzmsf2N/OTZ45j1Gu4fmsp79pYpFaXFjBCCGXBMAvxBpNP6VfMXswGLQ994mxePtHOC8faee5oGxXZ1liRvXIXv/7gZkz65NLnPn7+Yo409/BKVcewKtGhiESr0bChJGapMVbBvNO3OcxjC8C+UJSqtphQm2E2DEYDNntGRiobdBqW5Fgx6XVoNbFCgmdUuGjp8dHeE8A7RPQpyjRjNWopyjTT4w9xoHF4inwoIhMueE3EVzEUkcMmn8VOC1Vt/fhCYTaVZtLo9pFjNw5GMi/Li6XDmnQaghGJNxih2e2jPNsyTBTb1+Ahx2YkN8NAXaeXvkAkpYm8Py7oba/pYmOJA71WCyImqh1p9sQi3eL/zd3eEPsb3PHo1F4yLQYuXpk7X6OZAYqAN4a8boi/N4L5WrneatRhNeq4/bIVrCrIwKjTcO3mYr756KFRjzna0odOI/jq21dy2ZoC8jKMnOrycv4PXxjzWjptat+jZo8/6Yr0Q7EZtdR2jD0hPtnez9qiDPSakeOSSFTiCybuZ72BxJP6YATCMiZ4D6Tuv3VFLl++YuV87j/TzWeBI8BA1dJ/l1L2AAgh/hv4FPC9GWobUkqeO9rGz5498eZ7MOIZ053g2VnfFbv3pxJBPMB0CcvrSxwjMg8D4ehgP9GI2GJ3ls1Ijzc47FmcDiYrI2k1seyqVH2thYjVFZrIvWg0lufZWZGviu8qUuO7jx+dUK2iXLtp2D3C4w2RYzNSlmWhqr1v2FgfGOxspS4zp7p8FDpMBCPRlO9P22u60GsF7X0Bzl2Sxf7G9HmW9wbC/Ptf9/LbD29N2znnOkplUySNjK/MzKUB6lOHWwYjuL7aeJD/fOwwF63M4x3rC7lwea4SGhcYtR39nEiQSquYWe5+tZZwRHKJqmQ/59FqBBcsz+WC5bl846pVVHf0c7yll/OX5yQtLANoNIJf3LCJSFTy3rteH2Zxcax1YtFJqfgSN7p9bCzJjAugEokcjFAIRyTdviDNHj89/jCReAj0QPR0hklHZXEmff4wFoOWzv5gwhT+6aDHH8Kg1eDzRgfF9taeADpNzHs5EpUJ25boPtneF5iQJcjp7EmiOvdtD+wf9vryNfn89PqNs/6ZLYR4Bkh0I/uKlPKRyZ5/vleuL3FZ+OSFb9YaHivV/fxlOXzjqlUsyrENvpdMIbO+MRaY0kl5tnXQ93gsDjT2cN7SbDaVZrL7lBuDVlCYaZ6wt6pWCHyhmJ/te7cU8813rEGj7DDSghCiGHg7sYLXnwMYIiwLwMzk9cdJ8asXT/KDJ0Zm/SRDlzdI16ngMA/wAocJrUbQ0O2jxGnGYdFj0mkRAvyhKK1x//4yl4XcDNOUZwYax3kGRCVEI5IWj5/1xbGCW4FwzIZJpxF0e0M0uX0T/k9qGqNf6rWCSFSOet8y67WsLXZM6G8Ujkr6AmEsek1aBHMh4OMXLJ70eRQLj4YJRhFHTovw7Q2E6Q2Eae8LsLLAPkxcXpJjpS9uJ9XY7eOMChc7aruwmXQYdBqCSWYgDaDVCFYVZPByVeeE2j4Wmjmki00H805cnosC6Gzn+WNt3PNqLYeaejDpNVy+Jp/L1hSwvtjB69WdHGnu4YYzyhJWw55pdp5WcMEfivLY/mYe299MZYWL+285a4ZappgJ7nrpZNIpsYrp4+UTHXgDYVxWA5vLnOr+PU8QQrA4x8biIeJPqmg1gsvXFiT0T55qxrPCyM8wDgrLEJtYSgk9/vCssd6x6LU0JYh0CkehpmPyxcqmi38dbCFw7y7+5/2bUlqkmG6klBdP4LBGYKhnQXH8vQVPYaaZxTlWluTaCISjVLX1ISX84WOVlLos6LXDhaa8DNO45wxGYpYAIOnoDSb0Q04HFn1yY+LKcicvnejAYdZzRoWLJo9vwhGgG0oyByM4P3HBYm67dLl6nqaXnwBfBIZ59ggh7gauAA4Dn5/+ZsXmv79+qZqfPH1i/J3HYXs8E0ci2XvKjV6rYUW+ndqOfuq7R4qrBQ4jL57oAJi0T/lYmPXalCIm943iM60RsLXMlbI1BcQyGQaKjA1lY2kmx5p7WJmfgdmgpb7bi82ow2HWc6yll574YvPeFIuI2Yw6VhdmUNPRn1ZLjPwME+/cmDBBRqEYk9gYLHVrmMgYq8V9gTBby52DNUlaewKI+OM9It8M3ujxhRP2v/FYXeAgFImysTSTXn+Izr7gpOxthnLt5uK0nGe+MPvUwAni8Yb47r+O8MCuBsJRSVGmmfOWZXPLeYsHq9orUmdHbRe3/HHXsBWigSrwBq2GYNwn7nhrH//1nvUz1cxRqaxw8dCexHO0HOXxuuBQUcuzl12n3Fz7v6/z1bev5KZzF810cxSziIdHuYfPNG5vaNBruSjTjETishg4OAE7i3SzqiADrUYgpUwoLs9Fnjvaxsfv3cX/fXjrfIvEfBT4UzylvhBYCmyf2SbNDm6/fAW3X75i8HUoEkUjxKiF6ZKJIBqaVq4VDNpHpJu+wPgTVwHUxIVkjy+U8oT5dA41esi2G9lcmqmE5TQjhLgSaJNS7hJCXDB0m5TyxrgX88+B9wJ3Jzh+SixtBkTlZ4+0TUgsHY2h38VgZGwbpKHWUVN5a15VYGdXGopxR2Vy/XP04yUuq56u/tg5Kstd7K3vJhiRCYuFmvUazl+Ww46aToKR1GKmc+wG9pyKndth1rM8344gFkGdSOhPlmaPn1OdXkqzLBM+h2JhYp7AAn+Bw8TeMQI26rt8IxZP1hc7qOnsp+e0rMNtNV3DsivGo7J85EJShklHZYWLHl+Qoy0T1wZW5NtV1u1pzAtxeVddF5+/f9+wlf5Gt48/b6/n/p0N3FBZytevWjUiwkExPg/vaRw19SA4pADJqa6p99maCNduLh4Ul5fk2sjLMJJnN1FZ4VIrTQuQt6+bmQhIRfL85JkTFDvNXLamAI8vhFGnmdWRioqp5+wl2Umlu083/nAUp1VPWZaFuo5+egMRwhHJptJMur0h6jr7p62CvVGnoSjTTI7dSDgSZdcpNzaDlr4J+OLNZpo9fhrdPkpcc29CLIR4FzHxKQd4TAixV0p5qZTykBDifmJRj2Hgk1LK+fUflybGG8dvKs3krStyee5oW1Lni0ho75281UtixlfZJLFil1qNGDOqK1lCUUlnX4BPXLhRCcvp52zgHUKIKwATkCGEuFdK+QEAKWVECPEXYpHNI8TlqbK02Vvv5rv/Opqu002agfoDHX2BwboF6UKXxnn8ZOrv7KjtxqAVnLc0m/a+wLiivi8Upaq9D4kg22YY5hm7tsiBxRAb4/pDEfyhKAadhva+AMFwhAyTnpySWCGyhm7vYFaUXitGFDZMlW01nUpcVqTMysKMYYWkk2E8O5tEaITAYdaPEJchll1RlmWhbpwsn0TCMgzPMJxIJPQAHWmwiptvzGlxORKVfP+Jo/zm5WpGK9QYiUr++EYddpOOL162IvFOilHRxZegc+xGrttSjEmn5UdPHx+2T1GmmR/NwqhlgLMWZXHbpcvZUdtFfyDM72+sTOvgRDG3uHZzMb94rirlQhqK6aMvEOYzf97LC7dl0tYbQKcRrClyzHSzFDPIh84q4/9eqSaUYsTPdNDsCQyL2mrrDcS/t5Bh1o8sUDIBNpRkYtRpCEWihKOSoy29lGdZyDDrCYajdPQFaHL7qe7oHzbg7wtGWJFvxxeKjDsAnyscbenl3B88j1mvRacR5GYYeeRT58xKW67TkVI+BDw0yrY7ifm4KiaBEIIfX7eBbz92mAd2NSR1TI7dOCWFyAy65MTdAodpUhGIp3PO0hy2lLvSdj5FDCnlHcAdAPHI5S8AHxRCLJFSVsU9l98BTKvS+7ckv+eJMGhFypG0yTAg1KwuzJhQYdrRSNVndSwONfVQWe5k96luUj2tVsDa4kxeiluBJENJppnGbh95GUY8vhCRqGR9SSb7692M9V/Q1Z94YT0UkRxocMejL0MjIstNeg2rCjLo9gapGaWwqFEFbigmwO2XreDVE+2446KvXiPYUJqJNxihvTdApkWPw6zHH4oSDEfJMOsIpdjJkhF8rYaxx32x6ObxRePJFJV//xllEz52vpLUaFwIkQn8FlhDbKH9o8Ax4K9AOVALXCel7D7tuA3Ar4hV1I0Ad0op/5qWlgNPHGzh1y9VJ7XvI3ublLg8AW6/fCXnLM3hguU56LUa3N7gMHG52Gnmz//vzGmJIqrv8vLEwRa8wQgfOLOUrCRsLTQaMVgcJhqVM1tlQzFjhONR9naTnn972zK+9vDBGW6RYiyCkSjv/tVrXL+1hE+/delMN2faEULUAr3EnpthKeUWIYSLcZ658WMjwIH4y1NSyndMR5unksJMM+/cUDSpSfR0E47GbDNWFtip7fTim0QEsVGnGTbI1mtE0gUCj7b0ohGwLM82Y0UFp4JgJMqlqwv47MXL5oSwrJg+HBY9371mLZeuzicYjvLI3kZeO9k5WBxoujDqtKwpyuBgYw86jcCo09Cf4D6QrnYVOkz4QhG+e83atJxPkRQC+L0QIiP++z7g4+m+yNGWHg40ePj77gaiEtYUOsiyGdhR28X+eg/lWZaUF0g2l2VS1+mlPMvK7lPdRCXYDFrKsi14g9G0ePJbDekVL/fUu1lX7ABJQvuJVPAGI2yv7WZtUQYHkii8OcC6Ygc1Hf0p+0oPSGu1nV5MOg1SyElFHUNsnDEQfVnsNJOfYUII6PaGqO/qHyziu7nMyf4G94gF+olEkyoWNoFwhJt+v5OKbBv7GtwIYEWBfZi1VFuCbKANJckHCZn0GhrHWXBdmmvlRNvoVj2p2GZUtfezvsTBvnoPS3KtdPWF6PImDkIrdpq5/fIVvFrVwdZyF+9SvuUjSHZE/lPgCSnltUIIA2ABvgw8K6X8nhDiduB24EunHecFPiSlPCGEKAR2CSGelFK609H4rv7kQ9Fbevx09AXIVj67KWE2aHnbqrzB111DIj6nU1gG+PY/D/PU4VYgVpjtI28p57MXL8WoS27wMs88GhUpEAhHOdjo4Y3qLj5+wWIe3N0w6UGdYmpp9vgpy7Is5H57oZRyaFjM7Yz/zAXwSSk3TEcDp5MLV+TOKXF5gCPNvbgsepbn2hEa0ApBMBLFoNXEvSkFu051D0uJX5JrwxcMI4kV3en1D49+DqWYPh+VySTozx3WFjn4yfUbJlUoUjG/0Ws1g2PXt68rYHtNF799uZrXT3YOK+BXlGniZPsULbpIOWhXU+Q0EwxHOdXVjz8URUrIthkozDTT0RdAI5i0hc533rWWgkxzUkUNFZNDSvkC8EL85dlTdZ1AOMJfttfzX08do9f/5vf29IKxVpM2VoBPyqQFFRB09AXp6Ati1mvJd5io7/JyqCm2ILmhxIFAUN3RhydBWnoypPqsSob98SJ9k0llH8Bm1FGXoq2jSa8d9n+RLLVDxHr/FBQWb+j20TCKILerrpvyLAtZNiM1Hf3kZ5jIthm4cHlu2tuhmN+caO3jWGtM1HWY9WTZDBxo7GFFvh2rUYdGwIEGz4jvuEhhFOoPRWnt9bO5LJNdde4R23Wa2D6nL5bYjDoKHCYsBm0K90HwBSPsq/dgM+qoausny2oYce3KChfvqyzh3KU5ZNuMXLmuMOnzLzTGFZeFEA7gPOAjAFLKIBAUQlwNXBDf7ffEHrLDJrpSyuNDfm8SQrQR85pzT7rlkJKoGYlKbv7DTr5zzVpW5Gek4/ILkm1DVkj/cvOZFDunz6tpaNqgNxjhf144SV2nl1++f9O0tUExN7EadRRmminPtvDc0VZWFmTMenG5KNM8pedv8QQoyhx9ElrktIyYwEw3zxxp450blTd6nHGfufOZXPvcXRju8oboDXhGtfVYW+QgEpW09wUoc1mwGbW8cDy2rtDkTk8xvo6+IKsKMuj1h9Kagj8TvGtjkRKWFSlRWeGissLFnlPdfP+Jo5j0Wg42esixj11kaDJ4/OHBVPUmt48Msw6PL4zdqMVq0lHfHSvIVeKc/LP+4pW5XLBCCUXzjZ213Xzj0UPj7jdQDKvAYWJpro1AODpmLZzNpZlUtb25qOILRYZFKkcl7K33sLk0c8LCMoB7lOi/oeg0grIsC5GopLM/mLRwu7/Rg1YwpqXEeCzPtw+LQDbqBIHwmyfMsRnjkcBBNpU6qe3sZ/cE67aUuiwJIzqni9pO72B0+0CgWGd/gALH1M41FPML75DsG48vhMcXYmu5k1113YMLpImK5Pb4U7OIC0Uk0VHWYFYXxaKMAdYUZmAxajnY4KEvEOZE28QXiweyiDr7g3T2B1maa+Nkex//+c61vK+yRNUxSJJkIpcrgHbgbiHEemAX8FkgT0rZHN+nBcgb5XgAhBCVgAE4OfHmDqc7iYfWUHafcvP2n73C5962jE9csFh9SSbAayc7WZJr454bt06rsAzwmbcu4c7Hj9DQ7UOrEawtcnDr+YuntQ2KuUtehomGbh87artmXDRNhkb3zApARZkzX+TDblqw6e4SeEoIIYG74oWAkn3mmoQQO4kVBvuelPLhKW/tNLC5zMmXr1jBz56tSphGnm0zcst5izAbtHzvX0enPQV+PMbyix5arLC9N8D64vR7jA8MliHm4Xyqy0u3NzhqvYrZzCP7mrh8bb6aFCtSZmOpk7/cfBYQE74+/LvtU3Kd/AzjMA9UCYMiXW8gQm/gzQl6ltU46QUfyzjek4q5yVsWZ3HeshxeOt6e1P7Nnthi5EDkXTQKTR4frT3DRU1/OIrHN7bYs6ogg12TDMJo9fjJtRsRxLJHc+1GQhFJlzeIVghsJh3+YGRY4b8V+XZae/x0j1OvIMOkw2gzcKrLh14rWJJrw27UE45Gafb40WoEVqOOJrdvULDWa2Pz/lJXLIr3ZFsfZy12EY5IGrp9tPT40WsFm8tiYln7kGJdk4mSnq3WTU1un3qOKlIiw/zmd7nYaSbDpBshJCdS106291PiMlPfNf6zLsOso8RpxqDTsCLfPsJP/GRrH8vyYv1daGB7zcQWfMbDZTVw49lrueGM0ik5/3wlmbudDtgEfFpKuU0I8VNi6biDSCllfBKcECFEAfBH4MNSyhHrEEKIm4GbAUpLx/8P7A+E+dO2U/z3aYXlBrCbdHzhkuX8+qXqEQJNJCr54ZPHWJpr45LV+eNeSzGcn79v44xd+/K1BVy2Jp9TXV6ybcZJVfpVLDwMOg3Xby3hD6/XDlt5Vcxemj1+olG5EK0xzpFSNgohcoGnhRDDCgSN88wtix+7CHhOCHFASjliUTfV5+5MI4Tg5vMW86GzynnxeDsvHGujxxemPNvCljIXZy7KwmzQ0t4b4M/bTxEIR5FS0hcIj5hYz3b0Wg1rCjM4mMZCSEPZW++m2Gkmy2qbVJTHTLGv3s3XHj7I7ZevoLq9nya3jy3lLiqyrWpcoEiaTIuBxTk29jVMzrs1EYWZZlqSvO8cavKwKMdKdVxgW5Znw2kx0Ozxjxl9OhRVsX5+IoTge9es5aIfvYgvlPy4dehiYkW2lXVFJgLhKFajFp1WM260vl4rxhWfk8EbiuINvfndHBC/N5Y42FOfuN8dbemlwGFkVUEGR1t6sJv0OC16+uPFwnTx4KIDjW6KnRYc8YyAI81vClAmnWYwLV8QE6wNWg0HmzxoheBkez8n22Pp7ztru4ct/oYicvAnHawtcnC4ycPOCUY8pwu9VmA36enzhwnG69AYtKqgnyI1nBYDeq1gU2msGGZD98h+kqi2AMRs3rRCIATk2GM2PIWZZiJRSSAcO6a9N0BHX5BDvjf78+k1Q/qCEY639qERsaJ+Fr0Gbyj9VjNNHh//OtjM+hIHqwtVYflkSWYU3gA0SCm3xV8/QExcbhVCFEgpm+PicVuig+NFDh4DviKlfCPRPvGorF8DbNmyZdy7+Y137xiz+uPACuVT/34eH/v9Dt6oHrnv4wea0y4uB8IRTrT2cajJw+GmHtzxB3M4KvF4Q3T1B8kw67jpnEVcsDwHnVYZ6aeKEIKyLOtMN0MxR8myGfmPd6zh1nt3zXRTFEkgJTR0eyldYH1eStkY/7dNCPEQUEmSz9whx1YLIV4ANpIgYyjV5+5swaTXcunqfC4d5fmdYzfy2GfOHfZea4+fP7xey/++WD3M23i2srOum8py15Reo6Hbh8tq4IwKF95gmFBEjogOmc08c6SNZ46M7AK3nL+I2y9boTLTFElxztJsHtzTOGPX12sERU4zmWY9Zr2WtUWOwfnN1nInBQ4TESnZOY5/ZOEU22gpZo7bHtiXkrB8OjUd/awqsNPjDw16pY7HivyMYRk16WY8L+ZmT4BmTwCtgP5AaFDoNmgFwYhkT1wc12pEQtuOoX6vEoY926JD0nU6+xNnQNd09KPViLSMF06297GxzEl3f5C23gBLc23otBr6/GEON0/NAnIifnb9Ri5fW0A0bj8iBLgshmm7vmJ+4DDpybEZR43kN+u1HB/lPrM7bp2RadFT0+FFrxWDC05jkTnK9zQqoTcQTmjDkQ4G7IZWFjQpcTkFxhWXpZQtQoh6IcRyKeUx4CLgcPznw8D34v8+cvqx8eJ/DwF/kFI+kK5Gl2ZZxhSXAZ481MKH31LOPTdWcvMfd41IKRrtgZIKTW4f922r48HdjXT2BQlHo0kV5HijumtwELm+xMH1laUj/AO3VXdSnm1VhTkUijRz6eo8sqyGtNwDFFPLK1UdHG7uWVDishDCCmiklL3x3y8BvgU8yvjPXCfglVIGhBDZxAoN/WDaGj9LycswcdulK8i2GfmPfxye6eaMS5nLPKUT+wG6+oODEwSzXkOBw5TUQH82c6DBQ1SCVmnLinGQUnIozdkBAthYmpl0NPT6kkz21LvJtRsx6zXD5jZDJ8uLc6xkWQ24faFhEVwDdKrI5XlLbUdqBecScbi5F6NOJF0Ez2KY2ojWaDT2nR5qh5GIiCSmDscJnhZNnGU1jnuOidDVH2RDSWZa/Ni9wciwxaEjLb34ghH0WkF5lmXQB3mqMOo0VFa4yLLF6lZoNIKcOVzDYjyEEN8mVqMkSiwI4yNSyqYE+0WAA/GXp6SU75i+Vs5dTAbtmJY1S3Nt7B9l/DrQfbPtRrq9oaSzA+q7xu7jU5mdWJ5l4cNvKZ+y889Hkg2d/TRwnxBiP7AB+A6xCe7bhBAngIvjrxFCbBFC/DZ+3HXEiwEKIfbGfzZMttHvT8L7ZGBiZtJr+c2HNvPeLSXDtpv1k39wHm7q4ZfPn6TZ4ycYSU5YHsAXirC9tovfvFzDO37+Ci8ci0XgSCm59406vvLwwTldwEihmK0IIShOoRioYuaIROW0iGyzjDzgFSHEPmA78JiU8gmSe+auBHbGj32emOfy7FdTp4lrNs2N4pB1XT6KnSYW50zfoopWjF/L+4wKF5vLnGhELGJsRb59WtqWCq+d7OTLDx4Yf0fFgkcIwSWrxiwXkzKrizLYfco9ZsTjlnInm8ucZFr0tPUGiEQl22u76Rpjwn6yvZ/ttd3UtPdT6rKMmB/UTbFApZgZGrpj0X2Lsq2sKcxgTVEGS/MmVsw0EJbsqO3CnIRwfLDRg9Oin9B1hpJnN1JZ7mJTaSZbypyD39vDzT1Ut/ezqTRzwue2GrQp115KhdYef1J/q2TRCNhYksnqggwgZr9hm+K6IhXZVvZ/8xL++LEzqKyY2myoWcQPpZTrpJQbgH8CXx9lP5+UckP8RwnLKTDWvcFkGF9adKYQMS8EdPaN3c8z03CvOp1sm5EvXracRz99DkUqMyglkrqrSSn3AlsSbLoowb47gZviv98L3DuJ9iVkY6mTc5dm8/KJjlH3WZ735qTHqNPy/WvXcfWGQjy+EBEp2VjqnHQ7zlmajUmvwT9Jn5f+YIT/94edXLG2gNqOfvY1ePjsRUtVWmccKSVSshB9VxVTxJ3vXMM1v3qNYDj9Hk2KyaHXCtYXZ6KN9/fx0oHnG1LKamB9gvc7Gf+Z+xqwdqrbOFdxmPUUZZpnvFhmMpj02mn1Q+4PRlhd5CDbbqS+y5swMsUXirC/wUOBw0QwHOVoSy+V5S6213ZhN+mwGXWzIvK5NEstHiqSoySNC81nVLg4OM5iqE4jiEQkCFiZH/OUTYVQVA76MOfZjRRkmtlb7x604VPML14/2TkisrU8y4JeKybkCRyVsLbQwakuLy09o9+r+4MRVhVmJJVqbtJpKM+2EghHqemIRRi6LHoKnbHiXUOj8VcXZpBh1lPV1ock5p8/0ejd/mBkcJw4FTR7/GmLXi7PsqDTikE7jwEON/VQkW0d/LulmxaPn0A4ilG3cLyVpZRDb6pWhsW+K9KBw2KgaZSxni+JmkbRFKIxN5c6x/UrN+nSazNblmXhb7eeRa5duQdMhDlb+eQbV63mo/fsSFjswqDT8MkLl4x4/y1LstNy7ddOdvDVhw7i8YUIpEmcCkUkj+x9M2vjqvUFaTnvAE8eamFpro1FcfuNPae6CYSjLMqxzurO8z8vVPHrl6oRwM3nLebm8xZN6WBiITFa6pCIrWr8FLgC8Mbf3z1zLU0/a4ocvGdzMfdtOzXTTVlwWPQaVhc56PWH6QuEybYZMOi07KnrJhSVrC1yDBtITHV6pmJhYUjzIHSq8IWik164TgUJg+nSlRVOdtW5WVfsIByJYtJrMem17G9wAwwTkLfXdlGYaaLF46c/EKay3Mmhpp5RC7pMB+/aWDRj11bMLXLtRh76xFvwh6L4wxECoQjff+JYymLPxtLMpOwGwtGYX6xZrwHEpLx0u7xBsuORoOekaX6jmF28c2MR9d0+fvl81WA0fG2nl41xO5WJsL22C71GUFnhYmdt16hZt7tPuVmaZ+NEAhuWoawryWR7/Lu/It+ORggON/ckjMQ/1NSDRkCGSce6YgcHm3omZQthn8LI3zMqXOyfYLHPygoXBxvcaDWCqGTUzxiVsQAqjSCl7Oex+MCZpXzigiVoNYJQJIpcgNKqEOJO4EOAB7hwlN1MQoidQJhYlt/Do5xrThW/ng7GilxOxnKyvnv8Pq/XCjaUZCa1wJWOr7jLasCs1/LL929iTWGGqos2CeasuLwk18ajnzqbLz90gGeOtA1GIC7OsfLtd67hLYuncKAloXqKVhkhFl11ugfzZAiGo3z/X0cx6bU8+Im3YNJr+e0rNTy2vxmA/3znGj5wZlnarpdOXj/ZiTs+QPn+E0d5o7qT33xoy5wRCGY5P5RSfg1ACPEZYqlDtwKXA0vjP2cAv4r/O6+49fzF/HN/c1oqYs9HdJrYhDnddPYFhw0WGrpjUaTL8+3oNGLEvfWdSihSpBHDHBkw9gVGFimaLnbWduO0GNhzyj343hkVroSFkwCa3EPF5m7sJh0FDhPFzlgV8KMtvXinUWzeVtPJuzbODQsUxcyi02qGZTL6QxFuvTe1tfRcu5HG7tSyIXyh6KSLEG0qdQ5ZEFowKe8LCr1Ww+fetox3bijkpj/spDruL7yn3s3qwgwMOs2w+3SyhKISbzAcv09bONHWR1dcFNpS5iQYjrK/0YPHG8Jh1o167wdo9vjItOhxe0NJFYWNSujxh2n2+AfndxNlR22s+G1brx+NRhCOyIRBZxOhLxBGN4FgJrtJhy8Yxpvk4nBtp5d1xQ6Ot/QOK0Q4EQxaDV+6bAV2U/ptAmYTQohngERVnb8ipXxESvkV4CtCiDuATwHfSLBvmZSyUQixCHhOCHFASjlvil9PJaPZWuQ7TDS7x85eEzDueHBVQQYeXyjp5+Px1j604k1P51RxmPU8+7nzcVpVgct0MGfFZYhVj/yf928mEI5wuKmHvAzTtFRMNk1xJF15tjWtlhi/eO7EoGDznceP8K2r13DreYsHxeWvPnwQg07Ddaf5Us8G/u3ipeyrd9Pjjw1sXjzezk+fPc5tl66Y4ZbNfcZIHbqaWBFOCbwhhMgUQhRIKZunvZFTSInLwhVrC/jzdhW9nIiwZEKTlolybJRJyZVr05vFoVjYrCywcyxeyXpNUQbfvGo1BZlmzHot3mCY1p4Azx1t5a876unoCw4Wwzl3aTZLcm1Ut/fzy+erxixokip2o5ZIVA6bjM5kfk5UDo8+MWjFoPCQDL3+ML1x8WBdkWPUicTGkky8wQg2kw5dPMrK7Q1NevH+iw/sJ9tm5NylOZM6j2LhYdJruWRVHk8dbgVixbBWF2ag02ho7wsMi2jOthkIRSTlWRa2pygS59iMg0LhRBDAvngmAcQCbhTzl0U5Nt5/Rhnf/uebJRQONfWwpXxiFo8WvYb6Lh8eX4hGtx+jTlBZ7gQB22ti3+W1RRkcaOyhItuCWa+lZZSiWfVdPvIzjCzJtdHQ7UVKksrqDU9UCTqNobYbW8udaROXDzX1sLnMya5xUvIhVoNgILJ8WZ49qWOGsr/Bw9JcG7Ud/YQmGMJs0mu476Yz572wDCClvDjJXe8DHieBuCylbIz/Wy2EeAHYCIwQlxUjcSSIXM61G9EKMWYUcYZZx9oiB6+d7Bx1n2ybgfqufnoDyQckeHwhVhdmTKhA79JcG7//aKUSltPInBaXBzDqtGnxUB6LFo+fB3bV89LxDnafmloP0FS8aMbjZHsfv3zhzXvlH16vY2VBBu+rLB0WNfGbl6q5dlPxrPM13lzm4m+3voWP3rNj0CfzlRMd3HbpDDdsnjBK6lARUD9kt4b4e/NKXIZY2o1iFGZJLt2iNGZxKBTXV5YODmx/f2PlYAV1iKXFFTstbC5z8rm3LaejL4DDrMc0pADwW1fAVesLufOxIzxxsIVgJPVIo0yLHqfFQI8vRHm2lV113WRa9KwpzkRKSSAc5eQ0+i2PxZJcG1aDdsKersFIZFR/UCEYFPqHsqXcSbPHn3I0aFGmmZYeP5Go5JUTHUpcVkyIuz64mT+8XsuPnzlBWZaF3fFFVq2AzWVOwpFobAIt4WhrLxNZCnJ7g+Q5TDBBfVkCa4scg2N4jarRMu85MGQxYYBddd1sKRvfk/R0FuXYODhEiAmE5YgFkgGf3tpOL1vLXaOKy0BsW3z7gA//eLh9obTaQUCsCLTFoE1bpkw4iee7Wa9FytgikzcYTllYHuBEWx/5GSYKM02D95xU8IeifOufh7l6fSH3batDr9UQDEf5w8cqyc8wLZg0fyHEUinlifjLq4GjCfZxAl4pZUAIkQ2cDfxgGps5pylzWagsfzNbxh+KcLjZw1hrSnaTDq0QvFrVOeY9q6MvyMbSzJSDm3QTnM+fvSR7WgJTFxLzQlyeKqSU7D7l5g+v1/LY/mbCk3gCLsmxkmUzsjvuKzoWB5s8fO3hg9x0bgVlWZOrFn/vG3Ujqlbf8eABDjR6Bh9eOo3gR9etn3XC8gDL8+08/4ULePJQC4ebe7hynYpkTJY0pQ6Ndf457UV1esV1xZvMBml5VUEG+Y7Z6wmvmHucuSiL575wAcFwFNcYkQpajSAvI/F3Ly/DxM/et5GGbi+fuG93Sr6MawozkDAYYTEQIez2hgZ9K2cTVXGR+4wKF3UT8MY82tKHy6Inw6wf5jspBKNaEu2sjQkmqYjLv/vIFt66Io9AOIJGCPQLZCKtSD9CCN69uYTv/+so++rf7NsRyTDhyG7SsTTXilGf+nctN8OINzgx65sMs45F2TZqOvrZXObkqnUFyhZjHuMNhnn6cCuPH2gZsU3KmEXG1nIn+xvcBMKxkZtBK7Cb9NhNOhq6vYSjMUGoLh7Vm0xk8a66bvQagdmoZUcSz6biTDNZdsOYhQKH4vGFsJt09PonbwGlFbChxIlWK8i1Gyfl4zyU8WzzNpRkIkQsy+/kJDIRBmjp8dPS46eywjWh8cC+ejf7TvPifs//vk6O3cgfP3pGwojTecj3hBDLidUTqiNm94gQYgtwq5TyJmAlcJcQIgpoiHkuHx7thIrhhCLRpBaQhrKyIGPwO32gcexCnntOucm1G2nrHX1B63Tax1j8GouJBIgoxkaJy6PgDYZ51y9fGxZVYzVoWV3owGnV82pVZ0JPRLNey6Wr81hd6EAiCYSi/HN/M8dae6lq72dFvh2PL0izZ/ROICX88Y06Xj7Rzgu3jeZDnxyjFWL405BCZt+4ahXrijMndZ2pxqDTcNX6Qq5aXzjTTZlTTDB1qBEY6pFSHH8v0fnntBfVlnI1IRsNMaOJ+TFUf1dMBTajDtKwrlTstPDLGzZxxU9fpjzbyqbSTB7c0zhisryqIAOjToMvFOFwc09aI7WmGpfFwJJca8oTiaGUZlnpD4RZXxyzyAhHJQ6zHr1W4A9FB7OShpLKYr7LauD8ZbnAm9F2sxEhxA+Bq4AgsfTbG6WU7vi2O4CPARHgM1LKJ2eqnQro6guO65na6w9zqKkXg7aPZXk2jicYb5e6zGTbjOi0Gg42epDEIuzrOvsTRvMnQyQiOdTkIRSRdPYHuefGrRM6j2Ju8PF7d/Pi8fZRt0eikh213awpzAABJp2WnXXddPYH6ewPYtJrWFVo52Cjh3yHieJMMzqtwGl1gRwZsTyAJObNHBrDb3mAAaGoIcG9fCxW5Nsn5Ts+QETCkZaetHv7N3R7KXGZqe9K/LmiUsYkzDSzo7aLimwLGSY9bm+QulGunwzNHj/NHj9yVoSMTD1SyneP8v5O4Kb4768Ba6ezXfOJ4ASeXfVD7GoCYUkgHCHDpBu0PYVY3TSrQYdBp0nZ3maiAZJvV9aLaUeJy6NgMejYXO7kWGsvOo3g1vMX86m3LhlMjw2EI1z+k5dHeAP+9PoNXLJ6eKDoOzcW8f7fbuNUl5ejLb2Y9Vo+enY5mRYDTquBLKsBl9VAfyDMyyc6eOlEO81uP2ctzhrRrsNNPXz7n4cpdVk4f3kOZy/OxmrUEoxECYajGHVazEM8oTeWZvJKVceon/PfL17GB88qn8RfSjFXGSN16FHgU0KIvxAr5OeZb37LA1SWu1hfkjlipV8BsyF22TaFlcAVinRQ4rLw4Cfegj8UZW2xg/edUcplP3l5cHuGWUcoEuVwc098fzMtHv+EhaWppsxlJsduoi8QxmzQcqDBk7Kf7OnsHXJ/FYAmicIroXGiSVbk27l4ZR6rCjPYWu5CO0szr07jaeAOKWVYCPF94A7gS0KIVcD1wGqgEHhGCLFMSjl9VRAVw3ijenRPyNMJRiTHW/uoyLaSYdJxuLmHUEQOetaeOk0Yqpqk5Y3dFCuwFopEEMTmK4r5RV8gTGuPn1113WMKy0M5OIrfqD8UHcyuafH4afEMjyyeqFfpUKzGiX0Hd9R2szzPxrFRAqFSocRlGbV2x0QJR8EfjJLvMI34u0HMK3kqsgakhJqOmLi2qiADmLi4PMDn79/Hkjwbd1y+ctLnUixsgikWnky0+NrsCZBtM7A4x8rJ9n7WFTsw6mJZQAcaPfiTLIg5QIZJR4nTTF6GiT2nuonImAc7QLc3lPC5e9X6Qs5ekp3SdRTjo0YkY/DvFy/jn/ua+On1G7lwRe6wbUadlqvWF/LI3kYC4SjFTjNXrC3gopV5I85T4rLw5StWcOu9u7EYtDz/hQtGTbdNdDzEJlq/euEkP3v2BOGo5PXqTv66s37Efrl2Iz9730bOXBQTpj954RKyrAaePdrGtpquYTcEIeDaLaqi+gImYeoQsQjmK4AqwAvcODPNm3o0GsGXLlvODb/ZNtNNUSRgcc7kbIEUiulgaZ4dgCcONvP9J44N29bjC9Pj62NRthWTXsPh5l42lmSyZ5YtaK0tysBi0HGstZe6rqmrKyFJrqL3aGnbGSYdH79gCR87pwKDbm5ZX0gpnxry8g3g2vjvVwN/kVIGgBohRBVQCbw+zU1UEKt78rtXa1I+bqDYn92k46xFYwd2TIaOvgBOqxFfKIJWIwhHo2g1szdiX5E6O2q7uOUPu6YlZbuqrY+NpbEgi4lk1WwsyWR/g5v1xQ72pWARNUC6iuPKKaoT0t4XYE1RRkJxOctqYP8UPssLM01o0vSYe/ZoG1ajjmA4OueenYrZhT+U2rq3bZTFp46+IBXZVtp6Y8VyB7L+KrItg4sryV9Dz+HmXuq7fawvdtDjDw/Liih1WXBa9Bxs9BCR4DDr+fqVq1K6hiI5lLg8Bjl2I//49Dmj+h7/+9uW8e9vW5bUuS5dnc+m0kx2n3KjSyHCxuMN8Xp1J798vooDjeM/tNt6A9zwmzf47EXLBiOtP3J2BR85uwJ/KMK2mi7++HodzxxpRUr4/Wu1fPmK6VnFPNDgYVtNJ4tzbVy4PHf8AxRTyhipQxL45DQ3Z8Z4y+LsYdXhZwPFTjNnVLjIthnJthkQQhCKRFld6KC6vY9fvXhyQv6nqTDTcZU5diOby6a2UKtCkS5eONbGrffuHnX70Cyn2Rhle6K1j3UlDtxpmuhPFptRh82oG2E/lm03ct2W4vkwOf4o8Nf470XExOYBBoroKmaALm+Qjr7ghI/v9YcJhKNsKnUSikTp9ceiUPuHpOwbdZqkfG8TsansTT/Wn7x346y2glFMjAuX5/KrD2zi1nt3TXmWSyAc5UCDh7VFqYvDi7Kt7Kl3U+IyUz1Bz+HyuLg0Gc6ocCUsDpsuDjb2JCxMuyTXxrYprJVQ6DCnXKxxLM5Y5JoPz07FDJOqZcVAbZFERKOwMj9j0HpNK6DJnZxvO8QWc4f6OQMJ72Onuryc6ooFKBQ4TFy7uYQcVXdpSlDi8jhMtqDeAEIIvvL2lbz7V6/zr4MtfODMslH3lVLy42dO8MKxNg42elJeSY5K+PEzxznU5OGuD25GxKtIm/Razl+Ww/nLcrh/Rz2/e7WGEmd6KmRWt/fxt10NnOr08uP3bkCvFRxp7qWqvQ+PL4THG+TxAy209vj57Ye3pOWaCkW6qKxwzbi4XJRp5uwlWVy3pYTNZc7Bfns6lRUu3rmxiHteq0UAh5t7+Me+pjnl45oM33/3WjVpVswZ/rarIan9ChyxiMPZhj8c5WhLL8VOMw0pFNKbCvRawakub8K6FtXt/VR39JNlm52TgvGK6Mb3+QoQJlbrINXzz+kiunOBXn+Ybu/ExWWLXoM/HBlWDHBlgZ0Mk56+QBiPL0RDt4+luTZOpGiRUVnh4kRcRFtTlMHbVYHrectFK/P43w9s5pN/2p1yingqaDWClQX2lIRli17DioKMwSCH0TyJkyE0wUWWoexrcE/p30ivGSksQ9xzeQoZzx4qVb71j8MEQlFuPLt81DmGQjEeGhFb0Onxh6hu7xssJDqUXLuRYqcZnVbDnlOjL5DUd3uHLS4VZpqpT2IMatZr45Y+npSKX/b4w/QG+tiigpemDCUuTyMDvmgvHGsbU1zefcrNz549Mer2ZHnqcCt/29XAdVtKRmy7bmsJ120d+X6q7Krr4odPHuON6ljHfv8ZpUgkW+98jo6+4SvRGSYdT/zbeZzq8vLZv+yhxeNHpxWcaO1jZUEG37lmLd5AeDDFWKGYLqazWuziHCufuWgpmRYD3f1BdFrBivwMluTakj6HSa/l1vMXD77+/rvX0eLx88UH9k+q8NZsIcdu5JwlOTPdDIUiKWo7+vnXgeRs6QscZnafcqfluqsLM3CY9bx2Mnl/2LHo8YUJhaMTSklMB0WZZr5zzVrWFTn42iMH+ef+ZiwGLRcuz+Xpw6188bLlXLYmn2KnZdrblizjFdEVQnwEuBK4SL6Zx71giujOBSqyrVRkWyfsjZzvMA8TlgGONI+MqnRaDSmdV68VnGzro9sbwmLQTlvWoWLmuGhlHs9/4QLee9cbKUcLJsvaIgdNbh8rC+xoNYKDjWP7L5c6zWTZjGl7jvUHw9iNWnoDE190XV+cyeHmHnr9YYQAp8VA1yjRkgadBiklpS4LWTYjBxo9+MYpBBiVkuX59hGezql6z6aCTiM4PEkv7NMJhKN865+HOdbSy3euWTsrs6gUs5twJMoLx9oHiy5rNYJsm4FIVBKOSELRKKGIpK03kFRGwun7uKyGQXH5jAoXJ9v7EmYSrS12pCQqD0VKqOnsZ6MSmKcEJS5PI4tzbDz4ibfEzflH5/EDzQgR+/JPlm//8zDnL8sZ1eN5ooQjUX7+XBU/f+7EsIjJG88ux6jTJvTjufX8xfz46eMJI7zaets5+3vPAfDf163n6g1F6qGnmDb2pmmQPBYbSzP594uXcfaS7LR/t016LeXZVn72vo1c+F8vjBsZuSLfTrPHj8c3O1Lgh7KhJJOfv2+jSt1TzBn+sa8JCSMqXyfiQIOHFfl2jk6i8NCAV9w1m4ro8Yc53NSD3aTjHb94ZVIZDAatYF3xzPlB33h2Oecviy0q/eKGTXz/3WEsBi1CCD53/140QsxqYXk8hBCXAV8EzpdSDlWKHgX+JIT4b2IF/ZYC22egiYo4Z1S4JiQup+KnHkmxs64tcqDXarD3+Lnt0uW8ZbEqRLQQKHCY+fqVq7jl3l0pf2eSYaDg6oDIc0aFi/beANUd/Qhga4WLcCRKV38QnVZDe68fywQL+J2OXiuwm/T0myP0BiYe/bytpguLXkNlhYt99d109QcpcBjJshqHFTrMzzDR7Y19zpPt/Zxs76fEaaY+OPa1IzKWobu13EkgHMUUF6h31Lkn3ObxCEclW8qcabXFGOD+XfVoNPCtq9eg16qxtiJ5Grp9g8IyxJ5jk7GROh2TPpaxatZr2VfvZnWhY8T5jToNXX2Ts9J57mgb12xSdcemAiUuTyMGnYZNpeOvknztylV8+YqVdPUHae3xc//Oeu7bdmpCg4pef5ivP3KQuz6YPiuK/kCYW+/dxcsn3ixWotUIvnLFSpbkxqKOX/rihRxv7eVEay/eYISLVubywyeP8eShsa0HFmVb2VTqVMKyYlrJtOin7Nzv2ljEHZevIDfNCzyJyLToOWdpNm+c7KQ3QUo5gN2o43vvXseXHzwwprg8xdl+CblgeQ53f2SrStdTzCk+dm4F7z+zjAyTjnO+/zwtPaP7xYWictTiJslwxdp8/uMdawa94hxmPWctzqKjLzCusDxeGn5plgXJ1EZjnY5GxFL9r95QNCLLyjrk7/T5S5ZPW5umkF8ARuDp+D3uDSnlrVLKQ0KI+4HDxOwyPimlnH3eKQuIk+2pC8sCUrLT2Huqm1UFdk609Y3rq2sz6tjf4CYcjU2sL1uj7DBmAiGEFtgJNEoprxRC3AdsAULEFoRukVKmfdX+4lV5PPLJs/nuv47walV6MlVGY1tNF0tybeg0sKnUmTA6sM/fi0GnmfSzYkW+nV1pEk+9oeiwttqMerq9QSrLnURlzHO1LMsy7Pms1wpMBi3FTjNmvXbY83FruXNwHFzd0U9Xf3BYgbBleclnG04U9xQFgEgJf95ej5TwhUuXkz1LbaYUs4/J+qOPRyTe6dYVO9hW04VOO3w+aNRpWJxj5XCCbKDxWFmQwU/eu4HOvgDtkxSnFaOT1AxHCJEJ/BZYQ6zO00eBY8SKkZQDtcB1UsoRTwghxIeBr8Zf/qeU8veTbfRCQKsR5NiN5NiNrCly8KGzynjhWDsQeyjcv7M+aa+2Jw+1cqjJw+pCR1ra9sCuhsEq2BaDlrIsK1+7cuWwKAqX1cCZi7I4c1EW/lCEm/+4i5eOt4977uqO/in3sFIoBmjvDaDTCF46PjVV3R1mPV+7chWuFNNfJ4pJr+U3H9rC88fauPHuHQn3ueGMUtYXO2j2zKyv6uk4LXq+d806JSwr5hwWgw5LvIu/Z0sxP3+uasz9xxKfRyPbZuQ/37k6oajU1R/kod0JXRSGYdJrOaPCRVTKwX4miEWetPT4qWrrByZWlGkiGLQaHvnU2awcJ5sLYpYZcx0p5ZIxtt0J3DmNzVGMgXdImrzFoB32ejS2lrtSsqWKyFiNlNGE5aJMM5kWPUadhh5fiKr22IKx3TR1i+GKcfkscAQYuGndB3wg/vufgJuAX03FhdcUObjvpjN55UQH//dKNS8ebx91QXFLmRONEDS6/z97dx0mWXUtfPi3yqva3Xt63BmfAQa3ABGiBBJixN3vDUlu7N7YF0+IE4dAEgIBEoJbsHHGfaZ12l1L9/fHqW5aqm3au9f7PP10dVWdU/t01alzztp7r9VJRdPL53rzUn1kJbpp7AgiAonRz1JFUyc1LV1kJ3nJTfZQUt/BytwkthfHDvwuzhrb7Jtu3aMUJ0LYGCqauqjoVRysf2AsGDYcr7aupe0C6wuTqWsLkBbv6hNITvU5WZqV0KdoYLJvYs/r3Q4br1mTS3NnkLt3ldPcGWTDvBR++Oa1hCOGf+2v5NYnToyphsNdO8r4x0sV3Pb2TVywWGdCqOEleCZ+XOrm+ak9hTK3nW4gJ8lNapybiqZOlmYlnFURTZvAD9+8lqXZCYCmX51II/2E/Ah4yBjzRhFxAT7g88DjxphvicjngM8B/917IRFJBb6M1atrgF0icn+sILQa2qLMhJ5RwQBvO28eX77vIH/ZWTai5X/x9Cl+cuO6Eb9efZufXz5zis5AmOwkDwsz4tgwL5WMBDfvOL+IK1Zk4XHYSI1zDRsM+vvu8gGB5WtWZVPe2Mn+ipfz0qXGufjG61azIGPie4OVAvjTC8X8eJhAUH8Om1CQ6sPtsLE0O4G0ODcRY2jqCPD8yXoWZMQRiUAoEuFz1yyftMBybxcvzuDGzQXcuf3l74cVOYl89LJFXL48i58+eYLGjumVEuPSZZlkJ0386O6ZQESKgVYgDISMMRujx1Pt0J3mbt46n7t2lFE7xOiOs5mG+su3rWfDvNSYj33mb3t54kjNsOuIGDOhle1Ha1Ve4ogCy0pNtvs+vJXyxk7KGjtYnJnAntJGfvjYcQ5VDsyBGu+ysyQ7gV2ljdhtMqpZhsFwBLfDhj86AnRRZjzZiW5K6jsoa+wbGHQ5bHznjedw7eocnd03BUQkH3glVifQpwCMMQ/2enw7Vr70CXXB4nQuWJxOU0eARw9Vc7iylQMVzWwvbkCwcvH3TqWQkeCmMNVHmz/E0apWSobI3dw7GD3UCMX6tgAep21Ci+iN1em6duLddtpGmMs5bOjJI90/v3VDR5A2f4gVOYkcrmpheXYCXqeNwlQvpWMoZjiYRI+Dr163ktetsz5Ot1yzjPZAGLtNemY+ffjSRVy8JIM3//IF2kfQ+TWYrmCEL/5jP3/7wPk9M6KUGkzKBHeq7IzRoVXZ7CfF5yYj3k31WQzOALjp3HnRwLKaaMMGl0UkCbgIeCeAMSYABETkOuCS6NP+ADxFv+Ay8ArgUWNMQ3RdjwJXA3eOvelzm8dpx+ceeY/vwweq6AiEeooKDsYfCvP754q59YkTMafVz0+PY1NRCityEslO8pCd5CUnyUN6vHvQk91l2YlsnJfCydo24twObthUwIcvtQbwbDvdwO+eO40gfP7a5RSmzdx8imrmyU/1kRbnon6Qwh/9JXgc3PfhrdO+A8RmE77wyhXcu6eCrmCECxal8/t3bcJht9EZCPOTJ04MGIXRn8surCtIxibWTIoDZ1pGNHrrbKTHu/j45YsnZN0z2KXGmN5D6j+HduhOW8YYHj1Uze3bSmkc5vsk3m0nwe0YNHVNLMV1HTGDy8aYIWcFJXkdJHicJHqcHBzn4kBjsXVR2rim61JqPIlYncgFqdY56VUrs6lt8/OFew/0eV5Rmg+308bhyhbi3XZsImQlekj0Oilv6MAAlc2DXwyfrG1n8/xUjDGUNXRwoqYNl11I9rnoCkVw2W096QcuXJzOdWvzJnKz1dB+iJUzfUCEQkScwNuwRjZPimSfizdFUwl1BEI0tAe45Z79fVIWgjVDb6jOzrORFu8al2nlJfUTVzjWGGvGT5t/fF4jEDYcqmwh1ee0puRHp+UvzIgjLc4NAv5gmL3lzcOsaXC+aIqOP968pc9gC4fdRpJ3YKf0qrwkfnbTBt73x509HVTDcdiElDgXzZ3BnrQmxfUd/Pa50/z31cvOuu1qbpjINJJD8ThtMTt3RyIv2csnr1gyzi1SgxnJyOX5QC3wOxFZA+zCOnhmGWO6y6NXAVkxls0Deg+tLY/ep8bAGMMvnj7FH54vHvBYVqI1deBwvx3wdevy8A4z/eipozX8z30HKBuiF/Z0XTun6wZOm12Tn8Qfbt4cc5rQhnkp3P3B82Ourzt1hlJT4fqNBbx+XR6/fe4033jwyKDP2zgvhQ9ftogVOYnjXhxzorT7QyzLTqSlK8hPblyHIzpasiMQwh+K8PubN/Hl+w7yyKHYedDDhj6FiTYXpdLQEaCsoWPEJ7Ej9bZzi5iXFjeu65yFtEN3mmruDPL+P+3kxVMjGxW8v6Jl1EX9FmXG7tDaXdrYp7hKb/EuO4WpPvZXtADTKw3O0qzEMeWeVmqy9R9l73ZYo5SPVlnT6jujozj7zwraPEy6jN55Yj0OGzduKeSypVnYbNYosYlMHaBGRkReBdQYY3aJyCUxnvIz4BljzH+GWMf7gPcBFBYWjmv7rNRMDlbkJg4ILo+3xVnx45ISA85uFs9opMW5KB7nAHZDv/27uzBgt81FqYQjBrtdeKm0kUA07Y0IXL4sExGhvNFKQ3LF8izOW5jGttMNvPuCItLj3aNOt3Hxkgzu/8gFfPeRozx+uLpPqhSnXViancD89HiaOgI8d6KOy5dn8su3bcQfCvP8iXqC4QiBcIQMzbusRsDjtE/JrIXdpU3kJns40zS6kcvZiR7ufO+5pEzBLOK5aiRn9g5gPfBRY8w2EfkR1oipHsYYIyJnnSh3Ig+4s5GIcPWqbGpau6hs6mJeuo+itDhW5yWxMtc6+f3y/Qf54wslALzt3Hl85TUrh0xf8Z/jtbz3jzuHLSrSX2aCm4uXZHDJ0kydpqdmJIfdxvsuWsiGeancvauco1UttHSFqGruIi/Zy/WbCnjn+UUz7vOdlejhG69bzUtlTT0H1V0ljfxlRylrC5LJSfJy4+bCQYPL/e0ubSAUAZ9z/C8Gzl0Qe7r/HGaAR6LH1V8aY36FduhOW/vLm0ccWO42mrx189PjWJU3sGZCMBzh8/cciLGEpS0QHrJo51Sw24TvX7+GK1fE+vgqNX0VpcXhsAlhYzAG1hTELnbWX3378CM881O8FKX5+L/XrqYoXTtap6GtwGtE5FrAAySKyO3GmJtE5MtABvD+oVYQPY7/CmDjxo0TUlxmvGrrDMUxjufCBSnW7Ned/Yr65ad4yU70YLcJxkBnMNwnjeJIbJiXMm7FAkfjZG0bDR0BjLGKAu4obiTJ6+SHN6zl0qWZMZd57bqxnaYtzU7g12/fSHljB1//12GePVHH9RsLeP9FC/oUEz/T1MmBimaMMbgddi5dFrs9Sg2lIMU34rpf4yU1zol/lAHt9HgXd77vXJ0VP8lGcnVTDpQbY7ZF/74bK7hcLSI5xphKEckBYiX8q+DlkVZg5aJ6qv+TJuOAO9vMT4/jy69eGfOxSMTw5NEalmUn8PXXrRo0T2O3PaWNvP9Pu/oElhM8DlblJpGR4CbJ6+y5EA5FDIFQhIwEN5cszWBFTqIW4FKzwoZ5KWyYlzLVzRhXK3ITWZH78mircMTw9vOKeqb6Pn/SGuGyMjdx2Cnz3YOVO4IRtsxPZVfJ4CMmB5PgdrAwM57Tde09Qa/rN+bPuv/7OLjAGFMhIpnAoyLSZ1j9WDt0QTt1x9OWBam47DYC4ZGf+JY1dAyZGmNlbiJrC5LJSvTwmjW5MTu3fvPs6SFT2wCUNnT2TLsXZFQFxyaCTawL4eFSdCk13aTGufjJjetYlpPI4coWPn/v/hEtV1rfweLM+JgX4+sLk/n4FUu4aHE6jR1BUqZoyrEamjHmFuAWgOjI5c9EA8vvwZoxdLkxZsoTEF+1Ios4l31MOXiHc7iylTUFSewtO/v0DwBxLjun69qpbvWzMCMOp92G22EjHDEcONNCeWPf2TZb5qeyp6ypJ5VDLIsy40nxOWnqCExJYBnok2avKxgmyevAHwqzqWjiB1Hkp/j4yY3reOpoLVfE6MDNTfaSOwuK446EiHwa+C6Q0S/FXPfjWp/kLL15UwH/96/Dk/Z6IpAR7+Zo9egC2p+7ZjnztbN20g17dm+MqRKRMhFZaow5ClwOHIr+vAP4VvT3fTEWfxj4hoh0Rw6uInpwVhPnTHMnt1yznCtXZI1oytFtz57uk0vV7bCx53+u7JlGr5Sa+brzOb5U1siFizNYmpVARoKb+z+ylQf3V40qH+u20w1kJrjJSnRHp9yPTLLPiWB6Asvp8S7+6+pl+l3TjzGmIvq7RkTuBTYzjh260XVrp+44cdptPPjxC3lg7xkeP1JNOGLN6slIcOO02zhR08qRqlZau14OJFe1+HtGNYF18rxpXipXrcziFSuzezqAhvKvfZXDPgf6TrtfkB6HwXC6buJyXQ4mL9nLlSuyKNIUOGqGumZ1DmAV/GoaYVHcYMSQ4nPiddnpjJ5ri8C7t87nlmuX93QcTUXxXzVmvwBKgBeiA23uMcZ8baoa43HaefcF80ddqHq03PazT9XicdpYnZfEvvImqqO5oHunlRjMttMNpPpc5Gd52RdjFPO6wmT2lDaR5HUSHkVH70TaX9GC22FjfWHypKWBcthtMQPLc4mIFGDFnEoHeVzrk4zBu7bO5+ljtROagmfz/BS2n7beDmOgonF0qd1E4Mrlc3s/mCoj/ab7KHCHiLiAU8C7ABvwVxF5N9aB9XoAEdkIfMAY8x5jTIOI/C+wI7qer3XnglQTJz/FR37KyKcAFPR77oWL0zXYo9QsU9XSxcnaNjITPCT7nCR6nbzvooWAVXSzsrmT+1460/P84aKNNa1+GjsCbJyXQjAS4UB5MytyE/G6HAjgD0Vw2q2clCLCrpJGyho7+0zTf8OGfNI1z1sfIhIH2IwxrdHbVwFfA+5HO3SnrUWZ8XzyyiV88srYRUOMMZxp7uJoVQuHK1s5WtWKMYZrV2dzwaIMrlyRNepK7T9763ru33uGp47W9ASph3Oqrp1NRSmTHlxO8Tl54KMXaABNzQrbT9eP7vnR/XPz/FRK6tu59S3rJ2Ukoxp/xpiniHbaGmOm3RSMj1+xhDu2lY64UPXZ2FPaOKIZb/3ZbcKC9LgRH6/6a+gI0B4IsqkohUA4QnWLn6rmLhZmxHE8OounuTPIxqIUjla2EI4YVuUlcaK2jYb2yUkRZRMoTPXhD0XoCoYpSPXxjvOLJuW1VY8fYBXfjHWeDFqfZEzsNuEXN23grbdt46VetXnGS16Kt8+gxziXnY7g6GZjLM1KIElnAk2JER0UjTEvYfXu9Hd5jOfuBN7T6+/fAr89y/apSfDBSxayZUEqe8uaKEz18VqtRk04Yvjz9lIe3FdJZzBMYaqPeWk+CqPVw+NcDhZmxunUXjVjbCpKHfRi1uWw8c3Xr+bFU/VUt1gjSUaS7CYYNn1y5Q02ijnF50TE6n1u6TV6c3HmgKLrysqlfG90FJQD+LMx5iER2YF26M5YIkJespe8ZC+XLRuf0RQFqT4+fOkiPnTJQj565x7+OcxI5rQ4F4sy4+kIhLEJjDKrzVlz2W38/KYNGlhWs8YTR2p7jmkj5bAJhak+PnLpIg0sqwljtwnvuXAB335o8CLVYxWMGA6eaWFdQTIuh41tvWbH2AQ2zksFAX8wzN7yl0cZJ3gcHKocWzFAf8j0BKdT41xcujSDyuYu2vwvB5929gped3fsbCpKoaqli9oWPwsy4sbcjljS493c9o6NrC1IHvd1q5ERkeuACmPM3iHSdmp9kjGKczv49ds3ctn3nuozK2885Cd72V3SSILHQWtXiMxE96gHRJy7IG1c26RGTiNjiiSvk0uXZg5aaGAuOlHTxvceOdoz7bG7Zy41zsXizHgM8Mb1+Vy/qWDqGqnUOPK5HGwsSh3xVPvRaOwIsrYgeUAP90WL08f9tWY6Y8wpYE2M++vRDl0Vg4gMm1fOaRcSvY4+QYDJ8p03naMn+mpW+dO7N7O/vJl3/X7H8E+OCkUMFyxK46IlGRPYMqXgvRfOZ01BEr/5z2kePxIrg9b42BM9pzsnP4nmziAl9R1EjDUlvftYsyY/iRM1bfjcDgpTvewqaRq3129oD3CkqoXK5uGLZu4obsRuE3wuO4cqW1mZm4jTZuOl8rG1Z11hMseqWmkPhHnHefM0sDwJROQxIDvGQ18APo81a2+8XkvrkwwiI8HNp65cwlcfODRu68xMcHO8upVgxJAf76a1K4TLMfo0PG/ckD9ubVKjo8FlNeftKW3kV8+c4nBlC4FQhE9csYTrNxXw9Gcv5XfPneahA1UcqbJ6uBvaA3QGw3z+2uV6saxmnaNV4z+So9tLZU3kR4uJHKlqoaUrpFOWlBoHTR0B/vRiyaCPF6X5SI1z9RlBNpluf7GEjHg35y/SziQ1O6THu7loSQYXLk6npL6dhrYAbd35lIE1+ckEIxFauoJkJXjwh8KU1HfobB01KRx2G+cvTKe1KzShweVu+6LHlnUFyZxp7uwJOgO0B0K0B8K0B8LUtg4fBB6tFJ97RMFlsGaldo+yPHimBZfDRn6Kd0DxwKEUpfl494ULOG9BKh6nnbxkL0erW/n2v49oSslJYoy5Itb9IrIamA90j1rOB3aLyGZjTFWvp2p9knHytnPncdf2smGLS4/Ewow4mjqCNEQH9nXXsU7yjvxaMT/Fy5b5qazKSxpze9TZ0eCymtPCEcMHb99NVUtXz32fu2cfm+enUpQexyeuWMInrlhCVXMXTx+r6Ulg/80HD3Pvh7Zis40keYBSM8P33rSGd/9hB3VtE5Orr7ypk/KmTpx24fXr8nDY9ERcqbG6Y1vpoMXFzslLYl9FM8X1k1/Ar5tNhEVZ8VP2+kpNBLtNOHSmpSe3bU6Sp6cQZ+8immUNVuBKBJbofqAmSSAU4bb/nJrU19xT1kRWgpvzFqTx9LFaAE7UDF+sbywOVbawOCue49Vto142EIrgc418VKTTLjzyyYtxOfqeuy7LTuR379o86tdX48sYsx/omYYtIsXARmNM/8pzWp9knDjsNr7ympXc+OsXz3odG+elUNncNaCwZ1qcmzi3A+cgsZalWfEkeJxEjCEcMQTCEY5Vt3HTufPOui1q7DS4rOY0u0347CuW8uX7D9Lmt3qzIwa+8/BRfvrW9T3Py07y8OZNhbx5UyGhcIRQxGhgWc06awqS+dXbN/KeP+wc8TLJPiepPhen6mJfQNgELluWxeb5KST7XLgdNnwuB5cty8Su+5BSY/a+ixbw/UePEe6XRDnOZaembfxHio3WdWvzyEzwTHUzlBpXJ2rayEnykJHgoqyhk8rmLiqbuwZ9vjFwqq6Dpdk6ellNrNauIN99+OhZF84bi+pWP3VttazISeRQ5egK/p0t71lMmwdrpOSxXkHp9YXJVLV0kZ/i69NBBGAXWJ6dyEtlTWyerznTZxqtTzJxzluYxlUrsnjkUPWol90wL6VP7Z7ethe//JasL0zmeHUrrf4wdrGuV3eXNg1Y5p3nF7GuMGXA/WryaHBZzXlv2JDPK1Zl88DeM2w/3cChMy3sKW2kttVPRoJ7wPMddhtneR6j1LS3vjCFHV+4gtL6Dr7+4CEa2gPUtvmpbvYTCEf6PDczwc3Pb9rA8yfqeKmsacD0y3lpPn76lvU6PUmpCeS02wYU4PS57Kyfl8J/jvcfsDP56qZBgFup8bKvvIm7dpRx5/bSPgX94t0OVuYmcqapk7JBptnXtfo1uKwm3MMHq/nDC4OnSppoCzLiaWifmBlw3bwuO/PT4nA7bdSdZbqNk7XtLEiPo9UfItHjYE9ZE8ZYI5qzEtxUR9e7LDuBcMSwr6KZ63/5AqvyErnng1sHjGBW04sxpqjXba1PMoFeeU7OqIPLm+ensP30yDrAdpc2sTQrgeM1rayflxKz42zrojS+8Mrlo2qDGn8aXFYK66Lgxs2F3LhZk/UrZbcJ8zPiuO0dmwAwxuAPRfjztlLu3F7K8Zo23rqlkP951QrcDhtJXgebilKpbfNzpLKVeWk+lmYn8L/XrSIlzjXFW6PU7PfzmzZQXNdOSpyLNflJLMywpt8/cqiarz5wcMgRlRPtR48fp7i+nVeuzuHy5VlT1g6lxsIYw5+3l/LNB4/0zHTrrc0fYtvpBpx2YVNR7Ivf7GQdwa8m3uLMqU2/crymDY/DxuaiVHaWNOB12gmGzYABCt0cNiEUGV062/R4F8drWgmGx5YGt3vWXe980HVtAZK8TjYVpeAPRaho7OxJfwNwoKKF/RVNbJinI5iVArhocQY2sWZ/DyUnyUNuspea1q4RB5a7Ha1uJSfJE/PY+uo1uXznjefg1LznU06Dy0rNcSLyaeC7QIYxpk6sKgg/Aq4FOoB3GmN2T2Ub1dQSETxOOzdfMJ93bS2iqSPYJ2i8KDOBRZnw1/efx1NHa/CHIly3Nm8KW6zU3HLlithB26tXZbN1URp/2VHGCyfreamsqc9F8mQIRwz37K7gnt0V/PadG7lsmQaY1czSFQzzibte4qGDVcM+Nxg27CxpZFNRCtUtXT3F/vKSvRRGczIrNZHmpU3d5yw93sW5C9Jo7gyyq6SRr123ius3FnCqro3rf/ECLV0hPE4baXFuNhal8Kkrl+B22Lny+0/TGqPTZjBlDZ1smZ/KttMTk82guTM4ZFqRrz1wiD/evEULUysFpMS5WFeYwq5BUly4HTZW5CSyp6xpTIMdYi376SuX8JHLFhEt4qimmAaXlZrDRKQAq5BBaa+7rwEWR3+2AD+P/lYKERl0NLLHaefqVTkYowWVlZouEjxO3nPhAt5z4QK6gmE+e/c+Hth7Zkra8sm/7GXnF6+Yk6NLojkerwMiQA1Wx+0Z7dCd3kLhCB+8fRdPHq0d8TLG0BOYmp8eR7ZN+O6b1szJz72afKMcBDyuXrcujy+8cgUA5Y0d5CV7ERGWZSfy0Ccuwu2wkeh1DtgXtixI47HDo5tWv7u0kbX5yRgxlDd00tgRmLRtP3imhfZASIPLSkW9cnV2Ty2d7iJ7wVCErlCYhrYge8qaxv01v/zqFbxr6/xxX686e3qWo9Tc9gPgv4Dep2PXAX80lheBZBHJmZLWqWnr9hdLCIRiT3Hs33t8rLp1MpqklBqGx2nnh29ey1u2TE0KqObOIF++/yB/31VOdcvUpeqYIt8xxpxjjFkL/BP4UvT+3h2678Pq0FXTxP/96/CoAsu9LcqMpzDVxz0fOp+1Bcnj2zClBuF1Tk5hGJfdxkVLMhCxbq/KS+wT3M1P8fU5H8xN9pIW747ZyfKZVywhN2l0aWOCYcNL5U3sLWumvj1AgmfyxswVpvpI1bRvSvVYV5jC9tMNbD/dwM7iRvaUNnHgTAsnatpp6Bj/GXN5yV7efl7RuK9XjY2OXFZqjhKR64AKY8zefsHAPKCs19/l0fsqY6zjfVgXwxQWar7qucRpFyIjHKF8z+4KVuQm8po1uRPcKqXUcOw24euvXcXmolR+/tRJTtS2UZDiZVFmPB2BMM+frJ/Q1+/O3f7ARy4gK3Hu5KA1xrT0+jOOlzt1ezp0gRdFJFlEcowxA465avKEI4afP3WC3z9ffNbrKGvo4Ndv30iiR0c3qskjAmlxrglJgZTgcfCBixeSFudi66J0ClJ9HK5sweu0U5Qed9brXZadyH9dvYwnj9bw7PG6Ubfd57LT4Q+f9euP1qm6dp45VstVK7Mn7TWVms7mj2H/PxtvPbewZ6S0mj40uKzULCYijwGxzny+AHweKyXGWTPG/Ar4FcDGjRs1F8Ic8uZNVmdCuz9EnHvoQ8n7LprP8ycmNmCllBo5EeG16/J47bo8whHT5wT9wf2VfPZve2kPTNyFek6ih/wUL8aYOZUnT0S+DrwdaAYujd6tHbrTjDGGrz1wkEOVLSMqUtRbgsdBuz9ExMCNmwsn/YJbqYNnWoYMzrocNl6zJpf0eDe3/ecUboeNm86bR0GKj1A4QkcwzOOHa9hV0ogI3Lx1Plvmp9LYEWBpduKAUfjLcxLHpd3dxySAEzVtfOTPuzlS1crm+alsLkqlMNXHgwcq+c/xOsL9dspEr5PmjgDBScqLcfmyTA0sK9VLktdJgtsxqtzpZys1zsUNm/QcaDrS4LJSs5gx5opY94vIamA+0D1qOR/YLSKbgQqgoNfT86P3KTXA7tJGnj9Zz/z0OF65OqdPoNkYw/GaNvaWNXHewrQpbKVSajD9R35cuzqH507Ucce20kGWGLszzV2s/dqjvP/iBdxyzfIJe53JNlSHrjHmPmPMF4AviMgtwEeAL49m/dqhOzlEhA9duojMBDfPHK/jo3/eTUvXyC6Y7Tbhvg9fwG3PnuJdW4smtqFKxRA/TIf/79+5ifMXpQPwpo35pMe7SfL2HV3/oUsWUd7YgTFQMAWFKBdlxnPne8/lv/6+jzesz+fqVdbX6vWbCmhsD/DY4WoePljNM8drCYQiVDV34ZzgUYxep50l2QksTI/jU1ctmdDXUmqmERHyozMZJtKW+al8/XWrNC3NNKXBZaXmIGPMfiCz+28RKQY2GmPqROR+4CMichdWIb9mnZ6rBlPZ1MXPnzoJwLf+fYRrVmWTkeBmV0kju0sa8YcihCKG/7p6KR+6ZNEUt1YpNZzOQJg7tpWSl+wlN9nD7tKmAaPExsPCjDjetCF/3Nc7lQbr0I3hDuBBrOCyduhOQ90pWy5eksE3X38Of99dzrZT9cOO6H/D+nxEYOuidOal6ahlNfnsNvj5W9dT0dTJmaYuzjR1UtnSRZzLzrrCZDbNT+157sKM+EHXk58y+UHl3lLiXPz67Rtj3v+mjQW8aWMBbf4QJ2va+MFjxzhZ00ZZY+ew6/W57KzKS6IzEKa5M0hpQwfp8W42FaVw7oI0rl6VzQ8ePcbdu8pZV5hMnNvBG9bnc82qbBxalFOpQRWkeCcsuJwW5+K/rl7KGzcUaDqMaWxEweVo4KkVCAMhY8xGEVkD/AKIB4qBt/bLJ9e97CeB92DlltsPvMsYM+equCg1gzyIVbX+BFbl+ndNbXPUdHb16my+/dAR6tsDNLQHJnS0o1Jq4nlddv71sQvITPCQkeCm3R/int3lfO2fhwiGxyfILALfedMaFmUmjMv6ZgIRWWyMOR798zrgSPS2duhOc9euzuaV5+Twn+O1/PTJE7x4qiHm896ypZAPXbKQP75QwieuWDzJrVTKsigzYc58t8a7HawpSOb379rM8epW3vab7VTFKBab4HGwrjCFJK+T163L5bJlWT2PnaxtIzPBTUKv3OjfesM5/N9rV2kwWalRKJygWQ6FqT5uf/cWCtOmtsNLDW80I5cvNcbU9fr7NuAzxpinReRm4LPA//ReQETygI8BK4wxnSLyV+AG4Pdja7ZSajwZY4p63TbAh6euNWomSfQ4+dEN63jn77YTGmJ0o9OmJ+ijISJ2YCdW0c1XichlwHcBF7ALeLcxZsA8bREJY3XkApQaY14zWW1Ws8fK3KSe23FuB287rwify8Gn/7Z3XNb/mjW5rC9MGZd1zSDfEpGlQAQoAT4QvV87dKe57rzgFy7O4MLFGfz+udN8899H8IciPc/JT/Hy2rV5nKpr5xNXLJ5TucSVmg4WZyVwx3u38Pl79lPV0sWy7AS2zE9j8/xUluckDjracbDR2xpYVmp0xjuFjtth4/qNBXz08kVkJsydAtAz2VjSYiwBnonefhR4mH7B5V6v4RWRIOADzozhNZVSSk0zFyxO57JlmTxyqDrm4+fkJ/GqNTmT3KoZ7+PAYSBRRGzAH4DLjTHHRORrwDuA38RYrtMYs3bymqnmijdsyKe4vp2fPHFiTOsRgZW541MAaiYxxrxhkPu1Q3eGeefW+Vy3No9X/eRZKpqsafiLMuMpSPWSk+Sd4tYpNXctzIjnL+8/b6qbodScVJA69uPfd954DqvykthX3sRly7LISHCPQ8vUZBlpcNkAj4iIAX4ZLShyEGta3z+AN9E3X5y1kDEVIvJdoBToBB4xxjzS/3la/VoppWa2ofJfbV2YRka8nhyMlIjkA68Evg58CkgDAsaYY9GnPArcQuzgslIT5pNXLOHRQ9UcqWqN+fjCjDjecX4RDpuNF07Vc7SqhQsXZ/D+ixews7iRI5UtXLUym1V5STGXV2qmSIlz8ZO3rOO/797H8Zo2PnDxQg0sK6WUmrPGmhZjWXYCr16Ti8dpZ3nO3BuEMBuMNLh8QTRQnAk8KiJHgJuBH4vI/2Dliwv0X0hEUrAC0POBJuBvInKTMeb23s/T6tdKKTWzff7a5RyubKG4vqPnvnPyk7huTS7NnUGdXjg6PwT+C+hOmlgHOERkozFmJ/BGYnToRnlEZCcQAr5ljPnHBLdVzSE2mxAIW6kAvE47bztvHuctSGN7cQOnatv439eu6pm6+JYtfQcLXLs6h2tX6wwGNXvEuRzUtwdYlZfIll5F0pRSSk0dEfk0Viq5jH5pXbsf1xRyE2AsRUCXZiXwr49dqMX6ZrgRBZeNMRXR3zUici+w2RjzXeAqABFZgjXKqr8rgNPGmNro8+4Bzgduj/FcpZRSM1RBqo8/3ryFz969l50ljSR6HNy8tYhrV+fQ1SsvpRqaiLwKqDHG7BKRS8CaNi8iNwA/EBE38AhWgd1Y5kU7gxcAT4jIfmPMyRivozOG1Fn58qtXUtnUydWrskn2uQC4dFnmFLdKqcn3n+O15CR5+MVNGzTH8hwQoxbCR4BPAAsZJIillJpcIlKAFaMaqsK4ppCbAB6nnTesz6crGMZmE+wCdpsNu82a4Wq3CXYRbDahptXPzuIGqlv8AKzIHTwvupo5hg0ui0gcYDPGtEZvXwV8TUQyo8FmG/BF4BcxFi8FzhURH1ZajMuxDspKKaVmmcI0H3e+91zCxlBS38GiTKtIisthn+KWzShbgdeIyLWAByvn8u3GmJuACwFE5CqsugcD9OoMPiUiTwHrgAHBZZ0xpM7WxUsyproJSk0Lr12Xx03nzsPj1GPcHNFTCyH693PAP4GnpqpBSqkBfoA1++++qW7IXPS969eM+LnGGJo6gtS3BzS38iwxknnKWcCzIrIX2A78yxjzEHCjiBwDjmAV6fsdgIjkisiDAMaYbcDdwG6sqQc2ohezSimlZh+bTXDabT2BZTU6xphbjDH5xpgi4AbgCWPMTdG0VERHLv83MTp0RSQl+jgiko4VqD40aY1XSqk5JD3erYHlOaJXLYTbuu8zxuwxxhRPWaOUUn2IyHVYMwv2DvNUj4jsFJEXReS1k9A0FYOIkBLnYlFmPEle51Q3R42DYUcuG2NOAQO6IIwxPwJ+FOP+M8C1vf7+MvDlsTVTKaWUmtM+G02ZYQN+box5AkBENgIfMMa8B1gO/FJEItHnfcsYo8FlpZRSamx+SN9aCKOiqaiUGh8i8hiQHeOhLwCfJ5q2dRiaQk6pCTDSgn5KKaWUmkTGmKeITrc1xnwW+GyM5+wE3hO9/TywevJaqJRSSs1usWohjJamolJqfBhjroh1v4isBuYDe6M58POB3SKy2RhT1W8dmkJOqQkwkrQYSimllFJKKaXUXNNdC6EYuAu4TES0OL1S04gxZr8xJtMYUxRNLVcOrO8fWNYUckpNHDFmenXCiEgtUDLEU9KB2ViNd7ZuF+i2jdQ8Y8yMrZQ0yL47W9/72bpdMHu3bSK3azbuu5NhJn7WtM2TYzLarPvt+JmJn7Fu2vapMZa2T9m+Gx25/BljzKt63VcMbDTGjGh7ptm+O55m8udxJGbz9s26Y27v/bJ3CjkROR/4JdCdQu6HxpjfjGB9Y9lvZ8pnR9s5/mZKW4dq54j33WkXXB6OiOw0xmyc6naMt9m6XaDbNpfN1v/PbN0umL3bNlu3ayabie+JtnlyzMQ2z2Uz+f3Stk+Nmdr23sFlEfkYVh7mbKAGeDBa/2BOmqnv6UjN5u2bzds2HcyU/6+2c/zNlLaOVzs157JSSimllFJKKTWEfrUQfgz8eCrbo5RSSk0XmnNZKaWUUkoppZRSSiml1KjNxODyr6a6ARNktm4X6LbNZbP1/zNbtwtm77bN1u2ayWbie6Jtnhwzsc1z2Ux+v7TtU2Mmt13FNtvf09m8fbN526aDmfL/1XaOv5nS1nFp54zLuayUUkoppZRSSimllFJq6s3EkctKKaWUUkoppZRSSimlpti0CS6LyG9FpEZEDvS6b42IvCAi+0XkARFJHGTZ4uhzXhKRnZPX6uGJSIGIPCkih0TkoIh8PHp/qog8KiLHo79TBln+HdHnHBeRd0xu64c2DtsWjr5nL4nI/ZPb+qENsW1viv4dEZFBK2qKyNUiclRETojI5yav5ZNnkH025nsvlh9H/x/7RGT91LV8eINs23dE5Ei0/feKSHKvx26JbttREXnFlDR6hGJtW6/HPi0iRkTSo3/PmPdtsO0SkY9G37eDIvL/et0/Y96z2UREPCKyXUT2Rt+Tr051m0ZKROwiskdE/jnVbRmJ6XxuNBgRSRaRu6P77GEROW+q26QGJyJrReTF7s+YiGyO3j8jjh0z/fgwE4/Zs+Vcaq4b7Dqp1+N9PpszyVDbNth3xkwy2PYN9n2uRm6m/G+HaOeIYm+T3NaY1w0iMl9EtkWPGX8REdc0bedHom2cNt+HQ7T1jujx94BY19XOUa/cGDMtfoCLgPXAgV737QAujt6+GfjfQZYtBtKnehsGaVsOsD56OwE4BqwA/h/wuej9nwO+HWPZVOBU9HdK9HbKVG/TeGxb9LG2qd6Gs9i25cBSrErRGwdZ1g6cBBYALmAvsGKqt2kC/kex9tmY7z1wLfBvQIBzgW1T3f6z2LarAEf09rd7bduK6HvsBuZH33v7VG/DaLYten8B8DBQ0v19OpPet0Hes0uBxwB39O/Mmfiezaaf6GcpPnrbCWwDzp3qdo2w7Z8C/gz8c6rbMsL2FjNNz42GaPMfgPdEb7uA5Kluk/4M+X49AlwTvX0t8FSv29P62DHTjw8z9Zg9W86l5voPg1wnRf8e8NmcST+Dbdtg3xkz7WeI7Yv5fa4/s+9/O0Q7RxR7m+S2xrxuAP4K3BC9/xfAB6dpO9cBRUyjc/Ih2npt9DEB7jyb/+m0GblsjHkGaOh39xLgmejtR4E3TGqjxoExptIYszt6uxU4DOQB12FdRBH9/doYi78CeNQY02CMacT6H1w94Y0eoTFu27Q22LYZYw4bY44Os/hm4IQx5pQxJgDchfU/mVUG2WcHe++vA/5oLC8CySKSMykNPQuxts0Y84gxJhT980UgP3r7OuAuY4zfGHMaOIH1GZiWBnnfAH4A/BfQOxH/jHnfBtmuDwLfMsb4o8+pid4/o96z2ST6WWqL/umM/kz74g8ikg+8ErhtqtsyW4lIElYn0W8AjDEBY0zTlDZKDccA3SObkoAz0dsz4dgx048PM/KYPVvOpea6Ia4BIfZnc8YYYtsG+86YUYbYvsG+z9UIzZT/7RDtnHaxtyGuGy4D7o7eP+XxpsHaaYzZY4wpnrqWDTREWx+MPmaA7bx8fB6xaRNcHsRBXg7KvQmrJzQWAzwiIrtE5H2T0rKzICJFWL0X24AsY0xl9KEqICvGInlAWa+/y3n5wD2tnMW2AXiiU0NeFJHXTnwrz06/bRuJGfO+TYDB3vvZ9j+5GWt0EMyCbROR64AKY8zefg/N9G1bAlwYnTb1tIhsit4/07drRhMrvcRLQA1WB+pIv1un0g+xLpYjU9yO0ZgR50a9zAdqgd+JlX7kNhGJm+pGqSF9AviOiJQB3wVuid4/E75jZ+zxYRYds2fVudRc1fs6aYjP5ozU7xpwsO+MGavf9n2C2N/n6izMlP9tv3aONPY2qfpfN2DNbGnq1VE5LY4XM+n6Zqi2RtNhvA14aLTrne7B5ZuBD4nILqwh+4FBnneBMWY9cA3wYRG5aLIaOFIiEg/8HfiEMaal92PR3oEZ2bsLY9q2ecaYjcBbgB+KyMKJbenoDbVtamgz/XM9GBH5AhAC7pjqtowHEfEBnwe+NNVtmQAOrLRC5wKfBf4qIjK1TVLGmLAxZi1Wj/hmEVk1xU0akoi8Cqgxxuya6raM0rQ/N+rHgZXa5ufGmHVAO1Z6JTWFROSxaP69/j/XYY3k+6QxpgD4JNFR59PFMG2f1seHYdo+rY/Zw7S9+zmz6lxqrup9nYT1fk7rz+ZoxLgGnNbfGaMVY/um9ff5TDJT/rcx2jnS2Nuk6n/dACyb2hbFNpOub4Zp68+AZ4wx/xnteh3j1L4JYYw5gpWbCxFZgjUlNdbzKqK/a0TkXqwP3TOxnjsVotH/vwN3GGPuid5dLSI5xpjK6JS1WFNrKoBLev2dj5Xrd9oYw7b1ft9OichTWL1mJyeh2SMyyLaNRAV9e/ryo/fNBYO997PifyIi7wReBVweDZ7DzN+2hVgjBvdGz5Hzgd1iFZuY6dtWDtzTPb1HRCJAOjN/u2YFY0yTiDyJle5pQIHJaWQr8BoRuRbwAIkicrsx5qYpbteQpvu5UQzlQHmv0RN3o8HlKWeMuWKwx0Tkj0B3sau/8XLamGnxHTtM2z/IND4+DNZ2EVnNND9mD/V/h1l7LjXn9L9OGuqzaYypmsKmjtog14CDnVPWTlEzz9og2/cOYn+fq1GYKf/bWO0caextqvS6bjgPK+2TIzp6eVodL2bQ9c2AtorIl4EM4P1ns75pPXJZRDKjv23AF7GSdfd/TpyIJHTfxtohps2bGO3R/A1w2Bjz/V4P3Y/1RUP0930xFn8YuEpEUkQkBWvbHp7I9o7GWLYtuk3u6O10rIv3QxPb4pEbYttGYgewWKwqpi7gBqz/yVww2Ht/P/B2sZwLNPdKnzEjiMjVWNPiX2OM6ej10P3ADSLiFpH5wGKsPEUzgjFmvzEm0xhTZIwpwjp5Xh+9EJjp79s/sAqwdJ8kuYA6Zvh7NpOJSIaIJEdve4ErgSNT2qhhGGNuMcbkR/ePG4AnpntgebqfG8US/c4pE5Gl0bsuZxqdF6iYzgAXR29fBhyP3p4Jx45/MAOPDzP9mD1bz6XmmljXScN8NmeMIa4B/0Hs74wZZYjtG+z7XI3QTPnfDtbOkcTeJtsg1w2HgSeBN0afNlgsbdLMpOubwdoqIu/Bqvl2ozHm7NIAmmlQsTDaaX0nUAkEsQ5G78bq4TkW/fkWINHn5gIPRm8vwKouvBcrT8wXpnpb+m3XBVipAfYBL0V/rgXSgMexvlweA1Kjz98I3NZr+ZuxilqcAN411dszXtsGnA/sj75v+4F3T/X2jHDbXhf9fPqBauDh/p/J6N/XRj+3J6fbZ3Ic/0ex9tnB3nsBfhr9f+wHNk51+89i205g5QPs/jz8otfzvxDdtqNEqwFP159Y29bv8WJerjw/Y963Qd4zF3A7VlBtN3DZTHzPZtMPcA6wJ/rdegD40lS3aZTtvwT451S3YwTtnNbnRkO0ey2wM/r5+AeQMtVt0p8h368LgF3Rz9k2YEP0/ml/7Jgtx4eZdsyeLedSc/2HQa6T+j2n57M5k34G27ahvjNm0s8Q2xfz+1x/Zt//doh2xoy9TXFbY143YJ3nbo8eU/4GuKdpOz+GdV0awupkuG0q2zlMW0PRY3D3Z2LU12jdwVqllFJKKaWUUkoppZRSasSmdVoMpZRSSimllFJKKaWUUtOTBpeVUkoppZRSSimllFJKjZoGl5VSSimllFJKKaWUUkqNmgaXlVJKKaWUUkoppZRSSo2aBpeVUkoppZRSSimllFJKjZoGl5VSSimllFJKKaWUUkqNmgaXlVJKKaWUUkoppZRSSo2aBpeVUkoppZRSSimllFJKjZoGl5VSSimllFJKKaWUUkqNmgaXlVJKKaWUUkoppZRSSo2aBpeVUkoppZRSSimllFJKjZoGl5VSSimllFJKKaWUUkqNmgaX1VkTka+IyO1T3Q6lZjMReaeIPDvE4/8WkXdMZpuUmotE5Pci8n9T3Y7hiIgRkUVT3Q6llFJqJhORz4vIbVPdDqVmGxF5SkTeM8hjhSLSJiL2cXidgyJyyVjXo0bGMdUNUEopdfaMMddMdRuUUkopNTgRKQJOA05jTGiKm6PUrDTe+5kx5htjbpRSc5yIfAVYZIy5aSTPN8aUAvHj8drGmJXjsR41MjpyWSmllFJqhhMRHTCglFJKKaWUmnQaXJ7BRKRARO4RkVoRqReRW0VkoYg8Ef27TkTuEJHkXssUi8hnRGSfiDSLyF9ExBN9LEVE/hldX2P0dn6vZeeLyNMi0ioijwLp/drzNxGpiq73GRHRniKlRiHWPt3rse9G98vTInJNr/t7phV1p9AY4rnvEpHD0X34lIi8f3K3UKmZQ0TWicju6P7yF8DT67FXichLItIkIs+LyDm9HhvqOHuJiJSLyH+JSI2IVIrIa0XkWhE5JiINIvL5XuvaLCIvRF+nMnqcd/V63IjIh0XkOHA8xjZcICJlOiVQqb5EJFdE/h493p4WkY9F7/eKyB+ix9DD0X21PPrYZ0Xk7/3W82MR+VH09lMi8k0R2S4iLSJyn4ikRp/6TPR3k1jTfc+brG1VaqYaYj/dLCI7o/tZtYh8P7rIgP1MRGwi8kURKYked/8oIknR9RRFj6PvEJFSsa6dv9Dr9fukgNRrXaUGF2t/FZGrgc8Db47uk3t7LTJPRJ6Lnmc/IiLp0fV075eOXuu9P3qOfEJE3tvrNb8iIndHz7Vbo+fta3o9XiwiV0RvD3lOrcZOg8szlFg5aP4JlABFQB5wFyDAN4FcYDlQAHyl3+LXA1cD84FzgHdG77cBvwPmAYVAJ3Brr+X+DOzCCir/L9A/z+u/gcVAJrAbuGMMm6jUnDLEPg2wBTiKte/9P+A3IiKDrGqo59YArwISgXcBPxCR9eO+MUrNcNGTzX8AfwJSgb8Bb4g+tg74LfB+IA34JXC/iLh7rWKw4yxANlagOg/4EvBr4CZgA3Ah8D8iMj/63DDwSaz9+TzgcuBD/Zr7Wqz9fkW/bbgauBN4gzHmqVH+C5SatUTEBjwA7MXaDy8HPiEirwC+jHUMXgBcibVvdrsduFqigzaiF743AH/s9Zy3AzcDOUAI+HH0/ouiv5ONMfHGmBfGfcOUmkWG2U9/BPzIGJMILAT+Gl0s1n72zujPpVj7dTx9r28BLgCWRl/jSyKyfJBm6bWuUjEMtr8CBvgG8JfoPrmm12JvwboezQRcwGcGWf1dQDlWfOuNwDdE5LJej1+HdZ6eihWv+oeIOGOsZyTn1GoMNLg8c23G2sE+a4xpN8Z0GWOeNcacMMY8aozxG2Nqge8DF/db9sfGmDPGmAasL4G1AMaYemPM340xHcaYVuDr3cuKSCGwCfif6LqfiS7bwxjzW2NMqzHGjxXQXtPdM6yUGlbMfTr6WIkx5tfGmDDwB6yL1qxB1jPoc40x/zLGnDSWp4FHsIJZSqm+zgWcwA+NMUFjzN3Ajuhj7wN+aYzZZowJG2P+APijy3SLeZyNCgJfN8YEsU6Y07EukluNMQeBQ8AaAGPMLmPMi8aYkDGmGCuQ3f+Y/k1jTIMxprPXfW+KPvcaY8z2Mf4vlJptNgEZxpivGWMCxphTWJ08N2B1DH3DGNNojCnn5eAwxphKrJGRb4redTVQZ4zZ1WvdfzLGHDDGtAP/A1wv41CUSKk5aKj9NAgsEpF0Y0ybMebFIdbzVuD7xphTxpg24BbgBumbSuqrxphOY8xerODYmlgr0mtdpQY11P46mN8ZY45Fz1//St9zZcCa1QtsBf47em38EnAbVkdut13GmLuj59XfxxrAcW7/dY3wnFqNgQaXZ64CrCBSn2IFIpIlIneJSIWItGCNskjvt2xVr9sdRBOmi4hPRH4ZnTbUgnUCnRw9Kc4FGqMny91Ker2uXUS+JSIno8sWRx/q/9pKqdhi7tNRPfusMaYjenOwQgeDPldErhGRF6PTipqAa9F9VKlYcoEKY4zpdV/3MW8e8OnotLqm6L5UEF2mW8zjbFR9tPMHrBlCANW9Hu/k5X12iVgpqqqix9ZvMHCfLYvR/k8AfzXGHBhiG5Waq+YBuf324c9jdcTm0nef6r9//YGXRzPfhDW7obfezy/B6qTS46xSozfUfvpuYAlwRER2iMirhlhPLr2uWaO3HfQdpDHUMRvQa12lhjHU/jqYYfc7rP23ITrwsVsJ1ujobj3HXWNMhJdHOfcxwnNqNQYaXJ65yoBCGVjA5xtY0w9WR6cK3YSVKmMkPo01JWhLdNnuqUUCVAIpIhLX6/mFvW6/BWtKwhVAEtaUwu5llVLDG2yfHhfRKft/B74LZBljkoEH0X1UqVgqgbx+6We6j3llWCOPk3v9+Iwxd05AO34OHAEWR4/Ln2fgPmsGLGWNrHytiHx8Atqk1ExXBpzutw8nGGOuxdr383s9t6Dfsv8AzhGRVVhppvpPi+/9/EKsEZZ1xN5PlVKDG3Q/NcYcN8bciDWd/tvA3dFr1Fj72RmswFe3QqyUNdUxnjsUvdZVanBDHVfHcvw7A6SKSEKv+wqBil5/9xx3o+k58qPL9TeSc2o1Bhpcnrm2Y50Af0tE4kTEIyJbgQSgDWgWkTzgs6NYZwLWiKkmsQqQfLn7AWNMCbAT+KqIuETkAuDV/Zb1A/WADyvIrZQaucH26fHiAtxALRASq9DfVeO4fqVmkxewLj4/JiJOEXk9VuoasKb5fUBEtoglTkRe2e/Ed7wkAC1Am4gsAz44wuXOYOWS+7iIjHQZpeaK7UCriPy3WAX87CKySkQ2YU3NvUWsItd5wEd6L2iM6QLuxsrruN0YU9pv3TeJyAoR8QFfA+6OzlSoBSJYOV+VUsMbdD8VkZtEJCM6SrEp+vwIsfezO4FPilWYPp6X87/Gmik4FL3WVWpwQx1Xq4GiaOB3VIwxZcDzwDej18bnYM1cuL3X0zaIyOujA7Q+gbWfxkqVc7bn1GqENLg8Q0VPVF8NLAJKsYb/vxn4KrAeaAb+BdwzitX+EPBijbB4EXio3+NvwSoa1IAVeO5dwOSPWFMUKrDyRQ6V+0op1c8Q+/R4rb8V+BjWhXMj1v58/3itX6nZxBgTAF6PVQSoAWtfvCf62E7gvVgFgRqBE/Qt2DeePoO1r7ZiBbX/MtIFo0Gvy4HPich7JqZ5Ss080ePtq7DyO57GOu+9DWs04tewjr+ngcewAsn+fqv4A7CagSkxiN73e6zpvh6s4253mqqvA89FpwwPyAeplHrZMPvp1cBBEWnDKu53QzRncqz97LdY++Uz0fV0AR89iybpta5Sgxhmf/1b9Gn1IrL7LFZ/I9ZMgTPAvcCXjTGP9Xr8Pqzz9EbgbcDro/mX+zvrc2o1MtI3naBSSimllFJKqejI/xuMMRf3uq8Qa2pttjGmpdf9TwG3G2Num/SGKqWUUnOMiHwFWGSMuWm456qJpyOXlVJKKaWUUnOeiOSIyFYRsYnIUqx6JPf2etwGfAq4q3dgWSmllFJqLpuQwlFKKaWUUkopNcO4gF8C87Fyud4F/AwgWjCsGmtq/NVT1D6llFJKqWlH02IopZRSSimllFJKKaWUGjVNi6GUUkoppZRSSimllFJq1DS4rJRSSimllFJKKaVmDRH5rYjUiMiBXvd9RUQqROSl6M+1U9lGpWaLaZcWIz093RQVFU11M5SadLt27aozxmRMdTvOlu67aq7SfVepmUf3W6VmJt13lZp5pmq/FZGLgDbgj8aYVdH7vgK0GWO+O9L16H6r5qrR7LvTrqBfUVERO3funOpmKDXpRKRkqtswFrrvqrlqqvZdESkGWoEwEDLGbBSRtcAvAA8QAj5kjNk+1Hp031VzkR5zlZqZdN9VauaZqv3WGPOMiBSNdT2636q5ajT7rqbFUEoppWauS40xa40xG6N//z/gq8aYtcCXon8rpZRSSimlLB8RkX3RtBkpU90YpWYDDS4rpZRSs4cBEqO3k4AzU9gWpZRSSimlppOfAwuBtUAl8L1YTxKR94nIThHZWVtbO4nNU2pmmnZpMZRSSs1ekYihsqWLM02d7CtvprKpk4iBU3VthMKGNQVJXLMqh1V5SVPd1JnAAI+IiAF+aYz5FfAJ4GER+S5WB/L5U9g+pdQcdvuLJbxxQz4ep73P/aX1HTx/so6wMazISWRVXhJO+8wa79J9LDte3co5+cmkxrmmuklKKaVGwBhT3X1bRH4N/HOQ5/0K+BXAxo0bp1ehsmlqb1kTXpedJVkJU90UNQU0uKyUUmpSbDtVz3//fR/F9R3kJLmpaQ0QjvQ9V3v2RB0/ffIkCzPicDvsbJiXwgcuWUhesneKWj2tXWCMqRCRTOBRETkCvBH4pDHm7yJyPfAb4Ir+C4rI+4D3ARQWFk5mm5VSc8DJ2ja+dN8Btp9uYPP8VAxw6EwzL55q4HRde5/nep121s9LZn1hCvkpXnKSvCzIiCMjwY3bYY/9ApPoRHUrCzPjaekKcaCimdQ4F/kpXpo6Avzm2dPsKG7g+o0FvHZdHusLrdnVZQ0d7CtvZv28ZHKS9PillFLThYjkGGMqo3++Djgwle2ZTW579jRHq1q45drlFKXFMT89bqqbpCaRBpeVUkpNuAMVzfzpxRJqWv1kJ7px2u0DAsu9nay1gg+HKlu4e1c5D3z0AhZlxk9Wc2cEY0xF9HeNiNwLbAbeAXw8+pS/AbcNsqyOxlBKTYh/7avklnv2ETFw/94z3L936Ow8ncEwz52o57kT9X3uT/E5WZ2fTJLXyavPyWFBRjxel33SOxu/++gxdpU0cE5eMhuKUjh0pgURYfvpeqpb/MS7Hfx1Rxl/fKGEa1dnc/BMCyX1HXz40oVsKkqhurmTLA0wK6XUpBORO4FLgHQRKQe+DFwSLYBtgGLg/VPVvtmkqrmLf++vJBQxvOt3O8hIcPPoJy8i2dd3Zs9fd5Tx4IFKbnv7Rhx2G82dQQCSvM6paLYaRxpcVkopNeFW5SVx61vWc+OvXuSFU/XkJ3vZPD+VmpYuXA4bx6rbBl22Mxjmrbe9yFOfuRSva+pHsU0HIhIH2IwxrdHbVwFfw8qxfDHwFHAZcHzKGqmUmpO+/dARWrpCY15PY0eQZ45ZeS4fiAaoE9wOnr/lMhI8E3cR2hUMc8/uci5aksEjB6t56EAVizLjefxIDY8fqRnw/DZ/iNxkD2eauthxupH5GXG0doa46dx5ZCZ6aO4IUNHYQWcwTFFaHI4xpACJRAyPHKri8uVZMy6ViFJKTTZjzI0x7v7NpDdklmnpCvL00VpW5CayMMMa/HPHthJCvQYO1bb6+dhdL/Gt16+mvLGT3aWN7Djd0HMc/c7DR6lu6WJnSSPGQH6Kl6tXZVOY6qOsoYN1hSmsKUieis1TZ0mDy0oppSbFzuIGSuqtEcnlTZ2UN3UCsGV+6rDLVrf4uf3FEt570YIJbeMMkgXcKyJgHcv/bIx5SETagB+JiAPoIpr6QimlJkuyz0lpw8Ssu9Uf4vpfvsgVyzMpSoujtSvIgTMtfPdNa8Zl/SdqWvnQHbtJ9rn48/ZSmjqsEVX1bX5W5SZy4ExLzOUi0Qvq2jY/89J8ZCe5ed1Pn+fa1Tm8aWM+y3MS+ee+M3z1gUP88M1rSYt39ywbDkdo6AhQUt/BitxE7DahKxAmqddor6rmLv59oJK/7SznUGULv377Rq5ckTUu26xGRkSSsWYDrcIa8XgzcBT4C1CENQLyemNM49S0UCmlJkZFUyd7ShsJhCJcsDidv2wv43uPHqMw1ccTn76YsDHcub10wHLPHKvl/G89EXOdv3zmVJ+/85I93Lm9FH8wQklDBwCfunIJH71sEdHrHTXNaXBZTStdwTC7ShoJRQzxbuvj6bAJ6QluDlQ0c6yqlVDE4HLYcNlt5CZ7WVOQxCMHqzlZ20Y4YliYEU9du5/6tgCRiGFBRhzxbgd2m5Dsc2ETIc5tZ3VeEg6bDbFZufEWZybQEQiR4HFit+kXmFLj6WdPneD/PXQ05mPVLV14nXY6g+Ge++JcdlblJWGA7aetKMWtT57gDRvytXASYIw5BQyIphhjngU2TH6LlFLKkpngAZonbP2HK1s4XNk3yFuQ4iPB4yDB42BZdiItXUHykr3MS/ON6KK0IxDi/z10lIcOVJGb7Ok57nRr7AjS1Blkc1Eq24tffmxDYQo+l509ZS/HE3eWNOK0CfPSfOyvaMLrsvHCyXr2ljfRGQjz1tu28Z03nkNavJvK5i6eOlKNP2zYdqqeT1+1lOdO1HHvnnIWZSYQ73ZwqLKF8sbOPu25e1eZBpcn34+Ah4wxbxQRF+ADPg88boz5loh8Dvgc8N9T2UillBpPpfUdXP79pwiGrU5Un+vla7bShg6+8sBB1hWkUNcWGNPriMiAmazff/QYz5+s4+at81k/L4X0Xh2zavrR4LKacB2BEIfOtNDUESQ32UuCx0F+ihcR4fkTddyxrRR/KMz20w0kep34XHaaOoLUtfnpnZK1MNXHipxEdpY0Utfm7/MaCW4HbYEQZojMoXabkJ3oId7tIBCOUNPSRXsgPOB5m4tSefWaHDoCYdwOG8tyEjl3Qdp4/TumHREpBlqBMBAyxmwUkVR0JIYaJ9tPN/Cdh2MHlgGK6zuId9lZnBVPa2eQls4g7YEw26IX9+fkJXGkupXmziD3v1TBO7fOn6ymqznIGEObP0Scy4FNOxqVGrVrV2fz2OHqSX3NHzx2LOb9RWk+rlqZzevX57EsO3HA48YYnjxaw0+eOMGe0iaSvE4OnokdGDcG9pY3sXVRGsGwobUryK7SRnKTPKT4XLT5Xw4Ary1MZkdxI9S2s6O4kUWZcZyosWbu5CR5+N4jx3juZF3PxXq3t/92e8/tmta+Oah7e+JIDfVt/j4joNXEEZEk4CLgnQDGmAAQEJHrsPK5AvwBKyWVBpeVUrPGgwcq+xyrOvrFT/68rZQnDg9MGTVata1+nDYh2K8mz4unGnjxVAM2gVuuWa6zWKcxDS6rsxKJGCpbuqhp6SIQitDmD3G4soWKpk78oQi5SV4cduHgmRZau4KUNXRS0fTySXdeslUJvKKpE5fdRjAcIS3eTWcgTEN7IGbPV2lDB6XRKRL9tfqHz+0Xjpg+bYglNc5FeyDEttMNFKXFsaAgmWXZCcOuexa41BhT1+vvz6EjMdQ4qG3189E7dw/Z8QPQFghzfJC8yzYRAqEIAP/7r8MUpcdxydLM8W6qmuOK69r54wsl3L/3DFvmp/LadXlcsTxTp+IpNUrXrs7hGw8eHvMopvFQXN/Br545xe0vlvDBixdy07nzSIlz0e4P8Y+XKvjTCyUcqWplcbRgbJzLTkdg8HNKfyhCVzDCrpKX+9sddluf89NNRSlWYLmXePfLOaIrm7tI8joHBJZHIxg23LGtlI9dvvis16FGZT5QC/xORNYAu7CK52YZYyqjz6nCSlmllFKzxvMnB+/oBIgYONPcNebXOVXXTmGql9KG2PGaiIGvP3iYJK+T6zcVjPn11Pgb1+CyiHwSeA9WHqr9wLuAHOAuIA3rQPy2aG+vmgGMMRyrbiMUieBzOchO9OBx2nj6WC0GQ1lDJydq2jhc2UJNq5/OYJjOQJi2fsHeuH5FuCqaOocN9II1IjnR66S1Kzjm4jDp8W4SPA4cNsHrsrMwI57WrhCFqT5evSaHpdkJ+Fza3xKlIzHUuHjoQCXVLf7hnziIxVnxnI7maQark+iBvZVcsCh9TEWRlOrW0B7gx48f5/YXS8hMcPPbd27knPzkqW6WUjOWx2nnVefk8vvni6e6KT06AmG+9+gxfvLECdwOG+2BUJ/ZcQ671Yl0prmLjfNS2Fky+GSt/t1NyT4nNS02VucnEY4YXiprGrBMeWPfwRHduZzH4o8vlPD+ixfgdmih20ngANYDHzXGbBORH2ENvOhhjDEiErPHQETeR7QGQmFh4US3VSmlxk1esmfSXmsksZhb7t3PkuwE1mqxv2ln3CJpIpIHfAxYYYzpFJG/AjcA1wI/MMbcJSK/AN4N/Hy8XldNjLKGDv62s4yWrhDHotPRD0aLmGwqSuE9Fy7gkqUZuB12TtS08cyxWp48WkNpQ4eV9sLuJTPRw6Z5KRhgR3EDJ2raCEUMxhhaukIEQhFsQt+Te5uwOj+J9124gFDE8PjhavZXNOMP2YGxBZfr2/247MKivCSWZMWztiCFVXmJZCd65vrINAM8Ej0h/qUx5leMcCSGniwrgFA4gt0mffajY9WtPHqomieOjG2aVH1bgObOvhfhjxys4v+98ZwxrVepquYu7tpRym+ePU1rV4i1Bcn86u0bovlilVJjsWuI4OxUCoQjBMKRAfc7e3VWnqxtwy4w2MBir8vOosx4UnxOOqKzbmxibXMkxjKFqV4q+43qqm3zI1gnYGerrs3PP/dW8oYN+WNYixqhcqDcGLMt+vfdWMHlahHJMcZUikgOEPOkJ3pu/SuAjRs3juVtV0qpSROOGGpbz36Q0Gh1xkhZ2l84YvjK/Qe554Pna/q6aWa8h2k6AK+IBLGKHFQClwFviT7+B+AraHB52uoIhPjaA4d47mQduUlealv9lDd19kxJB9hR3MiO4l14nDauWZVDZoIbt9POb9+5ibt3lRMOG7YuTqcw1ced20tp6QqyrjCFNfnJeF12Ns5LYUlWAs+frOeZ6Ahou01wO+w4bMLhqha++sAhalq7Yp6kj1RWopvFmQl4nHauXpXNRUvSNWgQ2wXGmAoRyQQeFZEjvR8caiSGniwrgG/++whPHq1h68J01hQks+1UPXfvLh82FcZwnHYZMAsCrDQ4N922jStXZNHmD3HZskxW5SWN7cXUrHOqto2qli5cdhsep52WriC1rX6OVrWyo7ihTyDIaRd++tb1eoxQahyUN3YMmrd4urJHO0dX5SbS5g/ROMTI4rKGDkoaOnqOcectTMVls/HsyXq670z1OclN8eJ22Clt6BiQAiMcMSS47bT6h7+QHsoTR2o0uDwJjDFVIlImIkuNMUeBy4FD0Z93AN+K/r5vCpuplFLjqri+naeP1rJlfioVTZ0Disv2lp3oweWwDUhjuigznhM1sVMf9pbic+J1jWwmzktlTXz/0WN84orFOpN1Ghm34HI0OPVdoBToBB7BSoPRZIzpjg6UA3n9l9XRj5PrxVP1PHeijsOVLfz8pg09ozWMMdyzu4KaVj+ZCR4rxUUw3Cew3FtXMMK9eyp6/r53TzkAnYEI+yqa+OIrV/CPPRUDpha67NbUwaK0OACC4QhPHKmJGUQais9lJy/ZSyAcod0foq4tgNdpJyfZwxs35POaNbnkJXvn+qjkYRljKqK/a0TkXmAzIxyJMRuV1ndQ3+6nusXPK1Zm6ednGDuKG/jtc6cxBk7VtvOnF0vGZb0CrMlPjjm9GOCFU/W8cMrKAfb9R4+R6HFwweJ0vvn6c0jyOmMuo+aGYDjCl+47yJ3bS0e8zKLMBHKTNLCs1Hi4c3vpmAYHTAWXw8a8VB8HorP0hlLR1Nkz6jg1zsWZpi4CoTDhXhvd0BHE47JzpmnwPJRLsxOHTL8xEs+frMMYo+cqk+OjwB0i4gJOYaV/tAF/FZF3AyXA9VPYPqWUGjfhiOEL9+4nGDFsO92A12ljTX4Se8ub8TrtJPucPbNyvC47SV4nR6utGgZel52Kxk4CYWum+uq8RNr8YU7XtQ/6eosy4wfUKxjKrU+e4PEjNXzz9as1RcY0MZ5pMVKw8rTOB5qAvwFXj2RZHf04doFQhBM1bRgMnYEwIkJ+ipesxIEXy+cuSOPcBWlEIqbPVAIR4aZz5/Gatbn8/rliDlQ0sygznlO17cS7HcxL81Ha0MHRqlaaOoIDphWW9Uq+/uD+KorrOghHDK9cncOizHgEuGN7KbWtfnaVNPZMmUz0OMhL9uIPhalrCwwaZE70OFiSlUBWoocknxOPw068x4HPZefGTYU4HYI/GCHJ69QpEiMkInGAzRjTGr19FfA14H7m4EgMYwzv+v12Tta243Xa+fN7t7CuMGWqmzVtBUIRvnjvgTGPUI5lY4yCSENp6Qrx4P4q9pU3c9WKbL706hXj3yg17VU0dfKFe/fz1NHaUS13uLKF3z5XzLsvmD9BLVOznYh4gGcAN9b59d3GmC+LyHxGUHtERG7BSh0XBj5mjHl40ho/jv61r5KfPXVyqpsxak67UDJI0ej+Ej0OMhM9HK5sZUF6HDtLGllfmExlc9+pwwXJviGDywcrW0j1uWjoOPtSNI0dQf68vZS3bpl31utQI2OMeQnYGOOhyye5KUopNeHu3VPBi6caev7uDEbYW97MvFQfrV0hKpu7WJ2XiM0mnKpp42h1KwDH+41Sbu2y/rZiU+5Ba/GcTaf04coWXvez5/j0lUv48KWLtKN1io1nWowrgNPGmFoAEbkH2Aoki4gjOno5H6gYYh2qn9auIM7olN6h1Lf7OXimmWdP1OF12nnscA11bX5u2FRAa1cIBK5dlcPCzDhyk70keqwAbDhiOFHThtMuZCd58LkcJHqcfapPP3eijttfLOHpY7VDToUASPA4KEqLo77Nz+r8JDLi3aTFuxARnHbhujW5VDZ30eYPUVLfTsRgTVOOfhn1ZhMoSovD47TT5g9hMBisnrFAKMKW+alct7bvQHifa+T/WwVYuZTvjX4RO4A/G2MeEpEdzKGRGC+VNfHMsVp2FDdwstbqUe0MhvnM3/Zy4+ZC3nPhgilu4fR0x7aSmPvuWMxL9ZGV6B5ySvJQyhs7+dOLxbxiZRZbFqQN+rzK5k4OVrSwtjCZ9Hj32TZXTSN/3lbK//7zEJ3Bs5tm/r//tNIx3XLN8nFumZoj/MBlxpg2EXECz4rIv4FPMUztERFZgVWnZCWQCzwmIkuMMWPLmTDJalv93HLPvgnpcJxoxfUd5CR5BuRG7q8ozYc/FKGkrp2l2Qk4o4UA95Q1sbkolbJo4b70eBeNnQFW5yVhs4FNBAGqW/0EQhHmp8chgNMhPHu8fkxt/+7DR3njhnwt7KeUUmrcPHSgKub9vTti91cMP9unW3ljJ5kJbnKTPJyJcawdSb7lWIyB7z5yjOL6Dr7zxnM0wDyFxjO4XAqcKyI+rLQYlwM7gSeBN2KN2pgzIyDPRm2rn92ljXQEQhyubKW6pYvShg5CYcOSrAQ+ddUS8pK9MZfNSfLy6jW51LcHaGgPcOWKTErrO9h2qp6QMTS2B/nXPqs+m9Mu3Pnec9lYlIoAP3niOP8+UEU4YshMcHPp0ky8Ljtv2VLIkqwEti5KZ3FmPCdr23lg3xmeOFxDVYv1hbAgI468ZC+tXSHKGjr46nUr2TI/jb/sKOXnT53EAKGwQaKB4uM1rSPulYoYONVv6kRLpzWq+fXr81ianXBW/2f1MmPMKWBNjPvrmUMjMT71l5cGfNYATta283//OszzJ+u5elU2GQluLlyUrrmdgObOIN9/5NiA+5dFq/eWNXbw3ImRXzDbBDbOS2FveTNnmjvHdJEcDBtO1rYPCC4fqGjmrh2llDd29oxs/ebrV3PjZk3HNJMZY/jOw0fHZbTkL58+xeaiVC5fHrOGqVKDMsYYoHu4jjP6YxhZ7ZHrgLuMMX7gtIicwEpR9cIEN3tcPX+yjpausRVfnirljZ3YBTYXpXC8pi1mB+eGwhQOnGnGH00Xd7Sqlcx4F5uKUhARGtsD2G1CVXMnlc1deF12ugLhmEX7ugskrR6HegGNHUEeOlA1YMCFUkopdTb8oTDPnagb9/XWtPpZmZsYM7h8pKqFRK+jJ94zWnfvKufKFVm8YmX2WJupztJ45lzeJiJ3A7uBELAHK9XFv4C7ROT/ovf9ZrxeczZ4/mQdD+6v5KoV2eQmezhW1cqZ5k7q2wI0dwbJTHCzJCuBV56TM2hgORCK0OYPkRrn4gMXL+y5v7bVj9shPHywGo/TzqKMeO7aUcq+ima+98gxPnTpQi5cnMGtb1nP6bp2bvvPKWpb/XQGQzjsQnFdOw6b4LDZcNiFcxekct7CNHgddAXDtHQFcTvsJHocBKMBZKfdxq6SRkSED126iK2L0gF4+mgtf99d3tO2OJedvBQvx6qHTu4+L83HdWty8YcjuB12Un1OLl+eRUGqbxz++0qNzBNHanjiiJV2OsXn5CuvWTnnL+KSvE5+885N5CZ7enK0P3ywitesycXjtGOM4eGDVXzl/kM9nVGDWVuQTGcgzPZeaTCC4bEFKL7z8BH2lDbiddkJRwxNnUEeOVg1oKhSeePIpkGr6ckYw3cfGZ/AMlj793pNhaPOkojYsVJfLAJ+CpxkBLVHove92OvvwZ43rV29KpvsRM+w3/nTVdjA9uJGvE4bW+ansq+imc5AGLvAhnkpfY5R3WraAhSkxbGruGHAY52BMPNSvZQ0DJz1Z4/OHvSHxmdw+p3bS+f8eYlSSqnxUdbQedYzAYdztKqFojQf6fHuPnUHMhM9VA0ze2g4P3niOFcsz8KuKVKnxHiOXMYY82Xgy/3uPoU1+mLOaekKsq+smabOAOGIIdnnYmdxA8eqW7l0aSavXZfH+QvTOX+hFYBtaA/gdNho7Qrhctg4Jz8Jr8vBuoJklmUnDvo6Dpvw520lbDvdwI2bC7l2dQ4AGQnWVO83rM9HxMqp/NXrVsVcx/z0OL7+utU9Rf3a/CEqmjopa+zEHwqzJDOB7EQP3bMMnHYb33rwCOVNnVyxPJP3XfRyULupI8BLZU08f6KO7zx8lPMXppGX7GVBRhzLshNo6gxS3+bvCSyvzE2kMNVHcX0HHqc1IjTe7cDjtHPViizetLFgbG+EUliF+lwOG9kxinblJntjjlyOpbEjyJfuO8hFizNIiZvbeVg2z0/tue1y2Li+174qIly9KoeNRal88i8v8Z/jsXu/U+NcHKlqoSsYu3Do2WrsCPK3XeVDPuf716/htXoxPmMZY/jeI8f46ZPjl981P8U35/drdfaiaSzWikgycC+wbDzXP90LYLsddm6+oIhvPHhkqpsyJp3BCNtON5Dic7IqJ5FQxMQMLHcrqW8nzmWnPcaU3gSvC2tC58tevSYXr9PGX3eW09IZZEVOAg67DbsIHYEwlS2dox65tae0ia5geNg0ekqpkQtHDOWNHcyLFqHvdqCiGX8ozPrCFJ2Cr2Ylr2vijiWhiJWKKtxvOntTR4DNRbE7ckfqQEULH7trD//1iqUD9ls18cY1uKygzR/i+RN1/HVnGc8cqyMQjhDvdpAa56I0mp8mM8HNZ65aisdpp7kjyL6KJjoCYS5bltln5HFvxhgOnmnBH4qwvjC5z4HMZhM+ctli3hsK0xZjOmJ3cbs2f4jmziC5SZ6e5XsX9esIhPjF06fYVdKAIGQmuMlP8RLndmCz0RNYNsYgwPffvJa9ZU0EwxGejI7s3FnSSGN7gFAkQld02uDzJwefGi8CB8+0cDBandvjtNEVjPDGDfksyowftLifUqP1f/86xCOHqlmRk0iyz4nbYWNjUSp/3lZKRdPQucT7a+4Mcv0vX+DuD55Pktc5QS2euYwxGGN1sKXHu/n5TRu45DtPUtc2sGhRQ3uAtDgXizO9hCOGQ5Ujz901FmlxLl51Tq4W/5yhjDH84NFj3PrkiXFdb/UoRlzWt/lpaA/w5NEauoIRalq7OHSmhQ9cvJCrdErenGaMaRKRJ4HzGFntkQqgd096zOfNhALYK3LGnuZhushK9NDcFRx2ll1dW4AVOYkxj1+2GEkxNs5L4bJlmRyraqOqtYtDlQNrFyR7nWQlekjwOrAhnKhppWGIWgT+UIQH9p7RARlKjaO6Nj+v+vGz/OrtGzl3QWrP9fPTx2p7BlD94ebNOO022vwhOvwhMhM97IjOZFhXkKyp9NSMUdncyeHKForrOkZ1Pny2cpO9lPWq59UVjFDbFrvY32j8a18ljxys4g83b+4ZxKkmhwaXxygQivDPfWcoqe/geE0rjxysJhTthSlK82ET4bfv3MSTR2u476UzvGtrEUuyEghHDD998gTFde14XXbee+ECSuo7SPI6e0Ycdzt4pplvPHiY507Ukxbn4ta3rLfSU/TjdtipCfj56p17yEhwszwnkTX5STjtNu57qYKCVB+BUIS7d5XT5g+RneRh26kG1hYk8/XXrWJBRjwfvnQhz59I5r6XKjhS1UpJQweBUIQVOYn8bWc5+yuaqWvzk+hxsiQrgVV5idhtQoLbybw0H0uzEyht6CA93kV9e4BVuUm8cKqeisZOnHZh66J0jLFOgp12YU1BMvVtAbqCYb7+4GFcdhtZiW68TjtZiW42zx+8IJdSI3WkqoVHDlUD9Ln4ezKad/dsHK9p40RNGxvm6RT6cMRQ1tDBkaqWaAqRWuqiJwdLsuLxOu00tA8MLHerbw+wMCO+pwNuMrxuXR4uh57wz1Q/fOw4P35ifAPLYOWCq2ruijnDodtTR2v4y44y/t2r0MnK3ET+9O4tOO0SM7+qmv1EJAMIRgPLXuBK4NuMrPbI/cCfReT7WAX9FgPbJ6Xh4ywn2YPLbiMQHt/ZKJOpKM1HgsfJ/ormAY/lJHnIS/FiF6GlK8jhaGC41R+kMNVHMBzBHwrjD0bwhyIDvg9esTKLt583DxFhbWEyv3++OGYbmjqDNHW+HEx2OWxsKkqhpqUrZpoNgL/uLNPgspr1IhHDcyfruHBxxoS/VlqcC7tduPHXL7IgPY4f37iOVXlJvOP8Ih7cX8nzJ+u5d3cF128q4C87yvjhY8f4r6uX8aPHjlHXFmBemo9bb1xPUbqPiLE6xsMRq0B9qs+lAxzUtHGsupW33ratpx7AZOiuX9BbkscFjP16MBg23HLPfv750QtI8OhAsMmiweUxsgnEuR2szktifrqPGzcXsqO4keaOAB+9bDF7yhr5/fPFJHgc/Ondmylr6OQL9+6noqkTm0hPVeo/vlDSs85z8pO46dx5XL0qm0SPk5W5SXzh2hXccu9+9pU38eX7D3Dpskzykr2crGnjWHUb5y9M46OXLyY/xcvbzpvHcyfqePpYLQ8dqGRzUSp7y5v52VMnSY1zsTI3iZKGDo5VW8X1tp2u51h1Gwsy4nE77Fy6LJNLl2VS3+bnpbKmnsJGoXCEv+8u5yv3H6Km1Y/BGpm4uSiVrQuTOH9R7J6hV6/JBawDanljJydq20iLc9HSGaKmxU+c287K3ER2fOEKwBo59vTRWl65OleDP2pc/Oix4xOy3qxE9/BPmuWaO4Lc9JttMS/CgSFHfKXFWZ1QWYlujDF4nDbW5Cextzz2usaLy27jHecXTehrqInREQjxnYeP8rvniidk/TaBmtahg8sFqT4WZMSxcV4KO0sasQm8aUM+qZpOY67LAf4QzbtsA/5qjPmniBwiRu0REXkNsNEY8yVjzEER+StwCKtuyYejKTZmnIUZ8Zy/KK2naOpMkp3oJjfZy+7SpgGPrcxNAISDZ1p6zt3T41/e58sGCfj2v3h+04aCntGP8e6RX4YFQhF2RKcKF6R4yUn2cKiihbZeqTj2lk3ssVOp6aCypYsP3r6bH755LVesGFh8t7iunTt3lPL6dfljLv7usNv4wrXL+eoDhzhV187rf/48VyzPJDfJ2/M98IV/7OepYzX8+0AVxsD//ONAz/Il9R28+tZnY647Nc7FxUsyKEz1cU5+ElsXpfektTlS1cKp2nZS41wsz04kyafBMTVxwhHDp/+6d1IDy0DMvMhl41gLp6S+g589dZL/vnpcM5SpIWhweYwcdtuAipTdPaktXUGSfS7etDGfFTmJ3Lm9jH+8VGH1Vsa5qWq2TkQXZsSRn+LjmeO1uOw2jlS28vl79vPnbaVEjMEmgsdpI9nrxGm3cay6bUDA5hUrrYPrwwer2FvezJs3FlCUHsf+8mZCkQhXr8rB6RBO1bbzi6dP0tQRoDvNTaLXid0mlNZ3cLiqhT2ljTx3op7yxg7iPQ6ePVHHJy5fQpLPSUGqj1DEOlGubfVT2+pnX3kzjx2uJsnrpCMQxud24A+GyUv2sigzngNnmilt6KCyqatnVHcsboeNpdkJvHZtHjdfMH883h6lKGvo4NHoqOXx9K6tReSnzO3Cki1dQb798JFBA8tD8ThtpMa58LnsJPuc7IgWdHDZhbwULxWNo0tVMhpfu26lFgWdYdr9IR7cX8kPHzs+6jQ2I/WO8+bx3osWDLtfL8yI57OvWEYwHOGPL5RQlObr6YRVc5cxZh+wLsb9MWuPGGPuxxqx3P3314GvT2QbJ0soPLPG7yd5HSzJSmBPaRNVLX0vrrMS3KQnuHvSt/VW1xYgL9lDRdPg04f7p3f77XOnWVuYTHq8m6tXZZ9Vap+yRqsmisMmLMtOIN7twGYTgqEIJXXtzEvXPJNq9spL9rLzi1fgHmQAUtgYfvdsMbf95zTvvmA+n7hiMS67jcrmLgLhCAvS46hs7uJjd+5hY1EqWxelsSAjnpxET99UkU+dpDGaimZFbiLbTzcQCEV4cH9Vn9cLhg1Hqloxo/zaa2gPcO+el7Mfuew2CtN8RIzhVO3LdWBsAucuSOO9Fy7gkqUZmuNZjbs/bys5q2u5sapt7WJxZjzJPicl9R1kJXrG9Rzf47TxtnPnjdv61PA0uDyBEj1ONhW9XPDqLVsKecuWQhrbA+wqaWRhZjwl9e3kp3h57kQ9Baleqpr9dAXDGAz7y5vxuuyctyCN1DgXi7MSuPmC+VS3dOFz2alr9ZOb7GVpdkJPwvJl2YlkJXpIj6bWWJ3fN/ddapyLm8Pzee+FC3DYhLAx5CV7KUz14bDbaOgIYLcJ2UkeGjsClDV08ofni1mek8j1Gws4f2E6rzonl38fqCQ36eUiaGeaukj2ufCHIhyvaQLgSFUrjx+pifm/2VyUyvZ+lbX9oQiLMuKtqUO9ckErNVrNHUFePF1PYaqPeLeDV6/J7XMCNx4qm7qoa/OTHj93Ri+HwhG+8eAR/KEwDe0BdhQ39qS/GK2uYITqli4cNluffFuBsKGpPcDK3ESMgXAkQoLXycGKFlLjXaMOOid6HKzMTWJXaSOBUIT3X7yAGzZPv0JYc0k4Yvj77nJO17WTFucixeciNe7lH5fDRktnkNo2P4fOtLCnrIknj9TQEaNY1nj55BVL+PgVi0e1jNNu493aEarUANeszubZE7GLuE43+SleQmHTMyq4t6VZCVS1dMUMLHdblJmAy2Hn9CBFgVv65Ul+/mQ9r//Z8/zmHRtZkZPIxy5bdNYpfkIRK6jV7YJF6RSmacepmn26zzsz4t047LYBhSv3lDayr7yZt583j4UZ8Xz1upXccs9+fvXMKX7z7GkEegY45SV7WZgZz86SRnaWNPKLp62iwG6HjaK0OOanx5Ge4OL2F0tH3L64cSh+FghHOFEzcLZfxFjfG8+frOe6tbm8+4L5rM5LmtIgc7s/RNwoZl6o6avdHxrXwtijUdprxo/LLgTDEZo7B68tMFpfe80qcpO947Y+NTz9VjgLTxypZldJI00dQTqDYTr8Yera/ATCEZZlJ7CmIJmFGfHkp3hJjXNx8EwLwXCEnCQvRWlWJfruaTzz0+No7QqSl+wlGI6Qn+IjyeskJ8nDkqwEcnoV3xuJovQ4ihh8xILbYefSpZkD7j9Va6XFWFuQzKrcRE7WtrM0OwET7YZt6QwRCkdw2G384M1r+cGb1wJWVc+aVisHc3aShxdP1dPUEcRpF2w2IdHjpCsYJjk6naetK0RavJuiNB9Hqlpp7gzSGQgzL82Hx2mNYNS8OOpsbDtVz2+ePc2ukkYaOgJ9RhA4JqCj4qGDVTxyqIp5aXGkxbnISvTgtAsuh42CFB+vW583I0c217b6+e+/78MfCvPWLfPYMC+F9Hg3207X861/H2HfOKasKEzzcaBi4EV7eyAc82K+orGzJxXBcOw24Q3r83j7eUWsyksiEIpwqLKF3CHSHcw0IlIMtAJhIGSM2SgifwGWRp+SDDQZY9ZOZrseO1TNwweryEr0sDI3kdxkL6FIhPLGTk7VtvPwwao+AZHx4HXaiXPbYxaNHM6izHg+etmicW2PUnPZG9bn84NHj53V/jiZlmYlUNncSUuMYtjrC5PZX9FMcIhR2OfkJfH0sVqyEtw9Bal7c9qlT9qKbqUNHfzgsWP87K0beMf5RfxtV3nPFPuz5XLY+OENa3VUo5p1/u+fh/jNc6cxxgoMf+rKJST7nPxrXyWr85NYU5DMt/99hG2nGyhr6GBFbiI/fOxYz/LhfrNmK5o6Y46O9IciHK1u5Wj16M9Pjla1kh7vmvDvvIqmTl5z63Mk+5yctyCNi5ZkkBrnIs7lwOuyzoO8TjvBsMEfChMIWbnfu4Lh6E+EYDhCZqKHghQveSle3I6RB8bDEcMPHzvGPbsreOOGfN60MX9GXuuol/3sqRNU9Sre57TLkMe9iRIIGwIdQZZmJZzVPtjftauzedPG/HFomRoNDS6fhfWFKfx9dwX/2lc54LF95c38dWd5z99JXmefHpicJA+vWZPLq87JZWVuIjabkOBxxswZNRL1bX7KGztp84dwO2yck588aJ7ixvYA/9pfSX1bgESvg0DIutjvDm6/em0uy7ITcdhtRIyVBP2+lyroCoaJGGtaztLsRBI9DvyhCEleJ5+4YjHrCl8uaHbugjTKGqzihpVNXZzwt1kF/zzW6NHunuZ2fwibCF6XncwENwszrPQZ9e0BshM9JHgchMIGsUGC26Eny2pYWxak0dwZ7Cnc19tQ6VjGImLgdF17zBFLv3nuNFevzObDly6aUSkYbn3iOE9EZxw8d6IemLgTjTNNXT0n49mJ7gHTkWMpbehgY1EKO4sbiXPZsdskZmAgHDHcdO48VuVZszdcDhtrC5LHexOmg0uNMT1DBI0xb+6+LSLfAyZtnpsxhu8/eoyfTEChvf5cdhuvW5dHqz9Ia1eIL796BfPS4niprIlbnzjBjuIGlmUn4A9ZnaKnatpo9Q/8nABcsypbZ8ooNY48TjtbFqTFPE+eLtYUJHG4spVAjIJCW+ansu10Q4ylXpab7Ok59vvcdtIT3ByqbOnTsZ3kdQ4abHr8cA3BcIS0eDe3vmU9n/nb3kFHP4/E2oLkOTWTSs1OxhgOV7bS1GkVez9d18Gd20t79quKpk4+/be9Pc+/p9+sxNuePT2Zze0RCBsa2wMUpHj7zMYbT5kJbiLR65mmjiD/PlDVp7Dw2RCx1pvoceJ22nA77LgdVtq6/BQf+Sle8lO8+FwODp5p5u5d5T2DP370+HHu2FbC/R+5QEeHzlDHa1q548WX635tLkplf0Uz6wqT2D7MMXCijEd+8YwEN//32tUaP5oCGlweJWMM/9pfyfMjnO7Xf2i/PxThRE0rf9lZyrqCZJo6Q/hcdm7YVDDiHaCsoYOnj9WyODOebafq2V/RwqOHrYDaBy9ZGDNpeWN7gN8/X8yZpk6ePFrbZyp7QaqXxVkJpPpcGGMQEb76wEFePNX3SyVi4HCldUA5Jz+Jj/cKLIcjhgf2nuGXz5zqeQ5AgsfBxy5bTH6Kj188fZLj1W2crG0bMGrt1WtyKUz18e8DlX3yTAGk+JycvzCdd20tYmOvNCNK9dcZnD71j5o6gty1o4y/7y5nU1EqN2wu5DXR4pbTWUqMomQT1YPd0B5gRY7VoRWOGLxOG53BgRf6vdW0+qlp9bNxXgqdwTBxLseAFDvd/n2ginPykyeg5dOfWAeU64HLJuP1GtoDfOm+A/xzhMEkEdi6MJ0TNW2ctzCNN27IZ9upev74YglN0WnkdpuwODOe/BQfyT4nly3LpDDVh90mFKXFYbPBDx49ztPHannFD/9DapyLDn+I9uhIwe6iXHEuOzedN4/6tgD37z3TJ5gU73ZocUelJoBnFKPhJtvmolR2lDTEzJF6yZIMyhs78DltdMQ4HuUme8hP9nKitr2nwyrZ62JPWRPrC5OpbO7qGYWc4HEMCC6nxblYlBlPZzBMVXMXBak+NsxL4c/v3cJrbn3urAsqvXGDjtBSM9On/vISu0sbuWZ1Dh+4aCEtXUE+89e9nBnjaP7JFjaQkzQxwWWXw0ZmgjtmsdGxMAaqW/xUj2BwRyx1bQFe/ZNn+eSVS7hJc9vOKH/eVsr/e/gIS7ISqGzuIifZ0xNQ3n66oWemaKLXQUtn7MEZE2GsaTF8Ljs/uH6tFtmeIhpcHqXnT9bzvUeO9ST4H87CjDg2FaWQkeChvi3Aqbo2tp1upM1f25PLaU1+EhcuTueXT5/iRE0b+SleFmfFc+WKbJK9Tn78xHG6gmFesTKbi5dkcKqunS/2qkTrddq5aEk67zy/iMuW9R0Bfce2En7w6HFedU4Orzonh1N17bx4ur7n8Xi3g3i3k2eO1ZIe7+Kc/GSW5yRSmOrrCS4XpHrZXJRGmz9IY3uQjUUpfOSyRfhc1sfHGMOPHj/Ojx8/3ue1490O/vnRC0j0OLn5DzuobOqy0mDECAA+sPcM+SlefvfOTfz6P6do6QxRmOYjzmVNc27zh7hzeynxbgfLchJH9L9Xc8+VK7LITvT0md4z1YJhw/Mn69l+uoGiNN+0D3Z+/PLFnKxt54G9Zybl9Q716ozaVJQSM+9lLN2pMeLd1uyHnGQPkYihzR8mxedkd2nTuOTAm+YM8IiIGOCXxphf9XrsQqDaGHM81oIi8j7gfQCFhWPLQf3ooWo+9deXaI0xgry3a1dn84qV2RyrauXt5xeRldg3RcnWRel84JKFPH+inu3FDRyoaOZ0XTtHqqzO07t3lVOU5uN16/J570Xz+cCfdvPk0dqe5QcLyrQHwvzy6VM47cJlyzJpaA/Q1BFkWU4i79papKP9lJpDhhuVvKesqefiNiPBTWGqD5tYgyhKGzo409TFmV4F/Hqvrzvwk5PkJj/Fh9dpJxyxgswuh41w2LC/opltpxtI9DjI7pWmKSfJyyOfuIhzv/k4/hijqYeTm6QjB9XMdOmyTB49XM3PnzrJn7eVcsXyLLwz9PxtT1kjqXEuGtrHNz1GVqIbj9Mes2bRZLPbhMuXZZKb7MXnsnP58sye2k9q5vjNs6do6giyPXrd1b9TpL7dz+aiFERk2Jk846m4rp15qV5KGs6uk+av7z+vZ9aqmnwaXB6Fv+wo5dsPHR3RAePCxelcvCSDd51fxE+fOsn3Hz026HP3VzRzwbef7HNfTpKHAxUtHK5s4Xg0uf+d28u4YFE6f3r3Zq5ckcWj0en/ncEwzxyrY11ByoDg8ls2F7K+MIW7tpfym2dPs6O4oc8oijZ/qGek8bbTDXzr9atZnpPI165bxb8PVNHaFcLtsPOJKxYPOrX/oQNVAwLL3et+7HANN28tYuO8FI5723j2eOwR316nnfdfvJDGjiAJHicrc5NI8Di49ckTNHcEqY/+zx8+WE2828F/Xb2U163L0+kOqg+fy8Fr1+X1FOeYTkIRK2XA79+1eaqbElMwHOHvu8p5YN+ZnnQYU2FDYTIHK1sG5K4cTJs/jMth59CZlp4R1qeB5TkJREZbunvmucAYUyEimcCjInLEGPNM9LEbgTsHWzAaiP4VwMaNG8/6H/XnbaV88R/7iZV55pKlGVy9Mps2f4jVeUksyIjjx4+fYGNRyoDAcrcTNW1895Gjg+ZkLq7v4NYnj/P750+PuJO3WzBsePigddxM9jm545XLyRykHUqp2SXV5yQ/1TfkRXKyz9kzcwKsDquhRhKvzos9dbiy2U9l89AjAVu6QvzqmVN8+NKX872nxLnwueyjDi67HDbWz0se1TJKTQehcIQrV2Sxfl4Kr/zxf2jqCPL33eXDLzhNBcPGmlk8zsG4soZO6toC5KdMXSdSVqKbrQvT8bnt2EVYmBnP69flaWG/GWpRZjwnawdPxXS6roPTdR3MT/dNah5mfyiC13V2n6mFGXEaWJ5i+m0wQpGIoTA1js9dvYydJQ1sP91AcX1HzOe+ek0uP7lxHQC3/ecUd24vJT3e3ScVRZ91x9hXK5u7uD/GyMFnT9Txo8eP887zi3jxZH2fHJI/fuI46fEubjp3Xk/QVURYnpPIV69bBUBXMMw9uyv41TMnKa7vIDXORYLHQVcwzNqCZC5emkE4Yvj3gUpW5SaRm+ThvIVp5A2RS+nxaH7WWP62s4yMBDd7y5s5VTuwAm63zmCYO14s6Qko2G1CRrx7wAjUNn8Ij9POdx4+yoP7q7hubS6XLsskHDaEjSHJ68SuuTPnrKrmLnZOcY/+UJ46WstX7j/I/7xqxbT6nHYFw3zojt09uZanQnq8NX1pV2kTRWk+0uLdHKtqHTRPbm+9O/wuXpLB08dqOV7dxuevTRliqZnPGFMR/V0jIvcCm4FnRMQBvB7YMIGvzQ8eGzhjpduW+Sl86/Wrae4MUdncyb7yZr58/0GOVLUOmpvvaFUrN/7qxZ60FoMJhs2oA8v9rStI1sCyUnNAUZqPzAQ3R6vbhi1IuyA9jnDEYLMJAthEQMCG9bv7qB0MRzhS1Uplcydjudz+/qPHcNqF9120sOe+V56T0zOzcaRykjw9swmVmg66gmGMAY/Txi337GdfeTMRY3A7bGQmegiEIpyqa6OsoROX3cY1q7NpGeN0+ImyIicBn8uBzQbBkKGqpYv8FC+dwTB1bQFqoteqmQkespLc4z5qudtgnVmT4fJlmfz67Ru1PsUs4Q+FR5xi5XRdB4sy4jgxRCB6vB2pamV+etyo6xCkxelMxKmmZyIjZLMJ5y1M47yFaVy/qYBQOMKPHj/Ob549zcrcRC5dlklBio9Er5MN814OaLznwgW84/wi/vRCCSX17dS1B2juCFLe2EF9e2DYacSx/PCx2BfzxsBPnjjBmzYW9BTO68/jtPOWLYW8fn0ed20vpaEjyHsvnE+Cx0qefriyhe88fJSDFS09lTr/vqeC7z16jP977SouXz6w8ODHL1/Mgow4Tta009wZpL7dz0tlTRgDx2va+NaDh7liRRZv3VLIx+96adDt6j1SLRwxg6Y2qGvz43bYKK630oNkJbpp7AhS2+rHZbexZUEqt964nkSvFgKcaz50x65xz0c23naVNHDz73fQ2GEV/mjqDJKZ4CEzwU1mooeMBDfGGI5UtZLkdZKX7CU7yUOix8mSrPhx/UyfrG3j3/sruXdPxZC91yOV6HGQl+LlcOXwVX5T45wszIgnFDG0dgWpawv0pMQoru+guL5jREWVets4L4U/3LyZP71QzI2bC3HYYxc3nQ1EJA6wGWNao7evAr4WffgK4IgxZkKG/4TCEb74jwPctaNs0Od88ZUrOfebT/S57zVrcvnqa1ayICM+5jIZCW5eszaPO7ePLrByNo4OMjJaKTVzeZ025qfHkeBx0uYPUVzX3nM821Pj+AABAABJREFUGYmuYKRPqqah5CS5hx2dPJxwxPDTJ09y89b5Pcers6k/fPWq7DG1Q6mx6giE2HaqgSSflWrxTy+UEAxHeOf58ylv7Oy3X/Xt5AmEI9z30vimYrML5ETTNpyubSc4hsLecW7HgJRtlTHyQVe1dFHf7p+w4tGHz7SwLDuB6pYuFqTHs6t0ZGnkxsMNmws1sDyL/GNPxajy+3umIE1NRoJr1MHlwyM8fquJo8HlQXQXthuMw27j01ct5dNXLR12XTWtfvaWN/HiqXoCoQh2m402fxCn3UZ2ooe0eBdep52aVj/ljR1ndWLZrb49wOf+vo/3X7yQwlQfPpe9z3acaeokO9GDx2nnnVvnD1h+f3kzz52oG5DYv7K5i188fZLCVB+LsxL6PFaQ6mPjvFRuf6EEj9Pek6OupL6DRI+DM81d/PGFEu7eNfI4h90mhIf4R1iFEa2R0N258eLdDlLinFQ0dfKB23dxweJ0uoJhUuNcFKb6WFeYosndZ7kk79grzE40Y+DpY1ae2COVLST5XCNOQ/GO8+bx1nPnUZQWh8sxdOC0tSvI44dr2Ha6gcrmTiqbuqhu7cIYcNqFzkB42BGisWQneahp6RrwPbW+MJndpU20VLayoTCl56R3YUYcafFutp9uwOeyszI3MZqOp5WG9qFPjHeXNrIsO2HQFAndnHbhe9ev5eLFGQC87byiUW/XDJQF3Bv9fncAfzbGPBR97AaGSIkxVp+7Z/+g3+dZiW7+++pl7ClrxOO09Ulvsre8iR/dsHbQY6vXaedM08RUWe/vTHMXTR0Bkn16TFBqpttclEpdu5/iunYOjaBzM5Z5qb4RB5YBkryuMQeXwTqH/dlTJ/nIpYuw2YTXrbMGf4z0WiDZ5+RDFy8a/olKTaC33raNPTEGd/z4ieNkJrh7zhHHW5zLzsq8JE7WtBExhni3A6fDRml9B+XRHLIpPueYZjuNZkR1MGw4eKaFojTfiDu1RqrVH+o5H95X0cTqvEQ8TvuIa5WcrQUZcVyxPHNCX0NNrppRFnCcipkxe0qbSItz9aRGHYlWf4hwxEyr2cFzzZwPLhtjONPchddpp90f6skr/LOnTvLciTo+ccUSNs9P7fP8urYAGQkjH3afl+zlRzesIxIxFNe3U9XcRUNHgMaOIK1dQYIh01Psw+WwcehMC88cq+XUKHtrwBoF8Y+XzvCPl87gdtgoSPVx+fJMzp2fxvKcxGHzIhnMgMrW3XYUN/L+P+3ifRct4HXr83D3qgS+eX4qD3z0AvaWN/Hs8Xo2R4sYPna4mmdP1JHgcdLaFfvg7LQLPpejT3XQq1dls74whT2ljeyvaKZkBAfoNn+INn+IBelxNHcG+c7DR0nwOMhO9OBz2fnY5Ys5VdvOq9bkkKOFT2aN6pYu/nO8jj+9WMKRadpjmZvsISfJi03gZM3L+3UgbJiX6htx7/EfXijhDy+U4LAJS7ISeP36PNbPS+FUbTvnLUwjN8nDM8fruGt7KY8friEQHn1RoKGszkvk4JkWFmTE09QRYGF0BGpnMMyxXgHgY9UtuBw2AqEIcW4H2083sGV+KvXt/lGdBPfP72UTa9ph96yGD12ykDduyCctzk2Sb/p3LIwnY8wpYM0gj71zol63tL6Df++vHHB/ktfJrW9ZR3VzF79/vpjaVv+AvNlVzV0cr27lTHMXv3rmFB6nnaNVrQTDEW57x0aykzyTOuXzaFUrWxakTdrrKaXG34Z5KeNS4Coz0U1Jw8iDQQme8buE+v6jx+gIhPncNcvYVJTKD968ls/+bd+IjuE3bCqcc8c/Nf2878IFfPCO3TEfq2n1U9/mZ21+Mi6njcNnWkaU8mwksvqdN8QKItttwsKMuLOaoZcR7x5VcAugIxCmuL5jVEWqRysYNuyvaGF9YfKErL+3m7fO15nAs8yo978pKGETDBuykzyj2v9ErGvF/l4qa+K5E3WcuyCtT4YBNf5mZHC5uK4dh11wOWw4bUKc2znkKL5QOEJ5YydF0Vxqe8ubKKlvZ29ZM7WtfjqDYWwipMW5yEryUNHY2VNMYGfxNn5841pesTKbYNjw6b/t5UxTJ3+8eTNxbgd3bCuhsqkLEchMcLOmIJlVuYnYbAPbEwhHuPXJE4MWtQMrb1p1q59IxJDZK4BdM4qpC2DtWOnxbmxijQZ7cP8ZHjpYybff0DcWEQxH+N4jx8hL8XLNqmxevz6fxvYgu0sbOXimhTZ/qCfo63LYWJ6TyFUrs6lt9ZOX7O1zsEmLd3PZsiwuW5aFPxSmqrmLt2wpRET43XOnKa3voCsYZl66j/QEN43tQRw2oSgtDrtNyE/x8tTRWpq7gqzJT2J5TiJrC5Jx2W08caSGu3eXUdnURWiY4Ry9g/KdgTDHa9pYkBHHT588QW6Sl9KGDv7nVSuGHfmpprcjVS384NFjPHa4ZshR7lPJ67KzLCuBPWVNfarL9+YPjX70cChiOFTZwqF/vRxMT/Y5SfI6R9QRczZykz3UtvqJGKvN4YgZNGVFKGLIT/bS0BEgEC1MdLbFTXoX5fvyq1fypo35/OY/pylp6KCxIzhoigU1MUobOrjnQ1u5e1cZv/7P6Z77/aEw6fEu7tldQXFdOy39Uj45bMLnrlnGZ+7eFzPv6f/98zA/fet67vvIVm65Zz+7SiZ+uuetT55g8/xUvWhSaoZy2oXSUQSEBzM/PY69w+Rj7s3tsI1LKqnefv2fU2yZn8qlyzK5bq01gONL9x0Y8vw/3u3gAxcvGNd2qMGJSDHQCoSBkDFmo4isAX4BxAPFwFuNMdNzpMMEumZ1DhcsSufZE7GvccMGXipvAiAtzsWmnBT8wQhdoTBuhw2fy8GRqtY+A42Gk5PkoWwE+39dW4D69gBLsuJJ8roob+yImdYilgUZcaM+f3XahXUFyWyfoMDyusJkjIHKpk4OVIz8e+tsnLsglbdsLpzQ11CTb88oUqosSI/jeM3kp5JL9Dg4Vj306+YkeShI9fXUQ7DbhFufOMHCzHge2HuG1q4QxfXtPbMYEtwOrlqZzXfeeI6meZkgMzK4/NbbtlERnTob57JzzeocrlieyXkL0/tMi793Tzn3vXSGEzVttPlDXLQ4g+L6dlJ8LpK8Tqqau0j0OjhV2zbo1JVAOMIHbt/Nwow4zslP5vHD1SR6nNxyz34qmztj9kguzoxnTUGylUM1wc35i9JZnBmPx2nne29aw5NHazh0poWWrhCRiCFi4HRdG08erR1VELkozccXX7mCe/aUU9rQwZmmrp4iAhFj5a/0OG3sL2/m1res6+n5aekKEgobTtW28YcXSnjkYBX+UIT/feAQWxak8sFLFrJpfiob5qVQ3dLFx+7cQ22rn1N17fxrf+X/Z+8sw+O6zrV9r2EmMYNtmVm2kzjMTA00TdJQm/Jpm+Lp6fnKDGnaU0pDhTRp2iRtmqRhJjOzLWaaGQ3j+n6MNJGskSyWYd/XlcvSzGwYZWbvtZ71vs/DsztbUQvBpUsKuWF1MWsqs3l1Xwd6jYqTK7MQQqDXqCnLMqfPtTsQ5fHNTYPa8M06NVcuL0KnUXHF0iLsJi2lWSZ0ahW94TiPrG/g8qWFFDqMvHGgkwdvXUVtV5CfPL+X/e1+hEhZDIxEvxDdE4gSiSUp66tMf+DtWu44tQLtcezJOhaEEGpgI9AspbxUCFEBPApkAZuAm6WUU5NQMUoOdfpp7w2jFoL67iA/fWHfmBddphOHSYvDqGVLo2fE1+1t9bGyzDlhMc0TjA1KuZ9s7EZt2ku5sWewdYHDpB107FAsSU1XgAK7nsAIq+MqcWR/yf3tfhYUWDl1Tg4fPjkVVvqZc+aM/40ojBt3IEogGscYUfHR0yt5eW8HNZ0Bip1GSpwm/rqukZ9ftxRvKMbH/7KJ92p60KoFy0ocfO+qxbx1oAspU9f+wy1ZtjZ6+NeWJhCCQCQ+4iR1rFTmmDmpMos2bxiVgDm5VipyzBzs8PP6vk7OnDe97Z6/e/0Q2xo9zMmzcuWyQmWBREFhnCwvmXjVcqHDgC8cSy+EjobybPOk+7YnkpJv/nsXC4ts5FoNXLgon1NmZ3HZr94adtHYbtQeE3ZgxxlnSSkH3pzuA74opXxdCHE78CXgf2fm1DLT7Anxzy3NWPQaSlxG1s7OHtR9OlFiiSTPbG8ddSt6dyCasRpxTp5lWHF5Xr4Vm1FLIikJRRMIkVq0Hi6f53CkTI0nIbXd/AIrZp0GIRi2uthp0nKww4/VoBlTRtKyKRSWbQZNRvuRqcCq1/DTa5cqItxxwKt7O/jLe/X84AOL0apUhGKjL2xymXXj6qafKGqVIJ4YeZJY7DQO6Xh859DwVpPRRJKPnVGpfKankGNSXB5IIJrgH5ua0v6PpS4TJS4jTpMObyjG9iZv+kb11LYWzl+QR6M7lPY8HS2HOgPpKoVgNMFT24YPHqjvCXKgzw+4H6teQ4nLhMusS7UCt/eSbzOwvNTJdSuLKXWZuPieNwd9ec06NXajFrNekwr2chqpLneRY9ERjiXxRWK8tr8Do1bD1cuLOW9BHtua3Og1Glq9IRJJSb7NQDieJBhNUOw08credsqzzBh1ajzBGEuK7CSSSd6r6aEnEOXNA134wnG+fcVCADbVu7nllHK+8dSu9HlJCXEp+efWZm45pYxX93Vw24MbgNTq1u9uXknVAF/mVm8Ih1GLXjtYUAhEEzy8roG5eVZWlDqxm+zpwc7WRg9XLy8i12YA4FNnzebdQ92sr+3mqxfNo8sX5d2abjbVu2nrDR9xUqDXqLAaNBQ4jHzh/LmKF89QPgvsAWx9v/8IuFtK+agQ4nfAHcBvp/OEQtEE0XgSu0lLbzjGNb99Z0KeadOJQasiry+d/kjEkpJN9W6KHEYKHQZ6Q3HcwdSg2x2MDrGGmCn2tPqYl29hb9v778lp0jIr10JNR4DV5U56grG0FzqAxaAlfNgAZkGBjV99aDlqITjY4edzf9uKfxgB2qhVc8nifD599hzKskxKhekM88W/b+Pa6hJWlqWsop79r9N4flcbnmCMJ7c00+gOsuI7L/KtKxbx+5uqafIEmZtnpcMX4ab711EzTKVfsdPIvTdXY9KpqesO8Ox/nYZKJfju07t5bX8nhzr9LCq0o9OojrgIo1WL9AJyVZ4Vk07N3jYfm+rdGLVquvwRXtnbgU6T8oPeWNcz7eLy5UsLmZNr4dQ5kzvBV1A4kTDr1Ong6fGg1wiWljjY3uQdYuFzJDp6w6hFqhpzMqnvDnLLAxt48NZV6SDfn167lA/e+17GDq1mT4jaroCyQDWzVAFv9P38IvA8R5G4LKXkgbdquf+tVKeR1aDh+c+dTqFjdPaA3mAsXXFc5DBSnmUiHE8SiibIseqJJZJc8ss308JtllmHWiXGVfxR2+lnQYFtiPf5mgoX6+t6jlhQNFriSTkoeDrXqh9yvqPJ+xiOSDxJdbkTAdR0BsZsqzESk/U3OBI6tYpffmg5xU7T9BxQYcrY29bLHX/cQFLCh/6wDpdZx87m0TdXTLbF4mhxmXUjzvurx2E781/nzBmkUSlMPse8uHw4DT1BGnqC2IwaekNDBYsXdrdP+Tlkkj98kfiQm2V7b4RSl5l/bmnm02fP5vnPn447EMVq0KLXqAatqkgpicSTtHhCfOvfuylyGjHr1OjUapoDIX743F52tnhZWuLg+up83MEoWWb9EOuHs+flpX8usBt5cXc7bx/qQkrJjatLWVLiYHmJnbJsMz2BKImk5J6XDwzrCfurVw4OalnItuhp7AlSlWfluZ1tzMu38siGBn7/es3Qv5OAr100n+tWlQypvKjMNmMb8FgknmBXi5dQLMHr+zopzzbzxQuqMGrV/GdnG4+sbxjxQtneG6G9N8LeNh8Pvl3HRYvyOWNuDhcvLkCrVp3Q5u9CiGLgEuB7wF0ipeCdDXyo7yV/BL7JNInLu1t6+d6zu9nd0ssZVTmY9Rp2tfQeM8Ly8hIHB9p9oxKWB9LsCaU7MiA1mO6onbnK7MpsM5LUREGlEnT7I5gPC3QocZrY2HdjX18X5ZRZWRzq8KetuQ70/Q1WV7hYX9vDoiIbf7ljTTpEzWbUYjNoMorLVy4r5GuXzCfXapiy96gwet6r6ebNg10sLLJz4aJ8AAxaNVcsKwJgQaGN2x/cgC8S5839nVy+tJDesJav/3Mnb+zvpGWYFtQSl5FH7zwZTzDKj57bSySe5OntrVy5rIiX9rRT1x3EYdLS7A7iDcVYUepIX6t7Q/FB4tKsHDMV2RbqugPUdAXSi7yzc1IBmFsHdBGEY0mEYEY8lwsdxlFP7BUUFDKzqMg+Lrslq0HDggIbe9t8rK8dX3WhOxibMj/VPa293Hz/Or5z5SJOqsxiVbmLH169mC8/vj2jsKRRC5JJqVRiTQ8SeEEIIYHfSynvBXYBVwD/BK4FSmbu9AbzvWd288rejkEWLoFInGd3tFJd7iIUTRBLJJmbbyXPlnmsdf9bNfzylYPp3zUqke4K/fRZs7l0aQHN7vfHrt5QjDtOq+Dpba2DxrSjYVauFb1WxbISO1q1CpUQxBLJcduqjZZYIsnqcheNfXYZBXb9hDzVB1p/FToMLC91TFq1sdWoQatW0ROc2mbS39y4grPmKiF+xzpSSr7w2LZ0l+jBjrHNTSE11p8JarsCI3a4yjGutBi0Km4+uWwSzkxhJI47cbmfbLM+o7g8HeTbDGkD8pG+xMUOIxa9GptRy9PbUu1EBq2a3nAMdzBKly9Khy/MlgYPZ83LoSLbzOVLi/j5dUv5xMObh7QBPLG5mSc2N/ONf6WqjLMtei5ZnE+R04jVoKXTF6HVGyIST5Jl1lHkMPLsjjZcZh1fOH8uP31hH49vaeLFz5/Bt/+9m4fXNRzxvb6yt2PQ795QjPkFqeJXtUrw4+f38WyG8CdIrb7+7MV9JKXkppPKBoUN9gcr9vPfT+zgic3N6d8/dkYltZ1Btjd7yLboeexjJ/Ophzfz6r4jV6SHYgme2NLMmwe7+Pa/d1OaZcKoVbN2djZXLCs8EVdpfwF8GehfyssCPFLK/i9QE1CUaUMhxJ3AnQClpRPz5OroDXPLgxvY19abvpH8c+vwHQJHI3ajlr1tvYTGWAV1ONVlTrZPsY/aSBTaDbR5QwRjSWr7uimcJu2gtOBZOWb2tr2/oLOq3EmbN8zcDNUeldlmvnR+FdXl7/vbbmlw89XHdwwSHe1GLQV2A+cvzOeu86qm8i0qjJGfv7ifaDzJL18+wN82NHD3dctodAdJJFMC8amzs3npC2ewq9nLmX0TkhKXifJsM6/u6xh2v/k2A5FYgkt/9VZaOMmz6blxTSl13UHUKjHIcqU/bd6gUbGoyM6iQhs7W1Kfw/4Oo+UlDpYW2wlGE7gDUQ5mqJi+ekURKiFoH2VLrYKCwtGD06Qd8z3SZtQwL9/GjibvpIhVU9lVdKDDzwfvfY/vXbWIG9eUcW11CWVZZr737B62DVgk++w5c5ASXt3XgVmv4SQloHSqOVVK2SyEyAVeFELsBW4HfimE+F/gKSCj6jeZ4+VMSCkJRBN4glE8wRj/2NTEMztahxQHJSV895k9Q7avzDZz/aoSPnbGrEGPf/Ks2exu7SUQSXDO/Fy2N3mJJ5OsKHUST0rm5dt456vnsLu1l10tXnJtBs5fkMfmeveYxGWdOtWNsKXRM23Vuf24gzHW1/VQ5DAwJ9fCgQ4/rd7JKe5o8YRp8YRZWmxnb1svkfj43pxGJZhXYCUaT9LiGbtAOFoseg2fOms25y7IO/KLjxGEEA8AlwIdUspFfY+5gL8B5aS80q+TUk592McM0OQe2yLP4dR1BVhT4ZryRZ7DSUqwGzV4h9HzRuub3k84luTzj27l/ltXTcbpKQzDcSsuz5Q/DKRsMfoTp7PMOipyzERiCfa1+wfZN9R0BUZ9jn95LyX0/uyF/Vy0MJ+vXDiXj/5pU9pjORNd/gh/fLd+VPt/blcbACadmnvfqGFu/vhaBva1+zjrp6/xyTNns76um7cPvu97k2n1KRxL8qPn9rK0xDHioPjGNWXkWg0YtWry7XrOX5CP06zj1DnZ6dd85pw5vH2oe9S+ef0Drv52pdquAAc7/KhVgq9dNA+hEph1muM6+E8I0X+z3SSEOHOs2/dVbdwLUF1dPaHh4OYGN3taj+0MFF84Rp7NQGiMN7zD2VjvxqhVsbrCxa5m7xB/2oHk2w20TeB4mr5qJ6dZh8usw2bQ0N4bJniYQO4OxvCFven2QV84zvJSJ0kpUQmBAFp7wywssA3a7kNrSvn+VYsHPdbqDfHZR7fS6A5i1Kq5rrqYS5cWUl3mVKwvjkK8odigxcz23ghf/9fOQTYXxU4jVy0v4vFNTXznykWcMz81Mfn4GbM41OHn733WVYezoc7NeXe/MWgy2d4b4Q9v1vDja5bw4u52XszQcRSOJ9nYZ5FR4jKSSEqyzXq8oegRfc4/eloFz2xvpaXPgznLrOOq5cXML7Bm/PyFYwk6fRG8oRj5dgPZFn2GvSqcyAghSoA/AXmkqhvvlVLeI4T4GzC372UOUgu3yzJsX8dhQWHTcNrHLHPyrEMKLEbCpFVh1mnGtM2RaPVObMJ+JFQCajsD6ark1RUu/vHxk/nK49t560AXVy4v4nPnzkEIMSjjRGHqkFI29/3bIYR4ElgtpfwpcD6AEKKKVCdgpm0nPF7+3jO7eW1fJxaDBqtBiz8cwxOK0RtKZW4cKfB8JGq6Avx1fQMfPW2wH6lBq+a+W4YXY7yhGH98tw4BbG/2Eokn+dZTu8ZsBSGEwB+JT7uwPJBmTxjjFFVpbmvyjkqgq8qzYNSqCUYTOExa4klJZ28El1nL7tZexmANPyayLXpuP7WcG9eUHY8+7g8B/0fqHt3PV4GXpZQ/FEJ8te/3r8zAuU0pQqRyT8ZqBzuQDl+EHIuOJcV29H2aSCIp2dfWSyA6ug/k8hIH3lCMWDJJgX2oT3ImrIbhheV8m4EWz9jnvq/u6yAUTWDUKZZ0U8VxKy5vPMyXUadRUZVnGZPHzGQwMLTAoFGxtMSORqXiYId/TIm4/QSjCTY2uAnFEmNuBxgNkXiSHc1ent4+/orRSDzJ3S/tR60SWA0adGoVgWicUpeJbIuebn+Ufe0+ZuWYuXpFMXecWnHElouVZU5WljkzPucORPndG4cyWm9kQqMS5Fr1Q9q0W71hntzSTKnLxGX/9zZSSmblWrjrvCqWl2Y+9nHAWuByIcTFgIGU5/I9gEMIoemrXi4GmkfYx6Qwmkr5oxm7UUtZlgm7QUuhw4gnGCUcT2LSqnGadcQSyUFtcfk2PaVZZg62++jpq8x0mrRp+49QLMn62h6KnUYgSiCaoDzL1OdDLhEIDrT7aPOGWVZiZ2vj4CquxUV2egJRcm36YdvxdBoVy0sc7GrxggSHUTvswLfIkRLVtvW1+3X4IoM86ubmWwlFE/gjcf774nnsaPJSlmXiztNmDdlXvs3A1y6ez09f2Mf9t1QrE+OjnEzd1of7Jze5Q/yqr3X2bxsaWTs7G4NWjZSSTUdIpc7kJfrsjjae3dE2qvPrD5gc7UAzGk+mr/9JCX94s5Y/vFlLod1AgcOIWa/BH46lEub9kSGLOzesLuW7Vy46Ya2UFDISB74gpdwshLACm4QQL0opr+9/gRDiZ8BI5baHB4UpZCDPqh9T0j3A4mLHpFddtfdGsOjV+COjD0YaC0mZyiYZKPRp1Sp+ft0yEkmJJxhVFmOnESGEGVBJKX19P58PfFsIkdsnNquArwO/m6pz+MqF87hgYT6v7evktf0d7GzuRaMSFDmNFDmMtHrDEwq6ru8Ocv4v3uAX1y9jUZF9VNt0+iI88HbthAOlI3FJbVeA2bmWcbXuT5RSlxGLXjvEwnKyKbQbyLLoMGo19AQjZJn17G/30RuOs7LMOazo1uQJsbTEzrZGLwaNCpNOnZ47TITyLBN3nj6Lq1cUzZj9wVQjpXxDCFF+2MNXAGf2/fxH4DWOQ3EZUgWXE6HUZWR/h5/FRXY21LnJs+kpdZmQiCFZPMMRSyTTBZWF9tHZwhU5jMP6nhc7jaMO8xxIUsIj6xu4/dSKMW+rMDqOW3H5cKLxJCadBoNGRTyZnLKVv5EIx5NsGyAAzcu3YDPqUl6rY2hZqO8OUt8dRKee/IraRFIO8qWcCDaDhiuXF/H586ro8kV4amsL3lCUKy8sRohUsJdmAu8hEk/wzad28c8tLaNKPS2wG7AaNKwsc/HNyxfw1NYW/r6xia1NHqryUoOZcCxJQ1/V+aVLCjhnfi6LRznAOhaRUv438N8AfZXLX5RS3iiE+DtwDfAocAvwr6k+l2UlDna19NIbmlj1xXRR6DDgMusw6zQEo3H2tfkG+axlYkGBjWg8wcHOANkWPetrezBq1SwvcXCo048nlPJx3NLgTl+jmtwhnCYtlTkWjDr1kIFngV0/JEnebtRS3xOgNxQny5J5UGHRayjLMqUn3MkRvvsqkfJH3jbM+zPr1Kj7JrnfunzhEX1sX9zdjkYleOmuM0Z8ncLRwVgnHC/sbue8u1+nwG6k2R0as+/iVGLt83DPRIs3PKw39EAeWd/AgXYf/3vpApaWOCb5DBWORaSUrUBr388+IcQeUnZSuwH6sgyuI5VncEKgVYvhfUuPcIsf6Wl/JI5erUI/hsvSziYPlkmqVKoudxGKJVAJwbs1w6fSTwY5Fl1GP2W1SpCldFBMN3nAk32Cvgb4q5TyOSHEZ4UQn+p7zRPAg1N1Ahq1iupyF9XlLr54wVxiiSQqIdILnVJKXtvXyTee2pWey4yVgx1+vvL4dv58x5pRiVKzcy08eOsqbvjDe2MOxjycWEISiMSxGTT0hqfX2tJl0lPbPXUdz6srXGyq6yEuGTTOOEjqmGrBEas567uD5Fj1dPsjhINJyrJM5Fr1JJKScCyJL5KqYPeN8m/31Yvm8dHTKk/UhfK8vvs2QBup7/dxR5c/wruHxnef0qkFc/OttPVGiCVk2pauP8cqhaAqz0K3PzqkWyEVmuukxRNiV9+izaIi26hsOsqzTGjUw38ukxMosPz207vxhGKK/eIUccKIywCb691IwGrQYjdoqO+Z2QnvwJWeYoeRIqcRTzBGg7tvQCAhnkwO6+s2U+mdkGpVsOo1qFSC2bkWzpmfx762Xp7e3ppevZ6VY+GSxQV886ldGLVqKrLN3LCmlPW1PaypdE1IWAbQa9TcuKaMgx3+UYWqtHrDXLqkghWlTvQaNddWl3BtdQkHO/xcfM+b6b/naXNSFXcfP2PWqFfuj0O+AjwqhPgusAW4f6oP+MkzZ/PxM2YRT0qu/s3bgwJIjjZWlTvZWOcec0tOf0XE3DxruiUnFEsMauPfUOdmfoE1vXi0rcmLOxjDHRwq7M7Lt9LYExxSWVniMrKzuZclRfaMgrdJp8ZuHCyyjVTZtajQPqK/ZSCaYHdrL3qNYGO9m9UVrhErqs5fmD/scwpHHxqVGDFUIxONPaF0RfHRhC8SH9LZNB42NbhxT3GgjsKxSV+F1HJg3YCHTwPapZQHhtksU1DYMU0sIUctchxLBKMJ1tf14DJPfev4IxsaOXt+Hsv6FrFe3dvBwkJbXweTwnQipawBlmZ4/B5SHX/TjvaweZQQgrPm5bKg0Maa77884rZWvYYz5uaws8967WOnV5JnM1CWZeL5XW14Q7FRVzwuL3Xy9GdO41MPbx4Usjse9BoVWRbTtHcaT7bNjVGnpirPgkGjRpLyrR3Jbnk0Fu6HV4f3F5sdjlYtcJp02I1aTDo1Wo0KtRAkpCQaTxKMJsgy67jzMAuUExUppey79w5hqr3Sp5qfvbB/SIWvy6wjFEtQlWdBStjT0ksswwA/12ZgxxG+h3vbfAgBaiFYXuJgS6MHo1bFkmIHu1t7hyyYBCMpX/gj0dATZFHh8BrMRD+3D75Vy7Uri4dkfClMnBNKXO6vhsy16qnpnP6Wm5Fo8oRoylDdJUhZQjR7QhPyVZ1sfOF4etLQ5A7xzsFuVpY5WVPhYm+bD6dJx4O3raK9N8ITm5sRAlaXu3huZxtXLi8atS9yOJbgzQNd/PcT23GYdMzLtzIn18q2Jg9t3jB7B4S/jYY/vFmLWlXHDyNxrl5RjLpPHH/o9lW8sqeD9XU9LCm286UL5o3nz3JMI6V8jVRbUP8gevV0Hn+g/9GsHMtRLS4nkvJIhVcjcqTB957W959fUZryqcr097AbtezN4Mds0KT+ltubvVRmm8m26gd5N5dnmQe1/mVbdGweoc14e7OX1RWuI1ZVaNUqnt3Ryp/frWd2roXKHDPfvmLRiNsoHP0IkQqbDY7g/X2iMS/flg4uVFDoRwhhAR4HPielHDgruwF4ZIRNhwSFSSnfyLD/Y3qiezywtdFNtkVHlz/KmgpXWpybCjp9kVSH3qfWAnDWvFwiceU6rDAy2RY9WWbdsL7HJ1dmce+HV/KHN2t5dkcrRU4jV68oTovJS4odYzreuppuvvHULmq7A8wvsLGqPGUlGI2n/FW7/BGsBg3uYIwNdT0j2l7k2gyT6o0+GlaXO9nT5pvUxTC9RjWoW3k6iSXkEOu6w/n2R9ac6MJyuxCiQErZKoQoADImT09mttB0E4kneHZH65DHi51Gtjd505/PeflW6roChA/TZkZbHSwlxKVke7OX5aUO2rzhYYuVaroCo7LSMGjVw1Y4l2WZqBtlZtlwhTG+SJzTfvwqv71xBRctLhjVvhRGxwklLvfT5Y+wsszFrhbvlHmlTRYS2FTvRi1gYaENY1/7ueyrao7Gk4RiCXzhOL3h2IRbksZLNJFMtwda9BruOq8Kq0HLn99LBQpKSfpCs7HejUYlWDs7m+oyJ7euLcdqyFwB8veNjfzvv3YB0OWPcrDDT2VOL009Ia5fVYIQYNSq2dTgHnUIRCIp+crj2/nZC/uZlWvmsiWFfGBlMafMykZKOSaxWmFqOL0qhxcyhHgdLexp87G6wsWe1t4pr8za3OBBJaC6z3N8YNXlpvoeVpe72NLoptBhJNuiJxyLD2qHrOkKoFWr0KgEq8qdqISg/rDWvy5/9Iji8eb6HqwGzZD36zRpmZNrYWO9G38kka6GbusNU9sV4BuXSdQqQTAa56uP7+CdQ11cv6qEa1eWYDdqsRu1J/oA95hAr1Ep4vIAVpY5ZvoUFI4yhBBaUsLyw1LKJwY8rgGuBlYOt22moDBgiLh8LE90jxeiCUm2RUcknmRdbQ8GbSq7oMkdotM/fr/b4dja6OGelw7w0dMrMOk06DXHpy+qwuShVgl+ecNy7vjjhiHzQpNOzd3XL8Nq0PL5c+fw0dMqsOg14/bvllJi1mt48pNr6Q3H0KpVuMw6vMEYh7r86NQqFhTYeHlvB595ZDNmXWbpYUGBjUg8MSFheXauBSkl7b0REklJgcOAPxw/og91TzA64bF8llnHrFwLoWgcCdNeeT0WVpU7OWV29kyfxkzzFCnbxx8yTfaP083r+zrT+V6C9wPcQ4eN5fe2+ZiXb6Wm0090QAn9aAsB+0kk5bAZPwPxhOKsrnDhD8czepwvKbYjpcxYNW3UqQlHE3T5h69+LrAb8IVizM610uAOsrDAxpsHM8dZbKx3K+LyJHNCiss9gRjranvIMuvIsRpo94YIzpAoO1oSkmF9IgeiUwscJh1mvQaTTo1eo0KtEqOyjRiJ8iwT9T3BjALu0hIHPYEIyWQq5farF81nbr6VSDxBR+/QG7pBq+KiRQW8tKed1/d30uGL8IGVxVj0GmbnWga99kOrS6nIMdPlixJPSublW5mVY8GgVSGEIJ5IEk9KHnqnjt+8enDUHl1JmRK/2nrD1HUFWVRkZ2GhDSEEI1j8KEwD/9raPG6vuOkiFE0NgOflW4cNG5hMkvJ9UXlBgZWaztQKczwJ6+t6sOrVqISg2R0a1P5k0WvItelxmbXsa/cNex3QqQVN7pH/5itKXayvGzzoz7boUj7Qw+w3KSXv1XRj1Km5629bqetr3/v1q4f49auH+vah58lPnqK0Jh3lpHyXJx4eczSiVQtOqsziYIef1lF0CH30tAq+cuGJ192iMDx9nsr3A3uklD8/7Olzgb1SyqZhts0YFDalJ6wwIfa2+SlyGKjINrOrpZctjR6WFNvxhKLDWtlNhLtf2k9plpGrlhdP+r4Vjk8qc8xkW/SDqv+EgP+9dAH5dkPf72LY4p7RIoRIWwjubPFy433r0GtUg8TaAruBeflWNCrVsNXU/SLTkQod1CrBylIn7mAUu1GLr8+jOZ6QgyzmIBU8LEh1+XlDMfJtBoqdxrTHcFJKVEKgVQscRh3uYHRcXZMV2SYCkYkJ49NJsydEMBrHNIzQf7whhHiEVHhfthCiCfgGKVH5MSHEHUA9qUyE44r3at7/PK6ucFHfHcRl1mUUdPe2+Vhe6hgkDvd350x2GG6bN5zuxl9YaBuib3X5I8PaTi4pso94PkuL7Wxr8mLRa+gORnAHouxr92HRqfFnKJD5y3v1rCh1cskSRWCeLE6Mq8owdAdS5uMGrWpULd/HAtG+VhgGrNIuLrJNeL/hWJJipxGjVo1Rq8Zu0qESUOgw8qXz5+I8zJfLF47xrX/vxmrQcM3KYv6xKTWnqi5z8qmzZ3PW3FyklDzwdh1bGz186uHNLCqy8f2rFqdDSpJJiTsU46SKLN6r6aEsyzREgNKoVWjU8PEzZnH50kJe2dvBi7tTovVArAYNN59UxtsHu+jyRwcFTDV7Qnzx79v44vlzOXfBcennf0xx3oI8yrPM5Fr13P9W7ajEnplgSbGdyCiCJCeb3a0+qvIs7G9/v6XIF0ngiwQwaVWUuIxpr9vy7JRvnYqUvc72Jk/Gie+yEucQ4XgguVb9EPHZYdJS6DCOGGLY6g1z433rhjyuU6s4vSqba6tLaHKHFGH5GECvmfwA2aOBAruBu69fxkmVWXiCUS791VvDtuJV5pj5/LlVXLa0cJrPUuEYYC1wM7BDCLG177GvSSmfBT7IYZYYQohC4D4p5cUMExQ2XSeuMD6aPWGaPWFm55hp9obZ3uRlTq6FZndwSgpWXtrTwZXLisZdYapwYlFgN/LbG1eytcmDPxwny6xjTaWLsizzmPe1s9lLY0+QEpeJyhxzRlHy3UPd3HT/OhJJOaTisdUbzjiWtxu1qARk9dl4BCJx/JEYaypcJJKSSDyJPxInGI0TjiXJsuhwmXQjjlcPRwJz860AbKjtGeI/O5A1Fa5Ri8s2g4ZipxGrQUuLN3TE6ujpwmXWUuw0odeoUAlBUkoisSShWBxvKI47EKXFE+Y/O9r4wMoTY7FKSnnDME+dM60nMs30Vy0DxBLJdFHdcGxp8DAv30pDdyB9DzvQ4SfXqqci2zzpIjOkCidXl7uo6fKnq5EL7caM4rIgVeiyutzJxno3LrOOEqcJXySO06SlvjuITq1iabGdcCxBKJZAAh2+SNoP+nAi8STf+vcuzl+YN8TDXmF8nNDicj/hWJImd5A8q572o+TmcLSR6WK0oMDGQ7dltuW1GrT89NpU7kUknsCi17C4yM4VywrTQX5JCdesKOb2teUZB8uxZJInNzfjMGm5ekXxEX3mCh1Grl5RRJM7RJM7OGiA4AvHeWxjI585ew7nLcjj7YNdPLOjlQPtfpo9IU6qzKIqzzrqv4fC1GHSaVha4mBpiYNbTynn/LvfoGaU3kqTRZZZh0GnJtusQ6NW0emLDKmm7vZH0c2Q4DbcDTAYS7LAakiLy6lqUzjYGQAClDiNFDiMbGlwDxKZe8MjV6TajVpChwnpFdnmUbU/Hc4tJ5dx13lzsZumPgxJYfLo/ywdTywqsvHz65Zh1mv407t1LCqyp6spyrNMfP+qxTS5Q3zlie1csriAX92wXBF2FDIipXyL1Nwn03O3ZnisBbi47+eMQWEKxwYHOwPp6q4DHX5WVzhZXzvx0NDDeW5nG/vb/WmhTEHhSCwutrO42E4knhi3ncpbB7q46f7BRQILCmx88qxZXLrk/YXWfLuBxCh8BdUqQSIp0WlUFNj17G3z4w7GODiKc/GGYtQw9vnAaIrHtCrBgWHyUPotGOcX2FALQVtviIaeELv78lFWlDpmPMA4z6an2Glia4ObnsCRvZ7/ur7hhBGXT1TM+ve/8+0ZOskzsbfNR3WZk3ZfmMaeEJXZZrY2etLV/pONUaemNxwj12pIi8uqDOPs1eUudjR7eX1/J6vLXawsc7KlwUOX3zPodQMXeVZXuMgy69nS6GFLo2dYna/DF+Hie97kyuVFfPS0yhmb2x8vKOJyHy2eMCvLnPjCsaPeImMmuWBhHjedVIbDqGNh4egqovUaNd+8fGH69zf2d3LXY9voDcc4Z14u93xwOTrN0AuJXqPmo6dXcqDdx7rabiqyzRi16vTkPtC3mp2yAEl9lE06DV+9aB7XriziuV3tzM4xc6DDzz0vH6DLH+UbT+3ie8/s4bpVxXzzsoWUukysr+tJtUYp15KjDo1aRbHLNC3icnmWCYNWTas3lGrbC0DzgApGh0nLsmIHgWgcgUAiiSdm5lqxq6U33fpzOAPvybuae6kuc6YtNRrdqWBQg05NLPF+y+KRxgwHO/wYtGpyrXqKnUY0KhUmvZryLBMdvsiovHhzrHo+dnolVywrUoTlY4xkUo7ob3asYTVouPu6ZZwzP5d4UvKT5/fxzPZWFhXZmJ1rQadR8dBtq3GZddzz0gGkhDm5VkVYVlBQyMiWBjcLC22psF8JORYdnZN8zUwkJV/6xzae+vSpk7pfheOTaDzJf3a28qd369nc4Obz51bxyTNn0RuO4zBqicST/PrVgzR7QtiNWrr8EeYX2Fhe4mBFmZPecIyrf/MOgchQu8Hdrb08ur6RSxYXpO+LFdlmVpY52VQ/8sLKvHwrrd4wUsojhnpNF1q1wKrXIkRq0dmk1aTH0vFkkv1tPvyRRMb3tqLUQTCaYFaOmVAsgTcYm7KAz4GsLHNS3x2gMsdCLJ4EwRH/9gPZVO9mf7tPKaw6jil0GNLhmmOxR91Y76bEaWRRkY3drb3Ek3LKuohNWjXuQHSQ6CsZvEi1snRwd+1oOxfCscSgrsuybPOwRaQHOvz85Pl9vHuom9/dvBKLXpFIx4vylxvApno3aypcRGJJtjV5mHzXtGMXh0nLF8+fy9Uriibs0aTTqLjrvCoWF6VW1Afyx3fq+MF/9vDonSezrMTBP7c087m/bU0/n2XWsajIjhCpduY39nfR5Y9wxbJCPn7GLCpzUp7Ns3KtfCo3dcO8ALjppDLeq+mhxZPypN3W6OHa37/L/bdUs6bCRTiWQK2oy0clv7h+GQ09QX718gHePNg15oCBXKueUpcpvQrbj92opSrPgkCAkNR3BdOewJnw9IWTtLhDTIGl4phYWeZkd0vmyoRuf5TKHDM1nQHm5VvpOczfrirfOsTfal+bD51GNezftjzbTG1XgFAskV4VXlJsRyXEqIRlh0nL965cxPkL80fz9hRGiRCiDvABCSAupazue/wzwKf6Hn9GSvnliRzn7UOp6+zxwhlVOZwzPxfR57X4tYvn87WL5wPw8xf389iGxnTFx6fPns3pVdlD8gBmmlgiSU1nALUKXGY9rsOsqRQUFKaPaCJlBdDoDhKOJcm16lhSZGd785ErCMfC6XNyJnV/CscHHb1hfvL8Pmq7AvjCcXzhGO5gbFDH2c9f3M9jGxtp9oTIMuuIJyWe4OCutae3twIpy4dzF+Rx+9pyXGY9/9jUxFuHBWK9dbCLzz66lbuvX4ZaJejyRwhE4tywuoRH1jcOe64N3UFm5VjY2uSZvD/ABFhcZEevUbGt0UMsKYf1hB6OzRk6+JaXOtjZ7J00/3WLXoO/T+QXApaVONhc70YCXf7xWxX8dV3DoOIvheOLRHJsovJAGt0huvzRIV2rE6W63Ing/fPqDkRZVe5Mi74uk5a9bT6KHAaaPWGKnUZ2tY7vPnq4bWOLJ4RKpDrnh+Otg13ccO97PHjbKrL7bFoVxsakistCCAdwH7CIlM3R7cA+4G9AOVAHXCelnPx+sUmi30+mKs+CVq2iviuQ0QD8RKLAbuAHVy9mTUUWRt3EW6NPqszipMqsjM+tKHXyxfPnsrRPdD57fi7nzMvl5b0dQOoidLifMsBjG5v419YWLltayJcvnEuu1TDoeYdJx4WLBgtb4VgCrVpFY0+IP71bx/9cMn/C701h8nGZdbjMOu6/dRXReJIuf4QntzTzk+f3DXqdELC02IFGJVCpBFKmKoj2tfWysd5NnlXP0mI7GrWKWDzJ7lbvmG+6hXbjjLe+LSm2j1id0F/lvaDASiAaT/9ekW3GYdSgVQ/9Di8pGRzioFMLyrLNmHUa9BoVOw+bIK8qd7KvzTeqAE2TTs0jHz2J+QUT935XyMhZUsr0rE8IcRZwBbBUShkRQuRO9ADvHOrmjlMrmJNr4Z1D3by6r2PCyeozydPbWzl3fh5XLi8a8tz5C/LQa1Tp9l61SrC81DndpzgsO5u9PPh2HS/taX8/BVyk8gxOm5ODQasi327kokX5in+cgsI0cqDDz8JCGw09QTp8UTp8UarLnWycYKD2QMyTMAZXOD5o9Yb41SsH+d6Vi3jzQBd/35QxL3QQ/XkCR+pE6g3HeWJzM09sbua2teU8dNsqtjZ6eHxzM4uKbOg1ana1eJmV8/6ia7ZFz1OfPpV4Mkmpy8S6mh4SySSN7hAGrYrecJx2b5hANM6+9iMH1E8lRp2aOTkWhCBjB+BE2dLgQS2gzGXCG44NEfH7ybHqKXIY2dvWy7x8K7GExKRTk0hKWjxhuvwRlpU42FjvpthpJCklHb3hcVnSZeKJzU185cJ5kzK3Vzj6mMj9wqRTI6XklFlZ1PcEB3XyToQ2b5j4AHVXrRLsH2BHo1Gr6AlG0GtUFDkMGLRqwpPkKNDkDo0qoHBHs5dLf/kW168q4eLFBalCNKVzcdRMduXyPcBzUsprhBA6wAR8DXhZSvlDIcRXga8CX5nk4046/WFZA1vKAdQiFWx0olhnCAE/vmYJp01TtUS/P1g/GpUY9SpyJJ7kH5ua8ARTYRAlLiMry1wEInHKs4cGWPR7iJZmmfjKRfOUC8cxgE6jotBh5NrqYn7x0v5BVQErSwd/Vw+n3ReZsKd6bziGUasiNEPf/9m5liGVyMOxu9XH6nIXZVkm8mwG4olkxgoLIC0Uusw6KrLMNLqDHGgfvl0xkZQYtOq0uLyy1EE4nhxSEb26wsXlSwsVYXl6+QTwQyllBEBK2THRHerUKiqzzVxbXcIHV5cSiMT5+F828eaBriNvfJRS153ZamdRkZ1FRfaMz80kG+t6+L9XD/LavqGLq1KmqkAGLpblWvVcuCifj50xiyKHcTpPVUHhhGVXSy8lrtT3zReOs6u5F6tBM2mLcT96fh/zCmycNW/Ca4YKRzEtnhBvHeiipivAP7c0k2838OmzZnPugjx6wzF+8eIB/r29hc6+Me2hjqmzl3jw7Tqe2trCqnIXlTlmihxGTp2dzTUZ/Hp1GhU6VHzizNl84kzY3+7j/LvfGPK6mRpDFzoMZJl17GrpnfSugsNJSKjvCWIzalhT4eJghx+NWqDTqMi26InFk+xs6aXTF0GrFmxtzHw+/fOa4YKGJ0JvOM4zO1oz/r9UOPYxTcDaIZGULCq044/EJ01YBghGExTY9el8k6SUZJn1FDqMRGJJ7EYtHb4I3lCMPJuBg5N8bVtX28PqctcRrTXaesPc8/IB7nn5AJU5Zi5eVMBFi/NZUGBT9KIjMGnishDCDpwO3AogpYwCUSHEFcCZfS/7I/Aax4C43M/OllT6c5c/gkmXakupyrOwsc59zNhmyAmc6P+7dMG0CcuHE4jE6Q3HmF9gZWuGhM/heGlPOy/taQdSPlr33lxNebaZZFLyXm03p8zKzngsKcGptBYfE+RaDdx9/TIeeKuWRnfKLy4xkQ/6KNnb5sNq0MzYwNiiV9PpG73vVVJK6ruD1I9g9wFQ7DSi16jY3do7KvF6c4OHAnvKy8uk0xCJJ2h0h6guc6JWCSQpn97N9W421vXQ2BPkg6tLqciwyKMwISTwghBCAr+XUt4LVAGnCSG+B4SBL0opN0zkIEUOI4UDBEqzXsPtayuOWXFZqxbHRFVvtz/CsztaeXJL87ALQ8PR4YuwucGdOWFOQUFhymjsCTEv38KhzpSV1OqiI09kx8LPX9zPmXNzlAnucUyhw8iZc3N4alsLbb1h2nrD3Pnnjfz8umW0esM88HZt+rV/Xdcw5efz3xfP59V9Hdz3Zi0HO/z88uUD/O7mlUO6RA8nNkO5JMOh16jY0Ty9VdO9oTjrantwGjV4o0nCseSQDsjJss8YD39dV6+Iy8cpE/ENjsSTbGqYfKOBnkB00DxTylTHrVadCvrsL2qOJeSULKiMh5rOAP/36kH+79WDlGWZuGhRARcvzmdxkV25D2dgMiuXK4BO4EEhxFJgE/BZIE9K2dr3mjYgb6IH+vWNK/CH4+i1KjQqwTee2kU0nmQq///m21M3UJsxJTCfVpWdXjGeDiaimzlMWuYXjM2wX0rQqlV8cFXp+A88DmTfGxVCYNZrMOs1fPjkcv61tWVU3q4Dseo12IzatKDli8QpdpgyvvZXrxxAJVLem8qF4tjg0iWFOE06brpv3bR9F50mHbH49NrkzC+w0tEboTLHnBKKpGR1hQsYXQL2aNjd0ouvb4FltLR6wySSki5/hOoyFzaDht5wjJrOwKCWJ4Dfv1HDH96s4S8fWZNxcUdh3JwqpWzus754UQixl9R93QWcBKwCHhNCVEo5+P+uEOJO4E6A0tKRr/NXryhKezH2s6DQRlWeJd3lcywRS8hh74ktnhB3PbaVR+88ecLH2dLg5t2abgrtRpaVOADIsuiw6DVD7jPuQJQmd4jFxXa8wRjfeWY3/9zSDDDk+zQaFhba+PvHTlHaXRUUZoC9bX6WlTjY1uRhQ30PS4rsJKVkZ8vEha0dzV7+vb2Vy5cWTsKZKhyt5NoMPHDrKr7/7B4eeqeOpITvP7uHU+dM3xjqjKocrlpexBXLCvnAiqJ0d9rsXAvqIyVBA/GEPKLH6XSSZdFT2zVyscVU4Q7FWV3hmrRx+2SxucHTZ8uhdBgebwQiqc/cSJ2rRwtTscBiN2qpzDbTFYgMWtCpHaZzcTTUdwf53euH+N3rhyh2pizoLlpcwLJiB6pRXBNPBCZTXNYAK4DPSCnXCSHuIWWBkUZKKfsqrAYxlkkukJ6k9fPn29fw8xf38df1DekP57Uri7lwUT67W3r52Yv7x/eORmBPq2/E51eWOid1xUeI8QvMi4vsRzzfTOTZ9NM+Me0JRHGYdKgHfD/fPdQ9rsm1LxLHF4nT4glRnm3GbtRiN2qHvO7P79Xz1oFuvKEoLrOeT5w5ayJvQWEa2do4vcGbnmCUJcWOMVXSj0SRw4BapSIcS1CWZcrYEbGn1cfqChf1XQHafZG0X5TTpGV1uQtvKEqzJ4Q/Mlj0VglG/bfp8EVG1SY0ECHAG4pSXe6iJxDlYGfqZr2kyE48KdndOngSnZTwyPpGRVyeRKSUzX3/dgghngRWA03AE31i8nohRBLIJrX4O3Dbe4F7Aaqrq0f8qGjUKmq6AiSSMj2hzLMZeOKTa/ngve+ycxIrgRYW2jDp1AghCETiHOzwExljiOdosOiH3gsg5TO3qNDO3zY0cOGigoz3jNGyvNTJ8lIn3mCM+p4A/nCcP7xZwz82NZFt0bOyzElCSpp6UmGiP7t2KYux0+kPs6zEwZw8CzeuKaXJHeLSX7416vugUavmng8uU4RlBYUZZGujh1XlTjbUudnR7GVOnoUSp5FGd4gFBbZUVZlIdSgc6hzbZPdH/9nLhQvz0WmO/g4MhfGj06j4xmULiCWSPLyugQ5fhCc2N0/Z8dQqQb7NQLMnhMOk5da15Zw1930LlrFaRi0tcfDkJ9dyxa/fntB5XbAwj5MqswhE4mxt9PDavs5xzQvrusYvKk2UymwzjT0zI2wfiY11bkVcPkZ552AXTe4QzZ4QBq2aW08pp6EnyPq6Hr7z791E+7oH1lS42NzgnrIqeZ1GhUWvGdL9mio8ilOWZcJh1E6Jx3kmNCqB06RlS998vTzLRF1fF+9w4fVjpckd4g9v1vKHN2spsBu4aFEBlywpYHnJiS00T6a43AQ0SSnX9f3+D1LicrsQokBK2SqEKACG+D+OZZKbCbtJy7euWMTNJ5fzzad2cd6CPG4+qQyVSnDW3Fwqcyz87792jtqrVCGFVq0inkiimcb24awByZxSSn7z2iHueelA+uI4VjQqwd83NVHkNJJvN6DXDJ5sd/oi/HVdAy3eELNzzPz2tYOEonE+d27VCX1hOFY4a24u971Zg3uYsIzJJilTE8blpakAvPIsE+5gFG9ofH6KzZ7wgACgCMtL7GzJ4Lu2vk9MXlXuTC8yuYOxtBjcP4HtZ2mxnV0tvWw7ggjuMmnxR+JEE5L1dT1kW3RHDHrpZ1VZSow+vApje7OXJcWZJyDPbG/hM2fPpipvbJ0UCkMRQpgBlZTS1/fz+cC3AT9wFvCqEKIK0AET9q+ozDbz6t4Ozl3wfvORQaOiKs86JnHZadKSSMqMYZAr+hLWowMGv2admqUVLjbU9YxrgdVu1KLvE2A6fBF0GhV3nFrBilJHxtc7TDq+fukCbntwPXk2A6srXJh0Exsq2U1alphSxzt5VhZvHeyivjtIsydVSfHQbatQCcHa2amFl9m5VmbnWrnrb1s57+dv8OQn13Lx4gKe2tYyquOFYgme2tbKXecp3zMFhZlkQ52b0+Zks73JS3tvhMVFNlQqwe7WXgxaFSadht5QjLl5FvaNoQuk2RPibxsbufmksik8e4WZpNsfQaNWEYkncJi0aFRiXILqWMgy6/jXp9fS5g1T5DBOilXgkmI7K8ucFNgNxBOSrY0e2npHb+926ZIC/u9DKwY91tEb5q/rG7j3jZpRd7WWukw0zJC4u6LUwY5m74zaXwzH6VU53LB6eruUFSaPbzy1iwMDfIkfWd+Q8XO+rraHEqcRbyg2qjD2sbK02E59d5AVpQ7UKoE/EqehO0hvOM7sXAt6jYptTd602DzVOEzatJgMUNcdJN9mIMuim5JFpn67ogfeTgnNFy9+X2g+0TriJ01cllK2CSEahRBzpZT7gHOA3X3/3QL8sO/ff03WMQ9ndq6Fv3xkzaDHVCrBJUsKOHV2Nve/XcsvXz4wVYc/7mhyh7jmd+8ipUQCv/zg8ozBeFNFbyjOu4e6xy0sA5S4TKyv7eGMn7xGZbaZP96+mmKnkf3tfu55eT/N7hB7+iosd7b0srzUyd83NWHSa/jIqRXTKqwrjJ0FhTbWfe1cVn73xUkLzBkNWxo8uMw66rqD6YCT2q7AmL2YbUYNhzrfHxQc7AywutzJ1kYPc/Is7GpJdRysKHWwt83HjmZvxtTcFu/7A3WHUYNKpCqXo0cYyObaDBhCMQLRBFq1oDzbPCpxubrMyc5mz7DPe/vE/jm5Fg51+tMtkUkJv3z5wJCJgsK4yAOe7Bu0aIC/Simf6wvTfUAIsROIArccbokxHlZXuLj7xf2cuyCPjt4wz+9q44/v1o8pbGNgS+iKUgf72/34I3GWFNsJxRIZ2/YC0QTra3tYUmxn+ygqHlQCrl1Zgkmv5sy5uZxRlcoMkFLyxb9vZ29bL1+5cN6w27sDUX78/F5e3deJSggWF9knLC5LKRFC0NAdZHdr75BwlI//ZROP3nnykDbj/710AdXfe4ntTR4WF9lHLS5D6nt2/aoSJcxPQWGGefNAF6v67utvHeymItvEqnInO5q89IaiqFWqcV1jfvzcXq5aXjQhX02Fo5NwLMHBDj9ffWIHy0scPLFl6qqVIeVFfOrsbL5z5SKyLXqyBxT6TBQhBI9/4pT077FEkvbeMG3eMJvq3fzp3fr0QuvQbeEDGfyAc20GPnduFRXZZj776NZRnUcknmBNhYu23jAWvQajVo0QsLPZO6U5KitKHUetJYHDpOVXH1w+KosThaOTYqdxkLg80gJKozuESqQKkhJJSbsvMmlhfVsbPSwvcbC+bmjXfk3fPHB5qYNILMHucXTTj5XyrKHz2dIsE/FEksAYbVbHSqs3zP1v1XL/W7UUOVLWGZcsKWDZCSI0T/aI5DPAw32T2xrgNkBFyvPxDqAeuG6Sjzkq7CYtd51XhVWv4XvP7pmJUzgmGdj+/6Pn9vLbm1ZO27HtJi1/+cgaarsCfO+ZPemQvrFQ27c6pdeoCMUSnH/3G8zKNWestMu3G9hY14MQgn9sakKrVnHlssJB1dQKRw81nX7CsSQus46KbPOohKfJpL8ToqavnTXboiPPpsFh0qESqUTcWCJJlkXP7hbvENsKSFXWz+2zrfFH4vjCcdbXubHoNexr87Oi1IFGpSIQjY9YndHsDrGsxIFeo6I3HKPDH2VRkR2VEETiqYF8RwZf6qSUFPctwAB0+aOsLHPQ4gnT6h2+smRTg5uqXCt13X4i8aG6ZX1PkEVFNgwaNfMLbGmfPkilh+9v9ynVyxNESlkDLM3weBS4abKPV+gwUuw08j9P7uCdQ93EE0kQqXC8gdU4q8qdNLmD9K8Jlmeb6PRFkBJ2D0hn39zgwWbUkGvVj+q7u73Jy/ISBztbRq7+SUp4YksTBXYj+9p8PLO9ha9fugCbQctPrlmCPzryItS2Jg+PrG8E4My5OZNy/V9f28N3ntnN7pbeId6Ts3MtVJc5qesKpC2/4okkf3mvntf2d5JISr70j+384vplYz7uj5/byy+uX3ZCDGYVFI5mNtS5sRk1WIWgtiuY9n1dXGRjR3PvmDNFAHzhOP/z5A7u+eDyyT5dhRnmYIefDz+wnkRSpucxk4nDpKXEaSKWSHLanGw+d24V5mlapNCqVRQ7TRQ7TVSXu7j55DIeWd/Iz17YRzCaYHauhTybHn8kwSfPnDXIlqMfKVMV0GMJM2zvjdDeO3QcbNFrqC6z0+mLUD8Flc3e0PR0Vo6H6jIXdtP4rb8UZpbnd7WxsX5sFqxJmbofrS530pGhgyDXqqfUZRrzfmMJOexYs3/cqxKCZs/ouxYmQqY57Ez4nTd7Qtz3Vi339QnNFy/O55IlhSwtPn7DACf1TiKl3ApUZ3jqnMk8zkT46OmVqFWCbz+9e6ZP5ZjjPzvbWFfTzZrKrCk9TjAaH1TFUZFt5vc3r+RDf3iPdeO8METiyfSFZrgW7lTCt5V9bb50GrJRo+JDStvhUUkwmuDG+9ZNyyrkaOjyR1OrpN2DB6eHOgPMzrVg1A5Nqa7MtrChzo3DpMVp0qbtPfyRlAA2lmqHw32gD1+NnptnxW7UoFGr2FjvJhpPYjdqh9xsN9Wn9lPmMiKEwBuKpasf+8OIpIT9HT7KXKZBbUcDicaTQ75rJp2a2q4A59/9Bk9/5tQx+/cpzCy1XQH+uXVw9azVoGFxkQWVEASj8UH2LEDGRY1+ekNxehl9x8GWRg+FDgM2g5ZIPDFsME8sIWnoCdLQE+TChfkYtSk7JJVKYDOMPJFaU5HFZUsLaXIHOXmS/MHbesMZ7ztZZh1VeRb2tvn4+6YmZuVYWFxs58G36wYtgntDMZo9qffS2htiWwbrnEy8dWDCbigKCgqTRG8G+6x++7XxCjz/2trClcuKOGveUAFO4dhlUZGd/3z2NJ7Z3kpPMEoskeSZ7a2jtoBTqwTnzc9jf7uPS5cUUNMV4PSqHOq7A/z61UNUZpu554PLKXFlDjmfTkw6DXecWsGaChePbWzkaxfPx6AdOS/gm0/t4o/v1k/K8f2ROBvr3czNs0zK/g7HeIT3Ml5yrHrKXCaEgN5wHINGRYcvTKHdiDccx6hVoeuzgozFk2xvHjpu8IWPXuFbYWQ6fGH+65Et48ok0aoFrb3hjIUaSSmp6w6MKetLoxKUuExH7DRXq8S0LbYEj1BIMhM0e973aC7LMg3bdWQ3arn7+mXk2QzTfIaTwwnZS3X7qRU0uoM8+HbdTJ/KMYUQ8K9tLbx5oIudLV4ae4LMybVyzvxc5hfYqMwxT7h9GECXwYpCrRLcekr5uMXl0WLSqdMhaN5QjPveriXPbuCc+Xkjbqcw/SwqsnPm3Bz+tXX0reIzxcEOP4uL7JS5TBi0KrQaFSpEWhD2BGNDfJMnm33t71tspELLbEM8yAdSPyBZ1x2MsaLUwbISBzWdfnrDcfQaFTlW/bDissM02KvPrFOTZzcwP9+G1aDhu8/s4TtXLGSOUsF8TOMLx6e15bPFE6aFMDkWPfPyrXT5IyNauZj1Gtq84VFPoo06Nb+6YeRKwG5/hLruAIFIgv3tPqwGDa3eMM3uEF+8YC47m714QzF2Nvfy+v4OaoapPOsORHlxdzu3ra3gvAV5JPtG8hq1YE2FCwkEI3E6/RHsRh1z8iw8t6uNIoeBbIuegx3+ERfWSlym47YyQkHhWEarEqwoS1kDzcu3snUCAeD/9egWnv7MqZRlTZ9tncLUU5lj4TPnzEn/fl11Cdf89t1hBZzT5mRz1fKidGhyvt2ALxzDetiC6lXLi3CYdJNqfTEZLCqyj6rgIJZI8uq+ziO+bjRY9Brm5KYWx1u8U+PHPBnz4sOxG7UYNKqM1aWt3qEL+jajhhWlDiSpOXYskaQ7EGVHs5cNdd2sKp/aojGFyces07C4yE67L0xjz9isLfLthkHbLCiw0RuKUeQ00huO4Y/EscQ1o7abjCcl7mB0xC6L8izTkCKoqcSs00xbHtN4qB9m7uwy6/jxNUuOWWEZTlBxGeD/XbqAMpeJZ3e0saVx6tIzjyekZEgL0qHOAK/t62BJiYN9bT4+tKaU204pJ3ecXwopJXVdARrdIZaXOgYJVBbD1H9cB7Ym2gwa5ufbyLUeu1/wIyGEMABvAHpS14N/SCm/IYSoAB4FsoBNwM197fZHFVV5VipzzGlriqOZHX1VAyadOmML7OZ696h9ZceLw6Sl2x/BE4yxucGDWace5IM7Ev0CYlWehao8LWadmtdHqIxcX9tDdZkzPfgNRBPUdAao6QxwVlUO5y/IJd9+/H63jjfiiSTv1nTP9GkAqeR4tUqQbdFzwcJ8Ht/cxLqaHryhGGsqXKwoczIn10Kx04TVoJn06qwsi54six4pJa3eEC/samddbQ/+SJx3DnVT4jLyXs3oFkJjCcm9b9QA8LvXDnHfLdX85PlUe3CRw8g3L1/IwQ4/58zP5bGNKbuOaFyi16ixm7QjistlWSbeOtDJqXNyJv6mFRQUJo35hTbW1bpZUepgW6OHiUxBfOE4P3h2L7+7efps6xSmnyXFDh7+6Bre3N9Jhy/Crpbe9Ljy65fM5yOnVQ7Z5nBhGVKBsUcLUkqSkjF5/koJiUkINsy16inPNk95q3woNrJANzfPis2oYUuDByGgxGlCpRLpPIt5+VYseg3uYBSnSYcvHKO+O0jjGCpAe0PDFwHc8dBG/vGJUxSrumMMs17DPz5xComk5PldbeRY9Ty6vpF3DnWNaGsIqU7t/oKmXKuehp4A/kiCpgHe57lWPdF4ctSV0cHIyJ9zvVZNdBxV1uPFoD32MrNyrHoe/siaY/67eMKKy0IIbl1bwa1rK2jxhPj5C/v4x+apDUw4HllcZKO9N5K+Of/2tUM8vqmJL54/lyUldqpyrem2v9HgC8d5cU8HiWSS+QXvf7mi8SSPbWya9PM/HL1WhUYF8WSqzej5XW04TVoi8SJWljmPxyqwCHC2lNIvhNACbwkh/gPcBdwtpXxUCPE74A7gtzN5opn41FmzuX5VCf/1yBZ2NHunNdRvvAznrZiQTPmNtyLLzJYBK8eBaIL6Mfr57e9LtDdq1awodbC10TPER7afg51+HCYty4od+CJxdrd4mZVjYWODm9cPdHJ6VU7GyY/C0ce/trZk9CucCZ7f9b7//ou72/nzHWv4+XVT09I6HPFEko31bgxaNSvLnfQEo2xp8NDsCQ0bTnQkQrEEtz+0IX2NmJ1r4b+f2IFGJdjZ4uXNvsWcPJue9XXDT4j1GhVXLC1kd2svn39sG89/7nRcZt2wr1dQUJhepExVH05UWO7nuV1t1HUFpjV0+0RECFEH+IAEEJdSVgshlgG/AwxAHPiklHL9VBx/VbmLVeUuINVifd3v3qXZE2JJsWMqDjeldPoiXHTPG0TiSTb/73loRxmgrtOomF9gHfd9FlL30PIs86R2wy4rduCPpuwp+i3k1AICkThzci1EEymhLhJLEE9KKrPNqFUiLfq6TFp8kXi606kqL1VRrR9UoTz5hTS94Ti3PbiBJz55yjFdLXmiolYJLl5cAKSuD52+CF/6xzZeO0J1/9ZGD6vKnX2ZPEPnpR2+CNVlTrY1eUZVgFniMnFohEKvwBHE58mkPMvEwWOg6GwgBXYDD39kDZU50zuXmQpOWHF5IIUOI0tLHLx1sJu2DObmxzpH8sAZD3ajhlk5lowroR2+CF9+fDsATpOWlWUuPn/eHBYW2pFSkkhKNMMMImxGLZ84c9agxw52+PnakzsmdXV5OC+hbY1elpc62NL3vuJJyV/WNfCXdQ187PRKvnLhvDGJ5Uc7UkoJ9MfMavv+k8DZwIf6Hv8j8E2OQnEZINui568fPYkuf4RbH1w/rKf2scBUJTZb9RpsRg3bmjxA6iZm0qnJsujZ3z6+1N5QLDUYGamAxBOMUewwsqetl/beCHajlr1tPm45pYwbVpdRqUyEjwm6/RG+f5QG4bZ6w1z2q7cocho5Z34ud55WOWIIXzIp2dTgJhhN0OIJoRaCi5cUZPQ++8t79Vyzsjij/6NGreKkAfkDN6wq5Vv/3jXEk3osxJOS+IDFp9f3vz85eGZ7a/rnUCzB6nJXqnpLSOxGHeVZJuYX2NhQ18NVy4v59F83090XOvrD/+zhx9cMyX5UUFCYIUy61DVlMpsmH3qnjm9evnDydqgwHGdJKQe2bf0Y+JaU8j9CiIv7fj9zqg7uj8Qx69R89I8bafaEsBu1LD4G8yucJi13nTeXyhzzqIXlfoZrKR8Nq8qd7Gr2TpqwbNSqmJNnpd2XCsLWqAQLC234wnGaPSFqhsmG2HZYl2LPYS38VoOWTWMMVRsvzZ4Ql/7qLX75weWcPEuxyDiWybHqeei21fzshX386pWDw74ulkiFhRY5jLhMerb2zQ8HsrHeTYnLSL7NQJs3TKM784KOVi1oGCEMc02Fa8SCiMlGCIFKjDw/PZoocRn560dOOio88CcDRVwmtZqSSEo6/UdHVdZkM9mG/UuL7dT3BEfls+kOxnhpTztvH+xCIoklJCoBuVYDhQ4Dnz2nilPnDA1N8gSjvH2wm39va+GlPe3EJ/EKUegwoBICl1lHOJZIV2L2M5y898yOVp7e3sr8AivXVpdwUkUWWo2YEj+t6UQIoSZlfTEb+DVwCPBIKfuXGZuAohk6vVGTbdHzr0+dyqt7O/j6P3dybXUxxU4jP3puHz2Bo87RIyOtE6jEGMiailRlSzwp2VTvZl6BNe3nPNDbeaRV5tFQ2xXAqlfji2Suxp6Xb8WoU6cXa+bkWrhuVQnxhMRm1JCQEiE5HjsCjit++J+9aaHSqtfwgw8sptsf5Vv/3nVUDN7OmpfDLSeXZwybjcQTbGv0srvFy66WXt6r7aaxJ4RKpCqgwrEk3/z3Lu46r4o7Tq1Ifxa7/RF+9coBntrawn23Vh8xCNBp1nH39cs42Omf8gWuQ50BDnUGMOvUfPbcOdx6SgU6TWpyfm11CQAXLsrnjQOd3LimjGtXFk/p+SikEEKUAH8C8kgt0t4rpbxHCPFN4KNA/2rB16SUz2bY/kLgHkAN3Cel/OG0nLjCtOMNxfCGYqwsc06agPTQO3Vcs7JYCcqdfiRg6/vZDkxZEMhbB7q49cH12I3a9D35G5ctwKibmtC4qUSjVvGhNaVj3m5/u4+2I7T9j4ROreLyZUXML0j9L/vbhkZ2t/aypsLFx86o5H+e3HlEWwEAi17NggIbO5p7B9nZxZOSXS0THwNMZ6UnpCrJ/+/VA4q4fJxw13lV3PdmbboQKBP9QfTV5c5hX9PYE0r7Mxc5jLjMurQdD5DK29Kq09X6h1PsNLKhrmfU4YCTQW1XgCyzjtm5Fg52+NPXyqORymwzD390DQV240yfyqRxbKtik0A4liAYjfOzF/dPiofT0chkGZqbdWrmFdjGNRAeeHFLQLp12B8Zem77231cfM+bkyooD6TAbmRHk4emvhU4l0mHSgUqIci16tkxjOdt/+ubPSFe2tOBQaviwoX5fOvyReNO+j4akFImgGVCCAfwJDBvtNsKIe4E7gQoLR37IHGyUasE5y7IY0mJnRyLHiEEK0qdfOeZPbyxf3ICQKaSnmAMi16Df4KDSn8knh7clrmMg4ICI/HkoBVdq16NWa9Bo1Zh0qlxmnT4IzF2tfjSrzNpVQRjgzsgsi06jDo1xQ4TCZkKc1AL2Nv2/mKNxaBh44Bjb6x3p9v77n3DxCfOrGRpsZN5BTYUjl5uW1vB6goXWxs9/HtbC0UOIxctKqCxJ8h9b9VO+/ksKLCRlJKTKrOYk2shKSVf+sd2QrEEf/hwNQsLbexr8/HPLc08saU54+JSUkK47zMdjCb47jN7+NfWFh66bRVZFj3bmjwEownW1/Xwk+f28a3LF47YtbKvzccf363jUMf0tOJlW3Q88Ym1lGZlrnT47pWLAGXhZpqJA1+QUm4WQliBTUKIF/ueu1tK+dPhNuxb5P01cB6pBd0NQoinpJS7p/ysFaadvW2+vtBOyapyJzube0cUAUbLL17az323rJqEM1QYBgm8IISQwO+llPcCnwOeF0L8FFABp0zFgZ/d0crn/raVeFKmxZLPnD2bq1ecOIuHD6+r51v/3j0uCzmtWnD18mI+f17VoLyPk2dlcf7db7C5wY1eo+ZPt69md2sv7x7q5u+bmoZoA6vLXexr9xGIxFk/hSHcsSnoOj4SR1vIo8L4EULwiTNn8Yc3a4a1jNSqRarob9iyusH0azdz8ywYtGoi8SQH2n3DduAsL3Wwu6UXjVo1rX7LkArM7q7tYU2Fi+4p9lUfL1V5Fv7ykTXHXbbXCScuv1fTzf1v1TI/38oFi/JZWGjnYIef66tL+Mu6elRCYNZr6PRNsIr5KJrPhaIJDBoV4Ql8sefkWvBH4pPeorO/3c+FiwY/VpVn5efXL+O/Htkyqcfqxx+OEx1wJewJvi88dBzh/3uWWUdljhmBQKsRbGvy8uf36vjUWbOBY3siL6X0CCFeBU4GHEIITV/1cjGQ0ZC8b2B9L0B1dfVRszoz8EI9J8/KH29bxTuHuvnuM3vY0zpzthkalcBp1o14fZnoR+jwgL76w1KEtzd5WV3hYnN9D/P7qi5UKhXew/x0FxfZcQejFDmMHOjwA3GCsSQGjYolJQ6aeoLpFW2bQUNZlpm9bb2sKnciAbUQbBihDcofSSClYM4xHlxwIrCg0MaCQhvXVpfwhfPn8vB79bxX08PXL13ArFwL339mD75pqLLRqVV8YGUxBXYD/kicCxbm0+kL8+f36tMteVf++u1xtcPp1CpOnZONSafhUKef+u5gekD+zI5WPrCymGUljmG3r8wx870rF3H72nKu+vU7U/73+OHVS4YVluHYvhcdq0gpW4HWvp99Qog9jL7rZzVwUEpZAyCEeBS4AlDE5eOUdbU9lGWZUAlBvt1Asyc04Qn4S3s6eHF3O+ctyJuks1Q4jFOllM1CiFzgRSHEXuAa4PNSyseFENcB9wPnHr7heIsxgtE4b+zv4quPbx/0+XCYtJxedeKEtfYEonzvmT1H/I7cdFIp/nCcbU1ezp6XywUL88mx6sm16jFnsL+qyrPypQvm0hOIUuoyUeIyMSfPyhXLirjppDK+8/TutIVGRXZqnNs7xfkuVr16wp2F4+GVPR3c89IBPnvunGk/tsLk81/nzEGtgud2tmPUqTnY4UejEhQ7jfgicdo8IVwmDdszWGKMxL7DOr6HQ6dWMTvXQqsnRGGeBZNOM+UBmodztHYuLyy08ec71hyXeSgnnLi8rMRBMil5cmsznzu3CoDSLBNSQrHDyOoKFzuaewnHEhMKB+sNxSiw62n1Hh1WG06zblRtPodj1qlZWGhjY717Stqf97YNFvrCsQR6jYo5uVNnaB6KJZiTa+kTzEbP7FwLN64p5entrWyqf//i+M6hbn7/eg0Li2z89NqlFDuPHc8cIUQOEOsTlo2kqqZ+BLxKasD8KHAL8K+ZO8uJI4Rg7exs/njbKjbWu3lmeyvP7Gg98oYTZGWZky+cV8Xr+zvZ1+7j+1ctZn+7jy88ti1jm45Zp+7zKB6fDzLAjiYvy4odg/yzrAYN8/Nt9ASjNPQE2VTXw+lVObzaF/jgzZA63d/21OQOYdCqWFxkp9uf2v7wwUFvOJ5+/YY6N6srnEf0szt1dhZz8qxT5jOtMDW4zDo+c84cpJQEInF++9ohHv7IGjp8YXqCMWKJJAfa/TyyvmHUKdOjJZpI8sj6BiAVhiWAz547hy5/lLWzs/nda4foDcfHda86ZXYWZS4T5/zsNZISzl2QS0W2mao8C1+/ZMERvdD6PSNn51q547QKfvHSgbGfxBh4ZV8H58zPVUTkoxQhRDmwHFgHrAU+LYT4MLCRVHXz4Sv1RUDjgN+bgDUZ9ntUdQspTIz67iCVOWZqOgNUlzkHBHeNnx88u4dzlWvDlCClbO77t0MI8SSpRaFbgM/2veTvwH3DbDuuYgyDRk1ddyAtaGZb9Nx5egU3rinLKJYejySTki88tnVQILZJp2ZVX/ZAKJbApFNzUmVWuthnLAy3zaIiO3/72Ml4gzHeOdTJN57aPSXCslYlmJVrwaRTo1GpUKsglpS0esP4w3GcJi3xpKS9NzwkXM1m0KTPqdhppNBuJIlkb6tvzF2Qvkh8RgtwFCafj50+C5VQ8fT2FjzBKFIOLqQbztZwMhg4D+z3FNeoxJR1ph/OwkLbpFjUTDZLSxz86bbVx3TX+0icGHelARi0an58zRJ+/Pw+ntnRymVLC7EZtHzxgrl84sxK/u+Vg8wvsNLmDeGDcRuCH+jwo1ULZuWYCUbjMy4y2wzaMYvLy0sc1PcEp7Ttx6hV88uX9vNOTTefO7cqHZA0L9/K/ALblNzkGnqCrCp3ZrzorKlwUdcVoD1DZenBDj/f+vfQIqJ3DnUD8F5NDxvqeo4pcRkoAP7Y15KrAh6TUj4thNgNPCqE+C6whVQlxjFPrs3AxYsL0p7Ez+9qm5Kb3KIiG2tnZfPlC+ehVglOmf2+r3iWRceHTy7n7pf2D9pGJVLCnVatYlmxg33tvYRiRxbnDBrVoMWjUCxBfU+A1eVODnT4mZNnJRiJp8MUlpU42NroITCGAUU4lmRbo4ccq2FUf69NdW5m5ZhHrLzIsuhZWTa8z5fC0Y3o6/KZl2/l8l+/zfOfO51zF7xfhe4waadMYBUC/nLHGhYXp7xFbzqpDCklTpOO/3lyx7ju2a/t6xyUrv2X91Iidm1XgI11bn5380pWlbtGta/T5mRPubj813UNHGz3c96CPMx6DSvLnMzNV7oAjgaEEBbgceBzUspeIcRvge+Qaqn/DvAz4Pbx7Pto7RZSGD9N7hBqwaSFRdd0BXhhdzsXLMyflP0ppBBCmAFVX1eCGTgf+DYpj+UzgNdIhWFP6sVfpRLcsLo03Ul2XXVJxpDZ45l/bGpKF0PMy7dy6ZICPrSmbNqq/uwmLRctLiSehOd2tiEEzMm1kmfT8/1n90xYcF5UbE9nk2SivwBEpxYU2PVEYkkSUpJISnrDcVwmLUVOIwKRHuvr1IKlxXZ0GhVJmargrO06cjV0LJFkS4ObBYU29JoT63N2PKJRq/jEmbO46aRSFn/zhRk9l2yLji7/9FUSa9RH3wLr6nIX999ajfUIOS7HMiecuAwpUeN/L13Aw+/V0+YNk283YNSpMerUfGBlMRvr3fgjcbY1erEZteMWOGMJyaHOAJXZZhYV6ac85GckDLqxJfECdPkjU95O8PjmZj52RiWP3nkycoDbe79X0FRZY+xu6U2HOQwkKSWRcfpcGY/BwZ6Ucjup6qrDH68hVZFxXJJl0fPrG1cQiMS57aENNLtTPlKjYWWZk2Z3iLbezIs1H1pTyvevWjzs9lqVilybnltPKedgh59rq4v58XN7sRq07Gv3UWA3sKXRw5xcK7uPcO3RqgRLih34I7FBi0eVORa2NHiwGzVsqusZ5IdV0+WnKs+CeYwBMNGEJMusG9XfKSFTwQ/dgSieDJ7vVXkWZk9hd4LC9PH9qxdzsNOPOzj4XrF29tQJrFLCi3vaWVBoS1e+e0MxXt7TQYHdSKs3NKmdNt2BKB/6w3v84OolXDNMOJ43FONfW5tZX9vDC7vbJ+/gI7C+rmdQAvelSwr42XVLlQnhDCKE0JISlh+WUj4BIKVsH/D8H4CnM2zaDJQM+H1YOyqF44toPEl1mXPQGHii/ObVg5wyK+u4nsDOAHnAk30V4Rrgr1LK54QQfuAeIYQGCNPXWTCZ2I1a/vui+ZO922OCRFLyj01NQKo44tE7T5oxcf2ypYVctrRw0GPBaIJvPz0x9yKtWoUQHDH0LJqQGYvVeoKxdGXowNdu68sQSo23R3d9eXlvBy/v7UCnVrGyzMm9H16pXEeOAyx6DY/eeRI/eX7fpFucjpYuf5R5+VZ0GhUHO/yDOhHGihD0FWL5Mu7HoFWxr3X8XcBTwdrZWfzhw9WYdMe3/Hp8v7sRsOg13Hl65ZDE2cXFDhYV2YnGk7y8p4O23vC4q5f7qekKoFUL5uVb8YVjNHvGn3I7XnTqsYvL08W9b9RwsN3PF86fy4JCG75wjEgsyUtTOEEPRBNsa/JQlWchHEuSa9XjCUXZ1dLLoiI7gtRteDRrXhJYX9tDgd1AtkVPOJY44aoKjlXMeg2PfexkfOEYD7xVRzyZJCklf363nkRSsqDQxplzc6ntCvDsjlb+8OFqTpmVRW1XgB3NXlq9YVo8If70bj06jYrPnDWbz5wzsldZfxXKQBwmLbc8sAEg3SngCUZxmrRE40kCw9yAl5Y4WF/Xg16jYlaOmWyLnoMdfrY2epida2FfBnuN3lCc3pAf1RhbZg/3cs5EkcOIUafGZdaxqd7NrBwLnuDggMxTZmXx02uXUOg4pir8FYYh26Ln2f86bUj75fISB1lm3ZSlNP/y5QOsLndx6pxUV4DDpOO+W6oBuPRXb076Ym4sIfnq49tZXupgVs7QhRGbQUOezcCnz57Npnr3uGyoJsrT21v54KrS9N/keEVKeVS2/IvUSd0P7JFS/nzA4wV9fswAVwE7M2y+AZgjhKggJSp/EPjQFJ+ywlFCJJ6kyR3EqFMTmsCEu59tTV7+s6ON61aVHPnFCqOir+hiaYbH3wJWTv8ZnRioVYK/fGQNnlA0HdR9NHH7qRWcNS+XLn+EQCROMJpI/7u5wc2/trYccR8tntARheWJYNKqSUgVFdkmsvv+hvFEki5/lEZ3cMixhUj5Sw9cwFc4thFCcFJlFv976QKu/PXbU3qsuXkWbEYthzr8QxY99vbNSwsdBhwmLS3j1MRWlblYX9eDy6xjUZGdA+0+3MEYZp2aihwzRq16UJj9THPW3Bx+e9PKE0IfOmHFZUh90QocxoyPnzU3l7cOdrGntXdSSvhjCZn+Qq2pcB3Rj3SyGauQBKNd45w4UqZWSve2+XjotlV0+yP8c2vLmD2Rx0osIdnfZ0rf0BMk16onGE2M2mx+Vo6ZRUV2KrLNXLqkgG5/lJ5AVLkRH4NYDdpBARZfumDeoOd/8dJ+fn7dMtb22VtU5lio7BOYYokkN59Uxuxcy7gHvSdXZvPJM2fx4Nt16cT4Fm8YtUowv8CaUSizGjR0+lMVDJF4kkOdAQ51BlhabCfboqN9mMrqfrr90VF7XxU5jEf8XggB8USSgx3vVzYLVUo4L3WZ2N5XQfGDqxcrwvJxhkGrHjJg8oRieDJ4eU8m33hqJw/cuoqyLPOgxxcV2qekU+iRO08adsFRCJFuQ3/g1lV895ndvH2we9LPYSR0GhWN7uC0HnO62dzg5n+e3Mm9N688og/2DLAWuBnYIYTY2vfY14AbhBDLSA2r6oCPAQghCoH7pJQXSynjQohPA88DauABKeWu6T19hZnCpFPjDsYmdX7wwNu1irisMKl8/M+bWDs7i5tPLp/W4+o0qkFB3UcbFdlmKrLNQx4PxRKjEpcDkTgLCqwc7AxMONQzE9ub3y/yqO0aPEawGzXcde5cyrJNZJn1OM1asi36E0IEOxFZWmyf0sIPSC0IbahzYzNoWF3hYlujm0KHCbtRS5s3RFtvhBZPmOoy57jE5QUFtnTXXk8gmi7wy7WqKHIY2NLoPcIeppdz5uXy25tWotMcvYWek8kJLS4Ph5SSDl+EK5YVkW3R4w3FeGVvBwB6jWrCIUXrantYUGCj0R2cUGjgWEhMk3n6ROjwhTnv7jc4dVY279R0TUmA4MjHH50vtkWv4XtXLeKKZakQeE8wytW/fYfGniC/uXHluIR8haOb29ZWYDdmbgvTqlXMyZuY16lOo+LLF87jxd3tgxZVEknJzuZelhbb0+1t/ThMWuq7g1SXOekORNFrBP5IYsjrMlGZbcZi0NAbjo1KXO7oDbOsxM7WEW7Y2Rb9EK/ybX2vTyQDlGeZuHRJIaVHnyCkMAVYDZpRdX5MhEOdAW55YD2vfemsQY/rp2gA95XHt/PcZ08/4uvmF9i4aU0ZPYHYlOQGCAGFdiOlLlPqv6zUv6fOzsZ5HCZP9+MNxbjrb1up6w5y4S/e4GNnzOKG1aXkWPUzfWpAuoIx08f+2WFe3wJcPOD3Z4d7rcLxTaCv82Myh701nQFe3N3OeQvyJnGvCicy99ywjOAUBoAdb5w7P5c39nems3mGwx2M4Q7GRtUhONn8/ubqdN6RwvGPEIJrqov5/es1U3aM/qDR3nAcKSWxhEQlYGujByAdXhuOje9akkmkbfWG0WvEqLWc6eKMqhx+feOKE0ZYBkVcHpa67gD3vVmDWa9hfoGND6wowmHS0tkb4antrUfewRHY3dpLtkXHnFIHm0cw8Z8souPwEZ5uObo/AfdQl29ahGW1SpBt0eEy64knkqhVArVK0O2P4jTrCEbjtHnDROJJjNqUJ/fJs7L4f5cuIM+WWkFPJCW3P7SBms4A379qsTKIP04ZTliebAodxowV+/U9QUqcRhrd71cFm/s8m2LJJLVdgbSVy2io6Qpg1qmxG7WjuhHHknJEH9dV5U629Q0aMpFvS/na33Ve1VHX0qgwOXhDMd460IVZn0psN2hT/751sGvSj1XkMKLXqPBF4oM6Dvr51hWL+NRZs7n7pQOsq+mmpiswKQnVNZ0BApE4Os2RBdx5BTbybHouXFiFxaBhUaENjVrF+toe2nvDHOzws7/dR4cvwvXVJQSicZ4exdji0iUFfPH8uZRnqJI63tna6KGuO1V1FYgm+PmL+9MhzKdX5fD5c6smLRRNQWE6SQWEWdjSMHltvNFEkrse28p3r3y/GEJBYSLoNWrF038MzM618tePnsSuFi/3vVnLP7c2D2t/YTNq2Nk8/RWXx2JekMLEOLMqd0rF5X4P5Byrnp5AFPNhdk8b692sKHWgGed4bThROhI/ugop187O4vc3nxhWGANRxOUMCJHyRD2jKoe/rmvguV2t1HYF0ajge1cvxh+JE03ICU+au/zRaTP1Ho9p+vE8Rbvl5DK+fOG89OoawMEOP+tquyl2mlhabMdh0uELxxBCYNapM4pif3mvns0NHi5enM+e1l6e2tbCZUsKEEIo3ssKY8YXzmwj4AnGqMq10ugOoVMLnCZdujqzNxTDadIyJ886pooHl0VHY8/7YnWuVU9SymFtgHa3eNFpVBlb9gSCaGL4m3pvOMYjd56kCD/HMXe/uJ+H3qljVbmT+QU2DFo1t60tn1RxeUmxnauXF/HB1aVHvLbm2gwsL3Vw9YoiSl0mnCYdd/55I6/1Jc6PhwsW5qUrg33hGG3e8LBdCxXZZh66bWgm6soyZ/pnKSW9oTh2k5b73qyhNxxnZ7N3SJDu4iI7991SzVcf335CB/Z5gkOvTdFEkm1NXrY1eXlySzMfWlPK+Qvyqcg2KxZVCscMsYTErFeniywmC184zmcf3Uqu1cDJs5TqRAWFmWBhoZ27r1/GTSeV8rE/b6bLP7SoozcUZ3mpgy3TUHC2qMjG6vIsFhbamJs/sc5LhWOPkypdXLKkgGcmoVgyEwf7iqRKXSY21bsz2j1NpLDyWNBWVle4+MOHq4+Jc51sTpwa7TGiVglKXCa+eMFcvnfVYi5ZnE9Swg+f3cvqShcfO6OC/710wYTbMXsCUfJtU9/S2TsO78s5uTNzw5nKUIPKnJQ/8v+7bCFGrZouf4SaTj+BSJzZuRbOX5DPYxsbOe3Hr/LJhzext82HRa/JKCw3dAe5763Uyt9zO9t4eF09L+1u5/HNzfz+jUP86pUDPL3tyF5bCgoAwWh8RJ/xbU0eVpe7yLEa6ApE0/YXtV1B3MEYXWNsBWr3hllaYmdVuZPqMicdvgj5NgPDFRZLwKwbepO0GTTs7xg+kbcqz8Lnz60i23J0tK4fTwgh6oQQO4QQW4UQG/se+6YQornvsa1CiIuPtJ/JoL/iJsusR69R0emLTKolhF6joirPypq+qujRcHJlFk3uIHk2A95QjPKs8Vf76jUqbjmlHEhVTdzywHoOdQbGvT9ILWTbTamuiAWFNmwGDRb90AXnHc1eLv3VW9R0Bbj5/vW8sKttQsc9Vqk5wt+7yR3ix8/t49yfv849L+2fprNSUJg4Oo2KwBTaDXzn6d0jdhcpKChMPSvLXDz5yVOozBk6FrEZNbR4Qhm2mlwWFtr496dP5f9dtoAPrCw+IcWvEx0hBIuL7FO2/3ybnqXFdjY3uKnINk+6rhMbRzf+dLK02M4Dt66atgLSo40T812PAbVKcMqsbE6uzOLf21t5flcbP/zPPqwGDQ/duprf3LiC+u6JBeioRMpeYcR2cSkZVvUZBWNpme9nZZmDXS3eo86/ZjzMy7fyP5fMZ0GBjRd3t/OZRzbz5oGutOe1EHDLyeV88/KF/PpDK4gnkjR7QsN6VfvCMf7nnzvSlZ/9L3tqWwvP7WwjmkiiUQl+dt2QYGkFhSF4QzF+9fIB/JHhPdgj8WQ6wOBw7EYt9d3DCy8mnTrdvaDTqCh1mdCo3vdE7qem049BmzmtvsRlYk/rUBG51GViZ8vwIuL+dj+ReIJkUiqVy1PDWVLKw8uD75ZS/nQ6T6K63EU0keTjZ87CYdIRjiX4y3sNk7b/SDzJPzY18fbBLl686wwseg2BSJx1td3saOpFrYLLlxZRmvW+p3eJy0SJy0Q4luC9mm5Wlbs41OnntrXlrKvp4Z9bm2nvHf7+1n/L1agEP712KafMSgV6/uKlAzT0BDlnfu6E3lM8keSZHa2EYwmWlTi5YGH+sIJ1Z999eE6uJW2JkUxKhOCEsZpZVe5iSbE9HQ46EtlHiQ+zgsJILCmyY9Cq2NXSO6UVhLtbe7nyN2/zwK2rOHkMC3QKCgqTS4nLxBOfOIXPPLKFNw8MHroV2o0jjkkG8qE1pXT7I3T7o3T6I6PWIlq94RNmzKAwPAO76Cab+p4Q0YREkNJL3Bm6zibC0SwuV+aYefC21RkLRU4UTtx3PkaEEFy+tJCLF+Vzy8nlvHmgk3V13XzyzNmsKnfN9OlNGev/51zae8N0+SPo1Cr+/F49bx/s4lBnYEi4oVmnpjLHws4W74RWqSZjhUunVmE1pD7e8wtsfP68OTz0Tj3PbG/J6Ods1mkodhrTv2vUKsqGqXKLxpP8c2sLm+oze+P1+1snpOSv6xoIxxJcv6p0gu9I4XjFG4zxjad28s9RJEoPu49QLB2QMBC9RsXSEgetnhClLg02o5YdTZ50y9LhLC52pFuXihxGOnxh5uZbkTLV5rKmwoWEtP1GrlXP7hGqU50mLf/vsgUsLLAPWhuLJ5K8vr+T06ty0KqVBprjga9eNG/Q7+tre2jrHXsK9HBcvbyIHJueiiwzP/zPHubm2VAJuO+tWmq7UoLsb147xOfOncNZc3MpchrTVQMGrZrLlhYCcMmSAgDOnpfHVy+ah5Swoa6HPa29+CNxtjR4UKkEX7pgLnNyLUBq8bDfYqHZE+LRDQ1cX10y4c+uRq1Ke6GGYwm6AxFuO6Wcn7ywLy0mH05DT5AiR+pe9djGRjbVu7lkSQE2oxazTkO+3TBtHvHTzalzslk7ey0b6txsaXCzu7WXV/Z04DtsUe6UWVl8+OTymTlJBYUxUNPpx9+3mDtRT/gj8fBH1vCfHW10+6Ncs7J4So+loKAwPA6Tjj/dvpqX93Tw5NZm1tf2oFEJtozQXaBWCRJJiUYl+OSZs7jr/LmDnt9Q18OnHt48YkHYVcuLuHGNMh9VSC3WX728iCe2NE/J/n3hGIsK7WyfAh9xTzCGSjAt+VxjId9m4E+3r8Z1HAdrjwZFXB4jGrWK1RUuVlccv4Ly4eTZDOkAu29fsYhEUlLb5afYaaInEKWuK0A4nmBNRRZmvYbGniCPbWzksY2No16BnWyiiSTdgSjLSx2cXpXN9b9/j1yrnmUlDjRqFcjUZH5luZMlxXbMWjXVo1wkeHp7C998ahc6tWrQxc1p0qJWibRnbVWulRVlTlo8KXFesQVQyMRT21smJCz3IwQsKLBhNWjY2+aj2GmkvTc8Jh/m9t4wS4rttHrD9IZjFDtNNLtDuIMpW508q55E3+qPVa+h1GWiyGFkT2sv4QxezHedP5erlg+exLZ6Q1zyy7foCUT5/c0ruWBh/gTe9QmPBF4QQkjg91LKe/se/7QQ4sPARuALUsrJS4kaJSUuU3oyNBlkGgDPy7eyvNTBbWvLWVxk584/b+L7z+7l+8/uRadRcdvacr50/tzUNT8DQgiEgDWVWawZIS1dLVL+yK/t6+RL/9iOAD56euWkvK9+DFp1qjJ6FpxUmcVN96/jE2fO4onNTWyoS/3vyzLrsOg11HcHmJVr4brqEh7f3MStD24YtC+XWce3Ll+YFtSPJ4QQg8Zg4ViCdw51sbXBQ3cgSrMnxM0nlc3wWSoojA67WYdaHcMbirO9ycu8fCt724a3mRovOrWK1eWudPeFgoLCzCKE4NwFeZy7IA8pJY09QX7z2iEe3dCYfk2Rw8jHz5zFufNzybcZSMrUWCTTmGZVuYtnP3saj6xroNMfIRxL0NgTYmeL9/0uXRj1XFfh+Odz51bR7AkN8UOeDObkWkdcLBkvq8td7GrxHnXCst2o5c93rKbYaTryi49zFHFZYcyoVYLZfX7MhQ4jhQ7joOdLXCa+cP5cPnvOHF7Z28Gf36sf0vozEpNVvXHx4gJsBg1/39jEtdXFCOCdQ93ptHkgvaL2pQvmcv6igiH7ONTpJ9eqx2p4vxLsgoX5nFSZRYHdQCwh8YVj+CNx8mwGNje42dGUuuhdsCCPDz+4HinBatDwkdMmV4xQOD54bufkBCpo1Sqi8SjralOVxJFYIqPgOxJ13UGsejWz+wYF/QPSfqwGDY6+MMH23jA9gSg1XQHy7QYEqXY7rVrw2bNn4zDruWH14AqJaDzJpx7enA4sq8wevweuAgCnSimbhRC5wItCiL3Ab4HvkBKevwP8DLj98A2FEHcCdwKUlk5+JUtFtpnLlxby5BRVRQDsbfOxt83Hoc4Ae1p7+e6Vi/jq49txB2NE40l+/3oNXb7oIHsibzDGn96t48y5uSwqso2qPbSjN8xXn9jBK3s70GlUPPLRNUMWC92BKJ5QjGZ3iGZPkHAsyUWL8sntW5g9Ei/ubuftg12cOz+Pdw51ce3KYj6wopjLlhZyqMOPNxTjlFlZbGvy8tUndlDbFUjbXV29vIgSlwlPMEqTO0SzJ8Tr+zuPS3H5cAxaNWfPy+PseXkzfSoKCqMmy6wjx6qnqSeYrlwGRrS3mgip4EsPK8sUYUlB4WhDCEFplpkffmAJ5y3IQ6USSCmZk2ulxPW+WKUWkJKIM5Nt0fOZc+YMekxKSUNPkB3NXgSp/Sq2GO8jhKgDfEACiEspq2f2jKaP0iwTv7xhOWu+/zKnzMpifW3PpGkw8eTErSsGFvBlW3SUZZmHtYecSYxaNQ/etmrYgO8TDUVcVpgyNGoV5y/M5/yF+dR1BfjK49tHtTrWHYiyqtyZrtYa0zH7ghgXFdlSFdWxJI/ceVJaCKjvDnDGT14btI1OraLFE2Jfm4/ecGyQzcmsnFRb9Ct72wnHkly8uACzXoO5z0tHpxFkWfRk9e2/2x+lLMvMhYvy2dfm49ZTyrn/rVquWl405veicGKwujwLtUpFkcPAezU96Rb/sfLOoW4AVpY6iMSTdPgihMfhl+6LJNBqMld6HuwMAO+fX03fubZ5w6ypcNHqDWM3ajl3YT7z8m1Dtv/ze/XphOCVZc7090thfEgpm/v+7RBCPAmsllK+0f+8EOIPwNPDbHsvcC9AdXX1lNQADExEN+nUGLVqugMT915bVuLgllPK+N4ze+jyR9ne5OGaFUV88e/biCWSnDo7m33tPjp9ER7f3MQ1K4s5eVaqMtlu0nJ6VQ5f+sc2tGoVv7t5JSatGrtRm9ETPBpPctP969jfnrKS+fy5VUMEmvvfquUHz+4ZMij/3jN7OH9hHt++YtGwbXIdvjAuk45ip5GH3qnjoXfqgFQgyIt72pESfnXDcpaWOAB4dH1D2nP4ksUF/OADi7EZjk8bDAWF45XKHHPGMa5KiClr99WoFAsqBYWjnXPmT+5CqRCCsizzsFaPCkDm7JITgjybgX9/+lQWF9vp8IU51BHgEw9vwtPXsToWtGrB3Dwre9t6M2b0jIXVFU5qO4PYTVraPCG6/NF0Z/jRhEYl+O1NK1hROnUe1scairisMC2UZ5v5vw+t4L2abj7zyJYjvn5zvZvVFS4CkTit3hA9gZEvcnajluUlDmq7/NR2BdIC3Z9uXz2owkyXQTSLJpL8dX0D5y3Io8MX4fFNTWRb9NiMGj58cjkHO/x86uEt3HVeFd5QbEQ/y4GVYnPzrVTlWZSKZYURueWUMj57bqrS4NN/3TxucbmfTX3i7eoK17jCOBcW2tg9QkDfcEQTSc6syuZH1yxN2+j04w/HiSaS3P3i/vRjZ1TlKAF/E0AIYQZUUkpf38/nA98WQhRIKfvL4a8Cds7UOX7jsgU0uUMUOozMyrGgVgliiSR1XQE21LnZ1eKloSdIfXdwxADVfqx6DR9YWcwnzpxFMJrAE4xh0Kr4+BmzuLa6hJtOKiORlDzwdi2Li+0caPeTa9PTHRj8PVha4uDfnzmV+9+q5Yr/exuDVsXNJ5XR1hvmQ6tLB1UfbKp3s6DAxv52PzlWPbeeUj7kvHY0eTJWe0QTSZ7e3kp7b5hPnjmbleXOIULwP7c089jGJr59+ULybPq0ldS2AaF15/78dUqzTISiCb55+UKuWVlMOJ7k9DnZSgWSgsIxSPswfvTZFh31fUHRk43TdGL7QCooKCgoDGVxsR2AXKuBHIses05zRHF5foEVi16DEILeUAyrQdNnw9JLrlU/rvlnPzaDhi0NHmIJSad/ZuxVR8vPrlvKmXMnFu59vKGIywrTRo5Vz2VLCzl1djZX/PptGnqGT7ZNSAZ5xa4ud9HhCw+ytNBpVETjSeYXpALHXtvfOWgf8/KtnF6VM+gxnVqFRiWGCAFatYq/b2wkEk9y5txcNGrBogI7Wxs93P9WDTefXMbjm5tYVeFiWV8F2WhQJv4KR8IxYMJ32pxsnt4+fpsMq0HD7BwLGrVgf/v4Vo27A1H8hwVkHYlcq567r1tG+TA2FzqNYHerb9B++ytJFcZNHvBk3zVGA/xVSvmcEOLPQohlpBwT6oCPzdQJzs61pi2U+tGqVczJsw5pH4slkrR4QvxnZxs//M/eIfu6fGkh375i4aDvy9ZvnE8wGufe12swaNUAaNSCO0+fBTBi+6dWnRKlL1qUz/ef3cOGOjfnL8xLL3gkk5LHNzfx7X/vTgfG/dfZszHq1EP2dff1yzh5VhbffWbPECsZgA11bm57aAM6tYpT52Rz0aJ8lpY4uO7376YH8Hf+eRNfOn8uj25sGFLxEU9KajpTi05ffXw7j955MnPzlfY7BYVjlTybgXy7kaSUNHQH0xPx+p4QZVkm6ruHHx+Pl0c3NPDlC+cd+YUKCgoKJw7DZZeckHT5o7iDI1cIC1Idq+5hBOiJCMsA8wqsrK+d9qiYMfONyxakQ7kV3kcRlxWmHadZxytfOINndrTy2Ue3jmqb9XU9WA0aFhRY0ahV1HYFsBs0rJ2dxYHOAJvrPenXOkxazp6Xy9cunj9kP1kWPT/6wBK++e9dJJKSkyuzOHlWFstKHPx9YxM9gSA/em7vIIHguuoSbltbzn9fNE8RixWmlA+sKGZhoZ2P/HEjbcNUNg2H1aDh1S+eiUWn4TevH6LQYaS2K5BuoR8NWpUgmEFYvmZlMf/Y1DToMSHAYdSytMTBR06tHFZYBtBp1Bi1799u5uVbWT6GRRqFoUgpa4ClGR6/eQZOZ8Jo1SrKsszccWoFZr2GaDyJRa/mjKpcmtxB5uRasZsGV/1a9Boseg1fv3RBxn2O5npdlmXm9zcPtdhTqQRXLCvi0Q2NbKp3U+w0cv2qod7Uu1t6+fo/dyAho7A8kGgiySt7O3hlbwcalRhUue+PxPnef/Zw1fIiegLRIWG4Bq2Kz59bxY0nlWHRK0M3BYVjmX5LjKUl9kH2QZDyY54Kcbnf2kdBQUFBIc2Q7JLD7OWmNJ/kaKPTFyE4IAcgE6UuE/UjFAhOlDbv2Oa/k4laJVhSbOekyiwisST+SAxfON73XwxfJPXzh1aXctvaihk7z6MZZYaiMCNo1CquWFbEz1/cP+pBtC8cZ3erjxyrnq9fMp9lJSlvWXFYuIHDpB0UgHA4H1hZzJlzc3CadEQTSe59o4bbHtyALxJHJVIC9OpyF6fOyea8BXlK8qfCtKFRq7DoNRmFZbVKYNFrOL0qh/MX5PGvrc3cvraC/e0+zl2QR7ZFn67evOu8KgC2NXq49nfvEk0cOVhhUaENbyhGo3toS248keTLF8xlc4O7LwjNTq5VPyTMc8T9F9k4qdLF1kYPv7tppbJQo5ARrTplUTGQfPvoQvEmG51GxSfOmMVH/rSRL54/N6OtUmWOmcuWFqY8+0MxDnWOztYmnpRDjFWj8SR/29DIdSuLeftQN82e1HdRrRL89qaVnKW03ikoHDcUOYzsah6cel/mMrJrHLZUo2F9bTeeYHRQ94eCgoLCiUym7BLgjQHPT3k+ydGEWT+0O+9wGnqCU5YNkGfT0zBF1lDDodOouHZlMZcsKWBpsSOdq6UwPpS/nsKMsrLMOaYKjQ+sKOZrF89LB+iNlyyLnngiyYfvX59OHr2+uoTPnDMbp0mnXFgUZoz1dT1U5pip7w4O8qA9b34ev7lxBZKU2NTv733K7Oxh9xVNJEclLM/JtRCMJTIKy3NyLczOsXDZ0gJWlTtZVTE+OwshBH++Yw1ff3In5dlmovEkasVzWeEo59wFeez61gXD3hMMWvWg6gV/JM6uZi//3NrM09ta05Yao6Uyx8xHTq9kdp6F7z+7l8ocMz+8egmrK1xH3lhBQeGYodBhSC8g9aNSqYjEj3zPHg+94Ti/f6OGryjWGAoKCgrDZpfM8GnNKGVZZr50wVx+8vy+YV+zoszBpgEd45NJjkU/pHNvqjDr1Nx0chl3nFpBrnVmiliORxQFTWFGWVnm5InNzRmfsxk0GLTq9MrYraeU8emz50zasTVqFWVZJva29fKR0yr59FmzRwwYk1ISiCaUlmSFKeW66hKuqy7hR8/t5bevHUKrFuRaDbx9qItANI7VMHyg5OEsK3Hw4G2r+O/Hd6SroddUuNjW5CEcS6JVC5aVOGjvjQzyQL90SQHZFj3ZFh0fXF2aDsUscU0sbVqrVvGlC+cCqYRdBYVjgbEsNlr0GtZUZrGmMotvXLaQv29s5NevHhrSjWAzaChxmfCGYrR6w+mFpBZPiI7eCA+9XQfANy5bqAjLCgrHGVa9hr2tQyuUzXo1VXmWKbOwePtg14he9AoKCgonEBmzS2b2lGaeT501mxd2t7Ot0TPkuVyrnt0t48v0GQ2Zck2mgjm5Fu67pZqyrInNaxWGoqhkCjPKcFXLJ1W6+OtHThpR7J0MfvSBJXzj8oWjEoyFEMedsCyEKAH+ROoGK4F7pZT3CCFcwN+AclKhYNdJKY9+d/3jiI+fMYsCu4GlxQ7qugN89tGthGNJxrK4qlWrOGtuLm98+Swi8QQ7mr2sLHMiEDyyvoF5+VY++7etdPkirC53cfmyQhYX2Vna54cciSXQayf3Rt8vVE/1d1tBYaYxaNXcfHI5N6wuZV1tD09vbyEal9y2tpwFBbb0dyCeSNLqDdPlj1CZY8Fu1HLhogIeeLuWNu/0tgcqjI8R7qU/AS4DosAh4DYppSfD9nWAD0gAcSnlUCNwhWMWg1bFggIbLZ4wbb1h5uRZ2NzgAaC6zIkEegJRfKEYHb4IhQ4DLZ7J953c3uTl83/byi8+uHzS962goKBwLDFcdolCKqzu39taEAh84RgatQqBxKBV09AT4u2DXYRiI3szjxWbQZNR0J4Kfn/zSkVYniKOL6VM4ZgiHEvw2MbGIY8btWpKR/BMnkxUquNPMB4jceALUsrNQggrsEkI8SJwK/CylPKHQoivAl8FvjKD53nCYTdq+fDJ5QBU5Vl588tnjXtFV6dRodOoOGXW+xYat5xSzlsHuuj0Rbj7uqVcuqRwiOA72cKygsKJiEatYu3sbNYOY2GjUasocZkGZQX8zyXzafGEaJxm7zmFcTPcvfRF4L+llHEhxI+A/2b4e+lZUsquaTpfhSnEatCQZdYRjCYozzazp7WXzQ0edGrB7FwLzQMsqCSwqT61di9ESmxWCTEl4jLAP7e2sKjIzm1rKxRrKgUFBQWFIawodbKi1Dns895gjC/+Yxsv7m6ftGPOL7CxrrZnxNfo1KpR2T0Oh9Ok5QMriqnMsYx7Hwojc0KragozR4snxB1/3IgnGEOtEpw+J5t5BTbmF9g4Z16u4nk8TUgpW4HWvp99Qog9QBFwBXBm38v+CLyGIi7PGEadesSQyvGyrNSBRiU40OFXKokVFI4i1CrBL29Yjn+Mns0KM8Nw91Ip5QsDXvYecM1MnJ/C9JJn1XOwL9yzw/e+f2Q0ITnY8b7lxewc8yB7DClhQ50b6xSPgb/7zB4eeqeOhYU2VldkceOa0nQgsIKCgoKCwkjYTVp+f9NK/raxke8/uwdfeGJjVa1ajFi1XOIycu3KEq5fVcLfNzby0xf2H3GfVy4rpNRlwmnWUZVnpSrPSrZFp9hCTTGTOnoRQqiBjUCzlPJSIUQF8CiQBWwCbpZSRifzmArHJgatmjm5FtZUuLjj1IopEc4UxoYQohxYDqwD8vomywBtpFp9FY4zLHoNP7h6MUJALJFEq1bN9CkpKCj0odOocGl0M30aCmPksHvpQG4nZTeVCQm8IISQwO/7EuoVjlF0msH3UrWAFWVO9rb24oukWomXltjZ0+ojmiHAb6xBoOOhyR2iyR3i+V3t7G/z8aNrlkz5MY91MtnXCCH+Bszte4kD8Egpl83ICSooKChMEyqV4IbVpZw9L5f/96+dPL9r/FXM8/Jt7Gj2Dnl8dYWLD64q4cplRekiqE+fPYflpU5ufXA9sYQcsg3AA7dWc/Y8RbqYCSZ7afyzwB7A1vf7j4C7pZSPCiF+B9wB/HaSj6lwDOIy6/jlDYrn29GCEMICPA58TkrZO3BVT0op+ya8mba7E7gToLS0dDpOVWGSWF/bw983NtLhi9DiCfF/rxzk6c+cNm1hCgoKCgrHG4ffSwc8/j+krDMeHmbTU6WUzUKIXOBFIcReKeUbGfav3HOPAQ5v211c7GBDnZtip5H5hUai8QTbmrzIzPPiaefJrc0sKLRxyynlM30qxwKD7GuklNf3/yyE+BkwVCFRUFBQOE7Jsxn4/c3V/GdHK//vqV10DujWGS0G7eAF2bPn5fLps2cPa82xdnY2f/hwNc/vaseoVVPkNFKeZcKoU9PUE+Ksubnjei8KE2fSxGUhRDFwCfA94C6RUqfOBj7U95I/At9EEZcVFI4qhBBaUpPhh6WUT/Q93C6EKJBStgohCoCOTNv2VVfdC1BdXX2UTJMUjsSLu9v5yuPb6Qm830hy+dJCVErhsoKCgsK4GOZeihDiVuBS4BwpM8uJUsrmvn87hBBPAquBIeKycs89utFrVCwptrOh7v38Y61KEIymKpH7q4WPNqLxJN/69y6MWjVXryhCo3QxjZm+ee91pOa+CgoKCicUFy0u4JTZ2fzg2T08umFoptZwGLQq6rqC6d9/ft1Srl5RfMTtzpyby5mZRORZoz60whQwmaOHXwBfBvqX67NItQb193Y1kfJyVVBQOEroGwzfD+yRUv58wFNPAbf0/XwL8K/pPjeFqSGZlPx/9u46vLHjbPjwb8SSJUuWme1lZggzJw2nmGLalL9ym8Lbt03btG85pbRpmjalpGmoTZqGYcPLzOu118wgxvn+OLLXsiXTrmk993X5WuuI5sg7mnPmPPM8t/5lc9LEssWo43vXLcFsUFHLiqIoo5VuLBVCXIZ2bHy1lNKf5rkZiSKACCEygEuA3ePfauVkKXPbKHZZWFXuSppYXl/pxm03cbDZO8Szp4a4hC8/vJN33v0m7d7RR57NEL3pa7YkVhH0dzbQLKU8NAntUhRFmXROq5Ef3LCMu9+7mv6lfIYq67OsxEVrYswpdVu5alnROLdSGU8nJXJZCHEV0CKl3CKEOG8Mz1fL/BRlcpwJvBfYJYTYntj2NeAHwINCiFuAGrRoDOUU4TAb6OlXfOFDZ1bisBgnsUWKoijTWrqx9BeAGS3VBcCbUsqPCSGKgHuklFeg1TR4NHG/Afi7lPKpCW6/cgL84ShvW17EN65cxOrvPENljh1vODps5fupaHNNJ2/75at84MwKbj1HhYANMFT6mncB96d7ojrXVRRlprhkcQGv3XYBXf4ITd1B8jLNtHvDvHq4jcd3NNDuC1OaZcNu1rMxMU7Oys3gL7esH1SzQJleTlZajDOBq4UQVwAWtJzLdwIuIYQhEb1cAtSnerJa5qcok0NK+SqQ7nrihRPZFmVi6HSC379vDQ9vreNIq4/PXzyPM+fkTHazFEVRpq0hxtIn0zy+Abgi8XsVsHz8Wjc5su0mSt3WIR8zXjmHJzqXsRDwwTMq2VnXxdrKbPY3aem2h9v/qUKk+K/71zePMTvXzoULVVGkXunS1wghDMD1wOohnqvOdRVFmTEKnVYKnVYWFmb2bTtnXi5fu2IhAL5QlFcPtxGLS1460MJ71pdT7JoeY6aS3kmZXJZSfhX4KkAicvmLUsr3CCH+CdwIPIBaWq8oijIlrJ+VzfpZ2ZPdDEVRFOUU9bUrFvadRM4UZdk2fv++NZPdDGUcJFLW6KSUnn7pa25P3H0RsF9KWTdpDVQURZlGMswGLl1cAMAVSwsnuTXKyTLecedfQSvudxgtB/Mfxvn9FEVRFEVRFEVRFOVkyQdeFULsADYC/+mXvuadDJESQ1EURVFmgpOVFqOPlPIl4KXE71VoS4YURVEURVEURVEUZVoZKn2NlPIDE9saRVEURZl6VMZsRVEURVEURVEURVEURVEUZdSEnOiqF8MQQrQCNSN8eA7QNo7NORFTuW0wtds3U9tWLqXMHafXHnej7LvjZSr/3xmLU2l/TqV9geT9OVX77qnwN1P7MDVMxX04VfvtVDIV/+4jpdo+eYZr/0zsu9P9b5rOqbpfoPZtoJnWb6f631+178TMpPaNuO9Oucnl0RBCbJZSTsnKGVO5bTC126fapozVqfb3OZX251TaFzj19ieVU2Ef1T5MDafCPiijN53/7qrtk2e6t388nKqfyam6X6D2baab6p+Rat+JUe1LTaXFUBRFURRFURRFURRFURRFUUZNTS4riqIoiqIoiqIoiqIoiqIoozbdJ5fvnuwGDGEqtw2mdvtU25SxOtX+PqfS/pxK+wKn3v6kcirso9qHqeFU2Adl9Kbz3121ffJM9/aPh1P1MzlV9wvUvs10U/0zUu07Map9KUzrnMuKoiiKoiiKoiiKoiiKoijK5JjukcuKoiiKoiiKoiiKoiiKoijKJFCTy4qiKIqiKIqiKIqiKIqiKMqoTZvJZSHETUKIPUKIuBBiTYr7y4QQXiHEF/ttu0wIcUAIcVgIcdtEt00IcbEQYosQYlfi3wv63bc6sf2wEOIXQggxkW1L3PfVxPsfEEJc2m/7hHxuKdq6QgjxphBiuxBisxBiXWK7SHxGh4UQO4UQqyaqTQPa92khxP7E5/nDfttTfo7K+BJCfC7xt9gthLhfCGERQlQKId5K/D3+IYQwTXY70xFC3CuEaBFC7O63zS2EeFYIcSjxb1Zi+5ToA0NJsz8/SvSZnUKIR4UQrn73Tel+k2p/+t33BSGEFELkJG5P+b/PaKTqW5PdppEYTZ+aqkbbj6ai0fQd5dQghCgVQrwohNib+O74TGL7t4QQ9Ynjuu1CiCsmu60DJY4dNgohdiTa/u3E9mlxPDFE+/8khDja77NfMclNTUsIoRdCbBNCPJG4PS0++/EwRF+aVuNAKun2rd/903J8GGq/RJpzx+liiP+PKc/ZZ6KpPoZMlzFiqo8DKdo3ZT4/IUS10OYVtwshNie2Tc75j5RyWvwAC4H5wEvAmhT3PwT8E/hi4rYeOALMAkzADmDRRLYNWAkUJX5fAtT3u28jcBoggP8Cl09w2xYlPhMzUJn4rPQT+bmlaOszvZ8DcAXwUr/f/5v4rE4D3pqE/3/nA88B5sTtvKE+x4lu30z7AYqBo4A1cftB4AOJf9+Z2PZb4OOT3dYh9uEcYBWwu9+2HwK3JX6/Dfi/xO+T3gfGuD+XAIbE7//Xb3+mfL9JtT+J7aXA00ANkDNd/j6j2O+UfWuy2zXWv1m6PjVVf0bTj6bqz2j6jvo5NX6AQmBV4ncHcDDxPf8tEsflU/Un8b1tT/xuBN5KfI9Pi+OJIdr/J+DGyW7fCPfh88DfgScSt6fFZz9On0W6vjStxoHR7Fvi9rQdH4b4m6U8d5xOP0PsW8pz9pn4M9XHkOkyRkz1cSBF+6bM5wdUD/zeZJLOf6ZN5LKUcp+U8kCq+4QQ16KdDO/pt3kdcFhKWSWlDAMPANdMZNuklNuklA2Jm3sAqxDCLIQoBDKllG9K7S/+Z+DaiWwb2mfxgJQyJKU8ChxG+8wm7HNL1VwgM/G7E+j97K4B/iw1bwKuxGc4kT4O/EBKGQKQUrb0a1uqz1EZfwa0PmUAbEAjcAHahSaA+xinfnUySCk3AB0DNl+D1m5Ibv9U6ANDSrU/UspnpJTRxM03gZLE71O+36T5+wD8DPgy2vdVryn/9xmlgX2rYZjHTwmj7FNT0ij70ZQ0yr6jnAKklI1Syq2J3z3APrQLVVNe4nvbm7hpTPxIpsnxxBDtnxaEECXAlcA9iduCafLZj4d0fWm6jQOpDPM9MW3HhyH2K92547QxxL6lO2efcab6GDIdxoipPg4MbN80MSnnP9NmcjkdIYQd+Arw7QF3FQO1/W7XMbkHujcAWxMDTHGiPb0mo23pPp/J/Nw+C/xICFEL/Bj4amL7VPhbzgPOTizPeFkIsXYKtW3GkVLWo/0fOYY2qdwNbAG6+h18T8e/Rb6UsjHxexOQn/j9VPh/9iG06F6YpvsjhLgGbQXKjgF3Tcv9SSVV35JSPjO5rToh6frUdNW/H00bQ/Qd5RQjhKhAW7n3VmLTpxJL+e+dsGWZo5RY7rodaAGeRVtNM22OJwa2X0rZ+9l/L/HZ/0wIYZ68Fg7p52iTivHE7Wym0Wc/nlL0pV7Tchzor/++nUrjw4C/Wbpzx2lpwL59ltTn7DPSVB9DpsEY8XOm9jjwc5Lb12uqfH4SeEZoaXhvTWyblPOfKTW5LIR4Tmg5Hgf+DBU5+y3gZ/2uyEyltvU+dzHaEqaPTrW2TbRh2vpx4HNSylLgc8AfplDbDIAbbRnJl4AHE1fVlEmQOEG9Bi2lQhGQAVw2qY06yRKrGqbUleWxEkJ8HYgCf5vstoyVEMIGfA345mS3ZTyl6ltCiJsnt1Unx3TvU9O1H82UvqP0BXw8DHxWStkD3AXMBlagXaz6yeS1Lj0pZUxKuQItGnQdsGByWzQ6A9svhFiCNtmzAFiLdvz6lclrYWpCiKuAFinllsluy1SToi/1bp+W40B//fcNbV9OifEhxd/slDl3TLFvk3rOPtVM9TFkKo8RU30cGKJ9U+LzSzhLSrkKuBz4pBDinP53TuT5j2Ei3mSkpJQXjeFp64EbhZYk3wXEhRBBtCjG0n6PKwHqJ7htvWH0jwLvk1IeSWyuJ3k502S0rZ70n89J+9wGGqqtQog/A71FEP7J8aUHQ7X1pBmmbR8HHkl0zo1CiDiQM1FtUwa5CDgqpWwFEEI8ApyJlo7AkLjSOR3/Fs1CiEIpZWMirULvErpp+/9MCPEB4CrgwkT/gem5P7PRJlx3JM4NSoCtQitiMh33J51UfesM4K+T2qqxS9enppU0/Wi6SNt3pJRNk9oy5aQRQhjRJh/+JqV8BEBK2dzv/t8DT0xS80ZEStklhHgROJ1peDzRr/2XSSl/nNgcEkL8EfjiEE+dLGcCVwut0KMFbZn9nUzDz/5kStWXEts/wPQdB4DB+yaEWMopMD6k+ZvVkfrcsXWSmjkmafbt/aQ+Z5/RpvoYMkXHiKk+DgxqnxDir1LK3sCbyf78eledIqVsEUI8inaBY1LOf6ZU5PJYSCnPllJWSCkr0ELW75BS/grYBMwVWqVJE/BO4N8T2TahVfL9D1oy7df6tbkR6BFCnJa4gvk+4F8T2Ta0z+KdQssBXQnMRSsyOJmfWwNwbuL3C4BD/dr6PqE5DW2ZdmOqFxhHj6EVZkAIMQ+t2GEb6T9HZXwdA04TQtgSfehCYC/wInBj4jHvZ+L71Yn6N1q7Ibn9U6EPjJoQ4jK0ZURXSyn9/e6adv1GSrlLSpnXb7ypQyty0sQ0/fukkapv7ZvkNp2IdH1q2hiiH00Lw/Qd5RSQ+K74A7BPSvnTftv7556/Dtg90W0bjhAiN3G8jhDCClyM9p03LY4n0rR/f+9nn/jbXMsU/OyllF+VUpYkvhfeCbwgpXwP0+SzHw9D9KVpPQ5A6n07FcaHdH8z0p87ThtD7Fu6c/YZZ6qPIVN9jJjq40Ca9t08VT4/IUSGEMLR+zta8dfdTNb5j5wCFQ5H8oN2UFoHhIBm4OkUj/kW/apSo1UvPYiW9+brE9024BuAD9je7ycvcd8atD/8EeBXgJjozw34euL9D5Co+DqRn1uKtp6FFnG+Ay2f0+rEdgH8OtGeXcCaSfj/Z0KL3NsNbAUuGO5zVD/j/jf5NrA/8Tf5C2AGZqFNUh5Gu5Junux2DtH++9GWCUcSffQWtBxTz6MdpD0HuBOPnfQ+MMb9OYyWi7j3+++3/R4/pftNqv0ZcH81icq80+HvM8p9H9S3JrtNY/2bpetTU/VntP1oKv6Mpu+on1PjJ3H8JoGd/f6fXpH4/tiV2P5voHCy25qi7cuAbYk27ga+mdg+LY4nhmj/C4nPfjfa8at9sts6zH6cBzwxnT77cfoc0vWlaTUOjGbfBjxm2o0PQ/zN0p47TpefIfYt5Tn7TPyZ6mPIdBojpvo4MKB9U+LzS3xOOxI/e0jM3TFJ5z8i8eaKoiiKoiiKoiiKoiiKoiiKMmLTPi2GoiiKoiiKoiiKoiiKoiiKMvHU5LKiKIqiKIqiKIqiKIqiKIoyampyWVEURVEURVEURVEURVEURRk1NbmsKIqiKIqiKIqiKIqiKIqijJqaXFYURVEURVEURVEURVEURVFGTU0uK4qiKIqiKIqiKIqiKIqiKKOmJpcVRVEURVEURVEURVEURVGUUVOTy4qiKIqiKIqiKIqiKIqiKMqoqcllRVEURVEURVEURVEURVEUZdTU5LKiKIqiKIqiKIqiKIqiKIoyampyWVEURVEURVEURVEURVEURRk1Nbl8ihBCzBdCbBdCeIQQ/2+y26MoytAG9Nm4EOJ/Rvi8PwkhvjtObaoWQlw0Hq+tKIqiKJNBCLFHCHHeCTxfjbuKMoWMtU/378tCiLOFEAdOdtsUZSY4GX1wMgghfjvSc25l9AyT3QDlpPky8KKUcsVkN0RRlBFRfVZRFEVRxpmUcvFkt0FRlJPnZPRpKeUrwPyT0BxFmXGm67gqpfzYZLfhVKYil08d5cCeVHcIIfQT3BZFUYaXts8qinJqEEKoi/iKoiiKoiiKopzS1OTyKUAI8QJwPvArIYRXCPF3IcRdQognhRA+4HwhxJVCiG1CiB4hRK0Q4lv9nl8hhJBCiPcLIY4JIdqEEF/vd79eCPE1IcSRxBL+LUKI0sR9C4QQzwohOoQQB4QQb5/o/VeU6SZNn+1dpneeEKJOCPEFIUSLEKJRCPHBNK+TJYR4QgjRKoToTPxe0u/+l4QQ3xFCvJbou88IIXL63f9eIUSNEKK9f59XFAWEEKsS46ZHCPFPIcQ/+vXTqxJpbbqEEK8LIZb1e161EOIrQoidgE8IMScxxn4wMf52CiE+JoRYK4TYmXiNX/V7/mwhxAuJftkmhPibEMI14PW/mHhud6JdlsR9u4UQb+v3WGPiNVZOxGemKFNRb+qJk3E8q8ZdRZl8/fr0t4QQDwoh/pzob3uEEGv6PW6lEGJr4r5/AJZ+950nhKjrd/u2ft8Ne4UQ103wbinKtHEy+mDi/o8IIQ4nxt5/CyGK+t0nE8fLhxLHyr8WQoh+939ICLEvMRY/LYQoT2wXQoifCe08ukcIsUsIsSRxX//UOEOO58roqcnlU4CU8gLgFeBTUko7EAbeDXwPcACvAj7gfYALuBL4uBDi2gEvdRba8qALgW8KIRYmtn8eeBdwBZAJfAjwCyEygGeBvwN5wDuB3wghFo3LjirKKSJNn+2vAHACxcAtwK+FEFkpXkoH/BEtCroMCAC/GvCYdwMfROujJuCLAIl+ehfwXqAIyAbUgKoogBDCBDwK/AlwA/cD1yXuWwncC3wUrd/8Dvi3EMLc7yXehTbWuoBoYtt6YC7wDuDnwNeBi4DFwNuFEOf2vj3wfbR+uRAoBb41oIlvBy4DKoFlwAcS2/8M3NzvcVcAjVLKbaP7BBTllHQyjmfVuKsoU8vVwANo4+2/SfTHxDj+GPAXtHH8n8ANQ7zOEeBstOPvbwN/FUIUjlejFeUUMqY+KIS4AO149+1AIVCTeJ3+rgLWoh3rvh24NPHca4CvAdcDuWjn1fcnnnMJcA4wD60/vx1oT9HukYznyiioyeVT17+klK9JKeNSyqCU8iUp5a7E7Z1one/cAc/5tpQyIKXcAewAlie2fxj4hpTygNTskFK2o3X2ainlH6WU0cTJ68PATRO0j4pyqooAt0spI1LKJwEvKfLCSSnbpZQPSyn9UkoP2gWlgf36j1LKg1LKAPAgsCKx/UbgCSnlBillCPgfID5O+6Mo081paHUpfpHoh48AGxP33Qr8Tkr5lpQyJqW8DwglntPrF1LK2kS/6/WdxHj8DNoF3/ullC1Synq0g+KVAFLKw1LKZ6WUISllK/BTBvfrX0gpG6SUHcDjHO/XfwWuEEJkJm6/F+2gXlGUk3A8q8ZdRZlyXpVSPimljKGNd73nr6cBRuDniXH8IWBTuheRUv4zMa7GpZT/AA4B68a78YpyChhrH3wPcK+UcmtiTPwqcLoQoqLfY34gpeySUh4DXuT4ePox4PtSyn1SyihwB7AiEb0cQQuwXACIxGMaBzZ6hOO5MgpqcvnUVdv/hhBivRDixUTYfzdah8wZ8Jymfr/7AXvi91K0q7kDlQPrE8sUuoQQXWhfEgUnYwcUZQZrTwyUvfr3xz5CCJsQ4neJJbY9wAbAJZLzrKfr10X0+56QUvpIfVVXUWaiIqBeSin7bevtL+XAFwaMfaWJ5wx8bH/N/X4PpLhtBxBC5AshHhBC1Cf69V8Z4XgtpWwAXgNuEFoqjcuBvw2zr4oyU5zw8awadxVlyhnY3yxCq3eQahyvSfciQoj3iePprrqAJQweexVFGWysfbCo/20ppRdtTCwe4rV7x9Ny4M5+/bUDbeVfsZTyBbQI5F8DLUKIu/sFXfQZ4XiujIKaXD51yQG3/462TKFUSukEfovWAUeiFpidZvvLUkpXvx+7lPLjY261oiij8QW0iOb1UspMtCVAMLK+3Yh2oq09QQgb2hJdRVG0/lHcP7cbx/tLLfC9AWOfTUp5f7/HDhyDR+OOxPOXJvr1zYx8vAa4L/Gcm4A3EpHRiqKcnONZNe4qyvSQahwvS/XARLTj74FPAdlSShewm9GNvYqiJBuuDzagTRIDkEhRlQ2M5Li1FvjogHHbKqV8HUBK+Qsp5WpgEVp6jC+leI0TGc+VFNTk8szhADqklEEhxDq0fHAjdQ/wHSHE3ESC9GVCiGzgCWCe0IqTGBM/a/vlalYUZXw50CIeu4QQbuB/R/Hch4CrhBBnJXJi3Y4aExSl1xtADPiUEMKQyO3Wuzz298DHEiuChBAiQ2hFcx0n6b0daKlwuoUQxaQ+IB7KY8Aq4DNoOZgVRdGcjONZNe4qyvTwBlrNg/+X6NPXkz7NRQbaRd1WAKEV0l4yIa1UlFPXcH3wfuCDQogViboldwBvSSmrR/DavwW+KoRYDCCEcAohbkr8vjZxjG5ES0MXJHUKqhMZz5UU1AHNzPEJ4HYhhAf4JloOuJH6aeLxzwA9wB8AayI3zSVohU8a0JYt/B9gTvM6iqKcXD8HrEAb8Cbw1EifKKXcA3wSbVVDI9AJ1A35JEWZIaSUYbQiIbcAXWiRwE8AISnlZuAjaEvuOoHDHC+odzJ8G21yuBv4D/DIaJ6cyPP6MFqxv1E9V1FOcSfjePbnqHFXUaa8fuP4B9CWzL+DNGOilHIv8BO0ybBmYClaiilFUcZouD4opXwOrfbAw2hj4my0cXgkr/0o2jj9QCKlxW60VHCgFez9PdoYW4OWauNHKV7m54xxPFdSE8kpUBRFURRFUZSBhBBvAb+VUv5xstsyHCHEN4F5UsqbJ7stiqIoiqIoiqKc2lTksqIoiqIoygBCiHOFEAWJtBjvB5YxDaIaEkv7bgHunuy2KIqiKIqiKIpy6lOTy4qiKIqiKIPNB3agpcX4AnCjlLJxUls0DCHER9CKnPxXSrlhstujKIqiKIqiKMqpT6XFUBRFURRFURRFURRFURRFUUZNRS4riqIoiqIoiqIoiqIoiqIoo6YmlxVFURRFURRlAgghXEKIh4QQ+4UQ+4QQpwshVggh3hRCbBdCbBZCrJvsdiqKoijKdCeEuFcI0SKE2N1vm1sI8awQ4lDi36zJbKOinCqmXFqMnJwcWVFRMdnNUJQJt2XLljYpZe5kt2OsVN9VZirVdxVl+pmsfiuEuA94RUp5jxDCBNiAB4GfSSn/K4S4AviylPK8oV5H9VtlplJjrqJMP5M45p4DeIE/SymXJLb9EOiQUv5ACHEbkCWl/MpQr6P6rTJTjabvGsa7MaNVUVHB5s2bJ7sZijLhhBA1k92GE6H6rjJTqb6rKNPPZPRbIYQTOAf4AICUMgyEhRASyEw8zAk0DPdaqt8qM5UacxVl+pmsfiul3CCEqBiw+RrgvMTv9wEvAUNOLqt+q8xUo+m7Ki2GopyihBDzE0tse396hBCfHelSICHE+xOPOSSEeP9Et19RFEVRTjGVQCvwRyHENiHEPUKIDOCzwI+EELXAj4GvTmIbFUVRFOVUli+lbEz83gTkT2ZjFOVUoSaXFeUUJaU8IKVcIaVcAawG/MCjwG3A81LKucDzidtJhBBu4H+B9cA64H9VPipFURRFOSEGYBVwl5RyJeBDG4M/DnxOSlkKfA74Q6onCyFuTeRk3tza2jpRbVYURVGUU5LUcsSmzBOrxlxFGR01uayk5A9HJ7sJysl1IXBESlmDthTovsT2+4BrUzz+UuBZKWWHlLITeBa4bCIaqkwMKSWdvjC+UJR2b2iym6MoU46Ukp5gZLKboZxa6oA6KeVbidsPoU02vx94JLHtn2gXdQeRUt4tpVwjpVyTmzttU84qiqKMmpSSdm+IeHxq1YtSpqVmIUQhQOLfllQPUmOuoozOlMu5rEysY+1+th7rpMMX5lCLhx213XT4wnT4wjz7+XMoz86Y7CYqJ8c7gfsTv49kKVAxUNvvdl1imzLN1Xb4eWRrPS8caGFHbRcAJoOOr12+gPeeXoFeJya3gYoyRbx0sJXZOXYyLcbJbopyipBSNgkhaoUQ86WUB9Au/O4FZgHnouV9vAA4NHmtVBRFmVpeP9LGT585yI66LvZ8+zJM6lhVOTH/Rruo+4PEv/+a3OYoyqlBTS7PQLG45Nm9zfzw6f1Utfr6tq8uz2JvY0/f7Sd3NfHx82ZPRhOVkyhRjf5qUuRwlFLKRCGhsb72rcCtAGVlZWNuo3LyvLi/hf97aj/dgQg6IYhLSbHLSnGWlcauIPuaevAEk1cmhKNxvvX4Xh7ZVs9Nq0tYXOxkVZnKgqLMXLUdfl7c38LSC510ByKEIjFiUtLSEyIcizMvz4HTpiadlTH5NPC3xNhcBXwQ7cT2TiGEAQiSGFcVRVFmsnA0zp3PH+TXLx7p2/bEzgauX1Uyia1SphMhxP1oxftyhBB1aGkffwA8KIS4BagB3j55LVSUU4eaXJ6BpJR86Z878ISSJ5iOtHpZWeqi1ROirivA4zsayHOYuWF1CVJKjrb5CEbiLCrKTPPKyhR1ObBVStmcuN0shCiUUjYOsRSonuNVdAFK0CKqkkgp7wbuBlizZo1apzaJGrsD3P74Xp7e08TAFYON3UE213QO+xo767rZWdeNyaDj2hVFzC/IZF6+nfn5DnIdZoRQkSLKzNDuC/Oxc2fT5Y8wOzeDrrhk/XefRfbrW4VOC2VuG1csLeTalcXUdfoJR+M8vqORM+dkU+q2MTfPrvqNkkRKuR1YM2Dzq2i1ERRFUWaE7kCE2x/fy7EOHwsKMqnIyWB9hZs5+XYe2VrPG1Xt7Gvs4XCLN+l5d2+oYmFhJgsKHGp8VYYlpXxXmrsunNCGKMoMoCaXZ6B9jZ5BE8sAXf4I2/xdrKvIoq4rwN7GHr7wzx28WdVOsyfEhoOtGHSCu25ezcWLVFHVaeRdHE+JASNbCvQ0cEe/In6XoKrXT0m/e/kI/9hcS11ngHA0flJeMxyN8+DmuqRtWTYj8/IdnDUnh09dMEcd0CunNLfNREGmmfs31fLv7fW89/QKPnHe7KToqcbuII3dQd462sH//ntP0vPvfe0ooK0IMuoFFy3M58Nnz5rQfVAURVGUqWprTSePbKtDSthUrQVALC91sq+hh3AsfbzK/iYPl9/5CmfPzeHPH1qnjkcVRVGmCFXQbwbKd5ox6tMPxBurO3FnGCl2WSl1W6np8LPhoFYhNRqXPLatfqKaqpwgIUQGcDHHCwWBNql8sRDiEHBR4jZCiDVCiHsApJQdwHeATYmf2xPblCmktsPPq4fbqGr1nbSJ5XQ6/RHeOtrBT549yM+ePYiUKlBdOXVlWg3c9XIV6yvdrKlwk2k18KVLF/DEp8/CYR75dfktNZ28WdXBf3c3cazdP44tHpueYIQ/v1HN7Y/vpcsfnuzmKIqiKDPE2ko3169MTm+xo7abUreNhYWOYZ9/9fIiNbGsKIoyhajI5RnIF4oRGeKKMECHLwJEAOj2R1hUqC092tPQw7P7mvnao7to6QmxotTJjatLKXBaJqDlymhJKX1A9oBt7aRYCiSl3Ax8uN/te4F7x7uNytj95qXDvHKobcLf9+8ba7luVQmVOargp3JqctlM3HJWJRajnjl5DmJxSacvzOKiTH5z8yq+8dhuakYxWbylppOeYGQcWzx6rx5updydwbZjXSwsdHCw2csbR9qJS8lnLpyLThVMUhRFUcaJ3Wygpt03aPuRRD2g+fkODjR70j4/NM5BFYqiKMrojChyWQhRLYTYJYTYLoTYnNjmFkI8K4Q4lPg3ZfUnIcT7E485JIR4/8lsvDI2rZ4gc/O0PKrujOELEvUEo+xt9JBh0q5FhKNx/v7WMZ7b18yPnznI4zsaqG7z0ekL0+oJqYhG5ZTQ0hOksTuALxSdkv+nd9Z1seHgxE4s52ea+dKl83nu8+eoiWXllGcx6vt+f2p3E/VdAcKxOP/cXMcd1y4lP9M8otdZW5HFh86s5HCLl4e31I1olcGxdj8X/uQlLr/zFf6zs3HM+3C4xZvy+6s7EGFRQSYvHmhhw8FW7t5QxeEWL3/fWEOh04IKBlMURVHG27pKd9r7ajv9rC5PX1z6v7sbCUZi49EsRVEUZQxGE7l8vpSy/0zGbcDzUsofCCFuS9z+Sv8nCCHcaBU51wAS2CKE+LeUcvjKUsq4CUclDV0BfOEYVqOOZcVO2v1h6jsDGPUCKbX0FwN1+MMsL3Gyo647afvvNhzhjv/uA0BKOG9+Lv/vwrmsKkt/QKAoU9Vf3qzh7g1HqO0I9G2zGHV88ZL5fOjMyikTzfejpw9Q3xUY/oEngU7AT96+nKuWFWHUq2xKysyztiKL5/e38Ny+ZopcVr7yyE6ae0Ijeu6m6s6+fJJWox5/OMq/tjdQ6LJy3coi1lVmY++XaiMQjmEyCO64bilbajrp8IcJhGNYTfp0b5HSjtouPv/gdi5amE9cSvIzLTitRrYe62RevoN3ri1FrxN0+sPEJXzt0V0IoRUzrOsMUOq2jer9FEVRFGU0HBYjJr2OcCz5oqvTamROnp2mrgCrylxsPdaFzagjEpNEEueorx1u54wfvMA/bj2NufnDp9FQFEVRxteJpMW4Bjgv8ft9wEsMmFwGLgWe7c3VKoR4FriM5OJiygRq84b4ysM7KXBaONLqIxCJs7O+G4dZT7HLQocvzJw8O53+CO3eMNF4vC+FRiwuMRsHn9y2eZPzNL56qI3vXrtk0OO8oSgbj7ZzwQJVDFCZOkLRGA9tqSPfYWFlmYvz5uXy46cPJD0mGInz3f/s44X9Lfz4puUUuayT1NrjKrIzJiwlRp7DwgUL8tXEsjJjPbGzkTufP4SUEneGacyvU5GTwXee2KedSNd08viOBgw6wdvXlnLuvFzeONLO/RuPEYrGeff6Mu64bumY3ufVQ21kmPVkZ5j53YYqAIx6gctmotWjTYrrhOBnzx0kLkEIuPXsWZwxJwdfKMofXj3KN69aNGUupimKoiinno+fNxujXnD3hipa+sYmcFmNbKnRLsrWdwfJzzTjDUZZXuakwxumttNPJCbp8IV5dFs9X75swWTuhqIoisLIJ5cl8IwQQgK/k1LeDeRLKXvXajYBqWYMi4HafrfrEtuUCSal5IX9zfx9Y23KaEdPKIYnpC0tqm734wlGyXeYsRj15Gaa6fSFyc4wE47EKHFZiSMJhuMUZ1kw6XUIIegORAiEY9R1BXjpQCs3n1ae9B433vU6y0qcanJZmVK8wSi5djN7G3v4xmO78Yej9ASjKR/7+pF2Lv35Bm49exbvOa38hCaZTpTNPLooxrFaWJjJwgIHm452cNEi1XenEiFENeABYkBUSrmm331fAH4M5A5YdaSMwc2nlXPF0kItNcxDO3liZ8OYXmdfY8+gbdG45O9vHePvbx1L2u5N8z2UjpSS+zfW8sCmY1S3+XDajEkrMCIx2TexDPCTZw5wxuxsFhRmYtTr+nJMA1y0MF9NLCuKoijj7sNnz8KZmEx+clcjc/Ls1HYm1zToXSm0uboTm0nPT25azp6GHsKxOO87vWISWq0oiqIMNNLJ5bOklPVCiDzgWSHE/v53SillYuJ5TIQQtwK3ApSVlY31ZZQBgpEY+xp72FnXzX93N/JmVQcA8/PteIJRGrqDKZ/nSZzQNidOQms6tAH+SKuP8mwb9V0Bev/YHQOqy7tsRlaWuejwhfjl84eYnWenuSfIiwda2d/k4YNnVpz8HVWUE5BtN3PJ4gLOnZ9LhtnAvsYentvXTJc/dfEtTzDKT549yOM7G7j9miWsq3CP+yRMLC7ZXN3Ba0faMekFVa0+HtlWP67ved78XNZVusnJMHPm3ByKp0C0tpLSwJRVCCFKgUuAY6mfovQnpSQQjmEzpz8kMhl0FDgtBCMxGroCnDE7hxf2t4xLe2wmPe89rZz3nl6e9jFP7mqktsOPXieo6wxQ16n9/vSe5r7HpLtI1v/+p/Y089y+Fq5fVUynP0y7N8z+Jg89gTCd/gj/78K5asWCoiiKMq5uWFVCscvKttouDHpBqyec9rH+cIwndjbym/eswqDGJ0VRlCljRJPLUsr6xL8tQohHgXVAsxCiUErZKIQoBFKdZdVzPHUGQAla+oyBr383cDfAmjVrpl7lrGniULOH/+xqZOuxLjp8IQ40efpSWvR3oNmL1agjz2HuW4I0UgIY6g/U5Y+w7VgXR9t8eAIRBr79EzsbecdadQFBmXrMBj23nFUJaBdmfr+hihcOtLDtWFfKxx9s9vLOu9/kD+9fw4pSF1aTHptp+K/Up3Y38T//2o3LamRpiZMbVpWwujwrqXhYf8FIjEt+toFjHf6U94+Xlw608tKBVjJMev75sTPU5PL08jPgy8C/Jrsh04EQYsiJ5f4sRj3fv34peQ4LN9z1OntTRCKPVZ7DzA9uWMqSIid5mZaUj+nyh3lqdxO3PbJr0H36MV7kisYlD26u47XD7Ukrm65ZXsTN97zFVy5fQKHTQqFTfQcoiqIoJ1e7N8R77nmL/U2evm2pavz098zeZo60+phfoHItK4qiTBXDnk0JITIAnZTSk/j9EuB24N/A+4EfJP5NdRL7NHCHEKK3stslwFdPRsOnqzZviKbuIEuKnX3bahOTRsUu66gjIL2hKP/cXMuTuxr7CgaNRDQmmZNrJ9dhwhuMciyxdFYISFHLj0yrAZNel3YCbKD8TEvKyM+3qjpY+q2nWVvh5mtXLGROnn3EbVaUiWIx6vn0hXP56Lmz+6L+/7OzIWUk4If/vBmZyFlamZPBrBw7wUiMPIeZ95xWTlWrl03VHRxu8dLhC1PdrvX3Vk+IQy1eHtlaj1EvKM2yUeK2UZFt47LFBZwxJ4cWT5CX9rdO+MRyryXFmfzinSuZlav66RQ1KGWVEOIaoF5KuUOI9OOJWjE0di/sb+H7T+4fVIDoRHX5Izy5qwmjXscfX69ma00n4Vicb71tMbNyM/jTa9Xsqu/mmb3NKZ8fSzV4j8LAlFm+UJRbzqqkoSvAQ1vqWFyUybvWlql0GYqiKMpJYzLokiaWQYtO1qU5J+11tM1LoctCpsU4zi1UFEVRRmIkoTr5wKOJk1QD8Hcp5VNCiE3Ag0KIW4Aa4O0AQog1wMeklB+WUnYIIb4DbEq81u29xf1mKpNBx0Nb6nj3799kYSLP4auHtRXND9x6GqfNyh7V693++B4e3Fw36nYIAfube+jwRfraFY7GMegEiwsysRh1NHYFcdoMZJiMbKzuQCegPDtj2NdeW5HFjtqulPeFY3HCsTgv7G9hw8FWsu0mfnzjcs6am8NQEyGKMhlMBh3XrCjmmhXFfOGSeRxt8/HKwVZ++3JV38SSTBz4SglVrT6qWn19zx9p6opITFLV5qOqzccG4M9v1HD+/FxeOdRG9AQnjMbqiqUF/OwdKzAbJia3szImqVJWfQ3tQu6Q1Iqh0dlS04FBp2N5qYsPnFGB3WzgcIuXxu4gwWiMvQ3d1HWmTjU1UtF4nCMtHr7/5P6kiOi3/+4N4lKyujyLrTVdJ7gnI7flWCdzCxzc93o1LquRN460c+bsHCpyhj8OUBRFUZSR8IaiGPUiabXtoRYv7gwTpVnWpAjmimwbuQ4zEnh4ax0/evoAj3ziTJxWNcGsTK5YXOINRnHa1P9FZeYadnJZSlkFLE+xvR24MMX2zcCH+92+F7j3xJp56si0GMkw6+kJRnnr6PF59jK3jeUlrlG9Vm2Hn8e2HS8qZDPp8YdjI3puOCbJsZv7JpfDUW2iLBKT7KrXBnGdgLqu48+JSzCMIGIpFIkTTpGOoz+LQYc7w4TbbuJzD27nE+fPwWkxcqDZg0mv472nl5GfaSUYiVHXGWB2boaafFYmVY7dTI7dzNoKNx84s5JAJEYsJjnQ7KGm3Udth59XDrVR1xXo608n4sUDrSeh1WO3t6GHaEwywmwByiRIkbLqXKAS6I1aLgG2CiHWSSmbJq+lU1MwEqPLH8Fm0iMlaU8Ittd2ccNdbwBaNH95dgZd/jDVbf6+aN/KnAy+cPE8fvLswTG3Z1aunW21g5cBhxLfJ711EyZKIByjqSvAX29Zx8qyLDUGK4oyYwkhLMAGwIx2/vyQlPJ/hRCVwANANrAFeK+UMn3CYCVJMBLjdy9XpYxQ7vCFsZsNrChxsT1xQhqJyUErda+48xWWFjv56LmzWFmWNfiFFGUC6AQ0dgcQOlQ0vTJjqWmDSXD9qhJ++3JV0hLWYx1+Pvinjdz1ntXUdvopdFrJdZiHfJ1Cp4Uf3bSMLTUdHGz2sru+myXFWjS0DsHexh4CkeOTzavLswhFY1iNeqJxSXSYCeDRBkz2XnV2WAyUu219hQBTCUa1CObd9Vp01oObarEnZrE213Ry76tVrJ+VzaEWL3WdAcqzbTitRj51/hwuWVwwuoYpyknmzjD1/V6WbUu6r6rVy8Nb63hsW8OgZebTSXW7n+/+Zy/fv37ZZDdFSSFdyiopZV6/x1QDawYW/Jsp4olB7HCrlzZviDl5dqSEwy0eSlw2fJEoLT0hjHodnf4wc/McFGdZ8YeiSTmPv//kvr7fd9f39I1b/R1t8/HvHQ3cek4l/9re0FfZvj+3zURJlpXdDd0px9cWT5C1FVnsb/TgCQ1djG8iBKNxHt3ewL93NrKy1MXcfAdmg47/fdsiNdGsKMpMEwIukFJ6hRBG4FUhxH+BzwM/k1I+IIT4LXALcNdkNnS6iMTifOGfO/jPzsa0j6nvCpBlM7Ks2MnO+m5kiso/9V0B6rsCvHKolV+9exVnzMlWq+6UCReIxLjszlfQCfj0BXP5zIVzVRoxZcZRk8uTYHaunec+fy7vuvtNmnqOL6PdXN3J5x7czkuJiMX8TDMZJgMOiwGbyUBlbgYXLsgjLuFgs4cndjayr7EHh8WAXifwhmJJJ71rK7I42Oxlfr6DrkCYHbWd9A+oXF/pHlW711e6k6Ktey0osGMzGTjW4ScUifPm0Q5iccmyYidxKWn3hejyRwhEjr/56vIsttQcv/LcP9dWdoaJdl+YrkCEuk5tcq4mkaf2C//cweP5DrUsV5myZuXa+dKlC7jlrFlc9vMNoy6aOZXcv7GWRUVOrlxamDShrkwJKVNWTW6TJpeUkobuIPkOM55glFA0jstq4Fi7n7tePsL+xh58YS0fepc/Mihn8oICBw9+7HTyMi10+yPodGA3G+gJDq4fkMqhFi9N3UHesbaUe149CkC+w4zLZsRpM3G0zcfBFg/z8h2D8ksC9ASibKruxGHWo9eJE86hfLLE4pLNNZ1srulErxN8+oI5ZNuHvvitKIpyKpFSSsCbuGlM/EjgAuDdie33Ad9CTS6PyJFW75ATy0a9YHmJix21XUTiktNmuQmEYzR0pU5B5QvH+OCfNlHmtnHfh9ZRqc4VlQkkEOQ6zLR6Qtz5/CEe2VbH4kJtLqTLH2Fuvh2DTnDb5QuxmtTFD+XUpCaXJ0llTgY/vmk5H/rTpr4T3GhcsqWmk7UVWTR1B6ntDKBdKNe8UdXO3986Nui1PMEo6yrdbBww8bupuhOzQbCxevCEcKHTTFxK8hxmDHpBodNKqydEdyCCPxxNynvVq/fxAyfLpNROqj0Dip3trD++vLfIaaHAqMdi1KEXgn2NgyO/QFtS0nuVL9XFPk8wyjvvfpPHPnkmR9t8dPrDXLwoH6NeB2jLq0ZadFBRxpM7w8Q971+DTgje/rs3RpyyZqr5n8d28z+P7cadYWJOrp3ZeRnMzrVz7rxc5uarKt2TJV3KqgGPqZiY1kwN1e1+Ov1hCjMtZCUuhhxs9vC5B7cnjU/pLvjsb/Jw1S9e5R8fPY0P37eZDl+Ym1aXcMOqEh7dVs+ehtTjVn+eUJS/vlXD6bOyKcmyUt3uS1rCazXqaR3igtOCAgdOqzHlhdyJ5rIZBxXmjcUlrxxq49qVxZPUKkVRlMkhhNCjpb6YA/waOAJ0SSl7B5g6IOWXoyqim+xHT+/n8R2NrK90oxeCqJR0+cMcbPaiE9qsfZHTytZjncSlFuD0ZlUHJVlWKrJtfcWxBzIZdHztigVqYlmZcFaTns9cOJdvPLYbgNqOALUdx1ew9s7H7Gno4Q8fWKvyhCunJDW5PImWljiJyeRJXE9Qi1xaU56VmFwemYY0y+9D0cGTxHaTnrn5DjYf7UCXiHjufxXYbtazrMSBTgg6/WH0QocQEIlKFhQ4kk7MdQL0OkEwMvTEWUP38dd3mA1pJ9riEsqzbbR5QmnTdjT1BDnvxy+iFwJfOMblSwrIzjCh1wke3VbPabOy+dbViylyWYdsk6KMt2WJPOpvfPVCHt1ax6Pb6pMKk0wnHb4wG30dfQdHP3zqALdfs5h3rlMnScrUUJmTQSXHTyg7fWFuuOv1QRc+h/KRc2bhspr424fXs/q7z/GLFw6zotRJKDryi0PBSJw3qtoBWFfpxmrSEwjHcGeY6PCFKXRacGeYONTi7XtOmdtKQaaVA82elFHNE8lq0rOkKBNvKMq8PEdfnxdCu5j84OZarlpWiCFxUVdRFGUmkFLGgBVCCBfwKLBgFM9VRXQTdtd38+sXjwBaWkiHxYAvFEUAy0ucHGnxYjLo+9Ir6oRWBwTAaTXiD8dYU57VN/Hc39cuX8BlSwoncncUpc8715by3L7mvlXoqWyu6eT3G6r44qXzJ7BlyomKx6VKczICanJ5EtnNBk6flc2rh5PTYdpNekaTztBu1hONxwdV2k1lTm4GR9p8bDjYhlEvKM+ykZ1hwheOEozEqevwk2k1EgjHiUvJ4RZf0vOtJj2zczM40qpttxn1xCXDvm9/nlCUJUWZ7E4TBba7rhuLUY8nGKUky9qXGqO/YL8UGx2+MK2eEP5wjJ5glFcOtfL+P25ExrX8R+4ME2sr3Fy4MI8VpS4yZkiFssTB7z3AErQggA8BnwV6RzMXWsTFihTPrQY8QAyISinXjHd7T2VOq5F9jZ6UeVinq3Aszm2P7GJ3QzffvGoxJoOaaFKmlnZfeFQTy6BF6t/zShUmva4vLYUnGO0b80Zr49EO7GY9c/IyONrqo9xtw24xcKjZw+zcDLIzzLT7grgzzOxr7DmhXMt5iToNJ5KKZ12FdmG7N9paoEUwm/U6ugJhlpa4eP1IO9tru1hTMbrUWoqiKKcCKWWXEOJF4HTAJYQwJKKXS4D6yW3d1Cal5MfPHEja5g/HWFWWRSQep9sfwRuOQb8gpLgEh9WAJxTtW0F0tM2XMl3j25YXjf9OnGTba7soyLRQ4LTgC0W5e0MV+xp7+N51S4etv6RMLQa9jt/evJpP/m0rz+9vSfu4X714mKUlTi5VdaSIxSV7Grpp6ApiNxuIxOKYDTrm5NmT6p9Mtv97aj9fvmwBejXBPKSZMcs2jpq6g3hDEebkjX55uICkgnsAJVlWuvyRQZVwi10W/OEYwUiMQCROSZaVgkwLVW0+PMEItjgsKsrEO8xJcIbZwJryLDZVdxKJSQ63eDmMFpF01pxsCjLNhKOSqjYvZW7boOcHwjGq2nysLHNR2+GjINOadpI4nTXlWextSB+9uazUyabqTqrafBh0UOKyUuC0sLmmc9BjXTYj3YEIh1q8xOISk0FHIBLnWLufUCLBdH1XgF313Wyu6eDhj58xqrZOc3cCT0kpbxRCmACblPIdvXcKIX4CDBVGe/5MLQQ2Hl4+2JqUY/1U8dc3j/Hi/lZuWlPCdSuLKc9WSxGVqWF2bgYvf+k8/OEYv3v5CK8faR/RxGvNgOW2Y51Y7uUNxfou1NZ0+KHj+Ov2vvaRVj/Lip3Udfnp8I0sx3OvIpeFEpetL8K4IttGfqaFfY09hGPxpIuxqczNs2sXc91WNlV3JpVLktCXGmNtRRYHmjysKc/itSNtanJZUcao3RtSecunGSFELhBJTCxbgYuB/wNeBG4EHgDeD/xr8lo5tXmCEX7z0pFBUZ29ef1BG48GEkIriDsw1/Lm6g6WFmfS4Y/Q1B3k+pXF06pfhaIx/uex3Ty4uQ6TXsfCQgdmo56NRzuYm2fn8R0NfOisyslupjJKFqOe3753Nd95Yi9/fqMm5WPWlGfx0oFWzp2XO6XSeb5xpJ2mngDXrSyZsPf81r/38Jc3B39OJr2O37xnFXsaevjMRXMnrD3pLC5ypkzZqiRTk8tj8OsXD/P4jgZ84SidvghCwLUrivnk+XMocI78CosQYDEmR/u5bSbyMy3E4nEEgq5AhFZPiPquIBajjmAkTq7dTF1nICmit8UTosUTQie0Zbg7ajsJRSVGnWBWrp1AJEqB08LGo50Uu6zoBfQPNpYSdELQE4wQisYJhGOY00QiSgnbjnWxvMQ5piX+OgH+IU52g5E4vdlConGo6woggXUVbtq8Iarajp/od/kjCGB+vlZUsPfgJBRNfv1z5uXyzasW9eVmPtUJIZzAOcAHAKSUYSDc734BvB2tEIkyAa5ZUcTvNlRNdjPGRX1XgJ8/d4ifP3eILd+4aFod3CunLiEE5dkZNHQFeGJnI9ExFshbUGDHpNfT3BOkxRNKUav+5NhZ343FoGNVmYtWTyhlaiyrUc+S4kw6/WHcGWa6/WEONHuTTrqr2/1J+Shz7CYqcjLo8IbpCUaIxCRmg44ip5VIPN4XCTbcxa9N1Z1kmPRsrunEaTUipUSMZpmVoigABKNDX/A5EZuqO6jt8JNlMxGMxDh7Xi6P72jg4S11uBMrFc+dl8vlSwopTRFEoqRVCNyXyLusAx6UUj4hhNgLPCCE+C6wDfjDZDZyqnqrqp1b/7KF7sDQF08PtXgpd9v6UmIArC13E4sP7jMxCbsShextRh1H23w8vqOBZSXOKR3osKehm83VnTy6rZ7ttV2Athqw/zn1oRYv/9xSx7vXl02pyUdlZIx6Hd++ejHRuOT+jcfonwXVYdZzrMPP5ppOnt/XzCOfOIOSrKnxXdzpD/O3N49N6OTyw1vrUm4Px+L88On93P+R0yasLUOZl29Xx7wjoCaXB5BS8kZVO+FonKNtPnbWddMdiPC25YXc9dIRzp6by3P7mgdFNv3lzRp21nfzi3eu6BvQuv0R9jf1YDZq+QsbugP87a1jVGRn8K51ZcTiktsuW8AdT+5nY3UHsbhMKoK3tDiTo/0mUnujj1q96SOv4hK21HSyvjILX6Ki7oFmLX/jsURS+RZPkEJXcrqJdZVuXj7Yhk6Ay2rEZTPS4QunfI9eBr0OAUkn2u4ME3Py7ATCMSxG3aAI7NXlWYkiDWYaulPvhy/FsuD6rgD1ibzSS4oyATjQ7CESk3T6I3T6Iywtzhz0PKNe8LFzZ/OZC+fOtPyQlUAr8EchxHK0AiSfkVL2/oc6G2iWUh5K83wJPCOEkMDvErnilDFq6Qny7L7myW7GuLt4Ub6aWFamnO21XWOeWAbY3+Rldm4GXYEIWRkmZuVkoNeJcSm6F4zG2XqsC52AZcVarucsm4lOfxiH1Ug0Jtle25VIRTWyiOo2b5g27/HxXCvUFx5T+gxfYqny25YXqYPsGSoai7OxuoP8TAs7arto84Y40OTltFluLllUQLsvxO9ermJtpZvKHBtN3SGuXKZyoPZXPI41QTZXd/J/T+3vu20y6AgPmMx+40g7Vy4rIhqLz7Rj4zGTUu4EVqbYXgWsm/gWTR/haJwfP3Ng2InlXt5QlAUFdvY3aXUJ9jR0U+gaupCfPxJnc00nm2s6MRl0vGttKV+5fAE209Sa6jjW7ucDf9w0ZGHfXhXZNu54ch9Lip1cuqgAp00VgJtOhBDccd1Sbrt8Ad/+996+SVR3hpnaTu3/cYsnxOV3vsLNp5Xz6QvmTPr/13Pm5aZcPTBeorH4oFX8oNXz+tCZFaypcOMPx8iesBZp3jjSzvJSZ9LfY0Hh4HkmZbCp9Y07iZ7Z08Qrh9r4x+baQQdhAC8k8uY09wRxWFJ/ue+o7eIzD2znu9cu4WCzh58+e5C6zgAWo44VpS621nRy/oI8/vRaNb97+Qht3jDz8u1sPdYFgMNiSMoPmSrK1p1hRK/TDTkoxeKSXXU9lGVbUz4uEpM09wRZUpzJ7voeZudmUNWqDeBxCR3+CIucVvY2Dp3uot0bYnFRJjoh6PCHyXWYOdTsZWPihNtm0rO+0k1tpx+DTtAdiNDlD3Ok1Uexy8rq8iy2H+tMiqDWC1J+/v31puEwGwTFLisOi56G7iBmw+Aru9evLOELl8zIhPkGYBXwaSnlW0KIO4HbgP9J3P8u4P4hnn+WlLJeCJEHPCuE2C+l3DDwQar69cgY9Dq+evlCfKEoj+9oGDIP13Q0N8/Oly6dz8WL8ie7KYoyyMmYyDnS6mNRYSZ2s4FAJIbVOL4TMnFJ0sXmBQUOuv0RXDYja8qz2FHbNeQKoKH0prkYq+WlLi5SfX3G6gpE0AnB5x/cwY5E1J1OwCPb6rjtkV2YDTr84Rj/2FwLaEtbD7V4uHBBPktLnJPY8pnhhtXFSZPLqY6p4xLO/MEL5DnMzMt3sLo8i89dPG9Erx+LSzYcauVAkwcpYVWZi2hcEgjHWFvhVhNgM9z22i5Ks6x9gQa9OZYHBhsNpd0XZk6enbUVWQghkFKyqbqTZcUj+/4IR+Pc90YN22u7+O61S0/6986xdj/P7Wvm/AV5VOaMPEL69SNtfOCPm4Y9z52Vk0Ftp5//7m7q21Z3gZ/Pz8zz2Wkv02LkjuuXsK+xh72NPdR0+Cl1W6lNBP15glHueukIT+9p4ufvWNFXDH68DFWYzm42MDd/9Klex6qhK5gU1d0rFpdsrO7kwoX543oxNp2VZa5Bq+CVkZmxk8ueYIQuf4RSt41gJMZn/7Edf7/iAb1V0QfqDkQpc2ekLDIH2qB67a9fS4qSCkbivFmlTbjub/QQisb7rrwebvWyvtKNNxRhT4OHxUUOhBCEI1pajLUVWYB2MK8XgqNtXipz7OiFoKknyLx8O1k2E+2+MIf7VZ73hKIcbPZiN+vxhgZfEYrEJF3+CMtKnHT5I0lRTQA28/BLcLoCkaQryAM/E3841hfZ5bIZCUXiffkleyORnVYjc/Ps7Gvoxm03k59pQQgocFqSDkSMOkEkLnFnmCjJsrKzrpu41AoYNXQHyM4wp8zJfM2K6VfY4SSpA+qklG8lbj+ENrmMEMIAXA+sTvdkKWV94t8WIcSjaFEZgyaXVfXrkXFnmLh4UT51nX62pPh/Ol05zAb+9+rFXLeyWBU4UKasdOP1aA13wXU87W/SViCtrcjizaMd5NjNzM230BOMJq1wGk+LCjO5/ZrFrC7PUlHLM5SUkjeOtPPC/hbMBh3l2TbOmJ3NDatKeGJnI0uLnXz9sV0YdIIFhQ6OtPgIRGL8/LlD3PvqUZ749NmUZU+N5b+nqjyHhV+8ayVffHAH4djQJ8e9KfUKnJYRpbnZ09DNr144zPP7Wsh3mllfmU2ew8zCwkzWVthVYd8Z7uk9TXz0L1u4YEEeq8uzeG5fM3WdgRFF6Q5U2+mn3RsmFI2zpDiTc+fl8Nrh9lG9xo66bt72q1fJsZu5YXUxVy4tPCkTdx/96xb2NfZgMeqHnVz+1/Z6atr9bK/tYnN1x6CJZb1OYNAJFhVmEo7FaewKYDKIxOokzY2rS/jIObNOuN3K5DEb9Pz4puVc++vXCMe09KMDVbX6uObXr/Gzt6/g2pXFJ70Njd0BcuxmWj0hikYwYRuOxsf1O73NG+KpPY1p79/b0M3rR9o5bdZExy1rebNVOpqxmbGTyw6LsS8CWScE58/Pw2zQ9Q0Sz+1rTplPWMCwybyHWn7rzjAl5ZHqCUSTlta2eoZfqhqNxylz28i2m/pyJa4pz0p6TGmWlSKXdchlu715m9dXujnW4SfLZiQUjeOyGlNGNs3Ns+POMAHaF45eB1Vt/mHTZ4AWKVWZk0E0Hu+7UgfQHYiwuaaT9ZVu9jb09OWYzM4wsa5SKxbU2B2gyxch22Kg1ROiwxfGatJj0uvYloiamZ9vGvSeFqOO1RVZg7bPBFLKJiFErRBivpTyAHAhsDdx90XAfillyiRHQogMQCel9CR+vwS4fUIafgqLxOK87Zev0nmCUYNTxdlzc/jhjcsodE78FWVFGamtxzq57eGdk92MEXNYDNjNekqybHQHIpgMOjJMBuJS0tQT7Lvo2uoJ0eoJ4TAbWFXm6lva7gtF+44LTrbKnAxVxG+GE0LwtuVFvG25duG+1RNiT0M3h1u85DrM+MJR7rhuKetnZfPL5w/hD8do84ToCUbpCUb50kM7MBl0GHSCbLuZNeVZvHOdWvV0sr1tWSEPb6nj5YOtwz42x24mO8OEEIJYXCZdKH75YCsv7GtGAu3eMM/sbSI7w8x/P3s2s3Mnbum0MvVVtXr52iO7AG217wsnuEKvfx2B3fU9OMx6ilxWjnWkTosxlDavlqrn9xuqeMfaUlaXu6nt8FOZk8HhFi+XLSlgyQijopt7guxLXGjOtg8+9xzIpNexr7En5edhMuhYUpTJ9tquvvNZgGAkRp7DTKc/jNNq4t3ry9Kumlamni5/mG8/vpevXbGQXMfxVIGLijJ57JNnctUvX2F2rp027+A5Ginhtkd2sq7SPaIJ4NESMOLX7Q5Ektp/sn3mgW1DXjCKxCT3vFLFFUsLWFAwsSkp2rwhclSaxzGZsZPL/ZkMOn79nlUcavZwx5P7KHBa8Idjg9JUgJaINt1SgqEsLc4kLocvmOPOMA07uZxpMfZVhe+1uaaTcreNfKdFq0KdYR5xPkgpJfPy7Rxr92tX0/Q69PrB++i0Gge9Zp7DjE5oS+yGc7TNx5KiTGoZHEX21tEOilwWZuVlsKO2m3ZfmPYB7+Xpl4s5EI4R4PhVv0yrgdm5GdhMevY19hCNwxcvmZ8yVcYM8mngb0IIE1AFfDCx/Z0MSIkhhCgC7pFSXgHkA48mIlgMwN+llE9NWKtPUUa9jm9cuYgv/HPHZDflhBh0gi9dOp+PnD1rTN+FijKRvv343qSxYyqbk5vB4VYfnmCUxjQ1CQbyhKJ9qbUACp0WDDqtGO7J9kZVO5//x3Y+cs4sFqrcc2MmhHAB9wBL0A4rPySlfEMI8Wngk0AM+I+U8suT1UYpJYdbvLxyqI1AJEaRy8L8/EwWFjqSoluPdfj5+qO7+2pi9LKbDQQjsUHBFgOPIbce62TbsS7m5ttZV+ke9+XAJ0PvZ1PVpqXK+fMb1XzwzErcGaaUkU7BSIz9TR7sZu04dSxR/5urO3huXwsHmz24rEbOnpczqOBStz9CQ3cAfzjGhoOtI5pYhsTE24Yq/vbWMcLROGfPzeHd68s4d14uLx1o4b43apIe3+4L8ezeZmafqyaXFU2nL8wNd70+rsETnlCMeQXmMU0u94pLuH9jLfdv1FL2uDNMBMIxfvXiYZ767NkjmsBq84b6gp9iIzj5vXxpId5QlP/ubqLIZSEQjtHpj2DQCRYXZSaN31k2A7NyHTR1B/mfqxZy0cJ8JPDf3U2sKpuZwVLTkcumXRD45QuHuGJpYVLk7aKiTErdNqIpClT2CkbifPQvW/jrh9fhtA5/AWOkRhsMNJ4TywD5Dsuwj/GHY3z5oZ08+NHTJzSS2GUd+cWcTdUd7G/s4b2nV4xfg6YRNbncz9x8Bz97xwqicckDG4/x42cOJt1vNelZWuykxx9hZakTo0GPQMsNFYnGycs04wlG8YSi1HcGWFfp1paZAdv6CvAMrTswdBRwniP9wFrT4aemw49RL7Aa9czNs+MLR5Ou/g7kMBto94X70lUAdAYizMm3k2EyYDLoMBl0WI16mlNMjHuCUdZUuOn2R/oKBw71XkMtr2joClKQOfwXzUBlbltSCo1lxU5m59m55azKUb/WqURKuR1Yk2L7B1JsawCuSPxeBSwf5+bNSDesLsFtN/GdJ/ZS1ToxS9lPJp2Av354/aQsUVKUsajvHPuJ6EQ73OpjXaW7r27BWNhM+nGZWAbo8IV5ZFs9j2yr54ZVJdxx/ZKZfgF3rO4EnpJS3pi4+GsTQpwPXAMsl1KGEvUOJsWxdj/3vnaUp/c04bQaqWrz9S3lLnRaWF/p5vZrl6AXgtXlWbz8pfPY3dDDgaYe9jd52NfYw6bqzhFNvFS1+vrGwmKXldduu2Bc9ikel9R2+tlU3UlJlnXMY5iUkh89fYDN1Z1srO4gO0Mrtrm5ppOddd188ZL5fPy82UnP+eULh/j1i0cAbQn8wkIHOiEIReJ87cqFLChwkJ/m2FdKyZ6GHj734PakVX+PbKsnFofDLV46fCGWFDvZcLCNN6va8YaiFGRayDDp+wpwjoQ3cRHu+f0tPL+/hTK3Lel84wsXz6Ms28ZZc3JU4V4lSV1nAF+KFIwnW7s3xNy8DIpdNvzhKJ3+CIf6pYQcrQ5fmGUlTvY19vC2X77K29eUsrIsi9IsK+vTfEcsLnISjsbZXtvF4RYvm6s7Kc6ycu68XHbWdbGpupO1FVn4QlFaPCGMeh07a7vId5hp6AqiF1r0qAC29dZcMutZWJhJhz+CxajjHx89jZKs4+mDrl4+Y1M8TltrK9ysKc9K+t6u7fBT6rbxpUvn899dTUBX2ufvqu/m+0/u53vXLeXhrXVctDC/b/X4dCel5NuP7+WRbfUjevzOum4e2VrPu9dP3CqnkRS6lVISisT4+F+3cNmSgglo1fQgZKrEwpNozZo1cvPmzRP+vkdavTy0pY7Xj7T3FSgZSAhYUerqGwzSMRsEy0uy+qKLK3My8IejNPcMH4mkE5CXaaGpe/BErt2sZ35B5ohyts7KsVHV5ifDpGdJsTMpWmRxUSYWgw5fOEZLT5COEV5pzrWbsZh0SV+UvWwmPU6rkcYU7QYoclkod2fwRtXQ+bJKs6xkmA19+SWdVgPdgaGjzlaWupKWEwHcclYl/3PVoiGfN9UIIbZIKQdNBk8Xk9V3pyN/OMr/u38bz+2bXoX9Mkx6XvjieWlPhGcq1Xenjh89vZ/qdj8uqxGTQccfX6ue7CaN2rqKLA40e+kOjD4KbF1lFhuPjiyvu0EHs3PtOCxGdDpBtz9CfZc/ZZ2GVMrcNt6zvoxbzqoc0YH4VDMZ/VYI4QS2A7NkvwNwIcSDwN1SyudG+lonu9/+a3s9+5s8zMm1E4zGeG5vM7vqe2jzDj52XVDgoLbDzyOfOJPybBsWo542b4iDzR7WVbjp8IfZdLSTf22vZ19TT8rjxlQ+ft5sBPD6kXb+9MG1uGwndjL9j03H+MubNRxo8vQFeAgB71hTyh3XLR1y9U2HL8yPnj7AgaYeugIR7cJNTGLU69hV383q8iyq23y090sNV+yyotPBA7ee3leE6O4NR7jjyf3p3gaTXsflSwv437ctHjR58Pe3jvG1R3eNeH+tRj2ByPhM8mWY9Fy+tJDPXDgXh8WAy2airtPPC/tbyLKZuGpZ4YTlYldj7tTT4gny0v5WvjyOaaiWFTvpDkaoSdT70Qkt6KppBOfXqViNOubmO9hd3520AtdlM5JhMjAv387blhfR2B3k6uVF9AQjRGKSnz57gJwMM0/taSIak4RjcRYVZo6pLsOcPDveUJSm7iDfvnoR7z/j1A2Mmun9tn+qBSklz+xt5tv/3kNDmrmTOXl2BNpFyWhc8t7Tymj3hie8sGObN0QwEku64HEipJSc+YMX0u73QMtKnDz2iTOn1GpZKSV3PLmPW86axauH2zh3Xu64R3pPptH0XRW5nDA7185XLltAPC755QuH+dlzWtSySa9DCAhF40gJu+u7ybGbKHJZ2d/YQzhFNHIoKpPSVhxt85HnMJPrMA9Z1CDPYdbyKqbpbLNz7dS0jyzaMcOshfP7EkX1ytxWcuxmmnuCGPWCLcNMkKeSbTclHUT35w/HyM4wsbo8qy8ntUGnIxKLE47F2VnXTUNXkDXlWexr7EkbTVHbGSDHbuK8eTl0+CPsrNMO4A06gUSLQstzWPomk9NFefWM4aRcUSZKuzfMvsahI/2nIl84xmU/38B3r13KlcsKJ7s5ipKkxRPk0a31Iz5gHSmHxaCNn90B/JHxrx69uaaTMrdt1JPLRr0gEo1T7rZSM4LJvGKXjQPNyVFfuQ4zc/PsbKsdXHNioGMdfr7/3/2sn5XNilLXqNo6g1UCrcAfhRDLgS3AZ4B5wNlCiO8BQeCLUspNE9mwN6va+5aLg3bxYGGhAykdvHakLanI9f4mD2VuG7c/sQdvMMoHzqxgc3Unf3vrGOfOy+X2axZz5bJCrCYdX/rnyCeb7nrpCIVOC53+MLc9vAudDiwGPZ+/ZN6YTmzbfWF21ydP+EgJD2yqJRSN85Oblqc9YfUGozy1uzHtUv8tNZ0UuyyYDLq+yO7e9CDH2v0Uu6z8a3s97zu9ggc31yUV3e4vHIvzr+0NtHvD/M9Vi7Aa9TR2B8gwG7jz+YMpn5POeE0sgzb+P7Sljoe2aOU6BqYOjMbjg1J1KDNHnsNCZe7Qxe3Gak6eHSklO+uTxyWLUU+7d/i6P+kEInEEg1M7dvkjdPkj1HcFePGAll7mR08fAKAi28aliwv40qXzecfaUv67u4kndjaSn2lmb4raZAYdZCTSBIWiyW+UYdLT4Qv31S7KHMVSfGX66Z/DVwjBpYsLWFrs5OKfvpxyXiQ7w5QUHLjtWDdnzZnYlaPxuOSTf9vKxYvy+fDZJ6eo5DN7m0d1nL6zrpvHttdz/arxH1+auoOYDTqyhokS//eOBh7ZWs+t58zmxtVq3OtvxJPLQgg9sBmol1JeJYR4BXAk7s4DNkopr03xvBjQe9n9mJTy6hNr8vjS6QTvO72cFw+0sKQ4k/eeVoHdYuDeV4/yxpF2GroDuDNMGHQi5cRyOi2eEGsqsgZNLmdnmCjPtnGoxcucPDuvH9Eie406QaTfaGc16vCGorSNcBD1DcgxeawjwLHEyeZwHSYdg14MOTle2xnoK8gHsK7CzeYBUdabazqZk2dPe5BtN2mVd18+dPxEZmCkdn1XkEKnhcocG0fTpBY4WV+AijIeajv9g3JUThed/gif/PtWDjbP5XMXz5vs5ihKn0yLketWFVPd5qeu048/HEu7ZHZlmQuDTiSlVOpPL7RoCaNBz8ajHXiCUdZWZPU93mUzkucw47Qa077GWBl0YlBF+ZGIxCTbartZX+ke0eRygdOSVGAYtAJt4Wic9ZXuEdVtWF2eRbn75ESzzBAGYBXwaSnlW0KIO4HbEtvdwGnAWuBBIURSdDOAEOJW4FaAsrKTt0Q0FI3x4bNncctZlfxrewN/er2aYx3+IfObNnYHONbhZ0lxJne9dKRv+8sHW/nrmzW8UdXOFy6ez2cvnsf/PLZ7xG1p7A6yssxFTYefTIuBs+bksPVY15gml997Wjn3vlqdMvr60W31FLksfP7i+UlF7AB6ghG+8a/dw+aQtZsNKaMmP/X3rczOs1ORbcOk1/H0Z8/h8js3UN8ZSBtc8erhNq799WtcsDCP/+xsxGk1jmn1wngqdln7Cmob9QKDXodOaInD73u9Rk0uz3A2kx5DIsryZFlX6Wbbsc6UqSWXDliZOxa1nYFRrfjJtBo5a24OBr2O9bOyWVfp5hPnz+bhLfV4Q1FqOwO4bSbsFgORaJyaDq3wfZnb2nceDlDoNFPotCblXJ6b50jxjsqpQErJK4faiMTiXLgwv297kcvKTWtK+dPr1UmPr8i2Dar79dj2ep7c1UhTTxC9TrC81MUZs3PGtd13Pn+It452UN3u48KF+VTmDH0B6Z+ba/nPrkZCkTjvXl/GFUsL0esE9V0BdtZ20eIJjTgdRn+ff3AHO+u6+cplC7Caxicd24EmD7fct4nrV5Xw+WHObzccbKPdF+ZQs4dn9jaxu76H71+/dFzaNd2MJnL5M8A+IBNASnl27x1CiIeBf6V5XkBKuWKsDZwMWRkmHvvkmUnbelMsxOOSNl+I7z+5n4WFmTyxs5E5efYRpapo6AxgNugoclmwGg3YTHo213T2RQNH43GsJj1Wo47uQJQyt41suwkpodUbwmk1srosi32N3WmjpwoyLZTn2Ng3RLX4hk7twL25O0g4Fh92wjrfYcZhNQ6K/hhOPE3KFZNekOcwJxUu7C0KWJxlHdGJutmg4/UjHZS6rSwuymRPv/11mA3DfvkpymSIxyUvH2zl588fmuymjJhOaD8D57p+8cIh4lLy2YvmDToxV5TJYDHq+dKlC/pudwcirPvec4T6/efVC1hZlkWHL0xNh5+lxZlYjQb84Si7+40jMamtWAr0G2sPt3hZUpRJXErqu4J0ByIjKmY7WuGYRCfEoJynIzXSfO417T7sJj1mo55Cl4XWnhAZZgO5DvOIJ7Xes75szBesZ6g6oE5K+Vbi9kNok8t1wCOJyeSNQog4kIMW5dxHSnk3cDdoS3RPVqO+/+R+/vR6NRajLpHupJxDzR56ghHqOgPodQJvKEpXv8nW3smegceG8/MdvHKojf1NHn78zAHKs0c/Kdw//dxbRztYUODgqqWFo14W67AYeeDW9Vz5i1eTvgd6/frFI7xV1cHsXDvnzMvtW5GTaTHyxw+s5V2/fzNtDvRlxU7MRl3K3NK9Rak3Hu3gwc11fOK82Txw6+mEo3Euv3ND2knrQCTGf3Zq4Y9TYWLZqBcUOC24bSYkWgRZKusr3fzgJnViPdMtLnLy+lcv4DcvHhk0WTZWbd4QkZhMKh5v1AtWlWXRcIJBGgsKHPQEI2yt6Rrxcww6wfvu3cjtVy/miqWFZNvN5DksOK1GtifqK6VagdzQFWR1WRZbjnViMeiIxbXz5JVlLkx6Hesq3Swpdp7Q/ihTlxCCmnYf3/3PPv5yy/q+opAAly4uGNRfcuzmQQF6oK10+fEzB3nvaWWsq8ymvitAkdNCXGrpM6SU1HUGKD0JF/2llH2FYZt7Qtxw1+vc8/41aYtL1ncF+Oa/9vStoHmjqp3vPLGX02dn8/LBVopd1qT5mtH60+vVvHighQduPS1tccJAOMZH/ryZ/EwL7zu9nOUjXFW3vbaLD/1pE5FYnI+cPXRqmnhc8uSuRsqzbXQFInz90d1UjOE451Q1osllIUQJcCXwPeDzA+7LBC4APnjSWzcF6XSCPIeFn71jBQD/78K5fPaB7ZS5bSwpzmRVWRZP7W5K+YVQmm2joTvI0bbUJ4tbazpZXe6mut1HLC4HRY3UJ6KClxY7icbj2M3aCTFoX1oWg56qNh9vVWkHwusq3URi8UE5ojv8YTqOhSl2WYjFJU6rgWhMMq/AgUmvwx+O0tgd7Jt0bvaEyHdqOVaNejGiwoQLChxpJ9z3NnowGbQTmAKnGSm1tBrt3uTCgkM51uHHYtDyP6+vTP6C8YSiPLevmSuWqmX7ytTy391NfPLvWye7GSNWmZOBzaRnX2MPRU4L2XYzVqMehDa4vnGknTXlbZw7P3eymzojCSGqAQ8QA6JSyjVCiB8BbwPCwBHgg1LKrklr5CQ60upFoC2pNegETquRus5A0vi8KzExtrp88MHy3kYPy/qd7HX6I32TQlaTnmBkZLUUxiIQiRGJjT56uSDTMmxh4F69EZfecOx4yitPiKq2kRcb/cXzhyjPzmBFqUtdZBoBKWWTEKJWCDFfSnkAuBDYi9ZXzwdeFELMA0xA23i140CThy5/mCXFTjLMBj59wRwauwM8vaeZg81eDjYPjvjPsZtHFE3b6g31LfNu6Aqc0MkkaMEEN59WPuZ8i0UuKwsLM9mepp7K5ppONtd08s8ttTgs6zhnnjae6XWCCxbkpZ1cNht1I+7/v3npCMVZVt6zvpwbVpVwz6tHx7QvE8WoFywrceELRdnf5EmbM/u8+bl848pFzMmzJ22PxSWN3QGKXdYJy8OsTA15Dgs3rCrhL2/WjKio53BaPSEWFzmIS/rSydlMBgKRGKFonKXFmYnzUkkkJsmymahu99HmDVPuttEZCNMzoHaPUS9YXJTJ9hGkf+pV5LRQkmWjrsuPlPDY9gb84RgfPVcr4Lmi1MXb15Syt7GHuNS+twLhGNG4xKgX7GnowROKYNQL9DrBrNwM3qrqQAILCzP5fxfOPeHPShk9IcRlaEV29cA9UsofjNd73XxaOS8fbOXme97ija9e0FcYdW1FFu4MU9+4aTHohlwpDtrczENbaonEJDkZZt61voQydwb+cIz9TT0UuawnfExW2xFIGjc7fGHe8/u3+PFNy8nKMPKPTbXUdvipyM4gGI3x1O6mQQEXLZ4Q/9rewLx8Owebxp4O8gNnVPD3jceoaffz+X/s4P5bT0u6v67Tj04I/vR6Na8e1g6dXjvcxoICB5lWA/5wjDl5Dt6zvowdtV3YzHpm59rJdZh5aEsd//ff/UTjkrtuXoXDMnR6Gglcu7KIj587h0t/voFVZS6+fNmCIZ8zk4w0cvnnwJc5ngajv2uB56WU6Y4eLUKIzUAU+IGU8rFRtnFKy8+0cPs1i5mb76DTF+bhrXWcMSeHa1YUsaehh4e31jG/wIHZoGdnmgPb/qTUCucNdcC6q1/OKZ1IDGApIpk3Hu1AoC1jS7UEv74r+cpqKBLnQJMHf2LJ3sJCBxaDHr1OuxJk1AkqcjLItBjxh6NkmAxIBqetcFqNtHpCDHVIEY7GkybP11e6hzwBmZtnJyvDRCQWJxaXfTmVrSY9JoOO8+fn8uKBVoSAj5w9i8tV1U5lCiqbZsvH8xxm9jRoB8oN3cGUObK+9ugu/vrh9Wq1wOQ5X0rZfxLqWeCrUsqoEOL/gK8CX5mcpk2e5p4gv3v5CDEp06Zh6s+gE+TazbQOWD7f7gsn5VTtFQjHktJknGyBcJQSt42e4PBt78+gFwQnIC90r+p2Pzfc9TovfOFcZuXah3+CAvBp4G9CCBNQhRac4QPuFULsRrsw9P6BKTFOpl+9eJjHdzSgE7CoKJM15W6uWlbErefMxmk1su1YJy2eEPubPNiMeuq7ApRkWTnY7Elaxp1KR7/aHMOlleivyGnhvAV5PL27iXZfGCFgSZGTCxfm8Y61pWPdVWwmA7+9eTWnff/5IR8Xl/CD/+6noSvA0XYfp8/K5oUhiu729v2RppD55+Y6rl1RzB9em5oTy2sqstAJQTQWp8MXHnZFZm/KEn84yn2JNCpN3UEaugMcavayotTFb9+7GrtZlfeZaZaWOLl6eRGPjmL5u8tmZF6+Vii0f3F4TzCKTujY03D83Lc0y8rBJg9Gg67vAnGvWTnaqop1lVnsqe/BoNexpjwrOehLwoGmkY+tRr3AE4ywsbqD5aVOVpVl8dO3r8BkOF7IdlFRJt+7Ln30/n92NvD/7t9GTMKqMidvVvWvzeTFH47htE6/wrjTWSLl66+Bi9FWD20SQvxbSrl3nN6Pu9+7hkt+vgFnv/zaBr2OK5YW8Nc3jwGwuNiJSS8GpS3r75k9zawsc1HktLJmcRaHmn0Y9HpcViPnzsvjZFzS6wkOHr8DkdigIKnhjglASyE1O89OiyeEy2ok12Fma5p0NwP99O3LuX5VCd+4ciHeUDTpswMtwvqTf9vKnoaevpQ8vTW5mnqOf5c8t6+F376spfBaVeYa1O6fv2MFFyzIZzhVrV7yHGbO/8lLxOKSq5cXsbbCPezzZophR3whxFVAi5RyixDivBQPeRdwzxAvUS6lrBdCzAJeEELsklIe6f+A8cohNxH2NfYwO3FClZVh6sv1K6XknleqyLGbR5xOQiDo8IUwGnRkmPRp87L1t6TYmXaZGmhXV4pdlmHzuwq0jp9pNfZNLvcvOLa+0k0kLjmUIpqlItvWd/Wtpt3HrFx72kiPtO1M891SmmWlwGlhf2PPoNyZVqOe/7thKVcuK6KxO8BbVR1k202cOy9XRUooU9KS4kw+d9E8XjjQwo4RXGyabG8d7cBsEElX1Aeq7wrwtl++yneuXcy1K4pV35tkUspn+t18E7hxstoyGbYd6+T5fS385qXDo0pZEZcSg177v1vsslDotKLTCdq9obT5j70hLQ/zvoYevCMYr0djcbGT/WOI8qjrDLC6PIu9Dd0pLzqPB53QlmoqIyOl3A6kqrp980S14QfXLyXfYealg63sru9hd31P37LcYpeVm9aUcM2KYtq9YQ42ezjU4mFjdceYcoGPVEN3kBf3t/DUZ8/hsW31BCIxzAYd160sxqgfftJld303G492cM2Kor5j0l4jneTa29jDbY9oZWJ+93LViJ7jC0cRIv1xbK/ttV3ccNfrfPK8OfzqxcMjeu2JIoRWhLBlmGi5/nqCUb77n31p7+8ORHjpQAuXLi4Y0d9PObWsq8yirtNPLC6RUrvwebjFS6c/gkE3ONVaRXYGh5o95NjNlLltNPcE+grgWY3J/390OkEwGmd5qWvQhZ3elTfHcyjH+ur9GHSCuk4/3lCM9bNcff/fDzZ7+/pwjt1EkVOL+qxu91HksmI3G/rex6zX8/3rlyZNLA8nHI3xg6f2E5NaVOrG6uQ2f/7ieYMmzJQJsQ44LKWsAhBCPABcg7aaaFzodIJnPnvOoJU458/P41Czl+aeIL5QlL3tftZVuKntTL7Y0t+2Y13s1ndT4LRQ2+HniqWFXLuy+KS1NWfAODpWRS4LB5u9eBP1wDp8YboCYQy64VfDr63I4rrEPhn0Oly2wWnY/vxGDYdbvPzsHStw2YxsO9ZFjt3EB8+o4EirF4tRj8um1UsTQivY+f0n92E16TEIwdx8O1ctK+KaFUUj2p+5+Q6KXTaybCY+dFYFrx9pZ3NNJ79810p1DszIIpfPBK4WQlwBWIBMIcRfpZQ3CyFy0DrmdemeLKWsT/xbJYR4CViJtvyv/2PGJYfcROjyR/jH5lrevqYEs+F4gnEhBBU5dkrdNtp9Yc6ak0NPIEIkFk9ZZGhRYSa1HX4OjzAtBGgRy6mKlAwUjUvmFzg4kDhRNeoFs3LthCIxqtv9zM7NIBSJU93uG/LAMt3Bc3W7n+p27era7NwMAuHo4AcN42Czh1m5GQTCMXITX2ZdgTB1A4oE9heIxPjdhipWV7gpybJRsnp6RYUqM48Qgs9cNJf/d+EcfvDU/hGfvE4WnYAlxS521nUN+ThvKMrn/rGD+s4An7pALe2bQBJ4Rgghgd8lxtL+PgT8Y+KbNTmauoP88oXDvLA/fbRhOt5QFItRh82kp74rOGhlTyq9F2AXFjqSLsaOlttmYm6+nUA4hkQb23bVd485AnlLTSfz8u2YDTqOtHjT1mg4WeISNld3sqAgc1zfRxm7TdUd3P/WMcqzM1hZ5mJlmYsFhZkcaPYwKycDCbx8oJVwLE59V4BfvaBdnKnr9BOJxdOupusNhFhclEkgEmNFqYtHttZjMeqYm+dIWmk3Eo3dQW767esUZ1mJxyEv08z7z6ggGIlhMQ4u4uMNRXlubzOPbKtnQyI3ZP8TRCklO+u6+fEzB0bVjpFaVuxk5yj2cX+TZ9jlzpNBSsgdUAvlROQ6zBS7rNzxn31894l92C0GVpdlsX6Wm/JsG62eMA6LgTPnjG8xKmV8vXSghZaeEAg4fVY2jd1B7t5QxbnzcnhyV9OglT1CaOOlSa9jx4DAqHA03pd6an6+tlB6TXkWXYHI8bRNCfsae1hTnjXkCtmBDrd4tcmlxO3qdj91ifPLFSUuGroDOCwGjrT6+tJClrqTc8SWu21squlg5e3PcuPqEr75tkXYTENPpbR5Q9z53CHKsmzkOSyJmkHtffdX5mRwy1mqCP0kKQZq+92uA9aP95umSvF0/vxcOv1h7t5Q1RdYsLG6A7vZQJHLQkOKY1IhoNRt40+vVxOLS57d18yCQkffsVhth/+Eci8XOC385KblfOGfO8b8GhXZNnqCkb6J5V6ZFiMdvuFXNl25tHDYCdsHNtXyzbct4m3LtbH/7LnDp2q8eX0ZgWgcm1E/6pRb4Wicq5YX8reNx/jEeXMA8IWitHpC5GVaRvVap6JhJ5ellF9FW1ZLInL5i1LK3uiKG4EnpJQpz8KEEFmAX0oZSkxEnwn88CS0e8o4fXY2p8/OTnnfxYvyuXhRPuFonN++fISfPnsQAHeGiUyLgZ5+VUD3NvZQ5rbiCY18YnZJUSZbRrAUoTfs/5y5ObR6QzR3B/smms+em8Mrh4ZP6/fW0Q6WFjuHPVHozZm8otQ5qlxWpW4ru+p7MBl0FGRa2DaCqM4z52Tzg+uXUexKndRdUaYqIQRfvXwhbx5pH3SAPd6MOu0qbSASJxKL9x1c92cx6FhW4sIbihKMxIaNyOp13xs1vHNd2Um72q0M66zEyqA84FkhxH4p5QYAIcTX0dJR/S3VE6fziqF0CpwW7rhuKTfc9fqwq3UGOpHJ4S5/ZPCy21EIRqIcbRv64u5o9ebMzbQYmJNlo90bYm6eg55gmEPNXkawEnHEhIDrV528aBnl5InFJS/ub+Enzx5kX+PxSRJ3hokrlhYwN89Blz/Ms/uaicSPX4SIxiW/SFF4NjvDxMfOnc1DW+rIMOt557oy4nHJ9tou/r2jgZVnZrG9tguTXset58zi0/dvo8xtI9NqoKpVSzXR6Q8PuYy2N2DBqBesLs9i5e3PctOaEm6/ZsmgfbvhN69zoPl43xUCvvnvPXznmiXUtPu4e0MVm2s6T0ru11TCsTiry7OoafcNWxy718CJsom2rtJNLCbRJ6K4YnFJTMpB9VnGQgjtxN4TjPDUnqbjd/Rok3v/2Hx8HifXYea3N68iEpNYjHqWlzhV1Nc00eYN8eL+Fu57ozrl6tzn9jWnfJ5M5E0uz7ZR4rJS12+c3tvYQ45dWyXntBpZXuJiY5q0U5GYHPF4a9CJvqXyFqOehQUOhA5A9B3/bk8EUAwcg3tzjTssBmbn2DnW6UNKiErJv3c08K2rFw/53rc9vJPHttcTjMRZV5HFlppOMi0GLltcwNx8OweaPKyrdKt6BVPYeB4r13b4icYllTkZ6HQ6blxdyhVLCznnhy/1BQ9GYnF8aeaGpEwu4Py+08r7Ct1FY3F+9cIhPnfxfAqcY5/wXFLsHNHKnHRqO/yYUlwYDkbjrCpzcajFiyeYfu6rPHvolIv1XQE8wQjXrBjdMaher8M+xhU1QmgTzM3dQaSUCCHIMBvISKSA2t/Uw7w8BzqdoKUnyL2vVROKarXF3rO+jPWzUs8bnipONBHWO4GkxOdCiDXAx6SUHwYWAr9LVL3WoeVcHrelBlOVIVEUJD/TzHef2JdyeXmGSU+xy0Y4RZVZu0nPrFw7ZqOuLx8aQrCvsYe1FVnUjHApWzAaTzqBNukF3mCEBQUOYnE5KJo61X6MxJqKLHbWdbOy1EW7L8SxNIVAeq0odXIk8d7haLxvafJQvnvtEt69rmzMBV4UZSr4xbtWct1vXscbjBKOxSnItJBh1o+4sGUvm1E3oujEWTkZROOSvYnvAYfFwLISJ93+CMFoDH8oikTLJR+Tkr2NoyvE1OoJ8ZWHdnLP+9eok8QJ0G9lUIsQ4lG0lUQbhBAfAK4CLkyXt3U6rhjq9IV57UgbT+xopDzHxgXz8/CGtInZp3Y3Ud3uozsQGVEOt5OpsTtIqyfEuko37d7QqPuv02Y6KfnxUukJRvvyNvcuxbWa9CwrdhKLSyKx+Ald4HJYDPzwhmXDRm8pEy8YifHbl49wtM3HilInp8/KJsOsJxiJcbDZy1O7m/AEo5j0Oiwmfd8JXm/FeXeGiVk5dq5cVsiBZg9N3UGKXVY+cGYFHzknOdLuHWtLuXp5EXmZZt6xphSTQYcnGOG3N6+mIsfG9/6zjzxHlJcPtlKSZeWDZ1aQZTPx5zeqkyZlhYCVpVouxEhM8mZVB2fMzubChfnE4zLpmO+JnQ1JE8ugnQD/Z2cjR1q83Li6hNePtA9bgPBE9EaYFTrNOCyGIU+Sp4IFBQ62jTDP5Vi4bSZePdQ6opRErZ4Q7/vDxr4UgF+/YuGg/1fK1LS3oYf/7m5KmSpxJGra/ayrdCdNLht0WnH3uIRdDd0ETlKqqVXlWexr6MZlMxGIxNjUb1J6eYmWWjLVf1e7SY/DaqDUncHWmk52N3T3TVKDFqmdajVFr3ZviAc2aRdTrl1R1Pfd0BOM8sKBFn7xrpWjSq2hjIt6oH9C/5LEtj7jeawshFZ0rn/NGpvJwFcum8+XHtoJQCgaZ0WK9C+pXqsky0bvIf/LB1v54FmVNPUET2hyeUdt15gnlkHrf6lqkzR1B+nwhbU5rRNg1At8oSjmNH3pYLOHObn2kzZfdLjFy7N7m3BYDFy0KI83jrRzxoAVOP1X8TltRpaWONl2rJP5BQ5q2v19k8vBSIxn9jbT0BVgVVkWayuyTolz51GdDUgpXwJe6nf7vBSP2Qx8OPH760D67PYzxOtH2glFYywszKTUbSMQiXE0kRNqfaWbdl+YTl+YN6raqcyxsaQokxyHGX84hgA8wcigZXfrKt34wzE2VXfizjBi1AlcNhPl2TaaPcG+q61mgyDHYSEWk4PyIIdjkm2J6OLVZVnD7sfexuFPQN02I3UdAcLRONtqu9AJbUmEXic40urDZtQxK9eOyaAjEovjspl49VBb0sBen8gZ2dITTEqJYTbouHBhHpcuLuDq5UWnRAdUZrby7Awe//RZOCwGmrqDtHvD3PqXzSkfW+yyUpxl1RIhCC1PeiQWp8UTorE7yKLCTGJxSVzGicYhFteKX1pNelxWLUfV9tqupINjTzCaMme7t9WHVl9q9J7f38K+Rg+LitQS+fEkhMgAdFJKT+L3S4DbE5WvvwycK6VMXw1kmonHJe+9962kKKmplFYmGpfsqu+meAwH8TaTPm1OvfEQCMd462gHRr3AZkp/cjwShkShX2XqsRj1fPaieWnvD0fjPLa9nq89sgu9XrCoMJMyt43PXjy3L+pmpIQQg06wHBYjlyWKK//+fTn9PhwAAQAASURBVGt4aEsdbd4QHzt3dt+kzKLCTLYc6+RYux9fOMqxDn9fEUAhoMipLUt//70bWV7q4nc3r8Zk0PHlh3bymQvTp2Da3+QZMh/wyVbssrG7YewXaSbCuoqstJGgJ8too7J7J5azM0y8a/2psYJmJjhnXi7haHxMKah6banpZE1FFg1dAdo8IcqzM/qCnE7WxDJodRhm59pp7A7QHUi++HOoxYvdrMcTSn4/q1GHTifwh+Npawg9v7+Fpu70E3fuDBNlbhuhaIyvXbmQR7fW83zi85JSYhxBIJUy7jYBc4UQlWiTyu8E3j1Rb27Q6bg6RZ7fm9aU0uIJ8aOntXRObx3tGLaAtJRwxpzsvpzEUoLTamRBwYmt7r5ymZb+YTR1gvIdZspzMqjr8LO3IX2QUjgaZ1nJ0LXDXjnUxvkL8tLebzHqMRv0HGj2pEzNlu+w0H+6qKbdx72vHmVJsZOb1oy+UHCxy0Kxy8rvXznKb29exQ+fPsDaSnfaugJmg56z5uRw/vzcviAMKSVHWn18/sHtSfu+rMTJ165YyMoyFzohUr7m1mOd5NrNFLmsU3bFgwo1mQBnzc2h1RPk3B+91Fcsb2GhA4fFgISkSvZH247PBawsdaVND3G4xYvLZqTLH+nLWdPqDdHqDVGcZcVpNdAdiLKgMJMdI0hP0eEPo9eJIZcOZtlMNKXJu3f8dSIsL7X1VeeMS/ryMVdk26jvCrB7wBfN6vIsGrsDffmEGrqDNHQHWV7ixBeK0eHXDlbPmJ3Nb96zeth9UZTppDetS6bFCPnw6CfOYF+jJ3FFu51DzR4i8Tg7aruHXOo/dJTx2CaKRyrTYuALl8xnRakLk0FHrkOlxZgA+cCjiYtsBuDvUsqnhBCHATNamgyAN6WUH5u8Zp4cOp3grves5m2/epUu//hFIp6IxYWZbBlDaowjrT5Wl7vYUtN18hs1QH6muS9/rstmOuGokU5/hK88vJOfvn0Fc/LsJ6OJygQxGXS8fU0pN60uGfeL9RajnptPKwe0i6L/2l7P8/ta2Hqsc1BqpvWVbnLsJoQQSVG2O2q7ePlgCzetLmV7bRe/fvEwb19TwoOb68a17SOxuaaTZSVO9EJQ0+FPWwB3Mm2v62ZZiZM2byhl/s7JsLLMxbw8B+fMy8VuVqek08lFi/K547ql/PTZA32rD7TJLMewUZagpWPZXN2J02pkXYWbfWMoYDsSkZjEbNQRSrG6zx+Osa7SzaajHUlBToFInHn52qreoVY+/PKFQ3zvutQxdEII7n7fav61vYE8h4W8zOPHxTdOwHeuMjwpZVQI8SngaUAP3Cul3DNR71/gtCCl5K2qdtZVupP+T3zivNk8v6+5L4XUpupO1lW6OdispZUx6nVsru5kdXkWR9t8hCMxPv33rXz9ykWcNz+Pixbln5Q2ZpgN3LiqmEyLYcg0qmVuKw6Lkf1NHpo9IZpHmOZNoKViDKYoFnzl0kLetS79BLA/HOX9927EF4py28O7uPOdK5LSaNz3ejUumxF/OMZPnz1IOBpnbp6deQUO7t94bEyTyxajntNn5zA7z86+Rg8/vHEZR1q9Q9Ycae4J8lZVO/mZFsKxON95Ym/KOhY767p5591vAtrF9cc/dRZLip2AthIi224m02LkVy8cptMf5tfvWTUli+WqkXyc+cNRzAY9OXYzv3nPKr700E5aPaER5XfcVtvFggJH2orx6a7s1ncGqMi2MSvHnhSlOBSHxZByYtmgE5gNOhYXO7EYdHQHo0nva9AJyt02/JGYlmKjMDNteo3eSeaB4nGZ8kB3R103NpOeypwMjrb5WDmC6GpFme7m5DmYk6cVM7lqWRHdgQjVbVruyP/sapzk1mlWlbnQ6wS+UIy4lJgNOgqcFpaXuia7aTNGorr18hTb50xCcyZEqdvG4586i/N//NKIx7aJZNALMq1G8jPNuKwmNlV3DFlwaHZuBp2+CJ3+MHohmJObgdWkx2o0DKomP+q26ATz8u1kmA19qxx6glGOtPrIc5gpyDSDEKMuuJbKzrpuHttWzxcvnX/Cr6VMvImY5HhubzM76ro42uZjw8HWpJojA/WfmFpcpBW77n18S08IT2IJbFJO3ymgNwJpZalrSk4uh6NxDrd4mZfnmNTJ5Ry7GXeGESm1CUaJpM0bYnd9d9+JtDI9vHt9GdetLOato+30BKNcvqSAj/5ly6heozsQIRiLj1su8hy7iZ21qVNfgJabNlVO2R113RQ6LUkXZAdq7hm6Hy0oyGTBZdqk08WLCrAadxOIxLjt8oWj3Q1lnEgpnwSenKz3P9Ds4R13v8nfP7KeM2YfX/0jhOC6VSVJ9Qk2Hu1gdm5GX9BgmduaFNDgbfNzy32bybIZuWxJId+//uQkD1hd7uaBTbV8+dL5/PDpwcVxi11WmnqGT4Oayo66bubk2ZMCLefnOzhtlptvXb14yOOThzbX0u2P4AlF2V7bxXW/eZ3Xb7sAi1HPY9vq+d9/J18nyLGbueO6peyq7+ZzF80dlGprJIQQ5DrM5DrMLC7SxqvhilnPy3fw1O4mntrThECk/T7pT0otZcqSYidSSg63eMm2m5mTZ+e2yxfw1Ud28ftXqvoKCk4lanJ5nIWjcfzhGDl2M+fNz+PxT53FLfdtSqo+O5R0kcRWo44uf/qIo+p2PzkO84gK4wEcbPKwvMSZlHtxZamrL4dl77Igg07L2aYTYDUZiMUkcSlp6gkSicshl2yks6OuC0eKZUmgnVgIBD+6cRlrKtyjfu2ZTAjhAu4BlqAlU/gQcCnwEaA18bCvJQbWgc+9DLgT7UruPVLKHwx8jDIxnFYjy0tdnDY7e1Iml5cVO7EYdXhCUboDEXoC0UHFmBYUOLh0ccGEt02ZeUrdNv58yzo+8MdNhFNEOkxYO7Ks2EwGDjR7sBp1LC1x8WaVNk52ByIsK3YOObG8stTFwWYP4VicDLMhabl6adbYlzHOL3DQ5QvT4Qv35VYfqMUT6qvTsLLMNaJCXka9YGWZi1hMYkhESrR7Q9S0+ynPyUCngyOtXmblZKiILAWAFk+Qx3c08odXqmgYY9qXPQ09ZFoNrKt0s+1YJ79+6TDFWda+YkdT0bbaLsrdNgqcFo51+Cc05c1Q1lVmsa2mq6942WTp8oeT/n4767qxm5u4bEkBt1+zWOVvn2ZePthCjt3Mm1Ud/PSZA2kDidIZbrn/WDmtRubm2alu96Udi2flZqDXCZYWO7EY9QSjsb6Ju3WVbsLRON5glGaO/3/tv8r3raMdhKIxzIbh00vZzQbm5tvZWddNS08Qp9V4wvuoTH+zc+0sKc7krpeOJE0uA9y0uoTfvnQkadWqlvZCW42abjK30x/h+X3NDMxMG43F8Udi2krZUVhQ4ODxT51FOBbnp88eTAruWFKcSVWrb8zH4wsLHeQ5zH2Ty06rkW9fs5jTRlD07pm9zbgzTFQlUs12+MJ85M+bmZNn57FtSamzybGb+dMH1/LSwRYONXv5144Gvnr5AhYWjj6Fo5SS7/5nH3azgY+fN3vI3Ou9PnruLEpcVjYf62Rd1M2mmo5hc1k/vLWOj547GyFEUhHArAwTv31v6pX8UkqOdfiHLYQ4ntQIPs56c9/0KnBa+NGNy3nbr14dUfXqQy1ech1mWgcsL+j2R8gwD108ZH+jVoW2vjMw5HJ60Ir99XYOh8VAjt2EXif6ct/1isZJGUnde+A/FgsKMtMu6S9wWrjzHStV4b6xuRN4Skp5oxDCBNjQJpd/JqX8cbonCSH0wK+Bi4E6YJMQ4t8zsRjnVLJrAk4IjXqB22bCYTFgMxmwmPRp8831ctmMfOzc2ePeNkXpdcbsHPIc5kHL6SeKUSeISy3iZG1FFh2+8KB+YknkMrYYdGRajfhDUeYXZKLXC3bXdydd+I3Eksfx2s4AK8tc1LT78QRHV6DQZtRxYITLEQF0QqATUJmTgScYTVsceEWpi41HU4/xh1u8/OL5w/zi+cOUuW08/4Vzp+RSPWXiSCn5+XOH2FXXjW2YdAeVORl886pFROOSj/x5cM2BnkCUjUc7WFOexeaaTn7x/CEWFDhOqBDleKvp8FPT4aci2zbZTQG0zzhd/51o+ZlaDszemhAFmRZMBh0fO3c27d4wFpdeHfNPIzvruvnNS0eGfdx7TytnYWEm33p8T9JElE6IERelHo1ZORlsHiJN1YpSJztqu6nqV4B3bUUW6yrdRGNxuvxhDjZ7KXZZWFjo6FtxbDXqKXZZ6fCH6QlEaOkJUeoeWT+/bEkBpW6bVj9FUQCjXsd3rlnCZx7YzuEWb1J6MYtRz9evXMgn/raVOXl23DYTW4+NbFWb1ain1RMk16HlBP/1i4fZcLCVQy1eXv3K+SO6iLevsYeFhZl938c+fzTpQs2yYuegmmBjEUz0fZtJzx3XLR3RxDJoUXNVrT4yLYa+1U2vHGpLSt9R7LLyifNnc9XSIpw2I7NyM/CFYjgsBjb3u6j15K5G3qxqZ0mRk8XFmX1RybG4HJTb2BuKUt8ZwG038cjWet6dpl5Ahy/MjtouVpVl4bQZuX51CdevLgG0emrn/uilIVc5vT1F2o4jrV621nSyt7GHYpeV+QUOilxWZuVk8ML+Fn7yzEH2NvZwzrxcrl1RxIUL8yf8QpaaXJ4ECwsdPPaJM3loSy2vHWlPWgqQSjAyOKI3x2Ee9uqwN6QdkOfYTX05mEGLeg5E4lTmZGAx6tALgScYwWzUsb7SzabqDjzBaFL+5+H0vk9F9tCDOcCa8izqOrWcdEtLXBj1AqNepDyBfte6sr4vteo2H//d3YQQ2lW0c+flqgipNIQQTuAc4AMAUsowEB7h57UOOJxYdo8Q4gHgGkBNLk+S2g4/b1S1j9vru20mnDYDR9v8o8qV1esvb9awu76bb1y1aJxaqCjHNXYHTmrBn5HIshmZnWunKxAhGIn1RSOmiriak2en1RNiTm4G3cEo0VicDIuBLaO4ANs/mtioF8zNc9DQHRg237RhlJO62451YtRrBXd1AlaUuDAZdfSOFFJqxyAjjSw71uGnrjOQVP1cmXmEENzRLxdpfVeAmnYfHYmo+nZvGJ0QnDMvhxWlLgKRGJ/829a0r+cw69meuCBT3e5nQYFjvHfhpKhu92PQiUlP42M2TJ2LPQODXTp9Yebk2XnpQAu/fOEwG79+IWbdiRUaVSbOly6dT4bZ0Fd8LBUh4OoVRXT5I+TazTR0B5ASlhZncqjZQ3GWjcMt3rQRxr3F4Lv8EeoG/P8xGwRWkyFpbKzMsQ27cteo1w16v1TjXH1XkOaeIKvLXOyq7+GT58/hX9vrOWN2Nm9WtY8qCnQqLmFXJt/Ksiw2fPl8QJt0dPT7P3X5kgIWFDjItBiHTZe2tNhJmzeINxilrtPPX96o4ZMXzGHj0Q7+8OrRvonMR7bW99VAGMrAqF6dEBS7rBzr0OaHwrETPw73BKN9Ebz+cIyRTuvE4hJPMEqHP8x583Jo84axmY6nlBMCvn7FQi5amJ9UdNpmMhCJSixGPWfNzaHTFyYrw8ShZi89gQjtvjCHW7zUdfhp8YToCkS4cEF+UpF6h8WYNnK4lzcU5Yv/3MGO2i7++MG1LLO5ku53WIycMzeHx7Y3pH0NnRCDVkbMzrUzO9dOdyDClpqOvonyo20+brnv+MX5DQdb2XCwFYfZwJcvm88VSwvJtk9MPSQ1uTwJhBAsLXGytES7KvLH146y7VgXb1a1U55tQycEvlAUXyiKXiewW4x9B9W9qtv9rCx1EYrGhyzkNTs3A4fFSDgWI8cep8xt46WDreTYTdR1+pMmdGs6ApS5reTYzWmjl4bS5g0zK2fogj5Oq5Hd9d19idu31HQyOzcjka8nSHl2BgeaPBh0ghWlLv7wylGyM8y8/96NfUUCAcqzbbzwhfNQxXbTqkRLffFHIcRyYAvwmcR9nxJCvA/YDHxBSjnwaKoYqO13uw5YP87tVdCW0//xtaO0ekKcPTeHkiwbCwocZNtN/PwdK/jIn7eccC7H9ZVuojFJJB4nkijmFYrE+5YVjZZBJ7hoYT7z8lUxL2X81Xb4uem3b4xbfsZ05uY5iCfyng2n9zH5mcdXHZW7bUMW6R1KJCY52NzDyrKhlw8b9YJ9I0y51SsuIRSVfb+fjCXzX31kJw/cevoJv44yPcTjkiOtXu597Shz8xx86KxK9jR08/rhdiSSdl8Yq1FPtt3M/HwHlTkZNHUHKc7SCgDVdQa47/VqXjzQmvY9PKEYq8q0VG1aEWs5JSZthzNVDlEdlsk73TPpdfx/9u47TrKySvj471QOXV1dnXOYnDMz5JxFQFRMKKAu6hrXCOu6q64Bd31N666KEcWEIoqKgIgkgRkmMTl393TOoTpUft4/bnXToarTdHd1Tz/fD/OhK9yqp8Kte++55zmnONOJx27BZjFx5wUV7K/rYl9tJy+daqejL8zLVR2cbOnlNesK6A9NrMyANjeICO+/bAkZLiuffvhAwvsoBTurOnj95iIC4ehgMKk/HKMww8mB+m6jjEVeGk3dAWIxo+RiQ1eQTLcNpRQH6rvZWu7D47TgshrfZ3N8mxeJKlbkewhFY+Sk2QE1ZoKU02qeVPPdFQXpfOSqZWwozsDjtPLOC8sRZDD7XtOmy09frOamDYUU+4xseBFhcW4azx9vpTTTmbQUxuIcNyLQ0PVq/OZbT51gXXEGlyzP4Rf/tI2O3jBv+f5L7K3pnFBweSSf28a5izIHg8sdvWFMYuw7TlaRz0mh1zG4T5vnsROJKVomWPLqLwca2FfbxTnlPp4+9mqm8uYyH119Iarb+/jh85WUZ7mHBZcBvK5Xg/c+t1Fh4MNXLk34PA/tqh0WWJ6oNLuFH91xDkqppImQ/3nzGpw2M939Eeq7+slOs5OdZifdaeFwg5+WniChSCzh9tDrtHLhkhz+frSZ3+ys5Q976xI8A/iDET7zh4Pc+5cj3H5+OXdcUE5uPJt9pujgcortq+1kbZGXS5blYLcs51MP7ef5E8ZKYhIjnf9EkoPRPTWdrEvS/GJRthu71URNWx8nh0z5Ucr4N9DZd6TT7f04LEYG8/bKdjJcVsqzXCjFmFMQF+e4yU23D5tiAHDR0myqWntBwGO34rabRx0cn2zpJT/djttm4VRzD6sKPHT3R3DbLdx18SIUit7Q8GnDp9v7ONHcw/J5kr2SAhZgE/BBpdR2EfkmcDfwbeA/MWaT/Cfw/zBqMU+JiNwF3AVQWpp4Wog2cU6rmcU5aWwoyeCSZTkA9Iai7DndwaP7G1hdmD5mt96J6A1FONzgn1BZnokoz3Lz3ksW6VkE2qzYXtlOVppt2MnG2bCjqp00mxmPY+xyVEMNbdoxME1+cY4bq9mUtFFvMjkeB70J+hIMFY4qVhd4Ul5TVTffPbsEI1H6glF8bhsffXAv+2q7+PRrVvKTf1ThsplRCo43+znZ0osIvHiqjV3VHdPe1G736U4KMxxsrfDQ3R/mnHIfL546s8aXM211YToHJnnCZ7pkp9moyHbT4g+O2jefTaFobLD0gMNq4tMP7yfNYeGDly3ltm1lHG/uIRCOUpbl4tYtJXN2X0JESoCfAnkY+9D3KaW+KSKZwK+BcqAKuDVB0sZZ723byugJRPjyX44Mu14ErlyZxx3nlxOOxfA4LIMnhzPdtsGSUl394WHf0zS7heV5HswmGUyi2jHG93hgm9oXjBKNJS6xUZThpMjnJByJTepE7/9744Zhx5v65Ic2U95/2RJ6g2E6+0KDpVU/ftUyKlt6ON3WR3aabVgMpyLbjdkEjV2BUTPdr16Vx/MnWvmPRw5SkunkK69fx43rC3l4Tx0bSjK4cEn2sMBrdVsvBV4ntjFmuqwt8vLgzloAmvxBluWlcaxp/KSLkQrSHcPiQc09QSwmoWYCNduVUjx1pBlg1Gy+gZNGFhMU+5x88Jd7ePTDF015Nt36kjNrMjvW9szjsPLlW9YBxmv64fOVZLptrCvO4F9+vZff7KzlnRdUEIoEE2YdP7S7lnt+t39C4+gNRfm/p09y37OnyE6zU5LpZEV+Om/ZWjql4PlYdHA5xdYVZ6CUYk9NJz6Xbdh0gJgyGl9srciksy9EVVvfsDpVTqt52BnTNYXpHG/uYUW+B5/bxtMJskB64122g2MUXg9EYuysaue8RVn4A2H21nRRnuViaW4aDV0BeoKjD6xtFhMvnmwn3WmBUBS72cSiHDd9wQg18bqY6Y4wziRFzxuHHIQfbvSzPM9DgdfBo/sbeGh33ajnzHTZaOoO6OBycrVArVJqe/zyb4G7lVJNA3cQke8Df0qwbB0wtNBPcfy6UZRS9wH3AWzZsmVupxDNA8FIlPXFGfzkhSp++mI1B+u76OoPc9dFi9hQksEvd9SM/yAJ2C1CRXxWQTSmpi2wDLCzuoN7HzvCv1y5bEJNDTRtqo42+nnyUBNHJxmYPVNLct1kuuwEwtEzri+X5bZNKdjU0GU0ANpanjlYrzRRCaqO/hCby3xEYjFa/EHqO2e/mdi1urnnvKCU4lBDN7urO2joClCe7WZTaQY+l42D9d3840QrfznQiM1iorMvzLVr8thX24VSinse2p/wBI9S8NdDTQmebXrUdwaGfadLfE5yPXZMJiESNWojmk1COBqjJxihvTeEx2HFbjFhEmOaqYhxwDf4N0Zga2gixnSZ7cTqLeU+olFFIBKlsqV3Rhqlnalin4sCr4MjjX76wxGKfS7+5apl86FOewRjtt9uEfEAu0Tkrxjl5/6mlLpXRO7GSOT4VArHmTLvuWQxqwu9fOWxIzR2B7hyZR7vvWTRYHMpJ2beuKVksIRGR1/yE1A9wQhHmya/re8PRwkmKCeZ47Fjs5jG7SOSiE5m0maT3WLmc3/czxduXovNYqIiJ40vvG4td/xoB1azcE65DxSISThc34U/SeLBE0O2xXWd/bz7/p3csqmYR16p599+f4Cv3bp+MLjc3hvk8v/3DC6rmQfevY31JRkJH3NoqQyPwzJu0kMiS3LTOFg/fF9aKSNB4oOXJ84gHurTvz/A73YbYYmh9YTXFKXzsauWU93Wy2f/eIiXqzrYWpHJlx49zLffunFKJ4WW5I6/3iulBisBmE1CVVsv6Q4rOZ6xy1D8/Wgzj+5rYHm+h+q2Pn72UvXgYwwcp3/0wb1cuzqft43INP/Tvnr+80+Tr1YaiSkauwM0dgd4uaqDB3fW8M03b+DaNQWTfqxkdHB5DugPR9ld3cHrNxVz93UreOnUPwa/pP5gdHBD6LCYWJzjxm4xE1OKmvY+tle2U+C147ZbaewOEIzEeKW2i9JMF4tz3KN2lpv8QbZWZI67cY0qI9tg4CB4oL5zpstKUYaTLLcNh9VEbyjK0Ub/4NTf7nhd53A0ioiwa0jdyEy3bUJdhB0WM0ca/WNmdrX1hvj07/fznosXT2lqx9lOKdUoIjUislwpdRS4AjgkIgVKqYb43V4HJJrD9jKwVEQqMILKbwbeOisDX8AC4SjfePI4P/pH5agOst966sSUH3d9sZejTWOvT2fqe8+c4gfPVeJ1WjEJfOl1a7laB5i0afSBX+zmpVPttE5wytx0ynLb2T6FA9KRNpf6iMbAbbfQN4Wa0SPX4XPKfSiM344Ddca2ujqe2TLQ8X59sXdaG59lp9n49ls3cbTRTySm+NWO0xwfUirkkmU5rCs+s0wPbXb8Zlctn/ztvgnf/4GXTs/gaKampqN/MIEhmWQz9QCW5Lhx2y1TDiw7rCZyPQ7S7BYcVtNggDQSVQQiEdLsFgq9Duq7Zv4kT2GGg6ON/gnPrEiFQDjG/rou+kIRXjjZxkVLs/nPmxZNulZ8KsT3nRvif/tF5DBGGbmbgEvjd7sfeJoFGlwGuHBpNhcuvTDp7aZ4FtXWct+MlLfqDoQpz3JTOaLUm91iGnXdRNgtJt1DQJtVFrPR4PQLfz7E529aA8CmUh8fv2Y5//6HgzR0GbGcvTWdw5IOx3O8uYfjzX5euPtyvvfMSbLTbHT1hfG6rBxr7EEwyiiYxsi2XZSTxvffsYWGrn52VXdQluUmx2OnLzh61sIly3J45tjwRMccj52TSeqrv/mckmElK5KxDGmwN5B8WJTh5HfvuwCbxURtRx/3PXeK4gwnFhGONHbz1ceP8unXTL4v0EDg2CgFolickzaYjdzRG+L/nj7JD58/NXgieXVhOocbujGJ8Nr1hZRnudlakcl5i0c3KSzxOVmal8bX/nps2DGBzWzCYhX8wQgNnf38YsdpLl+ZS4HXaAR6sqWHz/z+wJSOI0YKRmKEJtE0fCJ0cHkOcNksKAWf++NB3rC5JGln+EAkxsmWXiqyXDT5A/SFjB8Uo77O8ANui0mSNvAIhKKjplWMlGYz05wgK6W9Lwx94WENOZbmptHUPXrnPjoiQtbaE+Kcch+7qzsY+hIFhv3IhKKxpNMsKrJf3WGoae/ny48e5nUbi3CP0418gfog8HMRsQGngDuBb4nIBoy3vAp4D4CIFAI/UEpdr5SKiMgHgMcBM/AjpdTBFIx/wYjFFK/7vxc4PEb99MnI9dgpzXThD0SmNbA0lmhM0d4bYmVBOntrOnVwWZtW33zzRuo7+7n9xzuGdXc/U6sK0jGbhP1JMpI3l2VMS2C5PMtFdyA8LBB7poZmJZZnubBbTDhsZnZVdw5e/0ptF5vLfJOqLzmW1p4QX3viGP/9xnWUZbkp9Dr43B8P0dgdIC/dzpduWTtnp7Vrw71xczHBSIx//8OBUSc0P3HNcrxOKydbethU6uOipdl4HFb213Wx/VQbocirNfvDMUV/KEp3v3GQ+kpNJ2aTcPPGIpSCL/z50GA3+LnkvEVZBMLRhBnYZpOQ47GT4bQOO9A2mwSnzUw4EqOlJ0htR/9g/cmx5HnslGS6UEBtR9+wkjnTpSjDOScylR1WExcszuaZYy2jamJnuKy86ZwSBGFlgYfXriscbNo9n4hIObAR2A7kDUnaaMQom6Elsb+2kw0lXk619o55HDpVBV7HqJPQIlDb0T/p+rA2s4nP3bh62qeNa9p4FuWk8bqNRcOue9u2Ml6u6uCPr9Szo7KdrRWZtPgDY9YXH2nv6U4KM5x8Lh60HrCpzMcfP3ghHX0h1hQl/75num1ctcr4iXvHeeWD19e09/Hlvxyh2OekvrOfy5bn8tU3rmdvTSd7TnfwradOsCLfQ266nWcT9PUyMrIzJ/QaBuJki7LdnG4zjgfqu/o51drDivx0dlZ1jJrl1DzFbe7fjzbzvgd2D874f826Ar75pg209Ybo6g/jcVg4pzyTPTWdvHVrKb/bXTvYW+3Jw034AxFMAs9+8rLBOtoDluR6WJLr4ZJlubz9h9sH+50tzUvjYH03DouJrkCElpZeHny5ltvPL6O6rY+3/3A73XP4JLKOyM0R/3TxIn798mn+7+nEGYomMc5wpDksuGwWKsfIAM712PG5rMOyhofaV9fFklw32fH6LSOzoUp8Tlp6guNmgwyo7einP8EUpAN13SzNS+N4PEjcE4zwclUHm8t8WE2CQtEXinK6vZ8Sn3MwS3pdsZdQJEZhhmPYD8OWMh817X2sLPBwvKmHL9+ylq0VmTqwnIRSai+wZcTVb09y33rg+iGXHwUenbHBaYMauvr5ztMnpyWwvKYo3TjD2taXcMr8bPjQ5Uu4bu30Ta/RNDCCOnariQznxDuzjyfLbcNiEk539LG1IpM9pzsIRxWLc4wsJavZNCxQeyZsFtOMZhSOnBW0KMdNTpqdytZejjef2awFq1nIdNu4ZFkOt59fzuKctMGT19etLWD36Q6ePNzMl29ZS1GG84yeS5s9IsLbzy2jPMs1WMqiNNNFjsfOjesLE54k2FCSwYYk02UHxGJqMGColOINm4t5/89380ptFxaTzHq99ESsZmMcA8kKaTYzRT4nJpPQ0Rui2R+ksStA4zRlHDf5gzQNOaDO89gpzjQONGviXenP1Cu1XVNurjSdAuEY/kCET1yznG///QT+QASbxUROmp28dDtXrcxjywSDCHORiKQBDwEfUUp1D11PlFJKRBJ+ArpHiVGa8bGDjTis5jPKuhMxTqiebu8fVebNH4jQM2Jbu7EkA6vZhFJG/4SxbKvIZGd1B1vKfPzLVcs4d9HojENNmw0j+1eYTcK33ryBrRWZ/OcfDw3OQt9QksHeCdYQ/8xrE2fv2iymYSUvJstpM/OFm9fwtm2lhKNqsG7zZSty2VTq48pVeawrzmDv6U7qOwOjmmNfuTKPX718mo2lGSzKGbtB/J0XlFOU4SArzT5Yc1gpo97yivx0HjvQOGqZlVM8QbS5LJNin3NwdtOf9zXwlnNKuXBpNg6rmbsuXsRr1hZwrMnPdWsL+PRrVnKqpZfl+R5Ot/Xx1SeO8uf9Dbz7/p385cMXJdyvWp7v4bZzy/jaX48BcMf55XzsN68QiCiWptsp8Tn5zjMn+PqTx6b0GmabjsrNIZGYorqtjyy3bdRUIbfdQkdfmOokXUIHFGU4Kcl0jpuldKK5F5tZWJ7vYWu5j4buAAXpDtr7wvjiTfyeO9E2oXH3h6NsLc9MuMG2mUevRLuqO3DFd+QHAs+haIwNJRk0dwfw94c50dJLpstGUYaDogwXUfVqfckmf5DFOcY0jNJM16jH17T54ESzn/9+/ChPH20Zswb6ZBxp6GZzWSZHE5zsmS0/eL6Si5blkKZP+mjT7EBdF7uTnDSdDLvFxLI8DzGlBmso76hsZ2NJBvtqO4nG1IRKOE2UWaChM4A/Qb+CmTCwPT6TDG+b2US608pt55bynosXD+vvMNKnX7NqStMNtbnhoqU5XLQ0Z9oeb2gmajiq+NO+BqxmE+29wXEDn9lpNuwWMyYTtPpDCRMXpiLLbaPY54wHtSJUt/cNmyLfE4pydApNiaZqZLC5wGunKMNFTBnTb6eS0bmh2Dtmw7PZ4rCaWFvspcUf5O7rVnDVyjxyPPazYkaDiFgxAss/V0r9Ln5100DJOREpAJoTLat7lIDLZiYv3UHDGZ608dgt1LT3UeJz4bCasVtMWEwmdtd04A9E2BKfJTvwe9MTjEyo6Viux85/vHY1uen2wQQsTZtLBk4KB0JRvvjoYc4p901oxsrGkgz21HTS3R8e975TkZ1mHyxTarMM/633uqysc2UAsKE0gy1lvsHg8qXLc3j3hYso9jl438/3jBtYBliW52FZnoeuvjD/8cjBwdIgAzOwvnrrevw/C/OPIXGsHz1fyZYy36RPbHqdVv78oYv4za5aDjd0c9P6QrZWZA7eBrA4N43Fuca4rWbTYH320iwX33rLRj54+RJ+9XLNmNvAPaeNz/DCJdncsqkYt93CD5+rHIytOa0mNpVmTMsx0EzTR/9zyNu2lXHDugJ++kI133rq+LDyGP5AhG0VmeyOZ1YlUpjhoKs/RN2pfraW+xjoDji0vnKmy0p/OMqaIi817f3sr3s1W7JmSOB6YMWZqD01HWyryBw1fTgYUawtSicUURxt8g9mU3X1h4dlTPfHazfnpNk4ET8gbu8LQR/UJWhIdLKllzt+/DJv2VrKl29ZO6mxalqqHWvyc9dPd05rAAsgEoPtle0sznHjc9k4PU0ZUZOxq7qD9Z97grIsF9sqsvjnSxdT7HOeFQeWWmpduiyXfZ+9mo/++hWePDzxpmED2XxOm5l0u4VmfzBhGYz9dZ1sKc/kldrOaRy1Md1woJHmbJSpCUSmFpATgZ/cuZVtFZlYTDIv6qBqc5vNYmJbRSaf+f2BMQPLBV4HuR47FdlGX5EnDzedUWDZaTWzJDcNp9VEXWeAus7+GanvOl0auoLxEneGogwHBRlOojFFZWsvnX1jBwQ2lmawZw4cdK4qSKfA66C7P8zbzi1jfbH3rNn2i/FCfggcVkp9bchNjwC3A/fG//+HFAxvXhAxpr4/8kr9lB9jfbGXqFIcqOsetQ+dnWYjO82OMDyD/1hTD0UZjoTHkwNyPXa++/bNugSGNi/ceUE5zx5voaqtN2mC34CB0mhbynx4HdM3+2+qcjx2btlYxHsuWTwYiO0PRfnvN6yb1ON4XVauW5PPH/YavyfL8ozHSrNb+PEdW/n1zho+83ujtVSzP8iHfrmHr7xhHY8fbOQT16wY1gxwLA6rmbefQX+vpXkePnPD2AkYd128mAyXjbdtM2a1XLM6n8uW59LsD/Dz7af5y/4GDk1T6cyZpoPLc8xnHznElnIfj3/kYj7zhwPDzrpsr2xnS7mPnQnOUFVku7GZTYNlJIZmL6zI99DUHWBproeqtl76+8Ljn+VSCo/DMuFpvOGoYntlO+uKvewbcvA8cGbKbTOzONsoxZGsfmV/OIrDZkaAdKeF/HTnuJ2C/3a4ieeO509r1o2mzZTGrgBff/IYv99TSzAyc4krxvSdXrZVZM56cBmM+sunWno51dLLL3ec5smPXsKS3PHPRmvaWEwmId1h5UuvW0MgHOX5E61J72s1C8vyPLhtFtr7grT3hOkJhodlC44UicHOqnZcNgsBpq9G7MD2dmu5D4/DQk8wMqrG7ZkSgUKvE7fdzIEk9aMTKcpwcvmKXN66rZS2nhAXLs2e3oFpC15Jpotvv3UjGS4bt/1gO/3hKFluGxctzWZJbhoeh5Wu/jD/89TxwZMvbpsZm8U04WZFFdmueFBJ4lmK3UnrqM8HRkD81UBYeZaL3HQ7gXCMk8099A4pKZAosSNV6rv6WVfs5aYNRawuTD9rAstxF2CUltsvInvj1/0rRlD5QRF5F1AN3Jqa4c0Pr9tUdEbBZZNJeOX06HXbLBBTCqtZEh7jZrptg+uUzWJiRZ4HBeyv62JbRSb/ctVSNo0oQ6Bpc5XFbOL779jCpx7axx/21rO1PJO6zv7Bnlhep5UV+R7qOvsHZ7PvrO4gM82WymED8LGrl4+6zmkzs6Zo8s2grUOSIIJDEitsFhP56Y5h9+3sD/Prl2v46FXLJhxYni3nLc7ivMVZdPaF6A6ESXdYsVlMFPtcfPDyJaTZLXzzb8dn5LnVNB+QTDi4LCJmYCdQp5S6QUR+AlwCDPzC3xGv8TpyuduBf4tf/IJS6v4zGvFZ7nBDNw/vqaMsy8XXbl3PkYZdw7ItEu2mjTcl4kijHxFo6QlOKNC0tdxHMBKjJxhha3kmiKK+M0BtRz9ep4XF8SkLIoLFJNR29GMxCbnpdhq6jPssyfEQjSn2xjPAekNRTCbG3QE+1tRDkc9JpsvG/roucj123HZL0g6/zf4gd/z4ZX50xzlcskwHmLW56YmDjWS4bHzyt69Q1daHx2FhWZ4bpdRgrfGZEAxHWZzjpqUnSHd/6or/76xq18FlbdpYzCay02ysyPeM6hngtJnJSbPjdVqGzcyZiC1lvhnP9vcHIqzI9+CwmidcIy87zcbinDSiMZWwlvraIi/V7b3DGu2O55rVeRRmOLl5QxHrx6mhq2ln6oqVefQEI7zpnBION3Tz3ksXU5rp4uZv/yNhuZjeCdZjXZaXhs1s4kB996SaGs03VW19g1maAizJTSPLbQQJ5kpgGaCzL0xnX5htFZnzslHfWJRSz5P4MAzgitkcy3zWdgZN/LLcNuqT9AOKKsj1OHDbLFjNMmyW75Yy3+CMJBEozXSyr64LAdLsZl6zroBzF+kTq9r84rCa+cabNnDR0hw+98eDuKzmwZl65VmuhNuGmvZ+1hVnzP5gZ8jQJtkNI2YmHIsnKK4uTOebb96Iz2XlcGM3//zz3Tz2kYtndZwTleEaHfx32Sy8/7IlvPOCCiKxGKfb+3i5sp0f/aNqQg2FZ9tkMpc/DBwGhs4X+YRS6rfJFhCRTOA/MJqKKWCXiDyilEp9UbA5SCk1eFBb3dbHB3+xh1s2F/H3I834XDZeruqgrSfE1nIfB+q76QtFyXTbJlQ/J9djH+yoOZatFZm8XNU+mFU1MM0ix2NnS5mPmFK094YSTuevHvIF33W6A4tJWFOYzuGGbjaX+9hR2cGly3KoauvFaTMTisQGC6QPVdfRT1185yEcjdE1znTANLuFi5bonQJtbgpFYnz1iaPD6r35AxH213Xhc1lZXZjOwWkMMGe5bSzJTaO2s5+9Q2YRDATd0p1GU1CUoqUnRE17L9NU8nmU8iwXH7t6OTes0w3+tOmT6bbxjTdv5EBdFzf/7z+IDJn/muG0UtPex+kpPG4kFpv2wPKWMh8KCISjgzOKBgLi2yoyOdTQPWyGUGGGA0GGBYpLMo2DhMIMB6sK0ukLGQ2y0h1WQpEYPreNQ/WJszSX5qaR73XgdVp545YSGjr7OVjfzb9ev3LMOsqaNt3S7BY+e+NqwNjfve6bz+G0mRFhsPN5WZaRgRyNKUKRGNVtvYOB5ky3FYfVTIs/yPriDNp7QxOqo3q2UUBVay8eu4U9EzxBNVl2i4lwNDah5oCFXgdvP68cEdhX28k916086wLL2vRZHp+6PllbKzKxiPDCqeT9gAa2rUPLBBjNzjoo9hnNSpVi8CStySS879IlvOO88imNSdNSTUR4w+Zi1hd7+fwfD7E4N40TzT2EookP7M6mn+ZwNMa+IWXsluQNT2K67dwy7BYTOR47oUiMC7/yd966rZQ3bimZ5ZFOD2Of3czqQi+rC73cfn45zx5v5Tc7a9hb00ltkhNvs21CwWURKQZeA3wR+OgkHv8a4K9Kqfb44/wVuBb45STHuSBUtvbSPiRLub4rgIoZzfegl83xAuinWntxW02syPfQ3B2YUBOSYCRGVpp9zAPnlQWeYfWZh2rxB2mJL7sif2I7BpGY4kRLD+kOKzsqjQ15bygyGJieSFf57kCE8iyXUX85zmISFuW46e6P8JErl3L5yly9I6vNCQNdq0+39fLTF6t59EADnX3hpA37OvrC9AQjbCzNIBp9tbnYVPhcVkoyXRyo60p4tro/FE14htPnsrIsz0NVa++wkgHbKjKp7ezHY7fgspkH668qpVDKeK2RmCISi5Fmt4yaPXH92ny+dusGHFYdwNKmn1KKQDjKtopMOvpCHGvyU57lJs1upaM3RGAKZ0xeqelibVH6pDOekynNdCXMNB6wvbKdLLdtcFr70OntxRlOnHYzJmSwNEB9Z2Cw9NVIm8t8uKxmDtR30dEXxmYx8bGrlnHXxYvOtqnp2lmgpSfIVavy+NvhZrr6w5y/OJurVuXS0BXgsYONmEQoznDisps5Ut9NTyhKTzDKouy0YcGhhchuMbE0N23GAstgHDOcU+7Dajaxv7ZrVHa5xSRcvCyH164v4JrV+cYJa02bgKXx2QbJgl+JbCrNYEdlO1vKJla2YkdVO2sK0zna5OdYUzcbSnyIMGw/dUuZj/9363rKstyTfg2aNtcszfNw/zu38p1nTvLCybak8Z6zqZfGk4eaBpMh3TYzG0fMwvM6rdyyqZh9tZ30h6NkuKx09Ye4elXe7A92BogIlyzL4ZJlOcTi1QK+/OjhCTV4nEkT3Rv4BvBJYGRU8Ysi8u/A34C7lVIjv8lFQM2Qy7Xx67QEEtWHO9bcw+YyH7tPd7CrugO3zczyPA+dfSHSndZRU4KTGWgGsq4ondqOfjr6wgxNSLCaBUk622u4I41+yjKdVLePfYZEBAq8zmElLYbuTPSFImwt99ETjCAiCbM3ozGFAkp8TvK9DmIKLlicxUeuXIYI+qBZmzP213Xywok2Vhd5+fAvd+O0WSjPchPxKSLRGMFIjDSHhX21XcPqSIajarARz5nUTlQwrN75RHX0hQefc1OpkQ1WlOGkqz9MKBzjSMf4vzE+l5Vzyn0oBZcuz+Xt55XNuXpWZyMRqQL8QBSIKKW2xGcM/RooB6qAW8+22UK1HX1895mTPPDS8PzkEwlmwkyU1SysKkg/oyZiA9YVe7GYZEK1j9t6Q4Qbu1mam0YgHGVDcQZ7azupjWcuu21m7JbxDwZ2VXfw9nPL+MQ1y/nAL/fwuRtXc9mK3DN+LZo2E9p6QizJTWNdcQYVWS6eONzEj/5RRWd/mMauANGYYl+86p7PZWVbkZdjTf4FHVQGI/u7KMMxo+W0wEgiWZLr4c4LyunqD/Pzl6rxuW3keOz8YvtpMlxW3n/ZEjZPMNinaQMcVjOXrcjh8YPjN+XN9dgp8TnZFd9H7g9PvLxbW2+QRdlustJsvHBy+H71+mIvP7z9HLwuvZ+qzU8//kclb9laOiyBx2QS/vnSxVS29vLbXbUJlxtZh3g+OzBkxl5vKMpLp9o5b3HWsPv0h6Psq+1iS7mP128q5mcvVWO3mNm2KIu6zv4JJTrOlkP13aMaivaFIoQjatzfKpNJ2FTq48H3nMfPt5/my48ennB5sek2bnBZRG4AmpVSu0Tk0iE33QM0AjbgPuBTwOenMggRuQu4C6C0tHQqD3FWSJTO/uyxFlYVpGM1GWd5e0PRwSZ36VMI3jisZtr7wuR7HWS5rQiCy27BZTXzj5OjmyPZLaZRWZcWE5RluccMLhd4HWSl2TgwIgOsqrUPh8VEIBKjoy88OE149RjdeVu6gyzL9wyeidlV3YHPbePOCyom/Lo1bSZ9+6njfP3J41y5MpfvPHPSOJnTGx5cp61m40e/sTswZuH87ZXtLMpxk+mysed0BwMl49YWpROKqDEbXMaUwus0GiNN1e74Dvzg7AKfc7B+11g6hjQJ3Vndwd6aDj5+zXJW5Ouu27PgMqXU0B/vu4G/KaXuFZG745c/lZqhzYwfPFc5KrB8ppbleQabiU2GxSQU+5w4rGbqOvvpDUaobe8fNttmPN39Ebr7E89A6g1FJ7yD+LOXqlmal8ZX37h+whle2uwTkQzgB8AajPOC71RKvRi/7WPAV4GcEev1WWVlQTorC9KJxhTPHmvBZjaR67FzpNFPRZZr8ERRmt1CMBydU3WFUyXTbcXrtE1otuJk2Mwmrl6dR3mWm6V5aWS6bSzP85A7JAhxTnnm4N//fOmSaX1+beHZUOIbM7i8tTyTSMw49hwILAM4rBPPkG/oCpLrcbC98tUTUj6XlX+6eBHvurACu0XPqtPmr2QxEBHhv16/DqWMkzHeeCLizRuK+MKfD1GQMfPB5Vh8ZqttAokRZ+J9ly6h1R9iUY6bVYXpFPtGB4qLMpx86IqlgJHJ7LCa+MDlSwdvmwuauwMEIzG6A8OP37v6wnztr0cxm0z8+2tXTeixRITbzi2jsrWX+1+oGlY2cLZM5Ff6AuBGEbkecADpIvKAUuq2+O1BEfkx8PEEy9YBlw65XAw8PfJOSqn7MALUbNmyZfbfhTmitiNxUe7jzf5hjQkGpDkslGW5yPM4BmtLjUUEgvHM4cauAI1dr06vXZKbNqp7/fI8Dy09QTaUpLG9sh2TwJayTCrbenn2eCtbyzNp7wuS7rDySk0nUWUEo4oznNR39Y8KLIMxTThRhrYrQe1Hr9NKsc+J02bGLIJZGAy2/e/fT9LVHybX4+BN55Rg1mUxtFnW0Rvib0easZqFrz5xDCDhzvLiHDfpDgv1nf0UZjipTlCvfKhTLb2copd8r4NCrwOL2TRYriY/3UFuuh2LSbCaTRyq78IfjGI1QYbTNu2F/Zu7A2SPU04nkScPN/Pk4WY2lGTwuRtXs67Yq2cZzJ6beHW7ez/GNvesCS5HY4pfv1wz/h0nyGM3U5zpGmz8AUYDvdZxmg5ZzcKyPA+nWnqo6+gnHFNkum2sLPBwqH5iM4pmwo//UcX9d27VpaLmtm8Cjyml3iAiNsAFICIlwNUwpZLh84pSipMtveyqbiemjH3Dv4Vj2MymYZlYBV4HJ1sWXl3lkfLi2/1kza0nw2ISNpRkUJrloizTzcoCD8vzPbo8gDZrNpVmJLxexAgA94bCHByxHTUJ4/4WZLptZKXZ8Lls1Hf2DzthvCLfwwPv3kZ2mv2Mx69pc5nJJHzl9Wt5/GATrxnS8+biZTlGY+iqdlYVpuOyWTjd1oc/GGZVQfq0Had19YeJKUXWDK9raXYLX3nDusHLL51qoyTTlfT+A7WKhwpGooQiMTyO1M1isJpN7Kru4Lq1w/sTOWwm/rSvgQ1TaLr9iWuW8+LJNg41zOwsp0TGDS4rpe7ByFImnrn8caXUbSJSoJRqEOObeDNwIMHijwNfEpGBFJqrBx5LGy0nzc5btpbwyx3DD5wTBZYB9pzuZFG2G6fNhN0iBCNjx+U3l/qSTik80dwzrLGY02qmvTdEe2+I7ZXtnFNuNPMbGsQe+ndZlouyTBfPn2gdbMaXyKkkOwY1Hf1sLvPR7A/Q2RtiZaGXmva+pI3OWnuCfOPJ4wCctziLimy9U6xNrxZ/ELfdPKqWYFVrLyYRQHGovpufvlg1eJvPZZwVFRE8dgtel20wMCwChT4nXqeFrv6xp/ZluKwUZzg52ugfVuuwsTtAY/erJ4UcVhPFPid56XZ2VXee8WseKRxVZLishKKxwdI6k7G3ppOb/vcfFHodnLc4m0uX53D92gJ9Mmj6KOAJEVHA9+InavOUUg3x2xuBhMXF5uuMIbPJqDH22MHGaXk8fzCKw2I0yDAJHGv009oTYmOJl2NNPUmzhsNRhdtuoT/86syegW1mKlW29nLl157h4mU53LKpiOvX6maac4mIeIGLgTsAlFIhYOBL83WMEnR/SMngpsHJlh6cVjOFE8gIOtro53CDn5+8UDV4XYbLOphps77Ey+H67gk1lTublWQ66Q9Faeo+82ajW8p83LShkFs2FeO26zrJWmqMPJEhAmsLvdR29NHZF6a9d/T+ZkxBOEkvBYsJyrPTSHdY6A1F2VXdMdgDZUBhhlMHlrUFw2I2DQssA1Rku7ntB9t5/oQxKeq6NfkEIzGeOtLMuy6s4Pq1+awu9GKOJzBNlc9tO6OxT1Vrz+S3kXaLGVuK61D73LZRgWWAP+9roC8UpW8K5S0cVjNXrsqbm8HlMfxcRHIAAfYC7wUQkS3Ae5VS71ZKtYvIfwIvx5f5/EBzP220lQXp+KvacVhNBMITa3SQ4bLyzLFWNpR4sZpNtPiDOKxmbBYTXX0hrBYzPYEIVrOMW6vO6zTqpppEaO0JcnJI/cqGrgA+V/Ifi+q2PrwO65gHAWl2C3aLKeHB+kAm9dqidAq8zqSNBYcqzXTxlq0leBx6B1mbPnWd/bxc2UY0Zpw02Vjqw2wS2ntDtPiDeOxmnjraQmtPkIEZPwJsKfex+3QnHX2JVwKlYPupdvLTHazIN6YDN/sDnE5QXqYi2z2h2pKBcIzajn7C0Rg2sxBKciLqTLhtFvxJpuxPVH1XgId21/LQ7lr+9+8neMd55Vy5Kpdcz9lT+ytFLlRK1YlILvBXETky9EallIoHnkeZzzOGvv3Wjbz3gd08eXj8mo0Tkagx1p4ao0bbzrEaY8zRdy0UjfHk4SZePNmKy2bm0uW69vIcUgG0AD8WkfXALuDDwJVAnVLqlfk8y+O+Z07x4K4abttWxudvWo2I0ZDycEM3hxu6yUqzc6Cui46+EE8ebqK+M8D6Yi8iRmm41p4QXf3hM+o/cDYp8Dro6g/TPc4J6WRE4JJlOWS57Xz06mVzZhqwtrDleux47JbB5ImV+R6ONHaPuQ9bmOEwgiwjjiGLMpz4A2FONI/eT8102zAJrC/O4F+uWja9L0LT5olINIbFbOJkS89gfGVruY+6jj4a4yctf/h8JT98vhKzSfC5bDz4nnNZlJOW9DFr2vvYfbqDmzbMnVZqU+0BMFf3uf5xoo2rV+fxtq2l9AQjpE3yhPCtW4p54KXqcZNecqb5pNukRqmUepp4WQul1OVJ7rMTePeQyz8CfjTlES4gP32xmur2XjwOK4Hw2GdfBNhakcmueABqb03iWpGrC9Npi0Rp7E6cdeiwmlhb5KXFH+RIoz/pF7C2o5++UBSbxTSsGdlQBxu6WVOUnrAcxsBYxjpYsJqF5u4gTf7Ry3vsFqwWob03jM1iYm1h+mDd5aFTKDXtTBV6HdgsZk4297CqMJ3vPnOS3+ysiU/zgZs3FHL/i9WjlhNkVKZEIiOzj8+Jb+BtFjNZaTbCUUVkkkHitp4QXqeVthnImjSbhHSnlY4pZC4ncqTRz78+vJ9/+z088O5tnL84e1oedyFSStXF/98sIg8DW4GmITOLCoDmlA5yBljMJn5w+xZeONnKb3fVcqi+e8LNbSejvrN/zG3eiZYeluSmDR7UptnM+Nw2GrsDSWcczabCDCcbS3Tt5TnGAmwCPqiU2i4i3wQ+i5HNfPV4C8/1GQc2i4k8j4OfvVRNbzCCx2HhcKM/YcKAw2LCLAxOXc/z2NlansmRxq6E+4o5HjuLst2cau3FHwhPOAljPivwOgZ7IUyW02rmfZcu5oOXL5mzB8/awmQyCdetzefBnUbTsTSHddzkiPrOAGsK0+nsC2MxwZJcDzaLid5ghLrOxCdf/vjBC/UJFW3BO9zQTVtPiM//6RCh6KvbzX0J4jXRmKK1J8j/PX2Se29ZiyVJVu+9jx3hz/saOFTfjYhwzeo8Vhd6Z7zO8lgKvGfXun64oZsLlmRR6HNOOrAMUOxzcd/bN/Om+15KGp+wWUxsW5SV8Lap0imfc4hCUd8ZYHleGuVZLhRgQjjR4h81RchqFl6p7Ry3UHd3f5ieQPKMh3XFGRPKEgZjyu855b7Bxl0jmQQyXTacVjP94dHZyQ1dRoZmeZaL7v7IsIZHWyt81HUEBu8DsKrAg4iRnRkMx+gLRzmn3Ed/KMqu050syU1D7y9r001EuHpVHpa1BfgDYUKRGEvzPPz1kJElmSiwvKk0g2Z/YNT1E/FyVQdbKzLZUdk+2EhvsiIxRVaajZ5geNzyOJO1s7oDr9PK1nIfJ5p7aJ+mIHNMwccefIV/umgRt59frktlTJKIuAGTUsof//tqjKa6jwC3A/fG/z9vp9iP5/zF2Zy/OJsfPHeKL/z58LQ/vj8QYX2xN+k2r703RHmWUd8tz2PH57ZxrMlPTBkzGapb+3BYTdSMUSpqptgsJr5z26ZxO0xrs64WqFVKbY9f/i1GcLkCGMhaLgZ2i8hWpdSw+i9zfcZBvtcxePL0d3vqxrxvIH7SJj/dQbHPyZ7THTQlqO9vNgnri73886VLqGrr5dcv19AbnFom73zTG0w8HXZtkZem7sCofggicMHibK5YmcvNG4pSNj1Z08bzoSuWsr2ynfaeEP7A2PuV2Wk2TCJEYoqNJRkEI1EONSQ+oXzR0mwuWZZDMBLTgWVNw6g13NAd4Ltv30wwHOOFk62DyYnJ/HZXLTXtfRxv7iHLbSMSU2woySAcjZGf7uAv+43qe9979hQAP3z+FFluO5vLfZy/OAufy8avXq4hEo0RUwqXzcJnX7ua0qzkNZGnQ1d/GK9z9vd7lVLTfhL3K69fx9K8tDNKomzsDuCymoeV2BwqFInxzLFmLl+RsILilOjg8hwRCEcHD2BHdoJ2WU1sLfdxoL57sO7KhpKMhFN5h9pa7qO9L8yaonT213UPBqKtZiHNbqEi241zkl9YIfmKYzYJe2s7WVfspdkfxGY2YbeacFrNNHQFyEu309AVICvNOAinVQ0Gqpq6gxT7nLT2BAhGFMvy0jjc4B8163ggs9psEooynDR3B8cs3q5pU/HciVYuW57L4QY/3/zb8THvu77EO+XMogHd/WHyPPaEB9YTsaXMKGfT7QoPTnGaTl39YV6p7WJVYTrtZ/hah2roCvD5Px3ij/vq+dm7tk3pzOwClgc8HN+ZsQC/UEo9JiIvAw+KyLuAauDWFI5xxj1+sJH/evzoqOszXVZcdgu1ZxDYrch2D26XnVYzCjUqW3LgstNmxuOwDJaGeqWmk2hM4XFYyXTbZr0WcygS4w3ffZGfvXMba4u94y+gzQqlVKOI1IjIcqXUUeAKYLdS6oqB+4hIFbBFKdWaqnFOVYHXQX66A4fVhN1iZmtFJi67mfMWZdEdiNAcD4i2+oOkO61kOK0szk1jUY4bpeCRV+o52dxDutNKusOCx2FlaV7a4NTbUCTGqsJ0XjzZxvGmHl6p7aQh3pw612Nnc5mPvxx4NR5flOGkrnP2T+5Ml2hsdHa2zWziMzes4sGdNVy4JJsHXqrm1i0llGS6WJzr1uWmtHmh2OfiXRdW8POXqjmcJFA8wOeycby5Z9zm0nnpdr7/ji16RqumDWGKx0wGrC328qVHx07I2BiPM4UiscH910QNZQu8dnI9Dl6p7aKxO8Cf9zXwwolWPnfjajYUe+kLRVlb7OX8xdnkeOw0dgXI987cNioYjkIKgsuHG/ysKkyf0H3ve/YkWysyKfG5xmx6OB377teszueBl6rZVd2RdEalf4wk1KnQR/JzxP66rqQp633hGDvi2Y39oSjpTovRnX6cKUTBaGxwuq7DYmJTqY/+cIRITHG8yT8YEFtV4KGytQ+LWcb9gtV09LGhJMOokRzPTrGYjLPJgXCMRdnupKUvHFYTS3M9NHYHqOvopyjDydY8D939YY40+jnd3se2ikz8gQjRmBqznOWm0gyeOdbCm773Iq9ZV8B1awvYWJIxeNYoFlOIzN06OrNBRDKAHwBrMKqDvhO4BXgtRgOhk8CdSqnOBMtWAX4gCkSUUltmZdBzgFKKLLeNN373hWF1x9cVeXFYzfHsXWNDuzjHTVvPmQeNjjT62ViSMeXg8v66LlYXpo+74z1Vm0ozqO3ox2oyYbQynF5rCr2TPtG10CmlTgHrE1zfhhGwOut194f49z8cIM1uIWZT5HjsZDitBMJRDjf4ae8L47KZWZzjxmm1DGtCOxH7ars4f3EW/eEolnhm/a7qjsEAsghke2xstvmoau0dNvNgYPvc1R9ma3kmO3rbyXBZp9QYc6o6+8K894FdPP2JS8+oOYs27T6I0bfEBpwC7kzxeKbNTRuKuHF9YdKptONZUzT2wZTNYhqcsQDG9vpgfTdN3QGcNjM/e7GavHQ7ZhHOXZSF12XlHydaOdZ0Zn0DZtLAPvSly3PYVdVBWbaLVn+I0kwX60q83HGBm4uX5hCKRqnp6CccMTLH7rygnNWFXq5cladPzGrz0vmLs/iPRw6O2zPkdHsfaTYzPeM0trp5Q5EOLGvaBNx5QTmbSjPo6AvT0NnPi6fahs3S21/XicdhTVgWbuhxYEmmix2Vw7OgO/rCHKzv5p7rV45adiYDywC56TPz+IFwFLvFhIjQ2RfCajYNa4o70cDyQ7tqufcvR9j1b1fN6Myi3ac7+O7TJznd3sely3PYc7qT2WoUo/dG5ojxpicAg+UrnFYTZVlutpT5ONLopydBqvvWikyqh5xhCkRiww6sSzKd5KY5iClFS08QkxhdeM8p99HeGxoWVBuqoStAQ1eALeU+ijKcmEzQ1B0gzW7FbjXFv7yJpTus7Ilnc4HROK2usx+LSTh3USaNXQEO1nXhTzINcCgVXz/quwJ8/7lKvv9cJcvy0rhiZR4nmnvYV9vJf79hPRcvyxn3sc5i3wQeU0q9IX4Q6wL+CtyjlIqIyFeAe4BPJVn+svmYOXWm2ntD/NNPd47qzG6zmAbXIafVyFJMtp5MxYnmHpbmpnE8QVOS8QQjMXaf7sTnshKNKUozXRyon54OsVvLMwdf90wErzeVZvC5G1dj0mUxtEnq7ItQluVmbzy7IlHgti8UZX9dNyU+Jw6LaXAq/kQFI7Fh2zWrSVhZ4CHNbqG1J8iuqo6ETWqH2lHVztaKTLr6whR4HeNmaU2nus5+PvrgK/zPWzbO2nNqY1NK7QWSnrBVSpXP2mCmmVHeaPZ+y0WENUXewaD0ouw0HjvQQGVrL88ca6Gqrc/YVxXGbDidKv9502qW5KZhEqGzP8wnrlnOqoL0pIkRS3I9o67TgWVtvlqS6+EDly3hf546kfQ+A/vbM5U8oWkLUYHXOapG8T9OtPK3w82cbOnh3EVZrClMp7E7QFtviFdqOnm5qoPFOW66+sN09IZo8gcJJ9mn/t6zp9hV3cG64gwUipr2Plp6QnzgsiVctWr6SjDMpGhM8R+PHMAfiLCruoN7b1nHhUuzcVjN2MepLX2ksZslOWnDTrRHojH+6/EjfOTKZTMaWK5q7eUt971EMP7Z5KXbZ7WMrN4jmSN2TiKjqj8c42ijn5WFHrLTbKzI92AyCU1dAZq6AxT5nIQi0TGzID12C7tOjw5ov1zVES/DkTlmltfRRj+FXsdgCQ+z9DNe/6Kd1R0JO4BHYortle0UeB0TCiyDcRa7Its9bIrGsaaewewUj8NCeZZ7Qo91NhIRL0aDoDsAlFIhjGzlJ4bc7SXgDbM+uDmuoStAfrpjWHB5a3kmR5teDQj1h6MJ64qfCX8wwoozrI860HRvvFrsE5HrsZOf7qC9L8T6+NScgcZL0yXLbeNLt6zVgWVtSkqzXDz4nvNo7g7wpvteSjhlb0BUKZblezhY1zXutmqoXdUd5Hrsgwe2JpORaThWc9pEBk4Ob6vInNRy0+HR/Q1YTcKXblmrs7q0s1q+18EdF1QQjSleONnKwfpuvv3UiTkZWL5xfSF7a7pYVehlY0mG3g5qC9L7L1vCXw81JW3Kq1AEIhPb3355krOTNE171QVLsrlgSfIm67GY4uljLdz37EnqOvrxuaxjHm/urO5g54jkyR88d4rLV+RiNglVrb0U+ZzjzqzrDRqz7qejlnJPMILbZp7QzHZ/IMzbtpURU4o0u4WyeFxpYD+6PxTFaUu8T/3SyTYKvE68zldfW384yh3nl/O+S5ec8esYy389fmQwsGwzm6iIN0Kuae/HbjFR5HNyahqT40bSweU5IBiJ8tKpiW0QBdhc7uN0Wx8uq4VD9f5RTcBOtvSyujCdZXlpw6YCep1WijKc5KbbefpoS9Ln6AvHONLUjddppat/dCZYltvG6sJ0qtt6qch243NZOdHcg89lo60nmHDaktNmZm2RFwGW53mGBerAyEQu8bmo75xYUzS7xUSOx053f5i2EbUsl+Smcf87ty70Rg4VQAvwYxFZD+wCPqyUGvpr8k7g10mWV8ATIqKA78WbCI0y1zvXT8XSvDTqu179HlpNQkN3f8J1YSrSnRaKM5yDzUgGap+77Waap6FestkkeBwWijIc1HcGWJKbhs1iwm4x0ReK4nVaUQoONySfJbAi38OxJv+oTJEV+R7ae0PTkkGyKMfNZ25YxYr8iU0l0rRkctMd/POli/m33x8Y3KEaqb4zgMc++R3TskwX1e2vbmODETXtJ1lmWjSm+N2eOo42+cn12CnIcHLPdSvwOHSzP+3sZDYJFy3N4aKlObxtWyn/9/RJHnixOmlTm1Q43tzDhy5fwuYyX6qHomkp47Caef2mYr6YpAZsIBxjTfz48XB995ilMVw2HdbQtJliMgmXr8jl8hW5VLb0cKSxm6q2fpbnp9PZFyIQjtHWG+JkSw8CXLQ0h1A0xrPHXo05VWS7ufJrz+Cwmjnc0E2ux84Pbz+HtcVe/rSvnuePt/JPFy9iUbabYCTG7/fUcaihm4d21fLdt2+mvTeE02pmRUE6pUN6bu2obOf54y0U+1xsrcikPHt0gmEspvj+s6fI9dhZlu/hnPJMgpEof9nfSGN3gF/uOI3XaeWrb1zPsjwPGS4bGa7kGcZVbb2EIjHWl2SMuu2OCyqGXe4JRthzupN/umjR5N/4Sajv7Odvh5sRgdJMF5csy6HA6+TJj17CqZZeluamUdXWx5u+9+Ko+Nl00b/Cc8Bzx1oTlrZIRAF1Hf00+4NjBngO1nezvsTL1vJMECOArZRRQ7Kq1cSqAk/STrsA3f0RNpf52DukjEVeup1in4tWf4Bnj7ciYgSFKweWCUTi9Zj7RzUVK/E5BzO3ADaXZtDQHRgWTG72B9la7mNH1fCzXKsLPbT1hEh3WvE6rVjNwsH6bmoqRzdpsZlNXLQ0e6EHlsFYtzcBH1RKbReRbwJ3A58BEJFPAxHg50mWv1ApVSciucBfReSIUurZkXea653rp8JuMfOJa5bzx1fqee54K7npdtIdVmDyTYG8TgsV2WnYLSYiMUV3f5iqtl6ON/ewrSKTrni98ekUjSleruqgyOck12NPWmbDaTOztcLH4Qb/YK11s8Dy/HTqOvsTZnodafSzudRHsc9pNCybwiduNQvvu3QJd128SE/n1abNG7eU4HFY+NAv95I30GCkpnMwq8JiMuqkTeY7W+C10xua3mBUTKXuZ/JgfTcH438faejmO7dtJm+G6tNp2lzhcVj51LUr+PAVS3m5qp1wNEaW25iNEIrEcFhNmESobO3l+ROt1HX0Uxk/aJwOK/I9vO3cMnZXd/DssRaiSrG+OINr1+Rzzer8aXkOTZvPrlmdz1ceO5I0CzISVdgtJnpCUcqzXEbfoQT3renoQym1oPvtaNpsqMhJoyInLeFtkWiMmDLKSQKcaunhwZ21PH20mbrOfp74yEU8f6KNf3lwL2uLvDhtZnqCET7wiz2AUYv9s48cZFd1B8vyPNz3js1sq8jiXffvHNwu/+qucznV0sOmMh+f/M0+HjvYOGwMFy/L4fWbithV3UFPIMK7LqrgK48dZVG2m+vW5LMszxMfq0KhuGVTEW/cXEym2zbh34+VBRNPjkqzW2alVGteuoNDn7928LLZJMRiCpNJBse7JDeNP3zgAt59/85pj0GADi7PCS+cbJvwfYsynBPuOv9KTRcr8j3UdfYPa9TXF47R1B0k022lvTd5NubAdOC+UIQtZZn0hSLDAr+JjpH31nQiYgSED9b7MQlsKc/EHxj+PLviNSztFmFxjgeH1URPMIIIXLg4k+r2fgoznPSGIhyo68ZuMdHWGxpskrS6MJ2u/ldryrptZi5bkcudF1SwMcEZpAWoFqhVSm2PX/4tRnAZEbkDuAG4QqnEkQ6lVF38/80i8jCwFRgVXD5b3bqlhPMWZfGabz1HXadxEmSsesi5Hjt56XacVgs2i9GYJBCOcry5h701nQmX2V7ZzjnlPjaVZnCgrmvMZiaTYbeYWJKbhlmEfXXJMyz7Q1F2VBr1swY2OMea/BxqGLtW80A5nU2lGeyt6ZzwdGOzSbhuTT7vOK+crSkoDaCd/a5dU8C33yqkOSycvzib54+3cv+LVdR19NMfjvL2c8tYmpfGZ35/YNSMn0SKfa5hDU6mw8tVHWwu802oz8JM2n26k9d/5wV+fMc5lGS6dLkM7ax2pLGbRdlpXLQ0+cHdZcA7LzSyjfpCEZ4/3sr+ui5OtfTy4qk22ntDmE2StPn2SJluo2ydz22jIstNnsfOW7eVsqnUF69NrWkaGCWuti3K5B8nEh8PH2/y0xeOUprpoqrNaP6+s6p91Mni7DQ7nX3hGa1neqZ6g5FhjcA07WwzsqHvopw07r5uBXdft4LK1l4auoJctiKXL9y8hvMXZYEIzx5rwWO3sCQvDbNJeO640fJpb00nN337H6wu9PLJa5az53QnN6wrINdjx+u0ku6wsiQ3jfflLDZms/eEeOZYC7urO/C5rBxr6uG16wto6AzwxZvXUDIk2xnAbbfwuo3Fs/bezLRE+xaJSm4V+1z87F3buP5bz037GPSvW4r1hSL8eX89AOkOC90BI8BqM5soyXTRE4jQF4pQnu2muz9MWZab3mAEi9nE3poOAuGxMyuONPrxOCz4XNbBeqwAbb0htpT5cNkC1HYkzsisyHbTF4yQ4bLx9LHkZTSG8tgtLMpxD2ZVry3y8nJlOwojADzQ+MhmMRGKxAhG1LBg1prC9MFGZDVDxjVyqvPB+m5WF6bT0NWP02rhf9+2iQ06qDxIKdUoIjUislwpdRS4AjgkItcCnwQuUUoljK6IiBswKaX88b+vBj4/a4OfI6IxhdNmpjsQIcdjp7F7dMmWDJeV5XlGHdf9dUEKvHY8DuuEO9MPBK6W53vwOq0EwlHaeoLUTbA8zFA+l5W8dAdHGv0cnEQzv5MtvVNqTLj7dCclPuew9TSZS5fn8F+vXzdjXXw1bcDVQzIBL1yazYVLR9eP+9Vd5/H4wUaePtqM02amrSc0eCJzgMdhoXoCAeipONTQzYaSDPbVTvzkzEyo7ejnqq8/S3aajf996ya2LcpK3WA0bQYFwzHUJDqlu2wWrl6dP+z3JBSJEYrG6IiXhnLbzdS091Pd1ktjVwCnzUxRhpNin4uyLBfFPqfOoNS0CVqa60kaXB44djwdL1G1vbKdtUXp7I9vs1fke7BbTLT6gxyo7xrzJFKqfenRw3zxdWtTPYwFQUTeCHwWWAlsVUrtHHLbPcC7gCjwIaXU4ykZ5AJTMaRcxQ3rCgf/vn5tAdetyUcpONXay5u2lLAkN41l+R7OX5w1Zl3mj1+zfNjlcDSGxSST2v7GYoonDjXyxKEmbj+vPGGpi7NNjsfOr+46N2Ez9DOhg8spFI0pPvzLPeR7HeR47Jxq7mFdsZf+cJTjTT2cGJIluS9e43Eg22pjSQZeh5Vin3XY/UYq9jlp6goknD60s7oDj8PC1nIfdZ0B6jr7sZplMDu4vrOfmFKDl8fispn58BVLufOCCkLRGB97cC/rirwcaexmcW6aUZPZbaM31I8IfPiKpfhcNr7x5LFh5T2q2/uwmWVCWZwnW3q495Z13LShUO/AJ/ZB4OciYgNOAXcCLwN2jFIXAC8ppd4rIoXAD5RS1wN5wMPx2y3AL5RSj6XiBaTSfz1+hN5glFUFHnLS7Bxr7qE/FCUSUyzNTUOhONHcy/bKdmxm4ZxyH5GYYk88K38yjg6ZllKW5WJLmY9oTLEnSdZzIr2h6KxnQ1jNJop9zqQnqPLTHXzs6mW8YXOxXke1OSPf6+D288u5/fzyYdcbtcqaeOlUG8eaepLOVDhT/aEoe2s6WV2YzqmWHvrHOUk801p7Qvzrw/v5z5vWUNPRx/VrC3Q9Zu2sMh0HijaLCZvFRJrdMpj9pHsGaNr02FaRyU9eqJrw/R1WM5tKM4gpOFjfNXismuW2z9AIz1xfKMKS3MSlBLQZcQC4Bfje0CtFZBXwZmA1UAg8KSLLlFLT26ldmxQRQcQo2/CVN6wb876Vrb2caO4hHI3RG4xw88aiwQD0eA0Ch2rvDdHaE+R3u+v47jMnWVfsZW2R94xex3yyOElpkzOhg8sp8rUnjvL4waZRje32TaBRkFmgNxRBYUyB31qeSUdfiOr2PkKRGEtzjSkFFrPgslqSBn7MYpxBaukJkem2ke91sOd0B2l2MygoznRxpNFPms1MVpp9WFOjAT6XlfddupibNxQNZiXaLCa+9/Ytw+730Qf3crK5hwuXZHPPdSv514f389KpNkSMwHRf/Kx0YYaTVn9wzCLjFpNwz/UruWJFLmVZLh20SkIptRfYMuLqhC1KlVL1wPXxv08B62d0cPPALZuKCISjPHWkBXh1PXVZTaOCTuGoIhiJ0ToNje6q2/qobuvDYhK8Tgtd/ROr+RqKGBvY2XSqtRen1Uya3UzPiOaAb9xczGdvXK2n/2nzRmGGk6tW5XPvX44MZkrNpIP13ZRnuSZUomOmnWzp5a0/MKoo/eVAI3ddvIjzFyfvGq5pmqZp0+XyFblcsDiLf4xRKrIs00U4FiMnzY6IsPv08PJSNouJRTmjG3nNFf6A0dTrzgtSPZKFQSl1GEgUJ7gJ+JVSKghUisgJjPKPL87uCLWpCEaivOE7LwyLFf1ix2m+fMvaSZ3w7egN8frvvEBl66uzd1PYFuWsoY/6U+SG9Ua27fVrC9h1umNYJ83xZKcZDcaONfWMaup3weIstle2kagPycaSDLoDYbLT7ESiMeq6AgmD2QNBos7+MFvKfIQiMU609LCxNINoTNHUFeA16wopz3Zx3qIslsaLoo/la7duGHb522/diFJGHZivPn6Ub//9BADd/eOn5l+6PJfbzi3FbtE1IrWZc+XKfJbkeNhX+wKtPa9uwPoSZBkqjBNDeR47HodlWI3zqYrEFA6LmS6SP5bHbsY/JKh7ur2PTJeV9mme4jKW/nCULWU+atr7KM504bCauO3cMq5bUzBrY9C06XCypYdPP7x/VgLLACaBjr6Z6dZ8Jp4+2sLTR1v40R1buHxFXqqHo2mapp3l7FYzS3LTCEcVO6raE94n3+tge2X7sGbwQ71xc/Gc7h8QjsZ0z5G5oQh4acjl2vh12jxgt5h5/lOXc6K5h0MNXfz340fZc7qTa7/xHF9/0/oJ11B+9EDDsMDyktw07n/n1oQ1irWJ08HlFFmW52HZVUZQ9tH9DZMKLodjalRQGWBzmY+Xq9qHBZbNAquLvPSFIvSFopxu7xusr7q1IhOTkHQj3dgVoLHr1dv2nO4kP93B/e/cyopJdMhMZGDqA8Bdlyzi1i0lbK9so6MvzHeePjFYf9q4r3G/i5bmsLownVUF6TqwrM2K8mw377ywgv9+/Oi4ZzNz0uzYrWaapiF7GYzvvc9tG/V4hRkO8tMdWMwm9td2sbLAQ4s/SGtPaHAGQHGGk9rO8Wshnymn1cyGkgxOtfbQ5A+yqczHPdetpDTLNf7CmjaHPLSrlo/95pVZe76luWn0hiLkehxJm36m2r7aLh1c1jRN02bF+y5dwg3/8xzbKjLZV9dF/4gTvY1d/YM9e0bKS7dzz/UrZ2uoU/L88VY2lWakehhnFRF5EshPcNOnlVJ/mIbHvwu4C6C0tPRMH06bJk6bmbXFXtYWe7lsRS63fvdFqtr6+PlLpycUXG7uDuCNl38r8DrYVpHJ525cg9elS8KdKR1cTjGlFI/ub+CLr1vDI3vr2V6Z+GztgEyXFa/TOuxMy4BjjX4KM5zDpthuKvPxclUH2Wm2YdmXADviz7W1PDPpWeKhTAI/e9fWCWUqT0a6w+j2ORCQumhpNjurO9hc6uPZ4y1cvTqPNJsFn9s2qTo6Zyocjc3q82lz0/piL1evyuPxg01j3i/DbaV+As3tJsLnslKW5ebEiLI5DouJFn9w2Amhww1+8r0OinxOFmW7Odbop9k/+YaAk1HodZCXbudQQzcvnmrDbTPztVvXc8ums6fjrrYwKKV47wO7xl2/p5uxHe9JenJ3Lhh5YK9pmqZpMyXf6+AHt5/DG7/7AgKctyiT2s5+CrwOYjGjP0miwDLANavzSZvjZdh2Vnfwuo06QXY6KaWunMJidUDJkMvF8esSPf59wH0AW7Zs0UUT5qBcj4OnPnYprT3BUY3je4IR+oKRUdeHojFWF3n5n7ds5JrV+dgsOt4zXeb2r/ACICJ8+62bAHjbtjK6+sP8/UhzvB6x8Msdp4fdvyDDycH67kQPhT8YwW59deXYWu4bDDSPDCwPFRsnJdNiEiIxxcZS37QHlhNZWZDOynhm9KrCdOo6+0f9KMw0pRRXfe0Zvv3WTaxZQIXdteFCkRhVbX3sqGzHbjERTLJTC0btcJfdMi1T6jv6wnidIUqynChlTAGymk3ElGJ3goaBjV0B7BYT7T3BaWkOZjbJYFPBmFKYRKhq60UQ/IEw9V0B6rsCZLisfOiKRbxxc/Gsr6OaNh2CkRhPHWme1ed02syIkLB8VSp98trlvG5jEburO3m5qp27Ll6U6iFpmqZpC8iGkgzecV45P3y+kkA4RltPiJr28RM3nHO4HMaAf750MfZ5MM4F4BHgFyLyNYyGfkuBHakdknYmTCZJeBxa3dZLodc5eDkYifLYgUYON/i5+7oVVGTP3Rrt89WEg8siYgZ2AnVKqRtE5OcYzcLCGCvke5RSowp9ikgU2B+/eFopdeOZD/vs5XVauXljETdvLEIpxfmLs/i33x+gPxylLNNFJJo8ELy1PJO6zn5et7GISNQ4YB4v0FXgtROJDT/C3VqeCSgGrj3R3EOa3cKSFDVJKMpwjn+nadbeG6KqrY9DDd06uLyAWc1GTZaOcWoYmwUEoa1nekpigBGAOtzgH/+OcaFojM2lPnZWd4y6bWluGl6XlVjM+P2wmk2Eo8YabhIB4z9EBKUU1W19486iuHxFLndft4Jls3DCSdNmyv/9/cRgl/mZtrU8k2AkSl1nPy9XjV5PU21tkZcCr5PXrHPymnW6ZrqmadoAEfkRcAPQrJRaE78uE/g1UA5UAbcqpebej/scEoupcWuavufiRfzkhSr21HSytdzHjglsL8fbZ50LFuWkpXoIC4qIvA74HyAH+LOI7FVKXaOUOigiDwKHgAjwfqWUnqp1FlpdODyGs+d0J2aT8PGrl6VoRGe/yWQufxg4DAwU2/05cFv8718A7wa+k2C5fqXUhqkOcCETEV67vpDzF2fhtluwmU2EojH+eqiJT/52Hx6HhaV5aRyo68ZuMRGJxajr7Of9ly1hSW4a/SHjIPaRvXU8dbSZzr4wtSOm7Td0BSnJdLOl3McrNZ34XDZONPtHNQTr7AsP1kA+m9V39vPc8RbOKc/EahYWz+Guw9rsmEjn2KgyAtErC9LxByKcbu8bf6EhluamkeGy0h+KYreYUSjCsRhbyn3EYor6zgCN3WNPn1fKmHK3ucyHoOgLxXDZjAyJgYBzpttKrsfBkcbOSY1vKI/DwsevXs7t55dP+TE0ba7YXze6qe1MKPQ62FndTmyOTqq8dHmObjSkaZqW3E+AbwM/HXLd3cDflFL3isjd8cufSsHY5o2JNMvKTXewuczHjsp2DtZ3syjHzamW0eUgh8pOs03XEGfEiWY/vcEo60syUj2UBUMp9TDwcJLbvgh8cXZHpKXauYuyUj2Es96EgssiUgy8BmMl/CiAUurRIbfvwKhXo82ArDT74N8Ok5nXri/kmtX5WM2CiNDRG8JlNxOKxDCbZLDZndNmdN796NXL+ejVywlGotz90H6W5KbxclU7Oyrb6QtF6Q8ZQeOVBensq01+oB2dq0fF0+DZYy28eKqNR/bWU9fZj9UshKMKj10Xdl+olFKcaOnhJy9UTej+QzMRl+amcby5Z8z7pzstFGU4SXdYOVTfPeb9izIcmE2SdB3cWJphZB4De053DAtguawmtlZkIoDdYqJznCzsRCwm4ZrV+bxhSzHnLcqa0924F5IEM4quAP4bMAE9wB1KqROpHONctqu6nX+caJuV56rvCrC1InOw10GqLcp2c/GyHBbnprEy32OclBLdIVvTNC0RpdSzIlI+4uqbgEvjf98PPI0OLk+L288rZ0dlO72h6ITq/7f1Ji//OBc4bRbSnfqYUtO0s9tEM5e/AXwSGDX/WUSswNsxMpsTcYjIToxpB/cqpX4/+WFqIw0tPO5zG2drB4LKydgtZr7+pg2Dlz/wi908f6KVytY+eoLjZyXvPt3BX/Y3cN3as2e6bG1HHx/65Z5RdWwHpkl/5Nd7efTDF6VgZFqq1Xb08+DLtcSUYl2xl75QFKUUJ8fInjCbhHVFXtx2C16XlfaeEGazcKKpBwVkuW24bGYyXDYO1HdNuOxFKKJwWc34k6ynVrOwozLxtMG+cIwdle14nVYcFhNN/smV7rhoaTZfef06ClNQnkYb18gZRd8BblJKHRaRfwb+DbgjRWOb09p6gnz64QOEorNX+LgqQSPe2Xb1qjxeu76Q69cWYJ5ABpmmaZqWVJ5SqiH+dyOQl8rBnE2uWZ1HjsdOiz9IusNKSaYr4clZl83Mw/98AWmOud1GKhUlHjVN02bbuL/EIjJQX2qXiFya4C7/BzyrlHouyUOUKaXqRGQR8JSI7FdKnRzxHHcBdwGUlpZOZvzaGfift2xkT00nP3yukr8fbebG9YWk2S08ebhpsBHglStzWV3o5cqVeYSiMXZWtaOUOisynHoCYb7/7KmEDdIGNHUHzprXq01cMBLlxVNtNHT1j5qKt6XMR5M/gNNqxueyoeL331/bRSym2FPTOXjf0kwnkZiQ7rTSHQjT1huio8+ojzyRchtgZDjnptuTNvI04kPjfz/D0RjL8zz4A2H6xmn6ZzULb9xSwjWr87lgcRYWs+6iO9ckmlEEKF4NNHuB+hQMbV74n6dOcKRx4jXNp0OzP8jaonT21yVel2fat9+6kdesLdDbM03TtGmmlFIiknTPTh/rTo7FbOKWTUV875lTHG3yJy3b9JatpSzP170/NE3T5oKJnOa7ALhRRK4HHEC6iDyglLpNRP4Do0j6e5ItrJSqi///lIg8DWwETo64z33AfQBbtmw5e2svzDEiwqZSHyU3uvh0dOVgZuI916/k0f0NZLltbFuUNSy7aXOZL1XDnXZ9YWOa1eZS4zXtOj0687M7EKa7P4LXpacyLSThqOKiJdn8YvvpUbclapiXjNdpHRVIiilo6p549vCyXA8mkxHwLfY5qW7rG1b2Iqaguz9MWaaT6jE6aveFouyoasckcE65j1AkRiSmRgWtz12Uyb23rKNcd9Cd677B6BlF7wYeFZF+oBs4NwXjmhdSVZ/RbErdiZrf76nnkmU5eBx6e6ZpmjYNmkSkQCnVICIFQHOyO+pj3clbnP1qA7xIgllGGS4rn7x2+WwOSdM0TRvDuMFlpdQ9wD0A8czlj8cDy+8GrgGuUEolTIMTER/Qp5QKikg2RqD6v6Zp7No0yfHYh102m4xGgme7nkCE3++tp6s/jAhsKs2guTtIbeerAbpwVM3qtGltbkizW0izW7hhXQF7h2QiT1ZtRz8bijPoCUXIcFmJRGMcafQTGCNz2OOwEIkp3DYzWW47JpPEZwxAZWsfW8sziaEwiRAIR3FYzSilsFtN5Hud7KhsZ6yjlpgaXh9aBM4pyyQUjfEfr13FxtKz5wTS2WqMGUX/AlyvlNouIp8AvoYRcE70GAs6iyrTbR//TtPMaTVzrDE1WcsATx5u4sO/2su9t6wlN92RsnFomqadJR4Bbgfujf//D6kdztllVWE6IkbDajViul92mp0rVuRS2dpLic+F2z63y2IA+ANhbBbTuGUsNU3T5qsz+SX+LlANvBifYvk7pdTnRWQL8F6l1LuBlcD3RCSG0WDoXqXUoTMdtKZNh9JMF59+zUq+9sQxGrsD7D7dSbHPSZrNTE+8eURRhhOnTe8ELDT9oQg7KtvJ9zrYXJrBkUY/b95ayt+PNo/bsXqojr4wHX2do65fV5TO4QY/eekOsjw27GYTfeEodouZXfHM6P5QlNae0Q1KdlSN3RCsKMPJljIfJpPwxMFGekNRBiYfVGS7R9WM3lTq48YNhbzpnBKsuvzFfJFoRtGfgRVKqe3x+/waeCzZAyzkLKpoTPGD50/N+vOGozHSHJZxy9LMpKeONPOx37zCz961LWVj0DRNm29E5JcYzfuyRaQW+A+MoPKDIvIujGPiW1M3wrPPmiIvFy/N4ZljLZiGzPq5cmUe37lt07zbZ9WzhjRNO9tNKrislHoaoxMuSqmEyyqldhLPlFJKvQCsPaMRatoMMZvEyP6MvNqFuLajnxX5Ho40+slwWfnRHeeQNg/OhmvTy2mz4LZbaPIHeeDd5/Lc8RbyvQ4yXTZyPDa+/1wl1e19hCKTDxJtLMmgtSdIOKao7ewflik/WSaB8mw3Va29uG0W/MEI2R47zf4gx5q6uXKV0VvmmtX5XLg0m66+MAfru9hV3UFppot0p5UrVubp7/g8k2hGEXAz0Cgiy5RSx4CrMJr9aSMcbuie8EmiQq+DmzYWkWa38NSR5sGTP1Nht5hwWk10TvkRpsebz1l4meqapmlnQin1liQ3XTGrA1lgvnbrel77P88ztP/sTRsK511gWdM0bSHQEQVtwRIRstJs3HvLWt77wO7B6480+slOs3Ht6vx53yRCRDKAHwBrMJp9vRM4ipHVWA5UAbcqpUZFTETkduDf4he/oJS6f+ZHPHeUZrnYUJKBxWzi6tX5RGOKP+ytJ9tj448fvIBd1e0crPcTisToCoR5eHfdYKaxxST43DZa/KNrK1stJmo6ph5QzvXYKchw8kpNJ+uKM1ie5+EzN6yiLNNFU3eQxTlu2npDFGY48DqH15Ud6Lh97ZqCKT+/NjcppSIi8k/AQ/HZQh0Y67s2QrM/MKH72cwm7n/nVgoynFhMwiXLcjjd3sd3nj7JyZYeNpZm0BOIcLq9j46+cMLHsFtM5KU7CEdjeByWeL30iddcn6zLludQmOGkPxTlREsP+2q7KMpwkhdvChpTiscPNnK4oZuPX6NrVWqapmmzKxpTw/r5jCUrzc6P79zKZx85AMC1q/O5bEXuTA5vRkVjir5QRGcxa5p2VtLBZW1BO7cii4//9pVR13f1h+kLRRMsMe98E3hMKfUGEbEBLuBfgb8ppe4VkbuBu4FPDV1IRDIxpvxtwQhK7xKRRxIFoc9W6Q4rIkIkGuN0ex+LctL46FXLqG7v5WRzL/tqu3HZzFy2PIe/7G+kwOtgY6mP5Xke/IEwP32petRjbq3IZEfl2GUthrKYhEhMceGSbFYXpdPeE+Ky5bm09wV5zdp8in0urlmdTzASxWWzsCjHaH6i66kuHCNmFD0MPJzK8cwHl6/I472XLOYX26vxByOcU57J/tou+sNRSjNdvOmcEkTgd7vr+J+nTrA0N40b1heypsjLmiIv163JB4wTlAMqW3t54KVqHtxZgz8QYXVhOl6nlZ5AmH3xpp4NXcPHYYtnXk22rr/PZaXIZwSQczx2NpQYddJDkRgrCzy8cUsJAL3BCK/UdrK1PBOL2cS3nzrOV584xiOv1LMi36ODy5qmadqsm2hgecDyfA8/vnMrLf4gJZmuGRrV7DCbhEA4hsUU1WUXNU076+jgsragOawmvnDTGpbkpPGtp44z0C8iHFUszZv3Wcte4GLgDgClVAgIichNGHXjAO7HCEx9asTi1wB/VUq1xx/rr8C1wC9netxzRVtviHAkRm1HPx19If60r4GNpRk0dQe4eGkOd15QwbEmPy3+EH8/1sKhBj/767pZU5jOruoO3DYLi3PdRKMKm8VEdVsfO8epl5zrsbOp1MfiXDfFPhc+l41Mt43l+R68zuFZDkqpwewPl03/lGvaZHz86mVctjyHAq+T0iwXHb0hwrEYmS4blnjQ958vXZJw2aFB5QEV2W4+c8MqPnb1Mv56qImDdV1cuiKX/HQHOyrb+cPeel481TZsmfJsFx+4fCmFXgdWs4m/HWkmGIny85dO0xOMjHqOdcVe0uwWPnHN8gk13nTbLZy/OHvw8mvWFXKk0c+f9jVw/Vo9e0HTNE2bHxxW87wPLA/I8cx+Q2FN07TZoCMS2oImIkSV4pc7TjO0EfH5i7N467Z5X5eyAmgBfiwi64FdwIeBPKVUQ/w+jUBegmWLgJohl2vj1y0YRRlOwKhpnMzqQi/fePIYRRlOMpxWNpf5OKfcxy2bi3h0XwMnW3p56kgzVrOJ4kwXbb1G2Qyfy8rmskzyvXZKfC4qst38+uUaNpX5+OdLFycMXo0kIljMk8v+0DTNYDGb2LYoa/Cyz20b494T57JZuGlDETdtePXnclFOGq/fXMz3njnJV584Nnj98eYeLlicRVaacaC5viQDpRTXrSngbd9/id5QlK3lmZxq7eX1m4v48BVLz+hEUkW2m2+/dRP/9poALrvOmEqVJOWqbgFeC4SAk8CdSqnOFA1R0zRNm0HN3QHjZLZF147WNO3soYPL2oKXnWbn6U9cyt+PtPDUkWYeeaWO91+2ZFSm6DxkATYBH1RKbReRb2KUwBiklFIiohIuPQEichdwF0Bp6bwPxk+a2SR85MplhKMxHNbhwZrzF+fwSm0XH7x8KVeszMXjsNLUHcBhMROJxajIdg8LIl+9On+2h69p2iyxxmu3L8pJ478fP0prT5D73r5lMLA8QETYUJLB85+6nJhSZKXZCUdj09q8KN+ry+akWKJyVX8F7onXTv8KRsPOkTOKNE3TtLOAAr7w6GE+e+PqVA9F0zRt2ujgsqZhZJu9Zl0Bl6/I5ZLlOWwszUj1kKZDLVCrlNoev/xbjOByk4gUKKUaRKQAaE6wbB2vls4AKCZe13UopdR9wH0AW7ZsmXKQej7rDUVwDQksR6IxXjrVTrM/wDvOK2dbReZgEPksOGGhadoULcvzkOdx0HFRiMtX5FLgdSa979BM6ukMLGuplaxcFfDEkLu9BLxh1genaZqmzYq8dAd3nF+e6mFomqZNKx1c1rQhnDYzN64vTPUwpoVSqlFEakRkuVLqKHAFcCj+73bg3vj//5Bg8ceBL4nIQGHPqzEyqbQR0kd0fLaYTVy4NDvJvTVNW8i8Litv21aW6mFoqZOwXJVSqnfIfd4J/DoVg9M0TdNmx1hl9zRN0+YjnQ6jaWe3DwI/F5F9wAbgSxhB5atE5DhwZfwyIrJFRH4AEG/k95/Ay/F/nx9o7qdpmqZp2pQMlKv6jlJqI9DLkHJVIvJpIAL8PNHCInKXiOwUkZ0tLS2zMV5N0zRN0zRNG5fOXNa0s5hSai+wJcFNVyS4707g3UMu/wj40YwNTtM0TdMWlmTlqhCRO4AbgCuUUgnLTOlSVJqmaZqmadpcpDOXNU3TNE3TNG2GKaUagRoRWR6/6grgkIhcC3wSuFEp1ZeyAWqapmmapmnaFEiS5IiUEZEWoHoWnzIbaJ3F55tOeuypMVNjL1NK5czA486KFKy7UzEfv3fzbczzbbxw5mPW6+7Uzcfvy1Tp1zq3pGS9FZENwA8AG3AKuBOj/JQdaIvf7SWl1HvHeZyB9XYuv9d6bFMzl8cGqR+f3uYml8rPJtXfC/38c/v59Xo7can+LJPR45qcs2VcE15351xwebaJyE6lVKKyAXOeHntqzOexL3Tz8bObb2Oeb+OF+Tnms8VCeu/1a9Vmwlx+r/XYpmYujw3m/vgWslR+Nqn+XujnX9jPfzaZq++lHtfkLMRx6bIYmqZpmqZpmqZpmqZpmqZp2qTp4LKmaZqmaZqmaZqmaZqmaZo2aTq4HO+6PU/psafGfB77QjcfP7v5Nub5Nl6Yn2M+Wyyk916/Vm0mzOX3Wo9tauby2GDuj28hS+Vnk+rvhX7+hf38Z5O5+l7qcU3OghvXgq+5rGmapmmapmmapmmapmmapk2ezlzWNE3TNE3TNE3TNE3TNE3TJk0HlwER+ayI1InI3vi/61M9pvGIyLUiclRETojI3akez2SISJWI7I+/1ztTPZ6xiMiPRKRZRA4MuS5TRP4qIsfj//elcozaaCJSIiJ/F5FDInJQRD4cv37OfnZjjHnO/j6JiENEdojIK/Exfy5+fYWIbI//Pv1aRGypHiuMOd6fiEjlkPd4Q4qHuiDMp23BZC2UbUeS1zlnf7PmIxH5bxE5IiL7RORhEcmIX18uIv1D3ufvJll+Rr93Y4zvKhHZFV/Hd4nI5UmWn7HvS7KxxW+7J76NOioi1yRZfsa2ZSLyxvh2KCYiW4Zc/7Yh78Xe+O0bEiw/o+vZGOObE987DUQkQ0R+G/+OHxaR82brfReR5SO+p90i8pHZ/NxF5F/i39EDIvJLMfbxZmydHfHcH44/70ER+Uj8upn+rZ3wfoUYvhV/H/aJyKYZev6EvxPx28b9jV2oUv1ZTnJcKf2Mk4zpjLbtMziu/4yPaa+IPCEihfHrU/oZDrntYyKiRCR7xsallFrw/4DPAh9P9TgmMV4zcBJYBNiAV4BVqR7XJMZfBWSnehwTHOvFwCbgwJDr/gu4O/733cBXUj1O/W/U51YAbIr/7QGOAavm8mc3xpjn7O8TIEBa/G8rsB04F3gQeHP8+u8C70v1WMcZ70+AN6R6fAvt33zaFkzhtS2IbUeS1zlnf7Pm4z/gasAS//srA98boHzo+z7G8jP6vRtjfBuBwvjfa4C6JMvP2PdljLGtiu8724GK+D61OcHyM7YtA1YCy4GngS1J7rMWODnb79tY45sr3zv9TwHcD7w7/rcNyEjF+45xXNoIlM3W8wNFQCXgjF9+ELhjJtfZIc+9BjgAuAAL8CSwZBZ+aye8XwFcD/wFY7/3XGD7DD1/st+JCf3GLtR/qf4s59NnnGRMZ7Rtn8FxpQ/5+0PAd+fCZxi/vgR4HKgmfuw1E+PSmcvz01bghFLqlFIqBPwKuCnFYzorKaWeBdpHXH0Txg4d8f/fPJtj0sanlGpQSu2O/+0HDmPsiM7Zz26MMc9ZytATv2iN/1PA5cBv49fPmfd5jPFq2rRaKNuOJK9Tm0ZKqSeUUpH4xZeA4kk+xIx+75KNTym1RylVH7/+IOAUEft0PvdUx4bxnvxKKRVUSlUCJzD2rQeJiDCD2zKl1GGl1NFx7vYWjH38WTfB8Y3lrPu9m0tExIsRRPghgFIqpJTqJDXv+xUYJ0GqZ/n5LRi/KxaMQG8Ds7P/uRIjCNMX/315BriFmf+tncx+xU3AT+P7vS8BGSJSMN3PP8bvxLi/sQtZqj/LyYwr1Z9xkjFNeds+w+PqHnLRzavHmCn9DOO+DnyS4ce90z4uHVx+1Qfi6eA/mu5pLDOgCKgZcrmWOR6EGkEBT4gxTfKuVA9mCvKUUg3xvxuBvFQORhubiJRjZFBtZ558diPGDHP490lEzCKyF2gG/opxlrhzyEZ/Tv0+jRyvUmrgPf5i/D3++mwHQBaw+b4tmKx58fszTebsb9Y8906MLJMBFSKyR0SeEZGLkiwzm9+7keMb8Hpgt1IqmGS52fi+DB3bRPajs0j9tuxNwC/HuD1V69lc+94tRBVAC/Dj+GfxAxFxk5r3/c28+j2dledXStUBXwVOYwSVu4BdzM46ewC4SESyRMSFkf1XQmre+2TPmepYQaqffz6aq59lMnNlXJPdts8oEfmiiNQAbwP+fS6MS0Ruwpg99sqIm6Z9XAsmuCwiT4pRG2nkv5uA7wCLgQ0YG6j/l8qxLgAXKqU2AdcB7xeRi1M9oKlSxpwCnfk4R4lIGvAQ8JERZxPn7GeXYMxz+vdJKRVVSm3AOGu8FViR2hGNbeR4RWQNcA/GuM8BMoFPpW6EC8pZsy2YrLn6+zNN5vRv1lw0zj7qwH0+DUSAn8evagBKlVIbgY8CvxCR9LGeZ6rfuymOb+D61RjTVt+T5OHP6PtyJmObaRMZ2xjLbgP6lFKj6ibGnfF6NsXxzdr3ThuTBWPq83fin0UvxlT6QbPxvotR0/hG4Dcjb5vJ54+fTLkJI8heiJEleO1MPNdISqnDGL9pTwCPAXuB6Ij7zPp3Xq9nZw/9WU5MqrbtY1FKfVopVYIxpg+kejzxE2D/yquB7hllmY0nmQuUUldO5H4i8n3gTzM8nDNVh3GGdEBx/Lp5IX62GaVUs4g8jBGQeja1o5qUJhEpUEo1xKcONKd6QNpoImLFCNL+XCn1u/jVc/qzSzRmpVTTkNvn7O+TUqpTRP4OnIcxrcYSzx6Zk79PQ8Z7rVLqq/GrgyLyY+DjKRzagnEWbAsma07//kyX+fKbNZeMt48qIncANwBXxA86iWcBB+N/7xKRk8AyYGRzzDP+3k1lfPHri4GHgXcopU4meewz+r5McWwT2Y9u4wy3ZRM99khiaDZoosc+4/VsKuObze+dNqZaoHbI7KvfYgSXZ/t9vw5jVsLA93G2nv9KoFIp1QIgIr8DLmCW9j+VUj8kXpJERL6E8Xmk4juf7DlTHStI9fPPR3P1s0wmpeM6g237bPk58CjwH6R2XIsxTsK9IiIDz71bRLbOxLgWTObyWGR4bZHXYUx3mcteBpaK0RHXhrED+kiKxzQhIuIWEc/A3xgF2ef6+z3SI8Dt8b9vB/6QwrFoCYjx6/lD4LBS6mtDbpqzn12yMc/l3ycRyZF4h14RcQJXYdSK/jvwhvjd5sz7nGS8Rwbe4/hncDNz6D0+W50l24LJmrO/P9NpLv9mzUcici1GnbwblVJ9Q67PERFz/O9FwFLgVIKHmNHv3RjjywD+jNGg6B9jLD9j35dkY8N4T94sInYRqcB473YMXTZ+sJqSbZmImIBbGaPecqrWs7nyvVvolFKNQI2ILI9fdQVwiNl/39/C8JMgs/X8p4FzRcQV33cbeP2zss6KSG78/6UY9ZZ/QWq+88me8xHgHWI4F+gaUnJhNoz7G6uNMlc/y2RS9hmfybZ9hse1dMjFm4AjQ8aVks9QKbVfKZWrlCpXSpVjnAjbFN+GTP+41Ax1KpxP/4CfAfuBffE3uSDVY5rAmK8HjmHUN/10qscziXEvwuji+QpGg5c5PXaMHaYGIBxfGd+FUYfvb8BxjA7Bmakep/436nO7EGM60T6M6Wp74+vMnP3sxhjznP19AtYBe+JjOwD8e/z6RRgb8xMYUyXtqR7rOON9Kv4eHwAeANJSPdaz/d982xZM4fUtiG1Hktc5Z3+z5uO/+O9ozZDtwkD38dfH1529wG7gtUOW+QHxru4z/b0bY3z/hjFVf++Qf7kJxjdj35dkY4vf9mmMfeijwHVDrn8UKIz/PWPbMoyAcC1GFnAT8PiQ2y4FXkqwzKy8b2ONb6587/Q/BUZJlJ3x78DvAd9svu8YpSjaAO+Q62bz+T+HEbw5EF8f7DO5zo547ucwgtmvYGROzvhrZxL7FYAA/xv/jds/sF7OwPOP9TuW8DdW/0v9ZzmfPuMkY5r0tn2WxvVQ/PdoH/BHoGgufIYjbq8CsmdqXBJ/YE3TNE3TNE3TNE3TNE3TNE2bMF0WQ9M0TdM0TdM0TdM0TdM0TZs0HVzWNE3TNE3TNE3TNE3TNE3TJk0HlzVN0zRN0zRN0zRN0zRN07RJ08FlTdM0TdM0TdM0TdM0TdM0bdJ0cFnTNE3TNE3TNE3TNE3TNE2bNB1c1jRN0zRN0zRN0zRN0zRN0yZNB5c1TdM0TdM0TdM0TdM0TdO0SdPBZU3TNE3TNE3TNE3TNE3TNG3SdHBZ0zRN0zRN0zRN0zRN0zRNmzQdXNY0TdM0TdM0TdM0TdM0TdMmTQeXNU3TNE3TNE3TNE3TNE3TtEnTwWVN0zRN0zRN0zRN0zRN0zRt0nRweQEQkYMicmmqx6Fp2sRMdZ0VkUtFpHb6R6RpWjJ6G6tp84uIVInIlakeh6Zpk6PXXU2bWQPrmIj8q4j84Awfa14el4rI20TkiVSPYz6ypHoA2sxTSq1O9Rg0TZu4gXVWRD4LLFFK3ZbaEWmalozexmqapmmapmlnC6XUl2b6OUTkJ0CtUurfZvh5PsskjqeVUj8Hfj6TYzpb6czlBUxE9MkFTdM0TdM0TdM07aymj301TdNmjg4uLwBDpjd8VkR+KyIPiEg3cIeIbBWRF0WkU0QaROTbImIbsqwSkfeKyPH4ff5XRCSFL0fTznrxdfYG4F+BN4lIj4i8Er/tThE5LCJ+ETklIu9J8hifEJGHRlz3LRH55sy/Ak1bOIZsYyeyPf1QfL1tFZH/FhFT/LbFIvKUiLTFb/u5iGSMeI6Pi8g+EekSkV+LiCMFL1fTzioislJEKkXkLSJyg4jsja/DL4jIuiH3S7oOisgBEXntkPta4+vxxvjl34hIY3y5Z0VEz3bQtDM0Yt39JxE5ISLtIvKIiBQOuZ8SkfeLyHHgePy6sdb1u0XkZHw/+5CIvC4FL0/TUioeN3pgyOVz4+tKp4i8IkPKwYlIpoj8WETqRaRDRH4/4rE+JiLN8X3jO+PX3QW8Dfhk/Dj3j/HrC0XkIRFpia/fHxoxpgdF5Kfx9fOgiGwZcvunRKQufttREblCRK4l8fG0V0R+GB9TnYh8QUTM8dvuEJHnhzyujodNkA4uLzw3Ab8FMjDS/aPAvwDZwHnAFcA/j1jmBuAcYB1wK3DNLI1V0xayAPAl4NdKqTSl1Pr49c0Y62Q6cCfwdRHZlGD5B4BrBwJUYmRrvBn46UwPXNMWqIlsT18HbAE2YWyP3xm/XoAvA4XASqAE+OyIZW8FrgUqMLbHd0zz+DVtQYlvOx8HPggcAX4EvAfIAr4HPCIi9iGLJFsHfwoMnW57PdCglNoTv/wXYCmQC+xGT7fVtDMyYt1twth+3goUANXAr0YscjOwDVgVP+kz1rp+ErgI8AKfAx4QkYKZfD2aNpeJSBHwZ+ALQCbwceAhEcmJ3+VngAtYjbGd+/qQxfMx1qUi4F3A/4qITyl1H8a28L/ix7mvjSdc/BF4JX7/K4CPiMjQ2NONGOt3BvAI8O34GJcDHwDOUUp5MOJVVUqpx0h8PP0TIAIsATYCVwPvHuNt0PGwCdDB5YXnRaXU75VSMaVUv1Jql1LqJaVURClVhbGBvWTEMvcqpTqVUqeBvwMbZnnMmqbFKaX+rJQ6qQzPAE9g7ASPvF8D8CzwxvhV1wKtSqldszdaTVs4Jrg9/YpSqj2+Pf0G8Jb4sieUUn9VSgWVUi3A1xIs+y2lVL1Sqh1j53vDDL4cTTvbXYRxYPoOpdSfgLuA7ymltiulokqp+4EgcO6QZZKtgw8A14tIevzy2zEOtgFQSv1IKeVXSgUxThqtFxHvDL42TTubjVx33wb8SCm1O76O3QOcJyLlQ5b5cnzb288467pS6jfx9TymlPo1Rrbz1tl7eZo259wGPKqUejS+XvwV2Imx3SsArgPeq5TqUEqF48enA8LA5+PXPwr0AMuTPM85QI5S6vNKqZBS6hTwfYzkqAHPx8cRxdjODgSLo4Ad4wSSVSlVpZQ6mehJRCQP4yTwR5RSvUqpZoyA+JsT3T9Ox8MmQAeXF56aoRdEZJmI/Ck+Xa8b48xO9ohlGof83QekzfAYNU1LQkSuE5GX4lP/OjE2jiPX2QH382o21W0MOdjVNG16TXB7OnQbXI2RqYyI5InIr+JT87oxglV6W6xpM+e9wAtKqafjl8uAj8WnvHbGt68lxNfRuITroFKqHvgH8Pr4bKHriGcni4hZRO6NT7PvBqriyyfbbmuaNraR624hxvYUAKVUD9CGkfk4YOi2d8x1XUTeMaRkRiewBr2+agtbGfDGEevMhRgzBUqAdqVUR5Jl25RSkSGXx9p/LQMKRzzPvwJ5Q+4zcjvsEBGLUuoE8BGME7jN8X3qodvvkc9jBRqGPM/3MLKuk9H74BOgg8sLjxpx+TsYUwGXKqXSMVZgXUNG0+aGYetrfMreQ8BXgTylVAbwKMnX2d8D60RkDcZ0Hj0VV9NmzkS2pyVD/i4F6uN/fwljfV8bX/a2BMtqmjZ93guUisjA9N0a4ItKqYwh/1xKqV9O8PEGTua+EWOWYF38+rdilMC5EmNqcHn8er1+a9rUjFx36zGCRQCIiBuj3EXdkGWG7k8nXddFpAwjU/IDQFZ8P/sAen3VFrYa4Gcj1hm3Uure+G2ZMqRPyCSMjEvVAJUjnsejlLp+Qg+m1C+UUhdi/B4o4CtjPE8QyB7yPOlKKd0P4Qzp4LLmAbqBHhFZAbwvxePRNO1VTUB5vAYVgA1jyk8LEBGR6zBqRCWklApg1Fj/BbAjPpVH07SZMZHt6SdExCciJcCHgV8PWbYH6IrXtvvEbAxY0xYwP0a5qItF5F6MgNJ7RWSbGNwi8hoR8Uzw8X6PUUv9wwzvbeDBOIhtw6hJ+aXpegGatkCNXHd/CdwpIhviSRhfArbHy1MlMta67sYIRLWA0UQbI3NZ0xayB4DXisg18dk4DhG5VESK42UY/wL8X3z/1ioiF0/wcZuARUMu7wD8YjTmc8afa42InDPeA4nIchG5PP4bEAD6gdiQ5xk8no6P+Qng/4lIuoiYxGisPbIcnTZJOrisfRwjq8KPsbH99dh31zRtFv0m/v82EdmtlPIDHwIeBDow1t1HxnmM+4G16JIYmjbTJrI9/QOwC9iL0Rzlh/HrP4cRmOqKX/+7GR6rpi14SqlO4CqMMhY3Af+E0RyoAzjBJJpmxmu5PoTR7G/o+vtTjCn7dcAh4KUzH7mmLWwj1t1LgM9grH8NwGLGqJ2qlNpJknVdKXUI+H/AixgBqbUYJW80bcFSStVgbCP/FePESw1GEsRALPHtGLWVj2A0nv/IBB/6hxg1kjtF5PfxOso3YNQzrgRagR9gzPoZjx24N75MI0aJi3vitw07no7//Q6MpK1DGL8Dv8Uo86GdAVFqZJa4pmmadrYQkVKMjX2+Uqo71ePRtLONiJwGblNKPTvO/RRGyYwTszMyTdNmk4j8O7BMKXXbuHfWNE3TNE07i1hSPQBN0zRtZsSn/3wU+JUOLGva9BORHCCHV5t0aZq2AIlIJvAujAwuTdM0TdO0BUWXxdA0TTsLxRuadGNMG/yPFA9H08468Rpwx4H/0fXMNW3hEpF/wpgm/JfxZjBomqZpmqadjXRZDE3TNE3TNE3TNE3TNE3TNG3SdOaypmmapmmapmmapmmapmmaNmnTGlwWEbOI7BGRP8UvV4jIdhE5ISK/FhHbdD6fpmmapmmapmmapmmapmmalhrTWhZDRD4KbAHSlVI3iMiDwO+UUr8Ske8CryilvjPWY2RnZ6vy8vJpG5OmzRe7du1qVUrlpHocU6XXXW2h0uuups0/er3VtPlJr7uaNv/o9VbT5qfJrLuW6XpSESkGXgN8EfioiAhwOfDW+F3uBz4LjBlcLi8vZ+fOndM1LE2bN0SkOtVjOBN63dUWKr3uatr8M5vrrYhUAX4gCkSUUltG3C7AN4HrgT7gDqXU7rEeU6+32kKlt7maNv/o9VbT5qfJrLvTFlwGvgF8EvDEL2cBnUqpSPxyLVA0jc+naZqmaZqmafPBZUqp1iS3XQcsjf/bhpGIsW22BqZpmqZpmqZpZ2Jaai6LyA1As1Jq1xSXv0tEdorIzpaWlukYkqZpmqad1RL0OfiJiFSKyN74vw0pHqKmaRNzE/BTZXgJyBCRglQPStM0TdM0TdMmYroa+l0A3Bif9vcrjHIY38TYOR7Iji4G6hItrJS6Tym1RSm1JSdnbpbiqe3o4w9764jGpq9GNUAgHJ3Wx9M07eyllOJ0Wx9/2d/ACyeTJcBpC8iHgcMjrvuEUmpD/N/eFIxJmwH9oSh9IWMiWG8wwkun2qjr7E/xqLRJUMATIrJLRO5KcHsRUDPksp7tN0XRmOJAXRfVbb2pHoqmafOMUornjrdwtNGf6qFo2lntQF0XbT3BVA9Dm2bTUhZDKXUPcA+AiFwKfFwp9TYR+Q3wBoyA8+3AH6bj+VLha08c43d76vjO0yf537dtYnFO2pQfKxKN8auXa/jGk8cIRmLc9/YtnLc4axpHq2nafOYPhPnmk8c50ugnGInS2RfG57bR1RfmaJMfm9nEy5++MtXD1FJoZJ+DFA9HmwUH67tYkZ/Oj56v4utPHiM7zcZX37ieS5fnpnpo2vguVErViUgu8FcROaKUenayDxIPTN8FUFpaOt1jnLfC0RjPHG3hN7tq2FHZTkdfmLdsLeW16wo4f0l2qoenado88dSRZt51/05WFaTzhw9cgNU8XXl4mqYNqGnv444f7yA7zc7P372NrDR7qoekTZOZ/sX8FEZzvxMYNZh/OMPPN636QhFePNnG0UY/2yvbATjS6Oe/HjtCbzAyztKjKaX4xfbTnPvlp/i33x+gtSeEPxDh9h/v4LEDDdM9fE3T5oGnjzbzvgd2cddPd1LZ2ktvMMK3nzrBD56v5PkTrbxc1cHx5h52VLZztMnIpAhFY1zwlac43qQzKxawb2D0OYiNuP6LIrJPRL4uInpv7SzhtJkpy3QTU7CxNAOA1p4Q77p/J3/Ym3BSmDaHKKXq4v9vBh4Gto64Sx1QMuRywtl+82Gm32w63NDNF/50iPO+/Dfe/dOdPH6wiY6+MAC/3HGa7kA4xSPUNG0+8TisABxq6OaXO06neDTagARl4J4bUgKuXkR+n2CZDSLyoogcjO8Xv2nIbbqMXIp09YW548c7aO0JcaTRz9t+sJ323lCqh6VNk+ls6AeAUupp4On436cYvQM9b5hEuOtnO/EHhgeSHz/YxCd/u49vvHnDhM9oHm30856f7aSqrW/UbR+/ehmXLNOZR5q2EP30xWqeOtIMwBOHmia0jMdupicY4U33vcQXbl7DyoJ0fE4rXpcVEZnJ4WpzwNA+B/HZQgPuARoBG3Afxgnezyd5DJ0BOc/kpjsAuHhZDisL0jnc0E00pvjkb/fhcVi4fEVeikeoJSIibsCklPLH/76a0evlI8AHRORXGI38upRSOusgiZ1V7Xz9yWP840TbOPfr4JrV+dR19lPsc83S6DRNm68e2lU7+PdPXqjirVtLsejs5blgoAxcOoBS6qKBG0TkIRLPju8D3qGUOi4ihcAuEXlcKdUZv/0TSqnfzuywtaGCkSjveWAnJ1teLVt1pNHPW7//Er/8p3PxuW0pHJ02HaY9uHw2cVjNfPF1a/nQL/eMuu3P+xv4+9Fmfn3Xeawt9iZ9jN5ghHt+t5+WnsBgYLnQ66C+KzB4n4f31HPxshxW5KdP/4vQNG3Oef54K/c8vI8PXraUmzcUDgaXB5gFognKu9vMkOGyU5jhpLk7gJiED/xiNzEFBV47TpuFAq8Dr9PKtoosnDYzKFiW72FFvgeH1TxLr1CbYQN9Dq4HHEC6iDyglLotfntQRH4MfDzZAyil7sMIQLNly5bpbSagzbh0x6u7b8FIjHffv5MPX7GM91+2WB8Izz15wMPxE38W4BdKqcdE5L0ASqnvAo8C1wMnMA6I70zRWOe0/lCUf/n1Xh472Dih+//0xWoU8PjBRjaW+vjvN6zT20FN00aJxRTfePIYv975aun7Uy29/OSFKt590aIUjkwbqwyciKRj9Poatc1USh0b8ne9iDQDOUDnTI5XS0wpxd0P7eelU+2jbjvS6Oct33+Jb791I0tyPSkYnTZddHB5HA5L8oO0vlCUrz15lLWFXgoznKwu9LIsP41gJEZVay+5HgfvvH8HguC2W1hVkE5bT5Ain3MwuJyf7uDKlbmYdbahps07DV39/HlfQ9Idz4/8ag9Om4Uv37J21HJdfWE++dA+AJbkuslLdxCOKBSKzr4waQ4Le053AmC3CF6nDavZRLM/QLP/1QYIAmwt93G0qYeGrl5Oxc8GP7r/1YPvK1fm8fFrlukTWGeJJH0ObhORAqVUgxhRrJuBAykbpDZjKlt7B38bBsQUfP3JY/x+bx1fvHkN5y3OSjqL4WB9F6sLk58U16ZXfBbf+gTXf3fI3wp4/2yOa77pD0V5909fHjdbeahQNMYPn68EoLajnytW5HLj+gLCMYXNbNIzfTTtLNDcHeBUay9KGT1LwlHFumIv2Wl2DtZ30ewP0tkXpjsQ5s3nlBCKxIgqhcNipjsQZkdlO/e/WMWBuu5Rj/3VJ45y1ao8yrLcKXhlWtw3MMrAJYo63gz8TSk1+sMbQkS2YszqOznk6i+KyL8DfwPuVkrp7nIz6OtPHufhPcnLuB1p9HPdN5/jU9eu4O3nlWG36BPB85EOLo/jypV5nLcoixdPjd6ZNQtsP9XO34+0DF7nspmJKUUgHKMi201vMEKzP4jHYSHNbqHJH8RifnVnNjfdzjWr81map8/SaNp8oZTimWMtfOnRw1hMpqTB5ZiC3+6qYUW+h0y3jd/s+v/snXWYpFeZt+9TLl3a7t3j7tMTNxIISYAEQgiBoEEXl7AsfMDuwgLLLrpY8IQgIVhIgoS4jrtLu3dXVZf7+f6o6pqW6mmf7pk593XNla5XT3X6vO85z3me36+Ndm+Y37z7Yr7zxAkksLzcjkmn4dkTfcgh+aMN9W6KC4zUF1tp90Zo90VYW+2g2x/JHeO2Gqh2men0R1lUUkA0kcJi0LK9yQuAWa/l3nc2sLnOPZu/DsX84X4hRDGZNYc9wHvntjmK2aDTFyGeGim1naGxL8QdP97Klno3Fy8opMJl5rXrK9FpNYTjSf79oUO8YlWpCi4rzinC8SR3/WIHL5yceGA5Hx/57R6+/NfDdPtjWA1a0hKS6TQ6jQZXVlbqyqXFvOeKBSqYpFDMc1461c83/3ksbybkWHz1b0eGjbXHI5pI8+VHj/CDOzdOoYWK6XIGGbhB3gj8eJxrlAP3AW+VUg4OniYkI6ck5GaG3+1o5duPHx/3uNpCK19+9DC/2tbCf92ymosWFJ6F1ilmEhVcHgeNRlDmMOXdl5Jg1GkIx1O5bUN/7gvGqHGbCcWS6DSCzmy2cjIl0WsFiZRkX9sAN33nOb7xhrVcsbhYuWUqFOcIv3ihiWPdQcx6Ld9+/DgfvGZRLgtKSsmf93RwpMvP5lo3n3/o4LBzb/3BC7iseow6DdsaPayqtI8a7LZ5w7mMikH2tg7QUOdmW1NmWyCawKgvoNUTodWTCTo31J8OJEeTKe555hRHugLceVHtbPwaFHPMCJ+Da+a0MYpZp9sf5fe7xjfw29royRkR/+TZRhaVFHC4y8+WerfSZlacU4TjSd7+s+25v+eZIjRkvJ5IpYgMZD7/amsLf9rdzg/v3Mjli+fWNDGVljxzrJfLFxcpuZs5RghhAp4BjGTmzw9KKT8vhHgZ8DVAAwSBt0kpT8xdSy8Mfvj0Se57qZk2b2T8g4cwmcDyIH8/1MWJnoAq158bxpSBE0IUkfH2umWsk7OyGY8An5FSvjS4fYinwRll5JSE3PR5/kQfn/7D/nGPKzDqCEYTpGRGkub2e17iDZuq+fQNy3BalBbzuYIaqUyA8jGCyw117pwrdT4C0SQHOwKE4qnccZvrXBj0GpLp4c+nj/52L3fdu4NgNMHuFi9yKm8/hUJxVnhgR2uuNDeSSPH1x45x/Tef5at/OwzA73e185Hf7sFpMdDmi7CszMamWheb6lxsrnNRYjPiMhto80YQQDpPEmKHL0osmdlh0mlYV+2gymXOBZbNeg0balwYdcPLemOJ0xNmKeFg+wDrqpwz/0tQKBRnnR88fZLf72ob/8AhHO0O8Mj+Tk71hjjVG8QbUpWfinOHcDxFY19o/ANn+J53/mQbH/vtnjlxsW/pD/O//zjKZV99grf/fDvv/eUuYsnU+CcqZpMYcI2Uci2wDrheCHER8H3gTVLKdcCvgM/OWQsvEI52Bfjq347gCcWpK8wYdbotegqMWooKZj4IJSV885/H1dx8DpBSflpKWSWlrANuB54Y4i9yK/CwlDKa71whhAH4I3DvSOO+bDYzSkZudjnRE+C99+0cFffKx9IyG13+4ePT3+5o5dqvP82f97Sr/neOoILLE+DOi2u5bFHRsG2bal25IM9EqSu00Nwfpi8Qp8AwOml8d4uPm7/3Am/96TZSE+iE85F0WtIfjNETiOYGwp0DEfVAUJxTHOsOkEylOdTh5+8Hu3jXvTv4l/t38ec97Xzx4UM8sKOVdTUOat3m3Dk2k44/7e7gueN9HGgfADLaBC2eMFajlh3NXnY0ednelPlvuy9CJJHCoBMMRPMvUq2pclDtMqPViGwAOqMjt6S0gEgizdZGDz3+GA6zPnfOYEB6kJpCC48e6EShUJx7nOwNkhwigbG+xjWt621t9PLCyX66/VHavOHpNk+hmHWKCoxcu2Jusu3/sLv9rE1spZTsbPbwhYcOcsXXnuQ7T5zIVTz+83A3l3/1Sdp9k8vSVMwcMkMw+1Gf/Sez/wYNLRxAxxw074LhkX2d3Pr9F0jLzCJQuy/Clno3JXYTJr2WUrsRs16DWT+zIY6H93Xy42cbZ/SaimlzO/DroRuEEJuEEIMyGbcBVwBvE0Lsyf5bl913vxBiP7AfKAK+eJbafEHxnw8fJhBLjntcpcvMrmZv3n19wThfeOgg0UR+OTjF/ELJYkyAaCLNcyf6hm3rHIhg1GlGBXLORFP/6Ymc3Zz/V++2GDjRE6SpPzSvy2+klAxEEjT3h6l2W3BZ9KTSki//9UjOPMVh1rO01MbhTj93X7+UOy+um9tGKxTj0NIf5vMPHeD5k/3E8/TtR/Z3srbKwd62TPDYadFz0QI34XiKQ50DhONp7nupKZfpJAGNgDbP8AlhpdNMazawE0tKyuwmKhwmLAYdRzr9dAdiLCuzsS97H4B97QOsrLAP2wZwtDvI4tIC1lTa8UUS2Ex6jDqBy2Kkyx/FG0pQ47LQ0h+mJpvhoVAozg0++8cDeMNxNte5WVvt5L6Xmqd1vaICAyd7Q5Q5TGysVVrsinODhjo3v9raMif39oTifPg3e/jT7na+dMtqKpzm8U+aBFJKnj3ex/89eWKYDNZIegIx7vrFDj75iiVYDDoC0SSnejPzBV84wSWLirhtU5UyQZpFhBBaYCewCPiulHKrEOIu4FEhRATwAxfNZRvPZ7Y3efjIb3eTSJ1e6Emk5DDJnL5gZvxdYjMSScxslc7X/n6UNVUOtigd2DlhqAxc9vNVeY7ZAdyV/fmXwC/HuJaSkZtldjZ7ePpY7/gHAmV2E+1nkLh552X1mA3q3XYuoILLE+ADv9o1alu7L0qZw0TXQN5KjHHxR5KsqXSwr/10oGhjzels6F0tvnkZXI4n0zy6v5OfvdDE3lZfbrtZr2V9tZMXhhgfDkQSue9z30vNXLeijKICg9KNU8xbnFY9LuuZS+oEUFtooT8Yp77QSk8gxqneEFvq3Wxt9HCsO4jDpGNLvZtEKs2GGhfHuk7381q3hWKbkbYhGUg7m73UF1npCwRYWmajwmUmPaJ6YUlpAUUFBgw6DWa9loFIJtu5xGbEbTFwtDtITyCGQafhrssW8MlXLGUgnODp471cv6qMxw518/iRbt5+af3M/cIUCsWs0lDv5luPH+dIV2DSgeX6Iit3NNQgkXQNxLhscSFLSm1UudQik+LcYm21k9dtqJq0JMxM8uTRXq77+tPcff0y7ryoFo1GjH/SOPQEorzrFztyC9bjcbjTzzt+viPvvuXldhVYnmWklClgnRDCCfxRCLEK+ChwQzbQ/Eng62SDW0M514zB+oMx/vexYxQVGPnYdUvmtC3RRIrnjvdx9+/3DQssn4meQIyVFXaa+0IE4zMjKRNPpXnXvTv4/fsuYXHp/JujKxTzif/9x7EJHbe60j5m1jJkKoPfckndDLVKMduo4PI4JFNpPnLtEv73H0c50hUYtq/QaphycBkypfflDlOu7E2rPT1Qff5EH7dtqp7ytWeDk71B/vX3+9jeNPoBEEmkSJ6hZPBYd5CLvvw4DXVukuk0WxYUcu3yEpU5pZhX2E16vn7bOlr6w+zMvuiWlBZgNerQZieSRp2WPdmJoF6nobjAyKneEIc6/TTUuvBEEkSTKVJSYtJrkRKWltvZ3uQDIJZKsyPPS9Rq0NIYS+b2mfVa3FZDLgvaYdbz9LE+zHoNy8psSAlCk1ntfeFkP+UOEx+8ZhG3bqzOre46rQZes64SgCuWFHOkMzDqvgqFYn6RTKX564Eu7t/azEunRmcy6jRiXP26NzZU8/lXrcSkV8EmxblPfZGVd1xWRyiW5IWTffij45fZzgaheIrPP3SQh/Z28LVb17CguGBa13tge+uEA8tnYn2Nk/dftXDa11FMDCmlTwjxJPBKYK2Ucmt212+Bv41xzjllDOa2GnjFyjLWVTvnuin8+18O8ettk69cONjhp77ISrlWcLw7OP4JE8AfTfK2n23nD++/hFJ7fk8mheJC58WT/bxwsn/c41ZX2jnSGWCsB2Kl08wbG2qwm/RjHKGYb6jg8jjotBquW1HKdStKecU3nuFo9+ngjNU4vV9fNJkmPGQ19XDHAG6rHk8owaP7O7l5XSVXLyuZ1j1mikA0wSu/9WxeqYBBjnUHqHCa6PCdIeAuMhPjbY0efrW1hQ9es4iVFQ62NXoocxgBuG5FGe5xskcVM0u21G8H0C6lvEkI8XPgSmBw1vM2KeWeOWreWefedzbw7385yF/2dnI0z4D0skWFeMMJDncMsLDEhlYjCESTIOBkT3DYS3JjrYtef4y11Q4MWg3xRHrYopRFr6GwwDjKCTeSSFFfZM0FlzOeE2DSa9nX5iOWTPPgey8mmZb86yuXUe44c6mu3aSnoV4t5igU852eQIwP/no3Oo3g52/fTJnDxEd/uxcpJR+5dgnXLi/BE45zz9On+NW2lmHjCIC7LqvnszetmKPWKxSzw8oKBz+4cyOtnjCX//eTc9qWnc1e3v7z7Xz5ltXYTHpKHUYKjDp2NftYV+OkYALzgyNdfn783PQ1XC0GLd+4bZ2qCpxlhBDFQCIbWDYD1wFfBRxCiCVSymPZbYfnsp0zhRCCyxYVcaB9gLVnOcAspcyNeYGcad9UaOwLsbluel4FI2n3RXj7z7bzwHsvnlBfVyguJKSUfP2xo+MeNxhYTmSTJcx6LQuLrViNOsLxJM2eMJ5QnDu2zP9KD8Vp1BNxEhSYhv+6DncMYNBpzhhwHY/aQgvRRIpj3UECsRTLXGYC0SSJlOTtP9/O5YuLuGlNOdUuC2UOE3qthmr32S1pTaclzxzrO+P33FDjJJZMc7DDf8ZrDdWTW1Vh56t/OzKqxOmLjxzmdRuquPPiWhZOMytEMWE+TGZAbB+y7ZMj3XUvFCwGHd5QYlTQZpBALJn7W9/T6uPyRUUMRBIc7gqwpsqBQadBCIEGON4TwKDTkk5Ltrd6WVhsZV2Vk4OdAyRSkhUVDnY0ewnFUmysdeUypiEz+bx4YSHNfaFc3/GGE2yocbK51sXaalcuo1qhUJz7HOny448kMek12Ex6Kp1mFpfa+MXbN+OyGtBnA0glNhOfvWkFb7+snntfaOLBnW30h+LYjDo+9cplc/wtFIrZY75k4zf3h7njx1vz7rtxdTkvW15CmcNEIiXZVOvCpNOg0QiEEOxu8fLWn26bkQzs/3fTCuqKrNO+jmJcyoFfZJMxNMADUsqHhRDvAn4vhEgDXuAdc9nImSSeTE87kWoipNKZOW+t28KGWidf+9tRvvDqlVy2uAiLQcdVS0v48l+PTOnaDXXunETjTHKo08977tvBD+/cpALMCsUQnj3el7fKfSS9gVgusLym0kGbL8KBEXGkuy6rVwmH5xjqaTgJ/uuW1dz94N5cCVsglqKowJAzD5gK+9oGqHGbKbQa6A/FOdIVZFGJlRM9ISDTQZ89PtxMsNJp5v/dtJzrV5VP/cucgZ3NXroGovgicZ473sdjh7rPWIJ78UI3L56c/Iu7zRfBqNOSSA0fXAeiSX7+QhMryu0quHwWEEJUATcCXwI+NsfNmTP80QTHugIEY0m+9fhx9gzRFB9JOJbi0oWFxFNppASNhpx++sgS15UVdtLpNAfa/WyqddHSH+Jkbwi9VrCopIBIIoUQ4AnH8TTHqSu0kJKSVk+EtIR4IoUnlDElcZh1VLss6DSCZ070sWJfR072QqFQnPvYTHqWldl57KNX8prvPs+N334Ol1XPV1+3hquWjq5kqnSa+fQNy7n7+mVsPdXPn/d05ALQCsX5yC9eaJrrJozLI/s7eWR/Z+6zzaRjaakNIeDqZSX842D3jASWr11ewu2b55eE3vmKlHIfsD7P9j8Cfzz7LZp9zAYti0pmfx6mEfDTt27idzvbONoVoGMgygd/vZs1VQ4a+0LcsaV2ytce9CeZDZ4/0c/rf/AiP3rLRuVloFCQyVq+f2szDfVu4sk0Lf1hPOH8cTKbSUconmJJiY2dLfmD0TNtoKuYfVRweRIsLbOxodY1LHiUltBQl9kWm2AGs0WvYWmZDb1WC0KCFAgBC6UEBGkpWVulG1OHrd0X4Wt/P8oVS4qxGGb+f+HJ3iB3P7hvQseur3Hy4kkPDXUuGvvC9AYn7sy7pMR2xtXkz/7pAELApYuK1MNldvkmcDcw0p3iS0KIzwGPA/8qpZxZ2+V5xnPH+/jX3+8bd8K3uLSAVk8Yh1mPViM40DFAKJ5iS72baCKFJxyn1XParM9q0HGqL8iikgICsSTxtOSShYXEk2laPWEwZQLGLZ4wAE39YawGLXWFFipdZvqDcaJJic2kI5JIc6DDT43bgkbAr7a2sLTMxrIy+1jNVSgU5xCV2XedTitIpSVajeCG1eX84oUmkinJtStK856n1QguWVTEJYuKzmZzFYqzzpoqx1w3YdIEoklO9AbxhRMTyuiaCEUFBr7yujXD5AMUivmGNxRHwhmzD4UQaDWZDOYyhxmbUUcglqTKZWF7k5eTvUHWVDnYN2Je3FDnRgjY2ph/LqnTZK47mxzu9HPbD17k+X+9RvVFxQXPE0d6+PvB7mHbFpcU4LYa6PBFaPVGMBu0OEx6qlwW+kOJMQPLAD94+iR3bKmZNxVLivFRweVJ8oqVZTywvZVQtlzeE4qzLauJ6rboqXJb2Nc2QKXLTKXTjJSSHc1eBr3ulpUV4Akl2N06voHHplpXXuMvgJO9IV75rWf5r9eu5pIFhTP6QrtueSlaTWZieybcVkPO5HBP2wDJ1OjgulGXuc7IuLtGZFyyz0Q8leaT2SD3FUuKectFtWNOrBVTQwhxE9AjpdwphLhqyK5PA12AgYwByaeA/8hz/jnlfn0mblhdzoH2Ab731MkzHucw6TmeOG3Kt77aye5WX25wq9cKVpTbOdTpp9ZtyS2gDK1w6A3EON4TRAgothkpd+jRawVOsx69TkMwlsSs15JOQYFRR0NdRiu53RchFM8Ev0vtJtq8Ed5z307++P5LVdmQQnGOk0ilc1nHjx/uIS0lX3v9Gm5aU8HRrgDlTmUepFAsL5/eYmqt20pfMD7uGHem8YUTuaDZdBECvvq6NRQVGGegZQrF7OGa4NhUCMGbL6rlaFeAhno3KSm5YkkRf9zdziP7OrEaTgeXSm1GagutufH1WFXEybTEatThtujxhGcvg7ljIMpTx3q5Ok91kUJxoZDRWj42avvxnox3kc2oo8CgIRhPEYmnhpnWj0VPIMavtrbwjsvqZ6XNiplHBZcnyYoKOwadJhdcHoonnMATHmBlhZ3OgWhOI7XKZabNG2FlhZ3jPcEJazTvaPZSX2ShsS+cd38qJfnob/ZQX2TlQy9bzKWTzFhKpyXHe4Ic7vRzpCuATiO4YkkRdrOeMruJdl/kjOcvKi7IvdjNei0xMiaFgzTUudnX7kOv1bChxkGbL5wz+0tL6ByI4LLo8U7ghf/MsV62Nfbz23dffNaNJc5zLgVeLYS4ATABdiHEL6WUb87ujwkhfgZ8It/J55r79Xjcff0y/uXqRXzjsWP8cmszdYVW4sk0BSYdWk2mqiAUS7Khxok3HKexL4w3HKfUbqTbn0nsTqQkXf4om2pdNPWHMOo0uaoGo06wpsqZ01XOSGoInj2RcdRdVmbjSIsPgE11LnQ6aO2N0DbCJNMXTtDiCfON29ZS5TKrwLJCcR4wVM7iDZuruWFVGVpNxtfh9ntepLbQytVLS/jwtYvnsJUKxdxS5TLztVvX5JIPJsu2Jg9GneasB5cBjHoNgWnWgAkB/3PrWl62XCVbKM4/lpbZ+MnbNhNNpDDqNGw95eFkb5A2b4RimzFr9pUaVvm6oLiAAmOUpv7R8+XtTV60GsGaKgdaIejwReiebifMw3vu3clL//ayszoejyVTHOkMUO22qHmAYs75+8GuM3pvraiwD6syONTpZ0ONk13Zee9YfP/pk7yxoQazQWUvnwuo4PIksei1/Pitm3jrT7cTHCP7YGTHshi0rK9xYpqE+Z9WwMKSAlo9EWrdZpqHlNlXOs3YjFqMei172wboCcR404+3srnOxaY6N0tKC1hX7aLGbcmZfaXSkmPdAQ53+jnZG+RIZ4Adzd5RWlQvnernVG9olD6Oy6JnUUkBhzsDGHUanBY9h7tOf8+BSIIFxVakhKa+EBtqnMNe/NuaPAgBa6scJNOSTl+UWDI1KTOyaCLNnT/Zyj8/diUOiz6bES1JpyVmgxajTj10JouU8tNkspTJZi5/Qkr5ZiFEuZSyU2RS4m8GDsxZI88yJr0WTyiOTohcZn4+zHoNdYWZAd3QF+PqSjuJlKTFE6bcYaYvmKlS2FznylsSO7TUx27SA1BiM7KjyYvDrM/0rSIrJr2GzoFobjFGK+DlK8vOitmKQqE4u+i1GrQaDVf+z5N89sYV/OztDVS7zONWVigU5ztCCF6/qZr/+cfR3KLuZHBa9FgNOjoGIrmqwrPBumonB9rHr1o8ExoB/3vbWm5ZXzVDrVIo5hetnjC/39XGCyf7KbWbKHcY2dnszRhtp9KsqLCPmmc394foPUPAOJWWOUmNukILeo3IGYnNFPFUmv974gSfvXE5mrNktP3Dp0/x9ceO8fAHL1PBZcWckkrnz1oeRKsRnOoNjdre4gljNmiJ5EnaHKQ3EOO9v9zJ99+8YVbkYBUzi/o/NEl0Wg3LyuzE80hAjMWx7mDu55V5Xor5SEnQCEEkkaJjIMqS0gLsJj3BWDIX8FpQZKXWbaE5q9W6vck7LHBl0GlYVWHHpNdytCtA/zilB5DJljbrtayrdnCyN4RMS5aW2TjeE8xdOxgj77UGHxoGnYadLT6WlhZwdMh3l3K02Vm+DPAz4Y8mafivx0dtf9XaCr7zxlE+G4qpc78QohgQwB7gvXPbnLPHfz58iD/sbh/3uEgizcJiK8d7Qiwrs6HXCsx6Hb5InGPdQapcZpr6giwrs1Fg1OXVWSwwaOnLDoi1WVM/yLyE7SZdbvHnVF+mb12+uIg2b4SiAgOxRJrDnX42ZSUzFBceWdf6HUC7lPImIUQ98BugENgJ3CmlnLrjrGLOiCfTHOr04wsn+Ov+TjoGohRaDTlNZoXiQueOhlp+8typSRvj+cIJfOEEDfVudjR5OBsJzMvLbWc0CZ4IGgHfeMM6ZeKrOK850RvkYIefD16ziMsXF/PDp0+SlhCMJdlS72Zro4eNNU5AoNFk5sodA5EJ9+OUlDMeWB7kp883Uu028/ZLz04J/wevWcRr1lVQW2g9K/dTKMbi4X0dw+JdI1lb5cibodwXjLO2ykEwluRknuDzIE8f6+VNP97Kz962GadFLaTMZ1RweQpYjTq+d8cGfvFiE88e78ttX1hsRQiBWa9BCEEskSYUT1JmNxGMJTDotBxsH8Bl0VNqN2E36dg+RI95JD2BGJvqXOxo8ubtsC2eECV2E5csdPPCydFmBvFketxSg3ysqrSzp9VHIpVp2M5JXiOeTOMw62nsG/shMdOoCff0kVI+BTyV/fmaOW3MHDLR1f8at5knjvbm+u/N6ypYWmbnZG8QrUbDiZ4AiZSkPxjHZdGzqsKOJWvuZzfriSVSaDUaTvWFEMCy8tMLT8U2I50DozXJI/EUjX2hXN862RtUweULmw8Dh4FBEdKvAt+QUv5GCPED4J3A9+eqcYqpIaXkPfft4MmjvQA8fqQnt6++yEowlqRAVSycMwghqoF7gVJAAvdIKb814pirgD8DjdlNf5BSjvI5UJzmw9cu5rbNVVz85SemdP62Rk8uWDWbrKl0sG+aGcsAr9tQpQLLivOeq5eWDNMuvmppCVqN4MWT/Tnjr8nOSwdZUGTNJWvMFv/9t6Osr3Gx7ixIOAohVGBZMeckU2m+9c/j4xwz9oLOYOJhpdNMlctMq/e0jOpQdrf4eP0PXuTedzZQ7lBxn/mKmp1MkWtXlBKKJ3PB5YZ6Nyd6AnhCo/WD27zDtYu94USutH1RSQEnevKv9HhCcQbCccodpryBJofZgNti4IWTHiwGLcvL7IQTSY53B0YZ6E2UVRX2GXGytpt1oyQ3ZpMXT/aNf5BCMQFuWF3Ob7e3nlFzXK8RhOMppMwY7v3iHZvZWDs8yLu/bYBQPMnX/n6UtITjPQHWVrnoC8bxheMsLbVj1GvoD8aocllygeUSm3FUZYAQGQ3zQx0DOC16lpTaONEd4Pc727ltU7VyqL4AEUJUATcCXwI+lpWwuQa4I3vIL4AvoILL5xxCCC5eWERPtqrBqNOg1QiOdgewmXR86Ne7+cprV1NiVwZ/5whJ4ONSyl1CCBuwUwjxmJTy0IjjnpVS3jQH7TtnKXeYqS200JxHa3Ui9MyC9upIkukpDshHoPQmFRciS8tsVLrMHGgfwKzX4heJKVcbDPU1mC0iiRT/+fAh7n1Hg5KtU1wQ/GlPx7iLNhPpe+2+SG7uvajYittq5ETv6dia1aDFH03w4d/s4b9ft4a6IrWwMh+Z/afseczFCwopMOq4qN7NtkZP3sDyeNhMY7943BY962tdY2Y294fiOc3icDzFzhYvhzsDXLqoiIY6F8vKbJNqS63bTN8EpDMmQl8gzlmSnAJQwTXFjLGopIDnPnU1D3/wMt56cS0Liq3csLqMV6wspcZtocRmZFWVI1PKU+3kO3esHxVYBlhd5eCiBYX8/n2X8K+vXMa6ahfbmjw01LnRaTSkpGRXi49EKoVRr2FjrZMt9W6SqTR9gSgOs55NtS7qCi1csbiI/lCMxaU2LHot2xo9hOIpOgYifPfJE6TnwJhIMed8E7gbGIxcFAI+KeVgjXgboNLczlHC8SQHO/wc7PCzq8WHTqshkcroRj5xpIf7t7bMdRMVE0RK2Sml3JX9OUCm2kD1zRniy7esnnImf0t/iHXVDiCziDvTLCqxcqhzbO+GyTAXBoQKxWzS6gnz7PHeUdv/eaibh/d18Oc97fxlbwd7W32sq3by/TdvnHK13toqB0e7Z6YvjsfOZi+ff+jgWbmXQjHX/PjZU+Meo9NO7gV7ojfEtiYP3lACu1mHICOl2u2Psa3Rw8d/t1fNfecpakltGhQVGNn5/66lqS/Mm3+yFU8ojt2ky2Ulj4deI+gZYUZS7jBS7bIiBBzu9LNjjCxivUawttpJq/d0tkZ9kZVOX4Snj53O4t1c58plIjfUuekPxSgsMBKMJokmUvQGYywsKsCg13CqN0hfcGaCy5FEioZ6F9sap58FPRH80QTheFIJvStmBCEEqyodrKp05LY9driL99+3i0RaUldkpdRu5Edv2UiJbfzswfU1Ln77nos50D6ANxzncIef3+/K6DrHU7CvbYCFxVYa+0JUuswsLbcj05KXsuW6Tf1hGurcw0wyY8k0vnCCX21r4YkjPXz3TRtUmdAFghDiJqBHSrkzW04/lWu8G3g3QE1Nzcw1TjFt/nGwi2eODZ9wdw1Ehhme/PS5Rt531cJhhqCK+Y8Qog5YD2zNs/tiIcReoIOMue6o6ITqt6O5ZFER168q48GdbZM+NyVPJydsrHGxo3nmxqxGnaDdO7rqcKqoebTifKPUbqI3OLp64NoVpQA8f6KPpWU2jnQG+Objx7EadGc07hsLvVaMMqqvcZtxWQz4wgnavGEWFBfgsujxRhK0ecJEEtOrOHjxZP+0zlcMJ4/HyLPAYBZdCbBNSnnziHPWkaneswMp4EtSyt9m9ymPkhkiX3X9SNJTdM+VgD8y2ldhZ7OXB3a0cnuDGgfNN1QkbhpoNAKjRsvSMhuPffQKTHotnlCcP+5u59uPHyc2jjZFIi3xhWJctaSIp7IBYbtJz7GeAL5xAtTra5xsGxJ4rnSaicSTREfcc3uTlzVVDuLJdC4wNSiYLkSmpH9Pm2+yX31CbGv0srLCzsme4Kh2zTSnekMEoiq4rJgd/rynnbsf3JczAQlEk/zfHesnFFgeymCw+vLFxWyud3PrD17MZSO5rQZO9oZo9UQotBpJjSilHbnqu7nOhS+c4JWryvjn4W7u/Mk2LAYt775iATeuLlfZ/Oc3lwKvFkLcAJjIDJy/BTiFELps9nIVMKYzpZTyHuAegE2bNqmwxTzi5SvLKHeYedX/PZfb1jViIToQS9LiCbOkdHIVSoq5QwhRAPwe+IiUcqSz8y6gVkoZzPbrPwGLR15D9dvRRBMpHtrTMeXzj3cHqC+ysqPZy8Ji6xlNhSZDLClZVGIeU/pOobjQMeg0bKhxjbn/0kVFAJTa49y+uYbaQgv/ONiV8yOYKBcvKCSaSGHNzhFDsSRlDjPbGj3UuC0UFhg5nu2nC4utWI06Eqn4lCUmIVPiv7vFy/ozfD/FpBjmMSKlvHxwhxDi92Q8C0YSBt4ipTwuhKggI0n1dymlD+VRMiOk0hJ/dPykylAsNe4xk+XLfz3CdStKKSwwzvi1FVNnxiJxQggT8AxgzF73QSnl54UQPweuBAbdLN4mpdwzU/edLzgtBmLJFNd9/WlC8Yl1oIY6NwjY1pQJwpr0WpASh8VAjz9KJJ6ie8gKba3bTKnDRCSeZl/bACU2I8U2IxaDFk8owcne0RqxZQ4THb5I3oxkKcGi1xKYpNP2ZPCG4qSmuFo1WU71hihVGpSKWUAjBO+9ciELiq001Lsps5umHbxdX+PitesraeoPMRBJYNBq2LLATSol0Wk1bD3lyx1b5TKz9VQ/NW4L5Q4TkUQKkJTajXz7iRMIAQathlgyzQd+tZs/LW/n31+9kkqXZXpfXDEvkVJ+Gvg05IzAPiGlfJMQ4nfArWSyMd5K/sG24hzAOyTLatDYdySeGZKxUsw+Qgg9mcDy/VLKP4zcPzTYLKV8VAjxPSFEkZRSGUqMg0mvpaHezXMnpvarCsZSBGOZgLLNqEcjZi5L2GHWz8yFFIoLjFRaohGZyoLFpTb+5eqFrP7CPyizm6gvsk7YNH5jjZNnjo9+NrRm/ZBaPMP12rv9MYSACqcFs16LQSfY3356LdCi17CiwkEkkcp5pYzF++/fxaMfuhzXBI3CFfkZ6TEyYp+djN/I20eeJ6U8NuTnDiFED1AshBhAeZTMCIFoYkz51qEc6vRTX2SlwKgd1p+mw0AkwZcePczXb1s3I9dTzAwzmeYZA67JZl3ogeeEEH/N7vuklPLBGbzXvKXKZZmwptPhzgEQGWOwfC+ojHFXAeUOE/5Ikt2tPpo9pwPI0UAsZ0ayqTb/ymiNy8zuVh8Nda6MRqsvgjecoMplxmnRc2CGOng+NAIsRh2JCZRLTJeiAuNZceZVXJi8am3FrFzXqNfQMRCleyDKse4gNqOWcqeZY93DM50qnWbavBFaPOHcQHhJaQGQxGrQEoqncpUSxQVGjnYHePk3nuHNF9Vy05oKFpcWqPL5C4NPAb8RQnwR2A38ZI7bo5gi33vqRO7nQJ6SwOXl9jHf+4r5RdZs8yfAYSnl18c4pgzollJKIUQDGU8UVVc9Qe68uHbKweWh7GnzsbHWxc4ZksfQnU3zEYXiPKA3EKM/FCMYTfLdJ0/w8ZcvZUW5HatByyMfuowOX5Sfv9A4bnDZqBMsLLZxtHtylQPBWOZ9OzTxqqjAwMpyO/2hOJFEih3NXgqMOhaVFJBMpXFZDEgy/X2otE4smT6jt5JiwnyTjMdIvlKtm4HH81QDDSP7XjUAJ1EeJTPGeJX2Qxnss8vKbEjJjGig/2FXO7durOKShUXTvpZiZpixJ56UUgKDT3B99t8FVbJn1Gn57pvW8+Hf7Bl3NRMgEEuxrtrJ0a5ANhNxOL5wAkHml3j8DC9HvSajOVzuMNHljw5bQUqmJYmUHCahYTNqafNGaPOOznSeKVZW2DHqNOxq8QGgFRltu9nig9csUk7ainOOlRV2HtjemntQFhYY6QnE2FznomMgSrndRIFRx9Mj9FeNOkE8mUarEayotHO43U8wnmJZmY3eQIzW7CLUD585xQ+fOcVli4q49x2b0WiUh+v5hpTyKeCp7M+ngIa5bI9i+nQORDjaFWBTrQtfJEE8labElnk2aEVGVuf9Vy9CNwH3bcW84FLgTmC/EGJPdtu/ATUAUsofkKk4eJ8QIglEgNuz42rFBFhT5Rj/oAkSS6SocJrwhROEJ1iJOBat3jBCMKHMLoXiQiadlhzq9PPAjlaOdAX40s2rWFhcwId+vZsim5Hj3QE+/vKlmblls4+Gejc6jeCFPNrGbquBSqeZ/e0Dee40OUpsRqpcZp4ekf0cjCVzkjdN/WE21bo4NUJSxxuOX1iBkFlgAh4jbwR+PM41yoH7gLdKKdOTqTxVPgdnxhuefAXdka5MUHlJaQE2o5597T4SI4JEdYUWrEYtp3pD1Lit2M06pARPOE5zf3iYwe1n/3SAxz56JVq1mDsvmNGZiRBCmx049wCPSSkHDUu+JITYJ4T4hhDivBVGOdLl53h3kKNdARrq87vZ1rotrK92sqDICsCeVh+rK+1jXrPEbqI/cOaOu77GxbHuIJ0DUawGLRtrXVS6MsZeu1p8rCgfvtAXmAXdm0HK7CYWlVg52OEnkkixocZJUYEBhGBTrYsC4+wEgAsLVMmR4tzjDZtqePNFdVQ4M3IuTf1hnGY9Bzv8tHsj7Gj28tSxXjaMyFBcWeGgqT/Myd4Q2xu9OCwGlpfbONIVoD8UZ0ONk401LrbUu1lX7cQbjuctC1QoFPOLVFryzceO4w0n2NHs5WRPkFjWfHdtlYPVVU7ecVn9mGMMxfxDSvmclFJIKddIKddl/z0qpfxBNrCMlPL/pJQrpZRrpZQXSSlfmOt2n0sUGHWU2GZmenGgw0+HL4qUkkUlBdO6VocvykaluapQnJFDHX4GIgn+dqCLz9y4HH8kwUun+nmpsZ92X4S9rT684QS/3d7KsjI7D33gUhrq3CRTaRrqXCwvt7Gm0oHbqmd9tZPiAuOMBJaXldmIp9K5RKkzEY4nScnhIs1SkqswVkyZQY+RJjKSb9cIIX4JIIQoIpNQ8chYJ2dlMx4BPiOlfCm7uZ+sR0n285geJVLKe6SUm6SUm4qLi2fi+5xXBKIJGurc1BVOXobxWHeQnS1eLAYdDfUuKpwm3FYDm2pdNPWHOdgRIJJIc7Q7wPYmLzuavdlgs4X6otP36x6IouLK84cZrdWQUqaAdUIIJ/BHIcQqMrqQXWRKEe4hU7b7H0PPOx9Whbr9UT7+wN5cxvK2Rg+bak87T5fZjVS7LWxv8tLsCWM2aLlqSTG9wRinxijtKSowYNJrWFhiJdw22qwPwGrQEh+y2hOMpdjZ7EWQMf1LS8ne1um/YCdCqc3IohIr0USackeKw53Dyx12NHspsRkJzkJwe1Otmmgrzj00GsGnb1hGqzdESYGJnS1ekmlJdEQlw85mLw31bva2+ogl0/jCiWHGQ+2+CO0+WFftwKDTsq/NR3SI03W5w8iDO9u4bFGRynZUKOYxD+1p5/Ej3bnPeq2gNxhDStjbNoBOI1hePvaCtEJxIWIz6YmnZtY4OpJIE4wm0GkEyWmIMO9uyfiqTKSiUaG4EDnU6ef1P3iBD75sMV946CBHugLcv7Ull+E4yP72Afa3D/D1x47RFxwdtC13GGn3RaYc0DXpM+PjwfGzRky87P9QZ4BlZTac5iS9gRjh7DW2N3qoXK8UF6bKGB4jb87uvhV4WEqZV39TCGEA/gjcO1SeNSs/9STKo2TaeEIJtjV5AKgvslJcYOBYT3DC/UanEZTajYCg0GqgPxgbJi2Tj8a+EFoBDfVudjV7qS20KhP7ecSsCAFJKX3ZTnu9lPJ/sptjQoifAZ/Ic/w57X4diiV5449eGlUOs6PZy/pqJ5FECl84wfYh0hQVDhNHugJ0+cfWI15QXMC2Rg+b61zUFlqHadNsrHXhDcc51RtiT6tv1LkS2N3ioz6bIT3baAXYzHqeOzG2RKDDrKfaZZnxVdwrlhRnH0wKxbmHXquh0mnBH/HTUO9Gr8kYcY408NrW6MFl0XPRgkJeONk3qoQIMvpue0YsJm2oyUjvPLyvk+tXlXHTmtnRj1YoFJOjuT+E2aClxHbaiPa+l5qpcJhzJryLSws42BHAoNPwvTs2UOYwqQwNhSIP8TwJGNOlyx9jfY2T3RPIXByLlIRoIoVJrxm26KtQKOCJI908fayXtIStp/p5PitzMTKwPMiLp/rzBpYBOgdirKtyTmqeaTZoWVxcgNmgJZmSdPoj6DQaXBY9XZP0DBps89JSW27O/uDONm5WweXZ4nbgK0M3CCE2Ae+VUt4F3AZcARQKId6WPeRtUso9KI+SGcE3RBajsS+UC/yurLBj0muzppwAgsGhq5SZbf5oglO9wZzPkCCTdDURUjIzL64vsrKxTlUHzSdmLLgshCgGEtnAshm4DviqEKJcStmZNTS5GTgwU/ecD6TTkt4zvMR25wn8QkZbdSASpNptzumjDmV1pYOBbIfdPiLItL7GyZ5W3zC9mbEosRkn7Kg7HTbWudnW6Mm7TyMymcWHOwfY2TIzJimDLCuz8Z+vWalWrBTnBIc6/Cwvtw37e5VScrjTz85mL7WFFk72htAIKDBosRp19IfipKUkLcEbTuCPJPIGlgEOdwZwWvS5FePNdS6SqdOlvU8c7lHBZYViHiCl5F9+tYsv37KGEpuJdFryl30d7G8bwJl1lndb9MSSmb7+mrUVXLuidC6brFDMWzp8kbzeJTPBoY4BVpTbOdQ59czjk70hSm1Gqlz6nE6rQqGAREqyssLO3lYfx3uCXLO0hJO9QQoLDLx0avS88i97O854PaN+ctV5qyscuczLobTkn9JOCLv5dHjlTElkiskx1GMk+/mqPMfsAO7K/vxL4JdjXEt5lMwAvsjoDOWUZEqVOiV2I93+ySUgNvWH+J/Xr5n0vRSzx0xmLpcDvxBCaMloOT8gpXxYCPFENvAsgD3Ae2fwnnPOrhYvt/7gxUmft7PJw/IKO2a9Nm9wWacR7B/DxO9kb5BNtS62jgjmFtuM1BVa0AhBWmaC3r2BKJvrXKTToNFkNKGOdQfHDE5NhZUVNrbneTEPsrnOPaqtM4HbauC7b9pAbeHZyc5WKKbLiorR5eyeUJwv3rwKgPffvwuAtIRgPEUwnsKk06ARglhKkkpLbCYd66qcGZMg5KhM5UqnmUUlBcTjKQSCg50DxJNp3FYDJr0WTzCGu0Bl+isUc0kqLbltUzULiq08f6KPj/52Ty7banFxAU6zHotBS+dAlC31btT6qUKRn0A0wZ0/2TprpnmxpKQ/GMsZ8+m1Ar1WM2mzv+5ADJdVj1mvnbVAuEJxrnH10hKiiU4eeM/FfPuJ4zjNehKpNGurnXmDyyNZU+lACNBl++VEzjHpNaypctDujRKOJ2fiawwjNqSK4rZNVTN+fYVivjBR+YuJ4LIYJh1cfsel9WxU0qjzihkLLksp9wHr82y/ZqbuMR+pdJnZXOcalV18Jow6wYLiAtJpOeZ5R7sDuCx6vHk6rT+SZFujh8UlBRwfkgFRbjflvd6pvvCI+2tYWWHDrNeSlhIpIS0lKSlJp8n+V5JMp0mlJcmUJJGWJFNpkilJPJVmS72bk30hNGR0psYa1Gs1YlgbJ4PToses19A5MPpBoxFw/aoyjnUFWFg8PcMVheJsI6Xk3/9yCLfVgE4reP9Vi5BS8s7L6vnD7vZhVQCDWutrqxxoNYJoMs2eNh9Azi3bYtDij2YGyIOrxRtqnBxo91FmN2Iz6enwRdja6OF3O9t4z5ULz+4XVigucDyhOAVGHQZdJqtKp9XwlovrCMWS/OfDh3KB5XVVTl44NVxeqicQY3uTh/+6ZbXSTFcoRnDvi805/4HZojsQY3Odi1gyzbGuABVO86QzkJeUFnCkS2UtKxRDMeg0vGZdRjai1GakptDKRQsKOdU7sb5iNmjZ2ujBpNMwUdGZtVXOXNJTu290gtd0aewLsSHre3TrhuoZv75CMV8YyJO5PFUa+4LD/MrGo67QwidevnTG7q+YGWZFc/lCwmk20B+Kj39gFrtZR7ndnDO7W1OVkb9ozmYvuy16POEE4XiKxSUFeMP5zfgkcLwniM2ko8xuwmU1EI5NbPU1lkxP21gklkzT7h3/hby83MaB9vHv5bYYWFiSyUBOpSXBWJLGvhAaoaPWbaHZE0aQ0egRwEeuW8IHr1k8re+gUMwVsWSaL7x6JZAJNAMIIbi9oYY3bK7mc38+yH0vNQ87p6k/jNOsI56SNNRnVmmPdPmxm/VE4kk21DjRaTV0+6O4rQZ6AjEWFFs52RumZUh1xLcfP87LlpewqMR2lr6tQnHh8tKpfn78bCNSSr5zx3oMnA4O9wSi3P3gvpxO44pye27haCQSSKYlOu1ZaLRCcQ6xb4w+M9MMTd440RPMZTJPlOPdQdxWA55JzBkUiguJlRUOdrZ4+dT1y/jJc40TOmewC5Y5TBQVGNEIweFOP4Ex5sTLymyzLhcZiCbZldVpP9od4OKCwlm9n0IxVwzVXJ4usaRkR7OXjTVODnUGxq3w+err1mA2qEHxfEOlwEyTB3e1cao3hFEnWFvtYF21g811LuoKLaOOXV/toMxuHGbMt69tgBZvhGKbkdpCC55wgkKrgauWFnOwI39geSiBaJLjPUG2NXrOapndRAfUhglmWYXiGcPD7U1edrX4ctIdnlCCZk8m81qSkQtIyUz2tUJxrpIe0oFG6oULIfiP16zkji01uW0Li62k02maPRE6B6Jsa/SwrdHDgqICPKE4kUSaxr4QqZSkuT/M7hYfJr2Wdl+UZWWng8h1hRZWVjr44iOHOdad3yxFoVDMHH/Z20G1y8yP37oJiyGznn+yN8h//OUQN3zrOZ462ps7NprMvMMXlxTQUOfGbdHn9pXZTZj0ahCtUAwSjif53lMnOD6GhNxss7F2ciZCkkzfVigU+VlQbOXJIz0kU2lWVtgpd5hwDnkP5mMwQaOpP8zxniDheDJXIZSPI12BsxqQOjHBDGyF4lwkn+bydNnZ4qOowECNe3QsbZC3XlzLlgVq0WY+ojKXp8mdF9VyoG2AvW0+9g7RPhUC1lY7MGg1JNMSvUag02gw6LTA8BVTKRlmCtgfihOMJkmmM8Ego16LVmTkJ/JRYjNSV2Qd01BvLvFOcEWr2GaibQKZ0IN0TtLBV6GYTwwGmZKp9LAydyklTf1hHGY9ZXYT//GalZzsCfJSo4dAbPTi0Z5WH5cvLiKeTHOsO5AzzNQK8EcSeMMJvGEfJTYjVqOORCrNtkYPDrOOjz+wl2uXl/LBaxZN2J1XoVBMjtWVDl442YcQggd3tvHE4W66A1H6g3GqXGYWFFs41h3EYdZT5TQD5KSkttS7afWGqXCYeesltXP5NRSKecVLp/r55j+P89IICZmzyVSM+ToHZr4EX6E4X1hQXMDC4gL2tvm4fHExTx7tpXMcI802b4RVlXb8kQQCONDhZ3Odi4XFBexs8ZJKj86GKiow0twfHn2xWcBmVKEWxfnLwAxqLg+l1RvBoBU01LnpC8Zo80WIZ2Uiq91m7r5+2azcVzF91BNvBvi3G5fzxUcO4QnFc7qJUpILNq+qsNM8EMETmngHbPGEWV/jpMMXoak/zMZaFwuKrBk5Cl+EFeV2bCYdwdjpzOWzyUTNhZr7w6yssOPLZmT3BKJ05RFrz5iWZTKTJ4JFlUEozkOEEJQ7MhmKH3rZadmXgXCCj/9uD/883IPbqh/2LOnxx3CM0GdPyczg2R9NEE2kM8+lQIxNdS7avBGWlNrY3uRlf/sAR7v9fPmWNTjGyQ5RKBSTIxxP8uTRHv5+sJvtTY/TF4xR5TTTmJ3U2oJxlpXbEGTelVaDbtgiayot6fBFaahz86q1lXP0LRSK+ccXHjpIJJGiwKglmGfh9Wzgn0LGVn8wTlGBgb6gksZQKPLx3TdtADKyURcvKOTwOMHlzoFoLuFocIF2UMLmkgWF7GsfIDhCIkN7lhIqFhRbuWJJ8Vm5l0IxF1S7LZyaJZmZeEqyrSkT3xJk+neRzch7rqjHqhZt5i1KW2AGcJj1/Pfr1vC5V63AmifoadRpiCUmajOQoScQY3eLL+eaubPZy6m+EBaDlqWlBRzq9LO10cPBDn9uJedsUWY3cnKCZT5pmTEYa/dF2Nc+QLnDnPe4E70hVlc6JtyG7z55kiu/9iSf/dN+0hONSCsU84x85lz5St8dlswz5tJFhQSjSTbXuVhVaWd9tZNWT4h9rT421brYUu9mcYmVLfVuCkw6FhRZh10nnZYsKS0glTr9zHh0fxdbvvzPURrPCoUig5yMsGoWfzTB+365i05fJvuiymVmTaWDIpsxd0yF04w/kswtDPUGYrn3WbnDRCp739dvUoZACsUgx7sDHO0O0NwfpthmAqDcYWRjrWvcEvqZJC2ZVHn9ygobKSlVYFmhmABFViOFBYZJndPmi2AzZYJOdYUWwonUqMAyZAJVZ4O3XVKH2zq576BQnEu854oFZ+U+kkz/3tPqw6gk4uY1Kuw/QwghuGlNBW3eCF/565Fh+3a2+FhRbiOWTE/b0VoIODpH+nKQycI+MA0zwJ7A6KxlyLzoJ/uw0AjB+65SJf2KCwN3gZHP3riCJ4708KNnT+EbUYo01F23od5Ijz9K04iyv10tPjQCNte5h22PJtI8tKeDp4/2cumiQt60pfaMmnUKxYVCMJLgj3vauXVj9YQDSad6g/znw4do7AthM+nQaTW5TKpq9+kF1qPdARrqMrqtm+tcSAkrK+3EEylePOXJZWOtKLfP8LdSKM5NmvtDfOJ3e3O+H419IdxWPZ0DMToHYqytcuAbwwh7opTajFS5zUgJfcHYMEPcQbQCNta62d8+sXuVO0w090eITjLRRKG4UNFoRF5Ji/FYVmZDIwSNvcGcZ08+lpYWcKInSGoW85OsBhVmUZzfXLywkDVVDva1Te+9OxlS6jU6r1FPvRnmDZuq+dEzp+gf4QZ9qDOAVsCaSgd9oRgdvslrBjvMejQT1aOYBard5mkFlgE6BiKYdBqiQ7KtV1XY8UeTk5L2sBl1/Pztm6l05s+EVijOR5aX21lebuf1m6r4wP27c+VCIznZE6TKZWJznWuYwz1ksq284TiXLyoiHE+yr32A1ZUOtmev9c/D3Ty6v4tUOk2xzYhRp6XLH0UrBOFEiv5gjLpCKz952yaMOrV6rDi/6Q/HedOW2kktYn7r8eM8mTXqu3hBIeF4pmy/zGHCMyRrcVGxFX8kzpLSAnY0e3MBs6VlNpaUWjnaHcJt0XP/tmY+cPXiUfdRKC4k4sk0//uPY+wdMYkdlInSa8WMmF6W2E3sbPYBmYSORSUFOX3lRcVWCguM7GsfGPP9OxSzXsOKCgeeUIzOgdEZlIpzByGECXgGMJKZPz8opfy8yLgyfxF4PZACvi+l/PbctfT8IJ2W2E063FYDntDEs/0Hx7wakfE8SKflqLnr1ux806DTsKHKMWqcPFPky5pWKM4nhBC854qF/Muvdo15TEO9m3Ra0jUQpc03fd+BVFpFl+czKrg8w2xv8hAfY0klJWFf+wA2k46FxdZcFvPaagcmnZa0lGiEoLk/TH8oRmLIcuqCYiunekMMzIIr50TQacBtMdCaJ4NjMkgJa6qduUDyinI7hzr9E9ZaHsRi1J7RRVShOJ8psZn41CuX8p77do4qsS0warEadextywymK5wmKhxmUlIST6Y53OknnZbsavESiqe4dGEhL41a2JHsavGNef8Kp5l4Mq2Cy3PIGSa6PweuBAYjMG+TUu6Zk0aeB9QWWvNuj2f9DwxaDf841MXli4tZVFJAOi1ZXmbjVKUds0FHIHr6nV3jNrOtMbOwvLDYysmsTp1Fr2VDtZNYMo3FoCOZTtPcH8Vm1OEJJ9jfNkBfMEZRgTFvWxSK8510WnL9N5/Jq+1Y5jBR6TSzq9mbCxpNFZNOg8WgZVOti3A8hSccJ5lKs6HGiUYIdrV4OTHBCsTNdS4OtPvZ2Tw7gSvFWScGXCOlDAoh9MBzQoi/AsuBamCZlDIthCiZ01aeJ5zqC2HSaykw6vIGl006DQtLCtBpRc7jCMCV9SBJS9jXNsCaM0gurq92TvuZcSZ+s72Vt15SN2vXVyjmA9evKqO20DKmSaY/kuBIVwAgb9LTZNAIeGR/J0adliuWFJ81/XTFxFHB5Rnm5SvL2L+yjK6BKN9/6gS/3NoyqqwnEE1i1Gkw6TWU2U3DXopD2VTrossfxW7SE46f/dVPs17DklIbeq2GU33BUdkiU2Vbo4cqlxmtgJSUkw4sA3T7Y+xtG2BdtXNG2qRQnGtsrHXz3Keu4cuPHmZfW8awxG01MBBJ0O2PUmg10B+K0+GLDquUGPliT6TlsGfUuiongWj+543Loucrr1vDdctLlRzN3DPWRBfgk1LKB+ewbec8iVSavx7o4vHD3ZTZTVQ4zfjCCWLJFN5wpl89fayXZWU2QvEkhzv8VLkt7G7xEomn8IUzg+mhi8T72/wUFxjpDcZwWwyclCE0AsKJFDqthv5QnJSU3LqxihKbiQ/+ejfvvmIBn37lMsQcVi0pFHPN7lbfmKZB8WQaTyjOTFS3R5PpUcGmhjoX2yYxGdZrBVUuy6xlQyrmBpkR3x/UJdRn/0ngfcAdUsp09rieuWnh+cWikgIWlRRw9bISrvmfpwhlK4BevqKUAx0DdA1EOdjhp77IwrIyG3aznkg8SWNfmFKbke6sDGOrN4zNpMs7rvWGZ1f/3KjT5LKXdzZ7uVKZ+ynOQ7QawbsuX8Bn/3Qg7/5BHXTIVBZsqnOxo8mLVsCGWhetnggaAeUOM1pNpl+e6g3llazZVOvmL3s7+cveTiqdZt7YUM1tm6opsZtm6+spJokKLs8SZQ4T//6aVdy2uZr3379r1GpOXzBOQ72bZCo9Shd1kEENVbclyYKSAuLJNB0Do+U0TDoNQkBkClpuZr2GRSUFBKJJWj1hyp1mKpxmgtEkx3sCMxZQHkmbN8LyMhuHsytZU+HPe9pVcFlxQWPSa/n316zi+0+d4Jljvbx4KjMpdlsMWA1akmk9wVhyWPA4kUxT4TBRbDfSPRAd5XhvMWrZ2+bLez+zXsuWercKLM8DzjDRVUyTdFry5z0dfOr3+0ilJZvrXPxlX0fGiV5AfzCOOVt+3xOIUeO28MDONiqdJuqLCnKVAEtKC3BaDPT4oxTZjCSSaSKJFBUuEx0DEdZVO4jE0wSiCfyRBG9sqCEcT1FfZOU99+0EMrIaKrB87iOEuB74FqAFfiyl/MqI/UbgXmAj0A+8QUrZdLbbOV/ZcQYJCk8ozuKSAhpnybHeP8Zi61gkUpICo6rqOR8RQmiBncAi4LtSyq1CiIXAG4QQtwC9wIeklMfnsp3nE6V2E1949UqeO9FHfZGVR/d3DkuYaOwbPYd2WvQsKrFyoidEMpVmbY2TcCzF/vYBXBYDBp2GCqeJbY0TWwByW/RUusxoNRoOtg+QmGBWlEGr4WRPkM/8aT81bosKLivOW27dWMU3/3lsQoa1e1p8bKl309QfGrYIOzTGpdcK6gutOLOSsOFEkkgsyf6O03Gpdl+E//nHMb75z+Ncu7yUN22p4dJFRWqOOseo4PIss7LCwcMfvIzP/ukAfzvQhSSTZQEQjCY41Dl+cNUTTuBp8nL54iKcFj2eUIJqtxkhBI19IbyhOGurnZMuvWuod3O8O8D+9kz5vEZkgr5t3unr4UyEybhs5+PhfZ189sYVqiRCccHz3isXckdDLfvaffzg6ZM8f6IfTzhT8tcbiFHqMHGiJ0ip3cjx7gB1xVb2tg6g08DS0kzGRzSRosMX4YWT/WyscbGzZfTzpGMgyod/s4faQguv21DFmiqHCnzNIWNMdN8HfEkI8TngceBfpZT5nVQVo/BHE/znXw7xu51trKywYzFkZGa84URuQmvQaSjPZkl4QnE8oThb6l3sbPZSOiR7IplKs7SkgH1tvtwicn2RlVPtAyTT0DUQ5b9vXcPetgG6/VHec+VCUmnJse4Am2rdfObG5aysUGZ+5zrZfvpd4DqgDdguhHhISnloyGHvBLxSykVCiNuBrwJvOPutnX8c6fLzo2dPsaXeTXN/iNpC66js4tlcVbNMYaxqVkZe5yVSyhSwTgjhBP4ohFhFRpoqKqXcJIR4LfBT4PKR5woh3g28G6CmpubsNfoc5rtPnuDpo70c7vKPWVGXjzZvBJ1G5DKWnzveD2SCzr2BGJKMvNtE0IjMgtHgXHlLvXvCUhrbmjy85rvPo9MIvnX7+gm3X6E41zDptXzoZYv53J8Pjto3VB4OIJmW4/ahRErmvA4G2bLAjdWoZ98II91kWvK3g110DET4zJ8OcHtDNa/fWE2xTUnJzQVq9HMWsJn0fOv29SRTafa3D3DL915AO4VMY3/kdDC6yz88g/lkbzDfKWMiyOhDyyEj8qnIU0yH/e0DlNmNdPmnFvfoDcTY2eylod49wy1TKKbPkS4/iaQEJMvK7ei1mlm7lxACh0XP5YuL2Vzn5u4H93HNshKcFj2P7u+kPxjnptXlHOryE0qkOdiReY4k0+CLJoZJ8ywqsWIyaGioc+c1LArFktz7YjP3vtjM0lIbr99cxW2bqrGb9LP2/RT5GWOi+2mgCzAA9wCfAv5j5LlqojuaU71B3vfLnZj0Whrq3exs9pJKS1wWPbFEKnecWa/FqNdwzbIStjd5CESTHGj3YzXq8UUSXL6oiN5gjFgixUeuW4I/lkSv1bC9yUM0kSKZzhiFfeeODdywupzf7mijvtBKfzCGEIKFxQX85G2bsKgA1flCA3BCSnkKQAjxG+A1wNDg8muAL2R/fhD4PyGEyFYoXLCEYkn+5f5dLCg6HVD2hRNUusy0ZxMhrAYtfYGpr5/ptWKYfM1Q3FYD3VMYo17g/9vOe6SUPiHEk8D1ZBaM/pDd9UfgZ2Occw+ZdzKbNm1SfyAT4F+uXsSSUhu/2dYCwMULC/n+Uyfpn4DBXzItRwWkfeHTQS7dBBOTagutw6oiJnLv0dewsLC4YNLnKU6TXaTdAbRLKW8SQjwL2LK7S4BtUsqb85z3N+Ai4Dkp5U1Dtv8c5U8yo9x5US0vnOjnbwe7hm1vn6GkxR5/jFZPiDWVjlEBZsjI0LR4wvz3347yjceO8fIVZdyxpYaLFxSqbOaziJq5nEV0Wg3ra1zctKacnc2eSZfw7W0bYFOtKyeXMRRfOMGS0gIGwomcztSZkIDLnDE9mCsSKUk8Ob3x1fYmjwouK+aMpr4QFU4zBt3pwLGUkt/tbOO+F5vZ3z7AxQsKuXVjJa/bWH1W2mTSa/n2G09nSFy19LS3zN8OdPLeX5529HVbDQRHDL4LrUaeP9HP+honS0sLaPWEqXZb0Gk1FFoNHBjyQrcYtPzyxWa+8ugR1lQ5uGZZCVcsKWZVhUO9yM8iQye6Usr/yW6OCSF+BnxijHMuiInuo/s7KSownvE9EYol+Y+HD/HH3e2sqXSMesd6wwlWVtjxhROYDVrefmktVywuodptYUeTh4FIAptJxwd/tZtTvSFMOg0t/SGK7SYOdPj5fzeu4FCnn3dfvgCDTpMxCgvFuXRRIQAfu24JqyodWPRakmmJQafBwOwtRinOOpVA65DPbcCWsY6RUiaFEANAIdB3Vlo4TxmIJOgciHJqiIleNJmm2GrMTVhXVNinpG+8qsIOApIpSTiepGWIYbVOwMY6F419Ydqn4G4vUO+/8w0hRDGQyL5vzWQqEb4K/Am4GmgkE6w6NmeNPA+5bkUp160o5TN/3M/3njqZ19xvsmyocbKvzcemWheHO/05Ped8WEdI3BQYJx86WVPlnPQ5ilF8GDgM2AGklLnqACHE74E/j3He1wAL8J48+5Q/yQwihOArr1uNP5ogmUqTSEta+sP0h+I5v5GpUmo35uJmhzoH8gaYm4ZI5CRSkkf2d/LI/k7qCi186vplvHJ1+ZTvr5g4Krg8B/zna1byrnt30jkw+U52sGOA9dVOdrf6Ru071h3EZtJhM2oJxMZ+UQIYdSJnMjAbrKt24gvHx9SThsmVFo2FWglWzBXRRIpgLIlee3oSmUpL/vUP+/jdjrbcthdP9aPXabhmWSkuq2Eumprj+lXl3LapiudP9tMfjLGgyIpJr6XcYSYUS9IbjOX65O4WH5AxagjFU7R5M9UR66udeMI+1lY5hj2HdrX42NXi43/+cYzaQgvvv2oht22qVrIZs8RYE10hRLmUslNkfvE3A/kdNi4QegMxXrmqLO++B7a38tDeDnoDMRr7Q6yudGDSa3nZsmK6AzE8wTirKh0sKbVx+6YqEPDAzjZ6/TEKjDoae4P8/IUm7rqsju89dZIFxVa6AzHC8RSJlMQTjPO9J0/w6RuWc8UZtBYvWpAJMgdjySlNXBUXDhdaxUGF08y1y0t4aG/nsO1Hu/2Y9Rp0GoEvnGBtlQOdVkMolsSg07BvHL8Ql0XP0e6M4WaxzTgqFLyhzk0gmiQ5RkZzPmrcZoptJpKpNEa9hjWVDrRagVYI9rb5xsyOnigqG3rOKQd+kc2g1AAPSCkfFkI8B9wvhPgoGR+Eu+aykecbfcEYn/7DfrRCsKrSwTPHeqd8rVq3mZ5gnF3Z8e2OZi9Wg5Yatxm31cCe1tHPjXZvhC31btp9EZxmPXvyzL/HY6wxiGJiCCGqgBuBLwEfG7HPDlwDvD3fuVLKx4UQV81yExVZnBYDn37lcl73/ReIpzIV+uUO06RkbfJR67bkqoiS6Uw8bEt9psJWyozk3FhJm039Yd7/q118+ZbV3N5w/o+b5ho1i5kDXFYj33jDOm753vMTEj4fSiSRpicQxazXEkmMDiBrhMhqEJ85uFxfVMCRaZjpjcWyMhvJtMy9fOsKLZTYjZzsCQ0rJaovskw7sAzDHUgVirNJLJHmHwe70AiB06LnnmdO8cSRbjRCUGIz0jOkguBkT5C/7Ovgzotq5zzY+sXXrOLl33wGo07LgY4Book0lywspN0XGdZmyGR3xJKpnIwGwIGOAZaUFgzL1h5Jc3+YT/1+P0e7AnzwmsVzHlQ/TxlrovtENvAsgD3Ae+ewjXNOTaFlzD53pCvA7hYviZTEbtZxvDtAMJbkmbuvZiAcx2zQsb91gNdsqCSdTvOWn20jEksjNPD3g93c3lDDl1+7mhdP9vOPQz1sqHGiEZnsjZctL+Xrb1g7KWmLAqOOnkCUEptyvT7PaAeGlq5UZbflO6ZNCKEDHGSM/YZxoVQcDCWVR7NtqKxcIKvLaNZrWV3pwB9NUOk00e4bbYA9SJXLnNNQ7Q3EWFlhp8RmxGTQsqPJSzKV5lCnH7dVT4XTNMxAbCyC0RR9QT/hPFmQJTYjTosep8XA0S4/A5HJT7Tz/R4UZw8p5T5glHCulNJHJvClmGF84Tj/9chhHjvUPe1r2c06+kMJIiP6ZyieIuSJ0OKJ5E3e8oYTufnqVDyJNAJWVTqm3G4FAN8E7ua0DMZQbgYel1L6p3Bd5U8yC6yucvCZG5fz+Ycy+sudA+O/P8+EQacZlayYkrC10cPychu9gRglNuMZFQGkhH/9w35C8RTvvKx+Wu1RnBkVmZsjqt0WblpTwc9faJr0ue2+KMvKCjjVF86ZAw7isuhp8QzvgDoNlNrNw0r7jPqZLbldVFKAzaRjT4tvmLFKU3+Ypv4wgszL1aAVHO70k56c3PSY5BvEKxRng8ePdPPtJ07w7SdOjNrXUOcaFqht90X43Y423rSlFu1Zji2n0zInUXGiJ0gileZP/3IpRp2WVm+YLz1ymHZfGG8oTqnNiMuqx27KBINHBpYhU2pk0mvZ1+bLBtMyC1oDkTgDkSSVTjPBWBK7Wcex7gAXfflxNte5edXacl67oWpWtacvJM4w0b1mDpozb7k6KwtzoifAopLMvOR4d4AfPnMKnUbw6IcvR6fVUGY30RuI8ZttzZzoCbKx1sWHf7OH7Y0e7t3ahEGrQasRtPvCOZ+A50708ZaLa4kkUmg1Am84QUO9G40Q3H390ilpJivt8vOS7cBiIUQ9mSDy7cAdI455CHgr8CJwK/DEha63PMjIRc+xWF5uY1uThwKjFt047xmdZvj+gx2ZuESF08SqCnsuiOQJJdhcVzCh4LInHB+zIq8nEMt9j/oiCwatdtIlwin156C4gHh0fyd3P7hvxqpsF5fYxjW+14+RNKHViHEXdxrq3fQHY1gMWlo8EQYiGdnJ122omrB5oGI0QoibgB4p5c4xMpDfCPx4CpdW/iSzyFsurmVrYz+P7u8a/+BxWFftZNsYCYmHOwPYTDpMeg1mg3bU4tFI/vPhQ0TiSf7l6kVznux1vqKCy3NEKJbk97vaxj9wDLr8MawG7ejgstWQW92pdpspKjDSPRDFYtCyrCyzulPmMGHRa2moc3OiN4AnNHXd5RKbEbfVMG4WtIScVqtFr6HYZsSg03C8Z3JGhCMZ6UCqUJwt6oqs1BZaaM4j/dLUH84Z4jXUuegNxmnxhNjW2M/FC4vOajuHah8vKhkuIxOKJWmod2PWF7OmysEfd7dz/9aWYcdsrnMN07N0mPWk05JYUuZKCyFTtdA5EB22Qu206NFrBc+d6OO5E3187s8H+fjLl/DuKxbO8LdUKM6MxaAlnU7zz8M9/PyFJl442Y9WI2iod1PlsnDvi0186hXL+Mh1S0mn0/xyawvPneij0KrnYIef6JBMyTWVDlZU2PnMjcsRQvCadZUYdVre+8udNPeH+OU7t7BgipJNJr12/IMU5xRZDeUPAH8HtMBPpZQHhRD/AeyQUj4E/AS4TwhxAvCQCUArYEKBXTgdfA3GUoxXvXcgKzF3qi+UCwIN3mvk/Q53BjDpNEST42dF7Gr2UuEw0XGGTK3GvjBrqxyTDy6rzGXFeczOZg8lNhPVbgsAD+5so8RmZGOtC08ozv48Bl6ToXNg/Kzjpr4Q62ucCCCRSpOWmbGDlIzyYjDoNCwostLhi7Ck1MahjoHsswcWlxRQYjMQiacxG9Q7fZpcCrxaCHEDYALsQohfSinfLIQoImOYe8tkLyqlHNRaUv4ks0BGf3kNe1sHJuxbYNZrWVM1Osv/YMeZ+34knuKFk/0YtBo217no9sdGJVoO5X/+cYxgLMWnrl+qAsyzgAouzxF/O9A1Zf0Zq0FLXaEVg1ZDJJHMlfZBJjNRp8no0Ri0GqKJ1KhB7lB5CqtBy+pK+7BrTIaaQgs7JmmkEk6kcy/pGreFMruJYz2BYS6+E+Vzfz7Iz55vYlOdC71WQ5XLTG2hlSsWF6kHhmJWWV/t5O8fuYKbv/v8qMWVnkCMlExnVluH9I9fvNB81oPLZ2J9jYv1Na7c53XVTna1+Djcefp5cKjDT4FRmxs0D0QSLCsbXZlmN+vRaeCuyxdS7jDx94NdvHCynw01Tpqzhg6xZJqH93WSTEvuaKjBaVFyGYrZZ3ezF18kwfvv352Rrchu31jr4suPHqE3GOP6lWVIoGsgSlN/iM8/dJAKhwmTXksyDZ9+5SJes66CZ4/3cd9LzfzXLavQDMl+vH5VGdv+7WV4wnGWldnn5Hsq5i9SykeBR0ds+9yQn6PA6892u+Y7qbSkyz+x4LJRN/EgTiIl2d3qY121c1wN1WAsyaJiKyd6xzfhTqQlRTbjGYPLAMd7ghPyRxmKCi4rzmfWV7uGJUP8v5tW8PTRHp4+1ot5mouutW4LzWcINg0ytMJgKAVGLZvrXAwWDwgBnb4oR7oCaEWm8mGoVOVg4lSl04w/opKgpoOU8tNksozJZi5/Qkr55uzuW4GHs+/PSaH8SWYfu0nPR69bwid+t3fcY0vtRnQazZQkU2sLLZzsDZFIpXLJUGuqHLR6wnjHiC394OmThONJvvCqlcqAfoZRweU5Yqput4PZx0MHw2uqHDT2BgnEUgSiSZaWFnC0O8jJ3hANda6xL0ZGa+pwp5/FJQVTyiLWTNMRu8UTpsUTRqcRrKt2kErLSQW6g7FkdjV7+Hm/f9/FbKx1T6ttFxJZ3dYdQLuU8qZs+e5vyLjV7wTulFJO36L5PEIIgUmv5S0X1/Lrba20ekIsLrUhEDT3h6gptORM8SDz4vzwtYvnrsETQKfVcMOqsmHB5VA8RandSLHNlNOzylemuL3Jwz13buS6FRnjkjKHCSFge6OXZDrNpQsLafGE2dc2wL62AR7Y3sq979hCTaHl7Hw5xQWHJxTDYtARiCX5yXONNGVN+3zhOHWFFoLRBDaTjt5gjKb+ED99rpG7Lq+n2GbkysXFBGNJdjR7+errVvOGzZlyyFetreDKpcXDAsuDlNhNlNinr5fc4YtQZjepAa/igqcnEJ1wUHW8cth8JFJpatyWM2Y5AbgLjDCB4DLAvrYBVlbYc1Ib+QjHU6wot+ENJyasR6mCy4rzmaHvO380weu+/0LeubJOk/EXik/CILPZk6kW2DuO0edYBGOpYRV8QylzmHCY9RzvCY4y7XzZ8hJuWV85pXsqJsTtwFeGbhBCbALeK6W8K/v5WWAZUCCEaAPeKaX8OxkTTuVPMsvcsr6SHzx9khPjxJjKHGb2TsEsE8BtNXJyxPt5X9sAboue1ZWOMase7n2xmXA8xVdeu3pcKS3FxFG/yTkiOcVBotWgG5Z5DJkOZDXq2VLvZlmZbZhmVGACWlXJNJgmqMFcaDVQ4TDhsuhZVmbDH52ZeGPGBHCA/e1+VpTbMJ3BLGwkJTbjqID0X0Y4iyvG5cPA4SGfvwp8Q0q5CPAC75yTVp0D3LGlljZvmMWlNtp9EfqCMcLxJNubvLl+Xmg18N+3rmF5+fzOaJRS5n0Jd/tjGIf0yYMdftZUOYYtXr3tkrpcYBngFSvLuP+ui9jz+et48dMv40u3rOYtF9fl9jf1h3nDPS/OmJ6eQjGURCrNs8d6MWg1XL64iEqnmWuXl/La9ZW8Zl0lTf1h2rwRotlsoyNdAb771Ak6B6KkpWR5hY3DnX7eeVl9LrA8yGzrIrssBlThjULBpCraUlMw8zjY4afYZhz3uJESdOPhjyay5tpjc6gzQOUktFinOm9QKM41fvTMqbyB5bXVDqxGPQUmPXWFFlZV2vNW0uXjTCbU06HdF+VQZ4Bat4WigtPVeAadhi+8auWw6kDF9JBSPiWlvGnI56uklH8bccyOwcBy9vPlUspiKaVZSlmVDSwjpbxGSrlaSrlKSvlmKeX0dDoVedFqBB+/bsm4x+mmkUwxlj2FJ5xgf/sADXVu9GMYHj24s40P/2bPpN/xirFRweU54o6GGp76xFX8v5tWTOq8gWicUvvogXCXP8rWRg9HugJE4ilsJh0lNiOHO8+shTzI/nY/tXkyCPVaweY6FwuLrVj0GvpDcToGonjDCY50BTjSNfPP4kOdAZZXTDwIV+UaPTiPp9RDYqIIIarIOF3/OPtZANcAD2YP+QWZkiHFGBSYdGxv8tLhi3KqL8TyitOaUeurnfijCX61tWXeZx4JIfjhnRt5/ONXct2KUiAzQC6zm/DmWdTSaARb6t3csaWGT12/LO81LQYdpXYTdUVW3nJJLZctOi0L0jkQ5dH9aiFIMbPsbfXx0+dO8crVFWg0AiEE168qY1mZjYf3dXLZoiLqi6z4o0mKCoyUOUysr3Hy9kvqKCowotdqeN+Vi/jK69Zw++bqs95+s0GrZJ0UCpiUAexUg0fpMxjlNdS72Vjroql/YlnLg7R6ImysHT+o1B+auO6y8ndUXAgEogmiiRQLi62Y9VoGY04CCEaTDEQSeEJxPKE4zX1h7OaJFWHP9vD7RG8IbyjO+honACvK7ar6SKEgIxu3unK0lvJQptNVvOE4qyvHjhtta/JQW2jJGz8DeGR/J+/95c5csolieihZjDnCYdHjsOiHrXJOhBM9mQFuQ52bI11+/Hl0m0/2hnBbDSwrs03YZRsy2ZUjzcnWV7vY1jR5/ZvpsrvFN8x126AVLCqxUWDK/Mm29Ifo8me+28jsELtJx5u2KEfXSfBN4G5gcPm/EPBJKQf/uNqAvHVdykUX7nnmJK2e02YFWo3Ak50wrqt2sjtb5tPYF5rWy/NsIYRgYXEB3759PX/e086aKie1hRbe98ud1BVZSaTS7GrxYdBpSKUl25u8XLeidEJGZEadliuWFPHciT4go3n76rUVs/2VFBcYKyvsLC2zDQs2XbywEKNOg1Yj6A3E6A3EsOg1nOoLEYwlsRl1fOCaxbn3id2s51Vz9LcppVTBZYUChlXMjEWN20KZw8iJ7qklO5zsHfu8UCx5RnmLM3Gky49JrxlmBjqSxr4wbosezwQytA+0+/GE4rityqtAcf7yj4Pd/OjZRgBcFn02SJvpp0NL3wfnvyd6gpTajBTbMpqtHQMRzHoNxTYTHQMRKhxmgtEEO5sn5w80FVISDrYP8MlXLOVdly+Y9fspFOcCQgg+/vIlvO1n28c8RjONMe/gc2FRSQFmvSavvOqJnhA2k25Mn7EnjvTwjp9v50dv2YTVqMKj00FlLp+jbGvysCxPif2mWhcbapwEIolJGwbuavGxYsQ1E3OYAby9ycMVi4tYWmpDAoc6/Wxr9LCt0UNfMM6G7OpweshydIFRx73v3MLKijOvkCkyCCFuAnqklDuncr6U8h4p5SYp5abi4uIZbt25wTXLSvnckAqEVFqSlnDZokIsQ1yiS+2mcypgZDZoub2hhhUVdqxGHR9/+RK2NnrY1eKj1m0BKTnQPsDqSge3TSK78x2X1vO5m1awutJBQ717QkFphWIy6LSaUX9XJr0WTzjOkpIC/rKvg0giRSSRzgVq3n3FgnHL2M8W59JzQqGYTdxWA598xVLKHaO1zDfXuXBa9LR4wmxr9E4oQJsPfyRJRZ7rQ0Y2o6F+av4d/kiSNZXOcY9bWFIwoet1+aN85Ld75n0FlEIxVboGojy0tyP32RtOsLPFy/YmL55Qpn9vqnWxpd5NQ12mX3pCCboDMQ50+NnT5qMnEKPZE2FHc6aacEezF8ssB4vW1zhZWmZDKzKmnjevr5w1GQ6F4lzkyiXFuT6bD8n032sneoLsb/ezrsqZd38gmmR/u58tY7zTXzjZz0d/u2fa7bjQmbEnnxDCJITYJoTYK4Q4KIT49+z2eiHEViHECSHEb4UQasl9CMvL7Vy+uGjU9ksXFfKLdzScsYxgrFK+XS0+EmmZy5icDH3B2DD9ud2tPsrGKCOYbdIS9rT5ONodGGWSkExntGHXVDmIZXVyTHoNP3nrJtZVO+egtecslwKvFkI0kTHwuwb4FuAUQgyOxqqA9rlp3vynqMBAqzecy0reVOuiwmHiuRP97Gjy5CbF+WRnziVWVDhyg+VmT5h4ShJJpFlaZpuUBq1Oq+Edl9Xzlw9exkevHV+HS6GYKW5aU8GzJ/p4ZF8nK8rtFNuMtHjCGHQaXr6ybPwLKBSKs4rVqONfrl7EU5+8is/euBy76XSQSDI5TeaxqHKaCQ8phx0cA1e7zLitBg51TM0EDKDVe2ajQIC+YHzCVU3PHOvlW48fn3J7FIr5TJnDNO4cTko40D7A4U4/BcaJJSdM1ShskGq3mRtXl+fdV2ozsrvFx9GuAItLbbzvyoWT0lJXKC4EhBB86NrFuYWh9dVOlpfbqHabsZt1NPWFqM4jczoVEuP4L2xt9IwZYH7scDet4xj8Ks7MTC6rxYBrpJRrgXXA9UKIi1DGYGdkSamN/71tLe+7amFum1Yj+NA1i/nekydo7But81Zg0FLhNDFykafEZiQcn545Vk+2VHgoNe65CYrVFVrwR8b+PomUZF/bAAc6/Bh0Gn78ls1sWVB4Flt47iOl/HTW4KCOjOvuE1LKNwFPArdmD3sr8Oc5auK8x2zQ8vMXmlhQXMDKCju7Wry5xZB4SmLSa1lf7aS+yDrHLZ0eeq2G12+sGrX9z3va+dgDe/j6P47ij05uoq8yOxRni1ZPiEA0gV6rIRRP0RuIUVeUebeV2o3DglYKhWJ+YdRpuevyBTz9yat5+6V16DSC3S0+atzTn4yWO02kUpKVFXbcVgPxZIpNtS6qXGY8oTjB2NR1GLv90XGPaewLTSop4jtPHOfJoz1TbpNCMV/o8EX40+42AtEEzx7v5b8ePcxtm6vZdAa98p0tXiKJFBI54b6Zkky5AsFi0NLqifCmi2p41+X1GLSanPlYjdtCddbIr9hm5P67tvDxly+d0n0UivOdEpuRrY0etjV52N3q43BngFZPBH8kSU8gzkA0waIJVvKciYMdfqrGWeDZ2uhhc93o54yU8MCO1mm34UJmxmb2MsOgcJk++0+ijMHGpcRm4hMvX5rLlkilJY19IX77nov56ds289+vW4MQ8PqNVbz46Wv46q1rcqU+m+tcrK1ysKbSgTcc59AEDfzORLMnMkz0PDFHJXgTcfCGjOngD968gcvyZIArpsyngI8JIU6Q0WD+yRy3Z97y2MFu1lY5OdET5GCHn7QEX+R0kLWxL8TuVh/l9vxlt+cSn7lx+aiypkRK8odd7Xz7iRO87H+f5v6tzapsVzHvsJsN2Ex63n3FAlwWPR+4ZhHbG71cuqiQjTUuJUWhUJwDuKwGPv+qlTz2sSu5dnkJZY7pB5e3N3mJJJIUGHV4QnEWl9joD8V58dT0/UYm+irUaSY+HZMSPvKbPSq7SnHO8/2nTuKLJPncnw8SS6Qx67X84oUmPjJOVVtaMulFn22Nnpyc4lAqHKa82u5FBQZev7GKl/7tZTz3qas51OHn325YzqMfvozvvHE999y5kQfeczEWo47vvWkjz959NYUFxnkjr6VQzDfGM+j1R5K0ecITjv+ciQrn+HPuHU1e1lSNVgh4YEcryTmUhT3XmdFUHSGEFtgJLAK+C5xkAsZgyhQsk638769eiT+SYHO9O1dK31DvZnOdi4sXFlKdzSC+ZKEWvVaQSEl2NXtZXGrjSNf0g8pDqXVb6A/GSc5hkGikFEY+dBrBd964gWuWlZ6FFp3fSCmfAp7K/nwKaJjL9pwrtPki7Gn1sbrSTiyZJpGSHOse3R/X1ozvHD/fsRh0fO5VK7jpO8+N2remyoFJr+W/HjlMiyfMp1+5fA5aqFDkx2HOSLf88qUWnBYDKyvsCAGfuWEFDsvEZV3OFul0Gs0kAk4KxYVEfZGVH965ie1NHv7jL4fY3z516QqAZDqTyVTjMqPTirxVg7NJODG5qsOBSIL337+L3733YuVboDhn+c+bVxGKJbl5XQWRRIprV5Tyrnt38Mi+zlm534H2AdZVO9nT6mNxSQGJVJovv3YNb/zRS6OOrXJZ2N8+wM4mL1cvK+Guyxfwl70dLC2zUVdkxajTUOYwce871FRJoZgIE6lWjSbTLCgw0huITetezRNYfJXAkU4/i0sKON4TxGHW47YaKDBqefZ4L1er2NKUmNGZi5QyJaVcR0ajtQFYNsHzLnhTMIAbVpdze0MNC4sLsBhOx/2FELnAMmQyN375zi0IkSn16fJHWVPlYFOdi7oZ0nXd1uSl2GbgskWFY2o7zzbN/eMP7mvcFi5eqKQwFHNDIJrIZenub/dj1Glp7AuxvCyjpX7jmnJ0GkFdoYXigrnRLp9pVpTbhxkVApQ7jJj1WrY1egjFU8zRI0OhGJf3XbWQhz94Gf3BOF957RpWVNjnpT6iCiwrFOOzuc7Nn//lUr75hnVjmvJNhhZvhOPdwVzZ+9niRE8Qh3ly+T772wf4j4cPzVKLFIrZJ5pIYTXqsGV9O363o5UFRVZ02pnrfwathkUlBRh1Gr77po3ceVEtb7molrdcXMuTn7iKxaUFucXnUrsRt9XAgmIre1p93HlxLVcvKwHgvheb+Lc/7KfHH2N5uZ0FxdMv31coLiT0E+zXZsP0F0y7/bEJ3S+ekjT1h9BrBQORBI19Ifa3+7nvpZZpt+FCZVZEBqWUPiHEk8DFZI3BstnLyhhshtiyoJCv3bqWf/vjfnzhBL5wJmujzG7EoNMQT04/nb9zIEYsISedUTFTVLsseMNnzkY51RfibT/bxn3v3ELBLLsBKxQj2XrKg1mvYUW5nUOdftq9YbQawQ2ry/jANYsBONxWH1tJAAEAAElEQVTpxxOKnzf6whqNYH2Nk2g8DSJTPdDqCdM1cFpbUslizD5CCBPwDGAk8y5/UEr5eSFEPRlzzkIylUR3Sinjc9fSuUdKiRCCWDKFUafFatRx7YpSYskUvnAcp0X5DCsU5yoajeDm9ZVcv6qMnzzXyPefOkkwNvVxa38ozuY6F9ubvDPSPiEYd8E1mkiztsrJ1saJSXEUGLUUGHXsmKE2KhRnEykl//OPo3QORHnflQtZVFKAhoyJ/H++eiX/ONQNwC3rK3n8cDf+6NT6c22hhXA8xU/euin7OeN9cqTLzyP7O6kttLK9ycOuz17LPc82sqHGSV2RlYMdA3zo13s41OHnwZ2t/GZbK1qNIBBL0jEQmZHfgUJxoWEYRxZjkJla3K10mGmaQAZzvkr5p4720O6LzMvkk/nOjEU7hBDFQghn9mczcB1wGGUMNmvcurGKe+7ciGmIAV+XP8bKcjuF1pmZLHvCcdZUObHNgdlRaoLpj7tbfNz1i+1E4lM3XVEopsK1K0opspn41bu2cMWSIsKJFGa9lvVDJDCWl9u5dNH5pQf+9kvqOdg5wM5mL1sbPXQMRGn2hLlkYSEOs57nT/SRVgHm2UaZ6E6QQT1lo254NsSTR3qIJpSumkJxPmDSa/mXqxfx1Cev4s0X1UxL+3R7k/eMpmITZXWlfcKVPGc6bFWlnZUVdmxGHUJk9Ga7/DFu2zTaZFehmO8IIfjEy5eyotzOs8f7EELQG4xzy/pKnjvZR18whs2o47oVpVy1tAT3JOe0S0ttvOPSer57xwakhP/+21G2N3l5//076fBFePxwD+k0eEJxwvEUrd4I77tqIWkJ8WSaNVVO/vWVy7hqaTGBaJL6IivHezK2UmquqVBMjfE0lweZqYp55zRiYWkJD2xXxn5TYSYjhuXAL7K6yxrgASnlw0KIQ8BvhBBfBHajjMFmhHgyjVYjuGppCUtLbextO53hu7vVh8uix2nR4wsnznCVibEtm0lR6TTR5Y+dtazEgcjE2/7SKQ+f+/MBvvb6tbPYIoViNK9eWwHAl25ejUmvJZpIDZOxOVeJxFNjliZdu6KUV6+t4A+72kimMwH0T75iCVcsLiYtM5laGmVqMqtIKSUwlonuHdntvwC+AHz/bLdvvuILx/nFC81cuqgQQ1Yzcb6STkvVjxSKSVJUYOSLN6/mrRfX8eW/HuGJIz1Tus5MTHAns3g10kBIrxGsrXbSE4hxoN0/6vjXrq/knZfVT7uNCsXZ5O8Hu2jsC3HdilLWVTv52fONvHlLDasqHfjCcZ4/0c/bL6nDbNBx34vN9IdieEITK74qs5tyUpEfe/kSCow6vvPG9bzxRy/xyP5OigoMlNlN3LSmnN/tbOMLfzmIL5zg7ZfWAbCpzoVWCDQaQandRJndxHUrynjqaA9/PdDFN9+wjosWKClGhWIqTLSC1xuemWLLfEadk+GBHa186GWLlUnnJJmx4LKUch+wPs92ZQw2C0gkybREoKGowEil00y773SpjjecYGOti53NM1cy1+6LsqHGya4W34xd80yU2U20eSdefvTwvk4+9LLF50VgT3HuMd/+7oKx5LSkYmSePKpIPMVf9nbQG4zx6P4u1tW4ONIZ4A/vu2RGNLIUk2OqJroXMk6Lgdesq6DEbhzmbTAfUYFlhWLqLC618dO3beb5E3188ZHDHO4cHaA9E7tbfDTUuTnYMUBoitmK+d6jYzGYDOIw61hWZudYd4Ad2TH84pICUmlJJJHi5StKWVpm5/bN1bmqDIVivtA1EKXEZhzz/WUz6YjEU5j0WlZWOFhR4aAnGMNh1nPjt5/j869aQSSRYkFxAQfaBwhMQOLGYtCyocbFR65dTDie4gsPHcyV1gdjSdxWA1+8eRUmvYbtTR5eu6GKzfVuTvYEeeFkP2X2zCLz0MzK61acNvO6YnExH87OL+fzgrRCMZ+ZqNzFqd4QJr1m2pWF+ZIhNQIWl9goKjCQSEuklCRT6Yw0xrDmZT48d7yPK5deuH5wU+H8EAG9ADHqtBh1WjQawU/etpk3X1Q76pidzV6Wltpm9L7ecAJ7HomM2RjftkxAJ2cokUSK//fnAzPfEIXiHGQigeXBF28gmpnUNvadNtHMF3j7/a427v79Pr79+HGCsSQ6jSAYS05qAq2YOaZqogsghHi3EGKHEGJHb2/vbDVxXpBOS2LJFAPZ4E1dkXXeB5YVCsXMcOmiIh7+4GX89+vWUGKbuLGuBLY1eYgn02ypd2PWT34BddCobCKc6guxqdZFNJFma6MH75DKw95gjE/fsIw1VQ5u3VjNHVtq1OKTYt6RTKX52fONZ5wTbqhxUekyYzFoMRsyUjZVLgsdvijd/iit3gh/P9hNJJHiA9csoqjgzKXtN6+rYNtnruVHb9nE9546yaP7OznVF+LGbz9LfzCGUaeh2mXmhtXllNnN/OjZRuqKrFy+uJi3XVrPPW/ZhC4bVB6IJHj+RB9yRNWCRiN41xUL2DgDUjkKxYXMREz20hLqi6xTvocgYzRv0GnYXOdiS72bjbUulpXZMOu1HO0O8FKjhw5fhO1NXna3DnCgw8+B9qH/BjjQPsB9LzVPuR0XKmp2dZ4gkRTbjPQGYsO2x5IpNCLTUWeCxr4QC4utOf2rgUiCuiIrMg172nwzc5MsVqMORnyf8XjqaC87m71qAKBQTIDBuengBLjCYWJHk4dNde68x2+sdVHpNDEQSbCu2k06DZvrXPQEotQVKufsuWIqJrpSynuAewA2bdp0Xq8OaDQCmQKHZeKBHoViJhBCfA14FRAnU1nwdimlL89xTUAASAFJKeWms9jM8x6tRnDb5mpuXFPOPc+c4p5nThFJTCwbOZGWbG30UOk0U+E0Tdjor8ZtZk+rb1Lt3DFGtaEvnECrEXzx5tXjBtsUirlCp9Xw6RuWn/EYk17LbZuque/FJoKxFO+7aiEAxTYjb7+0jqeO9rCmysHnHzo4ypx+TZWDfUNkIH/2ts1cvayEdl+EX77UjFmv5YEdrXz8uiXsbPHy0N4O3n5pfU7KwqDTnLH/2E06FhYXqIqAeUi2Um8H0C6lvEkI8SwwmEFXAmyTUt6c57y/ARcBz0kpbxqyXZlfn2V+ta0lr3lePuyTWJgdSkO9m90tXjoHYnQOjB1DSqUlhVbDuBXyzxzrJZlK5xagFOOjflPnCe+/ahGfu2nFqO1N/eEZMSUZitOip6k/TLs3QjyZZneLj2hyZg0O3FY9U03KeM99OyY9oFcoLkRGDqCNeu2okr9oIkU0Own/6t+O0O6LEoyl2NrowR9N8MaGGmrdU19hVkwNZaI7cVJpiWkKWYcKxQzwGLBKSrkGOAZ8+gzHXi2lXKcCy7OH1ajjo9ct4alPXsVtm6omVXXXG4hOqky3sMA4YTO/M2Ez6vjbRy7HH0lSbDOqwJfivODV6yqodJmBTMbzH3a10eIJ86YtNaytcvLrd21hebk9d7zdpBs2z91Q4+SqbLn6D58+idWg5XhPgLSE50/2cfcrlvH2SzOa5INar3/c3cbd149d4CWEULIX85cPkxnjAiClvDz7vlwHvAj8YYzzvgbcmWe7Mr8+i5zoCfCfDx+a8PFTNc4UMOEA9t62gXEr/FdW2lVgeZKo39Z5xFglBB2+6IzeZ1dWhy6RlkN06GYm8a3aZaahzkUoluRkb2j8E/LQF4xzx49e4p5nTnK40z+qvEmhOB8JRBOksyUKPYEoB9oHeOroxI2MpJT0BWM5OY1/Hurmu0+e4GX/+zT3b23mFd94hqeOnpZPeGNDDY9+6HJeu6FKTXbnhnLgSSHEPmA78JiU8mHgU8DHhBAnyGRkXPAmusqMQzFXSCn/MUQD/SUy1QSKOabUbuK/b13LIx+8nMsWFU3oHKtRR5d//PF0cYGRzXUuds+QP0kincZu0nPzeiWfrzh/cJgNvHptBS39YV7/wxf54iOH+fvBbp4+1se7rljA1/5+dJhOekO9G6Mus0hcYNTx/TdvRAiBlJJyh5lTvSH+65bVXLygkM/euIJim5HHD3cP0119z5ULczJwinMHIUQVcCPw4zz77GSMrP+U71wp5eNkqoKGniOy5zyY3fQL4OYZa7BiGLFkig/9es+kFmcPdQ7QUOfGYZ5cBvNkIz7jyTpOdHygOI2SxTiPWFXp4MbV5Tyyv3PY9jZfhKVlNo52BcY4c3JImdGhq3KZc+UEyTy6G2UOE/3B2IRXkADiqTRtvgix5PQCwuF4iv969AhwhEKrgfdeuZB3XbFgWtdUKOYrhzr8/O8/jnLl0mJeu76Kf/39fp440oPFoOXWjVXcddkCagozhoPJVBohBFpNZlA+EEmwp9XHV/56hCNdAfRaQY3bklvcecXKUlaW2znaffr5saLczpduXqU0H+cQZaKrUJxzvAP47Rj7JPAPIYQEfpiVrVHMMisq7Nz3zgaeOtbLfz1ymOM9wTGP9YYT1LotWA3aMxr8RRJJmvon5xkyEoNOQ7nDRCot+dVdF1HhNE/regrFfERKyTt/sT3X765dXspbLs54CL3j0npeOuVBqxHcsKqMj718Mfc808jHr1vCa9ZVUpo14ctkGxuxGrWsqnTw83dsxqjTIqWkwxchmkhlZBbJlNpPtdxeMad8E7ib0zIYQ7kZeFxKORnH1kImaH4thHg38G6AmpqaSdxCMcj//uMYhyZpqJtMZ2JNVoOWLfVu9rcPEJ5ANvNkEwqPdQdHye0M5VIVXJ40Krh8nvHVW9fw6IHOUaV4FsPMlgTrtYL+4GktmxM9ITbWujjS6SecSLGxxsWeVi8bat1sa/RM+LqReCq3Mj1T9IfifOnRwzx7oo/rlpdw58V1M3p9heJs4w3FcVkNdPujxJNpbvj2swA8fqSH//n7UYxZCYBwPMW9Lzbz+51tvGJlGQB/O9iFRgg21bo40OGnL9uPLXoNa6scdPiiucDy5joX37p9Pd5wnPU1TkKxJImU5C0X16rAskKhUABCiH8CZXl2fUZK+efsMZ8BksD9Y1zmMilluxCiBHhMCHFESvlMnnupie4MI4Tg6qUlXL6oiN/uaOUbjx2jL5hferPZE2ZVhZ3DXYG8TvQAwViKukLrKA+UiaDVCN575QLed9UiCow6UmmpKi8U5y1CCL73pg08uLONWzZUsqzstAxGMJbEoNNw3fJSnjvRR4nNyOY6N1qNwGbSIaXkN9tbWVxSwC3rRxeECCHUfO88QAhxE9AjpdwphLgqzyFvJE9G80xxIfmTzAbPHe/jnmdOTfn8UDwjw+gw69hS7yaRShOIJekPxvGERr+np1KsbtLlF3Iw67VsqFEeXpNFBZfPMwqMOt6wqZrfbG8dtn13i491Vc4ZM91zWQyEYslh23Y2e9FrBAVGXc6UJDpBw5RBlpXbJxWMngzPHOvlmqw+l0JxLuPKGmqW2k38bsfwvr6wuCAXMB4kFE/xh93Dfd12tXhZVmZjQZGVlMxkM+9rG8Co02A36dhU5+arr1uDSa+l3GHmj++/dHa/lEIxS/ijCVIpmes3CsVMIqW89kz7hRBvA24CXibHSKuRUrZn/9sjhPgjmeqDUcFlNdGdPXRaDW/aUsur11bw/adO8pPnGoklR5fxHujws6XezY4mDxtqXXT4IrSPkJ870OFnc51rwuZ/g3zi5UtzBmegJH0U5y+HOvw09oW4cU15XhPAW9ZXcqo3xPWryvi3G5fz42dPsb7aSas3gkmvRQjBTWvKZzwhSTHvuBR4tRDiBsAE2IUQv5RSvlkIUUTmXXnLJK/ZzwTNrxVTp9MX4TN/2j8j1xqIJNk6Ij6U7x07lXdmaoyI9JYF7pxeu2LiqN/Yechnb1rBp65fxqKSAlaU26l2Z8rp9rT5WFVhH+fsidETiLGywjFqeyItCURPB533tQ2wptIxZXO+mWY8V1CF4lyj2GYc9jI16DTUFlkoH2FKsqrSzsZaF1oBFU4TZQ4Tu1t9bGvysLPZh0wDMtN//dEkN6wup9hmPMvfRqGYOVJpyXeeOM5vt7ViN+unlEmoUEwHIcT1ZMp5Xy2lzKuVIISwCiFsgz8DLwcOnL1WKoZiM+m5+/plPPGJq7hlDJ3jaDyJy2pge5OXbn+MtVWjx8MH2gcmbQ523YrSKbVZoTjXWFFh58Y15WPuF0Lwhs3V2Ew6Kp1mPv+qldQXF3DFkmKM2YCPzaRXwZ/zHCnlp6WUVVLKOuB24Akp5Zuzu28FHpZSTspcKrvIq8yvZ5FH93dy/beeJZFMs6ysYFbusavZS8WId+xYgeIzMZZ8q9JbnhrqiXweUmDU8b6rFvLPj13Jox++nGc+eTWfvXE5lU4zgWgC6zQlMjbVuih3GNnRPLEM433tA6ytdk7rnjPFmfT0FIpzkauWlvDM3Vdz7fJSXru+EptJx3PH+xEM9lUTNqMOg1ZDhy/Cpjo3dpOeEz3B3Au1qMBAU3+ImsKMKajVoOXKJSrLX3Fuo9UILl9UxF2X16PVCLVYopgL/o+MTuRjQog9QogfAAghKoQQj2aPKQWeE0LsBbYBj0gp/zY3zVUMUuk08403rOOhD1xKQ7172D6DXpuTzkimJd2BGJVOE0PjXJFEGuckzYiKClR1xXxFCGESQmwTQuwVQhwUQvz7iP3fFkKoScYMEYwl+fW2Fva3+fjrEC+hp4728MHf7J7DlinmEbcDvx66QQixSQjx4yGfnwV+B7xMCNEmhHhFdpcyv54FAtEEH39gL++/fxcDkQQdA1GOdgdpqHdj0M5spmFKQumI4HJkArrMgxTbjGysdY0ZDFV6y1NDyWJcAAghuOvyBdx1+QK2NXr4978cpHMgmlerZih6bUbXKpUGu1lHXzBOrdvC7hYvk/DoA0A3wdTlSDw5/kHToHsCTt8KxblGpdPMj9+6Cchka2491c+zJ/r4/lMnc8foNBqMOg1bGz2srXIwKBfpMOsptBpp7g/hDcfRCPjANYtVIE5xzjGoOCCE4ERPkFgyxbrzWC8tnU6j0agcgfmMlHLRGNs7gBuyP58C1p7NdikmzpoqJ79990X841A3n/3TAXoDMboGho8luwai6LWCtMws6goB/kgCu0lHsc044aqJQ51+LlmoJrTzlBhwjZQyKITQk1kQ+quU8iUhxCbg/H3Z5EFKiZTMmv9GPJlmy4JCLl9UxFPHenLbr1paopIfLlCklE8BTw35fFWeY3YAdw35fPkY11Lm1zPM9iYPH/3tnlFV4lLCtkYPlU4zlS4ziWSa/lCMdm9k0vGkkUgpWVhsxWzQYtBqcJj1WOvcJNJpQrEkvnCCvmCMtMzMdxcUWdFpRU7OqjcQY3Pd6Ed3UYGBpaX5/CMV46GCyxcYDfVu1lY50GtEJlDc6ht1jEZAbaGVxr4QnlACgIFI5r9HugJTum9jX2jcYww6DUeneP2JUuO2zOr1FYq5RqsRXLKoiEsWFXHpwiK+9vcj7G8fYFuTB62A9TVOEsk0W+rdBKIJTHptxlE7maahzk1zf4jeQIxANIFNuWorziGEOD3JrSu0jFnqdr6QmdzLYd9boVDMPEIIXrGyjB1NHn61tYWePMHiwefNoOfIZKl2m1VgeR6TLaUfzEzWZ/9JIYQW+BpwB5PXfj1nCcdTbG3s55plsyPl4rYackHkkfcY653nC8fRaTUUGFV4Q6E4W8STab71+DG+/9RJxvC5BaDdF6HddzrwrNMIVlfY2N/un9J911c72dc+MMxct8xuIhBNEBqSwSyAdVUO9rQN5I17He8JohEMa/slC4uUcf0UUSkvFyCff9VKXrGqnBM9AdbXOGmod1NqN+K0ZAJJC4sLJhQMHoleK1hZYceSR3bDFz5zljTAomIr8VkOBvjCCR7a28F3Hj/Ow/s6ZvVeCsVcc9niIv78gct46hNX01DnJg30+GMc6PCztdHDQCTByd4QXf4YQkAilaI7EOOnzzfyl72d415foZiPNPaF0GoE5mlKQM13tFqtCiwrFGeRxaU2QvFUXqO/6XJRfeGMX1MxswghtEKIPUAP8JiUcivwAeAhKeUFNWiyGnWzFlieKnaTPpcMpVAoZp+eQJTX/+AFvvvkmQPL+Uim5ZQNOddUOUYFlgG6/FGWlw/3F5NAyxk8t3zhxKhzLlusFnqnilrauwAx6rW876qF3LSmnPu3tvDEkW66/ZksDJtJR1P/5ALLNqOOOy6q4RMvX4peq6G5P4TdpOfBnW186dHDACTTmazhFk9eP5vsMbOfZbatycO2poxW9K0bq7hxdbmanCvOe2oKLTzw3otp6Q+zu9WL02zg8SPd/GprM5cuLCKUSBGNpxjaA7//9AlevrKUogIlj6GY/8STaQw6DdFEivoi61w3Z8bJl6GcTqeJxNNYTWoop1DMNvFkmh1NE/MamSzvv2ohd12+YFaurZg5pJQpYJ0Qwgn8UQhxBfB64KrxzhVCvBt4N0BNTc0stvLCRaMRVDrNc90MheKCoLk/xJ0/2XbG2M54TFXZrT8Yx/L/2bvv8EauqvHj36Mu9+51XXt7tm+2pVdSSSGQFwgt1NBC7/D+6PWld0hCSIAQSIUQEtJJz/bei71re92rbMuyyv39MWOvbEuybMv9fp7Hz9ozo9GVVqOZOffecxxWPD1D06l2RUix2tLVi9tuxeuPnJO5uzdIqtOGxxfAbhVdzG8M9MjlWawkK4lPX7aIJz55Ad96w3IAPD2BuKcSF2e6efHzF/OBC+ZxuM7DZ+/fxZF6D3Ozk8lMdvCBC+ZxywWnL5arW7tZW5pJWXYSG8qzmJc7MADQ6PExkTMQ8tOcOrCszSql2Ulcv7qICxfn8s3rl3PP+8/ipWPNbK1sZe+pDnyBEDaLYLcK7z6nnFQdtNKmCZtFCIUUbd7hZ8lMR5HOVRaLRQeWNW2CvHq8mfu2Vid8v4XpLj512SKyknUxv+lCKdUGPAdcDCwAjopIJZBkFgiL9JjblFLrlFLrcnN1zmBN06av/ac6eNNvXx1TYNkwujhMTZuX4kx3xJpeyVHS4sxJjz5YqqKpi/x0F3PSXNz93g0U6k6qUdPB5VkuEAqx/WQrN60r4dtvWM7CvBQ2lGVxzvxsFuWnDNneYbPw9o2lfPmqJXzkovn8+bUT/PdQA1nJTn7wppWUZg/MafyRi+b3B4xDCradbKWyuZvNFS14e4Okh1XSbu32sy5CUvXx8pZ1euSANv28cLiR442JKUi+cV42H7loPm67MS2psyfQH4B+33nlo56upGkToW86XDCk2FzRzI+ePERz58wMLkfi6fH3FzHUNG18nTUvi8c/cT4ue+JunXJSnLz9rLnYrfp2bKoTkVxzxDIi4gYuA7YppeYopcqUUmVAd7QinpqmaTPB5ooW3nLbqzR1xleoNpZdVW0syBvdbMMDtR5Wl2Rgt8qAn2hn03R37A5cb2+QP79vg659MEZ6yMssl+SwsXZuFgBvPLOId5w1l4qmLgrSXbjsVu56uYLH99axqaKFpQVp/OQtqyjNSuK7jx1gXk4Kn3rdIjp9AXJTI/cGZSQ5WJiXyqH6oYX6clIcQ5K4j1dmjNUlGSzOT+X8RTmku+109wYpyHCNz5Np2jhaX5aFLxB5Ws9ofObyxXzskoU8susUwVCIRo+PplkUoNOmn0aPj9xUJ1az57K508e+Wg8fvGA+6UmzpwilLripaRPHabNyRkEaH7tkIT968hCJ6NexW4VLz8gb+460iVAA3G0W8LMA9ymlHp3kNmmapk2Yp/fX89G/bk9Y3QFfIERLVy/5qU7qIxTKHU6kArqbKyMX1XXYonfiripO5/ab15GXqmNDY6WDy1q/JIfxcUh2WPEHQ7jsVt59bjlv2ziXBk8Phenu/sqZ337Div7HjbZoUt/zhbMkOE2F1SJ89KL5fPryxQndr6ZNFrfDmvBCZQ6bhRvXFid0n5o2XjLDAsi+QJCnDtRzxbL8WRVY1jRtcnz04gWsLsng0/ft7K9XMlpdvsCMzBE/EymldgNrhtlm6JRPTdO0GeJnzxxOeEHbli4/pVlJJDusdPUmbvDUYLXtkYv6Xb40n5+/dc2MLwI+UfQ8LG2IvDRX/4gopRRNnT6KM5P6A8sjdd3qwojLFcbo5azk0wEBfzAxX1ipLhs3nz2Xpz99IbdesjAh+9Q0TdMSKxQa+J0fT5oHW9gUcqfNypvXlVCcmRTjEbGeX+FP4EwATdNmvnMX5PD4Jy7gdWfkj3ofbruV168s1OmnNE3TtGlhvApmnmzpZllR+rjsu09Vi5eizIHtf++55fz2HWt1YDmBdHBZi0lExpzU/PyFkXPXbK5ooamzl5YuPwvzUliQl0KMGQsjcuPaYr5x/XLKc5JjToPQNE2bjkSkRESeE5H9IrJPRD5hLv+6iNSIyE7z5+rJbms0gUBwSHB5NEVWx5Kv1BcIDQhWa5qmxSMr2cHt71rLt65fhnOE15lpLhtnzcviS1cvGafWadrMEgopunwBXWdA0yZRUcboBnLEI1H1hGIpNmNaFoGvX7uUr167tD/FnpYYOi2GNixvb7C/RycYUiM+COflprAoP4XD9dG/NI40GOvKsxPzpTUvV89M0zRtRgsAn1FKbReRVGCbiDxlrvupUupHk9i2uNimwIi96TZaIRDUwXBNmypEhHeeXcbGedl87K87ItYXiaQ8J5lbL1lIms6brmlDKKV45kADJ1q62VnVxs6qVuo7fPQGQlyxLJ9bL17IiuLxHeWoadpQg0f+JlJTZ++w8aKxau3uxW238oub1nDZ0tHPPNKi08FlbVjhN9/+YAirZWQ34ylOG5963SLueqWS2vYe2rp76egJRNy21etnyZwUDtaN/otlbnYS5y/QlT41TZu5lFK1QK35u0dEDgBFk9sqbbzpwLKmTT2L8lP5563n8v3HD3LXK5XDbt/c1cvyorTxb5imTSPPHKjnvq1VbKlspaUrcmHpJ/bVc6DWwyO3nktGkmOCW6hps9ub1xUzPzeZPdXt7KkxfmrbexK2//E+plu7evnbLWexqiRjXJ9nNtPBZW1EXPbRjfK6akUBV60oAGDHyVZ6/CHec9dmXHYr83KSaff6qW710tbtx2YRCtKd1LaPrlDKyuIMynSBFE3TZgkRKcMoNLQJOBe4VUTeBWzFGN0cuXSypmmalhAuu5WvX7eM8xfm8LkHdkcNjoGRuk3nWtY0g1KKnz51mF88ezSu7QvSXaQ4dQhD0yZaqsvORYvzuGhxXv+yRo+PvTXt7K5uZ09NG3tq2kdd7LbD609UU4dYmJfCH9+zftQ1WrT4JOSbWURKgD8B+Rh12m5TSv1cRL4OfABoNDf9slLqsUQ8pzZ9rSnNBGDnVy/HZpEBI7H+s7eOj9+7gwsX5bCiSNh2opXmCBfo68sy2VIZOV6SqNQamjbd9PiDo+4A0qYnEUkBHgQ+qZTqEJHfAt/COBd/C/gx8N4Ij7sFuAWgtLR04hocp44eP3ur2zl7fvao8jDPVF2+AMn6plrTpqxLz8jnP584n8/cv4sXjzQNWZ/itHH50jmT0DJNm5q++OAe/r61Kq5t15dlcs/7N+pZPLOMiFgxBkzUKKWuEZEXgVRzdR6wWSn1hgiPuxn4X/PPbyul7jaX/xcoALzmusuVUg3j9wpmrtxUJxcvyePiJacDzk2dPmpavdS2e6lp66G2zUttew+n2r3UtvXQ4OkhFCF9eoNndEHp4ZwzP5vfvmMt6W6dimq8JeoOZdrnftQmXqQg2JXL53DwW1diMfM69/iDdPkC7Klpx2W30u714wuEuOyMfG7963ZePtZEj39gQaicVOeEtF/TphodWJ5dRMSOEVi+Ryn1EIBSqj5s/e3Ao5Eeq5S6DbgNYN26dRNaIUcpNSRg3OMPAqc/w2kuO+fo9EZD6MCypk19eWku7n7PBu546Tg/fOIQ/uDpr9hbL1nA0kKdEkPTwKgj8MiuUzG3yU52sDA/hZs2lLKhPEsHlmenTwAHgDQApdT5fStE5EHgn4MfICJZwNeAdRgDLraJyCNhs/nerpTaOt4Nn41yUpzkpDijpp/wB0M0eHzUtnmpMQPPtW1eTrUbgefqFm/EwYXxSnPZWF2ayZqSDFaXZnDu/BwcIyy8q41OQu5SdO5HLZEsYQUDXXYrLrt1wPSLPn9493oCwRAnW7r5165a/vRqJWfNz+amDVNvFJ6mjafWrl4yk3XuudlEjOjsH4ADSqmfhC0vMM/JADcAeyejfbF4/UGSHMblx7YTLYDQ0ePn4gjf89rsEAyGsM7AgEG8M/hE5Erg54AVuEMp9f0Ja6Q2LiwW4ZYL5nP2vBw+/rcdbCzPIjvFwfvPK5/spmnalGGzWvjL+zfwuQd2s7o4g5XF6fQGQ7R0+XHbrZxRkMplS/P1DKZZTESKgdcD3wE+PWhdGnAJ8J4ID70CeEop1WJu+xRwJXDvuDZYG5bdaqEow01Rhpt1Ubbp8Qepa+/hlBl07gs+15qjn0+1e/H0BLBahCVzUllTmsHqkkzWlGZQnp08IJ6kTZyED4EZTe7HqT49V5u6bFYL83JT+MTrFnLrJQsIKYV9Bt6gjhcRcQEvAE6M74MHlFJfE5G7gAuBdnPTdyuldk5KI7VhhRfd1GaNc4F3AntEZKe57MvATSKyGmOURiXwwcloXCx9gWWAtXOzJrEl00+kUd8zwUwMLIeJOYPPnO77a+AyoBrYYo6u2j9RDdTGz4ridJ745AXYrTIjj11NG6u1c7P498fOx2mz6ICQFsnPgM9zOg1GuDcAzyilOiKsKwLC861UM3Dw4x9FJIgxA/DbSqkJncWnxeayWynLSY5ZR8vT48dqkQH3FdrkSuj/xGhzP07m9Fxt5rBaBCv6omSEfMAlSqlOc4r9SyLyuLnuc0qpByaxbVqcdDqM2Ucp9RJE/MLTdQ1mMB2cmpE2AEeVUscBRORvwPWADi7PEHo6rqbFpgdJaJGIyDVAg1Jqm4hcFGGTm4A7RrHrtyulasx0rg9iDNb4U4Tn1wMgp7BUl86hPNUk7GonWu5HpVRQKRUCbse4gNY0bYpQhk7zT7v5ozt4NE3TNC0xbhWR3SJyp4hkRlg/3OgqTdM0TZuNzgWuE5FK4G/AJSLyFwARycGILf07ymNrgJKwv4vNZSil+v71AH8lSoxKKXWbUmqdUmpdbm7u2F+Nps1wCQkux8r9GLbZlMz9qGmznYhYzWn1DRi5qTaZq75j3hD/VER0lURN0zRNG0REnhaRvRF+rgd+C8wHVmPUJvnxGJ/rFhHZKiJbGxsbh3+Apmmapk1TSqkvKaWKlVJlwFuBZ5VS7zBX3wg8qpTqifLwJ4DLRSTT7Ni9HHhCRGxmYLpvcOQ16BiVpiVEotJiTNvcj5o22ymlgsBqEckAHhaR5cCXgDrAgZGy5gvANwc/Vk8X0jRN02YzpdTr4tlORG4HHo2wKuroqgjPpdPIaZqmaZoRbB5Q/FZE1gEfUkq9XynVIiLfAraYq79pLkvGCDLbMYroPo0xw17TtDGSqZa7XEQagRNxbp4DNI1jc6Yq/bpnprlKqUmdcyMiXwW6w4sPmTmuPquUumaYx47k2J0IU/nzMpXbBlO7fVOxbZN+7I5FAo7dqfh/Eo1u6/iYjm0d9+NWRAqUUrXm758CNiql3jpoGxtwGLgUI6i8BXibUmrfMPsej3PudPp/HEy3ffJMdPtn+zl3LKbKZ023Y6DZ0A593I7NVPmMxGs6tXc6tRWm8Dl3ypVWHMmXjohsVUqtG8/2TEX6dWuJIiK5gF8p1SYiboxq9T/ouyE2U968gTimC021C4ap/HmZym2Dqd2+qdy26Wqsx+50+j/RbR0fuq1R/V+kGXwiUgjcoZS6WikVEJFbMabwWoE7hwssw/icc6fT/+Nguu2TZ7q3f6JN5vXyVPm/0u3Q7ZhuJvs+d7r930yn9k6ntsLUbu+UCy5rmjahCoC7RcSKkYP9PqXUoyLyrBl4FmAn8KFJbKOmaZqmTTtKqXdGWX4KuDrs78eAxyaqXZqmaZqmaZqWSDq4rGmzmFJqN7AmwvJLJqE5mqZpmqZpmqZpmqZp2jRimewGjNFtk92ASaJft6YNbyp/XqZy22Bqt28qt222mk7/J7qt40O3dWaYzu+Nbvvkme7tn02myv+VbsdAuh3acKbb/810au90aitM4fZOuYJ+mqZpmqZpmqZpmqZpmqZp2tQ33Ucua5qmaZqmaZqmaZqmaZqmaZNgWgWXRcQqIjtE5FHz73IR2SQiR0Xk7yLimOw2jgcRqRSRPSKyU0S2msuyROQpETli/ps52e1MNBHJEJEHROSgiBwQkbNnw+vWxibS8TLJ7blTRBpEZG/YsinxOY7Stq+LSI35/u0Ukatj7WOc21ciIs+JyH4R2ScinzCXT4n3bzaI8hn5ofm9vFtEHhaRjLB1XzLPyYdE5Iop0NZvme3cKSJPikihuVxE5BdmW3eLyJmT3dawdZ8RESUiOVO1rbG+J6baZ8Bc/jHzM7tPRP5vKrR1somIS0Q2i8gu8335hrl8yl9bx2j7XSJSEfa5XD3JTY1KpvE9TYS2T5v3faYb6TnbXF8qIp0i8tnJaoeIrBSRV83jeY+IuCa6HSJiF5G7zec/ICJfGsc2TPi1yQjb8XZz+R4ReUVEViWqHVpsIvIJEdlrHgufjLHdehEJiMiNE9i8wW2I2VYRuUhE2sPODV+dhGaGt2fY99Zs805zm+cnuInh7Rjuvf1c2Pu6V0SCIpI1CU0dSCk1bX6ATwN/BR41/74PeKv5+++AD092G8fpdVcCOYOW/R/wRfP3LwI/mOx2jsPrvht4v/m7A8iYDa9b/4ztJ9LxMsntuQA4E9gbtmxKfI6jtO3rwGcn+30z21IAnGn+ngocBpZOlfdvNvxE+YxcDtjM33/Q9/6b/ze7ACdQDhwDrJPc1rSw3z8O/M78/WrgcUCAs4BNk/2+mstLgCeAE33fY1OxrdG+J6boZ+Bi4GnAaf6dNxXaOtk/5ucpxfzdDmwyP19T/to6RtvvAm6c7PbF+Rqm7T1NhLZPm/d9pv+M5Jwdtv4B4P5I3+kT0Q7ABuwGVpl/Zyfqu3iE7Xgb8Dfz9ySM+4mycWrDhF+bjLAd5wCZ5u9XJbId+ifm/9FyYK/5+bNhXLssiLCdFXgWeGyyvnvjaStwUd95YrJ/4mxvBrAfKDX/zpuqbR20/bXAs5P9Hiulps/IZREpBl4P3GH+LcAlGCdEMAKRb5iUxk2O6zFeM8zA1y4i6RgnwT8AKKV6lVJtzPDXrc08SqkXgJZBi6fE5zhK26YMpVStUmq7+bsHOAAUMUXev9kg0mdEKfWkUipg/vkaUGz+fj3GjZlPKVUBHAU2THJbO8L+TAb6Ck1cD/xJGV4DMkSkYGJaGvPY+ynweU63E6ZuWyOZcp8B4MPA95VSPnObhqnQ1slmfp46zT/t5o9iGlxbx2j7tDCd72kGt12bWkZ4zkZE3gBUAPsmsR2XA7uVUrvM7ZqVUsFJaIcCkkXEBriBXiD8GiKRbZjwa5ORtEMp9YpSqtVcPuAzo42rMzAC+d3mZ/R54I0RtvsY8CDQEGHdRIm3rVNFPO19G/CQUuokDLhenGgjfW9vAu6dkJYNY9oEl4GfYdxwhcy/s4G2sJNDNUbQYSZSwJMisk1EbjGX5Sulas3f64D8yWnauCkHGoE/mlPv7hCRZGb+69bGLtLxMtVM9c/xreZ0uDtliqScEJEyYA3GCLWp/v7NJu/FGGUDxjm4KmzdlDgvi8h3RKQKeDvQNyVvyrVVRK4HavpusMNMubaaIn1PTMW2LgLOFyPlwPMist5cPhXbOqHESG+wE+MG9SmM0dvT4tp6cNuVUpvMVd8xP5c/FRHn5LUwpp8xfe9pfsbAtveZDu+7FnbOFpEU4AvANyazHRjf0UpEnhCR7SLy+UlqxwNAF1ALnAR+pJQatwEYU+XaJEo7wr2P0++RNr72YlyvZItIEsZI9pLwDUSkCLgB+O0ktC/csG01nS1GCqvHRWTZxDZxgHjauwjIFJH/mnGEd014Kw3xvreY66/E6GyYdNMiuCwi1wANSqltk92WSXKeUupMjGkpHxWRC8JXKmM8/LQZsREnG8bUnd8qpdZgnOy/GL7BDH3d2tjFPF6mmin4Of4tMB9YjXGB/eNJbQ39N0APAp8cNMpiKr5/s4aIfAUIAPdMdltiUUp9RSlVgtHOWye7PZGYF4dfJvKN3VQ05b4nYrABWRhTjD8H3GeOFJ31lFJBpdRqjFFpG4Alk9ui+A1uu4gsB76E8RrWY/yff2HyWhjZdL6nidH2Kf++axHP2V8Hfho2C2Cy2mEDzsMIbp4H3CAil05COzYAQaAQY5DTZ0Rk3ng9/1S5NonVDhG5GCO4rI/pCaCUOoCRquVJ4D/ATozPZLifAV9QSg3u4JtQcbZ1OzBXKbUK+CXwjwls4gBxttcGrMWYnXMF8P9EZNEENhOIu619rgVeHs+OsJGYFsFl4FzgOhGpBP6GMXXs5xhTRWzmNsVAzeQ0b3wppWrMfxuAhzFOfvV902TMfydzWsR4qAaqw0aiPIARbJ7pr1sboyjHy1QzZT/HSql686Y9BNzOJL9/ImLHCCzfo5R6yFw8Zd+/2UJE3g1cA7zdDPCDcQ4O71mfaufle4A3mb9PtbbOx7iZ3WVe6xQD20VkDlOvrbG+J6ZcWzGuJx4ypxlvxhhxmcPUbOukUEbaseeAs5lm19Zhbb9SGamUlJkC5Y9MzfP/dL6nGdJ2EfnLNHnfZ7Uo5+yNwP+Z/5+fBL4sIuMa5IzSjmrgBaVUk1KqGyOP7LgWro3SjrcB/1FK+c17iJeBdePZDtNUuTYJbwcishIj/c31SqnmCWrDrKeU+oNSaq1S6gKgFaPeTLh1wN/M4/ZG4DdmepsJN1xblVIdfZ1XSqnHALuYxaonQxzvbTXwhFKqSynVBLwATEoxyzja2uetTJGUGDBNgstKqS8ppYqVUmUYb+CzSqm3Y1xM9lXIvBn45yQ1cdyISLKIpPb9jpGXai/wCMZrhhn42pVSdUCViCw2F12KkWB9Rr9ubWxiHC9TzZT9HA/K7XYDk/j+maML/wAcUEr9JGzVlH3/ZgMRuRJjWvR15o1gn0eAt4qIU0TKgYXA5sloYx8RWRj25/XAQfP3R4B3ieEsoD0s1cqEU0rtUUrlKaXKzGudaoxilnVTra0Q83tiyn0GMEbKXAxgjkBxAE1MzbZOGBHJFZEM83c3cBlGXvspf20dpe0HwzodBSNn8ZQ7/0/ne5oobX/HdHjfZ7No52yl1Plh55yfAd9VSv1qotuBUcR2hYgkmR0sF2Lc8010O05idPb03UOcxelrhkS3YUpcm0Rrh4iUAg8B71RKRQtqaeNARPLMf0sx8uz+NXy9Uqo87Lh9APiIUuofE91OGL6tIjKnb6aYiGzAiD1OWkfFcO3FOO+eJyI2c0bhRozrogkXR1v7apRdyBS6XrANv8mU9gWMnptvAzswi7/NMPnAw+ZxaQP+qpT6j4hswZja+T6MqvJvnsQ2jpePAfeIiAM4DrwH40tppr9ubfQiHi+T2SARuRejWm6OiFQDXwO+zxT4HEdp20Uishoj1UQl8MHJaJvpXOCdwB4xcmuCkTpgSrx/s0GUz8iXACfwlHmsvaaU+pBSap+I3IdxUxgAPqoSVJRnDG292uykDGF8Vj5kbv4YRg6zo0A3xvllwkRqq1Iq2jXMlGsrUb4npuhn4E7gThHZi1Gg6WZzpNqktnUKKADuFhEr5rWVUupREdnP1L+2jtb2Z0UkFxCMaaQfirGPqWY639PcM43f9xllJOfsqdIOpVSriPwE2IJxTnlMKfXviW4H8GuMWj/7MD7Lf1RK7R6nNkz4tckI2/FVjFzwvzHfo4BSaiJGcWvwoIhkA36M65I2EfkQgFLqd5PbtCGGa+uNwIdFJAB4gbeGzRSYDDHbq5Q6ICL/AXZjHBN3KKUmq7M0ns/BDcCTSqmuSWrjEDK5/7+apmmapmmapmmapmmapmnadDQt0mJomqZpmqZpmqZpmqZpmqZpU4sOLmuapmmapmmapmmapmmapmkjpoPLmqZpmqZpmqZpmqZpmqZp2ojp4LKmaZqmaZqmaZqmaZqmaZo2Yjq4rGmapmmapmmapmmapmmapo2YDi5rmqZpmqZpmqZpmqZpmqZpI6aDy5qmaZqmaZqmaZqmaZqmadqI6eCypmmapmmapmmapmmapmmaNmI6uKxpmqZpmqZpmqZpmqZpmqaNmA4ua5qmaZqmaZqmaZqmaZqmaSOmg8uapmmapmmapmmapmmapmnaiOngsqZpmqZpmqZpmqZpmqZpmjZiOrg8y4jIXSLy7XHc//kicmi89q9pWnxEZJ+IXDTZ7dA0TdM0TdO0sRCRMhFRImKbivsbtO93i8hLid6vpk134x0r0ve/kyvhX6ba7KaUehFYPNnt0LTZTim1bLLboGmapmmapmkjJSKVwPuVUk9Pdls0TUuM8Y4V6fvfyaVHLmuapmmapk2A8RghpWnazCci1slug6bNFPpcrGkziz6mpwYdXJ4mRKRSRD4nIrtFpEtE/iAi+SLyuIh4RORpEck0t71fROpEpF1EXhCRiD04IpIpIo+KSKOItJq/F5vr/kdEtg3a/tMi8k/z96tFZL/53DUi8llz+UUiUh32mC+KyDFzu/0icsN4vUeaNl2M8Hg+S0ReEZE2EdnVN9VHRM4RkSYRKTH/XmUex0vCnuN15u9WEfly2LG4Lexx54jIFvP7YouInDMZ74mmTTUjPE6vM6fitYnIf0XkjEH7+YKI7Aa6RMQ2zPYlIvKQeW5uFpFfha37gIgcCDunnmkuP8PcT5u53+sm8K3StEkX7/EqIv8WkY8NeuzuvutTEfm5iFSJSId5rjw/bLuvi8h9IvInc5/7RGTdSNsQtn3U63Ux0tj9VkQeE5Eu4OJxfQM1bZyYx8VnzeOiXUT+LiIuc901IrLTPHe9IiIrzeV/BkqBf4lIp4h8PmyXbxeRk+Y18FfCnscip+87m81jNctc15cC430ichJ4NkI73xN2fj0uIh8MW3eRiFSLyGdEpEFEakXkPWHrs0XkEfN7YzMwP2ydiMhPzcd1iMgeEVmesDdY06agaMe9DI0VnSkiO8zj7n5zu2+HrY/4HRH2HIOvr8PvfzeIyKvmY2tF5Fci4pjQN2KW0cHl6eVNwGXAIuBa4HHgy0Auxv/lx83tHgcWAnnAduCeKPuzAH8E5mKcwL1A303sI0C5hN3wAu8E/mT+/gfgg0qpVGA5EU7SpmPA+UA68A3gLyJSEN/L1bQZbdjjWUSKgH8D3waygM8CD4pIrlLqFeD3wN0i4gb+Avw/pdTBCM/1aeAm4GogDXgv0G1edP8b+AWQDfwE+LeIZI/PS9a0aSee43QRcC/wSXP5Yxg3xOEXsDcBrwcygHnRthdjdOKjwAmgDCgC/gZGpy/wdeBdGMfxdUCziNiBfwFPYpz3PwbcIyI6RZU228RznXw38I6+B4jIKozj7N/moi3Aaoxz7l+B+/sCYabrMI7JDIxr5V8xULzX6jD89frbgO8AqYDO36pNZ28GrgTKgZXAu0VkDXAn8EGMa9DfA4+IiFMp9U7gJHCtUipFKfV/Yfs6D2Na/aXAV8PuVT8GvAG4ECgEWoFfD2rHhcAZwBUR2tgAXINxfn0P8FMxO3BNczDuZ4uA9wG/Duss+jXQAxRgXGO/N+xxlwMXYHwnpJvvRXO0N0rTZpAhx334SvM6+WHgLoxz7r3ADWHro35HhO2m//paKRUY9PxB4FNADnA2xnfGRxLyyrSIdHB5evmlUqpeKVUDvAhsUkrtUEr1YByYawCUUncqpTxKKR/GjegqEUkfvDOlVLNS6kGlVLdSyoNxAXuhuc4H/B3zAtwcTVGGcdML4AeWikiaUqpVKbU9UoOVUvcrpU4ppUJKqb8DR4ANiXk7NG1ai+d4fgfwmFLqMfMYegrYihEkBuP4Tgc2AzUMvYju837gf5VSh5Rhl1KqGeNkfEQp9WelVEApdS9wEOOGWNO0+I7TtwD/Vko9pZTyAz8C3ED4LIBfKKWqlFLeYbbfgHFT/DmlVJdSqkcp1RdUej/wf0qpLeZxfFQpdQI4C0gBvq+U6lVKPYtxrr5pXN8ZTZt64jleHwEWichC8zHvBP6ulOoFUEr9xbw+Diilfgw4GZgf8iXznBwE/gysGkUbMJ9ruOv1fyqlXjbP/z2JeIM0bZL8wrwfbMHoDF0N3AL8Xim1SSkVVErdDfgwzmmxfEMp5VVK7QJ2cfoY/BDwFaVUddgxdaMMnC7/dfPc6h28U6XUv5VSx8zz6/MYHbbnh23iB76plPIrpR4DOoHFZqfwm4Cvmvvei9GJFf64VGAJIEqpA0qp2mFeo6bNBJGO+3BnYdSA+4V5XD2EcU/bJ57viPDr6wGUUtuUUq+Z5/NKjOD0hQl7ddoQOrg8vdSH/e6N8HeKGNPfv29OCeoAKs31OYN3JiJJIvJ7ETlhbvsCkCGn87rdDbxNRATj4vs+82QNxkn0auCEiDwvImdHarCIvCtsKkMbxijnIW3RtFlo2OMZY1bB//QdP+YxdB7GyAjMwNRdGMfVj5VSKspzlWDMIhisEGOEZLgTGKMyNE2L7zgdcBwppUJAFQOPo6qw32NtXwKciDD6AmIfx1Xmfvro41ibjYY9Xs0g7d+Bd4iIBaMT5s99G5nTeA+Y03jbMDpww69b68J+7wZcg4JX8XxnEOf1evj3hqZNZ4OPm75r3M8MusYtwTinjXRfmPt7OGxfBzBGLuaHbR/1mBKRq0TkNRFpMR9/NQOPx+ZB5+a+587FCJCF7zv8HP8sxgyHXwMNInKbiKQN8xo1bSaIdqz2KQRqBt2/hh9H8XxHxDqmF4mR9rXOPM9+Fx2HGlc6uDzzvA24HngdxgVxmblcImz7GYzRGBuVUmkYU3b6t1VKvQb0YvTavo2wi29z5NT1GFP5/gHcN3jnIjIXuB24FchWSmUAe6O0RdO0oaqAPyulMsJ+kpVS3wcw02Z8DSO9zY8HTRMavJ/5EZafwjhxhyvFGAWtaVp8BhxHZodsCQOPIxXn9lVAqUQuTBLrOC4xA2V99HGsadHdDbwdY4pst1LqVQAx8it/HmMqb6Z53drO+Fy3xnO9Hq3DWNNmgirgO4OucZPMWXQw8s9/FXDVoP25zFkEfSLu07x+fhBjJlG+eew/RnzHfiMQwDiP9ykN30Ap9Qul1FpgKUZ6jM/F+Zo0bSarBYrM6+A+4cfRcN8REPt74rcYM3IXmrGuL6PjUONKB5dnnlSM6QLNQBJGD02sbb1Am5l79WsRtvkTRm+rv29qrpkX8u0ikm6OnOwAQhEem4xxwDeaj3sPxghLTdPi8xfgWhG5whzl1FcIodg8Ed+Fkf/8fRgn6G9F2c8dwLdEZKEYVpp5lR/DmB78NrMIwlswLnwfjbIfTdOGug94vYhcauY//gzGefiVUWy/GeNY/r6IJJvH/Lnm4+4APisia83jeIHZibsJY0TI50XELkbRz2sxczVrmjaQGUwOAT8mbOAExnVxAOO61SYiX8XIvzoeRnK9rmkz0e3Ah0Rko3lOSxaR14tIqrm+HqNGQbx+B3zHPC8iIrkicn2cj3VgpMBpBAIichVGruRhmSlyHgK+bs4KXgrc3LdeRNabr9EOdGHkZo5036xps82rGLMLbjXvQ69nYPrU4b4jhpOKEafqFKPg/YcT2nptCB1cnnn+hDEVpwbYD7wWY9ufYeR5bDK3+0+Ebf6MERD+y6Dl7wQqzSkGH8IYATKAUmo/xoX7qxgXCCuAl+N/KZo2uymlqjBGNn0Z44K3CmO0Q19RoDyMIn4Ko/jIeySssn2Yn2AEtJ7EOMn+AXArI+/yNRjBrWaMEVvXKKWaxvN1adpMopQ6hJEf/ZcY59NrMYoQ9Y50e/Mm9VpgAUYxo2qMHM0ope7HqI3wV8CDMWsoy3yea4GrzP39BniXilzcU9M0w58wrkvDr2+fwLgWPoxxLd3D+KWmGMn1uqbNOEqprcAHMAYxtQJHGVjw63vA/5rT4T8bxy5/jpFT/UkR8WAcUxvjbIsH47r6PrMtbzP3Fa9bMab812EM/Phj2Lo0jCBZK8Yx3wz8cAT71rQZybx+fSPGIKk2jGvjRzE6XuP5jhjOZzGOZQ/GMfj3xLRci0aip+jUNBARN0b13DOVUkcmuz2apmmapmmaNhYi8i7gFqXUeZPdFk3TNE3TQEQ2Ab9TSv1x2I21KUePXNaG82Fgiw4sa5qmaZqmadOdiCQBHwFum+y2aJqmadpsJSIXisgcMy3GzcBKIs+m16aBSAVjNA0AEanESHr+hsltiaZpmqZpmqaNjYhcgZEf9WmMFDOapmmapk2OxRjpaJKB48CNSqnayW2SNlo6LYamaZqmaZqmaZqmaZqmaZo2YjothqZpmqZpmqZpmqZpmqZpmjZiOrisaZqmaZqmaZqmaZqmaZqmjdiUy7mck5OjysrKJrsZmjbhtm3b1qSUyp3sdoyWPna12Uofu5o2/ejjVtOmJ33satr0o49bTZueRnLsTrngcllZGVu3bp3sZmjahBORE5PdhrHQx642W+ljV9OmH33catr0pI9dTZt+9HGradPTSI5dnRZD0zRN0zRN0zRN0zRN0zRNGzEdXNY0TdM0TdM0TdM0TdM0TdNGbMqlxdA0TeujlKLTF6C1y09rdy8t3b20dffS2uWnzfy7tdtPa5fx7+qSDL73xhWT3WxN07QJ1+kLUNfew4HaDv7y2gl+8pbVFGW4J7tZmjbj/f75YwSV4v3nzcNh0+N2NE0bmSf21dHe7ee61YW47NbJbo6mDXCssZOv/nMvJ5q7OWd+Nm9ZX8KZpZmIyGQ3TZtidHBZ07Qpq8Hj47wfPIs/qIbddmFeCntr2vjRE4e4bGk+K4rSsVj0SU/TtNnhfx/ewz92nur/+5Gdp/jwRfMnsUWaNvMdqfdw+4sVNHX6uHfzSf5+y9kU6k4dTdNMde09HKjroK27l86eAJ2+IGtKMzhrXnb/NlcsmzOJLdRmu05fgE3Hm9lc2cKWihaSnTZWFqdT29aD3Wrh5WNNVLd6AbhvazX3ba1mQV4Kb1lXwg1nFpGT4pzkVzC1BEOKp/bX4bBZyE1xsaI4fbKbNGF0cFnTtCkrP83F/924kk/9fdew22Ym29lc0cqemg5+9dxR8tOcvO6MfC5bms/Z87Nx2vRIAG3mEBEX8ALgxDiXP6CU+pqI3AVcCLSbm75bKbVzUhqpTZhOX4DH99YNWPa754+xqiSdc+bnTFKrNG3mO9nSTVOnD4CqFi+/fPaonkGlaTNEjz+I02YhGFL4g4reYIjeQAh/2L8lWUkRRxu3d/t5552b6PQFWF6YzrLCNJYXpbO0II3MZMckvBpNG+rFI43c+tcdtHv9g5Y3xXzc0YZOvvPYAX7wn4OcWZrJgboO/mdtCV++egk26+yewfPtf+/njy9XAiACf33/WZw9Pzv2g2YIHVzWNG1Ku2FNMXe+VMmemvaY27V3Bwb8Xd/h455NJ7ln00lSnDYuXJzL5UvzuWhxHulu+3g2WdMmgg+4RCnVKSJ24CURedxc9zml1AOT2DZtgv1t80l8gdCAZe1eP++/eyufv2IxN59TFvf0xUaPj5MtXaydmzUeTdW0GWPbiRb+7z+HBix78UgjSik9XVjTpgmlFC1dvZxq6+FUu5cuX4BrVxUSDCnO+t4ztHv9ZCU5OKMgbUAQOd1tZ252EmcUpHHx4twhATWXw8J3b1jB8qL4Ri2GQoqW7l4aPT6aOn00esJ+On20dfvJSLKTn+YiP83FeQtyWDwnNaHvhTZ79PiD/GdvHZ97YFdcM4SjCYQUmytbALjz5QpOtnTz67evmVWDupo6fbx8tIkn9tVht1p4cl99/zql4JN/38Hjn7iArFnQqaSDy5qmTXl/ft8G3n/3VraeaI26TXOXj2tXFvDKsSaauwb2vnb6Avx7dy3/3l2LzSKcNS+by5bm87ql+QnPSdrpC1DR2MXg+0oREIyFqS4bxZluffOpjZpSSgGd5p9282f0V4fatNXjD3LbC8cjruvuDfL1f+3nHztPccOaIlaXpFOSlcy2E628dryZwgwXzx1sZGVxOksL0zjW0MXdr1Zy3apCFuSlku6260CZpkXwz501fOJvO4csr2718uzBBraeaOVdZ8+lIF2nyNC0qcIXCHKqrYeaVi/Vrd0cqO3goR01zMtJ5gMXzCPJYeWCRbnYrRbsVnjs4+fT7vWzOD81rlR7oZA5ujkYIhBU5KU6qWntJmCOfFZKMS83BX8wxNbKVg7WdXC43sOhOg+H6zvx+oNxvxYReOpTF7AgTweYtZF71x829weFE+npA/V84t6d/Opta6bkCGZPj58Gj4/MJAeZSfYxX992+QJ88m87eelo9JHe9R0+Pv/ALm5/17oZfz2tg8uapk15boeVek9PzG2aOnspz0nmG9cv444XK/j9C8fJT3WS7LRxpKGzf7tASPHS0SZeOtrE1x7Zx7LCNC5baqTPWFqQNuYv/f2nOnjz718ddrufvmUVN6wpHtNzabObiFiBbcAC4NdKqU0i8mHgOyLyVeAZ4ItKKd9ktlMbX0/sraPLF4i5zc6qNnZWtbF2bibbwjrpSrLcVLV4h1wU//m1Ezx7sIF5uckca+ykKMPNXe/ZoAsNabOeUooGjw+jfy+y9929FYDVJRk6uKxpk6i7N8DDO2rYdqKVJ/bW0e0PMj83hY3lWSyek8rbNs7lq9cuwxolcFyY4Y6aQ93bG2T7yVZ2Vbfx1P569tV00BsMDdluQ1kmmytPn3dLs5Lo8gVo7uod02tTCv7y2km+ft2yMe1Hm51CMc5hY/WffXV897GDfPXapTG3CwRD3LPpJA/vqCE/zcnc7GTeeGYRS+akJaQdvYEQ+061s7u6nV1VbeysbuN4Y1f/eqvFGPYVUgqFcUwVprs4a142Z83L5nVL86OONg6FFC8caeQnTx1md3Xs2dUATx9o4O5XKnn3ueUJeW1TlQ4ua5o25TltVr5x3TI++OdtMafubCjPJivZyeevXMLbz5pLMKgoyXLzmft38dD2moiP2Xeqg32nOvjZ00coynBz+bJ8rlw2h3VlWVEvNhPh64/sp9MX5MYzi3E7dMBGGzmlVBBYLSIZwMMishz4ElAHOIDbgC8A3xz8WBG5BbgFoLS0dKKarI2DB7ZX0+0PUpadRF6qi93VbfQMSpFRnOkmJ8XJ7uq2AcubOntZWpDGgdqOAcPegyHFyZZuTrZ0A0Yu2ct++jzfun45Fy3OG+dXpGlTz10vV/D43jrqO3qobO7m+29cwZvXFnPftuqoj+kNDA00aZo2cY43dvHAtmrm5aTwrTcs59wFOeSnuUa1L6UUlc3dbK5oZlNFC88caBiSpzaS1m4/6+Zmsru6rf/cmigPbq/moxcvIDdVF1TTRqYg3c2GciO4uqWyhVACYs0um6X/+vOuVyq4aX0JC6OkbnnteDNff2QfB+s8A5bf9UolHzi/nE9ftnjU9+GBYIj7tlbz06cP0+iJPr4mGOFFn2rv4aEdNTy0owbHPyy8+9wyPn7pQlKcA8Omj+w6xSf/vnNE7fruYwdZV5YVd6qc6Uhi9bxPhnXr1qmtW7dOdjM0bcKJyDal1LrJbsdoTcSx+/ctJ/nCg3uirn/usxdRnpM8ZHlzp49XjjVzpN7DPZtOxjVawG234rQPP50n022nNeziMhBUdA4zijDcmtIM7n7vBtJcOg/0dDUVjl1zpHK3UupHYcsuAj6rlLom1mP1eXf6evVYMzfd/tqAZS67hWWF6fiDIZIdVmrbjWBYLKVZblq7jam/IrC7ug1fYOj1oQh87orFfOSiBQl9HZNhKhy3Y6GP24nRGwjxy2eP8Mtnj5Kb6sRhs5DqtJHksOL1hzhQ2xH1sR+/dCGfvmzRBLZ2dtDHrjZRQiHFY3treXxvHZsrWmIGqoZjtQgL8lI4NCiYNlYOm4UPXTifq5bPYcmc1Ck77V4ft1OHUoplX3uC7l4jDUthhouSzCQO13tYkJfClsroaSgjSXPbKM9JZnd1O+vmZgL0B6vvef/G/llvv37uKC1dvdS0evnPvrpouwPgimX5vPuccpbMSR1RAczeQIhP3beTf++uHdFriGVudhJXLJuDp8fPOfNzKMxw87G/budUe+xZ1ZHMy0nm8U+eP61yUo/k2NUjlzVNmzbWm6OJI/U0Amw70RoxuJyd4uTaVYWEzKIDzceHzzHl9Qfjyn02J81F2zCBm1h2nGzj0h8/z30fPDti2zUtEhHJBfxKqTYRcQOXAT8QkQKlVK0YdxdvAPZOZju18RMMKb756P4hy3v8IbadaCXdbSfFaaWmbfiL39xUF929QbaeaKUky02y044vMLQTTinIngUFSTQNYPvJVr7xr/3sqmrDZhEK0l1xTX/t09KlMxJp2kSo7+jh4R01NHl8LMpPZeO8LOZmj+6aurnTx8+fOcKemnaqW71jCiiHC4bUuBQU7w2E+MUzR/jFM0coznRTlp3MkjmpfPaKxTqVlRbRscbO/sAyYBSzjONaMZJlhWnsr+1gV5VxbhwcmH7L71/l9SsLqG718qdXT8S93yf21fPEvnoK0l089vHz4wowB0OKW/+6nSf31yPA0sJUqlq9dHjjH/QVyYnm7v7aJv/YcWpEudEHO97Uxd6aDtaaQfiZRgeXNU2bNublpnDHzev45N92RpyK9tn7d3HtqoKovYEiRk7kRHLYxl6soNHj4/pfvcTnr1zCG88sIsmhv5q1YRUAd5t5ly3AfUqpR0XkWTPwLMBO4EOT2EZtHN2z6UTUUZOL8lNo7/bHFVgG+vMwZyTZcVgtVHV5o257x4sVXL+6SN+0ajNWS1cvn7lvJ68db+m/iTyjIG1EgWWIPOVW07TE8fT4+d3zx3jlWDNfvHIJG+dlj3pfLV29vHC4kR8+cYiatujnwNFaOzeTzRWJL6AWrrrVS3Wrl82VLVy2NJ8z52Zin4JF1RJBRO4ErgEalFLLzWU/BK4FeoFjwHuUUm0RHlsJeIAgEJjOI6pHSinF//vHvqjrLSMc+W4RY+BBNLuq29lV3U5h+ujS0dS29/D6X7zIVSsKuGhxLuvmZuKOcp/87X/v58n99Wwoz+JIvYd9pzxsKM9K6HGX7raPKbgMsMusgTIT6QiGps1iIuICXgCcGN8HDyilviYi5cDfgGyMgmHvVEqNrfJEgly8OI/1ZZk8faAh4vrmzt6oxTdEhI3zsnlqf33C2rO7up3VJRk0d/moahn9xWhHT4D//cdebn/xOH+4eT0L8lIS1kZt5lFK7QbWRFh+ySQ0R5tgh+o8fPvfB4YsF/MiPyfFSWaSg+KsJGwW4UBdR1wjN7p8gWFHJjd39ca8kdC06e7R3ad47lDjgGVJo6iNMD9Xn8c1bbzsqmrjI/ds58a1xdz/wbOxjTKIGgwpfvf8MX7xzBF845Qn3e2wsmdQzYPx1BsI8ZbbXsNmEeZmJ3H5sjl84colE/b8E+Qu4FfAn8KWPQV8SSkVEJEfYNQh+UKUx1+slGqKsm7GundzFa8eb466fiQ5wV02S9wDouIdjLWhPIsTzV0IgkWgJCuJTRUt/OGlCu5+pYK52cm0dvspSHeRmeSgwdNDXqoLh81CfUcPywvTBgSTj9R7WFGUjt0qdPcGOFjXGffri6Suo4c1JensqBpZZ3O4nVVtY2rDVDYzu7I0TYuXD7hEKbUKWA1cKSJnAT8AfqqUWgC0Au+bvCYOFAop1pRmYrdG7ll9LcYJE+CHN65kUX5ib/h2VrXFVdQjHieauyNOddc0TQPjRvhHTx5iVXE6SwtSWTInlQ3lWWwsz6I4w836skwqmoxq2NtOtLKpogWXzUpRlE63cP6gIjs5dmGglq5enj0YuXNP02aCjKShHSxNnSObGp/ssDJfdxJr2rhJcdm4/V3r+NRli0YdWAb41qP7+eETh8YtsAywdE4agRgzGQrSnSyZk0qUW5tRC4QUxxq7eOnIzIuhKqVeAFoGLXtSKdXXk/4aUDzhDZuilFLct7WKrz0SO1te8jAdqRaBlcXpJDms9ARCbIpzVHC8QehgUFHf4aOuo4dT7T1sP9nKmaUZbCjPoiQrmWONXbR09bLvVAcvHW3icH0nLx1t4tmDDew71cHeQTOUW7v97KlpZ/vJNiySmNDnWAPUg4trzySjfodFZLGI7Az76RCRTw7a5iIRaQ/b5qtjbrGmaQmjDH3fkHbzRwGXAA+Yy+/GyN06JVgswkcvXsDNZ5dFXD9cYbyMJAfvObc84e3q8AYSkiID4IXDjfxr16mE7EvTtJmj0xfgE3/bwVP769lS2cr+Wg8H6zxsrmhhU0ULBelutlS2Utvew6aKFs4szQCgweOjps3L6pIM8lOdZCUN/J502y247RbKc5LYXDn8jUJ+mq5Mr81c+alOBhepH+k02JxUJ2tKMhLXKE3TADjV5uXG377CS0eaWFqYNqZ9VbV0c/erlYlpWBTr5may7WQrkWLLOSkO1s3NpNHTy8E6DxaLsKEsK+FtWFowtvdpmnov8HiUdQp4UkS2icgtE9imSdHpC/Dp+3bx+Qd24w/Gnno2zGrWzc1kd3X7gJzN8XDa47tH3l3dygULc7AILM5PZXVJBo2dPjZXtPQPnBitBs/o8koPtqI4fUyPr2zupq17SkwIT7hRp8VQSh3CGOmImfOxBng4wqYvDlepXtO0yWMev9uABcCvMXJUtYX1/FYDRZPUvKgykiIHkR/eWcOFi3Kwx6jCetHi3HFpU7LDSm+CRj7sqmrj2lWFCdmXpmnTW0uXj988d4y9Ne28FmOUSG8w9sV+31S8suwkPL4A/qCiwMyD5w+GyE1xkZ3sZOuJ2JXCc1J0cFmbuW5/8fiQQFCay84p4r8xfcv6Ejw9gYijoDVNG50uX4D3/HELh+o9VLd6eeOZRaQOM6gklns3nxz3NE/+YOT7ArfdgkVkwPnWHzQKjy/KT8HT46e2fezFBC0Cn3jdwjHvZzoRka8AAeCeKJucp5SqEZE84CkROWiOhB68n1uAWwBKS0vHrb3j7ZkD9Ty8oyaubatjpMUoznSzuTL29WE08eb+XlGcwQtHmthYnsWWyhZCCpbMSR3Vc/YpznTT0eOnLDuZ+bkpcY+2jmR9WWJypzd4fDPy+iBRaTEuBY4ppeIvAalp2pSglAoqpVZjTB3aAMSdlEtEbhGRrSKytbGxcfgHJND7zpsXMTXGv3fXcvtLFQSiXMwBZCc7uS7BgVu7VWjtTkxqDIBnDzbgjbNXuKnTx8+fPsIT++p45WgTR+o9nGju0sWENG2a21PdzvcfP8j7797KHS9V0NDpIytGTuTBxUxPtnSzvmxo0ZDK5m7KspNJdlgJhBS17T00dfZyoLaDTl/s3MwipwsAaiMjIiUi8pyI7BeRfSLyCXP510WkJmym39WT3dbZ6v6tVRFrOiQ7bcQzOWl1SQafvmwRH75wPiVZSePQQm2yiEiliOwxj9Gt5rJvichuc9mTIqJHBYwDpRT3b63isp88z6F6T//ysaSkq233cu/mk4loXkz1HT42lmexvixzQD2VZYXpNHgiB48P13fS3RtiWWEq6+ZmsqHMSH2V6hx57veQMtJZzRYi8m6MQn9vVypy14FSqsb8twFjcOSGKNvdppRap5Ral5s7PgOTJkI8BZitAmtKM1haFH2U+6k2LyOs99cv1n05QKrLxvqyTKpajfpFmypa+jt5D9Z52Fg+uhH9ywvTqG710uENsNVMFbduChTTe2h7DfdtreI/e2vp6Elc/GCyJaqg31uBe6OsO1tEdgGngM8qpaKXp9Q0bdIopdpE5DngbCBDRGzm6OVijJkJkR5zG3AbwLp16yY0kul2WPnhjav4yVOHhxQf+OETh3hgazW/eceZLJkz9CTpsFn46rVL2VTRTH3H2EcFAGQlOaiPcpE4GsebuvjNf4/y6csWITHO5N/8137ufLki4roPXjCPz12xeEy56DRNmzhKKeo6enjxcBP/PdzAieZumrt6CZlX2Mcbu3DYLNgsEAgZU2pzU50cqDVutnsDAzukmjp7KUyPnGu5sdNHqstOXcfp0ZhZKQ68vbGDy0rBfw838qa1OpXhKASAzyiltotIKrBNRJ4y1/1UKfWjSWzbrPetR/fzh5cin08P1XYQz8Skt20o5c3rSxLcMm0KGVwE7IdKqf8HICIfB74KfGhSWjaD/eKZo/z06cMDlqW5bTE7WyNp9/p5eHs1hxs6eXp/fUIHhURT19Ez4Dy7tCANt90y7Ayhdq9/SPA8O9nBytwUdlePrJjYC0caWV40tqn804GIXAl8HrhQKRVxCK6IJAMWpZTH/P1y4JsT2MwpKS/NyY6TbQOWrS/L7B+oZLUIIjLqUbuH6jxR1y3MT6Gm1cuWGKOiD9R2sG5uJgdqO+gaQUoOd4Qc0qMNkAMIiUmM/rvnj/X//qYzi/nhjSuxDM7HNQ2NObgsIg7gOoxqnINtB+YqpTrNURj/AIbMy5gpUw40bboRkVzAbwaW3cBlGMX8ngNuBP4G3Az8c/JaGd0b1hTx+pUF3PbCcf625SRVLUZvp1JGcPYNv36Z77xhBQUZLl480jSgUnJOipPPXL6Yzz+wOyFtmZPuSmhwGeCXzx7lsT213PaudRGrzrd19/KnGLnifv/CcSqauvj5W9dEPLlqmjY1KKU40dzNFx7czaaKFjaUZ7G5ogW7RUhyWmn3ng74Oq0WekIKUMzLTeHAqXY2lGcCwilzxEe4aBerbd1+YOCN64nmbtwOK2XZSVQ2R58aeemSvNG8zFlPKVUL1Jq/e0TkAFMw7dRsFYoxP35uTjL7BhUKCpeb6uSOd61jlc6zPKsopcI/FMkYuVy1BDpc7+HnzwwMLJ81L4tfve3M+IuEhRQPba/mR08eStigktHaX9uBw2ZhbWkG2wYF84bT3NVLc1cva0oyqGrtpqkzvhHJffdHM4mI3AtcBOSISDXwNYx4lBMj1QXAa0qpD5kzCu5QSl0N5AMPm+ttwF+VUv+ZhJcwYQ7HCOz2GTywONVpjRnsHamu3iC5qU4aI9wrpzptw+Zw7ugxRh4vzk8dMHshFpslclD7RHM3wui+rH2BkeWajseD26vJSLLz/65ZmvB9T7REDGe7CtiulKofvEIp1dFXLEwp9RhgF5GcCNvNiCkH2sxwsrmbp/fXc9fLFbz5969OdnPGWwHwnIjsBrYATymlHgW+AHxaRI4C2cAfxrMRvYFQ/8i8kbJbLXz04gU89akLuXxp/oB1Pf4Qn7l/F21dfvyBEL9+7uiA9QvzUnjHWYnp0Bqv0cHHGru49pcv8dG/bmfHyYEn+fu3VsesPg3w5P56Lvvp8xyO80SsadrEu/PlSi760X/ZVNFCaVZS/7HuD6kBgWUAjy+Ay25lZXE6/kCIJIeNzRWtbK5oobpt6A3krqo2CjNcMZ/fYbOQ5LBSnOlmcX5KzNkSAH9+7UTUPJJafESkDFgDbDIX3WpOr79TRCLO2ZzMVFSzwetXFERcvrwwDd8ww5avWj5HB5ZnvohFwETkOyJSBbwdY+SylkAtXb390+NTnDb+/L4N3PuBs+LK/R8KhXj2YD1X//xFPvfA7kkPLPfpDYSo8/jIHWX9gh1VbXT5gmwoy4prHGW7d+alxVBK3aSUKlBK2ZVSxUqpPyilFiilSpRSq82fD5nbnjIDyyiljiulVpk/y5RS35ncVzL+MuIY4T/4fjLZmagEB4bsZAdNnZGPv5HkPU9z2yjJdFOcEXlWXrj8NDcdPUNn4xn5jkeXq30sqXhiWTnGIoFTRSKiITcRJSWGiMwR8w5FRDaYz9ecgOfUtHFT2+7lnPnZ/O754yzMGzpadCZRSu1WSq1RSq1USi1XSn3TXH5cKbXBPEn/j1JqXK/Gnj/cyPGmzjHtw2W38su3reGGNUMHgd324jE+f+ViclOcAwIin3tgN/5AYgaZWMdxKkt3b5B/767lht+8wk23vcbLRxv5+5aTfOexA3E9vrrVy/vv3jrqAL6maePn37tr+W7YsVzd2j1svnSPL8Du6nZ2VLXR0ROIOTVYYYwKiebM0gxCoRDdvUGqW73srGoftiL3thOt3P1KZcxttOhEJAV4EPikOfLxt8B8jELZtcCPIz1OD8YYP4FgiN/+91jEdV29QY42RL9GKc50c/1qnWp3FjhPKXUmxsCqj4rIBQBKqa8opUowiofdGumBumNo9M6al839Hzqbb16/jAc+fDbnL8wdtgMUYMfJVt5622t8//GDcY90nEg1rV6CKjTqe02vP8jmyhbm5SZTmhU70DbaILY2M7R3x9G5MOiyM9H3tc1dvayMkpplJE+1pbKVqlYvOanRP9ML8lJYX5YVM5dxbozHxzLcCOvRGq4De7oYU3DZzFNzGfBQ2LIPiUhfrqkbgb1mzuVfAG+Nllhd06aKjfOySXLa+NfHzuM7N6yY7ObMCuctyCHNPfpqz32cNivfe+MK3n1O2YDlB+s8fOq+XSwvSu+vVtvdGyDJYWVpYRrfvWFFzOBLPILBiflq213dxq1/3cEXHtwzosedbOnmsb2149QqTdNGSinFfVur+NTfdw4IJocUrC+Lv3CJ1x+kZJgby0P1neSmOFlTkk5K2Hfd0oI0dlW1xZVLdsjzjtMF9kwnInaMwPI9SqmHAJRS9WZx3RBwO1GKC2nj555NJ3nm4NBCfgAVTV2UZiWRnewgK0J198X5qaydO7piQ9r0EUcRsHuAN0V5rO4YGoO69h4O1Hp4dFct+2Okp1FKsbemnQ//ZRs3/OYVNidwWv94aOnyjzlt3bHGLho7e1kVY+TjNQkuYq5NL+E5v6OZkz4w2Gq1JHZGblaSPWoBy7ZRjAZ2DqqwK8CG8iwW5qVwtKGTLZUteCKMWu6TEeFcHo/MUY54Hs6SOanjst+JNqZoilKqC2PKfPiy34X9/ivgV2N5Dk2bKIFgiA/fs51fvHUNAL9//hhr52ZyVZRpklriuB3WhOUEdtmtfPGqJfgCof4q0D3+EP/eXcuhOg9PfeoCWrv9BEIh/vnRcwkp44S071Q792wafdXoWLkaE2lZUfqoiyn8+MnDXLw4L+FTnTRNG5lAMMQP/nOQ218cWjzMZoGdVW2sL8scku/OZoFVxRnYrBaCIYWIMdjkVKuXogw3SU4rR+ojj7Bs7PTR2OljWWEqxxq7cNut1LV7GW2/2M+eOUJXb5CPXjyfVNf4XGzPNOZsvj8AB5RSPwlbXmDmYwa4Adg7Ge2brdq9fn785KGY2/QVDhYxRkWFj2R+7Xgzj+4+xTUrdQBnpopWBExEFiqljpibXQ8cnLRGzmC/fPYIh+s7EYGbNg5MZ3e0wcPvnz/OvlMd1HX00NI1cJTm4fpOzizNYPsI8xsnmgicMScVhVGc1x8MsbI4g6MJGFXt7Q2yq7qdjeVZbKlsIXzy03vPLR9Rh7U282woz+Yvr8W+xw2/N3TYLP1F76wWYXF+Kk2dvqjB4VjKspM41d6DxxegJUoBzYaOHpw2y4hG7w5uS2GGm3avP+Zo5XBVLdHrikRTkunmUJRr7LFYMieVpQVpCd/vZNARBk0zPb63jteON9PuNQKPd7xUQVOnTweXp4FQSA0oWuWyW/nOG5ZzpN4zoBrz0YZOvvvYAf5nXQmL8o0eQqv5sG9ev5wuX4An99ePasrLaE64I1WS5WbbMNWlY6lo6uJPr57gwxfNT2CrNE0bqZ89fSRiYFmAtXOz2FTRwpbKVjaWZ1HZ1EVTp4+ggpXFwxcAWpSfQjCkONYYObXFvlOe/ucabc45MAok/e75Yzyys4Y737OeJXNmxoXxODsXeCewR0R2msu+DNwkIqsx+goqgQ9ORuNmC2Pm0ulboH/vro2YlzGS7GQHeanOAcHlrt4g+0518PoVBeyubqfd68dqEXr8QdbOzRz1CCltSolYBExEHhSRxUAIOAF8KMY+tFEIhVR/545ScN0vX2JdWSYZbgen2r28fLSJ4bK+VbV4cdkt9PgnZ+p5UYabVJeV/bXG+TfVaSXN5WRnVVtCnye8IDDA+88r5yuvPyOhz6FNL1srW/j4vTuG3a6mzUtJlpvcFCe7qtpo7+6lIN2Jw2phf20HWUkONpZnEQwprBZBKdh+snXY2j+5qc6YBaKTHVaWFKRxsM4zouByRVMX5TnJ/WncasyaI+vmZsaVW722vYflRWnsrYk+E2Iwrz844PhKlIN1Hl4+1syFi6b/rJYZEVz2B0NYRMY156k28z13sIHeQAiF4g7zpr+vMvg/d9Zw3arCuHJ8aROn7wT359dOcPOgVBgA9Z6h04Buf7GC0qyk/uByH6tF+Nlb1/Dkvjpu+fO2uNuwoTwLFCgUDZ4e/OOYHiPNZacqNLaKz39+tZJrVxVQnJmUoFZpmjZSkapll2S5sYqwKeyite/33FQnZVlJNEQphhLucH3nsPkXAbz+ECUuO7XtY+sY++glC5ifO7PrEySKUuoliFh/6bGJbsts9pn7dtEbCLF4TirnL8zlgW1VcT+2NCtpyMyCgnQX5y3I4ZpfvtR/3QjwreuXcekZ+dF2pU0jSqnjwKoIyyOmwdASZ2d124CgcHNXL0/sqx/RPho7fWwoy2JzZWKDQsOZl5NMepKdnSfbBqS09fiCeHzjk1qqr77Kxy9dyKdet1Dfu85yP336cFzbpbns1LR5qWox7jPbvAHawgpKt3T3Drg+BSO12v7a2MHZHn/sz/kZhWn951KrRXDZLHTFOchLxLigCj+2LCOIByaNcNZ0U2cvFunCKox61l8kVotgnyFxzMQmU5kkzxyo58IfPqeLVWmjdrCug8f31vH6lQU8vKOGu8xCRUcbO/nVM0do6eodt+qg2uhZLUJ7tx+XfehXWWVTF7kpTooyXAN+CjNcHKiLPgXtdWfk877zygGI53rMZxbU2FLZOq6B5VXF6QNuWkfrVHsPr/vJ85xojl2wS9O08dMd6WJbGaMiImn0+NhyopX6YfLmuewWNpRn0Rvn6I/D9Z1sKMtkbpabogwXqa6RjTnISXFy/eqi/lz2mjYdFGW4eeZgA7/57zFuuv21IdPoYxGkf3ZTqsvGyqJ05qS5eN/dW4aco1880oQuNaNpoxcKKb7/WGIyjWyubGF5URo5KfHNJHDbLawsSmd9WSbryzJZXZIRcbtlhWlsKMvEbk6FXDc3k7VzMynNcpOT4mB3VdvgWmnjauuJVt6+sZRPX7ZIB5ZnuWBIsauqPa5tD9Z5YuYojmS4wDEY58xYLCKIwMbyLJLsFpYWxjcLzm4VWrt6hxxbJ5q6KM8ZnwFUVouQ6rIlLLAsApcvzef5z13EOQtyErPTSTZtRy4rpfq/MJs6e6lu9fKjJw+xcV425y/IwdMTIH2cEm5rM0tvIMRH7tmO1x/koe01A9YpBT966jDzc5N55Vgzn75sEWfMkJw4M0V6kp0b1hSzuaIFh83CwrwU9td2UNnUxd6aDnqDQ4MsLxxuJBAMYYsSEPl/1yzlveeVs6uqjcP1Hn717NGo035aunuZk+aKq1jCWCTywtTnD/Hxe3fwj4+eqy88NW2CVTZ18a9dp4Ysr2r1DjudLy/V1T89OJLsZMeIp+uFFzzqm+53waJc3rimiAV5KRRluPH6g8ZPb5Aef5Du3tN/N3p8A4oEatpUV5x5emR/utsW8TphsPVlmaCgwuyY7Rtptbsm+o37q8eaae7qJSdldFXpNW22u29rVUJHG++t6SDVaY2ZgzndbWPxnDQO1HYMOb7Xzs3EaTNqHgRDiqBS7DD347QJmUn2Aen4TrZ4mZebjM8fpKZtfO8Twl2nC/hpGMHQ/339GXzxoZEVgU932yjPTsFpt9DdG8DtsEW8tmz3+klx2uj0RQ5KZyU5sFiEtXMzB6R13FCWyYmWbkqzkujpDZDhtvePiu7uDTIvN5njUVK72SzCmtIMLCL0BkLMyzXua/eanbv1Hh9z7e640uBYLcK6uZlYLcL+U+3DziZYNzdzyOjtkerLLT0nzcVXr13K1TMs/eq0vBv43mMH2FPTzicuXcjGedlUNnWRmWTnX7tP8Zv/HiMv1UmPP8jPb1rDxYvzJru52hRW39HDh/6yLeoXWJ9jjV0ca+xia2ULW//3Mp2CZYpx2Cy47Ba++a/9/Rd1V6+Yw5vWFnHv5qHTXatbvXztkX187JKFzEl3DVjXN52mKMNNUYabFKctZj6pqhYvZdlJRmGtcRya4LInpuDhxvIsTrZ047Zb+ca/9vGOs+ayIG9mVKjVtKmuqqWb//fPvawvy0QQtlS29HccJTusHGmIXSikID16cDndbSc3xUlhhntIIcB4ec0RmY0eH9evPp0KKnNUe9O0qakurANnUX7qsMdLSaZxTK0qSaepM/5Rzh5fgE3HW3j9ypl186hpE+WOl4bWJhgrjy/I9pNtLC9Mo7mrl0BfoNj86fQFo3bSbjvRitUiLJmTisMq7AgbFeoLKHyBobNcU502OiZ49uuyovQJfT5t6nrL+hJeONLIY3vq4tp+fVkmO6va2Fnd1r9MBArSnUPSqDV39bK6JCNq7vC8NCOvuDFQwYXHF0CFYFd1O75AKOJgin2nOrBbhI3lWdS0ealuPZ0OUgSWFaVFPGeX5yTjsFpQKI7UdzIn3UVJphsF9PhD7BnUUVSc6aa5s5fDZoG+dLedxfmxC/Y1x5GaLpYb1hTxwxtXsqOqjfm5KWQlz7x6DNMyuPzGM4tRClLM6ZtXrSjg5WNNHDCT5PcV1nrtWDPLCtNIc9mHDcz05W7VZo8ef5CvPLy3v8c5Hg6bBf0xmZpWFmfwh3ev57YXjvHr544NexK9Z9NJHtpew+avXEqqy05vIITDNnQkczzT5yqbu9lYnjXm3sxYWroSUzDwREs3de09CNDm9bOjqp1/fvTchOxb07ToWrp6uen21wZcKM/LTSYzyYHVAt2+YP/Ii0jWlWVyOEJV+TSXjSUFaRw41c6hhk7mpLkiPDo2l91CYbqb/DQn161awtLCdIIhhc2qT3jazNLjD1LRdPrm0RLH7J2qVi8pThsNHT7sVhlRCqx7Np0AwO2wsKE8W4/y17Q41bX3DCicmWhHGztHVeAvGFL9KXDKc5Jp9/qjptaZn5vMrur40hIkistuIXmEuWS1mUtE+N4bV2K3Wqhq6Y46Yr9PXUcPywvTqWrt7u9MVQoyk4YGl9fNzcQZITUlGMHoY43G8Xu0oRO3w8rSgrS4CtP7Q4pNFS2kOq2UZiVxsqWbwnQXxZnuAbPtwvUV9gPISnZQ295DbXsPyQ4rywd1tiyZk0qDxzfgerzd6ycUUhRmuDgVZZaBP45ZTtHkpjr5zg3LsVktrC/LGvV+prppeYWzeE4qr1uaz7JC44Oydm4mb1xTzHdqDwzY7vcvHOeOlyo4szSD+z90Tsx93vVKJY/vqWVBXgpfef0ZpLp0So2ZzB8M8b67t/Da8fiDgeluO89/7mKdRmAKS3fb+dwVS3hyX/2wIwDByG/62/8e4/3nz4vae1iWncw3rl/G1/65L+a+xjuf2tGGLtJctrgr2g92ZmkG9R2+/mq6p9p7KMx0U9/Rgz8Y0jlTNW2c3bv55IALWcCcNRNf/nOLCK3dp0c/Lc5PJc1tY1dVW/8oqySHFYfVwvqyTPaf6oirKMq83GSe+fSF+tymzQqfvX/XgGJgIzl3941y3FCWGfUGd7BXjjXzyrFmUpw27n7vBtbO1fMANC0ej+4emj4qUVJdthHnl42koqmLtXMzowaXM5McxHuOT5TsZKc+n2sDpLvt5KQ4+efOU8zNThowCCEYUiigyxfgYJ2HqhajqJ/LZqEsO4nKZmO2XE8giMMqZCQ5KMtJpqbNy9YTrThtQn6ak66eAHNzkklyWOnyBTlc7xkw89fbG4wrsBzO4wuytNCYsZeeZI/7vJvhttPTGyCoFCVZSQMGf4UX4x36fAFcDiv5qU7qwwpvF2e6KUh3jXpWIMA9799IkmNahl5HZNq+wg3lAyP+bz+rlN89f4zmQV/uwZDqH8kcjafHzzMH6tl6opWtJ1pJctj46rVLE95mberYWtnKy0ebR/SYdq+fXVVtbJyXTTCk2HGylXUzuOdpOnvk1vM4WNfBlx7aw8EYxfvA6IQKKcUXrzoj4vokp42bzy5j3dxM9ta083//OTTkewaMUYkL81KwCDGn1IzFvNyUqFOPhmOzWoaMQuzxB6lp9dLdGyTdrYPLmjZe2r1+fvnskVE/3mYR3DYrS+ak0uMPkuqysadm6Cjn7t4gh8zRzflpzriCy6uLM/SNqDYreHr8PLFv4Kwmp82C3SL4Y6S/ykt10tTpY31ZFqfavCO+QQbjPkUHljUtfs8ebEj4PjeUZdHg6SHVZR8yTX60uqLkmwWjuN7G8iwCoRC9gRB7azri7tCyCqMqHJaTqnO8a0P1FaQ80dzNiebI6dXCc5H3BkMEw/I99qUQbfD4BsTWfAFFWXYyLV29CSk8P1hfC+ItVA1w3BzF7HZY+0dP9xmuU6nR42NDWRb1Hh8F6S6SHFaONXYNGRwynKwkB0WZLuxWC9nJDublJI/o8dPVjIkmJDlsXL5sTsR1GUkDRyT25VTq8/kHdvPKsdOBxr9sOjFsRXZtehtNb3hpVhL+oOKVo0187N7tvPuPW/AFhr9x1yae22FlTWkmj338fP747vWA0Wt7xbL8IdsGQ4p/7DjFP3fWxPz/XFaYzlvWl3LewsjVXI82dJLqsnGkoZO1pfHdQKa6bMPU0B1oLFPUN1e0kDuoqFBnT4CCdBcfv3fHgO9ETdMSy2kbvrBIJBlJdjaUZ5Gb6uD5I40crPNQ2dwdMbA8WDx52udmJ/GTt6wecbs0bTpKddmH3BP4/EFWl2bEfFyDWbSyuzdIVat3VAEff0CfYzUtXsGQYtcoB1NEs7Ionc2VLeY5NHGpKmravCwrTGNDeRaRLtM3VbSw7UQbe2o6SHHZyE1xsqIojeIM95Bt0902NpRnUpjuIqggM8nOmaUZLC86XUzeZhEcVqPWTCQrinTheW0obxyDDdrDcoOHFGS448sJ3Ob1xzVjeCxGUxjX2xsckMaqPCe5fwBGLCEzqF6alcSxYepyRZPmNgaBHKj18OXXL8U2S2YIT9uRy5GUZA39kk5x2rj7PUZwqaWrl3s3n+Qvr53gdWfk8603LKe23TskaX9vIMT//ecgn7l8MYURvvi16a3B0zNk5Mpw3HYrTZ0+3vGHTYCRy6cww8VLh5sIKMWKonQK0l169NcUY7EIFy/J46GPnMOakgz213ZQ2dQ95MRS19HDS0eaeHxPHb9759qY+/zClUtYlJ+KUoofPXm4f/nG8iw2V7agFGw72TqkMm4kmUkO8tNcZCU5olbDXlWczvHGLrJTHLht1hHnewRj1FVZThKH6gae+PtyRW+tbGH7ydYZnQNK0ybTSEc8OG0Wlhels7u6LWphoeHkp7mijk7p4+kJ8J4/buaXbztT54LVZoWz5mXzr12nBxgY04GHv+lOdds51tjJ8sK0mLnRIz7WZeMzly8aaVM1bdY60uCJa+bNcNx241za2tXL7gQGlMEI/BZnuvEFQrjsVkIhhctujdluT08ADwEaO3247VbWlGRgt1nwB4JYLRZEYHPF6XuH1m4/rSfbWJSfwm/ffibnLMgh3X06dWe718+Reg8OmwVB2HuqnSuiDLbTZrfr1xTy5P46nj4QfUZAutuO3SqsKs4AGHb2b5/QOA1QctksNJgDPhMxKtppE0qzkoa9Nu4LLqsxvKy8VBeVzd185fVnUD5LRi3DDAsuR/oAZCfb2X6ylYsX5/GW37/a36vyty0nqevwcrSha8gU95XF6fxz5yn2nergT+/bQF7qyIvjaFNTc6ePi3/43xFfsHj9A7cvz0nmS1ctYcfJNr7zmJHr+7wFOXzvjSsoyUpKWHu1xDjTHEm8rDCdO25ex2fv3zWk+N4ju07hsFl49mA9lywZOsK5T2GGm49evACAjp4A/9hRQ1ayY8j+vL2xp90syEsZUKhkYZ5RNTYQUlgt0NzZSyAY4nBDJ97eIB5fgMrmbubnJtPZExiQCyqWZYVpVLd6B1yshttU0cKC3GRuf+E4K4rS4xrtqGnayKS7bRSmu6jr6MFqOd1BtLQgFZvVQn1HDzarhVSnjTS3HW9vYFRT78P1+Ic/z7V09fLcoUb+e6iBa1YWjun5NG2qau3q5ekD9bR7/Tyxd+DggpACj89PSZabqpbonUDpLjs1rV5avf64Oo/D5aQ4+fNrJxDgnPk55Kc5yRtF4U1Nmy1GUmw9kvKcZHJSHOw91TGmPKnRbCjPZHNF64A6CCPl9QfZEefo7GSnjatWFAxZnu62D0jRuKI4fcg2mgbgtFkpzoweo8hLddLRE6A4M4mtI7z+7CuM67BZWFWcTlWrl4I0F/WeHqwiVI1wgEWfnkAIb2+QtXMzsVlkyL32SB2s62RZYeqw23X3BrloUQ4vH4svheqSOamkumxUtXRT12Hcn9d19JDutvOW9SVjavN0M6OCy+HVn/tkpTi55U/bWFeWOWC4fiCkePVoM50Rgowuu5VASHGwzsM1v3iJ377jTNbO1SP6pitPj58uX5A56S6ePlCfkJ7wbSdaufF3rw5Y9tLRJn74xCHesr6EcxdETp2gTb6SrCTu/cBZ3Le1ivu2VvXnlvIFQvgCIe5+5UTM4HK4RXnJZCTZI/bsRsrL3KcwwzWkAvbg6URWi5DitA2ZxnSssYt1czPjDi4nO20DpjlF4vEFON7UyYqvP8FFi/N451lzWTs3k2Q9klHTEqLLFyQQUmS4HbR095Kb4sRhs7C/Nr5RIaNhtcQ3kyY72cHVy4fetGraTPH3rVX85MnDKNSQmT9WC1S1eFlflkl9ew9uh5VgUA24P8hOdtA3Ma2m1cupNi8L81M4Emd9hYqmLr7/+MH+vz992SI+funCsb8wTZuhdpwcW0A4N9U56lk/8ahsij3yMdF2V7fzl9dO8I6z5k7o82ozQ48/iNUiUWdup7vtdPkCNHh8FGWMvOOzsbOHrGQ76W5Hf2dOXbsx4jg72UFxpnvEM/j61Ht8NHb6yEtQLvHDdZ1sKM9iZ1Vb1DzOB+s8pLltw84UtllgdUkm20+2ElLGrMP1ZZl0+gIcqPVw1fI52GdJOow+MyJyEAwpWrp6WVWcwfOHm2gMD7ooI5D82vGBJxil4IzCtGF7Mxs8Pm783atcdkY+P33Lah1smWZ6AyE+e/8u6jp8FGe6ef5Q47g+37MHG3hyfx3vO6+cD144nzSXffgHaRPOYhHeuqGU/1lXwg2/eZnd1aenym2qaKbR04M/qGKmxTlc7+Grj+ynO0pnRX2HjySHldKsJFq6egcUP3BYLVjEGDEVTTCkogaFgyOYp7O1smXYUVb1HT7yU13My0mmprWbD/xpC3Ozk3n3OeUkO62kueycNS8bt0OPata00ahp86KAlm6j06mxM77OobE4VOeJmkanIN1FXpqLJfmpvHl9MZY4A9GaNh11+wL0BiPfRPZ14B6q89AbVPR6jVlH68syEQRfIIhFZMAIwzUlGTSN4RjeUtnC8cZO5uWmAEYBoT+8VMGG8sy4O7c1bSYb68jlxjgHYIxWg8fH6pJ0dle3x7yWT4TsZAf/vPXcmKNOZyMRuRO4BmhQSi03l2UBfwfKgErgzUqpITdAInIz8L/mn99WSt09EW2eLF9/ZB/PHGyIelzkpDj6cwvXtPWwbm7miEYvz0lz4w+FIna4Nnf1sjIzfdTBZTAGSxRmuAmGxn797A8pNle0sLI4fcD9fzi3w8q2YWKEKU4ri/PTBrxPvkBoQGxxWeHsy38+pkipiFQCHiAIBJRS6watF+DnwNVAN/BupdT2sTxnJJ4ePxu++zRfu2YpnWEVW3NTnFGnm6Q4bQSinA0Cgy5AlYIn99dz61+384eb1+ubsGngeGMnc7OTee9dW3jpaBNAwgtDRNL3+fv1c8d46WgzbruFqhYvX776DF6/Uo8Mm2qsFuFXN53JBT98rn9ZIKioaulmWVHsqWW7qtqiBpb7dPcGOVjn4czSDFq6fPR1kCY7bWO6GLWOILd3SEFl0/DFCHbXtCNifN9tLM9iU0ULX354T//61SUZXLgoF5tF+JgecTXpRMQFvAA4Mc7lDyilviYi5cDfgGxgG/BOpVT0YfTahDh3QQ5/ed9Grv3VSyOqeB1JYbqLkqwkjjR00hJjhoTXH2RF0cCLZ5fdwu/fuY4LF+WOqQ2aNh30BkI0dfpIc0fv6D/Z0o3NInQMqiBf19EzJE1GeU4SoRD9M55G68UjTTy1v552bzUritL52dNHONXm5dIz8sa0X02bCY7UezjaOLbiYBVNXWwozxrX0cvBkGLJnDQO1XUQVEZaTYsINouMOK1ALM1dvcPeb8xSdwG/Av4UtuyLwDNKqe+LyBfNv78Q/iAzAP01YB1G2v1tIvJIpCD0TBAKKZ7cXx/zevF4UxfLClPZd8pDXqozrrRq4fbXxs6HvLu6nfKcJCpGOeLfH1TYLBaau3zMzXJzIkYKq3jFCud5e4OsL8uMOAh1WWEaDR4fjR4f24aZYTEbMx8kYpz2xUqp1YMDy6argIXmzy3AbxPwfEO47FZuPruMt24oJRAM4bJZWFqQNiRPbp/8NCd2q0TtFY0W83nuUCN/21KVmEZr42r7yTa6ewNcsGjy0lPsqmrjteMt1LR52Vk1Nc9XIlIiIs+JyH4R2ScinzCXf11EakRkp/lz9WS3dbyUZiexKixHWSCk+PfuWoIhRb1ZRCCS8xfm8sYziyjKcDMvN3ai/u0n21iUn8qivBTWzc3kcByVamMJhkYWnGru6o2r9zTWgOidVW38/JkjpCfp0fhThA+4RCm1ClgNXCkiZwE/AH6qlFoAtALvm7wmauEWz0llvjlScTSWFRrV5T09fjZVtDB/mO8dpYwL+pXF6RRmuFgyJ5W/fuAsHVjWZo37t1Vx1c9f5FhjJ8lRZt4UZSQNGGySmWRnQ3kWnp6hdRNEhBMtiZkO/73HD/Kb/x7jw/dsZ+O8LJ773EW6qK6mAT/4z6ExFdLqs7mihQ3l43NMLS9MY29NB/trOyjMcJOX6mR3dTs7q9rYeqKVdXMzE/p8t79wfMAAOg2UUi8Ag3sPrgf6RiHfDbwhwkOvAJ5SSrWYAeWngCvHq52TzWIRfvrmVSyZk8qq4nRWFqVjHRRYVco4vy0vMgKnIy1aG4vTJqwqTh91YBmMmUSbK1sIKchJQHqMMwpS+3MjR7OlspXVJRkDlhVlGIWy45kZkeSwUpYz+2YbjHeOh+uBPymlFPCaiGSISIFSqjaRT+KyW/n6dcvo8Popy07GabNQ19ET9Ut4bnZyzJ7M1q5e5qQZhXcG+8lTh3jT2iKcNj09fCq7cW0xALdcMJ/zFuTyhl+/HHVK5Hhz2S1cesaUneYYAD6jlNouIqkYvbdPmet+qpT60SS2bcJkDAqY3vXqCcpyknnn2WVRHzMn3cUP3rSSpw/UU9vWw/cePxAzN5PbYRtzgS4wCoDtqBp5xeuKxk5Ks5I4GceNsS8QuWMu1Wnj+tVFI35uLfHM82rf0B67+aOAS4C3mcvvBr7OOHXsaiPjCwQ5FudorJwUBwXpLiwinGrrISPZPqRSdrzzF3oDIX725tWsL89CRjDrQdOmu2WF6bR7/dy7uYqVxek4rBaONHQOSDl1onngzJ75uSlR7xGykh0cbxx+JtBILMpP4YtXLSHJodPuaVpLVy8vmzNOE+HAqfa4r33jtaYkg7017f2D0SIVK9t6opV1ZZlsTVAxwfu3VfOPnTUUZyaRnewgP83FmtIMlhakkeQ0Cok9d6iBb12/fLan8MwPizPVAZFuwIuA8NGC1eayGevZgw0D6gOtLc0cMuq2qsU7Lh0Y6W7HsLV/hiNhV7yCYLcI/jFMAU512TkQR82TnVVtnD0vm06fH6fNypGGzrjeo5+8eRUXLc4jK9kx6jZOV2P99lHAkyKigN8rpW4btD7awZvQ4HKfp/bXU9ncRbrbTlNn9KH/nRFGI4SrbO5mQ3lWxOByU2cvd7xYwUcvXjDm9mrjLxAM8fje2nEPLJ81L4sdJ9vwmdOdrRbhzNIMrl5RwLWrCslJSUwS+kQzT8C15u8eETnADD/BDubzB4eMUAqGFD956jBv3VBKMKRw2SN3JtmtFq5aXkBvIMgFi3L4+TNHef5Qw5DptQD+BH0Go7VlOF5/CIvA6uIM9tW2Rw2Ep7lsBKOcsD935WLSY0wv1iaWiFgxUl8sAH4NHAPalFJ9H8AZf8E8nfxtc1XUlBhl2UkojHReFotQ397DnprTweRIOea2nmhlcX4qh2LMhLjlgnl8+rJFo/7e0LTpbHVJBsuLjBGGfelh+tI+zUlzYbcKqS7bgMKabd29UXMxHqnvZO3cTHaebGWYOj9xKUx38Zb1pTqwrGmmXzxzJOrM45HITLKzIC+FrSda8fjGHljOTnZQnpOM1x+ImnJzsG0nWslKcvTXWhgrf1BR0dRFhZnq7t97hoZTqlq6+eN7NpAyuwPMgDEIw4xRjZqI3IIx+57S0tKEtGui9fiD/PfwwJpT20629p8L+4w1ABxNw6BRviuK0tlTM7JBUiosr8DumnYCSg1p/0hsrmhhfVkmu6vb+2M30bR09ca8zo5kRVH6rAwsw9iDy+cppWpEJA94SkQOmlMURiRRB+7rVxbw4PZqXjnWHHO7Bk/0qe4D2xV5mvivnj3KjWuLyU8beTVNbXx1+QIkOaw8tL2G3FQnzxysZ19NR8yk7WORnezgjpvXsaY0k2cO1BMwUylcs7Jw2n2piEgZsAbYBJwL3Coi7wK2Yoxunpq5PcaosdPHrgifjdZuP3969QTnLshmyZzYKSUcNisL8lL5yZtX8fLRJv74ciXPDzqROxJULXb7ybYBeaDm5yaT6rThDRjB4zSXPeLJdvGcVLPXOvJFdnlOErmpLk40dQ0IavXJTXXyjo26SvVUopQKAqtFJAN4GFgS72NnwgXzdHK8sZMfPXEo6vp2r5/Wbj8nmuO/CVaKiJ3gfW69eAGfvWLxiNqpjS8RKcHID5mPMUDjNqXUz+MtQqSN3GcvX8zH/roDrz9IIKTYVNHCmpIMbFbhRHMXBU43Nov0p8Y42tjFmtIM1pRk4PUHSHba+2cdtXv9CCQksLyyOJ37P3S2ngmpaabjjZ385bUTCdnXovzUUQee+pRlJ5GX5qLR46OiqYvmGDlrB5ubnUR+qovNleOX8zmSLZWtfPmhPfzipjUT+rxTSH3fLHkRKQAaImxTA1wU9ncx8N9IOzMHTt4GsG7dunEu3ZhYnb4A/9p1ipePNkW8ttxU0cKZpRljriEwUqMpDh+eL7pvkEa0QVt5qU4cVgvVbbHzMm+pbGVVcXrEGEA4FTVhbmR2q8zq8/qYoh1KqRrz3waMG9sNgzapAUrC/i42lw3ez21KqXVKqXW5uaPPBeiyW/n9O9dy3arCqNuUZLnj6pnZXNHC2tLI+ZK8/iC/fu7oqNupjY/tJ1v56F+309UbpN3r5113bubuV06w9UQrTltiAnuD5aW5WGrmsr30jHyuWDaHd51dNh0DyynAg8AnlVIdGNPo52Pkcq0FfhzlcbeIyFYR2drY2Bhpk3GjEpGQDdh0vIUlc1IjrvvWo/vZUtESdSTvYHarhbVzM4ek2QCjcnW0nI8jVdnczYK8FNLcNtq6/disFg7VeThQ6+m/WMhKcpDqPP18sUYu2q1CdrKTzRUt1EfJI3XholxdzHSKUkq1Ac8BZwMZItLXcRzxnGs+JiHnXW14NW1e3vz71/DEmEo33IyqSBRGp1EkZxSkcesleobVFNSXimopcBbwURFZyukiRAuBZ8y/tQS4aHEen7l8EVcun9N/bbajqo0tla00eHpRqCEFvg+c6mBHVRsH6zqpbx/YgTPWWUhWi7CiKJ3rVhXO6htQTRvs+48fHHIsjtbBug7OLM0Y1WOdNgtnlmZQ2dzN5oqW/pHCI5Hutk94YLnPaNo7gzwC3Gz+fjPwzwjbPAFcLiKZIpIJXG4um1Ee2FrFlx7aw6O7oycM2FPTzvI4avIkSqrTSnOEmXjDiTSbwRIlzVuy00Z1m5dVxeksyo9d5+T4MKnq+uq0jYQ/qDjVPvaCg9PVqCNuIpJs5mhFRJIxDsy9gzZ7BHiXGM4C2hOdb3mwVJed8xbkEC2t4Jw0V/90cLtV2FCexYayTBbPSWWBWRxn3dxMlhak0ukLsLwoLeI08KMNY6tiqyXWU/vrufG3r/DfQ41YRfifdcUDAspt3eMz1eNAbQdf/cc+6jq8HKn3EJikvM5jISJ2jMDyPUqphwCUUvVKqaBSKgTcztCOI8ztJi1AlajcoRvKs/jxm1cNSdrfZ3lROtYRBFVTXXZuvXgBLvvAr9cTLd0kO20UpI99xkOjx8fRhk7sFgvNXb2EBgXad1S1kZfmpCcQYqNZzKS7d2jwym4V1s7NxGWzsGuYaX6XLNFV7KcSEck1RywjIm7gMuAARpD5RnOzaBfW2gRRSvHpv++kKcrFdN93y5w4vhc2lGVx04YSlhWmcfa8bD5z2SI+evF8Hv3Yefz74+fxyhcv4elPX8ANa4q44+Z1OhXGFKSUqlVKbTd/92Acs0XEV4RIG6V3nV3GOfNzWJyfim3Q+XxLZSsL8wbegPaETZOtafOS5jo90XMsada+/YblPPyRc3jk1nN56wY9Y0TT+tz1SgXtXj8ritKNARLJY0vB1u4NsP1kG+U5yawuzmClud/1ZZnDpoxYVTK20ZwiRnqdyfKW9SXDbzQDiMi9wKvAYhGpFpH3Ad8HLhORI8DrzL8RkXUicgeAUqoF+Bawxfz5prlsxmjujK8onz+o2Huqg7wEFMmLh8cXHPEAvBVFaZxqGzpLb0dV25DBYRYxUuIA7Kpu53B9J4vyU1hZnD7k8caMJVhVMnTdnDQXG8uzaO3qZd+pkaXEAKMA92w1lrQY+cDDZoDHBvxVKfUfEfkQgFLqd8BjwNXAUYy52O8ZW3Pjk+S0Rq0ym+ywsbY0g+auXnJSjJF66W477V4/yQ4rqU4bWwcV3Vo3N3PIsqrWxBUG0OJT3dpNRVMXG8uzcQwaiVyek0RfZ/eheg+rSzI4oyCNnVVtFGa4xrUz4O9bq9hS2cz1q4u4aHEeq6IEKaciMQ7gPwAHlFI/CVseXnjzBoZ2HM0YJVlJ1Hf0cN2qAs5dkM2vnzs2YH2a286J5i6sFqE4M76qrwvzU3nqUxfys6ePcLypkx3mRWqDx8fywjRq2+NLzRPNKvMkWdveQ7rbjn1Qyg2l6C/csKmihfm5yRFH78/PTeFUWzce3/D57c6dnzOmNmsJVwDcbeZdtgD3KaUeFZH9wN9E5NvADozjW5skf3y5sn9qrogxg2BOmpMMtwMEdpxsoyTLTVOUGQNvWVfCsqI08lKdXLm8oH+5UipqB9tP37I64a9DS7xBqajiKUKkjZLFIly7qoBuX4DcVCfNXT5ePdbcf904uDM4nMLo/OnoMa4jB+dHtkrsNBl2q/Dbt6+lqrWbq5bPIduswaFzomqa4V+7TvGNf+3vv3dfX5ZJS1d8g4IsYhTaLMlMoicQxB8IcTSs6Gb4KF6XzUJxppvSLDf5aS6ON3UNSRdwRkEqOwcVOhsppeBki5cNZVkTPnp5QV4Kb984OzqulFI3RVl1aYRttwLvD/v7TuDOcWrapFJKcefLFTywrTrux/REKeQ+HiTuctSGaDUJgiFFdauX1SUZOG0WFODtDQ7pGDpcb5y7lxWmEQiGSHcbwe39p9rp6g1yuLaDnBQHgZDC2xsgGFKIMKq0OgvzUrhi2RxSXbO3PtGor2yUUseBVRGW/y7sdwV8dLTPMVqxiqd19Pj7P3SV5gmlL01GV2/kAysQUizpz1dqGBzM0cafUvDOP2xmyZxU/vie9RSku/vXZSY5+nNkP7GvjtUlGfQNTrFaZITZckbueFM3D++o4URzNxctzuWalYXTJYXAucA7gT0istNc9mXgJhFZjXFfVQl8cDIaN1Hy01xcv7qIHn+QBXmp/ODxg/25TO/ddJKvvP4MfvHMEW65YD5HGzpZEaEHdLCSrCS+c8Nyfvf8sf7gMhhT9TaWZ3Gq3UthuntEJy+LwNq5p/Mt94m1j6xkOw0eH6GQIs1to8N7egTzwToPywrTqG2PPUUpK9lBeoRUH9rkUUrtxghMDV5+nCgzDbSJdceLx/nOYwdw2S0syk/lSL0HK1DR1E147vOqlqHT5wrTXXzvTSu5cFHkGSGJmrmhTY7BqajC/z9jFSHSudJHL9Vl5w1nFnHF8jlUNHWxoSyL3/z3GL5AiD01Hf0DTSIJn6kv5o8CijPcuBxWMpPs/efl8P0kOayUZCbxuqW6r0DTInnlaBOfuW9Xf2A5K8kx5Bo3kvKcZLKTHXT3Btlf20FTpzFSeH1ZJjQOTQths0BxVlL/YKO+Ip7nLsimubOX7t4ArV29HKgd+SjFaE62dlOY4Yo46rKvTdnJTho7fSQoGwi9gRAhZXR6abPTvlMdQwZKDWdJfhoKFdexNxZz0pzsqBrZc5xq85LssEaM03X6AuyMs8DmvlMdlGYlcah+4D2zN6Dwdg6caZCX6qStuxevP76ZSm67lW9ev4z/WTc7Zg3EMiO7zf+581TUdd29QSzCiL7Ed1a1UZQxcMpqTauXTl9AjzyYQH2jxQ/WeXhgazUfu3Rh/7rsFCc3rCnioe01PLmvjkX5KdxywTw+9JftVLV4+wv6Xb+6kBePNFGQ7mJpQRpWi/D3rVW86cxijtR7CCqFUtDU6UMQ3A5rf6+3w2rhh/+zkh89eWhAMMBqEVYVp5OV7OTCxblcu6pw2tz4K6VegohdiI9NdFsmW99oohsyk7hiWT4/e/oIt71wnDteqmBTRQtHGzp56WgTn78i7pppuOxWPnHpQpbMSeXLD++lpauXQOh0MLim1cu8nGSOx5EfLc1lY2520ohP/HOzk/uD28UZ7gHBZYBgaPgTZ0mme9htNE077f6tVXz3sQMUZbgJhkJxF5R12Cy8+5wybrlgXsyOcm36ipSKiviKEE3r4kJTQd8xVZzpZmlBKi8daWKLOTOxPCeJnVVDj9Nkh5WqltOdQVtPtLJkTirVLd1kJtvZU9NhpNkrM1JQ3X7zOp7aX0+qy8aFi3L1YBRNi2J3dRu3/HnbgFQz5TnJ+BtCOG0W8tNcpDht9PiDHKzzsDAvhWSnDU9PgP21HRFzC0e7vz9zbhabIwzEONncTVXr+ORHrWvvYXlRWn+sINlp60/LEwgqDtR1UO/xsbwojaP1nQPS8YyG02Zh3dxMmrt85KWOPQWfNj3NzY5vlm24zZUtWC3C3Cw3JyIMeEiUug4fZ5Zm0BsI4bJbsVqEg3UeunsDrCnJZE9N+5D8ylWtXtbOzewvrDsW8aYv3VXdTprLRlayg5oonUPhFuan6MCyaUZGRuebuZMjOVjnoSw7qX/Ucrzcg4bkux3WIXlOtfEVnpD+lWPN5Ke5eLOZV6rHH+S5g8a92LHGLj71912EDxx22iycvzCHH964isrmLgrSXaS67Cil+OjFCyjJivxF3OMP8vvnj/PTpw8jYlwofO+GFTx/uJGqFi/vO7+cZYVpUadsaNNTksPGl68+g7LsZL788B721Bg3nFsqW/nBfw5yzwc2xl2IR0S4cnkBZ5Zm8tbbX+N42IiKkDJGBccTXC7JSmJPzfD5s/rYrcKywvQBo6YLMlxDqufG0xEy3QpUatpkUErx2vEWfvb04f4OpOoR3LQWpru48z3rWTJn9uZqm+mipaLidBGi76NzpY+73mCInVXtJLtsLClI5WCtJ2oQuMcf5NyFufT4g4RCiiSzMG+q08qWE22Akbdyd00bz332ItLddm5cWzxRL0XTpqWXjjTxwT9vHTIacZuZksID/aORAewWYd+pDtaVZdITobhXn0jFvudmudlXE7mD1+MLsDA/hSP145M+cW8c1+17azpYkJdCly8w6rR5OSkO7nn/WVGL/GqzR6ROlD6xBlgGQ4oTLV4W5qdQ2dhFSVZSXPensawpzTAL4gm7q9oIKkVTZy8nzQ7b5YVpdPb4yU11srmyhfVlQ2fnQuzUVSPR4PGRkWSPqxZXR0+ARfmpcQWXtdNmZETsmpWFnGzp5k+vnoi4PslhxW6V/sJ+wxGMPE05KQ6aOntZU5LB1SsKSJvF+VQm2r92neKvm072//3q8WZeq2imPDeZ9WVZ7Kpqo3XQF0X4l+d5C3L4xOsWAbAo//SJV0SiBpbBHHn6uoVcsiSPBk8POSkOdlW3866zy2I+TpsZ3raxFJfdwncfO9hfkGvriVaeO9gwIP9pPPLSXHznDSt42x2vDcgJH2/6lJF0Zs3LSTZvntsGLPf0nB61PCfNRU6Kg5Nx5I/PnaBCD5o2XVW1dPORe7b3d0SN1C0XzOPWSxbo64qZL1oqqu8D95kFiU4Ab56c5s0ONouF+7ZWkZnkoMFMgbWlsnVIagybRchOcdDtC/TXXjmz1Cj2tcEsltsnFMLIpa5pWkyP7DrFZ+7bGfd9OIDfvKnrCzxFG8nY0tXLssI0qlu9dPT4cVgtMUditnX7WZSXypqSdHZEmLkwUY42dGK3CuluOy67BV8gxPycFMQC/kCIXVFmP20oz+L1Kwq4blUhmXogyKzW7vXjtFm4d/PJiOvn5yZT1epldXFGzFzggaAizW3neFMXSwvSqG33DomxxCsQVP2DnBbmpZDqsg3IiXyozkNQGSOaAY6ZaWs2lmehlGJ3TTtOm5Vtla1sLM8aVR7kAe0JKRbkpgyppRZNS5yFOT9y0fyxNGtGmZHB5TnpLr541RKONnTyyrHmIev313ooynRTE+eIIgXsPWVOeyvPIqSU2QujTYQj9R6++ODuIcuVgnfcsYkvXLmEXzx7JOY+VhZnjKkNRo5dI8/uqpLMMe1Lm17eeGYxV68o4AN/2sqLR5oA+PA92/naNUt597nlI9rX2fOz+eVNa/jE33YSNC+UD9R2MD83mWMRcsT1KctOoqUzvhPcmtIMdlW1ReyZDg8ul2YnxezdDueyxzdKW9Nmo0N1Ht515ybqO2LnLo/l5nPKdGB5FoiRigoiFCHSxofVInzp6jN4429e5rpVhf35Vxflp/QHr0oy3QRCitr2ngHH9smWbvJTnZxoHnjOXlWSjk3fG2haTH98uYJv/Gv/qB9fmuUmJ8VJIEpKt8Ezk31xpJroC7StLc3sHzk9GfxBRbvXT7sZnuhry9q5mf0D3MLduLaYH964ctqkYtTGz5cf3sOD26oJhFT//WU4h9lxcayxi20nW1lflklrt5/6jh56/MEBHT3h6Wb213awpjSDokCI9h5/xBohsYR/NI80DJ0d4B/U1pZuP2tKM/qDyCuK0lDKiMPtqj7dqdvS6RtQuHMkLCM4Xo43drFkTiqH6jwx63fpNHanzcjgMsCvnzsaMbDcZzS5kv1BxeaKFtbNzaQoU49anQjbTrTwgT9ti1ps0RcI8c1HY1+krCpO57yFOePRPG2WcNmtfPP65Vz8o/8CRsdGtFEEw+mbWfF//zkEGAHfM+akxQwu56Y6h821nJPiIN1tjxpYBujqDZCRZKcsO5n9IxhhmatPmpoW0ak2L2+/47UhN32apk1dwZDit/89yh/evZ4Or5+XjzVztKGTLZWt/anzspIdEc/zxgxGY5RjXz0PgKUFaTq/8gwnIpUYGRuCQEAptU5EfghcC/QCx4D3KKXaJq2RU5QvEOR7jx3krlcqx7Qfb2+I7l4jB3Mi2a1Cu7eXgnQnIhK1CN9k6BuhXZDu4mMXLyA3zUVWsp3VJZk6sKwBRrG6SB0pAqwvy+JYY2f/iOFg6HThvoV5KVS1dOOPETrtG3lstworitI51ealuSu+a95Yn86sZActEfYTns4xPB1kjz/E5ooWXHYLOcmjuy+1WoSeQPS0OpFUNnfhsAm+QPT3SAeXT5uxV0Efu2Qh//v6M1hZnM6SOSn9y8tzjHzMmUmjHyF0uN7D2rl69Op4Ukrx4LZqbrp9U8QvnpE42tA5ol4qTYukPCeZMrNIwvKiND5w/rxR7+u955bzzrPm9v+9ubKF1SXpZCc7iJQlo6Zt+J7ikDLyjccqVtrW7cfnD3G0oZPiEaR1ida5o2mz1bGGTr772AGu+eVLOrCsadOM1SJ87JKFLMxL4aLFebxtQ2n/OhFhyZxU9sbogBUxCvhVtXT3j6Rq8Ix+5oI2rVyslFqtlFpn/v0UsFwptRI4DHxp8po2NZ1s7uZ/fvfqmAPLAI2dPkCxpiSDRN7aFWe6yUpxkuy0UzzFBpCJGPcdt79rHW87ay6XLc1n7dwsrHGm1dNmti5fgIrG06OCHVYhL9XJGQWplOUksbmyJWIwOMVpo7bNG3chSX9QsaemHZfd2l/AFoyit9HE6vwoHUV60WSHlfxU55D6QbFYxEgJsqE8k9wUR9wFtvusLEqPGVjOSnZQmKEL3/eZsSOXXXYr7z9/HiGl+MlTh1mQl0KG286Rhk42lp++IIx3Wng4h806qpHPWvz2nergM/fvSsi+zlmQo0/AWkJ86rJFHK738PFLF8Zd0C8SYyT0MgD+/JqRG95utdDc1UtOioOMJAdHw6YPNcYx3d7rD5Lqsg1IfRFtO6C/KFE8dBogbbbrq1Z/uN7DfVuqqG710tLlo3cEOSM1TZs6wutmXLOqgN+/cIz6Dh+F6S56gyHOKEhj76nIxbj6RoBlJdnZXNHCnTev45Iz8iei2doUo5R6MuzP14AbJ6stU9F/9tbxuQd2DXttGi+7RXDbbewYVFNkrCqauqloMlJqrC+bWgPIVhZncP8Hz8Zhm7FjArUx6PEH6TCPr9IsNyBUtXYP2+GplKI3zsByuJo2LzVtXjKT7CiMgUvLClPpDRi5msNzocfqABrNRJ+CDPeA++PhuB1WcpIdHGvsijlDOJZYA7yKMtz893MX6VlLYWZ8hPSWC+aT4rTz5Yf39C/ry+NS09bTP/1tJJo6ffz6uaN86rJFCW2rZujo8fOpv+9M3P68o0tCr2mDXb+6KGH7EhG+ef0yclOd/OSpw/jNXtGmzl5yU53kpzmp7/AhYuSkWjc3k0N1Hjy+yBfo3t4gy4uMIibxVMH1BUKsKUmnzRugpctHuzfyfh1WC29YXTj6F6pp01AwpPjJU4fYWtlKu9fPiebu/o6ZPqPtoNY0bWrJS3Xx+hWF3PlyBc1dvRys8+CyWSjJcsfMMZmR5KDN6+fzD+7h52+1cu4CnYJthlPAkyKigN8rpW4btP69wN8nvllTT1t3Lz97+khCRiuHy0x2YLEIhekuTrVHT11RmpVEbbt3REUD+xxr7GJOmrO/yNhk21XVxspvPMHZ87K5dlUhVy0vwD2CASLazJaR5GBBbgpZKXb2VHcMuVaNpqs3yLq5mXEXtxssvMhfssPOvlMtOG0WUp1WPD6jDdFiyyWZ7hGPIAZjNnp2siOutBwuu4VFeSmjTmMJRnB68D21CHzr+uWkumxcsiRPB5YHmfHBZYA3nlnEH146PqTHIsVhHXFguc8T++r45OsW6lxHCRYKKX7y5OGISd9Ha39tB929AZIcs+Ljrk0jIsLHL11IVUs3lWHFgbp9ASwipDhtzM9NZld1OxaLsHhOKltPtEYsAOiyWdhbYxQHLEh30dEToDjDHbWy7r6wEVnzcpPx+UP9U6NsFrBZLKS4bEb14Sle0K83EOJQnccsvKlpY/fAtip+/dyxmNv44ryA1zRt6nvdGXnc+XJF/+jAnkCIwvTYwWWPL0BIGYNOHtxerYPLM995SqkaEckDnhKRg0qpFwBE5CtAALgn0gNF5BbgFoDS0tJIm0xr3t4g1/zyRbKSHfgCIQ7WeUY1KnI4DR4fSQ4rQXU6aOywWVhWkIbFAlaLhSP1Hk62dLMgL5kef4hTbV5KspLITjZmBXb0BCjLTiI31UmPP4TbYcUfDOGwWqjv6KGyuZtkh5XCDNeUyb3c4w/x3KFGnjvUyM+fOcKDHz5H53nVAAiEQtS2eznaOPLYSW17D3aLDCmsF0mKw0p5bgqBUIgDtQNznvcGjWPdFwixtCCjf2bB4LSkhRkuSjKT2F/bMaqOHzAK0hvfM0Gykx3YrVYqm7sGjNRelJ9CS1fv2ALLdiuF6a4h99vpbjuXLMnTqTCimBXRNpfdyu/fuY53/WHTgF7O3mCIdLed9lGMbF07VyfRTzSlFL/579GE93J/7orFOrCsTWlnFKRx/7bq/r9PhN3MZiU7WF+WiVIKfyiEw2ahtau3f9RkVpKdhfmpVDR1sSonmV1Vbf1B4rwUR1zPf7yxCxGjsEOnL0Cay0YgqGju7uXM0kwO1HZMuRx04Rw2C4UZrsluhjZD/HNnDV94cE/U9flpTjLckYt9jcaHLpxPVlJ8x6qmaeNjbk4ydqvQHVZjIBA8HRxLcdroHDRzqK27F7tV8AcVaa7R13LRpgelVI35b4OIPAxsAF4QkXcD1wCXKqUiRkzMUc63Aaxbt27G5VNyO6xsKM/i3s1V4/5clc3dpLttrJ2biVWEiqauiGkyjjZ0saY0g+pWLyeauznR3I1VjKnslc3dUQeYleckk5vqpD7GyOjJ9Loz8keU2k6b2f57qHHUtXFq2rwDCtPGUp6bzB6zFsGcNBf56U7sFgsWEQ7Vnw42VzZ3sbQgjf21HTR5fKwoSiMjyc7emg5OtfWMucMmvODfSfN+2WYRNpZnUdveQ36akz3V7XHnko5mUf7QUc//s7aYL161hGzdsRPVrIm4LchL4advWc1bbnsNMPKkpbrs+AJB1pTkcqSxk1NtXiJfEgxV3Rp/InEtPq8ca+ZHTx5O+H7Pnped8H1qWiIVZUbv/TxU7+FUWw82i3FBvCgvxcgDaX5XLchL7R+d3ODxDZjiZB9BXmil6J8xUNtudKAda+piU0ULZ83L4rKlc0b56iaGPtFrifLo7tqo65w2C3aLZcCF9FglOax6iqumTbKiDDcritKxhU1xrW71sqIoHYfNQl17D73BUP9ozEX5KQSCisJ0F4cbOvnblpNcuDiXixfnTdZL0MaRiCQDFqWUx/z9cuCbInIl8HngQqXU6KbDzhA3n1M2IcFlgHZvYEBu10gW5aewb1BhzqAavkh2RVMXFU2jy886nmxmIdKPX7rg/7N33+GRXFXCh3+no9TKOWukydEz4wnOOWKDjcEYA4ttkoEFFpYcdkm7S477EU1Yk4wDYDC2Mc45TM45aEY559Dxfn9US9PKWd2Szvs8etSqru66Jel2VZ269xwd4Kb6JMzAADqbQGNE8eqath5q2oYOEjd3+fEGQhSlxyM2YW9lG+uLUvql0ZgqS3MS8QVCZCfFUd7cRVVLD6ebJv8xPFzau6wkt15vjmLeBJcBVuYn9xW8yk6Ow24TTlV1UZwRoL6th+xENwsyEmjp9nGkduSpBdMx1Wc+MsZwsLqdpw7WTvmI5V5jmOmhVFStyE3G7bDhHeJzxeOy931unWrqJicpxPqiVA5Wt5GV6GZn+ZmTa7fDhgicVZiCwyZUjaOabqT1xansiDhpf/5IPR+8dDFxMZ4eQ6nJOlTTxpMHa4d9flV+cl8xr6miBYKVig0LsxL7Baxq273YbVDVak23Pac0ve9m7tKcJB7fX8OJhk42laSxtayZd9+9lT994Hw2LIitgmBqSuQAD4aDeg7gHmPMYyJyDHBjpckAeNUY84HoNTN69k7RbJ6p0tAevaK7Dpvw6WuXYRPhntdOc2KMwWoR65pgbVEq64pSWJiViNNuw2ETCtPiSdVZTmqABRmTm1m6p6J11BoiIQM2m4xah6BXly9IsM3bd11rs008L3G8y073MCOzy5u7iXfYJpzmdigj/S60qObo5tUVzYtHG1hflMrzRxs4VtfO8tzk8DOCL2iobfdS2+4lzmFjTUFK39D/oWSMcbq56s8YQ1ljFy8da+CVE43sPNU8YkGGiVqem8SSnCQWZyWyNCdxyt9fqYk63dhFeqKrX0CpOMPD+y5ayI+eOTZo/WN1nf1GIxdneNhaZj3u9gc4pzQDf8jQ2u0nwWXve259UQptPX7WFqbgdtrZcrIJu01IiXfSNEohBKfNRuTpeEVzN6+eaOTsBWk69VfNaV979NCIM5i8gcnnWU5yO0hLcNHtDxLnHPqmklJqZlW2dPPgzkqCA0Yk2MRGnNNGjz/E6aYu7DYhGDIsyU5iYWYCP3/+RN8gBmPg3/64k3vvPJei9NhNJaXGzxhzAlg7xPLFUWhOTKlq6cbtsHHzhkJauvz8z6MHo9KOorR4spLc2EQ43dTVLwfrTFqSnUhhWjzPHannQ5ct5omPX8Ku8mbq273UtXv51mOH+1LsvGl9AQ2dPqpaujm7OJU7L17I4uykqLRbzU4jxavG6lhdO6UZHvxBQ1aSG6fDRmOHl9ONnfjDp6iZiW5SPc4xBZeBfue2kTXvUuIdBIOGDl+QlHjHsAXlSzMTqG3tpssXZElOImkeFz2+IL6gldMdrMGeWYkumqZoVPSirIQRg+xvPrtwSrYzl004uCwiRcBvse7kGuAuY8wPB6xzKfA34GR40V+MMV+d6DYnK95l5/mjDQAEQmC3CQWpcYPutPYEQuytbGXDgjT2VbYOeeFXN0wF2VDIUN/hJSdZ838GgiGO13dS3tRFS7efLScbeelY46jTkSZrQYaHe953LukJegNAxZ60BCeHqttYV5Tab/rthy9fTGKcg2/849Cg1/SehJZmJlAekZInEIL2ngB7BpxY2MTK29zWHejLF7WmIBmPy8HWsiZW5SfT7QtiswnH6jpYlZ+MJyIwPVB9h4+yhk4qmrv5l3MXTPp3MBP8wRCP7q3m4T3V+AIhjtd3sKkknbWFKZRmJoLA9584wt3v2qQjQRRg5U999UTjsM8vyU5kf9XQ6TCK0uO5YnkOi7MT6fEH2VfZyiN7qwcVLHnXBSV85trlOgtAqRiz/VTzoMAyQEVLd99IpurWHjaXphMyhg6vn49ftYyfPX8Ch+3MFPXKlm5u+/UWfv7ODSzN0SCRmpse31/DUwfr2F/dyv6qNoyxikPP5ACEhVkJZCa4EYFgyOBy2Hj5+PDH8IFsAvmp8RhjFRoLhgw2m2B1Z6tPH6/roHGUARnZSW4uWZpFSWYC16/JoyQzoe+5UPg9NyxI71t223kllDd18b0njvChyxezKEsHQamJq2zpYuOCtAndUCnNTKCsoRNfIITH7WB/VRsV4ThNUpyDrKQ4kuKcpMQ72VneTKLbMeoAzKF0+4JsKkmjucvPsboz2QHaewK47UJJZgIp8S4aOr2UNXQSMtasvpPhyPbRARkFzi5Opb0nQDBkxjwrYCzKm7tJ9TitzwKhX+DbZbcNeY6g+pvMyOUA8AljzA4RSQK2i8gTxpgDA9Z7wRjz+klsZ8qcU5rB/71rEx/8/XZ6/CFqWnuoHaET7i5vZllOMl3+4KDcS1vKmrh/Wzm3bCzqt/x0Uxf3bi3ns69bPi37EOv2V7WyIjeZX790kh8+eZR279B3o6bT+YsyNbCsYlZSnJOzi9Po9gf7BZfjnHYuW5Y9ZHD5aG07+alxZCW5++6oJrjsLA7nfBzIbhOS4hz9RijvrWzre7y/ynq8riiFrEQ3+6vaWJSVQGmGh5ONXbidg6f9fPufh/nBresnvuPTxBjDkdoODtW0UdHcTXlTFycbOtlb2dqvMBNARXMlD+6sJDvJ3XcC9u/37eIXt23s97dQ89PfwzcihpIc58AfHPq5+99/HptL0wct/9x1K9hW1sxZhSm8fLyB/NR4LlqSNaVtVkpNjUdHyLXuC1/gZkccg79w3QriXXbOKrBmCUU62dDJjlPNGlxWc9Zj+2pIjndy+bJsPn3Ncpq7fPzwyaPsGqKw3lRZXZCM02YjZAzd/iBHajs4UX/m+jwjwcXGBWnsrWwhFAL/KIGgdUWpfWmuhhv4tCgrgeIMDweqWvEGhn6/7GQ3H7l8CcVDpCew2YbOjVyU7uH7b103YvvUxIjIMuC+iEULgS8aY34Qsc6lxNAAyMmwi7DtVDObS9MIhMyos1MBktx2FmYlcqC6jbMXpFHZ3N13bQgQ77Thdtis2eURM8ybu/wsyh7/9VJ7T6DfdWivkIG81HgORwSP0zxOlmQncrq5u9/1WqSD1e0szk4g3ukgM8mNMYaK5m6qJzkb3hcIsTw3iR5/kG5fEKfdRkM41/QXrl/R78aRGtqEg8vGmGqgOvy4XUQOAgXAwOByzIh3WcGb792yju89cYQEl33E4PKq/BR2V7SSlegmPcE1qLN+9s976PYFuWJFNoVp1gGlIC2efzm3eFr3I5b98MmjFKZ5+PVLJ0dfeZqsKUiJ2raVGgubTUgYIs9qIDQ4eOW0C2keF1UtPdS09rAiL4kkt5Nuf4Dd5YPvHC/KSqCqtYdTI+SfSvM4yUmOo67dS32HVck3zmlnf2UrCzMTeO1EIyvzkgHDgWprpGanL8ih6jauWpkz8R2fYs8cruMnzxwbdsT1UNITnP1OVI7Udmhe9nnOGMPjB2r51mODb+wAxDvtpHmcw+Z0O1LbPmRwOSc5juvPygPgrenz97xAqVjX3uNnT0ULLodtyBtMTocVIMpPjaely8+/XraI9cVWXuVPX7ucL/9tH9esyuHFow10hm9qPnmwjls3a79Xc9P3hgiMXro0myu//xz105COYnNJOlvKhp+uDtDY6esbZexy2NhUnDrs+eGaguR+wbThHA8Hr5PiHKwtSiYQDBEMGYLGkOZx4g0Ydpxq4k/by/n41cvGuVdqOhhjDgPrAETEDlQCDw6xaswMgJyMq1fl8tWHD9LpDbIkO7GvLsBISrMS+2a2DlUYMzvJzalh0l9sK2tmbWEKCW4Hde3efiORhzNSTuSBN2Cau/xsKWvG47ThHmaWX7c/OChYHee0sbYwpW+/JmpPxOvXFKTQ0OHjnNJ0bjtvdszcjbYpybksIiXAeuC1IZ4+T0R2A1XAJ40x+6dim5Nx3Zo8rluTx77KFt7xyy20dg+dp6X3H7q+w0tOkpvNJel4A9ZUcpfdxvZTzfz2lTJ+8OQRnv3kZaR4nDjttr5A83yUkehid0VLVNvw42eO4bQLbxkwqlypWFbb1sMHf7+DswpTcNlt9ASsu6a+QKgvFUbIWHdrh+N2CF2+4LCFDxZlJZDmcWG3Sd/Jh8Nm5cXqPUj3Ti+qa+8hNb7/9Mb/e7mM284vISU++nmXt59q4l3/t3Xcr+v2hXA7pG8EylUrc7RAwzx2sqGTrz16kCcOjFDEryCZbcNcoL7rghLecY4GkJSazV442kBVa8+w033r271cuiyLdUWp/PmD52OPuBjeVJLGpnChv/REF9Lho8MX5MmDtTy0u4rUeCcXL9UZC2p2Olrbzj1bTnOqsYv6di9NnT4K0+JJcDtw2ASXw8b64jRuO28BKR4nly7N4oHtFVO2/US3g8VZiaMGlgfyBUL4gyHOKU0naAzBkMEXCNHjD9LS5R9yFOVI2nsCg3KxJsc5SHA7WJiVyJrCFE43dg05ellF1RXAcWPMqWg3ZLq0hVM37K9qG/MAu/hRUrPFu4YPES7OTuREQyftPQFW5iVjEyY1SKe9Z+hZ7l3+EF3+sdck6fGHOFzbztKcRI7Ujh7wHovDtdY19zkLMwgXbFWjmHRwWUQSgT8DHzPGDPyk3gEsMMZ0iMh1wF+BJUO8x53AnQDFxTN3kba6IJX/fP1Kvv7oQUoyPfgCIew2K5+K2yF0RqR06C32F6kwLZ5A0NDc5WfbqSauWBE7I/qiobypi25/iNJMz5B3wWbKOaXpnLswI2rbn02Gy50uIulYU4pKgDLgFmNM9P6o88DJhk7OW5TBA9vK+w7SboeNJdmJ/fIsj6QozTPi3eH0BNegURyrClIGjYCOd9mxi9Dc5WddYQouh40tZc00dfp4cEcFd1xQOr6dmwYvHRt7Xr1Iq/KT+4ojFqXH8+HL530tnnmpKpwXdSwjLoZLh7GuKJXPX7dCTziVmuVO1HdQmulhc2ka9e1eunwBjIFOX4CkOCe3n1/CG9bmk5noHvRaEeH9lyzklRONJLmdZCe62R6eav+/Tx3l7ndtmuG9UWrqfP/JIzy6twaA/JQ4EuMcg0ZGPrynmsf2VfOzf9nAf71xNTdvKGR/VRvPHK7jhXCto6GcXZyK024jEDJ0egP0+IPEOe0kxzno8gU53dxFtzfIrgkOWto1xOy+qdTWE6CtJ0B1K/zihRNsLWvmD+85h/MXZ07rdtW43Ar8cZjnYm4A5ESUZHooSo+nvKkbmw1EGLEwNcDeihbyUuKGTSNxvK6DpDjHkIHfJLedY+Hlpxo7OXdhBvur2oYdrDmajilModrjD3GqsYvC1Pi+3NGT4QuEKE73sL4odfKNmycmFVwWESdWYPkPxpi/DHw+MthsjHlURH4iIpnGmIYB690F3AWwcePGGZ2g/OazC7h2VQ6f+cteHonIt7apJG3U6TIVEQGfj9+/m0f+7cJ5PWr5E/fvxjC2XD/T5cdvP5vr1uTqxf7YDZk7HbgDeMoY8w0R+SzwWeAzUWznnNbjD+INhHDapd/dX28gxL4xTNvrVdXSTWaSm5phThYGFhc7pzSdo3WDR0Kvzk/meF0H8W5rVMaeylbWF6Wys7yFHz51lHMWZrAiL3nM7ZoOh2vaWJKdyMmGTgKj3DJ32ISQMWwsSWdnOLC8uiCZ792yjj+8epoPXbZIcy7PI4/ureZj9+7CN0zQeKB9lW0kuOx90917ffPNZ+HU/xulZr3NpRkkxzk5Xt9BaVYCwaChuq0bA9ywNp93jXJDNT3BjdNuIxgKsf20dcxekZfMwx+5sN8oZ6Vmm09ds5zzFmbgtNt43eo8PG47W0428bddldy/7cwI5a1lzVz6nWdZV5TKm88upLHTS12bF6ddBp17uh021hamjns0ciw7Ud9JRoKL6taeviJ+KrpExAXcAHxuiKdjegDkeHhcDjYuSKe8qZLd5a1sKklja1kzKfFOspPcuBw2XHYbOyPyoXf5Q6xIjR82uOwPGc4rSqEnYDDG4A2E2FPRSrzTztGIQRkr85N5+Xgj54RTwx2qaR93kLnbF2RzaRpbTk7NGDZvIET+FAWX7Tbhs69bzmXLs6egZfPDhIPLYkXvfgUcNMZ8b5h1coFaY4wRkc2ADZjYcLNpIiIkxjn54VvXsTAzgd++corWbv+owYqBWrv9PHOojneeVzI9DZ0FvIHgpPPcTNTy3CR+fccm8lLiNLA8DiPkTr8RuDS82m+AZ9Hg8rR5+lAd//qHHRN+/ar8ZBJcDnzBIP6goaa1h40laRyqbu93R/hIbTtFafGUN3eT5nFwoqGTps7BJwEVzdZFdUFKHC+FTxq2n2rCabNGM//LL1/jgQ+cx8IoVriuau3haF0HBalxdHiDw57MJLkdLMlJZFd5S9+UxninnZ++YwNVLd1sWJCmgeV55rUTjWMOLINVhX55bjL1HV5cdhtv3lDImoIUluVqsS41PiLya+D1QJ0xZnV42ZeB9wH14dU+b4x5NDotnJ82l6ZzdnEq3kCQ7adaCBlDY4ePHaeb+Y/Xrxj19XFOO3devJC7Xy7rW5ad5NbAspr1SjMTKB1QxOqCxZmcF54h+tddVX15yr2BEPXtXgyGfZWtiBjWFaVhMNgQgiFDm9dPZVPXnAosAzR0+FhXlMoX/7aPr//jIDesLeCLb1gZ7WbNd68DdhhjBuU9mw0DIMfjxWNnmr39VDObS9Lp8QfZE5HmKSvJ3S8f+kiDAdcUpLC/qr0vh7lgzVzIS4nrm5kD4A2nreidzeBx2saUH32g3tQeU6Wpa2ryvn/k8sVctyZvSt5rvpjMyOULgHcCe0VkV3jZ54FiAGPMz4CbgQ+KSADoBm41ZrSB+tHhsNv4xNXL+NBli/n77iqeO1LPzojOMxa/fPEkb9tcPOsDFf5gaEKjsW5aX4A3EOJQzfA5YadLdnIc+anxM77duWRA7vSccOAZoAYrbYaaJtetyRt3EYLcZDfF6R6qWnv6zbJI8zgpTo9nW1kzSW4HCzMTqG7rodsXpMsXZF1RPDabkJHgorXbz4J0T1+aiF7VrT3WtKrwz/sqW1lblMaRmnZW5ySy83QLt971Kn//yIXkJMdNxa9g3NrCweTKlh7WFqZwqKYd74BCTOuKUuj0Bfuqgfd630WlFKV7KEqfvzNN5qsOb4AnD9aN+3XbT1t95E1nF/DBSxdNdbPU/HE38COsdFSRvm+M+c7MN0f1cthtOOy2fvmR37yhcMyvL0yLp6qlmyS3nXZvUGc1qFnLGEOXz7pp39rtp6XL+t4W/jnOaePa1Xl86+a1/NcbV3O6sYuUeCct3X72VrTiC4S4fHk2pxq7yUl286Nnjg2bV3Uu2VXewlmFKeypaCXOqf0/BryNYVJizIYBkOORkeDqCxyHDEMGd3OSzwSXHTaoaB4+jaLbYesLLIN1PVjV2kNVxEhnp12oaes/8rnLH2Ln6WYWZSWQkegelKd8OMlTWMvHYRMaOiY/i95uE1bljy2HtTpjwsFlY8yLWDcyRlrnR1gn0bNGnNPOWzYWcfXKXI7Uto8rIfipxi7ufrmM9160cBpbOL38wRB/ePXUuHOqGmO4++WyEfO9TqdXjzfy991VvGFtflS2P9sNzJ0eOfo7fOAd8qbQbJguNFvccUEJ/37f7jGv7w8aAiGDe0AxuuYuP81dVuC1wxugyxdgY0k6BoMgHK3tZEV+Es8fse5yl2ZCgsvO4uxE4px29lW20ukLYsyZO9KdviDbTzWTnmBNGwaoa/fy4Xt2cM/7zp3xi+hAMESC+8zha3dFKyvzkjhQ3U6c08bq/BS6fMFh8+0lxk1JLVs1C/2/p45SOYmpclev1PtsauKMMc+Hb+SqOcZlt1Pb5uXs4lRON3VxzSr9rFCzgzGG1042cf+2cp4/0kBLl2/UGbzfefwID3zgPJbmJLEkJ4m/767i03/aQ7e/f/ooEThvYQZby5oGpceYa1wOG3sqWlmQ7uFvu6p44/oCluboDKdoEJEE4Crg/RHLPgCzbwDkaIwxY7p5Ewj3v3innbMKUwgEDcfqO/rN/NxYkoYNocc/dGH4SKsLUoYciOkPGY7Xd9LQMfzo4cXZidS09uAPhlhbmML2KZrJ4HbYKM1MGHagY0nGyLWJIgVDhs/8eQ9riy4iOyk6A6lmI72tNowUj5M/vu9cVhckk+YZ+92Upw/VDVv8Zzb41YsnuXdrOW0948uX8+yR+qgFlgEuXprFijw9gE/EMLnTa0UkL/x8HjDkUD9jzF3GmI3GmI1ZWVoNfTJuWl/I2zYXjXn9xk4fO0639AWSh2KAoLGmK2052cxrJ5uo7/DS6T1z0nCyoZMUj5PdFa0cqG6jxx+kMC0ej9NGvMtGfMToi7yU+H5Tl7aWNfP0ofGPAp2sd929lT0DRnkfqG7nkiWZGGPYdqqZA9VD56q+/qw8btk49t9zrBKRIhF5RkQOiMh+EfloePmXRaRSRHaFv66LdltjhS8Q4uGI2grjFe+0c/lyDRipafFhEdkjIr8WkbRoN0aN36LsBHKS3DR1+Xj+U5fxljlwnFFz38vHGrj0O89y612v8pcdlTR0eMeUGnJ1QTKHatp5/kg9h2rauG5NHk9/8hJuWl+AwxY5QAVePt7IujlWEGtTSRppHier8pNYW5TCgnQP/kCIwrR4atq6qWzp5s0/eZkXjtaP/mZqyhljOo0xGcaY1ohlPwsHljHG/MgYs8oYs9YYc64x5uXotXZyOn3BQQONhtLtC7AkOwGwbibtrWyh0+tnc0k6K/KS2LggjW1lzWwpa+qXTmM4w+Vr7jXcjPJNJWkcq+tgTUEyZxWmsKWsmam677S2MLVfYHlxdv/0jTdvKOS/blxFYdros90XZibwpw+cp4HlcdLg8ggyEt08/JGLeOxjF7N2jAfFl4838uftFaOvGKNef1YeBanxXPiNp7nntdP9nnt4TxWd3gDdvsF3s144Mnw14OkW57Txy9s3sjhbg8vjNULu9IeA28OPbwf+NtNtm4/+68bVvG3z4BHgRWnx2G1C0hAjbhdnJ/Y7kR+LtgH5iataeliWk0R7TwCP244AyfEuXjvZTGlmAvbw2ye6B2//2cMzf+K849TQRR/2VLZSkjFyHuiMBBePHxiUfm026i3GuRI4F/iQiPQm+Pu+MWZd+Etzt4b96sWTkxq1fP6iDFxjOIFXapx+CiwC1mHVQPjucCuKyJ0isk1EttXXa9BiMgLBEMFx1lcZictuIzs5DruI1v5Qs0ZGonvkacjDeOlYI//2x53c9ustXPuDF1j/1cf55Qsn+dIbVrL7S1ez+4tXs/0/ruQn7zibj16xhNLMhDl1/Gzs8NHc5Wd/VTu7y1s51dSFwapZ4g1Ynyvt3gC3/3oL33/iCKEp/KxRKlKnN8CJhs5R1zvV1M3Ruk66w7NSfUFDIGSl0DhYPTi1YC+nTUhy20ly2+ntwnEOG40jjEwGSIrrPzjTYRM2l6Sztcy6httV3kpzlx+bgMs+8qdQdpKbojEEhCPrqbzvolIe+vAFFKbFkxLvJD3BxbWrc3nneSU8/6nLuHTZ8IPi3rKhkEf+7aKo1haarebOp/w0ykmO428fuoDfv+ecQUUNIqUnuAB4aHfVTDVtyhWmeViWm0RbT4D//Ns+bvjRi1zwjae59gfP89W/H+DK7z03aFTzztPNHK5tIzdKuVc1H86k9OZOv3zASMdvAFeJyFHgyvDP885QN1Kmk8Nu45NXL+2ruhvntLEsJ4kuX5CMBBehkGFdUf//921lTePKe1yamUDLgODy4qwEyho7WZyVQI8/RG1bD/Eu6/BwuLaDtUWppMQ7KG/qYuOCNLKT3H2vffJgLS1dk89tNVaHatroHObv0tzl53h9BytHmMXg9Yc4u3j2Dww0xlQbY3aEH7cDvcU41TCeOji5mwrnLcqYopYodYYxptYYEzTGhIBfAJtHWFdnC00Rh902pQX3HHYbawpTOF7fyV92zt5BJmp+WZabxBMfv4Q3rZ/c6UNbT4BfvXiSf/nVa7gdNlI8TjIS3Vy3Jo9/v2op37p5LX/70AXDDoYQsW7QDOcNa/P53i1r+fBli0kaYqDDTDvR0ElusnvU9UIGfvjUUY7WjT3NplLjMZZRy6NZW5jCkdqhU0ksyUmk3Ruk3Rtkffj6aXVByqhpbgLhQG96gotzStNZnpvULxd0tz/IyYZOMhLdlA4I4maEY2q9bDahvLmbZblJ5KcOf83b6Q2wvjiVr79pDV+4fiUel4MXP3M5u790NTv+86q+gYg2m/DuC0opGGZ09aeuWUa8yz7i/qmhRf/TeRa5cEkmT/z7xTx7uJ5P/Wn3oOno64pSqW3rYVtZM+09/kF3bGaLfzl3AY8fqOVYXcegqecAF37zaTaVpHP58mx6/EFSPC5eOja2HPhOu7CuKJW3birGGEOnN4DH7SA7yc23/3m4X2Gy0STHOejwBvjOW9aO+TWqv1Fyp18xk22JRdE4sGQkuvnj+87lhWMN/HNfNc8daehXVMHlONOmc0rT2VPROq7RmB6XnZMD7nAnxzkpShdykt0cq+/E7bDR6Q2yqSSNYMj0FcRr7Q6QkxLXb+RzfbuXN/74Jf7x0Yun/ff1xIFa/v2+XSOuEwgZPK7hD23/2FfNl26YWxW8BxTjvABriv1twDas0c1DD/WeZ8Yy1XcklyzVYJ6aeiKSF1FA9yZgXzTboybuwsWZ3PPaaf7zr/tYnpvEhgXp0W6SUqNy2m188+azyEp28+LRBk41dmGMYU1hCp3eIHtHmCKfleRmU0kaDe0+tp9uZl9lGz9//gT/eukiRIRgyPTdxEnzuIhz2unwWunVVuYlc8O6fM5dmMHKvGTKGju5+vvP93v/RLeDb918FtetyetbVt3aw593DL6B86cPnEec084nH9g9I8XlF2QkUNM28ujNXnsrW1mWqzNs1dRL9bi4ckV2v2LVKfEOFqQnUNHcRWGaB8S62BcBjOANBjlYbfWRswqGLyi/uTS9X1G+iuZuspPcHB4mED2QwyZ9N2GahhiIFAwZ6tu9fTNjNyxIpdsXwhcIUpLhob7Dhy8QoiacguNwTTubS9Np7PBSlO6hrt3bL11jqsfJ/e8/b0yzhy5emsWLn7mMd/5qCy8e6z8Dv90bIHtMe6gG0uDyODnsNq5cmcO7Lijle08c4dyF6bznwoXYxMqB+tyRevZXtdHQ4Zu1weX81Hh+/55z+Mgfd/RNXYjkDxr2VbZypLadhg4f64tTecc5xRypbedwTTttwySVL0iN508fPI+8lMF3idp7/LxudS7BkBnyhCA/JY6PXbmUonQPO043c9XKHIrTPdy3tXzE0eRKTVTkCfFMs9mES5ZmccnSLA7XtHP3y2U8sK2cQMgQ57CxNCcRQXhtjFV4e51Tmj7kaxwOG8fKOzhW18GmkjS2n2qmrt1LXXv/k2YRqGjqpmfA1Kmyxi4+eu9Ofv7ODdMyHbisoZPvPnGEv0/BrJDNpRkjBp9nmyGKcf4U+C+slNv/hTXF/t1DvG7eFeMMhCZeD+GswhSWaGEeNUki8kfgUiBTRCqALwGXisg6rD5bRkQBIjW7XLI0i3innW5/kP/8635+dcfGIc95lYo1Dpvwb5cv4XOvW9FvuTGGh/dU86ftFbxyvLHftPPkOAf33Xlu39Tx4/UdfPuxw3zn8cP87LnjBIKGkDEkuh3YbUKc09YXWHY7bNzzvnNI9ZwZoVjb1sPKvGQS3Q5q23soSvPw1RtX9b3/7vIWfMEQ+6v6B8JE4MtvWMXGEutmznsvWsgnHxh7geyJ2n6qmQ3FqWwfoqjZQEtzdHq9mh6+QKhfYBlgeW4yr51sYlGWVdwuOd7J61bn8s/9NdS1e9lQnMaSnERO1nfgdAiLshJI87jYNiDt4MB0LqPlWY7ksNlYnJ3IgXAQ+5zSdKpaBr9+U0kaTruNmtZutp9q6Vu+tiiF002D63n1BruP1XWS5HawIN3DqfB6Zxenjes6VET65V9OinPwsSuXskjTYUzY3LnCnmFvOrsAu0244/wSEiKm51yzMpf3X7yQBemeKLZu8nJT4njgA+fzzl+9xgtHB+dTjgwg7zzdwr7KVoIhQ0lmwrDB5ZJMz7An2UlxTj58+RI+fPkSGju8/O9TR2nrCfDo3mqK0z38+B1n91XcjZyafPv5JZPYS6WG98SBWi5aktmvf0fDstwkvv6mNdy6qYj/9/TRQScQY7WxJI09FS3YxJqmB7AoK4FEt4PtEScTnd4gww3wXJmXzOGaoWcXPHeknq//4xAbF6SRFGfltprIKI0Ob4CGdi8d3gA5yW5qWr14A0H2VrSM+T0GpunISXbzrgtK+cY/DnH1Kqsgmy8QmvX5/4YqxmmMqY14/hfAw0O91hhzF3AXwMaNG+d8MsC2Hj+HJziSqTjdwzfffNYUt0jNR8aYtw2x+Fcz3pB5rscfJM459TNtEtwO3ra5mF+/dJID1W3c9OOX+eGt6zhnoabUUbElEAxxtK6DvRWt7KlsYVtZM4dr27l0aRZv3VTM2QtSyUp0IyK8YW0+b1ibT3Onj+88fhhvIMSCdA/Xrs5lYVYizxyu48sP7WddUSr/c9NqvvrGVZQ1dBEIhgiEDOkJLl472cTdL588s/2QVVTsmlW5fcsuWpLFRR8dfobQggwPx+s7+coNq+jwBthxupmyxi5uO3dBvz72xy2nh32PqRQIGXaUt7AyL6kvgDYc5wgpP5SajJMNnSzNSSQ5zklPIIhdhH3h2Qb/cf1KXA4bv32ljH/sq6EhnCd5++lmluUmYQx9Ad2ziwcPijSM//IgPcHFoqwEEtx2Dtda14zpHidby4YeENVb9DMz0UW3/8z128HqdpLcdtq9w6eobPcGiHfZ8Tht/OtliydUSHdFXnLf47dsKOI9F5aO+z3UGRpcnqDCNA8fumzxoOUpHidneVJnvkHT5Fe3b+KLf9vHQ7ur6Boh/2xv3p0T9cMnlH/LhrF1+IxEN1+5cTUAd168kNLMhGm5CFBqJNeuzh19pRm0tiiVD122mFeONw6bcxisGQI5yW5auvx43HbcDjutXT5sInT7Q5xVYOVsPt3cRXlTF3EuO4Vp8bgdNk7UdxI/Ql/bX9XGwswE4l12Onr8ZCbF0djhpayxC28gxF3Pn7CilVgjSd59QSlvXFfAmsLR86K/cryRb//zEDYRtp1qZlFWAv9942o2L8zgntdODcoTPZKk+DMnSJmJbm47r4QefxARuD48tXK2F1cZrhinTrEfzBjDtx87PGp+uIFcdhu3n7+Aj165dMhilkqp2Wm6zimDIUO8y0ZJhoeyxi5q2nr41z/s4KGPXDhsbkelZtr3Hj/Mz58/MWQBr2cO1/NMuFBzRoKLFXnJvOuCEi5blk1agov/uWkNYJ1D7atq5cfPHOOe105T2dLNqcYujtd38LrVeZxdnIbDbuN/nz7MVStzuXFdPg6bsKWsiWcP1dHpC/KJ+3dz+Rezxxx4TfW42LDgzEjnK1bkDLne2zcXc7C6bcTr1qngcdlZU5AyaCT1UOravazIG3U1pcatw+tnSXYSmYkuDBAyhsuX5xA0BrfDRpcvyB3nl/Khy+x4XA56/EEaO31Ut3RzoqGT6tZutpU1DUr3mupx0tQ5tpo6DpuQ4HawPDeJvRUtbC1rpig9ntZwyoqmLj+bS9L75VweqKGj/7bcdhtZSW7avSMXK2zr8fPbd29mU0n6hGbPvv2cYq5amUOc005q/OzMOhBL9GpJjcjlsPGNN5/FstwkvvL3A8OuV5LhIT3B1ZebNdIXrlvB5SuyJzSaO/JuklKj6fAG5nQQaH1xGp++djlfe/TgsFV9M4bph0ttQoLLTnO3j6rmbnrjbL7uAO3dAZLjHSzJTmRf1eDXZiS4ELEO/L0ViXtTbKzMS8ZpE/wDgrXGwK9ePMk/9lbz1w9dQHa46GCHN8Ch6jbu21rOM4fryE6Ko6q1m5YuPyLW6xZmJnC8vpOP3LuTDm8AXyA07GjqofReqOQku3npM5fjsNsIhQzGWCPLQiEz60ctc6YY514R2RVe9nngbTrF/oyjte188A87OFbXQUFaPG67jUS3g3iXnWDIYLMJXn+Q8uZuFqR7ELEuApfnJvOF65dTmqlT45RSY2OMYWVeCsfqOihrtKbpNnb6uOe1U3zqmuVRbp1SFrfTPuw5ZKTGTh8vHmvgxWMNJLodxDlt5KXEkxLvZH9V66BgFMC+yjb2Vfaf4famswvJTHRz+/kl3H5+CaGQoScQxCYyLSN637yhkOR4J+/77bYpe8/kOAeFaR4S4+z4g4b6Ni+VLd2jpqez24Q3nJXXV6hbqam2YUH6pPP7V7V28Y1HD/erybM0O5EtQ6RHHWh1QTLdviCd3kC//lDR1E2S20F7OBXOvsqWvuu8SKGBC8JSPM6+a87hLMlO5Nd3bKJoEhkDnHYb+Xrzd8rM3SiMmlJvP6cYY+A7jx/uuxNcmBbP19+0hsXZiX3pLo7WtlPR3I2I9XxFczeXLtOU6GpmzOXAcq/bzy/h5g2FvHy8kScP1PK33ZX0+K2LhM2l6VQNU9zvSK1VqbqzafDzBqtY35JsBzaxAf1He5RkevAHDSnxVvVvoO8E4kB1GxsWpOGwCUdrOwYVbKhq7eFD9+zgwsVZHK/v4OmDtXREjCaJvFPde37R5QuSFOegocNHSryD5DjnoPzPI+kdlfyVG1bjCF+42GzCBy5Z1Pd4thuhGOejM92WWFXR3MX7f7e97+S0snnkwpe9IzQcNuEP7z2HBRmaz18pNXYOu40Ll2SyvjiVZw/X9wXwDo0yZV6pmTTW0YiROrwBOryDRxeOxGW38cU3rOSWAVPVbTaZ9toXV67I5ptvXkOHN0hzp8/KAT2BGWur85Np6PBS0+blQPXYi86DdS5x97s2c+GSzHFvV6mZlJ/i4Xu3rGV1QTLf+ecRfMEQW8qa2VSSNmT9rUgn6jvp9gUHJdAwwMKshL5igV3+0JCjlx3D3GDKSYqjYoTz9qwkN9+9Ze2kAstq6s39SIyaEm6HnXdfWMrqghQe2VPFptJ0NpWkkxMejdhrSU5Sv6JHi7O1AJJSUy3B7eCqlTlctTKH/75pNUdrO3jmsJWLuaK5i/u3VRCcwEn0tlPNLMlOJD3BhTcQQgBfMIQx1h1ou004PkTqm96czRsWpNF0avCFx9ay5r6Tk9xkd19wOdFtZ1V+CmUNndRGBI9r2noozfSwKi+ZLn+QPRWtLM9NwuOyDzkqO1JSnINrVuWwuiCFa1b1nzIZ79L0OvPFqcZO3vrzV6lpG3vxkV63bi7SwLJSakJS4p0kxzm4elVuXxHaxgkE85SaLmuLUgctu+P8Eq5ZlUtBajwZiS5au/0cqGpjd0ULuyta2V3eQusY05NlJ7l5w9p83nfRQnJT4kZ/wTQQEd666Uyx4od2V3G6qQuHTfoFmfNT4njneSVctTKb8uZu/vvhA33nuYuzEzlU08YYBnkP6RtvPksDy2rWcNht3HnxIvJS4vnYfbuswvYigwLMqR4nLRGzFrp8QTaXpvcV2uuV7nFROWDA09G6dorS4ikfZbDHkuxEtp8ePqi9KCuBP7z33Kh9vqjhaXBZjcvm0nQ269QepWKG025jZX4yK/PPpJBZmZ/Cf/51Yql2j9ZZI5x7016MVUq8sy/ILFh3lIcabexxOyjNdHCyoZNluUm8drKJc0rT+4LLSXEOVuQmc6y+HbfDzskGqz2Hatq5ckUO9915br/3iwyhGwMuh0x6epiavYwxPLizku89cWRCgeULFmfo9HWl1KTsr2rjw5ct7gsuv+nsgii3SKkzblibj8tu4y87Kqhu7SHR7eBNZxdwVmFq3zoJbgf5qfFcudK6Se8Phrjj/7bw0rHGId9zQYZV4O+aVbmsK0yNuRli97//PJLjHXhcVmo0XzCEPxgi0e3oy9O6ODuJeKedW+96FYA0j5NjEwgs223Ct28+izedXTiVu6DUjHjD2nyS4hy87zfbOFbfQWaimw0L0voCw/ur2inNTMAbCFLVYp1nbznZxMLMhH5pLDKTXH2zZns1d/lZkp1IW4+fFbnJhAzUh6//4p12VuQl4bTbRrz+zEl2a2A5hmlwWSml5ph/OaeY4nQP/37frglNfwQrSDcerd1+NpekETJwuqmLgrT4IYPLJ+o7sduENfnJ1LRaz3f5gtjFClBnJcf1TZlq6vT3u2Pudtr6VQRXaqCd5S38/tVTI06lGyjR7eAtGwu54/wSHbGslJowYwwiwsKsBATB47LT5QvywtEGbjuvJNrNU6rPtatzx1W42mm38ZYNRbSFC3TZxBodnJ7g4paNRVy9MifmAsqRIgNRNpsQZ7MPWdhzbWEqH7hkIVtONo2aDmA416/J08CymtUuXZbNp69dznefOExuchxlDZ20dQfY322leDrZ0ElyvIMEl51OX3DIAUkpEcXxlucmcaLBKhrf2hMg0e2kvsNLVWsPXr81m3VhVsKos1NvXJfPx69aqoHlGKbBZaWUmmNEhEuWZvHq567ge08c4WfPHR/3e3T7x19lO7LwQ7s3wKr8ZPZXDc5RFwwZUhKc7A0/t7eylXVFqdS09XC4pn9uyq1lzWwoTmP76eYhEwwr1avHH6Suracvv9tY2ATuvfNcVhekTGPLlFLzgS8Ywu2wU9XSw6KsBJbkJLG7vIXnjtSzt6KVNYX6OaNmrzeuL+CN6+f2KPx4l53Pvm4FAFUt3dz1/Ak6vQFyU+J4+Xhj3wy9kSTFOTDGsOVkEzabsKlEZ9Op2eft5xRzvL6DP++oGDJfeUdPgLVFqdiEQYHlOIewp6KFzSVpINKXMsMXCIUHI53JveywwZLsJOwy+lXe5cuzdRBIjJtUcFlErgV+CNiBXxpjvjHgeTfwW2AD0Ai81RhTNpltKqWUGhuXw8Znrl3GdWtyeWRPNQ/vqR6U/2o4eyvbOLs4lV3lLUwgfTPdviB17V7WFqXgtNmwiSBiVQW2Cbx4tP/Uyl3lLcO+V1uPn9+8ezNnF6eOvyFq3nA7bHzzscPjyjd+/Vn5GlhWSk0JEzL4AiGeOFBDdX4K1eHjrS8Q4mP37eSpT1wa3QYqpcYsPzWeL9+wqu/njwZD/OG109hswp+3Vwx73vqH107z+IFaGju8/OVfL5ih1io1tRLcDi5ZmsW9W8tZX5xKc6ePlm5/X77lkIGdw4w0XpCRSJrHyavDpLcwEUkNAyE43dRJUtzoYUl/cAIXpGpGTTi4LCJ24MfAVUAFsFVEHjLGHIhY7T1AszFmsYjcCnwTeOtkGqyUUmrsRISzClM5qzCVz75uObvKW/jbrioe2l01asqMHadbKE73cLqpa0Lbrm/39uXS6uV22GBQTeGRHa3r4GP37uTud20eshCNUgD3bS3nZMPggpMjuXFt/jS1Rik13zR3+zle38Eb1ubT4w9SlO7pSw91uqmLth4/yXHOUd5FKRWLHHYbt59fgjGG371SNux6OclubjuvhNeflaejLNWsdu3qXD5y+WJeO9GETYRQyJCZ6KKhY+Trx1SPlfZiOLbwKGW3w0aqx0ltm5fcFCe0j/y+r51o5OYNmnImltkm8drNwDFjzAljjA+4F7hxwDo3Ar8JP/4TcIXIGMa8K6WUmnIiwvriNL58wyqe+PeLuXZVLonu4e8xLs9NmnBgeTirC1LwBsZ/57m5y89NP3mJTz2wm54JpOxQc1tjh5fvPnFkXK+xCZyzUKerKqWmRl5KPGsLUylM8wDgcZ3J6eoPmr4Cf2p2EpEyEdkrIrtEZFt42VtEZL+IhERkY7TbqKbfY/tqhlyelxLHf924iuc+dRkfumyxBpbVrCcivG1zMQAd3gDXn5VH4ygDkwpS4zlU007IQG7y4NzI8S47p5usgSDF6R5aunwszUkkO8k9anuuPytvAnuhZtJk0mIUAOURP1cA5wy3jjEmICKtQAbQMIntKqWUmqSMRDc/e+cGAJo7fbx2spGnDtZxtK6DXeUtLMxMoLq1Z0q3Ge+0c6pxfCNLI4UMPLC9glX5ydxxQekUtkzNdpUt3YNGyY9mYVYiSTqKUCk1SaGQwRsIEee04bTbqG3t4UhtO12+QL/1/rG3hnecsyBKrVRT5DJjTOR17D7gTcDPo9QeNYMe2VPNj545xpHaDtITXLT3+PEHDdeuyuUHt64bskigmnkiUga0A0EgYIzZOOB5wUrteh3QBdxhjNkx0+2cDfJT4/n5Ozfw+Qf3cqC6nZHqvW8uScMXCOFx2zka7iMDrclPZktZMx6XnZR4J96A4Whtx5hqEpy9IG0yu6JmQEwU9BORO4E7AYqLi6PcGqWUml/SElxcuzqPa1fn0eUL8B9/3cfxug5OjDPFwEBXrsgmM9HNnopWjta14w0ESR5DTq3RfPnvB2jtDvDRK5dM+r3U7BcIhvjsn/eO+3Ur85KnoTVKqflGxBqNBVY6qF3lLTy2r4YrVuSwt7INXyAEQEmmJ5rNVNPAGHMQrBF+au771YsnOFjdhk3guU9dSmVLN08eqOWOC0o1sBx7Bt4IivQ6YEn46xzgpwweJKnCUuKdPHO4jh5/aNh1NixIY0tZM/FOW9+o/cLUeBw2oa7dS7zTji8Y6kvJuDAzgW3hApkG8AZC/Qr9DeR22PBoH4t5k7nKrwSKIn4uDC8bap0KEXEAKViF/foxxtwF3AWwceNGzdStlFJR4nE5+N4t62jo8PLC0Xq+/dhhqsY5gtlhs6ZRXbY8iyXZSbx6opGc5DieOljLifoOasc5wnQoWWOYPqXmhy1lTRyobhv367RApFJqKkQGFtMTXCzJSeTKFWu5d+vpvsBycbqHr9ywOlpNVFPDAI+LiAF+Hr5+VfNEeVMXx+utQRchA/dvq+A9F5ayPFdvVM9CNwK/NcYY4FURSRWRPGNMdbQbFotsNuGjVyzhLzsqOVrXAYDLLqwrTsPrDxI0hh2nrUDx6oIUtpZZj/dUtva9R7c/iE2gtyaf29E/UHy4pp3luUnDtuHdF5bisE8mo6+aCZMJLm8FlohIKVYQ+Vbg7QPWeQi4HXgFuBl4OtyJlVJKxbDMRDc3rS/kqpW53P3SSerbvZxu6uJQTfuw6TISXHbOX5zJey4s5dyFGX3Li9Kt0VqbS9Np6fLz6T/v4fkj9aO24U3rC/jKjVal7siLdwFcDj3BUJbnxvC/NJTsIXLBKaXUZCS4HeQlxxPvsuOMuBD+j+tXYLfp6NZZ7kJjTKWIZANPiMghY8zzY3mhztKd3bp8Af73qaO0dvv7lj28p4qqlm4OVrdRnO6hIDWej1yhM+pixGg3goZK71oAaHB5GFlJcZxo6GRDcRoI7DzdzJaTg0cZd3gDQ7zasjIvmX1V1mAQGeIyrqHDi9Mu+IP9w4V5KXF8/Kqlk9sBNSMmHFwO51D+MPBPwA782hizX0S+CmwzxjwE/Ar4nYgcA5qwAtBKKaVmiUS3gw9ffuZk2RcI8dtXynhodxX7KlsREZZkJ/KhyxZz2fLsEQsExjnt5KbYufuOTfzfy2V8/dGDBEJD329MinPwuetWaE5cNaLWbj//91LZhF6b5hmcC04ppSbDHwyR4nFyurGTo7XtANywNp+rVuZEuWVqsowxleHvdSLyIFZx+zEFl3WW7uzmcTlIT+x/zrDzdAs7T7cA8PLxRq5amYMxRlOkxIYJ3wiKpDeFzrh0WRYCbA+PUB6KwwbNnf5hnxeRvuBx7RADlRo6fGwuSae+vYeTjWcKyv/PTav73axVsWtSyS+NMY8Cjw5Y9sWIxz3AWyazDaXU9BGRXwOvB+qMMavDy74MvA/oHQ74+XBfVwqXw8Z7L1rIey9aSEuXj+Q4J7Zxjsay2YT3XFjK2sIUPvD7HTR0DE6T8fGrlmrqCzUsYwxfemg/Txyo7Zt2Ph4r8pJZr2kxlFJTqKXLR2OnD6fNRrc/yFOH6njd6ly+d8taDTjNciKSANiMMe3hx1cDX41ys9QMOFjdxh9eO8XvXz094npPHKjldT98gTvOL+HWzfM7EBltY7gRNJb0rnpTKEJmopsb1uXzlx2Dfk19MhLctHT7+n4emEP5aG07/qAhM9FFQVo85c3dg95jS1kTr1udy5vOLuRXL53k7OI0Ll2aPbU7o6aN3gJQan67G7h2iOXfN8asC39pYFkNKdXjGndgOdLGknT+8sHzyU/pn55geW4S7zx3wWSbp+awP24p57evnBo2RctIVuYl85t3b9LiOyoqROTXIlInIvsilqWLyBMicjT8XUuiz0KpHheLshJJjnfw02ePk53k5ifvOFvzRM4NOcCLIrIb2AI8Yox5TERuEpEK4DzgERH5Z1RbqaZMMGT42XPHueFHL44aWO51qKadpw7VTXPL1EhEJEFEknofY90I2jdgtYeA28RyLtCq+ZZH98mrlzHSfdLadi+LshJZnZ9MSryT+g4vNoH1xaksy0miJzwYpKHDNyj1RaR/7KthbVEq379lHZ+4eumkrjXVzNKzHaXmsfAUoaHLsio1A4ozPDz0kQu5csWZu9Ip8ZoKQw0vGDL84MkjE3ptYVo8v3vPZrKTNN+yipq7GXxT97PAU8aYJcBT4Z/VLNPa5ccfDJHgdpCbEo8BHbE8RxhjThhj1oa/Vhlj/ie8/EFjTKExxm2MyTHGXBPttqqp8aOnj/GNfxwaMQgWyWW38bbNxbz57IJpbpkaxXA3gj4gIh8Ir/MocAI4BvwC+NfoNHV2yU+N55NXLxtxnf1VbeyraqMkw0Oi205pZgJXLM/mVFMnN28o5LyFGWQmuihKix/xfWraerhseTar8lOmchfUNJtUWgyl1Jz1YRG5DdgGfMIYM2SCJc1FpaZCZqKbb928lrf+/BWO1nVQ0dxNTyBEoo72UkM42dBJXfvgVCpjccGiTDISNd2Kih5jzPMiUjJg8Y3ApeHHvwGeBT4zc61SUyHF46THH8Qmgk3glo1Fo79IKRWTbliXzysnGnj1xNjG4KzMT+brb1ozza1SozHGnADWDrH8ZxGPDfChmWzXXPGhyxbjcdn570cOEoyom5PodvQV88tMdJGTHNd3vt7Y6SMpzsmKvCSK0uJ5xznFpCc4OXdRBjWtPSzPTSYn2U1pZgJ2m9DpDZKtqRFnJb1yV0oN9FNgEbAOq2rud4db0RhzlzFmozFmY1ZW1gw1T81F6Qku/njnuSzNSWR1QfKIhQHV/FbbNv5UGL2uWa1FtVRMyomYkluDNfJKzUK1bT2UNXayuTSdt2wojHZzlFITVJqZwL13nscj/3YhYNUcGU5mopvv3jIonqnUnPSuC0r57bs3U5Lh4dJlWThswjvOLe67dstKiiPOYeNYfQdv31yMy2HjqY9fTG2bl5X5ySzLTeLsBencuqmYj125lGtX57K+OI1Uj4ukOCe5KXGaCmOW0qt3pVQ/xpja3sci8gvg4Sg2R80jmYlu7rvzPB7bXxPtpqgY1uEN8K4LSliYlUii244giEBWohu7TWjt9nO6qYu6di/+YIgubxCbTdhUksblyzVmp2KbMcaIyJDzsHW20CxgYEl2IktzkqLdEqXUFPC4HPzrpYt4z4WlbC1r5uXjDdhtgk2EmrYeurwB/EHDayeaWJSVGO3mKjUjLlicySP/dhG7yltIcDs4uziNBekJbC5NJ85pwybCl29cTWr8mcLvn79uRZRbraabBpeVUv2ISF7ECKqbGFwEQalpk5bg4m1aZVuN4JpVuVyzKjfazVBqKtX2HntFJA8YsiKUVq6PfQsyE6LdBKXUFCrNTODT1y4H4NrVuVy7Ws8/lAJIcDu4YHEmFyzOjHZTVIzQ4LJS85iI/BErz2NmuNr1l4BLRWQdYIAy4P3Rap9SSik1DzwE3A58I/z9b9FtjlJKKaWUUmOnwWWl5jFjzNuGWPyrGW+IUkopNQ8Mc1P3G8D9IvIe4BRwS/RaqJRSSiml1PhocFkppZRSSqkZMMxNXYArZrQhSimllFJKTRExJrZStolIPdaojbHKBBqmqTnTYba1F2Zfm2drexcYY7Ki3ZiJGqXvzra/yUjmyr7Mlf2A6O/LXO67Uynaf6do0n2PPfO138bq32M8dB9iQ7T2Yb723ZHEwv9TtNsQ7e3HQhuivf2R2jAf+20s/D0mYza3fza3HWKr/WPuuzEXXB4vEdlmjNkY7XaM1WxrL8y+Nmt7Y89c2se5si9zZT9gbu3LXDaf/0667/Nz32PRXPh76D7EhrmwD3NFLPwtot2GaG8/FtoQ7e3HShtixWz/Xczm9s/mtsPsbb8t2g1QSimllFJKKaWUUkopNftocFkppZRSSimllFJKKaXUuM2F4PJd0W7AOM229sLsa7O2N/bMpX2cK/syV/YD5ta+zGXz+e+k+65ixVz4e+g+xIa5sA9zRSz8LaLdhmhvH6LfhmhvH2KjDbFitv8uZnP7Z3PbYZa2f9bnXFZKKaWUUkoppZRSSik18+bCyGWllFJKKaWUUkoppZRSM0yDy0oppZRSSimllFJKKaXGLeaDyyLyaxGpE5F9EcvSReQJETka/p4WXi4i8r8ickxE9ojI2THe3ktFpFVEdoW/vhgj7X2LiOwXkZCIbByw/ufCv9/DInJNLLdXREpEpDvi9/uzmW7vCG3+togcCv+fPigiqRHPRfV3PFkj/D2uEpHtIrI3/P3yiOc2hJcfC/dhiU7rzxhhPzJE5BkR6RCRHw14TcztB0ysT4vIteFlx0TkszPf6pGJyFoReSX8+/67iCRHPDer+9BcMpc/60YTy8fSmRDrnyHzgYj8e/h/cJ+I/FFE4kSkVEReC/9d7hMRV7TbORIR+Wi4/ftF5GPhZUOeV8eKYc77YvbaZSjD7MO8/kyLReE+vUVEdof/Nl+JUjvsIrJTRB6O0vbLwueDu0RkWxS2nyoifwqf7xwUkfNmePvL5Mz17i4Raev9vJzBNgw63szk9mPJbD//iXZ/Gq/xHHNj0TDt/7KIVEb06eui2cYxM8bE9BdwMXA2sC9i2beAz4Yffxb4ZvjxdcA/AAHOBV6L8fZeCjwcg7/fFcAy4FlgY8TylcBuwA2UAscBewy3tyRyvRj7HV8NOMKPvxnxPxH13/EU7O9wf4/1QH748WqgMuK5LeE+K+E+/LoY3o8E4ELgA8CPBrwm5vZjlH0Z8v8t/HUcWAi4wuusjPZ+DNinrcAl4cfvBv5rpH2Kdnvn69dc/qwbw77H7LF0BvY95j9D5voXUACcBOLDP98P3BH+fmt42c+AD0a7rSPsw2pgH+ABHMCTwGKGOa+OlS9m2bXLOPZh3n6mxepX+P8mMfzYCbwGnBuFdnwcuIcoXdcCZUBmFP8OvwHeG37sAlKj2BY7UAMsmMFtDnm8idbvIJpfc+H8J9r9aQLtHfMxNxa/hmn/l4FPRrtt4/2K+ZHLxpjngaYBi2/E+hAn/P2NEct/ayyvAqkikjcjDQ0bZ3ujbqj2GmMOGmMOD7H6jcC9xhivMeYkcAzYPAPNjGzbeNobE4Zp8+PGmED4x1eBwvDjqP+OJ2u4v4cxZqcxpir8434gXkTc4T6abIx51Vifpr8lBvrICPvRaYx5EeiJXB6r+wET6tObgWPGmBPGGB9wb3jdWLIUeD78+AngzeHHs74PzSVz+bNuNLF8LJ0Bs+EzZD5wYB1rHVgB2mrgcuBP4edj6px0CCuwgq1d4c+R54A3EcPn1TD7rl2GMtuuD+ar8P9NR/hHZ/jLzGQbRKQQuB745UxuN1aISApWcOhXAMYYnzGmJYpNugI4bow5NcPbHXi8qRpl/blKz39m2GyLvw00TPtnpZgPLg8jxxhTHX5cA+SEHxcA5RHrVYSXRdtw7QU4LzyV6R8isioKbRuPWP39jqQ0PE3rORG5KNqNGca7sUatwOz8HU/Em4Edxhgv1v5VRDw3W/d5Nu7HcP9vs+H/cD9nTtbeAhSFH8+Gts9X8/GzbijzYd/nwz7GNGNMJfAd4DRWULkV2A60RNzwifW/yz7gIrHSUXmwRvkWMfJ5dayabdcu4zEX9mHWCqek2AXUAU8YY16b4Sb8APg0EJrh7UYywONipd27c4a3XQrUA/8Xvub8pYgkzHAbIt0K/HEmNzjU8cYY8/hMtiGGzIXPw2j2p6kyG88TBvpwOF3Wr2M5rUek2Rpc7hMeITijd2gnY0B7d2BNWVkL/D/gr9Fq1xxVDRQbY9YTnq4lEXlZY4GIfAEIAH+IdlvGQ0SeDOfUGvg16p3Z8E2UbwLvn/6WjtqWCe9HrJlL+9JrlH16N/CvIrIdSAJ80W3t/DWW/73Z+lk3mrnY79TcEL4QuREr8JGPldLp2qg2apyMMQexzhceBx4DdgHBAevMqusAmJ1tVrHLGBM0xqzDmhm0WURWz9S2ReT1QJ0xZvtMbXMYFxpjzgZeB3xIRC6ewW07sKa0/zR8zdmJNQ1/xomVQ/8G4IEZ3u6g442I/MtMtkFNqWj2pyk3S4+5PwUWAeuwYlrfjWprxsgR7QZMUK2I5BljqsNTx+rCyys5M3oNrINs5Yy3brAh22uMaetdwRjzqIj8REQyjTENUWvpyGL19zuk8KhYb/jxdhE5jjWVPiYS04vIHcDrgSvCH3owS37HxpgrJ/K68NS5B4HbjDHHw4srOTNVHmZwnye6H8OI2n7AhPdlpP+3qP8fjmGfrgYQkaVYUzJhlvShuWS0v9Ns/qwbzTT0u7liPuxjrLsSOGmMqQcQkb8AF2ClXXCERy/H/N/FGPMrwtPNReRrWKPAhrsOiGWz7dplPObCPsx6xpgWEXkG6ybSvtHWnyIXADeEi03FAcki8ntjzIwGFsMjZzHG1InIg1ipCZ4f+VVTpgKoiBgx/ieiFFzGCgbuMMbUzvB2hzrenA/8fobbEQtm/edhlPvTVJmN5wl9IvuwiPwCiEqx1PGarSOXHwJuDz++HfhbxPLbxHIu1pSM6qHeYIYN2V4RyRURCT/ejPX3aIxKC8fmIeDWcJ7cUmAJVgGzmCQiWSJiDz9eiNXeE9FtlUVErsWaQnaDMaYr4qlZ9TseDxFJBR7BSq7/Uu/ycB9tE5Fzw/3hNs706Vljlu7HcP9vW4ElIlIaHgVxa3jdmCEi2eHvNuA/sApTwRzuQ7PRfPysG4P5sO8x/xkyD5wGzhURT/iYdAVwAHgGuDm8TuQ5dEyK+Kwvxsq3fA/DXwfEstl27TIe8+EzLSaFr3VSw4/jgauAQzO1fWPM54wxhcaYEqzP+adnOrAsIgkiktT7GGvgwUwF1zHG1ADlIrIsvKj3szYa3sYMp8QIG+p4czAK7YgFs/r8J9r9aQrNxvOEPtK/9sJNzJa/gYmBqoIjfWF9QFYDfqw7g+8BMoCngKNYlaPTw+sK8GOsCp17iahkHKPt/TBW3tDdWIWOzo+R9t4UfuwFaoF/Rqz/hfDv9zDwulhuL1Ze3/1Y0yh3AG+Iof/hY1j5mHaFv34WK7/jKdjf4f4e/4E1VWxXxFd2+LmNWB+ax4EfARKr+xF+rgwr8X5HeJ2VsbofY9iXIf/fsHJbHgk/94Vo78MQ+/TRcPuOAN+I/F3P9j40l77m8mfdGPY9Zo+lM7T/Mf0ZMh++gK9gBZr2Ab8D3FgV7LeE++YDgDva7RxlH17ACtTsxpr9AMOcV8fKF7Ps2mUc+zCvP9Ni8Qs4C9gJ7An38y9GsS2XAg9HYbsLw58Pu7Gu+2b8eIM1dX1b+O/wVyAtCm1IwBqklhKlv/+g40002hELX7P5/CcW+tME2jzmY24sfg3T/t+Fzwn2YAXK86LdzrF8SXiHlFJKKaWUUkoppZRSSqkxm61pMZRSSimllFJKKaWUUkpFkQaXlVJKKaWUUkoppZRSSo2bBpeVUkoppZRSSimllFJKjZsGl5VSSimllFJKKaWUUkqNmwaXlVJKKaWUUkoppZRSSo2bBpeVUkoppZRSSimllFJKjZsGl5VSSimllFJKKaWUUkqNmwaXlVJKKaWUUkoppZRSSo2bBpeVUkoppZRSSimllFJKjZsGl5VSSimllFJKKaWUUkqNmwaXlVJKKaWUUkoppZRSSo2bBpeVUkoNSUS+LCK/j3Y7lJoLRMSIyOJpeN9LRaRiqt9XKTUxIvJ5EflltNuhlJocEblbRP472u1QajbQY59yRLsBSimlxk5EDLDEGHMs2m1RSimlVH/GmK9Fuw1KKaXUTNJjn9KRy/OciOgNBqVmAe2rSiml1NTSY6tSsU/7qVJqOuhny9TS4PIsJiJlIvJJEdkjIq0icp+IxIWfe5+IHBORJhF5SETyI15nRORDInIUOCoiXxGR/xd+zikinSLy7fDP8SLSIyLp4Z8fEJGa8PaeF5FV4eWbRKRWROwR23mTiOyewV+JUjEp3Fc/JyIHRKRZRP5vgn31+fBTu0WkQ0TeKiJ3iMiLA7bXN/1eRDJE5O8i0iYiW0XkvyPXF5Efikh5+PntInLR9P9GlJq9JtqfB7zH9SKyM9zvykXkyxHPlYT78O0iclpEGkTkCxHPx4en6jaLyAFg03Tvs1JzSbgPf0ZE9gCdA1PWRE6FF5FMEXlYRFrC/foFEbGFn/uMiFSKSLuIHBaRK8LL+6WUGu7cWSk1vCH66T8injsqIg9E/FwuIuvCj4c9rw33zftF5LfhfrtfRDZGPL9eRHaEn7sPiIt4Li38WVAfPv4+LCKF0/xrUComDXX8izz2jfFc9jfhvnRQRD4tESneROSzInI8/P4HROSmiOfuEJGXRORH4ePqod7jb/j5/PA5eFP4nPx9Ec99WUT+JCK/F5E24A4RSRGRX4lIdXif/lsiYlpq7DS4PPvdAlwLlAJnYXWQy4Gvh5/LA04B9w543RuBc4CVwHPApeHlm4Aa4OLwz+cBh40xTeGf/wEsAbKBHcAfAIwxW4FG4OqIbbwT+O3kd1GpOeEdwDXAImAp8B/j7avGmN5+udYYk2iMuW8M2/0x0AnkAreHvyJtBdYB6cA9wAO9gTKl1LAm2p97dQK3AanA9cAHReSNA9a5EFgGXAF8UURWhJd/KbzdReE2DOzTSqnRvQ2r76WOst4ngAogC8gBPg8YEVkGfBjYZIxJwuqLZcO8x5DnzkqpUfX207OB80TEJtZNWxfWNSoishBIBPaEXzPaee0NWMfmVOAh4Efh93EBfwV+F37tA8CbI15nA/4PWAAUA929r1VqPhnn8W+kc9kSYCFwFfAvA153HLgISAG+AvxeRPIinj8nvE5m+L3+IuHBkFj9uwLIB24GvhY+R+91I/AnrM+APwB3AwFgMbAeK5713tF+D2owDS7Pfv9rjKkKB3//jnUwfQfwa2PMDmOMF/gc1gG5JOJ1XzfGNBljuoFXgCUikoEVVP4VUCAiicAlWMFnAIwxvzbGtIff98vAWhFJCT/9G8IfDOHOfQ3WQV0pBT8yxpSH++r/YJ0wj7evjkv4ruubgS8ZY7qMMQew+mkfY8zvjTGNxpiAMea7gBvrJEApNbyJ9mcAjDHPGmP2GmNCxpg9wB+xjreRvmKM6TbG7AZ2A2vDy28B/if8uVAO/O+07KFSc9v/hvvwaMdWP9bNogXGGL8x5gVjjAGCWMfLlSLiNMaUGWOOD/UGo5w7K6WG19tP9wPtWNe5FwP/BKpEZDnWsfMFY0wIxnRe+6Ix5lFjTBArkNx7bD0XcAI/CPf1P2EFqgm/b6Mx5s/h8+l2rGP/wOO2UvPBmI9/jHwu+zVjTLMxpoIB57LGmAfCMa5QeDDVUWBzxCp1nOmr9wGHgetFpAi4APiMMabHGLML+CXWgI5erxhj/hr+zEgGrgM+ZozpNMbUAd8Hbp3g72Ze0+Dy7FcT8bgL685tPtaIKQCMMR1Yo4oLItYtj3i+G9iGdYC8GCuY/DJWx+wLLouIXUS+EZ6i0MaZO1SZ4e+/B94gIglYHxgvGGOqp2Y3lZr1yiMen8Lqp+PqqxOQhVW4NfI9+r2fWKl1DoanFbVg3SHORCk1kon2ZwBE5BwReSY8vbYV+ACD+91Qx3fC2xm4faXU+Iz12Ppt4BjwuIicEJHPAoSL6n4MK1hcJyL3yhBpcMZw7qyUGl5kP+2dadt7rfos1nVqv4FQYzivHXhsjRMr72o+UBm+edSr7/gqIh4R+bmInAr35eeBVJ0+r+absR7/wsZ6Ljvw+vQ2EdklVkqqFmA1/fvxUH2191y8KXwDKPK54a6tF2DdVKqO2NbPsWYaqXHS4PLcVIXVUQAIB3szgMqIdcyA1zwHXI41FWBr+OdrsO4Q9eZ5fTvWNIIrsQ7UJb2bADDGVGKNgn4TVkqM303R/ig1FxRFPC7G6qcT6asDdQKeiPfIjXiuHmuaT2ROuKKIdS8CPo11MyjNGJMKtBLu00qpYU20P/e6B2s6bpExJgX4GWPvd9VDbF8pNT6Rx9YuIo6jWGmkrJWsEcefMMYsxJpO//He3I7GmHuMMRdi9XsDfHOI7Yx47qyUGlFkP+0NLl8UfvwcA4LLkzyvrcaauRu5buTx9RNYI6DPMcYkcyaFpPZlNe+M8fg3kmqGvz5dAPwCK/VGRrgf76N/Xxuqr/aei6eLSNKA54a7ti4HvECmMSY1/JVsjNHaCBOgweW56Y/Au0RknYi4ga8BrxljykZ4zXNY0wUOGGN8WHeD3wucNMbUh9dJwup8jVgn4V8b4n1+i3VQXwP8ZfK7otSc8SERKQynjPkCcB8T66u1WPmpeu0GVoXfIw7rLjIA4Sl/fwG+HB5xsZz+04KSsILP9YBDRL6INT1IKTWyyfbnJKyRFT0ishkrADVW9wOfE6u4UCHwkUntiVJqF/D28Cjja4mY6i4irxeRxeGL2Fas6cAhEVkmIpeH+3oPVv7V0BDvPZZzZ6XU6J4DLgPiw9PoX8CqO5QB7AyvM5nz2lfCr/03sQrcv4n+0/CTsPp5S/jY/6VJ7o9Ss9I4jn8jiTyXLcAKJPdKwAoA14e39y6skcuRsjnTV98CrAAeDaeLexn4uojEichZwHuwZtgPEp5l/zjwXRFJDud1XyQimvJmAjS4PAcZY54E/hP4M9ZdoUWMnjfmZSCeM6OUD2B9WDwfsc5vsaYVVIaff3WI93kQ6w7Wg8aYrgnuglJz0T1YB68TWAUI/nuCffXLwG/CU3duMcYcAb4KPImVj+rFAet/GGu0VA3WbII/Yl3ogpWz7jHgCFbf7mFyaTiUmi8m25//FfiqiLQDX8Q6yR6rr2D115PhNugsIaUm56PAG4AWrNzpf414bgnW8bUDK/j0E2PMM1j5Jr8BNGAdX7Ox8qwPNJZzZ6XUKMLnux1YQWWMMW1Yx+CXwoMpYBLnteHBVW8C7gCagLfSf6DUD7CulRuw+vFjk9kfpWaxsR7/RvJVrKJ7J7GOsX8ifH0arhH0Xaxjbi3WoMWXBrz+NazjcwNW/vObjTGN4efehjVLqAorNvWl8Dn6cG7DKhJ6AGgOtyVvhPXVMKR/qhKlJk9EjgPvH6UTKzVviEgZ8N5Y6BMi8k0g1xhze7TbotRsFEv9WSmllFJKqdlMRD4I3GqMGXXEsIjcgXUefuG0N0yNi45cVlNKRN6MNY3h6Wi3RSkFIrJcRM4Sy2asqUEPRrtdSimllFJKKaXmFxHJE5ELwmkolmHlNNfr01nOEe0GqLlDRJ4FVgLvNMaMN++OUmp6JGGlwsjHmlr0XeBvUW2RUkoppZRSSqn5yAX8HCjFSkl1L/CTaDZITZ6mxVBKKaWUUkoppZRSSik1bpoWQymllFJKKaXUvCcibxGR/SISEpGNI6x3rYgcFpFjIvLZmWyjUkopFWs0uKyUUkoppZRSSsE+4E3A88OtICJ24MfA67BSAr5NRFbOTPOUUkqp2BNzOZczMzNNSUlJtJuh1Izbvn17gzEmK9rtmCjtu2q+0r6r1Oyj/Vap2Wm6+64x5iCAiIy02mbgmDHmRHjde4EbgQOjvb/2XTUf6TFXqdlpPH035oLLJSUlbNu2LdrNUGrGicipaLdhMrTvqvlK+65Ss4/2W6VmpxjpuwVAecTPFcA5Y3mh9l01H8VIv50w7bdqvhpP352ytBgiskxEdkV8tYnIx0TkyyJSGbH8uqnaplJqaoiIXUR2isjD4Z//EM4jt09Efi0izmi3USmllFJKqckSkSfD57gDv26cpu3dKSLbRGRbfX39dGxCqXklfH1aJyL7Rllvk4gEROTmiGXBiNjUQ9PfWqXmhykbuWyMOQysg748VJXAg8C7gO8bY74zVdtSSk25jwIHgeTwz38A/iX8+B7gvcBPo9AupZRSSimlpowx5spJvkUlUBTxc2F42XDbuwu4C2Djxo1mkttWSsHdwI+A3w63Qjgm9U3g8QFPdRtj1k1by5Sap6YrLcYVwHFjzKlR8lUppaJMRAqB64H/AT4OYIx5NOL5LVgnzUpFnTGGli4/f9tVSUaimzeszY92k9QcFwwZTtR3sLeylRP1nXR4A7T3BOjw+unyBfvWK81M4Ia1+awvTsNu03MfpZSaw7YCS0SkFCuofCvw9ug2SUVba7efLl+A3OQ4RIQef5Cdp1tYmpNIRqI72s2bU4wxz4tIySirfQT4M7Bp+luklJqu4PKtwB8jfv6wiNwGbAM+YYxpnqbtKqXG7wfAp4GkgU+E02G8E2tks1JREQwZfvHCCV4+3sj2siY6wwG9xdmJbC1r4qs3ro5yC9Vs197jZ1tZM6ebuqhu7aGmtdv63tZDdWsPvkBo1Pd44WgDVS3d/NcbV9PpDWC32SjJ8IxWFEoppVQMEZGbgP8HZAGPiMguY8w1IpIP/NIYc50xJiAiHwb+CdiBXxtj9kex2SrKKlu6uep7z9HlC1KYFk9xuod9la209QQ4d2E6f3jvuXrjeQaJSAFwE3AZg4PLcSKyDQgA3zDG/HWGm6fUnDTlwWURcQE3AJ8LL/op8F+ACX//LvDuAa+5E7gToLi4eKqbpJQahoi8HqgzxmwXkUuHWOUnwPPGmBeGeb32XTWtTjV28uk/7eG1k02DnhPgnecuGPN7dfuCfOXv+3nD2nzae/ysyk/h+aP1XLI0i4wENycaOliVnzKFrVexKhAMsaeylReONPDisXp2nG4hGJr8TOVnD9ez/VQzrz8rH28gyImGTho7fCzNSSTV45qCliullJpOxpgHsVI7DlxeBVwX8fOjwKMD11Pz00tHG/pmM1U0d1PR3N333MevWqaB5Zn3A+AzxpjQEDf5FxhjKkVkIfC0iOw1xhwfuJJe506vYMiwq7yZV080YbcJSXEOkuKc1nd3xOM4BwkuBzbtQzFvOkYuvw7YYYypBej9DiAivwAeHvgCzUOlVNRcANwQLrQZBySLyO+NMf8iIl/CGrXx/uFerH1XTac9FS184v7dHK3rGPL5D1yyiCU5SRhjeOV4I+3eAG3dfk42dHLh4kw2l6bT6Q2S4nHiD4Z46VgD924t596t5UO+34YFafz23ZtJcE/XpB4VC7afauJzf9nLkdqh/68mIxAy3PX8CUoyElhdkMKirESK0kL88Kkj3H5+CdlJcVO+TaWUUkpF1/H64c8pfvfqKdYVpeJy2GawRfPeRuDecGA5E7hORALGmL8aYyoBjDEnRORZYD0wKLis17lTr6XLx3NH6nn6UB3PHamnpcs/pteJQKLbQXI44Lwgw8O1q3O5YkUOyXHOaW61GqvpuIJ+GxEpMUQkzxhTHf7xJmDEip5KqZljjPkc4VkG4ZHLnwwHlt8LXANcYYwZfT64UtPgm48dGjawnOpx8tddlVS2dFPb1sMfXjvd7/l7tpymJCOBypZushLdHK/vIN5lx2kX/MGhzw+P1LTjtOuJ/1zgDQTZerKZmrYeGju8NHZ4OVzbzt7KNpo6fdO67T0VrXzi/t08+tGLsNsEl8PGJ65ahl6VzB8i8mugd2bQ6vCydOA+oAQoA24xxjSLdeX7Q6wRkV3AHcaYHdFot1JKqfELhgwvHG0Y9vm/767i3y5fzJKcQRkI1TQxxpT2PhaRu4GHjTF/FZE0oMsY4xWRTKyBVt+KUjPnhZYuH/dtLeeJA7XsON3MRCYKGgPtPVbNE4BDNe38c38tLruNC5dk8rrVuVy1MkdnCUbZlAaXRSQBuIr+Ix2/JSLrsNJilDHCKEilhl0eUgABAABJREFUVMz4GXAKeCV8x/cvxpivRrdJar7JSY6jON1DQ4eXLl+QovR4kuOcnGrsorXbzwtHG9hV3kLmEEVSWrr87OpqAaC+3QtAvMtOcpyTxmGCi+uKdVTJXHCktp23/vwVmgeMhlhTkExb99hGSEzW4dp2Iifv6VS+eeduBlex/yzwlDHmGyLy2fDPn8Ga8bck/HUOVjq5c2a0tUoppSZkx+lmPv2nPRwbZjAEQGaim6wkN6cbuyjO8Mxg6+YuEfkjcCmQKSIVwJcAJ4Ax5mcjvHQF8HMRCQE2rJzLB6a5ufNSXXsPv3rhJL9/9VRfvZyp5guGePpQHU8fqsNhE85blMF1a/K4emWOFtGMgikNLhtjOoGMAcveOZXbUEpND2PMs8Cz4ceaF0BF3aeuWcZbf/4Ky3OTsNsEXzDE7vLWfuv03sXOTXZT0+Yd8f2W5SQNmbu515aTTXzs3p0cru1gTUEy77lwIctydZTJbOENBPn6o4f445bTeIcowLe3so3luUlUtnT3jXyYTn/fU8X1a/JwTGA0/P6qVu557TQr8pLJTHRhE8HttON22MJfdtxOGy67Dbcz/HP4OS0gGH3DVLG/EetCGOA3WMfbz4SX/9YYY4BXRSR1wKw/pZRSMerXL54cMbAM0NDhZd1Xn8DlsPHUxy+hKF0DzJNljHnbONa9I+Lxy8Ca6WiTspQ3dXHX8ye4b1v5mApiT5VAeAbBC0cb+MKDezmnNIPr1uRyzapcspM1Ld1M0ACSUkqpmJSbHIdNhB2nW0Zdt7c6t8MmlDV2DblOt3/ku+beQIi/7qoC4GB1G88eruf5T19GnNM+7rarmRUIhvjWY4e5++WyEdc7VNPO+qIUdg64STEdPnrvLj71wB7efWEpm0vTWJmXQmaii0DI4HbYaPcGaOzw0RBO21Hf4WPn6Wa2n2rmVGMXiW4Hh2vbqW7pprKlZ8zbdUUGoB1ngs9nlp8JTg+1Xt86QwSzI9eP67f+mfcfOEr7eF0HX3/0IJlJblbkJXPbeQvmawA8JyJgXAPkhB8XAJGJ4CvCywYFl7W4kFJKxY76di/PHa4f8/q+QIj9Va0aXFZz0rG6Dn7y7DH+tqtqSopkT0bIwCsnGnnlRCNffGg/5y/K4EOXLea8hRnz9Rx0RmhwWSmlVEwSEa5ZlcsfXj1FxximUyW47BwepkjbhuI0dlc0j2v737r5LA0sx7hgyLD9VDM/euYYr51oHNNr7LaZS33iC4b42XPH+dlz1s8i4LTZQBhyNEdKvJPluUmEjKG8qZttZeP7nwXrfX2BEO1M/+jsoTjt0hd0To53kpHgYtupM/vx991V/PdNq0nzuMiZpyNJjDFGRMZ95aXFhZRSKjaEQobP/WUP7d7xHWv/vruaa1fnTVOrlJp5+ypb+fEzx3hsfw0mBs9MjIGXjjXy0rFGNpem87Erl2iQeZpocFkppVTM8gZCdPqDbChOZfvpFtITXDhsgstuoyAtnqO17TR1+VmWm8TWYQJxSW4H20+PPUiX4LLz+etXcOmy7KnaDTVJ3kCQnadb2FfZSkuXn6YuH82dPrKS3Lx8vHHUKamRonkuaYwVcI5UkuGh2xckNyWOhg7viKlbYpnLYWN9USqBkMEfCNHlC3CyoZOTDZ391tt2qplrf/ACTrvwhrX5XLI0i4uWZJGeMOeLsNT2prsQkTygLry8EiiKWK8wvEwppVQMCgRDfPrPe3jyYN3oKw/wyN5qbj/ZxObS9GlomVIzZ2tZEz96+hjPHRn76P1o23Kyibf/4jUNMk8TDS4rpZSKWW/bXMzdL5dxrL6TzEQXDR1nivFVtHSTnuBiw4I0evxBPE4bXf7Bo0HjXHYcdhlU4G0opZkJfO+WtawvTpvS/ZgOIlIGtANBIGCM2Rjx3CeA7wBZxpjhS5jHoG5fkOP1HdZXXQe7K1rZcrJp1LQmo1lflIpNhMrm7ilq6dSobfeSGu9kd8X0p+qYLnabUJLhGVdg3B80/GVHJX/ZUUmi28F33rKWK1dkTyhH9SzxEHA78I3w979FLP+wiNyLVcivVfMtK6VUbPIFQnz03p38Y1/NhN/j/z19lN+9R+u2qunlC4SsGXNTeF7lD4Z4+VgDP37mOFvKZudgCIgIMpeEg8yLNMg8FTS4rJRSKmYtzUkkO8lNXfvQxfqaOn00dVoB500laYNGL3ucNorT49l+qmXE7Xzm2uW8/qw8CtPiZ9vJxWUDg8ciUgRcDZyOTpPGrscfZMepZl490ciuilaO13VQ2TI9wV9vIMiB6vZpee/J8AdCZCW6qW4de17lWBMMGWwipHucNI3hJs5AHd4AH/j9dj502SI+dc3yaWjhzBqmiv03gPtF5D3AKeCW8OqPAtcBx4Au4F0z3mCllFIjqmrpZufpFu56/vikbwa/cryRA1VtrMxPnqLWqfkuEAzxxIFaDlS3caS2naN1HZwK16DJS4mjKM1DcbqHovR4itI91leah8xEV7/rnmDIUNPWQ3lTFxXN3VQ0d1HeZH2vaO6mtq0bg0Q9p/JU2VLWxNt/qUHmqaLBZaWUUjFLRPjSG1bxoXt2jLheYWo8TruN9cWpuOw2OrwBfIEQJxs6qWzu4aLFmXiDIUIhw9G6Dlq7zwTA3nNhKR+4ZOFcOpn4PvBpzoyMjAktXb7wiOROjtd3sONUM7vLWweliZguB6rbWZydOK4UGjNhZV4yeypn76jlXodq2tlUkkbTBPJE97pvazmfuGrZoKKAs80IVeyvGGJdA3xoeluklFJqojq8AV73wxf6nTtORiBk2FXeosFlNSV2nG7mP/+6j/1VbUM+bwWJu3lliNok8U47RenxpHpc1LT2UNXSTWCEwPFIA35mMw0yTw0NLiullIpp64pT+x57XHYcNmF1fjLNXX46fUG6fAEqWrqpGGbEa01bDznJ7r6RJuuLU+n0BggZSPe4+OCli2brCYQBHg8XBvu5MeYuEbkRqDTG7I72PjV1+njleCMvHW/g5WMNlIVHUERTkjv2TnscdkGw/piz3dayZjYsSGNvRQu+4Pj36KzC1KlvlFJKKTUJ+ytbpyyw3Ksk0zOl76fmn+ZOH9/65yH+uKV8wu/R7Q9yZJhi6ENJT3DOyeByry1lTXz78cM4RPjYVUs5X4PM4xJ7V1lKKaVUhNQ4J8tyEunyB2nvCRAyhpdPNLG+OBW3087pppGDlh6XncaIXM07T7cAcNc7N3D1qtzpbPp0u9AYUyki2cATInII+DxWSowRicidwJ0AxcXFk2pEa7ef54/UU5qZgNth43BtO/e8dppXTjTGXNXo+nYvy3OTOFQTO+kxdpxuIdXjpCQjgV3lLdFuzqRtP9XMoqwEalt76PCNL0/26aauWT9qWSmlVGz4265KDlS38f6LF02qaOzRaZjx9PVHD/Gtm89iRZ6OXlbjEwoZ7t9WzjcfOzSmejJTyeOa2+HDJdmJ7KtsxR80vOOXr7GpJI2PXalB5rGas1VTlFJKzQ1bTzVxuLaD8qZuWrr8tHUHACtI7BpDkYpV+cm0dvsGLf/EA7tp6Rq8fLYwxlSGv9cBDwKXAKXA7nCxv0Jgh4gMiqAbY+4yxmw0xmzMysqaVDtau/z87pVTvP7/vcgd/7eVU41dpCe4WFeUSqydh1W0dFPR1MXaopRoN6Wfli4/x+o6WF+UylkFKWxYkBrtJk1KXZsXu338f/wT9R2UNXROQ4uUUkrNZd2+IDtON3Oq0TqGvHC0no/eu4ufP3eCT/9pN2aCd7v9wRB/3101lU0FYG9lK6/74QvcetcrlI8ySEKpXlUt3bz5Zy/z2b/snfHAMkxtccBYk53kprHDhz9i5t3Wsmbe8cvXuOXnr/DSsYYJf47MF3P71oNSSqlZ72B1O3bb4OIRq/OTqWkbughanNNGbnIcOclxHK3roN07eARle0+A371yio9csWRa2j2dRCQBsBlj2sOPrwa+aozJjlinDNg4sODfVCvO8PCH953DP/fXsK4olYJUqyhia7ef/374AA9sr5jOzY9bSWYCXv/M5Hkejw5vgJ3lLaQnOLHFWlR+nBZmJUyo4FHIwCN7q/nQZYunoVVKKaXmGmMMf3jtNN/+52Fau/3YBN5+TjFHas6MNn7yYB1/2l7BWzYWjfl9mzp9/Hl7BfduPc3x+um76fnqiSZu/tnLfP1Na7hkaTZ2nb2jhlHT2sPbfvFqX6G+aJipOikzLd5lx+OyD5vCrzfIrCOZR6bBZaWUUjEt0W2nIDW+X/qLzSVpbBmlcFggaHjtZNOI66R6nFPSxijIAR4Mn9g4gHuMMY9FqzFOu42iNA/5KfF9J1uvHG/g5eODi4dE24n6DhwxNvJiYVYCGeEpu7VtPZxuGjp/eKzLTnJTnO5h26mJF/W7d+tpbj+/hMQYzI+tlFIqempae2jt9pMY58AXCHGouo1fvXiy3zEnZOD3r54e9Nr7t5WPKbjc6Q3wm1fK+NHTx+gaZ2qniapt8/Luu7eRlxLHG9cX8OazC1mcnTgj21azQ11b9APLQL80g7Ek1eNkYWYCDpsgIhgMxtA3WMNgpRMJhgwi1nWLAbz+IJ2+APXt3jHVhtEg88hm7Zm7PxjiaG0HP3rmKILwzZvP0guREZxq7KStO0BOsgu7zUaC20Gc005rl5/6jh6S4pzkJMdR09pFbsrcLDDQ1uOnudNHcbqHjp4AtW09LMxKpLHTyyN7qnn+aAOXLsviqpU55KXE973OGMO+yjb2VrZiwiWXSjMSWJSdSE5yXLR2R6l5obXLTyBkqBpQrG+kSsYAPf4Qealxwxb567WzvIV3njfpZs44Y8wJYO0o65TMTGugocPLB36/nYxEF7dsLGJZThKnGruoHOX3Hw2F6Z5xFS+JtLkkHesUVSB8LhkMGfzBEHsmMFIXrLQth2vaODGNI6OmU7zLzsq8ZLp8AQ5Wt0+60Et5UzdVLd0szUmaohYqpZSazZ46WMvPnz/BllEGDIykonn08xFjDO++20rv5fXPTGA5UnVrDz999jg/ffY4qR4n77mgdFbOrlNTq77dy9t+8Sono5w2zGEjJs/r0xOcJLgc7AjX1JkJGmQe2pRFY0VkGXBfxKKFwBeB34aXlwBlwC3GmIkPaQGeO1JPnMPG+uI0fvz2s/UPiXWX9cVjDawvTsVps5HgtvP80Qa2lTVR1WLd5X3xWANxDhubStPxB0MszEykIC2e7/zzMJcuy8LlsLHrdAt2u5CbHEdGgpu0BBc2gaJ0D3detHDUQjvNnT46fQGCIYNNhDinnawk9wz9Fs7o9gVx2oVd5S0EQ4azF6RhE/AHDf/cX0NFczc/f/4EpZkJrC9O5dUTjVyxPJvr1+TR0u3n3+/bRac3wF23baSiuZv7t5Xz112VOGxCcUYCBalxvPPcEv68o4KjtR2UZiZwxwUlxDvtczoXkVIz7ZnDdXzl7wcGLXfYRu5n+alxtIwhF9klSyeXb1hZUuOdpHpc7KtsY1/lfgDeuC6fS5Zm8dyR+ii37gynXXBMYMrphuJUfEHDlrLhL2xT4p2keZwkuh143A58/hAuhw3EGhkxVJqIRVkJnKzvIDALZxl6XHZW5Sezp6KF7ZMYqTyUpw7WaXBZKaXmuW5fkP9+5AB/eG3wSOTxau8JjPh8IBjiT9sr+ma8bViQNuXHtvFo6fLz3SeOcNt5JaTM3ll2apIaO7y8/RevTmtqlrEqSk+IeoB7oN7AcvkYbh5Nh94g88YFaXzi6qWcu3B+B5mnLLhsjDkMrAMQETtQiVVg6LPAU8aYb4jIZ8M/f2Yy25ovwYCtZY08eaCOF481UJKZgDGGBJeDpTlJ5KbE8cieajwuOx++fDE/efY4f9pegcMmBEKGi5dmccNZeaR6XCzMTKDDGyQvJQ6Xw0Z5Uxe+QIjnjtRT09ZDIGR48mBdv22Xh6fk3ryhkPMWZrCuOHVMbU5LcJE2iWq8k1He1MWzh+v4845KLlicQUuXn3VFqWQluXlwRwU/fe4E/3n9Cv6+uxpfMES3L8j2U8247DY+duVSNpekc9/Wcr726EHinXa+dfNZBIIhvvGPQzyytxqA/JQ4VuQmccPafP65v4a7Xy4DwCbwp+0VNHf5WFOQgt0mvPuCUpblJpGfGj9Cq5VSI9lV3oItPH3JGxGBG+q4nRznYFV+MnXt3jGfhO0qb+HGdQVT1dx5y2G3cXZxKger2/qW/XXX1BfAmYw1BcnsrWyjJxAiJ8lN7TAjbBNddlYVpGCAbl8Au83G9jGMhmjt9tPaPfwNjeW5SbgdNho7fDjsQqrHSXVLD10xmP95JB6XndX5yZQ1drF1lNQ0E/XLF07wzvMW6Iw0pdSME5G3AF8GVgCbjTHbhlmvDGgHgkDAGLNxpto4H3T7gtz+6y0j3tQdjw5vgIPVbazIS+633BjD04fq+Po/DnGs7syspu2nmlmVn8z+qraBbzWj6tp7NLg8TzV3+njHL1/jaN3EZttNtTSPk5PRbkSEaAeWIzV3+bjt11tYW5jKx65cygWL52eQebrO2q8AjhtjTonIjcCl4eW/AZ5lksHl+WJZbjIP7arm3IUZ/GNvNVWtZwpXLclO7Pugef5oA+88dwEr8pL7Luy3lTXx/JF63A4bn79uBSLw5vWF2OyQlRSHwyb4gyHiXXZePdHE8boOvIEQmYkuNixIQ0TISXaTmxw3asfo8QeJc9qn7ffgDQRxO4Z//5YuH2UNnaR6XFy5Ioe8lDhONHSS5nHx02ePszQnCbvNytP13t9uw+2w0x2e6pQU5+BfL11EyMA1P3i+b8pUTyDIy8cb+do/DlLbeiYA0drt59nD9Zxu6uo3BTpk6MsH25tj9IWjDdhtwuaSdN57USlXrMiZ8t+NUnNZjz/In7dXsDQnifYeP8nxTg5Wt5OR4GJneUu/dVflJ1Pb1oM3EOoXWM5MdNHS5ac0M2HIk7Pr1uRN927MG1euyJmS0UXToTewDHCivpOcZDebS9LxB4MEDYSMoaq5h6YuH0tzk0bN1T0Rh2ra+y9ohHVFqcMGuWPJ4uxE0hNchEKG/VWto+Y7n6zGTh93PX+Cj1+1dFq3o5RSQ9gHvAn4+RjWvWy6i+bOR95AkDt/t23KAsu9PveXvfzmXZtJ8TgxxrDjdAvf+edhXjkxdH2Ipk4fDhtRnV2UnaQpGOerr//j4OBzxyiKtXolKfGumBhJneS20+kN4g8atp1q5l9+ZY1kno9B5ukKLt8K/DH8OMcYUx1+XINVhEiNwhjDX3dWcsnSTLyBEDWtPfhONtLeE8AbCHG0roOSDA+LshIxwPefPMKGBWlkJbmpb/f2FSDwBkJ86aH9pHqcLMpKJDclrq/gziVLs8hMcHPD2vwR23K0tp2MRDfpCS7ae/zUtXuJc9pxO2wkxTlwTfEHzc7TzbgdNnZVtLA028rbWdPWw7svKGVXeQu/fOEEt24q4uJlWbx6vJFnD9fjCwSpbushFLLuHMW77Jy7MIP73n8e7/vtNnZFBKK6I3JovefCUiqau/nWPw/REJGg3h80/O7VU/3aleCykxLvpKnLR1mDdQd8c2k6eSlxhIx1h73TG6DTF0CAi5dm8dZNRaR5XHhc0xd8V2queuFoA+3eQN+JlSB4XHaW5CRijJV732G3UdXc3TeypCA8U8BpF0ozE6hq6UYE2sIjSkXALtKXs/n3r55iU0l6FPZu7rlseTZv2VDIA9srot0USjMTaO32YRPBJsKxASPZa9u81Lb1D+rabcIlS7N4/ujMpfHYVd7C5pL0Kb+Anoj1xak4bDZsAlUtXbR0+XE77Xj9wX6juWbKXc8f59pVuazMTx59ZaWUmiLGmIPAvAoIxJofP32MF45Ofcx+V3kLF3zzaVblJ1Pd2tOvUPRQqlt72FSSNm2zdEazIi9ZRy0PQ0R+DbweqDPGrB5hvU3AK8Ctxpg/hZfdDvxHeJX/Nsb8ZrrbO141rT08uLMy2s3oJ5Y+EUsyPDERWAZYlJ3IrvL+qe/ma5B5yoPLIuICbgA+N/A5Y4wRkUFVmETkTuBOgOLi4qlu0qwkItx2XgllDZ1UtnTzueuW09Dh48/bK2jp9pPgsnPhkkyW5STx3JF6XHYbQWOobO7G47L3q2779Tet4U1nF+Cw2dh+qplfvnCCQ9XtPH2ozsq1bLexuiCF9cVpQ7ZlSUTew6Q4J0lx03uQ21PRwoM7q9hX2cq1q3NZnpvE2zYX87ddlSTGObhlUxFH69pJ8Tj52qOHKEqP581nF/LHreUcr+ugIC2OV0808eqJJp45VDdiDuQfPHl0yOWr8pN5/Vn5GAxNHT7WFKZw5YocEtwOnj9Sz69fOklVa09fYYmUeCclmQlcs9IaOb22KJVAyJCZ6MbtsMX8h0k4lc02oNIY83oRKQXuBTKA7cA7jTGxWR5WzVn3be0/CrbDFyA9wcWrJ4YPxMU57awtTKHTG+hXtC0p3kFxhocObwBfIERJZgLZiW7+643Dno+qCbhyZU5MBJcbO70kxTmpHMdUuY0L0qKSH3pneTObStJo6vRxqrFzxkZI5afGkZ8aj2DdiN5V3oIJn6FtKE6lvLmHdu/MFzTq1eMP8eE/7uDxj10cc6NllFIKq7rr4+Fr258bY+6KdoNmM2MM3kCIQ9Xtgwb4TKUOb2Bcs5MG3oieSQer23hsXzXXrtZZdkO4G/gRVn2vIYWvb78JPB6xLB34ErARqw9vF5GHJlsTbKr96sUT+IMjFy+faaMVU59JOclxlDWOfHNoJhSmxQ8KLEfqDTJvWJDGx65cwoWLM2M+LjQZ0zFy+XXADmNMbfjnWhHJM8ZUi0geUDfwBeGD8V0AGzdujJ3/2hhQkplASWYCAIVpHtYVpVLZ0s13/nmY10408dedVdht1p3Vtm4/bqeN7nbrYtDtsPHK564gzePs+yfeXJrOuqJUvvDgXh7YXtF3V3h5bhJrC1NZX5zKWzcVzcg/fTBk8AaCuOw2Dte28+ftlTx9qJZzSjO4YnkWHV4/r55oRET44O93sKWsie/dspa7Xypj++lmbCIEQ4bDte08ebCOvJQ4qlt7aOzwsrk0nWN17UMWUBrJspwkPnjpIt6wNh/7MEWfLl6axcVLs6ht6+FwTTtHatv50/YK9lW20uMPkhRn5+E9VTR1+dl5uoWzClN46MMXTsWvbDp9FDgI9A4R+ybwfWPMvSLyM+A9wE+j1Tg1/7R2+/ulngGruMloRfpCxgzZ74/VdQLWHW63w8ajH71oxHQ7amIuXZaF0y5RPyFu6w7Q5Q2wLCeJFI+DfZVt/W66DiRijYQXrCuNmeQPmr5RUUluB8tykzDG0NTln7JRGR6njcXZScSHZ9F4AyEO17RT1dIz5PreYGzkgT5R38lTh+q4ZlVutJsyZUTk34H3Yv2r7QXeBeShN3SVmjEi8iQw1AfLF4wxfxvj21xojKkUkWzgCRE5ZIx5fpjt6UCqIdy39TT/+9Qxmrt8dPuDfTc41xWl0tzVEtW29Trd1MXaohTcdntUZhl96oE9FKV7WJWfMuPbjmXGmOdFpGSU1T4C/BnYFLHsGuAJY0wTgIg8AVzLmVn3Udfa5eeeGEwz54+Rc0OwBpHEgoLU+L60qiPZfqqZd/5qy5wPMk9HcPlt9O+cDwG3A98Ifx/rAVsNoyA1nrdsKOQHTx2ltq2HHn+QkLGmfXsDIew24fu3rmNlXhLpQxTXO1Lbzo3rCnj7OcXYbcL/PnWM7GQ3167K5aIl0/+P3tjh5WhdB//YW82WsmaCoRAfvmwx3kCQm9YX8Ni+GoImBZfdToe3m7KGTvZVtbIqP5mnDtVR3drTF1iOVN3ag9MmrC5IobXbT1PnyEGoofzPTavZOMYp8jnJceQkx3Hx0izOXZjBjT9+iaO17aQnuHjXBaW8/+KFHKntwMx4qGJ8RKQQuB74H+DjYv0DXA68PbzKb7AKm2hwWc2YlHgnly7L4smDdTR1Dh1jSXDZCYRMv0J/Jxs6KUqLH7G4gzcQ4vN/2cd/vn4FqZ7oFCCdq9wOO7duKp7WUUdjFQjB4dp2UuIdZCS66Goa/n/CGNhxuoXV+cnsi2LxnnZvgG0R1emX5SRxtK6diQwWWZ2fTIc3wKmmLrr8IfZUjv1m66kYGA3S6/tPHOG8RRkkT/OsqZkgIgXAvwErjTHdInI/Viq565hHN3S9gSCNHT6yktwjzi5TaroYY66cgveoDH+vE5EHgc3AkMFlHUg12LG6Dj7/4L5B13MQThlVmt43QzTadpe3srlk6Bm+063dG+Crfz/Afe8/Lyrbn63Cx9ubgMvoH1wuAMojfq4IL4sZv3/tFJ0jDIiIlpCJjY8umzDqYKOZ4LTJuHNi9waZzypM4ab1Bbz+rHyyktzT1MKZN6XBZRFJAK4C3h+x+BvA/SLyHuAUcMtUbnO+On9xJucvzsQfDPHaiSZePt7Aw3uqqWzp5us3rRkxj/Lqgv53Pn95+9DFjUcrpDeaQDDEjtMt/N9LJ/n2W9aS6HZgjOFkQyef/fMekuOduB02cpI9PLK3mn/uryUn2Y3DZuPx/TUkuB0szExkb2UraR4nB6rb+lXsvf6sPN6+uRhfIMTvXz3FU4fq8IcMtW09E6oaevXKnDEHlnv5gyE+9cBuXjreyN8/fCEFqfH9cmPNklyRPwA+DfTmP8kAWowxgfDPMXfQVXPf3soWTjZ0sigrgUVZCfiDIeo7fKTGOzlS286q/BQOVreyNCeZvZWtZCa6yEl2U9Hc3S9/+nD+vKOCnkCQH7/97BnYm/lj+6nmmAgsC1Z6owS3g/KmLspHCCz38rjsJLgdUS/eE+lwbfuY8z0mxTlYkZeMMYbj9Z2TCpK39wSimmcy0qGadj55/26+/Za1pMTP/gAz1rl3vIj4AQ9QzRy4odvhDdDtC5LktlPR0k23L8iq/BRs4QLSzx2up8Prp7XbT3tPgLMXpOKyC+XN3bjtNpwOG6eauqht6+G61XmkDTE4YjRVLd0kxjnGdCOiscNLIGTITnKzs7wl/DnRhc0mXLYsm4VZCTq7RQ0rfM1rM8a0hx9fDXw1ys2aVX7yzLEhA8u9tpxs4pzSdI7Xd4zpvG669fijd2Kw/VQzHd4Aie7pKpc1J/0A+IwxJjTRgXPRmnHw5x3RTy8Xy0IGEt0OevxBOqKYvm1NYQo7TrdM6LV7KlrZU9HKfz18gAsWZ/LGdQVcvSpn2tPPTrcp/YQyxnRiBaYilzUCV0zldtQZTruNC5dkcuGSTN5/ySKqWrpZGpEjeaJau/0TKkJX3+7lleMNXLw0i589d4Katm6++PqVBIIhHttXzQWLM4lz2vmP61dit8Gj+2p4eHd1X5G9yLxWbT0BqlutKbvNXX6K0z2876JSluQkkZcSR0uXn7VFqYA1FfuRPdX87LnjnJjANGIRyJzAXSObCG9Ym8/Hr1pGcYZn3K+PNhHpLYSwXUQuncDrdZqfmhb/92LZoMBWZqKL/c3dbFiQxsmGTrwBQ0qcg+W5SRyqaR/3xceS7MSpbLICunyB0VeahHinnaU5iYQM7B1mJK6VFqlj3MHVeKedPRUtMRNYjnR2cSoHqttYlJVIgtuOYBWl7PEH6fEHSXA5CBozpaO89lS0siQ7kaNRKOY30LNH6qlr65n1weXwFPrvAKeBbqw8kNuZxTd0e8IFH+vbvdS09ZDkdhAIGZLjHPT4Apxu6SbB5eD8xRmUN3VxsqGT9IQQOclxvHayiXiXndzkeBZmJlCc4ZlUQDc/XNB1LDIS3VQ0d/HDp46yt6IVbyCEiHU+eLKhk7duLKLTF2RNQcqQswDV3CUiNwH/D8gCHhGRXcaYa0QkH/ilMeY6rAL1D4aDVg7gHmPMY1Fr9CxzqrGTv+2uGnW93tzIBanxxDltpMQ72RlRH2AmxUWxOHsgZHjiQA03rS+MWhtmoY3AveE+mglcJyIBoBK4NGK9QuDZod4gGjMOmjp9nKiPjUJ1sayssYtluUmcrO/AF6VUfIEp2G7IWAXsXzjagPtBG1euzOHGtflcuiwbl2P2zezS219zSEq8c8ouvMb7PqcaO/nNy6coSI0LF+SrJD3BTXVLDztPN/PDcOqNS5ZmseVkE4luBwdr2thb0TrmtBHVrd2sLUrlrMJUABZE3MYQEV6/Np+Llmbxxb/to6qlm/p2L1UtPSTGOViQ4eF9Fy2kqqWb547UU9bY2TeS7YEPnMeG4jQmclPTbhOuWJEz/hfGjguAG0TkOiAOK+fyD4FUEXGEL3YLsQ7Eg+g0PzUdatt6+PuewRcdzV1+4l12tp9qJjnOwTml6eyqaJnQXWuXw8Zly7KnorkqrKnTx7f/eXja3n9FXhK1rd6+nNoFqfFUtpwZkex2CGcVpk44wNrY6Yt6WoyBzilNZ19la9/0yP0z2DZvIMTRug7yU+MoSvOMqwDSVEv3uCY0kjXWiEgacCNQCrQAD2Dlehzr62Puhm6c0z5oRlyk5blnzieX5SazLPfMjK5FWf0HQ0wkdNPY4cXttE9oRF9hmof3XrSQDq+fF4828vj+Glq6/Gw92cTfd1fhcTn4+TvP5kgtPLKnmmW5SWQluTl3Ycasv9GhhmeMeRB4cIjlVVgpbDDGnADWznDT5oRAMMRX/n5gxFHLA0Ue65PiHIjAitzkGT0uHavrwO0QvIHoXO784MmjFKcnUNHcxY3rZs39x6gxxpT2PhaRu4GHjTF/DRf0+1r4eAzWrIPPRaGJQ9pxKvozxmaLwzXtnFWYMqhGz0ypah3/TPmReAMhHtlTzSN7qkmJd3LdmlxuWFvAOaXp2IapBRZrNLispkRGopubNxTw8vEGLlmWxYGqdp4/Ws/CzETu31bB8twkSjM9fOL+3STHO2nr9pOTHEdSnIOMBDeFafHcuK6Alm4fh2vasYtwqqmLQ9VtdPqCuB02vnLDqr7A8nBS4p388Nb1fT+39/hJdDv65ZF+70ULAesDKc5pY0FGwrT8TmYDY8znCB9QwyOXP2mMeYeIPADcjFVgSHOlqxn1i+f7V0jOTHRRmpnAifpOFmUn0tETIDnOukHV4Q3itAn+cSal/dIbVvbNfFCTs+N0M3/dWcmft1dMOkecTaAo3UNmohuHTTBYKS6C/5+9+w6P86oSP/4904tmNOpdltx7j9N7b4SS0ENCWZZlaQsLhLILu5SlLe0HC4TeIZRQQyCQXh07rnEvkiVZvY80fe7vj3ckS/JIluxpku7nefRImvLOGWnedt57z4krtjf2jl6KLHbbKM93UOKxE4nFyLNbOdrpP6cyDvXFLg605U5iGYyR4Nmuu3eyL0g0pqgvdqesweBMtQ0E+crfD/OJl67Oyuun0DXAcaVUJ4CI/BbjIq++oHuWivLOrVZhnt1Cnt3C7ZuquX3T+FGBkVicHzzVwJ6WfnwuK43dQ/QMhQlF49ywqpy+QBivw4rDqstnaNp09AcivPPnO3j8UOdZL2MwaEzyCGR439gzFGZzXQHbslQuqrF7mFd842lE4LIlJXPiguu5EJGfY4xALhaRZuBjgBVAKfXNyZ6nlOoRkU8Azydu+u+R5n65YPsJnVyeid3N/Wys9Z11eYqzVeCyprVcT38gws+3NvHzrU2Uex28ZH0lt62vZGWFN6cbAerksnZWhkJR7t/RQmP3EGur8jnU4edA2yCLS/LwOqzcsq6SZeUeLlxURO9QmCMdQ/zjQDsH2gapLXIRiyuaT/Syv/XUifxrzz99FI5SipP9QZp6htlQ65txnFPVrVlWfu7lQ+awD2JMJfoksAP4bqoW/H+PHuH2TdWUehypWqQ2h/QPR/jphA7JShnNXSIxRfeYUSqLS/PoD/hZU52PIOMOyERgZYUXq9lEMBIjz27BYTUTjMQo8di5bElJxt7TXKaU4v2/2sXRFEzhW1Xp5WiHn8bu4TM2lKsqcLI9xaM7uvxhVlbmg2JGze/SYV11PmaT0JClZO5EHYMhGAxldYSIfRZOD0ziBHCBiLgwymJcDWwDHkFf0B2nfzhCU+8wJR47Zd7UHi8MBiNJjw+jsTjtgyGqEuU1rGYT/3TZQo52+rnv+SaePdbNyf4gS0rziMXjLCh0s7JSn0pp2nQ0dA3xph8+n7Ip/+FY5mtYbWvoZUtdAVuz2I9AKaNMxnynlHrNDB5794Tfvwd8L9UxpcL2HOh1MRlnjl5I7fSHzvygFKvyOenNUFPBtoEg9z5+jHsfP0aJx87mBQVcvLiYlZVeVlV6c6o/hD4imuOisThbj/dw0eLilCzvkYMdoBShaBy33cw/XbaQfIeV61Yz+sHu9oc40unHZjHxzNFufrH1BJ946RqePdZNKBrnqSNdXLSomDs2VbO9sZedTX28+ZL6pK8nIlT5nKMH+lr6KKUeJVFzKjHdb0s6XudfLl+U01fctOx69nj3aA32EfXFbrYlSSRGYnHOry/keNcQHYMhFpW46QtEqC9yc6JnmP5AhL+/93I9qiyNuvzhGTe5Kfc6WFDkQiljRHKnP4TXaaFrMERwGgWP7RZJyzZkMBgdTZxuWlCQ8uT1dK2q9I6W/sg13f4wq6vy6RwIUulzYrOYMjYtuXso+w2dzpVS6jkR+TXwAhDFuHh7L/Bn0nRBN1dFYnFa+4Ic7hjkQNsgLpuZ3uEIHQNBuvwhOv1hlpTmcemS4pRPAZ+YWG7uHaahy9hnOG0mugYCtA6EONo5RFPPMDub+jjYPjha57VzMMTTR7tZUeFFODU1Nh5XLC3zcO3KMm5bX0V5fuovoiulEBH6AxGeO9ZNvtPK5rpCdpzopTjPTlWBE4tp/DYyGoszHImNNjpUShGJqVlZz1GbnYKRGG9OYWIZIBrPToOEF070jfb6yAabxaTrwM9R4WicXc192Q5jUi+29FOZ7+BkoidWrmjqCWR89LI7S801OwdD7Grq468vthFXxvZgbVU+mxYUsHFBAZsWFFB8jjO6zoVOLs9xFrMpZYllfyiKzWziwoVFk9Z9eeFEL/c+dpQVFV4ae4Z5vqGH5t4Ar//uc3gdFhaWuHng3ZeO1qq788K6lMSm5T6lFPtbB1le7jmr+tba3DcUivKDpxrG3WY1y6SNW8aOcN1SVzjajGlsIvr133mO/33lunld/iadivNs/OQt53P/jhZ+/EzDGa/iF+fZCEZj55SQXFdTkNLGdclYslTbzGO3cLIvtTXcUqmlLzBa+7J9MMSS0jzsFqGm0I0/GKFtIH2jR/qGZ39yGUAp9TGM6btjpe2Cbi7pHQrzt31tPH20m7+92E4gEmN9jY+rlpdS6XNy4aIiqnzOc+6WPtLo0uc6lYDxh6Ic7RhkT4vR76Ohe4je4TBd/jC9w+GzahA2dvbdiG2NvYjAhYuK0pJcPt41REW+k//3j8N858nj2C0mClw2ROCChUV0+UN4HBY+/pJVtPUH2d3cz4meYaoLnBTn2bluZRkWswmbRR+IaZnzk2cbUzLDKRdE44r2gSAV+XZa+zM/YnJRSR7mWVJ/VZuZfa0DhHKxq3TCcCROpd2MxSQ5N3q+N0PHiHl2MysqvKhsdBVNqPCdSvCHo3G2NfaOO/etK3KNJpqvWVGW8tlfU9HJZW3a8uwWLj5DovpIh5/rV5dzpMPPsc4hlEpM34nFqS5w8fnb1+kmKPPU/tZBbvrqE7zrqsW897pl2Q5HyzHhaJxXfOPp0ZEgtYUuHFYToUh8WvXHBoJhDrT5T7t9W2Mvr/jGM3zs1pXcuq4y5XHPdyJCfbGb9167lH+5fBG/3t7Epx7Yn3Q0c5HbhsdhPae6vWYBfzC909C21BWyP0u1lwdDUTbU5NM7nJsjlyc63OFHxNj3b6krTGtyOcfOY7QZiMcVO5p6+fQDB9je2EuBy8o/X76Ql6yrpK7InfJGNQ6rGREjoWwxCXaLie2NvfzXH/ZyrGvqkjtno8Rj5+JFRZy/sJDKfGOq7OrKyZscThSOxqc9irjYYyemFB+9ZSXvuGox4Wicpt4ANYVOvA4LDuupU7tSj4O11T7C0TiBSAy3zYzFrEcra5k1GIzw9UeOpHy5ZsneZ7l3OEJ9sSsrr72kNC8rr6ulX7ZmzM3EkY4httQVsrUhZ8pUA9DQPYzNLIRj6TlYXF7uwWUzs/fkAM839LKq0nvmJ6VBbaGLFxr7pnxMQ/cwDd3D/PaFFv7jd3u5ZEkJr9hYxfWrytM+m1cnl7VzFo8rjnT6uX9HCwdaB+geCo823uoYNE40//nyRbz9Cl0OYT4zmeCq5aUpG0mvzQ0DwQjfeeI4P36mgf6AkTQsz3cQisQ40TO9JEBxnm3KxFOXP4TOS6Wf02bmzgvrWFSSx0d/t5djXUN47BZWVHpBwZFO/zklltdW5bO/bYB9remdinqwfZBSj51Cl43BYDSj5RhMAtYcqp02HSODN0bW33TYWOvjAzfoi5KzUTAS4ztPHGNrQw9eh4V/vWIRd11UR+kMRtL4gxF+tb2Z8+oKWV1lJG2beoYpcFkxieCyW4jG4nQMhugZCvOfv99LMBInrhRD4SjBSByb2ZTSWVNLy/KoLnCxsNiNw2rmcMcgD+xpY39i+/Tc8R4Otw/SOxzGZTOaBl69opQt9YWUeuyYTSasZuHTD+zn6aNdrKrMp8Rjxx+McsWyUm5bX5n0mNk7ZlS3z2UjFldE43F+/twJuofCXLW8lCuWlY57js1i0iUwtKz50kOH01KbNBiJYjYJsSxdeYykKYl1Jot1cnnO2t6YWwnbyWxt6GFLfWHaZxHOhFJQXeDiWIp7layu9BKOxU8rg9OXxmPeySwty6NzcGbntHEFjx/q5PFDnXjsFm5eW8ErNlWzeUFBWvJyOrmsnZNYLM7DBzto7Q/SPhBkIBjFaTWzodZH+0AQc+JD+/m/HqTK5+SlG1JbN0+bPZaXe/ne3edlOwwtx3gdVswCCwrddA6FqPA6sJiE56Z5RXxlhZdQNMah9tNHLY/1xb8d5MKFRZR4sleHar64aHEx/3jf5Wxr7OV7Tx7nL3vbUrJcs0kycjLXH4iMJkrri10sKHIxHI7RMRCkJ83NOzYtSH/Jj3RpHwymbNRIlc/J8nIPyys83LSmglUzGAWq5Y49zf189sEDPHmkC4AfvPG80xKfZ7KrqY87vvnMaPOu61aW8a07N6GU4puPHePOC2p57FAnRzv9xJViWbmHixYV8+yx7qS1+lPlaOcQh9r9PDzmtqVleRTn2Tjc4edX25pOmzb8zLHuSZfX3GtMcbVZTLQPhFhR4R1tPD1SZzmZF0708svnm3hoXzuFbhvPHuvmh083sLTMw8YFBXQMhghFYpTnO7hsacm45LSmpdue5n5+8PTxtCy7sSfA+mofdquJQCSW8WazPpeV5t7Ml7Fy2WbXBWhtepp6hnnsYGe2w5i2rcdzL8Hsc6Vu/+ZxWKjyOdl7MvlMxu4MNxHctKCA3U19RM7hYtpgKMovnm/iF883cfXyUr5z1+aUJ5h1clk7K9FYnPt3tPDAnlaOdPhpmmLnuqWukA/csIxNCwoyGKGmabNFx2CInc19LCh0jiYDnFYTa6p9kx602Cwm1tf4eP54z7Su4DZ0D/PMsW5uWl2upwVngIhwXl0hh9oHU5Zc3tfaT6nHPjojJhOOdw1zHGMEvQisq86n2x+mOQ11kfOdVg53TH2RJJf1DUeoKnBiM5vOaoS6zWLitVtqee35tSwt86QhQi3TmnuHOa+ugMFQlF1NffzomUaWlHmm1aT5ZF+AHz7TwK+2NY8mlk0Ct66r5DtPHOdTD+znxtXlfP3Ro+xu7icUjRONxfnjrla6/CGuWFbKproCvvXYsbS8t2SjJQ+1+1lWlofDYmIoHEvyrDMLR+PsbOrj4QMd1BQ6CYRjvPbbz7GmOp/KfAcH2gYxibC6ysuh9kHMJhO/29mCUqdmDxxq93Oo3c+PnmkcbZBb5rVz0aJiVlR4eOn6Kkq9DoKRGJ2DIfoDEUSMi72VPicjVUpScdJ5oG2AB/e0cbx7iMUledx54YJxtbC1uSsai/Oh+3entaTRzuY+lpTlcbjdz/LyPLwOGz3DYY5kYF+ajcQywL2PH+Oui+qw6mPZOSMai/Nvv9x51vuNbMmlBLPHbsEfiqZmWQ4LJXn2SZt2ehwWBoOpea0zMZskLQNP/nGggz/sOpnyhsk6uazN2N6Wfv6xv4O/vtjGsS5/0tqaYJwEvOXShXzg+mU6maPlvN6hMG67RU8dzbCOgSC/33kSMEahjAgktit2i+m05hYmgcp8x4x3tO/6+Q5ab1zOuhofG2p92GdZ+YHZqCOFNXhDUUVdsTujyeWxlIJdzf2YTcLSsjx8TisvnhwYPRnYWOvjSKefgcDZHXAuLcvj+Ybcr7c3lZbeAJvrCmacXK4tdPGjN22hrlg33symqUbIno0b11Rw45oKXnfBApp7AwTCMY51+vE4LGxr6EEpuGxpSdIkidNq5oE9rfSMKUsTV/CXva185hVr+dnWE6dduKopdFLudXC4w8/jhzpTftI0lfPrCzna6efgGWbRTEcgEuOzDx7gC387iMtmZjAY5WD7+JPcB1+c+qJdy4QLYO0DIe7f0cL9O+BzDx7EajaNJp7HctvMfPnV67lyWSkWc/LPQjASQymjFNKxTj8um4UCtxWryXRa/eyFxXm86+olKa+rreW+Hz3TyN6W9Pcv8CV6+Yz03VhY7M5IuYy+4choYjuTrGYTJl1mck75xqNH0zrTJp1GEszPJ/bp2VBV4ATFGWexTsdIYnmq8hr5Tmvak8v5TivLyz0c6xxKW/L+v/+4j8uWlFDgTt0FX51c1qbNH4pysG2A/3vkKLua+xkIRghP0dH0J285n4sW6fq62uzwtUeO0OUP8ZVXb8h2KPPKd586nvRK8+YFBZR7HXQXOE/rMB5X4HUa5TTKvKc65k7H//zlAAB3X1THx1+y6tyC16b05b8f4qsPH07Z8mxmoS9D3aCnEour0QNYp9XM4tI8YvE4L5zoY1m5h8UlZmJK0TUYPi3BM5W5cq647+QAFfkOWqe5Xi4pzeMnbzk/o92sNYNSil3N/fx+Zwt7W/ppHwjxknWV1Ba58DqsVOQ7WFXpnfYAgVA0xhf/dohVVfm8ZEwDVbfNwtqq/HEJxosWFdHaH+Ljf3iRxw934rZZKM93cOGiIjYvKKS6wMF7r13KZ/9ykLaBU5+lPLuF1r4gDquZSxYX0x+IcLB9kHA0PlryYVNtAR3+IN97Kj3T8QEcFhNrqvPpGQrTNxzhuTSc/MXiKi0nsNG4IhpPPkJuKBzjE3/az8F2Py29wzT1DDMYilHuteOyWTCbhNa+ABcuKuKfLl3IFx86xJ92t2IxCSJgM5uIKcXyci+LS/NYVJLHVctLWFrm0X1X5pGTfQH+928HM/JaExOtx7qGOL++MGXr5Jb6QgB2NPaeNiW9MAuj8C9bWoJZX6yZM3Y29fHlf6TuWDkbth7vYU2Vl2OdQxkffb2q0suJ7iEGQ+f+ui6r6YyJZTBmLWys9bGvdWDSQZZnqzjPRl2Rm13NfWk5rhjLH4riD0V1clnLLKWUUcdKwXA4RkwpqnwO1uXl4w9F2d86wEAwSonHTpHbRlGejYsWFbO4RDcc0GaP/7hlZbZDmJccSUYPr6jwcLzLTzAaOy2xPGJ3cz+rKry09AdYXu7BYTXT5Q+NTlN02cysqcpHKZJ2NB45WdDSx2YxpXQUQzimcq5eaCASGzf99uCYKXQmMWqktfUHz5hk3lDrY+vx2TlqZaLhcIzhcIwSjx2rSfC5bDhtZuJKYTWb2NPcNzoz4dIlxfzf6zbiybH/63zRPRTmnT9/gaYxs0a+9siRcY/xOCzcuLqca1eWs2lBAYWJk5B4XPHs8W5+s72FRaVu3nRxPXaLiVdsqsZmNnHftiaOdvjZe7Kf4jw7lywu5tFDnQjQ2D3MwfZB7rpwAQ8f6Bi9EHGkYxB/MMofdrZwsM3PtSvLePnGKv7v0aOj8fxu50luXF3Bu69ewnvv24lS8InbVvGR+/fy4pjaiItK0jt6MRiNYxKZdB81GzltZmoKnLhsFp450kU4Fqeha5hOf4hdEx771NFufvbcCboSI8tH6ktHYsYJ/s6mPnY29QHwy+dPMBCM8tL1VVyypIjz64tw2/Up6Fz21X8czliSKdkavr2xh7oiFw3d02sMPZkCl5WjHX66h8LUFDqxm00cGbPOp2oa/ky8eDKztaW19BkKRXnPL3ZkrSllKu1pGaCmwEm+S3Gyb/qDfs6Ww2pibbWPbQ09KSu9s7oqn63TnEH4wok+agudxFVqS+RUF7gyNor97VcspqbQldJl6j27dkaDwSjPHOumYyDI8a4htjf0MphkZ/qmi+v5lysWZSFCTdNmqxcnNEpwWEzcsamaX29vmXQ6pUmM6UJuu5m+4Qh9iSZrPpeVDTU+jnX5iUTjPHe8B5tZqPI5xyX3rlxWwk1rKtL3pjQA3nxJPT999sSMRu+eiT+U+e7MZyuuYHtjL3aLiS31BcTi0NYfNJKuZkEwTooHg0Y92vU1+VhMJvyhKMc6/SlpjJdNnYnyJRNnFpR47KypchJH+MId63RiOYuK8+z88I1buOObz9A9FCbPbiESi48rRTQYjHLftmbu29aMzWzijZfU8aEbV2AyCce7hthxopfXnl8DwH3bmrj38WOjCVe7RXDbrAyFe/jLntbTXv8HTzcAUOi2sbgkj5P9AbY19rKx1kc0rk4re2ESeNvli9hUV8BH79/LcCJ59f8ePoLPZaXLf2pmQ6HbltbEb5nHTmCW1cc8k7VV+Wxr6GG6m56ZzBrqGQrzvaeO872njmM1CzesruC/X7KKYDRGodumy1TNIb1DYe7f0ZKx11NJrmJH40YN8rOpjepzWVlY7GZ/2yC9Y5r4NvUEMJvEKAGQ6PeRjYskB1qNmRq6jN/s98k/7zvnCyC5pKk3gMduZnWVN60lcTYtKOBE93DKy0XMtOzeiZ4ALquJDbU+dpzoS2ks6VZb6OKfL1+Y8uWmbIsoIj7gO8BqjPOlNwHXA/8EjLS+/LBS6oFUvaaWXgfaBqj0OXFYzeQ7rfz4mUZa+gKTTt0dDmf+6q2mZUowEuP3O1sIhGN4HFauXF46OoJLOzsPH2jn7/vbx932lksX8roLFvDiyQH2tQ4gAuur87FazLT2BajId7C/bZChUJS4MqbUjzRB6xuOsGO4b9zywjFFodtKudeB1SJcuayUV2yqztRbTCsRaQAGgRgQVUptFpHPA7cCYeAo8EalVF824rNbzDz5wSvZ2zLArV97MiXLdNlm3zXxUDQ+blRyS1+ANVX57G3pHzfiamfTqdFIbpuZDbX5hKJx7BYTcaXoHAwRjMbJs1s42uGfViPLXFRT4GRbYx9xBV/5x2EuXVzMmup8qgtSO3pCm56eoTDBRO3d4XCUzXWFnF9fiMtm4WDbAF1+ozmW2SSsrPRyfn0hP3+ukYFglJUVXpw2M++9bxfhaBx/MEq+yzrawHl/6wA90yhl0zMUZm+knzVV+djMJl6YcJJ2yeJilFKsr/URi8e54UuPj0tsJhs19HxDL1vqCpPOXEkFr9PK7pbZPYLQYzdT7DEa+w0GIrQPBFlR4WXvydQnBdZU5XO8awh/KEokpvjjrpO4bWbu39FCJBZnTbWPN11cx/WrynFYdaJ5NvvzntbTemWk09Ak0+F7hyOsqfLS7Q+f8ULIlvoCUEJj9xD5Lutp26ARsbhi6/EeSj12VlZ4efRQZ9LHpZPDapozZbTms7++2MbPtzZlO4yUGwzF2NsykNLSNCOWl3uIxOJsT8PI3rHnkzMxHImz40QfVT4H1QUumvsCtGSp2edMfPwlK9Oyr03lWdpXgAeVUreLiA1wYSSXv6SU+kIKX0fLkAKXDZfVzI+eaaSxZ5juIeNqzmTTnG9ZW5n8Dk3LUdsaetjfOsBlS0tYUDR1I6lD7YN88Dd7Rn/Pd1p56p6ryNNTO89avtNIQuxp6afUY8dts7CsPI9vPHqUxw52sqjEjctmZkci6ba0LG/cdKXpThva0zKAx2HhgXddQk3hnGsYdqVSqmvM7w8BH1JKRUXks8CHgA9mJzQQkaRNo87W/kk6N88WPpeVRcV5DIWjUyaHh8KxKQ/KF5W4Z+V0/M11BWwbsw7/7LkT/Oy5EwCsrvKysbaAj9+6Sjf/yqCNtQVU+pwc7vATV0btxB0nennqg1eR51hAz1CYinwnZpPw3SeP808/2p50Cm+hy4pC4XVYaOkNjKuTPBWn1cSaKh8mEzx7LPln/skjxibuqaPdM3pve1r60nKCC9DUM0ylz5GR6b/psHlBAUc7/aPNN61moaF7mLoiF+fXF9LcO0zLOby3sc14TSJ8/CWrONRuXBgOhGN88e+H+MXzTaOx3LSmghUVXp1YngOOnEWC5ly47ZN/ZvYkRk8uKnFjt5jp9odQQF2xmz3N/QQiMap9Tl5o7Bst7dI+jdGLHYMhBoM9WEzGKOlMevc1S5M2QdVmj46BIPf8Zne2w0ir5473sL7ax8GOwZTM8jmvriCtTa/znec2i66lLzi6z1xU4qY4z86BtkH6AzObcZmJeurXrCjjquVlaVl2SrIiIpIPXAbcDaCUCgNh3bhhdivzOtjd3EckFqeh08+CQjfHu4eSNvFbXeWlPF8349FyUyAc44+7TnLNyrJxo4031xXicVj58t8P09Ib4IbV5dyxuTrpNO211T5+968Xs62hh7b+IF6nVSeWz9GmBYX85l8uYjBojJh69b3P8dHfvTi6Ix6p5Qiwpa6QvS19Z/1ahW4bVb65PzJSKfW3Mb8+C9yerVhG2CwmFhS5aEzB1L9Sjz0ly8mWhcVutp8494PjY11DbKkrpGc4nPET+elaXJpH/3CEUq8dl82MiPBC4+RJvr0tA+xtGWB3cz+rq7x88IblumRGhly+tGTciJ1ITPHNx47xsg0VPH64m6ePdmEzm4jGVdLE8pLSPFw2MwqjoZvbbqHLHxpN1kzm/ESH+a0NPSwuzWNjrQ+TyOjFhUPtg5R7HeTZLfQOh2d8QSUQibOzqZcFhS5CsThtMyjjcCaLS/OwW8147FZO9Ayn9CJaquQ7LdjMZkq9xsXbSCyGiGA1m9ja0DNusEgkUQujoXt4dJp2baGLuiI3+1r7yXdayXdasZiESFzR3BOg0396Es5iEmwWE9UFTtbX+FhX4+P6VeUU59lHR7QD3LKukh0nennsUCfvuWYp9cVz7sLvvNWb4ca7Exv6JTNx29ExGKK+2E23P0SJx07zWZTvCkRilHns00pGp9Kta3VZt9ksHlf8+693jyu5MlftbDbqEg8Eo6MlDM9Geb6DvWmeKXQghYNXjnYOcbRzCKtZOK+ugNb+YErrMp8Lu8XEx25NX5+pVGVG6jFKX3xfRNYB24F3J+57h4i8AdgGvE8pNTc61sxBoWiMQDiGz2VjW0MPvcMRXmjsSdS0Ezr9IdZW5TMcjo1Ox4nFFcV5dj7+klXnfMVH09IhEI7xqQf28ZNnT/C65lruvqiOp492U57v4OrlpSwr9/ClV61nIBjhcPsg33rsGAVuG2+8qO600XPra3ysr/Fl543MYR6HFY/DyiWLi/jdzpPj7ltZ4WVf6wCRWAyLxYQpGsfntNIzw4OUixcXz8XRkAr4m4go4FtKqXsn3P8m4JeZD2u89TU+VpR7U5IUbusPnDb6dbZYVOJOWW29sY0qt9QXZK0ZoIgxyykWVywpzaN3OMxwOIbDauZYpzESNlkCaiojjcBKPQ7edfWSNEWePZOUkTuIsa7WAQ3AKzN1vGwyCTesLuexQ53jEszfe+o4zx3voj8QpWcoPFrfOJmmnmHW1fjY3th7xoTyWP2ByGgjnskukoytqb+lvoDhUIxoPE5Lb4C44rSmYYJRm3mkbnAoqvC5rOxqTu2J6f62QZaW5dE+EGB1lZcXTvTlVFOmVZUejnUO0x8I0T0UOquGR009wxS4jVrWY+tZA6ytzmc4HD3t7x+NK6LhGIfa/Rxq9xONKV6x8fRSVPXFbuqL3bw8yX3a7JbpgRdn2zj4eNcQ9cVuLOdwbFjpc2Y0ueyymen0hyj16gFds9UPn2ng8SyUU8mWEz0BVld6zym5XOCypvTicDLhWOqnIERianS09dqqfCLxOPtbJ09iixiNjdMpHU38xkrV1t8CbATeqZR6TkS+AtwDfA34BMbB8yeA/8U4iB5HRN4KvBWgtrY2RSFpMzEcjnKgdZCeoRDtgyEau4d5aF87J3qGxx0s9wyNP7i8cXU5n7t9rR5dpOUsp83MJ25bzQdvWI7VbOL/Hj3KV/9xGDBG5dx5wQKuXlHKgiI3mxYUsmlBYZYjnp+UUqMjp+qL3bz/+mUcaB1geYWXd/58x2hpDItJCETieOxmBieps5fMa7fMyX3LJUqpFhEpBR4SkQNKqccBROQjQBT4abInZnK/u7OpjwdfbDvzA6chFFVsa+hl0wIf4ajiYPtg0tk0uaSm0ElbXzBtZSwGAunvd2A1CxtqChgIRugPGMcBsTh0+0OjxwWp7m49NHf7OCQrI/dh4B9Kqc+IyD0Yx9AZK2ezvsbHLWsr+dLfD427/UiHn1WV+XSd4QJBMBrnaKef5RUe4nFF20DotOPFZGYytbtvOJL0IorZJKxK1H6OK0Vj9zBWi4kClxW3zUIwEhvdt6SSxSR0DoboC0R5vqGXtdX57E5xAnu6lpTmYbeaxjVQctsto6OpzzbnbbeYsJlNvO/apfzi+aZxzVmNz4aX4XAUm8WMYCT2t5/oY3FpHtevKsPrsHKwfZD2geAZS49pc0dZhhOf5zJS+njXEH3DYcwmOauLQ/4kDe7T6UuvWs/KCm9GX1NLnYNtg/zPXw5kO4yMO5dyR5sXFKT8+DIbRno0LCpxY7OYkiaZl5Tmcag9fbMR09XEb6xUJZebgWal1HOJ338N3KOUGu3UJCLfBv6U7MmJ0Vb3AmzevDl3LvvPI06rGYfVzIneYfyBKE8c6qSxe2jKA9J1NT4+cvMKXRpAy3kiMnoB5D1XL2FlhYdAJEb/cISD7YNEXoyzuCSP61aVZznS+SsYifPqLTV88qWr8bmsiAg1BS4+dP9uzqsrYE9zP0PhmDEqKh6bce2tz//1IN+6c9OcqueolGpJfO8QkfuBLcDjInI3cAtwtUrWRp3M7nd3pKAMxETbG/uwmsTIZuS4WFwRSeOIxu6hMCV5dixmIRpTMx4pPB0iQkP30Iw7aZ+Lf7tmacZeK1OmKCN3G3BF4mE/BB4lQ8nlXU29fPLP+0e3pyYxRuNZzSbsFsFiNrGqwsv2SRpcCUYScmR0a02Bk4FJagwWum0sLHYb09gFQpEYG2p8WC0mTvQMn9XIpFhcJW2sN9JQx2ExsbbGh9UsKUsyLypx47CaeXFM4zun1XzWCaqz5XVaWFbmYe/JgUSzYQvxuKIs38Gupj6WlXk42H7mUVB2i4kP3rCcZeUefC4rv9rWzI+fbeQl6yu5dV0lzxztHpdYBhgOx8btg8+vL+RV59Xw5VdvSOuoqEyYbmNcEbkB42KRGfiOUuozmYwzVy0ty8vo63nPcYBT73DkrOq5mk2S8cbe//zj7bzx4jo+duuqjL5uLhKR72Ec63YopVYnuf82jMGNcYzBFu9RSj2ZuC8GjDTSOaGUekm64w1FY7z7FztyfkBEOpzLzNFMX8BJt6OdQ5gFNi0oOK0xYYErvduTdDXxGyslWUGlVJuINInIMqXUQeBqYJ+IVCilWhMPexmwNxWvp6VOPK545GAHv995kmOdfo50+llamsfRzqkTywC7mvq45LOP8IEblvH2KxZnJmBNO0fGFGBdryzXOG1mLl1SMu62NdX51BW5+dPu1tMe/8KJPlZWeClwW4nGFJFYnF1NfSTLHdQVuQiEY7zvvl189TUbMtIsId1ExA2YlFKDiZ+vA/47cbL7AeBypVRWixPH44ov/O0g33r8WFqWH4krttQXEgzHsFtNdPvDHOvKvSZ35d70Nv3qnJDwXVyah91iGpf4OlfhaJzaIlfGksvrqvOxW+Zkw6LJysiVjTlebgPS02llgt3Nfbznlzvp8YepyHdQ6nUQicY51D7IqkrvaCkJj8PChkQ9ZKUUg8EoVrPQPhDCbBIGAhEuWlTEgbYBFIyWxlhR4SEQjqGASDTOyf7g6Ihms0ko9dhpTSSUqwuceBwWBoMzO5F02swsLnETV2A1mRABi9nYxh9oG2RpmYetKW7ol++08sKEZHuyhkUV+Q6qfE46/aG01IpfVuYZlxAb+dsd6xzCZTVNq1zdDavK+cANy1hYcioh6LvMxp0XLqClN8DPt57g7/s7sJiE1VX5DIWiXL60BLfdwoN721hV5eV15y9gY62POdRr54yNcUXEDHwduBZjkNXzIvIHpdS+jEebY5aUeTL6eqYU7CpCM0z4lXrsxJVKS7PQM5nOrJB54gcYs+R/NMn9/wD+oJRSIrIWuA9YnrgvoJRan/YIx/jCXw+mtK7vbFFb6OTFc6iXfKBtMO3N/DItpmB7Y69xDjOmX8PJ/vTVZX75hqq0NfEbK5VDTt8J/DQxxe8Y8EbgqyKyHqMsRgPwzyl8Pe0cKKU42DbI/3vkCH/d20Y0rthQ6yOuoG0gNGndmcWledQWuugbDnOyzzhJqJ3lIxTmMxFxAI8Ddoztwa+VUh8TkauBzwMmwA/crZQ6kr1ItfmqqsCZ9PZYXNHSF8BiltGpyMV5NhYUuVFKcaJnmN6hMOtrfBzu8NPQPczCEjdf/vsh3nfdMvyh6GyfdVEG3J84mbcAP1NKPSgiRzDW54cS9z2rlHpbNgKMK8WBtsGUj+TLd1oJRWMEI/FxSSOv04LNYsr6qJANtb5x0/1Tndg6kyMdfkSMRrtjp8mfqxdPDlBT4KQpA01JonGjTI7NMmeSVSMmKyM3KnEinHSlSXU5m8cOGnUfl5Z72NPcj8tmxmo24XVaiY+Z9DAYjLJjTDK11GPHahbMJmE4FKUk8XvPUIRFJXlU5jtp7Q9wvGuIYCTOwhI3jRNGJW9eUDAuMdPcG2BJWR4LikwcaB0kGlc4rSZWVuTTPRTCbjHjspvpG45wPHERyW0zs6oqf8p1bHdTH3VFLoKRGOX5xqjqs70IVeqx0zEYIhgZv40RYCAYId9ppchto2MwxPJyD7ua+mjtD4429RkIRKc1kjiZcq+dSExR4rFjt5hwWM2nJaw9DgurKr24bRZEjAtPt66roHMwxIULi3HbzTR0DfHA3jaGQlGWl3t433VLxyWWwbiY9KWHDvGn3a3UF7t59P2Xo5TRH8FhMWNLXPj5lysWYTOb5lw/g2k2xt0CHFFKHQMQkV8AtwHzPrm8oNCVkX3x5gUFNPUMpyTp5JzhaL4Sjz2lF3BnYnVlflZeN9copR4Xkbop7h9bX8CNkY/KiqeOdPHtJ45n6+WzptBlJRSNn1abf6b2tw5S6Lal9cJKgctK+0Bmm3Nm6vxgQ62PT798TUZeK2Vn1kqpncDmCTffmarla2dPKUUgEsNlM/7dsbhi6/EefvJsI48c7CCuFJctKaZtIMg3X7+RZ452n7YB3LSggM/fvva0A9B4XM25g8p5JgRcpZTyi4gVeFJE/gJ8A7hNKbVfRN4OfJTENF5Ny6SOJDv6IreNhSVudjX1jatxObHpkAjjpnIf6xzij7tO8tyxHnqGwzz0b5fN2pFWiRPadUluz5lpJBaziU+/bA3XfvExBlMwrU3EGKnX1DNMMBIn32mhIt85OhKkwGUjHld0DAap8rko8djZ1dx3WiIonbLZXG8spUj5adTiEjd7UpisnkyBy8of3nHJnJhhkETSMnJA+8hsPxGpADqSPTmV5WxebOnnV9ubKPM4MIvgsllG64I7rSasZhOXLSkhEI4iJqO2d57dQp7dzGOHu8Y10fKHA1T6nNgtpnGJnvpiNz6XlTy7hWMTao4faBs8rXb+4UStwQ3V+ZjNJvae7Gd7oqxOqcdOp1/RMxRmdZUXn8tGOBI748lZJK5GG2m2DYQ4v76Q491DM2oCZjUL66p97GzqZWWF57QLZgroGgwxFI7RMxTGYmJc4jwSU3T5wxSdxRR6k8B5dYWjy+tOcnJtNQuvO38B77tu6ZQ9UGJxRedgkLsvrqfEY8frsIzbB8biij/vaeXDv92DPxRlRYWXb71+I809QSNpPeGC7FwqMzWFyRrjVgFNY35vBs6fbCHzqb+QxWxiUUke+1vTu78wmSRlzfRmmrTK5syajQsKsvbas42IvAz4H6AUuHnMXQ4R2YZRLuMzSqnfpSuGvuEw77tvV7oWn7N8LitepzUljaz9oShbKgvTmowt9zoynlzOhIp8R0bLQs7qYVvambX2BXj2WDcneoZZWZnPlUuL2d0ywHPHuzneNcTCYjdl+Q5qClyUeBx8/6kGnjzSNW4Zb71sIe+/flnSxis6sTy7JeqxjlzZtSa+RtISIx0j8oGTmY9Om++CkRh/399+2u0V+Y5pjVRJljxo6B6moXuYL9yxbtYmlmeT8nwHj77/Cu7+/vPsOYdpcWaTsKzMw74xJ6v9gShOa5jz6owTrV1NfYQTdVGOdQ1xrGsoo1PpvA4LOyepS5spDquJ4jxjdOX+tkEWl7g5cg6NBAtcVnqHI4hkLpFU6nEwVw8tJisjl/i6C/hM4vvv0x2L12mlrT/EiZ4AKyo89AyHybOZWV7pZXtj72jZB6tZWFLq4UDbIAUuK3VFbs6rKzRGNiujmVaXP0QkFifPbgYUoajCZTXhc1rZcaKPUo993GsXuq2Ue53j1ucRRW4boZhif0vvuG34giIXL7b0k++0jI7IX17uocxjZzAYIRSNJy2LNNELJ3oTieK+SR9jStRDjMbi9AeieByW0YZC+ybp9O4fMzJr7IBNh8VEKBonGouzt6V/xqP/V1fls7Vh8hPq5eUe7rlxOVcsKz3jsswmoTw/+Wygrz9yhO89eXxc8no4HOXRQ5284cK6acc7W4jI34FkjTY+opT6feIxUzbGnYn51l9oaVn6k8up3E009w7jsVumfSF8Js1IU+27Tx7j2WP5vPWyhVmNYzZQSt2PMcvvMoz6y9ck7lqQaIi9EHhYRPYopY5OfP65XhRSSvHh+/fQNpC+0mi5aGT/n4rE8oh0HxbOxYulTquZb79hM6WezDVZ1cnlOeove1rxh6L4XDa6h8IMBKPsPNHLL58/wXPHegjH4rz32iX0D0cZjsRwWs0c7fRzsG2QfKeVvmGjGUtNoZN/ulTvvOayRN247cBi4OuJqbpvAR4QkQAwAFwwyXPnzUgMLfO+8ejRpPU3j3cNsbYqP2kTp6m8anMNlywpZkt9YdqbJminFOXZWVyad07J5Y21vqRJ4raBEG1TjDTY09zPlvpCGromb0a3rjofi9kECvzhKE09wwyfxRS++hI3u5rO/j2mwrpqH88d78FpNbGg2DXa1OxsVPoc9A6FcVqN/X+mkvTWuVcKY6JkZeRMwH0i8magEXhluoOo8jk5r76Ap450s791kMuWFvPk4S62Jf7PVpOwtNyD227BhNGwDYzRraFoDLfVwrYTvYSjcc6rKyAcjWMzm3DaLFyw0MfJvgAH2wcpdFmxmGBlhYdoXNE5GKLM4+Bg+yCVPgdDoRgum5lKnxMRozPase7h0y4O7j05wMISNy+ePJXcPdA2yMoKL+2DRu3nukInRXl2gpEYkVicoVCUlr4gHruZZeVeTCZBEs+bitVsorF7eNo1xtdX+1AoYnFFfyCSKBNiIhiJ4XFYGQpHaekNEIzG8TqtLBAh32nFbjUxGIxOGY/Dak56odQk8J+3rOQNF9ad80CPz//1AF9/5LS8Ck09w6c18psrlFLXTHX/NBrjtgA1Y36vTtymAUszUHd5pnWSJ+OwmPA4rJOu70vL8jCJ0NIXoMhto6F7OKvltx7Y08YDe9o42DbIV169Xg+UmIZECY2FIlKslOoa0xD7mIg8CmzAaN458XnndFHo19ubeWBP27kFPwsFo/FZ14gvFD230h256EuvWsfqqsyW0dHJ5TkoGI5yfn0Bjxzs5EDbAH1DERq6hzjZH8Bjt1DssXO8a4j/+cvBSTtbr6/xYbeYuGhRESUTRpxoc4tSKgasFxEfxtXd1cC/ATclEs3vB74IvCXJc+fVSIxUOdE9zN/2tXHD6nKqC3TN8slctrSYHz3TQG/iYteIoXBstGHTdJV7HXzqZauNJKKWUYPBCM8c7Z7WY/OdVobDUSKJIYgWk7BhksTydASjRl1miwm21BfiD0bp8ofIdxpT9a1mYeuEZVtNwuYFBaMjFadrJtPs02Xk5DgQiXO449yaG57sC2IxCT6Xlfpid8aSy3tbBvjRM43cdVFdRl4v0yYpIwfGKOZUvxbBSByn7fQROSaT8J03nMeu5j7a+oM8sKeVzQsKQYxRfLWFTg61D1Htc9DUE6CywIHHYWVf6wD1xW52tPWOJliGQhH2t/nZUOPjeNcQjx3qRARqC110DoZYWenlySOntgFWs5DvtDAUitEfiNAfiOC2WzjSYUykspqESp+DinwHJhH6hiMU59l55tj47cjY9TSWKH8xdqTU4tI8lpTmcbzLP/q4PJuJZRX5p3VpH2tlhYcdM7hQZLMKW4/3jf4+dmTyqkovJ7qHR0dE7m8doK7IjW1MCZHFpW68DisWswlJvBeTCUQZ+7mNtb5xDQRvXVfJO65cxLJyL+cqHld8/6mGpPd95hVrecm6ytHf+4cj5LvO3CRwtptmY9zngSUiUo+RVH418NoMhZjzMpFcjkzSH+hslpPvNJLL66rzsVvN9A6FKXDbiMbi7G7uG52NUOS2UeCycvgsa6en0h92neTWdZVcuzIj/V9nHRFZDBxN9DHYiNGPpFtECoBhpVRIRIqBi4HPpfr1T3QP8/E/vJjqxc4KcQULS/Lo8me+4eXZauufW6PL33ftUm5YXZHx19XJ5TlAKcXzDb384vkTFOfZ8QcjiAgneobJSxysH+44VdN+S13BaDOUyRotjUwXbOwe5k2X1E9Zw02bG5RSfSLyCHAjsG5MTchfAg9mL7K5p2MwyJceOsQvnm/iymUlxBVEY3EOtA3S2h9Eofivl6zKSFfXXLZpQSFb6gt55GAn0VicjbUFtPQN47Ba2NM8sxGi/3rlIp1YzhKPw8ozH7qKQ+1+Hj3Ywf07WkZH6pV7HfQOh1EY07t3N/eTZzezrtoYZdg3HE5JUjMaH984Y6oRiZG44mwGAg3lwCiN411DLC3L41C7/8wPnoZo3KgVG40rCl1WeiZc6EmXT/55H267hds3VWfk9eaicDTOFx86xJEOPzaL8PXXbjxthJvTZuaChUWAUSP4b/uMMkQba310+yMMBMLkV3px2CzElWJvywDD4Ri9QyGjqZQYtdCbe4a5aGERIsKSRFIpEI5iMZuMpG/X+PzcgiI3ghBTiu2NvdjMQpHbRo/bRqnHzua6AmoKXCwuzeOiRcU4bWZiccXFn3mYnuHwaFI7HItTme/g5JiTQrNJsJiEUDSeeO8m1lafSs5aLGa6/SEq8h0U5dlOa3q5usrL/klKX0xmqgtLSimWlXtGk9txZZTtcY1J+B+Z5EKQ3SKsrylg/5iRzdesKOWiRUX0D0fo9oewWkx47Ebt5P5ABLfNPKN9nQi4bJZxszXcNjPXrSrH67CeNlV4OBxFKU6rvzzHfI0kjXFFpBL4jlLqJqVUVETeAfwVY8D995RS8zOTlERdUfoHTriSXDQ7GzEFhzv8XLSoiKfPcCG8oXuYQpdtXBmcbHrkYMe8TS6LyM+BK4BiEWkGPoZR3hGl1DeBVwBvEJEIEABelUg0rwC+JSJxjFlDn1FKpbQRZzQW5z2/3HHOjexms63He1hSlkeByzbl7MFc0TYQYnWll71ZatSZSreuq+QdV2WnBc+cPjKYL5443ElrX5BFJXkc7fDz9NFuFAq33UIkFieQ2LCdV1fAYDA6bjRWfbEbr9NCNBbHajLTOxymsefUSYDTZtaJ5TlMREqASCKx7ASuBT4L5IvIUqXUocRt+7MZ51yzua6QR/79Cr79xDFa+4O80NhL11AYj91CfbGbCp+TiknqIs4nSimOdPipKXDidVrHbLumf4Bit5j41p2bplWPUksfEWFZuYdl5R7W1/j434cO0dYf4ESPMc0032kdbc7oD8VmPGo41U72TW8Eg0mMEVr9gQi+HBnRNxBIfZK7rsjN3pa+lC93MpGY4jN/OcDNayqSjrrVzsxmMXHPjcun/fhP3raKZWV5PLi3jXAsTjga55LFJexrHaBjMMQlS4qpLXJit5jJs1kYCIYxiZE89rlsNPYMEwjHWFjiHi314HFYUEqxujKfgVBk9LP5fEMvy8s9HGofxGoWvnf3FhYUuajyOTCZkidGzSbh6XuuYiAY4Y+7TtLSF+S29ZV4HBY+9+BBWvoCWEwyOqJwXY2P1r4Azb0BXjjRx4YaH/vbBugbjlBX5GZnUx8Ws+Cwmkabfi4sdlPgsrGmOp+jnUP0DIVPazo4Ub7zVCPEsRaXuEEkaY1mm9lEWb6DojyjfMYzR7uSJiHKvU4CkRjxuGJ5uQe7xcTf93ew9XgPlywpJt9p4+dbT3DtyjL+85aVPHG4i4Ul7tELBtMhIly+tITfvNA8etuHb17B685fcPp7zZFtXLpN1hhXKXUSuGnM7w8AD2Qqrtkk3eeOdUWulM+mmWzA1UQ9wzNr/pdOtYXzd/ajUuo1Z7j/sxjntBNvfxpYk664AL7+yNFxs03mq8NjBjqsrc7neOfQWTX4tltM9AfSv971DoexmmV09uRstK46n8/fvjZr5XJ0cnkWCoRj9AXC7Grq50+7T3Kkw0+XP0xcKQrdNmLKqGk3MQGzs6mPMq+DkX2n02qitT/A8a5T04rsFhNb6gvZ19KPPxwjHI3Pm2lw81QF8MNE3WUTcJ9S6k8i8k/AbxJXdXsxumVrKVTqdfCRm1cCxrRUEXTdtCREZHSq9Nm4clmpTiznmEqfc9wo4u6h8LgmUrkgEouzqtJLOBbHajIlbTxW5XNSVXDqvbTmwJS6ZWUeuodSPzqkbzhMpktM/tOl9TqxnEHHu4f58j8OYzWbGAhE2FxXwN6T/XT5w1y4sJCnDnexrsbHnuZ+onHFxYuKaO4dxmox47KZWVSSRygaIxpTNCcGKSwr97CtoZdnj/fgc1nZUOPjUPsgQ+EYeXYzS0rzsFnM+FxWaqaRJDGZBJ/Lxp0TGsx99TUb+MajR/nsgwdGb5vYVX5HUx+XLSmmqWfYKDshUOF10tRjlLDYUm90oj+WmNlnMQkXLixi+4lezqsr4ET3MO1jRl75XFaWlXk43DFIz5jtl0mgzGvH57IlvUhmMQlfefV6blxzarpqLK7Y29LP3d/fOq4MVGPPMPSMLFewWYzE+0AwOq6O50P72rl0cTH//ad9vOvqJTNKLgNcuqSY37zQjN1i4qF/u5yqAn1xWzs30Xh6dxhlXkdKm4WBMVNntpmvo5ZzWXPvMF99+HC2w8g5u5v7qfYZg4VmUsvfbjGxqCQv6XF4qrX0BTm/vpDnjs+ech5jlXsd3PuGzVltTqiTy7NEx0CQPLuFB19spa0/RFPvMC809hGNxznaOcTGWh9NvQGae4dRSlHpc1Dtc3G8e4iBQIS4UrhsFhxWM+fVFeC0mnnhRN9pxdZDifqUJgGP3YJJ4N4njvL+66c/+kWbPZRSuzGaGEy8/X7g/sxHND+dazOeuWooHKP1HJoJ2S0mPnrLihRGpKVCTaGLT9y2iv/4fe7OIO4YDI1O4Us2MshtM9PSF8ipZldmgbJ8O9F4nC5/apP1+S4rTK9sdsr8bV87V68oZXFp+mt3akZ94r+/93KK8+z8ensTH/zNHmJxxcISoz5wZYGTcDTG+hofJpPQMxymsSf5599lM/OOKxfT0hfAZbOwu7mPvuEIO4b72Fjrw2I20eUP0T4Q5F1XLaE8/9w7mb/t8oWc7Avw0+caGZsjclpNLC/30D0U4YkjXWxeUIBSxoWYQCTG5roC+ocjpyWjV1Xl855rlrD35AC7m/to7Q+ysdZHY/cw9SVuTnQPj56ALix2k2c3jrFb+gO09AZo7U9+kcfnslHqHf9+zSZhXY2P91679LTt4poqL7E47G8bmLT8hkmMWrBFebazakp06ZJinFYz/3HLSmozUM5Am/tOpDjxO5bdYmJ/W2oTTRtrfVPWYc9FC0vcLCrJy3YY2gSPHeqc9ij4+aa5L4DHbmZlhXdayeJMJpZH7GzqpdRjz/kyHhM5rCa+/YbNlHnP/XjqXOjk8iyglOKZY908c7Sblr4Ag8EoRW4bLrsZh8VKodsGwOKSPGwWEwfbBznZFzxtWu9I0xQwphNFYpMfgMYVDIaiDIaiVPr0CAZN0zIvz25hWblnRlPLHIlEgtlkIq4U+08O6KaJOagob/Y0is1LUlt0KGwk2Y60D2a99qIAS8ry8DqtPH6oi+I8G5tqfew92U8ompoTnNZplglJpe2NvbzjZzv46VvOn1Wfl9msOPF3fsXGahaV5PHpB/Zzsi/IE4lRyztO9OGymfHYLQQiUUo9dlw2M8UeO5FonGNdQ1y4sIhPv3zN6LLAOP78w66THO3wc+u6SuJKcbxziF3NfXQPhfEHo+MefzZEhP+4ZSUv21hFfyDCiy39rKjw8vudJ/nDrpOjj3u+oZfVlV6OdPpZXOrhyoVF9CXK2oydZn/50hLOX1jE+YlRwAfbBnndd56lPxChYyCEw2rGZjbhc1lpHQiOlqA7k8/fsZZNCwqS3nfH5hp+/GzjaM304jwbRzqHzrjsixcXc/O6Sv64u5XfbG/h369bNu2ZUP5glObeAE/dc9Xo+YSmnat0JoNEIBRJ3X7XaTOP6000W+hRy7npiUNd2Q4hpw2GYhxoG2BDrXFMMZlsJJYBQlFFRb5jViWXi/PsfOP1G1lTnZ/tUHRyeTZ4/HAnx7v87G3pxx+KUuKx0zMcpqkngEmM0cYjSeMNtT4KXTaEqafoNnQPU57vwJ4YPSIw6Qny1fO8qZimadkRCMdw2sxUFTiJxRSBSIxoLM6qqnzicTVuynFdkYsyr4N9rQPsbDrV7O9HzzZy7arybISvTeFX25qyHcIZWUxG3cgyr53hsOu0Kbg7m4xRmJmuq5dnM7OyMh+FQinoHgqNa+DX5Q/T5Q/jtplZV+9lW0MvEwfRLCvLI99lZevxM4/Uqi92cbwrfaPQpnKgbZCLPvMw/3zZQv7t2qW6dFCGiAgbagu4758vBIySEkc7/BS4bAwEIogYSdqBoHHc2NA9zCs2VvOtOzczEIyclijOd1q584LxNXzPqyvklefVpDRum8XExlojcXtlohzSZUtLWFji5nC7n4cPdFDgslJf7ObLr97AohL36GcqFI2x9XgPkVicpp7AaaUllpV7eO7D1zAYjOBzGUnYjsEgf97dylf/cZhAOIYILCh0saoyn3ddvYQyr51nj3Vzsi/ItsYeblhdwUWLJi9Z4bCaed91y/j51hNsb+ylyx/m/PpCDrUPjiuXMZHHcep0rssf4m/72rl+mvu9/mCYVZVe3fBWS6m/7G0784POUjASZ3Gpe9JGmDPlsVtmVSJpxHU6uZxzorE4Tx3VyeUziSvY3dTHmqp89rSc3qDd47BQXeDMeGJ5xK7mftbX5I87n8xV62t8fPP1m1IyAywVdHJ5FlhV6aXbH8ZhNXOo3U9zb2DSulAjV4Aq8u1sqDFGLk1WlLwtkXw2iXGQP1l9mbu/v5U7Ntfwio1VowfUmqZp6fadJ47x1JFTc/EtJnBazaPTlzfU+ojFFXaLiZ1NfUnr770wy6Y5zgdd/hDPHMtwjYUZqi920zEQpHc4wiMHOynOs1Fb6KK1P0BNgYvivJGLvMNsqStkOByl0x+ifcA4QU3nlLqVVfmnTeFPZigcY+vxXsq8dsq8DmwWE9GYYigU5XCHHwVsqMlnxxkOnpt6AuQ7LfSnoVHgdISicX629QR3bK6ZVl1eLXVGEq8bawvYWFvAIwc7ePhAL+VeO8V5Nrr8YbxOC8vLvVy0qIjyfEfOnOCMsJpNvOeapQD0DoVx2sxJ6xHaLWYuXVIy5bLMiZrPI0o9Dt54cT1vvLieYCRGOBbHO6GR2Q2rjdrKb7qkflrxXr+qnOtXlRMIx/i/R4/wzceOEokpNi3wATJu6r7LZmY4HOOyRNxNvcM8+v4rcNmmd3oXjcWp8ul1Skutlr5AWkpMFLlt5DksFLltKb2oG45luKFAChS4rKyvST4DQsueXc39DAazc6w028QUHGofYFmZh4PtpxrfLipx4w9G2Z+kGW4mnegJ4LFbzqoBYaa8+rwa/uu2VdgtudOfRCeXZwGf08afd7fS5Q/hdVrHNesxOnGDPxRNXOVxsb91gNb+ECWe6R3gx5UxOmiyk8cDbYN84k/7uPfxozz2/iuzWiRc07T5Y2vD+ARaNG5Mpxox1XSqEUPhGH3DYX1hLIf88vmmRAImgiAEUji9NRVMYjTYGhozm8eoYWzUMT7WNTTa9Aug03/qc+qwmLBaTPQMhdi0oMBopOuxYzGbcFhNFLhsdA+Fz6lJZVt/gOoCJ82906v33D5wKuk90Y6m/tF6sU6bmXA0zmAoSp7dgs1iQikIhKNYzJLVERxd/jD/9+hR/uflaW3wrk2iczDED54+zr6TxiiicExRX+xmWZmHEz1Gr497Hz9G91CIuy6qy6kTnbEK0lj2wWFNnrQ+W06bmdedv4CeoTCVPie3rq1kR1PvaNJucWkeZhFuWVfBqxIjwDcvKKDc65jWKOR4XOnRylpafOrP+1K+zPU1+Rxu99M9FKYxxfWc851W+qaYGZCL1tX4MOt+LTnnicOd2Q5hVglFFS19w6Mz5DbXFbDrRB+RHKhZ3TMUZvOCgqSNebPNahb+6yWree35tdkO5TQ6uZzjOgaC7G7u56JFRUTjikA4Rn2xi2hMYbOY8DgsHO8aYq03ny5/iHA0htNqJhCJYbeYWFWZz+FEZ+7JFLltVPmc7E4yLQGMkRG1hS5evrFKJ5Y1TcuI7Y09PHH43KaWFblt3LSmgtb+oE4u54ijnX6+9vARvnPXZjbU+mjrD/LiyQGePNzFL3OkVMaqSi97Ws5uKl4wGicYNUZBbW/sZXm5hwNtp4++qCl0UpnvJBKLowCLSRARdjb1EY4mH0W1pb6QWFzRORikIt8x7eTymYxNlE9mbQ7Ucfv51hNcsriYm9dWZDuUeWd/6wDNvQHyncaoXKUUh9oGWFLmoak3QFNvgPPrC/n0AwewmEzTHqWrTa0838GnXmZcUInG4vzH71tYVenFbbfwYks/L9tYxTuuXDw6wvxY1xB/2HWSl2+snnK5IyWnNC3VHtjTygN7UlcSw2Uzs6rSO64eeqpNnG0wG6ys8GY7BC2Jcz1vmY/8oRg2c4QLFhby7LEzz8rLpG2NvdNuPpgpJR4733z9RjYtKMx2KEnp5HKOK86zs6w8j+2NvQiKLn+I7qEQ/mCU1VX5DIWieBxWWvsD9AwZDftKPHZWVnhp6hmmbSBEnt3MhlofZhGOdPpPuzrbPRSmvtg9aQw3rangC3esS/db1TRNA4wRVV97+AgAVT4nq6u8vGZLLZ2DIR7a147LZqa5N4DHYeFQu5+WvvFJNpfNzNuvWMRbLl2oL4jlkJN9Ad7xsx0EIjH6AxFcNgsLS/JYWJJHOBrPieTyeXUF0xoRPx2rK73sPZn8gLSpJ0BTz+nJ4YXFbjr9oaTTKsPRODubjNjaJhmJnC52S26McHzvfTs52DbA6y5YkPWO2HNRLK74zfZmfvpcI++4agkban3k2c38bmcLv99pNMW7ZHER/lCUwWAUm9lEodtGz1CYYCTGS9dXsqHWl903MUd9/6kGHjt0alTcFctK+PBNK8bVIf/c7Wspcp/eGHE4HCUaU/QMhakrduvEspZySil+8HQDn/rz/pQts8rnRCCtiWUwjhlnm1ydHTKfDQYjo8do2sz0DEcYCOTm7IHe4RAOq4lgJPvlczbW+vjG6zfl9PFvSpPLIuIDvgOsBhTwJuAg8EugDmgAXqmUyr3x5TnKZBLcNgubFvho6R1mZaWV7Q099Aei7Go+NdK4yG2jwGmlpsBJTCm2nzj1J/aHYqMny8V5NqoLnHT7w6yu8nKgdZDBUJRtjb1U+hwsKHTxzISrRr99oZnLlpbwknWVGXnPmjbfdQwG+emzJ1hR4Rmt1zif9A6HWVSSxwdvXM6yMs+4k+c7No9vAKWU4qkj3fz42QYisTilHgfvvW4ppdMsC6RlTiyu+MzL1xCNx1lUkjfuvlvWVdDQPcTXHzlyWvO5TFlTldrRUZP1RpjKsa4hFibKDYgIw+EoB9sG2LigkD1j9vmTjW5Ol+5Eg8CpZkFlQnWBk+Pdw3zuwYN8+KblFOWdnkjTzp7ZJFywsJAfPdvIiZ5h3HbzaO3DynwH1YUu9rUOYDGZ6BgMcbRzCJsZLlxYyMpKLx+9eaVuuphCSine8sNtnOwPcqzzVCmdt1xSz4dvWoFpwrT4inznuN8HghG6BkNYTCZqi1x4nbNvhKaWm9r6gzR0DxGLK7Ye7+GxQ53nnFhzWs2srvIiIiilON41lChJlV4n+1IzCyiTBoK5mYibz9w2C0tK85LOVtPOLFcHA7X2hzi/fvLeZJnyuvNr+ditq7DlyGCPyaR65PJXgAeVUreLiA1wAR8G/qGU+oyI3APcA3wwxa87p5lNQt9whNaBIMV5dgYSI5quWFZC+0AIswl6hyI09g6jlDHyajIjO+mKfDvPN/RyXl0Bzzf0UuqxU+Vzsi1x2/bGU93l4wq+9+RxnVzWtAxx2SyUeOwcavdzw+psR5N5RXl2PnrLymk9VkS4ZEkx62t9BCMxinWyKWfVFLombchmt5h533XLKPXYWVnpZV/rIDsae9nW2MuJntTWV0xmXXV+Sqe9bakvGK1PO1MTazq7bSaGQ1HKvPakTSszoWc4jFKKLXUFRBO1Wrv9IXxOK60DQU72BTMSx/qaAv79+qWnJdG01KktcvOnd14y7rZrV5bx1JFufv78CZxWM7uberh4URExBVaTUQ7mj7taeddVS8l36QRmqogIXUNh9o/ZNr3nmiWjDQqn4g9FGQqEqS106drKWkr5Q1Gu+9Jjo+ej56LIbWNRaR4oI8mb7lHKyV6/KUUlpjIpV0d5zmcmk/Dv1y3jLT/alu1QZiVrDu+ntjX0UFvoysj5yEQum5n/vGUlr96Se/WVk0lZcllE8oHLgLsBlFJhICwitwFXJB72Q+BRdHJ5RqwWE4tK87h0SQl5djNNvcO86rxavvXYUeJxxcn+Uyd1hW4bFpOwusqLy2ZBMIaQx2Jxdjf3jxZIb+03ptQ+39DLhpp8rBYTB1oHiMQVzzf0sqm2gANtA6OjlK5fVZ7pt61p81ae3cLrL1iQ7TBmlTy7hTy7rvQ02915YR0AmxYUcucFC4jHFS+c6KU838HnHjzIH3adRARUCkc3LynLY1/rAJFYahaa77Sy9XjqTpAL3Xb2tw0Sy2KDkyWleTzf0MvWCSf++U5LRkeb/OaFZvqGw3zqZWsoz5+9sxNExAxsA1qUUreISD3wC6AI2A7cmTiOzgkjF/EuWVJMLK5o6BriaKefhw90kGc3s/V4Lz1DYZ5v6OGalWXZDnfOONIxyJsuriMYibG/dZDbN1Wzump69c/1PlFLl0cOdKQksexzWYkpY+RzNuTZLZR57XQPpXZT+66rFrOy0stziRHdxzrP3NdgpmKpPAjSUubqFaVsqPWlrLzafJLLH+mYymz5nOoCJ1cvL+WqFWWcX1+Ys6O6k0nlUUc90Al8X0TWYRwcvxsoU0q1Jh7TBpx21CkibwXeClBbOzuy8plk1KV089SRTroGw1y8uJgfPd1Ac28Aq1kwiTG6eH1NPm39wdPKWoxYXemluS9wWs1lu9VM33CYZeWnpgRvP9HLxYuLCEbiXLK4mLsu0okuTdM0LbNMJmFzndG04gt3rONdVy+myufipV9/CofVhMNqJhpX3La+kucbevnjrpMzfo3BQDRliWWAZWUetjak7mS5qTdAkdtGfYmb7Y29GT0Ar8x3ICKTjiZz2SzUFrooz3fS7Q/R2h9MexL8Hwc6OG9nC2+7fFFaXyfN3g3sB0a6Mn0W+JJS6hci8k3gzcA3shXcVMwmYVFpHotK87guMfDg6SNdfOOxo9zz2z08vrgIl00nNVNhYXEei0s92Q5D00YFIzG+9NChlCyrwGXj+DQayqaDxSTs+M9r+e6Tx9jXejBly33/9cv41ysXA3DD6gr2nRzg5v/3RMr32xfUF6V2gVpKiAjvv34Zr/32c9kOZdaJxrNf03gqB9oG2VRbMK70bKqYBDYvKOSqFaVctbyUJaV5s7bEWCqP/izARuCdSqnnROQrGCUwRimllIictnlVSt0L3AuwefPmHL5ukT1PHO6izOukyG3jueM9BCMxLllczHPHutlQU0A4FsdjtzBgswDJG/3sPTlAqcdOgctK73CEKp+D2kIXRXk27GahoXuYLYmTeH8oyuKSPP7rtnk4J1/TNE3LOTaLaTTR8tnb17K2Kn9czdE3XFjHyzdU8eYfPj+tus31xW5K8mynjcY9Vw3dQywuzeNIh//MD56m7qEw3UPh0VJWmeC2mRkMRhgMTV5nubU/SOuY2VMOi4m11fnE44o9Lf1pq59tMc3Og24AEakGbgY+BbxXjDOIq4DXJh7yQ+Dj5GhyOZmLFhezpb6QnqGwTiyn0MSaypqWTZFYnHt+s3tc2aZzcbxriMWlbo50ZD7BXOZ1YDWbeNvli1lb5aPTH+JPu1t5aF/7GZ/7/16zgWAkxjceO8qxziHcNjNb6gt53fkLTpu5sbLSy5deuZ4P/Gb3tHsl1Be7qS5w8tSRrqT70GtXlvGyjVXTWpaWeRctKuaSxcU8eaQr26HMKsNZ7ukxHce6/HjsFgZD5z5zI99p5YplJVy1vJTLl5bgc9lSEGH2pfIIsBloVkqNXKr5NUZyuV1EKpRSrSJSAXSk8DXnjS11hfzH7/bSPhikzOvAYTXR2h/AZBK2n+hlS30hTxzpxiRQ7XPSPElzgo7BEKsrvdQVuxFgZ1M//3LFIgLhKNtP9NOY6F7vsJr48Zu3ZPAdapqmadr0rK/xJb392WPd00pobqz18cKJvpSPmip02yh0GweIVT4nLSlsFLSmKj8jieWaAielXgd9w2GOznA6bzAaH50Ouq46f1zj4VTxOiyzvTHZl4EPACNDUouAPqXUyNlKM5A0c5DLM/0sZhOlOdzBXNO0s9PcO8yDe9v45fNNHE7hRVMAiyk7dVarC07V7b9ocTEAL1lXyft/vZtfb2+e9Hm1hS6uWl6K227h9k3VDIVjuKzmKS8EvXRDFfXFbt764220DyQfADaiptDJA++6FKfNTEOX0eT4tztaMAlcuKiYd1+9hE0LJu+tpOWGf79+mU4uz5B5FlxM7R2OTGuQh9kklHnslOc7qMh3Jr6f+rnS56DU45gV73mmUpZcVkq1iUiTiCxTSh0Ergb2Jb7uAj6T+P77VL3mfDIQjHBefQHVBW5WVHh4+EAHX3/kCOFYHIfVxEAggtdpYSAQJabUaKmMZPaeHKDQbWMoFCEUVRS4bVy7sozf7mghHIsTjsYJRuI8erCTV2yqzuwb1TRN07QZaOsP8sWHDvLn3a2jfQKmsrYqnxfSUA/PYhIWFrvZ1pieBPCeln6K3TaKPUby2mWzcLjDz2AKal+CkQyvyHewrbH3nBocmQU21xXiT8HIjmT+9M5LqS1K3hgy14nILUCHUmq7iFwx0+frmX6apmVKMBLjvfft5IE9bWlZ/voaHzub+tKy7DMZuQg8lojw6Zet4UTPcNI60E6rmXvfsAl3opa5iEy7rvm6Gh9/eMclfPbBA/x+58nR8lHn1xfSOxzmULsfk8BHblqJM1Hbta7YzefvWMd7r1uKSYQyffFu1lhf4+OeG5fzl71t7G3pz2rPjNnClsMN/cba1tA7rrmfxSRcs6KMG9eUU1vooiLfSYnHPicTx9OR6rlr7wR+KiI24BjwRsAE3CcibwYagVem+DXnhUUleSwszmPr8W46BkM8fKCDuIJCl43FpXlsa+hhbY1RQL61P8ja6nyUUvQFInQMBCnzOnFYTRxqN4bz376pmp0nerllXSV3JhqHPfCuSxkKR9lxoo/3/2o3VywryfK71jRN07SpHev084/9HQSnMeX0m6/fSHGeneNdQ+xq7uPRg5209QeJpuDAf1m5J+WJ5VKPnSqfMcLKajFxpMPPgbbxI8dWVHgYCsXOuov1miqj7O+eloGUjLSuKnDywoleIjFFodvKQCA65d93Y62Pbn+YYCSGz2XDaTOPJhyWl3uoLnBiEsEkwsYFPmoKnZMuaxa4GHiJiNwEODBqLn8F8ImIJTF6uRpoyWKMmqZpPHWkK22JZQCrOXvJl55JmvjZLCa+d/d5vPvnO/jHgfGTrT9/x1qWl3uTPm86yrwOvvjK9XzwhuU09w7jdVhZUuYZjUeAgiRJ74r8Wb3PSxsR+R4wcsH2tDqeInIb8AkgDkSB9yilnkzcdxfw0cRDP6mU+mGq43vb5Yt42+WL8IeivNDYy3PHu9l6vIddTf2EY7ldXzgbsrk9mAkFeBwWlpTm8arzanjphiqK8+zZDitnpDS5rJTaCWxOctfVqXyd+UhEEIGfbm3igT2t5Dut9A2HWVDk4rnE1dVwNE5NoZMyr4NtY4brm01CIBKjczDE686v5d3XLKHUc/rVz6I8O0XYqfK5uGhRMUV6RdE0TdNy3EWLi3n6Q1cRjsa56atP0NQzeYL0E3/azz/edzmb6wq5Y3MNAD946jj3bWumuXeYgSSjgB1WE8HImU8E+gORMz5mOs6vLyQWV8SVYndzPx2DU0+j3d86SEW+Y8oZSyNsFhM+p5XyfAc2swkF7G7qS2lt1xM9Adw2M0IcFGxcUEB/III/FCUeV0QSJ1XFeXbsFtO4UeTtife6utLLpgUFfPwlq2ZtU5NklFIfAj4EkBi5/O9KqdeJyK+A24FfoGf5aZqWA452prYExlgehyUlF3XPVqd/8v1qnt3Cd+7azO93nuQnzzbSF4jwT5fWc8vaypS8dpnXcdoo5GQjqbUz+gHwNeBHk9z/D+APiZ5fa4H7gOUiUgh8DCNnpYDtIvIHpVRapp3l2S1ctrSEy5Yag/aCkRg7TvTxfEMPQ6EoNosJm9mENfHdZjGN3jb2uzXx3W4Z/7vNfOoxJhN0+cO09Qdp6w/S2h8wvg8EaU/0yGgfSM2AilSbDcd6HruFW9dX8srNNayt8mLKUlmfXKa7bswyd16wgIauIQ60DRBX41fEF08OAJDvsCIYW0uAWFwxHIryyZeu5tZ1ldgsU68IZpNQ4tGJ5flARBzA44AdY3vwa6XUxxINhj4J3AHEgG8opb6avUg1TdMmZ7eYsVvMPP7+K/nVtmY+8JvdSR/X0hfg0s89wgPvunR0P3f3xfXcfXE9P3m2kX/sb6d7KMzCYjed/hAXLy6mrsjN23/6whlj6Bs+++Sy02piaZkHh9U8esF4Jlr7g2ypL0w6lXdVpReHxUwwGqW1L0jHYGhcwnpLXUHKmxqOlCfpGY4kjQmME6BkrGbhyuWlvOvqJbPiZCNFPgj8QkQ+CewAvpvleDRt3hKRzwO3AmHgKPBGpVRfksc1AIMYx8lRpVSyAVazVrpGzJ5XV8D+1oHR+vzZ0HmGi7Yiwks3VPHSDbpxXq5SSj0uInVT3D/26oibU6mR64GHlFI9ACLyEHAD8PM0hTqOw2rmwkVFXLioKC3Lr/I5R2e8JROPK7r8Ifae7Of5hl62NfSwq7l/2g0n0yWSw6O5L1hYyKvOq+GGVRWjZWu05HRyeZbZUl/IH995CU8e7uJPu0/S2h8kEo2Pq4+49+QAi0rcFLntHGwf5KXrK3nn1Uv0kH0tmRBwlVLKLyJW4EkR+QuwAqgBliul4iJSmtUoNU07TbIT28SIjF8CdUAD8Mp0jcbIRSLCK8+rwW418e5f7Bx3X5Hbxnl1hdy4ppzuodBpF1Fff8ECXrPFaJI2tlbaZMnRicteVJo3rccmE4jEsVvMPN9wds8HI84t9YXsbu4bHWm9pb6QHYkSFckU59lSnlg+W2aT8OrzaviXKxZRXTA7ayrPhFLqUeDRxM/HAN1FWdNyw0PAh5RSURH5LMZsgw9O8tgrlVJzsnPXlvpCbBZTSpNOtYWujDSmPROlQCk1ny5gzksi8jLgf4BS4ObEzVVA05iHTdpEdy4ymYRSr4OrvA6uWl4GQCgaY2/LSLK5l+2NPfSew4CJs5HqBtupUOKx89lXrBn9O2lnppPLs9QlS4q5ZEkxvUNhfrb1BC+e7KfbH6a5N0BFvoNVlV7W1fi4YXU5Lpv+N2vJKaUUMHJl15r4UsC/AK9VSsUTj+tIvgRN07Js4ontPcA/lFKfEZF7Er9PdlI8Z922voq/7GnjwReNepFvvWwh99yw/IzlH8YmlR/a187nHjzA4Y7kU4NXVXpx282EI4qdzX10n2VieUQ0biSYA5EzNyWczNbjPVhNgtdpQakzJ8Zzpe5fXZGLL71qPRtqC7IdiqZp85xS6m9jfn0Wo2TNvFPmdfDS9ZXct605ZcsMRmKsq85nX+vApBc9M+HixUU6sTwPKKXuB+4Xkcsw6i9fM5Pni8hbgbcC1NbWpj7AHGG3mNm0oJBNCwrhcuPCy9HOIbY19PB8Qy9bG7qnLDmXCr3DEeqLXRzvOrv+Ial289oKPnnb6qR10LXJ6azjLFfgtvGvVy7OdhjaLCYiZmA7sBj4ulLqORFZBLwqccW3E3iXUupwNuPUNG1abgOuSPz8Q4yRkfMuuQzwf6/byBNHurBbTFywcObTD69ZUUqVz8nTR7v45J/3j7tvQ42PHSnqcu+ymlhe4R1Xe/hcROKKSOD02tHJDASilOTZp6w/mW6v2VLLR29egduuD0k1Tcs5b8KYDZSMAv4mIgr4llLq3skWMhuTVLub+/jL3tQ29Bspy5TvtFLotmVttOIVy/SEzPkkUUJjoYgUYzTMvWLM3dUkZhEled69wL0Amzdvzr1CxWkiIiwuzWNxaR6v3lKLUoonDndx7+PHePJI+iZqlHocWU8u5zutfOKlq3nJutTUWJ9v9JG8ps1zSqkYsF5EfBhXd1dj1GAOJqbZvxz4HnDpxOfOxoNlTZtDkp3YlimlWhP3twHzdi6XySRcnmigcjZEhJWVXlZWejnWNcTPnjsBGI2IXrqhCoRzrhm5qMRNIBxLWWL5bOS7rFlJLjutZr5wxzpuXluR8dfWNG1+E5G/A+VJ7vqIUur3icd8BIgCP51kMZcopVoSpeMeEpEDSqnHkz1wNiapHj7QwWCSJrep0B+IsKzck8Xk8tkfG2izg4gsBo4mGvptxDi37Qb+CnxaREamSl1HotGulpyIjDYl3NvSz72PH+PPe1qJpbgxYPdQCItJstZw8PKlJXzu9rWnNdzUpk8nlzVNA0Ap1Scij2A0NWgGfpu4637g+5M8Z9YdLGvaHHLaie3YOxMH1EnXS31haGY+/bI1vGJjFZGY4vz6QkSEV2+poaFrmN+80MxPnm0kGlMzKjNR5rFzsj9IIHz2ZTBSIRTN/OtvXlDA1167kfJ8fQCvaVrmKaWmnB4vIncDtwBXJ0rIJVtGS+J7h4jcj1E3PWlyeTZ648X19AyF+dEzjWlZ/oHWAQrdNnqGkjd3TZcyrz1tzQq1zBGRn2OMQC4WkWbgYxjlHVFKfRN4BfAGEYkAAeBViXW5R0Q+ATyfWNR/jzT3085sdVU+X33NBt5//TK+++Rxfvl80zmVcxvrSMcQG2ry2dncT/Ktbnq4bGY+cvMKXrulVpfLOUc6uaxp85iIlACRRGLZCVwLfBb4HXAlcBy4HDiUtSA1TUtqkhPbdhGpUEq1ikgFkLReur4wNHObFhSO+91uMbOs3MOHb1rBbesrqStyMxiM8tcX23BYTXzwN3umXF4krlhZ4WV7Y/abG51fX8hz51gzerouXVLMvXdu1h23NU3LSSJyA/AB4HKlVNI52iLiBkxKqcHEz9cB/53BMNMu32nlv29bTWP3MI8d6kz58geCUc6rK8h4clmXYJoblFKvOcP9n8U4p0123/cwZuVqZ6mm0MXHX7KKd1+9hJ8828gPnm6gOwXr8o6mfjYvKGBbho6Nz6sr4At3rGNBkTsjrzfXmbIdgKZpWVUBPCIiuzGu4D6klPoT8BngFSKyB6PL7luyGKOmaROIiFtEPCM/Y5zY7gX+ANyVeNhdwO+zE+H8sqoyH7fdQnm+g7suquOVm2so8dinfE7PUJjjXUMsKHJlKMrk7GZT2qY+T/SaLbV85y6dWNY0Lad9DfBgzAjaKSLfBBCRShF5IPGYMuBJEdkFbAX+rJR6MDvhptfGOdZo1aX3P5qWMgVuG++8eglP3XMV7712aUqWua2xly11hWd+4DmwmU18+Kbl/OKtF+rEcgrpS3eaNo8ppXYDG5Lc3gfcnPGANE2brjKMGulg7Mt/ppR6UESeB+4TkTcDjcArsxjjvCUinFdXwAN7pm6G1DMUpmcozOa6ArY1ZGcEs9dpJRSNYzULkVj6BrG/6+olvP2KRdgt+sRe07TcpZRK2ildKXUSuCnx8zFgXSbjypaBYGTK+y9ZXMwlS4rxOqzkOSy09Ab41bYmjk2jnvLRziE8DkvGLnCCUe9f07TUcljNvPOqxTx7rJunj3af8/K2NvSkbVbdqkovX3zlepaVe1K+7PlOJ5c1TdM0bZaZ7MRWKdUNXJ35iLSJPnTjCmxmE3/Z20YoOnUt5m0Nvays8OC2W3g+w0nmkWaCFfl2LGYTTT2BlC7faTXz5kvqUzaiRdM0Tcucrikavl62tITv3rUZq3n8ZOh/vmwhjx3q5PtPN/Dk4U4m68/VMxRmS10BWzO433PadPpD09JBRPjkS1dzw5efmFEPksk8d7yHLfWF7GrqO+Nx9HSYTcLbr1jEO69ags2iCzikg966apqmaZqmpVhNoYsvv3oDnwxF+dOuk9zz26lrMO9rHWRLfXqnAU6ltT/Euur8lCaXHVYTv337Rayo8KZsmZqmaVrmdPsnr6N669qK0xLLACaTcOXyUq5cXkrvUJiD7YM09wY40DrAX/a20dJ3aj8Ty2TnLsBp1UklTUuXhSV5/OuVi/nS31PTrmnr8R5KPXaqC5yjgyHOLi43X3zletbX+FISl5ac3rpqmqZpmqalSZ7dwks3VJHvtE75OJvFxI2ry7nzggUZiux0fcNTT3+eCa/Dwi/eeqFOLGuaps1iS8ryJr1vOtPKC9w2LlhYxO2bqvnoLSv5x/su5zVbagGwmoXmFM+WOZNKnzOjr6dp883brljIwpLU1THuGAzxwok+lpTlsaR08u3RZN54cR1/fuelOrGcASkduSwiDcAgEAOiSqnNIvJx4J+AkTazH1ZKPZB8CZqmaZqmaXOLw2rmny6tZ8eJPp440kV4zPS+CxYWcsvaSi5YWMjiUg9KKZ5v6OFA22DG4+wZCiECqRhIduXyUn0gr2maNsv95y0r2bygkP/8/V66h06NYhaBJaUzr1nqsJq5eU0Ff3uxjfpiN9saM1sK6splpRl9PU2bb+wWM5966Rpe8+1nU7rcw+1+ABaXuClw23jx5ADD4dikj/fYLfzf6zdy6ZKSlMahTS4dZTGuVEp1TbjtS0qpL6ThtTRN0zRN03LeO65aAsA1X3yMIx3GAbLHYeELd6yjusA1+jgR4UM3reAbjx7h2WOpb2Ry6nWMJPIVy0o42RfgULufwVCMDbU+9jT3E1dq0jqZ0/H3fe3E4wqTSVIX9CwnIjXAjzAacirgXqXUV0SkEPglUAc0AK9USmWnw6OmadoYIsLNayu4YlkJTx/tprl3mF9vb2YoFMVpO7vmeGuqvVTmOzKeWF5R4eXSJcUZfU1Nm48uXGTMVvj19uaUL/tI5xB0DuGwmNi8oIDBYJSD7eMHZBS5bfzwTVtYXZWf8tfXJqdrLmuapmmapmXIq8+rocBloy8QYWlZ3rjE8ojLl5awtiqfnzzbiAK+/9RxeqcoWXHhwiJqC13UFbs51unnZH+A29ZVEYrF+cJfD9IfGP/cD9+0nFedV8u2hh6uWl6KiNAfiHCyL0CBy0qZ18HJ/iB/e7GNzz54gCWlHva09M/ofQ6FY3z2rwf40I0rZvS8OS4KvE8p9YKIeIDtIvIQcDfwD6XUZ0TkHuAe4INZjFPTNG0ct93CtSvLAHjDhXX85oWzTxrlO2386M3nc92XH6dzcPKGgalkEvjv21Yhoi94alom/OetK9nd3MehxIjjVAtG46MXqMo8dmoKXcSUYjgU4/9ev5FFJTMvoaGdm1QnlxXwNxFRwLeUUvcmbn+HiLwB2IZxUK1HY2iaps1Brf0BvvfkcT580wp9AK9pSbzl0oXTelyB28Y7rzZGO+9s6uPhAx3j7nfZzFyzoozLlpZwyeJiyvMdSZdz+ZISvvvkMZ473kNj9zCfu30tVy0vxW23cPWKstHH5Tut4+pCV/mcvPHiem7fVI3HYWVXUx/fefI4f9x1ctrv9Xc7WnRyeQylVCvQmvh5UET2A1XAbcAViYf9EHgUnVzWNC1HmU3CKzfXnNMyvE4rxXn2jCWXP3DDcs6ry17TXE2bb7wOK9+7+zxe+vWn6fKndz1vHwzRPhjC47Bw/9sv1onlLEl1cvkSpVSLiJQCD4nIAeAbwCcwEs+fAP4XeNPYJ4nIW4G3AtTW1qY4JE3TNC1TKvKdfOTmldkOQ9PmDKUUTuvpU48/f/s6bl5bccbn1xa5+K/bVhOPK0LR+IynMXscRsJ5XY2Pr756Pf2BCI8f6jzDswzhaByllL7QlISI1AEbgOeAskTiGaANo2yGpmnanPWdJ46xv3Ug5cv1OiwEIjEiMaOuk91i4v3XL5v2hV1N01KnusDFd+/azJ3ffY6BYDStr1VT6OR/XraWxWfR9E9LjZQml5VSLYnvHSJyP7BFKfX4yP0i8m3gT0medy9wL8DmzZtT0EZG0zRNSyWdINK07GjqCeAPRXnLJfXcsbmGP+9p5ZEDHdy0pnxGyzGZ5KzrY44QEd511WKK82xsb+yluTdAbIrCzG+6uF5vN5IQkTzgN8B7lFIDY/9GSimVmAGY7Hl6MIamaXPCyb5AypcpAo/8+xXYLCb2tw6ilGJZuQefy5by19I0bXrW1fh44T+uZe/JAZ4+2sUzR7t5vqGHYCR+5idPwWYxUV/kZnFpHi/bUMWVy0sx6z4fWZWy5LKIuAFTYpqfG7gO+G8RqRgzGuNlwN5UvaamaZqWfkop3vzDbZhNwg2ryjnS6aemwMUrN1djMZuyHZ6mzWm1RS5++KYto78vK/fw3muXZi2ezXWFbE5MLd7fOsCPnmmkbzjMgy+2oSakRH+5rYlKn5OXbajSjf0SRMSKkVj+qVLqt4mb20eOl0WkAuhI9lw9GEPTtLnijs01/PCZxhk/r77Yzcs3VOFxWPjri+08d7x7tPns0lIPRXl2ALbU6xIYmpYrLGYT62t8rK/x8fYrFhOKxth5oo/W/iCRWJxoXBGNxYnEFNF44nvi53AsTjSmUAqqC5wsLHGzqCSPSp9TJ5NzTCpHLpcB9ydGX1iAnymlHhSRH4vIeoyyGA3AP6fwNTVN07Q0ExFuXlPBh367h4f2tY/e/vVHjvAft6zg+lXlenSips1DKyq8/M/L1wBwqH2Q/a0DdPvDBCIxvvHoUZp7A7zvV7t4YE8r3737vCxHm31ibCi/C+xXSn1xzF1/AO4CPpP4/vsshKdpmpYxy8s9FLpt9AyFqS5wcvdFdVy4qIj+4Qj7WgfY29LPA3vaCMfi3LCqnFvXVVKcZ2PTgoLRgQ13X1xP52CI7Y09xBW6prKmzRJ2i5nzFxZlOwwtxVKWXFZKHQPWJbn9zlS9hqZpmpYdr9hUzdUrSvndjhb+tq+doVCUV55Xww2rz1zzVdO0uW9pmYelZZ7R3992+SJicUVD9xC/2tZEPK706GW4GLgT2CMiOxO3fRgjqXyfiLwZaARemZ3wNE3TMsNiNvGDN55HJBZnfU3BuBGIFy0uBuB91w0zFI6yvNw76XJKPHZ9LKppmpYDUt3QT9M0TZujfC4bd19cz90X12c7FE3TcpzZJJhNwtIyj27ymaCUehKYLMN+dSZj0TRNy7a11b4p768pdGUmEE3TNO2c6WKZmqZpmqZpmqZpmqZpmqZp2ozp5LKmaZqmaZqmaZqmaZqmaZo2Yzq5rGmapmmapmmapmmapmmaps2YKKWyHcM4ItKJ0cxkrGKgKwvhnI3ZFCvMrnjneqwLlFIl6QgmEyZZd6cym/6fqTQf3/dcf8/zbd1NlVz+XORybJDb8eVybHAqPr3epleufw6ma668D5g770Wvu7lhrnyeRuj3k156vU29XPsfz5SOP7umG/+0192cSy4nIyLblFKbsx3HdMymWGF2xatjnVvm699oPr7v+fietTPL5c9FLscGuR1fLscGuR/fXDFX/s5z5X3A3HovWvbNtc+Tfj/abDPb/8c6/uxKR/y6LIamaZqmaZqmaZqmaZqmaZo2Yzq5rGmapmmapmmapmmapmmaps3YbEku35vtAGZgNsUKsyteHevcMl//RvPxfc/H96ydWS5/LnI5Nsjt+HI5Nsj9+OaKufJ3nivvA+bWe9Gyb659nvT70Wab2f4/1vFnV8rjnxU1lzVN0zRN0zRN0zRN0zRN07TcMltGLmuapmmapmmapmmapmmapmk5JKeTyyJyh4i8KCJxEdk84b4PicgRETkoItdnK8axROSGRDxHROSebMczloh8T0Q6RGTvmNsKReQhETmc+F6QzRhHiEiNiDwiIvsS//93J27PuXhFxCEiW0VkVyLW/0rcXi8izyU+C78UEVu2Y80VIvJ5ETkgIrtF5H4R8Y25L+fW61SYbFsmInUiEhCRnYmvb2YzzlSbbdtwLTUm2d98XERaxnzWb5rkuWndj04S2y/HxNUgIjsneW6DiOxJPG5bGmI7p32fiNyVeMxhEbkrg/FNuk2f8Py0/f2miC0nPndzXbL/bS4esyUzyTYhaexi+Gric7JbRDZmL/LTzXTbq/fD2nRMsX1dJyLPJNb9P4qIN9uxTofMsXO3Kd7POxLvRYlIcbbj1KY2w33RbYl90E4R2SYilyRZnmfMdn+niHSJyJdnS/yJx70msX3ZLSIPpvNznKb4X5V43Isi8tl0xT7T+Mfcf56IREXk9kmWuSnx9z+SOPaRMwailMrZL2AFsAx4FNg85vaVwC7ADtQDRwFzlmM1J+JYCNgS8a3M9t9wTHyXARuBvWNu+xxwT+Lne4DPZjvORCwVwMbEzx7gUOJ/nnPxAgLkJX62As8BFwD3Aa9O3P5N4F+yHWuufAHXAZbEz58d+T/m4nqdwvc82basbuw6Ode+ZtM2XH+l9P+ebH/zceDfz/C8tO9Hk8U24f7/Bf5zkvsagOI0/t3Oet8HFALHEt8LEj8XZCi+pNv0TP79pogtJz53c/0r2f92Op/bXPiaZHuVNHbgJuAvGMd+FwDPZTv+abyXpOuA3g/rr+l+TbF9fR64PHH7m4BPZDvWab6fOXXuNsX72YBxnpG2fa/+Sun/cSb7ojxOlbddCxyYxvK3A5fNlvgBC9Ax8tlNLOvjsyj+IuAEUJL4/YfA1bkQf+J3M/Aw8ABw+yTL3JrYlgjGsc+NZ4ojp0cuK6X2K6UOJrnrNuAXSqmQUuo4cATYktnoTrMFOKKUOqaUCgO/wIgzJyilHgd6Jtx8G8YHncT3l2YypskopVqVUi8kfh4E9gNV5GC8yuBP/GpNfCngKuDXidtzItZcoZT6m1Iqmvj1WaA68XMurtcpMcW2bE6bZdtwLUUm2d9MR9r3o1PFlrgi/0rg56l8zek6x33f9cBDSqkepVQv8BBwQybim2KbnjFT/O2mI6eP32axnDtmS2aGx8e3AT9KHPs9C/hEpCIjgU7DDLe9ej+sTcsU29elwOOJhz0EvCI7Ec7MXDt3m+z9KKV2KKUasheZNhMz2Rcppfwqkf0D3Bif30mJyFKgFHgiVfFOlIb4JfHlThyfe4GTKQ57VBriXwgcVkp1Jn7/O2ncRp5Fru+dwG8wEvinSRzbeJVSzybe64+YxjYxp5PLU6gCmsb83sz0TyLSJRdjOpMypVRr4uc2oCybwSQjInUYV16fI0fjFRGzGNOoOzAOro4CfWNOtmfDZyFb3oRxJQxm5zqUCvUiskNEHhORS7MdTIbM1//1fPeOxPSw702cmpWQ7c/FpUC7UurwJPcr4G8isl1E3prOQM5i35fRv92E+MYau02fKCN/vySx5frnbi5I9r/NyWO2aZos9tn6WUm2DszW96Jl0YTt64ucuhB3B1CTpbBmbK6du018P0qpiftmbXaadD8qIi8TkQPAnzGOvabyauCXYxKimXLW8SulIsC/AHswksorge+mPeLxzuXvfwRYJkYJTAtGYjbT28ik8YtIFfAy4BtTPLcKYzs4YlrbxKwnl0Xk7yKyN8mXHjWSQYmNTaY3OFMSkTyMKyrvUUoNjL0vl+JVSsWUUusxRmttAZZnN6Lsm856LSIfAaLAT7MXaeqc5basFahVSm0A3gv8TGZJzboRehuuTdM3gEXAeozP/f9mNZrkXsPUo5YvUUptBG4E/lVELktHELm+75ssvmls09P+90sS22z43M0FU/5vc+Fze7Zmc+wJeh3QUiLJ9vVNwNtFZDtGuYxwNuObibl27jbx/YjI6iyHpKXYxH2RUup+pdRyjKTlJ87w9FeTpVl5I2Yav4hYMZLLG4BKYDfwoYwEm8RM40/MIvwX4JcYI8YbgFgmYk1mQvxfBj6olIqn+nUsqV7gTCmlrjmLp7UwPvNfnbgtm3IxpjNpF5EKpVRrYuh70mHx2ZDYoPwG+KlS6reJm3M2XgClVJ+IPAJciDFV0pK4Aj4bPgspdab1WkTuBm7BqD00sqGbjevQqLPZlimlQkAo8fN2ETmKMc0w5c3C0mUObcO1NFJKtY/8LCLfBv6U5GFZ+1wkRhW8HNg02WOUUi2J7x0icj/GCenjkz3+LOM4231fC3DFmN+rMWqdp9Qk8U22TR8n3X+/ZLHl+udurpjkf5vTx2xnMFnss+6zMsU6MOvei5Y9k2xfD2DU3B+Zdn9z9iI8O3Pt3G3M+7kB2Humx2s574z7UaXU4yKyUESKlVJdE+8XkXUYfTG2ZyLgCc4l/vWJ+48CiMh9GHWDM+mc/v5KqT8CfwRIzOrKdHJ5svg3A78Qoz9fMXCTiESVUr8b89wWxpe5m9Y2Mesjl8/SH4BXi4hdROqBJRgFp7PpeWCJGJ1mbRhXiP6Q5ZjO5A/AXYmf7wJ+n8VYRonxSf8usF8p9cUxd+VcvCJSIiK+xM9O4FqMWmSPACOdN3Mi1lwhIjcAHwBeopQaHnNXLq7XaZX4/JgTPy/EeM/HshtVRsy7//V8J+Prkr6M5Cc92dyPXoPRkKM52Z0i4hYRz8jPGCfUKT1xO8d931+B60SkQIxp79clbkt7fFNs08c+N61/vyliy/XP3aw3xf82547ZZmCy2P8AvEEMFwD9Y6ac5qQp1gG9H9amZYrta2niuwn4KEYTvJw3187dJnk/B7IalJYqSfdFIrI4sV4iIhsxGrN2T7KMM83KS6dzib8FWCkiJYnfR9bTTDqnv/+YbWQB8HbgOxmIeayk8Sul6pVSdUqpOow682+fkFgmcWwzICIXJN7rG5jONlGlqWNhKr4wDoKaMUb2tQN/HXPfRzDqIx1kGp0LMxTvTRgddI8CH8l2PBNi+znGdLhI4m/6Zowulv8ADmMUGS/MdpyJWC/BGLa/G9iZ+LopF+PF6BC6IxHrXuA/E7cvxDhIPwL8CrBnO9Zc+Ur8TZrG/G+/Oea+nFuvU/Sek27LMAr7v5j4O7wA3JrtWDPxvufy/1p/Tbq/+TFG3bTdGAc7FYnHVgIPjHluWvejyWJL3P4D4G0THjsaW2Kbvivx9WKaYpvRvg9j5MF3xjz/TYnt6xHgjRmML+k2PZN/vyliy4nP3Vz+mux/O9nnNte+JtleTbbOCfD1xOdkD7A52/FP470kXQcSj9f7Yf11xq8ptq/vTmw3DwGfASTbsU7z/cypc7cp3s+7EtuBKEbN2u9kM079dcb/40z2RR/k1PnjMxilqUaWs3PCco8By2dj/MDbMBLKuzFGABfNsvh/DuxLfL06V/7+E573A+D2SeLfnNimHAW+Np1tvCSeqGmapmmapmmapmmapmmapmnTNlvLYmiapmmapmmapmmapmmapmlZpJPLmqZpmqZpmqZpmqZpmqZp2ozp5LKmaZqmaZqmaZqmaZqmaZo2Yzq5rGmapmmapmmapmmapmmaps2YTi5rmqZpmqZpmqZpmqZpmqZpM6aTy5qmaZqmaZqmaZqmaZqmadqM6eSypmmapmmapmmapmmapmmaNmM6uaxpmqZpmqZpmqZpmqZpmqbNmE4ua5qmaZqmaZqmaZqmaZqmaTOmk8uapmmapmmapmmapmmapmnajOnksqZpmqZpmqZpmqZpmqZpmjZjOrmsaZqmaZqmaZqmaZqmaZqmzZhOLs8RIvJxEflJlmP4i4jclc0YNE07RUReJyJ/y3YcmqbNjIgoEVmc7Tg0ba4RkW+KyH9k6LUaROSaNCy3LrGNsKR62Zo2n+jjZE2b+zK535/vRCmV7Ri0FBCRjwOLlVKvz3YsmqZpmqadPRFRwBKl1JFsx6Jpc5WIXAH8RClVnablNwBvUUr9PcXLrQOOA1alVDSVy9Y0TdO0mUjXvk6bffTIZU3TNE3TNE3TtBTQI4o1Lffp9VTTNC21dHJ5FhKRD4pIi4gMishBEbk6yWNeIiIvikifiDwqIivGPPfXEx77FRH5auLnfBH5roi0Jl7jkyJiTtx3t4g8KSJfEJFeETkuIjeOWc6jIvKWxM+LRORhEekWkS4R+amI+NL4Z9G0WS/Zup0oefNrEfll4vYXRGTdmOfcIyJHE/ftE5GXjbnvbhF5cszvSkTeJiKHE9uGr4uIZPp9atpslGT9vFlEAiJSnLj/IyISFRFv4vdPiMiXEz/bE/vOEyLSnpii5xyz7Pcn9rsnReRNE1530ueKyBUi0iwi7xORjsQy3pixP4qmZcE5ros/SBzbuoG/AJUi4k98VSb2jSO/DyX2m3WJ594iIjsTj3laRNaOiakhEdduYGhi4kpEtojIM4nntorI10TENub+SffPImJObAO6ROQYcHM6/76aNhsk2Q68TkSGRaRozGM2ikiniFgTx8RPiciXRKQb+HiS4+SviEiTiAyIyHYRuTQrb07TZgkR+TFQC/wxsd/8gIj8SkTaRKRfRB4XkVVjHv+DxP7tz4l19zkRWZS47wNj9r9+EYmIyA8S971RRPYnnnNMRP55zDKnPBYe2e8nfi4QkT8ltgu9iZ/TMntpPtLJ5VlGRJYB7wDOU0p5gOuBhgmPWQr8HHgPUAI8gLHC24BfADeJiCfxWDPwSuBniaf/AIgCi4ENwHXAW8Ys/nzgIFAMfA747sjB78RQgf8BKoEVQA3w8bN935o2151h3b4N+BVQiLGu/k5ErIn7jgKXAvnAfwE/EZGKKV7qFuA8YC3Gun99at+Jps09k6yfB4DngcsTD7scaAQuHvP7Y4mfPwMsBdZj7F+rgP9MLPsG4N+Ba4ElwMQarZM+N6EcY/2vAt4MfF1ECs7tHWtabkrBugiAUmoIuBE4qZTKS3ydVEr5Rn4HvgI8AbSIyAbge8A/A0XAt4A/iIh9zGJfg5H49SUpVxED/g3j+PlC4Grg7RMeM9n++Z8S920ANgO3T+dvpWlz1STbgWeBRzHWnRF3Ar9QSkUSv58PHAPKgE8lWfTzGPvakePtX4mIIw1vQdPmBKXUncAJ4NbEvvNzGBdulwClwAvATyc87dUY56wFwBES66JS6nNj9r8rgE7gl4nndGDsB73AG4EvicjGMcuc7rGwCfg+sAAjKR4AvnbWfwBtHJ1cnn1igB1YKSJWpVSDUurohMe8CvizUuqhxM70C4ATuEgp1Yixko+MbrwKGFZKPSsiZcBNwHuUUkNKqQ7gSxgbgBGNSqlvK6ViwA+BCowd9DhKqSOJ1w8ppTqBL3LqoF/TtNNNtW5vV0r9OrE+fxFwABcAKKV+lTghjiulfgkcBrZM8TqfUUr1KaVOAI9gHERrmja1ydbPx4DLE6MU1wJfTfzuwEgSPZ64APtW4N+UUj1KqUHg05zat74S+L5Sam8i4fXxkRedxnMBIsB/K6UiSqkHAD+wLE1/B03LtrNeF2fyIiLyKuC1wCsS+963At9SSj2nlIoppX4IhEjsixO+qpRqUkoFJi5PKbVdKfWsUiqqlGrASE5PPC6ebP/8SuDLiWX3YAze0LT5bLLtwA+B18PoAKrXAD8e87yTSqn/l1gPk62nP1FKdSfu/9/Ea+j9qabNgFLqe0qpQaVUCOOYdp2I5I95yP1Kqa2Ji7A/ZcK5qBiz834HfEUp9ZfEMv+slDqqDI8Bf8MYXDViWsfCifX7N0qp4cQx9afQOaqU0cnlWSbR3Oc9GCtqh4j8QkQqJzysEmPExshz4kATxpUcMK7Evibx82s5NWp5AWAFWhNT8vowDn5Lxyy7bcxyhxM/5k2MU0TKErG1iMgA8BOM0RqapiVxhnW7aczj4kAzxnqOiLxBTk3T7QNWM/W61jbm52GSrL+apo03xfr5GHAFsBHYAzyEcZB6AXBEKdWNMYPIBWwfs54+mLgdjHV5dB1nzP57Gs8F6J4wSlKv19qcdY7r4rQkRil/DXhZYoAEGMfI7xtZDxPrYg2JfXFCE5MQkaWJ6bdtiePiT3P6vnqy/fNU2whNm3em2A78HiPhXI8xG6hfKbV1zFMnXUcBROTfE1Pv+xPreD76/FXTpk2MMk6fEaNk4wCnZuGOXY/OdC76XeCgUuqzY5Z7o4g8KyI9iXXzpgnLnNaxsIi4RORbItKYiO9xwJe4GKWdI51cnoWUUj9TSl2CcaCrgM9OeMjJxH3A6MinGqAlcdOvgCsS9WVexqnkchPGKIzixLRAn1LKq5Raxcx9OhHbGqWUF+Mqsq7tqmlTmGLdrhl5jIiYgGrgpIgsAL6NMTWwSCnlA/ai1zVNS7lJ1s+nMUZGvAx4TCm1D2Oa3U2cmobfhTHtbtWYfWt+YtofQCtj1vHE85nmczVt3jmHdfG0RU28QURKMUZM/atSaseYu5qAT41ZD31KKZdS6udTLW+Mb2CU71iSOC7+MNPfV0+1jdC0eSnZdkApFQTuwzjvvJPxo5ZhinVUjPrKH8CYKVCQOKbuRx9Ta9qZjF2vXotRzvEajIszdYnbp7Ueicg9GKXg3jzmNjvwG4zZ+GWJdfOB6S5zgvdhHCucn9gXXzaT+LSp6eTyLCMiy0TkqsRKFsQ46YxPeNh9wM1iNAOzYqxEIYwDbxKjMB7FqDdzXCm1P3F7K8YUg/8VEa+ImMRozHc2UwU8GNMR+kWkCnj/WSxD0+aNM6zbm0Tk5Ynpvu/BWJ+fBdwYO/TOxDLeiDFyWdO0FJps/UzM4NkO/CunElhPA28b+T0x2+DbGPXhShPLqxKRkXqq9wF3i8hKEXEBHxt53Wk8V9PmlXNZF5NoB4pGpusm9rG/Bn6ilLpvwmO/DbxNRM4Xg1uMRoKeaYbuAQYAv4gsB/5lms8DYxvxLhGpTtSQvGcGz9W0OecMx8w/Au4GXsLpyeWpeDD6DnUCFhH5T4z6rpqmTa0dWJj42YNxntqNMfPu09NdiIjcCLwLY9bQ2LI1NowSNZ1ANPG4684yVg/G9qJPRAoZc8ytnTudXJ597BjNfbowphSUAh8a+wCl1EGMK7b/L/G4WzGKrIfHPOxnGFeUfsZ4b8BYgfcBvRgH2VM1B5vMf2FMTewH/gz89iyWoWnzyVTr9u8xaqn3YozEeHmiptQ+4H+BZzB27GuApzIct6bNB1Otn49hlJTaOuZ3D+NrvH4Qo2nJs4lpeH8nUQsuUU/uy8DDicc8POG1J32ups1D57oujlJKHcBogH0sMc12C0YNx/fI+I71tUqpbRiN9b6GsS8+gpHAmq5/xxjRNYiRqP7l1A8f59vAX4FdGH1T9DG1Nt9Nuh1QSj2FkWh+QRm9hqbrrxhlpw5hlJ4JcoYyGpqmAUYfgI8m9qOFGOtPC0Y+6dkZLOdVGGXf9o/Z/34zURv5XRgXWnsx9qV/OMtYv4zRi6wrEduDZ7kcLQlRaqoZXJqmaVo2icjHgcVKqddnOxZN0zRN0zRNy2Ui8jDwM6XUd7Idi6Zp2nxhyXYAmqZpmqZpmqZpmqZp50JEzsOYPXtbtmPRNE2bT3RZDE3TNE3TNE3TNE3TZi0R+SFG6aj3JKbSa5qmaRmiy2JomqZpmqZpmqZpmqZpmqZpM6ZHLmuapmmapmmapmmapmmapmkzNu3ksoiYRWSHiPwp8fsTIrIz8XVSRH43yfPuEpHDia+7UhS3pmmapmmapmmapmmapmmalkUzaej3bmA/4AVQSl06coeI/Ab4/cQn/H/23jvMkaw+275PlXKWOufuyTnvzMIGWGDJYMCAMWAbMMG8nw02OOHwOmeDExhYMMkYeIlmyXkDmybszE7OnXO3cg51vj9KrWm1pG51T56p+7r22pZUKp3uUdU55xeeRwgRAP4M2ANI4JAQ4kEpZajWhzQ2Nsre3t5lDMvA4Nbg0KFDM1LKpus9jpViXLsGtyvGtWtgcPNhXLcGBjcnxrVrYHDzYVy3BgY3J8u5dusKLgshOoGXAX8DvG/Bax7gecBbq7z1RcCPpJTB4rE/Al4MfLHWZ/X29nLw4MF6hmVgcEshhBi83mO4HIxr1+B2xbh2DQxuPq7ndSuEUIGDwKiU8uVCiOcD/4TeURgH3iKlPL/YOYzr1uB2xZhzDQxuPozr1sDg5mQ51269shj/Cvw+oFV57VXAT6SU0SqvdQDD8x6PFJ8zMDAwMDAwMDAwuB2Z6wac46PAm6SUO4AvAH9yPQZlYGBgYGBgYGBgsBKWDC4LIV4OTEkpD9U45JdZpBK5HoQQ7xRCHBRCHJyenr6cUxkYGBgYGBgYGBjckMzrBvzkvKclRdk5wAuMXetxGRgYGBgYGBgYGKyUemQx7gJeKYR4KWADPEKIz0sp3yyEaAT2Aq+u8d5R4LnzHncCDy08SEr5APAAwJ49e2TdozcwMDAwMDAwuE0JJ7N89vFB+mfiZAsarR4761tdvG53F4oirvfwDKrzr+jdgO55z70d+K4QIgVEgTurvVEI8U7gnQDd3d1Xd5QGBgYGBjcVUko+/dgAb9jbhcOyHGstAwP9+6NJGAkl+a+f92O3qJd1PqtJJZMv1PHB8KqdHWxs8yx9rMENzZJ3HSnlB4APAAghngv8rpTyzcWXXwt8W0qZrvH2HwB/K4TwFx+/cO5cBgYGBgYGBgYGK8fnsPB/7lvNc//pIUbDKQDcNhNPXQzyrNUN/MKODiymehXQDK4287sBi2vqOX4HeKmU8ikhxO8BH0IPOJdhFGMYGBgYGFSjoEn+/nun+MSj/Xzs4Qts7/Lxj7+4Db/Tcr2HZnCTEExkef6HHiaSyiGvwAqj2W1lKpap69iPP3KRl29r4w9evIGugOPyP9zgunC5O443sEASQwixRwjxSYCikd9fAQeK//3lnLmfgYGBgYGBgYHB5fGTU5NMRC/l+GPpPF8/PMrvffUo9/3zQ3zkZ+cZDiav4wgN5jHXDTgAfAl4nhDiO8B2KeVTxWP+H/Ds6zQ+AwMDA4ObjOFgkrd8ej+feLQfgKlYhh+dnOTxC7PXeWQGNxMNLitvfXbfFQksA6RzdVQtz+PbR8d5/gcf5u++e4pIKndlBmFwTVlWv4SU8iHmyVpIKZ9b5ZiDzKu2kFJ+CvjUSgdoYGBgYGBgYHCrc2wkwqPnp0llC7xocysdPjvZgoaqCBqcFoQol7mIpHL8+0/O8V8/7695ztFwin/6wRn+6QdneNaqBrZ1eXnbXX20eGxX+9cxqEK1bkB0Y+wJIcQ6KeVZ4H7Kzf4MDAwMDAwAXQ7r5FiUk+PR0v/PTsbQqgQEY2kjQGewPN64r5vhUJIHnxkjm9cu61zpFbw/W9D4+CMX+fLBYd77/LW86c4ezKrRgXezYIjxGBgYGBgYGBhcZz7x6EUefEb3cfuPn54vey3gtLCxzc2GVg/rWlysaXbT7LbitZtx20zE0vklz//ExVmeuDjLp38+gM2s4HWYWdXooq/Ryb6+AC/c3Ipq6DRfc6SUeSHEO4CvCSE0IAS87ToPy8DAwMDgMtE0ycPnpnno9BRDwSSj4RTj4TQeu5k1zS7WNrtY0+xiZ7efdS0uhBBomiSdL5DKFoil85yZjHFyLMqJsSinxqMlCax6+PGpSd6w19DnN6ifJreVf37ddoKJLD89PbXi8/Q2OGh221hQF4GUkjOTMSKpxdetoWSOP//WST73xCB/+JIN3L+ppaLIwuDGwwguGxgYGFwDNE0yMJvAYTGRzOZZ1eS63kMyMDC4gdjc7ikFlxcSTGR57Pwsj52//BbXbEEjW9CIpvMMB1M8fHaazzw+gN9h5tfv7uM3n7f2sj/DYGnmdwNKKb8BfON6jsfAwMDA4PKRUjITz/L94+N86rEB+mcSFcfEMnlGw/r8O4fTopLXJJnLrBadw2FRefGWtityLoPbj9963hp+fn5mRdXLO7t8nJqIMjBbXZJtb1+A/f31KeVenEnwzv8+xJ2rAvzJyzaxpcO77PEYXDuM4LKBATAVTfOzM1O0ee2sbnKCEMTSORLpPOFUjlg6TyydI5rO0+iy8LrdXShGhZdBnTx6bprf+8pR3DYTAzMJWrw2Iqkc2zt9/NWrttDX6FzW+R6/MMP2Th9Oq3ELNzC42Tg4ECSSyrG7x4/PoRvtTETSfPf4xHUdVyiZ48M/O8/ZyTi/8ZzVbGo3XLsNDAwMDAzqYTae4SM/u8BXDg3X1U20kER2efq0i9Hb4OCTv7aHNc3uK3ZOg9uL7Z0+5ArEl/f1BXhqkcDxxjY3iczy5VqevBjk5f/xc9767F7ece8q2n32ZZ/D4OpjRCYMblsKmuSJC7N888go3zg8Sr4oVtXqsTIR1Z1NHRaVrR1eTk1Eic5r33jqYpBffXYv61vc2C3qdRm/wY3PmYkYf/+9U/zsjF6ZMBHVqxNPjEUB+Pn5Gd70iSd57e5OLCYFr93CSCiJxaQwm8jS5XcQTeeIpHIE41l8DjMjoRSPXZhhbbOLX9zViQR6Ag6aPVZ2dftX1DKUyOSNQLWBwVXk/FSc7x0b54cnJzk2Gik9v77FzY4uHz8+NclsInsdR6iTzmk8+MwY3z02zsu3tfHHL9tEk9t6vYdlYGBgYGBAJl9AFQLTDaTBmszm+a9H+/n4IxeJZ5YfVL7S7Onx88Cv7iHgtFzvoRjcxGhSIhBAfQFmm0lhfZt70cAy6OvMatX89XJ0NMJ9//wQ77hnFb/x3NW4jP3rDYXxr2FwWxFOZvnHH5zhyFCYC9NxMnmNTW0eehscOK0mEtkCbR4bHX47hwbDJLMFnuoPYreo3NHr58xkjGgqz49PT/L1w6N8+q13cN/65uv9axncoKRzBWzmS8kHu1mp0DQdi6T5r5/3s73Tx+MX6295PzsZ5+++d7rsuTavjS6/g06/nd5GJ3etaaDBaSXgNGMxqWhScnE6wZHhME9enCWd09Ck5KEzU9y/qYVfv3sVa5td+J0WpJQ8dGaa/pkEWzq8bGr31JzApZSGDpaBQQ1OjEX4hQ8/VkpgzufMZIwzk7HrMKrFyWuS33/xBiOwbGBwhfiPn5zjc08O8o57+njd7i6+fWycN+/rNuZOA4Ml0DTJD09O8OnHBjgwECwVVeztC7C3r4E7VwXo9Duu6ZhyBY2nB0McHAzx6ccGmIlnrunn1+KV29v5x9duK9t7GBishESmQLZQnyRGi9uK3aLyzHBkyWO9dhM7u3yMhFJMr+C6URVBJq/x4Z+d50sHhnnf/et4/Z7OGyrhdDtjBJcNbivsFpUv7h9ifpeH1aRwcjxaetzgtHBoMFzW1pHKFjgwEGJts4toKk5PwEFek9y7tula/woGNyDZvMZPT0+hKoJWj41zUzE+8/gA4WSuLDizptnN0ZHKiTeVK5DMXX473HgkzXgkzf4B/fGHfgQuq8q6FjdHhsNVnaTn+MGJSX58cpJWr4271jQyHcuUKq5NxYD4XWsa+aU7umh2W/E5zJydjHNgIMiF6QR/8YpN9DQ4DbkYA4N5RNM5fvcrR6sGlm90Dg2GjLZDA4MVks4V+NCPzjIwk2AomOT8VJy8Jvn606NMxzJ84tF+xsMpnrOuiX2rGq73cA0Mlo2Ukn/+4RnuWtPInp4AFtOVDe5MxdJ89+g4Xzk0Uur4m2NgNsnAbJIvHxwB4KVbW/mHX9yG22a+omNYSCSV4xtPj/DAIxcZi6Sv6mctl/c8bw2/c/+62zphJYT4J+AVQBa4ALxVShmuctwAEAMKQF5KuecaDvOmwGUz8aod7fzvkepeIHNsaHUzHkkzGVs6ULynx08omWUqlkHTJA1OC3lNW9LcrxYz8Qx/9I1jfObxfv7opRt5rlHwd90xgssGtxXnp+IslA8KJstbkSMpXQfoqf4gnX47LqvK6Yk4oMtkAFycTvCt99xdUYVqcHuRK2gcG43w8JlpPvKz81UDSENB3czA7zBzYqx6RleT+nHrWlycnYxf1pjcNhMbWt1oUg8KHx4O8/RQeNH3KEIfQ7PHSsBp5fsnJlCFwGVViWcKpd8rksrxf/7n6bL3rmpyYlEVnvehh1nV6CSd0/jWb91ttOMZ3LZIKfn8U0NcnI7znaPjTNWx4L7R8DnMbG73oGnSSBgZGKyAf/vJOR545GLF86cnYpye0LsV/vOhCxwaDPGFd9xprCcNbjo+/9QQH/nZBT7ysws4LCr7+gK0eu1s6fDwut1dyw42Z/MaF2finBiN8u2jYzxyboZCnYnZ7x6b4MJUgk/+2h66Ale2inlwNsGPT03xk1OT7O8P3nDJYrMq+LvXbOO1uzuv91BuBH4EfEBKmRdC/APwAeAPahx7n5Ry5toN7eZCVQST0drr12a3le4GB2fGo8Qy9RVIPTMSZle3D5tZxW5WOTUepTPgYH2riXxBFvfV0UXPMRZKsabZxfmpS/vls5Nx3vLpA9yztpE/ftlGNrQaniHXCyO4bHBbcXE6wa5uHyZFsH8gBOiVyzazQjqnsafHz8HBUOn4kVCKNc262VrAaSGZzbO6yUlvg5O+huWZsBncenzj6VH+6tsnidWhsZbI5FEVgVaovigNJrK4rCp7ewPsH6iuV2VSoJppb8Bpoc1rw2FRmYikOTAQYnO7h4vT8UVdfrv8dlq8Nk6MRen2O4hlchwbjXDnqgDnJuNsbPNwoHidbGh1E19gwOCymvDYzBwZDgNwYTrB/ZtamIym8drNxmbZ4LYkr0nOT8b47BOD13soKyaczPG8Dz5Mg9PCU3/0fKPd0MCgTsYjKf7r0X7++8n6rv8Wjw1VEYyEkrztMwfY2ObhbXf1sb3Ld3UHamBwmXzt0Ejp52S2UOp2A/j+8Qn++9f3LXmOeCbP558c5MEjY5ydjF1W4PbMZIwPfP0YL9vWxvM2NON3WMgWNFLZAuFkltlElg2t7pKR7nxyBY2h2SQXpuNcmE5wcTrOhek4F2cShJPLNx+7VnhsJj72K7t59urG6z2UGwIp5Q/nPXwSeO31GsvNjKZJhICRsF4g1dfoxO8wk85p2MwKx0Yi9DQ4ODAQYmuHZ8mA8By5guSp/hDdAUepG+HMRLk03KpGJ8lsvuR/tZCRcIqdNebHR8/N8NJ/e5TX7+nifS9cR7PbVudvbHClMILLBrcV4VSuVMU5d6O0mBTOTsaxqKIssAx6RafDbKLDbyeX1zg3pQvQX5hO8FR/kDuNVsbbmo8+fKGuwDJAtiDpDjhKlczVMKsKqQXyGHf0+gkmspgUhalYmoDTgtNiwqzqjx1WExem4gQXmIFdnI6zvctHMlsgnMzR4LQQTGQYDKZK5z0+FmU4pD+er/s6EUnT2+Dk8FCopEcOEM9o2M0KqZyG22qir9FZCizPsb8/yNs+cwAB3L+pheesb+KetU3kC9IwvzS4LTCrCn/xC1t49ppG3vXfh673cFZMh8/Od95ztxFYNjBYBt87NsEnf96/6DF7+/z0zyRZ1ejkwWfGODkeJVfQGJxNYlYFH/zhGT765t0VRrv5gsaZyRg2s4rfYTGSuAbXjalYumY3HsBwMEm+oPHw2enSPsusCvoanfQ1OnFZTXz54DAfe/hixfp1pewprpc/8PVjNY8RArZ2eLmjN4CUMBRMcGFal67Z3eNn/xJmZDcSXQE7n37LXtY0u673UG5U3gb8vxqvSeCHQggJfFxK+cC1G9aNzVcPjfDJRy8STeVK0i9mVVR0wc4VH6VyGt0BO0PF/WU9eGy1Q5AXZxI4LSo7u7wcH4uSW1CUdUevv/TZ1dAkfOnAMA8+M8ZvPGc1b7+nD4fFCHleK4y/tMFtxZb2S20S/TMJ+tH1f0AP/i3EpCqoCkyEUyx8+Y++fowvvONOWr03blZMCKECB4FRKeXLhRD/A+wBcsB+4F1SyoqUvBCiAMytzoaklK+8VmO+WShoko+9eTd/891TPHJ2uuoxZlVgM6mYTQodPhvnpxZ3x70wnWBbp4ftXd5SpcTCCTRUZwXF5g4vT168tEgeCiaxm1U6fDZGw2kyOY31RS3m+ezu9iOErhdZ0HRdu/koAp67romHzk5zdLRyYxFJ5UrSMp99YrBUvfmsVQHece8qnrehBdD/fkttiiPJHFazYhiTGNx0aJpEu8FaZ5fLaDjFt54Z48139tzWGo4GBsvhrjWN/PLeLr56aIRcQRJwWrh/YwvdDQ6cFpXzU3E+/9QQAD67GVfxuQanhWetCpArSB45N8OvfWo/b7mrl06/g2gqx9nJGF97epRT8zxChACPzVySH3jHPX20eGw0ua1sbPXgN+SpDK4SzwxHKoI+8xmYTXLn3/30mhrdzcQyzCayNLmsNY3CpISjI5Gq/idnJmJ0+u2MhOoPkl0P2rw2nrW6gT9+6UYaXLef6a4Q4sdAa5WX/lhK+c3iMX8M5IH/qXGau6WUo0KIZuBHQojTUspHqnzWO4F3AnR3d1+R8d/IpHMF/vJbJ4im9cIpsyrY2b140uX8VByTItjbG+DwUIhcHWvf42PRMm+rhSSyBQ4PR/A5zLitJiSgSVkhbboYyazue/A/Tw3yuy9czy/u6jRk3q4BRnDZ4Kbg8Qsz7OjyVc08aZrk1HiUh85O81R/kNl4BptZZXWTkxdtbuWetU2lhffObj9vv7uP/35ykExRLqCWbIBZFbgsJg7XcD69OJPg7Z87wPvvX899G25YAfn3AqeAuaj6/wBvLv78BeDtwEervC8lpdxx1Ud3E6MqgvWtbl67u5M9PX6+emiEoWASIWB9ixubWSWeyekB5Qw0upbe5LX7bOQKsmzzuBIanBYOVsnqpnIF2n0eehqc5DXJVLTSjOTQUIhVjU4a3VZsZoVtnT4KmkSTkqeHdFPAUHJ5VSbrm108cTHIExeDvHhzK5qUHBoMsb3Lx++9aD0b23RtV03KsirJP3vwOP97ZIy71zSyrsXNiza3GMZHBjc0mib5wv4hPv7IBYaXUcVxo/Kn3zzBD09O8qHX7ygzJzUwuN1J5wpYVKVis7q+1c3fvWYb77t/Peen4uzo8mIxqaiK4PBQqMwc6VxRM1IRuv/HExeDrGrSJdcODoYquukWIuUlnxCAv/3u6dLPZlXw0q1t/OqzetnV7TMSRAZXlGhq6UKHaxlYhkvFENKyssRuJJVDVWBvX4BcQcOkCE5PxIilV2Y2drm0emz0NTpZ3+pmXYub9a0u1jS78dqvrmnhjY6U8gWLvS6EeAvwcuD5UlYPR0opR4v/nxJCfAPYC1QEl4sVzQ8A7Nmz5+auGKiDx87PYJ63D1sqsDxHXpPsHwiiKoIt7R6Ojy29j32qP8i2Ti/np+Iks9U1m8PJXIUszXLXopPRDL/31aN8+rEB/vhlG7lrjSEhczUxgssGNwVv/fQBMnkNt81Ei8dGi8eKz65rIB8bjZDKFtjZ4+fUWJTZYnvVocEQXz44gtdu5iVbWrlvQzM9AQe/ff86XrSlldd//AmkhOFQkr19ASajaQaLCxMBdPrtZYv2ahwfjfLu/znEJ391D61eG6ubXDfMAl4I0Qm8DPgb4H0AUsrvznt9P2C4P1wmL9vaxvM++BB2s8prd3fyzSOjJbOe+ZydjC/ayiOAaCrPWPjy3adnE1lcVhPxBZIdu3v8HBoMsVRS+eJMAiFgY5uHXF7DpCoIAaubnPgcFo6Phusax7oWF06rCbN66Zr4/omJ0s8/PT3F/v4gWzo8nByLYlYV2n12mt1WClIihMBiUvj5+Rl+fn6Gzz85iNWksLbFxRfecadR0WxwQxFN53j/l5/hRycnr/dQrihPD4aYjKaN4LLBTUe+oCGhbLM8hyzOMfUSSeZ4+Nw0H3voAsPBJLFMHpfVxD1rG/nwG3dVdOIEnBZ+cGKCt3/2AIoieODNu5GCim4hAItJobdBlwo4N1W5flgJuYLkm0fG+OaRMbZ0ePjVZ/Xyyu3txrxpcNlIKfmPn5673sOoSofPzmh45YndYCJXFkyzmRX29gWuuVzGH710A++4Z9UNs6e8WRBCvBj4feA5UsqqOoRCCCegSCljxZ9fCPzlNRzmDYvdopbiKADnJ2M0u611G1MXNImkvutwQ6sbq0kpzs/1GQIC9E+vzPj+5HiUN33yKZ6/oZkPvHQDa5rdKzqPweIYwWWDG45cQWMsnEKTenbqRycmSlXGsXQer73AwEyCichsmVRFKlPApAp29/g5MhQqvRZJ5fjSgWFOjEU5PRFFIPj9F6+n0WlhOp4llNQXEqoAv8NMKJlDUQT9M0l2dvsIJsI1x3pHr59ktsB7v3SE2USWN9/ZzV+/autV/Ossi39Fn2Ar7p5CCDPwK+iVzdWwCSEOorcU/b2U8n+v0hhveqSUvOve1bxmZzuv+s/Hy9oEVUWwu9sPQj8us4i5XnfAQTCZxWpSFj2uHsyqIFeoPIcqxJKBZdDHrUl4eiiMz2Gm2W0lkS3Q5LISTWXJ5Jc+yZymcypbYG+vv+Zx8Uy+TL5jdoH23sY2N6fG9c12tqCRLWg8PRTmiYuz3Le+GU2TRpuTwXVFSsn+/iB/8LWjFTIytwLdDU62dHiv9zAMDJYkms7xs9NTPHlxlmeGI4xHUvzk/c8lsEAeYnA2wVs+fQCbWcVhUdna4eXPX7m56jmllHzs4Yv8y4/Okl0wr8Yzeb53fILX/Odj7Orx0+y2IQTYzSpP9c/y3WN6MtXvMPP+rz5DTw0j6HRO4/REjO6Ag/WtHvqnEzXb+lfC8dEov//Vo/ztd0/xS3u6ePOdPXQFHFfs/Aa3F0KIGzZJ0em/vODyQtI5jUQ6T4vbymSdAbbL5Y5eP2+/2wgsr5APA1Z0qQuAJ6WUvyGEaAc+KaV8KdACfKP4ugn4gpTy+9drwDcSuYJke6eXo6MRpASvw0LAaa47uAxwoih5sdh12OK2Vi3EqkWrxwbFOM3cnnClxDJ53vflZ7h3bRNveXYPjYbp3xXFCC4b3FD8x0/O8ZGHzpPOXVrA7+r2lX5e0+ws6db2NDiYiWVIZAs0OC0cH4uQyWtMRjN4bCZ6G53Yi4uffEFyaGiuYlTy1985xdYOL6sanTxVrCQtSGhwWQklcxSKEbhjIxH29QW4OG+h7zArJHManX47h4fC5DWJ26py15oG1jTdGKYKQoiXA1NSykNCiOdWOeQ/gUeklI/WOEVPUYtqFfBTIcQxKeWFKp9zW2lRVcOkKrxxXzcPPjOG22aiK2AvtcPv7vazf6C82mFzuxurSSWYyNLoslLQJBemdaOTWDqPx24iW9CWpSu1EFUIMlWCyzmtvqB1QZMEnGb6Z8pbkkZDKWxmhe6Ag1avjWAiU1VHurfBwZmJGF1+O+en4kTSeZwWlUSNtqdaOMxKzUruHxyf4CenJvnJqSk2tXnY2uHljXd2E0xkOT0eY2unfn0LITg7GePYSIQfn5rEYlJ44aZWXratbVljMTCoxe999ShfPTRyvYdxVXjXc1bxnuetvd7DMDBYlFg6x0cfusCR4TCDswlGw2ncVpVfe3Yv0VSOfEFjKJhkNJzi2EiErxwaIZMr4LCYCCazHBkOMx5JISgP5oSSWS5MJ5Zs739mJMIzRQ3XNc0uxsOpsvkulMzhtZt54sLsoucZCiYZCibZ2xu4osHlOcLJHB9/5CIPPHqR529o5lef1cvdaxqNBK3BsvmHX9zGmz75VEWH3PVke5f3qlQYO20mClIyFctwtXURzKrg716z1bgmV4iUck2N58eAlxZ/vghsv5bjull4zrom7l3byImxKD85NclnHh+gfyaB3axWGM4vxqnxKAJqXi/h1PLkFRtcFkbDKc5MrLy7t9ltpcFlKd0jjo5E+MzjA/yf+1bz63f3YTXdmAmzmw0juGxQk0QmzzMjYQ4PhTkxFsFhMeG0qAScVvxOMz6HhUanBY/djNtmIpvXSOc00vkCqWyBdK5AKldASr2aJJ0roEnY2eVjV4+/ok3x+GiErxwaLgssg149+axVAQqaLKtqHJxN0um30xkw4baqqIpCMJHl3FScaDrPTDxDp9/OVDTDbJVFusOi8lR/kM3tHqKpHMOhFIlMuQxGXpM81R9kQ6sbu0WloEmmYmnuXduIIkTJ9GFjm5dPveWOG+nGdBfwSiHESwEb4BFCfF5K+WYhxJ8BTcC7ar15nhbVRSHEQ8BOoCK4fLtpUS3GfeubePDIKIoQpeDyRDRdMbmeGLuUcZ2rcuzw2Tk/rQdpo6k8e3sDFUHppXBZVfIFSZvPTqPTwoEqWo01pMeqUksvNp3TShtg0K/n42Plxi7NHhsDs0miab11qaBJNnd4eXowyHKKspM5jQ0NzqryNF86MAyA1SQIJbM8en6GizNxvntsgnwxOfS8Dc3YLSqPnJkmNm8D9MMTk+zvn+X/vmLzkqaCBgaLIaVkVZOTvX0BsnmNwdlE3aabNwO9DU6cVmOpaHBjo2m6fuOh4rzXHXAQSmT5+flZPvyzS0sXRcD2Th/xdI5dPX6OjkTY2uHh2GiUH5y4fDmbXd0+jo6Eq85zy+lq2D+gay/77GaeHgqvaCxrml00OC1k8xonxiJlptVSwo9PTfHjU1OsbnLy3ffecyOtXw1uAja1e3j+xmaeHgzhtZvJ5LWShvi1pq/RgddmqSo5cyWYiqYZmE2yt8/P/v7FddAvlxduajXa9Q2uK0IItnR48TnM/OtPzrG9y8szNfynarG+1V1TBhJgXYubY6P1+wspQlRoLy+XJreVEwu0oOOZPP/4/TN0Bxy8fFv7ZZ3fQMfYMRiUCCayuG0mzKrC8dEIb/6vpyou5C0dHo7PuxmYVUGbx8pQqHYmaU+Pv8KUZFWTkz9/xeZSxcRwMMmnft7PSChFd8BBg9OCoggSmTynJ2I8eTFIm9fGWKT8c0ZCqTId2/UteuWwy6qSzhXY3x9iQ6u7Qs9nR6ev5FA6d6PZ3uXFZzMzHrkUiG7z2mj32UsbFtD1t85MxJiMZdjT46d/Jk4im+fx87M8d33TDdHGJKX8APABgGLl8u8WA8tvB16EbnJQNcwnhPADSSllRgjRiB6o/sdrMvCbGLOqsLrZxacfGyg9NxRMsqfXX9Vcbz5zrUMmBXb1BMjlNfb1BcgXJAhdKuZYsUWpGt0BOx0+B/sHgoyFU/TPVFYTA1yYShBwmEnlCqRytaO8FpNSl1kLwOHhMH6HmZ6AkyMjYQDOL9CMHA+n9OqxZap9OC1qSQe9FquaXBweDiMlpLLuUmAZdE3navz2C9Zyz9omI7BssCzOT8WZiKSJZ3JEU3kODAR5+Ox0WbugEPqi2mszMxRMMBG9toZGV5oP//Q8wUSWt93Vh91iBJ8MrhyhRJZTE1F2dfuREsYiKSyqQqffXvc6KlfQMKsKn39ykEyugM2kkM5rpeTnwmCTJi/NWXPrxrOTcTa0ujg9cfmBsbMTsWXPc7W4OJ1gX1+g4nmLKmh220hm8wSLa/SdXT7Gwqmytv3JaJoGp4XDw2E2t7s5ORZjV4+PqVgGr81cKpiYiKR54JGL/JbRoWCwDMyqwr+9YScf+PpRvrh/mBaPtaxz72ogBGxs9eCw6AaZ+YJGOJXjwnQCuDqSVA1OSykxtL8/xK5uH8dGywsqriSrm6pL5xgYXGuSWb1AcHg2xc5uH4eXSHR2B+wAtHhspQLCFrcVi1mpuC9U80FYjCuxWzsxFmVXt69qwvbs5PVJjN2KGMHl2xRNk5yeiJHXNKZiGb56aITJSBpNSn7/xRt49+cPEa3ijjsSSrGj08uRkQgdPhutXjuz8QzbOnR9nvls7/QihODpocrA2sXpBP/y47N84OvHKGiSyVgaKcFjN5VVRQKl4FyH314RXDaromzzcGYyzp4ePzazwmg4TTChL7wT2fLfJZHTH/scZlwWEyPhFPmC5NREjNVNTlq9NpCSk+PRssAy6JWba5p17a2DgyHWNDkByVs/c4BNbR7efGcPv3RH140auPoYMAg8Udy8fV1K+ZdCiD3Ab0gp3w5sBD4uhNAABV1z+eR1G/FNwjcOj/Jfj/ajScnaZhd7egNs7fACkuFgksk6gkyLufLazQq5gkZXwInVpGBRFWwWPYkipeSJi3q7bUGTpUqshcQyeVY1OjFn8qRytceTzWvs6fETSmbJ5DRcNpXTE/GShla71046V+DoaIQWjxWHxcRA8FJAe02Ti/2JS9dNIlugr9G5LM0u0KVvTi6hrSUlpaD7mck4G9vcpLIFmtxWJqNphqpsdH5wYoI33dmzrLEYGHz76Bj/+uPFTYykhDPzdOS6/Haa3FZMqsJYKMXIFdSCvBaMhlP80w/O8MSFWT7/9n3XezgGtwgFTfLSf3+U8UhlYUK718Yrd3Twhy/ZsOg50rkCr/7Px+lrdPD4hVnCyVyZ8db2Ti+5gsZoOM3aZhcXZxIEi91v87sLMnmNoWCKDa1uJqPpy+o8cNvNxJcp/7QYC7vuLKqg3WdnYDaJSRF47WaE0APmcMl016QIMvkCJ8f1dcCZiTi9jU4ODerHDXMpoa0qgg/+8Cxj4TSv2tHO3r7ADVEkYXBjUdAkPzs9hc9h5ptHxmjxWMkVJEeLcjCT0Qz7+gJXLbjc4LRgt6il7/S1orfRUdY1+/RQmDXNLsLJLDPx5bX210OnoYVucAPw5w+e4DOPDwAQTGbpLNiXfE+2IMnkCgwFQ+zu8bO+xc1oOEU0nWdbp5fjoxF2dvuZiKQ5OR6tGjuqxZWakp4eCtPpt5c6zwE8NhN3VknkGqwMI7h8G6Jpkj/8+lG+fFDXiOzw22lxWzk8HEYR8K8/Pls1sAy6VMZ4NI0QMBpOM1rUQ93dXW7YtbvHXxGU7fDZCTjNDIdSekW0pELsPeCw4LKaynRWDw6E6G1wIKVkX1+Ak+NRYsXxCShr9QNKVdIOs8Lmdg/ZvMb2Th8mVSGUyGJSBQ6LiX19AfpnEhSk5N61jTxybgbQpTCmomlimQJdfjtrWzwcHgqRK0hWNznJ5jU8NrNeUSLgyFAYj93M3l4/+wdC/NE3jnF0JMzfvWbrDbFAl1I+BDxU/LnqNS+lPAi8vfjz48AN40p4sxBO5mj32fnLX9jMc9c3l54fj6T05M0iweWNbR68dhNNLqv+XQeiqRyxdL5UiTtXabywKrnBaaHZbWV7p7ek+WhZJCN8cSaB125esqL64GCIZ60KcG4qjkeY2NF1qdp/JJRiVZMTj91EvqDR6rFgNSlkcwWSOa0ixay7AQu6/HaGQ/VtPDx2U1kVci28dnPp54ImS0YPA7NJdvf4qwaXnx7SdTk3txsmZQb186odHUsGlxcyHEqVfec3t3tQhah7QX012dTmwWJSSGbzrG5y8b3juvlYwGlBSonFpGA3qwzMJnn8wgxff3qE1+zqvM6jNrgVUAS8cFMLn31isOK1sYgeDF6KdK5Ap8/ORDjFumY36VyB8/Oqj2YT2dIGMp0rkFxEGzaZLXB6Isa9axtJZPOlIOxy8TvMVQPmK8VsKp/LswXJaCiF22oilslXSEbpFZyVnUt5TZatHZrdVnoaHIyGUszEM+xbFWBoNsEbP/EkL97SxkfetOuK/Q63CkIIG/AIulmYCfiqlPLPhL7Q/2vgdegtkh+VUv779Rvp1WEklOTtnztY9TWLSWF7p7e0RrwadAbsy27NvyLIyn3c+ak4Aaf5inU8zKfLbwSXDa4f+YLG909M8O2j42XPHx2NVARlF5LKFkpz0qHBEN0BR0mT/ehIBLfNVBYbOjoaYVWTE4dFZSyUJpTM1tRovlLxFKdFpSfgoN1n5/hImGROY0uHl41tnityfgMjuHxb8j9PDZYCy6CbdI2GUqXg1IGBEKubnJhVpcLJs81rYySUKmvP39cX4OA8fdh1LS5yVfoC23w2Dg6Eipp3Xiaj6QrJjIHZJPv6AhUmXgOzyVJbUsBhYW9fgEQmj89u5sBgiGyVz0vmNE6MRTGrApfVy8HBWTa3V6/onIikaXRZmIlnCSaydPjsaDLLbCJLk9vKmiYXA7NJHBaVgNPCocEgmbxeIZrJa/rNVIiSvu6XDgzjdZj5wxdvuCECzAZXn5dtbePXnt2Dw1J+W/3hiUmeHgrz/A3NbO/y4XeYGQomefTcDKlcgTavjXc9ZzX3zQtIz2kjv+XTB3j47PSinzub0L+ne+dlXc9PJ9jV7SNfkKgKHBuNlLXqrml2cbpG9ceqJiez8Sxrml08cVG/rqtVZ1ycTiAEOMwq4ZQuXxNwmvE7rRUb80xe4/BwBCH0+0U9G5BOn6OuCpVax+zp9TNdI6B/77omehuM1kOD5fHjU5evyTonw9TqtdETcDAdy3CxhozNlcZtM2E3q0zFMritJn7lWT28akcHsUyOUCLLa3d3Mh5J89KtutllwGnhwlQMi0nBaTUTcFquyTgNbm0+8rPz/PT0VEUBwnze/5Vn+MzjA7x4Syt39AZ4+OwUJ8aiZHIaq5qcaFLjByemyOQK9DY6eXq4fE7Z0+NnYFa/roSAgpSk69CrSOc0RkIpzIogV0dycyEnx2NlUm2Xy6lxvZvuQtGTYUeXj/NT8TIPgeXgtqoEXFYGZ5NMxTJs6/TS5beTyhYQ6MbW17oy9CYiAzxPShkXQpiBnwshvofe7dcFbJBSakKI5kXPcpOymHFfh8/O4SpdqlcKi0nh2Mj1Scj2z1YPHgcTuaJHil5YdKXoCixdIWpgcLX40oFh/uR/j1d9LeCwLBpcbnJbyxKe87vQgVJh4HwuTl9a/woB+3qr7xGtCxKtNpOCSRHEs4WyObIarR4rbT47qiKYimZ4rGisO3ftPn5hlud98CH2//ELli3XYVBJ3cFlIYQKHARGpZQvrzdTK4QoAMeKD4eklK+8/GEbrJRkJs+PTk6ys9tXNPm4tIh8ZiTCqkYnF2cSXJhO0NdYnj3d2xfgyHCYjW1upmNZpmIZbGaFC9NxClI3MomkcpydjGNSRFngeP5iW5OUKiy757X/qAK2dHjRljAdCyazpbZHp1lhXbOLk+NRFtsHnJuKo0n9RleterLZbS1rexoNp2h0WUhl8yVtnvUtbmLpfFlw2m4xsavbz7mpWIWcwccfvsip8Rj/9+WbWFNHFY7BzU13Q/Vqgzft6+YlW1ppclsrEg35goapykQ2d1wsXV97bofPxtA8beJIKlemKdUdcNDssZLJ6YkQl1Ulnqls3fXazfqmOl9YdOM/h5S65IWzGFDXZWhqj1lK3XSpJ+BgMFhdH08RcEcdhoa7un1IeakdeCEXp+P0NjiRSPwOC2cmYljNKn/yso28bk/Xkr+bgcFC/vfI6BU710QkzUSxwtFpUekKOPDazZyeiBJJrSxwtBSxdJ5Gl5UXdvlY1eTEaVHJ5HQD3vWtHta3VlZurDaMhQyuEIlMno89fIH/fOgChToCt8dGIxyrUuH/xMVZVEWwu9vP/oEgqhBsaHUzE8/Q5XdweiJWtvY8ORYtdbRUoydgp9FlI5rOlead9S1uQHJmBTqMV7KgwGlRS1rn1ToCq7Gzy4fFpKBJiSIE2YJGPJ0jkSkQS+dLPgbbOrw4LSomVSGSzpeKSe5d23jFxn8rIfWs/9wXwlz8TwLvBt4452Mipaxu9nCTs5jGcP9Mgp4GBy1uK8dHI3oH2xUkm9euaNKmXnobHIsaceY1yf4BXQLg6Ej4iugw28yGt4HB9eMLTw3VfK1a4LXZbaW30Ukqm79s3WIp4fREDFXoic45dnVf6pwV6GaiyWyBZDbPqmYXAuhr1CVKR0Opso72tS0uRkMpJqroLM+XyAglc7zzcwf5p9dtp9Flvazf43ZnOZXL7wVOAXO7j7dQX6Y2JaXcseIRGlxRPv/UYEn+ASqrCB3WS5Nas9uG22YmnMwhkaXg6YmxGK0eK11+O7OJLI0uK6sanWWZ27wmOTgY4o5eP2PhVCmYPB+XVSWezXNHry6pcW4qzjMjEbZ11teq3uW3oyiC42O6bs+F6TiJotadw6ywoc3DwGyCNU0ubGaVWCaPWVUYCyWLWmEafoeFWDqP12GmK+AotkbqgWqHxVRWsXlmMkajy8L2Ti9Ws0our/GCjc28ZEsbs4ksQ8Ek6VyBTzxyseSY/MjZaV71kcc4+CcvMBYMtykmVaHZY6v52mK87e4+fh3B4xdm+ML+oZqGfqPhNOtb3UxEq7fjLtQxN6mXquznsFtUWjzWZW+mexv062Y5DIeSZdqY85kvv1ELm0lhJp6tyIrPJ5jIEUyEAXBazfzz67fzwk2tWEy3TlZaCOEDPglsQf/nfBu6Yec7gLmS9z+SUn73ugzwFmNoCXPJlZIotuSDXrnR6bfT4rEhgFPj0dK8thLsZhW3zcTdxYBRg9PCW+7qI5nJY1IFPqcFn1GRbHCV0TTJ2z5zoOze3uS2IiXMxJdvelnQJPsHgmxqc2M1K1jNCjaTyrnJGKncpeslksqxusmFoghmYpmS5rkAtnV6MasKZydjDC6QTzozGWNXt2/Z42p2W0mssKq4GolsgeOjUe5Z28ij89butdjS7uHISLhirdDstuoSeF44Mx4lmdOwmdVSd9Ic73rOKv7gRYtrXd/OFAutDgFrgI9IKZ8SQqwGfkkI8Wr0efc9Usrl6Sfd4Dx0ZorzU4uvDQdnkwzO1l7bXS4HB0M1zbiuFs1u26LB5TkODYZY1eQkkc6XmWquhM89Mcj77l93WecwMFgJ//SD01ycqX2dHxoKsbndUypM7AnYCSVzV/R6j6RyZYmkBqcFh0XFrAqa3FbcNnNZYeRkNFPWlbcwruWzmzlXY1+b12SpIx/gZ2emecm/PcoHX7ede9c1XbHf6XajruCyEKITeBnwN8D7ik/f9JnaI8NhHj4zzepmJ+ta3PQ2OPVsvyaZSWQYC6cJJ3VZhNXFAOXNzGgoySNnZ9jS7ilV+j7VHywtBNp9NkKJS1WHyWyhatUIwESx3Xx1k5Nmt4VHzs1WPS6YyOqVEwvaERUB61s9VaswVCFwW1VavHpwGwl5TSNXkGTyGol0jmQ2z1QsQ6Z43qOjEfwOXXs1kS2wtfNSgGp/IsTevgCHh8L0Njho9zvI5Aq4bSZ+fl4f93yjMZMCDU4rw1UCVxva3Nyzponnrmti/Tx9nq6Agx1dPgBesa2dL+4fIpUroAjBg8+M8cjZaV64ubXq38jAoBYv39YOwF1rGvj5+ZlSxVE17Kb6708FTbKt00MmL1EVQa6gEXBYeGYkvKzxmVVR18J7IZqE/f1BPDYT7T57mfzO00Nhdnb5alYkb2rzoElJQVu8MsZhUXnrXb28Zlcnq5tu2c6BfwO+L6V8rRDCAjjQg8v/IqX85+s7tFuLzz4+sOwkykqQUtc0n996uKnNjdNqKi22uwN2Wj02JIJ0roCl2B6Y1zQSmQLBRLY0pzmtKj0NDhqcFt53//pSFaSBwbUkW9D4w5dswGs347Wb8djNmFWFRCbP+7/8DN8/MbGi8y40fF3d5KTbdMn0a2El1aY2D4qiJ13mV0HaLSqpedf3Qsm2elmuaW29PHpuho1t7kUrsEH/PexmtexeNdf6Ozc2s6pXelvN5YnWO3r9fOAlG6/84G8hpJQFYEcxsfsNIcQWdA3mtJRyjxDiNcCngHsWvlcI8U7gnQDd3d3XbtDLIJHJ47Coper746MR/uOn53jyYrBC37sW07EMNpNSlwzNcpDFrtdanXdXg2S2/kTRxWndz2RTm3tJI+rF+MQjF3nj3m7dWN7A4Brx+PkZPvKzC0seZ58XC/M5LRWJ2YVsade9PaQEDYnNpDIRSWFSFaaiada3ehBCDxLPFQw9MxLh7jWNxNI5jo9G+Pn5WTa1eYrzemURVSydL0luHBgIsrbFVQooL9VJtHArOR3L8Kuf2s877unj91604ZYqSLpW1Fu5/K/A7wPz+yPrzdTahBAHgTzw91LK/135cK8cUkoeeOQC3z12aUFrUgQ+h4VIKlvR2uK0qDxvYwsv2dLKc9c3Veiq3oicn4qTzhXIa5LDQyG+8NRQqaK202+nw2cnlStgUgSb2z04zCoHBkO6PEWnl5NjS+uuXZhO4LGZWdvswmFViabyqAIyBY1UtkDAaaloY1KErvk6F1ju8Nlo9dhRFD3oJaUklikQm6qun3NHr58zEzGe1efnoTOX9GjzBV2Lz242kS1ouuEe+jktqigtsOeCYX2NDgJOC51+O3azSr6gEc3kuTAVJ5TM0BWwl5mBvXxbG//wi9twWhf/t7dbVN52d1/p8bvuXbWoRpGBwWLE0jn+7METiwaWAWaTtTe1qxqdNLgspLIFhkN6dcmcjZLPoXcnAKxtdpXuEUvR2+CgwWVlPJKq0Eivl2g6T0O+gN2soCqCtS1u3DYTj5ytrNDa0OpmOJgsBQ16Gxw4LWrVqs433NHF/33FppviPr1ShBBe4F70LiKklFkga2i8X3nOTET54v6hugwmrwZzG9VGlwWHxVTsRFh8TjEpgma3lSaPLsezq9tvBJYNrhs2s8rOBcbPmXyBTzx6kaPLTGo2OC10BRyMhJIkM/lSC75eGGCp0Gacz0I9YSH0QPLJsShmRdDgsuCymTkyvPL2+6lYhvUtblRFXFH9YrfVvOQx0VSurJhjT0+lHmyuIPXWY+XSXOF3mPmDFxsVy/UipQwLIX4GvBgYAb5efOkbwKdrvOcB4AGAPXv2XJ/JZBHe+6XDfOuZMX7w2/eytkXf7n/l4DA/OLE8r4H+mcRVqzDe1e27ZtIYZkXUvR6eI5LKEUvn2NvnZ3//ysaZyhX4px+c4YOv376i9xsYrIQvHhiu6zhl3rzhsZnZ3unl7GS8rGNoDotJYSycJpis9O2ZYy6J6zArbOvwYrOoOMwKDy3YB54cj9bl2aNJPUlmMykEXJaF/vIV1NJU/8Sj/Tx+YZZ//+Wdt3KB0lVhyZ23EOLlwJSU8pAQ4rnzXqorUwv0SClHhRCrgJ8KIY5JKctSI9cjm5vJa2WBZdDL42u15yWyBb71zBjfemYMm1nhueua2dPrRwgYmNHlEHobnbx4S+sN8SX8/JODNQXZobIyag6XRTf7qNeRt7fBwcWZRM2M9oZWN1vaPZgUhbFIiqlYhl3dPhRFYUeXl6FgktFwmtF5wannrGtkb6+fYDJHvqAxFi7Xz9GkHpQKJrIlLeNgIktX0Ul4d7efE6ORsvc0u600zGv9ddtMNDitjARTHE2U3/ScFhWrWWUomGJDq5vZeJYGl4X3vXDdkoHlaiiKqKnHa2BQi0gqx5mJKJ9/crCuRWqjy8pwlYBTu8+G32GuuSCfCyyDLk2zp8dHrqCRyOrVzOenYqRzhQoNPb/TUpf+40L29vlBwoGBEBLon0liMSnYVIXDQ2H6Gh3s6dHvrQL9vhxO5bgwHS9L+g3MJtnR5eXIvHuVz2HmFdva+dOXb7odss196IndTwshtqO36r63+NpvCiF+Fd0n4f1Syop/qJuhiupG4MsHhvnzb50gmS3gtZtZ1+Li+GiE1BXWlKwHXaap9iJ9PnlNMhZJs7PHz689q7fM8NPA4Hrz4DNj/MP3TjMarp4kmUuIZvIawUSWXF6j0W3FYVE5PBRmdl5nixDgtJho89pACJ64WN5J1xNwYLeoFQbVUNT3n7dZnYhmoIYRbL30NDhwWtUrGlzb1e2rq7NIVZSyJJisoaXV7LZyZkIPfLd4rHz5Xc+ixzC5XRQhRBOQKwaW7cD9wD8A/wvcB/QDzwHOXrdBroCpWJo//sZxfnRSDyLf/y+P0B1w8P4Xrqt6zdTD00PhKx5gvlpyG7XoaXBwfhGTsFronXkhdnb7ODUWXVEF99eeHuH9L1xHu88w9zO4+vz7T87xrWfG6jp2zi/BpAjOTsSYLMZ15l/rioCNbR4yeY2JGnP8QpI5jaOjEfb2+atKqQJk6lx3JzIFVje7ODEWXbL4aTGd9BNjUf7vN4/zyu3tvH5P1xX1U7iVqSdSdhfwSiHESwEb4BFCfJ76M7Wjxf9fFEI8BOwELiw45ppnc4+Nhlf83nRO4/snJvj+iQk2tLrLJt8P/vAMb76zh/ffvx6vY+kqgyvN2ckYTw+GFg0sL4bPYWa2Tv279S0uJqKZRVulzk8lsJkVouk86VyBNq+Ng4PhRc97bDTKmmYXwXiGYDKH3aJyR5cu3q4qAlUI7l7dyMmJKMFEFlURrG9xY1H11uBDQyHWt7qZiWWYTWTZ1xfgwEAQR7FqS1UEq5tcJU3ohUG3RLZQqoac+7edjmc4OhxhVeP1TxwY3Pqcm4zxuo8/URb43drhwWExcW4qTpvXhiL0dh+rSSlpTrX7bExFM5hVhVSugMuq61AdWmKBbzerrGl2Mh3LVL0+XVYTd/R6OVgMCIMuX9PqtZZMgqphUUUpyWNWBRZV4fxUglAyi8tqYlO7h7FwiuFQqlRt1ey2LZmZBj34sK3Tx/0bW9nZ7WN9q5uG28uEwQTsAn6rqPv4b8AfAh8G/gpdg/mvgA+iazGXcaNXUV1v0rkCf/q/x/nKoZHSc5FUjgMDIRpdFrZ1utjfH+RG/cN5bCZetq2d337BWlpqaL4bGFwvPvzTczUDy/rcRsXarJaW6dpmF6oiyiQjegJ2UjmNUDJbMo/d1xdgLJLCblaxmhR8DkuFjvGGVheaBLfVVJo33TZT1Tlue5eXgZkkq5ucZRvrZrf1ilVXuq0q61rdDMwkSzJwixFJ5YqJJEksnefQUJitHd4yibtGlwWn1cRULIPDovJfv3aHEViujzbgs0XdZQX4spTy20KInwP/I4T4HXTDv7dfz0Eul2a3jfSCqsOhYJL3fukIu3v8bCsarR+vo5t1Pk8PhdnQ6iaUyF62DnHAaebI0LU180tk81UN4OtlTooxk9cYjyy/u+/sZMwILhtcdb55ZJT/+Gn9EvG5vMbObh/9M4nSdT03N61q1PeRjW4rJ8ai7Ozy0l+lorkWjS4LTw+GqDbVrWtxcWSJBKvLaqKnwcGJsSi9dRb1OSxqzT3s1g4Pj52f5bHzszxydoa/ffXW6xLbu9lYMrgspfwA8AGAYuXy70op3yyE+HuWyNQKIfxAUkqZEUI0ogeq//GKjb5OoukcPzs9xXQsQ7agEU7m+M7R8dLrDU4L8UyOTL7+baLLorKl01uhy6tJXYz/20fH+Z0XrGVPbwCrScGsKphUgUlRMCsCU1Ej0awqZa1pmXyB4WASr91Ck7u+QEk6V2A6luGL+4f42MMXcFpMrGl24bGZigZ19WWebSaFdr+DiWiITW0e3DYT4WSOizPxiszO6iYnOU1WDSwLAXf0+MnkNTL5AnazSjSdZ0uHl/FICiGoaUwGehXy/v4gJkWwq9tHMluoWKhbVFHa1Bc0ycnxKHt6/KxvdTMSSnGm2PLX4LSUAlVtPjuNLisz8QxHhsMIAdFU/Xpan3tigFft7Kj7eAOD5aJpervqn3/rRFlgGfSkyxzBRGX1YipbwKzqG3OTKtjW4iWdK3BhicqLLe0ehkNJVEVhtsp5AeKZPAcGQuws6oqbVIGUYFYUClq+olVpc7sbm9nE4GyCgNOC22YmlS0wEU2Vxh7L5Evv2dPrp6BJ3FZTmeHofFo9NrZ2erlzVQMv2NhsbIb1BO+IlPKp4uOvAn8opSz1sAohPgF8+3oM7mZmYCbBb3z+UM25cyaeZSYexKwKtnf6VqTNerWJpvOcnYwxHEzS7LYaFRcGNwynJ6IkFmimbm73lDrDpJR1dcU0uiw0u21VpScGgyl29/jLNJAXJi27AnYaXWZ8DitumwmTIkjldAM9syq4o9fPTDxL/0yCdS0ufHYL0XSO0xOxsirK4VAKu1kpdTMMziZpclmYjtfXZTCfNc1ONKlXhYEuPXdoiYKM+YyGU2VB+zavjVSuwL6+AAUpKRQ0jo9FS2bVH3r9drZ01GeifbsjpTyKXiC18Pkwui/RTUmuoDFVo1r/0GCIPT1+UrkCe3sDTMcz9M/UX80bLxrHXi6rm1zXTA5jDpOqEFzBNTyfgdkkbpuJLe2eZQfn09ehO8rg1iZX0BgJpdCKQZh3f/5QhS/BUhwdjeCzmwjPi59MxzJs6/BydDSC06KSK0aHD9fZBT9Hq8dWmpsWYjXppn7VKo3dVhOrmp2cGY+VzP60xQJN84im82XykHP4HOayufQ7x8Y5PBTiX35pB/tWNdT7K92WXI4g5d9TJVMrhNgD/IaU8u3ARuDjQggNPcv791LKk5c55mXx5MVZfvtLR5iIlmcN7WaVPT1+ZuIZBmaTxU2il7wmy1woF+K0qGzu8HJmIsaTRZflTW0e7GaV42PhUoA6mMjy4DNj/Ok3T5S9vztgp9ltK9uMCqEHaUyqbs6jSd1F+2Nv3sXOLn+Zvs18UtkC7/6fQ2W6w6AHbWJFnSiTomsNa1Kv2C1oGvmCLqoupUSTYLco5PKSUxOx0mJ5/mLdrArWtrjw2y0ks7rZw2wiy8UaQauFGm9rml2lgDHoLYoBl4Xjo5FF2xHymixVg6xrceG1mzkyFCanSewWle1dPsLJnK7RnM5jNSkcHAzR4bNR0CTxTL4sWBZP5zg2GqWnwcGmNjd5TeJzmMs2BYtxZDiMlNLYpBtcNVK5Au/50uElXbmrMV3sOOjw2RkNpzhabCuqZY7X6LKwqsnFwYEgmtS/3x0+W5lEzUJqmew91R9ka4eHbF6/puZv4mstFOZzsHi/UBWBx26qSPq8emcHf/PqLbe0hvJykVJOCCGGhRDrpZRngOcDJ4UQbVLKuezpq4GVtbHcxqTzBV6wsQW7ReXkWLRmxWCuIDk4qCdjzaogmMiuuMrpanBoMMRbP3OAV+3o4HfuX0dgnjSUgcG15vxUnA/96EyFJN36FjcXpuN1B1N2dfuIpHJcmE4sOr8cGgyxrsXFeCRdtTJpOJiq2WqfK8iyYNbcBtxrN7O6yVn2nukFDvW9DU4mY2n2NbnIFTRMikBDl3nKFSRHFsyjioCtHV6sZlVfpxckBamhCoXdPRaQ+j7h6aHQomvmasxVTJ6v8truHj8vMoymb3v+9H+Pc2ayeiJVoCcs5r5Ha5uX172paZLpK2BymS9c20Crx24iX5BVPT2WSyyd50SderHzyeSvjWmhwe3DRCTNff/80GWfZ32rp+y7PBXLlBK5evf38tfBixm5AxwbjbCuxVU1GO6xmyvkXOs14E5lC9hMCnf0+jkyHMZlNRFK5ugJOCrkOcYiaX75E0/ym/et4T3PX4tJveXlF1fEsnbqUsqHgIeKP4epkqmVUh6kGGiWUj4ObL3MMa6Yn56e5N2ff7rqxjCVK5QFeHMFWfoSrW91MzSbKAs4WlTB1k69BW7hQnQuEOuwqOzt8xBK5DCrCgMLsrtzE8t0PFvWLi6l7qQ9/zqYjmX4w68dJZEtsKHVQySVYziY5IOv3849a5sA+MzjAxWB5YXYzApDwVQpuL63L8CRwfLxb273LBpQzxVkyXVzLmtkVgSb2ty4beWBpO6Ag9MLqkiiqRzrW92cKVaBxTN5xiIpGl3Wkp7eUszdTHZ2+RBCv8ksNP0aCiZL2eGFG4ZtHV5OTUSxmRRaPeVt97u7/Ryqo93KpCrEM3ncNqMlwuDq4LSa+PNXbObN//XU0gdXYW2ziwvT5RPv4eEwfY3OimqT3obyDXKtSbtejo1GuaPXv6zF80L8DnNFsOA9z1vDb79gXc0k223Ob6EneS3AReCtwL8LIXagy2IMAO+6bqO7SdnQ6mFDq4ffZT3//IMzfPhn1UIzl5hbAzS7rezrC3B0JHxdNJmrYTerOCwqqpEUNbiOfPnAMH/yzeMl+aM2rw2nRcVtM3N0NFLScayHcCpX+j4rQl/DTscyul7yAs5Oxtna4Snr/JnP/v7gsua+SCpXtWPv5HgUl0Ulni2Q0zTdNLeGCe/2Ti/np+IksgW2dngYj6RrakzOZ02Tc0UasLXY0eUziiVuc3IFbdH9nwRavbZScNnvWF6CciySZm9vgP0Dl6eVfC2DOKqAdq99xXrT1ZByrgjDS65Q0L2alpC5uRH8m25GhBB/DrwD3ZME4I+klN+tctyLgX8DVOCTUsq/v2aDvE4sFrxdDldDDq6eDoezk/GK+E6D00IoUTn3X5hO0Oiy1FXgFErqknc2s0IomePZqxt4/MJs1WM1Cf/+0/P8/PwM//aGnXQFDE+thdySZWAz8Qwff/gCn3i0f0XvPzMRY3O7h4tTMboanHjtZk6Nx5ZsTUtmCyXjrUaXhdC8oOm2Dm8p6JLKFmhyWUuVhrUwqQpj4USZGPl7v3SEb/3W3bisJr50YGjJ32VVo4ujo4svWs0mwboWF8PBFB1+O167mYImGQ+nynSy5geocprk5HgMl1Vl3yo/mgYKglgmx1CwPFs0p+s2RzpXwGExMR5J0+iysLrJWaz8XrplaCaRqWpaBvoFH07l2NbpJZzMsqvbR0GTeOxmLkzp0h459IrmOVRFkMjmWdvs5NxUApMi+K3nrcViUvjPh86XVbtk8xov+NDD/OUvbDGqPQyuGl77ypIXXX476bze+bCQYEK/BlO5Ah6bme6AvUJ3vh49x6WYXKYR0lwrdCSVI5sv0OV3lMli2M0qY5E0k7E0bV5De24hUsojwJ4FT//KdRjKLcuaZVRqzVVvdPjteG1mLCalokrxWtHT4OA9z1vLq3d2GIkZg+tGvqDx2ScG+MmpKVY1OqDo3X45gZuL0wnsFpUdXT6i6RznpxNsbfcyEc3gtqpsbPMyHEoyHkljUQU2s7ro+axXwPw1ls6zp8fPwcFQRXvtQp4ZidDht7Olw47NrNTd7TAYTLK3N4AmJWcmYzV1Iuvl/FTc6Ma7zfnusfFS4U9N5q8pV/BV2T8QZHunl1xB48xEjGUW3wPU9Mi5Guzs9l81qas57XNVEaxt1jtyFUWU/qwS/Z75rFUNhlzN5fEvUsp/rvViUTf9I+imnCPAASHEg9e6u/5a8+CR+kz7FqOv0XlNjTUXcmw0UnYvWNXkrHlfsJoWn/sXks5pOCxqzcDyfJ4eCvONw6O85/lrl/UZtwO3THBZSsnPzkzxhaeGeejMVJlb8srOB16HBZ/dwngkhc2skMgurhU8n5m4biQ3E88wFc2UBXitJoWZJQLL27u8PDMcwW0zgZTEivp0wUSWF//LI6iK7sQ5NJtEos/3XruJVK5Au89Bs9vKSDhV9rlmVVRUUwMk0gXOFdvw57fjP3tVQym4rLfzVQaf4pkCJ0ejZAqSbF7DZlbY2e3lZDFQLBC0em3kFrhXb2738MxwuKhdqf+t6qHFrUtepHMaqWyB1AKh+DavrepNJuAw0+q1MRFJMx5J4bKqxDMFNrW52dzuZVunl6FgkhdsbGFPrz6WV+/s4KMPnefAQAizSWFds4s2r62m+7aBwZXAtwKzgK0devdBrdteJKVvfKWUIKiaKBsJpdjU5uH0RO3zgJ446w44MKu6RvNoOEUqW2C5+9M7ev2cGosSn9ey0T+TZHePnxOjEWwWleesa2Jbp3fFAXcDg8XI5Avs7w9yejzGVCxNwGml3Wej3Wen3Wcnmsrxj98/vezzjoZSjKIHjHobHPjsZo7UUZl4pXBYVL7yrmfRbBj5GVxHjo6E+aNvHON4sWp4b2+5ZNrlkMoWODIcpitgJ5MrsH8giN9hxm0zl1VJZhfIW1RjYDa5pBdIPRwcDBUDRiY06ahZuQzFe0QoxfYuL9FFTLHn09vgLP1uPoeZfX0BYuk8s3E9qbXc4T98dprvH5/gJVvblvlOg1uFX9jRwdnJGF/aP1zTcyORvbwkBujJl/7ZBHazyuZ2D3lNIgCTooCARCa/eAW11A0+r0QV9GLUksm50hQ0Wdp3L+SuNQ38zv3rrvoYbnP2AuellBcBhBBfAn4BuKWDy/0zK+9OBTAXvayWo7teL1qd9U2pog/XfeubiGfyHF6k83x+MWG9JLMFegJ2BmsUMs7hsZno9JcXPU3HMvgceoHmUkntW5mbPrjcP5PgO0fH+P6JidICdqU0OC2saXYxFk6V2lznt9mZFGj12Wnz2oil85yfii8axH6qP8i2Di+xTPlF2OyxVq2+bfVYaXBZEELQ4LCwtcPDUDBFJJ3HZlZwWkzYLSpeu5nxSJonLgZxW004bSZm45mSBk7/TKLqhb+z218xaW5oddesIBmYTbCqyUmjy4pJCE6MV98cxzIFdvf4OTQYIp3TyOblPHNEicOicrLo4r2vL4BE13ctaBrbOrylhcXevgAjoWRZpfZC4pk8ubwsk9JwWVU6/XZaPXaOjkYwq4LeRidSXgqWB5M5IMddqxvY3x8kp0mEgHAyx+omF2/c11P57+G18Re/sKXmWAwMrgYLEyZz1DIy6PDZGAqmFg0Ig77xnS9Ps5A5Y8ztnV7OTsYq2voVAXf0BhgKJkpa6AAb29ycGo9xR2+AY0s4+c7nyHC4ahHMocEQPQ0O/vbVW2j12o3WQIMrjqZJPvVYP//243PEVrD4XA4Ds0n29Ppp8Vhp99oxqwpC6GYjuYJGJq/hsOhmYrmCRjiVo9FpXfEGWgj4x9duMwLLBtcNTZO84RNPVqw356You1mlp8GB124mk9ewmARnJuJV5SZqMdeZFk7m0KQeFDozEWMoWDugW4vugGPRwNZymAsYNbks3LWmgVAix0QkVVyDlrOzy8fpidiSc/cc8yUJwslcmQSVSRFs6/SWzc31cGQkbASXb3N+70UbeMc9q3j9x5+oKg8zOq+yfiSUpM1rw6KKJYMvc+zs8jEcSiIlVQ3a59jc7sFmVomkcsRSOb1wSlBWOT0UTPDsVQ0cHJzlCsghl7G1w8OBqxi4rpdfubPH0HK9fH5TCPGrwEHg/VLKhV+6DmB43uMRYN+1Gtz1Ym2ze0mT98XY1XN50oeLoS7D+HNHl26kvVj3jsuq1r2m2NPrRxF6B0EqV6hL4317l49X7+woe+7bR8f4fweG+fzb9xnB5ZuVaDrHGx54Ytmt2NXY1xfgwEBw0Ysmr+nVfSPFibYrYKfNY+fMZKzqF3h7l7dCfxh0E5GFzrF7+wIcHAgyEc1gNSmMhFJlrXXpnEY6l4WEPobugINgIqub9xU3x8lFsssbWt1kcgXu6PXTP3PJBMVjr/0VWNfq5vR4lP3TCfb2BdAkpba/ZreVngYHE5E0w6FUmV6efcEFdXI8xqY2N40ua1nLO1BVsmNNs6umodlcIHxts6u0iI9nCpyeiDPX1W8zqSWNaL/DTLvPXto4DAWTpSpqKfUAcjRd/4bmZqPY+nMQGJVSvlwI0Qd8CWgADgG/IqWsKFcQQnwA+HWgALxHSvmDazjs25qJSHlyZUu7h1SuwFQsw/pWR1kSrTvgwGVVFzXhm2NXt68uo8BnRiLs7fOXJH5WNzlpcFkJxjOcm4pXaKSfGo9x79rGimt7KTp8dgZqVHa9ZEsbd61pWtb5DAzqIZLK8Tv/7wg/PT11TT7PbTMxOJtkOpape61ycTpBu9eG32nBaTVxcjRSVuG/EIdFZVObh7fd3ceGVjepXIFMvrDslkCDa0eVuflRwF18uRnYL6V81fUa30rQNMnXnh7h808OVtUQTmUL9AYcDAaTFUUNJmVpQ5/5nBiLsrbFhd2i0uK2MjSbXFZwej7zZduuBB0+G5PRDI+d11truwMOWr12ClLis5vJ5jUmoull618Gk7W1I1fSrbmvL8A771m17PcZ3Hr4HBb+8he28IYHnqx4zW5RS8Z2c8U/drPKnh4/qiJI5QpYisHQbEFjOJhEIFjdrLerq6pAq6MtoN4Ez0Q0Q6vHRsBpBgSKApmcRipXIJktEEvnlm182R2wc2E6cdndC1cCIzG8NEKIHwPV9Cn/GPgo8FfoaYm/Aj4IvO0yPuudwDsBuru7V3qaG4JfeVYP3z8xsfSBNUhfRZNJrc45rN4OqHafvS4vhd3d/pKp/HKwqEqFpNSmNg/pXOG277a9aYPLUkr+9H+PX5HA8s5u34oyMcPBFMPBFAGHhZ1dPmYSGQIOC8dGI+zo8nFiLDKvgrecbEFjXYsLn92CEHB28lL1wuZ2z5LVB36HmaEFQz42Gi0LCoG+yG10WcsW+jazwr6+ANmCxsl5gaqtHR7drVuA327hoTPTKAL29gYoaBqxdJ6DgyH29vq5OJMoZZ/9DjOxdI571jQghODUeGVl5MnxGHt76/u61eNov7C602s30+G14bKqHJnnGBpK5uhtdJYej0fSNDgtpfavUDLHa3Z11jWum5T3AqcAT/HxP6BrUX1JCPEx9ADyR+e/QQixCXgDsBloB34shFgnpTSsi68ymXyBUCKLw6Lis5vxOcxlSaixUJq9fQFy+QJ2i4lT41GGgsmqVc1mVdDuszM4m2RvX4B4Ok+2oLG6yclIKLWExvKlCdPvtCzZJvjIuRn29gV4ejBIvdLNnhqT797eAO9/odESaHDlefLiLH/4taM1kxpXgg2tLkLJHMlMgbwmiaXzK9JGHYukGSuZKJlZ77dzZt5C2WpSeAWekGYAAQAASURBVPXODu5a00iz28qGNk9pQRtKZI3A8o1P2dwspbxn7gUhxNeAb16nca2YH52a5Pe+erTm64v5auQ1XYe0XjJ57bK7FedQrrDmcIffgd9pIZ7OMxhMrqiaeiG7u30cWmRf4LWbyS8zoLa3N8Cj52Zo89pw2UxEU3ksJsFMPIvFpLCl3UuT23qZIze4WVjY4j3HqiYXM/HyNWAqV6ipS9zktiKg9H3M5ArUUQi4LCaiaTr8dg7VGIPbZioWX5hIZPIMziZrdin5HGayBUnySpdCrwCzKoxuvTqQUr6gnuOEEJ8Avl3lpVGga97jzuJz1T7rAeABgD179twA6YeVc9eaxkWlZQJOC81uK+mc7t/T6rFyfipBLKMnbKavQMytFifGo6VCy8XizPVOc7X2mPOxm1WOLqPjdj6/9uzeiuecVhWbWWUZRdi3JDdlcHkikuajD51nPJKm2W1lKlb5Zd/V7cOkKggoGVZIIJvTiGVymBSB02rCpCqEF6kGqIdgMluqKBgOptjV7SOazrO22Y2laBSyMFisCFGq3NjbGyBUrFLe2xtgYLayZaEnYMdtM+Owmhiarb1Y3d8fYlunl6MjETa3u7k4nayoakzntFIw/bnrm5iJZRiLpEpu2netaShVXGgSDgzq8h5zDM4my9w3Q8kcoWQOv8PCwcEQqiJKMhnzGZxNlgLq0XSW/plE1eD7VHTpKsx2n61UQd4dcJDJFXj43Ax+h5kdXb4yE6X5GfO8JlnT7MISTPK63Z289a4+/HUEs29GhBCdwMuAvwHeJ/QU2/OANxYP+Szw5ywILqPrTn1JSpkB+oUQ59H1qZ64FuO+XdE0yXP+8SEmit//ZLZQCi7NEUxmK1xy7+j1MxxMliR8fA691Xhts4tT41F2d/tIZ/OcHI/id5i5MJ3ApOj3SAkcG4lUVD3t7w9y95oGEtkCsTqrwfb3B1nV6KTZbWU4nEIVoup9anePnwvTcY5WqWx72bY2Pvi67ZiNlkCDq8Cp8ehVDSwDnJ6Is6XDw/HolQl8gT7HSqn7ANy7rpGHzkzzf567hvWt7qrH36pz2q3Cwrl5wWse9Hn6rddhaJdFvdrBC9na4SGczF01E62l6J9J1NxLrIT5c/TqJieaZMUalV0BO4WCXDSwDLC+1U1Bk+ztC3B2MrakqSDAw+em+Y+fnV/0mE6/nR1dPnZ0+djZ7WNzu/e2bve9lUnnqkeAF+uKrcZ08TqaimUwKaK0t7zSLOZ/E0tXajh3+e20FKuCZ+IZBoNJVAEtHtvSpobXiHvXNt32VY+XixCiTUo5Xnz4auB4lcMOAGuL3byj6AVVb6xy3C3HfRuay4LLJkWXu9A0GAmnyrqKhoJJ3DYTWzt0ySW/01KxL71SpLK6B8qSHUx1Bpen65jPm9zWFSV/rSalwnBT0ySffLSf1c0uFOX23sPelMHljz9ygc8+MVh63B1w0OKxIiWkixWtA7MJgomlF1f7+gL47GYaXZaygOnlcHwsyo4uHyARCCwmhX19flI5jdFQitlElsloGo/NRDSdZyySKlXTHhoK4bCo9DY4yOY18pqkzWsrVh5f0rdazHRgJJRiV5ePY2ORRVuD1re4ePzCLNl5pYY7u30oQmC3qKSKWVwpdTmKOSmK3kZnyehvPnOO9AVNcngoxIZWF6cnLlVa9TY6yyrEFaGbHTW6rCUzsGAiS4vHhkkRBFxWkHpweDyaZiycwqQIdnaVa0fnCoXSePRAd5gdXT6OjoTRpD7+PT1+Xratjb5GJ70NTroDjtJ4b2H+Ffh9LrXaNgBhKeXcSnEEXXdqIR3A/N64WscZXEEURfDhN+7kbZ85QLTOSsfZRJbZRJYWt5VVjU68DjNnxqNYzWopeDt/UzqXxMpr5QmvrR1eIqkcDota/M/ExZn4ovrn1bg4k2A8msZjNRHJ5tnV7St9zlxFxsXpeNWN711rGvjg67Zf143r0GySs5MxEtk8nX47u7r9FW1PBjcnn39ykL/+zqlr8lnHR3Xt8mg6f1nGJ0KAKgQFKXnznT387ovWA/Dqnbd0t83twL9SPjfP51XAT6SUVycicxUYnE3wrz8+x/8eqVr4tSTxTIHhUKV+q9tmIuAw163tulKmYhk2tbnpbXTqRnvh+j9PEXp7rNmk4DCrtHpt9M8maHJZaXBaODIcYke3f8X3geFgir19gSU39PPXxFs7vISTSxuIHh2JsK8vsGjn5pwU4LeP6rEakyK4Z20j//bLO/HYjCDYrcTqJie/uKuTC9NxUtk8FpOK1aRgM688ULISuZZ6qXedPMdwKFV2n3FaVNY2u5mKXZ1g2Uq4f1PL9R7CrcA/CiF2oIchB4B3AQgh2oFPSilfKqXMCyF+E/gBoAKfklKeuE7jvaa8Ynsb//SD06Xq4LwG6axWVaYU9ETNUDDJ9k7virrwlstcUWYtToxH6PTbSwWGtagnSdPqsa0ouPyqHR0VXfbT8Qyv2tlREXS+Hbkpg8u/8ZzVfPqxgdLjoRW2ne2ZJ0zutqrs7vFzdCS8bK2mhezo8lUEfte3uAkns2VyDFaTYHunl0S2QJvXxmwiS6HYRtvhszEwm6y58NvfH6zQbZ4jmMgSS+fY2eVjKqZnZ6sleM0mhWxeb5NvcFoYDiU5XAwENbutrGlycXw0gkRvQZyKZejy27gwXV3DZn7Viib1Ci6LSaEn4CDgtFRUpWhSNzuaqyTb2xfgwnSCC9MJ7uitNB8EyBUkqVyeZ69uQC0aII2FLv3bu6wmWr02MnmNV2xrp91v57W7OljdXL3C61ZFCPFyYEpKeUgI8dyr+Dm3jBbVjcDuHj9dKzAXanRby96TrFGBspCNbW7cNjPRVLbsHtruszG5wuz0XFKqw2vDadF1+WLpPA6LwuHh6ouXZ61q4L/ftu+qJ3zSuQLDwSST0Qx3rgpUmKZcmInzHz89x1AwSSiZ46139fJnr9h8VcdkcG1YNU8e6VowJ0W1rcNLMleoS+98PpvaPLzj3j62d/oYDCa5b33z1RimwTWmjrn5l4FPLvL+6z7nFjTJ+ak4R4ZDPHUxyIPPjK0oiOS1m9nQ5kJKgdduRhGU7smhRJbz03EaXdemCn/OdHpXt6/u4PKOTh+a1NfGE9EMsXS+VOgQTeW5MJ1gXYsLpGBfX4CCJiloGoqi1Gznr8b+/uCi5tsLqbVGr8ZQMInXbiKSqi9okNckPzszzbnJGLt7AnV/TjVS2QIf+tEZvnF4lDfu7eZ9L1x/WeczuDzymmQymi7r/ASwX0Zw+Wox5/9zOSSyBY6MhLGZlKrdtteDvmu8TrkVkVL+So3nx4CXznv8XeC712pcNwqdfgfP39jCj05Olp47OhrBZlZqdi8oQjAcStZVtHk5bG73LClTm85pdXW3nhiN6F2ENTon1rW4VmScbVIEr9lVWW/X4rGVOiNud27K4HKLx8bmds9luzvH5+kvxTIFDg2G8DnMrG/RM5kDs9WDsnN47WbWtbjIFySqIlAV3bRgMlK5MD0zGcNiUtjR5cOsCs5PxQklc1VNT/oanaWK31ofv7ndQ2iRFsRcQZYEz60mgdNixqQK0vkCihC6+YLUDVTCqWyFOHo8ncNlNeG0muhtcHB8LEp3wM6ZiSg7uvxkclqFfpXLWvl1yuY1zk3Fi7rNlb+NKnTHzXgmXxZMfnooTLvPVrVycjaRZTSULjM3uW99E++4ZxV3rmq4HSqS6+Eu4JVCiJcCNnRdx38DfEIIU7F6uZbG1G2pRXUj8PRQeEX3teFQkp3dvlJyqF6GZpMlo5b5hBI5VjVdMs1cLqlsgVRe49GivM7aZhc2s246dnKByenWDi//+aZdV/W6nYqm+djDF/nmkVFmE1ne/dzVPGt1Q8Vx961v5r71zSSzef77iUEODITIFepbyBjc2Dx7TSNvv6ePjz988Zp+7lw1yNYOD1NVTP3cVhMIShUhqxqdbOv08rev2YrDos+pqwwNxluJirlZCPF5KeWbhRCN6BJUr6715us156ZzBb57bJxvHB7l8FC4bP28XHRZpgAnxyM8dVFfe1YrpHBZTVeso7AeOn12jtWo3ppjb1+AMxMxYukcR4pajXazSsBhqWq4N99QSJdsi9DstrK901vyPqjnb3luMlZmZL0YbV4bF6aXrpRudluxmVXGV5BIXttyeQUbmXyBN33yyVJn07//9DwziSzvv38dDS5D5/l68M8/OMPPz1caM6dyWlk369XCZtaLkWLp/JKV+rEraMSezmscGgwtaiZ/rbiKhd4GBiXuXtNYFlwGPehc6/s/FcuwpcNDNJWvSCRvavMwGk6t2FB3PgsN7WvRP5Nga4dnUcmdgoSxUIqtHd6q87rPsbLE9dZOL/tWXdo/RtM5o4tnATdlcBngk7+2h7v/4WdsaHXT6rERS+c5Mhwmu4hrQHdA11vS3WTzVasAwslcaYHrMCv0Nupu1ADZfIFEpkA0nSOYyBJJ5Yhn8lUN7KqRzWscG43Q5bfrmswtLs5VcbJ02+b9syyYaAT64vbpoRAdvurmCwvJ5CWZfOWid05frtNnZ3ePnyPDYQqaRBXQ1+QqBbkmomnu6PVzeChEXoP9A6Gqwf1q3eOrGp00ua3FAE256ZjfoWtIVzMvLGgSm1mlzWsrW/h2BxxMRdOk50l59DY4+NDrdxg6k/OQUn4A+ABAsTrqd6WUbxJCfAV4LfAl4Neobhr0IPAFIcSH0A391gL7r8Gwb1uklGgS/uH7p1f0/mgqTypbYFuHt2ZrUzWqBZZBN2vJFTQsqiC7wk6ONo+N0WLb0rmpOOem9GDBuhYXPoeF/pkEG1rd/P0vbrtq126+oPGdY+P82YMnyqQ4HjwyRiSV48RohPe9cD3PWddU9j6HxcS7nrOadz3nqgzL4DqQzOb57OMD1/xz+xqdWE0KpydiVbuiYhm9E2cimiaSzNHus3Pfhmbshq7pLUmNufnNxZdfC3xbSnnj9GkXee+XDvODE5OLHmO3qGxu95AvyIrqxzl2dvmYjKURQpfDmGNgJlERwIpn8mzr9HJ8NHJVgy7NbqsuiRFOLdq52Fc8ZuEmutFtwWZSqwaXQTdJWtPs4vSEvmaeimXK9J23dXqxm1Vm4xm8DjOqUCoqqta0uBmrs6K6Xg3pDp+tZjfRUnz7mXHecEfXspPCF6bjFDTJocFQxdr/C08N8f3jE/z8D+4rJdYMrh1PD9Wu3LWalKsSXFYVwa5uH+FUjotTcc5MxrGaRE3d1U6/nQ6fnRNjK/veLsaNoICWzl9/U0GDW59qnje+JWQkjo9GafNaafXYMZt0T7NIKlcqGLoS1f+rm13MLlG5DBBwmuvScg8mcwSTEXZ3+zk07/62ud3D2ckYTS4rfU1Ojo+ESx2/bpsJkyJKhtwLecc9q0o/DweTPPDIRf7qVVvq+fVuG27a2bvNa+fPXrGJeCbPb9y7GkURxDN5+qcTPHx2igceuVihx+RzWDgwUP8XP5nTKqrs5uO2qnVnWUD/wm5s9bB/IIiqCAIOC32Nzgottsy8wOnBwSB39gWYjmfI5jXcNnMp+L1QT6bNa8NrN3FuMk5BUhHMBb1ixGu34LaZcFhMRT0tFZMqUAQUgG2d5ZN6JJXj6cFQmUOns0qVcjVjxHS+UBrvpjZ3qfUQIJHJLzqZX5xOsKbZhQBesb2dX9zdic2kEEnlSGTzxDMFzIrgZdvacBtZo3r5A+BLQoi/Bg4D/wUghHglsEdK+X+llCeEEF8GTgJ54P+TUhornivM158e4a+/c4psXkOTsuTOu1JOT8S4o9d/xcY3MJtc1FW4FmubXUzF0hyuslGJZ/JllVzvfs7qupNky+XQYIi/+NaJqouo0XCKLzw1RKPLes3lEgyuDw6LiTXNrpotcpeLAHoaHPgdFhRFn08FgoODiztfg/5dfd/96+hrcvKCDS1G983tyxuAv7/eg1iIpslF1852s8rWTi8nRyMcHAixodVdESjua3TSHbBzcCBEZ8DBU/3BMu+QyVimovvGYlKwm1W2d+oSb9F0jng6X6+fT930NDhqepgAbO/0YjEpHBuNVG0bHi5qQlerfNxT3HAvdv5qc9S+vgBj4RTtPjvDoSQOi1qX3qXbamJVs5NUJk9vgxMh9GKNdL5APJ1nOpYhkS3Q7LZyvo7q5lr80TeO8YlHL3LnqgA7u/zs6vGxqtG16L3r+GiEV//nY4sG8Aua3glqcO1p9dqBS9e5w6ywoc1DQUqeWWESYim2dHgq7i2ZvOTwcJhVTU4uFr+jTovKqiYnx0ajS2qtrpRzk3F6GxxX3fR3MTI5Y6tlcHV5+Ow0X3t6pOL5epIr45EM45HqScsz41EsRbnVlaLVuQle0+xedE5dyMWZOOtaXKVO+kgySziZK61B7uj1k8oWsJlVnhkOk9MkZlWwty/AoYEgBQkuq0pPg5Od3b7SeT/x6MUbQk7nRuOmDS4D/Oqzesseu6wmtnZ62drp5bW7u/iDrx3lkXPTSKmbblzOF34hHT47q5qcPHqusoVoIZvbPdjNKoeHQqVATUGTpaBro8tCT4MTRcDATJIzEzGes66RdE5DSl0b+cJ0ArMicBWrmm3FoPBdqwMksxpCUKw8trKhzc3ZyTi5gqTTb8drN1PQJKOhFLFMvmQCNseubh9HR2Ls6PJR0CThZI42r5V1LW7SOQ1VEaSyBcbCKewWFYdFIZ7O47GZUBVdK6/ZbUMi2dqhItANASWyrDJ74aI8W5C0++xV2yxAX/Dn8gV+70XrefdzVxvGWitESvkQ8FDx54vobbcLj3kQvWJ57vHfoDvZG1wlXr2zg0gqxwd/eJbkFaoIOT0RY3O7h/NTMda2uImmcqRzGn2NTvKaRiydx25RsZrUmhOzz2Gm0WXl/FR8RZUcEurSb9zZ7eMtz+5d/gfUScBpYVe3n1/c1cnuHj+v/PDPy4J8FpPC5962l66A46qNweDGIZrOXbGW1719AXIFDYE+r0XTOaZimTIPgaWYM/QFvSNnU7uHe9Y2LfEug1uJ+XNz8fFzr9dYFkNRBL/3ovV84OvHSs+5rSbWt7lJZvJcmI6XzSenJ2Ksb3VzZiJGwGFhVZOTQ0Mh+mcS7O31c3AgxN6+AMlsnj1Fr5Nmj41nFlQqZvNaVf3FbZ3eqgHZlbKYMZhJgQvTibqkK2KpHC1ua5nhtaLUbW5fxoEBPSk1Z0DW6CyXiujw2WlwWuifTaBpks3tXiSSsXBqXiCwMnisCj1YfnoiSiZ/eWH6/pkE/TMJvrh/GIAWj5U/f8VmXrK1rerxXz00sqSnzbZOL1aT0bVxrSlokh+emCh7Lq9JhBBYivu8+RX7q5ucZdIrzW4rAacFj91MJleouGbMqsCkKHjtZtp9NmKZPBOR9KLSk8PBJHf0+jkwEGJLh3dJLdYrwZWME6yElBFcNrjKHK/R3XpsJELAaV6xrnI8W7hsLfR6/Q5yy7xOQ8kcoWSObcX7yNYOb1lye36Ca259kStI9vcH8dhMtHhsjIRTzMQztM7TVfbazdjNCkeGdONeA52bOri8GK1eG599215yBY10roDLaiKWzvOX3zrJcCjJocEgy51DegJ2Wr12ktkCJ8YiaFKyp9ePKnSt5Zl4lv6ZBJvaPLhtJgpSksoWyOY1wqkc7X47mlZ58czEsyVdOVURRR3kXGmBuLdYjZjTJIMzCZ6zrpFjo1Ge6g+yvdNb0m0WAhwWlRNjl6qDR0IpZmIZmj1W7BaVZDbP5g4vNrOKlJJ8QTdmSWQLZRdXh8/GbDxbZhhoUgQ7Aj6CiSyJTKa0IA8lc1U31Pv6AtiLbrzJXAGnReXigirt46PRsgt8jrXNLgZnE+xb1cBvPMcILBvceggheOtdfYyEUnz28QFWN7vw2szkNY3TE7EVBZxj6TwFTePetU1MxTJ0+OwcHAwx1X9ps9vpt5PJaSiiXN/N7zCzrsXN0ZEI56fi2M0qU7E0PQEHgzUMU+1mtbQYNquCrR1erCaFqZiJ6BIBZqfFdFUrNPsanfz5K3UzPiklL9jYwomxKGORFFLCm/Z1s6ndc9U+3+DGwmMz8zev2sr7v/LMZZ9LwLL1zeejCPjOe+7hsfMz3NEXoNFlrcvZ2sDgeqFJyd6+AAI96HRqTK9SroUqJPv6AhwdjZRtNs9MxvE5LOzvD5Z0lje3ewglsnV17uztC5C8DL3naizWDry7p7qp9kLcVhOTsQx7+wIoiqCpqGdsUkRN8+3F0IpFMXf0BjgzGauQu3LbTBwdjeC26mv5ejuMCpKqXi9Xgslohnf/z9Ps6PLx/A3NbO30YlYVnhkJ852j43X5SRj+BteHbF6rKCbIFmSpKm9fUY4xV5Ds6vZxbjLG3r4AsrjPPT4WLZNh2dvrZ/9AiF3dPnIFjVAih9WsoCiiTA5lsSRRrqB3TOztC1R0+F4tmtxWxqOLB72vJvOlggwMrgbzK2/nk85rbOv0sT+x8iTOkeFQ1ZhOveQWkbadT3SFmutz0rmLeSvMJrK4baZSp1A0nSea1gtTUtkC3zg8ymt2dQLFBOtskh+cnKTBZTWKlYrcssHlOcyqUlqsOK0mxiIpniqWwC9HImNPsdpiMHgpMDweSZfpAQecFlY3OWtKaezq9lXVF56P125CIjk2b8INztMKVYRgMpohWKw8ti1w8W12W0lmC2QLGuuaXQzMJpmKZRgqjtukCDI5jYlIelE9ttFwGotJLauu2tLuLW0SWj22JQ3E5hbkc6Z8d/T6UQRsaC039drfH2RLhwdVEeQLGi6bicODYfKa5C9eudloETa4pfmF7e2cGI1wdirOmaIO/HK1q4SADa1uVCE4PhYtGYLqFZblq+S5lsI9PX40qbegSknp3jhHKlegf0YPKj97dQP9M3EaXVZyBUkwkaXTbydb0LCbVYTQTUrn7m9mVbC+xcVkLFOmdTyf/QNBRsOpqyaLMR8hBA/86h4AvnZohFavjbvWNF71zzW4sfjF3Z3s7w9yYizCTDzDRHRxTdJa6JUPHuwWE6oQBBMZRkIpWr02fA4LqiLI5QvkNUkmrzETz5bmbNADR+/78hH+9OWbWNXoNJKnBjc04WSWv/3OqZoa/dU4OR7H7zBX6LT2NDg4OhJBFXrAGliWiW0wkeH81JUNND3VH2Rnt4+JBWt6oKoRdVWKl3A0lWMieuk8Poe5/nMswGs3VwS2nRaVze3eUjA5dgMGo44Mh2tqbi/Fvr7AlR2MQV3YLSqv2tHBlw4MV309ksyyrcOLoghGwylimcKiAaSDgyHWNDuX3PPWw0oDVSvhmZEIe/v87O+/Pq3uVzpxZmCwkPUtblRFVJ2X9g8E6fDbS345yyWv6dfr5nY3ZybiVbvSa1HN1LcWuhnf8tcB1SRdFzIaSi0ar5vfwfHWu/pY2+ziYw9fZHe33wguF7nlg8vz+dcfn+XxC7MAPD0UrjvA3OqxLlqhAXrQtsll4UwVg745tEUSMn2NDkyKwrmpOMHEpcCyKqDBYcbb4yeZzeO2mSkUNPb0+MnktVLwB0BK3Wzvzr4AT/YH2V9lzHlNEkpmdWPDTJ6cptVsjeufSZTaA7oDjpIzNugmfxPR9LKCYKoiaPPaODkeZXunl7FImuligHtOB7Mn4ChVXt+3volVTa66zm1gcLOytdPL3lUNPDlvUi1okjt6/Xo7rdQzqfMrNywmBbMisJlVOv12bGa1YlLe2eUlky9UVCjPUW/r0s5uX+m+OV9ra7HkVK6gGyEkFmk3zuY1vrR/iPe/cH1d47gSHB+N8IJNLUaV6G3M00MhzhXlMRwWlS3tXs5OxWomQWoxZybS6rFiNasksoVim3D1Ba/NrNDstmE1KVjNClaTSm+DwwgsG9zwPHFhdlmB5TlaPDbSea0swBxKZvHaTXT5Hcsq8AA9UHvxMnSCF+PwUBiTUrnBrVf/N5bWJT7OTcXY23upyrM74FiRhMfqJidOi4lQMsKubh8mReimZ9PxZfsg3Cy8cV93mVmSwbXl1+/uqwguW00KG9s8y04WaJIrngS6VuzvD5UKyq41ht64wdWmwWXlN+9bw7/95FzFawHHldkbnRiL0dvgoMFlYWAmWSbFuhC7RWVzm2dZsjdyBa0FPoeZiUh9QXNlkXX5d46O88Z93VhNKrt7/Gzr9DIRTXO0uL80uE2Cy1OxNB/+6Xk+98Rg6blC0aBkXYsLp9XEM8Phmi15E9EMWzu8i5bR7+z2LblQnk3UDsbobvLlgem51oKnFpx3T4+f0XCK7oCjLMCjCL26WEOyusnJxZlEWWuP1aSwud3DuclY2e+ysc3NqXlGe2ZVsLHVg92qUCjuCYaCSfb2BTg8GCI37w91aDBUt8bO8dEIBQ02tXlQhMBh0XXVbCaFvKaxqzvAibEIm9s9mFSB3Wzorhnc+ggh+P/uW81rd3XyTz88w7eeGatYyAecFvb1BUjn9GDxZCxDOqfhsqpVW1w7fHY0uCImLJYVtql2BhyMLWF4+tPTU7z3+WsxLfMzPv1YP/97ZAxVwNfe/ey6A3QbWt3L/iyDW4fB2UQpsAyQzBbYPxBECL3rx++wcGYytsgZyllOB1Q6pzE0T17mr161BY/dUv/gDQyuEy/e0kqHz163HuIcpydi+BxmVjc6sZrVUkGDzaSWVfLXS5ffwbHk1ZF0AL3q6qliJ102r3F2Ms6hwaBuvt3kZDqWYSiYxO8w47CYiKZyxDJ5zKpge6ePZLaAlBKTInjW6gaiqdyK9INNiiCezpc0ba9E9efNgCIwOhWvI6uaXLitJmLzqme3dXqXnQS6FXh6MMTmds+yuiouF4/NxCt3tF+zzzO4fXn3c1fzqcf6K0xiO/2OCgmmlTIwm0RVBJlFNGi7AnYcZnXZOs31ymfMZ12zu+7ErFzEKeHgYIi7/v5nvOveVbzj3lWYVYW/ffXWZY/nVuaWDi5HUjkeeOQCn/r5QE2R/LPFSuNmt5UNrW5OF9vSF1blmRZZ8OyqI7AMeoDIblHxOyzE0nlMisBmUZGaZChUqWk6GkpiMysVRnhzF+FcdWM2r2Ezq/TPJMpuCgGHmdXNLiwmhWgqx5mJWNVFqtNiIuAwYzWrtLhtjEVSHB2NsLPLx+F5Qa79/cEy7bjdPX6klBU6yrWIZwqsa3FVyIZs6/RxYDBYuujnJnObWWUklKTTb7QZGNzaWE0qjW4L/TPVOx+CiWzVrG6wxqWXK2hkqrjar4SxOjO9Czk8FCpVX5+djFXVYD4xFuXvvneaP3rpxrorNr5zdJx//P4ZnFaVf/mlHcuq/DQCy7c3Pzo5WfV5KfU5v3uJlra+RicBhwW1aNJ1dpFOpaW4a3XDit9rYHCtGI+k+K9H+5cdWHaYFbZ0+nh6IIijRXd239sX4OBAkN09y5Olm+Na3b7nOulADzgHk1mCg3owPOCwEExmCRU7Hbx2E5os7wR6rNjps6nNw5Hh5VcZ7+7xXxPzshsJIcBnJNuuK6oieM2uDj5bLMTa3O4pXadrm12EU7lSt+mtjib1ZHSn316Skrva/OFLNtLsti19oIHBZWIzq/zBizfwp988XipCvByt5Fpk8tqiZrjBeJbhFXRFLVeb320zcX6q/sIRk6Lgsqo1NdBn4hm+e3wcr93M6+/oMjoQF3BLBpdT2QKfe2KA/3zoQpk2ymLMxDMMBVWmYhnu6PVXBJfnVxxtaHXhtVt4uljFazWp84xONGLpPOORdEVGSAhRczPa4bezp8fPTDyD22bGaVWJpfOMhmtX/k3FMgQTGXb1+ImkcjitJra4deO+eCaP22oilStwaDC0qFHKpUVxrqQT1+y2cnysMntlM6sEHBbafDb6ZxK0eqyYhN5KKNFl56SE81OxMq1o0E0Cq7U0Hh4O4bSYKm5A+/uDvONzB/nQ63ewsc0w3jK4dYmmc3z0oQtlm9rLodNvr6n9vlxGQykanJZF25qqMWfGArCnx8fBwTCgb85bvNaSqejjF2Z4zX8+xvYuH7/7ovV4bIu3ZW1sc/Nnr9jEi7e0FnW3DAzqozvgWLQC8+CgbkCUyhVIZvNEU/lSEAn0rp5DQ5dXxdXosvKWZ/fwjcOjvPWuPgJO4ztscOORyRf42++c4nNPDq7I3MpVvI+va3VzcTrO1g4PR4fDdPjsKzbnGgomr3k14UKCyfJ5MLKIca3TWn/V8rYOLyPFIpNrqTF7o/DmfT387ouunUSWQXV++wXraPPZOT8Vp8FpYUu7l3Aqy6/c2YvdovLvPznHyfHobRFkjmcKeOyyzHvoarGnx88b7ui6qp9hYDCfN9/ZQ2+Dk7/73ilURVzxeceiiiUTMyuR29rZ5eNElfjUYqxpcpUVSy7FU/1BzKpgdZOz1EE0H7MiGJxN8sEfneH+TS34jXV8GXUHl4UQKnAQGJVSvlzoYfq/Bl4HFICPSin/vcr7fg34k+LDv5ZSfvbyh12bh85M8YdfO4bPYabTb6saXO5tcNDssYHUg8FTsQzNbmupqne+1sr6Fhc+h0VvU8vkSWZ1k6tMPk6T20pfo5OcpiGlrNCVafPaaHBaSpW+FlPtTMtoKFUhoN7lt2NWRYUh13x08fTqm10h4DnrmtjT40cIQTavkdMkdrPC4GwSp9WkO05XaaufjmVo9doYj6Rp9dho99mwmVWeuDCL5NICO5jI0u6zkStoZVXRa5pddDc4EUAimyedK5AtSDa0unFYTaiAhh6I1qTEpAoSmTznpxMlfT4pocFp4XUfe4JXbG/jhZtbefbqhhW1GRoY3KgMB5O89mOPM7lCc7H5dPnttPvspHMF8itoG6qGJvVKaFXoTvP10NPgoNVjQwIHB4JIBNu7vNiK1261qqwL0wnuXdu0pGbVqiYX7T47Xzk4zCu3d+C9QhphBrc+L9zcyr3rmnjiwiwPn53ms08MVATOFnb3CAF+hwWPTTfv29LhIVGsZvA7zBwdiSzLtOS+9U28897Vi64HDAyuF8PBJF97eoSvHBxZdrXyfKZimbIijZl4lq6AnXi6PGGzHIKJHMFEjjXNLmwmpbS2vtEwK4J1ra5FdRvn2NbpxaQIDg+FF2nEvfXZaxj53RD4nRZ+4zmra76+ptnF08tsYb+ZGQun2dDqJjm1PHOy5WBSBH/7mq2GJIzBNefutY08uPpuPvjDMxWxIIdZIeCyYlIEA7OV3fVLMd8w0Ocws7bZRTJbKCWHvXZz3QWgoHf/N7ospPP5ml5htTCpy7+2cgWJq4YBYE6TrGp0cnAwxC898ATP39jCH7x4w7I/41ZlOZXL7wVOAXMlpG8BuoANUkpNCNG88A1CiADwZ8Ae9C7SQ0KIB6WUV2VmOj8V5+2fPUhek0xE09gtKp0+OyPzFsg7u30cGQ5XXCjzsytTsbRegQvEM3mGQymSVbIr07FMWfa2w28nIC2lwOt4JM1ULMPevgCJdI4jxYonIXS3TpfNBBKyBY2RUKpCg244lGJ7p7eqpmo9SAmRZI6jo5HqbtXFsVdrhZDATCyDx24qmfft6PLR2+hAEQKzqpAraIyEkoyF01hNKnf0+jkyHCZXkJyfql6hPVGsjF7b4uJclSpun8NMRzFrDnp7Yaffzhf3D/PF/cP0NDj49FvuMIz+DG4ZRkKpyw4sO8wKmzu8nJ6IMVy8l93R62cimmY4ePktfeta3HVrYs3dswaL99hnrWrg4ECwTKt9Ib/1vDX88t5u2n32uj5DCHjJ1jai6ZwRXDZYFjazyn0bmrlvQzOv2N7GWz51oExjciFS6knUahqx/cCaZiepnFa3u/ZENE0qWzCCywY3FBORNH/xrRN87/jEFT+3KvSK/XROW3FgeT7np+I3dDDSalI4OxlftDBk7rjB2cSi1c+3A6/e2cErthtaszc6//GTc/z3k4NkF9FQvRU5PRGr21toJbzrOatY1+K+Kuc2MFgKVRH83ovWE0nl+J+nhrCogu1dPg4PhUuxsZVIZrjtZsLJHHf0+jk2Eil1snb57VhMCpqUaFJWdPlXY0Orm6FgkrOTcZrdVnb3+Dk/FS8aZVs5MRZdtEN/pbIVR0cjRa8eUdFZnMkX2NcXIJ7J8dnHB7h7TSN3rWlc0efcatQVXBZCdAIvA/4GeF/x6XcDb5RSagBSyqkqb30R8CMpZbB4nh8BLwa+eJnjrkqTy4rVpJAvBoJT2QIRJceOTh9HRsJs6/RybCSyZItf/0yy5BRrt6iLSlPMZ659fP5FWNAk40Xzve4GJ/FMnt6AgycXXKR+hxmrSWF7lw+LKuifSdDhszN0mYGhw8PhCu3khezvD7K9y8vwbLJMyiKnSXLzFr1HhsMVTtqgV2h7bCYEeoXXQkmRasgad4FwMlfSWPY7zCSzeWbiWba0e/A7LYyGUzzVHzSCywa3DF/cP3RZ7w84zDR5bBUalgcGQqiKYG9vgLNTMcJ1bOobXRZ8DjPBeA67RcViUmh0WRCCuhfXgvJJXJOyamC5zWvj9Xu6uGdtI7u6/cuq2rCaVKwuo4PB4PJw28wka/gx1Mv5qQSqgL29gbrMQs5PxVdURWFgcDUoaJL/eWqQf/z+mUW1EVfKji4fg7MJJq9QG/2eHj+KgLHLqKq+migCNrR5UBWxpG7y1g7vVQtY3Uz86OQk33pmjA2tbroCDmyGmfcNydvvWcVvPm8N//SDM3z04Qsrksu5WTk4GGJvn79mp/BKafXY+M371l7Rc97uCCH+HzCnseMDwlLKHVWOGwBi6N33eSnlnms0xBsOIQR/8crNTEbSnJ2KV+wnl1NhDHridHObh5wmOT4SJj0vITU8rxBjV7evLsNat81UKvKc3xUVScFkVFcfaPZYsZtVcgXJZDTFeEQ/Znund8WSH1LqyaXN7ZXSrMdHo6Vuo1WNzqvW2XAzUm/l8r8Cvw/MT62tBn5JCPFqYBp4j5Ty3IL3dQDD8x6PFJ+74hwZDvPuzx+q0G+JpfMcGQlz95pGIqksHX57qaJuMQ4OhOj0WenwOTg/Vb8+3GwiS3AgyB29fvKa7hr9zHCYvCZxWlQmIml6iqZBXruZNq8Nt82Epkn6ZxLs79fNTsYjaUbDaXobHBV6p9s6vYyGUkgkXQEHE+F02cLdZlLY2ulFSjgyHMJiUljd5MTvsKBJSTiZY2A2gdduJl+QxDJ5nhmO0O6zYUrnqJaUNqsCq6qQyOQrqqnHI+mSVnO92C21F4/HRyP0NjgIJXP47BZMqoLVpPDouRlesLHF0KUyuKV43Z5OfnhyosK4s14kcGaiulFBQZPsHwjS4tEzvSAxKQoSkFIiJSSzBRShLy6mY5nS/c6c0SV55vQxfQ4z2zq8VZ2EO/x27EVTUW3ejsNiUjgyXLkYX9vs4v+961mG3qzBNSeeyTM4m0BKeOfnDlbv6lkmBQn7B4Ls6wtwYTrOTLy2PnlBk0bVssENwanxKB/4+jGOLEOLcLlYTMoVqVaeoyBlSb//RmRXt56E3du7dGX1YDBZU9Ox/Jw+QskczW4r4VSO/pnETVE92hWws7XDy5YOL5vaPFhMCn/+4IkK75l4Js9vffEwAO1eG997771GR9INyNy+7fdfvIF71zXxhgeevM4jurbs7w+xrdNbVUpyJVhUhb/8hc2L7ocNlo+U8pfmfhZCfBBY7B/sPinlzNUf1Y2PSVX4lWf38muf2l/x2sXpOPv6AmhSkslri14D+/oCHB0Jl4xtF+PpoXBNH4UtHR5UIRgNp5Y0AF4owwV69+6BgRDWy0hWmlXBuhZ31fHN7RwUAX/68k3cY1Qtl1gyuCyEeDkwJaU8JIR47ryXrEBaSrlHCPEa4FPAPSsZhBDincA7Abq7u1dyCja3e7h/UwufK7rczkcRehXzdCzLRLT+IGir105qBVVNUupVg/OrfOeCrzu7fRwcCLK53c10LMvpBUGhbZ1eDs2rZGj22BiYDbKj00de09Ckbog1d2EnMjF2dfvoaXCQKwazp2OZ0oW4s9s3r3ri0gLWpOgLuha3DbNJEEzkGAunSxfjfDa1eTg5HiVXKJQ07nZ2+TCbFCLJHGcm63fgBD2jZVnC6VOTsK3Dw0Qsw7nJeEn77xXb2wxXToNbinvWNvGfb9rF2z5zcEXvX9XkKrtnVGMymmEymkEAnjp1rha29IaTOZpcl+6HDU4Lq5tc5DWNI8Nh7GZV16CdF3zO5jWa3daKSf/b77nb0E43uOYUNMlrP/p4ad5d0+xiQ6u7Yh5eKXNzrVkV7Or2V61czBU0xsIpehqcV+QzDQxWwkd+dp5/+dHZq19tIyV2i4qm6ZvSy8FqUkqeHDcqc3uGsUh5ZbVZFTS59Llw7m8+Hcuwpsm1aHB5dZOTUFIPKM8lep0WldaAo8xo/EbjPc9fy/vuX1fxfKPLWtPYHGAskubkeJRnrW64msMzuEyWMl6+VTk3GaO3wbEiDVqHRWV7p49dPT52dfvZ1e03jMCuIkVvsNcDz7veY7lZuHdtY9Xvd64gy9aza5qcnK8xb4WTWVLLKJY6OxljY5ubU+P6OnxvXwApJRemE1Xl6Orl1HiMnd0+Lidi1OKxLWkgfPfaJu7bUKEMfFtTT+XyXcArhRAvBWyARwjxefQq5K8Xj/kG8Okq7x0FnjvvcSfw0MKDpJQPAA8A7NmzZ0UrXbOq8Bev3MzaFjefeawfj93M3WsaeeGmVta2uBgLp/jFjz5e17n+f/buOjzS8mr8+PeMSybutslu1n3ZXdwpbNFSoQYvLQVKXd+21Gh5K1R+daWlhRotRVpKsVJc190l7m7jc//+eCbZyExkN8kkm/tzXVwkM888c2Y2j53nvs9JdlpYlJvMrpoOvIEwq4tT8QXD/X/4Y7GuZPiFpUlgR1U7EQV7amOvyzFkRJPNLMzPTmJ7dXv/Y3vrjk/BLc1089rR2MP9M9w2GuIk041zfEV1u5c56U5SnTaqWntx2sycXppOly9IZWsvC3OT2Vo5PHG1raq9fzTzeJRkuAhFFFtGmQaRZLfw0uHhd70is2keljZrXLQoh5++ezXNXX4e2lrN4cbuQdOIhlpbkoZZhMrWHryBsU9lVhijhk90Km6K07igWJqfzP66zkFlAHoC4ZidfwvTnP3JZbvFxI/ftWpMjY40baKZTcKt583l0w/sAOiv7b+iMIWD9V0jbnPj0XciHquMVFtvkJ8/d5jvvn3lhLyXpp2I8uaeKZnGuXHAYIW1c9LYV9c57g7xc7PcmIDDTT0TdiNoNB67BafNTGtPYEzfU5LdwtL85P7tPT/FOaiXy7KCFLZVtmMSKEx1kp5ko9Mb5LWjLZRlu/HYrVjMgogQiSi8wTDVbb0xE89ZHvsJJbemSpLdEneG4e1vXszzBxq577UKmrtjl0opzdQ33qa7JfnJfPXKJdz52N5EhzKlvMEIvYEw6W4rrT1jm5FRlp3EJy6ez5uX5WIZ5zWzdlLOBRpizKrvo4CnRUQBv47momY1EeGsskzKW0Yu1+iJc3OpJMPFgRFuHsYSDBuzaBfnerBaTCdcwmKobn+IbZXt0Vm7J6a6zUtRmnNQKY+h3n5a4Qmv/1Q1anJZKXU7cDtAdOTyZ5VS14vIXcCFGD1tzgcOxnj5U8C3RKTvX/bSvnVNBhHhhjPmcMMZc4Y9NyfDPaapqH1Fwwf+cW+LJkLXl6aztaLthE/Ic1McmEQGnXD2Kcty0+kLDesW/cpho6HdUH0jGHpGSCzNyXDFnS4/UEWrl7XRUhwvHhw8O2SkEZHBsGJupovGLt+waY9Wk7B6ThooUCi2VbZRkOaipdtPl3/0CwuHNfa/VfcYCr9r2kyjlCLFaeW3Lx1ld20nmUk28p1WzCKkuqyDZhMUpDrYXN6Gx2Ghxx+iOH3sF2Jl2UkxbxaNxWnFqZhMxhTdw41djNKrqN/A+0GlmW42LMs7offXtInw1jWF1LZ7+f7Tx09ZdlYbpZj8oXB/nbaTtbIwJe6Ih4MN3fz+lWOEwor3n11CeUsveSkO3HE6U2vaRDtzXgYPbq2ekrqpfc33mrr8Y04spzitFKe7sFkEs8igJPVkW1eSxpaKNrr8IQTISbaT4bbhslto6wlQ0dJLKKIwCczLSiLNZWVvXeegG0kby1tZOyeNHn8Ij8PafyM2oqC63Tuo0fh4Su8BZHsc0za5PC/Lze/ety5uc97lhSksL0zhvWfMYVN5K3aLiQ5vkH11XRxq6GJ9aTq5KY4pjlo7ETnJs/PfqbHLz/zsJLr94RHL05RlJ/Gxi8q4ckU+5nH0FNFGJyLPALkxnvqSUuqf0Z/fzcg9vs5RStWISDbwHxHZr5R6McZ7nfTs+pnkjLkZ/OWNkZPLsfJpa+ekjTqLNp799V39/dEm2paKNtJcVuZne8bUF2V1USo2iwmlFC09AcqbRz4+nzlXz7IZ6mSuZO4C/iwinwK6gZsBRGQtcJtS6malVKuI/B+wKfqaO/ua+021Vw4347JZWF/q5nBDN629w4faF6Q6qW339hcNH2rjsVaK0pzGMPm6zrjT89LdtpijK2qjjQFXFqVQ3jy4Q3RGkp3D0SkA60rS2FbZRihi3FbLSXYMu2viDRqvNaYmxb6jsrUydgO+gQrTnITC6oRHMh5o6MLjsPQ3Dcvx2EGEZIdlUIJ+aX4y4YgaU2J5JLpgunaqqWrt5fKfvDSoY25zd2BQ3dYsj52FOUkcbe7pL7HTt/zWyrYxT+1PcVpH7Kgb7zXzstzsru3AHzJefOa8DA41dI1YW7bPtqr2/nI7X3jzovG9uTYiEUkFfgsswzhc3AQcAP4GlADlwHVKKd01aoCPXFjGs/sbBzUSKW/pJTPJNuJ0v/Fo7PKTm+LoHx09UI8/xNf/tReH1cQrR5p5/kATV6/M51tvXY7DYuJwUzeLcoc3ENG0ifDH1yv4yj92T9n7KaU42NDNolwPHrsFBeyKUbsfjIEFi/OS2VbZ3r/M6qLUKYt1YY6H2nZf/3FScbysVJ95WW78wQj1nV4Oxdi++xxt6iHZaWHfBI+29oWmb2mQy5bmjqnkT7rbxmVLj+eGrlk1iUFNEBFxAC9ilIW0AA8qpe4Y8PxPgJuUUrOi4/hFi7K4aFE2++o6yUyyY7eYqGjtpSDVwc7qjnGfa84khxq74zYjm5fl5uMXz9dJ5UmklLpkpOdFxAK8FThthHXURP/fKCKPAOsxtu+hy5307PqZ5Irlefzu5WMj9mLo8oWYl+WmvsPXf8O4srV32ADJsbKYiJmXmyhtvUE2V7RSmObEGwgP6mM21I7q9nHtu+o6vGR57P2/+0NhXj/ayvkLsk4m5BltXMllpdTzRMtaKKXagStiLLOZaKI5+vvvMOoxJ4xSirtfPDKoZtnq4tT+EckAy/KTqWrz0jnKyNiqNi9VbV7SXVaj03N567A/wpIM14jdL3dUdZCTbCfZaaWq1UgM17R7MYmRPN1U3kbxgHpqsUpB2C1mIsoYCWIW4o4iPNbcQ5LdTHecpG5+inNMd3JG0uULsbG8lSS7hXS3jcNNPcNGTAfDkRHrrA1kt5jwxal1vTQ/5aRinS3inQSLyEscb8yZDWxUSr0lxuvDwK7or5VKqasnP+rZJxxR/OL5I4MSy7E0dflxWU3Ud/iG7W+CYUWPP4TTah61Rvx4q1GIGDfdhu7P2nuN5PfcLDdHx5CI21TexjtOK+CChbou1QT7MfCkUurtImIDXMAXgf8qpe4SkS8AXwA+n8ggp5utle0xk759N3XmZrnp9oWG1Qofj7oOH1aTcFpxGgcauuj2h8j22DGbpL+Bjy8Y4fkDTQA8uqOWrZVtvH1NIQ6bmdJMt65Lrk245w40csc/py6xDPTPvBk40GFBThJ1HT66fCEsJmFVUSomEaraegedm5sFGuOUT5gI6W4bAhSmO/EFwmPqITJaA75FuUmYxMSxlh5aWyb+gnlndQfrSozZhrFmQoKRpP/GW5azdk4aHoeF7z99gPs3VnHBwixOL83gO0/un/C4APJO7VHHfuAipVS3iFiBl0XkCaXU69GBVSc+/3qGCYQifOmR3Ty7vxFgUFP3pi5/3MTrqWToAC6dVJ5WLgH2K6WqYz0pIm7ApJTqiv58KXDnVAY4XZlNwnfetoIrf/rSsN47ffbWHZ+Vl+ay9s+8a+sJEDyBu0oFqU7cdgsrClOwmASzSVAKmrr9VEzQLJ2IMgZkxjtmAuQmO8bVm00EPvfgTr54+WLOW5BFeXMPX/rHLr597YqJCHnGmhVzMB/ZVkN1m5fTS9MJRxTN3f5BJ68Lc5Jo7PKPqclVn9beIBuPtTIn3Ul6kp3tVe390wsPNXbHbGI1UEOnn2SHhXSXldbeINVtXtaWpLE5ehKe7rb1J5cPN3WTm+KgfsDBu6UnwPqSdLzBMAWpTo4298SMv7HLP+JUgw7f+Lp4J9ktdPtjJ8L66j/bLcLakjSONHb3l8sYS/OHdLcxbaG9N8DeGPWtz5ibzrqSWXPudrLinQT3N90UkYeAf8Z5vVcptWoK4pzVPvfgTh7aGvPcBzD2AwWpDuo7/XiDkRHvphZnuDjS2M3ywhRq2rwx9z9bytvGnBAGY8rvwJMIAItJaIiWDjCPI1v9ntOLCYQiYypPpI1ORFKA84D3ASilAkBARK7heK+D+zBuCOvk8gBNXf4RbyQfberB47CwvCCFiFIcbeoeU4OSsmw3aS4b4YhiW2U7wYiiwxdgVVEqvYEQe2o78Yci1HX4mJPuomJIQ67qNi8/fe4w7z29mAP1XZgElhWknuzH1TQAGjt93PqHzSc9ojAvxUF+qhPBGDjQ3B3ob7o8Vgcbullfms72qnYKUp1xZ8+57BZqRrgYPFHzsty4bZb+BrQjjWQaL7vVzI6q2COzJ0pfwn5BTlLMgRtf2LBoUC3Ib127nEsW57C+NH1S61Y/vbeB68+Yc0o23lZKKYyZugDW6H9KRMzA94D3ANcmKLwpdesfN/ffGI1la2U760vT2Hjs1J409caxVi5dksMVK/J0Unl6eRdDSmKISD7wW6XU5UAO8Eh0P2UB/qKUenLKo5ymFuZ6uPncufzy+SOjLtvWG+zP9WR77BSmDR+QNJqKVi/xZuHPyzLOqxH6c2RjZbeYWJDjocsXJMVpZUf1yMfluVnucSWXlTJKerT0+OkNhPjE37Zz09klFGe4xhXnqeaUTy639gT4xr/30doTICfZwZaKtmHD9g80dOO2mcdVUzk32Y7FbKKi1UtFq5cMt428FAdOmxlBcNnMNHYZB16LCcLREhcDdfpCnDs/k/LmHvJTnZQ39/R36RxYx6nTG6Ik3UVphouwMkY517R52VjeyorCFLZVtbMo10Oqy0pWkp1uf4hkp5X23gChsCLFFf+fuXKMd4SK011kJ9vZX9vJ6uJUGrv8g074rWZBRT+hP6TYXN5GSYarf4fT3O1n7ZxUKltjJ70AitJdI5bwKM10n5InrJMh3klw3/MikozRQff9Ux+dBkaH3H/vqh1xGbfNjNNqpmmUEZQWswmX1UxEqf4GBrG2M4XRrX1octnjsLAkL5mmLj+ZSTaCEYXVbIpZa2ppfnL/AbqqrZfSTHf/jJA+douJwjQnPf4wC3M9NHT6+Me2WnJTnOSlxK7FqI1bKdAE/F5EVgJbgE8AOUqpuugy9Rgn0VpURUsP97x8dNTlunyh/mn5eSkO1mYn4Q2EMZuEug4f2dFpcPvrO+n2h7GaBG8gwuFG4+R3XpYbq9nE4cbuQTVV7RaTMespTjItHFHsqenkwS2vk5lk55EPn0VGkj3mspo2Hlkee7SZ6vizywtzPHzognlsWJaLwzp8RH2HN8jBhi7213exv66TfXWd7KjuIDzC+fSOqjacVvOw40efdJcNm8U06syeeFYXp4ICs1k41NBNhzc4LKk8Uc6cm8ENZ85hWX4K+akOfKEIN/1+00nPDByNNU6DsKHd60WEixcbh4KxDPY4URaTcKSph3lZp+b5ejSRvAUoA36ulHpDRD4BPKqUqjsVP3MffyjMZx7YQW27d0zJo22V7awoTGHnKAmdmWpulptP6JHK05JS6n0xHqsFLo/+fBTQXZVH8L6zSrj7xaMjHsOHauzy09jlZ3lBCseau+POmh8PY6aQcY5Qlu3mWHPvmGJKc1lx2sxxS3ANtaIghdePtLCuJI19dV1xB1LG0ukN4bJZuOOqxVPSx2K6O+WTyz999hCt0REJbxxrxeOwUJLhxmISLGYhGI6wu6aDnkCYjcdaWZTrobylB1+MUUoCrCtJp6K1h/po/bX52UkcauympSfQP/JBBNbNSWNBThKtPcY0W4tJWJjrwWIWDtQZXelzPHbeONZKIBShqs1LitNKRpKdtSVpCEbjLIvZREu3n501nYPuAi/J82AySf9Be399F6uKUmNesB5t7mFhTlLMDp5rS9Jo7PQTVgqb2UREqWGjGvqm/fSNpN5W2Y7HbibHYyfNbcNuMVHV2svumuMjHC0mIdvjwOOwUNXmJRiOsLminfnZSXGTy45RpgA/sq2Gj100P26jEG2wWCfBA55+C8bU+dgdp8AhIpuBEHCXUuofcd5jVjU6mEjpbhtJdgu+YPwRU1VtXmrbvcNmLgw19OK8tt2Lw2qKuR/beKyVlYUp7KjuwGO3sDjPw8HG7v4bO0fjXOhbTMKa4jQau47H4QtG6PGHyE919NeUv2hRNne9dTnZyQ56/CHdpGzyWIA1wMeiF7g/xiiB0U8ppaKdsIeZTdvug1uqqWjpobK1lyd21RMIjz4KeaC6Dh8FaYNHV/YdD9PdNs6fk8aLh5oHjd4cOnU+y2MnL8VBOKLYHa/erMVESaabyrZeegNhKlt7ufOxvdx4ZglrTqLjtaaBUfblbacV8sjWmlFLKGV57HjsFsqyk7hubREXLcrGNEICJcVpZV1JOutK0vsfe25/A9/49z6auwP4Q+FhxyN/SOEPxb+Aa+0N4IyRyB6Jw2piRUEqDZ3eQTMUBaPHyGglLU7E5ctz+dm71wz6fpLMJi5YlDXpyeWkOMfXW/6wmac/dX7M55Kdk3dMfu5AE88deAGP3UJxhovrz5jDu9efOscXpVQYWBXtd/CIiJwHvIPjs4XimsnH3OZuPzfdu2lcieJgWLGzuoPlBcn4QhEOjbE04nQ3N9Mof3HVSp1U1k5dOckOzpibziuHW8b92l01HSzNT47b1PpEFKU5qWv3jSmxnOWxU5zuGnODQY/DQlO3nwjGrCCrSViS58Fls4zakyzNZeW6tUUArClOH3HZ2eKUv+o/OKR+2sDRSPNzkjjU0E2K08rCXA/dvhA9/iBl2UnYzWa2VB7/g+obrTv0RPFQYzenl6azp7aDjCQ72R47Ld2BYZ2tQxHVv5HZoiOXPHYLrx49vtF2eIMjluYIDah9E6tshGCMlhp68uy2mYdNmytMddLaG+ClQ82DHs/22FlVlIrFbHToPtLUTfuQ6YJpLitzM91sqWynIU6ieEle8qDvqj06gjle4gqMjp7LC5LZVRN7Z+QLRnjtSAtvGzDVT4svxknwMqVUX7HFd2M0AotnTrSL7lzgWRHZpZQaNj9mtjU6mEiZSXbWl6bz+K76EZczm4TAOBv41HX4WDsnjZYeP8eaj89OEDG2TRFYX5JOpy84bF8VT0mmK+aFct/NonPKMvnAOaWcMz+zfzSVTixPqmqgesBNowcxkssNIpIXHUWVBzTGevFs2nar23r56bOHT2od8Yq5tPYEePVIC+ku24hT6+eku2KepM7LcmOzmPA4rFS29g66ubs4L5mSDDehyPiS4ZoWS5bHzreuXc5n3rSAW/6wedjoQ6tZuOXcuXzgnNIJGS3fG4gMOh9dX5o+qNHzaApSnbSN0ORnToaLVKcxCrelJ0AgFKE43UV5S8+wQQwKRqy1eDK6fKGYiXdbnFHFEyne6KpOb/ykfbzRzhOpy2+UAeo79z/VKKXaReQ54EKMARyHo6OWXSJyWClVFuM1M/aYe+e/9p7wCOS+azqn1czS/OQTbiCfaHMz3Xzs4jKuXlmgk8rarHDhwuxxJ5dzkx3MyXChYFBN8pOR6rKS4rRSNYZj+No5aWyrbBt1xu9AeSmOQXmyYET159lOm5PGzur2QfWnHVYTJRlu3HYLVyzP7e+johlO+St/h8WM22bGJMZd1HBEkeqyUZLp6p/a3eENDjnh9WIzC6uLUjGbBKtZ2FrZjj8U+wLvjWOt/eUsxlJ4PBCKsKumg7Ls0TsqgzHKYGGOh311XSNuqNuinT3XzkkbdPDuDYZZER2p2Ke63UtBqpPewOANtW9Kw0A5yQ6SbGa6ox1B52YljXo3KN7MsHBEkeGOfRG+IMdDSYabNLeNvbVdNEebuPTVzLliRR5Xr8of8X214QacBG8AdotIJkZX3Li14QZ00T0qIs8Dq4HRiy9p41KaeXwfYLeYsFlMWEzSX04GIBBW0anM47O5oo25mW5WF6fS2hPoL5kz3jvJ60rSaO0JDJraP1RBqpOvXb2UsuxZ0SR9WlBK1YtIlYgsVEodAC4G9kb/uxG4K/r/eHXVZ4Wb79vMs/sbTno9fR2xYwmGFaVZbrr9Qfyh2DmDzRVtLMtPZveA7W99SXrMGzYum5nzFmTxhQ0LaeoOsFaPWtYmUEaSnRvPKmFr5fb+x9w2M7/5n7WcVZY5Ie/x7P4GPv3A9kGP1XeML7lb0+5lUa6H/fXGuW95cw/pSTZMIjitZjZXtFEx5DUn04RzvOZkuLjxzBLeua4o5vOTHYsQP7lc3+njYEMXC3I8w57LTLLz2MfO4Rv/3svrR0e+8E932+j0BglFFDaLiUsWZ3P1ynyW5KWQ6bHR0h3gyd31fPPxfcNe++23Luddcb6bmUhEsoBg9JzaCbwJ+I5SKnfAMt2xEsszkTcQxmkzU9fh5YPnzyUjycbvXyk/8fUFw+yp66Qg1TnuGu2JpJPK2mz1znVF/PrFo+NK1BakOXnjWCv5qQ66vCHKst0jXj+OhcdhGXTuHM+iXM+4b16NlgDfUtHG6aXpHG3uMZpyi7CvvrN/IMhHLzoldvcT6pRPLn/jLcv4+F+39Te/AKP7ZNMo3acDYcW2qnasJqEk080ZczPYUd0e9y58eUvs2qPxrC5OHTRlL57STDetPYFB3bbXl6az6VjrsKp5LquJpQUptHQHovWjWwlFjILju2o6WFWUyvaq4+9pNY/tILmntpNkh4Uz56YTjsDOOM0BBzrS1MPKopSYTU0K05y09AS45dxS1pdmcLChi7mZbjYsyx1Uoy0UjmA2ySlZt22yxTsJjj79duAxpVTMOgsikgb0KqX80UT02cB3pyLu2ebGs0p49/piPA4rDquJo009PH+giV+/eGTQvma8DZhKMlykumx0eIP9+5mKll5WF6WOaz1rilMH7TvjufManVhOkI8BfxYRG3AUo4a6CXhARD4AVADXJTC+hFuYm8Qz+04+uTzaKPzKll5ykx3RxiTGyIblBSn4gxF6AiE6vcdv7CzLT8ZqFqrbjt+MdtnMXLkij/xUJwtzk4hEYE6GUbdUHwO1ieQNhPnbpqr+3x1WE3+55QxWjvP4MBKTGGXnBqps9TIn3YnNYuZQ49imyKc4rSzN9/Rf/MWbLTfVVhen8rsb15HmtsVd5tUjzXGfmwinDWgCHsum8taYyWWAZQUpfO/tK7n4By8M6vEy1KMfPRubxcShBqNZ8NB6za50C7ecN5cHt1RzYMBM0cwk+ylVDiMqD7gvWnLOBDyglHoswTFNOF8wzJ2P7eWxHbXkpTg50NBFSYaLpQUpJ71ubyBMtznE0nwPe2onr7HkRNBJZW228zis/Ozdq7nx9xtjllmMpW9bqW33keqyTkhDXrdt9HTliTSLL4wmwkdT3txDssMSc3DWZM2ImslO+eRyXqqTv992FjXtXqpbe6nv9PHK4WYe2lpDOKLITbZTlG50dTSJEFGKYFjhDYbp9odo7PRxqLGbQ43dJNnNnF6azqHG7v46zn3SXNYxJ5YBzGO8WEx324att682dLLDgs1ipjcQoq03QGWrtz8RdDTaHFApqGjtJaJge1U758zPpKHDqFkzUokKMEZFgDGd0G41U9PupbJ1bBtRtz/EruqO/tquA9W0e0lzWVlVlMabluTwpiWx+01ZpmDq3ilspJPgd2GMauwnImuB25RSNwOLgV+LSCT62ruUUnunLvTZI9vjGPT74rxkFuclc+NZc/j1C0f51QtHcNssw/Y3AxWkOlEoQmFFpy/IysJUDjR0UR5rFoUY2/VYctX5qY4xNW3J9tg5e4JGu2njo5TaDqyN8dTFUxzKtHXDmXN4YFM17d4AOR4H1ScwYio/1cGmUWqnprlsNHb5WFeSxt7oCWi8GzMVLb247eb+3g0AvYEwhxq6CQTD+IJhFuUms6m8lfWlGeOOV9NG8usXj/BqtHGNLxghL8XB0vzkCX2PCxZmc/8tZ/CJv24f1H29otXLisKxJamWF6SwMcZAikTKTLJz2dIcvnTFYlwjXPDWdXgH9SGZDJER7jpbzcKZc0fedxSlu/jV9Wu464n9w0rngdFTJs1lw223DDtXGWpBrmdQcrm528+PnznERy8qO2USc0qpnRiz+EZaZkbfZfcFw9zyh839JRM7fca/aXlLb+xzyhPQ4Q3S7Q/FHSiVaH1J5atW5OvrUG3WO31uBk9+4jz21HZit5jo9AW5+8Wjw/pzAaS7rVQMyC1NVFmkTI+NeeHhZV/7lGa66faFYsY0EssYj00NXf64N7Yf2VrNDWfMGdf7nupO+eRyn4JUJwXRRnDXrCrgg+fP4/evHOOvG6sGXeCNpNsf5o1jrZgEVhSm0OULkWQ3U9XmZX62Z1yNO440dY9pqsCWijZWFaZS0+EdNC2h2xeius1Ltz+Ey2qiOMPF2jlphCKKfXWd9AbClLf0YjXLoDp3/mA45ogRk8CS/GSUgrbeAHnJTvbVd0bLiBg1ll8bZfrcUBEFhxu7sZqlv1aNw2qiLDuJixZls75UFz6fLCOdBCulLojx2Gbg5ujPrwLLJzM+bWQum4VPvWkBbz+tkPf+9nWWF2ZR1+HrryE/PzuJNLeNUDhCKKJo6fbT6w+R4bbR5QvFPaBvq2xnXpabNJeN/XWd/aVuYilIdfY36YvHbTNz++WLcIyz6ZKmTZZwRFHT5qU4w7hp/OLBZpq6/STZLVS3eynJcJGd7ECAhk7fmC6Ykx0WattHXuZAw8hlqwbKSrZztKkHm9lESaarP7HT0hOgON3JFcvzWJibPO7Gg5o2Fk/uNur899382FXTwb931XHNqoIJfZ/T52Zw/61n8JafvzKon8jO6o4xbSs2s2laJJ7cNjNfePMirlyRP+JI5YFiJWsn2sAakEN98pIFzM0aPc950aIcLlqUQ4c3SDAcIaIUShkzHrM99hGbOA709auX4g2EeGbf8RL/P3zmIK8dbeaeG9fp/gszxF1P7B/Wi2cyhCOKjcdaWZLnoa7DN6gUXKKUZrr52EVlXL1SJ5U1baCSTDclA8o4vmVVAWfe9V8aBuTP1pems7emg9bAxG3LeSl2un1hXj5k9DVZX5JObYeX6javMdizoZuidCc2i2lcAzz7ZCc7Tvqm2eHGbt442sLpo9zMnU1m7dF+XlYS33jLcm49dx5P763nqT31bK5oQ43hTDai4FhTN6kuG7tqeozyEgKZSTaau+OPMByorTdIly/EmuJUbBbTiHXPtle3k5fiwGkz440mg6rbvf1J495ghP31x09kB9ZcDoZV/0jntp4AkYjxfCAUwWkzs62qHafVTGGaY9AoC7fNQm/0vRo6/bT2BFicZ9R9Hg+nzcxblxUyJ8PF2pJ0luYnT0kzEU07FRSlu/jChkV86/H9/XXSk+wWatp7h90kWlaQjMUko9ZUNu78GvuteN18M5Ns9PgHJ55XFqVy1Yo83HYLj2ytYWN5K1948yKuXa0bbGrTx3ef3M+vXzzKz9+zhitW5PHQlmrgeG3SgSOwSjPdg25+Ws3C8oIU6jt8mEyC2SSYRPDYrYgw4vnBmuJUwhHVP3J5pBrNR5t6WF+aTrrLxtwsN4cbu7n98kWsLEzFajbhsluwRWuwa9pEiUQU3YEQtTFG73/5H7v542sV3PW25ZRlxy6lcCLMIjFH2L5xrDXmzDYwtsNVRWMryTQVPnvZQm44s2Rcr8lLGXmk70TwBmPvY/JSHHzwvLnjWleK0zr6QiNId9v47Y3ruO/Vcu54dE//468fbeVAQxdrinXd+OmuwxvkuQMx+/9Omr11XZRlJyU0uayTypo2PiaT8NlLF/LtJ/aT7LBQ3tJLIBQZccDSSKwmYWVRKiaT4A2E6PSFjMGOPQG6oufurb0BNpa3cnppOtVtXlT0sdbeAOljvOk7lD/OMXQ8On0h7t9YSVl20oQ0Qj4VzNrkcp/iDBc3nzuXm8+dS2OXj/f9bhN760ZOzszPSaK2zdvftbIvgWs1C6cVp7GlcvQT4jSXlfk5Hipbe6nvMKbSbi5vG15H2WZmWUEKRxq7WFGQwt66TrI8dtLdNhwWEyUZLqravISjJ+92i3C0efiIif31XbhsZixmYXN5K30DHjKTbHgD4UG1rywmhjVbCIYVbT3B/saFI3HZzFyzqoB3rStiRWGKrhepaSdhV21n/1T+kZqg+IIRDsepY+mwmrjjqqVElMJqNrEkL5luf4gcj53yll4cVjOby1tJcVnZsDQXfyhCIBxBKcWj22s51NjNZy9byLzoSKhrVxewv76LVRNYo1PTJsKHLyjjvtfK+fq/9vCrF46wqyZ+h/tjzT2cXprOnpoOugNhVhSksCVGKZhjzT0xm+/Ny3IbJ5MK9tV10BW9IeOxWwatN57rz5jDisIUbjhzDtkeB8FwBItJ9AWuNmEaOn38Y1sNj+2sY399J6GIinmTpMsXIs1tIytp4pKiwXCEj92/tf/icKiDDV3Mz04adKN0QU4SzV2BaZNYBrjzsb3YLCbee/rYp74uyPHw7bcu57cvHY07lfdktfUESHFaB40KB/jIhWUJ24e87bRC7nn5GClOK2fNy+BtpxXGrfusTS8pTivPfPp8nthdz8fv3zZl73u4sXtYT6CpUJrp5qMXlnHNKp1U1rTxesfaIt6x1mjY+sE/buapPQ3DjudjtWZO2phm/QH0BIxZulaTkO2x09jlH7F05Egmatbt9qp2Ul0nluA+Fc365PJA2R4H97xvLdf87JURuzy3dPljTtULhhV76zopTHUOq+uY7rJSlO7CZjHhD0U41NDdX6oCjOmJxekuUpwWdtV0YhI4bU46hxu7+pdr6SttEYrQ2hMYNPW9INWBUsZIx3gbaG8gzLaqdrKT7dR1GJ8v1kjrsmxPzLo19Z0+bBYTa4pT49ZitVuEf37kbObrk0lNmxC3nT+P5QUpfOGhnXT6hl+kl2UnEQrHTyznJjv40hWLuWplfsznS6MJ4zPnxZ7S8+lLFw57zGE168SyNi2FIhGsJhONXf4Rj+N9+o6XBalGo9l4tlW2sbo4FatZ8AUj2C0mNpW3xUwcdflDHG3u4Yx5GUSUMTpiR1U7KS4bH7pgHgtyPKwoTOk/sU2Ojho0m3R5GW3i1LR7Of+7zxEaoTavCFy+LI9bz5s7oQ39AP65vTbmyOQ+3mCE6rZeyrKTcFpNCMLOEW4GJYpS8PVH97K6KI0l46hN/e71xbx7fTGHG7v5/lMHeHJP/YTG1dITwGM395+Tz8ty8+N3rWbZBDReO1FJdgsvfu7ChL2/duJC4QjP7G3gmb3HG+DmeIy+RK29ATKT7IOuWyfSvrpOFuUmDZqFO1lKMlx87KL5OqmsaRPk8xsW8ek3LeSp3XU8urOODm9wUCnX0YRGKPE0VN8s+1eOtLAwJ4kef2jEmYIjGdp0+ETVtvt4bGctV6/M1wMq0cnlYfJSnNxz4zre8etX43bG7PaHyPI46A0MTiBnuG3kJNvZW9fF3GhdU6UUnb4QR5q6aR3hJBugstUYEXxOWQZbK9riNhAKhCKsLkodlESuafeRlWSjrmPkGqlDXxdLa08Aj8NCV4xEViAUiVnnzW4RVhUZ5Tb+8FoFd1y1RB+0NW0CpDitrClOozjDNaxBUIrTgs1sIt1l659RsCjXwyWLc1hemEK3L8TZZZnkTsEUXU2bDjKS7KwsSuXlw+OrGznSrACAYESxrbKd00vT2TnKsRygpdvP5oo2Or1BUpxW3nvGHD5x8XxcuvaoNkUKUp185MIyfvzfQzGfT3Fa+fl71nDO/MlpyPrH1ytGXcY7woyb6SQQjvDqkeZxJZf7lGUn8cvr1/CD/xzkp88entC4uvxhtla2c+bcdG47f15CE8vazNbjD/ORv2xl4L2ohi4/xRkuQmGFGkvdyBPkD0U42NDN+tJ09tV1xrz+PFklGS4+etF83qKTypo2ofrq+y/M9fDxSxbgD4V5+y9fG3Hm4EAHGjrj5p1Gfl03BalOUl1Gbs4oGzm2pt35KQ52T9DN7EA4wif+up2l+SmUZc/onq4TQl/lxLC8MIUfvXMVt/1p67DnzGJ0RY7VBbok082WaK3jo9G6pidiV00nxRmuEe/gVrUNL03R1B3AbQuzvjSdlm4/R5t7Bk1/LEh1srVi9KmGjV1+8lMdpLls/QnvJLtl0En1+pJ0EAAFCAcbunjjWCv5KQ6q27xElOLLVyxhU3krNe1e3rm2aMyNQTRNGyw3xcGGpbnD9jsd3hAdXuOxJXkevvXWFXpEsTarhcIRsj12itKd5KU42XisFZvFRCB08iMU1pWMfepeRBmdsjOT7KwqSuW0OWknNQXvSFM3eSkOXDZ92qaNXY8/xMIcD3Oz3LjtFnoDIV4/2srqolS+cuWSQU16JlI4ojjUML4eHdPdvJO4aBQRPv2mBQTCEX79wtEJiynDbeOmc0q5/vQ5pLhOrm6yNnu9fKiJbz6+n1iTHPpK1PRdD06WiIKNx1qxmISy7CSSHZa4s2THY050pLJOKmva1LBbzPzrY+fQ6Qvyx9cq+Plzh/GHIv0lXIfq9odZX5rGxmPjL4dV0+7lgoWZHG7sISfZMebkclG6i9pRBmSOl28CajifCvRVShwbluXx+Q2L+M6T+wc9XpzhjplYhhM78NotJgrSnNjMJmxmEy29AWravPT4Q6woSIk7RbClO8BnLp3PsaZeHt5W0/94TyDcP20pL8VBdrKdHVXGOgrTnGPe6GrbfbisJkoz3bT2BEhzWcc0Haq2w0eS3cLrR1tYdefT0bqt8NqRFn70zlU6waxNa75gmGf3N3L58rxEhzLMrefNo7bDx1/eqIz5/PkLs3RiWZv1LGYTP3jnKrZUtPK3TdUUpjrZXdPBwZMcHbm6OKW/Ue54NHf72VLRylUrcjmZ2XJ99c41bawiEcVtF8zjy1cuGfS4UmrSp26aTcKjHz2H/fWdHGns4ZXDzcNqls8UZpPw0QvLuHBh9kmtR0T4woZFuKwW7t9YSX3nyV3YlmUn8eBtZ+paj9pJOdbcww+fOcS+UfoNTZVQRPXPZliU66HDGxx1Vm4sRelOPn7RfK5dXaCTypqWAMkOKx+5sIybzi6lpt3Lh/60hdaeAB3e4LByXVvK2zh3fiYvHRr7rEOPw0JpppvnDzT3v99Y1XeOLR82VvOy3Jh0SQxAJ5dHdNv5c+n0Bbn7xaPYzcK87CTcdgvHmmOPSG7q8o+YEO6zOM9Dkt1CXYeP6jZvdJSzwWk1saooFZvFhGOETvFfv3op71pfzJaKtkHJ5YHqOnwszPVQmOYkzWVl6xgaDQ7UG4yQkWQjw20b10V1tz9EidWFf8BIsRcONnH/pspxNUTRtKlU2+7lid317K7pmJbJZZvFxJ1XL+Wms0t4YHM1d794fPTTHVct4drVBQmMTtOml+o2L1keG+GIonr3yY24Wpjj4VBDD6cVp/XfIBWIO4p5Ua6HZKeVcFhhNgugOGNepq7Fpk0pk0nIjNG9fKr+Dsuyk/qniJZkumZccnl5QQrrS9O5bm0RC3Mnpo+IiPCJS+bz8YvLeO1IC//YXkNBqovlhcn87uVyguEIR5t7xlSv8rKlOTqxrJ0UpRQ//e8h3HYzLquJ3jjlIBNlf30XTquZdSVpY27ymZNs5+MXz+e6tUVYdVL5lCUi7wC+BiwG1iulNg947nbgA0AY+LhS6qkYry8F/gpkAFuAG5RSJ9YZThuR02amLDuJpz91HmAMOHz/vZsoy07Cajaxp7aDc8oy+em7V/PBP23hlcMto66zJMNFMKz6y9TlpdjZO+QGmc1iIi/FQUXL8WsAi0lYX5rOq0dGf4/xONLUw4//e5Bf37B2Qtc7E+nk8ghEhM9vWMT7zirhhnveYFd0xHK2x05uigOzCNur2weVnlAo5ma6jA7yGNN8TGKsSylFpzfEvrr4UwW9wUh/x9x1JWkxl3nn2iKui3boDI1QjPz00nSeP9AEGBfaJ2JzeRvr48QRT1/X3+UFKWxYlst587NYVpCsL6y1aeuuJ/bzqxeOAPDVIaO8phOL2URZtocvXr6Y955ezKPba7FaTLxlVYG+yNS0Aa5ckc+PnzlIhsd2UhfMqS4rwXCEbn9o0E3WNcWpcV+TZLew8VgrInDu/Cyykmy4beMridHlC9LaE6A3EOZAfRd2i4lzF2SRpGs2nxJExAxsBmqUUleKcYL0DeAdGBfEv1RK/SSRMU6kh7bGHgQxnd37/nX95/ITTUQ4qyyTs8qO17u+aFEOAB3eINf/9o1R61XmJOteCtrJERF6AyH8wQhlOR4aOnw0DLmxsb40jYrm3v7HTytOo8MXpKHDS5d/8qeBe4NhNpW3sTjPQ1tPgPrO2Dde0t02PnzBPK4/Y85JlaDSZozdwFuBXw98UESWAO8ClgL5wDMiskApNfSP9TvAD5VSfxWRX2Eko385+WHPXn15oLPKMtn/fxv6f99b28mWilaSHFbuff96PvW37Ty2sy7uepYXJHOgobu/3J3HbibVZaOuw0+Wx057bwCb2cTSghRQqj+5PD87iWA4fnmOk7Wloo1wRGGe5bP09VXKKAKhMN976gAHG45PqR3YhT4vxUFxuottVe0EQhGcVqPB1ljvsI5ERRPTfduASeDLVyzh/WeX9G+Q83M8ZCbZae4efrAdqUP4eOyu6WBRrof99YOT4kvykokoRW8gRKrLuHgOK9hS3sqygmTuu2k96W6d8NKmN28gzD+21XDb+fO4dGkOq2dIaYk5GW4+dvF8AA41dNHc7Wd+zsSMrtK0mc5sEj71pgXc+djecb/WahbmZLgxCRxq7Ka9NzhsmQP1XaS7bbT2BChIdZDlcdDeGyDdbePAgFqzFpNwy3lzcY8xKayU4p6Xj3H/xkq6fCFMIvzgupWsL03XU3tPLZ8A9gF9zSzeBxQBi5RSERE5uRoM08x58zN525oCWnsCfP+pAyfc3X2qeOyWhJ2/BkKRuCUzzCbh1vPm8tbVBbpxkDYhbj1/Hrfct5mwUizK9dDU7ScvxUGqy0qS3cr++i7CEcX6kjQiiv6brOtL0ujwhnDbzVjMJiJKYRZhZ3U73kkYAb2vrgunbfgo5iS7hZvPLeXmc+fqm6+ziFJqH8SciXMN8FellB84JiKHgfXAa30LRG/mXgS8J/rQfRijoHVyeYoM/Hdbkp/c39fLajbxnbet4HBj97C8Exiz/3cNKU/rtFlIsltYX5LOrpp2IhFFT9goE9t3nFyan8yB+k6W5J9YibuxaO8N8tjOWq5ZNbtnEs/6vfCrh5t5dEctnb4gS/NTeOuaAvJSnCilaOsN8qm/bWdbVfw/wroOH3UdPkxi1H7ZWN7K+tL0CYltc0Ub60vS+6cSfubShdx0TumgZdLdNv7xkbP4yj9281x0lDIYXcCtZsFhMeE7yUZGvcEI++u7OGteBl2+IDazGV8ozIH6TvpWXdnqJdVlJTfZQXGGm9/+zzqdWNZiuvNfe3n5cBO3X774pGsYTgSbWXj60+eNq1bTdFOWnRSzEYumzWYiwvvPKqWqtZdn9jXicVgwmyRmsnigxbnJo5a36gmE8YcipLqspDhthCIRylt6KR8w/U4p2FndTntvcEwzd9p7A3z78f38bXMVABcuzOLu/1mrp/aeYkSkELgC+Cbw6ejDHwLeo5SKACilGhMU3qS4+dy5/T+fOz+LD/5xM0eaTqzp9VS4cmV+QmbbVbX28q67X49bFiPNZeVTlyzANkLZPE0bj1WFqSQ5LOR4HEQiiswkO7UdPmraB9/g2BhN6DqtZpxWYxBVrNPOkgwX1W29TEAP3WG8AWMU89L8ZDq9QS5bmsuHLyzT15vaQAXA6wN+r44+NlAG0K6UCo2wjJYgbruFe963jit/8hJtQ87X99V1ke620tpz/PGBgz6HSnNZWVeSxvaqduZledhT2zlpI5etZhNZkzTbaSaZ9WcnZ8zNoDjDxRO76/neUwc4+65nWffNZ1j45SdZ83//4YWDTSzKTR51PREFXT5jHzWWWmljVdPuZX52EvOy3Fy7Oj/mMoVpLn7//vX86QOns2FpLutK0vAFjY7gi/NHj32sunxBdtV0sqWyjT21ncNOHNp7g+yv76LDG+S+18on7H21U4sIHGzoprJlcjtPj8XzBxpZ/NWnONRwcs2+Ek1EZv00HE2LpTjDxdvWFJLuttHlC4062i/HY6elZ2xl90IRRXtvkEONXbhsse/V9/jDNIyxcdcH/7ilP7EMRp26yToJ1hLqR8DngIFnUfOAd4rIZhF5QkTmx3qhiNwaXWZzU1NTrEWmvbLsJP750XM4f0HWhK/7RA+DIkYDsAsWZvHxi+dzx1VTXx5LKcXtD+8asfF2S0+AzRUzq3a1Nr11+ULMzXBT3+kjGFY0dvkHlXscKhSJ4A9FYiaWAcpbellZNL5yiuNhEmMU4l9vPYMvX7lEJ5ZPYSLyjIjsjvHfNVMYw4w/5s5EBalObjt/Xszn5qS7x7yeTeVtbCpvIxhWpDitk3pObbOY+PI/d3P/xspJe4+ZYMwjl2PUh7sXOB/oG97zPqXU9hivCwO7or9WKqWuPqmIJ1A4omju9nP2vExeK2vhpUPNRNTw5PDGY62sK0mL1nry0T0FNab69J1kZnns5KU4R1z2nPmZnDUvg0VfeZJA2Nh4wmGF22aekCmIR5p6WF6QPGw6wlCtPQH+vrmaz122UNdZ1ob5yIVlPLS1mgXjLOHQ2hPgxYNNmEzC1Stj32gZr/s3VhIIR+j0jTySUdO0mWtpfgq/eO8abrlvMzurOyhKc5Kb4qC6rZe6DuN4bxI4bU4ahxq7h9WcHE1xuouNcZr7rS1J44y5GQDsr+/EYjLFTXAvyvX0Nwm0mIS5mUlUtPROWDMxLfFE5EqgUSm1RUQuGPCUHfAppdaKyFuB3wHnDn29Uupu4G6AtWvXztg7D0l2C/93zTIu+n/PT1gJt5VFqdz7vnUAHGjo4kB9F3trO3l8d13/4I9YlhUkc+/718dsfjiVRITf3riW14+28PDWGp7aUz+oMTbAz969hrPmZcZZg6aNX4rLyoWLs3nun3vI9oy+DQTDisV5Seyv6+y/1hxqS0UbS/I8JNmtVLf3Uts+thuso7lieR6fvnQB87J0SZjZQCl1yQm8rAajxFSfwuhjA7UAqSJiiY5ejrVMXwynxDF3JirJHJxEFowbS9ur209ofcHI5DYs7fAG6fAG+c6T+2ns9HH1qgKK012zbvDXeMpiDK0PB/C/SqkHR3mdVym1aryBTZSXDjVR1eolEApztLmHhk4f9Z1+RMGu2o4x38EYWN+pNNONNxCK21Qgy2PnWPPETve79dy5Y0rUdvlCxtYXtbOmgxSnldOKk9lSObi8h9NqGlddrOUFKewZZapwn+ZuP3tqO1lWkDLm9WuzQ7rbxg/fuYoz52WMaXmljG6wt/xhM2XZSfzsPWsmJI6XDjXx1J4GANbOmbxRFpqmJVZxhouCNCfnLsjk8V31VLV5qYo2uV2SlwwogmE1Yq+EonQnWUl2zCZBgA5viGSnBV8wgt1iojA1THWMC+jPb1hETrIDpRR3PbGfn757ddz36Ct/sbwghbesLuBd64rGXKtZmzHOBq4WkcsBB5AsIn/CmJb7cHSZR4DfJyi+KVOc4WLDstwRG/eMZm6mm1vPm8uFi7LJ9tj7z5PPmJvRf1PnM5ct4H/u2RizfuPcLDefumRBwhPLfRxWMxcszOaChdlUt/Vy+Y9fonNAYvxXLxxhw7LcWXexqk2uojQXC3M9o14TL8r14Io2p7VbzQTC8W/a7I02r1+an0xduy/uSOexOKcsk89vWMTyQn1NqY3qUeAvIvIDjIZ+84GNAxdQSikReQ54O/BX4Ebgn1MdqDay8xdkDeo9tq40Pe5AjrHYVtlOXoqd4nQ3DZ2+QWXsJsrqolRq27388JlDHGzsxmO38PkNi0ibRTMsxnTVEqc+3IywKDeZf+2o5aEt1bjsFrp8Idw2M1aL6YSHxh9r7qEsO4k5VnN/B8o+ZoHDjcNPYE9UTrKdj140n+tPLx7T8ikuK8986nz+8Fo5/9nXQEVLLx3eIFsq21hekExlay8d3hBL85M52NBFfqqDojQXuSkODtR3keK0srWijWCM78YbDLMoLxmFYktF+6ix/PKFI/zs3av16OUEEREH8CLGiCgL8KBS6o5xzDq4Efhy9NdvKKXum6jYRqu13OMP8ekHtuMNRthX10lTl5+VhSnc+/71E1JrMBIxEj1gTNG1W3Rn6Vi6fEE8M7gWtab1MZuEr129lKNNPYOSTHvrOinLTiLJbiEryU5OslEWI8VpIcluxRsMsae2i15/mK2t7XHXbzULa0vS2DwgQW0S2FrZxrKCFP6xvYZ3nFY04vZ0w5lzONDQxd03rMVp0/ukU5FS6nbgdoDoyOXPKqWuF5G7gAuBYxjH54OJinEq/d81y2jpDvDa0ZYRl1tWkEy2x0Fbb4D23iCFaU6uWVXAW1blj9roMtvj4KEPnUWnL0hEwetHWqjv9NHU5efy5XkT1idlohWmufju21dy25+29D+2q6aDt/7iFc4qy+Qzb1qgm3xqE+KMuRnkJTtoitEcvs/qolS2VbWPe917ajvJT3WQ43EQjg4WGaslecncfvkizp0/8SV0tJlNRK4FfgpkAf8Wke1KqcuUUntE5AFgLxACPqKUCkdf8zhws1KqFvg88FcR+QawDbgnIR9Ei8sXDBNRxrn02pJ0NpWffEmoug5//4xFj93M3Kwk7FYzLd3+cfWBKMkwRiSnOq10+UMca+5hTXFa/+xDgH9Hb5w3dPq458Z1mGbJTeGxDon5EUZ9uKFzM78pIl8F/gt8IdqZcyiHiGzG2MDvUkr94wRjPSFZHjtL8pJ5QMH87CR213ayujiVYFixo7od3wl0tLWahX9//BysJhO1HV6e3tPAD/5zkG5/iLACQSjLTuJw4+A6rjnJdpIdVo4294ya2LaZTXzsojJuOW8uDuv4LjKLM1x8+colfOmKxRxs6OY/e+v5z94GdlR3kJvsYEGOp7+2Vm27j2yPgx+/azVNXX5+9MxBFMS8M1Td1su8rCSqW+PXgxvo3zvrMIvw8Yvn667WieEHLlJKdYuIFXhZRJ6IPjfirAMRSQfuANYCCtgiIo8qpSanxSpwoN642eFxWHHbLeSlOLn31fL+59+1vnjCmtjsreuksqWX8xZkceu5c3VznDh8wQgeR6Kj0LSJke1x8L23r+S7T+3npUPN/Y/3HasX5BgnmSlO66AE9Oml6Rwa4aaxzWJiVVFqzMevW1vIoztq+eNrFTz84bNHjK+1J8CXrlisE8uz013An0XkU0A3cHOC45kSaW4bf/zAen7+3BHue62c1mi9c7NJWJqfzAULs7l0Sc5Jz4Jz2y39swDedlrhScc9VTYsy+XNy3J5Ynd9/2M7qjvYUd3Bm5flsqIwNXHBaaeMe189Rm8gxIH6+GUPT+Y8ubbdR227j9XFqWNavjDNyf9etpCrVuTPmoSMNj5KqUcwZvnEeu6bGAMihz5++YCfjwLrJy1A7aSlOK2sLkolrNRJjViOp8sfZseAm13rStJizmC0mo0ydTaLCV8wjM1iYk9tJ2aBvspA60rS4taq94cis2o/NmpyeYT6cLcD9YANoxbN54E7Y6xijlKqRkTmAs+KyC6l1JEh73ErcCtAcfHYRuiOx6riNDKT7GytbKcg1clrR1pYW5J+QollMOpN3fXEfr58xRIK01zcdE4pV67M41fPH+WpPfXUtHuZm+XGbBKW5Sdz+fI83rwsj+IMF2CMBnzxYDPPHWjkSJPR2KzbHyLFaSUjyc6VK/J4x2mFZCefXFZHRFiY62FhroePXjSfLz2yiz+/UUn9gOZCIvCJi42+MVkeO9+8djm+QJiqtl7+srGS2nYvobCivKWHQCgy4rThWB7dUcu/dtZy45kl3HHVEj2KeQoppRTGRSqANfrfWIfrXwb8RynVCiAi/wE2APdPdJx9rv7ZyyQ7jZH3KdGO6P/Z20BNu5f8FAeXL8uL+bpHd9Tyrx21ZLht3HhWCYvz4jexPNTQxbP7G2ntDfDaFy8mSU85H1HWGOrvadpMsrwwhT9+4PT+4+FAde0+DvqHN/d8Y5ST2oU5STFPfDcszeXhrTV89Z97+O9nzh81ttXFujzPbKKUeh54PvpzO8YMwVnHYjbxiUvm8/GLy+jwBglFFKlOqx6VGxVrcMZlS3NYrsvOaRMgGI6wv76LjaNc39WO0GhyrLZXtbO+JJ2NcUYgprmsxmzdM4r1jEJNm+VEhNPmpPHbl49NyfttKm9jToarvypBqsvKgpwk9td3caBh+ACTgSXnd1V3YDUPznFZTMJ3376Ca1YVTGrc081YMisx68Mppa6PPu8Xkd8Dn431YqVUTfT/R0XkeWA1cGTIMpNaLH1VUSqPf+IcvvXvfeyr62LDslzqOnycOTcDu9WE3WLCajbx+tEWmrtH7xKf7rbhtlkGljYm2+Pgq1ct4atXLaHLF8QXDJPmssU8OfY4rFyxIo8rVsROlk2WT71pARGlONrUQ28gzLqSdC5ZnM1ZZYObgzhsZubneLjjqqX9j/mDYX7/ajk/+e8hesfZHLA0w81t58/TieUEiDbi3AKUAT9XSr0hIh9i9FkHBUDVgN+ro49Nml/fcBpKGaVdwPj/d962gjeOtXDd2qL+xwfaXdPB957aT1V0NP2CHM+IyeXCNBcXL85mbmbSrLqLqGnaYF+7eilvWV3A95480H+hW5adNGzarwhxRyOAMcKyonV43bZ3rSviPacX8+67X+eGM+cwJ2Ps3a01bTYSEVJds6cu4VhtKm9lfWk6u2s66A2EOXNuBt97x0p9Tq2dtEhE8a3H9/HojtpRl+0coSnmWCkFG8tbWVeSxpaKtv5aqg6riZvPmcut588lWZdi0zQtal1p+pQllwE8DiM1ajULaS4bG4+NbVClLxRh4C4yN9kxrv5Sp5JRk8sj1IfLU0rViXF28xZg99DXikga0KuU8otIJkai+rsTF/7YZXsc/Ohd8RvpgFHb5dHttfzqxSMcjVF35fLluXzgnFJWFaWN2EzD47BOyzqlmUl2vv3WFSf0WrvVzG3nz+OaVfl849/7+uvIDFWQ6uTssgxOL83AbTdjNpk4c16GHiGaINE6U6tEJBV4RESWMfZZB6M6kVkHSqmYF0UXxKjDfM78TM6ZH78z+r66zv7EMkBvYOSTX6fNTFn20Oo+mqbNNtsq29la2UZRupON5cZjHd4AKwpTsJgEq9lEKKzYVdNOkt3C3Cw3FpOJytZe6jt9rJmThimaee72h3Fkmahu89LY5WdBThJ3XLWUFw81EYoobj1vbkI/q6ZpM9f9t5yBiOALhqls7aUkw61LeWkT5s3Lckl32Xj+YBNbKuInUpIcFjq8wQl5z03lbczLchMIRThnfhafvGQ+OSc5W1fTtFNPX6msqbK7ppMVhSkcbezmWPPYazD3cVrNfOiCedxwxpxZ1cRvoJPJ+P1ZRLIAAbYDtwGIyFrgNqXUzcBi4NciEgFMGDWX955cyJPHYTVz3boirl6Vzz+21XCgoYvGTj/1nT4uWJDFRy8qm/UjBfJSnPz8PWt47/pmXjrcTGOnn3AkwulzMzhrXgbF6a5Z/x1NR0qp9mhn3A1Kqe9HHx5p1kENcMGA3wuJTt8dst4xzzpo7QlwoL6Lbz6+l9/duO6ky74AXLOqgD21nfxrRy2XLM7hhjNLTnqdmqad2ipbeslIslHX7uXhrTXkpzpwWs1xm3m09gYpExOvR0tfmIRBjfv6OK1mVham8L6zSnDazHjsFq5ckU9einNSP4+maaeuvnNqh9XMghx9c1ybOCaTsL40g/WlGXzkwjK+//QBHt5aM6h8Yp+aNi8pTivF6U521cSvzTxW87KS+NyGhXrAh6Zpcf1nb8OUv6cA3eOYpZ/tsXPZ0lwW5Xm4YGE2Bamz+5x/XMnlIfXhLoqzzGaijUiUUq8Cy08qwgRwWM28a/3E134+lZxVljmsnIY2vURv/gSjiWUn8CbgO2OZdQA8BXwrOvsA4FKiMxhOlEmMkcZXLM+fkMQyGA1Gvnb1Ul3PW9O0Mcv02Lj6Z69Q1dqLwmg2NJqN0anpxekucpMdpLlttPcaIypykh1YTMKWijbS3TaujtZXW1uSzrrS9Mn8KJqmaZp20kwm4XMbFtEbCA9qpj1QSYZrUAOsE7F2Thq3X76I0+boY6OmaSNLxJX9WOq9m01COKJYX5rOz96zmmyPnnnRR9cq0LRTVx5wX7Tusgl4QCn1mIg8O9qsA6VUq4j8H7Apuq47+5r7nahUl42bzik9mVXEpRPLmqaNlctm4aHbzuLtv3qVQ43DG/gNJQLvOK2QNy3JIRxRbIjRXDQUjvDOdUWD9kV66rqmaZo2k3z0ojKe2lNPXcfwm67HmnuYn52E02pmZ834ksxl2Ul8fsMiLlmcrc/ZNU0bk++9YyVX/fRlaiagoehYNff4sZiEUGTwhOxkh4UvvHkxFy7KwuOwUt/hpSTDrZsPD6GTy5p2ilJK7cRooDn08VFnHUR//x3wu0kLUNM0LUFSXFZ+e+NaPvKXreweZYrvL997GhuW5Y64jD651DRN02a6zCQ7999yBs3dfuwWM//3771sjJaE6vSF6PR1s3ZO2ihrOS7bY+czly7gbWsK9XFS07RxSXfb+NyGhfzkv4filq6bKCaB379/PWfMTccbCLO3rpOP/HkrwbDim9cu4+qV+YNujOmSPrHp5LKmaZqmabPOnAw333nbCj76l21xG3dYzcK8LPcUR6ZpmqZpiVGS6aYk0zju/e3WM/j75mq+8s/d+EMRYGxNttw2oxH8B84txWXT6QZN007MNasKWF+azqU/eJEuf2jY88kOCx88fx5tPQF++/KxE36fs8syOX9BFmCUxjhrXiYbv3QJbb0BXfZiHPTeXtM0TdNmIBEpB7qAMBBSSq0Vka8BtwBN0cW+qJR6PDERTn87qjqobO2N+3wwrLj1j1t46pPn6TIXmqZp2qwiIly3rogl+cl85Z+7OdLYjcUcv6yFCLxzbRGfuXQhWR77FEaqadqpKi/FyYcunMeB+i4iCiIRRUuPn+buAF+9cgnnLcgiHFFcu6aAbz2+j1cOtwx6vdUsnL8gi0BY8crhZsJDSl7kpTh47+nD+61ZzSadWB4nnVzWNE3TtJnrQqVU85DHfqiU+n5CoplBevwh0t02zi7L5GB9F75QmDNKM1gzJxWH1UxHb5B99Z18+IIynVjWNE3TZq1lBSk88uGziUQU5S091Hf6aOz088rhZmo7vBxs6KYkw8VXr1zK8sKURIeradop5sMXlI34vNkkLM1P4WMXzcckQmmmm311ndR3+vjcZYu4amU+AC8cbOKf22vwByMca+7hfzcsZO2cNDwO61R8jFOeTi5rmqZpmjbruO0WNizLHbWesqZpmqZpYDIJc7OSmJuVBMBbVhckOCJN07TjzpibwRlzM+I+f/6CrP7yF9rE00NxNE3TNG1mUsDTIrJFRG4d8PhHRWSniPxORMbeeUfTNE3TNE3TNE3TxkknlzVN0zRtZjpHKbUGeDPwERE5D/glMA9YBdQB/y/WC0XkVhHZLCKbm5qaYi2iaZqmaZqmaZqmaaPSyWVN0zRNm4GUUjXR/zcCjwDrlVINSqmwUioC/AZYH+e1dyul1iql1mZl6elhmqZpmqZpmqZp2onRyWVN0zRNm2FExC0inr6fgUuB3SKSN2Cxa4HdiYhP0zRN0zRN0zRNmx1EKZXoGAYRkSagItFxjEMm0JzoICaJ/mxTa45SasYOIRzHtjsdv/vRzLSYZ1q8MPNiHhjvlG+7IjIXY7QyGM15/6KU+qaI/BGjJIYCyoEPKqXqRlnXTNt2p0Mc0yEGmB5xTIcYYPxxzJZjLkyff6OhdFzjN11jm8q4TqVtd7r9e063eGD6xTTd4oGZEdOptN2OZjr+e8SjY514MyVOGFusY952p11yeaYRkc1KqbWJjmMy6M+mTYaZ+N3PtJhnWrww82KeafFOhOnymadDHNMhhukSx3SIYTrFMR1N1+9GxzV+0zW26RrXdDfdvrfpFg9Mv5imWzygY5puZtJn17FOvJkSJ0x8rLoshqZpmqZpmqZpmqZpmqZpmjZuOrmsaZqmaZqmaZqmaZqmaZqmjZtOLp+8uxMdwCTSn02bDDPxu59pMc+0eGHmxTzT4p0I0+UzT4c4pkMMMD3imA4xwPSJYzqart+Njmv8pmts0zWu6W66fW/TLR6YfjFNt3hAxzTdzKTPrmOdeDMlTpjgWHXNZU3TNE3TNE3TNE3TNE3TNG3c9MhlTdM0TdM0TdM0TdM0TdM0bdx0cnkcROR3ItIoIrtjPPcZEVEikpmI2E5WrM8mIl8TkRoR2R797/JExnii4v27icjHRGS/iOwRke8mKr7ZQkTeEf2uIyKydsDjJSLiHfB39qtExtknXrzR524XkcMickBELktUjCOZKduviGyIfo+HReQLiY5nLESkXER2Rb/XzYmOZyok6jPHOTali8h/RORQ9P9pCYhhSrcvESkSkedEZG90v/SJ6ONT/V3Ei2PKvg8RcYjIRhHZEY3h69HHS0Xkjei+5G8iYpusGGYKEUkVkQej5zr7ROTMRMcEICILB/ytbBeRThH5ZKLjAhCRT0X/rnaLyP0i4kh0TAAi8oloTHsS/V1Nh/3yTBNvvzXg+Z+ISPd0iEkM3xSRg9H9xscTHM/FIrI1uq94WUTKpiKeIbGZRWSbiDwW/T2hx5sY8fxZjHPp3dHt0zqV8cSKacDjU/63PZWmw3nRGOOcMedOI8R6r4gcG/CdrkpwqMD02z+MJEasE/qd6uTy+NwLbBj6oIgUAZcClVMd0AS6lxifDfihUmpV9L/HpzimiXIvQz6biFwIXAOsVEotBb6fgLhmm93AW4EXYzx3ZMDf2W1THFc8MeMVkSXAu4ClGH9XvxAR89SHNybTevuNfm8/B94MLAHeHf1+Z4ILo9/r2tEXPWUk4jPfy/Bj0xeA/yql5gP/jf4+1THA1G5fIeAzSqklwBnAR6LbylR/F/HigKn7PvzARUqplcAqYIOInAF8JxpDGdAGfGASY5gpfgw8qZRaBKwE9iU4HgCUUgf6/laA04Be4JHERgUiUgB8HFirlFoGmDGO9wklIsuAW4D1GP+OVyYiwTbAvSR+vzzTxNtvIcYAhkQk4+PF9D6gCFiklFoM/DXB8fwSeG90f/EX4MtTFM9An2Dw/jPRx5uh8fwZWAQsB5zAzVMcT6yYEvm3PZWmw3nRWMykc6e4+0vgfwd8p9sTFeAQ023/MJJh2ykT+J3q5PI4KKVeBFpjPPVD4HPAjC1gPcJnm/HifLYPAXcppfzRZRqnPLBZRim1Tyl1INFxjNUI8V4D/FUp5VdKHQMOY1zwaeO3HjislDqqlApgXMBck+CYtGkkzv77GuC+6M/3AW9JQAxTSilVp5TaGv25C+PEsICp/y7ixTFllKFvFJQ1+p8CLgIejD4+6d/FdCciKcB5wD0ASqmAUqo9oUHFdjHGDeaKRAcSZQGcImIBXEBtguMBWAy8oZTqVUqFgBcwbn4nxHTYL8808fZb0Zvs38O4jpwWMWFcI92plIpEl5uSa6QR4lFAcvTxFKZ4mxSRQuAK4LfR34UEHm+GxgOglHo8+v0pYCNQOFXxxIspkX/bU2k6nBeNxUw6dxoh1mlnuu0fRhJrO51oOrl8kkTkGqBGKbUj0bFMko+KyM7oFJtT6c7jAuDc6JSFF0RkXaIDmuVKo1M0XhCRcxMdzCgKgKoBv1czDU8ioqb79juTvsuBFPC0iGwRkVsTHcwUmU6fOUcpVRf9uR7ISVAcCdm+RKQEWA28QQK/iyFxwBR+H9FpfduBRuA/wBGgPZp4g5mzL5lMpUAT8Pvo8fW3IuJOdFAxvAu4P9FBACilajBmslUCdUCHUurpxEYFGDOpzhWRDBFxAZdjjCydTqbLfnnaGrrfUkq9AXwUeHTAdzcdYpoHvFNENovIEyIyP8Hx3Aw8LiLVwA3AXVMVT9SPMBKkkejvGST2eDM0nn5ilMO4AXhyCuOJF1NC/7YTIZHnRWMxk86d4uwLAL4Z/U5/KCL2xEXY70dMr/3DSH5E7H3HhH2nOrl8EqIneF8EvproWCbJLzFOMFZhnGT/v4RGM7EsQDrG9JX/BR6I3mnSToKIPCNGva+h/400GrUOKFZKrQY+DfxFRJJHWD7R8U4bo8R/Km+/iXaOUmoNRjmPj4jIeYkOaApMy88cHaWTiNEMCdm+RCQJeAj4pFKqc+BzU/ldxIhjSr8PpVQ4OkW6EGMGxKLJfL8ZygKsAX4ZPb72MM1KFYhRh/Bq4O+JjgUgevF/DUZiPh9wi8j1iY3KmEmFMc32aYyk0XYgnMiYRpLA/fK0NnS/FT2OvgP46TSKaRlgB3zKKIH1G+B3CY7nU8DlSqlC4PfAD6YqHhG5EmhUSm2ZqvccyRji+QXwolLqpUTGJCL5JPhve6ol+rxoLGbSuVOcfcHtGDGvw8jjfD5xEU6//cNIRoh1Qr9Ty8m8WGMexgnojmheshDYKiLrlVL1CY1sAiilGvp+FpHfAI+NsPhMUw083Dd9SEQiQCbGKB/tBCmlLjmB1/gxaiuhlNoiIkcwRpZPetOwE4kXqGHwiKHC6GNTbqzxT+Ptd9p8l+MRHd2GUqpRRB7BOEGLVUv8lDHNPnODiOQppepEJA9jVMOUSsTxMToi6SHgz0qph6MPT/l3ESuORJ0vKKXaReQ54EwgVUQs0dEiM2JfMsmqgeoBo30eZJollzFuVm0d+PeTYJcAx5RSTQAi8jBwFvCnhEYFKKXuIVriRES+hfHvO50kfL88UwzYb10IlAGHo9eRLhE5rIw6nYmKaQPRa6ToU49gJHQTFc+bMfrj9O3H/sbUjso9G7hajGZsDozyHD8mccebYfGIyJ+UUteLyB1AFvDBKYolbkzAHoxru4T/bU+F6XReNBYz6dxp4L5JKdXXI8svIr8HPpvA0GD67R9GEnffEX1+Qr5TPXL5JCildimlspVSJUqpEoyD8ZpTIbEMED057HMtxrS8U8U/ME7qEJEFgA1oTmRAs5WIZEm0IZ6IzAXmA0cTG9WIHgXeJSJ2ESnFiHdjgmMaZoZsv5uA+WJ01bVhTI9+NMExjUhE3CLi6fsZo5nrdPxuJ8w0/MyPAjdGf74R+OdUBzDV21d0Zs09wD6l1MBRW1P6XcSLYyq/j+gxIzX6sxN4E0aNw+eAt0cXS8jfxXQSPRetEpGF0YcuBvYmMKRY3s00KYkRVQmcISKu6N/6xUyTJogikh39fzFGveW/JDaiYRK+X57O4uy3tiilcgdcR/ZOZfItTkz7GXCNBJwPHExgPPuAlOi1GgMemxJKqduVUoXRf593Ac8qpd5Lgo43ceK5XkRuBi4D3q2itbKnSpyY0hL5tz2VpsN50VjMpHOnePumvu80+p2/hQR/p9Nt/zCSEfYdE/qd6pHL4yAi9wMXAJli1H26IzqSYMaL9dmAC0RkFcbUtnKm/k7ohIjz2X4H/E5EdgMB4MboKGZtkojItRjTo7KAf4vIdqXUZRgNh+4UkSBGDaDblFIJby4ZL16l1B4ReQDjIj0EfEQpNR2np353um+/SqmQiHwUeAowA79TSu1JcFijyQEeiY7EsAB/UUpNdW27qZawzxxn/30XRimjDwAVwHUJiGGqj49nY9RR3CVGDTowynJN6XcxQhzvnsLvIw+4L3pT0gQ8oJR6TET2An8VkW8A24iO8pzlPgb8OXrz7ijw/gTH0y96o+pNTKNjk1LqDRF5ENiKcXzfBtyd2Kj6PSQiGUAQ47yjPVGBTIf98gwUc781HWMSkZcx9hufAroxah4nMp5bMP7+I0AbcNMUxTOSzzO9jje/wtjuXoueqz2slLozsSHNGtPhvGgsZtK5U7xYnxWRLEAwykPdlsAYRzLd9g8j+fNEfqei82mapmmapmmapmmapmmapmnaeOmyGJqmaZqmaZqmaZqmaZqmadq46eSypmmapmmapmmapmmapmmaNm46uaxpmqZpmqZpmqZpmqZpmqaNm04ua5qmaZqmaZqmaZqmaZqmaeOmk8uapmmapmmapmmapmmapmnauOnksqZpmqZpmqZpmqZpmqZpmjZuOrmsaZqmaZqmaZqmaZqmaZqmjZtOLmuapmmapmmapmmapmmapmnjppPLmqZpmqZpmqZpmqZpmqZp2rjp5LKmaZqmaZqmaZqmaZqmaZo2bjq5rGmapmmapmmapmmapmmapo2bTi5rmqZpmqZpmqZpmqZpmqZp46aTyzOciJSIiBIRywm+vltE5kZ/vldEvjGxEfa/T7mIXDIZ69a06UpEiqPbmHmK3u95Ebl5Kt5L07SpJyIXiEh1ouPQtNlOb4ualhgTve2JyBMicuNErU/TNG220snlGWgiE7VKqSSl1NGJWJemaYO3T6VUZXQbCyc6rrGazJtMmqZpmqZpmjZdKKXerJS6L9FxaJqmzXQ6uaxpmjbDiUHvzzVN0zRN0zQNONGZvZqmTR69XZ66dDJihhGRPwLFwL9EpBu4LvrUe0WkUkSaReRLA5ZfLyKviUi7iNSJyM9ExDbgeSUiZTHeJ01EHhORJhFpi/5cOOD550Xk/0TkFRHpEpGnRSRzwPM3iEiFiLQMjEfTTmVDt08R+dzAsjXR7eYbIvJq9Pl/iUiGiPxZRDpFZJOIlAxY31nRxzqi/z9rwHPPi8g3ReQVoBeYGyOem0RkX3QbfkpE5kQfFxH5oYg0Rt93l4gsE5FbgfcCn+uLL7p8vog8FN0fHBORj0/i16hp087QY+XQEf7Rbb1ORGpF5OaBy4vIFSKyLbqtVYnI1wa8rq+01Y1xjuHO6Hu1icheYN2QuL4gIkeix+G9InLtZH4PmjabjLbdD1n249FtsDDW85qmjd2JbnsSLZkhIp8XkXrg92O8pr05+vP7RORlEfl+dNljIvLmAcumiMg90eN9TfScfkpK32nadDbSNhtnu3yfiLwcbx3R6+N/Dbg+/kbf8hKjLOyQ7XieiDwrRh6qWYzr7NToc/8rIg8Ned+fiMiPJ+ebmV10cnmGUUrdAFQCVymlkoAHok+dAywELga+KiKLo4+HgU8BmcCZ0ec/PIa3MgG/B+ZgJMu8wM+GLPMe4P1ANmADPgsgIkuAXwI3APlABqBPtrVT3gjb50Dvwtg2CoB5wGsY21o6sA+4A0BE0oF/Az/B2IZ+APxbRDIGrOsG4FbAA1QMfBMRuQb4IvBWIAt4Cbg/+vSlwHnAAiAF4yZVi1LqbuDPwHej5TyuEmNE9L+AHdGYLwY+KSKXncBXpGmnHBHZAHwauAQoAy4YskgP8D9AKnAF8CERecuQZeIdw+/A2E/MAy4DhtaFPAKci7Edfx34k4jknexn0jRt7ETkq8D7gPOVUroOs6ZNkTjbXi7GOfUcjHPksVzTDnQ6cADj2vm7wD0iItHn7gVCGMf61Rjn07rXiaaNbuh2OZqfY5w/52Kc+46nLroA38bIQy0GioCvRZ/7E7BhQLLZgnFt/odxrF+LQyeXTx1fV0p5lVI7MJJAKwGUUluUUq8rpUJKqXLg18D5o61MKdWilHpIKdWrlOoCvhnjdb9XSh1USnkxkmiroo+/HXhMKfWiUsoPfAWITMBn1LRTwe+VUkeUUh3AE8ARpdQzSqkQ8HeMk1UwklCHlFJ/jG6/9wP7gasGrOtepdSe6PPBIe9zG/BtpdS+6Lq/BawSY/RyECMhvQiQ6DJ1ceJdB2Qppe5USgWiNdp/g3Eg1jTNuDnz++i22MvxE1gAlFLPK6V2KaUiSqmdGDd5hh5PYx7Do+v+plKqVSlVhXGzaeC6/66Uqo2u+2/AIWD9hH9CTdNiERH5AUaC6UKlVFOiA9K0WWKkbS8C3KGU8kePq2O5ph2oQin1m2i/lPuAPCBHRHKAy4FPKqV6lFKNwA/R58OaNhaDtsuRFozOBnhbdPlepdRejG1xTJRSh5VS/4m+VxPGAK3zo8/VAS8C74guvgFoVkptGf9H0obS9U5OHfUDfu4FkgBEZAHGBrUWcGH8m4+68YiIC+OAuQFIiz7sERHzgOZkMd8T4y5RVd8TSqkeEWkZ7wfStFNUw4CfvTF+H7gdDRqNHP29YMDvVcQ3B/ixiPy/AY8JUKCUelZEfoZxV3iOiDwMfFYp1RlnPfki0j7gMTPGSGhN04xtdfOA3wdtlyJyOnAXsAxjlo8d40bSQGM6njJ8hsL/YIyaLok+lIQx2krTtMmXijEC653RG8aapk2NVOJve01KKV/fL2O8ph2o/3islOqNDlpOwhh1aQXqjg9kxsTI5+KaphkGbZejyMLIWQ3ctsa8nUVvBP0YY2afB2M7bRuwyH3AhzAGS10P/HGs69ZGpkcuz0xqHMv+EmO043ylVDLGNHkZ+SUAfAZjiu7p0dedF318LK+tw5h+YLzAOKhnxF9c004p49k+R1KLkdgdqBioGeN7VQEfVEqlDvjPqZR6FUAp9ROl1GnAEozyGP8bZ51VwLEh6/EopS4/0Q+maTNQL8YN2j65A36uY3DppyIG+wvwKFCklEoBfsXYjqV96x64vuK+H6KzEH4DfBTIUEqlArvHsW5N00Y20nYPxsXqlRj1I8+esqg07dR3Mtve0PPYk7mmHagK8AOZA86Hk5VSS8e5Hk07FY22zQ7dLnsGLi8iA5dvwig/E+/cuif6/3jv963o+y2PbvPXM3h7/wewQkSWYexH/jz842gnQieXZ6YGYjTvisMDdALdIrII4y7NWF/nBdqjtV/vGEd8DwJXisg5YjQPvBP9t6bNHuPZPkfyOLBARN4jIhYReSdGIvixMb7+V8DtIrIU+puQvCP68zoROV1ErBgHaB/HS9cMjX8j0BVtwuAUEbMYzf8GNRbTtFPcduA90b//DQyeUvsA8H4RWRy9mfqVIa/1AK1KKZ+IrMfoVzBWD2Bsx2nRBkQfG/CcG+PkuQlARN6PMTpa07SJsZ342z1glL3BaIT7cHT71jTt5G1n4ra9k7mmHfh+dcDTwP8TkWQRMUUbh41ablLTZoHtjLLNDrEDWCoiq0TEwYCSctEZBQ8DXxMRVzSH9T8Dnm/CGGx1ffT9bsLoTdLHA3QDHSJSwPEBVH2v92Hkq/4CbFRKVZ7IB9aG0wm/menbwJej09TfPsqyn8W4kO3CGOH0tzG+x48AJ9AMvA48OdbglFJ7gI9gbLB1GHeXdYMTbbYYz/YZl1KqBeNu6meAFuBzwJVKqeYxvv4R4DvAX0WkE2NEY1/H62SM/UEbxjT7FuB70efuAZaISLuI/CN6gL8So6b6MYx9wm8xGohp2mzxCYx65+0YF7P/6HtCKfUERi3k54DDGMdMMEY4gdFE904R6QK+SuxGn/F8HWMbPYZxUds/dS9ag+7/YTQFbQCWA6+M61NpmjaSuNv9QEqp/wA3Af8SkTVTFZymncImctv7ESd4TRvD/2CUt9qLcQ79IEZNZk2b7ca0zfZRSh3EGID4DEa/kJeHLPJRjGvNeoxz3/s5fl4NcAtG0rgFWAq8OuC5rwNrgA7g3xiJ6qHuwzhv1iUxJpAoNVEzuDVN0zRN02Y3EVmMcTPHHm2mqWmapmmapmnaCRCR7wC5SqkbJ2h9xRilY3Pj9BzSToAeuaxpmqZpmnYSRORaEbGLSBrGjIF/6cSypmmapmmapo2PiCwSkRViWA98AHhkgtZtwmiG/VedWJ5YlkQHoGmapmmaNsN9ELgXCAMvYJTC0DRN0zRN0zRtfDwYpTDyMUq//T/gnye7UhFxR9dXAWw42fVpg+myGJqmaZqmaZqmaZqmaZqmadq46bIYmqZpmqZpmqZpmqZp2ownIv8nIjtFZLuIPC0i+dHHRUR+IiKHo8/rJqyaNkGm3cjlzMxMVVJSkugwNG3KbdmypVkplZXoOE6U3na12Upvu5o28+jtVtNmJr3tatrMM9XbrYgk99XTFZGPA0uUUreJyOXAx4DLgdOBHyulTh9tfXq71War8Wy7067mcklJCZs3b050GJo25USkItExnAy97Wqzld52NW3m0dutps1MetvVtJlnqrfbIY3a3EDfiMprgD8oY4Tl6yKSKiJ5Sqm6kdant1ttthrPtjvtksuapmmapmmapmmapmmadiJE5JvA/wAdwIXRhwuAqgGLVUcfGzG5rGna6HTNZU3TNE3TNE3TNE3TNG1GEJFnRGR3jP+uAVBKfUkpVQT8GfjoCaz/VhHZLCKbm5qaJjp8TTvlTFhyWUSKROQ5EdkrIntE5BPRx9NF5D8icij6/7SJek9tbJRShCPTq7a2lhgiskpEXo82N9gsIuvjLHdjdJs9JCI3TnWcmqZp2sSK6PMATZtQ+txa0zQtcZRSlyillsX4759DFv0z8LbozzVA0YDnCqOPxVr/3UqptUqptVlZM7bM+5SIRBS+YDjRYWgJNpFlMULAZ5RSW0XEA2wRkf8A7wP+q5S6S0S+AHwB+PwEvq8Wx2M7a/E4rPzp9QraegJ8+63L+fF/D/Gjd67CYtaD1mep7wJfV0o9EW1o8F3ggoELiEg6cAewFqM+1RYReVQp1TbVwWqadmJExAxsBmqUUlcmOh4tsV482MQXHtrJfTetZ36OJ9HhaNqM5wuG+dULRzh3fhYrC1OwmE28crgZq9lEaaabLI890SFqmqbNWiIyXyl1KPrrNcD+6M+PAh8Vkb9iNPTrGK3eshbfH1+v4G+bKqlo6aXHHyIn2UG3P8QX3ryI954+J9HhaVNswpLL0Y2yLvpzl4jsw6hfcw3Hk1f3Ac+jk8uTyhcM47CaqWzp4btPHex//O2/eo0Ob5D8VCdfvHxxAiPUEkgBydGfU4DaGMtcBvxHKdUKEL1JtAG4f0oi1DRtInwC2Mfx7V2bpV482MTNf9hMIBThxUPNOrmsaRPg9aMtrC5OY1lBMve8fIyLFmWT7bFTmObCaTMnOjxN07TZ7i4RWQhEgArgtujjjwOXA4eBXuD9iQlveqtq7QWgKN0Vd5ndNR189Z+7UQMm8dR1+AD46j/3UN3m5SMXlpFk123eZotJGb4qIiXAauANIGfA3aB6IGcy3lMz3PPyMZbd8RRv+fkrPLG7ARnwXIc3CMCTu+sTE5w2HXwS+J6IVAHfB26PsUy8Rgeaps0AIlIIXAH8NtGxaIn10qEmbokmlgH+tqkywRFp2sz29l++StkXH+fnzx3GYTFht5h5/9mlpLmsbK1sw2qW0VeiaZqmTSql1NuiJTJWKKWuUkrVRB9XSqmPKKXmKaWWK6U2JzrW6ehgQxefeWAHSsUv//Tk7nriPR2OKH75/BHO/NZ/eeVw8yRFqU03E34bQUSSgIeATyqlOkWOn2QppZSIDPsTFJFbgVsBiouLJzqkU1IgFMFmMQ177FhzN6GIorbdS3tvgFjb+/+cqaconMpE5BkgN8ZTXwIuBj6llHpIRK4D7gEuOYn30tuupk0/PwI+B8Qdoqq33VPfS4eauPm+zfijiWUAi8nUP7tJ07TxCYYjmEzCyqJUgmHFE7vr2XisldXFaSzJT+ad6/S+VNM0TZv5HFYzG8tbecsvXsVuNjE3y01mkp2mLj9pbhs2s3D3S0dHXU+XP8TdLx4l1WVlaX7KFESuJdKEJpdFxIqRWP6zUurh6MMNIpKnlKoTkTygcejrlFJ3A3cDrF27VnfHGIPb/rSFZQUpFKY5CYYjPLilmqrWXlp7AgDMyXDR2OUf9rrFuR6uXa0HoZ7KlFJxk8Ui8geM6fIAfyf2yMYaBtdhLsQoZxPrvfS2q2nTiIhcCTQqpbaIyAXxltPb7qktVmIZYG9dJ0/uruct+jxA08bt8V11WEzC9acXs7IoldxkB/e+Wk67N4BFj1jWNE3TTgFVrb3c8egeAHZUtQOwsbz1hNf3wsEmNh5r5XfvW8eZ8zImIkRtmpqw5LIYQ5TvAfYppX4w4KlHgRuBu6L/H9q9Uxunr/9rD8/ub+TZ/Uaefkmeh711XYOW6fEb3To9Dgu+QJhgRLGuJI1N5W38/LkjLC9MpqM3yC+eP8Jpc9K46ZxS1pWkT/ln0aZcLXA+RrL4IuBQjGWeAr4lImnR3y8ldvkMTdOmn7OBq6MNOx1Asoj8SSl1fYLj0k5CQ6ePXz5/hJvPLaUwLX79O4CXDzXHTCz3OdDQxecf3Mldb1vOwNllmqaN7OqV+XT6QgTCioJUJ/dvrKQwzcUVK/ISHZqmaZqmnbQXDzbx8b9uo703OKHr9QbD3HDPG9x63lw+elEZLpuuw3wqmsh/1bOBG4BdIrI9+tgXMZLKD4jIBzCKqV83ge8569S2e7n31fJBj1W2eoct57KZMQvMy0piZ3U7KwpT2FHdAcA/ttXw8Lbq/p3GG8da+cm7V0967Nq0cAvwYxGxAD6i0+JFZC1wm1LqZqVUq4j8H7Ap+po7+5r7aZo2vSmlbid6Myg6cvmzOrE8sbyBMOUtPWR77GQk2eMud6ihi8YuP2eXZZ7we7X1BPj7lip++fwR2nqD/GtHLb+8/jTWl8a+GfzyoWY+cN+muIllgF8+f4TvvX0FSoHOLWva2B1o6GJNcSqBUITm7gBvP60Qu0WXmJnpRKQc6ALCQEgptVZEvgdcBQSAI8D7lVLtY3ntFIWtaZo2YZRS/OqFo3zvqf1EJmk+Yyii+MXzRzjc2M2vbzhND3A4BU1Yclkp9TIQ7y/k4ol6n9ku2WnFajIRCEdwWs14g2HCSmEWCA/YEYhAboqD1p4AEQU7o4llgNbeAKuLU9lW2W783hOgvLlHd5CfBaLb6WkxHt8M3Dzg998Bv5vC0DRN06Y1pRSbK1r57N93UtFidNG+eFE2n9uwiIW5g4+fDZ0+3vf7TdR3+rjnxrVcsDA77noPNXSxrbKd5h4/rd0BWnsDtPYEaOrys6+uc9BJfktPgPf85nUuWZzDvCw3ESDJbsFlM1Pd5uWlQ00jJpb7fOfJA/z8ucM89KGzCCtFtsdxQt+Jps0k9R0+rvzpy6wqSmF1cRpXr8znqT31nDM/k8wkO/5QhD01HRxq7CbbY6c3EOaFg01sr2pnXpYbQfqnBi/K9fD3287EadIXx6eIC5VSA7tO/Qe4XSkVEpHvYNy0/fwYX6tpmjaj3P7wLv66qWpK3uvpvQ3cdO8mvnj5Yp1/OsXo8egzzNaKNoKRCFaz4LCaWJznIRRRNHb6qO88XmM5GI5QmObijWOtrJ2TxuaKtv7n5mW5aejwDVrv/Rur+OpVS6bsc2iapmmTSyn1PHHqpWvj8/yBRn73Sjld3kB/Yhngv/sbee5AI29bU8jHL57PoztqOdrUzQsHm2juNnogfPjPW3n+fy8YlsBt7w3wnScP8NdNlXG7bccSiiie3FPfX+pqoNPjjGgeqrnbT3M3XPj953HbLXzr2uVcuCh+AlzTTgWf/Ns2mrv9PLOvkaPNPTy+q449tZ0xt6Wh+nqa9DlvQRYeh3Uyw9USSCn19IBfXwfenqhYNE3TJlNTl3/KEst9njvQxKtHWvjEJfO56exS3Wj6FKGTyzNM30VomstGY5eftujo46HMJhNvHDNGV2yuaGNFYQp7azqwWUyEI4raIcnls3RxdU2bUSIRxZ7aTpYVJOtpRZo2iXr8Ib7yz91UtXopTncOez6i4O9bqvn7lmoW53nYN6QHQm8gzP66rkHJ5af21HP7w7uGJazGo77TN+yx/fVdpLttY15vpy9Epy/E1/61RyeXtVPan9+oGNTo+mhTT//PoyWWh3LbzPq8+dSigKdFRAG/jja8Hegm4G8n+FpN07RpLcVppSjdSVWMUquTyR+K8N0nD/Dq4Rb+cNN6THom0IxnSnQA2vicOdc4mY238dnMQn6qg6FNq3dWd7CsMIVkl43yAaOu+pRmuSc8Vk3TJkddh5frfv0aV/3sZfbUdiY6HE07pX37iX39J9wt3fGTtskOC00DklcD3fnYXt7xy1d5ak89AI/vqjupxLLZJFS1eslNHlzzucMbpDB1eAJ8NB6HHmugnZo2lbfy/IFGWroDBEIRimLcIBqr8xZk8d23reDZz14wYqkbbcY5Rym1Bngz8BEROa/vCRH5EhAC/jze1w4kIreKyGYR2dzU1DTB4Wuapp04m8XEN9+yPGHv//LhZr7z5H4ik1XsWZsy+mpihuj0BWns9LG/3hgR1esPDVvGbTOT6rYRCEWGJZ9NAu29xjrsFsEfOr7xnr8gi8K0Ez/Z1jRt6jR1+Xnvb97gaHMPaS4rS/KSEx2Spp2yegMhyrKSxrRsWXYSW6OziYrSneSlODnW1ENplpuWbj+bKtpQLx7l7hePkuw88dOvVUWp1LZ7CYSHH+sBdtZ0MDfTzdHmnhivHs5uMXHLuXNPOB5Nm85KM938zz0b2Vt34jdiM5Ps3HROCR88bx5mPbLqlKOUqon+v1FEHgHWAy+KyPuAK4GLlYpdvCjea2MsdzdwN8DatWt1BmUGaO7209YTIN1tG9a8t7HTx72vltPpCzInw0VxupuiNBeP76rDbjHxoQvmYTHrMXzazHHegiyW5CWf1LHyZPz6xaPMy07iurVFCXl/bWLo5PIM8dqRFj74xy39v3uD4UEXj0vzk6lp91LT5uW0OWm8frR10OtPm3O8nlxeinPQ6OUvX7F43N2uDzV08ZuXjlKQ6uLqVfnMSXfpqQyaNsmUUnz6ge392/21qwv1dqdpk8hls/CW1QXc+dheIgrS3TZ6AsOnDeanOPoTy2aT0O0LsbHVOA43dR8fzRwIRdhZ04HVLMxJd1HROnwmUSzrS9LZWW2sf2d1OxFl1FfeXx/7IiBpHCORFXDZ0twxL69pM0WHN8hvXjpKb2D4gIyxWFeSxntOL+by5XnjPk/WZgYRcQMmpVRX9OdLgTtFZAPwOeB8pVTMHXW8105V7NrkemJ3PV/5x24AVhYaTUDBGOTx7111/cstzU/mUEM3wUikv3/CYzvr+O2NaylKd0153Jp2ojYsy8ViEuxW07jLRU2Erz+6B4fVzNUr86f8vbWJoZPLM8SFC7N58LYzue7XrxFRxiiKgaOSun0hwmHFkjwPB4dcbK4qTGVHdUf/71kee39yeW1JGj/+7yF+9p41w97zYH0n87I9MUdp/G1TFa8cbqam3ccPnzlIYZqTc+dn8e23Jm5Khaad6h7YXMVLh443JH/vGcUJjEbTZoc9tZ1kJdlp6PLjtMVOMCU5LBA9zK4uSh3URLeP2STsi44ICYYVCFhMEIrEft+SDBc2i4kuX4iN5a3Dnu/rqxDLzuoOTitOZUucvgwDWU1CMBzRzVS0U4ZSip5AmBSnlbesKmBupptv/HsfXb7Rk8wisKY4jQ+eN5fzFmTp7eLUlwM8Eu1dYQH+opR6UkQOA3bgP9HnXldK3SYi+cBvlVKXx3ttIj6ENnY9/hD76jqxmE3kpzqwm834w2Gykuz9PUyC4Qh/fr2i/zU7qjsGXUsP5LKZByWWAQ40dHHh95/n+f+9gMI0nWDWZoZsj52dNcbf+cIcD7Ud3jEdNydKTyDMx+/fhlKKa1YVxFxGKaV7DU1jOrk8Q9gsJtaWpHPlinwe3VHL0PlUFa29LMr1EAwruvzh/sfnZbk51NhFYMDVa6c3SHG6k1SXja0VbVw0pInP4cZutle18+iOGkrSXXzuzYtJsht/Kkop/rm9lt++fIwleR4cVjNHmnqobvPy981VvGd9EcsLUyfra9C0WSkQivCtx/dx76vl/Y+dNS+DeWOcrq9p2onpDYSME10US/KSSXVZcdksNHX7sYj0jzzuO9FNd1vZWhl7tIcALruZDq9xol7R0svq4lR2V7cTjJFgtllMHGzoHjVGAeZkuKhp9xpJ6yiTSVhfmk5rj5/Kll4C4dgzsXsCYf66sYpbztOlMU6WiJQDXUAYCCml1orI34CF0UVSgXal1KqxvHYKQj7l3PPyMZxWM4/uqKE0M4lXDjdjNQt5KQ6U8tEdo6wcQHG6C7vFRIrTyoWLslmcl8ym8lbOnZ81xZ9Am0pKqaPAyhiPl8VZvha4fKTXatNLc7efG3+3kU5fkPUlGWwsb4nZuOzmc0oJK4UvGObZ/Y00dMbuoTBUIBRhXlYShxsHH69DEUVTl18nl7UZIxg+fjJ6oKGLojQni3I9AGwubxuWfzoRAhSnO6lp98YdXHEozrlvW0+Ac7/7HDecOYePXzQ/7oAPLXF0cnmGyUsxus33+kOUZbs53Hh89HKK08rG8laK0pxUtXlZX5I+aLRTcbqL7GQ7m6PTHCpbvaQ4rfzvZYv6lylv7uELD+1kc0UbczPdHGroZndtJ2fNy+S0kjR+/J9D1HV6cdvMuOwW9ta1cXppOntrO8hPdfL1f+3lr7eeoetMadoECYUjfOC+TYNGLANcf8acBEWkabPHp/+2g5Zo4z2XzTKoFp1JYGVRCntrOglFT8jnZ3vijijOTXFQ3Tb4gjaiFEUZbrp9IRqHNAM82NA94sjmPutK0tlb10m628bi3GQ6vEGsFhNbK9oIRZujnF6ajjcYpssX4liMWsxVbWMrz6GNyYVKqf4dtlLqnX0/i8j/o3+M++iv1cavyxfkoS3V1HV4h5WIG0ll9EaRx26hpSfAjqp2vjVgNl4gFKGm3dt/M0ePnNJmGqUU/lCEcERhs5ho7vbT0Olna0Ub++s7KUh1UZTuxGwSnFYT/pCi2x8iN8VBVpKd/FQn6W5boj/GuGypaOWzf9/Zf9yraq2Ou+xvXz42rnVnJdkpznDR3hvgSFPsHge3P7yL2y9fzPkL9E0qbfp67UgLv3j+cH9vrz5VbV6qouetpZkuUl02tle2n1SSeX1pOm8cayXJbqEk04XbZiEQjnCwvouegDFA8q1rho9abun209oToNsf4pfPH+G5/Y3cd9N6cpIdJxGNNtF0cnmGsUen53X6QpRkHL8TurwghYhSWExCKBLhtDlpmExGvbi+aTqbK9r6T577XL0yn4XRO1IvHGzis3/f0d/tXgF1HT6cVjPP7m/k7hePMj8niU5vCJvFhDl6Yt23g8hJdvDioWZu+9MWfvM/a/WJt6ZNgCd21w9LLGcm2XnTkpwERaRps0NHb5Bn9jUARumInOTByeGIgh1VHThtZtp6AyzMTaKh0xd3ffkpzkGvX5jj4VBDN72BMBluG6WZ7kGJ3znpLqxm4XBTDwWpTkBR026sX4A1c1Ixm4S6di/d/hDd/hBl2REsZqGmrbc/sQyDS2gUpDrJS3EMKt1R1xE/bm1iiHFSdB1wUaJjmclC4QgWs4nHdtbyy+ePcNdbV7C8MGXQMseae/AGw3HWMJwlOsq/vTfIquJULl2Sw/kLsvAFIzy8tZrK1l5eOtTMlug2k5vsYGl+Mt5gmM0VbczPTqKtJ0BatPGXSaCqtRer2cSBhi6W5afwyUvmc/FifdzWEuNzD+7g4a01g44LI3FZTQQjatBsGKfVzJo5qdgtZpYVpHDe/EwsZhOlmW5SnNbJCv2EPbilms89uIMxfuRxWZSbRHWbr3+fEM/++i5uuncTywpS+OF1K5mrZxxq05DHYWHjsVb8I4xmONbcC/SSm+JgTrqLQ43dtEYHX4zGaTVRlp2EPxTpPx/t9ofYXXN8wEZuigOrxUR7b5A01+CbWMFwhEt+8AJtvcH+x/bXd3HFT17mjx9Yz2Ld3H7a0MnlGebDF8yjsqWHug4fXb4QDosJl82C02amvTfA2WUZPH+gmfoOP4XREcxg1IAcan1pOudFp/t9+4l9/PqFo4Oez/HYyXDbaOjy0dMTYlVRav9IaG8wzMDGyd3+UP/dpmf2NfKZB3bwyUsWUJyhpwJp2slYlOvBZTPTGzh+oXzmvAysenaApk2qFw42saoolbBSeAPhuBeR3kCYZfnJOK1mXjwUe9BpssPCjurjry9Kd3K0ubv/wr2lJ8DCXA8ZbhsK8AfD7K41TrqX5idjNQs7qjtYV2I0512U52FLRfuw9/EHI2yuMGYU9SWih6pp91LT7mVVUSpHm7vp9IZ4Zl8DN9+3mdsvX6TL7ZwcBTwtIgr4tVLq7gHPnQs0KKUOncBrNYxaqb964QiL85IRhP31XVx/zxts/+qbqG7rJRyBfXWdXLw4m4qWXnbVjDRI/DiH1cym8lZWFKaysjCFHz1ziM8/tJMuX4il+cnDGhvVd/qoj95IKkp3ImJMgd9TG7vB5q6aDm770xZe/vxFepSVNqUCoQiPbKvmgc3xR+wOleK04LZZqB1y09EbDPPK4RYAnt3fyE/+a+zKjFk8qWQl2TnW3ENhmpPfv3/9xH2IE1DT7uWuJ/ZPSmIZwBuI4LCa6B6lcobZZDTv9dgtHGnq0cllbVpaVpDC204r5C9vVI66bH2Hj/oOHxluGwtzPBxoMEY7p7ttZHvshCKK+g4v3f4wbpuZkkw3LT0BdtXEPj4OXG9eioOkNAueAU2pq1p7+dqjewYllvs0d/t5929e5/5bztAJ5mlCJ5dnGIfVzA+uW8VH79/KG8daKctyk+qycbihm7CKkOK04nFY6PWHaB+4EUYHEfdt5DaziY3HWqnv8PHrF48Maz7ksJjwhyJsq2pnfWk6G4+1Dqo9leG2sXHIybZZhEW5SdgsZh7eVsN/9jXwr4+eQ0mme9K+D0071c3P8fDkJ87jr5sqeXpvA4cbu/Wo5VF4A2FMJrBbdC0u7cQ9tac+ZmO+WPbXd/X3JohlcV7yoNHDeSnOYTUfO33BQaM4+gxMWG0qb2N9aRqROINLQtEnxnI9vb2qnSS7hXPKMun0Bals7eHvm6v4wpsXj+HVWhznKKVqRCQboxHYfqXUi9Hn3g3cf4KvBUBEbgVuBSgunl0NXXsDId5592sEQ4q7XzxKRCnsFhO+YJitlW10ekMUpTt55XALgVCEiFJkJtlpHi37A/11mHfVdAy7idTaE2BdSRoiQlOXf9DsgtOj03urGF6/dah0t40uX1Anl7VJ85+9Dfxjew1pLiuXL8+jodPH9586SE376H+fA7ls5nE1sowo2Dageeyhxm4+/+BO3ntGMUeaugmGFMsKUijNdPPK4WYuXpxNOKK449E9vHVNAafNSY+53teOtLC5vJUPX1gWs7l8PEopvvjwrjFt+yeqorWXtSVpNHePPHLz4kXZ/Or60zCNI35Nm2qRiOLwGHp8DNTSE6ClJ0BppptUp5WdNR2DRjK7bGZ6AuG4N11jqevw4bab+dbj+1BAly/E8weaRtyW23uD3P3iUX74zlXjil+bHDq5PAOZTMLXrl7KjqoO0qKjnFp7jY15U3kbbpuZ1cWpdPpCdEV3FFZTX7Mh26CN3Gk1x6y1mOy0sidaW7KmzTts5KTTZqbE4aKytbf/rnDfqGarWTCJsUN47WiLTi5r2kkqznDxuQ2L+N/LFnKwobu/lI02WCgc4VcvHOHuF48Siihuf/Mi3rW+eNRR3pGI0if+2jA3nVPC1sq2MZWMKEh1DqtVl+2xMyfDRY8/zKbywbVfwzGGU+2u6WTtnLRRE9obj7WRlWSP+Zwv2hlwa0Ubc9Jd/Q0H4/EFw1S39VLeYiyX6pxZ9TSnG6VUTfT/jSLyCLAeeFFELMBbgdPG+9ohy9wN3A2wdu3aSRqTNz25bBbueusKNpe3cs78LG7942Zq2734QxE2l7eR7bFz3oIsvn71UrZWtrG1sh2ziXElmAIxpgQfaerhSFMPTqtp2LF3rKU3rliRx1euWEJuik4sa5MnHInw7511APzp9dFHIMZT1+FndZHzpGL52+Yq/ra5CjDGN126NIdrVhXw4T9vJTfZQVgZze4e2VbDmuI0Nh5r5coVefy/61Zyx6N7eHJ3Pc3dfiLKuO79yIXH+yseauiiKN2Fw2omEIpQ1+HFYjZFy0cZDXbXzknjhYNNJ/UZRqPGsAd+em8D33x8H1+5csmkxqJpJ+OfO2oG9ekaj1h9PIBBeaPxSHfb+N0r5eN6zfMHGnnlcDNnl2We0HtqE0cnl2eobI+D+285g0t/9EL/xWSfnkAYf0gN6jJvNpnwOCz9ZTL6HGjoojjdyYqCFNp6A4OeX5iTxK6aTmravawsTGFvXWf/FN6+upFr56RxuLGLdu/x7tsLcjz9CewleoqCpk0YEdGJ5TgqWnr45N+2Dxo985V/7uFXLxzl1vPm8s51RTFH4mwqb+UzD+xgXpY74dM4tenltDnp/OK9a7j2F6+OuNzCHM+gepNr56RxtKmbxi7/sCZ9o6lo7cVqlkF1LofqK40RS1+9vFBEUdnWy+qiVA42HG+SMtTq4tRB69pd29FfO1YbHxFxAyalVFf050uBO6NPXwLsV0rFnJs+ymu1qGUFKSwrSCEUjnD1ynx++9IxrGbFj/97iIU5Hl461Mzhpm7OiV5guqwWRMaWBBqNNxihvTeIWeC0knSau/3UtMUfEbq6OBWzCNnJdn543SpsFl3KSptcFy/OYW6mm6Nxkj3jEVYKp9WMw2qKOR19rJKdFhZke3hqTwNP7zV6GNQP6E3QGwjz8mGjnNRjO+uwmk39Sek+971azuXLc6nv8HH3i0d57kATi/OSSXdb2VLR1n8dfO3qAu64agmpLhvXringVy8ciXvsOxkmMZr5DWzwOxKr2YRSSvci0qatipbp0dTZYTGRmWQfNrNvNG29QT5w3ya2fuVNuGw6vZlI+tufwYozXGz9ypt40w9eHDblqTcQGvT7zup28lOddPkGT3kwizE9t2+67txMNy09xgVxaaYbs0kIRxR1nT5KMtzUtntxWM3My06isdNHS0+A7GQHHd5uFJDitGIzGwdPl83MiiFNVjRN0yaSUooHt1TztUf3xLyIqGn3cseje/jps4e4bm0R60rSyUiy0ekN8cTuOu7fWElEQWVrL3e/eISbzi7FoutZa1GrilKHzdwZyuOw8MaxVlYWpmC3mtl4bPTRH12+2BfrTV1+1pemsfFY/NHLLd3GNP1OX4gDQ0ZLN3R4+5PTSsG2qnbyUhwxt41sj31Ykro3EOYjf9nKB8+fx6rCVFJc069J0zSWAzwSTSBYgL8opZ6MPvcuhpTEEJF84LdKqctHea02hMVs4pOXLOBtawqxW01sq2ynwxvkp88e4gNnl1LR2oM/FKajN4BJhPBJZJfNAisKU+gJhDnc2M2CHM+o23i2x04orGju9XPBwiydWNamRH2Hb8SGXOPR0OHDGwyT6rKQm+wYlBAej/nZHrZWGseZ0TbDQDgyLLEM0Njl59IfvkiK09pfhmJfjMTuI9tqmJPh4l3riqlt942pPNSJiCgoSneNuWzWva8e4+yyDM6N9jnStOmmxx8afaFJ5LIajUHDCo40ja88Rx9fMMJX/7mHT14yn8I0o+eXvqkz9XRyeYZz2SzkpzqGJZdTXVYy3DYykmy0dAdIdlo51Dh8Y11VnDaoDuTR5h7OnpdBbyDMjqp2XFYTS/JTUMDGY62ku6z4AiHaewPUd/jwRU9iluYnYzEJFS091LT7WJqfjNtuocMbJNWlR0Bpmjbx2nsDfPGRXTy+q37UZZu7A/zi+SPAkbjLfOvx/dz3agXnLcjk/P/P3nsHRnbV59+fc+/0PqPepe29r9YNbJqxTTEEMCX0loQfKZCEmpBCCoQQyks1vdshoRoHsAH3srv29r5a9S5N7+28f9zRrEYa1ZW23s8/q7mae+eOdubec77n+T7PmipetKF2QT5/OlcfZ0aic7b2TXxGDvWVhodVOkw4TAaEollFBWJp/AUF2NgsiubjAxFWVds5O1JefXZuLMa5sRjtrd5pv4tn8mxqcE3xbi4/xa73WGipsBFOZDgzEi1aXD3RMc4THeO8YF0133jr7hnPU6cUKeU5YOsMv3trmW0DwB1z7atTSiieIZnJ8uNn+hiNpPjHl2/kxRtr+cZjnXz7re3cu7+X4wMRgvHMvJPsZ2NtrZNjgxFUIVAVMc3+phwjkRSjkRS7Wr286frWCz4HHZ350OSz8a237eYv7zlYtvi6EIYL96jBUAqHWWV3q5dDfaGy1jEzYVIF8XR2SUL1mnw2zo3Orcj+7INn+NzvztBWYV90W/5c1DjNBOLzv7ZU2M38529O8f7/PsSqKge7W7288foWBoNJHjs7Rj4veftNbdhnyW3Q0Vkunj43znef7L6k55DK5qlwmHnkzBhuq5FtTR4O9gYXfJz/eaaPnzzbx1+9cA1vuaGVN379ab74hh00V9iW/qR1yqJfxa4CdjSXtsgaVcHR/jCpbJ7xWBqzQZCXErtJJZPLky6021Y5zCWrQy6rgUq7mXQ2j0EVJLN5kllKis/+eAYBKEIUC8twPnBoIvxvJJJCCPTCjI6OzpITSmS4Z28PX3+sk9EF2g7MRX8wwY/29vKjvb3cvKaK77xdt8q4lvnwT44AmhKxnMXFiko7I5EUWxrcHO4PYVQFFXYTDrOBbn+8JOzHbFBorbBR5TSTzOaKheapRFNZsjkTLquBcKJUTWIxKKysdmBQBKNlgoRWVTvoHittb5xQTa6rdeKyGMlLSSKTw6gqxbFDtdOM06Kl2U/w6NkxMrn8nJ7lOjoXE7fNiBsjr9nVxNH+UFGV9I6b2nj87Bj3Hxmcl096OYyqoKXCRjYnqXFZUIQgL/Nsa/RwfCBEMidZV+vEbFAwGxS6/XEiySwNHisWo8KRSYs6EnjfC9eUWObo6Cw3a2qc/PQ9N/C8/3xo0d+DqURTOYQQZbMCZmNbs2fWLpyFkM7m2dPmY393YM7zMBuUJbEGmYl6j5XeQLzY3TsX/cFEUQQ2Gknx5LlxPv/7syXPWVnt4I7Ndctyvjo6s/Hv/3dyyToeFktOUrSZCSUyHOwNsrragcdm5HBfkFR2/teevIT/euA0n33wNHkJb/32Xr725l2srHIs1+nrTEIvLl8F/NktK/nR3h5cVk2tnMnJEh+oVFayoc7OQCiBSVXI5SV5mae5wl7S2remxsn+rkDxhryu1lloQUoVJ5x2k8raWifZSX6QdpPK+joXgXgaIWVxEi4l/PzgAG+8ruUi/SV0dHQuF7K5PLFUjsFwgnW1i/NeT2fzfP2xc/T64+xs8TEYTHCoL8QTHWPLpkiZzGNnxwjFM7o1wDXKqaEwitDC+obCSRxmlWiq9HOnKoIzI1H2tPlo8lqJp3MMhVPA9EJ0Kpuna1wLz2tvm646nozbaizr57qqxjFFlTydyJT2RpNB8xrvHo/PGEA2EkkRSWbZVO/iaGGxOJ3Nc3o4wsZ63d5K5/KjxmWhxnU+IC+VzbGhzsWGOheJdI7xKaplr81Y1jvWZzNiMii0VNgZiSSLHQNdZTwo2yrtZZXLZ0airKyyY1QEmbzEYlT46B3ruX5lxYW+TR2dBWMxqnzgtrW8795DS3bMk0Nh1tU6S0LhZ2N709IVlkHL+vFYjfMq5ubykt2tXgaDSfqCC/NunQ8HeoNUO83sbPHOywZrPrzv3oP8x69P8um7trGzZfbxgY7OUiCl5OHTo/P2Dl9OdjR7eHZSZg5Q7Ljf0ujm8JTOwPkwcak4NxrjBZ9+mL+5dQ1/evNK3fpwmdGLy1cBHpuJD96+jjq3ha88dI5DfdNvdG6rkQOT2gvW1033jDszXGqbMTGA3tXiBbTB9qYGN093+ql0mIoq5dXVzqLvVMdojFvWVNFamWNvp59/+sUx6twWXrC+Zgnfsc5iEUJsA74CWIAs8B4p5d4yz8sBRwoPe6SUL79oJ6lzRRNPZ/naI53c/cj5IJWXbqnjLTe0srXRMy/vyXOjUX52oJ/jg2EePDECwI/2TvfhW04UAR++fZ1eWL6G+d9n+0u6glor7BwdCNPgsdLgsZDJyeJ91aAqJDLTC1ozEU1O97erdpqpcVmIprKYDAqZvCwGeE54Kx/tD3PDygoO9gSIF0KMGr1WHGYDJ4cihBPTi2dDwSTXr/Dx5LnZJ8GJTI6jA2HaKm0MBjXbq+8/1c2/vGKz3oWkc1kxHk1R4TAD8B+/PklvIMGJwTAGRRBJZlEVUfRKd1kMvGJ7A8/2BEhl8yULkxaDgtVkoD+YKCwKzU7nWKxkAWYyHaMxVEVwy5oqPvf67bpiWeeS8optDShC8OWHOuZl5TIX62qc7J0hSLYcy3HPCCUy+OxG/LHZAwYzOcm+rgDtrT7Cqcy0DqClYCKbaKlIZfN0++OcHo7oxWWdi8I3H+/i4/cdx6AIVlbZGQgmZxQgLCezhVQDswbnLoT//O1p7n7kHG2Vdhq9Nuo9Flor7fzxHl0EuZToxeWrhFVVDr76yDnKeZarQlv9qXSYii26jim+TjVOc9FfazJOi4H+4Hn1xsSgfCyaJpQIsKnBRef4+daj9jYfD50exagKrl/hI5rK8anfnGJni1f3Xr48+A/gn6SU/yeEuKPw+JYyz0tIKbddzBPTubLZ1+Xnm4918tiZsWnKyfsOD3Lf4UFMqkKV08ymBhcff8Umqp2Wkucd7gvylYc7+L+jQ0ipFdsEMznGLh81LjOff9129qzQVWfXMg8Uku0nOD4Ypr3Vy96uwLScg/FoqsQCYy5ODUeLVhoAQmhhR0cKjweCcdbWOMjLPGeGY+xq8bK/O8DuVi9PnhtHFPbx2oz0FQbebquRtoJNx2QiqSxPnvOXVYaUo3Mszp42H0f6gty7r5fOsRj3vPv6eb83HZ3lIhTP8NVHOthY7+YlW+p4smOc/mCCRDrHG/c0c9/hwZJC2jtuamNHs4dvP9GF3WRgc4ObYDxDHolJFViNKicGF1Z4OzoQps5twWZSS2xkAPJS8qqdjXphWeeSk8zk+cFTPfT4pyvwF0p7m4+OMrk9s7Ec65G9gYR2D47Nr8i9t8tPe6uP44MhXFYjUkoGQ0tnpTa8yJDDmZASPv+7M9y4slL3iNVZdm7bVMvR/iBHB8KcGY7iMKvsafOV2KEuN3MFWAOMx9LsbPbwzDzGr3MRTmY51BcqyUixGFRetbPxgo+to6EXl68Cnun28/qvPUVewsZ6Z7F1VxWah82OFm1FaHerF6VQfc7kJG2VNjoL3ox5CRajQjJT6rkjAIvRwESLr9WkFn+XyUkCsTShglJqXa2TZwoK5u3N3qJKqtlnY8+/PciNq6r4yht36qnZlxYJTHgUuIGBS3guOpcAKSW5vFyytqB0Ns9nHzzNlx/umFcS+IT33OnhKN9/5x58NhMPnRrhB0/38NjZsZLnj0RSrKt1LonqZr7csraKT79ma1EVp3Ntkkjnive2CfJSu6eW4+RQZEGD8lxecnQgxK4WLwd7A6yucZYUuVJZyanhKDubtc6h/d0BdrWcV3dMnMZkBVcokWFvl5/tTW4O9Iaoc5tp9Gr+sXm5sO/80f4QWxo9PNXpZ39XgGe6/exs8c17fx2dpSKSzPCDp3vw2ow8f101H7htXfF3iXQWs0Hh2ECYeDrL+jonu1t9jEZTvGZnIw1eK3/748OcGIxgMSpEktkSb8k9bT7W1ToxqApSQjiZwVDILZmNaFJ73V0tXhRFcLZgjfORO9bT5NOLQjqXHqtJ5fOv385LPv/IgmzEWnxW7GYjdrOKEIIzwxEGg4l5d+UUKad2WgLGommMqiAzw824tcLGcDhJIpNHACORJNFUjmgqh92ksrPFW5yrXggTFjhLzXA4yRMdYzRXNC/5sXV0JtPgsfKvr9zMnn/9HaB5qz/d6WdDnZMTQ5E553QXisOkcqRvfpYcz/QE2dzgJpfPc3yBC8Jz8dc/PsSJwTB/99INS3rcaxW9uHwVEE6eT+LtHI3hsZmKg+ddzedvopNbDkYiKfa0+YrFZZNBIRmdbuZuNxsIJc4PKFKT2iWMqmBkUhuh2aBgMSjE0jnOTlrhrnSY6PHH2d/lZyiUpMlnLQaw6Fx0/gr4jRDiPwEFuGGG51mEEPvRrDM+IaX82cU5PZ2lpns8xu9PjnDfoQHOjESJFlTFrZV21tU6WVvjYm2tk/V1Tpp9tjm/m/m8JJ7J0TMe59hAiLsfOVf0xVoInWMxXvb/PUYyk5t14hOMZ1hd45hm27Mc/MnNK/jgi9eh6BYA1zxD4SQv3VLHb48NM1RQJ83Vuudf4OR7V6uPgUACn83E6SkLKO1tXlLZPCbD+c+ixaiwp81HIpMjlspOU02Cpnw63B9mZ7OHw/2hRam0fHYT/liafd0BvDYjsXRuyYMzdXTmi8Ns4PZNtbRUTG9Bf/76Gtw2E+dGY+zr8vNExzg+u4n33LKSeo+VLz/UQW8gTpXTzGAoURwbuywG2irtPNPtZ3KOUYXdRDo3d7DRqmoHt2+qpTeQ4ImOMb725p3saPbqY1udy4pat4VGr42VVSo5KYkmM5wdiZZdJK1xmvEWrv3d/vMFH1URZb3KZ6LRY8VtMzIUWnqvY9AWVmcqLE/YNa6vc2IzGZBS0hdIYDepxNI5YukcmVwes0GUBIS1+Kw4LUbsZgMnh8KE5mGjsabGwbHBCE6zSiQ1e/F+Quw1H3x2k66i1Llo2EwGLCa1pOP0+GAEq1GhyWfDazPR7Y8ztEThoJOxmFQiZSziZuJIf4h6t2XuJy6C7z7ZrReXlwi9uHwVMBpO4bOZ8MfTxDN5HPk825u8PNsTQEpYUWXndJnCTHrSiHowlKDKaS6ZQO5q9bK/K0BrhY1KhxmfzUQyk2dFlZ1zozE21rs5OMnH+VBfqGRFeCI8JZXVbrrhZJbnfuoPfOylG3j7TW3L9NfQEUI8CNSW+dVHgRcA75NS/q8Q4i7gG8ALyzy3RUrZL4RYAfxeCHFEStlR5rXeDbwboLlZX2W/HJBScno4yq+PDvHrY0OcKAQ17G71Ep50Ez83GuPcaIz7jwwVt21v9vDnz1/FzWuqUYQWoPKHUyM8cHyYZCbHyaHIggYCczGfYtxQOEm9x7NkrzkT77llJX/74rV6cUAH0IK7/vnOTTjMBr7+aCf3/sl1fPXhczM+36BAx+j0+6wioM5jZTyamtYZlMnlp4UNGRTY2aIpoK0mFYMAm1FhTa2Lx86OF5/X7LOxs9lLMpujZzxGJJVDoE1ijQoIIWjwWLGbDfMOYJpgwiszl5esqnawvs7FbZv0FHudS4MQomxhOZLM8Pc/O0qj18bqGie3baplfZ2LYDzDnhVevv5IJ78+OjRNcakqgng6h6IImnx2OsfOL9LYzSr1VguDoeSMNjc7mj2cGIyU5Jh8+CdH2FTv5l3PXcH6usUF2OroLDVfebiD44PhYjHWZzfSVmUvhlZOYFQEHrupbJfYfAL0GjwWqp0Wuv0x+kMJ+oIJdrV46fEvbYHZZTXMOG5UBRwptLpP7gLa1uQpmase7gtR77HgNBvJSUkkmaHbnwC0c93W6OFgX5DZWFfrJJjIUuuyMBROUu00U+kwYTMZEIKi4nt1jZN0Nk/3eGzeBfqxaJr/+PVJ3nZjG/Uea3G7lHJR49PF7qdzbXCkL1RWPJDI5Iu1I0Voc8hsTjIaTRWt2C6UsWiaFZV2zo1NF0rMRG6Z5NQSyQPHh3nRBj0j7EJZsuKyEOKbwEuBESnlpsK2fwTeBYwWnvYRKeX9S/WaOhp2s4Eatxl/PM2GOhfHB8OMRPy4rAb2dvlnbANyW41sbnBzpD9EXkJykip5e7OH/QWF1kRitsmgsL3Jg1cx0uSzYlAFjV5rYRVYxW01ks9L6j0WrEaVkUiK9lYvp4ZLBytVTr3dfDmRUpYrFgMghPgu8JeFhz8Gvj7DMfoL/54TQjwEbAemFZellHcDdwPs2rXrYlvjXtMc7gvyL786wU2rKrEYFYbDKc6ORDk9HGFwygpzpcNUVuU4lQM9Qd7+7f0oQlvNjk7xTp5YcLra+PPnr+L9L1qjD8B1pvHXt67lpVvq2VDv4rOv20b7vz5YDNybKBa3VdqxmdRpRdy2SjvBeJr+QIIqh5mVVeaS5xiV6TYVAlEMyDWpCnmpdQoc7Q+yoc5ZbAfs8ceLXppWo8qqKjuRVJYVlXb6g8niMUArhnWNxfHH56esnizcDyeyhYVqfYKqc3nhtBj57Ou2T9ueyuZ4+pyfNbXOkq4Yk0Fha6ObrvE4oUSGXn8Cl6V0GtQzqci0tsZJldNEIpMnlc0VrTIMqiiGHt2wsoJNDW6GQkn2rPCxssqxTO9WZzkRQnQBESAHZKWUu4QQPuBeoBXoAu6SUk4bAAkh3gL8XeHhv0gpv3MxzrkcUkq++IezdI/HSWXzPHB8uETl649lUIRga6ObYDyN1WTAqAoGgslF+4RvqHMV7M6CJduzeYnFoJDMzt0JMF+k1LpknWbDtGwPm9lAg8eKqoiS+2w4mcGgUNKhMBBMAuWVmL2BONuaPGTz+aItgNWoIiUIBTLZfIlfK2jdwFOzDgD2TrLJ2trk5uRguEQxPRPfeKyT44Nh/u4l6/nuk9387MAA6Vweh9nA39y6hjdd31p2v5FwklQ2jz+W5pHTo3zz8U5q3VZ++p4bsBjVsvvoXNvcs69nzufk5fnud7tJXVK7woVed5bBiQaAzQ1u3v29/bzrOSv44G3r9BDrC2AplcvfBr4AfHfK9s9IKf9zCV9Hp0Aml+fxs2Pcs6+HE4Oa32N20rcunNAmwM0VNoLxNKuq7QyHU0SSWXa3ennotFbz99lNbKx38UTHOPUeCw0ea9mLRjqb52BvkHxesr3Zg6oIwsnzKby7Wz2cGYmxvs7F3nPj5CTTkoW3Nrq5Y7OugLqEDAA3Aw8BzwfOTH2CEMILxKWUKSFEJXAjWvCfziXiSF+I7z3VxdmRKG2VDlZVO/jSQ2eJJLMlg9dyrKyyE4hl5l1YAu3mPbWwDNC1gNXlpeT0cJR1tQ5ODi2tNYbdpPKp12zVr0k6M6Iqgg31mhLRYlR56iMvIJOV/PWPD/HgiWFqCu32XpuJPW0+8nlJMpsjmcnjtRmLqsjRaIrRaIpGr5U6t4XRSAqrSZnmHZnJS6qdZkYiKUKJTNHHOZuHsyPRstYciUyO7vE4awoD/qkKqR5/nGw+P6etR/E9Tyoi++NpRiMpDvWF2NbkWeyfUUdnWZBS8r/P9vPK7Q2oiqBjNMrdD5/jTde3cHIoXCwCX7fCRyyVY19XACHgDe3N/ODpHmpcZpp8VnrLKCxPDUeocVUi0BaCat0WjKpgb2cAi1Hh7jft4rlrqgAtaFBVBUZVn5BewTxPSjk5+OFDwO+klJ8QQnyo8PiDk3coFKD/AdiF5tjwjBDiF+WK0MvNaCTFv99/gp8c6J/1eWPR9DRV/sqq6Z0Bk6lzW6hzW8jnIRBP0+2Ps6bGgcdmYl+Xv6w368HeIE6LgfV1TvqDybLF14USSWaJkKXJZyWTz5d0A0WSWU4ORTCpWtfOaDTFtkYPo9EUC6lve2zGYqfeUnKoNzSr33O9x4LPZiIvoT+Y4NmeIK/80hMl7zGUyPD3Pz/G0f4w/cEEmxrcfPC2tXz/6R5+8FR32XMOxDPs+PgDPPD+m2mYpITW0Ymns/zi4MKil2Jp7bvhsxlZUeWgL5BgOJJESqh3WxgIJVGEZskTiGWK9+CpOC3aYlA6m0cR8y8aj0ZStFbYGAoliwtXDrOKSVXwL8C+Zyo5KZES7n7kHP3BBP/56q0lOWM682fJistSykeEEK1LdTydufn4fcf57pPdxcdPd/rZ2eKd9ryBYKLoH/Wc1ZWMRlIlE0x/LE06m6fFZ6PXHy+s6JZnc4Ob/d0B9nYFcJgNxCYVoMLJHMF4hic7xnGYVNbUOqcl079sa72+GnRpeRfwOSGEAW3Z/t0AQohdwJ9KKd8JrAe+KoTIo/kyf0JKefxSnfC1wGAowaHeEMlMDpfVgNtqxGYy0DEa5XtPdpeEhE39ToF2k95Q5yqGfJ0Z1gpMlQ4TgfjCCsuzMRZNY1BEySLWxSCaynJuLM7WRvc0xchiWV3t4Ctv2nnVKc2EEE1oi7w1aJPdu6WUn7u0Z3X1YDMZwAQfvG0twXiagVCCrY0eDvQEGAwlWVXtKGYOtLdOvx/3BRLFlsKu8TjtrT72dp3/ft+0qoKhcIpMLk8gniGWPn+PTeck3YVOoqnkpCSUyJRtvTUbFMZjafZ1BVhT4yCVzc94HAAx6R49cY//9dFBvbisc9mRzuXZ1eJFVQS/OTbE++89yL/90WaGw0nu2dvLhjoXb7uxlf/4zSmSmRxuqxEhYH2di3c+p42fHuhnPJpmd6uXgWCCeo8Vu0klmsoihODYQIgKh5mb11SRyUlUAc0VdrY2ummpsBNNZfnWY518+oHTANy8pooXrK/mheurqffowX5XOHcCtxR+/g6aKOODU57zYuABKaUfQAjxAHAb8KOLc4qQzeX5ysMdfOEPZ6dZL82XjtEYLst5BeHWRjcSTbGbk5Jj/eFiR9y2Jg8VDlPZsehUIsksB3pDqIoouTdeKL3+BGtqHOUtH3OSRDqHURGMRlMltjdz0VphYyyaptppXtLx5gQHe4OsqtZsSVZXO3BaDBhVhVgqy/HB8Kzz78ncu78XgMfOjvHLQwP0B2e3KYinc/x4fy9/+YLV11QHkhDi42jf4zwwArxVSjkghPhjtO+yQOtY+DMp5aFLd6YXl+7xGN9/qpsnOsandQDMF388g7+wUCLQFmUGQkncVgOJdI6BYBKnxcC6Ciduqya0CCczJDN5hIAqh7m4GDLVlnUu+gIJsnmJ1aiSzeeJpnJADp/dRIPHgrHQ9Wc2qIQSaSLJLAPBJLPNXC2G84XkXx0epGMkyidftYWt+rh3wVwMz+X3CiHeDOwH/vpSrOZerZQr8ESTGXa3ejEUAhgyuTz5vCSWymFQBdFkBqd5+n/7icEw9R7LjMm3VpPKuhpnSautEJR8Ua3G8y2+0XSubFDwzw728+brWzEZ5p9ar7N0SCkfA3aW2b4feGfh5yeAzRf51K45DvcF+dWRQR4+NTqjQsJsUEq80aeiqUJcHOkPlRSgHWYD17X5eKYnMGPwyWLx2U1LokBZKOlsniP9IbY3ezgwj0nNbNy5rZ5/e+Vm7GWuhVcBWbR77bNCCCeakuoBfYFoaVld4+STr97Ca77yRMl3LzDZD3Iek7hM/vz3u9Jh4tnuAPFMnmqnmT1tPqauxSYyORQBRlUphpOpAloq7ARmWETqDyZp8FjpDyY4PRxFFRQV0eUwq+fvz/F0jhtXVfCtx7t493NX4rOb5nxPOjoXg7MjUQLxNN9+ootN9S6+8Puz/PkLVnPntga+92QX/cEEubxkZbUDVQhetaMBq9GA127koVMjnBwM0+y1sqLShiIEa2ucxNI5JILBUJLhsBZ8nczm+NqjnQDsavHyjce7WFfrxGPTinGT/V0fPj3KsYEQ/72vF4kWnPuBF68t6xmtc1khgd8KISTw1YLlW42UcrDw+yG0BdupNAC9kx73FbZdFHr9cf7yngPzKvTOxZlCZ8xwOMlQWPv8lyNfKDYvhFxeTrOguRDcVgP9s/i++uNp9rT56PHPv7BsN6n0BrRrRiiRYU2No1gIXipyeUnnWBxFaH9voypYWeW4IJX0XIXlCT774Bl6/HHe0N7MzhYtfPT0cISHT43yhj3NV+t4+FNSyr8HEEL8BfAx4E+BTuBmKWVACHE7mr3jnkt3mhcPKSVv+NrT8/7czOuYaOHrQEkY5kQ3wWRWVtnJS0p8ltsq7AsqLk/Uv6aqov2x9Iye7G6rkTU1jrLdexMZQ5M5ORThFV96nL+5dS0v2lDDT57t5w3tzTRX6IvGc7HcV5IvAx9H+9x9HPg08PapT9JDwRZHe6uPHz5d6pVzqrCKu73Zw9mRKFaTSjqbo8JuIpnJcmY4yoZ6N6ANks+NRWn02jg+ENYUWWXw2oy0VthLwktAU35MtOQ7zCqdY6VKqIM9wWmFIJfFqBeWda45BkMJHjg+TI3Lgsdq5Ed7e/jZPFqRUtk8K6vsJX7JBkUrbDktRk4MhMvaYkRTWY5NCnFZSuxmAyyiuOy0GEhmchd0TnkJh3qDrK9zlkzoF8LfvWQ977ip7apVbxQmw4OFnyNCiBNok129uLzE/PzgAP5YqVJ4sq/hfD5hh/u0BZMzw1Hq3VYO92tKqQkPR4dJ5aZVlaRzWihQKpNjY72Lk0MRtjS66RiJsrHBPas9jkGBkch5RVROap1OdpNKrOBJu7LKTqXDjJQwFi39fsfTuYLaOaYXl3UuCwaCCe743KM8Z3Ulvzs5gs2o8uE71vPG61oAWFvrYkWVg1A8zSf+7yS/ff9zGQ0n+fivTvDtt7Wzt9NPNp9HCMFYJEWlw0wyKzCpgr5AnAaPlXAiw+G+IDtbfexp85HO5TEq8JzVFcRSOZ7tCbKt0cO6Wicj4SShZBajIhiOpIq2A8cGwsRTWT5yx3pW1zgv5Z9MZ3ZuKoRYVwMPCCFOTv6llFIWCs+LZqnnuv93ZJAP//RIsahzoURTWfZ1BVhX66QvMPP4KpfPzyhEmon2Nh/75rBwWwihRHZO39eZFk9nYk2Ns2See3o4itWo0uS10rtEAWZQGpDY5LVxaontN2bjJ8/285Nn+7lrVyN/++J1/O7ECJ/89UkeODHM89ZWYzerrK1xsmdFxUU7p+VESjl5FcROQRNXEFFN8BTQeDHP61IihOA9z1vJR3969JK8/tT8H2PBYnW5CSUy7OsK0N7mmzZe3tlS3jJOSvjUb07xqd+cAuCXhwa4bVMtr9jWwOZG97Kf85XKshaXpZTDEz8LIb4G3DfD8/RQsEVwx+Y67t3Xy5Pnxqf97mBPkA31LrrHYqyqdnJsIKwVd7I5zEbBDSt8PHHOj9Ni4HBfiJYK64wr3/F0jqMDpa1BDV5ryZczmsqxp81dcjPPSa1dazLNPn3FR+fqZzya4tfHhjgxGObcaIxnugNFleFCURVBe6umMsjk8pwZjs6rsGozqkSSi2t3mo3F1mTX1Wqp2UvRZmhbRDCJEPDvr9zM69qvnQXMglXVduDpS3wqVx37uvx86Q9np2332Az0B7Wf93f5WVVlZyyWnrEAYFIVzgxFiKZzxcLyZKLpHOlsnr1dfkyqwGszcaSgGjvcF2J9nQNjQd68p81HfyBB3xRFiqoIcmUuPxajVlxub/Wxr8tfNvTTbTUWi+S1bssMfw0dnYvL4b4Q33zrbobDSX53coQnOsb5pzs3Fn9vMij0+uNct8LHq3Y08uc/PMCbrmvh86/fTianFZWHwmmiqRxtlXa6/QmafDbsJpWO0RgdozEsRq1z6KFTWj6JodDaP1HQavBYSyxtpmI1Kqyvc/GHU6M8eW6cz9y1jRdvrEXRreEuOyaFWI8IIX4KtAPDQog6KeWgEKIOra1+Kv2ct84ArUj10AyvsWRz3e892cXHfnGsrNfxYjAo0Oi1UWE3kcrm5/A/Xfjn99RQhGqnmeF5CBNUATtbfQBlF01bK2xUOMwzehfPxbpaByaDSq8/zpoaJ3kpUYQoW4xWBIseu8+Hc2MxKuwmWipsqIqYVybCUvDf+/voKMxNQPs7T/ytVUVw46pKXrGtnldub+DXR4cQQnDbptqLcm5LjRDiX4E3AyHgeWWe8g7g/y7qSV1iXrurib//2dFlC8dbCDazuuT+5rOxt9M/LZx+vt/x/mCCbzzWyXee6OL3f32LrmKegWUtLk/clAsPXwlcmmWSqxSTQeHuN+/khf/18LT2JQnFtFxzQSlsUAQrq+wk0nnSuTyraxycKSidTerMxZpUVgsmmuzlWOeyTGtJKte+bzaUHrfKaZ7/G9TRuQI52h/izd/cO2NrznypdpoxGRTsJsO0YMz50FJpn9dAfiH47KYLCvU71BdiRZWdc2WKWBMIoXU4hBLTi3FVTjM+m5FnFtgCqgj49F1beeX2a0acgBDCAfwv8FdT1BsTv9c7hhbJcDjJe37wbFlrqmMDkaLlRE7C2dHYrBYUOSlxWoxE0+VDTwDimfMqrcnfaa/NSJ8/wYnBKNsa3ezt8tPis7Gqys7ZSd+xdFaW9ZpbU+MkmEizv9s/oxfdyip7ceH53n29/NUL18x4njo6F4uJQsf3nurmZ//vRtbVOku6Bj71m5NEU1muX1nJ70+O8PDpUTpGo/z6r56LUVX48h/v4OxolH/71YlCEKBWaKlymKn3WHBbjZwejpZMvjc1uDk4Sdk4V1vxhjo3z/Ro9+5kJs97fvgsbRV23rCnmXc+Z8XS/TF0LgghhB1QCp0+duBW4J+BXwBvAT5R+PfnZXb/DfBvhSBsCvt+eDnP9zMPnObzvz+zZIVl0D6rh/tDdM3ixT+BYRGLI6FEhpzZwIY6Jz6HSfOGlpp4KZeX5KTk7EiUaqeZVDbP3k4/VqNatHOaYHuTmwO98zvPmXBbTcX78Vzq5lg6RzKbp73Ny97O5Sn8jsfSjBfmC41e67T2/OWgwWNlMFT+dXJ5ySOnR3nk9Ch//eNDSKktMoOmbq92mtmzwjdtfn+pEEI8CJSrfH9USvlzKeVHgY8KIT4MvBctgHNi3+ehFZdvmuX4V91YWVUEqiLIL0N360Lx2kwlVhoXg/1dgZKAa/MCO+qzeckrvvQ4r9rRwB2b69jePD1f5VpmyYrLQogfoa3eVgoh+tC+vLcIIbah1Tq7gD9ZqtfT0XBajHzkjvX81b0HZxxoGAv+iYF4hgaPlUN9QTI5ye5WL0ZFsKPFy5H+EHvafIzH0jgtBlQhSvyVV1Wf96kxGRSaK2xsanDznNWVhBIZ9nb6qXSaednWeqKpLLF0lhesq0EIyb/+6iSJdI633tjKH+24aFZkOjoXnWwuz/vuPXhBheVtjR6iqUyxOFTjWtyCzIGeAC0+K93+pRmoGhVBnduy6Pc2UYirsJtmLC7Xui2oQtAfTLCqyk6Fw0znWIyRSAqjKrCb1KL1z0L4/16/g5dsqVvUeV+JCCGMaIXlH0gpf1LuOXrH0OJIZXP82fefmdEfzmc3EZ0SkJKfpQpgUMScXnNH+8NsrC9tqV9ZZSeXl8VJtkRr4Zt4PDmMaG2tk9PDkWkqldPDkeKkdiaUSa0KF2PSq6OzEN5UsMGYytmRKG6rkTu31bOzxcuT58YZCafoC8RZV+vCoCqsq3Vxx+Y6PvSTI7S3etnbFWC0YAkTjmdYU+2gL5godgAt1NLtcF+QJp+V3sI9WBZ8Jj/565PcvrmOBo/1At65zhJSA/y0YJVlAH4opfy1EGIf8N9CiHcA3cBdUBqALaX0F0LD9hWO9c8T4X5LTTqb56/uPcD9R4aW7JiqgJ0tvlkV+NPOo1wbzDyYCMl87Mz0btsJJud5pHN5lElfuSafFYtRpc5tKYYLLhSDAkPhhe2by0v2dgZoq7QxHksTXsZC2Hg0zbpaJzkpi+Kv5SCTyxevdbMxMXQJJTL86fefKW7/u5esLy6QSSmJpLIlgZAXEynlC+f51B8A91MoLgshtgBfB26XUs74obwax8pH+5fHNnExVDrNF7RYtBjq3RZ6/HHW1TqIJLMLCv2cwB9L87VHO+kej3P3m3ctw1leuSxZcVlK+foym7+xVMfXmZk7tzVQ57byru/uL6v2S+fymA0Ct9VIJJUlk5PUuiwIIdjU4OLpTj8VdhOhRKaY5FvlNLO62kE4mdFWlfMSh9nAxnoX/3TnRtbVukpe4492zKwI/NjLNlDntlDn1gfSOlc3j54d48wi07BnGuQvVp2SyUk8NtMFFZe9NiNtlXYk4LYY2VdmArKi0k6l00Q6I8nk8wg0X+ZoSgtymPCXm2jd39cVYEuDG7NRQaAle5sMCgPBBJUOc1EZdnY0xtnRGE6zyooqO5V287wnQI1eKzuavWxv9rCl0c3OFt+i/wZXGkKbIX8DOCGl/K9LfT5XG5+4/yTZvGRnixacm5eS/V2BovK30WOdZm+Rn2Eu3lphYzg8c4K1IqDJa8VoUDg2ECmqtrY0ujnSFyrZLz5F+XyoL8SuFi/7uwO4rMYlaX9cU+O48INc5QghutDS53NAVkq5Swjxj8C7gNHC0z4ipby/zL63AZ8DVODrUspPXJSTvsr4zAOnGQ6nWF/nwmczUekw89gHn4+Usui1n8rmeP9/H+JXhwfZ2eyhZ9J90mc3ghScGIpgMyqsr3NydiRKLpdnQ50Li1Ehk8szEEyWXZxp8lrxOUzEU7my44FMTjIaSenF5csEKeU5YGuZ7ePAC8psLwZgFx5/E/jmcp4jwMd+fvSCC8vVTjNem4nRaJLV1Vo3zEIKyxfKQkLjcnlJMJahzm1BSuj1J+j1J9jT5lt0cbnRayv6oS+UzrE4O5u9xW6E5SCRyXFqOMLuluVVQrZW2C8omPtffnWC7z3Vzat2NLKvy8/R/hBffdMu2tsur7G2EGK1lPJM4eGdwMnC9mbgJ8CbpJSnL9X5XSq+82TXpT6FIrN1si4HQkClw8yxgRCxZHbWrsH58NCpUQaCCer1+3mRqzIa9Fqkvc3Hg++/mZd/4bFpN123xYAQgpFImpvXuEhlcoxHUwyFk6ytceCzGWmpsJV4Ljd4LBzrDxdDG9K5PNFUljfsaZ5WWJ6LHXq7gM41wpEF+AkLoMlno9JhwqAqjIST0wb5LquB8AX4Jh/uD1EzT5+7cqysdpT4UhkVwbpaBwZFQQgIJ7KcG4uVpP5OxmMzsqbaSTSVZXTSgL6ctyyUV0ZGUjlWW43zmgDtafPxqVdvvdZ9sG4E3gQcEUIcLGwrW8zSmT/5vOS/HjjNt57omva7DXVOjg9G8NlNZMtUkmPp0u9wa4WN7CTVcTlsRoW2KkfR3mpXq5dcQTGmKqKksOwwqdjM01tU93cHaKssZtgsiske62IRXpvXKM+TUo5N2fYZKeV/zrSDEEIFvgi8COgD9gkhfiGl1IM4yzAYSmBQFMwGhWA8U3LNv31zLTtbvKysdpT4G08Ocf3+Uz386rDm2newN8iWRg91HguRZBaTqnB8UPvexTN5ev1xVlQ6ptkxeWxG9rT5iKWzHC34oE+EBc0VAPZkxzjbmjwX8ifQucZorbRf8DE8NiOnhjV/UyllWUHSXFgWkXkxgZRyms3ibERSWSJTOoGmdgbNl92tXi1gc5HFJKfZMC3sdjnY1eLl8BJkk8xElcNMx+iFq6K7x+P81wNaXXZro/tyvZ59QgixFsijdR/8aWH7x4AK4EuF+0JWSnnNyE/f+7xV/P7kyAXbN14oS9ldO1/W1zqLc9ALLSyDVh/7ix8d4Ifvum7B3U1XK3px+Sqiymnms6/dxmvvfqq4zaQK4ukcLT47p4YjJNJ5bCYDnmoTUmrqDY9NS3+vsJuKKoxALF2SBhxOZHnVjkbu3KbbWujozMR8BuotPhtum5FTQxF6/HF6/NMLTG2VdiodJk4ORordBItBSqjzWBZVXDYbBCenBAdm8pKTQ/M/n2A8sySqGDFHiqCqCN73wtX82S2rUK/xsCQp5WMsJnFHZ0YiyQzvu/cgD54ol+ekTbZtJpVIMlN2sH52JEKty8JYNEVrpR1VQDyeQVC+7OuxGfHZTcXCMmgecbesrWR3q5dDBXV/k89KvduKQRUzXifq3RYe75i5DXkhLDbMU2detANnCypKhBD3oCmtrvnicjKT4z9/c4pql4WzIxFODIaxmQwc6w9hMCi4LJpA4rtvb0cIwbpaF+tmyJ7K5yX37OvlM4WiiNmgsKragdtq5Klz4yTLZIdEU7liQW4ywXiGpzv97Gj20OSzsrLSzkOnp64plOf7T3XzJ89doYf76cybdz1nBZ978AyJzOIKIhvrXQxPsoTY2xVgZZW9bJDrbAQuoCB1oCdIo9c67+JyORxmA0ZVTGvrn/xe9hQUtBNhfels/oLD8iKpLNWLtKmbi5VVdkYjKSodZobDybLXoaUimcku+c38UF+ID/3kMP9117YlPe6FIqV81Qzb38mk7oNrjdZKO194/Xbe8PVLl/XtMKlYTVdHGXJ/d4BfHRm4pnJ9ZuPq+F/VKdLe5uOV2xvoGIkSS2fp8cfZ2xVgV4uX1gobVpNKIJbCYTVS7bQQ8KeLrTEGBdbXOZFSG3BPXk1qb/XxvhetvlRvS0fnCkGiCKa1oNtNKutqXcQzWU4MRmCOemuVY/4WEHMx4bm+ULY0ei5acvVcJNIzK1U21rv4+Cs26R0SOsvCudEo7/7eM7Mu8ihCICUzethl85rP47YmD51jMTxWAyORFG6rka1NbsYiaXJSu3YoBc/xqa2CLT4rT3b4S1Kta12WYiBRtdM8bcLd3urlxGCYG1dWkMhkMSgKCE1/rKnWsrN6LnttRk5MKnDvar28Wl4vUyTwWyGEBL5a8GsEeK8Q4s3AfuCvpZRTL64NQO+kx33AnmU/28sQKSXHB8P0jMeo99j44dM93Lu/txjAs7XJzdOdfhQBjQ4zFoPCwd4gz/YEZrVAyuclj3eM8ZGfHtHsAexG6tyWCwrqavbZMChKsWV/ZZUdRYgZ7bEEsLPFQyKT51dHBnnZ1vpFv7bOtUUwnp7Vv38uAvE0PrupxBbCZzctuLh8Id662bykxmW5II/Vpzv9rK91ksrmGAwlWVfnonMsRl8gQaPXSoXdNGdQ32IxGxXa23yEE+kFCS1mo8FrLf4fXEin4mysq3XitBiIp3PYzSrnRmNMXy5bPIqA69oqlvCIOsuNz2G6ZK+9rtZJMJHh5NBSfgrnxmRQtDDRZeBiv5fLGb24fJUhhEARYlrbuT+Woms8jj+WZlerj0Q6x9H+IB6bifY2H8l0jsP9Ia3whVawAS1s6D3PW8Xz1lbR6L2mW811dOakezxBhd1MW5UNgcBqVDg3Fqc3EF+QT9vhviAGRRRD8BaKxaiwpcFNNJXDtIji8u5Wb9H7+FJS4zJT6TCzrtZJW5UDj9WI12bCYzPithpp9Nq4boVvTmWzjs5i+MPJEf7ingPFQK+Z2N8dYHuzhwNT2uancrA3WAwOA63T4ZHTY9hNKpsa3BzoDZKeQbE0HE6RmRKkNNkCaySSKiqZ81IigWMDYWLpHN3+eFnLmZtXVzIWTeEwqxgUgddhRhWC8VgKm8nAQDBBIJ3DoAj+eE/z5dr2erlxk5SyXwhRDTwghDgJfBn4OFrh+ePAp4G3L+bgV2Ny/VQeOD7Mu7+nhUdNTnTP5zURRCCapsphoq3STiiZZTicZGujh4/fd5x/feVmNta7yx73Iz89Qp3byvpCwGWu4OM6H7w2Ix++Yz2xVJaRSIrBYBKbSeUXB/tLuo/sZsOMLe1GRbCl0Y0iFCodBr79eCetFXY2N5Y/Xx2dCbK5PIoQvPn6Fr7zZPeM9wnQVLA2k4pBVTCqClJK0rk8XWMxBoKltomprOYjPmEDMx9MxoWNKSvsJlZVO0hncxgNypwhsvOhazyGz27GqCol992+QGJJg2dVAZPXjP3RNMcHtHlyvduCd0qH0XxYWWWnwmEilc0zGEySyeZZU+PAYlSJp7OcHVlaD1qjInCYDZwcihBJZlEVwfYmDysq7cWxyIWwqtrBZ+7apl/HriAiyQzv/eGBJT3mpgYXCoKjA6FZMz4avVbOjkQXPb9dLK0VNmKp3Iw2jhfKvk4/iXQOq2nxtkFXC3px+Spk9ZTQnRafDQnc8+49tLdWFNvwMtkcP9rXy8d+fgwhYHuzh3OjUUKJbHHgks1L/uoFq/XWPR2deRCIpxmNpoopzD67idXVjkKLe2je6bybGtzs75570LelwU0eSSieocJh4mBviJYKGxaDWhw07lxgMMjqasclVyy/vr2Z//e8lfqCls4l4+5HOvj3/zs570BNozL3hHtro7vsZC6WzvF0p7/Ynv9Mme9+MpvHqAryhWuIIqZ7lE+oJwHW1jiJFfzkrJM8MtfVOjGqCj3+ONFUjvFYmvGYdp2Y7K/e3uotKtzeflMbH7lj/ZzvTweklP2Ff0eEED8F2qWUj0z8XgjxNeC+Mrv2A02THjcWtk09/lWXXD+ZVDbHlx/uwKgKtjd76ByNsaXRzXAoiaoIchJ6Agl2NHnY1x0ofj8fOzvG1iY3b/z60/z7H23hptWVOKaEhz1ndRUf+J9DmAwKb76hlV8eGix6qG5v9rC10cPB3iAHe4PFLoAXbahhZ4uXGpeZV25v5GcH+vnJs/0cmSE3wKgqGBWBx2ZiNJpCFdBWZcdlMWqFtWgagyIwqiZOD0f43YlhvSijMyvxdJbbPvsomxvdtFXYuXFlBX84NVr2ua0VNnr9cdLzHGse6w+xc4EdKcoCXLfsJhWPzbjkSuLNje4L6jiYC6Mq2N7kpdsfo6XCzt5OPwZFW8RdVe3g7EiUgVCS4UiK1gobA8HEnH9zu0mlxm2hYzQ2TS0+0UEshNYp3DEaXZIi/OYGFz3+RMl8IpeX7O8OsLv1wrr9JhacN9a72VC/sCwmnUvLf/z61AVZLrqtBqLJLLtafZwZiRYEi9oiS43LTLPPRl5q41QhBNlcnoO9QfJSW5RZygWgBo+F/uDsAZ8TWQjLybM9Qf7yngN89U07r3nBk15cvgpJpHKsqLSTzUtq3Ra6x2K8tr2J61ZUljzPaFCLXzYpNS+sWreFWpcVs0EU22jGY2mqnMvjM6Wjc7UwGklxcor6wx9LFwfVq6sdnB2NzlmsMipizpXVzQ0ucvnSYLyVVQ62Nro5NEU1FZ/FUqIcUyfkF4sqp5kal5n/d8sqbt9cd0nOQUcH4L7DA/zb/ScXttMsY0mLQWFLowcE+GxG/DP4TU4M9jfWO/HZzZwbjdHotdI1FkNRtIRrEBzpD2EzqURTM3tvemxa67KqCJLZ889zWgzFxaOJpgZFaFZYk9nbFWBLg5sjAyFu2zSDga1OCUIIO6BIKSOFn28F/lkIUSelHCw87ZXA0TK77wNWCyHa0IrKrwPecDHO+1ITjKdxmLXP5bce7+RATxCnWSWZztNaacegwOpqJ4PhBKqArISclGxr9JDK5khn87itRiRa0emevT34bEbaV5S2ab9kSx1tlXZ+uLebj710A3//kg3s7w7wqd+cZF9XgLdc38rfvWQ9D54YJpuXOC1GblpVWfTxD8TSfP53Z2a9Pz/bE8BaUCDuavEyGE6WVSIaVUGDx8pXHungJVvqWF3jXNK/qc7VQSaX59bPPEJfIFFUyK+uceA0G6YF3QmhCRzmW1gGTZW7r9OP06zSWmmnL5CY0w95IXUTu9mwYNuN+TAQTFLntkwLsF8o1U4zrZV2MoXF2+7xOC0VdnJSFq3phsMpNtS5iKay+GPpkqJcrhDMu7LKjs+u2QzEUjlsJpXBUKKk6NVWZS8W4GZCSoqva1AEzT4bTouBYCKDy2KccVGrHCsq7URT2RmzYBLpHLtbvZwajhBOLNyOIxBPc/3KCiodZoLxdDG/Sefy5/GOURq9VvoDiXnFPa+otGM1qYxGUmTzEn8sjdmglF00Gg6nGA5Pz/lZVe1ACMmp4aWxkwHYUOeiNxBnR7O2MNxWqX0PpYRMPk88lcNrMy17YXmC3x4f5kP/e4S/f9mGSzaXvhy4dt/5VUouL/naY+dIZXKawqMwGPn8787y6h1NJYnaAL3+OE0+K9VOC7GU1i4TiKU4FTp/YfjiH87yjy/feFHfh47OlUJ/MMHPDvTzvSe7i0rBcpwZibKzxVtWlTiZTF7ishio91jKDkRNBoVgIjOtnfdIf6is0iGxwDTcA71BVlc7ZvSMXGpURfC1N+/k+etqLsrr6ejMxtmRCB/4n8ML3m8olCiroHCYVKrdluKE0WZSWVfrnNWf7dhAhDU1kmw+z/HBMJlsnmQ2z2Dhvry71Usyk6fHHyeby+OxmegPatcDRcDuVh/HC626G+tcxUWotTXOkuvPyaEIRlWwotLOEx3jNHmt1LotxeKzw2LgU6/eovuZz58a4KcF1YoB+KGU8tdCiO8JIbah2WJ0AX8CIISoB74upbxDSpkVQrwX+A2gAt+UUh67BO/hojIeTfE3Pz7EyaEI2ZykzmNhT5uPo/2h4ue2zm1hOJwkL7UW+3AyQ38wgdmgFj/3bRU2qpxmrmurIBRP8+CJEZ7q9PPnz19VoiLaUO/iplVVHO4LsbXJQ3ubjx+88zqODYSoc1sxqAq3bZq+uJnJ5Xnt3U/OufArJcTTOZxmFX8sTf8MCq1MTitK7WnzccfnH+XHf3I9a2tdekutTglff7RzmsrvzHAUj82I3aTS5LPRPR4nkckhJahi4TZoEoikchzpDxfuLTksRpXBULKswjCSnH8Y30gkhdNimNNaaqH0BRLa4s0FFpfbKu0lBTKjKsoGYM9lGzKhRq73WPDZTPhjaeo8Vuo9VuLpHOdGo5gNC/tuZ/Oy5Hrjs5vY0+bj2e4AmSmWApUOE/m8pMZtIV9YGDs5FCGamvnvfrQwRtjR7OHZOSy9yvHgiRG8NhPD4STXr6zkHTe1LfgYOpeGdbUu7j8yxOYGN93+2IyLC06LgQaPhb5ActpnKbXA0MmzI1HNymoewfflWFvjJCfzuC1GegMJalwW+oMJIsksz/YEMRsUrCb1knfe3ru/l4dPj/Ktt+1mfd21qejXi8tXGaoiuHNbAz/a21Oyva3STpPPWrItl5eMRFL47KaSCef2Jg8Dk4rL9x0e0IvLOjpluPuRjgUpHPsD8Xl5KU+EnTT7bKV+jiaVNTVODkzxQ650lIa0TKbKaV5weEoqmysbTLgc/PsfbdYLyzqXBdFUlg/95DDxBS7IAATiGaocZmwmlWqnGZ/dhEFV6B6LlYia4+kc3eNx1tU6Zg0EOj0cxWXVJuVTF6WmDp5j6QTPWV1JMpPDqCqks3lWVNmxGFUmO1qZDUrJd7rJZyOTyxeVJL2BBBaTis2ksqHOxTPdfp67pmrBf4trFSnlOWBrme1vmuH5A8Adkx7fD9y/bCd4mTESTnJyKMLtm+ro8cdxWYwMR5LTfGFzecmuFi8SrcVWIMkXAjSbvFZODUfoHI9T7bbwh1MjKEJQ5TRz9kyUJp91WoL7VCW+yaCwfY4FlN8cG+L0AhRXkVSOBq+gpUIr/k1Q7TSzutpBIpPDZFB46pyf56yu4BVfegKTQWFzg5vrVlSwvcnNLWurMSwykFfnyieTy3PPvp6yvwsW1MUnhyKYDYJN9S6sRpWclPh7Fm+nMPneYlQFLothWsjcQuwaTAZlyQvLE+zvDrC6xkHXWKys5ZzTYsBjNRJMZLCZVKxGFZ/dxHgsjc2klqiEJ5ivdd1MeKxGrCaVUDJTYjPltho5sIDclXJMdEJO9qGfYEWlg71dfvzxjGYftIDB+0KeO5kvvmEHL9qgj92vRN54XQv3HxniSH+IFVV2apwWzo1Gi/7im+q1kMxIMrtkwZWgzVU7F+l5PNVeZ2TKIlAqm8dmvDwWZ4fCSV771Sd5w54WXru7ibZK+6U+pYuKXly+CnnZ1jru3ddTMol89c7GaR4wwXia1gobT01pF5iqnLCaVJLpLBaT/nHR0Zkglsry9Uc7F7TPUDhVdmA4E7VuC1VOE6qiFYyOD4SmFZZBU3bNVFyeLfhlJnr8iQWd52J593NXcNeuprmfqKOzzEgp+eD/HMYfXZiqwmpU2NTgpjeQKKqMusbjJQs6iUwOt9VAqKAOSWRydPsTcwYphRPZogfzhjonxwdnVjsnUlmi6VxZRfTOFi+qEAyESlVoTrOBpzr9NHisNHisHOwNUGk3k0jlih6NRxfQhqujM19+d2KYD/3kCKNTJogb6lw4zAasRhWLUSVRUP3t7QoU/YurHGaGwsli0ba9zUevP87T5/xcv6KCdE6zyvjLF6zmh3t7phWXF8P6OteCO3ryUss88dlNGFWFaDJDjz/B4x3jrKt1kM0rbG100zUWx2FWMRu0VvrvPtnFF/+QpdJh4l9esVm3pbkGebYnwPvuPViyMDETqawsqlAB6j0WvLaFB81NZXuzhwPdQWqcZhp9NlQBoUSWU8MRdrV4S3x83VYjHpuRZCZHMpPHYlSodVmwmVRCieyCAgMXwpnhKOvrtE6gCcs5gSbEWF/nKrbDTxS4Fyq0WCiDoSSrqx2kM6Xj7sWqNcuxrytAe5uPcCKDRCtoaxYaVgKxNJFZ7LLKYV5EQa6iYAFyejjCGt3S54pjR7O3uAhxrmBbYzIoVNlMWE1KyfVkKVmo2nlPm49uf5xmn21e15AL7WRYSsLJLF95uIO7H+mgyWfjzq31vP2mtmvCPkavFl6F3LCykv+6axvff7qbbC6PQVGoKeOZ7LGZ+OBt61lf76TXH+fEYITVNQ7WVDv50E8O84dTo4xGUrgsBv7xl8f55zs3YTLoKgodHYD/+PXJaSun86FzLFYMC5qLM8OROf3vgFnb7Q71hWhv9fJMT3BBCoW+wPIOwhs8Vt73wjXL+ho6OrORz0ti6SzffbKbp86N8+iZMVp9c4dIbqzXCmChRAaf3cgTHbP7uYWTWfa0+UpUF4l0juODYTbWuwjFM/QFy7fPVzvNhBIZ8lJTfYzH0mV92wOJDCORFFsa3Rye4rv+THcAs0GwqtpBvcfLudEYbquRpzr9eGxGalxmBkIJKh1mVAX6ggnedmMr162oYNcCA0F1dObD89dV85E71vHx+07gn6SEnJhArqq2a5142xt4y/UtfP/pbn7ybD+H+0KcHYnhNKvcuLKCE0MR9nb6sRoVrlvh48lz44AWbPbb40O86zkrluR8V1Y5+Pl7b+Rt39o3r3AyoyLI5PI8cmas7O/LqcGmeqiPRdO85wfP8JU37uTWjXqB+Vrih0/3zKuwXI6BoKb+39PmQ6ItnC5GKJDM5MnkJcORVNEqwmczsrHeBUi2NrgwmwzkcpJQMs1wKEkikyObh1CCou9qa4WNzQ0ujszhN7xYRsIpWnw2hBA4LQYEmuXDxfJZnWCi4F4utHep6RmPk8rmivMDIbS/s81kWHBxuX+GscdsjMfSvOu7+6mwm9j/dy+85gPMrjQsRpVmn61ERZzO5hkKL19xdmWVfVY7uMlYjVpOycS9dmgeRWO3VbPLWG6EYN5B36AtMnePx/n8789y35FBvveOPTR4rHPveAWjF5evUq5fWcFf3Xuw+HhnmQmiqgi2NXsAWFXtZFX1+dXH/3j1Vn5xaIDPPHCa8Wiae/b1Uue28pcvXL3cp66jc9nz1LlxvvNk96L2HYumaW/1zmsA2ui1EYjPrRxUldkHdnu7AqyssmM2qPNWkARiS6e0KMdHX7Je95fUuaS84zv7ONIfKlH9T7asMShQ47IwHk2zod6Fogj6A4lpijCf3YTdpM46sM3myys2jg2EqXNbSrZVOcw0eq0c6A2SyWn7nRuLkc3lqXKYqXaZS/zYJ6vIDveFSlTOq2scuCxGzo1G6fEnWFPjZF2ts6iwOjMSLfotOszaxPy+P7+JTQ3uOf56OjqLRwjBK7c3cvumOt78zb080x0oWfw8OxKjyWflVTsaMKgKb7qulYdOjQJQ5zbT4LURSWVoq7SzutqhBVdmctS6LNy+uRYp4RXbG9jW5Fmyc7aZDHzgtrW85Zv7qHKa6RzTFmliqSxOi4FAPIMA1tU6sZsNJZZWiyUv4V/vP4GqCF6wXm9Bv1Z40YYaUtk8vzw0sOhjTBRmdhZUijUu8zTLmXJsqHPhtBjKihH88cyMgbTPXVPF0f4Qa2ucBBMZvDYj737uCnx2E1saPSQzOUKJDP/129Pcu7930e9rMu1tPgRaG3rXItvtl4qLWV+dWgSUElwWI51jC7/m9AcSNPms2E2GeRf/JhiPpfnNsWG9u+IKxGU1XtTXq3SYZw33tBgU1te76PXHGYum57WIO5lQIsOWBndJ0P1CsJs02xyPzYRAU3IjYDSSYiScIpHJsbnBRV8gQYPHynAkVey8sptUJJDM5IrBnuW6ic+NxvjGo5187GUbFnWOVwp6cfkqpcZloa3SXlyViqUX7nn18q312IwK7/3hAcwGhTU1jqU+TR2dK454OruowK/JdI7F51QvN/tsnB6evRBsMyqYjOqsoR0TTNzU19c6EYJZW+wBktk89W4LA8vQZvTcNVXcrg9GdS4hvf44D58eneYr7rYZGA4LVlY7yOUlZ0aiKIJZA2/8sTQOs41qp7lsN0N7mw9/NIXdpJYN/RwMJVlT4yh6urZU2Hi2J8CeNh/HBrSB8pYGN/u7A4xEUtS4znciuSyGaZNah9nAc1ZV0huIc2Y4is9uQhGCSDLDM93acTtGYyhC89ZTFBgMpvjj65p5wbpqvbCsc9GwGFX++0+uJ5+X/OrIIPcfGcRhNpDI5PjIHeuLLaSqIvjGW3YzHkvx0s8/xv6uAAZFYDWqRNNZkJodwCt31PPB29Yv2/nubPFx8GMv4q6vPsnGLXW8dncTdW4L/37/SYbDSXoDCfyxNCcWWKSZjRqnhbsfOccz3QFuXlPFnhUVS3ZsncuTF2+s5cZVlTzZMTaj5dl8eabg9RuOZ7RAuJ5A2bGn1aiypsbBob6FFWduWFnB89ZWc9fupsL9qHyV1VKwuvnEqzbzx9c187MDA3zvqa5F+xyvqXFcdHXybEy1+LnYDEdSiy6u9Ras8Jp81mlh4bPR4LESTmQIxtPXRLv/1YTTfHFLgHPNUzcVxriLpclnXXRheWezl2gqw6nhaFmRiCKgvRCkHYhnCMQzGBRwF3JRJo/rx6JpTKpgdbUDr91EJpvHoAoksL3JywduW7vYt3jFoBeXr2Lu2tXEJ3+thY0t1hPJaTHypTfuALSWAx2da5lsLs+H/vfIBSuSRqMptja6ZxzEC6GFF8z0Om2VdtK5PP2BBPFMvhjuMh8mJr3bmjwcLOPfPJlGn23Ji8u3bqjhc6/brrfR6VxSxqKpaYVlr9XAicEIEkoUPPNxk+nxx9nc4J5WXF5b4yxOgNvbfGUnw0ZVMBxOFi0tFEWQl5rybMKJarJX3ZH+MNsaPXSMRWnyaYFhJoPmy25UBUPhFBajUvSXrHNbODYQxmq429BiAACrQ0lEQVRU2NzoIV1QQ6uKwG7WBsdNPit3bKpjTa3un6hz8VEUwcu21vOyrfUzPkdVBB6ribfd2Eazz4bDYuDmNVWMRlLcu6+HJp+NOzbXLfu5GlSF771jD2aDgkFV+NHeHh49M1b8XlVVO2jy2RY0Ud5Y78RsUDncF6TZp1mCeGxGTg9Hi6FjlU4zO3SbmmsGh9nAox94PuOxFP/vhwc4NMd4bS6i6RxPd/qnBcSCpryrcJjmXVi+a1cjr29vpslno8JuWtB4TgjBlkYPq6odvGFPM6FEmi/+oYNHTo9iNihlF2CnYjYoeG0m9rT5SGfzRFJZzhb80GvdFqxGBX8sQ6PXiiK00DqnxUg0lcViVKe9/wvBbTXSWmkjmV54vslSMhRK0jIPW6+Z2NcVoMFrnTUgfCr9wQRD4SSOi1yo1Llw/vHlG3jTN/Yuu0+xz25iTY2DYDzD7lYv2ZxEUQThZIZ4Okc2l8dhNnCoL3hBr9PrT7Cyyj6rOrrCbmJVtYNsPk84kaVrLEa1y1JcgJuJvGRat7Fm/1O+YJ7OyZJ8BrtJ5a9vXcvbbmy9Jua++tXgKua2TbV88tcnefHGGt50XcuijrGq2kGPP872Zi+dYzFS2dys/q46lzdCiK3AVwAH0AX8sZRymjxWCHEb8DlABb4upfzExTzPy5Fef5x/+MUxfn9yZEmOZ5klRGN3a/ki1ARVTvMFKzZODIbmVCl0j8WwmrRQpQvBYlS4fkUFL1hfw+vbm+e08dDRWU6klHz14Y6SbR6bkQaPldhIdFEhmJsbXHSOlfqo7m71lgTihWZYBMrkJFajyuG+EJUOEz1lvDbHoqVF64N9QVp8VpwWA8cGwjjNBtLZPFsbPezvDmBUBbtbveTyEomm8kpn8+zt9LO1UVMmb2s672lnMSrUe69uHzidKx+TQeHPbllZsq3Kaea9z7+4lm12s4FsLs8PnurmD6dGi4VloKTI1eyzcbg3yJoaJxaTSjKTYyyaKlrQeGwmQvE0p4ejSAnXrajksbPlfZoP9wUX5PWoc+VjNak0mmx89rXbeLJjnHQ2x3/+9jTRVJbNDW5uWFXBPXt7FxQYNxRK0uS1FhV6K6vsBONa2OR88NiM/L/nraKlwr6o9zSBzWRgVbV2X/r0a7Zy35FBXr+7ib5Agh8/08sX/9DBlkY3A8EEK6scSDSBh1HVVlyf7Q6QmbTya1QEO1u9PNN1fnu5v4sqYEOdEyEEdpOBvJQoCjzbHSyxxZoLk0Fhc4ObwVCCQ72LU0xurHdhNxmIprLE01nyUlLlNGNQtPc4Fk1R6TCTyeWJprLF7qapx7AYVI4OhIgkL8zOrr/wmdjU4Cqx3pqJm1ZV8hcv0O0yr0RWVTv59F1becPXnl6219jc4OZIf4inzs0+Xx1maVT/M80sTQaFLQ1ujg+EptltLMZzfKH8+E9vYEO9a9lf53JBLy5fxbT4bKytcXLzmupFr5RUOMxUOMxEU1laK2z0BxM0ehe/Mqpzyfk68DdSyoeFEG8H/hb4+8lPEEKowBeBFwF9wD4hxC+klMcv+tleJhzsDXLXV59cVNFpJmbyYAXIZGcu5hpVwbnR+SfWz0QqK7EYVJwWQzFJeyrDkdS0VPByKALq3FYavVYavTaafIV/vVaafDZqXBa9oKxzyekPJnjw+DCPnx2jP5jAoGjqA6MqqHVZsJsNOM0GVjY5CMbTnBmJzruYYzEoxUAuoyrY3uxhb2fp9+bUcITdrV6ODYSJT1mwqXVbGAqnpimGal1W+oIJBkNJNtS5SjzTu/0JPDYTRkVQ47ZgiKaKFliZnORwX4hcPs/EZavObWFPwaPSaTGwf5IS43W7m3X1kY7OAsjmJZ958PSMKr+hUJKhUJLnrq4kns7hj6U5OxIt+R63VGidB2trHJgNKvlZilu9/gR/9v1n+OIf75h1cVrn6qOt0k5bpVbMPTEYoa3Kzu2bammpsPP2G9v44dM9gHaNHwgmODoQ5kh/CJ/NxOmRSPE+Vu+2gKCk281iVBmPzaz289qMrKlxUuk047UZeeN1LRdcWJ6MyaBgMpiKIqjWSjt/evNKBoJJHjw+xJ4VlTx4YnjO42TyknyekoJzOXJyui3c2hoHVqNKZJbWfatRZXODCyEEp4YjrKp2lNxDF0vHaJTxSaGmU4v8E0pMq1FhY71rWuaD1aSyvyuAOg+7u/lytD9Ms8+Gy2qYtcj8vhfpodxXMrNMQxeN1ahgMxloqbDN2R271ERTuWnj5AaPFQEXZLlxIdS5LddUYRn04vJVzed/f4ZKp4nXtzdd8LGePjfOC9bXFI3Kda5Y1gCPFH5+APgNU4rLQDtwVkp5DkAIcQ9wJ3DNFpfzUs5ZWJ5YoZ0vp4YiVDvNCAEmVcFqUqkqeLYemEUFsaXRzTPdwXm/zmycGYnishpob9UKyOXG5Pu7A8UC8/o6F2trHFMKyDbqPJaimkRH53Lkpwf6+OD/HCkqDFsqbFiNKmtrXSQyOY4NaJOp8Via8YKyoa6gPNzX5Z/TGiOSylHlMOO2GekLxOn1J9jZ7CUQT3NuUtDQvq4AAqYt2pwaKr9g1OC10FdQVoQSGRRRatMRiGfI5CVem5GzI5pNxgSpbL64eLSz2cszPYFiC+Rz11TyyGlNIem0GPjrW/VJoo7OQjCpCn/x/NX8529PEZ60QLuhzoWqaPY1q6odPHLmvBL5ljVVBBNp1tc5iady+GwmnGYDJwbDJcKNSoeJ3a0+oskMPocZp8XAycEwvzs5whu+9hTfeMtuvPp4fEkpCCv2A/1SypcKIR4FJnyCqoG9UspXlNkvBxwpPOyRUr58Oc/zk6/eUvK4xmWZVuSThWqyEJoY4fRwhM2NHho8VnJ5yecePM3nf38W0IqmoLWv/+2L11LrtuC1mfDajHhspll9lJcLp8XIf921lURmE0ZV4e3f3sejZ8or+iezv9uPxaiQzCysanZqOEprhW3W4nKD18rB3iDpgke0ugR/E5tJJRifnwVFIpNHoI1LBkNJDIrAYjzfWbhI6+qyKAJqXRaEgCavFX8sjdNinBYkWO00z3AEnSuBB44Pzet5c32nWitsWIwqXWMxVlU76RyLcaQ/NC9LuaVkKJxkKJxkc4ObsWiSfB7MRoVzs1hlLCd/tL2Bv3nx1e+xPBW9uHyV0jUW40sPdfCVN+5YkkHBREq1zaR/ZK5wjqEVin8GvAYot/LQAEyOcu4D9pQ7mBDi3cC7AZqbm5fyPC8rHi6k1M/Ec1ZX8p23tfPpB07xtUc6S1pkZyKayhWVjhOYVIUzZdreJrPUCuBwIsvergCrqh3E09lpaeKK0Oxx/uFlG9jc6FnS19bRuVh8+aGOku9lrctCjctStJcpp9AfDCUZDCXZ0+abNbm6rdJe9GgeLdhXTOwLWgvuZEWRRFu0mTxgz80gkc7mJUZFkMlL+oOJEuXS7lYv+wrKKVFoCDw1FC7xdl5V5eBwf4jeQKnVxiOnx9jV4qXRa+UjL1mP06JnKujoLISRSIrHO8ZIZLT7eI3TjMdmxGMzYjEo3Ly6ksc6xllf58RnM9EfTPDQ6VEcZm0hOZeXdIxG2dbsYWeLt3icG1ZVcGowwv8dHUIIkFILDnp9ezPPW1eNIhR+eqD/mvFvvIj8JXACcAFIKZ8z8QshxP8CP59hv4SUctuyn90CmPy5WFHlYEXV+UB2VRG8/9a1vHxbAx/4n0MoQlDntvDlN+5kW5PnEpxteYQQxTlnjcsyr33yUlvcmS2AdyaGw0m2N3lIZXMIIUhlcxgUBadFO4eRcLJYWAaWxKJmX1egJMx3Lo4W7v21LjOjkRTRVBYhwGcz4Z9nkXo+vP9Fa4pWQ7m8RBHa/0ckmUGi2Q+MR9Mli9k6VxaBWJqHTp+f21Y7zdR7rJgMAim1Qu1YJM3aGidH+oPUuS1k85JoKltilbij2cOR/hCZnPY5WYjIarmYOAejKmiptF/04nKTz8rnX7ed7c3XZkaCXim8CpFS8on/O4lJVXju6qpLfTo6FxkhxINAbZlffRR4O/B5IcTfA78ALmg0IqW8G7gbYNeuXVetG+AvDw3M+vs7tzWgKIK/ffE6Xrm9gT/9/rNF38WFYJiH+nc52phA84m0GBS2Nbk5WFBOt1bY+PRdW9nZ4lueF9XRuQR4C2GZk4NMZutMONgT4LoVPoZCSXoDCXIFOcaKSjs+u4lkZnZP8pFICodJJVoYkDvMBna0eIrK4YnXX1vj5NRwaVvrmeEomxrcdI3HCMQzWI0qRkXgtBhL0umjqSxVTm3C2TES4YaVFeTyEn8sTXurlyfLeN7t7w7w5y9YTbVzfhN3HR2d8xzoCRBKZGhv9ZHI5Eikc5wYivBcl4VoKofFqHDTqgr6Agn6AnFqXGbaKu1kcnme7QkST+dYW+MsuQ5sqnfxVMc4q6odOC0Gusbj7G710uOP8/jZcTpHo7xhTwt37W7UC8tLiBCiEXgJ8K/A+6f8zgU8H3jbJTi1ZWNVtYPvvWMP4USGGpcF5TK2LpvwAp4PR/pCeGxGkpkcyYwWcpuZh6w3kclzYJ5t/E6LYcmKaB7rwjsQhsLn7/1H+8Nsa/IsSXHZYzPy1htaec2u87qjyYKWyYvQ+oL0lcUfTo3QPRbDZjbgj6X53pPdDIYSWE0qm+pd7O8KTAukthgUDhaC9gZDSZp8VkYjOVp8ViKpLJFkloO9QRq9Vnr8iYuuVJ4Nu0mlwWu94HyiBb+uWeU7b2svWdC71tCLy1chT3aM8+tjQ7x2VxOKPvi85pBSvnCOp9wKIIRYgzaYnko/pYrmxsK2a5aZlMg3rqrgXc9ZwS1rq4vbVlU7+eE793DrZx8p8bWbDatRYXOjh3gqO2dSc68/jtmgkFpC/+cJktk8HaMxnBYDr9zewIduX6d3K+hcFUwOrlxT4yxRIrdW2Dg2OLOvoMmgkEjn6BqPYzMqbGz2kMrmGYum5uXjNhZNc/OaShLpPBLJudFYSWjfrhYv6Vyew32lk9Xqok1OEJNBYWuTG5tJxecwMRxOEUik2dbkYSCY4PhgmKZCIN94TEvhnvC7y+an+2M2+2y88zltPHd15Zznr6NzNfNMd4CnO8exGlVet7sZq2luP+ORcJL+YAKH2UgkmcGoKsRklj1tPhLpHJFkhvGYpMJuwmU1kkhl2dsVZFO9SwtSk5JdLV5ODobY1uRhPJqi2mWhayzGxno3xwZC+Oymgi2Pdo0Zj6ZZV+vk7kfPcfej5/izW1bygRev1YvMS8NngQ9w3gZjMq8Aflcu/LqARQixH8gCn5BS/mw5TnA5sJsN2C9zr/0DPQGe6Zm/X2omLwnGMwigymHGZFBQFGYNr14o6WyOnS0+Mrk8w+EUPf44q6odGFXBiVl8jxUBa2udOMwGAvEMw6EkqVkyVubLwd4g62qdOC2G4iL4fKl3W/jqm3YVPZb168nVhz+W5m3f2jdt++pqB2dGosV7zFSSU+aZE9+hbn8Cn93Exjo3CMl4TLs3DYYSqIqCP7Z0KvrFsKvFy4nBMPmLkIBrUAQrqux4bSb6AnHq3dZrurAMenH5quMPJ0f42qPn2Nnipa3KflmvROtcfIQQ1VLKESGEAvwd8JUyT9sHrBZCtKEVlV8HvOEinuZlx1tvaOVffnWi+Pj6FRX8w8s3sK62vEl/tcvCK7Y18O0nuuY8tkGhpD1/e5ObYDwzY2r1cCTF5gYXiUx+UerouXCYDfzXXVu5fqVedNK5eqh1W+gci9HgsfLMlIJwfyDB+lpnseV0KpFUrhigFc/kiwPx7c2eaTYy5VCE1hnQP+m547E0G+pcDIYSjESSBBMZjIqgwmFCVQQmg4LHZioqSdLZPMlMDodJZbigWpJSm1S6LAZ8dlNxwclpVun1ny9ed47F2N3qJZTI4LIasRhVvvamXfMqounoXM3cf2SQe/f18nChPXh/V4BbN9Zwy5pqFAV+tLeHbU1enBYDZ4YjPHZ2jHAywxuva2Vfl594OsONqyoYjaQ4PhDGbFAQAk4MhalzW0hm8wyHEsWupKMDYWqcZpp9NhCwps5FIp2jwWvlqUJ3wXgszaoqO2dHY0xuLsvmZck16ssPdbCtycOLN5ZrVNOZL0KIlwIjUspnhBC3lHnK69HCsGeiRUrZL4RYAfxeCHFEStlR5nWuCRu5pcagKKyudkwLspsLyXmbqtXVS1vsSWUlJwbDZHN5EhnNO32i+29Lg5t4Joc/mqLGbcFhNmA3GegcizEQTEwrPh/qWxoF9IQ1l8mgsKfNx1AoQfc8Cuq3b65jc6N7Sc5B5/LEYlSKFksTeG1G8lLSWmGjazw+884z4I+li0KnqcVkt9VIrcvMqXnavVwoqoCtTZroQxGiKPpYbnGUy2JAQomtzeYGz7K+5pWAXly+ijjQE+Dj9x3n3FgMgyL41JTQBx0d4PVCiP9X+PknwLcAhBD1wNellHdIKbNCiPeihf2pwDellMcuzeleHrzjpjaafDaODYTZVO/iRRtq5lzdt5vnV7hp8tnpnBT4daA3xPYm96yhfkcK6c3rap1kcvlimvSF8qodjXzsZRtwW/V2N52rizU1DjrHYtS6LfQHSydcK6rsRV/FmegaP/8dsxgUNtS75q3OyEuo91hLissA3eMxTAalJB1+PJbGbTXiMBs5MMU30mk28niHnx3NHg73BZkQlYSTWYyqoNFjZU2NA4/NNK0VMJnJFQfAr9vdpBeWdXSA56+rRqCNn8PJLB2jUX56IMvPDw7QF4iXTBq3NLg53B9iQ52TN379aVp8NiocJr71eBeBSV1KNU4zeQlnRmIItM6k3QVFsz+eYTiSYnhK+7FzynihwmFmNJoilJg5YAzg4/cd59Z5jEd0ZuVG4OVCiDsAC+ASQnxfSvlGIUQlWsj1K2faWUrZX/j3nBDiIWA7MK24fK3YyC01mxvd/OovnsO3Hu/k4/cdZ3X1dPuouZjveHwh1LgsdIxGyeYpWlIks3kOT7LL8BeuC2aDwGRQyRT8i5fTPiCdzZPLy3l1NxoUwS1rdfvMqx2byUBbhb0kXLq1wsaB3hCLvXM0ea3E07my4+BQIkO108yOZg+hRGbJ5qjlaPRYMRuVsj7ryxk0v67WSSyVndYlEErMr2P5akYvLl8lBONp3vqtfcX02r958dprXpavMx0p5eeAz5XZPgDcMenx/cD9F/HULmuEELx4Y+2CFEJTW9xnwm2dfhk+1BfCZlKJp2dvlzs5FMFiUIrt84ul0mHi3165mVt1BZTOVchQOMneTv+MwXwOi1ELtSyqBUvZWO/k3Oh5ZcfWJs+sAX/lKDcA39zgpicQJ5eXhJNaEWlro6ekkD2ZiRa/Z3uC095LJifpHI9zw4oKslOM2dtbvSXKlDs21y3o3HV0rlYsRpXbN9exu83H957s4huPdXJyKEKd20wkef7+qwhNEQhwZiTKxnpXsXjT5LMRiIdwmFQ2NLg5Nxolns7R6LHQXGHniY5xHj49hiKYphJzWQwY1OltxKlsfs7Csra/vhB8oUgpPwx8GKCgXP4bKeUbC79+NXCflLJsi4oQwgvEpZSpQiH6RuA/lv2kr0Hecn0rmxvceGwmXvhfDy9o375AgvZWL0IIusZjxe6fCWpc5mnb5qJjNIrZoJDJzW1rkcpK2iqtxNJZHGbDrNYZF8KGOifpbJ5newLzKmArQvDYmTGeo+czXdWMRVOEEhmMqmBrk4dMNl+8Dy1mnaPJq32W/bGZC6lnJnXWNnishBNpIqkLt4CZYEWlHbfVyMG+YNlwzQ11Lo4U/KIF59/nXNaTc2ExKmyoc3FqKEKszBx9pvH7tcSSlfSFEN8UQowIIY5O2uYTQjwghDhT+PfajE28CLgsRpwWA+msFiLyxutaLvUp6ehcsyQzuXmHCJRbWc1L8NrmF/KRzOZprpg7sVkR2gDaNkWxeMfmWn77vpv1wrLOVUkineOd395HpcPM053+sioNVRHk8rJkkN1WaWd9nbNYRDJMspgaiy58IaecimgslmYgmMSgKNR7LMVzGYumS0J0JjjYG2RicyKTY+pTrEaVs6NRUtk8NS4zRlWwpdHNsz2BYjeCxaiwZ4Ue0KmjM5lTQxF+cWiQaGHyOxRKsbbWiRBai+/Gejf9wQRWo0omJzk2ECaflzzbE6TXH2dtjZMqp5mhUJKxaJqbVlUwEErSMx6nwq7dy/MSql3mktf12Exkc1pA0gRCQGaGnIcJ3FYjn37NVu7785sQQpDPy0LLfZj+YIJsLj9n0KjOvHgd8KPJG4QQu4QQEzYZ64H9QohDwB/QPJePX+RzvCZQFMGuVh9/ODmy4H3Homn2dgU4PhimxWfHMcVneiSS4roVPkzzVDq2t/mocVqK14v5cHIoQq9fu4YsFzaTgaFwcv7KaKGJ0XSuXtLZPH/0pSfIS8n6Oi2471BfqKTbZqHkYdbC8lT6gwmqXBY8tgtbDN3d6mVXi5cNdS7OjcU40Fu+sAxgMgg2NbixGBWcFgM7W7zUuy2MRTVLuiqHuex+mxtctFXaWF9Xzn4fNta5eLYnWLawDFrwYTw998Lw1cxSKpe/DXwB+O6kbR9CC0H4hBDiQ4XHH1zC19QpcHIogj+WJpPN8+pdjeTmkYyro6OzPOzvCszakqYILawrnZMzttBUu8zT2vdnom8OX7U1NQ6+/MadrKxyIKVkKJzk3GgMn93Eulqn3lKrc9Xym2NDWIwqiiKocpqJJrNsbnSXXfzp8cexm1Q21Ls4MRghmtIGiBaDUvRAVwUzBuXaTSobG9wItMnqZLubch7q+cI2fzxNe42PgWCy6BHpKGPTsbv1vFr5xGCY61ZUFAOFzAYFm0nlUF+IkUiKHU0erEaVw30hVtc4OFNo719b60IsuhFSR+fq4r7DA3z5oQ6yOcn2Jg9vaG/m2ECInx8a4JnuADVOM+OxFEf6Q9hNKl67kXVOJ5FUBq/NRCqXx2Ey4LEZOTWcJJ7KUuM0MxROkZeQlbLYgVTjMnOsYGnVVmnHY9Osb567ppJEOke3P4FRFWxr8hBJzjxxr3SYed+LVvPybfUoiiCZyfGKLz5e9FwFcJoNpLJ5vHYjbZV22lt9vHJHI22V08M9dc4jpXwIeGjS41vKPGc/8M7Cz08Amy/O2emA1jlUYTcxvojQsEgyy94uP7tbvSUhZlLCcDjFnhU+Hj0zNudxUpkcix02L1QhvRD2dwfY3OAmns4WrQisRpV/ecUmVtc4CMYzrKt1kitcl/Z1+osdzzpXJ0ZVcMfmWr71eOe8O2rnwqwqC7Z3OTcaY2O9qxh0v7vViyIEeSnpCyQYDJ1vDvHZTayotKMqgkwuj0FVGAwlZgweLMfB3hAVdhPJTJ5kJl+StXK8EOBd57ZQ6TBjUAXd43EaPVaODYbJFd7Y5gY3mVyek0MRmnxWalwW9s9xDmKWOcK1wpIVl6WUjwghWqdsvhO4pfDzd9Bu2HpxeRn4/clhXFYjQ6EkFqOK+wJXh3R0dBbPXOnPG+pcxWCemXxbTw9FaG/1MhZNl/hkTaXWZWYofP6mbDEqvHRLPRvrXaiKwFpo+51QagghqHNbqXNbZzqkjs5Vw94ufzHco7it04/NpLK9yc3TnX7ihSJyJifJy/y0AeyKKkfBW1Gyo6V0Umo1qmxudJPJ5jg1FCkpWu9s8aIqgmwuT9dYDIdZxWs3YTepKELBZzcWv9sT1wyXxcjWBjenhkrbZqfaYGxt8vBExzigTR7sZkNx0A5gNCjFtsezw1EtQAz43jvai+39OkuPEKILiAA5ICul3CWE+BTwMrR0tg7gbVLK4Hz2vUinfU2yv8vPsYEwN62q5P23rsFs0BSFX36oA3lwAKDojdzgtWI1qnSORql1WbCbDGRykpFQkv5JM+wGj5V6jwWrSeXsSJShSRPmiUWgLQ1ujvSHWFvrpK3STiqjeaS2t/kYCiXZ1xWgymnGbBCkstNn72PRFB/96VF+cXCA2zfV0jUeLyksA0QK17ThcIrhcIqnzvn5//5wlts31fKeW1axqUEP8NK5Mmn0Wmn0WgnE0wv2Lt7V6iWazJYtUk0E/jb7bPT4Zw84MxtUgvHFtdb3BxNacHciQ+fYwoPU5iJdCDV70YYajg+E+cxrt9HeVr5baaVun3lNMBJOlb2XLJZzYzE2F+5jC91vXa2DaCpHXsK+Lm1Mu6bGQZNP+4wm0znSufy0cftCqHNbaPRa5yxGD4aSJUXtqfPxI/0h2lt9bK53cWQgTO88AjLrXJZiAPi1ynJ7LtdIKQcLPw8BNcv8etckyUyObz/RRUuFnaFQktYKXZmgc22QyeWJp3KX3WLKDSsr2NPmozcQZyA43arv6ECY9jbfrNYZsXRO84Gtnv37PBROYTOpJDI5/mh7I3/z4jV64fgaRwhxG5q3uooW1PmJS3xKl4yZEubj6RyZnMSoqiXhQBOKBa/NWBwgSilpq7RR77ESTeVorbBhNal0jsXY0exhPJaeVtwBikqJCrsJr91ELJ2j1mWhYyRKIJFhd6s2mN5YUEqDZn2xvclT0tHQVmkvGWjbTCqBSYPgTE6yutpRMpCebN0h0VoEP3PXNt2j9eLwPCnlZPnbA8CHC2G5n0Tzd51JaDF1X51lYlerj12t04sub7mhhV8dGeBofxi31Uid24LLaizerycHB01WQDpMKjUuM/u6Amyqd7G92VMM5TQqgkwhZMtsVLh+lY+95/xk81pRa7IKrN5todppQSBp9NoYDCXxx0qLAxPFon+67/iMbcFTkRLuPzLEA8eHeeB9N9Oqq5h1rkDqPVZ+/t6b2N/l59EzY3zzsc7iYspcBGLpaQWkyfkma2udHB3QCmY+uwmDIrTviQSJJJ3LowrBwd4A6QvoED7QG6LBY8FpMRBJLl0L/XUrfLzzOSu4cWUlVpNKLJXFbtbjta5l/u/oED850L/kx83P98YziUQ6h0lV6QtE6ZsUhDc5OPdCEWj3uoWonGdiQ52LvV0Ly1eZj03l1c5Fu+JIKaUQouwnUQjxbuDdAM3NzRfrlK4KpJT85Nl+VlTZ2dupfZHKpeKORlJUOkx6+7vOVUE8neUv7znI70+O4LIYOPCxWy/aa//66BD3HxmkNxDHbTXy8Ts30eSzMRJJ8oXfn2UwlCSdzRdVhpvqXZwajpCZMhDN5edOcgbw2c3AeeVypcPMB29bS5XTTPd4nK7xGLaCOllXI+kIIVTgi8CLgD5gnxDiF9eaD2Q2l+e9PzzA0VmUFUPhFIlJvqRGRbC+zoXVpHJmOMJQOImUFJUN8XS+qGhSBDgtBh7vGEcILTTvme4A5eab47E0Qmgq51AiQ4PXRqVT82Vv9FrpGouRnmSjM1VZ7DCrxaI3aMXoqQPnqW14U683b76+lc2Nnhn/FjrLh5Tyt5MePoUWEqZzmfLUuXFODEaodVnw2gycKLNwBJoK8vSkhaloOsezPUFWVzsYCCVpqbCxo9mDy2JkPJbCbTUQTeYQQhBP5Zhsq7ytycNwOEl/MIlBVTjYF6TeY0FVBE6LgcFQEp/dSFuFndPDWofEjmbPvAvLk8nkJPcdHuC9z1+98J11dC4TJhaHcnnJF/5wdl77dIzG2NLoJhDXxgWvb2/iV4cHi79v8dlYU+1ACMHxgRD+VO6CwrJnotpppsppoT8YXPQx2lt93Lqxhg11LhwWAz/e38c/vnxjSV6DXljWWS6ODYTZ3eqlP5goK6KaieODIRxmQ9F2bilZVe3AYzVekOoZwGxQ2Nro4fjgwm1EKmbwcr6WWO6rzrAQok5KOSiEqAPKuvBLKe8G7gbYtWuXbha8ABKZHAd6AuRykl0tXkYiqZIUTCklQgj6AvGCqbmuWtK5ssjk8pwdiXJ8IMyxgTDHB0Mc6w8XlQoN3oun0j3aH+K9P3y2xD/1DV9/irt2NnHPvt6yHslHB8LsafMxHkuTyubwWI1Yjeq8/eImjqkIuHNbAx+6fR01LsvSvCGdq5F24KyU8hyAEOIeNIuqa6q4/JNn+/n1saEZf68ISr6vK6vsDIaSHC4Uo1srbPinBJ70+ON4bEaC8Qx5CaGEdg2SEvZ2BWjwWHFaVE4ORVlX6ySTy5PK5qh2WjjaH6Kt0l5SFF5X6+DUcHTWAtFUb8imebT6aed0/qBGVfD6dn3h/iIhgd8WxBRfLYxvJ/N24N5F7quLMS4Cz1tbzc1rqnj49CgNXit1bjODodICU53bglqwmAolSovPZ0Y0FdaqagfJdJZ4OofZoPLYWT/PXV3Jo2fGkIDLYmB9nYuj/SGe7QliVDVf+FqXhSqniWe6gwwEkzR6LNywooIj/UGemaSa7g8maG/z0T0WK9p3zIbDpGI2qjT6rBcU5qSjczmRmGdwZbXTzKYGN2trHRhVhXW1TtbVOqlzW7EVbGyuX1lBKJHhnn29KIoC5DCpCuvrXXSORgkvkcp4LJqat/95g8fKa3c3sbHeha/gIXu4L8i7n7uiKBjL5yUNL7SWDQLWubaxGJfPBm1fV4Ddrd4FFZezea1D4JkLLACXoy8Q5+zI/IRbM+EwG3Ba1AUrlnXOs9zF5V8AbwE+Ufj358v8etcEk9tcpISnO/1Yjedbe3+0t4d33tSGQdVCiIyq4LtPdvNvr9QzJ3SuDIZCSR48McyDJ4Z5omO8RNU3lZtWVV2083q2JzAtmKvXn+DTD5yedb/JXqm9zC+kD6DGacZpNvB3L1nPy7fWU60XlXXmpgHonfS4D9hzic7lkmE0zD7JqnFZSrzWDIpSbI21GpWyvsSKgFxu5mtRfzDBnjYfdW4z4USGgVCSTfUuwskMK6oc04rCQ+HUrIXlTfWuaQPwOreV3sA8fN/cluLzMjnJvi4/N6ysnHM/nQvmJillvxCiGnhACHFSSvkIgBDio0AW+MFC951AF2MsP8cGwvz+pKaFeaY7wK4WL0OhFJP/2C6rpkY+OxJjXa2WKj9hjeMwq6yrdXF2OILXbsIfS9PgtXHjygp6A3F2tnhJZHLYTCpPd/pp9tnY4rEwFNZCQEcnFYpNBoUGr429XeNMHQZN+CnvafORyeeJpnJsb/KQl5JsTpLI5EhmcqiKoMJh5mh/iPFYmvFYmg++eN2y/g11dJaCcDLDg8eHWVvrZGO9m3xeIgQlXbi5vJw1XOzN17dw1y6tODu1ezeczHDfoUFODIZZVe3g6ECILU0e2qrstLf5CMUz/HBvD996vGtJ31deQsdolD1tPs6ORBmPpUvsOUAbb/zRjkY+fucmrKbSjuTrV1aUPFYK33Ednaksh6/3ZGYKpZ+N5DwXhBbK1kZPyXx7Mfjspjk912fjt8eG+Ph9x7lxVQXPX3dtugEvWXFZCPEjtPC+SiFEH/APaEXl/xZCvAPoBu5aqte7lslOmtw+dnaMSoep5Mvtj6UZCidp8FgZi6bI5ST/+LKN025OOjqXG384NcJXHupY0M3hplUXr2CSvQCPtYVQ6TDzim31/NGORjbUuy7Ka+pcW1ztCsjJheNyVNhNxedUOcwlvsvr61wlvqoT+Owm1tW6SGZyBBMZ+vxxklMqPpqNRkpTc4SSHC20DpZTG7f4bATjpW13NU6zlkzttdI1Hp82YY7Pc1C+tytQ4vn64PERvbh8EZBS9hf+HRFC/BStk+ARIcRbgZcCL5Cy/JLCTPtelBPXAeBQb5D3/ujZkm2qIpj6HzYRuLmrxVtswV1f68BhNuKPp4vbJrof+oJJtjV56ByLT5vs20wqT56bPuZp8FqpdVqQyGmF5ckkMzkcZgP+WGbGsVPH6HlrrdfuauKGizhu0tFZDPu6/LzpG0+TzOT5t1du5t59vRzoCfJnt6xkXa2T7zzRxYduX88/vnwjO1u8fPSnR8oqix1mw4yWcS6Lkde3NxFKZLAYVQ73hbj/yCDffqILVRHUeyzzCvFaDGPRNGNR7fva3ubjYE+Q99yyki891MErttXzkTvW64ISnQtGXWYxezixcDX/sYEwWxrcxU7BpSK30ITPMqgXKPTO5CTfeKyTnx/s5+fvvYkGz7WXgbRkxWUp5etn+NULluo1dDTcNhOgrbj+8tAAihAlA8dUJs/XHjlH13icx86OsbLKzm/fd/OlOl0dnXlxz94ePvSTIwveb+NFLL6uqXEu27FNBoVbN9Twqp2NPGdVJYYLvcPpXKv0A02THjcWtpVwtSsgn+wYL7t9dY2DeCqHEFpCdddYjNFoiiavpgiusJvKFpZBmwwG4mmODYQxqgKvzcQKh4njg5MDAbUq0PGBMBajQjKTZ19XgLU1mgXGZKYmShsUcFgMJKIpcnk5zZPOqApOD5UPKJxMjdNMpdPM4b7zA/c/nBrhYy/bMOe+OotHCGEHFCllpPDzrcA/FwI2PwDcLKUsK4mZad+Lde7XKvm8RAK/OjLI957sKrsI5I+Xt7Da2ugu8XY8MaR9v80GQZPPWlKUclsNnBudHlpU6zKTzpYuGFmMCquqHThMBp4qFIufu7qSzrFY2a6F/mCCRo+NnnkWwW7deG2qqXSuLCwGlWRGu5/++/+dKAbfvecHz+K2GgklMhzqC3F2JIqUklh6+sLry7fW8xcvmNlb/PRwhJYKGx6biU/++iQmVeG/92uNX7m8XLbC8lSC8TR/++I1vHhjHVsa3dy2qe6ivO7VjhDi42i2cHk0a9a3SikHJv1+N/Ak8Dop5f9cmrNcXqqcpQsU25s9BOMZ7GYVm8nAmeHIBdkkNXgsDIXnb4sxgXkZ7DomB1kvFuMSzb0/8OJ112RhGS5ioJ/O0tM5GsWgiJI2GoB0Ls93nuwGNFPyQCzDSDipr4DqXLacHYnyj788tuD93FYjHtvF8xHf3uzBalTn7fE2H0wGhT+7eSVvv6kNt1X3RNe5YPYBq4UQbWhF5dcBb7i0p3TxCSUybGvyYFAFihBksnlMBoVnujVrm/5ggk31LixGlW3NLtLZPL2BBOFkhvY2H3tnUABOFIQzOclIJEWTr3TwOBH+E0vn2Fjv4tiAVgyucJjZbTFqUdYFBJqnsvazwKQKMnlJndtCJidp8mmp0ycGw4STWTbVuznQG5zzvXvtxuLrThBeROuizoKpAX5aaL02AD+UUv5aCHEWMKNZXQA8JaX8UyFEPfB1KeUdM+17Kd7EtUAwnuYrD3dwoCfIsYFwcSHHbFDY1uQhncvjj6ZQFQWn2YDVqJDIlMqHy1nnAKSyErfVSC8JTAaFdDZPKJGlxmVmU72LA30hEukc7W0+hkJJMnmJQRG0VdrJS4ndpHK4P8zOZg/tbT7yecmxgTDZvGRdjYOxWJpUNs+KSjsmg4LVqDIcTrG92cNYNDVjQcxiVLh9Ux3PWX3xrMR0dBZLc4WN61b4eOqcv1hYnmCiW/fgLPfDtko7H33J+mmLuJNZU+MkEEvTH0jwqh0NGBSFW9ZW8cuDAzxxbrxodTMTTrMBCSULwdubPdhNBk4MhufMVtnZ4uVdz2ljZZWDtko7Z0eivHhj7az76CyIT0kp/x5ACPEXwMeAPy08VoFPAr+defcrny2NLmpcZpp9NgLxdLGbbYKtTW7q3BKTQZDJSU4NRabZP87GMz3BaYup5WitsFHlNHNqKEI4mV3yTuAWn9btdyHYTCpdY7G5nzgHO1u83LW7ae4nXqXoxeUrGJNB5ZeHBmZs96l3WzAZFLrG44STWar17nqdy4hUNsdvjg2zr9PP/UcGiwqFhfCXL1g9zUNtObGbDXzgtrX80y+XJhttU4OLL7x+B63zDPbQ0ZkLKWVWCPFe4DeACnxTSrnwlZsrmFAiU6LanYnRSIrNDW46RqOMR9NUO0w0+WyzerxPFjUIAd1TBrO9gUQxCXuyFdV4LIVAzDlZLUe920I0lS3xYl0otW59cXm5KYRobi2zfdUMzx8A7phtX52lQUqtQPvRnx4hnZOMRpLF8OutTW6O9oVQFEEqm59mLbGiyl72mjAcStLosdI3Jch3S6M2Jt9V8FYWaDY92ZzkiXN+tjW5MRmU4gJWe6uXOpeF/mCCkXCKldV21tc5SefyHOkJUukwsaragT+W5txYjHROcsPKCp4o053R7LOxoc6J2aASSWWpc1mocJoYi6R5/61r2NHsXYo/p47OsiOlZDi8uHuez27iB+/cM6/wa6/dhNduKj5uxc76Ohf+WJq7HznHob4gmVye3S0+1tY6CSYy5PKSm1ZVYjOpPNMd4N79vZwcjPDZ121jR7OXKqeZZCbHTw/08/uTI6SzeQ72Bqf50758az0v3ljLzw8OcLA3yCu3N1zUOc3VjpRy8iq7HUocjv4c+F9g90U9qYtMo9eGIsSMQdCHekvHymtrnDgsBjrHovhj2ufVZlJpq7TjMBuQUgu3nqxWrnOXLy47zAY21GtWcsf6Q3SNxzGpghtXVixpYF69x6INyC8AgyJo9tkWNUafyvPWXtsLuHpx+QqmezxOTsJoNIXVqJKXktSkAXCTz1YcJPcG4qyqdlyqU9XRKXJ2JMo9e3v432f7LqgV54+2N/C2G1uX7sTmydtubMNhNvAPvzg2rWtgIbxkSx3/+eqtuhe6zpIjpbwfuP9Sn8el4szw7IPDaqcZj83I6eEow5EUNpPK6hoHRoPCMz1BVlbNtthzfgC7s9kLAurdVsZiKZKZPBV2E8lMjnW1Ts4MR6koTFpPDUWpdpoxGwSp7MIVGzuavSUt+Aulzn1ttufp6AB8/+kenuwY49CkRacNdU6iqSyHe0NIIDeDkqrCbuLc6HQ1UzKbJ5XNU+kwsbLKwfGBEPUeKxajOmPnA4DZoJYUsPd2BTCqgtYKO5l8kpNDUXw2I6trHPjsJurcFjpGo8ViOMDR/hArKu2cm6KymhxEJIQ23nrRhhq+8/Z2VEUvWulcGQRiaZ7tCdC5CBXhdSt8fOa12y7onmcxqtR7rPzjyzcWt6WyObI5Sfd4nEQmS73HSpXTzOoaJ6/e2ch4LF1SzLYYVV7f3szr27VMi1xe8qfff4Z9XX4q7CZ6AwkeOzvGW25o5RXbGxZ9rjqzI4T4V+DNQAh4XmFbA/DKwuOrurgshOALb9jO3/3sGCcG57ZVm5w/Uu+xkC106U3uhrMZtQ4fRYAiBAZF0N7qJZrKMVJYuK11W7CWuRemc5InOsaxmVQyuQvvAlYFeG2mad16C8FqUmn0WJeksAxw4zWeaaAXl69gBkPaKtFgMMnuNi+BeIYzBU/HHc0eDvcFi8/9wVM9tLf6sJv1/3KdS8NgKMGfff/ZWdvY5svr25v45zs3XbIV/tfsauL6lRXc+YXH52x7m4rTbODPnreSP7t5pa5Q0NFZBnr8cbY1ecjk8iQzOc6NxhACtjd5GQglaPRaS1Qc8XSO44MRNhX82/sD2nP6yvibnh2OoiqCXF6Szctp1zN/LE2d20I8nZumUhqJpNjT5ltwmrVRVS4ovRo0XzwdnWuV1+1uwmUxcP+RIRQBq6oddIzGaG/1IYHWCjujkVRxctngsdLss5LOSaSUtLd5kRIMioLVpDISSVLlMPNsT4CxaIaxqJ8dzR6e7QlS67JQ6TDP6P84Wma712bCZFBoq7RrBTUBeQkOk8qR/tJJc63bQovPxsky/utWo0q1y8yfPHclDV4rHSNRbt9cqxeWda4Y+gJxbvrkHxa8n9tq5OY1VXzqNVswG5ZetGE2qJgNlA3ZNqjKnCppVRHc/aadJDN5rCaVwVCC2z/3KL3+eNECS2fhCCEeBMp5iXxUSvlzKeVHgY8KIT4MvBf4B+CzwAellPm55mFXQ/j1zhYfP/t/N/DHX3t6QSKFgWB5L+V4Jj9t7LunzcfxQvHaYlAYmiVUWwIrqx3z6jCciy2Nbg70XthxNtW72NcVoMJuWvCcfirVTjPbmjwXdIwrHb3SeAXTWmkvTJg9JDN5pIQqpxmzQeHYQKhEHfXgiWHe9d39fOa12+bVJqSjs9TUuiy4LtBTuMFj5QO3reXlW+sveWG20Wuj0mFe0I3oJVvq+OSrtuDQF3l0dJaN4wNhesbjxSCuOpcZr93MMz0BalxmbCZDMcBvAp/dWFRJJbN5al0WBkPJaenT/ni6mHLdMVJe5dDgsZYdwLe3eRdcWAbNe/LRM2ML3m8y9ddosIiODmgtr1sbPfzVC1dz3+FBvDYT9R4rn33tNjyFkOzfHhvi1FCE/mCCx8+O8XSnn0avjR5/nNYKG9FUlmxesq3Jw9H+MNe1+Wjx2RkIJVCEQFUEb7+xla7xOAcn+VqurXFiUAU2k4rZoJLK5DhHqSJzJJJiJJJidbUDAfhjGfyxAO2tPnoCCaqcJlp8dgyKwGwQPHxmnHKWzzaTSiKd49Ezo3z5jTu5ec213Z6rc2URjGtWFHOxu1Xr5BHAW25oZUOdi92tPloqbJd8bjAbQohit2Kd28oNKyv45K9P8oU37LjEZ3blIqV84Tyf+gO0jr5/AHYB9xQ+K5XAHUKIrJTyZ2WOf1WEX5sNKl95007u/MLj9AeXPqjy6U4/7a1e9nYFSM5iLTeBdRYv9PmypdHN2ZHFeSQ7LQbW1ToJxNPsL4hNKhwXVlxWFcFbbmi9rK9BFwO9wnEFs6vZy6oqB99/xx5+dWSQv/2fw8XfbWvyTFtVeqJjnKfOjXPnNr39RufiI4TgYy/dwG2ffWRaWMCGOhcfuWM9tW4zn//dWX5xaKDsMd5yQ8tl9fnd3uwpaSGajbZKu26DoaNzEbCZDbRW2vD3aIPEwXCKxoIyaDicYjg8CsDWRjdOi4FzYzFsJgNnR6LFY+zvDrC2xsFwJEVwBvueDfXuacVigyKwm1S8NuM02594anEtgF1j0bmfNAd1enFZ5xpGCEFrpZ33Pm8VL99aT1ulfdoE8Ja11fxwbw8VdjOv3N7Ae563ijPDUf7ingOMRZKYDCrBeIYDPUF2NHswqgKXRcVpdbKnzceaagd/9/PjjEVTVNhN3LSqAn8szcmhCHmpLTr5Yyk2NbhZVbDeMagK0WSWkUiSdE4LVdpU78RoUDk9FGEkkmBdrZNqp5lcLo/NrJKX8JxVFXSPJ2ittBFKZAjE02Tzks0NblKZPK/Z1Xgp/sw6Oovm0TOj/MWPDszLLu9N17cyGEryvhetYVW1g1VVjiuyM/dLf7yTU0MRUtncsqitr3WEEKullGcKD+8ETgJIKdsmPefbwH3lCstXG5UOMx++Yx3v/eGBZTn+3q4Au1ouzMJtvnhtRk4ORWbNSJmNFVX2aT7UiczibToMiuCrb9rJC9bXLPoYVwtX3pVYp4gomI8f6Q+xu9XH7lYvh3pDpHN5pCy/uHZiMMKd2y7ueeroTLCq2sEHblvLv91/sritpcLGvX9yHU6Lpmr+3Ou2YVAEPznQP23/2svMN/RDt6/jwRMjM7a/TmAyKHz6Lr2wrKNzMdjS4ObJjlKlr6IIdrd6kVBUKRzqC9He6mUgmGRXy/Sgq+FIqiTHYAKn1cDOFi9H+oK0FxRUeaklRJ8eCvPwmTF2t3pnDFBZKLnFjZ1LqNcD/XR0MKgKK6rK54+YDArfflt7ybbNjW4+9tIN/Pf+XsYiSRQhcFsN2EwG3n/rGrY3exmPpvinXx5nb6ef6v+/vfsOj/Os8j7+PVPVe7EsS5ZcYzuO7bglJIQQ0kgCIZSE0EINsMvC0kNZYCn7wrL03QVC28DSSyBLDxBSKHbsOHGL495lFavXaff7x4wUyVbXSKPy+1yXLs089Twz80w5z32fOztAOBLlbEeIrlCMvTVPX3xu7gxx0YI8nIv/yP97vwtTeRl+NszLJurig4aGo46lpVnkZQSIxVy8xWOal55wBJ/Xh89jLC3JpLU7TF5GgOXzssnPCHDl8mLSAz5WlmkEb5lZIjE36nFYLpiXzXdet4l0v3fa/S4Yq+XzslMdwmz2STNbDsSAY8CbUhxPyl27ch6fv20tR892cM9fj05o7KNzFWUF6ApHRrXsROobZ/g9FGcHaaodX8OLdRV57DinAebCwozzBugerYWFGfzHS9awsapgXOvPNkouz2CdPRE6QvFBBSoKMvjxm57BVx88xP/7zT7yMwJsWJjP/ro2qosycTFo74mMmAQTmWx3XrGY0pw0vv23YzR3hvjCS9f1JZYh3sLoIzev4s/762ns1z2luiiTq1eUpCLkIeVlBHjVpQv57P37z5uX5veQnxFgYWEGb79ao7SLTJXf7TlDQ3uIqsIMjp7tpCI/nW1Hm/pKXCwvzeZAXRsFmYG+xG203wXZvAw/83PTKcoO8Nix5gHbDvg8HKhtp64t/lm6NVGnbXFxFqdbumhLtE4+t5xGqqkshsj4PPuCEq5cXsyBunZau8J0haNUF2WyID+DB/bV8vYfPYHHjPK8NHxeD+YxctJ8OAa+B3SEon09HZaXZrGuMg+/xwMWHybU44FINN592YjR1Blmx4l4L4vN1QV4PF7aemJgEY6d7SAcjdHSFcFr8ZqazRlh/naogaLsNCry05mfl86h+nbauiN0hKK88pKFXLNSrapk+qht7eb9P9tFZtBHfdvof59+b8tx3visRTM+sSyTyzn3olEs8+opCGXaCPg8fQNILi7O4u0/fPy83sRjVZIdpCAzwFNn2gYMPDucpSVZw7Zwzknz0dYTofer+ar5OWQGfISiMbKCXh45eHb8AQ9StSIzML6UaMDr4Vuv3jjkReu5SMnlGawoK8jnb1vHvH4tkspy09hYlU9bT4TtiZM2HHHsrWnl1g0LyEnzE405De4xR5nZGuArQBZwFHi5c+68UWHM7CjQBkSBiHNuQzLjuHlt+bDlLXLS/Lx4/YIBtddesLacjHG++U+mdZV5fbe9HuPNz1rMyzZXKpkjkiJ/3l9PfaJ+KcCJpi6Wl2ZzsL6daMzxVG0by0uzeKq2nYb2EOsX5vd9XkK8h8W2o01QAwvy0ok5R3c4Sprfy/qF+RyoG9ha4mxHiLMdA8tjtHaPrvXGVCnJDqY6BJEZoSsUpbU7TE1LN00dIczi45nkpPlZXJzV9/3ZOccf99WRFfTR2h1m35k2FhZm9JW/CA/R5eCCedlkp/mG7NlQlpvGvNy0AWV6epPSRVkBOnqizMtN66sRH3Ww9Wj/95/zB/oD+OjzV431oZhTzMwLbANOOeduSnSXfxbQO1rUq51zjw+y3h3ABxN3P+6cu2cKwp0VSnPSuGJZMR++b8+g8/1e4+oVpdy2sYILy3Pp7Imy7Vgjdz90mLbuCJ+5dc0URywyezxvzXyWlmbx8q9tmVCt4ew0H4fq2xlLitozRF3iwswA1UWZbD/WRHF2kMqCDJo6Q+w5/fTnWn6GHzMYopP+sOblpHFikAGyR9vi+lyvuaxKieVzTL9MjYyax2MDEssA2Wl+/vvl67jjm9v6pvUOHuYcrKnI40RjJ1VFmVMaq0wbXwfe5Zx70MxeC7wb+Jchln22c25io0hNwKpzRmQ+VD/xuqOTobdLW9Dn4Yu3r+O6VYMNWiwiU6GlK9zXAupAXTvrK/PYfryZp2rb2FxdwJYjjaytyCMz6OVwQwcXV54/yF7/r7wn+w180hmK8vCBBvIy/JTlxgf8G8rBunY2VRew43gT4WjqWzFPs4bUItNCVyg6oFzVDx89znt/uqvv/qr5ObR0hTmZGPyzLDeN/IwAJ5s66QpHcY4Brb56BxfKDHhJG2LAotx0/7ADexZmBth7emCCeF5OGhUF6URijmjMEfR56OiJ0BWO0jaKC1lrK/ImPKDyHPA24Emg/5fPdzvnfjLUCmZWwNMDhDlgu5nd55yb/KKjs8TLNleSl+Fn65FG/rSvjpqWbj7+ggsJRWI8f+18irL6XRjNig9wu6w0m58PUjpPRMbmgnk5fP/OS7jlv/5CR2h8NYfrWntI83sJR0eXoF2Ql05Na/wzNTvooz30dAvlwqxAX4vm3oFuz9XUGWbNglyeONly3ryRVBZknHMxNm68vQ2fu7psXOvNZkouzzKXLi7E6zFuvKiMIw0d9ESi1CdKYfz0sZO8+crF7DvTpuTy3LUMeChx+37gdwydXE6p/qPZegyuXTU9u3MWZwV55tIiPvy8lSwpUe00kVTKDvrICHjpTHxJ7v91ccuRRtYsyO0b7Pbiyjx2nmyhIDOAc/F6jyXZQUYa6Lm5M8yyqqxhk8sAW480kh30sqw0E6/HiI2nmUWShKIxAj5PyvYvMh2lB7x09EToDEXJTfez43jzgPl7TrcyPy+NTVX51LeHiLl4T8CR5GX4yQz4WFKS1dcC2WPxizz9L1idywwygz4WF2diBl2hGLWt3ZxJ/AFsqi5ga7/k9EULcukORzl+tpOeSKzvPe/6VfO4bWMFayvyyM8MjO2BmWPMbAFwI/AJ4B1jWPU64H7nXGNiO/cD1wPfT3qQs5Tf6xnQm7ErFCXg8wzbw3ZRcSbvuHbZVIUoMqstK83mw89bxXt+unNc61cXZ7JzLIleg55wjKWlWRyobac4K8jCwgxau8PsH2Ud5TMt3aT5PXSHRz8oSU6aj5qWwT9/5+Wmc7xx6M/mwZTmBOnsmV69FKcDJZdnmd6WEjesnkdFfgb//MMdHGnoYFlp/AvuB+7dxXNXl9HSFSI3XV8256A9xEfM/TnwEqBiiOUc8Hszc8BXnXN3T014TyvPS+c1l1VRWZDBM5cWTdvErZnx7dduOm/keRGZemYDWx6fe17W9xt34LFEIqkrHCUz4KUwM0BBhp+tR0ZudDba872tJ9rXne/C8tQNshWKxECVMUTO87PHTvHvv9tHdzg6aC+D083dnG6OJ3b9HmNdRR5ej7GnppWuc1p6baoqoLU7hHPG7tOtZAbipXTausNk+D00dYYpzk7jVFMXi4oyyU33sePE0z/K11XkDduqeWNVPgdqBw6E1P9H/YL8dK5ZWcpfDzbwny9bh8+rC0qj9HngPcC5XzQ/YWYfAv4I3OWcO7cZXTlwot/9k4lpMk6jGfh6OpbIE5nJnrGkkNXluew6Ff88qSzI4MaLylhdnssvHj/Fmoo8esIx8jP87K1pJeDzEI44OkIR/nJwbJ2cTzZ1ccG87L5B/erbewZ8Nx+N2rYe8jP8IyaXzWDNgjy8Hthf286JpvMTyCXZwQEXbEeyqCiTtz5nKTdeVIZfn7Hn0bvzLFVdlMXCgkyisRjf33qCjKCX+rYe/na4kYb2EL/ZdYZvv26TTopZyMz+AAxWm+EDwGuBL5rZvwD3AUMVWbrcOXfKzEqA+81sn3PuoXMXMrM7gTsBKisrkxJ/r5HqMk8nSiyLTA8f/PnuAV37orGnv3j6vTbkoB0doSjOObDRZWAP13cwPzeN0yO0Xp4uQpHRt+4QmUv21rSyoixnVD8uwzE3YJT5jVX5+DyexOB6YXacGFgGpyMU7avnnpvuJxSJcizROup4Ywe3bawkM+invSfMkuJssoJedp1q6dtGVtCHx+Llt5bPy+ZsWw/NWQGaOsNA/Ifzs5eXsKQki6rCTG5cXUZuhspfjIWZ3QTUOee2m9mV/Wa9DzgDBIC7gfcCH53Afibt+7KIyEQsyM/gntdu4mRTJ/Ny0yjOCvb9tr1hhNIPT9a0cud3tnFiDC1/JzqIYLrfQ0tXeMj5QZ+H7DQfpTnBvt6KQ6lr62F+XlrfReSheAzecc0y7rxisXoCDkPJ5VnM4zGCfm9fbZmNVfk8erSJA3XtHKhr5zXfepQPP28li4qz2HLkLNlBPxeW5yhRNsM5564eYZFrAcxsGfFugINt41Tif52Z3Qts4ulyGv2Xu5v4l242bNigqp4iklK9rS56HazrID/DT1NnmHDUDds9fFV57oBBtubnphGKxgYd6KSho4dNVQXUtI4+uWzYiCU3Bl3PGNV6vcsMth8ll0XO98udp/m/J05TkhOkNDtI7SD1HYeSm+6nOxxlzYJs9tS0cqShY9AfzAvy01hbkU9m0EvA6yHo89ITiTE/L43jZzspyAxwxdIiblpThsPITvdz6aJCVs3PHTRR3NwZYt+ZNvbXtrFqfg7rFxZM6DEQLgOeb2Y3AGlAjpn9r3PuFYn5PWb2LeBdg6x7Criy3/0FwJ8H24m+L4vIdFaQGaBgHCWUVpTl8OWXr+fdP9nJk6MoGwVQkDGx3vNd4RgXV+b19UDslR7wsqosh23HmuhpD9HQPrqBCivyM/qSy55Eear+4xnkpvv50u3ruGJZ8YTinguUXJ7lrlpezL/ctJKP/2ovta0DvzQ/crCBaz73ENlpT59A77l+Of9w5ZJUhCpTwMxKEgljD/HRrb8yyDKZgMc515a4fS0TaK0hIjJV0v1eNlUXcLyxk6LMAJlBH+n++OB9xxs72XWyecDyvWU0SrLTOFjXjlm8BuRnXrKG6y+cp949IrOQc46P/fJJvvmXIwC010dYvzB/2OSyGdxwYRmLizN59WXVZAV9A1ovNXaE+MYjh/n9nlqeu7qM081dNLT3sOtkC4uLM3n7Ncv7lj3d3MWf9tXxl0NnOd3cxUULcinIDJLm9/LOa5cPtvs+eRkBLllUyCWLCif4KAiAc+59xFspk2i5/C7n3CvMrMw5V2PxFjcvAHYPsvrvgH8zs/zE/Wt7tyUiMldcWJ7Lz//xGbz/Z7v56WMnh112Q1X+oIPqjdVjx5tZUZbNyaYu0v1eyvLSqGvt6RsQcCzObQX94eet4te7avjTvjoWF2fyjTs2aryyUVJyeRaqa+vu685w7+Oned3l1Zxo7CQWi5GbEeBLfzo4YPkNC/No74mPOP3Q/npuWl1GZaFOoFnqdjP7x8TtnwHfAjCz+cDXnXM3AKXAvYkW7D7ge86536YiWBGRsSjNSeO+J05jgNcDu08/3YqiIDPA0uJMtvRrnfyKzQv5wI0rCHiNtp547eVw1I2q7qOIzCx1bd185nf7+eO+OhrOqfH42PEmNlXls/Xo+T9MCzL8PGdFKZ9+yZoht12QGeDd113ASzdWsiA/fdhegPPz0nnFJQt52aZKIjGnLrbT03fNrJj49cfHgTcBmNkG4E3Oudc75xrN7GPAo4l1Pto7uJ+IyFwS9Hn5zK1rWFaaxSd/u4+hxrBOZk+6zEC8gWRbd4S6MfQ86i87zddX/xngkkWFlOWmkR7wEvB5+OBNK5VYHgMll2eh/nVynr9mPgDvv2EFZ1q6WZCfztUrStly5Cx/OXiWzlCERw6eJRx1LC7OpLa1h3/43mP818suZqESzLOOc+4LwBcGmX4auCFx+zAw9C8oEZFp6ujZDiA+Iml5bganmp4uW9HYEWJfzLFhYT51bd0sKsrizisW9Q2Em5seT/D4lFcWmXXOtvfwtYcO88NtJwad7xyU52dwqcfDU2faaOx8ujvtouIsls8b3aDCFQUZo47J4zECHpWimy6cc38mUdbCOXfVEMtsA17f7/43gW9OQXgiItPeG5+1mJvXlnP/3jOcaOriqTNtbD3SSFc4Ph7KzpMtLC3JorU7TH5GgEP17YSjDr/XBh1UdzjbjjWxtiJvxLrKw+mJxPB5oDfnfai+nabOEHddfwFfuG2tBsYdIyWXZ6H+rSUyg/GnOODzUFkY/8K7piKPNRV5rC7P5ZuPHCEj4KOlK0x2mr/v5Lzlv//K996wmQvmpW50exERkbF4xuIidp6M113unxzq1dIVZtuxJrwe45+vXjamRJDISMzsKNAGRIGIc26DmRUAPwSqgKPArc6585rHmtkdxMtVAXzcOXfPVMQ8F5xo7OT99+7i4QNPj2r/3AvnUZqThtdjrCzLYU1FHkcbOsjL8PGlPx2iuSvME4nvxKU5aVx1QUmKohcREZk55uWm8cpLq/ruN3WE+NZfj9LSGSI3I8CjRxrJy/Dz6NEmLpyfQ2bQx2PHm9hYlc+xs50DWiGbxWse56X7yQj4aGjvobEj1DfGwUSvz0aiMUqygxRlB3n95Yu4YXWZehNNgJLLc9ili4u4dHERt331b2w50ojf+/TZ2dgR4nB9h5LLIiIyY6T7n252fLCuncXFmRyq7xiwTH6Gn2++eiPrKvPPXV0kGZ7tnGvod/8u4I/OuU+a2V2J++/tv0IiAf1hYAPxhvfbzey+wZLQMjLnHHtOt3KmpZtHDjbwk+0nae+JkB30kZfp5/lr5vPay6opzAoOWG9JSRYA97y2kFjM8a2/HuXJmlbec91ySnLSUnEoIiIiM1p+ZoB3XLOs7/6+M62880dPAAPL1z16tInN1QXUtfVQmhPkLVct5YYL51GQGRjQeLKpI8SuUy2YQVt3hB3Hm/jaw0fGHFdxdpCrV5TwgrXlbKouGLaclYyOkstzXCQa66uJ09AeIiPgpTMU5fZNFTz3wnmpDU5ERGQM5ufFE0DPWFxIXoafWzdU8IZvb+vraufzGC/dVKnEskylm4ErE7fvId7t/r3nLHMdcH9vvVYzux+4Hvj+1IQ4u7z5fx/jr4caeNWlVRyoa6MzFB+0+kPPW8m1q+aRm+4fcRsej/G6y6snO1QREZE5xecxSrKD7Encz8/w09QZH1TP7/XwT1ct4c1XLiYjMHiqMj8zwBXLivvu37C6jOLsIP/26319208PeGnrjgy6/mVLCrlmRSkv3lBBVlDp0GTSoznH/X5vLVuPNnLLunLecc0yTjd38R+/f4rXXlatqzciIjKjXLGsmN+87ZlcMC+77zNsRVkOO0+2kJ/h58dvupQlJaOrnSoyDg74vZk54KvOubuBUudcTWL+GeKD5p6rHOhfDPhkYpqMwxuuWMS7r1/O4uJES+S/HuW+J06zuCRrVIllERERmRxLSrL51ms2sf1YIz3hGD6vhx9sPc5LN1WytCSL/MzAmLd55xWLuXxJMTHnWFaaTcDn4Te7avj2347xt8NnKctN45Z15dy2sULjik0iJZfnuOdeOI9PvWg1N140n6ygj4qCDH78pmekOiwREZExK81Jo/Sc7uv/dNVS9te28cpLF5KTpsSSTKrLnXOnzKwEuN/M9vWf6ZxzicTzuJjZncCdAJWVlROLdIZzztHcGSI/M3jevPULB/ZMeNWlC7l9U6XqKIqIiEwT6xcW9N3eVF0wzJKjs3L+wHKuz11dxnWr5vGHJ2u5dpV65E+FKUkuDzbAyVTsV0ZmZty2cW7/QBERkdnrmpWlXLNysMaiIsnlnDuV+F9nZvcCm4BaMytzztWYWRlQN8iqp3i6dAbAAuLlM87d/t3A3QAbNmwYd5J6NjCzQRPLQy0b8Kk3noiIyFzi8ZgSy1NoKi/hP9s5t1aJZRERERGZTcws08yye28D1wK7gfuAOxKL3QH8YpDVfwdca2b5ZpafWPd3kx+1iIiIiMjEqSyGiIiIiMjElAL3Jmp9+4DvOed+a2aPAj8ys9cBx4BbAcxsA/Am59zrnXONZvYx4NHEtj7aO7ifiIiIiMh0N1XJ5cEGOOmjGnIiIiIiMlM55w4DawaZfhZ4ziDTtwGv73f/m8A3JzNGEREREZHJYM5Nfsk2MyvvP8AJ8E/OuYeGWLaeeMuOyVQENEzyPqajuXjcM+mYFzrnilMdxHiNcO7OpOdhtHRMM8NUHNNsPneTKdWvr1TvfzrEoP0/vX+dt+OT6udwomZ6/DDzj2Gi8evcTa65/npKtbkS/1w/b6fr8zwd45qOMcHcjWvU5+6UJJcH7NDsI0C7c+4/pnTHA2PYNhdrP8/F456LxzwdzcbnQcc0M8zGY5qpUv1cpHr/0yEG7T/1r4GZbqY/hjM9fpj5xzDT459tZvrzofhTa6bHP1Wm6+M0HeOajjGB4hqNSR/Qb5gBTkRERERERERERERkhpqKmsuDDnAyBfsVERERERERERERkUky6cnloQY4SbG7R15kVpqLxz0Xj3k6mo3Pg45pZpiNxzRTpfq5SPX+IfUxaP8yUTP9MZzp8cPMP4aZHv9sM9OfD8WfWjM9/qkyXR+n6RjXdIwJFNeIprzmsoiIiIiIiIiIiIjMfJNec1lEREREREREREREZp9Zn1w2s7eZ2W4z22Nm/5yYVmBm95vZgcT//BSHOWFm9k0zqzOz3f2mDXqcFvdFMztoZjvN7OLURT4xQxz3SxLPd8zMNpyz/PsSx/2UmV039RHPTkM8D582s32J19i9ZpZ3zjqVZtZuZu+a8oBHMJbjMbMqM+sys8cTf19JWeDDGOtzZGYXmdnfEufSLjNLS0ngwxjj8/Tyfs/R44n3h7Wpin22M7MKM3vAzPYmXkNvS0xfa2Z/TzwH28xs0yTtP83MtprZE4n9/2tierWZbUl8DvzQzAJTvP/vJj5/didev/6p3H+/+V80s/bJ2Pdw+098//iEme03syfN7K0piOE5ZvZY4jX4iJktmawYZovZ9r3KzD5iZqf6fR7ckOqYRsPMrk88zgfN7K5UxzMeZnY08Z3icTPblup45pJhPpdnzPmQ6s/2iRom/v8xsyP9noO1KQ51SGbmNbMdZvbLxP0Z8dinkpn9k8V/m+wxs3/vNz0ln59DnfNm5jezexLv0U+a2fumKqbh4krMS9nv0pHeIy0FOY1hnsNrzGx74jHabmZXTVVMADjnZu0fcCGwG8ggXl/6D8AS4N+BuxLL3AV8KtWxJuFYrwAuBnb3mzbocQI3AL8BDLgE2JLq+JN83CuA5cCfgQ39pq8EngCCQDVwCPCm+hhmw98Qz8O1gC9x+1PnnmfAT4AfA+9KdfwTOR6gqv9y0/VvjMfkA3YCaxL3C6fjuTKe111i+mrgUKrjn81/QBlwceJ2NrA/8R78e+C5iek3AH+epP0bkJW47Qe2JD7vfgS8NDH9K8Cbp3j/NyTmGfD9qd5/4v4G4DtA+yQ+/0Md/2uAbwOexLySFMSwH1iRmP4PwP9MVgyz5Y9Z9r0K+AjT8LvHCDF7E4/vIiCQeNxXpjqucRzHUaAo1XHMxb9hPpdnzPmQ6s/2SYz/f4AXpzq+UR7DO4DvAb9M3J8Rj30KH69nE89BBRP3SxL/U/b5OdQ5D7wM+EHidkbi/bpqCh+roeJK6e/Skd4jSUFOY5jHah0wP3H7QuDUVMXknJv1LZdXEE+cdjrnIsCDwAuBm4F7EsvcA7wgNeElj3PuIaDxnMlDHefNwLdd3N+BPDMrm5JAk2yw43bOPemce2qQxW8m/obZ45w7AhwEJqXV3FwzxPPw+8R5B/B3YEHvPDN7AXAE2DNVMY7FWI9nJhjjMV0L7HTOPZFY7qxzLjplwY7SBJ6n24EfTHJ4c5pzrsY591jidhvwJFAOOCAnsVgucHqS9u+cc70tc/2JPwdcRfxLIEzi5/9Q+3fO/ToxzwFbmaT3kaH2b2Ze4NPAeyZjvyPtH3gz8FHnXCyxXF0KYpiS1+Bsou9V08Im4KBz7rBzLkT8M+zmFMckM8gwn8szRqo/2ydqmPhnBDNbANwIfD1x35ghj30KvRn4pHOuBwZ875mOn58OyDQzH5AOhIDW1IYETOPfpdMtp+Gc2+Gc6/1euwdIN7PgVO1/tieXdwPPNLNCM8sg3mKoAih1ztUkljkDlKYqwEk21HGWAyf6LXeSGfblYpzm6nFPB68l3loeM8sC3gv867BrTG99x5NQnegi9qCZPTNVQU1Q/2NaRjwR9TuLdx+f1ETUJDr3eep1G/FWozIFzKyK+JX0LcA/A582sxPAfwCT1uUu0XXzcaAOuJ94q5DmfhcfJvUz4Nz9O+e29JvnB14J/HaK9/8W4L5+3w0mzRD7XwzcZvGSKL8xs6UpiOH1wK/N7CTx5+CTkxnDLDeTv1e9xeLlk75pM6M83kx+rPtzwO8T3XXvTHUwc9U5n8swg86HVH+2T9Qw3w0+kXgOPjeVyaAx+jzxi9OxxP1CZtBjnyLLiOejtiR+J25MTE/1e/pg5/xPgA6gBjgO/Idz7tzGi6mIazr8Lj0vrmmQ0xjpfftFwGO9FzamwqxOLjvnniTeLfr3xH/APQ5Ez1mmtxXLrDZXjlOmHzP7ABABvpuY9BHgc/2u3M8ogxxPDVDpnFtHoquYmeUMtf50NMgx+YDLgZcn/t9iZs9JUXjjMsgx9U7fDHQ653YPuqIkVeKL10+Bf3bOtRJvwfF251wF8HbgG5O1b+dc1Dm3lnjr4E3ABZO1r9Hs38wu7Df7v4GHnHMPT+H+rwBeAnxpsvY5wv4vJN79s9s5twH4GvDNFMTwduAG59wC4FvAZyczhpnCzP5g8Vrg5/7NyNaxIxzPl4lf6FhL/DP8M6mMdY653Dl3MfBc4B8T70syhQb5XJ5R50OqP9snaojPpfcRP46NQAHxhNW0YmY3AXXOue2pjmW6GeHzxkf8Ob0EeDfwo0SL71TGNNQ5v4l4rmw+8VId7zSzRdMgrkn/XTrOuD7CJOY0JvI9xsxWEc+DvnEyYhuKbyp3lgrOuW+Q+PFqZv9G/KpQrZmVOedqLF4OYtK6ZabYUMd5ingL7l4LEtNmu7l63CljZq8GbgKek7jAAbAZeLHFBzTIA2Jm1u2c+8/URDl6gx1P4mpgb1en7WZ2iPgV1hkxUM0Qz9FJ4omvhsQyvyZe2/iPKQlyjIY4pl4vRa2Wp4TFW+f+FPiuc+5nicl3AG9L3P4xia6Vk8k512xmDwCXEi8D5Uu0spmSz4B++78e2G1mHwaKmaIvfP32/2zi404cTPyuyTCzg865SR3Q7pzjPwn0vhbuJZ7cnXT9Yngu8Zp9vS3Ffsgkth6fSZxzV49jtWn7vWq0x2NmXwN+OcnhJMO0fazHwjl3KvG/zszuJZ7MeCi1Uc0dg30uO+dq+82fKedDyj/bJ6r/Z6Nz7j8Sk3vM7FvAtBvsHLgMeL7FBw5LI15e6gvMwMc+2Yb7vDGzNwM/S/we2WpmMaCISX5PH+dn4MuA3zrnwkCdmf2F+Dgdh1Mc16T/Lh1nXJOa0xjv9xiLl6+5F3iVc+5QMmIZrVndchnAzEoS/yuJ11v+HnAf8R+4JP7/IjXRTbqhjvM+4FUWdwnQMhVdZKeB+4CXmlnQzKqBpcRrXsokMLPriXeder5zrrN3unPumc65KudcFfHuVf82QxLLgx6PmRVbvI4piau7S0nih/BkGuqYgN8Bq80sw+J1t54F7E1FjGM1zDFhZh7gVlRvedIlWmV8A3jSOde/Zehp4q8niNfpOzBJ+y82s7zE7XTgGuL1JR8AXpxYbNI+/4fY/z4zez1wHXC7S9QdnsL9b3fOzev3/ts5WYnloY4f+DnxJDfEXwf7J2P/w8TwJJBrZssSi/VOk/GZkd+rbOA4I7cQL6M33T0KLDWzajMLEL9Qel+KYxoTM8s0s+ze28TraM6Ex35WGOpzeSadD6n+bJ+oYb4blCWmGfGaxdPuOXDOvc85tyDx/eGlwJ+ccy9nhjz2KfRzEt97Et89AkADKfz8HOacP078u3nve/QlxL+7TYlh4krp79Kh4kplTmOomBLvL78C7nLO/WUqYulv1rdcBn5qZoVAGPjHxFXCTxLvkvA64BjxZMOMZmbfB64EiixeR/DDxOsIDnacvyZef/og0El89PYZaYjjbiTe7bcY+JWZPe6cu845t8fMfkT8zShC/PUwLYrBz3RDPA/vI94F+v5EK7m/O+felLIgx2CMx3MF8FEzCxOvQfamFNSnGtFYjsk512RmnyX+Y9YBv3bO/So1kQ9tHK+7K4ATzrkZkfyf4S4jXs92l8VrCwK8H3gD8IXEl8NuYLJqbpYB9yQu/HiAHznnfmlme4EfmNnHgR1MXlmOofYfIf55/LfE6/NnzrmPTtX+J2E/Y9q/mT0CfNfM3g60E69/PNUxvIH4d8MY0ES8NrsMw8xuYXZ9r/p3M1tL/PPtKFPcbXQ8nHMRM3sL8R/ZXuCbzrlpMYDQGJQC9ybe+3zA95xz6jkwdYb6XL59Bp0Pqf5sn6ih4v+TmRUDRryM54z4vZTwXmbGY58q3wS+aWa7iQ+Qd0eiFXMqPz+H+gz8L+BbZraH+GvxW865nVMU05BxTYPfpdPxO8NQMb2FeC/FD5nZhxLTrnWTOIB2f3Z+j2ERERERERERERERkeHN+rIYIiIiIiIiIiIiIpJ8Si6LiIiIiIiIiIiIyJgpuSwiIiIiIiIiIiIiY6bksoiIiIiIiIiIiIiMmZLLIiIiIiIiIiIiIjJmSi6LiIiIiIiIiIiIyJgpuSwiIiIiIiIiIiIiY6bksoiIiIiIiIiIiIiMmZLLIiIiIiIiIiIiIjJmSi6LiIiIiIiIiIiIyJgpuSwiIiIiIiIiIiIiY6bksoiIiIiIiIiIiIiMmZLLIiKzjJm92sweGWb+b8zsjqmMSURERERERERmH1+qAxARkanlnHtuqmMQERERERERkZlPLZdFREREREREREREZMyUXJ4jzMyZ2ZJ+9//HzD6euF1kZr80s2YzazSzh83Mk5h3l5kdMrM2M9trZrek6hhEZgMzu83M2vv99ZjZn83sRjPbYWatZnbCzD7Sb52qxDn8msS8JjN7k5ltNLOdiXP3P8/flf2nmbWY2T4ze06/GX82s9cnbi82sz+Z2VkzazCz75pZ3pQ8GCIiIiIiIiIyoym5LADvBE4CxUAp8H7AJeYdAp4J5AL/CvyvmZWlIkiR2cA590PnXJZzLguYDxwGvg90AK8C8oAbgTeb2QvOWX0zsBS4Dfg88AHgamAVcKuZPeucZQ8BRcCHgZ+ZWcEgIRnw/xKxrAAqgI9M8DBFREREREREZA5QclkAwkAZsNA5F3bOPeyccwDOuR87504752LOuR8CB4BNqQxWZDZI9A74HvBn59xXnXN/ds7tSpxrO4knnJ91zmofc851O+d+TzwZ/X3nXJ1z7hTwMLCu37J1wOcT5/QPgaeIJ60HcM4ddM7d75zrcc7VA58dZL8iIiIiIiIiIudRclkAPg0cBH5vZofN7K7eGWb2KjN7PNHtvhm4kHhLSBGZmE8A2cBbAcxss5k9YGb1ZtYCvInzz7Xafre7Brmf1e/+qd6LRAnHiLdOHsDMSs3sB2Z2ysxagf8dZL8iIiIiIiIiIudRcnnu6AQy+t2f13vDOdfmnHunc24R8HzgHWb2HDNbCHwNeAtQ6JzLA3YT70YvIuNkZi8Fbgde7JwLJyZ/D7gPqHDO5QJfYWLnWrmZ9V+/Ejg9yHL/RrwMzmrnXA7wignuV0RERERERETmCCWX547HgZeZmdfMrqdft3czu8nMliQSUS1AFIgBmcSTTvWJ5V5DvOWyiIyTma0DvgS8IFGGolc20Oic6zazTcDLJrirEuCtZuY3s5cQr6f860GWywbagRYzKwfePcH9ioiIiIiIiMgcoeTy3PE24HlAM/By4Of95i0F/kA8wfQ34L+dcw845/YCn0lMqwVWA3+ZupBFZqWbgXzgETNrT/z9BvgH4KNm1gZ8CPjRBPezhfi53UC8BMeLnXNnB1nuX4GLiV9Y+hXwswnuV0RERERERETmCBtYklNEREREREREREREZGRquSwiIiIiIiIiIiIiY6bksoiIiIiIiIiIiIiMmZLLIiIiIiIiIiIiIjJmSi6LiIiIiIiIiIiIyJgpuSwiIiIiIiIiIiIiY+ZLdQDnKioqclVVVakOQ2TKbd++vcE5V5zqOMZL567MVTP93BUREREREREZr2mXXK6qqmLbtm2pDkNkypnZsVTHMBE6d2WumunnroiIiIiIiMh4qSyGiIiIiIiIiIiIiIyZkssiIiIiIiIiIiIiMmbTriyGiIhML9GY43RzF4fq2wn4PDxjcVGqQxIRERERERGRaUDJZRERAaClM8yhhnaO1HdwuKGdw/UdHK7v4MjZDkKRGABVhRn88Z1X4vVYiqMVERERERERkVRTcllEZA4JR2Mcb+xMJI7jCeSYczzwVB0N7aER1z96tpOfbD/BbRsrpyBaEREREREREZnOlFwWEZkjPv27fXzlwcNEYw4Aj8HGqgKeONFMd6Jl8mh89P/2sqIsh4sW5E1SpCIiIiIiIiIyEyQ1uWxmR4E2IApEnHMbzKwA+CFQBRwFbnXONSVzvyIiMrIL5+f2JZYBLq7MZ8uRxjFvpyMU5dav/o0XXbyAIw0dLCvNpjg7yOsurybN701myCIiIiIiIiIyjU1Gy+VnO+ca+t2/C/ijc+6TZnZX4v57J2G/IiIyjCdOtgy4X9PSPe5tdYdjfHfLcQD+eugsAD997CR/eueV496miIiIiIiIiMwsninYx83APYnb9wAvmIJ9iohIP7tOtvDNR4703S/LTeNUc1dS93G4voO/HGwYeUERERERERERmRWS3XLZAb83Mwd81Tl3N1DqnKtJzD8DlCZ5nyIiMowzLd38w/e2E4rG6ypnp/nITfdPqOXyUF75jS2sXpBHY0cPH7ppFdes1Fu+iIiIiIiIyGyV7OTy5c65U2ZWAtxvZvv6z3TOuUTieQAzuxO4E6CysjLJIYmIzF2nm7u4/Wt/50Tj062UV5bljKvW8mjEHDxxohmAX++q4XhjJ2sW5LKhqmBS9iciIiIiIiIiqZPU5LJz7lTif52Z3QtsAmrNrMw5V2NmZUDdIOvdDdwNsGHDhvOSzyIiMjbRmOPXu2r41//bQ0N7aMC8ww0dbKzK59Gjkzu26r07TnHvjlOYwUs3VlDb2sOrn1HFFcuKJ3W/IiIiIiIiIjI1klZz2cwyzSy79zZwLbAbuA+4I7HYHcAvkrVPmRr1bT3843cfS3UYIjIGn/rtPv7p+zvOSyxD/Jx+9GgTm6qnpjWxc7DzZAt/2lfHu3/yBF/84wF+t+cMsZiuJYqIiIiIiIjMZMlsuVwK3Gtmvdv9nnPut2b2KPAjM3sdcAy4NYn7HBXnHI0dId76gx2cHSTRMlqlOWnUtsZrlPq9HsKJ+qWptKQki4N17UnZlgNy0ny0dUcGTA9HYxw728me0y2smp+blH2JyOR693XLWVKSxXt+sjOlcQR8HkKRGHtOt1KcFaS2tYfP3r8fgGcuLeKfrlo6ZUluEREREREREUmupCWXnXOHgTWDTD8LPCdZ+xmNcDSG3/t0o+z6th7OtHazpCSLvxw8Nu7tRmIxDtZ1AJDm99AdTn1yOTfdz74zbUnb3gXzsth3ZvBk9Y1ffITsNB8XV+azpCSLnSebWVSUxR3PqGLl/JykxSAiE+f3erjpojK+9tBhDgxxAcqStC8zKMoKUt/WQ0l2kGjMsbgkiydrWmnrjpCX4ac8L51jDR0D1nv4QAMnm7r4+h0bWFyclaRoRERERERERGSqJHtAv2nhH777GN3hKJcvKaIgM0DA56E8L535uemk+710haPj3HKyUjHTV8DrHXZ+W3eEB/fX8+D+egAePdrEb3bXEPR7efnmSq5bNY+tRxoJ+jyU5aVTkh1keWk2kZjj4QP1/GzHKepbe3j+2vncvHY+2Wn+qTgskTkpI+DjDc9cxHt+Onjr5ceON7GuIo/dp1sIR8dXoiI/w095fjpPnm6lKCtAKBqjuTPM2X4DBjZ3hmnuDA+6/pGGDnYcb+b42U5Wzc+hJCdtXHGIiIiIiIiIyNSblcnll22q5A3f3sbDBxr6plUXZfLmZy2a0Hb7p5YvKs9j69HGIZedqWwcVbhbuyPQHeHzfzjA5/9w4Lz5S0qyOFLfTv/c1dajjXziV09y00VlvHRTJRdX5pEoqSJJYGYvAT4CrAA2Oee29Zv3PuB1QBR4q3Pud4OsXw38ACgEtgOvdM6Nv6aMpMyliwvxeozoIPWNw1HHjhPNFGUFWFiYSSwWvz8W1UWZPHY8vs5g9Z1H410/foKgz8N7rr+A111ePa5tiIiIiIiIiMjUS9qAftPJsy8o4TkrSvruF2cHCUdjNHaEJtBqOd71u9fWo41UFmRMJMykSPZwWE+caMHvSV6StzepNVijyK5wlB9vP8mLvvxXrv/8w9zz16O0dQ/eunEm6AxF+MvB+AWNrlCUSGprcu8GXgg81H+ima0EXgqsAq4H/tvMBmuu/ingc865JUAT8WS0zEAVBRk8c2nRsMs0tIfYfqyJHSea2VQ1tvrHlqQeHT2RGJ/9/VM80u+ioIiIiIiIiIhMb7MyuQzwykuqyE6LN8yub+thbUUeP3ns1IS2eW4S5VRTJ5tTPBDVZLT1zUkff6kKr8H6hflU5Kfj9xqbqvI5ck6d1cE8VdvGh+/bw+Z/+yPvv3cXT9a0jjuGVOjoifCabz3Km76znZd85a+s+9jvee4XHuZEY2dK4nHOPemce2qQWTcDP3DO9TjnjgAHgU39F7B4E/KrgJ8kJt0DvGASw5VJdLa9h78ePDvq5Z+qHVsN9701rZRkB8ca1qA6QlG+9vDhpGxLRERERERERCbfrE0uP2NxIRfOz+27/8udNRwcYlCr0RvY/DbqYMuRRtYvzKc8P32C254+irLGnihaNT+HzdUF5GcG2H6siRNNXczLSWPb0aYxbaczFOV7W47z3C88zFcfPDTmOFIhHI3xmm89ypYjjbT1RHj0aBPd4RgH6to5UJe8wRaTpBw40e/+ycS0/gqBZudcZJhlADCzO81sm5ltq6+vT3qwMnHtPRFCY2hFn58xtotLXeEoVUXJ68Vx28aKpG1LRERERERERCbXrE0uezxGmt9DwJu8Q/R6Bt/W9mNNpPlS81AmuywGQN4Yk0sQbx2+5UjjgJqrnaEoy+ZlMd6H5jP37+cfv/sY3/nb0fFtYIr88cm6Ietvj3eQtNEwsz+Y2e5B/m6etJ2ewzl3t3Nug3NuQ3Fx8VTtVsbgbMfY6iDnZwTGvI/jZ7vGvM5QPvmbfTzwVF3SticiIiIiIiIik2dWDujXa11lPmdauknze4nGHDtPtYy4TkbAy7ycNIJ+D84NrLNclDV00iUvIwCMXP4h2YzxJYOH0zjGZNSSkizOtHSfN/1sR4izHSF8HmNRUQZF2QG6wzHauiOjKpURisT41a4adp5q5mRzF7duqGBxcdaYYpsKn71/sOoTceFJrLvsnLt6HKudAvo3DV2QmNbfWSDPzHyJ1suDLSMzxLZRDjy6oSofY+znP8CZ1m7WVuTR1BHi2ARLwRxv7OQ133qU/3nNRq5cXjLyCiIiIiIiIiKSMrM6uXymtZsnz8TLEpTnpVORn05XOEplQQZej9HREyHg8xLwGpGY43hjJw3tIQ4PkfjcZ21sri5gy5HzkzU+j5Gf4cfn9VDf1jOpx3Wu5s7kDoK3rDR71MturMrn0RFKX0RijsMNHQMe1w1V+aMumXGisYuvPniYSNTxxisWUZKTNur4JtvPHjs5bLmV/bXttPdEyApOm1PtPuB7ZvZZYD6wFNjafwHnnDOzB4AXAz8A7gB+MdWBSnI8Y/Hwg/ktKcnCOTfmEjbnevxEM2n+5PXgOHY2NfXKRURERERERGT0pk3GazJ0h6N9t081P91tu3/phrFwbugyFLsTraIr8jOmNLnsJqEwRk84SlbAS3soOuKyx8eZADpQ2868nCC56X7SAz78XmPXyRa6I0O39P3GI0f49t+O8rw18/l/L1xN0Ocd174nyjnHgbp2njjRzLt/snPYZb/4xwOsrcjlqgtKpyi6ODO7BfgSUAz8yswed85d55zbY2Y/AvYCEeAfnXPRxDq/Bl7vnDsNvBf4gZl9HNgBfGNKD0CSprooc9j5oUiU443JKWsRGub8Hav//vNBnr9mPvmZYy/TISIiIiIiIiJTY1Ynlw/XJ7dMxfzctCG7mHckErE7T7WwvjKf7ccHbwV4wbzspLZinYwE6xMnW6guyqR9FKUrCrIC1I4jmd7SFaYsN5uDde1EYo71lfmjSpSHo46fPXaK2zZUsHlR4Zj3OxTnHDtONLP/TNuAKII+D93hpxNmDkdbd4T/euAgbd2R8zc0iLd9/3G+8sr1XLZk+BakyeScuxe4d4h5nwA+Mcj0G/rdPgxsmrQAZcoEfB4WFmYM2hK4MDNAbev5JW3Gozw/nfK8dLYO0rNjPGpbe/j075/i325ZnZTtiYiIiIiIiEjyzerk8unm5A0y5TEoyAxwepDawufad6aVTdUFbD3SiN9rZKf5AceS4myisRjbjk2s+3l/m6oLkrat8WjpCrOsNIv9tUOXhhjKvkTJkqKsADtONBEbQyPsbceakpZcrmvt5q6f7eJP+84fRGywCwWbqvKHTSx7jL5jqSrM4DkrSskIpKaVtQjEL2qdm1y+YF42XaHomAf8O1ea30NFfgYH6to51ZS899wrlhXznuuWJ217IiIiIiIiIpJ8sza53BOJ0tKVvFrE83LSaOocXRKmIxRl54lmKgrSaekK9w2QtbWjkYsr85IW03RwujmebF9emk1Ld3jQgf1Gsrg4i4b2sbV2fCwJCXrnHN/bepzP3X+AhvbBW197PTbg/qbqAvaejpdAyU7znZdkLsoK8qGbVtDcFeai8jwuWpCL55xtiEylL/3pIL/bUztgWkV+et/FHa/BxQvzCUVidIaiHBimhvhgVs3PZXsSL5iVZAdZPi+b/3jxRYmBUkVERERERERkupq1yeW61h56klj/83RLNxur8jnVPLrkaXckxolB6phakvOM0yVt+VRtGxl+D5uqCtg6ROmQoRwZRfmNc20/3kQs5saduI3GHG/9/g5+tatm2OVaup++QFGYGWD70UaiiVbJWcF4ctljUJabzsaqfF6wrpwrl5eMKyaZOZ440czu0y28fPPCVIcyop9sO3HetOLsICeaurhgXjbNXeG+QTkLMv2U56WN6n3O5zE8HhtQ236iKgsyuO8tlympLCIiIiIiIjJDzNrk8sExtr4bjY6e5CVRkiX5w/nFW+um+73kZ/jHvO7+2tZBW/QOpSgrQN04ajY3d4Y51dxFRUHGkMtEY46/HmrgyZpWXOKBMgPD2FvTOmJiGSAn7elTpLIwY0AJgd5SF19+xXquWFpMukpfzBnZaT7+9f/28qKLF5Dmn77P+66TLYOW8jEzstN8eD0M6G3Q2BFmU3X2iMllv9e4uDKfIw0d7DndmrR4jzd20tDeo+SyiIiIiIiIyAwxa5PL3/rr0VSHMCg3GdngJMsK+jhQ10Y4Or5gL67M47HjzaNaNuDzjGsfayvyWJCfPuwybd1hXvXNrRN6zCPRp1u/H0iUEehVmBnkto0VXLdq3vh3IDOSz+MhFIlxwb/8lqKsAF995XrWL0xt/fPB/Pmp8+uIA2w/1kRVYQaZwbFfQAJYWZbDliQN3Heu/3rgEJ+7be2kbFtEREREREREkmtWJpePNnTw0P76VIcxKEtyXYygzzOhOs5ej9HUGSbg9eD1GAfq2nDOTajchs87+rXrx9FqGeCOZywc8bHMTfdz0YI8njjRPK59AHgsnvxeXJzJofqny3ek+70UZwd5wzMXjXvbMnNVFmbg8xiRmKOhPcTfDzcOmVzuDEX4+Y7TXHVBCfNy06Y0zuF6BRw928nRcwb5AwiFY5RmB3FDrL+xKr+vjMZk+OuhBqIxd169cxERERERERGZfmZlcnlebhrpfi9dSawFGjf9mh2HIrFRtxIejTSfh5VlOew700qoa3SlLc6141gzm6ryaeuJ9LUadg4c7un7xAfUA2jtilA/xIB6g1lTkcdVy0uHnH+4vp1fPH6Knz9+mmODJM/Gwucz8jL8tHSGKctNw+cxfF4PzZ0h2nsidIdjKocxR5XlpfXVVe9tRe+c4/69tRyq7+DeHSdpaA/R1Bki3e/lxovKpjS+WMzx61GUfjmX32c0doYIRx0bqwp44kQToUQvhovKc/sGApws/3LTSiWWRURERERERGaIWZlcTvN7Kc0JDtoqbyKSPRjfdNQdifH3I41sri4Yd7f3cMyx9WgT6yvz2HW6ldAwAyv6x9DKGeD1l1fznusv6CunEYs5Htxfz2PHm2ho72Hb0SYO1LXjMYgl4VrAsYYOmjvDg85bkJ+Oz2uEIrFxl/eQmck5R1VhJicau6gsyKChPcTBuna+8McD/N8Tp89bPj8j0Feje6p85aFDA2qEj9bjJ5r7SuI8erSRioJ0fB4PeRl+dp5oZpzVckZlU3UBN100f/J2ICIiIiIiIiJJNSuTywBvuWoJX3nw8KiXL8kOUNc2fCImFHEsLckacn5+pp+mjsETkb1mSn56+7EmSrKD4xpsr9cTJ5spzU3nVFPXoPO9BqvKcjjRb37/vFVPOEpH6OnW52W5aWQEvJhBTyTKL3ac5qsPHeorV7EgP52TiW0tKs46/7Ee6sF38drP7d1hjjU+HYvfa3SEIhRnBfF64iVNirICtHZH6A5F+e6W4ywtyWJVeS7VRZkUZQVH+9DIDFff3sPDBxqA+CB0H/vlXj42zPJnWruJxhwTHftvLBcyjo/z4tq5tdZPNHaxYl42u0+1TGpiGWDV/Jx4WZ65cCVPREREREREZBaYtcnla1fN470/3UV0lM1X0/w5HKxrn9A+l5ZkcqCuY9hl1i/Mn9A+zjVZuZ5IzFFVmDGu5LLHYHFxFtlpvmFLdiwqzuLxky1Dzt9Ylc/uRMvnaMxR09LNF/90kO/8/RgOhmxRDIzruVyzIJemrjCtiXIguel+GtpDtPF0gtvvNSJRx3uuX0aa38eZ1m7S/R5y0sY3MJrMTD/dfmpMy0djjq8+eJh/ePZi/N6xt3Kvb+vh+s8/xOVLi/jCS9eNap03XLGIHzx6Ysz7GkxWmm/cA3yOxe/31HLD6nlsrCqc9H2JiIiIiIiIyMQlNblsZl5gG3DKOXeTmVUDPwAKge3AK51zY++nPQ69CcnZbjLb94231fKKshz2nG4decFRBN8VOr9udtMwSeWJqGnppjAjwIp5OZxu7iI/M8AF87J53pr55KT5yU73syAvndKcNNIDXrpCUTweaOoI41ON2DnlgrLsMa/zuT/sZ9+ZVpaWZHHJ4kIuqS7EbHSDfP798FnOdoQ43Tx4L4DBLCrKZFlpFvtrJ3bRbMPCyR3Ar7/0gJeGEXqQiIiIiIiIiMj0keyWy28DngRyEvc/BXzOOfcDM/sK8Drgy0ne56B2nxq6RWwq7T3dQm76+Q97Xrqf5q6xJ0331cS3d26CqjAz0FcuYrzGm1z2jrJL+3RLx87LSWPnqRaOnO3kmhWlZAS8NHaG+N2eWi6uzGP9woJEneV4y9Pegfzm5WpAv7kmNs4LV7/ZfYbfAF/800EyA14uWVTIf77sYvxew+uxIRPN247G659vP9bE//vNk7z1qqVkBod/+zYz/uWmlbz5fx+jvWd0g3P6vUZFfgZ5GX78Xg894RiPn5iaxPJF5bnsPNVCtnoBiIiIiIiIiMwYSUsum9kC4EbgE8A7LJ4luQp4WWKRe4CPMEXJ5a89PPp6y3ETT3WOJt3UFY7RFT5/gDu/10NL1+gSQKNRmj3x+r+doSjPXFpETUs3EB/EzAE4cDhc4oB782x+r1GSHWTbsdElo2yEx3yk+edakPd0zeXxCPrjSePCTD83XVRGRWEGFfkZFGUFVANWBjjSMLELNwAdoSh/3FfHig/9FoBlpVkEfV5izvHqZ1SxekEuta097Dndwg+3xctbxBx89cHDPPhUPb/8p8v7LnQM5ZlLi/nVWy/nQ7/Yw4P760eMaV1lPluPNJLu9wz6PjUZMgNelpVm09Aev5iVm67ksoiIiIiIiMhMkcyWy58H3gP09hcvBJqdc70Z05NAeRL3N6xXbF7Io0ebCEWmJkEy3fi8HjIDE29Re7CunXAkRkPH6LqqF2QGRl2b1WyE5Uaaf47x1LLt71B9B/Nygpxp7WF/XRs3r5uyl6vMMJ2DlGuZqP7lK979k53DLrvvTBu7T7eytiJvxO0uLMzkntdu4lO/3ceX/3xo2GU7eiKsq8jjQF07aT7onoT3z6DPWFMRrz3f3h1hf20bO040A1BVmMGF5TnDrC0iIiIiIiIi00lSkstmdhNQ55zbbmZXjmP9O4E7ASorK5MREs9dXUZnKMo7f/xEUrY300SiMTqSkADrCEXJTfexrjKPHcMMztcrHB1LMip5LZfzM/wcqG9nZdlQiSk35P6y03wUZAbYfqyJM609eA1evH7BqPc93ZjZS4j3ElgBbHLObUtMvwb4JBAAQsC7nXN/GmT9jwBvAHqbur7fOffryY985vBOgxrb39tyjDULckfdqv6d1ywjHInx9UeOnDdvXWUefq+HZy8r5jP37ycSc6wuz+V0cxdnR3lhaSQBr5GXEaC6KJMtRxoHXaalK8yZ1m7KctOTsk8RERERERERmVwTa+r5tMuA55vZUeID+F0FfAHIM7PeBPYC4NRgKzvn7nbObXDObSguLk5SSLBmFK36ZqtkDmXY0hUZdTLt8RMtXFSeS4Z/5JfWSIPgjeYYPAary3Mozg5ypqWbvTWt7K1ppSscIRSJ4vcaoUiUaMyRHvD0zd9b08rJpk6WlWZhBjHnqGvrwecxPn7LaqoKM0d1vNPUbuCFwEPnTG8AnuecWw3cAXxnmG18zjm3NvGnxPI5XnNZFWmjeI1PhpLsIGsW5HLsbCcf+sUe/rSvlg/+fBc7TzYPu57P6+F9N6xgxTkXYG7fVMm9/3AZP3rjpawszyWSqHOz61QLzV1hVpblsLEqn7yMiZWrWFuZT11bz5CJZYgP1vnjbSdp7AjNiQFZRURERERERGa6pLRcds69D3gfQKLl8ruccy83sx8DLyaecL4D+EUy9jdaFQXppPu9dIVHbsEbjc2u8hnJrhG880Qzq+bnsOd068jLnmphfWU+248PX3s5IzD8yy/o9bCxKp9tx5r66jv3l53mY1FxJk+cOH/wxpNNXX3lOS6uzOOx481UFKSzujyXpo4eTjZ389bnLOUn20+Sm+6nKCvIN1+9gQO17dy+KTmt51PFOfcknP8acM7t6Hd3D5BuZkHn3PhGbpzD0nxe8jMCffXIp8Laijx2JxK+vYNtbjnSyHf+fgyAB/fXs7GqgBesLWfV/BwKMs+vFe71GJ9+8UXsTgycd++OU+w+1UJ9Ww/Fg9Rpj8Yce2vi5/zq8hyaO8c+6CjAyrJstg6TVO7vs/fv53tbjvOTN1/KgvyMce1PRERERERERKZGMmsuD+a9wA/M7OPADuAbk7y/AYI+Lx+8aQX/8vPdjNQI7smaNi6uzGN/bTvtPckbWC9Vkt1pPxR1ZI6QDO5v+/Em/F6jODvI6ebBE3DdQyT9CzICVBdncrajh701bVxUnovXa7R3Rwj4PBw720l7T4R0v3fQxDJAOOrICvqoKsrgsUQ5jxONXZygi8uXFFLT2kNpThqFWQFCkRjf33qcm9eW88ZnLR71Mc5wLwIeGyax/BYzexWwDXinc250ozTOEf+75diUJpYDXqM7HI23Kh7izexEYxcnGk/xs8fiHUSet2Y+n79t7Xm9Di4sz+XC8lwAbryojO5wlKAv3grbDXYVpy+G8ddwzwyO7r0jK+hjcUkWn3zhaiWWRURERERERGaApCeXnXN/Bv6cuH0Y2JTsfYzFyzcvZEF+Bm+4ZxuhEeoBP3a8mZLsIBUF6TxZ0zZFEc5eS0uy2DvE41iUFeBs5/m1XNP9HhYUpLP92NO5zJ2nBiaQl5ZkkRn08vgQieWAz8OiokyizrH71PktrSsKMjnbHqK2tRuPGU2dYdZV5nOyqZNN1QVjOcSUMbM/APMGmfUB59ywPQTMbBXwKeDaIRb5MvAx4pVJPgZ8BnjtENtKer30meBrDx+esn0VZASoLMzg8cSgd6P1f0+c5splxbxohPrhaf7RJY2fPNPK5uoCjp3t4Ezr2Bq7146w/KbqAp53URmLS7J4xuKiMW1bRERERERERFJnslsuTwvPWlbMKy9dyP7aNupae2jrDlPb1jNoTc+6th7q2nrYVFXAjhNNfaUVBMZayfnY2c6+khTnqirMYF9NGwGvUZydRlbQS15GgM5QlJ0nB08a9zrd3EV6YOiE2JoFuTx6dOiGtj997CTrK/OJxhzffu0m3v3jJ/DguHZlyaiPLdWcc1ePZz0zWwDcC7zKOXdoiG3X9lv+a8Avh4njbuBugA0bNsyJk+VQfTsnGrumbH+LSzKHfT0P52+Hz46YXB6tzlCULUca2VRdMKbkcmbAy/HGziHnez3Gv91yIUtKspMRpoiIiIiIiIhModSMSJUC/3LTSm7fVMn8vDROt3SPOFjU1qONzM9Np7JgZnbNTnLJ5XFttCMU5bHjzVwwL5tzx+5r74nSE42R5vdS09LFU7XtbDnSyK5TwyeWe7dbnB0kN/38AcbWVeaNmIgLRWLsPtXC/XtrcQ66IzH+6eplZKUFxnR8M42Z5QG/Au5yzv1lmOXK+t29hfgAgZLQ1h2ZnPNrCJ2h8Zfp2XLkLMfPdtLQPrpk8OiuDoztGkJvCY6hZAS8KoEhIiIiIiIiMkPNmeQyQHF2kL8eOjvq5Y81dlLb2sX6hfmjWn6YcqVTbgpzXyPad6aN8rz0vvtrK/LYd6aNcNTR2h0ZsR72UCoL4sn/VfNzuLgyjzULcjnW0DHievkZfsrz08lK83HsbCc3XTSfioLM8QUxDZnZLWZ2ErgU+JWZ/S4x6y3AEuBDZvZ44q8ksc7XzWxDYrl/N7NdZrYTeDbw9qk+hulsbUUeH7xx5ZTtr6alh3WVeeNa90RjF8/7z0e4/e6/05GkWvJ7T7exubqADQvzyQ56KckOcsG8wVsdb6zK54mTzcNur607wjceOZKU2ERERERERERkas2Jshi91lfm87arl/L9rcdH3a29J+LYfqyJ9Qvz2HO6le7w8HWbN1cX4Bg8uTvcdL/HWFw8sey0z2tEEmU8Al4Pm6vPb9k7EecODDYWOel+Fnk9RJ1jb835dZBHK+A1Vi/IG1CTeayaOsN0haOsnJ9DQ0cP160qHfe2piPn3L3ES1+cO/3jwMeHWOf1/W6/cvKiS63X/c+jnGqeeEmLkeq3J1NjR4jGjhCbqgvYeqRxzOu3dIVp6Qrz6d89xUeev2r4hUfxFtTeE2FLIo6qwgwyAl721rRRmh2ktu3pFtKVBenUtHSP+J4JzJha5yIiIiIiIiIy0JxKLns8xj9cuYTalm7u+duxMa27/VgzFQXx1rdDJabNrC/pMlbFWUHqR9l1fSgbq/J5fJD6xv2Fx9tMmHji3O8dW4K5t2Z1NBrjbEdPX+vJjVX5GNaXbTcSeS0HDodzEHMO5xxRB8458jMChGOOzp4IaxbEu9p7PEYkGsMRbznuEhvpPUzXu72++U/ffuxYE0+caOZHb7yUwqzguB8XmTkON3RwZBSt26eb3HTfqEtbDOWn209yy7py1lTkJSco4OjZp2spZ6X5+pLLF1fmsfNkC5FRvt+k+UY3qKCIiIiIiIiITC9zKrncKyttfId9orGLdL+HdRV57DjRPGCex1JfiqInEhsxeew1GO8YhQ7GPMDh2opcznaE2FfbPmD6eAco668iPx0HnGwae0tUs3iCeU1FHjUtXUouzxGpPkfHa/m8bLYemdg509YT4SfbT56XXD7R2MmnfruPNzxz0YS2n5cR7ynh9xq7T7eOOrFcnpdOaa7OPxEREREREZGZaE7VXO71rmuXc/umynGt2xWOseNEM5uqCvrKRBRlxQeC6w5HkxbjuExyzeexHl9hZgC/10N1UfLqGQd8HjZV5bO4OJPTzV3jSiwDlGanccPqebx8UyV1bT0jDvAokkpdoeSU4bh/by2Pn2hif20bB2rbeNN3tnPVZ/7M7/fWMi83bULbrm8LAbCuIp9QZPTx3nRRGSXZE9u3iIiIiIiIiKTGnGy5bGZ89OZV9ISj/GzHqXFtY+vRRi6Yl01dWw8N7SH8XuPEOBOdyTKa9Kj11Z8Yu7PtobEt3xEize+hpqV7fDvsZ2VZDtlpPvbWtLJ1gq2ezaCxM8TDBxrYdrSJf3/xRbT3RMhNT26NapFk2FCVz7YktPQHONPazYd+vof9dW3EHP2SwI73/WzXmJLC/c3PTaM4K0h3OMrWo6MvDbSwMIM7nlE1rn2KiIiIiIiISOrNyeQygN/r4bO3rSUUjfHLnTXj2sa+M20UZAZYXppNTyQ6oP5oakxu69vGzrEllwHKctM51Tyx5PLGqvwBZTSCPmNJSRYAkSiEozHqWrtpD42+ZXVxVpAvv+JistN8zMtJG3UXfpGpVJYbnNDglf2VZgdJD3jZeapl0Pl/2lc3ru2uq8zjqZpWTo/xItLz1sznndcsY35e+rj2KyIiIiIiIiKpN2eTy73ee/0F404uAzR2hGjpDFFdnDWhOFxSEsMjV5Q1xt902e8xxtI2e015Dt3hKBfOzxkw3RGvUd0VjvXVqjYzzOLT8zOCNHeFsMRyPeEYq8tz8JoH88Ce063sOd02YJuZAS8ryrLpDseIxGI0tYeGTDYbkJvu51B9OzevKcfjmamVeGWs5uelcbihg/WV+eytaaUr1aVsRtATjrGkOJOucIxQJEY4GqOtO0xvA+NNVQU4HI0dIQ7VDz1Q4QXzsqlv60n6BbD5uWnsGGEQ0aH8dncNq8tzuPOKxUmNSURERERERESmzpxPLudl+NlUXUBrV5jD9R2EomPvFh514PNMJG2bHM6NvPcLy3PZc7qF0DhG9fN7R1+i2+8x9td30DVEgjfgtSFj2FztZ/ep1vOmZ/g9rCrPHfQ4O0JRnqx5OuFclBWgOCeNIw0DE27PWFzIO69dRnl+OrlpASWW55ialm4WFqSz/XgTVYUZdEdinElC2ZbJ0tgZJuj3Eo7GaEiUpfF5jPwMH5UFGew53UJHKMqqcy7gDOZsx9h7HgxnYWEGHhv/+ROOOo40dHCmpXvC9Z5FREREREREJDXmfHI5O83P999wCR6Ll1fYcqSRt//wCRrae8a0nWNnO1lRlsPemvOTolNlNOniHSeaAVi/MJ9YLEZrd4SOnghnWkc+3rEkl5eWZrG3pm3QeQWZARqHSXQNNXBgZzjGo0eb2FRdwNYjw9d1bWgP0dETZc2CXJ44GS8D8Pw18/nMrWvGdBwyuzjgWGO8/f3Rs50EfcaGhfk8fqKZtRV5AByoa6elKzzitsxgUVEmmUEfu0+1kJfhp7Fj5PXGqqkjhK/fazYScywuzuJwQzsdiYs3e063sqmqALN4HeXe9wKfx2ho7znvIstoZAa8lOSkPd0fwp7uG+HzemjpDI3qfWM43996gkN1HXz7dZvoicRU91xERERERERkhpnxyeVYzE249WkkGuNIQwc+r3H5kiK2vv85tIcivPX7O/jLwQbCo2jle9GCXLaMkPCcTvrXcc3L8LOuMo+A14Nz8aRZbWs3JdlpuETBDheDurbRtfBcX5nP9uND14ktyho+uXx6hBrNjx5pZFN1PluPDF+Ltisc5UhDB3c99wIKMgJct2qeEssyQE/Ese1YvBXzrlPN9EQcCwsyWF6aPWBgunS/l9ULcsE5usMxgn4PZ1q6+0pR+L1GW1eE5aVZZKf7kzYAH0BVUSb7zgy8ULNtkDrMYxlIbzQ6QlEisRgnGid3oNKtRxv53pbj/G7PGf7r5RdTlBWc1P2JiIiIiIiISPLM+OTyBHpl9wn6vVxQ9nS3crN4MunTL15DY0eI9/50J48nWvwOxu81WruT32JxrEZRFWNQzZ3hQeumnlufNT+RhH6qppXO8NDlQyKx4UuLZAWHf9nVt/cM27rZAVuPNLG5umDYhH52mo+fvPkZLCvNHnZ/Iv1f68caOznW2Mnm6gIa2nvIy/Cz93TrsK3ley9APVXbTnVRJktLsjjc0EE0CQNFHqprZ1lpFvtr2ye8rbE609LN+oX5SRtU8FyLijK5YXUZlywq5DWXVWHJeEMXERERERERkSkzC5LLyUtGOOfoDEXJDPrwmpEZ9FKcnc2P3ngpt3/t70MmWDICPk4keaCs8Zncis9NnWGajjdTmh0kHHs68XvuMxDwDd86eDSthxfkpw/buhlgy5FGNizMH7QVZ8Dr4V9uXKnEsozbeHsi9JagKMsNUlGQOWIJl5GEY468jMCEtjFeBZkBzo6xRNBIqosyuWH1PG66aD4XzMtWQllERERERERkBpvxyeVkMjMyE61qw7EYPeEYGYF4svTmtfMHTS7npvvJz/BTmBWctNZ9ozVVgwmGY27YUiEjDfI1UstmgOAICepe2441UZ6fzqmmp7vuLy/N5jO3ruHC8txRbUNkMtS09ODzJKcMSygy9oFGJ6og04/P4zmvB8NYmcGmqgI2VRfw3AvLWFGmhLKIiIiIiIjIbKHk8hCCPi9Bn7fv/ks3VjI/N538TD95GQHyMwLkpvvxeowna1r5t18/id9ro6rPPFnGWxYj2SLR4RNhHT2REbex+1QLAZ9nVEm17MQFgVXzc/inq5byzKVFfRcJRPqbypSm32PMy03jRNPYaxYvK80iJy3+/tLeE2F/7eCDY06WnDQfHjNONY+/3vLaijyuv3AeN64uo6IgI4nRiYiIiIiIiMh0oQzcKAV8Hq5eWTrovBVlOXzndZtp7Q7zwL46fr+3lgefqqd9FEnU0SjLHWqAq4GpskgS6ruOxkgJupHiONs+cn3qjICPrnCU4QtjxO0708azlhXzsZsvpLJQSSyZHgqzAjyaGNjP7zXKctOpaeliaUk2AZ+Hjp4wZ9vDNHYOfJUvK83idHM3+3umvsZyr6Wl2ePqiZER8PKay6p4+eaFzM9Ln4TIRERERERERGQ6UXI5iXLS/Ny8tpyb15bTE4nyt0Nn+d2eWv7wZC31baOrW7q5Ot59HCDmHNGYoyMU5Tt/OzaZoY9JdVEmZ4eoh7yoKJO9Na3Drt/aPXLKeH5eGrtODb+dXl6P8e7rliuxnGBmLwE+AqwANjnntiWmVwFPAk8lFv27c+5Ng6xfAPwQqAKOArc651Jb82UGOtPaEy8BgXGovo3jjZ0sL8067/wI+DwUZwUpz0/nYF07J5q66ApFUxKz12NUF2WSGfAS9Bo9o+iJsagok42JshdXryglN8M/BZGKiIiIiIiIyHSg5PIkCfq8XLm8hCuXl/CJ2IU8frKZ3++p5W+Hz/aVjegtO2oYWUEf8/Mi3LKunJduqhywLeccFfnp/Mfv96ek9uq59tS0UpAROK/FJUBOup9ww/AJqcyAj57I8K2XO8eQXHvWsmLVVx5oN/BC4KuDzDvknFs7wvp3AX90zn3SzO5K3H9vckOcG56sGVjOIif9/MRrKBLjVHMXp5q7UlZaJzvNx4qyHA7WtnOwLv4Xb0HdRXvPwHNxRVkO16ws5eLKPNZW5KVssEERERERERERSb2kJZfNLA14CAgmtvsT59yHzawa+AFQCGwHXumcG021gynV1h0mI+DD60l+VVaPx7i4Mp+LK/PHtb6ZcecVi7lkUSGvu2fbqFtBT5auUJTV5blsPdJ43rxYzLFqfs6AabWt3TS0P/2Upwe80BmmJDtIcfbgianMgI+jZzuJjqLUx5uvXDzGI5jdnHNPAhMZNO1m4MrE7XuAP6PkclI0tA9/7qYisZyT5qOjJ3Le+by/tp3N1QVsOdJIQWaA2zZW8IK15Syflz3lMYqIiIiIiIjI9JTMlss9wFXOuXYz8wOPmNlvgHcAn3PO/cDMvgK8DvhyEvc7ZqFIjNPNXfzlUAP7ato429HDA/vqKc0JUpQVpKIgg1AkxgsvLic7zU8kFiMr6KOqKJOctNR1+b5oQR6/edsz+fff7uNH206mLA6AziHqSe881XLetOWl2QOSy2l+L6U5QdL9XvbXtg+ZUNtYlY9zEI05QtEYoUiM7kiUzp4oHaEIK8py8HuN+UPWpJZBVJvZDqAV+KBz7uFBlil1ztUkbp8BBi82LmOWnxHgCJ0pjaE0J0hlQQbOxctgdIYiQ5agyUv38/9euJqb184nI6COLiIiIiIiIiIyUNKyBc45B/SOQOVP/DngKuBlien3EK8Fm5LksnOOz96/n68+dHjQ8hJHz3Zy9Gwn2xIDWf1qV815y6T7vWQEvFQWZtDSFcbv8XDJogJu21jJynNa7E6Goqwgn3rRRRw728mWQVoOTwWPwZ7TI9dDLs4OcumiQmpaullTkccVS4voDEVI83lZtzCfbzx8mBeuK6cgK0huup/D9R38z1+P0BmK0hOJ9Q2GNhgj3oJ6x5k29ta0U56fmcQjnP7M7A/AvEFmfcA594shVqsBKp1zZ81sPfBzM1vlnBvyyXTOOTMbsjmtmd0J3AlQWVk51GLTxgRacyfFyaaulO3b6zHWVeSx7VgTta2j6/1gZty+afo/ryIiIiIiIiKSGkltimZmXuKlL5YA/wUcApqdc73NXE8C5cnc50i6w1E+9su9NHaEOFTfzv7a9pFXGkZXOEpXODpgQLunatuoLsqckuQyxBM+L9lQkbLkcnVRJofrO0ZcLifNR0FmgCXFmawqz+HKZSVEYo6g3wvA1SvObxD7pisX8e+/fYpvPHIEgGWlWbzpWYv55c4a/rSvrm85B+w7E69n+/CBeq5ZObca1zrnrh7HOj3EexjgnNtuZoeAZcC2cxatNbMy51yNmZUBdQzBOXc3cDfAhg0bpr6mwwyyan7OqC7KJMumqgI6QmEyg36cc9S0dPddOButbccaicbcpJQLEhEREREREZGZL6nJZedcFFhrZnnAvcAFo1lvMls/pvm9vO3qpTz4VD2H6ieWWJ5Oblg9j3v+epRd55Sh+MANK3jR+gWcbu6iJxLj33+7LylJ6BevX8CWI2epLsriJesXUJgVr5X8xyfr+PvhsywryWLzokK++tBhjp3tIObgUH0Hhxs6WFeRx60bK4k5h8/rGXY/QZ+Xd127nPK8dJbPy+IZi4swM16wtpx/+v6OQVuT//HJOj50U2zEbc91ZlYMNDrnoma2CFgKHB5k0fuAO4BPJv4P1RJaxqAoK8im6gIg3ovCOYgl/kedIxZzff8jib+ecIzatm7cMGn7oM/D4uIszByZQT8tnWFausLsON5EeBQ1y4fT0B7ik795kg/cuHJC2xERERERERGR2cnccFmLiWzY7ENAF/GBwOY55yJmdinwEefcdUOtt2HDBrdt27kNKSemqTPEnlOtBP3x5OODT9Xz10MN7DrVkrQBtD7yvJW8+rLqpGxrtCLRGN945Ajf23qcY2c7WVGWw2/e9swBy0Rjjnf86HF+8fjpCe3rvdcv52WbK8lNH3wAvt59eQze8O1tPHKwgcuXFLFmQR5m0NQZ5o5Lq6gszBh3DN3hKO+/dxc/e+zUefO+ePs6nr9m/ri3PR2Y2Xbn3IYkbOcW4EtAMdAMPO6cu87MXgR8FAgDMeDDzrn/S6zzdeArzrltZlYI/AioBI4BtzrnRrxCMRnnbrJd/dkHOViXmotM8/PSON3cPeb1ynKD5KYH+lrqD8bvNcpy0zjeODllN/Z97HrSEj0O5HzJOndFREREREREZpqktVxOtIoMO+eazSwduAb4FPAA8GLgB0xxK8i9p1v5+iOHeWBfHU2dYQoyAxRmBugMRTnVnLrap8ni83p447MW89rLq/m/J06zeVHhect4Pcbnbl3LkYYOdp48f7C9kZjBHZdW8cYrFuMZoWt8b9f5r9+xke5wlIDXQ3ckSkbAx86Tzfi8E+tan+b38pmXrGF+bjr/+cDBAfM++/unuHZlqRJggHPuXuI9B86d/lPgp0Os8/p+t88Cz5m0AOegDQvzx1ySoldNSw/t3REW5KeTl+5nd6K0xsaqfGIOth9roiQnbVIH3GvpCuvcEhEREREREZHzJDMbUQbck6i77AF+5Jz7pZntBX5gZh8HdgDfSOI+h7Vyfg7vvHY5rV0R2nvC5GcEaO4Ms35hPg8fqOeJcSRbpyO/18MLL14w5HyPx/jEC1bz/P96ZNju9b1KsoO8aP0CWrrCvGLzwnHVku5NRPUmvC5akDfmbQzGzOKlBR4YOP14Yyc/fewkL9+8MCn7EUmmidYsbuuJ0tbTxcmmLublplGSFeTRo00UZAS4YF42LZ0hTjV1jnv7BZkBstN8bK4uoCw3nb01rczLSaO+rYdQNEZ9Ww+lOWkTOgYRERERERERmX2Sllx2zu0E1g0y/TCwKVn7Gc7h+nYaO0I4YPm8bHLS/JTnpfP1Ozb0xkJPJMauUy0caeiYNcnl0Vi9IJcbV5fxy53n1yzub35uGq9/ZjUvungBuRlDl8BIpZ0nm8+bFnNQ39Yz9cHIjDJZZYBG0hmKsK4ilx0nJv6eU5wVYGei1npjZ4jGzhB+rxGOOjZV53OsoZPaUZwLAa+Hm9fO55qVpVyyuJCcNP+EYxMRERERERGRuWXy+lGnwKLiLBYVw8mmTnz9WgpGY47/fuAgdz98mKDPQ0N7KIVRps7nb1tLTUs324fonl9VmMEHb1zBsy8onXBLy8l0pKGTqsIMjp4d2FLzt7vP8JZnL9HAfjLt7DrVyrLSrKRt61y9teO3HmnC6zEWFmZQ29rNirIcDte309IVGbD81StK+bcXXkhJtloji4iIiIiIiMj4zcos3IL8jAH1R7/y4CE+c/9+2rojY04sm0H6JNcabe+J0NET4Zb//gvHznZM2n58Xg/fes1GLl9SNOj8paVZXLq4aFonlgFee3kVjR3nP4/7zrTx8IGGFEQkM0Vq2i3H5U1RT4BozHHsbCfd4Rg7jjfT0hVhSUkWm6sLuOmiMt55zTK+9qr1SiyLiIiIiIiIyITNmpbLLZ1hctJ9mA1MjHaGIrzo4gXsPtXCwbp2jp3tBINQJDbs9szgTc9axNGGTg7Vt3P0bCcfvGEF+Zl+frPrDDuON1HT+nTX85iDnkgU5xjzwFfhSIy8DD/ff8MlA9Y90dhJesBLUVZwTNsbTk6an8uXFvHIwYFJ2AX56dy2sYLM4PR/SSwqyiLo90J35Lx539t6jGdfUJKCqGQmSOVlk5hz+D1GODb1Ke6Dde0cBP7+vucwL1dJZRERERERERFJjumfSRyl3Izz64U65/jbobN4PcYXXrqOe3ecpCQ7jZ8+dnLY2sMXlufwlmcvJc3v4de7zvC8i+azqbqAyvx0SnLTeN6acnrCUfadaSPo99DcGWbnyWa+/OdD7K9t4+1XL2NxcRY/3HaC9QvzWVaaPWzs+ZnxFo3nJqUfeKqOutYe3nntMoDzEufj9bw18/nKg4do7gz3TTvZ1EV2cGbUXE0PePn0iy/iy38+xJYjjQPm3b+3juNnO6kszEhRdDKdFWcHOVQ/eb0DhuMhNYnlXhkBL0VZ07OOuoiIiIiIiIjMTLMmuTwYM+M5K0r77t+2sRKAcDTGJYsK8Hs9PHWmnVA0ym9319LQHm+JvK4in7ULcgn4jQfeeSWeQcpEBP1e1lTk9d2/ZFEhEG8p/csnavjSnw7S2NHD/XvOsHlRAa9/5uIxl5t41aVVfbd/v+cMPo+RlebnogW5Y24d3V95XjqvvGQh//XAQfrnunacaGZz4jimuyuXl9DYHjovuQzQ2h0eZA0ReMHacv5++PzXzGSbl5vG3tOpHUA0K+jDk6QLVCIiIiIiIiIiMEtrLo/k2lXzeMUlVdy2sZIPPW8lm6oLaezo4eoVJfzn7euoLs7gi386gM/jHTSxPJyMgI9bN1bw6RdfxOLiLDZU5dHWHeH9P9tFJDp8KY7hXLakiKWl2fzxyVr+74nT495Or3deu5yH3vNs3nrVEqoKMwh4PfzfE6dp6uwZeeVp4oXrF7BwkBbKg00TAbj+wnmU56VP6T43LMyntTNEeyg6pfs9l4Mxv5+JiIiIiIiIiAxn1rVcds7RHY6SHhj50B492siPt52grTvCf798PddfOI/mzhCPn2jmRRcvICd9/GUign4v77xuOd/9+zEKs3w45/j8H/Zz++aF40puZQZ9ZAZ9vO+GFQCcbOpkQf7EkqgL8jN4x7XLece1y+kOR/nLwQaCvskdvDDZ7n7lBv7lF7vZmmjBXF2USXbazCjvIVMvLyNAfqafU81dU7K/C+fnsP1YU0oHEuz1msuqUh2CiIiIiIiIiMwysy65bGbDJpZbusL86NEThKNROkNRbrxoPpcvKcLrMSLRGHkZAa5cnpwB4XLS/LzxisUcrG/jS388wAXzsnn/z3Zy+6ZKrr+wbNzb7Q5HecF//ZV1lXl87OYLkzJAV5rfO6CEyEyxfF42X3zpOp7zmT/TEYryqksXpjokmeb+5caVvOqbW+kZYVDPZEjze1OaWK4qzOAlGyq4bEkRaxbkpjASEREREREREZmNZl1yeTDOOfacbuWpM21UFqTzwvXlZPi9dIUi5GcG+wbK83mTXyXE4zGWFGfxykuriMZg1fw8Vs7PmdA2tx5ppKG9h/v31tITifH1V20g4JuTFU4AKM0JctdzL8Dv9XDp4plRM1pSZ/OiQh5415X8elcN//brJ5nMMfa2HWviwvIcDNh1qnXydnSOG1eXccczqthYlZ+0gUBFRERERERERM41a5PLsZjjcEM7Rxo6WbMglwvL43/9jaZ0RjJ4PB42VScv6dmbQN1UVcAL15Xj987d5FEkGiMUjfHCdQsIeA3/BAY6lLljfl46r3/mIrpCUT5z//5J3dfuU61sqi6Y1H30KsoK8IEbV3DLugVTsj8RERERERERmdtmfHI5FnOEojG8HsPnMSKJZoj1bT1UFWaypCQ7xREmn89j/PfLL+b6VfPm/ABdkWiMjCm6SCCzz53PWsS2Y008uL9+UvcTmuQSHBfMy+bNVy7m+gvnzbi66SIiIiIiIiIyc83IrFxdWzedoQil2Wl0hqIA5Kb7MbO+VrzzxzFo3kxhZtywevw1m2eTNCWWZQKCPi93v2o939tynH/9v72Tso9lpVkcrGublG0DrJqfw0/f/AzS1GpfRERERERERKbYjCzUW5KdRlVhFukBH4VZQQqzgpNSL1lkJjKzl5jZHjOLmdmGftNfbmaP9/uLmdnaQdb/iJmd6rfcDVN6AFMs6PPymsuqec4FyRnI81wxB+090UnZdsDn4XO3rVViWURERERERERSQhlZkdlnN/BC4KH+E51z33XOrXXOrQVeCRxxzj0+xDY+17usc+7XkxrtNPGll63jlZcsJCuYvNbwuel+jja0J21753rF5oUsK519pX9EREREREREZGZQcllklnHOPemce2qExW4HfjAV8cwUGQEfH3vBhTzwrivJSUtOgnlZaRaTVW454PXwovXlk7NxEREREREREZFRUHJZ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nIlGON43A293zlUAbwe+kdpoZbzMLAv4KfDPzrnW/vMSvQembQvVQWL/MrCYeOmGGuAzqYtucM65aKKczALiPRguSG1Eo3Nu3GZ2IfGLShcAG4EC4L2pi1BERERERERkdvOlOoDJ4py7ejzrmdkC4F7gVc65Q4nJp4gnL3otSExLuXEe5ymgot/9/scz1PRpYbjjNbNvA29L3P0x8PXE7eGOV6YZM/MTT85+1zn3s8TkWjMrc87VJEqa1KUuwqENFrtzrrbf/K8Bv0xReCNyzjWb2QPApcTLx/gSrZen9TnTL+7rnXP/kZjcY2bfAt6VwtBEREREREREZrVZ23J5PMwsD/gVcJdz7i+90xPd8VvN7BIzM+BVwC9SE2VS3Ae8NFFPupr4QHdbgUeBpWZWbWYB4oP+3ZfCOMfqNPCsxO2rgAOJ2/cBr7K4S4CWfiUWZBpJnF/fAJ50zn2236z7iA+ySeL/tDv/hor9nPretxAfaHPaMLPixHsfZpYOXEO8XvQDwIsTi027x3yIuPf1Pt6J5+MFTLPHW0RERERERGQ2sXgP87nFzG4BvgQUA83A486568zsg8S7VB/ot/i1zrk6M9sA/A+QDvwG+Cc3zR+8oY4zMe8DwGuBCPHu+79JTL8B+DzgBb7pnPvE1Ec+PmZ2OfAF4i3yu4F/cM5tTySZ/hO4HugEXuOc25a6SGUoiefwYWAXEEtMfj/x2sU/AiqBY8CtzrnGlAQ5hGFiv514SQwHHAXeOJ0ubpjZRcQH7PMSv+D4I+fcR81sEfFBPQuAHcArEjXop4Vh4v4T8fc8Ax4H3tRv4D8RERERERERSaI5mVwWERERERERERERkYlRWQwRERERERERERERGTMll0VERERERERERERkzJRcFhEREREREREREZExU3JZRERERERERERERMZMyWURERERERERERERGTMll0VERERERERERERkzJRcFhEREREREREREZExU3JZRERERERERERERMbs/wMM0TzzkjnzFAAAAABJRU5ErkJggg==", + "image/png": "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Cy9www03cP7553PBBRcAMGLECPc9HA4HM2bM4KSTTuKxxx5zt6E1Y9TmHDp0iE8++YRZs2aRkpJCYWEhL730EieffDK7d+8mLi6uVfcTQhy/LrroIpKTk3n44YdZu3YtzzzzDOXl5bzxxhsAPPjgg9x9991cdNFFXHfddRQXF/Pss88ydepUtmzZ0qAEzhEul4uzzz6b9evXc8MNNzBo0CA+/fTTTnuOvvjiixk8eDD/+c9/+PLLL3nggQcICwvjpZde4tRTT+WRRx5hxYoVLFy4kHHjxjF16tROaYcQ4vjVXH963XXX8frrr/O3v/2N2267jXXr1vHwww+zZ88eVq5c2arPuf3223n//ffdC9KPeP/995k+fTqhoaGNXv/0009zzjnncPnll2Oz2Xj33XeZNWsWX3zxBWeeeWbbvrwQQrRTc30owI8//sj777/P/PnziYiIcC/waUm/9ve//53TTz/d4zO/+eYbVqxYQVRUVJd9T9GNKEL4SE1NTYNja9asUQDljTfecB/76aefFED56aefmrz24YcfVlQqlZKZmek+Nnv2bAVQ7rvvPo9zR48erYwZM8b9+pNPPlEA5b///a/7mMPhUKZMmaIAyrJly9ryFYUQQlGUlvd3y5YtUwDlpJNOUhwOh/u41WpVwsPDlXHjxil2u919fPny5QqgnHzyye5jb775pqJWq5XVq1d7fN6LL76oAMrvv//uPgYoer1eSUtLcx/btm2bAijPPvus+9ijjz6qAEp6enqD75GUlKTMnj27wXc4/fTTFZfL5T5+6623KhqNRjGbzU3+XP7+978r/v7+Sl1dXYP3hBDHp5b2oUuWLFG8Pd4c6ZeO9GErV65UAGXDhg2NfmZxcbECKEuWLGnw3pHx5aJFi1rUVm9jVG9tPbY/raurU5xOp8c56enpisFgaDC2FUIIb470Neecc47H8RtvvFEBlG3btikZGRmKRqNRHnzwQY9zduzYoWi1Wo/js2fPVpKSktyvP/roIwVQnnrqKfcxp9OpnHrqqQ2eo4/t99LT0xt91j62/z1y7fXXX+8+5nA4lPj4eEWlUin/+c9/3MfLy8sVPz8/j/5UCCHaqyX96datWxVAue666zzOWbhwoQIoP/74o/vYySef7PEc761PnDhxosfcpaIoyvr16xuMgY/tmxWl4ZjUZrMpw4YNU0499dTWfG0hhOgQLelDFaV+DKhWq5Vdu3Y1uEdb+rUDBw4oJpNJ+ctf/uKeZ/XW3zY2lyB6PkmBLnzGz8/P/Xe73U5paSn9+vUjJCSEzZs3t/hai8VCSUkJkyZNQlEUtmzZ0uD8f/zjHx6vp0yZwqFDh9yvv/rqK7RarXtHOIBGo+Gmm25q9fcSQohjtba/mzt3rkctmo0bN1JaWsrcuXPRav9M3nL55Zc3WPX9wQcfMHjwYAYNGkRJSYn7z6mnngrATz/95HH+6aefTmpqqvv1iBEjCA4O9ugj2+L666/3SHM5ZcoUnE6nRwq3o38uVVVVlJSUMGXKFGpqati7d2+7Pl8I0Xu0Z8zozZGdjF988QV2u73N7Tp63OitrS0ZozbFYDCgVtc/rjmdTkpLSwkMDGTgwIFt+t5CiOPXvHnzPF4fec796quv+Pjjj3G5XFx00UUeY8eYmBj69+/fYOx4tG+++QadTsfcuXPdx9RqdYPP6yjXXXed++8ajYaxY8eiKArXXnut+3hISAgDBw5s91hWCCG8aao//eqrrwBYsGCBxzm33XYbAF9++WWrPuviiy9m06ZNHDx40H3svffew2AwcO655zZ57dFj0vLycioqKpgyZYqMIYUQPtVUH3rEySefzJAhQxpc29p+zWKxcP755xMaGso777wjNb+PUxIAFz5TW1vLPffcQ0JCAgaDgYiICCIjIzGbzVRUVDR5bVZWFnPmzCEsLMxd1/vkk08GaHCt0WhskKo3NDTUXSsH6mtLxsbGEhgY6HHewIED2/MVhRACaH1/l5KS4vH6SNC4X79+Hse1Wm2DWl8HDhxg165dREZGevwZMGAAUJ/692iJiYkNPv/YPrItjr3vkUD90ffdtWsX559/PiaTieDgYCIjI7niiiuAhn25EOL41Z4xozcnn3wyF154IUuXLiUiIoJzzz2XZcuWNVub8Whardaj/MQRrRmjNsflcvHkk0/Sv39/j++9fft26SOFEK3Sv39/j9epqamo1WoyMjI4cOAAiqLQv3//BuPHPXv2NBg7Hu3Ic/SxpSiOHbN2lGPHlyaTCaPR6C7Rc/Tx9o5lhRDCm6b608zMTNRqdYM+MCYmhpCQEK/1vJsya9Ys1Gq1u4yYoih88MEHnHHGGQQHBzd57RdffMGJJ56I0WgkLCzMXeJHxpBCCF9qqg894tg50SNa26/NnTuXgwcPsnLlSsLDwzvsO4ieRWqAC5+56aabWLZsGbfccgsTJ07EZDKhUqm45JJLcLlcjV7ndDr5y1/+QllZGXfccQeDBg0iICCA3Nxc5syZ0+BaWd0jhPC11vZ3R69qbC2Xy8Xw4cN54oknvL6fkJDg8bqxPlJRlDa3oSX3NZvNnHzyyQQHB3PfffeRmpqK0Whk8+bN3HHHHU3+HhBCHF9a2ocenXXiaE6n0+O1SqXiww8/ZO3atXz++ed8++23XHPNNTz++OOsXbu2wYJIb47enX3057RmjNqchx56iLvvvptrrrmG+++/n7CwMNRqNbfccov0kUKIdjm6v3S5XKhUKr7++muv47eW9IntbcPRju2zj+atfZ01lhVCiJbw1pc11r+1VlxcHFOmTOH999/nzjvvZO3atWRlZfHII480ed3q1as555xzmDp1Ks8//zyxsbHodDqWLVvG22+/3SFtE0KIjuCtv/Q2J9rafu3pp5/mnXfe4a233mLUqFGd0XTRQ0gAXPjMhx9+yOzZs3n88cfdx+rq6jCbzU1et2PHDvbv38/rr7/OVVdd5T7+/ffft7ktSUlJ/PDDD1RXV3s84O/bt6/N9xRCiCPa2t8dkZSUBEBaWhrTpk1zH3c4HGRkZDBixAj3sdTUVLZt28Zpp53WYQ/eHXWfo/3888+Ulpby8ccfM3XqVPfx9PT0Dv8sIUTP1tI+9EimCbPZ7E5zDjS62+bEE0/kxBNP5MEHH+Ttt9/m8ssv59133+W6665rU7/X0WPUDz/8kGnTpvHqq696HDebzQ12OwohRFMOHDjgsZsmLS0Nl8tFcnIyGo0GRVFISUlxZwxqqaSkJH766Sdqamo8doGnpaU1e+3RffbRWrtDUgghulJT/amiKLhcLg4cOMDgwYPd5xQWFmI2m93P9a1x8cUXc+ONN7Jv3z7ee+89/P39Ofvss5u85qOPPsJoNPLtt99iMBjcx5ctW9bqzxdCiI7UVB/alNb0a6tXr2bhwoXccsstXH755R3WdtEzSQp04TNHHrSP9uyzzza54vvIdeC5oltRFJ5++uk2t+Wvf/0rDoeDF154wX3M6XTy7LPPtvmeQghxRFv7uyPGjh1LeHg4r7zyCg6Hw318xYoVDdI7XnTRReTm5vLKK680uE9tbS0Wi6XV7Q8ICAAaTlC2h7e+3Gaz8fzzz3fYZwgheoeW9qGpqakA/Prrr+5jFouF119/3eO88vLyBvc7sir8SBr0I4Gc1vR7HT1G9fa9P/jgA3Jzc9t0PyHE8eu5557zeH3kOfeMM87gggsuQKPRsHTp0gZ9jqIolJaWNnrfGTNmYLfbPcadLperwed5ExwcTEREhEefDchYUAjRrTXVn/71r38F4KmnnvI450h2tjPPPLPVn3fhhRei0Wh45513+OCDDzjrrLPcz+eN0Wg0qFQqj7FyRkYGn3zySas/XwghOlJTfWhTWtqv5efnc9FFF3HSSSfx6KOPdkyjRY8mO8CFz5x11lm8+eabmEwmhgwZwpo1a1i1alWzNRkGDRpEamoqCxcuJDc3l+DgYD766KN21fg6++yzmTx5MosWLSIjI4MhQ4bw8ccfS20cIUSHaGt/d4Rer+fee+/lpptu4tRTT+Wiiy4iIyOD5cuXk5qa6rFT8corr+T999/nH//4Bz/99BOTJ0/G6XSyd+9e3n//fb799lvGjh3bqvaPGTMGgH//+99ccskl6HQ6zj777GYfvJsyadIkQkNDmT17NjfffDMqlYo333xT0lUKIRpoaR86ffp0EhMTufbaa/nXv/6FRqPhtddeIzIykqysLPd5r7/+Os8//zznn38+qampVFVV8corrxAcHOyeuPTz82PIkCG89957DBgwgLCwMIYNG8awYcMabWdHj1HPOuss7rvvPq6++momTZrEjh07WLFiBX379m3T/YQQx6/09HTOOeccZs6cyZo1a3jrrbe47LLLGDlyJAAPPPAAixcvJiMjg/POO4+goCDS09NZuXIl119/PQsXLvR63/POO4/x48dz2223kZaWxqBBg/jss88oKysDms8idN111/Gf//yH6667jrFjx/Lrr7+yf//+jv3yQgjRgZrrT2fPns3LL7/sLvm1fv16Xn/9dc477zyPbG4tFRUVxbRp03jiiSeoqqri4osvbvaaM888kyeeeIKZM2dy2WWXUVRUxHPPPUe/fv3Yvn17q9sghBAdpbk+tDEt7dduvvlmiouLuf3223n33Xc97jFixAiPDJri+CABcOEzTz/9NBqNhhUrVlBXV8fkyZNZtWoVM2bMaPI6nU7H559/zs0338zDDz+M0Wjk/PPPZ/78+c12lo1Rq9V89tln3HLLLbz11luoVCrOOeccHn/8cUaPHt2mewohxBFt7e+ONn/+fBRF4fHHH2fhwoWMHDmSzz77jJtvvhmj0eg+T61W88knn/Dkk0/yxhtvsHLlSvz9/enbty///Oc/W53aEmDcuHHcf//9vPjii3zzzTe4XC7S09PbFQAPDw/niy++4LbbbuOuu+4iNDSUK664gtNOO61VPxchRO/X0j5Up9OxcuVKbrzxRu6++25iYmK45ZZbCA0N5eqrr3afd2Qy8t1336WwsBCTycT48eNZsWKFRzq2//3vf9x0003ceuut2Gw2lixZ0mQAvKPHqHfeeScWi4W3336b9957jxNOOIEvv/ySRYsWtfpeQojj23vvvcc999zDokWL0Gq1zJ8/32NXzKJFixgwYABPPvkkS5cuBSAhIYHp06dzzjnnNHpfjUbDl19+yT//+U9ef/111Go1559/PkuWLGHy5MkeY1Rv7rnnHoqLi/nwww95//33OeOMM/j666+JiorqmC8uhBAdrLn+9H//+x99+/Zl+fLlrFy5kpiYGBYvXsySJUva/JkXX3wxq1atIigoyL1Ysymnnnoqr776Kv/5z3+45ZZbSElJ4ZFHHiEjI0MC4EIIn2quD21MS/u14uJinE4nCxYsaHCPJUuWSAD8OKRSZKuVEEII0SO5XC4iIyO54IILvKY8F0IIIYQQoqt98sknnH/++fz2229MnjzZ180RQgghhBBCHIekBrgQQgjRA9TV1TVID/7GG29QVlbGKaec4ptGCSGEEEKI41ptba3Ha6fTybPPPktwcDAnnHCCj1olhBBCCCGEON5JCnQhhBCiB1i7di233nors2bNIjw8nM2bN/Pqq68ybNgwZs2a5evmCSGEEEKI49BNN91EbW0tEydOxGq18vHHH/PHH3/w0EMP4efn5+vmCSGEEEIIIY5TEgAXQggheoDk5GQSEhJ45plnKCsrIywsjKuuuor//Oc/6PV6XzdPCCGEEEIch0499VQef/xxvvjiC+rq6ujXrx/PPvss8+fP93XThBBCCCGEEMcxqQEuhBBCCCGEEEIIIYQQQgghhBCiV5Aa4EIIIYQQQgghhBBCCCGEEEIIIXoFCYALIYQQQgghhBBCCCGEEEIIIYToFVpdAzw3N5c77riDr7/+mpqaGvr168eyZcsYO3YsAIqisGTJEl555RXMZjOTJ0/mhRdeoH///o3e895772Xp0qUexwYOHMje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GVlZWYiJibFaZmhoKHx8fLBv3z7zg1W1Wo1jx45h4cKFdm1PW7HH52JNdnY2SkpKLB5Id2ZNfS4tIRKJEBUVhX379mHGjBkAakfH79u3D08++WSryycdR6lUQqlUtklZMTExeOutt1BYWGhOCbt3717IZDLzzVtMTAx+++03i/P27t3brN9JW9naturqagCol0mEx+OZR1/b0jZ7srUtUVFREIvFSE5OxqhRowDUBqIyMjIQHBwMoOPbAtjeng8//BBvvvmm+XVubi5iY2PxzTffIDo6GkBte1566SXo9XoIhUIAte2JiIgwpwi0p+b8DuXk5GD8+PHmUfw3fuc6ui2k49hyXRYTEwOVSoVTp06Z13/cv38/TCaT+fehM6gLfl+6dAkHDhyAh4eHxf6u0o6HHnrI6tpvDz30kHl9ta7QFpFIhGHDhiE5Odlie0pKivnvQltdM9ubXq+HXq+v13fy+Xzz3+uu0pbuyB73KN3dhAkTcO7cOYttc+fORe/evbF06VIKfrfAyJEjG+0vCWkNR7o/bYnmPntgjGHbtm14+OGHzfdGdbrifZOj3dO3RGuePyUkJIDH45nb2xW/A6RlHPm55fXaso+0JiEhocNiG476u9+WzwOt6cifmS3sGi9iDqyiooLFx8ez+Ph4BoCtXbuWxcfHs8zMTMYYY99++y07cOAAu3z5Mvvxxx9ZcHAwu/POOy3KeOihh9iyZcvMr1977TX2559/ssuXL7NTp06x++67j0kkEnbhwoV2bVtLLVy4kMnlcnbw4EGWl5dn/q+6utp8zOOPP86CgoLY/v372cmTJ1lMTAyLiYmxKCciIoL98MMP5terV69mbm5u7KeffmJnz55l06dPZ6Ghoaympqbd2tYa9vhcKioq2PPPP8/i4uJYeno6++uvv9iQIUNYeHg402g07dq+lrLlc8nLy2Px8fHs448/ZgDY4cOHWXx8PCspKTEfc/PNN7MNGzaYX3/99ddMLBaz7du3s8TERLZgwQLm5ubG8vPz27V9pONkZmay+Ph49tprrzEXFxdzX11RUcEYY8xgMLD+/fuzSZMmsYSEBPbHH38wpVLJli9fbi4jLS2NSaVS9p///IclJSWxjRs3Mj6fz/7444+OahYrKipiHh4e7M4772QJCQksOTmZPf/880woFLKEhATGmG1t6ywWL17M/P392Z9/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n3/+aVGdfX19MWjQIOzYscMi5c/evXsbXN+HEEJai8fjYcaMGfjll19w8uTJevsZY21+LWjrdWBz+kU+nw+O4yyycGRkZODHH39sUR0JIaS1bOlf25KXlxfGjRuHLVu2IC8vr97+669ZCSGkM2jvfrIh9IySENJebOn3br31Vhw/fhxxcXHm7VVVVdi6dStCQkLQt29fq2Vff/98/aSf8+fPY8+ePbj11lvbvD2fffYZKioqzK+/++475OXlYcqUKQ2eQ/fuXQ/NACd2k56ejmnTpmHy5MmIi4vD559/jlmzZmHgwIEAgEcffRSrV6/Go48+iqFDh+Lw4cNISUlpslxvb28sXrwY77//vrn8M2fO4Pfff4enp6dFiuDbbrsNr7/+OubOnYsRI0bg3Llz+OKLL8wjzFuid+/e6NGjB55//nnk5ORAJpPh+++/b9YaZ4QQ0hB79Z3Xe+SRR7B27VrExsZi3rx5KCwsxObNm9GvXz+o1eoW1XvVqlWYOnUqRo0ahUceeQSlpaXYsGED+vXrh8rKyhaVSQghTXn77bexZ88ejB07FgsWLECfPn2Ql5eHnTt34u+//27za8HmXAfa2i9OnToVa9euxeTJkzFr1iwUFhZi48aN6NmzJ86ePdviz4YQQlqjqf61rW3cuBGjRo3CgAEDMH/+fISFhaGgoABxcXHIzs7GmTNn2vw9CSGkNdq7n7SGnlESQtpTU/3esmXL8NVXX2HKlCl4+umnoVAosGPHDqSnp+P7778Hj9fwfNx3330XU6ZMQUxMDObNm4eamhps2LABcrkcr776apu3RaFQYNSoUZg7dy4KCgqwbt069OzZE/Pnz2/wHLp373poBjixm2+++QZisRjLli3D7t278eSTT1qkn3zllVcwb948fPfdd3jhhRdgNBrx+++/21T2mjVrsGLFCpw4cQLPP/88UlNTsWfPHjDGIJFIzMe9+OKLeO655/Dnn39i8eLFOH36NHbv3o3AwMAWt0soFOKXX37BoEGDsGrVKrz22msIDw/HZ5991uIyCSGkjj37zjp9+vTBZ599hvLycixZsgQ///wz/ve//2HIkCEtrvfkyZOxc+dOGI1GLF++HD/88AO2bduGoUOHtrhMQghpir+/P44dO4a7774bX3zxBZ5++ml89tlnGDduHKRSaZtfCzbnOtDWfvHmm2/GJ598gvz8fDzzzDP46quvsGbNGtxxxx0tqiMhhLSFpvrXtta3b1+cPHkSU6dOxfbt27Fo0SJs3rwZPB4Pr7zySpu/HyGEtFZ795PW0DNKQkh7aqrf8/b2xr///otbbrkFGzZswPLlyyESifDLL780eX87ceJE/PHHH/Dw8MArr7yC9957DzfddBP++ecfi6Ui28qLL76IqVOnYtWqVVi/fj0mTJiAffv2Ndp/071718Ox9srJQoidqVQquLu7480338RLL73U0dUhhBBCCCGEEEIIIYQQQgghhLQzmgFOuqSampp629atWwcAGDduXPtWhhBCCCGEEEIIIYQQQgghhBDSKdAa4KRL+uabb7B9+3bceuutcHFxwd9//42vvvoKkyZNwsiRIzu6eoQQQgghhBBCCCGEEEIIIYSQDkABcNIlRUZGQiAQ4J133oFarYa3tzcWL16MN998s6OrRgghhBBCCCGEEEIIIYQQQgjpILQGOCGEEEIIIYQQQgghhBBCCCGEEIdAa4ATQgghhBBCCCGEEEIIIYQQQghxCBQAJ4QQQgghhBBCCCGEEEIIIYQQ4hC6zRrgJpMJubm5cHV1BcdxHV0dQkgrMMZQUVEBPz8/8Hg0jsceqM8kxHFQn2l/1GcS4lio37Qv6jMJcSzUZ9oX9ZmEOBbqM+2L+kxCHEtr+8xuEwDPzc1FYGBgR1eDENKGrly5goCAgI6uhkOiPpMQx0N9pv1Qn0mIY6J+0z6ozyTEMVGfaR/UZxLimKjPtA/qMwlxTC3tM7tNANzV1RVA7Qclk8k6uDaEkNZQq9UIDAw0/16Ttkd9JiGOg/pM+6M+kxDHQv2mfVGfSYhjoT7TvqjPJMSxUJ9pX9RnEuJYWttndpsAeF3KC5lMRp0fIQ6CUtnYD/WZhDge6jPth/pM0p4YYzCYGPgch/grKmSVVkEs4EMq4sNoYpCKBHB3FuJ8jhrnslXQGRlEfA4iAQ9uUhFuCvNAUYUWey7ko7RaB6mIjxAPZ2SUVEFdY4DRxNDL2wUuEgH4HAe5VAQhn4NMIkSQhxQ9PF1QWq0DB6CwQosIb1eoNXooXcWQCPkd/fG0Keo37YP6TEIcE/WZ9kF9JiGOifpM+6A+kxDH1NI+s9sEwLsSxhi0BpPDPUAihBDiuDR6I/3dIoSQVmCMIbOkGmnFlXCVCOHpIobCWQS5kxCMMfxxPh/fn86BiTEcSysBj8fBXSoCAJRV6VChNViUF+DuhMFB7jiWVoLCCm299xMJeNAZTFbrEpdWYv63t0wMd6kIOoMJRZVaVGgMVs8ZGOiGOwb5oUZvgpBfW7epkb70t4EQ0qmZTAw8HgUhCCGkJQxGEyo0BjiLBRAJaD1rQrozxhgN7CCdDgXAO5n4rDI8v/MMCtVazBkZgkdGhsLdWdTR1SKEEOLANh28jFnRQZA7CVt0/pFLhXhk+0koXcR4dHQYHhkV2sY1JISQrokxhvIaPVTVehhMDMWVWiTmqpGv1kBnMMFXLoHMSYjzOeUoUGtRWKHBxfwKc2Ca44CoIHconEXIUdWA41B7npsTdAYT9EYTSip10BnrB7Kzy2qQXVbTYN0aCn7fqECtRYG6fgD9RjllNfjtXD6CPaTo4ytDhI8rRHx6EEoI6bz+70gaOI7DPLp2JYSQRplMDH9eyEdinhpl1TocuVQMrd4EVY0OGr0JMokAt/T1wR2D/SF3EiLc24UGQRLioPRGE4RW7vMo+E06IwqAdyIllVo8/Olx86yKDftT8enf6XgoJgTzR4fCw0XcwTUkbUGt0aO4QgtVjR4llTqczCzF7ZF+6O8v7+iqEUK6IZOJ4YO/UvD96WxMG+iHmB4eGBaisHpshUaPVb9fxJwRIejl7Yr8cg1+OZOL9/cmY3CQG46nl+G9PcmI8HHFyJ6e7dwSQqwzGo149dVX8fnnnyM/Px9+fn6YM2cOXn75ZfMNGmMMK1euxMcffwyVSoWRI0di06ZNCA8P7+Dak67EZGLguGs3/qmFFTiUUgw+BxxNK0VplQ4agxHqGj2qdUbU6Iz1Zm3fiDHgZGZZs+ohFvAg4HGo0hlb3Jbr8ThA6SqGh7MYoUpnSAR8VOsMCFJIcVOYB0I8neHnJoFYQA85u7qMjAy88cYb2L9/v7m/fPDBB/HSSy9BJLo2KPvs2bNYtGgRTpw4AaVSiaeeegovvPBCB9ackOY7lVmKXfE5SMpT4+4hAZBLWzYQlBBCHF1WSTWW/XAW/14ugYjPITLADZkl1RbHqDUGfH86G9+fzgYAOAn5eG5SL8wbFUpBMUIIIR2mUwbAV69ejeXLl2Px4sVYt26dxT7GGG699Vb88ccf2LVrF2bMmNEhdbSHC7nqeikFq3RGbD50GTv+zcAD0UGYPyYM3jJJB9WQtBRjDMfSS7H9nwzsScyHiVnu33IoDYOD3NDXV4ZQT2dE+LhigL8ccichXSgSQuyquFILncGE1MJKrN2bAt5fwCezh2F8b696x353KhtfHsvCl8ey4CTko0Z/LbhSWqUHAFTrjHj40+NYMbUPZo8IoT6MdLg1a9Zg06ZN2LFjB/r164eTJ09i7ty5kMvlePrppwEA77zzDj788EPs2LEDoaGhWLFiBWJjY5GYmAiJhK67iHWZJVU4n6OGwWTCj/E5qNQacCa7HN4yMQb4y2szYoys7QdnjwjBz2dy8XNCrnnmtcxJiAA+DyI+B5mTEEODFSir1iE+qwwFai0YGIwmoLRKW+/a8Xqjwz0RHarAhVw1Sip1uFJWjQK1pk3a6OkigqtECHWNHjqjCRyA/v61s7v7+srgJqVMVY7k4sWLMJlM2LJlC3r27Inz589j/vz5qKqqwnvvvQcAUKvVmDRpEiZOnIjNmzfj3LlzeOSRR+Dm5oYFCxZ0cAsIsd3mQ2m4kKsGAFzILccIGrxJCCFWyZ2EeG1aP9y24W+EejqjUmtAf38ZSit1yC23fs1Zozdi1e8XIXMS4p6hge1cY0KIPVmb/U1IZ9XpAuAnTpzAli1bEBkZaXX/unXrHPZhut5K6sI6NXoj/u/vdHzyTzr6+8kRqHDC6HAl7hsW6LCfR1elN5pwPqccSXkVOHKpCDqDCckFFY2moASA+CwV4rNUFtv+N284Rocr7VhbQkh3p70hBa6JAU9+eRqfPxqNwUHu5u0nMkrx1u4k8+vrg98AkFpYiQH+MpzLUcNoYnj1l0T8fj4fs6KD0NunNlhCSEf4999/MX36dEydOhUAEBISgq+++grHjx8HUDtIbd26dXj55Zcxffp0AMBnn30Gb29v/Pjjj7jvvvs6rO6kc1Jr9Fi39xKySqsgEvCQmKtGbrnGHNi+UlqDK6W16cB7erlg6gBfRAW7I8Bdimdv6QWjieFSQQUKKjQQ8fmIDJCjUmvAX0kFyFVpwOdx8Hd3grtUiKEhCvjKJchR1SC1oBJiIR9CPgcnER8SAR8CHofyGj0u5leg6GqGIQBwEQugbmCt7sa4S4Uoq9aDxwEje3pifIQXBge5oY+vjNJYdgOTJ0/G5MmTza/DwsKQnJyMTZs2mQPgX3zxBXQ6HT799FOIRCL069cPCQkJWLt2LQXASZfS10+GjOIquEgE+PJ4FgYFuUEq6nSPyAghpMPJpUIIBRyUrmJczK8wb5c5CcDj0OBATaOJ4Y1fEjF1gC+cxdS/EkIIaX+d6q9PZWUlHnjgAXz88cd488036+1PSEjA+++/j5MnT8LX17cDamgfpVU6HEwutCm9IWPAuZxynMspx2/n8jGxjzeUrpQavb0YTQwZJVXIL9fU/qe+9v+Cq/8urmx8lk5zLP/hHOaMCMG0QX7wcqUZaISQtmftb0iVzoh7tx7F0zf3xN1RgchRVWPh56dhaKJzuzH97bH0UiTmqvHTkyPbtM6ENMeIESOwdetWpKSkoFevXjhz5gz+/vtvrF27FgCQnp6O/Px8TJw40XyOXC5HdHQ04uLirAbAtVottNprayKr1Wr7N4S0m/isMiTmqSEV8TG5ny+cRNf6trzyGnxz4go0BiMK1FpIRXxUaAwNrqedWliJ9fsumV8HKaS4faAvfozPhVjIw7t3R2JggBve25OCSwWVcBLx4S4VgQEQCXgortAi0F0Ko5EhW1WD+Kwy6I1tdKF5ldJVDGcRHwpnEe4bHoRJfb3B53FwlVA6YAKUl5dDobi2NEpcXBzGjBljkRI9NjYWa9asQVlZGdzd3euVQX0m6YyC3KW4VFgJAEi4osJjY3pgQAAtS0YIITc6cqkIS749g6IKrcV2dY0Bfm4S5KosZ4GHKZ3B4zikFlaiQmvAO39cxGvT+7dnlQkhdlKjM1rcHxPS2XWqAPiiRYswdepUTJw4sV4AvLq6GrNmzcLGjRvh4+PTZFmd/SabMQZVtR6FFVqs+Ok8jqeXNut8H5kE9wwLpOC3nZlMDJml1UjMVePv1CLsTSxAtc6IYA8pkvIqmi6glbLLavDm7iRs2J+Kbx67CQHuUpgYA2O13yETq30Qeza7HNGhCoQpXexeJ0KIY5EI+XCVCOotwaEzmPDenhS8tyfF5rJOZpYhKtgNpzJV5m3v3B1JfRPpUMuWLYNarUbv3r3B5/NhNBrx1ltv4YEHHgAA5OfnAwC8vb0tzvP29jbvu9GqVavw2muv2bfipMMEezhD7iTEP6nFqNDqLW7wlS5i9PaRoUBdBKOJoUCtaTD4bU1WaTU2Hrhsfj3r42N4c0Z/eLqIMCjQDRUaPS4WVOLMFdV1Z6UDAAYGuuHhmBCkFFQgr1yD8hp9vQeR15OK+Ki+bh1wIZ9DmKcLhAIOQ4LcEerpjPxyDcRCPoIVUkwf5AcBpbMj10lNTcWGDRvMs7+B2j4zNDTU4ri6/jM/P99qAJz6TNIZ+bk5mf8tkwjhRmuAE0JIPfnlGjz5ZTzKr2YZupHewDAsxB0cOGj0RlTrDUgvqgKPx2FosDtOZpbhu1PZ+M/k3nChWeCEdHkSYde8X6zWGbD7bB72JBbgtkhf3B7pBx6Psip3B53mL8/XX3+N06dP48SJE1b3P/vssxgxYoQ5NWVTOvNNts5gwrT//m2RNsYWoZ7OeOX2vhjgL4enCwW+7clkYth06DI++TsdpVW6evuT8irgIxMjX93wQ8e2VF6jx+R1Rxo95uYIL6y9d6DFWoyFag2OZ5SCz3GYMsBxsiYQQtpOtc4Ard724E1T+Ny1i+HhoQrqe0iH+/bbb/HFF1/gyy+/NKfqfeaZZ+Dn54fZs2e3qMzly5djyZIl5tdqtRqBgbS2XWeVX67Bh/svQWcwoaxKB53RBIWzCMNCFLh3WCCyy2qgdBWbH8opnEVQOIusDt4R8HmY3N8Ho8M9cTqrDBUaA4IUUiTnVyBfrYGLWIDEXDX+TSuGqkqPCm3Dach5XO0yFP/57ixkEgHCvV0R6umM/94/GJcKK7D+r0u4XFSFyqtlnLmiuiEwbslVLIC7swhagxEiAQ8uYiHGRSjhfDWAL3MS4t5hgfWydRDHt2zZMqxZs6bRY5KSktC7d2/z65ycHEyePBkzZ87E/PnzW/X+1GeSzqi4sn3u5QkhpKvSGUx46qvTDQa/AaCoUosiK/2p0chgYrVZi6p0Riz47CR2PDKc1g4mpIvrikvxxl0uwVfHs/DzmVwAwN7EAvB5HG6L9OvgmpH20CkC4FeuXMHixYuxd+9eSCT10zz//PPP2L9/P+Lj420uszPfZKtqdM0OfgPAgjFhGB/hZYcakesxxrD4mwT8crVTbEgPLxe4O4uQV66Bqrrhi8H2EKyQYn9yIR785Bheua0f0ooqcfhSEfZcKDCnLP6/h4diYl/vJkoihHQ3/6aWQGdsuwB4rqrG/O+HY4LbrFxCWuo///kPli1bZk5lPmDAAGRmZmLVqlWYPXu2ObNQQUGBxRI7BQUFGDRokNUyxWIxxGIajNjeDEYTKjQGXMyvwKXCCugMJvTxdUVkgFuj6bp95BK8fccA7LlQuyb3F8ey8O3JK/jlTC7W77uEogoteBxw6wBfeDiLEO7titsj/SC/OhvwlzO5OHNFBbmTEIEKKaKC3RGokGJ0uNL8HtU6I85kq/D9pWJo9EZUaAwWwW8RnweDyQQTq52Z7efmhNsj/VCjN8BbJkF6USUqdUaUVunw9NfxcBELIOTzEBXsDgYgq6QKHMchv1yDGr3xxiYCACq0BoiFPOiNDIUVWjBWg6ySKvT3l0PuJMT43l4Q0UPHbum5557DnDlzGj0mLCzM/O/c3FyMHz/evITE9Xx8fFBQUGCxre51Q5naqM8kndH1MxHLa/TYf7EQs0eEdFyFCCGkkzlyqQgnMppertOaXt4uSCuuMr/+93IJkvMr0N+flpoghLSvH+NzzMFvAHCXCmm5r26kUwTAT506hcLCQgwZMsS8zWg04vDhw/jvf/+LhQsX4vLly3Bzc7M476677sLo0aNx8ODBemV25pvsIynFzT6HxwGTKHhpd0UVWnzwV0qTwe8hQW44lVkGjd4EZxEfw0MUuFJWDaWrGGezy9ulrhIBD75uTsgsqTLPUj+fo8Y9W+KsHr8jLoMC4ISQeg6mFLZpeX5uTshW1cDTRYxJfZtesoQQe6uurgaPZxn04/P5MJlqB36EhobCx8cH+/btMwe81Wo1jh07hoULF7Z3dclV7OqMEY7jcKmgAol5amj1Jlwpq4aLWAATA8qqtDAYTSiv1uPWJkZvM8ZQXqPHZ3GZkEkEeGJcD1RrjSir0YHPcchXa5CUp8blotoHdUUVWsyKDoK3TAIPFxFyy2tw+FIRUgoqwXGAi0gAb7kEG+4fjD6+MgwPVWB4qAJGE8P+i4X493IxMoqrUFatB8cBY3sp4SoRIldVA8aAxRPD4Szi441fE7H93wwEKaTIL9dAazBhSn8f/JSQi3y1ptE2WVNcaZm5SCLkI9zbBUtuiYDCWdTAWcTRKZVKKJXKpg9E7czv8ePHIyoqCtu2bavXf8bExOCll16CXq+HUFj74Gjv3r2IiIiwmv6ckM4q3MsFw0Nr17cvqdTitV8uYObQAEhFneIxGSGEtButwWiRIahArcEvZ3LxT2rzn1/XKarQ1psstPtcHgXACSHtorxGj1/P5mL32Tz8e7kEfB6HAf5yxPTwwMyoAFqqsRvpFFf2EyZMwLlz5yy2zZ07F71798bSpUvh6emJxx57zGL/gAED8MEHH+D2229vz6q2iUMpRc0+p6eXCzxsTHteXq1HekkV8ss1UNfoIRbyIBHy4STkQyrio7+/HBIhpT68nlqjx8eH0/DJ3+kWayVaEx2qwLHr1myv0hlxPKP2dV65BsNC3Fs8QrI5IgPccDyjFC5iQaPpNescuVSMK6XVCFRI7V43QkjXkZJf2ablMdQGre4dFgCRgGYako53++2346233kJQUBD69euH+Ph4rF27Fo888giA2gDrM888gzfffBPh4eEIDQ3FihUr4OfnhxkzZnRs5bsptUaPTQcvQ6M34oHoYFzIVePL41nIVdWgtEqHap0RMokAPb1csHhCOEb29GywLI3eiH8vFyMqSIGZQwMx84b9p7PKEJ+lQkwPTwwNccf+pEKkFFTAaGJIzFPDWybBiB6eGBLkjpMZZYhLK4aLWID8cg1cJUIkZKmQmKsGn8dBLODh5j5euKWvN265OuiwSmtApdYAhbPIIuUjYww7/s2AzmjCiB6eCPWU4tYBvlBV63Hnpn/N64pzHDA40A1l1XqkXzeLpiFPTwhHdKgCOoMJLhIB3JyECPV0prW9iU1ycnIwbtw4BAcH47333kNR0bX71rrZ3bNmzcJrr72GefPmYenSpTh//jzWr1+PDz74oKOqTUiLJOVX4Ph19/UAcCqzzCK7ByGEODpVtQ6T1x1BkEJ69XkxD5/+kw5NK5ZJE/I4VFl5tvp/R9KgrtHDRSKAl6sEdw3xh5OIT8vzEELa1PH0Ujy/8wyySqsB1N5T//jESAwIoAE43VGnCIC7urqif//+FtucnZ3h4eFh3m4tnVpQUBBCQ0PbpY5tRWswIi6tpNnnXS6qwh/n8zCprw94PA46gwlqjR7qGj3Ka/RQ1egRn1mGsznlTaazdZMKcdeQANw/PAg9vWpHu5RV6ZBdVoNQpbNFKrDuoEprwLQNfyOjpLrJYwcGyHEio7TRYxKuqNDPTwYXsQCVWgMyi6tQqTPCRcRHtd6IqxnJW8RHJkaFxoAavRGGqzPXKm0IftfZcvgyXpvWH3xe11uvgxBiHw2l0m0JJyEfFZraPolmf5POYsOGDVixYgWeeOIJFBYWws/PD4899hheeeUV8zEvvPACqqqqsGDBAqhUKowaNQp//PGH1aV5SMsZTQynMsuQmFuO8hoDjCYTPF3FuJCjxj+XizGprw9mRddeny6dfG0tYjepEBIhDxdy1eA4Dr5yCaQiPvzdnBAV7N7oOmQSIR+MAQ99egwxYR549pZeFgNBhwS5Y0jQtVmr9wyzvmSSRMjHqHBPjAr3RLXOgLPZ5bXrGjLAyBh0BhOCPaT1HuAduVSMXfHZKK7U4blJvTCiR22wnuM4jOzpiRxVDX47l4+vjtfgvT9TMDrcE9GhCihdxSir0qFSa0B8lgoGEwPHAZH+cvRQuiC1qBJyJyG0ehM8XUXwcpXAWybB3VEBULp2zixYpPPbu3cvUlNTkZqaioCAAIt9dVkZ5HI59uzZg0WLFiEqKgqenp545ZVXsGDBgo6oMiEtdrmo/iDQXadzKABOiANKKajAyYwyqDV6PBAdRKlvr/P6L4nIV2uQr9aYJ/e0Bp8DBge71xtgBAB6I8MXx7LMr9/4NRGBCidsuH8IBgW6tfq9CSHdS6XWgK+PZ2FoiAJermLoDCb8dj4P7/6ZDHZd/GXGIH8Kfndj3SvS2QnsTSxAUYW22ecZTQyPf34aTlcf2NUFLIaHKqxeVDRGVa3HJ3+n45O/0xHu5YLSKh1KrqbQdhbxceeQAMT08EAfXxmCFVLwHDhYqqrW4ZHtJ2wKft8487sheiPDhVy1+XW4lwvcnYXIKq1BHz9Zi2eH170/jwPkTkKczlI1u4zPj2bheHoppg/yx9QBvgjxdG5RXQghrfdvajEOphShvLp2BPRdQwLQ10/W7vVoqwD4sBB3JOaqcTG/AuFeLpTajHQarq6uWLduHdatW9fgMRzH4fXXX8frr7/efhXrJgxGE5ILKvBTQi5+OJ2D4sra62BPFxE8XcS4mF9hPjZQ4WQenHk+pxxZpdWQOwkxsqcnJvf3xeT+vlbfI7usGmezy9HfT44gj/qZbib08caEPt5gjIGx2kCetaB5rqoGRhNDgLuTeb9Gb7QImMddLsF/D1xCTlkNpCIBvGViBLhLIRXzUVqlQ5DCGSIBD4wxVOuMmNjHCyN6emBfUgHcpEJsPJCK4+mliM8qg1pjOYhRZzRh38WGl6XgAJzJLseZG5bb8ZFJcM/QAKQWViKjpIoC4KTF5syZ0+Ra4QAQGRmJI0eO2L9ChNhRdln9ZwCJeWqcziqDm5OQUmMS4iAYY9h4IBU/JeSCz+MQ4O6E25pYOqe7OJRShB/ic9q0zCENBL8bcqW0Bndt+hfDQtzx9YKYNq0LIcTxlFbqYDCZ4CWTID6rDG/uTgJQO2nxxvtkkYCHJ8b1wD1DrQ9yJ91Dpw2AW1vX+3qMtWIabQcaGOAGV4nAPEOuueoCFf5utbM8clU1rapPWlElrp8rXqUz4n9HM/G/o5kAamfzRfi4oo+vK/r4ytDHV4YIH1fImhgtmVlShbV7U7A/qRB8Poehwe4Y1dMTo3spEebp3OhMnfZQl3byvwcumx/ENqWkSochQW4oqtTiSqntn/ulwmsjy/PLNRgeorB5VOWwEHeU1+ghFvDMI5dMDCi7YR2d5kgpqMS7fybj3T+T0cdXhqkDfDBlgC960A0+Ie0mragSs7cdh9547W/ZJ3+n46YwBe6OCkRkgBwB7k7tsgZhTRPLPtji+n4txEOK7Y8Mp0wThHRTjDHEXS7B6awylFXr8fOZXPPgTxexAO7S2pTcmx+Mws9naoPi9w4LRHSYAn5yJ/zvaCYu5qmhqtZjRE8PxIR5IKukGp6uonp9YnGlFh8fTsPHR9JgYsDUAb54fXq/BpcN0hpMWPr9WYj4PPRQOqOfvxzDQhQ4mFyEM9kqjOjhgaQ8Nb45cQUGE0NfXxl+P5+P3j6umD0iBPcPD0JMDw/085fhh1PZ2JtUgFyVBsWVOugMJuSpNDh8qRjH00ugqtbDYGII93JBuJcLvGUSlFbqwMAwLkKJ8RFKZJfVwFsmQWGFBlHBCpzOKkNqYSVqdEbInAS4Z2ggUq9eRwr5PAwPVSBXVQOd0YQP9qagsEILpasYYZ4ucJUIcVeUB82eIYQQG5zNVuGn+Nx62y/mV+DOj/7FwnE9LDKREEK6ngK1Bs9+k4DLRZUoUNdeixpNDE9+GY8fTudg/X2DuvVM8CqtAev/Smmz8vr7y1CjM7YodbrRxHA0rRSHUoowtlf9LByMMexLKsShlCJEBsgxk4JZhHRL8VllmLfjJPzdnPDsLeH443y+eZ9IwIO/mxMKKzTmZ62LJ4Rj0fieHVVd0kl02gC4owpUSPHKbX3xn+/OtqociZAPHschu6x1AXAvmQR55ZoG99fojUi4okLCFZXF9gB3J/T2kcFNKoRGX3uBozUYYTCaoNYYkJxfAcN1ub7/SirEX0m1M1r85BKMCvfETWEeCFRIwaE2ZUWV1ohKrR6VWiNqdAaEerogpocHFM6iVrXRmvf3pOC/B1KbdU7dA0geB/i5SZCravhza8zprDIMC3FHZkk1ChvIBuAi5iNQIbX7WuJJeWok5anx3p4UBHtIEeLhjAB3JwS4S6/+3wleMgn0BhOqdUbU6A3wdBEj2INmjhPSGmezyy2C33WOppXiaFptIJnjgGHBCrw2vR/6+NpnZjhjDGIhDwMD5BALeDibXQ6NwfYbViGfQ38/ucWgnrfuGAB/NycAtYOhGANlmyCkGzGx2kCzXFqblnt2TDCGBrtjw4FUDAxww2NjwnA+V43Pj2WhWmvA549GQ8jnsHZvCvZcKAAAVOkMUFXrsftcHl7adR4AIOBxGB3uiYdHhCA6VAGpSABPFzEWjuuB3HINfj2bi30XC2BiDGN7KRGkkOLXc3koq9IhKtgdj44Og0TIx6OjwrAnMR+ZpdXY9m8GZgzyh7dMguPppfjk73T08q7NYLE3sQC/l9TeUF/Mr0Dc5RLcPzwIACCTCDFnZCjmjAzFpYIK5KhqMC7Cq7b9JoZfzuZize8XkVuuQWGFFnweh0qtAWFKF8T290GAe/1Z6gAwub/l0hF55TUIUkjh7ixCUYUWVVoDgj2c4SOTYFJfH4gEPBiMJvyYkIueXi4U/CaEEBsFK5whFPCABsbC39pAxhFCSNex/2Ih/r1sfQnK/RcLMfytfejnJ0NUsDsm9vXGsBBFO9ewYxVWaFFUqcUdg2vX4T6brYJMIsTiCeHQGkxYuzel3rNga5xFfPTxleF0VlmrlnwEajMtDQp0g6tYgCqdASkFFXhzdxLir8uAOTXSlwLgXdjhw4fx7rvv4tSpU8jLy8OuXbswY8YM837GGFauXImPP/4YKpUKI0eOxKZNmxAeHt5xlSYdzmhi+PJYJlb8dAEAEKZ0xsYDl5GUdy0Db5XWiBxVDQYHuSEpVw1fNyc8Ma5HR1WZdCIUAO8AvnKnVpdxuagKQBVCPaVIL246fXdDlC7iRgPgDckuq7EafI/wdkFyQf21tK6XW67Btyez8e3JbJveq4+vDP39ZHCRCOAqFsBFIkCguxQxPTzgJm06OM4Yw+5zefgntRg6A8P5nHIkF1Q0eV5DpEJ+i4PfAGAwMZzIKIOvXILePq5wlQjAAci4LiDuK3dCUl7L69gSmSXVyLQhFfzzk3rhyZvpwoOQ1rClD2IMOJ5Rio8Pp2HtvYPsUo9zOeVIK6oyvx4U6GbTTa6XqxhBCmnt2rQ3HJ9aWIkKjR4/nM5BamElvls4oo1rTQjpzPg8DuN7e9XbftPVta/r0nT395Ph5t5e+Du1GJ8fzURplQ5eMjEqNAaUVNUGjYMUUugMJuSoamAwMRxILsKB5CKEKZ0x4OoyC35yJyikQozo4YF/Ukvw+/l8/H7dSHAA8HCpvV4sUGuQUlCB2yL9EOHjCrVGjz/O58NFLMCSW3pByOchpaAC+y8WQiriQ2cwmQd0ypwEKFRrrvZ5DBfzKnAuR418dQ08XcQoUGtw15AACPg8xIR5QCquvc0qrdKhtEqHC6hdD3x0uCf4PA5iAR8CPgeDkUHhLEKEjyvKa/SIz1IhR1WD4kptg8smSYS1o9u9ZRKMj/DCPcMCIXfqvjOYCCGkuQwmE0qvLgN3PT+5BLOig9Dfv/2XJSKEtK2QJiZu1OiNOJlZhpOZZdhyOA1bH4rCpH4+jZ7jSEI9nXH4P+PNGTpNJgYGmDO5jemlxNfHs7Dip/NWB+8DtVkrz+WU42Rm20ze2XzoMjYfugweB6vB9ECFEyb2qX+fQbqOqqoqDBw4EI888gjuvPPOevvfeecdfPjhh9ixYwdCQ0OxYsUKxMbGIjExERKJpANqTDqDX8/m4v29KfB0EaFSY0BuWQ1yb4hnSYQ8AEBaURUEPA5vTO/X4RmISedAAfAOMLKnB2ZFB+Gr41loaSb3EA8pvFzFOJejbvrgRpjaMJW8t6vYvJZ4W6qbpXw9IZ/D8JDaFJSPj+1hniWuNRhxMa8CBpMJWoMJx9JK8VdSgcWa3C0l4AE8joO7iwiVzUiB3pC8cg00eiMu5temM3eVCDA4yA1VWgOMJgZfeeOz8zuKSMDr6CoQ0uWl5Ns+wGV/ciHO55TbZU3tTQcvW7xOuKLC0GD3Bm9gFc4i9FS6IOFKWYMZLFb+XDsi008uwbePx9gliwchpOvq6eViXucbAPr6yrB4Qi/oTSb8c6kYLhIB1DUGeLqKcO/QQGz/NwOZJdXQGoxQXV0Cpqxah5/P5MJFJMBNPTxQqTFgeKgCAW5SiAQ86I0mlNfoEeLpjAhvV/PM6vTiKhRXapFdVm1e0ufG9cACFU7IL9egj68rJAI+9EYTPFzEuLm3F7xkEoztpcQHf6Xgt3N5yC+/ll7tYHIRKrVGzBsVCk8XMYaHKszZg+rUFpEOPgABAABJREFUBfEFPA48joPO2HTGDYmQB7GAj/Kaa8vfaPQmXC6qzbCRr9agRmekADghhDRDXTrk6z0cE4yVt/ejZXwI6WK2Hr6MSwWVGN1LCRGfQ4inMyo0BnxxLLNZ5bz9WxJ6ebt2q+xl1weHeFb6vvuGByHCxxX3bImzGgQvq9bBy1WCK2XVLX6+bU1DM8kXjOmBOwYHtN0bkXY3ZcoUTJkyxeo+xhjWrVuHl19+GdOnTwcAfPbZZ/D29saPP/6I++67rz2rSjqRwylFUFXrIRZwuCnME4dSisz7XMUCeMnEOH01U0R5jR5SER8je3p2UG1JZ0MB8A7AcRzevmMAHhkZiinrDzc4kq4hPjIxyqr1yLBhtm5jIrxdcL6VgeEeSmd4OIuhMRiRmKu2SHtuT/395fjncjH+uVyM7f9mYFCAG8RCHhKyVOA4QKM3QtfMz7UhA/zl4LjalMUSIdes9b8b4yoRwMtVYl7Pu0JjMKf1EfA4DAl2R4Fa0+oUQm1NxKcAOCGt1ZzBR6pqPd74NRHfPBbTpnX49WxuvVmSAJBSUIFe3i5IuS6bh5DPoY+vDGezy3G8qrTeOTeSOwnxxfybGkzzSwhxLLmqGpRV61Beo0eNzogavREllbWva4PB7gjxcIbAyjWEl0wCL1ntaP4hQe4W+749cQVH00pRVKEBA+AuFcFXLkF0mAeemxSB4SEKqw/rGnJTmAduCvNo9BhfuROej42ot71ArYGqWgc3qQjLp/TBgtFhUNXoUakxoKhCCz6fQ7+ry1XweBxen9YP9w4NhLOYj7xyDdKLq6Cq1iMyQI4hwe7YeigN2WXVEPB5MJkYvGQSaPRGyJyEEPA4lFbpIBXx4SOXICbMA7vic1Beo4dGb0KopxQSIR8B7tJ6adMJIYQ0LchDCgGPs3h+EezhTMFvQrqYSq0BHx28DFW1HjtP1WaZ5Di0KBibUVKNN3cn4v9mD2vjWnYd/14uRmphJc5cKUelVo++vnLInARwFgvMA1Gvl1pYhRAPKYaFKHAio7RNg+A3chULMHUALU/hyNLT05Gfn4+JEyeat8nlckRHRyMuLq7BALhWq4VWe21gm1rd+klwpPOo0hogEfIBAFoDg7rGsi/q7etabwnZMKUzzf4mZhQA70A9vVwQ5unS7HTcQR7OOJ7edACiMRIBD1JR6378UcHuOJutupqOvf309nGxmNGtM5gs1p8FgEB3J1xp5froQG3QJ6WgAtqra+Jq9LavjWuNk5CPfn4ypBVXQe4kbPBnbzAxHE8vxbAQdxSqNVA4iyEU8JBaWGk1VVt7oj8ghLTO/osFVmedNGbBmLBWvadGb0S1zgiFswiMMfx8Jhf/2XnW6rFqjQEMGni7ilFwdZb3wAC3ZqU1u3dYIEK70ch5Qrq7ExmleOG7s+brJWtEfB7ClM7wlUvgLhXhWHopDCYTvGUSDAtRYGqkLwYHullcZ9wzLBD3DGvfNf4YY8gsqYaXqxiJeWpcKqyERm9EZIDcIhOHh4sYblIRtv2TjsySaugMJnx5LAvOIj7CvV3RQ+mM8ho9xAI+/N2dMGt4kMUAgBuD7HqjCRxgdZAAALwwubdd2ksIId1RRnEVOA4Q8jiIBTz09ZNjSJBbR1eLENJMO/7NqBeYbU0Q1sNZ3MoadT355Rr857szKK3SISlPbTEJ588LBU2e7yoRAoxhWLACp7LKYLTTLJ5b+npTdjkHl59fO0HD29vbYru3t7d5nzWrVq3Ca6+9Zte6kY7jLBbgTLbKPFHnxixqiblq9FA6W8SngptYAoN0LxQA72BKV3Hz16NmDFIRH9U6Y4vfVyLiw9iKq0IeB5RWaZs9e70tSIQC6Bp5wDo8xB3HM9pm/Rkhj0N1K4PedXp6uUBnqF1jqPbzazqQXTeCKUelQYiHFJH+cmSrauql1GxP3568gvuGB0Is4HdYHQjpyl7/JbHZGTyac6N349pdAPDJ3+l4b08y/OROqNEbm+x/KjQGeMskCPF0hsFoQnxW8/pUpUv3e3BASHc2tpcS9wwNxP+ONpxqUmc04WJ+BS7esAREgVqLs9nl+OTvdIR4SDFvVCgeiglpdZ10BhM+3HcJR9NKUKk1gM/jMC5Cif/EWg8kX8gtx//iMnE4pQgVGgO0RhN6KJ1RqTWguEIHE2OYOTQAb0zvD47jUF6jx5xtx1FQrqm3/tj1PF1EWDS+p8Xs9iqtAX9eyMeeCwVIKahAvlqDap0RAh6H2P4+mDcqFEEKKYoqtDiUUoTUwkpcKa2GwcTgIhZg9ohgpBRU4rdzefCRSaB0FYMB0BtMcJUI0dPLBRP6eMFbRuvkEUKINedyVAjxcEauqgaVOiOOZ5TiaFopBt+QiYQQ0nlpDUZ83si1Z3NxHHD30O6VXrtaZ8CLu87hyKXiZp3Xz08GPsfBScRHSkGFObNlqKcz0ovbfpKUj0yCFbf1bfNyiWNYvnw5lixZYn6tVqsRGNi+g6iJ/VRpDajUGKBwrs0Gl15UCZGAZ44N6U0MzmLLECdliyDXowB4B7ulrzf+Tm3ehcaZbBXClC5Iymtm4Pw6qmo9NLoKRIcqcKwFs8lNDFA4i5Fe3Lo07C2RU1YDPo9rcFShiQEyp9r1I1vKTSqEt6sEHAd4y8RQ1egh4vNQpTUgsQWfu5DPoaxKZ14j3dYBkRwHDA12x4WccqQWVSH16mimqGA3nMpUXf23O9KLq9ptZviFXDUSc9X0cICQFmpOut46v57Nw+AgdxhNDIdTilBUqUWEjysivF0hEfJRVqXDycwyXMgtx1fHs9BT6YIgDynG9lKCx3HYFZ8DxoAcle2ZMVILK5Er4sNdKkRzxjoFKaS4bzjdbBDSXVRo9Lj/42NIymt+qjkXsQBRwW4IVjjDRSKARm9EXFoJdsRl4kppNR6OCcZLU/viSmk1tAYTAtydzOnPdAYTLuar4eEihr+bk7nMx/53EpcKKxGskELA52FQkBsu5KiRUVKFPldTlF/v70vFMDKG0T098cS4npjUzxsb9qciPktlvtYeHe6Jm3t74Za+3tgVn4M7hwTAWcQ3L13TkKkDfPH2HQMgl15bn3vPhXy8+vOFekHzQYFuWH/fIPA4Dst+OIujaaUNXuueyCjFlP4+eHJ8Tzz5VbzVgaGin3m4baAvXrmtL9ykNFuGEEfGGHPoLF3s6sD9tmxjtc6ESzcMKu/nV/9vBCGkc2GMIau0GjV6I3zlThgWosDPZ3LbpGwBj4NMInToPpUxhs/iMlGlq13C54/z+chrZCBnQy7kqjHcyvPkgvIaDA1xB1jtTPxyjR6ZJVUQ8Hio0ds+iUvpKobBaEJZtR58HoevF9wEd5r97fB8fGqXdiooKICv77UAZkFBAQYNGtTgeWKxGGIxTcJwRBdyy6Gq1sHEgNNZKriK+fBzc4KAzzMPrB8U6GaRKfmuIQGYQsuEketQALyD3RUVgDV/XGx0NncPpTM8XMSo1hpQqTXgSllNi4LfLmI++vrKUK0zgs+vXcu6JcHvOglZZRgYIEdSfkWjM7LbklTIg4eLCEWVDacPPplZBj83CSK8668BYYvhoQqcyy43z8y/caZSL28XqKr1KKywLYVxpL8cQgFnDlg3V1m1vt5s/azSGkSHKlBeo8fprDIEuDvBWdQ2ad+bEuwhxYDrUoASQprnlydH4WJ+Bbb9k45fz+bZdM5PCTnQG03Yf7EQ2Vd/zyP95cgoqcLk/j7Ym1hgHnUNAJ4uYvxz/Aq+On6lVXWt1hnRz0+GHJXtN8Uv3tq7Ng0aIcThafRGLPn2TLOC3/5uTnh8bBjkTkL8e7kEexMLcCil/mBQiZAHjd6EVb8nYcuhNPP2YA8pXr29H3p6ueCzuEykFlZAZ2C4c4g/HooJxqhwJf68UIC061KgCXgcvls4AoMC3Szeo0ZnxK74HOy7WAClixiDAt2QXFCBs9nlFscduVSMI5eKsSs+B8NCFBgXoYO7VIg7B/vjh/gcAECYpzMWTwyHm1SEkkqtee3u6x+gxl0uwYu7zqPYynXs0xN6ItjDGYu+PI1/UkvgLhVCVaO3msazWlebUWjuyFDse3Yskgsq4OEiQo3OiP3JhchV1cBkql0r8VByEZSy2ra1dvkjQkjn5KiBmjr2aN9pK9mNdsXnYEwvZZu/FyGkdRhj2HwoDXsT83GlrAZFFVrwuNq+wUnYdpkJ9UaG2HWHEeIhRYinM9ychJA5CcHjOAS4O2H6IH8oXbtGkG332Tz8cDobUSHuuG2AH3zdJEgvrsK7fyZjb2LTac1tobfyHLhab8LJG57DSgQ8mJgJfX1lSGzinkEi5OH2SD88PSEcAe5OSCuuQlZpNUJoebVuITQ0FD4+Pti3b5854K1Wq3Hs2DEsXLiwYytH2t33p7Lx3M4zEPCAIUEKZJVWo0JrRB8XMU5mlGJ4qAK5qhrEZ5VBIRWhtLr2Hv2BmwLx/ekc3B3VvTJ6kIbRU5AO5iIWYNWdA7D+r0tIayBNjIDHa/Wa325SIaQifpulBgcAIwPOZJdDyOfgKhGgQtPyGde2kDsJIHcS1QtIW5Or0sBX7tTkcTcS8jnzaNKGpBRUYniIu00B8F7eLjibU97kcQ1hrHZNyBsVVWhRdN37XymtgUjAQz8/GYR8HhKuqFr8nk156dY+Da5PSQhpmrNYgKhgd/jIJTYHwIsrdfgszjK9W255DdQaA749mW2x3VUigKAFs8yt8XAW4XxOOTycRVBr9DYte2Gw05pfhJDOJUdVg4f+71iD1683ignzwB2D/TGhjxeKK3V4989k/JXU8AM4jd5kNaW6Vm/Cf747i9IqLUysdsR3Yl45EnerUVypwwuxEfgxPgenMq9d8xpMDMt/OIfvF8ZYBIGdRHy8f89AqDV6nMooQ3ZZNcqqG86ocza7HBIhH25OQnAch+djI3A8oxQ8jkN0mAK39PVuMMhsMjG8vyfZavAbAP7vSDqGh3pgVE9POIv4OJlRZjGw6XpiAQ93DQlA/P+zd9/xkZX14sc/50zvJZPeN9ndbG/ZXZbeZFFAUBQLKqBX1IsVC+C1XBRFrPxUrFcRK6ggFgTpILKwvffd9J5M7+38/phkNpNeN1l43q8XL8lk5syZYE6e83xbi5cfPXccm0HDNWtKeepgF52+KN5wnFB/cu0DW5rQqWWuWFHM1WtKqSuyiNbognAGCceTSGTazAozI55M88yQvz//dW41/31R7RydkSAIY5EkiY9cWMMjO1uz+2BpBVAUgrGZ34ds7AuPOLLsJy+c5MqVxfz3hTUUzOO1lC+S4PZH9hKIJnnmcDfffOIIsgT9P7IZMzByrdJpoMk9ejFOtD9QnkorrCm3s6vFS6nDQNsIBTyJlMKn3rCIkv7uTjX5ZmryzTN30sKcCwaDHD9+PPt1Q0MDu3fvxul0UlFRwSc/+UnuuusuFi5cSHV1NV/84hcpKSnhmmuumbuTFk67aCLFd586CkAyDVsb3SwqNNPYF+Zwp5/FRRa2Nrgxa1WsLrejliW2nHSzsNDCW3+0BYtOzc5mD19/y4o5/iTCfCAC4PPA1atLuWJFMd9/9jhHOv3868Cpm7GFhebJzwgfQZFVP6HA8VQkUgorSs3sHKcN5HT5IklK7QZWlNrYN4Gg8qEOP2sr7BM6L1mCRYUWEqk0J3rG38j1hBNsrHaSVhQ8oXi2NflQTX1hVBKTah88lM2gocU9fqv5eDLNgXY/kgSrymzsaZ1a4H1VuZ0SWyY7dPD/ZyrzjNz9lhWcXeua0nEFQchVajdw49lV/Orlxim9vjcYH/F6mGfSZlsET1e1KzP/tskdxqhVYzdoaBrnevTFR/ezqsxOudM4I+cgCML8VGLT88ynL+BwZ4BdzV5ePtE7alKPViXztbcsZ0H/BtYftjYjSZkuR4PXXVq1jEmrGjXwC9DpH70jxU9fPEGxTc/qcntOABwy68L3/N+r/PS99cOqd6x6DRfVFQDw3k1VHOkMcN9zx/nbnnYkCS5fVkQilSbfouONy4uRZYnj3UG++o+DdPmjrCl3YNKq8UUSowbA46k0x3uCI34PYMvJPu596ihOs5ZoIo03MvrPIJZM88Pnjmc7MHX4onz7X0eAkZOQtGqZx/d3ggQvW3ScvzCfxUUWtjW4cZq0FNn0lDuMUxrRIQjC7BKdG2be/nZfTgc7rVrmoxfXinERgjDPDe2MeLr1BmP86uVGfv9qM0uKLXz77atYWGiZ03MaiU4tU1tgzhnVMxs56vvafNQWmDneHcwGtsdypCtAoUWXrdocPNrSrFMTjCVJpRVeONrDuzZUzPwJC/PC9u3bueiii7JfD8zuvuGGG/jVr37F5z73OUKhEDfffDNer5dzzz2XJ554Ar1+/iadCDNrf5uPb/7r8LARjg6jlmPdQeLJNOFYAKdJgzuUYFujJzN6YZBALMm/9ndy19XLxT2ugKQoc7yCOE38fj82mw2fz4fVOr9nO/1mSyN7W320eyPsa/Phn4HK6oksRqaj2mWiYYIVQNO1otTKvraJt9qsdhnJM+k40OFnRamN3c0e4kMi0k6TlnA8STQx+VbuKllCUZRhC8r1VQ4OdQQotmf+SB/rGn3TczQrSm0c6vAx2Q7zKlliTYWdHY0eFKDErqfEZqDNG8mZ73PeQhcfPG8BxTY9sWQap0mbzbQE2NPi5d6nj+IOJ/j9f23EpJsfGzBn0u/zXHnzm9/M7t276e7uxuFwcOmll3LPPfdQUlIyodeLn/Hpsb/Nx5U/eGnKr6/OM9LkDo94QzuQ2GM1aEilFGLJFIFoctwA9mBqWUKSMolOFr2auiILkiTR4g6POSus0Krju9et5pxaFw9ubabZHebDF9ZgFa3R54T4fZ594mec8fTBLr75r8NUOI1sqnFxwSIXaQUqnMZhiTnheJI/bG2hJxDDE4rTF4rR6onQ2Bea1Hpsdbl9wp1vVLLEvz55PrUFE6sk2d7opqE3xAWL8nMqfb781/009IXZ2+rFOyhYL0lwy4W1fGbz4hGP1+oJ89TBLjp8UZIphd5gjBeP9eANJzBpVThMWrQqma9cvZzbHt477KZ/OtSyRJFNT3cgRjyZpsJppLn/70GxTc+lSwr52MW1uMw6sUmA+J2ebeLnK8yl7zx5hB88m6k+U8kS33/nGq5YWTzOq4SxiN/p2SV+vhl/3N7C5/68d65PI6vcaeCZWy9Eq55/HRJ3NHl4+09enpXA90jqiiyTLrraWO0kmkjhiyTwRhIsKswE7e99x2v/mix+p2eX+PmeWf6xt52L+5PRv/bYIR7Z2UaeWUsolsxJjN9Y7cwZ5WvSqrJdz1aU2jjY7sNm1OIOnero9sD7N3CBGG9zxpvu7/T8iGYJOd67qQrIZBd++o97eOFoz7SOZ9apxmznOBNaPRMPqExGiV1PTyCW03Z3X5ufqjzjiC2JRtLQG6ahN/PcrQ1uLHo1NQUGDBoVKlmiLxQn36yjqS9ERalx0m3iFUWh3GEknkrT7Y9SaNOTb9ZxtCtIMJakNxAjzzS1bHKDRjXp4DdkWgttb/TgMmspdxjZ3+6j3RvFqFWxtsJOOJ6iriiTsTpWO/NV5Xbuv2kDnlB83gS/hYm56KKL+PznP09xcTFtbW185jOf4W1vexsvv/zyXJ+aMMjSYivv2lDOX3e3E46PPnphJGV2A1aDhvVVuYvAAWmFYTeh9VWOSQXAByoJdWqJCqeRbf3XR0mCDdXOUcdzdPljfPOJw9xwdhW3P7IPgD9ub+Xzb6rjmtWlIrgiCGcYRVFQFMb93b10aSGXLi2c0DF7AjEae0O8dLyXSDyFRi0RiqUwadU4jTJWgwaXWYeCQpsnQvMoyT6TkUor3Hj/Vj67eTEXLi5AkhiWmHO8O0hNvglJkqivclJf5cz5fjqt0NAXZlezZ9j4H0WBv+5pY02FnYsWFwz7eZU5jOjUKn75UgMmnRqXWYterQISxFNpWvtbQb7nF69O+rNpVTLxEcbmDEimlezxgWzwu9plosUd5uUTvRzpDHD+Ihcdvij5Fh2ldgPrKh3Zyn1BEIQzXSKV5l8HOrNfX7go/zUfaBGE14rNS4v4ono/salsks2CFneEB7c1877+Pdz54IWjPdz33HG2N7pPW/AbwBOOc3ZNHoFockIdO4FhexhbGzxYdCoC0dG7IAmC8NrT2BviY7/fxY/fs448s45IIkWrJ0K1y5gTAD/ZE2J9f6X3wXY/es2pAPix7gApBWrzTWwdFAD/6O928usPbGBNRW6FuPD6IiJa85jLrOP+G9dz7zPH+P4zx6Z0DJUEC1zTm0M9mFmrQlZJLC7MVAFKgDsU51j35KubB9OqMhuECmSD3aV2A2a9mhKbge2D2lguKjSPOj9xIgLRJIc6coNC3nCCmnwTqbSSbaExUWmFbEBJr5HpCcRo956qjFyQbx7WhnOiDnX4sRs1OdVFk9EbjNMbPHXhD8dT7Gz2IknwvXesnvAsb8cUA/jC3PnUpz6V/ffKykpuv/12rrnmGhKJBBqNqMKdL2RZ4u63ruRTb1jEZd97cdzf9fVVDiRJwhuOc7QrSGt/daDTqME9gevEWFXbo6nNNxHpH7EwQFEyWeUuszbnGjOYVi3z2UEZ+r3BGLf+cQ9P7O/kZ++rn/R5CIJwevQGY1j1GnqCMUr7u8Lsa/Nx+8P7eMPSQm65qDan0kVRFPzRJDbD5P62VOaZ+Oo1y4HMWrLNE6EvFMMTjuOPJAnGkqhkCateg0YloVXL7G/z8cLRHo5OoavOgFZPhE88uBtJAqNGRX2Vk/MWujhvYT6lDgMFVh2SNHqgXwG6fNFhwe8BLe4In/nTHm48u5o3rSga1hrz3RsruLiugN0tXv5zvBeLQU2p3cDeVh8PbWtBLUsjtjEfIEuglnOD3TX5Jt65voLuQJSG3jDPHenOtpQcT0NvCJtBg8Oo5XCnn62NbgwaFZV5RrRqmVRaYUeTh9oCs9g4EAThjLe/zUdfMJ7tkCeC34JwZvBHE7z/gW3zJvg94Et/PYBGJXNOjQtfJI7VoKHQqp+xkWQTlUorPLKzldsf2TfhNeBMGNhHNWpVbDnRh0KmO1MolpzwPrEswdfesoKfvXiStRUO3iSuy4LwuvK+s6v4846X+OKj+7OtzOsrHTmxIICeYIyeYIzKPANatUzfoEB3vllHiydCdMjfiEAsyR+3t4j72Nc5EQCf52RZ4hOXLOSBlxvxjTELcDTrqkav0JuMqrxM68pj3UFScSVbBTgSWQKTTj3qxuCAuiIzqTSZ+Q39Qe9im55ShwFvOMHxQYulDdUOvKEEVoOGnc2eGc9kdIfiOS0y6qscbJ9kJTgwYsvOxBQX6IVWHWpZntH2lwPevKqEJcWiDczrhdvt5ne/+x1nn332qMHvWCxGLHYqscTvn/iYAWH6Cix6zq7J45/7Okd9zppy26jX3vI8I+7w+IlObZ4Iy0qsdHgjYwbMFxeasRm1KIrCzmbviDfRmYShkQPgG6ud7Gz2jPi654/28PE/7OJghz/bchcyHTq2Nbp5z1mVOaMYBEEYWTSRQtcfiJYkiVgyhU49/mabNxzPzjmNJlI09oXo9EV55lB3JnM6reAy67JzodOKwn3PHccTTnCww8+x7gDfetsqTDo1vcEY//OXfUhIfO8dqzFoVbx8ojc79sWsU7Oo0MKSYsuYSXdf/+chdjZ5SI8xmanAoqM7kPk7VZVnzD5+rGty7RYHmPvXqkatim2Nbl442sPSYit3vGnJsOc+sb+TZneIa9eWkWfW8Z3rVvGLf59kT6uvfwxFpkIeMuvgJcVWLllSQLXLRDSRGrYJWmTTc7mtiMuXFxGOJznRHeKqVSV8+aql7Gv1sb/NR7M7gkmnotRuwG7U0OwOE4qlqHaZMOvVFFh07G7x0u2PoVFL1Fc5qHAaiSbTXHA4n38f7eGVk30EY8lx182+SCJng0EtSxzuDGDRqfnD1mbUsoTVoOG/zlvAObWuKf28BUEQ5oM1FQ7yzFp2t3pZVGjm7Nq8uT4lQRAmYFezd8qFJbOpwKLjrn8cJBRPYdKqUKtkfJEElv61WoFFTySRoqkvRKFVT4ndgMOo5fxFLq5eXTrh90mk0nQHYrR7I3T5o0QTabRqmWg8xd42L0/s75pWoZBOLbOyzIaiQLp/DwAynd/MQ/Z311TY0apkDrT5aOoLDetaubvF2z86DcYbulpo1fGmFcW8a0MFmxbkUeUyTfkzCIJwZrLqNVy5soRdzR7WVNgBiCSGd8hcVGgmmVLo8kdxmbUkUwqBWObaVGI3IEvQ4g7jMGpyKsfXlIvg9+udCICfAVSyxB8/tIn3/2rbpIOhu5o9LC22YNZrON4dmFRl82B6jSqnlW6RVYdBq6apL5TdVFNJsKTESoc3ij+aYHmJlf3tw4NoTpOWMruBgx3+YRUuHb7oiBWKWxs8OI1ajk6z0nyiOqdQJTmaDn8UWWLCQXuDRkWRTUe+Wc/WxuknLwylVct86tJFM35cYf657bbb+OEPf0g4HOass87iH//4x6jPvfvuu7nzzjtP49kJQ33wvAV0+WMcbPfnLPbW9I8t2NUyeoBbO8FuDgAH2v1oVBL1lQ52NHkYemmazDzdYGx4otOGKseILdkHxJNp/ranHci0Gv7Ziyey18crVxZTbNOP+lpBEE756O938ezhLgCKrHqWl9p4e30559TmYdTmLvH3tnp55lA3e1q97Gnxcv3GSsLxFC8d76HQqqfaZaLJHWZDlZNnj3Tz+P7Rk3H+ua+TLSf6uHJlCVaDmn8d6GKBy8QvXjpJTyDGn3a0DhvpcP4iF9V5JmoLLeSbtRTZDKwotaHqbxH+zWtX8tc9bWw50UeXPzOjWpYhEk9xvDuIP5qc8OibAS6zjo9eVMMPnzsx4oagTi3zjnOrOdkb4t0bKthUkzcs2TSZSvP4/k7u/PtBeoMx7n78MOfWunjr2lI2Ly/mv85fQG1BptPPvU8dIxhLcrDDz8sn+rjx/q0kUgrLS628c305S4qt1BZY2N/mo8plwtw/WsaoVbOizJZ9z2Asydf+eWjYutFl1vKZyxZTmWdkWYkNg1bFgnwzsgQWvYYOX4TfvtLERy6s5YoVxTT2hvjoRbW8eKyHP+9ondTPb2AjwahToQCVLhOylEkE0Kpl1g9pCy8IgnCmiCfT9ARiKAoc7QpyojtEkVUkXgrCfNYTiLFngvenp5vLfCpBMxRPsaHaxtYGN4FokkA0yYmeUPa5nnAiu6/68M5W/ri9hSVFVuqKrVy6pAB7fwI6ZJJb48k0zx7u4h97O3jucHe21e90DAS6T/QEcYcSmHVq7EYNTpM2m2xfYNFR5jDQ6omwwGWiyxel1G6gxK7ncIefXf3B8bEc7gywqtzGnhH2MOxGDRcuyseoU3P9xgqWlWTWwSL4LQivL4n+jmYt7jA/ev44hVY9tz+yD6NGHjbOsSrPSLs3QjCWuQ6G3BHWVTjY0Zy5bsWSaewmLXqNmiNDEuTXVtpn/8MI85qkKOPlY702THdY+nzQ5o3w1b8fZEezh57A5DP7Sux6vOHEpOfMAiwutGAzaEgpaYLRVPZiopIl6oosyJLE8Z4gkUHH1qgklpXY0KlloskU/kgStSxlZzlMhlqWyDNp6ZrC556KxYUWTvQEx2xBOVE2g4ZgNEFqgocqdxhomeTPZyJWl9tZWWbjzatKhs2zPNO8Fn6fp+L222/nnnvuGfM5hw4doq6uDoDe3l7cbjdNTU3ceeed2Gw2/vGPf4zY2nWkCvDy8vLX3c94PgjGktz60G6ePJgJbA2uehyNVi2jU8vjdt4YzKIf3qljXX9QfCJq8k05N/QDJnK+I1lSbOUv/332aW8X93rwer1mnk5z8TP+rwe28/ShrmGPa1Uyy0qt1BVZKXMY0KtlDrT72XKyLyfJcIHLxNvry/nRc8ezAc/ZsqHKOSypz2HUsKLMTqXTiMusw6LPJFbGUworSm2cW+uiIs/IE/s7+fBvd4x5fI1KoibfzIWLCyiy6nCYtFQ4jTS7wzT1hVlRaiPfouPRXW1o1ZnuOsFoEqNOTYXTQL5Zz43nVAH0b0Za0GlUPLyjlaNdAZrcYU4Oud7917nVvHtjBQvyzdz/nwbavRF+92rziOvsN68q4fvvWsMvXmrgq/84iMOo4c2rSvj05sXDZpC3uMP8bU873/rXkRE/a12Rha9eszwnCH2408+/j/byzg3lWPqPl0orPLyjlf3tPvJMOqwGNU8f6uKVk24kmNAatzLPiEmrptim50tXLaUy7/WzMSmum7NL/HyFufKZP+3hzztagUzHou+/aw2FVpF8OV3id/qUb3zjG9xxxx184hOf4N577wUgGo3y6U9/mgcffJBYLMbmzZv50Y9+RGFh4YSO+Xr8+caTaf6+p50/7WhhZ5M3Z/TLXKuvdOCNxGn3RIin0jkV0FaDmlgiPelW7Vq1zJJiK019Ia5ZXYrNoOF3rzZPq6p7tHPf3uRhQ7WTWDLFgTbfsApuIFvQNLCeHmv02WgGr/8/cmENyVSaP2xtIZ5M8+gt57C05PXx/+WRvB5/p08n8fM9M3jDcb7+z0Mc7PCzv81PmcNAOq3gDsWRJClbGFTmMGDUqoaNQSux6Wnv39/YUJ3pgLyh2gGKBBLZjshb7riYYptIdjyTTfd3WlSAn0FK7QZ+8t51APx6SyOP7GgjnEhOaA7iwIVgqgYC3usqHTmZNKm0kjMXdrBESsmpIpxMFTRkFkuJVBqNWsYXinPkNFV/Q2auRJnDMOlqo6FMWhWpdHrCwW/ItI9fVmId9ec6FesqHXz77auoFhmVZ7RPf/rT3HjjjWM+Z8GCBdl/d7lcuFwuFi1axJIlSygvL+eVV15h06ZNw16n0+nQ6XQzfcrCFJh1aj71hkXZAHj+BALK8WSalaW2YTNyxpJMpVlRZmNfayYre0O1k+2T6DphHTLv16xTsbTYxq6WqbWmW1RoFsFvQZgB8VSaXc3ebHWGBMM6PQCc7A1xzxOHT8s5KSOcgSec4MWjPSM+/w9kqtrff24VN59fw/03rafVE8GqV6NTqzDpVDiMWix6NSadGodRi0qW+O6TR7jv+ROU2PSY9WoWFlhQFIU7HtnHF65YwqpyO5ctK8xpFZ9KK3T6TyUGXFdfnv33O960hBZ3mGPdAf66ux2NLLGw0ILDqOUNSwtwmDJ/N9+yppSfvXgSvUY1YgB8Z7OHF4728P1njmU/+78OdFFTYOZ9m6oIxpIk+zd2z//WcyO2i9SqZT5z2SKcJh0LC8w531tcaEFCyga/IZOkur7aSWWeEbVK4plD3dxz7Uqa3WG2Nrh5eGcrLe6xEy6b+tfBoXiSr/7jENUuIx84dwF6jZxtoy8IgnAmGRyUeteGChH8FmbUtm3b+OlPf8rKlStzHv/Upz7FY489xp/+9CdsNhsf/ehHeetb38p//vOfOTrT+WdwbVZ3IMZN92/jYMf8GsumliVWldnHvOdW0gplDsOIieJjiSfT2Sr3X73cOI2zHF2Zw5A99/H2h/tCMZYWW3CZdTS7w5MOfgPsafVQYtOzptLBpy5dhFYt8/k3LSGWTGe7QAmC8Pr1o+dP8MftrdmvWz0Rim168q068ky67Li3gx3+EQspi2x6ArFMtw1vOHON2tpw6vq8qNDM0a4gn/3TXt63qZLLlhXN8icS5isRAD9DHWz3s7vVi0YljduutsJpxBeJs7LMRqcvOqXKvAHpaVRET+alNoMmp1JofdXpnddQmWecUFufsWQq4+Fgx+RmU7Z7IywqtEzrvYfa0eThmUNd/Nd5C8Z/sjBv5efnk5+fP6XXptOZzZ7BVd7C/FXmOJWdONH25upJ3ETKEtQWWNjX6uPc2jyiifSkkqSqRrhGLi60TGtsw193t7Oo0MItF9VO+RiCIMxP7lCc5aVWjnQGSIyTFahRSXzpqmVsXlpIviUTYL5ocUH2+7Fkim5/DH80wXOHu3FZdFy4KJ94SuGWi2t544pifvT8CVo9YR7c1kw0kfn799E/7MKiU/PUwS7iyTTJtMI715ezcYGTQosORclkm3f5Y6TSCg6ThhKbgUMdfn7ywgk21eTxn+N9PHWomxK7gavXlHDHI3vp9sd4+UTfiHPKBrR6Itzwy605j71xRRHv21QFwINbm2nqC3GyNzTqrMR4Ms3DO9r444c2YTPmJiBJkkTtoKC4oijc+feDORuoV6wspqE3xN/3tFNkM/DATRv4xuOHs8lWY2nqC2eD4U8e7GJpsZWFhRbKHQbKnUaWlVhzgu+CIAjzVYUzs8ZeVGjmzatK5vhshNeSYDDI9ddfz89//nPuuuuu7OM+n49f/OIX/P73v+fiiy8G4P7772fJkiW88sornHXWWXN1ynNOUZRsd7pP/2kPj+3tQKOSRxyzNR+sKreP2y0tEEsR6QtR3T8+xmXWkUylUankaRUlzYQuf5QFLhMne3OD86vKbCiAP5KgzRshkVLo8MWQJWlY0KncaeBTly4inkzzm1eaxizcqcoz8eELannz6pJswFuSJJH0LggCAMtKrKhlKaczWYcvSqldP6GxjAfafaSVTDFP7wixroG91JeO95JWFN6wtHBYR9RoIkW7N0KJ3SCuTa9hIgB+BmrqC/HIrjbgVJX1mnI7WrXcnzUpEYwliKcU1LLE0a4AaSXT4muqwe/6SgeKogybwTAbnCYt5Q4De1pPzYrZ1uihvtKRaXukQFpRSKZn53x0ailbETkdyVSa45PM+gRYVGRhe+PUKihHo1XLvH1d+fhPFF4TXn31VbZt28a5556Lw+HgxIkTfPGLX6SmpmbE6m9h/jHr1GxakEc0mWLvBK9H3kgCp0lLiU2PAjT3hQjERg7IrK9yZud072vzD5t7O558i25YhwzVJOaQj+YHzx7j5vMXoJmBYwmCkLGh+tTv+1wZqIIxaGSWFdtQqSSOdwdHvPYkUgpffHQ/X3x0PypZwqJXo5YltCoZTzgxYqBZluCypUUsLrKwsMBMhzcyYiJjIJbkb3vas18PtJCXJDBqVMNmKw6+IfdHk4RiSXyRBFesLCaeTAMSzxzuntLP5FcvNxJLpvnsZYs5p9bFX3a1cqB97HXtka4Am77xDD941xouWZLbNnVwJY2iwJYTfdmvCyw6Ni3I47yF+Zy38FQi3Y/fs44b79/Kv4/1Tvi8B4Lhj+/vzHZ3WlFq44tXLsVh1FBbYB5x1IogCMJ8sLzEhlqGDm+EEz1BFs5w4rnw+nXLLbdwxRVXcOmll+YEwHfs2EEikeDSSy/NPlZXV0dFRQVbtmwZMQA+0niy15LnDnfz6O42OrxR3nd2JQfa/TyyM7PHOdnW4afDhion3kh8wqPCkmlIptO0eyLZNfCGORhDKEuZ/dUimx6dWoVKgnhSyenOuXHQfUKJXY9alrLJqm3eKDaDOts2vTLPyKP/fQ4OU6YLkNOk5ebfDB9TVJNv4s43L+ec2jyxJhQEYVRXry7l73vaefrQqfvpjdVOugZ1ZxtLLKlQ4TTQ4YuQGiHJvicYY32Vg0g8M4r3Uw/t5khXkL5gDJdZx8JCM9sbPbR5I9QWmHnD0kIWFZp5y5qyGfuMwvwgAuBnmGcPd/HVfxzq33Q7ZdcEMmNebXCzvsrBvjZfthpmKJ1aJp5KD6s+kWUpp43EbFpYYB5xo3akNkMDc2lmUiypsLDAzLFptFw3alVTzhyKxFOU2Q20emduDvjGauewaiHhtctoNPLII4/w5S9/mVAoRHFxMZdffjlf+MIXRJvzM8TX/3mILSf7xn/iIB2+KL5IAnco0/pnfZWDbeMk01Q4DTSP0wJ3JDsGzQ1TFOj0RTg8Ay3qVJLEiZ4gdUViTpMgzJRANJGZhTVIhzdKywhtxGZbJJFmd6sXyLRmryuyYDWoafNEaRth3ZNKK3jD4yfopBV44kAnLxzt4b8vquHt9WUc7gxMuIJIURgW/IbcOdnHB60LXznRxzt/9sq0ssQVBX7/ajNPHugc1lay2KanyKYfFsQ369S8ZU0py0ttYx5bliX+8fFziSXTGDSqUdtMPrqrDf8kE6AGG/jx7G/3cd1Pt7Co0MyHL6hBliQ84ThvXVuGzSDWn4IgzB/5Fh2SJKFVq9jT6hUBcGFGPPjgg+zcuZNt27YN+15nZydarRa73Z7zeGFhIZ2dnSMe7+677+bOO++cjVOdU1tO9PHNfx3OWd9Mp4PY6dLqDdPunVhAZsDgMTMb5ygZdSDpfWCdqZZhcZE1u35bWWrjYHsm2b7UbmBhgRl/NMHOQf99fJEkFr2aH7xrDZuXFaHtb0n8xP4OPvunvTnvV2zTs7DQws/eu05UUgqCMCF3Xr2cFvc2jnQFqHaZ2NbonlQHYYB0muws8MG6/DG6/DHMWhWyLPH0wS6C/ff83YFYzpiN491BjncHUckSJTYDGxfkTetzCfOLCICfQU72BPngr3eQmkYb8m2NHpYUWzjSmakKX1thR5YkdjR7WFVm40R3EJNWQ4nDgEGjQkKi2RMGRaHYpkclD2+BM9Mm8+ma+sKsqbCjkSUkSSJT/54JIrtD8SkHkbVqGZUsDftZF1h0uMw6+kKZi+hITFoVNQXmCVdtDqbXyGhUMk6TdsYC4Badmi9duXRGjiWcGVasWMGzzz4716chTFE6rfDbV5on/bpFheacgHc0kWJ9lQNJkoa1WxuYx+s06gjGUtQWmOkJRGnoza3qHvUclVNzwzZWO+kJxCd17R5NKJ7iB88e5753r52BowmCACOPYqkdMkN6LiiQ08mn3GGg2G7AG45zrDs4aivwsUQSKe577jjlDiOh+Oy1zzzZG8KsU89Ii87eYBytWuYd/bPHFRT+uK2VvmCcd22ooNUTRlEULq4r5KpVJdm28OPRqOQRu2koisLOZi8/fv4Ezx3pnvB9xcICM0U2PVqVPKzqfeC/1dGuILf+cQ9OkxaTToUnnOBTly4U1T+CIMwbCplOI32hOL97tZm3rilDFrNohWloaWnhE5/4BE899RR6/czMlL/jjju49dZbs1/7/X7Ky8/sjn6ptMLf97ZPe9TgXLDoNMDkAuCDvdrgpsSux2bQcLw7OOo4oCKrns4JVj4OpdfIRBNpFhWaUcuZNuPbhiQXJNOZcZqFVh1d/hiheJIlxVaSaQWTTt3f/jxNVZ4x2+3t3FoXv7xxfc5a7uXjvdz6xz2E4ymWl1p571mVnL8onyKrXqz5BEGYlFK7gW9cu4K3/OhlGnpDrCy1sbdtYvEUi149ZkFPucNAnlnL7hYfq8tt7G4Z/7iptMItv9/J3z92LsU2w7jPF84MIgB+hvjnvg4+9+e90wp+DzjUEWBFqZVwPJWT2XfqQpDCPaTaprM/k6Yqzzjt9x/LwgIzRzonXkUYiCVHXUBrVBJ2o2ZClUNDHesKsKjQzKEhm8bxVJqDHX4WFpjJN+vQ9VfVJJIp4imFA+1+iu0GWt0TCyINtrHayYF234TmXEyGRa+eFxvdgiBM3FizZEcz9K/DvrbMtXRhgRm1DE6TjnKnAaNGzfamzM3w7lYv+WYdWxvcLCuZfNX1hYvyeeVk34wEvwcsLRbV34Iw25rdYZaXWEkrCqFYkqYpdIKYaS2eSLYq3WHUUJNvJpFKc6QrMGrnopFEE+lpdfGZqIkGv6tdJoKxJIqioFXJI2anx5NpnjjQyY+vX0tdsZXNy4pIpdIc6Qry6TcsRJYzyZEz4a7HDvGLlxom/HyXWcsFiwpIpNJ8/JJaFrjMbDnZxz/2dtDQm9nE3dPizamWX1Vm46vXLKfMMbv3DYIgCJP14NZmNlQ5afNGMOvUtHrCVOSZ5vq0hDPYjh076O7uZu3aUwm8qVSKF198kR/+8If861//Ih6P4/V6c6rAu7q6KCoqGvGYOp3uNde5LZ5M8+SBrrk+jUmx6tXU5Jsx69UYtSrc4TjRRAqHUYvNkNlrPNJ1as9wQ7UTX/9jGpVEgUWf7XDU7o3S7o2yodrJ7hYvsgQry+woioIsSZzsCdHpj7Kq3MaeQUEaWYI15Q58kTiNfeGc9dYAm0HDApeJZneYDm8Em1E7YgJssU1PsU2f7SB6oieUbdFem2/ieE8IlSzx1auXsbvFS7nDyFvXlQ0Lai8vs3H16lLyzVo+9YZFIugtCMK0DI696DUTH4e4rMTKKydH766hkiV2t/hYWTY8+O0wanAYtbR6MtdVi15Nid1Apy9KbzDOh3+7kz9+6Cx0ahWKouRc51JphXA8yd/3dLCmws4SsYc574kA+Dz3191tfPepozT1TT6gOpaBwMhkBWNJbAbNpOfFTpSCgi8yMxU7KlkilZra/CAFsOo1VDiNNLvD2AwaCq06jnZlNlRH21jdUOWccgsnRYFgLEWRVU9lnpHeYAyHUUtjX2hYa8zJaPdFOdoVZHGRaO8mCGcCWZYwaFSTCoI7jRr2j5Ileaw7iM2gwR2K0x3IdK5YWWbLdqnoCWYeO9DuZ0O1Y8LjLjZUOXj+aA96jczKMhuyJNHhjdAVGLk7xkQUWHS8Z2PllF8vCMLExJPp7AiZRYXzL0nOE05kR99oVRIrS21o1XImkAygZNaMDb2hUato5ouG3szGot2oYWO1g7vWldLqifDg1pZs27UrVhZz++V13P+fRt7981f5nyvqWFJs5YqVxbR5oyzIn1xwJpZM4Y8kcRg1qIdUgb9zfTkmrYrvP3t8QsfqDcZ54Wg37z2rCo1KRpYlzql1cU6ti0d3tfGpP+7OVoBfs7qEhYUWLq4rEMFvQRBmRCyZQqc+1Uo3FEti0k19GyuRSrO9KdNes80bYVujRwTAhWm55JJL2LdvX85jN910E3V1ddx2222Ul5ej0Wh45plnuPbaawE4cuQIzc3NbNq0aS5OeU4YtCqWFFuIJ03sbvHOy1nfDqOGBflmVLKEP5LgZE9wxHGTA90gJQnqqxz0+GM0ucMcbPcTjCWpyTfR1BemzRthXaWDva3e7Hp1a4ObFaVWdGoVB9p8OSN4agvMHO3M3WtcV5kZa7aqzDZi8LvYpkenlrPnubbCnlPoNFihVT/q99QqmUWFZtZWOHj3xkrePcY9+QtHevj4JbWiOlIQhBnRPKiIcFeLl7oiC4FoJjY00pg0yFx/Y4kURTZ9tmhTkqAm38zx7iAWnTrbDU2nltlQ5SStKHQFogSiSTzhBJ7+gkmVLOGLJPFFAhRYdKwssxFLJPnCX/bjNGn54/YW8i06im0Gmt1huv3R7LXbolPzyucvmdbaVJh94r/OPJZOK3zrX0dmveX4ZPQG4xRYdGysdnKyN0TPNAIdI3EatUBoRo5V5jDS0DO1CqBESuHVBjdWvYrFhWYaekMc7Ro/6B9PpaktMKPXyOwflGSwujyT2ZlKK+g0KiQyF9i0ohCIZmbqRBJJ9GqJTn90UNujEFaDOhuIn6oD7T4RABeEM4jTpB11oTeSijzTmN0jhiYtNfWFc1qbDdja4JlQIs/g50QT6WwwXZagzGHAbtBkg2uTYTNosBnFvFhBOF3UsoR5nt+sxVPKqG3Q8s06Kl1Gdjd7R9wUnE+84QSP7evgsX0dlNoz7diqXSasejX/86YlFNv0/HV3G/FUmvueO4E3nOCsmjzqKx0U2fRY9BO7Nu5v8/HrLY38cXsrWpVMXbGFZSVWdjR5aOwNE59CcmhvMM73nj7Ks4e7+ObbVlFbkNkcvmZNKaUOAwfafLxy0k1FnolbLqqd9PEFQRBGMzj4DUxrg3F7o5suf4zlJTYkCXQaFRr1xCuNBGEkFouF5cuX5zxmMpnIy8vLPv6BD3yAW2+9FafTidVq5WMf+xibNm3irLPOmotTnjO/fv8GJEnihaM93PDLrXN9OjkKLDrCsSQ7miaWDA6ZIpbtjR4kCdaU29nT6gXIVlUD7GjysCDfhMukI55Ms7vVO2JBUm2BiRM9w0cAJfsD52klE9wZ/H2dWiYcT9LhywSKim36bML7UHajhqa+0fdaB8YS9QXjvGVNH6sr7GhV8ojV3VetKhn1OIIgCJN16xsW8fDOVnoCMRIpJXs9WllmG3Vf1GXWsavFx7JSKzq1TFNfpsOdViVTX+mgJxDLFi/KksSrDaPvcQ7uttwdiOEy6zjcGeTwoIQkTziRLYocbG2lY0qfWTi95veO1+vcv4/1TDn4bTOoUQD/DFVTD9YdiNEdiLG81DrjAfCZ3Ls83h2kJt+EXiNzoH14+5/x1BaYMGhUk6qW16gkjncHMetUVOYZiSXTlDsM7GnxEp9ihZI/kkSrktlY7SQUT+YE1lWyxMICM1a9hlA8yYFRAk7WCW6aCoIwP3x28yI++dCe7NcSmfY+A5t+oXgSnVpGJUm0eaNEJjHrdlGhmU5/dFjwe0A0OXbl+VgB8rQCrZ7IlANqk61yFARhepJphWAsyfqqTHXJmaYnGKMnGMNh1FDmMKBVq8gkekuk0wrxVJpoIkUolsIfTWQzyedamzdCmzeCRa/m05ctosRuYMuJPvpCmY4/A5uXLx7t4cWjPdz79FHOWpDHmgo7H7qgZsx13Wf+tCe7aRBPZRKUgrEkHd4o795YwcneENF4imZ3eNJzJve0+rjqBy9R5TKiUcnc/sY6zluYz/oqJzeeUz3Fn4YgCMLpsbPZk7MBev5CF1etLJ7DMxJeL773ve8hyzLXXnstsViMzZs386Mf/WiuT+u0GwimriqzZTo2zqPkxe5AjDXl9hErvsejKIz5upM9IU72hJAkWFpsIZ5SOD6kq6RFp8GgUREeVBFu1auzXeH2tfnQyBLrFzg53h2kOxBjSbE1JwneqFVlxwkN5Q0nqMozEogmR0waLbLqKLLpkSWJd/zsFVSyhEmr4vnPXpQdw+MJxWnzRlhWYhVtzwVBmDHecJx8s25YjKkveOrr+ioHre4wkiRRZNNj0qpIpRUMahXNoTDLSqy4Qwl6g1Fiydxr3K5mDxadmsAERpitq3RMKhHqC1csEdXfZwDxX2iOHe8O8Pc9HTx7uJuTPUEWFVlYWGCmsTfMjmYPa8pt7GrxIUuTCw5X5plo9URYX+XgcGeAQDRJbb4JpzmT1ThQmadTS8MuDBMVmIXg+vYmDxVOI4VWHTubPEy3q+WJnhCrymyTft3qcvuUZnFLZBaBwViKYCwTXOocYdbjZPUG4/QGMzfrLrOWIqueUDxFqzuc3eSETLujfW2+Ye1A9ZrczHlBEOaveDLNo7vbWVFqZV+bH6tBTZ5JO2pFtU4tYzdOrIWxJEE0kRozOUo3RiXMhirHhMY8dPqjlNoNtHkjmLSqnNZuQ71rQwU7mzwsLbHyxSuXjntsQRBm1tGuIJIETpOGCufY3STmq8EtzMYikamAMevVmLRq9GoVarWEJxTPqdaZqkKrLtsWcyiVLLG8xEqbN0IskWZ1hZ0vX7WU2gILiqIQiI58/sU2PYsKLbxwtIeXT/QRTaR55/py1CqZatfwpKHffmAj+9t8dPqjaNUyS0usVOWZsmvBVFpBlmBbo4e7HjuY7eAxUfFUOpv9/vtXm1lWYpux+eSCIAizRVEUXj7ex/oqB5FECpNWzY3nVIkgjjArnn/++Zyv9Xo99913H/fdd9/cnNA8YzNoWFfpYOsYFXlzYU+rl3UVDnY2e5iN0LyikJ3NvbDAjN2oySag7mrxUmzTU1dkxaJX0eKOcLI3hH/Qfp9Fr2FXsxeVnFkfHhjSIelET4hSh4G2UYLgnb4oTpM2p0pcI0usqXBwrDuQMyM3lVZIphVMusz68Yn9HXzqoT1EEik2VDm5fHlRpvK9wsHqcvuM/HwEQXj9SabSfPWxQ9nRYINp1SrWlNtJpdOc7AlSYjfgCyfY1Zy5VrtDcZwmLS6zDpNOjcTwlukOo4YSu2HUgkHIjOhYUWrjaFdgUsHvModBBL/PEOK/0hxJpRV++VIDP3nhRLbaA2BXs5ddg2ay7GrxsabcTiCW5GRPcMJB8O5ADHcojrv/2CatiuM9Iejf3FuQb8q0iOgNwRSXdjajBmZhvdrsDtPsDrOh2jkjC2JZntxNrSxBd2BqQeuDHX5UEtMO3I8lEwwfeSb4zmYvxTYd5U4jfcHMHwKVLHFObd7snZAgCDNqd4uX54/0oFXLrCm344smONkTYk2FHY1K5kR3MOfvRiyZnvCiS1EgHE+xrMQyYmeMZSXWEatAbQYNdUWWMdsGDeYNJ4jEU9QVWTjRE2RNuZ02byR7s61RSVy+vJjNywq5YkWx2HwUhDmmKOAOJXCHvORbdFQ4jZO6+TtTKIwcLF9bYZ+R4zuM2uz1uNRuIJpIIUkSyVSaDdV5fOayRahkKeeaF0+m+fSf9hCJp7h2bRl/39tOPJlGluC8hfn8zxVLWFRoIZpIceffD7Kz2cNvXmnCZdLy8xvqWVaSm+hpNWjYVJPH1kY366ucw5IgVf3r4g3VTv7y3+fw9z3t7G7x8vj+jmHBe41K4l0bKnjpWC/RRIr2IUmdzxzq5kD7f3jg/RtGDMYLgiDMFz96/gTPH+3Jfq3XyKwuF20rBeF0C0QT3Pv0MZKp9LCW3nMtrUCrN8yiQjNHRmh1O5MGWvMOrjrv8EXp8EWx6FQsLrJysvdUcubGaidqOdPGN5JQCMaGJ5iP19FpVbl92P38mkr7qPuu4XiKm+7fhsus4/H9HafmmDe62d3ipcxhIBhNigC4IAhTplbJ3Hh2FX/f0z7sey6zlm2NHjZUO/v3KhJUu0ysrbCj9MeyBrppNPSGcBg1GDUy4UQavVqmzGkkmUqPGfzWqCTqCs1Tij997S0rKLEbJv064fQTAfA54g7F+e5TR7PtbMYysBgqtevJM+vGrNQwaVXUFVuHbVoOrb472RNieamVcGLycwAHaCc4L6vcacBh0BJPpen0R/FOoEIHYG+rd9KV70Pp1DLHBmVMFlh0hGJJQCGtgFmnwWnSEEmkUckSGpXE0a4g7d6pBcAXF1rY0Ty3G8YdvhgdvswG5kA1U5c/RpFNP5enJQjCBPn753XHk2l2tXjRqSVWl9uzyVGrymw5AXBgUi3Qe4NxKvNGDlQMzBjLt+godxjwRxP0BGL4IokJB78HxJLpbIeKXS1eSh2ZheECl4mfvW8dtQWWSR1PEITToycQQ6uWx+3eIAw3uCvPyf41mN2o4TtvX8UlSwpHfI1WLfODd63Jfu0wamjsC/GuDRU5r9FrVNz91hVAppOHLEnD1uLbG9389MWTfPzihVTlmQjFkmN2ARqY411XbOHfx3rwqhPEkqfuDRIphScPdPGlq5ayotTGlpN9/GVnGzuaPMRTaeKpNLdcVDPhewJBEIS5EIwleGJ/R85j0USaDl9EdLAQhNPMotdku37953gv33ziMHsm2Y1mNunVqlkPfg8WGuE+PhBLsavZg0GjIpJIoVPLnOgJ0huMY9aqWFpqy4yyGZKYOFZSebFNn51RPmAiRUcvn+jL+bquyMI71pdz5coS7EYNIo1dEITpUkbJhOrwRllUaKaxPxloQ5WDHc1eGnoVVpYO7/brCSeoLTBzvDtInlk3bNTESBYWmNnVMrW/Qd7wyMWJwvwjAuBzJN+i45OXLuTuxw9P+DVt3iht3ijFNh0VThOptMLOZk9OgDiaSLF3yKJmJGsr7OxsHv95Y9ne6EEjS0hSZgPNoFFTW2jGG46jKJBIpSm06tna4KaFUy0o1pTb2d8+vE33UCU2A2lFobEvjN2oocJpRKOSiCXSpBUIxBLkmXS4Q3Ga3Zl242admmQ6TWWeCbtBQyyZwqxXE0ukCUST2Y1JWQJZkrKzI2eCy6xlvhYx9gZFAFwQzhQW/ak/zStLbXQFojktiROp4YlLx7qC2AwafJGxE4wsOhVlTiM6tUxtgYnj3bktf816NVa9mnKHYdp/I4Zq80RYWmzl/pvWU2gV1yNBmM/aPBE2VjsnnfgiZGhUEu/eUEG+RcfiIivrq50Tfu0XhoyC+M/xXn71ciPecByDVs39N64fNahdX+Wkvmr094omUvQEYpQ5DDmbpHVFVp6+9QIe2tbC9iYPRq2Kkz0hXjreS6c/yn//bicus47r6sv4znWrsBs17Gnx8cjOVmryzZSKzHdBEOaxPS1emvrCLHCZcJl1BGNJrlxVzKJCkYwpCHPpnFoXly8vnvUA+NJiKxa9mkQqTTSRpjcYIxJPUukyYdKqafGEseo1hGJJwhMoUppJR7uCI+7PphRYUmxhZ7OXZFqh2mWiNxgnGE9lg9YLXKacKvGxtiM7fFHOqc0jmVIIxjIJj4qiTHgWe75FR6FVxy9vXE+BRdzLC4Iwc8qdRtSyRHLQtUiWwGnWYtCo6PBGqXaZSCtkr1eD53kPHv3gNGqRyIwmG9oOfbAiq46FBRb+fbx3yuctxs2eOUQAfA7dcHYVf9nVllMtMhGDK3w3LnCSSil0+aMU2vTEEmn2tY29eDRqVTT2hqd83oMlBi5OKYVIIs7WBjcaWaI8z0hjX5jGvuHvs6vFy8JCM+l0JrhdaNVh0qoJxJJ0+qJY9WoWF1nY1uih0KpDljLtdL3hU59LItPGssWduZgVWnTkW3Sc6AkSTaQ5MuhnajdqhlWdp5XMrIaBwPl0rSyzsbfVN2pr8tPJolNj7Q+EBfv/IOg1ojJHEM4UdqOWAouuP0t7+PV8pHbn0WSaleV2vOE4VoMmk+ATiOE0afFFEkiAP5qgyx/jUP/cMZUsUWzTZf+eANnuITubvawstbF3nL8nkxVNpPjJCyf4/JuWoFGJ65IgzGevNrhZU25nd4t3VuYgvlatLrfzhSuWsKrcPu3rXCyZ4v/+fZJIIsUlSwq58eyqbAtzyHSU+s6TR1haYuX6jZUAfOPxw/z+1SYkSWJRoZllJTZWldtIJBVqC828etLNyyd6OX9hPm9bV4ajv/pRkiTeuaGCa9aUoteoSKcV/rm/g+cO99DUF6I3GOMnL5zg//7dwOcuX8z7z6lmU00ee1q8dPqiItFSEIR5KZ1O8+1/HaU638SeFh8ne0PcdE4V/31h7VyfmiAIwLXrSoklU/xha/OwUSzjkSTIM2kJxVLDumsuKjQjIWE1qEdtC76/LdMWt77Swfb++2DNJEcoTpfTpCE8SselgXGOalkiMuQ5hRYdrUOCO+N1GD3Q7s/ZG62v1LK40DLi7N2hNi8r5M43L89ZhwqCIMyEAosOtSo3AL6uMjPSQS3BmorMyJpj3Zm9TK1KorEvk/xj1qlxGDXZAPjWRje1BWZsBs2I71WTb8Ki17Cn1Yt6mvfqFU7jtF4vnD4iAD6HvvPkkUkHv4fa3uBmXaWTTn+UFs/omS2D1RVZZryyb7BShyHb9nE0x/pbCskSw9qN+6PJ7ALVqFWN2AJ96ENdgRhdgZEXy6O1XC+26WcsAH60K8DaCjvheIo2b4TaAjM6tUwsmc6Z6X46/OWWs6ktsKAoCoFYEpUkYdSKrCRBOFM4jBoC0STdgZGDz0NvfgdsbXBT4TRwdFDLtobe0a/FqbSC06TNCYAPFhuh0ny6TvaGaHKHue3yOkSypHA6tbW1cdttt/H4448TDoepra3l/vvvp76+Hsi03fryl7/Mz3/+c7xeL+eccw4//vGPWbhw4Ryf+dza1eJFLUusqbCzu9l7KvFRGNHly4r40lVLZ2wWmE6t4v6bNoz6/UMdfv62p51zal3ZxxQU/NFMAuS2Rs+om77/PtbLT188wfUbK3n/OdXYjJlNgoFMdlmWuHJlCVeuLMm+xhdJsK/VR4snjCxLHO8KYNSqRPBbEIR5KZVW+MYTh9nd6kVRYF2Fg2A8SaFFN9enJghCvwKLnk9euohbLqplT4uXFk+Yx/d18uTBrpznldj0lDmNxBIpYsk0vkiCIquOXS0+lpVYMWnVKCjIkkRDbyjnnng86UHtd0/nWlevkSm2GUadT7u90cPiQgsmnSq7h6tRSeRbdGhkmfSQsWi6ISNp1HKm5bzdqMVh1OTsAy8pttDsDtM9yj7qYF9/ywretaF8zBbrgiAIU9XcFyY6aESv1aDOxpUMWhUnekNU5RnxRjL3uHlmHR39IyA0Kgm9WkWhVUepPdPJ8nh3EH8kwbpKB3taPBRa9ZQ5MsHqwR3upnu1P94dZEmxdZpHEU4HEQCfQ2O1YpiolJLJbimy6nCYtNnKvrFMN8NlPI19YTZUOTnQ7ht3duR4a0uXWUfDDFWrD9XUF0KSYJRRE5MSTaRzFpO7mr3YDGp8kSRrym1TnicxGWadmvMWuhhofCRJElb9yBlPgiDMXzajZtTsba1a5kjX6Nf5Dm80OytsPDq1zIH20Y91pDOAUSMTTsxcIFyvkfnudatFqyDhtPJ4PJxzzjlcdNFFPP744+Tn53Ps2DEcDkf2Od/85jf5/ve/zwMPPEB1dTVf/OIX2bx5MwcPHkSvf30H95JphW2NHhxGDZV5Rva1+hhnis0ZR5qBCYY3nl3Fl65cmq3WOR3OqXWx/QuXolOfuqbefnkdj+3toHUCibG9wTg/ePYYf9nVxmMfPxfLOOtGm0HDuQtPBdujyTQH2n0sFG2EBUGYh5LpNA9tbWF9pZNkOs2O5kxC0ECSkCAI84dGJWdHuZQ5jMMC4Ba9eti86oEAyGgB5Imaq6rmlWX2cWdwD9z7ry63o1XJpBWFPa3eEUdKDnTCNGlVLCu1cbw7gDuUwBNO0DDkuRa9JjsfV6OSWF5iY3+bLycBYHGhhfMXuXj3xoppfEpBEITRJVNpnj7Uxdk1TraccKMA6ZRCOJnZ0wzEUqzMN3N00D5oPJlmfZWDWDJNMqXgjyYotOjZ2eylwKLDadJyuDOAJxxHo1ZlRwoPNd0rf/sMxPWE00MEwOdIOq3Q5olQ7TJh0qlQlEy182hVGuPp9MdwmSeWyXysK4BJqxo3OD0eWYLlpTb0ahXJdCZAMhAE3tropirPiDaSWWxNhUWvHrV6eyZ0+mOzMt9yRakNo1aVPe5EK/On44oVxfzw3WtERqYgvAbo1CqMWtWIrdAqnUaOdY+ezZ5IK9QUGCfUXSTPrB3WgWMwl1k7Y2MdZAk+evFCbjy7Cmd/u11BOF3uueceysvLuf/++7OPVVdXZ/9dURTuvfdevvCFL3D11VcD8Otf/5rCwkIeffRR3vnOd572c56PPOEEnrAv2/FmINnGolfTF4znzCB8vVlabOXWyxad1uD3gMHB755AjJeO99AzgWqeAWkFmt1hVt35JCV2AwUWHZctK8KoVfG+TVVjvnZ5qY3lpbapnrowz8ViMTZu3MiePXvYtWsXq1evzn5v79693HLLLWzbto38/Hw+9rGP8bnPfW7uTlYQRqCRZS6qK+DfR3txh+OZGeAW7YwUIgiCMHvqKx3c+oZF/PaVJiQps1c6U90bRxKYg6QYl1lLX3Bi67Uyh4GG3hC+yNj7o6vKbLjDCQ52+McNrG9tcLO02IpZr8aokWnzRlldYSeeTKNVyyRSCi3uMA9ubcGkU/OuDRUUWl/fScGCIGQkU+kZK65Uq2QsBg0gYdGrWVJspScYy+ksLEsQjJ3aH+0LxekLxVlX6UAijUatYk9/4WF3IJbtbJFIKSRSo8e+pnLnXuYwYDNoiCfTbG/y8KEpHEM4/cQAzjlyqNPPnlYfDb0h9rf5OdDuZ3eLl3Ln1FsmNrnDrKt0oFGN/SvsCScmtVlV5jBQ7TJlv1ZJmfkMK8vs7G31sbXRzc5mL3tbM5ui2v73b+wLU2CZ+gIpEE3O+szJ42MEkiarwKJjeYmVfW2+nKB6bzDOmvLZ3Rxs80ZE8FsQXkMcxpGDxNZR5tgM0Kvl7CycseSZtFhGmCU+2GgzcyarvtLB996xmlvfsEgEv4U58be//Y36+nre/va3U1BQwJo1a/j5z3+e/X5DQwOdnZ1ceuml2cdsNhsbN25ky5YtIx4zFovh9/tz/jnd7EYNVr0arUpmbYV9womQ07Wz2cvhzgC7WjL/u63Rg04jY36djlvRqWV+cWP9vOi6k2/RcfWq0ikFpdMKtHoi7Gz28o3HD/OGpYVAf4LI00eJjtJZ5D/HMzPChdeez33uc5SUlAx73O/3c9lll1FZWcmOHTv41re+xf/+7//ys5/9bA7OUhBGl1IUzDo17nAmofNkb4itDR6eP9KDOzQzSZ6CIMw8SZL4+CWZ5Okuf4yG3jCRGexKNtTQ1uGzaX2Vg6XFVqpdJiQU1lbYqa90jPmaLl8Ui378+jVfJMmBdv+Eu1we7QrQ2Btib5ufSDyFJEl0+KJsa/Swu8VLXyhOIJbk3qePcd49z3GgffY7WwqCMP/NdGfh6+rLedeGChQyLcoHB78XFZrZPUJXXVkCg0bGH01kg98zTZbIxtjsRg0bqpyEYpnr7LHuIE8d7OKVk32z8t7CzBIV4HNkSZGVL1+1lG88fphYMrOQS6QUIvEUZp0qJ7NlogLRJDuaPBTbdLjMOva1jb4Zu6s/2N7iHjv7eU25nV0tXgAWuEw4zVqOdQVzMmoGJNMKO5u9uMxajFoVes30szTzTFqOT+sIoyuw6CixG+ib4s3vhioHJ3tDqGWJVJoRfyYDDncGZ7yV8FeuXsbZNS5SaYVoIkUsmcqpAhIE4cxlN2pGrE4Zrz2bc5yqboCVZTZa3RGOjDMXrS8UR6eWiCWnlor0wfOqqS0w8471omWaMLdOnjzJj3/8Y2699VY+//nPs23bNj7+8Y+j1Wq54YYb6OzsBKCwsDDndYWFhdnvDXX33Xdz5513zvq5j+Xbb1+F8raVJFIKWrXMH7e38MT+ToKx5IjZzDM19mU0qyvsI7ZjnG1atUw8Ob31lVmvYmO1c9KvU4Byh4Fi28zM/J6sZCpNKJbKzu+GzOzuT126iPf84tUpHdNh1GA1aPCEEhTbDEiSxCcvXTTic0/0BPnhsyfIM2v59ttXifEWryGPP/44Tz75JA8//DCPP/54zvd+97vfEY/H+eUvf4lWq2XZsmXs3r2b7373u9x8881zdMaCMJxGJXPFimJ+92pz9jGTVsXLt1+MaZxEUEEQ5t7e1tMTcG3sC1PuMMxI98YF+SZ84QRlDgMHO/zD1sZHu4IscBnZ2+rFadLR2OcjmVbYUO0kkUzR1BfJJu1AJsDjsuhom8C5Her0s6LUxr62if3cSuwGPOE4S4qt7G3x0uqNoJElNlQ52dqYW0EeT6V5aFsLX7ladP4RBGFmpdMK2xvdI3bjMIySZL+2woEvkpjW2NyR6gitejXlTiMmnZrtjW7UskRtgZkjnYFh10WAd/7sFV747IVU5pmGH0yYN8Sqf47IssRN51TzhqWFfPZPe9nSnzHSG4yzrMSKSTd8vs1EdfhilNkNrCyzIQH72nzZWdvrqzKZhdsaPaBkFlNjZVKe7A1SaNXR5Y9xsjc0ofaWvcE4iwrNHB0nuDIRO5rcbKh2ZmfZ6DUyXf6Jt3UcS1pRpjzvYaCF/ETbA0cSKRYWmOkKRPFHpt9e6awFznHbUgqCcOayG4dXEpbaDRzpHLvKtMxuGDUArpYllpVY2TPBjQRvOMGachu7ppBNecOmSm5/45I5m6cmCIOl02nq6+v5+te/DsCaNWvYv38/P/nJT7jhhhumdMw77riDW2+9Nfu13++nvLx8Rs53MiRJQqvO/J5dV1/OJXUF3PfcCX77ShPxVBpZgq+9ZQWXLikkEE1w+b3/Jp6avQqa8WhU0owHyVeX29ndn6w5Vesq7OxontoxNKq8ab33dCTTSk7wG8AdivM/j+6b8jEzre4TNPWFWFpiHfV5iqLwuT/vJRJP0tgX4huPH+b2N9aJIPhrQFdXFx/84Ad59NFHMRqNw76/ZcsWzj//fLTaU11dNm/ezD333IPH48HhGLuSTRBOJ7tRw4ZqJ819mfbBV64sFsFvQThDXH9WBfvafLM+tsAXSaCSJeqKLITjSZwm3ZTXli6zjpM9IfpCcdZXOYaNufRFEnT6o2ysziMUTxJJpPCGE9n93/VVDtyNp/YZlxRbs6MmR7O40EIsmSIUSzGZ22+dRiYQTebsPSfSColUGpUskUrnrtn/sLWZD11QQ6l9bhI/BUF4bfrr7jZ+/UpTzmMDcZfj/bGlYpuecqcRiczsbV8kMeZ4yKlaVGRh+6DrdiSR5lDH2CMm73vuON9826oZPxdh5oiV/xwrcxj5wpVLuOL7L2UfO9DuxziNNpKVTgM7mr3ZoHep3UCxTY9Klni1wY1KymQlnuwJsbTYSqcvgnuUWdu+SKYNeV2RZUIzZQfM1OZXMk3OYqzSaZuxAHhvME4oNrVg9KIiC7smuVF6rDuIVa+e9ubvWQucfP5NS6b8ekEQ5r+qPBPdgRjp/gu5y6zjWFcA3ygJNBqVxNJiK419oVGvMcm0gm6S1+apxMnOWuDkzquXT/6FgjBLiouLWbp0ac5jS5Ys4eGHHwagqKgIyAR9iouLs8/p6urKmXk7mE6nQ6c7PS3HJyPPrONLVy3lorp8Xjzaw0V1BZxd4wIy7bFf/NxFfPGv+3nqYNccn+lrx0AnnrkI/A59zyOdAf7r19vG7fA0HrNOzeP7O3GYtFTmGYdVuCuKwp92tLKvzYfTqCXPrOVvu9vwhuN87S0rRHDpDKYoCjfeeCMf/vCHqa+vp7GxcdhzOjs7qa6uznlsoINGZ2fniAHwWCxGLHbqHm4uxkYIrz+hWJL/eXQ/u5q9SFLmmnlRXcFcn5YgCBN03sJ8fvKedVz1w5fGf/I0uUPx7GiEZneEtRV2ookUnb4YvkiciW7hdfhOrcG2NXqor3QQSaTQqWX2tnpJpkGnVvHisd4RX9/ujaKSIKXAijJrdm9YliA9yjn4InHyzDoa+8L0BGNsqHKwdUjgfagN1Q62Noz8nF0tXlaU2lDJ0BOIZxMQEimF37/axGc31433YxAEQZiQ490Bfv5SA+sqHaBkCggVRaHNG2FFqTXb3dhm0GTjQ2oZVpXNfMJtTb6JxgkUfg526ZJCvnjl0vGfKMwpsTsxDzSO0K4hHE+xrtLBjqaxFy0jKbQZaBq08dXmjeRkTKYUsrNfD3b42VjtzJlZPZQ/ksQfCVBo0aHTyDRPYFNtf5tvQouuydKoZdSyRHK0ld8kucy6CbU5qnYZiSXTFFsNhOLJSQe/B/ijSQosOsqdBnY0Te0Y3f4YD25r4VhXkL/uaSfPpCWaSPHj96yb0vEEQZh/0orCsUFdNE70jL0IW11uz2aXj5RpPmB7o5t8s46e4MQSifZNYc7X0ExxQZhr55xzDkeOHMl57OjRo1RWVgJQXV1NUVERzzzzTDbg7ff7efXVV/nIRz5yuk93Rpy3MJ/zFuYPe7zIpudn713HjiYPn/nTHhr7pjeqRoBXTrp5989focsfQyVLfOPaFdmkg9OtsS9EagYq7AssOl4+0cvf9rSjliV+ddMGzlrgJBBN8vj+Th54uZFOf5R4Mk2nP0pvMMbaSgevNrj5/rPH+MgFNdiN2vHfSDhtbr/9du65554xn3Po0CGefPJJAoEAd9xxx4y+/3wYGyG8/hzq9IMC9ZUOtjd5iCVSLCsR7XsF4Uzwtz3tABxsn5uEqcFV1yatikWFFjRqCRSJcCJJizs8YnL6gjwTBRZ9di93e///6jUyC/LNBKPJMUdFtnkjuMxaHEYthzsCJFIKNfkmWjwRVpTaiCdTw8ZdVuSZ8EVOFTVtbfSwpsJOPJnGH0mg16joC8WRJbJdLPe0+NhQ7cQdjHF8hL2GfW0+1lc5sBnUtJ36UfD4vk6WFFu5cmXJuD9DQRCEkYRiyWzC9PeeOjbqdX5fm5/1VQ5kScqJW22qcU2qSHOwgbFwBo0KlZw7yzzPrBt373Wwt64p5ZtvWznjM9GFmScC4HOsJxDj/146OeL3djR5WF1uo80THTNYoZJArRo0p3UCAx4b+0JU5RnRqGUOTDDAEUmmqHKZJhQATyujZydO1YYqJylFYWmJdcZmAbV4MpmdY7UUWllmQ6eW2dboGXe27kQMzApfVW5jzxRaCw+0ov/9oFlmADfdv5Vyp5HPv2mJaD8pCGe45CQDGIM7Y2xr9AxLoJIlWFfpQALc4cSEA+CKQjYDfaLWVojWp8L88qlPfYqzzz6br3/961x33XVs3bqVn/3sZ/zsZz8DMm3EP/nJT3LXXXexcOFCqqur+eIXv0hJSQnXXHPN3J78LJAkifoqJ79+/0be/X+v0DoD8w5f7wavI+/6xyEe+/i5SCMNFZtlm5cVcemSQl442s1X/n5wygkOAyOPtGoZm0HDx/6wk2qXiX1tvhE7jCwusrC1wY0swb/2d2LWqrlufTmFVv20Po8wcz796U9z4403jvmcBQsW8Oyzz7Jly5ZhHS7q6+u5/vrreeCBBygqKqKrK7eLxMDXAx01hpovYyOE15cXjvSwq7+Ncb5FR75ZR7lzeFt/QRDmn2UlVq657z8jzoQ93ULxVPZaMsCiV7PAZcqumZwmLbUFZl7or+weus8YTaQnPCayNxjPGbc4EJAZuL+vdhkpsxuIJNPZvdEjQ4JBIxXtbKx20hvMBJFiyTRbG9yZqkuGB3yW9e+7xpKZlnAmrYrKPBPRZIo7Ht6HWpa4fHnxsNcJgiCMRwIi8RTbGt08c3jsznStnnBOZ0qHUcNLx3qpcpnoCYy/r6mWJeqKLaTTmWKd7kCUtKLgjyRp6A3hMmtZWGAhmUqzbZKjiPe2+Xh0dztvW1c2qdcJp58IgM+hP25v4baH944Zr97d4sNl1lLpNKAADqOWDl8UXySBRiVTk29Co5ZpcYcpcxhBybS4XV5iJRxPjTqz2xdJjtpKdyTlTgMt7siYleJDtc/wnJ5Dnf5ZWfzK42xQatUyx2dhrsSeFh8rS23oNTK+SIIj05yZ/tyRHsqdBr581bIZOkNBEOZKYhK9x6tdJhqGXOt3N3uy3T10apkNC5wEIkmOdAWIxFMTPrbNoKHKZUSnVmXbDa2tsKOQ6fQxNBCSb9Hx3xfVTvj4gnA6rF+/nr/85S/ccccdfOUrX6G6upp7772X66+/Pvucz33uc4RCIW6++Wa8Xi/nnnsuTzzxBHr9azeAV5Fn5KEPbeIdP90iguAz6GCHn7/sauOta0/PjXAwlsQ8qOW4Spa4uK6Q5aU2Lvvei3hHGXM0EfFkOrux4BkjWfRAu5815Xb2tHpp7Atz3/PH8UcSfOSiWpwmUQk+H+Tn55OfP7wrxFDf//73ueuuu7Jft7e3s3nzZh566CE2btwIwKZNm/if//kfEokEGk1mBv1TTz3F4sWLR53/PV/HRgivbar+YbiyBJ5QfJxnC4Iwn9Tkm1ngMrFnhopfZlogmqTQqmd9lQN/NAlK7vjGvmAMg1Y1qXvviWroDeM06djR5KEm34RWJWPQqIgkxn6vva1eFhWaMWrVtHrClDuNtHtHTpZs6guxrOTU/PFQPMXBDj9Liq185MIFHOsKcrmYeiYIwiTd/58Gnj3cDYpCNJkmmhh77zMYTVJoM9AdiGHSqlhYmEm8TqXHfp1Bo2JpsYXeYIz9bWN3EvGEYxzunHxM5nh3kM/8aQ+pdJp3rK+Y9OuF00cEwOeIJxTn3qeOTqRYO5P91//vg6uvY8l0zmJw6Gxsl1mLQSMTGediMh6nUTOlWYLtvigry2wzVq1dZNUTiM58IHp7k2eclsGeWWnnDplsIcjM7y206OiaQPbSWNq9UX6/tZkCi47Ny0auwBAEYf4b7+Z1MJdZOywAnlLg1QY3Fp2aJcVW/n0081dkTYV9UiMcFrhM2Wz3+koH3kgiexNs1qlZU2HhWFcQT3+A5c43L8Nm0Ez4+IJwulx55ZVceeWVo35fkiS+8pWv8JWvfOU0ntXcK7Ub+O0HNvLWH7+cnXsoTN/zR3ootRvY1+bjYIcflSRx3qJ8zqnJI888s0FA8yjztgsset6zsZIfPnd8Rt9vNGlFyXZ/iibSPLavgwUFZt61QWwGnEkqKnL/e5nNZgBqamooK8skdbz73e/mzjvv5AMf+AC33XYb+/fv5//9v//H9773vdN+voIwlrpCC9fVl3Ht2jI+8+c9eMMJoomU6JYmCGeIL1y5lAe3tvDwzta5PpURjVUo0+SOsKrMNisB/GqXib399+gnekKc6AmxstSW3V8cTWRIFXq1yzRqQVAwliKWTLGx2ok/mqDNG8EfSdLtj/Krl5t471lifScIwuTsbvHytccOZcfaljoMoz53XYWDlKJwoN2XvdYuL7VlCzO1I7QdX1VmQ6uWURRodofZMYG9z4FuGwtcJtzhOEatatLdf297eB/lTuOcjUETxicC4KfZzmYPH3xgO/5oYsQWgjOpNxhnWYmVxt4QoSlmHTqMGjzhxJgB4rHEphl8H0ynnr2ZCtsaPSwusgxrGwSZzeGpzGKfjAX5Zto805/DmUorfPHR/Vy6pIA3LClElk9/+01BEKZvMtWYYwWtql0m9rSeun55wxMLcKlkiTXldg53nsqU3D7kOhiMJdnacGruuAS8cblIvBGEM02Vy8T33rGab/3r8LjZ0dM2u0vfeeNve9qzsysH/GlHZvP2wkX5mHRqPnJhDctKrNNulR6OJ/GE4hRa9cPmj5WNsakw05KDsvAtejV2o3bGu0EJ84PNZuPJJ5/klltuYd26dbhcLr70pS9x8803z/WpCUKWNxzn1j/t4c43L6WmwMziQgtatUwskRYBcEE4Q6yvcrK2wsG7N1bwf/8+yeP7O+f6lCZFOwt7mGsq7ETiKRKDZk4uLrRkO15MxrbGTNe4tlGCPQfaA0jA6nI7erWKxVUWQrEkDqMWu1F0+BEEYXIe39+RDX4DaGSJNeU2ugIx+oLx7MiFqjwjvmgiJ8loeYk1pytxQ2+IAouO7kGFhHqNalKdiwcMjJ2QJFhabJ1UAHx5qZUiq4FXTvSJAPg8JgLgp9naCge3vbGO2x7ee1re70C7H6NWRVWecUpzAA1aFaUOw6Ta8Q7WHYhmg+jTsazEgkYtI0kTGnE+JWbtyDfChVYdbbO4gbfAZRox8D4dd7xpiQh+C8IZSlEUdGqZjdVOwvEkjX1hIvEkGpWMWiWjkWXMehWFVj2SJLGrefQEnSZ3iFgyc9GUpYkF1tdXOTjRExoW8B7LtkYPHzyvek5m3gqCMH0XLMrngkX5tLjD/G1POw9ua55S9x9hdNUuEypZ4vmjPQA8tq+DN68q4RvXrsConfot2UvHenn6YBcLCy3ccHZVzmbr4RleX45Fq1YhkclxCEQzM9W84QTd/igFYhb4GauqqgplhJuvlStX8u9//3sOzkgQJsYXSeAwalld7qCpN8x/jvfx5auWYjOKTkWCcCZRyRLrKh0sKlzJ+Yvy+eGzx5EkWFfp4LnD3Zn24/NUt39yVYQjWVfpoLN/DKZKljjZE8QXSbLAZQIySelHuqa+3kuNscFq1qlYUmzNFkNVu0y8YWkR16wppbr//QVBECYikUrzgXOr+e2WpmyRZmNfmMa+zPfXVtiz3SbzLbqcIsxCq44md25MS5akGUkyWl1u70+QTHG8Ozih8WGf3byY7z9zjNoCM3/+8NlEEyk+/uBuFEURe6LzlAiAz4Hr6stBgdseGXv+90xZVmKddAWzTi2xsszOtkbPpFs/DOYJJ1hRap12ALzZHZmV+d+55uYiNRtZobf8bif/d0N9Zi68IAhnlJ5gLLvwGyyZTkN/Vw13OHckxmh8kVPXzWKbPpvdXV/poM0bocOXe33Xa2S2N3qmVKR5qOP0BVoEQZgd5U4jt1xUi1mn5st/OzDXp3P6zOKNqkYlsabCwY4mD6l07tX1b3vaeWJ/J7UFZjYucLKu0sFFiwswjdLWfCRLiq1Uu0zU5JuzyY+ptMJ3njzCr15unMmPMqa9rT4WF1myQfdIIsVvX21ia4Ob2kIz33n7KlF1KQjCafPUwS5CsQRGrSqTTJpI8fKJPt64oliM6xGEM5BFr+FdGyq4cHE+sUSaKpeJl0/08qW/HhizFflcavdGUctSTsXjZNgMGg61+wgn0tQVWYgmUtnCpkQqTZs3wuBD1xVZMOnUqCQJXyTO0a7gmPf1Zp2Kfa1e8i1aqvJMNPSG6AvGs6+pzbfkBKF2Nnto9UT4f88c4xOXLGR1uY2zFuRhmEYipyAIr33xZJr3/uJVdrV4iSdHLrCUJYkN1U72tfnY1ujJjm8069SYtOphY38TaYVWT4S6IgsWvZp2X3RSt/RrKuyEY0l294+TGNDpj3LVqmIuX1aMWiXR3H/NHXzssxbksbHaSbXLhF6jQq9R8ZY1Jexs9rKu0jHxkxBOG/FXao5ct76cMoeB2x7ZO6sVNhurndn2D2oZRrnO5FhRauVIV3BKLc9HMsXi8RzlDgMHpxBcKbHr6fbHJrTgTCsjn2h4iu3jJ8qin/lfw8OdATZ/70V+eeN6Ni7Im/HjC4Iwexp6QuM/aQocRi1t3ig2g4ZdzR7WVTmHBcBXldkn3TJIo5IosunZ2uAWGY+C8BrhNGlY4DJxsnd2rkfzjXqWuuYsLrT0j4sY/boaT6U52OHnYIef+//TSKndwHvOqkSjkvBFEtgMGvItOmryzSwttg7r8FPuPJXsmEorPH2oi+89dXTWqr8XF1pocoeIDhlzlEorqGQJvVom2n/DoShwpCtAhy/CL//TQLnDSLnTyKoym/hbIQjCrOnwRXjPWZVctrSQUoeRHzx7HKNG5vkj3cQSKRABcEE4YxXbTo13ObvGxT8+di5/2tHK/3v6GL3B2BivnB16jTxsTZQlTa/MptJpzM71Hrqu6w3GqK9ysq3BzboqB429IWLJVM7zBgJDsiQRiifxRxLZJPr6Kgdd/ijBaBJvOEHEkkKnVrG63I4sS/jCcTr8uXvViZSS7Y75xP5O3l5fJoLfgiCMS6uWeffGijH3Grc3eTDrVOjUMmpZYlezl43Vme6UY+1JDL7mOQyaCXUOtujVHGjzER9hNLE7FEcjy1yxsnj8DzbIilIbj+3tFAHweUr8pZpDZ9e6uPPNy3j/r7bP2nuc7A1Rk2+iwxfFpFOjlqWcgEeBRUeBRYdJp0ZRFEKxJG3e6KgZOVMRT6WzLRGn6nh3kBWlVtzhBMVWPYFoAqtBQ4s7QueQtkIb+tsGS8C+Nv+E55fvavGxvspBMJZEr1HhjyRwmrQzlggwGmmWKs9D8RTv/eVWfvdfG1lf5ZyV9xAEYebNVtKNSadGljLzdPa0+kgrClV5RvqCcQKxZE7C1ETpNTKPfOQclhRbONETFAENQTjDJVJp3ME4Tx/set0Ev2HmR5NrZIk1lQ62Nbon3e2pzRvhnicOj/i977x9FdeuK8t5LJFK87fd7fznRC8vHu2hNxif6mmPa0O1k0QyjUWnYVWZiUg8BVIm+N3lz9w/REe4h/BHk3zziSO4zDp6gzGu31iBy6xjZZmNc2pdojJcEIQZVWwz4A3GaXaH0apldrV4CSfSrC220hOMibEMgvAaoteoeO9ZlayrcHCow88Pnj02pfGPE3XeQhdvW1fG04e6cRo1fO7yOj746+28fKJv2HN1ahmXWTfl8+kLx7HoVARip/YH6isddAdi+CIJdjV5uGBRfna8ztA14NCg+YZqB3ajlsbeENuH7HPub/cDmXVotStTDT6Wi+oKsIpkIkEQJujq1aX0BuPc88ThUWNOlXkmNCqZeDJFizvM1kbPpO6l97f72VDtzCafq2SJtKIMO8biQsuYIx+nsq/piyTY1+ad9OuE02Pmey/PgG984xtIksQnP/lJANxuNx/72MdYvHgxBoOBiooKPv7xj+Pz+eb2RGfAxXWFfPe6VbjM2lk5fk8gxomeEOF4ip5AjL5QnIUFZiSgJt9EdyDG/nY/rza42dro4UBHABSwz9BsrPpKB8e7x267MxHxlMK+Nj/uYIztTR6OdAXZ2+qj2mViWYk1W7njNGnZ1uBmf5uffW2ZBZyiZDbsqvKGtwNfVmKl1HEqg3Rbo4dDHQF2NXtp6gvPevAbYFuTm1K7YfwnTkE8mea6n24Zs/JIEIT5ZbZmE7b7Mjeze1ozfzu3N3po7AvjsmgptOqmNDvsIxfUsrTEiiRJ1BZYZvqUBUGYZeF4MjvfN51WiCZSaNUyJ3vDmLSvn6BkcibaFfWrdBoodRj6u2LM2GGBzHp2KI1K5lh3kEd2ts1q8Ht1uZ29LV52tXjpCcZ4tcHN3jYfe1t9HGj30xuMc2ycFqQDlVm/e7WZF4728PShLvzR6Y1JEgRBGModivHv41209YXpC8ZYWWrFblCzs9nLL15q4D/He+f6FAVBmGFLS6xcu66M+65fy9Ji64yvY+srHXx282J+/f4NXL26lB+8aw13Xr0ck07NN966csRuQg6TFr1GxbpKx4TKXsw6FRXOU3uDbZ4IFXkmNlQ7WFhgZkWplWPdAZrdYRYXWUikFULxiY+K3N7oIRJPjTs3vaE3xMYR1pyDXbKkAKteBMAFQZi4D5xbzZOfPJ+VZbYRvx9NpNjd4iWaSCNLEmdVO6nJN03qPQ60+VhabMWoVVFk1VOTb6JyUDxIJUuk0mPf+x/rDvDTF07wyM5Wjk1wn3R1uYOfv69+UucqnD7zrgJ827Zt/PSnP2XlypXZx9rb22lvb+fb3/42S5cupampiQ9/+MO0t7fz5z//eQ7Pdma8dW0Zm5cV8YuXGvj5v0+OO+t6YaGZY13DN5gkMgFdvUaFAvQFY8MyDWvzTThNWgwa1bDK6QGxZArDDC0Wo8mZrWSMDGotZNCq2HLyVJZlpdOARa/BHcrd/BvI6tHIEvWVDrY3edCpZVaU2bJZjxa9mtoCM7sGzd1NKQpOowb3NOeXj0ctS8NmPZ5dk8d5C/M51OHnif2dxKexMaso8I6fbeGNy4v41ttWTWqupCAIp5/DODsJUaON27DqNTT0Tj4rvdRu4ObzF0z3tARBmEPv+vmrJFNpql0mvnHtSix6DS8f7yXfomVfW4oCi45iu4E9Q2ZjTZXDpKU7cPrbU44nmpiZ9er6Kgd7Wn0z2klpsAdebuQLVy4d9vhnNy/mpeM97O9P/pwNKlkasbp7olxmLRfXZeab72/z0e6NsqfViyeU4LOXL8asU1MoqjIFQZim3mCMPJOWaFLBF0typCtIbzCON5JkcaGFJUVW6opE0qYgvFYtK7Hx2MfP5cVjvfzh1WaeP9o9eovyfi6zjvMXuvjn/o5hz5UleN+mKv73zctGfb0/muDrb13BrmYvl9QV8MCWRgLRJPvafKwqs7GjyTNutzWDRmZJsbW/G1zmvl2nlgnFkhzp9KNVyYQHndvWBjf1lQ5Mk2hBnlYmPoIx0X9/MLQSXJLgsqWFFIk1m3Aa3HfffXzrW9+is7OTVatW8YMf/IANGzbM9WkJ01DlMvGX/z6Hx/d38OiuNva3+en0R7HoVHj64y8Dnei2nHRj0qrYUO2kJxAbtzMFZLrhHu3yk2fSZUc2LCw0Z0d1Fdn07GoZu6B2b2smyRsyrc3//rFzx31f1SyNVBNmxryKhAWDQa6//np+/vOfc9ddd2UfX758OQ8//HD265qaGr72ta/xnve8h2QyiVo9rz7GlJh0aj5+yUI+eN4CnjjQwUvH+nh0dxuylJmzMmCgnXe1y4RVr0ZCIpJIYjNqONkTyratGWDRq6l2mdCqZPzRxITmaOvUqgnNzJ6IVs/szTf3hhMUWHTZjdQmd4SBheJIEmmF7U0eVpXZaOjLbfkTiCbZ1ezNaZWhKFDtMuEeFBSfaWadmn987FyqXCYOtPvYcqKPcDzFhy+oQavONGg42RPkAw9sn9CFfjSKAv/c10k0keYXN9SLNsWCMI/ZT3MrsaHzZCfCqlfz0/eum7FkKUEQ5sZ33r6KG365lUKrPlsps7DQwvJSO2pZojrfTENPiDyTFnc4Pu2K5lKHAaNWRasnzCzFiKckGJteALzaZUKjkma9c1AsmSaaSBFLpLPdQiLxTOJqhdM4qwHwXc2ZNfRAF5HJetOKYg53Btje6GbwbUZjX4hLvvMCBo2Kz12+mJvOqZ6hMxYE4fXIZdaRTqfRqWSiqRQNg/ZIjnQFeHR3G+85q3KOz1IQhNkkSRIXLMrngkX5vHqyj1ZPhFKHgfv/04AnlGBxkYULF+fzz32dtHjCPHDTBgxaFR+/ZCEneoJoVDJf/cdBVLLEVatKuOWi2jHfb3mpjeWlNq6rLwdgaYmFs7/xHAA7+/cTvZEES4otHOsKjLgGXlhgYVujB5NWxbpKO8m0wvGuIJ3+KKvLHSO2693e5KG2YOLVkeMF4XVqmZVlNiTgaHeQRQWWYfuQn3/jEt61sQKzKKwRZtlDDz3Erbfeyk9+8hM2btzIvffey+bNmzly5AgFBQVzfXrCNKhkiStXlnDlyhJeOdnHFx7dj0mnYs8IgelQPMXWBjeyBGUOA+3eCOOFrJJp6BqUdH+sK0iF00CxzTDu2EeDRkVNgYmLFhewotTGf473oiiKiKOc4ebVX6xbbrmFK664gksvvTQnAD4Sn8+H1WodNfgdi8WIxU79n93vn70NoZlk0Kp4y5oy3rKmjG+/fSWptMK3njzCkQ4/wViKw/0B7IkGQwPRZDZrZaLKHAYOdc7Mz6s6z8iu8Oy1qi+xGSZdSTTWxt3WBjfrqxwAnOwJsa/dz9oKO/Fkmg5fFHcoPmNzIi9anM9Xrl5OuTPTimNZiY1lJcPbgCzIN/Orm9bz1h+9TF9oeq0tnz3czUPbWnjnhoppHUc4c8RiMTZu3MiePXvYtWsXq1evnutTEsZhNWhQy9KMJSKNZ7KJShadmt98YCPLS0duWyQIwpmjtsDM7z+4kff9civvWF/OokIL+RYdn7p0IeF4kj9sbWZHo4cKpzG7BtGopJzkzMkY6LRT1j9+ZjYTJSfDG57a+koC6qsc7GjyjHsjPhMSqTQ/eu44WxvdvGVNKe9YX5FNRHr7unL+ua9z1t47rYA7FKfaZSKdVmhyn+ocopElVpbb6QlEaR6l28ivtzSN+PjAfMpIIjXpexZBEISh/NEEf9reQo8vQkWekQe3t9EzaL/gC1csFQmcgvA6snFBHhv7//2sBXk53zvU4eeON9VlrwlVLhNVrkxA+albL5jye5bYjfz+gxv5+B92Z8e/HOlf7wwuuhlQatf3V0CqMWhVHGj3U2o3EEukSCmMOatWp1YhSUwoSfXoOK18V5Xb2Npw6r2OdwdYU2FHo5Jp6A1h0qp4/7nVotJROC2++93v8sEPfpCbbroJgJ/85Cc89thj/PKXv+T222+f47MTZspZC/J4y5pSvv/MUYxaVX8XDDi31kUgmsjGcNJKZu9geYmVZnd43FEOQzW7IyRTCha9eszOy5cvL+J771id/fqyZUWT/1DCvDNvAuAPPvggO3fuZNu2beM+t7e3l69+9avcfPPNoz7n7rvv5s4775zJUzztJElCrZK4441L2Nfq46ofvjTr76lXy7R6I1Pe2BxKo57dm0udZubH2A+t3tk5qAJckqDKaSSRShOIJZElCe84LdJlKTM3cWezl4vrCljgMrG6ws5Fiwsm3I68Ms/EgzefxS2/38nREdrfj+SsBU7esb6cTl+MZw93kUorxFNpDrSfGckgwsz43Oc+R0lJCXv27JnrUxEmSCVLXLi4gKcPdc36e6llCadRk7MxOJ67r13BqnL77J2UIAinVWWeid+8fyOP7++gzGHAqFUjSRImnYbzFubjMOroCUZpcoepzDNyrCtIIjW5G86hWj0RFhaYp1VRPJP80SRqmUlXpZt0qlmv+h7swW0t3LCpkgdv3jTse+fUulhTYc8Z5zPTWjwRZAmKbLltL9UqCZUMnmkkampUErLIrBcEYZpeONLNb19potMX423rSnMSrVSyRL5ldkYNCYJw5vnoxQtn7dhn17godxqyAfABhzr8lNkNtHpPXZtcFh17WnysLrezu3/s0Ime8YueyhwGTFo1NoNm3H1JyCS+jrZurcozEorlru/d4US2I6ZOLfOjd68VwW/htIjH4+zYsYM77rgj+5gsy1x66aVs2bJlDs9MmA23XFTLh85fwL42H1tO9hFNpLlqZTELCy187bGD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7OCWu66xY7zWBx98AA6H0wGtbD5Xju/w4cOYNGkSJkyYgISEBBw7dgyLFy8Gl9s1vi6uHOO8efOQmpqKbdu24cyZM5gxYwZmz56NkydPdmDLCXEdfc6bLzg4GG+99RYSExNx/PhxjBs3DtOmTcPZs2cBAE8++SR+/fVXbNiwAX/99Rdyc3MxY8aMDm5159DQa+cO5wCk9RiNRsyaNQsPP/xwg9utXr0aeXl5tn/XXqSkp6djypQpGDt2LJKSkvDEE0/gvvvuw86dO9u49c41dkyJiYnw9fXF999/j7Nnz+KFF17A0qVL8fHHHztsm5qaanfcvr6+bd18pxo7JovFgilTpsBoNOLQoUNYu3Yt1qxZg2XLltm26WzvU13Dhw+3e63z8vJw3333ISIiAoMHD7bbdvfu3XbbxcbGdlCrXfPqq6/atffRRx+1rdNqtZgwYQLCwsKQmJiIlStX4pVXXsGXX37ZgS0mnZE7xrZa10OMq+XOsa4WxTzS1Rw7dszuM7tr1y4AwKxZs2zb3H///XbbdKWOGzqdDv3798cnn3zidP0777yD//73v/j8889x9OhRyGQyTJw4EXq93rbNnXfeibNnz2LXrl347bffcODAATzwwAPtdQhN0tDxVlVV4cSJE3jppZdw4sQJbN68Gampqbj11lsdtm0olnUmjb2/ADBp0iS7Y/nxxx/t1nel95eQlrrllltgNpuxd+9eJCYmon///rjllltsHUJdOe8kzbNp0ybcfffduOeee3Dq1Cn8888/uOOOO2zrr/vXnpFmKywsZADYX3/9Ve82P//8MxMKhcxkMrVjy1pPfcd48uRJFhQUxPLy8hgAtmXLlo5pYAs5O764uDj24osvdmCrWpezY5TJZOy7776z287T05N99dVX7d08QloFfc5bRq1Ws6+//pqVl5czgUDANmzYYFuXkpLCALDDhw93YAs7r9rXzpmufg5AWm716tVMpVI5XdfY+dP//d//sd69e9stmzNnDps4cWIrtrDpGjqmuh555BE2duxY29/79u1jAFhZWVnbNK6Z6jum33//nXG5XJafn29b9tlnnzGlUskMBgNjrPO+T/UxGo3Mx8eHvfrqq7Zl6enpDAA7efJkxzWsicLCwtiqVavqXf/pp58ytVpte58YY+y5555jMTEx7dA60hW5Y2yrdT3FuFruEutqUcwj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Bw+GTCaDQqHAzJkzcfDgwU58Y4QQctqCBQswadIkAMA111wDhmEwefJkLFiwADKZDAUFBbjkkksgl8txww03AAh9bNd0jYqKCsyePRsymQxRUVFYsmQJ3G6337kejwevvfYaBg8eDJFIhKioKMyYMQN79uzxO+/jjz/GiBEjIBaLodFocP3116OsrKwLvyFCCAneVzaN85pjGAaLFi3Cd999h0GDBvnGp+vXr2/zPt9//z0uvfRSxMfHQygUIiMjA88++2yLPnPy5MkYNGhQm2NYACgvL8fs2bMhlUoRHR2N+++/v8XzPiGEdMTWrVsxcuRIiEQiZGRk4J133gnYL4Yyfmvq1/bu3YuJEydCIpHg8ccf9z2L/+c//8Ebb7yB9PR0SCQSTJs2DWVlZWBZFs8++ywSExMhFotxxRVXQKvV+l07nH2ryWSCVCrFvffe2+L7KC8vB5fLxfLlyzv71ZIuQCnQSZtqamowZswY32AuKioK69atwy233AKDwYD77ruvXddbunQpli9fjltvvRU5OTkwGAzYs2cP9u3bh4svvhgA8Ntvv6GwsBALFy5EbGwsjh49infffRdHjx7Fjh07WnSoTa677jrcdNNN2L17t2/iEwBKSkqwY8cOvPzyy75jb731FgYOHIjLL78cPB4PP/74I+6++254PB7885//9J331FNP4bnnnsMll1yCSy65BPv27cO0adPgcDhafE/jxo2DxWLB4sWLERERgTVr1uDyyy/H119/jSuvvNLv/GeffRYCgQBLliyB3W6n1MGEEACh9bnvvfceFi9ejKuvvtoXTDl06BB27tyJf/zjH7jqqqtw8uRJfPbZZ1ixYgUiIyMBAFFRUQCAW2+9FWvWrMHVV1+NBx98EDt37sTy5ctx/PhxrF271q89+fn5uPrqq3HLLbdg/vz5+PDDD7FgwQKMGDECAwcODPo5vvrqK1gsFtx1112IiIjArl27sHLlSpSXl+Orr77qui+QEHLOa6ufnDt3Lp555hk89dRTuP322zFhwgQAwLhx43zXaGxsxIwZM3DVVVfh2muvxddff41HHnkEgwcPxsyZM4Pee+PGjZg5cybS09OxdOlSWK1WrFy5EhdccAH27duH1NRUv/OvvfZapKamYvny5dixYwdef/11NDY2tlhI1FxhYSG+++47XHPNNUhLS0NNTQ3eeecd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3n77bcjlckilUowePdpvN3ZHvPzyy5g5cybGjh2LW265BVarFStXroRSqcTSpUtbnF9UVITLL78cM2bMwPbt2/Hxxx/jH//4B4YMGRL0HpdddhmeeeYZLFy4EOPGjcPhw4fxySef+GUjIoSQ7tQVY7spU6Zg3rx5eP3115GXl+crd7Zt2zZMmTIFixYtQkZGBp577jk89thjKC4uxuzZsyGXy1FUVIS1a9fi9ttvx5IlS8L4SQkhpHuNGzcOarUa8+fPx+LFi8EwDP73v/91KqX5bbfdhv/+97+46aabsHfvXsTFxeF///sfJBJJGFtOCDkfLV26FBs2bMAFF1yAu+66C263G//9738xaNAgHDhwAAB6xfitK/rWJv/4xz/w8MMPY+3atbjrrrvA5/PD0GLSVSgATtoUExODXbt24ZlnnsG3336LN998ExERERg4cCBefPHFdl9v8eLF+OGHH7BhwwbY7XakpKTgueeew0MPPeQ759NPP8U999yDN954AyzLYtq0aVi3bp1fGvPWiEQiXH755fjkk08wdepUREdH+/08KysLX3/9NZ544gksWbIEsbGxuOuuuxAVFYWbb77Z79znnnsOIpEIb7/9tm+ydcOGDS12ScbExODvv//GI488gpUrV8JmsyE7Oxs//vhjWHZUEkLOD6H0uXfccQc++eQTvPLKKzCZTEhMTMTixYvxxBNP+K4zatQoPPvss3j77bexfv16eDweFBUVQSqV4v3330d6ejpWr16NtWvXIjY2Fo899hiefvrpsHwGPp+PH3/8EYsXL8by5cshEolw5ZVXYtGiRa0GfQghJBSh9JN8Ph9r1qzBY489hjvvvBMulwurVq3qdAB86tSpWL9+PZ5++mk89dRT4PP5mDRpEl588cWA1/7iiy/w1FNP4dFHHwWPx8OiRYvw8ssvt3qPxx9/HGazGZ9++im++OILDB8+HD///DMeffTRTrWdEEI6qqvGdqtWrUJ2djY++OADPPTQQ1AqlRg5ciTGjRvnO+fRRx9F3759sWLFCt9u8aSkJEybNg2XX355pz8bIYT0pIiICPz000948MEH8cQTT0CtVuPGG2/ERRddhOnTp3fomhKJBJs2bcI999yDlStXQiKR4IYbbsDMmTMxY8aMMH8CQsj5ZMSIEVi3bh2WLFmCJ598EklJSXjmmWdw/PhxXxlY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zJgxEAqFSEtLw2OPPQan0xn0Omlpabjwwgvx448/Ij8/HyKRCBkZGXj77bc7vefx48exaNEiiMViJCUl4emnnw6Z8aLj/Pbc97rxxhsDt9vrnH3//fe46667oNPpkJSUBCC8OTEAuN1urF+/HllZWRCJRIiJicHcuXOxefPmXvQmIWQ0C1Vz8euvv8b8+fMhl8uhUCgwY8aMTufDu3fvxvLly6FUKiGRSDB//nz89NNPPb7fp59+ipUrV0Kv10MoFGLMmDH47W9/C6/XG3TcggULkJubixMnTmDhwoWQSCRITEzEM8880+k1q6urcemll0IqlUKn0+GBBx7oNN4TQshg6ji2DsScs2MNcJfLhSeeeALTpk2DUqmEVCrFvHnz8N133w3UxySEjFKDMcYBwEsvvYScnBwIhULo9XrcfffdMBqNQcf0Zs7odDrx5JNPIjMzE0KhEMnJyfjVr37Vad64efNmzJ07FyqVCjKZDNnZ2XjssccCj4eKd1G8Z/igHeAkbAcPHsTy5cuRkJCA9evXw+v14qmnnoJWq+3T6+3duxc7duzA1VdfjaSkJJSXl2Pjxo1YsGABTpw4AYlEgvPOOw/33nsvnn/+eTz22GMYP348AAT+fuedd7BmzRosW7YMf/zjH2Gz2bBx40bMnTsXBw8eDArMeL1erFixAueddx6eeeYZ/Otf/8I999wDqVSKX//617juuuuwatUqvPzyy/jZz36GWbNmIT09HQBQWlqKTz75BFdeeSXS09PR0NCAV155BfPnz8eJEyeg1+u7/JybN29GaWkpbrrpJsTHx+P48eN49dVXcfz4cezatSuweIAQQvpj9erVSE9Px4YNG3DgwAH84x//gE6nwx//+EcAwMaNG5GTk4OLL74YPB4Pn3/+Oe666y74fD7cfffdIV9z/PjxeOqpp/DEE0/g9ttvx7x58wAAs2fPHrTPRQghPY1vt956K9566y1cccUVePDBB7F7925s2LABJ0+exMcffxz0WsXFxbjiiitwyy23YM2aNfjnP/+JG2+8EdOmTUNOTg4AoL6+HgsXLoTH48EjjzwCqVSKV199FWKxuN+f5a677oJWq8UTTzwBq9UKILw5MQCsW7cOGzZswK233or8/HyYTCbs27cPBw4cwPnnn9/vthFCRp8333wTN998M3JycvDoo49CpVLh4MGD+Oabb3DttdcCALZu3YoVK1Zg2rRpePLJJ8HhcAILK7dv3478/PxuX18mk2Ht2rWQyWTYunUrnnjiCZhMJvzpT38KOra1tRXLly/HqlWrsHr1avzf//0fHn74YUycOBErVqwAANjtdixevBiVlZW49957odfr8c4772Dr1q0D10mEENIHAz3nNJlM+Mc//oFrrrkGt912G8xmM15//XUsW7YMe/bs6VS+jBBCIinSY9y6deuwfv16LFmyBHfeeScKCwuxceNG7N27Fz/99FNQBspw5ow+nw8XX3wxfvzxR9x+++0YP348jh49imeffRanT5/GJ598AsAfoL/wwguRl5eHp556CkKhEMXFxT0u9KR4zzDCEhKmiy66iJVIJGxNTU3gvqKiIpbH47HtP0plZWUsAPaNN97o9HwA7JNPPhm4bbPZOh2zc+dOFgD79ttvB+7797//zQJgv/vuu6BjzWYzq1Kp2Ntuuy3o/vr6elapVAbdv2bNGhYA+/vf/z5wX2trKysWi1mGYdhNmzYF7j916lSntjocDtbr9Qa9T1lZGSsUCtmnnnoq6L6Onz/U53z//fdZAOwPP/zQ6TFCCOmNJ598kgXA3nzzzUH3X3bZZWxMTEzgdqixaNmyZWxGRkbQffPnz2fnz58fuL13794ux/U1a9awqamp/Wo/IYR0JZzx7dChQywA9tZbbw065qGHHmIBsFu3bg3cl5qa2mn+1djYyAqFQvbBBx8M3Hf//fezANjdu3cHHadUKlkAbFlZWeD+jnPGc99rzZo1gdtvvPEGC4CdO3cu6/F4go4Nd048adIkduXKlZ2OJYSQcLWPRWVlZazRaGTlcjlbUFDA2u32oON8Pl/g76ysLHbZsmWB+1jWP26lp6ez559/fsjXPve4jn7+85+zEomEdTgcgfvmz5/facxzOp1sfHw8e/nllwfue+6551gA7Icffhi4z2q1spmZmSGvGRBCyGDoOP4NxJyz43m6x+NhnU5nUDtaW1vZuLi4TnNnQgjpj4Ee4xobG1mBQMAuXbo0KP7ywgsvsADYf/7zn4H7wp0zvvPOOyyHw2G3b98e9FlefvllFgD7008/sSzLss8++ywLgG1qaury81O8Z3ijFOgkLF6vF1u2bMGll14atNs5MzMzsLKmt85d7eN2u9HS0oLMzEyoVCocOHCgx+dv3rwZRqMR11xz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jRs3cvHFF5OcnExFRQUvv/wyCQkJTJ8+vcVri3hP/yIC4EKHZWRk8M033/CHP/yBRx55hMTERB5//HEOHTpEVlZW8LxHH32UyspKVqxYwUcffcS8efP45ptviIqKanK9//u//0Mmk/Hee+/hdDqZNm0a33//PXPnzm1yXkxMDEuXLmXJkiXcdttt+Hw+1q1bR1RUFL/85S+Ji4vj6aef5tlnn8XlchEfH88555zDrbfe2m2f/eGHH6a+vp7ly5fz4YcfMm7cOFatWsWf/vSndl+7fPly7rnnHl566SUCgQAXXHAB33zzDXFxcd3WPkEQhLYMGTKEFStW8Je//IU//OEPxMTE8Nvf/pbIyEgWLFjQ5msVCgVvvfUWixYt4s4778Tr9bJs2TIRABcEoc94/fXXSU1N5c0332TlypXExMSwaNGiLqeAjI2NZd26ddxzzz08/fTThIeHc+eddxIXF8dtt93W5Nw77riD3Nxc3njjDVavXs0555zDd999x3nnndfh9+vomPjee+/liy++YM2aNbhcLpKTk3niiSd48MEHu/Q5BUEQbrvtNqKionj66af529/+hkKhYOjQoTzwwAPBc2bNmsWWLVv429/+xosvvojNZiMmJoZJkybxm9/8ptVrh4eH89VXX/H73/+ev/zlL4SFhXHTTTdx3nnnNevfOkqr1bJ27VruueceXnjhBbRaLTfeeCPz5s3jwgsv7NI1BUEQektnxpwnu+WWWygrK+PVV1/l22+/JT09nXfffZePP/6Y9evXn54PIAiC0IbO9HGPPfYYkZGRvPjiizzwwAOYTCZ+/etf89RTT6FQKDr93lKplM8++4znn3+et99+m5UrV6LVaklNTeW+++5j8ODBAFx22WXk5eXx3//+l6qqKiIiIpg5cyaLFy/GaDS2en0R7+k/JIHTUZleOKNdccUVHDhwQNQ5EARBEARBEARBEARBEARBEARBEAShV4ka4EKnOByOJo+PHDnC119/zaxZs3qnQYIgCIIgCIIgCIIgCIIgCIIgCIIgCMeJHeBCp8TGxnLLLbeQmppKfn4+r7zyCi6Xi127djFo0KDebp4gCIIgCIIgCIIgCIIgCIIgCIIgCGcxUQNc6JQLL7yQ999/n7KyMlQqFVOmTOGpp54SwW9BEARBEARBEARBEARBEARBEARBEHpdn0iBvnHjRi69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hk8++QQVFRUW6wsLC5t1XGvPUZVKZYuCLvfffz9OnDiBU6dOmbVv06ZNZtuVlpZanLfbs9spDToh5LbG3PO2JCZ0W2OPMW7cOOh0OrPnpUajEV988YXFMcPCwnD16lWzPvr8+fM4evSoxWtTTKjjoxngxO4efPBBbNu2DZMnT8YDDzyA1NRUfPXVV4iKirJ6gVh33++++w5yuRxRUVE4fvw49u3bB3d3d6vbz5w5E//5z39w4MABfPjhh2brysvLERAQgEceeQR9+vSBVCrFvn37cPr0abMR5XU98MADWLFiBe677z488cQTKCgowBdffIHu3bvjwoULTT8hhBDSTDNmzMDPP/+MefPm4cCBAxg6dCgMBgOuXr2Kn3/+GXv27MGAAQOwf/9+fPnll1iyZAn69+8PoGaE4siRI/Hmm2/io48+snp8LpeL1atXY8KECejbty9mz54NX19fXL16FZcuXcKePXsA1KR4Gz9+POLi4jB37lxUV1fj888/h1wux9KlS9vrdBBCCADgmWeewZo1a/DUU08hISEBISEh2Lp1K44ePYpVq1bBxcWlwWM0tl/74IMP8Ndff2HEiBF45pln0LNnT+Tm5mLLli04cuQIFAoFXnvtNWzduhWPPvoo5syZg9jYWJSUlOC3337DV199hT59+rRKmwkhpCmeeOIJ/POf/8T27dvx3HPPQSAQmK1/8MEH8c4772D27Nm46667kJSUhE2bNqFbt252anHTnwcQQkhYWBjee+89LF68GGlpaXjooYfg4uKC1NRUbN++Hc888wxeffVVADUB7J9++gmLFi3CwIEDIZVKMWHChEa/FpfLxdq1azF+/HhER0dj9uzZ8Pf3R3Z2Ng4cOACZTIadO3c2+T2MHTsWQqEQEyZMwLPPPouKigp888038PLyQm5ubpOPBwD//Oc/8d133+G+++7DSy+9BGdnZ3z99demrES3bdy4EV9++SUmT56MsLAwlJeX45tvvoFMJqPB7oQQk8bc87YkJnRbY4/x0EMPYdCgQXjllVeQkpKCHj164LfffkNJSQkA84wfc+bMwYoVKzBu3DjMnTsXBQUF+OqrrxAdHQ2VSmXajmJCnQMFwIndPfXUU8jLy8OaNWuwZ88eREVF4fvvv8eWLVtw8OBBm/t+9tln4PF42LRpE9RqNYYOHYp9+/Zh3LhxVrePjY1FdHQ0rly5gunTp5utc3Jywvz58/HXX39h27ZtMBqN6N69O7788ks899xz9bZh1KhRWLduHZYvX46FCxciNDQUH374IdLS0qizI4S0Ky6Xix07dmDlypX49ttvsX37djg5OaFbt2546aWXEBERgfLycsyZMwf9+vXD//3f/5n2HTZsGF566SV8+umnePjhhzFkyBCrrzFu3DgcOHAAb7/9Nj799FMYjUaEhYXh6aefNm0zZswY/Pnnn1iyZAneeustCAQCjBgxAh9++CFCQ0Pb/DwQQkhtEokEBw8exBtvvIGNGzdCpVIhMjIS69evx1NPPdWoYzS2X/P398fJkyfx5ptvYtOmTVCpVPD398f48eNNqdakUikOHz6MJUuWYPv27di4cSO8vLwwevRoBAQEtFqbCSGkKby9vTF27Fj88ccfVkuF/etf/0JlZSU2b96Mn376Cf3798euXbvwxhtv2KG1NZr6PIAQQgDgjTfeQEREBFauXIm3334bABAYGIixY8di4sSJpu3mz5+PxMRErF+/HitXrkRwcHCTAuAAMHLkSBw/fhzvvvsu/vvf/6KiogI+Pj4YPHgwnn322Wa1PzIyElu3bsW///1vvPrqq/Dx8cFzzz0HT09PzJkzp1nH9PX1xYEDB/DCCy9g+fLlcHd3x7x58+Dn54e5c+eathsxYgROnTqFH3/8Efn5+ZDL5Rg0aBA2bdpE9/qEEJPG3PO2JCZ0W2OPwePxsGvXLrz00kvYuHEjuFwuJk+ejCVLlmDo0KEQi8WmbXv27Ilvv/0Wb731FhYtWoSoqCh899132Lx5s9kxKSbUOXBYSyrVE9IJ9evXD25ubvj777/t3RRCCCGEEEIIIaRDmDx5MpKSkqzWQySEEEIIIcSR7NixA5MnT8aRI0cwdOhQezeHtAGqAU66lDNnziAxMREzZ860d1MIIYQQQgghhJAOITc3F7t27bI6+5sQQgghhJDOrLq62ux3g8GAzz//HDKZzFQekjgeSoFOuoSLFy8iISEBn376KXx9ffHYY4/Zu0mEEEIIIYQQQohdpaam4ujRo1i7di0EAkGzU/ISQgghhBDSUb3wwguorq5GXFwcNBoNtm3bhmPHjuGDDz6ARCKxd/NIG6EAOOkStm7dinfeeQeRkZH44YcfzOo6EEIIIYQQQgghXVF8fDxmz56NoKAgbNy4ET4+PvZuEiGEEEIIIa1q1KhR+PTTT/H7779DrVaje/fu+Pzzz/H888/bu2mkDVENcEIIIYQQQgghhBBCCCGEEEIIIQ6BaoATQgghhBBCCCGEEEIIIYQQQghxCBQAJ4QQQgghhBBCCCGEEEIIIYQQ4hC6TA1wo9GInJwcuLi4gMPh2Ls5hJAWYIyhvLwcfn5+4HJpHE9boD6TEMdBfWbboz6TEMdC/Wbboj6TEMdCfWbboj6TEMdCfWbboj6TEMfS0j6zywTAc3JyEBgYaO9mEEJaUWZmJgICAuzdDIdEfSYhjof6zLZDfSYhjon6zbZBfSYhjon6zLZBfSYhjon6zLZBfSYhjqm5fWaXCYC7uLgAqDlRMpnMzq0hhLSESqVCYGCg6XtNWh/1mYQ4Duoz2x71mYQ4Fuo32xb1mYQ4Fuoz2xb1mYQ4Fuoz2xb1mYQ4lpb2mV0mAH475YVMJqPOjxAHQals2g71mYQ4Huoz2w71mYQ4Juo32wb1mYQ4Juoz2wb1mYQ4Juoz2wb1mYQ4pub2mVRoghBCCCGEEEIIIYQQQgghhBBCiEOgADghhJAuzWBkKK7QIKWgAqfTSvDXpTz8fDoTa+JvIE+ptnfzCCGEOLBKjR67LuTauxmEENIudp7PgUZvsHczCCGENKCkUotfErKQVVpl76YQQkiHVa01oEqrh1pnwOHrhVDrDGCM2btZpJYukwKdEEIIYYxh6W+XcCFbidJKLUqrdFBW66xuGxvsCh+5GPf08IJMLGjnlhJCCHFkXx+6gZ9OZyK9uOah4rAID/pbQwhxaEdTivDCD+cwMMQVH0zujXBvqn1KCCH2pDcYUa7Wo0KjR5XWAD+FGC63rkfdnIWY1NcPGr3Rzq0khJCOa+f5HHx7Ig1cDgcXs5VgAEZGeMJHLkFcmDvGRnlDLODZu5ldGs0AJ4QQ0mVwOBzEhXngUrYKacVV9Qa/+VwOUgsr8dKPiYh9dy9mrDuJ746nIVdZ3c4tJoS01OrVqxETE2OqARYXF4fdu3eb1o8cORIcDsfsZ968eXZsMXF0BiPDN4dTcaOwEnojg97I8P7vV6A30ANGQojj+vZ4GgDgdFopnlh70r6NIYSQLuy7E+mY+N8jGPVpPF7begG/nM1CRkkVKjR6s+34PC6cRTR3jhBC6tIbjPj+RDqW/HYJF7NVuJClhJEBPjIxDiQXok+AHBP7+FHwuwOgv2KEEEK6lPt6+WBMlBf+SMqrdxu9kcHPVYySKi10BobD14tw+HoR3vz1Enr7y3FvlDfGRnsj0tsFHA6nHVtPCGmqgIAALF++HOHh4WCMYePGjZg0aRLOnTuH6OhoAMDTTz+Nd955x7SPk5OTvZpLuoC9l/NRWK4xW/bTmUxUaPR4Z1I03KWiRh3nbEYp+ge5tkUTCSGkVf11KQ/XCypMv9eUHypHdy+aBU4IIQ0xGhmKKjTILquGWMBDT18ZNh5Lw/cn0sHlcODhIoSYz4PWYITOYISzkI8AVwke6uePflauFT2lImyYPQhuzsJGvb5Gb0BRhRaF5Rqzn3K1Du5SEbxlIgS6OaF/kCt4XHo+QghxXNll1fj39iRIxQLsPJ9jtu61cZF4fGAgFmw+i8cGBtqphaQuCoATQgjpcj55tA80OiP+vlpgdT2HA/grJKjSGnCzsNJsXVK2EknZSqzYew2BbhKM6emNsVE+GBjiCj6vdRKrqHUG5JRV18xGrdUmAOCAAx6PA28XUau9HiGObMKECWa/v//++1i9ejVOnDhhCoA7OTnBx8fHHs0jXQxjDP89cN3qul1JuTiZWoy5d3fDoFA3RPnKkJxfjtOpJZBJ+DhxswT9ghQIcXfG0ZQi/JqYg69mxKJvoKJ93wQhhDTB539fx4p911C7HKKRAb8m5sDdWYjRPb0R6EYDzwghhDEGVbUemaVVyC6rxtXccvyamA1/VwnujfKGwkmIeyI9AQAP9fWHv0KCKD8Z/BSSRh3faGTQGoy4O9wDer0RheUaGIwMDAw+MjGqtAZcyFIiOU+F5PxyJOeV40ZhZb2Z8+qa3M8fKx/r29y3TwghLWY0Mvx1OR+Xc1UIcXfC5H7+LZq4xBgDh8NBnlKN9UdT8cvZbBRVaCy26+krw/yRYdhzKQ9z7+5Gk6U6EAqAE0II6XLEfB7UekO96xmrSc/4+wtDkZipxDs7L6NKq0c3TykSM8tM22WWVGP90TSsP5oGhZMAoyK9cG+UN4ZHeLYoVdi1/HJM/O9Rm9uM6emNb2bG0kUVIU1gMBiwZcsWVFZWIi4uzrR806ZN+P777+Hj44MJEybgzTfftDkLXKPRQKO5c9OjUqnatN3EcZxJK0VmSVW964sqtPjwz6twdRJApdbDYKyJGPm7SpBdWo3t57LNtv/HxjMIdJNAIuAhX6XGZ4/3Qy9/eZu+B0IIaQyDkSFfpUZZtc4s+H3bFwdSYGRApdaABfd0b/8GEkJIB5CUpcTey3n463I+Mkqq4OokxF1h7oj0ccGoHl54Zng3iAVci/t+uZMAY6K8rR6ztFKLhPRSnE4rwb4r+chTqqHRG6E33umMY4NckZBRavq9h48LssuqUa7WWztko+w8n4PF43vASyZu9jEIIaS51DoD3vjlAnYk3pmZ7a+QYHA3d5v7GYwMZVVauEtFyFVW44sDKZgQ4weJkIdfE3NQWK7B31fyUamt/znyldyaNOjVOgMe6kuTKzoSCoATQmwqrdTi96RcjIvyxgd/XIGQz8VHj/Sxd7MIaREul4M3H4zCtK9PoLTK+mjmnr4u8FM4wU/hhHsivVBUoUGgmxOW/nYJG46lWWxfVqXDtnPZ2HYuG0I+F8O6e2BctA9G9vCEi0hgsz0MDIzdmeWt1jVcB3bflXy88UsSnhsZhhAP5wa3J6QrS0pKQlxcHNRqNaRSKbZv346oqCgAwBNPPIHg4GD4+fnhwoULeP3115GcnIxt27bVe7xly5bh7bffbq/mEweyJSETymo9fORiBLpKkJxfDlX1nQeNCicBIrxdkJxXbgp+A0BRuQb9AhU4n1WGWotRVKExG4H+yFfH8OLocMwbHgYupaAkhNjBhluzY3KV1Siu1OKrJ2NxKrUESdlKs+1u92V6g5XoOCGEdBHHbxYho6QKM+NCMLS7O4LcnJo8yF1vMOJSjgqnUktwKq0Eh68XNvhMIb2kEoNC3ZBVWoUqrQFX88pb8jZq2mFk+Cr+Jhbf3wMCylZHCGlHBiPDlNXHcCnHfHLCB7uv4udnh0DEt6zFXa01gIFBrTNi2EcHsHRiNK7kqvD7hVx8fyKjyW14av0pSAQ8xAa5Icidsht1FBzGrI3FdTwqlQpyuRxKpRIymczezSGkUzAaGT788yqeGByEZX9cxZ+X8jCmpxfWzhpo13bR97ntdZVzfDSlCNPXnrS67uH+/lgxta/Fcq3eiEs5SlzNK8cHu66gXNP8EdK1dfN0tki33hguYj7WzRqIQaFurdIO4ni6yvfZFq1Wi4yMDCiVSmzduhVr165FfHy8KQhe2/79+zF69GikpKQgLCzM6vGszQAPDAzs0ueYNOxafjnGf3bYLLANAAOCXSHgcZCn0iCjpMpi/W1cDuAs4iPU3Rl6I4OziIfTaaVWt31icBA+mNy71d9DV0H9Ztui8+uYdAYjPtmTjK8P30SgqxPcnIUQ8rjgcICz6aXQ1dO3jYv2xpoZA9q5taQ10Xe6bdH5dSwqtQ56A4NCImjRYEW1zoD4a4X4/kQ6EtJLUWVjZmJDonxdcDm35QHw27p5OmP2XSEYFu6J4FpBIMpeV4O+022Lzm/XdCylCE/U83x3aHd39AlQYHA3d/jIxIj0cQEALPvjCvJUakR4u+DjPcmt1pZVj/XFQ/38W+14XV1Lv9M0A5wQUi8ul4PX7+sBLpeDCB8XzLk7FL0prSZxIGGeUnjLRMhXWdZvOXStCJklVRY1CYV8LvoFuSLc2wUf/nm11dqSp1Q3a79ytR6PfX0cnzzSB1NiA1qtPYQ4EqFQiO7da9KrxsbG4vTp0/jss8+wZs0ai20HDx4MADYD4CKRCCKRqO0aTBwOYwzv/n7ZanD7THopBoe6IbXI9iAoIwPcnIW4cGsW5aAQV5vba/VGCPk0+4YQ0raMRoZLOSq8+OM5pBZVwkMqhIDHMSsbZEtFKw0mJYSQjooxhgPJBdh3pQCh7s7oE6hAD18XyMS2M8VZO86XB29g/dE0qzVom0PE50LUyteLNwsr8eavlwAALiI+Inxc8P3cwZAILWdgEkJIa1A4CcDjANYSCx1NKcbRlGJ8efAG3J2FeGRAAI6lFFtkJ2otZzNKKQDegdATEUKIVQYjg95gNI1IfXlMOAaFutEFawewevVqxMTEQCaTQSaTIS4uDrt37zatV6vVWLBgAdzd3SGVSjFlyhTk5+fbscUdl49cjG3zh8JXblmjqqhCg50XcqzsVUOtM6CsnvTpTcXjAAGukmbvzxjwypbzePrbM7iSS7WICWmI0Wg0m8FdW2JiIgDA19e3HVtEHN1v53Nw+HqR1XUDgl1xKrWkUcdJL66pH94vUIFT9cz+BoDjN4qb3khCCGkixhimrz2JCf89YhrEI+LzcKMJWY2ElCaXEOLAkvPKMfN/p3AqtRT/ur8nnh7eDYNC3ZoU/K7Q6LH28E1MWX0MH+9JbrXgNwDEBMhxLrNtgkAAUK7RIyG9FJ/8lYw9l/KQUlABta75s9UJIaS2M2kluJBVhgPJhegXbHuAOAAUV2qxJv5mmwW/AWDf5Xx0kaTbnQLdaRBCrFp9MAVLd9aM2GSM4bsT6Zi74TSu5bdeWiTSPAEBAVi+fDkSEhJw5swZjBo1CpMmTcKlSzX/Xy+//DJ27tyJLVu2ID4+Hjk5OXj44Yft3OqOy1cmhrfMMgAOANfzK+rdz0MqwqOtNOPawGpeKzZYAQGv+WnB9l7Ox0NfHKXAByG1LF68GIcOHUJaWhqSkpKwePFiHDx4ENOnT8eNGzfw7rvvIiEhAWlpafjtt98wc+ZMDB8+HDExMfZuOnEQecpqvLfrMrxdRAhxd4KQxwGfy0EvfxkEPA6chTzIJAI4C3noEyCHwqnhB6IXc5RwcxLWuz61qBJpxU0vq0EIIU2VkGE+GMdPYf26uj79ghp+WEkIIZ1RSkEF/rU9CfNHdscb43tAKmp6ItYLWWUYt/IQ3tt1BWczylq1fTwup90G0K87kopnv0vAmBXx+O/+lHZ5TUKI4zt0vQgT/3sUH+9Jhl7fMYLOOUo1ssuq7d0McgsFwAkhFpRVOvx8JguF5TWjSg1Ghi8OpODvqwU4mmJ99hJpPxMmTMD999+P8PBwRERE4P3334dUKsWJEyegVCqxbt06rFixAqNGjUJsbCzWr1+PY8eO4cSJE/ZueofE5XLw7qRe8LMyCzyngQuW5VNi4C1rnTTIDEBCehm86gnGN5ZGb8Tn+6/DWE+dRUK6moKCAsycORORkZEYPXo0Tp8+jT179uDee++FUCjEvn37MHbsWPTo0QOvvPIKpkyZgp07d9q72cRBqHUGvLrlAooqtMgv1yCtuAo8LheeLiJUqPXQGRjirxchwluKSq0B57OUUEgECPeW2jxuhLcLNHrbs2fONzL9MCGENBeHw8GQbu5myxIzyyDiN25Ap1jARVyYe8MbEkJIJ3OzsAJlVVr88txdze7ntHojFmw+2yaBFImAhyhfF1RorF9PxvjLEe0nw6AQN/Tya906ygz0rIIQ0nJ6g9EsTnGjqAItmFPUqnZdyLV3E8gtVAOcEGLhbGYpMkqqkK9SgzGG5PxylKtrarO53ErTVK01QCzggsPpIH9ZuiiDwYAtW7agsrIScXFxSEhIgE6nw5gxY0zb9OjRA0FBQTh+/DiGDBli9TgajcYsHbBK1bXSaPcOkCM2xA05581TnqvUehiNzFQKoC4el4PZQ0OxfHfr1QJ3acao8LqO3SjG4ZQijIjwbIUWEdK5rVu3rt51gYGBiI+Pb8fWkK7i9s34x38l42K2+d/Uap0B1UoDBoW6Ie1WSvPTaaXo4eOCq3nlSCuugpuzEH0Da7KCnL6V6pwDYFCoG4yMwcAYKrW2A+C9/OVt8t4IIeS21KJKnEo1zzwU6uGMazayKNXm6iRESaW2LZpGCCF2cz2/HI98dRzOQh72LhoB52be4++5lIfMkraZRdjbX45TaZYleKRCHnwVElyokx54cKgbzqaXQtfCgfYCHgcP92+dTHqEkK7tdFopEtLvZCLylomRUtC4a9C2tiMxB8+OCLO5za+J2bi7uwfcpa0zsYpYRzPAm2jv5Xycy6i/3h4hjuD2jKE5d4eiWmfAW79eQtWth6w/nspAgUqNRT8n4uC1Qju2smtLSkqCVCqFSCTCvHnzsH37dkRFRSEvLw9CoRAKhcJse29vb+Tl5dV7vGXLlkEul5t+AgMD2/gddDyDQizTL17JVeGTv5Jt7jcwxBW8egLkzVHdSvWw0puQ+vZyjopmjBNCSCswGhl2nMvGlNXHMHvDaRSq6q/RWPcvh0zCh1xSM9CwpFKLxMwynE4rRcytQHafQAVOppbgdFopLmarENBAmuEKjb5F74UQQmxhjOHH0xlQ64xmy/NVGkgEDT9q8pWL8b+nBmJctE9bNZGQNrd06VJwOByznx49epjWP/vsswgLC4NEIoGnpycmTZqEq1dbb/A06VgYYzhwtQBzNp6GslqHHKUaR5qZRdFoZPj2eFrrNrCWsmotgt0kkEvMg/M9fGW4biWAdDK1BMEezpAKeZAKeejuJYWXS9ODNv4KCULcnZvdbkIIuS022BVRvncyVPA60CS9K7kqFFXU/yxAWa3DmbTSVn2eTKyjGeBN9P6uy3BzFmLb/KH2bgohbeJsRqmpHs+gUDdM+/oEzmfdGfl5MUeJT/5KxoMxvvBuxsUuaR2RkZFITEyEUqnE1q1bMWvWrBbNYly8eDEWLVpk+l2lUnW5IPiEPn7Ydi4b5+rU1frm8E1klVbjjfE94KeQWOwXG+yG2XeFYO2R1FZpR2krzYJZsfcaJvX1NwVTrNmdlIuvD99EYmYZnAQ8iAQ8eEiFiPB2wceP9IFEyGuVthBCiCNjjOFqXjn+vJiHDcfSIJcIkFFSM7NbZzQi2k+GSzk1s8AVTgKUVekAAJV1AtSnUksRG+xqNoodAPRGhgHBrjhTa3nfQAVOpVrO2qlt7eGbGBji1uL3RwghdRmMDC//lIjf6mRPAgAPqRA3Cm0PxAx2d8LBV0dSNjHiEKKjo7Fv3z7T73z+nUetsbGxmD59OoKCglBSUoKlS5di7NixSE1NBY9H91qOhDGGf269gC0JWaZlQh4XfnLLZwi25CnVuJKrws7zOaYsQG2hdqYOb5kI4V5SaA3M5vVlSkEFXMR8lKv1SCmoAJdT89zwXEYpdIbGDahPK65CUrYSfQMVLX0LhJAuSm8worRKhyu5KpRV3XmGmpxfjr6BCnA4QFmVDqlFjZ8Y1Np4XA6E/PoHhMolArz7UK92bFHXRQHwJjAaGYoqtEgrrsKXB1LQN1CBuDB3cDgc6AxGCHg0oZ50bkYjw9Mbz0B/aybo7PWnLbZR64z4+UwWzqSXorhCi8Xje2BiXz84Cak7aU9CoRDdu3cHUHNTffr0aXz22Wd47LHHoNVqUVZWZjYLPD8/Hz4+9c+uEIlEEIm69oAGhZMQ2+cPxYGrBfj3joumOls6A8Nv53NwNKUI/5nWDzKxAJmlVbi/t69p39fH90D8tUKrI6WbQsTnQKVunRl7ZVU6TPj8CBaOCbeaYkxnMOLNXy+iqKLmYrFSa0Cl1oCSSi2u5VcgV6nGx4/EoJun7Tq0hBDSVTHG8OXBG/jpdCZ85GKcSi2Bn0KMsuo7N+EllToEudbMconwliJXqUb/IAX0RmY17a+1Go+Xcy3LkpxKLcHAEFebD0bvDqcyGISQtpFZUoVD161nA2so1e/4Xj5YcE93Cn4Th8Hn8+u9137mmWdM/w4JCcF7772HPn36IC0tDWFhtlOjks7l5zOZZsFvPpeDNydEoXdA40rSqNQ6fLE/BWuPpMLQztnZ8lUaFFdoEenjAndnIYptDMovr/W8wshqrkkDXCWQivi4mlfeqNfLKKmiADghpFkuZivx9LdnkKtUW12feCurbf8gBVpnmlLz3BftA5m4/glJpP1QxLYex1KKsPdyPj744wrUt9LRZpRUoUKjh4DHwa6kXDyx9iRGfRqPN365gEn/PYoLWWX2bTQhLVBYrsETa0/YvNCt7WZhJZTVOryxLQkLNp1t49aRhhiNRmg0GsTGxkIgEODvv/82rUtOTkZGRgbi4uLs2ML219yU3vf08MKR1+/BB5N7m6WiKa7U4sl1J5GtrML+qwXYeznftI7P5eDZEWEQNyLdoy19AhQt2r+ujJIqLPr5PBZsOos/L+aarTuSUmQKfluTkF6KqWtO4MDVglZtEyGEOIJr+eUY8N4+fLwnGYwxXLkVpM4pU0NVbT6QKb2kEgOCXeHuLIREwMPZjDJcyFIiq9Qy2B3k6tSo13d3FkKrN8JWxrTD1wrBGJW3IIS0vhAPZ4yN8rZY7qcQg9dAXPudSb3Qy79xASFCOoPr16/Dz88P3bp1w/Tp05GRkWF1u8rKSqxfvx6hoaE2s61pNBqoVCqzH9LxJWbeyZw4uocXDrw6EjOGBDe4n0ZvwLojqRjx0QGsOXSz3YPft+mNDJdyVOjm2fT05Fml1biaV47+QQq4OjUc8Cksrz8tMHFshw4dwoQJE+Dn5wcOh4MdO3bUu+28efPA4XCwatWqdmsf6diSspSY+N8j9Qa/a+PbcaKqWMDFP++LtNvrE3MUAK8HA/DGLxfww6kMU/oXTxcRnARcRPvJTWkMU4sq8ePpTFzOVeHXRMv0X4R0BnqDEQ99cRQnbtpOpVmfM2ml9IC1HS1evBiHDh1CWloakpKSsHjxYhw8eBDTp0+HXC7H3LlzsWjRIhw4cAAJCQmYPXs24uLiMGTIEHs3vV1tOpne7H05HA6eGByEL57ob7acMWDd4VS8PTHK7KYtMbMMS369iNggyzriTaHWGxveqBl2JeVi3vdnMW7lIfx9OR9Hrhfh+UYMXCmq0OCFH841qZ44IYQ4upyyaszdeNo0aLCwQmM2G6au0iodzqSX4vjNEpSr9fC3Uk7jtjPpJQir58Fj/yAFpCIeBDwOiiu1OJ+lhK1npH9dzse2s9mNe1OEENIEeUo1dp7PtVheqTHgQq3yWXU9PrBrlVgijm/w4MHYsGED/vzzT6xevRqpqakYNmwYysvvzIT98ssvIZVKIZVKsXv3buzduxdCobDeYy5btgxyudz009VKk3VWb9zXA+9MisY7k6LxxfT+CHSzPajRaGTYcS4b/9h4Bu/+fhmlt0rk2NvptFL0C1RA0NBoJivOZpTBYGQNPhdxc6ZZkV1VZWUl+vTpgy+++MLmdtu3b8eJEyfg5+fXTi0jncG3x9Ns3v/WVqVtneyazfHymAgEuzd9MBFpGxQAr8fQ7h5YMjEanz3WD8MjatIHOov4WDqpF87XM9P7ap4Kp9NK8P2JdNMskMYortCgXK2zqANISHtQqXX45y8XrKbcbAyZmI+pAwMphV07KigowMyZMxEZGYnRo0fj9OnT2LNnD+69914AwMqVK/Hggw9iypQpGD58OHx8fLBt2zY7t7r93dPDq8XHGBftjQ2zB5rNBE/KVuLNHZcQG3znpq5aa4CvQoIPHu7dolRetWvXtIXk/HKs/Psanlx3EpVaQ6P2qdDosf5oWpu2ixBCOovLOSrMWHcSmSV3rpvUOiMGBDduAFS1zgBXZ0G9M7eNDMgurUZ3LynCve6UoIjyleF8ZhkqNIZG11gEgNI2/rtCCOl6DEaGF388h2qd5bWksloHDxcRAt0k8HaxLK80oY8fPK0sJ6SzGj9+PB599FHExMRg3Lhx+OOPP1BWVoaff/7ZtM306dNx7tw5xMfHIyIiAlOnToVaXf/stcWLF0OpVJp+MjMz2+OtkBaSivm4ll+Om4WVNgcgqnUG7L2cjwc/P4KFPyXi8PUi9O5gWTHOZZYhwtulWfuq1HokZJRiUIir1etdFxEfw6lMT5c1fvx4vPfee5g8eXK922RnZ+OFF17Apk2bIBDQYAkCFKjU+HjPVbMyEw2pbuQzz9YWG+yKuXeH2uW1iXVUtNeG4eEeFqkJpw4IxN9X8rHnUr7F9kdTinE05TgA4LVxkejpK2vU61zOVeG1LRdQodFjfC8fvPtQL4gFvJa/AUIaoDcYsWDTWRy+XtTsYzzUzx9vPhjViq0iDVm3bp3N9WKxGF988UWDIyodXUAj08jawuFwMDLSC2uejMX8zWeh1Ruh1hmx7Vw2Cis0+HbOIKiq9Yj0ccHel4eDw+Fg6cRoPLX+FMqaMYK7rdOdxQTIbc7Kqc/mkxl4ckgQuns17yaYEEIcwcHkAizYdNZiAJFUyENSthIDQlxxpk5N7mg/GZyEPOiNDAYjA5fDQVZpFdychfCVi5GUbTloVq03IqWgAi5iPiK8pdDqjchTVqMJcW+TD/+8ilylGgvHhMOFapARQlrB3st5pix51uSr7mRJ8nYRIb9W1qR/bU/CnoXD6XkHcVgKhQIRERFISUkxLbs9kzs8PBxDhgyBq6srtm/fjmnTplk9hkgkgkhEA0U6m0s5Snx/oib9/ZNDgsAYM00UScwswxcHUnA5R4WCcrXFYMaSSi34XA70dkh/LuJz0ctfDiNjputPH5kYZzPKWnTcU2mliPCWoqxKh4Jbfwe4HOCDh3vDXUqfb2Kd0WjEjBkz8NprryE6OtrezSFtRKM34Hp+BdylQvjK68+OBtSUTJi1/nSTJpsCsMu1pkTAw+fT+tk1/TqxRAFwGxROQiicLNMSvTAq3GoAvLbMkqpGvQZjDGfSSpGnqhn9uSUhC74KCRbdG9H0BhPSRAeTC1sU/AaAXxKy8MrYSMglNQ9VKzR68DgcSIT0UIN0Tlq9EQYjM/sMj4nyxhODgrDhWJpp2bEbxXh+8zl8+EgM5E53buD6Birwn8f7YeW+azjXxJvGnDI1PKRCm7W5m0vA5TS71pbWYMRHfybj65kDWrlVhBDSOVRp9Zi78YzFQCUXMR/hXlKczSjDmbRSDAp1Q7VWj2v55dAbGHLKqutNaVlUoUWIuxNU1TqUWNmmXK1HuboCANDLT2Z1m4boDAzrjqTiwNUC7HpxGF2fEUKaLLOkCgGuElMg54dTjZuNGu0ng1TENwuAq3UGaPRGnEwtwbW8cqh1BriI+bi/ty+8ZOI2aT8h7amiogI3btzAjBkzrK5njIExBo2GaiA7mrTiO8+Bvz+Rgb2X8xHo6oTSKi1uFNouKZZdVo1BIW44lda8soTNFe0ng7JKh4T0mgGcAi4H5Wo9csoarq/bGNfyKzAwxBUF5RoIeBx89ng/3N/bt1WOTRzThx9+CD6fjxdffLHR+2g0GrM+VaVqWqCUtC+jkWHW/07hxM0SbJ0XV28AvKxKiw//TMYPpzKa/Bphns6m8sXtxUcmxg/PDIGfjXJnxD5oOEIz9PKXY1i4h81ttIbG1XH94I8r+Ozv62bL/nckFaWVlK6QtL0bhRUtPgYDUK6ueSBbVqXF9LUn8cEfV1p8XELswWBkuJBVhpOpxRbrskqrLLbdlZSLa/nlFtsOj/DEhtmDbNZ5rS02yBXB7k7oEyhHRRuVw+gX7IpcZfNvZPdfLWjWhSchhDiCcrXeIvh9u4+vPUPmVGoJkrJVcBELMDzcs8F6jnkqtdU0wta2E/GbV27G00WELfPiKPhNCGmWj/Yko9+7ezF97QmsOXQDR1MaP4A6Ib0U/YIUpt8f6O2LuRtOY9b/TuH9P67g073XoNEbKfhNOq1XX30V8fHxSEtLw7FjxzB58mTweDxMmzYNN2/exLJly5CQkICMjAwcO3YMjz76KCQSCe6//357N520sr2XzSdK5as0OJNe2mDw+7bLOUpE+rR9xjUnIQ/9gxSmAFFWrXKIujaYga7RGxHs5oSvZwyg4DexKSEhAZ999hk2bNjQpDKby5YtM2XakMvlCAwMbMNWkpao0urx+DcncOJmzWCf5zefw/Ebls9fV+27hnGrDjXrGSSHU/PT3l4aE45QD6r73RHRDPBmCvOU1jtz1tNFhEdiA8yWqXUG/HU5H1G+MnS/Vc+PMWZKj1NbhUaP1fE38K/7e7Z+wwm5RW8wWgy+aKqevjL08HHB7xdycfxGMc6klaBSa0B2aTUW3RsBV2fLDAqEdGQ8Lgf+rhKI+eZBgss5SkhFfAwOdTNbzgBcyVGhf5Bl7VcXER9rZvTHh38mI6WgAvkqNeq7nyyu1CC9uArpltd9rcJTKkJSM1Kf16Y3MizelgQnIQ+T+vq3UssIIaRzsDZoMFdZjdhgV5yuk/YcqJndXaG1PaCpb6ACecpq5KkangVWVKFF30A5hLf+PqUWVqKwomY/VycBevrKYGQM1Toj1FoDqnW3frQGuDsL0f4JNQkhjmJQiCt2ns/B0ZRinLxZDH0DY/3dnIUoqdRCcjv1JKs5hkqtx/+Oplls/+nea5jcz5+C4KRTysrKwrRp01BcXAxPT0/cfffdOHHiBDw9PaHT6XD48GGsWrUKpaWl8Pb2xvDhw3Hs2DF4eXnZu+mkFR27UYSd53NadIwKrQHJeeUYHOqGsxmlFmnSa/NyESHUwxlVWgOMjIHLAaq0BrNgu5eLCL4KMXgcDrR6IyRCHjKKq1BQrkFKQUW7BWouZCkxe2gI7ulBn3li2+HDh1FQUICgoCDTMoPBgFdeeQWrVq1CWlqa1f0WL16MRYsWmX5XqVQUBO+AGGN49/fLZmV08lRqzN5wCs+N6I5+QQoMj/BERnEVVu1rfrxiQD33521tFPVxHRYFwJvJ1qy+F0Z1x11hNTPEc8qqsf1cNtbE34BKrUeEtxS7XrgbfB4XXx+6We+Mj0PXCqDVGbH4gR4Q8Wm2BmldeoMRG4+no0rb8IwjW67kqsxqcPC5HEzq6wcuh4OMkkr872gqIn1cEOrhjGg/eUubTUi78JVLkKesxuJtF+DuLIKRMQS7O6GoQouE9FKLulxcDjB1YCAEdWq8cLkc9PJX4Ns5g1Cu0SMhrRSzN5y2+pppxVWIDXLFuczSeoPkLSEWclFY0bLvu1TEQ5iXFJ/+dQ0x/nKEekpbqXWEENKxlVRq8eHuq3AR8VCuudOXGhnAtTG8vEBVf9YNAY8DjU7fpNHpiZl3BjJFektRWKHBb88PRUyAovEHIYSQJqqd/aJ3gMJmiR8eB5BL+OjtJ0P8rQkD5zLr3x4AdAYj0kuqKABOOqUff/yx3nV+fn74448/2rE1xB4YY3hzx8VWO97J1BIEukngIRXBYGDgcgEOOKZZjRxwcD6rDAWp5gMoZWI+7gpzR6VGjwqNHqlFlaba23Wp1Hqcz1Kif5CixbW+G2NctE+bvwbp/GbMmIExY8aYLRs3bhxmzJiB2bNn17ufSCSCSER15Tu6T/5KtlpGR60zYuW+a5CJ+dj89BD4yMUIdJMgs6TaylFs83IR4WJ2yyb/NEd3Lym86Tq2w6IAeDNV2pjRcbOwElmlVQhwdcJbv17Cvit30uBcy6/AM98lAAAOJBda3b+HjwvSi6twNS8NfB4Hi+/vCR7XDrkbiMN667dL2Hyy9VMZ640Ms4eGAqgJjn++P8W0bnI/fyydGG2qFU5IR+Yjl+DVsZF47vuzpjpc3TycLYLfAHDiZgkmfH4Ebz0Yhbu6W5bH4HA4kIkFppl69UnIKG2zul+ZJdWm2TjN1cNXhjNppejh44Knv03AMyO6YeoAGlVLCHFsKrUOczeeRlK2EkZWM6K8oFyNCo0BLiI+zmZYH13O4wASIR9cDiwGNkkEPPQOkONUagn6BymQq2x6HVCpmI9uHs5IziunADghpE3l1Cqho7cxIxEADAxQVuuRZmxcyl8AYAw4llKMfoEK8LicJqU9JYQQe7teUNHoNOeNlVlSDTGfh+sFjS9bqFLrcexWKuFIbxdEeEtxNc/6/pE+LhDxue0S/AaAIDendnkd0vFVVFQgJeXOs+LU1FQkJibCzc0NQUFBcHd3N9teIBDAx8cHkZGR7d1U0oqS88rxxYEbNrdRqfV48PMjGNbdo1nBbwDwlonqHfjTlsb09G731ySNRwHwZqrviyjkcXAwuQCn00pwT6QX/r6ab7FNVmm1zYsYmZhvmhm+9kgqUgor8Nlj/SB3osAhaZ4Cldo0ot5gZDhwtaDNXmvyl0fBrDwX2X4uG2IBF9MHB6OXP80GJx2fu1SEn54dgkU/n8f2c9m4WVT/Te3VvHK8/8cVbJ9/FzgcjsVscAAYEuqOSG8XJFupGX5bW9X/BoAQd6dmB8BjgxTIKK6pgX41rxyDQlxx4kYxBcAJIQ7vv/tTzGY7nkm/E/C21ad285TiZlGlWfDb00WEUA8nXMlR4VRqielhoIdUiKKKhvtnX7kYC8eEI8DVCeFeUpotSQhpc7su5GLPpTzT740Zl+/qJIBcIoCXTIw8lbpRDzFX7ruGLQmZkIkF+Ozxvgj3bvs6uIQQ0hpqT3pqTaVVzR+8npxfDh6Xg24ezlafY0hFfCSkt1+KYDcqj0huOXPmDO655x7T77dTl8+aNQsbNmywU6tIS+Qqq/Hxn8kwMIZ8lRo3CisR5ukMH5kYA0PdIBXx8dNpy5nf9TmR2vjakLHBrqjU6OEsqglxtme/VtuYnpT+vCOjAHgzBbhKMCjUDdml1cguu3NDZzAy5CjV0OqNuJSjsrqvVGz7tNcd8XwwuRAP/vcwXrgnHJP7+1sNrBBSH73BiA3H0jC4mzvCvaT46XQmcpX1p+RsKWvB79tuFlZi2tcn8OnUPrg3yptG95MOj8Ph4PlR3RHoKsGWhCyb351LOSq89etFvH5fT7haucELcnfC2lkD8FX8DVzOUeJcpmVaHoORgYOa1LjaBmbYNFVzv22DQ92QnF+OsiqdaZmBAZdzrf+NI4QQR3GjsALrj6Y2a9+04kr09JHhQrYS/q4SuIj4uJpXjsJaI9IzSqqQUVIFFzEffQMUSMwqs3nMbp7OeGxgkM1tCCGkNX17PA3ptwZBAjWpfm3hc4FKjQFiAQ/OIj6MTajtk1VajRlDvCj4TQjpVHZdyG21Y3m7iBDs4Qyd3tjgdWFDDEYGd6nQagA8Ib0UMQFy3CiogMHIoNYbW/RatkhFfIgFVNqT1Bg5cmSD1xK11Vf3m3QcB64WYtu5bLNlt+95dyTmNOlYQW5OyCipanAbd2chqnUGuwW8axPxuegTqLB3M4gNFEltoks5SvxwKgPdPJ1xKrUErnVmZfcJVEDbwIXDhSwlvFzqr03BYPmHILOkGv/85QKe/S4BOkPbXZgQx1Kp0ePpb8/gy4M3MOt/p3DX8v347O/rdmvPydQSlGv0eOa7BDz97Rkk55WjUqNHlVaPG4WNT+1ESHsK85Ri0dhI/PxsHF6/r4dpeS9/mcW2P57OwrnMUpSrdRbrACDQzQnvT+6Nb2YNtFraIjm/HHeFuUMq5iM22LX13gRq6ow3R0J6CcLq1Ps2MobMkiocSG67bBKEEGJv+Uo1dE0cjMTnctAvUIEgNydcyFbCVy5CgVKNq3n1Z/8oV+sh5NsepuQhFeK/0/o3qS2EENJSymrza1qxgIcQ9/pT2eqNAJdbU+rhVGoJssuaNvCaZgkSQjqTSo0eV1pxYLjCWYhTqSU4l1lmc3JJY2n0RgwMcbV4dg3UPJvW6I0AB+gXqMCAYFf0D1JYPU6wmwSDQ93Q21+OfkE127o1MktpmKdzS94CIaSD43FqJs4MCHaFgNeyiW6KBsqmerqIkF1ahXOZZTbvr9tTtJ+MJqt2cDQDvIn2XMzD5wdSsHp6zQMoIf/OB5zLaTjA4OYsgMEIaG0EsZVV1gMnALD/agGW/HYJH0zu3cSWk67kaEoRhnb3wPxNZxF/zXqteXvbd6UAuUo10ooqwedxoTMYsWPBUETQiH/SQQW6OWHeiG5wdRJgQIgrruaV45Wfz9fcNNby5YEbkEkysPKxvvXWvPeQivDq2EjkKqux60Iuim+l0Q3zdMaNwkqUVOpQqVGafq/PwBBXVOsM4HI4uJBlOaMcAAaFuqFKo4dEWDMTp6HRlHWFe7vAUGf2zvnMMvT0lWHxL0k49sYocBuTD5MQQjqZpmTMEfA46B/kiusFFTiXWVbrGI2rQVY3yFQXj8vBt8fT8cKo7tTnEkLazYhIT7MHjAwceMvENp97yMQC3CyqQJCbBBlNqOEoFnDxxGDKckEI6TwuZCnRhEQXVkmFPET5yVFYoUZyKwV0eFwOPKUiZJRUwV8hQTdPZySkl1lspzcy6I3M7Nq1X5ACxRUaSEUCGIwMheVqlFTpkF6nP+8bqMDcYV4YEOwGZxEfXA4HBiPDjcIKlFRq4SLmI6WgAkO7e7TKeyKEdEwT+/rj9W1JAIABwa5Iyi6Dh1QMZxEPZVU6s5rcfgoxAl2dcCGrDNU6y9hYekn9zz8BoJuHs1lGtY4gwLX+gaGkY+g0AfClS5fi7bffNlsWGRmJq1evtms7gtydMaV/AMZF+yDY3Ql8bk0AvKevC/JVapu1AL1lIugMDMpq23VcGho1svlkBu7v5Yu7w+kiglgqq9Jix7lsDO3ugbHR3jh8vbDFF+Rt5U6ZgJqa99ll1RQAJx0ah8PB44NqHsx193IBl8PB4m1JZoGLM+mlCHSTYMuZTPxjWLd6j/XcyDAAwGMDA/HAf45gUIgrzmWWmWYbavRGKJyEAKxfAPI4QEG5xpSWsm+gHHwuFzwuB0bGcCVHhR6+MpxKLTHt4yMTI9TDGak26pnfJuBxEBOgsJpSyMiA6wUV4IBh35V8jI32afB4hBDS2cglAvC5HOhrXUg5CXmI8JbiUo4KEgEPLmIBvGUiMFaT6aY5hHwu8lS2g+35Kg1W7ruGu8PdERvs1qzXIYSQxvrzYh68ZCL8XKdmIwcMBmPNdWh9CTKchDyUVOrg6SJGpLcLkvMbF9AJdnPG4etFcBHz0ctfDk+pyGzCASGEdDTnMpuffjfCWwqZWICLOUqcSmveNaQ1g0PdcDFbabq2LLMxycqacxllt/51J+BtrXqhq5MAC+4Jt1jeO0DepNcjhHRuap3B9O8z6aVQOAnMygV7uYig1hkQ4OoEHrfmnrlPgBzn60zicRHxoW8g+1qFRt+6jW8FEirx0OF1mgA4AERHR2Pfvn2m3/n89m/+I7EBeCQ2AMCdQLWHVIgClQYllbYvKgJdnXCmEbUJGGouLmylu3nrt4vY9/IImgFCLCichPj40T4AgOmDgxHu5YIfTmVge516HB2NgMeBr1xs72YQ0iT39/ZF30AF1sTfwK6kPBRV1IxEzCypxlfxNzH37tAGa937uIgwNsobf13Ot1hXaePiLtzbxWxGTmKdmuIeUiESa43kBoA8lRpBbo0bneghFeGajRHoWr0Rvf3lWPRTIuROQsy/Jwx3d/dAsDulOCOEOIYKjR6hHs7IVdbcwPspJMhXqU39rc6gh0qtN7vBbw6JgAchjwvA9g19sLsT+gW2bnkMQgipK6u0CvO+T4DCSWARODGwmtqxXi4iVGn0YKgpjXN7Fo9UeOchYHJeOVxEfKvHsSY5vxyvbjlv+v33F+5GL38KpBBCOq47weKm0+qNjXpG3FS5SjUqtYaGN2wCa8+nT6WW4EByAe6J9GrV1yKEdC6uzkJEeEtxLb+mtGnda77bM8Av1yoXcT5LieERHqjWGsDhcFBWpUVRuRYlVbYnjTqLOl6weUgYDU7v6DrVcFo+nw8fHx/Tj4eH/WZAX8gqg4uYDwGfA4mAZ0pfa0tDMztuu5SjQt8GRszdLKzEX5fzGnU80rUNCnWDk7Dj/YGorZe/DF/PHIAePpY1lQnp6PwUErw9qRc+e7yv2SyVogoNLmYrG6xv/387LlkNfgPA1bxyuIj56Bto/jdBJuGjocQORRVas1mLt3nLRA3sWSNXqYa/q8TmNknZSvT0k8FFzMf6I6kY/Wk8lv1xBd+fSMeWM5koaOTfPULa0urVqxETEwOZTAaZTIa4uDjs3r3btF6tVmPBggVwd3eHVCrFlClTkJ9v/TtJuha9kSGrtBoVGgMqNAZcy6+Asrr1R50rq3X1Dk4KdnfC3d098NRdIfjiif40+JUQ0uZuz66xFrTm3+qDqrQGVGgNqNQa4OosxJBQNwwKdUOUnwxnbwWEOBwgyk8GLprXb/1yNgv6W6XjGGP49ngaVuy91qxjEUJIa2OMtSgA7uXSNhNAMkqq0C9QjhaW4rXJ1UmA/a+OpOA3IQQAcFeYeYxOwOOg9m2rVMRDgEICDgB/VwkGhLjiTGoJTqeV4lRqCa7lV9gMfnNv1Rk/2waDhlpCwONgHGXE7PA61Qzw69evw8/PD2KxGHFxcVi2bBmCgqzXiNJoNNBo7tQEUKlUVrdrrrIqXZMudLxcRMgqbfzsEBslwk3e/f0KRkR4QdLBg5vEvjYeS8NviTl2e/17Ij3R01eGLw/eMC3jcIA+AQqMjPTEA719EU5pz4kDGNrdA4/EBmDzyQzTsrTiygbTg1/IKgMAizS7t5Wr9UjMVGJwqJspvW6YhzPOZVqv+d2QuvW8bbmaV44ePuYzzes6nVZzAXq7/WsO3TSt85aJMDzcEwGuTnhpjGV6NELaQ0BAAJYvX47w8HAwxrBx40ZMmjQJ586dQ3R0NF5++WXs2rULW7ZsgVwux/PPP4+HH34YR48etXfTiZ09EhsAAY+Dl35MbNb+UhEfGr0B/QJdoTMYzeor1pWnUiPcS4rrBXcGTX04pTemDghsMJMIIYS0ltNpJQhU1D8AsvrWrMLaKSiVVTrkcNXIKLlTFzzcS4rCCk2zS0MAwM+nM+HuLETprfqRf13Kw7uTejX7eIQQ0poOXy8yZYBrjnMZpegbqLDI2tYayqr16OVfk2LYXyGGr1wClVqHCo0eOWUtH6ReWqWDqloHbxllcSSEAPm1Jr+EuDtBWa2DgMdFsLsTytV6XMsvR4WmGsMjPHAmtQTZTYiRAcCAYLcWXVO2lUgfFzgJO1V4tUvqNP9DgwcPxoYNGxAZGYnc3Fy8/fbbGDZsGC5evAgXF8vg2bJlyyxqhremYeEemDYoEFvOZFkNWNTl6iw0pXxoDI3eAImAh2pd/Wlrssuq8c3hm3hxNAUVSM3oU43eWBOAir+BcdE+OHC1AH9fzUeopzOKK7QtTtHZFC4iPjY/PQRRfjLwuBwEuzshwtsF1wsqEBMgp9nexCHdE+llFgD/4sANjIzwgqpaD08X6zOvVz3eD6v21cxmOXajuN5jn0wtwfBwD1TrDLhZ2HAN7/rwuU1L/iLkcyGXCMzqnFtjLT6Tr9JgS0IWvpzev0mvSUhrmjBhgtnv77//PlavXo0TJ04gICAA69atw+bNmzFq1CgAwPr169GzZ0+cOHECQ4YMsUeTSQcS7de06xUXER88HgdBbk64kKUEB8CptBIEudnOqJFdVg0OBxgQ7Aohn4vnRoZhWLhnC1pOCCFNwxjDjHUnEeDqhIEhrqZBjrWJBHeuI3kcYECIGzJKqsyC30BNBo2m1p2tq1JrwCd/1Vwjx3Vzx4FXR8LPRnCeEELa0xcHUlq0v87IkJhZht7+MiRlt96krUGhbjh1K1AkFnCRXaZG9q2gt0TIa3CAe2O9u+sKFo4JRzcPZ8glAosBmwYjA48yFxHSJUzq64fdF2syFfO4HJTeugasGwsrq9ShSteIWZ+1RHpLIeQ3vi+RSfjwkYnB43JwJbflfZ0tntLGZdgk9tVpAuDjx483/TsmJgaDBw9GcHAwfv75Z8ydO9di+8WLF2PRokWm31UqFQIDA1utPRwOB+8/1BthnlK8t+tKg9vLxE071cn5FXBzEsJdKrQ5c3xN/A08OSQYbs7CJh2fOBaN3oC1h1MR5SdDLz85diXl4vP95hfjA4Jd2zUAPribO6L9ZKZUnY8NrMnW0C+IalcSx1VTw/WOq3nleGXLeXw9c0C9+wwKdcPKx/rial45fORibDubXe+2l3JUjSq5UR9nIQ/ns5qWMuhClhIDQ1xxNbcc5TZqkhuMDN29nJFSYB6cD/Vwxr1R3s1qLyGtzWAwYMuWLaisrERcXBwSEhKg0+kwZswY0zY9evRAUFAQjh8/Xm8AvK0zDZGO42wjMz71DZRDwOPifGYZtBoGVXVNlo7bw2QrNAZ4uYhsDoj1dhHj5XsjMLS7/co8EUK6Lg6Hgwd6++GXs1kQ87noH6RAldZgFijRG+4M/hfxuTiVVmK1NqyniwipRc0fsFmbk5CHNx+MouA3IaTDSCmoaJX63b5yMSStNHvQSchDtJ/MFPwGAHWdQFO11gBltQ7eLiLkN2GSljWHrhXi0LVCADXZ4ILcndA/yBX+CgmqtHrsu1KAhWPCMamvf4tehxDSMal1BpxKLcHgbm6I8q0p2xgb7IoEG31jU8p5ebuIYGAMyfkVuFZQgShfmVkd8doivKWQimr60sJyDa7lV0AuETS5rxPxOdDoG58105XicZ1Cp6oBXptCoUBERARSUqyPuBOJRKZaj7d/WhuXy8FTd4Wgl3/Dxy6qMA9YhHtJAQA9fKSI9nNBgJU6qxIhD908nG0et1Jr6HD1D0j72nY2C/3e2YuP9ySDy+HA00WEp+4KMdtGwOOgsIUXt02170o+tp2rP5BHiCO6XmA5uvCvy/nILquGRl9/Rg9vmRgjIjyxYmpfbH56MIaFWwY/5BJ+i4LfQM2DTQ+peZoyFxEPgW4SuDkJrO7jIRWCy+Eg0scFEoH1khtOQh76BMgtgt8A8P5DvSDgddrLDeIgkpKSIJVKIRKJMG/ePGzfvh1RUVHIy8uDUCiEQqEw297b2xt5eXn1Hm/ZsmWQy+Wmn9YcZEk6DrXOgC/rmd3TP0iBQaFuiPGXo5uHMy7nqHA6rRTaW8GhugmiSiq1CHS1XucbAMb09MKel4dT8JvY3bJlyzBw4EC4uLjAy8sLDz30EJKTk822UavVWLBgAdzd3SGVSjFlyhTk5+fbqcWkNT06IAAAoNYbcTajDGpdzeCdCG8p+gTIzTL+VOmM8JWLoXASQCriI7BWpotTqSWI8m35M5hgdye8Ni4S3jKaYUMI6TiW777SpNJi1gwOdUNRhcYsYN1U7s5CxAa7ol+gAlzAauaOunKV6lZPXa43MtwsrMTWhCx89vd1fHM4FalFlXj5p0T8dt5+JRkJIW2jpFKLx78+gZn/O4XhHx3Aa1vPI8ZfbirxWB+1jUzHdXnKRKZ4GmNAnqoaoVbiZNF+MlzLr8DZjDKczShD5q2JpMpqHZxEfAh4NRevzkIeQtyc0NtfhgHBrhgYUvMzONQNLmI+wjydoTfCFOeTCnkYEFyzfkCwK1ytPDOttDFJiHQcnfaJdEVFBW7cuAFfX1+7toPP4yLIrf6HWQAQ5SuzGP0sdxJgUIgbeFwuLuWUQ29k6O7pjB4+LvCRidE/SAEhn4ujKUWIDXbFgOD6Z83mKNtvVi/peLYmZKHqVi02/a3i8eN7+aL2oKowTynS66Slaw+Lt13AusM38efFXHz+93Wcb4PaRoS0FmZt+koTGI0MmfV8z1764Rx2J+U26jh3hXngwykxmNDHz2y5slpvdbBUU1Ro9ChX30lHeVeYO8DhILOkGiVVOvQLVEBQZ0RmN09nnEwtwZn0UqtlOWIC5BALeFZrkge4ShAX5t6iNhPSGiIjI5GYmIiTJ0/iueeew6xZs3D58uVmH2/x4sVQKpWmn8zMzFZsLekIdAYjFv2ciLRi6/263shwKrUEF7KVuFlUaQp828LjWR/x7iMTY+VjfSGXWB+IREh7io+Px4IFC3DixAns3bsXOp0OY8eORWXlnfvZl19+GTt37sSWLVsQHx+PnJwcPPzww3ZsNWktg0Pd8MKo7vCT1wRHMkurUVqlRUG5BpklVRYPLnPK1OjuKYXRaASvTvpbidD6wMmmWDG1L2YPDYU7pZgkhHQQx24UYd+VghYfx8gYdI24frSmf5AC3TycUVypRUJ6Kc5llqFC23BgydVJgGA3J1zItrx3bwtGBrz168UWP2shhHQs/zuSisRbz/jzVRroDAxX8lQ2+zQel9PozLSDQl1xsU5piJJKHTJLqjAo1A0+tQZG2iq1kKdUI9xLChcRH5VaA9JKqpCUrcKZ9FKcTqv5OZlagnK1HjcKK2EwMmh0RsQGu8JJxMeZ9FLT81BfueXz2JSCika9H2JfnSYF+quvvooJEyYgODgYOTk5WLJkCXg8HqZNm2bvpuGGlRlvtVVo9BgY4goOOFCpdZCK+DiTVgo+l2OqH56nVJvtk6e683tCeikivS3rnN+WU6audx3p3H4+kwmpiI/hEZ6mVB519Q9yNdUNPpJShNE9veHpIoJMIjDVXatv37amMzC8u+sKIr1d8MzwUPi3MHhHSFuqW7OqqXKU1YgNdsPptFKLtDxn0kvxzPBujT6Wn0KCoWHu2FlntDSXA4S4O9UbkGkMlVqPCG8pXJ2EOHaj2KxG2LnMMoR5OsPVSQgul1OzvJ7rV2+ZCMHuzjiXXgpdPaPfR0Z6tvi8EtIahEIhunfvDgCIjY3F6dOn8dlnn+Gxxx6DVqtFWVmZ2Szw/Px8+Pj41Hs8kUgEkYgexjuy93ddwR9J9WcBaGrPJuRzIeRxcX8vH3C5HLg6CVFYrsH+5AL894l+cBFT8Jt0DH/++afZ7xs2bICXlxcSEhIwfPhwKJVKrFu3Dps3b8aoUaMAAOvXr0fPnj1x4sSJektHkM6Bw+Hg5TER6OUvx6p915FSUA6d4U49b1+F5azB22mA04qrEOTmZKoH3pzSr3wuB8MjPNHDxwXeMjF6+8ub/2YIIaSVVah19WYHaqrTaaWIDVKgWmcwPRvOV2mgrNbZ3G9giGujZnpbE+HtgpMtmHHeHMHuzvRMgBAH41wnzsDlosEBPQYjQ09fWYNZL2o/o6zr9iB0N2chBoe6QaM3mgLx1kT5yWymZLfmej1BbamV8sZpxVXQ6A0Q8Vs+6JO0nU4TAM/KysK0adNQXFwMT09P3H333Thx4gQ8PT3t3TT0CZQjOd8y7e1tWr3B6sWJvgnpcgQ8DgJdJchTqS06FJmk0/w3kiYqrtDin1svwE8uxlczYhEToLDYxqVWB7w7KQ9LJkQDAHT6O7V+7D3WMjm/HD+cysSB5ELc39sXQW5O6EUPM4iDCXB1gpDPha9cjFV/X8PRlGKz9cPCPZFZUgV/haRRdW/uj/FFekkVfj6dibJqHQxGhoySarg7C+Ei4tusx20Lh1MzStH0J6hOB3GjsBJAzcCu29lI6uoTIEdWaXWDF673RHo1q42EtDWj0QiNRoPY2FgIBAL8/fffmDJlCgAgOTkZGRkZiIuLs3Mrib2czSjFppPpFsvlEgEifaTggGM1IwZQk65XJhZgZKQn5gwNhVpvQHJeOUZEWA4IMhgZKjR6mvlNOjSlsmaWmJubGwAgISEBOp0OY8aMMW3To0cPBAUF4fjx41YD4BqNBhrNnXJMKpX1+n2kY+ByOYgJkGNkhAeKKzSo1hpM152Xcspt1mD0lolMAXBOE4cKje7hhTyVGksmRCHY3XYpOEIIaW86gxELNp/DkZRieLuI4OosQFapGhWNvC/ncixL5CRklFlsF+MvBwOQZGWWdncvabOD30BNybYBwa6tUr+8sd6eGN1ur0UIabrmBHDrlngUcLkYEOKKKo0eUpEABeVqOIv4uJKrMuv3TqWWYHCoG06nlVj0h2I+FxE+Lo0qC1FSqW3UYJ7bk0ptxe0a61RqCXr7y5Cv0qDgVplZg5EhtagSPXxav/QyaT2dJnL6448/2rsJVql1Buy/WmhzG2cRH+FegnpHkDTGxZyaG8xBIW44lWb+Bc9pZPoI0vlUa2supHOUarz16yXsWDDUYpupAwLx85lM3CisRJ5KjbSiSoR4OOOpoSH44sANADCrTeTpIjLVAxfyuDAwBlcngamuhr9C0uiUJADQL0gBNych/r5qOwXUmfRSjOrhhT4BCvjIW7feECEdhZeLGDoDw0ujw9EnQIGvD900DXY6kFyAGH85Lueq4KeQQCER2AyEy8QCvDY2EtMHB2HOhtO4ll/zN6S4UovBoW7QGmpSTTbl5tVfIYGTkIf04koEuTtByOPiSm796c+4XA4uZCnhpxCbZRs5n6WsScduOwEKerZC7UdCWmrx4sUYP348goKCUF5ejs2bN+PgwYPYs2cP5HI55s6di0WLFsHNzQ0ymQwvvPAC4uLiaBZjF3U2oxTzvkuAzsAQ4u4Ed6kIlRo9Siq1t+o0Wu9zBTwO5o/sjgX3dLcYOGQtXRpQk66Ngt+kIzMajVi4cCGGDh2KXr16AQDy8vIgFArNsmYAgLe3N/LyrGdNWLZsGd5+++22bi5pRb5yCZ4YHIxhEZ5Qaw3Yfi4bu5JyYWQ1s7TrUzvLrbbWgOze/jKIBDxkFlchv1xjsZ9YwMW6pwa26nsghJDWwhjD679cQPy1mue/xZUa6G8NZLRFKuQhzEsKjd6IjJIqSAQ8+CnESMq2HETU3csZWj1DUYUGar0R/goJwjydodYZwOFwoDcwXCtoWRCnpFKHsqpSuDsLUVypbdGxGkPE5yKKngkQ0qGtO5IKmViA6YODGpWt4WK2Ev/db54JI624ErlKywzF1mZzn7wVBK/S6k19oVzCh5eLGBeyWr88AwODk4CLKp2x4Y0bkJStgojPxeBQNxSWa2BkDDcLKQDe0XWaAHhHVViuQUml5Q1cbTcKK9Hbv+VfhABXCTJLLdPeHr9RbGVr4giO37zzf5tSUAGjkVkEzArKNcgqvROwHvnJQQS7O+G+aB/wuBwYjAyJmWWmPzrLJveGs4iPf+9IwruTeqFfkCuEfC42HEtDQbkaM+NCkJRVhmg/Oc5mlMLLRWyqa+wlE+H4jWKsPZJqCqpXaw344un+2HclH2/9egklty6i+wUpEOUrw7BwD/grnOCrEMPVSWizNgchjsBfIYG/QoJBoe6YOiAQS3dewsHkQvxrexIeGxiI74+nY/mUGPT0dUF3r/rLWwA1AegAVyesmzUQr2w5b7pwrD3SMcJbagqO29LDxwXFFVrTAJeUBsp3eMtEuJilhFpvRIS3i0W5jeIK23/7BDwOvGU02IXYX0FBAWbOnInc3FzI5XLExMRgz549uPfeewEAK1euBJfLxZQpU6DRaDBu3Dh8+eWXdm41sYfUokq8/dslBLs7wVsmwuUcVaNKTsQGu+KtB6PQJ1DR9o0kpB0tWLAAFy9exJEjR1p0nMWLF2PRokWm31UqFQIDA1vaPNLGAt2cEOAqQaXWABcxHydSS1BYrkFqUYXVmYwAzIJBl/NU8HYRoVKrh5EBZ9JK0TdQAamYj4f6+qNSa0C1Vo+7unugmwfN+CaEdEyMMXy0JxnbzmablvX2l+Nc5q0MKc5CBLs7wWBguJCtRLC7EzykIpSrdbiWX4HztQI6VVoDunla9ncCHgcVGoNFeUyJkNvgfXtTGRmgcBIgzFNaU9OHMeiMDBwAfB4XpZVa0yD+1KKWvbaziI9LOUr0C3JtecMJIa1KZzDi9a0XsO1cTd+WU1aNf97XAwBQqdHjSq4KKrUOqmo9VGod9AYGsYCHZbuvWGQ1zlWq0S9IgXN1slqU1DPQJqu0Gtll1egXpEBZlQ5FFZoWTRy1RSYRtErw+zaN3mj2TPZKrgr39/ZtteOT1kcB8BYKdHNCTIDCZr0BAEgrqoSbswAllbZrudjiJ5dYzP4GgAfoS+aQDlwtMEttpNYZMOmLo7g73AOv3/qDBAD5KjU0evOOPL24CmsO3TRbptbp8cq9ERgZ6Qk+j4u/Xh5hFoyee3eo6d/+ipqZSoFuTgCAuDB307qRkV6Y3N8fT649iaIKLULcnfHI6mMY2t0DvzwXh7+vFKCXvxxDut3Zh5CuKsTDGf+bNRDv/3EF646kYk18zffylZ/P4+NHYxoMgN8W6OaEzf8YjE/3XsPqgzfM1skaWTe2WmtAYQNB69v8XSXgAlDf6luszVTvHaCwmZrIQyqiAS+kQ1i3bp3N9WKxGF988QW++OKLdmoR6WhUah02HE3DN4duNqm8BI/LwbKHe+PR2ACqbUgczvPPP4/ff/8dhw4dQkBAgGm5j48PtFotysrKzGaB5+fnw8fHx+qxRCIRRCJRWzeZtAEOhwOJgAfGgOHhHvj7Sj7KqvUI83S+VTbHnLtUiH6BCgh4HPC4XPC5NQ8KT926r03MLMNjAwLx/Kju1G8SQjo8o5HhvV1X8L+jqWbLz2Uq4e0iglpvQEmlFiWVWkgEXPjKRZCLBajQ6OsdpF6utrzW7BfkavXemgNOk7M0NsaNwkqrfXhtzkIeevnLcNHKbPXGmDM0FG+M72G1pBohxP7+vJhnCn4DwPqjaXi4vz8EPC6e/S4B6cVV9Zb9skartwwyuzkLzX6P9pNBxOfi7K1Aed2AeWvq5SeDs4iP4gYmrrbUtVZIr07aFgXAW8GHU2LwxYEU/HY+p95tyjUGDPCRobSq1CwtWFMYwdDLX4bLOTX1E7xlIrg6CTFtUFAzW046qsySKiz8KdFsmd7IkJStREpBBR6M8UW0nxyMMWxNyGrUMf91f5RZULolgakePjLEv3YP0oor4Szko1Krx/X8CmSUVOMfw7o1+7iEOCIul4N/P9ATUhEfX8XfgEZvhNZgxMq91/BgjF+jv4t8Hhf/HBeJ06klZmnPDY34oyLgcSAUNO7GMzbYFdfyy81uzC/Wqj/m5SJCoJsTrubZvhF2lwptrieEEHtjjOHz/Sn4+tDNRtdvvG1QiBuWToxGlB+lOyOOhTGGF154Adu3b8fBgwcRGhpqtj42NhYCgQB///03pkyZAgBITk5GRkYG4uLi7NFk0saMjGHtkVQonASQCHgoq9bDRWQ5AFMi4EGnZzh3a3LAoFBXHE8pRaSP+YDPEA9nCn4TQjo8rd6IV7ecr/dZb91yDtU6I6qVGuQqa5bHBims1vjmcTnoG6ioSaNuYGBAvQPLrxdUYFCoGyQCLlIaCFi3tkqtARezVQhxdwKfxwUHgPxWGbdKjR6XciyfBwj5XDwY44vxvXwxpqcX9fWEdGBRfjK4OglQWlUzWbNaZ8DYlYfgK5egWmeA1tC0WdNVWstguVpnQJCbEzJKqhDq4WS132htTkIeevrIkJDR+HKRLVE3cwfpeGgYViuI9HHBZ4/3xYBgVwh59Z/SM+ml8G1BOtgzaaW4mK1CoKsE4V5SCPlcVGr1VE/ZwWj0BizYfBbKauvZAqp1Bjy25gTOZZTind8v2xx4UVsvf3lrNhPOIj6i/eQI8XBGtJ8cD/Xzx4gIz1Z9DUIcBYfDwcv3RuDw6/eYMiykFVdhzIp4VGkbH3ThcDhYN2sgomsFXC5mK9GrgTIb/QIVuN6INOkDQ1yRkF5qMSq9SmuAiF9z8xri4YyE9FKoqm23WyLgNfh6hBBiL1q9Ef/anoQVe681OfgNAFMHBlLwmzikBQsW/D979x3fVPX+Afxzs9M2Tbr3okAZZY+yl8gQQcSJqAwFByB8cSAqAvpVXF/05wInQ0Fc4GCpbJBdKGWWFrr3StKmbeb5/VEaGpq2aZs0Hc/79eoLcnNzc07Gyb3nOec5+P7777FlyxbIZDLk5OQgJycH5eWVs8/kcjmeeOIJLFmyBAcOHEBsbCxmz56NwYMHY9CgQU4uPXEEIZ+HxWM7Y/eFHIzo7AsASMorQZdqge2+oQqU640WGeuylRWQSwVwFVmeE3antpO0IStXrgTHcRZ/XbpUZuwrKirCwoULERUVBalUitDQUDz33HNQqey/ximxr1KtAU9sPG1zf1t1fA6IifAEj8fBWvz3UpYacelKpBeVI1tVUW/w5FRyEZLyNRgQ7pw04imFZUjKK0ViXinOpBbjVHIRRAIefGWWmV2EfA5bnozBmgd7485ufhT8JqSFi/Rxw1//GYEH+t3K9GRiQKayHEUanXnpU1uVWbmmjs9QIa2oDL4yMUI9HbPcTd9QBXoGyxHu5YKOPq7wlYmbLfgNgOJyrQDNALeTd3ZfRbaqot7RMfZYcSC1qLLzoVuAOyoMRuSqtfRlayM0WgOe++Ec4jPqviAq1Rpw7+fHbD7upB4BcBPT150QZ/OVSfD8uM5Y8tN5AJVraqnK9XAR2f79lLsIsXHOQAx/9wDK9UbojZXrddXGTSwwp52sTbeAyvXBT9exX4inCxQuIsTZeCLp5UqpTgkhLRNjDG/vuoIfTqU7uyiEtDhr164FAIwaNcpi+/r16zFr1iwAwIcffggej4f77rsPWq0W48ePx+eff97MJSXNxWRi+PbfZGyZOwgFGi12X8yGusKAqiRGPYPk5lSW1aUXl6OjjysuZKrgKxMjr0QLAY+zuv4tIa1Z9+7dsXfvXvNtgaDy2i4rKwtZWVn44IMP0K1bN6SmpuLpp59GVlYWfvnlF2cVl9QjuUCDZzefxZXsxs1UNDLAaGIWWduaKkghRVJeKXoEueNCI1OS21NV2uJewXI8O6ojPN1ECPaQIkAudW7BCCEN4iuT4P0HeuGxwWHYeSHbvGxjY/jJJTUyY1TJK9Ei3Nv2dOq28nET41yaEn1CFdAbGVIKy+z+HLX5/okYdPBxxfZqaeRJy0QRMTtxEQnA5wEdfd2QlFf7LLtAucRuqRGU5ToMi/Sm4HcbkauuwJwNpx2SDmRMF1+7H5MQ0jjDO/mA4yrTh704PqpRF4nebmJsmRuDuZtiUVCqxYVMNbr5ywCOQ6ay3CKDRCc/NxvW1eFqPVGtkpSngVhQju6BcnNqy7o0ZkYlIYQ4UpFGh53xWfjuRGqt6zIS0t4xG5ZWkUgk+Oyzz/DZZ581Q4mIs/F4HF69qyvcpULweRxGRfnij/NZqPqkqCusZy4DKrOG9Q31QEJuCQZ38EKuuqIyi5BzJjIS4hACgQD+/v41tkdHR+PXX381346MjMRbb72FRx99FAaDwRwoJy3Hn+ez8PKv8dBYSeXbELGpxRgQ7oGEnBKoraz53VBiAQ/+cjdczVYj2EOKjGL7rgneUFIhH3f1CMArd3WBlxsNfCektesZrEB0oBzn0pS1LslgjYjPITpIjiKNzmLpRGv0VtYIb6g+IXLEpavM56C+7mKUVOhxLl0JsYCHrgEyXMlunjW5z2co0SVABrm05rJApGWhFOh2smhsJ6y6JxpFGh36h3sgyu9WOrBewXJ4uFR+GSR2TAmbpazAKApstgmnU4ow9bN/HbYWRmIdgzIIIc3LRybG/z3cB38uGIYZMWGNPk6fUA98O6u/OfWYTCrE5Ww1tDfX2KkisGGN8WxVOSSC+k8JqtYvt4WPjNYAJ4Q4j95oQpFGh1PJRfjy8HUs/OEcYt7ei59jMyj4TQghDeThKgL/5jnlvBEdIBLwkKvWYnAHL3i7iuEist7PcT5DhdTCMvDAIVtVju+fHEjLR5A2JzExEYGBgejQoQNmzJiBtLS0WvdVqVRwd3en4HcLU6E34tXtF7Dwh3NNDn4DwMAIT5xOKbZL8BsAbhRoEJtaDI3OCLnU+Z+dAIUEj8SEwp0CP4S0GTweh08f6YNgD9sm6YgFlcHvs2lKpBSWob6M6aUNWP6xCgcgOsgdEd4uCPGQ4ly6ClH+MvQMrlzmVSLkIzpIDsaACr0JXJ35Me1r3aHrSMwtRQBNTG3xnP+r2YaMjvLFt7MGYPb6U9AZTOjg7QoPFxE4rnINhb6hClzKUmFguCeu55eiUKNr8nO6UlrrVk9vNGHBlrPIVdc9+7IpxnalgRKEtCRTegXa5Tg9gxX4+enBmPb5MfMISJlECC9XEYR8DtfzNeBxHAaEe4DjOMSlK6GzMuqyuEyPjr5uUJfroS7XI8zLBQm1BIhSC8vQP9wDfI5DjqoCqUXWUwxN7R1sdbuzleuMkNbSSUsIaRue++Ecdl3IhsHKVXh8hgq9QuQ4n07rbxJCSGN09HXD0EgvHEjIh7pCj0tZavQP86g13W+OugJ9QxU4m6bEg1+cwOEXR4NnwwBNQlqDmJgYbNiwAVFRUcjOzsaqVaswfPhwXLx4ETKZzGLfgoICvPnmm5g3b16dx9RqtdBqb/UPqdXOT3nd1qTfvIYV8DnEpSnx8f6kRqc8t+ZKjhq9guU4b2V5Q5GAhyg/GaQiPq5kqVFiQ+Y0jgOqErRotEYEyMXIVjmuD7E+N/I1uG/tMXi6inBXD3/MH92R0p8T0gb4yiTYOGcgnv4uts7JdEIeh06+MqtL4Fjj6SqCQiqEp6sIRbXEwxQuQoR5ukAi5EOjM8BkAtKKynDxtmUfruaUQC4Vok+oAmAMifka830FpVpEervieoEGjqYzmKA3mqjtawUoempnvUMU+GfJSDzy1Ymbs0tufeGqGoVTKUXoGSS3SwD80/2JGNzBCyIbZu6Rlum9PVcdGvwGAAGfPh+EtFVhXq6YN6IDNh1PBQDkl2qRX6pFhLcrBkZ4Qlmmh4DPQSLkI1AugY9MjOv5GvNJp5DPoWuAOy5nqRDq5Qq5VIi8Ei3EAg5aQ83gUanWgDM31wrv4O2KvqEK5Km18FdIADDwOR4S80qRW2Kf5T7s7XK2Gv3CKO8mIW3Vmr8T8Mf5rFrvr2qzmsJFxIfUjlmdCCGkNZEI+Qj2qMw2ZDBWnism5dedWaNq9nhGcTmy1RUIUlBnIWkbJk6caP5/z549ERMTg7CwMPz000944oknzPep1WpMmjQJ3bp1w8qVK+s85urVq7Fq1SpHFZmgcube5pO1z9RvKnW5AQyAVMRHuc6IbgHuEPA5mEwMyjI9LtxMFRzmKUWPYDkMRoYynQGuYgFKKgyQSQQoKtPBVSRAtrIcBaVahHi5wNddghv5pfBwEQFwXgC8SpFGh+9PpOFqdgl+eWaIs4tDCLGDSB83bJ8/FEt+jMPfl3Ot7tMnzMPmVOmeriIYjCacvtmP6CcTI9hDimt5pSi5mSVDLhWAz3FWBw1ZoyrXW13qMcTDBSmFGvjJxPUu89gUoZ4u+Hh6H6QUaOBNy0C0eBQVcwBvNzEeHVR3Wlt7zT47nVKMb/9NtsuxSPP7N6kAXx1x/Pv3b1KBw5+DEOI8vUMUyFRargOWXKBBUm4Jisu0uJSlRkFJBUq1BmQqy6G4maos0scVMokA8RkqdPBxw418DRLzSmEwMqvB79vdKNDgbJoSGcpynEkphqrMgJPJRSgu0yG10PrMcGej4Dchbde13BJ8vD/J6n0cV9lWVrVZTTEg3BOTegY06RiEENKaje3mBwAwmCozC5kYg0jAg0jAQ38r51olFQa430zbm0TLc5E2TKFQoHPnzkhKunU+UlJSggkTJkAmk2H79u0QCutOG71s2TKoVCrzX3p6uqOL3e7MH90RQr5jM1HEZ6igkAoQ4iHF5Ww14jNUuJiltjgPNQGIT1fiVEoRLmapcTK5CJezK/9NzC1FXLoSuSVaGBmQUliGU8lFKCjVIUfdcgab9w5RYOOcgc4uBiHEjtzEAnzxWD+snNytRlvZPdAdZ2vJ+mNNsEJqsRxEbokWsWlKyCVCDAj3QL8wDxhNaPJEUTcRH7FpxSjU6BBSbVlIexoS6YXf5g/F3iUj8dXhG3jh5/PYczHbIc9F7IcC4A7y8IBQDO/kXev99YcVbBfi4ZgvNXGsK9lqLP4xrlmeS2NDSiVCSOtV29pbIgEPPK7ypz61qBwFpTpwALzcROAA8DgORRo9AOBabilGRfkgQC5BsGfDZ+UIeBwULpXlYAz453IOtIamr59GCCG2+ul07R3EfUM9EJeutMvzVAV8CCGkvQrxkCLUU4rrN9NOqssNcBXx0SNIjjOpxehebZ3vAeEekEkE8HQRAQCe/i4WRxLznVJuQhyttLQU169fR0BA5UA5tVqNcePGQSQS4Y8//oBEUv9aoWKxGO7u7hZ/xL5cRQK4NcOSktkqLdKLrQ+89HIVQas3obQRa46XNGFtcU9XEboFNO4zFe7lgju7+eHungG4t08Qlk3sgq3zBtHynIS0QRzHYdbQCKyfNRA+biKEe7lgYLgHkvJKrS41Vpv04jJYW/kmQ1mO0ynF0GgNKLVD3CKo2trlsWmW56L2wudxkEuFEAl4EPA5GEwM359MQ74DZ5uTpqMAuIOIBDysebA3eocoatnDfiHwrgGy+nciLUqeugLzt5xtlgYy0scVL46PcvjzEEKah9HEYDBaBl+6BrhjfHe/GvvmqLXguFu/Nx28XZGr1uJ0SjFcxXzIJAJ43Axax0R44mBCPvQGI8QCHgaEezTohJEBKCi9NWIzpbAM59OVYMyeQ74IIcS6pLxS81IQ1thzMGBKQcvMcEEIIc0ltagMmUrLGYilFQbzQKPqp3/39A5CSmEZUgrLEKyQolxvxH9+jDOvwUtIa/bCCy/g0KFDSElJwbFjx3DvvfeCz+dj+vTp5uC3RqPBN998A7VajZycHOTk5MBopIHCziQW8nBnt5rXz83BTSxAr2A5Qj1dkOeEoEmYlws+fKg3/lo8ArOGhOPObn6Va+neJOLzIJPcCmiPjvLBt7P649zyO3HwxdH46vH++PSRvvjwod54amQkJLQsECFtWvdAd3z4cG/kqCtwKqUYWoPtg8F5HBDu7Yq64uWuoqYNoAlWSNEv1AP51fojGQNEDsjycSSxAOsOXgcALLqjE4DKpSCOXafMuy0ZDdFyIB+ZGN8/GYPBb+9DSbVON6mQh1PJxegbqoCLSIC4dGWTRrqkFZWhg4+bPYpMmskzm8/iRr6m/h3tIKaDFzjOsamdCCHNh8/jcDAhH8M7+ZjXUwSA1yZ1Q5FGZ15Xp4qHixjZKi0EvMolOm4UVLY9pVojBHweisv0ULgIcfLm+j1ebhLEpd9ad6dfqALpxeWQuwjh4SLCubRi8HkcKvQmdAtwR3pxGUoqDOjo64Yb1VJa6gwmZCrLobqS57TOBVtdzVHjbKoS+SVaGEwmjOniizBPF6grDDiYkIepfYKguDlriRDSMu2Mz4bOaP1ivIO3K67mlFi9Ty4Vok+oAhwqM2HcvpwEAEwfGIqHB4SAx3HQGU0IdVBKNUIIaS3+PJ8F4229mXoTw8AIT5y6mcK3i78MBaVaiAU8vDCuM5b+esHcTheU6jB30xn838N9EOVPA/pJ65WRkYHp06ejsLAQPj4+GDZsGE6cOAEfHx8cPHgQJ0+eBAB07NjR4nHJyckIDw93Qonbp2u5JTiTUowTNwpxo6AUnX1l6BboDqmQj3K9YwcjdLnZxinL9AjzkuJUcrHN69xWifCuXLosV1UBmUQAPo9DjroCqvK6+5IFPA4hni6IDpLj/n7B6Bkkh9ZgQqayDH1DPbBySncAgNZgxMkbRTiQkId/kwqwZ9EIZKsrwOc4+Mvrz1pACGm7PFxFGNbRB+se7Yelv8YjV23bwB0+B0QHy62u1V1dbFoxooPccTFT3aByyaUCdPaT4XRKsdUlzgR8x8z7DVRUzjS/lluKucMj0NlPhjFdfB3yXMQ+KADuYG5iASJ93cwjobsGyHAjX4MwTynOpikxINwDHq5CdPJ1AzggIacEZQ1Mf5Ojajlrv5C6lekM+PpIMmIbsFZGU90+U5QQ0voN7eiNLGU5/NwlEAkqT+pCPF2w/O5umPLpvxb7Xs5WIybCE9mqcpxKKTJv95GJzclIlGV683Yjs2wzYm+erFaNTvd0EcLXXQKpkIerOSXoESTHufTK4HFnfxkuZd06aV366wW8NTXabvVuKqOJIaO4DJnKcmQUld9cw7wYsanFFp24n+xPwuAOXkgvLkOuugK7LuTgx6cG0WAiQlook4lhR3yW1fuEfA4iQc3v7sAITyyd0AW9guXmi2OTiWH/1TycSilCZz8ZTtwoxKgoH9zdM9Ch5SeEkNbEZGI4fM36TJdsVWUHpEwiwNWcEogFHIZ18jb3cXi6isznlFdzSvDVkRv44IFezVNwQhxg69attd43atQoyobVAqQVluGRr06ik68bAuQS3NMrCJtPpmLbuUyHPF+vYDkkQj4YgCKN1mIQpsJFiECF1OqAy9v1D/NAcoEGDAzJBbcm0OTebENlEgG6BbjjWq4atU3IfGJ4BF6e0KXGdeztQW2xgI8RnX0worOPeVuQouHLohFC2q5RUb7Yu2QkXvj5PP66lFvnvgIe0C1QjvPptg32cRHWHqLs4i+Dq1gAHgdw4FCuN6K4TIdsVUWNCUDVXcsthbebyCJTpT0cScyHq5gPg4nh1Und7Hps4hgUAHewknI97u4ZYA6AX8kugaerCKXaygtAHschvagc6UW3Tn56BstxMVNVZ3qI6rzcxPYuNrETxhhSC8tw7Hoh9l3JxdGkggalCrGHPqEezfp8hBDHE/J5CLEyA9Fa+9InRI6UQg1UZXpEB7lDIuAjpVCD/BJtjWUY+oQq6sxOIRXxEenrhiKNDldzShAd6A6dwYROvm4wMQbGKtd5rDoJ1RlMTknrdrsynQEbj6Xiu+MpyLJx0JjWYETGzfXaLmWpoCzTwcOVfm8JaWl0BhM+3HsNidUyUFTh8zh09rMcmFMlo6gM/cIsz5F4PA5ju/lh7M2sFff3C3ZMoQkhpBW7lleCglItOM4y1TlQmToXqAycXM0pwTOjOiJALgVjDJN6BqCoVAs/mdgcwLmcpYbJxMCztjgkIYTYQaiXC868NtZi2+NDwjD9yxM4W8/MxIYQC3iI9HGtc3b31ZwScBwQqJDAXSKEskyHHCuzKX3cxMhQlqNQU3vgpqTCgMvZani6itDR1w2qMj0MJhP0RhOCFFKUag344tANTOoRgJ7BCntUkRDSzskkQnzxWH8cupaPlX9cshicU13fsMqMQLY6lVJk0ZdYJTrQHRetXMvbQlWuR/8wD7sHwM+kFiNbVYHt84fY9bjEcSgA7mCpRWU10pu7iHjIKK7sgC+pqJmuJj5DhR5B7shSVtR5slPFy43SsrYUVQHvf68X4FhSIY5dL0BxtZmVzeXNe7ojv1SHPiEKDOrg1ezPTwhpfoWlWiz/7SJ6Bssh5PMg4HG4kKGEgM8zpyiqK6VQkEKKS1lq6KwE0WXiytRCPB7MJ6RuIj4yleUWbZxMLECXAMs0lhuOpWDmkHC4iZ13yjFvUyyOJjVsTR4B71a6pK4B7pQCnZAWhjGGEzeKsOKPi7iWWzP4DQA9b2aouJ2bWIDPZvR1cAkJIaRt2nwiDQAQ5SersbxEhd6IoR290DNYgR/mDoKHa+X5E8dx+OD+nnh52wWcS1eaU11ezlbj59h0eLuJcUfXlr1kDiGk5ctWlePnMxlIKdAgv1SLUq0BoZ4uEPB4EPI5eLqKMGNQGIIUUtzXL9huAfBAuQQSIR+Xs60vuVMdY0CWsgJZqEBMhCfCvFzBUJmtTG80oVxnREqhBnqjbbOiijS6GoEmBkCp0WFyrwCU64yo0BtprW5CiN2M7OyDPYuH4+sjyfh4X2LNyTiNyH5yI18DiZCHCv2tYzW13bp9uR57iQ5yh6+MlodoLSgA7mAR3q5Ye/C6xbYAuRTZygp08pPhcrb1YMSFTDVkEgH6hXogNq3udNlphZVrt9QmR1VBa7Y4QIXeiKS8UpRqDchVV+BYUiGOJhXYlMrIkf47NRqPDgpzahmIY61evRrbtm3D1atXIZVKMWTIELz77ruIiooy71NRUYHnn38eW7duhVarxfjx4/H555/Dz486ltqq1KIy9A5RYOvpdPO2cC8XpBSW2fT4AIWk1vark59bjd+ibkHyGhfaXQPdcT69GB19XOEiEiA+U4X8Ei1+O5fptHYpR1Xe4HZZLOAhKa+y80Iq5OP1yd0o/TkhLUhsahHmbYqtd6CovpZlYF6f3I0y5BBCSCMlF2gwfWAoMorLkF9SORNcVa6H3sjwQP8QPNg/xLw+YnVSkQBDIr1w/HohpNU6NL86kowPH+zdjDUghLRV3x5NxldHkgFUps3V6Aw11p/dfDINn0zvg+kDQtE1wB2Xs9Q4mJCPvVesp/T1lYkR7u0KMKDCYES5zgiRgAdXsQAlFXpkqyqQq66AjfFqCycbMEOyIaqyjO6/kofLWWpIhHzsWDiMrmmJ0x0+fBjvv/8+YmNjkZ2dje3bt2Pq1KkAAL1ej9deew27du3CjRs3IJfLMXbsWLzzzjsIDKQlqVoasYCP+aM7orOfDHM3nbG4ryGrsVYt51ChN9bIoFGub9gywbe7fVJqU0X5yaA3mdA9UN6gx2WrylGuM6KDj5tdy0NsQwFwBxMJeHjnvh747niqeWTh6ZRi9Ahyr3dkYEmFATmqMgyM8MTVbDXUVmaLA8BHe69hTFdfuEuEVu9f9eclfPhQbxrt1wQ6gwkiAQ+MMfx1KQef7E/C1ZwSh40kaixPVxGl62wHDh06hPnz52PAgAEwGAx45ZVXMG7cOFy+fBmurq4AgP/85z/YuXMnfv75Z8jlcixYsADTpk3Dv//+W8/RSWukrtDjel4pim4LBtka/AYqOy5rk15sGUAeEO6Bc7cFxAU8DqkFGkQHKeAq4uNcutKcwuh/fyegd4gC0UENO0m0h6Q8DXzcxCip0Neb+sjTVQRvNxHK9UakF5XDw0WITXMGYtfFHHTylUEqot9RQpzty8PX8fauqzbteylbDXepAOryW+fQfUMVeIDOlQghpNEWje2E+AwVCkorIBbw0C3QHddyS+HvLsHisZ3rfGywhwuCPaTmjEJCPoedzw2DWEDnWISQpntmVEf0CfWAkM/DyM4+MDGGMynF+GR/ojnYrCrX4/FvT6GjrxvGdvWDiM/hcrYKPA4WS1FyHNA9wB2qcn2DUvm2JBqdES4iAZRlOlzMVCM6yJ2C4MSpNBoNevXqhTlz5mDatGkW95WVleHs2bNYvnw5evXqheLiYixatAhTpkzBmTNnajkicbY7uvgi2ENqXkIQqFyKrC69guXguMplHIs1epxMLgKPA2IiPM1tdZin1OpSZg2RXKCBwkUIpZ2y8ybll2JIpFedE1GtcZcI4e9Ok1OdhQLgDibk83Bvn2AM7eiNCR8dMQcnOI6zKXga5OmKU8lF6OIvQ1leKQxWHpNSWIaZ357CxjkDrQbBXcUCSnfTRDO+PoGvZ/bHK9svYmd8trOLUyuFVAi90UTvdRu3Z88ei9sbNmyAr68vYmNjMWLECKhUKnzzzTfYsmULxowZAwBYv349unbtihMnTmDQoEHOKDZxoIyiciz//aJFqiBbyMR8dAuUo0xngKrcgBAPKVzFAriKBYhNvRXgzi/RmoPZoZ5SpBeV10jJZjAxGBkDYwyHEwvQPdAdp1OKEXJz/1nrT2HrvEHo6Cu7vRgOZWQMp1IqT6D7h3vgTIr1rCrdAmTIUVVYpFJePa0nOvrK0DdUS8FvQlqI22fx1IUxoKu/O3RGEwLlEswYFIbuAXLq+COEkCYYEO6J/mEemNo7EEl5pQhUSPHH+Sybsv0M7eiNtQevmwNNHi4iCn4TQuzG01WEu3oEWGwb1skbnfzc8PauKzh2vRBavRFBHi4I9ZSiR5Ac/yYVoEJvwpCOXtDqTdBojSjTGZClLG/02rMtyaUsFfqHe2Lyp0fhIxNj2zNDEOLp4uxikXZq4sSJmDhxotX75HI5/vnnH4ttn376KQYOHIi0tDSEhoY2RxFJA/F4HB4dFIb391xFv3BPgAGnU2sfNDQw3NPcRwcA/UIVyFFXwMQqs2JUBcE93cRILWpall2DiSHKT2a3bBt8Hgd3iRD5pRUNepyrE5eEJBQAbza+Mgl+nz8U285m4uC1PMRZWY/QmsLSynVbr+aUoF+YB86mFVtdRuFcmhKLfziHEE8XLJ3YBS6iW2/tBw/0skcV2jWtwYTdF3NadPAbAII8aqaaI22fSlWZIsbT0xMAEBsbC71ej7Fjx5r36dKlC0JDQ3H8+HGrAXCtVgutVmu+rVa3/gu99qRboDtGdfbFnks5Nu3v4yaGp6sI1/NLrZ4I9ghyR+8QOfRGZh5xyeM49A1VQFWuR5lObw6IB8olyCvRwmBiKCjVoVxnBJ8DLmWpzcHvquU8HvvmFP5YMAw+MrFd618XfbW1iK5mqdE90N1iFKm/uwSBCgkuZKigrzbILNzLBROi/QEAd3ajpQMIaQmS8kpwICGvQY+pauMemtYDQyK9HVEsQghpdziOg5ebGF5uled080d3tOlxOoMJ7lIBBoRXdm7WtlQFIYTYIltVjszicqjK9RZ/yjI91OV6qCsM8HMX4+mRkfi/h/sAqEyJe+RaPk7cKMS+K7kQCTiM6eKDMC8XrDt4Axpd01LutjQmBpxKLkK/UA/cKChFAC2RSVoRlUoFjuOgUChq3Yf6M51v1pBw/BqbgRv5pfVmXjRVC2x5ugoRn2mZ9vxMajGiA93hYqfJfelFtmfGrE+3AHe8PrlbgwblE+ejAHgzCvF0waKxnbBgdCQ2HE/Fmzsu17k/n7NMXxubWoxghRSBCilMYCgpN6BEq4e/uwRn05RIKy7D/oR8aA0mvHNfT0dXp13xc5egqJ4GvCU4kliAfv/di92LhiOS1pVoF0wmExYvXoyhQ4ciOjoaAJCTkwORSFTjBNHPzw85OdYDpKtXr8aqVascXVziQC+M74wjifk2XbDnl2pRrjegk58brlhZjuNCZuUFQ5BCgig/N5gYEJ+hRK9gOa7nawAAcqkQfUMVOJumxMBwT+SoK5BWVIbu1dYGTy8qR6BcYl4/PFtVgRd+Po+Ncwbaq9p1MpqYxdrlpTojruWWoIOPK9wlQhhNJlzNKUGOuubozQA5DShqK1avXo1t27bh6tWrkEqlGDJkCN59911ERUWZ9xk1ahQOHTpk8binnnoK69ata+7ikjp8tDexwZkuAEDE52Fcd38HlIgQQkhDiAQ8lOuMOJNajHt6B+LB/iHOLhIhpJUp1xmx+2I2fjqTjhM3bJvVl1+ixReP9QPHcWCMIS5diS2n0mpkNeviL0NaURnKWnEQPMRTCleRAJnKcoBVTpRxEfHBwFBcpscTG8/g00f6QFbLMpqEtBQVFRVYunQppk+fDnd391r3o/5M55MI+fj68f54fP2pWgPg3QPdUVyms8iI3Mm35uxso4nhYpYaUiEfUiEP5Y24/q8uS1WBmAhPxGcom3wsVbkexWU6DAhvWAp04lwUAHcCPp+HmYPDsOdiNk6n3Axqe0hhMjEwVjkSxsgYyrQGJN0MNFTJUJYjQ2mZ/iFLWYHoQHfzCJpLWWoYTaze9RaIbSr0RphMDBwHhHm5ILUBa+o2N4mQh1VTujfr7EriXPPnz8fFixdx9OjRJh1n2bJlWLJkifm2Wq1GSAh1SLUmHX1l+OCBXnjh5/M2BcFLtUaY6jn3y1RaBoZ11ToIrlf7fTqVUoQBYR6QSQQQcBz6h3ngzM0U6oEeUmSpbh3n0LV85JVUwFfm+JHnBxPysPbgdYtteiODi5BfZyaWXsFyfDy9DwxGEwR8noNLSRzt0KFDmD9/PgYMGACDwYBXXnkF48aNw+XLl+Hq6mreb+7cuXjjjTfMt11cKDVgS5JWWIYDVxs2+7tKvzAPeLqK7FwiQgghjTEg3AOlWgMeGxSG/uGezi4OIaSVmb/lLPY38JywUKPDExvPQCEVIspfhgf6h+ChASHYdDwVBaVasJupd6/mlCDU0wVpdpwx2Nx83MQ4W2124tUcywHvh67l44F1x7Hu0X4I93YFIS2RXq/Hgw8+CMYY1q5dW+e+1J/ZMoR5u2L+qI546df4GvdFB7nDYGAIkEtx4eaMb6mIj8tZqhr7VinXG9EvVIFYO8y2PplcBHeJAJ18ZTVmnDfE6ChflOuM5gxIpHWgALiTCPg8fDajLzKLyrH4pzjzbLkqriJ+gzrqqq9LcyFThTd3XMaKyd1ojUM7mPDRYYzr5ocijQ4FJdr6H+AkY7v6YtldXWnmdzuyYMEC7NixA4cPH0ZwcLB5u7+/P3Q6HZRKpcUs8NzcXPj7W58BJxaLIRbTD7ijMMaapT2e2CMA+aVavP77JfO2QIUEgXIpGACt3mjxe8FxDN5uonpTFFUx3DZC3k8mRpi3K04lF0Eq4kNZrsexG4UAKtf1ic9QQmcwgc8B1R+652IOHh8c3uh62srazG6g8jezR5AcibklqDDUHAVwJacEH+29hjfviXZ0EUkz2LNnj8XtDRs2wNfXF7GxsRgxYoR5u4uLS61tJHG+TcdTGp2ScnhnSn1OCCFNoTOYIORzdjmflUmFOJ+uwumUYgqAE0Ia7J37emD1rqvYfi7T5sfEphZb3H5nz1XMHBxu0W/KGIOyTIcLmWq8vetKjcCxLdzEAihchMgobtq6tU1hS/D+ak4JJn18BL/NH4pOfrJmKBUhtqsKfqempmL//v11zv4GqD+zJZnWNwg7LmTj8LV887bewQqcz1Sal/T1dBUh2E8KFzG/3iwe1vrrGqKjrxtEfB74PA5agxFpRZr6H1SLaX2C8NqkrpXZNUirQtOanMhXJkGfMA9sf3YoIn0sR92Fe7sivQknTBuOpViscUoap7BUi5TCMnx5JBlfHUlukWsBebmKMKlHAD59pC8Fv9sJxhgWLFiA7du3Y//+/YiIiLC4v1+/fhAKhdi3b595W0JCAtLS0jB48ODmLi4BoG3iSVtDPBoThi8e64eYCE/0C1WY00zGphZDXaE37xfiKYW7VIQijW3B7z4hihojJUO9XHAquQhyqQAVehOKy3Twcxcj0scVeqMJUhEf8Rkq9ApRWAzq+uxAEi5kNH7UpS2u5Zbg8wPXa73/QmZluayRCvmIDpKDR5lU2iSVqvKz5+lp2em+efNmeHt7Izo6GsuWLUNZWe2dR1qtFmq12uKPONa1vNJGP3Yorf1NCCFNIhLw7DaYc0qvIMgkAnx+IAkXmzALhxDSPvnKJFjzYC/MiAlt9DEYq+w3/TM+27yN4zh4uIoxorMPlt/dzWJ/VxEfd3TxxZI7O+O1SV1rHI/jgOfGdETs8rE4unQM1s7oa/V5H+ofgrt6OHbAbUGpDtGBdQcMAUCjM+JwYoFDy0JIQ1UFvxMTE7F37154eXk5u0ikAQR8Hr6d2R+9b/a19QyS40qOGtWW/UaRRoerOWok2XB9fzlbDZ9GzraOifBEUl4pLmercSFThWu5pYj0bfyAn9/PZ+FkchGe+i4WN/Ib3zdBmh/NAG8BPF1F2D5/KL47norNJ1KRpaqASND0sQkJOSWIDpLboYTtl85ogq9MDFW5vlkDWA3x9rQeGE/rWrYr8+fPx5YtW/D7779DJpOZ1/WWy+WQSqWQy+V44oknsGTJEnh6esLd3R0LFy7E4MGDMWjQICeXvn2SCPnN9lw8Hofx3f0xvrs/slXleP33S9h7JReMARw49AvzAMcBWcXlNbKP1MbfXYzrVk7wOHDo6OMKTzcRRHweCkp1EPI55Kots2Uk5pWipMJgvp2r1uLZLbHY9sxQuy/ZUK4zYv2xZPzf3sR6221Wy3ZVuR4dKB1cm2QymbB48WIMHToU0dG3Zvg/8sgjCAsLQ2BgIOLj47F06VIkJCRg27ZtVo9D64w1P5dGtqNBCil60PkwIYS0GHKpED2D5TiQkI+lv8bjt/lDIaQlZwghDcBxHN66tweeHd0R1/NKoSzXo4u/DEI+Dx/8lYC/LuXAYLK82uvg44rvnoiBkM/hxI0irPk7Act+jcfJG4Wo2lUs4IExhqNJtwLDU3sHYvW0npCKKs9Fbx+44+EixIcP9caoKF8AlcsoVhhqTp4ZGO6JN6dGQyTg4YWfz+OX2Ax7viQWKgwmyMR8lGhb3iQe0r6VlpYiKSnJfDs5ORlxcXHw9PREQEAA7r//fpw9exY7duyA0Wg093d6enpCJKIlrVoDAZ+H58d1xju7r+JClsoi+F0l1NOlxrK/1jAGRPi4Ir/U9oy83W8OALp9bXEAKK3Qg8/jLNYht5XRxDD9qxMAgOM3CtGBJiG2GhQAbyHcJULMH90RT43ogIMJ+dhzMQdx6UqrjYSt3t51BZN6BjRr4KUlscc66F6uYrwwPgrbz2bi+M20voQ4W9X6N6NGjbLYvn79esyaNQsA8OGHH4LH4+G+++6DVqvF+PHj8fnnnzdzSQkA/JtUgB7BcrhLhM3+3AFyKb56vD8uZanw0i/x0BlMNdK/1aeLvwwuIr5FKjVPVyE8XcQ4m1Zc2bGQr0HvYAWAyjW2q4v0cUVaYc2ZtOlF5fh0fyKmx4Qi0scNHNCk9bZNJob04jIcSSzAB38lwJbzWXW53uJ2lJ8MQgGH1MIy9ApRwGRiNAu8jZk/fz4uXryIo0ePWmyfN2+e+f89evRAQEAA7rjjDly/fh2RkZE1jkPrjDW/hNyGp6EU8Di8PLELfY8JIaQJdAaTXQboVzd7aAQOJOTjUpYa0z4/hrWP9kWwh4tdn4MQ0vboDCYk5JQgPlOJQwn58JaJMSMmFCM6+5j3+WxGX6jK9dh1IRtr/rkGL1cRQj1dsPzubghSSPHhP9cgFvKwdd4gnEtT4kq2Gjojg8FoQpiXC04mF+F6tcCMr7vEHPwGKoMrx5eNgVTIR36JFoEKKVzFld3rJhPDD6fS4CoS4KkRHZCQW4KLmSrc1SMAr9zV1dyWxmcoHfo6JeWVIsLbBVpDOXTG2i+MbZkpTog9nTlzBqNHjzbfrrqmnjlzJlauXIk//vgDANC7d2+Lxx04cKBGHyhpuYZ38oGQz8NzP5xDnpXlZOtolmrIUVlf2tAaL1cRspXlKCrTW70/IbcUkT6uFm18Yxy/XogZMWFNOgZpPhQAb2EEfB7GdvPDHV19UW4wYme1dDwNVajRYe3B6/jPnZ3tWMLWwWhi2Ho6rcmNkdZgxCvbLtQYOdqSrPn7GiJ93NDRl0YetRfMhpExEokEn332GT777LNmKBGpy9COzk+92z1Qjk1zBmLKp//WuV9nPzdIRXxcylQhxNMVZVoDRAIezqYp0T/MAxIhHx4uQuSqtXAV8yo7AhhQojWgVGewesyM4nL0DlUgo7gcJhNDmJcLTqVUBuE3Hk/F5pNpMJgYhHwOL4yLwt29AhGkkNZZTqOJYd2h67ieX4qjiQWQS4V4//6e6Owng1wqhFjAR7m+/tHutw+SenliF6z68xLu6xsMiZCPCr0REl77HETWFi1YsAA7duzA4cOHERwcXOe+MTExAICkpCSrAXBaZ6x5/XYuE8kFDbtI7Rksx9v39qBsSIQQ0kQCBwwikor46ODjihv5GlzIVOHhL09g58LhkLs0/4BRQkjL99XhG/gzPgtXs0ugM1pm+dpyMg3ebiJ08XdH1wAZHhoQio6+bpg+MBTTB1amSWeMIaWwDGsPXsf/7UsEAOy6kI2FYzrhkZgwiAQ8rD2YhC4B7vCRieEmFmDXhWyoKwz48vAN9AyW4+6egQAqZ58HyCuvVxUuljNSeTwOs4daLlF3O8YYQjxccC3XcSl0eRzg6SqGskwPXS2BIAA4l65ETAdKMU2az6hRo+rs07Slv5O0DoM6eGHXouGYs+E04m9bAtHbTYTkAg16BMnBcZXLEN4+K5vjKrM2cgAC3CVgALRGE0or9CjU6KCs1ra5SwTo4O2Gy9mqOgf9AICXm7jJAXBrs8tJy0UB8BaK4zh89FBvgAE7LzQ+CP7tv8ntMgD+9q4rUJXrmxwA332xZtqkliYhtwQe1FFAiEOU6QxwEbWNn0ovNzH+92AvzNlwGmU668Fhd6kQZ1KKIeBxSC7QgM/jwONxCPNyQaFGh3KdERnF5QCAvBIt5FIBugfJkVygQeFtKYmEfA5yqRAFpTqcvhnwHhbphaPXC9E3VIGzaUoAMLexeiPD6t1XsfFYCnY8N9y8ZrjWYMSZlGL8fCYd6cXl8HIV4VKWGjnqCvC4ytRJiXmlWPDDOUiFfNwo0Niczsj15nvbP8wD3z0RA6mIDwYGnaHy8U3NIkJaBsYYFi5ciO3bt+PgwYOIiKi7UwoA4uLiAAABAQEOLh2pi95owso/LuHXsxno4i9DkUYHuVQIhYsQPI6DwViZ+cFgNCHS1w0GY2XWhpmDw3B3z0Ca+U0IIXbgiLbUVyZG7xAFbtzsgMwoLsem4ylYeEcnuz8XIaT1SysqqxFAqa6gVIejSQU4mlSAb44mo2uAO6RCPkI9XcAAnEouQqay3OIxFzPVeOq7WIttA8I9MSE6ABOiA/Dm1GikFmpQrjOhs7/9JpxwHIevZ/bHoq1x+ON8ll2O6e8ugZ9cDImAD43WgCxVRb2Z3zr6uuGuaLrWIYQ4jrebGG/cE415m85YzAQX8nno7OeGXHWF1RnithDxOfi6SyCXCiCTCHHiRvMFpW/PJklatrbRq99GCfk8rJzSHb1DFEgrKsN3J1IbfIxSrQG7L2RjYo/2dVJzOqUIl7LUiA50x8MDQ62mgWeMgeNqv5hnjOHjmyNDW6pZQ8Lx6KAweLnRLDRCHKGtBL+rDOrghVOvjsXRxAIcTMjDb3GZqNBXjqAfGO6JpPzKFMNVQWmjiSG7jnRDqnID4jOUiPB2w4Xb1kLrHaIAALiKBfBzFwOMw9HrlUtJJOWVIibCE2U6Ay5kqi0el6WqwIItZzG8kw8ylWX4PS4LGq3BakpzI4BsVQU8XUXIKC6Hp4sQbmI+VOXWZ6PXeDxj4Dhg5ZTu5rR2wzreSp9H61G2DfPnz8eWLVvw+++/QyaTmdcRk8vlkEqluH79OrZs2YK77roLXl5eiI+Px3/+8x+MGDECPXv2dHLp2y+D0YQVf1zClpNpAICrOZXtU20XyEU3B9osv7sbpvQOap5CEkIIaZRQTxe8cldXXM5Sm9v3S1nqeh5FCGmv1BW2BxtM7FZ7csbG5b9EfB5W3dMd47r7m7cJ+Tx09JU1rKA24jgOr9zVFR193cDncdh9MRsXMxvWBrqI+IjylyEptwQ56grkqG1PEzxnaARem9SVBosSQhyud4gCR5eOwa4L2Xhzx2XweBwuZChRoq0/a2NddEaGjOJy6AxiXM22fbm0vAa0lbeTCHl4fHA4Fo7p2OhjkObXtnr22yAfmRhzR3QAAAR5SPHd8dQaoxbrwhjw+h+XMKarL8SC9pPGdePsgXj9j0tY+edlfHUkGV893h/dqq1tk1Fchh3x2ZjWNwg8joO3lQByidaAYo2uOYvdYH1CFZT6nBDSIG5iASZE+2NCtD/enBqNhJwS7LuSB5lEgCOJfBxIyG/Q8Uq1RlzJVqF/mAd4XOXFfJaq8nfqUqYKMokQp5ItOx7UFQacTC5CuJf1tR6PXS/EseuFkAr50BqM5uB331AFOACxN2ePA0CZzgg/dzG6BLihqFSPa7kl6BkkR6nWgBt1pEx2FfFxdw9/TOjub5Ei2d5rXBLnW7t2LQDUWDNs/fr1mDVrFkQiEfbu3YuPPvoIGo0GISEhuO+++/Daa685obQEqFw/cclP5xs8KybYQ4pHB4U6qFSEEELsheM4eLqI8PjgcLyy/QIAoKiFX3sTQpynT4gCv8fdOi/0cBFizYO94S+XIMhDCoORITG3BOczlDifrkJsarFNAeEAuQR39wzAE8M6wF8ucWQVavCXS/DczawXPjIxlv4aD08XEQwmBp3BBL3RhI6+bpgxKAwjOnnjXJoSr/9+EeqKysHeEd6uOFftuthW47s7TM5hAAEAAElEQVT7UfCbENKsRAIepvYJQt9QD7y75wp2Xsix27HDvFwaNItc2YTZ2+O7++OVu7o2+vHEOSgA3oo8PTISc4ZG4KsjN/DxvkRoDaY693cTC1CqNSC/RIuTN4oworNPnfu3JR6uIkiFlUGMTGU5ntx4Gh6uIhRrdPByE8NoYkgp1GD9v8nYvWhEjcczxrDyj0sY0rHyJLOgtHHpOBytZ7DC2UUghLRiQj4P0UFycwB45pBwLPzhLHY18GTUYKocXR8gFyNbVdlephdVBsHL9LW3n74yCVIKy8DjKi/gb1+Hp1xvRBd/GTRaA9KLy1FQqkN+tfZYxOfQJ9QDiXkl4PN4yCoug4kB8ZkqrJrSHcM6Va6/XnMZKQYex6GDDw0gag/qW0csJCQEhw4daqbSkPpczVHjzR2X8W9SYYMe1ztEgRWTu7WrAZ+EENKaXcsrwfSBIXhzx2WU6424q4d//Q8ihLRLM4eEI1Ahxf6reSipMCDS1w2ju/ha7BPTwcu8nrXJxDDls6NWZ1UHe0hxT+9AjO/uf3P9WecHgu/vG4wpvQKtZq+sEubliqS8Unx6IAnBHtJGZc2Y1icI79zXk4LfhBCnCPVywdwRkbiYpUZqYVmTj+cjE+Ncmm2ZPqr4uUss1g9viME3f2NI60IB8FZGJOBh/uiOmNonCD+eTseGf5PNo/9uN6aLL/ZcygEYcCAhr10FwAFgSq8g/BaXBZ3BhCxVBbJupvHNqpbOt0xnxENfHEffUA88NjgM2aoKdA2QwWBk2HY2s9HPLeLzMKaLL3RGE0q1hsoTdB9XuEuFOJVchKS80ibXb8Hojojwdm3ycQghpAqfx+GT6X0xJDINH+29hoLShs3EMRgBHger6cqtSSnUYGCEB1IKyiCTCK3uczWnBO4SAQZGeJhnkkcHuiOtuAyBcilOJleu81Ok0SMmwtN8W+EiRCQFuAlpVQpLtTifrmxQ8HtanyDMGRZhkcmBEEJIy6UzmCAS8NDB2w0cx6FLgAzn0pTYeyUPs4ZGOLt4hJAWiOM4jOvub5GivC48HofFd3TGvqu54DgOPA4Q8HjoE6rApB4BELSwpa54PA4SXv2DOGcMCgVjwMnkAuSqK6A32njhfdPyu7tRxjNCiFP1DlFg96LheOq7WBxJLGjSscK9XJDfwDXEUwpK0S9MgbSicpsfy3HApjkDMSTSuzHFJE5GAfBWKkghxZI7O2NMF19M/exf83YRn4eewXJczFJBbzRh+oAQfHciFYeuNSylbVswrJM3vp05APO+O4MyXe3rSiTmlSIxrxR6kwlHEwtQUKrFc3d0wqgoHxxsYCrgnsFyzB4ajn6hngitJbXvx/sSseafazYdTy4VIkAuQVJeKXxlYkwfGIqiMh02HEvBnGHUOUAIsT8+j8Ojg8IwuWcgFv14rkHtYH6pFlH+MiTk2Lb+Tl6J1pyqKK9Ei/5hHlbXaZNLhUjKvTVw6Hq+Bm4SgXnNyConk4twR1dfFJTqoHAR2VxuQkjLoDOasOVUus37T+jujzUP9XZcgQghhNgdQ2XAJq1QAyMDIrwq0/gev1GIX2IzcH+/YCeXkBDSFozt5oex3fycXQy7CpBL8eKEKABRSC3U4OSNIvjJJchSluO/Oy5DU0ffJwDEpStRqNFBbzTh4QEhLWL2OyGk/XERCbBpzkAs+ek8tp9r3AREbzcR4hqxDITWwBCbqoRUyMPAcE+cSimq9zH9Qj0wvFP7mljallAAvJXrHVK5BnR6URkm9wrE+/f3BMdxKCjVoqTCgOSCUmw8nopAudTZRXWKYZ288fmMvvj+RBr2Xsmtc9/qM74/2puI+/sF48lhEchWVSC9uAzxGao6Hy+TCLBh9kB4utYedNEajBjUwQsbZg/At/+m4HKW2mp6dZlYgB/mDUL3QHdwHIekvFKEe7mYR6nOHd6hzuchhJCmkrsIsWH2QGQqy7EzPgs747Nxvp52EAASckrQM1heb5tpTVXw200sgJtYAKmIB4WLCBczVNBXm1ZerjeiXG/94v5oYgHWPdYPI9tZ1hNC2oKDCfk4n660ef+nRnZwXGEIIYQ4hFjAx+UsNfg8ID5DBdPNpUqMJobNJ1MpAE4IITYI83JFmNetrJBju/qBgeGFn+NxuJZJULM3nEawhxT/GduZgt+EEKfiOA4fPNAL9/YJwtJf45FdLWOvLTp4u9kUvK5Nud6EUylFCPaQIqO4vM59xULKnNGaUQC8DVg8thMYAyb1CDCfwHi7ieHtJkaEtytOvXoHFNL2GywdFeWL7oFynP2oGEUa29P5/hKbYf5/BxtSjfvIxJBLrafwrSIW8DEwwtNcLqOJYf2/yTidUgS9kWH/1TyEerrgw4d6W6Ty7OhrmcY3UNE+BzQQQppfkEKKeSMiMW9EJJILNNjwbzI2Hk+t8zH8Jq4pVqo1oFRbubxHTITEIvhdH63BhKc2xeL1yd1wf7/gOtdRI4S0HOoKPVbvumLz/t5uIvQOUTiuQIQQQhxGbzChS7AcgQopfq523X0xU4WCUi283cROLB0htlu5ciVWrVplsS0qKgpXr14FAHz55ZfYsmULzp49i5KSEhQXF0OhUDihpKSt85GJUVKhh85gfaD48E7emD+6I2IiPCn4TQhpEfg8DiM6++C7J2LwwLpjKLZxbW4vVxHOpTds7e/aSAQ8dPZzw7Xc2perrSuzMGn5KADeBtzdMxCMsVpPYHxlkmYuUcvjIxNj13PD8fCXx5FSWNbgx98o0NS7z319gxsc9OHzODw5vAOeHN4BBqMJv57NwORegXAR0VeTENLyRHi7YtU90bi7VyDOpRXjep4GR5MKkKm8NVqyb6gCF7PUdnk+HgdcyWn4sXRGE1777SL+iMvCj08Nogt8QlqBjf+mQF1hsHn/AeHUeUcIIa2NwWiCgM9Dr1AFSiv0OJJYgOggd5xKrpzBozcy7L6QjccGhzu3oIQ0QPfu3bF3717zbYHgVn9OWVkZJkyYgAkTJmDZsmXOKB5pJxhj+PLwDZy4YTkjslewHK9P7o5+YR5OKhkhhNSto68bvp01AI98ddIi22N0kDuu5ZRCZzRZ7B/p07TZ39Ul5VfGfAZGeJrPR293OUsNrcEIsYAm2LRGFGVrI6gDsH7+cgkOvjgaP55Ow9JfL9jlmDwOmNIrED4ycZNTtQn4PDw0INQu5SKEEEcaEO6JAeGV2SwYY8gv1eKd3Vdx8Go+LmSqoDfaPmO7OgGPQ5iXC24UaMAYEOblguSChg9aqnIqpQhv7byCJeM608AiQlowdYXepiUWqovylzmoNIQQQhzBZGLmdOcZxWUo0xlxI78UQh4PcqkQqvLKWT9nUospAE5aFYFAAH9/f6v3LV68GABw8ODB5isQaZcWbDmHPZdyIOLz8L8He+Gfy7lIKyrDxtkDIXepO1slIYQ4W59QD7w8sQtW/HEJAHBvnyB8+FBvxKUr8er2C7h0c6KNwkWIODvN/q7uVHIR+oYqcNbKuuJagwkXM9U0kKiVot5g0u480C8EP53JQGyq9cZSJhEgQC5B/3BPDO7gBa3BhA3HkpGlrECp1oBgDyn4HIfEvFIsm9gVc0fQ+pOEkPaL4zj4yiR4d1oP/HMlD6eSi/BrbAZKtLbP5AQAuVSImUPCMbKzDw4m5EFVrseVbDXy1FpompBu6NezGVg6sUujH08Icbxd8dnYeyW3QY+hi09CCGldeDwOIl7lzJlAuRQHEvIwOLLyevuLwzdubpfg7Xt7OLOYhDRYYmIiAgMDIZFIMHjwYKxevRqhoY2f3KDVaqHVas231Wr7ZNcibRdjDDweB6OJwQiGEE8XfDy9j7OLRQghDTK5VyC2nctEQo4aL4yPAgD0DlFgx8JhuJytxq+xmdgRn4XOoR64lKlqUl+hNWfTlAjxlMLHTQy9sXKyj4eLEFnKCuy5mE19EK0UBcBJu8Pjcfj68f44dr0Qz209B2O1tWXv6R2I9+/vBZGAZ/GYqtnd59KKzetNKsv08HBtv2urE0JIdUIBH3f1CMBdPQLwzKhIrN51BdfzNUgvLoOyjnV8RHwe7ujqi3em9TSPTO8X5gGjieFyVuU6kHM3xcJQzzrg/cI88OSwCNxKiFL5H4mQByGfV+vjCCHOV9ugxLqEero4oCSEEEKaA4/HYUCEJ9wlQuy9fGsA1HN3dIKrmLqpSOsRExODDRs2ICoqCtnZ2Vi1ahWGDx+OixcvQiZrXLaa1atX11hXnJDaMMbw+cHr+PN8lnnblpOpSC4oRZayAiGeLujs54Yu/u5OLCUhhNTP01WE3+cPhbJMB4XLrZgLx3HoHihH90A5XrmrC44kFeDP81nIKi6HslyPqzkltR7TXSLAY4PDcCSxAPE2ZJ1LLypHelE5OAAMQI6qAv3DPLDtXCYeHxyOEOqHaHXoyoK0Sx6uIkzqGQCpiIctJ9MxtKMXooPk6BEkrxH8rq5PqIfFMQghhNTk5y7BRw/fGnGeVliGd/dcxf6reeb1fAZGeGJGTCju6OoHNysdnXwehx7BCgDAzueGY+EPZ3Ett9Tq8/F5HN66N5ou6glphdKLyvBzbEaDH+cuoVSOhBDSmrlLhCjWaJGjrgAADAj3wIP9Q5xcKkIaZuLEieb/9+zZEzExMQgLC8NPP/2EJ554olHHXLZsGZYsWWK+rVarERJC3w1Su0EdPCHi88zr5P50JgM/nbl1fr1xzkB0sZ6lnxBCWpzqwe/bCfg8jI7yxegoX5RU6LH7Yg4OXM1DsUaHbHU5UgvLzfuO7+6HN6dGw1cmwX/GmpBaVIYj1/Lxzb/JSC+q3I/HAdbm21TfdObmgP3vT6Ri2V1d7VJH0nwoAE7atTFd/DCmi5+zi0EIIW1aqJcLPpvRFwajCddyS+HhKoS/uwTcrenadYryl+H3+cPw4i/nsSM+u8b9MweHU/CbkFaGMYYP9yZiR7XZKrYa3smbBiIS4iCHDx/G+++/j9jYWGRnZ2P79u2YOnWq+X7GGFasWIGvvvoKSqUSQ4cOxdq1a9GpUyfnFZq0KlqDERqtAWlF5fBwEeLA1Tz0DJZjw+yB4PFsOzckpKVSKBTo3LkzkpKSGn0MsVgMsVhsx1KRtqpCb8Sf57Pw3l8J5uC3Nc//FIdJPQKw5M4oWg+cENJmyCRCPNg/BA/2D0Gmshy/ncvEqeQi6AwmPDY4DHf1CDDvK+DzEOnjhkgfN9zVMwDLf7uIe/sE41RyEb79N9mm51v/bzK6+Mtwb99gR1WJOAAFwAkhhBDSLAR8HroFNi5QLRXx8cn0PvBzl+Cbo7dOTr3dxFh8J3W6E9La/Ho2Ex/vS2zw4wZGeOKzGX0dUCJCCABoNBr06tULc+bMwbRp02rc/9577+Hjjz/Gxo0bERERgeXLl2P8+PG4fPkyJBKJE0pMWhuxgA+xgA8ex2HPxRxcyFTh6NIxdWZiI6S1KC0txfXr1/HYY485uyikjbuao8birXF1pv6tUlCqw8bjqXh8SDgFwAkhbVKQQor5ozti/uj69/WVSfDFY/0BAIMjvWA0mfDD6XToDLUPJAIAnZFh5Z+XYWS3lsslLR8FwAkhhBDSKnAch9cmdUWUvwyvbb8IndEEqYgHVvfy4ISQFsZkYvjwn2sNflxnPzesnzWA1oclxIEmTpxokdK3OsYYPvroI7z22mu45557AACbNm2Cn58ffvvtNzz88MPNWVTSSlXojeA4QCLkw9tNDD6Po+A3abVeeOEFTJ48GWFhYcjKysKKFSvA5/Mxffp0AEBOTg5ycnLMM8IvXLgAmUyG0NBQeHp6OrPopBXTGoyY8um/9QZrqvQKUeDOrr4IlEsdXDJCCGld5FIhVt0TjYcGhGLq5/W3q6pyPfZczKYAeCtCVxmEEEIIaTU4jsOD/UPwnzs7AwBKKgywMZM6IaSFyCvRIlNZXv+OtxkY4UnBb0KcKDk5GTk5ORg7dqx5m1wuR0xMDI4fP17r47RaLdRqtcUfab8kwsoZ4BV6I0yMYUZMqLOLREijZWRkYPr06YiKisKDDz4ILy8vnDhxAj4+PgCAdevWoU+fPpg7dy4AYMSIEejTpw/++OMPZxabtHJiAR/v3dcT3QPdbboWnj0kHAvGdIJUxHd84QghpBWSivgQC3ioWo2nrrbVXUKZNFoT6kEihBBCSKvzzKhIcBzwR1wWnXwS0spkqawHv/k8DkaT9ZQOAl7l4BdCiPPk5OQAAPz8/Cy2+/n5me+zZvXq1Vi1apVDy0ZaF73RhPPpKnQLdMfQjt7OLg4hjbZ169Y671+5ciVWrlzZPIUh7crUPkG4p3cg7vjfIRgZg0ZrREGptsZ+Izv7YHx3fyeUkBBCWo8Ib1fEvT4OOeoKXMhQoVeIHF8evoH1/6YAAPqHeWDGoFAM7egNXxkt+9SatLoA+GeffYb3338fOTk56NWrFz755BMMHDjQ2cUihBBCSDN7emQkRnTycXYxCCENJBMLsH72AHTwdoVUxAcHDiI+D+5SAUwMyCupQHpRObQGIzRaIwCgk58bIn3cnFxyQkhjLFu2DEuWLDHfVqvVCAmhAS3tmc5gwpCOXhDyKSkhIYQ0xf8e7IUOPm5gjCE2tRh8HgeO45CjKkeF3gQTY9DoDDT7mxBC6sHncQhSSBGkqFwu4vW7u2FQBy/IpUL0C/Og89ZWqlUFwH/88UcsWbIE69atQ0xMDD766COMHz8eCQkJ8PX1dXbxCCGEENLMugW6O7sIhJAG6uQnQyc/mdX7+BwQIJcigNYoJKTF8fevnEGWm5uLgIAA8/bc3Fz07t271seJxWKIxWJHF4+0IrScBSGENB3HcegT6mG+fUdXvzr2JoQQ0hAcx1EGjTagVQ1bWLNmDebOnYvZs2ejW7duWLduHVxcXPDtt986u2iEEEIIIYQQQkibFRERAX9/f+zbt8+8Ta1W4+TJkxg8eLATS0YIIYQQQgghhFhqNcNudTodYmNjsWzZMvM2Ho+HsWPH4vjx4zX212q10GpvrX2iVqubpZyEEEIIIYQQQkhrVFpaiqSkJPPt5ORkxMXFwdPTE6GhoVi8eDH++9//olOnToiIiMDy5csRGBiIqVOnOq/QhBBCCCGEEELIbVpNALygoABGoxF+fpbpXPz8/HD16tUa+69evRqrVq2qsZ0C4YS0flXfY8aYk0vSdlW9ttRmEtL6UZvpeNRmEtK2tOd288yZMxg9erT5dtXa3TNnzsSGDRvw0ksvQaPRYN68eVAqlRg2bBj27NkDiURi83NQm0lI29Ke28zmQG0mIW0LtZmORW0mIW1LU9vMVhMAb6hly5aZL9YBIDMzE926dUNISIgTS0UIsaeSkhLI5XJnF6NNKikpAQBqMwlpQ6jNdBxqMwlpm9pjuzlq1Kg6Oxc4jsMbb7yBN954o9HPQW0mIW1Te2wzmwO1mYS0TdRmOga1mYS0TY1tM1tNANzb2xt8Ph+5ubkW23Nzc+HvX3MxerFYDLFYbL7t5uaG9PR0yGQycBzXoOdWq9UICQlBeno63N3dG1eBFq6t17Gt1w9oX3VMS0sDx3EIDAx0dpHarMDAwEa3mc2lPXzmWxp6zZ2jqa87YwwlJSXUZjpQa2gz7aE9tQHtpa7tpZ5Aw+pK7aZjteY2sz19Z5yJXufmY4/XmtpMx3Jkm9kev2vtrc7trb5Ay68ztZmO1dznmS3982YLqkPL0RbqYe86NLXNbDUBcJFIhH79+mHfvn3m9cVMJhP27duHBQsW1Pt4Ho+H4ODgJpXB3d291X7wbNXW69jW6we0jzrK5fI2X0dns0eb2Vzaw2e+paHX3Dma8rrTyHLHak1tpj20pzagvdS1vdQTsL2u1G46TltoM9vTd8aZ6HVuPk19ranNdJzmaDPb43etvdW5vdUXaNl1pjbTcZx1ntmSP2+2ojq0HG2hHvasQ1PazFYTAAcq1x+bOXMm+vfvj4EDB+Kjjz6CRqPB7NmznV00QgghhBBCCCGEEEIIIYQQQgghTtaqAuAPPfQQ8vPz8frrryMnJwe9e/fGnj174Ofn5+yiEUIIIYQQQgghhBBCCCGEEEIIcbJWFQAHgAULFtiU8tyexGIxVqxYYbGmeFvT1uvY1usHUB1J+0Ofh+ZHr7lz0OtOWor29FlsL3VtL/UE2lddiePQ56h50OvcfOi1bt/a4/vf3urc3uoLtM86E+dpC583qkPL0Rbq0dLqwDHGmLMLQQghhBBCCCGEEEIIIYQQQgghhDQVz9kFIIQQQgghhBBCCCGEEEIIIYQQQuyBAuCEEEIIIYQQQgghhBBCCCGEEELaBAqAE0IIIYQQQgghhBBCCCGEEEIIaRMoAE4IIYQQQgghhBBCCCGEEEIIIaRNaNcB8MOHD2Py5MkIDAwEx3H47bffLO5njOH1119HQEAApFIpxo4di8TERIt9ioqKMGPGDLi7u0OhUOCJJ55AaWlpM9aidvaoX3h4ODiOs/h75513mrEWdauvjtu2bcO4cePg5eUFjuMQFxdX4xgVFRWYP38+vLy84Obmhvvuuw+5ubnNU4F62KN+o0aNqvEePv30081TARvUVUe9Xo+lS5eiR48ecHV1RWBgIB5//HFkZWVZHKMlfw9J07311lsYMmQIXFxcoFAoatx//vx5TJ8+HSEhIZBKpejatSv+7//+r8Z+Bw8eRN++fSEWi9GxY0ds2LDB8YVvxep73QEgLS0NkyZNgouLC3x9ffHiiy/CYDBY7EOve9Ncu3YN99xzD7y9veHu7o5hw4bhwIEDFvvY8j4Q0hQpKSl44oknEBERAalUisjISKxYsQI6nc5iv/j4eAwfPhwSiQQhISF47733nFTixrNX29dafPbZZwgPD4dEIkFMTAxOnTrl7CI1mT2ugUj7ZjQasXz5cos278033wRjzLwPfY4ap633wbQUdI1N6rN69WoMGDAAMpkMvr6+mDp1KhISEpxdrGbzzjvvgOM4LF682NlFcajMzEw8+uij8PLyglQqRY8ePXDmzBlnF8shbPntJqQxzp49izvvvBMKhQJeXl6YN29ejd/DxlwfNvfvbH19Sxs2bKgRP6j6y8vLq/W4zRk7sqV/zFr5t27dWudxm/O9qK8OtvZx366lvQ8t6TvRrgPgGo0GvXr1wmeffWb1/vfeew8ff/wx1q1bh5MnT8LV1RXjx49HRUWFeZ8ZM2bg0qVL+Oeff7Bjxw4cPnwY8+bNa64q1Mke9QOAN954A9nZ2ea/hQsXNkfxbVJfHTUaDYYNG4Z333231mP85z//wZ9//omff/4Zhw4dQlZWFqZNm+aoIjeIPeoHAHPnzrV4D1tSh3RddSwrK8PZs2exfPlynD17Ftu2bUNCQgKmTJlisV9L/h6SptPpdHjggQfwzDPPWL0/NjYWvr6++P7773Hp0iW8+uqrWLZsGT799FPzPsnJyZg0aRJGjx6NuLg4LF68GE8++ST++uuv5qpGq1Pf6240GjFp0iTodDocO3YMGzduxIYNG/D666+b96HXvenuvvtuGAwG7N+/H7GxsejVqxfuvvtu5OTkALDtfSCkqa5evQqTyYQvvvgCly5dwocffoh169bhlVdeMe+jVqsxbtw4hIWFITY2Fu+//z5WrlyJL7/80oklbzh7tH2txY8//oglS5ZgxYoVOHv2LHr16oXx48fX2cHRGtjrGoi0X++++y7Wrl2LTz/9FFeuXMG7776L9957D5988ol5H/ocNU5b74NpKegam9Tn0KFDmD9/Pk6cOIF//vkHer0e48aNg0ajcXbRHO706dP44osv0LNnT2cXxaGKi4sxdOhQCIVC7N69G5cvX8b//vc/eHh4OLtoDmHLbzchDZWVlYWxY8eiY8eOOHnyJPbs2YNLly5h1qxZ5n0ae33Y3L+z9fUtPfTQQxaxg+zsbIwfPx4jR46Er69vncdurthRfXWosn79eovyTJ06tc7jNud7UV8dbOnjrk1LeR9a3HeCEcYYYwDY9u3bzbdNJhPz9/dn77//vnmbUqlkYrGY/fDDD4wxxi5fvswAsNOnT5v32b17N+M4jmVmZjZb2W3RmPoxxlhYWBj78MMPm7GkjXd7HatLTk5mANi5c+cstiuVSiYUCtnPP/9s3nblyhUGgB0/ftyBpW24xtSPMcZGjhzJFi1a5NCy2Utddaxy6tQpBoClpqYyxlrX95A0zfr165lcLrdp32effZaNHj3afPull15i3bt3t9jnoYceYuPHj7dnEduk2l73Xbt2MR6Px3Jycszb1q5dy9zd3ZlWq2WM0eveVPn5+QwAO3z4sHmbWq1mANg///zDGLPtfSDEEd577z0WERFhvv35558zDw8Pi8/d0qVLWVRUlDOK12RNaftai4EDB7L58+ebbxuNRhYYGMhWr17txFLZV2OvgUj7NmnSJDZnzhyLbdOmTWMzZsxgjNHnyF7aeh9MS0HX2MQWeXl5DAA7dOiQs4viUCUlJaxTp07sn3/+aVV9ZY2xdOlSNmzYMGcXo9nU99tNSGN88cUXzNfXlxmNRvO2+Ph4BoAlJiYyxhp3fdjcv7O29C3dLi8vjwmFQrZp06Y6j91csSNb62DLeU91zfleNOZ9YKxmH7c1Lel9aGnfiXY9A7wuycnJyMnJwdixY83b5HI5YmJicPz4cQDA8ePHoVAo0L9/f/M+Y8eOBY/Hw8mTJ5u9zA1hS/2qvPPOO/Dy8kKfPn3w/vvvt9oUj9bExsZCr9dbvA5dunRBaGhojdehNdu8eTO8vb0RHR2NZcuWoayszNlFajSVSgWO48xpSVvz95A4jkqlgqenp/n28ePHLb7nADB+/Pg29T1vbsePH0ePHj3g5+dn3jZ+/Hio1WpcunTJvA+97o3n5eWFqKgobNq0CRqNBgaDAV988QV8fX3Rr18/ALa9D4Q4grV2dsSIERCJROZt48ePR0JCAoqLi51RRIdoK985nU6H2NhYizaax+Nh7NixbbqNbsg1EGm/hgwZgn379uHatWsAKlMRHj16FBMnTgRAnyNHaet9MC0ZXWMTlUoFABbndm3R/PnzMWnSpBrXqG3RH3/8gf79++OBBx6Ar68v+vTpg6+++srZxXKY+n67CWkMrVYLkUgEHu9WCE0qlQIAjh49CqBx14fN/TtrS9/S7TZt2gQXFxfcf//99R6/OWJHDanD/Pnz4e3tjYEDB+Lbb7+tcymE5nwvGvM+ADX7XmrTUt6HlvadEDTp0W1Y1ZT96m9U1e2q+3JycmqkgBAIBPD09KyReqGlsaV+APDcc8+hb9++8PT0xLFjx7Bs2TJkZ2djzZo1zVpeR8nJyYFIJKqxxuPtr0Nr9sgjjyAsLAyBgYGIj4/H0qVLkZCQgG3btjm7aA1WUVGBpUuXYvr06XB3dwfQur+HxDGOHTuGH3/8ETt37jRvy8nJsdreqdVqlJeXm09gie1qe02r7qtrH3rdbcNxHPbu3YupU6dCJpOBx+PB19cXe/bsMaeus+V9IMTekpKS8Mknn+CDDz4wb8vJyUFERITFftU/i20l3WJb+c4VFBTAaDRarcvVq1edVCrHs/UaiLRvL7/8MtRqNbp06QI+nw+j0Yi33noLM2bMAECfI0dp630wLRVdYxOTyYTFixdj6NChiI6OdnZxHGbr1q04e/YsTp8+7eyiNIsbN25g7dq1WLJkCV555RWcPn0azz33HEQiEWbOnOns4tldfb/dhDTGmDFjsGTJErz//vtYtGgRNBoNXn75ZQBAdnY2gMZdHzb376wtfUu3++abb/DII4/U22/XXLEjW+vwxhtvYMyYMXBxccHff/+NZ599FqWlpXjuueesHrc534vGvA/W+ritaUnvQ0v7TtAMcFKnJUuWYNSoUejZsyeefvpp/O9//8Mnn3wCrVbr7KIRG82bNw/jx49Hjx49MGPGDGzatAnbt2/H9evXnV20BtHr9XjwwQfBGMPatWudXRzSRC+//DI4jqvzrzEd8BcvXsQ999yDFStWYNy4cQ4oeevmqNedNIyt7wNjDPPnz4evry+OHDmCU6dOYerUqZg8ebL5YouQpmhMm5CZmYkJEybggQcewNy5c51U8oahto8Q0hA//fQTNm/ejC1btuDs2bPYuHEjPvjgA2zcuNHZRSPErugamwCVM+UuXryIrVu3OrsoDpOeno5FixZh8+bNkEgkzi5OszCZTOjbty/efvtt9OnTB/PmzcPcuXOxbt06ZxfNIei3mzSErdeH3bt3x8aNG/G///0PLi4u8Pf3R0REBPz8/Cxmhbf0ejS0b+n48eO4cuUKnnjiiXrL0NTYkb3rsHz5cgwdOhR9+vTB0qVL8dJLL+H999+3/UVtBEe9Dw3p425p70NLQjPAa+Hv7w8AyM3NRUBAgHl7bm4uevfubd4nLy/P4nEGgwFFRUXmx7dUttTPmpiYGBgMBqSkpCAqKsrRxXQ4f39/6HQ6KJVKi1ngubm5Lf49bKyYmBgAlbO3IiMjnVwa21RdmKempmL//v3mkelA6/4etmfPP/88Zs2aVec+HTp0aNAxL1++jDvuuAPz5s3Da6+9ZnGfv78/cnNzLbbl5ubC3d29Xc1Ctufr7u/vj1OnTllsq3qNq7579LpbZ+v7sH//fuzYsQPFxcXmdu/zzz/HP//8g40bN+Lll1+26X0gpDYNbROysrIwevRoDBkyBF9++aXFfrV936vuc6bmbvtaA29vb/D5fKvvWWuqR0M19hqItC8vvvgiXn75ZTz88MMAgB49eiA1NRWrV6/GzJkz6XPkIG29D6aloWtsAgALFizAjh07cPjwYQQHBzu7OA4TGxuLvLw89O3b17zNaDTi8OHD+PTTT6HVasHn851YQvsLCAhAt27dLLZ17doVv/76q5NK5Fj1/XYTUl1Drg8feeQRPPLII8jNzYWrqys4jsOaNWvM9zfm+tBev7P27Fuq7uuvv0bv3r3rTMtdm4bGjhxVh+rlefPNN6HVaiEWi2vcb4/3whF1qKuP2xbOfB+c+Z2whgLgtYiIiIC/vz/27dtnvthSq9U4efIknnnmGQDA4MGDoVQqERsba24Q9u/fD5PJZA4ytlS21M+auLg4c2qDtqBfv34QCoXYt28f7rvvPgBAQkIC0tLSMHjwYCeXzjHi4uIAwKJToSWrujBPTEzEgQMH4OXlZXF/a/4etmc+Pj7w8fGx2/EuXbqEMWPGYObMmXjrrbdq3D948GDs2rXLYts///zTZr/ntbHn6z548GC89dZbyMvLM/8m/PPPP3B3dzdfaNPrbp2t70NZWRkA1BhZzOPxYDKZANj2PhBSm4a0CZmZmRg9ejT69euH9evX1/hcDh48GK+++ir0ej2EQiGAys9iVFSU09OfN3fb1xqIRCL069cP+/btw9SpUwFUzhTat28fFixY4NzCOVBjr4FI+1JWVlajjePz+ebfXvocOUZb74NpSegamzDGsHDhQmzfvh0HDx6ssYxNW3PHHXfgwoULFttmz56NLl26YOnSpW0u+A0AQ4cORUJCgsW2a9euISwszEklcqz6frsJqa4x14dVKZy//fZbSCQS3HnnnQAad31or99Ze/YtVSktLcVPP/2E1atX21yO6hoaO3JEHW4vj4eHh9XgN2Cf98Ledaivj9sWznwfnPmdsIq1YyUlJezcuXPs3LlzDABbs2YNO3fuHEtNTWWMMfbOO+8whULBfv/9dxYfH8/uueceFhERwcrLy83HmDBhAuvTpw87efIkO3r0KOvUqRObPn26s6pkoan1O3bsGPvwww9ZXFwcu379Ovv++++Zj48Pe/zxx51ZLQv11bGwsJCdO3eO7dy5kwFgW7duZefOnWPZ2dnmYzz99NMsNDSU7d+/n505c4YNHjyYDR482FlVstDU+iUlJbE33niDnTlzhiUnJ7Pff/+ddejQgY0YMcKZ1bJQVx11Oh2bMmUKCw4OZnFxcSw7O9v8p9Vqzcdoyd9D0nSpqans3LlzbNWqVczNzc38eSkpKWGMMXbhwgXm4+PDHn30UYvPSF5envkYN27cYC4uLuzFF19kV65cYZ999hnj8/lsz549zqpWi1ff624wGFh0dDQbN24ci4uLY3v27GE+Pj5s2bJl5mPQ6940+fn5zMvLi02bNo3FxcWxhIQE9sILLzChUMji4uIYY7a9D4Q0VUZGBuvYsSO74447WEZGhkVbW0WpVDI/Pz/22GOPsYsXL7KtW7cyFxcX9sUXXzix5A1nj7avtdi6dSsTi8Vsw4YN7PLly2zevHlMoVCwnJwcZxetSexxjUfat5kzZ7KgoCC2Y8cOlpyczLZt28a8vb3ZSy+9ZN6HPkeN09b7YFoKusYm9XnmmWeYXC5nBw8etPgMlJWVObtozWbkyJFs0aJFzi6Gw5w6dYoJBAL21ltvscTERLZ582bm4uLCvv/+e2cXzSFs+e0mpDE++eQTFhsbyxISEtinn37KpFIp+7//+z/z/bZcH548eZJFRUWxjIwM87bm/J21pW+pytdff80kEgkrLi6ucZzb69GcsSNb6vDHH3+wr776il24cIElJiayzz//nLm4uLDXX3+91jow1nzvhS11sKWPu6W/Dy3tO9GuA+AHDhxgAGr8zZw5kzHGmMlkYsuXL2d+fn5MLBazO+64gyUkJFgco7CwkE2fPp25ubkxd3d3Nnv2bHMHmbM1tX6xsbEsJiaGyeVyJpFIWNeuXdnbb7/NKioqnFSjmuqr4/r1663ev2LFCvMxysvL2bPPPss8PDyYi4sLu/feey06dJ2pqfVLS0tjI0aMYJ6enkwsFrOOHTuyF198kalUKudV6jZ11TE5OdnqfQDYgQMHzMdoyd9D0nQzZ86s8zOwYsUKq/eHhYVZHOfAgQOsd+/eTCQSsQ4dOrD169c3e11ak/ped8YYS0lJYRMnTmRSqZR5e3uz559/nun1eovj0OveNKdPn2bjxo1jnp6eTCaTsUGDBrFdu3ZZ7GPL+0BIU9R2vnH7WNrz58+zYcOGMbFYzIKCgtg777zjpBI3nr3avtbik08+YaGhoUwkErGBAweyEydOOLtITWaPazzSvqnVarZo0SIWGhrKJBIJ69ChA3v11VctgoP0OWqctt4H01LQNTapT22fgfZ0rdbWA+CMMfbnn3+y6OhoJhaLWZcuXdiXX37p7CI5jC2/3YQ0xmOPPcY8PT2ZSCRiPXv2ZJs2baqxT33Xh1W/y8nJyeZtzf07a0vfEmOMDR48mD3yyCNWj3F7PZo7dlRfHXbv3s169+7N3NzcmKurK+vVqxdbt24dMxqNtdaBseZ9L+qrgy193C39fWCsZX0nOMYYu31WOCGEEEIIIYQQQgghhBBCCCGEENLa8OrfhRBCCCGEEEIIIYQQQgghhBBCCGn5KABOCCGEEEIIIYQQQgghhBBCCCGkTaAAOCGEEEIIIYQQQgghhBBCCCGEkDaBAuCEEEIIIYQQQgghhBBCCCGEEELaBAqAE0IIIYQQQgghhBBCCCGEEEIIaRMoAE4IIYQQQgghhBBCCCGEEEIIIaRNoAA4IYQQQgghhBBCCCGEEEIIIYSQNoEC4IQQQgghhBBCCCGEEEIIIYQQQtoECoATQgghhBBCCCGEEEIIIYQQQghpEygATgghhBBCCCGEEEIIIYQQQgghpE2gADghhBBCCCGEEEIIIYQQQgghhJA2gQLghBBCCCGEEEIIIYQQQgghhBBC2gQKgBNCCCGEEEIIIYQQQgghhBBCCGkTKABOCCGEEEIIIYQQQgghhBBCCCGkTaAAOCGEEEIIIYQQQgghhBBCCCGEkDaBAuCEEEIIIYQQQgghhBBCCCGEEELaBAqAE0IIIYQQQgghhBBCCCGEEEIIaRMoAE5alPDwcMyaNctpzz9r1iyEh4c77fkJIYQQQgghhBBCCCGkuRw8eBAcx+HgwYPOLgohhFgYNWoURo0a5ZTnplhR60cBcEIIIYQQQgghhBBCCCHEwd5++2389ttvzi4GIYQQ0uYJnF0AQqpLSEgAj+e8cRlfffUVTCaT056fEEIIIYQQQgghhBDSNr399tu4//77MXXqVGcXhRBCCGnTaAY4aVHEYjGEQmGzP69GowEACIVCiMXiZn9+QghpDowxlJeXO7sYhBBCCCGklaHzSEIIaTxqQwkhhJDmRwFw0ixWrlwJjuOQlJSEWbNmQaFQQC6XY/bs2SgrKzPvZ20N8Pj4eIwcORJSqRTBwcH473//i/Xr14PjOKSkpFjsu3v3bgwfPhyurq6QyWSYNGkSLl26ZLHPrFmz4ObmhuvXr+Ouu+6CTCbDjBkzzPfdvq7DBx98gCFDhsDLywtSqRT9+vXDL7/8YrfXhhBCqtjaVhoMBrz55puIjIyEWCxGeHg4XnnlFWi1WovjhYeH4+6778Zff/2F/v37QyqV4osvvsC0adPQt29fi30nT54MjuPwxx9/mLedPHkSHMdh9+7dAICioiK88MIL6NGjB9zc3ODu7o6JEyfi/Pnz5seUlpbC1dUVixYtqlG/jIwM8Pl8rF692i6vFyGk/alqJ69evYoHH3wQ7u7u8PLywqJFi1BRUWHeb/369RgzZgx8fX0hFovRrVs3rF27tsbxqtrJo0ePYuDAgZBIJOjQoQM2bdpksZ8t7R9wa/3En376CatWrUJQUBBkMhnuv/9+qFQqaLVaLF68GL6+vnBzc8Ps2bNrtN22lp0QQqpzVPt4+3lkQ45hMpmwcuVKBAYGwsXFBaNHj8bly5drXPdXlf12GzZsqHHd//vvv2PSpEkIDAyEWCxGZGQk3nzzTRiNRvM+K1asgFAoRH5+fo1jzps3DwqFwuI1IYQQW9vQpl6LcxwHjUaDjRs3guM4cBxnbg9rW2vWWhtZXl6O5557Dt7e3pDJZJgyZQoyMzPBcRxWrlxp3i81NRXPPvssoqKiIJVK4eXlhQceeKBGfyohhNiLvdvT2+l0Orz++uvo168f5HI5XF1dMXz4cBw4cMBiv5SUFHAchw8++ABffvml+XkGDBiA06dP1zjub7/9hujoaEgkEkRHR2P79u32eUGIU1EKdNKsHnzwQURERGD16tU4e/Ysvv76a/j6+uLdd9+1un9mZiZGjx4NjuOwbNkyuLq64uuvv7Y6S/u7777DzJkzMX78eLz77rsoKyvD2rVrMWzYMJw7d87iJNJgMGD8+PEYNmwYPvjgA7i4uNRa5v/7v//DlClTMGPGDOh0OmzduhUPPPAAduzYgUmTJjX5NSGEkNvV11Y++eST2LhxI+6//348//zzOHnyJFavXo0rV67UOEFLSEjA9OnT8dRTT2Hu3LmIiooCYwy///471Go13N3dwRjDv//+Cx6PhyNHjmDKlCkAgCNHjoDH42Ho0KEAgBs3buC3337DAw88gIiICOTm5uKLL77AyJEjcfnyZQQGBsLNzQ333nsvfvzxR6xZswZ8Pt9clh9++AGMMfOgI0IIaawHH3wQ4eHhWL16NU6cOIGPP/4YxcXF5sD12rVr0b17d0yZMgUCgQB//vknnn32WZhMJsyfP9/iWElJSbj//vvxxBNPYObMmfj2228xa9Ys9OvXD927dwdgW/tX3erVqyGVSvHyyy8jKSkJn3zyCYRCIXg8HoqLi7Fy5UqcOHECGzZsQEREBF5//XXzYxtSdkIIuZ0920dr55ENOcayZcvw3nvvYfLkyRg/fjzOnz+P8ePHNyn4vGHDBri5uWHJkiVwc3PD/v378frrr0OtVuP9998HADz22GN444038OOPP2LBggXmx+p0Ovzyyy+47777IJFIGl0GQkjbVV8b2tRr8e+++w5PPvkkBg4ciHnz5gEAIiMjG1zOWbNm4aeffsJjjz2GQYMG4dChQ1b7KE+fPo1jx47h4YcfRnBwMFJSUrB27VqMGjUKly9frrM/lBBCmsKe7Wl1arUaX3/9NaZPn465c+eipKQE33zzDcaPH49Tp06hd+/eFvtv2bIFJSUleOqpp8BxHN577z1MmzYNN27cMGci/vvvv3HfffehW7duWL16NQoLCzF79mwEBwc77PUhzYQR0gxWrFjBALA5c+ZYbL/33nuZl5eX+XZYWBibOXOm+fbChQsZx3Hs3Llz5m2FhYXM09OTAWDJycmMMcZKSkqYQqFgc+fOtTh+Tk4Ok8vlFttnzpzJALCXX365RjlnzpzJwsLCLLaVlZVZ3NbpdCw6OpqNGTPGlqoTQojNbGkr4+LiGAD25JNPWuzzwgsvMABs//795m1hYWEMANuzZ4/FvqdPn2YA2K5duxhjjMXHxzMA7IEHHmAxMTHm/aZMmcL69Oljvl1RUcGMRqPFsZKTk5lYLGZvvPGGedtff/3FALDdu3db7NuzZ082cuRIW18OQgipoaqdnDJlisX2Z599lgFg58+fZ4zVPH9jjLHx48ezDh06WGyraicPHz5s3paXl8fEYjF7/vnnzdtsbf8OHDjAALDo6Gim0+nM26dPn844jmMTJ060OMbgwYPrPfesreyEEFKdo9rH288jbT1GTk4OEwgEbOrUqRb7rVy5kgGwuO6vKvvt1q9fb3HdX9tzP/XUU8zFxYVVVFSYtw0ePNjivJYxxrZt28YAsAMHDtQ4BiGkfbOlDbXHtThjjLm6ulq0gVWs9UlWL1uV2NhYBoAtXrzYYr9Zs2YxAGzFihXmbdbazOPHjzMAbNOmTeZtVeew1D4SQprK3u3pyJEjLfoSDQYD02q1Fo8rLi5mfn5+Fv2pycnJDADz8vJiRUVF5u2///47A8D+/PNP87bevXuzgIAAplQqzdv+/vtvBsBqu0xaD0qBTprV008/bXF7+PDhKCwshFqttrr/nj17MHjwYIuRO56enjVmD/7zzz9QKpWYPn06CgoKzH98Ph8xMTE1UmAAwDPPPGNTmaVSqfn/xcXFUKlUGD58OM6ePWvT4wkhpKHqait37doFAFiyZInFPs8//zwAYOfOnRbbIyIiMH78eIttffr0gZubGw4fPgygcqZ3cHAwHn/8cZw9exZlZWVgjOHo0aMYPny4+XFisRg8XuWpg9FoRGFhIdzc3BAVFWXRJo4dOxaBgYHYvHmzedvFixcRHx+PRx99tFGvCSGEVHf7LMWFCxcCgLmNrH7+plKpUFBQgJEjR+LGjRtQqVQWj+3WrZtFW+fj44OoqCjcuHHDvM3W9q/K448/bh5NDgAxMTFgjGHOnDkW+8XExCA9PR0Gg8G8rSFlJ4SQ29mzfbR2HmnrMfbt2weDwYBnn33Wankaq/pzl5SUoKCgAMOHD0dZWRmuXr1qvu/xxx/HyZMncf36dfO2zZs3IyQkBCNHjmxSGQghbVddbag9rsXtYc+ePQBgU/tavc3U6/UoLCxEx44doVAoqF+TEOJQ9mxPq+Pz+RCJRAAql9spKiqCwWBA//79rbZrDz30EDw8PMy3q679q673s7OzERcXh5kzZ0Iul5v3u/POO9GtWzfbKktaLAqAk2YVGhpqcbuq8SkuLra6f2pqKjp27Fhj++3bEhMTAQBjxoyBj4+Pxd/ff/+NvLw8i/0FAoHNKSx27NiBQYMGQSKRwNPTEz4+Pli7di11QBJCHKautjI1NRU8Hq9GO+jv7w+FQoHU1FSL7RERETWOz+fzMXjwYBw5cgRAZQB8+PDhGDZsGIxGI06cOIHLly+jqKjIIihkMpnw4YcfolOnThCLxfD29oaPjw/i4+Mt2kQej4cZM2bgt99+M69dvnnzZkgkEjzwwANNeGUIIaRSp06dLG5HRkaCx+OZ1zP8999/MXbsWLi6ukKhUMDHxwevvPIKANQ4h7u9zQUq293q56e2tn+1HbPqQjokJKTGdpPJZHGMhpSdEEJuZ8/20dp5pK3HqDonvf2c1dPT06ITsqEuXbqEe++9F3K5HO7u7vDx8TEPsKxe/oceeghisdg8IFOlUmHHjh2YMWOG1fXGCSEEqLsNtce1uD1UleP241vrPy0vL8frr7+OkJAQi3NYpVJJ55WEEIeyZ3t6u40bN6Jnz56QSCTw8vKCj48Pdu7cadO1+e3xqKrnur28AMzL/5DWi9YAJ82q+lqw1THGmnRck8kEoHIdcH9//xr3CwSWH/Xqs3jqUrUW7ogRI/D5558jICAAQqEQ69evx5YtW5pUZkIIqY0tbaWtHXfVR3xXN2zYMLz11luoqKjAkSNH8Oqrr0KhUCA6OhpHjhyBn58fAFgEwN9++20sX74cc+bMwZtvvglPT0/weDwsXrzY3A5Xefzxx/H+++/jt99+w/Tp07FlyxbcfffdFqMpCSHEXqq3idevX8cdd9yBLl26YM2aNQgJCYFIJMKuXbvw4Ycf1mivbGlzG9L+1XXM+p6roWUnhJD6NKV9tHYe6Yh2qrbzWqPRaHFbqVRi5MiRcHd3xxtvvIHIyEhIJBKcPXsWS5cutXhuDw8P3H333di8eTNef/11/PLLL9BqtZSNiBDSINbap6ZeizfkuYCabWFDLFy4EOvXr8fixYsxePBgyOVycByHhx9+mM4rCSHNqintaXXff/89Zs2ahalTp+LFF1+Er68v+Hw+Vq9ebZH5p4qj4lGkdaAAOGnRwsLCkJSUVGP77dsiIyMBAL6+vhg7dqzdnv/XX3+FRCLBX3/9BbFYbN6+fv16uz0HIYQ0RFhYGEwmExITE9G1a1fz9tzcXCiVSoSFhdl0nOHDh0On0+GHH35AZmamOdA9YsQIcwC8c+fO5kA4APzyyy8YPXo0vvnmG4tjKZVKeHt7W2yLjo5Gnz59sHnzZgQHByMtLQ2ffPJJY6tNCCEWEhMTLWa9JCUlwWQyITw8HH/++Se0Wi3++OMPi9He1pbEsVVD2r+mcETZCSHti6PbR1uPUXVOmpSUZFGewsLCGhngqmbiKJVKKBQK8/bbZ/8cPHgQhYWF2LZtG0aMGGHenpycbLWsjz/+OO655x6cPn0amzdvRp8+fdC9e3eb60oIaX/qakMZY3a5Fq8t4OPh4QGlUllj++1tYVWfQHJyssWMRWv9p7/88gtmzpyJ//3vf+ZtFRUVVp+HEELsyVHt6S+//IIOHTpg27ZtFu3pihUrGlXOqueqyjBcXUJCQqOOSVoOSoFOWrTx48fj+PHjiIuLM28rKiqyWFe2aj93d3e8/fbb0Ov1NY6Tn5/fqOfn8/ngOM5itGVKSgp+++23Rh2PEEKa6q677gIAfPTRRxbb16xZAwCYNGmSTceJiYmBUCjEu+++C09PT3Nn4PDhw3HixAkcOnTIYvY3UNkm3j5C8ueff0ZmZqbV53jsscfw999/46OPPoKXlxcmTpxoU9kIIaQ+n332mcXtqgE2EydONI/wrt5eqVSqJg1gbGj715TnAexbdkJI++Lo9tHWY9xxxx0QCARYu3atxfZPP/20xjGrBrQfPnzYvE2j0WDjxo31PrdOp8Pnn39utawTJ06Et7c33n33XRw6dIhmfxNC6lVXG2qva3FXV1erAejIyEioVCrEx8ebt2VnZ2P79u0W+1WtK35722dtwLm1c9hPPvmkSbPKCSHEFo5qT62dD548eRLHjx9vVDkDAgLQu3dvbNy40SKF+j///IPLly836pik5aAZ4KRFe+mll/D999/jzjvvxMKFC+Hq6oqvv/4aoaGhKCoqMo/ycXd3x9q1a/HYY4+hb9++ePjhh+Hj44O0tDTs3LkTQ4cOtXqhXZ9JkyZhzZo1mDBhAh555BHk5eXhs88+Q8eOHS1OSAkhpLn06tULM2fOxJdffmlOA3nq1Cls3LgRU6dOxejRo206jouLC/r164cTJ05g8uTJ5vZ0xIgR0Gg00Gg0NQLgd999N9544w3Mnj0bQ4YMwYULF7B582Z06NDB6nM88sgjeOmll7B9+3Y888wzEAqFTas8IYTclJycjClTpmDChAk4fvw4vv/+ezzyyCPo1asXJBIJRCIRJk+ejKeeegqlpaX46quv4Ovri+zs7EY9X0Pbv8YaN26c3ctOCGlfHN0+2tpO+fn5YdGiRfjf//5nLs/58+exe/dueHt7W8zYGTduHEJDQ/HEE0/gxRdfBJ/Px7fffmu+pq8yZMgQeHh4YObMmXjuuefAcRy+++67WlNYCoVCPPzww/j000/B5/Mxffr0Rr6qhJD2oq42FIBdrsX79euHvXv3Ys2aNQgMDERERARiYmLw8MMPY+nSpbj33nvx3HPPoaysDGvXrkXnzp1x9uxZi8ffd999+Oijj1BYWIhBgwbh0KFDuHbtGgDLGeZ33303vvvuO8jlcnTr1g3Hjx/H3r174eXlZcdXjRBCanJUe3r33Xdj27ZtuPfeezFp0iQkJydj3bp16NatG0pLSxtV1tWrV2PSpEkYNmwY5syZg6KiInzyySfo3r17o49JWgaaAU5atJCQEBw4cABdu3bF22+/jY8++ggzZ87EnDlzAAASicS87yOPPIJ9+/YhKCgI77//PhYtWoStW7eid+/emD17dqOef8yYMfjmm2+Qk5ODxYsX44cffsC7776Le++91y71I4SQxvj666+xatUqnD59GosXL8b+/fuxbNkybN26tUHHqQpwDxs2zLzN398fHTt2tLi/yiuvvILnn38ef/31FxYtWoSzZ89i586dCAkJsXp8Pz8/jBs3DkDlbHBCCLGXH3/8EWKxGC+//DJ27tyJBQsWmNOTR0VF4ZdffgHHcXjhhRewbt06zJs3D4sWLWr08zW0/WssR5SdENK+OLp9bMgx3n33XSxfvhynT5/GCy+8gKSkJPz9999gjFlcywuFQmzfvh2RkZFYvnw5Pv74Yzz55JNYsGCBxfG8vLywY8cOBAQE4LXXXsMHH3yAO++8E++9916t5X388ccBVM5IDwgIsLmehJD2qa42FLDPtfiaNWvQr18/vPbaa5g+fbo5U4aXlxe2b98OFxcXvPTSS9i4cSNWr16NyZMn1zjGpk2bMH/+fOzcuRNLly6FTqfDjz/+CMCyr/T//u//8Pjjj2Pz5s14/vnnkZ2djb1798LNza2xLxEhhNjEUe3prFmz8Pbbb+P8+fN47rnn8Ndff+H7779H//79G13WCRMm4Oeff4bRaMSyZcuwbds2rF+/vknHJC0Dx2i1d9IKLV68GF988QVKS0vNaS8IIYS0PPfeey8uXLhgdT0yQghpqJUrV2LVqlXIz8+369rbhBDS2rWW9lGpVMLDwwP//e9/8eqrrzr8+c6fP4/evXtj06ZNNCCTEFKr1tKG1iUuLg59+vTB999/jxkzZji7OISQdqottKek7aAZ4KTFKy8vt7hdWFiI7777DsOGDaPgNyGEtGDZ2dnYuXMndTYSQgghhLRDt1/LA7fWehw1alSzlOGrr76Cm5sbpk2b1izPRwghzaG29pXH42HEiBFOKBEhhBDS8tAa4KTFGzx4MEaNGoWuXbsiNzcX33zzDdRqNZYvX+7sohFCCLEiOTkZ//77L77++msIhUI89dRTzi4SIYQQQghpZj/++CM2bNiAu+66C25ubjh69Ch++OEHjBs3DkOHDnXoc//555+4fPkyvvzySyxYsACurq4OfT5CCGlO7733HmJjYzF69GgIBALs3r0bu3fvxrx58+y+RA8hhBDSWlEAnLR4d911F3755Rd8+eWX4DgOffv2xTfffEMjGgkhpIU6dOgQZs+ejdDQUGzcuBH+/v7OLhIhhBBCCGlmPXv2hEAgwHvvvQe1Wg0/Pz8sWrQI//3vfx3+3AsXLkRubi7uuusurFq1yuHPRwghzWnIkCH4559/8Oabb6K0tBShoaFYuXJlsywtQQghhLQWtAY4IYQQQgghhBBCCCGEEEIIIYSQNoHWACeEEEIIIYQQQgghhBBCCCH1WrlyJTiOs/jr0qWL+f5Ro0bVuP/pp5+u85iMMbz++usICAiAVCrF2LFjkZiY6OiqEELaMAqAE0IIIYQQQgghhBBCCCGEEJt0794d2dnZ5r+jR49a3D937lyL+9977706j/fee+/h448/xrp163Dy5Em4urpi/PjxqKiocGQ1CCFtWLtZA9xkMiErKwsymQwcxzm7OISQJmCMoaSkBIGBgeDxaByPI1CbSUjbQW2m41GbSUjbQu2mY1GbSUjbQm2mY1GbSUjb0pbaTIFAAH9//1rvd3FxqfP+6hhj+Oijj/Daa6/hnnvuAQBs2rQJfn5++O233/Dwww/bdBxqMwlpW5raZrabAHhWVhZCQkKcXQxCiB2lp6cjODjY2cVok6jNJKTtoTbTcajNJKRtonbTMajNJKRtojbTMajNJKRtagttZmJiIgIDAyGRSDB48GCsXr0aoaGh5vs3b96M77//Hv7+/pg8eTKWL18OFxcXq8dKTk5GTk4Oxo4da94ml8sRExOD48eP2xwApzaTkLapsW1muwmAy2QyAJUvlLu7u5NLQwhpCrVajZCQEPP3mtgftZmEtB3UZjoetZmEtC3UbjoWtZmEtC3UZjoWtZmEtC1tpc2MiYnBhg0bEBUVhezsbKxatQrDhw/HxYsXIZPJ8MgjjyAsLAyBgYGIj4/H0qVLkZCQgG3btlk9Xk5ODgDAz8/PYrufn5/5Pmu0Wi20Wq35NmMMALWZhLQVTW0z200AvCrlhbu7OzV+hLQRlMrGcajNJKTtoTbTcajNJKRtonbTMajNJKRtojbTMajNJKRtau1t5sSJE83/79mzJ2JiYhAWFoaffvoJTzzxBObNm2e+v0ePHggICMAdd9yB69evIzIy0m7lWL16NVatWlVjO7WZhLQtjW0zW/dCE6RVqBp5RQghhBBCCCGEkLaDrvcJIYTYin4z2i6FQoHOnTsjKSnJ6v0xMTEAUOv9VWuF5+bmWmzPzc2tcx3xZcuWQaVSmf/S09MbU3ziRIwx8x8h9tZuZoATx9MZTBAJbo2pSMwtwfwtZ5FRXI6RnX3w4IAQjOjkAz6vdY9wI4QQQgghhBBC2prCUi3iM1Q3/5S4mlMCrcEEE2MwmhhMJgZj1f/N/wJTewfilUld4SuTOLsKhBBCWhCN1oC4dCUyisuw80IOJnT3x7S+QZAI+c4uGrGz0tJSXL9+HY899pjV++Pi4gAAAQEBVu+PiIiAv78/9u3bh969ewOoTH188uRJPPPMM7U+r1gshlgsblLZiWMwxlCiNSBHVYEsZTmu5ZbgYqYaSXmlKNHqodEaUVphgM5oAgAI+Rzu7OaHRXd0RrCHFK5iCl2SpqNPEWk0g9GEPZdy8G9SIU6nFCGlQIPhnbxRqNGBMSClUIOSCgMAYPfFHOy+mIMAuQT39wvGg/1DwONxcBMLIJcKnVyT5rfnYjYuZakhFfHx8IBQeLqKnF0kQgghhBBCCCHthKpcj4uZKpzPUOLCzaB3prK8Ucf6LS4Le6/k4bk7OmLWkAiLgfGEEELaH3WFHst/u4i9l3Oh0RnN248k5kOjNWDuiA42HadUa4BbtSDY7ZOviPO88MILmDx5MsLCwpCVlYUVK1aAz+dj+vTpuH79OrZs2YK77roLXl5eiI+Px3/+8x+MGDECPXv2NB+jS5cuWL16Ne69915wHIfFixfjv//9Lzp16oSIiAgsX74cgYGBmDp1qvMqSmxiMJpwPkOFo4kFOJNahCxlOXJUFRbf//rojQx/X8rFs6M6Ql2hR666AgAQ7OFC33vSaBQAJ42i0Rrw1HexOJpUYLH9QEJ+nY/LVlXgk/1J+PRAEngcB4mAhzUP9cb47rWnMmkrGGOo0JuQVlSGZzafRVVWj7Opxfjq8f6tfu0XQgghhBBCCCEtT5nOgEtZapxPVyI+Q4ULmSokF2js+hylWgPe3nUVW0+nY8Xk7hjZ2ceuxyeEENI65KorcM+n/yLnZvCqunem9cBDA0IBAMUaHTxcRajQGyHgcRDwLQNcFzOVmPb5cQzv5A2d0QQfNzEuZakxIdofGcXl+N+DvZqlPsS6jIwMTJ8+HYWFhfDx8cGwYcNw4sQJ+Pj4oKKiAnv37sVHH30EjUaDkJAQ3HfffXjttdcsjpGQkACVSmW+/dJLL0Gj0WDevHlQKpUYNmwY9uzZA4mEMsy0VMeSCrDxeAqOXS80T4RsCoOJYdHWc9i1aDjE8spMEWdSipBfosXEHtazBxBSFwqAkwb77Vwmvv03GfEZqvp3rgVjgJExaHRGPPN9LD58qDfu6R1kx1K2LL+dy8Q3R5ORmFcCkwmovqTF3it52HAsBbOHRjivgIQQQgghpFloDUbkl2gR7OHi7KIQYiElJQVvvvkm9u/fj5ycHAQGBuLRRx/Fq6++CpHoVsaq+Ph4zJ8/H6dPn4aPjw8WLlyIl156yYklJ7c7n67Eviu5SC4sw7Wcksrr0GZaVvFGvgYzvz2FsV398Prd3RDqRW0dIYS0FzmqCtz54aFaA2GXs0qQq67AjvgsfH8iDa5iPhJySiCXCvHKXV1xOqUYAyM8cDFTjev5pdAZTdh3Nc/iGAm5JeDzOEwfGIL+4Z7NUS1ixdatW2u9LyQkBIcOHar3GLev+cxxHN544w288cYbTS4fsb9ynRGFGi0yispxPkOJc2lK7LmUY/fnuZ6vwcNfnsCvTw8Bj8ehf7gn4tKV0BtNEPJpJjhpGAqAkwb7eF8ibthxtLiJAc//dB4yiQBjuvjVu/+VbDVMjCHMy9UiDY49aA1GXM0uQXyGEtfzNRALePB1l4DPVZaz6mc50scV/cM9631+xhh+PZuJZdvioTfW3uOwetdVDAj3RHSQ3I61IYQQQkh7k6euwLl0JUZ08oFURGvrtSS/xGZg94VsnM9QQmsw4fSrYyER8mEwmmrMeCHEGa5evQqTyYQvvvgCHTt2xMWLFzF37lxoNBp88MEHACrXYhw3bhzGjh2LdevW4cKFC5gzZw4UCgXmzZvn5BqQKq9sv4BLWWqnlmHvlVwcvpaPuSMiMH90R7iIqPuJEELauuIyHUoqDBDwOBhMDByAPqEK8HkcynRGbDqRgh3xWVCW6VC9m7SgVIclP50HAPxwKg0A4C4RQMTnoLPSnyri86gPlZBmcCO/FKt3X8WxpAJzOvNwLxfklmhR3oD05g11Lk2JhNwSdA1wBwD0DlE47LlI20ZXIKTBZBIBvN1EKNMZUWanhs5gYvjPj+dx+MXRkLtYXxM8U1mOt3Zexq4Lt0YWDe/kjbfv7YEQz8aPKs9RVeCbozdwKqUYV7LU0BlNNj2Oz+PQJ0SBR2JCMbV3EHg8yxTmyQUaLN56DudtmCmvM5rw3A/n8OfCYXC1c1CfEEIIIe1Duc6IaWuPIaO4HDKJAE+PjMSzoyJrLLOSqSyHm1gAudT6ORexL8YY3tl9FV8cvmHeJpcK8fauKwiQS7HlVCoEPB56BMkRoJCgW4A7hnX0hpeb2OqxCkt1yFZV4EZBKUq1BtzXNxgSIQ12IE03YcIETJgwwXy7Q4cOSEhIwNq1a80B8M2bN0On0+Hbb7+FSCRC9+7dERcXhzVr1lAAvIW4lKVyevC7is5owmcHrmPb2UxsmjMQnfxkzi4SIYQQB+riL8P0gSE4eaMQPI6DTCLE2TSlxT4mxtAjWI649Lr7S7sGuONkcpHV+8r1RvxwKg3pReXo4i/D3b0CaKAVIXa2/VwGvj6SXOO8MqWwDB193VCk0aFIo3PY86cWaswB8IbIVVfg+PVCdA1wh1TEg0TAh1jAh1jIg4jPqxHDIW0b/TKQBjGZGK7klEBnMCHEQ4ooPzGu5paAB0Ao4EFZpm/Q8QZGeEJvNOFaTgk8XIT48sgNvDg+ynx/fIYSLiIBdl3IxucHk1ChtwxOH0kswB3/O4S1j/bFHV3rnz1+u03HU/D2ris1jmsLo4nhTGoxzqQW4/sTqXh1UlcYTUCPIDmkIj6+PnLDpuB3lRsFGqz44xI+eIDWsCGtm6pMj1V/XkJchhJ3dvXDsru6OrtI7Yq6Qg9NhQH+cgkyi8shFvIhkwgsgiPKMh3cJULweBwq9EYwBpopaoXJxKAq18PDtTLta0mFHpey1BjUwQsAcDlLjYtZKhy+lg9vNzEeGhACT1cR/Nxrrk+lKtdDZzDhx9NpGBzpbX7dh3XybtY6kbZNyOfMKcFKKgx4/68ExKUr8dSIDub0gIev5ePY9ULsuZiNtY/2a9QFJWm46/mW2ZNU5XpsOp5qse329Xj7hXlgaKQXFC4i7L6YjTKdESUVBvi5i1GhNyHEU4rBN9sjQhxFpVLB0/NWetHjx4/j/9m77/DIyrLx499zpveS3su2bO+7LL0KiIKC2JVi74qvBX1VEPwh9oL6qq8igsirIiiiIFVg2d77bnbTezK9t/P7Y7Kzm2SSTHp29/lcl5fJzJkzz4TNyXOe+37u++KLLx5QEv3qq6/m/vvvx+1243A4hpwjGo0SjUYz3/t8syM4e7b68/bWmR7CEB3eCPvbvSIALgiCcJaTJIll5Xb+uLVl2GPcoTjhuJ/l5TZ0GpmtDe6sx40WWLv7qYOZrx/d2swTHz9/SOKvIAhjpygKD25s5Jv/ODjsMfXdASocBlyTVyR4iI8+spP5RWZuv6CGNdVOavJNyBKZ3/NEMoUrFKMvEKM3EOVAu4/tjS42He8jqSgsLrFxtNs/pCWDViWjU8voNDI6tQqtuv97tZwJlJ/8esBzGhX6/v8ffLxWdep82c5z+vupRgjA72v18OjWFpaX27h0QSHFtqHri8LYiAC4MCZtnjCxRDpY3OIO0+IO4zBqsOo1RJMpILcA+PoaJ75InF3N7kxp8GBfiJ+9VI9alnjz8lJer+/l638/MOq5YskUH/r9dvLNOm45v5pPXDY3pzH85rUG7vvnIRIpBZUEI1QoH9XOZg83/WITkL6ILi61sq9t7D3S/7KjlU9eNpfqfNP4ByMIM+Bwp49Nx/uYW2jGYdRy6wXVzCkwi4oGUywcS7LpeC+tnjDzCsw0ukKc6AnwxK529BqZ65aWsLDEijccp8iq54qFhXzxL3vZdLyPt60u5/KFhTyzv5OmviCldgOFFj02g4YyhwG9WkYlS1gNGqrzTGjVuZfnDUQTuIMxwv1BXrUqPbmrdBpnfb+evkAUh1GLLEuE40lePNzNmmoHsiTR7gnzi5ePs/lEHwUWHWuqHOxpcVNg1lHuNKLXqHCatGw50cdTe9u5ZUM184osNPYGeWxbC4c6fPznaA9wFEhXVCmzG3jg3StRyzINfUFsBg0Liizid0cYF7VK5j3rK7n36UOZx5472MXBdh//+uxFWPUaXjzcze9ebwTgrT/fyH03LuWtK8tnaMTnhuM9QZ4/1DXm1+1ocrOjaeiC4Hm1Tr7zNpEwKUy9+vp6fvrTn2Z2fwN0dnZSU1Mz4LiioqLMc9kC4Pfddx9333331A5WANLJek/sapvpYWTV0Bua6SEIgiAI0+D8uXkUWXR0+aPDHhOJp4gnUzS7sv9tWFFh51iXP+f3vOOq+SL4LQgTpCgKXb4oP3juSP/a1cgSKQW5v23sVDnaFeDLf90HgF4jo1HJ2I0aApEE7kEbMY1aFUtKrZTY9DT1hdjRnD25JpZMEUumGOESNaXUspQJqJ8eSLfo1UTiSfa3+/jjVrDo1PzvLWsosupFrGgCxOqqMCY/ffHYkMfcoTiJlDIkm2Yk/kicQx3ZJzI/fuEYP37hGLoxBFtSCnT7o3zv30dwBWNcs6SYlRX2Yfsp/n1PO/f84yCrq+yEYymOdvkpsWrp8E78yhdLpjjU4SMxzqv/nlaPuKgJI6qurqapqWnI4x//+Mf52c9+RiQS4fOf/zyPPfYY0WiUq6++mp///OeZxcmpUO4w8t7zzLM+uDnTYokUwWiCREqh2RWkwmmkqS9EucNAY2+IvmAUCYnrlpXQ1B8MtRu1HO8J8KftLfx9dztvWFRENJGi2KZnXY2TeUUWnj3QxXefPUIwmiClgFmnxqJX8+Lhbl491otGLROOJfj5y/U09AbxRxI88FI9D7xUP+J4tSqZpeU2PnX5XC5dUJjz51TLEoVWHTr17NtVrigKwVgSRVHo8EboDUSJxJOoZZkndrWxuNTKTavK2dboos0T5rzaPHRqFQ+8dIxSu4Ftja7MjcDJEtIfvKiGd6ytoMMb4YMPbWd7o4s5hebM52/3hNnX5skEspaUWblmcTGSJPHRS+bw6NZm7vr7AZL9fzfWVTu55fxqGvuCXLe0hD2tHlZVOibU7kM4+22s72Vvq5c9LZ4hz7V5wlz23ZdZX+tky4lTZQQj8RSf+789tLrCfOqKedM42nNHtz/CZ/9v17DPVzgNFJr1eMKxIbvEhxOJT12vNeHs9OUvf5n7779/xGMOHTpEXV1d5vu2tjauueYabr75Zj70oQ9N6P3vvPNO7rjjjsz3Pp+PioqKCZ1TyO6Xr5xgfpGZHn+Uxr7ZFXAusAxt6yAIgiCcfQwaFd2BKCsq7Oxu8VBm1yNL6YBPnlnH7hY30YRCNJ4aEsCCdFWrPS0ecllVNWlVfPW6RVw8v2DyP4ggnMU6vRE21vfS5ArhCaVbbDmMGpr6QsO2HhiswKyjwxuZ4pGeEomniMRTQ2JQtfkmtGqJaEJha2P2oPdskkgpJONJFpfZSCYVoskkwWiS7YOS3/3RBO/41WYg3Qb4DYuKuHRBoVgbHCMRABdy9tqxXv40TDk1fyTBohILB4cJap9OLUMsh+3Wcg6Ze0vKrKgkCQWQSF9AfvNaA795rYGlZVbUKpliq54iqx5PKIZFr8GiV7Or2c3aagfbTrsoFlkNVDhMxFMpdg3qTzNWC0us7MqyAJ2LXc0eblhRNqH3F85u27ZtI5k8tfi9f/9+rrrqKm6++WYAPve5z/H000/z5z//GZvNxic/+UluvPFGNm7cOGVjMovdqjmRUPif/xzn+UNdHO8JYtSq0GtUmHVqSu16LpiTz0XzC/jA77bxwuFutCqZ922o4tNXzOOFQ910eCM8dFrJ3PdvqCIUS6KWJf7y0Q3MK7TQ4g6xvdFNKJ6koSfI5hN9+MNxXKEYyaSCWiWhVcnEktlbP8gSLC23c9ebF1FXbB1XafTZ3ou23RPmX/s6ea2+hwqHkTKHAaNWxflz8lDJEp/7027etqqcp/d20OuPEk+l+OPWFowaFSf/MtXmm/jYpXN468oyEimFhzc18ZvXGuj0RZAkKLHpKbHraewN8s1/HKS+O0AipaBVySRTsLvFyxuXFrPlRB/f//eRTPAbYGuji62NLrQqmZ+9VE88maKu2MoFc/OpzjNy/YpS0d9MGKCxN8h7/nfLiMf0BWP8c19n1ue+/9xRUgp8+oq5mZ0T/kiceFLBadJmfY0wuua+EF96fC/724aWe1bJEtV5Ro73BGlxhYF0haTRFhuWl9s40O7jM4/twqBR0ReMUeU0csv51VQ4jShK+lpyvCfIsS4/bZ4w7z2vasB1ORRLjFp6TTi7fP7zn+fWW28d8Zja2trM1+3t7Vx22WWcf/75/OpXvxpwXHFxMV1dAysanPy+uLg467l1Oh06nQh+TrUdTW5+8fLxzJwiz6SlOt9ESlE40RPEGx5bu7LJ5pnCHpGCIAjC7FFo0XP5gkJePtqDWaemzXMqQFbfE8Rp0lKTr8Nq0HC8d2gCaJ5ZRySeHLXN5rJyG3ddv5hVlUOrzwiCkBZPpmhxhajvDnC8J0h9d4A9rR7quwPjPmehRUeJTU9PYIa2UA+SZ9YOiPGcCdZWO9iaY6IBpNsAv3qsF63qEF9700LesbZyTJU6z2Vi9VTIydYGF5/6484Rjxlpw7NJq2JOoZlef5TeYCyni6zVoCY8yg4Xk1Y9YKGwxKZnfY0ThXQvitH6xZxu92kB6zK7fsAEbax2t3owamRC4+gtvrfVM+oxwrmtoGBgZuu3v/1t5syZwyWXXILX6+U3v/kNjz76KJdffjkADz74IAsXLmTz5s2cd955MzFkoZ9GreJ9G6ro9EW4YUUZrx7rYVujG1cwRrMrxOYTLn75ygmM/UHnWDLFb15r4Fh3gHeureB3rzfS6g5nzneyf6xKlvCG46ypdqIoCufVOunwRthQ6+Trb14EpHc+S5JEPJniH3vb6QvEiCVTxBMKa6sdLCq1ZnqBz/YA9ulOfq7ReEIxDnb4WFhsxWbQ8NFLa7l4fj7PH+rCadTgDsX5xX+OI0sSF87N5zcbG9jV7BmQgemPnsoyzTNruWheAa/V9/LVJ/bT5jn130VRwGbQcPWPXuHEoB2dsWSK+m4/x7sDpBSF1+p7SQ3zBzRdlin99b42b6a1xg+fP4pJp+Z3t66jMk9kfgrgmYSgxg+fP8rmE30sKbNy7dISbvnNVvItOp7+9IUi4SJHJ4PPkiTxs5fq+e6zR4Y9dn6RedhqSDX5JuxGDfVdgQHXnZWV9kyS5uDd4k/ubmNFhYNuf4T67gCh2Kk59L1PH2JuoZkyu4GlZTYe3NhAucPI29dWUJtvYnGZlUKL6C12NisoKBgyfxxOW1sbl112GatXr+bBBx9ElgcurGzYsIGvfvWrxONxNBoNAM899xwLFizIWv5cmB7eUJxP/3HXgIS6vmCMvtPuh+cVmnCadHhCcY51+6e0XGU2D7xUz8cvmyuSbwRBEM4Blywo4IXD3QSiQ6uFuoIxXMEYalkasnY6t9BEiVXPq/V9AFnLK79tdTnfuWkZsvh7IghDdPsjbDnhYvOJPrY3ujnRG8i0n52894jiNGlpn0DsZLLoNfK0z2knw75WH8vKbextHVsL3Vgyxdf+dgB/NMHHL82tDfC5TqxmCSNKpRR+9lI9P3z+6LgvJmoZ5hdZxrwj2qxT08XImUTbGlxcMi+f1+p7qSuxYtCoONYVwBWaWHZ5nlk3oQD4igr7uHeR72/3EU+mRClpISexWIxHHnmEO+64A0mS2LFjB/F4nCuvvDJzTF1dHZWVlWzatEkEwGfYlhN9vHKsh6+9aSGvHO0lkVJYUmYdsDswEE0QiCYosOiIJ1OsrLCz+YSLV472sKDIQp5JO2AxEyCZUvjX/k7+tf/U7s5Ci44lZTZMOjUXzc3n7WvTpUY1Kjnnfr97Wz1o1TJ1xVYA3MEY7d50oNdp0qIo6f+PJ1OYtOopvwGNJ1NE40l+/MIx3r+hGlcoxqbjfSSSKa5dWkJtvomXj/bw6JZmlpTa+OiltWhkmb/uauX1+j5CsQS+SIJQLEkimaI630QgksCkV3N+rZN/f/Zinj3QxVee2DfiLqmL5uXzzRuWcKTLzzefOjgg+H3ScBVT0p9DARRcwRixRAq9RuaiefnEkwqdvnRZ9kAkMaSVxlWLinj/hipKbAZMOhXFVhGwEtLUk/S7t+lEH2uqHSwrs/HeDVX84uXj/Hl7K7ecXz0p5z9bJZIp1CqZo10B3v3rzVy7tJjto2SgW/WaIY91+6OoZWjo3wkzuFqRMkJeZW8gNmyfcYl0Ymh9dyDTwuFIl597/nEQSJeZ/PqbF/OONRUii/wc19bWxqWXXkpVVRXf+9736Ok51fvv5O7ud7/73dx999184AMf4Etf+hL79+/nxz/+MT/84Q9natjnPEVR+NLje7POR053rDsIpK8vZq2KuUUW1LJEsytE9zQ0QYwmUnzzqQP895sWiXtdQRCEs9w71lbw6JZmDncOTPgssxtQUHAYtZh0ava1eVlcaqXDG8YTilPfHaSxN8Sl8wto84RJpBSa+oKZNeklZVYR/BYE0vO/4z1BdjW7Od4T5HhPgGNd/mlrgWMaR7XIqbCk1DakdPiZIBxP4g7GcBq144pj/ftAlwiA50gEwIUR9QSifP+5ozkdO1wJ5NoC87jKgWdbGBxsYamV/xzrZU2VI3OxW1fjHFMJicz7GdRUOAxEE+kStSU2/bj6WCwqsbJ3nOXPId0j2BeOk2cWZQKF0T355JN4PJ5MWcvOzk60Wi12u33AcUVFRXR2Zi99CxCNRolGTy18+XxDy7UKE7e+Ng+rQcMz+7sosur5yhsXEo2neGRzExvrezM7/Sw6NZ++Yh7XLyulzRPmzztaiCdTLCu38/iOVjR9Ibr8EZTT4qMWvZpPXjaXJWU26oot9AaiPLy5iT0tHnY2ufnVqye4ZH4BX3vTopzHu6zcTuK0UukOkxZHlnLI07Fj3BOK8ftNTTS7guxt9fZnkiusrXYiSxJmrYpmV4gqp5HPXjmP7Y0u/r67jeuWlnK8J8iiUivn1Tqp7w7w2LYWohIcbPfhi8TxhOK8Xt9LIgX727zkmbUjBsD3t3l5y8824ovEB/w3OJ2mv9R8PKkQS6bIN2u5aVU5Vy4qQqOS+cPmJp7c3Qak+xhtOtFHdZ6JmnwTb1xaQrFVz4Vz8zHpVJmECLELVxhOLm1jcmEzaPjYpXNQq2S+dE0dFr2aJWU2nj3QSaXTSKndgM0w+vzsXPK1J/eTVBT+31uXpqtrBGM8srmZEtvICSre8NCb3IZBJSB3t3hwmrSUOwzEEil2D1MlSKuS0Kpl5hVakKR0VZBQLEkknsRm0NDhjWDVqznSdaoCk1mnwm7Q0uoJE08qfO3J/fzPy8e5vK6Qd62rZFGpdew/DOGM99xzz1FfX099fT3l5QOT5U5WOLDZbPz73//mE5/4BKtXryY/P5+vf/3rfPjDH56JIQvAH7Y088yB4ef52QRiyQEV0ModBkrtekKxJMe6AkQTY69klot/7u/krusXT8m5BUEQhNlDp1axoNhCSlHSyfKSRDSRpCcQpdsfHbBz9ED7wPUnBej0RTjWXz20ymlkbqGZDXPyuHRBgQh+C+escCzJMwc6ePVoLxuP99Llm7kS5IFoAp1anrI5Y672tHpYV+2gyxelyTU9wf/J0uIOY9WrWVhiGbY63HAuW1A4RaM6+4iVVGFEuQQ1VlbYcYdiHO3K/ovaM85s8pF2oDhNWuYVmjnek54MnZ7ps7XBxaISKwc7xhbAq803sbvlVNmJdAbi2APgeo3MRCuLfPfZIzhNWgotOt63oVqUiROG9Zvf/IZrr72W0tLSCZ3nvvvu4+67756kUQkjWVhiZWGJFUVRaOwLUZNv4sJ5+Rzt8hNPpvjrzjaWlFlp7gvz85fr2droosUVojcQA5qznnNdtZMFxRY+cGEN6v4dNXlmHZ+9cj5P723n9eN9NLtCbG3s45ofvYI7FOP9G6r5yMW1meOHM9rzU01RFPa2egnGEnT6wkTjKcrsBtzBGNV5Jo52BXjP+koe3drCb19r4O4bFrO31YvdqOFAu49Nx108va+DaCJFbYGJC+bkk0gqmSodyyts9AZiuENxvvH3AzmNyT1CLzKtWuZjl8zh01fMQyVLKIqCOxTHbtAMuFFfUWHntgtq+Nf+Dv61v5OG3iCHO/0c7vTz3MEu8s06Ht/RwuoqJ5VOI+5QFLNeg0YlU+YwsK7aiWmYxDPh3DNZ84RIPEl9d4Bl5XYAPnLxHEKxBBVOA8/s7+T3m5r47tuWsVL02QPSAeqHNzfx9jXl9Aai/PTF+sxzo80ho4nRJ4urqxxE40l29c9PJdILgidZDWoWFluJJpLsbvGOmHDa7ZdYX+MkEk+i16jo8kXwRRJU5xnxRxL0BWO0ecI8vLmJx7Y18651lVyzuJgNc/JyajMhnB1uvfXWUXuFAyxbtoxXX3116gck5OTRLdnnh2PR6g5n2uxoVBKLS62YdKr0YuIk7iTq8UfpC8bIF8negiAIZ72mvhBHuwa2wLTo1ayqcLCjefgdm1q1jD9yqnR6kyu9AeBDF9cyt9AyZeMVhNnm73va+b9tzRSYdaysdPDTF+vpnSV9t490BahwGvCFEyNuIJlq8aTC1kY3GpXEnAITkN7Q6QsPbb8wG/kiCYJdAawG9ZjGvPF4L5+5ct4UjuzsIVZOhRFFEyP34IZ0Od3Ty2usq3aSQkFGIqUo+COJEYMFwxmuDJtWJRFLpAb0/h6ssS/IumonWxtz2wmuV8sc6Rw4KRtP8BuYlEXCx7a1ZL4OxZN86KJaUSZOGKKpqYnnn3+ev/71r5nHiouLicVieDyeAbvAu7q6MqUrs7nzzju54447Mt/7fD4qKiqmZNxCmiRJ1OSbMt/PL0rfyO1v89LuiaBVy0QSEutr8lhebudQhw9vOI5KlmjsDRLs7+8qS/Dtm5ZSW2Ae8h75Zh03rChjW6M7k02okiWSKYXvPnuEBzc2UJ1n4iOXzOGqRUXT8KlH1+OPolXJIMGBNi/PH+rm73va+8uEF3BpXQHffOpQZoJ948oyvvT4PrY2uJAkWFJm47FtLVkrgZzoCXKiJ8jpscKWvjDrapwc6fRPeNL+lTfW8ZYVZRSeVppckiScWXbNAywqtbKo1Mrn37CAaCJJQ2+Q7Y1uvvH3AwSjCU70BtnR7MGkVbGi0k4qlS5RDfC5K+eLya6QMVkBcKdJyxO72jIBcJUsYdFrsOg13LC8jB8/f4xvPX2Ie9+6JNMa4Vy1u8XD7b/bBsCfd7Ty0pGeUV5xSoXTMGS392BFVh0trhAlNgPLymwc6U+SWlRipcMTwRWKUeU0jjgfPl0ypWQ91hWMMa/QTFJR8PTP1+NJhd9vauL3m5q4cG4+N60uozbfzLJymwiGC8IsNNm/lvGkMmA33oIi84AKEhP18Ud28v9uXMrcwqFzV0EQBOHs4A7G2N82tLft3AIz8WT2HaOLStKJnSatmr2DXhuJp/jvJ/fz1CcvxDBLSi8LwlR787ISfOE4zx7oxKBV8a/PXIQ7FONHzx/ln/vGVv1nKrgDMRaWWtnd4pn0PuNjFU+mS8LLUvpasj985lQ2XVlhH3MZ960NLk70BLKuBQsDiQC4MKLj3SMvzsHQG+5uf2RS+k0Eo9mzXtLlZEfOiAnFkv3lcXOzsMQ6ZNeMKxhjUYmFg2MsQTFZfThP+s4zR7i8rvCcX2gWhnrwwQcpLCzkuuuuyzy2evVqNBoNL7zwAjfddBMAR44cobm5mQ0bNgx7Lp1Oh04ndmLMBtcvL+MLf9nDxvpewvEksiShUckYNKp0z+j+m8WafBPfu3kZFr1m2AmPoqQDHu9aV8mHLqrFatCwsb6XBzc2UGIzcMOKUi5dUEiBZWb/23vDcTyhGM/s7+S1+l5O9AQpsur44tULiCWT3H/TUn6/qZHnDnZSaNGRb9YSjCZQyRLuUIzXj6eDwreeX803nzpIqyuESavKJAkMdrJ/2LoaJ5FYknZPeMLB70sXFHD7BTXj3jGvU6uoK7ZSV2ylLxDjh88fJRxPj9+sV/PxS+dy/pw8mvpC+CPpHbmCcNJkBcBXVTn40jV1WZ+zGTVcu7SYb16/5JwvO/jK0R4+/PB2IvH09VhRxlbxqNiqp8U1cq/ek+Xs2jwDEzIPtPtQyRIalcS+tsm5qT/WHRjQb9ygkSmw6Gh2hXmtvpfX6nsBWFVp5/tvX0GV03jO/xsQhNlksu8/B+sNxDBoVJl5yUQ1u0KZkvqCIAjC2anFHWJuoZn67gCJ/hvwpWVD115Pp5LTLYFSw/yJ8IXjIvgtnFMkSeI96yu5aVV55t++w6ihwmGc4ZGlJRUFVzA248FvgPlFZjQqGaNWlbmvPRMsKLZwaIxVjE/61/5OPnGZ6AM+GhEAF0Y0nqzsxHAzlTEyalXkm7X9ZX9PUcsS8Rzeo6E3yOJS66gXPqdJO2zW/HgmVsNlMo6XzaBhQZEo8SMMlEqlePDBB7nllltQq09dym02Gx/4wAe44447cDqdWK1WPvWpT7FhwwbOO++8GRyxkCuDVsUD715FMJqg2x/lX/s72NnkxhWMkUgp9AailNr0PPDulSwutY14LkmSuHrxwJ3/Nfkm3nte1VR+hGFtrO9ld4tnwARNURT+vL2FX75yAlcwRrL/+m41aPjn/k4e2dzMEzvbuHZpCU5ThL/saEWnkfn4ZXP5y/YWXjrSg1Yts6DIwsObmzKvP+mCuekd9LFEir2t3gGVQRp7g9gMmkzJz/HSqCS+cPWCCZeL39rg4tevnqCxN8h33raMArOOeUVmCi36TFuQ6tOqBgjCSZMV/Hh6bwdLy2x89JI5hGPJzDzIG4pjM2q454Yl5/wO4B1Nbj76yI5M8Hs8JvoTTKYUJicMdcr+dh+VTiMGjYpOXyRrG6SdzR4u+97L6DUyVy8u5kfvWHHO/3sQhNlgqttl9QVj42oxNhxfJM7ML5MKgiAIUymZUih3GDnceWpT0WjrxSmFYYPfkC5r3BuIijYawjnlUIef//rzHj5wYQ0b5uThi8T55SsnZnpYQHpD4d7WoZUeRjOnwIRZpyYYTaBRy+l7T0XJtP4aC7Ussah0fOOYKRadmgUlFnzhOEc6x7bx8nR/2t4iAuA5EAFwYUQvHeke9ZjUoOztwcGH8Wp1h1hWbh8SAE8pCjq1TDQx8sJjOJ7M7JLRq2Uipx1v0MjMKTQjIXGg3cvOYCzrOVTy2IMZk70AoSgKijL5pe2EM9vzzz9Pc3Mzt99++5DnfvjDHyLLMjfddBPRaJSrr76an//85zMwSmEiTDo1Nbr0zt9USmFvm5dnD3Syv83LO9dWjhr8Hg9/JE44nqTArJvUoMZLR7p5ZFMT4XiSO69dOOC5Y90B9BoVNXkmPn/VfPQamR1NHrr9UV49mi4pHIwl+cuO1gGv+8kLxzJfxxIp9rV5MWhUaHUydqOGC+fmc6jDx6cvn8f62jwAUimF329q5Mnd7UhSeqI8nhYdgykKzJlg2aFUSuHrf9tPSlH43s3LWV5hn/C4hHPHZO7G/c1rDcwrNHO0K8D6WievHevl8Z2t/Op9a1hQfG4m5EXiSbY1uvjz9lae2ttOto2LZp2aEpueY93DlwmuzTeh18hsnYUZ6eFYkmbXqQpO3nCcVZV24skUkXgKh0nD1ob0uCPxFH/b3U6l08iHL67FotfM1LAFQWByWnCNZjK7cYViSe775yEevG3d5J1UEARBmDUUReG/n9w/oJ0GgHWUOaNJN3KYotiqxzzKMYJwtoknUxzs8PH5P+8B0lW5PnbpHH7x8vEZHhmoVfKYNkKWOwyU2g3sanZn3TVe4TDgNGvRquRMlbVCazrhpc0Tpt0ztF3t8nI7O5pn3/11NmUOA4VmHfvbvGyfhDWBZleIDm+YEpuoEDkS8VdDGNEl8wvQqmViIwSb+wYFqCcaALca1CwsTvd92dnsGfJ8UoEKmz7nMuvLy20DzmPRqQCJ/TmUjWzsDSLBmDLUoxPYEZTN+XPyRZlJYYg3vOENw5YO1Ov1/OxnP+NnP/vZNI9KmCqyLLGiws6KKQ6K6tSqSQlkePrLkj+9r4MvXbOA3f3X4OtXlLKo1Mq2Rhe7WzxctqCQ+UUWKhwGFhSlA26eUIy9rR4Od/pHTXQ6nSTBxfPz+d7Ny4f9DLIscesFNVy7tIS7nzow4Z5JdmO6QkdVnnFIMthYybLEM5+9eELnEM5dqkkMfvT4o3zgoe0ALC2z8daVZeSZtLxW3zsgAP6Dfx/htgtqcPT3uA/FEnzk4R187qr5rKp0TNp4Zko0keTRLc387vVG2tzhUW/sq/ON7G/zUW43UOowsDVLv22TTjVpZcunw+nz52yLjT99sZ5HtzTz549uEL3HBGGGKIpC2wQr2eRiX5uP+f1ztclgN2on5TyCIAjC7HO0K0C3P4pKlkZdI67NN5Fv0XG0y591/ny6vmCMcCyZtVKRIJytllfYyTfr6A2kW2TtbPZkjZdMp0UlVnoDUXr8EWryTTT0Zm+hO6/QjN2oIRJPEk2kE6tH+j1vcYdpGTSvbepP0lbJEutqnPT4owSjCQwamao8E68c6528DzZF8s1a5hSY2dXsntR5u6LAL/9zgruuXzxp5zwbiQC4MCxFUfjus0dGDH5XOg2c6A2Sb9amF74UkGWoyjPS6Y1QYNHR7o0QiCRwmDT0BtKTlZHMLTCzZYSLoUrqv2HOMQDe4Y2wtMyaWXAMxpKUOQzUlVhG7QnR7Y+yrNyWcxkNvUYmNckF3Uw6NYqiiBKTgiBMuZNltsfr4c1NbDzWS4XTQCCa4Einn8e2trCt0YUnHGfT8T5SKfjmPw6gkiRuWFHKgXYvj+9oZXGpjSNdfo52+en2R8cU/Ib0xO9Qh3/EkmknFVn1/Pw9q3lwYwN7W70c7fITjCbo8kWJJJLU5Jkodxr5+psW4QnFeO5gF7uaPbS4Q3R40xmnl9cV8sv3rUYzmVuiBGGcxlGwZkQWvRp/JMHSchu3X1jDbRdUE4gmBhyzstLBrhY3l9cVoSgKj25p5qZV5Xzlr/v4ztuWsazcPrmDmiLxZPom/NkDnZzoCeIKxnCHYvQFYsRybGtTW2DKJFa2esK0esKsqrQPWJg4vcf2RGlUEkVWPbUFZo50+jL9wqdSgUVHTb6Rhp4ggdPm8n3BGLf/bhv//MxFGLXi1lIQptu+Ni+dvqG7YabCaDv3xsKkE8ELQRCEs9VLR7qJJ1MsLLZg1KnZ0+LBqFWx+7T+3yatiiVlNlrdoQEBMYdRQzypUGrXD0m6WlpmyyTfCsK55PK6Av60vXX0A6dJOJ5u2Yg/vXawvsZJIpkipSgkU9DQF0Qjy7R5wiNWSBuLZEoZEjz3hBOU2vVZd4bPJJUssaDIjEWvIZJIsq/VS29g5ASf8XpkcxO3nl8t2iWOQKxSCMN6rb53SMnZwUKxJOuqHexsdmfN4Dk9aycQTVBk0Y0aAB8p0Os0aQFlwKRpNB3eCJF4khKbng5vhJQCLa4wpTmWhxhLSfNIPMX+Nh8lNh0d3slZjPzX/g6+87ZlqET8WxCEWe68GicLisy8dqwXo1bN566cx/ZGF72BGJUOI/5Igv8c7eaqhUXkmbXc/8/DNPQFcRi1HOsOoJYljBoVdqMGi16NQaNiYYmVQqueTcd76fBG0Kllun1R/IOCcZctKOBbb12KzZD74uxtF9QM+L4vEEUty9iMA8+xptqZ+bq+O8CuZjdXLiwSwe+zjN/v52tf+xpPPPEE3d3drFy5kh//+MesXbt2poc2qsncAW7QyFh0akLRBMmkQiqlIMvSkMoKl9UVZr6WJImL5hXwxcf3crjTz6bjfSMGwLc1uvBH4lxeVzRp4x6r/W1eHtncxL/2d+INT6wVgi1LUOhAu5eVFTZkSSYUT0xa8FuW4G2rK9hY38vmE30jJqpOppNZ/ZIEa6odA0q2NfaFuPfpQ9ywvJSkonD+nPxpGZMgCPDsgYlVsxkLeZL+1kgS3Hp+9aScSxBmm29/+9vceeedfOYzn+FHP/oRAJFIhM9//vM89thjA1qUFRXN3DxIEKbS03s78ITieEJxLLr0/X2V0whIIKU3XO1p8WQ2P5XZ9bR5IiwuteIOxXB7IpkKa1a9Gl8kfe9/tMtPQ2+QGhHoEc4x37xhCf/a1zlkHWy6rK12sKfVm4mRNPSe2pTojySGbGQstOhwmDQc6Zyc4PdwvOE4eSYtKildMXi65Zm0VOebiCdTGNQqtja60KolUik42DH+3t5jkUgpfPHxvfzhg+vFGuUwRABcGFYuN9O9gdiQHt0jMWhHz/SOxocPkDuMGo73BCm16ymy6tGo5FFL5ADMK7IMOS4US2DUqgiNEpCXGduN/rpqx6T1djx/Th5ff/OiSe8rLgiCMBkUReFoVwCdWsaglen2R/nH3naMGhUGrYpdzR5Uskyl08icAhMLii0sLbPxwqFu+oIx6nsCLC6zcfG8fBr7QjT0BGnoC9Ljj+EJxdBrVDzx8QvSbSCumj/gfVvdYQ51+KjvCVDfFaA634RpgrsP88y6UY+ZW2hmbqEo9Xs2+uAHP8j+/ft5+OGHKS0t5ZFHHuHKK6/k4MGDlJWVzfTwRqRWyWyozcMVjHGka2I3WvOKLOxt9bKk1Mr/bW/h+hWlXDB39IDmgmILf/rIedzwwEY2nehjUamV2gIzZfahCYdrqhyER5jvTRVFUXj5SA8/ffHYpJaNy7b7MppQ2NWSWwWhXKlkibvevIgfPHcUd2hiQfvxUhTY3ujmknkF9ASiHOxI73x/dEszNXkmnjnQSf6NOuYXnZv94gVhuv37QNe0vE+V04AnnPt9/0g08tj6RQrCmWLbtm388pe/ZNmyZQMe/9znPsfTTz/Nn//8Z2w2G5/85Ce58cYb2bhx4wyNVBCmzs5mN/vaTs2B/dEkSNKw66R2o4YSmwGzTjOgZ3ggkmBRiYVOX5RKp4EbV5VzyfwCEfwWzkl6jYqL5udPuI3feLW6w1Q4DBzvyV7q/HQOowaTTj3lwe+TTvQGWVxqxaRV0RuIcWKYcuyTZW21A284jkqWaHGF2dGUvrbVFVtQSK8DTLetDS4eer2RD15UO+3vfSYQAXBhWO9aV8mftrXmXP4RSAemLXo0/WV0BwedG/tCrK9xDlviXKOSsBk1Q8pErq5yIEtwrDvAebVO9rZ4aPdEWFJmpdimp9ObvdRFsVVPqV2Pur9/rjsYpcUdJqWk+5itrnJkLlTDkSWFuiIzeq2ava2eEcvrVjqNY9qdPhyHUcO3b1rG1YuLJ3wuQRCEyVbf7edf+zr53euNrKx08MalxbiCMTq9Ed64tASDRkWeWUuZ3YhGJRFNpNIB7+4A+9t8VDiNtHsjWA0antrTzqNbmpElWFPlZGvjqb8P0USS3mCUQot+wPtLkkSF00iF08gbpvvDC2elcDjM448/zt/+9jcuvjjdi/2uu+7iqaee4he/+AX33nvvDI9wZDaDhj9++DwOd/r40l/2sifH1i2DldsNdPkiFFp09PijmXPnSqdW8b2bl/POX23m5SM9GDQqHnj3Sq5YOHCHkyRJ014uu8cf5XP/t5vX6sfeI2xeoXnE0m2VTmOmPcJUSqYUvvPsEeYVmnHPYN+3xaVW/nOsB4D1NU52NLlIpOBb/zyEJMEnH93Js5+9WLTvEYQp1tAbnLSykiPRq2W6/FEi8cmpOPH2teXUFVsn5VyCMFsEAgHe85738Otf/3rAvNHr9fKb3/yGRx99lMsvvxyABx98kIULF7J582bOO++8mRqyIEwJbyg+pJWkPzL8rlVvOI47FBsSWOv0Rensb/OzqrKQz145P9vLBeGccd3S0hkLgJ+81zVrVSwqs424GTEUSzKvSEeHJ0xkmqqVnZ48U+4wUGzVI0twqMOXTsIZI40ssaDYgkqW0GtUeMNxUopCly86bGW3w51+zFrVgHZh0+nBjY3cen41arELfAgRABeGtbjUxpeureOefxwc9ViLTkWRzUB9d2BA34Uyu4E2T3jAsUdH2Jm0tMzGxvo+FpVYsRnUVDqNeMOJAUHqzSdOXWT3t/nQq2XWVTs53hOgL3gqK73CacAXjg/Z4TOv0IxRq0IlS+xocrOk1IpRpyaWSNHqDg3Y0W7WqlCQONzfd6bSaSSWSGYmYYOV2PQ0u3LrTT7YumonP3vPKnY0uVlT7SA/h52IgiAIJ+1qdpNIKaw9rVz3ZEqmFH7ywjFq8o0YtWreuKyEt60pp8iiT+/QHqSpL8irx3oIRBKE40k84TjtnjBt7jC3XVCDSauivjuAP5KgrtjCGxYXc/Pqco50+tnW5OJQh587rpo/JPgtCFMhkUiQTCbR6wf+ezMYDLz22mtDjo9Go0Sjp+YCPp9vyDEzoa7YyhMfv4BfvXqC7//7CPEx1AFbW+1gf5uPcDzJvEIz0URyQPsVfyQ+pAx6NkvKbLz8hUv50fNHeXRLMx94aDvP33HJjFVOCEQT/G5jAz976fi4d53r1DJVeUaa+rLP8U6WaByPfLOOi+fnU+4wsqDIQiiWQKuWSSkKalnmaJefxr4QNXlG/rithSsXFvLcwe5xv99kOP3zbmlwUVtgIhhJ0OWPoihwtCvARx7ewQPvXoVWLW7ABWGqPLN/ehZBawtMk1rGcbb1aRSEyfCJT3yC6667jiuvvHJAAHzHjh3E43GuvPLKzGN1dXVUVlayadOmrAHw2TrPFIRcxJIp9rV50aikIfciFp2auhILu1s8xJMKGpXEvEIL6lF6Pj5/qJu3/88mHrp9XU6VRQXhbGQ1qNGq5WlrgZVNIqUQH+X9o4kUWxtcrKtx5lS1d7K1usO09rfkrSu2cLgz9zms06RlbqGJNk+E/e1j/9s7t8gyKRsjx6PNE+b+Zw7z1esWzcj7z2YiAC6M6Lbzq+n0RdjT7GZHk3vYfgrBWBKnSTtkh4zdqBkQANeoJOYWmjneE8AVHFi60WnSZjL+Dnb4KLLqSKYYNaAcSaTY2uiiyKLDYdTgDsVZXGrFG47jDQ/NMhycJX/yglaTb8Jp0mYC4OUOA2admu2nBd+bXaH+x1UExpFBNBy9RuaH71xBgUXHNUvErm9BEMZuZaVjSs9/pNPPhjl5nFebN+qxB9q9PLqlmRZ3iGVlNg53+nn9eB+JlEIskb4hdpq0dPuj/OkjG1hXcypoX+E0cuUi0Q9PmF4Wi4UNGzZwzz33sHDhQoqKivjjH//Ipk2bmDt37pDj77vvPu6+++4ZGOnoZFnio5fM4Z1rK3hqTzv3PH0op5vkSDxJXbGFfW3ezFxpXY2Tz/3fbnzhOD2BKG9eXsqP37ky6+u7fBH0ahU2o4Z8s45737KUva1e9rZ6ufXBrfz1Y+dTaJ3ehJZ2T5gPPLSdQx3jXzheUWFjX6uXlZUOmvpCLC+3oVHJNPYFMWrVFFl1A/phj8W6aic/eddKim25/VxO7nwpsdXz4MaGGSuD3usfWAb5RE8Qp0lLud1Aa/+8/98Hu/j5y/Vit44gTKFn9ndMy/vkkvw0Fs2uEIqiiCoRwlnjscceY+fOnWzbtm3Ic52dnWi1Wux2+4DHi4qK6OzMnsQym+eZgjCaX/3nOCZtes20rtiCWacmpSgEogksejXbGt0sK7chS5BKwd623CpXbW10sbvFw4Y5o69HCMLZ6M/bW2ck+O00aZlbYMYditHQG2RXDgHelRV2djROf/B7sMOdfmrzTUhSurJdfU8AX5ZY0dpqR3+sKsbWhvG3/Gn3hGd0F/ivX22g1G7gtgtqZuT9ZysRABdGJMsSy8tt/PqVE+SbtVTnpXutpBSFaCKFXqOi3ROiwxvNZPWcnuETiCYodxiwGdTo1Wr2tXvZ1ujuL0fuYU21g2giRSyRor47MKAXWJcvStcwO62z6fJHWVFhI5EMDih9Mexnk9K7wWPJdPZSw2k9IvLNWjq8EZJZ6p23usPMKTARdYUy2YxFVh3VeSZ2t4xvAfTbNy3L2iNTEARhtlhUmnupykAkwaJSK1cvLubFw93Udwcotukzuye7/VG6/VHuvLZuQPBbEGbSww8/zO23305ZWRkqlYpVq1bxrne9ix07dgw59s477+SOO+7IfO/z+aioqJjO4Y7KbtTyvg3V9ARi/OSFY6Mev68tPXeqK7ZwtMtPSjnVymZ9jZMuf5S/7W7nyoVFvHl5KU19QXY0uanKM7GwxMLn/7SHEz0BFpfZuHBuPjesKCXSv+O61R3mv/6yl9/dujZrxYip4A7GuOW3WydUHvj0Oe3hDh+Xzs/n5aOnl1CPjavyz5wCE95wnJ++eyVFY0gK8ITjOE1aPn3FPD51+VzquwP84j/HeXJX24gteiZbtv+ErmAMyaSlxKbPlMjbNgsWPQThbNXuCY+73cVY+SOTm2yzrNwmgt/CWaOlpYXPfOYzPPfcc0MqCY3XmTDPFIRsdrd42HFaFc7Td15qVRKxpEKhRYcvHKdxmMpKw7Hq1aypntqkf0GYrSLxJFsa+ib9vEVWHSU2Az3+KCU2/YBNgABzC0x0+aMDWhXmoskVmtb702wkCRaVWDFoVOxv92Y2XaplCYdJi02vRqdR4Y8khi1rPlbd/ihzCkws7N9g2TDF/cizWVZun/b3nO1EAFwYVW1+umRlbyA2oDz4STq1zPJyW+YG/PSg8clgR+ug68j+Vg/ra50DyplPhkRKyXlhNaXAka7si6I1+SZ6R7j4He8JUmbX0+aJsKbKwfYm95iC9ZDuax6MprOOrqgrHNNrBUEQZptufwSNLBOKJznS5eeVo73YDBoOd/pYUGxhb6sXtSyhUUl8/+YVLCi2zFhJZEHIZs6cOfznP/8hGAzi8/koKSnhHe94B7W1tUOO1el06HRnRquSa5cU88TOVlrc4dEPJr1QtbTMxr7TdmMkUqcyze/4v93895P70KtVFFp17GvzpXdw9E//2r0RnjvYxTf+fmDAeV852sNDmxqnJRs5kUzx6cd2jRj8zjdrKbUb0KgkDrT7hvS2XVvtGFCyLRBLEopNTsa9Atz7lqWZeWCunCZt5mtJkphXZOEHb1/Bxy6Zww+eO8q/prgc8roaJ32B6JAejSf1BWMsKbNmAuAb6/t4vb6X8+fmT+m4BOFcNF3lzzWyRP0wv/PjZdCI8rXC2WPHjh10d3ezatWqzGPJZJJXXnmFBx54gGeffZZYLIbH4xmwC7yrq4vi4uzV/86keaYgnO5Xrxwf8H2Z3UCZ3UAKhe2Nbi6el88rx3qHefXIfvD2FWhEb1vhHBOJJ3nxcDc/fbF+zHGHwXRqGbsxXdVHUaDCYeRotz9Tsru2wEShRUe3P4rDqGF+kYVdLZ5x7TrPN2txBce/k3oySKTb8A5uxZBIKfT4o/T4J/bzHM7xniDHe4LUFVum5Pyj+emLx/jdbetm5L1nKxEAF0Zl0qX7ZWfbDQ3p3g6n79wepXULAHUl1kkPfqffW8IbjrOs3MbecWbEa1QSbTksEof7y1nsa/OM6338kTj13QH+9JENk15WThAEYbpZtGp2tnh4cGMDvkiCmjwTbZ4w3nCclAKxRIpo/8T5yd1t3H/TshkesSBkZzKZMJlMuN1unn32Wb7zne/M9JDGJZVSePloN/f84xDecJwKZzqzO5pIYdKqWVxqZcswPbl6AgNvBpMpMOtUFFh0NPSG8IYTeEn3fAZyzu6+75+HmV9k4YIpCIh6Q3Ge3tdBMpXi5SM9vDrK4lpNvimT6W3UyKyrduKNxHEHY5Q5DEOywCschgntaLYbNdy0qpwKhwGtWsU1S4qHnVuP1bwiC79472o2n+jjnb/aPCnnHGx9jXPYfy+n29/mY2WFnTZPmG5/lPv+dZi7rl/M6iqxY0cQJtMzB6YnAB5PKRgmOeAw1W17BGE6XXHFFezbt2/AY7fddht1dXV86UtfoqKiAo1GwwsvvMBNN90EwJEjR2hubmbDhg0zMeRp8fiOVt68vBStWgQszxX13f4hyZgGrczWRhdWgxqbQc0rx3oz1YLWVDno8UdpGqaaklqWkCWJpKJQm2/iMrFxSDjHROJJLrz/xaybEXOl18gsK7PT7Y/Q1BcaEETvHhQAbuoL0e2PYtGrcYfiOd37Df++Kpb3x2ZmYiN4hcNAoVXPnnFW6p0Mhzv9VOcZcYViWcuuT5WZ2HU+24kAuDCqqjwT/33dQu5+6mDW51WyRLcvyroaZ7pXQg5lI8Lx7L0Q5hWaaXaFMkGSscgzafH376TRq8efVR5PKuRbdLT3714ZliRRatPT6RvluCwKLTqOdQe4ZUM1a6pF+V9BEM5s/9zXQSyRYktDH72BGIc6fHhCMTq9EdbX5rG7xUNKOTXtfe5gF2uqWvjIJXNmcNSCMNCzzz6LoigsWLCA+vp6vvCFL1BXV8dtt90200Mbk75AlD/vaOXRLc0DynP7IqduugLRBFsbXSwuTZcEi8ST7O9vH1PlNNDkGpgIeKA93QN76wRuggFiyRQf+v12fvLOlVy5qGhC5wJQFIVdLR4e29rM3/e0E4mnMpV5Rh3LaXPNUDw1oKzb4MUAgCKrPudd9KebX2TmjqsWUGzTs6LCPuA51SSXgz+vNo8Kp4EWV5iafNOYbn41Kolim552T7oFkFmnZkGRmUMdPiKJ1JgWQHa1eDBpVaytdrCt0c37f7OF7799OZcuKEQvdn4KwoS5gzG2T2OLgSKrjnhSIaUoaFUSWrWMQaMmlkwNKG+bq+o8IwBdvghqWSLPnNtOV0VReGpvB7X5JpaU2cb8voIwFSwWC0uWLBnwmMlkIi8vL/P4Bz7wAe644w6cTidWq5VPfepTbNiwgfPOO28mhjwtLp5fIILf55h/7O3gtFt+NCoJVyDdQuP04E+Z3UCRJV1qucJpYHGpFU84TqFZR6cvwtOfugidRkatklBJ6SD4dLVQEoTZxB9JjKmMuEWvZn6hhYSi0OEJ0xeMsazcntM9fJldjycUy7zvRJ3clHh6e7Xpsq7awa5mz7ju3SdbY1+INdUODrf7CMeTLK+wc6I3iCc0ue2FThefgT7xs50IgAs5Od6TvYRkvllLkVXPgXYfeWYt9Tn2WTTr0//0nCYt5Q4DWpVMLJHiRG+A5RV2tjW6BkycctEXjNEXjLGu2sGx7rHfiJ9ub6uXBcUWjoxwQx+JJ3EaNaNexC16NdV5JhKpFBpZZm+bl+p8E93+KDetKp/QOAVBEGZKjz/Kw5saOd4TpL7bjzsUo9t/KjP1aH+LiecOdg143RsWFfGRS+awclAgSBBmmtfr5c4776S1tRWn08lNN93Et771LTSaM6dKy/42Lzf94vWcEgkVBQ70B70BSu16yuwGVJI0JAAeTyoTDn6fFIol+cgjO/jpu1Zy7ZLiMfeBVRSFSDzFD547wtN7O4YkLHb6IjhNo5dcC8ayJ2MOJ5Yc+41kiU3PXz9+AWbd9N1yffvGZXz/30f48rUL+dUrJ3j+UNeor1lX7eRgu5cWVxibQU2hRY/TpJ1Q1n8wlmRbozvTR/2Tj+7ihhVlvHNdBWtF8qcgTMhLR7qndSFxuD6ta6sd1BVbsOjVKArIksTpl/RkSiGeUognkvQGYpnkorueOkCvP0ZvIEpNvon3b6gi36xjTbWTSDyJQasif1BQXFEUHt7cxNf/doAlZVYe+/CGab22CsJE/PCHP0SWZW666Sai0ShXX301P//5z2d6WFOm3ROm1G6Y6WEI08gfifOPvR0DHqstMHMiy1ryyURVjUqi1GZAlqCpN5ipxPnB32/jh+9YQVWeaeoHLgizmFGr4rtvW8ZDm5p45WjPiMcWWnSE40l2NA9MBM/lHl6nlkgpAxPmJ8uRLj9WvRrvNO2A1qplmvpCxGe6Aflptje6My3jdjZ7qCu2kFIULDoNbZ7JD9K7QjNben42mhV3DK+88grf/e532bFjBx0dHTzxxBO85S1vyTyvKArf+MY3+PWvf43H4+GCCy7gF7/4BfPmzZu5QZ8jWlwhnt7XwStHs5eRrC0wZy6mVkPuC8T+cIJCiw4JhpQq39rgGvOuldP5Ignck5BJc7TTz6pKOzubPVmfL7DoODHKGOuKLfijiQF9NJeV2TjRE8CgUbGo1DrhcQqCIEyneDJFY2+QHU1uOn0Rtja6cuqdo1XJfOP6Rbx7XeWYA16CMB3e/va38/a3v32mhzEhGpU8rio6AO2eCO2eCBa9mnXVTto84Sm5IYN0UOTjf9hJmd2AWiVh0qoptRuIJ1O8a10FpXYDsUSK+u4AvkicvkCMVk+YDk+YE71BQrHksL3IWt1hLDoV62qcNPYGs+7mliRwGMeW2HC4049JqxpT4HxttTNrgOaFQ10UWvQsLZ/8HYwXzM3PlJgvtev5z9HuIX3PhpDSPc6BdHn7cG4JrbnY2uBiZaWdXc0eHt/ZytP72nnyExdQVyzmwIIwXoHo9JVRHKzIoqPEbkBBYW+rN+e/OeX9fWDbPGEMGhW+SJxESuFYd4Cv/e3AkOPnFZoptRu4vK6QHU1ujnUHONSRTtra3+bjqh/8h09dPg+HUYNBq2J+kYUSm17MMYVZ4eWXXx7wvV6v52c/+xk/+9nPZmZA06jdE+bC+1/krusX8/4N1TM9HGEaBKIJrv3xq7T2B7DXVTtwh+P0+KIjzkGLbXoOtnvxRwfOrXc2e3jb/2zim9cv5tqlJVM6dmFi7rrrLu6+++4Bjy1YsIDDhw/jcrn4xje+wb///W+am5spKCjgLW95C/fccw822/D3QLfeeisPPfTQgMeuvvpqnnnmmSn5DLOZSafmioVFXLGwiGNdfu5/5kjW5OZ8sxajVpX1vjen99GqKbTq6BitEu4YaVQSdcUW9rX5Rj94ksQSKUrshkyrttni9Hh8fXeApKJQkGMFpDG/Vyq93jLZ1ebOZLMiAB4MBlm+fDm33347N95445Dnv/Od7/CTn/yEhx56iJqaGr72ta9x9dVXc/DgQfR6/QyM+Nzxv6+e4KFNTcM+Hz9tN0z7GEpLnOgNolVJxIaZDFn1aiw6daak+Vgc7vRz4bx8ovHkkP6NY6EA6hEampu06qyZ9xKwptqBosDBDh+hQQule/uD4asq7eJiJAjCGaXHH2V7o4v/fa2BSDzJse7AsEGo011eV8jnrpw/JcEeQRDSntnfwWce2z3h8/gjiUw5cKtBTaFFRzyh4DRrqe8KjGtuNpzTA+wH+wMb/xmU3X6ypPdY+KNJtja4cJq0FFh09PijzC8yE44n0alVeEKxMc8RY4kUSysdQ7LqRxKKZf9ZXbGwiMQ4dpSPVbnDyMcuncuDrzXgjyaozjNi0KozQaSTYomx7YbPhUWnpjLPyImeAKdPdyPxFF/56z6uXVLChy6unfT3FYRzwfvOq6LIqueuvx+Y9MXK0VTmGcd1j93af71fXGollkyxtMw2YpWJY90BjnUH+M/RHiSgJt9EoUWXWdzt8Eb4yhMD+y5/4MIavvamRWMemyAIk0eS4MZV5ayrEdVeznbRRJKfvlDPQ683Zu4P1lSl29/ksvcyz6TFNUxv4x5/lMgUzE+Fybd48WKef/75zPdqdTrU1N7eTnt7O9/73vdYtGgRTU1NfPSjH6W9vZ2//OUvI57zmmuu4cEHH8x8r9NNTaDwTDKvyMLP37OKHz1/lIc3NxGMJlhT7SSVUjjRExi2Ws9o1lQ72N7oxhXyjn7wGMWTCrIkMbfQjF4js38aAuEqWUI9y2Mtif5gUqs7jEYljZ6sPgbzCs3ccdV8EW8aZFYEwK+99lquvfbarM8pisKPfvQj/vu//5sbbrgBgN///vcUFRXx5JNP8s53vnM6h3rOuXxhEY9saSY5TOmII51+8kxaqvKMNI3xYjtc8BvSJSsCwywajmZttYONx3rJM2vH9fpcHezwUVdsodsXHVBeYk1/v8PRiN3fgiCcSQ51eEkp8PDmJqKJgcHvfLOO3kD2DEtJgruvX0yF0zidwxWEc063Pzru3d/D8YUTmZ59Ta4QS8tsA6raTIfABEqxuYIx1tc46fFH8YTi486KP2msGwsPtvvwhuLYsuw2V6umpy/mHVfN53NXzuOOP+3BH8n+M2joHd+CyXDW1Tg40RPMlNjf0eRhaZmNhp4AgViSnc0eblot2gAJwnhJksTVi4tZUWHnFy8f59GtzTklJE7U0jIbu1s8EzrHyevCumpHzq9RSM81R6u+9pvXGvjKGxeKRT9BmEElNgPfu3n5TA9DmAY6tQqHUUO+RYfNqCHPpEWrlim26UdMzlLLEqurHOxsdo8Y+Ln3H4e4fEFR1nm0MHuo1WqKi4uHPL5kyRIef/zxzPdz5szhW9/6Fu9973tJJBKZQHk2Op0u6znPdVq1zBevqeOzV87n95saue9fh4eN18wWe/qr/kpSOl4jkU6IPtThm5Iy5asrHZlk/tkumkixsMTCoY7xt/EtsxtYV+NkQbGF1VUO1lQ5RDWkLGZFAHwkDQ0NdHZ2cuWVV2Yes9lsrF+/nk2bNg0bAI9Go0SjpxZ4fL7pK7dwNsk3a3GatPT4o6hlieUVNnY0eTLPK6R/2YYrEz4eFc70+cbaA/ykbl8EBUhMMINmZaWdrQ0jB7IPd/pZUmYFSSEcS7K03D5qf40iq44PXFjDW1eKhT9BEGa/3kA6cNTsClFmN1Js1dPmCXPjyjI6fRHUssz2plPXPaNWhUmnxqJXs7TMxqULCnCYpjYhSRAEeM/6KjbW9/LsgdF7Po+XQTs9QdvTuUNxLHo1/nEGwt2hGItLrQP6nY9Xt39sOy2TioJRp5rw+06UJEncd+NSjnb5uf6BjUOeD8USSJDTbp3RrBpm/ryvzUttgYlof0+2x3e0cvG8ApEcJQgTUGTVc9f1i7EZNPz4hWNT+l4lNh31PYFJ26Uy1j6TDX25tUfbWN/LxfMLxjMkQRAEYYwOd/pp6A2iV8uZEujldgMVDgMtWaqE1haYUBRGrAByUl8wxq9fPcGHLqoVQfBZ7NixY5SWlqLX69mwYQP33XcflZWVWY/1er1YrdYRg9+QbiNRWFiIw+Hg8ssv59577yUvL2/Y48+1GJBWLXNebd6kBL/bp6jl2WCKwoDNgvlmLVV5Jg62ewnHJyeJM9+s5VDH9CbrT9SRTj+rqxzsaBpbdaVVlXbuuGoB58/JQxaJn6Oa9QHwzs5OAIqKigY8XlRUlHkum/vuu29IHwph7J7a05Hp7ZpIKexp8VJXbOFwZzo7JRxLZkp6T5YWVxinUUOeRYdGljjRGyQyhouhpn9HjTcSZ2GJBZUsjavMxq5mD+uqnexqGTkrcX+bL/MzGS34DenybR++eM6YxyMIgjDdIvEk/9zbgUol0dAT5PedTWys7wOgxRXK2gbi4Q+sY3WVKHknCNNNJUv8+J0ruf6B1zjaNXk9nE83UxnmBo1q3AFwq15DarxZlYM0u9L9xQf3KsxmebmNe96yBI1KJhRLYNTO7G2XXqNiSamNL16zgFZ3mEe3NGeeW1JqY9cEd3UCFFh0HOse/t/eiZ4gS8usHO70s7PZw1U//A9vXVnG3EILLa4Q1XlGbr2gZsLjEIRzze0X1vDQpkY8ofiUnF8lgUmnocM7Of0UnSYtVr0m06IiF1r1wAQsm0GDNzz0897y4FYe/eB5bJgz/EK5IAjnlj9tb+GKukLypqjf6rnqaJefJ3e3ARA5rQpJuzfMRfPyswbAZQnqe3JLaAJ44KV6XKEYJq2Kz1w5H7Nu1ocxzinr16/nd7/7HQsWLKCjo4O7776biy66iP3792OxWAYc29vbyz333MOHP/zhEc95zTXXcOONN1JTU8Px48f5yle+wrXXXsumTZtQqbInFp9rMaBUSmHT8b5JOVe7J0KpXU+7Z3pb6vQGYvT2t0CoK07Hbnr9UaryTCDBriY3TpN2TL28LXp15pxnipRC1vnsSN62upxv37h02irKnQ3O2p/UnXfeidfrzfyvpaVlpod0RjneE+Cxrc38dmPDgMcTKYU2T5hyu2FK398VinOsK8DBDj+Fltz7vJ8+mVIUONThZ3+bD22WXt4OowbzKLtytja6mFNgHtvgR1FkFX3rBUE4M+g1KpaU2/CHE/zvaw0c7vBTaktfw4aLgz2zf/jkNEEQppZeo+KLV9dN2fmDOQR+p0JoAn3H033AJu+WpzaHeeH5c/J48LZ1yJLEN586SP0IQeHpJMsSH790Lt948yIe/eB6rlyYTjBWZ5knj1WxTU8ymRo1UWFfm4+VlenSx5F4ij9ubeHHzx9lbqGZSxYUTngcgnAushk0fPji2ik7/+pq56RexwwamVZPKOfgN0BZ//yz0mlkVaUdozb7fbyiDA2WC4JwbtOopEmpBCQMtLG+d8hmoVKbnvNr8+jyZb+++8IJNtTmsa7aSblj6LqyWpYotAxMVHh0SzO/frWBg+K/4axz7bXXcvPNN7Ns2TKuvvpq/vnPf+LxePjTn/404Difz8d1113HokWLuOuuu0Y85zvf+U6uv/56li5dylve8hb+8Y9/sG3bNl5++eVhX3OuxYD+c7SHb/3z0KScqzrPiDs4NQmUuTrc6edAu48uf5StjS62NrjQa1R0+aOsqrRTZh89jiJJYDeemZUn67sDrKt2srLCxtIyKxVOAzaDesi1EOAjF9fynZuWieD3GM361KmTPR+6urooKSnJPN7V1cWKFSuGfZ1Op0OnE9l946EoCjc8sJHAMIuN/kgCiy79izjRXoqjqXIaB/TXHo1Zpx5STm1OgYnjWTIMyxwGTvQEWV/j5ERPkJ5h+tce7vRj0qoIxrIv+q6ssHOoI/eJ2JHO8fd2EARBmGrdvgiP72zjo5fUkkwp/PqVEzT1hdBrZPqCo1+P372+ahpGKQjCcC6an49WJRNLTn4/2JH6+Y2XRafGP0qAW6dRERhmHjYStSzhCcU4Mok74vWa0Uuav368jzX3Pse8QgsP3raW0ilOHB0rnVrF+XPzOdEb5PlDXUTiE09scBq1HMxxPtzqCqFVScT6F021ahXvPU/87RCEifjoxXM40RPkLztaJ/3cE+37PVibJ4LVoEavkXOu9BZNpJhfZMYTimfary0psw6p9KZVySwvt03qeAVBOLOJ9oNTQzWo7K5KllhX46TNE85UDR0sEE2wu8VNOJ6i1K6n2KqjwKJHLUto1DJ9gSi9geiQ9kfXLy9lbbVjSj+PMHF2u5358+dTX1+feczv93PNNddgsVh44okn0GjGVs6+traW/Px86uvrueKKK7Iec67FgC6clz9srGOsGvtCrKlysH2MJbin2sn1gZ3NHuT+/uE7m9zMKTRj1Wuo7wmgKOkWjHqNiiKrjuAEkuZnWva+5QmWldvo9Ibp9sf4wtUL+MRlc6d9bGeDWZ8uUFNTQ3FxMS+88ELmMZ/Px5YtW9iwYcMMjuzs9e+DXUMmMoO1eyPDZl1PpiZXiNp8U87HLyyxDnnseE9wyERJI0vIkkQolmRLgwt3KMbqKseQDESNKp19uLjs1Hn1GhmHUcPiUiuLSqzsavEMKPczmsWl4oZcEITZq9Cq52OXpts0fOPvB1hWbqPIqiOaw3Uuz6SlZgzXbEEQJp9OraIgS7bwZJiKROMKp4GFJRZWVtqBdPa2etA8tGycAeTVVY5JDX5Dbn2y5xaa+dTl8/jTRzfMuuD3SeFYEncwhl4j0ztMEuhgI90eHO70sbjUMvwBp2n3RrAaNKyvcSIBF8/Lz+l1giAMT5YlvvLGhUiT3AbQbtQQG8O9bq6i8eSYKr3tafVytCswIAFfZuiHjSVTNPaFJmWMgiCcG0KxBO5gjPgUJI+erbzhOL97vXHAY5+4dA7XLSuhxZUufV7hMLC0fy21zG5gXY2TxaVW6oqtWHQq2j0ROn1R9rV52dXiYWuDi+M9QbzhBItKrCwutbK83MaG2jw+fHEt0mT/gRMmXSAQ4Pjx45kNjD6fjze84Q1otVr+/ve/o9ePvSJqa2srfX19AzZFnus0Kpmfv2c1n79q/qRUvXHlsNFlJqX6+4engKNdAbY3uQnHkug1Mh3eCA29QTafcLGvzYdOLVPpNLKuxkGeSYtahjK7niVlVtZWOyixnVmJEntbvdTmm7Ho1WhU0oy1pDvTzYod4IFAYEB2UENDA7t378bpdFJZWclnP/tZ7r33XubNm0dNTQ1f+9rXKC0t5S1vecvMDfosdbwnwJcf35tT/wHNNJRbkCWG7OgeSWKYC8G2RjeVTiP5Zi0SEt5InL2t3gGv29HkRt2fsSgpCknSPW26/VG6/VHUMiRS6XKNVr2Go13+EXuDD+YwarisrpDbL6zO+TWCIAgz5V/7O8kzaWn3hDnaFaDSaaTVHR5xwnXBXBHEEITZIM+spc0ztO/eRFn0GlyTXCLNFYzR2V8mUSNLyHK6P6xeo6ahN53V3heKoZIg12lXhdOATiWzpSFbJvXEpEa4BqpliVe+eNmsDXqfzqBVUWTVE4mnKLEZsBm0NPWFCA/aDb683Mae/jnzdctK+cfedrK1VE8pYyuRn+775uJtq8u554YlE/osgiCkOU1afvqulXzzqYOTVqktPgXBb4BoQqHYqqfTFxl3gH1vmzdrL/DnDnYxt3By25gJgnBmOdSRDoTU5JtGDJz2BqKc/+0XiSVSqGWJD19cyxevmbp2QmcLXzjOiUG7TzfMyeNwh4+afCOVeUbcwRgH2n2sqLCxv82buTfJ1qJysC0NLrRqmZ+8cwVXLy4Wwe9Z6r/+679485vfTFVVFe3t7XzjG99ApVLxrne9KxP8DoVCPPLII/h8Pny+dNWWgoKCTD/vuro67rvvPt761rcSCAS4++67uemmmyguLub48eN88YtfZO7cuVx99dUz+VFnnQXFFiqcBn76Yv3oB49gXqGZY7OkXddoTr8HLXcYkGVpSLuFaCJFsytEsyuESpZIKenKQ239Pc6NWhXLy20c7PCNKaYzEyQJVlU62Ny/pvH//nmY7zxzhLoSC9cuKWF1lYPzavNmeJRnhlkRAN++fTuXXXZZ5vs77rgDgFtuuYXf/e53fPGLXyQYDPLhD38Yj8fDhRdeyDPPPDOuzCFhZL/b2Ig7lNvCZmNfkJWVdlIpJbMwNtmWV9jZ1V/iLBfuUAyDRiacpZTayQvgSBIpha0NLpaUWtk/qL/M6ffl3f4oa6sdHOsO4Mnh57WmysED715FsU38mxUEYfba3+ZFo0pXuTjS4cNq0NDhjVBg0XGg3YtRq6Ku+NQOP4X07htJSi+6/vAdK2Zs7IIgnJKYgpu5RSXWnEtc56rUrqfdc6qsejylQAo6vFE0qhjra5x4wnGOdPpZV+Nka44B7RZXmHXVDpiEsnCDDZchX2rT8/9uXHpGBL9PunlNOb969QQalUyJTYPVoBnwM9b2LxyfnOdvb3Tx1Tcu5N6ns/ecC8aSzC00Ud+d+8/9AxfWYJiGqlKCcK5407JS1tfkcdvvtg4pDz4e1flGDrRPTQuvrY0uavNNNLlC49rRsrLCzr62oesQf9vdxgcvqpmWhH1BEGZeuyeMQaPCYTrV/3VBkYU/bW/h3qcPMbfQzHvWV1KVN7RSWb5Zx7fesoSN9b20eyMEowkURREB11GUOwwcvfdadjW7CcYSPLypiW8/c4Q9g1pmFFh0KMrA9dRYjvcp84vMXLNE7PqdzVpbW3nXu95FX18fBQUFXHjhhWzevJmCggJefvlltmzZAsDcuQPLNjc0NFBdXQ3AkSNH8HrTf8tVKhV79+7loYcewuPxUFpayhve8Abuueeec6rEea76AulqXhNpfTZaBeDZqMppzKn8e7a5ZSiWZE+rl7XVDo50+fGFZ0/Z9EqnkTyTFo1KptMXodiqH1IaPZFS2N/mY3+bD5NWxW0X1HBZXSGrq0SLiJHMigD4pZdeipJtK0E/SZL45je/yTe/+c1pHNW5qXAMJTPjSYVdzR7mFpqpK7YM2+NlIo50+Dh/Th7JlEIwlsCi09DhDWM3aEkoqSE39Sd6gqyrdrC1cWK9K+QcJrvbGt1UOA14Q/FRy2FaDRoR/BYEYVZRFIWXjvTgj8SRgKq89AJkQ0+Qv+5K94+0GzUkUwoGjYpl5XYOdvjYluX6euOqMu65YckZOXkWhLNNKJbgeM/kZ3HrNacCCVq1PCklcSscxgEB8NPFk0pmB3eeScuRzrEFcnY2eyi3G2id5J3wgSy9xeqKLTz5iQty6g8+VTyhGIFognKHMefXSJJEbyBKOJak0xfh5tXlbG1wsbrKwY4mN7ddUE2rK0xtvolWd5huf3TEXsA9/iixRGpI38aRhONJmvtCVOblPm5BEEZWYNHx/966lE/9cRdNEywHrldP7XXtRG+QKqcBbySRU2L5SWV2Pb2BaNYKcIc7/XR6I1Q4xXVFEM52R7v8fOChbYSiSZ797MXsafVg0qlZV+3knesqeee6Sva0eHjhUDfecJyrFxezqHRg68Sb11Rw85qKGfoEZyZJktCqJdbX5pFKKfzwuWMDEpLMOjWKolCTZ2Jnswu1nH7NWHZcZktYEGaXxx57bNjnRov1nHT6MQaDgWeffXZSxnYuqHAa+cCFtfzw+aPjPsfhTj+LSy1E4qlJ6Sk+1eYXmTk6CS3OTq5rjiXJfjJJUjqQn2/WEY4n0cgy9T3+ARs3R9vEGYwleeClen71ygk23Xk5eWaRJDKcWREAF2aPf+7vzPr48nIbre4wfVl2vdR3B1hQlC69UWoz4I8kxr1DaH2Nk6a+EEadimg8SbHVwOvH+wBYWWln04m+/iND6NUyKlnCoFERjidJphR0ahmtWkajGtvEajCdJrds8RZXOKfg/3m1znGPRRAEYSpIksQl8/KRJIm+YJSn93bQ7Aqzp9WTWSxt6hv5HFq1zF1vXsy71lWILHlBmAUSyRT3/OMg0SkoWZtIKayrceALJzjeHWBuoZn6CZZLa3bldpOdbf45mkRKId+im/QAeLc/OqBU3NIyG//zvtUzFvx+4VAXD7xUz54WDyatmoc/uJ4VFfacX7+hNo/j3QGMWhXRRIp8s5YfvWMFf9jSzIoKGw6jFl8kzq9vWUOnN8LvNzXiMGqGrRjlDccHlE0fzY0/fx2AX75vNVcvLs553IIgjGxZuZ3/fOEyHt/Ryuf/vGfc5+kJTH1fyCZXmJp8Y84BcKMmXZ2iyxdlfY1zSLsLlSwRiefekkEQhDPX/CILf/vEhSRSKdo8YT74++0oCswtNHPLhiouXVDI0jIby8cwNxLGRgEM/fPgNy4tZl21k1A8yd4WL88c6Mys0yoK6NUK/hxb5tx+Qc0UjloQznz+SJwHXjo24fMcaPdTaNGxosJGty9Kuzd7gvpMmldkptcfnZTg9+kisambL+o1MsvK7QSjccKxFJKUTv7u9kVIpqCxL0TjBBNVAZDSaxQiAD48EQAX2Fjfy84mN4FYgkNZAtfVeUb2tHqZV2gmlkhmnawc6UoHgFtc6UXGddXOIWUacpFIKXT60hdai06NO3RqPNpBJcwiiRTzCs0kUwo9/gh5Zh2FVj2v1fexttrBtkb3uAPhw5W3zMakU6NTS0QTw7/PW1aWjXkMgiAIUy2pwO82nsATiiFLEs2uIMe6cq/m8e51lVyzRPTkEoSZ1heI8tDrjTy5u33UTOHx2jsooJlMKeg1MpEsbWdyFRth7jQZ9rV5RwzWjpcrGKPcruc951XzoYtqUE9Tmd2D7T7+tb+Dj14yB5MufRs3p8CcaRfkjyZ4fEfrmALgP3nXSn78/DE2Hu+loTfI3z95IaV2A1++to76bj8/fqEem0FNbb6JIqueNwZKuPX8Gt71683DnlMtj/3ncf+/DnPVwiJkUUlEECbVTavLKbLqeXhzIy8e7h7TvbHdqJmyvymD5Zv1NPSm3yvPpKXYpsekU5NMKchSukJbSlFIKekdMa/Vp7M05xQM3SGY7F9TmFdkGfKcIAhnH2d/6fNCi54nPn4Bnd4wgWiSY91+njvYxfpaJ4tLbTM8yrNXKJbgK9ctZH6RGaNWTSqlcP8zh+nwRSi16Wn3RjLJuWOp2PmD547wv+9fK1rlCMIwdjS5J62Pdbc/Src/yqpK+6wMgEfiyUm/pwfo8EWoyTehVcn4IjE6vNHRX5QjWZKo7wrgCk1tMumVCwtZWGId/cBzmAiAn+MUReFLj++l1Z19d8yKCjt9wfQv/7HuADq1zIoKGzq1akim9el2t6ZLo1v7SyAey3GH0OlLXv4sJSYHq+8OZMqPp5RoZtfitkY3eo1Mmd0wrhIeY/kDsqPJnTXz/HQzWRJTEARhsP1tXv61r5NdLW5eP97HvEIzC0usbDnhyunae9LvXm/koU2NXLukmJ+/Z/UUjlgQhOEc6fTz3t9socc/eTdruWjoDbKiwj5iSezhLCgyYzNo6QlExrW7O1fJlMK8Qsu4kjJHUpNv4ts3LmXuNAdX5hWZ+dd+8ITjmQC4zaAZcMxr9b1j6l2pUcnML7awrdHFrhZPZgcPgKLAm5aV8PY1FWxrdPPrV0/w6/ev4cXDXSOes8sfQSNL6Z7uOTrRG+Rwp39IWVJBECbuwnn5XDgvnxcOdfHtfx0e9t5cI0sYdSqMWhV2oxa1LOMJ5VbNYaIk0qXb48kUfcFYTn8bZCldIWRdjZODbV4C/bt4VBI4jJpRXi0IwtloRYUdxG7vaWXRawYkX8qyxM1rKvjlKyeGHLu10U1tgQm7UYNKkkgpsKvZzeApY12xhVA0yX/9eQ8/eMdydFPcjkMQzjQPb27inqcOTvp5+wIx1tU4iCdSSJLEzv5E65lmM2hoYXIru0G6hdfp6yh1xRZCsQTNrom/VyiWZEmZla0NUxsAX1ImErxGIwLg57j07umhC6bVeUY0KnnIomY0keJYVyCTYTmcWCI1oCzm+honjb1BukZbnB1hrS6cpYzZ6XOk4KCyFYMXBHO1qMRKLDG2EhgjlWuzGTRY9eIGXBCEmReIJnjgxXr+b1sz7lCc+UVmTFoVx7oDOScqDaYosL9tfG0vBEEYv1RK4a+72rj36YNj6puajVmnRqeWBwQcTlbR0agkCi162rKUEo8nx14y7GSVHoDF0xDs7PBN3o3yvEIzd1w1n6sXF8/ITmWNSubzb1gw4DFJSu+WPPnf7uQOSdUYhnf98lLiiRQrKu04TpvjzyuyMK/IgqIo/OylenY1ezjRE+CieQVUOo3D7gxtdYdZWmZl3xj/NrS4QyIALghT6IqFRVw0r4CLv/NSpupakUVHVb6JZleITm8EbziBN5yY1B0wuajv9uMwaceUvJ5S0onmjb3BAb3AV1TYeWpvB0vK7FMwUkEQBGE0xTZ91sfVsoRNr6HNFc6sD1v1aiqcRgwaFdFEEqNWzc7m9M7WDl+E37/eyHXLSnEFYyLQIwj9qvOMxFOT0/bMolMzt8hMKJqk1R2iqf8eTyXB3AITSBJtnjDhKSwXPtiaagfhWBKVLJFMpaZtzfFwp59Kp3HSzucNJTDrVARybP0wVla9mjK7YUrOfTYRAfBz3L42b6YUTZFFh9OsRZYkDnb4UIbZtFHmMIy558KWBhf5Zm06iyipoChg1KoIRZPsbvVkjhturU6jkmjoGdt7ltkNOWcqOYwaKpxGGnoCY+5fvqDIkikBP5hJq+LX718zpvMJgiBMhcOdPr70+D72tnoy13erXkOHFOY96yvxhuM8s79zwALiSRqVxBV1RVw0P58qp4loIkm7N0KHJ0ynN8KHLq6d5k8jCMI3/3GQ373eOOIxNoOG8+fkUZlnRKeSafWEeeVoL72BgYGNj1xcy742L/8+2EWeScvP3rOKEpuey7//Hz51+Ty2N7mzBsAPtPuxGtRUO02o+yOuKlmiNxCjoXdoEEMtSwOCG8ZpKGnY4goPCLqPRKeWs/ZPry0w8Zkr5vGmZaWoZrBEdyqlsLvVw6pKR+axeFIZkCRaYNYxniHetLocZZjJf0NvMPNv7cof/IcNc/K4aF4+f9jSPOz5Wt3hAYH5XDT1jb1qkyAIY6NVy9z5xjo+89huAKryTWwdoZLZdHGF4rhCceYWmgck0o+m0xthRYWdbn+UxaVWevxRdjR72NHs4UMX1ZIv+iEKgiBMuz1ZKkQtLrXiDcfZNeg5XyTBgfbs67Cd3gjf+udhvvXPw/zkXStFAFwQ+l00r4CPXDyH/331RNY1vFwtK7cRjacyLbUWlVg51JmOCa2qcrC90Y1Cek1wVaV9WnaELy61sj3HVglTIRxPUp1nnJT+3Fq1NGXBb0gnt96wQrTdHY0IgJ/jHEYtFr2auQVmjnT5R9+hTbrseJFFl9Oxp+sNxOgNnFoEK7bp6fRGWFhi4VBHOoA8XLnGZeV2djSN7eKXa+lHtSxRZjcM6W2ZK4th6K/RVYuKKLLqeOvKclZXObK8ShAEYfKFY0nC8eSAKh2uYIznDnbyj70ddHrDKAoYtCpWVdg53hPgC9fUYTdqefFQV9aJc02+iQfevVL0TROEWeYzV8zDFYzx9z3tQ567aF4+H7tkDmtrnGgG9aeOJ1O8cKiLv+5sY1ujC5UsM6/ITGWekbpiCwUWHeF4kqo8E5vuvByjVs2DGxuGHYcvnGBv28A5VKXTkE507M8SX1fjpNUVotRuYPtp8zlppNI/k2i4pM7T2QwafvTOFZzoCRKOJVhabscTilGTb2JpmS3neeVU2ni8lw//fge7vn5Vpr2OSpZYWWlnQZGVKxcVUmjRj3usg1/39N4OrlxUyOHOU4meKQU21veRb9Zl+jpm4w7FWVpmI5ZM4Y/k1lrjtfo+PnzxnHGNXRCE3F2/vBSNSuapPe34IpPfT3EitGMpX0E6oG/SqrImOnV6I1kD4Ilkiq0NLh7b1sJ71leyvjZvQmMWBEEQBvrrzrYhj5l0apqyJMiOZlWlnRK7geuWlkzG0AThrPHla+vQqiR+8mL9uF6/ssI+JCHlYIePcoeBSDw5YF4VTyrsbPawvNzGnnHGT3KVnEBAfyJWVtrRqmTC8SQ6tTyuALgkwbpqZ+YzBMbQYnI8Su3Zq20IA4kA+DnOpFORSCpDLngjSSlQmWfMKQCukSVWVjk40unDGz71S19k0dHZv2B2sodh2sCLnFWvpq7Eyt5x9Jds84RZUGShvttPnllHsVVPoyuI77RxzCkwEUuk2D9MtuFoqvOMWTPUbzu/mvPn5o/rnIIgCGPV44/S4gqx8XgvdqOGeYUWlpRaMes17G31EI4liSVSBKIJ1lU7CMWSVOWbmFto5pWjvXT7I1mTgK5fXsq9b10i2jgIwizkMGn53s3LecvKUl4+0sPvNzUB8PY15dx/07Jhg6Aalcw1S0q4ZsnARaRn9ndwpMvPT16s585r67hsQTqYCqAeFEQfTbMrTJndwOJSPbFEKrO7cHCwdLpiyqO9j9Ok5Q8fXM/CEiuXLRj52Jm0v83H/GILO5vdnD8nPc90mrT85pa1/H1Pe+axiUokU+xocvPo1ia+8sQ+QrGhN+4b6/v456cvZEeTmyd3t5FIKmxpcA24yd/X5mVttYPdzZ6c+oG/crSHm//ndT51+Twunl8wKZ9FEIShJEnijUtLeGN/MKHTG+GJXW38+tUTuMZQtWGy5Zu1AxLmcxFLpGh2h2jJ0qux2RUasFswmVJ48XA3X3liX6YN3N/3tPPWlWV8/+blM9LaQhCEs4eiKLMiYXKmdfkibD7RN+TxrQ0u1lQ7ct7ZqVXJvPD5Syi26Yck9AqCkLb5xPiq+NQVWzjYkT2Q3eoevoXYnlYv8wrN6DUq9g1Kgi+26jFqVcSSKTQqGbtRgyxJ7D+t+nAusrXqnRZK+n52gqcgpShIEvjCcY6MsYLyWO1t9Yq/PTkQAfBz3IuHu7P21h7NzmYPRo1MKD7yBWx5hZ2tDS60apmlZVYMGjWSlA5znwyg72/zZspodHojrKt2olPLNLvSfSfGW5Kt0xvJBNm7/VG6/VG0apl1NU5O9ASoyjNxqN076mcYjsOoIRxLDui7WWY38MC7V7KyUuz6FgRhakUTSfa3+VDJErIEP3+5nkJLurJGlzdCiyvE84e62FjfhyTBxy6Zw0Xz8nEYNdQUmNHIMq/W9/BQf9BsMJUs8dXrForgtyDMYlq1zOV1RSwutfH7TU2oZYkvXF03rhugMruRnc0erlxYyMoKO799rQFPOM6blhZTZNVlbkRvWlXOC4e78ITi6DUykXiKi+bls7G+l9NjnG2ecNay6SeV2PQDdhZPFbUsZS3HfpLNoOGPHzqPBcWWKR/LRMkSXLe0eEigW69RgZIukT4ZARy1SuZod4CN9UMXL0/qDUS5+ZebKLHpqck3sel4HzesKOWFQ92Z3sIA2xrdmLQqVpXZclpQ2Nbo5mt/288Ld1wy5sQLQRDGp9im52OXzuH2C6tp7A3xWn0vnlCMCoeRE71BfvPaCeLJqd+N0xuIsabKQfcYFj4lCRwGLS0M/Xvz2f/bzQMv1rOs3MahDh8neoNZK1I8sauNHn+U7799OUVWsZNGEISxe/9vt3K8O8DP37MKh1GLOxSj3ROm2RVCkuAdayqxGc+N++oiq56vv2khH3lkJ5Buo1lmM6Cg0D7CvcFgb1pWQsUk9uIVhLPRJy6fy6LD3bx8pDvrjuUCi47qPCOKApFEklZ3mHmFZnY2uRnv1O5Y/0bAfLOWUpuBWDIdG+kNRBgc51ZJUFdiHbbNQTYOk2ZMbbQmy2TNdU/unK8rtiAxeKvn5Hr1WC+f+7/dfOutSwdtMBVOJ34y5zi1PL6FpWRKYXGlfdR+iidvXmOJFPvasl/sIvEUO5s9LCqxIEsSWxtdLC610uSaeK+FkyQJ5haacRg0uIKxIeXYx0qjksi36Dg2KJPHadKK4LcgCNMinlTo9EZIpVIsK7fzqSvm8fvXm9jV7KaxL8jyCjsNvcHMbry/7W5HkqDDG8EbTifuaFQSy8ttqGQJSZIIxRKZlhS/uWWNWAQUhDNEkVXP6ioHHZ4wBZbx9TtdWm5j61euQJIkEskUzx3qYmujmzVVDu65YQmecJyfv1TPt966hPvlpXR4I9iMGh7Z3ESxVc/rx/uG1Bq36tWE48khN5N6tYxWLdMxTPnsybSqyjFiMuV1y0rOiOA3wK0XVA9bzv3taysm9b3ed14V/kic7zxzZNhjmvpCNPWFMjsPGvuaqXAa0KpkYslTqx/BWJItDS5WVzlyamnU1BfisW0tvPe8qol/EEEQcqZTq1hQbBlyTXzb6jK+/rcD6ev8FDvQ7mVZmW1Ia41stGqZeYWmYY+NJVIc7PBxsGP0RVeHSUvhOP9+CoIg3H/TUv7fPw/zgYe20ReMDZiv2Y0aVlc5WF3lnLkBTrMOb4RFJRbUKpkub4StjWPb2HT98lK+8ebFUzQ6QTh7XDK/gEvmFwCL+ckLx/j3gU4MWhXuUByHUUOrOzQkdjNaLCdXucRWlleMrW+4QaPCHZyZ9jwHOnysq3GOeyPmYMFYAo1KIjbFSaRP7m7n/Ln5vH3N5K4HnE1EAPwcV2o3jPu12xrd1BWbOdw5fDmHeDJJTb6Rht7Rg9nHugOZBdLxZK3YDBq0ajlrqQxFAbNOzdZJuMhrVBJ1xZasAX2LXvxKCYIwtSLxJJ3eCIFoHItexabjHrY2uOgLxugNRHGaNORbnMQTKVSShEWnwh9NcqRr6E7LeFIZ0L9HltKVLJIphX/s7eCS+QWilI4gnCE+cnEtX3li34TOcfL3Xa2S+ep1iwhEExg0KlSyhKIoJJNKpvf0yR0ZH790LgDXLilhc0Mff9jczEtHutPJkqU2jFoVLxzuzryHRpaYV2QZUjJtpuTSH3y20KlV0/p+H7tkDv/7asOYSiJ3+aK8b0MVWxr62D9orryz2U2RRTdqG6VCi45/7evg4nn5VOaZxjV2QRAmz9xCC3/44Hr+vqedLz++b1wV5HIViadLmueiwKLjQPvkVBLxR+JizisIwriV2Az89F0rAXAHYxzrDmDUqqjJN52Tu/IqnEaa+kIEY2P/e1FmN/Djd64Q12RBGKPafNO4W7xOlcMdPtbXOFGAWCLJ7pahawAqWWJVpZ0DbV60GnlGdn9Desd20wiV48aqwKzL2qJnsuk1MiU2sXlpJOfeX2FhgAPtE1t8VMkSy8tsqNUSspTeQdjpDdPrjxKKpyh3GDFq1YSiyVEXuwbsDur/0qJXU+EwEo4nkSWQgDZvhPCgSdTi0lPlNGrzTRRYdCgK9AWjHO8JMpntvJaV24fdvXLlwqLJeyNBEIR+sUSKB16q55WjPcwtNBOOJXCatXR6IkQSKXRqmVK7gS39gfCTjFoV+WYt/mhuk66UQqZk8dEuP8FYEvM5eMMuCGeiKxcW8e1nDtPli0yoekMypbC7xcPqKseA339Jkrhy0fDzHINWxWULCrlsQSFdvgj/++oJCi16blxVxht/8ipdvvQ8cGWlY8y7QMZLIl0W/NL5BXR4I2jVEgaNmlAskVkciE5hIOdM1+oO4w6NvR/vb15r4F3rKplbYOZve9ozSQaKkk6+HXxPoFVJLC23IUsSHd4Ire4w3f4o337mMD9/z+rJ+jiCIEyAJEncsKKMRSVWfvnKCf6yo3VK3kcB5hdZctp90+YOU5NvGrHNRa5ePtLDsS4/84rOjIoggiDMXg6TlnU1585u72z2tHrHFfwGuOOq+SL4LQjjcOWiIi6ZX8B/jvbM9FAyQvFUpg1Wtutibb6Jxr5gZlf6eNvUTpRBI5Nn0nG8e/J6dseT0/NZ9BoVzZNYRflsJFa1z3HecJw1VQ6OdQcyJXFHIwFrqh1sa3Rj0KjZflow2GnUYDFoQErvkt7Z7CGlKKytdo4aAD9dKJZgWbmNg+0DS5atq3ZyojdIdZ6RQqseVzBG/aCL04neICf6b4JVEpw/J48ef5RdYyi5MZL67gAGjcy8Igv1Xf4BF+cyx/h31AuCIGTT4Q3z7IFOTFqZ6jwjTX1BunxRYokUJp0Kk05NIJqgxx8lGEuXO19ZaUctS/QFYpnr4Un2/t5jkVgSjTrdBiNbP0S9RiWC38I5I5lMctddd/HII4/Q2dlJaWkpt956K//93/99xizAyLLEu9dV8s99Hdx2Qc24z/OHLU0caPOxumr8LV2KrHq+et2izPdfuLqO//rzHiA9x5suJ+erg6lliaVlNrQqGZOo3gPAwXYfi0qtme+jiSRfeWIfigI6tUx0cEO3UTy+s5Uyu2HIDvtdLZ5MabnafBMqWUKjktnR5Blyjn/u6xwyLkEQZta8Igvfu3k5q6sc3PnXiVUdGU5yDKUiFUXBadKOqVJFNoUWHUVi94wgCMKkWFlpH9PxlU4jeSYtGrWMPzoz5Y8F4Uyn16iYX2SeVQHwgYbO75pcIdZUOactQT6buYUmLDoNr9X3sqLChjsYo2kSdm5PpPXuWHhCcb76xH7MOjU3rCiblvc804gVn3Ncqd3A9iY3qyrtmd0WI6nOM+IwatnW6KYqzzgg+A1Q6jBkyh0e7jxVjiyWSOEwanCHcpvIHOnyD+kXCeAJx5CAxr4QjX3p7JYyuwGdWs5aUjGpQDiexKhVUVdsQauW0WtktjW4s1x2c+MNx6nJN7KvzcvcAjPNriDRhML7N1Rx9eLicZ5VEARhoBcOdXGow8exrgCBaBxXKM7SMhuldgN7W73sbHbT6TvVP1eSTpXybe4LUek0Dgl+rx0UDIolU6QUWFFhp7EviOe0a3TZBFpkCMKZ5v777+cXv/gFDz30EIsXL2b79u3cdttt2Gw2Pv3pT8/08HIWTaR47VjvhALg71lfhWoSS+d4QjG6/REMGhXxZJL6nsnLqs7GalBTV2Slwxsetr9ZIqVkSrAnFIVEMoVaJU/puGazHn+Um//ndX70zpU09QWZV2ThgRePsa3RzaISC+5QnAqHYUythGKJ1LC7Mrc2uMg3a4f8jcrmmf0dIgAuCLPQu9ZVYtVr+P5zRzjRM3nlIiF9z5+rxr4Qy8ptQwLgRRYdpQ4DWpWMoihEEyncoTg9/mjWEu5vW12OVa+Z8NgFQRAEONYVYGWlnR5/FLWcrvCzosJOUlHY3j+fNGhVzCs0E0ukONzpz+xgbHOHuWVD9RmThCwIs8kTu9pmeghDSKQTDTWyzNIy24BWaMmUwq4WNzaDGm94ehLl11Y7kCWJlKLQG4hS331qHnuyRPvcQjOplDLkfnVZmQ2tWh4SDxuszGGgzT315c9P95nHdvPwpiZ++b7V5Jl10/res50IgJ/jqvLS/Rsbe0MYdKP3FSyw6DKLiU19Q8srDJd5faDdy+pKB0c6/SAxaiA8W/Ab4GhXgMWllgG9vto84UzJ3myy7fxeWWmf0I7wkz3Nj3UHWFPl4FCHjy9eUzfu8wmCIHR4w4SiSZ7a087aGieuYIyN9X0EognsRg2HOnxZr1tGjUypw4hFp0KWZEAhnlQw6lRoVRKx/uvpklLrkGtvqv9Su7vFg1Yts67GmSkHvLPZzcZjvVwwL38qP7YgzAqvv/46N9xwA9dddx0A1dXV/PGPf2Tr1q0zPLKx6fZFeN+GqgmdYzKD3wB2oxatKp2AWOk0cKRragPgRRb9mDLI97R42Hi8j0vmF0zhqGY3lSyRUuBDv98+5LlYUqHDG8ksXO5u8UzKe+aaEf+fY73c8YYFk/KewugaGxu55557ePHFFzPVMN773vfy1a9+Fa1WmzmmpmZoks2mTZs477zzpnvIwgy6blkJ1ywp5rmDnfzmtYZhk47GKqWALJ2ap45mb6uXumJLJgF/SZmVo10BuvzRAa3SIL0AW+YwkEylaPdEMtUtxtruQRAEQciuNxDlV68cHzDXkyUyZZCXldnQaWRiiRR7Woe25WzzhHEFYyKAIwhj9Hp977TtOh6LRf1zsZObFldV2nEFYzhMWtSyxOFOP3kmHXXFVmKJFK5QDE8oTrFVz5Eu/yhnH5s5Baac5qv13QFUskRVnhGrXkM8mcIbjrO3zYsspeeaJzeAZtPuCVNo1tI9zf89tje5eWJXGx+8qHZa33e2EwHwc5xEepHTG44RT43+z2FwGcPBjNrs51hebmdz/2RnabmNlBLKueT6YJORBbir2cOaakcm83AiZFlCo5YxaUdPIBAEQTidLxJnf5uXmnwTj+9oIRRLoVHJ3PLbrSQVhbpiK0c6faQUuHh+AY29QTyhGL5IgsWlVmQpvePz6DABJVlK99QpsurYdGLkgFAskRrSb/G3GxtEAFw4J5x//vn86le/4ujRo8yfP589e/bw2muv8YMf/CDr8dFolGj0VNUZn2/4m5/pdNf1i2flbonbLqjBHYplFr6m0rHuABqVNGwyZTa3/HYr62qcfOryuVwwJx95kpMAZjunScvbVpfz8OamIc/VdwcotOjo9kc51uVHLUskco1KTYL9bV5SKeWc+28yUw4fPkwqleKXv/wlc+fOZf/+/XzoQx8iGAzyve99b8Cxzz//PIsXL858n5eXN93DFWYBlSxxzZISrl5czF92tHL3UwcJRCe2g6ehN5i57uSqqS9EhdNAoVnPnlZP5jplHHSP3u2P0huIklJgXqEZh0lLMqVw6fzCCY1ZEARBSGvsDQ4Jwp0+ddzbNjToPVizKyQC4IIwBoqi8NuNjVy3tIQ9rR50apnjk1yhZzwGV6EE2Nm/safxtI2V/khiyG5rbzjOygo7oXgSk1aFLEuoJIloIkU8meJQhy/nZElIt8k93hNkfY0zp3WJZErJuvkzpcD+Nh82gwa7UUO+WYtKlpBI3ycHown6gjGKrfppD4AD/OLl49y0qhyHSTvt7z1biQD4Oe68WifrqtO9Fkpteo5E0kGUumILHd7IkCD19ib3gOzqwZxG7ZCFMVliwEVMI0tUOg009irEUyki8bH1FDRoJifQvL3RzcISC4c6JpZN1OOP8oO3L5+VC86CIMxux7sD9AVi/GVHCwfa/ITjScodBtZWO+nxR7Ho1aypdtLsChFLJCmz66nNN9HsDg3YzTKclJK+/vYFY2NeSATYMEcsZgvnhi9/+cv4fD7q6upQqVQkk0m+9a1v8Z73vCfr8ffddx933333NI9ydLN1LqKSJT552Tx2NW9jVaU9c9M7FdZUOUYtSZbN1gYXP32xnm8+dZCnPnUh+kmab54pzKf1QlfLEkvLbdR3B8gzaTOLE8FYMucFg8mSTCn8YWsz7ztvYpUNhNxcc801XHPNNZnva2trOXLkCL/4xS+GBMDz8vIoLhbtn4Q0SZK4eU0FF88vYEuDi2f2d3C4009Db3DUJPrBFhRb0pXjRjqmyEIsmW61IEvp9Qu1SmJ3i2fAWkS2hdGTjx3rTq99zCkwcVmdCIALgiBMhp+8WJ/5WqeWUckSodjQ1hPZnFfr5H3nVWM3isCNIIzFn7e38vKRbv72yQuYX2QhmVJo94R5+y830xsY2zrgZCm06OjyTey9d7V4qHIas84L7UYNVU4japWMNxxHJUlIElljVoUWHe5QjJXldlJjnZgOwxuO4w3HswbJ0+85M9exvmCMTz+2i1+9bw0GsVkTEAHwc14wlmRPqweAI10B1tU4aXWF8EcS6NUyYZVEVZ4pc3MIEMnSM+ukdKmy9IXEbtQQjadYXGodsBCpAPvafKgkqMozkW/WjalU5fYmN5VOA82uifdSiCfHFnzP5gtXL+DyuqIJn0cQhHPLa8d62d3iJhCJs6vZi1WvpjLPSDyZyvQn7PJFCEYTBKNJNnvT18nlFbYx91oMRhNU5VkpsevZ0zJ6xvVJVy0S1zbh3PCnP/2JP/zhDzz66KMsXryY3bt389nPfpbS0lJuueWWIcffeeed3HHHHZnvfT4fFRUV0znkM45Bq+JDF9eyrcE1ZQHw1VUOdjaPPfgtS5Bn1nGiJ0BvIMb/bWvhlvOrJ3+As9iG2jx+8fJxAIqsukzLDX9k4E7OY11+JAlWVzrY1eIhOcW7wbUqmf95+TgLiy2sqXZO6XsJ2Xm9XpzOoT/766+/nkgkwvz58/niF7/I9ddfP+w5ZmvVDGHyFVn1XL+8lOuXlwLwn6M9fPChbahlOWvv7cEKLboBi5wOo4YyuwFZkjjU4SOeUlhcaqWhN4jdoGF+kRm7QTvsekIu9/tXLSpGq5Zz/ISCIAjCcJ4/2MXeVg9vXVnGhto8rlpUhFmvZmN9L5Ik0eWNYNSp2Nvq5U/bW/D0t2irLTDxpWvquHqxSKwThLHa1ezmzztamFtoptxhRKOS0aigJt9EmV0/IwHwcocBXzg+5k04g80rNA+ISZ3OE4rjCQ1c39TIEkvLrOwbVJ48z6yl2x8dV6L8eJm0mml7r8FePdbLFd9/mXesreQDF9Vg1p3bIeBz+9MLmLSqARnZg8vfAug1p24GNSqJFnf2wHNNvilT5hzSF6I5BaYBF5diq462/tcn+3cmnugNsq7GSTKlsCOHC5FVr5mU4DdAU2/2LJ1cLS+3ce0SMUETBGHsFpZYePZAJwc7fHR4wzT0pgAvallCgWGDCntavBSYdaQUhZp8U04TuERKYW+rlyKrjpUVdiQJZEka8bVqWWJbo5tyh3HSewILwmzzhS98gS9/+cu8853vBGDp0qU0NTVx3333ZQ2A63Q6dDpRlm+sLltQyPeePTIp59KqZGL9gQ27UcPcAjM7mt1j2mlY6TSioNDiCtNz2s35X3e1nXMB8Avn5md65Y5U4twVilOdZ2R7k3tKd/NfMr+A2y+s4bxaJzq1yFyfKfX19fz0pz8dsPvbbDbz/e9/nwsuuABZlnn88cd5y1vewpNPPjlsEHy2Vs0Qpt4l8wt45APrWVRq5W+72/nlK8dpGeZeXiWlr8u1BSY6PBEC/SUk3f0BkkqnkQqngdeP96EoEIol0QZlEsnsC6MAWrWM3ajJBFmyOa9WJNcIgjB19rd5+fQfd3HdshI+/4YFMz2cKXXenDxe+eJlWPUDAz+XLhhYZeNNy0r5yMW17G31EE8pXLagEI1KJCIJwnisrHTw54+eP+RxSZL480fP57P/tyuzU7l1mJjOZMo3a5EAX2RiLXH0GhmHcWxB5HhK4UC7jwqngVQqndht0alp8Uz95x6swxtmXbWTA+1egrEkFQ4DFr2aY92BMbVrG4+L5xfwhTcsQJJAL5I8RQD8XBdPKmjVpxYQsznWFUAlSyRTCguKLASiiQF9GjQqiaVltqznGNxvojLPyNaGoQGXk4F3g0aVNTPcrFMTiCYotelxmLTj7h9+umx9KE6y6NT4c+hdtqfVy4MbG7n9wpoJj0cQhHNLnlnHJy+fy89fqieeTNEXiOENx0ftm6hVyQSiCcLxJN5wjGXlNlzBWE4T2S5fNFOCaH6RecRjEymF//rzHu5/5jAXzc3nv9+0CKfoISOcpUKhELI88MZApVKRSk28Uoww0NpqZ04tHE533bISnt7bAYBFr2ZlpYPmvmBmPnoyIDtWJp0qayucPS0enj3QeU7tQpFliV+9fw3v/vVm9Gp5xHJ1J3/uU7X7+8MX1/KVNy6cknOfq7785S9z//33j3jMoUOHqKury3zf1tbGNddcw80338yHPvShzOP5+fkDKmCsXbuW9vZ2vvvd7w4bABdVM85t62vTLXXee14V7z2vio31vTyzv5OHNzcB6V3ecwvM+CKJEa/lza4QBs3ABP5YYuS/09sb3WhU0ogJO8FobqV5BUEQxmNJmY0X/+tSEpNQgXK2G8suwzyzjstENU1BmFJatcwP37Eik1Dc7Y+w5YSLfx/sIs+k5febGsfUR3s0dqMGjUoedvPkWCwqsbJ1mLjNSFIKmWTLNk+YRSVWzNrpD4GadGq2NrrQqSUKLbrMz2RlhY1dY6jMOR4b63tZV+3gI5fMQS2Si0QA/FwXiCZG3dlXYNFRZNXTF4yxv91HkUVHoUWHRi0jAaV2Q9ad40POY9ZxsH34Xl4FZh09g8pyaFQSi0qtHGz3cf4cJ63u8JgXTbNZXTUw+O0wajKZ5Wadmp+8ayV3P3VgQKA/m4vnF3Dt0nNncVQQhMn1hy3NvHqsF18kQSiWGNIby2HUYNSqaevPVrQbNSwts/HqsV4AEql024nxZHEe7QqwssLOrhbPiMf1+KP8dVcbjX1B/vrxC8b8PoJwJnjzm9/Mt771LSorK1m8eDG7du3iBz/4AbfffvtMD+2sc+OqMuxGDT96/ljOr3EFYtx5bR3PHOikwKzj3rcs4cZfvJ55Xh5H7/PRrn8fe2QH/3X1Aj52yZxZ21t9spXZDfz+9nXc8tutFFl0dI1Ssu5Qhw+9RiYSn7wFXYtOzaevmDdp5xPSPv/5z3PrrbeOeExtbW3m6/b2di677DLOP/98fvWrX416/vXr1/Pcc88N+7yomiGc7oK5+Zw/J49im57vPnuE+cUWtpxwsbbaMeprW1xjawMEoJZldjZ7WFfjHLJuoVFJVOUZx3xOQRCEsRJBCEEQZsLp1bQKLXrevLyUN/e3qjmv1kmLK8yRLj9/2dGKVi2TSKZYX5PHse7AmMunl9oMHOyYeNzGZtBwcBLiP5BO2jbr1Vj16gnvSs/VuhonTb3pOWs0oQwoBS9JUs4bL8crmVL43r+PUmwz8LbV5VP2PmcKEQA/xzX0BkfdTd3iDg/I3Dl9Mcxh1Awb/Nao0ouFJ8s65Jm1HO4cPgBeYtcPCIAbtCoWFFnY3b84GUsoNLvCaGSJ+AjpSSU2Hf5wgkBspEzu9OslCb5y7ULmF1v40O+3o5Ik3rCoiMvqCrlkfgH3P3uYX/7nxJBXn3zdBy+qOWcWRQVBmDyhWIKn9rSzvsZJIpni1WO9lNj0aFQyrmCMRCqFSaemxKanvjtAbYEpnbAkpatx2Awa/JE4KQV0annEvjjZWHRqFpVa2ZJD8hKkr3lff/Pi8X5cQZj1fvrTn/K1r32Nj3/843R3d1NaWspHPvIRvv71r8/00M46y8rtfP1vB8b0mk0n+rj3rUv4yCVzgPQ19KZV5fxpewsd3siYA+CrqxzsaRk5mzylwHeeOcK+Vi/fvXn5OdM3qyrPxPqaPE70BkYNgMeSCnUF5hHn92P1wYtqz5mf9XQqKCigoKAgp2Pb2tq47LLLWL16NQ8++OCQ6hjZ7N69m5KSkokOUziHSJLEhy6qpbEvSEN/1bjtjW7KHIZMy7TBKpyGYcunD6eu2EKrO8TiUit9gSg2gxpv+NSC4w0rylhSZhv/BxEEQRAEQThDXbMkPX8/3hPgmsXFXLqggBO9QeYXWYgmkvzguaNZ4yLZTObO5lRKId+so3USSpcf6Urfq9YVW0i4QkM2Hk221VX2ETeKnqxI5DRpKbHpMenU1HcHcAVjkz6WY92Td59+JhOrC+c4i378/wQ0ssScAnPWMmXrqp1sbUz/sq+vcbKlwYV5lPcyaNIZSUVWHVV5Jnr80UzwG2B7k5timx53MEaeQUNfMIYEFJ62Q8Vp1NLhjaJRSZn3zSYST3JerZMPXFjLVYvSJXeO3nvtgGNkWeJ951Xx2rHeIbvOa/JNIvgtCMK49QVirKt28pedrWxrdFOTb6LbHyGeVIjEExi0agKRBMciAWQpXY63Ms9IizdCbyA9KTJpVcwpNKOSJI51B7AbNcwvsqRf1+0fsaeMQasilUOj3OuWlXDvDUvQa1QYtKIHq3D2slgs/OhHP+JHP/rRTA/lnDCv0DxgjpeLJ3e1Zfom3vrgtpyqDw1HJUuMUjU341/7O2nqC/G729dSaNGP+z3PJLdeUM0tv92a07HhWHLSsunXVTv55OVzJ3weYfza2tq49NJLqaqq4nvf+x49PT2Z54qL01WvHnroIbRaLStXrgTgr3/9K7/97W/53//93xkZs3Dm0qplPnLxHL75VDopSiGdpLm41Drk/ntuoXnM5YPzzVq6fREC0WTWKnK1BSb+31uXjnv8giAIgiD8f/buO7zJ8usD+Dd7NelM926hpZRZoJS9ZMhUBMEBCIIITpz4U4aooLgXqK8WFRUFEVBUBGTvVVahtKV7793M+/2jNDZNukfa9HyuiwvyrJwnJCdPnnMPYg0ClDYIUFZNk9jdRQ6gque4h52kwX37edniVlZpqw7rLeBzodHrEewqb5XG1gFKGYorNW1a/PZ2kMLVVtzo+xT5ZWqjore3gxTJ+fWPRNxUCnHT5lC3VlQA7+J8HWXwd5Lhdu5/Q4n187ZDRmEFPOwk4HI5YACqy7wqrR5XUqsSWh8vO7PF71B3haH4DVT1MpeL+bhUx5xbNfG5HNiK+eDA/HxemUWVAACFmIN+3nZQa/UortAg3NceCXnlKLszfIRGx3AmIR/+TjII+RzwuBxcrzH8uqNMhG8XDmqwgO1pL8Xep4bjpR1X8PP5FMNynZ5R8ZsQ0mxeDlKoNDqE+dijoEyN2OxSxGaVQKVlqNCYXpAFKmUQ8bmwkwrB5XDgohChoFxjyMcAUFiuMVxoyYQ8hLrLkVJQbiiY15RdokJBuRoDfe1xM6MYJXXMfXjsVg7UOj3sae5vQkgrui/ME0l55QhwlmHXpXSzea/ayO5KnE/Mx/iQ/6aceWZcN7y26xri7/QajM0uQYBShrwyNQrL6x/ZCAAKy5vWujo6oxgzN53ED4sGw7sLDJXbw02BWQM8cTI+r8Hr96T8cvTyUOBqWsuHqONy0eDUTKRt7d+/H3FxcYiLi4Onp/FweaxGw7l169YhKSkJfD4fwcHB+Pnnn3Hfffe1d7jECgQ62yDIVY6jd6b3EfK4yC6phJutGBl3fvubG7q8IQIeBw4yIW5l1T1CkqtCDCGfhiQmhBBCCKmm0enx7clE/HwuBfE59Y80aScVID6nDGWtWFgOUMoMv/Ozips2BHtdEnLL4GYrxqjuTsgv00DI5yI6o7jFBXGJgAdXWzGKytVIzi9vdgF7oK99qxfnNz3YH5N60QhdAEBX+11cWmGFUfFbIeHjZmYJSlU6qHUMZSodBvs5Ir2wEucSC8DncjDAp2puLi6Hg0F+DvBzMr4RyK114yq7RIWSSi109QxbDgBanR5BrnLcyi7DmYR82EpMW6m42orhYSeGWMhFdrEK19OLkVJQAQYOsktUJgn3dm4ZbmaW4np6CQb5ORiW9/Wya1IB20Xx35x1fTxt8enc/o3el5C2kJaWhoceegiOjo6QSCTo1asXzp8/b1jPGMOqVavg5uYGiUSCcePGITa28fOtkraXV6ZGH0872EmF6OGmgL/SBr29zA/BmFmsQlx2GeKySw25LrOo7qGAytQ6XEophFIuQqi7AhIBD/297RBeIw9q9QwXkgoADgdD/B3NHqe4Uou5X55ucKoMQghpinB/R/y0ZDAA1Fv8BqoaHf66bAh6ef6XH4cEOOGlicGGx0UVWsTnlKGbs02jnv9WVik87JrWmzslvwKLvzuPcnX7zBtmaZNC3ZCSXw6HRjSAqqv3t4jPhVjQ+J+bp2/nY9Ph+EZvT1rfggULwBgz+6fa/PnzER0djbKyMhQVFeHMmTNU/CbNFp1ejD+vZgKoGgoypaAcmcUqQ/G7v7cdav5q93OSIdzPAQN97THIzx6DfB3Qy0MBz1o9lMK87c3eT6ipqfNaEkIIIYRYu9SCCvx2KQ0ZRZWor5QzPsQFPywKx7oZoVg83A/dXWxapTFzU0f8qU+QixxhPnbo720PO6kQh2/l4kpaEc4nFaBcrUOImxye9g33cq9NyOdiaKAj+DwOEnLLkN+IRvh1cZGLcD29GLHZpXCzrf8eRW9PWwQoZfCwk6CXhwKBd+5/yMV8jA12xuRebpjS2w2Lh/thTA/nZsdkbagHeBcXm1WCcD8H3MoqAQOg0zFUqHUYFuiExSP88cWReGw9kwSJgAdHmRBRKYUIdbeFr6MU5xLzIRPy4CQXGR2zooktVrzsJXBRiMHnAReSq3qP+DpKzc5TkFlUCamAiwqtHjVH7z2flA8HqaDehHM2IR8DfOwxL8LHMMdFY0UEOGHv1QyIBTw8c1d3o5uwhLS3goICDB06FKNHj8Zff/0FpVKJ2NhY2NvbG7Z555138PHHH+Pbb7+Fn58fXnvtNUyYMAHR0dEQi7vGEK4dnbudBH9dy4BOz3A8Ngch7rY4czsPAOBkI0KYjx2S8ysQoJThYlIB9AyGQvTtnDLIRbw6e25Xu5FRlUflIp5hnhkfRymS8sqhEAvQ3cUG5xMLcPJ2Hgb42uNCYgFqX98m5JXhamoRhnVzatXzJ4R0bTwuBw8M8kE/L3uIBFy8/OtVs8VwBoZvTyZh/b3Gw9SG+zma9AosaeQw3IHONojLrr81uzkxWSV46der+HhOX6sfCehGRjFyS9Xwc5JCrdGhtJ7r+7qGVvt+UTjspAIs3HIOqXXM6VubpAkFc0JI5/b18QRs3HcTlRo9+FxAKuSZ5IrCcg0KKzQY4GMPDgc4l1iAhBoN+KuJBVwM8LFHUYUGHA5wOiG/wWE7p/f1aNXzIYQQQgjp7PycZPj9iWHQ6hke/voMzibmw9wMiv9EZ2HOIC9M7+uB6X098L/JwE9nk7E/Ogsn4nKhqjWyr4tC1Kge3QqJAEDz5/4e4GMPrV6PMpXOMP93XaIzSuDbiBHe5GI+POwkUIgF0Oh0KK7UokKta/T9h/pklajA4wA69l9n00q1Dlq9HjpWNR+6RMgDj8sxGp0trbACPE5V7/GVdwejv7dD3U/SxVEBvIvzdZLhocE+cJAJodbqIRXyIBPxYSsRQCkXYUQ3J6MbfDo9Q2ZxJW6kFyM6oxgXkwtwIi7XsN5GyGuwpzcABLnKkVeqgo+jDFHJBUgpqACXUzVUmUbHkJhXjjBvO1yoNeyirUSA4gqNSYHGw06CggaGs/R2kOLdWX3g6yRrML7aIgIccfC5UU3ej5C28Pbbb8PLywuRkZGGZX5+foZ/M8bw4Ycf4tVXX8X06dMBAN999x1cXFywa9cuzJkzp91jJqYYY8gpUSEiwBF/XcuErUQALpeD0UFKuNtJ8Pvl9KoWijE5KFUZX1SF+djjQlIB+FzAx1EGAY+LcnXVSBvFlVqTi7CahfIKddXQ63HZpdAzGPLp+cQC9PO2Mxnutqe7gorfhJA20cvT1tCo0MdRhrSCChyPy8HRW7nILK6ETs9wIi4P7mGmRYzLqYW4lGw8Fc/NzBIM8LE3O0VPtUF+DohOa/78ZL9fTkcfT1s8Oty/2cfoDGYN8MKZhHzsuJAKPycpukuFUGn1KFfrTIpPdfXyDlDK4Ggjwq7lQzHpo2PIKan7hkegsw3emBGKwXWMSEIIsS4FZWrsvZIO/Z17B84KsdmGMtWj1fk7yXAuse7cXi0prwxqHUMfT1tcTq0/159PbNqw6oQQQgj5z5o1a7B27VqjZUFBQbh58yYAoLKyEs899xy2bdsGlUqFCRMm4PPPP4eLi0udx2SMYfXq1fjqq69QWFiIoUOHYtOmTejWrVubngsxxuVyIORy8PNjEfj7WgaW/3jJbL1n0bfnsenB/oaOhnMHeWPuIG/8eiEVh2Ky0cNNAbVWDz6Xg7nh3gh/62CDdSMBr3kNogf62kOnZ/XeCzAnMa/c7HQ7fk5SCHhcVGh0yCysNJqL3EEqbJXidzXdnZckrbACaYWNL/7397HHW/f0Qrc787YT86gA3sV1d5GjexM+JDwuBx52EnjYSTAuxAWVGh1e3HEFey6nV63ncaA31yyoFgmfhzKVtmr43Tv0DAhytjH0WMwqVsFRJkRe2X+FbTupwOxQvLYSAVLq6VniZivGP8+OgFjAa/S5EtJR7dmzBxMmTMCsWbNw5MgReHh4YNmyZVi8eDEAICEhAZmZmRg3bpxhH1tbW4SHh+PUqVNmC+AqlQoq1X83pouLWz6XJ6kfh8PBvAhfHI/NwacP9MP+6CzM6OuBiaGuWL3nOhgDMooqoNH9l1PFAi5C3W0Rm1UCiYAHrV5vmBvnv+NWDRd5sY55W7NLVPC0l4DLgeFP9fXnpeRC+DhKkXtnmHUhj4upvd3b6iUghFi5a2lFuJ1bhml9Gs4jfb3s0NfLDpN7V/14Vmv1+N9vV/HrxVSzw9iO6K7ElkcGYdG351Cp+a91eXR6UZ2ty8O87Zs8j6w56/+6iQG+DujrZdfiY3Vk787qAx8HKd7bfwsJ+G8+Mx8HKZJqzG9W16V/TqkKjjYiONmIsGxUANb+Hm2yjYjPxVNju2HxcH+ai5eQLmTbuWTcyCyBr5MMZSotMosqIeRzodaaH/YyNrsEDjIB8suM7wVwOcAAXwfEZZUY3fDkN+LmqbWP5EEIIYS0tZ49e+LAgQOGx3z+f6WmZ599Fnv37sX27dtha2uLJ554Avfeey9OnDhR5/FoNMuOZ2KoGz6eAyz/8aJhWR8vOwz2c8DMME/YmfmtPjPMEzPDPAFUNWrILlHhXEI+5GI+CusYvdfbQQpXWzFuZDTvfnRqQTnU2oZrUuacTcjHIF97FN+ZwtdeJsSlpAJo6ijW+zlJTTpttqdgVzlWTQlBRIAjXc82AhXASYuIBTx8PLcfxvZwxjM/R6GoQgsbkQCe9pJ6hzrkcIAKjemPW6nwv7dkamEFBvk5IK/GjcqU/HLDsBDVZEIeUutpHdPTXYEv5w2g4jexGrdv38amTZuwYsUKvPLKKzh37hyeeuopCIVCzJ8/H5mZVfPo1W5V6eLiYlhX2/r1601abpK2V67WolSlxWu7r+Gte3rh1O18LN16AeVqHTicqvxVodEjJrOq4O3nJGuwNSNjwMXkQvT3tkN8TimKKoxbJUoEPHA4uFN8z4VMaDyUemp+OZ4bHwQnuQgjuinh2sAcNIQQUlulRod91zOx7o9o+CttGlUAr03I52LjrD54bKQ/fBzNj94zNNAJq6b0xCu/XTUsK9fo4etkWgC3lQgQl1P/EGiNpdMzvLX3Bn5+bLDV/+B8YkwgLqcW4cCNLMMyF4UILrZi6PUMesZwPd38TYrT8XkIdlUAAB4Z6oerqUXYeSnNsH5YoBPeuqcXvBsx7BwhxHro9Qx7r2agQq3DraxSeDtI0d/Hvt4e3kq5GIV3RnyTCXnwdZIhIbcMfk4ysw2b9HqGIBc5BDwOYjJLzN7AnNqnadOiEUIIIcQYn8+Hq6uryfKioiJ8/fXX+PHHHzFmzBgAQGRkJHr06IHTp09j8ODBJvvQaJYd16RQVywc6odfzqdgSm83rJ3eEyJ+4+osKq0ea3+/jpsZJSbFb6VcBDfbqmu85PxyJNdoZN0UQh4HnvbSRo0WVJezTdjXXE2rPXA4wOLh/lhxV3eqczUBFcBJq6ieP+u5Xy7D016CpLwyOMtF8HOSQaXVgcfhoFKrN9wgu5RSaDK8hFzEM+oRDlT14hnVXYlyjQ4ZRRV35iGvGsos2FWOnBIVvB2lJkP2VuvhpsBPSwbXOTchIZ2RXq/HgAED8NZbbwEA+vXrh2vXrmHz5s2YP39+s465cuVKrFixwvC4uLgYXl5erRIvqV9qQQXmRfiiVKWFi6Kqp1xppRYMQFRKEXwdpQhQylBcoYG9VID+3naITi9GZR09ZKpdTC40GtLcWS6Cj6MUjjYiVKh1OH07D9fSC9HHyx5aXdX8OGIBFxIhD3287DA0kIY9J4Q0z+rd1/Hz+RQAQG5pPnJLVXCyETXrWIHOVSMVMcbw+5UM/HE5HRqdHmOCnfFwhC+m93XHb5dSjX7sRmcUo5+XHfLL1UjKK4dYwIWHnQTRzWxNbs7ZxHzsj87C+J6mN3ysCYfDwX1hnridU2oYirixNwe+OZGIBwf7GIaxe2Son6EAPrm3Gz66v2+jemkSQqxHSn453v77Jq6l/ZePk/PLwW2gLZFaq0N+mRqh7gpo9VUNb+QiXp0NcC6lFAIA+njawlYqQG6p6XRpdhJhs8+DEEIIIUBsbCzc3d0hFosRERGB9evXw9vbGxcuXIBGozEamTI4OBje3t44deqU2QJ4c0azBGhEy/bA5XKwamoIVk0NafK+YgEPnz8YBpVWh/s2ncLVGtORDfJ1wN6rGS2KzddRCh1jLSp+N1V6UfPnKG8uN1sx3p/dFxEBNGVYU1EBnLSa6X09kFuqwpdHb0OvZwhQ2uB0rdbYg3wdcDYxHzwuBxqdcfHG21Fm+AE7yNcBDAxcDgeZxRW4mVmKXh62SCuoBFDV4qWgTI2SSk2dxe8xwc5YO60nFb+J1XFzc0NIiPFFR48ePfDrr78CgKH1ZVZWFtzc/uvZkJWVhb59+5o9pkgkgkjUvOIEaT6pkA8uBzgck4OCMhUcbETgcTmQivjQ6fWwEfGRmFcOEZ8LPycZTsTnAYDZ+WnMuZRc1dgoo6AcbnYS3MwsgZNcjUeH+SG/XI28MrXJcd6f3YeK34SQZitXa3EoJtto2Ss7r2L1tJ7wsDOdy7sxsksqsfNiGq6mFWFSL1ecTcjHyO7OAACZiI8hAU4mP3irix+D/R1QWK5p1eJ3tQ8PxOKuEBer7wU+oacL/riSbiiAN1ZyfjkuJBUY5vXu4SZHgFKGIQFOWD01hIrfhHQxV1ILMe1T02FPBTxOg3k0Ob8Co7orcSu7BOmFVfcEao5gZA6XUzVih7utBHKxANnFlejpbgtwgMTcMkiF1HOGEEIIaa7w8HBs2bIFQUFByMjIwNq1azF8+HBcu3YNmZmZEAqFsLOzM9qnvpEpmzOaJUAjWnYWIj4PkY8MxNt/3URBuRqjgpwxNNAJg/0d8E90Fo7F5jb5mH08bRGdUWw0dWR74DfUcrOVjQ9xwevTQ2mEzmaiAjhpVQuH+uF6ejGuphaZFL+BqpuiLgoRXBVik8K1WquHh50YjjIRziYa7ysT8pBbqoKLQgQvBwl0eobLqUWoi5DPxaaH+jd6OA5COpOhQ4ciJibGaNmtW7fg4+MDAPDz84OrqysOHjxoKHgXFxfjzJkzePzxx9s7XNKAMrUOA3zskVemhoedBN6OUuyJSsPp2/koV1cNX97Hy86oUJ2cV45QD4VR75m6nE3Ih6e9BNHpxShV61Ci0iK1oALDAp2w+fBtk+0/OxSHe/t7tt4JEkK6jLjsUjz2/XlklxgPP345tRCxWSVNLoDr9Qyv/xGNHRdS8dqUHvhkTj9wuRzc0++/HMUYMym415RTokJ8TtMKt411K6sEOj0Dn2fdBXAOh4NX7u6BgzeyUaGpv+BUk1TIQzdnG8NjPo+Lg8+NaoMICSGdwR9XTHv4iPlc+DjJEJNZ/xQVznIRTsTnNvoGp4+jFBIBD9dq9BAX8bmG+wx2UgHc7ekmIiGEENJckyZNMvy7d+/eCA8Ph4+PD3755RdIJM1r+NwcNKJl5+FkI8LGWX2Mlvk5yfBwhC/iskvwy/lUBChlOHgjG6UqLS4kFUBVz+iXAh633YvfAFBYrkaYtz1iskpQqtI2vEMLLBsVgBcmBFl9o/u2RAVw0qo4HA4WDvXDlE+Ow9tBikqNDoXlGqjv9Pau/gFae15GHgfwsBfjcEwu0u606K6JywEyiiqRUVQJqYCL3p529cbhbiuGVscgonc4sULPPvsshgwZgrfeeguzZ8/G2bNn8eWXX+LLL78EUPU5fOaZZ/DGG2+gW7du8PPzw2uvvQZ3d3fMmDHDssETEx52EvT2tIWLQozCcg3ic0pxJbUIeWX/DdXI4wDdnGWo1OqRkl+BzOJK2Ij5kIt4DfZ+cZaLkFFUCVeFGKXqCtzTzwMvTgwGALxxT09EpxejXK3Dqfg8xOeUIbBGsYIQQprCz0kGR5nIpOD8w6PhhqHMm0LPGP43uQfWTOtZ5zYcDgfvz+6DWZtPoaDWnGIAUFRhuqy1jO/p0mV6MbvbSbD10UG4b/MpsAbuMYT7OcBZIca8CB84NnPoe0KIdSlTabHrzhQINfXytDU7ZKWNiA+NTm+46enrJEN2gspku5rspQIo5SLEZZciKc90DsmaN1AFPC487aRNPQ1CCCGE1MHOzg7du3dHXFwc7rrrLqjVahQWFhr1As/KyjI7ZzjQvNEsARrR0loEOsvxyt09AAD3D/QGAMzafLLeoc3PJxWgm7MNYrNL2yXGalo9kFVSCQ97SYONOJuLz61qhL5wmF+bHL8r6Rp3bEi7CvWwxSt3ByNAKYOtRACpiAeJoP6e2EGucpTWU8SR3alkK8R8lGv0qH/mWyAxr7zOodEJ6ewGDhyI3377DT/99BNCQ0Oxbt06fPjhh3jwwQcN27z44ot48sknsWTJEgwcOBClpaX4+++/IRZTT4eO5t7+ngh0lmPnxTRcTC7AxeRC6FlV4drJRoiBvvY4dTvfqKDE5VT1tLSTVq0P93NAqIcCnnYSDPCxx0BfeygkfAjvDJ2+8/EITAp1xY6lEUaFpBl9PbF0ZCDemNELWx8Nh0TAw0ODfSzxMhBCrACPy8HzE4KMlnE4gI2oedPR8Hlcw/zR9Ql0lmP1VPNF8txSNVwVTf/u43IAbwfT4kiwqxyv3B2MbxcOwvp7ejf5uJ1ZmI8DflgUDhG//v+TN+/phU/m9sNAX4d2iowQ0tEVlKuRU2pawOaa6c2iEPMhE/IgEfIw0NceSrkI8fXc2HSWizDA1x5SIQ+3skqhb0RHoGfGdaOeNIQQQkgrKi0tRXx8PNzc3BAWFgaBQICDBw8a1sfExCA5ORkRERFm9685mmW16tEs69qHWDcvM7/Ha0vMLUO4X/v+7uRyACcbIZLy2makOYmAhw0ze1Pxu5V0mv6xa9asMZnPISgoCDdv3rRQRKQ+M/t74uit3Ko5Hbor8ee1uufqAACtniG/VA1fRykSa7XW7u5ig1tZVT943e0k6CERoLiy/t48TjZCDOtGc9gS6zVlyhRMmTKlzvUcDgevv/46Xn/99XaMijQXYww7L6YapnawlQhQVKGBnVSAK6mFAACRgAcOOBDwOJAK+ahQa5FSUIGUggrDcbgcILdMBb0e6O9jh/kRPpjUyx0A0MfL3uxzO8iEAAA3WwlurJvYhmdJCOkKBvk54PXpPbH292jo9AyMAct+uICdy4a26fPG59RdHPFxlCKz2HSEobp4OUiwbnoourvIkV+mRnGFBgqJAFIhD35Osi5dNBkS6IRtSwbjl/Mp+Olsisl6f6WMRhIhhJgQ8XmwkwhMRuooU2sR7CqHTMjH5dRCSIU8eDtIDSPHnUssQG93Ba5mmJ/2RyLkgQPgfD29g2pzUYjwYDg1+CSEEEJa4vnnn8fUqVPh4+OD9PR0rF69GjweD3PnzoWtrS0WLVqEFStWwMHBAQqFAk8++SQiIiIwePBgwzGCg4Oxfv163HPPPTSaJTHx8sRg5JWqcTwuF7o6Wjhq9AxnEvLR18sOfC4H55Maf03YXHoGRKUUQcDjYJCvg8lUvi0hFfLw0Zx+uCvEpdWO2dV1mgI4APTs2RMHDhwwPObzO1X4XYqjjQj/N38AnvrpEm5llUJdx3wNPd3lkAj4yCiqQEmlFkq56ZAlPG7VTUY/Jxkq1DrczCzByG5K3EDdQ0w0NEQ6IYR0JBwOBw9H+CJ65xVodMwwZK+dRACdTg+VVocKtQ7J+VUNhLo525i9qNMzoFKjxwPh3nh0mB/8lVSEIIS0v3kRvujpboulWy8gp0SFi8mFGLXxEOykQrw4MQhDAlq/keLQQCf8cCYZ+TWmj6h2KbkAXvYSowZDdZk7yBtvzAg1XH+6N3He8q6gn7c9XBRiZBercPCm8fzr40PMD2lICOnaLiYXoMzMiG8yIR9nEqpuGkoEXBRXao3m7QaAK+nFCHVXAIDRuiBXOUQ8Lq6kFTU6jjHBzri7l1vDGxJCCCGkXqmpqZg7dy7y8vKgVCoxbNgwnD59GkqlEgDwwQcfgMvlYubMmVCpVJgwYQI+//xzo2PExMSgqOi/7/EXX3wRZWVlWLJkCQoLCzFs2DAazbILc1aI8e3CQcgtVeH/jiVg85H4OreNSinEoHYegUyjYziXmA83WzEyihrf4L4unvYS/PX0cMjFzRtBj5jXqSrIfD6/znkiSMcjFvBwNa2ozgTQ18sO8TmlKKnUop+3HdIKC+FoI0KwqxxFFRqIBVxwORzcyCi5czyu4d/XM4rQ18sOUSmFZo+tpPkGCSGdzH1hnrgrxAX/3szCuj9uIL9MjcS8cgS7ynGz1pwyKQXl6HnnRmBibhnK1FU3FL0dpHjl7mBM6OnapXsoEkIsL8zHHt8vGoS3/7qJzGIV4rJLkJhXjjf33sDvTwwDl9u6OWqwvyPC/Rzwl5lRh9Q6Bne7xhXAQ9wVhuI3qZu7nQR5ZhobjO9JLdUJIcZ0eoatp5Og1pk2ildp/ltWoal7orNr6cUY6GOHAT724HI4yClVNXnORQ87CV6d3IMaiBJCCCGtYNu2bfWuF4vF+Oyzz/DZZ5/VuQ1jxr16aTRLYo6TjQiPDPXFl0fj65zqRsTnYnJvVwz0s8dnh+oulLc2BsBeKmxxAdxfKcNPiwdT8bsNdKoCeGxsLNzd3SEWixEREYH169fD29vb0mGReiwZ4Y+9VzNwPrEAUgEX3Vzk4HI54AC4nl4MlVaPAKXMMF93Qq7x3AnONXqEV6j/azGeW6o2+rFck51UgMdG+rf6uRBCSFuzlQhwTz9PzOjrgevpxbieXoTjsblIyS83FLkBIKtYhaziqnkUuznbwNtBism93TCjr0erF5UIIaS5gl0ViHxkEICqa7w/r2YYGu+0toTcMpyrZ+ixUpUGSrkIOSWmc9BWc7cVo8BMUZeYt/G+3njo6zOG7yNnuQh9aRQmQkgNjDG8ufcGjsXmml1/Lb0Qgc42iKtnju9q5Ro9rqebHwq9IYuG+eHVyT2ogShpdZs2bcKmTZuQmJgIoGrkylWrVmHSpEkAgFGjRuHIkSNG+zz22GPYvHlze4dKCCGEdFouCjFWTuqB6+lF2BWVbljezdkGr9zdA4HONvBykIIxhoM3sk06ErUlmYjX4mMMCXCEi4JGOmgLnaYAHh4eji1btiAoKAgZGRlYu3Ythg8fjmvXrkEul5tsr1KpoFL9d4OruLh5P5RIy/g6ynA+sQC+jlIUV2oN89vW5CATIj6nzMzegJudGNklKng7SJFaYDw3eIlKiwClDGmFFaisUQxfMMSXWnUTQjo1DoeDUA9bdHOxQYVah/sHemPv1QwAwO2cUgh4XAzwtUeouy087CUIUNpAyOdaOGpCCKmSkl+O7RdSsXCoL+ykQgBVU9ksHx3YZs+5PzoTuaV1F6+vp5dALubD016CVDM9wb0cJNi2JAIeNOR5o3VzkeOLhwdg9uZTUOv0uCvEhRphEUIMGGO45/OTdY7aBgBaPVBQpoarrRiZDfScKazQ1Lu+toG+9pjcyw16VjUqCRW/SVvw9PTEhg0b0K1bNzDG8O2332L69Om4dOkSevbsCQBYvHixUW9GqVRqqXAJIYSQTmvxCH/E55QaFcBfubsHRgc7Gx5zOBy8O6sPNh2ON9xHbS3dnG3A43JQXKHBYyMDcCo+D9EZVTXHIQGO0OpYs+cDP3gjG2um6sHn0b3d1tZpCuDVrScBoHfv3ggPD4ePjw9++eUXLFq0yGT79evXY+3ate0ZIjEjIsARrgoxEvPK69ymZs/u2vgcLvp72wGAYe7bmsrVOvT2tEV8dhnyytTwtJdg6ciAFsdNCCEdgYjPw4KhfgCAYd1af85cQghpCwqxAHHZJYbid3vIKlZBwONAo6tjTDQAJZVahLgpkFpQAYWYD097KVxtxUjJL8c3CwZS8bsZ+nrZ4eO5/fDUT5cwvidNVUUI+c/HB+PqLX5XyytTw0UuQrifA9Q6PW5kFBs1cDdsV1r3CB61CXlcbH4oDI40NRppY1OnTjV6/Oabb2LTpk04ffq0oQAulUppOkfSaUSlFKKvl52lwyCEELM87CTY88RQ+CttkF+qhrejaaOyUA9bvDe7D5aM8EdGUSWWbr1g9lhcDvDixGAEKm3QzcUGp2/nwddRhhB3BX67lIbXf4+G9s6Y685yEZ6fEIS7erhAo9dDxOdh/hBfk2Pml6mx7o9oBDrb4MczyUgrbHgaNgDIKKrEhr9u4tUpIY1/MUijdJoCeG12dnbo3r074uLizK5fuXIlVqxYYXhcXFwMLy+v9gqP3CEW8PBwhA827oupcxupqKo3TlphBYYEOOJEXB4AQCbk4UJyAQCAC5jtsZNRVAkuh4MP7++Lt/66iVfuDoZY0PJhJwghhBBCSPPYSgV4dXL7/nB7bUoI+njZ4fXfr0Mq5KNSU9XAUizgwUUhQoibAiHuCoS42cLbUQpbCc2t1Vomhrri+EujYS9rvwYPhJCObcNfN/HNiYRGb59VokJWiQo8DmAjFpgUwGVCHkLcFTiXWNDgsQKdbbDniaGQCjvt7S7SSel0Omzfvh1lZWWIiIgwLP/hhx+wdetWuLq6YurUqXjttdfq7QVOI1oSSykq16CoiaNtEEJIexILeOh9Z9otG1Hd13piAQ99vOzg7aCGWMA1urb0V8qwakoIRnZXGo0Q5OMoM/x7XoQvxvZwwZWUQpyMz8NTY7tBeWeqXhG37tqTg0yID+7vCwB4fGQAfjmfgpd3Xm3UuV1NMx05mbRcp/1FUFpaivj4eDz88MNm14tEIohE1Nq3I5gX4YPIE4nIraPF9tmEqqEhwv0ckJRXDg87CSaFuuJYbC4KytXILlFBD9wZBt201UxaYQWSC8qxY2kEDQFMCCGEENIBuFugN/W0Pu4YG+wMqZBHQ922M2ear4wQUkO4nwN2XkxFgNIGDjIhbER85JerIRfzkZBbhqupRYYeNTWFetricorpzb+eHraG+wYNUYj5VPwm7erq1auIiIhAZWUlbGxs8NtvvyEkpKoh4AMPPAAfHx+4u7vjypUreOmllxATE4OdO3fWeTwa0ZJYiq1UgJHdlZYOgxBCWs0/0ZlQafWI8HeESqvDxeRCrJoSglFBzg3u62EnqapT9XJr1nNzuRzMGeSNn8+n4FJyYYPb0+gbbaPT/Cp4/vnnMXXqVPj4+CA9PR2rV68Gj8fD3LlzLR0aaYBcLMDPjw3Gg1+dQWax+Xm9hDwu4nPKEOIux5XUIpSptYjNLsHqqT3hLBeiuFKL0kotUgrK4aoQw/1OApKJ+ChXazE+xBWyelr9EEIIIYQQ60fXg4QQYnlDAh1xauVY8LjmGyOVqbS4mlaEv69l4pfzKSi/My2a3nTkcwCmw5/LxXwsHRmAB8O9cTYhH5dTC/HZoXg42QjxcIRPq54LIQ0JCgpCVFQUioqKsGPHDsyfPx9HjhxBSEgIlixZYtiuV69ecHNzw9ixYxEfH4+AAPPT99GIlqS1Mcbw49lkBCptEOKuQEJuGXq629aZowkhxFpM7u2OcD9HRtACpAABAABJREFU+NwZKv1sQj7CfOzbNYZflw5BelEFziXm46MDsUgvrIRaZ3rRKxHyoNLqIOLT6MatqdPcIUpNTcXcuXORl5cHpVKJYcOG4fTp01AqqWVaZxCgtMHOZUPw5E+XcC2tCE42IijlIpSrtbiVVQp7mQC9PGxxLrEAYT72qNTo8flDYfj8UBweHOQNHo+L4d2VWDTc39KnQgghhBAr4+vri6SkJJPly5Ytw2effWaBiAghhJDOq6EbdzIRH4P9HTHY3xHP3tUdGUUVkAn5+OlsMlILymEvFWLhMD/oGcMbf9yAj6MMEQGO2HY2BVo9wyND/bB8dCAAYHxPV4zr4YIBvg7wc5TB10lW73MT0tqEQiECA6vej2FhYTh37hw++ugjfPHFFybbhoeHAwDi4uLqLIDTiJakLRyPzcX/frtmeNzN2QZzBnnjvv6esJXS1ECEEOtkI+IbDZUe7u/Y7jFwuRx42kvhaS/FPf08wRjD71cycDgmG/llapRUanEhqQAfHojFH1cy8OaMUIvEaa06TQF827Ztlg6BtJC7nQTfLxqEf29m41xCPrR6hsJyDWb294SDTAi5mI+Z/T3R19sOShsR+DwuJvZ0tXTYhBBCCLFy586dg06nMzy+du0a7rrrLsyaNcuCURFCCCHWz1YigK2kqvjy4sRgvDgx2Gj99D4eUEj44HA46O1ph6+O3sZjI4wbxnO5HIxuxFCWhLQHvV5vNId3TVFRUQAAN7fmDadKSHNwOBx8NKcfpt/Mws/nUnA+qQDlah3CfOyp+E0IIe2Mw+FgWh93TOvjDqBqlI6olEJUaHQ4fTsfNzKKqQDeijpNAZxYB6mQjym93TGlt7ulQyGEEEIIAQCTEYU2bNiAgIAAjBw50kIREUIIIQSAUXFm9gAvzB5AQ0GTjmPlypWYNGkSvL29UVJSgh9//BGHDx/Gvn37EB8fjx9//BF33303HB0dceXKFTz77LMYMWIEevfubenQSRcj5HMxMdQNE0Op8QUhhHQkHA4H/byrhmUfEuBk4WisDxXACSGEEEIIuUOtVmPr1q1YsWIFOByaF48QQgghhJiXnZ2NefPmISMjA7a2tujduzf27duHu+66CykpKThw4AA+/PBDlJWVwcvLCzNnzsSrr75q6bAJIYQQQroEKoATQgghhBByx65du1BYWIgFCxbUuY1KpTIa2rK4uLgdIiOEEEIIIR3J119/Xec6Ly8vHDlypB2jIYQQQgghNXWZAjhjDADdoCTEGlR/jqs/16T1Uc4kxHpQzmyar7/+GpMmTYK7e93Ttaxfvx5r1641WU45kxDrQHmzbdF1JiHWhXJm26KcSYh1oZzZtihnEmJdWpozu0wBvKSkBEBVC0xCiHUoKSmBra2tpcOwSpQzCbE+lDMblpSUhAMHDmDnzp31brdy5UqsWLHC8DgtLQ0hISGUMwmxMpQ32wZdZxJinShntg3KmYRYJ8qZbYNyJiHWqbk5k8O6SHMjvV6P9PR0yOXyTjWfY3FxMby8vJCSkgKFQmHpcKwOvb5try1eY8YYSkpK4O7uDi6X2yrHJMbqypnW/pmx5vOjc+ucWuPcKGc23po1a/DFF18gJSUFfH7j24l21uvMlrLmz15j0Plb7/lT3mxbtXOmNb2X6Fw6Lms6n452LpQz21Znvc7saO/TtmDt52jt5wdY5hwpZ7atzpozW6orfF5bil6jhnXE16ilObPL9ADncrnw9PS0dBjNplAoOsybzhrR69v2Wvs1plaSbauhnGntnxlrPj86t86ppedGObNher0ekZGRmD9/fpOK30Dnv85sKWv+7DUGnb91nj/lzbZTV860pvcSnUvHZU3n05HOhXJm2+ns15kd6X3aVqz9HK39/ID2P0fKmW2ns+fMluoKn9eWoteoYR3tNWpJzqRmRoQQQgghpMs7cOAAkpOTsXDhQkuHQgghhBBCCCGEEEIIaYEu0wOcEEIIIYSQuowfPx5dZGYgQgghhBBCCCGEEEKsGvUA7+BEIhFWr14NkUhk6VCsEr2+bY9eY+ti7f+f1nx+dG6dkzWfG+n8uvr7k86/a58/aT3W9F6ic+m4rOl8rOlciPXqCu9Taz9Haz8/oGucI+ka6L3cMHqNGmaNrxGHUVcXQgghhBBCCCGEEEIIIYQQQgghVoB6gBNCCCGEEEIIIYQQQgghhBBCCLEKVAAnhBBCCCGEEEIIIYQQQgghhBBiFagATgghhBBCCCGEEEIIIYQQQgghxCpQAZwQQgghhBBCCCGEEEIIIYQQQohVoAJ4B/bZZ5/B19cXYrEY4eHhOHv2rKVD6rSOHj2KqVOnwt3dHRwOB7t27TJazxjDqlWr4ObmBolEgnHjxiE2NtYywXZC69evx8CBAyGXy+Hs7IwZM2YgJibGaJvKykosX74cjo6OsLGxwcyZM5GVlWWhiElzvPnmmxgyZAikUins7OzMbpOcnIzJkydDKpXC2dkZL7zwArRabfsG2kzWknOtNd9Ze57ZtGkTevfuDYVCAYVCgYiICPz111+G9Z353Ih1unXrFqZPnw4nJycoFAoMGzYMhw4dMqy/fPky5s6dCy8vL0gkEvTo0QMfffSRBSNuXQ2dP9C5vxPrc/jwYXA4HLN/zp07Z9hu3759GDx4MORyOZRKJWbOnInExETLBU46nMa+l65cuYLhw4dDLBbDy8sL77zzjgWjrt/evXsRHh4OiUQCe3t7zJgxw2i9uXPdtm2bZYJtQEPn0plynK+vr8nrvmHDBsP6xMREs/83p0+ftmDU5jV0LkDn+swQ65OYmIhFixbBz88PEokEAQEBWL16NdRqtdF2nfl92ph7I50p35tj7fd/zGlMfiXE0hq657dgwQKT9/HEiRMtE6wFWPu9w9bQmNdo1KhRJu+jpUuXWijilqECeAf1888/Y8WKFVi9ejUuXryIPn36YMKECcjOzrZ0aJ1SWVkZ+vTpg88++8zs+nfeeQcff/wxNm/ejDNnzkAmk2HChAmorKxs50g7pyNHjmD58uU4ffo09u/fD41Gg/Hjx6OsrMywzbPPPovff/8d27dvx5EjR5Ceno57773XglGTplKr1Zg1axYef/xxs+t1Oh0mT54MtVqNkydP4ttvv8WWLVuwatWqdo606awp51prvrP2POPp6YkNGzbgwoULOH/+PMaMGYPp06fj+vXrADr3uRHrNGXKFGi1Wvz777+4cOEC+vTpgylTpiAzMxMAcOHCBTg7O2Pr1q24fv06/ve//2HlypX49NNPLRx562jo/Dvzd2JDhgwZgoyMDKM/jz76KPz8/DBgwAAAQEJCAqZPn44xY8YgKioK+/btQ25uLuUtYqQx76Xi4mKMHz8ePj4+uHDhAjZu3Ig1a9bgyy+/tHD0pn799Vc8/PDDeOSRR3D58mWcOHECDzzwgMl2kZGRRudcu7DcETR0Lp0xx73++utGr/uTTz5pss2BAweMtgkLC7NApA2r71w602eGWKebN29Cr9fjiy++wPXr1/HBBx9g8+bNeOWVVwzbdPb3aUP3Rqp1hnxfF2u+/1OfxnxXEGJJDd3zA4CJEycavY9/+umndozQsqz93mFraMxrBACLFy82eh91poZqRhjpkAYNGsSWL19ueKzT6Zi7uztbv369BaOyDgDYb7/9Znis1+uZq6sr27hxo2FZYWEhE4lE7KeffrJAhJ1fdnY2A8COHDnCGKt6PQUCAdu+fbthmxs3bjAA7NSpU5YKkzRTZGQks7W1NVn+559/Mi6XyzIzMw3LNm3axBQKBVOpVO0YYdNZa8615nzXFfKMvb09+7//+z+rPDfSueXk5DAA7OjRo4ZlxcXFDADbv39/nfstW7aMjR49uj1CbFONOf/O/J3YVGq1mimVSvb6668blm3fvp3x+Xym0+kMy/bs2cM4HA5Tq9WWCJN0AubeS59//jmzt7c3+ty89NJLLCgoyBIh1kmj0TAPDw/2f//3f/VuV/varCNqzLl0thzn4+PDPvjggzrXJyQkMADs0qVL7RZTczV0Lp3lM0O6lnfeeYf5+fkZHlvL+7SueyOMdY583xjWeP+nLg3lV0I6GnN5Zv78+Wz69OkWiacj6gr3Dluq9mvEGGMjR45kTz/9tOWCakXUA7wDUqvVuHDhAsaNG2dYxuVyMW7cOJw6dcqCkVmnhIQEZGZmGr3etra2CA8Pp9e7mYqKigAADg4OAKp6gWk0GqPXODg4GN7e3vQaW5FTp06hV69ecHFxMSybMGECiouLDb1YO6KulHOtKd9Zc57R6XTYtm0bysrKEBERYVXnRqyDo6MjgoKC8N1336GsrAxarRZffPEFnJ2d6+0tV1RUZPjMdmaNOf/O+p3YHHv27EFeXh4eeeQRw7KwsDBwuVxERkZCp9OhqKgI33//PcaNGweBQGDBaElHZu69dOrUKYwYMQJCodCwbMKECYiJiUFBQYElwjTr4sWLSEtLA5fLRb9+/eDm5oZJkybh2rVrJtsuX74cTk5OGDRoEL755hswxiwQcd0acy6dMcdt2LABjo6O6NevHzZu3Gh2mN5p06bB2dkZw4YNw549eywQZePUdy6d5TNDupba14Bd5X3a0fN9S3TG74HGaMx3BSEd3eHDh+Hs7IygoCA8/vjjyMvLs3RIFmPN9w5bS+3XqNoPP/wAJycnhIaGYuXKlSgvL7dEeC3Gt3QAxFRubi50Op3RRQQAuLi44ObNmxaKynpVD1Vp7vWuXkcaT6/X45lnnsHQoUMRGhoKoOo1FgqFJvMG0WtsXTIzM81+jqrXdVRdKedaS76z1jxz9epVREREoLKyEjY2Nvjtt98QEhKCqKioTn9uxLpwOBwcOHAAM2bMgFwuB5fLhbOzM/7++2/Y29ub3efkyZP4+eefsXfv3naOtvU15vw763dic3z99deYMGECPD09Dcv8/Pzwzz//YPbs2Xjssceg0+kQERGBP//804KRko7O3HspMzMTfn5+RtvV/CzVlXPa2+3btwEAa9aswfvvvw9fX1+89957GDVqFG7dumW4ofT6669jzJgxkEql+Oeff7Bs2TKUlpbiqaeesmT4RhpzLp0txz311FPo378/HBwccPLkSaxcuRIZGRl4//33AQA2NjZ47733MHToUHC5XPz666+YMWMGdu3ahWnTplk4emMNnUtn+cyQriMuLg6ffPIJ3n33XcOyrvA+7Qz5viU62/dAYzSUXwnpDCZOnIh7770Xfn5+iI+PxyuvvIJJkybh1KlT4PF4lg6vXVnrvcPWZO41AoAHHngAPj4+cHd3x5UrV/DSSy8hJiYGO3futGC0zUM9wAkhrWr58uW4du0atm3bZulQSCO8/PLL4HA49f6xtiIw6fysNc8EBQUhKioKZ86cweOPP4758+cjOjra0mGRLqSx3wmMMSxfvhzOzs44duwYzp49ixkzZmDq1KnIyMgwOe61a9cwffp0rF69GuPHj7fAmTVOW51/Z9Gca4LU1FTs27cPixYtMlqemZmJxYsXY/78+Th37hyOHDkCoVCI++67z6p6PxHzWvO9ZGmNPRe9Xg8A+N///oeZM2ciLCwMkZGR4HA42L59u+F4r732GoYOHYp+/frhpZdewosvvoiNGzd2ynOxtKa8z1asWIFRo0ahd+/eWLp0Kd577z188sknUKlUAAAnJyesWLEC4eHhGDhwIDZs2ICHHnqow/3fNOZcCGkrzcntaWlpmDhxImbNmoXFixdbKPLGae17I5bM93Xpivd/KL+SrmbOnDmYNm0aevXqhRkzZuCPP/7AuXPncPjwYUuH1u6s9d5ha6rrNVqyZAkmTJiAXr164cEHH8R3332H3377DfHx8RaKtPmoB3gH5OTkBB6Ph6ysLKPlWVlZcHV1tVBU1qv6Nc3KyoKbm5theVZWFvr27WuhqDqnJ554An/88QeOHj1q1HPD1dUVarUahYWFRi2s6D1tec899xwWLFhQ7zb+/v6NOparqyvOnj1rtKw6j3Xk/+eulHOtId9Zc54RCoUIDAwEUDV88Llz5/DRRx/h/vvv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w87Ojhq/E9JGOnsObokpU6bg+++/h62tLUJCQnDq1CkcOHAAjo6OHTZmQkjn0Jjc2hJvvfUWpk+fjqFDh+KRRx5BQUEBPv30U4SGhhpdW06ePBnvv/8+Jk6ciAceeADZ2dn47LPPEBgYaPS7ulpoaCgmTJiAp556CiKRyNCwfO3atYZt3njjDezfvx/Dhg3DsmXLwOfz8cUXX0ClUuGdd95pMHaFQoFNmzbh4YcfRv/+/TFnzhwolUokJydj7969GDp0KD799NMWv0akFTBCGrB69WoGgEVHR7P77ruPyeVyZm9vz5544glWUVFhtG15eTlbtGgRs7W1ZXK5nM2ePZtlZ2czAGz16tVG22ZlZbHly5czLy8vJhAImKurKxs7diz78ssvDdscOnSIAWDbt283G9tXX33F/P39GY/HYwDYoUOHDOs+/fRTFhwczAQCAXNxcWGPP/44KygoaPT55uTk1Lmutm+++Yb169ePiUQiZm9vz0aOHMn2799vtE1z4yGEkPry0tatW5m/vz8TCoWsb9++bN++fWz+/PnMx8fHsM2OHTvY+PHjmbOzMxMKhczb25s99thjLCMjw7DNG2+8wQYNGsTs7OyYRCJhwcHB7M0332Rqtdokjpr27NnDevfuzcRiMfP19WVvv/02++abbxgAlpCQ0OqvBSGEVKsvN16/fp0BYD169DBa/sYbbzAA7LXXXjPZp7H5zMfHh02ePNlk/5EjR7KRI0caLbty5QobOXIkE4vFzMPDg61bt459/fXXJsc8ceIEGzx4MJNIJMzd3Z29+OKLbN++fSbXt4SQjkmlUrEXXniB9enTh8nlciaTyVifPn3Y559/brRddHQ0GzduHLOxsWFOTk5s8eLF7PLlywwAi4yMNGxn7poLAFu+fLnJc/v4+LD58+cbLVu3bh3z8PBgXC63wWuykSNHsp49e7Lz58+ziIgIJhaLmY+PD/v000+NttPr9eytt95iPj4+TCQSsX79+rE//vjD5LozISGBAWAbN240+3y7d+9mISEhjM/nG513dRy11T4+Y4yp1Wr29ttvs549exp+g4eFhbG1a9eyoqKiel+bkpIStnLlShYYGMiEQiFzcnJiQ4YMYe+++67hureuc6jr/kRkZCQDwM6dO2cS/y+//MIAsCVLlph9PQghLWcNOdjccc1db9aOo6CggD3yyCPM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nZ2N//znP0hPT8fOnTshFAqdy2ZmZuKmm27CggULMHfuXHz88ceYN28e0tLS0KtXr2b389tvv0VtbS3uu+8+BAYGYt++fXjrrbeQn5+Pb7/91hVdSQghjbTlGFtZWYnrr78et9xyC+bMmYNvvvkG9913H0QiEebPnw8A0Ov1+PDDDzFnzhzcc889MBgM+OijjzBx4kTs27cP/fr1a7Utt9xyC+Lj47Fq1SocOnQIH374IUJCQvDCCy+4swsIIaTFY+G1114Lh8OBHTt2YOrUqQDqBy7yeDxs377duY709HQYjUaMHDnS+VxbzyGfeeYZPPfcc7j++utx/fXX49ChQ5gwYQIsFkuDdtbW1mLUqFEoKCjAokWLEBMTg127dmHZsmUoKirC66+/3mD5L7/8EgaDAYsWLQLHcXjxxRcxc+ZMnDt3rsH5KyGk63HXce9yM2fOxJkzZ/DVV1/htddeQ1BQEAAgODgYixYtwvjx4xssv2HDBnzxxRcICQkBUD+IaNq0adixYwcWLlyInj174tixY3jttddw5swZrF+/vsH7//rrL3zzzTdYvHgxgoKCEBcX12S79u/fj127duHWW29FVFQUcnJy8M4772D06NE4efIkZDJZg+UffPBBaDQarFixAjk5OXj99dexePFifP31185l2nocJ4SQ1rR0fL7jjjvwz3/+E19//TUWL17sfI/FYsH//vc/zJo1q0Hmi4yMDMyZMweLFi3CPffcg+Tk5Ca3ee7cOaxfvx4333wz4uPjUVJSgvfeew+jRo3CyZMnERER4fb9JoR0PS2dK77zzjvo1asXpk2bBoFAgJ9++gn3338/HA4HHnjggQbraUs85rPPPmu0/aeffhqlpaVQKBQAgI0bN+LcuXO46667EBYWhhMnTuD999/HiRMnsGfPHnAc1+D9V3Mfk463nRwjxMXUajV74IEHmn197ty5LDY21vl4/fr1DAB77rnnGix30003MY7jWGZmJmOMsYyMDAaAvfXWWw2Wu//++5lCoWC1tbWMMca2b9/OALAvvviiwXIbNmxo9HxsbCwDwLZt2+Z8rrS0lInFYvbII484n9u8eTMDwDZv3ux87uL2Lrdq1SrGcRzLzc1tdv8JIaQjWjvGjho1igFgr7zyivM5s9nM+vXrx0JCQpjFYmGMMWaz2ZjZbG7w3srKShYaGsrmz5/f4HkAbMWKFc7HK1asYAAaLXfjjTeywMDAq901Qghps5aOhXa7nalUKvb4448zxhhzOBwsMDCQ/T979x0feV0nfvz1/X6n95n0nmy29750RZoInh1UFNE7f3icNMWC3tkVy53lrOApoqIICHaKKJ1ld9nea3pPpvf2/f0xyWwmM0km2WTr5/l43OPcyZTvrO4nn+/n3d71rnepiqKogUBAVVVV/fa3v63Ksqx6PB5VVYvfQ/b396s6nU695ppr1HQ6nX3eZz7zGRVQP/CBD2Qf+/KXv6yazWb10KFDOe/56U9/WlUURW1vb1dVVVVbWlpUQC0pKVHdbnf2eX/84x9VQP3zn/88jb8lQRDOJrOx7qlq/j7vW9/6lgqoLS0tE17P4cOHVbvdrl5xxRVqMplUVVVVf/WrX6myLKsvvvhiznN/8pOfqID68ssv53yuLMvq3r1789577DUVuvfeuHGjCqi//OUvs4/df//9KqBefvnlOevznXfeqSqKonq9XlVVp7aOC4IgTGaye/Tzzz9f3bBhQ85jjz32WN4548gZ5ZNPPpn3Hg0NDTlrUzQaVVOpVM5zWlpaVL1er37pS1+a3hcRBEEownh7xUL7tauuukqdM2dOzmPFxmPG+uY3v5m39yv0mb/97W/z3n8q55hivT27iBbowoxzOBxs2rSJ7u7uop7/t7/9DUVRuO2223Ie//jHP46qqjzxxBMAzJ8/n5UrV+ZkbadSKR599FHe/OY3YzQagUxltt1u54orrmBwcDD7f2vWrMFiseS19128eDEXX3xx9s9lZWUsWLCAY8eOTXjdI58HmRbug4ODXHDBBaiqyvbt24v67oIgCFNVzBqr0Wi4+eabs3/W6XTcfPPN9Pf3s3XrVgAURUGn0wGZah23200ymWTt2rUTjqwY7SMf+UjOny+++GKGhobw+/1T/VqCIAhTMtFaKMsyF1xwAS+88AIA+/fvZ2hoiE9/+tOoqsrGjRuBTHXk0qVLcTgcQPF7yGeeeYZ4PM6tt96ak1F+xx135F3LI488wsUXX4zT6cx5z8svv5xUKpW9xhHXX389Tqcz++eRPepk+1JBEM5+s7HuTVcoFOJtb3sbTqeT3/72tyiKAmTWvEWLFrFw4cKcNe8Nb3gDQN69+Ote9zoWL1486eeNvvdOJBIMDQ0xd+5cHA5HwX3r//t//y9nfb744otJpVK0tbUBU1vHBUEQJjPZPfqNN97Ipk2bOHr0aPaxBx98kLq6Ol73utflPLepqYmrrrpq0s/U6/XIcuZYP5VKMTQ0hMViYcGCBUXfzwuCIMyk0fs1n8/H4OAgr3vd6zh27Bg+ny/nuVONxzz77LPcfffd3Hrrrbz//e8v+JnRaJTBwUHOO+88gIJr4XTOMcV6e2YTAXBhxn3zm99kz5491NXVsX79er7whS9MeGjX1tZGdXU1Vqs15/FFixZlfz7i+uuv5+WXX6arqwvIzObu7+/n+uuvzz7n8OHD+Hw+ysvLKSsry/m/YDBIf39/zufU19fnXZPT6cyb9ThWe3s7N910Ey6XC4vFQllZWXbjOnZRFwRBmCnFrLHV1dWYzeacx+bPnw+QMyvxgQceYPny5RgMBkpKSigrK+Ovf/1r0WvY2PVzJGgz2fopCIJwoiZbCy+++GK2bt1KJBLhxRdfpKqqitWrV7NixYpsO+CXXnop56a72D3kyN503rx5OddUVlaWE7weec8nn3wy7/1G2ghPti8V66ogCCNmY92brg9/+MMcPXqUxx9/nJKSkuzjhw8fZu/evXlr3sg+dOya19TUVNTnRSIRPve5z1FXV4der6e0tJSysjK8Xm/Bfetka+lU1nFBEITJTLY+X3/99ej1eh588EEgc2b4l7/8hRtuuCGvPW+x62I6neY73/kO8+bNy1kXd+3aJc4kBUE4JV5++WUuv/xyzGYzDoeDsrIyPvOZzwD5sZKpxGM6Ozu5/vrrufDCC/n2t7+d8zO3283tt99ORUUFRqORsrKy7Do6nT1iIWK9PbOJGeDCjLvuuuu4+OKLefzxx3n66af51re+xTe+8Q0ee+wxrr766hN67+uvv567776bRx55hDvuuIOHH34Yu93OG9/4xuxz0uk05eXl2Y3lWGVlZTl/HslWH0tV1XGvI5VKccUVV+B2u/nUpz7FwoULMZvNdHV1cdNNN5FOp6fx7QRBECY3U2vsr3/9a2666Sbe+ta38olPfILy8nIUReGee+7JyUyfyHTWT0EQhJkw2Vp40UUXkUgk2LhxIy+++GI24HPxxRfz4osvcuDAAQYGBnICQVPdQxYjnU5zxRVX8MlPfrLgz0eCQiPEuioIwnhmY92bju9973v89re/5de//jUrV67M+Vk6nWbZsmV5h5Mj6urqcv48umpnIrfeeiv3338/d9xxB+effz52ux1Jknj3u99d8N5brKWCIJxMk63PTqeTa6+9lgcffJDPfe5zPProo8RiMd73vvflvVex6+LXvvY1/uu//osPfehDfPnLX8blciHLMnfccYc4kxQE4aQ7evQol112GQsXLuTb3/42dXV16HQ6/va3v/Gd73wnb10qdq8Wj8d55zvfiV6v5+GHH0ajyQ1nXnfddbzyyit84hOfYOXKlVgsFtLpNG984xtnbI8o1tszmwiAC7OiqqqKW265hVtuuYX+/n5Wr17NV7/61YLBmYaGBp555hkCgUBOFfiBAweyPx/R1NTE+vXr+d3vfsdHP/pRHnvsMd761rei1+uzz2lubuaZZ57hwgsvLHrjOFW7d+/m0KFDPPDAA9x4443Zx//+97/PyucJgiCMNtka293dTSgUyqkCP3ToEACNjY0APProo8yZM4fHHnssJ+v885///Mn7IoIgCCdgorVw/fr16HQ6XnzxRV588UU+8YlPAHDJJZfw05/+lH/84x/ZP48odg85sjc9fPgwc+bMyT4+MDCQlzne3NxMMBjMVnwLgiCciJle9woZW4042osvvshdd93FHXfcwQ033JD38+bmZnbu3Mlll1024ftM1aOPPsoHPvAB/ud//if7WDQaxev1Tuv9prKOC4IgFGOye/Qbb7yRt7zlLWzZsoUHH3yQVatWsWTJkml/3qOPPsqll17Kz372s5zHvV4vpaWlJ/RdBEEQJlJoj/fnP/+ZWCzGn/70p5wq67Hjb6bqtttuY8eOHbzwwgtUVFTk/Mzj8fCPf/yDL37xi3zuc5/LPn748OET+syxxHp7ZhMt0IUZlUql8lo/lJeXU11dTSwWK/iaN73pTaRSKX7wgx/kPP6d73wHSZLygubXX389r776Kj//+c8ZHBzMaX8OmcyfVCrFl7/85bzPSiaT075JHm0kW2h0dpCqqnzve9874fcWBEEYT7FrbDKZ5N57783+OR6Pc++991JWVsaaNWuAwuvYpk2bsjMiBUEQTlfFrIUGg4F169bx29/+lvb29pxKyEgkwv/+7//S3NxMVVVV9j2K3UNefvnlaLVavv/97+esod/97nfzXnfdddexceNGnnrqqbyfeb1eksnklL+/IAjnntla9woZSaAce9/c09PDddddx0UXXcS3vvWtgq+97rrr6Orq4qc//WnezyKRCKFQqKjvO5aiKHmVOd///vdJpVLTer+prOOCIAgTKfYe/eqrr6a0tJRvfOMbPP/88wWrv6ei0Lr4yCOPZEdGCoIgzJZCe8VCZ4w+n4/7779/2p9z//33c++99/LDH/6Q9evX5/280GfCzO/nxHp7ZhMV4MKMCgQC1NbW8s53vpMVK1ZgsVh45pln2LJlS0629mhvfvObufTSS/nsZz9La2srK1as4Omnn+aPf/wjd9xxB83NzTnPv+6667jrrru46667cLlceRU1r3vd67j55pu555572LFjB1deeSVarZbDhw/zyCOP8L3vfY93vvOdJ/Q9Fy5cSHNzM3fddRddXV3YbDZ+//vfi2xxQRBmVbFrbHV1Nd/4xjdobW1l/vz5/O53v2PHjh3cd999aLVaAK699loee+wx3va2t3HNNdfQ0tLCT37yExYvXkwwGDxVX1EQBGFSxa6FF198MV//+tex2+0sW7YMyBxILliwgIMHD3LTTTflvG+xe8iysjLuuusu7rnnHq699lre9KY3sX37dp544om8DPBPfOIT/OlPf+Laa6/lpptuYs2aNYRCIXbv3s2jjz5Ka2uryBoXBGFSs7XuFTKSLPnZz36Wd7/73Wi1Wt785jdz2223MTAwwCc/+UkeeuihnNcsX76c5cuX8/73v5+HH36Yj3zkIzz77LNceOGFpFIpDhw4wMMPP8xTTz3F2rVrp/z9r732Wn71q19ht9tZvHgxGzdu5JlnnsmZPz4VU1nHBUEQJlLs+qzVann3u9/ND37wAxRF4T3vec8Jfe61117Ll770JT74wQ9ywQUXsHv3bh588MGcrhaCIAizodBe8ZJLLkGn0/HmN7+Zm2++mWAwyE9/+lPKy8vp6emZ8mcMDg5yyy23sHjxYvR6Pb/+9a9zfv62t70Nm83GJZdcwje/+U0SiQQ1NTU8/fTTtLS0zMj3HCHW2zObCIALM8pkMnHLLbfw9NNP89hjj5FOp5k7dy4/+tGP+Pd///eCr5FlmT/96U987nOf43e/+x33338/jY2NfOtb3+LjH/943vNra2u54IILePnll/m3f/u3bDBntJ/85CesWbOGe++9l8985jNoNBoaGxt53/vex4UXXnjC31Or1fLnP/+Z2267jXvuuQeDwcDb3vY2PvrRj7JixYoTfn9BEIRCil1j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IWRUoAA4IYQQQgghhBBCCCGEEEIIIYSQUWHMBMB/+eUXXHTRRdDpdGAYBp9//nnA42vWrEFOTg6kUinUajUWLFiAHTt2DE1jI6C399vV7373OzAMgw0bNgxa+yKtt/d74403gmGYgH+LFi0amsaeoXB+t0eOHMHFF18MpVIJqVSKadOmobq6evAbS8gYsm7dOsyaNQsSiQQqlSroPtXV1ViyZAkkEgliYmJw//33w+12D25DR7HXXnsNqampEIlEKCoqws6dO4e6SYQENRY+q72NV1iWxeOPP474+HiIxWIsWLAAx48fH5rGRsj69esxbdo0yOVyxMTE4NJLL0VpaWnAPna7HXfeeSeioqIgk8lwxRVXoKmpaYhaHBmvv/468vPzoVAooFAoMHPmTHzzzTf+x0fjeyYjQ11dHa677jpERUVBLBYjLy8Pu3fvHupmjWgejwePPfYY0tLSIBaLkZGRgaeffhosyw5100aUsfgdScam3sYI8+bN63av7ne/+90QtnhkefbZZ8EwDO69917/Nhp3nZlg55Q+pyPDWL0WiwS6nosc6pfDt2bNmm59a05Ojv/xSJ23MRMAt1gsmDRpEl577bWgj48bNw6vvvoqDhw4gF9//RWpqak4//zz0dLSMsgtjYze3m+nzz77DNu3b4dOpxuklg2McN7vokWL0NDQ4P/3j3/8YxBbGDm9vdfy8nLMmTMHOTk52Lx5M0pKSvDYY49BJBINcksJGVucTieWLl2KO+64I+jjHo8HS5YsgdPpxNatW/Hee+/h3XffxeOPPz7ILR2dPvroI6xatQpPPPEE9u7di0mTJmHhwoVobm4e6qYREmCsfFZ7G688//zzePnll/HGG29gx44dkEqlWLhwIex2+yC3NHK2bNmCO++8E9u3b8cPP/wAl8uF888/HxaLxb/PypUr8eWXX+Ljjz/Gli1bUF9fj8svv3wIW33mEhMT8eyzz2LPnj3YvXs3zj33XFxyySU4dOgQgNH5nsnw197ejtmzZ4PP5+Obb77B4cOH8eKLL0KtVg9100a05557Dq+//jpeffVVHDlyBM899xyef/55vPLKK0PdtBFlLH5HkrGptzECANx6660B9+qef/75IWzxyLFr1y68+eabyM/PD9hO467+C3VOAfqcjgRj9VosEuh6LjKoX+673NzcgL71119/9T8WsfPG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n//8Z1x88cVYtmwZnE4nPvzwQyxduhRfffUVlixZErBvOO07cOAAzj//fERHR2PNmjVwu9144oknEBsbe6anjxAyivTWHwZz9913Iy4uDk8++SS2b9+Ot956CyqVClu3bkVycjKeeeYZ/Oc//8Ef//hHTJw4ETfccAMAX4Dl4osvxqZNm3DLLbdg8uTJ+O6773D//fejrq4OL730UsDr/Pzzz/jnP/+Ju+66C1qtNuigFQCampowY8YM/4A1Ojoa33zzDW655RYYjUbce++9AIC3334b99xzD37zm99gxYoVsNvtKCkpwY4dO3Dttdf2ei7WrVuHxx57DFdeeSV++9vfoqWlBa+88grmzp2Lffv2QaVSncFvghAy1t1444345z//ieuvvx4zZszAli1buo0Bgb6PQe+++26o1Wo88cQTqKysxIYNG3DXXXfho48+8u/z+OOPY+3atbjgggtwwQUXYO/evTj//PPhdDoDjnXixAl8/vnnWLp0KdLS0tDU1IQ333wTZ599Ng4fPgydTjcwJ4cQQobAo48+imeeeQZvvvkmbr311qFuDiGERERPfdvTTz8NgUCA++67Dw6HAwKBAIcPHz6j8Z/H48HChQtRVFSEF154AT/++CNefPFFZGRk4I477vDvd/vtt+Pdd9/FTTfdhHvuuQcVFRV49dVXsW/fPvzvf/8bNtnpCCGjU7B7kH0pj/j111/jqquuQl5eHtavX4/29nbccsstSEhI6HebfvjhB5w4cQI33XQT4uLicOjQIbz11ls4dOgQtm/fDoZhMG/ePCQlJeGDDz7AZZddFvD8Dz74ABkZGZg5c2a/20AGCUtIhP3xj39kAbAVFRUB2wGwAoGALSsr82/bv38/C4B95ZVX/NusVmu3Y27bto0FwP7973/3b9u0aRMLgN20aZN/2/Lly9mUlJSA555+PKfTyU6cOJE999xz+9W+Sy+9lBWJRGxVVZV/2+HDh1kul8vSnxQhpKtQ/WFKSgq7fPly/89/+9vfWADswoULWa/X698+c+ZMlmEY9ne/+51/m9vtZhMTE9mzzz7bv+3zzz9nAbBr164NeJ3f/OY3LMMwAf0aAJbD4bCHDh3q1l4A7BNPPOH/+ZZbbmHj4+PZ1tbWgP2uvvpqVqlU+vvXSy65hM3Nze3XuaisrGS5XC67bt26gO0HDhxgeTxet+2E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lZXxv//7v5x22mmcc845vPvuu72qFwmCIBwNxmtuG4/1X2lpKatXr2bZsmWD2ggvCIIwGEOZJ/t7P9DrHIe/v/ueuq/798NfG+w5Ozo6ePfdd1m+fDm//OUvk6/3Fe8BuOyyy7j55pt5+umnCQQCqNVqvvnNb/bzyYSjjegBLow6o9EI9J5sBkupVPbKnPnTn/40rB1ASqUSSZJS3ltVVcXLL7887LGdffbZvPzyy9TU1CRf3717N2+99dawzikIwrFrpPPhYJ133nnEYrFeOxDvu+8+JEni3HPPHfI5lUoll1xyCS+88AI7duzo9f3W1tbkn9vb21O+p9FomD59OrIsE4lEgP5/FhdffDFKpZLly5f3mvtlWe51bkEQhG6lpaW43W62bduWfK2xsZGXXnop+fXZZ58NwMMPP5zy3j/96U+9zjeaa1CAM888E7VazZ/+9KeU895///2Duvbzzz9PfX39sK4tCIIwHgYzD/c0e/ZsXn/9dXbv3s2FF15IIBAYr6EKgiAM2njNbeOx/rv00kuJxWLcfffdvb4XjUbH/FmFIAjHpqHOk4crKipCqVTywQcfpLx++H17bm4uM2fOTLab6LZ27Vq2b98+rHN2V884fP7t6z4dID09nXPPPZcnn3ySp556inPOOUdsUv8CERngwqibP38+AHfddReXXXYZarWaCy+8cNDvv+CCC/jnP/+J1Wpl+vTpfPrpp6xevXpY/Q+66/TsAAEAAElEQVTPP/98/vjHP3LOOedw+eWX09LSwkMPPURZWVnKBD0Uy5cv58033+Tkk0/mhz/8IdFolD/96U/MmDFj2OcUBOHYNNL5cLAuvPBCTj/9dO666y6qqqqYM2cOb7/9Nq+88go33XQTpaWlwzrvPffcw/vvv8/ixYv5/ve/z/Tp03E6nXz++eesXr0ap9MJwFlnnUV2djbLli0jKyuL3bt38+CDD3L++ecnd7/397MoLS3lt7/9LXfccQdVVVVcdNFFmM1mKisreemll7juuuu49dZbR+cHJQjCMeWyyy7jtttu42tf+xo/+tGP8Pv9PPLII0yePDnZC2z+/Plccskl3H///bS3t7NkyRLWrl3Lvn37gNRKHaO5BoVEJY1bb72VFStWcMEFF3DeeeexefNm3njjjV43zBdccAG/+c1vuOaaazjxxBPZvn07Tz31VErmuCAI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QfEWCqsaiLPpufCoDM6emEpKC3VgN+2r5sLnVuCuD3RXs4UQol9zmHScNjZ8D/vh88Z36FzDk2xRj688dhCzRyZi1mtIsBtbOUr0JxIAF/2CUaeJBL+F6E+eeOIJZsyYgdVqZdmyZdxyyy088MADUStvRowYwZIlSzj77LOpra1l8eLFzJs3j6SkJHbt2sWtt97KkCFDmDNnTs9diBBCCNEOg+KtDIq39nQzhBiwnE4nw4YNY+fOnZx88sn4fD6qqqqixqLFxcUt1gxv1FdL7fRHBwe/WyPBbyGO3OrVq3n22WcZN25cs21XXXUV9957b+Sx2SzZFXqLK2Zmc+7kNDbnV/PpliLW762ioKqBv10wkcw4M7UNgRYD343GpjkYmWxnXJqs/hZCiL4gK87S000Q3UgC4EII0YutWrWKu+++m9raWkaMGMGzzz7LJZdcErXP9u3bqa6uBkCj0bBx40aWLl1KVVUVKSkpnHLKKdx3332S4lwIIYQQQhyR2tpadu3axSWXXMLkyZPR6XQsX76cefPmAeFxaF5eHtOnT2/1HFJqRwjR39XW1nLxxRfz97//nT/96U/NtpvN5kNOFBI9y2HSccyQOI4ZEtdsW1syEL16xTRMek1XNE0IIYQQHSABcCGE6MVeeeWVw+6jKAdSdZlMJj799NOubJIQQgghhOinbr75Zs4880wyMzMpKCjg7rvvRqPRMH/+fBwOB1dccQULFy4kJiYGu93O73//e6ZPn87RRx/d000XQogec80113D66acze/bsFgPgr732Gv/4xz9ISkrizDPP5M4775RV4P2IBL+FEEKI3mnABMAbA0Rut7uHWyKE6KjG3+OmgV/RuaTPFKL/kD6z60mfKUT/MpD7zX379jF//nzKy8uJj49n5syZ/PDDD8THxwPw17/+FbVazbx58/B6vcyZM4ennnrqiF5D+kwh+peB3GcCvPnmm6xdu5bVq1e3uP2iiy4iMzOTlJQUNm7cyG233cb27dt57733Wtzf6/Xi9XojjxuzvUmfKUT/MND7zK4m40wh+peO9pkDJgBeU1MDILXGhOhHampqcDikzlJXkD5TiP5H+syuI32mEP3TQOw333zzzUNuNxqNPPnkkzz55JPtfg3pM4XonwZin7l3716uv/56li1bhtFobHGfq6++OvLvsWPHkpyczKxZs9i1axeD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/TbHH3981La33nqL0aNHM2bMGLZs2cIxxxxDamoqt99+OxaLhbfffpu5c+fyz3/+k7PPPjvq2N///ve4XC7uvvtucnNzefTRR7n22mt56623Ivu8+uqrXHbZZcyZM4cHH3yQuro6nn76aWbOnMm6devIyspi5MiRvPrqq1HnrqqqYuHChSQkJBzx9dbV1XH88ceTn5/Pb37zGzIyMvj+++9ZtGgRhYWFPProo60eu3r1ar7//nsuvPBC0tLSyM3N5emnn+aEE05g69atmM3mI26PEKL/i4+Pb9aP+f1+brzxxsgq63feeYe6ujp+97vfERsby6pVq3j88cfZt28f77zzTtSxwWCQ0047jeOOO46HHnqI1157jWuvvRaLxcIf//hHLr74Ys455xyeeeYZLr30UqZPn052dnbUOa699lqcTif33HMP27dv5+mnn2bPnj2RSUctkXGqEEIIIYQQQgghROeSALjo85YtW4bP5+Pjjz8mLi6uxX1cLhe5ublRKSevuuoqRowYweOPP84LL7zQXc0VQgwQJpOJM888k3fffZfHHnsMjUYDQFFREV9//XVkVfX1119PRkYGq1evxmAwAPB///d/zJw5k9tuu61ZADw2NpbPPvssEkgJhUI89thjVFdX43A4qK2t5brrruPKK6/kueeeixx32WWXMXz4cO6//36ee+45EhMT+dWvfhXZrigKZ511FgaDgZdffvmIr/eRRx5h165drFu3jqFDhwLwm9/8hpSUFB5++GFuuukm0tPTWzz29NNP59xzz4167swzz2T69On885//5JJLLjni9ggh+j+LxRLVjwFcc8011NbWsmzZMgAefPBBTCZTZPvVV1/NkCFD+MMf/kBeXh4ZGRmRbQ0NDfzqV79i0aJFAFx00UWkpKTw61//mjfeeIMLLrgAgJNPPpkRI0awdOnSZhky9Ho9y5cvR6fTAZCZmcmtt97Kf/7zH84666wWr0PGqUIIIYQQQgghhBCdS1Kgiz7P6XQC8K9//avVNLsajSZyUzEUClFRUUEgEGDKlCmsXbu2u5oqhBhgLrjgAkpKSvjqq68iz7377ruEQiEuuOACKioq+OKLLzj//POpqamhrKyMsrIyysvLmTNnDjt27CA/Pz/qnFdffXXUKsJjjz2WYDDInj17gPCkoKqqKubPnx85X1lZGRqNhmnTprWaUve+++7jww8/5OWXX2bUqFFHfK3vvPMOxx57LC6XK+p1Z8+eTTAY5Jtvvmn12KbBKb/fT3l5OUOGDMHpdEofLYRos1deeYWnnnqKhx56iBNPPBGI7l88Hg9lZWXMmDEDRVFYt25ds3NceeWVkX87nU6GDx+OxWLh/PPPjzw/fPhwnE4nu3fvbnb81VdfHQl+A/zud79Dq9Xy3//+t9V2yzhVCCGEEEIIIYQQonPJCnDR511wwQU8//zzXHnlldx+++3MmjWLc845h3PPPRe1+sAcj6VLl/KXv/yFn376Cb/fH3n+4NSVQgjRWU499VQcDgdvvfUWs2bNAsLpzydMmMCwYcNYtWoViqJw5513cuedd7Z4jpKSElJTUyOPm65WhPDKQSBSY3bHjh0AnHTSSS2ez263N3vuk08+YfHixSxatIh58+Yd4VUSed2NGzcSHx/f4vaSkpJWj62vr2fJkiW89NJL5OfnoyhKZFt1dXW72iOEGFjWr1/Pb3/7W+bPn8/ChQsjz+fl5XHXXXfx73//u1kt7oP7F6PR2KwPczgcpKWlNUtf7nA4mp0PiGTAaGS1WklOTiY3N/eQ7ZdxqhBCCCGEEEIIIUTnkQC46NVaq5UYDAYj/zaZTHzzzTd8+eWXfPTRR3zyySe89dZbnHTSSXz22WdoNBr+8Y9/sGDBAubOncstt9xCQkICGo2GJUuWsGvXru66HCHEAGMwGJg7dy7vv/8+Tz31FMXFxXz33Xfcf//9AJGsFTfffDNz5sxp8RxDhgyJetyYSv1gjUHjxnO++uqrJCUlNdtPq43+05+Tk8PFF1/MySefzJ/+9Kc2X1vTfrjxdU8++WRuvfXWFvcfNmxYq+f6/e9/z0svvcQNN9zA9OnTcTgcqFQqLrzwwlYzewghRKPKykrmzZvHsGHDeP755yPPB4NBTj75ZCoqKrjtttsYMWIEFouF/Px8FixY0Kx/aa1/PVy/21EyThVCCCGEEEIIIYToXBIAF72ay+Wiqqqq2fONqX4bqdVqZs2axaxZs3jkkUe4//77+eMf/8iXX37J7Nmzeffddxk0aBDvvfdeVFD97rvv7upLEEIMcBdccAFLly5l+fLlbNu2DUVRInVkBw0aBIBOp2P27Nmd8nqDBw8GICEh4bDnrK+v55xzzsHpdPLGG29EZc1o1FI/7PP5KCwsbPa6tbW17bqOd999l8suu4y//OUvkecaGhpa7P+FEKKpUCjExRdfTFVVFZ9//jlmszmybdOmTfz8888sXbqUSy+9NPJ8Y33wrrBjx45I+nWA2tpaCgsL+cUvftHqMTJOFUIIIYQQQgghhOhcUgNc9GqDBw+murqajRs3Rp4rLCzk/fffjzyuqKhodtyECRMA8Hq9wIGVO01X6qxcuZIVK1Z0RbOFECJi9uzZxMTE8NZbb/HWW28xderUSErbhIQETjjhBJ599tlmAWWA0tLSI369OXPmYLfbuf/++6PS6LZ0zt/+9rf8/PPPvP/++5FU6gcbPHhws/rdzz33XLMV4Oeffz4rVqzg008/bXaOqqoqAoFAq23WaDTNVlI+/vjjzV5DCCEOtnjxYj799FPeeOONZunCWxr/KYrC3/72ty5rz3PPPRfV9z799NMEAgFOO+20Vo+RcaoQQgghhBBCCCFE55IV4KJXu/DCC7nttts4++yzue6666irq+Ppp59m2LBhrF27FoB7772Xb775htNPP53MzExKSkp46qmnSEtLY+bMmQCcccYZvPfee5x99tmcfvrp5OTk8MwzzzBq1Chqa2t78hKFEP2cTqfjnHPO4c0338Tj8fD//t//i9r+5JNPMnPmTMaOHctVV13FoEGDKC4uZsWKFezbt48NGzYc0evZ7XaefvppLrnkEiZNmsSFF15IfHw8eXl5fPTRRxxzzDE88cQTfPTRR7zyyivMmzePjRs3Rk00slqtzJ07F4Arr7yS3/72t8ybN4+TTz6ZDRs28OmnnxIXFxf1urfccgv//ve/OeOMM1iwYAGTJ0/G4/GwadMm3n33XXJzc5sd0+iMM87g1VdfxeFwMGrUKFasWMHnn39ObGzsEV27EGJg2bRpE/fddx/HHXccJSUl/OMf/4jafsEFFzB48GBuvvlm8vPzsdvt/POf/2yxdndn8fl8zJo1i/PPP5/t27fz1FNPMXPmTM4666xWj5FxqhBCCCGEEEIIIUTnkgC46NViY2N5//33WbhwIbfeeivZ2dksWbKEHTt2RALgZ511Frm5ubz44ouUlZURFxfH8ccfz+LFi3E4HAAsWLCAoqIinn32WT799FNGjRrFP/7xD9555x2++uqrHrxCIcRAcMEFF/D888+jUqk4//zzo7aNGjWKH3/8kcWLF/Pyyy9TXl5OQkICEydO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bQLgGRkZqK6uhsFggCCM/Tn+nE4nsrOzUV1dDaPRONLDGTbcb+430JmN43K5kJGRMYKjG92Sk5Mhk8nQ2NgYtbyxsRFpaWnd2q9evRr33ntv1+tIJIK2tjYkJSWNuXPmeP++jPf9A8b/Pg73/vGcOfTG23Xmycb793Gk8LgOjUQdV543iYiIiIiIiMa20yYALooisrKyRnoYCWc0Gk/Lm2bc79NLrP1mNk7vlEoliouL8cEHH+Cyyy4D0BnU/uCDD3DHHXd0a69SqaBSqaKWmc3mYRjp0Bnv35fxvn/A+N/H4dw/njOH1ni9zjzZeP8+jhQe16GRiOPK8yYRERERERHR2HXaBMCJiE439957L1atWoV58+ZhwYIFeOqpp+B2u3HjjTeO9NCIiIiIiIiIiIiIiIiGBAPgRETj1NVXX43m5mY8+OCDaGhowOzZs/HOO+8gNTV1pIdGREREREREREREREQ0JBgAH6NUKhUeeuihbiWLxzvuN/eb+ueOO+6IWfJ8PBvvPzfjff+A8b+P433/aHzhz+vQ4HEdGjyuRERERERERAQAgiRJ0kgPgoiIiIiIiIiIiIiIiIiIaLDEkR4AERERERERERERERERERFRIjAATkRERERERERERERERERE4wID4ERERERERERERERERERENC4wAE5EREREREREREREREREROMCA+Cj3KOPPopFixZBq9XCbDZ3W79jxw5cc801yM7OhkajwbRp0/Db3/62W7sNGzZg7ty5UKlUKCgowNq1a4d+8IPQ134DQFVVFS6++GJotVrYbDZ8//vfRygUimoz1vY7lgMHDmDlypVITk6G0WjE4sWL8dFHH0W1iedYjEVvvfUWFi5cCI1GA4vFgssuuyxq/Xjdbxq48fx92bBhAwRBiPlny5YtXe127tyJs846C2q1GtnZ2fjlL385gqPuv/H+vc/Ly+v2+T3++ONRbcb6Z0hjz2OPPYb58+fDYDDAZrPhsssuQ3l5eVQbn8+H22+/HUlJSdDr9bjiiivQ2Ng4QiMeG5577jnMnDkTRqMRRqMRJSUl+O9//9u1nsc0MR5//HEIgoC77767axmPLREREREREdHpjQHwUS4QCODKK6/ErbfeGnN9aWkpbDYb/vrXv2LPnj340Y9+hNWrV+Ppp5/ualNRUYGLL74YS5YsQVlZGe6++258+9vf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KSnBj370IwSDwa5169evx5QpU0asdPbp8L0fzO+3srKyrnL9wOj8DGn8kyQJd955J15//XVs2LChWxn+4uJiKBQKfPDBB7jiiisAAOXl5aiqqhoV11VjSSQSgd/v5zEdhPPPPx+7du2KWnbjjTdi6tSp+OEPf4js7GweWyIiIiIiIqLTnUSj2tGjR6Xt27dLDz/8sKTX66Xt27dL27dvl1wulyRJkrRr1y4pJSVF+uY3vynV19d3/Wlqaurq48iRI5JWq5W+//3vS/v27ZOeeeYZSSaTSe+8885I7Vaf+trvUCgkFRUVScuWLZPKysqkd955R0pJSZFWr17d1cdY3O9TNTc3S0lJSdLll18ulZWVSeXl5dL3vvc9SaFQSGVlZZIkxXcsxqK77rpLyszMlN59911p//790k033STZbDapra1NkqTxu980cKfL9+X999+XAEj79u3rts5ut0upqanSddddJ+3evVtat26dpNVqpeeff34ERtp/4/17/8UXX0i/+c1vpLKyMunw4cPSX//6VyklJUW6/vrru9qM9c+QxqZbb71VMplM0oYNG6KuJz0eT1ebW265RcrJyZE+/PBDaevWrVJJSYlUUlIygqMe/e6//37p448/lioqKqSdO3dK999/vyQIgvTee+9JksRjmkjnnHOOdNddd3W95rElIiIiIiIiOr0xAD7KrVq1SgLQ7c9HH30kSZIkPfTQQzHX5+bmRvXz0UcfSbNnz5aUSqU0YcIEac2aNcO+L/3R135LkiRVVlZKK1askDQajZScnCzdd999UjAYjOpnrO13LFu2bJGWLVsmWa1WyWAwSGeccYb09ttvR7WJ51iMNYFAQLrvvvskm80mGQwGaenSpdLu3buj2ozH/abBOR2+L9dcc420aNGiHtfv2LFDWrx4saRSqaTMzEzp8ccfH8bRDc54/96XlpZKCxculEwmk6RWq6Vp06ZJP//5zyWfzxfVbix/hjQ2xbrmAhB13eT1eqXbbrtNslgsklarlb761a9K9fX1IzfoMeBb3/qWlJubKymVSiklJUU6//zzu4LfksRjmkinBsB5bImIiIiIiIhOb4IkSdJwZpwTERERERERERERERERERENBbHvJkRERERERERERERERERERKMfA+BERERERERERERERERERDQuMABORERERERERERERERERETjAgPgREREREREREREREREREQ0LjAATkRERERERERERERERERE4wID4ERERERERERERERERERENC4wAE5EREREREREREREREREROMCA+BERERERERERERERERERDQuMABORERERERERERERERERETjAgPgREREREREREREREREREQ0LjAATkRERERERERERERERERE4wID4ERERERERERERERERERENC78fzKb2ZcvOL18AAAAAElFTkSuQmCC", "text/plain": [ - "<Figure size 1440x1440 with 50 Axes>" + "<Figure size 2000x2000 with 69 Axes>" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1771,7 +1749,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 67, "metadata": { "scrolled": false }, @@ -1781,362 +1759,76 @@ "output_type": "stream", "text": [ "aland\tSize 0.913\tSaving geojson for aland...\n", + "argentina\tSize 662.347\tSaving geojson for argentina...\n", "australia\tSaving geojson for australia...\n", "belgium\tSize 7.709\tSaving geojson for belgium...\n", + "bolivia\tSize 161.264\tSaving geojson for bolivia...\n", "brazil\tSaving geojson for brazil...\n", - "bulgaria\tSize 18.715\tSaving geojson for bulgaria...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "bulgaria\tSize 18.715\tSaving geojson for bulgaria...\n", "burundi\tSize 3.99\tSaving geojson for burundi...\n", "canada\tSaving geojson for canada...\n", + "chile\tSize 1652.977\tSaving geojson for chile...\n", "china\tSaving geojson for china...\n", - "denmark\t" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Size 22.461\tSaving geojson for denmark...\n", + "colombia\tSize 264.526\tSaving geojson for colombia...\n", + "costa rica\tSize 25.939\tSaving geojson for costa rica...\n", + "cuba\tSize 37.185\tSaving geojson for cuba...\n", + "denmark\tSize 22.461\tSaving geojson for denmark...\n", + "dominican republic\tSize 8.806\tSaving geojson for dominican republic...\n", + "ecuador\tSize 112.048\tSaving geojson for ecuador...\n", "egypt\tSize 117.982\tSaving geojson for egypt...\n", + "el salvador\tSize 3.116\tSaving geojson for el salvador...\n", "estonia\tSize 13.694\tSaving geojson for estonia...\n", "ethiopia\tSize 172.021\tSaving geojson for ethiopia...\n", - "france\t" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Size 142.834\tSaving geojson for france...\n", + "france\tSize 142.834\tSaving geojson for france...\n", "finland\tSize 112.354\tSaving geojson for finland...\n", - "germany\t" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Size 71.47\tSaving geojson for germany...\n", + "germany\tSize 71.47\tSaving geojson for germany...\n", + "guatemala\tSize 16.442\tSaving geojson for guatemala...\n", + "haiti\tSize 5.882\tSaving geojson for haiti...\n", + "honduras\tSize 27.669\tSaving geojson for honduras...\n", "iceland\tSize 34.959\tSaving geojson for iceland...\n", "india\tSaving geojson for india...\n", - "indonesia\tSaving geojson for indonesia...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "indonesia\tSaving geojson for indonesia...\n", "iran\tSize 284.014\tSaving geojson for iran...\n", - "italy\t" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Size 138.162\tSaving geojson for italy...\n", - "japan\t" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Size 661.569\tSaving geojson for japan...\n", + "italy\tSize 138.162\tSaving geojson for italy...\n", + "japan\tSize 661.569\tSaving geojson for japan...\n", "kenya\tSize 77.61\tSaving geojson for kenya...\n", "korea\tSize 34.227\tSaving geojson for korea...\n", - "liechtenstein\tSize 0.029\tSaving geojson for liechtenstein...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "liechtenstein\tSize 0.029\tSaving geojson for liechtenstein...\n", "malaysia\tSize 127.7\tSaving geojson for malaysia...\n", - "mexico\tSize 575.302\tSaving geojson for mexico...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "mexico\tSize 575.302\tSaving geojson for mexico...\n", "morocco\tSize 231.84\tSaving geojson for morocco...\n", "myanmar\tSize 168.709\tSaving geojson for myanmar...\n", "netherlands\tSize 10.818\tSaving geojson for netherlands...\n", - "nigeria\tSize 115.287\tSaving geojson for nigeria...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "nicaragua\tSize 21.415\tSaving geojson for nicaragua...\n", + "nigeria\tSize 115.287\tSaving geojson for nigeria...\n", "norway\tSize 530.052\tSaving geojson for norway...\n", + "panama\tSize 14.275\tSaving geojson for panama...\n", + "paraguay\tSize 69.763\tSaving geojson for paraguay...\n", "portugal\tSize 105.727\tSaving geojson for portugal...\n", "poland\tSize 58.556\tSaving geojson for poland...\n", + "puerto rico\tSize 1.616\tSaving geojson for puerto rico...\n", "russia\tSaving geojson for russia...\n", - "rwanda\tSize 3.59\tSaving geojson for rwanda...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "rwanda\tSize 3.59\tSaving geojson for rwanda...\n", + "saint barthelemy\tSize 0.004\tSaving geojson for saint barthelemy...\n", + "saint martin\tSize 0.012\tSaving geojson for saint martin...\n", "singapore\tSize 0.067\tSaving geojson for singapore...\n", "slovenia\tSize 4.537\tSaving geojson for slovenia...\n", - "spain\tSize 178.488\t" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Saving geojson for spain...\n", + "spain\tSize 178.488\tSaving geojson for spain...\n", "sweden\tSize 178.774\tSaving geojson for sweden...\n", "switzerland\tSize 8.935\tSaving geojson for switzerland...\n", - "syria\tSize 33.348\tSaving geojson for syria...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "syria\tSize 33.348\tSaving geojson for syria...\n", "tanzania\tSize 119.579\tSaving geojson for tanzania...\n", - "thailand\tSize 122.959\t" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Saving geojson for thailand...\n", + "thailand\tSize 122.959\tSaving geojson for thailand...\n", "timorleste\tSize 4.486\tSaving geojson for timorleste...\n", "uganda\tSize 31.083\tSaving geojson for uganda...\n", - "uk\tSaving geojson for uk...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "uk\tSaving geojson for uk...\n", "ukraine\tSize 128.988\tSaving geojson for ukraine...\n", "uruguay\tSize 25.985\tSaving geojson for uruguay...\n", - "usa\tSaving geojson for usa...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n", - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "usa\tSaving geojson for usa...\n", + "venezuela\tSize 204.361\tSaving geojson for venezuela...\n", "zambia\tSize 115.483\tSaving geojson for zambia...\n", "Done. \n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/yann/Library/Python/3.8/lib/python/site-packages/geopandas/io/file.py:362: FutureWarning: pandas.Int64Index is deprecated and will be removed from pandas in a future version. Use pandas.Index with the appropriate dtype instead.\n", - " pd.Int64Index,\n" - ] } ], "source": [ @@ -2194,7 +1886,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3.10.7 64-bit", "language": "python", "name": "python3" }, @@ -2208,7 +1900,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.9" + "version": "3.10.7" + }, + "vscode": { + "interpreter": { + "hash": "cfa538cd06c93e304ca575fcc7e49a96f6a8b18fe97e2a1aa2a1d32cf31b50ca" + } } }, "nbformat": 4, diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts index f1aad661eeaea..c6b26bd2b6850 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts @@ -22,6 +22,7 @@ import { D3_FORMAT_OPTIONS, D3_FORMAT_DOCS, sections, + getStandardizedControls, } from '@superset-ui/chart-controls'; import { countryOptions } from './countries'; @@ -88,6 +89,11 @@ const config: ControlPanelConfig = { renderTrigger: false, }, }, + formDataOverrides: formData => ({ + ...formData, + entity: getStandardizedControls().shiftColumn(), + metric: getStandardizedControls().shiftMetric(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries.ts b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries.ts index 871c3cdb7cc85..fcabfa6d23b5e 100755 --- a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries.ts @@ -18,21 +18,33 @@ */ import austria from './countries/austria.geojson'; +import argentina from './countries/argentina.geojson'; import australia from './countries/australia.geojson'; import belgium from './countries/belgium.geojson'; +import bolivia from './countries/bolivia.geojson'; import brazil from './countries/brazil.geojson'; import bulgaria from './countries/bulgaria.geojson'; import burundi from './countries/burundi.geojson'; import canada from './countries/canada.geojson'; +import chile from './countries/chile.geojson'; import china from './countries/china.geojson'; +import colombia from './countries/colombia.geojson'; +import costa_rica from './countries/costa rica.geojson'; +import cuba from './countries/cuba.geojson'; import cyprus from './countries/cyprus.geojson'; import denmark from './countries/denmark.geojson'; +import dominican_republic from './countries/dominican republic.geojson'; +import ecuador from './countries/ecuador.geojson'; import egypt from './countries/egypt.geojson'; +import el_salvador from './countries/el salvador.geojson'; import estonia from './countries/estonia.geojson'; import ethiopia from './countries/ethiopia.geojson'; import france from './countries/france.geojson'; import finland from './countries/finland.geojson'; import germany from './countries/germany.geojson'; +import guatemala from './countries/guatemala.geojson'; +import haiti from './countries/haiti.geojson'; +import honduras from './countries/honduras.geojson'; import iceland from './countries/iceland.geojson'; import india from './countries/india.geojson'; import indonesia from './countries/indonesia.geojson'; @@ -44,6 +56,7 @@ import jordan from './countries/jordan.geojson'; import kenya from './countries/kenya.geojson'; import korea from './countries/korea.geojson'; import kuwait from './countries/kuwait.geojson'; +import latvia from './countries/latvia.geojson'; import liechtenstein from './countries/liechtenstein.geojson'; import lithuania from './countries/lithuania.geojson'; import nigeria from './countries/nigeria.geojson'; @@ -53,15 +66,22 @@ import mexico from './countries/mexico.geojson'; import morocco from './countries/morocco.geojson'; import myanmar from './countries/myanmar.geojson'; import netherlands from './countries/netherlands.geojson'; +import nicaragua from './countries/nicaragua.geojson'; import oman from './countries/oman.geojson'; import pakistan from './countries/pakistan.geojson'; +import panama from './countries/panama.geojson'; +import papua_new_guinea from './countries/papua new guinea.geojson'; +import paraguay from './countries/paraguay.geojson'; import philippines from './countries/philippines.geojson'; import peru from './countries/peru.geojson'; import poland from './countries/poland.geojson'; import portugal from './countries/portugal.geojson'; +import puerto_rico from './countries/puerto rico.geojson'; import qatar from './countries/qatar.geojson'; import russia from './countries/russia.geojson'; import rwanda from './countries/rwanda.geojson'; +import saint_barthelemy from './countries/saint barthelemy.geojson'; +import saint_martin from './countries/saint martin.geojson'; import saudi_arabia from './countries/saudi_arabia.geojson'; import singapore from './countries/singapore.geojson'; import slovenia from './countries/slovenia.geojson'; @@ -72,6 +92,7 @@ import syria from './countries/syria.geojson'; import tanzania from './countries/tanzania.geojson'; import thailand from './countries/thailand.geojson'; import timorleste from './countries/timorleste.geojson'; +import turkey from './countries/turkey.geojson'; import united_arab_emirates from './countries/united_arab_emirates.geojson'; import uganda from './countries/uganda.geojson'; import uk from './countries/uk.geojson'; @@ -79,25 +100,38 @@ import ukraine from './countries/ukraine.geojson'; import uruguay from './countries/uruguay.geojson'; import usa from './countries/usa.geojson'; import zambia from './countries/zambia.geojson'; +import venezuela from './countries/venezuela.geojson'; import vietnam from './countries/vietnam.geojson'; export const countries = { austria, + argentina, australia, belgium, + bolivia, brazil, bulgaria, burundi, canada, + chile, china, + colombia, + costa_rica, + cuba, cyprus, denmark, + dominican_republic, + ecuador, egypt, + el_salvador, estonia, ethiopia, france, finland, germany, + guatemala, + haiti, + honduras, iceland, india, indonesia, @@ -109,6 +143,7 @@ export const countries = { kenya, korea, kuwait, + latvia, liechtenstein, lithuania, malaysia, @@ -116,17 +151,24 @@ export const countries = { morocco, myanmar, netherlands, + nicaragua, nigeria, norway, oman, pakistan, + panama, + papua_new_guinea, + paraguay, philippines, peru, poland, portugal, + puerto_rico, qatar, russia, rwanda, + saint_barthelemy, + saint_martin, saudi_arabia, singapore, slovenia, @@ -137,6 +179,7 @@ export const countries = { tanzania, thailand, timorleste, + turkey, united_arab_emirates, uganda, uk, @@ -144,6 +187,7 @@ export const countries = { uruguay, usa, zambia, + venezuela, vietnam, }; diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/argentina.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/argentina.geojson new file mode 100644 index 0000000000000..35ac2073a0a1f --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/argentina.geojson @@ -0,0 +1,30 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "AR-E", "NAME_1": "Entre Ríos" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -58.200111852217844, -32.447129912359713 ], [ -58.222808397999927, -32.534274997999944 ], [ -58.179351365999935, -32.828301690999922 ], [ -58.137766079999949, -32.900323174999926 ], [ -58.14679928299995, -33.049981377999927 ], [ -58.204457160999937, -33.091892184999949 ], [ -58.383168097999942, -33.07545338299991 ], [ -58.430165167999917, -33.102634372999944 ], [ -58.41234290299991, -33.298272393999923 ], [ -58.50649980399993, -33.405857028999947 ], [ -58.549387173999946, -33.683038018999923 ], [ -58.540679490999935, -33.745212497999944 ], [ -58.461048956999946, -33.859470309999949 ], [ -58.439361131999931, -33.979668877999927 ], [ -58.446970686747761, -34.006940156662893 ], [ -58.638508267342672, -34.048515719524858 ], [ -59.031817592907601, -33.829562676876037 ], [ -59.231314459594614, -33.797988376462399 ], [ -59.268934903023364, -33.721248874635876 ], [ -59.392648281393065, -33.739387301882459 ], [ -59.520702481334411, -33.655309746747434 ], [ -59.602764654864927, -33.677788994666344 ], [ -59.772392544380409, -33.610506279641072 ], [ -59.843886887969518, -33.533921807445438 ], [ -60.118082038255466, -33.393568616798234 ], [ -60.495423346909945, -33.122060641685266 ], [ -60.675464036735889, -32.846521905161808 ], [ -60.705823941221922, -32.679503675554201 ], [ -60.767008836388698, -32.578321221946851 ], [ -60.706934984362022, -32.156176446186066 ], [ -60.66179561957216, -32.069256687146378 ], [ -60.719957444580416, -31.922340589546593 ], [ -60.674042935233274, -31.85288746508445 ], [ -60.647765469001172, -31.716048271910211 ], [ -60.414110480414308, -31.673518568826864 ], [ -60.163660650818372, -31.442059828098593 ], [ -60.063382533876847, -31.26951222121204 ], [ -59.719837612815581, -30.830986016491465 ], [ -59.660642259033011, -30.736056409675541 ], [ -59.622350022935223, -30.574825941563972 ], [ -59.61477942562999, -30.462688083488274 ], [ -59.661520759075756, -30.336907646670568 ], [ -59.388540004717413, -30.305953463881281 ], [ -59.241313849654432, -30.343470553623149 ], [ -59.004997525215629, -30.204099215806139 ], [ -58.876168178918306, -30.226991875774445 ], [ -58.587141893283729, -30.153042901009087 ], [ -58.229644335117939, -30.252985121166432 ], [ -58.06800045405771, -30.420726821185838 ], [ -57.98725602924236, -30.603506362128883 ], [ -57.801867634999979, -30.773314309999932 ], [ -57.807241984999848, -30.907569681999917 ], [ -57.911731730999946, -30.94736053499993 ], [ -57.855249389999898, -31.058981627999955 ], [ -57.911731730999946, -31.17060272199997 ], [ -57.905117146999942, -31.240986022999905 ], [ -57.990228230999975, -31.399322611999921 ], [ -58.07523596199988, -31.475183613999931 ], [ -57.986817585999944, -31.554145202999891 ], [ -57.988626260999922, -31.642821960999896 ], [ -58.059267943999913, -31.811493834999922 ], [ -58.15285396399986, -31.835988464999971 ], [ -58.202618367999975, -31.893142597999898 ], [ -58.145309203999915, -32.017889505999904 ], [ -58.186546996999908, -32.152920023999883 ], [ -58.096526652999955, -32.280974222999888 ], [ -58.200111852217844, -32.447129912359713 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-A", "NAME_1": "Salta" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -67.284732110969486, -23.834136437456095 ], [ -67.251328739999906, -23.733090625999878 ], [ -67.079775967386979, -23.833583672748318 ], [ -66.873561164116438, -24.050056247597752 ], [ -66.768502976930847, -24.098373712177079 ], [ -66.675330370200413, -24.199142754634408 ], [ -66.50448808475727, -24.237124933269058 ], [ -66.388009406009246, -24.140955092103809 ], [ -66.351990933035097, -24.04137460715242 ], [ -66.337934943143125, -23.723822930583765 ], [ -66.406664598092732, -23.518822524140205 ], [ -66.377570767277064, -23.390716648254738 ], [ -66.352197638610107, -23.367823989185752 ], [ -66.257164679906055, -23.391285089035648 ], [ -65.992090419637123, -23.533860365063788 ], [ -65.986845262299028, -23.719223727493045 ], [ -66.025964321596177, -23.847639661741027 ], [ -66.000203620200921, -23.94132903420757 ], [ -65.959405076982705, -23.993160496259918 ], [ -65.901940883964585, -23.980396416661279 ], [ -65.759107224618731, -24.076824640244979 ], [ -65.751536628212818, -24.175113214003602 ], [ -65.580358445985496, -24.407967217812882 ], [ -65.276862759308869, -24.501811619010994 ], [ -65.164879929964798, -24.454269300787587 ], [ -65.064265917138357, -24.54646005558709 ], [ -64.922310756935872, -24.599531751988764 ], [ -64.828182135796908, -24.455457859192848 ], [ -64.618014086380981, -24.613949477086692 ], [ -64.502982346657973, -24.480727634172979 ], [ -64.298033617057797, -24.401611016435254 ], [ -64.177084927327542, -24.240690605786824 ], [ -64.183415290283392, -23.525953870974377 ], [ -64.367486742419203, -23.509572442014587 ], [ -64.438283454018176, -23.619591566597535 ], [ -64.555769823118851, -23.505645032492282 ], [ -64.660104539892586, -23.454640394538558 ], [ -64.79567766029578, -23.502441095180416 ], [ -64.868954840593403, -23.496291598478479 ], [ -64.95254147021268, -23.308396090507188 ], [ -65.036877406866836, -23.265814710580457 ], [ -65.013002895866919, -23.033994235545549 ], [ -65.05718624534893, -22.991826266768783 ], [ -65.181984829336386, -22.984953301453686 ], [ -65.227175869170992, -22.950640150822323 ], [ -65.285596075698322, -22.731790460061688 ], [ -65.265235562171426, -22.638204441281971 ], [ -65.345489060571651, -22.588233331203298 ], [ -65.190478219194461, -22.098473959105945 ], [ -65.020367594999897, -22.096582946999916 ], [ -64.586879841999917, -22.21275156699997 ], [ -64.542774006999934, -22.275486755999921 ], [ -64.572022867999891, -22.343182881999908 ], [ -64.428284871999921, -22.542343851999931 ], [ -64.453709675999846, -22.642906188999945 ], [ -64.355731160999909, -22.751943460999968 ], [ -64.325293741999957, -22.871936136999878 ], [ -64.250828002999924, -22.540690204999876 ], [ -64.160549275999898, -22.438474223 ], [ -63.933172973999916, -22.001808369999949 ], [ -63.81312862199988, -22.003048604999904 ], [ -63.740419880999923, -22.050590921999913 ], [ -63.639392455999882, -21.997467549999968 ], [ -62.804352986999902, -22.004082131999965 ], [ -62.78347570899993, -22.130896097999937 ], [ -62.624829060999929, -22.247271422999944 ], [ -62.625294148999842, -22.305045674999946 ], [ -62.341356966999911, -22.472261048 ], [ -62.334380866383867, -24.4029029267287 ], [ -63.398579474962787, -25.659363701473637 ], [ -63.924387173029629, -25.652335706527651 ], [ -64.191761033944545, -25.579885348530013 ], [ -64.425002611381387, -26.027558281689323 ], [ -64.486342536179109, -26.220208021483018 ], [ -64.767358974936712, -26.21137135230606 ], [ -64.945720180841647, -26.274106541083995 ], [ -65.252807380256399, -26.172355644897095 ], [ -65.314379849050795, -26.076030775899596 ], [ -65.442072312886921, -26.120059095750662 ], [ -65.665340338685667, -26.074790540650952 ], [ -65.71900631428997, -26.299014580858227 ], [ -66.053817918961784, -26.253487644239385 ], [ -66.1570415916961, -26.169875177097765 ], [ -66.209053920901738, -26.165741062000393 ], [ -66.399352383205894, -26.387329603878129 ], [ -66.533271857210423, -26.259998875247902 ], [ -66.815838588679924, -25.812480970820161 ], [ -66.809973313717421, -25.73016041397193 ], [ -66.745713670649366, -25.677398776832092 ], [ -66.571279873367473, -25.667115166831479 ], [ -66.495031297056698, -25.608514093150859 ], [ -66.469244758139041, -25.479788099641098 ], [ -66.560350308220166, -25.272358900442896 ], [ -67.806863368849406, -25.283210951224419 ], [ -68.496467799049697, -25.159996516725869 ], [ -68.36664912899991, -25.123426614999929 ], [ -68.443543660999893, -25.021107278999921 ], [ -68.473050903999933, -24.907935892999973 ], [ -68.551030639999908, -24.868765156999928 ], [ -68.578005737999945, -24.80871714299991 ], [ -68.49553015099994, -24.601804707999904 ], [ -68.451501831999877, -24.629296569999966 ], [ -68.397654988999932, -24.500518899999875 ], [ -68.326806599999884, -24.49824513699987 ], [ -68.244486043999927, -24.385383809999979 ], [ -67.362369344999934, -24.030366718999929 ], [ -67.284732110969486, -23.834136437456095 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-Y", "NAME_1": "Jujuy" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -67.251328739999906, -23.733090625999878 ], [ -67.013966837999874, -23.000713805999879 ], [ -67.193904174999972, -22.82222340899996 ], [ -67.026627563999909, -22.639392190999985 ], [ -67.032725382999871, -22.524567158999986 ], [ -66.785091918999882, -22.427622171999957 ], [ -66.735895955999922, -22.225050557999921 ], [ -66.377468220999845, -22.127072040999892 ], [ -66.307601684999952, -22.077049254999906 ], [ -66.22246476199993, -21.786937763999973 ], [ -66.094488078999944, -21.832929789999881 ], [ -66.046532348999932, -21.917989196999983 ], [ -65.9326891689999, -21.944550882999906 ], [ -65.775308593999938, -22.105057880999908 ], [ -65.190478219194461, -22.098473959105945 ], [ -65.345489060571651, -22.588233331203298 ], [ -65.265235562171426, -22.638204441281971 ], [ -65.286629605371957, -22.722798761253841 ], [ -65.231025764327569, -22.945059095800616 ], [ -65.017421230905086, -23.026707859080432 ], [ -65.041347418748387, -23.256667983040984 ], [ -64.95254147021268, -23.308396090507188 ], [ -64.874742601190064, -23.494069513097543 ], [ -64.79567766029578, -23.502441095180416 ], [ -64.660104539892586, -23.454640394538558 ], [ -64.555769823118851, -23.505645032492282 ], [ -64.438283454018176, -23.619591566597535 ], [ -64.367486742419203, -23.509572442014587 ], [ -64.188841314774834, -23.513293145062619 ], [ -64.158765632028292, -24.183639824818044 ], [ -64.298033617057797, -24.401611016435254 ], [ -64.502982346657973, -24.480727634172979 ], [ -64.609358282558674, -24.610538831501856 ], [ -64.828182135796908, -24.455457859192848 ], [ -64.901743536934646, -24.592555433886162 ], [ -64.935875821312095, -24.597671400914408 ], [ -65.064265917138357, -24.54646005558709 ], [ -65.164879929964798, -24.454269300787587 ], [ -65.276862759308869, -24.501811619010994 ], [ -65.587102220091367, -24.402592869265504 ], [ -65.751536628212818, -24.175113214003602 ], [ -65.759107224618731, -24.076824640244979 ], [ -65.901940883964585, -23.980396416661279 ], [ -65.959405076982705, -23.993160496259918 ], [ -66.000203620200921, -23.94132903420757 ], [ -66.025964321596177, -23.847639661741027 ], [ -65.986845262299028, -23.719223727493045 ], [ -65.986819423877307, -23.543317152764416 ], [ -66.170193244022983, -23.420688979113095 ], [ -66.342120734184505, -23.368702487429857 ], [ -66.377570767277064, -23.390716648254738 ], [ -66.406664598092732, -23.518822524140205 ], [ -66.337934943143125, -23.723822930583765 ], [ -66.351990933035097, -24.04137460715242 ], [ -66.388009406009246, -24.140955092103809 ], [ -66.50448808475727, -24.237124933269058 ], [ -66.675330370200413, -24.199142754634408 ], [ -66.768502976930847, -24.098373712177079 ], [ -66.873561164116438, -24.050056247597752 ], [ -67.079775967386979, -23.833583672748318 ], [ -67.251328739999906, -23.733090625999878 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-P", "NAME_1": "Formosa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -62.341356966999911, -22.472261048 ], [ -62.2872269289999, -22.483949482999961 ], [ -62.241183227999983, -22.538416442999861 ], [ -62.25281042499995, -22.603632100999974 ], [ -62.192969116999876, -22.628230081999959 ], [ -62.188266560999892, -22.70832855299993 ], [ -62.035821085999885, -22.884855244999898 ], [ -61.956446085999914, -23.034406839999917 ], [ -61.769274048999961, -23.165561624999953 ], [ -61.732997192999903, -23.243386331999901 ], [ -61.51605952999995, -23.344982197999911 ], [ -61.501073363999893, -23.407820739999892 ], [ -61.296951456999921, -23.481407979999886 ], [ -61.272611856999902, -23.52357594799993 ], [ -61.109856933999907, -23.606981709999985 ], [ -61.118848632999942, -23.666409606999935 ], [ -61.006349039999861, -23.805470885999924 ], [ -60.837625487999929, -23.871823424999945 ], [ -60.632159993999892, -23.89228729299991 ], [ -60.577538004999951, -23.944170430999918 ], [ -60.337371785999892, -24.016414082999944 ], [ -60.033669392999883, -24.007008971999895 ], [ -59.610516927999925, -24.289575703999958 ], [ -59.465900431999927, -24.353551126999946 ], [ -59.34097265699998, -24.487599792999958 ], [ -59.000915893999974, -24.644179381999905 ], [ -58.809196329999878, -24.776781106999934 ], [ -58.473402872999941, -24.851298522999883 ], [ -58.335995238999914, -24.991858418999882 ], [ -58.224064087999892, -24.941215514999911 ], [ -57.983768676999915, -25.074230651999954 ], [ -57.870700643999982, -25.085289407999952 ], [ -57.754066934999912, -25.18089080799993 ], [ -57.640792195999921, -25.372610371999926 ], [ -57.558109904999952, -25.443510436999901 ], [ -57.575318156999941, -25.56443328899995 ], [ -57.774582478999974, -25.701685891999944 ], [ -57.740372680999883, -25.722149759999908 ], [ -57.820626179999891, -25.778270364999941 ], [ -57.801867634999979, -25.831393737999889 ], [ -57.875351521999875, -25.876145527999938 ], [ -57.851373656999925, -25.908391621999911 ], [ -57.905840617999843, -25.968646341999971 ], [ -57.859590210999954, -25.980945332999923 ], [ -57.872716023999942, -26.010297546 ], [ -58.08650142399992, -26.127189635999954 ], [ -58.124018514999932, -26.201913756999957 ], [ -58.151303669999919, -26.181449889999982 ], [ -58.105983438999914, -26.239534199999881 ], [ -58.169958862999891, -26.270333353999945 ], [ -58.16763342299987, -26.33503224699993 ], [ -58.213057006999918, -26.418644713999939 ], [ -58.1854101159999, -26.451717630999923 ], [ -58.217346150999873, -26.527578632999933 ], [ -58.164946248999939, -26.592277526999922 ], [ -58.192283081999875, -26.612844746999912 ], [ -58.178640502999968, -26.650671894999888 ], [ -58.235536254999914, -26.649845072999952 ], [ -58.24793859899998, -26.758158874999893 ], [ -58.287936157999951, -26.768597513999921 ], [ -58.288556274999934, -26.811488952999881 ], [ -58.340026001999917, -26.808595071999903 ], [ -58.315789753999923, -26.874120788999903 ], [ -58.351274896203968, -26.885811609526552 ], [ -58.382141485940792, -26.845647882243952 ], [ -58.457589076574607, -26.8342273897822 ], [ -58.56983028833713, -26.694804376021125 ], [ -58.863326585853258, -26.503859958570217 ], [ -58.982104865247322, -26.389603367001769 ], [ -59.152301194644394, -26.296379082528631 ], [ -59.264516567985197, -26.346660251869139 ], [ -59.346992153565054, -26.340097344916558 ], [ -59.419623378715926, -26.184447930927263 ], [ -59.663200242996822, -26.132203057724951 ], [ -59.67356136736322, -26.013502292696671 ], [ -59.853679571554949, -25.866121108002744 ], [ -59.867838915133802, -25.817700290635912 ], [ -60.038629522834185, -25.697190850477398 ], [ -60.178052538393899, -25.665099786126234 ], [ -60.238694831201485, -25.495239352614021 ], [ -60.344243943902882, -25.424029228965765 ], [ -60.360341152921876, -25.363257744948953 ], [ -60.499660813895446, -25.209572034821576 ], [ -60.645129970671576, -25.164510186196139 ], [ -61.034253506094444, -24.897963148480528 ], [ -61.076473150815275, -24.895275974206868 ], [ -61.145202805764882, -24.72567392311305 ], [ -61.208532273745448, -24.66578093823972 ], [ -61.44366004067831, -24.62397470466891 ], [ -61.573367886119058, -24.486101982720356 ], [ -61.654603238248853, -24.483621514920969 ], [ -61.775706956710678, -24.341718031561925 ], [ -61.902029994988254, -24.317275078881778 ], [ -62.026621874300076, -24.215989271587603 ], [ -62.339212612571998, -24.120646253621715 ], [ -62.341356966999911, -22.472261048 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-N", "NAME_1": "Misiones" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -54.598497273999925, -25.653833516999939 ], [ -54.60020261299988, -25.574944883999891 ], [ -54.560050007999877, -25.570221048999926 ], [ -54.473026895999936, -25.625824890999922 ], [ -54.447343708999938, -25.689180195999938 ], [ -54.395408894999946, -25.58107309899988 ], [ -54.299239054999902, -25.552651061999939 ], [ -54.255624144999871, -25.598746438999882 ], [ -54.190253458999905, -25.580763040999983 ], [ -54.214799764999952, -25.531463723999892 ], [ -54.16508703599996, -25.534357604999883 ], [ -54.11640783699994, -25.494566751999869 ], [ -54.098889526999869, -25.597196146999948 ], [ -54.082714802999874, -25.550067240999937 ], [ -53.997448689999914, -25.574975279999919 ], [ -53.96773474099993, -25.653213398999881 ], [ -53.898126586999922, -25.639467467999935 ], [ -53.883450480999926, -25.735585632999943 ], [ -53.84035233599991, -25.791396178999918 ], [ -53.833427693999937, -25.962238464999928 ], [ -53.765008097999953, -26.02807423899992 ], [ -53.666719522999955, -26.219173685999948 ], [ -53.72444209799994, -26.37606333399988 ], [ -53.739531616999926, -26.675579935999863 ], [ -53.774309854999984, -26.714337259999894 ], [ -53.722426716999877, -26.814382832999868 ], [ -53.724597127999886, -26.940473327999925 ], [ -53.800923217999923, -27.039071960999919 ], [ -53.830017049999924, -27.156790872999906 ], [ -53.882210245999886, -27.119893900999969 ], [ -53.909495401999919, -27.168263040999918 ], [ -53.964117390999945, -27.154000345999947 ], [ -53.961791951999913, -27.191414082999913 ], [ -54.00514847799991, -27.188210143999939 ], [ -54.091758178999925, -27.285155130999968 ], [ -54.158059041999934, -27.279470722999932 ], [ -54.177024292999903, -27.243400573999935 ], [ -54.231646281999929, -27.380549824999903 ], [ -54.286888386999948, -27.428402200999898 ], [ -54.347711547999978, -27.394295755999934 ], [ -54.371586059999856, -27.454447122999881 ], [ -54.388897664999973, -27.411142272999911 ], [ -54.444553181999879, -27.408971861999916 ], [ -54.448377237999921, -27.458891296999894 ], [ -54.543255167999916, -27.487003274999921 ], [ -54.58945389799996, -27.452586770999872 ], [ -54.690326293999959, -27.55128875699998 ], [ -54.773938760999982, -27.563794453999975 ], [ -54.805047973999933, -27.526380716999924 ], [ -54.845097208999931, -27.611853535999941 ], [ -54.89827225699986, -27.62363576199995 ], [ -54.913206745999929, -27.73691050199993 ], [ -54.985192016999889, -27.785279641999878 ], [ -55.081155151999951, -27.778251647999952 ], [ -55.029633747999952, -27.850702005999935 ], [ -55.099939533999958, -27.843777363999962 ], [ -55.119240682999902, -27.880881042999945 ], [ -55.177557535999938, -27.853595885999923 ], [ -55.260239827999925, -27.919224954999962 ], [ -55.314112508999955, -27.914987487999909 ], [ -55.44074560599995, -28.078905130999942 ], [ -55.505935424999876, -28.078905130999942 ], [ -55.553477742999888, -28.145567727999961 ], [ -55.604740763999928, -28.116938984999891 ], [ -55.623041889271747, -28.144350089584975 ], [ -55.736954107945735, -28.065986829428653 ], [ -55.832658861117523, -27.918398940059035 ], [ -55.858600429666069, -27.753292739268488 ], [ -56.017324591556644, -27.45155404997945 ], [ -56.014482387652038, -27.393779798598814 ], [ -55.966094416224337, -27.331723069164298 ], [ -55.913094034999915, -27.327839863999969 ], [ -55.854157063999878, -27.401220397999921 ], [ -55.754731607999872, -27.443698424999951 ], [ -55.591330728999964, -27.328356627999923 ], [ -55.568670613999927, -27.245984394999937 ], [ -55.598281209999953, -27.167539570999921 ], [ -55.555338094999911, -27.153793639999975 ], [ -55.533840698999938, -27.099430033999923 ], [ -55.461855428999911, -27.097983092999925 ], [ -55.414003051999885, -26.979850768999924 ], [ -55.280600341999843, -26.934272155999935 ], [ -55.138360962999911, -26.953702493999927 ], [ -55.125777750999873, -26.863578795999928 ], [ -55.060897989999944, -26.805184427999876 ], [ -54.975270141999886, -26.787821145999942 ], [ -54.919898844999949, -26.674132995999869 ], [ -54.793059041999896, -26.644987487999941 ], [ -54.789829264999895, -26.528508808999987 ], [ -54.697664347999961, -26.428153177999931 ], [ -54.638288126999925, -26.196952819999908 ], [ -54.66381628399995, -26.149203796999927 ], [ -54.642525594999967, -26.06280080199987 ], [ -54.662265990999941, -25.97991180399994 ], [ -54.60640376799995, -25.946632181999902 ], [ -54.587903604999923, -25.810826517999899 ], [ -54.642887329999979, -25.661584980999947 ], [ -54.598497273999925, -25.653833516999939 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-H", "NAME_1": "Chaco" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -58.351274896203968, -26.885811609526552 ], [ -58.475469930999907, -26.937992858999863 ], [ -58.511540079999918, -27.060155944999948 ], [ -58.545439819999928, -27.041035664999953 ], [ -58.565490274999974, -27.115966490999909 ], [ -58.653288533999927, -27.156274108999952 ], [ -58.652358357999873, -27.198028665999914 ], [ -58.601560424999974, -27.245674336999954 ], [ -58.604195923403154, -27.31626434282515 ], [ -58.886529304184023, -27.478942560250971 ], [ -58.815732590786411, -27.716860854245056 ], [ -58.864747687355873, -27.999324232926995 ], [ -61.709948696874847, -28.00040943764543 ], [ -61.710517136756437, -26.146569105979438 ], [ -61.722325201946489, -25.744164727020518 ], [ -61.753873663938407, -25.661430759022323 ], [ -63.398579474962787, -25.659363701473637 ], [ -62.334380866383867, -24.4029029267287 ], [ -62.339212612571998, -24.120646253621715 ], [ -62.026621874300076, -24.215989271587603 ], [ -61.902029994988254, -24.317275078881778 ], [ -61.775706956710678, -24.341718031561925 ], [ -61.654603238248853, -24.483621514920969 ], [ -61.573367886119058, -24.486101982720356 ], [ -61.44366004067831, -24.62397470466891 ], [ -61.208532273745448, -24.66578093823972 ], [ -61.145202805764882, -24.72567392311305 ], [ -61.076473150815275, -24.895275974206868 ], [ -61.034253506094444, -24.897963148480528 ], [ -60.645129970671576, -25.164510186196139 ], [ -60.499660813895446, -25.209572034821576 ], [ -60.360341152921876, -25.363257744948953 ], [ -60.344243943902882, -25.424029228965765 ], [ -60.238694831201485, -25.495239352614021 ], [ -60.178052538393899, -25.665099786126234 ], [ -60.038629522834185, -25.697190850477398 ], [ -59.867838915133802, -25.817700290635912 ], [ -59.853679571554949, -25.866121108002744 ], [ -59.67356136736322, -26.013502292696671 ], [ -59.663200242996822, -26.132203057724951 ], [ -59.419623378715926, -26.184447930927263 ], [ -59.346992153565054, -26.340097344916558 ], [ -59.264516567985197, -26.346660251869139 ], [ -59.152301194644394, -26.296379082528631 ], [ -58.95352779836918, -26.405623060755659 ], [ -58.863326585853258, -26.503859958570217 ], [ -58.56983028833713, -26.694804376021125 ], [ -58.462394986139714, -26.83040333394672 ], [ -58.382141485940792, -26.845647882243952 ], [ -58.351274896203968, -26.885811609526552 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-W", "NAME_1": "Corrientes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -58.238223428999845, -27.257043151999937 ], [ -57.944029500999903, -27.274613138999911 ], [ -57.513358113999914, -27.414139505999927 ], [ -57.33522945099989, -27.409488626999874 ], [ -57.180096801999952, -27.487313333999907 ], [ -57.076227173999939, -27.484006042999908 ], [ -56.904351358999918, -27.418687031999951 ], [ -56.771155354999934, -27.506743671999885 ], [ -56.612999633999948, -27.446385598999896 ], [ -56.546440388999883, -27.455067240999938 ], [ -56.39973099799991, -27.586842142999942 ], [ -56.296998250999906, -27.480905456999963 ], [ -56.279841674999943, -27.389644876999881 ], [ -56.149978799999957, -27.311820169999919 ], [ -55.966094416224337, -27.331723069164298 ], [ -56.000555588969235, -27.360396823954261 ], [ -56.017324591556644, -27.45155404997945 ], [ -55.873276537182448, -27.7157756486273 ], [ -55.83862748886753, -27.906616713290703 ], [ -55.736954107945735, -28.065986829428653 ], [ -55.623041889271747, -28.144350089584975 ], [ -55.772534138999902, -28.231970723999936 ], [ -55.663600219999921, -28.326538593999928 ], [ -55.694244343999941, -28.400125833999923 ], [ -55.842348999999871, -28.346382344999924 ], [ -55.905600951999958, -28.378008320999911 ], [ -55.902035278999904, -28.465134785999894 ], [ -56.011589314999952, -28.496554056999926 ], [ -56.040812336999892, -28.609001973999881 ], [ -56.184705362999892, -28.744187520999915 ], [ -56.286146199999877, -28.780154316999884 ], [ -56.301003173999902, -28.881440123999909 ], [ -56.391617797999913, -28.95223683699993 ], [ -56.427972167999883, -29.069852396999892 ], [ -56.617288777999931, -29.160906269999927 ], [ -56.688653930999919, -29.329578144999871 ], [ -56.769940958999911, -29.379084166999917 ], [ -56.819033569999931, -29.474995625999966 ], [ -57.020933390999915, -29.683355000999896 ], [ -57.112865763999878, -29.766037291999865 ], [ -57.291511189999909, -29.815129902999985 ], [ -57.325152547999949, -29.981011249999952 ], [ -57.506175089999942, -30.144308776999935 ], [ -57.64246584634791, -30.193092102762034 ], [ -57.623738972999888, -30.25810028099994 ], [ -57.652729451999875, -30.329103698999944 ], [ -57.849616658999963, -30.485269877999968 ], [ -57.889769246999975, -30.550795592999876 ], [ -57.808659168999952, -30.747331216999925 ], [ -57.98725602924236, -30.603506362128883 ], [ -58.06800045405771, -30.420726821185838 ], [ -58.260753546638853, -30.230712578822477 ], [ -58.629749111632179, -30.152267754653167 ], [ -58.876168178918306, -30.226991875774445 ], [ -59.004997525215629, -30.204099215806139 ], [ -59.241313849654432, -30.343470553623149 ], [ -59.388540004717413, -30.305953463881281 ], [ -59.661520759075756, -30.336907646670568 ], [ -59.669298061955999, -30.293861178750376 ], [ -59.595349087190641, -30.049173272228757 ], [ -59.6727862210073, -29.847118421577875 ], [ -59.5910857808841, -29.614987888180508 ], [ -59.582895066853837, -29.377793063698959 ], [ -59.511271532055559, -29.207570895880167 ], [ -59.358877733120892, -29.143492119965345 ], [ -59.197440557635616, -29.022052503820021 ], [ -59.194391649055376, -28.921386814150139 ], [ -59.086956345958583, -28.627089531856427 ], [ -59.066208258804068, -28.401366875780695 ], [ -59.087524786739493, -28.175230807655623 ], [ -59.059929571792281, -28.129445488618387 ], [ -58.95047888888962, -28.112392266989559 ], [ -58.894720018214286, -28.070792738993703 ], [ -58.841570808346148, -27.916331881611029 ], [ -58.815732590786411, -27.716860854245056 ], [ -58.886529304184023, -27.478942560250971 ], [ -58.655974901020841, -27.331147962608384 ], [ -58.510764932999905, -27.278437194999952 ], [ -58.238223428999845, -27.257043151999937 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-K", "NAME_1": "Catamarca" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.33776200399987, -27.045583190999892 ], [ -68.305360880999871, -26.897995300999895 ], [ -68.570150919999918, -26.5506263219999 ], [ -68.595317342999948, -26.457298685999945 ], [ -68.57516353399987, -26.303509623999958 ], [ -68.409023804999919, -26.144242857999885 ], [ -68.498475707999916, -25.754912617999906 ], [ -68.559350545999877, -25.663031920999941 ], [ -68.555009724999906, -25.572598163999956 ], [ -68.609941772999917, -25.474206237999937 ], [ -68.496467799049697, -25.159996516725869 ], [ -67.806863368849406, -25.283210951224419 ], [ -66.555105149982694, -25.275459486765897 ], [ -66.469244758139041, -25.479788099641098 ], [ -66.495031297056698, -25.608514093150859 ], [ -66.571279873367473, -25.667115166831479 ], [ -66.735378383805369, -25.673988132146576 ], [ -66.799250454145124, -25.717913100109513 ], [ -66.80286780530497, -25.859196465844207 ], [ -66.533271857210423, -26.259998875247902 ], [ -66.410592006715717, -26.382730400787352 ], [ -66.362300380558111, -26.372033379636775 ], [ -66.30158057338474, -26.245632826094038 ], [ -66.224815233136496, -26.170960381816144 ], [ -66.1570415916961, -26.169875177097765 ], [ -66.053817918961784, -26.253487644239385 ], [ -66.10017167788061, -26.321545504721257 ], [ -66.152028978354679, -26.537863050839121 ], [ -66.015835741226454, -26.600753269248003 ], [ -65.852021449830033, -26.730357761001869 ], [ -65.883776618296281, -26.940267428898721 ], [ -66.194636196703129, -27.319365736739371 ], [ -65.981884324901671, -27.393831475442255 ], [ -65.929329393336843, -27.654332371042074 ], [ -65.877859667389714, -27.697223810230639 ], [ -65.850832893223412, -27.780164482904581 ], [ -65.703038295580882, -27.81788827912078 ], [ -65.664565192329746, -27.945167331806942 ], [ -65.570694952709914, -28.050225518992534 ], [ -65.496952684418829, -27.961238701504897 ], [ -65.348951382100608, -27.863260186108675 ], [ -65.227589281220332, -27.923514907087281 ], [ -65.169091559427898, -27.909665622770262 ], [ -65.079097053386306, -28.274604587931378 ], [ -65.07222408717189, -28.424052830173991 ], [ -65.179995287052861, -28.645072931270761 ], [ -65.092584600698729, -28.721347345103879 ], [ -65.035430466942501, -29.292681979789563 ], [ -64.882468228126243, -29.557110284012424 ], [ -64.951146206232409, -29.578969415206359 ], [ -64.961636521808032, -29.610492038776556 ], [ -64.943394740874567, -29.878330986785613 ], [ -65.138189052582675, -30.063074232489839 ], [ -65.401893887293056, -30.140175469522319 ], [ -65.729496628966217, -29.502178236536395 ], [ -65.755386521570699, -29.314799492502573 ], [ -65.792438524218483, -29.250100599862776 ], [ -66.121824102600272, -28.970634453817013 ], [ -66.362300380558111, -28.854517511174208 ], [ -66.379327765563914, -28.82444182662897 ], [ -66.337573207937169, -28.735713392459104 ], [ -66.464697231891705, -28.631068616423534 ], [ -66.495961473043508, -28.499138685601849 ], [ -66.584354011328571, -28.404157402841861 ], [ -66.976164720125723, -28.267421562455127 ], [ -67.042646450373354, -28.284216403464256 ], [ -67.098586188202034, -28.341473890907366 ], [ -67.18710791679689, -28.356305027155258 ], [ -67.704156460052559, -28.339251803727734 ], [ -67.82409746032954, -28.382401624435431 ], [ -67.914402024733647, -28.248921400901907 ], [ -67.931946173676977, -28.124071140071067 ], [ -68.092091437070167, -28.154353530191258 ], [ -68.151519334849411, -28.105622653562591 ], [ -68.277273933245397, -28.086243991966683 ], [ -68.348432380050269, -28.019426364934816 ], [ -68.442225104405054, -27.9994275857145 ], [ -68.442302618770839, -27.743060805211996 ], [ -68.849616258283675, -27.79344532554137 ], [ -69.134060456999947, -27.772343536999884 ], [ -69.075830647999908, -27.696189473999951 ], [ -69.092341268999888, -27.640172220999943 ], [ -69.028572550999854, -27.55128875699998 ], [ -69.017410441999914, -27.460441588999913 ], [ -68.931446695999881, -27.395225931999889 ], [ -68.870752726999882, -27.198442077999914 ], [ -68.814322061999945, -27.120307311999895 ], [ -68.718617309999843, -27.106664733999892 ], [ -68.585860554999954, -27.162785338999925 ], [ -68.518009398999936, -27.076899108999982 ], [ -68.33776200399987, -27.045583190999892 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-F", "NAME_1": "La Rioja" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.420305744999894, -28.212643737999983 ], [ -69.303232787999889, -27.999530130999887 ], [ -69.190190592999869, -27.951367695999892 ], [ -69.134060456999947, -27.772343536999884 ], [ -68.849616258283675, -27.79344532554137 ], [ -68.657095709699206, -27.752052504019844 ], [ -68.569064906620156, -27.772102960083544 ], [ -68.499172532586272, -27.735774427847559 ], [ -68.428556688140645, -27.760217379628386 ], [ -68.442225104405054, -27.9994275857145 ], [ -68.348432380050269, -28.019426364934816 ], [ -68.277273933245397, -28.086243991966683 ], [ -68.151519334849411, -28.105622653562591 ], [ -68.092091437070167, -28.154353530191258 ], [ -67.931946173676977, -28.124071140071067 ], [ -67.914402024733647, -28.248921400901907 ], [ -67.82409746032954, -28.382401624435431 ], [ -67.704156460052559, -28.339251803727734 ], [ -67.18710791679689, -28.356305027155258 ], [ -67.098586188202034, -28.341473890907366 ], [ -67.042646450373354, -28.284216403464256 ], [ -66.976164720125723, -28.267421562455127 ], [ -66.584354011328571, -28.404157402841861 ], [ -66.518337368174969, -28.467512709244147 ], [ -66.464697231891705, -28.631068616423534 ], [ -66.335531988810203, -28.740674329856461 ], [ -66.377570767277064, -28.816793714957953 ], [ -66.362300380558111, -28.854517511174208 ], [ -66.121824102600272, -28.970634453817013 ], [ -65.792438524218483, -29.250100599862776 ], [ -65.755386521570699, -29.314799492502573 ], [ -65.729496628966217, -29.502178236536395 ], [ -65.401893887293056, -30.140175469522319 ], [ -65.767272101126537, -31.096241143913687 ], [ -65.75964982787724, -31.885495294272403 ], [ -65.907289394989562, -31.900739840771053 ], [ -66.054386358843374, -31.871439303481054 ], [ -66.21716712056616, -31.925441175869594 ], [ -66.373850064229089, -31.93381275795241 ], [ -66.730520799195517, -31.8765552705093 ], [ -66.782119717251135, -31.77444264091514 ], [ -66.836741706364649, -31.747467542692959 ], [ -66.854466721561948, -31.635743096666602 ], [ -66.944822963708816, -31.615692640602902 ], [ -67.048925137385197, -31.523295180228388 ], [ -67.103934699226954, -31.354261569915536 ], [ -67.05995805532001, -31.081823418815702 ], [ -67.114735074064413, -31.038518568477173 ], [ -67.08362586074486, -30.89160247177665 ], [ -67.192275559769257, -30.713990573805916 ], [ -67.566232062159941, -30.379747409915012 ], [ -67.634522468437183, -30.247869155037449 ], [ -67.913704392743512, -30.050723564940597 ], [ -68.076562669731402, -29.88272348430138 ], [ -68.156247728250037, -29.849133803182497 ], [ -68.335461594876676, -29.687231540603136 ], [ -68.605005866127783, -29.645321954244821 ], [ -68.700581428090402, -29.60212045669374 ], [ -68.823054572110777, -29.633074639483027 ], [ -69.01293962326497, -29.622377617433074 ], [ -69.019476690896568, -29.52233204448828 ], [ -68.979349942146087, -29.452982272813642 ], [ -68.975241664571172, -29.34291147228663 ], [ -68.941884528348282, -29.310613701461136 ], [ -69.000227219610508, -29.233409111641208 ], [ -69.004102953188749, -29.150261732492936 ], [ -68.913410814257645, -29.002053724599705 ], [ -69.102985806150002, -28.777674655660803 ], [ -69.190189785130485, -28.594016615574333 ], [ -69.473040738339364, -28.426429946085136 ], [ -69.542984789216632, -28.437540379285053 ], [ -69.65404516415299, -28.400993548313579 ], [ -69.510093546999883, -28.267524108999893 ], [ -69.490508178999875, -28.198381041999909 ], [ -69.420305744999894, -28.212643737999983 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-J", "NAME_1": "San Juan" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.957663126999904, -30.092735696999924 ], [ -69.980374918999871, -30.07247853599992 ], [ -69.927975016999937, -29.976773782999913 ], [ -69.915598510999871, -29.805621439999911 ], [ -69.929086059999946, -29.718288268999885 ], [ -69.973191894999928, -29.666095071999905 ], [ -70.040655477999849, -29.297538757999959 ], [ -69.910947631999903, -29.143232930999929 ], [ -69.803925740999915, -29.098687845999933 ], [ -69.802788859999907, -28.939937845999893 ], [ -69.73276729299991, -28.794313658999926 ], [ -69.753386189999901, -28.67339080799988 ], [ -69.678403686999928, -28.573861998999931 ], [ -69.65404516415299, -28.400993548313579 ], [ -69.542984789216632, -28.437540379285053 ], [ -69.473040738339364, -28.426429946085136 ], [ -69.420666673028506, -28.477331231251299 ], [ -69.33633073637435, -28.484772638246682 ], [ -69.161793586304952, -28.62135344810315 ], [ -69.102985806150002, -28.777674655660803 ], [ -68.908630744013635, -29.014146009730553 ], [ -68.998831957428877, -29.117912285723435 ], [ -69.000227219610508, -29.233409111641208 ], [ -68.941884528348282, -29.310613701461136 ], [ -68.978859015730961, -29.356295667710924 ], [ -69.017254604616312, -29.617778416140993 ], [ -68.823054572110777, -29.633074639483027 ], [ -68.700581428090402, -29.60212045669374 ], [ -68.605005866127783, -29.645321954244821 ], [ -68.335461594876676, -29.687231540603136 ], [ -68.156247728250037, -29.849133803182497 ], [ -68.076562669731402, -29.88272348430138 ], [ -67.913704392743512, -30.050723564940597 ], [ -67.634522468437183, -30.247869155037449 ], [ -67.566232062159941, -30.379747409915012 ], [ -67.192275559769257, -30.713990573805916 ], [ -67.08362586074486, -30.89160247177665 ], [ -67.114735074064413, -31.038518568477173 ], [ -67.05995805532001, -31.081823418815702 ], [ -67.103934699226954, -31.354261569915536 ], [ -67.048925137385197, -31.523295180228388 ], [ -66.944822963708816, -31.615692640602902 ], [ -66.854466721561948, -31.635743096666602 ], [ -66.836741706364649, -31.747467542692959 ], [ -66.782119717251135, -31.77444264091514 ], [ -66.730520799195517, -31.8765552705093 ], [ -67.366967740368921, -31.857951756168632 ], [ -67.393012660805653, -32.262164808459147 ], [ -67.493264940224776, -32.21348560957324 ], [ -67.739063889886609, -32.252863051288784 ], [ -67.831848923888742, -32.239168796602655 ], [ -67.985482958072055, -32.088376967223269 ], [ -68.055840420099287, -32.068429863947074 ], [ -68.251590746215982, -32.139588310751947 ], [ -68.393700935150036, -32.150130304070274 ], [ -68.68960018609971, -32.33508025445019 ], [ -68.88617733361707, -32.33657887121791 ], [ -68.922169969068818, -32.0762330061483 ], [ -69.039062058966863, -32.070755303914154 ], [ -69.174996913676637, -31.955671889146345 ], [ -69.291785650787119, -32.053857110117519 ], [ -69.447693448094128, -32.052823582242524 ], [ -69.608148769849834, -32.120261325999422 ], [ -69.662305670969943, -32.258030694261151 ], [ -69.981226773097092, -32.305366306010228 ], [ -70.256119043999973, -32.314277880999953 ], [ -70.309708821999948, -32.288312275999971 ], [ -70.335236979999905, -32.140000914999874 ], [ -70.387481852999883, -32.041712340999965 ], [ -70.284697428999948, -32.046776631999947 ], [ -70.244467326999938, -31.942235208999932 ], [ -70.313326172999922, -31.882083841999901 ], [ -70.428280395999963, -31.870094909999935 ], [ -70.475228433999916, -31.82007212399995 ], [ -70.486313028999945, -31.731188659999901 ], [ -70.589769246999936, -31.567684427999964 ], [ -70.568969482999904, -31.304237975999897 ], [ -70.535922403999905, -31.172566426999921 ], [ -70.479801798999887, -31.096705423999907 ], [ -70.408643350999938, -31.150035501999895 ], [ -70.339784505999916, -31.041721699999954 ], [ -70.266559000999933, -31.036450703999932 ], [ -70.339216064999874, -30.938162129999924 ], [ -70.21710465599989, -30.51513885499989 ], [ -70.143930826999906, -30.439587910999961 ], [ -70.173412231999919, -30.364657084999905 ], [ -70.030191, -30.397109882999914 ], [ -69.964587768999877, -30.374785664999948 ], [ -69.912136190999917, -30.329517109999955 ], [ -69.890742146999912, -30.228954772999927 ], [ -69.835758422999874, -30.161878762999905 ], [ -69.880716919999884, -30.099763691999925 ], [ -69.957663126999904, -30.092735696999924 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-M", "NAME_1": "Mendoza" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.010011352999925, -33.299103291999913 ], [ -70.10946264699993, -33.169602151999925 ], [ -70.111193807999911, -33.038447366999975 ], [ -70.04248998999995, -32.992662047999943 ], [ -70.000218668999963, -32.876596780999918 ], [ -70.155738891999931, -32.738414001999956 ], [ -70.181086181999916, -32.607569274999918 ], [ -70.13772965499993, -32.56901865599994 ], [ -70.172482056999883, -32.464942321999956 ], [ -70.245319986999874, -32.403964130999981 ], [ -70.256119043999973, -32.314277880999953 ], [ -69.662305670969943, -32.258030694261151 ], [ -69.608148769849834, -32.120261325999422 ], [ -69.447693448094128, -32.052823582242524 ], [ -69.291785650787119, -32.053857110117519 ], [ -69.184272834223918, -31.95675709386478 ], [ -69.13530941359852, -31.968280938214718 ], [ -69.024980230653114, -32.077318210866736 ], [ -68.922169969068818, -32.0762330061483 ], [ -68.88617733361707, -32.33657887121791 ], [ -68.68960018609971, -32.33508025445019 ], [ -68.393700935150036, -32.150130304070274 ], [ -68.020726283790964, -32.069049980672048 ], [ -67.831848923888742, -32.239168796602655 ], [ -67.467194179567741, -32.217929783033071 ], [ -67.393012660805653, -32.262164808459147 ], [ -67.361696742810409, -32.396833591297195 ], [ -67.32071733333828, -32.430991713196988 ], [ -67.258369717288588, -32.653562107005655 ], [ -67.192120531037688, -32.761100762889896 ], [ -67.226950445606576, -32.91613006015416 ], [ -67.151942105443823, -33.429070325834857 ], [ -67.01967627603932, -33.616500745812743 ], [ -66.929578417210166, -33.83793425895891 ], [ -66.844002245307365, -33.896276951120399 ], [ -66.747057257786196, -34.064173678972111 ], [ -66.759201218861165, -34.184528089499736 ], [ -66.82136796685819, -34.229279880661977 ], [ -66.812608812047017, -34.3846192362887 ], [ -66.737962206190844, -34.615406182549293 ], [ -66.546087612753126, -34.924896336296854 ], [ -66.553554857270854, -34.997243340607668 ], [ -66.505134039904021, -35.124160658987194 ], [ -66.521127896135511, -35.494215590277292 ], [ -66.608151007962647, -35.82985401814841 ], [ -66.617168545192214, -35.999921157235633 ], [ -68.24631974955679, -35.999301038711963 ], [ -68.282234869743434, -36.021056817118392 ], [ -68.293190274211781, -36.128285413740855 ], [ -68.256758389188292, -36.276751804052537 ], [ -68.24939449655875, -37.557035413853271 ], [ -68.427523159366274, -37.537760105044811 ], [ -68.506846482679009, -37.447378024476222 ], [ -68.678153856115557, -37.426294040537528 ], [ -68.756676194650652, -37.371672051424014 ], [ -68.985060186578323, -37.363817234177986 ], [ -69.020148485364302, -37.344335218895253 ], [ -69.061050381369967, -37.236021416655035 ], [ -69.154662237672142, -37.182691338734287 ], [ -69.302353481627847, -37.149773451183819 ], [ -69.53099585597397, -37.173647963083056 ], [ -69.703362595707233, -37.112153008654445 ], [ -69.815888028309871, -36.997379653148471 ], [ -69.787956915679104, -36.960172620869741 ], [ -69.790127326015295, -36.863227634247949 ], [ -69.907200283066572, -36.79558318491604 ], [ -69.956008674061025, -36.705821221971803 ], [ -70.067655605721598, -36.611770115198681 ], [ -70.162998622788223, -36.581591077865937 ], [ -70.260253668671851, -36.372818291530905 ], [ -70.341463182379925, -36.376952406628277 ], [ -70.37799842019092, -36.325327651050259 ], [ -70.358800624848925, -36.199392184601663 ], [ -70.430748044186885, -36.129402118113262 ], [ -70.38032466699994, -36.046015726999954 ], [ -70.412725789999939, -35.968914489999918 ], [ -70.383683634999869, -35.913207295999968 ], [ -70.42078731299992, -35.903802184999918 ], [ -70.420244710999981, -35.8683521519999 ], [ -70.3573286539999, -35.815228779999956 ], [ -70.421536620999944, -35.659682718999903 ], [ -70.408229939999927, -35.506203714999899 ], [ -70.471766113999877, -35.37938974999993 ], [ -70.428383748999892, -35.357065530999961 ], [ -70.475280110999847, -35.314070739999892 ], [ -70.560417033999869, -35.298361104999927 ], [ -70.578891357999908, -35.259707132999921 ], [ -70.542898722999922, -35.209270934999921 ], [ -70.38662919099994, -35.166689553999859 ], [ -70.353711303999916, -34.953265888999866 ], [ -70.276713419999879, -34.798236592999928 ], [ -70.316297566999935, -34.745629983999933 ], [ -70.252218790999933, -34.695813903999905 ], [ -70.227827514999916, -34.585329690999885 ], [ -70.067578898999869, -34.414590759999982 ], [ -70.057579508999936, -34.291187438999955 ], [ -69.911567749999875, -34.284572855999969 ], [ -69.828885457999917, -34.23330983399994 ], [ -69.873249674999869, -34.139982197999885 ], [ -69.855808878999937, -33.984746195 ], [ -69.909552367999936, -33.955704039999915 ], [ -69.91425492399992, -33.771942647999893 ], [ -69.860046345999876, -33.7263640339999 ], [ -69.895367187999881, -33.662285257999898 ], [ -69.878830728999873, -33.558002216999867 ], [ -69.841468668999937, -33.53278411799991 ], [ -69.787673502999922, -33.379408466999934 ], [ -69.813899292999935, -33.289491475999895 ], [ -69.869684000999911, -33.249597269999953 ], [ -69.940558227999958, -33.242879333999937 ], [ -70.010011352999925, -33.299103291999913 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-Q", "NAME_1": "Neuquén" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.499128784999925, -36.163631285999926 ], [ -70.430748044186885, -36.129402118113262 ], [ -70.372029792440969, -36.172158704860351 ], [ -70.382416755229087, -36.306569106179325 ], [ -70.35619096494105, -36.365997003059249 ], [ -70.260253668671851, -36.372818291530905 ], [ -70.162998622788223, -36.581591077865937 ], [ -70.067655605721598, -36.611770115198681 ], [ -69.956008674061025, -36.705821221971803 ], [ -69.907200283066572, -36.79558318491604 ], [ -69.790127326015295, -36.863227634247949 ], [ -69.787956915679104, -36.960172620869741 ], [ -69.815888028309871, -36.997379653148471 ], [ -69.703362595707233, -37.112153008654445 ], [ -69.53099585597397, -37.173647963083056 ], [ -69.302353481627847, -37.149773451183819 ], [ -69.154662237672142, -37.182691338734287 ], [ -69.061050381369967, -37.236021416655035 ], [ -69.020148485364302, -37.344335218895253 ], [ -68.985060186578323, -37.363817234177986 ], [ -68.756676194650652, -37.371672051424014 ], [ -68.678153856115557, -37.426294040537528 ], [ -68.506846482679009, -37.447378024476222 ], [ -68.427523159366274, -37.537760105044811 ], [ -68.24939449655875, -37.557035413853271 ], [ -68.252133347675851, -38.659293714533305 ], [ -68.01041683626795, -38.975501803965074 ], [ -68.258437873109358, -38.996327407284014 ], [ -68.320914680368219, -38.961807550178321 ], [ -68.604566615656779, -39.129600925242528 ], [ -68.67146175795375, -39.213626803534169 ], [ -68.797733120287262, -39.293466891683693 ], [ -68.835198534085066, -39.374340508607588 ], [ -68.962219204352778, -39.488700452963542 ], [ -69.244475878359083, -39.585490410853765 ], [ -69.364029304109067, -39.717161961055638 ], [ -69.516061366938516, -39.821910088979394 ], [ -69.680392422272462, -39.823150322429456 ], [ -69.944717372808498, -39.947380465636002 ], [ -70.095638394296429, -40.441303805825953 ], [ -70.180232713369037, -40.465643405718595 ], [ -70.238937140736425, -40.549824313641182 ], [ -70.444816047222787, -40.566877537068706 ], [ -70.536309170032155, -40.512203871111751 ], [ -70.680512254936616, -40.590183608186976 ], [ -70.812080450552344, -40.584964287471905 ], [ -70.971502245332317, -40.640361423840659 ], [ -71.130226407222892, -40.779474379239218 ], [ -71.026279263177457, -40.906805107869445 ], [ -71.148003099263633, -41.05124073677058 ], [ -71.297322150296964, -41.095114027890077 ], [ -71.553740606743588, -41.031965427062801 ], [ -71.867401588999911, -41.010235286999929 ], [ -71.851449340999949, -40.938326924999942 ], [ -71.955577352999853, -40.72035573299992 ], [ -71.853102986999914, -40.616382751999964 ], [ -71.861836303999979, -40.549720153999942 ], [ -71.796413940999912, -40.414534606999922 ], [ -71.729286255999881, -40.421355895999881 ], [ -71.67404414899994, -40.32410085099994 ], [ -71.68670487499989, -40.288547464999894 ], [ -71.742670450999896, -40.296505635999949 ], [ -71.81599930899992, -40.227155862999908 ], [ -71.814035603999884, -40.092900492999931 ], [ -71.683707641999973, -40.098998311999893 ], [ -71.680503702999914, -40.009494730999876 ], [ -71.61663163299994, -39.909862568999898 ], [ -71.684586140999926, -39.833484802999948 ], [ -71.714351766999897, -39.601354267999881 ], [ -71.689753783999919, -39.568384704999914 ], [ -71.617820190999879, -39.616650492999923 ], [ -71.503511922999905, -39.601664326999952 ], [ -71.495657104999879, -39.565594176999952 ], [ -71.541959187999879, -39.532314554999914 ], [ -71.46165401199994, -39.433819274999863 ], [ -71.476536824999897, -39.382969665999937 ], [ -71.412044636999951, -39.317960713999881 ], [ -71.430234741999897, -38.999117126999934 ], [ -71.399900674999884, -38.910543720999968 ], [ -71.236034708999938, -38.811635029999906 ], [ -71.048423421999871, -38.746626077999935 ], [ -70.945044718999981, -38.747246195999907 ], [ -70.87383459499992, -38.691435648999942 ], [ -70.883420572999938, -38.643066507999905 ], [ -70.83430212499988, -38.564414977999931 ], [ -70.97375097699998, -38.424681904999957 ], [ -71.019743000999966, -38.234305927999941 ], [ -71.007418171999916, -38.071008402999965 ], [ -71.185030069999897, -37.706069436999911 ], [ -71.190766154999949, -37.640026957999879 ], [ -71.127927611999951, -37.584423115999954 ], [ -71.117695678999979, -37.466497497999924 ], [ -71.205597289999872, -37.292657978999983 ], [ -71.146479451999909, -37.214833271999936 ], [ -71.139296427999852, -37.133287861999889 ], [ -71.089118611999936, -37.103418884999968 ], [ -71.207147583999898, -36.972367451999958 ], [ -71.135679077999981, -36.951490173999986 ], [ -71.195158650999929, -36.839145608999956 ], [ -71.145342569999912, -36.688250426999957 ], [ -71.057440958999905, -36.687630309999903 ], [ -71.043281615999973, -36.484335224999953 ], [ -70.934967813999947, -36.472552998999859 ], [ -70.890371053999928, -36.400412699999947 ], [ -70.807197835999915, -36.433382262999913 ], [ -70.71865026899988, -36.414572041999904 ], [ -70.710511230999941, -36.265847269999895 ], [ -70.604367838999906, -36.194637145999948 ], [ -70.581423502999883, -36.143167418999951 ], [ -70.499128784999925, -36.163631285999926 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-U", "NAME_1": "Chubut" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.923796346999922, -42.176907653999962 ], [ -71.749440063999941, -42.10435394299995 ], [ -71.739569865999869, -42.031903584999966 ], [ -71.769259569273686, -41.999606621748171 ], [ -65.127207810591983, -42.000226738473202 ], [ -65.054595506999931, -42.010674737999921 ], [ -64.972401495999918, -42.126885674999926 ], [ -64.857289191999939, -42.193617445999905 ], [ -64.602894660999937, -42.258233330999929 ], [ -64.480865037999934, -42.254652601999908 ], [ -64.464222785999937, -42.275323174999926 ], [ -64.602284308999913, -42.422051690999922 ], [ -64.445057745999918, -42.446709893999923 ], [ -64.103586391999954, -42.427829684999949 ], [ -64.051584438999953, -42.372247002999927 ], [ -64.068430141999954, -42.269626559999949 ], [ -64.339711066999939, -42.237399997999944 ], [ -64.162180141999954, -42.209405205999929 ], [ -63.87091450999992, -42.083712721999916 ], [ -63.76864810099994, -42.077723186999947 ], [ -63.59797115799995, -42.299981377999927 ], [ -63.579335089999915, -42.592950127999927 ], [ -63.633290167999917, -42.714613539999903 ], [ -63.620269334999932, -42.75123463299991 ], [ -63.671498175999943, -42.802178643999923 ], [ -64.107899542999917, -42.883721612999921 ], [ -64.251332160999937, -42.77507903399993 ], [ -64.202381964999915, -42.635430596999925 ], [ -64.388050910999937, -42.51726653399993 ], [ -64.614857550999943, -42.51531340899993 ], [ -64.734730597999942, -42.55787525799991 ], [ -64.804025844999899, -42.621514580999929 ], [ -64.946034308999913, -42.654229424999926 ], [ -65.018910285999937, -42.746840101999908 ], [ -64.997141079999949, -42.78484465899993 ], [ -64.645497199999909, -42.925388278999947 ], [ -64.503163214999915, -42.937269789999903 ], [ -64.433461066999939, -42.976332289999903 ], [ -64.315785285999937, -42.95045338299991 ], [ -64.302113410999937, -42.980889580999929 ], [ -64.44758053299995, -43.068617445999905 ], [ -64.765248175999943, -43.147393487999921 ], [ -64.943918423999946, -43.239434502999927 ], [ -65.032338019999941, -43.299411716999941 ], [ -65.039051886999914, -43.395603122999944 ], [ -65.330799933999913, -43.66334400799991 ], [ -65.318226691999939, -43.832207940999922 ], [ -65.271962042999917, -43.964043877999927 ], [ -65.22860967999992, -43.975253423999902 ], [ -65.241977130999942, -44.027267402999939 ], [ -65.186707583999919, -44.035539424999911 ], [ -65.237863735999952, -44.084161065999922 ], [ -65.2148171259999, -44.137434820999943 ], [ -65.282567470999936, -44.154517219999946 ], [ -65.30870792199994, -44.200084510999943 ], [ -65.216884701999902, -44.366410337999923 ], [ -65.331590022999933, -44.460759638999946 ], [ -65.279277940999918, -44.516263273999925 ], [ -65.373101766999923, -44.516183220999949 ], [ -65.36122495099994, -44.540394157999913 ], [ -65.393308255999898, -44.551921981999953 ], [ -65.356328053999903, -44.574118015999943 ], [ -65.36867923099993, -44.586061982999922 ], [ -65.461812047999899, -44.576558053999918 ], [ -65.460914654999954, -44.600993420999941 ], [ -65.64320848299991, -44.667999982999902 ], [ -65.727100467999946, -44.809604833999913 ], [ -65.715443141999913, -44.869962545999954 ], [ -65.52139967599993, -44.931897591999927 ], [ -65.605435772999954, -44.97274058499994 ], [ -65.602642604999915, -45.02768655299991 ], [ -65.690618944999926, -45.062721426999929 ], [ -65.75137518799994, -45.023645878999901 ], [ -65.817396704999908, -45.040290191999929 ], [ -65.841591843999936, -45.003216459999919 ], [ -65.936237910999921, -45.04868440599995 ], [ -66.016356974999951, -45.003107233999913 ], [ -66.200366618999908, -44.992919196999935 ], [ -66.281578807999949, -45.057602903999907 ], [ -66.349707295999906, -45.043450413999949 ], [ -66.496589922999931, -45.088381841999933 ], [ -66.525300853999909, -45.131880123999906 ], [ -66.454758083999934, -45.149340906999953 ], [ -66.473302345999912, -45.168673843999954 ], [ -66.587798631999931, -45.139336846999925 ], [ -66.52399711399994, -45.216097126999955 ], [ -66.929265871999917, -45.256533542999932 ], [ -67.06479532499992, -45.349948803999951 ], [ -67.331924500999946, -45.613491404999934 ], [ -67.364597391999951, -45.786610410999913 ], [ -67.455873973999928, -45.825002835999953 ], [ -67.581661577619684, -46.000030059539597 ], [ -71.649163192227547, -45.999414157937053 ], [ -71.612290812999873, -45.970526224999915 ], [ -71.624383097999953, -45.934146015999929 ], [ -71.758483438999889, -45.848156432999971 ], [ -71.749026651999912, -45.7867648309999 ], [ -71.798532674999876, -45.739945983999874 ], [ -71.782409627999897, -45.641760762999894 ], [ -71.742825480999841, -45.59432179799991 ], [ -71.765098022999894, -45.572410990999941 ], [ -71.713731648999925, -45.53324025499991 ], [ -71.48909419799989, -45.498513691999875 ], [ -71.508317830999914, -45.408389993999975 ], [ -71.389358683999916, -45.370769550999867 ], [ -71.311533976999954, -45.299456074999895 ], [ -71.317166706999899, -45.267209980999922 ], [ -71.487182169999897, -45.123342793999939 ], [ -71.588726358999878, -44.978132018999887 ], [ -71.702362833999956, -44.973687845999876 ], [ -71.782461303999924, -44.92738576299989 ], [ -71.889431518999885, -44.947229512999883 ], [ -72.073502970999897, -44.902167663999933 ], [ -72.088747518999924, -44.782795104999906 ], [ -72.047819783999898, -44.7547864779999 ], [ -71.854549927999898, -44.790959980999929 ], [ -71.762669229999943, -44.754373066999889 ], [ -71.631204386999912, -44.780004576999943 ], [ -71.497104044999872, -44.742900899999967 ], [ -71.297839721999935, -44.795610859999982 ], [ -71.238153442999931, -44.747861836999917 ], [ -71.234897826999941, -44.638824563999975 ], [ -71.131648314999978, -44.570611673999863 ], [ -71.122656616999933, -44.53030405699991 ], [ -71.209783080999898, -44.427571308999887 ], [ -71.822045450999951, -44.403180033999959 ], [ -71.860596069999929, -44.377135110999888 ], [ -71.804010376999969, -44.314813334999954 ], [ -71.831812296999914, -44.270164896999916 ], [ -71.805095580999961, -44.205155944999959 ], [ -71.858735717999934, -44.107797546999905 ], [ -71.762204141999916, -44.06407928499992 ], [ -71.659884806999912, -43.926309915999894 ], [ -71.761842407999922, -43.828434753 ], [ -71.755021118999963, -43.771383971999896 ], [ -71.819203246999905, -43.758051452999965 ], [ -71.709184122999915, -43.684360859999956 ], [ -71.714300089999881, -43.602195332999926 ], [ -71.800703084999952, -43.544214374999882 ], [ -71.873825235999931, -43.538943379999935 ], [ -71.868812621999979, -43.462565612999896 ], [ -71.955112264999912, -43.443548685999929 ], [ -71.901730509999908, -43.322005716999897 ], [ -71.750680297999878, -43.295340677999945 ], [ -71.742980508999977, -43.190127461999879 ], [ -71.861887980999882, -43.133180033999892 ], [ -72.054434366999914, -43.105378112999944 ], [ -72.148537150999886, -42.99871795599995 ], [ -72.112673705999924, -42.863842467999916 ], [ -72.143214477999919, -42.557091165999879 ], [ -72.039189819999962, -42.481230163999953 ], [ -72.075208292999946, -42.433791198999955 ], [ -72.069885620999912, -42.3499720249999 ], [ -72.133706013999955, -42.287598571999936 ], [ -72.009837605999905, -42.124714456999897 ], [ -71.923796346999922, -42.176907653999962 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-R", "NAME_1": "Río Negro" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.769259569273686, -41.999606621748171 ], [ -71.794036824999949, -41.86746917699989 ], [ -71.925915079999896, -41.653011983999917 ], [ -71.853258015999955, -41.567332458999942 ], [ -71.888087931999905, -41.512762145999915 ], [ -71.903952595999925, -41.367654723999891 ], [ -71.853981486999942, -41.078886819999923 ], [ -71.867401588999911, -41.010235286999929 ], [ -71.553740606743588, -41.031965427062801 ], [ -71.297322150296964, -41.095114027890077 ], [ -71.148003099263633, -41.05124073677058 ], [ -71.026279263177457, -40.906805107869445 ], [ -71.130226407222892, -40.779474379239218 ], [ -70.971502245332317, -40.640361423840659 ], [ -70.812080450552344, -40.584964287471905 ], [ -70.680512254936616, -40.590183608186976 ], [ -70.536309170032155, -40.512203871111751 ], [ -70.444816047222787, -40.566877537068706 ], [ -70.238937140736425, -40.549824313641182 ], [ -70.180232713369037, -40.465643405718595 ], [ -70.095638394296429, -40.441303805825953 ], [ -69.944717372808498, -39.947380465636002 ], [ -69.680392422272462, -39.823150322429456 ], [ -69.516061366938516, -39.821910088979394 ], [ -69.364029304109067, -39.717161961055638 ], [ -69.244475878359083, -39.585490410853765 ], [ -68.962219204352778, -39.488700452963542 ], [ -68.835198534085066, -39.374340508607588 ], [ -68.797733120287262, -39.293466891683693 ], [ -68.67146175795375, -39.213626803534169 ], [ -68.604566615656779, -39.129600925242528 ], [ -68.320914680368219, -38.961807550178321 ], [ -68.258437873109358, -38.996327407284014 ], [ -68.01041683626795, -38.975501803965074 ], [ -68.252133347675851, -38.659293714533305 ], [ -68.24939449655875, -37.557035413853271 ], [ -67.850323248818881, -37.600236912303671 ], [ -67.748598191952965, -37.669069920040783 ], [ -67.711752895779512, -37.734750664611454 ], [ -67.72369015217879, -37.816864515884674 ], [ -67.848256192169515, -37.907763359491469 ], [ -67.871743130441132, -38.007240492554672 ], [ -67.84489722432744, -38.056901544270829 ], [ -67.705655076820335, -38.100568128915995 ], [ -67.591992763555197, -38.247122491309938 ], [ -67.375959439176768, -38.255545750236195 ], [ -67.176591762799603, -38.222627861786407 ], [ -67.135767381159724, -38.338073011760059 ], [ -67.069828254170602, -38.408973077045857 ], [ -66.647941860828212, -38.557387790514099 ], [ -66.593500738867988, -38.607307223749388 ], [ -66.56195227687607, -38.70156503699684 ], [ -66.391859300266503, -38.734172866184849 ], [ -66.215229255126019, -38.716602878819799 ], [ -65.960180223338625, -38.742131036218325 ], [ -65.689550747369083, -38.817888686113974 ], [ -65.562995165094776, -38.775824070124713 ], [ -65.367399867709707, -38.838352552428375 ], [ -64.970163132622474, -38.803574313803551 ], [ -64.471485562408759, -38.853700452613793 ], [ -64.010221727350824, -38.999789727913594 ], [ -63.908160772801409, -39.092238865131492 ], [ -63.782121955363948, -39.128360690893146 ], [ -63.71122189007815, -39.20019093216581 ], [ -63.516401739948321, -39.305972588863881 ], [ -63.388580084902969, -39.325764661609867 ], [ -63.387417364919429, -40.709091077890946 ], [ -63.10301611989803, -40.753946221840636 ], [ -62.861454637221698, -40.938379409182403 ], [ -62.801625129196339, -41.041680597181823 ], [ -63.099517381999931, -41.154880466999941 ], [ -63.779408331999946, -41.158786716999941 ], [ -64.062855597999942, -41.041273695999905 ], [ -64.062123175999943, -40.999444268999923 ], [ -64.174305792999917, -41.008965752999927 ], [ -64.64476477799991, -40.846449476999908 ], [ -64.911203579999949, -40.823825778999947 ], [ -64.867990688999953, -40.792168877999927 ], [ -64.744984503999945, -40.797295830999929 ], [ -64.800282355999911, -40.758884372999944 ], [ -64.771636522999927, -40.736504815999922 ], [ -64.796213344999899, -40.723321221999925 ], [ -64.981841600999928, -40.723321221999925 ], [ -64.922474738999938, -40.729668877999927 ], [ -64.90884355399993, -40.770114841999941 ], [ -65.010853644999941, -40.76726653399993 ], [ -65.121937628999945, -40.83367278399993 ], [ -65.175689256999931, -40.969170830999929 ], [ -65.104888475999928, -41.32976653399993 ], [ -65.06118730399993, -41.448418877999927 ], [ -64.991363084999932, -41.524102471999925 ], [ -65.037220831999946, -41.665134372999944 ], [ -64.999908006999931, -41.793389580999929 ], [ -65.07453365799995, -41.950941664999903 ], [ -65.054595506999931, -42.010674737999921 ], [ -71.769259569273686, -41.999606621748171 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-Z", "NAME_1": "Santa Cruz" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.912530884999853, -47.23453175899995 ], [ -71.863283243999973, -47.196601256999955 ], [ -71.874135294999917, -47.142547709999874 ], [ -72.005186726999938, -47.061932474999963 ], [ -71.914804646999869, -46.998473815999915 ], [ -71.970356811999864, -46.94845102999993 ], [ -71.950099649999856, -46.813988952999892 ], [ -71.834086059999947, -46.788564147999892 ], [ -71.680193644999918, -46.659579772999933 ], [ -71.680503702999914, -46.538140156999944 ], [ -71.751868855999902, -46.39303273499992 ], [ -71.763341023999914, -46.244514668999955 ], [ -71.912634236999878, -46.142091979999933 ], [ -71.770162312999872, -46.112636413999937 ], [ -71.649163192227547, -45.999414157937053 ], [ -67.581661577619684, -46.000030059539597 ], [ -67.622466600999928, -46.16375090899993 ], [ -67.540882941999939, -46.401299737999921 ], [ -67.423219764999942, -46.567419448999942 ], [ -67.129994791999934, -46.706595608999919 ], [ -67.033192511999914, -46.819105726999908 ], [ -66.786447719999899, -47.006605726999908 ], [ -66.628795452999952, -47.051218087999928 ], [ -66.505238410999937, -47.040785414999903 ], [ -66.200492770999915, -47.089586768999936 ], [ -65.979562954999949, -47.066176039999903 ], [ -65.881155731999911, -47.096555184999943 ], [ -65.744902193999906, -47.204164007999907 ], [ -65.713013816999933, -47.341497173999926 ], [ -65.73566515999994, -47.50953542499991 ], [ -65.845625843999926, -47.742205726999941 ], [ -66.032064417999948, -47.739525295999954 ], [ -66.273915167999917, -47.859470309999949 ], [ -66.389149542999917, -47.863864841999941 ], [ -66.30109615799995, -47.872491143999923 ], [ -66.02257205199993, -47.770993068999928 ], [ -65.901824013999942, -47.769949847999953 ], [ -65.853409382999928, -47.879590371999939 ], [ -65.761738816999923, -47.911907625999902 ], [ -65.795121458999915, -47.935934179999947 ], [ -65.761952337999901, -47.94855158699994 ], [ -65.927384798999924, -47.941408740999918 ], [ -65.968445, -48.047168107999937 ], [ -65.903187628999945, -48.078545830999929 ], [ -65.917237455999953, -48.113813629999925 ], [ -66.108631964999915, -48.123304945999905 ], [ -66.159535285999937, -48.185316664999903 ], [ -66.316883917999917, -48.264255466999941 ], [ -66.354987535999953, -48.321216130999915 ], [ -66.341114641999923, -48.352724522999949 ], [ -66.448597785999937, -48.350274346999925 ], [ -66.501055556999916, -48.413988107999955 ], [ -66.650990363999938, -48.431084893999923 ], [ -66.857811500999901, -48.548307111999918 ], [ -66.866435494999905, -48.589834355999926 ], [ -67.114348487999905, -48.673750085999927 ], [ -67.198284666999939, -48.818353344999935 ], [ -67.405736886999932, -48.904235248999953 ], [ -67.556548697999915, -49.01581686399993 ], [ -67.632557745999918, -49.129978122999944 ], [ -67.609929546999922, -49.178107403999945 ], [ -67.732329881999931, -49.27467213299991 ], [ -67.711903449999909, -49.315606377999927 ], [ -67.774312151999936, -49.37440818999994 ], [ -67.830881313999953, -49.379571221999925 ], [ -67.725183958999935, -49.390745539999955 ], [ -67.663207323999927, -49.267152912999904 ], [ -67.60765540299991, -49.265069268999923 ], [ -67.700062628999945, -49.534274997999944 ], [ -67.732012047999945, -49.781301772999939 ], [ -67.833207005999952, -49.954540455999904 ], [ -68.076350219999938, -50.087267966999946 ], [ -68.341867641999954, -50.117608330999929 ], [ -68.654042120999918, -49.757907809999949 ], [ -68.739735480999911, -49.727715752999927 ], [ -68.664051886999914, -49.767510674999926 ], [ -68.577272287999904, -49.927615881999941 ], [ -68.674387173999946, -49.968357028999947 ], [ -68.875379085999953, -49.962495301999923 ], [ -69.013498501999948, -50.007745049999926 ], [ -68.583469757999922, -49.970337441999902 ], [ -68.518851004999931, -50.015666031999956 ], [ -68.493753645999902, -50.08011367499995 ], [ -68.349872666999943, -50.148810460999925 ], [ -68.438099738999938, -50.200778903999947 ], [ -68.876429323999901, -50.330572018999931 ], [ -69.076518607999901, -50.5601720599999 ], [ -69.149973110999952, -50.742120049999926 ], [ -69.136799819999908, -50.903480807999927 ], [ -69.410715298999946, -51.083916924999926 ], [ -69.167778304999899, -50.978224847999911 ], [ -68.962554490999935, -51.560153903999947 ], [ -69.047596808999913, -51.563164971999925 ], [ -69.119618292999917, -51.60475025799991 ], [ -69.37718665299991, -51.556898695999905 ], [ -69.616810675999943, -51.625176690999922 ], [ -69.304558921999899, -51.593489703999921 ], [ -69.156982355999901, -51.634883308999918 ], [ -69.218902147999927, -51.680433851999908 ], [ -69.198963995999918, -51.686618747999944 ], [ -69.028920050999943, -51.614190362999921 ], [ -68.973511143999929, -51.619951743999934 ], [ -68.685059011999954, -52.005006357999946 ], [ -68.365610640999932, -52.306203708999931 ], [ -68.362472384999933, -52.339071520999937 ], [ -68.417814782999926, -52.386051570999939 ], [ -68.442451000999938, -52.379480573999956 ], [ -68.454499063999975, -52.299907327999861 ], [ -68.820497396999912, -52.243166605999939 ], [ -69.212256428999865, -52.13795338999995 ], [ -69.485288859999855, -52.13247568699996 ], [ -69.952753865999881, -52.007418721999976 ], [ -71.917698527999875, -51.990055439999963 ], [ -71.965240844999869, -51.970625101999893 ], [ -71.948497680999935, -51.896004332999915 ], [ -71.981725626999946, -51.844948018999936 ], [ -72.14212927199992, -51.739424742999873 ], [ -72.300724243999923, -51.691469014999939 ], [ -72.330903279999916, -51.599381611999917 ], [ -72.450069132999914, -51.552666117999927 ], [ -72.35121211799995, -51.475978291999894 ], [ -72.320464640999887, -51.312577412999893 ], [ -72.258814656999846, -51.245191345999977 ], [ -72.382217977999886, -51.160597025999898 ], [ -72.404593872999953, -51.105820006999913 ], [ -72.293437866999852, -51.029235534999906 ], [ -72.265946004999876, -50.960712584999982 ], [ -72.263465535999899, -50.836275736999973 ], [ -72.347388061999908, -50.743154805999971 ], [ -72.302842977999916, -50.648896993999962 ], [ -72.505983032999893, -50.601251321999918 ], [ -72.662614298999955, -50.667810566999904 ], [ -72.755786905999884, -50.616444193999946 ], [ -73.05173783399988, -50.757830911999868 ], [ -73.177724975999922, -50.749459329999894 ], [ -73.192246053999952, -50.641352233999918 ], [ -73.261854207999875, -50.55660288499989 ], [ -73.284333455999871, -50.333050638999943 ], [ -73.346345174999925, -50.243650410999955 ], [ -73.530571655999978, -50.140814310999914 ], [ -73.531501831999947, -50.083143411999941 ], [ -73.478585164999856, -50.009452819999922 ], [ -73.568398803999855, -49.920052591999934 ], [ -73.465097615999895, -49.759959004999935 ], [ -73.196749612564901, -49.682423211773184 ], [ -73.059744674589552, -49.554970792414601 ], [ -73.057423510851791, -49.475919864136046 ], [ -73.118651507246582, -49.392427141779507 ], [ -73.097626505999955, -49.266552428999965 ], [ -73.183151000999885, -49.239060566999903 ], [ -73.171317097999889, -49.1893478389999 ], [ -73.009724894999863, -48.990393574999935 ], [ -72.781211710999884, -48.933859557999973 ], [ -72.618792684999846, -48.819654641999946 ], [ -72.578019978999862, -48.721882832999974 ], [ -72.614710245999845, -48.51000946099991 ], [ -72.576779743999936, -48.452131856999898 ], [ -72.295091511999885, -48.333276061999896 ], [ -72.325632283999909, -48.285527038999916 ], [ -72.309509236999901, -48.211216328999924 ], [ -72.343047241999926, -48.070449726999883 ], [ -72.509445353999922, -47.972987976 ], [ -72.543913533999898, -47.914800312999901 ], [ -72.344442505999893, -47.602261250999874 ], [ -72.320878051999898, -47.498391621999943 ], [ -72.370487426999972, -47.474517109999866 ], [ -72.361185669999941, -47.450952656999874 ], [ -72.17055131099994, -47.407544453999961 ], [ -72.038156290999979, -47.287035012999922 ], [ -72.030301473999941, -47.197531432999909 ], [ -71.912530884999853, -47.23453175899995 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-V", "NAME_1": "Tierra del Fuego" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -68.654135431866308, -54.886244564385144 ], [ -68.642342895999917, -54.853653258999927 ], [ -68.641997850999928, -54.799167575999945 ], [ -68.568226691999939, -54.878350518999923 ], [ -68.654135431866308, -54.886244564385144 ] ] ], [ [ [ -68.641881926766189, -54.78297131557072 ], [ -68.627616776477794, -52.639571698869695 ], [ -68.311431443999936, -52.912041924999926 ], [ -68.225819464999915, -53.102471612999921 ], [ -68.280425584999932, -53.015394789999903 ], [ -68.34956888499994, -53.016162039999926 ], [ -68.520715487999951, -53.120631403999937 ], [ -68.554798715999937, -53.167051676999904 ], [ -68.550750821999941, -53.23853671899991 ], [ -68.451350728999898, -53.297717398999907 ], [ -68.111401855999929, -53.343801801999916 ], [ -68.047678188999953, -53.523207289999903 ], [ -67.983631964999915, -53.601332289999903 ], [ -67.702461186999926, -53.774746160999939 ], [ -67.708779429999936, -53.804568288999917 ], [ -67.558247920999918, -53.836188706999906 ], [ -67.587757941999939, -53.869317315999922 ], [ -67.571522589999915, -53.907972914999903 ], [ -67.140844462999951, -54.123398269999939 ], [ -66.766581649999921, -54.249841673999924 ], [ -66.482213313999921, -54.465800354999942 ], [ -65.844227667999917, -54.647393487999921 ], [ -65.698109503999945, -54.662367445999905 ], [ -65.309315558999913, -54.626560153999947 ], [ -65.141916469999899, -54.646905205999929 ], [ -65.193714972999942, -54.690199476999908 ], [ -65.243397589999915, -54.820977471999925 ], [ -65.358957485999952, -54.926690362999921 ], [ -65.462717251999948, -54.88445403399993 ], [ -65.499663865999935, -54.933038018999923 ], [ -65.615142381999931, -54.934177341999941 ], [ -65.669097459999932, -54.971774997999944 ], [ -65.718861456999946, -54.909274997999944 ], [ -65.9662250639999, -54.902073326999925 ], [ -65.987557938999942, -54.910682792999921 ], [ -65.950828884999908, -54.939949353999907 ], [ -65.993355086999941, -54.972366361999946 ], [ -66.317068197999902, -54.994977935999941 ], [ -66.450672980999911, -55.05201588299991 ], [ -66.630067345999919, -55.031097363999947 ], [ -66.802805141999954, -54.942559502999927 ], [ -67.030995245999918, -54.905205987999921 ], [ -67.93195553299995, -54.862481377999927 ], [ -68.302072719999899, -54.792168877999927 ], [ -68.328236456999946, -54.842380466999941 ], [ -68.520334438999953, -54.852227471999925 ], [ -68.641881926766189, -54.78297131557072 ] ] ], [ [ [ -63.888417120999918, -54.729913018999923 ], [ -63.812123175999943, -54.729913018999923 ], [ -63.966786261999914, -54.815036716999941 ], [ -63.990834113999938, -54.811211846999925 ], [ -63.979644334999932, -54.757419528999947 ], [ -64.244536912999934, -54.837090752999927 ], [ -64.270741339999915, -54.824883721999925 ], [ -64.251576300999943, -54.77703215899993 ], [ -64.311105923999946, -54.777601820999905 ], [ -64.445139126999948, -54.843357028999947 ], [ -64.506581183999913, -54.827325127999927 ], [ -64.624419725999928, -54.903741143999923 ], [ -64.68976803299995, -54.900567315999922 ], [ -64.66860917899993, -54.86646900799991 ], [ -64.758656378999945, -54.832289320999905 ], [ -64.683094855999911, -54.770196221999925 ], [ -64.60374915299991, -54.79810963299991 ], [ -64.522572394999941, -54.781670830999929 ], [ -64.504750128999945, -54.770928643999923 ], [ -64.569894985999952, -54.722100518999923 ], [ -64.542347785999937, -54.715590101999908 ], [ -64.497914191999939, -54.750420830999929 ], [ -64.407053188999953, -54.74382903399993 ], [ -64.384388800999943, -54.78443775799991 ], [ -64.363880988999938, -54.705987237999921 ], [ -64.187163865999935, -54.747002862999921 ], [ -64.158762173999946, -54.715590101999908 ], [ -64.093251105999911, -54.715590101999908 ], [ -64.065988735999952, -54.750420830999929 ], [ -63.888417120999918, -54.729913018999923 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-B", "NAME_1": "Buenos Aires" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -56.668324347999942, -36.736423434999949 ], [ -56.686431443999936, -36.927666924999926 ], [ -57.055897589999915, -37.412692966999941 ], [ -57.487416144999941, -37.832207940999922 ], [ -57.528879360999952, -37.913669528999947 ], [ -57.558420376999948, -38.120863539999903 ], [ -58.155669725999928, -38.430108330999929 ], [ -59.063221808999913, -38.693780205999929 ], [ -59.632394985999952, -38.783786716999941 ], [ -59.796864386999914, -38.838474216999941 ], [ -61.143381313999953, -39.001071872999944 ], [ -61.42804928299995, -38.982517184999949 ], [ -61.518055792999917, -39.011488539999903 ], [ -61.722808397999927, -38.968194268999923 ], [ -61.839019334999932, -38.980889580999929 ], [ -62.064035610999952, -38.922946872999944 ], [ -62.157338019999941, -38.810479424999926 ], [ -62.379750128999945, -38.798435153999947 ], [ -62.373931443999936, -38.899997653999947 ], [ -62.336008266999954, -38.896905205999929 ], [ -62.320464647999927, -38.960707289999903 ], [ -62.274037238999938, -38.954522393999923 ], [ -62.357818162999934, -39.102227471999925 ], [ -62.339182094999899, -39.194105726999908 ], [ -62.257232225999928, -39.25554778399993 ], [ -62.325591600999928, -39.254652601999908 ], [ -62.167876756999931, -39.283379815999922 ], [ -62.023915167999917, -39.364841403999947 ], [ -62.056996222999942, -39.411553643999923 ], [ -62.188343878999945, -39.310723565999922 ], [ -62.283924933999913, -39.310723565999922 ], [ -62.154204881999931, -39.42742278399993 ], [ -62.055775519999941, -39.451918226999908 ], [ -62.114369269999941, -39.821465752999927 ], [ -62.164173956999946, -39.858819268999923 ], [ -62.305043097999942, -39.811130466999941 ], [ -62.283924933999913, -39.852634372999944 ], [ -62.314564581999946, -39.869398695999905 ], [ -62.366322394999941, -40.054131768999923 ], [ -62.339182094999899, -40.112725518999923 ], [ -62.35968990799995, -40.191827080999929 ], [ -62.490061001999948, -40.30787525799991 ], [ -62.414906378999945, -40.462090752999927 ], [ -62.328684048999946, -40.496270440999922 ], [ -62.283680792999917, -40.564385674999926 ], [ -62.264149542999917, -40.551527601999908 ], [ -62.267201300999943, -40.633477471999925 ], [ -62.34601803299995, -40.59929778399993 ], [ -62.329741990999935, -40.669122002999927 ], [ -62.181548631999931, -40.62664153399993 ], [ -62.229237433999913, -40.658623955999929 ], [ -62.337798631999931, -40.87273528399993 ], [ -62.751332160999937, -41.04420338299991 ], [ -62.801625129196339, -41.041680597181823 ], [ -62.861454637221698, -40.938379409182403 ], [ -63.117795580201857, -40.74614307963941 ], [ -63.387417364919429, -40.709091077890946 ], [ -63.381887986741162, -34.579646091094219 ], [ -63.373593919923451, -34.413609713417543 ], [ -63.339616665176948, -34.380485121191384 ], [ -61.710517136756437, -34.376816094986793 ], [ -60.963069220867851, -33.677220553885434 ], [ -60.910462613358902, -33.563739108672905 ], [ -60.671510789691183, -33.576916598522189 ], [ -60.566762660868108, -33.640323581767859 ], [ -60.47565711078704, -33.622185153621956 ], [ -60.410131394947882, -33.459559421530059 ], [ -60.347809618219287, -33.410053398545529 ], [ -60.34052324085485, -33.346439710624168 ], [ -60.27752966965852, -33.306442153082912 ], [ -60.294091965771599, -33.256574394892425 ], [ -60.118082038255466, -33.393568616798234 ], [ -59.640617642290351, -33.671019382138752 ], [ -59.520702481334411, -33.655309746747434 ], [ -59.392648281393065, -33.739387301882459 ], [ -59.268934903023364, -33.721248874635876 ], [ -59.231314459594614, -33.797988376462399 ], [ -59.031817592907601, -33.829562676876037 ], [ -58.638508267342672, -34.048515719524858 ], [ -58.446970686747761, -34.006940156662893 ], [ -58.395375128999945, -34.031182549999926 ], [ -58.378570115999935, -34.188246351999908 ], [ -58.460194464999915, -34.272881768999923 ], [ -58.570423956999946, -34.288181247999944 ], [ -58.454607113999941, -34.366182764999905 ], [ -58.511465270999906, -34.435944762999952 ], [ -58.474191861065549, -34.521579685054405 ], [ -58.538480224882449, -34.567009778178715 ], [ -58.560532174320372, -34.653642438547706 ], [ -58.541630503245131, -34.710347452672806 ], [ -58.443971868606866, -34.774928162704555 ], [ -58.315030934430069, -34.657194617637515 ], [ -57.965031436999936, -34.824530286999902 ], [ -57.871032093999929, -34.829914576999954 ], [ -57.522032339999953, -35.013153725999928 ], [ -57.248768683999913, -35.248793226999908 ], [ -57.128143504999912, -35.441320754999936 ], [ -57.352625390999947, -35.727523632999919 ], [ -57.393299933999913, -35.86296965899993 ], [ -57.366444464999915, -35.987888278999947 ], [ -57.248036261999914, -36.170342705999929 ], [ -57.108265753999945, -36.282321872999944 ], [ -56.93773352799991, -36.350762627999927 ], [ -56.939198370999918, -36.384860934999949 ], [ -56.856678839999915, -36.343926690999922 ], [ -56.76789303299995, -36.343926690999922 ], [ -56.77603105399993, -36.306410414999903 ], [ -56.740589972999942, -36.316582940999922 ], [ -56.697621222999942, -36.39617278399993 ], [ -56.668324347999942, -36.736423434999949 ] ] ], [ [ [ -61.907215949999909, -39.136651299999926 ], [ -61.868275519999941, -39.239434502999927 ], [ -62.026844855999911, -39.18287525799991 ], [ -62.098011847999942, -39.087823174999926 ], [ -61.907215949999909, -39.136651299999926 ] ] ], [ [ [ -62.085926886999914, -39.023370049999926 ], [ -62.130767381999931, -39.020603122999944 ], [ -62.040191209999932, -39.005466403999947 ], [ -61.967274542999917, -39.046970309999949 ], [ -62.010243292999917, -39.064385674999926 ], [ -62.085926886999914, -39.023370049999926 ] ] ], [ [ [ -62.155299648999915, -40.374205078999921 ], [ -62.093997489999936, -40.377419249999946 ], [ -62.028517293999926, -40.454881721999925 ], [ -62.10870882599994, -40.564063739999938 ], [ -62.161339835999911, -40.557101384999953 ], [ -62.165729508999902, -40.509400967999909 ], [ -62.237325909999925, -40.509949104999919 ], [ -62.155299648999915, -40.374205078999921 ] ] ], [ [ [ -62.118961952999939, -40.130719995999925 ], [ -62.014659846999905, -40.175163236999936 ], [ -62.021164559999931, -40.343552548999924 ], [ -62.133179519999942, -40.181094019999932 ], [ -62.118961952999939, -40.130719995999925 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-C", "NAME_1": "Ciudad de Buenos Aires" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -58.474191861065549, -34.521579685054405 ], [ -58.378771882999899, -34.57250942099995 ], [ -58.315030934430069, -34.657194617637515 ], [ -58.443971868606866, -34.774928162704555 ], [ -58.541630503245131, -34.710347452672806 ], [ -58.560532174320372, -34.653642438547706 ], [ -58.538480224882449, -34.567009778178715 ], [ -58.474191861065549, -34.521579685054405 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-S", "NAME_1": "Santa Fe" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -59.597441983160991, -28.00040943764543 ], [ -58.864747687355873, -27.999324232926995 ], [ -58.920299851556877, -28.094822279624509 ], [ -59.059929571792281, -28.129445488618387 ], [ -59.087524786739493, -28.175230807655623 ], [ -59.066208258804068, -28.401366875780695 ], [ -59.086956345958583, -28.627089531856427 ], [ -59.194391649055376, -28.921386814150139 ], [ -59.197440557635616, -29.022052503820021 ], [ -59.358877733120892, -29.143492119965345 ], [ -59.511271532055559, -29.207570895880167 ], [ -59.582895066853837, -29.377793063698959 ], [ -59.5910857808841, -29.614987888180508 ], [ -59.6727862210073, -29.847118421577875 ], [ -59.595349087190641, -30.049173272228757 ], [ -59.669298061955999, -30.293861178750376 ], [ -59.61477942562999, -30.462688083488274 ], [ -59.660642259033011, -30.736056409675541 ], [ -60.163660650818372, -31.442059828098593 ], [ -60.414110480414308, -31.673518568826864 ], [ -60.647765469001172, -31.716048271910211 ], [ -60.674042935233274, -31.85288746508445 ], [ -60.719957444580416, -31.922340589546593 ], [ -60.66179561957216, -32.069256687146378 ], [ -60.706934984362022, -32.156176446186066 ], [ -60.767008836388698, -32.578321221946851 ], [ -60.705823941221922, -32.679503675554201 ], [ -60.675464036735889, -32.846521905161808 ], [ -60.552112392672768, -33.061082452093501 ], [ -60.294091965771599, -33.256574394892425 ], [ -60.27752966965852, -33.306442153082912 ], [ -60.34052324085485, -33.346439710624168 ], [ -60.347809618219287, -33.410053398545529 ], [ -60.410131394947882, -33.459559421530059 ], [ -60.430569423739882, -33.547926120494083 ], [ -60.49991919631384, -33.634019057233729 ], [ -60.582937385152206, -33.635207614739613 ], [ -60.67763444707208, -33.575676365072184 ], [ -60.910462613358902, -33.563739108672905 ], [ -60.963069220867851, -33.677220553885434 ], [ -61.710517136756437, -34.376816094986793 ], [ -62.853806524651361, -34.38213876669073 ], [ -61.91991004071582, -33.114102471651734 ], [ -61.76283952522391, -32.999845880083285 ], [ -61.735295987120082, -32.81226043047451 ], [ -61.833016120097852, -32.676919854067989 ], [ -61.894485236104742, -32.658781426821406 ], [ -61.86611487480161, -32.586176039192878 ], [ -61.914122281018422, -32.462927747917206 ], [ -62.014632941057357, -32.386291598878188 ], [ -62.078220790557054, -32.244078058055948 ], [ -62.218573981204258, -32.138503106033511 ], [ -62.184079963419549, -31.962751560036452 ], [ -62.237539231650203, -31.730982760945665 ], [ -62.121551480216624, -31.608561292869354 ], [ -61.857097336672723, -30.731457207484141 ], [ -62.12532385920872, -30.457675470146853 ], [ -62.134083014919213, -30.416851087607597 ], [ -61.709948696874847, -28.00040943764543 ], [ -59.597441983160991, -28.00040943764543 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-T", "NAME_1": "Tucumán" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -65.658699917367301, -26.074583835975261 ], [ -65.442072312886921, -26.120059095750662 ], [ -65.314379849050795, -26.076030775899596 ], [ -65.252807380256399, -26.172355644897095 ], [ -64.945720180841647, -26.274106541083995 ], [ -64.767358974936712, -26.21137135230606 ], [ -64.486342536179109, -26.220208021483018 ], [ -64.524040493074267, -26.446550795183043 ], [ -64.500631070067811, -26.677596123862031 ], [ -64.581453010148266, -26.676510919143595 ], [ -64.622070685313872, -26.79185271543048 ], [ -64.674367235359625, -26.804823499704753 ], [ -64.879832729796647, -27.309185478626944 ], [ -65.063594122670622, -27.47237965329839 ], [ -64.969594692740884, -27.513720797976475 ], [ -65.069407721689004, -27.60069223385949 ], [ -64.99915361244922, -27.778149102199336 ], [ -65.09149939598035, -27.899071953507871 ], [ -65.227589281220332, -27.923514907087281 ], [ -65.348951382100608, -27.863260186108675 ], [ -65.496952684418829, -27.961238701504897 ], [ -65.558008389275756, -28.054359633190529 ], [ -65.664565192329746, -27.945167331806942 ], [ -65.703038295580882, -27.81788827912078 ], [ -65.850832893223412, -27.780164482904581 ], [ -65.877859667389714, -27.697223810230639 ], [ -65.929329393336843, -27.654332371042074 ], [ -65.981884324901671, -27.393831475442255 ], [ -66.194636196703129, -27.319365736739371 ], [ -65.883776618296281, -26.940267428898721 ], [ -65.850962084432638, -26.752785332976714 ], [ -65.872562832308859, -26.699145195794131 ], [ -66.152028978354679, -26.537863050839121 ], [ -66.10017167788061, -26.321545504721257 ], [ -66.053817918961784, -26.253487644239385 ], [ -65.711823289713038, -26.2953972305977 ], [ -65.658699917367301, -26.074583835975261 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-G", "NAME_1": "Santiago del Estero" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -63.398579474962787, -25.659363701473637 ], [ -61.753873663938407, -25.661430759022323 ], [ -61.722325201946489, -25.744164727020518 ], [ -61.709948696874847, -28.00040943764543 ], [ -62.087134975898437, -30.156608574426173 ], [ -62.242577684312664, -29.8056222472689 ], [ -62.28815629687557, -29.776735121128922 ], [ -63.384058397077354, -29.771309095738161 ], [ -63.396331550260811, -29.72852101023642 ], [ -63.457904019055206, -29.714309990713502 ], [ -63.462709926821674, -29.655243829039478 ], [ -63.807650112762474, -29.649766126805332 ], [ -64.027585008241545, -29.545173027613146 ], [ -64.049056565807859, -29.473032728877342 ], [ -64.253746913888961, -29.424301853147995 ], [ -64.882468228126243, -29.557110284012424 ], [ -65.035430466942501, -29.292681979789563 ], [ -65.092584600698729, -28.721347345103879 ], [ -65.179995287052861, -28.645072931270761 ], [ -65.07222408717189, -28.424052830173991 ], [ -65.079097053386306, -28.274604587931378 ], [ -65.169091559427898, -27.909665622770262 ], [ -65.07261165990019, -27.889718519494068 ], [ -65.031296352744448, -27.790396416961073 ], [ -64.99915361244922, -27.778149102199336 ], [ -65.069407721689004, -27.60069223385949 ], [ -64.969594692740884, -27.513720797976475 ], [ -65.063594122670622, -27.47237965329839 ], [ -64.879832729796647, -27.309185478626944 ], [ -64.674367235359625, -26.804823499704753 ], [ -64.622070685313872, -26.79185271543048 ], [ -64.581453010148266, -26.676510919143595 ], [ -64.500631070067811, -26.677596123862031 ], [ -64.523265346718347, -26.437455742688371 ], [ -64.425002611381387, -26.027558281689323 ], [ -64.191761033944545, -25.579885348530013 ], [ -63.924387173029629, -25.652335706527651 ], [ -63.398579474962787, -25.659363701473637 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-D", "NAME_1": "San Luis" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -65.086615973848097, -35.001790866855004 ], [ -65.087778692932318, -35.998784274774437 ], [ -66.623111335419765, -35.997905775631011 ], [ -66.521127896135511, -35.494215590277292 ], [ -66.505134039904021, -35.124160658987194 ], [ -66.572003342879952, -34.852911064494037 ], [ -66.737962206190844, -34.615406182549293 ], [ -66.812608812047017, -34.3846192362887 ], [ -66.82136796685819, -34.229279880661977 ], [ -66.759201218861165, -34.184528089499736 ], [ -66.747057257786196, -34.064173678972111 ], [ -66.844002245307365, -33.896276951120399 ], [ -66.929578417210166, -33.83793425895891 ], [ -67.01967627603932, -33.616500745812743 ], [ -67.151942105443823, -33.429070325834857 ], [ -67.226950445606576, -32.91613006015416 ], [ -67.192120531037688, -32.761100762889896 ], [ -67.38986039943785, -32.304332778135176 ], [ -67.366967740368921, -31.857951756168632 ], [ -66.730520799195517, -31.8765552705093 ], [ -66.373850064229089, -31.93381275795241 ], [ -66.21716712056616, -31.925441175869594 ], [ -66.054386358843374, -31.871439303481054 ], [ -65.907289394989562, -31.900739840771053 ], [ -65.671515672010628, -31.885701999847413 ], [ -65.310529954793594, -32.061143486582637 ], [ -65.245081753320221, -32.125118909709897 ], [ -65.189658780328443, -32.327638849253503 ], [ -64.922827520873398, -32.299165134263546 ], [ -64.883191697638722, -32.61950733789331 ], [ -65.014656542265584, -32.948169447661883 ], [ -65.032484911149709, -33.111260267747184 ], [ -65.091137660774393, -33.136840101989094 ], [ -65.131703660895198, -33.205466404151252 ], [ -65.086900193788892, -33.96237110774041 ], [ -65.086615973848097, -35.001790866855004 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-L", "NAME_1": "La Pampa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -65.095788539809234, -36.001316419417208 ], [ -65.086615973848097, -35.001790866855004 ], [ -63.384058397077354, -35.002100925217519 ], [ -63.388580084902969, -39.325764661609867 ], [ -63.516401739948321, -39.305972588863881 ], [ -63.71122189007815, -39.20019093216581 ], [ -63.782121955363948, -39.128360690893146 ], [ -63.908160772801409, -39.092238865131492 ], [ -64.010221727350824, -38.999789727913594 ], [ -64.471485562408759, -38.853700452613793 ], [ -64.970163132622474, -38.803574313803551 ], [ -65.367399867709707, -38.838352552428375 ], [ -65.562995165094776, -38.775824070124713 ], [ -65.689550747369083, -38.817888686113974 ], [ -65.960180223338625, -38.742131036218325 ], [ -66.215229255126019, -38.716602878819799 ], [ -66.391859300266503, -38.734172866184849 ], [ -66.56195227687607, -38.70156503699684 ], [ -66.593500738867988, -38.607307223749388 ], [ -66.647941860828212, -38.557387790514099 ], [ -67.069828254170602, -38.408973077045857 ], [ -67.135767381159724, -38.338073011760059 ], [ -67.176591762799603, -38.222627861786407 ], [ -67.375959439176768, -38.255545750236195 ], [ -67.591992763555197, -38.247122491309938 ], [ -67.705655076820335, -38.100568128915995 ], [ -67.84489722432744, -38.056901544270829 ], [ -67.871743130441132, -38.007240492554672 ], [ -67.848256192169515, -37.907763359491469 ], [ -67.72369015217879, -37.816864515884674 ], [ -67.711752895779512, -37.734750664611454 ], [ -67.748598191952965, -37.669069920040783 ], [ -67.850323248818881, -37.600236912303671 ], [ -68.24939449655875, -37.557035413853271 ], [ -68.256758389188292, -36.276751804052537 ], [ -68.293190274211781, -36.128285413740855 ], [ -68.266111823202095, -36.006484063288895 ], [ -65.095788539809234, -36.001316419417208 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "AR-X", "NAME_1": "Córdoba" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -62.087134975898437, -30.156608574426173 ], [ -62.132067634213911, -30.441035657869293 ], [ -61.857097336672723, -30.731457207484141 ], [ -62.121551480216624, -31.608561292869354 ], [ -62.235885586150857, -31.719768975857562 ], [ -62.184079963419549, -31.962751560036452 ], [ -62.218573981204258, -32.138503106033511 ], [ -62.078220790557054, -32.244078058055948 ], [ -62.014632941057357, -32.386291598878188 ], [ -61.916990323344749, -32.458690280931705 ], [ -61.86611487480161, -32.586176039192878 ], [ -61.894485236104742, -32.658781426821406 ], [ -61.833016120097852, -32.676919854067989 ], [ -61.742272305222684, -32.796964207132476 ], [ -61.780254482958014, -33.029921562829884 ], [ -61.91991004071582, -33.114102471651734 ], [ -62.853806524651361, -34.38213876669073 ], [ -63.339616665176948, -34.380485121191384 ], [ -63.373593919923451, -34.413609713417543 ], [ -63.384058397077354, -35.002100925217519 ], [ -65.086615973848097, -35.001790866855004 ], [ -65.086900193788892, -33.96237110774041 ], [ -65.131703660895198, -33.205466404151252 ], [ -65.091137660774393, -33.136840101989094 ], [ -65.032484911149709, -33.111260267747184 ], [ -65.014656542265584, -32.948169447661883 ], [ -64.883191697638722, -32.61950733789331 ], [ -64.919391038665481, -32.308156833970713 ], [ -65.189658780328443, -32.327638849253503 ], [ -65.245081753320221, -32.125118909709897 ], [ -65.310529954793594, -32.061143486582637 ], [ -65.640587327643061, -31.893246758730925 ], [ -65.75964982787724, -31.885495294272403 ], [ -65.767272101126537, -31.096241143913687 ], [ -65.401893887293056, -30.140175469522319 ], [ -65.138189052582675, -30.063074232489839 ], [ -64.943394740874567, -29.878330986785613 ], [ -64.951146206232409, -29.578969415206359 ], [ -64.253746913888961, -29.424301853147995 ], [ -64.049056565807859, -29.473032728877342 ], [ -64.027585008241545, -29.545173027613146 ], [ -63.807650112762474, -29.649766126805332 ], [ -63.462709926821674, -29.655243829039478 ], [ -63.457904019055206, -29.714309990713502 ], [ -63.396331550260811, -29.72852101023642 ], [ -63.384058397077354, -29.771309095738161 ], [ -62.28815629687557, -29.776735121128922 ], [ -62.242577684312664, -29.8056222472689 ], [ -62.087134975898437, -30.156608574426173 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/bolivia.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/bolivia.geojson new file mode 100644 index 0000000000000..c4fb51bf7d325 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/bolivia.geojson @@ -0,0 +1,15 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "BO-L", "NAME_1": "La Paz" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.290029459999914, -17.976627704999899 ], [ -69.317857218999876, -17.951616312999903 ], [ -69.334238647999911, -17.805785420999968 ], [ -69.359405069999951, -17.759379983999864 ], [ -69.497122762999965, -17.621403909999884 ], [ -69.522599243999906, -17.369119567999931 ], [ -69.597271687999893, -17.30049326599989 ], [ -69.666492269999878, -17.288297627999967 ], [ -69.622799845999907, -17.185564879999944 ], [ -69.595049601999875, -17.179673766999954 ], [ -69.510093546999883, -17.112080992999978 ], [ -69.427437092999924, -17.086862894999939 ], [ -69.406017211999909, -17.062988382999947 ], [ -69.413587809999882, -17.022267353999979 ], [ -69.364314331999879, -16.991158141999932 ], [ -69.325944579999941, -16.922221780999905 ], [ -69.224452066999874, -16.818248799999949 ], [ -69.182361612999841, -16.728745218999933 ], [ -69.112055826999949, -16.711485289999942 ], [ -69.037073323999977, -16.670247496999934 ], [ -69.008341227999949, -16.634177347999938 ], [ -69.040122233999909, -16.58136403399989 ], [ -69.02787491899997, -16.454136657999925 ], [ -69.001726643999859, -16.422820739999906 ], [ -68.855844075999926, -16.363186135999911 ], [ -68.833494018999943, -16.328976338999908 ], [ -68.843648437999917, -16.302001240999886 ], [ -68.918760131999932, -16.266654560999967 ], [ -68.982037923999911, -16.210017190999892 ], [ -69.053558105999855, -16.208363545999944 ], [ -69.120814982999917, -16.231204528999939 ], [ -69.184867919999931, -16.195031025999924 ], [ -69.219646159999883, -16.152759704999937 ], [ -69.430020915999933, -15.626280211999884 ], [ -69.356407837999939, -15.501429951999867 ], [ -69.343411214999918, -15.442208760999875 ], [ -69.285921182999886, -15.405415140999963 ], [ -69.291166341999912, -15.35084482799995 ], [ -69.255897176999923, -15.313327738999945 ], [ -69.222591715999982, -15.302165628999916 ], [ -69.209130005999924, -15.263615010999942 ], [ -69.166135213999922, -15.263925068999924 ], [ -69.148100138999922, -15.233332620999917 ], [ -69.28858251999992, -15.101971129999924 ], [ -69.384313110999926, -14.981771748999876 ], [ -69.367750813999919, -14.900536396999897 ], [ -69.370541341999882, -14.801524352999891 ], [ -69.339044555999919, -14.774755960999926 ], [ -69.267627726999905, -14.750674742999976 ], [ -69.234658162999949, -14.574251403999938 ], [ -69.170398518999889, -14.57755869599994 ], [ -69.164274861999928, -14.503041279999891 ], [ -68.990254475999848, -14.3790178429999 ], [ -69.016170206999902, -14.32114023799997 ], [ -69.010149902999871, -14.245899352999928 ], [ -68.984905964999911, -14.228329365999954 ], [ -68.883723510999914, -14.211482848999964 ], [ -68.864448201999949, -14.191225686999971 ], [ -68.905763508999883, -14.039296975999989 ], [ -68.982968098999976, -13.972220967999959 ], [ -68.992993327999898, -13.869798278999937 ], [ -69.023094848999875, -13.806029561999907 ], [ -69.015963500999931, -13.75311289499993 ], [ -69.101591349999893, -13.66660654699993 ], [ -69.087587036999906, -13.643868916999864 ], [ -69.044023803999949, -13.648003031999878 ], [ -69.023844157999889, -13.634980569999939 ], [ -69.02319820199989, -13.596946715999906 ], [ -68.985655273999896, -13.550231221999908 ], [ -68.970746622999854, -13.501448668999956 ], [ -68.962788452999888, -13.283580829999948 ], [ -68.986585448999847, -12.890478209999941 ], [ -68.87656632599996, -12.754982604999938 ], [ -68.766133788999952, -12.710540872999957 ], [ -68.742956909999862, -12.665789082999908 ], [ -68.785331583999977, -12.645945332999915 ], [ -68.793418945999861, -12.620210469999918 ], [ -68.726058715999869, -12.565950215999877 ], [ -68.689463238237863, -12.49341765609995 ], [ -68.629681362804661, -12.490813490150458 ], [ -68.581958177427907, -12.406942640590387 ], [ -68.558212856737953, -12.402291761555546 ], [ -68.50994706900201, -12.427406507804108 ], [ -68.476874151820653, -12.416709486653474 ], [ -68.390161099255295, -12.242456556524871 ], [ -68.271770392589531, -12.18132333730216 ], [ -68.2461647199259, -12.153676445511564 ], [ -68.215133022770772, -12.019937838660326 ], [ -68.012819789701496, -11.970018405425094 ], [ -67.973519864150376, -11.904854424791893 ], [ -66.927821418023996, -12.382241305491846 ], [ -66.938285895177899, -12.420016777652165 ], [ -66.927666389292426, -12.525333347256151 ], [ -66.96665625738035, -12.581505629081505 ], [ -66.948569505178511, -12.670802504032338 ], [ -67.004095831857171, -12.901072685456086 ], [ -67.052258266805552, -13.015897718704764 ], [ -67.119928554559124, -13.03724008596123 ], [ -67.159073452277994, -13.107468356779236 ], [ -67.193179898233723, -13.129637545436367 ], [ -67.205943976033666, -13.167826429646027 ], [ -67.336659511827008, -13.304458917245256 ], [ -67.395596483191127, -13.402489108585485 ], [ -67.361076626085435, -13.573899834809538 ], [ -67.471664191449293, -13.710532321509447 ], [ -67.492644822600482, -13.771355483268962 ], [ -67.482722947805769, -13.836674492633733 ], [ -67.509207118713562, -13.87997934297232 ], [ -67.535975511360732, -13.998370049638083 ], [ -67.50360022616951, -14.258664238763629 ], [ -67.568169929398721, -14.330287773561906 ], [ -67.532383998622606, -14.443045750161275 ], [ -67.48794226762152, -14.511620374580616 ], [ -67.497838303994513, -14.551307874658676 ], [ -67.535975511360732, -14.598591810463688 ], [ -67.504116991006299, -14.668871759024455 ], [ -67.427506680389001, -14.754137871665478 ], [ -67.434250453595553, -14.896351414286357 ], [ -67.417558967172567, -14.968491713022161 ], [ -67.363892991568321, -15.012054945779141 ], [ -67.281288214779295, -15.023578790129079 ], [ -67.179072232397573, -15.165172214226288 ], [ -67.115510220420333, -15.289815768582855 ], [ -67.120006069824228, -15.367950535288969 ], [ -67.107500372644097, -15.400144951528318 ], [ -67.055875617066079, -15.43177092878534 ], [ -67.025644903789271, -15.476781100567337 ], [ -66.784419317897175, -15.699299818431882 ], [ -66.934461839342418, -15.844717299263948 ], [ -66.918235440013518, -15.863992608072408 ], [ -66.944383714137075, -15.923833917001673 ], [ -66.949938930737062, -16.057830906271306 ], [ -66.872062547348662, -16.171105645009504 ], [ -66.870563930580943, -16.215237318547395 ], [ -66.834907192812693, -16.22944833717105 ], [ -66.799612189351024, -16.283295179928643 ], [ -66.816200323885823, -16.482972913768947 ], [ -66.765944993866356, -16.589529717722314 ], [ -66.758451910926965, -16.741148370301062 ], [ -66.798216926270129, -16.79525359457773 ], [ -66.932291429006227, -16.8351478002308 ], [ -66.978102587364504, -16.914626153174424 ], [ -66.977895880890173, -16.963873792841298 ], [ -67.015206265057088, -17.046866143257887 ], [ -66.994974941840098, -17.078853854821546 ], [ -66.948802049175242, -17.09647551813066 ], [ -66.9032751125564, -17.159520766170431 ], [ -66.885085007567056, -17.291502373835499 ], [ -66.850461798573122, -17.377491956888321 ], [ -66.870021328221696, -17.415370781836145 ], [ -66.841935186859359, -17.468080743031862 ], [ -66.989936490076957, -17.551279799023519 ], [ -67.083729214431685, -17.429220066153107 ], [ -67.12008358419007, -17.403381849492746 ], [ -67.302449713983094, -17.445136407119492 ], [ -67.751001146285887, -17.726721286658062 ], [ -67.732630174143196, -17.814209486478603 ], [ -67.772162644590367, -17.862630303845435 ], [ -67.809318000025655, -17.860356540721796 ], [ -68.005765957233109, -17.718453058262014 ], [ -68.140486416015278, -17.65902515958345 ], [ -68.32685746879713, -17.643522230666406 ], [ -68.446617601021444, -17.652358900742684 ], [ -68.552089199357056, -17.694785251937844 ], [ -68.73176815487642, -17.878443292024315 ], [ -68.867703009586194, -17.966758315044217 ], [ -69.08228408714092, -18.039077667900074 ], [ -69.092057047999901, -18.023343199999971 ], [ -69.157711954999854, -18.025720315999934 ], [ -69.234813191999905, -17.992957457999921 ], [ -69.262046671999911, -17.964018655999965 ], [ -69.290029459999914, -17.976627704999899 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "BO-O", "NAME_1": "Oruro" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.9896085213162, -18.946490987269271 ], [ -68.959842895999884, -18.907837015999903 ], [ -68.951445475999918, -18.867322692999906 ], [ -69.010537475999854, -18.744539488999933 ], [ -69.003483642999953, -18.702681579999961 ], [ -69.03384354699989, -18.649454853999899 ], [ -69.034386148999943, -18.478302510999896 ], [ -69.077820190999944, -18.398824157999911 ], [ -69.100351114999881, -18.234286396999906 ], [ -69.141201334999948, -18.186847432999912 ], [ -69.155438192999924, -18.140235289999936 ], [ -69.08921484399994, -18.08308115699991 ], [ -69.08228408714092, -18.039077667900074 ], [ -68.816801724420031, -17.940351657602946 ], [ -68.696395637049022, -17.847127374029071 ], [ -68.552089199357056, -17.694785251937844 ], [ -68.446617601021444, -17.652358900742684 ], [ -68.32685746879713, -17.643522230666406 ], [ -68.140486416015278, -17.65902515958345 ], [ -68.005765957233109, -17.718453058262014 ], [ -67.809318000025655, -17.860356540721796 ], [ -67.772162644590367, -17.862630303845435 ], [ -67.732630174143196, -17.814209486478603 ], [ -67.755858730895682, -17.73865854305734 ], [ -67.732035894940566, -17.712872003240363 ], [ -67.302449713983094, -17.445136407119492 ], [ -67.132615118892602, -17.401056409525665 ], [ -67.083729214431685, -17.429220066153107 ], [ -66.989936490076957, -17.551279799023519 ], [ -66.808345505740476, -17.687912285723428 ], [ -66.68047217475106, -17.863973890982265 ], [ -66.624920009650737, -17.991252943668428 ], [ -66.654168870996614, -18.027271416642577 ], [ -66.734758267080338, -18.053936455602923 ], [ -66.748349168978962, -18.162663669892481 ], [ -66.736231045426393, -18.208190605611946 ], [ -66.684580451426655, -18.237387791013759 ], [ -66.521618821651316, -18.252632337512352 ], [ -66.679826218705045, -18.358000583959779 ], [ -66.690574916699063, -18.494271335453789 ], [ -66.641249762666405, -18.591009616500628 ], [ -66.503041143933615, -18.69839324275398 ], [ -66.350647345898267, -18.734876803721534 ], [ -66.28460486522232, -18.765727633723316 ], [ -66.182130500422261, -18.995842786415437 ], [ -66.040588752269116, -19.172886243605262 ], [ -66.055988329297975, -19.198672783422239 ], [ -66.097096930878649, -19.20905974710962 ], [ -66.453922696375344, -19.241512545767364 ], [ -66.728117844862652, -19.44150033886956 ], [ -67.551891852327117, -19.782358086556428 ], [ -67.687464972730311, -19.826024672100914 ], [ -67.739606493145118, -19.824939466483215 ], [ -67.831926439153847, -19.807886243955011 ], [ -68.576735882999941, -19.564606984999969 ], [ -68.510206257999926, -19.47162689199989 ], [ -68.447626098999905, -19.434626566999938 ], [ -68.455015828999933, -19.415402933999914 ], [ -68.60007157499993, -19.303368428999974 ], [ -68.663323526999932, -19.273602802999889 ], [ -68.698463500999964, -19.215621845999934 ], [ -68.815407267999944, -19.113302509999926 ], [ -68.908502359999943, -19.067930602999908 ], [ -68.961703246999889, -18.969435322999942 ], [ -68.9896085213162, -18.946490987269271 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "BO-P", "NAME_1": "Potosí" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.597177693999953, -20.056707457999963 ], [ -68.574543415999898, -20.035210062999923 ], [ -68.544622761999875, -19.93475107799992 ], [ -68.553511107999981, -19.857856546999926 ], [ -68.705439818999963, -19.733833109999935 ], [ -68.690298624999855, -19.695385843999887 ], [ -68.576735882999941, -19.564606984999969 ], [ -67.831926439153847, -19.807886243955011 ], [ -67.687464972730311, -19.826024672100914 ], [ -66.728117844862652, -19.44150033886956 ], [ -66.453922696375344, -19.241512545767364 ], [ -66.097096930878649, -19.20905974710962 ], [ -66.046169807290767, -19.191541435688691 ], [ -66.05857214988481, -19.140846856097539 ], [ -66.182130500422261, -18.995842786415437 ], [ -66.220500250885834, -18.92633798600923 ], [ -66.272848476875708, -18.777354831760078 ], [ -66.350647345898267, -18.734876803721534 ], [ -66.503041143933615, -18.69839324275398 ], [ -66.633317430155273, -18.602895196056465 ], [ -66.690574916699063, -18.494271335453789 ], [ -66.679826218705045, -18.358000583959779 ], [ -66.521618821651316, -18.252632337512352 ], [ -66.684580451426655, -18.237387791013759 ], [ -66.736231045426393, -18.208190605611946 ], [ -66.748349168978962, -18.162663669892481 ], [ -66.734758267080338, -18.053936455602923 ], [ -66.654168870996614, -18.027271416642577 ], [ -66.624920009650737, -17.991252943668428 ], [ -66.534382901249899, -17.976938572257325 ], [ -66.346435716435167, -17.988617446238152 ], [ -66.175154182319659, -17.866816094886872 ], [ -66.018522914600794, -17.862165215852031 ], [ -65.94025895938347, -17.981331068873715 ], [ -65.843313971862301, -17.968308607756057 ], [ -65.642370165250895, -18.129073988773541 ], [ -65.595396287808398, -18.203694757107371 ], [ -65.510336879843123, -18.266688328303701 ], [ -65.436310390711924, -18.369266045891322 ], [ -65.347194382914438, -18.413862806523298 ], [ -65.391894497233238, -18.428177178833721 ], [ -65.503179693687912, -18.387972913918873 ], [ -65.554261847806004, -18.405181166077966 ], [ -65.585474413013742, -18.374950452801158 ], [ -65.657046270968635, -18.364201754807141 ], [ -65.672833420725794, -18.345236505260516 ], [ -65.692444628117073, -18.354899997636778 ], [ -65.683607958040795, -18.421097507044294 ], [ -65.628650072143103, -18.45825286158032 ], [ -65.624283413049056, -18.476391289726223 ], [ -65.628572556877998, -18.565739840621177 ], [ -65.607772792880098, -18.674105319704722 ], [ -65.651930304839709, -18.725058281714325 ], [ -65.652188687258104, -18.748674412094431 ], [ -65.457446052393379, -18.683045342568505 ], [ -65.423804694431112, -18.702475681007854 ], [ -65.437188889855349, -18.751309909524707 ], [ -65.506357795276017, -18.812908216740823 ], [ -65.469977587095968, -18.904995618752821 ], [ -65.540774298694942, -19.012947685787083 ], [ -65.506176927223407, -19.093614597135968 ], [ -65.461631843434816, -19.128082778297596 ], [ -65.447214118336888, -19.178932386620374 ], [ -65.292804937797655, -19.310293877560412 ], [ -65.248001471590612, -19.318303724437328 ], [ -65.130540940911658, -19.379230238984348 ], [ -64.963703579356718, -19.350446465631876 ], [ -64.919985317868111, -19.370600273583761 ], [ -64.868670619753289, -19.454057711993812 ], [ -64.870815191667759, -19.547126966836061 ], [ -64.746920946144712, -19.732438652421877 ], [ -64.867740444665799, -19.868399346452691 ], [ -65.05643693741473, -19.968651624972495 ], [ -65.228235236367027, -19.991337578466471 ], [ -65.313242966589598, -20.042342218218778 ], [ -65.315103318563274, -20.108746433201361 ], [ -65.368846809432682, -20.203107599236318 ], [ -65.366056280572877, -20.26904672622544 ], [ -65.29595720096404, -20.533785088810816 ], [ -65.422719488813357, -20.836815687493981 ], [ -65.429282395765938, -20.962596124311688 ], [ -65.471992966901894, -21.101295667660963 ], [ -65.476876389933466, -21.292085055480925 ], [ -65.458453741846711, -21.335079847456996 ], [ -65.317377081686971, -21.477913506802906 ], [ -65.234927333629514, -21.53537769892165 ], [ -65.238467170423576, -21.589379571310189 ], [ -65.289420132433179, -21.678418063842571 ], [ -65.328539190831009, -21.802906588568192 ], [ -65.27647518568125, -21.85070728921005 ], [ -65.211492072201338, -21.946463717426639 ], [ -65.17301896805094, -22.098082370904706 ], [ -65.457343505999944, -22.101440530999923 ], [ -65.579894165999917, -22.086454365999955 ], [ -65.744612793999892, -22.114049580999861 ], [ -65.775308593999938, -22.105057880999908 ], [ -65.9326891689999, -21.944550882999906 ], [ -66.046532348999932, -21.917989196999983 ], [ -66.063585571999852, -21.864039000999924 ], [ -66.094488078999944, -21.832929789999881 ], [ -66.22246476199993, -21.786937763999973 ], [ -66.240008910999904, -21.792415465999866 ], [ -66.307601684999952, -22.077049254999906 ], [ -66.335248575999884, -22.082320250999928 ], [ -66.377468220999845, -22.127072040999892 ], [ -66.626755330999885, -22.192597757999906 ], [ -66.641379760999939, -22.212544859999923 ], [ -66.699309041999896, -22.200762634999919 ], [ -66.735895955999922, -22.225050557999921 ], [ -66.790517943999959, -22.388348082999883 ], [ -66.785091918999882, -22.427622171999957 ], [ -66.9353153079999, -22.480538838999934 ], [ -66.978155069999843, -22.522500100999935 ], [ -67.032725382999871, -22.524567158999986 ], [ -67.026627563999909, -22.639392190999985 ], [ -67.113237263999849, -22.710085550999906 ], [ -67.193904174999972, -22.82222340899996 ], [ -67.547112589999927, -22.892503356999967 ], [ -67.80358272299992, -22.878654072999907 ], [ -67.833038289999934, -22.840103454999934 ], [ -67.887091837999918, -22.818709411999919 ], [ -67.891329304999971, -22.715666605999914 ], [ -67.859186564999931, -22.547304788999966 ], [ -67.951894083999917, -22.334087828999941 ], [ -67.934789184999971, -22.251715596999958 ], [ -67.976595418999921, -22.159834899999893 ], [ -67.960627400999982, -22.102887470999917 ], [ -68.096226359999946, -21.953955993999955 ], [ -68.107595173999925, -21.789624938999907 ], [ -68.128369099999873, -21.712316996999988 ], [ -68.198442341999908, -21.571860452999942 ], [ -68.193739786999942, -21.32846445699991 ], [ -68.207537394999889, -21.284332783999915 ], [ -68.416310180999915, -20.959804788999932 ], [ -68.453930622999934, -20.9397543339999 ], [ -68.510206257999926, -20.940167744999911 ], [ -68.55511307799992, -20.913916116999971 ], [ -68.571959594999896, -20.872368265999881 ], [ -68.572786417999907, -20.742867126999982 ], [ -68.550203816999982, -20.699045511999898 ], [ -68.481629190999854, -20.643028258999962 ], [ -68.480957397999873, -20.624734802999896 ], [ -68.685544392999958, -20.516834410999891 ], [ -68.765410319999944, -20.421233012 ], [ -68.757684692999959, -20.36428558399993 ], [ -68.678516398999932, -20.32862884499994 ], [ -68.7294693609999, -20.228686624999895 ], [ -68.726265421999926, -20.150965270999876 ], [ -68.789465698999891, -20.125850524999947 ], [ -68.792592121999945, -20.106626891999923 ], [ -68.652884887999875, -20.054226988999886 ], [ -68.597177693999953, -20.056707457999963 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "BO-T", "NAME_1": "Tarija" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -62.650357218999943, -22.234455667999967 ], [ -62.679296020999914, -22.194768167999896 ], [ -62.78347570899993, -22.130896097999937 ], [ -62.8013557539999, -22.013487242999929 ], [ -62.81856400599986, -22.00087819399991 ], [ -63.639392455999882, -21.997467549999968 ], [ -63.693911092999912, -22.012040302999935 ], [ -63.740419880999923, -22.050590921999913 ], [ -63.81312862199988, -22.003048604999904 ], [ -63.933172973999916, -22.001808369999949 ], [ -64.004383097999948, -22.099270120999932 ], [ -64.051021077999934, -22.229184671999931 ], [ -64.086238565999906, -22.257916767999944 ], [ -64.160549275999898, -22.438474223 ], [ -64.250828002999924, -22.540690204999876 ], [ -64.325293741999957, -22.871936136999878 ], [ -64.343897257999913, -22.863667906999936 ], [ -64.355731160999909, -22.751943460999968 ], [ -64.453709675999846, -22.642906188999945 ], [ -64.428284871999921, -22.542343851999931 ], [ -64.4981255699999, -22.472787373999921 ], [ -64.53132767799994, -22.42565846699992 ], [ -64.524558065999884, -22.38535085099997 ], [ -64.572022867999891, -22.343182881999908 ], [ -64.542774006999934, -22.275486755999921 ], [ -64.586879841999917, -22.21275156699997 ], [ -64.657779907999981, -22.178438414999945 ], [ -64.762321329999907, -22.17440765399995 ], [ -64.832472086999957, -22.137510680999924 ], [ -65.020367594999897, -22.096582946999916 ], [ -65.190478219194461, -22.098473959105945 ], [ -65.17301896805094, -22.098082370904706 ], [ -65.211492072201338, -21.946463717426639 ], [ -65.27647518568125, -21.85070728921005 ], [ -65.328539190831009, -21.802906588568192 ], [ -65.289420132433179, -21.678418063842571 ], [ -65.235521612832144, -21.576925550973385 ], [ -65.171907924910784, -20.962027682631458 ], [ -65.15661170066943, -20.945749606459174 ], [ -65.109792852857879, -20.962492770624863 ], [ -65.078476934862636, -20.955154718215681 ], [ -65.033776822342475, -21.000371595572688 ], [ -64.922000697674036, -21.021765638773218 ], [ -64.829577398877859, -21.097523288668867 ], [ -64.775187953761019, -21.073752129557136 ], [ -64.750124885255218, -20.985798841743133 ], [ -64.702660082296973, -20.928851413561915 ], [ -64.640700038975581, -20.947196547282829 ], [ -64.530990973654525, -21.089978529785299 ], [ -64.445699021692462, -21.083208917257707 ], [ -64.359037645071226, -21.13473032004822 ], [ -64.23235287068843, -21.142016696513338 ], [ -64.198969896043877, -21.110235690524689 ], [ -64.175172899409745, -20.891437676607495 ], [ -64.142590907744193, -20.916345717281047 ], [ -64.074326340787991, -20.914330335676482 ], [ -64.053526576790091, -20.945284518465769 ], [ -64.000403205343616, -20.944250989691398 ], [ -64.00996334493243, -20.965593356947863 ], [ -63.983039923553633, -20.996702568468777 ], [ -62.271885774109194, -21.00042365282934 ], [ -62.275703084999861, -21.06656829799995 ], [ -62.650357218999943, -22.234455667999967 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "BO-S", "NAME_1": "Santa Cruz" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -57.859745238999921, -19.980122985999955 ], [ -57.895608682999864, -20.024151305999922 ], [ -57.959170694999926, -20.02621836299997 ], [ -58.103554647999943, -20.144040628999889 ], [ -58.158796752999962, -20.165124612999918 ], [ -58.141846883999875, -20.000896910999899 ], [ -58.175281534999954, -19.821372984999925 ], [ -59.069645548999858, -19.291482848999948 ], [ -60.006384236999878, -19.298097431999935 ], [ -61.753202677999894, -19.645879821999941 ], [ -61.944250447999906, -20.104146422999946 ], [ -62.210573102366766, -20.471305463076646 ], [ -63.285873176106179, -20.475132338286812 ], [ -63.303107265787673, -20.46887948969669 ], [ -63.368477952895205, -20.357413425189407 ], [ -63.415219286340971, -20.403250421070084 ], [ -63.467102424337384, -20.420355319542352 ], [ -63.502423265321454, -20.460352878882247 ], [ -63.651897345985731, -20.450120944825755 ], [ -63.706906907827545, -20.003843275646659 ], [ -63.725303718391899, -19.962967218062659 ], [ -63.767652554321899, -19.271278171050767 ], [ -63.741349249668133, -19.044366956569775 ], [ -63.750521817427909, -19.02829558687182 ], [ -63.872633226242385, -19.026280206166575 ], [ -63.896585253406727, -19.055890801819032 ], [ -63.905912848998753, -19.128909600597581 ], [ -63.927126024146673, -19.162757664134915 ], [ -63.973453946442476, -19.174436537216422 ], [ -64.016293707888281, -19.160587252899404 ], [ -64.064662849311048, -18.999821872781183 ], [ -64.120370043142941, -18.955276788093272 ], [ -64.191967740418875, -18.939205417495998 ], [ -64.220648159185203, -18.865566501992475 ], [ -64.289041918249893, -18.814200127933589 ], [ -64.319453497780671, -18.735393568558322 ], [ -64.319866908930692, -18.679014581158015 ], [ -64.340201585834507, -18.65694874348975 ], [ -64.29325354681373, -18.591009616500628 ], [ -64.302116055311672, -18.499594008057045 ], [ -64.420041673084711, -18.420942478312725 ], [ -64.445647345748398, -18.356398613505235 ], [ -64.441229010710288, -18.326116225183625 ], [ -64.488383755306074, -18.240333346806494 ], [ -64.589307827394293, -18.114914646094064 ], [ -64.641242642234147, -18.005257256717016 ], [ -64.710644089852849, -17.910741061950432 ], [ -64.689896002698333, -17.866971123618441 ], [ -64.564322272354957, -17.745686537104007 ], [ -64.405649787307823, -17.520377293077615 ], [ -64.396373866760541, -17.45629851716285 ], [ -64.339503953844371, -17.420693454439402 ], [ -64.224601406229908, -17.41599089856112 ], [ -64.216229824147035, -17.35971526484758 ], [ -64.238269823393637, -17.310932712274848 ], [ -64.375677456449466, -17.174610283937454 ], [ -64.503447434651378, -17.103141777870746 ], [ -64.591504076152205, -17.020252781140925 ], [ -64.647443813980829, -16.996016534035846 ], [ -64.741649950384897, -16.898399752946261 ], [ -64.782215948707062, -16.766263115650247 ], [ -64.807744107004908, -16.729624525951124 ], [ -64.751055060342765, -16.611182142441919 ], [ -64.778366055349181, -16.587255954598618 ], [ -64.779890509639301, -16.556146742178441 ], [ -64.723149787033037, -16.491086113433369 ], [ -64.682170375762212, -16.37434905406559 ], [ -64.696433072128571, -16.343963311157893 ], [ -64.67596920401553, -16.306084487109388 ], [ -64.699792039970646, -16.304689223129174 ], [ -64.67596920401553, -16.265156751782683 ], [ -64.677286952730697, -16.169090265203579 ], [ -64.661680671026147, -16.118033948607831 ], [ -64.689611781858218, -16.056590671022661 ], [ -64.688681606770729, -15.969929295300744 ], [ -64.730591193129044, -15.922490329864843 ], [ -64.703900315746978, -15.911586602239879 ], [ -64.67596920401553, -15.922490329864843 ], [ -64.703900315746978, -15.874741306066426 ], [ -64.664393683721528, -15.872467542942786 ], [ -64.657520718406431, -15.850453383017225 ], [ -63.317395798777056, -15.914067070938586 ], [ -63.384807705011553, -15.891329440601226 ], [ -63.420696987675854, -15.856551201976401 ], [ -63.440876634049403, -15.774230645128171 ], [ -63.498676723851702, -15.692065117910886 ], [ -63.623811204623394, -15.627366225271089 ], [ -63.67016496444154, -15.580185642253582 ], [ -63.68812252543421, -15.504944757194778 ], [ -63.757989061046317, -15.456058851834541 ], [ -63.863176439441133, -15.298083997878223 ], [ -63.949786140118249, -15.08564218443928 ], [ -63.934748298295347, -15.027919609902085 ], [ -63.940200161208452, -14.832324313416336 ], [ -63.963015305911654, -14.737394707499732 ], [ -63.570403612336804, -14.618538913739883 ], [ -61.593060170999934, -13.506794492999958 ], [ -61.550811930999913, -13.538035582999981 ], [ -61.503424641999914, -13.548164163999942 ], [ -61.45875036699988, -13.543719990999932 ], [ -61.347723551999934, -13.493697204999947 ], [ -61.248556477999983, -13.524393004999894 ], [ -61.14910518399995, -13.519845478999954 ], [ -61.1187194419999, -13.484498798999951 ], [ -61.047225097999871, -13.464551696999933 ], [ -61.041256469999951, -13.515194600999891 ], [ -61.022006998999927, -13.535245055999937 ], [ -60.896743326999882, -13.552918395999939 ], [ -60.801968750999947, -13.60418141599996 ], [ -60.652701375999897, -13.718799742999906 ], [ -60.588622599999951, -13.744534606999906 ], [ -60.575135050999904, -13.765618590999935 ], [ -60.472634846999938, -13.797864684999894 ], [ -60.448812011999877, -13.896773375999956 ], [ -60.387187866999938, -13.983279723999971 ], [ -60.419433960999896, -14.076917418999912 ], [ -60.473513345999891, -14.117225036999869 ], [ -60.464340779999901, -14.27835215199994 ], [ -60.391347818999861, -14.357107034999942 ], [ -60.338431151999885, -14.53260019899993 ], [ -60.36920446799985, -14.542832132999905 ], [ -60.291715657999902, -14.630061949999913 ], [ -60.269804849999844, -15.083367614999972 ], [ -60.27497249399994, -15.095149840999881 ], [ -60.582240559999946, -15.098870543999894 ], [ -60.246395425999879, -15.478278909999872 ], [ -60.1798103429999, -16.222006122999943 ], [ -60.160690063999908, -16.264794209999963 ], [ -58.464721232999892, -16.331250101999927 ], [ -58.421623087999876, -16.318434345999947 ], [ -58.392942667999904, -16.279366963999934 ], [ -58.349741170999948, -16.280400491999913 ], [ -58.33454829899992, -16.386647236999892 ], [ -58.363590453999905, -16.436670022999877 ], [ -58.342661498999917, -16.473153584999892 ], [ -58.35609737199988, -16.50953379299996 ], [ -58.455884562999898, -16.619087829999941 ], [ -58.480275838999916, -16.683683369999898 ], [ -58.45293900599998, -16.841296487999912 ], [ -58.4662715259999, -16.887288512999916 ], [ -58.40627518799991, -17.110117288999945 ], [ -58.39914383999988, -17.237448017999952 ], [ -58.381160441999981, -17.267213642999934 ], [ -58.231557169999945, -17.329742125999928 ], [ -58.204065307999969, -17.377387796999884 ], [ -58.152233845999888, -17.396404723999936 ], [ -58.010175333999882, -17.496760354999907 ], [ -57.943564412999905, -17.51784433999994 ], [ -57.836749226999871, -17.511023050999981 ], [ -57.800730753999886, -17.533450622999879 ], [ -57.785899617999945, -17.677524514999917 ], [ -57.724456339999875, -17.736642353999883 ], [ -57.732982950999968, -17.768475036999931 ], [ -57.696809448999943, -17.825112406999921 ], [ -57.698773152999877, -17.843095804999905 ], [ -57.730089070999981, -17.846093037999921 ], [ -57.551081909999937, -18.183643492999934 ], [ -57.465660766999946, -18.217749938999901 ], [ -57.466797648999943, -18.239557393999931 ], [ -57.535734008999981, -18.240487568999882 ], [ -57.5667398679999, -18.256093850999918 ], [ -57.782333943999873, -18.910420836999904 ], [ -57.731794392999944, -18.921996357999944 ], [ -57.71582637599991, -19.044572854999956 ], [ -57.789000203999905, -19.059248961999941 ], [ -58.124638630999897, -19.729905699999875 ], [ -58.1169388429999, -19.758017679999909 ], [ -57.859745238999921, -19.980122985999955 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "BO-H", "NAME_1": "Chuquisaca" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -62.210573102366766, -20.471305463076646 ], [ -62.277305053999896, -20.579776305999886 ], [ -62.271885774109194, -21.00042365282934 ], [ -63.983039923553633, -20.996702568468777 ], [ -64.00996334493243, -20.965593356947863 ], [ -64.000403205343616, -20.944250989691398 ], [ -64.053526576790091, -20.945284518465769 ], [ -64.074326340787991, -20.914330335676482 ], [ -64.142590907744193, -20.916345717281047 ], [ -64.175172899409745, -20.891437676607495 ], [ -64.198969896043877, -21.110235690524689 ], [ -64.23235287068843, -21.142016696513338 ], [ -64.359037645071226, -21.13473032004822 ], [ -64.445699021692462, -21.083208917257707 ], [ -64.530990973654525, -21.089978529785299 ], [ -64.640700038975581, -20.947196547282829 ], [ -64.697001512010161, -20.929988295123735 ], [ -64.717439540802161, -20.935879407608581 ], [ -64.750124885255218, -20.985798841743133 ], [ -64.775187953761019, -21.073752129557136 ], [ -64.829577398877859, -21.097523288668867 ], [ -64.922000697674036, -21.021765638773218 ], [ -65.033776822342475, -21.000371595572688 ], [ -65.078476934862636, -20.955154718215681 ], [ -65.109792852857879, -20.962492770624863 ], [ -65.15661170066943, -20.945749606459174 ], [ -65.174285040821985, -20.968228855277459 ], [ -65.234927333629514, -21.53537769892165 ], [ -65.317377081686971, -21.477913506802906 ], [ -65.458453741846711, -21.335079847456996 ], [ -65.476876389933466, -21.292085055480925 ], [ -65.471992966901894, -21.101295667660963 ], [ -65.429282395765938, -20.962596124311688 ], [ -65.422719488813357, -20.836815687493981 ], [ -65.29595720096404, -20.533785088810816 ], [ -65.366056280572877, -20.26904672622544 ], [ -65.368846809432682, -20.203107599236318 ], [ -65.315103318563274, -20.108746433201361 ], [ -65.313242966589598, -20.042342218218778 ], [ -65.228235236367027, -19.991337578466471 ], [ -65.05643693741473, -19.968651624972495 ], [ -64.867740444665799, -19.868399346452691 ], [ -64.746920946144712, -19.732438652421877 ], [ -64.870815191667759, -19.547126966836061 ], [ -64.868670619753289, -19.454057711993812 ], [ -64.919985317868111, -19.370600273583761 ], [ -64.963703579356718, -19.350446465631876 ], [ -65.130540940911658, -19.379230238984348 ], [ -65.248001471590612, -19.318303724437328 ], [ -65.292804937797655, -19.310293877560412 ], [ -65.447214118336888, -19.178932386620374 ], [ -65.461631843434816, -19.128082778297596 ], [ -65.506176927223407, -19.093614597135968 ], [ -65.540774298694942, -19.012947685787083 ], [ -65.469977587095968, -18.904995618752821 ], [ -65.506357795276017, -18.812908216740823 ], [ -65.437188889855349, -18.751309909524707 ], [ -65.423804694431112, -18.702475681007854 ], [ -65.457446052393379, -18.683045342568505 ], [ -65.652188687258104, -18.748674412094431 ], [ -65.651930304839709, -18.725058281714325 ], [ -65.607772792880098, -18.674105319704722 ], [ -65.628572556877998, -18.565739840621177 ], [ -65.624283413049056, -18.476391289726223 ], [ -65.628650072143103, -18.45825286158032 ], [ -65.683607958040795, -18.421097507044294 ], [ -65.692444628117073, -18.354899997636778 ], [ -65.672833420725794, -18.345236505260516 ], [ -65.657046270968635, -18.364201754807141 ], [ -65.585474413013742, -18.374950452801158 ], [ -65.554261847806004, -18.405181166077966 ], [ -65.503179693687912, -18.387972913918873 ], [ -65.391894497233238, -18.428177178833721 ], [ -65.343938767859811, -18.422647799756135 ], [ -65.336988288178929, -18.451896661102012 ], [ -65.305956590124538, -18.451844985157948 ], [ -65.293502569787734, -18.495356541071544 ], [ -65.250249396292588, -18.530238131584497 ], [ -65.231387498634149, -18.616279391480759 ], [ -65.157257656715501, -18.613643894050483 ], [ -65.080182258104742, -18.655863538771314 ], [ -65.05486080628117, -18.644132988846366 ], [ -65.024759284213587, -18.576178481151999 ], [ -64.964582079399463, -18.531323337202252 ], [ -64.816038173822676, -18.484659519021591 ], [ -64.771699794709775, -18.521194756832585 ], [ -64.685012579666818, -18.540108330435089 ], [ -64.57458004393385, -18.666715589552837 ], [ -64.493990647850126, -18.666250501559432 ], [ -64.413995530968975, -18.609716484528121 ], [ -64.369993048640254, -18.608941339071521 ], [ -64.319866908930692, -18.679014581158015 ], [ -64.319453497780671, -18.735393568558322 ], [ -64.281781379307176, -18.826240737120315 ], [ -64.220648159185203, -18.865566501992475 ], [ -64.191967740418875, -18.939205417495998 ], [ -64.120370043142941, -18.955276788093272 ], [ -64.064662849311048, -18.999821872781183 ], [ -64.006940273874534, -19.168648776619762 ], [ -63.955108811822186, -19.172989597292087 ], [ -63.917591722080317, -19.153817641271132 ], [ -63.896585253406727, -19.055890801819032 ], [ -63.872633226242385, -19.026280206166575 ], [ -63.750521817427909, -19.02829558687182 ], [ -63.741349249668133, -19.044366956569775 ], [ -63.767652554321899, -19.271278171050767 ], [ -63.725303718391899, -19.962967218062659 ], [ -63.706906907827545, -20.003843275646659 ], [ -63.651897345985731, -20.450120944825755 ], [ -63.502423265321454, -20.460352878882247 ], [ -63.467102424337384, -20.420355319542352 ], [ -63.415219286340971, -20.403250421070084 ], [ -63.368477952895205, -20.357413425189407 ], [ -63.303107265787673, -20.46887948969669 ], [ -63.285873176106179, -20.475132338286812 ], [ -62.210573102366766, -20.471305463076646 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "BO-N", "NAME_1": "Pando" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -65.44248653199989, -9.679821471999986 ], [ -65.397993123999896, -9.686746113999973 ], [ -65.370501261999948, -9.710620625999866 ], [ -65.340063842999967, -9.789685566999935 ], [ -65.299110270999847, -9.841258645999858 ], [ -65.336834065999881, -9.96724578899989 ], [ -65.284821736999874, -10.206817727999891 ], [ -65.327816528999847, -10.314408060999909 ], [ -65.365023559999941, -10.332184752999936 ], [ -65.394646196065082, -10.392070070277555 ], [ -65.464241503342691, -10.406444593743004 ], [ -65.526253220809508, -10.486594740255043 ], [ -65.652292040045609, -10.560388686288832 ], [ -65.67391862724287, -10.57155079453355 ], [ -65.761432664585811, -10.564109388437544 ], [ -65.753112759346379, -10.666997166186263 ], [ -65.785746426056733, -10.701258639974242 ], [ -65.85623308019251, -10.723014417481409 ], [ -65.89806515218504, -10.679761243986206 ], [ -65.921784633554012, -10.682396741416483 ], [ -65.942429368820285, -10.719500420907707 ], [ -65.886722174988392, -10.764820651951538 ], [ -65.895042080227824, -10.811742851651275 ], [ -66.011675787707418, -10.789418634262574 ], [ -66.107923143238452, -10.840681654634636 ], [ -66.094849006176673, -10.858303317943751 ], [ -66.053275315703274, -10.851482028572775 ], [ -66.045342984091405, -10.867553399170049 ], [ -66.090353155873458, -10.969976088026044 ], [ -66.12153988265942, -10.968167412895809 ], [ -66.130609096732428, -10.981809990738498 ], [ -66.147223069688891, -11.080615330233286 ], [ -66.171175095953913, -11.100820815028612 ], [ -66.217838915033894, -11.097720228705612 ], [ -66.211534389600388, -11.174614760163081 ], [ -66.264115159586936, -11.253938083475759 ], [ -66.267758348269126, -11.277295830538151 ], [ -66.24316036595809, -11.31295256920572 ], [ -66.254632534363964, -11.33165943813259 ], [ -66.308918626693242, -11.344475192775917 ], [ -66.316876796726774, -11.385919692040147 ], [ -66.416715664096614, -11.400802504232217 ], [ -66.4970208402396, -11.442298678541192 ], [ -66.564794480780677, -11.434598890926054 ], [ -66.678999396405004, -11.449378349431299 ], [ -66.690833299117457, -11.537590019663696 ], [ -66.720857306819255, -11.583530369231141 ], [ -66.715276251797548, -11.655567315179439 ], [ -66.729022183327061, -11.674739272099714 ], [ -66.796769986345794, -11.685746351612863 ], [ -66.835604823903509, -11.727810967602068 ], [ -66.905290493261646, -11.735407402429701 ], [ -66.876842616693409, -11.795558769721424 ], [ -66.888366461942667, -11.818141370427895 ], [ -66.917615323288544, -11.841809176752122 ], [ -66.970609504425056, -11.848992200429734 ], [ -66.974562750570499, -11.869197686124323 ], [ -66.961333583877774, -11.910538831701729 ], [ -66.933066576261467, -11.911779066950373 ], [ -66.896970588022214, -11.965987644014547 ], [ -66.877436895896039, -12.064999688185083 ], [ -66.897228970440608, -12.152229505587229 ], [ -66.889348313873597, -12.223181247716411 ], [ -66.919294807209553, -12.288758639499633 ], [ -66.905238817317581, -12.34167530716968 ], [ -66.927821418023996, -12.382241305491846 ], [ -67.973519864150376, -11.904854424791893 ], [ -68.012819789701496, -11.970018405425094 ], [ -68.215133022770772, -12.019937838660326 ], [ -68.2461647199259, -12.153676445511564 ], [ -68.271770392589531, -12.18132333730216 ], [ -68.390161099255295, -12.242456556524871 ], [ -68.476874151820653, -12.416709486653474 ], [ -68.50994706900201, -12.427406507804108 ], [ -68.558212856737953, -12.402291761555546 ], [ -68.581958177427907, -12.406942640590387 ], [ -68.629681362804661, -12.490813490150458 ], [ -68.689463238237863, -12.49341765609995 ], [ -69.577634643999943, -10.952301940999931 ], [ -69.502884684999941, -10.955299173999947 ], [ -69.395940307999894, -10.93504201199994 ], [ -69.086889404999908, -10.967184752999884 ], [ -68.996998250999894, -11.001704609999948 ], [ -68.8840335699999, -11.016380716999947 ], [ -68.80465856999993, -10.99467661599995 ], [ -68.757633016999932, -11.011936543999937 ], [ -68.791171020999855, -11.085110371999917 ], [ -68.775926473999903, -11.140610859999896 ], [ -68.615729532999893, -11.112498880999865 ], [ -68.536096150999953, -11.061545918999911 ], [ -68.428195760999927, -11.043665872999952 ], [ -68.378276326999867, -11.005011900999946 ], [ -68.293320271999903, -10.978966979999882 ], [ -68.112091023999938, -10.714073587999906 ], [ -68.043774780999883, -10.666944681999908 ], [ -67.862648885999874, -10.658779804999881 ], [ -67.755782022999938, -10.714176940999934 ], [ -67.721727254999877, -10.705495299999967 ], [ -67.68467525199992, -10.610514017999961 ], [ -67.584629678999931, -10.50178680399992 ], [ -67.468047648999857, -10.452280781999974 ], [ -67.41833491999995, -10.381484069999942 ], [ -67.342835652999923, -10.372492370999893 ], [ -67.337823038999971, -10.326086933999889 ], [ -67.323508666999885, -10.31885223399992 ], [ -67.184705769999965, -10.326707051999946 ], [ -67.151736206999914, -10.288983254999906 ], [ -67.064299682999945, -10.256943867999908 ], [ -66.902655802999931, -10.093129576999985 ], [ -66.770622517999954, -9.992567240999961 ], [ -66.66008662899992, -9.945334980999931 ], [ -66.642619995999979, -9.90792124399988 ], [ -66.513842325999889, -9.883943379999948 ], [ -66.432710327999956, -9.886113788999936 ], [ -66.190657918999875, -9.800847676999879 ], [ -66.118181721999889, -9.806015319999887 ], [ -66.086994995999902, -9.784517923999942 ], [ -66.029479126999888, -9.808289082999906 ], [ -65.946951863999857, -9.77139210999988 ], [ -65.86246089699992, -9.781830748999909 ], [ -65.834064696999889, -9.758266295999903 ], [ -65.806417805999871, -9.784414570999914 ], [ -65.788563598999929, -9.733048196999945 ], [ -65.772440552999853, -9.76880828799996 ], [ -65.709963744999868, -9.755992532999898 ], [ -65.713116007999929, -9.794233092999974 ], [ -65.678957886999854, -9.789375507999864 ], [ -65.628883422999934, -9.826892597999858 ], [ -65.583976603999929, -9.837227884999962 ], [ -65.510776936999946, -9.734081725999928 ], [ -65.44248653199989, -9.679821471999986 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "BO-B", "NAME_1": "El Beni" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -65.394646196065082, -10.392070070277555 ], [ -65.387270263999909, -10.4067021689999 ], [ -65.410938069999929, -10.449180195999929 ], [ -65.449979614999933, -10.468093769999967 ], [ -65.429231526999899, -10.561421406999926 ], [ -65.435691081999948, -10.625810241999929 ], [ -65.386753498999951, -10.66952850299991 ], [ -65.381069091999905, -10.698053893999955 ], [ -65.404736897999925, -10.799236348999941 ], [ -65.327118896999934, -10.850499368999877 ], [ -65.299110270999847, -10.982067565999927 ], [ -65.341975871999892, -11.032813821999909 ], [ -65.341045695999924, -11.106607767999961 ], [ -65.394737508999924, -11.153426614999972 ], [ -65.398148152999852, -11.178024596999961 ], [ -65.360010945999903, -11.218848978999858 ], [ -65.388613850999945, -11.253162129999879 ], [ -65.387270263999909, -11.277553404999907 ], [ -65.326447102999879, -11.327782897999953 ], [ -65.354765787999952, -11.382353209999891 ], [ -65.319548299999894, -11.476404316999933 ], [ -65.292469848999929, -11.504723001999935 ], [ -65.257562418999953, -11.495317890999971 ], [ -65.222654988999864, -11.517435403999883 ], [ -65.219244343999947, -11.584511413999905 ], [ -65.167438721999957, -11.615517272999938 ], [ -65.193354451999909, -11.632363789999914 ], [ -65.19619665599987, -11.741814472999948 ], [ -65.151496541999933, -11.773130390999953 ], [ -65.133978231999976, -11.702643737999907 ], [ -65.113411010999897, -11.690551452999927 ], [ -65.113566039999938, -11.722590839999924 ], [ -65.065558634999974, -11.753079935999907 ], [ -65.038454345999924, -11.818709004999945 ], [ -65.033674275999914, -11.879790547999932 ], [ -64.998120889999967, -11.90893605499987 ], [ -65.016336832999912, -11.968467304999933 ], [ -64.997449096999873, -11.996269225999896 ], [ -64.792500365999899, -12.03254608099985 ], [ -64.736793171999949, -12.119775898999947 ], [ -64.739532023999914, -12.144580585999975 ], [ -64.716277628999876, -12.146544290999913 ], [ -64.710283162999957, -12.111921080999906 ], [ -64.689922648999925, -12.104376321999951 ], [ -64.688992472999871, -12.153882343999911 ], [ -64.66485957799992, -12.180960794999876 ], [ -64.593416910999906, -12.215997415999894 ], [ -64.48939225299992, -12.239458515999956 ], [ -64.468153239999964, -12.272634785999884 ], [ -64.489779825999847, -12.373610533999909 ], [ -64.452521118999925, -12.390353697999956 ], [ -64.395728718999891, -12.457326354999864 ], [ -64.29769852799987, -12.465697936999931 ], [ -64.287544107999906, -12.497117207999878 ], [ -64.215222940999951, -12.473759459999926 ], [ -64.144787963999903, -12.520371601999983 ], [ -64.11982824699993, -12.489675801999852 ], [ -64.104454508999936, -12.507142435999896 ], [ -64.044458170999945, -12.509106139999929 ], [ -64.022831583999874, -12.537838235999928 ], [ -63.972447062999976, -12.523885599999943 ], [ -63.921235717999963, -12.544349466999904 ], [ -63.862893025999909, -12.46921193499989 ], [ -63.801398071999898, -12.454949238999916 ], [ -63.657737589999954, -12.475413105999877 ], [ -63.542189086999969, -12.547966816999889 ], [ -63.485758422999936, -12.557475280999967 ], [ -63.431446492999982, -12.636953633999966 ], [ -63.317913370999946, -12.701962585999922 ], [ -63.23595454999986, -12.698551940999906 ], [ -63.136684122999895, -12.633749695 ], [ -63.075034139999843, -12.65266326899993 ], [ -63.043459838999865, -12.719119160999895 ], [ -63.051107950999949, -12.742166849999947 ], [ -63.014727742999952, -12.777720234999919 ], [ -62.988011026999914, -12.843866067999983 ], [ -62.955144815999887, -12.857508646999889 ], [ -62.928893188999922, -12.846036478999878 ], [ -62.86507279499989, -12.935540059 ], [ -62.831431437999953, -12.94494516999994 ], [ -62.789831909999947, -13.00065236399989 ], [ -62.770453247999882, -13.01047088599995 ], [ -62.768644571999886, -12.990627135999958 ], [ -62.686634073999926, -12.964995625999904 ], [ -62.65133907099991, -12.992487487999966 ], [ -62.641675577999905, -13.030004577999961 ], [ -62.554600788999949, -13.066798196999869 ], [ -62.472125203999923, -13.06845184399991 ], [ -62.427476765999899, -13.124572448999956 ], [ -62.381846476999897, -13.13986867299991 ], [ -62.290327514999944, -13.142039082999901 ], [ -62.211520954999912, -13.120334981999903 ], [ -62.173952189999909, -13.140798848999864 ], [ -62.172453572999899, -13.117854512999926 ], [ -62.162376668999883, -13.120748392999914 ], [ -62.139845743999842, -13.14700002099994 ], [ -62.114679321999915, -13.150203958999924 ], [ -62.099228068999906, -13.262600198999863 ], [ -62.003264933999844, -13.360475361999946 ], [ -61.872316853999877, -13.456076761999924 ], [ -61.836350056999976, -13.540619404999902 ], [ -61.735115926999896, -13.538035582999981 ], [ -61.668091593999861, -13.512507425999956 ], [ -61.593060170999934, -13.506794492999958 ], [ -63.570403612336804, -14.618538913739883 ], [ -63.963015305911654, -14.737394707499732 ], [ -63.940200161208452, -14.832324313416336 ], [ -63.934748298295347, -15.027919609902085 ], [ -63.949786140118249, -15.08564218443928 ], [ -63.863176439441133, -15.298083997878223 ], [ -63.757989061046317, -15.456058851834541 ], [ -63.68812252543421, -15.504944757194778 ], [ -63.67016496444154, -15.580185642253582 ], [ -63.623811204623394, -15.627366225271089 ], [ -63.498676723851702, -15.692065117910886 ], [ -63.440876634049403, -15.774230645128171 ], [ -63.420696987675854, -15.856551201976401 ], [ -63.384807705011553, -15.891329440601226 ], [ -63.320599737887562, -15.916599215581357 ], [ -64.684108242101672, -15.842908624133713 ], [ -65.163898078033867, -15.907142428780048 ], [ -65.193922084836345, -15.927141208899684 ], [ -65.2732454090484, -16.071886895264015 ], [ -65.330864630798089, -16.279109388887207 ], [ -65.359570888885401, -16.324171237512587 ], [ -65.45555986199804, -16.368871351831444 ], [ -65.804375779718441, -16.465712985665789 ], [ -65.886153734207483, -16.466333103290083 ], [ -66.069579230297222, -16.420082696259442 ], [ -66.239232958234425, -16.316936536991591 ], [ -66.460795660791121, -16.074212335231095 ], [ -66.50353207124806, -15.97194467510667 ], [ -67.025644903789271, -15.476781100567337 ], [ -67.055875617066079, -15.43177092878534 ], [ -67.107500372644097, -15.400144951528318 ], [ -67.120006069824228, -15.367950535288969 ], [ -67.115510220420333, -15.289815768582855 ], [ -67.179072232397573, -15.165172214226288 ], [ -67.270513679262876, -15.036394544772406 ], [ -67.292708706341728, -15.015362236777833 ], [ -67.363892991568321, -15.012054945779141 ], [ -67.417558967172567, -14.968491713022161 ], [ -67.434250453595553, -14.896351414286357 ], [ -67.427506680389001, -14.754137871665478 ], [ -67.504116991006299, -14.668871759024455 ], [ -67.535975511360732, -14.598591810463688 ], [ -67.497838303994513, -14.551307874658676 ], [ -67.48794226762152, -14.511620374580616 ], [ -67.532383998622606, -14.443045750161275 ], [ -67.568169929398721, -14.330287773561906 ], [ -67.50360022616951, -14.258664238763629 ], [ -67.535975511360732, -13.998370049638083 ], [ -67.509207118713562, -13.87997934297232 ], [ -67.482722947805769, -13.836674492633733 ], [ -67.492644822600482, -13.771355483268962 ], [ -67.471664191449293, -13.710532321509447 ], [ -67.361076626085435, -13.573899834809538 ], [ -67.395596483191127, -13.402489108585485 ], [ -67.336659511827008, -13.304458917245256 ], [ -67.205943976033666, -13.167826429646027 ], [ -67.193179898233723, -13.129637545436367 ], [ -67.159073452277994, -13.107468356779236 ], [ -67.119928554559124, -13.03724008596123 ], [ -67.052258266805552, -13.015897718704764 ], [ -67.004095831857171, -12.901072685456086 ], [ -66.948569505178511, -12.670802504032338 ], [ -66.96665625738035, -12.581505629081505 ], [ -66.927666389292426, -12.525333347256151 ], [ -66.938285895177899, -12.420016777652165 ], [ -66.905238817317581, -12.34167530716968 ], [ -66.919294807209553, -12.288758639499633 ], [ -66.889348313873597, -12.223181247716411 ], [ -66.897228970440608, -12.152229505587229 ], [ -66.877436895896039, -12.064999688185083 ], [ -66.896970588022214, -11.965987644014547 ], [ -66.933066576261467, -11.911779066950373 ], [ -66.961333583877774, -11.910538831701729 ], [ -66.970609504425056, -11.848992200429734 ], [ -66.917615323288544, -11.841809176752122 ], [ -66.888366461942667, -11.818141370427895 ], [ -66.876842616693409, -11.795558769721424 ], [ -66.905290493261646, -11.735407402429701 ], [ -66.835604823903509, -11.727810967602068 ], [ -66.796769986345794, -11.685746351612863 ], [ -66.729022183327061, -11.674739272099714 ], [ -66.715276251797548, -11.655567315179439 ], [ -66.720857306819255, -11.583530369231141 ], [ -66.690833299117457, -11.537590019663696 ], [ -66.678999396405004, -11.449378349431299 ], [ -66.564794480780677, -11.434598890926054 ], [ -66.4970208402396, -11.442298678541192 ], [ -66.416715664096614, -11.400802504232217 ], [ -66.316876796726774, -11.385919692040147 ], [ -66.308918626693242, -11.344475192775917 ], [ -66.254632534363964, -11.33165943813259 ], [ -66.24316036595809, -11.31295256920572 ], [ -66.267758348269126, -11.277295830538151 ], [ -66.264115159586936, -11.253938083475759 ], [ -66.211534389600388, -11.174614760163081 ], [ -66.217838915033894, -11.097720228705612 ], [ -66.171175095953913, -11.100820815028612 ], [ -66.147223069688891, -11.080615330233286 ], [ -66.130609096732428, -10.981809990738498 ], [ -66.12153988265942, -10.968167412895809 ], [ -66.090353155873458, -10.969976088026044 ], [ -66.045342984091405, -10.867553399170049 ], [ -66.053275315703274, -10.851482028572775 ], [ -66.094849006176673, -10.858303317943751 ], [ -66.107923143238452, -10.840681654634636 ], [ -66.011675787707418, -10.789418634262574 ], [ -65.895042080227824, -10.811742851651275 ], [ -65.886722174988392, -10.764820651951538 ], [ -65.942429368820285, -10.719500420907707 ], [ -65.921784633554012, -10.682396741416483 ], [ -65.89806515218504, -10.679761243986206 ], [ -65.85623308019251, -10.723014417481409 ], [ -65.785746426056733, -10.701258639974242 ], [ -65.753112759346379, -10.666997166186263 ], [ -65.761432664585811, -10.564109388437544 ], [ -65.67391862724287, -10.57155079453355 ], [ -65.526253220809508, -10.486594740255043 ], [ -65.464241503342691, -10.406444593743004 ], [ -65.394646196065082, -10.392070070277555 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "BO-C", "NAME_1": "Cochabamba" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -66.989936490076957, -17.551279799023519 ], [ -66.841935186859359, -17.468080743031862 ], [ -66.870021328221696, -17.415370781836145 ], [ -66.850461798573122, -17.377491956888321 ], [ -66.885085007567056, -17.291502373835499 ], [ -66.897228970440608, -17.174972019143354 ], [ -66.948802049175242, -17.09647551813066 ], [ -67.010374517969638, -17.065056248247288 ], [ -67.012312385208418, -17.026247247312597 ], [ -66.977895880890173, -16.963873792841298 ], [ -66.970997077153356, -16.897159518596936 ], [ -66.932291429006227, -16.8351478002308 ], [ -66.798216926270129, -16.79525359457773 ], [ -66.758451910926965, -16.741148370301062 ], [ -66.765944993866356, -16.589529717722314 ], [ -66.816200323885823, -16.482972913768947 ], [ -66.799612189351024, -16.283295179928643 ], [ -66.834907192812693, -16.22944833717105 ], [ -66.870563930580943, -16.215237318547395 ], [ -66.872062547348662, -16.171105645009504 ], [ -66.949938930737062, -16.057830906271306 ], [ -66.944383714137075, -15.923833917001673 ], [ -66.918235440013518, -15.863992608072408 ], [ -66.934461839342418, -15.844717299263948 ], [ -66.784419317897175, -15.699299818431882 ], [ -66.50353207124806, -15.97194467510667 ], [ -66.460795660791121, -16.074212335231095 ], [ -66.239232958234425, -16.316936536991591 ], [ -66.069579230297222, -16.420082696259442 ], [ -65.886153734207483, -16.466333103290083 ], [ -65.804375779718441, -16.465712985665789 ], [ -65.45555986199804, -16.368871351831444 ], [ -65.359570888885401, -16.324171237512587 ], [ -65.330864630798089, -16.279109388887207 ], [ -65.2732454090484, -16.071886895264015 ], [ -65.193922084836345, -15.927141208899684 ], [ -65.163898078033867, -15.907142428780048 ], [ -64.684108242101672, -15.842908624133713 ], [ -64.657520718406431, -15.850453383017225 ], [ -64.664393683721528, -15.872467542942786 ], [ -64.703900315746978, -15.874741306066426 ], [ -64.67596920401553, -15.922490329864843 ], [ -64.703900315746978, -15.911586602239879 ], [ -64.730591193129044, -15.922490329864843 ], [ -64.688681606770729, -15.969929295300744 ], [ -64.689611781858218, -16.056590671022661 ], [ -64.661680671026147, -16.118033948607831 ], [ -64.677286952730697, -16.169090265203579 ], [ -64.67596920401553, -16.265156751782683 ], [ -64.699792039970646, -16.304689223129174 ], [ -64.67596920401553, -16.306084487109388 ], [ -64.696433072128571, -16.343963311157893 ], [ -64.684237434210218, -16.388353367114178 ], [ -64.723149787033037, -16.491086113433369 ], [ -64.779890509639301, -16.556146742178441 ], [ -64.778366055349181, -16.587255954598618 ], [ -64.751055060342765, -16.611182142441919 ], [ -64.807744107004908, -16.729624525951124 ], [ -64.782215948707062, -16.766263115650247 ], [ -64.741649950384897, -16.898399752946261 ], [ -64.647443813980829, -16.996016534035846 ], [ -64.591504076152205, -17.020252781140925 ], [ -64.503447434651378, -17.103141777870746 ], [ -64.375677456449466, -17.174610283937454 ], [ -64.238269823393637, -17.310932712274848 ], [ -64.212147385893161, -17.378732192136965 ], [ -64.224601406229908, -17.41599089856112 ], [ -64.339503953844371, -17.420693454439402 ], [ -64.396373866760541, -17.45629851716285 ], [ -64.405649787307823, -17.520377293077615 ], [ -64.564322272354957, -17.745686537104007 ], [ -64.689896002698333, -17.866971123618441 ], [ -64.710644089852849, -17.910741061950432 ], [ -64.641242642234147, -18.005257256717016 ], [ -64.589307827394293, -18.114914646094064 ], [ -64.488383755306074, -18.240333346806494 ], [ -64.441229010710288, -18.326116225183625 ], [ -64.445647345748398, -18.356398613505235 ], [ -64.420041673084711, -18.420942478312725 ], [ -64.302116055311672, -18.499594008057045 ], [ -64.29325354681373, -18.591009616500628 ], [ -64.340201585834507, -18.65694874348975 ], [ -64.369993048640254, -18.608941339071521 ], [ -64.391412930262504, -18.60180999043871 ], [ -64.493990647850126, -18.666250501559432 ], [ -64.57458004393385, -18.666715589552837 ], [ -64.685012579666818, -18.540108330435089 ], [ -64.771699794709775, -18.521194756832585 ], [ -64.816038173822676, -18.484659519021591 ], [ -64.910270147749088, -18.506725355790536 ], [ -65.001944138611123, -18.555921318613969 ], [ -65.066798061781128, -18.654778334052878 ], [ -65.157257656715501, -18.613643894050483 ], [ -65.231387498634149, -18.616279391480759 ], [ -65.250249396292588, -18.530238131584497 ], [ -65.293502569787734, -18.495356541071544 ], [ -65.305956590124538, -18.451844985157948 ], [ -65.336988288178929, -18.451896661102012 ], [ -65.350966762805854, -18.410245457162148 ], [ -65.436310390711924, -18.369266045891322 ], [ -65.510336879843123, -18.266688328303701 ], [ -65.595396287808398, -18.203694757107371 ], [ -65.642370165250895, -18.129073988773541 ], [ -65.843313971862301, -17.968308607756057 ], [ -65.94025895938347, -17.981331068873715 ], [ -66.018522914600794, -17.862165215852031 ], [ -66.175154182319659, -17.866816094886872 ], [ -66.346435716435167, -17.988617446238152 ], [ -66.534382901249899, -17.976938572257325 ], [ -66.624920009650737, -17.991252943668428 ], [ -66.68047217475106, -17.863973890982265 ], [ -66.808345505740476, -17.687912285723428 ], [ -66.989936490076957, -17.551279799023519 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/chile.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/chile.geojson new file mode 100644 index 0000000000000..f07ed52bee545 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/chile.geojson @@ -0,0 +1,22 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "CL-AP", "NAME_1": "Arica y Parinacota" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.510088751999945, -17.506588197999946 ], [ -69.497122762999965, -17.621403909999884 ], [ -69.334238647999911, -17.805785420999968 ], [ -69.302405964999963, -17.976214293999888 ], [ -69.081721761999916, -18.039983011999908 ], [ -69.155438192999924, -18.140235289999936 ], [ -69.034386148999943, -18.478302510999896 ], [ -68.959842895999884, -18.907837015999903 ], [ -69.078336147894902, -19.049948011591482 ], [ -69.19298031309097, -19.102864679261529 ], [ -69.788292813362659, -18.98819467474442 ], [ -70.270334439282919, -19.171482028672699 ], [ -70.356597459999932, -18.773370049999926 ], [ -70.303561491999915, -18.445438941999953 ], [ -70.394702746778677, -18.337746206368088 ], [ -70.159067226999895, -18.325969708999963 ], [ -69.970344894999897, -18.250625470999907 ], [ -69.783095342999928, -17.981597962999913 ], [ -69.849835454999948, -17.691589825999912 ], [ -69.683902430999865, -17.656036439999951 ], [ -69.510088751999945, -17.506588197999946 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-TA", "NAME_1": "Tarapacá" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.9896085213162, -18.946490987269271 ], [ -68.908502359999943, -19.067930602999908 ], [ -68.447626098999905, -19.434626566999938 ], [ -68.70321773299986, -19.715539652999965 ], [ -68.553511107999981, -19.857856546999926 ], [ -68.579349324999896, -20.045441995999909 ], [ -68.792592121999945, -20.106626891999923 ], [ -68.726265421999926, -20.150965270999876 ], [ -68.678516398999932, -20.32862884499994 ], [ -68.757684692999959, -20.36428558399993 ], [ -68.75070837399997, -20.451825459999924 ], [ -68.480957397999873, -20.624734802999896 ], [ -68.572786417999907, -20.742867126999982 ], [ -68.531554425999872, -20.927688032999924 ], [ -68.557902798375437, -21.064140313124938 ], [ -68.690220302824684, -21.124446710047607 ], [ -68.794348314023466, -21.240873711952247 ], [ -69.449993048740168, -21.446339207288588 ], [ -69.742404140638541, -21.384172459291563 ], [ -69.913298102025749, -21.451300143786625 ], [ -70.061354116260617, -21.448341796045341 ], [ -70.080094470999938, -21.23332500999993 ], [ -70.171294725999928, -21.014580987999921 ], [ -70.12746248499991, -20.935275 ], [ -70.213844252999934, -20.811577406999959 ], [ -70.12328040299991, -19.999932549999926 ], [ -70.151193813999953, -19.719414971999925 ], [ -70.242544126999917, -19.598202934999904 ], [ -70.199574347999942, -19.534356377999927 ], [ -70.28774980399993, -19.300957940999922 ], [ -70.270334439282919, -19.171482028672699 ], [ -69.788292813362659, -18.98819467474442 ], [ -69.19298031309097, -19.102864679261529 ], [ -68.9896085213162, -18.946490987269271 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-AN", "NAME_1": "Antofagasta" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.531554425999872, -20.927688032999924 ], [ -68.416310180999915, -20.959804788999932 ], [ -68.207537394999889, -21.284332783999915 ], [ -68.198442341999908, -21.571860452999942 ], [ -68.107595173999925, -21.789624938999907 ], [ -68.096226359999946, -21.953955993999955 ], [ -67.960627400999982, -22.102887470999917 ], [ -67.951894083999917, -22.334087828999941 ], [ -67.859186564999931, -22.547304788999966 ], [ -67.876343139999904, -22.833592223999872 ], [ -67.616772420999951, -22.89725758799996 ], [ -67.193904174999972, -22.82222340899996 ], [ -67.013966837999874, -23.000713805999879 ], [ -67.339786742999905, -24.000601094999936 ], [ -68.244486043999927, -24.385383809999979 ], [ -68.326806599999884, -24.49824513699987 ], [ -68.397654988999932, -24.500518899999875 ], [ -68.451501831999877, -24.629296569999966 ], [ -68.503695027999953, -24.612346699999961 ], [ -68.578005737999945, -24.80871714299991 ], [ -68.473050903999933, -24.907935892999973 ], [ -68.36664912899991, -25.123426614999929 ], [ -68.493049682999953, -25.155879414999944 ], [ -68.554228469999913, -25.291191962999903 ], [ -68.68975521483128, -25.370854180675906 ], [ -69.005524054691364, -25.38501352245612 ], [ -68.9942585918605, -25.479581394066088 ], [ -69.079524706300163, -25.649545179466486 ], [ -69.441001349932321, -25.679879245530742 ], [ -69.568254564196764, -25.64804656269871 ], [ -69.711449957849254, -25.660810642297292 ], [ -69.883248256801608, -25.746696872562609 ], [ -70.147340664240232, -25.737136732973852 ], [ -70.271415777815889, -25.826226901450354 ], [ -70.398694831401315, -25.823074640082552 ], [ -70.634635707410524, -26.028631179974749 ], [ -70.739985094999952, -25.829322758999922 ], [ -70.634774733999905, -25.625502419999918 ], [ -70.646880662999934, -25.521661065999922 ], [ -70.538482225999928, -25.468194268999923 ], [ -70.444813605999911, -25.344903252999927 ], [ -70.437001105999911, -25.193454684999949 ], [ -70.500599738999938, -25.095472914999959 ], [ -70.472727016999897, -24.975274346999925 ], [ -70.57640540299991, -24.73170338299991 ], [ -70.582834438999953, -24.524834893999923 ], [ -70.506097837999903, -24.167380796999907 ], [ -70.498524542999917, -23.784600518999923 ], [ -70.390736456999946, -23.576918226999908 ], [ -70.413084759999947, -23.511252712999919 ], [ -70.49698299399995, -23.469472339999925 ], [ -70.539315015999932, -23.532273105999934 ], [ -70.631612254999936, -23.517038645999946 ], [ -70.585072394999941, -23.423597914999959 ], [ -70.600123425999925, -23.244225197999924 ], [ -70.562245245999918, -23.05982838299991 ], [ -70.50617428299995, -23.010023695999905 ], [ -70.48438615799995, -23.086034158999951 ], [ -70.425423188999901, -23.088530150999929 ], [ -70.291574673999946, -22.901950778999947 ], [ -70.312570766999897, -22.790622653999947 ], [ -70.240589972999942, -22.48756275799991 ], [ -70.192128058999913, -21.884372653999947 ], [ -70.150054490999935, -21.861993096999925 ], [ -70.150217251999948, -21.653497002999927 ], [ -70.082915818999936, -21.483330987999921 ], [ -69.742404140638541, -21.384172459291563 ], [ -69.449993048740168, -21.446339207288588 ], [ -68.794348314023466, -21.240873711952247 ], [ -68.690220302824684, -21.124446710047607 ], [ -68.557902798375437, -21.064140313124938 ], [ -68.531554425999872, -20.927688032999924 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-AT", "NAME_1": "Atacama" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.554228469999913, -25.291191962999903 ], [ -68.608236449999936, -25.492913105999918 ], [ -68.409023804999919, -26.144242857999885 ], [ -68.57516353399987, -26.303509623999958 ], [ -68.595317342999948, -26.457298685999945 ], [ -68.570150919999918, -26.5506263219999 ], [ -68.305360880999871, -26.897995300999895 ], [ -68.330475626999885, -27.04496307299992 ], [ -68.518009398999936, -27.076899108999982 ], [ -68.585860554999954, -27.162785338999925 ], [ -68.718617309999843, -27.106664733999892 ], [ -68.814322061999945, -27.120307311999895 ], [ -68.931446695999881, -27.395225931999889 ], [ -69.017410441999914, -27.460441588999913 ], [ -69.190190592999869, -27.951367695999892 ], [ -69.303232787999889, -27.999530130999887 ], [ -69.420305744999894, -28.212643737999983 ], [ -69.490508178999875, -28.198381041999909 ], [ -69.653030558999916, -28.397852070999903 ], [ -69.678403686999928, -28.573861998999931 ], [ -69.753386189999901, -28.67339080799988 ], [ -69.73276729299991, -28.794313658999926 ], [ -69.802788859999907, -28.939937845999893 ], [ -69.803925740999915, -29.098687845999933 ], [ -69.910947631999903, -29.143232930999929 ], [ -70.040655477999849, -29.297538757999959 ], [ -69.929352837999886, -29.717877115999968 ], [ -70.089153001709633, -29.746969495845576 ], [ -70.302163255030166, -29.675604342566373 ], [ -70.455978156366825, -29.510859876981726 ], [ -70.605323045821876, -29.091453953237362 ], [ -70.708133308305548, -29.070886733236136 ], [ -70.762832810885527, -29.151346938110692 ], [ -70.974706184442823, -29.206640719893301 ], [ -71.052375861356893, -29.385802910575876 ], [ -71.199317795579816, -29.335470066190624 ], [ -71.337345547159259, -29.192378024426262 ], [ -71.487120921937759, -29.211343169083875 ], [ -71.511219855999911, -28.889580987999921 ], [ -71.301869269999941, -28.674899997999944 ], [ -71.316232876999948, -28.572930596999925 ], [ -71.173939581999946, -28.36060963299991 ], [ -71.173085089999915, -28.092950127999927 ], [ -71.104725714999915, -27.838962497999944 ], [ -71.031605597999942, -27.657403252999927 ], [ -70.91242428299995, -27.621840101999908 ], [ -70.891672329999949, -27.493096612999921 ], [ -70.959950324999909, -27.16139088299991 ], [ -70.929269985999952, -27.10670338299991 ], [ -70.870838995999918, -27.117852471999925 ], [ -70.788644985999952, -26.996270440999922 ], [ -70.824208136999914, -26.873793226999908 ], [ -70.732466942999906, -26.749280592999924 ], [ -70.699289516999897, -26.392998955999929 ], [ -70.629954372999919, -26.340976922999914 ], [ -70.681443437999917, -26.304495915999951 ], [ -70.634635707410524, -26.028631179974749 ], [ -70.398694831401315, -25.823074640082552 ], [ -70.271415777815889, -25.826226901450354 ], [ -70.147340664240232, -25.737136732973852 ], [ -69.883248256801608, -25.746696872562609 ], [ -69.711449957849254, -25.660810642297292 ], [ -69.568254564196764, -25.64804656269871 ], [ -69.441001349932321, -25.679879245530742 ], [ -69.079524706300163, -25.649545179466486 ], [ -68.9942585918605, -25.479581394066088 ], [ -69.005524054691364, -25.38501352245612 ], [ -68.716678636210077, -25.379432467434413 ], [ -68.554228469999913, -25.291191962999903 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-CO", "NAME_1": "Coquimbo" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.929352837999886, -29.717877115999968 ], [ -69.922187256999877, -29.939566751999905 ], [ -69.980374918999871, -30.07247853599992 ], [ -69.849736898999879, -30.126635436999933 ], [ -69.848961750999962, -30.199085794999917 ], [ -69.964587768999877, -30.374785664999948 ], [ -70.173412231999919, -30.364657084999905 ], [ -70.143930826999906, -30.439587910999961 ], [ -70.21710465599989, -30.51513885499989 ], [ -70.339216064999874, -30.938162129999924 ], [ -70.266559000999933, -31.036450703999932 ], [ -70.339784505999916, -31.041721699999954 ], [ -70.408643350999938, -31.150035501999895 ], [ -70.479801798999887, -31.096705423999907 ], [ -70.568969482999904, -31.304237975999897 ], [ -70.589769246999936, -31.567684427999964 ], [ -70.475228433999916, -31.82007212399995 ], [ -70.244467326999938, -31.942235208999932 ], [ -70.284697428999948, -32.046776631999947 ], [ -70.387481852999883, -32.041712340999965 ], [ -70.330823609022332, -32.209588118696729 ], [ -70.444454312016887, -32.21405404945483 ], [ -70.721233282889671, -32.030499363055185 ], [ -70.959875047295611, -31.97391367007981 ], [ -71.045425380776692, -32.030654391786754 ], [ -71.180972662758165, -31.997116387511255 ], [ -71.338999192658605, -32.079230238784476 ], [ -71.448372362094801, -32.043160088966943 ], [ -71.543839657530185, -32.193026502100871 ], [ -71.501128709999932, -31.889825127999927 ], [ -71.666167772999927, -31.169854424999926 ], [ -71.703480597999942, -30.508558851999908 ], [ -71.637766079999949, -30.24146900799991 ], [ -71.542144334999932, -30.285332940999922 ], [ -71.445912238999938, -30.162367445999905 ], [ -71.398793097999942, -30.176690362999921 ], [ -71.412464972999942, -29.991794528999947 ], [ -71.297759568999936, -29.933851820999905 ], [ -71.282582160999937, -29.88014088299991 ], [ -71.335926886999914, -29.728122653999947 ], [ -71.288075324999909, -29.603122653999947 ], [ -71.336048956999946, -29.524997653999947 ], [ -71.30882727799991, -29.408868096999925 ], [ -71.360910610999952, -29.295586846999925 ], [ -71.487120921937759, -29.211343169083875 ], [ -71.337345547159259, -29.192378024426262 ], [ -71.199317795579816, -29.335470066190624 ], [ -71.052375861356893, -29.385802910575876 ], [ -70.974706184442823, -29.206640719893301 ], [ -70.762832810885527, -29.151346938110692 ], [ -70.708133308305548, -29.070886733236136 ], [ -70.605323045821876, -29.091453953237362 ], [ -70.455978156366825, -29.510859876981726 ], [ -70.302163255030166, -29.675604342566373 ], [ -70.089153001709633, -29.746969495845576 ], [ -69.929352837999886, -29.717877115999968 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-RM", "NAME_1": "Región Metropolitana de Santiago" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.10610066299995, -33.052592520999909 ], [ -70.10946264699993, -33.169602151999925 ], [ -70.010011352999925, -33.299103291999913 ], [ -69.869684000999911, -33.249597269999953 ], [ -69.787673502999922, -33.379408466999934 ], [ -69.878830728999873, -33.558002216999867 ], [ -69.860046345999876, -33.7263640339999 ], [ -69.91425492399992, -33.771942647999893 ], [ -69.832761189999957, -34.243231709999932 ], [ -70.04817621499987, -34.283461794999965 ], [ -70.188759325082799, -34.081536960762151 ], [ -70.313997157742619, -34.060039564774115 ], [ -70.437581345802471, -33.9001526829 ], [ -70.811563686614818, -33.957565199973999 ], [ -70.815000169722055, -34.027380059642041 ], [ -70.949126350200913, -34.151041762067678 ], [ -71.066845262398942, -34.185768324748381 ], [ -71.712077195905863, -33.981439710973859 ], [ -71.400675015139825, -33.797109876419654 ], [ -71.366723598815042, -33.512682793875854 ], [ -71.451188726678367, -33.433307793719678 ], [ -71.44431576226259, -33.336879571035354 ], [ -71.053357713287824, -33.044442640715317 ], [ -70.79812781434714, -32.9604167615243 ], [ -70.676507331048469, -33.013281751451643 ], [ -70.61622677344684, -32.973645929116344 ], [ -70.302008226298597, -33.171359959094843 ], [ -70.10610066299995, -33.052592520999909 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-VS", "NAME_1": "Valparaíso" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -70.256119043999973, -32.314277880999953 ], [ -70.13772965499993, -32.56901865599994 ], [ -70.181086181999916, -32.607569274999918 ], [ -70.155738891999931, -32.738414001999956 ], [ -70.000218668999963, -32.876596780999918 ], [ -70.04248998999995, -32.992662047999943 ], [ -70.302008226298597, -33.171359959094843 ], [ -70.61622677344684, -32.973645929116344 ], [ -70.676507331048469, -33.013281751451643 ], [ -70.79812781434714, -32.9604167615243 ], [ -71.053357713287824, -33.044442640715317 ], [ -71.44431576226259, -33.336879571035354 ], [ -71.451188726678367, -33.433307793719678 ], [ -71.366723598815042, -33.512682793875854 ], [ -71.400675015139825, -33.797109876419654 ], [ -71.717942470868309, -33.971156100973303 ], [ -71.871253985532391, -33.93280402130739 ], [ -71.808094855999911, -33.776950778999947 ], [ -71.671864386999914, -33.69850025799991 ], [ -71.624663865999935, -33.541436455999929 ], [ -71.705922003999945, -33.434340101999908 ], [ -71.671864386999914, -33.325778903999947 ], [ -71.761870897999927, -33.101983330999929 ], [ -71.572865363999938, -33.010186455999929 ], [ -71.518299933999913, -32.873142184999949 ], [ -71.548695441999939, -32.78484465899993 ], [ -71.454172329999949, -32.685642184999949 ], [ -71.476714647999927, -32.535251559999949 ], [ -71.407948370999918, -32.386325778999947 ], [ -71.543853318999936, -32.193291924999926 ], [ -71.448372362094801, -32.043160088966943 ], [ -71.338999192658605, -32.079230238784476 ], [ -71.180972662758165, -31.997116387511255 ], [ -71.045425380776692, -32.030654391786754 ], [ -70.959875047295611, -31.97391367007981 ], [ -70.771902024958479, -32.012309258965104 ], [ -70.444454312016887, -32.21405404945483 ], [ -70.330823609022332, -32.209588118696729 ], [ -70.321801107999931, -32.280147399999947 ], [ -70.256119043999973, -32.314277880999953 ] ] ], [ [ [ -80.759348110999952, -33.766778252999927 ], [ -80.777333136999914, -33.734470309999949 ], [ -80.740834113999938, -33.685153903999947 ], [ -80.704701300999943, -33.766778252999927 ], [ -80.759348110999952, -33.766778252999927 ] ] ], [ [ [ -78.788970506999931, -33.60906340899993 ], [ -78.757639126999948, -33.643243096999925 ], [ -78.991688605999911, -33.656914971999925 ], [ -78.884877081999946, -33.575616143999923 ], [ -78.788970506999931, -33.60906340899993 ] ] ], [ [ [ -109.231597459999932, -27.092461846999925 ], [ -109.243560350999928, -27.129164320999905 ], [ -109.451324022999927, -27.195489190999922 ], [ -109.379628058999913, -27.059502862999921 ], [ -109.231597459999932, -27.092461846999925 ] ] ], [ [ [ -105.459543423999946, -26.464776299999926 ], [ -105.47093665299991, -26.457696221999925 ], [ -105.463490363999938, -26.456963799999926 ], [ -105.459543423999946, -26.464776299999926 ] ] ], [ [ [ -79.901763475999928, -26.347426039999903 ], [ -79.890736456999946, -26.351739190999922 ], [ -79.890207485999952, -26.356052341999941 ], [ -79.909413214999915, -26.358168226999908 ], [ -79.901763475999928, -26.347426039999903 ] ] ], [ [ [ -80.095692511999914, -26.266045830999929 ], [ -80.090443488999938, -26.274509372999944 ], [ -80.107777472999942, -26.274997653999947 ], [ -80.095692511999914, -26.266045830999929 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-ML", "NAME_1": "Maule" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.372446571999944, -35.027388544999923 ], [ -70.38662919099994, -35.166689553999859 ], [ -70.578891357999908, -35.259707132999921 ], [ -70.428383748999892, -35.357065530999961 ], [ -70.471766113999877, -35.37938974999993 ], [ -70.361566121999942, -35.78308603999993 ], [ -70.420244710999981, -35.8683521519999 ], [ -70.38032466699994, -36.046015726999954 ], [ -70.451483113999871, -36.152262471999933 ], [ -70.581423502999883, -36.143167418999951 ], [ -70.710511230999941, -36.265847269999895 ], [ -70.71865026899988, -36.414572041999904 ], [ -70.907786010999956, -36.40516693099994 ], [ -70.971037963999947, -36.485472106999879 ], [ -71.108754848757258, -36.401912123245893 ], [ -71.414723088123154, -36.426077007963855 ], [ -72.050609503625708, -36.124047946755354 ], [ -72.190402738456243, -36.195604514567279 ], [ -72.38304015761193, -36.187401449057717 ], [ -72.496060349605443, -36.059865818053083 ], [ -72.698218553043773, -36.012685235035576 ], [ -72.799135160834751, -36.053102038421557 ], [ -72.793324347999942, -35.967461846999925 ], [ -72.583566860999952, -35.770603122999944 ], [ -72.646595831999946, -35.566582940999922 ], [ -72.529652472999942, -35.490411065999922 ], [ -72.398060675999943, -35.233493747999944 ], [ -72.230580206999946, -35.116143487999921 ], [ -72.18781490799995, -34.885511976999908 ], [ -72.103016730999911, -34.760918877999927 ], [ -71.736804369426068, -34.951044609521091 ], [ -71.417960781664704, -34.925309746547555 ], [ -71.325718350021816, -34.845159600934835 ], [ -71.170534024025983, -34.818391209186927 ], [ -70.95695532902522, -34.915439547696963 ], [ -70.785131191651146, -34.919883722056113 ], [ -70.649248012885494, -35.013986504773357 ], [ -70.372446571999944, -35.027388544999923 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-LI", "NAME_1": "Libertador General Bernardo O'Higgins" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.04817621499987, -34.283461794999965 ], [ -70.067578898999869, -34.414590759999982 ], [ -70.316297566999935, -34.745629983999933 ], [ -70.276713419999879, -34.798236592999928 ], [ -70.372446571999944, -35.027388544999923 ], [ -70.649248012885494, -35.013986504773357 ], [ -70.785131191651146, -34.919883722056113 ], [ -70.95695532902522, -34.915439547696963 ], [ -71.170534024025983, -34.818391209186927 ], [ -71.325718350021816, -34.845159600934835 ], [ -71.417960781664704, -34.925309746547555 ], [ -71.736804369426068, -34.951044609521091 ], [ -72.103016730999911, -34.760918877999927 ], [ -72.057240363999938, -34.658786716999941 ], [ -72.055490688999953, -34.428155205999929 ], [ -71.989084438999953, -34.355238539999903 ], [ -72.026844855999911, -34.162692966999941 ], [ -71.871253985532391, -33.93280402130739 ], [ -71.066845262398942, -34.185768324748381 ], [ -70.949126350200913, -34.151041762067678 ], [ -70.815000169722055, -34.027380059642041 ], [ -70.811563686614818, -33.957565199973999 ], [ -70.437581345802471, -33.9001526829 ], [ -70.313997157742619, -34.060039564774115 ], [ -70.188759325082799, -34.081536960762151 ], [ -70.04817621499987, -34.283461794999965 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-NB", "NAME_1": "Ñuble" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.027819303999934, -36.481168389999937 ], [ -71.057440958999905, -36.687630309999903 ], [ -71.145342569999912, -36.688250426999957 ], [ -71.196863973999911, -36.848240661999938 ], [ -71.135679077999981, -36.951490173999986 ], [ -71.207147583999898, -36.972367451999958 ], [ -71.089118611999936, -37.103418884999968 ], [ -71.257224486867983, -37.104549661739036 ], [ -71.451313946871565, -37.036579979880294 ], [ -71.572324374856237, -37.13094363717142 ], [ -72.203955119703437, -37.198294008409931 ], [ -72.268925914689063, -37.154626315306011 ], [ -72.187237227153787, -37.053143363119943 ], [ -72.21278575311031, -37.019094912370321 ], [ -72.385944239307804, -36.924838597873659 ], [ -72.654597449781946, -36.915770531963773 ], [ -72.556317032128902, -36.871810455610031 ], [ -72.600239533150457, -36.724008440769524 ], [ -72.798250177494268, -36.605965154944123 ], [ -72.812602241784518, -36.462806388067506 ], [ -72.895863410999937, -36.438083591999941 ], [ -72.826161261999914, -36.287041924999926 ], [ -72.819081183999913, -36.081149997999944 ], [ -72.698218553043773, -36.012685235035576 ], [ -72.496060349605443, -36.059865818053083 ], [ -72.38304015761193, -36.187401449057717 ], [ -72.190402738456243, -36.195604514567279 ], [ -72.050609503625708, -36.124047946755354 ], [ -71.414723088123154, -36.426077007963855 ], [ -71.108754848757258, -36.401912123245893 ], [ -71.027819303999934, -36.481168389999937 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-AR", "NAME_1": "La Araucanía" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -71.016142412999869, -38.143697093999947 ], [ -70.97375097699998, -38.424681904999957 ], [ -70.83430212499988, -38.564414977999931 ], [ -70.87383459499992, -38.691435648999942 ], [ -71.399900674999884, -38.910543720999968 ], [ -71.412044636999951, -39.317960713999881 ], [ -71.541959187999879, -39.532314554999914 ], [ -71.495657104999879, -39.565594176999952 ], [ -71.519996703999908, -39.614996845999968 ], [ -71.632392944999935, -39.607555439999956 ], [ -71.680916306642246, -39.495986829428659 ], [ -71.770213181593022, -39.455369155162373 ], [ -71.992034268366751, -39.729719334179947 ], [ -72.373845588003462, -39.733026625178582 ], [ -72.54533382769398, -39.623214207070021 ], [ -72.966186693161376, -39.589159437957676 ], [ -72.956936611935078, -39.37976653399835 ], [ -73.246694477929154, -39.385850630523741 ], [ -73.209828253999945, -39.193780205999929 ], [ -73.245432094999899, -39.221286716999941 ], [ -73.433420376999948, -38.686944268999923 ], [ -73.445057745999918, -38.76140715899993 ], [ -73.520659959999932, -38.521579684999949 ], [ -73.525135870999918, -38.475681247999944 ], [ -73.364172736182809, -38.425354506005647 ], [ -73.270457526193866, -38.476824232852039 ], [ -73.280818650560263, -38.331665133539104 ], [ -73.091372849877132, -38.137826837138846 ], [ -73.166562058991815, -38.025017184595413 ], [ -73.059152595216062, -37.811335137706465 ], [ -73.111940069878301, -37.722038262755632 ], [ -73.071554937810106, -37.649277845496158 ], [ -72.505646327615921, -37.679508558772966 ], [ -72.377204555845537, -37.853554782427238 ], [ -72.089160122141891, -38.01649057378097 ], [ -71.720629645142026, -38.057056573002455 ], [ -71.745563524237241, -38.102273451258782 ], [ -71.655078090881204, -38.246140638479687 ], [ -71.312928432900833, -38.063051039174127 ], [ -71.016142412999869, -38.143697093999947 ] ] ], [ [ [ -73.882435675999943, -38.360772393999923 ], [ -73.912098761999914, -38.409926039999903 ], [ -73.95343990799995, -38.313571872999944 ], [ -73.930775519999941, -38.323825778999947 ], [ -73.882435675999943, -38.360772393999923 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-BI", "NAME_1": "Bío-Bío" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -71.089118611999936, -37.103418884999968 ], [ -71.205597289999872, -37.292657978999983 ], [ -71.117695678999979, -37.466497497999924 ], [ -71.127927611999951, -37.584423115999954 ], [ -71.192264770999941, -37.660904235999936 ], [ -71.007418171999916, -38.071008402999965 ], [ -71.016142412999869, -38.143697093999947 ], [ -71.312928432900833, -38.063051039174127 ], [ -71.655078090881204, -38.246140638479687 ], [ -71.745563524237241, -38.102273451258782 ], [ -71.720629645142026, -38.057056573002455 ], [ -72.089160122141891, -38.01649057378097 ], [ -72.377204555845537, -37.853554782427238 ], [ -72.505646327615921, -37.679508558772966 ], [ -73.061090460656203, -37.647159112003408 ], [ -73.111940069878301, -37.722038262755632 ], [ -73.059152595216062, -37.811335137706465 ], [ -73.166562058991815, -38.025017184595413 ], [ -73.091372849877132, -38.137826837138846 ], [ -73.280818650560263, -38.331665133539104 ], [ -73.270457526193866, -38.476824232852039 ], [ -73.364172736182809, -38.425354506005647 ], [ -73.524768911556009, -38.478105612983654 ], [ -73.462961391999897, -38.051202080999929 ], [ -73.668080206999946, -37.719414971999925 ], [ -73.685129360999952, -37.598402601999908 ], [ -73.59788977799991, -37.49187590899993 ], [ -73.680409308999913, -37.347832940999922 ], [ -73.644642706999946, -37.201429945999905 ], [ -73.594471808999913, -37.152439059999949 ], [ -73.460682745999918, -37.241957289999903 ], [ -73.23696855399993, -37.191501559999949 ], [ -73.173329230999911, -37.076348565999922 ], [ -73.145375128999945, -36.833916924999926 ], [ -73.207427537999934, -36.775323174999926 ], [ -73.131703253999945, -36.736423434999949 ], [ -73.118641730999911, -36.597100518999923 ], [ -73.070220506999931, -36.713799737999921 ], [ -72.988026495999918, -36.702569268999923 ], [ -72.986195441999939, -36.521416924999926 ], [ -72.932240363999938, -36.523614190999922 ], [ -72.895863410999937, -36.438083591999941 ], [ -72.812602241784518, -36.462806388067506 ], [ -72.798250177494268, -36.605965154944123 ], [ -72.600239533150457, -36.724008440769524 ], [ -72.556317032128902, -36.871810455610031 ], [ -72.654597449781946, -36.915770531963773 ], [ -72.385944239307804, -36.924838597873659 ], [ -72.191888626439834, -37.033175127816605 ], [ -72.259358093345199, -37.098049955915727 ], [ -72.241708181749033, -37.190968392267031 ], [ -71.572324374856237, -37.13094363717142 ], [ -71.451313946871565, -37.036579979880294 ], [ -71.257224486867983, -37.104549661739036 ], [ -71.089118611999936, -37.103418884999968 ] ] ], [ [ [ -73.540830256999925, -36.989441495999927 ], [ -73.523095958999932, -36.975265374999935 ], [ -73.446493783999927, -37.059169519999955 ], [ -73.518884494999952, -37.079921528999932 ], [ -73.540830256999925, -36.989441495999927 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-LR", "NAME_1": "Los Ríos" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.641098842999952, -39.599999000999915 ], [ -71.705411743999974, -39.583577574999936 ], [ -71.714351766999897, -39.726307881999929 ], [ -71.61663163299994, -39.909862568999898 ], [ -71.683707641999973, -40.098998311999893 ], [ -71.814035603999884, -40.092900492999931 ], [ -71.823750773999933, -40.210102640999963 ], [ -71.742670450999896, -40.296505635999949 ], [ -71.68670487499989, -40.288547464999894 ], [ -71.678488321999879, -40.34022389699993 ], [ -71.729286255999881, -40.421355895999881 ], [ -71.796413940999912, -40.414534606999922 ], [ -71.892634649669333, -40.593490899185667 ], [ -72.011438768384437, -40.65131682651031 ], [ -72.634346482704018, -40.652918796964912 ], [ -72.88626908974669, -40.522280775537354 ], [ -72.992877569644122, -40.353040459649492 ], [ -73.748646613999938, -40.273044528999947 ], [ -73.73501542899993, -40.174737237999921 ], [ -73.659982876999948, -40.109551690999922 ], [ -73.71117102799991, -39.968682549999926 ], [ -73.458404100999928, -39.833754164999903 ], [ -73.378773566999939, -39.900485934999949 ], [ -73.406076626999948, -39.694919528999947 ], [ -73.241566535999937, -39.48951588299991 ], [ -73.24645382398478, -39.385761000170021 ], [ -72.956936611935078, -39.37976653399835 ], [ -72.966186693161376, -39.589159437957676 ], [ -72.54533382769398, -39.623214207070021 ], [ -72.373845588003462, -39.733026625178582 ], [ -71.992034268366751, -39.729719334179947 ], [ -71.770213181593022, -39.455369155162373 ], [ -71.680916306642246, -39.495986829428659 ], [ -71.641098842999952, -39.599999000999915 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-LL", "NAME_1": "Los Lagos" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -71.769259569273686, -41.999606621748171 ], [ -71.749440063999941, -42.10435394299995 ], [ -71.923796346999922, -42.176907653999962 ], [ -72.009837605999905, -42.124714456999897 ], [ -72.12471431599991, -42.263310648999948 ], [ -72.039189819999962, -42.481230163999953 ], [ -72.143214477999919, -42.557091165999879 ], [ -72.112673705999924, -42.863842467999916 ], [ -72.148537150999886, -42.99871795599995 ], [ -72.054434366999914, -43.105378112999944 ], [ -71.750163533999938, -43.172454121999877 ], [ -71.750680297999878, -43.295340677999945 ], [ -71.901730509999908, -43.322005716999897 ], [ -71.955112264999912, -43.443548685999929 ], [ -71.868812621999979, -43.462565612999896 ], [ -71.873825235999931, -43.538943379999935 ], [ -71.714300089999881, -43.602195332999926 ], [ -71.709184122999915, -43.684360859999956 ], [ -71.819203246999905, -43.758051452999965 ], [ -71.755021118999963, -43.771383971999896 ], [ -71.669599975999944, -43.959796243999889 ], [ -71.745259914013786, -44.044998116469912 ], [ -71.796413132560019, -44.000001315808049 ], [ -72.107660284594431, -43.954526056032648 ], [ -72.348188239395711, -43.733040866942474 ], [ -72.561663580709649, -43.777327569211934 ], [ -72.768317633551931, -43.725651136790532 ], [ -72.825445929785815, -43.636457614627204 ], [ -72.875727098227003, -43.695885511507129 ], [ -73.045887824999909, -43.728448174999926 ], [ -72.973011847999942, -43.621351820999905 ], [ -72.905832485999952, -43.607679945999905 ], [ -73.02603105399993, -43.586683851999908 ], [ -73.111317511999914, -43.461032809999949 ], [ -73.084584113999938, -43.316338799999926 ], [ -72.912180141999897, -43.235446872999944 ], [ -72.934437628999945, -43.098239841999941 ], [ -72.864857550999943, -43.018731377999927 ], [ -72.734486456999946, -43.079685153999947 ], [ -72.747141079999949, -42.909763278999947 ], [ -72.842193162999934, -42.838067315999922 ], [ -72.864857550999943, -42.75123463299991 ], [ -72.823841925999943, -42.66529713299991 ], [ -72.856800910999937, -42.55592213299991 ], [ -72.753570115999935, -42.49187590899993 ], [ -72.539418097999942, -42.55828215899993 ], [ -72.678456183999913, -42.478448174999926 ], [ -72.843739386999914, -42.278252862999921 ], [ -72.594553188999953, -42.182061455999929 ], [ -72.456166144999941, -42.440850518999923 ], [ -72.419789191999939, -42.439629815999922 ], [ -72.481312628999945, -42.288506768999923 ], [ -72.41234290299991, -42.237399997999944 ], [ -72.481312628999945, -42.199151299999926 ], [ -72.42601477799991, -42.147230726999908 ], [ -72.488026495999918, -42.127536716999941 ], [ -72.464344855999911, -41.976169528999947 ], [ -72.517201300999943, -41.950941664999903 ], [ -72.580555792999917, -42.031182549999926 ], [ -72.737294074999909, -42.013929945999905 ], [ -72.888579881999931, -41.910821221999925 ], [ -72.645130988999938, -41.722832940999922 ], [ -72.494943813999953, -41.716566664999903 ], [ -72.303089972999942, -41.648207289999903 ], [ -72.343413865999935, -41.61296965899993 ], [ -72.303089972999942, -41.380791924999926 ], [ -72.339222785999937, -41.371514580999929 ], [ -72.416086391999897, -41.658298434999949 ], [ -72.58429928299995, -41.709730726999908 ], [ -72.669667120999918, -41.682386976999908 ], [ -72.758859829999949, -41.543877862999921 ], [ -72.947377081999946, -41.483168226999908 ], [ -73.104115363999938, -41.576592705999929 ], [ -73.059193488999938, -41.697442315999922 ], [ -73.20140540299991, -41.784763278999947 ], [ -73.494862433999913, -41.80592213299991 ], [ -73.759946025999909, -41.748841348999917 ], [ -73.696631787999934, -41.637124513999936 ], [ -73.554758266999897, -41.608493747999944 ], [ -73.494862433999913, -41.510430596999925 ], [ -73.615223761999914, -41.599867445999905 ], [ -73.798166469999899, -41.56568775799991 ], [ -73.931684519999919, -41.094883543999913 ], [ -73.946904237999945, -40.972840597999948 ], [ -73.854640368999924, -40.916162739999947 ], [ -73.893229782999924, -40.863782443999924 ], [ -73.808885281999949, -40.70598594799992 ], [ -73.841495232999932, -40.666706764999901 ], [ -73.728497657999924, -40.544180162999908 ], [ -73.782826300999943, -40.424574476999908 ], [ -73.748646613999938, -40.273044528999947 ], [ -72.992877569644122, -40.353040459649492 ], [ -72.88626908974669, -40.522280775537354 ], [ -72.526652798088151, -40.672555840979271 ], [ -72.011438768384437, -40.65131682651031 ], [ -71.860596069999929, -40.559435322999988 ], [ -71.853102986999914, -40.616382751999964 ], [ -71.955577352999853, -40.72035573299992 ], [ -71.851449340999949, -40.938326924999942 ], [ -71.903952595999925, -41.367654723999891 ], [ -71.853258015999955, -41.567332458999942 ], [ -71.925915079999896, -41.653011983999917 ], [ -71.794036824999949, -41.86746917699989 ], [ -71.769259569273686, -41.999606621748171 ] ] ], [ [ [ -73.611480272999927, -42.936211846999925 ], [ -73.552805141999897, -42.918633721999925 ], [ -73.365101691999939, -42.990817966999941 ], [ -73.450062628999945, -42.993747653999947 ], [ -73.611480272999927, -42.936211846999925 ] ] ], [ [ [ -73.604725714999915, -42.579278252999927 ], [ -73.616769985999952, -42.638767184999949 ], [ -73.755034959999932, -42.598809502999927 ], [ -73.620961066999939, -42.56804778399993 ], [ -73.604725714999915, -42.579278252999927 ] ] ], [ [ [ -73.41234290299991, -42.525648695999905 ], [ -73.419422980999911, -42.564222914999903 ], [ -73.612660285999937, -42.451836846999925 ], [ -73.646311001999948, -42.373793226999908 ], [ -73.54320227799991, -42.379164320999905 ], [ -73.41234290299991, -42.525648695999905 ] ] ], [ [ [ -73.087635870999918, -42.247491143999923 ], [ -73.073231574999909, -42.288995049999926 ], [ -73.141590949999909, -42.31373463299991 ], [ -73.193918423999946, -42.249118747999944 ], [ -73.087635870999918, -42.247491143999923 ] ] ], [ [ [ -72.542713995999918, -42.141045830999929 ], [ -72.617787238999938, -42.103610934999949 ], [ -72.559722459999932, -42.051690362999921 ], [ -72.509266730999911, -42.073337497999944 ], [ -72.50804602799991, -42.138929945999905 ], [ -72.542713995999918, -42.141045830999929 ] ] ], [ [ [ -74.33462480399993, -43.281670830999929 ], [ -74.407215949999909, -43.237888278999947 ], [ -74.311714246999941, -43.137515868999913 ], [ -74.317849796999951, -43.072118534999902 ], [ -74.229519769999911, -43.022876985999915 ], [ -74.255649993999953, -42.990917052999919 ], [ -74.167362736999905, -42.882514078999918 ], [ -74.131390855999939, -42.692981927999938 ], [ -74.189617663999911, -42.431906016999903 ], [ -74.159503479999898, -42.241297913999915 ], [ -74.053335515999947, -42.130345173999956 ], [ -74.055287238999938, -41.94500090899993 ], [ -74.008778449999909, -41.887872002999927 ], [ -74.064035610999952, -41.80592213299991 ], [ -73.917062954999949, -41.782647393999923 ], [ -73.896107550999943, -41.842705987999921 ], [ -74.00617428299995, -41.845147393999923 ], [ -73.866037563999953, -41.89226653399993 ], [ -73.825835740999935, -41.856866143999923 ], [ -73.76984615799995, -41.901543877999927 ], [ -73.777414516999897, -41.858086846999925 ], [ -73.690988735999952, -41.809014580999929 ], [ -73.564930792999917, -41.804945570999905 ], [ -73.502308722999942, -41.846856377999927 ], [ -73.57843990799995, -41.945489190999922 ], [ -73.456450975999928, -42.044366143999923 ], [ -73.502308722999942, -42.116631768999923 ], [ -73.386219855999911, -42.195733330999929 ], [ -73.378773566999939, -42.278252862999921 ], [ -73.666167772999927, -42.354099216999941 ], [ -73.688547329999949, -42.452732028999947 ], [ -73.611480272999927, -42.511651299999926 ], [ -73.753732876999948, -42.533623955999929 ], [ -73.789662238999938, -42.504164320999905 ], [ -73.762318488999938, -42.457126559999949 ], [ -73.82445227799991, -42.514418226999908 ], [ -73.809152798999946, -42.60865650799991 ], [ -73.491932745999918, -42.818617445999905 ], [ -73.509510870999918, -42.877699476999908 ], [ -73.70767167899993, -42.867364190999922 ], [ -73.577381964999915, -42.965752862999921 ], [ -73.522775844999899, -43.052911065999922 ], [ -73.611740700999917, -43.049549053999954 ], [ -73.502308722999942, -43.128024997999944 ], [ -73.775746222999942, -43.118096612999921 ], [ -73.744984503999945, -43.226983330999929 ], [ -73.666047110999898, -43.294407384999943 ], [ -73.731543404999911, -43.316730932999917 ], [ -73.66901449799991, -43.363847189999944 ], [ -73.731109191999906, -43.392640296999957 ], [ -73.799976153999921, -43.359775889999923 ], [ -73.847490657999913, -43.423483242999907 ], [ -73.929529614999922, -43.364898904999905 ], [ -74.053378751999901, -43.362935892999928 ], [ -74.084948394999913, -43.401628082999935 ], [ -74.33462480399993, -43.281670830999929 ] ] ], [ [ [ -73.087635870999918, -41.84343840899993 ], [ -73.085804816999939, -41.747816664999903 ], [ -73.066883917999917, -41.736993096999925 ], [ -73.003000454999949, -41.844333591999941 ], [ -73.087635870999918, -41.84343840899993 ] ] ], [ [ [ -74.253361380999934, -43.350392082999917 ], [ -74.230726440999945, -43.413369569999929 ], [ -74.257307307999952, -43.427452099999925 ], [ -74.284026069999925, -43.417837554999949 ], [ -74.253361380999934, -43.350392082999917 ] ] ], [ [ [ -73.691091608999898, -43.188156497999955 ], [ -73.6564222209999, -43.196000224999921 ], [ -73.661238284999911, -43.24479598399995 ], [ -73.718523942999923, -43.215980905999913 ], [ -73.691091608999898, -43.188156497999955 ] ] ], [ [ [ -73.009191783999938, -42.695259426999939 ], [ -72.93044389399995, -42.723340169999915 ], [ -72.918815191999897, -42.786532358999921 ], [ -72.956524680999905, -42.807804137999938 ], [ -73.03361629099993, -42.713886268999943 ], [ -73.009191783999938, -42.695259426999939 ] ] ], [ [ [ -73.307340928999906, -42.627343397999937 ], [ -73.241038163999917, -42.631371442999921 ], [ -73.238950666999926, -42.65082611999992 ], [ -73.356926876999921, -42.629037360999916 ], [ -73.307340928999906, -42.627343397999937 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-AI", "NAME_1": "Aisén del General Carlos Ibáñez del Campo" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -71.745259914013786, -44.044998116469912 ], [ -71.858735717999934, -44.107797546999905 ], [ -71.804010376999969, -44.314813334999954 ], [ -71.860596069999929, -44.377135110999888 ], [ -71.209783080999898, -44.427571308999887 ], [ -71.122656616999933, -44.53030405699991 ], [ -71.234897826999941, -44.638824563999975 ], [ -71.238153442999931, -44.747861836999917 ], [ -71.297839721999935, -44.795610859999982 ], [ -71.497104044999872, -44.742900899999967 ], [ -72.088747518999924, -44.782795104999906 ], [ -72.073502970999897, -44.902167663999933 ], [ -71.588726358999878, -44.978132018999887 ], [ -71.317166706999899, -45.267209980999922 ], [ -71.389358683999916, -45.370769550999867 ], [ -71.508317830999914, -45.408389993999975 ], [ -71.48909419799989, -45.498513691999875 ], [ -71.765098022999894, -45.572410990999941 ], [ -71.801788289999962, -45.724029642999938 ], [ -71.758483438999889, -45.848156432999971 ], [ -71.665879272999945, -45.884019876999915 ], [ -71.612290812999873, -45.970526224999915 ], [ -71.770162312999872, -46.112636413999937 ], [ -71.91470129399994, -46.152323912999918 ], [ -71.763341023999914, -46.244514668999955 ], [ -71.680503702999914, -46.538140156999944 ], [ -71.687169962999917, -46.690068867999926 ], [ -71.950099649999856, -46.813988952999892 ], [ -71.970356811999864, -46.94845102999993 ], [ -71.914804646999869, -46.998473815999915 ], [ -72.005186726999938, -47.061932474999963 ], [ -71.874135294999917, -47.142547709999874 ], [ -71.880698201999905, -47.221922708999926 ], [ -72.030301473999941, -47.197531432999909 ], [ -72.038156290999979, -47.287035012999922 ], [ -72.17055131099994, -47.407544453999961 ], [ -72.361185669999941, -47.450952656999874 ], [ -72.320878051999898, -47.498391621999943 ], [ -72.344442505999893, -47.602261250999874 ], [ -72.543913533999898, -47.914800312999901 ], [ -72.343047241999926, -48.070449726999883 ], [ -72.302326212999873, -48.347538756999967 ], [ -72.576779743999936, -48.452131856999898 ], [ -72.614710245999845, -48.51000946099991 ], [ -72.592334350999863, -48.791129251999898 ], [ -72.781211710999884, -48.933859557999973 ], [ -73.009724894999863, -48.990393574999935 ], [ -73.171317097999889, -49.1893478389999 ], [ -73.171135422761552, -49.250740247664282 ], [ -74.089222785999937, -48.717217705999929 ], [ -74.330922003999945, -48.712985934999949 ], [ -74.289906378999945, -48.692478122999944 ], [ -74.364328579999949, -48.682305596999925 ], [ -74.399769660999937, -48.610528252999927 ], [ -74.327992316999939, -48.549004815999922 ], [ -74.197132941999939, -48.473321221999925 ], [ -73.993478969999899, -48.597263278999947 ], [ -74.028553839999915, -48.448011976999908 ], [ -73.892689581999946, -48.411309502999927 ], [ -74.237904425999943, -48.350762627999927 ], [ -74.107167120999918, -48.306084893999923 ], [ -74.270090298999946, -48.33562590899993 ], [ -74.317860480999911, -48.212090752999927 ], [ -74.442494269999941, -48.182386976999908 ], [ -74.512074347999942, -48.089939059999949 ], [ -74.468658006999931, -48.027764580999929 ], [ -74.626823284999944, -48.058903881999925 ], [ -74.625409323999918, -48.004227071999935 ], [ -74.537464972999942, -47.963067315999922 ], [ -74.415394660999937, -47.98365650799991 ], [ -74.334380662999934, -48.032159112999921 ], [ -74.276478644999941, -48.184502862999921 ], [ -74.205637173999946, -48.231052341999941 ], [ -74.171986456999946, -48.218601169999943 ], [ -74.330922003999945, -48.000420830999929 ], [ -73.891102667999917, -48.022230726999908 ], [ -73.879709438999953, -48.095961195999905 ], [ -73.76984615799995, -48.027764580999929 ], [ -73.804188605999911, -48.108086846999925 ], [ -73.748117641999897, -48.08171965899993 ], [ -73.601307745999918, -48.13014088299991 ], [ -73.604725714999915, -48.205824476999908 ], [ -73.556263800999943, -48.246840101999908 ], [ -73.486398891999897, -48.172539971999925 ], [ -73.351429816999939, -48.219496351999908 ], [ -73.276682094999899, -48.13836028399993 ], [ -73.290028449999909, -48.062432549999926 ], [ -73.294585740999935, -48.127048434999949 ], [ -73.400298631999931, -48.162041924999926 ], [ -73.642201300999943, -47.983575127999927 ], [ -73.642689581999946, -47.896579684999949 ], [ -73.507069464999915, -47.977959893999923 ], [ -73.227853969999899, -48.004082940999922 ], [ -73.481312628999945, -47.963067315999922 ], [ -73.516835089999915, -47.878513278999947 ], [ -73.619007941999939, -47.863864841999941 ], [ -73.550119594999899, -47.808038018999923 ], [ -73.731922980999911, -47.743096612999921 ], [ -73.666167772999927, -47.616306247999944 ], [ -73.701527472999942, -47.629815362999921 ], [ -73.673573370999918, -47.568454684999949 ], [ -73.721424933999913, -47.527439059999949 ], [ -73.775990363999938, -47.588962497999944 ], [ -73.730946417999917, -47.623711846999925 ], [ -73.772938605999911, -47.779473565999922 ], [ -73.923695441999939, -47.842705987999921 ], [ -74.023019985999952, -47.828545830999929 ], [ -74.067738410999937, -47.77076588299991 ], [ -74.350697394999941, -47.788506768999923 ], [ -74.407215949999909, -47.767673434999949 ], [ -74.338368292999917, -47.754001559999949 ], [ -74.378407355999911, -47.744805596999925 ], [ -74.548898891999897, -47.784763278999947 ], [ -74.735585089999915, -47.718682549999926 ], [ -74.656727667999917, -47.644138278999947 ], [ -74.567616339999915, -47.68092213299991 ], [ -74.632191535999937, -47.621270440999922 ], [ -74.556711391999897, -47.55006275799991 ], [ -74.520659959999932, -47.60320403399993 ], [ -74.437652147999927, -47.554782809999949 ], [ -74.344553188999953, -47.636651299999926 ], [ -74.481760219999899, -47.698825778999947 ], [ -74.344553188999953, -47.670830987999921 ], [ -74.295887824999909, -47.725355726999908 ], [ -74.205067511999914, -47.756605726999908 ], [ -74.159657355999911, -47.746514580999929 ], [ -74.26976477799991, -47.732598565999922 ], [ -74.303578253999945, -47.678317966999941 ], [ -74.132883266999897, -47.663995049999926 ], [ -74.253895636999914, -47.631280205999929 ], [ -74.043527798999946, -47.609470309999949 ], [ -74.140004035999937, -47.586195570999905 ], [ -74.057199673999946, -47.534274997999944 ], [ -74.314116990999935, -47.595798434999949 ], [ -74.344553188999953, -47.519952080999929 ], [ -74.392323370999918, -47.534763278999947 ], [ -74.453521287999934, -47.481052341999941 ], [ -74.394398566999939, -47.44654713299991 ], [ -74.465321417999917, -47.418145440999922 ], [ -74.506581183999913, -47.469659112999921 ], [ -74.528553839999915, -47.431735934999949 ], [ -74.324696417999917, -47.218926690999922 ], [ -74.283762173999946, -47.246270440999922 ], [ -74.177601691999939, -47.205254815999922 ], [ -74.112416144999941, -47.335544528999947 ], [ -74.115386522999927, -47.192966403999947 ], [ -74.016224738999938, -47.17742278399993 ], [ -73.973500128999945, -47.254978122999944 ], [ -73.989572719999899, -47.167413018999923 ], [ -74.057199673999946, -47.156914971999925 ], [ -73.941273566999939, -47.027927341999941 ], [ -74.153228318999936, -46.967217705999929 ], [ -74.208648240999935, -46.893975518999923 ], [ -74.126088019999941, -46.828545830999929 ], [ -74.243316209999932, -46.864678643999923 ], [ -74.289906378999945, -46.821709893999923 ], [ -74.266835089999915, -46.781670830999929 ], [ -74.591623501999948, -46.725518487999921 ], [ -74.477650519999941, -46.772393487999921 ], [ -74.640004035999937, -46.780043226999908 ], [ -74.673491990999935, -46.849053643999923 ], [ -74.434559699999909, -46.855889580999929 ], [ -74.47915605399993, -46.902276299999926 ], [ -74.680978969999899, -46.883884372999944 ], [ -74.815256313999953, -46.768487237999921 ], [ -74.856353318999936, -46.813897393999923 ], [ -75.00649980399993, -46.753513278999947 ], [ -75.083363410999937, -46.640883070999905 ], [ -74.94163977799991, -46.516778252999927 ], [ -74.934193488999938, -46.437595309999949 ], [ -75.201730923999946, -46.629978122999944 ], [ -75.207915818999936, -46.595147393999923 ], [ -75.342355923999946, -46.657321872999944 ], [ -75.414865688999953, -46.632745049999926 ], [ -75.575062628999945, -46.687920830999929 ], [ -75.661040818999936, -46.767185153999947 ], [ -75.631337042999917, -46.785414320999905 ], [ -75.540598110999952, -46.698174737999921 ], [ -75.422474738999938, -46.713962497999944 ], [ -75.476063605999911, -46.774021091999941 ], [ -75.386708136999914, -46.780043226999908 ], [ -75.43390865799995, -46.863376559999949 ], [ -75.346302863999938, -46.866794528999947 ], [ -75.410552537999934, -46.931573174999926 ], [ -75.551747199999909, -46.948337497999944 ], [ -75.650217251999948, -46.873223565999922 ], [ -75.707020636999914, -46.786553643999923 ], [ -75.704701300999943, -46.639255466999941 ], [ -75.636057094999899, -46.573011976999908 ], [ -75.517079230999911, -46.554294528999947 ], [ -75.540598110999952, -46.513278903999947 ], [ -75.373036261999914, -46.471612237999921 ], [ -75.401112433999913, -46.440524997999944 ], [ -75.345326300999943, -46.394789320999905 ], [ -75.270619269999941, -46.362399997999944 ], [ -75.222238735999952, -46.40398528399993 ], [ -75.196278449999909, -46.298272393999923 ], [ -75.10578365799995, -46.347100518999923 ], [ -75.029774542999917, -46.341973565999922 ], [ -75.138661261999914, -46.314060153999947 ], [ -75.090687628999945, -46.21607838299991 ], [ -74.92804928299995, -46.273614190999922 ], [ -74.958119269999941, -46.215264580999929 ], [ -74.87954667899993, -46.146742445999905 ], [ -74.777211066999939, -46.21217213299991 ], [ -74.756011522999927, -46.177992445999905 ], [ -74.821197068999936, -46.112237237999921 ], [ -74.77375240799995, -46.04029713299991 ], [ -74.70148678299995, -46.03289153399993 ], [ -74.737863735999952, -46.02312590899993 ], [ -74.72874915299991, -45.944024346999925 ], [ -74.665598110999952, -45.823337497999944 ], [ -74.559966600999928, -45.826267184999949 ], [ -74.558094855999911, -45.903090101999908 ], [ -74.458159959999932, -45.933851820999905 ], [ -74.45335852799991, -46.016371351999908 ], [ -74.399769660999937, -45.930433851999908 ], [ -74.461822068999936, -45.815036716999941 ], [ -74.35960852799991, -45.79029713299991 ], [ -74.321278449999909, -45.83171965899993 ], [ -74.170277472999942, -45.791761976999908 ], [ -74.103138800999943, -45.836846612999921 ], [ -74.192779100999928, -45.881931247999944 ], [ -74.059193488999938, -45.929864190999922 ], [ -74.080067511999914, -45.981866143999923 ], [ -74.167062954999949, -46.00554778399993 ], [ -74.083851691999939, -46.029717705999929 ], [ -74.167062954999949, -46.13640715899993 ], [ -74.076283331999946, -46.096123955999929 ], [ -74.061350063999953, -45.980889580999929 ], [ -73.970570441999939, -46.084161065999922 ], [ -74.063588019999941, -46.172051690999922 ], [ -74.313221808999913, -46.249932549999926 ], [ -74.489898240999935, -46.189385674999926 ], [ -74.342152472999942, -46.260837497999944 ], [ -74.049712693999936, -46.19109465899993 ], [ -74.077707485999952, -46.322035414999903 ], [ -74.026437954999949, -46.286716403999947 ], [ -73.844878709999932, -46.341973565999922 ], [ -74.019276495999918, -46.20435963299991 ], [ -73.968169725999928, -46.144707940999922 ], [ -73.881825324999909, -46.141778252999927 ], [ -73.76984615799995, -46.234551690999922 ], [ -73.773060675999943, -46.320896091999941 ], [ -73.989165818999936, -46.559747002999927 ], [ -73.873890753999945, -46.602227471999925 ], [ -73.78734290299991, -46.497165622999944 ], [ -73.741851365999935, -46.533786716999941 ], [ -73.742339647999927, -46.420993747999944 ], [ -73.601307745999918, -46.318454684999949 ], [ -73.488636847999942, -46.300957940999922 ], [ -73.568348761999914, -46.270440362999921 ], [ -73.523915167999917, -46.175225518999923 ], [ -73.344593878999945, -46.026543877999927 ], [ -73.430287238999938, -46.029717705999929 ], [ -73.687855597999942, -46.322035414999903 ], [ -73.619007941999939, -46.102308851999908 ], [ -73.660552537999934, -45.975681247999944 ], [ -73.522775844999899, -45.875746351999908 ], [ -73.560210740999935, -45.82976653399993 ], [ -73.402088995999918, -45.701918226999908 ], [ -73.18578040299991, -45.662530205999929 ], [ -73.327259894999941, -45.619073174999926 ], [ -73.591664191999939, -45.780205987999921 ], [ -73.510853644999941, -45.451755466999941 ], [ -73.445871548999946, -45.413506768999923 ], [ -73.406076626999948, -45.451267184999949 ], [ -73.392445441999939, -45.375583591999941 ], [ -73.323557094999899, -45.395928643999923 ], [ -73.327707485999952, -45.340915622999944 ], [ -73.226429816999939, -45.300876559999949 ], [ -73.01431230399993, -45.444756768999923 ], [ -72.859527147999927, -45.464450778999947 ], [ -72.830637173999946, -45.418064059999949 ], [ -72.981516079999949, -45.400974216999941 ], [ -73.256662563999953, -45.248223565999922 ], [ -73.448068813999953, -45.279473565999922 ], [ -73.450062628999945, -45.199476820999905 ], [ -73.304432745999918, -45.144789320999905 ], [ -73.397775844999899, -44.988213799999926 ], [ -73.117095506999931, -44.948337497999944 ], [ -72.727650519999941, -44.758558851999908 ], [ -72.679839647999927, -44.543552341999941 ], [ -72.59797115799995, -44.505303643999923 ], [ -72.591135219999899, -44.340752862999921 ], [ -72.721913214999915, -44.501397393999923 ], [ -72.75023352799991, -44.448988539999903 ], [ -72.924631313999953, -44.373711846999925 ], [ -72.939930792999917, -44.306735934999949 ], [ -73.183501756999931, -44.248142184999949 ], [ -73.128081834999932, -44.14576588299991 ], [ -73.197661912999934, -44.195489190999922 ], [ -73.283599412999934, -44.174086195999905 ], [ -73.286936001999948, -44.123467705999929 ], [ -73.223011847999942, -44.127048434999949 ], [ -73.215402798999946, -44.067966403999947 ], [ -73.116118943999936, -44.085707289999903 ], [ -73.139149542999917, -43.985121351999908 ], [ -73.012684699999909, -43.772149346999925 ], [ -72.967274542999917, -43.820082289999903 ], [ -72.898915167999917, -43.776950778999947 ], [ -72.824615037999934, -43.80787525799991 ], [ -72.847157355999911, -43.679457289999903 ], [ -72.885894334999932, -43.751153252999927 ], [ -73.042328591890964, -43.729587928939793 ], [ -72.875727098227003, -43.695885511507129 ], [ -72.825445929785815, -43.636457614627204 ], [ -72.768317633551931, -43.725651136790532 ], [ -72.561663580709649, -43.777327569211934 ], [ -72.348188239395711, -43.733040866942474 ], [ -72.129519415788423, -43.946257826737337 ], [ -71.796413132560019, -44.000001315808049 ], [ -71.745259914013786, -44.044998116469912 ] ] ], [ [ [ -75.338937954999949, -48.624200127999927 ], [ -75.296986456999946, -48.727146091999941 ], [ -75.384185350999928, -48.696465752999927 ], [ -75.493234829999949, -48.775567315999922 ], [ -75.647857225999928, -48.778903903999947 ], [ -75.641835089999915, -48.701348565999922 ], [ -75.507557745999918, -48.717543226999908 ], [ -75.338937954999949, -48.624200127999927 ] ] ], [ [ [ -75.32835852799991, -48.552178643999923 ], [ -75.339914516999897, -48.614841403999947 ], [ -75.54165605399993, -48.70086028399993 ], [ -75.606556769999941, -48.661065362999921 ], [ -75.499379035999937, -48.660088799999926 ], [ -75.440663214999915, -48.610528252999927 ], [ -75.598947719999899, -48.637302341999941 ], [ -75.675363735999952, -48.583184502999927 ], [ -75.606434699999909, -48.439222914999903 ], [ -75.547718878999945, -48.472914320999905 ], [ -75.344349738999938, -48.42742278399993 ], [ -75.366200324999909, -48.541680596999925 ], [ -75.32835852799991, -48.552178643999923 ] ] ], [ [ [ -74.472075975999928, -48.455987237999921 ], [ -74.510243292999917, -48.408298434999949 ], [ -74.303130662999934, -48.479913018999923 ], [ -74.429025844999899, -48.525811455999929 ], [ -74.472075975999928, -48.455987237999921 ] ] ], [ [ [ -74.090687628999945, -48.479587497999944 ], [ -74.179066535999937, -48.443129164999903 ], [ -74.250803188999953, -48.378024997999944 ], [ -74.057199673999946, -48.425551039999903 ], [ -74.090687628999945, -48.479587497999944 ] ] ], [ [ [ -74.495432094999899, -48.349867445999905 ], [ -74.358794725999928, -48.370293877999927 ], [ -74.393177863999938, -48.313164971999925 ], [ -74.314116990999935, -48.28093840899993 ], [ -74.22329667899993, -48.444919528999947 ], [ -74.27171790299991, -48.462660414999903 ], [ -74.495432094999899, -48.349867445999905 ] ] ], [ [ [ -74.499134894999941, -48.583184502999927 ], [ -74.514068162999934, -48.666110934999949 ], [ -74.607329881999931, -48.693942966999941 ], [ -74.750599738999938, -48.629489841999941 ], [ -74.996245897999927, -48.603692315999922 ], [ -75.033070441999939, -48.504489841999941 ], [ -74.84593665299991, -48.390232028999947 ], [ -74.78156490799995, -48.485039971999925 ], [ -74.717152472999942, -48.453545830999929 ], [ -74.813588019999941, -48.342543226999908 ], [ -74.737660285999937, -48.125746351999908 ], [ -74.680043097999942, -48.303399346999925 ], [ -74.584787563999953, -48.376560153999947 ], [ -74.673491990999935, -48.418145440999922 ], [ -74.605213995999918, -48.459161065999922 ], [ -74.599436001999948, -48.563653252999927 ], [ -74.530629035999937, -48.621758721999925 ], [ -74.499134894999941, -48.583184502999927 ] ] ], [ [ [ -74.543812628999945, -48.32195403399993 ], [ -74.521880662999934, -48.194512627999927 ], [ -74.60374915299991, -48.235446872999944 ], [ -74.605213995999918, -48.157403252999927 ], [ -74.558176235999952, -48.12232838299991 ], [ -74.372629360999952, -48.25318775799991 ], [ -74.543812628999945, -48.32195403399993 ] ] ], [ [ [ -75.160755988999938, -48.298435153999947 ], [ -75.11978105399993, -48.26100025799991 ], [ -75.207915818999936, -48.212090752999927 ], [ -75.256337042999917, -48.068617445999905 ], [ -75.017504644999917, -48.083020135999902 ], [ -74.804514126999948, -48.174493096999925 ], [ -74.841297980999911, -48.359307549999926 ], [ -75.031117316999939, -48.443780205999929 ], [ -75.160755988999938, -48.298435153999947 ] ] ], [ [ [ -75.149891730999911, -48.658379815999922 ], [ -75.224476691999939, -48.706475518999923 ], [ -75.229644334999932, -48.637302341999941 ], [ -75.282826300999943, -48.63054778399993 ], [ -75.320668097999942, -48.492445570999905 ], [ -75.270619269999941, -48.418145440999922 ], [ -75.325266079999949, -48.39421965899993 ], [ -75.317941860999952, -48.34889088299991 ], [ -75.48656165299991, -48.423028252999927 ], [ -75.554188605999911, -48.397149346999925 ], [ -75.345773891999897, -48.301446221999925 ], [ -75.407134568999936, -48.31568775799991 ], [ -75.394154425999943, -48.274102471999925 ], [ -75.543771938999953, -48.32195403399993 ], [ -75.43390865799995, -48.198988539999903 ], [ -75.540109829999949, -48.22625090899993 ], [ -75.585316535999937, -48.085707289999903 ], [ -75.551136847999942, -48.055759372999944 ], [ -75.338937954999949, -48.017510674999926 ], [ -75.268910285999937, -48.165948174999926 ], [ -75.289947068999936, -48.215508721999925 ], [ -75.164784308999913, -48.369561455999929 ], [ -75.187408006999931, -48.411309502999927 ], [ -75.098703579999949, -48.465915622999944 ], [ -75.149891730999911, -48.483005466999941 ], [ -75.083404100999928, -48.507745049999926 ], [ -75.071400519999941, -48.596286716999941 ], [ -75.149891730999911, -48.658379815999922 ] ] ], [ [ [ -75.270619269999941, -48.027764580999929 ], [ -75.16777265099995, -47.893604282999945 ], [ -74.94292566799993, -47.883665608999934 ], [ -74.872792120999918, -47.815524997999944 ], [ -74.78832381299992, -47.812324270999909 ], [ -74.765736867999919, -47.884211562999951 ], [ -74.812981955999931, -47.938897175999955 ], [ -74.777181868999946, -47.970611898999948 ], [ -74.834868943999936, -48.007907809999949 ], [ -74.764418836999937, -48.021441390999939 ], [ -74.727379237999912, -48.105891838999923 ], [ -75.012847459999932, -48.041436455999929 ], [ -75.052357550999943, -47.986260674999926 ], [ -75.270619269999941, -48.027764580999929 ] ] ], [ [ [ -74.413726365999935, -47.938246351999908 ], [ -74.502837693999936, -47.917901299999926 ], [ -74.364247199999909, -47.830824476999908 ], [ -74.248931443999936, -47.876885674999926 ], [ -74.330922003999945, -47.822198174999926 ], [ -74.289906378999945, -47.807386976999908 ], [ -73.80890865799995, -47.887383721999925 ], [ -73.831206834999932, -47.952569268999923 ], [ -73.923003709999932, -47.963636976999908 ], [ -73.924875454999949, -47.915948174999926 ], [ -74.318470831999946, -47.981215101999908 ], [ -74.413726365999935, -47.938246351999908 ] ] ], [ [ [ -75.182362433999913, -47.831475518999923 ], [ -75.342546400999936, -47.782862441999953 ], [ -75.355913455999939, -47.736140027999909 ], [ -75.091637528999911, -47.680492216999937 ], [ -75.059369179999919, -47.749886964999916 ], [ -75.123199022999927, -47.781914971999925 ], [ -75.023682360999942, -47.803325029999939 ], [ -75.227313789999926, -47.854714287999911 ], [ -75.182362433999913, -47.831475518999923 ] ] ], [ [ [ -74.885228798999947, -47.712063181999952 ], [ -74.868040452999935, -47.763242241999933 ], [ -74.957722775999912, -47.774795059999917 ], [ -75.054421420999915, -47.689572060999922 ], [ -75.000383613999929, -47.662200149999933 ], [ -74.885228798999947, -47.712063181999952 ] ] ], [ [ [ -74.468658006999931, -47.074965101999908 ], [ -74.356678839999915, -47.045017184999949 ], [ -74.315785285999937, -47.078057549999926 ], [ -74.454701300999943, -47.167738539999903 ], [ -74.468658006999931, -47.074965101999908 ] ] ], [ [ [ -74.074574347999942, -47.020277601999908 ], [ -73.97524980399993, -47.047621351999908 ], [ -74.145904100999928, -47.17115650799991 ], [ -74.226470506999931, -47.122002862999921 ], [ -74.177357550999943, -47.016534112999921 ], [ -74.111195441999939, -47.053887627999927 ], [ -74.074574347999942, -47.020277601999908 ] ] ], [ [ [ -73.725087042999917, -46.05046965899993 ], [ -73.684071417999917, -46.105401299999926 ], [ -73.775461391999897, -46.199476820999905 ], [ -73.940500454999949, -46.068129164999903 ], [ -73.896473761999914, -46.011488539999903 ], [ -73.725087042999917, -46.05046965899993 ] ] ], [ [ [ -73.70767167899993, -45.923597914999903 ], [ -73.683176235999952, -46.017673434999949 ], [ -73.819488084999932, -45.998711846999925 ], [ -73.77212480399993, -45.898695570999905 ], [ -73.70767167899993, -45.923597914999903 ] ] ], [ [ [ -74.752919074999909, -45.807549737999921 ], [ -74.71507727799991, -45.848402601999908 ], [ -74.780751105999911, -46.011488539999903 ], [ -74.919667120999918, -46.104180596999925 ], [ -75.074330206999946, -46.093845309999949 ], [ -75.084380662999934, -46.026788018999923 ], [ -74.890451626999948, -46.016208591999941 ], [ -74.859120245999918, -45.998711846999925 ], [ -75.07876542899993, -45.985039971999925 ], [ -75.029774542999917, -45.96453215899993 ], [ -75.088734503999945, -45.950290622999944 ], [ -75.108265753999945, -45.874200127999927 ], [ -74.883534308999913, -45.92937590899993 ], [ -74.970529751999948, -45.862888278999947 ], [ -74.889393683999913, -45.881931247999944 ], [ -74.831857876999948, -45.807549737999921 ], [ -74.752919074999909, -45.807549737999921 ] ] ], [ [ [ -73.741851365999935, -45.793877862999921 ], [ -73.694081183999913, -45.888848565999922 ], [ -73.789662238999938, -45.875746351999908 ], [ -73.856556769999941, -45.967543226999908 ], [ -73.934315558999913, -45.97193775799991 ], [ -73.911447719999899, -45.875258070999905 ], [ -73.741851365999935, -45.793877862999921 ] ] ], [ [ [ -73.926828579999949, -45.74537525799991 ], [ -73.97524980399993, -45.780205987999921 ], [ -74.015614386999914, -45.913995049999926 ], [ -74.094593878999945, -45.763929945999905 ], [ -73.926828579999949, -45.74537525799991 ] ] ], [ [ [ -74.790842251999948, -45.63250090899993 ], [ -74.752430792999917, -45.699639580999929 ], [ -74.879261847999942, -45.624607028999947 ], [ -74.839100714999915, -45.601820570999905 ], [ -74.790842251999948, -45.63250090899993 ] ] ], [ [ [ -74.554351365999935, -45.574802341999941 ], [ -74.583892381999931, -45.735284112999921 ], [ -74.685699022999927, -45.743340752999927 ], [ -74.679676886999914, -45.620700778999947 ], [ -74.554351365999935, -45.574802341999941 ] ] ], [ [ [ -74.071441209999932, -45.690850518999923 ], [ -74.114654100999928, -45.599704684999949 ], [ -74.050445115999935, -45.54461028399993 ], [ -73.910227016999897, -45.590997002999927 ], [ -73.920643683999913, -45.697686455999929 ], [ -74.071441209999932, -45.690850518999923 ] ] ], [ [ [ -74.502837693999936, -45.732354424999926 ], [ -74.421254035999937, -45.454278252999927 ], [ -74.273548956999946, -45.495293877999927 ], [ -74.276966925999943, -45.567315362999921 ], [ -74.221669074999909, -45.601495049999926 ], [ -74.289906378999945, -45.622491143999923 ], [ -74.207997199999909, -45.635511976999908 ], [ -74.241810675999943, -45.675957940999922 ], [ -74.358794725999928, -45.697686455999929 ], [ -74.330922003999945, -45.724867445999905 ], [ -74.43968665299991, -45.776950778999947 ], [ -74.502837693999936, -45.732354424999926 ] ] ], [ [ [ -73.666167772999927, -45.436944268999923 ], [ -73.58421790299991, -45.512627862999921 ], [ -73.611480272999927, -45.629327080999929 ], [ -73.680409308999913, -45.622491143999923 ], [ -73.611480272999927, -45.690850518999923 ], [ -73.680409308999913, -45.752862237999921 ], [ -73.818267381999931, -45.642510674999926 ], [ -73.741851365999935, -45.608982028999947 ], [ -73.786203579999949, -45.569919528999947 ], [ -73.770904100999928, -45.511976820999905 ], [ -73.666167772999927, -45.436944268999923 ] ] ], [ [ [ -73.885894334999932, -45.471123955999929 ], [ -73.816965298999946, -45.474786065999922 ], [ -73.870472785999937, -45.561700127999927 ], [ -74.029652472999942, -45.517347914999903 ], [ -74.142648891999897, -45.574965101999908 ], [ -74.064035610999952, -45.423272393999923 ], [ -73.885894334999932, -45.471123955999929 ] ] ], [ [ [ -74.554351365999935, -45.546807549999926 ], [ -74.51976477799991, -45.444105726999908 ], [ -74.445668097999942, -45.428155205999929 ], [ -74.501332160999937, -45.588067315999922 ], [ -74.554351365999935, -45.546807549999926 ] ] ], [ [ [ -73.82445227799991, -45.395928643999923 ], [ -73.921742316999939, -45.430433851999908 ], [ -74.023019985999952, -45.392673434999949 ], [ -73.941029425999943, -45.366306247999944 ], [ -73.82445227799991, -45.395928643999923 ] ] ], [ [ [ -74.341420050999943, -45.337660414999903 ], [ -74.310414191999939, -45.389255466999941 ], [ -74.378041144999941, -45.400974216999941 ], [ -74.525786912999934, -45.295017184999949 ], [ -74.389271613999938, -45.281670830999929 ], [ -74.341420050999943, -45.337660414999903 ] ] ], [ [ [ -73.82445227799991, -45.266289971999925 ], [ -73.786244269999941, -45.333916924999926 ], [ -74.012277798999946, -45.353610934999949 ], [ -74.129505988999938, -45.323988539999903 ], [ -74.167062954999949, -45.252618096999925 ], [ -74.070383266999897, -45.204278252999927 ], [ -73.986073370999918, -45.27076588299991 ], [ -73.82445227799991, -45.266289971999925 ] ] ], [ [ [ -74.273548956999946, -45.207940362999921 ], [ -74.325347459999932, -45.302341403999947 ], [ -74.420277472999942, -45.23211028399993 ], [ -74.387562628999945, -45.155205987999921 ], [ -74.273548956999946, -45.207940362999921 ] ] ], [ [ [ -73.731922980999911, -45.214776299999926 ], [ -73.767974412999934, -45.284600518999923 ], [ -73.842844204999949, -45.239678643999923 ], [ -73.989572719999899, -45.24578215899993 ], [ -74.084095831999946, -45.140069268999923 ], [ -74.205474412999934, -45.169366143999923 ], [ -74.250111456999946, -45.109633070999905 ], [ -74.173898891999897, -45.026055596999925 ], [ -73.866078253999945, -44.994561455999929 ], [ -73.714588995999918, -45.114190362999921 ], [ -73.731922980999911, -45.214776299999926 ] ] ], [ [ [ -74.270090298999946, -44.944105726999908 ], [ -74.163726365999935, -44.864678643999923 ], [ -73.913197394999941, -44.950372002999927 ], [ -74.356922980999911, -45.011488539999903 ], [ -74.270090298999946, -44.944105726999908 ] ] ], [ [ [ -73.96157792899993, -44.810153903999947 ], [ -74.071441209999932, -44.854180596999925 ], [ -74.187489386999914, -44.80632903399993 ], [ -73.995716925999943, -44.772149346999925 ], [ -73.96157792899993, -44.810153903999947 ] ] ], [ [ [ -73.930531378999945, -44.789239190999922 ], [ -73.854481574999909, -44.768731377999927 ], [ -73.762318488999938, -44.929864190999922 ], [ -73.813710089999915, -44.960870049999926 ], [ -73.883208787999934, -44.928155205999929 ], [ -73.926747199999909, -44.854424737999921 ], [ -73.857899542999917, -44.895684502999927 ], [ -73.930531378999945, -44.789239190999922 ] ] ], [ [ [ -75.091473254999926, -44.796056055999941 ], [ -75.021734398999911, -44.843664722999904 ], [ -75.031272062999903, -44.903969270999937 ], [ -75.152357944999949, -44.921213887999954 ], [ -75.198322394999934, -44.807232422999903 ], [ -75.147181885999942, -44.763766525999927 ], [ -75.091473254999926, -44.796056055999941 ] ] ], [ [ [ -73.604725714999915, -44.744886976999908 ], [ -73.627308722999942, -44.82976653399993 ], [ -73.749256964999915, -44.802829684999949 ], [ -73.741688605999911, -44.754652601999908 ], [ -73.604725714999915, -44.744886976999908 ] ] ], [ [ [ -74.341420050999943, -44.80632903399993 ], [ -74.312367316999939, -44.841403903999947 ], [ -74.393544074999909, -44.857028903999947 ], [ -74.527740037999934, -44.743259372999944 ], [ -74.427113410999937, -44.718194268999923 ], [ -74.341420050999943, -44.80632903399993 ] ] ], [ [ [ -74.482329881999931, -44.636325778999947 ], [ -74.46898352799991, -44.697198174999926 ], [ -74.669504360999952, -44.670179945999905 ], [ -74.622670050999943, -44.622002862999921 ], [ -74.482329881999931, -44.636325778999947 ] ] ], [ [ [ -73.926828579999949, -44.628838799999926 ], [ -73.875884568999936, -44.694024346999925 ], [ -74.258697068999936, -44.804457289999903 ], [ -74.368763800999943, -44.747491143999923 ], [ -74.317860480999911, -44.704522393999923 ], [ -74.413807745999918, -44.685967705999929 ], [ -74.400542772999927, -44.626071872999944 ], [ -74.267160610999952, -44.603122653999947 ], [ -73.926828579999949, -44.628838799999926 ] ] ], [ [ [ -74.777211066999939, -44.581149997999944 ], [ -74.732533331999946, -44.593194268999923 ], [ -74.747792120999918, -44.665622653999947 ], [ -74.803863084999932, -44.673760674999926 ], [ -74.824940558999913, -44.581149997999944 ], [ -74.798247850999928, -44.548760674999926 ], [ -74.777211066999939, -44.581149997999944 ] ] ], [ [ [ -73.659982876999948, -44.676527601999908 ], [ -73.591542120999918, -44.70671965899993 ], [ -73.752512173999946, -44.741387627999927 ], [ -73.844309048999946, -44.652520440999922 ], [ -73.821400519999941, -44.578708591999941 ], [ -73.67992102799991, -44.544854424999926 ], [ -73.625152147999927, -44.622002862999921 ], [ -73.659982876999948, -44.676527601999908 ] ] ], [ [ [ -74.193714972999942, -44.492282809999949 ], [ -74.132883266999897, -44.546970309999949 ], [ -74.326324022999927, -44.579685153999947 ], [ -74.368885870999918, -44.541110934999949 ], [ -74.193714972999942, -44.492282809999949 ] ] ], [ [ [ -74.036040818999936, -44.498467705999929 ], [ -74.143666144999941, -44.458103122999944 ], [ -74.167062954999949, -44.430271091999941 ], [ -73.971547003999945, -44.471286716999941 ], [ -73.947336391999897, -44.543552341999941 ], [ -74.132883266999897, -44.518975518999923 ], [ -74.036040818999936, -44.498467705999929 ] ] ], [ [ [ -74.392974412999934, -44.546970309999949 ], [ -74.523304816999939, -44.526462497999944 ], [ -74.541127081999946, -44.453789971999925 ], [ -74.420277472999942, -44.471286716999941 ], [ -74.348255988999938, -44.402276299999926 ], [ -74.259510870999918, -44.412855726999908 ], [ -74.223052537999934, -44.467380466999941 ], [ -74.420277472999942, -44.505303643999923 ], [ -74.392974412999934, -44.546970309999949 ] ] ], [ [ [ -73.789662238999938, -44.422784112999921 ], [ -73.867014126999948, -44.46607838299991 ], [ -73.910959438999953, -44.396742445999905 ], [ -73.887684699999909, -44.369235934999949 ], [ -73.789662238999938, -44.422784112999921 ] ] ], [ [ [ -73.382476365999935, -44.587823174999926 ], [ -73.241200324999909, -44.639336846999925 ], [ -73.280506964999915, -44.541761976999908 ], [ -73.131581183999913, -44.545179945999905 ], [ -73.241566535999937, -44.512139580999929 ], [ -73.246245897999927, -44.43718840899993 ], [ -73.167103644999941, -44.409112237999921 ], [ -73.036203579999949, -44.484795830999929 ], [ -73.090809699999909, -44.402276299999926 ], [ -73.002023891999897, -44.361260674999926 ], [ -72.926258917999917, -44.437107028999947 ], [ -72.980946417999917, -44.512139580999929 ], [ -72.872303839999915, -44.437107028999947 ], [ -72.721180792999917, -44.528008721999925 ], [ -72.813343878999945, -44.636325778999947 ], [ -72.980946417999917, -44.601495049999926 ], [ -72.831288214999915, -44.676527601999908 ], [ -72.837635870999918, -44.710137627999927 ], [ -73.256988084999932, -44.940036716999941 ], [ -73.407582160999937, -44.822442315999922 ], [ -73.207427537999934, -44.80006275799991 ], [ -73.299631313999953, -44.758558851999908 ], [ -73.393422003999945, -44.788669528999947 ], [ -73.468129035999937, -44.642510674999926 ], [ -73.382476365999935, -44.587823174999926 ] ] ], [ [ [ -73.726470506999931, -44.42506275799991 ], [ -73.789662238999938, -44.382419528999947 ], [ -73.654123501999948, -44.35084400799991 ], [ -73.72883053299995, -44.388604424999926 ], [ -73.678700324999909, -44.434502862999921 ], [ -73.726470506999931, -44.42506275799991 ] ] ], [ [ [ -74.029896613999938, -44.354587497999944 ], [ -73.926828579999949, -44.354587497999944 ], [ -73.940500454999949, -44.450616143999923 ], [ -74.112416144999941, -44.327243747999944 ], [ -74.029896613999938, -44.354587497999944 ] ] ], [ [ [ -73.262806769999941, -44.388441664999903 ], [ -73.302723761999914, -44.349704684999949 ], [ -73.249012824999909, -44.306735934999949 ], [ -73.177154100999928, -44.367771091999941 ], [ -73.262806769999941, -44.388441664999903 ] ] ], [ [ [ -73.865386522999927, -44.334079684999949 ], [ -73.932484503999945, -44.328545830999929 ], [ -73.97524980399993, -44.289646091999941 ], [ -73.805653449999909, -44.266371351999908 ], [ -73.789051886999914, -44.309502862999921 ], [ -73.865386522999927, -44.334079684999949 ] ] ], [ [ [ -74.386626756999931, -44.249932549999926 ], [ -74.303578253999945, -44.258233330999929 ], [ -74.290028449999909, -44.297295830999929 ], [ -74.409901495999918, -44.28443775799991 ], [ -74.386626756999931, -44.249932549999926 ] ] ], [ [ [ -73.741851365999935, -44.265069268999923 ], [ -73.675689256999931, -44.241306247999944 ], [ -73.666167772999927, -44.265069268999923 ], [ -73.722035285999937, -44.302829684999949 ], [ -73.741851365999935, -44.265069268999923 ] ] ], [ [ [ -74.108713344999899, -44.227471612999921 ], [ -74.110503709999932, -44.18914153399993 ], [ -74.049712693999936, -44.196872653999947 ], [ -74.064320441999939, -44.149021091999941 ], [ -73.893625454999949, -44.239353122999944 ], [ -74.009348110999952, -44.257256768999923 ], [ -74.017933722999942, -44.327732028999947 ], [ -74.108713344999899, -44.227471612999921 ] ] ], [ [ [ -74.276966925999943, -44.149021091999941 ], [ -74.258168097999942, -44.17310963299991 ], [ -74.337391730999911, -44.189873955999929 ], [ -74.385568813999953, -44.159600518999923 ], [ -74.276966925999943, -44.149021091999941 ] ] ], [ [ [ -73.882801886999914, -44.118340752999927 ], [ -73.846262173999946, -44.190199476999908 ], [ -74.016224738999938, -44.142836195999905 ], [ -73.952707485999952, -44.10475025799991 ], [ -73.882801886999914, -44.118340752999927 ] ] ], [ [ [ -74.297352667999917, -44.011895440999922 ], [ -74.277414516999897, -44.011895440999922 ], [ -74.207997199999909, -44.019301039999903 ], [ -74.298329230999911, -44.031914971999925 ], [ -74.297352667999917, -44.011895440999922 ] ] ], [ [ [ -73.744984503999945, -43.953545830999929 ], [ -73.638824022999927, -44.005059502999927 ], [ -73.633412238999938, -44.123793226999908 ], [ -73.72883053299995, -44.04656340899993 ], [ -73.744984503999945, -43.953545830999929 ] ] ], [ [ [ -73.227935350999928, -44.011895440999922 ], [ -73.284169074999909, -43.935723565999922 ], [ -73.159657355999911, -43.881524346999925 ], [ -73.151600714999915, -44.015801690999922 ], [ -73.227935350999928, -44.011895440999922 ] ] ], [ [ [ -74.143937792999907, -43.82755091699994 ], [ -74.045244664999927, -43.796093797999902 ], [ -73.967349755999919, -43.82883363499991 ], [ -73.865101691999939, -43.762627862999921 ], [ -73.762318488999938, -43.888929945999905 ], [ -73.872181769999941, -43.888929945999905 ], [ -73.913197394999941, -43.867852471999925 ], [ -73.865386522999927, -43.84734465899993 ], [ -73.928456183999913, -43.840752862999921 ], [ -73.97524980399993, -43.867852471999925 ], [ -73.906361456999946, -43.90943775799991 ], [ -73.995716925999943, -43.936700127999927 ], [ -74.165394660999937, -43.875095309999949 ], [ -74.143937792999907, -43.82755091699994 ] ] ], [ [ [ -74.818186001999948, -43.635023695999905 ], [ -74.825025557999936, -43.562412198999937 ], [ -74.744900592999898, -43.565905912999938 ], [ -74.737900484999898, -43.530177431999903 ], [ -74.557486089999941, -43.627409746999945 ], [ -74.758454711999946, -43.676949150999917 ], [ -74.818186001999948, -43.635023695999905 ] ] ], [ [ [ -74.649865233999947, -47.797742236999909 ], [ -74.526180506999935, -47.812868098999957 ], [ -74.524671364999904, -47.868351277999921 ], [ -74.593972314999917, -47.864388601999906 ], [ -74.644015791999948, -47.923110272999907 ], [ -74.689230284999951, -47.834117121999952 ], [ -74.649865233999947, -47.797742236999909 ] ] ], [ [ [ -75.323146851999923, -46.685089311999945 ], [ -75.17399230399991, -46.677963655999918 ], [ -75.132213585999921, -46.777994805999924 ], [ -75.342251861999898, -46.701736590999928 ], [ -75.323146851999923, -46.685089311999945 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CL-MA", "NAME_1": "Magallanes y Antártica Chilena" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -73.170447858999893, -49.250870019999937 ], [ -73.098246622999909, -49.272753600999955 ], [ -73.457862914999936, -49.307686868999944 ], [ -73.466725423999947, -49.387578632999954 ], [ -73.54044185499987, -49.427782897999883 ], [ -73.586588907999896, -49.529998880999948 ], [ -73.521114868999916, -49.608960469999907 ], [ -73.539511678999901, -49.692676288999863 ], [ -73.465097615999895, -49.759959004999935 ], [ -73.57273962499994, -49.932351582999971 ], [ -73.478585164999856, -50.009452819999922 ], [ -73.530571655999978, -50.140814310999914 ], [ -73.301438354999931, -50.299564310999948 ], [ -73.257616740999907, -50.573035990999948 ], [ -73.139484415999931, -50.770233255999933 ], [ -72.77842118399991, -50.619648131999917 ], [ -72.662614298999955, -50.667810566999904 ], [ -72.505983032999893, -50.601251321999918 ], [ -72.302842977999916, -50.648896993999962 ], [ -72.347388061999908, -50.743154805999971 ], [ -72.263465535999899, -50.836275736999973 ], [ -72.265946004999876, -50.960712584999982 ], [ -72.404593872999953, -51.105820006999913 ], [ -72.258814656999846, -51.245191345999977 ], [ -72.320464640999887, -51.312577412999893 ], [ -72.35121211799995, -51.475978291999894 ], [ -72.450069132999914, -51.552666117999927 ], [ -72.330903279999916, -51.599381611999917 ], [ -72.300724243999923, -51.691469014999939 ], [ -71.981725626999946, -51.844948018999936 ], [ -71.965240844999869, -51.970625101999893 ], [ -69.952753865999881, -52.007418721999976 ], [ -69.485288859999855, -52.13247568699996 ], [ -69.212256428999865, -52.13795338999995 ], [ -68.454499063999975, -52.299907327999861 ], [ -68.448609732999898, -52.346617015999925 ], [ -68.898461399999917, -52.303537198999948 ], [ -69.234708121999915, -52.203143069999953 ], [ -69.47093665299991, -52.27271900799991 ], [ -69.496937628999945, -52.385349216999941 ], [ -69.672351495999919, -52.53085653799991 ], [ -69.846579596999902, -52.48654268599995 ], [ -70.151981893999903, -52.586508318999904 ], [ -70.2077156819999, -52.651003467999942 ], [ -70.321792923999908, -52.638147171999947 ], [ -70.517734388999941, -52.723254926999914 ], [ -70.548235298999941, -52.722721843999921 ], [ -70.525878290999913, -52.659927067999945 ], [ -70.698178096999925, -52.73943212599994 ], [ -70.734038865999935, -52.701429945999905 ], [ -70.863758917999917, -52.721368096999925 ], [ -70.738840298999946, -52.783868096999925 ], [ -70.889214765999952, -52.913626393999948 ], [ -70.809152798999946, -52.961602471999925 ], [ -70.950550910999937, -53.197523695999905 ], [ -70.992746548999946, -53.382989190999922 ], [ -70.939442511999914, -53.592217705999929 ], [ -70.973622199999909, -53.756036065999922 ], [ -71.285023566999939, -53.88600025799991 ], [ -71.644642706999946, -53.823663018999923 ], [ -71.874419725999928, -53.69654713299991 ], [ -71.929432745999918, -53.728773695999905 ], [ -72.001454230999911, -53.674086195999905 ], [ -72.103871222999942, -53.689060153999947 ], [ -72.453277147999927, -53.407321872999944 ], [ -72.41234290299991, -53.310967705999929 ], [ -72.282297329999949, -53.242771091999941 ], [ -72.114613410999937, -53.256768487999921 ], [ -72.080433722999942, -53.329034112999921 ], [ -72.099598761999914, -53.390069268999923 ], [ -72.241688605999911, -53.434502862999921 ], [ -72.092518683999913, -53.422621351999908 ], [ -72.015126105999911, -53.392998955999929 ], [ -72.02171790299991, -53.24732838299991 ], [ -71.855620897999927, -53.225355726999908 ], [ -71.789173956999946, -53.441338799999926 ], [ -72.007964647999927, -53.554294528999947 ], [ -71.814198370999918, -53.520684502999927 ], [ -71.754465298999946, -53.462497653999947 ], [ -71.74242102799991, -53.223402601999908 ], [ -71.360218878999945, -53.116143487999921 ], [ -71.198581546999947, -52.923903591999931 ], [ -71.118764335999913, -52.9196357699999 ], [ -71.169285396999953, -52.812813005999942 ], [ -71.352114779999908, -52.807111447999944 ], [ -71.398793097999942, -52.72820403399993 ], [ -71.398629153999934, -52.831715458999952 ], [ -71.483957485999952, -52.824883721999925 ], [ -71.906232838999927, -53.010888517999945 ], [ -72.021962042999917, -53.125420830999929 ], [ -72.117054816999939, -53.12859465899993 ], [ -72.286000128999945, -53.029880466999941 ], [ -72.268950975999928, -53.071465752999927 ], [ -72.380034959999932, -53.050388278999947 ], [ -72.56314042899993, -53.078871351999908 ], [ -72.367095506999931, -53.068129164999903 ], [ -72.191395636999914, -53.180596612999921 ], [ -72.364572719999899, -53.180759372999944 ], [ -72.315785285999937, -53.20671965899993 ], [ -72.364572719999899, -53.222263278999947 ], [ -72.488026495999918, -53.187595309999949 ], [ -72.461984829999949, -53.229913018999923 ], [ -72.538197394999941, -53.197360934999949 ], [ -72.41234290299991, -53.256442966999941 ], [ -72.535878058999913, -53.270114841999941 ], [ -72.522206183999913, -53.366306247999944 ], [ -72.645130988999938, -53.317803643999923 ], [ -72.364572719999899, -53.536879164999903 ], [ -72.531727667999917, -53.542087497999944 ], [ -72.721424933999913, -53.462497653999947 ], [ -72.763172980999911, -53.387790622999944 ], [ -72.794667120999918, -53.440118096999925 ], [ -72.809559699999909, -53.386814059999949 ], [ -73.199086066999939, -53.240817966999941 ], [ -73.30304928299995, -53.153415622999944 ], [ -73.139149542999917, -53.187595309999949 ], [ -72.956369594999899, -53.160577080999929 ], [ -72.713286912999934, -53.29029713299991 ], [ -72.689198370999918, -53.240329684999949 ], [ -72.795969204999949, -53.173272393999923 ], [ -72.65257727799991, -53.153415622999944 ], [ -72.713978644999941, -53.105564059999949 ], [ -72.845082160999937, -53.150160414999903 ], [ -72.933745897999927, -53.10475025799991 ], [ -72.878488735999952, -53.016778252999927 ], [ -72.92642167899993, -53.024590752999927 ], [ -72.923980272999927, -52.88640715899993 ], [ -72.976470506999931, -52.838799737999921 ], [ -72.762440558999913, -52.769789320999905 ], [ -72.703480597999942, -52.707696221999925 ], [ -72.611317511999914, -52.774102471999925 ], [ -72.714833136999914, -52.869398695999905 ], [ -72.58820553299995, -52.795993747999944 ], [ -72.595855272999927, -52.834242445999905 ], [ -72.473988410999937, -52.806410414999903 ], [ -72.431263800999943, -52.856622002999927 ], [ -72.398060675999943, -52.783461195999905 ], [ -72.16087419899992, -52.6521177649999 ], [ -71.980140099999915, -52.645461079999905 ], [ -71.850528565999923, -52.694709557999943 ], [ -71.478102850999903, -52.646137732999932 ], [ -71.571611052999913, -52.561277867999934 ], [ -72.28156490799995, -52.513848565999922 ], [ -72.433461066999939, -52.618910414999903 ], [ -72.398060675999943, -52.618910414999903 ], [ -72.419260219999899, -52.653008721999925 ], [ -72.54914303299995, -52.591566664999903 ], [ -72.389637824999909, -52.507582289999903 ], [ -72.569976365999935, -52.556898695999905 ], [ -72.858021613999938, -52.502211195999905 ], [ -72.988352016999897, -52.704278252999927 ], [ -72.819203253999945, -52.586521091999941 ], [ -72.673898891999897, -52.652520440999922 ], [ -72.790842251999948, -52.752699476999908 ], [ -73.015614386999914, -52.841729424999926 ], [ -72.953602667999917, -52.893324476999908 ], [ -72.979562954999949, -53.054782809999949 ], [ -73.139719204999949, -53.099216403999947 ], [ -73.176665818999936, -53.015232028999947 ], [ -73.198475714999915, -53.104913018999923 ], [ -73.455962693999936, -52.986504815999922 ], [ -73.351429816999939, -52.99578215899993 ], [ -73.371937628999945, -52.965264580999929 ], [ -73.313872850999928, -52.934258721999925 ], [ -73.241566535999937, -52.961602471999925 ], [ -73.262074347999942, -52.92742278399993 ], [ -73.213856574999909, -52.887790622999944 ], [ -73.351429816999939, -52.885918877999927 ], [ -73.563710089999915, -52.797051690999922 ], [ -73.23306230399993, -52.790622653999947 ], [ -73.306630011999914, -52.715427341999941 ], [ -73.152699347999942, -52.633965752999927 ], [ -73.122141079999949, -52.55006275799991 ], [ -73.003977016999897, -52.55828215899993 ], [ -73.117990688999953, -52.532810153999947 ], [ -73.091623501999948, -52.49382903399993 ], [ -72.885853644999941, -52.525648695999905 ], [ -72.905832485999952, -52.496026299999926 ], [ -73.143544074999909, -52.490004164999903 ], [ -73.194976365999935, -52.429864190999922 ], [ -73.235340949999909, -52.496026299999926 ], [ -73.159657355999911, -52.56373463299991 ], [ -73.268910285999937, -52.673597914999903 ], [ -73.337757941999939, -52.646661065999922 ], [ -73.308461066999939, -52.584649346999925 ], [ -73.393625454999949, -52.544122002999927 ], [ -73.397328253999945, -52.636488539999903 ], [ -73.508697068999936, -52.656019789999903 ], [ -73.616444464999915, -52.749118747999944 ], [ -73.69953365799995, -52.71453215899993 ], [ -73.57054602799991, -52.632012627999927 ], [ -73.669585740999935, -52.643243096999925 ], [ -73.687855597999942, -52.597832940999922 ], [ -73.55337480399993, -52.551039320999905 ], [ -73.619252081999946, -52.520440362999921 ], [ -73.565500454999949, -52.478936455999929 ], [ -73.494862433999913, -52.475518487999921 ], [ -73.515288865999935, -52.420342705999929 ], [ -73.666167772999927, -52.424004815999922 ], [ -73.562977667999917, -52.322849216999941 ], [ -73.612660285999937, -52.277439059999949 ], [ -73.580555792999917, -52.208428643999923 ], [ -73.680409308999913, -52.145928643999923 ], [ -73.73501542899993, -52.029961846999925 ], [ -73.550119594999899, -52.186944268999923 ], [ -73.468332485999952, -52.169040622999944 ], [ -73.495716925999943, -52.131931247999944 ], [ -73.30304928299995, -52.221774997999944 ], [ -73.221791144999941, -52.179864190999922 ], [ -73.204090949999909, -52.108086846999925 ], [ -72.997792120999918, -52.064873955999929 ], [ -72.987456834999932, -52.142998955999929 ], [ -73.040882941999939, -52.148858330999929 ], [ -73.079253709999932, -52.237074476999908 ], [ -72.994536912999934, -52.186944268999923 ], [ -72.866444464999915, -52.256768487999921 ], [ -72.754872199999909, -52.056817315999922 ], [ -72.841175910999937, -52.105726820999905 ], [ -72.883697068999936, -52.198337497999944 ], [ -72.947377081999946, -52.166436455999929 ], [ -72.947377081999946, -52.049737237999921 ], [ -72.902333136999914, -52.064060153999947 ], [ -72.864857550999943, -51.95476653399993 ], [ -72.802805141999897, -51.937432549999926 ], [ -72.686675584999932, -51.988376559999949 ], [ -72.703480597999942, -52.060316664999903 ], [ -72.601389126999948, -52.111911716999941 ], [ -72.535878058999913, -52.221774997999944 ], [ -72.601714647999927, -52.339288018999923 ], [ -72.679025844999899, -52.323011976999908 ], [ -72.930531378999945, -52.448174737999921 ], [ -72.721424933999913, -52.406670830999929 ], [ -72.522206183999913, -52.448337497999944 ], [ -72.637562628999945, -52.397637627999927 ], [ -72.497141079999949, -52.315362237999921 ], [ -72.466949022999927, -52.204278252999927 ], [ -72.64867102799991, -52.049004815999922 ], [ -72.669667120999918, -51.961032809999949 ], [ -72.46898352799991, -51.929294528999947 ], [ -72.508371548999946, -51.837090752999927 ], [ -72.466949022999927, -51.789727471999925 ], [ -72.689035610999952, -51.59343840899993 ], [ -72.926258917999917, -51.54265715899993 ], [ -73.067941860999952, -51.478610934999949 ], [ -73.090972459999932, -51.420830987999921 ], [ -73.267648891999897, -51.480564059999949 ], [ -73.054310675999943, -51.502618096999925 ], [ -73.098255988999938, -51.60475025799991 ], [ -72.989165818999936, -51.52662525799991 ], [ -72.793812628999945, -51.596123955999929 ], [ -72.702951626999948, -51.698011976999908 ], [ -72.555246548999946, -51.729668877999927 ], [ -72.562408006999931, -51.778252862999921 ], [ -72.724110480999911, -51.838148695999905 ], [ -72.829741990999935, -51.767998955999929 ], [ -72.976673956999946, -51.76921965899993 ], [ -73.048817511999914, -51.696872653999947 ], [ -73.150786912999934, -51.703057549999926 ], [ -73.182443813999953, -51.637465101999908 ], [ -73.280018683999913, -51.606215101999908 ], [ -73.224476691999939, -51.710870049999926 ], [ -73.070057745999918, -51.724541924999926 ], [ -72.994536912999934, -51.789727471999925 ], [ -73.106027798999946, -51.744886976999908 ], [ -73.139149542999917, -51.76921965899993 ], [ -73.060373501999948, -51.76921965899993 ], [ -73.049794074999909, -51.83131275799991 ], [ -73.207427537999934, -51.879082940999922 ], [ -72.972401495999918, -51.821709893999923 ], [ -72.919422980999911, -51.858575127999927 ], [ -73.145334438999953, -51.940036716999941 ], [ -73.176665818999936, -52.081231377999927 ], [ -73.223703579999949, -52.09148528399993 ], [ -73.272613084999932, -52.039646091999941 ], [ -73.326771613999938, -51.726983330999929 ], [ -73.386219855999911, -51.652520440999922 ], [ -73.292836066999939, -52.16570403399993 ], [ -73.563547329999949, -52.039971612999921 ], [ -73.611480272999927, -51.934340101999908 ], [ -73.577992316999939, -51.926934502999927 ], [ -73.645578579999949, -51.848728122999944 ], [ -73.620920376999948, -51.81218840899993 ], [ -73.399810350999928, -52.015720309999949 ], [ -73.589182094999899, -51.749607028999947 ], [ -73.460682745999918, -51.686700127999927 ], [ -73.550119594999899, -51.721449476999908 ], [ -73.550119594999899, -51.680433851999908 ], [ -73.591664191999939, -51.721449476999908 ], [ -73.654855923999946, -51.688571872999944 ], [ -73.718902147999927, -51.775811455999929 ], [ -73.812001105999911, -51.688571872999944 ], [ -73.714588995999918, -51.638848565999922 ], [ -73.899525519999941, -51.625176690999922 ], [ -73.816965298999946, -51.536553643999923 ], [ -73.909250454999949, -51.526950778999947 ], [ -73.934315558999913, -51.406019789999903 ], [ -73.880360480999911, -51.367933851999908 ], [ -73.814035610999952, -51.392185153999947 ], [ -73.611887173999946, -51.625420830999929 ], [ -73.638824022999927, -51.536553643999923 ], [ -73.604603644999941, -51.51295338299991 ], [ -73.659982876999948, -51.494886976999908 ], [ -73.59788977799991, -51.432793877999927 ], [ -73.692209438999953, -51.414483330999929 ], [ -73.717681443999936, -51.288506768999923 ], [ -73.782826300999943, -51.234795830999929 ], [ -73.759592251999948, -51.19500090899993 ], [ -73.682728644999941, -51.275974216999941 ], [ -73.673573370999918, -51.187676690999922 ], [ -73.72883053299995, -51.179620049999926 ], [ -73.694081183999913, -51.139255466999941 ], [ -73.76984615799995, -51.118096612999921 ], [ -73.762847459999932, -51.163832289999903 ], [ -73.879383917999917, -51.237888278999947 ], [ -74.023304816999939, -51.11101653399993 ], [ -74.029896613999938, -51.207614841999941 ], [ -74.129505988999938, -51.187676690999922 ], [ -74.152943488999938, -51.060967705999929 ], [ -74.071441209999932, -50.953708591999941 ], [ -74.232248501999948, -51.035577080999929 ], [ -74.256418423999946, -50.939385674999926 ], [ -74.15103105399993, -50.872816664999903 ], [ -73.926828579999949, -50.864353122999944 ], [ -73.803334113999938, -50.960544528999947 ], [ -73.789662238999938, -50.919528903999947 ], [ -73.879709438999953, -50.834161065999922 ], [ -73.854603644999941, -50.797295830999929 ], [ -73.741851365999935, -50.820489190999922 ], [ -73.789662238999938, -50.79656340899993 ], [ -73.772938605999911, -50.670668226999908 ], [ -73.636708136999914, -50.63990650799991 ], [ -73.553212042999917, -50.707207940999922 ], [ -73.474354620999918, -50.672458591999941 ], [ -73.725087042999917, -50.559502862999921 ], [ -73.563710089999915, -50.404961846999925 ], [ -73.759388800999943, -50.515720309999949 ], [ -73.822621222999942, -50.757907809999949 ], [ -73.937123175999943, -50.827080987999921 ], [ -74.042713995999918, -50.822035414999903 ], [ -74.126088019999941, -50.762465101999908 ], [ -74.060170050999943, -50.712009372999944 ], [ -74.118641730999911, -50.68678150799991 ], [ -74.14712480399993, -50.728692315999922 ], [ -74.235951300999943, -50.604180596999925 ], [ -74.198719855999911, -50.559014580999929 ], [ -74.297352667999917, -50.480645440999922 ], [ -74.207997199999909, -50.463636976999908 ], [ -74.126088019999941, -50.590508721999925 ], [ -74.149810350999928, -50.483086846999925 ], [ -73.879709438999953, -50.542738539999903 ], [ -74.128895636999914, -50.422946872999944 ], [ -74.016224738999938, -50.363946221999925 ], [ -74.252552863999938, -50.440524997999944 ], [ -74.321278449999909, -50.38445403399993 ], [ -74.262928839999915, -50.317071221999925 ], [ -74.282704230999911, -50.26490650799991 ], [ -74.354847785999937, -50.359551690999922 ], [ -74.439320441999939, -50.35711028399993 ], [ -74.536366339999915, -50.296319268999923 ], [ -74.481760219999899, -50.248630466999941 ], [ -74.694650844999899, -50.183038018999923 ], [ -74.573719855999911, -50.09929778399993 ], [ -74.504383917999917, -50.131931247999944 ], [ -74.495432094999899, -50.076592705999929 ], [ -74.347645636999914, -50.086114190999922 ], [ -74.289906378999945, -50.131280205999929 ], [ -74.324696417999917, -50.172784112999921 ], [ -74.224964972999942, -50.197035414999903 ], [ -74.194406704999949, -50.259698174999926 ], [ -74.121449347999942, -50.223077080999929 ], [ -73.857899542999917, -50.289483330999929 ], [ -73.999134894999941, -50.241794528999947 ], [ -74.00609290299991, -50.201918226999908 ], [ -74.174712693999936, -50.19850025799991 ], [ -74.242176886999914, -50.080010674999926 ], [ -74.364857550999943, -49.990329684999949 ], [ -74.349436001999948, -49.935316664999903 ], [ -74.266346808999913, -49.932549737999921 ], [ -74.139475063999953, -50.015883070999905 ], [ -73.934315558999913, -50.028903903999947 ], [ -73.885894334999932, -50.076592705999929 ], [ -73.913197394999941, -50.007745049999926 ], [ -74.007679816999939, -49.991387627999927 ], [ -73.879709438999953, -49.919040622999944 ], [ -73.906361456999946, -49.856866143999923 ], [ -74.035959438999953, -49.964776299999926 ], [ -74.324696417999917, -49.871189059999949 ], [ -74.348255988999938, -49.792087497999944 ], [ -74.064035610999952, -49.713555596999925 ], [ -74.289906378999945, -49.74146900799991 ], [ -74.322255011999914, -49.63250090899993 ], [ -74.233876105999911, -49.566013278999947 ], [ -74.053822394999941, -49.539320570999905 ], [ -74.023019985999952, -49.617852471999925 ], [ -73.999134894999941, -49.559258721999925 ], [ -73.926828579999949, -49.569512627999927 ], [ -73.901356574999909, -49.649997653999947 ], [ -73.727853969999899, -49.781670830999929 ], [ -73.687855597999942, -49.720310153999947 ], [ -73.852528449999909, -49.653252862999921 ], [ -73.879709438999953, -49.528497002999927 ], [ -74.090972459999932, -49.497165622999944 ], [ -74.123524542999917, -49.422621351999908 ], [ -74.07445227799991, -49.261651299999926 ], [ -73.96353105399993, -49.32976653399993 ], [ -73.844878709999932, -49.349786065999922 ], [ -73.985096808999913, -49.273370049999926 ], [ -73.979725714999915, -49.164239190999922 ], [ -74.043527798999946, -49.082940362999921 ], [ -73.942250128999945, -49.023532809999949 ], [ -73.832875128999945, -49.032159112999921 ], [ -74.057484503999945, -49.012465101999908 ], [ -74.036040818999936, -49.144952080999929 ], [ -74.106434699999909, -49.221286716999941 ], [ -74.192860480999911, -49.208184502999927 ], [ -74.145904100999928, -49.30201588299991 ], [ -74.214914516999897, -49.52312590899993 ], [ -74.422759568999936, -49.384698174999926 ], [ -74.412709113999938, -49.218845309999949 ], [ -74.371896938999953, -49.186618747999944 ], [ -74.405506964999915, -49.067803643999923 ], [ -74.440785285999937, -49.090427341999941 ], [ -74.468658006999931, -49.031670830999929 ], [ -74.403146938999953, -48.987237237999921 ], [ -74.422474738999938, -48.934991143999923 ], [ -74.365630662999934, -48.932061455999929 ], [ -74.453480597999942, -48.830987237999921 ], [ -74.371896938999953, -48.719170830999929 ], [ -74.334828253999945, -48.755059502999927 ], [ -74.066725035931654, -48.741957988470404 ], [ -73.170447858999893, -49.250870019999937 ] ] ], [ [ [ -68.641997850999928, -54.799167575999945 ], [ -68.665842251999948, -54.88640715899993 ], [ -68.928578253999945, -54.778497002999927 ], [ -68.965687628999945, -54.78443775799991 ], [ -68.737863735999952, -54.896091403999947 ], [ -69.067005988999938, -54.948825778999947 ], [ -69.648304816999939, -54.822523695999905 ], [ -69.678822394999941, -54.787692966999941 ], [ -69.624379035999937, -54.760837497999944 ], [ -69.627064581999946, -54.692071221999925 ], [ -69.678822394999941, -54.764743747999944 ], [ -69.716053839999915, -54.689060153999947 ], [ -69.73078365799995, -54.803155205999929 ], [ -69.774403449999909, -54.715590101999908 ], [ -69.808990037999934, -54.810967705999929 ], [ -69.911610480999911, -54.818617445999905 ], [ -69.966623501999948, -54.778415622999944 ], [ -69.969553188999953, -54.676853122999944 ], [ -69.993275519999941, -54.835056247999944 ], [ -70.092844204999949, -54.849053643999923 ], [ -70.087147589999915, -54.77857838299991 ], [ -70.164865688999953, -54.845961195999905 ], [ -70.309437628999945, -54.838555596999925 ], [ -70.244536912999934, -54.689060153999947 ], [ -70.365345831999946, -54.83521900799991 ], [ -70.581166144999941, -54.77898528399993 ], [ -70.758778449999909, -54.840590101999908 ], [ -70.837025519999941, -54.787692966999941 ], [ -70.624582485999952, -54.731540622999944 ], [ -70.452870245999918, -54.633721612999921 ], [ -70.543080206999946, -54.623467705999929 ], [ -70.630970831999946, -54.667738539999903 ], [ -70.606353318999936, -54.703789971999925 ], [ -70.815907355999911, -54.750420830999929 ], [ -70.92210852799991, -54.71257903399993 ], [ -70.774322068999936, -54.681573174999926 ], [ -70.944813605999911, -54.672133070999905 ], [ -71.02757727799991, -54.77703215899993 ], [ -70.951568162999934, -54.616387627999927 ], [ -71.062367316999939, -54.592705987999921 ], [ -71.050038214999915, -54.657403252999927 ], [ -71.103342251999948, -54.633721612999921 ], [ -71.179676886999914, -54.702569268999923 ], [ -71.289662238999938, -54.676446221999925 ], [ -71.192697719999899, -54.626885674999926 ], [ -71.255767381999931, -54.613864841999941 ], [ -71.233631964999915, -54.531345309999949 ], [ -71.297963019999941, -54.559340101999908 ], [ -71.347075975999928, -54.517185153999947 ], [ -71.336048956999946, -54.565524997999944 ], [ -71.412464972999942, -54.579196872999944 ], [ -71.336048956999946, -54.606377862999921 ], [ -71.487863735999952, -54.687432549999926 ], [ -71.521066860999952, -54.661065362999921 ], [ -71.494292772999927, -54.592705987999921 ], [ -71.583119269999941, -54.654880466999941 ], [ -71.555775519999941, -54.585870049999926 ], [ -71.597767706999946, -54.580987237999921 ], [ -71.64517167899993, -54.654880466999941 ], [ -71.685047980999911, -54.634698174999926 ], [ -71.652007615999935, -54.599541924999926 ], [ -71.754465298999946, -54.592705987999921 ], [ -71.822661912999934, -54.654880466999941 ], [ -71.944325324999909, -54.654554945999905 ], [ -71.980946417999917, -54.613213799999926 ], [ -71.905262824999909, -54.613213799999926 ], [ -71.889759894999941, -54.568129164999903 ], [ -72.001454230999911, -54.571709893999923 ], [ -72.007720506999931, -54.505303643999923 ], [ -71.940012173999946, -54.510837497999944 ], [ -72.002349412999934, -54.459079684999949 ], [ -71.973500128999945, -54.448663018999923 ], [ -71.849761522999927, -54.538181247999944 ], [ -71.671864386999914, -54.571709893999923 ], [ -71.748199022999927, -54.510837497999944 ], [ -71.583119269999941, -54.545017184999949 ], [ -71.69359290299991, -54.469333591999941 ], [ -71.840687628999945, -54.465915622999944 ], [ -71.850656704999949, -54.414646091999941 ], [ -71.749134894999941, -54.397149346999925 ], [ -71.563221808999913, -54.510837497999944 ], [ -71.494292772999927, -54.476006768999923 ], [ -71.614125128999945, -54.410902601999908 ], [ -71.389271613999938, -54.457289320999905 ], [ -71.323068813999953, -54.427666924999926 ], [ -71.432932094999899, -54.400974216999941 ], [ -71.364613410999937, -54.372979424999926 ], [ -71.090240037999934, -54.510837497999944 ], [ -71.144886847999942, -54.435153903999947 ], [ -70.972401495999918, -54.469008070999905 ], [ -70.952504035999937, -54.338799737999921 ], [ -70.800648566999939, -54.315850518999923 ], [ -70.610463019999941, -54.338799737999921 ], [ -70.727162238999938, -54.427666924999926 ], [ -70.764393683999913, -54.599541924999926 ], [ -70.740223761999914, -54.551202080999929 ], [ -70.634022589999915, -54.600274346999925 ], [ -70.696929490999935, -54.494805596999925 ], [ -70.585194464999915, -54.390557549999926 ], [ -70.249419725999928, -54.575372002999927 ], [ -70.301991339999915, -54.496514580999929 ], [ -70.130726691999939, -54.545017184999949 ], [ -70.427642381999931, -54.437676690999922 ], [ -70.577707485999952, -54.274834893999923 ], [ -70.843251105999911, -54.263116143999923 ], [ -70.898508266999897, -54.181817315999922 ], [ -70.822743292999917, -54.195489190999922 ], [ -70.932687954999949, -54.113539320999905 ], [ -70.136870897999927, -54.427666924999926 ], [ -70.144642706999946, -54.391371351999908 ], [ -70.074818488999938, -54.369805596999925 ], [ -70.199045376999948, -54.320570570999905 ], [ -70.034494594999899, -54.256931247999944 ], [ -69.973011847999942, -54.297295830999929 ], [ -69.966867641999897, -54.379815362999921 ], [ -69.874867316999939, -54.420993747999944 ], [ -69.883656378999945, -54.503350518999923 ], [ -69.785227016999897, -54.484144789999903 ], [ -69.775380011999914, -54.554864190999922 ], [ -69.741322394999941, -54.477959893999923 ], [ -69.881947394999941, -54.312676690999922 ], [ -69.859120245999918, -54.280368747999944 ], [ -69.691883917999917, -54.317803643999923 ], [ -69.558583136999914, -54.436455987999921 ], [ -69.522043423999946, -54.436455987999921 ], [ -69.570871548999946, -54.372816664999903 ], [ -69.522938605999911, -54.337497653999947 ], [ -69.239979620999918, -54.441338799999926 ], [ -69.226673956999946, -54.476983330999929 ], [ -69.417469855999911, -54.623304945999905 ], [ -69.37718665299991, -54.681573174999926 ], [ -69.373036261999914, -54.615899346999925 ], [ -69.269439256999931, -54.532403252999927 ], [ -69.169911261999914, -54.578220309999949 ], [ -69.157460089999915, -54.453057549999926 ], [ -68.994943813999953, -54.46843840899993 ], [ -68.989003058999913, -54.431410414999903 ], [ -69.27961178299995, -54.32154713299991 ], [ -70.014027472999942, -54.113539320999905 ], [ -70.178212042999917, -53.833428643999923 ], [ -70.13695227799991, -53.738702080999929 ], [ -69.651439879999941, -53.636230524999917 ], [ -69.36084245099994, -53.521674508999922 ], [ -69.318612726999902, -53.450522830999944 ], [ -69.352650519999941, -53.355726820999905 ], [ -69.897822395999924, -53.386643750999951 ], [ -70.202707485999952, -53.468682549999926 ], [ -70.442534959999932, -53.362481377999927 ], [ -70.473540818999936, -53.309258721999925 ], [ -70.418992610999908, -53.01171639599994 ], [ -70.314865037999937, -52.968047700999932 ], [ -70.335238748999927, -53.051295798999945 ], [ -70.243452110999954, -53.061724858999924 ], [ -70.134229284999947, -53.011950621999915 ], [ -70.089174815999911, -52.91106302299994 ], [ -70.21939042899993, -52.865166924999926 ], [ -70.30089064099991, -52.914930227999946 ], [ -70.257201763999944, -52.868296175999944 ], [ -70.282659854999906, -52.798448676999953 ], [ -70.416127081999946, -52.758070570999905 ], [ -70.128615208999918, -52.732282481999903 ], [ -70.001133009999933, -52.841733788999932 ], [ -69.911399762999906, -52.847904273999916 ], [ -69.734351084999901, -52.774459190999949 ], [ -69.591011074999926, -52.641873410999949 ], [ -69.603871222999942, -52.52117278399993 ], [ -69.417565115999935, -52.451472415999945 ], [ -69.140248175999943, -52.683770440999922 ], [ -68.920656562999909, -52.640175252999938 ], [ -68.779026105999947, -52.548253849999924 ], [ -68.627616776477794, -52.639571698869695 ], [ -68.641881926766189, -54.78297131557072 ], [ -68.712391730999911, -54.770928643999923 ], [ -68.641997850999928, -54.799167575999945 ] ] ], [ [ [ -67.245106574999909, -55.839613539999903 ], [ -67.224110480999911, -55.897556247999944 ], [ -67.417062954999949, -55.833591403999947 ], [ -67.358550584999932, -55.810479424999926 ], [ -67.245106574999909, -55.839613539999903 ] ] ], [ [ [ -67.094309048999946, -55.826104424999926 ], [ -67.07843990799995, -55.910088799999926 ], [ -67.170033331999946, -55.873793226999908 ], [ -67.140370245999918, -55.817315362999921 ], [ -67.094309048999946, -55.826104424999926 ] ] ], [ [ [ -67.501616990999935, -55.821058851999908 ], [ -67.472013427999912, -55.8425992949999 ], [ -67.621842579999907, -55.9185042229999 ], [ -67.632030186999941, -55.859396381999943 ], [ -67.693558354999936, -55.88952097799995 ], [ -67.748408918999928, -55.849203520999936 ], [ -67.802810182999906, -55.897956432999933 ], [ -67.913944711999932, -55.836566116999904 ], [ -67.501616990999935, -55.821058851999908 ] ] ], [ [ [ -67.232085740999935, -55.771416924999926 ], [ -67.18781490799995, -55.756931247999944 ], [ -67.156971808999913, -55.778252862999921 ], [ -67.228505011999914, -55.798435153999947 ], [ -67.232085740999935, -55.771416924999926 ] ] ], [ [ [ -67.376088019999941, -55.750909112999921 ], [ -67.44554602799991, -55.762627862999921 ], [ -67.581532355999911, -55.709405205999929 ], [ -67.505848761999914, -55.654066664999903 ], [ -67.420643683999913, -55.707452080999929 ], [ -67.431996222999942, -55.595472914999903 ], [ -67.348703579999949, -55.575616143999923 ], [ -67.320871548999946, -55.654066664999903 ], [ -67.361805792999917, -55.706231377999927 ], [ -67.269927537999934, -55.716241143999923 ], [ -67.252552863999938, -55.763929945999905 ], [ -67.341379360999952, -55.791924737999921 ], [ -67.376088019999941, -55.750909112999921 ] ] ], [ [ [ -67.643137173999946, -55.49732838299991 ], [ -67.587757941999939, -55.585870049999926 ], [ -67.73859615799995, -55.61687590899993 ], [ -67.683949347999942, -55.565362237999921 ], [ -67.699370897999927, -55.505466403999947 ], [ -67.643137173999946, -55.49732838299991 ] ] ], [ [ [ -69.714507615999935, -55.34498463299991 ], [ -69.637318488999938, -55.38836028399993 ], [ -69.801747199999909, -55.407810153999947 ], [ -69.801747199999909, -55.332614841999941 ], [ -69.714507615999935, -55.34498463299991 ] ] ], [ [ [ -70.014027472999942, -55.30592213299991 ], [ -69.947824673999946, -55.283868096999925 ], [ -70.006459113999938, -55.374444268999923 ], [ -70.02765865799995, -55.318942966999941 ], [ -70.110218878999945, -55.29225025799991 ], [ -70.014027472999942, -55.30592213299991 ] ] ], [ [ [ -66.855336066999939, -55.27117278399993 ], [ -66.839588995999918, -55.302504164999903 ], [ -66.938059048999946, -55.334567966999941 ], [ -67.060170050999943, -55.326348565999922 ], [ -67.07445227799991, -55.278008721999925 ], [ -66.992258266999954, -55.228692315999922 ], [ -66.865305141999954, -55.233005466999941 ], [ -66.855336066999939, -55.27117278399993 ] ] ], [ [ [ -66.426747199999909, -55.185479424999926 ], [ -66.515492316999939, -55.264336846999925 ], [ -66.643055792999917, -55.264336846999925 ], [ -66.632191535999937, -55.205987237999921 ], [ -66.534820115999935, -55.162774346999925 ], [ -66.426747199999909, -55.185479424999926 ] ] ], [ [ [ -66.869007941999939, -55.024102471999925 ], [ -66.80687415299991, -55.112888278999947 ], [ -67.070912238999938, -55.00945403399993 ], [ -67.023915167999917, -54.992445570999905 ], [ -66.869007941999939, -55.024102471999925 ] ] ], [ [ [ -67.999256964999915, -55.627536716999941 ], [ -68.033355272999927, -55.661553643999923 ], [ -67.985585089999915, -55.675225518999923 ], [ -68.09829667899993, -55.712090752999927 ], [ -68.153309699999909, -55.596286716999941 ], [ -68.289784308999913, -55.610121351999908 ], [ -68.252512173999946, -55.524509372999944 ], [ -68.353627081999946, -55.475274346999925 ], [ -68.500477667999917, -55.490980726999908 ], [ -68.616810675999943, -55.407810153999947 ], [ -68.602528449999909, -55.462334893999923 ], [ -68.801136847999942, -55.421319268999923 ], [ -68.768299933999913, -55.492608330999929 ], [ -68.865345831999946, -55.505303643999923 ], [ -68.965687628999945, -55.407810153999947 ], [ -68.753407355999911, -55.380466403999947 ], [ -68.808664516999897, -55.359958591999941 ], [ -68.760243292999917, -55.332614841999941 ], [ -68.971302863999938, -55.377129815999922 ], [ -68.801136847999942, -55.188653252999927 ], [ -68.986683722999942, -55.265232028999947 ], [ -69.116607225999928, -55.205661716999941 ], [ -69.122670050999943, -55.147637627999927 ], [ -69.134103969999899, -55.24773528399993 ], [ -69.212717251999948, -55.21648528399993 ], [ -69.239979620999918, -55.127129815999922 ], [ -69.438628709999932, -55.161879164999903 ], [ -69.287831183999913, -55.168145440999922 ], [ -69.267323370999918, -55.23015715899993 ], [ -69.479603644999941, -55.236993096999925 ], [ -69.459095831999946, -55.30592213299991 ], [ -69.280384894999941, -55.318942966999941 ], [ -69.308257615999935, -55.359958591999941 ], [ -69.240589972999942, -55.369561455999929 ], [ -69.300852016999897, -55.428155205999929 ], [ -69.13703365799995, -55.441827080999929 ], [ -69.161610480999911, -55.514336846999925 ], [ -69.339222785999937, -55.474867445999905 ], [ -69.362863735999952, -55.388929945999905 ], [ -69.437082485999952, -55.491306247999944 ], [ -69.451527472999942, -55.408868096999925 ], [ -69.520578579999949, -55.393975518999923 ], [ -69.416086391999897, -55.353122653999947 ], [ -69.60765540299991, -55.365492445999905 ], [ -69.620187954999949, -55.329522393999923 ], [ -69.788075324999909, -55.30592213299991 ], [ -69.568959113999938, -55.27117278399993 ], [ -69.673980272999927, -55.260349216999941 ], [ -69.500070766999897, -55.174981377999927 ], [ -69.848052537999934, -55.257907809999949 ], [ -69.924672003999945, -55.222751559999949 ], [ -69.852406378999945, -55.215508721999925 ], [ -69.911610480999911, -55.196058851999908 ], [ -69.842681443999936, -55.168145440999922 ], [ -70.031076626999948, -55.147637627999927 ], [ -69.885975714999915, -55.063571872999944 ], [ -69.587473110999952, -55.041192315999922 ], [ -69.582020636999914, -55.154473565999922 ], [ -69.541493292999917, -55.145114841999941 ], [ -69.52757727799991, -55.031996351999908 ], [ -69.32876542899993, -55.05201588299991 ], [ -69.383412238999938, -55.016696872999944 ], [ -68.441151495999918, -54.939711195999905 ], [ -68.335072394999941, -55.010430596999925 ], [ -68.334828253999945, -55.062432549999926 ], [ -68.441395636999914, -55.045668226999908 ], [ -68.431263800999943, -55.078789971999925 ], [ -68.510812954999949, -55.112399997999944 ], [ -68.602609829999949, -55.06609465899993 ], [ -68.569447394999941, -55.135430596999925 ], [ -68.616078253999945, -55.152276299999926 ], [ -69.061879035999937, -55.04461028399993 ], [ -68.786610480999911, -55.165215752999927 ], [ -68.38312740799995, -55.184502862999921 ], [ -68.20921790299991, -55.262872002999927 ], [ -68.500070766999954, -55.311455987999921 ], [ -68.616810675999943, -55.30592213299991 ], [ -68.660959438999953, -55.25750090899993 ], [ -68.745961066999939, -55.27117278399993 ], [ -68.561594204999949, -55.326348565999922 ], [ -68.602528449999909, -55.359958591999941 ], [ -68.447987433999913, -55.326348565999922 ], [ -68.345326300999943, -55.344008070999905 ], [ -68.324370897999927, -55.399509372999944 ], [ -68.146473761999914, -55.404392184999949 ], [ -68.177357550999943, -55.462334893999923 ], [ -68.057484503999945, -55.469008070999905 ], [ -68.101389126999948, -55.527601820999905 ], [ -67.96515865799995, -55.593357028999947 ], [ -67.999256964999915, -55.627536716999941 ] ] ], [ [ [ -67.883168097999942, -55.24382903399993 ], [ -67.73859615799995, -55.236993096999925 ], [ -67.898101365999935, -55.168715101999908 ], [ -67.985585089999915, -55.223565362999921 ], [ -68.13508053299995, -55.218845309999949 ], [ -68.186350063999953, -54.97820403399993 ], [ -68.328846808999913, -54.990655205999929 ], [ -68.360503709999932, -54.93092213299991 ], [ -67.301828579999949, -54.928887627999927 ], [ -67.183094855999911, -54.96803150799991 ], [ -67.05337480399993, -55.093682549999926 ], [ -67.088490363999938, -55.190524997999944 ], [ -67.270619269999941, -55.306898695999905 ], [ -67.451161261999914, -55.271579684999949 ], [ -67.423247850999928, -55.21648528399993 ], [ -67.502919074999909, -55.172133070999905 ], [ -67.608794725999928, -55.188653252999927 ], [ -67.647368943999936, -55.261488539999903 ], [ -67.883168097999942, -55.24382903399993 ] ] ], [ [ [ -70.29515540299991, -55.082452080999929 ], [ -70.267241990999935, -55.112888278999947 ], [ -70.338449673999946, -55.128513278999947 ], [ -70.418080206999946, -55.078789971999925 ], [ -70.397572394999941, -55.106622002999927 ], [ -70.446034308999913, -55.127129815999922 ], [ -70.370269334999932, -55.161879164999903 ], [ -70.49445553299995, -55.209649346999925 ], [ -70.538482225999928, -55.154473565999922 ], [ -70.548085089999915, -55.213555596999925 ], [ -70.564076300999943, -55.14031340899993 ], [ -70.513661261999914, -55.106622002999927 ], [ -70.59007727799991, -55.05046965899993 ], [ -70.715809699999909, -55.122816664999903 ], [ -70.728993292999917, -55.05396900799991 ], [ -70.815337693999936, -55.086195570999905 ], [ -71.007150844999899, -55.04461028399993 ], [ -70.919016079999949, -54.990655205999929 ], [ -71.012847459999932, -54.965020440999922 ], [ -70.864409959999932, -54.930840752999927 ], [ -70.795480923999946, -54.976332289999903 ], [ -70.788563605999911, -54.932224216999941 ], [ -70.562652147999927, -54.968926690999922 ], [ -70.610463019999941, -54.942152601999908 ], [ -70.350453253999945, -54.893731377999927 ], [ -70.315663214999915, -54.907972914999903 ], [ -70.493804490999935, -54.942152601999908 ], [ -70.524525519999941, -54.996758721999925 ], [ -70.729847785999937, -55.01336028399993 ], [ -70.309437628999945, -55.027927341999941 ], [ -70.277740037999934, -55.04851653399993 ], [ -70.342925584999932, -55.069105726999908 ], [ -70.29515540299991, -55.082452080999929 ] ] ], [ [ [ -69.904164191999939, -54.996758721999925 ], [ -69.950347459999932, -54.952894789999903 ], [ -69.842681443999936, -54.942152601999908 ], [ -69.915598110999952, -54.886895440999922 ], [ -69.836333787999934, -54.872247002999927 ], [ -69.774403449999909, -54.955824476999908 ], [ -69.713490363999938, -54.948825778999947 ], [ -69.733469204999949, -54.914239190999922 ], [ -69.691883917999917, -54.914239190999922 ], [ -69.774403449999909, -54.879489841999941 ], [ -69.728342251999948, -54.86451588299991 ], [ -69.513742641999897, -54.893731377999927 ], [ -69.530018683999913, -54.946058851999908 ], [ -69.426380988999938, -54.899590752999927 ], [ -69.16429602799991, -54.955824476999908 ], [ -69.776437954999949, -55.034600518999923 ], [ -69.917795376999948, -55.03834400799991 ], [ -69.904164191999939, -54.996758721999925 ] ] ], [ [ [ -70.421783006999931, -54.845961195999905 ], [ -70.400990363999938, -54.873304945999905 ], [ -70.580881313999953, -54.897881768999923 ], [ -70.747670050999943, -54.873304945999905 ], [ -70.421783006999931, -54.845961195999905 ] ] ], [ [ [ -70.983794725999928, -54.928480726999908 ], [ -71.151722785999937, -54.934177341999941 ], [ -71.090240037999934, -54.907972914999903 ], [ -71.279042120999918, -54.865411065999922 ], [ -71.350982225999928, -54.95435963299991 ], [ -71.33462480399993, -54.902276299999926 ], [ -71.402821417999917, -54.94264088299991 ], [ -71.459584113999938, -54.879489841999941 ], [ -71.404123501999948, -54.829847914999903 ], [ -71.165394660999937, -54.832289320999905 ], [ -71.077870245999918, -54.88014088299991 ], [ -70.946888800999943, -54.873304945999905 ], [ -70.966175910999937, -54.907972914999903 ], [ -70.911529100999928, -54.921075127999927 ], [ -70.983794725999928, -54.928480726999908 ] ] ], [ [ [ -71.946848110999952, -54.702569268999923 ], [ -71.926380988999938, -54.736748955999929 ], [ -71.997466600999928, -54.753106377999927 ], [ -71.991525844999899, -54.69890715899993 ], [ -72.104318813999953, -54.644789320999905 ], [ -72.028187628999945, -54.629327080999929 ], [ -71.946848110999952, -54.702569268999923 ] ] ], [ [ [ -72.339833136999914, -54.331475518999923 ], [ -72.30532792899993, -54.365166924999926 ], [ -72.378814256999931, -54.352634372999944 ], [ -72.360829230999911, -54.379815362999921 ], [ -72.41234290299991, -54.366794528999947 ], [ -72.470692511999914, -54.427666924999926 ], [ -72.541737433999913, -54.34303150799991 ], [ -72.415882941999939, -54.304131768999923 ], [ -72.339833136999914, -54.331475518999923 ] ] ], [ [ [ -70.384592251999948, -54.188083591999941 ], [ -70.28774980399993, -54.188083591999941 ], [ -70.218658006999931, -54.234633070999905 ], [ -70.339751756999931, -54.265801690999922 ], [ -70.521107550999943, -54.174411716999941 ], [ -70.384592251999948, -54.188083591999941 ] ] ], [ [ [ -72.296945766999897, -54.078789971999925 ], [ -72.206288214999915, -54.14771900799991 ], [ -72.296742316999939, -54.200941664999903 ], [ -72.301503058999913, -54.251397393999923 ], [ -72.501698370999918, -54.242771091999941 ], [ -72.515370245999918, -54.202325127999927 ], [ -72.296945766999897, -54.113539320999905 ], [ -72.393137173999946, -54.094496351999908 ], [ -72.296945766999897, -54.078789971999925 ] ] ], [ [ [ -73.180083787999934, -54.07195403399993 ], [ -73.178456183999913, -54.127211195999905 ], [ -73.313384568999936, -54.121189059999949 ], [ -73.337391730999911, -54.065850518999923 ], [ -73.474354620999918, -54.07195403399993 ], [ -73.358265753999945, -54.023614190999922 ], [ -73.180083787999934, -54.07195403399993 ] ] ], [ [ [ -71.630930141999897, -54.078789971999925 ], [ -71.657053188999953, -53.983168226999908 ], [ -71.612172003999945, -53.948011976999908 ], [ -71.514800584999932, -53.989434502999927 ], [ -71.463286912999934, -53.941582940999922 ], [ -71.396351691999939, -54.062758070999905 ], [ -71.398793097999942, -53.975762627999927 ], [ -71.337961391999897, -53.97625090899993 ], [ -71.282093878999945, -54.009942315999922 ], [ -71.288929816999939, -54.106133721999925 ], [ -71.221058722999942, -54.184665622999944 ], [ -71.179676886999914, -54.08562590899993 ], [ -71.155140753999945, -54.155368747999944 ], [ -71.112456834999932, -54.070489190999922 ], [ -71.016224738999938, -54.09539153399993 ], [ -71.062367316999939, -54.202325127999927 ], [ -71.004953579999949, -54.166436455999929 ], [ -71.02798417899993, -54.237399997999944 ], [ -70.990142381999931, -54.265801690999922 ], [ -71.062367316999939, -54.291110934999949 ], [ -71.056467251999948, -54.330010674999926 ], [ -71.157948370999918, -54.297295830999929 ], [ -71.082834438999953, -54.335137627999927 ], [ -71.106516079999949, -54.37664153399993 ], [ -71.176828579999949, -54.327732028999947 ], [ -71.207508917999917, -54.369235934999949 ], [ -71.357818162999934, -54.297295830999929 ], [ -71.24054928299995, -54.277439059999949 ], [ -71.21320553299995, -54.229099216999941 ], [ -71.300770636999914, -54.26140715899993 ], [ -71.331695115999935, -54.204034112999921 ], [ -71.354807094999899, -54.244561455999929 ], [ -71.411000128999945, -54.233330987999921 ], [ -71.44595292899993, -54.185316664999903 ], [ -71.371449347999942, -54.153903903999947 ], [ -71.416615363999938, -54.110039971999925 ], [ -71.507964647999927, -54.14031340899993 ], [ -71.481312628999945, -54.171319268999923 ], [ -71.542144334999932, -54.269952080999929 ], [ -71.596791144999941, -54.229099216999941 ], [ -71.549631313999953, -54.181817315999922 ], [ -71.651519334999932, -54.232028903999947 ], [ -71.699818488999938, -54.166192315999922 ], [ -71.59634355399993, -54.087823174999926 ], [ -71.630930141999897, -54.078789971999925 ] ] ], [ [ [ -72.015126105999911, -54.202325127999927 ], [ -72.110707160999937, -54.153903903999947 ], [ -72.042388475999928, -54.14031340899993 ], [ -72.124379035999937, -54.133477471999925 ], [ -72.042388475999928, -54.113539320999905 ], [ -72.103871222999942, -54.058363539999903 ], [ -72.20531165299991, -54.091892184999949 ], [ -72.203195766999897, -53.996270440999922 ], [ -72.259103969999899, -53.929864190999922 ], [ -72.128041144999941, -53.934177341999941 ], [ -72.06476803299995, -53.983575127999927 ], [ -72.083404100999928, -53.94850025799991 ], [ -72.042388475999928, -53.962090752999927 ], [ -71.945708787999934, -53.85279713299991 ], [ -71.830148891999897, -53.920586846999925 ], [ -71.85187740799995, -53.974053643999923 ], [ -71.792591925999943, -53.897067966999941 ], [ -71.652902798999946, -53.926364841999941 ], [ -71.792225714999915, -53.997979424999926 ], [ -71.700591600999928, -53.985446872999944 ], [ -71.702015753999945, -54.030694268999923 ], [ -71.768666144999941, -54.051446221999925 ], [ -71.652007615999935, -54.089043877999927 ], [ -71.766102667999917, -54.163995049999926 ], [ -71.952300584999932, -54.01490650799991 ], [ -71.915516730999911, -54.116794528999947 ], [ -71.74445553299995, -54.231052341999941 ], [ -71.871083136999914, -54.283623955999929 ], [ -71.830148891999897, -54.331475518999923 ], [ -71.987863735999952, -54.317803643999923 ], [ -71.905262824999909, -54.229099216999941 ], [ -72.015126105999911, -54.202325127999927 ] ] ], [ [ [ -70.455035868999914, -53.611598014999913 ], [ -70.419718551999949, -53.871226476999936 ], [ -70.452219204999949, -53.886895440999922 ], [ -70.34279526499995, -54.028068898999948 ], [ -70.439252421999925, -54.060409171999936 ], [ -70.669961948999912, -53.950341516999913 ], [ -70.568918423999946, -54.065118096999925 ], [ -70.540435350999928, -54.221612237999921 ], [ -70.822743292999917, -54.113539320999905 ], [ -70.884185350999928, -54.02703215899993 ], [ -70.881505322999942, -53.842263989999935 ], [ -70.606114426999909, -53.865125201999945 ], [ -70.60054127099994, -53.829152182999906 ], [ -70.699289516999897, -53.787204684999949 ], [ -70.712880011999914, -53.701429945999905 ], [ -70.566453036999917, -53.626053264999939 ], [ -70.535552537999934, -53.560479424999926 ], [ -70.469534061999923, -53.566314954999939 ], [ -70.455035868999914, -53.611598014999913 ] ] ], [ [ [ -73.82445227799991, -53.472100518999923 ], [ -73.706450975999928, -53.508233330999929 ], [ -73.687855597999942, -53.523207289999903 ], [ -73.848540818999936, -53.588311455999929 ], [ -73.82445227799991, -53.536879164999903 ], [ -73.892323370999918, -53.526299737999921 ], [ -73.833363410999937, -53.505791924999926 ], [ -73.854847785999937, -53.448174737999921 ], [ -73.82445227799991, -53.472100518999923 ] ] ], [ [ [ -73.392445441999939, -53.413995049999926 ], [ -73.509103969999899, -53.475518487999921 ], [ -73.392445441999939, -53.530694268999923 ], [ -73.481800910999937, -53.571709893999923 ], [ -73.54328365799995, -53.510349216999941 ], [ -73.577992316999939, -53.544366143999923 ], [ -73.803334113999938, -53.434502862999921 ], [ -73.574940558999913, -53.491143487999921 ], [ -73.619007941999939, -53.455010674999926 ], [ -73.537017381999931, -53.455010674999926 ], [ -73.592600063999953, -53.385837497999944 ], [ -73.392445441999939, -53.413995049999926 ] ] ], [ [ [ -72.529652472999942, -54.075372002999927 ], [ -72.574370897999927, -54.095472914999903 ], [ -72.635487433999913, -54.023614190999922 ], [ -72.706898566999939, -54.103285414999903 ], [ -72.843088344999899, -54.133558851999908 ], [ -72.926258917999917, -54.119805596999925 ], [ -72.88508053299995, -54.083916924999926 ], [ -73.008859829999949, -54.092461846999925 ], [ -72.795969204999949, -54.058363539999903 ], [ -72.880726691999939, -54.03443775799991 ], [ -72.762440558999913, -54.030450127999927 ], [ -72.823841925999943, -53.996270440999922 ], [ -72.77603105399993, -53.975762627999927 ], [ -72.850575324999909, -53.955254815999922 ], [ -72.645130988999938, -53.859633070999905 ], [ -72.768625454999949, -53.87273528399993 ], [ -72.727650519999941, -53.838636976999908 ], [ -72.809559699999909, -53.859633070999905 ], [ -72.801665818999936, -53.817478122999944 ], [ -73.007313605999911, -53.873711846999925 ], [ -73.056019660999937, -53.812758070999905 ], [ -73.104400193999936, -53.934177341999941 ], [ -73.036203579999949, -53.98601653399993 ], [ -73.098255988999938, -54.037855726999908 ], [ -73.308949347999942, -53.973809502999927 ], [ -73.337757941999939, -53.955254815999922 ], [ -73.236398891999897, -53.896579684999949 ], [ -73.313059048999946, -53.844496351999908 ], [ -73.252837693999936, -53.786065362999921 ], [ -73.310454881999931, -53.742364190999922 ], [ -73.245350714999915, -53.715752862999921 ], [ -73.591664191999939, -53.756036065999922 ], [ -73.484852667999917, -53.70086028399993 ], [ -73.608754035999937, -53.656833591999941 ], [ -73.615345831999946, -53.614027601999908 ], [ -73.435454881999931, -53.563246351999908 ], [ -73.204213019999941, -53.666192315999922 ], [ -72.952870245999918, -53.664483330999929 ], [ -72.958485480999911, -53.633233330999929 ], [ -73.080799933999913, -53.648207289999903 ], [ -73.029286261999914, -53.584730726999908 ], [ -73.134836391999897, -53.646254164999903 ], [ -73.258656378999945, -53.635186455999929 ], [ -73.29124915299991, -53.605889580999929 ], [ -73.262074347999942, -53.558038018999923 ], [ -73.420318162999934, -53.478936455999929 ], [ -73.077137824999909, -53.530694268999923 ], [ -73.175160285999937, -53.420830987999921 ], [ -73.037709113999938, -53.385511976999908 ], [ -73.002023891999897, -53.493259372999944 ], [ -73.015614386999914, -53.407321872999944 ], [ -72.913238084999932, -53.42701588299991 ], [ -72.940988735999952, -53.518324476999908 ], [ -72.872547980999911, -53.53484465899993 ], [ -72.913238084999932, -53.623223565999922 ], [ -72.884144660999937, -53.68132903399993 ], [ -72.81704667899993, -53.564873955999929 ], [ -72.858469204999949, -53.452732028999947 ], [ -72.734486456999946, -53.516534112999921 ], [ -72.678578253999945, -53.673272393999923 ], [ -72.630482550999943, -53.659926039999903 ], [ -72.673003709999932, -53.536879164999903 ], [ -72.464182094999899, -53.575127862999921 ], [ -72.397287563999953, -53.633477471999925 ], [ -72.48468990799995, -53.674004815999922 ], [ -72.453277147999927, -53.742364190999922 ], [ -72.373036261999914, -53.687758070999905 ], [ -72.138661261999914, -53.797621351999908 ], [ -72.250884568999936, -53.877536716999941 ], [ -72.391835089999915, -53.84539153399993 ], [ -72.34406490799995, -53.910088799999926 ], [ -72.419789191999939, -53.897067966999941 ], [ -72.37140865799995, -53.94850025799991 ], [ -72.419789191999939, -53.969496351999908 ], [ -72.323597785999937, -53.989434502999927 ], [ -72.329904751999948, -54.034600518999923 ], [ -72.454213019999941, -54.038262627999927 ], [ -72.453277147999927, -53.989434502999927 ], [ -72.515370245999918, -53.982598565999922 ], [ -72.529652472999942, -54.075372002999927 ] ] ], [ [ [ -74.145904100999928, -53.242771091999941 ], [ -74.058094855999911, -53.250258070999905 ], [ -74.116118943999936, -53.307386976999908 ], [ -74.242176886999914, -53.310967705999929 ], [ -74.145904100999928, -53.242771091999941 ] ] ], [ [ [ -73.433420376999948, -52.865411065999922 ], [ -73.378773566999939, -52.910332940999922 ], [ -73.419300910999937, -52.957696221999925 ], [ -73.501942511999914, -52.885918877999927 ], [ -73.81078040299991, -52.91375090899993 ], [ -73.684559699999909, -52.849704684999949 ], [ -73.601307745999918, -52.865411065999922 ], [ -73.611724412999934, -52.821709893999923 ], [ -73.433420376999948, -52.865411065999922 ] ] ], [ [ [ -73.207427537999934, -53.317803643999923 ], [ -73.090809699999909, -53.355726820999905 ], [ -73.317290818999936, -53.352634372999944 ], [ -73.420318162999934, -53.283135674999926 ], [ -73.58421790299991, -53.317803643999923 ], [ -73.603627081999946, -53.293226820999905 ], [ -73.494862433999913, -53.290622653999947 ], [ -73.880441860999952, -53.057712497999944 ], [ -74.057199673999946, -53.057793877999927 ], [ -74.016224738999938, -53.085137627999927 ], [ -74.086293097999942, -53.104913018999923 ], [ -74.248931443999936, -53.037286065999922 ], [ -74.239857550999943, -53.082940362999921 ], [ -74.318348761999914, -53.09734465899993 ], [ -74.330922003999945, -53.037286065999922 ], [ -74.407215949999909, -53.029880466999941 ], [ -74.407215949999909, -52.969008070999905 ], [ -74.596547003999945, -52.922946872999944 ], [ -74.571156378999945, -52.851739190999922 ], [ -74.749867316999939, -52.75554778399993 ], [ -74.674427863999938, -52.721286716999941 ], [ -74.370961066999939, -52.872653903999947 ], [ -74.407215949999909, -52.91375090899993 ], [ -74.358794725999928, -52.947930596999925 ], [ -74.188303188999953, -52.940524997999944 ], [ -74.142974412999934, -52.989678643999923 ], [ -74.083851691999939, -52.961602471999925 ], [ -74.132883266999897, -52.934258721999925 ], [ -74.074574347999942, -52.947930596999925 ], [ -73.938221808999913, -52.996189059999949 ], [ -73.96157792899993, -53.023614190999922 ], [ -73.875884568999936, -53.00318775799991 ], [ -73.628895636999914, -53.146579684999949 ], [ -73.659982876999948, -53.057793877999927 ], [ -73.62328040299991, -53.05982838299991 ], [ -73.551177537999934, -53.11842213299991 ], [ -73.577992316999939, -53.187595309999949 ], [ -73.516346808999913, -53.26140715899993 ], [ -73.468129035999937, -53.222263278999947 ], [ -73.497710740999935, -53.143243096999925 ], [ -73.459543423999946, -53.132907809999949 ], [ -73.311675584999932, -53.238864841999941 ], [ -73.366037563999953, -53.27117278399993 ], [ -73.266468878999945, -53.268731377999927 ], [ -73.207427537999934, -53.317803643999923 ] ] ], [ [ [ -73.330962693999936, -52.694024346999925 ], [ -73.369211391999897, -52.728610934999949 ], [ -73.399810350999928, -52.72820403399993 ], [ -73.371937628999945, -52.707696221999925 ], [ -73.330962693999936, -52.694024346999925 ] ] ], [ [ [ -73.837391730999911, -52.70086028399993 ], [ -73.954741990999935, -52.707696221999925 ], [ -73.844878709999932, -52.597832940999922 ], [ -73.982045050999943, -52.653008721999925 ], [ -73.872181769999941, -52.55006275799991 ], [ -74.1234192739999, -52.706616519999955 ], [ -74.184368000999939, -52.586800723999943 ], [ -74.049712693999936, -52.56373463299991 ], [ -73.943999463999944, -52.482787733999942 ], [ -74.034209823999902, -52.475987113999906 ], [ -74.029728727999952, -52.429917726999918 ], [ -73.725168423999946, -52.404717705999929 ], [ -73.676991339999915, -52.485121351999908 ], [ -73.78734290299991, -52.554294528999947 ], [ -73.748524542999917, -52.627862237999921 ], [ -73.837391730999911, -52.70086028399993 ] ] ], [ [ [ -74.672565600999917, -52.390548821999914 ], [ -74.713277681999898, -52.34282817299993 ], [ -74.81541341399992, -52.350446949999935 ], [ -74.806660388999944, -52.284244089999902 ], [ -74.911610480999911, -52.20281340899993 ], [ -74.815174933999913, -52.236586195999905 ], [ -74.620676235999952, -52.204278252999927 ], [ -74.544421839999927, -52.246159275999901 ], [ -74.593838670999901, -52.394820257999925 ], [ -74.672565600999917, -52.390548821999914 ] ] ], [ [ [ -73.76984615799995, -52.379327080999929 ], [ -73.872670050999943, -52.376153252999927 ], [ -73.82445227799991, -52.338474216999941 ], [ -74.092762824999909, -52.166599216999941 ], [ -74.042225714999915, -52.141289971999925 ], [ -73.815337693999936, -52.241143487999921 ], [ -73.76984615799995, -52.379327080999929 ] ] ], [ [ [ -74.122547980999911, -52.39771900799991 ], [ -74.245350714999915, -52.316582940999922 ], [ -74.193714972999942, -52.280043226999908 ], [ -74.235951300999943, -52.248304945999905 ], [ -74.207102016999897, -52.226332289999903 ], [ -74.104969855999911, -52.248304945999905 ], [ -74.221669074999909, -52.186944268999923 ], [ -74.145904100999928, -52.193780205999929 ], [ -74.416859503999945, -52.129001559999949 ], [ -74.286773240999935, -52.088636976999908 ], [ -73.935699022999927, -52.324883721999925 ], [ -74.122547980999911, -52.39771900799991 ] ] ], [ [ [ -74.790842251999948, -52.179457289999903 ], [ -74.793853318999936, -52.123955987999921 ], [ -74.60179602799991, -52.064060153999947 ], [ -74.671945766999897, -52.163018487999921 ], [ -74.790842251999948, -52.179457289999903 ] ] ], [ [ [ -74.344553188999953, -52.064060153999947 ], [ -74.387806769999941, -52.077243747999944 ], [ -74.407215949999909, -52.043064059999949 ], [ -74.359730597999942, -52.056817315999922 ], [ -74.344553188999953, -52.064060153999947 ] ] ], [ [ [ -74.492298956999946, -51.978692315999922 ], [ -74.514068162999934, -52.005303643999923 ], [ -74.735585089999915, -52.084567966999941 ], [ -74.543812628999945, -51.920668226999908 ], [ -74.492298956999946, -51.978692315999922 ] ] ], [ [ [ -73.70767167899993, -52.186944268999923 ], [ -73.694081183999913, -52.242282809999949 ], [ -73.871245897999927, -52.094903252999927 ], [ -74.090240037999934, -52.010023695999905 ], [ -74.043527798999946, -52.008884372999944 ], [ -74.110218878999945, -51.968926690999922 ], [ -74.09439042899993, -51.92701588299991 ], [ -74.034982876999948, -51.914483330999929 ], [ -73.784006313999953, -52.059665622999944 ], [ -73.70767167899993, -52.186944268999923 ] ] ], [ [ [ -74.749867316999939, -52.043064059999949 ], [ -74.850575324999909, -52.13014088299991 ], [ -74.896351691999939, -52.113051039999903 ], [ -74.783355272999927, -52.008884372999944 ], [ -74.844878709999932, -51.996758721999925 ], [ -74.750884568999936, -51.833916924999926 ], [ -74.72874915299991, -51.872247002999927 ], [ -74.598459438999953, -51.837497653999947 ], [ -74.749867316999939, -52.043064059999949 ] ] ], [ [ [ -75.061146613999938, -51.882256768999923 ], [ -75.116851365999935, -51.894138278999947 ], [ -75.095366990999935, -51.776462497999944 ], [ -74.98265540299991, -51.721449476999908 ], [ -75.000884568999936, -51.843845309999949 ], [ -75.061146613999938, -51.882256768999923 ] ] ], [ [ [ -74.434559699999909, -51.844903252999927 ], [ -74.409657355999911, -51.808689059999949 ], [ -74.502837693999936, -51.707207940999922 ], [ -74.163075324999909, -51.855564059999949 ], [ -74.221669074999909, -51.872247002999927 ], [ -74.096302863999938, -51.877373955999929 ], [ -74.194732225999928, -51.950290622999944 ], [ -74.434559699999909, -51.844903252999927 ] ] ], [ [ [ -73.789662238999938, -51.735039971999925 ], [ -73.771555141999897, -51.781019789999903 ], [ -73.838775193999936, -51.812595309999949 ], [ -73.940500454999949, -51.663181247999944 ], [ -73.789662238999938, -51.735039971999925 ] ] ], [ [ [ -74.889800584999932, -52.002048434999949 ], [ -74.964222785999937, -52.117608330999929 ], [ -74.947865363999938, -52.056573174999926 ], [ -75.01398678299995, -52.104099216999941 ], [ -74.975168423999946, -52.036228122999944 ], [ -75.071400519999941, -51.98211028399993 ], [ -74.96898352799991, -51.926934502999927 ], [ -75.037220831999946, -51.920668226999908 ], [ -74.957508917999917, -51.815606377999927 ], [ -74.865345831999946, -51.879082940999922 ], [ -74.831857876999948, -51.837497653999947 ], [ -74.886382615999935, -51.773044528999947 ], [ -74.844838019999941, -51.762383721999925 ], [ -74.852284308999913, -51.707207940999922 ], [ -74.922230597999942, -51.655857028999947 ], [ -74.865345831999946, -51.618340752999927 ], [ -74.783355272999927, -51.659356377999927 ], [ -74.762928839999915, -51.78289153399993 ], [ -74.889800584999932, -52.002048434999949 ] ] ], [ [ [ -73.943918423999946, -51.741306247999944 ], [ -73.928537563999953, -51.776299737999921 ], [ -74.014556443999936, -51.799737237999921 ], [ -74.240630662999934, -51.69850025799991 ], [ -74.139068162999934, -51.666761976999908 ], [ -74.149647589999915, -51.604180596999925 ], [ -74.071441209999932, -51.60475025799991 ], [ -74.082142706999946, -51.538181247999944 ], [ -73.992665167999917, -51.663181247999944 ], [ -74.008778449999909, -51.714613539999903 ], [ -73.943918423999946, -51.741306247999944 ] ] ], [ [ [ -74.197132941999939, -51.426690362999921 ], [ -74.23859615799995, -51.409600518999923 ], [ -74.254628058999913, -51.290785414999903 ], [ -74.165109829999949, -51.287041924999926 ], [ -74.112416144999941, -51.378838799999926 ], [ -74.11937415299991, -51.447442315999922 ], [ -74.197132941999939, -51.426690362999921 ] ] ], [ [ [ -75.023589647999927, -51.330987237999921 ], [ -75.016184048999946, -51.413506768999923 ], [ -75.070790167999917, -51.400648695999905 ], [ -75.115956183999913, -51.473239841999941 ], [ -75.160755988999938, -51.426690362999921 ], [ -75.141753709999932, -51.565036716999941 ], [ -75.215402798999946, -51.549493096999925 ], [ -75.205799933999913, -51.601739190999922 ], [ -75.312896287999934, -51.629164320999905 ], [ -75.31468665299991, -51.536553643999923 ], [ -75.225331183999913, -51.490655205999929 ], [ -75.187408006999931, -51.375420830999929 ], [ -75.219838019999941, -51.305433851999908 ], [ -75.126047329999949, -51.270196221999925 ], [ -75.148833787999934, -51.367120049999926 ], [ -75.102406378999945, -51.29615650799991 ], [ -75.023589647999927, -51.330987237999921 ] ] ], [ [ [ -73.793080206999946, -51.258721612999921 ], [ -73.754872199999909, -51.297621351999908 ], [ -73.793690558999913, -51.371026299999926 ], [ -73.895578579999949, -51.33521900799991 ], [ -73.82445227799991, -51.303643487999921 ], [ -73.920643683999913, -51.303643487999921 ], [ -73.793080206999946, -51.258721612999921 ] ] ], [ [ [ -74.739003058999913, -51.368584893999923 ], [ -74.798654751999948, -51.432305596999925 ], [ -75.024159308999913, -51.456231377999927 ], [ -74.798329230999911, -51.330010674999926 ], [ -74.963775193999936, -51.343682549999926 ], [ -74.793080206999946, -51.211195570999905 ], [ -74.643055792999917, -51.19695403399993 ], [ -74.555734829999949, -51.250420830999929 ], [ -74.548980272999927, -51.284356377999927 ], [ -74.626332160999937, -51.262139580999929 ], [ -74.543812628999945, -51.365166924999926 ], [ -74.594227667999917, -51.399509372999944 ], [ -74.646229620999918, -51.392510674999926 ], [ -74.687163865999935, -51.283298434999949 ], [ -74.735585089999915, -51.29615650799991 ], [ -74.739003058999913, -51.368584893999923 ] ] ], [ [ [ -74.865345831999946, -51.121514580999929 ], [ -74.876942511999914, -51.158461195999905 ], [ -75.020497199999909, -51.172784112999921 ], [ -74.96898352799991, -51.104424737999921 ], [ -74.865345831999946, -51.121514580999929 ] ] ], [ [ [ -74.420277472999942, -51.111260674999926 ], [ -74.385365363999938, -51.143731377999927 ], [ -74.434152798999946, -51.205824476999908 ], [ -74.574370897999927, -51.154880466999941 ], [ -74.605213995999918, -51.080254815999922 ], [ -74.486073370999918, -51.021254164999903 ], [ -74.460275844999899, -51.062107028999947 ], [ -74.519520636999914, -51.096368096999925 ], [ -74.420277472999942, -51.111260674999926 ] ] ], [ [ [ -74.248931443999936, -51.234795830999929 ], [ -74.284575975999928, -51.23560963299991 ], [ -74.351958787999934, -50.925713799999926 ], [ -74.301340298999946, -50.939222914999903 ], [ -74.196929490999935, -51.175388278999947 ], [ -74.248931443999936, -51.234795830999929 ] ] ], [ [ [ -74.385568813999953, -50.981052341999941 ], [ -74.398304816999939, -51.086846612999921 ], [ -74.475493943999936, -50.994561455999929 ], [ -74.725453253999945, -51.105075778999947 ], [ -74.749867316999939, -51.042413018999923 ], [ -74.680978969999899, -51.008233330999929 ], [ -74.774566209999932, -50.993340752999927 ], [ -74.831857876999948, -51.076429945999905 ], [ -74.89321855399993, -51.049248955999929 ], [ -74.838002081999946, -50.974216403999947 ], [ -74.966420050999943, -50.949883721999925 ], [ -74.903187628999945, -50.885430596999925 ], [ -74.625477667999917, -50.924899997999944 ], [ -74.584787563999953, -50.885430596999925 ], [ -74.640451626999948, -50.885430596999925 ], [ -74.643055792999917, -50.847832940999922 ], [ -74.558094855999911, -50.817071221999925 ], [ -74.66047115799995, -50.727715752999927 ], [ -74.399769660999937, -50.844414971999925 ], [ -74.434559699999909, -50.925713799999926 ], [ -74.385568813999953, -50.981052341999941 ] ] ], [ [ [ -74.906320766999897, -50.79656340899993 ], [ -74.958973761999914, -50.728285414999903 ], [ -74.844838019999941, -50.748223565999922 ], [ -74.901112433999913, -50.676039320999905 ], [ -74.831857876999948, -50.707207940999922 ], [ -74.804514126999948, -50.666273695999905 ], [ -74.71507727799991, -50.802829684999949 ], [ -74.777211066999939, -50.802829684999949 ], [ -74.718169725999928, -50.861504815999922 ], [ -74.66047115799995, -50.82390715899993 ], [ -74.693023240999935, -50.890069268999923 ], [ -74.781971808999913, -50.882012627999927 ], [ -74.931263800999943, -50.851006768999923 ], [ -74.859120245999918, -50.82390715899993 ], [ -74.94163977799991, -50.79656340899993 ], [ -74.906320766999897, -50.79656340899993 ] ] ], [ [ [ -74.981516079999949, -50.797784112999921 ], [ -75.083892381999931, -50.783623955999929 ], [ -75.113148566999939, -50.721286716999941 ], [ -75.044056769999941, -50.707207940999922 ], [ -75.081695115999935, -50.654880466999941 ], [ -74.985422329999949, -50.657159112999921 ], [ -74.981516079999949, -50.797784112999921 ] ] ], [ [ [ -74.608713344999899, -50.514825127999927 ], [ -74.602650519999941, -50.563083591999941 ], [ -74.673491990999935, -50.576918226999908 ], [ -74.680978969999899, -50.514825127999927 ], [ -74.608713344999899, -50.514825127999927 ] ] ], [ [ [ -75.126047329999949, -50.494317315999922 ], [ -75.119862433999913, -50.533623955999929 ], [ -75.215402798999946, -50.556410414999903 ], [ -75.215402798999946, -50.59693775799991 ], [ -75.345570441999939, -50.560723565999922 ], [ -75.270863410999937, -50.620538018999923 ], [ -75.304758266999897, -50.64576588299991 ], [ -75.263172980999911, -50.666273695999905 ], [ -75.290598110999952, -50.781833591999941 ], [ -75.336293097999942, -50.740817966999941 ], [ -75.461822068999936, -50.762465101999908 ], [ -75.407053188999953, -50.673760674999926 ], [ -75.513824022999927, -50.649102471999925 ], [ -75.359364386999914, -50.590508721999925 ], [ -75.468617316999939, -50.494317315999922 ], [ -75.403797980999911, -50.460137627999927 ], [ -75.352609829999949, -50.501153252999927 ], [ -75.330922003999945, -50.46648528399993 ], [ -75.126047329999949, -50.494317315999922 ] ] ], [ [ [ -74.310414191999939, -50.834161065999922 ], [ -74.373768683999913, -50.82740650799991 ], [ -74.399769660999937, -50.748223565999922 ], [ -74.517079230999911, -50.731622002999927 ], [ -74.581206834999932, -50.633558851999908 ], [ -74.420277472999942, -50.528497002999927 ], [ -74.673491990999935, -50.473809502999927 ], [ -74.552479620999918, -50.423923434999949 ], [ -74.476673956999946, -50.476332289999903 ], [ -74.38312740799995, -50.455987237999921 ], [ -74.239003058999913, -50.676202080999929 ], [ -74.427113410999937, -50.652601820999905 ], [ -74.222645636999914, -50.721612237999921 ], [ -74.181304490999935, -50.782321872999944 ], [ -74.199208136999914, -50.848321221999925 ], [ -74.269357876999948, -50.786553643999923 ], [ -74.310414191999939, -50.834161065999922 ] ] ], [ [ [ -74.783355272999927, -50.480645440999922 ], [ -74.736724412999934, -50.371840101999908 ], [ -74.544585740999935, -50.38209400799991 ], [ -74.720285610999952, -50.489353122999944 ], [ -74.783355272999927, -50.480645440999922 ] ] ], [ [ [ -75.040638800999943, -50.289483330999929 ], [ -75.22288977799991, -50.436455987999921 ], [ -75.323231574999909, -50.400323174999926 ], [ -75.194894985999952, -50.302504164999903 ], [ -75.454945441999939, -50.363946221999925 ], [ -75.390451626999948, -50.162286065999922 ], [ -75.26789303299995, -50.158623955999929 ], [ -75.352609829999949, -50.200778903999947 ], [ -75.179310675999943, -50.255791924999926 ], [ -75.11978105399993, -50.138767184999949 ], [ -75.187977667999917, -50.164157809999949 ], [ -75.304758266999897, -50.125095309999949 ], [ -75.400380011999914, -50.039157809999949 ], [ -75.296986456999946, -50.002862237999921 ], [ -75.271473761999914, -50.067071221999925 ], [ -75.157053188999953, -50.021416924999926 ], [ -75.052113410999937, -50.125176690999922 ], [ -74.953277147999927, -50.07976653399993 ], [ -75.071400519999941, -50.186455987999921 ], [ -74.799712693999936, -50.125420830999929 ], [ -74.811268683999913, -50.213799737999921 ], [ -74.942372199999909, -50.220147393999923 ], [ -75.040638800999943, -50.289483330999929 ] ] ], [ [ [ -75.448109503999945, -49.774997653999947 ], [ -75.617386955999905, -49.864222678999909 ], [ -75.634854258999951, -49.827943019999907 ], [ -75.626786262999929, -49.756342570999948 ], [ -75.510757276999925, -49.718222964999939 ], [ -75.613519646999919, -49.636375453999904 ], [ -75.504351867999901, -49.556973395999933 ], [ -75.355339445999903, -49.610176139999908 ], [ -75.211293097999942, -49.792738539999903 ], [ -75.180653449999909, -49.905368747999944 ], [ -75.262766079999949, -49.834567966999941 ], [ -75.270415818999936, -49.898044528999947 ], [ -75.339711066999939, -49.859551690999922 ], [ -75.366200324999909, -49.720310153999947 ], [ -75.448109503999945, -49.774997653999947 ] ] ], [ [ [ -75.521308187999921, -49.379099001999919 ], [ -75.429432675999919, -49.466365155999938 ], [ -75.440419541999916, -49.517810861999919 ], [ -75.54429919599994, -49.452866366999956 ], [ -75.501575445999947, -49.438411025999926 ], [ -75.547554101999935, -49.411311342999909 ], [ -75.521308187999921, -49.379099001999919 ] ] ], [ [ [ -74.903187628999945, -49.076755466999941 ], [ -74.935699022999927, -49.280450127999927 ], [ -75.057728644999941, -49.165459893999923 ], [ -75.201730923999946, -49.172295830999929 ], [ -75.11978105399993, -49.131280205999929 ], [ -75.235585089999915, -49.144952080999929 ], [ -75.15843665299991, -49.051039320999905 ], [ -75.098703579999949, -49.048760674999926 ], [ -75.126047329999949, -49.021416924999926 ], [ -74.903187628999945, -49.076755466999941 ] ] ], [ [ [ -75.557972785999937, -49.24732838299991 ], [ -75.661040818999936, -49.205743096999925 ], [ -75.337269660999937, -48.989353122999944 ], [ -75.373036261999914, -49.056247653999947 ], [ -75.28742428299995, -49.086602471999925 ], [ -75.315907355999911, -49.133477471999925 ], [ -75.403797980999911, -49.186618747999944 ], [ -75.415191209999932, -49.134942315999922 ], [ -75.493763800999943, -49.263441664999903 ], [ -75.557972785999937, -49.24732838299991 ] ] ], [ [ [ -75.215402798999946, -49.014580987999921 ], [ -75.228138800999943, -49.06609465899993 ], [ -75.27603105399993, -49.063246351999908 ], [ -75.316517706999946, -48.953708591999941 ], [ -75.373036261999914, -48.952569268999923 ], [ -75.499338344999899, -49.039157809999949 ], [ -75.533273891999897, -49.019463799999926 ], [ -75.468617316999939, -48.952569268999923 ], [ -75.597401495999918, -48.987725518999923 ], [ -75.654855923999946, -48.911065362999921 ], [ -75.614735480999911, -48.85865650799991 ], [ -75.468617316999939, -48.842705987999921 ], [ -75.511057094999899, -48.908623955999929 ], [ -75.394154425999943, -48.829034112999921 ], [ -75.421620245999918, -48.884209893999923 ], [ -75.359364386999914, -48.918389580999929 ], [ -75.379261847999942, -48.852227471999925 ], [ -75.305978969999899, -48.86492278399993 ], [ -75.215402798999946, -49.014580987999921 ] ] ], [ [ [ -75.105824347999942, -48.969903252999927 ], [ -75.223011847999942, -48.978936455999929 ], [ -75.235910610999952, -48.870700778999947 ], [ -75.308176235999952, -48.794854424999926 ], [ -75.091420050999943, -48.870700778999947 ], [ -75.090728318999936, -48.914483330999929 ], [ -75.139637824999909, -48.921807549999926 ], [ -75.064442511999914, -48.948337497999944 ], [ -75.105824347999942, -48.969903252999927 ] ] ], [ [ [ -75.198312954999949, -49.77117278399993 ], [ -75.297230597999942, -49.632989190999922 ], [ -75.235910610999952, -49.555840752999927 ], [ -75.317779100999928, -49.549004815999922 ], [ -75.256337042999917, -49.49382903399993 ], [ -75.335194464999915, -49.511163018999923 ], [ -75.325266079999949, -49.459649346999925 ], [ -75.423200333999944, -49.411058337999918 ], [ -75.461984829999949, -49.306573174999926 ], [ -75.383290167999917, -49.280450127999927 ], [ -75.166981574999909, -49.501153252999927 ], [ -75.323353644999941, -49.263604424999926 ], [ -75.259755011999914, -49.264092705999929 ], [ -75.152211066999939, -49.377699476999908 ], [ -75.09243730399993, -49.370293877999927 ], [ -75.187408006999931, -49.295179945999905 ], [ -75.111154751999948, -49.319431247999944 ], [ -75.112538214999915, -49.273207289999903 ], [ -75.037220831999946, -49.260430596999925 ], [ -75.09243730399993, -49.199639580999929 ], [ -74.89321855399993, -49.364027601999908 ], [ -74.88508053299995, -49.254571221999925 ], [ -74.844838019999941, -49.23992278399993 ], [ -74.859120245999918, -49.110772393999923 ], [ -74.804514126999948, -49.103936455999929 ], [ -74.954701300999943, -49.00709400799991 ], [ -74.856922980999911, -48.976495049999926 ], [ -74.818186001999948, -49.00709400799991 ], [ -74.823638475999928, -48.950372002999927 ], [ -74.96898352799991, -48.986586195999905 ], [ -74.954701300999943, -48.918389580999929 ], [ -75.015207485999952, -48.891778252999927 ], [ -74.872792120999918, -48.842705987999921 ], [ -75.011830206999946, -48.873223565999922 ], [ -75.057972785999937, -48.816664320999905 ], [ -74.94163977799991, -48.829034112999921 ], [ -75.009917772999927, -48.774346612999921 ], [ -74.83031165299991, -48.689548434999949 ], [ -74.794789191999939, -48.747247002999927 ], [ -74.783314581999946, -48.687758070999905 ], [ -74.696644660999937, -48.679864190999922 ], [ -74.680978969999899, -48.726657809999949 ], [ -74.622670050999943, -48.722832940999922 ], [ -74.667347785999937, -48.857028903999947 ], [ -74.634836391999897, -48.855238539999903 ], [ -74.616322394999941, -48.76336028399993 ], [ -74.543812628999945, -48.706149997999944 ], [ -74.530140753999945, -48.86687590899993 ], [ -74.563872850999928, -48.900974216999941 ], [ -74.475493943999936, -48.946384372999944 ], [ -74.530140753999945, -49.028252862999921 ], [ -74.461781378999945, -49.119317315999922 ], [ -74.445790167999917, -49.302341403999947 ], [ -74.539418097999942, -49.519301039999903 ], [ -74.503651495999918, -49.587497653999947 ], [ -74.605213995999918, -49.713555596999925 ], [ -74.508290167999917, -49.620293877999927 ], [ -74.430083787999934, -49.65789153399993 ], [ -74.423654751999948, -49.744886976999908 ], [ -74.536366339999915, -49.747002862999921 ], [ -74.434559699999909, -49.788669528999947 ], [ -74.454416469999899, -49.884860934999949 ], [ -74.475493943999936, -49.843194268999923 ], [ -74.523304816999939, -49.856866143999923 ], [ -74.474232550999943, -49.944512627999927 ], [ -74.612131313999953, -49.911553643999923 ], [ -74.536366339999915, -49.994724216999941 ], [ -74.67992102799991, -50.050225518999923 ], [ -74.673491990999935, -49.994724216999941 ], [ -74.768422003999945, -50.053317966999941 ], [ -74.804514126999948, -49.987237237999921 ], [ -74.831857876999948, -50.028903903999947 ], [ -74.856271938999953, -49.991306247999944 ], [ -74.739654100999928, -49.921807549999926 ], [ -74.66047115799995, -49.953057549999926 ], [ -74.680531378999945, -49.928399346999925 ], [ -74.73460852799991, -49.899102471999925 ], [ -74.881214972999942, -49.958916924999926 ], [ -74.913685675999943, -49.925876559999949 ], [ -74.891224738999938, -49.867852471999925 ], [ -74.72874915299991, -49.843194268999923 ], [ -74.838002081999946, -49.836358330999929 ], [ -74.77375240799995, -49.767510674999926 ], [ -74.882557745999918, -49.796970309999949 ], [ -74.865345831999946, -49.733982028999947 ], [ -74.920521613999938, -49.67937590899993 ], [ -74.844838019999941, -49.686211846999925 ], [ -74.891957160999937, -49.614434502999927 ], [ -74.708322719999899, -49.63836028399993 ], [ -74.766590949999909, -49.621026299999926 ], [ -74.756011522999927, -49.576348565999922 ], [ -74.864003058999913, -49.589450778999947 ], [ -74.88695227799991, -49.534600518999923 ], [ -74.782948370999918, -49.478692315999922 ], [ -74.743316209999932, -49.518731377999927 ], [ -74.752552863999938, -49.457696221999925 ], [ -74.66047115799995, -49.432305596999925 ], [ -74.735585089999915, -49.432305596999925 ], [ -74.646229620999918, -49.349786065999922 ], [ -74.746978318999936, -49.398044528999947 ], [ -74.811268683999913, -49.377699476999908 ], [ -74.748890753999945, -49.424899997999944 ], [ -74.944732225999928, -49.542168877999927 ], [ -74.987700975999928, -49.479261976999908 ], [ -75.002797003999945, -49.580173434999949 ], [ -75.044056769999941, -49.590020440999922 ], [ -75.010975714999915, -49.676039320999905 ], [ -74.952870245999918, -49.640883070999905 ], [ -75.022572394999941, -49.742120049999926 ], [ -74.961537238999938, -49.785251559999949 ], [ -75.043446417999917, -49.826348565999922 ], [ -75.009917772999927, -49.898532809999949 ], [ -75.133941209999932, -49.858330987999921 ], [ -75.198312954999949, -49.77117278399993 ] ] ], [ [ [ -75.085031704999949, -48.637302341999941 ], [ -75.060658331999946, -48.699395440999922 ], [ -75.109445766999897, -48.809177341999941 ], [ -75.246083136999914, -48.784763278999947 ], [ -75.085031704999949, -48.637302341999941 ] ] ], [ [ [ -75.023589647999927, -48.68873463299991 ], [ -74.975168423999946, -48.684991143999923 ], [ -75.009917772999927, -48.637302341999941 ], [ -74.824940558999913, -48.658379815999922 ], [ -74.988270636999914, -48.740492445999905 ], [ -75.044056769999941, -48.732842705999929 ], [ -75.023589647999927, -48.68873463299991 ] ] ], [ [ [ -73.037178985999901, -54.4564614169999 ], [ -72.972841243999937, -54.445011876999899 ], [ -72.9537844809999, -54.45685838299994 ], [ -72.989115445999914, -54.495697428999904 ], [ -73.09831420699993, -54.485808119999945 ], [ -73.037178985999901, -54.4564614169999 ] ] ], [ [ [ -70.402603411999905, -54.078632689999949 ], [ -70.313252632999934, -54.052750105999905 ], [ -70.298143286999903, -54.125952652999899 ], [ -70.405134176999923, -54.150441659999956 ], [ -70.513691449999953, -54.091285822999907 ], [ -70.402603411999905, -54.078632689999949 ] ] ], [ [ [ -70.686814366999897, -52.847389516999954 ], [ -70.619251986999927, -52.843384318999938 ], [ -70.725155177999909, -52.91360801299993 ], [ -70.789740348999942, -52.900540722999949 ], [ -70.686814366999897, -52.847389516999954 ] ] ], [ [ [ -74.427757414999917, -52.503661635999947 ], [ -74.39419819099993, -52.519902713999954 ], [ -74.349256660999913, -52.622980783999935 ], [ -74.481960304999916, -52.570765139999935 ], [ -74.427757414999917, -52.503661635999947 ] ] ], [ [ [ -74.476368398999909, -52.309666915999912 ], [ -74.488886782999941, -52.389906569999937 ], [ -74.45232240799993, -52.394783463999943 ], [ -74.482232513999918, -52.441658257999904 ], [ -74.536448527999937, -52.368736196999919 ], [ -74.476368398999909, -52.309666915999912 ] ] ], [ [ [ -73.815143293999938, -51.864058671999942 ], [ -73.718329605999941, -51.848860045999913 ], [ -73.713450735999913, -51.996006957999953 ], [ -73.767059469999936, -52.005296916999953 ], [ -73.979358161999926, -51.838543888999936 ], [ -73.900748790999899, -51.803603080999949 ], [ -73.815143293999938, -51.864058671999942 ] ] ], [ [ [ -74.359035942999924, -51.33794079799992 ], [ -74.296510172999945, -51.39538906599995 ], [ -74.306248931999903, -51.417783641999904 ], [ -74.396488010999917, -51.413082380999924 ], [ -74.412026427999933, -51.367044337999914 ], [ -74.359035942999924, -51.33794079799992 ] ] ], [ [ [ -74.970276692999903, -50.287516392999919 ], [ -74.889258390999942, -50.294923200999904 ], [ -74.976266336999913, -50.432887515999937 ], [ -75.044522301999905, -50.475994397999955 ], [ -75.171581489999937, -50.462150014999906 ], [ -74.970276692999903, -50.287516392999919 ] ] ], [ [ [ -74.42601477799991, -49.61492278399993 ], [ -74.468617316999939, -49.501153252999927 ], [ -74.427032029999907, -49.426527601999908 ], [ -74.287993943999936, -49.548435153999947 ], [ -74.42601477799991, -49.61492278399993 ] ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/colombia.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/colombia.geojson new file mode 100644 index 0000000000000..bfe3ae6a74eac --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/colombia.geojson @@ -0,0 +1,40 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "CO-NAR", "NAME_1": "Nariño" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -78.641267455999895, 1.259407450000069 ], [ -78.684288086999885, 1.281886698000079 ], [ -78.719479735999954, 1.341056214000062 ], [ -78.828684048999946, 1.43431224200009 ], [ -78.812855597999942, 1.441799221000053 ], [ -78.854481574999909, 1.490179755000042 ], [ -78.860707160999937, 1.558498440000051 ], [ -78.899599346999935, 1.545328417000064 ], [ -79.021511546999932, 1.638310358000069 ], [ -79.0087697539999, 1.664760146000049 ], [ -78.955839935999904, 1.692179301000067 ], [ -78.84605195599994, 1.82158548600006 ], [ -78.759447805999912, 1.830547266000053 ], [ -78.571230417999914, 1.782207066000069 ], [ -78.545399542999917, 1.914740302000041 ], [ -78.59136712399993, 1.896842641000092 ], [ -78.586333787999934, 2.000392971000053 ], [ -78.608021613999938, 2.02798086100006 ], [ -78.629017706999946, 2.025336005000042 ], [ -78.647474133999935, 1.980641280000043 ], [ -78.665605777999929, 1.982915292000087 ], [ -78.703158746999918, 2.189805173000082 ], [ -78.574086066999939, 2.433172919000071 ], [ -78.558990037999934, 2.449164130000042 ], [ -78.558990037999934, 2.381537177000041 ], [ -78.525045132999935, 2.495506662000082 ], [ -78.506457944999909, 2.490871279000089 ], [ -78.432215845999906, 2.587028252000039 ], [ -78.346018238999932, 2.647985921000043 ], [ -78.277503605999925, 2.542509370000062 ], [ -78.254750128999945, 2.541896877000056 ], [ -78.270076330999927, 2.634952070000054 ], [ -78.24693074399994, 2.663600774000088 ], [ -78.207753058999913, 2.537339585000041 ], [ -78.132476365999935, 2.492743231000077 ], [ -78.085275844999899, 2.516058661000045 ], [ -78.096104901999922, 2.651451390000091 ], [ -77.983921372373402, 2.586920565331809 ], [ -77.952729864791422, 2.555658271212224 ], [ -77.933351203195457, 2.477471829461365 ], [ -77.948750780224316, 2.381973781864531 ], [ -77.859428066851763, 2.237383124231769 ], [ -77.840126918722319, 2.177231756940046 ], [ -77.70274512408821, 2.142608547046791 ], [ -77.446326666742266, 2.221363430477936 ], [ -77.313027310362088, 2.171392320399264 ], [ -77.30132259795954, 2.154804184965144 ], [ -77.326385668263981, 2.062200019015677 ], [ -77.213963589348168, 1.986442369120027 ], [ -77.199261644309445, 1.961017564509007 ], [ -77.213679369407373, 1.926911119452598 ], [ -77.28339087628791, 1.855700994904964 ], [ -77.325067918649495, 1.689406235709214 ], [ -77.232980515738177, 1.663464667160667 ], [ -77.150866665364276, 1.686822415122322 ], [ -77.099371100995484, 1.667908839721179 ], [ -77.044671596616865, 1.704289048800547 ], [ -76.94090532062404, 1.727543443075433 ], [ -76.844812994723895, 1.607085679760303 ], [ -76.854088915271234, 1.55804474476912 ], [ -76.924472214820867, 1.502957668561521 ], [ -76.911708137020867, 1.313201809515874 ], [ -76.94204220218586, 1.287208564123944 ], [ -76.970102505126476, 1.29521841100086 ], [ -76.973280605815319, 1.247779446464278 ], [ -76.991005621911881, 1.225661932851892 ], [ -77.088699917367251, 1.186077786460658 ], [ -77.086710375083726, 1.073423163548171 ], [ -77.032140061914333, 1.041280422353623 ], [ -77.038212043351109, 0.996425279303196 ], [ -77.118775601013169, 0.835194810292251 ], [ -77.238561570759884, 0.697167060511447 ], [ -77.109137946159251, 0.584512436699583 ], [ -77.124615037553951, 0.540019028855113 ], [ -77.086245287090321, 0.390622463455941 ], [ -77.103856080293838, 0.354140948446002 ], [ -77.185180623999969, 0.335432841000028 ], [ -77.362534138999962, 0.374810283000031 ], [ -77.424390828999947, 0.408296610000107 ], [ -77.468057413999929, 0.650865784000118 ], [ -77.543349975999973, 0.656446838000136 ], [ -77.645565959999942, 0.7162881470001 ], [ -77.666804972999927, 0.747707418000047 ], [ -77.673316202999899, 0.819641012000076 ], [ -77.703185180999924, 0.843102112000054 ], [ -77.847982543999962, 0.809254048000057 ], [ -77.903224649999856, 0.832095032000069 ], [ -77.91826249199994, 0.874418030000072 ], [ -78.077942667999935, 0.900773011000126 ], [ -78.250154378999923, 1.019628804000121 ], [ -78.349218099999945, 1.05580230700005 ], [ -78.485204630999903, 1.192641500000121 ], [ -78.540601766999941, 1.205353902000084 ], [ -78.570057332999852, 1.19584543900001 ], [ -78.602148396999951, 1.263644918000111 ], [ -78.641267455999895, 1.259407450000069 ] ] ], [ [ [ -78.131418423999946, 2.62726471600007 ], [ -78.097279425999943, 2.572170315000051 ], [ -78.096180792999917, 2.540025132000039 ], [ -78.107289191999939, 2.512518622000073 ], [ -78.134429490999935, 2.504380601000094 ], [ -78.207020636999914, 2.575344143000052 ], [ -78.216420050999943, 2.596869208000044 ], [ -78.194965920999948, 2.632143556000074 ], [ -78.214867980999941, 2.681913849000068 ], [ -78.145085734999952, 2.673748199000045 ], [ -78.131418423999946, 2.62726471600007 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-PUT", "NAME_1": "Putumayo" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -76.177593546999901, 0.400131735000102 ], [ -76.243687703999854, 0.415427958000052 ], [ -76.290506551999869, 0.457182516000103 ], [ -76.311590535999898, 0.458526103000068 ], [ -76.365385701999912, 0.406953023000057 ], [ -76.416390339999879, 0.401888733000078 ], [ -76.408018757999912, 0.254507548000035 ], [ -76.565425171999976, 0.21606028300009 ], [ -76.626868448999886, 0.258538310000034 ], [ -76.724536905999912, 0.277555237000087 ], [ -76.736887573999866, 0.272904358000034 ], [ -76.734355427999873, 0.233113505000119 ], [ -76.797865763999937, 0.249960022000096 ], [ -76.882460082999927, 0.240141500000036 ], [ -76.945867065999948, 0.287063701000079 ], [ -77.04462072799987, 0.305667216000131 ], [ -77.103856080293838, 0.354140948446002 ], [ -77.084979214319276, 0.396771959258501 ], [ -77.124615037553951, 0.540019028855113 ], [ -77.112238531582932, 0.59427928276267 ], [ -77.238561570759884, 0.697167060511447 ], [ -77.118775601013169, 0.835194810292251 ], [ -77.028832770016322, 1.023193671051047 ], [ -77.032140061914333, 1.041280422353623 ], [ -77.086710375083726, 1.073423163548171 ], [ -77.088699917367251, 1.186077786460658 ], [ -76.976897956075788, 1.238012600401191 ], [ -76.970102505126476, 1.29521841100086 ], [ -76.94204220218586, 1.287208564123944 ], [ -76.911708137020867, 1.313201809515874 ], [ -76.772750210353934, 1.313976955871794 ], [ -76.722830777118645, 1.354646307880785 ], [ -76.670482551128828, 1.433711248775126 ], [ -76.638184781202654, 1.431902574544154 ], [ -76.588368699855607, 1.407459621864064 ], [ -76.520465868105305, 1.301522935535047 ], [ -76.546174892657177, 1.117606513030125 ], [ -76.5365889146467, 1.075593572984985 ], [ -76.492405565164688, 1.024588935031318 ], [ -76.351018845743113, 0.976943264020406 ], [ -76.209838832795867, 0.972137356253995 ], [ -76.148473069576482, 1.006863918035378 ], [ -76.086383836844561, 1.011411444282714 ], [ -76.06227678094865, 1.043244127114747 ], [ -75.949803026088773, 1.03482086818849 ], [ -75.917815313625795, 1.019162908741237 ], [ -75.899573533591706, 0.953843899376466 ], [ -75.828105028424318, 0.879481513461087 ], [ -75.732296921565649, 0.84811391772314 ], [ -75.600082769903906, 0.847442125054044 ], [ -75.55985266836592, 0.828580227395548 ], [ -75.498616096355761, 0.763571275493973 ], [ -75.459083625009271, 0.749463608758504 ], [ -75.31759355280019, 0.751323960732179 ], [ -75.27387529221096, 0.736286118909277 ], [ -75.212432013726414, 0.619497381798737 ], [ -75.21604936398694, 0.55190460931027 ], [ -75.186697149853558, 0.496197415478321 ], [ -75.164863857980663, 0.488445950120479 ], [ -75.095694952559995, 0.507462877409864 ], [ -75.072337206396924, 0.472943020304115 ], [ -74.996166143552671, 0.469945786768619 ], [ -74.989034796718499, 0.360908515015922 ], [ -74.962447272123882, 0.270836492809906 ], [ -74.855347866710645, 0.221898912404868 ], [ -74.742874111850767, 0.200298162730007 ], [ -74.682903611712277, 0.150947170275685 ], [ -74.676702439965595, 0.109864407116675 ], [ -74.695590176045755, 0.074621080498446 ], [ -74.658279791878897, 0.053847154022947 ], [ -74.684066331695817, 0.00630483579954 ], [ -74.663835007579507, -0.054156588955436 ], [ -74.609703945780439, -0.063561699812624 ], [ -74.592676560774635, -0.102060641485423 ], [ -74.558957689345846, -0.116633396214297 ], [ -74.469790004704919, -0.125780124653033 ], [ -74.429637416633454, -0.082992039151293 ], [ -74.4131784742072, -0.09027841561641 ], [ -74.399458381099407, -0.132291354762231 ], [ -74.327576463882679, -0.122834567960979 ], [ -74.282023687942853, -0.149396254133819 ], [ -74.251612108412075, -0.221433200981437 ], [ -74.19290768104463, -0.220451348151187 ], [ -74.168774786726999, -0.258330173099012 ], [ -74.116684943155576, -0.246341240755669 ], [ -73.989715948831986, -0.349539075967584 ], [ -73.864142219387929, -0.392947279093676 ], [ -74.414716937236847, -0.563756555820419 ], [ -74.422920288999933, -0.538312275999886 ], [ -74.562394978999947, -0.439403584999909 ], [ -74.64231258199996, -0.339771422999931 ], [ -74.686573445999869, -0.353414000999948 ], [ -74.718121907999944, -0.32726572699994 ], [ -74.790701456999869, -0.312589618999951 ], [ -74.755328938999952, -0.278276468999934 ], [ -74.824652872999906, -0.170479430999933 ], [ -74.872711954999943, -0.221949156999926 ], [ -74.933457601999862, -0.209443460999921 ], [ -75.015364745999904, -0.140507100999898 ], [ -75.050737263999935, -0.134305928999908 ], [ -75.101638549999848, -0.06909026999989 ], [ -75.14168778599992, -0.043458759999922 ], [ -75.222096313999884, -0.032400003999925 ], [ -75.240131388999885, -0.07477467799994 ], [ -75.283487914999881, -0.107020771999899 ], [ -75.464923868999875, -0.039738056999923 ], [ -75.626774454999946, 0.078911031000118 ], [ -75.731625935999915, 0.071159567000024 ], [ -75.789710245999913, 0.084388733000111 ], [ -75.951974243999899, 0.203967997000092 ], [ -76.053466756999882, 0.363544820000058 ], [ -76.119560913999919, 0.351762594000149 ], [ -76.136304077999881, 0.396721090000071 ], [ -76.177593546999901, 0.400131735000102 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-CHO", "NAME_1": "Chocó" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -77.46937330143669, 8.537811606220657 ], [ -77.429093384999931, 8.592629090000059 ], [ -77.434002644999879, 8.628259989000043 ], [ -77.374936483999932, 8.6509459440001 ], [ -77.366688605999911, 8.678412177000041 ], [ -77.298817511999914, 8.574286200000074 ], [ -77.274728969999899, 8.495794989000046 ], [ -77.144439256999931, 8.421087958000044 ], [ -77.052805141999897, 8.276312567000048 ], [ -76.985457524345236, 8.256179684045151 ], [ -76.960516527115999, 8.169553331521001 ], [ -76.959870571969304, 8.065218613847946 ], [ -77.003459642248686, 7.99940867806805 ], [ -77.02167558476043, 7.898484605080455 ], [ -77.093350796402092, 7.837144680282734 ], [ -77.120170864993383, 7.842389838520205 ], [ -77.113323737200687, 7.788387966131722 ], [ -77.126372035840745, 7.780920722513315 ], [ -76.980851203120494, 7.63917226788584 ], [ -76.876878220653339, 7.565404161173092 ], [ -76.692496711054332, 7.354435126080205 ], [ -76.646220465601971, 7.321310532954726 ], [ -76.59785132507858, 7.312241318881775 ], [ -76.542945116024271, 7.266998603103048 ], [ -76.508347743653417, 7.186305854231762 ], [ -76.505272996651456, 7.074426378574515 ], [ -76.546097378291336, 6.991020616108528 ], [ -76.68340165855966, 7.026031398730083 ], [ -76.816597663051709, 7.008332221055127 ], [ -76.835640427863439, 6.985982164345387 ], [ -76.802257453218886, 6.926786811462193 ], [ -76.797244838978145, 6.889321396765013 ], [ -76.811042447351042, 6.862630520282266 ], [ -76.836157192700284, 6.840590521935042 ], [ -76.883286098874351, 6.844621283345532 ], [ -76.972789680299513, 6.810204779027345 ], [ -76.966614346075175, 6.752378851702645 ], [ -76.948837653135172, 6.731966661332365 ], [ -76.969947476394907, 6.704655667225268 ], [ -76.944858567668746, 6.702175198526561 ], [ -76.932172004234587, 6.672357896399774 ], [ -76.905739509270916, 6.693648585913479 ], [ -76.901062791814354, 6.650033678111754 ], [ -76.866284553189587, 6.639801744055205 ], [ -76.896127691939398, 6.614531969075074 ], [ -76.893182136146663, 6.582156683883852 ], [ -76.866336229133651, 6.581769111155552 ], [ -76.852641975346899, 6.540169583159695 ], [ -76.788098111438671, 6.483454698075832 ], [ -76.8032909819932, 6.451492824933894 ], [ -76.784377408390696, 6.437772731826101 ], [ -76.805461392329391, 6.423484197937398 ], [ -76.788718228163702, 6.39570811583684 ], [ -76.798019986233385, 6.368862208823884 ], [ -76.784377408390696, 6.362661037976522 ], [ -76.798019986233385, 6.300597641867682 ], [ -76.770708991226968, 6.286929226502593 ], [ -76.713735724623973, 6.178382880265701 ], [ -76.673841518970903, 6.161717231365117 ], [ -76.349778612293107, 6.192206326160999 ], [ -76.258207974218635, 6.173964545227591 ], [ -76.216970181428735, 6.03477407546319 ], [ -76.188729011334772, 5.998471380749606 ], [ -76.111266039096392, 5.975578722579996 ], [ -76.105142380816233, 5.929974269796674 ], [ -76.135579799667994, 5.837240911738661 ], [ -76.087572395249822, 5.727764390414279 ], [ -76.097907681194499, 5.643428452860803 ], [ -76.042484707303402, 5.577334296240792 ], [ -76.080234341042001, 5.537595120218612 ], [ -76.093256802159658, 5.455377916157886 ], [ -76.165552131425727, 5.40866242113384 ], [ -76.18291541231639, 5.35194753694924 ], [ -76.179918178780895, 5.308720200976495 ], [ -76.097597621932721, 5.17503327096864 ], [ -76.075919358791339, 5.035713609095751 ], [ -76.141057501902196, 4.96998118678232 ], [ -76.169531215992833, 4.8894434684413 ], [ -76.298515591021669, 4.764076442773614 ], [ -76.316912400686704, 4.678965358864218 ], [ -76.427319098897271, 4.581736152301573 ], [ -76.450315110753763, 4.514324246067076 ], [ -76.44233110229851, 4.46644603105949 ], [ -76.455715297722804, 4.420686550443918 ], [ -76.547105068643987, 4.391670233994091 ], [ -76.495971238581774, 4.319969183930709 ], [ -76.49651384094102, 4.237571111817317 ], [ -76.454888475422763, 4.216228746359548 ], [ -76.443338792651161, 4.18829763372878 ], [ -76.473285285087798, 4.155870673492757 ], [ -76.520801764889541, 4.136957098990933 ], [ -76.574958666009593, 4.055799262126243 ], [ -76.654256150900608, 4.063318183487354 ], [ -76.743242966589605, 3.994640204481868 ], [ -76.892742885675602, 4.041898301865103 ], [ -76.956795824068024, 4.122591050736389 ], [ -76.987259081341506, 4.12398631381734 ], [ -77.018239101653194, 4.101558742741759 ], [ -77.065807258298321, 4.103884181809519 ], [ -77.155465867555733, 4.182871609237338 ], [ -77.221172451447444, 4.16806631141111 ], [ -77.244530199409155, 4.190855617692591 ], [ -77.254437965351315, 4.24218662549124 ], [ -77.236317511999914, 4.265326239000046 ], [ -77.336537238999938, 4.268744208000044 ], [ -77.387196417999917, 4.347235419000071 ], [ -77.358998175999943, 4.387193101000094 ], [ -77.345082160999937, 4.445542710000041 ], [ -77.31273352799991, 4.471380927000041 ], [ -77.333159959999932, 4.471380927000041 ], [ -77.318918423999946, 4.683661200000074 ], [ -77.298980272999927, 4.65570709800005 ], [ -77.291615363999938, 4.682074286000045 ], [ -77.318837042999917, 4.709662177000041 ], [ -77.325754360999952, 4.752508856000077 ], [ -77.28579667899993, 4.737005927000041 ], [ -77.25804602799991, 4.704087632000039 ], [ -77.318918423999946, 4.820868231000077 ], [ -77.339995897999927, 4.813381252000056 ], [ -77.348622199999909, 4.854193427000041 ], [ -77.372873501999948, 5.14915599200009 ], [ -77.346180792999917, 5.24477773600006 ], [ -77.360585089999915, 5.253485419000071 ], [ -77.380970831999946, 5.375067450000074 ], [ -77.408558722999942, 5.38617584800005 ], [ -77.408273891999897, 5.403021552000041 ], [ -77.380970831999946, 5.403021552000041 ], [ -77.408273891999897, 5.464504299000055 ], [ -77.462147589999915, 5.501044012000079 ], [ -77.501332160999937, 5.502427476000094 ], [ -77.510650193999936, 5.484930731000077 ], [ -77.559193488999938, 5.503078518000052 ], [ -77.526234503999945, 5.530178127000056 ], [ -77.490834113999938, 5.594794012000079 ], [ -77.404855923999946, 5.62836334800005 ], [ -77.355620897999927, 5.607896226000094 ], [ -77.333159959999932, 5.615301825000074 ], [ -77.318918423999946, 5.663031317000048 ], [ -77.261138475999928, 5.700913804000038 ], [ -77.245920376999948, 5.734198309000078 ], [ -77.246449347999942, 5.787339585000041 ], [ -77.31273352799991, 5.896429755000042 ], [ -77.353016730999911, 6.026190497000073 ], [ -77.366688605999911, 5.998928127000056 ], [ -77.484364386999914, 6.188788153000075 ], [ -77.483387824999909, 6.294338283000059 ], [ -77.415109829999949, 6.239081122000073 ], [ -77.380970831999946, 6.300523179000038 ], [ -77.377919074999909, 6.351792710000041 ], [ -77.399281378999945, 6.387640692000048 ], [ -77.373524542999917, 6.404201565000051 ], [ -77.360463019999941, 6.389878648000092 ], [ -77.359934048999946, 6.419175523000092 ], [ -77.380970831999946, 6.444525458000044 ], [ -77.347523566999939, 6.521551825000074 ], [ -77.345366990999935, 6.566107489000046 ], [ -77.415109829999949, 6.636297919000071 ], [ -77.411244269999941, 6.693793036000045 ], [ -77.462635870999918, 6.720689195000091 ], [ -77.505686001999948, 6.700140692000048 ], [ -77.510650193999936, 6.671087958000044 ], [ -77.537993943999936, 6.663641669000071 ], [ -77.531809048999946, 6.712062893000052 ], [ -77.593251105999911, 6.828111070000091 ], [ -77.671050584999932, 6.879706122000073 ], [ -77.696278449999909, 6.849188544000071 ], [ -77.692209438999953, 6.947251695000091 ], [ -77.652740037999934, 6.976629950000074 ], [ -77.665028449999909, 7.015570380000042 ], [ -77.696278449999909, 7.07453034100007 ], [ -77.688832160999937, 7.04718659100007 ], [ -77.895839150733224, 7.235098056585514 ], [ -77.820180623999903, 7.476547343000107 ], [ -77.755119994999916, 7.486107483000097 ], [ -77.731245483999942, 7.530342509000121 ], [ -77.765817016999932, 7.626460674000043 ], [ -77.764215047999897, 7.705732320000081 ], [ -77.740237182999891, 7.718858134000044 ], [ -77.679930786999904, 7.670954081000033 ], [ -77.674814819999909, 7.644650778000084 ], [ -77.625463826999891, 7.587444967000039 ], [ -77.613319865999898, 7.537473857000066 ], [ -77.57998856699993, 7.528378805000088 ], [ -77.509346883999939, 7.594111227000056 ], [ -77.339744832999969, 7.707230937000091 ], [ -77.379897420999953, 7.774410299000039 ], [ -77.300419067999968, 7.90210276300013 ], [ -77.163269815999911, 7.939258117000037 ], [ -77.201200317999906, 7.98199452700004 ], [ -77.231069294999941, 8.098731588000064 ], [ -77.316903849999875, 8.250841166000086 ], [ -77.374368042999976, 8.289314270000133 ], [ -77.391266235999865, 8.393545634000063 ], [ -77.422323770999895, 8.456410014000141 ], [ -77.488727986999947, 8.473644104000115 ], [ -77.46937330143669, 8.537811606220657 ] ] ], [ [ [ -77.435160502512787, 4.152847603334193 ], [ -77.426665818999936, 4.180365302000041 ], [ -77.377552863999938, 4.193589585000041 ], [ -77.360096808999913, 4.221136786000045 ], [ -77.313099738999938, 4.198879299000055 ], [ -77.285227053605013, 4.211282578561078 ], [ -77.298635422786504, 4.178763333461063 ], [ -77.350208503319777, 4.194679674427448 ], [ -77.394624395899143, 4.159668890906573 ], [ -77.435160502512787, 4.152847603334193 ] ] ], [ [ [ -77.353016730999911, 4.265326239000046 ], [ -77.27171790299991, 4.258490302000041 ], [ -77.30296790299991, 4.217596747000073 ], [ -77.333159959999932, 4.244818427000041 ], [ -77.381581183999913, 4.231634833000044 ], [ -77.466297980999911, 4.237372137000079 ], [ -77.504505988999938, 4.210638739000046 ], [ -77.549549933999913, 4.204779364000046 ], [ -77.544260219999899, 4.231634833000044 ], [ -77.499663865999935, 4.260972398000092 ], [ -77.435617641999897, 4.258490302000041 ], [ -77.462880011999914, 4.28579336100006 ], [ -77.428130662999934, 4.28579336100006 ], [ -77.452015753999945, 4.291693427000041 ], [ -77.415109829999949, 4.320502020000049 ], [ -77.435617641999897, 4.327337958000044 ], [ -77.428130662999934, 4.341009833000044 ], [ -77.386138475999928, 4.314642645000049 ], [ -77.353016730999911, 4.265326239000046 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-GUA", "NAME_1": "Guainía" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -67.065229858999913, 1.172694397000015 ], [ -67.086107136999971, 1.176001689000103 ], [ -67.098199421999965, 1.253361308000123 ], [ -67.07360144099988, 1.541199035000133 ], [ -67.117164673999923, 1.709793396000052 ], [ -67.155715291999883, 1.788083191000112 ], [ -67.264752563999906, 1.932544657000065 ], [ -67.340613565999917, 2.090106100000071 ], [ -67.381748005999896, 2.122739767000041 ], [ -67.439728962999965, 2.139560445000114 ], [ -67.592949585999889, 2.05481109600008 ], [ -67.820842651999925, 1.784000753000015 ], [ -67.928846394999965, 1.741290181000096 ], [ -67.998247842999916, 1.749971823000067 ], [ -68.031785848999931, 1.777515361000042 ], [ -68.111109171999971, 1.942414856000141 ], [ -68.177099975999909, 1.973188172000107 ], [ -68.192189493999905, 2.014891052000038 ], [ -68.280246134999942, 1.829398499000135 ], [ -68.248310098999951, 1.82211212100006 ], [ -68.238956664999904, 1.770280660000083 ], [ -68.193533081999874, 1.763743592000097 ], [ -68.188778849999977, 1.73583831800002 ], [ -68.163302367999876, 1.721291402000062 ], [ -69.352402913999953, 1.720206197000067 ], [ -69.541952066999869, 1.772709452000043 ], [ -69.649051472999957, 1.738938904000065 ], [ -69.729149942999925, 1.738990581000081 ], [ -69.841184587999862, 1.707579109000065 ], [ -70.050188972043429, 1.780976873783686 ], [ -70.163851284409247, 1.885363267400862 ], [ -70.119047818202262, 2.007061265065317 ], [ -70.103028124448372, 2.122248033519895 ], [ -69.994455938890439, 2.213353582701643 ], [ -70.037321539657341, 2.277432359515785 ], [ -70.062642992380177, 2.287405911153883 ], [ -70.189922045066339, 2.251852525273819 ], [ -70.237257656815416, 2.265598455904012 ], [ -70.284619106986213, 2.25826040349483 ], [ -70.304256151000573, 2.226427721562118 ], [ -70.407298956581542, 2.263324692780316 ], [ -70.492875129383719, 2.244772854383712 ], [ -70.50287451944348, 2.275882065904625 ], [ -70.590750291992379, 2.301358547359087 ], [ -70.622324592406017, 2.327610175169411 ], [ -70.676093919898449, 2.437887681271491 ], [ -70.747071498650712, 2.529044908195942 ], [ -70.899775356847215, 2.592503567385734 ], [ -70.908534511658388, 2.610797024263263 ], [ -70.499748093799496, 2.78453318955502 ], [ -70.359136521633161, 2.860807603388196 ], [ -70.333272468349719, 2.910003567110948 ], [ -70.281466843819771, 2.941965440252829 ], [ -70.276014980906609, 2.983694159457855 ], [ -70.291595425088758, 3.030254624851068 ], [ -70.265576341275107, 3.04508576109896 ], [ -70.263405930938973, 3.062914129983085 ], [ -70.308519457307113, 3.083946437977716 ], [ -70.202996182128118, 3.196213487262639 ], [ -70.163954637196753, 3.186291612467926 ], [ -70.159872198942821, 3.227710273310436 ], [ -70.144627652444171, 3.201949571015859 ], [ -70.129253912937713, 3.20427501098294 ], [ -70.141578742065292, 3.276441148140464 ], [ -70.116024746245046, 3.290161241248256 ], [ -70.151138881654049, 3.347883815785451 ], [ -70.119745449293021, 3.416639309156778 ], [ -70.068611620130127, 3.424623318511351 ], [ -70.054865688600614, 3.48451630338468 ], [ -70.082770961910342, 3.525495713756186 ], [ -70.010863207171269, 3.528596300079187 ], [ -69.962984992163626, 3.505006008120745 ], [ -69.926346401565183, 3.555907294186284 ], [ -69.89410030758313, 3.566449285705971 ], [ -69.866660122266808, 3.530611680784432 ], [ -69.849400194163593, 3.559007880509284 ], [ -69.722043627111702, 3.568619696042106 ], [ -69.658119879928506, 3.532472031858788 ], [ -69.648740606593719, 3.594690456699198 ], [ -69.611404384904404, 3.618823350117509 ], [ -69.612412075257055, 3.686338609139511 ], [ -69.474280971789426, 3.715742499216958 ], [ -69.430717739931765, 3.68608022672106 ], [ -69.346252611169064, 3.712771104103183 ], [ -69.301526659327862, 3.700136217512409 ], [ -69.279538336924702, 3.728919989066242 ], [ -69.251012945990681, 3.701221422230844 ], [ -69.191119961117295, 3.679879054974379 ], [ -69.183549363812062, 3.652102972873877 ], [ -69.140089483842587, 3.674530543949459 ], [ -69.105776333211224, 3.655823675921908 ], [ -69.108928596377609, 3.627892564190461 ], [ -69.090299241816524, 3.609366563316257 ], [ -69.040638190100367, 3.655203559196877 ], [ -68.962425909927788, 3.640940862830519 ], [ -68.937776251672688, 3.707345078712422 ], [ -68.907312995298469, 3.688560696319087 ], [ -68.848350186411949, 3.709825548310391 ], [ -68.827757127989059, 3.689361681096671 ], [ -68.804476895292453, 3.690136827452591 ], [ -68.810135463780625, 3.727989813978695 ], [ -68.744222175213224, 3.736206366430679 ], [ -68.739597133700727, 3.772534897767287 ], [ -68.68879920132207, 3.797804674546057 ], [ -68.643168911016403, 3.781836655836969 ], [ -68.579606899938483, 3.80806244522563 ], [ -68.546353114704459, 3.795944322572439 ], [ -68.504882778817205, 3.84452016777152 ], [ -68.438452725412958, 3.873071397127262 ], [ -68.444938117100435, 3.912629705996096 ], [ -68.37253943504686, 3.923585110464444 ], [ -68.351377935843061, 3.968491930358311 ], [ -68.368431159270585, 3.994898586000943 ], [ -68.355537889362097, 4.019858303517879 ], [ -68.26789465991061, 4.00272756572457 ], [ -68.252365891672525, 3.94322215447886 ], [ -68.18810624860447, 3.973168646915497 ], [ -68.183481207991349, 3.922112332118445 ], [ -68.156583625034273, 3.927693386240776 ], [ -68.092737393116181, 4.00544057931927 ], [ -68.048709073265115, 3.955934556334682 ], [ -68.013414068904126, 3.998464260317348 ], [ -67.999125535914743, 3.936375026686108 ], [ -67.950704719447231, 3.957484849046523 ], [ -67.876962450256883, 3.922732448843419 ], [ -67.838489346106428, 3.924282742454579 ], [ -67.797096523685582, 3.953764145998548 ], [ -67.749114955890491, 4.021563625860608 ], [ -67.716932481999919, 4.039878247000033 ], [ -67.693873657999916, 3.928598531000105 ], [ -67.644419311999883, 3.834624939000079 ], [ -67.631758585999933, 3.761864523000014 ], [ -67.594809936999894, 3.730910340000094 ], [ -67.537449096999921, 3.735509542000045 ], [ -67.499828654999902, 3.717913717000059 ], [ -67.471406616999872, 3.680060730000079 ], [ -67.403917195999924, 3.504464213000063 ], [ -67.304646768999959, 3.425709331000064 ], [ -67.309452677999872, 3.383928935000114 ], [ -67.395803995999927, 3.266571757000037 ], [ -67.452182983999933, 3.243679098000101 ], [ -67.838619344999927, 2.886129863000065 ], [ -67.85525915499997, 2.858172913000061 ], [ -67.855930948999941, 2.789753316000073 ], [ -67.823323120999902, 2.827322083000084 ], [ -67.751027790999842, 2.842101542000094 ], [ -67.690411336999972, 2.80634145100008 ], [ -67.62659094299994, 2.813421122000108 ], [ -67.594293172999954, 2.776110738000071 ], [ -67.57558630399987, 2.691103007000066 ], [ -67.500293741999911, 2.675341695000085 ], [ -67.470889852999932, 2.627127584000092 ], [ -67.340613565999917, 2.510493876000098 ], [ -67.325420694999906, 2.474630432000055 ], [ -67.189718383999917, 2.394376933000046 ], [ -67.173750365999894, 2.336447652000103 ], [ -67.217675333999921, 2.284512838000097 ], [ -67.217261921999921, 2.266064351000082 ], [ -67.177832804999895, 2.15449493400007 ], [ -67.11463252799993, 2.102999370000077 ], [ -67.111170206999901, 2.048842469000064 ], [ -67.132615925999914, 1.990809835000093 ], [ -67.066831827999948, 1.894123230000034 ], [ -66.980893920999904, 1.66594594300004 ], [ -66.97417598499996, 1.580033875000083 ], [ -66.933609985999851, 1.501692403000092 ], [ -66.932731485999909, 1.424642843000072 ], [ -66.883535521999931, 1.349944560000068 ], [ -66.900898803999951, 1.288966370000097 ], [ -66.87506058799994, 1.222510478000046 ], [ -67.065229858999913, 1.172694397000015 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-VAU", "NAME_1": "Vaupés" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.841184587999862, 1.707579109000065 ], [ -69.856170613999922, 1.707674663000063 ], [ -69.852191528999953, 1.05941965700012 ], [ -69.749665486999902, 1.090528870000085 ], [ -69.716024128999948, 1.058592835000098 ], [ -69.619905965999919, 1.072752177000055 ], [ -69.54295975699992, 1.055595601000093 ], [ -69.478260864999953, 1.060659892000075 ], [ -69.418161172999902, 1.02862050400006 ], [ -69.370851399999964, 1.062985332000011 ], [ -69.338786173999949, 1.064122213000104 ], [ -69.232849487999971, 0.988364563000033 ], [ -69.226183227999854, 0.957203675000059 ], [ -69.204324096999926, 0.943664449000082 ], [ -69.209982665999945, 0.907542623000069 ], [ -69.152389282999906, 0.867803446000067 ], [ -69.17538529499987, 0.844445699000119 ], [ -69.167763021999889, 0.756027323000097 ], [ -69.192257649999931, 0.728948873000135 ], [ -69.141201334999948, 0.668177388000032 ], [ -69.143655965999926, 0.637533265000101 ], [ -69.162336995999908, 0.631435445000051 ], [ -69.200603393999899, 0.639496969000035 ], [ -69.226183227999854, 0.614795634000117 ], [ -69.297057454999901, 0.618102925000116 ], [ -69.302147583999982, 0.656550191000065 ], [ -69.362557331999909, 0.640943909000029 ], [ -69.439710245999976, 0.715771382000057 ], [ -69.478079996999895, 0.732824606000094 ], [ -69.594119425999935, 0.689313049000077 ], [ -69.619156656999934, 0.650659078000075 ], [ -69.694681762999949, 0.668745829000088 ], [ -69.805321004999911, 0.60694081600009 ], [ -70.039415242999922, 0.574591369000103 ], [ -70.054246378999949, 0.588130595000081 ], [ -70.068043985999907, -0.160144144999933 ], [ -69.933633585999871, -0.314346618999934 ], [ -69.85810848099996, -0.341425068999897 ], [ -69.834776570999907, -0.383179625999929 ], [ -69.746461547999928, -0.453046162999911 ], [ -69.649516560999871, -0.492010192999899 ], [ -69.619750935999889, -0.52456634499994 ], [ -69.584223388999931, -0.644559020999864 ], [ -69.628380900999929, -0.733442483999909 ], [ -69.57272538299992, -0.813540954999965 ], [ -69.573242147999849, -0.849197691999947 ], [ -69.53732702699989, -0.889505309999905 ], [ -69.532598632999907, -0.934050394999915 ], [ -69.442862508999923, -1.008361103999988 ], [ -69.448159342999958, -1.092076924999944 ], [ -69.399454304999921, -1.182717386999883 ], [ -69.421065071999919, -1.239310156999906 ], [ -69.465315111403243, -1.180031020015576 ], [ -69.564456345883627, -1.137449639189526 ], [ -69.650600958567395, -1.160497327889402 ], [ -69.649102341799619, -1.055490817547195 ], [ -69.716436733668331, -0.995132744680404 ], [ -69.746925829363533, -0.997251479072531 ], [ -69.774159309104846, -1.043811943566368 ], [ -69.864567227195778, -1.026086927469748 ], [ -69.93148820701515, -1.05502572955379 ], [ -69.947352871138094, -1.029187513792749 ], [ -69.902781948927782, -0.91606780378612 ], [ -69.971149867772169, -0.93570484780048 ], [ -70.001509772258146, -0.920563653190072 ], [ -70.033936734292865, -0.946866956944518 ], [ -70.071143764772899, -0.933534437464346 ], [ -70.099850022860267, -0.942371107540566 ], [ -70.124112108387067, -0.974410495947666 ], [ -70.07235816070056, -1.044122002828203 ], [ -70.098635626932605, -1.073422540118145 ], [ -70.138374802954786, -1.071355482569459 ], [ -70.196019864025516, -1.023089694833573 ], [ -70.185968797122257, -0.956117039070079 ], [ -70.242192755791052, -0.988001396946913 ], [ -70.279735683954641, -0.933689467095235 ], [ -70.212711351347764, -0.852402439021375 ], [ -70.264181078194213, -0.788065280688159 ], [ -70.273069424214555, -0.75204680681469 ], [ -70.23464799690754, -0.720162448937856 ], [ -70.244466518914692, -0.564099622899278 ], [ -70.260253668671851, -0.550560397844094 ], [ -70.303713547742007, -0.556709892747335 ], [ -70.305031297356493, -0.534230644828426 ], [ -70.221392991793152, -0.446897474638774 ], [ -70.21612199603328, -0.423436374788878 ], [ -70.280381639101336, -0.404781181806129 ], [ -70.329551765301744, -0.43387501352106 ], [ -70.334383510590555, -0.471805515312269 ], [ -70.448330043796489, -0.465552666722203 ], [ -70.457140876350365, -0.407416681034988 ], [ -70.500859137838916, -0.359564303549803 ], [ -70.567418381553068, -0.359719334080012 ], [ -70.6158391989199, -0.321065361876947 ], [ -70.661030239653826, -0.324424329719079 ], [ -70.740922003747471, -0.279259128306137 ], [ -70.76053321023943, -0.280602715442967 ], [ -70.787224086722233, -0.321943861020372 ], [ -70.847323778069892, -0.321323744295398 ], [ -70.90062801756892, -0.193682957302656 ], [ -70.939049444875991, -0.145727227029909 ], [ -70.934501918628655, -0.07100310590863 ], [ -70.984111294400691, 0.000930487252162 ], [ -71.041988897669455, -0.002531834276738 ], [ -71.1400449292301, 0.037672431537487 ], [ -71.173867154345658, 0.115807196444962 ], [ -71.268383348212922, 0.098340561867417 ], [ -71.352822638553903, 0.162471015524943 ], [ -71.421423102294341, 0.191616523183995 ], [ -71.538547736189059, 0.177663886079472 ], [ -71.688977831261866, 0.258279119685596 ], [ -71.787085536967936, 0.373310859408605 ], [ -71.847004361162305, 0.355534166468601 ], [ -71.84302527479656, 0.417235826472222 ], [ -71.936404588001324, 0.486688950934308 ], [ -71.932787237740797, 0.555211900308962 ], [ -71.96084754068147, 0.580326646557467 ], [ -71.979115160036599, 0.564513658378644 ], [ -71.995083176947048, 0.576295885146976 ], [ -72.008596563580511, 0.63339834205982 ], [ -72.035752529855358, 0.664042467385968 ], [ -71.786542934608747, 0.916946926359572 ], [ -71.756699794959559, 0.971310533054634 ], [ -71.724660406552516, 0.986606757295988 ], [ -71.673113166239602, 0.981955878261147 ], [ -71.609861212624878, 1.042520656702948 ], [ -71.552913784443604, 1.160963040212152 ], [ -71.527824876616762, 1.116521308311746 ], [ -71.505061407857681, 1.115126044331475 ], [ -71.553120490018614, 1.216463528469035 ], [ -71.552448697349519, 1.262042141031998 ], [ -71.441008470364579, 1.548019517186958 ], [ -71.405248378909562, 1.598662420834046 ], [ -71.390778977867512, 1.732245998953658 ], [ -71.263758307599801, 1.673386541955324 ], [ -71.15983700197603, 1.756223862741081 ], [ -70.967729865440901, 1.853272203049698 ], [ -70.904529587770242, 1.918591213313846 ], [ -70.65534583184467, 1.904276841902742 ], [ -70.499257168283691, 1.951819159226829 ], [ -70.444454312016887, 1.988354397037767 ], [ -70.201652594991231, 2.031245836226333 ], [ -70.104965989888512, 2.1011640495812 ], [ -70.119047818202262, 2.007061265065317 ], [ -70.161990933334891, 1.902313137141562 ], [ -70.15656490704481, 1.869343572747653 ], [ -69.999933641124642, 1.754983629291075 ], [ -69.841184587999862, 1.707579109000065 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-AMA", "NAME_1": "Amazonas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.421065071999919, -1.239310156999906 ], [ -69.433948323999914, -1.42218597399993 ], [ -69.947198648999859, -4.201137796999902 ], [ -69.964949503999975, -4.236484476999905 ], [ -70.030501058999903, -4.131581318999906 ], [ -70.188398396999901, -4.028951923999912 ], [ -70.216975463999859, -3.924978942999957 ], [ -70.311104084999926, -3.829274189999865 ], [ -70.377689168999922, -3.818835550999921 ], [ -70.438512328999934, -3.867721455999913 ], [ -70.490886393999887, -3.878470153999928 ], [ -70.5442939859999, -3.865240986999936 ], [ -70.690641642999964, -3.78679616299992 ], [ -70.734127359999974, -3.782041930999924 ], [ -70.050629027999946, -2.715130309999935 ], [ -70.075795450999891, -2.691359150999887 ], [ -70.094967406999899, -2.632551370999906 ], [ -70.105793619999957, -2.625213316999904 ], [ -70.150467895999981, -2.66924163799996 ], [ -70.183876709999964, -2.619528910999875 ], [ -70.236069905999841, -2.625109964999879 ], [ -70.273948730999933, -2.546251728999948 ], [ -70.295885376999905, -2.535399678999909 ], [ -70.364615030999886, -2.557620543999946 ], [ -70.376345580999953, -2.532609150999946 ], [ -70.349628865999904, -2.518346455999961 ], [ -70.357535360999947, -2.486927184999928 ], [ -70.445256103999981, -2.498502705999968 ], [ -70.48445267799994, -2.452510680999893 ], [ -70.57860713799991, -2.40548512799991 ], [ -70.59607377099988, -2.416543883999907 ], [ -70.598631754999957, -2.446619567999974 ], [ -70.647595174999964, -2.450753682999903 ], [ -70.663718221999943, -2.398250426999937 ], [ -70.69903906299993, -2.370138447999906 ], [ -70.706583821999885, -2.32828053799993 ], [ -70.787870849999877, -2.307403258999955 ], [ -70.90455623399987, -2.211078388999894 ], [ -70.925252644999915, -2.220276794999975 ], [ -71.021448323999948, -2.196712340999881 ], [ -71.029690714999873, -2.263995055999956 ], [ -71.119969441999899, -2.252109476999934 ], [ -71.142810424999908, -2.262858174999863 ], [ -71.161930705999907, -2.310193785999914 ], [ -71.209059611999919, -2.339235940999913 ], [ -71.253346313999941, -2.326626891999879 ], [ -71.307606567999898, -2.347814228999937 ], [ -71.315461384999935, -2.334068297999906 ], [ -71.420829630999947, -2.3760295619999 ], [ -71.432146768999928, -2.355152281999935 ], [ -71.41163122599994, -2.326626891999879 ], [ -71.456486368999947, -2.255106708999946 ], [ -71.480567586999882, -2.265752054999936 ], [ -71.498137572999951, -2.315051370999939 ], [ -71.52097855599996, -2.292107034999901 ], [ -71.538393513999893, -2.22296396899992 ], [ -71.67853999899998, -2.169530536999986 ], [ -71.731404988999941, -2.189891051999922 ], [ -71.746132772999943, -2.132323506999896 ], [ -71.836204793999912, -2.179762470999975 ], [ -71.948652709999863, -2.324146423999906 ], [ -72.061514038999917, -2.320012307999974 ], [ -72.176390746999942, -2.410342711999931 ], [ -72.250959839999894, -2.396286721999914 ], [ -72.281862344999894, -2.405691832999963 ], [ -72.283826049999931, -2.433183694999926 ], [ -72.378032186999917, -2.450753682999903 ], [ -72.414257364999884, -2.437111103999896 ], [ -72.441594197999905, -2.405175068999924 ], [ -72.562982137999882, -2.383057555999912 ], [ -72.6443208419999, -2.334068297999906 ], [ -72.683181518999845, -2.404761657999913 ], [ -72.712430378999898, -2.422124938999929 ], [ -72.733721069999973, -2.367554626999905 ], [ -72.761678019999863, -2.402281187999932 ], [ -72.804672810999961, -2.377786559999976 ], [ -72.935414184999871, -2.425328877999988 ], [ -72.987555705999938, -2.337685648999894 ], [ -73.05644038899996, -2.299858499999914 ], [ -73.083828898999911, -2.345127054999907 ], [ -73.098866739999977, -2.31494801799991 ], [ -73.158914754999898, -2.293037210999955 ], [ -73.197775431999872, -2.213558857999956 ], [ -73.195294962999895, -2.187203877999906 ], [ -73.14992305499996, -2.14358896899995 ], [ -73.1110623779999, -2.073412373999886 ], [ -73.168733276999973, -1.959310810999881 ], [ -73.158914754999898, -1.895232034999964 ], [ -73.193641317999948, -1.836837666999898 ], [ -73.193021199999862, -1.788675231999918 ], [ -73.257255005999923, -1.742373147999928 ], [ -73.267693643999877, -1.772242125999952 ], [ -73.316579549999943, -1.765420836999894 ], [ -73.350530965999951, -1.790638935999951 ], [ -73.387066202999904, -1.760873311999958 ], [ -73.440086221999906, -1.758702900999964 ], [ -73.446287394999899, -1.738135680999974 ], [ -73.510934611999943, -1.698551533999932 ], [ -73.530985066999904, -1.673746845999887 ], [ -73.528814656999913, -1.635092874999884 ], [ -73.508815876999876, -1.586827086999961 ], [ -73.484527953999873, -1.572461038999961 ], [ -73.497162841999909, -1.477996520999909 ], [ -73.574212402999933, -1.416914977999909 ], [ -73.583436645999939, -1.401722106999969 ], [ -73.562921102999979, -1.372163186999941 ], [ -73.588966023999944, -1.350252379999901 ], [ -73.597130899999883, -1.306120706999906 ], [ -73.618214884999901, -1.306120706999906 ], [ -73.636560017999898, -1.255167744999952 ], [ -73.732368123999919, -1.216513772999861 ], [ -73.754718180999902, -1.183337503999937 ], [ -73.802544718999883, -1.22364512099989 ], [ -73.857166707999909, -1.210519306999927 ], [ -73.91990189699996, -1.113781025999941 ], [ -73.981293497999843, -1.107476501999926 ], [ -73.982792113999949, -1.066238707999929 ], [ -74.016795206999888, -1.091560159999901 ], [ -74.037207397999936, -1.079674580999963 ], [ -74.076894897999921, -0.990894469999944 ], [ -74.092371988999929, -1.0201433309999 ], [ -74.119631306999935, -1.020970153999926 ], [ -74.266754109999908, -0.972290954999906 ], [ -74.303392699999876, -0.897773538999942 ], [ -74.344423787999915, -0.858602802999911 ], [ -74.28913000599988, -0.836278584999945 ], [ -74.310601562999921, -0.801448668999882 ], [ -74.30279842199991, -0.78542897599992 ], [ -74.344320434999901, -0.774060159999934 ], [ -74.385144815999894, -0.721970315999982 ], [ -74.364887654999876, -0.676184996999936 ], [ -74.414716937236847, -0.563756555820419 ], [ -73.864142219387929, -0.392947279093676 ], [ -73.770091111715431, -0.406899916198199 ], [ -73.713660448371002, -0.386694430503553 ], [ -73.64942664282529, -0.416666762261286 ], [ -73.644026454956929, -0.454235527947276 ], [ -73.595838181586771, -0.462038669249182 ], [ -73.554212816068571, -0.520639743829122 ], [ -73.388977424068855, -0.531336764979756 ], [ -73.331771612569867, -0.507307223449629 ], [ -73.205500251135675, -0.604717298964204 ], [ -73.16532182464249, -0.608386326068114 ], [ -73.081295946350849, -0.593555189820165 ], [ -72.997425095891458, -0.526582533157409 ], [ -72.884822149822355, -0.601720065428708 ], [ -72.749894986364495, -0.559242039188746 ], [ -72.590447354062121, -0.67303354186447 ], [ -72.549752162732091, -0.683265475920962 ], [ -72.478412848773928, -0.59402027781357 ], [ -72.421852993320954, -0.556554864015766 ], [ -72.324520433071541, -0.629263603532479 ], [ -72.279820318752684, -0.621253756655562 ], [ -72.24238074427592, -0.586940606024143 ], [ -72.232381354216102, -0.467309665908374 ], [ -72.128640916644997, -0.326336357636819 ], [ -72.036863572995458, -0.259622084291777 ], [ -71.981388923160239, -0.244480888781993 ], [ -71.845040656401181, -0.245876152762264 ], [ -71.774192267958767, -0.224688816036064 ], [ -71.689055344728388, -0.085679212525633 ], [ -71.389719610671477, 0.067489731865635 ], [ -71.32233354375802, 0.133222154179066 ], [ -71.251666021569633, 0.096015122799656 ], [ -71.173867154345658, 0.115807196444962 ], [ -71.1400449292301, 0.037672431537487 ], [ -71.041988897669455, -0.002531834276738 ], [ -70.996565313838175, 0.008733629453445 ], [ -70.971528082854718, -0.012815444277351 ], [ -70.930109422012208, -0.086867770930894 ], [ -70.939049444875991, -0.145727227029909 ], [ -70.90062801756892, -0.193682957302656 ], [ -70.847323778069892, -0.321323744295398 ], [ -70.787224086722233, -0.321943861020372 ], [ -70.76053321023943, -0.280602715442967 ], [ -70.740922003747471, -0.279259128306137 ], [ -70.661030239653826, -0.324424329719079 ], [ -70.6158391989199, -0.321065361876947 ], [ -70.567418381553068, -0.359719334080012 ], [ -70.500859137838916, -0.359564303549803 ], [ -70.457140876350365, -0.407416681034988 ], [ -70.448330043796489, -0.465552666722203 ], [ -70.334383510590555, -0.471805515312269 ], [ -70.329551765301744, -0.43387501352106 ], [ -70.280381639101336, -0.404781181806129 ], [ -70.21612199603328, -0.423436374788878 ], [ -70.221392991793152, -0.446897474638774 ], [ -70.305031297356493, -0.534230644828426 ], [ -70.303713547742007, -0.556709892747335 ], [ -70.260253668671851, -0.550560397844094 ], [ -70.244466518914692, -0.564099622899278 ], [ -70.23464799690754, -0.720162448937856 ], [ -70.273069424214555, -0.75204680681469 ], [ -70.264181078194213, -0.788065280688159 ], [ -70.212711351347764, -0.852402439021375 ], [ -70.279735683954641, -0.933689467095235 ], [ -70.242192755791052, -0.988001396946913 ], [ -70.185968797122257, -0.956117039070079 ], [ -70.196019864025516, -1.023089694833573 ], [ -70.138374802954786, -1.071355482569459 ], [ -70.098635626932605, -1.073422540118145 ], [ -70.07235816070056, -1.044122002828203 ], [ -70.124112108387067, -0.974410495947666 ], [ -70.099850022860267, -0.942371107540566 ], [ -70.071143764772899, -0.933534437464346 ], [ -70.033936734292865, -0.946866956944518 ], [ -70.001509772258146, -0.920563653190072 ], [ -69.971149867772169, -0.93570484780048 ], [ -69.902781948927782, -0.91606780378612 ], [ -69.947352871138094, -1.029187513792749 ], [ -69.93148820701515, -1.05502572955379 ], [ -69.864567227195778, -1.026086927469748 ], [ -69.774159309104846, -1.043811943566368 ], [ -69.746925829363533, -0.997251479072531 ], [ -69.716436733668331, -0.995132744680404 ], [ -69.649102341799619, -1.055490817547195 ], [ -69.650600958567395, -1.160497327889402 ], [ -69.564456345883627, -1.137449639189526 ], [ -69.465315111403243, -1.180031020015576 ], [ -69.421065071999919, -1.239310156999906 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-LAG", "NAME_1": "La Guajira" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.327506533469858, 11.849997690578633 ], [ -71.357629353999897, 11.850802307000023 ], [ -71.449458373999931, 11.795456848000086 ], [ -71.990613973999871, 11.649057516000099 ], [ -72.267082885999884, 11.154901632000048 ], [ -72.341341918999944, 11.162110494000103 ], [ -72.49931677299989, 11.12079518700007 ], [ -72.576469685999939, 10.957368469000073 ], [ -72.682974812999902, 10.855617575000025 ], [ -72.754391641999888, 10.674853414000012 ], [ -72.843016723999966, 10.560596822000065 ], [ -72.915232105177495, 10.428171729841438 ], [ -73.012592128923586, 10.400864163050699 ], [ -73.077652756769282, 10.415126858517681 ], [ -73.139586961668954, 10.404429836467784 ], [ -73.151472541224791, 10.436701767972181 ], [ -73.181341519295643, 10.456571356882591 ], [ -73.125117560626904, 10.527238878171659 ], [ -73.075198127391673, 10.630049139755954 ], [ -73.123541428594024, 10.678469957122786 ], [ -73.249916143715041, 10.7338670916929 ], [ -73.254515346805817, 10.810141506425396 ], [ -73.284952765657579, 10.852490343254715 ], [ -73.452151862418475, 10.866313788250693 ], [ -73.605785894803205, 10.845514024252793 ], [ -73.650150113237146, 11.009767564321635 ], [ -73.637773607266126, 11.139165351399811 ], [ -73.581808031015782, 11.191461900546244 ], [ -73.565581834999932, 11.277085679000038 ], [ -73.292388475999928, 11.294012762000079 ], [ -73.054839647999927, 11.493963934000078 ], [ -72.933990037999934, 11.556789455000057 ], [ -72.741322394999941, 11.707953192000048 ], [ -72.511626756999931, 11.789252020000049 ], [ -72.433461066999939, 11.796087958000044 ], [ -72.263050910999937, 11.885972398000092 ], [ -72.232167120999918, 11.919745184000078 ], [ -72.138661261999914, 12.104559637000079 ], [ -72.145415818999936, 12.200832424000055 ], [ -72.170521613999938, 12.234279690000051 ], [ -72.138661261999914, 12.256048895000049 ], [ -72.107533331999946, 12.245021877000056 ], [ -72.004872199999909, 12.262884833000044 ], [ -71.969634568999936, 12.255113023000092 ], [ -72.015126105999911, 12.19399648600006 ], [ -71.967274542999917, 12.153021552000041 ], [ -71.937611456999946, 12.166449286000045 ], [ -71.914418097999942, 12.202785549000055 ], [ -71.868031378999945, 12.208238023000092 ], [ -71.871083136999914, 12.256048895000049 ], [ -71.905262824999909, 12.282700914000088 ], [ -71.946848110999952, 12.269029039000088 ], [ -71.960519985999952, 12.282700914000088 ], [ -71.871245897999927, 12.362616278000075 ], [ -71.829090949999909, 12.376206773000092 ], [ -71.809071417999917, 12.372137762000079 ], [ -71.843129035999937, 12.338080145000049 ], [ -71.822865363999938, 12.319810289000088 ], [ -71.802845831999946, 12.32367584800005 ], [ -71.803212042999917, 12.335882880000042 ], [ -71.751088019999941, 12.35618724200009 ], [ -71.740793423999946, 12.385728257000039 ], [ -71.751820441999939, 12.390814520000049 ], [ -71.732533331999946, 12.410223700000074 ], [ -71.713449673999946, 12.413723049000055 ], [ -71.719838019999941, 12.395982164000088 ], [ -71.69359290299991, 12.365301825000074 ], [ -71.69163977799991, 12.393377997000073 ], [ -71.630930141999897, 12.427394924000055 ], [ -71.679107225999928, 12.416978257000039 ], [ -71.658802863999938, 12.440375067000048 ], [ -71.69359290299991, 12.427394924000055 ], [ -71.686146613999938, 12.454657294000071 ], [ -71.734527147999927, 12.413723049000055 ], [ -71.730539516999897, 12.438055731000077 ], [ -71.697255011999914, 12.46430084800005 ], [ -71.511301235999952, 12.443264065000051 ], [ -71.439076300999943, 12.396185614000046 ], [ -71.29515540299991, 12.358465887000079 ], [ -71.227162238999938, 12.30540599200009 ], [ -71.107492641999897, 12.07493724200009 ], [ -71.138091600999928, 12.015814520000049 ], [ -71.298817511999914, 11.92023346600007 ], [ -71.327506533469858, 11.849997690578633 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-CES", "NAME_1": "Cesar" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -72.915232105177495, 10.428171729841438 ], [ -72.935620890999928, 10.175193991000057 ], [ -72.987710733999876, 9.999416606000082 ], [ -72.996960814999909, 9.900714620000073 ], [ -72.977633829999945, 9.838056946000052 ], [ -72.985540323999885, 9.81216705300011 ], [ -73.107651733999973, 9.577995301000087 ], [ -73.178448445999919, 9.523037415000147 ], [ -73.324382690999954, 9.255921936000078 ], [ -73.390838582999919, 9.194504496000093 ], [ -73.391148640999916, 9.172774556000078 ], [ -73.363644981999926, 9.165032761000077 ], [ -73.417011887688432, 9.150707912839891 ], [ -73.436597255758727, 9.116343085365088 ], [ -73.44783688016787, 8.865505683040851 ], [ -73.426701219385734, 8.781944891843295 ], [ -73.476413947046012, 8.736495470489558 ], [ -73.479514533369013, 8.705980536372635 ], [ -73.539975959023252, 8.653787340013707 ], [ -73.562326015733049, 8.608622137701502 ], [ -73.553127611350192, 8.563766995550395 ], [ -73.491813524074871, 8.462222804938506 ], [ -73.527211880323989, 8.380522365714569 ], [ -73.468688321009211, 8.356777045024614 ], [ -73.455640020570456, 8.324117539892541 ], [ -73.406289029015454, 8.373856105974482 ], [ -73.419931606858142, 8.455453193310234 ], [ -73.356679654142738, 8.43917511623863 ], [ -73.36711829287492, 8.332721665972088 ], [ -73.413084479065446, 8.206191921220181 ], [ -73.408562792139151, 8.127592068319302 ], [ -73.379830694730742, 8.084674790709016 ], [ -73.375541550901858, 8.029897772863933 ], [ -73.289267747908241, 7.985688584960201 ], [ -73.290818040620081, 7.945949408038757 ], [ -73.350581835183561, 7.89646922437521 ], [ -73.357377285233497, 7.810582994109893 ], [ -73.396212123690532, 7.747331041394432 ], [ -73.483777838776234, 7.68154694313688 ], [ -73.515377976712216, 7.684104926201371 ], [ -73.598447842394023, 7.737021592972098 ], [ -73.751901007625406, 7.7408973247517 ], [ -73.744227058431989, 7.830736802961098 ], [ -73.676996019350781, 7.893368638951529 ], [ -73.670303921188975, 7.928973699876337 ], [ -73.728517422141294, 7.987238878571361 ], [ -73.77122799327725, 8.077310898978794 ], [ -73.796368577947476, 8.212935696225372 ], [ -73.755415005098371, 8.329000962924113 ], [ -73.767429775863434, 8.358637396998233 ], [ -73.754691534686572, 8.388738918166553 ], [ -73.762236293570083, 8.459354763511499 ], [ -73.829648199804581, 8.643581244378936 ], [ -73.807582363934955, 8.816593940158214 ], [ -73.870395067078675, 8.887674871697982 ], [ -73.799805061054712, 9.055597438870677 ], [ -73.8550471668932, 9.117970893342033 ], [ -73.878689133896387, 9.184452622690344 ], [ -73.958529222045968, 9.20292694672122 ], [ -73.955738694984746, 9.295040188054202 ], [ -73.994676887128605, 9.34227244701583 ], [ -74.000955573241072, 9.399064846465478 ], [ -74.137097134425176, 9.498231920266903 ], [ -74.027103848263948, 9.591171983000606 ], [ -73.876053635566791, 9.569287014284271 ], [ -73.8257983064467, 9.597218126015662 ], [ -73.800709397720539, 9.577839464419753 ], [ -73.784224615973244, 9.597450670012392 ], [ -73.842748176187342, 9.739819241364899 ], [ -73.841766324256469, 9.789945380175141 ], [ -73.952612271139401, 9.915183213734338 ], [ -73.997725795708902, 9.945982366892679 ], [ -74.066197069139434, 10.053753566773651 ], [ -74.050539109692124, 10.169896348737495 ], [ -73.906387701631104, 10.367894599556109 ], [ -73.77045284692133, 10.391174832252716 ], [ -73.570878464969155, 10.51243358034543 ], [ -73.597595180772942, 10.549046332522209 ], [ -73.614079963419556, 10.65046133102561 ], [ -73.563721279713263, 10.744021511383608 ], [ -73.58968868668353, 10.763348497035508 ], [ -73.64560258698981, 10.77109996239335 ], [ -73.605785894803205, 10.845514024252793 ], [ -73.452151862418475, 10.866313788250693 ], [ -73.284952765657579, 10.852490343254715 ], [ -73.254515346805817, 10.810141506425396 ], [ -73.249916143715041, 10.7338670916929 ], [ -73.123541428594024, 10.678469957122786 ], [ -73.075198127391673, 10.630049139755954 ], [ -73.125117560626904, 10.527238878171659 ], [ -73.181341519295643, 10.456571356882591 ], [ -73.151472541224791, 10.436701767972181 ], [ -73.139586961668954, 10.404429836467784 ], [ -73.077652756769282, 10.415126858517681 ], [ -73.012592128923586, 10.400864163050699 ], [ -72.915232105177495, 10.428171729841438 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-NSA", "NAME_1": "Norte de Santander" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -73.009724894999863, 9.295376892000093 ], [ -72.980062622999895, 9.216518656000076 ], [ -72.973189656999949, 9.128436178000044 ], [ -72.955309611999979, 9.103993225000096 ], [ -72.826686971999919, 9.141691182000045 ], [ -72.791030232999844, 9.113940939000102 ], [ -72.800021932999897, 9.079446920000123 ], [ -72.783072062999878, 9.059939067000116 ], [ -72.675430053999946, 8.651514384000052 ], [ -72.386765502999907, 8.33861358700004 ], [ -72.395963907999914, 8.256603088000062 ], [ -72.357258259999895, 8.172137960000015 ], [ -72.33384883599993, 8.065477804000125 ], [ -72.350075235999924, 8.042585144000014 ], [ -72.40707434199993, 8.043773702000124 ], [ -72.430122029999978, 7.990521139000066 ], [ -72.491203572999979, 7.937501119000061 ], [ -72.45864741999992, 7.893524475000106 ], [ -72.451774454999878, 7.832804667000104 ], [ -72.483348754999952, 7.649353333000064 ], [ -72.463401651999931, 7.570753479000103 ], [ -72.478697875999899, 7.484453837000061 ], [ -72.414619099999868, 7.413812155000059 ], [ -72.20620804899994, 7.381876119000083 ], [ -72.164040079999978, 7.328856099000078 ], [ -72.174220337999941, 7.279608460000091 ], [ -72.164143432999907, 7.22080068000011 ], [ -72.098255981999927, 7.086752014000098 ], [ -71.99381791199994, 7.012854716000021 ], [ -72.18171261304667, 7.040139065465496 ], [ -72.242070685913404, 6.978850815712576 ], [ -72.2878301656296, 7.005696722725588 ], [ -72.326354946623496, 6.927949530546357 ], [ -72.383199022017266, 6.878365994095361 ], [ -72.42278316930782, 6.879218654817066 ], [ -72.50487118215932, 6.915082099059589 ], [ -72.546574062942625, 6.884954739469663 ], [ -72.560733404722839, 6.999495550978907 ], [ -72.650882941294697, 6.995438951146639 ], [ -72.670080735737372, 6.973424791221134 ], [ -72.688813443085905, 7.005076606000557 ], [ -72.74483069528037, 6.989160265034172 ], [ -72.792993130228751, 7.030837307395814 ], [ -72.879370286909193, 7.05985362384564 ], [ -72.885933193861774, 7.073806260950164 ], [ -72.830045131977272, 7.162095445548346 ], [ -72.837176479710763, 7.207880763686262 ], [ -72.88146318198028, 7.256379096318256 ], [ -72.844514533019264, 7.300975856950231 ], [ -72.842292446739009, 7.357535712403205 ], [ -72.897637906264322, 7.428694159208078 ], [ -72.903115606699885, 7.47633983021899 ], [ -72.983885870836275, 7.546774807511326 ], [ -72.991327276932282, 7.613179023393229 ], [ -73.027655809168266, 7.621188870270146 ], [ -73.056594611252308, 7.607597968371522 ], [ -73.216403977861262, 7.630025540346423 ], [ -73.247849087065731, 7.597055975952514 ], [ -73.260742356974163, 7.544914456437027 ], [ -73.360348680347329, 7.549642848938333 ], [ -73.393835007779387, 7.573620714524338 ], [ -73.496722784628787, 7.600854194265651 ], [ -73.544316778796315, 7.669764716368547 ], [ -73.640331590330618, 7.745160631058241 ], [ -73.588655157909216, 7.733455919555013 ], [ -73.505042690767539, 7.679299018434961 ], [ -73.452823655986947, 7.695602932129589 ], [ -73.365671352950585, 7.792341213176428 ], [ -73.350581835183561, 7.89646922437521 ], [ -73.312315435708797, 7.91918101629085 ], [ -73.286968146362824, 7.960392971558406 ], [ -73.289267747908241, 7.985688584960201 ], [ -73.319420945919887, 8.011836859983077 ], [ -73.375541550901858, 8.029897772863933 ], [ -73.379830694730742, 8.084674790709016 ], [ -73.408562792139151, 8.127592068319302 ], [ -73.413084479065446, 8.206191921220181 ], [ -73.36711829287492, 8.332721665972088 ], [ -73.356679654142738, 8.43917511623863 ], [ -73.419931606858142, 8.455453193310234 ], [ -73.406289029015454, 8.373856105974482 ], [ -73.462047898791468, 8.328380846199082 ], [ -73.468688321009211, 8.356777045024614 ], [ -73.529227261029234, 8.385483303111926 ], [ -73.491813524074871, 8.462222804938506 ], [ -73.562196825423143, 8.587899888968707 ], [ -73.54708146833508, 8.645002345881551 ], [ -73.479514533369013, 8.705980536372635 ], [ -73.476413947046012, 8.736495470489558 ], [ -73.426701219385734, 8.781944891843295 ], [ -73.44783688016787, 8.865505683040851 ], [ -73.436597255758727, 9.116343085365088 ], [ -73.40814938008981, 9.154686998306317 ], [ -73.212244832999886, 9.173446350000063 ], [ -73.032669230999915, 9.294601746000083 ], [ -73.009724894999863, 9.295376892000093 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-ARA", "NAME_1": "Arauca" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.964020716999897, 7.005920692000061 ], [ -71.848193725999863, 6.983864238000137 ], [ -71.771505899999937, 7.011149394000057 ], [ -71.77403804599993, 7.028926086000084 ], [ -71.669599975999944, 7.027737529000063 ], [ -71.667016153999953, 7.051508688000112 ], [ -71.62040401299987, 7.052128805000095 ], [ -71.5947208259999, 7.030114645000111 ], [ -71.509919799999864, 7.034610494000034 ], [ -71.467700154999903, 7.012441304000106 ], [ -71.413904988999974, 7.030993144000135 ], [ -71.292517048999883, 7.025773824000041 ], [ -71.275515503999969, 6.984381002000077 ], [ -71.18404821799993, 6.962573547000062 ], [ -71.13604081299988, 6.99213246700009 ], [ -71.011268065999872, 6.99089223200005 ], [ -70.961322794999916, 7.009444072000093 ], [ -70.895538696999921, 7.06851023300004 ], [ -70.703302368999886, 7.099929504000073 ], [ -70.63927526899991, 7.073471171000094 ], [ -70.57860713799991, 7.085821838000044 ], [ -70.510704305999866, 7.009702454000063 ], [ -70.451663981999928, 7.007687073000113 ], [ -70.31906225599991, 6.938285624000059 ], [ -70.287617146999935, 6.936942037000094 ], [ -70.195012979999888, 6.977559713000034 ], [ -70.129203043999922, 6.972547099000067 ], [ -69.432018568999922, 6.122237244000132 ], [ -69.53236528243184, 6.062317613567018 ], [ -69.784908006199487, 6.062136746413728 ], [ -69.855756394641901, 6.026273302171148 ], [ -69.888054164568018, 6.040277615219736 ], [ -69.939627245101292, 6.114691677079236 ], [ -70.025797696206723, 6.150296738903364 ], [ -70.052591926376294, 6.194066677235355 ], [ -70.118091803793675, 6.250006415063979 ], [ -70.165298225232902, 6.267524726484908 ], [ -70.347741869391768, 6.279022732413182 ], [ -70.504889899249463, 6.224710802561503 ], [ -70.727227749061342, 6.209130357479978 ], [ -70.789446173901808, 6.23253978138581 ], [ -70.864170295023087, 6.215254014860875 ], [ -70.959668341720601, 6.222307848228581 ], [ -71.031421067728104, 6.247836004727844 ], [ -71.207146776202762, 6.274061794116506 ], [ -71.462273322355941, 6.198872585001766 ], [ -71.557357957903434, 6.190733546915624 ], [ -71.608750170384042, 6.210422267773424 ], [ -71.721999070700519, 6.200035304985306 ], [ -71.856125251179378, 6.154508368366521 ], [ -71.946481493326246, 6.149909166175064 ], [ -72.057999233777593, 6.110195828574604 ], [ -72.115050014746373, 6.068828844575478 ], [ -72.156313645957994, 6.073970649126124 ], [ -72.259847377954145, 6.138359483403406 ], [ -72.345423549856946, 6.262796332184962 ], [ -72.350591192829256, 6.297574570809786 ], [ -72.272688971918512, 6.432088324016945 ], [ -72.236153734107518, 6.426352240263668 ], [ -72.19941179072157, 6.462189846084527 ], [ -72.157269660366524, 6.474695543264716 ], [ -72.136289029215334, 6.504409490805358 ], [ -72.10169165684448, 6.729098619006038 ], [ -72.053038296380237, 6.782402859404442 ], [ -71.964020716999897, 7.005920692000061 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-BOY", "NAME_1": "Boyacá" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.99381791199994, 7.012854716000021 ], [ -71.965110846988011, 7.001433417318367 ], [ -72.053038296380237, 6.782402859404442 ], [ -72.10169165684448, 6.729098619006038 ], [ -72.136289029215334, 6.504409490805358 ], [ -72.157269660366524, 6.474695543264716 ], [ -72.19941179072157, 6.462189846084527 ], [ -72.236153734107518, 6.426352240263668 ], [ -72.258813850079093, 6.438392849450452 ], [ -72.282042405932259, 6.422243964487336 ], [ -72.295452439778273, 6.375218411100775 ], [ -72.354363572720672, 6.334497382248401 ], [ -72.395963100716529, 6.267524726484908 ], [ -72.415729335940114, 6.204066067295173 ], [ -72.371210089673866, 6.109110622956848 ], [ -72.341031053240499, 6.078854071258377 ], [ -72.392759161606023, 5.900932114925126 ], [ -72.44107662618535, 5.882096055688407 ], [ -72.447381150719536, 5.854242459222121 ], [ -72.311136236747927, 5.77401479744492 ], [ -72.237652350875294, 5.683090115416462 ], [ -72.26682369695601, 5.659422309092292 ], [ -72.302609625933485, 5.584000555980879 ], [ -72.319275274834069, 5.506098334170758 ], [ -72.348059048186485, 5.510154934002969 ], [ -72.398495246258619, 5.564311835123078 ], [ -72.420612758971629, 5.557697252226376 ], [ -72.590137294800286, 5.354195460751896 ], [ -72.690182867745136, 5.277921046918777 ], [ -72.709613207083805, 5.279548854895722 ], [ -72.808470221623395, 5.383986925356282 ], [ -72.857588670980363, 5.3458238795684 ], [ -72.938255581429928, 5.240455634020293 ], [ -72.934612392747738, 5.205160631457943 ], [ -72.953190069566062, 5.160460517139143 ], [ -72.938462287004938, 5.115372830092042 ], [ -72.90611284023538, 5.083023383322484 ], [ -72.933062100035897, 5.020417384854397 ], [ -72.973679776100767, 4.978766180914533 ], [ -73.011351894574261, 4.994889228355191 ], [ -73.030937262644557, 4.985122382292104 ], [ -73.068609382017371, 4.81079193779766 ], [ -73.052977260991781, 4.734827582327057 ], [ -73.073311936996276, 4.728471380949486 ], [ -73.113231981071067, 4.6639791938847 ], [ -73.218083461782328, 4.677647610149052 ], [ -73.228392910204605, 4.723587957917914 ], [ -73.296424934063452, 4.729789130563915 ], [ -73.329058600773806, 4.783791002053079 ], [ -73.36825517443674, 4.797743639157602 ], [ -73.365800544159754, 4.819783637504827 ], [ -73.402723354699049, 4.871460069026966 ], [ -73.523258633279283, 4.888358262823544 ], [ -73.545298630727189, 4.919389959978673 ], [ -73.514266933572117, 4.991246038773681 ], [ -73.517600063891848, 5.023828030439233 ], [ -73.475948859052608, 5.065892646428495 ], [ -73.525093145931919, 5.210974229577005 ], [ -73.521630825302339, 5.237277533331508 ], [ -73.584831102073679, 5.304611925200163 ], [ -73.590102097833551, 5.385614732433964 ], [ -73.641675178366768, 5.430702419481065 ], [ -73.653767462598296, 5.461734117535457 ], [ -73.791510993337681, 5.507958686144434 ], [ -73.791510993337681, 5.558549912948138 ], [ -73.812620815698097, 5.561960556734277 ], [ -73.899230516375212, 5.481887926386662 ], [ -73.90672359931466, 5.442019558255993 ], [ -73.93483557819934, 5.434190579431686 ], [ -74.000102911620047, 5.374297594558357 ], [ -74.088702154580744, 5.419669501546252 ], [ -74.098029751072147, 5.455610460154617 ], [ -74.147535773157415, 5.45294912430262 ], [ -74.24993262359169, 5.49075043398534 ], [ -74.256908941694292, 5.544674791108719 ], [ -74.31352047399065, 5.613792018786626 ], [ -74.288379890219744, 5.681617336171144 ], [ -74.312848680422235, 5.793186754365195 ], [ -74.339074469810896, 5.825691229866379 ], [ -74.440644497045867, 5.767193508073944 ], [ -74.533946295884846, 5.790551256035599 ], [ -74.646084153960544, 5.752517402356204 ], [ -74.662491421341997, 5.771947739896291 ], [ -74.639882982213862, 5.861761378784593 ], [ -74.590816209700279, 5.918166205505941 ], [ -74.605130581111439, 5.978446764006947 ], [ -74.57425391268788, 6.001597805494328 ], [ -74.577690395795116, 6.078802395314256 ], [ -74.605130581111439, 6.136111557802167 ], [ -74.566734992226088, 6.241169744987701 ], [ -74.519425217999412, 6.282304184990153 ], [ -74.479789394764737, 6.155180161934936 ], [ -74.419534674685451, 6.073583075498505 ], [ -74.356851161851637, 6.039114895236196 ], [ -74.290266078816444, 6.070689194750514 ], [ -74.26998307965539, 6.04983775480855 ], [ -74.239158088075271, 5.981702379061517 ], [ -74.269569667606049, 5.898451646226476 ], [ -74.257451544952801, 5.848196316207009 ], [ -74.233783738628631, 5.846310125811669 ], [ -74.174510871379596, 5.900777086193557 ], [ -74.11081966819313, 5.87059804886087 ], [ -74.087978685068265, 5.824063421889377 ], [ -74.04873043456189, 5.813650621578915 ], [ -74.008422817758799, 5.752129827829265 ], [ -73.97317949114057, 5.73257029908001 ], [ -73.893959519716077, 5.747323920062854 ], [ -73.877448900446382, 5.737091986905682 ], [ -73.878534105164817, 5.71140879987621 ], [ -73.833885667689401, 5.739107366711607 ], [ -73.737121548220841, 5.761147365958152 ], [ -73.694307624297437, 5.751974799097695 ], [ -73.64865149557005, 5.715439561286701 ], [ -73.613976609732731, 5.844863185887334 ], [ -73.618653327189293, 5.904756170760663 ], [ -73.589249437111846, 5.988859565216728 ], [ -73.535221727200963, 6.042060451928307 ], [ -73.499280768592598, 6.107095242251603 ], [ -73.438121710948167, 6.069552314088014 ], [ -73.381871913857708, 6.001029363814098 ], [ -73.400759649937868, 5.922274482181592 ], [ -73.47155636333548, 5.847705389791884 ], [ -73.468300747381591, 5.813495591948026 ], [ -73.428794115356141, 5.763937893019317 ], [ -73.403007574639844, 5.756238105404236 ], [ -73.351331143117761, 5.862536526039833 ], [ -73.28616716158524, 5.855870266299746 ], [ -73.219246181765868, 5.982477525417437 ], [ -73.195423346710072, 5.991107489019385 ], [ -73.127029587645325, 5.955476588773536 ], [ -73.016855435230127, 5.940748806212412 ], [ -72.992386644128317, 5.999634100733147 ], [ -72.893658819898633, 6.123218288792998 ], [ -72.817436082908898, 6.153423162748766 ], [ -72.799297654762938, 6.202515774583333 ], [ -72.754623378865801, 6.229516710327914 ], [ -72.733410203717938, 6.45660879196214 ], [ -72.794414231731423, 6.533193264157831 ], [ -72.791623704670201, 6.567093004538492 ], [ -72.762245653014475, 6.57360423374837 ], [ -72.708889736672006, 6.528774929119663 ], [ -72.66155412492293, 6.434801336712326 ], [ -72.616673142551463, 6.438082791087936 ], [ -72.550578985931452, 6.490353501812649 ], [ -72.542414110322909, 6.561356919885952 ], [ -72.497817348791614, 6.645770371805213 ], [ -72.476862556062088, 6.759820257798651 ], [ -72.487766282787732, 6.809171251152293 ], [ -72.477973599202244, 6.844078680986343 ], [ -72.50487118215932, 6.915082099059589 ], [ -72.42278316930782, 6.879218654817066 ], [ -72.383199022017266, 6.878365994095361 ], [ -72.326354946623496, 6.927949530546357 ], [ -72.2878301656296, 7.005696722725588 ], [ -72.242070685913404, 6.978850815712576 ], [ -72.18171261304667, 7.040139065465496 ], [ -71.99381791199994, 7.012854716000021 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-VID", "NAME_1": "Vichada" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -67.456299400197167, 6.193223721097866 ], [ -67.486961221999906, 6.166782328000039 ], [ -67.491198689999948, 6.114485779000034 ], [ -67.428566853999939, 6.038469747000079 ], [ -67.422469034999978, 5.978240865000103 ], [ -67.485204223999915, 5.944082743000124 ], [ -67.625144002999946, 5.784505921000076 ], [ -67.649070190999936, 5.656089986000083 ], [ -67.617030802999921, 5.541600851000069 ], [ -67.652480834999949, 5.477961324000077 ], [ -67.809783895999914, 5.378820089000044 ], [ -67.843683634999906, 5.29724884000008 ], [ -67.81474483299985, 5.210277405000056 ], [ -67.82663041299989, 5.120386251000113 ], [ -67.793092406999875, 5.063335470000112 ], [ -67.826372029999902, 4.894844462000052 ], [ -67.813504598999913, 4.840506694000084 ], [ -67.82285803299996, 4.743587545000139 ], [ -67.845647338999953, 4.689740703000027 ], [ -67.855155802999946, 4.566156515000046 ], [ -67.875051228999951, 4.532644348000119 ], [ -67.829059203999947, 4.491432394000128 ], [ -67.813504598999913, 4.443269959000048 ], [ -67.793092406999875, 4.42898142500006 ], [ -67.799862019999921, 4.398905741000092 ], [ -67.77939815299996, 4.350794983000114 ], [ -67.799862019999921, 4.306069031000064 ], [ -67.79944860899991, 4.235323995000044 ], [ -67.777744506999909, 4.153933614000039 ], [ -67.740175740999888, 4.118716126000066 ], [ -67.714079141999918, 4.056497701000055 ], [ -67.797096523685582, 3.953764145998548 ], [ -67.838489346106428, 3.924282742454579 ], [ -67.876962450256883, 3.922732448843419 ], [ -67.950704719447231, 3.957484849046523 ], [ -67.999125535914743, 3.936375026686108 ], [ -68.013414068904126, 3.998464260317348 ], [ -68.048709073265115, 3.955934556334682 ], [ -68.092737393116181, 4.00544057931927 ], [ -68.16942521809932, 3.919709376886203 ], [ -68.1894498357413, 3.930638942932831 ], [ -68.177254197822947, 3.960895493732039 ], [ -68.18810624860447, 3.973168646915497 ], [ -68.252365891672525, 3.94322215447886 ], [ -68.26789465991061, 4.00272756572457 ], [ -68.355537889362097, 4.019858303517879 ], [ -68.368431159270585, 3.994898586000943 ], [ -68.351377935843061, 3.968491930358311 ], [ -68.37253943504686, 3.923585110464444 ], [ -68.444938117100435, 3.912629705996096 ], [ -68.438452725412958, 3.873071397127262 ], [ -68.504882778817205, 3.84452016777152 ], [ -68.546353114704459, 3.795944322572439 ], [ -68.579606899938483, 3.80806244522563 ], [ -68.643168911016403, 3.781836655836969 ], [ -68.68879920132207, 3.797804674546057 ], [ -68.739597133700727, 3.772534897767287 ], [ -68.744222175213224, 3.736206366430679 ], [ -68.810135463780625, 3.727989813978695 ], [ -68.804476895292453, 3.690136827452591 ], [ -68.827757127989059, 3.689361681096671 ], [ -68.848350186411949, 3.709825548310391 ], [ -68.907312995298469, 3.688560696319087 ], [ -68.937776251672688, 3.707345078712422 ], [ -68.962425909927788, 3.640940862830519 ], [ -69.040638190100367, 3.655203559196877 ], [ -69.090299241816524, 3.609366563316257 ], [ -69.108928596377609, 3.627892564190461 ], [ -69.105776333211224, 3.655823675921908 ], [ -69.140089483842587, 3.674530543949459 ], [ -69.183549363812062, 3.652102972873877 ], [ -69.191119961117295, 3.679879054974379 ], [ -69.251012945990681, 3.701221422230844 ], [ -69.279538336924702, 3.728919989066242 ], [ -69.301526659327862, 3.700136217512409 ], [ -69.346252611169064, 3.712771104103183 ], [ -69.430717739931765, 3.68608022672106 ], [ -69.474280971789426, 3.715742499216958 ], [ -69.603213670874197, 3.691997179426266 ], [ -69.616029426416901, 3.675848293563888 ], [ -69.611404384904404, 3.618823350117509 ], [ -69.648740606593719, 3.594690456699198 ], [ -69.658119879928506, 3.532472031858788 ], [ -69.722043627111702, 3.568619696042106 ], [ -69.849400194163593, 3.559007880509284 ], [ -69.866660122266808, 3.530611680784432 ], [ -69.89410030758313, 3.566449285705971 ], [ -69.926346401565183, 3.555907294186284 ], [ -69.962984992163626, 3.505006008120745 ], [ -70.010863207171269, 3.528596300079187 ], [ -70.082770961910342, 3.525495713756186 ], [ -70.054865688600614, 3.48451630338468 ], [ -70.068611620130127, 3.424623318511351 ], [ -70.119745449293021, 3.416639309156778 ], [ -70.151138881654049, 3.347883815785451 ], [ -70.116024746245046, 3.290161241248256 ], [ -70.141578742065292, 3.276441148140464 ], [ -70.129253912937713, 3.20427501098294 ], [ -70.144627652444171, 3.201949571015859 ], [ -70.159872198942821, 3.227710273310436 ], [ -70.163954637196753, 3.186291612467926 ], [ -70.202996182128118, 3.196213487262639 ], [ -70.308519457307113, 3.083946437977716 ], [ -70.263405930938973, 3.062914129983085 ], [ -70.265576341275107, 3.04508576109896 ], [ -70.291595425088758, 3.030254624851068 ], [ -70.2750848049198, 2.960362249917864 ], [ -70.383424444682362, 2.846751614395487 ], [ -70.499748093799496, 2.78453318955502 ], [ -70.592843187063409, 2.841868191363915 ], [ -70.650204027294023, 2.832333889297558 ], [ -70.694774950403598, 2.869411729467743 ], [ -70.686403368320782, 2.823419704855496 ], [ -70.734824184788295, 2.782517807950455 ], [ -70.748208381111908, 2.813937078733204 ], [ -70.811279465774703, 2.791974596550403 ], [ -70.848641526785002, 2.828845730246258 ], [ -70.889595099634107, 2.815874945072665 ], [ -70.904064500676157, 2.857629502699353 ], [ -70.923598191903011, 2.828458157517957 ], [ -70.961709560847567, 2.866001084782226 ], [ -70.980132208934265, 2.813006902746338 ], [ -70.986514247834236, 2.854683946007299 ], [ -71.063667161710157, 2.868636583111822 ], [ -71.060334032289745, 4.919389959978673 ], [ -71.027080247955041, 4.959206651265958 ], [ -70.960288459344895, 5.117724107581466 ], [ -70.887889777291377, 5.154956977382597 ], [ -70.695705126390465, 5.313681139273172 ], [ -70.67865190296294, 5.389412949847724 ], [ -70.448795131789893, 5.53309926991534 ], [ -70.342858446360196, 5.568187567801999 ], [ -70.185193650766337, 5.587411199767018 ], [ -70.122768521250237, 5.620949204941837 ], [ -69.986575283222749, 5.779208278839008 ], [ -69.898647833830466, 5.97079865233593 ], [ -69.817102424237476, 6.05479869220585 ], [ -69.53236528243184, 6.062317613567018 ], [ -69.432018568999922, 6.122237244000132 ], [ -69.331396443999949, 6.15636952700001 ], [ -69.246104492999876, 6.08066355400004 ], [ -69.061128702999895, 6.217838644000011 ], [ -68.892921915999892, 6.184326477000099 ], [ -68.807862507999886, 6.184326477000099 ], [ -68.635314900999902, 6.135879822000049 ], [ -68.584723673999861, 6.170012106000115 ], [ -68.4490213629999, 6.194997661000102 ], [ -68.304172322999932, 6.176988424000101 ], [ -68.146507527999887, 6.223781433000028 ], [ -68.019021769999966, 6.211611634000107 ], [ -67.924143839999971, 6.234555970000144 ], [ -67.904300089999879, 6.275147807000081 ], [ -67.868126587999967, 6.279876201000064 ], [ -67.827198852999942, 6.313414205000072 ], [ -67.573984334999949, 6.266233622000058 ], [ -67.490475219999951, 6.201638082000017 ], [ -67.456299400197167, 6.193223721097866 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-CAU", "NAME_1": "Cauca" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -77.902333136999914, 2.696234442000048 ], [ -77.850493943999936, 2.63812897300005 ], [ -77.785023566999939, 2.593817450000074 ], [ -77.839914516999897, 2.577337958000044 ], [ -77.888050910999937, 2.593817450000074 ], [ -77.86750240799995, 2.639837958000044 ], [ -77.914051886999914, 2.658677476000094 ], [ -77.916371222999942, 2.697211005000042 ], [ -77.902333136999914, 2.696234442000048 ] ] ], [ [ [ -77.806141730999911, 2.662054755000042 ], [ -77.75413977799991, 2.617987372000073 ], [ -77.759103969999899, 2.603094794000071 ], [ -77.847075975999928, 2.648382880000042 ], [ -77.880686001999948, 2.696234442000048 ], [ -77.882557745999918, 2.724595445000091 ], [ -77.860096808999913, 2.709865627000056 ], [ -77.847075975999928, 2.724107164000088 ], [ -77.806141730999911, 2.662054755000042 ] ] ], [ [ [ -78.073901625059932, 2.646820262744939 ], [ -77.949840129999927, 2.67451808800007 ], [ -77.917591925999943, 2.63226959800005 ], [ -77.888050910999937, 2.634711005000042 ], [ -77.904286261999914, 2.579982815000051 ], [ -77.839670376999948, 2.56586334800005 ], [ -77.76040605399993, 2.591620184000078 ], [ -77.751535610999952, 2.62726471600007 ], [ -77.798695441999939, 2.675726630000042 ], [ -77.778187628999945, 2.689398505000042 ], [ -77.797596808999913, 2.698716539000088 ], [ -77.812367316999939, 2.764471747000073 ], [ -77.794789191999939, 2.75726959800005 ], [ -77.733550584999932, 2.786118882000039 ], [ -77.785755988999938, 2.794826565000051 ], [ -77.764556443999936, 2.815659898000092 ], [ -77.709339972999942, 2.812241929000038 ], [ -77.688832160999937, 2.79173411700009 ], [ -77.698597785999937, 2.81313711100006 ], [ -77.735422329999949, 2.822495835000041 ], [ -77.708159959999932, 2.848456122000073 ], [ -77.668324347999942, 2.86749909100007 ], [ -77.641713019999941, 2.846380927000041 ], [ -77.636057094999899, 2.869614976000094 ], [ -77.657704230999911, 2.876898505000042 ], [ -77.709339972999942, 2.860663153000075 ], [ -77.715687628999945, 2.897528387000079 ], [ -77.696278449999909, 2.928941148000092 ], [ -77.640126105999911, 2.900051174000055 ], [ -77.619699673999946, 2.931586005000042 ], [ -77.641713019999941, 2.956244208000044 ], [ -77.627349412999934, 2.991034247000073 ], [ -77.654652472999942, 3.004706122000073 ], [ -77.665435350999928, 2.984564520000049 ], [ -77.688832160999937, 2.997259833000044 ], [ -77.723540818999936, 2.969916083000044 ], [ -77.721791144999941, 2.982001044000071 ], [ -77.647706847999928, 3.073852830000078 ], [ -77.571428684999944, 3.13807513900008 ], [ -77.539628839999921, 3.196844681000073 ], [ -77.508656378999945, 3.194566148000092 ], [ -77.501820441999939, 3.22337474200009 ], [ -77.479683974999944, 3.227463768000064 ], [ -77.500799921999942, 3.24475811700006 ], [ -77.54179451899995, 3.246080663000043 ], [ -77.464864340999952, 3.301625682000065 ], [ -77.418834804582559, 3.25866445609978 ], [ -77.372403531297891, 3.169677639511463 ], [ -77.31922848210877, 3.175491238529844 ], [ -77.261480069149854, 3.124047349205796 ], [ -77.234246589408542, 3.125442613186067 ], [ -77.18603247761672, 3.169445095514732 ], [ -77.109603034152713, 3.191872667489577 ], [ -77.014647589814388, 3.168204861165407 ], [ -76.985243699736941, 3.140041205437285 ], [ -76.869591844188221, 3.092860623319098 ], [ -76.828974169022672, 3.105366318700646 ], [ -76.778589646894659, 3.183940334079125 ], [ -76.672833827718932, 3.107846788298616 ], [ -76.632345343762609, 3.124615789986706 ], [ -76.608858404591672, 3.098157457500633 ], [ -76.576663988352379, 3.124047349205796 ], [ -76.553306241289988, 3.110094713000592 ], [ -76.515504929808628, 3.163088894137161 ], [ -76.466774054978657, 3.178591823953525 ], [ -76.447602098058383, 3.203964951721161 ], [ -76.442356939820911, 3.254866237786644 ], [ -76.462846646355615, 3.285277818216741 ], [ -76.436698371332739, 3.317937323348758 ], [ -76.353990240856945, 3.290238756513418 ], [ -76.255882534251555, 3.282874863883876 ], [ -76.176636726203924, 3.241068630313009 ], [ -76.075764330059769, 3.213292548212507 ], [ -76.091525642294528, 3.203189806264561 ], [ -76.112790493386569, 3.095108547121754 ], [ -76.044577603273751, 3.035525621510203 ], [ -76.024423794422546, 2.911863918185247 ], [ -75.819035814351366, 2.734872137838863 ], [ -75.781027798194316, 2.669604804418157 ], [ -75.823376634124372, 2.530388495332772 ], [ -75.795342169605419, 2.474732978344264 ], [ -75.844486457384107, 2.428120836107666 ], [ -75.877533535244424, 2.426622219339947 ], [ -75.966184455048563, 2.490959376773787 ], [ -76.050081143030297, 2.420627753168276 ], [ -76.233661668750983, 2.351794745431164 ], [ -76.277689988602106, 2.35634227077918 ], [ -76.348719245097072, 2.413186347072269 ], [ -76.378898282429759, 2.419955958700541 ], [ -76.392566697794848, 2.366780911310002 ], [ -76.357323371176619, 2.271541246131619 ], [ -76.396519944839554, 2.186223455747893 ], [ -76.421531338300611, 2.163847561515752 ], [ -76.416751268056544, 2.131446437902753 ], [ -76.455405240259608, 2.112791245819324 ], [ -76.550799934169618, 2.12157623905216 ], [ -76.566974656655077, 2.100027167120061 ], [ -76.565036791214936, 2.01445099521726 ], [ -76.600719367404849, 1.958640447698485 ], [ -76.576896532349053, 1.879678860491026 ], [ -76.504084439145515, 1.823093167515651 ], [ -76.381766323856766, 1.659072170544221 ], [ -76.145294968887697, 1.575511379346665 ], [ -76.227072923376682, 1.464820461195302 ], [ -76.282289190793506, 1.339970201263782 ], [ -76.29704281267567, 1.196051337199435 ], [ -76.255004035108129, 1.137501939462936 ], [ -76.15960934119812, 1.132644354853085 ], [ -76.06051978176248, 1.043657538264767 ], [ -76.07806393070581, 1.021488348708317 ], [ -76.148473069576482, 1.006863918035378 ], [ -76.209838832795867, 0.972137356253995 ], [ -76.351018845743113, 0.976943264020406 ], [ -76.512456021228388, 1.038593248079906 ], [ -76.546174892657177, 1.117606513030125 ], [ -76.520465868105305, 1.301522935535047 ], [ -76.588368699855607, 1.407459621864064 ], [ -76.654488694897339, 1.437742011084936 ], [ -76.772750210353934, 1.313976955871794 ], [ -76.911708137020867, 1.313201809515874 ], [ -76.924472214820867, 1.502957668561521 ], [ -76.865173509150111, 1.544402166926432 ], [ -76.843650274740355, 1.598869127308376 ], [ -76.924446377298466, 1.719791977717591 ], [ -77.044671596616865, 1.704289048800547 ], [ -77.099371100995484, 1.667908839721179 ], [ -77.150866665364276, 1.686822415122322 ], [ -77.232980515738177, 1.663464667160667 ], [ -77.325067918649495, 1.689406235709214 ], [ -77.28339087628791, 1.855700994904964 ], [ -77.213679369407373, 1.926911119452598 ], [ -77.199261644309445, 1.961017564509007 ], [ -77.213963589348168, 1.986442369120027 ], [ -77.326385668263981, 2.062200019015677 ], [ -77.30132259795954, 2.154804184965144 ], [ -77.313027310362088, 2.171392320399264 ], [ -77.446326666742266, 2.221363430477936 ], [ -77.70274512408821, 2.142608547046791 ], [ -77.840126918722319, 2.177231756940046 ], [ -77.859428066851763, 2.237383124231769 ], [ -77.948750780224316, 2.381973781864531 ], [ -77.931697556796792, 2.467033188930486 ], [ -77.952729864791422, 2.555658271212224 ], [ -78.073901625059932, 2.646820262744939 ] ] ], [ [ [ -78.186611575999905, 2.990372525000055 ], [ -78.164269952999916, 3.001595525000084 ], [ -78.16709082999995, 2.959704273000057 ], [ -78.193223497999952, 2.933616561000065 ], [ -78.220288919999916, 2.933616538000081 ], [ -78.186611575999905, 2.990372525000055 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-VAC", "NAME_1": "Valle del Cauca" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -77.464864340999952, 3.301625682000065 ], [ -77.477658403999897, 3.313153257000067 ], [ -77.468658006999931, 3.344671942000048 ], [ -77.380970831999946, 3.387640692000048 ], [ -77.343739386999914, 3.329413153000075 ], [ -77.318918423999946, 3.319973049000055 ], [ -77.367054816999939, 3.402085679000038 ], [ -77.353016730999911, 3.429836330000057 ], [ -77.333159959999932, 3.411810614000046 ], [ -77.346180792999917, 3.436021226000094 ], [ -77.326283331999946, 3.490668036000045 ], [ -77.333159959999932, 3.511786200000074 ], [ -77.31273352799991, 3.511786200000074 ], [ -77.316151495999918, 3.480373440000051 ], [ -77.282826300999943, 3.485174872000073 ], [ -77.264271613999938, 3.470851955000057 ], [ -77.284779425999943, 3.49750397300005 ], [ -77.27171790299991, 3.504950262000079 ], [ -77.298980272999927, 3.511786200000074 ], [ -77.274891730999911, 3.532782294000071 ], [ -77.325754360999952, 3.532212632000039 ], [ -77.321766730999911, 3.547837632000039 ], [ -77.277943488999938, 3.545884507000039 ], [ -77.298980272999927, 3.558986721000053 ], [ -77.277943488999938, 3.566392320000091 ], [ -77.284779425999943, 3.580633856000077 ], [ -77.20962480399993, 3.580633856000077 ], [ -77.227162238999938, 3.591009833000044 ], [ -77.189198370999918, 3.662583726000094 ], [ -77.169545050999943, 3.652248440000051 ], [ -77.118275519999941, 3.67804596600007 ], [ -77.170806443999936, 3.67719147300005 ], [ -77.174916144999941, 3.692694403000075 ], [ -77.126454230999911, 3.717230536000045 ], [ -77.198719855999911, 3.710028387000079 ], [ -77.195423956999946, 3.758205471000053 ], [ -77.167388475999928, 3.737941799000055 ], [ -77.12564042899993, 3.733547268000052 ], [ -77.174916144999941, 3.758205471000053 ], [ -77.144439256999931, 3.759588934000078 ], [ -77.126454230999911, 3.778713283000059 ], [ -77.150380011999914, 3.813666083000044 ], [ -77.133941209999932, 3.827093817000048 ], [ -77.120269334999932, 3.79913971600007 ], [ -77.105620897999927, 3.813462632000039 ], [ -77.114491339999915, 3.852606512000079 ], [ -77.06859290299991, 3.867743231000077 ], [ -77.03156490799995, 3.915838934000078 ], [ -77.093006964999915, 3.909002997000073 ], [ -77.079335089999915, 3.922064520000049 ], [ -77.126454230999911, 3.929510809000078 ], [ -77.123036261999914, 3.886135158000059 ], [ -77.181141730999911, 3.85297272300005 ], [ -77.253163214999915, 3.840806382000039 ], [ -77.291615363999938, 3.860581773000092 ], [ -77.27171790299991, 3.88540273600006 ], [ -77.311756964999915, 3.908433335000041 ], [ -77.300200975999928, 3.969142971000053 ], [ -77.270415818999936, 3.986395575000074 ], [ -77.25999915299991, 3.975409247000073 ], [ -77.27171790299991, 3.964260158000059 ], [ -77.20962480399993, 3.97728099200009 ], [ -77.243763800999943, 3.97728099200009 ], [ -77.189198370999918, 4.067328192000048 ], [ -77.264271613999938, 4.108221747000073 ], [ -77.264271613999938, 4.067328192000048 ], [ -77.298980272999927, 4.067328192000048 ], [ -77.298980272999927, 4.045599677000041 ], [ -77.318918423999946, 4.05304596600007 ], [ -77.326324022999927, 3.981390692000048 ], [ -77.346180792999917, 3.929510809000078 ], [ -77.362131313999953, 3.92804596600007 ], [ -77.379790818999936, 3.950018622000073 ], [ -77.373524542999917, 3.964260158000059 ], [ -77.430775519999941, 4.012640692000048 ], [ -77.430409308999913, 4.044012762000079 ], [ -77.408273891999897, 4.045599677000041 ], [ -77.431141730999911, 4.09438711100006 ], [ -77.435160502512787, 4.152847603334193 ], [ -77.394624395899143, 4.159668890906573 ], [ -77.350208503319777, 4.194679674427448 ], [ -77.298635422786504, 4.178763333461063 ], [ -77.254437965351315, 4.24218662549124 ], [ -77.244530199409155, 4.190855617692591 ], [ -77.221172451447444, 4.16806631141111 ], [ -77.155465867555733, 4.182871609237338 ], [ -77.065807258298321, 4.103884181809519 ], [ -77.018239101653194, 4.101558742741759 ], [ -76.987259081341506, 4.12398631381734 ], [ -76.956795824068024, 4.122591050736389 ], [ -76.892742885675602, 4.041898301865103 ], [ -76.822643806066765, 4.029806015834936 ], [ -76.761407233157286, 3.995880438831193 ], [ -76.730375536002157, 3.998619289948238 ], [ -76.654256150900608, 4.063318183487354 ], [ -76.574958666009593, 4.055799262126243 ], [ -76.545942348660446, 4.110498764706222 ], [ -76.473285285087798, 4.155870673492757 ], [ -76.43964392802485, 4.200648302177399 ], [ -76.49651384094102, 4.237571111817317 ], [ -76.495971238581774, 4.319969183930709 ], [ -76.545709804663716, 4.394848333783557 ], [ -76.503671027096232, 4.396243597763828 ], [ -76.455715297722804, 4.420686550443918 ], [ -76.44233110229851, 4.46644603105949 ], [ -76.450315110753763, 4.514324246067076 ], [ -76.427319098897271, 4.581736152301573 ], [ -76.316912400686704, 4.678965358864218 ], [ -76.298515591021669, 4.764076442773614 ], [ -76.169531215992833, 4.8894434684413 ], [ -76.141057501902196, 4.96998118678232 ], [ -76.075919358791339, 5.035713609095751 ], [ -76.02238257529558, 4.941507472691683 ], [ -75.986286587056327, 4.911095893160905 ], [ -75.981118944084017, 4.872622789010506 ], [ -75.922181972719841, 4.872416083435496 ], [ -75.94026872402236, 4.821954046941698 ], [ -75.91928809287117, 4.77012258488935 ], [ -75.894302537831834, 4.760820827718987 ], [ -75.851902025058394, 4.776633815897867 ], [ -75.853555670557739, 4.731959540000787 ], [ -75.713951788744055, 4.712942612711402 ], [ -75.716018846292684, 4.658785712490612 ], [ -75.824849413369691, 4.664444280978785 ], [ -75.862108119793902, 4.612948717509312 ], [ -75.876758388888504, 4.552564806220801 ], [ -75.866914029358952, 4.458229477708244 ], [ -75.890375129208849, 4.423632107136029 ], [ -75.809062262713212, 4.397483832113153 ], [ -75.787926601931133, 4.350845852354212 ], [ -75.790252040998894, 4.288394884416391 ], [ -75.828105028424318, 4.210337632975381 ], [ -75.8381560944282, 4.121815904380469 ], [ -75.762217577379261, 4.078511054041883 ], [ -75.745448574791908, 4.041510728237483 ], [ -75.79614315528238, 4.008076076749546 ], [ -75.857663947233391, 3.869893297337796 ], [ -75.988792894176697, 3.6467544618489 ], [ -75.99677690263195, 3.559240424505958 ], [ -76.049383511040162, 3.442400011451355 ], [ -76.064989793644031, 3.357831529001828 ], [ -76.043854132861952, 3.314061591569157 ], [ -76.06072648823681, 3.294734605017993 ], [ -76.075764330059769, 3.213292548212507 ], [ -76.176636726203924, 3.241068630313009 ], [ -76.255882534251555, 3.282874863883876 ], [ -76.353990240856945, 3.290238756513418 ], [ -76.436698371332739, 3.317937323348758 ], [ -76.462846646355615, 3.285277818216741 ], [ -76.442356939820911, 3.254866237786644 ], [ -76.447602098058383, 3.203964951721161 ], [ -76.466774054978657, 3.178591823953525 ], [ -76.515504929808628, 3.163088894137161 ], [ -76.553306241289988, 3.110094713000592 ], [ -76.576663988352379, 3.124047349205796 ], [ -76.608858404591672, 3.098157457500633 ], [ -76.632345343762609, 3.124615789986706 ], [ -76.672833827718932, 3.107846788298616 ], [ -76.778589646894659, 3.183940334079125 ], [ -76.828974169022672, 3.105366318700646 ], [ -76.869591844188221, 3.092860623319098 ], [ -76.985243699736941, 3.140041205437285 ], [ -77.014647589814388, 3.168204861165407 ], [ -77.109603034152713, 3.191872667489577 ], [ -77.18603247761672, 3.169445095514732 ], [ -77.234246589408542, 3.125442613186067 ], [ -77.261480069149854, 3.124047349205796 ], [ -77.31922848210877, 3.175491238529844 ], [ -77.372403531297891, 3.169677639511463 ], [ -77.418834804582559, 3.25866445609978 ], [ -77.464864340999952, 3.301625682000065 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-ANT", "NAME_1": "Antioquia" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -76.985457524345236, 8.256179684045151 ], [ -76.962025519999941, 8.266546942000048 ], [ -76.96312415299991, 8.203680731000077 ], [ -76.935292120999918, 8.20538971600007 ], [ -76.935292120999918, 8.184963283000059 ], [ -76.921701626999948, 8.199204820000091 ], [ -76.917591925999943, 8.188950914000088 ], [ -76.928537563999953, 8.15766022300005 ], [ -76.948963995999918, 8.164496161000045 ], [ -76.942534959999932, 8.128851630000042 ], [ -76.918324347999942, 8.11391836100006 ], [ -76.895741339999915, 8.117254950000074 ], [ -76.893706834999932, 8.136542059000078 ], [ -76.83226477799991, 8.136542059000078 ], [ -76.846547003999945, 8.095526434000078 ], [ -76.825428839999915, 8.103013414000088 ], [ -76.860218878999945, 8.082505601000037 ], [ -76.839100714999915, 8.054632880000042 ], [ -76.866444464999915, 8.061997789000088 ], [ -76.83226477799991, 8.027289130000042 ], [ -76.907704230999911, 8.044094143000052 ], [ -76.933705206999946, 7.964585679000038 ], [ -76.907053188999953, 7.929510809000078 ], [ -76.853586391999897, 7.91274648600006 ], [ -76.757232225999928, 7.923570054000038 ], [ -76.730620897999927, 8.051336981000077 ], [ -76.732004360999952, 8.079291083000044 ], [ -76.744130011999914, 8.103013414000088 ], [ -76.750355597999942, 8.075669664000088 ], [ -76.759185350999928, 8.11469147300005 ], [ -76.747914191999939, 8.171535549000055 ], [ -76.77017167899993, 8.258490302000041 ], [ -76.774810350999928, 8.416693427000041 ], [ -76.802072719999899, 8.430161851000037 ], [ -76.838612433999913, 8.500433661000045 ], [ -76.947173631999931, 8.545477606000077 ], [ -76.893706834999932, 8.620347398000092 ], [ -76.660227016999897, 8.687445380000042 ], [ -76.647328253999945, 8.747300523000092 ], [ -76.560454881999931, 8.775376695000091 ], [ -76.44483097368402, 8.869865946937113 ], [ -76.412307094596713, 8.839512436749544 ], [ -76.388845994746873, 8.738898423923104 ], [ -76.346316290764207, 8.674793808687298 ], [ -76.277534959870479, 8.64151418683025 ], [ -76.229114143402967, 8.577590440546373 ], [ -76.213688727952444, 8.452921046868823 ], [ -76.217331915735315, 8.410158799788746 ], [ -76.317945930360395, 8.280890203919739 ], [ -76.41938676638614, 8.09865326623526 ], [ -76.419490119173645, 7.979099840485219 ], [ -76.468324347690498, 7.874816798756228 ], [ -76.505117967020567, 7.74074229602013 ], [ -76.497573208137055, 7.600001531745306 ], [ -76.407759569248697, 7.38035085710635 ], [ -75.856992153664919, 7.367250880723532 ], [ -75.769426438579274, 7.49889659340306 ], [ -75.590005866377624, 7.569512436949367 ], [ -75.565433723387628, 7.606280218757092 ], [ -75.546675177617317, 7.689453437226348 ], [ -75.490296190217009, 7.738571886583259 ], [ -75.458566861071745, 7.807792467048728 ], [ -75.361673550394016, 7.883808499362715 ], [ -75.228761765842819, 8.045969143461207 ], [ -75.114401822386185, 8.067621568180812 ], [ -75.060942552356892, 8.05914663331049 ], [ -75.01735348207751, 8.074675401548518 ], [ -74.942577684112791, 8.072582506477488 ], [ -74.886224535134204, 8.154205431335583 ], [ -74.834883998597661, 8.188725287541956 ], [ -74.599549526989051, 7.99824595808451 ], [ -74.552472296759049, 7.929206243873068 ], [ -74.522344937169123, 7.771541449178528 ], [ -74.480900437904893, 7.724231675851172 ], [ -74.499038866050796, 7.678058783186259 ], [ -74.573556280697801, 7.605970160394577 ], [ -74.586113653822053, 7.492617906391274 ], [ -74.562600878028093, 7.423578193079152 ], [ -74.507978888914579, 7.362832545685421 ], [ -74.468653124042419, 7.361359768238685 ], [ -74.432686327012391, 7.396499742069409 ], [ -74.404419317597444, 7.457400418194709 ], [ -74.364370083212748, 7.488819688078138 ], [ -74.347420214371368, 7.432879950249514 ], [ -74.358323941097012, 7.391926378299729 ], [ -74.396461147563912, 7.343428046567055 ], [ -74.405065273643459, 7.19997427049617 ], [ -74.343906215999084, 7.010425116126214 ], [ -74.252878181183121, 6.99605906787167 ], [ -73.93023637600794, 7.300794988897621 ], [ -73.926722377635599, 7.126102810096597 ], [ -73.887810024812779, 7.019856065405065 ], [ -73.925068732136253, 6.97450999593957 ], [ -74.016096767851536, 6.927794500915468 ], [ -74.108571742591835, 6.790309353493853 ], [ -74.29272070999275, 6.654426173828824 ], [ -74.386435919981693, 6.626288357421743 ], [ -74.40876013916909, 6.567144680482613 ], [ -74.405840419999379, 6.47534149841141 ], [ -74.379201218561377, 6.423484197937398 ], [ -74.392223679679034, 6.402581082051256 ], [ -74.413333502938769, 6.404234727550602 ], [ -74.459506394704363, 6.33351553031747 ], [ -74.547201300999234, 6.262718817819177 ], [ -74.579834967709587, 6.215951645951691 ], [ -74.605130581111439, 6.136111557802167 ], [ -74.577690395795116, 6.078802395314256 ], [ -74.57425391268788, 6.001597805494328 ], [ -74.605130581111439, 5.978446764006947 ], [ -74.590816209700279, 5.918166205505941 ], [ -74.639882982213862, 5.861761378784593 ], [ -74.662491421341997, 5.771947739896291 ], [ -74.715098028850946, 5.772774563095595 ], [ -74.743726772572472, 5.699600734686157 ], [ -74.777264776847971, 5.689678859891444 ], [ -74.866768358273077, 5.743835761011553 ], [ -74.990946824636239, 5.71388926857486 ], [ -75.021539273118947, 5.67650137004216 ], [ -75.0911991031561, 5.659577337823862 ], [ -75.091715867992889, 5.596273709164336 ], [ -75.134426439128845, 5.535424708983101 ], [ -75.215765144046145, 5.502997747847758 ], [ -75.276123216013616, 5.433647976173177 ], [ -75.29141944025497, 5.473826401767042 ], [ -75.318032803271251, 5.463594469509133 ], [ -75.316172451297575, 5.517131252105571 ], [ -75.339917771987587, 5.586636054310418 ], [ -75.377486537673576, 5.619218044177387 ], [ -75.384617886306387, 5.674150092552736 ], [ -75.426114060615419, 5.694329738926285 ], [ -75.486653002434082, 5.669654242249464 ], [ -75.530577968598379, 5.688128567179604 ], [ -75.556131965317945, 5.721020616308408 ], [ -75.601142137099941, 5.735050766879397 ], [ -75.613234422230789, 5.735179958987885 ], [ -75.612536791139974, 5.700840969035482 ], [ -75.59246049665461, 5.683167628882927 ], [ -75.585742560970402, 5.518759060082573 ], [ -75.687415940992878, 5.528990994139065 ], [ -75.724726325159793, 5.558937486575758 ], [ -75.85779313844256, 5.489355170005069 ], [ -75.925411750252067, 5.493928533774806 ], [ -75.982591722430016, 5.521084500049653 ], [ -76.097907681194499, 5.643428452860803 ], [ -76.087572395249822, 5.727764390414279 ], [ -76.135579799667994, 5.837240911738661 ], [ -76.105142380816233, 5.929974269796674 ], [ -76.111266039096392, 5.975578722579996 ], [ -76.188729011334772, 5.998471380749606 ], [ -76.216970181428735, 6.03477407546319 ], [ -76.258207974218635, 6.173964545227591 ], [ -76.349778612293107, 6.192206326160999 ], [ -76.649217699137466, 6.158616645042116 ], [ -76.713735724623973, 6.178382880265701 ], [ -76.770708991226968, 6.286929226502593 ], [ -76.798019986233385, 6.300597641867682 ], [ -76.784377408390696, 6.362661037976522 ], [ -76.798019986233385, 6.368862208823884 ], [ -76.788718228163702, 6.39570811583684 ], [ -76.805461392329391, 6.423484197937398 ], [ -76.784377408390696, 6.437772731826101 ], [ -76.8032909819932, 6.451492824933894 ], [ -76.788098111438671, 6.483454698075832 ], [ -76.852641975346899, 6.540169583159695 ], [ -76.866336229133651, 6.581769111155552 ], [ -76.893182136146663, 6.582156683883852 ], [ -76.896127691939398, 6.614531969075074 ], [ -76.866284553189587, 6.639801744055205 ], [ -76.901062791814354, 6.650033678111754 ], [ -76.905739509270916, 6.693648585913479 ], [ -76.932172004234587, 6.672357896399774 ], [ -76.944858567668746, 6.702175198526561 ], [ -76.969947476394907, 6.704655667225268 ], [ -76.948837653135172, 6.731966661332365 ], [ -76.966614346075175, 6.752378851702645 ], [ -76.972789680299513, 6.810204779027345 ], [ -76.883286098874351, 6.844621283345532 ], [ -76.836157192700284, 6.840590521935042 ], [ -76.811042447351042, 6.862630520282266 ], [ -76.797244838978145, 6.889321396765013 ], [ -76.802257453218886, 6.926786811462193 ], [ -76.835640427863439, 6.985982164345387 ], [ -76.816597663051709, 7.008332221055127 ], [ -76.68340165855966, 7.026031398730083 ], [ -76.546097378291336, 6.991020616108528 ], [ -76.505272996651456, 7.074426378574515 ], [ -76.508347743653417, 7.186305854231762 ], [ -76.542945116024271, 7.266998603103048 ], [ -76.59785132507858, 7.312241318881775 ], [ -76.646220465601971, 7.321310532954726 ], [ -76.692496711054332, 7.354435126080205 ], [ -76.876878220653339, 7.565404161173092 ], [ -76.980851203120494, 7.63917226788584 ], [ -77.126372035840745, 7.780920722513315 ], [ -77.113323737200687, 7.788387966131722 ], [ -77.120170864993383, 7.842389838520205 ], [ -77.093350796402092, 7.837144680282734 ], [ -77.02167558476043, 7.898484605080455 ], [ -77.003459642248686, 7.99940867806805 ], [ -76.959870571969304, 8.065218613847946 ], [ -76.960516527115999, 8.169553331521001 ], [ -76.985457524345236, 8.256179684045151 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-COR", "NAME_1": "Córdoba" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -76.44483097368402, 8.869865946937113 ], [ -76.426869269999941, 8.910549221000053 ], [ -76.323963995999918, 8.941351630000042 ], [ -76.264271613999938, 8.996323960000041 ], [ -76.254953579999949, 9.070786851000037 ], [ -76.192616339999915, 9.134914455000057 ], [ -76.168120897999927, 9.246975002000056 ], [ -76.116932745999918, 9.265814520000049 ], [ -76.096099412999934, 9.333197333000044 ], [ -75.976925156999926, 9.382517238000048 ], [ -75.953284621999899, 9.402296152000076 ], [ -75.943798042999902, 9.440734321000093 ], [ -75.909982876999948, 9.428168036000045 ], [ -75.811024542999917, 9.443548895000049 ], [ -75.798207160999937, 9.418198960000041 ], [ -75.826730923999946, 9.426011460000041 ], [ -75.852853969999899, 9.412054755000042 ], [ -75.82485917899993, 9.412054755000042 ], [ -75.811879035999937, 9.391546942000048 ], [ -75.76203365799995, 9.421820380000042 ], [ -75.698272265352728, 9.416896877388979 ], [ -75.699094814973705, 9.354080512205883 ], [ -75.580884976360551, 9.30581472446994 ], [ -75.548535528691673, 9.26785838515633 ], [ -75.465336472700017, 9.237989407085479 ], [ -75.430222338190333, 9.152800807910921 ], [ -75.212845424876434, 9.04161896424381 ], [ -75.222431402886912, 9.02309296336955 ], [ -75.197652554321905, 8.983353787347369 ], [ -75.209202237093564, 8.92384837520234 ], [ -75.29681962812333, 8.896692409826812 ], [ -75.356609260209154, 8.84176036235084 ], [ -75.344491135757323, 8.678592027000434 ], [ -75.305268723672668, 8.491239122287652 ], [ -75.183544887586493, 8.401942247336819 ], [ -75.078099127672601, 8.453127753343153 ], [ -74.943326992047048, 8.486278183990976 ], [ -74.809407518042519, 8.350730902908822 ], [ -74.800958421593862, 8.249625962767936 ], [ -74.834883998597661, 8.188725287541956 ], [ -74.886224535134204, 8.154205431335583 ], [ -74.942577684112791, 8.072582506477488 ], [ -75.01735348207751, 8.074675401548518 ], [ -75.060942552356892, 8.05914663331049 ], [ -75.114401822386185, 8.067621568180812 ], [ -75.228761765842819, 8.045969143461207 ], [ -75.361673550394016, 7.883808499362715 ], [ -75.458566861071745, 7.807792467048728 ], [ -75.490296190217009, 7.738571886583259 ], [ -75.546675177617317, 7.689453437226348 ], [ -75.565433723387628, 7.606280218757092 ], [ -75.590005866377624, 7.569512436949367 ], [ -75.769426438579274, 7.49889659340306 ], [ -75.856992153664919, 7.367250880723532 ], [ -76.407759569248697, 7.38035085710635 ], [ -76.497573208137055, 7.600001531745306 ], [ -76.505117967020567, 7.74074229602013 ], [ -76.468324347690498, 7.874816798756228 ], [ -76.419490119173645, 7.979099840485219 ], [ -76.41938676638614, 8.09865326623526 ], [ -76.317945930360395, 8.280890203919739 ], [ -76.217331915735315, 8.410158799788746 ], [ -76.213688727952444, 8.452921046868823 ], [ -76.229114143402967, 8.577590440546373 ], [ -76.277534959870479, 8.64151418683025 ], [ -76.346316290764207, 8.674793808687298 ], [ -76.388845994746873, 8.738898423923104 ], [ -76.412307094596713, 8.839512436749544 ], [ -76.44483097368402, 8.869865946937113 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-SUC", "NAME_1": "Sucre" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -75.698272265352728, 9.416896877388979 ], [ -75.672607851999942, 9.409990145000052 ], [ -75.620632772999897, 9.452853128000072 ], [ -75.577167464999945, 9.56221350900006 ], [ -75.57636690399994, 9.62108590400004 ], [ -75.618031378999945, 9.689276434000078 ], [ -75.657794426999942, 9.705232142000057 ], [ -75.702806239999916, 9.690716519000091 ], [ -75.70513735399993, 9.700661772000046 ], [ -75.639945061999924, 9.783262609000076 ], [ -75.589515920999929, 9.964189339000086 ], [ -75.581576475907369, 10.09200204903731 ], [ -75.485645311182168, 10.143127956989588 ], [ -75.53654659724765, 10.04721649824279 ], [ -75.524144252854967, 10.032953802775751 ], [ -75.475749273909855, 10.039620063415157 ], [ -75.463941209619122, 9.965050971025505 ], [ -75.478203905086161, 9.915415757731012 ], [ -75.375083584240031, 9.877614447149028 ], [ -75.327205370131708, 9.881412665462108 ], [ -75.37446346661568, 9.640290432357574 ], [ -75.29793067126343, 9.677678330890217 ], [ -75.182769742129892, 9.643158473784524 ], [ -75.067763840828604, 9.539805609840982 ], [ -75.008413459213784, 9.53127899812722 ], [ -75.029549119995863, 9.483090724757119 ], [ -75.020454068400511, 9.46828542693089 ], [ -74.984668137624453, 9.457950140986213 ], [ -74.942035081753602, 9.469293118182861 ], [ -74.903975388753167, 9.437408759406708 ], [ -74.940794847404277, 9.34669078205394 ], [ -74.900409715336082, 9.176856186963448 ], [ -74.862789272806708, 9.14931264885962 ], [ -74.825349698329887, 9.076474718133738 ], [ -74.659209967865706, 8.96568044719487 ], [ -74.542188686758493, 8.814526881710208 ], [ -74.602960170775248, 8.727090358733051 ], [ -74.550508591997925, 8.462765408197015 ], [ -74.574408942318826, 8.40101207135001 ], [ -74.603735318030488, 8.4050428327605 ], [ -74.636007250434261, 8.331946518716848 ], [ -74.680216437438617, 8.309829006003838 ], [ -74.740006070423817, 8.311301785249157 ], [ -74.804963344582688, 8.279882514466465 ], [ -74.809407518042519, 8.350730902908822 ], [ -74.943326992047048, 8.486278183990976 ], [ -75.078099127672601, 8.453127753343153 ], [ -75.183544887586493, 8.401942247336819 ], [ -75.295114304881224, 8.48061961550286 ], [ -75.31914384641135, 8.52126312909013 ], [ -75.356609260209154, 8.84176036235084 ], [ -75.29681962812333, 8.896692409826812 ], [ -75.209202237093564, 8.92384837520234 ], [ -75.197652554321905, 8.983353787347369 ], [ -75.222431402886912, 9.02309296336955 ], [ -75.212845424876434, 9.04161896424381 ], [ -75.430222338190333, 9.152800807910921 ], [ -75.465336472700017, 9.237989407085479 ], [ -75.548535528691673, 9.26785838515633 ], [ -75.580884976360551, 9.30581472446994 ], [ -75.699094814973705, 9.354080512205883 ], [ -75.698272265352728, 9.416896877388979 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-BOL", "NAME_1": "Bolívar" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -75.581576475907369, 10.09200204903731 ], [ -75.589360705999923, 10.128261433000091 ], [ -75.540882941999939, 10.188544012000079 ], [ -75.530669725999928, 10.240668036000045 ], [ -75.64378608699991, 10.154375703000085 ], [ -75.703576645999931, 10.134428033000063 ], [ -75.688922325999897, 10.167966257000046 ], [ -75.630848761999914, 10.213446356000077 ], [ -75.615101691999939, 10.269517320000091 ], [ -75.592152472999942, 10.268622137000079 ], [ -75.592152472999942, 10.302720445000091 ], [ -75.583811001999948, 10.282375393000052 ], [ -75.515695766999897, 10.31899648600006 ], [ -75.523833787999934, 10.391506252000056 ], [ -75.539173956999946, 10.386297919000071 ], [ -75.551136847999942, 10.419419664000088 ], [ -75.578480597999942, 10.398342190000051 ], [ -75.565500454999949, 10.43305084800005 ], [ -75.502756313999953, 10.48773834800005 ], [ -75.522206183999913, 10.432928778000075 ], [ -75.493275519999941, 10.434637762000079 ], [ -75.489125128999945, 10.501369533000059 ], [ -75.510243292999917, 10.508205471000053 ], [ -75.504465298999946, 10.551581122000073 ], [ -75.524525519999941, 10.567084052000041 ], [ -75.463856574999909, 10.602728583000044 ], [ -75.461822068999936, 10.631048895000049 ], [ -75.424183722999942, 10.64329661700009 ], [ -75.403797980999911, 10.680121161000045 ], [ -75.30728105399993, 10.709540106000077 ], [ -75.27961178299995, 10.742743231000077 ], [ -75.263050910999937, 10.739813544000071 ], [ -75.262868211798548, 10.673974106819571 ], [ -75.227133958765194, 10.62826630304744 ], [ -75.266382209271512, 10.530675361278895 ], [ -75.25382483614726, 10.497369900100807 ], [ -75.174914923984545, 10.478611355229873 ], [ -75.176775275058901, 10.456571356882591 ], [ -75.132746955207779, 10.402569485393428 ], [ -75.07652299743836, 10.414351711262441 ], [ -74.982652756919208, 10.342754014885884 ], [ -74.917462937864286, 10.267409776140255 ], [ -74.944644741661477, 10.186639512903184 ], [ -74.943482021677937, 10.137469386702833 ], [ -74.852660692436984, 10.09307933254513 ], [ -74.807598842912284, 10.034452419543527 ], [ -74.81232723721223, 9.985463162295105 ], [ -74.87051489884351, 9.95065908524856 ], [ -74.878860643403982, 9.915493272096796 ], [ -74.874080573159915, 9.848985704326765 ], [ -74.815221117060901, 9.768680528183836 ], [ -74.828450282854249, 9.685791531454015 ], [ -74.781347215101903, 9.631324571072071 ], [ -74.799795701610321, 9.44862254539413 ], [ -74.770236782801248, 9.453066717954641 ], [ -74.742305671069857, 9.418314316852218 ], [ -74.703238287716772, 9.429631456526465 ], [ -74.677115852014936, 9.394724025793153 ], [ -74.636472338427666, 9.38216665356822 ], [ -74.53265438469208, 9.242976182005179 ], [ -74.512164679956015, 9.240831610990028 ], [ -74.478807542833806, 9.269279487558265 ], [ -74.43072262225121, 9.267496649950431 ], [ -74.413333502938769, 9.226517239578925 ], [ -74.35362138521873, 9.231245632080231 ], [ -74.311660122017031, 9.213908188711912 ], [ -74.294968634694726, 9.16646922417533 ], [ -74.238021205614132, 9.154325263100418 ], [ -74.197015956820962, 9.093062851769162 ], [ -74.141515468564023, 9.058310452465378 ], [ -74.153271856910635, 9.049008694395695 ], [ -74.090795050551151, 9.029164943907006 ], [ -74.060460985386158, 9.032472235805017 ], [ -74.043407761958633, 9.055209866142377 ], [ -74.010438199363421, 9.022963772160324 ], [ -74.016096767851536, 9.007409166399896 ], [ -73.984057380343813, 8.989270738253936 ], [ -73.872100389421405, 8.973276882022446 ], [ -73.882409837843738, 8.914184881926758 ], [ -73.807582363934955, 8.816593940158214 ], [ -73.829648199804581, 8.643581244378936 ], [ -73.796368577947476, 8.579450792520049 ], [ -73.754691534686572, 8.388738918166553 ], [ -73.767429775863434, 8.358637396998233 ], [ -73.755415005098371, 8.329000962924113 ], [ -73.796368577947476, 8.212935696225372 ], [ -73.785645718375179, 8.16146596937898 ], [ -73.855357225255716, 8.105448717184515 ], [ -73.872255419052351, 8.044909776265172 ], [ -73.816858282683597, 7.80141042724938 ], [ -73.836004401182151, 7.694776108930284 ], [ -73.823291999326273, 7.672038479492244 ], [ -73.830475023003885, 7.610078437070229 ], [ -73.913183152580416, 7.494865831093193 ], [ -73.899385546006158, 7.421252753112071 ], [ -73.93023637600794, 7.300794988897621 ], [ -74.252878181183121, 6.99605906787167 ], [ -74.343906215999084, 7.010425116126214 ], [ -74.398269822694147, 7.168554998814159 ], [ -74.396461147563912, 7.343428046567055 ], [ -74.358323941097012, 7.391926378299729 ], [ -74.347420214371368, 7.432879950249514 ], [ -74.364370083212748, 7.488819688078138 ], [ -74.404419317597444, 7.457400418194709 ], [ -74.445993008070843, 7.380893459465597 ], [ -74.489065314412699, 7.357768256399879 ], [ -74.528701137647374, 7.381746121086621 ], [ -74.581772834049048, 7.466779689730856 ], [ -74.573556280697801, 7.605970160394577 ], [ -74.499038866050796, 7.678058783186259 ], [ -74.480900437904893, 7.724231675851172 ], [ -74.522344937169123, 7.771541449178528 ], [ -74.552472296759049, 7.929206243873068 ], [ -74.599549526989051, 7.99824595808451 ], [ -74.834883998597661, 8.188725287541956 ], [ -74.800958421593862, 8.249625962767936 ], [ -74.804963344582688, 8.279882514466465 ], [ -74.740006070423817, 8.311301785249157 ], [ -74.657117071895357, 8.317451280152454 ], [ -74.620917730868598, 8.349103094931877 ], [ -74.603735318030488, 8.4050428327605 ], [ -74.574408942318826, 8.40101207135001 ], [ -74.567510138582008, 8.413078518059137 ], [ -74.550508591997925, 8.462765408197015 ], [ -74.562342494710322, 8.570459092812882 ], [ -74.585751918616154, 8.611800238390288 ], [ -74.602960170775248, 8.727090358733051 ], [ -74.542188686758493, 8.814526881710208 ], [ -74.659209967865706, 8.96568044719487 ], [ -74.825349698329887, 9.076474718133738 ], [ -74.862789272806708, 9.14931264885962 ], [ -74.900409715336082, 9.176856186963448 ], [ -74.940794847404277, 9.34669078205394 ], [ -74.903975388753167, 9.437408759406708 ], [ -74.942035081753602, 9.469293118182861 ], [ -74.984668137624453, 9.457950140986213 ], [ -75.020454068400511, 9.46828542693089 ], [ -75.029549119995863, 9.483090724757119 ], [ -75.008413459213784, 9.53127899812722 ], [ -75.067763840828604, 9.539805609840982 ], [ -75.182769742129892, 9.643158473784524 ], [ -75.29793067126343, 9.677678330890217 ], [ -75.37446346661568, 9.640290432357574 ], [ -75.327205370131708, 9.881412665462108 ], [ -75.375083584240031, 9.877614447149028 ], [ -75.478203905086161, 9.915415757731012 ], [ -75.463941209619122, 9.965050971025505 ], [ -75.475749273909855, 10.039620063415157 ], [ -75.524144252854967, 10.032953802775751 ], [ -75.53654659724765, 10.04721649824279 ], [ -75.485645311182168, 10.143127956989588 ], [ -75.581576475907369, 10.09200204903731 ] ] ], [ [ [ -75.229682862134098, 10.763420758879358 ], [ -75.249501105999911, 10.747748114000046 ], [ -75.270008917999917, 10.759100653000075 ], [ -75.267404751999948, 10.795314846000053 ], [ -75.228736899568716, 10.810866721483071 ], [ -75.229682862134098, 10.763420758879358 ] ] ], [ [ [ -75.586801161999915, 10.367791823000061 ], [ -75.575830134999933, 10.377872464000063 ], [ -75.535319918999903, 10.350646060000088 ], [ -75.590661324999928, 10.319043831000045 ], [ -75.586801161999915, 10.367791823000061 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-ATL", "NAME_1": "Atlántico" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -75.256337043719554, 10.709337773519394 ], [ -75.222238735999952, 10.73468659100007 ], [ -75.228736899568716, 10.810866721483071 ], [ -75.215687628999945, 10.826605536000045 ], [ -75.049549933999913, 10.901190497000073 ], [ -75.023589647999927, 10.974310614000046 ], [ -74.962809279999931, 10.994894226000042 ], [ -74.923570574999928, 11.045671746000039 ], [ -74.861510172999942, 11.048833740000077 ], [ -74.845338024999933, 11.062129538000079 ], [ -74.8474980055788, 11.087667762584534 ], [ -74.774267544211796, 11.010025945840709 ], [ -74.724709846182463, 10.900316881418917 ], [ -74.742305671069857, 10.840940660483056 ], [ -74.722642787734458, 10.774820665441325 ], [ -74.728637254805449, 10.583953762356259 ], [ -74.748119269188919, 10.550338242815656 ], [ -74.806720343768859, 10.51034068437508 ], [ -74.836072557002865, 10.406135158810514 ], [ -74.917462937864286, 10.267409776140255 ], [ -74.982652756919208, 10.342754014885884 ], [ -75.07652299743836, 10.414351711262441 ], [ -75.132746955207779, 10.402569485393428 ], [ -75.176775275058901, 10.456571356882591 ], [ -75.17134924966814, 10.476363430527897 ], [ -75.25382483614726, 10.497369900100807 ], [ -75.266382209271512, 10.530675361278895 ], [ -75.227133958765194, 10.62826630304744 ], [ -75.262868211798548, 10.673974106819571 ], [ -75.256337043719554, 10.709337773519394 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-MAG", "NAME_1": "Magdalena" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -74.8474980055788, 11.087667762584534 ], [ -74.84437231499993, 11.10966965700004 ], [ -74.5229509159999, 10.995924341000091 ], [ -74.403472459999932, 10.982855536000045 ], [ -74.297829547999925, 10.991499283000053 ], [ -74.361805792999917, 10.971665757000039 ], [ -74.491566535999937, 10.979478257000039 ], [ -74.517445441999939, 10.926662502000056 ], [ -74.481760219999899, 10.850816148000092 ], [ -74.525013800999943, 10.88344961100006 ], [ -74.536366339999915, 10.871893622000073 ], [ -74.581369594999899, 10.888088283000059 ], [ -74.596994594999899, 10.86782461100006 ], [ -74.598459438999953, 10.781927802000041 ], [ -74.564279751999948, 10.830959377000056 ], [ -74.543812628999945, 10.80923086100006 ], [ -74.543812628999945, 10.76203034100007 ], [ -74.499663865999935, 10.764715887000079 ], [ -74.495432094999899, 10.781927802000041 ], [ -74.515614386999914, 10.778225002000056 ], [ -74.523304816999939, 10.802964585000041 ], [ -74.509632941999939, 10.844549872000073 ], [ -74.477121548999946, 10.82758209800005 ], [ -74.456613735999952, 10.748032945000091 ], [ -74.402088995999918, 10.748032945000091 ], [ -74.362172003999945, 10.77570221600007 ], [ -74.280425584999932, 10.989732164000088 ], [ -74.218129035999937, 11.079087632000039 ], [ -74.235951300999943, 11.125148830000057 ], [ -74.233631964999915, 11.241156317000048 ], [ -74.187489386999914, 11.316961981000077 ], [ -74.151844855999911, 11.319728908000059 ], [ -74.153391079999949, 11.343654690000051 ], [ -74.139068162999934, 11.323716539000088 ], [ -74.126088019999941, 11.343654690000051 ], [ -74.112416144999941, 11.337388414000088 ], [ -74.112416144999941, 11.357896226000037 ], [ -74.083851691999939, 11.330633856000077 ], [ -74.065419074999909, 11.351752020000049 ], [ -74.004628058999913, 11.355292059000078 ], [ -73.951039191999939, 11.320298570000091 ], [ -73.826039191999939, 11.276760158000059 ], [ -73.565581834999932, 11.277085679000038 ], [ -73.581808031015782, 11.191461900546244 ], [ -73.637773607266126, 11.139165351399811 ], [ -73.651002773958851, 10.999819851105258 ], [ -73.605785894803205, 10.845514024252793 ], [ -73.64560258698981, 10.77109996239335 ], [ -73.58968868668353, 10.763348497035508 ], [ -73.563721279713263, 10.744021511383608 ], [ -73.614079963419556, 10.65046133102561 ], [ -73.597595180772942, 10.549046332522209 ], [ -73.570878464969155, 10.51243358034543 ], [ -73.77045284692133, 10.391174832252716 ], [ -73.920159470683018, 10.357171739084492 ], [ -74.050539109692124, 10.169896348737495 ], [ -74.069090948988105, 10.079488429747244 ], [ -74.008009405709515, 9.958307196020257 ], [ -73.841766324256469, 9.789945380175141 ], [ -73.842748176187342, 9.739819241364899 ], [ -73.784224615973244, 9.597450670012392 ], [ -73.800709397720539, 9.577839464419753 ], [ -73.8257983064467, 9.597218126015662 ], [ -73.876053635566791, 9.569287014284271 ], [ -74.027103848263948, 9.591171983000606 ], [ -74.137097134425176, 9.498231920266903 ], [ -74.000955573241072, 9.399064846465478 ], [ -73.994676887128605, 9.34227244701583 ], [ -73.955738694984746, 9.295040188054202 ], [ -73.958529222045968, 9.20292694672122 ], [ -73.878689133896387, 9.184452622690344 ], [ -73.8550471668932, 9.117970893342033 ], [ -73.799805061054712, 9.055597438870677 ], [ -73.870395067078675, 8.887674871697982 ], [ -73.884890305643069, 8.943640447948326 ], [ -73.872100389421405, 8.973276882022446 ], [ -73.984057380343813, 8.989270738253936 ], [ -74.016096767851536, 9.007409166399896 ], [ -74.010438199363421, 9.022963772160324 ], [ -74.043407761958633, 9.055209866142377 ], [ -74.060460985386158, 9.032472235805017 ], [ -74.090795050551151, 9.029164943907006 ], [ -74.153271856910635, 9.049008694395695 ], [ -74.141515468564023, 9.058310452465378 ], [ -74.197015956820962, 9.093062851769162 ], [ -74.238021205614132, 9.154325263100418 ], [ -74.294968634694726, 9.16646922417533 ], [ -74.311660122017031, 9.213908188711912 ], [ -74.35362138521873, 9.231245632080231 ], [ -74.413333502938769, 9.226517239578925 ], [ -74.43072262225121, 9.267496649950431 ], [ -74.478807542833806, 9.269279487558265 ], [ -74.512164679956015, 9.240831610990028 ], [ -74.53265438469208, 9.242976182005179 ], [ -74.636472338427666, 9.38216665356822 ], [ -74.677115852014936, 9.394724025793153 ], [ -74.703238287716772, 9.429631456526465 ], [ -74.742305671069857, 9.418314316852218 ], [ -74.770236782801248, 9.453066717954641 ], [ -74.799795701610321, 9.44862254539413 ], [ -74.781347215101903, 9.631324571072071 ], [ -74.828450282854249, 9.685791531454015 ], [ -74.815221117060901, 9.768680528183836 ], [ -74.874080573159915, 9.848985704326765 ], [ -74.878860643403982, 9.915493272096796 ], [ -74.87051489884351, 9.95065908524856 ], [ -74.81232723721223, 9.985463162295105 ], [ -74.804369066279378, 10.025331529526454 ], [ -74.852660692436984, 10.09307933254513 ], [ -74.932113206958945, 10.12604889603972 ], [ -74.947745327085158, 10.165633043330274 ], [ -74.924310064757663, 10.254154771025867 ], [ -74.836072557002865, 10.406135158810514 ], [ -74.806720343768859, 10.51034068437508 ], [ -74.748119269188919, 10.550338242815656 ], [ -74.725846726844964, 10.605115261560059 ], [ -74.722642787734458, 10.774820665441325 ], [ -74.742305671069857, 10.840940660483056 ], [ -74.728637254805449, 10.919127102233972 ], [ -74.759022996813826, 10.954447944117305 ], [ -74.774267544211796, 11.010025945840709 ], [ -74.8474980055788, 11.087667762584534 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-SAP", "NAME_1": "San Andrés y Providencia" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -81.711496548999946, 12.522935289000088 ], [ -81.716949022999927, 12.56321849200009 ], [ -81.691029425999943, 12.59125397300005 ], [ -81.704741990999935, 12.504461981000077 ], [ -81.717396613999938, 12.502427476000037 ], [ -81.711496548999946, 12.522935289000088 ] ] ], [ [ [ -81.382639126999948, 13.319159247000073 ], [ -81.386138475999928, 13.341457424000055 ], [ -81.365345831999946, 13.373968817000048 ], [ -81.346302863999938, 13.348700262000079 ], [ -81.382639126999948, 13.319159247000073 ] ] ], [ [ [ -80.089914516999897, 13.578355210000041 ], [ -80.089426235999952, 13.576849677000041 ], [ -80.090402798999946, 13.576605536000045 ], [ -80.090891079999949, 13.578029690000051 ], [ -80.089914516999897, 13.578355210000041 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-X01~", "NAME_1": null }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -81.611724412999934, 3.958970445000091 ], [ -81.601429816999939, 3.988348700000074 ], [ -81.58226477799991, 3.991522528000075 ], [ -81.58031165299991, 3.97601959800005 ], [ -81.611724412999934, 3.958970445000091 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-CAQ", "NAME_1": "Caquetá" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -75.155587938332701, 2.523670558749302 ], [ -75.122385829942061, 2.534109198380804 ], [ -75.003194139397976, 2.638185532736145 ], [ -75.003504197760492, 2.685107734234521 ], [ -75.049573736738523, 2.724381822263297 ], [ -75.052906867058255, 2.768203437438672 ], [ -75.020299037870302, 2.835434474721239 ], [ -74.922578904892532, 2.941732896256156 ], [ -74.897515834588091, 2.950724595963322 ], [ -74.712565884208175, 2.896955268470833 ], [ -74.662465582920277, 2.795591945911553 ], [ -74.59644894066605, 2.721229559996175 ], [ -74.659442511862437, 2.382645575432946 ], [ -74.645851609963813, 2.318205064312281 ], [ -74.543738980369653, 2.181934311918951 ], [ -74.549190843282759, 2.142918606308626 ], [ -74.6159051166278, 2.043131414882907 ], [ -74.606835904353488, 1.962361152545157 ], [ -74.550534431318965, 1.871358954352274 ], [ -74.510821091919865, 1.843918769035952 ], [ -73.917834031615257, 1.634732571550899 ], [ -73.757482061747737, 1.6382465681246 ], [ -73.675058153011321, 1.624500637494407 ], [ -73.665213792582449, 1.584037991060427 ], [ -73.563927985288274, 1.436811835098126 ], [ -73.496877814259733, 1.381156318109561 ], [ -73.443186001133029, 1.302349757835032 ], [ -73.425745204977204, 1.209435533523049 ], [ -73.247254807863101, 1.028309638079349 ], [ -73.199040696970599, 1.009447740420853 ], [ -73.175682949908207, 0.968468329150085 ], [ -73.135297817840012, 0.941544907771288 ], [ -73.062899135786495, 0.924698390818094 ], [ -73.011351894574261, 0.947746080417289 ], [ -72.938178067064143, 1.024743963762887 ], [ -72.893064540696002, 1.046551418113438 ], [ -72.870611131198757, 1.157655748314141 ], [ -72.82557512099504, 1.194759426006669 ], [ -72.760747036246698, 1.153418280429264 ], [ -72.738629522634369, 1.197343248392201 ], [ -72.670700853361666, 1.191090399802079 ], [ -72.544507005393996, 1.103602199981538 ], [ -72.474097865624003, 1.085102037528998 ], [ -72.428105841911076, 1.042417303915443 ], [ -72.40291358129673, 0.947332668367949 ], [ -72.362425096441029, 0.932966620113405 ], [ -72.347051357833891, 0.876846015131491 ], [ -72.312247280787346, 0.883615626759763 ], [ -72.311523811274867, 0.813542385572646 ], [ -72.264084845838966, 0.784655260331988 ], [ -72.238117437969379, 0.736596178171055 ], [ -72.152463751700793, 0.727707831251394 ], [ -72.098410204267509, 0.704143377714672 ], [ -72.078023851419573, 0.669210110358279 ], [ -72.019655320836364, 0.655464178828765 ], [ -71.995083176947048, 0.576295885146976 ], [ -71.979115160036599, 0.564513658378644 ], [ -71.96084754068147, 0.580326646557467 ], [ -71.932787237740797, 0.555211900308962 ], [ -71.936404588001324, 0.486688950934308 ], [ -71.84302527479656, 0.417235826472222 ], [ -71.847004361162305, 0.355534166468601 ], [ -71.787085536967936, 0.373310859408605 ], [ -71.688977831261866, 0.258279119685596 ], [ -71.538547736189059, 0.177663886079472 ], [ -71.421423102294341, 0.191616523183995 ], [ -71.32233354375802, 0.133222154179066 ], [ -71.389719610671477, 0.067489731865635 ], [ -71.689055344728388, -0.085679212525633 ], [ -71.774192267958767, -0.224688816036064 ], [ -71.845040656401181, -0.245876152762264 ], [ -72.012188076318637, -0.247581475104994 ], [ -72.128640916644997, -0.326336357636819 ], [ -72.232381354216102, -0.467309665908374 ], [ -72.24238074427592, -0.586940606024143 ], [ -72.279820318752684, -0.621253756655562 ], [ -72.324520433071541, -0.629263603532479 ], [ -72.421852993320954, -0.556554864015766 ], [ -72.478412848773928, -0.59402027781357 ], [ -72.56442827024847, -0.684970798263748 ], [ -72.749894986364495, -0.559242039188746 ], [ -72.884822149822355, -0.601720065428708 ], [ -72.997425095891458, -0.526582533157409 ], [ -73.081295946350849, -0.593555189820165 ], [ -73.16532182464249, -0.608386326068114 ], [ -73.205500251135675, -0.604717298964204 ], [ -73.331771612569867, -0.507307223449629 ], [ -73.388977424068855, -0.531336764979756 ], [ -73.554212816068571, -0.520639743829122 ], [ -73.586071337322323, -0.470565280962944 ], [ -73.640434943118123, -0.457852878207746 ], [ -73.643561366963525, -0.421886082077037 ], [ -73.695857917009278, -0.39377410229298 ], [ -73.728362393409725, -0.386539401771984 ], [ -73.787325202296245, -0.407365004191604 ], [ -73.941682705092774, -0.369744560762854 ], [ -74.011420051294294, -0.335121351768976 ], [ -74.116684943155576, -0.246341240755669 ], [ -74.168774786726999, -0.258330173099012 ], [ -74.19290768104463, -0.220451348151187 ], [ -74.240424159946997, -0.22789275514657 ], [ -74.282023687942853, -0.149396254133819 ], [ -74.327576463882679, -0.122834567960979 ], [ -74.399458381099407, -0.132291354762231 ], [ -74.4131784742072, -0.09027841561641 ], [ -74.429637416633454, -0.082992039151293 ], [ -74.469790004704919, -0.125780124653033 ], [ -74.592676560774635, -0.102060641485423 ], [ -74.609703945780439, -0.063561699812624 ], [ -74.663835007579507, -0.054156588955436 ], [ -74.684066331695817, 0.00630483579954 ], [ -74.658279791878897, 0.053847154022947 ], [ -74.695590176045755, 0.074621080498446 ], [ -74.676702439965595, 0.109864407116675 ], [ -74.682903611712277, 0.150947170275685 ], [ -74.742874111850767, 0.200298162730007 ], [ -74.855347866710645, 0.221898912404868 ], [ -74.962447272123882, 0.270836492809906 ], [ -74.989034796718499, 0.360908515015922 ], [ -74.996166143552671, 0.469945786768619 ], [ -75.072337206396924, 0.472943020304115 ], [ -75.095694952559995, 0.507462877409864 ], [ -75.164863857980663, 0.488445950120479 ], [ -75.186697149853558, 0.496197415478321 ], [ -75.21604936398694, 0.55190460931027 ], [ -75.212432013726414, 0.619497381798737 ], [ -75.251421881814395, 0.679700425933902 ], [ -75.262868211798548, 0.728948066500038 ], [ -75.31759355280019, 0.751323960732179 ], [ -75.459083625009271, 0.749463608758504 ], [ -75.498616096355761, 0.763571275493973 ], [ -75.55985266836592, 0.828580227395548 ], [ -75.600082769903906, 0.847442125054044 ], [ -75.732296921565649, 0.84811391772314 ], [ -75.828105028424318, 0.879481513461087 ], [ -75.899573533591706, 0.953843899376466 ], [ -75.932749802661249, 1.030738429934559 ], [ -76.06051978176248, 1.043657538264767 ], [ -76.15960934119812, 1.132644354853085 ], [ -76.255004035108129, 1.137501939462936 ], [ -76.295337491232203, 1.184785875267892 ], [ -76.282289190793506, 1.339970201263782 ], [ -76.164647792961262, 1.562695623803961 ], [ -76.145294968887697, 1.575511379346665 ], [ -75.980576340825451, 1.563729153477652 ], [ -75.840998298332806, 1.680621243375697 ], [ -75.626386074557672, 1.964634914769476 ], [ -75.551222703864653, 2.032899481725678 ], [ -75.421463181580577, 2.247408351813988 ], [ -75.305966355662747, 2.345076808847637 ], [ -75.231448941015799, 2.531318671319639 ], [ -75.207858649057414, 2.546718248348498 ], [ -75.155587938332701, 2.523670558749302 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-HUI", "NAME_1": "Huila" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -74.897515834588091, 2.950724595963322 ], [ -74.976787481956706, 2.892226874170888 ], [ -75.052906867058255, 2.768203437438672 ], [ -75.049573736738523, 2.724381822263297 ], [ -75.003504197760492, 2.685107734234521 ], [ -75.003194139397976, 2.638185532736145 ], [ -75.122385829942061, 2.534109198380804 ], [ -75.155587938332701, 2.523670558749302 ], [ -75.207858649057414, 2.546718248348498 ], [ -75.231448941015799, 2.531318671319639 ], [ -75.305966355662747, 2.345076808847637 ], [ -75.421463181580577, 2.247408351813988 ], [ -75.551222703864653, 2.032899481725678 ], [ -75.626386074557672, 1.964634914769476 ], [ -75.840998298332806, 1.680621243375697 ], [ -75.960164151354491, 1.573030911547335 ], [ -76.006337043120027, 1.560111803217126 ], [ -76.145294968887697, 1.575511379346665 ], [ -76.346936408388501, 1.638918361693015 ], [ -76.408586392448058, 1.685168768723713 ], [ -76.504084439145515, 1.823093167515651 ], [ -76.576896532349053, 1.879678860491026 ], [ -76.600719367404849, 1.958640447698485 ], [ -76.562272101676115, 2.024114488492842 ], [ -76.566974656655077, 2.100027167120061 ], [ -76.5365889146467, 2.129069321991608 ], [ -76.455405240259608, 2.112791245819324 ], [ -76.419438443229581, 2.126175442142937 ], [ -76.421531338300611, 2.163847561515752 ], [ -76.396519944839554, 2.186223455747893 ], [ -76.357323371176619, 2.271541246131619 ], [ -76.392566697794848, 2.366780911310002 ], [ -76.378898282429759, 2.419955958700541 ], [ -76.348719245097072, 2.413186347072269 ], [ -76.277689988602106, 2.35634227077918 ], [ -76.233661668750983, 2.351794745431164 ], [ -76.050081143030297, 2.420627753168276 ], [ -75.966184455048563, 2.490959376773787 ], [ -75.877533535244424, 2.426622219339947 ], [ -75.844486457384107, 2.428120836107666 ], [ -75.795342169605419, 2.474732978344264 ], [ -75.823376634124372, 2.530388495332772 ], [ -75.781027798194316, 2.669604804418157 ], [ -75.806039190756053, 2.71998932474753 ], [ -76.031245082894259, 2.929537258337803 ], [ -76.001091884882555, 2.949949448708082 ], [ -75.974013434772189, 2.948166611999511 ], [ -75.854692552119559, 2.890909125455778 ], [ -75.812472907398728, 2.891916815808372 ], [ -75.781570400553505, 2.948244127264672 ], [ -75.627548793641893, 3.090302639355286 ], [ -75.569645351951408, 3.233291327432823 ], [ -75.492311570922254, 3.347263699060477 ], [ -75.387046678161653, 3.378708808264889 ], [ -75.355317349016445, 3.408655299802206 ], [ -75.316120775353511, 3.411755886125206 ], [ -75.257778083191965, 3.373644517180708 ], [ -75.213258836925775, 3.410128079047581 ], [ -75.178015510307546, 3.388708197425387 ], [ -75.177602098258205, 3.40547720001274 ], [ -75.142642991580772, 3.432142238973142 ], [ -75.03564693895504, 3.434157620577707 ], [ -75.067841356093709, 3.3014267031798 ], [ -74.966142136750193, 3.278844102473329 ], [ -74.908884650206403, 3.289928697251582 ], [ -74.777109748116345, 3.441392320199384 ], [ -74.77452592573087, 3.514772854183889 ], [ -74.733882412143601, 3.560325629224394 ], [ -74.727991298759434, 3.608668931326122 ], [ -74.563531053115582, 3.772121487516642 ], [ -74.493561163816651, 3.70401194929201 ], [ -74.498367071583061, 3.675150662473072 ], [ -74.542602097908457, 3.583528347555159 ], [ -74.6159051166278, 3.48505890484455 ], [ -74.651742723347979, 3.259982204814889 ], [ -74.681353319000436, 3.210398668363837 ], [ -74.824600388597048, 3.107381700305211 ], [ -74.897515834588091, 2.950724595963322 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-GUV", "NAME_1": "Guaviare" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -73.082897915006754, 0.924336656511457 ], [ -73.175682949908207, 0.968468329150085 ], [ -73.199040696970599, 1.009447740420853 ], [ -73.247254807863101, 1.028309638079349 ], [ -73.425745204977204, 1.209435533523049 ], [ -73.443186001133029, 1.302349757835032 ], [ -73.496877814259733, 1.381156318109561 ], [ -73.563927985288274, 1.436811835098126 ], [ -73.665213792582449, 1.584037991060427 ], [ -73.675058153011321, 1.624500637494407 ], [ -73.661131354328518, 1.641967271172632 ], [ -73.660330369550877, 2.253402817985659 ], [ -73.626637335644489, 2.366367499260662 ], [ -73.598266975240676, 2.386366278480978 ], [ -73.585399542854589, 2.362543443425182 ], [ -73.530415819434495, 2.383110663426351 ], [ -73.510313687426731, 2.352414862156138 ], [ -73.455071580688866, 2.347195543239707 ], [ -73.444684617900805, 2.385901191386836 ], [ -73.42685624901668, 2.331020819854928 ], [ -73.395488654178052, 2.344094956916706 ], [ -73.376704270885398, 2.329418850299703 ], [ -73.36344926577101, 2.353758450192288 ], [ -73.346344367298684, 2.349055894314063 ], [ -73.344122281018429, 2.328643703943783 ], [ -73.317741461998878, 2.347247219183828 ], [ -73.250355394186101, 2.34378489855419 ], [ -73.247125616653875, 2.371948554282369 ], [ -73.215318773142826, 2.388381659186223 ], [ -73.173202481209501, 2.385126044131596 ], [ -73.144754604641264, 2.36171662022582 ], [ -73.124445767058489, 2.394169419782884 ], [ -73.102431607132928, 2.382077135551356 ], [ -73.061323004652934, 2.413082994284764 ], [ -73.020576138278159, 2.411274319154472 ], [ -72.930452440128022, 2.467756659342342 ], [ -72.937635463805577, 2.513645331167083 ], [ -72.819942390029269, 2.596741034371234 ], [ -72.790305955955091, 2.600978502256055 ], [ -72.762297328958539, 2.565890204369452 ], [ -72.737208422031017, 2.559534002991825 ], [ -72.703334520072019, 2.607489732365252 ], [ -72.670442470943271, 2.613897609686944 ], [ -72.641994595274355, 2.562789618046452 ], [ -72.610032722132416, 2.620512193482909 ], [ -72.576727260954328, 2.579584459055525 ], [ -72.573445808377357, 2.629400540402628 ], [ -72.535747849683503, 2.641596178320981 ], [ -72.553679572254453, 2.675444240958939 ], [ -72.507274135592866, 2.665212306902447 ], [ -72.474847175356842, 2.687949937239807 ], [ -72.421904670164395, 2.694202785829873 ], [ -72.366533373116681, 2.738076076949369 ], [ -72.309818488032761, 2.71673370969296 ], [ -72.283747728275046, 2.752390448360472 ], [ -72.252302619070576, 2.697613430515389 ], [ -72.247780931244961, 2.754870917059179 ], [ -72.193469001393282, 2.772957668361698 ], [ -72.197370571594604, 2.833884182009399 ], [ -72.1807049217947, 2.853753770020433 ], [ -72.121044480918044, 2.867086290399982 ], [ -72.07877315935383, 2.827295437534417 ], [ -71.980381231908325, 2.799105943384575 ], [ -71.83728919104334, 2.830938625317287 ], [ -71.792046475264613, 2.861195177015816 ], [ -71.759309454867434, 2.816727606693689 ], [ -71.743160569904376, 2.881994941013716 ], [ -71.683138393821821, 2.840085353756081 ], [ -71.649548712702938, 2.86336558735195 ], [ -71.643657600218091, 2.819311428179844 ], [ -71.622625292223461, 2.815719916341038 ], [ -71.56149207210143, 2.855691637259213 ], [ -71.468707038099296, 2.852280992573753 ], [ -71.443411423798182, 2.876258857260439 ], [ -71.382381558262296, 2.845924791196126 ], [ -71.35685339996445, 2.875328681273629 ], [ -71.329594081801417, 2.858094590692815 ], [ -71.293394740774659, 2.905430203341211 ], [ -71.273757696760299, 2.871582138904557 ], [ -71.225130173818457, 2.855071518735599 ], [ -71.169061244780607, 2.884087836084746 ], [ -71.128107672830822, 2.864373276805281 ], [ -71.111803758236817, 2.876956488351254 ], [ -71.082839117731112, 2.864063219342086 ], [ -71.041007045738581, 2.873158270937438 ], [ -70.986514247834236, 2.854683946007299 ], [ -70.980132208934265, 2.813006902746338 ], [ -70.969900274877773, 2.865380968057195 ], [ -70.923598191903011, 2.828458157517957 ], [ -70.904064500676157, 2.857629502699353 ], [ -70.889595099634107, 2.815874945072665 ], [ -70.848641526785002, 2.828845730246258 ], [ -70.811279465774703, 2.791974596550403 ], [ -70.748208381111908, 2.813937078733204 ], [ -70.734824184788295, 2.782517807950455 ], [ -70.686403368320782, 2.823419704855496 ], [ -70.694774950403598, 2.869411729467743 ], [ -70.650204027294023, 2.832333889297558 ], [ -70.592843187063409, 2.841868191363915 ], [ -70.499748093799496, 2.78453318955502 ], [ -70.895692918593284, 2.62092560553225 ], [ -70.909387173279413, 2.601908678242921 ], [ -70.747071498650712, 2.529044908195942 ], [ -70.676093919898449, 2.437887681271491 ], [ -70.622324592406017, 2.327610175169411 ], [ -70.590750291992379, 2.301358547359087 ], [ -70.50287451944348, 2.275882065904625 ], [ -70.492875129383719, 2.244772854383712 ], [ -70.407298956581542, 2.263324692780316 ], [ -70.304256151000573, 2.226427721562118 ], [ -70.284619106986213, 2.25826040349483 ], [ -70.237257656815416, 2.265598455904012 ], [ -70.189922045066339, 2.251852525273819 ], [ -70.051403367971034, 2.286837470372973 ], [ -69.99507605741411, 2.219554755347644 ], [ -69.999933641124642, 2.19774730099715 ], [ -70.103028124448372, 2.122248033519895 ], [ -70.104965989888512, 2.1011640495812 ], [ -70.201652594991231, 2.031245836226333 ], [ -70.444454312016887, 1.988354397037767 ], [ -70.499257168283691, 1.951819159226829 ], [ -70.672786628000495, 1.901176256479062 ], [ -70.745417853151366, 1.917971095689495 ], [ -70.904529587770242, 1.918591213313846 ], [ -70.967729865440901, 1.853272203049698 ], [ -71.15983700197603, 1.756223862741081 ], [ -71.263758307599801, 1.673386541955324 ], [ -71.390778977867512, 1.732245998953658 ], [ -71.405248378909562, 1.598662420834046 ], [ -71.441008470364579, 1.548019517186958 ], [ -71.552448697349519, 1.262042141031998 ], [ -71.553120490018614, 1.216463528469035 ], [ -71.505061407857681, 1.115126044331475 ], [ -71.527824876616762, 1.116521308311746 ], [ -71.552913784443604, 1.160963040212152 ], [ -71.609861212624878, 1.042520656702948 ], [ -71.673113166239602, 0.981955878261147 ], [ -71.724660406552516, 0.986606757295988 ], [ -71.756699794959559, 0.971310533054634 ], [ -71.786542934608747, 0.916946926359572 ], [ -72.035752529855358, 0.664042467385968 ], [ -72.078023851419573, 0.669210110358279 ], [ -72.098410204267509, 0.704143377714672 ], [ -72.152463751700793, 0.727707831251394 ], [ -72.238117437969379, 0.736596178171055 ], [ -72.264084845838966, 0.784655260331988 ], [ -72.311523811274867, 0.813542385572646 ], [ -72.312247280787346, 0.883615626759763 ], [ -72.347051357833891, 0.876846015131491 ], [ -72.362425096441029, 0.932966620113405 ], [ -72.40291358129673, 0.947332668367949 ], [ -72.428105841911076, 1.042417303915443 ], [ -72.474097865624003, 1.085102037528998 ], [ -72.544507005393996, 1.103602199981538 ], [ -72.703231167284514, 1.203854478501398 ], [ -72.738629522634369, 1.197343248392201 ], [ -72.760747036246698, 1.153418280429264 ], [ -72.818159553320697, 1.197756659542222 ], [ -72.857924566865279, 1.17398550043049 ], [ -72.885028856296685, 1.114195868344666 ], [ -72.893064540696002, 1.046551418113438 ], [ -72.938178067064143, 1.024743963762887 ], [ -73.033236864189917, 0.932243149701605 ], [ -73.082897915006754, 0.924336656511457 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-CAL", "NAME_1": "Caldas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -74.662491421341997, 5.771947739896291 ], [ -74.631847296915225, 5.702546292277532 ], [ -74.65194942892299, 5.660042425817267 ], [ -74.637376675093492, 5.644203599216723 ], [ -74.660372686949927, 5.574388739548681 ], [ -74.640683966991446, 5.562890732721144 ], [ -74.677632615952461, 5.549403184509345 ], [ -74.660372686949927, 5.525967922181849 ], [ -74.660372686949927, 5.458323472849997 ], [ -74.674997117622866, 5.455843004151291 ], [ -74.673395148067641, 5.42695587801137 ], [ -74.748687709969829, 5.290840155248929 ], [ -74.833075324366689, 5.314404608785651 ], [ -75.01275427898679, 5.293914903150267 ], [ -75.062828741852968, 5.26892934811093 ], [ -75.125098842637442, 5.163716132193713 ], [ -75.170625780155603, 5.173741359775931 ], [ -75.223258226086273, 5.142451280202408 ], [ -75.294364996947024, 5.131831773417616 ], [ -75.348470222123012, 5.060208237719962 ], [ -75.317283495337051, 5.027471218222104 ], [ -75.353922085036174, 4.939104519258137 ], [ -75.330719366705409, 4.878901475122973 ], [ -75.378029140932085, 4.800069078225363 ], [ -75.49244076213148, 4.919389959978673 ], [ -75.610650600744634, 4.933678493867376 ], [ -75.6380907860609, 4.973546861098725 ], [ -75.666977912200878, 4.947011013347549 ], [ -75.705580206661182, 4.949103909317955 ], [ -75.748419969006363, 5.045092882430595 ], [ -75.783430751627861, 5.000315252846633 ], [ -75.790536261839009, 4.9480187037002 ], [ -75.818803270354636, 4.920165107233913 ], [ -75.858490770432695, 4.932283229887162 ], [ -75.895878668965395, 4.973159288370425 ], [ -75.926807014232281, 5.043465074453593 ], [ -75.887636278091747, 5.12439036732161 ], [ -75.837923550431469, 5.111109523785501 ], [ -75.804075486894192, 5.20841624651257 ], [ -75.81733049200858, 5.272339992796446 ], [ -75.79805518320012, 5.28779124576937 ], [ -75.752037320166153, 5.283657131571374 ], [ -75.692454392756019, 5.256992091711652 ], [ -75.667546352981788, 5.265699571478024 ], [ -75.643723517925991, 5.304353541882449 ], [ -75.669225836902854, 5.352567654573591 ], [ -75.718809374253226, 5.396260076741157 ], [ -75.802731899757362, 5.364969998066954 ], [ -75.839163783881531, 5.360861721391302 ], [ -75.856372036040625, 5.374220079293195 ], [ -75.85779313844256, 5.489355170005069 ], [ -75.724726325159793, 5.558937486575758 ], [ -75.687415940992878, 5.528990994139065 ], [ -75.585742560970402, 5.518759060082573 ], [ -75.59246049665461, 5.683167628882927 ], [ -75.612536791139974, 5.700840969035482 ], [ -75.613234422230789, 5.735179958987885 ], [ -75.556131965317945, 5.721020616308408 ], [ -75.530577968598379, 5.688128567179604 ], [ -75.486653002434082, 5.669654242249464 ], [ -75.426114060615419, 5.694329738926285 ], [ -75.384617886306387, 5.674150092552736 ], [ -75.377486537673576, 5.619218044177387 ], [ -75.339917771987587, 5.586636054310418 ], [ -75.316172451297575, 5.517131252105571 ], [ -75.318032803271251, 5.463594469509133 ], [ -75.29141944025497, 5.473826401767042 ], [ -75.276123216013616, 5.433647976173177 ], [ -75.215765144046145, 5.502997747847758 ], [ -75.134426439128845, 5.535424708983101 ], [ -75.091715867992889, 5.596273709164336 ], [ -75.0911991031561, 5.659577337823862 ], [ -75.021539273118947, 5.67650137004216 ], [ -74.990946824636239, 5.71388926857486 ], [ -74.866768358273077, 5.743835761011553 ], [ -74.777264776847971, 5.689678859891444 ], [ -74.743726772572472, 5.699600734686157 ], [ -74.715098028850946, 5.772774563095595 ], [ -74.662491421341997, 5.771947739896291 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-CAS", "NAME_1": "Casanare" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -72.321678229166935, 6.351343899201595 ], [ -72.350901252091091, 6.288169459952599 ], [ -72.32330603714388, 6.225718492014778 ], [ -72.245507168121321, 6.126654771000858 ], [ -72.131224738131152, 6.069087226094609 ], [ -71.946481493326246, 6.149909166175064 ], [ -71.856125251179378, 6.154508368366521 ], [ -71.721999070700519, 6.200035304985306 ], [ -71.608750170384042, 6.210422267773424 ], [ -71.557357957903434, 6.190733546915624 ], [ -71.462273322355941, 6.198872585001766 ], [ -71.207146776202762, 6.274061794116506 ], [ -71.031421067728104, 6.247836004727844 ], [ -70.959668341720601, 6.222307848228581 ], [ -70.864170295023087, 6.215254014860875 ], [ -70.789446173901808, 6.23253978138581 ], [ -70.727227749061342, 6.209130357479978 ], [ -70.671778936748524, 6.208871975061584 ], [ -70.504889899249463, 6.224710802561503 ], [ -70.347741869391768, 6.279022732413182 ], [ -70.165298225232902, 6.267524726484908 ], [ -70.118091803793675, 6.250006415063979 ], [ -70.052591926376294, 6.194066677235355 ], [ -70.038871833268502, 6.161097112841446 ], [ -69.939627245101292, 6.114691677079236 ], [ -69.888054164568018, 6.040277615219736 ], [ -69.855756394641901, 6.026273302171148 ], [ -69.898647833830466, 5.97079865233593 ], [ -69.986575283222749, 5.779208278839008 ], [ -70.091400926411609, 5.645288804834479 ], [ -70.185193650766337, 5.587411199767018 ], [ -70.342858446360196, 5.568187567801999 ], [ -70.448795131789893, 5.53309926991534 ], [ -70.662089605950541, 5.404554145357508 ], [ -70.67865190296294, 5.389412949847724 ], [ -70.695705126390465, 5.313681139273172 ], [ -70.887889777291377, 5.154956977382597 ], [ -70.960288459344895, 5.117724107581466 ], [ -71.048577643943077, 4.93011282045029 ], [ -71.215208299023743, 4.815597846463447 ], [ -71.274507004694499, 4.80658030833456 ], [ -71.564980231152731, 4.681988429922114 ], [ -71.685748053729696, 4.607651882428399 ], [ -71.809435593677676, 4.577860418723333 ], [ -71.897440559234383, 4.485385443983034 ], [ -72.012162237896973, 4.398646552096693 ], [ -72.069884813333431, 4.394305732323687 ], [ -72.089237637407052, 4.42270193114922 ], [ -72.149905768636302, 4.450710557246396 ], [ -72.323461065875506, 4.409963690871621 ], [ -72.36666256432585, 4.343559474989775 ], [ -72.414592455277557, 4.341311550287799 ], [ -72.433325160827508, 4.354721584133813 ], [ -72.50487118215932, 4.321364447011604 ], [ -72.520813360648049, 4.343714503721344 ], [ -72.559648200004403, 4.354721584133813 ], [ -72.595485805825263, 4.306171576457075 ], [ -72.614580248379752, 4.320589301555003 ], [ -72.679744229012954, 4.320589301555003 ], [ -72.718113980375904, 4.298239243945943 ], [ -72.748034634390876, 4.313147895458997 ], [ -72.753150601419122, 4.34883047074959 ], [ -72.784182297674874, 4.350690822723266 ], [ -72.812604335821447, 4.426267605465625 ], [ -72.837098965344978, 4.430298366876116 ], [ -72.926576708348421, 4.525253811214384 ], [ -72.994582892886172, 4.649561468786771 ], [ -73.040600755020819, 4.694313259049636 ], [ -73.066309781371274, 4.830093085027841 ], [ -73.030937262644557, 4.985122382292104 ], [ -73.011351894574261, 4.994889228355191 ], [ -72.973679776100767, 4.978766180914533 ], [ -72.933062100035897, 5.020417384854397 ], [ -72.90611284023538, 5.083023383322484 ], [ -72.938462287004938, 5.115372830092042 ], [ -72.953190069566062, 5.160460517139143 ], [ -72.934612392747738, 5.205160631457943 ], [ -72.938255581429928, 5.240455634020293 ], [ -72.857588670980363, 5.3458238795684 ], [ -72.808470221623395, 5.383986925356282 ], [ -72.709613207083805, 5.279548854895722 ], [ -72.690182867745136, 5.277921046918777 ], [ -72.590137294800286, 5.354195460751896 ], [ -72.420612758971629, 5.557697252226376 ], [ -72.398495246258619, 5.564311835123078 ], [ -72.348059048186485, 5.510154934002969 ], [ -72.319275274834069, 5.506098334170758 ], [ -72.302609625933485, 5.584000555980879 ], [ -72.26682369695601, 5.659422309092292 ], [ -72.237652350875294, 5.683090115416462 ], [ -72.311136236747927, 5.77401479744492 ], [ -72.447381150719536, 5.854242459222121 ], [ -72.447639533137931, 5.874318751908845 ], [ -72.392759161606023, 5.900932114925126 ], [ -72.341031053240499, 6.078854071258377 ], [ -72.371210089673866, 6.109110622956848 ], [ -72.415729335940114, 6.204066067295173 ], [ -72.354363572720672, 6.334497382248401 ], [ -72.321678229166935, 6.351343899201595 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-MET", "NAME_1": "Meta" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -74.897515834588091, 2.950724595963322 ], [ -74.824600388597048, 3.107381700305211 ], [ -74.681353319000436, 3.210398668363837 ], [ -74.651742723347979, 3.259982204814889 ], [ -74.6159051166278, 3.48505890484455 ], [ -74.520665453248057, 3.62099376135302 ], [ -74.493561163816651, 3.70401194929201 ], [ -74.464544847366824, 3.677631130272459 ], [ -74.427777065559098, 3.67956899751124 ], [ -74.223551804572082, 4.009626370360706 ], [ -74.208462286805059, 4.019935817883663 ], [ -74.123299526951598, 4.005130520057435 ], [ -74.022633837281774, 4.094117335746432 ], [ -73.959924486026182, 4.111428940693031 ], [ -73.919177618752087, 4.154320379881597 ], [ -73.814429490828331, 4.203981430698434 ], [ -73.751901007625406, 4.202198594889239 ], [ -73.764019131177974, 4.261471462138275 ], [ -73.787351039818645, 4.293510850545317 ], [ -73.810682950257956, 4.420996608806433 ], [ -73.740196296122178, 4.473112290799577 ], [ -73.70957801011707, 4.517889919484162 ], [ -73.622374030237268, 4.483757636006089 ], [ -73.581058723081583, 4.421306667168949 ], [ -73.552197435363325, 4.320666815920788 ], [ -73.52765112989573, 4.299867051922888 ], [ -73.486878425099235, 4.285681870821691 ], [ -73.428690761669316, 4.315705878523488 ], [ -73.365671352950585, 4.322294622998413 ], [ -73.220615607324419, 4.283046373391414 ], [ -73.14434119259198, 4.226331488307551 ], [ -73.052977260991781, 4.734827582327057 ], [ -73.040600755020819, 4.694313259049636 ], [ -72.994582892886172, 4.649561468786771 ], [ -72.926576708348421, 4.525253811214384 ], [ -72.837098965344978, 4.430298366876116 ], [ -72.812604335821447, 4.426267605465625 ], [ -72.784182297674874, 4.350690822723266 ], [ -72.753150601419122, 4.34883047074959 ], [ -72.748034634390876, 4.313147895458997 ], [ -72.725555385572591, 4.300564683013704 ], [ -72.679744229012954, 4.320589301555003 ], [ -72.614580248379752, 4.320589301555003 ], [ -72.595485805825263, 4.306171576457075 ], [ -72.559648200004403, 4.354721584133813 ], [ -72.520813360648049, 4.343714503721344 ], [ -72.50487118215932, 4.321364447011604 ], [ -72.433325160827508, 4.354721584133813 ], [ -72.414592455277557, 4.341311550287799 ], [ -72.36666256432585, 4.343559474989775 ], [ -72.323461065875506, 4.409963690871621 ], [ -72.149905768636302, 4.450710557246396 ], [ -72.049756842903946, 4.388259589308575 ], [ -71.973663296224117, 4.421849270427458 ], [ -71.809435593677676, 4.577860418723333 ], [ -71.685748053729696, 4.607651882428399 ], [ -71.564980231152731, 4.681988429922114 ], [ -71.274507004694499, 4.80658030833456 ], [ -71.215208299023743, 4.815597846463447 ], [ -71.060334032289745, 4.919389959978673 ], [ -71.063667161710157, 2.868636583111822 ], [ -71.111803758236817, 2.876956488351254 ], [ -71.128107672830822, 2.864373276805281 ], [ -71.169061244780607, 2.884087836084746 ], [ -71.225130173818457, 2.855071518735599 ], [ -71.264740160430051, 2.865380968057195 ], [ -71.303471646099581, 2.905430203341211 ], [ -71.329594081801417, 2.858094590692815 ], [ -71.35685339996445, 2.875328681273629 ], [ -71.382381558262296, 2.845924791196126 ], [ -71.443411423798182, 2.876258857260439 ], [ -71.468707038099296, 2.852280992573753 ], [ -71.56149207210143, 2.855691637259213 ], [ -71.622625292223461, 2.815719916341038 ], [ -71.643657600218091, 2.819311428179844 ], [ -71.649548712702938, 2.86336558735195 ], [ -71.683138393821821, 2.840085353756081 ], [ -71.743160569904376, 2.881994941013716 ], [ -71.759309454867434, 2.816727606693689 ], [ -71.792046475264613, 2.861195177015816 ], [ -71.83728919104334, 2.830938625317287 ], [ -71.980381231908325, 2.799105943384575 ], [ -72.07877315935383, 2.827295437534417 ], [ -72.121044480918044, 2.867086290399982 ], [ -72.192357958253183, 2.847862657535586 ], [ -72.193469001393282, 2.772957668361698 ], [ -72.247780931244961, 2.754870917059179 ], [ -72.252302619070576, 2.697613430515389 ], [ -72.283747728275046, 2.752390448360472 ], [ -72.309818488032761, 2.71673370969296 ], [ -72.366533373116681, 2.738076076949369 ], [ -72.421904670164395, 2.694202785829873 ], [ -72.474847175356842, 2.687949937239807 ], [ -72.507274135592866, 2.665212306902447 ], [ -72.553679572254453, 2.675444240958939 ], [ -72.535747849683503, 2.641596178320981 ], [ -72.573445808377357, 2.629400540402628 ], [ -72.576727260954328, 2.579584459055525 ], [ -72.610032722132416, 2.620512193482909 ], [ -72.641994595274355, 2.562789618046452 ], [ -72.670442470943271, 2.613897609686944 ], [ -72.703334520072019, 2.607489732365252 ], [ -72.737208422031017, 2.559534002991825 ], [ -72.762297328958539, 2.565890204369452 ], [ -72.790305955955091, 2.600978502256055 ], [ -72.819942390029269, 2.596741034371234 ], [ -72.937635463805577, 2.513645331167083 ], [ -72.930452440128022, 2.467756659342342 ], [ -73.020576138278159, 2.411274319154472 ], [ -73.061323004652934, 2.413082994284764 ], [ -73.102431607132928, 2.382077135551356 ], [ -73.124445767058489, 2.394169419782884 ], [ -73.144754604641264, 2.36171662022582 ], [ -73.173202481209501, 2.385126044131596 ], [ -73.215318773142826, 2.388381659186223 ], [ -73.247125616653875, 2.371948554282369 ], [ -73.250355394186101, 2.34378489855419 ], [ -73.317741461998878, 2.347247219183828 ], [ -73.344122281018429, 2.328643703943783 ], [ -73.346344367298684, 2.349055894314063 ], [ -73.36344926577101, 2.353758450192288 ], [ -73.376704270885398, 2.329418850299703 ], [ -73.395488654178052, 2.344094956916706 ], [ -73.42685624901668, 2.331020819854928 ], [ -73.444684617900805, 2.385901191386836 ], [ -73.455071580688866, 2.347195543239707 ], [ -73.510313687426731, 2.352414862156138 ], [ -73.530415819434495, 2.383110663426351 ], [ -73.577493048765177, 2.361199856288351 ], [ -73.592711757741426, 2.385281072863222 ], [ -73.606716070790014, 2.382645575432946 ], [ -73.626637335644489, 2.366367499260662 ], [ -73.660330369550877, 2.253402817985659 ], [ -73.661131354328518, 1.641967271172632 ], [ -73.675058153011321, 1.624500637494407 ], [ -73.757482061747737, 1.6382465681246 ], [ -73.917834031615257, 1.634732571550899 ], [ -74.510821091919865, 1.843918769035952 ], [ -74.550534431318965, 1.871358954352274 ], [ -74.606835904353488, 1.962361152545157 ], [ -74.6159051166278, 2.043131414882907 ], [ -74.549190843282759, 2.142918606308626 ], [ -74.543738980369653, 2.181934311918951 ], [ -74.645851609963813, 2.318205064312281 ], [ -74.659442511862437, 2.382645575432946 ], [ -74.59644894066605, 2.721229559996175 ], [ -74.662465582920277, 2.795591945911553 ], [ -74.712565884208175, 2.896955268470833 ], [ -74.897515834588091, 2.950724595963322 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-CUN", "NAME_1": "Bogota" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -74.154382900950111, 4.007223416027841 ], [ -74.208462286805059, 4.019935817883663 ], [ -74.223551804572082, 4.009626370360706 ], [ -74.427777065559098, 3.67956899751124 ], [ -74.464544847366824, 3.677631130272459 ], [ -74.493561163816651, 3.70401194929201 ], [ -74.370054491021904, 3.909141546944852 ], [ -74.371604783733744, 4.033526719782287 ], [ -74.341994188081287, 4.112514146310787 ], [ -74.328144903764269, 4.12607920978769 ], [ -74.27267025392905, 4.098535670784543 ], [ -74.262515835137663, 4.109465236831227 ], [ -74.250630255581825, 4.196462511135962 ], [ -74.214017504304366, 4.256122952012618 ], [ -74.191512417064359, 4.394305732323687 ], [ -74.216420457737911, 4.399189154455883 ], [ -74.179265103201942, 4.500759181690853 ], [ -74.188799405268298, 4.581968695398984 ], [ -74.224714524555623, 4.628994248785546 ], [ -74.166061774031618, 4.667570705723506 ], [ -74.174924283428936, 4.698989976506198 ], [ -74.134332444886411, 4.730874335282351 ], [ -74.084671394069574, 4.80658030833456 ], [ -74.081389939693963, 4.835519111317922 ], [ -74.010696580882495, 4.815365302466716 ], [ -74.013564623208765, 4.681523341928653 ], [ -74.03121212404028, 4.65064667440447 ], [ -73.995038622334562, 4.632249863840116 ], [ -74.013693814417991, 4.566543279948405 ], [ -74.116400723214781, 4.430298366876116 ], [ -74.107693244347729, 4.342241726274608 ], [ -74.15298763696984, 4.248733221860675 ], [ -74.093895636874151, 4.141995550754075 ], [ -74.133479784164706, 4.08791616489907 ], [ -74.154382900950111, 4.007223416027841 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-SAN", "NAME_1": "Santander" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -73.625448778138605, 7.734541124273449 ], [ -73.544316778796315, 7.669764716368547 ], [ -73.496722784628787, 7.600854194265651 ], [ -73.393835007779387, 7.573620714524338 ], [ -73.360348680347329, 7.549642848938333 ], [ -73.260742356974163, 7.544914456437027 ], [ -73.247849087065731, 7.597055975952514 ], [ -73.216403977861262, 7.630025540346423 ], [ -73.056594611252308, 7.607597968371522 ], [ -73.027655809168266, 7.621188870270146 ], [ -72.991327276932282, 7.613179023393229 ], [ -72.983885870836275, 7.546774807511326 ], [ -72.903115606699885, 7.47633983021899 ], [ -72.897637906264322, 7.428694159208078 ], [ -72.842292446739009, 7.357535712403205 ], [ -72.844514533019264, 7.300975856950231 ], [ -72.88146318198028, 7.256379096318256 ], [ -72.837176479710763, 7.207880763686262 ], [ -72.830045131977272, 7.162095445548346 ], [ -72.885933193861774, 7.073806260950164 ], [ -72.879370286909193, 7.05985362384564 ], [ -72.792993130228751, 7.030837307395814 ], [ -72.74483069528037, 6.989160265034172 ], [ -72.688813443085905, 7.005076606000557 ], [ -72.670080735737372, 6.973424791221134 ], [ -72.650882941294697, 6.995438951146639 ], [ -72.560733404722839, 6.999495550978907 ], [ -72.546574062942625, 6.884954739469663 ], [ -72.50487118215932, 6.915082099059589 ], [ -72.477973599202244, 6.844078680986343 ], [ -72.481203375835094, 6.721579698544247 ], [ -72.497817348791614, 6.645770371805213 ], [ -72.542414110322909, 6.561356919885952 ], [ -72.542414110322909, 6.502549139731002 ], [ -72.616673142551463, 6.438082791087936 ], [ -72.66155412492293, 6.434801336712326 ], [ -72.708889736672006, 6.528774929119663 ], [ -72.762245653014475, 6.57360423374837 ], [ -72.791623704670201, 6.567093004538492 ], [ -72.794414231731423, 6.533193264157831 ], [ -72.733410203717938, 6.45660879196214 ], [ -72.735322231635678, 6.375993557456695 ], [ -72.755734422005958, 6.319666246000452 ], [ -72.747750413550705, 6.241324775517967 ], [ -72.799297654762938, 6.202515774583333 ], [ -72.817436082908898, 6.153423162748766 ], [ -72.893658819898633, 6.123218288792998 ], [ -72.992386644128317, 5.999634100733147 ], [ -73.016855435230127, 5.940748806212412 ], [ -73.127029587645325, 5.955476588773536 ], [ -73.195423346710072, 5.991107489019385 ], [ -73.219246181765868, 5.982477525417437 ], [ -73.28616716158524, 5.855870266299746 ], [ -73.351331143117761, 5.862536526039833 ], [ -73.36941789442028, 5.810937607984215 ], [ -73.415306566245022, 5.755075385420696 ], [ -73.468300747381591, 5.813495591948026 ], [ -73.47155636333548, 5.847705389791884 ], [ -73.400759649937868, 5.922274482181592 ], [ -73.381871913857708, 6.001029363814098 ], [ -73.438121710948167, 6.069552314088014 ], [ -73.499280768592598, 6.107095242251603 ], [ -73.535221727200963, 6.042060451928307 ], [ -73.578268195121098, 6.007230536460099 ], [ -73.613718228213656, 5.922196966916488 ], [ -73.638367885569437, 5.722725937751818 ], [ -73.64865149557005, 5.715439561286701 ], [ -73.694307624297437, 5.751974799097695 ], [ -73.737121548220841, 5.761147365958152 ], [ -73.833885667689401, 5.739107366711607 ], [ -73.878534105164817, 5.71140879987621 ], [ -73.877448900446382, 5.737091986905682 ], [ -73.893959519716077, 5.747323920062854 ], [ -73.97317949114057, 5.73257029908001 ], [ -74.008422817758799, 5.752129827829265 ], [ -74.04873043456189, 5.813650621578915 ], [ -74.087978685068265, 5.824063421889377 ], [ -74.11081966819313, 5.87059804886087 ], [ -74.174510871379596, 5.900777086193557 ], [ -74.233783738628631, 5.846310125811669 ], [ -74.257451544952801, 5.848196316207009 ], [ -74.269569667606049, 5.898451646226476 ], [ -74.239158088075271, 5.981702379061517 ], [ -74.26998307965539, 6.04983775480855 ], [ -74.290266078816444, 6.070689194750514 ], [ -74.356851161851637, 6.039114895236196 ], [ -74.419534674685451, 6.073583075498505 ], [ -74.479789394764737, 6.155180161934936 ], [ -74.519425217999412, 6.282304184990153 ], [ -74.459506394704363, 6.33351553031747 ], [ -74.413333502938769, 6.404234727550602 ], [ -74.392223679679034, 6.402581082051256 ], [ -74.379201218561377, 6.423484197937398 ], [ -74.405840419999379, 6.47534149841141 ], [ -74.40876013916909, 6.567144680482613 ], [ -74.386435919981693, 6.626288357421743 ], [ -74.29272070999275, 6.654426173828824 ], [ -74.108571742591835, 6.790309353493853 ], [ -74.016096767851536, 6.927794500915468 ], [ -73.925068732136253, 6.97450999593957 ], [ -73.887810024812779, 7.019856065405065 ], [ -73.926722377635599, 7.126102810096597 ], [ -73.937109341323037, 7.253898626720229 ], [ -73.899385546006158, 7.421252753112071 ], [ -73.913183152580416, 7.494865831093193 ], [ -73.835151739561127, 7.595273139243943 ], [ -73.823291999326273, 7.672038479492244 ], [ -73.836004401182151, 7.694776108930284 ], [ -73.815540533968431, 7.779525458533044 ], [ -73.872255419052351, 8.044909776265172 ], [ -73.855357225255716, 8.105448717184515 ], [ -73.785645718375179, 8.16146596937898 ], [ -73.778979457735772, 8.098033149510229 ], [ -73.728517422141294, 7.987238878571361 ], [ -73.670303921188975, 7.928973699876337 ], [ -73.676996019350781, 7.893368638951529 ], [ -73.744227058431989, 7.830736802961098 ], [ -73.751901007625406, 7.7408973247517 ], [ -73.625448778138605, 7.734541124273449 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-TOL", "NAME_1": "Tolima" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -74.563531053115582, 3.772121487516642 ], [ -74.727991298759434, 3.608668931326122 ], [ -74.733882412143601, 3.560325629224394 ], [ -74.77452592573087, 3.514772854183889 ], [ -74.777109748116345, 3.441392320199384 ], [ -74.908884650206403, 3.289928697251582 ], [ -74.966142136750193, 3.278844102473329 ], [ -75.067841356093709, 3.3014267031798 ], [ -75.03564693895504, 3.434157620577707 ], [ -75.142642991580772, 3.432142238973142 ], [ -75.177602098258205, 3.40547720001274 ], [ -75.178015510307546, 3.388708197425387 ], [ -75.213258836925775, 3.410128079047581 ], [ -75.257778083191965, 3.373644517180708 ], [ -75.316120775353511, 3.411755886125206 ], [ -75.355317349016445, 3.408655299802206 ], [ -75.387046678161653, 3.378708808264889 ], [ -75.492311570922254, 3.347263699060477 ], [ -75.569645351951408, 3.233291327432823 ], [ -75.627548793641893, 3.090302639355286 ], [ -75.781570400553505, 2.948244127264672 ], [ -75.812472907398728, 2.891916815808372 ], [ -75.854692552119559, 2.890909125455778 ], [ -75.974013434772189, 2.948166611999511 ], [ -76.001091884882555, 2.949949448708082 ], [ -76.031245082894259, 2.929537258337803 ], [ -76.044577603273751, 3.035525621510203 ], [ -76.112997198961523, 3.105908921959156 ], [ -76.091525642294528, 3.203189806264561 ], [ -76.065997483996682, 3.227167670051927 ], [ -76.064162971344047, 3.282022203162114 ], [ -76.043854132861952, 3.314061591569157 ], [ -76.064989793644031, 3.357831529001828 ], [ -76.049383511040162, 3.442400011451355 ], [ -75.99677690263195, 3.559240424505958 ], [ -75.988792894176697, 3.6467544618489 ], [ -75.961714444066331, 3.712150987378152 ], [ -75.857663947233391, 3.869893297337796 ], [ -75.79614315528238, 4.008076076749546 ], [ -75.745448574791908, 4.041510728237483 ], [ -75.762217577379261, 4.078511054041883 ], [ -75.601400518619016, 4.296456407237372 ], [ -75.582073533866492, 4.42712026618733 ], [ -75.512646246926749, 4.559411933114234 ], [ -75.422134976048312, 4.636978258140061 ], [ -75.389604662125464, 4.7090668809318 ], [ -75.378029140932085, 4.800069078225363 ], [ -75.330719366705409, 4.878901475122973 ], [ -75.353922085036174, 4.939104519258137 ], [ -75.317283495337051, 5.027471218222104 ], [ -75.348470222123012, 5.060208237719962 ], [ -75.338858404791551, 5.085813910383649 ], [ -75.279508023176732, 5.138653061889272 ], [ -75.241577521385466, 5.136250108455727 ], [ -75.170625780155603, 5.173741359775931 ], [ -75.125098842637442, 5.163716132193713 ], [ -75.062828741852968, 5.26892934811093 ], [ -75.01275427898679, 5.293914903150267 ], [ -74.833075324366689, 5.314404608785651 ], [ -74.748687709969829, 5.290840155248929 ], [ -74.742305671069857, 5.269626980101066 ], [ -74.735458544176481, 5.108241482358494 ], [ -74.749747077165864, 5.02630849913794 ], [ -74.728637254805449, 4.985354926288778 ], [ -74.762795375805922, 4.964245103029043 ], [ -74.749747077165864, 4.889133409179465 ], [ -74.770805222682895, 4.863062649421749 ], [ -74.767187873321689, 4.786891588376079 ], [ -74.827907681394379, 4.722166856415299 ], [ -74.790700650014969, 4.652351995847937 ], [ -74.818037481644467, 4.607961940790915 ], [ -74.804369066279378, 4.591528834987741 ], [ -74.818037481644467, 4.587498074476571 ], [ -74.805764330259649, 4.504634915269094 ], [ -74.89115963410984, 4.279635727806578 ], [ -74.880720995377601, 4.26906789786517 ], [ -74.784034390274883, 4.283588974851284 ], [ -74.749152797963234, 4.242532050113994 ], [ -74.73212541385675, 4.247906399560691 ], [ -74.699310879093787, 4.218554185427308 ], [ -74.65463660319665, 4.209174912991841 ], [ -74.616990323144876, 4.256898098368538 ], [ -74.581385261320747, 4.272633572181576 ], [ -74.523895229880964, 4.242532050113994 ], [ -74.480202805914757, 4.133443101517912 ], [ -74.524773729024389, 4.052156073443996 ], [ -74.531801723970375, 3.98425324079443 ], [ -74.511363695178375, 3.936995144310458 ], [ -74.551283739253165, 3.845605374288596 ], [ -74.563531053115582, 3.772121487516642 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-QUI", "NAME_1": "Quindío" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -75.390379807582065, 4.716818346289642 ], [ -75.428361986216657, 4.626823839348674 ], [ -75.504972296834012, 4.570341498261541 ], [ -75.55907752111068, 4.475773627550836 ], [ -75.582073533866492, 4.42712026618733 ], [ -75.601400518619016, 4.296456407237372 ], [ -75.710566983379579, 4.137422186984338 ], [ -75.762217577379261, 4.078511054041883 ], [ -75.829913702655233, 4.109413559987786 ], [ -75.837897712009806, 4.154165351150027 ], [ -75.790252040998894, 4.288394884416391 ], [ -75.787926601931133, 4.350845852354212 ], [ -75.809062262713212, 4.397483832113153 ], [ -75.890375129208849, 4.423632107136029 ], [ -75.866914029358952, 4.458229477708244 ], [ -75.876758388888504, 4.552564806220801 ], [ -75.862108119793902, 4.612948717509312 ], [ -75.824849413369691, 4.664444280978785 ], [ -75.716018846292684, 4.658785712490612 ], [ -75.703048062018411, 4.720228990075839 ], [ -75.659433153317366, 4.702943223550903 ], [ -75.532670864568729, 4.699145006137087 ], [ -75.484560105564412, 4.671368923137265 ], [ -75.390379807582065, 4.716818346289642 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-CUN", "NAME_1": "Cundinamarca" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -74.493561163816651, 3.70401194929201 ], [ -74.563531053115582, 3.772121487516642 ], [ -74.551283739253165, 3.845605374288596 ], [ -74.511363695178375, 3.936995144310458 ], [ -74.531801723970375, 3.98425324079443 ], [ -74.524773729024389, 4.052156073443996 ], [ -74.480202805914757, 4.133443101517912 ], [ -74.523895229880964, 4.242532050113994 ], [ -74.581385261320747, 4.272633572181576 ], [ -74.616990323144876, 4.256898098368538 ], [ -74.65463660319665, 4.209174912991841 ], [ -74.699310879093787, 4.218554185427308 ], [ -74.73212541385675, 4.247906399560691 ], [ -74.749152797963234, 4.242532050113994 ], [ -74.784034390274883, 4.283588974851284 ], [ -74.880720995377601, 4.26906789786517 ], [ -74.89115963410984, 4.279635727806578 ], [ -74.805764330259649, 4.504634915269094 ], [ -74.818037481644467, 4.587498074476571 ], [ -74.804369066279378, 4.591528834987741 ], [ -74.818037481644467, 4.607961940790915 ], [ -74.790700650014969, 4.652351995847937 ], [ -74.827907681394379, 4.722166856415299 ], [ -74.767187873321689, 4.786891588376079 ], [ -74.770805222682895, 4.863062649421749 ], [ -74.749747077165864, 4.889133409179465 ], [ -74.762795375805922, 4.964245103029043 ], [ -74.728637254805449, 4.985354926288778 ], [ -74.749747077165864, 5.02630849913794 ], [ -74.735458544176481, 5.108241482358494 ], [ -74.750522224421104, 5.302364000498187 ], [ -74.673395148067641, 5.42695587801137 ], [ -74.674997117622866, 5.455843004151291 ], [ -74.660372686949927, 5.458323472849997 ], [ -74.660372686949927, 5.525967922181849 ], [ -74.680113084651111, 5.539610500923857 ], [ -74.640683966991446, 5.562890732721144 ], [ -74.660372686949927, 5.574388739548681 ], [ -74.637376675093492, 5.644203599216723 ], [ -74.65194942892299, 5.660042425817267 ], [ -74.631847296915225, 5.702546292277532 ], [ -74.646084153960544, 5.752517402356204 ], [ -74.533946295884846, 5.790551256035599 ], [ -74.440644497045867, 5.767193508073944 ], [ -74.347523566259554, 5.826388861856458 ], [ -74.312848680422235, 5.793186754365195 ], [ -74.288379890219744, 5.681617336171144 ], [ -74.31352047399065, 5.613792018786626 ], [ -74.256908941694292, 5.544674791108719 ], [ -74.243886480576577, 5.483929145513628 ], [ -74.208772346066894, 5.484239202976823 ], [ -74.147535773157415, 5.45294912430262 ], [ -74.098029751072147, 5.455610460154617 ], [ -74.088702154580744, 5.419669501546252 ], [ -74.000102911620047, 5.374297594558357 ], [ -73.93483557819934, 5.434190579431686 ], [ -73.90672359931466, 5.442019558255993 ], [ -73.899230516375212, 5.481887926386662 ], [ -73.821612515405263, 5.558472398582296 ], [ -73.798254768342872, 5.563975938338899 ], [ -73.791510993337681, 5.507958686144434 ], [ -73.653767462598296, 5.461734117535457 ], [ -73.641675178366768, 5.430702419481065 ], [ -73.590102097833551, 5.385614732433964 ], [ -73.584831102073679, 5.304611925200163 ], [ -73.521630825302339, 5.237277533331508 ], [ -73.525093145931919, 5.210974229577005 ], [ -73.475948859052608, 5.065892646428495 ], [ -73.517600063891848, 5.023828030439233 ], [ -73.514266933572117, 4.991246038773681 ], [ -73.545298630727189, 4.932438259518051 ], [ -73.523258633279283, 4.888358262823544 ], [ -73.411689215984495, 4.877738756038752 ], [ -73.365800544159754, 4.819783637504827 ], [ -73.36825517443674, 4.797743639157602 ], [ -73.329058600773806, 4.783791002053079 ], [ -73.296424934063452, 4.729789130563915 ], [ -73.228392910204605, 4.723587957917914 ], [ -73.218083461782328, 4.677647610149052 ], [ -73.113231981071067, 4.6639791938847 ], [ -73.073311936996276, 4.728471380949486 ], [ -73.052977260991781, 4.734827582327057 ], [ -73.137726609695278, 4.229819648258172 ], [ -73.220615607324419, 4.283046373391414 ], [ -73.365671352950585, 4.322294622998413 ], [ -73.428690761669316, 4.315705878523488 ], [ -73.486878425099235, 4.285681870821691 ], [ -73.52765112989573, 4.299867051922888 ], [ -73.552197435363325, 4.320666815920788 ], [ -73.581058723081583, 4.421306667168949 ], [ -73.622374030237268, 4.483757636006089 ], [ -73.697279019411212, 4.521300564169678 ], [ -73.810682950257956, 4.420996608806433 ], [ -73.787351039818645, 4.293510850545317 ], [ -73.764019131177974, 4.261471462138275 ], [ -73.751901007625406, 4.202198594889239 ], [ -73.814429490828331, 4.203981430698434 ], [ -73.919177618752087, 4.154320379881597 ], [ -73.959924486026182, 4.111428940693031 ], [ -74.022633837281774, 4.094117335746432 ], [ -74.123299526951598, 4.005130520057435 ], [ -74.154382900950111, 4.007223416027841 ], [ -74.133479784164706, 4.08791616489907 ], [ -74.093895636874151, 4.141995550754075 ], [ -74.15298763696984, 4.248733221860675 ], [ -74.107693244347729, 4.342241726274608 ], [ -74.116400723214781, 4.430298366876116 ], [ -74.013693814417991, 4.566543279948405 ], [ -73.995038622334562, 4.632249863840116 ], [ -74.03121212404028, 4.65064667440447 ], [ -74.013564623208765, 4.681523341928653 ], [ -74.010696580882495, 4.815365302466716 ], [ -74.085188158007099, 4.833038641719952 ], [ -74.084671394069574, 4.80658030833456 ], [ -74.134332444886411, 4.730874335282351 ], [ -74.174924283428936, 4.698989976506198 ], [ -74.166061774031618, 4.667570705723506 ], [ -74.224714524555623, 4.628994248785546 ], [ -74.188799405268298, 4.581968695398984 ], [ -74.179265103201942, 4.500759181690853 ], [ -74.216420457737911, 4.399189154455883 ], [ -74.191512417064359, 4.394305732323687 ], [ -74.214017504304366, 4.256122952012618 ], [ -74.250630255581825, 4.196462511135962 ], [ -74.262515835137663, 4.109465236831227 ], [ -74.27267025392905, 4.098535670784543 ], [ -74.328144903764269, 4.12607920978769 ], [ -74.341994188081287, 4.112514146310787 ], [ -74.371604783733744, 4.033526719782287 ], [ -74.370054491021904, 3.909141546944852 ], [ -74.493561163816651, 3.70401194929201 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CO-RIS", "NAME_1": "Risaralda" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -75.85779313844256, 5.489355170005069 ], [ -75.856372036040625, 5.374220079293195 ], [ -75.839163783881531, 5.360861721391302 ], [ -75.802731899757362, 5.364969998066954 ], [ -75.718809374253226, 5.396260076741157 ], [ -75.669225836902854, 5.352567654573591 ], [ -75.643723517925991, 5.304353541882449 ], [ -75.667546352981788, 5.265699571478024 ], [ -75.692454392756019, 5.256992091711652 ], [ -75.752037320166153, 5.283657131571374 ], [ -75.79805518320012, 5.28779124576937 ], [ -75.81733049200858, 5.272339992796446 ], [ -75.804075486894192, 5.20841624651257 ], [ -75.837923550431469, 5.111109523785501 ], [ -75.887636278091747, 5.12439036732161 ], [ -75.926807014232281, 5.043465074453593 ], [ -75.895878668965395, 4.973159288370425 ], [ -75.858490770432695, 4.932283229887162 ], [ -75.818803270354636, 4.920165107233913 ], [ -75.790536261839009, 4.9480187037002 ], [ -75.783430751627861, 5.000315252846633 ], [ -75.748419969006363, 5.045092882430595 ], [ -75.705580206661182, 4.949103909317955 ], [ -75.666977912200878, 4.947011013347549 ], [ -75.6380907860609, 4.973546861098725 ], [ -75.610650600744634, 4.933678493867376 ], [ -75.49244076213148, 4.919389959978673 ], [ -75.378029140932085, 4.800069078225363 ], [ -75.390379807582065, 4.716818346289642 ], [ -75.441410284856772, 4.68516653151022 ], [ -75.491639777353839, 4.671756496764885 ], [ -75.532670864568729, 4.699145006137087 ], [ -75.853555670557739, 4.731959540000787 ], [ -75.851902025058394, 4.776633815897867 ], [ -75.894302537831834, 4.760820827718987 ], [ -75.924094000637581, 4.774928494454457 ], [ -75.94026872402236, 4.821954046941698 ], [ -75.922181972719841, 4.872416083435496 ], [ -75.981118944084017, 4.872622789010506 ], [ -75.986286587056327, 4.911095893160905 ], [ -76.02238257529558, 4.941507472691683 ], [ -76.075919358791339, 5.035713609095751 ], [ -76.097597621932721, 5.17503327096864 ], [ -76.179918178780895, 5.308720200976495 ], [ -76.165552131425727, 5.40866242113384 ], [ -76.093256802159658, 5.455377916157886 ], [ -76.080234341042001, 5.537595120218612 ], [ -76.042484707303402, 5.577334296240792 ], [ -75.960474208817686, 5.507028510157625 ], [ -75.85779313844256, 5.489355170005069 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/costa rica.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/costa rica.geojson new file mode 100644 index 0000000000000..b0dd0f68f6763 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/costa rica.geojson @@ -0,0 +1,13 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "CR-A", "NAME_1": "Alajuela" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -84.355466471999875, 10.994627177000098 ], [ -84.3459838469999, 10.989898784000019 ], [ -84.343658406999879, 10.982379863000062 ], [ -84.343865112999936, 10.972277121000033 ], [ -84.341798055999874, 10.959900615000066 ], [ -84.337405558999876, 10.952665914000093 ], [ -84.324098876999955, 10.936181132000115 ], [ -84.321308349999896, 10.9291531370001 ], [ -84.310740519999939, 10.919412130000055 ], [ -84.264283406999908, 10.901816305000082 ], [ -84.253663900999925, 10.89471079600014 ], [ -84.244723877999888, 10.88491811100009 ], [ -84.225655273999905, 10.875306295000073 ], [ -84.208369506999901, 10.860966085000072 ], [ -84.204648803999902, 10.836988220000066 ], [ -84.218523925999875, 10.829831035000026 ], [ -84.222658040999903, 10.827040507000063 ], [ -84.227102213999899, 10.819314881000068 ], [ -84.225241862999894, 10.81368214900003 ], [ -84.221159423999978, 10.809418844000078 ], [ -84.218885660999973, 10.80595652300012 ], [ -84.19687150099989, 10.788515727000089 ], [ -84.19160050499994, 10.781720276000044 ], [ -84.180412557999915, 10.789755961000125 ], [ -84.164832112999875, 10.789445903000043 ], [ -84.15772972504675, 10.788424645281168 ], [ -84.157984178327126, 10.784251613820913 ], [ -84.160516323869217, 10.571138006813555 ], [ -84.162686734205408, 10.41011424427694 ], [ -84.164185350073808, 10.295702623077602 ], [ -84.165787319629089, 10.158398341909958 ], [ -84.177362839923092, 10.006831366174595 ], [ -84.177621223240862, 10.004350898375264 ], [ -84.196018032905897, 9.985075587768165 ], [ -84.200978970303197, 9.977169094578016 ], [ -84.201599087028228, 9.974171861042521 ], [ -84.201857469446622, 9.971381333981356 ], [ -84.201754116659117, 9.966006985434035 ], [ -84.199971279950603, 9.957221991301822 ], [ -84.214673224989326, 9.941460679966383 ], [ -84.242449307089828, 9.932520657102657 ], [ -84.309241095699974, 9.914020493750797 ], [ -84.327069464584099, 9.911540025052091 ], [ -84.332340461243291, 9.913141995506692 ], [ -84.344329392687314, 9.914537257688266 ], [ -84.349135301353044, 9.915674140149463 ], [ -84.352959357188581, 9.916966051342172 ], [ -84.37275143083383, 9.920118312709974 ], [ -84.392155930851516, 9.925647690888184 ], [ -84.416573046009262, 9.920945135909278 ], [ -84.461040616331388, 9.917276108805368 ], [ -84.49183976859041, 9.903840237437009 ], [ -84.499927130732488, 9.898930975983717 ], [ -84.500908982663418, 9.897484036059382 ], [ -84.502175056333783, 9.895106920148237 ], [ -84.51382809099357, 9.883738105429188 ], [ -84.531036343152721, 9.874849758509527 ], [ -84.537625087627703, 9.869992173899675 ], [ -84.540544806797357, 9.86647817642671 ], [ -84.540260585957242, 9.863894354940498 ], [ -84.540725673950703, 9.860638738986609 ], [ -84.559199998880842, 9.837952786391952 ], [ -84.560853645279508, 9.834180406500536 ], [ -84.562145554673577, 9.82658397077364 ], [ -84.563773362650522, 9.824723618799965 ], [ -84.57105974001496, 9.824516913224954 ], [ -84.592789679999726, 9.853145656946481 ], [ -84.601781378807573, 9.860070299105018 ], [ -84.613744472729195, 9.862447415016163 ], [ -84.626766933846909, 9.863170885428019 ], [ -84.643303392437588, 9.86761505798853 ], [ -84.664206509222993, 9.875883287283841 ], [ -84.671079475437409, 9.880637519106187 ], [ -84.674412603958501, 9.884358222154219 ], [ -84.672965664034166, 9.889629217914035 ], [ -84.67304317929927, 9.895520331298258 ], [ -84.672552252884145, 9.898259182415302 ], [ -84.670846931440735, 9.900481268695557 ], [ -84.669244960986134, 9.901979885463334 ], [ -84.662191127618428, 9.905080470887015 ], [ -84.643690965165888, 9.933864244239487 ], [ -84.635991176651487, 9.941253974391373 ], [ -84.624906581873233, 9.944612942233505 ], [ -84.575710619049801, 9.976342271378712 ], [ -84.560000982759107, 9.982543443125394 ], [ -84.55506588378347, 9.985127265510869 ], [ -84.551758591885516, 9.988124498147045 ], [ -84.550880092742091, 9.990294908483236 ], [ -84.55010494728549, 9.997736314579242 ], [ -84.562791510719649, 10.018303534580468 ], [ -84.569974535296524, 10.021714179265928 ], [ -84.572455003995231, 10.020680650491613 ], [ -84.580335659662921, 10.014634508375821 ], [ -84.58806128569978, 10.01251577398375 ], [ -84.591394416019455, 10.012619126771256 ], [ -84.593513150411525, 10.013239244395606 ], [ -84.594443326398391, 10.014686184319942 ], [ -84.595812751057622, 10.017786769743623 ], [ -84.596432867782596, 10.020163886554087 ], [ -84.602685716372719, 10.029775702086965 ], [ -84.619041306910788, 10.049206041425634 ], [ -84.627102830631088, 10.062228502543348 ], [ -84.643458422068534, 10.082278957707729 ], [ -84.649375372975044, 10.091218980571455 ], [ -84.660434130230897, 10.113801581277926 ], [ -84.664929978735529, 10.129769599087695 ], [ -84.661131761321712, 10.154936021280321 ], [ -84.661519334949332, 10.158708401171737 ], [ -84.662604539667768, 10.164289456193444 ], [ -84.668159756267698, 10.174314682876286 ], [ -84.668960741045339, 10.178397122029537 ], [ -84.668960741045339, 10.182066148234128 ], [ -84.663198818870399, 10.20449372020903 ], [ -84.660201586234223, 10.211883450360915 ], [ -84.649633755393495, 10.231003730437806 ], [ -84.648496873831618, 10.236068019723291 ], [ -84.648884446559919, 10.239788722771323 ], [ -84.65046057769348, 10.241494045114052 ], [ -84.656480882286871, 10.246144924148894 ], [ -84.660511643697362, 10.251777655114665 ], [ -84.666066861196668, 10.267280584931029 ], [ -84.683921067603194, 10.278752753336903 ], [ -84.69154334175181, 10.279837958055282 ], [ -84.694153001659686, 10.278907782068472 ], [ -84.696452603205046, 10.277874254193478 ], [ -84.702989671735963, 10.273998521514557 ], [ -84.716683926422036, 10.270071112891515 ], [ -84.735726691233822, 10.266712144150119 ], [ -84.743917406163348, 10.26635040894422 ], [ -84.74955013712912, 10.266712144150119 ], [ -84.756035528816597, 10.270897935191556 ], [ -84.757844203946831, 10.272448227903396 ], [ -84.764252082167843, 10.280096340473733 ], [ -84.786627977299304, 10.315339667091962 ], [ -84.770608282646094, 10.345467027581265 ], [ -84.768902961202684, 10.355388902375921 ], [ -84.771280077113829, 10.359729723048247 ], [ -84.77267534019478, 10.361693426910108 ], [ -84.775465868155266, 10.368566392225205 ], [ -84.779393276778308, 10.387066555577064 ], [ -84.763993699749449, 10.442153631784663 ], [ -84.785775315678279, 10.485148423760734 ], [ -84.79326839861767, 10.496620592166607 ], [ -84.850396694851554, 10.540028795292642 ], [ -84.86845760773241, 10.549123846887994 ], [ -84.923389655208382, 10.563283189567528 ], [ -84.937316453891242, 10.568760890902354 ], [ -84.948013475041819, 10.580543118570063 ], [ -84.974704353323204, 10.604107571207408 ], [ -84.977934129956111, 10.607724921467934 ], [ -84.983592699343603, 10.616251532282377 ], [ -84.986538256035658, 10.623227851284298 ], [ -84.991111619805395, 10.650151271763775 ], [ -85.002532111367827, 10.67046011024587 ], [ -85.016717291569762, 10.692732651690505 ], [ -85.022995978581548, 10.699347236385847 ], [ -85.029326340638079, 10.703222968165448 ], [ -85.042839729070238, 10.708907375974604 ], [ -85.05402767573662, 10.71211131418579 ], [ -85.107099372138293, 10.724617011365979 ], [ -85.122731493163883, 10.72983633118173 ], [ -85.128906827388164, 10.734332179686305 ], [ -85.136348232584851, 10.741256821844843 ], [ -85.166036342603093, 10.761255601065102 ], [ -85.17373613201687, 10.765131333744023 ], [ -85.179575567658333, 10.767508450554544 ], [ -85.185931769935223, 10.768025214492013 ], [ -85.192520515309525, 10.76781850801774 ], [ -85.204819506015383, 10.7662682153059 ], [ -85.226704474731719, 10.760997219546027 ], [ -85.252801072911154, 10.758516750847377 ], [ -85.282721726926127, 10.759550278722372 ], [ -85.307319709237163, 10.80771271457013 ], [ -85.316053025626616, 10.820941881262797 ], [ -85.320471360664726, 10.824145820373303 ], [ -85.322770962210143, 10.825489407510133 ], [ -85.325251430908793, 10.826574612228569 ], [ -85.327783575551564, 10.827453111371995 ], [ -85.350340338735634, 10.83024363933248 ], [ -85.356438157694811, 10.832414048769294 ], [ -85.380829434430836, 10.846366684974498 ], [ -85.392198249149885, 10.854944973531701 ], [ -85.437544317716061, 10.906879788371498 ], [ -85.438784552964705, 10.908585109814965 ], [ -85.441006639244961, 10.912770900856401 ], [ -85.441187507297627, 10.91540639918594 ], [ -85.440722419304166, 10.917680162309637 ], [ -85.437001716256191, 10.922020982082643 ], [ -85.403024462409007, 10.924501450781293 ], [ -85.393877733070894, 10.928428860303654 ], [ -85.390983853222224, 10.93297638655099 ], [ -85.388968471617659, 10.937420559111501 ], [ -85.310471970604965, 10.99023387309478 ], [ -85.262671270862427, 11.043357245440518 ], [ -85.258950567814452, 11.045941066926673 ], [ -85.256263394440111, 11.046767890126034 ], [ -85.25233598491775, 11.047284654063503 ], [ -85.246289841902637, 11.049403388455573 ], [ -85.238848435806631, 11.05110870989904 ], [ -85.236478239279279, 11.05309661721509 ], [ -85.092837483999915, 11.000647482000119 ], [ -84.931400309999873, 10.941891378000065 ], [ -84.908404296999919, 10.939359233000076 ], [ -84.884969034999955, 10.947679138000041 ], [ -84.781771199999923, 11.014884339000091 ], [ -84.707770548999918, 11.063046774000085 ], [ -84.676454630999899, 11.070410665000082 ], [ -84.658729614999885, 11.062736715000099 ], [ -84.620669921999934, 11.035761617000077 ], [ -84.603229125999889, 11.033281149000089 ], [ -84.581680053999946, 11.034469706000024 ], [ -84.558606526999966, 11.027209168000056 ], [ -84.508738769999923, 11.005530904000054 ], [ -84.503338582999874, 11.004032288000047 ], [ -84.498170939999852, 11.001991069000098 ], [ -84.493313354999941, 10.999407248000097 ], [ -84.489127563999887, 10.996358337000061 ], [ -84.46638993399992, 10.968453064000087 ], [ -84.457837483999896, 10.961347555000145 ], [ -84.448871623999963, 10.956334941000094 ], [ -84.438200439999946, 10.952200826000066 ], [ -84.427245035999874, 10.951115621000071 ], [ -84.417762410999899, 10.955043030000041 ], [ -84.363967244999884, 10.989614563000131 ], [ -84.355466471999875, 10.994627177000098 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CR-G", "NAME_1": "Guanacaste" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -85.597793741999936, 11.209937032000099 ], [ -85.569164998999952, 11.195390117000045 ], [ -85.540949666999978, 11.17032704600004 ], [ -85.508626058999909, 11.152421163000071 ], [ -85.407417765999895, 11.115446676000118 ], [ -85.272361409999917, 11.066199036000043 ], [ -85.236478239279279, 11.05309661721509 ], [ -85.238848435806631, 11.05110870989904 ], [ -85.246289841902637, 11.049403388455573 ], [ -85.25233598491775, 11.047284654063503 ], [ -85.256263394440111, 11.046767890126034 ], [ -85.258950567814452, 11.045941066926673 ], [ -85.262671270862427, 11.043357245440518 ], [ -85.310471970604965, 10.99023387309478 ], [ -85.388968471617659, 10.937420559111501 ], [ -85.390983853222224, 10.93297638655099 ], [ -85.393877733070894, 10.928428860303654 ], [ -85.403024462409007, 10.924501450781293 ], [ -85.437001716256191, 10.922020982082643 ], [ -85.440722419304166, 10.917680162309637 ], [ -85.441187507297627, 10.91540639918594 ], [ -85.441006639244961, 10.912770900856401 ], [ -85.438784552964705, 10.908585109814965 ], [ -85.437544317716061, 10.906879788371498 ], [ -85.392198249149885, 10.854944973531701 ], [ -85.380829434430836, 10.846366684974498 ], [ -85.356438157694811, 10.832414048769294 ], [ -85.350340338735634, 10.83024363933248 ], [ -85.327783575551564, 10.827453111371995 ], [ -85.325251430908793, 10.826574612228569 ], [ -85.322770962210143, 10.825489407510133 ], [ -85.320471360664726, 10.824145820373303 ], [ -85.316053025626616, 10.820941881262797 ], [ -85.307319709237163, 10.80771271457013 ], [ -85.282721726926127, 10.759550278722372 ], [ -85.252801072911154, 10.758516750847377 ], [ -85.226704474731719, 10.760997219546027 ], [ -85.204819506015383, 10.7662682153059 ], [ -85.192520515309525, 10.76781850801774 ], [ -85.185931769935223, 10.768025214492013 ], [ -85.179575567658333, 10.767508450554544 ], [ -85.17373613201687, 10.765131333744023 ], [ -85.166036342603093, 10.761255601065102 ], [ -85.136348232584851, 10.741256821844843 ], [ -85.128906827388164, 10.734332179686305 ], [ -85.122731493163883, 10.72983633118173 ], [ -85.107099372138293, 10.724617011365979 ], [ -85.05402767573662, 10.71211131418579 ], [ -85.042839729070238, 10.708907375974604 ], [ -85.029326340638079, 10.703222968165448 ], [ -85.022995978581548, 10.699347236385847 ], [ -85.016717291569762, 10.692732651690505 ], [ -85.002532111367827, 10.67046011024587 ], [ -84.991111619805395, 10.650151271763775 ], [ -84.986538256035658, 10.623227851284298 ], [ -84.983592699343603, 10.616251532282377 ], [ -84.977934129956111, 10.607724921467934 ], [ -84.974704353323204, 10.604107571207408 ], [ -84.948013475041819, 10.580543118570063 ], [ -84.937316453891242, 10.568760890902354 ], [ -84.923389655208382, 10.563283189567528 ], [ -84.86845760773241, 10.549123846887994 ], [ -84.850396694851554, 10.540028795292642 ], [ -84.79326839861767, 10.496620592166607 ], [ -84.785775315678279, 10.485148423760734 ], [ -84.763993699749449, 10.442153631784663 ], [ -84.779393276778308, 10.387066555577064 ], [ -84.775465868155266, 10.368566392225205 ], [ -84.77267534019478, 10.361693426910108 ], [ -84.771280077113829, 10.359729723048247 ], [ -84.768902961202684, 10.355388902375921 ], [ -84.770608282646094, 10.345467027581265 ], [ -84.786627977299304, 10.315339667091962 ], [ -84.802260098324837, 10.32784536427215 ], [ -84.806678433363004, 10.329809068133954 ], [ -84.81238867869456, 10.33166942010763 ], [ -84.817401292935301, 10.331979478470146 ], [ -84.824920214296412, 10.33166942010763 ], [ -84.829183518804314, 10.330790920064885 ], [ -84.832516649124045, 10.329705715346449 ], [ -84.838433600929932, 10.325674953935959 ], [ -84.847089402953543, 10.316528225497223 ], [ -84.850810106001575, 10.313427639174222 ], [ -84.859879320074526, 10.308776760139381 ], [ -84.865822110302133, 10.304797675572274 ], [ -84.870240445340244, 10.300301825269003 ], [ -84.872979295558025, 10.296271063858512 ], [ -84.87481380910998, 10.292860419172996 ], [ -84.875433925835011, 10.289914863380204 ], [ -84.875433925835011, 10.28696930578883 ], [ -84.874891324375085, 10.284333808358554 ], [ -84.873728604391545, 10.282163398022362 ], [ -84.87228166356789, 10.280199693261238 ], [ -84.864917771837668, 10.273481757577031 ], [ -84.863600023122558, 10.27151805281585 ], [ -84.862850715188358, 10.26888255538563 ], [ -84.862488979982402, 10.266247057056034 ], [ -84.862954067975863, 10.263559881883054 ], [ -84.867630785432368, 10.25033071519033 ], [ -84.869878710134344, 10.231107083225311 ], [ -84.870886399587675, 10.228109848790496 ], [ -84.876984219446172, 10.215500799722122 ], [ -84.877914395432981, 10.212090155036606 ], [ -84.877940232955382, 10.209402980762945 ], [ -84.877139248177741, 10.206922512064239 ], [ -84.876183233769211, 10.204752101728104 ], [ -84.87481380910998, 10.202685045078738 ], [ -84.871635708421195, 10.199067694818268 ], [ -84.870240445340244, 10.196173814070278 ], [ -84.869542813350165, 10.192401435078125 ], [ -84.870085414810035, 10.185166734557129 ], [ -84.8717390612087, 10.181756089871612 ], [ -84.87380611785801, 10.179120592441393 ], [ -84.892978074778284, 10.170904039090146 ], [ -84.897344732973011, 10.16806183518554 ], [ -84.915405645853866, 10.152352199794166 ], [ -84.920108201732091, 10.14666779198501 ], [ -84.922795376005809, 10.142223619424499 ], [ -84.923622199205113, 10.136125800465322 ], [ -84.923699713570898, 10.133025214142322 ], [ -84.922640347274182, 10.127289130389045 ], [ -84.918867967382766, 10.116592109238411 ], [ -84.918351203445241, 10.112768053402931 ], [ -84.919927333679482, 10.111217759791771 ], [ -84.922330288012347, 10.11101105421676 ], [ -84.925043300707728, 10.111631170941791 ], [ -84.927575446249818, 10.112457994141096 ], [ -84.93685136589778, 10.117367254695012 ], [ -84.944706184043127, 10.123310044922619 ], [ -84.948375210247718, 10.126927395183145 ], [ -84.960570848166071, 10.142120265737674 ], [ -84.968038092683798, 10.148528143958686 ], [ -84.970053474288363, 10.149975083883021 ], [ -84.979251878671221, 10.154936021280321 ], [ -84.984212816068577, 10.156848049198118 ], [ -84.987158372760689, 10.157468166822412 ], [ -84.990388150292858, 10.157623196453358 ], [ -84.994367234859965, 10.157003078829007 ], [ -84.999483201888268, 10.155452786117166 ], [ -85.001085171443492, 10.155142726855331 ], [ -85.003513964198078, 10.154987698123762 ], [ -85.006175300050018, 10.155607814848736 ], [ -85.008500739117778, 10.156589666779666 ], [ -85.010593635088185, 10.158036606704002 ], [ -85.014366014080281, 10.161137193027002 ], [ -85.016562262838136, 10.162170721801374 ], [ -85.019197761167732, 10.162790839425668 ], [ -85.021962449807177, 10.162739163481604 ], [ -85.027621019194669, 10.161653957863848 ], [ -85.033873867784735, 10.161033840239497 ], [ -85.037077805995921, 10.161137193027002 ], [ -85.040152553897201, 10.161653957863848 ], [ -85.048369107248504, 10.161808987494737 ], [ -85.068393723991164, 10.155866197267187 ], [ -85.068565921124971, 10.155815093516726 ], [ -85.072865363999938, 10.158758856000077 ], [ -85.076771613999938, 10.160589911000045 ], [ -85.089873826999906, 10.172390041000085 ], [ -85.107899542999917, 10.166571356000077 ], [ -85.175567186999899, 10.16555410400008 ], [ -85.193470831999946, 10.170111395000049 ], [ -85.209462042999917, 10.18117910400008 ], [ -85.234527147999927, 10.207098700000074 ], [ -85.234527147999927, 10.213324286000045 ], [ -85.228789842999902, 10.231594143000052 ], [ -85.246245897999927, 10.252630927000041 ], [ -85.289173956999946, 10.282253322000088 ], [ -85.283070441999939, 10.26203034100007 ], [ -85.254180467999902, 10.241156317000048 ], [ -85.247547980999911, 10.216742255000042 ], [ -85.244903123999904, 10.170355536000045 ], [ -85.238880988999938, 10.143133856000077 ], [ -85.227080857999908, 10.124579169000071 ], [ -85.240101691999939, 10.116278387000079 ], [ -85.238270636999914, 10.102443752000056 ], [ -85.226470506999931, 10.08938222900008 ], [ -85.195912238999938, 10.07876211100006 ], [ -85.185047980999911, 10.067084052000041 ], [ -85.171864386999914, 10.042059637000079 ], [ -85.165638800999943, 10.042059637000079 ], [ -85.157582160999937, 10.045355536000045 ], [ -85.154082811999899, 10.042669989000046 ], [ -85.15257727799991, 10.035834052000041 ], [ -85.161284959999932, 10.035183010000083 ], [ -85.170277472999942, 10.036322333000044 ], [ -85.178822394999941, 10.038845119000086 ], [ -85.186146613999938, 10.042059637000079 ], [ -85.186146613999938, 10.035834052000041 ], [ -85.167397671565254, 10.019403308315987 ], [ -85.177508511008966, 9.986987615685905 ], [ -85.183373785971412, 9.978822740077362 ], [ -85.205336269952852, 9.973603420261611 ], [ -85.210323045771929, 9.971484686768861 ], [ -85.23613542401057, 9.956756904207737 ], [ -85.240786302146091, 9.955464993015028 ], [ -85.242827521273057, 9.956498520890023 ], [ -85.244713710769133, 9.958152167288688 ], [ -85.246264004380293, 9.959857488732098 ], [ -85.248072678611209, 9.961459459186699 ], [ -85.254868129560521, 9.960787664718964 ], [ -85.265306770091343, 9.957532050563657 ], [ -85.289930589924779, 9.945749822896005 ], [ -85.299103155885916, 9.937378240813132 ], [ -85.303288946927353, 9.929678453198051 ], [ -85.301583624584566, 9.923942369444774 ], [ -85.298224656742491, 9.919394843197438 ], [ -85.294400600907011, 9.916035875355362 ], [ -85.290163133022133, 9.913917140963292 ], [ -85.285925666036633, 9.913245348294197 ], [ -85.276598070444606, 9.914485581744202 ], [ -85.27336829291238, 9.914537257688266 ], [ -85.270319383432764, 9.914433904900761 ], [ -85.261431037412422, 9.912831936244856 ], [ -85.258976407135492, 9.911746731526421 ], [ -85.25466142398551, 9.909266261928451 ], [ -85.25218095618618, 9.908232734053399 ], [ -85.249390428225638, 9.907612616429105 ], [ -85.239933641424386, 9.907715969216611 ], [ -85.23419755677179, 9.906475734867229 ], [ -85.227531297931023, 9.902755031819254 ], [ -85.219831509416622, 9.900119534388978 ], [ -85.217480231027821, 9.898930975983717 ], [ -85.215568203110081, 9.897329006428492 ], [ -85.21130489770286, 9.891437893044326 ], [ -85.205801357946314, 9.886476956546289 ], [ -85.203088345250933, 9.882291165504853 ], [ -85.202003139633177, 9.879914048694388 ], [ -85.200659553395667, 9.877743639257517 ], [ -85.198644171791102, 9.873041083379292 ], [ -85.197765672647677, 9.867098293151685 ], [ -85.196318731824022, 9.861517239029354 ], [ -85.195000983108855, 9.859450182379987 ], [ -85.192908088037825, 9.858003241556332 ], [ -85.190350104074014, 9.857124742412907 ], [ -85.175725674300395, 9.853714097727391 ], [ -85.173839483905056, 9.851802069809651 ], [ -85.173400235232634, 9.849373277055065 ], [ -85.176345791025426, 9.843223782151824 ], [ -85.180144009338562, 9.832940172151211 ], [ -85.190401780917455, 9.794596259209982 ], [ -85.190660163335849, 9.788446764306741 ], [ -85.189264899355578, 9.784312649209369 ], [ -85.186448533872749, 9.781108710098863 ], [ -85.186009284301008, 9.778834946975223 ], [ -85.186939460287874, 9.776974595900867 ], [ -85.192649705619431, 9.772427070552851 ], [ -85.194665087223996, 9.769378160173915 ], [ -85.19683549666081, 9.765037340400909 ], [ -85.199677700565417, 9.756355699056257 ], [ -85.201848110901608, 9.752169908014821 ], [ -85.204251065234473, 9.749534410584545 ], [ -85.206834885821308, 9.747829088241815 ], [ -85.209754604991019, 9.745400295487229 ], [ -85.216188320734375, 9.732222804738626 ], [ -85.218642951011361, 9.730672512026786 ], [ -85.220735846981711, 9.730259100876765 ], [ -85.226626960365934, 9.727571925703785 ], [ -85.229184943430369, 9.724936428273509 ], [ -85.229295448878645, 9.724822572867236 ], [ -85.234527147999927, 9.737331447000088 ], [ -85.238636847999942, 9.742010809000078 ], [ -85.247914191999939, 9.747748114000046 ], [ -85.272979295999903, 9.758002020000049 ], [ -85.275054490999935, 9.76593659100007 ], [ -85.274688279999907, 9.775051174000055 ], [ -85.275502081999946, 9.782009182000081 ], [ -85.299305792999917, 9.808010158000059 ], [ -85.332427537999934, 9.826605536000045 ], [ -85.439971482999908, 9.864528713000084 ], [ -85.449574347999942, 9.862494208000044 ], [ -85.4638972649999, 9.852606512000079 ], [ -85.470366990999935, 9.85024648600006 ], [ -85.480010545999903, 9.852484442000048 ], [ -85.493560350999928, 9.862250067000048 ], [ -85.50454667899993, 9.864528713000084 ], [ -85.510975714999915, 9.865057684000078 ], [ -85.513213670999903, 9.86664459800005 ], [ -85.514515753999945, 9.869655666000085 ], [ -85.518177863999938, 9.874172268000052 ], [ -85.525176561999899, 9.877386786000045 ], [ -85.530995245999918, 9.875881252000056 ], [ -85.534820115999935, 9.872707424000055 ], [ -85.535552537999934, 9.870754299000055 ], [ -85.592071092999902, 9.888739325000074 ], [ -85.619130011999914, 9.89288971600007 ], [ -85.625518357999908, 9.89679596600007 ], [ -85.630604620999918, 9.901556708000044 ], [ -85.638579881999931, 9.905462958000044 ], [ -85.649810350999928, 9.904974677000041 ], [ -85.657215949999909, 9.900539455000057 ], [ -85.663807745999918, 9.900091864000046 ], [ -85.672718878999945, 9.911688544000071 ], [ -85.665557420999903, 9.93032461100006 ], [ -85.676136847999942, 9.955511786000045 ], [ -85.778553839999915, 10.079901434000078 ], [ -85.784657355999911, 10.090887762000079 ], [ -85.792713995999918, 10.11782461100006 ], [ -85.805043097999942, 10.136664130000042 ], [ -85.844024217999902, 10.231024481000077 ], [ -85.847564256999931, 10.259344794000071 ], [ -85.851836717999902, 10.276556708000044 ], [ -85.857696092999902, 10.289089260000083 ], [ -85.843902147999927, 10.302435614000046 ], [ -85.838164842999902, 10.31203847900008 ], [ -85.840321417999917, 10.320135809000078 ], [ -85.861602342999902, 10.346991278000075 ], [ -85.874989386999914, 10.355047919000071 ], [ -85.867583787999934, 10.364894924000055 ], [ -85.85024980399993, 10.378485419000071 ], [ -85.83853105399993, 10.395453192000048 ], [ -85.830352342999902, 10.412014065000051 ], [ -85.813262498999904, 10.405300197000088 ], [ -85.803985154999907, 10.415920315000051 ], [ -85.796742316999939, 10.431423244000086 ], [ -85.775502081999946, 10.447292385000083 ], [ -85.783721482999908, 10.465236721000053 ], [ -85.798817511999914, 10.483954169000071 ], [ -85.80923417899993, 10.494533596000053 ], [ -85.80296790299991, 10.498806057000081 ], [ -85.800282355999911, 10.500270901000079 ], [ -85.795643683999913, 10.501369533000059 ], [ -85.795643683999913, 10.508205471000053 ], [ -85.80923417899993, 10.508205471000053 ], [ -85.80923417899993, 10.515041408000059 ], [ -85.797840949999909, 10.517157294000071 ], [ -85.790516730999911, 10.524115302000041 ], [ -85.781971808999913, 10.542995510000083 ], [ -85.775135870999918, 10.542995510000083 ], [ -85.761219855999911, 10.531805731000077 ], [ -85.741607225999928, 10.539821682000081 ], [ -85.721587693999936, 10.550930080000057 ], [ -85.706288214999915, 10.54913971600007 ], [ -85.700062628999945, 10.54913971600007 ], [ -85.70140540299991, 10.562282619000086 ], [ -85.697987433999913, 10.568630276000079 ], [ -85.692290818999936, 10.572088934000078 ], [ -85.687001105999911, 10.57648346600007 ], [ -85.677845831999946, 10.59210846600007 ], [ -85.674224412999934, 10.59125397300005 ], [ -85.661854620999918, 10.590114651000079 ], [ -85.631743943999936, 10.621161200000074 ], [ -85.634022589999915, 10.629461981000077 ], [ -85.63931230399993, 10.635809637000079 ], [ -85.652251756999931, 10.644720770000049 ], [ -85.693226691999939, 10.603786526000079 ], [ -85.694203253999945, 10.607082424000055 ], [ -85.694081183999913, 10.61001211100006 ], [ -85.695179816999939, 10.61163971600007 ], [ -85.700062628999945, 10.611232815000051 ], [ -85.700062628999945, 10.617458401000079 ], [ -85.688465949999909, 10.629950262000079 ], [ -85.681385870999918, 10.635199286000045 ], [ -85.672718878999945, 10.637884833000044 ], [ -85.679554816999939, 10.644720770000049 ], [ -85.680449998999904, 10.643825588000084 ], [ -85.681792772999927, 10.641913153000075 ], [ -85.683867967999902, 10.639797268000052 ], [ -85.687001105999911, 10.637884833000044 ], [ -85.684478318999936, 10.646185614000046 ], [ -85.683990037999934, 10.64907461100006 ], [ -85.672718878999945, 10.652167059000078 ], [ -85.672718878999945, 10.658392645000049 ], [ -85.679554816999939, 10.658392645000049 ], [ -85.679554816999939, 10.665838934000078 ], [ -85.662871873999904, 10.678981838000084 ], [ -85.659575975999928, 10.712958075000074 ], [ -85.665272589999915, 10.77883535400008 ], [ -85.680287238999938, 10.79633209800005 ], [ -85.713368292999917, 10.81085846600007 ], [ -85.746490037999934, 10.816188869000086 ], [ -85.761504686999899, 10.80609772300005 ], [ -85.767486131999931, 10.80609772300005 ], [ -85.795074022999927, 10.828640041000085 ], [ -85.803089972999942, 10.837184963000084 ], [ -85.798329230999911, 10.835638739000046 ], [ -85.792388475999928, 10.838324286000045 ], [ -85.789906378999945, 10.843898830000057 ], [ -85.795643683999913, 10.850856838000084 ], [ -85.80296790299991, 10.852484442000048 ], [ -85.822295701999906, 10.850612697000088 ], [ -85.830352342999902, 10.850856838000084 ], [ -85.859771287999934, 10.861761786000045 ], [ -85.882923956999946, 10.875148830000057 ], [ -85.908802863999938, 10.886419989000046 ], [ -85.946441209999932, 10.891140041000085 ], [ -85.946441209999932, 10.898586330000057 ], [ -85.923817511999914, 10.904201565000051 ], [ -85.88149980399993, 10.923163153000075 ], [ -85.857696092999902, 10.925930080000057 ], [ -85.861480272999927, 10.932074286000045 ], [ -85.864491339999915, 10.93585846600007 ], [ -85.869130011999914, 10.93813711100006 ], [ -85.878163214999915, 10.939601955000057 ], [ -85.878163214999915, 10.946356512000079 ], [ -85.828724738999938, 10.949286200000074 ], [ -85.816151495999918, 10.946356512000079 ], [ -85.810902472999942, 10.938666083000044 ], [ -85.812163865999935, 10.929714260000083 ], [ -85.814605272999927, 10.922267971000053 ], [ -85.812652147999927, 10.919094143000052 ], [ -85.808501756999931, 10.917181708000044 ], [ -85.795643683999913, 10.905462958000044 ], [ -85.789418097999942, 10.905462958000044 ], [ -85.781971808999913, 10.912868557000081 ], [ -85.781971808999913, 10.919094143000052 ], [ -85.793365037999934, 10.930243231000077 ], [ -85.782460089999915, 10.937445380000042 ], [ -85.761138475999928, 10.940578518000052 ], [ -85.740996873999904, 10.939601955000057 ], [ -85.734160936999899, 10.936428127000056 ], [ -85.725209113999938, 10.927679755000042 ], [ -85.717071092999902, 10.925930080000057 ], [ -85.710560675999943, 10.928290106000077 ], [ -85.707793748999904, 10.934027411000045 ], [ -85.708892381999931, 10.940822658000059 ], [ -85.713734503999945, 10.946356512000079 ], [ -85.713734503999945, 10.953802802000041 ], [ -85.698882615999935, 10.959255276000079 ], [ -85.694691535999937, 10.97024160400008 ], [ -85.698150193999936, 10.983221747000073 ], [ -85.706288214999915, 10.994818427000041 ], [ -85.71353105399993, 11.000026760000083 ], [ -85.730376756999931, 11.006903387000079 ], [ -85.737578904999907, 11.011867580000057 ], [ -85.746001756999931, 11.020656643000052 ], [ -85.746001756999931, 11.023016669000071 ], [ -85.740956183999913, 11.02407461100006 ], [ -85.734160936999899, 11.028957424000055 ], [ -85.718861456999946, 11.042914130000042 ], [ -85.7099910149999, 11.038112697000088 ], [ -85.699615037999934, 11.028631903000075 ], [ -85.679554816999939, 11.028957424000055 ], [ -85.667510545999903, 11.039862372000073 ], [ -85.670196092999902, 11.054388739000046 ], [ -85.681019660999937, 11.068386135000083 ], [ -85.693226691999939, 11.077337958000044 ], [ -85.701735565999883, 11.080880181000097 ], [ -85.677582153999907, 11.119632467000059 ], [ -85.659314534999851, 11.158829041000018 ], [ -85.631150879999893, 11.196216939000067 ], [ -85.597793741999936, 11.209937032000099 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CR-L", "NAME_1": "Limón" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -82.719726521999945, 9.541330872000032 ], [ -82.729364176999951, 9.544896546000089 ], [ -82.771092895999885, 9.579855652000091 ], [ -82.829022175999938, 9.6027224730001 ], [ -82.847470662999854, 9.600655416000052 ], [ -82.866048340999896, 9.585074972000101 ], [ -82.877391316999876, 9.569184469000092 ], [ -82.879251668999899, 9.55990854900007 ], [ -82.867133544999888, 9.538643697000097 ], [ -82.860208902999915, 9.511203512000037 ], [ -82.855919758999846, 9.505441590000075 ], [ -82.849382690999875, 9.503477885000038 ], [ -82.844783488999923, 9.500687358000079 ], [ -82.846385457999958, 9.492548320000068 ], [ -82.861294108999914, 9.484099223000072 ], [ -82.914624186999902, 9.476864522000099 ], [ -82.933305216999969, 9.470327454000127 ], [ -82.941702636999935, 9.45634897900004 ], [ -82.944286458999869, 9.437151185000118 ], [ -82.94320125399986, 9.354313863000101 ], [ -82.941650960999937, 9.234424540000134 ], [ -82.93952108499991, 9.070641889000072 ], [ -82.940229050829998, 9.071229559896267 ], [ -82.949504971377337, 9.078929348410668 ], [ -82.952657232745082, 9.080996405060034 ], [ -82.968831957029181, 9.086060696144216 ], [ -82.985807665191601, 9.102855536253969 ], [ -82.990897792898807, 9.110245266405911 ], [ -82.997150642388192, 9.127505195408446 ], [ -83.002473314092128, 9.135825099748558 ], [ -83.006607429189501, 9.138357245290649 ], [ -83.012860276880247, 9.14125112603864 ], [ -83.047302618720835, 9.150759588783956 ], [ -83.050299852256387, 9.152516587970126 ], [ -83.053090380216872, 9.154997057568153 ], [ -83.056113451274769, 9.160164700540463 ], [ -83.057482875933943, 9.163885402689175 ], [ -83.068386603558906, 9.217628891759944 ], [ -83.071952276975992, 9.227447415565734 ], [ -83.074277716943072, 9.231788235338797 ], [ -83.075750495289128, 9.233751939200602 ], [ -83.077559170419363, 9.235405584699947 ], [ -83.079626227968049, 9.236955878311107 ], [ -83.115437995367188, 9.257109687162313 ], [ -83.119391242411893, 9.259951890167599 ], [ -83.12660010361185, 9.266773180437895 ], [ -83.165667486964935, 9.316847642404753 ], [ -83.170008307637261, 9.318087876754078 ], [ -83.176571214589842, 9.318811347165934 ], [ -83.198068609678558, 9.317261054454093 ], [ -83.211917893995576, 9.314728908912002 ], [ -83.215328538681092, 9.314728908912002 ], [ -83.220625372862628, 9.315659084898812 ], [ -83.227705043752735, 9.317777818391619 ], [ -83.243337164778325, 9.32568431248103 ], [ -83.252871466844681, 9.332040513858601 ], [ -83.257677374611148, 9.334520982557308 ], [ -83.276151700440607, 9.340618801516484 ], [ -83.281267665670214, 9.342892563740804 ], [ -83.283567268114894, 9.344287827721075 ], [ -83.28584103123859, 9.345373033338831 ], [ -83.30434119279181, 9.361289374305159 ], [ -83.30873369030752, 9.364183254153829 ], [ -83.313462083708202, 9.366560370065031 ], [ -83.316795214027877, 9.36671539969592 ], [ -83.321136033800883, 9.36594025334 ], [ -83.328448248687721, 9.36211619750452 ], [ -83.332143114213352, 9.359739080693998 ], [ -83.334726935699507, 9.357258612894668 ], [ -83.346405808781014, 9.341032213565768 ], [ -83.34805945517968, 9.339326890323719 ], [ -83.352296923064557, 9.337931627242767 ], [ -83.371003791092051, 9.336174628056654 ], [ -83.376584846113758, 9.334831040919767 ], [ -83.380305549161733, 9.333074041733653 ], [ -83.383845384157155, 9.329456692372446 ], [ -83.385705736130774, 9.328009752448111 ], [ -83.38795366083275, 9.326666165311281 ], [ -83.390124071168941, 9.32645945883695 ], [ -83.392371995870917, 9.32738963482376 ], [ -83.395007494200456, 9.335141099282282 ], [ -83.395627610925487, 9.338396715236229 ], [ -83.396402757281408, 9.341032213565768 ], [ -83.400045945963598, 9.344132798989449 ], [ -83.403275722596504, 9.34609650285131 ], [ -83.42939816009698, 9.353692939477583 ], [ -83.441645473959454, 9.362322903079473 ], [ -83.445159471432419, 9.36573354686567 ], [ -83.453634406302797, 9.377309068059049 ], [ -83.48686235221578, 9.467587794940755 ], [ -83.490428025632866, 9.478284816990708 ], [ -83.496835903853878, 9.491462306839992 ], [ -83.498954637346628, 9.494356186688663 ], [ -83.502158575557814, 9.497766832273498 ], [ -83.50401892843081, 9.500505683390543 ], [ -83.510065069647226, 9.514044908445783 ], [ -83.512132128095232, 9.526395575095705 ], [ -83.514302538431366, 9.535852362796277 ], [ -83.51091773126825, 9.566444810379664 ], [ -83.496990932585447, 9.594556790163722 ], [ -83.439113329316683, 9.663286445113329 ], [ -83.416634081397717, 9.719717109357077 ], [ -83.40875342483065, 9.732119451951121 ], [ -83.378548549975562, 9.7683446313996 ], [ -83.335915493205448, 9.821002915751933 ], [ -83.329249234364681, 9.838262843855148 ], [ -83.331833054951517, 9.856452947945172 ], [ -83.343382737723175, 9.891902981037731 ], [ -83.344855516069174, 9.913917140963292 ], [ -83.34154822507054, 9.931590481115791 ], [ -83.333641730081752, 9.947920234131459 ], [ -83.321291063431829, 9.965748603015584 ], [ -83.318913946621308, 9.969624334795185 ], [ -83.338990241106728, 9.973603420261611 ], [ -83.444901089014024, 9.976032213016197 ], [ -83.589052497075045, 9.977169094578016 ], [ -83.615226609620322, 9.986574205435204 ], [ -83.713256801859927, 10.031739406848146 ], [ -83.773563198782597, 10.059954739419652 ], [ -83.817462328323757, 10.080418605734053 ], [ -83.942726000304674, 10.136229153252827 ], [ -83.929083421562666, 10.181187649090703 ], [ -83.922546353031748, 10.190127671954485 ], [ -83.913554654223901, 10.198964342030763 ], [ -83.866477423993899, 10.248728746534425 ], [ -83.863402676092619, 10.253534654300836 ], [ -83.85107784696504, 10.279269517274372 ], [ -83.848416511113101, 10.286504217795425 ], [ -83.84722795270784, 10.291981920029571 ], [ -83.847718879122965, 10.294772447090736 ], [ -83.84686621840126, 10.306916409065025 ], [ -83.843610603346633, 10.321230780476128 ], [ -83.842732103303888, 10.328310452265555 ], [ -83.842912971356554, 10.333219712819471 ], [ -83.844127367284159, 10.335493475943167 ], [ -83.84722795270784, 10.339317531778647 ], [ -83.849863451037436, 10.343348293189138 ], [ -83.851749641432775, 10.348412584273319 ], [ -83.854798550013072, 10.359264635054842 ], [ -83.868131070392565, 10.383759264578373 ], [ -83.869422979786691, 10.387531643570469 ], [ -83.87167090538793, 10.402104397400024 ], [ -83.871076626185356, 10.408047186728254 ], [ -83.870275642307035, 10.412336331456515 ], [ -83.866787482356415, 10.419519355134128 ], [ -83.863945279351128, 10.423601793388059 ], [ -83.855935431574892, 10.438846339886652 ], [ -83.853920050869647, 10.441223455797854 ], [ -83.85164628774595, 10.442256985471488 ], [ -83.849010790315731, 10.442567042934684 ], [ -83.846246100776909, 10.443290514245803 ], [ -83.843998176074933, 10.444479070852424 ], [ -83.842060309735473, 10.446029364463584 ], [ -83.838029548324982, 10.450111802717515 ], [ -83.829037848617816, 10.463651027772698 ], [ -83.823430956073764, 10.484631658923888 ], [ -83.823405117652044, 10.489592597220565 ], [ -83.823870204746129, 10.492331448337666 ], [ -83.827875128634275, 10.502201646288938 ], [ -83.828495246258569, 10.505198878925114 ], [ -83.828650274990196, 10.50860952450995 ], [ -83.827720099902649, 10.516774400118436 ], [ -83.827616747115144, 10.520081692016447 ], [ -83.828030158265165, 10.522975571865118 ], [ -83.829192878248705, 10.525301011832198 ], [ -83.830588142228976, 10.527419745324949 ], [ -83.833766242018442, 10.53114044837298 ], [ -83.835239021263817, 10.533207505921666 ], [ -83.836195034773027, 10.535584621832811 ], [ -83.836350064403916, 10.541475735216977 ], [ -83.830691494117161, 10.584367174405543 ], [ -83.831363287685576, 10.593772284363411 ], [ -83.829968023705305, 10.624261379159293 ], [ -83.828650274990196, 10.633356432553285 ], [ -83.82699663039017, 10.639247545038131 ], [ -83.825394659935569, 10.641056220168423 ], [ -83.821570604100089, 10.644260159278929 ], [ -83.813121506752111, 10.64968618377037 ], [ -83.803509691219233, 10.65464712206699 ], [ -83.799556444174527, 10.657644354703166 ], [ -83.789531215693046, 10.668289699909735 ], [ -83.772581345952347, 10.679090073847817 ], [ -83.762142707220164, 10.682552395376717 ], [ -83.756329108201783, 10.683740952882658 ], [ -83.72715776212101, 10.686221422480628 ], [ -83.716615769702003, 10.688856919910904 ], [ -83.712765876344122, 10.688960272698409 ], [ -83.709174363605996, 10.688650214335894 ], [ -83.704575161414539, 10.687151598467494 ], [ -83.703567471061945, 10.688081773554984 ], [ -83.703696662271113, 10.689787095897771 ], [ -83.70578955824152, 10.6929910341089 ], [ -83.70827002604085, 10.695833238013506 ], [ -83.711990729088882, 10.698933824336507 ], [ -83.720646532011813, 10.704153144152258 ], [ -83.724573940634855, 10.707357083262764 ], [ -83.72793290937625, 10.71076772704896 ], [ -83.73100765727753, 10.71459178288444 ], [ -83.731886156420956, 10.718105780357462 ], [ -83.732273729149256, 10.722963364967313 ], [ -83.72927649561376, 10.743013821031013 ], [ -83.729431525244706, 10.746527818504035 ], [ -83.729999966025616, 10.749835110401989 ], [ -83.732738817142661, 10.754641018168456 ], [ -83.736511197034076, 10.759136868471671 ], [ -83.741549648797218, 10.763994452182203 ], [ -83.743849250342635, 10.765648098580868 ], [ -83.74625220377618, 10.767146715348645 ], [ -83.749352790099181, 10.768335272854529 ], [ -83.760799120083334, 10.771487535121651 ], [ -83.763818115413699, 10.773683167843899 ], [ -83.698142252999872, 10.789161682000071 ], [ -83.66302811699984, 10.807015889000112 ], [ -83.660134236999852, 10.834171855000093 ], [ -83.669306803999945, 10.869751078000064 ], [ -83.669854510493167, 10.891717678072528 ], [ -83.679831847356198, 10.897010590307339 ], [ -83.676850114500567, 10.910298763549688 ], [ -83.678799709060002, 10.916154380185779 ], [ -83.680976324785831, 10.917119398852687 ], [ -83.688754410845718, 10.93458680566807 ], [ -83.696499785854115, 10.936594144736317 ], [ -83.686867076854611, 10.937970246495594 ], [ -83.681766322780319, 10.935434518184676 ], [ -83.67833546290187, 10.935952757867287 ], [ -83.672991238860462, 10.933231989430151 ], [ -83.672991238860462, 10.931288568122966 ], [ -83.675564383769284, 10.929409915424063 ], [ -83.675564383769284, 10.925976484931059 ], [ -83.671275808921237, 10.926494741135784 ], [ -83.666195497178151, 10.931223787193453 ], [ -83.665352396489226, 10.935318186754772 ], [ -83.660755988999938, 10.934393622000073 ], [ -83.644357876999948, 10.925930080000057 ], [ -83.624256964999915, 10.902899481000077 ], [ -83.598703579999949, 10.856594143000052 ], [ -83.580555792999917, 10.807318427000041 ], [ -83.582875128999945, 10.77570221600007 ], [ -83.597564256999931, 10.79360586100006 ], [ -83.623850063999896, 10.857611395000049 ], [ -83.606922980999911, 10.777777411000045 ], [ -83.608631964999915, 10.745510158000059 ], [ -83.637521938999896, 10.721096096000053 ], [ -83.622222459999932, 10.723863023000092 ], [ -83.611887173999946, 10.730861721000053 ], [ -83.602162238999938, 10.739569403000075 ], [ -83.589100714999915, 10.747748114000046 ], [ -83.593658006999931, 10.742661851000037 ], [ -83.594715949999909, 10.736558335000041 ], [ -83.593006964999915, 10.729315497000073 ], [ -83.589100714999915, 10.721096096000053 ], [ -83.585275844999899, 10.732855536000045 ], [ -83.581044074999909, 10.755804755000042 ], [ -83.575428839999915, 10.768255927000041 ], [ -83.526966925999943, 10.636053778000075 ], [ -83.466175910999937, 10.494533596000053 ], [ -83.394520636999914, 10.376044012000079 ], [ -83.203724738999938, 10.129339911000045 ], [ -83.188384568999936, 10.117743231000077 ], [ -83.124663865999935, 10.040594794000071 ], [ -83.085316535999937, 10.002142645000049 ], [ -83.061512824999909, 10.015326239000046 ], [ -83.052398240999935, 10.009588934000078 ], [ -83.02603105399993, 10.005031643000052 ], [ -83.020578579999949, 9.997381903000075 ], [ -83.01984615799995, 9.978705145000049 ], [ -83.016672329999949, 9.963120835000041 ], [ -83.009348110999952, 9.949286200000074 ], [ -82.99632727799991, 9.935939846000053 ], [ -82.949777798999946, 9.867580471000053 ], [ -82.934885219999899, 9.857082424000055 ], [ -82.87726803299995, 9.780096747000073 ], [ -82.833811001999948, 9.739488023000092 ], [ -82.808257615999935, 9.747219143000052 ], [ -82.802479620999918, 9.731512762000079 ], [ -82.796986456999946, 9.691229559000078 ], [ -82.78774980399993, 9.672756252000056 ], [ -82.772328253999945, 9.661037502000056 ], [ -82.705230272999927, 9.637925523000092 ], [ -82.681385870999918, 9.63548411700009 ], [ -82.657948370999918, 9.636297919000071 ], [ -82.635894334999932, 9.634507554000038 ], [ -82.616444464999915, 9.624335028000075 ], [ -82.591420050999943, 9.586981512000079 ], [ -82.574574347999942, 9.57680898600006 ], [ -82.573597785999937, 9.576198635000083 ], [ -82.562836873999913, 9.53869537300011 ], [ -82.570614176999925, 9.538230285000083 ], [ -82.585884562999865, 9.546240133000055 ], [ -82.601103271999904, 9.548668925000115 ], [ -82.608208781999934, 9.537868551000088 ], [ -82.612394572999875, 9.499498800000055 ], [ -82.618854125999917, 9.486708883000077 ], [ -82.632134969999925, 9.484667663000039 ], [ -82.650712646999892, 9.487845764000085 ], [ -82.668205118999936, 9.493168437000037 ], [ -82.678049479999913, 9.497767639000088 ], [ -82.688668986999915, 9.509446513000057 ], [ -82.701458903999878, 9.53355356900002 ], [ -82.711690836999963, 9.544999899000118 ], [ -82.719726521999945, 9.541330872000032 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CR-P", "NAME_1": "Puntarenas" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -82.93952108499991, 9.070641889000072 ], [ -82.939377197999931, 9.059577332000032 ], [ -82.90945654399988, 9.072005514000097 ], [ -82.900232299999885, 9.072057190000109 ], [ -82.893281819999885, 9.066941224000033 ], [ -82.889690307999928, 9.059370626000074 ], [ -82.88687394299987, 9.051489970000119 ], [ -82.882429769999931, 9.04534047500006 ], [ -82.876564494999855, 9.041929830000129 ], [ -82.854085246999944, 9.031982117000041 ], [ -82.80817073599988, 8.9983665970001 ], [ -82.762695475999919, 8.98299285900012 ], [ -82.749130411999914, 8.974078674000097 ], [ -82.72334387199993, 8.930928854000072 ], [ -82.719364786999847, 8.921523743000108 ], [ -82.720156710164019, 8.92023775007209 ], [ -82.733860025999974, 8.897985128000116 ], [ -82.763780679999911, 8.879950053000115 ], [ -82.866926839999934, 8.838066304000051 ], [ -82.8785798749999, 8.829772238000089 ], [ -82.888320882999949, 8.816930644000095 ], [ -82.883566650999853, 8.812383118000071 ], [ -82.875634318999914, 8.807525533000046 ], [ -82.875789347999842, 8.793908793000043 ], [ -82.885116943999975, 8.78318593400013 ], [ -82.914882568999957, 8.764789124000032 ], [ -82.92296992999988, 8.756159160000081 ], [ -82.924158488999893, 8.741198832000123 ], [ -82.919223388999939, 8.72706532800008 ], [ -82.910335042999918, 8.713913676000104 ], [ -82.878941609999913, 8.679057923000045 ], [ -82.862224284999854, 8.655700176000096 ], [ -82.849796102999875, 8.629861959000067 ], [ -82.841863769999918, 8.599476217000117 ], [ -82.835972656999928, 8.52976471000008 ], [ -82.838918213999932, 8.494624736000034 ], [ -82.848297485999865, 8.46516916900012 ], [ -82.870414998999877, 8.438116557000072 ], [ -82.896511596999886, 8.425352478000107 ], [ -82.924778604999858, 8.41674835200007 ], [ -82.953510701999875, 8.402098084000087 ], [ -82.997771565999898, 8.360162659000096 ], [ -83.043298502999875, 8.334737854000082 ], [ -83.052109334999869, 8.327632345000055 ], [ -83.053246216999952, 8.315100810000047 ], [ -83.044073649999859, 8.305359803000101 ], [ -83.016065023999943, 8.289004211000062 ], [ -83.010768188999918, 8.283371480000127 ], [ -83.001104695999885, 8.269237976000085 ], [ -82.995523640999892, 8.264819641000088 ], [ -82.989193277999874, 8.264457907000093 ], [ -82.977126830999879, 8.269237976000085 ], [ -82.968005940999888, 8.267971904000134 ], [ -82.95051346899993, 8.258825175000055 ], [ -82.943666341999887, 8.248567403000067 ], [ -82.939092977999849, 8.216838074000052 ], [ -82.886408854999928, 8.102193909000093 ], [ -82.891369791999892, 8.057545471000068 ], [ -82.897629258999899, 8.034748020000023 ], [ -82.911244269999941, 8.045355536000045 ], [ -82.909698045999903, 8.060614325000074 ], [ -82.902129686999899, 8.077460028000075 ], [ -82.897613084999932, 8.092800197000088 ], [ -82.900380011999914, 8.105047919000071 ], [ -82.968495245999918, 8.221218166000085 ], [ -82.992583787999934, 8.24640534100007 ], [ -83.116851365999935, 8.336127020000049 ], [ -83.150868292999917, 8.369289455000057 ], [ -83.121490037999934, 8.40493398600006 ], [ -83.116078253999945, 8.407782294000071 ], [ -83.110463019999941, 8.418036200000074 ], [ -83.099598761999914, 8.431341864000046 ], [ -83.092681443999936, 8.446682033000059 ], [ -83.099029100999928, 8.462713934000078 ], [ -83.131703253999945, 8.503200588000084 ], [ -83.137196417999917, 8.514553127000056 ], [ -83.1377253899999, 8.529323635000083 ], [ -83.130604620999918, 8.534491278000075 ], [ -83.118153449999909, 8.538153387000079 ], [ -83.102447068999936, 8.548041083000044 ], [ -83.114247199999909, 8.551784572000088 ], [ -83.143422003999945, 8.55023834800005 ], [ -83.157704230999911, 8.555487372000073 ], [ -83.165150519999941, 8.563747463000084 ], [ -83.185047980999911, 8.602687893000052 ], [ -83.181752081999946, 8.607855536000045 ], [ -83.180165167999917, 8.611354885000083 ], [ -83.178212042999917, 8.616970119000086 ], [ -83.171376105999911, 8.616970119000086 ], [ -83.161732550999943, 8.600734768000052 ], [ -83.158802863999938, 8.592800197000088 ], [ -83.157704230999911, 8.579413153000075 ], [ -83.153309699999909, 8.577175197000088 ], [ -83.123565232999908, 8.589016018000052 ], [ -83.123565232999908, 8.596462307000081 ], [ -83.137237107999908, 8.60219961100006 ], [ -83.151722785999937, 8.612860419000071 ], [ -83.164051886999914, 8.62563711100006 ], [ -83.171376105999911, 8.637477932000081 ], [ -83.178212042999917, 8.637477932000081 ], [ -83.18578040299991, 8.625189520000049 ], [ -83.203968878999945, 8.62445709800005 ], [ -83.224761522999927, 8.626857815000051 ], [ -83.240264451999906, 8.623806057000081 ], [ -83.247588670999903, 8.637233791000085 ], [ -83.259307420999903, 8.651312567000048 ], [ -83.273182745999918, 8.658474026000079 ], [ -83.287383592999902, 8.651068427000041 ], [ -83.319081183999913, 8.669582424000055 ], [ -83.32835852799991, 8.684597072000088 ], [ -83.322173631999931, 8.70571523600006 ], [ -83.329009568999936, 8.706203518000052 ], [ -83.335804816999939, 8.70571523600006 ], [ -83.331695115999935, 8.722072658000059 ], [ -83.345855272999927, 8.72992584800005 ], [ -83.366932745999918, 8.734279690000051 ], [ -83.383656378999945, 8.739813544000071 ], [ -83.389515753999945, 8.728094794000071 ], [ -83.394805467999902, 8.728949286000045 ], [ -83.4013972649999, 8.733710028000075 ], [ -83.411529100999928, 8.733669338000084 ], [ -83.416289842999902, 8.728298244000086 ], [ -83.417510545999903, 8.721258856000077 ], [ -83.421660936999899, 8.71515534100007 ], [ -83.435170050999943, 8.712551174000055 ], [ -83.468251105999911, 8.717474677000041 ], [ -83.481719529999907, 8.712591864000046 ], [ -83.486683722999942, 8.692694403000075 ], [ -83.479115363999938, 8.698431708000044 ], [ -83.479237433999913, 8.698879299000055 ], [ -83.473011847999942, 8.698879299000055 ], [ -83.437896287999934, 8.646429755000042 ], [ -83.433257615999935, 8.630519924000055 ], [ -83.41274980399993, 8.598456122000073 ], [ -83.404774542999917, 8.589016018000052 ], [ -83.391590949999909, 8.582302151000079 ], [ -83.354237433999913, 8.571071682000081 ], [ -83.339222785999937, 8.569159247000073 ], [ -83.325469529999907, 8.560980536000045 ], [ -83.312367316999939, 8.545070705000057 ], [ -83.299712693999936, 8.534369208000044 ], [ -83.287383592999902, 8.541815497000073 ], [ -83.286854620999918, 8.517157294000071 ], [ -83.288848436999899, 8.507025458000044 ], [ -83.294911261999914, 8.500270901000079 ], [ -83.294911261999914, 8.493434963000084 ], [ -83.279815232999908, 8.472927151000079 ], [ -83.273711717999902, 8.437933661000045 ], [ -83.276356574999909, 8.401556708000044 ], [ -83.287383592999902, 8.376735744000086 ], [ -83.309844529999907, 8.375921942000048 ], [ -83.346424933999913, 8.387600002000056 ], [ -83.380889451999906, 8.404120184000078 ], [ -83.397246873999904, 8.417669989000046 ], [ -83.391102667999917, 8.417669989000046 ], [ -83.386626756999931, 8.414129950000074 ], [ -83.382964647999927, 8.412502346000053 ], [ -83.36937415299991, 8.410915432000081 ], [ -83.388661261999914, 8.419501044000071 ], [ -83.396473761999914, 8.424587307000081 ], [ -83.404774542999917, 8.43195221600007 ], [ -83.404774542999917, 8.417669989000046 ], [ -83.462432420999903, 8.442694403000075 ], [ -83.482940232999908, 8.44562409100007 ], [ -83.544178839999915, 8.438259182000081 ], [ -83.561146613999938, 8.438177802000041 ], [ -83.575591600999928, 8.444973049000055 ], [ -83.5888972649999, 8.458563544000071 ], [ -83.613270636999914, 8.490016994000086 ], [ -83.7002253899999, 8.570339260000083 ], [ -83.705799933999913, 8.579413153000075 ], [ -83.710113084999932, 8.580511786000045 ], [ -83.730580206999946, 8.588812567000048 ], [ -83.736805792999917, 8.592718817000048 ], [ -83.739898240999935, 8.623806057000081 ], [ -83.709462042999917, 8.670355536000045 ], [ -83.702381964999915, 8.678412177000041 ], [ -83.686675584999932, 8.687689520000049 ], [ -83.675933397999927, 8.691799221000053 ], [ -83.671009894999941, 8.68891022300005 ], [ -83.667836066999939, 8.682928778000075 ], [ -83.660918748999904, 8.689846096000053 ], [ -83.636586066999939, 8.726752020000049 ], [ -83.630034959999932, 8.733669338000084 ], [ -83.642567511999914, 8.74953847900008 ], [ -83.627471482999908, 8.767401434000078 ], [ -83.600005662999934, 8.782049872000073 ], [ -83.575428839999915, 8.788275458000044 ], [ -83.575428839999915, 8.79446035400008 ], [ -83.597075975999928, 8.797023830000057 ], [ -83.607940232999908, 8.796047268000052 ], [ -83.615386522999927, 8.790106512000079 ], [ -83.626942511999914, 8.777736721000053 ], [ -83.638661261999914, 8.772284247000073 ], [ -83.642567511999914, 8.78188711100006 ], [ -83.637806769999941, 8.798854885000083 ], [ -83.623809373999904, 8.815578518000052 ], [ -83.599029100999928, 8.827541408000059 ], [ -83.587635870999918, 8.835353908000059 ], [ -83.582875128999945, 8.846625067000048 ], [ -83.589100714999915, 8.856756903000075 ], [ -83.602080857999908, 8.863796291000085 ], [ -83.613880988999938, 8.873236395000049 ], [ -83.616363084999932, 8.890692450000074 ], [ -83.597035285999937, 8.880886135000083 ], [ -83.587676561999899, 8.877997137000079 ], [ -83.575428839999915, 8.877630927000041 ], [ -83.581410285999937, 8.884955145000049 ], [ -83.588978644999941, 8.890529690000051 ], [ -83.603382941999939, 8.898138739000046 ], [ -83.609486456999946, 8.903143622000073 ], [ -83.612945115999935, 8.907782294000071 ], [ -83.618275519999941, 8.910956122000073 ], [ -83.630034959999932, 8.911769924000055 ], [ -83.617909308999913, 8.919012762000079 ], [ -83.619618292999917, 8.924261786000045 ], [ -83.626576300999943, 8.928249416000085 ], [ -83.630034959999932, 8.931667385000083 ], [ -83.625518357999908, 8.942653713000084 ], [ -83.620391404999907, 8.950832424000055 ], [ -83.613392706999946, 8.958075262000079 ], [ -83.603382941999939, 8.966376044000071 ], [ -83.629872199999909, 9.035345770000049 ], [ -83.634755011999914, 9.044094143000052 ], [ -83.651153123999904, 9.06195709800005 ], [ -83.657989061999899, 9.055202541000085 ], [ -83.680449998999904, 9.084133205000057 ], [ -83.700917120999918, 9.117865302000041 ], [ -83.72720292899993, 9.144313869000086 ], [ -83.767201300999943, 9.151393947000088 ], [ -83.764881964999915, 9.17719147300005 ], [ -83.786895311999899, 9.199245510000083 ], [ -83.817128058999913, 9.214504299000055 ], [ -83.839507615999935, 9.220282294000071 ], [ -83.918080206999946, 9.294745184000078 ], [ -83.995106574999909, 9.330226955000057 ], [ -84.007435675999943, 9.339748440000051 ], [ -84.103627081999946, 9.37726471600007 ], [ -84.109852667999917, 9.37726471600007 ], [ -84.116322394999941, 9.37258535400008 ], [ -84.121937628999945, 9.372626044000071 ], [ -84.126616990999935, 9.376898505000042 ], [ -84.130360480999911, 9.384711005000042 ], [ -84.144073045999903, 9.378851630000042 ], [ -84.152251756999931, 9.385321356000077 ], [ -84.161529100999928, 9.394720770000049 ], [ -84.178700324999909, 9.397772528000075 ], [ -84.167958136999914, 9.416205145000049 ], [ -84.182240363999938, 9.442206122000073 ], [ -84.208363410999937, 9.464992580000057 ], [ -84.233387824999909, 9.473456122000073 ], [ -84.233387824999909, 9.466701565000051 ], [ -84.224598761999914, 9.464992580000057 ], [ -84.218658006999931, 9.462551174000055 ], [ -84.205433722999942, 9.453029690000051 ], [ -84.231434699999909, 9.457546291000085 ], [ -84.272694464999915, 9.481594143000052 ], [ -84.298858201999906, 9.487127997000073 ], [ -84.324208136999914, 9.489081122000073 ], [ -84.457915818999936, 9.52602773600006 ], [ -84.483509894999941, 9.528102932000081 ], [ -84.495472785999937, 9.52602773600006 ], [ -84.508290167999917, 9.521999416000085 ], [ -84.521595831999946, 9.519313869000086 ], [ -84.535023566999939, 9.521307684000078 ], [ -84.546742316999939, 9.531073309000078 ], [ -84.550689256999931, 9.542873440000051 ], [ -84.555409308999913, 9.552394924000055 ], [ -84.569121873999904, 9.555446682000081 ], [ -84.566558397999927, 9.55141836100006 ], [ -84.56509355399993, 9.548407294000071 ], [ -84.562977667999917, 9.541164455000057 ], [ -84.579497850999928, 9.554348049000055 ], [ -84.616566535999937, 9.578070380000042 ], [ -84.623768683999913, 9.592962958000044 ], [ -84.627308722999942, 9.606716213000084 ], [ -84.636097785999937, 9.613348700000074 ], [ -84.647206183999913, 9.617702541000085 ], [ -84.657948370999918, 9.624335028000075 ], [ -84.661366339999915, 9.634466864000046 ], [ -84.659942186999899, 9.644924221000053 ], [ -84.662709113999938, 9.651678778000075 ], [ -84.67837480399993, 9.65102773600006 ], [ -84.674427863999938, 9.662380276000079 ], [ -84.675526495999918, 9.67328522300005 ], [ -84.678089972999942, 9.683539130000042 ], [ -84.67837480399993, 9.692572333000044 ], [ -84.672474738999938, 9.703802802000041 ], [ -84.655262824999909, 9.720770575000074 ], [ -84.648467576999906, 9.737697658000059 ], [ -84.641468878999945, 9.746120510000083 ], [ -84.634429490999935, 9.757025458000044 ], [ -84.631214972999942, 9.771429755000042 ], [ -84.634551561999899, 9.783392645000049 ], [ -84.642364061999899, 9.793768622000073 ], [ -84.657948370999918, 9.809271552000041 ], [ -84.698394334999932, 9.868841864000046 ], [ -84.709706183999913, 9.87759023600006 ], [ -84.725941535999937, 9.884466864000046 ], [ -84.723784959999932, 9.899603583000044 ], [ -84.709706183999913, 9.922552802000041 ], [ -84.734283006999931, 9.942572333000044 ], [ -84.738799607999908, 9.952297268000052 ], [ -84.733631964999915, 9.966945705000057 ], [ -84.762318488999938, 9.975653387000079 ], [ -84.850941535999937, 9.966945705000057 ], [ -84.850941535999937, 9.974391994000086 ], [ -84.838653123999904, 9.97915273600006 ], [ -84.82290605399993, 9.980861721000053 ], [ -84.788238084999932, 9.980617580000057 ], [ -84.788238084999932, 9.987453518000052 ], [ -84.820098436999899, 9.988959052000041 ], [ -84.848540818999936, 9.993963934000078 ], [ -84.874256964999915, 10.002630927000041 ], [ -84.898101365999935, 10.015326239000046 ], [ -84.928252732999908, 10.040106512000079 ], [ -84.932850714999915, 10.045477606000077 ], [ -84.939320441999939, 10.046942450000074 ], [ -84.952015753999945, 10.055446682000081 ], [ -84.960967576999906, 10.064886786000045 ], [ -84.956166144999941, 10.069362697000088 ], [ -84.97288977799991, 10.077948309000078 ], [ -85.01390540299991, 10.115993557000081 ], [ -85.035755988999938, 10.126735744000086 ], [ -85.046050584999932, 10.136135158000059 ], [ -85.052357550999943, 10.138251044000071 ], [ -85.057362433999913, 10.136013088000084 ], [ -85.061675584999932, 10.13226959800005 ], [ -85.067372199999909, 10.131415106000077 ], [ -85.076201951999906, 10.138251044000071 ], [ -85.070301886999914, 10.148871161000045 ], [ -85.068348761999914, 10.155666408000059 ], [ -85.068565921124971, 10.155815093516726 ], [ -85.068393723991164, 10.155866197267187 ], [ -85.048369107248504, 10.161808987494737 ], [ -85.040152553897201, 10.161653957863848 ], [ -85.037077805995921, 10.161137193027002 ], [ -85.033873867784735, 10.161033840239497 ], [ -85.027621019194669, 10.161653957863848 ], [ -85.021962449807177, 10.162739163481604 ], [ -85.019197761167732, 10.162790839425668 ], [ -85.016562262838136, 10.162170721801374 ], [ -85.014366014080281, 10.161137193027002 ], [ -85.010593635088185, 10.158036606704002 ], [ -85.008500739117778, 10.156589666779666 ], [ -85.006175300050018, 10.155607814848736 ], [ -85.003513964198078, 10.154987698123762 ], [ -85.001085171443492, 10.155142726855331 ], [ -84.999483201888268, 10.155452786117166 ], [ -84.994367234859965, 10.157003078829007 ], [ -84.990388150292858, 10.157623196453358 ], [ -84.987158372760689, 10.157468166822412 ], [ -84.984212816068577, 10.156848049198118 ], [ -84.979251878671221, 10.154936021280321 ], [ -84.970053474288363, 10.149975083883021 ], [ -84.968038092683798, 10.148528143958686 ], [ -84.960570848166071, 10.142120265737674 ], [ -84.948375210247718, 10.126927395183145 ], [ -84.944706184043127, 10.123310044922619 ], [ -84.93685136589778, 10.117367254695012 ], [ -84.927575446249818, 10.112457994141096 ], [ -84.925043300707728, 10.111631170941791 ], [ -84.922330288012347, 10.11101105421676 ], [ -84.919927333679482, 10.111217759791771 ], [ -84.918351203445241, 10.112768053402931 ], [ -84.918867967382766, 10.116592109238411 ], [ -84.922640347274182, 10.127289130389045 ], [ -84.923699713570898, 10.133025214142322 ], [ -84.923622199205113, 10.136125800465322 ], [ -84.922795376005809, 10.142223619424499 ], [ -84.920108201732091, 10.14666779198501 ], [ -84.915405645853866, 10.152352199794166 ], [ -84.897344732973011, 10.16806183518554 ], [ -84.892978074778284, 10.170904039090146 ], [ -84.87380611785801, 10.179120592441393 ], [ -84.8717390612087, 10.181756089871612 ], [ -84.870085414810035, 10.185166734557129 ], [ -84.869542813350165, 10.192401435078125 ], [ -84.870240445340244, 10.196173814070278 ], [ -84.871635708421195, 10.199067694818268 ], [ -84.87481380910998, 10.202685045078738 ], [ -84.876183233769211, 10.204752101728104 ], [ -84.877139248177741, 10.206922512064239 ], [ -84.877940232955382, 10.209402980762945 ], [ -84.877914395432981, 10.212090155036606 ], [ -84.876984219446172, 10.215500799722122 ], [ -84.870886399587675, 10.228109848790496 ], [ -84.869878710134344, 10.231107083225311 ], [ -84.867630785432368, 10.25033071519033 ], [ -84.862954067975863, 10.263559881883054 ], [ -84.862488979982402, 10.266247057056034 ], [ -84.862850715188358, 10.26888255538563 ], [ -84.863600023122558, 10.27151805281585 ], [ -84.864917771837668, 10.273481757577031 ], [ -84.87228166356789, 10.280199693261238 ], [ -84.873728604391545, 10.282163398022362 ], [ -84.874891324375085, 10.284333808358554 ], [ -84.875433925835011, 10.28696930578883 ], [ -84.875433925835011, 10.289914863380204 ], [ -84.87481380910998, 10.292860419172996 ], [ -84.872979295558025, 10.296271063858512 ], [ -84.870240445340244, 10.300301825269003 ], [ -84.865822110302133, 10.304797675572274 ], [ -84.859879320074526, 10.308776760139381 ], [ -84.850810106001575, 10.313427639174222 ], [ -84.847089402953543, 10.316528225497223 ], [ -84.838433600929932, 10.325674953935959 ], [ -84.832516649124045, 10.329705715346449 ], [ -84.829183518804314, 10.330790920064885 ], [ -84.824920214296412, 10.33166942010763 ], [ -84.817401292935301, 10.331979478470146 ], [ -84.81238867869456, 10.33166942010763 ], [ -84.806678433363004, 10.329809068133954 ], [ -84.802260098324837, 10.32784536427215 ], [ -84.786627977299304, 10.315339667091962 ], [ -84.764252082167843, 10.280096340473733 ], [ -84.757844203946831, 10.272448227903396 ], [ -84.756035528816597, 10.270897935191556 ], [ -84.74955013712912, 10.266712144150119 ], [ -84.743917406163348, 10.26635040894422 ], [ -84.735726691233822, 10.266712144150119 ], [ -84.716683926422036, 10.270071112891515 ], [ -84.702989671735963, 10.273998521514557 ], [ -84.696452603205046, 10.277874254193478 ], [ -84.694153001659686, 10.278907782068472 ], [ -84.69154334175181, 10.279837958055282 ], [ -84.683921067603194, 10.278752753336903 ], [ -84.666066861196668, 10.267280584931029 ], [ -84.660511643697362, 10.251777655114665 ], [ -84.656480882286871, 10.246144924148894 ], [ -84.65046057769348, 10.241494045114052 ], [ -84.648884446559919, 10.239788722771323 ], [ -84.648496873831618, 10.236068019723291 ], [ -84.649633755393495, 10.231003730437806 ], [ -84.660201586234223, 10.211883450360915 ], [ -84.663198818870399, 10.20449372020903 ], [ -84.668960741045339, 10.182066148234128 ], [ -84.668960741045339, 10.178397122029537 ], [ -84.668159756267698, 10.174314682876286 ], [ -84.662604539667768, 10.164289456193444 ], [ -84.661519334949332, 10.158708401171737 ], [ -84.661131761321712, 10.154936021280321 ], [ -84.664929978735529, 10.129769599087695 ], [ -84.660434130230897, 10.113801581277926 ], [ -84.649375372975044, 10.091218980571455 ], [ -84.643458422068534, 10.082278957707729 ], [ -84.627102830631088, 10.062228502543348 ], [ -84.619041306910788, 10.049206041425634 ], [ -84.602685716372719, 10.029775702086965 ], [ -84.596432867782596, 10.020163886554087 ], [ -84.595812751057622, 10.017786769743623 ], [ -84.594443326398391, 10.014686184319942 ], [ -84.593513150411525, 10.013239244395606 ], [ -84.591394416019455, 10.012619126771256 ], [ -84.58806128569978, 10.01251577398375 ], [ -84.580335659662921, 10.014634508375821 ], [ -84.572455003995231, 10.020680650491613 ], [ -84.569974535296524, 10.021714179265928 ], [ -84.562791510719649, 10.018303534580468 ], [ -84.55010494728549, 9.997736314579242 ], [ -84.550880092742091, 9.990294908483236 ], [ -84.551758591885516, 9.988124498147045 ], [ -84.55506588378347, 9.985127265510869 ], [ -84.560000982759107, 9.982543443125394 ], [ -84.575710619049801, 9.976342271378712 ], [ -84.624906581873233, 9.944612942233505 ], [ -84.635991176651487, 9.941253974391373 ], [ -84.643690965165888, 9.933864244239487 ], [ -84.662191127618428, 9.905080470887015 ], [ -84.669244960986134, 9.901979885463334 ], [ -84.670846931440735, 9.900481268695557 ], [ -84.672552252884145, 9.898259182415302 ], [ -84.67304317929927, 9.895520331298258 ], [ -84.672965664034166, 9.889629217914035 ], [ -84.674412603958501, 9.884358222154219 ], [ -84.671079475437409, 9.880637519106187 ], [ -84.664206509222993, 9.875883287283841 ], [ -84.643303392437588, 9.86761505798853 ], [ -84.626766933846909, 9.863170885428019 ], [ -84.613744472729195, 9.862447415016163 ], [ -84.601781378807573, 9.860070299105018 ], [ -84.592789679999726, 9.853145656946481 ], [ -84.57105974001496, 9.824516913224954 ], [ -84.579973923557702, 9.817333889547342 ], [ -84.570439623289985, 9.813044744819081 ], [ -84.563256598713053, 9.809117336196095 ], [ -84.559277513246627, 9.80612010355992 ], [ -84.555530971776932, 9.802709458874403 ], [ -84.553825650333465, 9.800745754113223 ], [ -84.548063728158525, 9.792787584079747 ], [ -84.543180305126953, 9.78358917879757 ], [ -84.542353481927648, 9.779713446118649 ], [ -84.541810878669082, 9.774184067940382 ], [ -84.543283657914458, 9.765915839544334 ], [ -84.544911464992083, 9.761936754077908 ], [ -84.546901008174984, 9.759404609435137 ], [ -84.548864712036789, 9.758061021398987 ], [ -84.551293504791374, 9.757027493523992 ], [ -84.554032355009156, 9.756355699056257 ], [ -84.557107102910436, 9.755993963850358 ], [ -84.576304898252431, 9.757027493523992 ], [ -84.582247687580718, 9.756304023112136 ], [ -84.585038214641884, 9.755477199912832 ], [ -84.587441168974749, 9.754185288720066 ], [ -84.589379035314209, 9.752634996008226 ], [ -84.59072262155172, 9.75061961530298 ], [ -84.59149776880696, 9.748242499391836 ], [ -84.591626960016185, 9.745503648274735 ], [ -84.59131690075435, 9.742868149945139 ], [ -84.583642950661613, 9.717650050909128 ], [ -84.581214158806347, 9.705609443520984 ], [ -84.581937629218203, 9.68628245696982 ], [ -84.581627569956368, 9.68318187154614 ], [ -84.579250454045223, 9.677290758161973 ], [ -84.557055426966372, 9.638688462802293 ], [ -84.556306118132852, 9.636414700577973 ], [ -84.54971737275855, 9.603186753765669 ], [ -84.547004360962489, 9.595693670826222 ], [ -84.542586025924322, 9.58639191275654 ], [ -84.536384854177641, 9.578072008416427 ], [ -84.529253506444149, 9.571457423721142 ], [ -84.526101244177084, 9.569287014284271 ], [ -84.515817634176472, 9.568046779934946 ], [ -84.484940964853649, 9.573059394175687 ], [ -84.477835456441142, 9.57021719027108 ], [ -84.475354986843172, 9.569855455065181 ], [ -84.471324226331944, 9.569907131009302 ], [ -84.455743781250476, 9.573937893319112 ], [ -84.452694871770916, 9.573989570162496 ], [ -84.449645962291299, 9.573679510900718 ], [ -84.447268846380155, 9.572645982126346 ], [ -84.445072597622243, 9.571199042202011 ], [ -84.440344204221617, 9.565876370498074 ], [ -84.438432176303877, 9.564171047256025 ], [ -84.436210090023621, 9.5629308129067 ], [ -84.433781298168356, 9.562103989707339 ], [ -84.430861578998645, 9.561845608188264 ], [ -84.428148566303264, 9.562207343394164 ], [ -84.425047979980263, 9.563550930530994 ], [ -84.422334968184202, 9.566031399229701 ], [ -84.416262986747427, 9.578123684360548 ], [ -84.414841885244812, 9.580190741009858 ], [ -84.412128871650111, 9.58277456339539 ], [ -84.400837572196167, 9.591766262203237 ], [ -84.397297736301482, 9.595176906888753 ], [ -84.395101488442947, 9.598225816368313 ], [ -84.394171311556761, 9.600757961011084 ], [ -84.393628710096891, 9.606700751238691 ], [ -84.397116869148192, 9.62649282488394 ], [ -84.396961840416566, 9.62902497042603 ], [ -84.394481370818596, 9.630678615925376 ], [ -84.38877112458772, 9.631815497487196 ], [ -84.377092250606836, 9.631608791912186 ], [ -84.350840623695831, 9.636569729309542 ], [ -84.308130051660555, 9.638791816489118 ], [ -84.293298916311926, 9.637448228452968 ], [ -84.288053758074454, 9.632693997529941 ], [ -84.284178026294853, 9.62995514641284 ], [ -84.277434252188982, 9.621583564330024 ], [ -84.275858120156101, 9.620084947562248 ], [ -84.265212774949589, 9.618224596487948 ], [ -84.22960771402478, 9.619103094731997 ], [ -84.216585252907066, 9.613522039710347 ], [ -84.201650763871612, 9.612281806260341 ], [ -84.156898972709428, 9.616260890827448 ], [ -84.147907273901581, 9.615227362952453 ], [ -84.145504319568659, 9.614400539753092 ], [ -84.142119514204182, 9.61166168953531 ], [ -84.139406500609482, 9.607269192019601 ], [ -84.137287767116732, 9.599414373874254 ], [ -84.136977708754216, 9.594763494839412 ], [ -84.137313604639132, 9.59083608621637 ], [ -84.139225632556872, 9.582464504133554 ], [ -84.139768235815438, 9.576056626811862 ], [ -84.139535691818708, 9.573007717332302 ], [ -84.137830370375298, 9.569338691127655 ], [ -84.134316372002957, 9.565204576030339 ], [ -84.126719937175324, 9.558383287558684 ], [ -84.119071824604987, 9.555644436441582 ], [ -84.114420945570146, 9.554714260454716 ], [ -84.105351732396514, 9.556264553166557 ], [ -84.092303432857136, 9.556522934685688 ], [ -84.083234218784128, 9.555179348448178 ], [ -84.078092414233538, 9.553318997373822 ], [ -84.075663622378272, 9.551872057449486 ], [ -84.073441535198697, 9.548203030345576 ], [ -84.071400316071731, 9.542777004055495 ], [ -84.069359096944765, 9.530271307774626 ], [ -84.069384935366486, 9.524276842502275 ], [ -84.070134243300686, 9.520039373718134 ], [ -84.072795580051945, 9.515440172425997 ], [ -84.074836799178911, 9.510479234129321 ], [ -84.071090256809896, 9.504278062382639 ], [ -84.049360317724449, 9.494511217218871 ], [ -84.03300472718638, 9.463402003899375 ], [ -84.0102412584273, 9.441439520817198 ], [ -83.944715541688879, 9.398186347322053 ], [ -83.92934180398106, 9.393328761812882 ], [ -83.928024055265894, 9.395602524936578 ], [ -83.926318732023844, 9.397359524122749 ], [ -83.92451005689361, 9.398909816834589 ], [ -83.922365484979139, 9.400253403971419 ], [ -83.920117561176482, 9.401286932745734 ], [ -83.917507901268607, 9.402113755945095 ], [ -83.914691534886401, 9.402527167095059 ], [ -83.911590948563401, 9.402527167095059 ], [ -83.908826259923956, 9.40201040315759 ], [ -83.905751512022618, 9.399736640033893 ], [ -83.902418381702944, 9.396222642560872 ], [ -83.895261197346372, 9.38351023980573 ], [ -83.893736742156932, 9.379582831182688 ], [ -83.889550951115496, 9.360255846430164 ], [ -83.88849158391946, 9.357775376832137 ], [ -83.856142137149902, 9.325322577275131 ], [ -83.8495275542532, 9.316589259986358 ], [ -83.845936042414394, 9.31023305950805 ], [ -83.84722795270784, 9.300414537500899 ], [ -83.847098762397934, 9.294316718541722 ], [ -83.845470954420989, 9.28330963812931 ], [ -83.839088914621698, 9.263207506121489 ], [ -83.834231330011846, 9.253492336002466 ], [ -83.831518317316466, 9.249461575491296 ], [ -83.827823451790834, 9.245224106707155 ], [ -83.820950487375057, 9.239074611803858 ], [ -83.771237758815516, 9.216905422247407 ], [ -83.763770515197109, 9.214941718385603 ], [ -83.760979987236624, 9.215355129535567 ], [ -83.758499519437237, 9.216130275891487 ], [ -83.756639166564241, 9.217628891759944 ], [ -83.754933845120831, 9.219489243733619 ], [ -83.746174689410395, 9.231478176076962 ], [ -83.74434017585844, 9.232925116001297 ], [ -83.742040575212343, 9.234165351249942 ], [ -83.739379239360403, 9.235198879124937 ], [ -83.736459520190692, 9.235974026380177 ], [ -83.733203905136122, 9.236439114373638 ], [ -83.730568406806526, 9.236439114373638 ], [ -83.72772620290192, 9.235974026380177 ], [ -83.72503902862826, 9.235198879124937 ], [ -83.715272182565172, 9.230548000989415 ], [ -83.701397060725753, 9.217370510240869 ], [ -83.678633591966673, 9.189620266562031 ], [ -83.675093756971307, 9.183625800390359 ], [ -83.674835374552856, 9.180938626116699 ], [ -83.674292772193667, 9.178354803731168 ], [ -83.666748013310155, 9.152619940757631 ], [ -83.665636970169999, 9.150449530421497 ], [ -83.66300147184046, 9.14662547368664 ], [ -83.656154344047707, 9.138615626809724 ], [ -83.565358853228474, 9.080376288335003 ], [ -83.563059251683114, 9.079342760460008 ], [ -83.552155524058151, 9.080066229972545 ], [ -83.54370642760955, 9.081306464321869 ], [ -83.541122606123338, 9.081358140265934 ], [ -83.537608608650373, 9.081048081903418 ], [ -83.535128139951667, 9.080066229972545 ], [ -83.530890672966166, 9.076965644548864 ], [ -83.526394822662894, 9.071642971046288 ], [ -83.524741177163605, 9.070041002390326 ], [ -83.520348679647839, 9.067457180004851 ], [ -83.517506476642552, 9.06663035680549 ], [ -83.514845139891293, 9.0660619169239 ], [ -83.512235479983417, 9.066320299342351 ], [ -83.509884203393256, 9.066992092011446 ], [ -83.507817145844569, 9.068284003204155 ], [ -83.506008469815015, 9.070092678334447 ], [ -83.495208095876933, 9.085078844213285 ], [ -83.491616584038127, 9.088437812055361 ], [ -83.488464321771005, 9.090504868704727 ], [ -83.486293911434871, 9.091538398378361 ], [ -83.484201016363784, 9.092881985515191 ], [ -83.482288988446044, 9.094638983802042 ], [ -83.480971238831614, 9.098256334062569 ], [ -83.480273606841479, 9.10347565387832 ], [ -83.483141649167749, 9.126419988891371 ], [ -83.482521532442775, 9.130709132720312 ], [ -83.480893723566453, 9.135773423804437 ], [ -83.473219774373092, 9.149726060009641 ], [ -83.471307745555976, 9.155927231756323 ], [ -83.471902024758606, 9.16781281221148 ], [ -83.473116420686267, 9.173393866333868 ], [ -83.474615038353306, 9.177424627744358 ], [ -83.476010301434258, 9.179491685293044 ], [ -83.476733770946737, 9.182127182723264 ], [ -83.477844814986213, 9.184297593958775 ], [ -83.479575974851343, 9.185589504252221 ], [ -83.482133958815155, 9.185641181095605 ], [ -83.48474361782371, 9.1851760931022 ], [ -83.48743079299669, 9.1851760931022 ], [ -83.48970455612033, 9.186002916301561 ], [ -83.491616584038127, 9.187449856225896 ], [ -83.493166876749967, 9.18920685541201 ], [ -83.495027228723586, 9.190860500911356 ], [ -83.497300991847283, 9.191997382473232 ], [ -83.506034309136055, 9.193754380760026 ], [ -83.508178881050526, 9.194994615109408 ], [ -83.509444952922252, 9.196958319870532 ], [ -83.509651659396525, 9.199645494144249 ], [ -83.499833137389373, 9.250081692216327 ], [ -83.498980475768349, 9.252665513702482 ], [ -83.495724859814402, 9.257523098312333 ], [ -83.468362188863921, 9.287960517164095 ], [ -83.466088425740224, 9.291939601731201 ], [ -83.463556281097453, 9.297675686383798 ], [ -83.456838345413303, 9.322015286276439 ], [ -83.453944464665312, 9.32718292924875 ], [ -83.451257290391595, 9.330955308240846 ], [ -83.42939816009698, 9.353692939477583 ], [ -83.403275722596504, 9.34609650285131 ], [ -83.400045945963598, 9.344132798989449 ], [ -83.396402757281408, 9.341032213565768 ], [ -83.395627610925487, 9.338396715236229 ], [ -83.395007494200456, 9.335141099282282 ], [ -83.392371995870917, 9.32738963482376 ], [ -83.390124071168941, 9.32645945883695 ], [ -83.38795366083275, 9.326666165311281 ], [ -83.385705736130774, 9.328009752448111 ], [ -83.383845384157155, 9.329456692372446 ], [ -83.380305549161733, 9.333074041733653 ], [ -83.376584846113758, 9.334831040919767 ], [ -83.371003791092051, 9.336174628056654 ], [ -83.352296923064557, 9.337931627242767 ], [ -83.34805945517968, 9.339326890323719 ], [ -83.346405808781014, 9.341032213565768 ], [ -83.334726935699507, 9.357258612894668 ], [ -83.332143114213352, 9.359739080693998 ], [ -83.328448248687721, 9.36211619750452 ], [ -83.321136033800883, 9.36594025334 ], [ -83.316795214027877, 9.36671539969592 ], [ -83.313462083708202, 9.366560370065031 ], [ -83.30873369030752, 9.364183254153829 ], [ -83.30434119279181, 9.361289374305159 ], [ -83.28584103123859, 9.345373033338831 ], [ -83.283567268114894, 9.344287827721075 ], [ -83.281267665670214, 9.342892563740804 ], [ -83.276151700440607, 9.340618801516484 ], [ -83.257677374611148, 9.334520982557308 ], [ -83.252871466844681, 9.332040513858601 ], [ -83.243337164778325, 9.32568431248103 ], [ -83.227705043752735, 9.317777818391619 ], [ -83.220625372862628, 9.315659084898812 ], [ -83.215328538681092, 9.314728908912002 ], [ -83.211917893995576, 9.314728908912002 ], [ -83.198068609678558, 9.317261054454093 ], [ -83.176571214589842, 9.318811347165934 ], [ -83.170008307637261, 9.318087876754078 ], [ -83.165667486964935, 9.316847642404753 ], [ -83.12660010361185, 9.266773180437895 ], [ -83.119391242411893, 9.259951890167599 ], [ -83.115437995367188, 9.257109687162313 ], [ -83.079626227968049, 9.236955878311107 ], [ -83.077559170419363, 9.235405584699947 ], [ -83.075750495289128, 9.233751939200602 ], [ -83.074277716943072, 9.231788235338797 ], [ -83.071952276975992, 9.227447415565734 ], [ -83.068386603558906, 9.217628891759944 ], [ -83.057482875933943, 9.163885402689175 ], [ -83.056113451274769, 9.160164700540463 ], [ -83.053090380216872, 9.154997057568153 ], [ -83.050299852256387, 9.152516587970126 ], [ -83.047302618720835, 9.150759588783956 ], [ -83.012860276880247, 9.14125112603864 ], [ -83.006607429189501, 9.138357245290649 ], [ -83.002473314092128, 9.135825099748558 ], [ -82.997150642388192, 9.127505195408446 ], [ -82.990897792898807, 9.110245266405911 ], [ -82.985807665191601, 9.102855536253969 ], [ -82.968831957029181, 9.086060696144216 ], [ -82.952657232745082, 9.080996405060034 ], [ -82.949504971377337, 9.078929348410668 ], [ -82.940229050829998, 9.071229559896267 ], [ -82.93952108499991, 9.070641889000072 ] ] ], [ [ [ -85.167397671565254, 10.019403308315987 ], [ -85.144520636999914, 9.999335028000075 ], [ -85.083851691999939, 9.97492096600007 ], [ -85.076201951999906, 9.970648505000042 ], [ -85.069081183999913, 9.973415432000081 ], [ -85.053130662999934, 9.966945705000057 ], [ -85.014515753999945, 9.944973049000055 ], [ -84.996693488999938, 9.939276434000078 ], [ -84.9775691399999, 9.938788153000075 ], [ -84.959584113999938, 9.946478583000044 ], [ -84.947783982999908, 9.937160549000055 ], [ -84.922596808999913, 9.921454169000071 ], [ -84.911122199999909, 9.911688544000071 ], [ -84.911122199999909, 9.905462958000044 ], [ -84.931060350999928, 9.90070221600007 ], [ -84.930165167999917, 9.886297919000071 ], [ -84.918080206999946, 9.869533596000053 ], [ -84.90493730399993, 9.857082424000055 ], [ -84.913075324999909, 9.854315497000073 ], [ -84.920765753999945, 9.848944403000075 ], [ -84.932850714999915, 9.836615302000041 ], [ -84.918080206999946, 9.830023505000042 ], [ -84.90062415299991, 9.828070380000042 ], [ -84.864613410999937, 9.829169012000079 ], [ -84.864613410999937, 9.822943427000041 ], [ -84.878692186999899, 9.813544012000079 ], [ -84.896595831999946, 9.80609772300005 ], [ -84.912017381999931, 9.795843817000048 ], [ -84.91860917899993, 9.778265692000048 ], [ -84.922352667999917, 9.774196682000081 ], [ -84.945912238999938, 9.760891018000052 ], [ -84.950347459999932, 9.753566799000055 ], [ -84.955474412999934, 9.735134182000081 ], [ -84.959584113999938, 9.727362372000073 ], [ -84.990956183999913, 9.742743231000077 ], [ -85.007598436999899, 9.744086005000042 ], [ -85.014800584999932, 9.73078034100007 ], [ -85.010365363999938, 9.722601630000042 ], [ -84.994984503999945, 9.703273830000057 ], [ -84.997425910999937, 9.699408270000049 ], [ -85.029815232999908, 9.683742580000057 ], [ -85.035267706999946, 9.682399807000081 ], [ -85.038929816999939, 9.67727285400008 ], [ -85.062611456999946, 9.665309963000084 ], [ -85.067494269999941, 9.657375393000052 ], [ -85.089344855999911, 9.588568427000041 ], [ -85.098500128999945, 9.571071682000081 ], [ -85.110463019999941, 9.555446682000081 ], [ -85.11782792899993, 9.555446682000081 ], [ -85.145782029999907, 9.612616278000075 ], [ -85.229115363999938, 9.724391994000086 ], [ -85.229295448878645, 9.724822572867236 ], [ -85.229184943430369, 9.724936428273509 ], [ -85.226626960365934, 9.727571925703785 ], [ -85.220735846981711, 9.730259100876765 ], [ -85.218642951011361, 9.730672512026786 ], [ -85.216188320734375, 9.732222804738626 ], [ -85.209754604991019, 9.745400295487229 ], [ -85.206834885821308, 9.747829088241815 ], [ -85.204251065234473, 9.749534410584545 ], [ -85.201848110901608, 9.752169908014821 ], [ -85.199677700565417, 9.756355699056257 ], [ -85.19683549666081, 9.765037340400909 ], [ -85.194665087223996, 9.769378160173915 ], [ -85.192649705619431, 9.772427070552851 ], [ -85.186939460287874, 9.776974595900867 ], [ -85.186009284301008, 9.778834946975223 ], [ -85.186448533872749, 9.781108710098863 ], [ -85.189264899355578, 9.784312649209369 ], [ -85.190660163335849, 9.788446764306741 ], [ -85.190401780917455, 9.794596259209982 ], [ -85.180144009338562, 9.832940172151211 ], [ -85.176345791025426, 9.843223782151824 ], [ -85.173400235232634, 9.849373277055065 ], [ -85.173839483905056, 9.851802069809651 ], [ -85.175725674300395, 9.853714097727391 ], [ -85.190350104074014, 9.857124742412907 ], [ -85.192908088037825, 9.858003241556332 ], [ -85.195000983108855, 9.859450182379987 ], [ -85.196318731824022, 9.861517239029354 ], [ -85.197765672647677, 9.867098293151685 ], [ -85.198644171791102, 9.873041083379292 ], [ -85.200659553395667, 9.877743639257517 ], [ -85.202003139633177, 9.879914048694388 ], [ -85.203088345250933, 9.882291165504853 ], [ -85.205801357946314, 9.886476956546289 ], [ -85.21130489770286, 9.891437893044326 ], [ -85.215568203110081, 9.897329006428492 ], [ -85.217480231027821, 9.898930975983717 ], [ -85.219831509416622, 9.900119534388978 ], [ -85.227531297931023, 9.902755031819254 ], [ -85.23419755677179, 9.906475734867229 ], [ -85.239933641424386, 9.907715969216611 ], [ -85.249390428225638, 9.907612616429105 ], [ -85.25218095618618, 9.908232734053399 ], [ -85.25466142398551, 9.909266261928451 ], [ -85.258976407135492, 9.911746731526421 ], [ -85.261431037412422, 9.912831936244856 ], [ -85.270319383432764, 9.914433904900761 ], [ -85.27336829291238, 9.914537257688266 ], [ -85.276598070444606, 9.914485581744202 ], [ -85.285925666036633, 9.913245348294197 ], [ -85.290163133022133, 9.913917140963292 ], [ -85.294400600907011, 9.916035875355362 ], [ -85.298224656742491, 9.919394843197438 ], [ -85.301583624584566, 9.923942369444774 ], [ -85.303288946927353, 9.929678453198051 ], [ -85.299103155885916, 9.937378240813132 ], [ -85.289930589924779, 9.945749822896005 ], [ -85.265306770091343, 9.957532050563657 ], [ -85.254868129560521, 9.960787664718964 ], [ -85.248072678611209, 9.961459459186699 ], [ -85.246264004380293, 9.959857488732098 ], [ -85.244713710769133, 9.958152167288688 ], [ -85.242827521273057, 9.956498520890023 ], [ -85.240786302146091, 9.955464993015028 ], [ -85.23613542401057, 9.956756904207737 ], [ -85.210323045771929, 9.971484686768861 ], [ -85.205336269952852, 9.973603420261611 ], [ -85.183373785971412, 9.978822740077362 ], [ -85.177508511008966, 9.986987615685905 ], [ -85.167397671565254, 10.019403308315987 ] ] ], [ [ [ -85.131337042999917, 10.098700262000079 ], [ -85.121571417999917, 10.096380927000041 ], [ -85.116037563999896, 10.091701565000051 ], [ -85.107899542999917, 10.089544989000046 ], [ -85.097320115999935, 10.089829820000091 ], [ -85.097320115999935, 10.083644924000055 ], [ -85.109486456999946, 10.079291083000044 ], [ -85.124826626999948, 10.07562897300005 ], [ -85.141835089999915, 10.074164130000042 ], [ -85.158802863999938, 10.076157945000091 ], [ -85.176136847999942, 10.083238023000092 ], [ -85.185292120999918, 10.09243398600006 ], [ -85.199126756999931, 10.117743231000077 ], [ -85.180287238999938, 10.124009507000039 ], [ -85.171864386999914, 10.124579169000071 ], [ -85.139963344999899, 10.119208075000074 ], [ -85.110463019999941, 10.110296942000048 ], [ -85.110463019999941, 10.103461005000042 ], [ -85.145130988999938, 10.103461005000042 ], [ -85.135650193999936, 10.098456122000073 ], [ -85.131337042999917, 10.098700262000079 ] ] ], [ [ [ -87.099029100999928, 5.516017971000053 ], [ -87.117665167999917, 5.51508209800005 ], [ -87.104603644999941, 5.53742096600007 ], [ -87.092518683999913, 5.546698309000078 ], [ -87.078521287999934, 5.555080471000053 ], [ -87.064605272999927, 5.557847398000092 ], [ -87.064605272999927, 5.54759349200009 ], [ -87.065541144999941, 5.53461334800005 ], [ -87.078521287999934, 5.520656643000052 ], [ -87.099029100999928, 5.516017971000053 ] ] ], [ [ [ -83.896617592999917, 8.706491863000053 ], [ -83.883463738999922, 8.712992682000049 ], [ -83.869114045999936, 8.713587405000055 ], [ -83.870305238999947, 8.701776235000068 ], [ -83.878076405999934, 8.698821179000049 ], [ -83.890634796999905, 8.701178567000056 ], [ -83.896617592999917, 8.706491863000053 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CR-H", "NAME_1": "Heredia" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -83.859527750999916, 10.721775615000055 ], [ -83.855807047999917, 10.723997701000059 ], [ -83.835343180999956, 10.747613831000081 ], [ -83.768964802999932, 10.772470195000039 ], [ -83.763818115413699, 10.773683167843899 ], [ -83.760799120083334, 10.771487535121651 ], [ -83.749352790099181, 10.768335272854529 ], [ -83.74625220377618, 10.767146715348645 ], [ -83.743849250342635, 10.765648098580868 ], [ -83.741549648797218, 10.763994452182203 ], [ -83.736511197034076, 10.759136868471671 ], [ -83.732738817142661, 10.754641018168456 ], [ -83.729999966025616, 10.749835110401989 ], [ -83.729431525244706, 10.746527818504035 ], [ -83.72927649561376, 10.743013821031013 ], [ -83.732273729149256, 10.722963364967313 ], [ -83.731886156420956, 10.718105780357462 ], [ -83.73100765727753, 10.71459178288444 ], [ -83.72793290937625, 10.71076772704896 ], [ -83.724573940634855, 10.707357083262764 ], [ -83.720646532011813, 10.704153144152258 ], [ -83.711990729088882, 10.698933824336507 ], [ -83.70827002604085, 10.695833238013506 ], [ -83.70578955824152, 10.6929910341089 ], [ -83.703696662271113, 10.689787095897771 ], [ -83.703567471061945, 10.688081773554984 ], [ -83.704575161414539, 10.687151598467494 ], [ -83.709174363605996, 10.688650214335894 ], [ -83.712765876344122, 10.688960272698409 ], [ -83.716615769702003, 10.688856919910904 ], [ -83.72715776212101, 10.686221422480628 ], [ -83.756329108201783, 10.683740952882658 ], [ -83.762142707220164, 10.682552395376717 ], [ -83.772581345952347, 10.679090073847817 ], [ -83.789531215693046, 10.668289699909735 ], [ -83.799556444174527, 10.657644354703166 ], [ -83.803509691219233, 10.65464712206699 ], [ -83.813121506752111, 10.64968618377037 ], [ -83.821570604100089, 10.644260159278929 ], [ -83.825394659935569, 10.641056220168423 ], [ -83.82699663039017, 10.639247545038131 ], [ -83.828650274990196, 10.633356432553285 ], [ -83.829968023705305, 10.624261379159293 ], [ -83.831363287685576, 10.593772284363411 ], [ -83.830691494117161, 10.584367174405543 ], [ -83.836350064403916, 10.541475735216977 ], [ -83.836195034773027, 10.535584621832811 ], [ -83.835239021263817, 10.533207505921666 ], [ -83.833766242018442, 10.53114044837298 ], [ -83.830588142228976, 10.527419745324949 ], [ -83.829192878248705, 10.525301011832198 ], [ -83.828030158265165, 10.522975571865118 ], [ -83.827616747115144, 10.520081692016447 ], [ -83.827720099902649, 10.516774400118436 ], [ -83.828650274990196, 10.50860952450995 ], [ -83.828495246258569, 10.505198878925114 ], [ -83.827875128634275, 10.502201646288938 ], [ -83.823870204746129, 10.492331448337666 ], [ -83.823405117652044, 10.489592597220565 ], [ -83.823430956073764, 10.484631658923888 ], [ -83.829037848617816, 10.463651027772698 ], [ -83.838029548324982, 10.450111802717515 ], [ -83.842060309735473, 10.446029364463584 ], [ -83.843998176074933, 10.444479070852424 ], [ -83.846246100776909, 10.443290514245803 ], [ -83.849010790315731, 10.442567042934684 ], [ -83.85164628774595, 10.442256985471488 ], [ -83.853920050869647, 10.441223455797854 ], [ -83.855935431574892, 10.438846339886652 ], [ -83.863945279351128, 10.423601793388059 ], [ -83.866787482356415, 10.419519355134128 ], [ -83.870275642307035, 10.412336331456515 ], [ -83.871076626185356, 10.408047186728254 ], [ -83.87167090538793, 10.402104397400024 ], [ -83.869422979786691, 10.387531643570469 ], [ -83.868131070392565, 10.383759264578373 ], [ -83.854798550013072, 10.359264635054842 ], [ -83.851749641432775, 10.348412584273319 ], [ -83.849863451037436, 10.343348293189138 ], [ -83.84722795270784, 10.339317531778647 ], [ -83.844127367284159, 10.335493475943167 ], [ -83.842912971356554, 10.333219712819471 ], [ -83.842732103303888, 10.328310452265555 ], [ -83.843610603346633, 10.321230780476128 ], [ -83.84686621840126, 10.306916409065025 ], [ -83.847718879122965, 10.294772447090736 ], [ -83.84722795270784, 10.291981920029571 ], [ -83.848416511113101, 10.286504217795425 ], [ -83.85107784696504, 10.279269517274372 ], [ -83.863402676092619, 10.253534654300836 ], [ -83.866477423993899, 10.248728746534425 ], [ -83.913554654223901, 10.198964342030763 ], [ -83.95052914070726, 10.195140286195226 ], [ -83.969933640724946, 10.170438951096685 ], [ -83.975979783740001, 10.164237779350003 ], [ -83.980785692405789, 10.162584132951338 ], [ -84.002929042641199, 10.160930488351369 ], [ -84.022281866714764, 10.156796373253997 ], [ -84.066413540252654, 10.15338572856848 ], [ -84.071400316071731, 10.151525377494181 ], [ -84.070625169715811, 10.146564439197505 ], [ -84.067059496298725, 10.138554592320588 ], [ -84.044089321964634, 10.104913235257584 ], [ -84.030911831216031, 10.090857245365555 ], [ -84.028302172207475, 10.082847398488639 ], [ -84.02664852580881, 10.058869533801953 ], [ -84.018509487722667, 10.050032863725676 ], [ -84.013677740635217, 10.045795395840855 ], [ -84.01042212558059, 10.042281399267154 ], [ -84.009414436127315, 10.034943345958652 ], [ -84.015512255086492, 10.015099596369282 ], [ -84.02799211294564, 9.982026679187868 ], [ -84.04747412822843, 9.97050283483793 ], [ -84.073906623192102, 9.962182928699178 ], [ -84.084216070715058, 9.960219223937997 ], [ -84.109925096166251, 9.962337958330124 ], [ -84.114550136779371, 9.962027899967609 ], [ -84.15131791858704, 9.945646471007819 ], [ -84.162738410149473, 9.950400701930846 ], [ -84.182401292585553, 9.960219223937997 ], [ -84.199971279950603, 9.957221991301822 ], [ -84.201754116659117, 9.966006985434035 ], [ -84.201857469446622, 9.971381333981356 ], [ -84.201599087028228, 9.974171861042521 ], [ -84.200978970303197, 9.977169094578016 ], [ -84.196018032905897, 9.985075587768165 ], [ -84.177621223240862, 10.004350898375264 ], [ -84.177362839923092, 10.006831366174595 ], [ -84.165787319629089, 10.158398341909958 ], [ -84.164185350073808, 10.295702623077602 ], [ -84.162686734205408, 10.41011424427694 ], [ -84.160516323869217, 10.571138006813555 ], [ -84.157984178327126, 10.784251613820913 ], [ -84.15772972504675, 10.788424645281168 ], [ -84.149019124999882, 10.787172140000038 ], [ -84.137004354999931, 10.789161682000071 ], [ -84.118426676999974, 10.771229960000099 ], [ -84.106928670999935, 10.766914978000031 ], [ -84.095430663999934, 10.775519104000068 ], [ -84.088557698999864, 10.775519104000068 ], [ -84.076439574999966, 10.763814393000075 ], [ -84.051634887999938, 10.779549866000053 ], [ -84.034555826999878, 10.775519104000068 ], [ -84.022696085999968, 10.78722381700004 ], [ -84.00923437599991, 10.789445903000043 ], [ -83.998201456999908, 10.782056173000043 ], [ -83.99362809299987, 10.765002950000095 ], [ -83.933321695999979, 10.718054911000053 ], [ -83.92657792199995, 10.714902649000095 ], [ -83.917276163999929, 10.7134815470001 ], [ -83.907483479999968, 10.715367737000108 ], [ -83.893556681999968, 10.724927877000113 ], [ -83.886864583999852, 10.72714996400012 ], [ -83.859527750999916, 10.721775615000055 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CR-SJ", "NAME_1": "San José" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -84.084216070715058, 9.960219223937997 ], [ -84.073906623192102, 9.962182928699178 ], [ -84.04747412822843, 9.97050283483793 ], [ -84.02799211294564, 9.982026679187868 ], [ -84.015512255086492, 10.015099596369282 ], [ -84.009414436127315, 10.034943345958652 ], [ -84.01042212558059, 10.042281399267154 ], [ -84.013677740635217, 10.045795395840855 ], [ -84.018509487722667, 10.050032863725676 ], [ -84.02664852580881, 10.058869533801953 ], [ -84.028302172207475, 10.082847398488639 ], [ -84.030911831216031, 10.090857245365555 ], [ -84.044089321964634, 10.104913235257584 ], [ -84.067059496298725, 10.138554592320588 ], [ -84.070625169715811, 10.146564439197505 ], [ -84.071400316071731, 10.151525377494181 ], [ -84.066413540252654, 10.15338572856848 ], [ -84.022281866714764, 10.156796373253997 ], [ -84.002929042641199, 10.160930488351369 ], [ -83.980785692405789, 10.162584132951338 ], [ -83.975979783740001, 10.164237779350003 ], [ -83.969933640724946, 10.170438951096685 ], [ -83.95052914070726, 10.195140286195226 ], [ -83.913554654223901, 10.198964342030763 ], [ -83.922546353031748, 10.190127671954485 ], [ -83.929083421562666, 10.181187649090703 ], [ -83.942726000304674, 10.136229153252827 ], [ -83.928644171990925, 10.088686835029421 ], [ -83.926370408867285, 10.084707750462314 ], [ -83.922598028975813, 10.080211900159043 ], [ -83.913864711687097, 10.072563788488026 ], [ -83.905389776816719, 10.06667267510386 ], [ -83.900868089890423, 10.064295559192715 ], [ -83.898826869864138, 10.062900295212444 ], [ -83.878828090643879, 10.040472724136919 ], [ -83.875081550073446, 10.034839993171147 ], [ -83.872394374900466, 10.026054999038934 ], [ -83.870430671038605, 10.000061754546323 ], [ -83.865960660056373, 9.977995916878058 ], [ -83.86820858385903, 9.969882717213636 ], [ -83.871231655816246, 9.96590363174721 ], [ -83.875004034808342, 9.962596339849199 ], [ -83.880585089829992, 9.960632635987338 ], [ -83.892677374960897, 9.959237372007124 ], [ -83.905234748085149, 9.945646471007819 ], [ -83.90849036313972, 9.944612942233505 ], [ -83.912236904609472, 9.943786119034144 ], [ -83.915156622879806, 9.944664618177569 ], [ -83.917507901268607, 9.94585317658283 ], [ -83.926680467229744, 9.947300116507165 ], [ -83.95300961030523, 9.94699005814465 ], [ -83.953965623814497, 9.946473293307804 ], [ -83.999957648426744, 9.930298569923025 ], [ -84.026338467446294, 9.887148749215385 ], [ -84.028069628210744, 9.878983872707522 ], [ -84.026415981812079, 9.877691962414133 ], [ -84.022591925976599, 9.875469876133877 ], [ -84.002618985178003, 9.86683991073329 ], [ -84.03145443357522, 9.820692857389417 ], [ -84.038895839671227, 9.812734687355942 ], [ -84.051272345642246, 9.804363105273069 ], [ -84.06884233300724, 9.788653468982375 ], [ -84.075508591848006, 9.777801418200852 ], [ -84.078609178171007, 9.771341864035776 ], [ -84.079280971739422, 9.766949368318706 ], [ -84.079177618951917, 9.763848781995705 ], [ -84.078712530958512, 9.761058254035163 ], [ -84.077627326240076, 9.758577786235833 ], [ -84.076128710371677, 9.756717434262157 ], [ -84.073932460714502, 9.755580552700337 ], [ -84.071090256809896, 9.755477199912832 ], [ -84.068222215382946, 9.755787258275348 ], [ -84.056052415886256, 9.760438137310189 ], [ -84.047965053744235, 9.762556870802939 ], [ -84.045019497052124, 9.762815253221333 ], [ -84.039050869302173, 9.761988430022029 ], [ -84.033288947127176, 9.760644842885199 ], [ -83.996391975009601, 9.768809719393005 ], [ -83.988149584136011, 9.767672837831185 ], [ -83.985979173799819, 9.758164374186492 ], [ -83.983860440307069, 9.75330679047596 ], [ -83.982129278643299, 9.748242499391836 ], [ -83.975514695746597, 9.736098538316867 ], [ -83.956187710094753, 9.729845688827481 ], [ -83.950761684703991, 9.725091457904455 ], [ -83.95014156797896, 9.722766017937374 ], [ -83.949831508717125, 9.720853990019634 ], [ -83.940917325174382, 9.70607452971575 ], [ -83.918748134718612, 9.677549140580368 ], [ -83.913451301436396, 9.672794907858702 ], [ -83.910557420688406, 9.672071438346165 ], [ -83.898387621191773, 9.66773061857316 ], [ -83.877846238712948, 9.657602037304173 ], [ -83.87283362537147, 9.656465154843033 ], [ -83.8703531557735, 9.657291978042338 ], [ -83.86820858385903, 9.658583889235103 ], [ -83.865263028066295, 9.659979153215318 ], [ -83.861154751390643, 9.660702622727854 ], [ -83.853144903614407, 9.659824124483748 ], [ -83.849062466259795, 9.658377182760773 ], [ -83.846142747989404, 9.656413478898912 ], [ -83.84454077843418, 9.654501450981172 ], [ -83.836970181128947, 9.642150784331193 ], [ -83.830200567702036, 9.627939764808275 ], [ -83.829451259767836, 9.625459296109625 ], [ -83.827513394327696, 9.620808417074784 ], [ -83.823275926442818, 9.612850247041251 ], [ -83.818289150623798, 9.604995428895904 ], [ -83.814956021203386, 9.601274725847929 ], [ -83.811881273302106, 9.598794257149223 ], [ -83.809168259707405, 9.597864081162413 ], [ -83.787205776625285, 9.593316554915077 ], [ -83.782451544802939, 9.593626614176912 ], [ -83.763279588781984, 9.595693670826222 ], [ -83.752014125951121, 9.580190741009858 ], [ -83.749378627621525, 9.578123684360548 ], [ -83.744391852701824, 9.575023098037548 ], [ -83.72925065809136, 9.569958807852686 ], [ -83.724780646209865, 9.567374986366531 ], [ -83.722041795992084, 9.564791164880319 ], [ -83.721034104740113, 9.562310696181669 ], [ -83.718011033682217, 9.551665350975156 ], [ -83.715866461767803, 9.538436184282489 ], [ -83.714161140324336, 9.536885891570648 ], [ -83.712016568409865, 9.536679185096318 ], [ -83.698167284092847, 9.543448798523229 ], [ -83.693180508273826, 9.545309150496905 ], [ -83.690260790003435, 9.545929267221879 ], [ -83.678633591966673, 9.544844062503444 ], [ -83.675248785702877, 9.544947415290949 ], [ -83.672277390589102, 9.545309150496905 ], [ -83.6695127019496, 9.545980943166001 ], [ -83.666954718885165, 9.546962795096931 ], [ -83.664784309448294, 9.54804800071463 ], [ -83.662923956575298, 9.549443263795581 ], [ -83.661011928657558, 9.551045234250125 ], [ -83.659513311889839, 9.553008938111986 ], [ -83.654552375391802, 9.561897284132328 ], [ -83.650573289925376, 9.566341458491479 ], [ -83.638739387212922, 9.569907131009302 ], [ -83.613211228915077, 9.543500474467294 ], [ -83.604529589369065, 9.536369126733803 ], [ -83.594685228040817, 9.531666570855521 ], [ -83.592153083398046, 9.530788071712152 ], [ -83.48686235221578, 9.467587794940755 ], [ -83.453634406302797, 9.377309068059049 ], [ -83.445159471432419, 9.36573354686567 ], [ -83.441645473959454, 9.362322903079473 ], [ -83.42939816009698, 9.353692939477583 ], [ -83.451257290391595, 9.330955308240846 ], [ -83.453944464665312, 9.32718292924875 ], [ -83.456838345413303, 9.322015286276439 ], [ -83.463556281097453, 9.297675686383798 ], [ -83.466088425740224, 9.291939601731201 ], [ -83.468362188863921, 9.287960517164095 ], [ -83.495724859814402, 9.257523098312333 ], [ -83.498980475768349, 9.252665513702482 ], [ -83.499833137389373, 9.250081692216327 ], [ -83.509651659396525, 9.199645494144249 ], [ -83.509444952922252, 9.196958319870532 ], [ -83.508178881050526, 9.194994615109408 ], [ -83.506034309136055, 9.193754380760026 ], [ -83.497300991847283, 9.191997382473232 ], [ -83.495027228723586, 9.190860500911356 ], [ -83.493166876749967, 9.18920685541201 ], [ -83.491616584038127, 9.187449856225896 ], [ -83.48970455612033, 9.186002916301561 ], [ -83.48743079299669, 9.1851760931022 ], [ -83.48474361782371, 9.1851760931022 ], [ -83.482133958815155, 9.185641181095605 ], [ -83.479575974851343, 9.185589504252221 ], [ -83.477844814986213, 9.184297593958775 ], [ -83.476733770946737, 9.182127182723264 ], [ -83.476010301434258, 9.179491685293044 ], [ -83.474615038353306, 9.177424627744358 ], [ -83.473116420686267, 9.173393866333868 ], [ -83.471902024758606, 9.16781281221148 ], [ -83.471307745555976, 9.155927231756323 ], [ -83.473219774373092, 9.149726060009641 ], [ -83.480893723566453, 9.135773423804437 ], [ -83.482521532442775, 9.130709132720312 ], [ -83.483141649167749, 9.126419988891371 ], [ -83.480273606841479, 9.10347565387832 ], [ -83.480971238831614, 9.098256334062569 ], [ -83.482288988446044, 9.094638983802042 ], [ -83.484201016363784, 9.092881985515191 ], [ -83.486293911434871, 9.091538398378361 ], [ -83.488464321771005, 9.090504868704727 ], [ -83.491616584038127, 9.088437812055361 ], [ -83.495208095876933, 9.085078844213285 ], [ -83.506008469815015, 9.070092678334447 ], [ -83.507817145844569, 9.068284003204155 ], [ -83.509884203393256, 9.066992092011446 ], [ -83.512235479983417, 9.066320299342351 ], [ -83.514845139891293, 9.0660619169239 ], [ -83.517506476642552, 9.06663035680549 ], [ -83.520348679647839, 9.067457180004851 ], [ -83.524741177163605, 9.070041002390326 ], [ -83.526394822662894, 9.071642971046288 ], [ -83.530890672966166, 9.076965644548864 ], [ -83.535128139951667, 9.080066229972545 ], [ -83.537608608650373, 9.081048081903418 ], [ -83.541122606123338, 9.081358140265934 ], [ -83.54370642760955, 9.081306464321869 ], [ -83.552155524058151, 9.080066229972545 ], [ -83.563059251683114, 9.079342760460008 ], [ -83.565358853228474, 9.080376288335003 ], [ -83.656154344047707, 9.138615626809724 ], [ -83.66300147184046, 9.14662547368664 ], [ -83.665636970169999, 9.150449530421497 ], [ -83.666748013310155, 9.152619940757631 ], [ -83.674292772193667, 9.178354803731168 ], [ -83.674835374552856, 9.180938626116699 ], [ -83.675093756971307, 9.183625800390359 ], [ -83.678633591966673, 9.189620266562031 ], [ -83.701397060725753, 9.217370510240869 ], [ -83.715272182565172, 9.230548000989415 ], [ -83.72503902862826, 9.235198879124937 ], [ -83.72772620290192, 9.235974026380177 ], [ -83.730568406806526, 9.236439114373638 ], [ -83.733203905136122, 9.236439114373638 ], [ -83.736459520190692, 9.235974026380177 ], [ -83.739379239360403, 9.235198879124937 ], [ -83.742040575212343, 9.234165351249942 ], [ -83.74434017585844, 9.232925116001297 ], [ -83.746174689410395, 9.231478176076962 ], [ -83.754933845120831, 9.219489243733619 ], [ -83.756639166564241, 9.217628891759944 ], [ -83.758499519437237, 9.216130275891487 ], [ -83.760979987236624, 9.215355129535567 ], [ -83.763770515197109, 9.214941718385603 ], [ -83.771237758815516, 9.216905422247407 ], [ -83.820950487375057, 9.239074611803858 ], [ -83.827823451790834, 9.245224106707155 ], [ -83.831518317316466, 9.249461575491296 ], [ -83.834231330011846, 9.253492336002466 ], [ -83.839088914621698, 9.263207506121489 ], [ -83.845470954420989, 9.28330963812931 ], [ -83.847098762397934, 9.294316718541722 ], [ -83.84722795270784, 9.300414537500899 ], [ -83.845936042414394, 9.31023305950805 ], [ -83.8495275542532, 9.316589259986358 ], [ -83.856142137149902, 9.325322577275131 ], [ -83.88849158391946, 9.357775376832137 ], [ -83.889550951115496, 9.360255846430164 ], [ -83.893736742156932, 9.379582831182688 ], [ -83.895261197346372, 9.38351023980573 ], [ -83.902418381702944, 9.396222642560872 ], [ -83.905751512022618, 9.399736640033893 ], [ -83.908826259923956, 9.40201040315759 ], [ -83.911590948563401, 9.402527167095059 ], [ -83.914691534886401, 9.402527167095059 ], [ -83.917507901268607, 9.402113755945095 ], [ -83.920117561176482, 9.401286932745734 ], [ -83.922365484979139, 9.400253403971419 ], [ -83.92451005689361, 9.398909816834589 ], [ -83.926318732023844, 9.397359524122749 ], [ -83.928024055265894, 9.395602524936578 ], [ -83.92934180398106, 9.393328761812882 ], [ -83.944715541688879, 9.398186347322053 ], [ -84.0102412584273, 9.441439520817198 ], [ -84.03300472718638, 9.463402003899375 ], [ -84.049360317724449, 9.494511217218871 ], [ -84.071090256809896, 9.504278062382639 ], [ -84.074836799178911, 9.510479234129321 ], [ -84.072795580051945, 9.515440172425997 ], [ -84.070134243300686, 9.520039373718134 ], [ -84.069384935366486, 9.524276842502275 ], [ -84.069359096944765, 9.530271307774626 ], [ -84.071400316071731, 9.542777004055495 ], [ -84.073441535198697, 9.548203030345576 ], [ -84.075663622378272, 9.551872057449486 ], [ -84.078092414233538, 9.553318997373822 ], [ -84.083234218784128, 9.555179348448178 ], [ -84.092303432857136, 9.556522934685688 ], [ -84.105351732396514, 9.556264553166557 ], [ -84.114420945570146, 9.554714260454716 ], [ -84.119071824604987, 9.555644436441582 ], [ -84.126719937175324, 9.558383287558684 ], [ -84.134316372002957, 9.565204576030339 ], [ -84.137830370375298, 9.569338691127655 ], [ -84.139535691818708, 9.573007717332302 ], [ -84.139768235815438, 9.576056626811862 ], [ -84.139225632556872, 9.582464504133554 ], [ -84.137313604639132, 9.59083608621637 ], [ -84.136977708754216, 9.594763494839412 ], [ -84.137287767116732, 9.599414373874254 ], [ -84.139406500609482, 9.607269192019601 ], [ -84.142119514204182, 9.61166168953531 ], [ -84.145504319568659, 9.614400539753092 ], [ -84.147907273901581, 9.615227362952453 ], [ -84.156898972709428, 9.616260890827448 ], [ -84.201650763871612, 9.612281806260341 ], [ -84.216585252907066, 9.613522039710347 ], [ -84.22960771402478, 9.619103094731997 ], [ -84.265212774949589, 9.618224596487948 ], [ -84.275858120156101, 9.620084947562248 ], [ -84.277434252188982, 9.621583564330024 ], [ -84.284178026294853, 9.62995514641284 ], [ -84.288053758074454, 9.632693997529941 ], [ -84.293298916311926, 9.637448228452968 ], [ -84.308130051660555, 9.638791816489118 ], [ -84.350840623695831, 9.636569729309542 ], [ -84.377092250606836, 9.631608791912186 ], [ -84.38877112458772, 9.631815497487196 ], [ -84.394481370818596, 9.630678615925376 ], [ -84.396961840416566, 9.62902497042603 ], [ -84.397116869148192, 9.62649282488394 ], [ -84.393628710096891, 9.606700751238691 ], [ -84.394171311556761, 9.600757961011084 ], [ -84.395101488442947, 9.598225816368313 ], [ -84.397297736301482, 9.595176906888753 ], [ -84.400837572196167, 9.591766262203237 ], [ -84.412128871650111, 9.58277456339539 ], [ -84.414841885244812, 9.580190741009858 ], [ -84.416262986747427, 9.578123684360548 ], [ -84.422334968184202, 9.566031399229701 ], [ -84.425047979980263, 9.563550930530994 ], [ -84.428148566303264, 9.562207343394164 ], [ -84.430861578998645, 9.561845608188264 ], [ -84.433781298168356, 9.562103989707339 ], [ -84.436210090023621, 9.5629308129067 ], [ -84.438432176303877, 9.564171047256025 ], [ -84.440344204221617, 9.565876370498074 ], [ -84.445072597622243, 9.571199042202011 ], [ -84.447268846380155, 9.572645982126346 ], [ -84.449645962291299, 9.573679510900718 ], [ -84.452694871770916, 9.573989570162496 ], [ -84.455743781250476, 9.573937893319112 ], [ -84.471324226331944, 9.569907131009302 ], [ -84.475354986843172, 9.569855455065181 ], [ -84.477835456441142, 9.57021719027108 ], [ -84.484940964853649, 9.573059394175687 ], [ -84.515817634176472, 9.568046779934946 ], [ -84.526101244177084, 9.569287014284271 ], [ -84.529253506444149, 9.571457423721142 ], [ -84.536384854177641, 9.578072008416427 ], [ -84.542586025924322, 9.58639191275654 ], [ -84.547004360962489, 9.595693670826222 ], [ -84.54971737275855, 9.603186753765669 ], [ -84.556306118132852, 9.636414700577973 ], [ -84.557055426966372, 9.638688462802293 ], [ -84.579250454045223, 9.677290758161973 ], [ -84.581627569956368, 9.68318187154614 ], [ -84.581937629218203, 9.68628245696982 ], [ -84.581214158806347, 9.705609443520984 ], [ -84.583642950661613, 9.717650050909128 ], [ -84.59131690075435, 9.742868149945139 ], [ -84.591626960016185, 9.745503648274735 ], [ -84.59149776880696, 9.748242499391836 ], [ -84.59072262155172, 9.75061961530298 ], [ -84.589379035314209, 9.752634996008226 ], [ -84.587441168974749, 9.754185288720066 ], [ -84.585038214641884, 9.755477199912832 ], [ -84.582247687580718, 9.756304023112136 ], [ -84.576304898252431, 9.757027493523992 ], [ -84.557107102910436, 9.755993963850358 ], [ -84.554032355009156, 9.756355699056257 ], [ -84.551293504791374, 9.757027493523992 ], [ -84.548864712036789, 9.758061021398987 ], [ -84.546901008174984, 9.759404609435137 ], [ -84.544911464992083, 9.761936754077908 ], [ -84.543283657914458, 9.765915839544334 ], [ -84.541810878669082, 9.774184067940382 ], [ -84.542353481927648, 9.779713446118649 ], [ -84.543180305126953, 9.78358917879757 ], [ -84.548063728158525, 9.792787584079747 ], [ -84.553825650333465, 9.800745754113223 ], [ -84.555530971776932, 9.802709458874403 ], [ -84.559277513246627, 9.80612010355992 ], [ -84.563256598713053, 9.809117336196095 ], [ -84.570439623289985, 9.813044744819081 ], [ -84.579973923557702, 9.817333889547342 ], [ -84.57105974001496, 9.824516913224954 ], [ -84.563773362650522, 9.824723618799965 ], [ -84.562145554673577, 9.82658397077364 ], [ -84.560853645279508, 9.834180406500536 ], [ -84.559199998880842, 9.837952786391952 ], [ -84.540725673950703, 9.860638738986609 ], [ -84.540260585957242, 9.863894354940498 ], [ -84.540544806797357, 9.86647817642671 ], [ -84.537625087627703, 9.869992173899675 ], [ -84.531036343152721, 9.874849758509527 ], [ -84.51382809099357, 9.883738105429188 ], [ -84.502175056333783, 9.895106920148237 ], [ -84.500908982663418, 9.897484036059382 ], [ -84.499927130732488, 9.898930975983717 ], [ -84.49183976859041, 9.903840237437009 ], [ -84.461040616331388, 9.917276108805368 ], [ -84.416573046009262, 9.920945135909278 ], [ -84.392155930851516, 9.925647690888184 ], [ -84.37275143083383, 9.920118312709974 ], [ -84.352959357188581, 9.916966051342172 ], [ -84.349135301353044, 9.915674140149463 ], [ -84.344329392687314, 9.914537257688266 ], [ -84.332340461243291, 9.913141995506692 ], [ -84.327069464584099, 9.911540025052091 ], [ -84.309241095699974, 9.914020493750797 ], [ -84.242449307089828, 9.932520657102657 ], [ -84.214673224989326, 9.941460679966383 ], [ -84.199971279950603, 9.957221991301822 ], [ -84.182401292585553, 9.960219223937997 ], [ -84.162738410149473, 9.950400701930846 ], [ -84.15131791858704, 9.945646471007819 ], [ -84.114550136779371, 9.962027899967609 ], [ -84.109925096166251, 9.962337958330124 ], [ -84.084216070715058, 9.960219223937997 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CR-C", "NAME_1": "Cartago" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -83.912236904609472, 9.943786119034144 ], [ -83.90849036313972, 9.944612942233505 ], [ -83.905234748085149, 9.945646471007819 ], [ -83.892677374960897, 9.959237372007124 ], [ -83.880585089829992, 9.960632635987338 ], [ -83.875004034808342, 9.962596339849199 ], [ -83.871231655816246, 9.96590363174721 ], [ -83.86820858385903, 9.969882717213636 ], [ -83.865960660056373, 9.977995916878058 ], [ -83.870430671038605, 10.000061754546323 ], [ -83.872394374900466, 10.026054999038934 ], [ -83.875081550073446, 10.034839993171147 ], [ -83.878828090643879, 10.040472724136919 ], [ -83.898826869864138, 10.062900295212444 ], [ -83.900868089890423, 10.064295559192715 ], [ -83.905389776816719, 10.06667267510386 ], [ -83.913864711687097, 10.072563788488026 ], [ -83.922598028975813, 10.080211900159043 ], [ -83.926370408867285, 10.084707750462314 ], [ -83.928644171990925, 10.088686835029421 ], [ -83.942726000304674, 10.136229153252827 ], [ -83.817462328323757, 10.080418605734053 ], [ -83.773563198782597, 10.059954739419652 ], [ -83.713256801859927, 10.031739406848146 ], [ -83.615226609620322, 9.986574205435204 ], [ -83.589052497075045, 9.977169094578016 ], [ -83.444901089014024, 9.976032213016197 ], [ -83.338990241106728, 9.973603420261611 ], [ -83.318913946621308, 9.969624334795185 ], [ -83.321291063431829, 9.965748603015584 ], [ -83.333641730081752, 9.947920234131459 ], [ -83.34154822507054, 9.931590481115791 ], [ -83.344855516069174, 9.913917140963292 ], [ -83.343382737723175, 9.891902981037731 ], [ -83.331833054951517, 9.856452947945172 ], [ -83.329249234364681, 9.838262843855148 ], [ -83.335915493205448, 9.821002915751933 ], [ -83.378548549975562, 9.7683446313996 ], [ -83.40875342483065, 9.732119451951121 ], [ -83.416634081397717, 9.719717109357077 ], [ -83.439113329316683, 9.663286445113329 ], [ -83.496990932585447, 9.594556790163722 ], [ -83.51091773126825, 9.566444810379664 ], [ -83.514302538431366, 9.535852362796277 ], [ -83.512132128095232, 9.526395575095705 ], [ -83.510065069647226, 9.514044908445783 ], [ -83.50401892843081, 9.500505683390543 ], [ -83.502158575557814, 9.497766832273498 ], [ -83.498954637346628, 9.494356186688663 ], [ -83.496835903853878, 9.491462306839992 ], [ -83.490428025632866, 9.478284816990708 ], [ -83.48686235221578, 9.467587794940755 ], [ -83.592153083398046, 9.530788071712152 ], [ -83.594685228040817, 9.531666570855521 ], [ -83.604529589369065, 9.536369126733803 ], [ -83.613211228915077, 9.543500474467294 ], [ -83.638739387212922, 9.569907131009302 ], [ -83.650573289925376, 9.566341458491479 ], [ -83.654552375391802, 9.561897284132328 ], [ -83.659513311889839, 9.553008938111986 ], [ -83.661011928657558, 9.551045234250125 ], [ -83.662923956575298, 9.549443263795581 ], [ -83.664784309448294, 9.54804800071463 ], [ -83.666954718885165, 9.546962795096931 ], [ -83.6695127019496, 9.545980943166001 ], [ -83.672277390589102, 9.545309150496905 ], [ -83.675248785702877, 9.544947415290949 ], [ -83.678633591966673, 9.544844062503444 ], [ -83.690260790003435, 9.545929267221879 ], [ -83.693180508273826, 9.545309150496905 ], [ -83.698167284092847, 9.543448798523229 ], [ -83.712016568409865, 9.536679185096318 ], [ -83.714161140324336, 9.536885891570648 ], [ -83.715866461767803, 9.538436184282489 ], [ -83.718011033682217, 9.551665350975156 ], [ -83.721034104740113, 9.562310696181669 ], [ -83.722041795992084, 9.564791164880319 ], [ -83.724780646209865, 9.567374986366531 ], [ -83.72925065809136, 9.569958807852686 ], [ -83.744391852701824, 9.575023098037548 ], [ -83.749378627621525, 9.578123684360548 ], [ -83.752014125951121, 9.580190741009858 ], [ -83.763279588781984, 9.595693670826222 ], [ -83.782451544802939, 9.593626614176912 ], [ -83.787205776625285, 9.593316554915077 ], [ -83.809168259707405, 9.597864081162413 ], [ -83.811881273302106, 9.598794257149223 ], [ -83.814956021203386, 9.601274725847929 ], [ -83.818289150623798, 9.604995428895904 ], [ -83.823275926442818, 9.612850247041251 ], [ -83.827513394327696, 9.620808417074784 ], [ -83.829451259767836, 9.625459296109625 ], [ -83.830200567702036, 9.627939764808275 ], [ -83.836970181128947, 9.642150784331193 ], [ -83.84454077843418, 9.654501450981172 ], [ -83.846142747989404, 9.656413478898912 ], [ -83.849062466259795, 9.658377182760773 ], [ -83.853144903614407, 9.659824124483748 ], [ -83.861154751390643, 9.660702622727854 ], [ -83.865263028066295, 9.659979153215318 ], [ -83.86820858385903, 9.658583889235103 ], [ -83.8703531557735, 9.657291978042338 ], [ -83.87283362537147, 9.656465154843033 ], [ -83.877846238712948, 9.657602037304173 ], [ -83.898387621191773, 9.66773061857316 ], [ -83.910557420688406, 9.672071438346165 ], [ -83.913451301436396, 9.672794907858702 ], [ -83.918748134718612, 9.677549140580368 ], [ -83.940917325174382, 9.70607452971575 ], [ -83.949831508717125, 9.720853990019634 ], [ -83.95014156797896, 9.722766017937374 ], [ -83.950761684703991, 9.725091457904455 ], [ -83.956187710094753, 9.729845688827481 ], [ -83.975514695746597, 9.736098538316867 ], [ -83.982129278643299, 9.748242499391836 ], [ -83.983860440307069, 9.75330679047596 ], [ -83.985979173799819, 9.758164374186492 ], [ -83.988149584136011, 9.767672837831185 ], [ -83.996391975009601, 9.768809719393005 ], [ -84.033288947127176, 9.760644842885199 ], [ -84.039050869302173, 9.761988430022029 ], [ -84.045019497052124, 9.762815253221333 ], [ -84.047965053744235, 9.762556870802939 ], [ -84.056052415886256, 9.760438137310189 ], [ -84.068222215382946, 9.755787258275348 ], [ -84.071090256809896, 9.755477199912832 ], [ -84.073932460714502, 9.755580552700337 ], [ -84.076128710371677, 9.756717434262157 ], [ -84.077627326240076, 9.758577786235833 ], [ -84.078712530958512, 9.761058254035163 ], [ -84.079177618951917, 9.763848781995705 ], [ -84.079280971739422, 9.766949368318706 ], [ -84.078609178171007, 9.771341864035776 ], [ -84.075508591848006, 9.777801418200852 ], [ -84.06884233300724, 9.788653468982375 ], [ -84.051272345642246, 9.804363105273069 ], [ -84.038895839671227, 9.812734687355942 ], [ -84.03145443357522, 9.820692857389417 ], [ -84.002618985178003, 9.86683991073329 ], [ -84.022591925976599, 9.875469876133877 ], [ -84.026415981812079, 9.877691962414133 ], [ -84.028069628210744, 9.878983872707522 ], [ -84.026338467446294, 9.887148749215385 ], [ -83.999957648426744, 9.930298569923025 ], [ -83.953965623814497, 9.946473293307804 ], [ -83.95300961030523, 9.94699005814465 ], [ -83.926680467229744, 9.947300116507165 ], [ -83.917507901268607, 9.94585317658283 ], [ -83.915156622879806, 9.944664618177569 ], [ -83.912236904609472, 9.943786119034144 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/cuba.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/cuba.geojson new file mode 100644 index 0000000000000..eaeb865197e5b --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/cuba.geojson @@ -0,0 +1,22 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "CU-14", "NAME_1": "Guantánamo" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -75.095005810746201, 19.897225962598796 ], [ -75.09495029099989, 19.97158369 ], [ -75.137035780433081, 19.971550610171906 ], [ -75.135159714999929, 19.976278928000056 ], [ -75.129750128999945, 19.981146552000041 ], [ -75.115052261999949, 19.990617325000073 ], [ -75.102076925999938, 19.99290049800004 ], [ -75.090132651999909, 20.014136874000087 ], [ -75.084857109999916, 20.025895131000084 ], [ -75.090809699999909, 20.03546784100007 ], [ -75.09243730399993, 20.061224677000041 ], [ -75.112791213999913, 20.057484937000083 ], [ -75.122380731999897, 20.043912247000037 ], [ -75.128609475999951, 20.033508485000084 ], [ -75.135794742999906, 20.021295780000059 ], [ -75.143811785999901, 20.025948425000081 ], [ -75.154332992999912, 20.031165777000069 ], [ -75.169425450999938, 20.025576828000055 ], [ -75.175445115999935, 20.013739325000074 ], [ -75.177357550999943, 20.003973700000074 ], [ -75.17406165299991, 19.993475653000075 ], [ -75.168680239999901, 19.991935841000043 ], [ -75.162111921999951, 19.990411082000037 ], [ -75.158070441999939, 19.991359768000052 ], [ -75.155425584999932, 19.994940497000073 ], [ -75.153309699999909, 19.999172268000052 ], [ -75.151234503999945, 19.994574286000045 ], [ -75.146996645999934, 19.984277612000085 ], [ -75.15912652399993, 19.97776874200008 ], [ -75.160192443999904, 19.970647995000036 ], [ -75.178862062999883, 19.970731793000041 ], [ -75.22896927899987, 19.937440491000118 ], [ -75.232858852999925, 19.900051174000055 ], [ -75.284657355999911, 19.888251044000071 ], [ -75.382080421154143, 19.882543917011262 ], [ -75.382111579186017, 19.882585150983914 ], [ -75.442753871993602, 19.962838650283459 ], [ -75.464277106403301, 19.98177806230774 ], [ -75.470529954993424, 19.98888357251883 ], [ -75.483707444842707, 20.009528306885841 ], [ -75.488280808612387, 20.024617825552184 ], [ -75.489676072592658, 20.061721503244769 ], [ -75.476111009115755, 20.067199205478914 ], [ -75.47295874684869, 20.067199205478914 ], [ -75.468798794228974, 20.069653835755901 ], [ -75.4569390530948, 20.083528958494639 ], [ -75.43327124677063, 20.094665229216957 ], [ -75.430480719709408, 20.098205064212323 ], [ -75.428827074210119, 20.103631090502404 ], [ -75.429628058987703, 20.112545274045146 ], [ -75.432082689264689, 20.117015285926698 ], [ -75.438361376276475, 20.120348416246372 ], [ -75.442521327996872, 20.120658473709568 ], [ -75.445544399954088, 20.121433620964808 ], [ -75.448102383018522, 20.123500678513494 ], [ -75.451202969341523, 20.134895330754887 ], [ -75.450505337351444, 20.161457016927784 ], [ -75.460039639417801, 20.1679424104139 ], [ -75.461874152070436, 20.169957791119145 ], [ -75.462726812792141, 20.171404731043481 ], [ -75.467816942298043, 20.18471141210199 ], [ -75.470219895731589, 20.188974718408531 ], [ -75.47528418591645, 20.203366604185419 ], [ -75.480994432147327, 20.22729279202872 ], [ -75.481511196984115, 20.233674831828012 ], [ -75.48045182978808, 20.238170681231963 ], [ -75.475955980384185, 20.246258043373984 ], [ -75.473320482054589, 20.25000458394436 ], [ -75.470633307780929, 20.252355862333161 ], [ -75.467351854304638, 20.254758815766706 ], [ -75.465181443968447, 20.256929226102898 ], [ -75.463501960047381, 20.262329413071939 ], [ -75.462106696067167, 20.294601345475712 ], [ -75.464561327243416, 20.31108612722295 ], [ -75.475129157184824, 20.331498318492606 ], [ -75.479134081072971, 20.340024929307049 ], [ -75.477325405942736, 20.342841294789878 ], [ -75.472545335698669, 20.346717027468799 ], [ -75.459962124152696, 20.351471259291145 ], [ -75.448567471011984, 20.358266710240457 ], [ -75.437017788240325, 20.3671808937832 ], [ -75.426992560658107, 20.381546942937064 ], [ -75.423039312714081, 20.389608465758045 ], [ -75.421773240842356, 20.396119696766561 ], [ -75.421644049633187, 20.401054795742198 ], [ -75.420946417643052, 20.404697984424445 ], [ -75.419241096199642, 20.407927761057294 ], [ -75.416553921026605, 20.409116319462555 ], [ -75.4114896308418, 20.40808279068824 ], [ -75.407820603737832, 20.406454982711239 ], [ -75.398467169724086, 20.403354397287615 ], [ -75.39355790917017, 20.404232896430983 ], [ -75.389397955651134, 20.407333481854664 ], [ -75.384772915038013, 20.415730903258577 ], [ -75.375471157867651, 20.422862250092749 ], [ -75.364076503827562, 20.425756129941419 ], [ -75.344801195019102, 20.438597723905843 ], [ -75.337230597713926, 20.439889635098552 ], [ -75.330719366705409, 20.437977607180812 ], [ -75.326481899719909, 20.434256904132781 ], [ -75.316973436075216, 20.428159085173604 ], [ -75.311495733841014, 20.423120632511143 ], [ -75.307981737267369, 20.417617091855277 ], [ -75.306663987652882, 20.415911770411867 ], [ -75.299971890390395, 20.41017568575927 ], [ -75.291109381892454, 20.404930528421119 ], [ -75.286742722798408, 20.403302721343493 ], [ -75.282221034972792, 20.403741970015915 ], [ -75.263901739673543, 20.412191067363835 ], [ -75.260181036625511, 20.412578640092136 ], [ -75.25653784884264, 20.41017568575927 ], [ -75.255065069597265, 20.407152614701374 ], [ -75.240492315767767, 20.396791490334977 ], [ -75.231397264172415, 20.412036037732946 ], [ -75.228296677849414, 20.442111721378808 ], [ -75.225764533206643, 20.447692776400515 ], [ -75.212354499360629, 20.459216619851134 ], [ -75.189694383389053, 20.471696479508921 ], [ -75.183028123648967, 20.473298448164826 ], [ -75.177834642254936, 20.472290757812232 ], [ -75.169488897694464, 20.465650336493809 ], [ -75.164605475562212, 20.464668484562878 ], [ -75.158352626972146, 20.465572822128024 ], [ -75.139878302941327, 20.475003770507612 ], [ -75.116882290185515, 20.483220322959539 ], [ -75.110474412863823, 20.484744778148979 ], [ -75.104970873107277, 20.484176337368069 ], [ -75.098847214827117, 20.479292914336497 ], [ -75.070476854423305, 20.45081920024586 ], [ -75.048255988023413, 20.433714300874271 ], [ -75.015854865309791, 20.43115631780978 ], [ -74.988776415199368, 20.413224596138207 ], [ -74.982239345769187, 20.412036037732946 ], [ -74.978234421881041, 20.41304372808554 ], [ -74.977304246793551, 20.416686916767787 ], [ -74.97725256995011, 20.419477443828953 ], [ -74.978001878783687, 20.422242133367718 ], [ -74.979242113133012, 20.425136013216445 ], [ -74.981774257775783, 20.429554348254555 ], [ -74.985494960823758, 20.433921007348602 ], [ -74.991411912629644, 20.438571886383443 ], [ -74.999344245140776, 20.439372870261764 ], [ -75.000506965124316, 20.439734605467663 ], [ -75.000713670699326, 20.441284898179504 ], [ -75.000196905862481, 20.444437161345888 ], [ -74.998104010791451, 20.451490993814275 ], [ -74.998336554788182, 20.454074815300487 ], [ -74.999447597928281, 20.456994534470198 ], [ -75.003400844972987, 20.464823513294505 ], [ -75.001204597114452, 20.466735541212245 ], [ -74.99577857082437, 20.468311672345806 ], [ -74.968777635079789, 20.472058213815501 ], [ -74.959527553853491, 20.471231391515516 ], [ -74.949838223055565, 20.466347968483944 ], [ -74.91617102667152, 20.443403632571574 ], [ -74.879635789759902, 20.4273322619743 ], [ -74.868602870925713, 20.421079413384177 ], [ -74.858396776190261, 20.413999742494127 ], [ -74.844986742344247, 20.408186143475746 ], [ -74.838708055332461, 20.406765041973074 ], [ -74.834703132343691, 20.40847036431586 ], [ -74.833230353098315, 20.411674303426366 ], [ -74.83214514837988, 20.417384547858603 ], [ -74.830594854768719, 20.421415310168413 ], [ -74.829147914844384, 20.42443838122631 ], [ -74.826409063727283, 20.427280585130859 ], [ -74.823618536666118, 20.42924428989204 ], [ -74.783155891131457, 20.444773058130124 ], [ -74.791604986680795, 20.471567288299696 ], [ -74.790287237965629, 20.491023464261445 ], [ -74.784706183843298, 20.506681422809379 ], [ -74.779641892759116, 20.516164048931671 ], [ -74.772510545924945, 20.5260084093606 ], [ -74.767187873321689, 20.531796169957261 ], [ -74.759591436695416, 20.538074856069727 ], [ -74.75599992485661, 20.539728502468392 ], [ -74.751891649080335, 20.540167752040134 ], [ -74.744010993412587, 20.539986883987467 ], [ -74.740936244611987, 20.540658678455202 ], [ -74.737603116090895, 20.542544867051959 ], [ -74.727758754762704, 20.549857082838059 ], [ -74.715167585115921, 20.556063378921806 ], [ -74.709828253999945, 20.552232164000088 ], [ -74.673491990999935, 20.540961005000042 ], [ -74.669992641999897, 20.52765534100007 ], [ -74.65070553299995, 20.513088283000059 ], [ -74.605213995999918, 20.485744533000059 ], [ -74.597279425999943, 20.476792710000041 ], [ -74.586496548999946, 20.45579661700009 ], [ -74.554798956999946, 20.414455471000053 ], [ -74.547230597999942, 20.410060940000051 ], [ -74.543934699999909, 20.403550523000035 ], [ -74.494984503999945, 20.355169989000046 ], [ -74.485747850999928, 20.350816148000035 ], [ -74.472075975999928, 20.349188544000071 ], [ -74.450266079999949, 20.343085028000075 ], [ -74.423410610999952, 20.32758209800005 ], [ -74.401112433999913, 20.30727773600006 ], [ -74.392974412999934, 20.286525783000059 ], [ -74.385568813999953, 20.286525783000059 ], [ -74.372181769999941, 20.300523179000038 ], [ -74.351918097999942, 20.300441799000055 ], [ -74.329701300999943, 20.29523346600007 ], [ -74.310414191999939, 20.293931382000039 ], [ -74.293690558999913, 20.300930080000057 ], [ -74.276234503999945, 20.311224677000041 ], [ -74.257191535999937, 20.319647528000075 ], [ -74.235951300999943, 20.321234442000048 ], [ -74.223540818999936, 20.317368882000039 ], [ -74.213612433999913, 20.310980536000045 ], [ -74.193714972999942, 20.293931382000039 ], [ -74.159657355999911, 20.273423570000091 ], [ -74.147531704999949, 20.259182033000059 ], [ -74.139637824999909, 20.242336330000057 ], [ -74.13508053299995, 20.223822333000044 ], [ -74.132883266999897, 20.204575914000088 ], [ -74.141957160999937, 20.182603257000039 ], [ -74.162912563999953, 20.17055898600006 ], [ -74.184071417999917, 20.162665106000077 ], [ -74.198068813999953, 20.148871161000045 ], [ -74.218332485999952, 20.137844143000052 ], [ -74.225087042999917, 20.135687567000048 ], [ -74.230295376999948, 20.13031647300005 ], [ -74.235951300999943, 20.094671942000048 ], [ -74.267404751999948, 20.068304755000042 ], [ -74.304514126999948, 20.069322007000039 ], [ -74.346587693999936, 20.079575914000088 ], [ -74.392974412999934, 20.081040757000039 ], [ -74.455922003999945, 20.06867096600007 ], [ -74.49836178299995, 20.065619208000044 ], [ -74.580476955999927, 20.047642379000081 ], [ -74.618649989999938, 20.054519508000055 ], [ -74.650183918999915, 20.042163631000051 ], [ -74.713124171999937, 20.051800607000075 ], [ -74.788424855999949, 20.03946681900004 ], [ -74.812977667999917, 20.037258205000057 ], [ -74.838002081999946, 20.026434637000079 ], [ -74.855132615999935, 20.012762762000079 ], [ -74.870676235999952, 19.997015692000048 ], [ -74.887806769999941, 19.984076239000046 ], [ -74.910023566999939, 19.978664455000057 ], [ -74.933516762999943, 19.97821893400004 ], [ -74.9473341019999, 19.975949496000055 ], [ -74.955515932999901, 19.967813299000056 ], [ -74.961560749999933, 19.947009654000055 ], [ -74.977867950999951, 19.92303486600008 ], [ -75.01008053299995, 19.91156647300005 ], [ -75.045667739999942, 19.90760060100007 ], [ -75.05103469799991, 19.919371866000063 ], [ -75.058231433999936, 19.922965563000048 ], [ -75.063517880999939, 19.921604784000067 ], [ -75.066378021999924, 19.914368366000076 ], [ -75.066332835999901, 19.904861972000049 ], [ -75.091779838999912, 19.89713258800009 ], [ -75.095005810746201, 19.897225962598796 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-09", "NAME_1": "Camagüey" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -78.333119269999941, 20.554632880000042 ], [ -78.326079881999931, 20.535101630000042 ], [ -78.32835852799991, 20.521307684000078 ], [ -78.338978644999941, 20.518011786000045 ], [ -78.357289191999939, 20.530422268000052 ], [ -78.368967251999948, 20.536525783000059 ], [ -78.383859829999949, 20.540594794000071 ], [ -78.396595831999946, 20.546454169000071 ], [ -78.409779425999943, 20.573635158000059 ], [ -78.427845831999946, 20.585638739000046 ], [ -78.463449673999946, 20.602443752000056 ], [ -78.449208136999914, 20.612941799000055 ], [ -78.433501756999931, 20.609523830000057 ], [ -78.418934699999909, 20.599107164000088 ], [ -78.408192511999914, 20.588771877000056 ], [ -78.393422003999945, 20.569973049000055 ], [ -78.384185350999928, 20.562160549000055 ], [ -78.367258266999897, 20.554632880000042 ], [ -78.364491339999915, 20.570217190000051 ], [ -78.355295376999948, 20.573431708000044 ], [ -78.343576626999948, 20.567328192000048 ], [ -78.333119269999941, 20.554632880000042 ] ] ], [ [ [ -78.436146613999938, 20.725978908000059 ], [ -78.449126756999931, 20.711615302000041 ], [ -78.495757615999935, 20.701239325000074 ], [ -78.511830206999946, 20.691148179000038 ], [ -78.527821417999917, 20.699286200000074 ], [ -78.545399542999917, 20.704250393000052 ], [ -78.533192511999914, 20.712795315000051 ], [ -78.49836178299995, 20.72016022300005 ], [ -78.483957485999952, 20.732163804000038 ], [ -78.478586391999897, 20.730169989000046 ], [ -78.478423631999931, 20.729193427000041 ], [ -78.476470506999931, 20.725978908000059 ], [ -78.465891079999949, 20.73118724200009 ], [ -78.455799933999913, 20.731756903000075 ], [ -78.436146613999938, 20.725978908000059 ] ] ], [ [ [ -77.634185350999928, 22.054266669000071 ], [ -77.626576300999943, 22.042059637000079 ], [ -77.624379035999937, 22.029730536000045 ], [ -77.627064581999946, 22.016180731000077 ], [ -77.64867102799991, 21.971136786000045 ], [ -77.645578579999949, 21.961493231000077 ], [ -77.634185350999928, 21.945013739000046 ], [ -77.649647589999915, 21.944484768000052 ], [ -77.661529100999928, 21.940130927000041 ], [ -77.682606574999909, 21.925116278000075 ], [ -77.677886522999927, 21.943019924000055 ], [ -77.684315558999913, 21.951157945000091 ], [ -77.695057745999918, 21.948065497000073 ], [ -77.703114386999914, 21.93195221600007 ], [ -77.700428839999915, 21.928859768000052 ], [ -77.696156378999945, 21.922267971000053 ], [ -77.695423956999946, 21.915187893000052 ], [ -77.703114386999914, 21.910834052000041 ], [ -77.708892381999931, 21.912176825000074 ], [ -77.712635870999918, 21.916937567000048 ], [ -77.715891079999949, 21.923041083000044 ], [ -77.728179490999935, 21.938788153000075 ], [ -77.732980923999946, 21.948187567000048 ], [ -77.739125128999945, 21.957220770000049 ], [ -77.751535610999952, 21.966131903000075 ], [ -77.765777147999927, 21.959784247000073 ], [ -77.787261522999927, 21.964056708000044 ], [ -77.808664516999897, 21.973578192000048 ], [ -77.82258053299995, 21.98314036700009 ], [ -77.825103318999936, 21.991848049000055 ], [ -77.821156378999945, 22.002427476000037 ], [ -77.815297003999945, 22.013617255000042 ], [ -77.812367316999939, 22.024115302000041 ], [ -77.817128058999913, 22.031317450000074 ], [ -77.827951626999948, 22.036118882000039 ], [ -77.847075975999928, 22.041205145000049 ], [ -77.84203040299991, 22.032619533000059 ], [ -77.84007727799991, 22.023993231000077 ], [ -77.841664191999939, 22.015366929000038 ], [ -77.847075975999928, 22.007025458000044 ], [ -77.853911912999934, 22.027533270000049 ], [ -77.860096808999913, 22.027533270000049 ], [ -77.870228644999941, 22.013251044000071 ], [ -77.886586066999939, 22.00922272300005 ], [ -77.901844855999911, 22.015204169000071 ], [ -77.908558722999942, 22.031236070000091 ], [ -77.917225714999915, 22.043158270000049 ], [ -77.934478318999936, 22.056138414000088 ], [ -77.947132941999939, 22.072821356000077 ], [ -77.94204667899993, 22.095851955000057 ], [ -77.94945227799991, 22.102606512000079 ], [ -77.930165167999917, 22.102118231000077 ], [ -77.91624915299991, 22.093817450000074 ], [ -77.903635219999899, 22.083238023000035 ], [ -77.888050910999937, 22.075995184000078 ], [ -77.871693488999938, 22.07562897300005 ], [ -77.860422329999949, 22.080959377000056 ], [ -77.850819464999915, 22.088690497000073 ], [ -77.839670376999948, 22.095851955000057 ], [ -77.82249915299991, 22.100531317000048 ], [ -77.808501756999931, 22.099554755000042 ], [ -77.796376105999911, 22.095038153000075 ], [ -77.785023566999939, 22.089016018000052 ], [ -77.781239386999914, 22.084784247000073 ], [ -77.771962042999917, 22.071356512000079 ], [ -77.767689581999946, 22.068508205000057 ], [ -77.759103969999899, 22.07062409100007 ], [ -77.744699673999946, 22.080023505000042 ], [ -77.737212693999936, 22.082180080000057 ], [ -77.726307745999918, 22.077622789000088 ], [ -77.694203253999945, 22.058010158000059 ], [ -77.682606574999909, 22.054266669000071 ], [ -77.669667120999918, 22.06085846600007 ], [ -77.661447719999899, 22.069322007000039 ], [ -77.651722785999937, 22.070257880000042 ], [ -77.634185350999928, 22.054266669000071 ] ] ], [ [ [ -77.847075975999928, 22.260321356000077 ], [ -77.839588995999918, 22.27374909100007 ], [ -77.850697394999941, 22.288804429000038 ], [ -77.868478969999899, 22.301743882000039 ], [ -77.880686001999948, 22.308742580000057 ], [ -77.85610917899993, 22.312445380000042 ], [ -77.83421790299991, 22.295884507000039 ], [ -77.818430141999897, 22.271144924000055 ], [ -77.805734829999949, 22.228216864000046 ], [ -77.790150519999941, 22.211493231000077 ], [ -77.772043423999946, 22.196112372000073 ], [ -77.757720506999931, 22.17837148600006 ], [ -77.781727667999917, 22.177801825000074 ], [ -77.807118292999917, 22.20258209800005 ], [ -77.847075975999928, 22.260321356000077 ] ] ], [ [ [ -77.997303839999915, 22.147365627000056 ], [ -78.00413977799991, 22.162258205000057 ], [ -78.036040818999936, 22.183417059000078 ], [ -78.045725063999953, 22.198879299000055 ], [ -78.029449022999927, 22.20453522300005 ], [ -78.016468878999945, 22.21743398600006 ], [ -78.007923956999946, 22.23383209800005 ], [ -78.004750128999945, 22.250067450000074 ], [ -78.003325975999928, 22.286363023000035 ], [ -78.006825324999909, 22.297674872000073 ], [ -78.01781165299991, 22.314886786000045 ], [ -78.002674933999913, 22.312689520000049 ], [ -77.987172003999945, 22.307806708000044 ], [ -77.97492428299995, 22.298895575000074 ], [ -77.969960089999915, 22.284816799000055 ], [ -77.975656704999949, 22.275620835000041 ], [ -77.986480272999927, 22.265570380000042 ], [ -77.993397589999915, 22.253119208000044 ], [ -77.987416144999941, 22.236721096000053 ], [ -77.978627081999946, 22.233221747000073 ], [ -77.953968878999945, 22.236517645000049 ], [ -77.94204667899993, 22.232977606000077 ], [ -77.935129360999952, 22.224025783000059 ], [ -77.930572068999936, 22.213853257000039 ], [ -77.923410610999952, 22.206366278000075 ], [ -77.908558722999942, 22.205023505000042 ], [ -77.921620245999918, 22.212469794000071 ], [ -77.917632615999935, 22.218817450000074 ], [ -77.913197394999941, 22.224310614000046 ], [ -77.908070441999939, 22.228949286000045 ], [ -77.902333136999914, 22.232977606000077 ], [ -77.89484615799995, 22.220851955000057 ], [ -77.884877081999946, 22.214789130000042 ], [ -77.875070766999897, 22.216294664000088 ], [ -77.867583787999934, 22.226752020000049 ], [ -77.85960852799991, 22.20962148600006 ], [ -77.870472785999937, 22.202215887000079 ], [ -77.888661261999914, 22.198431708000044 ], [ -77.902333136999914, 22.19204336100006 ], [ -77.890777147999927, 22.189154364000046 ], [ -77.882191535999937, 22.183294989000046 ], [ -77.874908006999931, 22.176703192000048 ], [ -77.867583787999934, 22.171535549000055 ], [ -77.857004360999952, 22.168198960000041 ], [ -77.836415167999917, 22.164211330000057 ], [ -77.825998501999948, 22.157904364000046 ], [ -77.848500128999945, 22.116034247000073 ], [ -77.863433397999927, 22.099188544000071 ], [ -77.874419725999928, 22.109523830000057 ], [ -77.878977016999897, 22.107570705000057 ], [ -77.890492316999939, 22.104641018000052 ], [ -77.894886847999942, 22.102606512000079 ], [ -77.898101365999935, 22.110296942000048 ], [ -77.900746222999942, 22.114488023000035 ], [ -77.908558722999942, 22.123114325000074 ], [ -77.912831183999913, 22.14321523600006 ], [ -77.933949347999942, 22.150213934000078 ], [ -77.950754360999952, 22.142157294000071 ], [ -77.94204667899993, 22.116888739000046 ], [ -77.954945441999939, 22.122259833000044 ], [ -77.990101691999939, 22.141831773000035 ], [ -77.997303839999915, 22.147365627000056 ] ] ], [ [ [ -78.196522589999915, 22.329169012000079 ], [ -78.175363735999952, 22.341620184000078 ], [ -78.184885219999899, 22.358221747000073 ], [ -78.205189581999946, 22.367987372000073 ], [ -78.216420050999943, 22.359605210000041 ], [ -78.217681443999936, 22.350287177000041 ], [ -78.221547003999945, 22.339911200000074 ], [ -78.228138800999943, 22.33344147300005 ], [ -78.237456834999932, 22.336004950000074 ], [ -78.243723110999952, 22.346625067000048 ], [ -78.244211391999897, 22.359116929000038 ], [ -78.239613410999937, 22.366929429000038 ], [ -78.23070227799991, 22.363348700000074 ], [ -78.230458136999914, 22.380764065000051 ], [ -78.24632727799991, 22.400620835000041 ], [ -78.26976477799991, 22.410142320000091 ], [ -78.292144334999932, 22.396877346000053 ], [ -78.297230597999942, 22.402044989000046 ], [ -78.301747199999909, 22.403225002000056 ], [ -78.306548631999931, 22.403021552000041 ], [ -78.312611456999946, 22.404282945000091 ], [ -78.298736131999931, 22.420396226000037 ], [ -78.279042120999918, 22.425441799000055 ], [ -78.243723110999952, 22.424750067000048 ], [ -78.21157792899993, 22.436590887000079 ], [ -78.197621222999942, 22.437201239000046 ], [ -78.18968665299991, 22.424750067000048 ], [ -78.169748501999948, 22.435044664000088 ], [ -78.144195115999935, 22.428941148000035 ], [ -78.119048631999931, 22.413763739000046 ], [ -78.100331183999913, 22.396877346000053 ], [ -78.090728318999936, 22.384466864000046 ], [ -78.082020636999914, 22.369696356000077 ], [ -78.075550910999937, 22.354071356000077 ], [ -78.071644660999937, 22.320868231000077 ], [ -78.06704667899993, 22.310451565000051 ], [ -78.045725063999953, 22.288234768000052 ], [ -78.037220831999946, 22.288031317000048 ], [ -78.023345506999931, 22.283026434000078 ], [ -78.010975714999915, 22.281398830000057 ], [ -78.02765865799995, 22.266017971000053 ], [ -78.051584438999953, 22.27220286700009 ], [ -78.100331183999913, 22.301906643000052 ], [ -78.122141079999949, 22.305853583000044 ], [ -78.146311001999948, 22.305853583000044 ], [ -78.171538865999935, 22.310736395000049 ], [ -78.196522589999915, 22.329169012000079 ] ] ], [ [ [ -78.081820195245825, 22.082791411494441 ], [ -78.079823370999918, 22.082180080000057 ], [ -78.065052863999938, 22.086981512000079 ], [ -78.055572068999936, 22.077460028000075 ], [ -78.042307094999899, 22.051174221000053 ], [ -78.023264126999948, 22.034328518000052 ], [ -78.01781165299991, 22.027533270000049 ], [ -78.011219855999911, 22.009263414000088 ], [ -77.993234829999949, 21.979681708000044 ], [ -77.985218878999945, 21.970038153000075 ], [ -77.973378058999913, 21.966131903000075 ], [ -77.961333787999934, 21.958238023000035 ], [ -77.915394660999937, 21.914252020000049 ], [ -77.911976691999939, 21.905991929000038 ], [ -77.895008917999917, 21.876939195000091 ], [ -77.888050910999937, 21.86985911700009 ], [ -77.876047329999949, 21.871527411000045 ], [ -77.870350714999915, 21.881537177000041 ], [ -77.865589972999942, 21.956244208000044 ], [ -77.860096808999913, 21.966131903000075 ], [ -77.849110480999911, 21.970526434000078 ], [ -77.822255011999914, 21.966457424000055 ], [ -77.806141730999911, 21.966131903000075 ], [ -77.815012173999946, 21.955755927000041 ], [ -77.846994594999899, 21.950384833000044 ], [ -77.853911912999934, 21.941839911000045 ], [ -77.852528449999909, 21.924017645000049 ], [ -77.848540818999936, 21.910589911000045 ], [ -77.842152472999942, 21.899969794000071 ], [ -77.833485480999911, 21.890326239000046 ], [ -77.822010870999918, 21.880275783000059 ], [ -77.813303188999953, 21.876450914000088 ], [ -77.788726365999935, 21.876695054000038 ], [ -77.777943488999938, 21.870021877000056 ], [ -77.770375128999945, 21.854559637000079 ], [ -77.766021287999934, 21.83734772300005 ], [ -77.764556443999936, 21.825506903000075 ], [ -77.760894334999932, 21.813299872000073 ], [ -77.751576300999943, 21.804632880000042 ], [ -77.738392706999946, 21.798651434000078 ], [ -77.710072394999941, 21.790187893000052 ], [ -77.704457160999937, 21.789252020000049 ], [ -77.68976803299995, 21.795884507000039 ], [ -77.681263800999943, 21.791693427000041 ], [ -77.673207160999937, 21.784735419000071 ], [ -77.664662238999938, 21.781154690000051 ], [ -77.603871222999942, 21.789740302000041 ], [ -77.586415167999917, 21.787909247000073 ], [ -77.569650844999899, 21.780585028000075 ], [ -77.524973110999952, 21.753810940000051 ], [ -77.524403449999909, 21.767645575000074 ], [ -77.516590949999909, 21.774603583000044 ], [ -77.490834113999938, 21.781154690000051 ], [ -77.489247199999909, 21.771226304000038 ], [ -77.483387824999909, 21.766180731000077 ], [ -77.474232550999943, 21.765041408000059 ], [ -77.462880011999914, 21.766831773000035 ], [ -77.464955206999946, 21.770575262000079 ], [ -77.467518683999913, 21.777736721000053 ], [ -77.469715949999909, 21.781154690000051 ], [ -77.455637173999946, 21.776841539000088 ], [ -77.442250128999945, 21.766587632000039 ], [ -77.421986456999946, 21.74640534100007 ], [ -77.436350063999953, 21.744614976000037 ], [ -77.446278449999909, 21.750230210000041 ], [ -77.452544725999928, 21.750677802000041 ], [ -77.456044074999909, 21.733343817000048 ], [ -77.453724738999938, 21.715033270000049 ], [ -77.439076300999943, 21.683823960000041 ], [ -77.435617641999897, 21.667873440000051 ], [ -77.430287238999938, 21.657619533000059 ], [ -77.417469855999911, 21.653713283000059 ], [ -77.387196417999917, 21.650132554000038 ], [ -77.363352016999897, 21.638251044000071 ], [ -77.356760219999899, 21.636542059000078 ], [ -77.347157355999911, 21.638617255000042 ], [ -77.342152472999942, 21.64329661700009 ], [ -77.339426235999952, 21.648016669000071 ], [ -77.336537238999938, 21.650132554000038 ], [ -77.336903449999909, 21.655585028000075 ], [ -77.342884894999941, 21.667547919000071 ], [ -77.352406378999945, 21.679510809000078 ], [ -77.378407355999911, 21.690497137000079 ], [ -77.389149542999917, 21.70384349200009 ], [ -77.401478644999941, 21.733343817000048 ], [ -77.407093878999945, 21.75657786700009 ], [ -77.411691860999952, 21.763413804000038 ], [ -77.418568488999938, 21.767279364000046 ], [ -77.438303188999953, 21.77484772300005 ], [ -77.442372199999909, 21.777736721000053 ], [ -77.443714972999942, 21.788234768000052 ], [ -77.448801235999952, 21.801906643000052 ], [ -77.459136522999927, 21.809271552000041 ], [ -77.476551886999914, 21.800970770000049 ], [ -77.490834113999938, 21.815252997000073 ], [ -77.504383917999917, 21.803534247000073 ], [ -77.518544074999909, 21.811835028000075 ], [ -77.545480923999946, 21.843166408000059 ], [ -77.583078579999949, 21.873277085000041 ], [ -77.593658006999931, 21.888739325000074 ], [ -77.600493943999936, 21.890448309000078 ], [ -77.614328579999949, 21.884182033000059 ], [ -77.605824347999942, 21.901271877000056 ], [ -77.589914516999897, 21.919256903000075 ], [ -77.571644660999937, 21.930812893000052 ], [ -77.556019660999937, 21.928534247000073 ], [ -77.521229620999918, 21.901190497000073 ], [ -77.517486131999931, 21.893011786000045 ], [ -77.511097785999937, 21.867743231000077 ], [ -77.507557745999918, 21.862453518000052 ], [ -77.401356574999909, 21.79047272300005 ], [ -77.380970831999946, 21.781154690000051 ], [ -77.330067511999914, 21.76634349200009 ], [ -77.315785285999937, 21.756903387000079 ], [ -77.301584438999953, 21.743353583000044 ], [ -77.267730272999927, 21.71751536700009 ], [ -77.254302537999934, 21.712836005000042 ], [ -77.195423956999946, 21.671291408000059 ], [ -77.180653449999909, 21.664252020000049 ], [ -77.166737433999913, 21.660142320000091 ], [ -77.151844855999911, 21.660060940000051 ], [ -77.133941209999932, 21.664455471000053 ], [ -77.141713019999941, 21.645575262000079 ], [ -77.136301235999952, 21.633490302000041 ], [ -77.126210089999915, 21.624741929000038 ], [ -77.120269334999932, 21.616034247000073 ], [ -77.123768683999913, 21.596177476000037 ], [ -77.147816535999937, 21.571966864000046 ], [ -77.154408331999946, 21.554592190000051 ], [ -77.163197394999941, 21.56000397300005 ], [ -77.180490688999953, 21.578029690000051 ], [ -77.185414191999939, 21.581854559000078 ], [ -77.249745245999918, 21.609767971000053 ], [ -77.266021287999934, 21.614243882000039 ], [ -77.284779425999943, 21.616034247000073 ], [ -77.284250454999949, 21.614243882000039 ], [ -77.286732550999943, 21.610581773000035 ], [ -77.290028449999909, 21.607123114000046 ], [ -77.291615363999938, 21.60610586100006 ], [ -77.293771938999953, 21.602484442000048 ], [ -77.298817511999914, 21.603989976000037 ], [ -77.304676886999914, 21.607367255000042 ], [ -77.313588019999941, 21.611151434000078 ], [ -77.32445227799991, 21.620347398000035 ], [ -77.333159959999932, 21.623439846000053 ], [ -77.356190558999913, 21.621649481000077 ], [ -77.364247199999909, 21.611761786000045 ], [ -77.360951300999943, 21.600775458000044 ], [ -77.349598761999914, 21.595526434000078 ], [ -77.338002081999946, 21.592962958000044 ], [ -77.329701300999943, 21.587103583000044 ], [ -77.322010870999918, 21.580267645000049 ], [ -77.31273352799991, 21.575100002000056 ], [ -77.302805141999897, 21.572943427000041 ], [ -77.274769660999937, 21.575100002000056 ], [ -77.255116339999915, 21.567450262000079 ], [ -77.249989386999914, 21.550848700000074 ], [ -77.257232225999928, 21.534247137000079 ], [ -77.274769660999937, 21.526678778000075 ], [ -77.27757727799991, 21.518459377000056 ], [ -77.271229620999918, 21.500474351000037 ], [ -77.262521938999953, 21.483099677000041 ], [ -77.25804602799991, 21.476385809000078 ], [ -77.24673417899993, 21.474310614000046 ], [ -77.224354620999918, 21.477769273000035 ], [ -77.208485480999911, 21.476060289000088 ], [ -77.216460740999935, 21.458400783000059 ], [ -77.206613735999952, 21.460882880000042 ], [ -77.181711391999897, 21.472642320000091 ], [ -77.180775519999941, 21.473822333000044 ], [ -77.171294725999928, 21.478949286000045 ], [ -77.161854620999918, 21.480129299000055 ], [ -77.153065558999913, 21.495266018000052 ], [ -77.140736456999946, 21.548407294000071 ], [ -77.11546790299991, 21.59320709800005 ], [ -77.107248501999948, 21.60297272300005 ], [ -77.088286912999934, 21.60618724200009 ], [ -77.069935675999943, 21.595770575000074 ], [ -76.962635870999918, 21.472642320000091 ], [ -76.946766730999911, 21.459051825000074 ], [ -76.944813605999911, 21.45774974200009 ], [ -76.947209846057547, 21.455796617519866 ], [ -76.955374721666033, 21.448432725789644 ], [ -76.971265225110017, 21.442464098039693 ], [ -76.999738939200654, 21.421638494720753 ], [ -77.012425502634812, 21.41616079428519 ], [ -77.039555629588619, 21.4098045920083 ], [ -77.057461513737849, 21.409029446551699 ], [ -77.080690069591014, 21.414326279833915 ], [ -77.10048214413564, 21.416470851748386 ], [ -77.116346809157903, 21.37068553271115 ], [ -77.124666714397335, 21.361461289906572 ], [ -77.130738694934792, 21.348490504732979 ], [ -77.131591355656496, 21.339111233196832 ], [ -77.127147183095985, 21.322703965815379 ], [ -77.122289597586871, 21.316838690852876 ], [ -77.117793749082239, 21.313893134160821 ], [ -77.079501512085074, 21.314099839735775 ], [ -77.073687913966069, 21.31265289981144 ], [ -77.071672533260767, 21.309164739860819 ], [ -77.073248664394328, 21.305521552077948 ], [ -77.129705166160477, 21.256687323561096 ], [ -77.134795294767002, 21.244930935214484 ], [ -77.135518765178858, 21.238083808321107 ], [ -77.131126267663092, 21.17351410599116 ], [ -77.167558152686581, 21.116825059329017 ], [ -77.174069382795778, 21.109538682863899 ], [ -77.18698849202525, 21.099048367288276 ], [ -77.193473883712727, 21.097110500948816 ], [ -77.222722744159285, 21.091219387564649 ], [ -77.227735358400082, 21.089178168437684 ], [ -77.237088793313148, 21.083648790259474 ], [ -77.248948534447266, 21.078351956077881 ], [ -77.263004523439974, 21.059903469569463 ], [ -77.291839972736511, 20.995023708877056 ], [ -77.300082363610159, 20.991147976198135 ], [ -77.308298916062085, 20.993395900900111 ], [ -77.314267543812093, 20.996186427961277 ], [ -77.324292772293575, 21.005255642034228 ], [ -77.328995327272537, 21.008485419566455 ], [ -77.333646206307378, 21.009493109919049 ], [ -77.339692349322434, 21.006573390749395 ], [ -77.346306932219136, 21.001509101463853 ], [ -77.356590542219749, 20.980657659723192 ], [ -77.366641608223631, 20.990450344208 ], [ -77.369793871390016, 20.997116603948086 ], [ -77.369664680180847, 21.000243027793488 ], [ -77.368967048190711, 21.003085231698094 ], [ -77.362326625972969, 21.012516180976945 ], [ -77.361525642094705, 21.015203355250605 ], [ -77.361835699557901, 21.017477118374302 ], [ -77.36390275710653, 21.020112615804578 ], [ -77.368786180138102, 21.021585395049897 ], [ -77.377235276586759, 21.023032334974289 ], [ -77.393926764808327, 21.024220893379493 ], [ -77.411419236908216, 21.02845836036505 ], [ -77.413693000031913, 21.030499579491959 ], [ -77.414519823231217, 21.03303172503405 ], [ -77.414054735237812, 21.038974514362337 ], [ -77.414907395959517, 21.043573717453057 ], [ -77.416922776664819, 21.048172918745195 ], [ -77.42560441800947, 21.060652778402982 ], [ -77.428627489067367, 21.063805039770727 ], [ -77.432864956052867, 21.06910187395232 ], [ -77.434492764029812, 21.071685696337795 ], [ -77.435629644692312, 21.074166165036445 ], [ -77.436120572006757, 21.076259060107532 ], [ -77.437670864718598, 21.076104031375905 ], [ -77.441055670982394, 21.073907781718731 ], [ -77.44792863629749, 21.066078802894424 ], [ -77.46239803733954, 21.059386704732617 ], [ -77.465963710756625, 21.056957912877351 ], [ -77.467901577096086, 21.053676459401061 ], [ -77.46777238588686, 21.047862861281999 ], [ -77.467074754796101, 21.043522039710354 ], [ -77.464749314829021, 21.035951443304441 ], [ -77.464826830094125, 21.034582016846571 ], [ -77.468935105870401, 21.025848700457118 ], [ -77.469994473066492, 21.018949896720358 ], [ -77.473172573755278, 21.011999417039476 ], [ -77.479735479808539, 21.004092922050688 ], [ -77.497925584797883, 21.000682278264492 ], [ -77.511361457065561, 20.999364529549382 ], [ -77.524177211708945, 21.000217190271087 ], [ -77.526786871616821, 21.000139675005983 ], [ -77.529396532424016, 20.996909898373076 ], [ -77.532187058585862, 20.982285467700137 ], [ -77.546656459627911, 20.980270086994892 ], [ -77.566913622165941, 20.974689031973242 ], [ -77.576990525692167, 20.969443875534409 ], [ -77.5823131991948, 20.955982163945691 ], [ -77.582261522351359, 20.943347276455654 ], [ -77.58422522711254, 20.940272529453637 ], [ -77.587351650957885, 20.937792059855667 ], [ -77.594973924207238, 20.938644721476692 ], [ -77.600141568078868, 20.939781602139192 ], [ -77.611510382797917, 20.940479234129327 ], [ -77.617013922554463, 20.941331894851032 ], [ -77.620812140867599, 20.944432481174033 ], [ -77.625876431052461, 20.95078868345098 ], [ -77.629778002153046, 20.956989854298342 ], [ -77.635281541909592, 20.964017849244328 ], [ -77.640810920087858, 20.966239936423904 ], [ -77.647425502984561, 20.965154730806148 ], [ -77.655125292398338, 20.960142117464727 ], [ -77.655151129920682, 20.952183946531875 ], [ -77.653523321943737, 20.9457502298892 ], [ -77.652644822800312, 20.939394029410892 ], [ -77.653316617268047, 20.933657944758352 ], [ -77.657528245831884, 20.917483222272892 ], [ -77.658535936184478, 20.909680080970929 ], [ -77.658690964916104, 20.902652086024943 ], [ -77.658096685713474, 20.896864325428282 ], [ -77.666029019123926, 20.891515815302625 ], [ -77.68117021373439, 20.885728053806645 ], [ -77.742174241747819, 20.874669298349431 ], [ -77.765790371228661, 20.876193753538871 ], [ -77.817725186068458, 20.807309068059055 ], [ -77.831109382392071, 20.725686143200903 ], [ -77.831130344456355, 20.725558300366398 ], [ -77.840809699999909, 20.728257554000038 ], [ -77.877512173999946, 20.732163804000038 ], [ -77.899240688999953, 20.72728099200009 ], [ -77.914173956999946, 20.716376044000071 ], [ -77.926869269999941, 20.704901434000078 ], [ -77.94204667899993, 20.69798411700009 ], [ -78.007069464999915, 20.696193752000056 ], [ -78.041127081999946, 20.704494533000059 ], [ -78.051909959999932, 20.725978908000059 ], [ -78.059396938999953, 20.725978908000059 ], [ -78.065541144999941, 20.71165599200009 ], [ -78.098378058999913, 20.748114325000074 ], [ -78.110259568999936, 20.753241278000075 ], [ -78.132069464999915, 20.757391669000071 ], [ -78.144113735999952, 20.768255927000041 ], [ -78.161773240999935, 20.800441799000055 ], [ -78.172352667999917, 20.811753648000035 ], [ -78.190785285999937, 20.827622789000088 ], [ -78.211048956999946, 20.839504299000055 ], [ -78.226918097999942, 20.838934637000079 ], [ -78.237660285999937, 20.833400783000059 ], [ -78.241281704999949, 20.83852773600006 ], [ -78.241851365999935, 20.847886460000041 ], [ -78.243723110999952, 20.855047919000071 ], [ -78.255726691999939, 20.868638414000088 ], [ -78.262074347999942, 20.878159898000035 ], [ -78.264800584999932, 20.886664130000042 ], [ -78.272043423999946, 20.90110911700009 ], [ -78.342681443999936, 20.949408270000049 ], [ -78.356353318999936, 20.953029690000051 ], [ -78.391468878999945, 20.951239325000074 ], [ -78.403920050999943, 20.957953192000048 ], [ -78.415028449999909, 20.973089911000045 ], [ -78.42992102799991, 20.999701239000046 ], [ -78.442250128999945, 21.011135158000059 ], [ -78.478993292999917, 21.037583726000037 ], [ -78.487904425999943, 21.038560289000088 ], [ -78.494740363999938, 21.047919012000079 ], [ -78.500884568999936, 21.082098700000074 ], [ -78.504383917999917, 21.14712148600006 ], [ -78.512277798999946, 21.175116278000075 ], [ -78.52757727799991, 21.203273830000057 ], [ -78.538197394999941, 21.231634833000044 ], [ -78.531727667999917, 21.26040273600006 ], [ -78.522572394999941, 21.25031159100007 ], [ -78.511463995999918, 21.248846747000073 ], [ -78.502105272999927, 21.255560614000046 ], [ -78.498199022999927, 21.269964911000045 ], [ -78.505523240999935, 21.280218817000048 ], [ -78.537993943999936, 21.290350653000075 ], [ -78.545399542999917, 21.29759349200009 ], [ -78.547474738999938, 21.31509023600006 ], [ -78.55687415299991, 21.347479559000078 ], [ -78.558990037999934, 21.366522528000075 ], [ -78.563303188999953, 21.38344961100006 ], [ -78.582102016999897, 21.413885809000078 ], [ -78.586333787999934, 21.428208726000037 ], [ -78.59243730399993, 21.461818752000056 ], [ -78.607818162999934, 21.493719794000071 ], [ -78.628163214999915, 21.521063544000071 ], [ -78.641632785454689, 21.533876702401543 ], [ -78.641499192633603, 21.53393138332666 ], [ -78.604886441356143, 21.548917548306179 ], [ -78.552744920941336, 21.579561671833687 ], [ -78.545794440361135, 21.585220242120442 ], [ -78.542461310940723, 21.589276841952653 ], [ -78.530756599437495, 21.599250392691431 ], [ -78.519516975028353, 21.605580756546658 ], [ -78.496831020635057, 21.615399278553866 ], [ -78.479700283741067, 21.620282700686062 ], [ -78.477168138198977, 21.619714259905152 ], [ -78.474971890340441, 21.618060615305126 ], [ -78.469855923312196, 21.61216950102164 ], [ -78.46802140976024, 21.609534002692044 ], [ -78.465980190633275, 21.607053533993394 ], [ -78.463448045990503, 21.605890814909174 ], [ -78.459365606837252, 21.605864976487453 ], [ -78.453887906401746, 21.61160106024073 ], [ -78.45083899602281, 21.615864366547271 ], [ -78.439392666038714, 21.645268255725398 ], [ -78.429496629665721, 21.669866238036434 ], [ -78.420608282746059, 21.674077867499591 ], [ -78.415156419832897, 21.67307017714694 ], [ -78.39187618713629, 21.671649074745005 ], [ -78.378440313969293, 21.669271958833804 ], [ -78.359707608419399, 21.669943753301538 ], [ -78.352421231054961, 21.671183986751544 ], [ -78.349708218359581, 21.67366445634957 ], [ -78.351620246277321, 21.6757573514206 ], [ -78.356167771625337, 21.678470364115981 ], [ -78.359371710735843, 21.683198757516607 ], [ -78.360844489081899, 21.690355942772499 ], [ -78.348803880794435, 21.707228298147413 ], [ -78.34392045776292, 21.712654324437494 ], [ -78.337641770751077, 21.722111111238803 ], [ -78.334308641330722, 21.724023139156543 ], [ -78.328985968727466, 21.724591579937453 ], [ -78.32655717597288, 21.726116034227573 ], [ -78.32485185363015, 21.729785061331484 ], [ -78.32407670817355, 21.735960395555821 ], [ -78.324412604058409, 21.743866888745913 ], [ -78.325316941623555, 21.749938870182689 ], [ -78.330510423017586, 21.765984402358242 ], [ -78.333766038971532, 21.784613756020008 ], [ -78.330510423017586, 21.790194810142339 ], [ -78.324438443379449, 21.798411363493585 ], [ -78.30940060065717, 21.812183132545499 ], [ -78.299065313813173, 21.818048407508002 ], [ -78.290745408573741, 21.820916448934952 ], [ -78.286430427222399, 21.820606391471756 ], [ -78.283639899261914, 21.819598700219842 ], [ -78.282012092184289, 21.817428289883651 ], [ -78.281030240253358, 21.81412099888496 ], [ -78.280952724988254, 21.808074855869904 ], [ -78.279531622586319, 21.803268948103437 ], [ -78.276586065894207, 21.798152981075191 ], [ -78.270488246935031, 21.79236522137785 ], [ -78.267155116615299, 21.786990871931152 ], [ -78.251910570116706, 21.767379666338513 ], [ -78.241549444850989, 21.762857978512898 ], [ -78.227777675799075, 21.762341212776732 ], [ -78.188865322976255, 21.767224635808304 ], [ -78.183206752689443, 21.769214178991149 ], [ -78.1835684878954, 21.772573146833224 ], [ -78.187754278936836, 21.792985338102881 ], [ -78.187625087727611, 21.796990261091651 ], [ -78.18607479501577, 21.799780789052136 ], [ -78.182974208692769, 21.802545477691638 ], [ -78.168582322915881, 21.809625149481064 ], [ -78.156076625735693, 21.818125921873786 ], [ -78.176152920221057, 21.849777737552529 ], [ -78.193180305226917, 21.866236680878103 ], [ -78.24216956157602, 21.904632269763397 ], [ -78.245838588679931, 21.908120428814698 ], [ -78.251910570116706, 21.925612900914643 ], [ -78.240360887345048, 21.954680894207911 ], [ -78.235115729107576, 21.957626450899966 ], [ -78.228165249426695, 21.960778713167088 ], [ -78.221369797578063, 21.961011257163761 ], [ -78.215401170727432, 21.961967271572291 ], [ -78.199148932976868, 21.966824856182143 ], [ -78.18359432631712, 21.967160752966379 ], [ -78.171295335611262, 21.969512031355123 ], [ -78.162691210430978, 21.973697822396559 ], [ -78.151580777231061, 21.981061713227461 ], [ -78.127422045391086, 22.004652004286527 ], [ -78.109619514029362, 22.018759670122677 ], [ -78.097966477570878, 22.024857489981173 ], [ -78.084556443724864, 22.029353339385068 ], [ -78.078897875236748, 22.033048204011379 ], [ -78.075254685655182, 22.03769908304622 ], [ -78.071585658551271, 22.048318589831013 ], [ -78.070655484363101, 22.05410635042773 ], [ -78.070862189038792, 22.059894111024391 ], [ -78.072825893799973, 22.065165106784207 ], [ -78.074996304136107, 22.068885809832238 ], [ -78.083497077428149, 22.0739242624947 ], [ -78.081820195245825, 22.082791411494441 ] ] ], [ [ [ -78.581695115999935, 20.661607164000088 ], [ -78.578480597999942, 20.65766022300005 ], [ -78.578277147999927, 20.648423570000091 ], [ -78.585682745999918, 20.643622137000079 ], [ -78.59398352799991, 20.64288971600007 ], [ -78.600982225999928, 20.64524974200009 ], [ -78.606312628999945, 20.650213934000078 ], [ -78.611724412999934, 20.653631903000075 ], [ -78.613392706999946, 20.657945054000038 ], [ -78.609038865999935, 20.660711981000077 ], [ -78.604074673999946, 20.658351955000057 ], [ -78.579945441999939, 20.653998114000046 ], [ -78.58071855399993, 20.657375393000052 ], [ -78.581288214999915, 20.659002997000073 ], [ -78.581695115999935, 20.661607164000088 ] ] ], [ [ [ -78.651519334999932, 20.664943752000056 ], [ -78.643625454999949, 20.663275458000044 ], [ -78.629750128999945, 20.65884023600006 ], [ -78.63117428299995, 20.653143622000073 ], [ -78.646473761999914, 20.652289130000042 ], [ -78.656158006999931, 20.65851471600007 ], [ -78.654693162999934, 20.663804429000038 ], [ -78.651519334999932, 20.664943752000056 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-08", "NAME_1": "Ciego de Ávila" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -78.826568162999934, 20.753241278000075 ], [ -78.807036912999934, 20.757228908000059 ], [ -78.785959438999953, 20.748968817000048 ], [ -78.750843878999945, 20.725978908000059 ], [ -78.768055792999917, 20.712225653000075 ], [ -78.792347785999937, 20.719916083000044 ], [ -78.814808722999942, 20.737453518000052 ], [ -78.826568162999934, 20.753241278000075 ] ] ], [ [ [ -78.925852016999897, 20.807847398000035 ], [ -78.876616990999935, 20.80923086100006 ], [ -78.858550584999932, 20.79954661700009 ], [ -78.847035285999937, 20.773138739000046 ], [ -78.854481574999909, 20.773138739000046 ], [ -78.871490037999934, 20.784857489000046 ], [ -78.94163977799991, 20.792629299000055 ], [ -78.964344855999911, 20.814113674000055 ], [ -78.952137824999909, 20.831366278000075 ], [ -78.942250128999945, 20.839585679000038 ], [ -78.932728644999941, 20.838934637000079 ], [ -78.928089972999942, 20.831122137000079 ], [ -78.926136847999942, 20.820746161000045 ], [ -78.925852016999897, 20.807847398000035 ] ] ], [ [ [ -79.025217251999948, 20.886664130000042 ], [ -79.013539191999939, 20.88226959800005 ], [ -78.989979620999918, 20.87962474200009 ], [ -78.971180792999917, 20.873521226000037 ], [ -78.973988410999937, 20.858791408000059 ], [ -78.98273678299995, 20.844631252000056 ], [ -78.988880988999938, 20.839056708000044 ], [ -78.991688605999911, 20.845445054000038 ], [ -78.995106574999909, 20.849188544000071 ], [ -79.018910285999937, 20.855047919000071 ], [ -79.069203253999945, 20.885972398000035 ], [ -79.079823370999918, 20.897284247000073 ], [ -79.06704667899993, 20.89915599200009 ], [ -79.048817511999914, 20.898016669000071 ], [ -79.032297329999949, 20.893744208000044 ], [ -79.025217251999948, 20.886664130000042 ] ] ], [ [ [ -79.073597785999937, 20.917710679000038 ], [ -79.078602667999917, 20.91828034100007 ], [ -79.09406490799995, 20.917710679000038 ], [ -79.091297980999911, 20.912095445000091 ], [ -79.087228969999899, 20.897284247000073 ], [ -79.115589972999942, 20.910834052000041 ], [ -79.134510870999918, 20.927069403000075 ], [ -79.169178839999915, 20.964911200000074 ], [ -79.169178839999915, 20.972357489000046 ], [ -79.151763475999928, 20.966050523000035 ], [ -79.13890540299991, 20.954657294000071 ], [ -79.127552863999938, 20.94171784100007 ], [ -79.114572719999899, 20.930812893000052 ], [ -79.127674933999913, 20.950873114000046 ], [ -79.149810350999928, 20.976792710000041 ], [ -79.175038214999915, 20.997015692000048 ], [ -79.197092251999948, 20.999701239000046 ], [ -79.197092251999948, 20.992254950000074 ], [ -79.193755662999934, 20.988714911000045 ], [ -79.192860480999911, 20.986761786000045 ], [ -79.192209438999953, 20.984279690000051 ], [ -79.189605272999927, 20.979193427000041 ], [ -79.200998501999948, 20.982407945000091 ], [ -79.210764126999948, 20.987779039000088 ], [ -79.218658006999931, 20.995510158000059 ], [ -79.224436001999948, 21.005845445000091 ], [ -79.182118292999917, 21.008002020000049 ], [ -79.137684699999909, 20.982652085000041 ], [ -79.098947719999899, 20.947007554000038 ], [ -79.073597785999937, 20.917710679000038 ] ] ], [ [ [ -79.38890540299991, 21.123236395000049 ], [ -79.357329881999931, 21.12759023600006 ], [ -79.331898566999939, 21.113185940000051 ], [ -79.292632615999935, 21.074774481000077 ], [ -79.308013475999928, 21.068793036000045 ], [ -79.324777798999946, 21.068304755000042 ], [ -79.340728318999936, 21.07290273600006 ], [ -79.354115363999938, 21.082220770000049 ], [ -79.347401495999918, 21.081691799000055 ], [ -79.32681230399993, 21.082220770000049 ], [ -79.331166144999941, 21.093003648000035 ], [ -79.33853105399993, 21.099839585000041 ], [ -79.346791144999941, 21.101263739000046 ], [ -79.354115363999938, 21.095892645000049 ], [ -79.380238410999937, 21.113836981000077 ], [ -79.38890540299991, 21.123236395000049 ] ] ], [ [ [ -78.426177537999934, 22.462591864000046 ], [ -78.445668097999942, 22.454575914000088 ], [ -78.472767706999946, 22.451157945000091 ], [ -78.518055792999917, 22.452093817000048 ], [ -78.540842251999948, 22.458482164000088 ], [ -78.568226691999939, 22.476304429000038 ], [ -78.609527147999927, 22.483465887000079 ], [ -78.638417120999918, 22.492010809000078 ], [ -78.655995245999918, 22.503119208000044 ], [ -78.641590949999909, 22.514146226000037 ], [ -78.656971808999913, 22.529974677000041 ], [ -78.677357550999943, 22.515692450000074 ], [ -78.69359290299991, 22.507513739000046 ], [ -78.696197068999936, 22.541449286000045 ], [ -78.692534959999932, 22.538723049000055 ], [ -78.683176235999952, 22.53461334800005 ], [ -78.679758266999897, 22.554429429000038 ], [ -78.670643683999913, 22.556545315000051 ], [ -78.660023566999939, 22.551906643000052 ], [ -78.652170376999948, 22.551703192000048 ], [ -78.64126542899993, 22.55337148600006 ], [ -78.596913214999915, 22.544867255000042 ], [ -78.57258053299995, 22.530462958000044 ], [ -78.544422980999911, 22.528387762000079 ], [ -78.515980597999942, 22.530462958000044 ], [ -78.490793423999946, 22.528469143000052 ], [ -78.466420050999943, 22.529852606000077 ], [ -78.450550910999937, 22.54173411700009 ], [ -78.436838344999899, 22.55540599200009 ], [ -78.419056769999941, 22.56195709800005 ], [ -78.396351691999939, 22.559800523000035 ], [ -78.372385219999899, 22.553534247000073 ], [ -78.352040167999917, 22.543036200000074 ], [ -78.340565558999913, 22.528469143000052 ], [ -78.344227667999917, 22.529852606000077 ], [ -78.353586391999897, 22.53461334800005 ], [ -78.349110480999911, 22.521144924000055 ], [ -78.282215949999909, 22.457464911000045 ], [ -78.278472459999932, 22.44867584800005 ], [ -78.28148352799991, 22.438788153000075 ], [ -78.288685675999943, 22.43891022300005 ], [ -78.297678188999953, 22.443101304000038 ], [ -78.305775519999941, 22.445257880000042 ], [ -78.42992102799991, 22.41860586100006 ], [ -78.42992102799991, 22.424750067000048 ], [ -78.427805141999897, 22.427801825000074 ], [ -78.425282355999911, 22.43032461100006 ], [ -78.423329230999911, 22.434393622000073 ], [ -78.422474738999938, 22.44212474200009 ], [ -78.419545050999943, 22.445868231000077 ], [ -78.412953253999945, 22.445379950000074 ], [ -78.406076626999948, 22.444037177000041 ], [ -78.401966925999943, 22.445257880000042 ], [ -78.401112433999913, 22.454657294000071 ], [ -78.40461178299995, 22.46430084800005 ], [ -78.412831183999913, 22.468817450000074 ], [ -78.426177537999934, 22.462591864000046 ] ] ], [ [ [ -78.927194791406464, 22.39874909099774 ], [ -78.828684048999946, 22.388332424000055 ], [ -78.781849738999938, 22.390611070000091 ], [ -78.776722785999937, 22.380560614000046 ], [ -78.757639126999948, 22.322333075000074 ], [ -78.754017706999946, 22.32485586100006 ], [ -78.744618292999917, 22.329169012000079 ], [ -78.73460852799991, 22.316229559000078 ], [ -78.725331183999913, 22.324204820000091 ], [ -78.709868943999936, 22.355902411000045 ], [ -78.722645636999914, 22.372707424000055 ], [ -78.729481574999909, 22.379136460000041 ], [ -78.737782355999911, 22.383775132000039 ], [ -78.737782355999911, 22.390611070000091 ], [ -78.708078579999949, 22.386908270000049 ], [ -78.676136847999942, 22.357001044000071 ], [ -78.566883917999917, 22.32103099200009 ], [ -78.552845831999946, 22.311835028000075 ], [ -78.544300910999937, 22.299058335000041 ], [ -78.524403449999909, 22.283270575000074 ], [ -78.501454230999911, 22.268866278000075 ], [ -78.483957485999952, 22.260321356000077 ], [ -78.460072394999941, 22.253607489000046 ], [ -78.399891730999911, 22.244045315000051 ], [ -78.38149980399993, 22.246649481000077 ], [ -78.381947394999941, 22.239935614000046 ], [ -78.380970831999946, 22.22601959800005 ], [ -78.38149980399993, 22.219305731000077 ], [ -78.371205206999946, 22.224025783000059 ], [ -78.367258266999897, 22.226752020000049 ], [ -78.360503709999932, 22.216782945000091 ], [ -78.351144985999952, 22.197658596000053 ], [ -78.343902147999927, 22.18891022300005 ], [ -78.334868943999936, 22.182562567000048 ], [ -78.316965298999946, 22.173895575000074 ], [ -78.309193488999938, 22.167792059000078 ], [ -78.30142167899993, 22.163804429000038 ], [ -78.291574673999946, 22.163641669000071 ], [ -78.281117316999939, 22.164618231000077 ], [ -78.271636522999927, 22.164048570000091 ], [ -78.237456834999932, 22.151068427000041 ], [ -78.221913214999915, 22.147040106000077 ], [ -78.172352667999917, 22.143622137000079 ], [ -78.163644985999952, 22.139349677000041 ], [ -78.161691860999952, 22.129461981000077 ], [ -78.160878058999913, 22.118109442000048 ], [ -78.155588344999899, 22.109523830000057 ], [ -78.147328253999945, 22.107570705000057 ], [ -78.121693488999938, 22.107855536000045 ], [ -78.124989386999914, 22.106350002000056 ], [ -78.128285285999937, 22.102606512000079 ], [ -78.117787238999938, 22.093451239000046 ], [ -78.105376756999931, 22.089016018000052 ], [ -78.09243730399993, 22.08624909100007 ], [ -78.081820195245825, 22.082791411494441 ], [ -78.083497077428149, 22.0739242624947 ], [ -78.074996304136107, 22.068885809832238 ], [ -78.072825893799973, 22.065165106784207 ], [ -78.070862189038792, 22.059894111024391 ], [ -78.070655484363101, 22.05410635042773 ], [ -78.071585658551271, 22.048318589831013 ], [ -78.075254685655182, 22.03769908304622 ], [ -78.078897875236748, 22.033048204011379 ], [ -78.084556443724864, 22.029353339385068 ], [ -78.097966477570878, 22.024857489981173 ], [ -78.109619514029362, 22.018759670122677 ], [ -78.127422045391086, 22.004652004286527 ], [ -78.151580777231061, 21.981061713227461 ], [ -78.162691210430978, 21.973697822396559 ], [ -78.171295335611262, 21.969512031355123 ], [ -78.18359432631712, 21.967160752966379 ], [ -78.199148932976868, 21.966824856182143 ], [ -78.215401170727432, 21.961967271572291 ], [ -78.221369797578063, 21.961011257163761 ], [ -78.228165249426695, 21.960778713167088 ], [ -78.235115729107576, 21.957626450899966 ], [ -78.240360887345048, 21.954680894207911 ], [ -78.251910570116706, 21.925612900914643 ], [ -78.245838588679931, 21.908120428814698 ], [ -78.24216956157602, 21.904632269763397 ], [ -78.193180305226917, 21.866236680878103 ], [ -78.176152920221057, 21.849777737552529 ], [ -78.156076625735693, 21.818125921873786 ], [ -78.168582322915881, 21.809625149481064 ], [ -78.182974208692769, 21.802545477691638 ], [ -78.18607479501577, 21.799780789052136 ], [ -78.187625087727611, 21.796990261091651 ], [ -78.187754278936836, 21.792985338102881 ], [ -78.1835684878954, 21.772573146833224 ], [ -78.183206752689443, 21.769214178991149 ], [ -78.188865322976255, 21.767224635808304 ], [ -78.227777675799075, 21.762341212776732 ], [ -78.241549444850989, 21.762857978512898 ], [ -78.251910570116706, 21.767379666338513 ], [ -78.267155116615299, 21.786990871931152 ], [ -78.270488246935031, 21.79236522137785 ], [ -78.276586065894207, 21.798152981075191 ], [ -78.279531622586319, 21.803268948103437 ], [ -78.280952724988254, 21.808074855869904 ], [ -78.281030240253358, 21.81412099888496 ], [ -78.282012092184289, 21.817428289883651 ], [ -78.283639899261914, 21.819598700219842 ], [ -78.286430427222399, 21.820606391471756 ], [ -78.290745408573741, 21.820916448934952 ], [ -78.299065313813173, 21.818048407508002 ], [ -78.30940060065717, 21.812183132545499 ], [ -78.324438443379449, 21.798411363493585 ], [ -78.330510423017586, 21.790194810142339 ], [ -78.333766038971532, 21.784613756020008 ], [ -78.330510423017586, 21.765984402358242 ], [ -78.325316941623555, 21.749938870182689 ], [ -78.324412604058409, 21.743866888745913 ], [ -78.32407670817355, 21.735960395555821 ], [ -78.32485185363015, 21.729785061331484 ], [ -78.32655717597288, 21.726116034227573 ], [ -78.328985968727466, 21.724591579937453 ], [ -78.334308641330722, 21.724023139156543 ], [ -78.337641770751077, 21.722111111238803 ], [ -78.34392045776292, 21.712654324437494 ], [ -78.348803880794435, 21.707228298147413 ], [ -78.360844489081899, 21.690355942772499 ], [ -78.359371710735843, 21.683198757516607 ], [ -78.356167771625337, 21.678470364115981 ], [ -78.351620246277321, 21.6757573514206 ], [ -78.349708218359581, 21.67366445634957 ], [ -78.352421231054961, 21.671183986751544 ], [ -78.359707608419399, 21.669943753301538 ], [ -78.378440313969293, 21.669271958833804 ], [ -78.39187618713629, 21.671649074745005 ], [ -78.415156419832897, 21.67307017714694 ], [ -78.420608282746059, 21.674077867499591 ], [ -78.429496629665721, 21.669866238036434 ], [ -78.439392666038714, 21.645268255725398 ], [ -78.45083899602281, 21.615864366547271 ], [ -78.453887906401746, 21.61160106024073 ], [ -78.459365606837252, 21.605864976487453 ], [ -78.463448045990503, 21.605890814909174 ], [ -78.465980190633275, 21.607053533993394 ], [ -78.46802140976024, 21.609534002692044 ], [ -78.469855923312196, 21.61216950102164 ], [ -78.474971890340441, 21.618060615305126 ], [ -78.477168138198977, 21.619714259905152 ], [ -78.479700283741067, 21.620282700686062 ], [ -78.496831020635057, 21.615399278553866 ], [ -78.519516975028353, 21.605580756546658 ], [ -78.530756599437495, 21.599250392691431 ], [ -78.542461310940723, 21.589276841952653 ], [ -78.545794440361135, 21.585220242120442 ], [ -78.552744920941336, 21.579561671833687 ], [ -78.604886441356143, 21.548917548306179 ], [ -78.641499192633603, 21.53393138332666 ], [ -78.641632785454689, 21.533876702401543 ], [ -78.649037238999938, 21.540920315000051 ], [ -78.665353969999899, 21.551174221000053 ], [ -78.680978969999899, 21.556626695000091 ], [ -78.733998175999943, 21.564357815000051 ], [ -78.74632727799991, 21.568060614000046 ], [ -78.751088019999941, 21.575506903000075 ], [ -78.744618292999917, 21.58930084800005 ], [ -78.733306443999936, 21.583238023000035 ], [ -78.720611131999931, 21.581244208000044 ], [ -78.693104620999918, 21.581854559000078 ], [ -78.689116990999935, 21.586411851000037 ], [ -78.694203253999945, 21.596665757000039 ], [ -78.706776495999918, 21.612616278000075 ], [ -78.713693813999953, 21.61859772300005 ], [ -78.723947719999899, 21.625555731000077 ], [ -78.744618292999917, 21.636542059000078 ], [ -78.759266730999911, 21.640611070000091 ], [ -78.766509568999936, 21.639715887000079 ], [ -78.773060675999943, 21.635646877000056 ], [ -78.785552537999934, 21.63031647300005 ], [ -78.831898566999939, 21.620306708000044 ], [ -78.878407355999911, 21.616034247000073 ], [ -78.883371548999946, 21.614203192000048 ], [ -78.889027472999942, 21.60968659100007 ], [ -78.893544074999909, 21.604193427000041 ], [ -78.895415818999936, 21.599269924000055 ], [ -78.89875240799995, 21.595526434000078 ], [ -78.90648352799991, 21.594671942000048 ], [ -78.937082485999952, 21.596380927000041 ], [ -78.949208136999914, 21.598781643000052 ], [ -78.959950325247291, 21.599554754748112 ], [ -78.964848980096349, 21.620314369412597 ], [ -78.967760748359808, 21.650887929434361 ], [ -78.964848980096349, 21.677093838409917 ], [ -78.970672515724004, 21.690196792447978 ], [ -78.992510772753917, 21.704755630168165 ], [ -79.017260798047403, 21.714946816842087 ], [ -79.03181963576759, 21.694564443494244 ], [ -79.03181963576759, 21.678549721192667 ], [ -79.043466707022901, 21.665446767154549 ], [ -79.072584383362596, 21.653799696798558 ], [ -79.100246175120844, 21.653799696798558 ], [ -79.108981478112696, 21.665446767154549 ], [ -79.10315794338436, 21.682917373138253 ], [ -79.098790291438775, 21.710579164896501 ], [ -79.106069710748557, 21.726593887198135 ], [ -79.122084433050134, 21.749888027910117 ], [ -79.114805012841032, 21.765902750211751 ], [ -79.092966755811119, 21.809579265170953 ], [ -79.082775570036517, 21.848888128184569 ], [ -79.072584383362596, 21.870726385214482 ], [ -79.058025544743089, 21.89693229418998 ], [ -79.046378474387097, 21.91877055121995 ], [ -79.040554938759385, 21.939152924567793 ], [ -79.028907868403394, 21.946432342978255 ], [ -79.012893146101817, 21.944976460195448 ], [ -78.998334308381629, 21.942064691931989 ], [ -78.992510772753917, 21.95371176228798 ], [ -78.97504016677027, 21.978461787581409 ], [ -78.960481329050083, 22.003211811975518 ], [ -78.960481329050083, 22.026505952687558 ], [ -78.964848980096349, 22.043976559570524 ], [ -78.977951935033786, 22.049800094298917 ], [ -78.999790192063699, 22.059991280972838 ], [ -79.030363752085464, 22.08328542258414 ], [ -79.046378474387097, 22.096388375722938 ], [ -79.047834358069167, 22.116770749970101 ], [ -79.03327552034898, 22.148800194573312 ], [ -79.034731404031049, 22.17646198633156 ], [ -79.021628449093612, 22.188109056687608 ], [ -79.012893146101817, 22.211403198298967 ], [ -78.999790192063699, 22.23324145532888 ], [ -78.985231354343512, 22.256535596040919 ], [ -78.97504016677027, 22.275462085706693 ], [ -78.966304863778419, 22.307491530309846 ], [ -78.956113678003817, 22.32787390275837 ], [ -78.950290142376161, 22.339520973114418 ], [ -78.94155483938431, 22.346800393323463 ], [ -78.934275420074584, 22.354079811733925 ], [ -78.931363652710388, 22.384653371755689 ], [ -78.927194791406464, 22.39874909099774 ] ] ], [ [ [ -78.737660285999937, 22.548407294000071 ], [ -78.735422329999949, 22.551255601000037 ], [ -78.728260870999918, 22.547919012000079 ], [ -78.72883053299995, 22.54165273600006 ], [ -78.736195441999939, 22.530585028000075 ], [ -78.738758917999917, 22.524318752000056 ], [ -78.756988084999932, 22.518540757000039 ], [ -78.765980597999942, 22.518784898000035 ], [ -78.76789303299995, 22.525213934000078 ], [ -78.768137173999946, 22.54165273600006 ], [ -78.762196417999917, 22.543524481000077 ], [ -78.74828040299991, 22.53978099200009 ], [ -78.738880988999938, 22.541001695000091 ], [ -78.737660285999937, 22.548407294000071 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-11", "NAME_1": "Holguín" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -75.517079230999911, 20.794256903000075 ], [ -75.508168097999942, 20.78656647300005 ], [ -75.493763800999943, 20.761053778000075 ], [ -75.485707160999937, 20.749823309000078 ], [ -75.482167120999918, 20.737779039000088 ], [ -75.500843878999945, 20.737941799000055 ], [ -75.534087693999936, 20.74640534100007 ], [ -75.551828579999949, 20.749009507000039 ], [ -75.567534959999932, 20.756781317000048 ], [ -75.577748175999943, 20.769517320000091 ], [ -75.578480597999942, 20.78742096600007 ], [ -75.529164191999939, 20.795803127000056 ], [ -75.517079230999911, 20.794256903000075 ] ] ], [ [ [ -76.313547330045253, 21.251898504712187 ], [ -76.290272589999915, 21.233710028000075 ], [ -76.275868292999917, 21.225043036000045 ], [ -76.169667120999918, 21.187160549000055 ], [ -76.137806769999941, 21.167222398000035 ], [ -76.133412238999938, 21.143703518000052 ], [ -76.129994269999941, 21.135565497000073 ], [ -76.130726691999939, 21.114162502000056 ], [ -76.126576300999943, 21.102118231000077 ], [ -76.116769985999952, 21.091498114000046 ], [ -76.109852667999917, 21.092230536000045 ], [ -76.09984290299991, 21.102118231000077 ], [ -76.083811001999948, 21.110541083000044 ], [ -76.072661912999934, 21.112982489000046 ], [ -76.058257615999935, 21.109564520000049 ], [ -76.048085089999915, 21.10382721600007 ], [ -76.041005011999914, 21.096665757000039 ], [ -76.037220831999946, 21.08734772300005 ], [ -76.037180141999897, 21.074774481000077 ], [ -76.030913865999935, 21.074774481000077 ], [ -76.028920050999943, 21.079575914000088 ], [ -76.025746222999942, 21.084540106000077 ], [ -76.023548956999946, 21.089056708000044 ], [ -76.016713019999941, 21.07367584800005 ], [ -76.008168097999942, 21.070298570000091 ], [ -76.00218665299991, 21.078070380000042 ], [ -76.003041144999941, 21.095892645000049 ], [ -75.994618292999917, 21.094549872000073 ], [ -75.967884894999941, 21.093980210000041 ], [ -75.95531165299991, 21.095892645000049 ], [ -75.949045376999948, 21.099798895000049 ], [ -75.933461066999939, 21.112941799000055 ], [ -75.924875454999949, 21.115708726000037 ], [ -75.91242428299995, 21.115179755000042 ], [ -75.899891730999911, 21.112779039000088 ], [ -75.890248175999943, 21.10773346600007 ], [ -75.881947394999941, 21.090277411000045 ], [ -75.873524542999917, 21.088771877000056 ], [ -75.868275519999941, 21.093085028000075 ], [ -75.87336178299995, 21.102118231000077 ], [ -75.821766730999911, 21.136867580000057 ], [ -75.816273566999939, 21.135646877000056 ], [ -75.801258917999917, 21.129299221000053 ], [ -75.798207160999937, 21.126613674000055 ], [ -75.794016079999949, 21.119045315000051 ], [ -75.784291144999941, 21.118638414000088 ], [ -75.766835089999915, 21.123236395000049 ], [ -75.732289191999939, 21.123277085000041 ], [ -75.704009568999936, 21.118963934000078 ], [ -75.684315558999913, 21.103094794000071 ], [ -75.675363735999952, 21.068589585000041 ], [ -75.635894334999932, 21.076361395000049 ], [ -75.613148566999939, 21.062567450000074 ], [ -75.578480597999942, 21.013373114000046 ], [ -75.598947719999899, 20.972357489000046 ], [ -75.604847785999937, 20.965399481000077 ], [ -75.616037563999953, 20.956732489000046 ], [ -75.620106574999909, 20.951239325000074 ], [ -75.621937628999945, 20.944810289000088 ], [ -75.624175584999932, 20.929877020000049 ], [ -75.626332160999937, 20.923976955000057 ], [ -75.634877081999946, 20.912543036000045 ], [ -75.64875240799995, 20.899400132000039 ], [ -75.665150519999941, 20.89008209800005 ], [ -75.681548631999931, 20.890448309000078 ], [ -75.686512824999909, 20.900051174000055 ], [ -75.690256313999953, 20.915187893000052 ], [ -75.696400519999941, 20.924872137000079 ], [ -75.708851691999939, 20.917710679000038 ], [ -75.71703040299991, 20.922552802000041 ], [ -75.723622199999909, 20.923407294000071 ], [ -75.729481574999909, 20.921454169000071 ], [ -75.735503709999932, 20.917710679000038 ], [ -75.727365688999953, 20.916571356000077 ], [ -75.721424933999913, 20.914455471000053 ], [ -75.717518683999913, 20.910345770000049 ], [ -75.715687628999945, 20.903509833000044 ], [ -75.744007941999939, 20.901556708000044 ], [ -75.743397589999915, 20.889349677000041 ], [ -75.730458136999914, 20.872219143000052 ], [ -75.721831834999932, 20.855047919000071 ], [ -75.715687628999945, 20.855047919000071 ], [ -75.704497850999928, 20.870835679000038 ], [ -75.678130662999934, 20.878241278000075 ], [ -75.648182745999918, 20.87954336100006 ], [ -75.626332160999937, 20.876776434000078 ], [ -75.584868943999936, 20.856838283000059 ], [ -75.578480597999942, 20.851955471000053 ], [ -75.577381964999915, 20.838080145000049 ], [ -75.573312954999949, 20.827541408000059 ], [ -75.564930792999917, 20.821478583000044 ], [ -75.551136847999942, 20.821519273000035 ], [ -75.559071417999917, 20.797674872000073 ], [ -75.573150193999936, 20.797674872000073 ], [ -75.589100714999915, 20.807684637000079 ], [ -75.602691209999932, 20.814113674000055 ], [ -75.610178188999953, 20.816555080000057 ], [ -75.613433397999927, 20.822495835000041 ], [ -75.615712042999917, 20.829657294000071 ], [ -75.620106574999909, 20.835842190000051 ], [ -75.627430792999917, 20.841457424000055 ], [ -75.630604620999918, 20.843085028000075 ], [ -75.685373501999948, 20.835109768000052 ], [ -75.704741990999935, 20.828680731000077 ], [ -75.770253058999913, 20.835842190000051 ], [ -75.765004035999937, 20.824408270000049 ], [ -75.766346808999913, 20.811590887000079 ], [ -75.776478644999941, 20.78742096600007 ], [ -75.77570553299995, 20.781317450000074 ], [ -75.776600714999915, 20.768703518000052 ], [ -75.779367641999897, 20.756903387000079 ], [ -75.783924933999913, 20.74640534100007 ], [ -75.774647589999915, 20.737616278000075 ], [ -75.763050910999937, 20.716009833000044 ], [ -75.724517381999931, 20.695502020000049 ], [ -75.708851691999939, 20.690578518000052 ], [ -75.702015753999945, 20.701117255000042 ], [ -75.691029425999943, 20.722886460000041 ], [ -75.643177863999938, 20.760728257000039 ], [ -75.63312740799995, 20.780585028000075 ], [ -75.617298956999946, 20.768622137000079 ], [ -75.60773678299995, 20.753159898000035 ], [ -75.60570227799991, 20.735988674000055 ], [ -75.612619594999899, 20.718491929000038 ], [ -75.586822068999936, 20.721502997000073 ], [ -75.577504035999937, 20.718451239000046 ], [ -75.581898566999939, 20.707953192000048 ], [ -75.583566860999952, 20.698228257000039 ], [ -75.573312954999949, 20.691392320000091 ], [ -75.551136847999942, 20.684393622000073 ], [ -75.556711391999897, 20.706447658000059 ], [ -75.497792120999918, 20.693426825000074 ], [ -75.482248501999948, 20.71165599200009 ], [ -75.476063605999911, 20.71165599200009 ], [ -75.471262173999946, 20.706122137000079 ], [ -75.464711066999939, 20.70062897300005 ], [ -75.456857876999948, 20.695502020000049 ], [ -75.448109503999945, 20.691148179000038 ], [ -75.440663214999915, 20.71165599200009 ], [ -75.457183397999927, 20.717962958000044 ], [ -75.465931769999941, 20.719224351000037 ], [ -75.476063605999911, 20.718491929000038 ], [ -75.463612433999913, 20.734076239000046 ], [ -75.43968665299991, 20.740627346000053 ], [ -75.413563605999911, 20.741156317000048 ], [ -75.394154425999943, 20.738959052000041 ], [ -75.376576300999943, 20.732163804000038 ], [ -75.356027798999946, 20.719916083000044 ], [ -75.349232550999943, 20.708482164000088 ], [ -75.373036261999914, 20.704250393000052 ], [ -75.364328579999949, 20.691392320000091 ], [ -75.359364386999914, 20.677557684000078 ], [ -75.352609829999949, 20.677557684000078 ], [ -75.351389126999948, 20.681870835000041 ], [ -75.345773891999897, 20.691148179000038 ], [ -75.337228969999899, 20.669663804000038 ], [ -75.31281490799995, 20.664740302000041 ], [ -75.256337042999917, 20.670721747000073 ], [ -75.27375240799995, 20.681586005000042 ], [ -75.311594204999949, 20.699448960000041 ], [ -75.331410285999937, 20.704250393000052 ], [ -75.318714972999942, 20.71710846600007 ], [ -75.294300910999937, 20.723130601000037 ], [ -75.267974412999934, 20.723334052000041 ], [ -75.249501105999911, 20.718491929000038 ], [ -75.256337042999917, 20.725978908000059 ], [ -75.241037563999953, 20.724798895000049 ], [ -75.194325324999909, 20.715643622000073 ], [ -75.18195553299995, 20.709133205000057 ], [ -75.178578253999945, 20.702215887000079 ], [ -75.194894985999952, 20.69798411700009 ], [ -75.194894985999952, 20.691148179000038 ], [ -75.166981574999909, 20.684393622000073 ], [ -75.165150519999941, 20.686428127000056 ], [ -75.164865688999953, 20.68781159100007 ], [ -75.163970506999931, 20.689195054000038 ], [ -75.160755988999938, 20.691148179000038 ], [ -75.14907792899993, 20.683091539000088 ], [ -75.131825324999909, 20.687404690000051 ], [ -75.115345831999946, 20.686590887000079 ], [ -75.10610917899993, 20.663275458000044 ], [ -75.104115363999938, 20.66860586100006 ], [ -75.099598761999914, 20.677679755000042 ], [ -75.098703579999949, 20.684393622000073 ], [ -75.089426235999952, 20.677679755000042 ], [ -75.08039303299995, 20.673651434000078 ], [ -75.071929490999935, 20.673244533000059 ], [ -75.064564581999946, 20.677557684000078 ], [ -75.07876542899993, 20.691148179000038 ], [ -74.99836178299995, 20.700751044000071 ], [ -74.978871222999942, 20.694566148000035 ], [ -74.969227667999917, 20.689520575000074 ], [ -74.959095831999946, 20.687323309000078 ], [ -74.951079881999931, 20.683579820000091 ], [ -74.947865363999938, 20.67413971600007 ], [ -74.940744594999899, 20.668402411000045 ], [ -74.924672003999945, 20.668036200000074 ], [ -74.900054490999935, 20.670721747000073 ], [ -74.883534308999913, 20.659491278000075 ], [ -74.869292772999927, 20.64594147300005 ], [ -74.850900844999899, 20.634588934000078 ], [ -74.771839972999942, 20.625799872000073 ], [ -74.751210089999915, 20.619574286000045 ], [ -74.735585089999915, 20.609279690000051 ], [ -74.745716925999943, 20.603949286000045 ], [ -74.749867316999939, 20.602443752000056 ], [ -74.735585089999915, 20.578558661000045 ], [ -74.734934048999946, 20.567613023000035 ], [ -74.732574022999927, 20.564846096000053 ], [ -74.728382941999939, 20.564439195000091 ], [ -74.721913214999915, 20.56085846600007 ], [ -74.715167585115921, 20.556063378921806 ], [ -74.727758754762704, 20.549857082838059 ], [ -74.737603116090895, 20.542544867051959 ], [ -74.740936244611987, 20.540658678455202 ], [ -74.744010993412587, 20.539986883987467 ], [ -74.751891649080335, 20.540167752040134 ], [ -74.75599992485661, 20.539728502468392 ], [ -74.759591436695416, 20.538074856069727 ], [ -74.767187873321689, 20.531796169957261 ], [ -74.772510545924945, 20.5260084093606 ], [ -74.779641892759116, 20.516164048931671 ], [ -74.784706183843298, 20.506681422809379 ], [ -74.790287237965629, 20.491023464261445 ], [ -74.791604986680795, 20.471567288299696 ], [ -74.783155891131457, 20.444773058130124 ], [ -74.823618536666118, 20.42924428989204 ], [ -74.826409063727283, 20.427280585130859 ], [ -74.829147914844384, 20.42443838122631 ], [ -74.830594854768719, 20.421415310168413 ], [ -74.83214514837988, 20.417384547858603 ], [ -74.833230353098315, 20.411674303426366 ], [ -74.834703132343691, 20.40847036431586 ], [ -74.838708055332461, 20.406765041973074 ], [ -74.844986742344247, 20.408186143475746 ], [ -74.858396776190261, 20.413999742494127 ], [ -74.868602870925713, 20.421079413384177 ], [ -74.879635789759902, 20.4273322619743 ], [ -74.91617102667152, 20.443403632571574 ], [ -74.949838223055565, 20.466347968483944 ], [ -74.959527553853491, 20.471231391515516 ], [ -74.968777635079789, 20.472058213815501 ], [ -74.99577857082437, 20.468311672345806 ], [ -75.001204597114452, 20.466735541212245 ], [ -75.003400844972987, 20.464823513294505 ], [ -74.999447597928281, 20.456994534470198 ], [ -74.998336554788182, 20.454074815300487 ], [ -74.998104010791451, 20.451490993814275 ], [ -75.000196905862481, 20.444437161345888 ], [ -75.000713670699326, 20.441284898179504 ], [ -75.000506965124316, 20.439734605467663 ], [ -74.999344245140776, 20.439372870261764 ], [ -74.991411912629644, 20.438571886383443 ], [ -74.985494960823758, 20.433921007348602 ], [ -74.981774257775783, 20.429554348254555 ], [ -74.979242113133012, 20.425136013216445 ], [ -74.978001878783687, 20.422242133367718 ], [ -74.97725256995011, 20.419477443828953 ], [ -74.977304246793551, 20.416686916767787 ], [ -74.978234421881041, 20.41304372808554 ], [ -74.982239345769187, 20.412036037732946 ], [ -74.988776415199368, 20.413224596138207 ], [ -75.015854865309791, 20.43115631780978 ], [ -75.048255988023413, 20.433714300874271 ], [ -75.070476854423305, 20.45081920024586 ], [ -75.098847214827117, 20.479292914336497 ], [ -75.104970873107277, 20.484176337368069 ], [ -75.110474412863823, 20.484744778148979 ], [ -75.116882290185515, 20.483220322959539 ], [ -75.139878302941327, 20.475003770507612 ], [ -75.158352626972146, 20.465572822128024 ], [ -75.164605475562212, 20.464668484562878 ], [ -75.169488897694464, 20.465650336493809 ], [ -75.177834642254936, 20.472290757812232 ], [ -75.183028123648967, 20.473298448164826 ], [ -75.189694383389053, 20.471696479508921 ], [ -75.212354499360629, 20.459216619851134 ], [ -75.225764533206643, 20.447692776400515 ], [ -75.228296677849414, 20.442111721378808 ], [ -75.231397264172415, 20.412036037732946 ], [ -75.240492315767767, 20.396791490334977 ], [ -75.255065069597265, 20.407152614701374 ], [ -75.25653784884264, 20.41017568575927 ], [ -75.260181036625511, 20.412578640092136 ], [ -75.263901739673543, 20.412191067363835 ], [ -75.282221034972792, 20.403741970015915 ], [ -75.286742722798408, 20.403302721343493 ], [ -75.291109381892454, 20.404930528421119 ], [ -75.299971890390395, 20.41017568575927 ], [ -75.306663987652882, 20.415911770411867 ], [ -75.307981737267369, 20.417617091855277 ], [ -75.311495733841014, 20.423120632511143 ], [ -75.316973436075216, 20.428159085173604 ], [ -75.326481899719909, 20.434256904132781 ], [ -75.330719366705409, 20.437977607180812 ], [ -75.337230597713926, 20.439889635098552 ], [ -75.344801195019102, 20.438597723905843 ], [ -75.364076503827562, 20.425756129941419 ], [ -75.375471157867651, 20.422862250092749 ], [ -75.401464403259581, 20.456116034427453 ], [ -75.417096524285171, 20.468905951548436 ], [ -75.423504400707486, 20.476812446537167 ], [ -75.424589606325242, 20.480429795898374 ], [ -75.420403815283862, 20.482729397443734 ], [ -75.416760626601615, 20.485571601348283 ], [ -75.414305996324686, 20.489111436343705 ], [ -75.412729865191125, 20.492418728241717 ], [ -75.411748013260194, 20.495777696083792 ], [ -75.409680955711508, 20.499420884765982 ], [ -75.407200487012858, 20.502263087771269 ], [ -75.403479783964826, 20.504330146219274 ], [ -75.396736008959635, 20.506965644548814 ], [ -75.395004849094505, 20.508386746051485 ], [ -75.393402880438543, 20.513115139452111 ], [ -75.390147263585334, 20.537635606498043 ], [ -75.390689866843843, 20.54432770376053 ], [ -75.392705248448465, 20.547505805348635 ], [ -75.401929491252986, 20.543242499042094 ], [ -75.406993781437848, 20.541640530386132 ], [ -75.411076218792459, 20.540865383130892 ], [ -75.423426887241021, 20.540762031242707 ], [ -75.467222663095413, 20.532984727463202 ], [ -75.485800339913737, 20.538488267219748 ], [ -75.501794196145227, 20.550528876406531 ], [ -75.507401088689278, 20.551846625121641 ], [ -75.511638556574098, 20.55086477319071 ], [ -75.515023362837894, 20.54815176049533 ], [ -75.518744065885926, 20.546136378890765 ], [ -75.524816047322702, 20.544250190294008 ], [ -75.528562587893077, 20.542467352686174 ], [ -75.53174068858192, 20.540245266405918 ], [ -75.535538906894999, 20.535749417001966 ], [ -75.55543433332781, 20.516422431350122 ], [ -75.570498012673113, 20.505182806940979 ], [ -75.57793941876912, 20.500712795059428 ], [ -75.582590297803961, 20.499550075975208 ], [ -75.5953543774026, 20.506035468562004 ], [ -75.601788093145956, 20.50828339326398 ], [ -75.609203660820299, 20.511771552315281 ], [ -75.611425747100554, 20.510634669854142 ], [ -75.61421627506104, 20.50712067328044 ], [ -75.61555986219787, 20.503115750291613 ], [ -75.61576656777288, 20.500015163968612 ], [ -75.614836391786014, 20.496888739223891 ], [ -75.609565396026198, 20.485985012498304 ], [ -75.612510951818933, 20.477019151212858 ], [ -75.61555986219787, 20.469836127535245 ], [ -75.658813035693015, 20.441491603754514 ], [ -75.701342739675681, 20.437874254393307 ], [ -75.73314958408605, 20.442060045434744 ], [ -75.744337530752432, 20.441052354182773 ], [ -75.752399055372109, 20.439036974376847 ], [ -75.824668545317081, 20.407617702694779 ], [ -75.85626868415244, 20.410098171393486 ], [ -75.873011848318129, 20.418314723845413 ], [ -75.876655036100999, 20.421725369430249 ], [ -75.87805030008127, 20.424360866860525 ], [ -75.879445563162221, 20.427797349967705 ], [ -75.883553839837816, 20.443972073352484 ], [ -75.900141975271936, 20.448080349128816 ], [ -75.929752570025073, 20.467071437996424 ], [ -75.937193977020399, 20.472936712958926 ], [ -75.940578783284195, 20.477122504000363 ], [ -75.939364387356591, 20.479215399970712 ], [ -75.936806403392779, 20.482160955763504 ], [ -75.934222581906624, 20.48629507086082 ], [ -75.931716274786254, 20.491023464261445 ], [ -75.930786098799388, 20.497844752733158 ], [ -75.933292405919758, 20.500454413540353 ], [ -75.940139532813191, 20.501642971046238 ], [ -75.952438524418369, 20.501462103892948 ], [ -75.969827643730753, 20.502960719761404 ], [ -75.977243212304415, 20.505828762087674 ], [ -75.980498827358986, 20.509704494766595 ], [ -75.976183845108324, 20.520143134398097 ], [ -75.985614794387232, 20.534767564171716 ], [ -76.033027919602773, 20.567866318875474 ], [ -76.046670498344781, 20.573602403528071 ], [ -76.049202643886872, 20.57241384512281 ], [ -76.051398891745464, 20.56608348216696 ], [ -76.048970099890198, 20.557505195408453 ], [ -76.041864589679051, 20.541433823911802 ], [ -76.04106360490141, 20.534690049805931 ], [ -76.043440720812612, 20.529574082777685 ], [ -76.061346604961841, 20.522675279040868 ], [ -76.066307543258517, 20.519755560770477 ], [ -76.079019945114339, 20.509161892407406 ], [ -76.094548713352424, 20.499395046344318 ], [ -76.096925829263569, 20.495984402558122 ], [ -76.09640906442678, 20.493374741750927 ], [ -76.092869229431358, 20.492031155513416 ], [ -76.090285407045883, 20.488853053925254 ], [ -76.088347540706422, 20.479499619911508 ], [ -76.08173295780972, 20.464435940566204 ], [ -76.084368456139316, 20.442008367691983 ], [ -76.090543788564958, 20.420562649446708 ], [ -76.092610847012963, 20.417462063123708 ], [ -76.111343552562914, 20.400615546170513 ], [ -76.114805874091815, 20.408315335584234 ], [ -76.107106085577357, 20.424128322863794 ], [ -76.106150072068147, 20.42828827638283 ], [ -76.106770188793178, 20.430277817767035 ], [ -76.111756964612198, 20.428779201898635 ], [ -76.116304490859534, 20.42846914353612 ], [ -76.121394618566796, 20.42983856909467 ], [ -76.130463832639748, 20.434153551345275 ], [ -76.138189459575869, 20.436892402462377 ], [ -76.146457688871237, 20.438597723905843 ], [ -76.155423550156684, 20.438881943846638 ], [ -76.17965979726182, 20.437590033553192 ], [ -76.204335293039321, 20.474331976939141 ], [ -76.233971727113499, 20.502779853507434 ], [ -76.244410366745001, 20.509471950769921 ], [ -76.253092007190389, 20.513631904288957 ], [ -76.28006710541257, 20.519574692717867 ], [ -76.300530971726971, 20.528566392425034 ], [ -76.312881639276213, 20.53213206584212 ], [ -76.338048062368159, 20.536369533726997 ], [ -76.360372280656236, 20.544560247757204 ], [ -76.372567918574589, 20.545800483005848 ], [ -76.366935186709497, 20.5668586294222 ], [ -76.367813686752243, 20.571948757129405 ], [ -76.370785081866018, 20.578692532134653 ], [ -76.374479947391649, 20.581250515199088 ], [ -76.377890591177845, 20.582413235182628 ], [ -76.380758632604795, 20.582723294444463 ], [ -76.385306158852131, 20.581741440714893 ], [ -76.387347377979097, 20.580397854477383 ], [ -76.390137905939582, 20.578072415409622 ], [ -76.393057624209973, 20.576547960220182 ], [ -76.396132372111254, 20.576392931488556 ], [ -76.404762335713201, 20.579932766483978 ], [ -76.439566412759746, 20.589906318122075 ], [ -76.485894335055491, 20.615770372304837 ], [ -76.503826056727121, 20.623289292766628 ], [ -76.550670742061072, 20.633857122708037 ], [ -76.559843308921529, 20.638223781802083 ], [ -76.564416672691266, 20.641892808905993 ], [ -76.564442512012306, 20.646181951835615 ], [ -76.562814704035361, 20.660935573717722 ], [ -76.563408983237991, 20.67264028612027 ], [ -76.564520026378091, 20.680055853794613 ], [ -76.570307786974752, 20.696463121176066 ], [ -76.581237352122116, 20.697083237901097 ], [ -76.608160772601536, 20.683828232786709 ], [ -76.618237677926459, 20.681787014559063 ], [ -76.627901171202097, 20.682432969705758 ], [ -76.635394253242168, 20.684835924038623 ], [ -76.649915331127602, 20.68772980388735 ], [ -76.657976853948639, 20.690985418941921 ], [ -76.664462245636116, 20.696127224391887 ], [ -76.673608974974229, 20.710674139799721 ], [ -76.677174649290635, 20.713180446920092 ], [ -76.6803527490801, 20.713180446920092 ], [ -76.689938727989897, 20.70793528958194 ], [ -76.699783088418769, 20.704524643997104 ], [ -76.707250332037177, 20.706152451974049 ], [ -76.712831387058827, 20.70964061102535 ], [ -76.717043015622664, 20.714498196534521 ], [ -76.721900601131836, 20.722301336937107 ], [ -76.712392136587823, 20.725634467256839 ], [ -76.702237717796436, 20.732068183000251 ], [ -76.699473029156934, 20.736564032404146 ], [ -76.698827074010239, 20.742636012941603 ], [ -76.702547777058271, 20.752454534948811 ], [ -76.707818772818086, 20.759534206738238 ], [ -76.71872250044305, 20.770825507091445 ], [ -76.720892909879865, 20.776406562113152 ], [ -76.721125453876596, 20.784287217780843 ], [ -76.71965267642986, 20.797283840476837 ], [ -76.71678463410359, 20.806404731393229 ], [ -76.709575772004257, 20.819608058764857 ], [ -76.691308152649128, 20.841932277952253 ], [ -76.687923347284652, 20.851518255962731 ], [ -76.686347215251772, 20.865496731488975 ], [ -76.687303228760982, 20.936138414356321 ], [ -76.674668342170264, 20.970348212200236 ], [ -76.662756924192706, 20.965309760437094 ], [ -76.652809210976272, 20.956886502410157 ], [ -76.647279832798006, 20.953320828093752 ], [ -76.642809820916511, 20.951563828907581 ], [ -76.636789517222439, 20.951098740914119 ], [ -76.629735683854733, 20.951641344172685 ], [ -76.613586798891617, 20.955181179168051 ], [ -76.56082516085246, 20.976626899212022 ], [ -76.547802699734802, 20.979804999001487 ], [ -76.538423428198655, 20.980399278204118 ], [ -76.532558153236153, 20.978332221554751 ], [ -76.527623054260516, 20.977557074299511 ], [ -76.5207759255685, 20.978409735920536 ], [ -76.517236090573135, 20.981277778246863 ], [ -76.514368049146128, 20.996212267282317 ], [ -76.50245663116857, 21.024195054957829 ], [ -76.48356889508841, 21.042307643782692 ], [ -76.458815884045805, 21.060652778402982 ], [ -76.453079800292528, 21.063598334195774 ], [ -76.437008429695254, 21.076362412895037 ], [ -76.392592536216569, 21.103182481486328 ], [ -76.370836757810139, 21.111709093200091 ], [ -76.343913337330662, 21.12749624295725 ], [ -76.338513150361564, 21.134059149909831 ], [ -76.336859503962899, 21.140337836022297 ], [ -76.340295987070135, 21.158243720171527 ], [ -76.339960090285899, 21.164470730339929 ], [ -76.334740769570828, 21.171059474814911 ], [ -76.330839200268883, 21.174444281078706 ], [ -76.325671556397197, 21.177570705823371 ], [ -76.318075120670244, 21.194262193145676 ], [ -76.314199387991323, 21.250667018967761 ], [ -76.313547330045253, 21.251898504712187 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-99", "NAME_1": "Isla de la Juventud" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -81.372303839999915, 21.70538971600007 ], [ -81.376535610999952, 21.703070380000042 ], [ -81.417551235999952, 21.667914130000042 ], [ -81.496693488999938, 21.618475653000075 ], [ -81.527699347999942, 21.605861721000053 ], [ -81.560658331999946, 21.60297272300005 ], [ -81.56078040299991, 21.622381903000075 ], [ -81.551380988999938, 21.62759023600006 ], [ -81.523508266999897, 21.623439846000053 ], [ -81.512440558999913, 21.630845445000091 ], [ -81.503041144999941, 21.645697333000044 ], [ -81.493519660999937, 21.657049872000073 ], [ -81.482167120999918, 21.653876044000071 ], [ -81.46906490799995, 21.648179429000038 ], [ -81.454497850999928, 21.65180084800005 ], [ -81.442697719999899, 21.659979559000078 ], [ -81.43781490799995, 21.667873440000051 ], [ -81.431711391999897, 21.68500397300005 ], [ -81.417307094999899, 21.697211005000042 ], [ -81.385975714999915, 21.715969143000052 ], [ -81.377674933999913, 21.718939520000049 ], [ -81.371652798999946, 21.714748440000051 ], [ -81.36937415299991, 21.708563544000071 ], [ -81.372303839999915, 21.70538971600007 ] ] ], [ [ [ -82.568023240999935, 21.636542059000078 ], [ -82.575184699999909, 21.624701239000046 ], [ -82.567128058999913, 21.612005927000041 ], [ -82.552642381999931, 21.601385809000078 ], [ -82.540760870999918, 21.595526434000078 ], [ -82.550892706999946, 21.580267645000049 ], [ -82.571441209999932, 21.559759833000044 ], [ -82.594634568999936, 21.541815497000073 ], [ -82.612700975999928, 21.534084377000056 ], [ -82.631459113999938, 21.530747789000088 ], [ -82.759185350999928, 21.470607815000051 ], [ -82.835560675999943, 21.444728908000059 ], [ -82.906239386999914, 21.437486070000091 ], [ -82.918120897999927, 21.441595770000049 ], [ -82.927235480999911, 21.450995184000078 ], [ -82.992583787999934, 21.452134507000039 ], [ -83.00226803299995, 21.455023505000042 ], [ -83.021839972999942, 21.463080145000049 ], [ -83.033558722999942, 21.465806382000039 ], [ -83.069488084999932, 21.46515534100007 ], [ -83.078521287999934, 21.469224351000037 ], [ -83.111154751999948, 21.509751695000091 ], [ -83.123605923999946, 21.520453192000048 ], [ -83.151722785999937, 21.537909247000073 ], [ -83.162098761999914, 21.549261786000045 ], [ -83.171376105999911, 21.568264065000051 ], [ -83.178212042999917, 21.595526434000078 ], [ -83.189523891999897, 21.620266018000052 ], [ -83.191802537999934, 21.63031647300005 ], [ -83.185047980999911, 21.63031647300005 ], [ -83.173939581999946, 21.620103257000039 ], [ -83.123605923999946, 21.585638739000046 ], [ -83.117014126999948, 21.57172272300005 ], [ -83.101307745999918, 21.559800523000035 ], [ -83.082020636999914, 21.551459052000041 ], [ -83.065256313999896, 21.548407294000071 ], [ -83.023915167999917, 21.548407294000071 ], [ -83.020578579999949, 21.552476304000038 ], [ -82.992583787999934, 21.575100002000056 ], [ -82.976918097999942, 21.584865627000056 ], [ -82.969227667999917, 21.59125397300005 ], [ -82.965931769999941, 21.599269924000055 ], [ -82.962798631999931, 21.59829336100006 ], [ -82.957630988999938, 21.592352606000077 ], [ -82.956532355999911, 21.582180080000057 ], [ -82.965931769999941, 21.568264065000051 ], [ -82.959095831999946, 21.561997789000088 ], [ -82.941029425999943, 21.593085028000075 ], [ -82.946115688999896, 21.604641018000052 ], [ -82.975900844999899, 21.609198309000078 ], [ -82.987660285999937, 21.61977773600006 ], [ -83.073475714999915, 21.760565497000073 ], [ -83.085601365999935, 21.800279039000088 ], [ -83.075184699999909, 21.843166408000059 ], [ -83.032826300999943, 21.874335028000075 ], [ -83.027333136999914, 21.887274481000077 ], [ -83.018666144999941, 21.897691148000035 ], [ -82.998524542999917, 21.910956122000073 ], [ -82.975697394999941, 21.921820380000042 ], [ -82.959095831999946, 21.925116278000075 ], [ -82.970082160999937, 21.92999909100007 ], [ -82.981027798999946, 21.93195221600007 ], [ -82.992583787999934, 21.93195221600007 ], [ -83.004709438999896, 21.937648830000057 ], [ -83.005238410999937, 21.939601955000057 ], [ -82.998768683999913, 21.941839911000045 ], [ -82.989491339999915, 21.948431708000044 ], [ -82.858998175999943, 21.933661200000074 ], [ -82.777495897999927, 21.914862372000073 ], [ -82.721424933999913, 21.900091864000046 ], [ -82.703724738999938, 21.892808335000041 ], [ -82.690174933999913, 21.881822007000039 ], [ -82.684722459999932, 21.866156317000048 ], [ -82.688221808999913, 21.847642320000091 ], [ -82.693470831999946, 21.835435289000088 ], [ -82.692534959999932, 21.824042059000078 ], [ -82.677886522999927, 21.807806708000044 ], [ -82.632964647999927, 21.773627020000049 ], [ -82.619536912999934, 21.774318752000056 ], [ -82.60960852799991, 21.769598700000074 ], [ -82.602935350999928, 21.758490302000041 ], [ -82.59788977799991, 21.746039130000042 ], [ -82.592600063999896, 21.736761786000045 ], [ -82.592355923999946, 21.729071356000077 ], [ -82.597727016999897, 21.71743398600006 ], [ -82.608998175999943, 21.698553778000075 ], [ -82.616444464999915, 21.698553778000075 ], [ -82.611073370999918, 21.690130927000041 ], [ -82.609527147999927, 21.681586005000042 ], [ -82.611439581999946, 21.672919012000079 ], [ -82.616444464999915, 21.664455471000053 ], [ -82.593861456999946, 21.651068427000041 ], [ -82.581898566999939, 21.645738023000035 ], [ -82.568023240999935, 21.643947658000059 ], [ -82.568023240999935, 21.636542059000078 ] ] ], [ [ [ -81.981190558999913, 21.647772528000075 ], [ -81.973622199999909, 21.639878648000035 ], [ -81.972767706999946, 21.622219143000052 ], [ -81.989816860999952, 21.60883209800005 ], [ -82.029449022999927, 21.59516022300005 ], [ -82.058583136999914, 21.581447658000059 ], [ -82.065297003999945, 21.579738674000055 ], [ -82.070464647999927, 21.57648346600007 ], [ -82.074330206999946, 21.572211005000042 ], [ -82.088368292999917, 21.568182684000078 ], [ -82.11001542899993, 21.567450262000079 ], [ -82.114247199999909, 21.570298570000091 ], [ -82.102162238999938, 21.574448960000041 ], [ -82.082183397999927, 21.590033270000049 ], [ -82.071197068999936, 21.592962958000044 ], [ -82.061838344999899, 21.59837474200009 ], [ -82.054514126999948, 21.606146552000041 ], [ -82.048329230999911, 21.610663153000075 ], [ -82.01976477799991, 21.621039130000042 ], [ -82.007883266999897, 21.621527411000045 ], [ -81.996652798999946, 21.626613674000055 ], [ -81.987619594999899, 21.634833075000074 ], [ -81.984120245999918, 21.641913153000075 ], [ -81.982899542999917, 21.646307684000078 ], [ -81.981190558999913, 21.647772528000075 ] ] ], [ [ [ -81.852528449999909, 21.663560289000088 ], [ -81.839019334999932, 21.666205145000049 ], [ -81.837798631999931, 21.661078192000048 ], [ -81.852650519999941, 21.649888414000088 ], [ -81.870106574999909, 21.639471747000073 ], [ -81.901356574999909, 21.615627346000053 ], [ -81.918853318999936, 21.615464585000041 ], [ -81.932362433999913, 21.628485419000071 ], [ -81.935699022999927, 21.641913153000075 ], [ -81.932850714999915, 21.640204169000071 ], [ -81.92218990799995, 21.629339911000045 ], [ -81.905629035999937, 21.631008205000057 ], [ -81.892201300999943, 21.641058661000045 ], [ -81.888172980999911, 21.647040106000077 ], [ -81.892079230999911, 21.647406317000048 ], [ -81.889149542999917, 21.649359442000048 ], [ -81.859201626999948, 21.66156647300005 ], [ -81.852528449999909, 21.663560289000088 ] ] ], [ [ [ -82.64517167899993, 21.95453522300005 ], [ -82.60773678299995, 21.938706773000035 ], [ -82.591175910999937, 21.926662502000056 ], [ -82.602894660999937, 21.921942450000074 ], [ -82.630116339999915, 21.920721747000073 ], [ -82.657866990999935, 21.932074286000045 ], [ -82.668080206999946, 21.949123440000051 ], [ -82.64517167899993, 21.95453522300005 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-07", "NAME_1": "Sancti Spíritus" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -78.984201626999948, 22.637681382000039 ], [ -78.989857550999943, 22.651434637000079 ], [ -79.004505988999938, 22.656724351000037 ], [ -79.064442511999914, 22.660345770000049 ], [ -79.074615037999934, 22.664252020000049 ], [ -79.087228969999899, 22.671820380000042 ], [ -79.070383266999897, 22.674017645000049 ], [ -78.976551886999914, 22.668524481000077 ], [ -78.960845506999931, 22.660142320000091 ], [ -78.96117102799991, 22.649115302000041 ], [ -78.984201626999948, 22.637681382000039 ] ] ], [ [ [ -79.416737434085292, 22.472479559284238 ], [ -79.341786261999914, 22.413153387000079 ], [ -79.312489386999914, 22.400295315000051 ], [ -79.285878058999913, 22.404282945000091 ], [ -79.275746222999942, 22.39484284100007 ], [ -79.256947394999941, 22.38226959800005 ], [ -79.238758917999917, 22.37641022300005 ], [ -79.230580206999946, 22.387193101000037 ], [ -79.219838019999941, 22.388413804000038 ], [ -79.167469855999911, 22.377875067000048 ], [ -79.14867102799991, 22.377630927000041 ], [ -79.137806769999941, 22.384833075000074 ], [ -79.135650193999936, 22.391180731000077 ], [ -79.13312740799995, 22.395656643000052 ], [ -79.120716925999943, 22.396877346000053 ], [ -79.110585089999915, 22.394598700000074 ], [ -79.095041469999899, 22.385728257000039 ], [ -79.083485480999911, 22.383775132000039 ], [ -79.062001105999911, 22.386664130000042 ], [ -79.024484829999949, 22.399969794000071 ], [ -79.005279100999928, 22.404282945000091 ], [ -78.982492641999897, 22.40460846600007 ], [ -78.927194791406464, 22.39874909099774 ], [ -78.931363652710388, 22.384653371755689 ], [ -78.934275420074584, 22.354079811733925 ], [ -78.94155483938431, 22.346800393323463 ], [ -78.950290142376161, 22.339520973114418 ], [ -78.956113678003817, 22.32787390275837 ], [ -78.966304863778419, 22.307491530309846 ], [ -78.97504016677027, 22.275462085706693 ], [ -78.985231354343512, 22.256535596040919 ], [ -78.999790192063699, 22.23324145532888 ], [ -79.012893146101817, 22.211403198298967 ], [ -79.021628449093612, 22.188109056687608 ], [ -79.034731404031049, 22.17646198633156 ], [ -79.03327552034898, 22.148800194573312 ], [ -79.047834358069167, 22.116770749970101 ], [ -79.046378474387097, 22.096388375722938 ], [ -79.030363752085464, 22.08328542258414 ], [ -78.999790192063699, 22.059991280972838 ], [ -78.977951935033786, 22.049800094298917 ], [ -78.964848980096349, 22.043976559570524 ], [ -78.960481329050083, 22.026505952687558 ], [ -78.960481329050083, 22.003211811975518 ], [ -78.97504016677027, 21.978461787581409 ], [ -78.992510772753917, 21.95371176228798 ], [ -78.998334308381629, 21.942064691931989 ], [ -79.012893146101817, 21.944976460195448 ], [ -79.028907868403394, 21.946432342978255 ], [ -79.040554938759385, 21.939152924567793 ], [ -79.046378474387097, 21.91877055121995 ], [ -79.058025544743089, 21.89693229418998 ], [ -79.072584383362596, 21.870726385214482 ], [ -79.082775570036517, 21.848888128184569 ], [ -79.092966755811119, 21.809579265170953 ], [ -79.114805012841032, 21.765902750211751 ], [ -79.122084433050134, 21.749888027910117 ], [ -79.106069710748557, 21.726593887198135 ], [ -79.098790291438775, 21.710579164896501 ], [ -79.10315794338436, 21.682917373138253 ], [ -79.108981478112696, 21.665446767154549 ], [ -79.100246175120844, 21.653799696798558 ], [ -79.072584383362596, 21.653799696798558 ], [ -79.043466707022901, 21.665446767154549 ], [ -79.03181963576759, 21.678549721192667 ], [ -79.03181963576759, 21.694564443494244 ], [ -79.017260798047403, 21.714946816842087 ], [ -78.992510772753917, 21.704755630168165 ], [ -78.970672515724004, 21.690196792447978 ], [ -78.964848980096349, 21.677093838409917 ], [ -78.967760748359808, 21.650887929434361 ], [ -78.964848980096349, 21.620314369412597 ], [ -78.959950325247291, 21.599554754748112 ], [ -78.970570441999939, 21.595526434000078 ], [ -78.977365688999953, 21.60297272300005 ], [ -78.994536912999934, 21.59406159100007 ], [ -79.012806769999941, 21.590073960000041 ], [ -79.055897589999915, 21.58930084800005 ], [ -79.075550910999937, 21.586086330000057 ], [ -79.128163214999915, 21.561997789000088 ], [ -79.169260219999899, 21.551703192000048 ], [ -79.208892381999931, 21.548488674000055 ], [ -79.249419725999928, 21.551947333000044 ], [ -79.329579230999911, 21.57367584800005 ], [ -79.346099412999934, 21.583156643000052 ], [ -79.364654100999928, 21.599269924000055 ], [ -79.378773566999939, 21.601263739000046 ], [ -79.430653449999909, 21.595404364000046 ], [ -79.450306769999941, 21.595526434000078 ], [ -79.472279425999943, 21.601996161000045 ], [ -79.481760219999899, 21.607367255000042 ], [ -79.491322394999941, 21.616034247000073 ], [ -79.506459113999938, 21.639797268000052 ], [ -79.515288865999935, 21.648586330000057 ], [ -79.519195115999935, 21.640204169000071 ], [ -79.522206183999913, 21.630031643000052 ], [ -79.529693162999934, 21.623439846000053 ], [ -79.539662238999938, 21.621975002000056 ], [ -79.549672003999945, 21.626898505000042 ], [ -79.559152798999946, 21.634995835000041 ], [ -79.564930792999917, 21.637884833000044 ], [ -79.607777472999942, 21.648993231000077 ], [ -79.613677537999934, 21.651312567000048 ], [ -79.621652798999946, 21.657619533000059 ], [ -79.62759355399993, 21.666937567000048 ], [ -79.632313605999911, 21.678208726000037 ], [ -79.639271613999938, 21.687730210000041 ], [ -79.652088995999918, 21.69171784100007 ], [ -79.722727016999897, 21.693426825000074 ], [ -79.790109829999949, 21.711615302000041 ], [ -79.815785285999937, 21.71124909100007 ], [ -79.827056443999936, 21.695135809000078 ], [ -79.833851691999939, 21.677679755000042 ], [ -79.850819464999915, 21.680080471000053 ], [ -79.872954881999931, 21.69086334800005 ], [ -79.895375128999945, 21.698553778000075 ], [ -79.895375128999945, 21.70538971600007 ], [ -79.874867316999939, 21.712836005000042 ], [ -79.874867316999939, 21.71906159100007 ], [ -79.890370245999918, 21.722398179000038 ], [ -79.893625454999949, 21.733587958000044 ], [ -79.892648891999897, 21.747748114000046 ], [ -79.895375128999945, 21.759995835000041 ], [ -79.91234290299991, 21.74835846600007 ], [ -79.93000240799995, 21.743312893000052 ], [ -79.94945227799991, 21.743109442000048 ], [ -79.971669074999909, 21.74640534100007 ], [ -79.992054816999939, 21.753322658000059 ], [ -80.003651495999918, 21.755804755000042 ], [ -80.012684699999909, 21.753810940000051 ], [ -80.015370245999918, 21.74673086100006 ], [ -80.009022589999915, 21.739935614000046 ], [ -79.999134894999941, 21.73501211100006 ], [ -79.990956183999913, 21.733343817000048 ], [ -80.003244594999899, 21.720892645000049 ], [ -80.02179928299995, 21.729193427000041 ], [ -80.038807745999918, 21.747137762000079 ], [ -80.046213344999899, 21.763413804000038 ], [ -80.048451300999943, 21.784898179000038 ], [ -80.05532792899993, 21.803697007000039 ], [ -80.067250128999945, 21.81704336100006 ], [ -80.084339972999942, 21.822088934000078 ], [ -80.101026702777816, 21.824765419775595 ], [ -80.101022508382016, 21.824843858457257 ], [ -80.09880042210176, 21.866391710508992 ], [ -80.097715217383382, 21.871481838216255 ], [ -80.094097867122855, 21.87639110056881 ], [ -80.087276576852503, 21.883419093716213 ], [ -80.060043098010567, 21.903702093776587 ], [ -80.024050462558762, 21.938506170823132 ], [ -79.98860043036558, 21.953905747851991 ], [ -79.969893562338029, 21.968090928953188 ], [ -79.963072272067677, 21.969822088818319 ], [ -79.948292812663169, 21.968762722521603 ], [ -79.943202684056587, 21.971734116736059 ], [ -79.940489672260526, 21.976824246241961 ], [ -79.938319261025072, 21.985325019534002 ], [ -79.934521043611255, 21.993231512724094 ], [ -79.924650844760663, 22.004987901070763 ], [ -79.914496425969276, 22.008992824958909 ], [ -79.904962123902862, 22.010233059308234 ], [ -79.846877814159768, 21.997262275033961 ], [ -79.839591436795331, 21.994368394285971 ], [ -79.834733853084856, 21.990906072757014 ], [ -79.820548671983602, 21.983929755553731 ], [ -79.790705533233734, 21.981785182739998 ], [ -79.765926682870088, 22.001551418862846 ], [ -79.746263801333328, 22.03152374882194 ], [ -79.72977901868677, 22.062374578823722 ], [ -79.724482185404497, 22.080874742175581 ], [ -79.723552009417688, 22.093871364871575 ], [ -79.72745357871969, 22.099374905527441 ], [ -79.731820237813736, 22.101441962176807 ], [ -79.737685512776181, 22.101700343695882 ], [ -79.742723965438643, 22.101209418180076 ], [ -79.747142299577433, 22.102062078901781 ], [ -79.750242885900434, 22.105033474015613 ], [ -79.753782721795176, 22.111570543445794 ], [ -79.758304408721472, 22.122810166955617 ], [ -79.772877162550969, 22.14929433786341 ], [ -79.779259203249637, 22.166528429343543 ], [ -79.779646775977938, 22.176915392131605 ], [ -79.777528041585811, 22.183710842181597 ], [ -79.766624314860223, 22.192831733097989 ], [ -79.73360307542157, 22.19208242426447 ], [ -79.722001715806527, 22.183168239822407 ], [ -79.718306851180216, 22.176605332869826 ], [ -79.713320075361196, 22.169784044398114 ], [ -79.702855598207293, 22.161257433583671 ], [ -79.692416957676414, 22.158802802407365 ], [ -79.683838670917908, 22.159267890400827 ], [ -79.676578131975191, 22.162962755027081 ], [ -79.662237922142367, 22.171928616312584 ], [ -79.64900875455038, 22.173323879393479 ], [ -79.639732835801738, 22.172652085825064 ], [ -79.598805101374296, 22.161050727109341 ], [ -79.578367071682976, 22.167226060434302 ], [ -79.564827846627793, 22.161438299837641 ], [ -79.556172044604182, 22.1560122753462 ], [ -79.541961025980527, 22.150689601843624 ], [ -79.527853360144434, 22.152291572298225 ], [ -79.516717089422116, 22.156709906437015 ], [ -79.507725388815629, 22.164306342163968 ], [ -79.499250453945251, 22.174977524892824 ], [ -79.491809047849245, 22.188904324475004 ], [ -79.486693080820999, 22.201565050386762 ], [ -79.481267056329557, 22.219445095214951 ], [ -79.463387009702728, 22.23654999368722 ], [ -79.45144975510209, 22.242415269549042 ], [ -79.433828090893655, 22.248487250086498 ], [ -79.421580777031238, 22.249314073285859 ], [ -79.41173641570299, 22.247169501371388 ], [ -79.386905891193919, 22.235025540296419 ], [ -79.361119351376942, 22.231201484460939 ], [ -79.358044602576342, 22.249184882076634 ], [ -79.359129808194098, 22.265049547098897 ], [ -79.356649340394711, 22.27703847944224 ], [ -79.352696091551365, 22.289544175723108 ], [ -79.353471238806605, 22.296830553087545 ], [ -79.381841600109738, 22.333262437211715 ], [ -79.415353766862836, 22.395480862052125 ], [ -79.423699509624669, 22.408064072698778 ], [ -79.435378383605496, 22.416461493203315 ], [ -79.416852382731236, 22.448449204766973 ], [ -79.417369146668761, 22.471445217522728 ], [ -79.416737434085292, 22.472479559284238 ] ] ], [ [ [ -79.224517381999931, 22.639715887000079 ], [ -79.215728318999936, 22.643011786000045 ], [ -79.176869269999941, 22.644680080000057 ], [ -79.18976803299995, 22.634507554000038 ], [ -79.206410285999937, 22.624416408000059 ], [ -79.213246222999942, 22.624416408000059 ], [ -79.21320553299995, 22.631048895000049 ], [ -79.216420050999943, 22.636623440000051 ], [ -79.224517381999931, 22.639715887000079 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-05", "NAME_1": "Villa Clara" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -79.357533331999946, 22.637681382000039 ], [ -79.366363084999932, 22.639349677000041 ], [ -79.375559048999946, 22.64321523600006 ], [ -79.38890540299991, 22.651312567000048 ], [ -79.403797980999911, 22.663641669000071 ], [ -79.437367316999939, 22.698472398000035 ], [ -79.45539303299995, 22.692287502000056 ], [ -79.473744269999941, 22.694322007000039 ], [ -79.490834113999938, 22.702053127000056 ], [ -79.513579881999931, 22.718410549000055 ], [ -79.520090298999946, 22.720689195000091 ], [ -79.524037238999938, 22.725002346000053 ], [ -79.525461391999897, 22.736395575000074 ], [ -79.528879360999952, 22.740301825000074 ], [ -79.544829881999931, 22.75141022300005 ], [ -79.549672003999945, 22.753729559000078 ], [ -79.557972785999937, 22.760158596000053 ], [ -79.563099738999938, 22.774237372000073 ], [ -79.571766730999911, 22.788275458000044 ], [ -79.590646938999953, 22.794663804000038 ], [ -79.620350714999915, 22.783148505000042 ], [ -79.633656378999945, 22.78384023600006 ], [ -79.635324673999946, 22.802150783000059 ], [ -79.606922980999911, 22.810248114000046 ], [ -79.586537238999938, 22.811224677000041 ], [ -79.569976365999935, 22.804103908000059 ], [ -79.517974412999934, 22.749579169000071 ], [ -79.49632727799991, 22.73314036700009 ], [ -79.450266079999949, 22.719916083000044 ], [ -79.412912563999953, 22.691351630000042 ], [ -79.371978318999936, 22.676662502000056 ], [ -79.351918097999942, 22.657294012000079 ], [ -79.335601365999935, 22.634670315000051 ], [ -79.32681230399993, 22.616522528000075 ], [ -79.349476691999939, 22.635321356000077 ], [ -79.357533331999946, 22.637681382000039 ] ] ], [ [ [ -79.895375128999945, 22.959173895000049 ], [ -79.887115037999934, 22.95970286700009 ], [ -79.887847459999932, 22.946275132000039 ], [ -79.898548956999946, 22.936712958000044 ], [ -79.919829881999931, 22.949286200000074 ], [ -79.929351365999935, 22.946478583000044 ], [ -79.939808722999942, 22.932847398000035 ], [ -79.949696417999917, 22.928412177000041 ], [ -79.957427537999934, 22.953029690000051 ], [ -79.943023240999935, 22.961127020000049 ], [ -79.927235480999911, 22.966294664000088 ], [ -79.911000128999945, 22.966376044000071 ], [ -79.895375128999945, 22.959173895000049 ] ] ], [ [ [ -80.32054602799991, 22.986517645000049 ], [ -80.271880662999934, 23.008693752000056 ], [ -80.249745245999918, 23.010931708000044 ], [ -80.231800910999937, 23.000148830000057 ], [ -80.23696855399993, 22.997300523000035 ], [ -80.246693488999938, 22.989447333000044 ], [ -80.251616990999935, 22.986517645000049 ], [ -80.24250240799995, 22.982570705000057 ], [ -80.236073370999918, 22.976752020000049 ], [ -80.232533331999946, 22.968939520000049 ], [ -80.231800910999937, 22.959173895000049 ], [ -80.332508917999917, 22.97532786700009 ], [ -80.347808397999927, 22.986517645000049 ], [ -80.341704881999931, 22.991034247000073 ], [ -80.335764126999948, 22.993353583000044 ], [ -80.328968878999945, 22.992254950000074 ], [ -80.32054602799991, 22.986517645000049 ] ] ], [ [ [ -80.197010870999918, 23.124253648000035 ], [ -80.190744594999899, 23.111395575000074 ], [ -80.179839647999927, 23.10024648600006 ], [ -80.166493292999917, 23.092474677000041 ], [ -80.15265865799995, 23.089544989000046 ], [ -80.136586066999939, 23.089016018000052 ], [ -80.131255662999934, 23.086981512000079 ], [ -80.134103969999899, 23.082831122000073 ], [ -80.142404751999948, 23.075873114000046 ], [ -80.16242428299995, 23.067328192000048 ], [ -80.182728644999941, 23.07094961100006 ], [ -80.224964972999942, 23.089544989000046 ], [ -80.222645636999914, 23.099758205000057 ], [ -80.217396613999938, 23.107123114000046 ], [ -80.210804816999939, 23.114447333000044 ], [ -80.204457160999937, 23.124253648000035 ], [ -80.197010870999918, 23.124253648000035 ] ] ], [ [ [ -80.593095662534779, 23.068032199226593 ], [ -80.556792772999927, 23.007391669000071 ], [ -80.536244269999941, 22.993963934000078 ], [ -80.520375128999945, 22.99290599200009 ], [ -80.479847785999937, 22.985663153000075 ], [ -80.464507615999935, 22.980292059000078 ], [ -80.455067511999914, 22.972072658000059 ], [ -80.444732225999928, 22.96039459800005 ], [ -80.431507941999939, 22.94993724200009 ], [ -80.413319464999915, 22.945502020000049 ], [ -80.356922980999911, 22.94562409100007 ], [ -80.344471808999913, 22.942084052000041 ], [ -80.329416469999899, 22.929836330000057 ], [ -80.313343878999945, 22.921291408000059 ], [ -80.296701626999948, 22.915676174000055 ], [ -80.27961178299995, 22.912014065000051 ], [ -80.246693488999938, 22.911037502000056 ], [ -80.215687628999945, 22.917059637000079 ], [ -80.156076626999948, 22.938706773000035 ], [ -80.163563605999911, 22.962551174000055 ], [ -80.14671790299991, 22.963080145000049 ], [ -80.093617316999939, 22.938544012000079 ], [ -80.070057745999918, 22.931789455000057 ], [ -80.050038214999915, 22.935248114000046 ], [ -80.046213344999899, 22.959173895000049 ], [ -80.035511847999942, 22.95384349200009 ], [ -80.024566209999932, 22.946682033000059 ], [ -80.016102667999917, 22.938055731000077 ], [ -80.012684699999909, 22.92845286700009 ], [ -79.990061001999948, 22.890611070000091 ], [ -79.987863735999952, 22.884100653000075 ], [ -79.950021938999896, 22.86359284100007 ], [ -79.944569464999915, 22.862779039000088 ], [ -79.926747199999909, 22.86359284100007 ], [ -79.919829881999931, 22.861314195000091 ], [ -79.916981574999909, 22.856431382000039 ], [ -79.916411912999934, 22.851548570000091 ], [ -79.916493292999917, 22.849310614000046 ], [ -79.895741339999915, 22.855169989000046 ], [ -79.863148566999939, 22.883693752000056 ], [ -79.801747199999909, 22.899725653000075 ], [ -79.792958136999914, 22.897772528000075 ], [ -79.792958136999914, 22.890122789000088 ], [ -79.802357550999943, 22.882147528000075 ], [ -79.820912238999938, 22.870428778000075 ], [ -79.843861456999946, 22.880682684000078 ], [ -79.854969855999911, 22.872544664000088 ], [ -79.868031378999945, 22.83624909100007 ], [ -79.857167120999918, 22.820705471000053 ], [ -79.850900844999899, 22.814113674000055 ], [ -79.841379360999952, 22.808335679000038 ], [ -79.83071855399993, 22.805650132000039 ], [ -79.789540167999917, 22.802150783000059 ], [ -79.771880662999934, 22.796616929000038 ], [ -79.71312415299991, 22.757798570000091 ], [ -79.709950324999909, 22.753078518000052 ], [ -79.706166144999941, 22.74876536700009 ], [ -79.700184699999909, 22.746893622000073 ], [ -79.694650844999899, 22.749172268000052 ], [ -79.688628709999932, 22.754095770000049 ], [ -79.684193488999938, 22.758978583000044 ], [ -79.683094855999911, 22.76117584800005 ], [ -79.660308397999927, 22.763861395000049 ], [ -79.651722785999937, 22.758775132000039 ], [ -79.627023891999897, 22.657497463000084 ], [ -79.626454230999911, 22.656927802000041 ], [ -79.611480272999927, 22.652329820000091 ], [ -79.599354620999918, 22.646551825000074 ], [ -79.58853105399993, 22.638495184000078 ], [ -79.577259894999941, 22.627101955000057 ], [ -79.565825975999928, 22.611151434000078 ], [ -79.552113410999937, 22.580267645000049 ], [ -79.542836066999939, 22.565659898000035 ], [ -79.517486131999931, 22.539129950000074 ], [ -79.511830206999946, 22.53461334800005 ], [ -79.496937628999945, 22.53196849200009 ], [ -79.468006964999915, 22.531398830000057 ], [ -79.456532355999911, 22.528469143000052 ], [ -79.429839647999927, 22.490220445000091 ], [ -79.424712693999936, 22.478745835000041 ], [ -79.416737434085292, 22.472479559284238 ], [ -79.417369146668761, 22.471445217522728 ], [ -79.416852382731236, 22.448449204766973 ], [ -79.435378383605496, 22.416461493203315 ], [ -79.423699509624669, 22.408064072698778 ], [ -79.415353766862836, 22.395480862052125 ], [ -79.381841600109738, 22.333262437211715 ], [ -79.353471238806605, 22.296830553087545 ], [ -79.352696091551365, 22.289544175723108 ], [ -79.356649340394711, 22.27703847944224 ], [ -79.359129808194098, 22.265049547098897 ], [ -79.358044602576342, 22.249184882076634 ], [ -79.361119351376942, 22.231201484460939 ], [ -79.386905891193919, 22.235025540296419 ], [ -79.41173641570299, 22.247169501371388 ], [ -79.421580777031238, 22.249314073285859 ], [ -79.433828090893655, 22.248487250086498 ], [ -79.45144975510209, 22.242415269549042 ], [ -79.463387009702728, 22.23654999368722 ], [ -79.481267056329557, 22.219445095214951 ], [ -79.486693080820999, 22.201565050386762 ], [ -79.491809047849245, 22.188904324475004 ], [ -79.499250453945251, 22.174977524892824 ], [ -79.507725388815629, 22.164306342163968 ], [ -79.516717089422116, 22.156709906437015 ], [ -79.527853360144434, 22.152291572298225 ], [ -79.541961025980527, 22.150689601843624 ], [ -79.556172044604182, 22.1560122753462 ], [ -79.564827846627793, 22.161438299837641 ], [ -79.578367071682976, 22.167226060434302 ], [ -79.598805101374296, 22.161050727109341 ], [ -79.639732835801738, 22.172652085825064 ], [ -79.64900875455038, 22.173323879393479 ], [ -79.662237922142367, 22.171928616312584 ], [ -79.676578131975191, 22.162962755027081 ], [ -79.683838670917908, 22.159267890400827 ], [ -79.692416957676414, 22.158802802407365 ], [ -79.702855598207293, 22.161257433583671 ], [ -79.713320075361196, 22.169784044398114 ], [ -79.718306851180216, 22.176605332869826 ], [ -79.722001715806527, 22.183168239822407 ], [ -79.73360307542157, 22.19208242426447 ], [ -79.766624314860223, 22.192831733097989 ], [ -79.777528041585811, 22.183710842181597 ], [ -79.779646775977938, 22.176915392131605 ], [ -79.779259203249637, 22.166528429343543 ], [ -79.772877162550969, 22.14929433786341 ], [ -79.758304408721472, 22.122810166955617 ], [ -79.753782721795176, 22.111570543445794 ], [ -79.750242885900434, 22.105033474015613 ], [ -79.747142299577433, 22.102062078901781 ], [ -79.742723965438643, 22.101209418180076 ], [ -79.737685512776181, 22.101700343695882 ], [ -79.731820237813736, 22.101441962176807 ], [ -79.72745357871969, 22.099374905527441 ], [ -79.723552009417688, 22.093871364871575 ], [ -79.724482185404497, 22.080874742175581 ], [ -79.72977901868677, 22.062374578823722 ], [ -79.746263801333328, 22.03152374882194 ], [ -79.765926682870088, 22.001551418862846 ], [ -79.790705533233734, 21.981785182739998 ], [ -79.820548671983602, 21.983929755553731 ], [ -79.834733853084856, 21.990906072757014 ], [ -79.839591436795331, 21.994368394285971 ], [ -79.846877814159768, 21.997262275033961 ], [ -79.904962123902862, 22.010233059308234 ], [ -79.914496425969276, 22.008992824958909 ], [ -79.924650844760663, 22.004987901070763 ], [ -79.934521043611255, 21.993231512724094 ], [ -79.938319261025072, 21.985325019534002 ], [ -79.940489672260526, 21.976824246241961 ], [ -79.943202684056587, 21.971734116736059 ], [ -79.948292812663169, 21.968762722521603 ], [ -79.963072272067677, 21.969822088818319 ], [ -79.969893562338029, 21.968090928953188 ], [ -79.98860043036558, 21.953905747851991 ], [ -80.024050462558762, 21.938506170823132 ], [ -80.023275316202842, 21.95212291114342 ], [ -80.024748093649578, 21.954215807113769 ], [ -80.045005256187608, 21.968607692890714 ], [ -80.048415899973804, 21.977211818970261 ], [ -80.04988867921918, 21.986797796980738 ], [ -80.049268561594829, 22.001809801281297 ], [ -80.05084469272839, 22.028319809711434 ], [ -80.053376838270481, 22.03653636306268 ], [ -80.058777025239522, 22.043435166799497 ], [ -80.077380541378886, 22.057878730319146 ], [ -80.084124314585438, 22.070255235390789 ], [ -80.089369472822909, 22.083768622024252 ], [ -80.099859789297795, 22.123404446158247 ], [ -80.100479906022827, 22.131879381028568 ], [ -80.099808111555092, 22.151593940308089 ], [ -80.103580492345827, 22.190196234768393 ], [ -80.102417772362287, 22.199265447942025 ], [ -80.098567878105086, 22.207611192502497 ], [ -80.09497636626628, 22.213424791520879 ], [ -80.084072638641373, 22.245619207760228 ], [ -80.109187384889879, 22.25641958349695 ], [ -80.121434698752353, 22.271431585998869 ], [ -80.130219692884509, 22.286211046302753 ], [ -80.135697395118655, 22.29768321380925 ], [ -80.138410406914716, 22.306726589460538 ], [ -80.141588507603501, 22.329102485491319 ], [ -80.143293829946288, 22.332642320486684 ], [ -80.145696784279153, 22.334554348404424 ], [ -80.14990841284299, 22.335381170704466 ], [ -80.154972703927115, 22.334916082711004 ], [ -80.169984707328354, 22.330626938882119 ], [ -80.177090216640181, 22.330110174944593 ], [ -80.184273241217113, 22.331350409293918 ], [ -80.196598070344635, 22.33737071388731 ], [ -80.23295244010302, 22.370314438960179 ], [ -80.239050259062196, 22.378169257105526 ], [ -80.242486742169376, 22.384654648793003 ], [ -80.243003506106902, 22.39537750926462 ], [ -80.223986578817517, 22.4146786564948 ], [ -80.220808479028051, 22.427804470399963 ], [ -80.223521490824112, 22.432145291072288 ], [ -80.227242193872144, 22.436021022851889 ], [ -80.234399380027355, 22.43950918190319 ], [ -80.238481818281286, 22.446692206480122 ], [ -80.238998583118075, 22.452402451811679 ], [ -80.23737077514113, 22.45955963796689 ], [ -80.23352088088393, 22.468292955255663 ], [ -80.236518114419425, 22.478473212468771 ], [ -80.255560879231155, 22.488472602528589 ], [ -80.259100715125896, 22.493588569556834 ], [ -80.270236985848214, 22.517798977340931 ], [ -80.271399705831755, 22.526480617786262 ], [ -80.271089646569919, 22.531648260758629 ], [ -80.268014898668639, 22.53418040630072 ], [ -80.264785122035732, 22.535575670280934 ], [ -80.260806036569306, 22.536609198155929 ], [ -80.257937995142356, 22.53797862371448 ], [ -80.25548336486537, 22.542862046746052 ], [ -80.254010585619994, 22.551362820038094 ], [ -80.25398474809765, 22.569036160190649 ], [ -80.255405849600265, 22.57559906714323 ], [ -80.257550422414056, 22.578544622935965 ], [ -80.260134243000891, 22.576606757495824 ], [ -80.264785122035732, 22.571697496042589 ], [ -80.267756517149508, 22.569862983389953 ], [ -80.273725144899515, 22.568881130559703 ], [ -80.280158860642871, 22.568803616193918 ], [ -80.294137336169115, 22.570043850543243 ], [ -80.299950935187496, 22.569862983389953 ], [ -80.303516607705262, 22.568571072197187 ], [ -80.306798062080873, 22.564927883514997 ], [ -80.310492926707184, 22.558313299718975 ], [ -80.318011848068295, 22.536040758274339 ], [ -80.319975551930156, 22.533327745578958 ], [ -80.323153652618942, 22.531648260758629 ], [ -80.328657193274807, 22.531389879239498 ], [ -80.33640865773333, 22.531699936702694 ], [ -80.341834683124091, 22.531260688030329 ], [ -80.346459723737269, 22.529581204109263 ], [ -80.357595995358906, 22.522734076316567 ], [ -80.364055548624663, 22.519814358046176 ], [ -80.37537268739959, 22.516248683729771 ], [ -80.380824551212072, 22.51604197815476 ], [ -80.385217047828462, 22.517411403713311 ], [ -80.386767341439622, 22.519633489993566 ], [ -80.387464973429758, 22.522372341110611 ], [ -80.386689826174518, 22.526713161782993 ], [ -80.381754727198881, 22.540071518785567 ], [ -80.379816860859421, 22.549450792120354 ], [ -80.379274257600912, 22.563971869106467 ], [ -80.383976812579817, 22.569320380131444 ], [ -80.39234839466269, 22.570870672843284 ], [ -80.4171789209704, 22.566452337805117 ], [ -80.441079271291301, 22.584797472425407 ], [ -80.446221075841947, 22.586425279503032 ], [ -80.454618496346541, 22.587097073071448 ], [ -80.459424405012271, 22.584642441895141 ], [ -80.463196784004367, 22.581412665262292 ], [ -80.465909796699748, 22.57751109506097 ], [ -80.478157110562165, 22.564514472364976 ], [ -80.519679125091557, 22.542009386024347 ], [ -80.534096849290165, 22.565082913145886 ], [ -80.540349697880231, 22.571413276101794 ], [ -80.544768032918398, 22.581386826840571 ], [ -80.547610235923628, 22.591515408109558 ], [ -80.549935675890708, 22.611178290545638 ], [ -80.554844937343944, 22.618981431847601 ], [ -80.559314948326175, 22.623658149304106 ], [ -80.561717901759721, 22.627818101024502 ], [ -80.562648077746587, 22.63515615523238 ], [ -80.557532110718341, 22.682130031775557 ], [ -80.557997198711746, 22.690811672220889 ], [ -80.559625006688691, 22.69740041849451 ], [ -80.564172532936027, 22.704247545387886 ], [ -80.571433071878744, 22.711301377856273 ], [ -80.573138394221473, 22.71571971289444 ], [ -80.57194983581627, 22.721429959125317 ], [ -80.566368780794562, 22.728948878687788 ], [ -80.557015346780815, 22.732721259478524 ], [ -80.551796026965064, 22.735589300905474 ], [ -80.550323248619009, 22.740705267933777 ], [ -80.552984585370325, 22.748224189294888 ], [ -80.568074104036668, 22.772176215559909 ], [ -80.57523128929256, 22.792846788348584 ], [ -80.579572109964886, 22.801580104738036 ], [ -80.580760668370147, 22.804939073479431 ], [ -80.584920620090543, 22.813646552346484 ], [ -80.587659471207587, 22.81747060818202 ], [ -80.595049201359529, 22.82049367923986 ], [ -80.604712693735792, 22.82033865050829 ], [ -80.624298061806087, 22.81341400834981 ], [ -80.644115973873056, 22.799952296761091 ], [ -80.651402351237493, 22.7970067409683 ], [ -80.667473720935448, 22.795973212193985 ], [ -80.687730881674838, 22.812251288366269 ], [ -80.704396532374062, 22.822405707157657 ], [ -80.708530645672738, 22.825893866208958 ], [ -80.711424527320048, 22.829821274831943 ], [ -80.714421759956224, 22.835273139543744 ], [ -80.720726283591091, 22.843696397570682 ], [ -80.730932380125239, 22.854057521937079 ], [ -80.734394700754819, 22.85886342970349 ], [ -80.73633256709428, 22.863514308738331 ], [ -80.737366095868595, 22.870077215690912 ], [ -80.739329799730456, 22.873306993223139 ], [ -80.743050502778487, 22.875735785078405 ], [ -80.746848721091567, 22.877647812996145 ], [ -80.748424852225128, 22.880515855322471 ], [ -80.747158780353402, 22.884288235213887 ], [ -80.740130785407416, 22.888008938261862 ], [ -80.735092332744955, 22.892763170084208 ], [ -80.729666307354194, 22.899997869705885 ], [ -80.727056647446318, 22.914493110068975 ], [ -80.728271044273242, 22.922606308834077 ], [ -80.732224291317948, 22.937825018709646 ], [ -80.732792731199595, 22.948987127853627 ], [ -80.732095100108779, 22.956945298786479 ], [ -80.729382087413398, 22.966402086487108 ], [ -80.725945604306162, 22.970717067838393 ], [ -80.720726283591091, 22.973275050902885 ], [ -80.695792406294515, 22.972603258233789 ], [ -80.691529099987974, 22.973068346227194 ], [ -80.677473110995265, 22.978029282725174 ], [ -80.672667202329535, 22.979088649921266 ], [ -80.667318692203878, 22.979424546705445 ], [ -80.663442958625637, 22.978804429980414 ], [ -80.659360521271026, 22.9770215932719 ], [ -80.650704719247358, 22.971363022985088 ], [ -80.646131353679039, 22.970484523841662 ], [ -80.640317755559977, 22.971104641466013 ], [ -80.630189175190253, 22.973972682892963 ], [ -80.623006150613321, 22.979424546705445 ], [ -80.618019374794301, 22.987305203272513 ], [ -80.61742509559167, 23.003945013751377 ], [ -80.61817440532451, 23.014280299696054 ], [ -80.61530636299824, 23.03717296056368 ], [ -80.59928666924435, 23.065672512176661 ], [ -80.593095662534779, 23.068032199226593 ] ] ], [ [ [ -79.680083787999934, 22.859442450000074 ], [ -79.666371222999942, 22.852118231000077 ], [ -79.66079667899993, 22.84516022300005 ], [ -79.669829881999931, 22.83624909100007 ], [ -79.685292120999918, 22.833685614000046 ], [ -79.692372199999909, 22.84015534100007 ], [ -79.692290818999936, 22.847154039000088 ], [ -79.695179816999939, 22.850490627000056 ], [ -79.699086066999939, 22.852484442000048 ], [ -79.704579230999911, 22.851752020000049 ], [ -79.711537238999938, 22.853461005000042 ], [ -79.730865037999934, 22.866115627000056 ], [ -79.739857550999943, 22.875799872000073 ], [ -79.738758917999917, 22.885809637000079 ], [ -79.726185675999943, 22.88898346600007 ], [ -79.728260870999918, 22.895331122000073 ], [ -79.727528449999909, 22.903957424000055 ], [ -79.722157355999911, 22.907212632000039 ], [ -79.715443488999938, 22.896144924000055 ], [ -79.718332485999952, 22.880031643000052 ], [ -79.711293097999942, 22.877834377000056 ], [ -79.692005988999938, 22.873928127000056 ], [ -79.68586178299995, 22.865301825000074 ], [ -79.680083787999934, 22.859442450000074 ] ] ], [ [ [ -79.826283331999946, 22.964667059000078 ], [ -79.818470831999946, 22.954331773000035 ], [ -79.81704667899993, 22.947251695000091 ], [ -79.823109503999945, 22.942450262000079 ], [ -79.835072394999941, 22.938950914000088 ], [ -79.842152472999942, 22.931789455000057 ], [ -79.837635870999918, 22.926174221000053 ], [ -79.829009568999936, 22.924750067000048 ], [ -79.827381964999915, 22.919134833000044 ], [ -79.834950324999909, 22.911810614000046 ], [ -79.846506313999896, 22.910345770000049 ], [ -79.858021613999938, 22.916937567000048 ], [ -79.864491339999915, 22.925970770000049 ], [ -79.861480272999927, 22.93195221600007 ], [ -79.855295376999948, 22.936712958000044 ], [ -79.852935350999928, 22.941636460000041 ], [ -79.861887173999946, 22.942938544000071 ], [ -79.871164516999897, 22.947699286000045 ], [ -79.861073370999918, 22.962591864000046 ], [ -79.83853105399993, 22.968085028000075 ], [ -79.826283331999946, 22.964667059000078 ] ] ], [ [ [ -80.061390753999945, 23.049790757000039 ], [ -80.057606574999909, 23.04242584800005 ], [ -80.053578253999945, 23.029201565000051 ], [ -80.056304490999935, 23.026678778000075 ], [ -80.061919725999928, 23.034247137000079 ], [ -80.066558397999927, 23.038885809000078 ], [ -80.070708787999934, 23.038560289000088 ], [ -80.077300584999932, 23.037298895000049 ], [ -80.085357225999928, 23.038316148000035 ], [ -80.091216600999928, 23.042873440000051 ], [ -80.094797329999949, 23.048325914000088 ], [ -80.094471808999913, 23.050685940000051 ], [ -80.091053839999915, 23.049994208000044 ], [ -80.089466925999943, 23.055487372000073 ], [ -80.087635870999918, 23.067450262000079 ], [ -80.076771613999938, 23.069891669000071 ], [ -80.064605272999927, 23.058010158000059 ], [ -80.061390753999945, 23.049790757000039 ] ] ], [ [ [ -80.244699673999946, 23.107489325000074 ], [ -80.242176886999914, 23.104315497000073 ], [ -80.238148566999939, 23.097642320000091 ], [ -80.239409959999932, 23.091009833000044 ], [ -80.244618292999917, 23.085272528000075 ], [ -80.25031490799995, 23.084865627000056 ], [ -80.257069464999915, 23.08930084800005 ], [ -80.261789516999897, 23.096177476000037 ], [ -80.26585852799991, 23.103745835000041 ], [ -80.273793097999942, 23.106268622000073 ], [ -80.288563605999911, 23.114081122000073 ], [ -80.293039516999897, 23.11587148600006 ], [ -80.294748501999948, 23.120428778000075 ], [ -80.296457485999952, 23.122626044000071 ], [ -80.30296790299991, 23.12641022300005 ], [ -80.305734829999949, 23.134507554000038 ], [ -80.296009894999941, 23.140448309000078 ], [ -80.288563605999911, 23.141750393000052 ], [ -80.281117316999939, 23.142320054000038 ], [ -80.272450324999909, 23.140041408000059 ], [ -80.272572394999941, 23.134466864000046 ], [ -80.265533006999931, 23.127427476000037 ], [ -80.250884568999936, 23.115301825000074 ], [ -80.244699673999946, 23.107489325000074 ] ] ], [ [ [ -80.401437954999949, 23.15460846600007 ], [ -80.390004035999937, 23.154486395000049 ], [ -80.376291469999899, 23.152167059000078 ], [ -80.378000454999949, 23.147691148000035 ], [ -80.386097785999937, 23.145819403000075 ], [ -80.393950975999928, 23.146429755000042 ], [ -80.419667120999918, 23.143377997000073 ], [ -80.429269985999952, 23.136216539000088 ], [ -80.444406704999949, 23.130194403000075 ], [ -80.458078579999949, 23.126776434000078 ], [ -80.459787563999896, 23.128607489000046 ], [ -80.462228969999899, 23.135199286000045 ], [ -80.458404100999928, 23.137193101000037 ], [ -80.44945227799991, 23.136216539000088 ], [ -80.451079881999931, 23.145086981000077 ], [ -80.446115688999896, 23.150620835000041 ], [ -80.431792772999927, 23.152533270000049 ], [ -80.42446855399993, 23.152777411000045 ], [ -80.401437954999949, 23.15460846600007 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-04", "NAME_1": "Matanzas" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -80.828236456999946, 23.178900458000044 ], [ -80.820790167999917, 23.178900458000044 ], [ -80.811105923999946, 23.164292710000041 ], [ -80.804798956999946, 23.157538153000075 ], [ -80.804839647999927, 23.152899481000077 ], [ -80.814035610999952, 23.144761460000041 ], [ -80.830637173999946, 23.135646877000056 ], [ -80.842600063999896, 23.136664130000042 ], [ -80.853179490999935, 23.141750393000052 ], [ -80.86554928299995, 23.144761460000041 ], [ -80.897816535999937, 23.141750393000052 ], [ -80.92218990799995, 23.133856512000079 ], [ -80.971669074999909, 23.110663153000075 ], [ -80.960438605999911, 23.122137762000079 ], [ -80.899810350999928, 23.159165757000039 ], [ -80.881947394999941, 23.162787177000041 ], [ -80.862538214999915, 23.162176825000074 ], [ -80.841297980999911, 23.157782294000071 ], [ -80.845204230999911, 23.163234768000052 ], [ -80.850819464999915, 23.173651434000078 ], [ -80.854969855999911, 23.178900458000044 ], [ -80.848133917999917, 23.185126044000071 ], [ -80.843739386999914, 23.178208726000037 ], [ -80.828236456999946, 23.165228583000044 ], [ -80.828236456999946, 23.178900458000044 ] ] ], [ [ [ -80.491851365999935, 23.192572333000044 ], [ -80.486439581999946, 23.193793036000045 ], [ -80.479400193999936, 23.196356512000079 ], [ -80.473378058999913, 23.19603099200009 ], [ -80.470773891999897, 23.188869533000059 ], [ -80.473011847999942, 23.181545315000051 ], [ -80.478911912999934, 23.177435614000046 ], [ -80.486805792999917, 23.173895575000074 ], [ -80.495228644999941, 23.168361721000053 ], [ -80.505279100999928, 23.169745184000078 ], [ -80.522938605999911, 23.176743882000039 ], [ -80.543080206999946, 23.182196356000077 ], [ -80.560170050999943, 23.178900458000044 ], [ -80.564076300999943, 23.184759833000044 ], [ -80.568470831999946, 23.185126044000071 ], [ -80.580637173999946, 23.178900458000044 ], [ -80.576975063999896, 23.192572333000044 ], [ -80.570423956999946, 23.200913804000038 ], [ -80.559681769999941, 23.205064195000091 ], [ -80.543365037999934, 23.206244208000044 ], [ -80.53929602799991, 23.204331773000035 ], [ -80.531361456999946, 23.195461330000057 ], [ -80.525990363999938, 23.192572333000044 ], [ -80.517323370999918, 23.191799221000053 ], [ -80.491851365999935, 23.192572333000044 ] ] ], [ [ [ -81.683914255838204, 23.156927833552686 ], [ -81.658070441999939, 23.156805731000077 ], [ -81.642323370999918, 23.15884023600006 ], [ -81.628977016999897, 23.165228583000044 ], [ -81.617583787999934, 23.15961334800005 ], [ -81.606434699999909, 23.15884023600006 ], [ -81.594593878999945, 23.159328518000052 ], [ -81.581166144999941, 23.157782294000071 ], [ -81.574289516999897, 23.153998114000046 ], [ -81.556792772999927, 23.140814520000049 ], [ -81.535552537999934, 23.129380601000037 ], [ -81.532093878999945, 23.109320380000042 ], [ -81.535308397999927, 23.086330471000053 ], [ -81.540191209999932, 23.069037177000041 ], [ -81.546213344999899, 23.06118398600006 ], [ -81.552398240999935, 23.05735911700009 ], [ -81.552561001999948, 23.054348049000055 ], [ -81.540191209999932, 23.048570054000038 ], [ -81.528797980999911, 23.04718659100007 ], [ -81.517648891999897, 23.049790757000039 ], [ -81.502674933999913, 23.055365302000041 ], [ -81.498768683999913, 23.060492255000042 ], [ -81.492543097999942, 23.084865627000056 ], [ -81.489003058999913, 23.093247789000088 ], [ -81.48070227799991, 23.10032786700009 ], [ -81.47329667899993, 23.102606512000079 ], [ -81.464222785999937, 23.102850653000075 ], [ -81.380116339999915, 23.116359768000052 ], [ -81.368885870999918, 23.120917059000078 ], [ -81.358143683999913, 23.131740627000056 ], [ -81.333363410999937, 23.138251044000071 ], [ -81.286284959999932, 23.144761460000041 ], [ -81.271392381999931, 23.149562893000052 ], [ -81.234242316999939, 23.166449286000045 ], [ -81.209828253999945, 23.183742580000057 ], [ -81.165598110999952, 23.207831122000073 ], [ -81.149159308999913, 23.212388414000088 ], [ -81.130604620999918, 23.205633856000077 ], [ -81.14476477799991, 23.194281317000048 ], [ -81.172434048999946, 23.183661200000074 ], [ -81.217884894999941, 23.172674872000073 ], [ -81.272206183999913, 23.141994533000059 ], [ -81.286284959999932, 23.130519924000055 ], [ -81.286284959999932, 23.124253648000035 ], [ -81.241932745999918, 23.113714911000045 ], [ -81.184885219999899, 23.052069403000075 ], [ -81.149159308999913, 23.034898179000038 ], [ -81.129302537999934, 23.034491278000075 ], [ -81.120716925999943, 23.038967190000051 ], [ -81.113677537999934, 23.049221096000053 ], [ -81.098540818999936, 23.065985419000071 ], [ -81.093739386999914, 23.074204820000091 ], [ -81.083159959999932, 23.098700262000079 ], [ -81.078114386999914, 23.10382721600007 ], [ -81.066761847999942, 23.104966539000088 ], [ -81.046254035999937, 23.109849351000037 ], [ -81.039906378999945, 23.110663153000075 ], [ -80.99836178299995, 23.10382721600007 ], [ -80.991444464999915, 23.104071356000077 ], [ -80.987538214999915, 23.105861721000053 ], [ -80.985707160999937, 23.102240302000041 ], [ -80.985259568999936, 23.086411851000037 ], [ -80.977772589999915, 23.064439195000091 ], [ -80.959380662999934, 23.059027411000045 ], [ -80.936756964999915, 23.062933661000045 ], [ -80.916371222999942, 23.069037177000041 ], [ -80.759348110999952, 23.096991278000075 ], [ -80.734771287999934, 23.097601630000042 ], [ -80.68814042899993, 23.08860911700009 ], [ -80.663156704999949, 23.089544989000046 ], [ -80.642241990999935, 23.097805080000057 ], [ -80.623524542999917, 23.112941799000055 ], [ -80.618031378999945, 23.131740627000056 ], [ -80.636463995999918, 23.15102773600006 ], [ -80.623443162999934, 23.156724351000037 ], [ -80.609852667999917, 23.158189195000091 ], [ -80.597279425999943, 23.156073309000078 ], [ -80.587473110999952, 23.15102773600006 ], [ -80.587473110999952, 23.144761460000041 ], [ -80.59601803299995, 23.13743724200009 ], [ -80.622222459999932, 23.089544989000046 ], [ -80.594349738999938, 23.070135809000078 ], [ -80.593095662534779, 23.068032199226593 ], [ -80.59928666924435, 23.065672512176661 ], [ -80.61530636299824, 23.03717296056368 ], [ -80.61817440532451, 23.014280299696054 ], [ -80.61742509559167, 23.003945013751377 ], [ -80.618019374794301, 22.987305203272513 ], [ -80.623006150613321, 22.979424546705445 ], [ -80.630189175190253, 22.973972682892963 ], [ -80.640317755559977, 22.971104641466013 ], [ -80.646131353679039, 22.970484523841662 ], [ -80.650704719247358, 22.971363022985088 ], [ -80.659360521271026, 22.9770215932719 ], [ -80.663442958625637, 22.978804429980414 ], [ -80.667318692203878, 22.979424546705445 ], [ -80.672667202329535, 22.979088649921266 ], [ -80.677473110995265, 22.978029282725174 ], [ -80.691529099987974, 22.973068346227194 ], [ -80.695792406294515, 22.972603258233789 ], [ -80.720726283591091, 22.973275050902885 ], [ -80.725945604306162, 22.970717067838393 ], [ -80.729382087413398, 22.966402086487108 ], [ -80.732095100108779, 22.956945298786479 ], [ -80.732792731199595, 22.948987127853627 ], [ -80.732224291317948, 22.937825018709646 ], [ -80.728271044273242, 22.922606308834077 ], [ -80.727056647446318, 22.914493110068975 ], [ -80.729666307354194, 22.899997869705885 ], [ -80.735092332744955, 22.892763170084208 ], [ -80.740130785407416, 22.888008938261862 ], [ -80.747158780353402, 22.884288235213887 ], [ -80.748424852225128, 22.880515855322471 ], [ -80.746848721091567, 22.877647812996145 ], [ -80.743050502778487, 22.875735785078405 ], [ -80.739329799730456, 22.873306993223139 ], [ -80.737366095868595, 22.870077215690912 ], [ -80.73633256709428, 22.863514308738331 ], [ -80.734394700754819, 22.85886342970349 ], [ -80.730932380125239, 22.854057521937079 ], [ -80.720726283591091, 22.843696397570682 ], [ -80.714421759956224, 22.835273139543744 ], [ -80.711424527320048, 22.829821274831943 ], [ -80.708530645672738, 22.825893866208958 ], [ -80.704396532374062, 22.822405707157657 ], [ -80.687730881674838, 22.812251288366269 ], [ -80.667473720935448, 22.795973212193985 ], [ -80.651402351237493, 22.7970067409683 ], [ -80.644115973873056, 22.799952296761091 ], [ -80.624298061806087, 22.81341400834981 ], [ -80.604712693735792, 22.82033865050829 ], [ -80.595049201359529, 22.82049367923986 ], [ -80.587659471207587, 22.81747060818202 ], [ -80.584920620090543, 22.813646552346484 ], [ -80.580760668370147, 22.804939073479431 ], [ -80.579572109964886, 22.801580104738036 ], [ -80.57523128929256, 22.792846788348584 ], [ -80.568074104036668, 22.772176215559909 ], [ -80.552984585370325, 22.748224189294888 ], [ -80.550323248619009, 22.740705267933777 ], [ -80.551796026965064, 22.735589300905474 ], [ -80.557015346780815, 22.732721259478524 ], [ -80.566368780794562, 22.728948878687788 ], [ -80.57194983581627, 22.721429959125317 ], [ -80.573138394221473, 22.71571971289444 ], [ -80.571433071878744, 22.711301377856273 ], [ -80.564172532936027, 22.704247545387886 ], [ -80.559625006688691, 22.69740041849451 ], [ -80.557997198711746, 22.690811672220889 ], [ -80.557532110718341, 22.682130031775557 ], [ -80.562648077746587, 22.63515615523238 ], [ -80.561717901759721, 22.627818101024502 ], [ -80.559314948326175, 22.623658149304106 ], [ -80.554844937343944, 22.618981431847601 ], [ -80.549935675890708, 22.611178290545638 ], [ -80.547610235923628, 22.591515408109558 ], [ -80.544768032918398, 22.581386826840571 ], [ -80.540349697880231, 22.571413276101794 ], [ -80.534096849290165, 22.565082913145886 ], [ -80.519679125091557, 22.542009386024347 ], [ -80.539807094621722, 22.529271144847428 ], [ -80.543321092094686, 22.525162869071153 ], [ -80.565257737654463, 22.486870632073988 ], [ -80.571639776554434, 22.47865408052138 ], [ -80.576083950913585, 22.474390774214839 ], [ -80.580192226689917, 22.473563951015535 ], [ -80.588486294406948, 22.472633775028669 ], [ -80.594764981418734, 22.471393541578664 ], [ -80.601560432368046, 22.469223131242472 ], [ -80.623703782603457, 22.45953380044449 ], [ -80.630085822402748, 22.459197902760991 ], [ -80.634891730169215, 22.459766344441221 ], [ -80.644555223444797, 22.462841091443181 ], [ -80.736875170352789, 22.472013658303695 ], [ -80.760336270202686, 22.470204983173403 ], [ -80.767829353142133, 22.470592555901703 ], [ -80.81821387437077, 22.482969061872666 ], [ -80.829272630727303, 22.483356635500286 ], [ -80.83710160955161, 22.482038885885856 ], [ -80.845834926840382, 22.47650950770759 ], [ -80.849684821097583, 22.473512275071414 ], [ -80.861699591862646, 22.466587632912933 ], [ -80.882886928588846, 22.457363390108355 ], [ -80.888984748447342, 22.45379771579195 ], [ -80.900766975215731, 22.443359076160391 ], [ -80.903790046273627, 22.440129299527541 ], [ -80.909112717977564, 22.435633450123589 ], [ -80.921179164686691, 22.427571926403289 ], [ -80.928672247626139, 22.419226182742136 ], [ -80.928388027685287, 22.41736583076846 ], [ -80.925442470993232, 22.415893053321724 ], [ -80.920326503964986, 22.41506623012242 ], [ -80.916373256920281, 22.41333506935797 ], [ -80.91482296420844, 22.411087143756674 ], [ -80.91536556656763, 22.406849676771174 ], [ -80.921721767945201, 22.390519923755448 ], [ -80.925132411731397, 22.383621120917951 ], [ -80.940738695234586, 22.360134181747071 ], [ -80.942986619936562, 22.35491486283064 ], [ -80.941901415218126, 22.352899482125395 ], [ -80.939472621564221, 22.352279365400364 ], [ -80.935545213840555, 22.35261526128528 ], [ -80.930687629230704, 22.35413971647472 ], [ -80.925985074251741, 22.356155097179965 ], [ -80.922781135141236, 22.357188625954279 ], [ -80.919938931236686, 22.357111110689175 ], [ -80.916993373645255, 22.35607758191486 ], [ -80.913427701127489, 22.354088040530655 ], [ -80.91210995061374, 22.350057278220788 ], [ -80.913427701127489, 22.344889635248478 ], [ -80.921230842429395, 22.334037584466955 ], [ -80.924279751009692, 22.328094794239348 ], [ -80.925597499724802, 22.322823798479476 ], [ -80.924331427853076, 22.318793036169666 ], [ -80.921230842429395, 22.312204290795364 ], [ -80.921256679951796, 22.307036647822997 ], [ -80.922574428666962, 22.299155992155306 ], [ -80.927897102169538, 22.285280870315887 ], [ -80.929938321296504, 22.276547553027115 ], [ -80.930946010749778, 22.269106146931108 ], [ -80.929860806031343, 22.260011095335756 ], [ -80.928310513319502, 22.254791775520005 ], [ -80.926372646980042, 22.251510322043714 ], [ -80.923607958340597, 22.249469102017429 ], [ -80.919473843243281, 22.248409735720713 ], [ -80.903324958280166, 22.250218410850948 ], [ -80.89937171123546, 22.250089220541099 ], [ -80.89725297684339, 22.248978176501623 ], [ -80.896219448968395, 22.246704413377984 ], [ -80.89572852165395, 22.242131048708927 ], [ -80.894255744207214, 22.238410346560215 ], [ -80.893248053854563, 22.230142117264904 ], [ -80.897433844896, 22.211486925181418 ], [ -80.855343391384395, 22.183840033390823 ], [ -80.843044399779217, 22.172936305765859 ], [ -80.832269864262798, 22.157536728737 ], [ -80.800773078214945, 22.140741889526566 ], [ -80.765891485903353, 22.127461045990458 ], [ -80.752042201586335, 22.11958039032271 ], [ -80.744781664442257, 22.116944891993171 ], [ -80.741190151704131, 22.116944891993171 ], [ -80.73827043343374, 22.119399522270101 ], [ -80.735660772626545, 22.122448431749717 ], [ -80.732844408042979, 22.124644680507572 ], [ -80.728839484154832, 22.125884914856897 ], [ -80.712923143188505, 22.126453354738487 ], [ -80.705559252357602, 22.127512721934579 ], [ -80.696283331810321, 22.127693589987189 ], [ -80.691219041625459, 22.125600694016782 ], [ -80.684759488359703, 22.119632066266831 ], [ -80.6800310940597, 22.117926743924102 ], [ -80.670729335990075, 22.118340155973385 ], [ -80.656440803000635, 22.121905829390471 ], [ -80.635589362159294, 22.124386298089178 ], [ -80.624711472956108, 22.123507798945752 ], [ -80.61817440532451, 22.121285711766177 ], [ -80.611068895113419, 22.113973496879339 ], [ -80.608200852787093, 22.110020249834633 ], [ -80.606211311402888, 22.105472724486617 ], [ -80.605203620150917, 22.100201727827482 ], [ -80.604790209000953, 22.082786770093321 ], [ -80.602955695448998, 22.07144379289673 ], [ -80.600785285112806, 22.065320136415153 ], [ -80.593421394281904, 22.054313056002741 ], [ -80.593365862034759, 22.05423004999443 ], [ -80.638010219999899, 22.05304596600007 ], [ -80.761097785999937, 22.061102606000077 ], [ -80.905262824999909, 22.046128648000035 ], [ -80.992095506999931, 22.054266669000071 ], [ -81.011626756999931, 22.060532945000091 ], [ -81.049183722999942, 22.07843659100007 ], [ -81.088449673999946, 22.085842190000051 ], [ -81.103667772999927, 22.095892645000049 ], [ -81.113758917999917, 22.111232815000051 ], [ -81.139475063999896, 22.161810614000046 ], [ -81.142974412999934, 22.171535549000055 ], [ -81.143625454999949, 22.187404690000051 ], [ -81.136097785999937, 22.229885158000059 ], [ -81.140695766999897, 22.23273346600007 ], [ -81.167144334999932, 22.270819403000075 ], [ -81.180531378999945, 22.278876044000071 ], [ -81.193959113999938, 22.28156159100007 ], [ -81.205189581999946, 22.27806224200009 ], [ -81.211822068999936, 22.267767645000049 ], [ -81.21157792899993, 22.25531647300005 ], [ -81.19758053299995, 22.212469794000071 ], [ -81.196888800999943, 22.09125397300005 ], [ -81.204701300999943, 22.060288804000038 ], [ -81.225493943999936, 22.061672268000052 ], [ -81.21125240799995, 22.083482164000088 ], [ -81.215443488999938, 22.114976304000038 ], [ -81.229807094999899, 22.143947658000059 ], [ -81.239125128999945, 22.151068427000041 ], [ -81.267079230999911, 22.141587632000039 ], [ -81.273304816999939, 22.137396552000041 ], [ -81.276437954999949, 22.128892320000091 ], [ -81.275257941999939, 22.110256252000056 ], [ -81.27953040299991, 22.102606512000079 ], [ -81.29133053299995, 22.097560940000051 ], [ -81.299305792999917, 22.101263739000046 ], [ -81.306060350999928, 22.107367255000042 ], [ -81.314279751999948, 22.109523830000057 ], [ -81.321522589999915, 22.104722398000035 ], [ -81.322743292999917, 22.097845770000049 ], [ -81.325591600999928, 22.091701565000051 ], [ -81.337880011999914, 22.089016018000052 ], [ -81.374094204999949, 22.10415273600006 ], [ -81.396107550999943, 22.170721747000073 ], [ -81.434071417999917, 22.185777085000041 ], [ -81.482167120999918, 22.185777085000041 ], [ -81.493560350999928, 22.188869533000059 ], [ -81.512806769999941, 22.201971747000073 ], [ -81.523508266999897, 22.205023505000042 ], [ -81.531239386999914, 22.201971747000073 ], [ -81.545887824999909, 22.188869533000059 ], [ -81.557606574999909, 22.185777085000041 ], [ -81.560210740999935, 22.184637762000079 ], [ -81.562123175999943, 22.182074286000045 ], [ -81.565174933999913, 22.179510809000078 ], [ -81.571197068999936, 22.17837148600006 ], [ -81.574330206999946, 22.180121161000045 ], [ -81.576771613999938, 22.188869533000059 ], [ -81.581166144999941, 22.19204336100006 ], [ -81.622710740999935, 22.205023505000042 ], [ -81.627797003999945, 22.207953192000048 ], [ -81.639556443999936, 22.212713934000078 ], [ -81.651478644999941, 22.212958075000074 ], [ -81.656849738999938, 22.201971747000073 ], [ -81.666615363999938, 22.19790273600006 ], [ -81.688628709999932, 22.196844794000071 ], [ -81.711984829999949, 22.199164130000042 ], [ -81.725738084999932, 22.205023505000042 ], [ -81.732004360999952, 22.205023505000042 ], [ -81.73460852799991, 22.192775783000059 ], [ -81.741078253999945, 22.189601955000057 ], [ -81.759917772999927, 22.19204336100006 ], [ -81.756906704999949, 22.188055731000077 ], [ -81.755238410999937, 22.185370184000078 ], [ -81.752512173999946, 22.17837148600006 ], [ -81.763539191999939, 22.178412177000041 ], [ -81.810210740999935, 22.183823960000041 ], [ -81.82445227799991, 22.18891022300005 ], [ -81.849680141999897, 22.214992580000057 ], [ -81.858754035999937, 22.228908596000053 ], [ -81.862375454999949, 22.243557033000059 ], [ -81.879709438999896, 22.26040273600006 ], [ -82.021392381999931, 22.313299872000073 ], [ -82.035878058999913, 22.320990302000041 ], [ -82.05101477799991, 22.332586981000077 ], [ -82.059966600999928, 22.337307033000059 ], [ -82.079904751999948, 22.33930084800005 ], [ -82.088246222999942, 22.342230536000045 ], [ -82.093169725999928, 22.347845770000049 ], [ -82.104644334999932, 22.366197007000039 ], [ -82.105620897999927, 22.370184637000079 ], [ -82.119252081999946, 22.370062567000048 ], [ -82.137603318999936, 22.372137762000079 ], [ -82.15453040299991, 22.379868882000039 ], [ -82.163970506999931, 22.396877346000053 ], [ -82.158384389999924, 22.412534203000064 ], [ -82.146392381999931, 22.42218659100007 ], [ -82.131214972999942, 22.428127346000053 ], [ -82.118737067999916, 22.431827964000036 ], [ -82.003629358999945, 22.428152882000063 ], [ -81.966079797999896, 22.437123578000069 ], [ -81.939472509999916, 22.433215589000042 ], [ -81.909035309999922, 22.43546427800004 ], [ -81.890575232999936, 22.438550096000085 ], [ -81.863891580999905, 22.432626484000082 ], [ -81.841138343999944, 22.430757290000088 ], [ -81.789641646999939, 22.438316738000083 ], [ -81.750070766999897, 22.454006252000056 ], [ -81.738840298999946, 22.452093817000048 ], [ -81.728505011999914, 22.457220770000049 ], [ -81.708729620999918, 22.457180080000057 ], [ -81.697865363999938, 22.459540106000077 ], [ -81.68350178299994, 22.463594853000075 ], [ -81.67030253799993, 22.475948351000056 ], [ -81.660949184999936, 22.484185962000083 ], [ -81.651562644999899, 22.487827104000075 ], [ -81.652803766999909, 22.50878298400005 ], [ -81.648793097999942, 22.51829661700009 ], [ -81.651308485999948, 22.533840785000052 ], [ -81.642648891999897, 22.56195709800005 ], [ -81.643255003999911, 22.572736736000081 ], [ -81.65071455219578, 22.5750738990961 ], [ -81.649231980271679, 22.577162400924067 ], [ -81.648085699895091, 22.578777166932696 ], [ -81.647233039173386, 22.579474798922831 ], [ -81.643925747275375, 22.580870062903045 ], [ -81.639481573815544, 22.583893133960942 ], [ -81.636122605973469, 22.586838691552373 ], [ -81.623358527274206, 22.606010647573328 ], [ -81.614754401194659, 22.616397610361389 ], [ -81.609095831807167, 22.625105089228441 ], [ -81.605917731118382, 22.632468980059343 ], [ -81.603850673569696, 22.639522813427106 ], [ -81.596176724376335, 22.690088201809033 ], [ -81.598088752294075, 22.704971014900423 ], [ -81.614340990044639, 22.718432726489141 ], [ -81.652116462204958, 22.739930121577856 ], [ -81.657981737167404, 22.749361069957388 ], [ -81.6575424866964, 22.764631455777021 ], [ -81.646638759970756, 22.789901230757152 ], [ -81.646638759970756, 22.796128240925555 ], [ -81.650902066277297, 22.801657620003141 ], [ -81.663795336185785, 22.810184230817583 ], [ -81.679169073893604, 22.823568427141197 ], [ -81.695498826909329, 22.850646878150883 ], [ -81.682605557000841, 22.888008938261862 ], [ -81.68009924988047, 22.916586005140005 ], [ -81.679039882684435, 22.920668443393936 ], [ -81.679789190618635, 22.927489731865592 ], [ -81.68066769066138, 22.930667833453754 ], [ -81.692269050276423, 22.946454983210913 ], [ -81.708572963971108, 22.966014512859488 ], [ -81.716427782116455, 22.972758286965359 ], [ -81.723688321059171, 22.97800344520283 ], [ -81.730974698423552, 22.980613105110706 ], [ -81.742007616358421, 22.981853339460031 ], [ -81.745573289775507, 22.983636176168602 ], [ -81.747175259330731, 22.986840115279051 ], [ -81.744643113788641, 22.99456574131591 ], [ -81.743015305811696, 22.998260605942221 ], [ -81.741878425149196, 23.00030182506913 ], [ -81.741387498734071, 23.000973619536921 ], [ -81.735754767768299, 23.005546983306601 ], [ -81.715497606129588, 23.018414414793369 ], [ -81.706195848059906, 23.030403347136769 ], [ -81.702268439436921, 23.031953639848609 ], [ -81.699839646682335, 23.034821682174879 ], [ -81.700098029100729, 23.037663886079486 ], [ -81.704490525717176, 23.043141588313631 ], [ -81.713068814274322, 23.049523627213603 ], [ -81.713688930999353, 23.053270169582618 ], [ -81.711751064659893, 23.058256944502375 ], [ -81.704645555348065, 23.067377835418768 ], [ -81.699477912375755, 23.070142524058213 ], [ -81.694310269403388, 23.070297552789839 ], [ -81.684750128915312, 23.065026557029967 ], [ -81.682062953742332, 23.064096381043157 ], [ -81.680564337873875, 23.064509793092441 ], [ -81.680745205027165, 23.071460272773379 ], [ -81.68257971857912, 23.084172675528521 ], [ -81.695343798177703, 23.136546739040739 ], [ -81.685215216908716, 23.148742376959092 ], [ -81.683914255838204, 23.156927833552686 ] ] ], [ [ [ -81.556263800999943, 22.065985419000071 ], [ -81.549387173999946, 22.058417059000078 ], [ -81.547027147999927, 22.044582424000055 ], [ -81.55492102799991, 22.044012762000079 ], [ -81.565419074999909, 22.049872137000079 ], [ -81.575754360999952, 22.049058335000041 ], [ -81.581857876999948, 22.050604559000078 ], [ -81.586333787999934, 22.056789455000057 ], [ -81.588856574999909, 22.064357815000051 ], [ -81.588856574999909, 22.072699286000045 ], [ -81.582508917999917, 22.076605536000045 ], [ -81.571522589999915, 22.074123440000051 ], [ -81.561146613999938, 22.069159247000073 ], [ -81.556263800999943, 22.065985419000071 ] ] ], [ [ [ -80.668527798999946, 23.212225653000075 ], [ -80.665882941999939, 23.209173895000049 ], [ -80.663644985999952, 23.201402085000041 ], [ -80.666127081999946, 23.194484768000052 ], [ -80.670521613999938, 23.194810289000088 ], [ -80.673695441999939, 23.194037177000041 ], [ -80.674672003999945, 23.186835028000075 ], [ -80.679839647999927, 23.185614325000074 ], [ -80.691314256999931, 23.187730210000041 ], [ -80.698841925999943, 23.18390534100007 ], [ -80.700835740999935, 23.17719147300005 ], [ -80.704253709999932, 23.18032461100006 ], [ -80.704945441999939, 23.193060614000046 ], [ -80.694894985999952, 23.203924872000073 ], [ -80.677601691999939, 23.210272528000075 ], [ -80.668527798999946, 23.212225653000075 ] ] ], [ [ [ -80.775013800999943, 23.206610419000071 ], [ -80.712473110999952, 23.199896552000041 ], [ -80.711008266999897, 23.197007554000038 ], [ -80.711903449999909, 23.190822658000059 ], [ -80.717762824999909, 23.188950914000088 ], [ -80.725168423999946, 23.192775783000059 ], [ -80.732289191999939, 23.193060614000046 ], [ -80.736805792999917, 23.186753648000035 ], [ -80.740834113999938, 23.184271552000041 ], [ -80.762074347999942, 23.193182684000078 ], [ -80.773833787999934, 23.196600653000075 ], [ -80.780751105999911, 23.197699286000045 ], [ -80.799224412999934, 23.195868231000077 ], [ -80.810047980999911, 23.196600653000075 ], [ -80.838490363999938, 23.206244208000044 ], [ -80.848255988999938, 23.208482164000088 ], [ -80.855620897999927, 23.217718817000048 ], [ -80.861439581999946, 23.220363674000055 ], [ -80.857329881999931, 23.225816148000035 ], [ -80.837880011999914, 23.223537502000056 ], [ -80.809925910999937, 23.213812567000048 ], [ -80.775013800999943, 23.206610419000071 ] ] ], [ [ [ -80.878773566999939, 23.250433661000045 ], [ -80.874134894999941, 23.248968817000048 ], [ -80.870920376999948, 23.240383205000057 ], [ -80.878570115999935, 23.232123114000046 ], [ -80.890126105999911, 23.233872789000088 ], [ -80.901234503999945, 23.237209377000056 ], [ -80.913156704999949, 23.238714911000045 ], [ -80.92446855399993, 23.243109442000048 ], [ -80.929432745999918, 23.250148830000057 ], [ -80.933745897999927, 23.254461981000077 ], [ -80.942697719999899, 23.25726959800005 ], [ -80.93586178299995, 23.26312897300005 ], [ -80.912993943999936, 23.265570380000042 ], [ -80.885609503999945, 23.250067450000074 ], [ -80.878773566999939, 23.250433661000045 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-10", "NAME_1": "Las Tunas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -76.944813605999911, 21.45774974200009 ], [ -76.92992102799991, 21.447943427000041 ], [ -76.893706834999932, 21.431626695000091 ], [ -76.838449673999946, 21.420599677000041 ], [ -76.825428839999915, 21.411200262000079 ], [ -76.83226477799991, 21.397528387000079 ], [ -76.811756964999915, 21.397528387000079 ], [ -76.817616339999915, 21.376898505000042 ], [ -76.825550910999937, 21.36664459800005 ], [ -76.837717251999948, 21.363185940000051 ], [ -76.873158331999946, 21.361070054000038 ], [ -76.887440558999913, 21.355658270000049 ], [ -76.897450324999909, 21.346096096000053 ], [ -76.901193813999953, 21.332017320000091 ], [ -76.887277798999946, 21.30735911700009 ], [ -76.83617102799991, 21.332464911000045 ], [ -76.839100714999915, 21.307562567000048 ], [ -76.829457160999937, 21.314113674000055 ], [ -76.825021938999953, 21.324408270000049 ], [ -76.82258053299995, 21.33657461100006 ], [ -76.81859290299991, 21.348537502000056 ], [ -76.825428839999915, 21.348537502000056 ], [ -76.811431443999936, 21.368068752000056 ], [ -76.80728105399993, 21.378119208000044 ], [ -76.805572068999936, 21.39008209800005 ], [ -76.744130011999914, 21.370266018000052 ], [ -76.738392706999946, 21.37055084800005 ], [ -76.730580206999946, 21.374945380000042 ], [ -76.726144985999952, 21.373277085000041 ], [ -76.709339972999942, 21.362779039000088 ], [ -76.68228105399993, 21.356634833000044 ], [ -76.671498175999943, 21.355943101000037 ], [ -76.656076626999948, 21.349554755000042 ], [ -76.642486131999931, 21.335516669000071 ], [ -76.636586066999939, 21.321356512000079 ], [ -76.643910285999937, 21.315008856000077 ], [ -76.660145636999914, 21.311590887000079 ], [ -76.716175910999937, 21.287665106000077 ], [ -76.712310350999928, 21.302639065000051 ], [ -76.721506313999953, 21.311468817000048 ], [ -76.731434699999909, 21.311916408000059 ], [ -76.729847785999937, 21.301336981000077 ], [ -76.73468990799995, 21.285549221000053 ], [ -76.72134355399993, 21.279038804000038 ], [ -76.701161261999914, 21.275864976000037 ], [ -76.685210740999935, 21.269964911000045 ], [ -76.67015540299991, 21.259019273000035 ], [ -76.653309699999909, 21.251898505000042 ], [ -76.634388800999943, 21.247992255000042 ], [ -76.613148566999939, 21.24673086100006 ], [ -76.613148566999939, 21.252915757000039 ], [ -76.634917772999927, 21.26007721600007 ], [ -76.641468878999945, 21.264634507000039 ], [ -76.647328253999945, 21.273382880000042 ], [ -76.654042120999918, 21.28774648600006 ], [ -76.653553839999915, 21.294134833000044 ], [ -76.634266730999911, 21.301336981000077 ], [ -76.616769985999952, 21.301825262000079 ], [ -76.592925584999932, 21.294826565000051 ], [ -76.570790167999917, 21.282416083000044 ], [ -76.557932094999899, 21.266587632000039 ], [ -76.551665818999936, 21.266587632000039 ], [ -76.551665818999936, 21.287665106000077 ], [ -76.544911261999914, 21.287665106000077 ], [ -76.548410610999952, 21.247626044000071 ], [ -76.559885219999899, 21.234523830000057 ], [ -76.613148566999939, 21.232367255000042 ], [ -76.613148566999939, 21.225572007000039 ], [ -76.592681443999936, 21.225572007000039 ], [ -76.602365688999953, 21.220200914000088 ], [ -76.606312628999945, 21.218736070000091 ], [ -76.598255988999938, 21.205877997000073 ], [ -76.588449673999946, 21.206366278000075 ], [ -76.577300584999932, 21.211371161000045 ], [ -76.565337693999936, 21.211981512000079 ], [ -76.556792772999927, 21.205226955000057 ], [ -76.546742316999939, 21.18781159100007 ], [ -76.537464972999942, 21.184637762000079 ], [ -76.532378709999932, 21.186712958000044 ], [ -76.525502081999946, 21.191595770000049 ], [ -76.519520636999914, 21.197251695000091 ], [ -76.516957160999937, 21.202053127000056 ], [ -76.514556443999936, 21.205267645000049 ], [ -76.508941209999932, 21.205471096000053 ], [ -76.502430792999917, 21.204738674000055 ], [ -76.497059699999909, 21.205145575000074 ], [ -76.467640753999945, 21.22134023600006 ], [ -76.456125454999949, 21.225572007000039 ], [ -76.471587693999936, 21.230658270000049 ], [ -76.504261847999942, 21.234808661000045 ], [ -76.516957160999937, 21.239243882000039 ], [ -76.529042120999918, 21.252630927000041 ], [ -76.532378709999932, 21.268622137000079 ], [ -76.525542772999927, 21.282049872000073 ], [ -76.507313605999911, 21.287665106000077 ], [ -76.387562628999945, 21.284328518000052 ], [ -76.363026495999918, 21.277085679000038 ], [ -76.348784959999932, 21.266058661000045 ], [ -76.316517706999946, 21.25421784100007 ], [ -76.313547330045253, 21.251898504712187 ], [ -76.314199387991323, 21.250667018967761 ], [ -76.318075120670244, 21.194262193145676 ], [ -76.325671556397197, 21.177570705823371 ], [ -76.330839200268883, 21.174444281078706 ], [ -76.334740769570828, 21.171059474814911 ], [ -76.339960090285899, 21.164470730339929 ], [ -76.340295987070135, 21.158243720171527 ], [ -76.336859503962899, 21.140337836022297 ], [ -76.338513150361564, 21.134059149909831 ], [ -76.343913337330662, 21.12749624295725 ], [ -76.370836757810139, 21.111709093200091 ], [ -76.392592536216569, 21.103182481486328 ], [ -76.437008429695254, 21.076362412895037 ], [ -76.453079800292528, 21.063598334195774 ], [ -76.458815884045805, 21.060652778402982 ], [ -76.48356889508841, 21.042307643782692 ], [ -76.50245663116857, 21.024195054957829 ], [ -76.514368049146128, 20.996212267282317 ], [ -76.517236090573135, 20.981277778246863 ], [ -76.5207759255685, 20.978409735920536 ], [ -76.527623054260516, 20.977557074299511 ], [ -76.532558153236153, 20.978332221554751 ], [ -76.538423428198655, 20.980399278204118 ], [ -76.547802699734802, 20.979804999001487 ], [ -76.56082516085246, 20.976626899212022 ], [ -76.613586798891617, 20.955181179168051 ], [ -76.629735683854733, 20.951641344172685 ], [ -76.636789517222439, 20.951098740914119 ], [ -76.642809820916511, 20.951563828907581 ], [ -76.647279832798006, 20.953320828093752 ], [ -76.652809210976272, 20.956886502410157 ], [ -76.662756924192706, 20.965309760437094 ], [ -76.674668342170264, 20.970348212200236 ], [ -76.687303228760982, 20.936138414356321 ], [ -76.686347215251772, 20.865496731488975 ], [ -76.687923347284652, 20.851518255962731 ], [ -76.691308152649128, 20.841932277952253 ], [ -76.709575772004257, 20.819608058764857 ], [ -76.71678463410359, 20.806404731393229 ], [ -76.71965267642986, 20.797283840476837 ], [ -76.721125453876596, 20.784287217780843 ], [ -76.720892909879865, 20.776406562113152 ], [ -76.71872250044305, 20.770825507091445 ], [ -76.707818772818086, 20.759534206738238 ], [ -76.702547777058271, 20.752454534948811 ], [ -76.698827074010239, 20.742636012941603 ], [ -76.699473029156934, 20.736564032404146 ], [ -76.702237717796436, 20.732068183000251 ], [ -76.712392136587823, 20.725634467256839 ], [ -76.721900601131836, 20.722301336937107 ], [ -76.762182380412526, 20.706953436751689 ], [ -76.766290656188801, 20.704292100899693 ], [ -76.782878790723601, 20.690985418941921 ], [ -76.793446620665009, 20.695274562770862 ], [ -76.812024299281973, 20.732610785359441 ], [ -76.821300218030615, 20.739767971514652 ], [ -76.836105515856843, 20.743333644931738 ], [ -76.858688116563314, 20.743101100935064 ], [ -76.9012178214453, 20.74785533275741 ], [ -76.92121659976624, 20.747596951238279 ], [ -76.929252285064877, 20.746537584042244 ], [ -76.970955165848238, 20.753565578988287 ], [ -76.993227709091514, 20.746460068777139 ], [ -77.008084682861806, 20.744496364915278 ], [ -77.02162390791699, 20.743953762556089 ], [ -77.03805701372022, 20.738992825158732 ], [ -77.046867845374777, 20.738760281162001 ], [ -77.053456589849702, 20.740879015554128 ], [ -77.068029343679257, 20.750620022296175 ], [ -77.104357875915241, 20.763435776939559 ], [ -77.202491420942295, 20.76614879053426 ], [ -77.225875007325726, 20.772220771071716 ], [ -77.228355476024376, 20.778163560400003 ], [ -77.232205370281577, 20.784209703415058 ], [ -77.238639086024989, 20.784209703415058 ], [ -77.246209683330221, 20.781031601826953 ], [ -77.261815965034771, 20.77056712557237 ], [ -77.268198004834062, 20.767544054514474 ], [ -77.272202927822832, 20.767466539249369 ], [ -77.276259527655043, 20.777026678838126 ], [ -77.281685553945124, 20.782736925069003 ], [ -77.285328741728051, 20.781625881029584 ], [ -77.288119269688536, 20.777078354782248 ], [ -77.289359504037861, 20.766407172053334 ], [ -77.291349047220763, 20.760619412355993 ], [ -77.293726162232588, 20.755735989324421 ], [ -77.303673876348284, 20.744961452908683 ], [ -77.307265388187091, 20.739302883521248 ], [ -77.309616664777252, 20.73297252056534 ], [ -77.310779384760792, 20.730595405553515 ], [ -77.312717251100253, 20.728399155896284 ], [ -77.316851366197568, 20.726022039985139 ], [ -77.332405971958053, 20.719226589035827 ], [ -77.336540087055369, 20.716436061974662 ], [ -77.33668027431905, 20.71633924892582 ], [ -77.343129035999937, 20.718491929000038 ], [ -77.37173417899993, 20.716131903000075 ], [ -77.403187628999945, 20.709173895000049 ], [ -77.429351365999935, 20.698431708000044 ], [ -77.442372199999909, 20.684393622000073 ], [ -77.451893683999913, 20.690008856000077 ], [ -77.45767167899993, 20.689886786000045 ], [ -77.462717251999948, 20.686997789000088 ], [ -77.469715949999909, 20.684393622000073 ], [ -77.480295376999948, 20.681789455000057 ], [ -77.486724412999934, 20.679185289000088 ], [ -77.493397589999915, 20.677476304000038 ], [ -77.504505988999938, 20.677557684000078 ], [ -77.521962042999917, 20.68032461100006 ], [ -77.572743292999917, 20.69798411700009 ], [ -77.61164303299995, 20.67845286700009 ], [ -77.620513475999928, 20.677557684000078 ], [ -77.63499915299991, 20.687933661000045 ], [ -77.641713019999941, 20.691148179000038 ], [ -77.649281378999945, 20.692572333000044 ], [ -77.678863084999932, 20.691148179000038 ], [ -77.686675584999932, 20.69204336100006 ], [ -77.706125454999949, 20.697414455000057 ], [ -77.712717251999948, 20.701117255000042 ], [ -77.716420050999943, 20.698879299000055 ], [ -77.729318813999953, 20.69798411700009 ], [ -77.778431769999941, 20.700751044000071 ], [ -77.79556230399993, 20.705877997000073 ], [ -77.822132941999939, 20.723049221000053 ], [ -77.831130344456355, 20.725558300366398 ], [ -77.831109382392071, 20.725686143200903 ], [ -77.817725186068458, 20.807309068059055 ], [ -77.765790371228661, 20.876193753538871 ], [ -77.742174241747819, 20.874669298349431 ], [ -77.68117021373439, 20.885728053806645 ], [ -77.666029019123926, 20.891515815302625 ], [ -77.658096685713474, 20.896864325428282 ], [ -77.658690964916104, 20.902652086024943 ], [ -77.658535936184478, 20.909680080970929 ], [ -77.657528245831884, 20.917483222272892 ], [ -77.653316617268047, 20.933657944758352 ], [ -77.652644822800312, 20.939394029410892 ], [ -77.653523321943737, 20.9457502298892 ], [ -77.655151129920682, 20.952183946531875 ], [ -77.655125292398338, 20.960142117464727 ], [ -77.647425502984561, 20.965154730806148 ], [ -77.640810920087858, 20.966239936423904 ], [ -77.635281541909592, 20.964017849244328 ], [ -77.629778002153046, 20.956989854298342 ], [ -77.625876431052461, 20.95078868345098 ], [ -77.620812140867599, 20.944432481174033 ], [ -77.617013922554463, 20.941331894851032 ], [ -77.611510382797917, 20.940479234129327 ], [ -77.600141568078868, 20.939781602139192 ], [ -77.594973924207238, 20.938644721476692 ], [ -77.587351650957885, 20.937792059855667 ], [ -77.58422522711254, 20.940272529453637 ], [ -77.582261522351359, 20.943347276455654 ], [ -77.5823131991948, 20.955982163945691 ], [ -77.576990525692167, 20.969443875534409 ], [ -77.566913622165941, 20.974689031973242 ], [ -77.546656459627911, 20.980270086994892 ], [ -77.532187058585862, 20.982285467700137 ], [ -77.529396532424016, 20.996909898373076 ], [ -77.526786871616821, 21.000139675005983 ], [ -77.524177211708945, 21.000217190271087 ], [ -77.511361457065561, 20.999364529549382 ], [ -77.497925584797883, 21.000682278264492 ], [ -77.479735479808539, 21.004092922050688 ], [ -77.473172573755278, 21.011999417039476 ], [ -77.469994473066492, 21.018949896720358 ], [ -77.468935105870401, 21.025848700457118 ], [ -77.464826830094125, 21.034582016846571 ], [ -77.464749314829021, 21.035951443304441 ], [ -77.467074754796101, 21.043522039710354 ], [ -77.46777238588686, 21.047862861281999 ], [ -77.467901577096086, 21.053676459401061 ], [ -77.465963710756625, 21.056957912877351 ], [ -77.46239803733954, 21.059386704732617 ], [ -77.44792863629749, 21.066078802894424 ], [ -77.441055670982394, 21.073907781718731 ], [ -77.437670864718598, 21.076104031375905 ], [ -77.436120572006757, 21.076259060107532 ], [ -77.435629644692312, 21.074166165036445 ], [ -77.434492764029812, 21.071685696337795 ], [ -77.432864956052867, 21.06910187395232 ], [ -77.428627489067367, 21.063805039770727 ], [ -77.42560441800947, 21.060652778402982 ], [ -77.416922776664819, 21.048172918745195 ], [ -77.414907395959517, 21.043573717453057 ], [ -77.414054735237812, 21.038974514362337 ], [ -77.414519823231217, 21.03303172503405 ], [ -77.413693000031913, 21.030499579491959 ], [ -77.411419236908216, 21.02845836036505 ], [ -77.393926764808327, 21.024220893379493 ], [ -77.377235276586759, 21.023032334974289 ], [ -77.368786180138102, 21.021585395049897 ], [ -77.36390275710653, 21.020112615804578 ], [ -77.361835699557901, 21.017477118374302 ], [ -77.361525642094705, 21.015203355250605 ], [ -77.362326625972969, 21.012516180976945 ], [ -77.368967048190711, 21.003085231698094 ], [ -77.369664680180847, 21.000243027793488 ], [ -77.369793871390016, 20.997116603948086 ], [ -77.366641608223631, 20.990450344208 ], [ -77.356590542219749, 20.980657659723192 ], [ -77.346306932219136, 21.001509101463853 ], [ -77.339692349322434, 21.006573390749395 ], [ -77.333646206307378, 21.009493109919049 ], [ -77.328995327272537, 21.008485419566455 ], [ -77.324292772293575, 21.005255642034228 ], [ -77.314267543812093, 20.996186427961277 ], [ -77.308298916062085, 20.993395900900111 ], [ -77.300082363610159, 20.991147976198135 ], [ -77.291839972736511, 20.995023708877056 ], [ -77.263004523439974, 21.059903469569463 ], [ -77.248948534447266, 21.078351956077881 ], [ -77.237088793313148, 21.083648790259474 ], [ -77.227735358400082, 21.089178168437684 ], [ -77.222722744159285, 21.091219387564649 ], [ -77.193473883712727, 21.097110500948816 ], [ -77.18698849202525, 21.099048367288276 ], [ -77.174069382795778, 21.109538682863899 ], [ -77.167558152686581, 21.116825059329017 ], [ -77.131126267663092, 21.17351410599116 ], [ -77.135518765178858, 21.238083808321107 ], [ -77.134795294767002, 21.244930935214484 ], [ -77.129705166160477, 21.256687323561096 ], [ -77.073248664394328, 21.305521552077948 ], [ -77.071672533260767, 21.309164739860819 ], [ -77.073687913966069, 21.31265289981144 ], [ -77.079501512085074, 21.314099839735775 ], [ -77.117793749082239, 21.313893134160821 ], [ -77.122289597586871, 21.316838690852876 ], [ -77.127147183095985, 21.322703965815379 ], [ -77.131591355656496, 21.339111233196832 ], [ -77.130738694934792, 21.348490504732979 ], [ -77.124666714397335, 21.361461289906572 ], [ -77.116346809157903, 21.37068553271115 ], [ -77.10048214413564, 21.416470851748386 ], [ -77.080690069591014, 21.414326279833915 ], [ -77.057461513737849, 21.409029446551699 ], [ -77.039555629588619, 21.4098045920083 ], [ -77.012425502634812, 21.41616079428519 ], [ -76.999738939200654, 21.421638494720753 ], [ -76.971265225110017, 21.442464098039693 ], [ -76.955374721666033, 21.448432725789644 ], [ -76.947209846057547, 21.455796617519866 ], [ -76.944813605999911, 21.45774974200009 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-16", "NAME_1": "Mayabeque" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -82.100088300334789, 23.187648537050336 ], [ -82.088246222999942, 23.190415757000039 ], [ -82.065012173999946, 23.192572333000044 ], [ -82.05492102799991, 23.19476959800005 ], [ -82.044016079999949, 23.198716539000088 ], [ -82.033192511999914, 23.200506903000075 ], [ -82.023426886999914, 23.19594961100006 ], [ -81.985829230999911, 23.171454169000071 ], [ -81.956125454999949, 23.163641669000071 ], [ -81.892079230999911, 23.157863674000055 ], [ -81.862375454999949, 23.15102773600006 ], [ -81.84007727799991, 23.157782294000071 ], [ -81.683914255838204, 23.156927833552686 ], [ -81.685215216908716, 23.148742376959092 ], [ -81.695343798177703, 23.136546739040739 ], [ -81.68257971857912, 23.084172675528521 ], [ -81.680745205027165, 23.071460272773379 ], [ -81.680564337873875, 23.064509793092441 ], [ -81.682062953742332, 23.064096381043157 ], [ -81.684750128915312, 23.065026557029967 ], [ -81.694310269403388, 23.070297552789839 ], [ -81.699477912375755, 23.070142524058213 ], [ -81.704645555348065, 23.067377835418768 ], [ -81.711751064659893, 23.058256944502375 ], [ -81.713688930999353, 23.053270169582618 ], [ -81.713068814274322, 23.049523627213603 ], [ -81.704490525717176, 23.043141588313631 ], [ -81.700098029100729, 23.037663886079486 ], [ -81.699839646682335, 23.034821682174879 ], [ -81.702268439436921, 23.031953639848609 ], [ -81.706195848059906, 23.030403347136769 ], [ -81.715497606129588, 23.018414414793369 ], [ -81.735754767768299, 23.005546983306601 ], [ -81.741387498734071, 23.000973619536921 ], [ -81.741878425149196, 23.00030182506913 ], [ -81.743015305811696, 22.998260605942221 ], [ -81.744643113788641, 22.99456574131591 ], [ -81.747175259330731, 22.986840115279051 ], [ -81.745573289775507, 22.983636176168602 ], [ -81.742007616358421, 22.981853339460031 ], [ -81.730974698423552, 22.980613105110706 ], [ -81.723688321059171, 22.97800344520283 ], [ -81.716427782116455, 22.972758286965359 ], [ -81.708572963971108, 22.966014512859488 ], [ -81.692269050276423, 22.946454983210913 ], [ -81.68066769066138, 22.930667833453754 ], [ -81.679789190618635, 22.927489731865592 ], [ -81.679039882684435, 22.920668443393936 ], [ -81.68009924988047, 22.916586005140005 ], [ -81.682605557000841, 22.888008938261862 ], [ -81.695498826909329, 22.850646878150883 ], [ -81.679169073893604, 22.823568427141197 ], [ -81.663795336185785, 22.810184230817583 ], [ -81.650902066277297, 22.801657620003141 ], [ -81.646638759970756, 22.796128240925555 ], [ -81.646638759970756, 22.789901230757152 ], [ -81.6575424866964, 22.764631455777021 ], [ -81.657981737167404, 22.749361069957388 ], [ -81.652116462204958, 22.739930121577856 ], [ -81.614340990044639, 22.718432726489141 ], [ -81.598088752294075, 22.704971014900423 ], [ -81.596176724376335, 22.690088201809033 ], [ -81.603850673569696, 22.639522813427106 ], [ -81.605917731118382, 22.632468980059343 ], [ -81.609095831807167, 22.625105089228441 ], [ -81.614754401194659, 22.616397610361389 ], [ -81.623358527274206, 22.606010647573328 ], [ -81.636122605973469, 22.586838691552373 ], [ -81.639481573815544, 22.583893133960942 ], [ -81.643925747275375, 22.580870062903045 ], [ -81.647233039173386, 22.579474798922831 ], [ -81.648085699895091, 22.578777166932696 ], [ -81.649231980271679, 22.577162400924067 ], [ -81.65071455219578, 22.5750738990961 ], [ -81.65767724299991, 22.577255391000051 ], [ -81.672631177999904, 22.577679783000065 ], [ -81.700021938999896, 22.599595445000091 ], [ -81.718848665999928, 22.613702271000079 ], [ -81.753385962999914, 22.638036906000082 ], [ -81.788412189999917, 22.650097021000079 ], [ -81.877500934999944, 22.679730389000042 ], [ -81.91242428299995, 22.678534247000073 ], [ -81.992543097999942, 22.671698309000078 ], [ -82.098793446999935, 22.65492148800007 ], [ -82.130970831999946, 22.667873440000051 ], [ -82.198855197999933, 22.685773595000057 ], [ -82.274841361999904, 22.685616806000041 ], [ -82.317209438999896, 22.680975653000075 ], [ -82.339019334999932, 22.678656317000048 ], [ -82.359852667999917, 22.680812893000052 ], [ -82.391583815999923, 22.688420458000053 ], [ -82.387950241810188, 22.709693630156892 ], [ -82.39129437983172, 22.722239080968791 ], [ -82.404351811986544, 22.729922232924707 ], [ -82.41694692426114, 22.736723887397488 ], [ -82.437375403152316, 22.763280910585536 ], [ -82.457803882043493, 22.802095020568743 ], [ -82.457803882043493, 22.838866281853427 ], [ -82.449632490846739, 22.871551848439026 ], [ -82.437375403152316, 22.896066022928608 ], [ -82.437375403152316, 22.922623045217335 ], [ -82.435918748751249, 22.957281196470035 ], [ -82.419692349422348, 22.963379015429211 ], [ -82.412070075273732, 22.965471910500241 ], [ -82.405016241906026, 22.961234443514741 ], [ -82.394319220755392, 22.948987127853627 ], [ -82.388789841677863, 22.947850247191127 ], [ -82.381865201317964, 22.950614935830629 ], [ -82.368687709670041, 22.961441148190431 ], [ -82.36481197789044, 22.968417467192353 ], [ -82.355820279082593, 22.976685696487664 ], [ -82.316649542942059, 22.973300890223868 ], [ -82.290888840647483, 22.97490285887983 ], [ -82.280321010706075, 22.970562039106824 ], [ -82.270399135911362, 22.969321803858122 ], [ -82.258539394777245, 22.969399319123283 ], [ -82.249831915910192, 22.972577419812069 ], [ -82.24378577289508, 22.980251369904806 ], [ -82.236137661224063, 22.993170478234958 ], [ -82.202134568955159, 23.028129584013072 ], [ -82.201256069811734, 23.031798611116983 ], [ -82.202599656948621, 23.036552842939329 ], [ -82.211022914975558, 23.052650051059004 ], [ -82.212573207687342, 23.061331692403655 ], [ -82.212211473380762, 23.067739569725347 ], [ -82.209782680626176, 23.076188666174005 ], [ -82.209033372691977, 23.081227117937146 ], [ -82.209265916688707, 23.086110540968662 ], [ -82.210816210299868, 23.089908759281798 ], [ -82.211436327024842, 23.092725124764684 ], [ -82.210351122306406, 23.094146226267299 ], [ -82.204615037653866, 23.094533799894919 ], [ -82.199059821053879, 23.088978583294988 ], [ -82.191928474219708, 23.079599310859464 ], [ -82.188543667056592, 23.079056708500275 ], [ -82.182730068937531, 23.082699897182465 ], [ -82.176218837929014, 23.088358466569957 ], [ -82.171206223688273, 23.100864162850826 ], [ -82.170121018969837, 23.106186835454082 ], [ -82.168338182261266, 23.109468288930373 ], [ -82.164875860732366, 23.112491359988269 ], [ -82.160767584956091, 23.113809108703379 ], [ -82.151879238935692, 23.109674994505383 ], [ -82.14606563991731, 23.105902615513287 ], [ -82.110977342030708, 23.067610379415441 ], [ -82.101339688076109, 23.084017645897632 ], [ -82.099970261618239, 23.100941677216611 ], [ -82.098833380955739, 23.105463365042226 ], [ -82.09637874977949, 23.108279731424432 ], [ -82.090952725288048, 23.112543035932333 ], [ -82.090022549301182, 23.116832179761275 ], [ -82.092761400418283, 23.125798041046721 ], [ -82.093200649989967, 23.131430772012493 ], [ -82.090797695657102, 23.134970607907235 ], [ -82.081366747277571, 23.135384019057199 ], [ -82.076199104305203, 23.139388942945345 ], [ -82.092993944415014, 23.158896795750479 ], [ -82.098574999436664, 23.167888495457703 ], [ -82.096869676194558, 23.177913723039865 ], [ -82.100088300334789, 23.187648537050336 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-03", "NAME_1": "Ciudad de la Habana" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -82.538736165592212, 23.073564129558381 ], [ -82.532093878999945, 23.077093817000048 ], [ -82.50999915299991, 23.083319403000075 ], [ -82.504465298999946, 23.086493231000077 ], [ -82.494536912999934, 23.100653387000079 ], [ -82.489572719999899, 23.10382721600007 ], [ -82.47720292899993, 23.105169989000046 ], [ -82.467681443999936, 23.108547268000052 ], [ -82.452015753999945, 23.11749909100007 ], [ -82.422352667999917, 23.138861395000049 ], [ -82.40689042899993, 23.147447007000039 ], [ -82.367095506999931, 23.153021552000041 ], [ -82.321034308999913, 23.171454169000071 ], [ -82.251088019999941, 23.182114976000037 ], [ -82.219349738999938, 23.194240627000056 ], [ -82.150298631999931, 23.178900458000044 ], [ -82.128407355999911, 23.181057033000059 ], [ -82.100088300334789, 23.187648537050336 ], [ -82.096869676194558, 23.177913723039865 ], [ -82.098574999436664, 23.167888495457703 ], [ -82.092993944415014, 23.158896795750479 ], [ -82.076199104305203, 23.139388942945345 ], [ -82.081366747277571, 23.135384019057199 ], [ -82.090797695657102, 23.134970607907235 ], [ -82.093200649989967, 23.131430772012493 ], [ -82.092761400418283, 23.125798041046721 ], [ -82.090022549301182, 23.116832179761275 ], [ -82.090952725288048, 23.112543035932333 ], [ -82.09637874977949, 23.108279731424432 ], [ -82.098833380955739, 23.105463365042226 ], [ -82.099970261618239, 23.100941677216611 ], [ -82.101339688076109, 23.084017645897632 ], [ -82.110977342030708, 23.067610379415441 ], [ -82.14606563991731, 23.105902615513287 ], [ -82.151879238935692, 23.109674994505383 ], [ -82.160767584956091, 23.113809108703379 ], [ -82.164875860732366, 23.112491359988269 ], [ -82.168338182261266, 23.109468288930373 ], [ -82.170121018969837, 23.106186835454082 ], [ -82.171206223688273, 23.100864162850826 ], [ -82.176218837929014, 23.088358466569957 ], [ -82.182730068937531, 23.082699897182465 ], [ -82.188543667056592, 23.079056708500275 ], [ -82.191928474219708, 23.079599310859464 ], [ -82.199059821053879, 23.088978583294988 ], [ -82.204615037653866, 23.094533799894919 ], [ -82.210351122306406, 23.094146226267299 ], [ -82.211436327024842, 23.092725124764684 ], [ -82.210816210299868, 23.089908759281798 ], [ -82.209265916688707, 23.086110540968662 ], [ -82.209033372691977, 23.081227117937146 ], [ -82.209782680626176, 23.076188666174005 ], [ -82.212211473380762, 23.067739569725347 ], [ -82.212573207687342, 23.061331692403655 ], [ -82.211022914975558, 23.052650051059004 ], [ -82.202599656948621, 23.036552842939329 ], [ -82.201256069811734, 23.031798611116983 ], [ -82.202134568955159, 23.028129584013072 ], [ -82.236137661224063, 22.993170478234958 ], [ -82.24378577289508, 22.980251369904806 ], [ -82.249831915910192, 22.972577419812069 ], [ -82.258539394777245, 22.969399319123283 ], [ -82.270399135911362, 22.969321803858122 ], [ -82.280321010706075, 22.970562039106824 ], [ -82.290888840647483, 22.97490285887983 ], [ -82.316649542942059, 22.973300890223868 ], [ -82.355820279082593, 22.976685696487664 ], [ -82.36481197789044, 22.968417467192353 ], [ -82.368687709670041, 22.961441148190431 ], [ -82.381865201317964, 22.950614935830629 ], [ -82.388789841677863, 22.947850247191127 ], [ -82.394319220755392, 22.948987127853627 ], [ -82.405016241906026, 22.961234443514741 ], [ -82.412070075273732, 22.965471910500241 ], [ -82.419692349422348, 22.963379015429211 ], [ -82.435918748751249, 22.957281196470035 ], [ -82.445117154033426, 22.990612494271204 ], [ -82.44728756436956, 22.993041287025733 ], [ -82.450801560943262, 22.99554759414616 ], [ -82.452997809701117, 22.994488226950068 ], [ -82.455529955243207, 22.994255682953394 ], [ -82.492246060207492, 23.008802599260548 ], [ -82.499713303825899, 23.013918565389474 ], [ -82.502968919779789, 23.0182593860618 ], [ -82.50203874379298, 23.020429796397991 ], [ -82.482143317360169, 23.03601024058014 ], [ -82.473642544068127, 23.047714952083368 ], [ -82.474986132104277, 23.056861681421424 ], [ -82.485011358787176, 23.069548244855582 ], [ -82.492995368141692, 23.071615302404268 ], [ -82.499894171878509, 23.069935818483202 ], [ -82.50532019726927, 23.065439968179987 ], [ -82.517205776825108, 23.059729722848431 ], [ -82.534414028984258, 23.066757716895097 ], [ -82.538736165592212, 23.073564129558381 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-15", "NAME_1": "Artemisa" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -82.944424028446122, 22.985082820215951 ], [ -82.942453579999949, 22.986314195000091 ], [ -82.931752081999946, 23.011053778000075 ], [ -82.917591925999943, 23.032456773000035 ], [ -82.885161912999934, 23.033107815000051 ], [ -82.849354620999918, 23.027777411000045 ], [ -82.825306769999941, 23.031480210000041 ], [ -82.803293423999946, 23.038804429000038 ], [ -82.712717251999948, 23.034898179000038 ], [ -82.619984503999945, 23.046128648000035 ], [ -82.59601803299995, 23.055365302000041 ], [ -82.575510219999899, 23.054022528000075 ], [ -82.538736165592212, 23.073564129558381 ], [ -82.534414028984258, 23.066757716895097 ], [ -82.517205776825108, 23.059729722848431 ], [ -82.50532019726927, 23.065439968179987 ], [ -82.499894171878509, 23.069935818483202 ], [ -82.492995368141692, 23.071615302404268 ], [ -82.485011358787176, 23.069548244855582 ], [ -82.474986132104277, 23.056861681421424 ], [ -82.473642544068127, 23.047714952083368 ], [ -82.482143317360169, 23.03601024058014 ], [ -82.50203874379298, 23.020429796397991 ], [ -82.502968919779789, 23.0182593860618 ], [ -82.499713303825899, 23.013918565389474 ], [ -82.492246060207492, 23.008802599260548 ], [ -82.455529955243207, 22.994255682953394 ], [ -82.452997809701117, 22.994488226950068 ], [ -82.450801560943262, 22.99554759414616 ], [ -82.44728756436956, 22.993041287025733 ], [ -82.445117154033426, 22.990612494271204 ], [ -82.435918748751249, 22.957281196470035 ], [ -82.437375403152316, 22.922623045217335 ], [ -82.437375403152316, 22.896066022928608 ], [ -82.449632490846739, 22.871551848439026 ], [ -82.457803882043493, 22.838866281853427 ], [ -82.457803882043493, 22.802095020568743 ], [ -82.437375403152316, 22.763280910585536 ], [ -82.41694692426114, 22.736723887397488 ], [ -82.404351811986544, 22.729922232924707 ], [ -82.39129437983172, 22.722239080968791 ], [ -82.387950241810188, 22.709693630156892 ], [ -82.391583815999923, 22.688420458000053 ], [ -82.45735629099994, 22.68038488600007 ], [ -82.50999915299991, 22.692287502000056 ], [ -82.52171790299991, 22.69017161700009 ], [ -82.541086391999897, 22.680812893000052 ], [ -82.550933397999927, 22.678656317000048 ], [ -82.597418005999941, 22.688008495000076 ], [ -82.632945362999919, 22.680184949000079 ], [ -82.738433397999927, 22.706366278000075 ], [ -82.759877081999946, 22.705959377000056 ], [ -82.780669725999928, 22.696112372000073 ], [ -82.790882941999939, 22.679877020000049 ], [ -82.794300910999937, 22.66046784100007 ], [ -82.794585740999935, 22.640814520000049 ], [ -82.800689256999931, 22.622748114000046 ], [ -82.815419074999909, 22.613430080000057 ], [ -82.824601541721293, 22.610579205774144 ], [ -82.82501644575234, 22.61451141996605 ], [ -82.828013679287835, 22.620376694928495 ], [ -82.835765143746357, 22.631228745710018 ], [ -82.868863897550796, 22.665748602815768 ], [ -82.873437263119172, 22.673603420061795 ], [ -82.893151822398693, 22.71626231525363 ], [ -82.900644904438764, 22.728561305959488 ], [ -82.907078620182176, 22.736752020889014 ], [ -82.912737188670292, 22.740705267933777 ], [ -82.921883918008405, 22.745433661334403 ], [ -82.92544959232481, 22.747914130033053 ], [ -82.937567714978059, 22.762977810277732 ], [ -82.954078335147017, 22.789306952453899 ], [ -82.959090949387814, 22.795637315409749 ], [ -82.963095873275904, 22.79912547536037 ], [ -82.974257982419942, 22.803698839130107 ], [ -82.976428391856757, 22.805300807786011 ], [ -82.978030362311358, 22.807109482916303 ], [ -82.976635098331087, 22.809047350155083 ], [ -82.971906704031142, 22.810830185964278 ], [ -82.947567105037876, 22.81341400834981 ], [ -82.939712286892529, 22.816152859466854 ], [ -82.934544643920162, 22.820235296821465 ], [ -82.915941127780798, 22.840569972825961 ], [ -82.914675055909072, 22.849509995689743 ], [ -82.919170905313024, 22.873772081216543 ], [ -82.944389004349034, 22.91898895947287 ], [ -82.940849169353669, 22.93885854748396 ], [ -82.940823330032629, 22.943431912153017 ], [ -82.945396694701685, 22.979579576336334 ], [ -82.944424028446122, 22.985082820215951 ] ] ], [ [ [ -82.514475063999896, 22.625148830000057 ], [ -82.510812954999949, 22.613185940000051 ], [ -82.507720506999931, 22.590073960000041 ], [ -82.513579881999931, 22.572455145000049 ], [ -82.518788214999915, 22.565741278000075 ], [ -82.522857225999928, 22.55931224200009 ], [ -82.527455206999946, 22.563462632000039 ], [ -82.525298631999931, 22.626369533000059 ], [ -82.527821417999917, 22.634751695000091 ], [ -82.528309699999909, 22.640041408000059 ], [ -82.524566209999932, 22.640855210000041 ], [ -82.51976477799991, 22.636664130000042 ], [ -82.51593990799995, 22.629136460000041 ], [ -82.514475063999896, 22.625148830000057 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-01", "NAME_1": "Pinar del Río" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -82.824601541721293, 22.610579205774144 ], [ -82.849232550999943, 22.602932033000059 ], [ -82.909291144999941, 22.555568752000056 ], [ -82.921254035999937, 22.54828522300005 ], [ -82.943959113999938, 22.546576239000046 ], [ -82.959380662999934, 22.542059637000079 ], [ -83.025990363999938, 22.509751695000091 ], [ -83.058705206999946, 22.489447333000044 ], [ -83.086089647999927, 22.462795315000051 ], [ -83.143177863999938, 22.361273505000042 ], [ -83.166859503999945, 22.339544989000046 ], [ -83.199330206999946, 22.336004950000074 ], [ -83.232248501999948, 22.344794012000079 ], [ -83.245838995999918, 22.345933335000041 ], [ -83.260121222999942, 22.342230536000045 ], [ -83.260568813999896, 22.339748440000051 ], [ -83.260121222999942, 22.325751044000071 ], [ -83.261789516999897, 22.321966864000046 ], [ -83.265695766999897, 22.322251695000091 ], [ -83.270253058999913, 22.323553778000075 ], [ -83.277455206999946, 22.32103099200009 ], [ -83.281971808999913, 22.322333075000074 ], [ -83.28579667899993, 22.322699286000045 ], [ -83.28742428299995, 22.31867096600007 ], [ -83.286936001999948, 22.304632880000042 ], [ -83.28742428299995, 22.301906643000052 ], [ -83.323597785999937, 22.280218817000048 ], [ -83.335804816999939, 22.267767645000049 ], [ -83.341175910999937, 22.259344794000071 ], [ -83.34203040299991, 22.25454336100006 ], [ -83.341460740999935, 22.251044012000079 ], [ -83.342640753999945, 22.246649481000077 ], [ -83.349232550999943, 22.232163804000038 ], [ -83.354115363999938, 22.225775458000044 ], [ -83.363148566999939, 22.219305731000077 ], [ -83.366363084999932, 22.222398179000038 ], [ -83.367909308999913, 22.225572007000039 ], [ -83.368478969999899, 22.213853257000039 ], [ -83.375559048999946, 22.206976630000042 ], [ -83.381147589999898, 22.217147133000083 ], [ -83.389440523999951, 22.220365092000065 ], [ -83.398222607999912, 22.21928046000005 ], [ -83.398991226999897, 22.202831413000069 ], [ -83.415472436999949, 22.186093371000084 ], [ -83.465321417999917, 22.182074286000045 ], [ -83.516957160999937, 22.18821849200009 ], [ -83.561146613999938, 22.205023505000042 ], [ -83.552845831999946, 22.213446356000077 ], [ -83.555490688999896, 22.223618882000039 ], [ -83.562855597999942, 22.234849351000037 ], [ -83.56859290299991, 22.246649481000077 ], [ -83.575428839999915, 22.246649481000077 ], [ -83.589588995999918, 22.219916083000044 ], [ -83.614369269999941, 22.195746161000045 ], [ -83.643625454999949, 22.178290106000077 ], [ -83.671009894999941, 22.171535549000055 ], [ -83.668934699999909, 22.175034898000035 ], [ -83.666737433999913, 22.18195221600007 ], [ -83.664784308999913, 22.185777085000041 ], [ -83.775461391999897, 22.170721747000073 ], [ -83.780873175999943, 22.171535549000055 ], [ -83.784779425999943, 22.175441799000055 ], [ -83.787505662999934, 22.18235911700009 ], [ -83.788726365999935, 22.189032294000071 ], [ -83.787709113999938, 22.19204336100006 ], [ -83.79914303299995, 22.188788153000075 ], [ -83.811024542999917, 22.174750067000048 ], [ -83.825550910999937, 22.171535549000055 ], [ -83.903228318999936, 22.175685940000051 ], [ -83.925445115999935, 22.171535549000055 ], [ -83.966460740999935, 22.133978583000044 ], [ -83.967681443999936, 22.126369533000059 ], [ -83.975331183999913, 22.098822333000044 ], [ -83.980091925999943, 22.089016018000052 ], [ -83.97484290299991, 22.082464911000045 ], [ -83.97329667899993, 22.07648346600007 ], [ -83.972645636999914, 22.061672268000052 ], [ -83.983998175999943, 22.070542710000041 ], [ -83.994984503999945, 22.068264065000051 ], [ -84.001779751999948, 22.057562567000048 ], [ -84.000599738999938, 22.041205145000049 ], [ -83.993031378999945, 22.02798086100006 ], [ -83.983225063999896, 22.023098049000055 ], [ -83.971669074999909, 22.025783596000053 ], [ -83.958973761999914, 22.034979559000078 ], [ -83.964670376999948, 22.013332424000055 ], [ -83.999256964999915, 21.989488023000035 ], [ -84.007435675999943, 21.969183661000045 ], [ -84.003814256999931, 21.964422919000071 ], [ -83.997059699999909, 21.958685614000046 ], [ -83.993031378999945, 21.951361395000049 ], [ -83.997466600999928, 21.941839911000045 ], [ -84.006906704999949, 21.933294989000046 ], [ -84.017689581999946, 21.925482489000046 ], [ -84.029408331999946, 21.919867255000042 ], [ -84.041615363999938, 21.917669989000046 ], [ -84.060414191999939, 21.921942450000074 ], [ -84.098215298999946, 21.940741278000075 ], [ -84.120432094999899, 21.945013739000046 ], [ -84.142160610999952, 21.940334377000056 ], [ -84.180734829999949, 21.91828034100007 ], [ -84.199208136999914, 21.910834052000041 ], [ -84.209339972999942, 21.910101630000042 ], [ -84.230091925999943, 21.911525783000059 ], [ -84.240142381999931, 21.910834052000041 ], [ -84.251210089999915, 21.90656159100007 ], [ -84.273915167999917, 21.89321523600006 ], [ -84.305165167999917, 21.884507554000038 ], [ -84.423247850999928, 21.792303778000075 ], [ -84.466175910999937, 21.770453192000048 ], [ -84.508371548999946, 21.766831773000035 ], [ -84.521351691999939, 21.78656647300005 ], [ -84.481312628999945, 21.865179755000042 ], [ -84.473540818999936, 21.90460846600007 ], [ -84.496164516999897, 21.933783270000049 ], [ -84.536040818999936, 21.94017161700009 ], [ -84.580555792999917, 21.93390534100007 ], [ -84.659982876999948, 21.912054755000042 ], [ -84.698719855999911, 21.89484284100007 ], [ -84.799712693999936, 21.832098700000074 ], [ -84.839914516999897, 21.82290273600006 ], [ -84.883412238999938, 21.823553778000075 ], [ -84.925404425999943, 21.835760809000078 ], [ -84.939116990999935, 21.846096096000053 ], [ -84.947255011999914, 21.860337632000039 ], [ -84.949615037999934, 21.876776434000078 ], [ -84.946034308999913, 21.893540757000039 ], [ -84.942738410999937, 21.900051174000055 ], [ -84.937570766999897, 21.908107815000051 ], [ -84.931223110999952, 21.914740302000041 ], [ -84.924549933999913, 21.917222398000035 ], [ -84.919789191999939, 21.914740302000041 ], [ -84.916574673999946, 21.90961334800005 ], [ -84.913889126999948, 21.903713283000059 ], [ -84.91079667899993, 21.898993231000077 ], [ -84.903553839999915, 21.893622137000079 ], [ -84.895375128999945, 21.890570380000042 ], [ -84.886586066999939, 21.889553127000056 ], [ -84.87759355399993, 21.890326239000046 ], [ -84.860503709999932, 21.897040106000077 ], [ -84.848744269999941, 21.908392645000049 ], [ -84.848215298999946, 21.921087958000044 ], [ -84.864613410999937, 21.93195221600007 ], [ -84.847564256999931, 21.940619208000044 ], [ -84.832386847999942, 21.940578518000052 ], [ -84.82290605399993, 21.930894273000035 ], [ -84.822987433999913, 21.910834052000041 ], [ -84.741078253999945, 21.95180898600006 ], [ -84.668446417999917, 21.971869208000044 ], [ -84.583322719999899, 22.007513739000046 ], [ -84.528879360999952, 22.044338283000059 ], [ -84.521351691999939, 22.048041083000044 ], [ -84.50804602799991, 22.049017645000049 ], [ -84.495920376999948, 22.047349351000037 ], [ -84.489654100999928, 22.042792059000078 ], [ -84.494048631999931, 22.034979559000078 ], [ -84.462635870999918, 22.022040106000077 ], [ -84.439320441999939, 22.028143622000073 ], [ -84.41665605399993, 22.041001695000091 ], [ -84.387318488999938, 22.048041083000044 ], [ -84.372792120999918, 22.043931382000039 ], [ -84.355824347999942, 22.034084377000056 ], [ -84.341664191999939, 22.021673895000049 ], [ -84.335804816999939, 22.010443427000041 ], [ -84.330962693999936, 22.004584052000041 ], [ -84.303822394999941, 22.02289459800005 ], [ -84.288563605999911, 22.020697333000044 ], [ -84.274322068999936, 22.075995184000078 ], [ -84.286284959999932, 22.063381252000056 ], [ -84.296864386999914, 22.045965887000079 ], [ -84.308176235999952, 22.036688544000071 ], [ -84.322132941999939, 22.048041083000044 ], [ -84.328033006999931, 22.06712474200009 ], [ -84.326771613999938, 22.081854559000078 ], [ -84.330189581999946, 22.093329169000071 ], [ -84.350005662999934, 22.102606512000079 ], [ -84.340728318999936, 22.123968817000048 ], [ -84.335804816999939, 22.130560614000046 ], [ -84.354359503999945, 22.132513739000046 ], [ -84.374582485999952, 22.13930898600006 ], [ -84.39281165299991, 22.148504950000074 ], [ -84.405344204999949, 22.157904364000046 ], [ -84.413441535999937, 22.172023830000057 ], [ -84.420033331999946, 22.188666083000044 ], [ -84.429269985999952, 22.201727606000077 ], [ -84.445668097999942, 22.205023505000042 ], [ -84.435699022999927, 22.213690497000073 ], [ -84.42446855399993, 22.22915273600006 ], [ -84.415353969999899, 22.247381903000075 ], [ -84.411488410999937, 22.26398346600007 ], [ -84.409657355999911, 22.287258205000057 ], [ -84.405344204999949, 22.308742580000057 ], [ -84.391021287999934, 22.352769273000035 ], [ -84.388539191999939, 22.355169989000046 ], [ -84.373931443999936, 22.380682684000078 ], [ -84.368804490999935, 22.383286851000037 ], [ -84.358021613999938, 22.384263414000088 ], [ -84.353138800999943, 22.387193101000037 ], [ -84.349110480999911, 22.393622137000079 ], [ -84.345122850999928, 22.406236070000091 ], [ -84.342600063999896, 22.411078192000048 ], [ -84.321278449999909, 22.440130927000041 ], [ -84.306507941999939, 22.455633856000077 ], [ -84.288563605999911, 22.465765692000048 ], [ -84.288563605999911, 22.473211981000077 ], [ -84.309071417999917, 22.473211981000077 ], [ -84.291818813999896, 22.486273505000042 ], [ -84.249012824999909, 22.493557033000059 ], [ -84.230295376999948, 22.503607489000046 ], [ -84.218373175999943, 22.518744208000044 ], [ -84.205799933999913, 22.541164455000057 ], [ -84.201161261999914, 22.56281159100007 ], [ -84.212880011999914, 22.575588283000059 ], [ -84.212880011999914, 22.583075262000079 ], [ -84.202381964999915, 22.580064195000091 ], [ -84.192372199999909, 22.575588283000059 ], [ -84.178130662999934, 22.585679429000038 ], [ -84.164621548999946, 22.587632554000038 ], [ -84.15298417899993, 22.582017320000091 ], [ -84.144602016999897, 22.569403387000079 ], [ -84.135731574999909, 22.606838283000059 ], [ -84.130360480999911, 22.616522528000075 ], [ -84.120513475999928, 22.620266018000052 ], [ -84.094634568999936, 22.622381903000075 ], [ -84.089344855999911, 22.627101955000057 ], [ -84.088612433999913, 22.637152411000045 ], [ -84.085438605999911, 22.654201565000051 ], [ -84.078277147999927, 22.666205145000049 ], [ -84.065500454999949, 22.661281643000052 ], [ -84.052113410999937, 22.653306382000039 ], [ -84.041615363999938, 22.658433335000041 ], [ -84.031971808999913, 22.66937897300005 ], [ -84.021107550999943, 22.678656317000048 ], [ -84.028675910999937, 22.69009023600006 ], [ -84.038970506999931, 22.697088934000078 ], [ -84.052316860999952, 22.69985586100006 ], [ -84.068837042999917, 22.698472398000035 ], [ -84.064320441999939, 22.706244208000044 ], [ -84.057036912999934, 22.713283596000053 ], [ -84.048003709999932, 22.718247789000088 ], [ -84.038441535999937, 22.720200914000088 ], [ -84.022328253999945, 22.714748440000051 ], [ -84.013783331999946, 22.702541408000059 ], [ -84.007191535999937, 22.690375067000048 ], [ -83.997466600999928, 22.684881903000075 ], [ -83.984038865999935, 22.687079169000071 ], [ -83.972075975999928, 22.692531643000052 ], [ -83.911244269999941, 22.733303127000056 ], [ -83.897572394999941, 22.720200914000088 ], [ -83.888050910999937, 22.741441148000035 ], [ -83.872792120999918, 22.750799872000073 ], [ -83.829253709999932, 22.753729559000078 ], [ -83.812652147999927, 22.756740627000056 ], [ -83.743723110999952, 22.789129950000074 ], [ -83.709136522999927, 22.800685940000051 ], [ -83.692738410999937, 22.802150783000059 ], [ -83.681548631999931, 22.800360419000071 ], [ -83.668934699999909, 22.794907945000091 ], [ -83.658029751999948, 22.794663804000038 ], [ -83.651112433999913, 22.796820380000042 ], [ -83.637318488999938, 22.805121161000045 ], [ -83.630034959999932, 22.808335679000038 ], [ -83.630034959999932, 22.815822658000059 ], [ -83.637196417999917, 22.812689520000049 ], [ -83.644357876999948, 22.808335679000038 ], [ -83.645659959999932, 22.811997789000088 ], [ -83.645375128999945, 22.814276434000078 ], [ -83.646229620999918, 22.815375067000048 ], [ -83.651193813999896, 22.815822658000059 ], [ -83.629872199999909, 22.828314520000049 ], [ -83.607899542999917, 22.834377346000053 ], [ -83.558013475999928, 22.83624909100007 ], [ -83.553781704999949, 22.842230536000045 ], [ -83.54133053299995, 22.873846747000073 ], [ -83.534982876999948, 22.877020575000074 ], [ -83.493519660999937, 22.87726471600007 ], [ -83.496083136999914, 22.870347398000035 ], [ -83.497629360999952, 22.86749909100007 ], [ -83.500355597999942, 22.86359284100007 ], [ -83.480824347999942, 22.860256252000056 ], [ -83.469105597999942, 22.870591539000088 ], [ -83.461048956999946, 22.885972398000035 ], [ -83.452504035999937, 22.897772528000075 ], [ -83.437570766999897, 22.903469143000052 ], [ -83.42609615799995, 22.899237372000073 ], [ -83.414051886999914, 22.890814520000049 ], [ -83.397287563999896, 22.884100653000075 ], [ -83.404367641999897, 22.87376536700009 ], [ -83.393462693999936, 22.876898505000042 ], [ -83.377512173999946, 22.886135158000059 ], [ -83.36937415299991, 22.89398834800005 ], [ -83.363352016999897, 22.91046784100007 ], [ -83.348459438999896, 22.932114976000037 ], [ -83.329660610999952, 22.951076565000051 ], [ -83.311634894999941, 22.959173895000049 ], [ -83.298166469999899, 22.963324286000045 ], [ -83.246449347999942, 22.993963934000078 ], [ -83.226185675999943, 23.001857815000051 ], [ -83.207630988999938, 23.00267161700009 ], [ -83.191477016999897, 22.997381903000075 ], [ -83.178212042999917, 22.986517645000049 ], [ -83.178212042999917, 22.980292059000078 ], [ -83.187367316999939, 22.973822333000044 ], [ -83.191232876999948, 22.961859442000048 ], [ -83.189320441999939, 22.947821356000077 ], [ -83.181630011999914, 22.935288804000038 ], [ -83.169422980999911, 22.930121161000045 ], [ -83.159169074999909, 22.936224677000041 ], [ -83.150542772999927, 22.946275132000039 ], [ -83.143422003999945, 22.953029690000051 ], [ -83.161691860999952, 22.966945705000057 ], [ -83.160511847999942, 22.979966539000088 ], [ -83.145822719999899, 22.991400458000044 ], [ -83.123605923999946, 23.000148830000057 ], [ -83.081939256999931, 23.007635809000078 ], [ -83.074126756999931, 23.011297919000071 ], [ -83.061146613999938, 23.019598700000074 ], [ -83.055287238999938, 23.021226304000038 ], [ -83.044911261999914, 23.019517320000091 ], [ -83.031117316999939, 23.010687567000048 ], [ -83.020578579999949, 23.007635809000078 ], [ -83.015370245999918, 23.010321356000077 ], [ -83.009388800999943, 23.016017971000053 ], [ -83.002023891999897, 23.019232489000046 ], [ -82.992583787999934, 23.01439036700009 ], [ -82.986317511999914, 23.004095770000049 ], [ -82.99282792899993, 23.000962632000039 ], [ -83.002837693999936, 22.99945709800005 ], [ -83.006906704999949, 22.993963934000078 ], [ -83.002797003999945, 22.983587958000044 ], [ -82.996693488999938, 22.980169989000046 ], [ -82.988880988999938, 22.983628648000035 ], [ -82.979603644999941, 22.993963934000078 ], [ -82.981678839999915, 22.974188544000071 ], [ -82.964222785999937, 22.972886460000041 ], [ -82.944424028446122, 22.985082820215951 ], [ -82.945396694701685, 22.979579576336334 ], [ -82.940823330032629, 22.943431912153017 ], [ -82.940849169353669, 22.93885854748396 ], [ -82.944389004349034, 22.91898895947287 ], [ -82.919170905313024, 22.873772081216543 ], [ -82.914675055909072, 22.849509995689743 ], [ -82.915941127780798, 22.840569972825961 ], [ -82.934544643920162, 22.820235296821465 ], [ -82.939712286892529, 22.816152859466854 ], [ -82.947567105037876, 22.81341400834981 ], [ -82.971906704031142, 22.810830185964278 ], [ -82.976635098331087, 22.809047350155083 ], [ -82.978030362311358, 22.807109482916303 ], [ -82.976428391856757, 22.805300807786011 ], [ -82.974257982419942, 22.803698839130107 ], [ -82.963095873275904, 22.79912547536037 ], [ -82.959090949387814, 22.795637315409749 ], [ -82.954078335147017, 22.789306952453899 ], [ -82.937567714978059, 22.762977810277732 ], [ -82.92544959232481, 22.747914130033053 ], [ -82.921883918008405, 22.745433661334403 ], [ -82.912737188670292, 22.740705267933777 ], [ -82.907078620182176, 22.736752020889014 ], [ -82.900644904438764, 22.728561305959488 ], [ -82.893151822398693, 22.71626231525363 ], [ -82.873437263119172, 22.673603420061795 ], [ -82.868863897550796, 22.665748602815768 ], [ -82.835765143746357, 22.631228745710018 ], [ -82.828013679287835, 22.620376694928495 ], [ -82.82501644575234, 22.61451141996605 ], [ -82.824601541721293, 22.610579205774144 ] ] ], [ [ [ -83.552845831999946, 21.961371161000045 ], [ -83.550363735999952, 21.961493231000077 ], [ -83.545318162999934, 21.96124909100007 ], [ -83.550648566999939, 21.959418036000045 ], [ -83.570139126999948, 21.958807684000078 ], [ -83.592600063999896, 21.960109768000052 ], [ -83.607818162999934, 21.966498114000046 ], [ -83.597808397999927, 21.971747137000079 ], [ -83.568104620999918, 21.966213283000059 ], [ -83.552845831999946, 21.961371161000045 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-06", "NAME_1": "Cienfuegos" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -80.101026702777816, 21.824765419775595 ], [ -80.104888475999928, 21.825384833000044 ], [ -80.145904100999928, 21.839911200000074 ], [ -80.188221808999913, 21.848456122000073 ], [ -80.217681443999936, 21.871486721000053 ], [ -80.269927537999934, 21.88703034100007 ], [ -80.300770636999914, 21.911688544000071 ], [ -80.409901495999918, 22.020697333000044 ], [ -80.411854620999918, 22.025091864000046 ], [ -80.411854620999918, 22.030259507000039 ], [ -80.412587042999917, 22.035834052000041 ], [ -80.416737433999913, 22.041205145000049 ], [ -80.421131964999915, 22.041896877000056 ], [ -80.433216925999943, 22.040187893000052 ], [ -80.437245245999918, 22.041205145000049 ], [ -80.448109503999945, 22.050279039000088 ], [ -80.451079881999931, 22.056626695000091 ], [ -80.450917120999918, 22.068508205000057 ], [ -80.436756964999915, 22.065904039000088 ], [ -80.419341600999928, 22.066636460000041 ], [ -80.402170376999948, 22.071682033000059 ], [ -80.388783331999946, 22.082180080000057 ], [ -80.404164191999939, 22.078517971000053 ], [ -80.409901495999918, 22.075995184000078 ], [ -80.405832485999952, 22.08470286700009 ], [ -80.400298631999931, 22.093166408000059 ], [ -80.396148240999935, 22.101385809000078 ], [ -80.396311001999948, 22.109523830000057 ], [ -80.404286261999914, 22.112616278000075 ], [ -80.41633053299995, 22.109605210000041 ], [ -80.425363735999952, 22.110052802000041 ], [ -80.424183722999942, 22.123114325000074 ], [ -80.443918423999946, 22.123195705000057 ], [ -80.456532355999911, 22.130438544000071 ], [ -80.457753058999913, 22.142767645000049 ], [ -80.443430141999897, 22.157904364000046 ], [ -80.467274542999917, 22.171616929000038 ], [ -80.476714647999927, 22.180161851000037 ], [ -80.484445766999897, 22.19204336100006 ], [ -80.491281704999949, 22.181830145000049 ], [ -80.503570115999935, 22.178208726000037 ], [ -80.518422003999945, 22.179917710000041 ], [ -80.532826300999943, 22.185777085000041 ], [ -80.538238084999932, 22.164455471000053 ], [ -80.528797980999911, 22.150864976000037 ], [ -80.498646613999938, 22.130560614000046 ], [ -80.483998175999943, 22.111883856000077 ], [ -80.470855272999927, 22.089097398000035 ], [ -80.464670376999948, 22.06476471600007 ], [ -80.470773891999897, 22.041205145000049 ], [ -80.513742641999897, 22.056341864000046 ], [ -80.593365862034759, 22.05423004999443 ], [ -80.593421394281904, 22.054313056002741 ], [ -80.600785285112806, 22.065320136415153 ], [ -80.602955695448998, 22.07144379289673 ], [ -80.604790209000953, 22.082786770093321 ], [ -80.605203620150917, 22.100201727827482 ], [ -80.606211311402888, 22.105472724486617 ], [ -80.608200852787093, 22.110020249834633 ], [ -80.611068895113419, 22.113973496879339 ], [ -80.61817440532451, 22.121285711766177 ], [ -80.624711472956108, 22.123507798945752 ], [ -80.635589362159294, 22.124386298089178 ], [ -80.656440803000635, 22.121905829390471 ], [ -80.670729335990075, 22.118340155973385 ], [ -80.6800310940597, 22.117926743924102 ], [ -80.684759488359703, 22.119632066266831 ], [ -80.691219041625459, 22.125600694016782 ], [ -80.696283331810321, 22.127693589987189 ], [ -80.705559252357602, 22.127512721934579 ], [ -80.712923143188505, 22.126453354738487 ], [ -80.728839484154832, 22.125884914856897 ], [ -80.732844408042979, 22.124644680507572 ], [ -80.735660772626545, 22.122448431749717 ], [ -80.73827043343374, 22.119399522270101 ], [ -80.741190151704131, 22.116944891993171 ], [ -80.744781664442257, 22.116944891993171 ], [ -80.752042201586335, 22.11958039032271 ], [ -80.765891485903353, 22.127461045990458 ], [ -80.800773078214945, 22.140741889526566 ], [ -80.832269864262798, 22.157536728737 ], [ -80.843044399779217, 22.172936305765859 ], [ -80.855343391384395, 22.183840033390823 ], [ -80.897433844896, 22.211486925181418 ], [ -80.893248053854563, 22.230142117264904 ], [ -80.894255744207214, 22.238410346560215 ], [ -80.89572852165395, 22.242131048708927 ], [ -80.896219448968395, 22.246704413377984 ], [ -80.89725297684339, 22.248978176501623 ], [ -80.89937171123546, 22.250089220541099 ], [ -80.903324958280166, 22.250218410850948 ], [ -80.919473843243281, 22.248409735720713 ], [ -80.923607958340597, 22.249469102017429 ], [ -80.926372646980042, 22.251510322043714 ], [ -80.928310513319502, 22.254791775520005 ], [ -80.929860806031343, 22.260011095335756 ], [ -80.930946010749778, 22.269106146931108 ], [ -80.929938321296504, 22.276547553027115 ], [ -80.927897102169538, 22.285280870315887 ], [ -80.922574428666962, 22.299155992155306 ], [ -80.921256679951796, 22.307036647822997 ], [ -80.921230842429395, 22.312204290795364 ], [ -80.924331427853076, 22.318793036169666 ], [ -80.925597499724802, 22.322823798479476 ], [ -80.924279751009692, 22.328094794239348 ], [ -80.921230842429395, 22.334037584466955 ], [ -80.913427701127489, 22.344889635248478 ], [ -80.91210995061374, 22.350057278220788 ], [ -80.913427701127489, 22.354088040530655 ], [ -80.916993373645255, 22.35607758191486 ], [ -80.919938931236686, 22.357111110689175 ], [ -80.922781135141236, 22.357188625954279 ], [ -80.925985074251741, 22.356155097179965 ], [ -80.930687629230704, 22.35413971647472 ], [ -80.935545213840555, 22.35261526128528 ], [ -80.939472621564221, 22.352279365400364 ], [ -80.941901415218126, 22.352899482125395 ], [ -80.942986619936562, 22.35491486283064 ], [ -80.940738695234586, 22.360134181747071 ], [ -80.925132411731397, 22.383621120917951 ], [ -80.921721767945201, 22.390519923755448 ], [ -80.91536556656763, 22.406849676771174 ], [ -80.91482296420844, 22.411087143756674 ], [ -80.916373256920281, 22.41333506935797 ], [ -80.920326503964986, 22.41506623012242 ], [ -80.925442470993232, 22.415893053321724 ], [ -80.928388027685287, 22.41736583076846 ], [ -80.928672247626139, 22.419226182742136 ], [ -80.921179164686691, 22.427571926403289 ], [ -80.909112717977564, 22.435633450123589 ], [ -80.903790046273627, 22.440129299527541 ], [ -80.900766975215731, 22.443359076160391 ], [ -80.888984748447342, 22.45379771579195 ], [ -80.882886928588846, 22.457363390108355 ], [ -80.861699591862646, 22.466587632912933 ], [ -80.849684821097583, 22.473512275071414 ], [ -80.845834926840382, 22.47650950770759 ], [ -80.83710160955161, 22.482038885885856 ], [ -80.829272630727303, 22.483356635500286 ], [ -80.81821387437077, 22.482969061872666 ], [ -80.767829353142133, 22.470592555901703 ], [ -80.760336270202686, 22.470204983173403 ], [ -80.736875170352789, 22.472013658303695 ], [ -80.644555223444797, 22.462841091443181 ], [ -80.634891730169215, 22.459766344441221 ], [ -80.630085822402748, 22.459197902760991 ], [ -80.623703782603457, 22.45953380044449 ], [ -80.601560432368046, 22.469223131242472 ], [ -80.594764981418734, 22.471393541578664 ], [ -80.588486294406948, 22.472633775028669 ], [ -80.580192226689917, 22.473563951015535 ], [ -80.576083950913585, 22.474390774214839 ], [ -80.571639776554434, 22.47865408052138 ], [ -80.565257737654463, 22.486870632073988 ], [ -80.543321092094686, 22.525162869071153 ], [ -80.539807094621722, 22.529271144847428 ], [ -80.519679125091557, 22.542009386024347 ], [ -80.478157110562165, 22.564514472364976 ], [ -80.465909796699748, 22.57751109506097 ], [ -80.463196784004367, 22.581412665262292 ], [ -80.459424405012271, 22.584642441895141 ], [ -80.454618496346541, 22.587097073071448 ], [ -80.446221075841947, 22.586425279503032 ], [ -80.441079271291301, 22.584797472425407 ], [ -80.4171789209704, 22.566452337805117 ], [ -80.39234839466269, 22.570870672843284 ], [ -80.383976812579817, 22.569320380131444 ], [ -80.379274257600912, 22.563971869106467 ], [ -80.379816860859421, 22.549450792120354 ], [ -80.381754727198881, 22.540071518785567 ], [ -80.386689826174518, 22.526713161782993 ], [ -80.387464973429758, 22.522372341110611 ], [ -80.386767341439622, 22.519633489993566 ], [ -80.385217047828462, 22.517411403713311 ], [ -80.380824551212072, 22.51604197815476 ], [ -80.37537268739959, 22.516248683729771 ], [ -80.364055548624663, 22.519814358046176 ], [ -80.357595995358906, 22.522734076316567 ], [ -80.346459723737269, 22.529581204109263 ], [ -80.341834683124091, 22.531260688030329 ], [ -80.33640865773333, 22.531699936702694 ], [ -80.328657193274807, 22.531389879239498 ], [ -80.323153652618942, 22.531648260758629 ], [ -80.319975551930156, 22.533327745578958 ], [ -80.318011848068295, 22.536040758274339 ], [ -80.310492926707184, 22.558313299718975 ], [ -80.306798062080873, 22.564927883514997 ], [ -80.303516607705262, 22.568571072197187 ], [ -80.299950935187496, 22.569862983389953 ], [ -80.294137336169115, 22.570043850543243 ], [ -80.280158860642871, 22.568803616193918 ], [ -80.273725144899515, 22.568881130559703 ], [ -80.267756517149508, 22.569862983389953 ], [ -80.264785122035732, 22.571697496042589 ], [ -80.260134243000891, 22.576606757495824 ], [ -80.257550422414056, 22.578544622935965 ], [ -80.255405849600265, 22.57559906714323 ], [ -80.25398474809765, 22.569036160190649 ], [ -80.254010585619994, 22.551362820038094 ], [ -80.25548336486537, 22.542862046746052 ], [ -80.257937995142356, 22.53797862371448 ], [ -80.260806036569306, 22.536609198155929 ], [ -80.264785122035732, 22.535575670280934 ], [ -80.268014898668639, 22.53418040630072 ], [ -80.271089646569919, 22.531648260758629 ], [ -80.271399705831755, 22.526480617786262 ], [ -80.270236985848214, 22.517798977340931 ], [ -80.259100715125896, 22.493588569556834 ], [ -80.255560879231155, 22.488472602528589 ], [ -80.236518114419425, 22.478473212468771 ], [ -80.23352088088393, 22.468292955255663 ], [ -80.23737077514113, 22.45955963796689 ], [ -80.238998583118075, 22.452402451811679 ], [ -80.238481818281286, 22.446692206480122 ], [ -80.234399380027355, 22.43950918190319 ], [ -80.227242193872144, 22.436021022851889 ], [ -80.223521490824112, 22.432145291072288 ], [ -80.220808479028051, 22.427804470399963 ], [ -80.223986578817517, 22.4146786564948 ], [ -80.243003506106902, 22.39537750926462 ], [ -80.242486742169376, 22.384654648793003 ], [ -80.239050259062196, 22.378169257105526 ], [ -80.23295244010302, 22.370314438960179 ], [ -80.196598070344635, 22.33737071388731 ], [ -80.184273241217113, 22.331350409293918 ], [ -80.177090216640181, 22.330110174944593 ], [ -80.169984707328354, 22.330626938882119 ], [ -80.154972703927115, 22.334916082711004 ], [ -80.14990841284299, 22.335381170704466 ], [ -80.145696784279153, 22.334554348404424 ], [ -80.143293829946288, 22.332642320486684 ], [ -80.141588507603501, 22.329102485491319 ], [ -80.138410406914716, 22.306726589460538 ], [ -80.135697395118655, 22.29768321380925 ], [ -80.130219692884509, 22.286211046302753 ], [ -80.121434698752353, 22.271431585998869 ], [ -80.109187384889879, 22.25641958349695 ], [ -80.084072638641373, 22.245619207760228 ], [ -80.09497636626628, 22.213424791520879 ], [ -80.098567878105086, 22.207611192502497 ], [ -80.102417772362287, 22.199265447942025 ], [ -80.103580492345827, 22.190196234768393 ], [ -80.099808111555092, 22.151593940308089 ], [ -80.100479906022827, 22.131879381028568 ], [ -80.099859789297795, 22.123404446158247 ], [ -80.089369472822909, 22.083768622024252 ], [ -80.084124314585438, 22.070255235390789 ], [ -80.077380541378886, 22.057878730319146 ], [ -80.058777025239522, 22.043435166799497 ], [ -80.053376838270481, 22.03653636306268 ], [ -80.05084469272839, 22.028319809711434 ], [ -80.049268561594829, 22.001809801281297 ], [ -80.04988867921918, 21.986797796980738 ], [ -80.048415899973804, 21.977211818970261 ], [ -80.045005256187608, 21.968607692890714 ], [ -80.024748093649578, 21.954215807113769 ], [ -80.023275316202842, 21.95212291114342 ], [ -80.024050462558762, 21.938506170823132 ], [ -80.060043098010567, 21.903702093776587 ], [ -80.087276576852503, 21.883419093716213 ], [ -80.094097867122855, 21.87639110056881 ], [ -80.097715217383382, 21.871481838216255 ], [ -80.09880042210176, 21.866391710508992 ], [ -80.101022508382016, 21.824843858457257 ], [ -80.101026702777816, 21.824765419775595 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-12", "NAME_1": "Granma" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -77.03464353527859, 19.887765132826136 ], [ -77.088042772999927, 19.885443427000041 ], [ -77.113433397999927, 19.88930898600006 ], [ -77.163400844999899, 19.908107815000051 ], [ -77.188954230999911, 19.912583726000037 ], [ -77.202788865999935, 19.902899481000077 ], [ -77.20962480399993, 19.902899481000077 ], [ -77.21711178299995, 19.90961334800005 ], [ -77.227284308999913, 19.911078192000048 ], [ -77.237172003999945, 19.90688711100006 ], [ -77.243763800999943, 19.896714585000041 ], [ -77.269154425999943, 19.904527085000041 ], [ -77.298247850999928, 19.906683661000045 ], [ -77.324086066999939, 19.900295315000051 ], [ -77.339995897999927, 19.882473049000055 ], [ -77.31273352799991, 19.882473049000055 ], [ -77.31273352799991, 19.87563711100006 ], [ -77.330474412999934, 19.874823309000078 ], [ -77.358509894999941, 19.864488023000035 ], [ -77.37726803299995, 19.86196523600006 ], [ -77.469960089999915, 19.859564520000049 ], [ -77.533355272999927, 19.844916083000044 ], [ -77.569325324999909, 19.841498114000046 ], [ -77.611480272999927, 19.844631252000056 ], [ -77.673247850999928, 19.828924872000073 ], [ -77.692534959999932, 19.827826239000046 ], [ -77.706044074999909, 19.830023505000042 ], [ -77.719553188999953, 19.835882880000042 ], [ -77.730580206999946, 19.844794012000079 ], [ -77.737212693999936, 19.855698960000041 ], [ -77.735991990999935, 19.874172268000052 ], [ -77.717355923999946, 19.907212632000039 ], [ -77.716175910999937, 19.916571356000077 ], [ -77.708811001999948, 19.91868724200009 ], [ -77.696115688999953, 19.919989325000074 ], [ -77.688832160999937, 19.923407294000071 ], [ -77.682118292999917, 19.929592190000051 ], [ -77.675282355999911, 19.939886786000045 ], [ -77.668324347999942, 19.943915106000077 ], [ -77.671376105999911, 19.954779364000046 ], [ -77.666737433999913, 19.962469794000071 ], [ -77.647857225999928, 19.978664455000057 ], [ -77.625559048999946, 20.007798570000091 ], [ -77.623931443999936, 20.012762762000079 ], [ -77.620432094999899, 20.020331122000073 ], [ -77.572743292999917, 20.061102606000077 ], [ -77.574696417999917, 20.069810289000088 ], [ -77.58812415299991, 20.082464911000045 ], [ -77.586415167999917, 20.08852773600006 ], [ -77.577381964999915, 20.087958075000074 ], [ -77.55101477799991, 20.079779364000046 ], [ -77.541086391999897, 20.088771877000056 ], [ -77.521880662999934, 20.094549872000073 ], [ -77.517486131999931, 20.098456122000073 ], [ -77.514719204999949, 20.104437567000048 ], [ -77.496978318999936, 20.129461981000077 ], [ -77.479562954999949, 20.140855210000041 ], [ -77.436634894999941, 20.16242096600007 ], [ -77.42023678299995, 20.185044664000088 ], [ -77.401356574999909, 20.198065497000073 ], [ -77.300648566999939, 20.242743231000077 ], [ -77.281361456999946, 20.24555084800005 ], [ -77.266468878999945, 20.253241278000075 ], [ -77.250721808999913, 20.289292710000041 ], [ -77.236317511999914, 20.300767320000091 ], [ -77.233387824999909, 20.301214911000045 ], [ -77.229847785999937, 20.301336981000077 ], [ -77.22329667899993, 20.300767320000091 ], [ -77.228993292999917, 20.289129950000074 ], [ -77.22297115799995, 20.283392645000049 ], [ -77.210072394999941, 20.282863674000055 ], [ -77.195423956999946, 20.286525783000059 ], [ -77.181752081999946, 20.294867255000042 ], [ -77.171213344999899, 20.30727773600006 ], [ -77.16429602799991, 20.322170315000051 ], [ -77.161854620999918, 20.338324286000045 ], [ -77.15453040299991, 20.34406159100007 ], [ -77.113433397999927, 20.368475653000075 ], [ -77.110259568999936, 20.416408596000053 ], [ -77.103505011999914, 20.423651434000078 ], [ -77.095814581999946, 20.430161851000037 ], [ -77.082427537999934, 20.465277411000045 ], [ -77.113433397999927, 20.51243724200009 ], [ -77.123199022999927, 20.52094147300005 ], [ -77.150135870999918, 20.537909247000073 ], [ -77.185943162999934, 20.550930080000057 ], [ -77.195668097999942, 20.552150783000059 ], [ -77.189198370999918, 20.540961005000042 ], [ -77.195423956999946, 20.534125067000048 ], [ -77.214019334999932, 20.546210028000075 ], [ -77.229481574999909, 20.552923895000049 ], [ -77.239898240999935, 20.563055731000077 ], [ -77.243763800999943, 20.585353908000059 ], [ -77.240386522999927, 20.59210846600007 ], [ -77.232492641999897, 20.59601471600007 ], [ -77.223378058999913, 20.598822333000044 ], [ -77.216460740999935, 20.602443752000056 ], [ -77.195423956999946, 20.629787502000056 ], [ -77.195423956999946, 20.636542059000078 ], [ -77.231678839999915, 20.658270575000074 ], [ -77.251047329999949, 20.662095445000091 ], [ -77.25804602799991, 20.643377997000073 ], [ -77.278187628999945, 20.662054755000042 ], [ -77.29515540299991, 20.687079169000071 ], [ -77.314849412999934, 20.709051825000074 ], [ -77.33668027431905, 20.71633924892582 ], [ -77.336540087055369, 20.716436061974662 ], [ -77.332405971958053, 20.719226589035827 ], [ -77.316851366197568, 20.726022039985139 ], [ -77.312717251100253, 20.728399155896284 ], [ -77.310779384760792, 20.730595405553515 ], [ -77.309616664777252, 20.73297252056534 ], [ -77.307265388187091, 20.739302883521248 ], [ -77.303673876348284, 20.744961452908683 ], [ -77.293726162232588, 20.755735989324421 ], [ -77.291349047220763, 20.760619412355993 ], [ -77.289359504037861, 20.766407172053334 ], [ -77.288119269688536, 20.777078354782248 ], [ -77.285328741728051, 20.781625881029584 ], [ -77.281685553945124, 20.782736925069003 ], [ -77.276259527655043, 20.777026678838126 ], [ -77.272202927822832, 20.767466539249369 ], [ -77.268198004834062, 20.767544054514474 ], [ -77.261815965034771, 20.77056712557237 ], [ -77.246209683330221, 20.781031601826953 ], [ -77.238639086024989, 20.784209703415058 ], [ -77.232205370281577, 20.784209703415058 ], [ -77.228355476024376, 20.778163560400003 ], [ -77.225875007325726, 20.772220771071716 ], [ -77.202491420942295, 20.76614879053426 ], [ -77.104357875915241, 20.763435776939559 ], [ -77.068029343679257, 20.750620022296175 ], [ -77.053456589849702, 20.740879015554128 ], [ -77.046867845374777, 20.738760281162001 ], [ -77.03805701372022, 20.738992825158732 ], [ -77.02162390791699, 20.743953762556089 ], [ -77.008084682861806, 20.744496364915278 ], [ -76.993227709091514, 20.746460068777139 ], [ -76.970955165848238, 20.753565578988287 ], [ -76.929252285064877, 20.746537584042244 ], [ -76.92121659976624, 20.747596951238279 ], [ -76.9012178214453, 20.74785533275741 ], [ -76.858688116563314, 20.743101100935064 ], [ -76.836105515856843, 20.743333644931738 ], [ -76.821300218030615, 20.739767971514652 ], [ -76.812024299281973, 20.732610785359441 ], [ -76.793446620665009, 20.695274562770862 ], [ -76.782878790723601, 20.690985418941921 ], [ -76.766290656188801, 20.704292100899693 ], [ -76.762182380412526, 20.706953436751689 ], [ -76.721900601131836, 20.722301336937107 ], [ -76.717043015622664, 20.714498196534521 ], [ -76.712831387058827, 20.70964061102535 ], [ -76.707250332037177, 20.706152451974049 ], [ -76.699783088418769, 20.704524643997104 ], [ -76.689938727989897, 20.70793528958194 ], [ -76.6803527490801, 20.713180446920092 ], [ -76.677174649290635, 20.713180446920092 ], [ -76.673608974974229, 20.710674139799721 ], [ -76.664462245636116, 20.696127224391887 ], [ -76.657976853948639, 20.690985418941921 ], [ -76.649915331127602, 20.68772980388735 ], [ -76.635394253242168, 20.684835924038623 ], [ -76.627901171202097, 20.682432969705758 ], [ -76.618237677926459, 20.681787014559063 ], [ -76.608160772601536, 20.683828232786709 ], [ -76.581237352122116, 20.697083237901097 ], [ -76.570307786974752, 20.696463121176066 ], [ -76.564520026378091, 20.680055853794613 ], [ -76.563408983237991, 20.67264028612027 ], [ -76.562814704035361, 20.660935573717722 ], [ -76.564442512012306, 20.646181951835615 ], [ -76.564416672691266, 20.641892808905993 ], [ -76.559843308921529, 20.638223781802083 ], [ -76.550670742061072, 20.633857122708037 ], [ -76.503826056727121, 20.623289292766628 ], [ -76.485894335055491, 20.615770372304837 ], [ -76.439566412759746, 20.589906318122075 ], [ -76.404762335713201, 20.579932766483978 ], [ -76.396132372111254, 20.576392931488556 ], [ -76.393057624209973, 20.576547960220182 ], [ -76.390137905939582, 20.578072415409622 ], [ -76.387347377979097, 20.580397854477383 ], [ -76.385306158852131, 20.581741440714893 ], [ -76.380758632604795, 20.582723294444463 ], [ -76.377890591177845, 20.582413235182628 ], [ -76.374479947391649, 20.581250515199088 ], [ -76.370785081866018, 20.578692532134653 ], [ -76.367813686752243, 20.571948757129405 ], [ -76.366935186709497, 20.5668586294222 ], [ -76.372567918574589, 20.545800483005848 ], [ -76.360372280656236, 20.544560247757204 ], [ -76.338048062368159, 20.536369533726997 ], [ -76.312881639276213, 20.53213206584212 ], [ -76.300530971726971, 20.528566392425034 ], [ -76.28006710541257, 20.519574692717867 ], [ -76.253092007190389, 20.513631904288957 ], [ -76.244410366745001, 20.509471950769921 ], [ -76.233971727113499, 20.502779853507434 ], [ -76.204335293039321, 20.474331976939141 ], [ -76.17965979726182, 20.437590033553192 ], [ -76.205601365810367, 20.404439602005993 ], [ -76.21952816359385, 20.393871772064585 ], [ -76.227305467373412, 20.393251655339611 ], [ -76.230896979212218, 20.397514959847513 ], [ -76.235832079087174, 20.41071828901778 ], [ -76.240844693327915, 20.420226751763153 ], [ -76.24187822120291, 20.42560110120985 ], [ -76.24187822120291, 20.43175059701241 ], [ -76.241025559581885, 20.437745063184082 ], [ -76.24094804611542, 20.443842882143258 ], [ -76.243195969918077, 20.450018215468276 ], [ -76.248337775368043, 20.455237535284027 ], [ -76.258414679793646, 20.461076971824752 ], [ -76.266011114621222, 20.460560207887283 ], [ -76.270274420927763, 20.459087429541228 ], [ -76.271282111280414, 20.454617418558996 ], [ -76.267483893866597, 20.436091416785416 ], [ -76.267328864235708, 20.427048041134185 ], [ -76.268879156947548, 20.418314723845413 ], [ -76.272289801633008, 20.411570949739541 ], [ -76.277018195033634, 20.405602321989534 ], [ -76.283012661205362, 20.399788722971152 ], [ -76.286500821155983, 20.395267035145537 ], [ -76.288231981021113, 20.39128795057843 ], [ -76.289136318586202, 20.381857001299579 ], [ -76.289988980207283, 20.377283637529843 ], [ -76.293347948049359, 20.370539863423915 ], [ -76.298722296596679, 20.368576157763471 ], [ -76.308127408353187, 20.368576157763471 ], [ -76.329779833072848, 20.372503567285776 ], [ -76.339572516658279, 20.373278712742376 ], [ -76.355514696046384, 20.372865302491675 ], [ -76.363188646139122, 20.36661245390161 ], [ -76.369467333150908, 20.356638902263512 ], [ -76.390447964302098, 20.276256211754742 ], [ -76.390292934671209, 20.271553655876517 ], [ -76.390577154612004, 20.26853058481862 ], [ -76.389104377165268, 20.258686225289068 ], [ -76.404400601406621, 20.243932603406904 ], [ -76.413159756217738, 20.234760037445767 ], [ -76.419645147905214, 20.231065171920136 ], [ -76.420420295160454, 20.225975043313554 ], [ -76.41747473756908, 20.219076239576793 ], [ -76.411842006603308, 20.189517319868401 ], [ -76.408276333186222, 20.105284736001749 ], [ -76.418611620030219, 20.086681219862385 ], [ -76.447369554061652, 20.061101386519738 ], [ -76.462433234306332, 20.051179510825762 ], [ -76.476747605717435, 20.044048163092214 ], [ -76.488736538060778, 20.039474799322534 ], [ -76.498374192914639, 20.037304388986342 ], [ -76.505376350338281, 20.036658433839648 ], [ -76.528785773344737, 20.038105373763983 ], [ -76.557104457804485, 20.042601223167878 ], [ -76.56371904160045, 20.038777167332398 ], [ -76.563564011969561, 20.036012477793577 ], [ -76.56219458731033, 20.030379746827862 ], [ -76.554313930743319, 20.010225937976656 ], [ -76.555554165092644, 20.00549754547535 ], [ -76.562478807251125, 20.003766383811524 ], [ -76.590358242139132, 20.010096746767431 ], [ -76.598626472333819, 20.013042304358862 ], [ -76.604543423240386, 20.014489244283197 ], [ -76.606532966423231, 20.012861436306252 ], [ -76.609995287052868, 20.004076443073359 ], [ -76.613483446104169, 20.002190253577339 ], [ -76.637022061219113, 20.001906032737224 ], [ -76.654721238894069, 19.999322211251013 ], [ -76.663454556182785, 19.999193020041844 ], [ -76.668880580674227, 19.999787299244474 ], [ -76.670844286334727, 20.000820828018789 ], [ -76.674513311639998, 20.002190253577339 ], [ -76.690998094286613, 20.00585927978193 ], [ -76.698904589275344, 20.008856513317426 ], [ -76.70518327538781, 20.013042304358862 ], [ -76.713942430198983, 20.02262828236934 ], [ -76.72004024915816, 20.027330837348245 ], [ -76.725879685698942, 20.027201646139019 ], [ -76.744948289831711, 20.022602443947619 ], [ -76.750296799957312, 20.020612900764718 ], [ -76.753914151117158, 20.018287461696957 ], [ -76.755774502191514, 20.015031847541707 ], [ -76.759417690873704, 20.01141449638186 ], [ -76.762750821193436, 20.011336982016076 ], [ -76.766445685819747, 20.013584905818732 ], [ -76.769003668884181, 20.016427109723338 ], [ -76.771613328792057, 20.018287461696957 ], [ -76.774352179909158, 20.019450182579874 ], [ -76.777814501438058, 20.020225328036418 ], [ -76.781173469280191, 20.021233018389069 ], [ -76.78458411306633, 20.023248399094314 ], [ -76.788640712898541, 20.026814073410719 ], [ -76.790836961656453, 20.029268703687706 ], [ -76.800707159607725, 20.037950344133037 ], [ -76.81698523578001, 20.02857107169757 ], [ -76.833521695270008, 20.012422186734511 ], [ -76.843236863590391, 20.0083397493799 ], [ -76.858688116563314, 20.005600898262855 ], [ -76.88057308617897, 20.00529083900102 ], [ -76.894577399227558, 20.00642772146216 ], [ -76.918503587970179, 20.005006619060225 ], [ -76.92584164127868, 20.003352973560879 ], [ -76.930699225888532, 20.001105047959584 ], [ -76.968603889258077, 19.952968451432866 ], [ -76.973823208174508, 19.949583645169071 ], [ -76.980902879963935, 19.947516588519704 ], [ -77.039116380916255, 19.941470445504649 ], [ -77.047772182939866, 19.938912462440157 ], [ -77.047849698204971, 19.935889391382318 ], [ -77.047229579681357, 19.932788805059317 ], [ -77.044154832679396, 19.928060410759315 ], [ -77.035111457028108, 19.910593777081147 ], [ -77.03464353527859, 19.887765132826136 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "CU-13", "NAME_1": "Santiago de Cuba" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -75.382080421154143, 19.882543917011262 ], [ -75.383290167999917, 19.882473049000055 ], [ -75.394276495999918, 19.883490302000041 ], [ -75.427601691999939, 19.890692450000074 ], [ -75.437489386999914, 19.895656643000052 ], [ -75.444406704999949, 19.896714585000041 ], [ -75.447336391999897, 19.894761460000041 ], [ -75.455637173999946, 19.88548411700009 ], [ -75.461822068999936, 19.882473049000055 ], [ -75.488880988999938, 19.879095770000049 ], [ -75.520904100999928, 19.87962474200009 ], [ -75.550852016999897, 19.885158596000053 ], [ -75.571644660999937, 19.896714585000041 ], [ -75.604725714999915, 19.89203522300005 ], [ -75.645619269999941, 19.912583726000037 ], [ -75.687001105999911, 19.940375067000048 ], [ -75.721831834999932, 19.957505601000037 ], [ -75.743723110999952, 19.959865627000056 ], [ -75.815297003999945, 19.957505601000037 ], [ -75.834339972999942, 19.959784247000073 ], [ -75.87336178299995, 19.969549872000073 ], [ -75.893788214999915, 19.971828518000052 ], [ -75.932118292999917, 19.967678127000056 ], [ -75.952219204999949, 19.962225653000075 ], [ -75.96548417899993, 19.954413153000075 ], [ -75.980091925999943, 19.952378648000035 ], [ -76.112049933999913, 19.982489325000074 ], [ -76.202259894999941, 19.992336330000057 ], [ -76.248158331999946, 19.990627346000053 ], [ -76.327992316999939, 19.97016022300005 ], [ -76.366118943999936, 19.964992580000057 ], [ -76.438710089999915, 19.964992580000057 ], [ -76.460275844999899, 19.962103583000044 ], [ -76.50226803299995, 19.948391018000052 ], [ -76.524403449999909, 19.943915106000077 ], [ -76.651600714999915, 19.951117255000042 ], [ -76.781076626999948, 19.940741278000075 ], [ -76.801747199999909, 19.930731512000079 ], [ -76.823597785999937, 19.931586005000042 ], [ -76.845611131999931, 19.93626536700009 ], [ -76.866444464999915, 19.937689520000049 ], [ -76.881825324999909, 19.931382554000038 ], [ -76.914133266999897, 19.906642971000053 ], [ -76.935292120999918, 19.896714585000041 ], [ -76.958892381999931, 19.891058661000045 ], [ -77.03464353527859, 19.887765132826136 ], [ -77.035111457028108, 19.910593777081147 ], [ -77.044154832679396, 19.928060410759315 ], [ -77.047229579681357, 19.932788805059317 ], [ -77.047849698204971, 19.935889391382318 ], [ -77.047772182939866, 19.938912462440157 ], [ -77.039116380916255, 19.941470445504649 ], [ -76.980902879963935, 19.947516588519704 ], [ -76.973823208174508, 19.949583645169071 ], [ -76.968603889258077, 19.952968451432866 ], [ -76.930699225888532, 20.001105047959584 ], [ -76.92584164127868, 20.003352973560879 ], [ -76.918503587970179, 20.005006619060225 ], [ -76.894577399227558, 20.00642772146216 ], [ -76.88057308617897, 20.00529083900102 ], [ -76.858688116563314, 20.005600898262855 ], [ -76.843236863590391, 20.0083397493799 ], [ -76.833521695270008, 20.012422186734511 ], [ -76.81698523578001, 20.02857107169757 ], [ -76.800707159607725, 20.037950344133037 ], [ -76.790836961656453, 20.029268703687706 ], [ -76.788640712898541, 20.026814073410719 ], [ -76.78458411306633, 20.023248399094314 ], [ -76.781173469280191, 20.021233018389069 ], [ -76.777814501438058, 20.020225328036418 ], [ -76.774352179909158, 20.019450182579874 ], [ -76.771613328792057, 20.018287461696957 ], [ -76.769003668884181, 20.016427109723338 ], [ -76.766445685819747, 20.013584905818732 ], [ -76.762750821193436, 20.011336982016076 ], [ -76.759417690873704, 20.01141449638186 ], [ -76.755774502191514, 20.015031847541707 ], [ -76.753914151117158, 20.018287461696957 ], [ -76.750296799957312, 20.020612900764718 ], [ -76.744948289831711, 20.022602443947619 ], [ -76.725879685698942, 20.027201646139019 ], [ -76.72004024915816, 20.027330837348245 ], [ -76.713942430198983, 20.02262828236934 ], [ -76.70518327538781, 20.013042304358862 ], [ -76.698904589275344, 20.008856513317426 ], [ -76.690998094286613, 20.00585927978193 ], [ -76.674513311639998, 20.002190253577339 ], [ -76.670844286334727, 20.000820828018789 ], [ -76.668880580674227, 19.999787299244474 ], [ -76.663454556182785, 19.999193020041844 ], [ -76.654721238894069, 19.999322211251013 ], [ -76.637022061219113, 20.001906032737224 ], [ -76.613483446104169, 20.002190253577339 ], [ -76.609995287052868, 20.004076443073359 ], [ -76.606532966423231, 20.012861436306252 ], [ -76.604543423240386, 20.014489244283197 ], [ -76.598626472333819, 20.013042304358862 ], [ -76.590358242139132, 20.010096746767431 ], [ -76.562478807251125, 20.003766383811524 ], [ -76.555554165092644, 20.00549754547535 ], [ -76.554313930743319, 20.010225937976656 ], [ -76.56219458731033, 20.030379746827862 ], [ -76.563564011969561, 20.036012477793577 ], [ -76.56371904160045, 20.038777167332398 ], [ -76.557104457804485, 20.042601223167878 ], [ -76.528785773344737, 20.038105373763983 ], [ -76.505376350338281, 20.036658433839648 ], [ -76.498374192914639, 20.037304388986342 ], [ -76.488736538060778, 20.039474799322534 ], [ -76.476747605717435, 20.044048163092214 ], [ -76.462433234306332, 20.051179510825762 ], [ -76.447369554061652, 20.061101386519738 ], [ -76.418611620030219, 20.086681219862385 ], [ -76.408276333186222, 20.105284736001749 ], [ -76.411842006603308, 20.189517319868401 ], [ -76.41747473756908, 20.219076239576793 ], [ -76.420420295160454, 20.225975043313554 ], [ -76.419645147905214, 20.231065171920136 ], [ -76.413159756217738, 20.234760037445767 ], [ -76.404400601406621, 20.243932603406904 ], [ -76.389104377165268, 20.258686225289068 ], [ -76.390577154612004, 20.26853058481862 ], [ -76.390292934671209, 20.271553655876517 ], [ -76.390447964302098, 20.276256211754742 ], [ -76.369467333150908, 20.356638902263512 ], [ -76.363188646139122, 20.36661245390161 ], [ -76.355514696046384, 20.372865302491675 ], [ -76.339572516658279, 20.373278712742376 ], [ -76.329779833072848, 20.372503567285776 ], [ -76.308127408353187, 20.368576157763471 ], [ -76.298722296596679, 20.368576157763471 ], [ -76.293347948049359, 20.370539863423915 ], [ -76.289988980207283, 20.377283637529843 ], [ -76.289136318586202, 20.381857001299579 ], [ -76.288231981021113, 20.39128795057843 ], [ -76.286500821155983, 20.395267035145537 ], [ -76.283012661205362, 20.399788722971152 ], [ -76.277018195033634, 20.405602321989534 ], [ -76.272289801633008, 20.411570949739541 ], [ -76.268879156947548, 20.418314723845413 ], [ -76.267328864235708, 20.427048041134185 ], [ -76.267483893866597, 20.436091416785416 ], [ -76.271282111280414, 20.454617418558996 ], [ -76.270274420927763, 20.459087429541228 ], [ -76.266011114621222, 20.460560207887283 ], [ -76.258414679793646, 20.461076971824752 ], [ -76.248337775368043, 20.455237535284027 ], [ -76.243195969918077, 20.450018215468276 ], [ -76.24094804611542, 20.443842882143258 ], [ -76.241025559581885, 20.437745063184082 ], [ -76.24187822120291, 20.43175059701241 ], [ -76.24187822120291, 20.42560110120985 ], [ -76.240844693327915, 20.420226751763153 ], [ -76.235832079087174, 20.41071828901778 ], [ -76.230896979212218, 20.397514959847513 ], [ -76.227305467373412, 20.393251655339611 ], [ -76.21952816359385, 20.393871772064585 ], [ -76.205601365810367, 20.404439602005993 ], [ -76.17965979726182, 20.437590033553192 ], [ -76.155423550156684, 20.438881943846638 ], [ -76.146457688871237, 20.438597723905843 ], [ -76.138189459575869, 20.436892402462377 ], [ -76.130463832639748, 20.434153551345275 ], [ -76.121394618566796, 20.42983856909467 ], [ -76.116304490859534, 20.42846914353612 ], [ -76.111756964612198, 20.428779201898635 ], [ -76.106770188793178, 20.430277817767035 ], [ -76.106150072068147, 20.42828827638283 ], [ -76.107106085577357, 20.424128322863794 ], [ -76.114805874091815, 20.408315335584234 ], [ -76.111343552562914, 20.400615546170513 ], [ -76.092610847012963, 20.417462063123708 ], [ -76.090543788564958, 20.420562649446708 ], [ -76.084368456139316, 20.442008367691983 ], [ -76.08173295780972, 20.464435940566204 ], [ -76.088347540706422, 20.479499619911508 ], [ -76.090285407045883, 20.488853053925254 ], [ -76.092869229431358, 20.492031155513416 ], [ -76.09640906442678, 20.493374741750927 ], [ -76.096925829263569, 20.495984402558122 ], [ -76.094548713352424, 20.499395046344318 ], [ -76.079019945114339, 20.509161892407406 ], [ -76.066307543258517, 20.519755560770477 ], [ -76.061346604961841, 20.522675279040868 ], [ -76.043440720812612, 20.529574082777685 ], [ -76.04106360490141, 20.534690049805931 ], [ -76.041864589679051, 20.541433823911802 ], [ -76.048970099890198, 20.557505195408453 ], [ -76.051398891745464, 20.56608348216696 ], [ -76.049202643886872, 20.57241384512281 ], [ -76.046670498344781, 20.573602403528071 ], [ -76.033027919602773, 20.567866318875474 ], [ -75.985614794387232, 20.534767564171716 ], [ -75.976183845108324, 20.520143134398097 ], [ -75.980498827358986, 20.509704494766595 ], [ -75.977243212304415, 20.505828762087674 ], [ -75.969827643730753, 20.502960719761404 ], [ -75.952438524418369, 20.501462103892948 ], [ -75.940139532813191, 20.501642971046238 ], [ -75.933292405919758, 20.500454413540353 ], [ -75.930786098799388, 20.497844752733158 ], [ -75.931716274786254, 20.491023464261445 ], [ -75.934222581906624, 20.48629507086082 ], [ -75.936806403392779, 20.482160955763504 ], [ -75.939364387356591, 20.479215399970712 ], [ -75.940578783284195, 20.477122504000363 ], [ -75.937193977020399, 20.472936712958926 ], [ -75.929752570025073, 20.467071437996424 ], [ -75.900141975271936, 20.448080349128816 ], [ -75.883553839837816, 20.443972073352484 ], [ -75.879445563162221, 20.427797349967705 ], [ -75.87805030008127, 20.424360866860525 ], [ -75.876655036100999, 20.421725369430249 ], [ -75.873011848318129, 20.418314723845413 ], [ -75.85626868415244, 20.410098171393486 ], [ -75.824668545317081, 20.407617702694779 ], [ -75.752399055372109, 20.439036974376847 ], [ -75.744337530752432, 20.441052354182773 ], [ -75.73314958408605, 20.442060045434744 ], [ -75.701342739675681, 20.437874254393307 ], [ -75.658813035693015, 20.441491603754514 ], [ -75.61555986219787, 20.469836127535245 ], [ -75.612510951818933, 20.477019151212858 ], [ -75.609565396026198, 20.485985012498304 ], [ -75.614836391786014, 20.496888739223891 ], [ -75.61576656777288, 20.500015163968612 ], [ -75.61555986219787, 20.503115750291613 ], [ -75.61421627506104, 20.50712067328044 ], [ -75.611425747100554, 20.510634669854142 ], [ -75.609203660820299, 20.511771552315281 ], [ -75.601788093145956, 20.50828339326398 ], [ -75.5953543774026, 20.506035468562004 ], [ -75.582590297803961, 20.499550075975208 ], [ -75.57793941876912, 20.500712795059428 ], [ -75.570498012673113, 20.505182806940979 ], [ -75.55543433332781, 20.516422431350122 ], [ -75.535538906894999, 20.535749417001966 ], [ -75.53174068858192, 20.540245266405918 ], [ -75.528562587893077, 20.542467352686174 ], [ -75.524816047322702, 20.544250190294008 ], [ -75.518744065885926, 20.546136378890765 ], [ -75.515023362837894, 20.54815176049533 ], [ -75.511638556574098, 20.55086477319071 ], [ -75.507401088689278, 20.551846625121641 ], [ -75.501794196145227, 20.550528876406531 ], [ -75.485800339913737, 20.538488267219748 ], [ -75.467222663095413, 20.532984727463202 ], [ -75.423426887241021, 20.540762031242707 ], [ -75.411076218792459, 20.540865383130892 ], [ -75.406993781437848, 20.541640530386132 ], [ -75.401929491252986, 20.543242499042094 ], [ -75.392705248448465, 20.547505805348635 ], [ -75.390689866843843, 20.54432770376053 ], [ -75.390147263585334, 20.537635606498043 ], [ -75.393402880438543, 20.513115139452111 ], [ -75.395004849094505, 20.508386746051485 ], [ -75.396736008959635, 20.506965644548814 ], [ -75.403479783964826, 20.504330146219274 ], [ -75.407200487012858, 20.502263087771269 ], [ -75.409680955711508, 20.499420884765982 ], [ -75.411748013260194, 20.495777696083792 ], [ -75.412729865191125, 20.492418728241717 ], [ -75.414305996324686, 20.489111436343705 ], [ -75.416760626601615, 20.485571601348283 ], [ -75.420403815283862, 20.482729397443734 ], [ -75.424589606325242, 20.480429795898374 ], [ -75.423504400707486, 20.476812446537167 ], [ -75.417096524285171, 20.468905951548436 ], [ -75.401464403259581, 20.456116034427453 ], [ -75.375471157867651, 20.422862250092749 ], [ -75.384772915038013, 20.415730903258577 ], [ -75.389397955651134, 20.407333481854664 ], [ -75.39355790917017, 20.404232896430983 ], [ -75.398467169724086, 20.403354397287615 ], [ -75.407820603737832, 20.406454982711239 ], [ -75.4114896308418, 20.40808279068824 ], [ -75.416553921026605, 20.409116319462555 ], [ -75.419241096199642, 20.407927761057294 ], [ -75.420946417643052, 20.404697984424445 ], [ -75.421644049633187, 20.401054795742198 ], [ -75.421773240842356, 20.396119696766561 ], [ -75.423039312714081, 20.389608465758045 ], [ -75.426992560658107, 20.381546942937064 ], [ -75.437017788240325, 20.3671808937832 ], [ -75.448567471011984, 20.358266710240457 ], [ -75.459962124152696, 20.351471259291145 ], [ -75.472545335698669, 20.346717027468799 ], [ -75.477325405942736, 20.342841294789878 ], [ -75.479134081072971, 20.340024929307049 ], [ -75.475129157184824, 20.331498318492606 ], [ -75.464561327243416, 20.31108612722295 ], [ -75.462106696067167, 20.294601345475712 ], [ -75.463501960047381, 20.262329413071939 ], [ -75.465181443968447, 20.256929226102898 ], [ -75.467351854304638, 20.254758815766706 ], [ -75.470633307780929, 20.252355862333161 ], [ -75.473320482054589, 20.25000458394436 ], [ -75.475955980384185, 20.246258043373984 ], [ -75.48045182978808, 20.238170681231963 ], [ -75.481511196984115, 20.233674831828012 ], [ -75.480994432147327, 20.22729279202872 ], [ -75.47528418591645, 20.203366604185419 ], [ -75.470219895731589, 20.188974718408531 ], [ -75.467816942298043, 20.18471141210199 ], [ -75.462726812792141, 20.171404731043481 ], [ -75.461874152070436, 20.169957791119145 ], [ -75.460039639417801, 20.1679424104139 ], [ -75.450505337351444, 20.161457016927784 ], [ -75.451202969341523, 20.134895330754887 ], [ -75.448102383018522, 20.123500678513494 ], [ -75.445544399954088, 20.121433620964808 ], [ -75.442521327996872, 20.120658473709568 ], [ -75.438361376276475, 20.120348416246372 ], [ -75.432082689264689, 20.117015285926698 ], [ -75.429628058987703, 20.112545274045146 ], [ -75.428827074210119, 20.103631090502404 ], [ -75.430480719709408, 20.098205064212323 ], [ -75.43327124677063, 20.094665229216957 ], [ -75.4569390530948, 20.083528958494639 ], [ -75.468798794228974, 20.069653835755901 ], [ -75.47295874684869, 20.067199205478914 ], [ -75.476111009115755, 20.067199205478914 ], [ -75.489676072592658, 20.061721503244769 ], [ -75.488280808612387, 20.024617825552184 ], [ -75.483707444842707, 20.009528306885841 ], [ -75.470529954993424, 19.98888357251883 ], [ -75.464277106403301, 19.98177806230774 ], [ -75.442753871993602, 19.962838650283459 ], [ -75.382111579186017, 19.882585150983914 ], [ -75.382080421154143, 19.882543917011262 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/dominican republic.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/dominican republic.geojson new file mode 100644 index 0000000000000..6af4a2f9fb0fe --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/dominican republic.geojson @@ -0,0 +1,38 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "DO-15", "NAME_1": "Monte Cristi" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.746041408999929, 19.649017002000036 ], [ -71.745047566999943, 19.664898987000058 ], [ -71.748613240999902, 19.682598165000073 ], [ -71.757435675999943, 19.710109768000052 ], [ -71.738270636999914, 19.706122137000079 ], [ -71.720326300999943, 19.697455145000049 ], [ -71.724110480999911, 19.717189846000053 ], [ -71.741851365999935, 19.755804755000042 ], [ -71.740793423999946, 19.765692450000074 ], [ -71.740793423999946, 19.773179429000038 ], [ -71.767648891999897, 19.774481512000079 ], [ -71.771066860999952, 19.785142320000091 ], [ -71.760243292999917, 19.800930080000057 ], [ -71.744496222999942, 19.817206122000073 ], [ -71.739979620999918, 19.820257880000042 ], [ -71.734852667999917, 19.821275132000039 ], [ -71.723703579999949, 19.820990302000041 ], [ -71.716908331999946, 19.823635158000059 ], [ -71.705799933999913, 19.836493231000077 ], [ -71.699818488999938, 19.841498114000046 ], [ -71.687896287999934, 19.84601471600007 ], [ -71.679025844999899, 19.848089911000045 ], [ -71.670277472999942, 19.851996161000045 ], [ -71.658802863999938, 19.86196523600006 ], [ -71.665638800999943, 19.874497789000088 ], [ -71.666737433999913, 19.885687567000048 ], [ -71.661447719999899, 19.893622137000079 ], [ -71.648589647999927, 19.896714585000041 ], [ -71.64085852799991, 19.895575262000079 ], [ -71.628895636999914, 19.890448309000078 ], [ -71.621245897999927, 19.88930898600006 ], [ -71.617909308999913, 19.891424872000073 ], [ -71.610951300999943, 19.900824286000045 ], [ -71.607329881999931, 19.902899481000077 ], [ -71.504628058999913, 19.910345770000049 ], [ -71.478505011999914, 19.90688711100006 ], [ -71.452707485999952, 19.898098049000055 ], [ -71.357248501999948, 19.851263739000046 ], [ -71.329213019999941, 19.845892645000049 ], [ -71.302601691999939, 19.855698960000041 ], [ -71.282460089999915, 19.841782945000091 ], [ -71.268055792999917, 19.835516669000071 ], [ -71.223744269999941, 19.834051825000074 ], [ -71.221774161131975, 19.834566661839293 ], [ -71.214975755027069, 19.800626329341583 ], [ -71.195054491071915, 19.771584174470036 ], [ -71.163919440229961, 19.763057562756273 ], [ -71.133972947793268, 19.751766262403066 ], [ -71.145031704149801, 19.722465725113125 ], [ -71.153687507072789, 19.692493394254711 ], [ -71.150819464746462, 19.659420477972674 ], [ -71.148390671991933, 19.626295884847195 ], [ -71.172678595940454, 19.628621323914956 ], [ -71.17895728205292, 19.60730479597953 ], [ -71.172781948727959, 19.570872910956041 ], [ -71.184202440290392, 19.536508084380557 ], [ -71.201514045236991, 19.542063300081224 ], [ -71.216319343063219, 19.532218940551672 ], [ -71.247764452267631, 19.535009466713518 ], [ -71.278951179053649, 19.552321072559437 ], [ -71.300293545410796, 19.549711411752241 ], [ -71.319749722271865, 19.54025462495099 ], [ -71.352202520929609, 19.537644965043114 ], [ -71.382588263837306, 19.548367825514731 ], [ -71.3997965159964, 19.560537625011364 ], [ -71.413051520211468, 19.544543768779874 ], [ -71.454211798635583, 19.562940579344229 ], [ -71.492297329158419, 19.58684092876581 ], [ -71.507361009403041, 19.612860012579517 ], [ -71.532501594073324, 19.619629625107109 ], [ -71.637714809990484, 19.607330634401251 ], [ -71.734763150299159, 19.646294664067455 ], [ -71.746041408999929, 19.649017002000036 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-05", "NAME_1": "Dajabón" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.749517077051451, 19.279707722733178 ], [ -71.753729206999907, 19.28378529900003 ], [ -71.771557576999953, 19.307556457000075 ], [ -71.776518514999907, 19.327503561000086 ], [ -71.769955607999918, 19.333808085 ], [ -71.742980508999977, 19.348380839000058 ], [ -71.733472046999907, 19.355460511000089 ], [ -71.720811320999957, 19.385949606000068 ], [ -71.715281942999951, 19.391659851000028 ], [ -71.703861450999852, 19.414630025000079 ], [ -71.703189656999967, 19.459278463000103 ], [ -71.715126912999921, 19.53746490500005 ], [ -71.743083862999924, 19.600070903000059 ], [ -71.747683064999961, 19.622782695000026 ], [ -71.746041408999929, 19.649017002000036 ], [ -71.734763150299159, 19.646294664067455 ], [ -71.637714809990484, 19.607330634401251 ], [ -71.532501594073324, 19.619629625107109 ], [ -71.507361009403041, 19.612860012579517 ], [ -71.492297329158419, 19.58684092876581 ], [ -71.454211798635583, 19.562940579344229 ], [ -71.413051520211468, 19.544543768779874 ], [ -71.436331752908075, 19.508086046234041 ], [ -71.448656582035596, 19.46581472377045 ], [ -71.446460334177061, 19.443232123064035 ], [ -71.454082608325677, 19.422199815069405 ], [ -71.466174892557206, 19.358637803991428 ], [ -71.515060797917499, 19.338018907146818 ], [ -71.505138923122786, 19.316418158371278 ], [ -71.488266567747871, 19.298848171006284 ], [ -71.505319790276076, 19.281975816530689 ], [ -71.525809495911517, 19.270193589762357 ], [ -71.549632330967313, 19.277764187067589 ], [ -71.574075282748083, 19.284042874079375 ], [ -71.586348435931541, 19.270167752239956 ], [ -71.593764003605884, 19.251900132884828 ], [ -71.614925502809683, 19.244484565210485 ], [ -71.635105150082609, 19.232934882438883 ], [ -71.651732717191123, 19.21792388447966 ], [ -71.716522176999888, 19.247766825000028 ], [ -71.749517077051451, 19.279707722733178 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-07", "NAME_1": "La Estrelleta" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.862456421999951, 18.947087504000038 ], [ -71.865401977999852, 18.964424948000058 ], [ -71.848142048999961, 18.975483704000041 ], [ -71.796827351999923, 18.988609518000104 ], [ -71.783701537999946, 18.996309306000015 ], [ -71.740345011999864, 19.041887919000075 ], [ -71.710424356999937, 19.081652934000104 ], [ -71.695283161999924, 19.094546204 ], [ -71.661383422999904, 19.117593893000063 ], [ -71.648774373999885, 19.135293071000078 ], [ -71.64365840699989, 19.15247548400005 ], [ -71.63911088099988, 19.212110088000045 ], [ -71.651732717191123, 19.21792388447966 ], [ -71.635105150082609, 19.232934882438883 ], [ -71.614925502809683, 19.244484565210485 ], [ -71.593764003605884, 19.251900132884828 ], [ -71.586348435931541, 19.270167752239956 ], [ -71.574075282748083, 19.284042874079375 ], [ -71.549632330967313, 19.277764187067589 ], [ -71.525809495911517, 19.270193589762357 ], [ -71.505319790276076, 19.281975816530689 ], [ -71.488266567747871, 19.298848171006284 ], [ -71.446822069382961, 19.273604234447873 ], [ -71.415893724116074, 19.234485175150724 ], [ -71.371271125062378, 19.213272000002803 ], [ -71.327371996420482, 19.191076972024632 ], [ -71.334322476101363, 19.160923774012929 ], [ -71.336337856806608, 19.129995428746042 ], [ -71.367757127589357, 19.10718028404284 ], [ -71.405842658112192, 19.105139064915875 ], [ -71.43721025295082, 19.123251655539434 ], [ -71.471135829954562, 19.128393460090081 ], [ -71.491367154070872, 19.092349147794891 ], [ -71.50309770399582, 19.049716091024777 ], [ -71.518755663443073, 19.018064277144674 ], [ -71.549709846232417, 19.009460151065127 ], [ -71.577976853848725, 19.006747138369747 ], [ -71.60004269061767, 18.987756049502082 ], [ -71.624847377604397, 18.937836615367473 ], [ -71.633244798108933, 18.88380890635591 ], [ -71.615907354740614, 18.862905789570505 ], [ -71.627896287983276, 18.814200751363558 ], [ -71.605313687276862, 18.800248114259034 ], [ -71.585004848794711, 18.78340159820516 ], [ -71.577821825117098, 18.760431422971749 ], [ -71.577873501061219, 18.735859279981753 ], [ -71.559321661765239, 18.717049059166754 ], [ -71.532294887598994, 18.711002916151642 ], [ -71.520745204827335, 18.682580878005126 ], [ -71.534982061872654, 18.650774034494077 ], [ -71.597794765915694, 18.663667304402566 ], [ -71.661925217774581, 18.668421536224912 ], [ -71.729440476796583, 18.678446763807074 ], [ -71.784897638415259, 18.684730212729107 ], [ -71.758070027999878, 18.700513407000031 ], [ -71.744065714999891, 18.711442973000104 ], [ -71.732076782999911, 18.730072327000059 ], [ -71.725255492999878, 18.746970520000062 ], [ -71.72034623299993, 18.76544484500009 ], [ -71.71884761599992, 18.784229228000086 ], [ -71.726909139999918, 18.82352915500006 ], [ -71.727942668999901, 18.864069316000084 ], [ -71.733472046999907, 18.882569479 ], [ -71.740913452999933, 18.891612854000059 ], [ -71.763806111999941, 18.911508281000053 ], [ -71.772952839999931, 18.921714376000054 ], [ -71.787112182999891, 18.950033061000042 ], [ -71.796258910999967, 18.957061056000057 ], [ -71.819668334999932, 18.957810364000053 ], [ -71.844524698999891, 18.949748841000044 ], [ -71.862456421999951, 18.947087504000038 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-10", "NAME_1": "Independencia" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.79177913299992, 18.680681698000072 ], [ -71.784897638415259, 18.684730212729107 ], [ -71.729440476796583, 18.678446763807074 ], [ -71.661925217774581, 18.668421536224912 ], [ -71.597794765915694, 18.663667304402566 ], [ -71.534982061872654, 18.650774034494077 ], [ -71.567460699851381, 18.642299098724436 ], [ -71.59947424983676, 18.632583930404053 ], [ -71.604280157603171, 18.6215251731482 ], [ -71.602678188947266, 18.608812771292321 ], [ -71.609447800575538, 18.586256008108251 ], [ -71.62066158656296, 18.565301215378781 ], [ -71.592601283622344, 18.47799388271153 ], [ -71.489971890090658, 18.439753323457069 ], [ -71.451627977149428, 18.423268540810511 ], [ -71.415454475443653, 18.402107042505975 ], [ -71.376722988874803, 18.392727769171188 ], [ -71.338404914355294, 18.407016303059947 ], [ -71.290552537769372, 18.404174099155341 ], [ -71.264585129899785, 18.357872016180579 ], [ -71.236731533433499, 18.335987047464243 ], [ -71.200764737302791, 18.338364163375445 ], [ -71.233915167950613, 18.296325384908585 ], [ -71.286625129146387, 18.282837835797466 ], [ -71.337061327218464, 18.299167588813134 ], [ -71.381373867010325, 18.290124213161903 ], [ -71.366646084449201, 18.232815049774729 ], [ -71.351013963423668, 18.177960517563804 ], [ -71.373984137757759, 18.17501495997243 ], [ -71.399305588681955, 18.181603705346731 ], [ -71.417573208037084, 18.162974350785646 ], [ -71.42193986713113, 18.135947577518664 ], [ -71.451834682724439, 18.159873766261285 ], [ -71.480463426445965, 18.185453600503251 ], [ -71.515086636339163, 18.198811957505825 ], [ -71.551621874150158, 18.207622789160382 ], [ -71.636784634003618, 18.247672024444341 ], [ -71.719492763580149, 18.292113756344747 ], [ -71.721708773141359, 18.292996236786905 ], [ -71.721111735999841, 18.293973823000087 ], [ -71.709339151999927, 18.313250224000015 ], [ -71.711509562999936, 18.316144105000106 ], [ -71.720707967999942, 18.323973083000041 ], [ -71.734970662999899, 18.332938945000066 ], [ -71.788714152999916, 18.352214254 ], [ -71.826437947999864, 18.37616628100001 ], [ -71.834551147999946, 18.38508046500003 ], [ -71.8497440189999, 18.406448670000131 ], [ -71.858167277999883, 18.413554179000059 ], [ -71.897182983999897, 18.422881775000107 ], [ -71.912169148999851, 18.430736593000049 ], [ -71.918163615999873, 18.449236755000058 ], [ -71.914391235999858, 18.460217997000044 ], [ -71.906898152999929, 18.464300436000045 ], [ -71.901575479999877, 18.469778138000052 ], [ -71.904055949999957, 18.484790141000119 ], [ -71.910515502999914, 18.494272766 ], [ -72.000949259999885, 18.582458598000059 ], [ -72.009837605999905, 18.598814189 ], [ -71.992629353999916, 18.61113901800006 ], [ -71.955474, 18.618606262000085 ], [ -71.88028479099998, 18.605402934 ], [ -71.841579141999972, 18.617986145000103 ], [ -71.828556680999924, 18.631292827000024 ], [ -71.807989460999949, 18.664649964000077 ], [ -71.794346883999935, 18.679171041000032 ], [ -71.79177913299992, 18.680681698000072 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-16", "NAME_1": "Pedernales" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -71.776234503999945, 18.039252020000063 ], [ -71.764271199999968, 18.069492493000084 ], [ -71.760653849999898, 18.086804097000098 ], [ -71.762875935999887, 18.115846253000072 ], [ -71.762204141999916, 18.132486064000105 ], [ -71.764581257999851, 18.143674011000044 ], [ -71.775329955999979, 18.172328593000131 ], [ -71.776828572999875, 18.181785380000079 ], [ -71.77403804599993, 18.201474101000045 ], [ -71.766131551999877, 18.220258484000041 ], [ -71.721708773141359, 18.292996236786905 ], [ -71.719492763580149, 18.292113756344747 ], [ -71.636784634003618, 18.247672024444341 ], [ -71.551621874150158, 18.207622789160382 ], [ -71.515086636339163, 18.198811957505825 ], [ -71.480463426445965, 18.185453600503251 ], [ -71.451834682724439, 18.159873766261285 ], [ -71.42193986713113, 18.135947577518664 ], [ -71.391166550595813, 18.118971869356244 ], [ -71.389900478724087, 18.078225002981469 ], [ -71.388970302737278, 18.05993154520462 ], [ -71.390908169076738, 18.041948146689606 ], [ -71.396385871310883, 18.031251126438292 ], [ -71.406411098893102, 18.027427069703492 ], [ -71.416849737625284, 18.023861396286406 ], [ -71.423748542261421, 18.014998887788408 ], [ -71.402225307851666, 17.963865057726196 ], [ -71.352925991341408, 17.925081895213282 ], [ -71.327656216361277, 17.930895494231663 ], [ -71.2976838846036, 17.929526069572432 ], [ -71.281715867693151, 17.894566961995679 ], [ -71.281741706114815, 17.855732123538644 ], [ -71.281044074124736, 17.853225816418274 ], [ -71.281017156045905, 17.853130772829296 ], [ -71.282093878999945, 17.853989976000037 ], [ -71.283599412999934, 17.846747137000079 ], [ -71.285145636999914, 17.844183661000045 ], [ -71.288929816999939, 17.841009833000044 ], [ -71.282093878999945, 17.841009833000044 ], [ -71.286122199999909, 17.832586981000077 ], [ -71.29133053299995, 17.826157945000091 ], [ -71.297718878999945, 17.821966864000046 ], [ -71.305653449999909, 17.820502020000049 ], [ -71.309315558999913, 17.816392320000091 ], [ -71.315825975999928, 17.796454169000071 ], [ -71.319650844999899, 17.789211330000057 ], [ -71.331857876999948, 17.772406317000048 ], [ -71.36554928299995, 17.678412177000041 ], [ -71.375884568999936, 17.660142320000091 ], [ -71.417225714999915, 17.604803778000075 ], [ -71.427235480999911, 17.609279690000051 ], [ -71.43586178299995, 17.617092190000051 ], [ -71.436350063999953, 17.621283270000049 ], [ -71.446115688999953, 17.629339911000045 ], [ -71.514881964999915, 17.737779039000088 ], [ -71.531605597999942, 17.755072333000044 ], [ -71.565256313999953, 17.767523505000042 ], [ -71.645130988999938, 17.75726959800005 ], [ -71.679310675999943, 17.765285549000055 ], [ -71.669667120999918, 17.772406317000048 ], [ -71.637766079999949, 17.804022528000075 ], [ -71.630930141999897, 17.816799221000053 ], [ -71.632394985999952, 17.838324286000045 ], [ -71.636586066999939, 17.853461005000042 ], [ -71.652007615999935, 17.881984768000052 ], [ -71.662831183999913, 17.897691148000092 ], [ -71.664947068999936, 17.903469143000052 ], [ -71.665638800999943, 17.91547272300005 ], [ -71.658802863999938, 17.953314520000049 ], [ -71.66624915299991, 17.970770575000074 ], [ -71.68382727799991, 17.990179755000042 ], [ -71.720326300999943, 18.019110419000071 ], [ -71.776234503999945, 18.039252020000063 ] ] ], [ [ [ -71.524484829999949, 17.54555898600006 ], [ -71.541167772999927, 17.554632880000042 ], [ -71.541371222999942, 17.576157945000091 ], [ -71.532215949999909, 17.601304429000038 ], [ -71.521066860999952, 17.621283270000049 ], [ -71.506947394999941, 17.613674221000053 ], [ -71.492583787999934, 17.603664455000057 ], [ -71.46711178299995, 17.580267645000049 ], [ -71.482533331999946, 17.57562897300005 ], [ -71.507394985999952, 17.551255601000037 ], [ -71.524484829999949, 17.54555898600006 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-11", "NAME_1": "La Altagracia" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -68.664051886999914, 18.169338283000059 ], [ -68.612375454999949, 18.170803127000056 ], [ -68.598784959999932, 18.166205145000049 ], [ -68.588693813999953, 18.153387762000079 ], [ -68.577504035999937, 18.133734442000048 ], [ -68.570179816999939, 18.115708726000037 ], [ -68.571848110999952, 18.107855536000045 ], [ -68.587025519999941, 18.111070054000038 ], [ -68.619292772999927, 18.125148830000057 ], [ -68.636097785999937, 18.12836334800005 ], [ -68.653920050999943, 18.126288153000075 ], [ -68.684885219999899, 18.116888739000046 ], [ -68.701893683999913, 18.11469147300005 ], [ -68.737049933999913, 18.123602606000077 ], [ -68.762074347999942, 18.14516836100006 ], [ -68.778187628999945, 18.172023830000057 ], [ -68.786936001999948, 18.196682033000059 ], [ -68.772084113999938, 18.200873114000046 ], [ -68.75454667899993, 18.197658596000053 ], [ -68.737172003999945, 18.189520575000074 ], [ -68.722320115999935, 18.179266669000071 ], [ -68.710764126999948, 18.175360419000071 ], [ -68.664051886999914, 18.169338283000059 ] ] ], [ [ [ -68.785145636999914, 18.979885158000059 ], [ -68.776966925999943, 18.974351304000038 ], [ -68.76781165299991, 18.96946849200009 ], [ -68.749989386999914, 18.968085028000075 ], [ -68.739735480999911, 18.964422919000071 ], [ -68.623524542999917, 18.861883856000077 ], [ -68.580799933999913, 18.812567450000074 ], [ -68.520497199999909, 18.768866278000075 ], [ -68.477284308999913, 18.740220445000091 ], [ -68.464995897999927, 18.73501211100006 ], [ -68.458566860999952, 18.731024481000077 ], [ -68.413400844999899, 18.689601955000057 ], [ -68.356190558999913, 18.65656159100007 ], [ -68.328602667999917, 18.616522528000075 ], [ -68.334055141999954, 18.577297268000052 ], [ -68.42804928299995, 18.441229559000078 ], [ -68.434681769999941, 18.435777085000041 ], [ -68.441273566999939, 18.429022528000075 ], [ -68.444325324999909, 18.419501044000071 ], [ -68.442494269999941, 18.384751695000091 ], [ -68.444325324999909, 18.374823309000078 ], [ -68.455677863999938, 18.357855536000045 ], [ -68.472157355999911, 18.349839585000041 ], [ -68.49282792899993, 18.347479559000078 ], [ -68.516590949999909, 18.347479559000078 ], [ -68.534901495999918, 18.353338934000078 ], [ -68.57453365799995, 18.378159898000092 ], [ -68.588937954999949, 18.38226959800005 ], [ -68.605458136999914, 18.37173086100006 ], [ -68.602853969999899, 18.355658270000049 ], [ -68.597523566999939, 18.336615302000041 ], [ -68.606027798999946, 18.317084052000041 ], [ -68.618316209999932, 18.301459052000041 ], [ -68.626088019999941, 18.283351955000057 ], [ -68.641509568999936, 18.225165106000077 ], [ -68.647084113999938, 18.214829820000091 ], [ -68.65843665299991, 18.210923570000091 ], [ -68.742990688999953, 18.20453522300005 ], [ -68.760243292999917, 18.210353908000059 ], [ -68.762521938999953, 18.246975002000056 ], [ -68.786854620999918, 18.295396226000037 ], [ -68.820139126999948, 18.342474677000041 ], [ -68.849598761999914, 18.374823309000078 ], [ -68.880970831999946, 18.395493882000039 ], [ -68.901149176876245, 18.403656131063737 ], [ -68.883283453768342, 18.444275011282741 ], [ -68.865584276093443, 18.489724433535741 ], [ -68.85201921261654, 18.51863739719812 ], [ -68.853104418234295, 18.549824123984138 ], [ -68.874136726228926, 18.574732163758313 ], [ -68.899328985943953, 18.596436266220678 ], [ -68.918707648439238, 18.629741726499446 ], [ -68.935295782973981, 18.665682685107811 ], [ -68.942866380279213, 18.686404933840606 ], [ -68.938861457290386, 18.708109036302972 ], [ -68.916588914946431, 18.720743922893689 ], [ -68.889898036665045, 18.7248005227259 ], [ -68.838712530658768, 18.763402818085581 ], [ -68.818041957870037, 18.82004018790434 ], [ -68.845172084823844, 18.869261990048813 ], [ -68.837446458787042, 18.911249090772912 ], [ -68.831736212556166, 18.92217865592022 ], [ -68.832408006124581, 18.935692044352322 ], [ -68.803830939246438, 18.956827704235138 ], [ -68.785145636999914, 18.979885158000059 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-08", "NAME_1": "El Seybo" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.211742894119254, 19.020982731867548 ], [ -69.173247850999928, 19.011135158000059 ], [ -69.157460089999915, 19.012193101000037 ], [ -69.138661261999914, 19.022284247000073 ], [ -69.144886847999942, 19.02960846600007 ], [ -69.157338019999941, 19.036688544000071 ], [ -69.157460089999915, 19.046372789000088 ], [ -69.139515753999945, 19.051214911000045 ], [ -69.123890753999945, 19.037787177000041 ], [ -69.102853969999899, 19.005357164000088 ], [ -69.089263475999928, 18.997870184000078 ], [ -69.074126756999931, 18.993557033000059 ], [ -69.06118730399993, 18.988185940000051 ], [ -69.054432745999918, 18.977484442000048 ], [ -69.042469855999911, 18.986761786000045 ], [ -69.018055792999917, 18.997463283000059 ], [ -69.006581183999913, 19.005357164000088 ], [ -69.014230923999946, 19.013413804000038 ], [ -69.010568813999953, 19.015366929000038 ], [ -69.001576300999943, 19.015611070000091 ], [ -68.992990688999953, 19.018459377000056 ], [ -68.982533331999946, 19.028794664000088 ], [ -68.979359503999945, 19.032863674000055 ], [ -68.975412563999953, 19.033148505000042 ], [ -68.939564581999946, 19.031317450000074 ], [ -68.91860917899993, 19.027289130000042 ], [ -68.899810350999928, 19.020900783000059 ], [ -68.88312740799995, 19.012193101000037 ], [ -68.881214972999942, 19.009426174000055 ], [ -68.88117428299995, 19.005804755000042 ], [ -68.880360480999911, 19.002020575000074 ], [ -68.876291469999899, 18.998602606000077 ], [ -68.855824347999942, 18.991766669000071 ], [ -68.853993292999917, 18.992092190000051 ], [ -68.818226691999939, 18.984930731000077 ], [ -68.795887824999909, 18.984116929000038 ], [ -68.786854620999918, 18.981024481000077 ], [ -68.785145636999914, 18.979885158000059 ], [ -68.803830939246438, 18.956827704235138 ], [ -68.832408006124581, 18.935692044352322 ], [ -68.831736212556166, 18.92217865592022 ], [ -68.837446458787042, 18.911249090772912 ], [ -68.845172084823844, 18.869261990048813 ], [ -68.818041957870037, 18.82004018790434 ], [ -68.838712530658768, 18.763402818085581 ], [ -68.889898036665045, 18.7248005227259 ], [ -68.916588914946431, 18.720743922893689 ], [ -68.938861457290386, 18.708109036302972 ], [ -68.942866380279213, 18.686404933840606 ], [ -68.935295782973981, 18.665682685107811 ], [ -68.978988206940187, 18.649482123301311 ], [ -69.004180466655214, 18.603257554692391 ], [ -69.042524379596443, 18.55698130924003 ], [ -69.092702196149446, 18.527344876065172 ], [ -69.085312465997504, 18.553415635822944 ], [ -69.080170661446857, 18.576489162944483 ], [ -69.10952287468092, 18.579408881214874 ], [ -69.140942144564292, 18.575119737385933 ], [ -69.169390021132585, 18.595041002240464 ], [ -69.193677945081106, 18.6203882924857 ], [ -69.210007697197454, 18.624703273836985 ], [ -69.226750861363143, 18.623101305181081 ], [ -69.240470953571617, 18.631085312736957 ], [ -69.253570929954435, 18.64023204207507 ], [ -69.241530320767652, 18.677129015091964 ], [ -69.224192878298709, 18.715111191927974 ], [ -69.219826219204663, 18.757795925541529 ], [ -69.235277473076906, 18.797948512713674 ], [ -69.292638312408201, 18.854534207487688 ], [ -69.328553432594845, 18.924064846315616 ], [ -69.27199357804119, 18.933599148381973 ], [ -69.189543829983734, 18.915279853082723 ], [ -69.217061529665841, 18.962382920835125 ], [ -69.212333137164535, 19.017056585892703 ], [ -69.212281460321151, 19.017366645154539 ], [ -69.211742894119254, 19.020982731867548 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-30", "NAME_1": "Hato Mayor" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.620887150421652, 19.10196055233763 ], [ -69.608469204999949, 19.093451239000046 ], [ -69.553293423999946, 19.101467190000051 ], [ -69.534250454999949, 19.094794012000079 ], [ -69.510487433999913, 19.102036851000037 ], [ -69.463449673999946, 19.08470286700009 ], [ -69.438628709999932, 19.08734772300005 ], [ -69.444732225999928, 19.092352606000077 ], [ -69.452748175999943, 19.096909898000035 ], [ -69.462310350999928, 19.100287177000041 ], [ -69.473378058999913, 19.101629950000074 ], [ -69.473378058999913, 19.108465887000079 ], [ -69.419992641999897, 19.111151434000078 ], [ -69.404449022999927, 19.108465887000079 ], [ -69.386708136999914, 19.096096096000053 ], [ -69.372954881999931, 19.065375067000048 ], [ -69.356068488999938, 19.053208726000037 ], [ -69.338978644999941, 19.048895575000074 ], [ -69.304595506999931, 19.044867255000042 ], [ -69.211742894119254, 19.020982731867548 ], [ -69.212281460321151, 19.017366645154539 ], [ -69.212333137164535, 19.017056585892703 ], [ -69.217061529665841, 18.962382920835125 ], [ -69.189543829983734, 18.915279853082723 ], [ -69.27199357804119, 18.933599148381973 ], [ -69.328553432594845, 18.924064846315616 ], [ -69.292638312408201, 18.854534207487688 ], [ -69.235277473076906, 18.797948512713674 ], [ -69.219826219204663, 18.757795925541529 ], [ -69.224192878298709, 18.715111191927974 ], [ -69.241530320767652, 18.677129015091964 ], [ -69.253570929954435, 18.64023204207507 ], [ -69.287677375010844, 18.617571926103494 ], [ -69.303903775239007, 18.580235704414235 ], [ -69.325297818439537, 18.553777371028843 ], [ -69.353745694108511, 18.521970527517794 ], [ -69.368990240607104, 18.554733385437373 ], [ -69.382917040189227, 18.588116360081926 ], [ -69.405758023314092, 18.621111761998179 ], [ -69.428547328696254, 18.654107163914489 ], [ -69.43557532364224, 18.694828192766863 ], [ -69.441259732350773, 18.736272691131774 ], [ -69.459165615600682, 18.767924505911196 ], [ -69.459113938757241, 18.802573554226115 ], [ -69.441311408294837, 18.825879625344442 ], [ -69.420459968352873, 18.846550198133116 ], [ -69.399918585874047, 18.858616644842243 ], [ -69.380875821062261, 18.871122341123112 ], [ -69.399350145093138, 18.888769842853947 ], [ -69.435601162063961, 18.893265693157218 ], [ -69.484512905845918, 18.918742173712303 ], [ -69.534716559921264, 18.942358303193146 ], [ -69.591663988102539, 18.969720974143627 ], [ -69.637836879868075, 19.008891710284161 ], [ -69.624452684443838, 19.037468777162303 ], [ -69.618639086324777, 19.067932034435842 ], [ -69.621558803695848, 19.094571234974524 ], [ -69.620887150421652, 19.10196055233763 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-20", "NAME_1": "Samaná" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.771477950746828, 19.303253286010317 ], [ -69.767689581999946, 19.299750067000048 ], [ -69.733469204999949, 19.28656647300005 ], [ -69.71320553299995, 19.289740302000041 ], [ -69.674387173999946, 19.303859768000052 ], [ -69.654367641999897, 19.307033596000053 ], [ -69.609364386999914, 19.308783270000049 ], [ -69.589426235999952, 19.31281159100007 ], [ -69.568959113999938, 19.320705471000053 ], [ -69.539418097999942, 19.339422919000071 ], [ -69.52798417899993, 19.341782945000091 ], [ -69.517648891999897, 19.339667059000078 ], [ -69.496449347999942, 19.329779364000046 ], [ -69.483306443999936, 19.32758209800005 ], [ -69.459095831999946, 19.333319403000075 ], [ -69.448597785999937, 19.334377346000053 ], [ -69.442779100999928, 19.334173895000049 ], [ -69.437367316999939, 19.332953192000048 ], [ -69.433420376999948, 19.329901434000078 ], [ -69.431792772999927, 19.324123440000051 ], [ -69.428618943999936, 19.319240627000056 ], [ -69.421701626999948, 19.321112372000073 ], [ -69.410715298999946, 19.32758209800005 ], [ -69.352691209999932, 19.305121161000045 ], [ -69.335601365999935, 19.293402411000045 ], [ -69.324289516999897, 19.31509023600006 ], [ -69.305897589999915, 19.331122137000079 ], [ -69.260487433999913, 19.354885158000059 ], [ -69.231271938999953, 19.363348700000074 ], [ -69.224354620999918, 19.351792710000041 ], [ -69.232085740999935, 19.327948309000078 ], [ -69.246815558999913, 19.299627997000073 ], [ -69.22687740799995, 19.292669989000046 ], [ -69.204335089999915, 19.292792059000078 ], [ -69.182443813999953, 19.298163153000075 ], [ -69.16429602799991, 19.307033596000053 ], [ -69.158355272999927, 19.285101630000042 ], [ -69.171376105999911, 19.26788971600007 ], [ -69.189320441999939, 19.25226471600007 ], [ -69.198394334999932, 19.235052802000041 ], [ -69.202707485999952, 19.216945705000057 ], [ -69.214344855999911, 19.20062897300005 ], [ -69.231800910999937, 19.188666083000044 ], [ -69.253651495999918, 19.183539130000042 ], [ -69.332142706999946, 19.197211005000042 ], [ -69.418120897999927, 19.190985419000071 ], [ -69.438384568999936, 19.196478583000044 ], [ -69.475453253999945, 19.214016018000052 ], [ -69.602935350999928, 19.228989976000037 ], [ -69.617298956999946, 19.22524648600006 ], [ -69.622792120999918, 19.211859442000048 ], [ -69.626047329999949, 19.164292710000041 ], [ -69.633534308999913, 19.12368398600006 ], [ -69.630441860999952, 19.108465887000079 ], [ -69.620887150421652, 19.10196055233763 ], [ -69.621558803695848, 19.094571234974524 ], [ -69.618639086324777, 19.067932034435842 ], [ -69.624452684443838, 19.037468777162303 ], [ -69.637836879868075, 19.008891710284161 ], [ -69.666930711583063, 19.029458930285386 ], [ -69.698608364784207, 19.046537991235311 ], [ -69.727340461293238, 19.066872667239807 ], [ -69.755788336962155, 19.087594915972602 ], [ -69.736125453626755, 19.105397447334326 ], [ -69.732533941787949, 19.136687526907849 ], [ -69.719020555154486, 19.152655544717618 ], [ -69.703285082240768, 19.162603257933995 ], [ -69.676749233590272, 19.179423936465469 ], [ -69.676800910433656, 19.206476549053491 ], [ -69.737314012032016, 19.220119126896179 ], [ -69.786148241448188, 19.198053290127234 ], [ -69.792814501188275, 19.221591905242235 ], [ -69.786587491019873, 19.246344916284841 ], [ -69.77725989362915, 19.271382148167561 ], [ -69.773642544268, 19.298202215859533 ], [ -69.771477950746828, 19.303253286010317 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-14", "NAME_1": "María Trinidad Sánchez" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.094044021252884, 19.636723807569691 ], [ -70.061024542999917, 19.670111395000049 ], [ -70.042103644999941, 19.67845286700009 ], [ -69.986683722999942, 19.677639065000051 ], [ -69.959543423999946, 19.680121161000045 ], [ -69.947255011999914, 19.678656317000048 ], [ -69.932036912999934, 19.670152085000041 ], [ -69.897938605999911, 19.635972398000035 ], [ -69.887196417999917, 19.61273834800005 ], [ -69.887766079999949, 19.58734772300005 ], [ -69.904164191999939, 19.532375393000052 ], [ -69.884144660999937, 19.524400132000039 ], [ -69.876535610999952, 19.506659247000073 ], [ -69.876820441999939, 19.461004950000074 ], [ -69.874379035999937, 19.441148179000038 ], [ -69.867990688999953, 19.425279039000088 ], [ -69.801380988999938, 19.330877997000073 ], [ -69.771477950746828, 19.303253286010317 ], [ -69.773642544268, 19.298202215859533 ], [ -69.77725989362915, 19.271382148167561 ], [ -69.786587491019873, 19.246344916284841 ], [ -69.792814501188275, 19.221591905242235 ], [ -69.786148241448188, 19.198053290127234 ], [ -69.855420497857665, 19.210739854460712 ], [ -69.922599860095431, 19.240686346897348 ], [ -69.991277839100974, 19.257119451801259 ], [ -70.039931199565217, 19.296109320788503 ], [ -70.053547939885505, 19.319337877540988 ], [ -70.083933681893882, 19.3230327421673 ], [ -70.118686082996305, 19.347088121219826 ], [ -70.131062588067948, 19.389230252474135 ], [ -70.133956467916676, 19.423517563784515 ], [ -70.145738694685008, 19.455195216985658 ], [ -70.17966427258807, 19.477002672235528 ], [ -70.215140144102349, 19.497389024184088 ], [ -70.21209123372347, 19.52596609106223 ], [ -70.206174281917583, 19.551649278091702 ], [ -70.184831915560437, 19.552941189284468 ], [ -70.161474169397366, 19.551416734094971 ], [ -70.111993984834498, 19.578701891579044 ], [ -70.093416307116854, 19.630740058307026 ], [ -70.094044021252884, 19.636723807569691 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-09", "NAME_1": "Espaillat" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.372716378957705, 19.714184419675234 ], [ -70.33617102799991, 19.677639065000051 ], [ -70.319569464999915, 19.666449286000045 ], [ -70.301340298999946, 19.65766022300005 ], [ -70.280832485999952, 19.65180084800005 ], [ -70.235218878999945, 19.64720286700009 ], [ -70.198557094999899, 19.634670315000051 ], [ -70.131418423999946, 19.622137762000079 ], [ -70.116444464999915, 19.622381903000075 ], [ -70.106434699999909, 19.625921942000048 ], [ -70.097523566999939, 19.633205471000053 ], [ -70.094044021252884, 19.636723807569691 ], [ -70.093416307116854, 19.630740058307026 ], [ -70.111993984834498, 19.578701891579044 ], [ -70.161474169397366, 19.551416734094971 ], [ -70.184831915560437, 19.552941189284468 ], [ -70.206174281917583, 19.551649278091702 ], [ -70.21209123372347, 19.52596609106223 ], [ -70.215140144102349, 19.497389024184088 ], [ -70.225785489308862, 19.499326891422868 ], [ -70.236585863247001, 19.499197699314379 ], [ -70.259349331106762, 19.534441025932608 ], [ -70.288339810034188, 19.558573920250183 ], [ -70.318312140892601, 19.542218328812794 ], [ -70.338827684050386, 19.513899644353103 ], [ -70.362443814430492, 19.498706772899254 ], [ -70.374251878721225, 19.52539765118064 ], [ -70.390814174834304, 19.533045762851657 ], [ -70.408900926136823, 19.539453640173349 ], [ -70.442258063258976, 19.500308743353798 ], [ -70.441922167374116, 19.433620307531157 ], [ -70.445720383888613, 19.377344672018978 ], [ -70.467321132664154, 19.3188211127042 ], [ -70.495458949970555, 19.313601792888392 ], [ -70.515561082877639, 19.361505846317755 ], [ -70.536076626035424, 19.357320055276318 ], [ -70.558504198010326, 19.349000149137566 ], [ -70.590078498423964, 19.351945705829621 ], [ -70.61390133258044, 19.368843898726936 ], [ -70.599070197231811, 19.379360052724223 ], [ -70.583670620202952, 19.390548001189302 ], [ -70.583412237784557, 19.412613837058927 ], [ -70.586254441689107, 19.435325628974567 ], [ -70.580518357935887, 19.460311184013904 ], [ -70.566875780093142, 19.481705227214434 ], [ -70.551941291057744, 19.497595729759098 ], [ -70.547703824072187, 19.517827052976088 ], [ -70.525586309560538, 19.564439195212685 ], [ -70.517395596429594, 19.617433377248517 ], [ -70.509824999124419, 19.637302965259607 ], [ -70.494167039677109, 19.650687161583221 ], [ -70.481092901716011, 19.650609646318117 ], [ -70.468535528591758, 19.647664088726685 ], [ -70.450681322185233, 19.649912014327981 ], [ -70.43293046676763, 19.654407863731933 ], [ -70.415050421939384, 19.654278673422027 ], [ -70.39822974340791, 19.659239609920064 ], [ -70.383476122425122, 19.685878811358066 ], [ -70.372716378957705, 19.714184419675234 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-18", "NAME_1": "Puerto Plata" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.221774161131975, 19.834566661839293 ], [ -71.212066209999932, 19.837103583000044 ], [ -71.209339972999942, 19.844794012000079 ], [ -71.208811001999948, 19.854966539000088 ], [ -71.203521287999934, 19.865383205000057 ], [ -71.191761847999942, 19.869696356000077 ], [ -71.183338995999918, 19.860419012000079 ], [ -71.172230597999942, 19.834051825000074 ], [ -71.164418097999942, 19.83860911700009 ], [ -71.15851803299995, 19.843491929000038 ], [ -71.154408331999946, 19.849107164000088 ], [ -71.151722785999937, 19.855698960000041 ], [ -71.160227016999897, 19.858221747000073 ], [ -71.162017381999931, 19.859442450000074 ], [ -71.162180141999897, 19.86204661700009 ], [ -71.165394660999937, 19.868801174000055 ], [ -71.149728969999899, 19.863023179000038 ], [ -71.136586066999939, 19.863714911000045 ], [ -71.123199022999927, 19.866888739000046 ], [ -71.107045050999943, 19.868801174000055 ], [ -71.096791144999941, 19.876206773000035 ], [ -71.078277147999927, 19.909125067000048 ], [ -71.066070115999935, 19.916571356000077 ], [ -71.050852016999897, 19.92023346600007 ], [ -71.018422003999945, 19.935492255000042 ], [ -71.000884568999936, 19.937689520000049 ], [ -70.984730597999942, 19.933742580000057 ], [ -70.969349738999938, 19.925197658000059 ], [ -70.961048956999946, 19.912665106000077 ], [ -70.966175910999937, 19.896714585000041 ], [ -70.946888800999943, 19.88930898600006 ], [ -70.939442511999914, 19.88930898600006 ], [ -70.944447394999941, 19.904730536000045 ], [ -70.946888800999943, 19.910345770000049 ], [ -70.898508266999897, 19.902899481000077 ], [ -70.884266730999911, 19.904282945000091 ], [ -70.854725714999915, 19.910834052000041 ], [ -70.843251105999911, 19.910345770000049 ], [ -70.830962693999936, 19.902533270000049 ], [ -70.786976691999939, 19.852850653000075 ], [ -70.783314581999946, 19.843329169000071 ], [ -70.788644985999952, 19.834051825000074 ], [ -70.750965949999909, 19.833807684000078 ], [ -70.73656165299991, 19.827093817000048 ], [ -70.698475714999915, 19.796820380000042 ], [ -70.662220831999946, 19.779364325000074 ], [ -70.62368730399993, 19.766546942000048 ], [ -70.579090949999909, 19.760199286000045 ], [ -70.518706834999932, 19.759751695000091 ], [ -70.513661261999914, 19.762640692000048 ], [ -70.508534308999913, 19.769354559000078 ], [ -70.496449347999942, 19.777248440000051 ], [ -70.482777472999942, 19.783880927000041 ], [ -70.472727016999897, 19.786851304000038 ], [ -70.433705206999946, 19.775213934000078 ], [ -70.372716378957705, 19.714184419675234 ], [ -70.383476122425122, 19.685878811358066 ], [ -70.39822974340791, 19.659239609920064 ], [ -70.415050421939384, 19.654278673422027 ], [ -70.43293046676763, 19.654407863731933 ], [ -70.450681322185233, 19.649912014327981 ], [ -70.468535528591758, 19.647664088726685 ], [ -70.481092901716011, 19.650609646318117 ], [ -70.494167039677109, 19.650687161583221 ], [ -70.509824999124419, 19.637302965259607 ], [ -70.517395596429594, 19.617433377248517 ], [ -70.525586309560538, 19.564439195212685 ], [ -70.547703824072187, 19.517827052976088 ], [ -70.608604499298167, 19.536120509853617 ], [ -70.63798255095395, 19.58110484501259 ], [ -70.658756477429506, 19.628724676702461 ], [ -70.712138231294318, 19.651100571833922 ], [ -70.715755580655525, 19.592370306944076 ], [ -70.760455694974326, 19.590432441503935 ], [ -70.782702398896561, 19.609139309531486 ], [ -70.805233323658967, 19.627303575199846 ], [ -70.832957729815348, 19.634848334083358 ], [ -70.864118618179646, 19.641747137820118 ], [ -70.906234911012348, 19.64701813447931 ], [ -70.943907030385105, 19.66494985615094 ], [ -70.977651740235615, 19.690478014448786 ], [ -71.01821774035642, 19.702570299579634 ], [ -71.045244513623402, 19.709262396842121 ], [ -71.067491218444957, 19.72525625307361 ], [ -71.099814825893475, 19.740242418053128 ], [ -71.133972947793268, 19.751766262403066 ], [ -71.163919440229961, 19.763057562756273 ], [ -71.195054491071915, 19.771584174470036 ], [ -71.214975755027069, 19.800626329341583 ], [ -71.221774161131975, 19.834566661839293 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-04", "NAME_1": "Barahona" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.96561521108714, 18.262083186130727 ], [ -70.965809699999909, 18.262152411000045 ], [ -70.972035285999937, 18.27024974200009 ], [ -70.977284308999913, 18.280259507000039 ], [ -70.983794725999928, 18.289129950000074 ], [ -70.994252081999946, 18.296616929000038 ], [ -71.004872199999909, 18.301011460000041 ], [ -71.048247850999928, 18.31000397300005 ], [ -71.068348761999914, 18.310370184000078 ], [ -71.083973761999914, 18.304388739000046 ], [ -71.090240037999934, 18.289129950000074 ], [ -71.092355923999946, 18.28070709800005 ], [ -71.101226365999935, 18.266099351000037 ], [ -71.103342251999948, 18.254950262000079 ], [ -71.101429816999939, 18.242132880000042 ], [ -71.096547003999945, 18.23509349200009 ], [ -71.089914516999897, 18.228705145000049 ], [ -71.082834438999953, 18.217718817000048 ], [ -71.066517706999946, 18.163316148000092 ], [ -71.061268683999913, 18.153998114000046 ], [ -71.061105923999946, 18.142075914000088 ], [ -71.080555792999917, 18.11391836100006 ], [ -71.097157355999911, 18.073716539000088 ], [ -71.191802537999934, 17.941799221000053 ], [ -71.200103318999936, 17.919175523000092 ], [ -71.204253709999932, 17.911118882000039 ], [ -71.213734503999945, 17.904852606000077 ], [ -71.233631964999915, 17.894964911000045 ], [ -71.245920376999948, 17.88507721600007 ], [ -71.254709438999953, 17.87531159100007 ], [ -71.261545376999948, 17.863226630000042 ], [ -71.26781165299991, 17.846584377000056 ], [ -71.275217251999948, 17.84906647300005 ], [ -71.278065558999913, 17.850775458000044 ], [ -71.281017156045905, 17.853130772829296 ], [ -71.281044074124736, 17.853225816418274 ], [ -71.281741706114815, 17.855732123538644 ], [ -71.281715867693151, 17.894566961995679 ], [ -71.2976838846036, 17.929526069572432 ], [ -71.327656216361277, 17.930895494231663 ], [ -71.352925991341408, 17.925081895213282 ], [ -71.402225307851666, 17.963865057726196 ], [ -71.423748542261421, 18.014998887788408 ], [ -71.416849737625284, 18.023861396286406 ], [ -71.406411098893102, 18.027427069703492 ], [ -71.396385871310883, 18.031251126438292 ], [ -71.390908169076738, 18.041948146689606 ], [ -71.388970302737278, 18.05993154520462 ], [ -71.389900478724087, 18.078225002981469 ], [ -71.391166550595813, 18.118971869356244 ], [ -71.42193986713113, 18.135947577518664 ], [ -71.417573208037084, 18.162974350785646 ], [ -71.399305588681955, 18.181603705346731 ], [ -71.373984137757759, 18.17501495997243 ], [ -71.351013963423668, 18.177960517563804 ], [ -71.366646084449201, 18.232815049774729 ], [ -71.381373867010325, 18.290124213161903 ], [ -71.337061327218464, 18.299167588813134 ], [ -71.286625129146387, 18.282837835797466 ], [ -71.233915167950613, 18.296325384908585 ], [ -71.200764737302791, 18.338364163375445 ], [ -71.197793342188959, 18.370791124510788 ], [ -71.18027503076803, 18.397068589843514 ], [ -71.163531866602341, 18.407093818325052 ], [ -71.147357144116881, 18.41766164826646 ], [ -71.13598832939789, 18.434172268435418 ], [ -71.119891120378895, 18.446652127193886 ], [ -71.089221158429723, 18.457297472400398 ], [ -71.063408780191025, 18.475306708437813 ], [ -71.047776659165493, 18.499878852327186 ], [ -71.034418301263599, 18.525872096819796 ], [ -71.014755418827519, 18.5020234242416 ], [ -71.004626837558476, 18.485771186491036 ], [ -71.001474575291411, 18.453886826815562 ], [ -71.02165422166496, 18.428875434253882 ], [ -71.052350022935173, 18.403786526427041 ], [ -71.047363247116152, 18.392288520498823 ], [ -71.042712368081311, 18.380661322462061 ], [ -71.033229742858339, 18.373865872412068 ], [ -71.020749884999191, 18.369318346164732 ], [ -70.988477952595417, 18.360688380764145 ], [ -70.959384120880486, 18.354047960345099 ], [ -70.96173539926923, 18.339552720881329 ], [ -70.958324754583771, 18.318287868890025 ], [ -70.950702481334417, 18.286067613329692 ], [ -70.96561521108714, 18.262083186130727 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-02", "NAME_1": "Azua" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.579381748901312, 18.271769273180571 ], [ -70.59243730399993, 18.279852606000077 ], [ -70.596791144999941, 18.289129950000074 ], [ -70.594349738999938, 18.299058335000041 ], [ -70.588449673999946, 18.303615627000056 ], [ -70.581654425999943, 18.307074286000045 ], [ -70.57640540299991, 18.313950914000088 ], [ -70.571766730999911, 18.334051825000074 ], [ -70.571156378999945, 18.355169989000046 ], [ -70.573882615999935, 18.37368398600006 ], [ -70.579457160999937, 18.385646877000056 ], [ -70.601429816999939, 18.411851304000038 ], [ -70.614654100999928, 18.420843817000048 ], [ -70.637806769999941, 18.429388739000046 ], [ -70.657541469999899, 18.433783270000049 ], [ -70.682484503999945, 18.435614325000074 ], [ -70.703846808999913, 18.430121161000045 ], [ -70.712880011999914, 18.412665106000077 ], [ -70.709462042999917, 18.391750393000052 ], [ -70.711984829999949, 18.383368231000077 ], [ -70.741688605999911, 18.355414130000042 ], [ -70.749867316999939, 18.350409247000073 ], [ -70.760650193999936, 18.347479559000078 ], [ -70.772328253999945, 18.347886460000041 ], [ -70.793120897999927, 18.354071356000077 ], [ -70.802316860999952, 18.35492584800005 ], [ -70.810047980999911, 18.352036851000037 ], [ -70.823963995999918, 18.342678127000056 ], [ -70.833322719999899, 18.340643622000073 ], [ -70.84601803299995, 18.342189846000053 ], [ -70.850453253999945, 18.339585679000038 ], [ -70.860340949999909, 18.33071523600006 ], [ -70.863107876999948, 18.326971747000073 ], [ -70.86937415299991, 18.314601955000057 ], [ -70.870594855999911, 18.310248114000046 ], [ -70.87328040299991, 18.306301174000055 ], [ -70.886708136999914, 18.302069403000075 ], [ -70.891672329999949, 18.299709377000056 ], [ -70.91828365799995, 18.269598700000074 ], [ -70.932484503999945, 18.261542059000078 ], [ -70.956206834999932, 18.258734442000048 ], [ -70.96561521108714, 18.262083186130727 ], [ -70.950702481334417, 18.286067613329692 ], [ -70.958324754583771, 18.318287868890025 ], [ -70.96173539926923, 18.339552720881329 ], [ -70.959384120880486, 18.354047960345099 ], [ -70.988477952595417, 18.360688380764145 ], [ -71.020749884999191, 18.369318346164732 ], [ -71.033229742858339, 18.373865872412068 ], [ -71.042712368081311, 18.380661322462061 ], [ -71.047363247116152, 18.392288520498823 ], [ -71.052350022935173, 18.403786526427041 ], [ -71.02165422166496, 18.428875434253882 ], [ -71.001474575291411, 18.453886826815562 ], [ -71.004626837558476, 18.485771186491036 ], [ -71.014755418827519, 18.5020234242416 ], [ -70.993619758045384, 18.509619859069232 ], [ -70.993283861261204, 18.527344876065172 ], [ -71.019871384956446, 18.544268907384151 ], [ -71.051394009425962, 18.549720771196633 ], [ -71.113819138942119, 18.570287991197802 ], [ -71.161309781221405, 18.615918281503468 ], [ -71.117384813258525, 18.627132065692251 ], [ -71.091055671082358, 18.664364936392701 ], [ -71.07470007964497, 18.670281887299268 ], [ -71.05581234356481, 18.678756822169589 ], [ -71.058086106688449, 18.691624254555677 ], [ -71.064726528906192, 18.702553818803665 ], [ -71.054287889274633, 18.716093044758168 ], [ -71.053099330869429, 18.728779609091646 ], [ -71.05942969382528, 18.766425890042797 ], [ -71.026899379902432, 18.776115220840779 ], [ -71.018476121875494, 18.758829454315844 ], [ -71.003929205568397, 18.753145046506688 ], [ -70.990260790203308, 18.765624905265156 ], [ -70.982457648002026, 18.78262645094992 ], [ -70.981940884064556, 18.834122016218032 ], [ -70.975274624324413, 18.883679714247421 ], [ -70.963130663249501, 18.908742784551862 ], [ -70.938584356882529, 18.92504669824649 ], [ -70.924502530367477, 18.937836615367473 ], [ -70.92049760558001, 18.957215277862758 ], [ -70.899568651272205, 18.967033799869967 ], [ -70.891197069189388, 18.988453681492217 ], [ -70.838693813568625, 18.954476426745657 ], [ -70.827428351637082, 18.862285671046891 ], [ -70.784795294866967, 18.807327786048461 ], [ -70.723765428431761, 18.777794704761789 ], [ -70.685834926640553, 18.734024767329117 ], [ -70.699994269320086, 18.676844794251849 ], [ -70.671262172810998, 18.622972113971855 ], [ -70.650333217603873, 18.572355047847168 ], [ -70.635553758199364, 18.563750921767621 ], [ -70.627983160894132, 18.548893947997271 ], [ -70.610619880003469, 18.533003445452607 ], [ -70.587417161672647, 18.525174464829661 ], [ -70.554137538916279, 18.504452216096865 ], [ -70.521865607411826, 18.488742580705491 ], [ -70.501091681835646, 18.454739488436644 ], [ -70.479077521010765, 18.413217474806629 ], [ -70.472462938114063, 18.394820665141594 ], [ -70.482178107333766, 18.376501369842345 ], [ -70.489981248635729, 18.349577948463548 ], [ -70.487397427149517, 18.321155911216294 ], [ -70.523700120963781, 18.28193349913164 ], [ -70.579381748901312, 18.271769273180571 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-17", "NAME_1": "Peravia" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.180387699080853, 18.234131163402001 ], [ -70.202137824999909, 18.233547268000052 ], [ -70.220773891999897, 18.230536200000074 ], [ -70.233143683999913, 18.223944403000075 ], [ -70.250803188999953, 18.234320380000042 ], [ -70.269602016999897, 18.238104559000078 ], [ -70.397572394999941, 18.237616278000075 ], [ -70.419056769999941, 18.231146552000041 ], [ -70.460194464999915, 18.208929755000042 ], [ -70.483550584999932, 18.204087632000039 ], [ -70.552845831999946, 18.204250393000052 ], [ -70.568918423999946, 18.210353908000059 ], [ -70.570301886999914, 18.218939520000049 ], [ -70.563059048999946, 18.225653387000079 ], [ -70.553700324999909, 18.231512762000079 ], [ -70.54906165299991, 18.237616278000075 ], [ -70.551909959999932, 18.248439846000053 ], [ -70.558705206999946, 18.254380601000037 ], [ -70.565744594999899, 18.258205471000053 ], [ -70.573312954999949, 18.268011786000045 ], [ -70.579381748901312, 18.271769273180571 ], [ -70.523700120963781, 18.28193349913164 ], [ -70.487397427149517, 18.321155911216294 ], [ -70.489981248635729, 18.349577948463548 ], [ -70.482178107333766, 18.376501369842345 ], [ -70.472462938114063, 18.394820665141594 ], [ -70.479077521010765, 18.413217474806629 ], [ -70.452050746844463, 18.451251329385343 ], [ -70.403139003961826, 18.464919744750432 ], [ -70.378050096135041, 18.48143036491939 ], [ -70.356552700147006, 18.50357371695344 ], [ -70.308209398045278, 18.483574936833861 ], [ -70.268728604441549, 18.447220567075476 ], [ -70.236973435975301, 18.433009548451878 ], [ -70.238885463893041, 18.408902493455287 ], [ -70.264775357396843, 18.394691473932369 ], [ -70.269736293894823, 18.368801581327887 ], [ -70.251313645808068, 18.346503201461587 ], [ -70.231263189744425, 18.323972275799861 ], [ -70.224209357275981, 18.311208197100598 ], [ -70.21671627523591, 18.298676663297385 ], [ -70.203642137274812, 18.286481025378976 ], [ -70.190826381732109, 18.275939032060649 ], [ -70.186588914746608, 18.253433945720019 ], [ -70.180387699080853, 18.234131163402001 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-21", "NAME_1": "San Cristóbal" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.004017706999946, 18.417466539000088 ], [ -70.016590949999909, 18.411363023000092 ], [ -70.038929816999939, 18.392482815000051 ], [ -70.055775519999941, 18.367254950000074 ], [ -70.062408006999931, 18.337225653000075 ], [ -70.067697719999899, 18.329087632000039 ], [ -70.090687628999945, 18.317531643000052 ], [ -70.09593665299991, 18.310248114000046 ], [ -70.100005662999934, 18.299221096000053 ], [ -70.133778449999909, 18.269273179000038 ], [ -70.158070441999939, 18.242621161000045 ], [ -70.171783006999931, 18.231431382000039 ], [ -70.177886522999927, 18.234198309000078 ], [ -70.180387699080853, 18.234131163402001 ], [ -70.186588914746608, 18.253433945720019 ], [ -70.190826381732109, 18.275939032060649 ], [ -70.203642137274812, 18.286481025378976 ], [ -70.21671627523591, 18.298676663297385 ], [ -70.224209357275981, 18.311208197100598 ], [ -70.231263189744425, 18.323972275799861 ], [ -70.251313645808068, 18.346503201461587 ], [ -70.269736293894823, 18.368801581327887 ], [ -70.264775357396843, 18.394691473932369 ], [ -70.238885463893041, 18.408902493455287 ], [ -70.236973435975301, 18.433009548451878 ], [ -70.268728604441549, 18.447220567075476 ], [ -70.308209398045278, 18.483574936833861 ], [ -70.356552700147006, 18.50357371695344 ], [ -70.371564704447565, 18.533287665393402 ], [ -70.378799404968561, 18.565714627428122 ], [ -70.367895677343597, 18.601035468412135 ], [ -70.372184821172539, 18.636330470974428 ], [ -70.368748338065359, 18.679506130103789 ], [ -70.350015631616088, 18.720149643691116 ], [ -70.31306698265513, 18.719529526966085 ], [ -70.29955359602161, 18.75761505838824 ], [ -70.285394253342133, 18.786088772478877 ], [ -70.251184454598899, 18.80172089350441 ], [ -70.23464799690754, 18.78172211428415 ], [ -70.217233039173379, 18.762498481419755 ], [ -70.191317308147234, 18.748700873046857 ], [ -70.167184413829602, 18.731673488940373 ], [ -70.166383429951338, 18.686921697778132 ], [ -70.139304978941595, 18.645348009103316 ], [ -70.148012457808647, 18.623101305181081 ], [ -70.152844203996779, 18.598554998814109 ], [ -70.142121345323801, 18.56315664346431 ], [ -70.123647020393662, 18.531246446266493 ], [ -70.099074877403666, 18.513857326954053 ], [ -70.080497198786702, 18.492308254122634 ], [ -70.077810025412305, 18.475125841284523 ], [ -70.066312018584767, 18.463369452038592 ], [ -70.043703578557313, 18.464041246506326 ], [ -70.021224330638347, 18.463240260829366 ], [ -70.008537767204189, 18.445386054422841 ], [ -70.007710944004828, 18.423759467225636 ], [ -70.004017706999946, 18.417466539000088 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-32", "NAME_1": "Santo Domingo" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.980918008185284, 18.426464324006311 ], [ -69.993519660999937, 18.422552802000041 ], [ -70.004017706999946, 18.417466539000088 ], [ -70.007710944004828, 18.423759467225636 ], [ -70.008537767204189, 18.445386054422841 ], [ -70.021224330638347, 18.463240260829366 ], [ -70.043703578557313, 18.464041246506326 ], [ -70.066312018584767, 18.463369452038592 ], [ -70.077810025412305, 18.475125841284523 ], [ -70.080497198786702, 18.492308254122634 ], [ -70.099074877403666, 18.513857326954053 ], [ -70.123647020393662, 18.531246446266493 ], [ -70.142121345323801, 18.56315664346431 ], [ -70.152844203996779, 18.598554998814109 ], [ -70.148012457808647, 18.623101305181081 ], [ -70.139304978941595, 18.645348009103316 ], [ -70.166383429951338, 18.686921697778132 ], [ -70.167184413829602, 18.731673488940373 ], [ -70.1390207590008, 18.722035834086455 ], [ -70.120701462802231, 18.690694078568868 ], [ -70.088842943347174, 18.679480292581445 ], [ -70.056054247005875, 18.671031196132787 ], [ -70.008770311200863, 18.66222036447823 ], [ -69.966343960005759, 18.68092723250578 ], [ -69.963682624153762, 18.690125636888638 ], [ -69.959083421063042, 18.69903982223002 ], [ -69.947301195193972, 18.702838040543099 ], [ -69.934640469282215, 18.70340648042469 ], [ -69.91143775095145, 18.7024763053372 ], [ -69.888260871042348, 18.70133942287606 ], [ -69.861156581610942, 18.68108226213667 ], [ -69.838470629016285, 18.656690986299964 ], [ -69.824621344699267, 18.63927602856586 ], [ -69.818988613733552, 18.61943227807717 ], [ -69.797982144160585, 18.600105292425269 ], [ -69.789972297283668, 18.571838283909642 ], [ -69.743851080562933, 18.617726955734383 ], [ -69.685740933297438, 18.638242498892168 ], [ -69.663933478047568, 18.642660833930336 ], [ -69.645097418810792, 18.654288031067779 ], [ -69.611120164963609, 18.6612385125473 ], [ -69.575334235086871, 18.648216051429586 ], [ -69.587814093845338, 18.635167751890208 ], [ -69.593550177598615, 18.619794013283069 ], [ -69.587917446632844, 18.619354762812065 ], [ -69.582543098085523, 18.621628525935705 ], [ -69.578047247782251, 18.596591294952304 ], [ -69.579907599755927, 18.571528225547183 ], [ -69.600474819757096, 18.546180935301891 ], [ -69.616572027876771, 18.51998098433495 ], [ -69.576962043063816, 18.479750880998324 ], [ -69.518257615696371, 18.468537095910222 ], [ -69.524665493018063, 18.436601060290684 ], [ -69.528110123960076, 18.410312170145868 ], [ -69.579986131999931, 18.444484768000052 ], [ -69.602121548999946, 18.45571523600006 ], [ -69.616810675999943, 18.45734284100007 ], [ -69.623158331999946, 18.44798411700009 ], [ -69.622629360999952, 18.436753648000092 ], [ -69.620838995999918, 18.425482489000046 ], [ -69.623605923999946, 18.41632721600007 ], [ -69.632557745999918, 18.41351959800005 ], [ -69.646595831999946, 18.413560289000088 ], [ -69.659494594999899, 18.415920315000051 ], [ -69.665150519999941, 18.419501044000071 ], [ -69.68195553299995, 18.446763414000088 ], [ -69.689930792999917, 18.454087632000039 ], [ -69.697377081999946, 18.456366278000075 ], [ -69.851470506999931, 18.472479559000078 ], [ -69.879383917999917, 18.471218166000085 ], [ -69.877822232310166, 18.500964057045564 ], [ -69.905727504720574, 18.504968980034391 ], [ -69.924486049591508, 18.500085557902139 ], [ -69.943502976880893, 18.501816717767269 ], [ -69.955801967586751, 18.520239365854025 ], [ -69.967997606404424, 18.53674998602304 ], [ -69.994765998152275, 18.52243561371256 ], [ -69.997401495582551, 18.493884386155457 ], [ -69.975180630081979, 18.462620144104335 ], [ -69.980918008185284, 18.426464324006311 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-01", "NAME_1": "Distrito Nacional" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.879383917999917, 18.471218166000085 ], [ -69.883656378999945, 18.47101471600007 ], [ -69.899810350999928, 18.466457424000055 ], [ -69.931223110999952, 18.451971747000073 ], [ -69.957102016999897, 18.435288804000038 ], [ -69.966908331999946, 18.430812893000052 ], [ -69.980918008185284, 18.426464324006311 ], [ -69.975180630081979, 18.462620144104335 ], [ -69.997401495582551, 18.493884386155457 ], [ -69.994765998152275, 18.52243561371256 ], [ -69.967997606404424, 18.53674998602304 ], [ -69.955801967586751, 18.520239365854025 ], [ -69.943502976880893, 18.501816717767269 ], [ -69.924486049591508, 18.500085557902139 ], [ -69.905727504720574, 18.504968980034391 ], [ -69.877822232310166, 18.500964057045564 ], [ -69.879383917999917, 18.471218166000085 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-23", "NAME_1": "San Pedro de Macorís" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -69.085438605999911, 18.395900783000059 ], [ -69.104359503999945, 18.399115302000041 ], [ -69.148182745999918, 18.413234768000052 ], [ -69.168039516999897, 18.41632721600007 ], [ -69.185292120999918, 18.421698309000078 ], [ -69.214222785999937, 18.445135809000078 ], [ -69.236317511999914, 18.450506903000075 ], [ -69.255604620999918, 18.446682033000059 ], [ -69.275217251999948, 18.440334377000056 ], [ -69.295033331999946, 18.439032294000071 ], [ -69.31509355399993, 18.450506903000075 ], [ -69.336008266999897, 18.432074286000045 ], [ -69.465931769999941, 18.422552802000041 ], [ -69.504750128999945, 18.40892161700009 ], [ -69.525257941999939, 18.408433335000041 ], [ -69.528110123960076, 18.410312170145868 ], [ -69.524665493018063, 18.436601060290684 ], [ -69.518257615696371, 18.468537095910222 ], [ -69.576962043063816, 18.479750880998324 ], [ -69.616572027876771, 18.51998098433495 ], [ -69.600474819757096, 18.546180935301891 ], [ -69.579907599755927, 18.571528225547183 ], [ -69.578047247782251, 18.596591294952304 ], [ -69.582543098085523, 18.621628525935705 ], [ -69.587917446632844, 18.619354762812065 ], [ -69.593550177598615, 18.619794013283069 ], [ -69.587814093845338, 18.635167751890208 ], [ -69.575334235086871, 18.648216051429586 ], [ -69.518309291640492, 18.743429877286985 ], [ -69.459113938757241, 18.802573554226115 ], [ -69.459165615600682, 18.767924505911196 ], [ -69.441259732350773, 18.736272691131774 ], [ -69.43557532364224, 18.694828192766863 ], [ -69.428547328696254, 18.654107163914489 ], [ -69.405758023314092, 18.621111761998179 ], [ -69.382917040189227, 18.588116360081926 ], [ -69.368990240607104, 18.554733385437373 ], [ -69.353745694108511, 18.521970527517794 ], [ -69.325297818439537, 18.553777371028843 ], [ -69.303903775239007, 18.580235704414235 ], [ -69.287677375010844, 18.617571926103494 ], [ -69.253570929954435, 18.64023204207507 ], [ -69.240470953571617, 18.631085312736957 ], [ -69.226750861363143, 18.623101305181081 ], [ -69.210007697197454, 18.624703273836985 ], [ -69.193677945081106, 18.6203882924857 ], [ -69.169390021132585, 18.595041002240464 ], [ -69.140942144564292, 18.575119737385933 ], [ -69.10952287468092, 18.579408881214874 ], [ -69.080170661446857, 18.576489162944483 ], [ -69.085312465997504, 18.553415635822944 ], [ -69.092702196149446, 18.527344876065172 ], [ -69.108747728325, 18.502126777029105 ], [ -69.121770189442657, 18.475616766800329 ], [ -69.115000576015746, 18.462387600107661 ], [ -69.103011643672403, 18.452646593365557 ], [ -69.090557624234975, 18.423811143169701 ], [ -69.085438605999911, 18.395900783000059 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-12", "NAME_1": "La Romana" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.901149176876245, 18.403656131063737 ], [ -68.92251542899993, 18.412298895000049 ], [ -68.964344855999911, 18.417954820000091 ], [ -69.012562628999945, 18.399115302000041 ], [ -69.085438605999911, 18.395900783000059 ], [ -69.090557624234975, 18.423811143169701 ], [ -69.103011643672403, 18.452646593365557 ], [ -69.115000576015746, 18.462387600107661 ], [ -69.121770189442657, 18.475616766800329 ], [ -69.108747728325, 18.502126777029105 ], [ -69.092702196149446, 18.527344876065172 ], [ -69.042524379596443, 18.55698130924003 ], [ -69.004180466655214, 18.603257554692391 ], [ -68.978988206940187, 18.649482123301311 ], [ -68.935295782973981, 18.665682685107811 ], [ -68.918707648439238, 18.629741726499446 ], [ -68.899328985943953, 18.596436266220678 ], [ -68.874136726228926, 18.574732163758313 ], [ -68.853104418234295, 18.549824123984138 ], [ -68.85201921261654, 18.51863739719812 ], [ -68.865584276093443, 18.489724433535741 ], [ -68.883283453768342, 18.444275011282741 ], [ -68.901149176876245, 18.403656131063737 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-27", "NAME_1": "Valverde" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.148390671991933, 19.626295884847195 ], [ -71.150819464746462, 19.659420477972674 ], [ -71.153687507072789, 19.692493394254711 ], [ -71.145031704149801, 19.722465725113125 ], [ -71.133972947793268, 19.751766262403066 ], [ -71.099814825893475, 19.740242418053128 ], [ -71.067491218444957, 19.72525625307361 ], [ -71.045244513623402, 19.709262396842121 ], [ -71.01821774035642, 19.702570299579634 ], [ -70.977651740235615, 19.690478014448786 ], [ -70.943907030385105, 19.66494985615094 ], [ -70.906234911012348, 19.64701813447931 ], [ -70.864118618179646, 19.641747137820118 ], [ -70.870655686710563, 19.60826081038806 ], [ -70.885202603017717, 19.577771714692858 ], [ -70.910808274782028, 19.574593614004073 ], [ -70.935638801089794, 19.591207586960536 ], [ -70.933855964381223, 19.571105454952772 ], [ -70.925846116604987, 19.553122057337077 ], [ -70.911376715562938, 19.546507473541055 ], [ -70.896519740893325, 19.537825833095724 ], [ -70.897449916880134, 19.510333970936017 ], [ -70.904400396561016, 19.481550198482864 ], [ -70.881585252757191, 19.46527212231058 ], [ -70.885564338223617, 19.447547105314641 ], [ -70.929540982130618, 19.447288722896246 ], [ -70.970804613342239, 19.464083563905319 ], [ -70.979718796884981, 19.453438218698807 ], [ -70.989175584585553, 19.440467434424534 ], [ -71.003619147205882, 19.438658759294299 ], [ -71.018269416300484, 19.441811021561364 ], [ -71.047363247116152, 19.453438218698807 ], [ -71.075165167638374, 19.468062649371745 ], [ -71.148804084041217, 19.480594184074334 ], [ -71.184202440290392, 19.536508084380557 ], [ -71.172781948727959, 19.570872910956041 ], [ -71.17895728205292, 19.60730479597953 ], [ -71.172678595940454, 19.628621323914956 ], [ -71.148390671991933, 19.626295884847195 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-26", "NAME_1": "Santiago Rodríguez" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.3997965159964, 19.560537625011364 ], [ -71.382588263837306, 19.548367825514731 ], [ -71.352202520929609, 19.537644965043114 ], [ -71.319749722271865, 19.54025462495099 ], [ -71.300293545410796, 19.549711411752241 ], [ -71.278951179053649, 19.552321072559437 ], [ -71.247764452267631, 19.535009466713518 ], [ -71.216319343063219, 19.532218940551672 ], [ -71.201514045236991, 19.542063300081224 ], [ -71.184202440290392, 19.536508084380557 ], [ -71.148804084041217, 19.480594184074334 ], [ -71.075165167638374, 19.468062649371745 ], [ -71.088342658386978, 19.451009425944221 ], [ -71.090487230301449, 19.431191514776572 ], [ -71.077283902030445, 19.422329006278574 ], [ -71.068705614372618, 19.412458808327301 ], [ -71.107023687992807, 19.400185655143844 ], [ -71.143197190597846, 19.383855903027495 ], [ -71.162084926678006, 19.382899889518285 ], [ -71.180895148392381, 19.384760239693264 ], [ -71.196294725421239, 19.375070908895339 ], [ -71.208619553649442, 19.361505846317755 ], [ -71.226861334582907, 19.347165636484931 ], [ -71.240891486053215, 19.328975531495587 ], [ -71.244224616372946, 19.298718979797059 ], [ -71.247040981855832, 19.267893989116317 ], [ -71.243475308438747, 19.246861681121686 ], [ -71.226938849848011, 19.232030544873737 ], [ -71.225543585867797, 19.201593126021919 ], [ -71.230840420049333, 19.170173855239227 ], [ -71.284092983604296, 19.170690619176696 ], [ -71.327371996420482, 19.191076972024632 ], [ -71.371271125062378, 19.213272000002803 ], [ -71.415893724116074, 19.234485175150724 ], [ -71.446822069382961, 19.273604234447873 ], [ -71.488266567747871, 19.298848171006284 ], [ -71.505138923122786, 19.316418158371278 ], [ -71.515060797917499, 19.338018907146818 ], [ -71.466174892557206, 19.358637803991428 ], [ -71.454082608325677, 19.422199815069405 ], [ -71.446460334177061, 19.443232123064035 ], [ -71.448656582035596, 19.46581472377045 ], [ -71.436331752908075, 19.508086046234041 ], [ -71.413051520211468, 19.544543768779874 ], [ -71.3997965159964, 19.560537625011364 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-13", "NAME_1": "La Vega" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.61390133258044, 19.368843898726936 ], [ -70.590078498423964, 19.351945705829621 ], [ -70.558504198010326, 19.349000149137566 ], [ -70.536076626035424, 19.357320055276318 ], [ -70.515561082877639, 19.361505846317755 ], [ -70.495458949970555, 19.313601792888392 ], [ -70.467321132664154, 19.3188211127042 ], [ -70.452515834837868, 19.284973049166865 ], [ -70.432465379673545, 19.253295395965722 ], [ -70.404508430419696, 19.227612209835627 ], [ -70.363632371936376, 19.22492503556191 ], [ -70.331257086745154, 19.177589422913513 ], [ -70.281441006297371, 19.146428534549216 ], [ -70.279554815902031, 19.143741360275556 ], [ -70.277642787984291, 19.141080024423559 ], [ -70.299863654384126, 19.133251043800612 ], [ -70.324358283008337, 19.121184597091485 ], [ -70.364123298351501, 19.103304552263239 ], [ -70.392312791602023, 19.072324531052232 ], [ -70.399780036119751, 19.098266100500098 ], [ -70.423732062384772, 19.111727810290176 ], [ -70.443420783242516, 19.10508738897181 ], [ -70.454195318758934, 19.086483872832446 ], [ -70.501840989769846, 19.074210720548308 ], [ -70.522640753767746, 19.037365424374798 ], [ -70.523519252911171, 18.969049181474531 ], [ -70.583334724318036, 18.922462876760335 ], [ -70.592378099070004, 18.853242296294923 ], [ -70.533673671702559, 18.787949124452496 ], [ -70.548013882434702, 18.743559068496211 ], [ -70.574058803770754, 18.712036444925957 ], [ -70.595142787709449, 18.693587958417538 ], [ -70.610464851271843, 18.677361559088638 ], [ -70.654699876697919, 18.677904161447884 ], [ -70.699994269320086, 18.676844794251849 ], [ -70.685834926640553, 18.734024767329117 ], [ -70.723765428431761, 18.777794704761789 ], [ -70.784795294866967, 18.807327786048461 ], [ -70.827428351637082, 18.862285671046891 ], [ -70.838693813568625, 18.954476426745657 ], [ -70.891197069189388, 18.988453681492217 ], [ -70.89967200405971, 19.009925239058532 ], [ -70.916208461751125, 19.025919094390702 ], [ -70.911815965134679, 19.048139959891216 ], [ -70.919179856864901, 19.069404811882521 ], [ -70.890034349205848, 19.08307322814693 ], [ -70.857142300077101, 19.096612454101432 ], [ -70.794898036814914, 19.125137844136191 ], [ -70.742472297358631, 19.162809963509005 ], [ -70.730302496962679, 19.189707546466082 ], [ -70.708779262552923, 19.190844428027901 ], [ -70.682527634742542, 19.18598684341805 ], [ -70.685473192333973, 19.214770615871203 ], [ -70.67826433023464, 19.248799547461147 ], [ -70.694025641570079, 19.274999498428087 ], [ -70.724592250731746, 19.283035182827405 ], [ -70.748776821892818, 19.300579331770734 ], [ -70.74164547415927, 19.32093984619695 ], [ -70.716892463116665, 19.327502753149531 ], [ -70.666662970619598, 19.352591660976373 ], [ -70.61390133258044, 19.368843898726936 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-19", "NAME_1": "Hermanas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.288339810034188, 19.558573920250183 ], [ -70.259349331106762, 19.534441025932608 ], [ -70.236585863247001, 19.499197699314379 ], [ -70.242502814153511, 19.473721217859918 ], [ -70.250564337873868, 19.441681830352195 ], [ -70.279038051964505, 19.418763332861488 ], [ -70.321076830431366, 19.399436347209644 ], [ -70.340558844814836, 19.357216702488813 ], [ -70.348723721322642, 19.310397853777886 ], [ -70.362728034371287, 19.267480577066976 ], [ -70.363632371936376, 19.22492503556191 ], [ -70.404508430419696, 19.227612209835627 ], [ -70.432465379673545, 19.253295395965722 ], [ -70.452515834837868, 19.284973049166865 ], [ -70.467321132664154, 19.3188211127042 ], [ -70.445720383888613, 19.377344672018978 ], [ -70.441922167374116, 19.433620307531157 ], [ -70.442258063258976, 19.500308743353798 ], [ -70.408900926136823, 19.539453640173349 ], [ -70.390814174834304, 19.533045762851657 ], [ -70.374251878721225, 19.52539765118064 ], [ -70.362443814430492, 19.498706772899254 ], [ -70.338827684050386, 19.513899644353103 ], [ -70.318312140892601, 19.542218328812794 ], [ -70.288339810034188, 19.558573920250183 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-06", "NAME_1": "Duarte" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.225785489308862, 19.499326891422868 ], [ -70.215140144102349, 19.497389024184088 ], [ -70.17966427258807, 19.477002672235528 ], [ -70.145738694685008, 19.455195216985658 ], [ -70.133956467916676, 19.423517563784515 ], [ -70.131062588067948, 19.389230252474135 ], [ -70.118686082996305, 19.347088121219826 ], [ -70.083933681893882, 19.3230327421673 ], [ -70.053547939885505, 19.319337877540988 ], [ -70.039931199565217, 19.296109320788503 ], [ -69.991277839100974, 19.257119451801259 ], [ -69.922599860095431, 19.240686346897348 ], [ -69.855420497857665, 19.210739854460712 ], [ -69.786148241448188, 19.198053290127234 ], [ -69.737314012032016, 19.220119126896179 ], [ -69.676800910433656, 19.206476549053491 ], [ -69.676749233590272, 19.179423936465469 ], [ -69.703285082240768, 19.162603257933995 ], [ -69.719020555154486, 19.152655544717618 ], [ -69.732533941787949, 19.136687526907849 ], [ -69.736125453626755, 19.105397447334326 ], [ -69.755788336962155, 19.087594915972602 ], [ -69.821339891222976, 19.089997870305467 ], [ -69.874928351562176, 19.083977565712075 ], [ -69.876995409110805, 19.072815457467357 ], [ -69.878287320303571, 19.057338365173393 ], [ -69.893428514014715, 19.038347276305728 ], [ -69.920326096971792, 19.039251613870874 ], [ -69.911153531010655, 19.066846828818086 ], [ -69.907768723847539, 19.093486030256088 ], [ -69.929059414260564, 19.106379299265257 ], [ -69.95383826372489, 19.113691515051357 ], [ -69.986136033651007, 19.115810248544108 ], [ -70.016909349287005, 19.116146145328344 ], [ -70.040525478767847, 19.123122463430946 ], [ -70.063056402630878, 19.133070177546642 ], [ -70.089075487343848, 19.144283961735425 ], [ -70.117445847747661, 19.146325181761711 ], [ -70.161241625400692, 19.151156927949842 ], [ -70.205502489248488, 19.150433458437362 ], [ -70.226095546772058, 19.146945299386061 ], [ -70.247076178822567, 19.150588487168932 ], [ -70.266429002896132, 19.155626938932073 ], [ -70.285006679714513, 19.149839179234732 ], [ -70.281880255869112, 19.150666002434036 ], [ -70.281441006297371, 19.146428534549216 ], [ -70.331257086745154, 19.177589422913513 ], [ -70.363632371936376, 19.22492503556191 ], [ -70.362728034371287, 19.267480577066976 ], [ -70.348723721322642, 19.310397853777886 ], [ -70.340558844814836, 19.357216702488813 ], [ -70.321076830431366, 19.399436347209644 ], [ -70.279038051964505, 19.418763332861488 ], [ -70.250564337873868, 19.441681830352195 ], [ -70.242502814153511, 19.473721217859918 ], [ -70.236585863247001, 19.499197699314379 ], [ -70.225785489308862, 19.499326891422868 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-25", "NAME_1": "Santiago" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.547703824072187, 19.517827052976088 ], [ -70.551941291057744, 19.497595729759098 ], [ -70.566875780093142, 19.481705227214434 ], [ -70.580518357935887, 19.460311184013904 ], [ -70.586254441689107, 19.435325628974567 ], [ -70.583412237784557, 19.412613837058927 ], [ -70.583670620202952, 19.390548001189302 ], [ -70.599070197231811, 19.379360052724223 ], [ -70.61390133258044, 19.368843898726936 ], [ -70.666662970619598, 19.352591660976373 ], [ -70.716892463116665, 19.327502753149531 ], [ -70.74164547415927, 19.32093984619695 ], [ -70.748776821892818, 19.300579331770734 ], [ -70.724592250731746, 19.283035182827405 ], [ -70.694025641570079, 19.274999498428087 ], [ -70.67826433023464, 19.248799547461147 ], [ -70.685473192333973, 19.214770615871203 ], [ -70.682527634742542, 19.18598684341805 ], [ -70.708779262552923, 19.190844428027901 ], [ -70.730302496962679, 19.189707546466082 ], [ -70.742472297358631, 19.162809963509005 ], [ -70.794898036814914, 19.125137844136191 ], [ -70.857142300077101, 19.096612454101432 ], [ -70.890034349205848, 19.08307322814693 ], [ -70.919179856864901, 19.069404811882521 ], [ -70.911815965134679, 19.048139959891216 ], [ -70.916208461751125, 19.025919094390702 ], [ -70.942124192777271, 19.033696397270887 ], [ -70.968065762225137, 19.04147370015113 ], [ -70.992482875584244, 19.036306057178763 ], [ -71.015427212395934, 19.025609036028186 ], [ -71.060540737864756, 19.038941555508359 ], [ -71.105085821653347, 19.066071682462166 ], [ -71.124102748942676, 19.082298081791009 ], [ -71.127151659321612, 19.107102768777736 ], [ -71.135704107658455, 19.121933905925005 ], [ -71.152369758357622, 19.130098782432867 ], [ -71.193245815941623, 19.149141547244596 ], [ -71.230840420049333, 19.170173855239227 ], [ -71.225543585867797, 19.201593126021919 ], [ -71.226938849848011, 19.232030544873737 ], [ -71.243475308438747, 19.246861681121686 ], [ -71.247040981855832, 19.267893989116317 ], [ -71.244224616372946, 19.298718979797059 ], [ -71.240891486053215, 19.328975531495587 ], [ -71.226861334582907, 19.347165636484931 ], [ -71.208619553649442, 19.361505846317755 ], [ -71.196294725421239, 19.375070908895339 ], [ -71.180895148392381, 19.384760239693264 ], [ -71.162084926678006, 19.382899889518285 ], [ -71.143197190597846, 19.383855903027495 ], [ -71.107023687992807, 19.400185655143844 ], [ -71.068705614372618, 19.412458808327301 ], [ -71.077283902030445, 19.422329006278574 ], [ -71.090487230301449, 19.431191514776572 ], [ -71.088342658386978, 19.451009425944221 ], [ -71.075165167638374, 19.468062649371745 ], [ -71.047363247116152, 19.453438218698807 ], [ -71.018269416300484, 19.441811021561364 ], [ -71.003619147205882, 19.438658759294299 ], [ -70.989175584585553, 19.440467434424534 ], [ -70.979718796884981, 19.453438218698807 ], [ -70.970804613342239, 19.464083563905319 ], [ -70.929540982130618, 19.447288722896246 ], [ -70.885564338223617, 19.447547105314641 ], [ -70.881585252757191, 19.46527212231058 ], [ -70.904400396561016, 19.481550198482864 ], [ -70.897449916880134, 19.510333970936017 ], [ -70.896519740893325, 19.537825833095724 ], [ -70.911376715562938, 19.546507473541055 ], [ -70.925846116604987, 19.553122057337077 ], [ -70.933855964381223, 19.571105454952772 ], [ -70.935638801089794, 19.591207586960536 ], [ -70.910808274782028, 19.574593614004073 ], [ -70.885202603017717, 19.577771714692858 ], [ -70.870655686710563, 19.60826081038806 ], [ -70.864118618179646, 19.641747137820118 ], [ -70.832957729815348, 19.634848334083358 ], [ -70.805233323658967, 19.627303575199846 ], [ -70.782702398896561, 19.609139309531486 ], [ -70.760455694974326, 19.590432441503935 ], [ -70.715755580655525, 19.592370306944076 ], [ -70.712138231294318, 19.651100571833922 ], [ -70.658756477429506, 19.628724676702461 ], [ -70.63798255095395, 19.58110484501259 ], [ -70.608604499298167, 19.536120509853617 ], [ -70.547703824072187, 19.517827052976088 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-03", "NAME_1": "Bahoruco" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.376722988874803, 18.392727769171188 ], [ -71.415454475443653, 18.402107042505975 ], [ -71.451627977149428, 18.423268540810511 ], [ -71.489971890090658, 18.439753323457069 ], [ -71.592601283622344, 18.47799388271153 ], [ -71.62066158656296, 18.565301215378781 ], [ -71.609447800575538, 18.586256008108251 ], [ -71.602678188947266, 18.608812771292321 ], [ -71.604280157603171, 18.6215251731482 ], [ -71.59947424983676, 18.632583930404053 ], [ -71.567460699851381, 18.642299098724436 ], [ -71.534982061872654, 18.650774034494077 ], [ -71.487904833441291, 18.634263414325119 ], [ -71.438450487300145, 18.62480662752381 ], [ -71.393543667406334, 18.603180040326606 ], [ -71.344864467621051, 18.599614366010144 ], [ -71.323315395688951, 18.612766018337084 ], [ -71.300241868567355, 18.62020742443309 ], [ -71.272620816097799, 18.61731354458442 ], [ -71.245206468303877, 18.621861069932436 ], [ -71.197689989401454, 18.635374457465218 ], [ -71.161309781221405, 18.615918281503468 ], [ -71.113819138942119, 18.570287991197802 ], [ -71.051394009425962, 18.549720771196633 ], [ -71.019871384956446, 18.544268907384151 ], [ -70.993283861261204, 18.527344876065172 ], [ -70.993619758045384, 18.509619859069232 ], [ -71.014755418827519, 18.5020234242416 ], [ -71.034418301263599, 18.525872096819796 ], [ -71.047776659165493, 18.499878852327186 ], [ -71.063408780191025, 18.475306708437813 ], [ -71.089221158429723, 18.457297472400398 ], [ -71.119891120378895, 18.446652127193886 ], [ -71.13598832939789, 18.434172268435418 ], [ -71.147357144116881, 18.41766164826646 ], [ -71.163531866602341, 18.407093818325052 ], [ -71.18027503076803, 18.397068589843514 ], [ -71.197793342188959, 18.370791124510788 ], [ -71.200764737302791, 18.338364163375445 ], [ -71.236731533433499, 18.335987047464243 ], [ -71.264585129899785, 18.357872016180579 ], [ -71.290552537769372, 18.404174099155341 ], [ -71.338404914355294, 18.407016303059947 ], [ -71.376722988874803, 18.392727769171188 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-22", "NAME_1": "San Juan" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.405842658112192, 19.105139064915875 ], [ -71.367757127589357, 19.10718028404284 ], [ -71.336337856806608, 19.129995428746042 ], [ -71.334322476101363, 19.160923774012929 ], [ -71.327371996420482, 19.191076972024632 ], [ -71.284092983604296, 19.170690619176696 ], [ -71.230840420049333, 19.170173855239227 ], [ -71.193245815941623, 19.149141547244596 ], [ -71.152369758357622, 19.130098782432867 ], [ -71.135704107658455, 19.121933905925005 ], [ -71.127151659321612, 19.107102768777736 ], [ -71.124102748942676, 19.082298081791009 ], [ -71.105085821653347, 19.066071682462166 ], [ -71.060540737864756, 19.038941555508359 ], [ -71.015427212395934, 19.025609036028186 ], [ -70.992482875584244, 19.036306057178763 ], [ -70.968065762225137, 19.04147370015113 ], [ -70.942124192777271, 19.033696397270887 ], [ -70.916208461751125, 19.025919094390702 ], [ -70.89967200405971, 19.009925239058532 ], [ -70.891197069189388, 18.988453681492217 ], [ -70.899568651272205, 18.967033799869967 ], [ -70.92049760558001, 18.957215277862758 ], [ -70.924502530367477, 18.937836615367473 ], [ -70.938584356882529, 18.92504669824649 ], [ -70.963130663249501, 18.908742784551862 ], [ -70.975274624324413, 18.883679714247421 ], [ -70.981940884064556, 18.834122016218032 ], [ -70.982457648002026, 18.78262645094992 ], [ -70.990260790203308, 18.765624905265156 ], [ -71.003929205568397, 18.753145046506688 ], [ -71.018476121875494, 18.758829454315844 ], [ -71.026899379902432, 18.776115220840779 ], [ -71.05942969382528, 18.766425890042797 ], [ -71.053099330869429, 18.728779609091646 ], [ -71.054287889274633, 18.716093044758168 ], [ -71.064726528906192, 18.702553818803665 ], [ -71.058086106688449, 18.691624254555677 ], [ -71.05581234356481, 18.678756822169589 ], [ -71.07470007964497, 18.670281887299268 ], [ -71.091055671082358, 18.664364936392701 ], [ -71.117384813258525, 18.627132065692251 ], [ -71.161309781221405, 18.615918281503468 ], [ -71.197689989401454, 18.635374457465218 ], [ -71.245206468303877, 18.621861069932436 ], [ -71.272620816097799, 18.61731354458442 ], [ -71.300241868567355, 18.62020742443309 ], [ -71.323315395688951, 18.612766018337084 ], [ -71.344864467621051, 18.599614366010144 ], [ -71.393543667406334, 18.603180040326606 ], [ -71.438450487300145, 18.62480662752381 ], [ -71.487904833441291, 18.634263414325119 ], [ -71.534982061872654, 18.650774034494077 ], [ -71.520745204827335, 18.682580878005126 ], [ -71.532294887598994, 18.711002916151642 ], [ -71.559321661765239, 18.717049059166754 ], [ -71.577873501061219, 18.735859279981753 ], [ -71.577821825117098, 18.760431422971749 ], [ -71.585004848794711, 18.78340159820516 ], [ -71.605313687276862, 18.800248114259034 ], [ -71.627896287983276, 18.814200751363558 ], [ -71.615907354740614, 18.862905789570505 ], [ -71.633244798108933, 18.88380890635591 ], [ -71.624847377604397, 18.937836615367473 ], [ -71.60004269061767, 18.987756049502082 ], [ -71.577976853848725, 19.006747138369747 ], [ -71.549709846232417, 19.009460151065127 ], [ -71.518755663443073, 19.018064277144674 ], [ -71.50309770399582, 19.049716091024777 ], [ -71.491367154070872, 19.092349147794891 ], [ -71.471135829954562, 19.128393460090081 ], [ -71.43721025295082, 19.123251655539434 ], [ -71.405842658112192, 19.105139064915875 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-28", "NAME_1": "Monseñor Nouel" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.392312791602023, 19.072324531052232 ], [ -70.380892300039591, 19.048682563149725 ], [ -70.371823085966639, 19.02545400639724 ], [ -70.367120530987677, 18.998427232230995 ], [ -70.341799079164161, 18.986825873515215 ], [ -70.332652350725368, 18.975715440315298 ], [ -70.329577602824088, 18.961013495276575 ], [ -70.313867967432714, 18.94127309847471 ], [ -70.292913173803925, 18.926726183066876 ], [ -70.249918381827854, 18.897606512930224 ], [ -70.223847622070082, 18.854766751484362 ], [ -70.244414842071308, 18.833010973077933 ], [ -70.251184454598899, 18.80172089350441 ], [ -70.285394253342133, 18.786088772478877 ], [ -70.29955359602161, 18.75761505838824 ], [ -70.31306698265513, 18.719529526966085 ], [ -70.350015631616088, 18.720149643691116 ], [ -70.375621304279775, 18.737151191174519 ], [ -70.402286343240121, 18.747383124331691 ], [ -70.426470912602497, 18.739166571879764 ], [ -70.451456467641833, 18.73660858791601 ], [ -70.491686570978459, 18.76472056680069 ], [ -70.533673671702559, 18.787949124452496 ], [ -70.592378099070004, 18.853242296294923 ], [ -70.583334724318036, 18.922462876760335 ], [ -70.523519252911171, 18.969049181474531 ], [ -70.522640753767746, 19.037365424374798 ], [ -70.501840989769846, 19.074210720548308 ], [ -70.454195318758934, 19.086483872832446 ], [ -70.443420783242516, 19.10508738897181 ], [ -70.423732062384772, 19.111727810290176 ], [ -70.399780036119751, 19.098266100500098 ], [ -70.392312791602023, 19.072324531052232 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-24", "NAME_1": "Sánchez Ramírez" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.223847622070082, 18.854766751484362 ], [ -70.249918381827854, 18.897606512930224 ], [ -70.292913173803925, 18.926726183066876 ], [ -70.313867967432714, 18.94127309847471 ], [ -70.329577602824088, 18.961013495276575 ], [ -70.332652350725368, 18.975715440315298 ], [ -70.341799079164161, 18.986825873515215 ], [ -70.367120530987677, 18.998427232230995 ], [ -70.371823085966639, 19.02545400639724 ], [ -70.380892300039591, 19.048682563149725 ], [ -70.392312791602023, 19.072324531052232 ], [ -70.364123298351501, 19.103304552263239 ], [ -70.324358283008337, 19.121184597091485 ], [ -70.299863654384126, 19.133251043800612 ], [ -70.277642787984291, 19.141080024423559 ], [ -70.279554815902031, 19.143741360275556 ], [ -70.281441006297371, 19.146428534549216 ], [ -70.281880255869112, 19.150666002434036 ], [ -70.285006679714513, 19.149839179234732 ], [ -70.266429002896132, 19.155626938932073 ], [ -70.247076178822567, 19.150588487168932 ], [ -70.226095546772058, 19.146945299386061 ], [ -70.205502489248488, 19.150433458437362 ], [ -70.161241625400692, 19.151156927949842 ], [ -70.117445847747661, 19.146325181761711 ], [ -70.089075487343848, 19.144283961735425 ], [ -70.063056402630878, 19.133070177546642 ], [ -70.040525478767847, 19.123122463430946 ], [ -70.016909349287005, 19.116146145328344 ], [ -69.986136033651007, 19.115810248544108 ], [ -69.95383826372489, 19.113691515051357 ], [ -69.929059414260564, 19.106379299265257 ], [ -69.907768723847539, 19.093486030256088 ], [ -69.911153531010655, 19.066846828818086 ], [ -69.920326096971792, 19.039251613870874 ], [ -69.93531226285063, 18.974966132381098 ], [ -69.952546353431444, 18.909983018001867 ], [ -69.980554978629357, 18.889389960478297 ], [ -70.013085292552205, 18.904556993510425 ], [ -70.033084072671784, 18.908045152561726 ], [ -70.045357224955978, 18.890526842040117 ], [ -70.063159756317702, 18.893239853836178 ], [ -70.084114549047172, 18.897218940201924 ], [ -70.110469529645059, 18.891069444399307 ], [ -70.129615648143613, 18.874920559436248 ], [ -70.171990323394709, 18.865205390216545 ], [ -70.223847622070082, 18.854766751484362 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-31", "NAME_1": "San José de Ocoa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.533673671702559, 18.787949124452496 ], [ -70.491686570978459, 18.76472056680069 ], [ -70.451456467641833, 18.73660858791601 ], [ -70.426470912602497, 18.739166571879764 ], [ -70.402286343240121, 18.747383124331691 ], [ -70.375621304279775, 18.737151191174519 ], [ -70.350015631616088, 18.720149643691116 ], [ -70.368748338065359, 18.679506130103789 ], [ -70.372184821172539, 18.636330470974428 ], [ -70.367895677343597, 18.601035468412135 ], [ -70.378799404968561, 18.565714627428122 ], [ -70.371564704447565, 18.533287665393402 ], [ -70.356552700147006, 18.50357371695344 ], [ -70.378050096135041, 18.48143036491939 ], [ -70.403139003961826, 18.464919744750432 ], [ -70.452050746844463, 18.451251329385343 ], [ -70.479077521010765, 18.413217474806629 ], [ -70.501091681835646, 18.454739488436644 ], [ -70.521865607411826, 18.488742580705491 ], [ -70.554137538916279, 18.504452216096865 ], [ -70.587417161672647, 18.525174464829661 ], [ -70.610619880003469, 18.533003445452607 ], [ -70.627983160894132, 18.548893947997271 ], [ -70.635553758199364, 18.563750921767621 ], [ -70.650333217603873, 18.572355047847168 ], [ -70.671262172810998, 18.622972113971855 ], [ -70.699994269320086, 18.676844794251849 ], [ -70.654699876697919, 18.677904161447884 ], [ -70.610464851271843, 18.677361559088638 ], [ -70.595142787709449, 18.693587958417538 ], [ -70.574058803770754, 18.712036444925957 ], [ -70.548013882434702, 18.743559068496211 ], [ -70.533673671702559, 18.787949124452496 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "DO-29", "NAME_1": "Monte Plata" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -70.251184454598899, 18.80172089350441 ], [ -70.244414842071308, 18.833010973077933 ], [ -70.223847622070082, 18.854766751484362 ], [ -70.171990323394709, 18.865205390216545 ], [ -70.129615648143613, 18.874920559436248 ], [ -70.110469529645059, 18.891069444399307 ], [ -70.084114549047172, 18.897218940201924 ], [ -70.063159756317702, 18.893239853836178 ], [ -70.045357224955978, 18.890526842040117 ], [ -70.033084072671784, 18.908045152561726 ], [ -70.013085292552205, 18.904556993510425 ], [ -69.980554978629357, 18.889389960478297 ], [ -69.952546353431444, 18.909983018001867 ], [ -69.93531226285063, 18.974966132381098 ], [ -69.920326096971792, 19.039251613870874 ], [ -69.893428514014715, 19.038347276305728 ], [ -69.878287320303571, 19.057338365173393 ], [ -69.876995409110805, 19.072815457467357 ], [ -69.874928351562176, 19.083977565712075 ], [ -69.821339891222976, 19.089997870305467 ], [ -69.755788336962155, 19.087594915972602 ], [ -69.727340461293238, 19.066872667239807 ], [ -69.698608364784207, 19.046537991235311 ], [ -69.666930711583063, 19.029458930285386 ], [ -69.637836879868075, 19.008891710284161 ], [ -69.591663988102539, 18.969720974143627 ], [ -69.534716559921264, 18.942358303193146 ], [ -69.484512905845918, 18.918742173712303 ], [ -69.435601162063961, 18.893265693157218 ], [ -69.399350145093138, 18.888769842853947 ], [ -69.380875821062261, 18.871122341123112 ], [ -69.399918585874047, 18.858616644842243 ], [ -69.420459968352873, 18.846550198133116 ], [ -69.441311408294837, 18.825879625344442 ], [ -69.459113938757241, 18.802573554226115 ], [ -69.518309291640492, 18.743429877286985 ], [ -69.575334235086871, 18.648216051429586 ], [ -69.611120164963609, 18.6612385125473 ], [ -69.645097418810792, 18.654288031067779 ], [ -69.663933478047568, 18.642660833930336 ], [ -69.685740933297438, 18.638242498892168 ], [ -69.743851080562933, 18.617726955734383 ], [ -69.789972297283668, 18.571838283909642 ], [ -69.797982144160585, 18.600105292425269 ], [ -69.818988613733552, 18.61943227807717 ], [ -69.824621344699267, 18.63927602856586 ], [ -69.838470629016285, 18.656690986299964 ], [ -69.861156581610942, 18.68108226213667 ], [ -69.888260871042348, 18.70133942287606 ], [ -69.91143775095145, 18.7024763053372 ], [ -69.934640469282215, 18.70340648042469 ], [ -69.947301195193972, 18.702838040543099 ], [ -69.959083421063042, 18.69903982223002 ], [ -69.963682624153762, 18.690125636888638 ], [ -69.966343960005759, 18.68092723250578 ], [ -70.008770311200863, 18.66222036447823 ], [ -70.056054247005875, 18.671031196132787 ], [ -70.088842943347174, 18.679480292581445 ], [ -70.120701462802231, 18.690694078568868 ], [ -70.1390207590008, 18.722035834086455 ], [ -70.167184413829602, 18.731673488940373 ], [ -70.191317308147234, 18.748700873046857 ], [ -70.217233039173379, 18.762498481419755 ], [ -70.23464799690754, 18.78172211428415 ], [ -70.251184454598899, 18.80172089350441 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/ecuador.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/ecuador.geojson new file mode 100644 index 0000000000000..76f332f09d54a --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/ecuador.geojson @@ -0,0 +1,30 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "EC-E", "NAME_1": "Esmeraldas" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -78.828684048999946, 1.43431224200009 ], [ -78.769967610999856, 1.394102072000067 ], [ -78.664676879999945, 1.266642151000042 ], [ -78.602148396999951, 1.263644918000111 ], [ -78.570057332999852, 1.19584543900001 ], [ -78.540601766999941, 1.205353902000084 ], [ -78.47812265099995, 1.18711995600006 ], [ -78.495694139073237, 1.171350002100894 ], [ -78.494143846361396, 1.100759996076931 ], [ -78.53062740822827, 1.021384995920812 ], [ -78.534787359948666, 0.964024155690197 ], [ -78.523496059595459, 0.928367417922004 ], [ -78.442105678734094, 0.871936754577575 ], [ -78.450632290447857, 0.789047756049115 ], [ -78.513444993591577, 0.759902249289382 ], [ -78.424225633006529, 0.586217759941633 ], [ -78.426318528976935, 0.558519192206973 ], [ -78.448616908843235, 0.542034410459678 ], [ -78.497399462315343, 0.542137763247183 ], [ -78.539205694986833, 0.51505931223744 ], [ -78.667414923659805, 0.372949124202705 ], [ -78.719608120018734, 0.402714749486108 ], [ -78.859961310665938, 0.422816881493873 ], [ -78.987576260136279, 0.267477524967774 ], [ -79.01070146410126, 0.267425849023709 ], [ -79.040208706066892, 0.295021063970921 ], [ -79.14506018677821, 0.317655341520776 ], [ -79.221877203869838, 0.31558828397209 ], [ -79.3522310053566, 0.231665758467955 ], [ -79.303655158358879, 0.173271389463025 ], [ -79.369878506188115, 0.035967109194701 ], [ -79.450364548585014, -0.000929863822194 ], [ -79.420702276988493, -0.03338266427852 ], [ -79.43315629822456, -0.050125827544889 ], [ -79.492997606254505, -0.025631198920678 ], [ -79.595549486319726, -0.013590589733951 ], [ -79.618416306966992, 0.045372219152569 ], [ -79.567850917685689, 0.116530666856761 ], [ -79.623945686044578, 0.15389272696774 ], [ -79.649938931436509, 0.145676174515813 ], [ -79.659602423812771, 0.175958563736742 ], [ -79.682133347675858, 0.170429185558476 ], [ -79.702106289373717, 0.187430732142559 ], [ -79.652186856138485, 0.259157619728342 ], [ -79.71223486974344, 0.303651028472189 ], [ -79.695595059264576, 0.347110907542344 ], [ -79.717583380768417, 0.370778712967194 ], [ -79.75269751707674, 0.369280097098795 ], [ -79.814580044233651, 0.322667954862197 ], [ -79.889665899661509, 0.318688870295091 ], [ -79.929405076583009, 0.260294501290218 ], [ -79.973975999692641, 0.284272365976904 ], [ -79.999521235313509, 0.345101779873908 ], [ -79.993316209999932, 0.378119208000044 ], [ -80.043568488999938, 0.458929755000042 ], [ -80.043365037999934, 0.501206773000092 ], [ -80.016957160999937, 0.55890534100007 ], [ -80.036366339999915, 0.625230210000041 ], [ -80.090321417999917, 0.652167059000078 ], [ -80.104969855999911, 0.679673570000091 ], [ -80.097279425999943, 0.780340887000079 ], [ -80.046213344999899, 0.839667059000078 ], [ -79.981312628999945, 0.832220770000049 ], [ -79.862172003999945, 0.87641022300005 ], [ -79.765614386999914, 0.955145575000074 ], [ -79.655751105999911, 1.003607489000046 ], [ -79.670074022999927, 0.921616929000038 ], [ -79.614857550999943, 0.845282294000071 ], [ -79.648304816999939, 0.907416083000044 ], [ -79.632679816999939, 0.986029364000046 ], [ -79.614857550999943, 0.996079820000091 ], [ -79.571766730999911, 0.983710028000075 ], [ -79.435047980999911, 1.078029690000051 ], [ -79.364654100999928, 1.072455145000049 ], [ -79.272206183999913, 1.092962958000044 ], [ -79.248158331999946, 1.080267645000049 ], [ -79.165760870999918, 1.099798895000049 ], [ -79.057240363999938, 1.21751536700009 ], [ -79.013050910999937, 1.192775783000059 ], [ -78.991688605999911, 1.119696356000077 ], [ -78.962147589999915, 1.144680080000057 ], [ -78.954579230999911, 1.20734284100007 ], [ -78.928944464999915, 1.243150132000039 ], [ -78.901682094999899, 1.236314195000091 ], [ -78.871693488999938, 1.288967190000051 ], [ -78.812855597999942, 1.277289130000042 ], [ -78.881947394999941, 1.319281317000048 ], [ -78.83234615799995, 1.381333726000094 ], [ -78.828684048999946, 1.43431224200009 ] ] ], [ [ [ -78.901682094999899, 1.374172268000052 ], [ -78.899281378999945, 1.271429755000042 ], [ -78.912505662999934, 1.245266018000052 ], [ -78.936390753999945, 1.256822007000039 ], [ -78.956898566999939, 1.236314195000091 ], [ -78.995432094999899, 1.286810614000046 ], [ -78.901682094999899, 1.374172268000052 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-C", "NAME_1": "Carchi" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -78.47812265099995, 1.18711995600006 ], [ -78.349218099999945, 1.05580230700005 ], [ -78.250154378999923, 1.019628804000121 ], [ -78.077942667999935, 0.900773011000126 ], [ -77.91826249199994, 0.874418030000072 ], [ -77.903224649999856, 0.832095032000069 ], [ -77.847982543999962, 0.809254048000057 ], [ -77.703185180999924, 0.843102112000054 ], [ -77.673316202999899, 0.819641012000076 ], [ -77.666804972999927, 0.747707418000047 ], [ -77.645565959999942, 0.7162881470001 ], [ -77.579833536999899, 0.670916239000078 ], [ -77.514137794999868, 0.660531216000038 ], [ -77.570014207589622, 0.624716702513808 ], [ -77.669543015697627, 0.638669337819692 ], [ -77.673005337226527, 0.616965237155966 ], [ -77.649957647627332, 0.584977524692988 ], [ -77.775143806141728, 0.448293362049014 ], [ -77.791861130986376, 0.370985419441524 ], [ -77.814081997386268, 0.345663966718689 ], [ -78.000453050168119, 0.46865387647523 ], [ -78.130806850755562, 0.505602525436188 ], [ -78.168608161337545, 0.651381741474154 ], [ -78.258421800225904, 0.775405178206427 ], [ -78.360301886722652, 0.852816474500685 ], [ -78.428618129622976, 0.865373846725618 ], [ -78.523496059595459, 0.928367417922004 ], [ -78.53062740822827, 1.021384995920812 ], [ -78.494143846361396, 1.100759996076931 ], [ -78.495694139073237, 1.171350002100894 ], [ -78.47812265099995, 1.18711995600006 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-U", "NAME_1": "Sucumbios" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -77.509346883999939, 0.661201070000033 ], [ -77.468057413999929, 0.650865784000118 ], [ -77.434726115999865, 0.433824769000054 ], [ -77.397467406999851, 0.387626038000093 ], [ -77.206936401999968, 0.334192607000077 ], [ -77.117432820999852, 0.357550354000125 ], [ -77.082861287999947, 0.348868713000073 ], [ -77.04462072799987, 0.305667216000131 ], [ -76.945867065999948, 0.287063701000079 ], [ -76.882460082999927, 0.240141500000036 ], [ -76.797865763999937, 0.249960022000096 ], [ -76.734355427999873, 0.233113505000119 ], [ -76.736887573999866, 0.272904358000034 ], [ -76.724536905999912, 0.277555237000087 ], [ -76.626868448999886, 0.258538310000034 ], [ -76.565425171999976, 0.21606028300009 ], [ -76.425692098999917, 0.242725322000126 ], [ -76.408018757999912, 0.254507548000035 ], [ -76.416390339999879, 0.401888733000078 ], [ -76.365385701999912, 0.406953023000057 ], [ -76.300480102999899, 0.461626689000099 ], [ -76.223740600999946, 0.406746318000089 ], [ -76.136304077999881, 0.396721090000071 ], [ -76.119560913999919, 0.351762594000149 ], [ -76.053466756999882, 0.363544820000058 ], [ -75.951974243999899, 0.203967997000092 ], [ -75.81787390199986, 0.100098369000079 ], [ -75.75384680199997, 0.073019918000028 ], [ -75.626774454999946, 0.078911031000118 ], [ -75.464923868999875, -0.039738056999923 ], [ -75.283487914999881, -0.107020771999899 ], [ -75.330746012999896, -0.144641214999922 ], [ -75.402576253999911, -0.14577809599993 ], [ -75.429499674999931, -0.163658141999889 ], [ -75.539260417999856, -0.120043232999933 ], [ -75.623002075999921, -0.106607360999888 ], [ -75.643207560999912, -0.128828226999929 ], [ -75.619565592999976, -0.180918069999976 ], [ -75.578973754999936, -0.182675068999856 ], [ -75.484767619999872, -0.247684020999912 ], [ -75.452728230999952, -0.360648701999907 ], [ -75.405625162999854, -0.442400817999925 ], [ -75.34735998599993, -0.470926208999884 ], [ -75.290980997999895, -0.527976989999971 ], [ -75.272041584999869, -0.525703225999948 ], [ -75.257029581999888, -0.56198008199992 ], [ -75.257649699999945, -0.633190204999963 ], [ -75.282091843763567, -0.643526299898838 ], [ -75.289739956333904, -0.618359876806892 ], [ -75.382757534332711, -0.601771742272092 ], [ -75.403014695971422, -0.565494886879549 ], [ -75.542411872210096, -0.542343844492848 ], [ -75.574451259717875, -0.49516326327398 ], [ -75.588533088031568, -0.499969171040448 ], [ -75.654368863132504, -0.455010675202516 ], [ -75.69958574138883, -0.464157402741932 ], [ -75.748316617118178, -0.422609551589517 ], [ -75.831644864319003, -0.436665540582226 ], [ -75.886912807679892, -0.413411147206716 ], [ -75.947632615752582, -0.422867934007968 ], [ -75.937193977020399, -0.561670831044012 ], [ -75.994425625142469, -0.553299248961196 ], [ -76.077986416340025, -0.501622816539737 ], [ -76.102842780170135, -0.441936537241418 ], [ -76.274382696704095, -0.443125094747359 ], [ -76.410214200425003, -0.510304456985125 ], [ -76.427396613263056, -0.485706474674089 ], [ -76.502172411227775, -0.473665867285945 ], [ -76.575733812365513, -0.405091241067908 ], [ -76.621855028186985, -0.424883314713213 ], [ -76.714097459829873, -0.341942641140008 ], [ -76.767608404903967, -0.252645766189175 ], [ -76.917547573561649, -0.078599541635526 ], [ -76.945427009348975, -0.065680434204694 ], [ -77.073610398700907, -0.102112319228183 ], [ -77.147249315103807, -0.083043715095357 ], [ -77.19742713075749, -0.090588473978926 ], [ -77.284010993012885, -0.047335299584404 ], [ -77.349975959323046, -0.131619561193816 ], [ -77.374212206428183, -0.141076347995067 ], [ -77.446455857951491, -0.124849948666224 ], [ -77.44392371330872, -0.060409437545502 ], [ -77.46487850603819, -0.023460788584543 ], [ -77.588979458035567, -0.100045260780178 ], [ -77.64086259603198, -0.081028333490792 ], [ -77.758917405913564, -0.075033868218441 ], [ -77.778864509189759, -0.046818535646935 ], [ -77.778942022656224, 0.015813300343552 ], [ -77.845191209806501, 0.035967109194701 ], [ -77.863898077833994, 0.074155992505041 ], [ -77.970429043365641, 0.119734605067947 ], [ -77.835501879008518, 0.26918284731056 ], [ -77.852477587170881, 0.29264394805972 ], [ -77.791861130986376, 0.370985419441524 ], [ -77.783747932221274, 0.43470246015039 ], [ -77.649957647627332, 0.584977524692988 ], [ -77.673005337226527, 0.616965237155966 ], [ -77.669543015697627, 0.638669337819692 ], [ -77.570014207589622, 0.624716702513808 ], [ -77.509346883999939, 0.661201070000033 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-D", "NAME_1": "Orellana" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -75.266641397999877, -0.642698668999941 ], [ -75.293978230999926, -0.667916767999898 ], [ -75.297027139999841, -0.746981709999972 ], [ -75.252068644999923, -0.933430276999943 ], [ -75.227263957999895, -0.969810484999925 ], [ -75.34872941099988, -0.974978128999922 ], [ -75.406400309999952, -0.915136819999873 ], [ -75.41257564299994, -0.92392181299995 ], [ -75.5807400973776, -1.54663979598979 ], [ -75.602330694605882, -1.496187431704641 ], [ -75.702996385175027, -1.445596204900937 ], [ -75.717569139004524, -1.45567311022586 ], [ -75.747541469862938, -1.405288588097847 ], [ -75.833014288978234, -1.383997897684822 ], [ -75.844176398122272, -1.357332858724476 ], [ -75.880246547939805, -1.342863457682427 ], [ -75.878463711231291, -1.328445732584498 ], [ -75.89962521043509, -1.347307631142257 ], [ -75.950190598817073, -1.344517104081092 ], [ -76.004812587930587, -1.310152275706969 ], [ -76.056411505986205, -1.301160576899122 ], [ -76.063542852820376, -1.276149183438065 ], [ -76.105943365593816, -1.273048598014384 ], [ -76.155630255731694, -1.293099054078084 ], [ -76.245263028366026, -1.282143649609736 ], [ -76.284201218711246, -1.311082451693778 ], [ -76.358331060629951, -1.283125501540667 ], [ -76.362749395668061, -1.262661635226323 ], [ -76.463673468655657, -1.251344495552019 ], [ -76.511267462823128, -1.187782484474099 ], [ -76.515065681136264, -1.084377943687173 ], [ -76.545373907879537, -1.05156340892421 ], [ -76.594673225289114, -1.046344089108459 ], [ -76.760942145163881, -1.097865491898915 ], [ -76.810732388089207, -1.089648939446988 ], [ -76.850006477017303, -1.156828301684811 ], [ -77.056221280287843, -1.093524672125909 ], [ -77.074463060321989, -1.039626152524932 ], [ -77.04283708396423, -0.987949721002849 ], [ -77.061879848775959, -0.963713473897712 ], [ -77.036144985802423, -0.925214532224913 ], [ -77.113995530769103, -0.904233901073667 ], [ -77.186885139237745, -0.860360609954171 ], [ -77.196316087617333, -0.835762627643135 ], [ -77.176704881125374, -0.786928399126339 ], [ -77.1186205722816, -0.730342706150964 ], [ -77.124201626403931, -0.707915134176119 ], [ -77.16481930156948, -0.722797947267452 ], [ -77.209545254310001, -0.764707532726447 ], [ -77.254994675663738, -0.833850599725395 ], [ -77.49921749509133, -0.945316664232678 ], [ -77.566164313332365, -0.947177016206354 ], [ -77.579005907296789, -0.931364028027474 ], [ -77.528466356437207, -0.841188653033896 ], [ -77.533272264203617, -0.780778904223041 ], [ -77.496607836082774, -0.69137867558544 ], [ -77.575285204248758, -0.577018731229487 ], [ -77.621716478432745, -0.544772638146753 ], [ -77.566474371694881, -0.49573170315557 ], [ -77.551539882659426, -0.458007907838692 ], [ -77.448006150663332, -0.507823988286418 ], [ -77.404029506756331, -0.504154962081827 ], [ -77.356564703798028, -0.425658461069133 ], [ -77.329047004115921, -0.424056491513909 ], [ -77.32323340509754, -0.387417900915409 ], [ -77.273184780653082, -0.360391126749107 ], [ -77.254374558938707, -0.294865410910006 ], [ -77.259955613960415, -0.246341240755669 ], [ -77.297911953274024, -0.19027231171782 ], [ -77.299410570041744, -0.058549085571826 ], [ -77.284010993012885, -0.047335299584404 ], [ -77.19742713075749, -0.090588473978926 ], [ -77.147249315103807, -0.083043715095357 ], [ -77.073610398700907, -0.102112319228183 ], [ -76.931706916241183, -0.069607842827679 ], [ -76.767608404903967, -0.252645766189175 ], [ -76.714097459829873, -0.341942641140008 ], [ -76.621855028186985, -0.424883314713213 ], [ -76.575733812365513, -0.405091241067908 ], [ -76.502172411227775, -0.473665867285945 ], [ -76.427396613263056, -0.485706474674089 ], [ -76.410214200425003, -0.510304456985125 ], [ -76.274382696704095, -0.443125094747359 ], [ -76.102842780170135, -0.441936537241418 ], [ -76.077986416340025, -0.501622816539737 ], [ -75.994425625142469, -0.553299248961196 ], [ -75.937193977020399, -0.561670831044012 ], [ -75.947632615752582, -0.422867934007968 ], [ -75.886912807679892, -0.413411147206716 ], [ -75.831644864319003, -0.436665540582226 ], [ -75.748316617118178, -0.422609551589517 ], [ -75.69958574138883, -0.464157402741932 ], [ -75.654368863132504, -0.455010675202516 ], [ -75.588533088031568, -0.499969171040448 ], [ -75.574451259717875, -0.49516326327398 ], [ -75.542411872210096, -0.542343844492848 ], [ -75.403014695971422, -0.565494886879549 ], [ -75.382757534332711, -0.601771742272092 ], [ -75.289739956333904, -0.618359876806892 ], [ -75.285140754142503, -0.641355888663327 ], [ -75.266641397999877, -0.642698668999941 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-Y", "NAME_1": "Pastaza" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -75.5807400973776, -1.54663979598979 ], [ -76.091242228999931, -2.12891286199995 ], [ -76.625266479999937, -2.537673441999928 ], [ -76.725905524120606, -2.577051690083465 ], [ -76.831351284034497, -2.529974459853463 ], [ -76.918271043973505, -2.540361422641524 ], [ -76.95904374877, -2.528269137510677 ], [ -77.017128059412414, -2.477212822713625 ], [ -77.034620530612983, -2.430032239696118 ], [ -77.123064744842111, -2.313656914634919 ], [ -77.384263272432065, -2.154338473541713 ], [ -77.710625779755901, -2.02246021866415 ], [ -77.753155483738567, -1.950785007022489 ], [ -77.838318243592028, -1.912751152443718 ], [ -77.914127570331118, -1.668114922765483 ], [ -77.948544073749986, -1.655609225585295 ], [ -78.008979661881881, -1.668114922765483 ], [ -78.078458624765688, -1.506109306499297 ], [ -78.129282395566065, -1.45624155010745 ], [ -78.172561408382251, -1.446991468881208 ], [ -78.116828376128638, -1.357694593930376 ], [ -78.116518316866802, -1.23330942109294 ], [ -77.941955329275004, -1.223852634291632 ], [ -77.897177699691099, -1.23713347692842 ], [ -77.882062344401675, -1.214085789127864 ], [ -77.831109382392071, -1.221837252687067 ], [ -77.695613776354662, -1.151660657813125 ], [ -77.547069871677195, -1.13574431684674 ], [ -77.445525681964625, -1.087323499479908 ], [ -77.373023648022922, -1.079313652602991 ], [ -77.233755662993417, -1.024536634757908 ], [ -77.051647914719467, -1.010377292078374 ], [ -77.074463060321989, -1.039626152524932 ], [ -77.056221280287843, -1.093524672125909 ], [ -76.867938198688933, -1.157396741566401 ], [ -76.850006477017303, -1.156828301684811 ], [ -76.810732388089207, -1.089648939446988 ], [ -76.760942145163881, -1.097865491898915 ], [ -76.594673225289114, -1.046344089108459 ], [ -76.545373907879537, -1.05156340892421 ], [ -76.515065681136264, -1.084377943687173 ], [ -76.511267462823128, -1.187782484474099 ], [ -76.463673468655657, -1.251344495552019 ], [ -76.362749395668061, -1.262661635226323 ], [ -76.358331060629951, -1.283125501540667 ], [ -76.284201218711246, -1.311082451693778 ], [ -76.245263028366026, -1.282143649609736 ], [ -76.155630255731694, -1.293099054078084 ], [ -76.105943365593816, -1.273048598014384 ], [ -76.063542852820376, -1.276149183438065 ], [ -76.056411505986205, -1.301160576899122 ], [ -76.004812587930587, -1.310152275706969 ], [ -75.950190598817073, -1.344517104081092 ], [ -75.89962521043509, -1.347307631142257 ], [ -75.878463711231291, -1.328445732584498 ], [ -75.880246547939805, -1.342863457682427 ], [ -75.844176398122272, -1.357332858724476 ], [ -75.833014288978234, -1.383997897684822 ], [ -75.747541469862938, -1.405288588097847 ], [ -75.717569139004524, -1.45567311022586 ], [ -75.702996385175027, -1.445596204900937 ], [ -75.602330694605882, -1.496187431704641 ], [ -75.5807400973776, -1.54663979598979 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-S", "NAME_1": "Morona Santiago" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -76.669661558234338, -2.564588924739098 ], [ -77.86782629399994, -2.990255634999897 ], [ -77.941465209999961, -3.054541116999957 ], [ -78.042544311999904, -3.189933369999949 ], [ -78.104917765999858, -3.245433857999927 ], [ -78.148170938999925, -3.322431742999939 ], [ -78.196410888999935, -3.363669534999943 ], [ -78.154527140999846, -3.456790465999859 ], [ -78.163725545999938, -3.477254332999919 ], [ -78.226305704999845, -3.507019958999905 ], [ -78.257182372999921, -3.409558206999918 ], [ -78.33397355199989, -3.384546813999918 ], [ -78.36172379599995, -3.408524677999935 ], [ -78.355290079999889, -3.44552500399989 ], [ -78.375871848407087, -3.529348454167859 ], [ -78.645271573424338, -3.539370212165579 ], [ -78.684364794299825, -3.579316094662033 ], [ -78.822185839404938, -3.547018323836596 ], [ -78.864043748919869, -3.497305597075638 ], [ -78.873603889407946, -3.449608250120662 ], [ -78.84939347982521, -3.389146823567046 ], [ -78.938974575616157, -3.3227426076852 ], [ -78.937579311635886, -3.287809339429486 ], [ -78.671652390645306, -3.090767103918722 ], [ -78.656097784884878, -3.008446547070491 ], [ -78.56992733377939, -2.839206231182629 ], [ -78.598685268710142, -2.785927830105265 ], [ -78.566387498784025, -2.720815524516865 ], [ -78.421435105945363, -2.627022800162081 ], [ -78.427842984166375, -2.601494642763555 ], [ -78.472103848014171, -2.568266696850571 ], [ -78.510266892902791, -2.585216566591271 ], [ -78.526364101921729, -2.622837009120701 ], [ -78.550264452242686, -2.612501723175967 ], [ -78.549101732259146, -2.562944024247315 ], [ -78.528043585842795, -2.562220553835516 ], [ -78.490242276160075, -2.505893243278535 ], [ -78.481224738031244, -2.380681248141116 ], [ -78.579900886316864, -2.311538181142168 ], [ -78.544631721276915, -2.286888522887011 ], [ -78.530162320234865, -2.240379733437976 ], [ -78.497812872565987, -2.210510756266387 ], [ -78.500577562104809, -2.127104993800458 ], [ -78.445800544259669, -2.075221855803989 ], [ -78.489544644169996, -1.964840996914461 ], [ -78.415647346248022, -1.854356785237485 ], [ -78.44835852732416, -1.755654798530145 ], [ -78.44758338096824, -1.705993747713308 ], [ -78.359397549157563, -1.621709487003216 ], [ -78.363092413783875, -1.541611015535921 ], [ -78.30653255923022, -1.484560234567198 ], [ -78.218553432994497, -1.482079765868491 ], [ -78.172561408382251, -1.446991468881208 ], [ -78.129282395566065, -1.45624155010745 ], [ -78.069776984320356, -1.520733738071556 ], [ -78.008979661881881, -1.668114922765483 ], [ -77.948544073749986, -1.655609225585295 ], [ -77.914127570331118, -1.668114922765483 ], [ -77.829481574415126, -1.924843437574566 ], [ -77.753155483738567, -1.950785007022489 ], [ -77.710625779755901, -2.02246021866415 ], [ -77.384263272432065, -2.154338473541713 ], [ -77.123064744842111, -2.313656914634919 ], [ -76.992891812307278, -2.506048272010162 ], [ -76.918271043973505, -2.540361422641524 ], [ -76.831351284034497, -2.529974459853463 ], [ -76.725905524120606, -2.577051690083465 ], [ -76.669661558234338, -2.564588924739098 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-Z", "NAME_1": "Zamora Chinchipe" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -78.375871848407087, -3.529348454167859 ], [ -78.402393147999902, -3.594353128999927 ], [ -78.400739501999936, -3.679825947999859 ], [ -78.425854248999968, -3.689437763999962 ], [ -78.419678914999878, -3.791033629999959 ], [ -78.480682942999863, -3.849531351999957 ], [ -78.497632812999967, -3.949576924999946 ], [ -78.562073323999869, -3.979755960999853 ], [ -78.576620239999926, -4.10005869499993 ], [ -78.682427734999891, -4.326918232999972 ], [ -78.673151814999954, -4.401539000999946 ], [ -78.637210855999882, -4.435128681999885 ], [ -78.66979284699994, -4.493419697999911 ], [ -78.68167842699998, -4.567110290999935 ], [ -78.853063314999929, -4.652273049999877 ], [ -78.898641927999932, -4.694234313999885 ], [ -78.928614257999868, -4.74746103899993 ], [ -78.90021805899994, -4.843682555999891 ], [ -78.910811726999924, -4.863526305999883 ], [ -78.980342366999935, -4.873964944999912 ], [ -79.009281168999877, -4.960109557999914 ], [ -79.06392899599993, -5.011372578999939 ], [ -79.104159097999883, -4.980056660999935 ], [ -79.303216715999952, -4.961246438999922 ], [ -79.341043863999914, -4.904247333999933 ], [ -79.378070027999883, -4.884816995999955 ], [ -79.395329956999973, -4.847609964999947 ], [ -79.450572062999896, -4.810196227999882 ], [ -79.460823144172764, -4.770455598247281 ], [ -79.33158627009027, -4.60819386225694 ], [ -79.318357103397602, -4.513419285071961 ], [ -79.29151119728391, -4.482258395808344 ], [ -79.266422288557749, -4.477659193616887 ], [ -79.205056525338364, -4.50298064454114 ], [ -79.156093105612342, -4.469545993952465 ], [ -79.113537564107276, -4.407999362680471 ], [ -79.102633837381688, -4.206047864817094 ], [ -79.154775356897176, -4.138765150691142 ], [ -79.135887620817016, -4.032104993950327 ], [ -79.139608323865048, -3.947303969302766 ], [ -79.119247810338152, -3.883121839701175 ], [ -79.193558519410146, -3.731038100028286 ], [ -79.152863328979436, -3.71010914482116 ], [ -79.143949143638054, -3.676777846120729 ], [ -79.102246262854749, -3.636005140424913 ], [ -79.065478481946343, -3.619417005890114 ], [ -79.046306525026068, -3.474722995469847 ], [ -79.055091519158282, -3.412246189110363 ], [ -78.938974575616157, -3.3227426076852 ], [ -78.84939347982521, -3.389146823567046 ], [ -78.873603889407946, -3.449608250120662 ], [ -78.864043748919869, -3.497305597075638 ], [ -78.822185839404938, -3.547018323836596 ], [ -78.684364794299825, -3.579316094662033 ], [ -78.645271573424338, -3.539370212165579 ], [ -78.375871848407087, -3.529348454167859 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-L", "NAME_1": "Loja" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -80.325505737999919, -4.015412698999938 ], [ -80.259075683999868, -3.943685810999852 ], [ -80.181147623999891, -3.907925719999923 ], [ -80.165073793999909, -3.880695936999885 ], [ -80.01363766134898, -3.86239959096838 ], [ -79.934831101973771, -3.829533380261296 ], [ -79.741328700559052, -3.832840671259987 ], [ -79.606272345892023, -3.751915377492708 ], [ -79.559763557342308, -3.794858493524657 ], [ -79.446385464017908, -3.80514210352527 ], [ -79.415302090019452, -3.793359876756938 ], [ -79.396362677995171, -3.7656096330781 ], [ -79.402538011320132, -3.721839694746109 ], [ -79.366338671192693, -3.653316746270832 ], [ -79.379722866616987, -3.620295505033539 ], [ -79.427988654352873, -3.589444675031757 ], [ -79.485943772886799, -3.628408704697961 ], [ -79.467753668796774, -3.511671644430862 ], [ -79.422769335436442, -3.449349866802947 ], [ -79.456617398074457, -3.415760185684007 ], [ -79.457754278736957, -3.328013603445072 ], [ -79.317866176982477, -3.346772149215326 ], [ -79.281692674377382, -3.449918307583857 ], [ -79.236553311386217, -3.4607703592647 ], [ -79.184902717386478, -3.44206348943851 ], [ -79.130487433847975, -3.537509861091223 ], [ -79.120436366944773, -3.610942071019792 ], [ -79.102246262854749, -3.636005140424913 ], [ -79.143949143638054, -3.676777846120729 ], [ -79.152863328979436, -3.71010914482116 ], [ -79.193558519410146, -3.731038100028286 ], [ -79.119247810338152, -3.883121839701175 ], [ -79.139608323865048, -3.947303969302766 ], [ -79.135887620817016, -4.032104993950327 ], [ -79.154775356897176, -4.138765150691142 ], [ -79.102633837381688, -4.206047864817094 ], [ -79.113537564107276, -4.407999362680471 ], [ -79.156093105612342, -4.469545993952465 ], [ -79.205056525338364, -4.50298064454114 ], [ -79.266422288557749, -4.477659193616887 ], [ -79.29151119728391, -4.482258395808344 ], [ -79.318357103397602, -4.513419285071961 ], [ -79.33158627009027, -4.60819386225694 ], [ -79.460823144172764, -4.770455598247281 ], [ -79.527854166999902, -4.618063252999974 ], [ -79.507209431999883, -4.531556904999974 ], [ -79.557774821999914, -4.516570739999906 ], [ -79.657975422999925, -4.438746031999955 ], [ -79.795744791999965, -4.484738056999944 ], [ -79.832874308999862, -4.478950296999884 ], [ -79.904084431999905, -4.398645120999959 ], [ -79.9820124929999, -4.388619892999941 ], [ -80.079655110999909, -4.309038187999917 ], [ -80.140245727999883, -4.283096617999959 ], [ -80.205047973999882, -4.298186136999959 ], [ -80.255406656999867, -4.386759541999936 ], [ -80.382866577999891, -4.476263121999949 ], [ -80.469967203999971, -4.446084085999942 ], [ -80.4885448819999, -4.395957946999928 ], [ -80.345271972999882, -4.198450621999967 ], [ -80.469605468999958, -4.213230081999882 ], [ -80.512212686999931, -4.064195251999891 ], [ -80.481077636999885, -3.99877288799992 ], [ -80.447694661999918, -3.982753193999955 ], [ -80.407102823999878, -3.982443135999887 ], [ -80.325505737999919, -4.015412698999938 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-O", "NAME_1": "El Oro" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -80.165073793999909, -3.880695936999885 ], [ -80.188769897999862, -3.857696226999892 ], [ -80.226312825999855, -3.749279072999926 ], [ -80.216390950999966, -3.631560159999935 ], [ -80.224995076999903, -3.59187265999995 ], [ -80.249980631999904, -3.577713317999908 ], [ -80.240291300999871, -3.514047952999917 ], [ -80.271633056999889, -3.485522562999961 ], [ -80.265664428999855, -3.426404723999894 ], [ -80.340728666670429, -3.393497653515368 ], [ -80.341053839999915, -3.368584893999923 ], [ -80.30687415299991, -3.320733330999929 ], [ -80.314320441999939, -3.376071872999944 ], [ -80.286447719999899, -3.320733330999929 ], [ -80.259103969999899, -3.348077080999929 ], [ -80.135568813999896, -3.327569268999923 ], [ -80.059885219999899, -3.204034112999921 ], [ -80.037505662999934, -3.20826588299991 ], [ -80.039947068999936, -3.279880466999941 ], [ -80.029204881999931, -3.273532809999949 ], [ -79.953195766999897, -3.197442315999922 ], [ -79.933338995999918, -3.115411065999922 ], [ -79.89589342508755, -3.045437722386621 ], [ -79.760474819956983, -3.06467050483991 ], [ -79.638518438974756, -3.128852633542238 ], [ -79.600432909351298, -3.161718845148584 ], [ -79.594696824698701, -3.204351901918756 ], [ -79.632162237597186, -3.290909925752487 ], [ -79.667767300320634, -3.319848727836529 ], [ -79.614850632650587, -3.329873955418691 ], [ -79.507932095289959, -3.312975762521432 ], [ -79.457754278736957, -3.328013603445072 ], [ -79.456617398074457, -3.415760185684007 ], [ -79.422769335436442, -3.449349866802947 ], [ -79.467753668796774, -3.511671644430862 ], [ -79.48772660959537, -3.618693535478315 ], [ -79.481267056329557, -3.635333346856498 ], [ -79.427988654352873, -3.589444675031757 ], [ -79.373056606876901, -3.628357028753896 ], [ -79.368354050998619, -3.669078056706951 ], [ -79.402538011320132, -3.721839694746109 ], [ -79.40755062466161, -3.785505058611591 ], [ -79.446385464017908, -3.80514210352527 ], [ -79.559763557342308, -3.794858493524657 ], [ -79.606272345892023, -3.751915377492708 ], [ -79.741328700559052, -3.832840671259987 ], [ -79.934831101973771, -3.829533380261296 ], [ -80.01363766134898, -3.86239959096838 ], [ -80.165073793999909, -3.880695936999885 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-G", "NAME_1": "Guayas" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -80.059885219999899, -2.662774346999925 ], [ -80.014515753999945, -2.664239190999922 ], [ -79.902821417999917, -2.717461846999925 ], [ -79.907215949999909, -2.732354424999926 ], [ -79.995187954999949, -2.798028252999927 ], [ -80.131033119999927, -3.020920851999961 ], [ -80.203724738999938, -3.034112237999921 ], [ -80.26593990799995, -3.018487237999921 ], [ -80.262203789999944, -2.840848014999949 ], [ -80.210682745999918, -2.724867445999962 ], [ -80.059885219999899, -2.662774346999925 ] ] ], [ [ [ -79.89589342508755, -3.045437722386621 ], [ -79.874867316999939, -3.005466403999947 ], [ -79.881214972999942, -2.965427341999941 ], [ -79.834584113999938, -2.806817315999922 ], [ -79.776437954999949, -2.65943775799991 ], [ -79.726429816999939, -2.593845309999949 ], [ -79.745025193999936, -2.490166924999926 ], [ -79.789540167999917, -2.481052341999941 ], [ -79.839466925999943, -2.377048434999949 ], [ -79.839833136999914, -2.209567966999941 ], [ -79.868641730999911, -2.160902601999908 ], [ -79.861887173999946, -2.108005466999941 ], [ -79.818348761999914, -2.079847914999959 ], [ -79.765614386999914, -2.004978122999944 ], [ -79.831369594999899, -2.043552341999941 ], [ -79.834584113999938, -2.07000090899993 ], [ -79.874338344999899, -2.075372002999927 ], [ -79.891957160999937, -2.115899346999925 ], [ -79.901844855999911, -2.18482838299991 ], [ -79.863026495999918, -2.297133070999962 ], [ -79.878570115999935, -2.49187590899993 ], [ -79.896107550999943, -2.543389580999929 ], [ -79.933216925999943, -2.580254815999922 ], [ -79.998402472999942, -2.608168226999908 ], [ -80.063588019999941, -2.577243747999944 ], [ -80.068918423999946, -2.560804945999962 ], [ -80.02570553299995, -2.52507903399993 ], [ -80.001779751999948, -2.48015715899993 ], [ -79.97484290299991, -2.477227471999925 ], [ -79.943755662999934, -2.498304945999962 ], [ -79.929676886999914, -2.484144789999959 ], [ -79.936350063999896, -2.462985934999949 ], [ -79.940825975999928, -2.483982028999947 ], [ -79.977935350999928, -2.45671965899993 ], [ -80.034331834999932, -2.47389088299991 ], [ -80.008941209999932, -2.358819268999923 ], [ -79.977935350999928, -2.347426039999959 ], [ -79.950021938999896, -2.307224216999941 ], [ -80.012684699999909, -2.326429945999962 ], [ -80.076039191999939, -2.457696221999925 ], [ -80.175119594999899, -2.586683851999908 ], [ -80.231800910999937, -2.628676039999959 ], [ -80.270008917999917, -2.605075778999947 ], [ -80.27961178299995, -2.61256275799991 ], [ -80.27961178299995, -2.649183851999908 ], [ -80.244252081999946, -2.699476820999962 ], [ -80.255482550999943, -2.730238539999959 ], [ -80.278431769999941, -2.727146091999941 ], [ -80.467884894999941, -2.617933851999908 ], [ -80.542747415450577, -2.52976243927536 ], [ -80.41076665945377, -2.416674574272179 ], [ -80.276516835683424, -2.367938822418751 ], [ -80.232020041891417, -2.299776686444943 ], [ -80.213445776201581, -2.110307938660469 ], [ -80.288407472127119, -2.017346144708824 ], [ -80.478271172476639, -1.931161345819476 ], [ -80.516087613252751, -1.840817559282925 ], [ -80.437539436295936, -1.835701593153999 ], [ -80.396069098609985, -1.746198011728893 ], [ -80.329303148421559, -1.687131850054868 ], [ -80.299744228713166, -1.697622165630435 ], [ -80.221170214234007, -1.680672295889735 ], [ -80.226001960422138, -1.61891895904273 ], [ -80.267911546780454, -1.59519947677444 ], [ -80.283259446965872, -1.567655937771349 ], [ -80.222048713377433, -1.559439386218685 ], [ -80.188174812317698, -1.536546726250435 ], [ -80.201636522107776, -1.480684502787597 ], [ -80.191973028832194, -1.431178480702329 ], [ -80.130891485553605, -1.397743829214335 ], [ -80.124328578601023, -1.333975111662085 ], [ -80.043299933844878, -1.271808362765739 ], [ -79.983742844856408, -1.118432711900141 ], [ -79.975164558097845, -1.138224785545447 ], [ -79.937699144300041, -1.142875664580288 ], [ -79.853053148384049, -1.088305352310158 ], [ -79.712183193799319, -0.872246188610745 ], [ -79.535889045443071, -0.837467949985921 ], [ -79.517078823728696, -0.860463961842356 ], [ -79.53278845912007, -0.959527682856276 ], [ -79.561675585260048, -0.986709485754147 ], [ -79.580950894068508, -1.050633232937344 ], [ -79.673761765592985, -1.114298597702145 ], [ -79.686396653982399, -1.146648043572384 ], [ -79.738305630400532, -1.184836927781987 ], [ -79.748149990829404, -1.235169773066559 ], [ -79.847317063731509, -1.399139093194606 ], [ -79.870545619584675, -1.519028415728826 ], [ -79.859693569702472, -1.633698418447239 ], [ -79.758872850401701, -1.696691989643625 ], [ -79.649525520286545, -1.906549980697037 ], [ -79.523615892259613, -1.885155937496506 ], [ -79.482429776313097, -1.897454929101684 ], [ -79.372953254089396, -1.970111992674333 ], [ -79.285930142262259, -2.107674656260372 ], [ -79.235493944190182, -2.154338473541713 ], [ -79.17164771227209, -2.16198658611205 ], [ -79.139944220649227, -2.146535333139127 ], [ -79.130074021798634, -2.203689466895412 ], [ -79.192008225798986, -2.266941419610816 ], [ -79.352644415607301, -2.303321627790922 ], [ -79.416387294737831, -2.347918388422897 ], [ -79.425146451347644, -2.421815688143511 ], [ -79.514314134189931, -2.495196222127959 ], [ -79.489741991199935, -2.51777882193511 ], [ -79.437393765210061, -2.497056573202315 ], [ -79.419100308332531, -2.545529066513211 ], [ -79.690556606602115, -2.825718682071511 ], [ -79.703579067719772, -2.874966321738384 ], [ -79.69484575133032, -2.957131849854989 ], [ -79.74884762192022, -3.023691094468461 ], [ -79.760474819956983, -3.06467050483991 ], [ -79.89589342508755, -3.045437722386621 ] ] ], [ [ [ -79.819639715999926, -2.485910851999961 ], [ -79.772570694999899, -2.541987347999907 ], [ -79.828701939999917, -2.592050637999932 ], [ -79.833236679999914, -2.636017324999955 ], [ -79.877239380999924, -2.649677722999911 ], [ -79.881801126999903, -2.62693980399996 ], [ -79.819639715999926, -2.485910851999961 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-W", "NAME_1": "Galápagos" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -89.661284959999932, -1.340101820999962 ], [ -89.614572719999899, -1.370049737999921 ], [ -89.613270636999914, -1.391696872999944 ], [ -89.67609615799995, -1.397556247999944 ], [ -89.756906704999949, -1.36060963299991 ], [ -89.736398891999897, -1.340101820999962 ], [ -89.661284959999932, -1.340101820999962 ] ] ], [ [ [ -90.380686001999948, -1.254489841999941 ], [ -90.367054816999939, -1.278741143999923 ], [ -90.432118292999917, -1.345961195999962 ], [ -90.475209113999938, -1.342054945999962 ], [ -90.524037238999938, -1.30592213299991 ], [ -90.471913214999915, -1.216729424999926 ], [ -90.380686001999948, -1.254489841999941 ] ] ], [ [ [ -89.308094855999911, -0.685642184999949 ], [ -89.257191535999937, -0.681573174999926 ], [ -89.273182745999918, -0.759942315999922 ], [ -89.331695115999935, -0.819431247999944 ], [ -89.367298956999946, -0.82976653399993 ], [ -89.420033331999946, -0.919366143999923 ], [ -89.544585740999935, -0.956638278999947 ], [ -89.629953579999949, -0.925876559999949 ], [ -89.604603644999941, -0.883070570999962 ], [ -89.55142167899993, -0.853610934999949 ], [ -89.540882941999939, -0.819431247999944 ], [ -89.47720292899993, -0.796807549999926 ], [ -89.413238084999932, -0.713474216999941 ], [ -89.366444464999915, -0.689629815999922 ], [ -89.308094855999911, -0.685642184999949 ] ] ], [ [ [ -90.191965298999946, -0.538262627999927 ], [ -90.180531378999945, -0.54851653399993 ], [ -90.198801235999952, -0.681573174999926 ], [ -90.259510870999918, -0.743340752999927 ], [ -90.313628709999932, -0.74382903399993 ], [ -90.337066209999932, -0.776950778999947 ], [ -90.428863084999932, -0.762465101999908 ], [ -90.48306230399993, -0.702732028999947 ], [ -90.544545050999943, -0.681573174999926 ], [ -90.52757727799991, -0.569919528999947 ], [ -90.460560675999943, -0.513848565999922 ], [ -90.407948370999918, -0.517754815999922 ], [ -90.26398678299995, -0.483005466999941 ], [ -90.24282792899993, -0.497247002999927 ], [ -90.240589972999942, -0.528008721999925 ], [ -90.191965298999946, -0.538262627999927 ] ] ], [ [ [ -91.401112433999913, -0.452894789999959 ], [ -91.507557745999918, -0.490411065999922 ], [ -91.606516079999949, -0.45631275799991 ], [ -91.651966925999943, -0.381117445999962 ], [ -91.668568488999938, -0.284926039999959 ], [ -91.580962693999936, -0.287204684999949 ], [ -91.474191860999895, -0.24928150799991 ], [ -91.455677863999938, -0.257582289999959 ], [ -91.399525519999941, -0.30787525799991 ], [ -91.401112433999913, -0.452894789999959 ] ] ], [ [ [ -90.565012173999946, -0.284926039999959 ], [ -90.551503058999913, -0.292738539999959 ], [ -90.558176235999952, -0.310804945999962 ], [ -90.586781378999945, -0.363702080999929 ], [ -90.604888475999928, -0.369805596999925 ], [ -90.740061001999948, -0.353936455999929 ], [ -90.795887824999909, -0.330661716999941 ], [ -90.818226691999939, -0.339613539999959 ], [ -90.848947719999899, -0.275648695999962 ], [ -90.874134894999941, -0.271254164999959 ], [ -90.831654425999943, -0.212660414999959 ], [ -90.82681230399993, -0.164157809999949 ], [ -90.777251756999931, -0.14771900799991 ], [ -90.632476365999935, -0.201267184999949 ], [ -90.551991339999915, -0.278090101999908 ], [ -90.565012173999946, -0.284926039999959 ] ] ], [ [ [ -90.811431443999936, -0.730645440999922 ], [ -90.791574673999946, -0.754001559999949 ], [ -90.829090949999909, -0.77467213299991 ], [ -90.860463019999941, -0.872653903999947 ], [ -90.858631964999915, -0.915459893999923 ], [ -90.880279100999928, -0.908786716999941 ], [ -90.928700324999909, -0.970310153999947 ], [ -90.993885870999918, -0.963474216999941 ], [ -91.159779425999943, -1.030205987999921 ], [ -91.399728969999899, -1.018487237999921 ], [ -91.43586178299995, -0.997491143999923 ], [ -91.445790167999917, -0.941501559999949 ], [ -91.477406378999945, -0.935479424999926 ], [ -91.502308722999942, -0.896254164999959 ], [ -91.465891079999949, -0.80787525799991 ], [ -91.310454881999931, -0.68328215899993 ], [ -91.234771287999934, -0.661879164999959 ], [ -91.157785610999895, -0.678806247999944 ], [ -91.086781378999945, -0.582452080999929 ], [ -91.106841600999928, -0.558689059999949 ], [ -91.161488410999937, -0.538262627999927 ], [ -91.208892381999931, -0.484633070999962 ], [ -91.238677537999934, -0.376153252999927 ], [ -91.374989386999914, -0.281914971999925 ], [ -91.373768683999913, -0.250176690999922 ], [ -91.40648352799991, -0.216403903999947 ], [ -91.40453040299991, -0.195896091999941 ], [ -91.380604620999918, -0.18873463299991 ], [ -91.405751105999911, -0.148044528999947 ], [ -91.423329230999911, -0.02857838299991 ], [ -91.476429816999939, -0.01108163899994 ], [ -91.563099738999938, -0.051771742999961 ], [ -91.603382941999939, -0.01421477699995 ], [ -91.604359503999945, 0.001450914000088 ], [ -91.504465298999946, 0.066148179000038 ], [ -91.497303839999915, 0.10610586100006 ], [ -91.452748175999943, 0.103745835000041 ], [ -91.368763800999943, 0.150620835000041 ], [ -91.339670376999948, 0.153794664000088 ], [ -91.323638475999928, 0.13930898600006 ], [ -91.28351803299995, 0.033189195000091 ], [ -91.247425910999937, -0.003838799999926 ], [ -91.20929928299995, -0.010674737999921 ], [ -91.173573370999918, -0.228448174999926 ], [ -91.128041144999941, -0.27076588299991 ], [ -91.124134894999941, -0.299574476999908 ], [ -91.005034959999932, -0.373142184999949 ], [ -90.956044074999909, -0.422133070999962 ], [ -90.949208136999914, -0.521416924999926 ], [ -90.990142381999931, -0.579196872999944 ], [ -90.967844204999949, -0.564548434999949 ], [ -90.956044074999909, -0.60711028399993 ], [ -90.892974412999934, -0.625746351999908 ], [ -90.894602016999897, -0.64812590899993 ], [ -90.859730597999942, -0.664157809999949 ], [ -90.859852667999917, -0.689629815999922 ], [ -90.811431443999936, -0.730645440999922 ] ] ], [ [ [ -90.513783331999946, 0.28351471600007 ], [ -90.544545050999943, 0.31085846600007 ], [ -90.542307094999899, 0.333563544000071 ], [ -90.504465298999946, 0.361029364000046 ], [ -90.436431443999936, 0.346625067000048 ], [ -90.407948370999918, 0.31085846600007 ], [ -90.454579230999911, 0.267401434000078 ], [ -90.513783331999946, 0.28351471600007 ] ] ], [ [ [ -90.797759568999936, 0.653509833000044 ], [ -90.756988084999932, 0.630601304000038 ], [ -90.744496222999942, 0.58539459800005 ], [ -90.760568813999896, 0.553697007000039 ], [ -90.805246548999946, 0.571600653000075 ], [ -90.797759568999936, 0.653509833000044 ] ] ], [ [ [ -91.819162563999896, 1.386419989000046 ], [ -91.810943162999934, 1.377183335000041 ], [ -91.817738410999937, 1.368068752000056 ], [ -91.825306769999941, 1.377020575000074 ], [ -91.819162563999896, 1.386419989000046 ] ] ], [ [ [ -91.822010870999918, 1.394476630000042 ], [ -91.817534959999932, 1.394761460000041 ], [ -91.820464647999927, 1.39134349200009 ], [ -91.822010870999918, 1.394476630000042 ] ] ], [ [ [ -92.011586066999939, 1.658636786000045 ], [ -92.00609290299991, 1.66437409100007 ], [ -91.999826626999948, 1.651190497000073 ], [ -92.006662563999896, 1.649603583000044 ], [ -92.011586066999939, 1.658636786000045 ] ] ], [ [ [ -89.957117753210582, 0.341870937337148 ], [ -89.936668733838701, 0.327995159529848 ], [ -89.944702239599451, 0.303895008840129 ], [ -89.952005426654637, 0.317770860016822 ], [ -89.970993712998279, 0.309737474712847 ], [ -89.957117753210582, 0.341870937337148 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-SE", "NAME_1": "Santa Elena" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -80.542747415450577, -2.52976243927536 ], [ -80.656646287999934, -2.415785414999959 ], [ -80.803456183999913, -2.374769789999959 ], [ -80.86392167899993, -2.329278252999927 ], [ -80.913644985999952, -2.318780205999929 ], [ -80.934803839999915, -2.260918877999927 ], [ -81.010894334999932, -2.176690362999921 ], [ -81.001210089999915, -2.164483330999929 ], [ -80.949330206999946, -2.186211846999925 ], [ -80.931286318999923, -2.217333015999941 ], [ -80.906342922999897, -2.216258380999932 ], [ -80.780702356999939, -2.142843412999923 ], [ -80.744979189999924, -2.102914607999935 ], [ -80.737446656999907, -2.043497173999924 ], [ -80.762521938999896, -1.97389088299991 ], [ -80.733185043999924, -1.953769676999912 ], [ -80.733021613999938, -1.90398528399993 ], [ -80.782134568999936, -1.736993096999925 ], [ -80.818164557642575, -1.676979241717978 ], [ -80.624866502586997, -1.655867608003689 ], [ -80.563810797730127, -1.667339775510243 ], [ -80.539807094621722, -1.727387790913838 ], [ -80.561537034606431, -1.816994724227129 ], [ -80.516087613252751, -1.840817559282925 ], [ -80.478271172476639, -1.931161345819476 ], [ -80.288407472127119, -2.017346144708824 ], [ -80.213445776201581, -2.110307938660469 ], [ -80.232020041891417, -2.299776686444943 ], [ -80.276516835683424, -2.367938822418751 ], [ -80.41076665945377, -2.416674574272179 ], [ -80.542747415450577, -2.52976243927536 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-M", "NAME_1": "Manabi" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -80.818164557642575, -1.676979241717978 ], [ -80.855580206999946, -1.588311455999929 ], [ -80.816489555999908, -1.552254752999943 ], [ -80.82054602799991, -1.499932549999926 ], [ -80.770861664999927, -1.477829952999912 ], [ -80.764290159999916, -1.390887025999916 ], [ -80.74266293699992, -1.368161967999924 ], [ -80.744256335999921, -1.343773381999938 ], [ -80.882150844999899, -1.14576588299991 ], [ -80.916180217999909, -1.065524767999932 ], [ -80.909610914999917, -1.044915051999908 ], [ -80.816365198999904, -0.946343556999921 ], [ -80.722245176999934, -0.931125513999916 ], [ -80.690874930999939, -0.949588742999936 ], [ -80.653041719999919, -0.923064662999934 ], [ -80.616320398999903, -0.941408096999908 ], [ -80.569883134999941, -0.912242570999922 ], [ -80.547211961999949, -0.888489750999952 ], [ -80.497561625999936, -0.692437544999962 ], [ -80.448969096999917, -0.60606015299993 ], [ -80.421991646999913, -0.599599732999934 ], [ -80.405824602999928, -0.646034024999949 ], [ -80.37879806299992, -0.657885419999957 ], [ -80.299006949999921, -0.66222862099994 ], [ -80.298996049999914, -0.650355188999924 ], [ -80.391737228999943, -0.625486672999955 ], [ -80.437125419999916, -0.557538114999943 ], [ -80.452056443999936, -0.476739190999922 ], [ -80.496463547999952, -0.381374052999945 ], [ -80.432724739999912, -0.339187023999955 ], [ -80.371232334999945, -0.222830502999955 ], [ -80.349658206999948, -0.215264482999942 ], [ -80.323695251999936, -0.173172607999959 ], [ -80.305350455999928, -0.189366935999942 ], [ -80.231847859999903, -0.139698740999961 ], [ -80.107899542999917, 0.007066148000092 ], [ -80.098784959999932, 0.039211330000057 ], [ -80.066458956999952, 0.052209779000066 ], [ -80.036976691999939, 0.175970770000049 ], [ -80.048491990999935, 0.318304755000042 ], [ -80.036529100999928, 0.357082424000055 ], [ -80.012684699999909, 0.32453034100007 ], [ -79.999521235313509, 0.345101779873908 ], [ -79.961211920993321, 0.266082261886879 ], [ -79.933435838892819, 0.259674384565187 ], [ -79.889665899661509, 0.318688870295091 ], [ -79.814580044233651, 0.322667954862197 ], [ -79.75269751707674, 0.369280097098795 ], [ -79.717583380768417, 0.370778712967194 ], [ -79.695595059264576, 0.347110907542344 ], [ -79.71223486974344, 0.303651028472189 ], [ -79.652186856138485, 0.259157619728342 ], [ -79.702106289373717, 0.187430732142559 ], [ -79.682133347675858, 0.170429185558476 ], [ -79.659602423812771, 0.175958563736742 ], [ -79.649938931436509, 0.145676174515813 ], [ -79.623945686044578, 0.15389272696774 ], [ -79.567850917685689, 0.116530666856761 ], [ -79.619010586169622, 0.042116604097998 ], [ -79.595549486319726, -0.013590589733951 ], [ -79.607305873767018, -0.040824069475264 ], [ -79.598753425430232, -0.07177825316387 ], [ -79.496692470880816, -0.161850273571304 ], [ -79.411426358239851, -0.188101902280948 ], [ -79.410263638256311, -0.398269951696932 ], [ -79.449072639190945, -0.462297051667633 ], [ -79.536044074174697, -0.691016941278804 ], [ -79.578728806888932, -0.723108004730648 ], [ -79.619630702894597, -0.850232028685184 ], [ -79.722363451012427, -0.881237887418592 ], [ -79.841451788769007, -1.074817804098416 ], [ -79.904367844700232, -1.129749850675069 ], [ -79.969738531807764, -1.139775079156607 ], [ -79.977334968434036, -1.114712008852109 ], [ -79.993096279769475, -1.128819674688259 ], [ -80.043299933844878, -1.271808362765739 ], [ -80.124328578601023, -1.333975111662085 ], [ -80.130891485553605, -1.397743829214335 ], [ -80.191973028832194, -1.431178480702329 ], [ -80.201636522107776, -1.480684502787597 ], [ -80.188174812317698, -1.536546726250435 ], [ -80.222048713377433, -1.559439386218685 ], [ -80.283259446965872, -1.567655937771349 ], [ -80.267911546780454, -1.59519947677444 ], [ -80.226001960422138, -1.61891895904273 ], [ -80.221170214234007, -1.680672295889735 ], [ -80.299744228713166, -1.697622165630435 ], [ -80.329303148421559, -1.687131850054868 ], [ -80.396069098609985, -1.746198011728893 ], [ -80.437539436295936, -1.835701593153999 ], [ -80.516087613252751, -1.840817559282925 ], [ -80.552803718217035, -1.828105156527783 ], [ -80.562880621743261, -1.798029472881865 ], [ -80.539807094621722, -1.727387790913838 ], [ -80.577401699628695, -1.65974334068261 ], [ -80.818164557642575, -1.676979241717978 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-A", "NAME_1": "Azuay" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -79.437393765210061, -2.497056573202315 ], [ -79.388120287121524, -2.507753595252211 ], [ -79.349233770921785, -2.569972019193358 ], [ -79.29399166508324, -2.588007093652436 ], [ -79.163612026973453, -2.731667576197708 ], [ -79.142579718978823, -2.728515313031266 ], [ -79.137928839943982, -2.703297213995256 ], [ -79.078707647739748, -2.650845636117197 ], [ -79.060517543649723, -2.654256279903393 ], [ -78.951041022325285, -2.762156670993591 ], [ -78.915151739661042, -2.822514743860324 ], [ -78.816191372333947, -2.822514743860324 ], [ -78.784229499192008, -2.699628187790665 ], [ -78.725576747768685, -2.690998223289398 ], [ -78.638011033582302, -2.644024346746221 ], [ -78.610674201053541, -2.59736052766624 ], [ -78.564423794022844, -2.561600437110485 ], [ -78.549101732259146, -2.562944024247315 ], [ -78.554036831234782, -2.602269789119475 ], [ -78.533314581602667, -2.62392221383908 ], [ -78.480707974093718, -2.568111667219682 ], [ -78.421357590680259, -2.618496188448376 ], [ -78.436783006130838, -2.645264581095546 ], [ -78.557705858338693, -2.709963473735343 ], [ -78.597470872782537, -2.779158216678354 ], [ -78.56992733377939, -2.839206231182629 ], [ -78.656097784884878, -3.008446547070491 ], [ -78.671652390645306, -3.090767103918722 ], [ -78.937579311635886, -3.287809339429486 ], [ -78.938974575616157, -3.3227426076852 ], [ -79.055091519158282, -3.412246189110363 ], [ -79.05023393364911, -3.552134290864842 ], [ -79.065478481946343, -3.619417005890114 ], [ -79.084676276389018, -3.633317966151253 ], [ -79.102246262854749, -3.636005140424913 ], [ -79.120436366944773, -3.610942071019792 ], [ -79.123356086114484, -3.557043551418758 ], [ -79.178779060005581, -3.448161309297006 ], [ -79.236553311386217, -3.4607703592647 ], [ -79.281692674377382, -3.449918307583857 ], [ -79.317866176982477, -3.346772149215326 ], [ -79.43258785744365, -3.338090508769994 ], [ -79.507932095289959, -3.312975762521432 ], [ -79.614850632650587, -3.329873955418691 ], [ -79.667767300320634, -3.319848727836529 ], [ -79.626891241837313, -3.281608167682805 ], [ -79.595161912692106, -3.174999687785373 ], [ -79.638518438974756, -3.128852633542238 ], [ -79.760474819956983, -3.06467050483991 ], [ -79.74884762192022, -3.023691094468461 ], [ -79.69484575133032, -2.957131849854989 ], [ -79.703579067719772, -2.874966321738384 ], [ -79.690556606602115, -2.825718682071511 ], [ -79.424836392085808, -2.555347588520419 ], [ -79.417162441993071, -2.534160250894899 ], [ -79.437393765210061, -2.497056573202315 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-F", "NAME_1": "Cañar" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -79.1529150049235, -2.735026544039783 ], [ -79.29399166508324, -2.588007093652436 ], [ -79.349233770921785, -2.569972019193358 ], [ -79.388120287121524, -2.507753595252211 ], [ -79.437393765210061, -2.497056573202315 ], [ -79.489741991199935, -2.51777882193511 ], [ -79.512867194265596, -2.508838799970647 ], [ -79.514314134189931, -2.495196222127959 ], [ -79.425146451347644, -2.421815688143511 ], [ -79.425663215285169, -2.360734144864921 ], [ -79.364788377581533, -2.308540947606673 ], [ -79.192008225798986, -2.266941419610816 ], [ -79.130074021798634, -2.203689466895412 ], [ -79.116741503217781, -2.245030612472817 ], [ -79.028374803354495, -2.345127862261052 ], [ -78.945072394575334, -2.397372734564044 ], [ -78.862441779364588, -2.389983005311478 ], [ -78.762034471213838, -2.325955906240097 ], [ -78.598762783975303, -2.302546481435002 ], [ -78.481224738031244, -2.380681248141116 ], [ -78.490242276160075, -2.505893243278535 ], [ -78.517708298998798, -2.549663180711207 ], [ -78.600545619784498, -2.586611829672222 ], [ -78.638011033582302, -2.644024346746221 ], [ -78.725576747768685, -2.690998223289398 ], [ -78.784229499192008, -2.699628187790665 ], [ -78.816191372333947, -2.822514743860324 ], [ -78.930008714330711, -2.817088717570243 ], [ -78.951041022325285, -2.762156670993591 ], [ -79.072041388898981, -2.649967136074451 ], [ -79.132347784922331, -2.696992689461069 ], [ -79.1529150049235, -2.735026544039783 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-N", "NAME_1": "Napo" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -78.391436936665286, -0.963558445166143 ], [ -78.331673143001126, -1.059831638219521 ], [ -78.34508317684714, -1.164269707780818 ], [ -78.291933966979002, -1.140240167150012 ], [ -78.221524828108329, -1.139981784731617 ], [ -78.175791185015157, -1.184165134213572 ], [ -78.119696417555588, -1.200649915960867 ], [ -78.114167040276698, -1.342553398420591 ], [ -78.148170131646225, -1.424357192230673 ], [ -78.201655240097239, -1.474483331040915 ], [ -78.30653255923022, -1.484560234567198 ], [ -78.353377244564172, -1.526366469037328 ], [ -78.36893185122392, -1.493190199068465 ], [ -78.480087857368687, -1.440583590660196 ], [ -78.515434535875102, -1.480116062006687 ], [ -78.619717576704772, -1.489831231226333 ], [ -78.698575812024103, -1.478100681301385 ], [ -78.799964973005103, -1.424357192230673 ], [ -78.880735236242117, -1.459238782743626 ], [ -78.927554084053725, -1.383171074485517 ], [ -78.866239996778404, -1.17832569677347 ], [ -78.76691789424541, -1.131765232279633 ], [ -78.661239590334787, -1.138534844807225 ], [ -78.575120816072797, -1.102774752452888 ], [ -78.553287523300526, -1.060916842937957 ], [ -78.467840541707631, -1.080502211008252 ], [ -78.434380051797916, -1.044432061190662 ], [ -78.419988166021028, -0.988156426577859 ], [ -78.391436936665286, -0.963558445166143 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-T", "NAME_1": "Tungurahua" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -78.338571946737943, -1.164373060568323 ], [ -78.335729742833337, -1.045207207546582 ], [ -78.391436936665286, -0.963558445166143 ], [ -78.441537237953128, -0.938133639655746 ], [ -78.387793748882416, -0.813800143661695 ], [ -78.405053676985574, -0.710240574143199 ], [ -78.396759610167862, -0.684350680639398 ], [ -78.329657762295881, -0.660424492796096 ], [ -78.310873379003226, -0.598464451273401 ], [ -78.262297532904824, -0.531440117767204 ], [ -78.237467006597058, -0.452840263967005 ], [ -78.24565772242596, -0.399923598095597 ], [ -78.187444220574321, -0.296467379565911 ], [ -78.177263964260533, -0.180867200860632 ], [ -78.126801926867415, -0.169395032454815 ], [ -78.095175951409033, -0.184432875177038 ], [ -78.056909552833588, -0.132704765912251 ], [ -78.013139615400917, -0.135960381866141 ], [ -77.980350918160354, -0.100562025617023 ], [ -77.964486254037354, -0.047800387577809 ], [ -77.857025113418217, 0.001395575245567 ], [ -77.832685512626313, 0.031936346884891 ], [ -77.778942022656224, 0.015813300343552 ], [ -77.772120734184512, -0.066197198142163 ], [ -77.740288052251799, -0.078392836060573 ], [ -77.64086259603198, -0.081028333490792 ], [ -77.588979458035567, -0.100045260780178 ], [ -77.46487850603819, -0.023460788584543 ], [ -77.44392371330872, -0.060409437545502 ], [ -77.446455857951491, -0.124849948666224 ], [ -77.391058723381377, -0.139422702495722 ], [ -77.349975959323046, -0.131619561193816 ], [ -77.299410570041744, -0.058549085571826 ], [ -77.297911953274024, -0.19027231171782 ], [ -77.257681850836718, -0.25326588291415 ], [ -77.254503750147933, -0.309438164739504 ], [ -77.273184780653082, -0.360391126749107 ], [ -77.32323340509754, -0.387417900915409 ], [ -77.329047004115921, -0.424056491513909 ], [ -77.356564703798028, -0.425658461069133 ], [ -77.404029506756331, -0.504154962081827 ], [ -77.448006150663332, -0.507823988286418 ], [ -77.551539882659426, -0.458007907838692 ], [ -77.566474371694881, -0.49573170315557 ], [ -77.620166184821585, -0.536607760739571 ], [ -77.618796760162354, -0.552885836911855 ], [ -77.575285204248758, -0.577018731229487 ], [ -77.509707810666896, -0.655721937817191 ], [ -77.496607836082774, -0.69137867558544 ], [ -77.533272264203617, -0.780778904223041 ], [ -77.528466356437207, -0.841188653033896 ], [ -77.579109260084294, -0.940045667573486 ], [ -77.49921749509133, -0.945316664232678 ], [ -77.254994675663738, -0.833850599725395 ], [ -77.209545254310001, -0.764707532726447 ], [ -77.16481930156948, -0.722797947267452 ], [ -77.124201626403931, -0.707915134176119 ], [ -77.1186205722816, -0.730342706150964 ], [ -77.187711962437106, -0.803361504929512 ], [ -77.192466193360133, -0.852247410289749 ], [ -77.113995530769103, -0.904233901073667 ], [ -77.036144985802423, -0.925214532224913 ], [ -77.061879848775959, -0.963713473897712 ], [ -77.04283708396423, -0.987949721002849 ], [ -77.051647914719467, -1.010377292078374 ], [ -77.233755662993417, -1.024536634757908 ], [ -77.373023648022922, -1.079313652602991 ], [ -77.445525681964625, -1.087323499479908 ], [ -77.547069871677195, -1.13574431684674 ], [ -77.695613776354662, -1.151660657813125 ], [ -77.831109382392071, -1.221837252687067 ], [ -77.882062344401675, -1.214085789127864 ], [ -77.897177699691099, -1.23713347692842 ], [ -77.941955329275004, -1.223852634291632 ], [ -78.116518316866802, -1.23330942109294 ], [ -78.126801926867415, -1.194087009008285 ], [ -78.175791185015157, -1.184165134213572 ], [ -78.221524828108329, -1.139981784731617 ], [ -78.291933966979002, -1.140240167150012 ], [ -78.338571946737943, -1.164373060568323 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-H", "NAME_1": "Chimborazo" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -78.922334764237974, -2.40036996809954 ], [ -79.028374803354495, -2.345127862261052 ], [ -79.116741503217781, -2.245030612472817 ], [ -79.130074021798634, -2.203689466895412 ], [ -79.076330532727866, -2.175164075961334 ], [ -79.016360032589432, -2.09878630844139 ], [ -79.02558427629333, -2.046903170444978 ], [ -78.999591030901342, -1.918280530621985 ], [ -79.001709764394093, -1.781854749497086 ], [ -78.975199755064637, -1.760512384039316 ], [ -78.925667893658328, -1.752089125113059 ], [ -78.859754605090927, -1.663929131724046 ], [ -78.852649094879837, -1.540887546023441 ], [ -78.880735236242117, -1.459238782743626 ], [ -78.799964973005103, -1.424357192230673 ], [ -78.698575812024103, -1.478100681301385 ], [ -78.619717576704772, -1.489831231226333 ], [ -78.515434535875102, -1.480116062006687 ], [ -78.480087857368687, -1.440583590660196 ], [ -78.36893185122392, -1.493190199068465 ], [ -78.353377244564172, -1.526366469037328 ], [ -78.36531450096345, -1.549879245730608 ], [ -78.355651007687868, -1.612872816926995 ], [ -78.450167201555075, -1.717310885588915 ], [ -78.415647346248022, -1.854356785237485 ], [ -78.489544644169996, -1.964840996914461 ], [ -78.445800544259669, -2.075221855803989 ], [ -78.500577562104809, -2.127104993800458 ], [ -78.497812872565987, -2.210510756266387 ], [ -78.530162320234865, -2.240379733437976 ], [ -78.544631721276915, -2.286888522887011 ], [ -78.579900886316864, -2.311538181142168 ], [ -78.598762783975303, -2.302546481435002 ], [ -78.762034471213838, -2.325955906240097 ], [ -78.862441779364588, -2.389983005311478 ], [ -78.922334764237974, -2.40036996809954 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-B", "NAME_1": "Bolivar" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -78.866239996778404, -1.17832569677347 ], [ -78.927554084053725, -1.383171074485517 ], [ -78.852649094879837, -1.540887546023441 ], [ -78.859754605090927, -1.663929131724046 ], [ -78.925667893658328, -1.752089125113059 ], [ -78.975199755064637, -1.760512384039316 ], [ -79.001709764394093, -1.781854749497086 ], [ -78.999591030901342, -1.918280530621985 ], [ -79.02558427629333, -2.046903170444978 ], [ -79.016360032589432, -2.09878630844139 ], [ -79.076330532727866, -2.175164075961334 ], [ -79.130074021798634, -2.203689466895412 ], [ -79.139944220649227, -2.146535333139127 ], [ -79.17164771227209, -2.16198658611205 ], [ -79.235493944190182, -2.154338473541713 ], [ -79.205521613331769, -2.065041598590938 ], [ -79.279496425619527, -1.944893893638266 ], [ -79.258515795367657, -1.923086440187092 ], [ -79.22944780117507, -1.822937513555416 ], [ -79.252133754669046, -1.774878432293804 ], [ -79.250376756382195, -1.736172784146675 ], [ -79.299262660843112, -1.659588311051721 ], [ -79.343859423273727, -1.63834929748208 ], [ -79.292415533949736, -1.585277601979783 ], [ -79.266422288557749, -1.585794365917252 ], [ -79.2500925364414, -1.540887546023441 ], [ -79.318512132129172, -1.468023776875839 ], [ -79.318951381700913, -1.359244886642216 ], [ -79.292182989953005, -1.33444019875617 ], [ -79.337348192265267, -1.291135348417583 ], [ -79.377836677120911, -1.325913587941727 ], [ -79.385975715207053, -1.305656427202337 ], [ -79.327839727721255, -1.225196221428462 ], [ -79.137773811212412, -1.156208184060461 ], [ -79.082066617380463, -1.154916273767014 ], [ -78.990909389556691, -1.209279879562814 ], [ -78.951221890377951, -1.203440443921352 ], [ -78.906935187209115, -1.171556085145198 ], [ -78.866239996778404, -1.17832569677347 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-I", "NAME_1": "Imbabura" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -77.814081997386268, 0.345663966718689 ], [ -77.852477587170881, 0.29264394805972 ], [ -77.835501879008518, 0.26918284731056 ], [ -77.94536597396052, 0.161282457119682 ], [ -78.077683478409767, 0.197766018087236 ], [ -78.202172004034765, 0.134720770946785 ], [ -78.254881965230481, 0.142162177042849 ], [ -78.320330165804478, 0.188515936860995 ], [ -78.365366176907514, 0.16665680656638 ], [ -78.360689460350329, 0.217713121363431 ], [ -78.38670854416398, 0.242311102775147 ], [ -78.63106055390142, 0.215025946190451 ], [ -78.778105841811112, 0.239313870138972 ], [ -78.951661139949636, 0.211305243142419 ], [ -78.993854947148066, 0.228875230507469 ], [ -79.01070146410126, 0.267425849023709 ], [ -78.982847866735653, 0.271043199284236 ], [ -78.902465176226883, 0.386695054832899 ], [ -78.859961310665938, 0.422816881493873 ], [ -78.719608120018734, 0.402714749486108 ], [ -78.667414923659805, 0.372949124202705 ], [ -78.539205694986833, 0.51505931223744 ], [ -78.497399462315343, 0.542137763247183 ], [ -78.431176113586787, 0.55133616852936 ], [ -78.424225633006529, 0.586217759941633 ], [ -78.513444993591577, 0.759902249289382 ], [ -78.450632290447857, 0.789047756049115 ], [ -78.442105678734094, 0.871936754577575 ], [ -78.360301886722652, 0.852816474500685 ], [ -78.258421800225904, 0.775405178206427 ], [ -78.168608161337545, 0.651381741474154 ], [ -78.130806850755562, 0.505602525436188 ], [ -78.000453050168119, 0.46865387647523 ], [ -77.814081997386268, 0.345663966718689 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-X", "NAME_1": "Cotopaxi" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -78.396759610167862, -0.684350680639398 ], [ -78.39110103988105, -0.83281707095108 ], [ -78.441537237953128, -0.938133639655746 ], [ -78.391436936665286, -0.963558445166143 ], [ -78.419988166021028, -0.988156426577859 ], [ -78.455438199113587, -1.074766127254975 ], [ -78.492438524018667, -1.082259210194422 ], [ -78.553287523300526, -1.060916842937957 ], [ -78.575120816072797, -1.102774752452888 ], [ -78.661239590334787, -1.138534844807225 ], [ -78.7860381743223, -1.135899346477686 ], [ -78.866239996778404, -1.17832569677347 ], [ -78.906935187209115, -1.171556085145198 ], [ -78.96848181758179, -1.208659762837783 ], [ -79.014783902355191, -1.202665296666112 ], [ -79.082066617380463, -1.154916273767014 ], [ -79.109455125853344, -1.152280775437418 ], [ -79.234537929781595, -1.199564711242431 ], [ -79.280710822446508, -1.202613620722047 ], [ -79.322982144010723, -1.120964857442232 ], [ -79.29071021160695, -0.914000746237434 ], [ -79.180613572658217, -0.785481459202003 ], [ -79.086820848303489, -0.551903984980925 ], [ -79.047236701012935, -0.585080254949844 ], [ -78.990806036769186, -0.531646824241534 ], [ -79.032353888820921, -0.475629571147806 ], [ -79.002691617224343, -0.418682142966532 ], [ -78.927218187269489, -0.347006930425493 ], [ -78.869805671094809, -0.425348402706618 ], [ -78.829446377448335, -0.515678805532445 ], [ -78.751957566788235, -0.572316176250524 ], [ -78.714052904318066, -0.65262135149419 ], [ -78.617986415940322, -0.606732679669449 ], [ -78.589874437055585, -0.621667168704903 ], [ -78.552434861679501, -0.603477064614822 ], [ -78.489854701633135, -0.604355563758247 ], [ -78.396759610167862, -0.684350680639398 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-R", "NAME_1": "Los Rios" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -79.280710822446508, -1.202613620722047 ], [ -79.327839727721255, -1.225196221428462 ], [ -79.388378668640655, -1.31805876979638 ], [ -79.369697639034825, -1.322089532106247 ], [ -79.337348192265267, -1.291135348417583 ], [ -79.292182989953005, -1.33444019875617 ], [ -79.318951381700913, -1.359244886642216 ], [ -79.318512132129172, -1.468023776875839 ], [ -79.2500925364414, -1.540887546023441 ], [ -79.266422288557749, -1.585794365917252 ], [ -79.292415533949736, -1.585277601979783 ], [ -79.343859423273727, -1.63834929748208 ], [ -79.299262660843112, -1.659588311051721 ], [ -79.250376756382195, -1.736172784146675 ], [ -79.252133754669046, -1.774878432293804 ], [ -79.22944780117507, -1.822937513555416 ], [ -79.258515795367657, -1.923086440187092 ], [ -79.279496425619527, -1.944893893638266 ], [ -79.205521613331769, -2.065041598590938 ], [ -79.235493944190182, -2.154338473541713 ], [ -79.285930142262259, -2.107674656260372 ], [ -79.372953254089396, -1.970111992674333 ], [ -79.482429776313097, -1.897454929101684 ], [ -79.523615892259613, -1.885155937496506 ], [ -79.649525520286545, -1.906549980697037 ], [ -79.758872850401701, -1.696691989643625 ], [ -79.862122361557738, -1.624189954802603 ], [ -79.855662808291981, -1.573495375211394 ], [ -79.870545619584675, -1.519028415728826 ], [ -79.847317063731509, -1.399139093194606 ], [ -79.748149990829404, -1.235169773066559 ], [ -79.741406215824213, -1.189126071610929 ], [ -79.686396653982399, -1.146648043572384 ], [ -79.673761765592985, -1.114298597702145 ], [ -79.580950894068508, -1.050633232937344 ], [ -79.561675585260048, -0.986709485754147 ], [ -79.53278845912007, -0.959527682856276 ], [ -79.523073289900367, -0.845271091287827 ], [ -79.619630702894597, -0.850232028685184 ], [ -79.58658362503428, -0.740264580945677 ], [ -79.539067145232536, -0.696753025032081 ], [ -79.479975145136848, -0.543739108473062 ], [ -79.341999071300108, -0.554229424948005 ], [ -79.357269457119742, -0.577173760860376 ], [ -79.34721839111586, -0.622132256698308 ], [ -79.360602587439416, -0.655721937817191 ], [ -79.350758226111225, -0.682490329565042 ], [ -79.316186693061411, -0.695874525888655 ], [ -79.289728359676019, -0.691998793209734 ], [ -79.205469937387704, -0.62931528127524 ], [ -79.13154680014469, -0.555521335241451 ], [ -79.086820848303489, -0.551903984980925 ], [ -79.166014981306319, -0.758919773029106 ], [ -79.281640998433318, -0.899427991508617 ], [ -79.303732672724664, -0.948882337649763 ], [ -79.322982144010723, -1.120964857442232 ], [ -79.280710822446508, -1.202613620722047 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-P", "NAME_1": "Pichincha" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -77.832685512626313, 0.031936346884891 ], [ -77.857025113418217, 0.001395575245567 ], [ -77.964486254037354, -0.047800387577809 ], [ -77.980350918160354, -0.100562025617023 ], [ -78.013139615400917, -0.135960381866141 ], [ -78.056909552833588, -0.132704765912251 ], [ -78.095175951409033, -0.184432875177038 ], [ -78.134682583434483, -0.169395032454815 ], [ -78.183206752689443, -0.18779184301917 ], [ -78.194187994680192, -0.319980157158511 ], [ -78.24565772242596, -0.399923598095597 ], [ -78.237467006597058, -0.452840263967005 ], [ -78.262297532904824, -0.531440117767204 ], [ -78.310873379003226, -0.598464451273401 ], [ -78.329657762295881, -0.660424492796096 ], [ -78.396759610167862, -0.684350680639398 ], [ -78.462078620431953, -0.61541432011478 ], [ -78.527035894590824, -0.602030124690486 ], [ -78.589874437055585, -0.621667168704903 ], [ -78.617986415940322, -0.606732679669449 ], [ -78.70756751173127, -0.65587696654876 ], [ -78.751957566788235, -0.572316176250524 ], [ -78.829446377448335, -0.515678805532445 ], [ -78.921585456303774, -0.345146580250514 ], [ -78.891159546076153, -0.297630224555235 ], [ -78.76438574600536, -0.284952844997804 ], [ -78.745369675769894, -0.215227254734032 ], [ -78.796079195798256, -0.15817904492701 ], [ -78.92285299586905, -0.075776075105807 ], [ -79.100336315968207, -0.082114764884523 ], [ -79.106675005746922, 0.00028820493668 ], [ -79.309513085860203, 0.006626895614716 ], [ -79.363832364072323, 0.046922511864409 ], [ -79.303655158358879, 0.173271389463025 ], [ -79.3522310053566, 0.231665758467955 ], [ -79.221877203869838, 0.31558828397209 ], [ -79.195134649644331, 0.318895574970782 ], [ -79.040208706066892, 0.295021063970921 ], [ -78.993854947148066, 0.228875230507469 ], [ -78.951661139949636, 0.211305243142419 ], [ -78.778105841811112, 0.239313870138972 ], [ -78.63106055390142, 0.215025946190451 ], [ -78.38670854416398, 0.242311102775147 ], [ -78.360689460350329, 0.217713121363431 ], [ -78.365366176907514, 0.16665680656638 ], [ -78.320330165804478, 0.188515936860995 ], [ -78.226769986345801, 0.13327383102245 ], [ -78.175016038659237, 0.140715237118513 ], [ -78.077683478409767, 0.197766018087236 ], [ -77.94536597396052, 0.161282457119682 ], [ -77.970429043365641, 0.115342109350877 ], [ -77.863898077833994, 0.074155992505041 ], [ -77.832685512626313, 0.031936346884891 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "EC-SD", "NAME_1": "Santo Domingo de los Tsáchilas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -78.921585456303774, -0.345146580250514 ], [ -79.002691617224343, -0.418682142966532 ], [ -79.032353888820921, -0.475629571147806 ], [ -78.990806036769186, -0.531646824241534 ], [ -79.020054898115063, -0.546167901227648 ], [ -79.037030606277426, -0.580842787064967 ], [ -79.061912807629938, -0.582548110307073 ], [ -79.086820848303489, -0.551903984980925 ], [ -79.115449592025016, -0.546839694796063 ], [ -79.289728359676019, -0.691998793209734 ], [ -79.340784675372447, -0.68905323561836 ], [ -79.360602587439416, -0.655721937817191 ], [ -79.34721839111586, -0.622132256698308 ], [ -79.357269457119742, -0.577173760860376 ], [ -79.341999071300108, -0.554229424948005 ], [ -79.479975145136848, -0.543739108473062 ], [ -79.406930507936579, -0.383438815448983 ], [ -79.411426358239851, -0.188101902280948 ], [ -79.496692470880816, -0.161850273571304 ], [ -79.598753425430232, -0.07177825316387 ], [ -79.603430141987474, -0.022530612597677 ], [ -79.575214810315231, -0.012350356283946 ], [ -79.492997606254505, -0.025631198920678 ], [ -79.43315629822456, -0.050125827544889 ], [ -79.420702276988493, -0.03338266427852 ], [ -79.450364548585014, -0.000929863822194 ], [ -79.383546923351844, 0.022479560083639 ], [ -79.363832364072323, 0.046922511864409 ], [ -79.309513085860203, 0.006626895614716 ], [ -79.106675005746922, 0.00028820493668 ], [ -79.100336315968207, -0.082114764884523 ], [ -78.92285299586905, -0.075776075105807 ], [ -78.796079195798256, -0.15817904492701 ], [ -78.745369675769894, -0.215227254734032 ], [ -78.76438574600536, -0.284952844997804 ], [ -78.891159546076153, -0.297630224555235 ], [ -78.921585456303774, -0.345146580250514 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/el salvador.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/el salvador.geojson new file mode 100644 index 0000000000000..14639b3160446 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/el salvador.geojson @@ -0,0 +1,20 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "SV-AH", "NAME_1": "Ahuachapán" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.098306575132682, 13.731404008980572 ], [ -90.114313924999891, 13.796264954000023 ], [ -90.114779011999929, 13.81200042800009 ], [ -90.112298542999866, 13.828252666000111 ], [ -90.106975870999918, 13.844065654000104 ], [ -90.09904353899995, 13.85850921600013 ], [ -90.087080443999895, 13.870472310000082 ], [ -90.059640258999934, 13.884709167000054 ], [ -90.0473671069999, 13.894295146000061 ], [ -90.038091186999878, 13.908376974000078 ], [ -90.031476602999902, 13.922923889000032 ], [ -90.022975830999883, 13.936954041000135 ], [ -90.008170532999941, 13.949692281000097 ], [ -89.912078206999951, 14.015192159 ], [ -89.890787516999865, 14.035888570000026 ], [ -89.880116332999961, 14.042684021000071 ], [ -89.835855468999938, 14.059091289000037 ], [ -89.821101846999937, 14.060073141000089 ], [ -89.802963419999912, 14.055473938000134 ], [ -89.776944335999929, 14.0357852180001 ], [ -89.762268229999847, 14.029997457000121 ], [ -89.747643798999974, 14.037645569000105 ], [ -89.747256225999962, 14.04320078500011 ], [ -89.7480100679999, 14.044894904000031 ], [ -89.739658983075572, 14.041468817831685 ], [ -89.721572231773052, 14.030332546210047 ], [ -89.717903204669142, 14.027309475152151 ], [ -89.716197883225732, 14.025216580081064 ], [ -89.71498348729807, 14.02302033132321 ], [ -89.7128389153836, 14.014907130759468 ], [ -89.711805385709965, 14.012504177325923 ], [ -89.710332608263229, 14.010333766989731 ], [ -89.70671525800276, 14.006897283882552 ], [ -89.702658658170549, 14.003848375302255 ], [ -89.699041307010702, 14.000231025041785 ], [ -89.698963792644918, 13.999998481045054 ], [ -89.696819220730447, 13.996096909944413 ], [ -89.695863207221237, 13.993719794033268 ], [ -89.698808763013972, 13.975839749205022 ], [ -89.718833380655951, 13.908970445329771 ], [ -89.736584235174291, 13.901709906387055 ], [ -89.758546719155731, 13.895792955480488 ], [ -89.770716518652421, 13.893984280350253 ], [ -89.773481208191185, 13.892149765898978 ], [ -89.775625780105656, 13.889281724471971 ], [ -89.776633469558931, 13.882899685571999 ], [ -89.776866013555662, 13.878662217687179 ], [ -89.774488897644517, 13.859955348760309 ], [ -89.772835253044491, 13.854141751540567 ], [ -89.771000738593216, 13.849594224393911 ], [ -89.768649462003054, 13.844995022202511 ], [ -89.767745124437909, 13.84266958313475 ], [ -89.768339402741219, 13.83920726250517 ], [ -89.788699917167435, 13.809028225172426 ], [ -89.79056026914111, 13.803602199781665 ], [ -89.79110287060098, 13.799597275893575 ], [ -89.782653775051642, 13.773604031400907 ], [ -89.781594407855607, 13.768048813901601 ], [ -89.782963833414158, 13.764095566856895 ], [ -89.785935227628613, 13.759341335933868 ], [ -89.793531664254886, 13.750608017745833 ], [ -89.796451381625957, 13.745207830776735 ], [ -89.798053352080501, 13.74091868694785 ], [ -89.798621791962091, 13.731720282564993 ], [ -89.799448615161452, 13.729188137022902 ], [ -89.81226436980478, 13.70676056594732 ], [ -89.814098884256111, 13.701928818859869 ], [ -89.819757452744227, 13.679682114937634 ], [ -89.824770066984968, 13.677718411075773 ], [ -89.833064133802736, 13.676659043879738 ], [ -89.863243171135423, 13.678338527800804 ], [ -89.869418505359704, 13.679604600571849 ], [ -89.871408046743966, 13.6809740261304 ], [ -89.878668585686682, 13.687717800236271 ], [ -89.891768562069444, 13.702419745274995 ], [ -89.893758104353026, 13.704047553251939 ], [ -89.897892218551021, 13.706838080313162 ], [ -89.900295172883887, 13.707923285031541 ], [ -89.902982347157604, 13.708853461018407 ], [ -89.906522183052289, 13.709241033746707 ], [ -89.910552945362099, 13.709241033746707 ], [ -89.916289029115376, 13.708207505871712 ], [ -89.919622159435107, 13.70714813957494 ], [ -89.922593552750243, 13.70580455243811 ], [ -89.925022346404148, 13.704176744461165 ], [ -89.927838710987714, 13.701851305393404 ], [ -89.935331793927105, 13.693143826526352 ], [ -89.951222297371089, 13.668778388212047 ], [ -89.953482681905044, 13.665072624253359 ], [ -90.021170746999928, 13.695175041000084 ], [ -90.098306575132682, 13.731404008980572 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-SA", "NAME_1": "Santa Ana" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.7480100679999, 14.044894904000031 ], [ -89.754465087999932, 14.059401347000104 ], [ -89.755446939999899, 14.067075297000102 ], [ -89.752604736999928, 14.075240174000029 ], [ -89.709868326999896, 14.148724060000077 ], [ -89.689843709999963, 14.170014750000064 ], [ -89.664625610999906, 14.188850810000091 ], [ -89.638322306999868, 14.200555522000073 ], [ -89.530938679999906, 14.225566915000059 ], [ -89.524504964999949, 14.231768087000134 ], [ -89.524659993999876, 14.247374369000084 ], [ -89.527863931999946, 14.2514568080001 ], [ -89.540550496999913, 14.257606303000074 ], [ -89.544917155999883, 14.261817932000014 ], [ -89.546777506999888, 14.268329163000075 ], [ -89.54858618199998, 14.28359954900013 ], [ -89.549878092999933, 14.288276265 ], [ -89.555691690999907, 14.299024963000122 ], [ -89.558585571999913, 14.302823182000054 ], [ -89.564373331999974, 14.308145853000099 ], [ -89.571272135999948, 14.311143087000104 ], [ -89.592175252999937, 14.313830261000049 ], [ -89.598350586999914, 14.327989604000095 ], [ -89.592433634999907, 14.336387024000075 ], [ -89.582408406999974, 14.343363343000064 ], [ -89.576078043999956, 14.353130189000112 ], [ -89.578971923999944, 14.364783223000089 ], [ -89.586284139999918, 14.374679261000082 ], [ -89.590573283999902, 14.38597056100005 ], [ -89.584062052999911, 14.401809387000057 ], [ -89.569876871999867, 14.412015483000118 ], [ -89.555174926999968, 14.410826925 ], [ -89.544245361999913, 14.400052388000077 ], [ -89.541351480999907, 14.381526387000036 ], [ -89.527760579999921, 14.391060689000128 ], [ -89.503033406999918, 14.420051168000015 ], [ -89.496148129999909, 14.42289748400006 ], [ -89.485282551999887, 14.427389222000102 ], [ -89.469417886999878, 14.425373840000049 ], [ -89.458126586999896, 14.419586080000073 ], [ -89.446835286999942, 14.415529481000078 ], [ -89.431099812999946, 14.418707580000046 ], [ -89.40836218299998, 14.441522726000045 ], [ -89.398181925999921, 14.445372620000086 ], [ -89.396864176999969, 14.426045635000037 ], [ -89.391696533999948, 14.433719585000119 ], [ -89.390611328999881, 14.435993348000039 ], [ -89.361821562322675, 14.415505745792339 ], [ -89.36162084999998, 14.415477804000062 ], [ -89.346206290288023, 14.413075726263742 ], [ -89.308057421412855, 14.378502508783754 ], [ -89.301416999195112, 14.371319485106142 ], [ -89.300176764845787, 14.369407457188402 ], [ -89.296843635425432, 14.36186269830489 ], [ -89.292399461965601, 14.354602159362173 ], [ -89.290177374786026, 14.352405911503581 ], [ -89.286637538891284, 14.349692897908881 ], [ -89.271780565120991, 14.342070623760264 ], [ -89.2696101547848, 14.340365302316854 ], [ -89.264830085440053, 14.334138292148452 ], [ -89.24651079014086, 14.322846990895926 ], [ -89.259404060049292, 14.28664765076843 ], [ -89.263305630250613, 14.266519680338945 ], [ -89.272116461905171, 14.256959539850868 ], [ -89.309349330806981, 14.242257594812145 ], [ -89.30950436133719, 14.222258816491149 ], [ -89.30854834692866, 14.211200059235352 ], [ -89.30893591965696, 14.207427680243256 ], [ -89.3108479475747, 14.202750962786695 ], [ -89.330200771648265, 14.176602687763818 ], [ -89.333740606643687, 14.173243719921743 ], [ -89.335704312304131, 14.171822618419071 ], [ -89.338029751371892, 14.170530707226362 ], [ -89.340484381648878, 14.169600531239496 ], [ -89.343274908710043, 14.168825384883576 ], [ -89.346375495033044, 14.16833445936777 ], [ -89.356659105033657, 14.167714341743476 ], [ -89.359294603363253, 14.167326768115856 ], [ -89.362007616058634, 14.1665774601816 ], [ -89.364410570391499, 14.165543932306605 ], [ -89.36634843583164, 14.164252021113896 ], [ -89.368363817436204, 14.16254669787179 ], [ -89.380042691417032, 14.141824449138994 ], [ -89.382419807328233, 14.138620510028488 ], [ -89.384383511190094, 14.136785997375853 ], [ -89.386683111836135, 14.135519923705488 ], [ -89.389163581434104, 14.134615587039718 ], [ -89.40797380224916, 14.135829982967323 ], [ -89.427171596691835, 14.071622015843332 ], [ -89.424122688111538, 14.050150458277017 ], [ -89.413012254911621, 14.040228583482303 ], [ -89.398051926555127, 14.037438056421138 ], [ -89.383117438419049, 14.037489732365259 ], [ -89.37136105007238, 14.04059031778894 ], [ -89.382187263331502, 13.98527069758461 ], [ -89.383918423196633, 13.970827134964281 ], [ -89.383660040778238, 13.9677265495406 ], [ -89.385210334389399, 13.948554591721006 ], [ -89.386295539107834, 13.945428167875605 ], [ -89.38854346380981, 13.942740994501264 ], [ -89.393659430838056, 13.94054474484409 ], [ -89.397380133886031, 13.940312200847359 ], [ -89.400687424884723, 13.94038971611252 ], [ -89.403452115322864, 13.940105496171668 ], [ -89.405570847916294, 13.939020291453289 ], [ -89.41355485727081, 13.926540431795502 ], [ -89.416836310747101, 13.924473375146135 ], [ -89.419626837808323, 13.924085802417835 ], [ -89.422133144928694, 13.924860947874436 ], [ -89.424820319202354, 13.925067654348766 ], [ -89.427223272635899, 13.924447536724415 ], [ -89.429342007027969, 13.923078111165864 ], [ -89.43089229973981, 13.921166083248124 ], [ -89.432106695667471, 13.915585029125793 ], [ -89.433424445281901, 13.888790798056846 ], [ -89.432597622082596, 13.870755724497087 ], [ -89.434457974056215, 13.849490872505726 ], [ -89.452002122999545, 13.80293040621325 ], [ -89.456627162713346, 13.775076808847643 ], [ -89.504272833724258, 13.783939317345585 ], [ -89.517036913322897, 13.788150946808742 ], [ -89.518638881978802, 13.790088813148202 ], [ -89.520008308436672, 13.792155869797512 ], [ -89.526054449653088, 13.80678030047045 ], [ -89.539335293189197, 13.818872586500675 ], [ -89.560470953971333, 13.834194648264372 ], [ -89.570134447246915, 13.839827379230144 ], [ -89.576929898196227, 13.842747097500535 ], [ -89.579642910891607, 13.84207530393212 ], [ -89.581580777231068, 13.840680039951849 ], [ -89.583311937096198, 13.83881968797823 ], [ -89.585973272948195, 13.834556383470328 ], [ -89.589177212058644, 13.827528388524286 ], [ -89.59049496077381, 13.82202484786842 ], [ -89.59046912325141, 13.813058987482293 ], [ -89.591115078398104, 13.810630194727707 ], [ -89.59336300310008, 13.808356432503331 ], [ -89.596980354259927, 13.806573594895497 ], [ -89.604163377937539, 13.804919949396151 ], [ -89.608891771338165, 13.80585012538296 ], [ -89.612121547971071, 13.807116197254686 ], [ -89.614317796728926, 13.808821518698096 ], [ -89.616023119071656, 13.810656033149371 ], [ -89.617263353420981, 13.812981472217132 ], [ -89.618426073404521, 13.816082058540132 ], [ -89.620803189315723, 13.819389350438144 ], [ -89.625376553085459, 13.82396271420788 ], [ -89.631603563253805, 13.8250995957697 ], [ -89.634833339886711, 13.827063300530881 ], [ -89.636125251079477, 13.829207872445352 ], [ -89.635686000608416, 13.831714179565722 ], [ -89.634523282423515, 13.833936265845978 ], [ -89.632817959181466, 13.835874132185438 ], [ -89.628968064924265, 13.838948879187399 ], [ -89.627417772212425, 13.840680039951849 ], [ -89.626125861019659, 13.842927965553145 ], [ -89.625324877141338, 13.845692654192646 ], [ -89.625092333144664, 13.848509018776156 ], [ -89.626177537863043, 13.853676663547162 ], [ -89.630621711322874, 13.860704656694509 ], [ -89.636745367804451, 13.866208197350431 ], [ -89.639871791649853, 13.869593004513547 ], [ -89.642093878829428, 13.872486884362218 ], [ -89.645246141096493, 13.879618232095709 ], [ -89.648217536210325, 13.883597317562135 ], [ -89.664443936438488, 13.899022732113394 ], [ -89.67025753455755, 13.90318268473311 ], [ -89.674908412693071, 13.905378933490965 ], [ -89.678086514281176, 13.905378933490965 ], [ -89.681109585339073, 13.904991359863345 ], [ -89.686587286673898, 13.90357025836073 ], [ -89.695553147959401, 13.903286038419935 ], [ -89.718833380655951, 13.908970445329771 ], [ -89.698808763013972, 13.975839749205022 ], [ -89.695863207221237, 13.993719794033268 ], [ -89.696819220730447, 13.996096909944413 ], [ -89.698963792644918, 13.999998481045054 ], [ -89.699041307010702, 14.000231025041785 ], [ -89.702658658170549, 14.003848375302255 ], [ -89.70671525800276, 14.006897283882552 ], [ -89.710332608263229, 14.010333766989731 ], [ -89.711805385709965, 14.012504177325923 ], [ -89.7128389153836, 14.014907130759468 ], [ -89.71498348729807, 14.02302033132321 ], [ -89.716197883225732, 14.025216580081064 ], [ -89.717903204669142, 14.027309475152151 ], [ -89.721572231773052, 14.030332546210047 ], [ -89.739658983075572, 14.041468817831685 ], [ -89.7480100679999, 14.044894904000031 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-CH", "NAME_1": "Chalatenango" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.346206290288023, 14.413075726263742 ], [ -89.30756730199991, 14.407054546000069 ], [ -89.276535604999964, 14.392740173000078 ], [ -89.225530965999923, 14.382146505 ], [ -89.200157836999921, 14.36467987000006 ], [ -89.153984944999962, 14.351295675000117 ], [ -89.144502319999901, 14.35971893300011 ], [ -89.130110432999885, 14.38674570700006 ], [ -89.122178100999918, 14.394678040000102 ], [ -89.113341430999924, 14.397055156000064 ], [ -89.107476155999933, 14.395969951000069 ], [ -89.10256689499991, 14.391525777000055 ], [ -89.096830810999847, 14.384006856000013 ], [ -89.091844035999884, 14.374834290000109 ], [ -89.089673624999904, 14.364886577000021 ], [ -89.090552123999942, 14.354706320000048 ], [ -89.094479532999912, 14.34486195900007 ], [ -89.083084879999916, 14.335327657000079 ], [ -89.048978434999924, 14.331451925000039 ], [ -89.032984578999901, 14.323674622000027 ], [ -89.026602539999942, 14.311298117000149 ], [ -89.02262345399987, 14.28065399200004 ], [ -89.018127604999876, 14.27168813100009 ], [ -88.992754475999874, 14.252955424000106 ], [ -88.983530232999868, 14.242129211000062 ], [ -88.974564371999918, 14.227375590000051 ], [ -88.970791991999903, 14.214844056000047 ], [ -88.970228476163243, 14.210176262024845 ], [ -88.969241699999969, 14.202002462000067 ], [ -88.965986083999979, 14.19138295500008 ], [ -88.957175252999889, 14.18518178300009 ], [ -88.94748592199997, 14.187274679000055 ], [ -88.935626180999947, 14.194018453000083 ], [ -88.921647704999941, 14.199883728000088 ], [ -88.906015584999892, 14.199573670000092 ], [ -88.881262572999873, 14.184199931000123 ], [ -88.860333618999874, 14.158516744000053 ], [ -88.845321614999904, 14.128621928000115 ], [ -88.838758707999915, 14.100406596000056 ], [ -88.821188720999942, 14.102938741000045 ], [ -88.777341268999919, 14.099734802000071 ], [ -88.765429850999908, 14.104256490000097 ], [ -88.755120401999903, 14.110457662000087 ], [ -88.746387085999913, 14.111336162000029 ], [ -88.73922989999997, 14.099941508000128 ], [ -88.740056722999896, 14.083017477000041 ], [ -88.746077026999842, 14.066558533000062 ], [ -88.746645466999894, 14.052476705000032 ], [ -88.730961669999942, 14.042477316000117 ], [ -88.709515950999901, 14.039686788000054 ], [ -88.704865071999848, 14.038033142000103 ], [ -88.697656209999877, 14.032012838000071 ], [ -88.692695272999941, 14.025294902000056 ], [ -88.690447346999917, 14.016949157000084 ], [ -88.690811757999967, 14.011789871000062 ], [ -88.736851976137757, 14.004985255964755 ], [ -88.757574225769872, 13.995270086745109 ], [ -88.76509314713104, 13.985374050372116 ], [ -88.771914435602696, 13.980309760187254 ], [ -88.783825852680934, 13.974909573218213 ], [ -88.845320808008864, 13.955272529203853 ], [ -88.860410325775888, 13.949691474182146 ], [ -88.874027066096232, 13.946358343862471 ], [ -88.900227017063173, 13.948709622251272 ], [ -88.929734259928125, 13.947908637473631 ], [ -88.94621904167542, 13.949743150126267 ], [ -88.961670294648343, 13.955556749144648 ], [ -88.979808722794303, 13.954109809220313 ], [ -89.001202765994833, 13.964005846492626 ], [ -89.00502682183037, 13.966331285560386 ], [ -89.009496832812545, 13.970336209448476 ], [ -89.014767828572417, 13.97795848179851 ], [ -89.017455003745397, 13.983436184032655 ], [ -89.019160326088183, 13.988009547802392 ], [ -89.019806281234878, 13.990490017400361 ], [ -89.020193854862498, 13.993022162043133 ], [ -89.020168016440778, 13.995709337216113 ], [ -89.019392870084857, 13.999972641724014 ], [ -89.019392870084857, 14.000205185720745 ], [ -89.019806281234878, 14.00183299369769 ], [ -89.021640794786833, 14.004571844814791 ], [ -89.043577440346553, 14.029944973481747 ], [ -89.048099128172225, 14.037748113884334 ], [ -89.049649420884066, 14.039608465858009 ], [ -89.066521776258924, 14.051339015782958 ], [ -89.07378231520164, 14.057643541216464 ], [ -89.078820766964782, 14.06025320112434 ], [ -89.104607306781759, 14.069374091141356 ], [ -89.117138840585028, 14.075497748522253 ], [ -89.120627001434968, 14.075936998093994 ], [ -89.123675910015209, 14.075962836515657 ], [ -89.141349250167764, 14.066996975230211 ], [ -89.168970302637319, 14.054620470158568 ], [ -89.180339118255688, 14.057385158798013 ], [ -89.194420945670117, 14.068211371157815 ], [ -89.200751308625968, 14.055834866086172 ], [ -89.214678107308771, 14.055989894817799 ], [ -89.235400356940886, 14.064800727371676 ], [ -89.243074307033623, 14.062242743407865 ], [ -89.256019252886176, 14.053147690913192 ], [ -89.260205043927613, 14.051132310207947 ], [ -89.26731055413876, 14.052114163038198 ], [ -89.276819016884076, 14.056377468445419 ], [ -89.280074632838023, 14.057333481954629 ], [ -89.296404384954371, 14.059633084399309 ], [ -89.314439460312826, 14.069606635138086 ], [ -89.324774746257503, 14.071622015843332 ], [ -89.334567429842991, 14.064438992165719 ], [ -89.343688320759384, 14.059555569134204 ], [ -89.355496385050117, 14.057333481954629 ], [ -89.363816291188868, 14.054232896530948 ], [ -89.367020230299374, 14.047411607159916 ], [ -89.37136105007238, 14.04059031778894 ], [ -89.383117438419049, 14.037489732365259 ], [ -89.398051926555127, 14.037438056421138 ], [ -89.413012254911621, 14.040228583482303 ], [ -89.424122688111538, 14.050150458277017 ], [ -89.427171596691835, 14.071622015843332 ], [ -89.40797380224916, 14.135829982967323 ], [ -89.389163581434104, 14.134615587039718 ], [ -89.386683111836135, 14.135519923705488 ], [ -89.384383511190094, 14.136785997375853 ], [ -89.382419807328233, 14.138620510028488 ], [ -89.380042691417032, 14.141824449138994 ], [ -89.368363817436204, 14.16254669787179 ], [ -89.36634843583164, 14.164252021113896 ], [ -89.364410570391499, 14.165543932306605 ], [ -89.362007616058634, 14.1665774601816 ], [ -89.359294603363253, 14.167326768115856 ], [ -89.356659105033657, 14.167714341743476 ], [ -89.346375495033044, 14.16833445936777 ], [ -89.343274908710043, 14.168825384883576 ], [ -89.340484381648878, 14.169600531239496 ], [ -89.338029751371892, 14.170530707226362 ], [ -89.335704312304131, 14.171822618419071 ], [ -89.333740606643687, 14.173243719921743 ], [ -89.330200771648265, 14.176602687763818 ], [ -89.3108479475747, 14.202750962786695 ], [ -89.30893591965696, 14.207427680243256 ], [ -89.30854834692866, 14.211200059235352 ], [ -89.30950436133719, 14.222258816491149 ], [ -89.309349330806981, 14.242257594812145 ], [ -89.272116461905171, 14.256959539850868 ], [ -89.263305630250613, 14.266519680338945 ], [ -89.259404060049292, 14.28664765076843 ], [ -89.24651079014086, 14.322846990895926 ], [ -89.264830085440053, 14.334138292148452 ], [ -89.2696101547848, 14.340365302316854 ], [ -89.271780565120991, 14.342070623760264 ], [ -89.286637538891284, 14.349692897908881 ], [ -89.290177374786026, 14.352405911503581 ], [ -89.292399461965601, 14.354602159362173 ], [ -89.296843635425432, 14.36186269830489 ], [ -89.300176764845787, 14.369407457188402 ], [ -89.301416999195112, 14.371319485106142 ], [ -89.308057421412855, 14.378502508783754 ], [ -89.346206290288023, 14.413075726263742 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-CA", "NAME_1": "Cabañas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.690811757999967, 14.011789871000062 ], [ -88.690938272999858, 14.009998678000088 ], [ -88.684814615999898, 14.012298279000021 ], [ -88.659338135999889, 14.016122335000148 ], [ -88.633861653999958, 14.014468689000097 ], [ -88.558104003999858, 13.990904236000105 ], [ -88.514049845999892, 13.987648621000119 ], [ -88.50436051499986, 13.983695374000135 ], [ -88.495420491999937, 13.97514292400011 ], [ -88.49619563899995, 13.971990662000067 ], [ -88.496505696999918, 13.969561870000106 ], [ -88.497085348999917, 13.969068092000015 ], [ -88.497900960999914, 13.968373311000079 ], [ -88.498182576999938, 13.968409755000081 ], [ -88.502293457999912, 13.968941752000134 ], [ -88.501198105999947, 13.966600438000029 ], [ -88.496092285999907, 13.955686747000129 ], [ -88.496815754999915, 13.944033712000063 ], [ -88.500226399999946, 13.931863912000068 ], [ -88.502293457999912, 13.917110291000057 ], [ -88.499502930999938, 13.907601827000065 ], [ -88.48867671699989, 13.881350200000043 ], [ -88.48800492399991, 13.865330506000078 ], [ -88.496815755342823, 13.851197002439676 ], [ -88.498675299725278, 13.849568385972248 ], [ -88.50296444355422, 13.845692654192646 ], [ -88.496789110229258, 13.833264472277563 ], [ -88.498210211731873, 13.821404731143389 ], [ -88.505315721043701, 13.811431179505291 ], [ -88.516012743093597, 13.804713242921821 ], [ -88.513919847123248, 13.790838121082402 ], [ -88.523247442715274, 13.776911322399599 ], [ -88.532394172053387, 13.759651394296384 ], [ -88.532342495209946, 13.759367174355589 ], [ -88.548568895438166, 13.748695989828036 ], [ -88.558025682239418, 13.751150621004342 ], [ -88.583243781275485, 13.754199530483902 ], [ -88.586912808379395, 13.755413927310883 ], [ -88.588876512241256, 13.757093411231949 ], [ -88.590065069747141, 13.759263821568084 ], [ -88.590943569789886, 13.761666775001629 ], [ -88.592183804139211, 13.76709280039239 ], [ -88.593630744063546, 13.769392401937807 ], [ -88.596421272024088, 13.770813503440422 ], [ -88.603345913283249, 13.772648016992378 ], [ -88.605774706037835, 13.773681544867372 ], [ -88.612440965777921, 13.777557278445613 ], [ -88.623086310984434, 13.78117462780682 ], [ -88.625489265317299, 13.782414863055465 ], [ -88.64386023566135, 13.795644028848812 ], [ -88.64613399878499, 13.796729234466568 ], [ -88.657141079197402, 13.798744615171813 ], [ -88.670861172305251, 13.799442247161949 ], [ -88.677424079257833, 13.800604967145489 ], [ -88.70936011397805, 13.800294907883654 ], [ -88.716491461711598, 13.800915025508004 ], [ -88.721219855112224, 13.802155259857329 ], [ -88.735611741788432, 13.812283840227053 ], [ -88.738919033686443, 13.811973781864538 ], [ -88.742510546424569, 13.810165106734246 ], [ -88.74752315976599, 13.80370555346849 ], [ -88.75077877482056, 13.800346584727095 ], [ -88.754266933871861, 13.798098660025119 ], [ -88.760183884778428, 13.798589586440244 ], [ -88.767341070933639, 13.800372423148815 ], [ -88.773929816307941, 13.798641262384365 ], [ -88.805039028728174, 13.78520539011663 ], [ -88.814702522003756, 13.782208157480454 ], [ -88.821575487318853, 13.781097113441035 ], [ -88.831962450106971, 13.784481919704831 ], [ -88.837801886647753, 13.78579966931926 ], [ -88.844235603290429, 13.786058050838335 ], [ -88.847051967873995, 13.78233734779036 ], [ -88.84886064300423, 13.779314276732464 ], [ -88.850255906984501, 13.750633857066816 ], [ -88.884853277556715, 13.75980642302801 ], [ -88.893844978163202, 13.764870714112135 ], [ -88.894826830094132, 13.767377021232505 ], [ -88.901260545837488, 13.776911322399599 ], [ -88.91092403821375, 13.786988226825201 ], [ -88.915032314889402, 13.792336737850178 ], [ -88.917435269222267, 13.796729234466568 ], [ -88.918753017937433, 13.803240465475085 ], [ -88.919993252286758, 13.807038682888901 ], [ -88.9250317040499, 13.815668647390169 ], [ -88.926220261555784, 13.819880275953949 ], [ -88.927021247232744, 13.824350286936181 ], [ -88.93058692064983, 13.832153429137406 ], [ -88.935470343681402, 13.837424424897279 ], [ -88.943635220189265, 13.84282461186632 ], [ -88.949784715991825, 13.849206650766291 ], [ -88.969266730375296, 13.876104233723368 ], [ -88.973995123775921, 13.884682522280571 ], [ -88.976527269318012, 13.891038722758822 ], [ -88.976010505380486, 13.894035956294317 ], [ -88.975209519703526, 13.896774807411418 ], [ -88.974227667772652, 13.899151923322563 ], [ -88.972729051004876, 13.90127065681537 ], [ -88.971127082348971, 13.903027655102164 ], [ -88.969060024800285, 13.904577947814005 ], [ -88.955779182163496, 13.912096869175173 ], [ -88.951955126328016, 13.915171617076453 ], [ -88.948596157586564, 13.918659776127754 ], [ -88.94565060089451, 13.922974758378359 ], [ -88.944462043388569, 13.925222683080335 ], [ -88.929734259928125, 13.947908637473631 ], [ -88.900227017063173, 13.948709622251272 ], [ -88.874027066096232, 13.946358343862471 ], [ -88.860410325775888, 13.949691474182146 ], [ -88.845320808008864, 13.955272529203853 ], [ -88.783825852680934, 13.974909573218213 ], [ -88.771914435602696, 13.980309760187254 ], [ -88.76509314713104, 13.985374050372116 ], [ -88.757574225769872, 13.995270086745109 ], [ -88.736851976137757, 14.004985255964755 ], [ -88.690811757999967, 14.011789871000062 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-MO", "NAME_1": "Morazán" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.235074625999886, 13.992867941000043 ], [ -88.220062622999905, 13.991317647000116 ], [ -88.217658813303558, 13.990796705103833 ], [ -88.193475097999908, 13.985555725000054 ], [ -88.177532918999958, 13.985193990000056 ], [ -88.125391397999891, 13.991265971000104 ], [ -88.09903641799994, 13.98981903100011 ], [ -88.087538411999901, 13.980543112000092 ], [ -88.072888143999933, 13.94341359500001 ], [ -88.058392903999902, 13.926489563000104 ], [ -88.039970255999975, 13.910133972000054 ], [ -88.023640502999854, 13.891168722000103 ], [ -88.015320597999903, 13.866364035000061 ], [ -87.969741984999899, 13.888533223000081 ], [ -87.954781656999842, 13.892460633000056 ], [ -87.952594894338858, 13.892029035511541 ], [ -87.949380663386876, 13.872409369097113 ], [ -87.94503984181523, 13.856131292924829 ], [ -87.943076137953369, 13.827890122830865 ], [ -87.947210253050741, 13.767170314758232 ], [ -87.94695186973297, 13.763914699703605 ], [ -87.946254238642155, 13.761227525429945 ], [ -87.94503984181523, 13.759108791937194 ], [ -87.940518154888935, 13.753424384128039 ], [ -87.939122890908664, 13.751228136269447 ], [ -87.938141038977733, 13.748851020358302 ], [ -87.937365891722493, 13.746344713237932 ], [ -87.936358202269219, 13.740298570222819 ], [ -87.936668259732357, 13.721204128567649 ], [ -87.939613817323789, 13.697975571815164 ], [ -87.945634121017861, 13.671052151335687 ], [ -87.968552619407831, 13.613329575899172 ], [ -87.970257940851297, 13.594545193505837 ], [ -87.977595995059119, 13.583744819567755 ], [ -88.008550177848406, 13.551447047842942 ], [ -88.030099249780562, 13.554935207793562 ], [ -88.040408698202839, 13.554263414225147 ], [ -88.07957943434343, 13.5425587018226 ], [ -88.08704667796178, 13.541783556365999 ], [ -88.091852586627567, 13.542481187456815 ], [ -88.093325364973623, 13.544134832956161 ], [ -88.094979011372232, 13.546873684073262 ], [ -88.095883348038058, 13.548889064778507 ], [ -88.098260463949259, 13.551627915895608 ], [ -88.10154191832487, 13.554547634165942 ], [ -88.116347216151098, 13.56322927551065 ], [ -88.118465948744529, 13.564779568222491 ], [ -88.119964566411568, 13.566794948927736 ], [ -88.121101447074125, 13.569017035207992 ], [ -88.123995326922795, 13.586871243413157 ], [ -88.125545619634636, 13.592142239172972 ], [ -88.129240485160267, 13.59886017485718 ], [ -88.133503790567488, 13.604312039568981 ], [ -88.137198656093062, 13.606534124949917 ], [ -88.140945196663495, 13.607696844933457 ], [ -88.179599168866559, 13.604673773875561 ], [ -88.18533525261978, 13.60345937704858 ], [ -88.190373705282241, 13.60157318845188 ], [ -88.198486904946662, 13.596896470995318 ], [ -88.20388709191576, 13.595346178283478 ], [ -88.205618251780891, 13.596508897367698 ], [ -88.205695767045995, 13.598265896553869 ], [ -88.204533047062455, 13.60041046846834 ], [ -88.198616096155888, 13.608187771348582 ], [ -88.197582567381573, 13.610590724782128 ], [ -88.197427537750627, 13.613174547167603 ], [ -88.198977831361788, 13.615758367754438 ], [ -88.201277432007885, 13.617980454934013 ], [ -88.208382941319655, 13.622424628393844 ], [ -88.210630866021631, 13.624181627580015 ], [ -88.212155321211071, 13.626145331441876 ], [ -88.213137173142002, 13.628470771408956 ], [ -88.213886481076202, 13.631235460048401 ], [ -88.214325730647943, 13.634258531106298 ], [ -88.216444465040013, 13.638108425363498 ], [ -88.220087652822883, 13.642836818764181 ], [ -88.229621954889296, 13.649709784079278 ], [ -88.233290981993207, 13.653223782451562 ], [ -88.235073818701778, 13.659244086145634 ], [ -88.238406949021453, 13.66417918512127 ], [ -88.251119350877332, 13.675315456742908 ], [ -88.256286993849642, 13.68112905486197 ], [ -88.259387580172643, 13.685779933896811 ], [ -88.261067064093709, 13.710894680145373 ], [ -88.260912035362139, 13.713556015997312 ], [ -88.259826829744384, 13.715726427232823 ], [ -88.258147345823318, 13.717509263941338 ], [ -88.22522945827285, 13.740608629484655 ], [ -88.220707771346554, 13.7430115829182 ], [ -88.213033820354497, 13.745672918770197 ], [ -88.210708381286736, 13.747068182750411 ], [ -88.208770514947275, 13.748670152305692 ], [ -88.207220222235435, 13.750556341801712 ], [ -88.206445074980195, 13.753527736915487 ], [ -88.206470913401915, 13.757170924698414 ], [ -88.208150397322981, 13.763139553347685 ], [ -88.210811734074241, 13.767015286026606 ], [ -88.213137173142002, 13.769573269091097 ], [ -88.250860969358257, 13.794662176917939 ], [ -88.256545376268093, 13.799597275893575 ], [ -88.260136888106899, 13.80331797894155 ], [ -88.260989548828604, 13.80585012538296 ], [ -88.26168718081874, 13.808614814022462 ], [ -88.262152268812144, 13.818252467977004 ], [ -88.261247932146318, 13.823885198942776 ], [ -88.260705328887809, 13.825745550916452 ], [ -88.260085212162778, 13.827425034837461 ], [ -88.258922492179238, 13.829388738699322 ], [ -88.255873582699678, 13.833109443545993 ], [ -88.254064907569386, 13.834582220992672 ], [ -88.251946174076636, 13.835951646551223 ], [ -88.250189174890465, 13.837656968894009 ], [ -88.248690559022066, 13.839724026442639 ], [ -88.247527839038526, 13.841920274301231 ], [ -88.246545987107595, 13.844452418943945 ], [ -88.245925868583925, 13.847242946904487 ], [ -88.24608089911419, 13.853289089020222 ], [ -88.24933651416876, 13.861634833580695 ], [ -88.253238085269402, 13.869127916520142 ], [ -88.254840053925307, 13.873468736293148 ], [ -88.255201789131263, 13.876827704135223 ], [ -88.256958788317434, 13.88483755101214 ], [ -88.268741014186446, 13.911760973290257 ], [ -88.274170772999895, 13.919119724000055 ], [ -88.27016292299993, 13.926024475000077 ], [ -88.263600015999941, 13.93310414600009 ], [ -88.251636921999904, 13.938090922000058 ], [ -88.2427744149999, 13.936695658000076 ], [ -88.236366536999952, 13.938142599000074 ], [ -88.231586466999943, 13.951811015000075 ], [ -88.233369303999922, 13.954498190000024 ], [ -88.242309326999958, 13.962533875000091 ], [ -88.244376383999935, 13.966099548000059 ], [ -88.245358235999902, 13.98589162200004 ], [ -88.244893147999875, 13.989250591000058 ], [ -88.235074625999886, 13.992867941000043 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-SM", "NAME_1": "San Miguel" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.326206014999855, 13.885070903000056 ], [ -88.319255533999865, 13.89760243700006 ], [ -88.308429321999938, 13.901478170000104 ], [ -88.296311197999842, 13.902356669000142 ], [ -88.28543330899987, 13.905974019000027 ], [ -88.277526814999931, 13.913337911000028 ], [ -88.274170772999895, 13.919119724000055 ], [ -88.268741014186446, 13.911760973290257 ], [ -88.256958788317434, 13.88483755101214 ], [ -88.255201789131263, 13.876827704135223 ], [ -88.254840053925307, 13.873468736293148 ], [ -88.253238085269402, 13.869127916520142 ], [ -88.24933651416876, 13.861634833580695 ], [ -88.24608089911419, 13.853289089020222 ], [ -88.245925868583925, 13.847242946904487 ], [ -88.246545987107595, 13.844452418943945 ], [ -88.247527839038526, 13.841920274301231 ], [ -88.248690559022066, 13.839724026442639 ], [ -88.250189174890465, 13.837656968894009 ], [ -88.251946174076636, 13.835951646551223 ], [ -88.254064907569386, 13.834582220992672 ], [ -88.255873582699678, 13.833109443545993 ], [ -88.258922492179238, 13.829388738699322 ], [ -88.260085212162778, 13.827425034837461 ], [ -88.260705328887809, 13.825745550916452 ], [ -88.261247932146318, 13.823885198942776 ], [ -88.262152268812144, 13.818252467977004 ], [ -88.26168718081874, 13.808614814022462 ], [ -88.260989548828604, 13.80585012538296 ], [ -88.260136888106899, 13.80331797894155 ], [ -88.256545376268093, 13.799597275893575 ], [ -88.250860969358257, 13.794662176917939 ], [ -88.213137173142002, 13.769573269091097 ], [ -88.210811734074241, 13.767015286026606 ], [ -88.208150397322981, 13.763139553347685 ], [ -88.206470913401915, 13.757170924698414 ], [ -88.206445074980195, 13.753527736915487 ], [ -88.207220222235435, 13.750556341801712 ], [ -88.208770514947275, 13.748670152305692 ], [ -88.210708381286736, 13.747068182750411 ], [ -88.213033820354497, 13.745672918770197 ], [ -88.220707771346554, 13.7430115829182 ], [ -88.22522945827285, 13.740608629484655 ], [ -88.258147345823318, 13.717509263941338 ], [ -88.259826829744384, 13.715726427232823 ], [ -88.260912035362139, 13.713556015997312 ], [ -88.261067064093709, 13.710894680145373 ], [ -88.259387580172643, 13.685779933896811 ], [ -88.256286993849642, 13.68112905486197 ], [ -88.251119350877332, 13.675315456742908 ], [ -88.238406949021453, 13.66417918512127 ], [ -88.235073818701778, 13.659244086145634 ], [ -88.233290981993207, 13.653223782451562 ], [ -88.229621954889296, 13.649709784079278 ], [ -88.220087652822883, 13.642836818764181 ], [ -88.216444465040013, 13.638108425363498 ], [ -88.214325730647943, 13.634258531106298 ], [ -88.213886481076202, 13.631235460048401 ], [ -88.213137173142002, 13.628470771408956 ], [ -88.212155321211071, 13.626145331441876 ], [ -88.210630866021631, 13.624181627580015 ], [ -88.208382941319655, 13.622424628393844 ], [ -88.201277432007885, 13.617980454934013 ], [ -88.198977831361788, 13.615758367754438 ], [ -88.197427537750627, 13.613174547167603 ], [ -88.197582567381573, 13.610590724782128 ], [ -88.198616096155888, 13.608187771348582 ], [ -88.204533047062455, 13.60041046846834 ], [ -88.205695767045995, 13.598265896553869 ], [ -88.205618251780891, 13.596508897367698 ], [ -88.20388709191576, 13.595346178283478 ], [ -88.198486904946662, 13.596896470995318 ], [ -88.190373705282241, 13.60157318845188 ], [ -88.18533525261978, 13.60345937704858 ], [ -88.179599168866559, 13.604673773875561 ], [ -88.140945196663495, 13.607696844933457 ], [ -88.137198656093062, 13.606534124949917 ], [ -88.133503790567488, 13.604312039568981 ], [ -88.129240485160267, 13.59886017485718 ], [ -88.125545619634636, 13.592142239172972 ], [ -88.123995326922795, 13.586871243413157 ], [ -88.121101447074125, 13.569017035207992 ], [ -88.119964566411568, 13.566794948927736 ], [ -88.118465948744529, 13.564779568222491 ], [ -88.116347216151098, 13.56322927551065 ], [ -88.10154191832487, 13.554547634165942 ], [ -88.098260463949259, 13.551627915895608 ], [ -88.095883348038058, 13.548889064778507 ], [ -88.094979011372232, 13.546873684073262 ], [ -88.093325364973623, 13.544134832956161 ], [ -88.091852586627567, 13.542481187456815 ], [ -88.08704667796178, 13.541783556365999 ], [ -88.07957943434343, 13.5425587018226 ], [ -88.040408698202839, 13.554263414225147 ], [ -88.030099249780562, 13.554935207793562 ], [ -88.008550177848406, 13.551447047842942 ], [ -88.015061407957603, 13.542868761084435 ], [ -88.017205979872074, 13.530233872695078 ], [ -88.016663378412147, 13.50000316031759 ], [ -88.012787644833907, 13.485611274540645 ], [ -88.012787644833907, 13.482381497008475 ], [ -88.013795336085877, 13.478945013901239 ], [ -88.017516039133909, 13.474552517284849 ], [ -88.020306566195075, 13.472201238896048 ], [ -88.023019578890455, 13.470315050299291 ], [ -88.027360398663461, 13.467912095966426 ], [ -88.029220750637137, 13.466439316721051 ], [ -88.030771044248297, 13.46240855620988 ], [ -88.031597867447601, 13.456000677988868 ], [ -88.031132778554877, 13.430343329381117 ], [ -88.028238897806887, 13.412747504493723 ], [ -88.027257045875956, 13.410163683007568 ], [ -88.026042649948295, 13.407760727775326 ], [ -88.016663378412147, 13.393239650789212 ], [ -88.015500658428607, 13.390836697355667 ], [ -88.014647996807582, 13.388356227757697 ], [ -88.014234584758242, 13.385953274324152 ], [ -88.027050341200265, 13.314019680264039 ], [ -88.02674028193843, 13.309885566065986 ], [ -88.02518998922659, 13.304020291103541 ], [ -88.025887621216725, 13.297922472144364 ], [ -88.038935919856783, 13.256219591361059 ], [ -88.041313035767985, 13.253868312972259 ], [ -88.045963914802826, 13.252498888313028 ], [ -88.049322882644901, 13.252550564257149 ], [ -88.052552660177128, 13.253170680982123 ], [ -88.063068814174414, 13.256813870563633 ], [ -88.071672940253961, 13.261878159849175 ], [ -88.079889492705888, 13.267820950076782 ], [ -88.081982387776975, 13.268673610798487 ], [ -88.084617886106514, 13.258855088791279 ], [ -88.085961473243401, 13.251103624332757 ], [ -88.091465012999947, 13.172787991372672 ], [ -88.091470945800239, 13.172705728065043 ], [ -88.098378058999913, 13.174017645000049 ], [ -88.105213995999918, 13.174017645000049 ], [ -88.112507114174903, 13.171196219997629 ], [ -88.173759732325777, 13.240664984701255 ], [ -88.176421068177717, 13.241672675053906 ], [ -88.179289109604724, 13.242215278312415 ], [ -88.182389695927725, 13.242370307044041 ], [ -88.209571498825596, 13.238236191946669 ], [ -88.212051968423566, 13.238804632727579 ], [ -88.213912320397242, 13.24079417591048 ], [ -88.214041510707148, 13.245703437363716 ], [ -88.213498908347901, 13.249010728362407 ], [ -88.212517056417028, 13.252162991528849 ], [ -88.2050498118993, 13.265573025374806 ], [ -88.205618251780891, 13.268337714014251 ], [ -88.207943691747971, 13.271464137859653 ], [ -88.214506598700552, 13.274926459388553 ], [ -88.218304816114369, 13.277846178558264 ], [ -88.220630256081449, 13.281489366341191 ], [ -88.220862800078123, 13.296294664167419 ], [ -88.221172858440639, 13.299162706493689 ], [ -88.222154711270889, 13.302314967861491 ], [ -88.223834195191955, 13.305260525452866 ], [ -88.227115647768926, 13.308800361347608 ], [ -88.231353115653746, 13.309342962807477 ], [ -88.234531216342532, 13.308955390079177 ], [ -88.243910488777999, 13.304020291103541 ], [ -88.24894894144046, 13.301927395133191 ], [ -88.251791145345067, 13.301384792773945 ], [ -88.254685025193737, 13.301152248777271 ], [ -88.257423876310838, 13.301643175192339 ], [ -88.259981859375273, 13.302495835914101 ], [ -88.262074755345679, 13.303839423050931 ], [ -88.26589881118116, 13.306965846896276 ], [ -88.26801754377459, 13.308361110876547 ], [ -88.270549689316681, 13.309291286863356 ], [ -88.273391893221287, 13.309497992438367 ], [ -88.275949877185042, 13.309368801229198 ], [ -88.278869594556113, 13.311280829146938 ], [ -88.282952032810044, 13.315104884982418 ], [ -88.291866218151426, 13.325388494983031 ], [ -88.296956345858632, 13.329470933236962 ], [ -88.301478033684305, 13.332003078779053 ], [ -88.321115077698664, 13.334225165059308 ], [ -88.32641191277952, 13.335568752196139 ], [ -88.333904994819648, 13.338824368150028 ], [ -88.336075406055102, 13.340142116865195 ], [ -88.337909918707737, 13.341537379946089 ], [ -88.34493791365378, 13.350296536555902 ], [ -88.354988979657662, 13.366006171047957 ], [ -88.360415005048424, 13.376703193097853 ], [ -88.365686000808296, 13.394686590713604 ], [ -88.367158780053614, 13.402334703283941 ], [ -88.367753059256245, 13.408251655089771 ], [ -88.367598028726036, 13.414685369933864 ], [ -88.368166470406265, 13.417785956256864 ], [ -88.369665087174042, 13.420369777743019 ], [ -88.373747525427916, 13.421687527357506 ], [ -88.378346726720054, 13.420059719380504 ], [ -88.380155401850288, 13.420085557802224 ], [ -88.381498989886438, 13.421222439364044 ], [ -88.382687548291699, 13.42442637847455 ], [ -88.385891485603565, 13.442849026561305 ], [ -88.386124029600296, 13.449308579827061 ], [ -88.387829352842346, 13.462718614572395 ], [ -88.38790686720813, 13.46566417126445 ], [ -88.387674323211456, 13.468687242322346 ], [ -88.386821661590375, 13.471167711021053 ], [ -88.385271368878534, 13.473028062095352 ], [ -88.383411017804235, 13.473596502876319 ], [ -88.381964076980523, 13.473028062095352 ], [ -88.380827196318023, 13.472072047686822 ], [ -88.379457770759473, 13.470470079030918 ], [ -88.377829962782528, 13.469307359047377 ], [ -88.375995450129892, 13.469126491894087 ], [ -88.374574347727958, 13.470676785505248 ], [ -88.373644171741091, 13.473234768569682 ], [ -88.373204922169407, 13.479487616260485 ], [ -88.373411627744417, 13.485611274540645 ], [ -88.373024055016117, 13.488634344699221 ], [ -88.372197231816756, 13.491192327763713 ], [ -88.370879483101646, 13.493595282096578 ], [ -88.369303351968085, 13.495429796547853 ], [ -88.363980679364829, 13.5002098658926 ], [ -88.363773972890499, 13.500519924255059 ], [ -88.362533739440494, 13.50305206979715 ], [ -88.362197841756995, 13.505248318555061 ], [ -88.362611253806278, 13.509046535968821 ], [ -88.366667853638489, 13.522224025818105 ], [ -88.36746883841613, 13.527417507212192 ], [ -88.367494675938531, 13.531551622309507 ], [ -88.3653759433451, 13.539380601133814 ], [ -88.365427619289164, 13.541783556365999 ], [ -88.36671952958261, 13.545478420092991 ], [ -88.378811814713458, 13.570386460766542 ], [ -88.379586961968698, 13.573125311883643 ], [ -88.379948697174598, 13.575967515788193 ], [ -88.380155401850288, 13.58188446669476 ], [ -88.379690313856884, 13.584855861808535 ], [ -88.378837653135179, 13.587439683294747 ], [ -88.377752448416743, 13.589661770474322 ], [ -88.376124641339118, 13.591522122447998 ], [ -88.373825038894438, 13.592710679953882 ], [ -88.368399014402996, 13.594467678240733 ], [ -88.366151088801701, 13.595578722280209 ], [ -88.364497443302355, 13.597361558089403 ], [ -88.36307634090042, 13.599428616537409 ], [ -88.362068651447089, 13.601909085236059 ], [ -88.361681077819469, 13.604596259509776 ], [ -88.362223680178658, 13.608187771348582 ], [ -88.363515591371424, 13.612296047124858 ], [ -88.366357795276031, 13.6192982045485 ], [ -88.368321499137835, 13.627747300997157 ], [ -88.368269823193771, 13.630692856789892 ], [ -88.367753059256245, 13.633638414381323 ], [ -88.362998827433898, 13.646557521812156 ], [ -88.362921312168794, 13.649399725716762 ], [ -88.366254441589206, 13.651957708781197 ], [ -88.372429775813487, 13.653843899176593 ], [ -88.396795214127792, 13.656789455868704 ], [ -88.404546677686994, 13.65937327735486 ], [ -88.413202480609982, 13.665445257892316 ], [ -88.420075445925079, 13.671749783325822 ], [ -88.428421189586231, 13.68461721391327 ], [ -88.434544846967071, 13.692136135274382 ], [ -88.44648210336635, 13.692833767264517 ], [ -88.48733232342795, 13.688260403494837 ], [ -88.498830329356224, 13.705727037173006 ], [ -88.529655320936286, 13.735828559240588 ], [ -88.532342495209946, 13.759367174355589 ], [ -88.532394172053387, 13.759651394296384 ], [ -88.523247442715274, 13.776911322399599 ], [ -88.513919847123248, 13.790838121082402 ], [ -88.516012743093597, 13.804713242921821 ], [ -88.505315721043701, 13.811431179505291 ], [ -88.498210211731873, 13.821404731143389 ], [ -88.496789110229258, 13.833264472277563 ], [ -88.50296444355422, 13.845692654192646 ], [ -88.498675299725278, 13.849568385972248 ], [ -88.496815755342823, 13.851197002439676 ], [ -88.470150715999864, 13.852488912000098 ], [ -88.451443847999883, 13.863573507000098 ], [ -88.433227905999843, 13.871066590000041 ], [ -88.392946126999902, 13.879774068000103 ], [ -88.383360148999884, 13.879257304000063 ], [ -88.36741796899986, 13.873107809000089 ], [ -88.360105753999875, 13.872384338000103 ], [ -88.358917195999936, 13.87527821900008 ], [ -88.358917195999936, 13.881195170000098 ], [ -88.358193725999854, 13.887396343000077 ], [ -88.355067301999895, 13.890962016000046 ], [ -88.348556071999923, 13.891375427000057 ], [ -88.340572062999854, 13.890031840000091 ], [ -88.332613891999898, 13.887706401000059 ], [ -88.326206014999855, 13.885070903000056 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-UN", "NAME_1": "La Unión" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -87.817890787999943, 13.915870057000106 ], [ -87.808459839999898, 13.908635356000048 ], [ -87.798718831999935, 13.882332051000105 ], [ -87.790605631999938, 13.870472310000082 ], [ -87.785412150999917, 13.86739756200005 ], [ -87.771433674999912, 13.862126567000104 ], [ -87.765335855999865, 13.858870952000117 ], [ -87.749528722999912, 13.845627388000096 ], [ -87.721204183999873, 13.821896464000076 ], [ -87.703608357999883, 13.814997661000106 ], [ -87.712625895999849, 13.800450745000148 ], [ -87.732805541999937, 13.75510467600013 ], [ -87.737843993999888, 13.738774923000094 ], [ -87.731358602999933, 13.72221262700009 ], [ -87.73629370099988, 13.711463929000075 ], [ -87.746318929999887, 13.702188009000054 ], [ -87.755026407999964, 13.689914857000119 ], [ -87.758643757999948, 13.672267355000116 ], [ -87.757816935999926, 13.635163676000047 ], [ -87.760090698999932, 13.616947734000092 ], [ -87.784068563999938, 13.560465394000047 ], [ -87.789933838999843, 13.53281850200004 ], [ -87.779469360999911, 13.509977519000131 ], [ -87.769159911999907, 13.506360168000057 ], [ -87.747972574999949, 13.513233135000107 ], [ -87.733425659999909, 13.507703756000112 ], [ -87.725725871999913, 13.498970439000047 ], [ -87.720584065999901, 13.486981507000081 ], [ -87.718801228999922, 13.473674825000074 ], [ -87.721152506999942, 13.460833232000084 ], [ -87.738412434999958, 13.441687113000071 ], [ -87.817168748999904, 13.40656159100007 ], [ -87.817860480999911, 13.406805731000077 ], [ -87.825713670999903, 13.411281643000052 ], [ -87.830677863999938, 13.419501044000071 ], [ -87.838286912999934, 13.44094472900008 ], [ -87.866444464999915, 13.393337307000081 ], [ -87.873768683999913, 13.365261135000083 ], [ -87.855376756999931, 13.352809963000084 ], [ -87.843617316999939, 13.348456122000073 ], [ -87.810414191999939, 13.317409572000088 ], [ -87.791533982999908, 13.304958401000079 ], [ -87.789906378999945, 13.299099026000079 ], [ -87.789906378999945, 13.287014065000051 ], [ -87.798085089999915, 13.265651760000083 ], [ -87.817982550999943, 13.250392971000053 ], [ -87.892323370999918, 13.213893947000088 ], [ -87.912464972999942, 13.198187567000048 ], [ -87.916005011999914, 13.182196356000077 ], [ -87.892933722999942, 13.166571356000077 ], [ -87.928212042999917, 13.158636786000045 ], [ -88.066029425999943, 13.167873440000051 ], [ -88.091470945800239, 13.172705728065043 ], [ -88.091465012999947, 13.172787991372672 ], [ -88.085961473243401, 13.251103624332757 ], [ -88.084617886106514, 13.258855088791279 ], [ -88.081982387776975, 13.268673610798487 ], [ -88.079889492705888, 13.267820950076782 ], [ -88.071672940253961, 13.261878159849175 ], [ -88.063068814174414, 13.256813870563633 ], [ -88.052552660177128, 13.253170680982123 ], [ -88.049322882644901, 13.252550564257149 ], [ -88.045963914802826, 13.252498888313028 ], [ -88.041313035767985, 13.253868312972259 ], [ -88.038935919856783, 13.256219591361059 ], [ -88.025887621216725, 13.297922472144364 ], [ -88.02518998922659, 13.304020291103541 ], [ -88.02674028193843, 13.309885566065986 ], [ -88.027050341200265, 13.314019680264039 ], [ -88.014234584758242, 13.385953274324152 ], [ -88.014647996807582, 13.388356227757697 ], [ -88.015500658428607, 13.390836697355667 ], [ -88.016663378412147, 13.393239650789212 ], [ -88.026042649948295, 13.407760727775326 ], [ -88.027257045875956, 13.410163683007568 ], [ -88.028238897806887, 13.412747504493723 ], [ -88.031132778554877, 13.430343329381117 ], [ -88.031597867447601, 13.456000677988868 ], [ -88.030771044248297, 13.46240855620988 ], [ -88.029220750637137, 13.466439316721051 ], [ -88.027360398663461, 13.467912095966426 ], [ -88.023019578890455, 13.470315050299291 ], [ -88.020306566195075, 13.472201238896048 ], [ -88.017516039133909, 13.474552517284849 ], [ -88.013795336085877, 13.478945013901239 ], [ -88.012787644833907, 13.482381497008475 ], [ -88.012787644833907, 13.485611274540645 ], [ -88.016663378412147, 13.50000316031759 ], [ -88.017205979872074, 13.530233872695078 ], [ -88.015061407957603, 13.542868761084435 ], [ -88.008550177848406, 13.551447047842942 ], [ -87.977595995059119, 13.583744819567755 ], [ -87.970257940851297, 13.594545193505837 ], [ -87.968552619407831, 13.613329575899172 ], [ -87.945634121017861, 13.671052151335687 ], [ -87.939613817323789, 13.697975571815164 ], [ -87.936668259732357, 13.721204128567649 ], [ -87.936358202269219, 13.740298570222819 ], [ -87.937365891722493, 13.746344713237932 ], [ -87.938141038977733, 13.748851020358302 ], [ -87.939122890908664, 13.751228136269447 ], [ -87.940518154888935, 13.753424384128039 ], [ -87.94503984181523, 13.759108791937194 ], [ -87.946254238642155, 13.761227525429945 ], [ -87.94695186973297, 13.763914699703605 ], [ -87.947210253050741, 13.767170314758232 ], [ -87.943076137953369, 13.827890122830865 ], [ -87.94503984181523, 13.856131292924829 ], [ -87.949380663386876, 13.872409369097113 ], [ -87.952594894338858, 13.892029035511541 ], [ -87.946926839999918, 13.890910339000129 ], [ -87.932173217999889, 13.881556905000096 ], [ -87.925326090999931, 13.879619039000062 ], [ -87.920752725999904, 13.881866963000078 ], [ -87.907885294999886, 13.891530457000101 ], [ -87.900107991999874, 13.894140117000106 ], [ -87.890108602999959, 13.893545837000147 ], [ -87.87054907299995, 13.889566752000064 ], [ -87.860911417999944, 13.890186870000036 ], [ -87.851222087999901, 13.896878968000053 ], [ -87.842953857999959, 13.907110901000038 ], [ -87.832902791999913, 13.915249939000134 ], [ -87.817890787999943, 13.915870057000106 ] ] ], [ [ [ -87.726293426999916, 13.198387437000065 ], [ -87.727187439999909, 13.211114757000075 ], [ -87.719913325999926, 13.216190972000049 ], [ -87.706086587999948, 13.211726236000061 ], [ -87.697564970999906, 13.193313885000066 ], [ -87.696996275999936, 13.178063536000082 ], [ -87.693193511999937, 13.167862440000079 ], [ -87.701673410999945, 13.163412359000063 ], [ -87.714584805999948, 13.167903057000046 ], [ -87.723110910999935, 13.164077582000061 ], [ -87.723028398999929, 13.174895253000045 ], [ -87.728351879999934, 13.185678928000073 ], [ -87.726293426999916, 13.198387437000065 ] ] ], [ [ [ -87.765782054999931, 13.248011011000074 ], [ -87.757933196999943, 13.243557905000046 ], [ -87.751386787999934, 13.228924729000084 ], [ -87.757267368999919, 13.220651650000036 ], [ -87.763804817999926, 13.214287112000079 ], [ -87.776890196999943, 13.225736371000039 ], [ -87.780168819999915, 13.241643430000067 ], [ -87.774286185999927, 13.247372301000041 ], [ -87.765782054999931, 13.248011011000074 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-SO", "NAME_1": "Sonsonate" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.609424675506958, 13.513063056996836 ], [ -89.616352566999922, 13.514382675000093 ], [ -89.67976587499993, 13.534732428000041 ], [ -89.713127605999944, 13.527996506000079 ], [ -89.80804823099993, 13.526857633000077 ], [ -89.823296528999947, 13.537140191000049 ], [ -89.833376673999908, 13.573887876000072 ], [ -89.837147589999915, 13.596828518000052 ], [ -89.849662051999928, 13.606876111000076 ], [ -89.870262593999939, 13.619275773000084 ], [ -89.951318273999902, 13.664110063000066 ], [ -89.953482681905044, 13.665072624253359 ], [ -89.951222297371089, 13.668778388212047 ], [ -89.935331793927105, 13.693143826526352 ], [ -89.927838710987714, 13.701851305393404 ], [ -89.925022346404148, 13.704176744461165 ], [ -89.922593552750243, 13.70580455243811 ], [ -89.919622159435107, 13.70714813957494 ], [ -89.916289029115376, 13.708207505871712 ], [ -89.910552945362099, 13.709241033746707 ], [ -89.906522183052289, 13.709241033746707 ], [ -89.902982347157604, 13.708853461018407 ], [ -89.900295172883887, 13.707923285031541 ], [ -89.897892218551021, 13.706838080313162 ], [ -89.893758104353026, 13.704047553251939 ], [ -89.891768562069444, 13.702419745274995 ], [ -89.878668585686682, 13.687717800236271 ], [ -89.871408046743966, 13.6809740261304 ], [ -89.869418505359704, 13.679604600571849 ], [ -89.863243171135423, 13.678338527800804 ], [ -89.833064133802736, 13.676659043879738 ], [ -89.824770066984968, 13.677718411075773 ], [ -89.819757452744227, 13.679682114937634 ], [ -89.814098884256111, 13.701928818859869 ], [ -89.81226436980478, 13.70676056594732 ], [ -89.799448615161452, 13.729188137022902 ], [ -89.798621791962091, 13.731720282564993 ], [ -89.798053352080501, 13.74091868694785 ], [ -89.796451381625957, 13.745207830776735 ], [ -89.793531664254886, 13.750608017745833 ], [ -89.785935227628613, 13.759341335933868 ], [ -89.782963833414158, 13.764095566856895 ], [ -89.781594407855607, 13.768048813901601 ], [ -89.782653775051642, 13.773604031400907 ], [ -89.79110287060098, 13.799597275893575 ], [ -89.79056026914111, 13.803602199781665 ], [ -89.788699917167435, 13.809028225172426 ], [ -89.768339402741219, 13.83920726250517 ], [ -89.767745124437909, 13.84266958313475 ], [ -89.768649462003054, 13.844995022202511 ], [ -89.771000738593216, 13.849594224393911 ], [ -89.772835253044491, 13.854141751540567 ], [ -89.774488897644517, 13.859955348760309 ], [ -89.776866013555662, 13.878662217687179 ], [ -89.776633469558931, 13.882899685571999 ], [ -89.775625780105656, 13.889281724471971 ], [ -89.773481208191185, 13.892149765898978 ], [ -89.770716518652421, 13.893984280350253 ], [ -89.758546719155731, 13.895792955480488 ], [ -89.736584235174291, 13.901709906387055 ], [ -89.718833380655951, 13.908970445329771 ], [ -89.695553147959401, 13.903286038419935 ], [ -89.686587286673898, 13.90357025836073 ], [ -89.681109585339073, 13.904991359863345 ], [ -89.678086514281176, 13.905378933490965 ], [ -89.674908412693071, 13.905378933490965 ], [ -89.67025753455755, 13.90318268473311 ], [ -89.664443936438488, 13.899022732113394 ], [ -89.648217536210325, 13.883597317562135 ], [ -89.645246141096493, 13.879618232095709 ], [ -89.642093878829428, 13.872486884362218 ], [ -89.639871791649853, 13.869593004513547 ], [ -89.636745367804451, 13.866208197350431 ], [ -89.630621711322874, 13.860704656694509 ], [ -89.626177537863043, 13.853676663547162 ], [ -89.625092333144664, 13.848509018776156 ], [ -89.625324877141338, 13.845692654192646 ], [ -89.626125861019659, 13.842927965553145 ], [ -89.627417772212425, 13.840680039951849 ], [ -89.628968064924265, 13.838948879187399 ], [ -89.632817959181466, 13.835874132185438 ], [ -89.634523282423515, 13.833936265845978 ], [ -89.635686000608416, 13.831714179565722 ], [ -89.636125251079477, 13.829207872445352 ], [ -89.634833339886711, 13.827063300530881 ], [ -89.631603563253805, 13.8250995957697 ], [ -89.625376553085459, 13.82396271420788 ], [ -89.620803189315723, 13.819389350438144 ], [ -89.618426073404521, 13.816082058540132 ], [ -89.617263353420981, 13.812981472217132 ], [ -89.616023119071656, 13.810656033149371 ], [ -89.614317796728926, 13.808821518698096 ], [ -89.612121547971071, 13.807116197254686 ], [ -89.608891771338165, 13.80585012538296 ], [ -89.604163377937539, 13.804919949396151 ], [ -89.596980354259927, 13.806573594895497 ], [ -89.59336300310008, 13.808356432503331 ], [ -89.591115078398104, 13.810630194727707 ], [ -89.59046912325141, 13.813058987482293 ], [ -89.59049496077381, 13.82202484786842 ], [ -89.589177212058644, 13.827528388524286 ], [ -89.585973272948195, 13.834556383470328 ], [ -89.583311937096198, 13.83881968797823 ], [ -89.581580777231068, 13.840680039951849 ], [ -89.579642910891607, 13.84207530393212 ], [ -89.576929898196227, 13.842747097500535 ], [ -89.570134447246915, 13.839827379230144 ], [ -89.560470953971333, 13.834194648264372 ], [ -89.539335293189197, 13.818872586500675 ], [ -89.526054449653088, 13.80678030047045 ], [ -89.520008308436672, 13.792155869797512 ], [ -89.518638881978802, 13.790088813148202 ], [ -89.517036913322897, 13.788150946808742 ], [ -89.504272833724258, 13.783939317345585 ], [ -89.456627162713346, 13.775076808847643 ], [ -89.445206672050233, 13.771588649796342 ], [ -89.442777880195024, 13.770425929812802 ], [ -89.440710821747018, 13.768953152366066 ], [ -89.438979661881888, 13.767377021232505 ], [ -89.437661913166721, 13.765309962784556 ], [ -89.436654221914807, 13.76285533340689 ], [ -89.436163296399002, 13.760064806345724 ], [ -89.437584397901617, 13.756395779241814 ], [ -89.440297410596997, 13.752442532197108 ], [ -89.447480435173929, 13.74626719797277 ], [ -89.453784959708116, 13.74184886293466 ], [ -89.468538580690904, 13.733528957695228 ], [ -89.473964606081665, 13.728568020297871 ], [ -89.485798508794119, 13.714486191984179 ], [ -89.489829271103986, 13.711359768138777 ], [ -89.493756679726971, 13.709680284217711 ], [ -89.500758837150613, 13.709060167492737 ], [ -89.502980923430869, 13.708440049868386 ], [ -89.507089200106464, 13.706114609901306 ], [ -89.509078742390045, 13.704331773192791 ], [ -89.5112749911479, 13.70063690856648 ], [ -89.513497077428156, 13.695210883175719 ], [ -89.516442634120267, 13.683299465198161 ], [ -89.518018765253771, 13.671749783325822 ], [ -89.516726854061062, 13.649709784079278 ], [ -89.516985235580137, 13.646402493080586 ], [ -89.519672410753117, 13.641544908470735 ], [ -89.524633348150473, 13.635007839040497 ], [ -89.546389125657583, 13.613794663892634 ], [ -89.548456184105589, 13.612399399912363 ], [ -89.550471563911515, 13.610435696050502 ], [ -89.552745327035211, 13.607257595361716 ], [ -89.555122442946356, 13.602348333908481 ], [ -89.556982794920032, 13.594002590247328 ], [ -89.558300543635141, 13.581961981959864 ], [ -89.561013557229842, 13.577931220549374 ], [ -89.565431892268009, 13.572970282252697 ], [ -89.590727504770484, 13.551395371898877 ], [ -89.596076015795461, 13.54294627545022 ], [ -89.606669685057909, 13.519355984391154 ], [ -89.609424675506958, 13.513063056996836 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-LI", "NAME_1": "La Libertad" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.135715548042128, 13.414457692887732 ], [ -89.183501756999931, 13.443060614000046 ], [ -89.251454230999911, 13.472316799000055 ], [ -89.32485917899993, 13.489325262000079 ], [ -89.358998175999943, 13.489325262000079 ], [ -89.38499915299991, 13.495306708000044 ], [ -89.527066724999941, 13.494173340000089 ], [ -89.587790098999903, 13.508942124000043 ], [ -89.609424675506958, 13.513063056996836 ], [ -89.606669685057909, 13.519355984391154 ], [ -89.596076015795461, 13.54294627545022 ], [ -89.590727504770484, 13.551395371898877 ], [ -89.565431892268009, 13.572970282252697 ], [ -89.561013557229842, 13.577931220549374 ], [ -89.558300543635141, 13.581961981959864 ], [ -89.556982794920032, 13.594002590247328 ], [ -89.555122442946356, 13.602348333908481 ], [ -89.552745327035211, 13.607257595361716 ], [ -89.550471563911515, 13.610435696050502 ], [ -89.548456184105589, 13.612399399912363 ], [ -89.546389125657583, 13.613794663892634 ], [ -89.524633348150473, 13.635007839040497 ], [ -89.519672410753117, 13.641544908470735 ], [ -89.516985235580137, 13.646402493080586 ], [ -89.516726854061062, 13.649709784079278 ], [ -89.518018765253771, 13.671749783325822 ], [ -89.516442634120267, 13.683299465198161 ], [ -89.513497077428156, 13.695210883175719 ], [ -89.5112749911479, 13.70063690856648 ], [ -89.509078742390045, 13.704331773192791 ], [ -89.507089200106464, 13.706114609901306 ], [ -89.502980923430869, 13.708440049868386 ], [ -89.500758837150613, 13.709060167492737 ], [ -89.493756679726971, 13.709680284217711 ], [ -89.489829271103986, 13.711359768138777 ], [ -89.485798508794119, 13.714486191984179 ], [ -89.473964606081665, 13.728568020297871 ], [ -89.468538580690904, 13.733528957695228 ], [ -89.453784959708116, 13.74184886293466 ], [ -89.447480435173929, 13.74626719797277 ], [ -89.440297410596997, 13.752442532197108 ], [ -89.437584397901617, 13.756395779241814 ], [ -89.436163296399002, 13.760064806345724 ], [ -89.436654221914807, 13.76285533340689 ], [ -89.437661913166721, 13.765309962784556 ], [ -89.438979661881888, 13.767377021232505 ], [ -89.440710821747018, 13.768953152366066 ], [ -89.442777880195024, 13.770425929812802 ], [ -89.445206672050233, 13.771588649796342 ], [ -89.456627162713346, 13.775076808847643 ], [ -89.452002122999545, 13.80293040621325 ], [ -89.434457974056215, 13.849490872505726 ], [ -89.432597622082596, 13.870755724497087 ], [ -89.433424445281901, 13.888790798056846 ], [ -89.432106695667471, 13.915585029125793 ], [ -89.43089229973981, 13.921166083248124 ], [ -89.429342007027969, 13.923078111165864 ], [ -89.427223272635899, 13.924447536724415 ], [ -89.424820319202354, 13.925067654348766 ], [ -89.422133144928694, 13.924860947874436 ], [ -89.419626837808323, 13.924085802417835 ], [ -89.416836310747101, 13.924473375146135 ], [ -89.41355485727081, 13.926540431795502 ], [ -89.405570847916294, 13.939020291453289 ], [ -89.403452115322864, 13.940105496171668 ], [ -89.400687424884723, 13.94038971611252 ], [ -89.397380133886031, 13.940312200847359 ], [ -89.393659430838056, 13.94054474484409 ], [ -89.38854346380981, 13.942740994501264 ], [ -89.386295539107834, 13.945428167875605 ], [ -89.385210334389399, 13.948554591721006 ], [ -89.383660040778238, 13.9677265495406 ], [ -89.383918423196633, 13.970827134964281 ], [ -89.382187263331502, 13.98527069758461 ], [ -89.37136105007238, 14.04059031778894 ], [ -89.367020230299374, 14.047411607159916 ], [ -89.363816291188868, 14.054232896530948 ], [ -89.355496385050117, 14.057333481954629 ], [ -89.343688320759384, 14.059555569134204 ], [ -89.334567429842991, 14.064438992165719 ], [ -89.324774746257503, 14.071622015843332 ], [ -89.314439460312826, 14.069606635138086 ], [ -89.296404384954371, 14.059633084399309 ], [ -89.280074632838023, 14.057333481954629 ], [ -89.276819016884076, 14.056377468445419 ], [ -89.26731055413876, 14.052114163038198 ], [ -89.26844743480126, 14.018421129131809 ], [ -89.273795945826237, 13.996949571565438 ], [ -89.274106005088072, 13.991549383697077 ], [ -89.273330857832832, 13.987983710279991 ], [ -89.26731055413876, 13.983410346510254 ], [ -89.264907599805895, 13.979948024981354 ], [ -89.262013719057848, 13.974702866743883 ], [ -89.257026944138147, 13.963385727968955 ], [ -89.254055549024372, 13.957985540999914 ], [ -89.251316697907271, 13.954419867582828 ], [ -89.247105069343434, 13.951758530831512 ], [ -89.242376675043488, 13.949536445450576 ], [ -89.234263475379066, 13.947159329539431 ], [ -89.231266241843571, 13.946978461486822 ], [ -89.222041999038993, 13.947701930999301 ], [ -89.218889736771928, 13.947598578211796 ], [ -89.215918341658096, 13.947211005483496 ], [ -89.213076137753546, 13.946539211015761 ], [ -89.210363125058166, 13.945583197506551 ], [ -89.207133348425259, 13.943800360797979 ], [ -89.203490159743069, 13.940854804105925 ], [ -89.198141648718092, 13.938090115466423 ], [ -89.196591356006252, 13.936048896339457 ], [ -89.196203783277952, 13.934369412418448 ], [ -89.198839280708228, 13.927806505465867 ], [ -89.200157030322657, 13.922199612022439 ], [ -89.200544603050957, 13.920959376773794 ], [ -89.201371426250319, 13.920313422526419 ], [ -89.208838670768046, 13.92052012810143 ], [ -89.211422492254201, 13.919822496111294 ], [ -89.213282844227876, 13.918065496925124 ], [ -89.214316372102871, 13.914809881870553 ], [ -89.219328986343612, 13.859025172773499 ], [ -89.220775926267947, 13.853366604285327 ], [ -89.221886970307423, 13.851092841161687 ], [ -89.223928189434389, 13.849723416502457 ], [ -89.229069993985036, 13.847863064528781 ], [ -89.231266241843571, 13.846545314914351 ], [ -89.233333300291577, 13.845020859724855 ], [ -89.236356371349416, 13.841274319154479 ], [ -89.238371752054718, 13.836468411388068 ], [ -89.239586147982322, 13.831714179565722 ], [ -89.241446499056678, 13.814273383409898 ], [ -89.243539395027028, 13.806547756473776 ], [ -89.246795010081655, 13.799209703165275 ], [ -89.248629522734291, 13.789985460360697 ], [ -89.249818081139495, 13.773991604129208 ], [ -89.250670742760576, 13.769728297822667 ], [ -89.251420050694776, 13.767221990702296 ], [ -89.258318855330913, 13.754561265689858 ], [ -89.262685512626263, 13.742081406931391 ], [ -89.262375454263804, 13.738076483942564 ], [ -89.260566779133512, 13.735983587972214 ], [ -89.258008796069078, 13.735311794403799 ], [ -89.254779019436171, 13.735053411985348 ], [ -89.24976640519543, 13.728723049029497 ], [ -89.250748257126361, 13.71874949829072 ], [ -89.250050625136225, 13.709241033746707 ], [ -89.24896542041779, 13.706734727525657 ], [ -89.247595994859239, 13.70464183245457 ], [ -89.245942349359893, 13.702703966115109 ], [ -89.242092455102693, 13.699939277475664 ], [ -89.240206264707354, 13.697510483821759 ], [ -89.238991868779692, 13.694151515979684 ], [ -89.237157355227737, 13.686322537155377 ], [ -89.235658739359337, 13.681981716482994 ], [ -89.23374671144154, 13.67906199821266 ], [ -89.231576301105406, 13.67751170550082 ], [ -89.217184414429141, 13.670018622561372 ], [ -89.215453253664691, 13.668881740999552 ], [ -89.211164109835806, 13.6651351995298 ], [ -89.204472011674, 13.656479397506189 ], [ -89.203490159743069, 13.652655340771332 ], [ -89.203800218105584, 13.649580592870052 ], [ -89.207081671581875, 13.643611965120101 ], [ -89.209407110649636, 13.638134263785219 ], [ -89.209303757862131, 13.635033678361538 ], [ -89.207133348425259, 13.632785752760242 ], [ -89.199459398332522, 13.629220079343156 ], [ -89.198270839927318, 13.626817125010291 ], [ -89.198761766342443, 13.624595037830716 ], [ -89.200389574319388, 13.622631333968855 ], [ -89.202404955024633, 13.621081041257014 ], [ -89.203800218105584, 13.615370795026138 ], [ -89.204575365360824, 13.606017361012391 ], [ -89.202715013387149, 13.564676215434986 ], [ -89.203180101380553, 13.561523953167864 ], [ -89.209432949970619, 13.545736803410762 ], [ -89.211680873773275, 13.537132677331158 ], [ -89.212042608979232, 13.532404283031212 ], [ -89.211448329776601, 13.528683579983237 ], [ -89.195428636022712, 13.50346548094717 ], [ -89.189770066635276, 13.491579902290653 ], [ -89.18829728918854, 13.489693711895256 ], [ -89.186075202008965, 13.488479315967652 ], [ -89.183155483738574, 13.488117580761752 ], [ -89.180003220572132, 13.488272610392642 ], [ -89.174396328028081, 13.489564520686088 ], [ -89.163931850874178, 13.492975165371547 ], [ -89.157989060646628, 13.493672797361683 ], [ -89.154268357598596, 13.493181870946557 ], [ -89.151736212955825, 13.492484238956422 ], [ -89.144372321225603, 13.489254462323572 ], [ -89.140884162174302, 13.472976386151288 ], [ -89.137861091116463, 13.468816433531572 ], [ -89.135458136783541, 13.468919786319077 ], [ -89.131272345742161, 13.468687242322346 ], [ -89.125742966664575, 13.467447007973021 ], [ -89.115898607134966, 13.46354543687238 ], [ -89.112668829602796, 13.4601089537652 ], [ -89.111867844825156, 13.457292589181634 ], [ -89.114425828788967, 13.452951768509308 ], [ -89.119231736555378, 13.447189846334311 ], [ -89.120523647748144, 13.445148627207345 ], [ -89.122073941359304, 13.443236599289605 ], [ -89.12987708176189, 13.429749050178486 ], [ -89.132667608823056, 13.423780422428536 ], [ -89.135690680780272, 13.414530341202294 ], [ -89.135715548042128, 13.414457692887732 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-PA", "NAME_1": "La Paz" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.831558195814722, 13.266079643793562 ], [ -89.064808722999942, 13.372015692000048 ], [ -89.135715548042128, 13.414457692887732 ], [ -89.135690680780272, 13.414530341202294 ], [ -89.132667608823056, 13.423780422428536 ], [ -89.12987708176189, 13.429749050178486 ], [ -89.122073941359304, 13.443236599289605 ], [ -89.120523647748144, 13.445148627207345 ], [ -89.119231736555378, 13.447189846334311 ], [ -89.114425828788967, 13.452951768509308 ], [ -89.111867844825156, 13.457292589181634 ], [ -89.112668829602796, 13.4601089537652 ], [ -89.115898607134966, 13.46354543687238 ], [ -89.125742966664575, 13.467447007973021 ], [ -89.131272345742161, 13.468687242322346 ], [ -89.135458136783541, 13.468919786319077 ], [ -89.137861091116463, 13.468816433531572 ], [ -89.140884162174302, 13.472976386151288 ], [ -89.144372321225603, 13.489254462323572 ], [ -89.142201910889469, 13.497677721249829 ], [ -89.139230515775637, 13.499563909846529 ], [ -89.132073329620425, 13.507341212726772 ], [ -89.126957364390819, 13.517960720410883 ], [ -89.118456591098777, 13.542739569875209 ], [ -89.116208666396801, 13.553539943813348 ], [ -89.115666063138292, 13.560567938759334 ], [ -89.117603928578433, 13.565477200212626 ], [ -89.12527787957049, 13.578680528483574 ], [ -89.128197597840824, 13.586716212882891 ], [ -89.130032111392836, 13.595397854227599 ], [ -89.129592861821095, 13.599997057318319 ], [ -89.12817176031848, 13.603149318686121 ], [ -89.125949673138905, 13.604363715513045 ], [ -89.123236661342844, 13.604854641028851 ], [ -89.120058559754739, 13.604854641028851 ], [ -89.116983811853402, 13.604467068300551 ], [ -89.101015794942953, 13.599351101272305 ], [ -89.097941047041672, 13.5988860132789 ], [ -89.094892136662736, 13.598730984547274 ], [ -89.08980200895553, 13.60252920196109 ], [ -89.059726325309668, 13.6397362333405 ], [ -89.023578661126294, 13.672938340831763 ], [ -88.979550341275228, 13.657228705440389 ], [ -88.962238736328629, 13.648185329789101 ], [ -88.94335100024847, 13.642294216404935 ], [ -88.939940354663634, 13.642449246035881 ], [ -88.935470343681402, 13.643095201182575 ], [ -88.933506638920221, 13.643663641963485 ], [ -88.931336228584087, 13.644671332316136 ], [ -88.929785935872246, 13.646531684289812 ], [ -88.927563849591991, 13.651337592056223 ], [ -88.925961880036709, 13.653197944029898 ], [ -88.923791469700575, 13.654412339957503 ], [ -88.921078457005194, 13.655213323835824 ], [ -88.908546923201925, 13.656686103081199 ], [ -88.903017544124339, 13.658546454155498 ], [ -88.896067064443457, 13.662577216465365 ], [ -88.88857398060469, 13.642940172451006 ], [ -88.888238084719831, 13.626507065748456 ], [ -88.88934912785993, 13.609583035328797 ], [ -88.888263923141494, 13.602761745957821 ], [ -88.886377732746155, 13.598756822069674 ], [ -88.883277147322474, 13.598420925285438 ], [ -88.880073208211968, 13.5984984405506 ], [ -88.876946784366567, 13.5988860132789 ], [ -88.853046434045666, 13.606172389743961 ], [ -88.848938158269391, 13.606379096218291 ], [ -88.844390632022055, 13.605629788284091 ], [ -88.836509976354307, 13.602761745957821 ], [ -88.833848639602991, 13.599506130003874 ], [ -88.80919898134789, 13.548113919321906 ], [ -88.808475510936091, 13.545323391361421 ], [ -88.80803626226367, 13.54240367309103 ], [ -88.80824296693936, 13.535995794870018 ], [ -88.809483202188005, 13.530233872695078 ], [ -88.817157152280743, 13.509821682324741 ], [ -88.817699754639932, 13.507444566413596 ], [ -88.818552416260957, 13.505119127345836 ], [ -88.819250048251092, 13.50191518823533 ], [ -88.819405076982719, 13.500364895523489 ], [ -88.819405076982719, 13.500054836261654 ], [ -88.823409999971489, 13.478169867545319 ], [ -88.823565029602435, 13.473622341297983 ], [ -88.822118089678099, 13.456233221985599 ], [ -88.820800340962933, 13.450548814176443 ], [ -88.819353400139278, 13.446414699978391 ], [ -88.812816331608417, 13.439335029088284 ], [ -88.806796027015025, 13.434709988475163 ], [ -88.798062709726253, 13.429516506181812 ], [ -88.791163906888755, 13.42308279133772 ], [ -88.78452348467107, 13.414814561143089 ], [ -88.782275559969094, 13.409698595014106 ], [ -88.781319545560564, 13.405461127129286 ], [ -88.781629604822399, 13.402360540806285 ], [ -88.782973191959229, 13.396650295474728 ], [ -88.783825852680934, 13.394221502720143 ], [ -88.78514360229542, 13.392076930805672 ], [ -88.791189745310476, 13.387451891091871 ], [ -88.792843390809821, 13.385720730327421 ], [ -88.794109462681547, 13.38357615841295 ], [ -88.794962124302572, 13.380992336027475 ], [ -88.795401373874313, 13.378046780234683 ], [ -88.795556402605882, 13.374817002702514 ], [ -88.791034715679586, 13.333966783540234 ], [ -88.791318935620382, 13.328308214152742 ], [ -88.792610846813091, 13.326060289450766 ], [ -88.794161140424251, 13.324199937477147 ], [ -88.796176521129553, 13.322365423925135 ], [ -88.798269416200583, 13.32097015994492 ], [ -88.807493659005161, 13.316474311440288 ], [ -88.814857550735383, 13.313606269114018 ], [ -88.819327561717557, 13.311125800415368 ], [ -88.823177455974815, 13.308025214092368 ], [ -88.82480526395176, 13.306113186174571 ], [ -88.826200527931974, 13.304046129525261 ], [ -88.827414923859635, 13.301643175192339 ], [ -88.828370938268165, 13.299136868071969 ], [ -88.829120246202365, 13.296294664167419 ], [ -88.831549038057631, 13.266193142099837 ], [ -88.831558195814722, 13.266079643793562 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-SV", "NAME_1": "San Vicente" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.81663977799991, 13.25930410400008 ], [ -88.831558195814722, 13.266079643793562 ], [ -88.831549038057631, 13.266193142099837 ], [ -88.829120246202365, 13.296294664167419 ], [ -88.828370938268165, 13.299136868071969 ], [ -88.827414923859635, 13.301643175192339 ], [ -88.826200527931974, 13.304046129525261 ], [ -88.82480526395176, 13.306113186174571 ], [ -88.823177455974815, 13.308025214092368 ], [ -88.819327561717557, 13.311125800415368 ], [ -88.814857550735383, 13.313606269114018 ], [ -88.807493659005161, 13.316474311440288 ], [ -88.798269416200583, 13.32097015994492 ], [ -88.796176521129553, 13.322365423925135 ], [ -88.794161140424251, 13.324199937477147 ], [ -88.792610846813091, 13.326060289450766 ], [ -88.791318935620382, 13.328308214152742 ], [ -88.791034715679586, 13.333966783540234 ], [ -88.795556402605882, 13.374817002702514 ], [ -88.795401373874313, 13.378046780234683 ], [ -88.794962124302572, 13.380992336027475 ], [ -88.794109462681547, 13.38357615841295 ], [ -88.792843390809821, 13.385720730327421 ], [ -88.791189745310476, 13.387451891091871 ], [ -88.78514360229542, 13.392076930805672 ], [ -88.783825852680934, 13.394221502720143 ], [ -88.782973191959229, 13.396650295474728 ], [ -88.781629604822399, 13.402360540806285 ], [ -88.781319545560564, 13.405461127129286 ], [ -88.782275559969094, 13.409698595014106 ], [ -88.78452348467107, 13.414814561143089 ], [ -88.791163906888755, 13.42308279133772 ], [ -88.798062709726253, 13.429516506181812 ], [ -88.806796027015025, 13.434709988475163 ], [ -88.812816331608417, 13.439335029088284 ], [ -88.819353400139278, 13.446414699978391 ], [ -88.820800340962933, 13.450548814176443 ], [ -88.822118089678099, 13.456233221985599 ], [ -88.823565029602435, 13.473622341297983 ], [ -88.823409999971489, 13.478169867545319 ], [ -88.819405076982719, 13.500054836261654 ], [ -88.819405076982719, 13.500364895523489 ], [ -88.819250048251092, 13.50191518823533 ], [ -88.818552416260957, 13.505119127345836 ], [ -88.817699754639932, 13.507444566413596 ], [ -88.817157152280743, 13.509821682324741 ], [ -88.809483202188005, 13.530233872695078 ], [ -88.80824296693936, 13.535995794870018 ], [ -88.80803626226367, 13.54240367309103 ], [ -88.808475510936091, 13.545323391361421 ], [ -88.80919898134789, 13.548113919321906 ], [ -88.833848639602991, 13.599506130003874 ], [ -88.836509976354307, 13.602761745957821 ], [ -88.844390632022055, 13.605629788284091 ], [ -88.848938158269391, 13.606379096218291 ], [ -88.853046434045666, 13.606172389743961 ], [ -88.876946784366567, 13.5988860132789 ], [ -88.880073208211968, 13.5984984405506 ], [ -88.883277147322474, 13.598420925285438 ], [ -88.886377732746155, 13.598756822069674 ], [ -88.888263923141494, 13.602761745957821 ], [ -88.88934912785993, 13.609583035328797 ], [ -88.888238084719831, 13.626507065748456 ], [ -88.88857398060469, 13.642940172451006 ], [ -88.896067064443457, 13.662577216465365 ], [ -88.876585049160667, 13.681284085392235 ], [ -88.874337123559371, 13.68461721391327 ], [ -88.871934170125826, 13.689190579481647 ], [ -88.868497687917966, 13.703194892530234 ], [ -88.850255906984501, 13.750633857066816 ], [ -88.84886064300423, 13.779314276732464 ], [ -88.847051967873995, 13.78233734779036 ], [ -88.844235603290429, 13.786058050838335 ], [ -88.837801886647753, 13.78579966931926 ], [ -88.831962450106971, 13.784481919704831 ], [ -88.821575487318853, 13.781097113441035 ], [ -88.814702522003756, 13.782208157480454 ], [ -88.805039028728174, 13.78520539011663 ], [ -88.773929816307941, 13.798641262384365 ], [ -88.767341070933639, 13.800372423148815 ], [ -88.760183884778428, 13.798589586440244 ], [ -88.754266933871861, 13.798098660025119 ], [ -88.75077877482056, 13.800346584727095 ], [ -88.74752315976599, 13.80370555346849 ], [ -88.742510546424569, 13.810165106734246 ], [ -88.738919033686443, 13.811973781864538 ], [ -88.735611741788432, 13.812283840227053 ], [ -88.721219855112224, 13.802155259857329 ], [ -88.716491461711598, 13.800915025508004 ], [ -88.70936011397805, 13.800294907883654 ], [ -88.677424079257833, 13.800604967145489 ], [ -88.670861172305251, 13.799442247161949 ], [ -88.657141079197402, 13.798744615171813 ], [ -88.64613399878499, 13.796729234466568 ], [ -88.64386023566135, 13.795644028848812 ], [ -88.625489265317299, 13.782414863055465 ], [ -88.623086310984434, 13.78117462780682 ], [ -88.612440965777921, 13.777557278445613 ], [ -88.605774706037835, 13.773681544867372 ], [ -88.603345913283249, 13.772648016992378 ], [ -88.596421272024088, 13.770813503440422 ], [ -88.593630744063546, 13.769392401937807 ], [ -88.592183804139211, 13.76709280039239 ], [ -88.590943569789886, 13.761666775001629 ], [ -88.590065069747141, 13.759263821568084 ], [ -88.588876512241256, 13.757093411231949 ], [ -88.586912808379395, 13.755413927310883 ], [ -88.583243781275485, 13.754199530483902 ], [ -88.558025682239418, 13.751150621004342 ], [ -88.548568895438166, 13.748695989828036 ], [ -88.532342495209946, 13.759367174355589 ], [ -88.529655320936286, 13.735828559240588 ], [ -88.498830329356224, 13.705727037173006 ], [ -88.48733232342795, 13.688260403494837 ], [ -88.550145025672407, 13.643663641963485 ], [ -88.555855271903283, 13.626041977755051 ], [ -88.570634732207111, 13.606146552221617 ], [ -88.590840217002381, 13.593718370306533 ], [ -88.612828539405541, 13.598653469282169 ], [ -88.641612311858694, 13.563901069079066 ], [ -88.642930060573804, 13.557674058011344 ], [ -88.659363166377034, 13.555012722159404 ], [ -88.665099250130254, 13.547106228069936 ], [ -88.667450527619735, 13.516720486061558 ], [ -88.675873785646672, 13.487161567252485 ], [ -88.721452399108898, 13.402541408858895 ], [ -88.725689866993775, 13.391973578018224 ], [ -88.728118658848985, 13.379287014584065 ], [ -88.72938473162003, 13.348281154951337 ], [ -88.731865201218056, 13.341485704002025 ], [ -88.749383510840346, 13.324923406989626 ], [ -88.758736944854093, 13.311435858777827 ], [ -88.764757250346804, 13.300402939943694 ], [ -88.774136521882951, 13.292935696325287 ], [ -88.793773565897311, 13.290171006786522 ], [ -88.805633307930805, 13.285830186114197 ], [ -88.813203905236037, 13.275727444166193 ], [ -88.817157152280743, 13.2616197783301 ], [ -88.817131313859022, 13.259630235147199 ], [ -88.81663977799991, 13.25930410400008 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-US", "NAME_1": "Usulután" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.112507114174903, 13.171196219997629 ], [ -88.121937628999945, 13.167547919000071 ], [ -88.208282029999907, 13.160427151000079 ], [ -88.300892706999946, 13.174221096000053 ], [ -88.324940558999913, 13.166571356000077 ], [ -88.337757941999939, 13.170843817000048 ], [ -88.352284308999913, 13.174017645000049 ], [ -88.352284308999913, 13.180243231000077 ], [ -88.329701300999943, 13.181708075000074 ], [ -88.328114386999914, 13.197088934000078 ], [ -88.340199347999942, 13.216131903000075 ], [ -88.3584285149999, 13.228664455000057 ], [ -88.354481574999909, 13.220892645000049 ], [ -88.342559373999904, 13.204657294000071 ], [ -88.337920701999906, 13.194525458000044 ], [ -88.3740535149999, 13.195705471000053 ], [ -88.391753709999932, 13.193915106000077 ], [ -88.406849738999938, 13.187689520000049 ], [ -88.397206183999913, 13.183620510000083 ], [ -88.389393683999913, 13.184759833000044 ], [ -88.379994269999941, 13.187404690000051 ], [ -88.36587480399993, 13.187689520000049 ], [ -88.36587480399993, 13.180243231000077 ], [ -88.389149542999917, 13.170843817000048 ], [ -88.414824998999904, 13.171576239000046 ], [ -88.434844529999907, 13.183661200000074 ], [ -88.441029425999943, 13.208197333000044 ], [ -88.431182420999903, 13.203884182000081 ], [ -88.427357550999943, 13.201361395000049 ], [ -88.413685675999943, 13.215033270000049 ], [ -88.413685675999943, 13.221218166000085 ], [ -88.430775519999941, 13.228786526000079 ], [ -88.449574347999942, 13.254584052000041 ], [ -88.462147589999915, 13.262233791000085 ], [ -88.458770311999899, 13.247748114000046 ], [ -88.453114386999914, 13.235907294000071 ], [ -88.450184699999909, 13.225368557000081 ], [ -88.454701300999943, 13.215033270000049 ], [ -88.469227667999917, 13.223089911000045 ], [ -88.511504686999899, 13.233465887000079 ], [ -88.529774542999917, 13.242946682000081 ], [ -88.546294725999928, 13.271755276000079 ], [ -88.553985154999907, 13.276434637000079 ], [ -88.565703904999907, 13.277370510000083 ], [ -88.5986628899999, 13.283880927000041 ], [ -88.613392706999946, 13.283880927000041 ], [ -88.653920050999943, 13.276434637000079 ], [ -88.710438605999911, 13.274969794000071 ], [ -88.722767706999946, 13.269598700000074 ], [ -88.716053839999915, 13.264349677000041 ], [ -88.708729620999918, 13.260524807000081 ], [ -88.70140540299991, 13.259344794000071 ], [ -88.694854295999903, 13.262233791000085 ], [ -88.666615363999938, 13.255764065000051 ], [ -88.586333787999934, 13.264227606000077 ], [ -88.577381964999915, 13.262844143000052 ], [ -88.564483201999906, 13.256008205000057 ], [ -88.557484503999945, 13.249579169000071 ], [ -88.545033331999946, 13.234767971000053 ], [ -88.536610480999911, 13.228664455000057 ], [ -88.536610480999911, 13.221218166000085 ], [ -88.55532792899993, 13.224310614000046 ], [ -88.568959113999938, 13.226833401000079 ], [ -88.5986628899999, 13.235500393000052 ], [ -88.5986628899999, 13.228664455000057 ], [ -88.516713019999941, 13.212225653000075 ], [ -88.473907029999907, 13.198635158000059 ], [ -88.454701300999943, 13.180243231000077 ], [ -88.461699998999904, 13.16828034100007 ], [ -88.479603644999941, 13.171210028000075 ], [ -88.499541795999903, 13.181423244000086 ], [ -88.512684699999909, 13.191107489000046 ], [ -88.527455206999946, 13.198431708000044 ], [ -88.785674607999908, 13.245266018000052 ], [ -88.81663977799991, 13.25930410400008 ], [ -88.817131313859022, 13.259630235147199 ], [ -88.817157152280743, 13.2616197783301 ], [ -88.813203905236037, 13.275727444166193 ], [ -88.805633307930805, 13.285830186114197 ], [ -88.793773565897311, 13.290171006786522 ], [ -88.774136521882951, 13.292935696325287 ], [ -88.764757250346804, 13.300402939943694 ], [ -88.758736944854093, 13.311435858777827 ], [ -88.749383510840346, 13.324923406989626 ], [ -88.731865201218056, 13.341485704002025 ], [ -88.72938473162003, 13.348281154951337 ], [ -88.728118658848985, 13.379287014584065 ], [ -88.725689866993775, 13.391973578018224 ], [ -88.721452399108898, 13.402541408858895 ], [ -88.675873785646672, 13.487161567252485 ], [ -88.667450527619735, 13.516720486061558 ], [ -88.665099250130254, 13.547106228069936 ], [ -88.659363166377034, 13.555012722159404 ], [ -88.642930060573804, 13.557674058011344 ], [ -88.641612311858694, 13.563901069079066 ], [ -88.612828539405541, 13.598653469282169 ], [ -88.590840217002381, 13.593718370306533 ], [ -88.570634732207111, 13.606146552221617 ], [ -88.555855271903283, 13.626041977755051 ], [ -88.550145025672407, 13.643663641963485 ], [ -88.48733232342795, 13.688260403494837 ], [ -88.44648210336635, 13.692833767264517 ], [ -88.434544846967071, 13.692136135274382 ], [ -88.428421189586231, 13.68461721391327 ], [ -88.420075445925079, 13.671749783325822 ], [ -88.413202480609982, 13.665445257892316 ], [ -88.404546677686994, 13.65937327735486 ], [ -88.396795214127792, 13.656789455868704 ], [ -88.372429775813487, 13.653843899176593 ], [ -88.366254441589206, 13.651957708781197 ], [ -88.362921312168794, 13.649399725716762 ], [ -88.362998827433898, 13.646557521812156 ], [ -88.367753059256245, 13.633638414381323 ], [ -88.368269823193771, 13.630692856789892 ], [ -88.368321499137835, 13.627747300997157 ], [ -88.366357795276031, 13.6192982045485 ], [ -88.363515591371424, 13.612296047124858 ], [ -88.362223680178658, 13.608187771348582 ], [ -88.361681077819469, 13.604596259509776 ], [ -88.362068651447089, 13.601909085236059 ], [ -88.36307634090042, 13.599428616537409 ], [ -88.364497443302355, 13.597361558089403 ], [ -88.366151088801701, 13.595578722280209 ], [ -88.368399014402996, 13.594467678240733 ], [ -88.373825038894438, 13.592710679953882 ], [ -88.376124641339118, 13.591522122447998 ], [ -88.377752448416743, 13.589661770474322 ], [ -88.378837653135179, 13.587439683294747 ], [ -88.379690313856884, 13.584855861808535 ], [ -88.380155401850288, 13.58188446669476 ], [ -88.379948697174598, 13.575967515788193 ], [ -88.379586961968698, 13.573125311883643 ], [ -88.378811814713458, 13.570386460766542 ], [ -88.36671952958261, 13.545478420092991 ], [ -88.365427619289164, 13.541783556365999 ], [ -88.3653759433451, 13.539380601133814 ], [ -88.367494675938531, 13.531551622309507 ], [ -88.36746883841613, 13.527417507212192 ], [ -88.366667853638489, 13.522224025818105 ], [ -88.362611253806278, 13.509046535968821 ], [ -88.362197841756995, 13.505248318555061 ], [ -88.362533739440494, 13.50305206979715 ], [ -88.363773972890499, 13.500519924255059 ], [ -88.363980679364829, 13.5002098658926 ], [ -88.369303351968085, 13.495429796547853 ], [ -88.370879483101646, 13.493595282096578 ], [ -88.372197231816756, 13.491192327763713 ], [ -88.373024055016117, 13.488634344699221 ], [ -88.373411627744417, 13.485611274540645 ], [ -88.373204922169407, 13.479487616260485 ], [ -88.373644171741091, 13.473234768569682 ], [ -88.374574347727958, 13.470676785505248 ], [ -88.375995450129892, 13.469126491894087 ], [ -88.377829962782528, 13.469307359047377 ], [ -88.379457770759473, 13.470470079030918 ], [ -88.380827196318023, 13.472072047686822 ], [ -88.381964076980523, 13.473028062095352 ], [ -88.383411017804235, 13.473596502876319 ], [ -88.385271368878534, 13.473028062095352 ], [ -88.386821661590375, 13.471167711021053 ], [ -88.387674323211456, 13.468687242322346 ], [ -88.38790686720813, 13.46566417126445 ], [ -88.387829352842346, 13.462718614572395 ], [ -88.386124029600296, 13.449308579827061 ], [ -88.385891485603565, 13.442849026561305 ], [ -88.382687548291699, 13.42442637847455 ], [ -88.381498989886438, 13.421222439364044 ], [ -88.380155401850288, 13.420085557802224 ], [ -88.378346726720054, 13.420059719380504 ], [ -88.373747525427916, 13.421687527357506 ], [ -88.369665087174042, 13.420369777743019 ], [ -88.368166470406265, 13.417785956256864 ], [ -88.367598028726036, 13.414685369933864 ], [ -88.367753059256245, 13.408251655089771 ], [ -88.367158780053614, 13.402334703283941 ], [ -88.365686000808296, 13.394686590713604 ], [ -88.360415005048424, 13.376703193097853 ], [ -88.354988979657662, 13.366006171047957 ], [ -88.34493791365378, 13.350296536555902 ], [ -88.337909918707737, 13.341537379946089 ], [ -88.336075406055102, 13.340142116865195 ], [ -88.333904994819648, 13.338824368150028 ], [ -88.32641191277952, 13.335568752196139 ], [ -88.321115077698664, 13.334225165059308 ], [ -88.301478033684305, 13.332003078779053 ], [ -88.296956345858632, 13.329470933236962 ], [ -88.291866218151426, 13.325388494983031 ], [ -88.282952032810044, 13.315104884982418 ], [ -88.278869594556113, 13.311280829146938 ], [ -88.275949877185042, 13.309368801229198 ], [ -88.273391893221287, 13.309497992438367 ], [ -88.270549689316681, 13.309291286863356 ], [ -88.26801754377459, 13.308361110876547 ], [ -88.26589881118116, 13.306965846896276 ], [ -88.262074755345679, 13.303839423050931 ], [ -88.259981859375273, 13.302495835914101 ], [ -88.257423876310838, 13.301643175192339 ], [ -88.254685025193737, 13.301152248777271 ], [ -88.251791145345067, 13.301384792773945 ], [ -88.24894894144046, 13.301927395133191 ], [ -88.243910488777999, 13.304020291103541 ], [ -88.234531216342532, 13.308955390079177 ], [ -88.231353115653746, 13.309342962807477 ], [ -88.227115647768926, 13.308800361347608 ], [ -88.223834195191955, 13.305260525452866 ], [ -88.222154711270889, 13.302314967861491 ], [ -88.221172858440639, 13.299162706493689 ], [ -88.220862800078123, 13.296294664167419 ], [ -88.220630256081449, 13.281489366341191 ], [ -88.218304816114369, 13.277846178558264 ], [ -88.214506598700552, 13.274926459388553 ], [ -88.207943691747971, 13.271464137859653 ], [ -88.205618251780891, 13.268337714014251 ], [ -88.2050498118993, 13.265573025374806 ], [ -88.212517056417028, 13.252162991528849 ], [ -88.213498908347901, 13.249010728362407 ], [ -88.214041510707148, 13.245703437363716 ], [ -88.213912320397242, 13.24079417591048 ], [ -88.212051968423566, 13.238804632727579 ], [ -88.209571498825596, 13.238236191946669 ], [ -88.182389695927725, 13.242370307044041 ], [ -88.179289109604724, 13.242215278312415 ], [ -88.176421068177717, 13.241672675053906 ], [ -88.173759732325777, 13.240664984701255 ], [ -88.112507114174903, 13.171196219997629 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-CU", "NAME_1": "Cuscatlán" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.929734259928125, 13.947908637473631 ], [ -88.944462043388569, 13.925222683080335 ], [ -88.94565060089451, 13.922974758378359 ], [ -88.948596157586564, 13.918659776127754 ], [ -88.951955126328016, 13.915171617076453 ], [ -88.955779182163496, 13.912096869175173 ], [ -88.969060024800285, 13.904577947814005 ], [ -88.971127082348971, 13.903027655102164 ], [ -88.972729051004876, 13.90127065681537 ], [ -88.974227667772652, 13.899151923322563 ], [ -88.975209519703526, 13.896774807411418 ], [ -88.976010505380486, 13.894035956294317 ], [ -88.976527269318012, 13.891038722758822 ], [ -88.973995123775921, 13.884682522280571 ], [ -88.969266730375296, 13.876104233723368 ], [ -88.949784715991825, 13.849206650766291 ], [ -88.943635220189265, 13.84282461186632 ], [ -88.935470343681402, 13.837424424897279 ], [ -88.93058692064983, 13.832153429137406 ], [ -88.927021247232744, 13.824350286936181 ], [ -88.926220261555784, 13.819880275953949 ], [ -88.9250317040499, 13.815668647390169 ], [ -88.919993252286758, 13.807038682888901 ], [ -88.918753017937433, 13.803240465475085 ], [ -88.917435269222267, 13.796729234466568 ], [ -88.915032314889402, 13.792336737850178 ], [ -88.91092403821375, 13.786988226825201 ], [ -88.901260545837488, 13.776911322399599 ], [ -88.894826830094132, 13.767377021232505 ], [ -88.893844978163202, 13.764870714112135 ], [ -88.884853277556715, 13.75980642302801 ], [ -88.850255906984501, 13.750633857066816 ], [ -88.868497687917966, 13.703194892530234 ], [ -88.871934170125826, 13.689190579481647 ], [ -88.874337123559371, 13.68461721391327 ], [ -88.876585049160667, 13.681284085392235 ], [ -88.896067064443457, 13.662577216465365 ], [ -88.903017544124339, 13.658546454155498 ], [ -88.908546923201925, 13.656686103081199 ], [ -88.921078457005194, 13.655213323835824 ], [ -88.923791469700575, 13.654412339957503 ], [ -88.925961880036709, 13.653197944029898 ], [ -88.927563849591991, 13.651337592056223 ], [ -88.929785935872246, 13.646531684289812 ], [ -88.931336228584087, 13.644671332316136 ], [ -88.933506638920221, 13.643663641963485 ], [ -88.935470343681402, 13.643095201182575 ], [ -88.939940354663634, 13.642449246035881 ], [ -88.94335100024847, 13.642294216404935 ], [ -88.962238736328629, 13.648185329789101 ], [ -88.979550341275228, 13.657228705440389 ], [ -89.023578661126294, 13.672938340831763 ], [ -89.024431321847999, 13.70309153884341 ], [ -89.026627569706534, 13.708052476240766 ], [ -89.028384568892704, 13.713400987265743 ], [ -89.033267991924276, 13.719266262228189 ], [ -89.05065711123666, 13.751538193732642 ], [ -89.052129889582716, 13.756318263976709 ], [ -89.050424567239986, 13.777867335908809 ], [ -89.051354743226796, 13.782259833424575 ], [ -89.053137579935367, 13.78502452206402 ], [ -89.055695562999801, 13.785903022106766 ], [ -89.059493781312938, 13.788435166749537 ], [ -89.063679572354374, 13.792620957790973 ], [ -89.076340298266132, 13.810630194727707 ], [ -89.078304003027313, 13.812102973073706 ], [ -89.080784470826643, 13.813110663426357 ], [ -89.083704189996354, 13.813679104207267 ], [ -89.090137905739766, 13.813989163469103 ], [ -89.097088386319967, 13.819492703225649 ], [ -89.106235113859384, 13.829698797961157 ], [ -89.132900152819786, 13.870445665235252 ], [ -89.135613166414487, 13.878042100062828 ], [ -89.133856167228316, 13.879747423304934 ], [ -89.12662146670732, 13.882848008728615 ], [ -89.124011806799444, 13.884630846336449 ], [ -89.122073941359304, 13.886723741407536 ], [ -89.120316942173133, 13.890444444455511 ], [ -89.121221279738279, 13.892692369157487 ], [ -89.12739661306324, 13.900262966462719 ], [ -89.14817053863942, 13.933465073953982 ], [ -89.157679003183432, 13.952482001243368 ], [ -89.159694382989358, 13.960000921705159 ], [ -89.160831264551177, 13.968579210262305 ], [ -89.160133632561099, 13.970103665451802 ], [ -89.158660855114363, 13.971524766055097 ], [ -89.156800503140687, 13.972971706878752 ], [ -89.154991828010452, 13.974599513956377 ], [ -89.152356329680856, 13.978630276266244 ], [ -89.15147783143675, 13.981084906543174 ], [ -89.150754361024951, 13.983823756760955 ], [ -89.14992753782559, 13.989689031723401 ], [ -89.148454758580215, 13.995166733957603 ], [ -89.14801550990785, 13.999275011532518 ], [ -89.14801550990785, 14.00030853940757 ], [ -89.147834641855241, 14.002168891381245 ], [ -89.148635626632824, 14.011806545335787 ], [ -89.151710375433481, 14.028239651138961 ], [ -89.152097948161781, 14.032632147755407 ], [ -89.151116096230851, 14.035810248444193 ], [ -89.1462843491434, 14.04539622645467 ], [ -89.141891853426273, 14.057307644432228 ], [ -89.141349250167764, 14.066996975230211 ], [ -89.123675910015209, 14.075962836515657 ], [ -89.120627001434968, 14.075936998093994 ], [ -89.117138840585028, 14.075497748522253 ], [ -89.104607306781759, 14.069374091141356 ], [ -89.078820766964782, 14.06025320112434 ], [ -89.07378231520164, 14.057643541216464 ], [ -89.066521776258924, 14.051339015782958 ], [ -89.049649420884066, 14.039608465858009 ], [ -89.048099128172225, 14.037748113884334 ], [ -89.043577440346553, 14.029944973481747 ], [ -89.021640794786833, 14.004571844814791 ], [ -89.019806281234878, 14.00183299369769 ], [ -89.019392870084857, 14.000205185720745 ], [ -89.019392870084857, 13.999972641724014 ], [ -89.020168016440778, 13.995709337216113 ], [ -89.020193854862498, 13.993022162043133 ], [ -89.019806281234878, 13.990490017400361 ], [ -89.019160326088183, 13.988009547802392 ], [ -89.017455003745397, 13.983436184032655 ], [ -89.014767828572417, 13.97795848179851 ], [ -89.009496832812545, 13.970336209448476 ], [ -89.00502682183037, 13.966331285560386 ], [ -89.001202765994833, 13.964005846492626 ], [ -88.979808722794303, 13.954109809220313 ], [ -88.961670294648343, 13.955556749144648 ], [ -88.94621904167542, 13.949743150126267 ], [ -88.929734259928125, 13.947908637473631 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "SV-SS", "NAME_1": "San Salvador" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.141349250167764, 14.066996975230211 ], [ -89.141891853426273, 14.057307644432228 ], [ -89.1462843491434, 14.04539622645467 ], [ -89.151116096230851, 14.035810248444193 ], [ -89.152097948161781, 14.032632147755407 ], [ -89.151710375433481, 14.028239651138961 ], [ -89.148635626632824, 14.011806545335787 ], [ -89.147834641855241, 14.002168891381245 ], [ -89.14801550990785, 14.00030853940757 ], [ -89.14801550990785, 13.999275011532518 ], [ -89.148454758580215, 13.995166733957603 ], [ -89.14992753782559, 13.989689031723401 ], [ -89.150754361024951, 13.983823756760955 ], [ -89.15147783143675, 13.981084906543174 ], [ -89.152356329680856, 13.978630276266244 ], [ -89.154991828010452, 13.974599513956377 ], [ -89.156800503140687, 13.972971706878752 ], [ -89.158660855114363, 13.971524766055097 ], [ -89.160133632561099, 13.970103665451802 ], [ -89.160831264551177, 13.968579210262305 ], [ -89.159694382989358, 13.960000921705159 ], [ -89.157679003183432, 13.952482001243368 ], [ -89.14817053863942, 13.933465073953982 ], [ -89.12739661306324, 13.900262966462719 ], [ -89.121221279738279, 13.892692369157487 ], [ -89.120316942173133, 13.890444444455511 ], [ -89.122073941359304, 13.886723741407536 ], [ -89.124011806799444, 13.884630846336449 ], [ -89.12662146670732, 13.882848008728615 ], [ -89.133856167228316, 13.879747423304934 ], [ -89.135613166414487, 13.878042100062828 ], [ -89.132900152819786, 13.870445665235252 ], [ -89.106235113859384, 13.829698797961157 ], [ -89.097088386319967, 13.819492703225649 ], [ -89.090137905739766, 13.813989163469103 ], [ -89.083704189996354, 13.813679104207267 ], [ -89.080784470826643, 13.813110663426357 ], [ -89.078304003027313, 13.812102973073706 ], [ -89.076340298266132, 13.810630194727707 ], [ -89.063679572354374, 13.792620957790973 ], [ -89.059493781312938, 13.788435166749537 ], [ -89.055695562999801, 13.785903022106766 ], [ -89.053137579935367, 13.78502452206402 ], [ -89.051354743226796, 13.782259833424575 ], [ -89.050424567239986, 13.777867335908809 ], [ -89.052129889582716, 13.756318263976709 ], [ -89.05065711123666, 13.751538193732642 ], [ -89.033267991924276, 13.719266262228189 ], [ -89.028384568892704, 13.713400987265743 ], [ -89.026627569706534, 13.708052476240766 ], [ -89.024431321847999, 13.70309153884341 ], [ -89.023578661126294, 13.672938340831763 ], [ -89.059726325309668, 13.6397362333405 ], [ -89.08980200895553, 13.60252920196109 ], [ -89.094892136662736, 13.598730984547274 ], [ -89.097941047041672, 13.5988860132789 ], [ -89.101015794942953, 13.599351101272305 ], [ -89.116983811853402, 13.604467068300551 ], [ -89.120058559754739, 13.604854641028851 ], [ -89.123236661342844, 13.604854641028851 ], [ -89.125949673138905, 13.604363715513045 ], [ -89.12817176031848, 13.603149318686121 ], [ -89.129592861821095, 13.599997057318319 ], [ -89.130032111392836, 13.595397854227599 ], [ -89.128197597840824, 13.586716212882891 ], [ -89.12527787957049, 13.578680528483574 ], [ -89.117603928578433, 13.565477200212626 ], [ -89.115666063138292, 13.560567938759334 ], [ -89.116208666396801, 13.553539943813348 ], [ -89.118456591098777, 13.542739569875209 ], [ -89.126957364390819, 13.517960720410883 ], [ -89.132073329620425, 13.507341212726772 ], [ -89.139230515775637, 13.499563909846529 ], [ -89.142201910889469, 13.497677721249829 ], [ -89.144372321225603, 13.489254462323572 ], [ -89.151736212955825, 13.492484238956422 ], [ -89.154268357598596, 13.493181870946557 ], [ -89.157989060646628, 13.493672797361683 ], [ -89.163931850874178, 13.492975165371547 ], [ -89.174396328028081, 13.489564520686088 ], [ -89.180003220572132, 13.488272610392642 ], [ -89.183155483738574, 13.488117580761752 ], [ -89.186075202008965, 13.488479315967652 ], [ -89.18829728918854, 13.489693711895256 ], [ -89.189770066635276, 13.491579902290653 ], [ -89.195428636022712, 13.50346548094717 ], [ -89.211448329776601, 13.528683579983237 ], [ -89.212042608979232, 13.532404283031212 ], [ -89.211680873773275, 13.537132677331158 ], [ -89.209432949970619, 13.545736803410762 ], [ -89.203180101380553, 13.561523953167864 ], [ -89.202715013387149, 13.564676215434986 ], [ -89.204575365360824, 13.606017361012391 ], [ -89.203800218105584, 13.615370795026138 ], [ -89.202404955024633, 13.621081041257014 ], [ -89.200389574319388, 13.622631333968855 ], [ -89.198761766342443, 13.624595037830716 ], [ -89.198270839927318, 13.626817125010291 ], [ -89.199459398332522, 13.629220079343156 ], [ -89.207133348425259, 13.632785752760242 ], [ -89.209303757862131, 13.635033678361538 ], [ -89.209407110649636, 13.638134263785219 ], [ -89.207081671581875, 13.643611965120101 ], [ -89.203800218105584, 13.649580592870052 ], [ -89.203490159743069, 13.652655340771332 ], [ -89.204472011674, 13.656479397506189 ], [ -89.211164109835806, 13.6651351995298 ], [ -89.215453253664691, 13.668881740999552 ], [ -89.217184414429141, 13.670018622561372 ], [ -89.231576301105406, 13.67751170550082 ], [ -89.23374671144154, 13.67906199821266 ], [ -89.235658739359337, 13.681981716482994 ], [ -89.237157355227737, 13.686322537155377 ], [ -89.238991868779692, 13.694151515979684 ], [ -89.240206264707354, 13.697510483821759 ], [ -89.242092455102693, 13.699939277475664 ], [ -89.245942349359893, 13.702703966115109 ], [ -89.247595994859239, 13.70464183245457 ], [ -89.24896542041779, 13.706734727525657 ], [ -89.250050625136225, 13.709241033746707 ], [ -89.250748257126361, 13.71874949829072 ], [ -89.24976640519543, 13.728723049029497 ], [ -89.254779019436171, 13.735053411985348 ], [ -89.258008796069078, 13.735311794403799 ], [ -89.260566779133512, 13.735983587972214 ], [ -89.262375454263804, 13.738076483942564 ], [ -89.262685512626263, 13.742081406931391 ], [ -89.258318855330913, 13.754561265689858 ], [ -89.251420050694776, 13.767221990702296 ], [ -89.250670742760576, 13.769728297822667 ], [ -89.249818081139495, 13.773991604129208 ], [ -89.248629522734291, 13.789985460360697 ], [ -89.246795010081655, 13.799209703165275 ], [ -89.243539395027028, 13.806547756473776 ], [ -89.241446499056678, 13.814273383409898 ], [ -89.239586147982322, 13.831714179565722 ], [ -89.238371752054718, 13.836468411388068 ], [ -89.236356371349416, 13.841274319154479 ], [ -89.233333300291577, 13.845020859724855 ], [ -89.231266241843571, 13.846545314914351 ], [ -89.229069993985036, 13.847863064528781 ], [ -89.223928189434389, 13.849723416502457 ], [ -89.221886970307423, 13.851092841161687 ], [ -89.220775926267947, 13.853366604285327 ], [ -89.219328986343612, 13.859025172773499 ], [ -89.214316372102871, 13.914809881870553 ], [ -89.213282844227876, 13.918065496925124 ], [ -89.211422492254201, 13.919822496111294 ], [ -89.208838670768046, 13.92052012810143 ], [ -89.201371426250319, 13.920313422526419 ], [ -89.200544603050957, 13.920959376773794 ], [ -89.200157030322657, 13.922199612022439 ], [ -89.198839280708228, 13.927806505465867 ], [ -89.196203783277952, 13.934369412418448 ], [ -89.196591356006252, 13.936048896339457 ], [ -89.198141648718092, 13.938090115466423 ], [ -89.203490159743069, 13.940854804105925 ], [ -89.207133348425259, 13.943800360797979 ], [ -89.210363125058166, 13.945583197506551 ], [ -89.213076137753546, 13.946539211015761 ], [ -89.215918341658096, 13.947211005483496 ], [ -89.218889736771928, 13.947598578211796 ], [ -89.222041999038993, 13.947701930999301 ], [ -89.231266241843571, 13.946978461486822 ], [ -89.234263475379066, 13.947159329539431 ], [ -89.242376675043488, 13.949536445450576 ], [ -89.247105069343434, 13.951758530831512 ], [ -89.251316697907271, 13.954419867582828 ], [ -89.254055549024372, 13.957985540999914 ], [ -89.257026944138147, 13.963385727968955 ], [ -89.262013719057848, 13.974702866743883 ], [ -89.264907599805895, 13.979948024981354 ], [ -89.26731055413876, 13.983410346510254 ], [ -89.273330857832832, 13.987983710279991 ], [ -89.274106005088072, 13.991549383697077 ], [ -89.273795945826237, 13.996949571565438 ], [ -89.26844743480126, 14.018421129131809 ], [ -89.26731055413876, 14.052114163038198 ], [ -89.260205043927613, 14.051132310207947 ], [ -89.256019252886176, 14.053147690913192 ], [ -89.243074307033623, 14.062242743407865 ], [ -89.235400356940886, 14.064800727371676 ], [ -89.214678107308771, 14.055989894817799 ], [ -89.200751308625968, 14.055834866086172 ], [ -89.194420945670117, 14.068211371157815 ], [ -89.180339118255688, 14.057385158798013 ], [ -89.168970302637319, 14.054620470158568 ], [ -89.141349250167764, 14.066996975230211 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/guatemala.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/guatemala.geojson new file mode 100644 index 0000000000000..034fd9c0a6a51 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/guatemala.geojson @@ -0,0 +1,28 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "GT-JU", "NAME_1": "Jutiapa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.7480100679999, 14.044894904000031 ], [ -89.747256225999962, 14.04320078500011 ], [ -89.747643798999974, 14.037645569000105 ], [ -89.762268229999847, 14.029997457000121 ], [ -89.776944335999929, 14.0357852180001 ], [ -89.802963419999912, 14.055473938000134 ], [ -89.821101846999937, 14.060073141000089 ], [ -89.835855468999938, 14.059091289000037 ], [ -89.880116332999961, 14.042684021000071 ], [ -89.890787516999865, 14.035888570000026 ], [ -89.912078206999951, 14.015192159 ], [ -90.008170532999941, 13.949692281000097 ], [ -90.022975830999883, 13.936954041000135 ], [ -90.031476602999902, 13.922923889000032 ], [ -90.038091186999878, 13.908376974000078 ], [ -90.0473671069999, 13.894295146000061 ], [ -90.059640258999934, 13.884709167000054 ], [ -90.087080443999895, 13.870472310000082 ], [ -90.09904353899995, 13.85850921600013 ], [ -90.106975870999918, 13.844065654000104 ], [ -90.112298542999866, 13.828252666000111 ], [ -90.114779011999929, 13.81200042800009 ], [ -90.114313924999891, 13.796264954000023 ], [ -90.098306575132682, 13.731404008980572 ], [ -90.09832812399992, 13.731414130000076 ], [ -90.240563423844662, 13.788715510162957 ], [ -90.236992967051776, 13.802310289488275 ], [ -90.2305075753643, 13.82721832926245 ], [ -90.23012000173668, 13.84515005093408 ], [ -90.230817633726815, 13.849955960499187 ], [ -90.232548793591945, 13.855020249784673 ], [ -90.245442064399754, 13.877757880122033 ], [ -90.255131395197736, 13.912691148377803 ], [ -90.258516202360852, 13.92070099525472 ], [ -90.261461758153587, 13.925455227077066 ], [ -90.266500209916728, 13.927780667044146 ], [ -90.268567268364734, 13.929227606968482 ], [ -90.27022091296476, 13.931036282098717 ], [ -90.271409471369964, 13.933413398009918 ], [ -90.278644171891017, 13.974702866743883 ], [ -90.280246141446241, 13.978785304997814 ], [ -90.285258754787662, 13.98390127202606 ], [ -90.28854020916333, 13.987932034335927 ], [ -90.29200252979291, 13.995166733957603 ], [ -90.292648484939605, 13.998784085117393 ], [ -90.292855191413935, 14.004003404033881 ], [ -90.291692471430395, 14.009739487787101 ], [ -90.29024553060674, 14.013253486159442 ], [ -90.284121874125162, 14.017749335563394 ], [ -90.265957607557539, 14.022710272960694 ], [ -90.237871467094521, 14.006897283882552 ], [ -90.218518643020957, 13.991032619759608 ], [ -90.213402675992711, 13.989068914998427 ], [ -90.174102748642895, 13.979818833772129 ], [ -90.164129197904117, 13.975943101093208 ], [ -90.159943406862737, 13.976201484410979 ], [ -90.15668779180811, 13.976769924292569 ], [ -90.141055670782578, 13.987311916711576 ], [ -90.125449388178708, 14.015837306746278 ], [ -90.119170702066242, 14.026999416789636 ], [ -90.115682543014941, 14.029531562331726 ], [ -90.110023972728129, 14.032787177386297 ], [ -90.098525966799912, 14.035991116496803 ], [ -90.085064257009833, 14.038471585195509 ], [ -90.082738817042753, 14.039350084338935 ], [ -90.077054410132916, 14.045447903298111 ], [ -90.059665289921156, 14.069580796716366 ], [ -90.054394294161341, 14.080742905860404 ], [ -90.051526251835014, 14.089269517574166 ], [ -90.050466884638979, 14.095108954114949 ], [ -90.05033769432913, 14.098157864493828 ], [ -90.05493689741985, 14.137845364571888 ], [ -90.053464118174475, 14.159756170810624 ], [ -90.058295865261982, 14.169729723348041 ], [ -90.082712978621032, 14.192932440779487 ], [ -90.113770515097201, 14.217840481453038 ], [ -90.120643480412298, 14.224713446768135 ], [ -90.124519213091219, 14.22771068030363 ], [ -90.130255296844439, 14.229984443427327 ], [ -90.176634895084305, 14.24274852122727 ], [ -90.191052619282914, 14.252928779339697 ], [ -90.155473395880506, 14.338918362392519 ], [ -90.142166713922677, 14.350132148379942 ], [ -90.139970466064142, 14.351785793879287 ], [ -90.105166389017597, 14.358452052720054 ], [ -90.094107631761801, 14.357883612838464 ], [ -90.089301723995334, 14.355558172871383 ], [ -90.084263272232192, 14.353852851427916 ], [ -90.082015346630897, 14.354834703358847 ], [ -90.080930141912518, 14.357935288782528 ], [ -90.083953212970357, 14.376900540127792 ], [ -90.069948899921769, 14.378450832839633 ], [ -90.051887987040971, 14.433486233103167 ], [ -89.988558519060405, 14.434313056302472 ], [ -89.964761522426329, 14.464905503885859 ], [ -89.960653245750677, 14.469298001401626 ], [ -89.957785204323727, 14.470796617270082 ], [ -89.953986986010591, 14.472140204406912 ], [ -89.947088182273774, 14.473483792443062 ], [ -89.942592332869822, 14.473793849906258 ], [ -89.938561570560012, 14.473483792443062 ], [ -89.9356160138679, 14.472863673919392 ], [ -89.932877162750856, 14.471933498831902 ], [ -89.929828254170559, 14.470589910795752 ], [ -89.885257331060984, 14.436483465739343 ], [ -89.880012172823513, 14.47089997005753 ], [ -89.87164059074064, 14.482940579244314 ], [ -89.851280077213801, 14.496428127456113 ], [ -89.83213395871519, 14.508727118161971 ], [ -89.815726691333737, 14.519475816155989 ], [ -89.796244676050947, 14.52469513597174 ], [ -89.789087490795055, 14.523403224778974 ], [ -89.785289273381238, 14.520302639355293 ], [ -89.782059495849012, 14.516426907575692 ], [ -89.775393236108926, 14.509863999723791 ], [ -89.764360318174113, 14.50138906485347 ], [ -89.762344936569548, 14.500458888866604 ], [ -89.699971482997512, 14.52986277894405 ], [ -89.678396572643692, 14.542213447392669 ], [ -89.677698940653556, 14.545417384704535 ], [ -89.677853970284502, 14.555235906711687 ], [ -89.685502081955519, 14.577611802742467 ], [ -89.645194465152429, 14.573219306126077 ], [ -89.632637092028176, 14.569033515084641 ], [ -89.630518357636106, 14.567224839954406 ], [ -89.623542040432824, 14.559835109802464 ], [ -89.617883470146012, 14.551825262925547 ], [ -89.613103399901945, 14.542730211330195 ], [ -89.601734585182953, 14.526348782370405 ], [ -89.598220587709932, 14.524075019246709 ], [ -89.594525723083621, 14.52298981452833 ], [ -89.519388189913002, 14.525935370321065 ], [ -89.513135342222256, 14.523713284040809 ], [ -89.499131029173668, 14.508727118161971 ], [ -89.496314662791463, 14.501854152846875 ], [ -89.496547206788136, 14.497306627498858 ], [ -89.497554898040107, 14.492138984526491 ], [ -89.502309129862454, 14.478341376153594 ], [ -89.505306363397949, 14.471933498831902 ], [ -89.5085619775532, 14.462321682399704 ], [ -89.511171638360395, 14.450849513993887 ], [ -89.5116625638762, 14.44547516544651 ], [ -89.511507535144631, 14.441857815185983 ], [ -89.510732387889391, 14.440307522474143 ], [ -89.50954383038345, 14.438343817713019 ], [ -89.496547206788136, 14.423357651834124 ], [ -89.496148129999909, 14.42289748400006 ], [ -89.503033406999918, 14.420051168000015 ], [ -89.527760579999921, 14.391060689000128 ], [ -89.541351480999907, 14.381526387000036 ], [ -89.544245361999913, 14.400052388000077 ], [ -89.555174926999968, 14.410826925 ], [ -89.569876871999867, 14.412015483000118 ], [ -89.584062052999911, 14.401809387000057 ], [ -89.590573283999902, 14.38597056100005 ], [ -89.586284139999918, 14.374679261000082 ], [ -89.578971923999944, 14.364783223000089 ], [ -89.576078043999956, 14.353130189000112 ], [ -89.582408406999974, 14.343363343000064 ], [ -89.592433634999907, 14.336387024000075 ], [ -89.598350586999914, 14.327989604000095 ], [ -89.592175252999937, 14.313830261000049 ], [ -89.571272135999948, 14.311143087000104 ], [ -89.564373331999974, 14.308145853000099 ], [ -89.558585571999913, 14.302823182000054 ], [ -89.555691690999907, 14.299024963000122 ], [ -89.549878092999933, 14.288276265 ], [ -89.54858618199998, 14.28359954900013 ], [ -89.546777506999888, 14.268329163000075 ], [ -89.544917155999883, 14.261817932000014 ], [ -89.540550496999913, 14.257606303000074 ], [ -89.527863931999946, 14.2514568080001 ], [ -89.524659993999876, 14.247374369000084 ], [ -89.524504964999949, 14.231768087000134 ], [ -89.530938679999906, 14.225566915000059 ], [ -89.638322306999868, 14.200555522000073 ], [ -89.664625610999906, 14.188850810000091 ], [ -89.689843709999963, 14.170014750000064 ], [ -89.709868326999896, 14.148724060000077 ], [ -89.752604736999928, 14.075240174000029 ], [ -89.755446939999899, 14.067075297000102 ], [ -89.754465087999932, 14.059401347000104 ], [ -89.7480100679999, 14.044894904000031 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-CQ", "NAME_1": "Chiquimula" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.36162084999998, 14.415477804000062 ], [ -89.361821562322675, 14.415505745792339 ], [ -89.390611328999881, 14.435993348000039 ], [ -89.391696533999948, 14.433719585000119 ], [ -89.396864176999969, 14.426045635000037 ], [ -89.398181925999921, 14.445372620000086 ], [ -89.40836218299998, 14.441522726000045 ], [ -89.431099812999946, 14.418707580000046 ], [ -89.446835286999942, 14.415529481000078 ], [ -89.458126586999896, 14.419586080000073 ], [ -89.469417886999878, 14.425373840000049 ], [ -89.485282551999887, 14.427389222000102 ], [ -89.496148129999909, 14.42289748400006 ], [ -89.496547206788136, 14.423357651834124 ], [ -89.50954383038345, 14.438343817713019 ], [ -89.510732387889391, 14.440307522474143 ], [ -89.511507535144631, 14.441857815185983 ], [ -89.5116625638762, 14.44547516544651 ], [ -89.511171638360395, 14.450849513993887 ], [ -89.5085619775532, 14.462321682399704 ], [ -89.505306363397949, 14.471933498831902 ], [ -89.502309129862454, 14.478341376153594 ], [ -89.497554898040107, 14.492138984526491 ], [ -89.496547206788136, 14.497306627498858 ], [ -89.496314662791463, 14.501854152846875 ], [ -89.499131029173668, 14.508727118161971 ], [ -89.513135342222256, 14.523713284040809 ], [ -89.519388189913002, 14.525935370321065 ], [ -89.594525723083621, 14.52298981452833 ], [ -89.598220587709932, 14.524075019246709 ], [ -89.601734585182953, 14.526348782370405 ], [ -89.613103399901945, 14.542730211330195 ], [ -89.617883470146012, 14.551825262925547 ], [ -89.623542040432824, 14.559835109802464 ], [ -89.630518357636106, 14.567224839954406 ], [ -89.632637092028176, 14.569033515084641 ], [ -89.645194465152429, 14.573219306126077 ], [ -89.685502081955519, 14.577611802742467 ], [ -89.696173264684376, 14.577146714749063 ], [ -89.699609747791612, 14.577611802742467 ], [ -89.696044074374527, 14.598954169099613 ], [ -89.660232306975388, 14.695692450146453 ], [ -89.664133877176653, 14.707423000970721 ], [ -89.6677770658589, 14.715742906210153 ], [ -89.66893978584244, 14.721323961231803 ], [ -89.668629726580605, 14.72726675145941 ], [ -89.668035448277294, 14.730212307252145 ], [ -89.667182786656269, 14.733054511156752 ], [ -89.665089890685863, 14.745146796287599 ], [ -89.664986537898415, 14.748350735398105 ], [ -89.66700191860366, 14.759874578848724 ], [ -89.67082597533846, 14.77057160089862 ], [ -89.676045295154211, 14.778633123719658 ], [ -89.6889644025851, 14.782250474879504 ], [ -89.73635169117756, 14.779873358968302 ], [ -89.712683884853391, 14.821369534176654 ], [ -89.7086272859205, 14.837802639080508 ], [ -89.71170203292246, 14.862245591760654 ], [ -89.71035844578563, 14.867258206001395 ], [ -89.687517462660765, 14.888238837152585 ], [ -89.670412564188496, 14.901054591795969 ], [ -89.658656174942507, 14.899607651871634 ], [ -89.624678921095324, 14.882657782130934 ], [ -89.59258785674416, 14.867464911576405 ], [ -89.577860074183036, 14.864157620577714 ], [ -89.524323289787958, 14.863175766848144 ], [ -89.509104579912389, 14.86674144116455 ], [ -89.44866899267987, 14.913818671394552 ], [ -89.429342007027969, 14.919244696785313 ], [ -89.421073777732659, 14.919037991210303 ], [ -89.399162970594602, 14.912578437045227 ], [ -89.385391202442008, 14.903483385449874 ], [ -89.369113125370404, 14.903483385449874 ], [ -89.319762132916082, 14.919658107935334 ], [ -89.304130011890493, 14.914903876112987 ], [ -89.300099249580683, 14.909787909084741 ], [ -89.293691372258991, 14.905498766155119 ], [ -89.286172451797199, 14.905808824517635 ], [ -89.274286872241362, 14.909632880353115 ], [ -89.268163214860465, 14.914490464962967 ], [ -89.263512335825624, 14.919606431991213 ], [ -89.258344692853257, 14.927202866818845 ], [ -89.254236416177662, 14.930975246710261 ], [ -89.247544318015855, 14.935471096114156 ], [ -89.225452643724509, 14.946426500582504 ], [ -89.217856207997556, 14.948545234075254 ], [ -89.212585212237741, 14.949320380431175 ], [ -89.210027229173249, 14.948235174813476 ], [ -89.208115201255509, 14.94694326452003 ], [ -89.206332363647618, 14.945341294964749 ], [ -89.204730394092394, 14.943532619834514 ], [ -89.203180101380553, 14.941413886341763 ], [ -89.199356044645754, 14.934540920127347 ], [ -89.196436327274682, 14.927512926080681 ], [ -89.195118577660196, 14.925239162956984 ], [ -89.194110887307602, 14.922965399833345 ], [ -89.192715624226651, 14.920691636709648 ], [ -89.189563361060266, 14.913818671394552 ], [ -89.189214955999915, 14.913059034000113 ], [ -89.198814249999941, 14.899815165000064 ], [ -89.223618937999902, 14.879015401000103 ], [ -89.231447916999912, 14.867310690000124 ], [ -89.232429768999879, 14.848500468000026 ], [ -89.227675537999886, 14.83457367000004 ], [ -89.218968058999934, 14.821680400000034 ], [ -89.198814249999941, 14.798090108000025 ], [ -89.189409139999896, 14.783000590000114 ], [ -89.170547240999952, 14.738791403000107 ], [ -89.159669352999913, 14.725122986000088 ], [ -89.150522624999923, 14.717294007000064 ], [ -89.14621323435324, 14.710857663850106 ], [ -89.144502319999901, 14.708302308000029 ], [ -89.142693644999895, 14.691274923 ], [ -89.145225789999898, 14.683445943000066 ], [ -89.155845295999967, 14.672257995000038 ], [ -89.159410970999943, 14.665979309000122 ], [ -89.155225179999917, 14.615594788000038 ], [ -89.155741943999942, 14.59784393400011 ], [ -89.16039282299991, 14.581281637000103 ], [ -89.172149210999919, 14.570403747000057 ], [ -89.183698893999946, 14.569525248000019 ], [ -89.208813639999875, 14.577948507000102 ], [ -89.221086791999909, 14.580093079000093 ], [ -89.238114176999915, 14.577948507000102 ], [ -89.245684774999887, 14.572987570000066 ], [ -89.250542358999894, 14.565184428000038 ], [ -89.259611571999869, 14.554254862000064 ], [ -89.290927489999973, 14.528003235000128 ], [ -89.304854288999962, 14.513352966000056 ], [ -89.31480200199988, 14.495963847000041 ], [ -89.323044392999918, 14.487463074000118 ], [ -89.345265258999945, 14.481959534000026 ], [ -89.355497192999934, 14.475448303000064 ], [ -89.361982584999879, 14.462400004000102 ], [ -89.363791259999886, 14.44656117800011 ], [ -89.36162084999998, 14.415477804000062 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-PE", "NAME_1": "Petén" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.150727874192, 17.321032080166333 ], [ -89.149204845179298, 17.036270806333576 ], [ -89.166067397566337, 16.777009063383176 ], [ -89.184352706122695, 16.495872444329748 ], [ -89.193139671658514, 16.392625602989199 ], [ -89.2085168605212, 16.186131919766652 ], [ -89.234135091999946, 15.954944560000044 ], [ -89.236022275999858, 15.90649316800004 ], [ -89.236692268133652, 15.90709137626601 ], [ -89.237415737646131, 15.907737332312024 ], [ -89.242531703775114, 15.91150971130412 ], [ -89.265992805423593, 15.914739487937027 ], [ -89.358002692170487, 15.912930812806735 ], [ -89.369526537419745, 15.901613674031807 ], [ -89.375934413842117, 15.885232245072018 ], [ -89.377768928293392, 15.878307602913537 ], [ -89.378957485799333, 15.875000311914846 ], [ -89.380662808142063, 15.871641344072771 ], [ -89.384590216765048, 15.867894801703699 ], [ -89.396346605111717, 15.861280218807053 ], [ -89.426396451235235, 15.853968003920215 ], [ -89.438437058623322, 15.848619492895239 ], [ -89.446395229556174, 15.849368800829495 ], [ -89.463345100196193, 15.858257147749157 ], [ -89.484661628131619, 15.854174710394545 ], [ -89.511119960617691, 15.842289129939388 ], [ -89.51243771023212, 15.842108262786098 ], [ -89.513031989434751, 15.843115953138692 ], [ -89.515512458133401, 15.895179959187772 ], [ -89.516313442911041, 15.897686266308142 ], [ -89.520602586739983, 15.899288234964047 ], [ -89.526958788117554, 15.899856675744957 ], [ -89.540833909956973, 15.899210719698942 ], [ -89.546931728916149, 15.897944647827217 ], [ -89.551324226431859, 15.896497707902881 ], [ -89.553365444659505, 15.894973252713442 ], [ -89.555665046204922, 15.893707179942396 ], [ -89.558300543635141, 15.89277700395553 ], [ -89.561246101226573, 15.892156887230556 ], [ -89.565044317741069, 15.892182724752956 ], [ -89.626952684218963, 15.900063381319967 ], [ -89.633954840743286, 15.899701646114067 ], [ -89.645659553145833, 15.890554918574594 ], [ -89.647907477847809, 15.889237168960165 ], [ -89.65038794564714, 15.888229477708194 ], [ -89.655839810358941, 15.886963405836468 ], [ -89.669249844204955, 15.887738552192388 ], [ -89.67390072323974, 15.889314683325949 ], [ -89.679533454205512, 15.892001858498929 ], [ -89.700384895046852, 15.905799465073244 ], [ -89.716197883225732, 15.918770250246837 ], [ -89.718988410286897, 15.920320542958677 ], [ -89.742552862924242, 15.930862535377685 ], [ -89.745472582093953, 15.931637681733605 ], [ -89.748495653151849, 15.93192190257372 ], [ -89.75219051777816, 15.929312241766524 ], [ -89.757616543168922, 15.926289170708628 ], [ -89.760407071129407, 15.925849921136944 ], [ -89.76916622594058, 15.926599229071144 ], [ -89.772163458576756, 15.926521714705359 ], [ -89.774798956906295, 15.925669053983654 ], [ -89.776736823245756, 15.924196274738279 ], [ -89.778442145588542, 15.922490953294869 ], [ -89.782602098208258, 15.916677354276487 ], [ -89.783842332557583, 15.915282091195536 ], [ -89.785005051641804, 15.914326076787006 ], [ -89.786865403615479, 15.913292548012691 ], [ -89.792213914640456, 15.911819770565955 ], [ -89.825855271703404, 15.910036932958064 ], [ -89.841332363997367, 15.912310696081761 ], [ -89.845595669404588, 15.912594916022556 ], [ -89.849238858086835, 15.912207343294256 ], [ -89.851951869882896, 15.911458035360056 ], [ -89.855336677046012, 15.91262075444422 ], [ -89.858902351362417, 15.915747179188941 ], [ -89.863604906341322, 15.924609686787619 ], [ -89.865181036575564, 15.92959646170732 ], [ -89.867790697382759, 15.935513414412526 ], [ -89.880838996022817, 15.952592475362451 ], [ -89.884249640708333, 15.958612779056466 ], [ -89.887272711766229, 15.962669378888734 ], [ -89.889701503621495, 15.963961290081443 ], [ -89.895308397064866, 15.963108629359738 ], [ -89.904713507922054, 15.964219672499894 ], [ -89.922180141600222, 15.975717678428111 ], [ -89.926624315060053, 15.971299343389944 ], [ -89.929078946236359, 15.97029165303735 ], [ -89.940473599377071, 15.97256541616099 ], [ -89.957449306640171, 15.985148626807643 ], [ -89.954943000419121, 15.991995753701076 ], [ -89.955201381938195, 15.99416616493653 ], [ -89.957087572333592, 15.99571645854769 ], [ -89.960007289704663, 15.997473455935221 ], [ -89.961350877740813, 15.999928087111527 ], [ -89.961195848109867, 16.000419013526653 ], [ -89.960885789747408, 16.001013291829963 ], [ -89.960188157757273, 16.002873642904262 ], [ -89.959645555398026, 16.005069892561494 ], [ -89.959723069763868, 16.007627874726609 ], [ -89.961118333744082, 16.009462389177884 ], [ -89.963211228815112, 16.010805976314714 ], [ -89.970781827019664, 16.01380320895089 ], [ -89.97284888366903, 16.014345811310136 ], [ -89.97455420601176, 16.013932400160115 ], [ -89.974812588430211, 16.01096100504634 ], [ -89.972719693359124, 16.003183702166098 ], [ -89.972487149362451, 16.001168321460852 ], [ -89.97246131094073, 16.000108954264817 ], [ -89.972538825306515, 15.999773058379901 ], [ -89.973081427665761, 15.999152939856288 ], [ -89.97494177874006, 15.998041896716131 ], [ -89.983003303359737, 15.996543279948412 ], [ -89.985793830420903, 15.995303046498407 ], [ -89.98866187184791, 15.994786282560881 ], [ -89.991038987759055, 15.995251370554286 ], [ -89.994940558859696, 15.999566351905628 ], [ -89.996490851571536, 16.000031439899033 ], [ -89.999255541110301, 16.000005601477312 ], [ -90.004733243344504, 15.998765367127987 ], [ -90.008531459858943, 15.999488837539786 ], [ -90.011296149397765, 16.002873642904262 ], [ -90.012097134175406, 16.006206773223994 ], [ -90.014732631605625, 16.008945624341095 ], [ -90.019176805065456, 16.010082505902915 ], [ -90.03010637111214, 16.008532213191074 ], [ -90.034447190885146, 16.006077582014768 ], [ -90.037160203580527, 16.003493761427933 ], [ -90.037780321204821, 16.001478379823368 ], [ -90.038322923564067, 16.000238145474043 ], [ -90.038477953194956, 16.000005601477312 ], [ -90.040105760272581, 15.998791205549708 ], [ -90.046668667225219, 15.999462999118123 ], [ -90.21681332067817, 16.052147121892119 ], [ -90.420754360825072, 16.082377835168927 ], [ -90.447841201999921, 16.079686593000091 ], [ -90.444164591999908, 16.084652405 ], [ -90.437420816999889, 16.098863424000044 ], [ -90.434475260999903, 16.107183330000012 ], [ -90.440211344999852, 16.104857890000076 ], [ -90.442743489999941, 16.104186096000106 ], [ -90.44452632699992, 16.103255920000052 ], [ -90.448143676999905, 16.099741924000099 ], [ -90.455585083999921, 16.099741924000099 ], [ -90.459486653999875, 16.11679514600003 ], [ -90.435302083999915, 16.136277161000024 ], [ -90.448143676999905, 16.148214417000062 ], [ -90.448143676999905, 16.154415589000038 ], [ -90.426129516999907, 16.163148906000018 ], [ -90.432718261999923, 16.173225810000062 ], [ -90.461812093999924, 16.18914215100007 ], [ -90.46558447299995, 16.208107402000039 ], [ -90.458504801999908, 16.221749980000041 ], [ -90.446231648999884, 16.230845032 ], [ -90.434475260999903, 16.236322734000098 ], [ -90.447988647999864, 16.241490377 ], [ -90.457833008999842, 16.249138489000089 ], [ -90.459434977999962, 16.259060364000064 ], [ -90.448143676999905, 16.27110097300006 ], [ -90.443725342999898, 16.266863505000103 ], [ -90.440624755999863, 16.265313212000066 ], [ -90.427679809999944, 16.263607890000017 ], [ -90.431426350999857, 16.268930563000069 ], [ -90.437524169999904, 16.280040996000068 ], [ -90.441296549999947, 16.285363668000016 ], [ -90.436749023999909, 16.284846904000077 ], [ -90.435508788999869, 16.286242168000072 ], [ -90.435508788999869, 16.288774312000058 ], [ -90.434475260999903, 16.291564840000106 ], [ -90.428558309999886, 16.28763743100005 ], [ -90.420238403999917, 16.285363668000016 ], [ -90.414063069999941, 16.287844137 ], [ -90.414011392999925, 16.298386129000065 ], [ -90.420186727999919, 16.296009013000017 ], [ -90.434733642999873, 16.301228333000026 ], [ -90.444888061999904, 16.308359680000066 ], [ -90.437885904999916, 16.312080383000094 ], [ -90.419463256999904, 16.317816467000043 ], [ -90.404683797999894, 16.331510722000061 ], [ -90.398792683999886, 16.347582092000025 ], [ -90.40719010499987, 16.360449524000032 ], [ -90.414011392999925, 16.360449524000032 ], [ -90.414011392999925, 16.353008118 ], [ -90.420806843999884, 16.353008118 ], [ -90.418223022999967, 16.367167461000051 ], [ -90.408740397999907, 16.372335103000054 ], [ -90.395123656999885, 16.371404927000086 ], [ -90.379853271999934, 16.367270813000076 ], [ -90.391377116999877, 16.385977681000057 ], [ -90.392694864999839, 16.391713766000024 ], [ -90.392901570999896, 16.404839580000086 ], [ -90.394916951999846, 16.419205627000096 ], [ -90.400601359999882, 16.420549215000065 ], [ -90.409463867999904, 16.41667348300011 ], [ -90.420806843999884, 16.415123190000074 ], [ -90.426697957999892, 16.417707011000076 ], [ -90.434113525999891, 16.42240956600007 ], [ -90.444371297999879, 16.426802063000068 ], [ -90.475842244999939, 16.430729472000039 ], [ -90.47842606699993, 16.436413879000057 ], [ -90.477082478999961, 16.44499216700008 ], [ -90.482301798999885, 16.45605092400011 ], [ -90.488218750999891, 16.461580302000087 ], [ -90.497753052999883, 16.468039856000061 ], [ -90.508915161999909, 16.47108876500009 ], [ -90.532893025999925, 16.459926656000064 ], [ -90.539068359999902, 16.468866679000072 ], [ -90.54371923899987, 16.490209045000071 ], [ -90.553408569999903, 16.490260722000087 ], [ -90.579350138999956, 16.482767639000073 ], [ -90.584724487999921, 16.480235495000059 ], [ -90.590615600999911, 16.483387757000045 ], [ -90.604671590999942, 16.486178284000076 ], [ -90.620742961999895, 16.486746725000032 ], [ -90.633093627999955, 16.483336080000115 ], [ -90.627874307999946, 16.492896220000105 ], [ -90.618985961999925, 16.500079244000077 ], [ -90.612061319999839, 16.507624003000032 ], [ -90.612629760999909, 16.518114319000077 ], [ -90.624153604999918, 16.524935608000121 ], [ -90.639501505999903, 16.525865784000061 ], [ -90.648183146999941, 16.529586487000088 ], [ -90.639966592999912, 16.544831034000126 ], [ -90.643532267999888, 16.561005758000121 ], [ -90.637021037999915, 16.577903952000028 ], [ -90.63376542199984, 16.592166646000081 ], [ -90.647356323999929, 16.600073140000049 ], [ -90.650250203999917, 16.593406881000121 ], [ -90.653609171999932, 16.590099590000122 ], [ -90.658828491999941, 16.588445943000082 ], [ -90.667200073999908, 16.586999003000088 ], [ -90.667200073999908, 16.593200175000064 ], [ -90.654022582999943, 16.616609599000029 ], [ -90.667716837999961, 16.6525763960001 ], [ -90.735309610999934, 16.74657582600004 ], [ -90.749779011999863, 16.757686259000067 ], [ -90.785590779999978, 16.774997864000071 ], [ -90.800370239999893, 16.786831767000066 ], [ -90.79695959599988, 16.798665670000091 ], [ -90.79695959599988, 16.805435283000023 ], [ -90.810602172999978, 16.812928365000076 ], [ -90.819955606999912, 16.805331930000094 ], [ -90.831737833999938, 16.805435283000023 ], [ -90.900622518999938, 16.826002503000026 ], [ -90.91907100399996, 16.836337789000126 ], [ -90.948164835999961, 16.864708150000027 ], [ -90.968887085999881, 16.87437164300006 ], [ -90.952764037999913, 16.890908102000068 ], [ -90.955192830999863, 16.898762919000077 ], [ -90.968835408999979, 16.901036682000026 ], [ -90.986250366999911, 16.901088359000127 ], [ -90.987955688999875, 16.896902568000073 ], [ -90.984286662999892, 16.887755840000082 ], [ -90.983253133999909, 16.878609110000113 ], [ -90.993071655999955, 16.87437164300006 ], [ -90.998342651999906, 16.877162170000119 ], [ -91.010900024999899, 16.890287984000096 ], [ -91.016687784999874, 16.894835511000039 ], [ -91.054928345999969, 16.908013 ], [ -91.066865600999904, 16.918193258000073 ], [ -91.071309774999918, 16.938915507 ], [ -91.076942504999948, 16.949509176000063 ], [ -91.11223750899984, 16.990488587000115 ], [ -91.116113240999908, 16.999273580000093 ], [ -91.121229207999875, 17.018393860000103 ], [ -91.126551879999937, 17.024595032000079 ], [ -91.137145548999911, 17.0265070600001 ], [ -91.161226765999857, 17.023974915000011 ], [ -91.171200317999961, 17.02800567700011 ], [ -91.206753703999908, 17.065367737000045 ], [ -91.215952107999925, 17.079217021000105 ], [ -91.22024125199988, 17.089293925000064 ], [ -91.225357218999875, 17.107018942000067 ], [ -91.229594685999928, 17.113995260000067 ], [ -91.238793090999934, 17.119214579000086 ], [ -91.259205281999868, 17.124330547000071 ], [ -91.263132690999839, 17.130738424000114 ], [ -91.265148071999903, 17.146241354000026 ], [ -91.270832479999939, 17.164276428000036 ], [ -91.279514119999902, 17.18008941600003 ], [ -91.290417846999873, 17.189081116000082 ], [ -91.317754679999979, 17.19047638000005 ], [ -91.344523071999873, 17.186342265000022 ], [ -91.364883585999877, 17.189752910000053 ], [ -91.372945108999971, 17.213575745000028 ], [ -91.388344685999954, 17.221585592000011 ], [ -91.419247192999961, 17.227735087000084 ], [ -91.442501586999867, 17.237967020000056 ], [ -91.438264119999928, 17.253676657000128 ], [ -91.433267451748108, 17.254538150951397 ], [ -91.430771036999886, 17.254968567000063 ], [ -90.991986449999871, 17.251919658000034 ], [ -90.991443847999932, 17.526941630500019 ], [ -90.990901245999879, 17.801963603 ], [ -90.982839721999881, 17.810541890000124 ], [ -90.962220825999879, 17.816019593000121 ], [ -90.919122680999862, 17.816019593000121 ], [ -90.699239461999923, 17.815812887000064 ], [ -90.479459594999923, 17.815606181000092 ], [ -90.259653890999886, 17.815347799000037 ], [ -90.039770670999928, 17.815141093000065 ], [ -89.820016642999946, 17.814986064000024 ], [ -89.600159261999892, 17.814727681000065 ], [ -89.380301880999866, 17.814520976000026 ], [ -89.160496174999935, 17.814314270000054 ], [ -89.156217395392076, 17.59824334848561 ], [ -89.150727874192, 17.321032080166333 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-SM", "NAME_1": "San Marcos" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -92.246256503999888, 14.546279476000095 ], [ -92.226097167999882, 14.54934560200013 ], [ -92.208062093999899, 14.570507101000089 ], [ -92.186073770999911, 14.62957326300004 ], [ -92.164731404999912, 14.668149720000116 ], [ -92.160803996999846, 14.683497620000082 ], [ -92.16173417199991, 14.702333679000105 ], [ -92.179381672999881, 14.751581320000085 ], [ -92.180105143999896, 14.758790182000041 ], [ -92.178813232999943, 14.773388774000111 ], [ -92.179381672999881, 14.781243591000049 ], [ -92.188657592999903, 14.80589324900005 ], [ -92.190828002999893, 14.814238993000103 ], [ -92.191654826999923, 14.835297140000122 ], [ -92.186797241999898, 14.847260233000085 ], [ -92.166023315999951, 14.870824687000081 ], [ -92.154680338999896, 14.900797018000034 ], [ -92.157574218999883, 14.963041280000127 ], [ -92.154215250999954, 14.995933329000081 ], [ -92.142355509999931, 15.007483012000108 ], [ -92.129875650999935, 15.010945333000052 ], [ -92.116982380999843, 15.012392274000135 ], [ -92.103830729999856, 15.017869975000039 ], [ -92.093598795999895, 15.02941965800008 ], [ -92.073806721999915, 15.073706360000102 ], [ -92.203359537999916, 15.237158915000109 ], [ -92.21093013499987, 15.253359477000117 ], [ -92.211291870999872, 15.272066345000013 ], [ -92.204651448999954, 15.289507141000044 ], [ -92.186177123999926, 15.320383810000038 ], [ -92.137446248999908, 15.401825866000067 ], [ -92.105931231441161, 15.4544690619976 ], [ -92.099773321581495, 15.433606064868002 ], [ -92.082461716634896, 15.412599596194411 ], [ -92.067553066920482, 15.407121893960209 ], [ -92.065020922277711, 15.39229075771226 ], [ -92.055228237792903, 15.288498643297714 ], [ -92.044066127749602, 15.280152900535938 ], [ -91.992983975430093, 15.277904974934643 ], [ -91.990245124312992, 15.281160589989213 ], [ -91.956577927929004, 15.318936062149533 ], [ -91.942883674142251, 15.327410997019854 ], [ -91.910250007431898, 15.32983978887512 ], [ -91.879941778889986, 15.34818492349541 ], [ -91.862914394783502, 15.358287665443413 ], [ -91.856222296621695, 15.360690618876959 ], [ -91.849607713724993, 15.361233222135468 ], [ -91.840796882070435, 15.357279975090762 ], [ -91.806819628223252, 15.336557725458647 ], [ -91.785632289698412, 15.334955755903422 ], [ -91.731113654271724, 15.349941920882941 ], [ -91.715739915664585, 15.35012278893555 ], [ -91.714990606831009, 15.346324571521734 ], [ -91.710081346277093, 15.332914536776457 ], [ -91.69594784201928, 15.30808401136801 ], [ -91.6793855459062, 15.285863144968175 ], [ -91.660937059397781, 15.26648448337221 ], [ -91.641170824174196, 15.250361435931495 ], [ -91.631274786901884, 15.243643500247344 ], [ -91.621275396842066, 15.234290066233541 ], [ -91.616107753869755, 15.220880032387583 ], [ -91.620681119438075, 15.201940619463983 ], [ -91.627011480595343, 15.195584418086412 ], [ -91.661660528910261, 15.168428452710884 ], [ -91.679850633000285, 15.149411526320876 ], [ -91.699125942708065, 15.122384752154574 ], [ -91.708376023934363, 15.092464098139601 ], [ -91.696412930012684, 15.064765530404884 ], [ -91.677370165200955, 15.0492625996892 ], [ -91.673287726947024, 15.033191229991246 ], [ -91.679669765846995, 14.990403144489505 ], [ -91.683390468895027, 14.980171210433014 ], [ -91.691607022246274, 14.96947418928238 ], [ -91.720778368327046, 14.941775621547663 ], [ -91.728529832785512, 14.938468328750332 ], [ -91.736488002819044, 14.933765773771427 ], [ -91.737728238067689, 14.931078600397086 ], [ -91.739045986782855, 14.926944485299714 ], [ -91.738322517270319, 14.919968167197169 ], [ -91.739976161870345, 14.910408026709035 ], [ -91.749148728730802, 14.898160711947298 ], [ -91.755763313426144, 14.860695299048814 ], [ -91.763308072309655, 14.847621161087716 ], [ -91.764961716909681, 14.845140693288329 ], [ -91.791885139187798, 14.789743556919575 ], [ -91.792944506383833, 14.786694648339335 ], [ -91.795347459817378, 14.782973945291303 ], [ -91.79906816286541, 14.779253241344009 ], [ -91.812245652714694, 14.7697964545427 ], [ -91.81679317896203, 14.7648355171454 ], [ -91.819221970817296, 14.761528225247389 ], [ -91.832141079147448, 14.738480536547513 ], [ -91.841933762732936, 14.732382716689017 ], [ -91.850667080021708, 14.72897207290282 ], [ -91.86074398534663, 14.728041896916011 ], [ -91.888830125809648, 14.729592190527171 ], [ -91.951487800221798, 14.736103419736992 ], [ -92.039311896826575, 14.711505439224652 ], [ -92.06075761597117, 14.707526352858906 ], [ -92.072436489952054, 14.701790269105629 ], [ -92.099669968793989, 14.680396225905099 ], [ -92.134086473112234, 14.642052313863189 ], [ -92.137962205791155, 14.635954494904013 ], [ -92.136773648285214, 14.633008938211901 ], [ -92.133698900383934, 14.630063381519847 ], [ -92.125094774304387, 14.626859443308661 ], [ -92.119797940122794, 14.625515855272511 ], [ -92.060680100706065, 14.619624741888288 ], [ -92.052153489891623, 14.617557685238978 ], [ -92.049543829983747, 14.616420802777839 ], [ -92.040474615910796, 14.599212551518008 ], [ -92.016625943332599, 14.530947984561806 ], [ -92.046494921403507, 14.523713284040809 ], [ -92.055176560949519, 14.519785875417824 ], [ -92.066338670992877, 14.507796943074425 ], [ -92.070266078716543, 14.505109767901445 ], [ -92.073960944242174, 14.503559475189604 ], [ -92.07677730972506, 14.503197739983705 ], [ -92.07987789604806, 14.503352768715274 ], [ -92.08272009995261, 14.503766180764615 ], [ -92.087965258190081, 14.505626531838971 ], [ -92.097447883413054, 14.507538559756711 ], [ -92.107473110995272, 14.508210354224445 ], [ -92.112356534026787, 14.507228502293515 ], [ -92.115741340290583, 14.505936591100806 ], [ -92.124681363154366, 14.497978420167954 ], [ -92.133543870752987, 14.491828925264656 ], [ -92.138530646572065, 14.489658514928522 ], [ -92.143517422391085, 14.489296779722565 ], [ -92.153981900444307, 14.491777249320592 ], [ -92.157986823433134, 14.491053778908736 ], [ -92.160699836128515, 14.490123602921926 ], [ -92.16232764410546, 14.487436427748946 ], [ -92.162394631747958, 14.487325889609581 ], [ -92.246256503999888, 14.546279476000095 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-HU", "NAME_1": "Huehuetenango" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -92.105931231441161, 15.4544690619976 ], [ -92.068535725999965, 15.516935120000042 ], [ -91.989599975999937, 15.648968404000115 ], [ -91.910560871999849, 15.780950013000066 ], [ -91.841676188999941, 15.896085103000061 ], [ -91.792971150999904, 15.977578837000081 ], [ -91.774470987999877, 16.008429667000073 ], [ -91.751888386999923, 16.04630849200008 ], [ -91.739847778999973, 16.060984599000065 ], [ -91.723776408999896, 16.068787740000076 ], [ -91.678404500999875, 16.068891093 ], [ -91.540480102999908, 16.069149475000089 ], [ -91.402607381999928, 16.069304505000034 ], [ -91.26478633699989, 16.069511210000073 ], [ -91.126913615999939, 16.069769593000061 ], [ -90.994797831999875, 16.069868593000066 ], [ -91.117430182756721, 15.834279283062472 ], [ -91.127171190398087, 15.815959987763222 ], [ -91.192257656665504, 15.68777659841129 ], [ -91.194583095733265, 15.684572659300784 ], [ -91.213289964660135, 15.667080186301519 ], [ -91.212023891889089, 15.660491440927217 ], [ -91.210835334383148, 15.658811957006208 ], [ -91.210034348706188, 15.656357326729221 ], [ -91.21204973031081, 15.654652004386492 ], [ -91.215692918993, 15.653308417249661 ], [ -91.224322882594947, 15.652533270893741 ], [ -91.228405320848879, 15.651628933328595 ], [ -91.232410243837649, 15.646073716728608 ], [ -91.25941117958223, 15.62762523022019 ], [ -91.262718472379561, 15.627005113495159 ], [ -91.269126349701253, 15.627030951017559 ], [ -91.272175259180869, 15.626643378289259 ], [ -91.27488827187625, 15.625945746299124 ], [ -91.277213710944011, 15.624783027214903 ], [ -91.289486864127468, 15.61449941721429 ], [ -91.293672655168905, 15.61318166849918 ], [ -91.297470872582664, 15.612613226818951 ], [ -91.300597297327386, 15.612923285181466 ], [ -91.303413661910952, 15.610985418842006 ], [ -91.305687425034591, 15.606877143065674 ], [ -91.307134365858303, 15.594836533878947 ], [ -91.309744024866859, 15.585379747077639 ], [ -91.31555762388524, 15.574165961090216 ], [ -91.318813238939811, 15.569385890846149 ], [ -91.321164517328612, 15.563572292727088 ], [ -91.322198046102926, 15.560032456832403 ], [ -91.323541633239756, 15.536803900979237 ], [ -91.329174364205528, 15.52781220127207 ], [ -91.331138068067389, 15.523006293505603 ], [ -91.331758185691683, 15.520319119231942 ], [ -91.332197435263424, 15.517141018543157 ], [ -91.332223272785768, 15.513988756276092 ], [ -91.331499803273289, 15.507839260473474 ], [ -91.330828009704874, 15.505152086199814 ], [ -91.329897833718007, 15.502516587870218 ], [ -91.327649909016088, 15.497969062522202 ], [ -91.326280484356857, 15.495927843395236 ], [ -91.325246954683166, 15.493705756215661 ], [ -91.322223883625327, 15.489235745233429 ], [ -91.302199265983347, 15.465826321327654 ], [ -91.300545619584682, 15.462699897482253 ], [ -91.299796311650425, 15.459650987103373 ], [ -91.299770474128081, 15.446964422769895 ], [ -91.298581915722821, 15.441331691804123 ], [ -91.294370287158984, 15.431668199427861 ], [ -91.288582525663003, 15.423064073348314 ], [ -91.282381354815641, 15.416320299242386 ], [ -91.263571133101266, 15.399292914236582 ], [ -91.25961788605656, 15.398466091037278 ], [ -91.253933479146724, 15.398311062305652 ], [ -91.224736293744968, 15.401773382935232 ], [ -91.212023891889089, 15.399318751758983 ], [ -91.184377000997756, 15.386787217955714 ], [ -91.182180752239901, 15.368752143496636 ], [ -91.190784878319448, 15.332914536776457 ], [ -91.189777187966854, 15.3272042914449 ], [ -91.184041104213577, 15.312269802409446 ], [ -91.179080165916901, 15.292245184767467 ], [ -91.19450558136748, 15.28880870255955 ], [ -91.203290574600317, 15.28787852657274 ], [ -91.227759365702127, 15.292167670401625 ], [ -91.236828578875816, 15.291935126404951 ], [ -91.259488694847391, 15.284648749040514 ], [ -91.302871059551762, 15.276897284581992 ], [ -91.310855068906278, 15.27165212724384 ], [ -91.31535091831023, 15.263151353052478 ], [ -91.341111619705487, 15.264908352238649 ], [ -91.352790493686314, 15.262815457167619 ], [ -91.376923387104625, 15.252325140692676 ], [ -91.392477993764373, 15.241240545914422 ], [ -91.43580868162536, 15.231499539172376 ], [ -91.445782233263458, 15.228786526476995 ], [ -91.450820685925919, 15.22638357214413 ], [ -91.454386359343005, 15.222688707517818 ], [ -91.467563850091608, 15.203878485803443 ], [ -91.473506639419838, 15.192664699816021 ], [ -91.474204271409974, 15.190003363964081 ], [ -91.47645219611195, 15.164862779293799 ], [ -91.47704647531458, 15.161813869814239 ], [ -91.481413132609987, 15.159385077059653 ], [ -91.485185513400722, 15.157731432459627 ], [ -91.51882686956435, 15.155974433273457 ], [ -91.538412237634645, 15.178970445129949 ], [ -91.541719530431976, 15.188298040721975 ], [ -91.541357795226077, 15.198064886785062 ], [ -91.548902554109588, 15.204007677012669 ], [ -91.616107753869755, 15.220880032387583 ], [ -91.621275396842066, 15.234290066233541 ], [ -91.631274786901884, 15.243643500247344 ], [ -91.641170824174196, 15.250361435931495 ], [ -91.660937059397781, 15.26648448337221 ], [ -91.6793855459062, 15.285863144968175 ], [ -91.69594784201928, 15.30808401136801 ], [ -91.710081346277093, 15.332914536776457 ], [ -91.714990606831009, 15.346324571521734 ], [ -91.715739915664585, 15.35012278893555 ], [ -91.731113654271724, 15.349941920882941 ], [ -91.785632289698412, 15.334955755903422 ], [ -91.806819628223252, 15.336557725458647 ], [ -91.840796882070435, 15.357279975090762 ], [ -91.849607713724993, 15.361233222135468 ], [ -91.856222296621695, 15.360690618876959 ], [ -91.862914394783502, 15.358287665443413 ], [ -91.879941778889986, 15.34818492349541 ], [ -91.910250007431898, 15.32983978887512 ], [ -91.942883674142251, 15.327410997019854 ], [ -91.956577927929004, 15.318936062149533 ], [ -91.990245124312992, 15.281160589989213 ], [ -91.992983975430093, 15.277904974934643 ], [ -92.044066127749602, 15.280152900535938 ], [ -92.055228237792903, 15.288498643297714 ], [ -92.065020922277711, 15.39229075771226 ], [ -92.067553066920482, 15.407121893960209 ], [ -92.082461716634896, 15.412599596194411 ], [ -92.099773321581495, 15.433606064868002 ], [ -92.105931231441161, 15.4544690619976 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-QC", "NAME_1": "Quiché" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.994797831999875, 16.069868593000066 ], [ -90.988989217999858, 16.069872946000075 ], [ -90.851116496999907, 16.070131327000055 ], [ -90.713295451999841, 16.070338034000102 ], [ -90.575474405999898, 16.070596415000082 ], [ -90.485738281999915, 16.070699768000097 ], [ -90.466152913999906, 16.072921855000104 ], [ -90.44819509742581, 16.079259908118274 ], [ -90.436412320272325, 16.073282781774935 ], [ -90.431503058819089, 16.065479641372349 ], [ -90.433544277946055, 16.056048692093441 ], [ -90.441993374394713, 16.044834906106018 ], [ -90.435998908223041, 16.034008693746216 ], [ -90.440262213630263, 16.024810289363359 ], [ -90.450494146787435, 16.020676174265986 ], [ -90.462483080030097, 16.024965318094928 ], [ -90.464395107947837, 16.019978543175228 ], [ -90.467831591055074, 16.015637722502902 ], [ -90.469330206923473, 16.010702623527266 ], [ -90.475531378670155, 16.010702623527266 ], [ -90.487365282281928, 16.017963162469982 ], [ -90.506743943877893, 16.006206773223994 ], [ -90.517105069143611, 16.010702623527266 ], [ -90.523952196036987, 16.010702623527266 ], [ -90.527776251872524, 16.004527289302928 ], [ -90.531031866927094, 16.003958849421338 ], [ -90.538214890604706, 16.010702623527266 ], [ -90.540385300940841, 16.00729197794243 ], [ -90.541625536189542, 16.004268906884533 ], [ -90.542710740907921, 16.004501450881264 ], [ -90.544416063250708, 16.010702623527266 ], [ -90.548576015870424, 16.006310126011499 ], [ -90.555113085300604, 16.000884101520057 ], [ -90.558084480414436, 15.997680162409551 ], [ -90.571339483730185, 16.004346422149638 ], [ -90.580227830649847, 16.012614651445006 ], [ -90.590304735075449, 16.018350735198283 ], [ -90.607099576084579, 16.017523911998921 ], [ -90.607099576084579, 16.024965318094928 ], [ -90.602216153053007, 16.026463934862704 ], [ -90.597281053178051, 16.02925446192387 ], [ -90.59283687971822, 16.03119232826333 ], [ -90.59283687971822, 16.038633735258657 ], [ -90.599761521876701, 16.042664495769827 ], [ -90.605549283372739, 16.042948717509319 ], [ -90.610096808720755, 16.039176336718526 ], [ -90.613300746931884, 16.03119232826333 ], [ -90.620147874724637, 16.03119232826333 ], [ -90.634307217404114, 16.045222479733638 ], [ -90.660145433165212, 16.039796454342877 ], [ -90.702700974670222, 16.017523911998921 ], [ -90.695259568574215, 16.003881334156233 ], [ -90.704199592337318, 15.998196926347077 ], [ -90.704044562706372, 15.993856106574071 ], [ -90.702158373210352, 15.988636785858944 ], [ -90.705801560993223, 15.980291043097168 ], [ -90.712752040674104, 15.976286119209021 ], [ -90.71748043497405, 15.980471910250458 ], [ -90.720684374084556, 15.987086493147103 ], [ -90.723164841883943, 15.990212917891824 ], [ -90.734430304714749, 15.985381170804374 ], [ -90.750191616949564, 15.97279796015772 ], [ -90.763524136429737, 15.96972321225644 ], [ -90.763524136429737, 15.962281806160433 ], [ -90.759364182910701, 15.958871161474917 ], [ -90.750501675312023, 15.949259345042719 ], [ -90.743654548418647, 15.956080634413752 ], [ -90.741871710810813, 15.952980048090751 ], [ -90.742181770072591, 15.951145535438116 ], [ -90.741380785295007, 15.950112005764424 ], [ -90.73621314232264, 15.949259345042719 ], [ -90.73621314232264, 15.942438056571063 ], [ -90.746109177796313, 15.935565090356647 ], [ -90.753808967210034, 15.921044013370533 ], [ -90.763524136429737, 15.88781606745755 ], [ -90.738616095756186, 15.885283921915459 ], [ -90.73256995274113, 15.868101508178029 ], [ -90.742956916428511, 15.848619492895239 ], [ -90.767244838578392, 15.839395250090718 ], [ -90.771353116153364, 15.833452459863111 ], [ -90.784633958790153, 15.798415838819892 ], [ -90.811815761688024, 15.765110378541124 ], [ -90.818146124643931, 15.750640977499074 ], [ -90.805020310738712, 15.75211375584513 ], [ -90.793341437657205, 15.75079600713002 ], [ -90.783858812434232, 15.745938422520169 ], [ -90.777166714272425, 15.736972561234722 ], [ -90.782101814147381, 15.734802150898531 ], [ -90.786520148286172, 15.731158962216341 ], [ -90.791455248161128, 15.729531155138659 ], [ -90.791455248161128, 15.723329983391977 ], [ -90.7766499503349, 15.712348741401286 ], [ -90.770965541626424, 15.709041449503275 ], [ -90.784478929159263, 15.699739692332912 ], [ -90.788225470628959, 15.688448391080385 ], [ -90.780629034902006, 15.678914089013972 ], [ -90.743396166000252, 15.672738755689011 ], [ -90.700995653226812, 15.660801500189052 ], [ -90.689032559305133, 15.654419461289081 ], [ -90.680790168431486, 15.659199529734508 ], [ -90.671617600671709, 15.660801500189052 ], [ -90.662470873132293, 15.659199529734508 ], [ -90.65428015820271, 15.654419461289081 ], [ -90.657819994097451, 15.65361847651144 ], [ -90.660688036423721, 15.65361847651144 ], [ -90.662186652292178, 15.652326565318731 ], [ -90.661721564298716, 15.647598171018785 ], [ -90.642756313852772, 15.635815945149716 ], [ -90.632705247848889, 15.622922675241227 ], [ -90.631904263071249, 15.608608302930804 ], [ -90.640637580360021, 15.59235606518024 ], [ -90.625548061693678, 15.582124132023068 ], [ -90.615445318846355, 15.561272691181728 ], [ -90.608649868796363, 15.540757148023943 ], [ -90.603378872137228, 15.531532905219365 ], [ -90.596970994815536, 15.525951850197714 ], [ -90.603740607343127, 15.514066269742557 ], [ -90.614515143758865, 15.503162543016913 ], [ -90.620147874724637, 15.500501207164973 ], [ -90.648078985556708, 15.476290798481557 ], [ -90.648078985556708, 15.469469509110525 ], [ -90.640069138679792, 15.458875840747453 ], [ -90.65221310065408, 15.45262299215733 ], [ -90.692158983150534, 15.44897980437446 ], [ -90.705594855418212, 15.442313543735054 ], [ -90.709754808037928, 15.426603909242999 ], [ -90.707765265754404, 15.408439643574695 ], [ -90.702700974670222, 15.394357815260946 ], [ -90.682030401881548, 15.37495331524326 ], [ -90.650817836673809, 15.363093573209824 ], [ -90.493514777185226, 15.339735826147432 ], [ -90.477624273741242, 15.330976671336316 ], [ -90.478476936261586, 15.310641995331821 ], [ -90.487830370275333, 15.287645982576009 ], [ -90.497235480233201, 15.270851142466256 ], [ -90.503772548764118, 15.262195339543268 ], [ -90.541315476927707, 15.212508450304711 ], [ -90.574362555687401, 15.20997630476262 ], [ -90.691564703947904, 15.214937242159976 ], [ -90.85739437515025, 15.252686875898576 ], [ -90.865662605344937, 15.256846829417611 ], [ -90.871915453035683, 15.148481350334009 ], [ -90.797243007858526, 15.054947008397733 ], [ -90.707274340238598, 15.000221666496714 ], [ -90.707739427332683, 14.995519111517751 ], [ -90.712157762370794, 14.973763333111322 ], [ -90.694277716643285, 14.955676580909483 ], [ -90.687404751328188, 14.949940497156206 ], [ -90.680816005953886, 14.945703030170705 ], [ -90.673477952645385, 14.939036770430619 ], [ -90.669007940763834, 14.92957998272999 ], [ -90.657613287623121, 14.903948473443279 ], [ -90.671385056675035, 14.908909409941316 ], [ -90.707274340238598, 14.916195787305753 ], [ -90.736704067838446, 14.92596263336884 ], [ -90.753602260735704, 14.92823639649248 ], [ -90.805123664425537, 14.92823639649248 ], [ -90.852898525746355, 14.941878974335168 ], [ -90.868375617140998, 14.941568915073333 ], [ -90.882199063036296, 14.939295151949693 ], [ -90.893955451382965, 14.936814683251043 ], [ -90.95896440328454, 14.935264391438523 ], [ -90.977154507374621, 14.938623359280598 ], [ -90.99387183311859, 14.928649806743181 ], [ -91.010950894068515, 14.92420563418267 ], [ -91.020717740131602, 14.919554755147828 ], [ -91.022578091205901, 14.918262843955063 ], [ -91.024593471911203, 14.916557522511653 ], [ -91.030897997344709, 14.906583970873555 ], [ -91.05345475873014, 14.844933986813999 ], [ -91.060766975415561, 14.838939521541647 ], [ -91.087432014375963, 14.82627879473057 ], [ -91.103916796123201, 14.832014879383166 ], [ -91.108541835837059, 14.829224351422681 ], [ -91.112443406937643, 14.815633450423377 ], [ -91.1135802876002, 14.813359687299737 ], [ -91.114949714058014, 14.811344305695116 ], [ -91.11647416924751, 14.809483953721497 ], [ -91.11854122589682, 14.808140367483929 ], [ -91.121125048282352, 14.80721019149712 ], [ -91.124148119340191, 14.807106837810295 ], [ -91.127093675132983, 14.80741689707213 ], [ -91.129755011884299, 14.810207424133296 ], [ -91.13187374537705, 14.814858303168137 ], [ -91.133294846879664, 14.825607001162155 ], [ -91.133294846879664, 14.830981349709532 ], [ -91.132442186157959, 14.834908759231837 ], [ -91.131150274965194, 14.837079169568028 ], [ -91.122830369725762, 14.84596751648769 ], [ -91.11988481303365, 14.850101629786366 ], [ -91.117249314704111, 14.854855862508032 ], [ -91.116680873923201, 14.857336331206682 ], [ -91.11854122589682, 14.860540269417868 ], [ -91.123062913722492, 14.863847561315879 ], [ -91.134690110859935, 14.868136705144821 ], [ -91.14014197467236, 14.869531969125035 ], [ -91.144482795344686, 14.870255439536891 ], [ -91.147221645562468, 14.870358792324396 ], [ -91.150089687888794, 14.870875556261922 ], [ -91.156265022113075, 14.875319728822433 ], [ -91.165721808914327, 14.89180451146899 ], [ -91.170786099099189, 14.9051370300499 ], [ -91.182981737017542, 14.910666409127487 ], [ -91.214685227741029, 14.934850979389182 ], [ -91.212488979882494, 14.941155503923369 ], [ -91.206933763282507, 14.957743639357432 ], [ -91.207243821645022, 14.963996487048234 ], [ -91.210163539915413, 14.969577542069885 ], [ -91.226596645718587, 14.980739651213923 ], [ -91.233547126298845, 14.991488349207941 ], [ -91.23822384285603, 15.00936839403613 ], [ -91.240988532394852, 15.014484361064376 ], [ -91.243003913100097, 15.017429917756488 ], [ -91.2607806060401, 15.030400702030761 ], [ -91.271477627190734, 15.037066961770847 ], [ -91.273182950432783, 15.038927313744523 ], [ -91.274423183882789, 15.041304430554987 ], [ -91.274862434353849, 15.044301663191163 ], [ -91.275017463085419, 15.047402249514164 ], [ -91.274242315830179, 15.055153713073366 ], [ -91.271865200818354, 15.061716620026004 ], [ -91.268532071397942, 15.06641917590423 ], [ -91.260470546778265, 15.07256867080747 ], [ -91.25543209501518, 15.074687405199597 ], [ -91.251142951186239, 15.075720933074592 ], [ -91.240678474032336, 15.075927639548922 ], [ -91.237758754862625, 15.078046373041673 ], [ -91.235407478272464, 15.081922104821274 ], [ -91.234503139808055, 15.092050686090261 ], [ -91.234554815752119, 15.097218329062628 ], [ -91.240807665241562, 15.108483791893491 ], [ -91.247732307400042, 15.110705878173746 ], [ -91.249127569581674, 15.124555162490765 ], [ -91.25886857812236, 15.138042710702507 ], [ -91.263803677097997, 15.157576401929418 ], [ -91.270676643312413, 15.160470281778089 ], [ -91.2985302397787, 15.18824636477791 ], [ -91.301656663624101, 15.195119330093007 ], [ -91.315195888679284, 15.201630561101524 ], [ -91.32015682697596, 15.217081814074447 ], [ -91.320001797345071, 15.235220242220407 ], [ -91.31535091831023, 15.263151353052478 ], [ -91.310855068906278, 15.27165212724384 ], [ -91.302871059551762, 15.276897284581992 ], [ -91.259488694847391, 15.284648749040514 ], [ -91.236828578875816, 15.291935126404951 ], [ -91.227759365702127, 15.292167670401625 ], [ -91.203290574600317, 15.28787852657274 ], [ -91.19450558136748, 15.28880870255955 ], [ -91.179080165916901, 15.292245184767467 ], [ -91.184041104213577, 15.312269802409446 ], [ -91.189777187966854, 15.3272042914449 ], [ -91.190784878319448, 15.332914536776457 ], [ -91.182180752239901, 15.368752143496636 ], [ -91.184377000997756, 15.386787217955714 ], [ -91.212023891889089, 15.399318751758983 ], [ -91.224736293744968, 15.401773382935232 ], [ -91.253933479146724, 15.398311062305652 ], [ -91.25961788605656, 15.398466091037278 ], [ -91.263571133101266, 15.399292914236582 ], [ -91.282381354815641, 15.416320299242386 ], [ -91.288582525663003, 15.423064073348314 ], [ -91.294370287158984, 15.431668199427861 ], [ -91.298581915722821, 15.441331691804123 ], [ -91.299770474128081, 15.446964422769895 ], [ -91.299796311650425, 15.459650987103373 ], [ -91.300545619584682, 15.462699897482253 ], [ -91.302199265983347, 15.465826321327654 ], [ -91.322223883625327, 15.489235745233429 ], [ -91.325246954683166, 15.493705756215661 ], [ -91.326280484356857, 15.495927843395236 ], [ -91.327649909016088, 15.497969062522202 ], [ -91.329897833718007, 15.502516587870218 ], [ -91.330828009704874, 15.505152086199814 ], [ -91.331499803273289, 15.507839260473474 ], [ -91.332223272785768, 15.513988756276092 ], [ -91.332197435263424, 15.517141018543157 ], [ -91.331758185691683, 15.520319119231942 ], [ -91.331138068067389, 15.523006293505603 ], [ -91.329174364205528, 15.52781220127207 ], [ -91.323541633239756, 15.536803900979237 ], [ -91.322198046102926, 15.560032456832403 ], [ -91.321164517328612, 15.563572292727088 ], [ -91.318813238939811, 15.569385890846149 ], [ -91.31555762388524, 15.574165961090216 ], [ -91.309744024866859, 15.585379747077639 ], [ -91.307134365858303, 15.594836533878947 ], [ -91.305687425034591, 15.606877143065674 ], [ -91.303413661910952, 15.610985418842006 ], [ -91.300597297327386, 15.612923285181466 ], [ -91.297470872582664, 15.612613226818951 ], [ -91.293672655168905, 15.61318166849918 ], [ -91.289486864127468, 15.61449941721429 ], [ -91.277213710944011, 15.624783027214903 ], [ -91.27488827187625, 15.625945746299124 ], [ -91.272175259180869, 15.626643378289259 ], [ -91.269126349701253, 15.627030951017559 ], [ -91.262718472379561, 15.627005113495159 ], [ -91.25941117958223, 15.62762523022019 ], [ -91.232410243837649, 15.646073716728608 ], [ -91.228405320848879, 15.651628933328595 ], [ -91.224322882594947, 15.652533270893741 ], [ -91.215692918993, 15.653308417249661 ], [ -91.21204973031081, 15.654652004386492 ], [ -91.210034348706188, 15.656357326729221 ], [ -91.210835334383148, 15.658811957006208 ], [ -91.212023891889089, 15.660491440927217 ], [ -91.213289964660135, 15.667080186301519 ], [ -91.194583095733265, 15.684572659300784 ], [ -91.192257656665504, 15.68777659841129 ], [ -91.127171190398087, 15.815959987763222 ], [ -91.117430182756721, 15.834279283062472 ], [ -90.994797831999875, 16.069868593000066 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-AV", "NAME_1": "Alta Verapaz" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.44819509742581, 16.079259908118274 ], [ -90.447841201999921, 16.079686593000091 ], [ -90.420754360825072, 16.082377835168927 ], [ -90.21681332067817, 16.052147121892119 ], [ -90.046668667225219, 15.999462999118123 ], [ -90.040105760272581, 15.998791205549708 ], [ -90.038477953194956, 16.000005601477312 ], [ -90.038322923564067, 16.000238145474043 ], [ -90.037780321204821, 16.001478379823368 ], [ -90.037160203580527, 16.003493761427933 ], [ -90.034447190885146, 16.006077582014768 ], [ -90.03010637111214, 16.008532213191074 ], [ -90.019176805065456, 16.010082505902915 ], [ -90.014732631605625, 16.008945624341095 ], [ -90.012097134175406, 16.006206773223994 ], [ -90.011296149397765, 16.002873642904262 ], [ -90.008531459858943, 15.999488837539786 ], [ -90.004733243344504, 15.998765367127987 ], [ -89.999255541110301, 16.000005601477312 ], [ -89.996490851571536, 16.000031439899033 ], [ -89.994940558859696, 15.999566351905628 ], [ -89.991038987759055, 15.995251370554286 ], [ -89.98866187184791, 15.994786282560881 ], [ -89.985793830420903, 15.995303046498407 ], [ -89.983003303359737, 15.996543279948412 ], [ -89.97494177874006, 15.998041896716131 ], [ -89.973081427665761, 15.999152939856288 ], [ -89.972538825306515, 15.999773058379901 ], [ -89.97246131094073, 16.000108954264817 ], [ -89.972487149362451, 16.001168321460852 ], [ -89.972719693359124, 16.003183702166098 ], [ -89.974812588430211, 16.01096100504634 ], [ -89.97455420601176, 16.013932400160115 ], [ -89.97284888366903, 16.014345811310136 ], [ -89.970781827019664, 16.01380320895089 ], [ -89.963211228815112, 16.010805976314714 ], [ -89.961118333744082, 16.009462389177884 ], [ -89.959723069763868, 16.007627874726609 ], [ -89.959645555398026, 16.005069892561494 ], [ -89.960188157757273, 16.002873642904262 ], [ -89.960885789747408, 16.001013291829963 ], [ -89.961195848109867, 16.000419013526653 ], [ -89.961350877740813, 15.999928087111527 ], [ -89.960007289704663, 15.997473455935221 ], [ -89.957087572333592, 15.99571645854769 ], [ -89.955201381938195, 15.99416616493653 ], [ -89.954943000419121, 15.991995753701076 ], [ -89.957449306640171, 15.985148626807643 ], [ -89.940473599377071, 15.97256541616099 ], [ -89.929078946236359, 15.97029165303735 ], [ -89.926624315060053, 15.971299343389944 ], [ -89.922180141600222, 15.975717678428111 ], [ -89.904713507922054, 15.964219672499894 ], [ -89.895308397064866, 15.963108629359738 ], [ -89.889701503621495, 15.963961290081443 ], [ -89.887272711766229, 15.962669378888734 ], [ -89.884249640708333, 15.958612779056466 ], [ -89.880838996022817, 15.952592475362451 ], [ -89.867790697382759, 15.935513414412526 ], [ -89.865181036575564, 15.92959646170732 ], [ -89.863604906341322, 15.924609686787619 ], [ -89.858902351362417, 15.915747179188941 ], [ -89.855336677046012, 15.91262075444422 ], [ -89.851951869882896, 15.911458035360056 ], [ -89.849238858086835, 15.912207343294256 ], [ -89.845595669404588, 15.912594916022556 ], [ -89.841332363997367, 15.912310696081761 ], [ -89.825855271703404, 15.910036932958064 ], [ -89.792213914640456, 15.911819770565955 ], [ -89.786865403615479, 15.913292548012691 ], [ -89.785005051641804, 15.914326076787006 ], [ -89.783842332557583, 15.915282091195536 ], [ -89.782602098208258, 15.916677354276487 ], [ -89.778442145588542, 15.922490953294869 ], [ -89.776736823245756, 15.924196274738279 ], [ -89.774798956906295, 15.925669053983654 ], [ -89.772163458576756, 15.926521714705359 ], [ -89.76916622594058, 15.926599229071144 ], [ -89.760407071129407, 15.925849921136944 ], [ -89.757616543168922, 15.926289170708628 ], [ -89.75219051777816, 15.929312241766524 ], [ -89.748495653151849, 15.93192190257372 ], [ -89.745472582093953, 15.931637681733605 ], [ -89.742552862924242, 15.930862535377685 ], [ -89.718988410286897, 15.920320542958677 ], [ -89.716197883225732, 15.918770250246837 ], [ -89.700384895046852, 15.905799465073244 ], [ -89.679533454205512, 15.892001858498929 ], [ -89.67390072323974, 15.889314683325949 ], [ -89.669249844204955, 15.887738552192388 ], [ -89.655839810358941, 15.886963405836468 ], [ -89.65038794564714, 15.888229477708194 ], [ -89.647907477847809, 15.889237168960165 ], [ -89.645659553145833, 15.890554918574594 ], [ -89.633954840743286, 15.899701646114067 ], [ -89.626952684218963, 15.900063381319967 ], [ -89.565044317741069, 15.892182724752956 ], [ -89.561246101226573, 15.892156887230556 ], [ -89.558300543635141, 15.89277700395553 ], [ -89.555665046204922, 15.893707179942396 ], [ -89.553365444659505, 15.894973252713442 ], [ -89.551324226431859, 15.896497707902881 ], [ -89.546931728916149, 15.897944647827217 ], [ -89.540833909956973, 15.899210719698942 ], [ -89.526958788117554, 15.899856675744957 ], [ -89.520602586739983, 15.899288234964047 ], [ -89.516313442911041, 15.897686266308142 ], [ -89.515512458133401, 15.895179959187772 ], [ -89.513031989434751, 15.843115953138692 ], [ -89.51243771023212, 15.842108262786098 ], [ -89.511119960617691, 15.842289129939388 ], [ -89.484661628131619, 15.854174710394545 ], [ -89.463345100196193, 15.858257147749157 ], [ -89.446395229556174, 15.849368800829495 ], [ -89.438437058623322, 15.848619492895239 ], [ -89.426396451235235, 15.853968003920215 ], [ -89.396346605111717, 15.861280218807053 ], [ -89.423760952006319, 15.825804348192094 ], [ -89.43396704764109, 15.817949530046747 ], [ -89.453319871714712, 15.816037503028326 ], [ -89.456859706710077, 15.814280503842156 ], [ -89.459314337886383, 15.812316799080975 ], [ -89.464378628071188, 15.803247585907343 ], [ -89.465360480002118, 15.800586249156083 ], [ -89.477530280398128, 15.779192205955553 ], [ -89.481406013077049, 15.77428294540158 ], [ -89.484945848072414, 15.77159577112792 ], [ -89.495384487703916, 15.766996568037143 ], [ -89.512101813447941, 15.755601914896431 ], [ -89.517295294841972, 15.753121446197781 ], [ -89.527656420107689, 15.75002085987478 ], [ -89.530627814322145, 15.747953803225414 ], [ -89.532694871870831, 15.745447496105044 ], [ -89.534916958151086, 15.740434881864303 ], [ -89.597910529347416, 15.654626165964771 ], [ -89.654031135228706, 15.577705796984901 ], [ -89.661369187637888, 15.560885118453427 ], [ -89.658630337420107, 15.560109972097507 ], [ -89.654186163960276, 15.557526149712032 ], [ -89.652222460098415, 15.555898341735087 ], [ -89.650207079393169, 15.553753769820617 ], [ -89.648760138569514, 15.552022609955486 ], [ -89.644961921155698, 15.545950629417973 ], [ -89.622844408442688, 15.522954617561538 ], [ -89.614963751875621, 15.511482449155665 ], [ -89.606204597064504, 15.502154853563638 ], [ -89.593104620681686, 15.490553493948596 ], [ -89.589564785686321, 15.485101630136114 ], [ -89.588143684183649, 15.481225898356513 ], [ -89.596308559792192, 15.468487657179594 ], [ -89.597548794141517, 15.46613637879085 ], [ -89.599409146115192, 15.461072089505308 ], [ -89.602303025963863, 15.449987493827791 ], [ -89.604654304352664, 15.445259101326428 ], [ -89.606023729011895, 15.443269558143584 ], [ -89.607754889776345, 15.441228339016618 ], [ -89.6095894033283, 15.439523017573208 ], [ -89.61165645997761, 15.438024399906112 ], [ -89.630621711322874, 15.429239407572595 ], [ -89.636667854337986, 15.424769394791724 ], [ -89.638295661415611, 15.422909043717368 ], [ -89.647261521801795, 15.305706895456865 ], [ -89.647054816226785, 15.290694892055626 ], [ -89.64620215460576, 15.287258408948389 ], [ -89.642093878829428, 15.277620754094528 ], [ -89.639716762918283, 15.273254095899802 ], [ -89.63305050317814, 15.264391588301123 ], [ -89.627391933790705, 15.254857286234767 ], [ -89.626539273069, 15.250697332715731 ], [ -89.626616787434784, 15.245555528165085 ], [ -89.62979488812357, 15.22907074641779 ], [ -89.630053269642644, 15.223593044183644 ], [ -89.62979488812357, 15.219252224410639 ], [ -89.62788286020583, 15.214058743016551 ], [ -89.623438686745999, 15.204653632159363 ], [ -89.605506965074369, 15.179900621116758 ], [ -89.67467586869634, 15.164294338512889 ], [ -89.706611905215254, 15.166361396061575 ], [ -89.770251430658959, 15.156956285204387 ], [ -89.782033658326668, 15.159333401115532 ], [ -89.817044440048846, 15.172355862233246 ], [ -89.840117967170443, 15.17318268543255 ], [ -89.850530769279544, 15.171735745508215 ], [ -89.877996792118267, 15.159850165053058 ], [ -89.907193976620704, 15.152408758957051 ], [ -89.923833787998888, 15.151065171820221 ], [ -89.97300391329992, 15.156542874054367 ], [ -89.928846402239628, 15.217934474796152 ], [ -89.918149380189732, 15.247054144932804 ], [ -89.917374233833812, 15.257182725302528 ], [ -89.919312100173272, 15.262143662699884 ], [ -89.921715053606817, 15.266561997737995 ], [ -89.926417608585723, 15.272194728703766 ], [ -89.937657232994866, 15.282478338704379 ], [ -89.945098639990249, 15.28674164501092 ], [ -89.948741827773119, 15.287826849729299 ], [ -89.952100795615195, 15.288498643297714 ], [ -89.997007616408325, 15.284855455514844 ], [ -90.006050992059613, 15.282788397966158 ], [ -90.038813849979192, 15.270153510476121 ], [ -90.078010423642127, 15.268835760861634 ], [ -90.187176886603993, 15.283718573053704 ], [ -90.235235968764925, 15.294932359041127 ], [ -90.248775193820109, 15.295707506296367 ], [ -90.253090176070771, 15.292787787126656 ], [ -90.254821336835221, 15.291056627261526 ], [ -90.256371630446381, 15.289118760922065 ], [ -90.258903775089152, 15.284338691577318 ], [ -90.259756435810857, 15.282168280341864 ], [ -90.260505743745057, 15.275967109494502 ], [ -90.268567268364734, 15.24509044017168 ], [ -90.275336879993006, 15.235659490892772 ], [ -90.280091111815352, 15.231654567903945 ], [ -90.292312588155426, 15.216849270077716 ], [ -90.29621415925601, 15.21287018551061 ], [ -90.306316901204013, 15.20752167448569 ], [ -90.310270148248719, 15.207056586492286 ], [ -90.313164028996709, 15.207805894426485 ], [ -90.323835211725623, 15.218089504427098 ], [ -90.378922288832541, 15.254314682976201 ], [ -90.400548876029802, 15.260980942716344 ], [ -90.424113328667147, 15.260128281994582 ], [ -90.45770300978603, 15.260980942716344 ], [ -90.480569831332616, 15.261135973246553 ], [ -90.503772548764118, 15.262195339543268 ], [ -90.497235480233201, 15.270851142466256 ], [ -90.487830370275333, 15.287645982576009 ], [ -90.478476936261586, 15.310641995331821 ], [ -90.477624273741242, 15.330976671336316 ], [ -90.493514777185226, 15.339735826147432 ], [ -90.650817836673809, 15.363093573209824 ], [ -90.682030401881548, 15.37495331524326 ], [ -90.702700974670222, 15.394357815260946 ], [ -90.707765265754404, 15.408439643574695 ], [ -90.709754808037928, 15.426603909242999 ], [ -90.705594855418212, 15.442313543735054 ], [ -90.692158983150534, 15.44897980437446 ], [ -90.65221310065408, 15.45262299215733 ], [ -90.640069138679792, 15.458875840747453 ], [ -90.648078985556708, 15.469469509110525 ], [ -90.648078985556708, 15.476290798481557 ], [ -90.620147874724637, 15.500501207164973 ], [ -90.614515143758865, 15.503162543016913 ], [ -90.603740607343127, 15.514066269742557 ], [ -90.596970994815536, 15.525951850197714 ], [ -90.603378872137228, 15.531532905219365 ], [ -90.608649868796363, 15.540757148023943 ], [ -90.615445318846355, 15.561272691181728 ], [ -90.625548061693678, 15.582124132023068 ], [ -90.640637580360021, 15.59235606518024 ], [ -90.631904263071249, 15.608608302930804 ], [ -90.632705247848889, 15.622922675241227 ], [ -90.642756313852772, 15.635815945149716 ], [ -90.661721564298716, 15.647598171018785 ], [ -90.662186652292178, 15.652326565318731 ], [ -90.660688036423721, 15.65361847651144 ], [ -90.657819994097451, 15.65361847651144 ], [ -90.65428015820271, 15.654419461289081 ], [ -90.662470873132293, 15.659199529734508 ], [ -90.671617600671709, 15.660801500189052 ], [ -90.680790168431486, 15.659199529734508 ], [ -90.689032559305133, 15.654419461289081 ], [ -90.700995653226812, 15.660801500189052 ], [ -90.743396166000252, 15.672738755689011 ], [ -90.780629034902006, 15.678914089013972 ], [ -90.788225470628959, 15.688448391080385 ], [ -90.784478929159263, 15.699739692332912 ], [ -90.770965541626424, 15.709041449503275 ], [ -90.7766499503349, 15.712348741401286 ], [ -90.791455248161128, 15.723329983391977 ], [ -90.791455248161128, 15.729531155138659 ], [ -90.786520148286172, 15.731158962216341 ], [ -90.782101814147381, 15.734802150898531 ], [ -90.777166714272425, 15.736972561234722 ], [ -90.783858812434232, 15.745938422520169 ], [ -90.793341437657205, 15.75079600713002 ], [ -90.805020310738712, 15.75211375584513 ], [ -90.818146124643931, 15.750640977499074 ], [ -90.811815761688024, 15.765110378541124 ], [ -90.784633958790153, 15.798415838819892 ], [ -90.771353116153364, 15.833452459863111 ], [ -90.767244838578392, 15.839395250090718 ], [ -90.742956916428511, 15.848619492895239 ], [ -90.73256995274113, 15.868101508178029 ], [ -90.738616095756186, 15.885283921915459 ], [ -90.763524136429737, 15.88781606745755 ], [ -90.753808967210034, 15.921044013370533 ], [ -90.746109177796313, 15.935565090356647 ], [ -90.73621314232264, 15.942438056571063 ], [ -90.73621314232264, 15.949259345042719 ], [ -90.741380785295007, 15.950112005764424 ], [ -90.742181770072591, 15.951145535438116 ], [ -90.741871710810813, 15.952980048090751 ], [ -90.743654548418647, 15.956080634413752 ], [ -90.750501675312023, 15.949259345042719 ], [ -90.759364182910701, 15.958871161474917 ], [ -90.763524136429737, 15.962281806160433 ], [ -90.763524136429737, 15.96972321225644 ], [ -90.750191616949564, 15.97279796015772 ], [ -90.734430304714749, 15.985381170804374 ], [ -90.723164841883943, 15.990212917891824 ], [ -90.720684374084556, 15.987086493147103 ], [ -90.71748043497405, 15.980471910250458 ], [ -90.712752040674104, 15.976286119209021 ], [ -90.705801560993223, 15.980291043097168 ], [ -90.702158373210352, 15.988636785858944 ], [ -90.704044562706372, 15.993856106574071 ], [ -90.704199592337318, 15.998196926347077 ], [ -90.695259568574215, 16.003881334156233 ], [ -90.702700974670222, 16.017523911998921 ], [ -90.660145433165212, 16.039796454342877 ], [ -90.634307217404114, 16.045222479733638 ], [ -90.620147874724637, 16.03119232826333 ], [ -90.613300746931884, 16.03119232826333 ], [ -90.610096808720755, 16.039176336718526 ], [ -90.605549283372739, 16.042948717509319 ], [ -90.599761521876701, 16.042664495769827 ], [ -90.59283687971822, 16.038633735258657 ], [ -90.59283687971822, 16.03119232826333 ], [ -90.597281053178051, 16.02925446192387 ], [ -90.602216153053007, 16.026463934862704 ], [ -90.607099576084579, 16.024965318094928 ], [ -90.607099576084579, 16.017523911998921 ], [ -90.590304735075449, 16.018350735198283 ], [ -90.580227830649847, 16.012614651445006 ], [ -90.571339483730185, 16.004346422149638 ], [ -90.558084480414436, 15.997680162409551 ], [ -90.555113085300604, 16.000884101520057 ], [ -90.548576015870424, 16.006310126011499 ], [ -90.544416063250708, 16.010702623527266 ], [ -90.542710740907921, 16.004501450881264 ], [ -90.541625536189542, 16.004268906884533 ], [ -90.540385300940841, 16.00729197794243 ], [ -90.538214890604706, 16.010702623527266 ], [ -90.531031866927094, 16.003958849421338 ], [ -90.527776251872524, 16.004527289302928 ], [ -90.523952196036987, 16.010702623527266 ], [ -90.517105069143611, 16.010702623527266 ], [ -90.506743943877893, 16.006206773223994 ], [ -90.487365282281928, 16.017963162469982 ], [ -90.475531378670155, 16.010702623527266 ], [ -90.469330206923473, 16.010702623527266 ], [ -90.467831591055074, 16.015637722502902 ], [ -90.464395107947837, 16.019978543175228 ], [ -90.462483080030097, 16.024965318094928 ], [ -90.450494146787435, 16.020676174265986 ], [ -90.440262213630263, 16.024810289363359 ], [ -90.435998908223041, 16.034008693746216 ], [ -90.441993374394713, 16.044834906106018 ], [ -90.433544277946055, 16.056048692093441 ], [ -90.431503058819089, 16.065479641372349 ], [ -90.436412320272325, 16.073282781774935 ], [ -90.44819509742581, 16.079259908118274 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-IZ", "NAME_1": "Izabal" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.22093665299991, 15.725653387000079 ], [ -88.232619995999926, 15.721418762 ], [ -88.23574641999997, 15.71242706300005 ], [ -88.234919596999958, 15.701575013000095 ], [ -88.241585855999858, 15.688242493000089 ], [ -88.247761190999938, 15.695683899000088 ], [ -88.264995279999937, 15.688604228000074 ], [ -88.279697224999921, 15.680749410000047 ], [ -88.295587728999948, 15.675013326000098 ], [ -88.316671712999948, 15.674599914000069 ], [ -88.322304443999911, 15.667261861000085 ], [ -88.352560994999919, 15.616903178000101 ], [ -88.398992269999923, 15.572797343000033 ], [ -88.467433936427028, 15.520739666502379 ], [ -88.500019693999974, 15.495954489000027 ], [ -88.587378702999928, 15.430299581 ], [ -88.674195108999896, 15.365058086000076 ], [ -88.76089940199995, 15.299961814000071 ], [ -88.847026936999868, 15.235298564000104 ], [ -88.97342749099991, 15.140394796000123 ], [ -89.008283243999898, 15.124400940000086 ], [ -89.109827433999868, 15.09145721400003 ], [ -89.140523234999904, 15.076393534000132 ], [ -89.146940319140413, 15.071284391261656 ], [ -89.147472906649284, 15.071690172563422 ], [ -89.150185920243985, 15.073757229212731 ], [ -89.157420619865718, 15.076857815535732 ], [ -89.161787278959764, 15.079855048171908 ], [ -89.181243455820834, 15.102592678509268 ], [ -89.183207159682638, 15.108173733530975 ], [ -89.189149949910245, 15.136389065203161 ], [ -89.190648565778645, 15.152098699695216 ], [ -89.190028449053671, 15.161710517026734 ], [ -89.19039018425957, 15.167911688773415 ], [ -89.198193325561533, 15.199692694762064 ], [ -89.198296678348981, 15.20633311608043 ], [ -89.197211472731283, 15.21038971591264 ], [ -89.184679938028694, 15.215247301421812 ], [ -89.180571662252419, 15.218011990061257 ], [ -89.178788824644528, 15.219588121194818 ], [ -89.177109340723462, 15.221603501900063 ], [ -89.174628872024812, 15.226073512882294 ], [ -89.173750372881386, 15.22832143848359 ], [ -89.172587652897846, 15.234832669492107 ], [ -89.170365566617591, 15.259869900475508 ], [ -89.170830654610995, 15.266251939375479 ], [ -89.171605800966915, 15.269042467335964 ], [ -89.173207771421517, 15.272168891181366 ], [ -89.175559048011621, 15.275605374288602 ], [ -89.180519986308298, 15.280773017260913 ], [ -89.183723925418803, 15.283486029956293 ], [ -89.186591965946434, 15.285346381030649 ], [ -89.209872198643041, 15.297619534214107 ], [ -89.219871588702858, 15.299944973281868 ], [ -89.25051571312963, 15.302890529973979 ], [ -89.273718430561132, 15.298032945364127 ], [ -89.288187831603125, 15.291056627261526 ], [ -89.314284430681937, 15.272117214337982 ], [ -89.43130571178915, 15.22638357214413 ], [ -89.549799771242419, 15.187755439262105 ], [ -89.564656745012769, 15.184551500151599 ], [ -89.605506965074369, 15.179900621116758 ], [ -89.623438686745999, 15.204653632159363 ], [ -89.62788286020583, 15.214058743016551 ], [ -89.62979488812357, 15.219252224410639 ], [ -89.630053269642644, 15.223593044183644 ], [ -89.62979488812357, 15.22907074641779 ], [ -89.626616787434784, 15.245555528165085 ], [ -89.626539273069, 15.250697332715731 ], [ -89.627391933790705, 15.254857286234767 ], [ -89.63305050317814, 15.264391588301123 ], [ -89.639716762918283, 15.273254095899802 ], [ -89.642093878829428, 15.277620754094528 ], [ -89.64620215460576, 15.287258408948389 ], [ -89.647054816226785, 15.290694892055626 ], [ -89.647261521801795, 15.305706895456865 ], [ -89.638295661415611, 15.422909043717368 ], [ -89.636667854337986, 15.424769394791724 ], [ -89.630621711322874, 15.429239407572595 ], [ -89.61165645997761, 15.438024399906112 ], [ -89.6095894033283, 15.439523017573208 ], [ -89.607754889776345, 15.441228339016618 ], [ -89.606023729011895, 15.443269558143584 ], [ -89.604654304352664, 15.445259101326428 ], [ -89.602303025963863, 15.449987493827791 ], [ -89.599409146115192, 15.461072089505308 ], [ -89.597548794141517, 15.46613637879085 ], [ -89.596308559792192, 15.468487657179594 ], [ -89.588143684183649, 15.481225898356513 ], [ -89.589564785686321, 15.485101630136114 ], [ -89.593104620681686, 15.490553493948596 ], [ -89.606204597064504, 15.502154853563638 ], [ -89.614963751875621, 15.511482449155665 ], [ -89.622844408442688, 15.522954617561538 ], [ -89.644961921155698, 15.545950629417973 ], [ -89.648760138569514, 15.552022609955486 ], [ -89.650207079393169, 15.553753769820617 ], [ -89.652222460098415, 15.555898341735087 ], [ -89.654186163960276, 15.557526149712032 ], [ -89.658630337420107, 15.560109972097507 ], [ -89.661369187637888, 15.560885118453427 ], [ -89.654031135228706, 15.577705796984901 ], [ -89.597910529347416, 15.654626165964771 ], [ -89.534916958151086, 15.740434881864303 ], [ -89.532694871870831, 15.745447496105044 ], [ -89.530627814322145, 15.747953803225414 ], [ -89.527656420107689, 15.75002085987478 ], [ -89.517295294841972, 15.753121446197781 ], [ -89.512101813447941, 15.755601914896431 ], [ -89.495384487703916, 15.766996568037143 ], [ -89.484945848072414, 15.77159577112792 ], [ -89.481406013077049, 15.77428294540158 ], [ -89.477530280398128, 15.779192205955553 ], [ -89.465360480002118, 15.800586249156083 ], [ -89.464378628071188, 15.803247585907343 ], [ -89.459314337886383, 15.812316799080975 ], [ -89.456859706710077, 15.814280503842156 ], [ -89.453319871714712, 15.816037503028326 ], [ -89.43396704764109, 15.817949530046747 ], [ -89.423760952006319, 15.825804348192094 ], [ -89.396346605111717, 15.861280218807053 ], [ -89.384590216765048, 15.867894801703699 ], [ -89.380662808142063, 15.871641344072771 ], [ -89.378957485799333, 15.875000311914846 ], [ -89.377768928293392, 15.878307602913537 ], [ -89.375934413842117, 15.885232245072018 ], [ -89.369526537419745, 15.901613674031807 ], [ -89.358002692170487, 15.912930812806735 ], [ -89.265992805423593, 15.914739487937027 ], [ -89.242531703775114, 15.91150971130412 ], [ -89.237415737646131, 15.907737332312024 ], [ -89.236692268133652, 15.90709137626601 ], [ -89.236022275999858, 15.90649316800004 ], [ -89.236512207999908, 15.89391469300007 ], [ -89.228243977999853, 15.880840556000109 ], [ -89.225996053999921, 15.884044495000083 ], [ -89.21653926699986, 15.888643697000035 ], [ -89.204834553999888, 15.89241607700005 ], [ -89.195765339999923, 15.892932841000103 ], [ -89.17744604499984, 15.900270894000087 ], [ -89.100913248999944, 15.896808574000048 ], [ -89.072387858999889, 15.901511129000127 ], [ -89.040322631999885, 15.901717834000081 ], [ -88.951878418999854, 15.879651999000075 ], [ -88.913970506999959, 15.893947658000044 ], [ -88.900013800999943, 15.887844143000052 ], [ -88.866200324999909, 15.860337632000039 ], [ -88.831613735999952, 15.868638414000088 ], [ -88.78734290299991, 15.859076239000046 ], [ -88.753285285999937, 15.839789130000042 ], [ -88.749501105999911, 15.818793036000045 ], [ -88.72679602799991, 15.81517161700009 ], [ -88.625965949999909, 15.753892320000091 ], [ -88.638295050999943, 15.708807684000078 ], [ -88.636219855999911, 15.702093817000048 ], [ -88.609242316999939, 15.702093817000048 ], [ -88.598378058999913, 15.706122137000079 ], [ -88.595204230999911, 15.714667059000078 ], [ -88.59634355399993, 15.722154039000088 ], [ -88.598703579999949, 15.723211981000077 ], [ -88.598988410999937, 15.727362372000073 ], [ -88.602365688999896, 15.730902411000045 ], [ -88.605580206999946, 15.735541083000044 ], [ -88.605458136999914, 15.743068752000056 ], [ -88.600453253999945, 15.744574286000045 ], [ -88.591175910999937, 15.743557033000059 ], [ -88.582183397999927, 15.745021877000056 ], [ -88.578195766999897, 15.753892320000091 ], [ -88.574330206999946, 15.769964911000045 ], [ -88.565500454999949, 15.780951239000046 ], [ -88.556060350999928, 15.789496161000045 ], [ -88.550282355999911, 15.79828522300005 ], [ -88.54906165299991, 15.813666083000044 ], [ -88.556711391999897, 15.83734772300005 ], [ -88.557687954999949, 15.852932033000059 ], [ -88.550282355999911, 15.852932033000059 ], [ -88.550648566999939, 15.842474677000041 ], [ -88.550282355999911, 15.839260158000059 ], [ -88.544056769999941, 15.839260158000059 ], [ -88.532134568999936, 15.846828518000052 ], [ -88.503041144999941, 15.841376044000071 ], [ -88.488840298999946, 15.846747137000079 ], [ -88.51195227799991, 15.867580471000053 ], [ -88.524810350999928, 15.877020575000074 ], [ -88.54328365799995, 15.885158596000053 ], [ -88.55101477799991, 15.89516836100006 ], [ -88.557687954999949, 15.90656159100007 ], [ -88.564523891999897, 15.914984442000048 ], [ -88.607574022999927, 15.938421942000048 ], [ -88.619862433999913, 15.953273830000057 ], [ -88.605458136999914, 15.969631252000056 ], [ -88.590199347999942, 15.961004950000074 ], [ -88.561838344999899, 15.949042059000078 ], [ -88.550282355999911, 15.942328192000048 ], [ -88.521229620999918, 15.91274648600006 ], [ -88.50023352799991, 15.901068427000041 ], [ -88.44790605399993, 15.858710028000075 ], [ -88.344838019999941, 15.81195709800005 ], [ -88.311024542999917, 15.782416083000044 ], [ -88.300404425999943, 15.777818101000037 ], [ -88.256337042999917, 15.740383205000057 ], [ -88.221547003999945, 15.725897528000075 ], [ -88.22093665299991, 15.725653387000079 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-ZA", "NAME_1": "Zacapa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.146940319140413, 15.071284391261656 ], [ -89.16080623499991, 15.060244649000055 ], [ -89.172769328999976, 15.042209575000058 ], [ -89.18858231699997, 14.996088359000026 ], [ -89.169100300999872, 14.97841501900011 ], [ -89.169151977999888, 14.952060038000056 ], [ -89.181528482999852, 14.923663839000127 ], [ -89.189214955999915, 14.913059034000113 ], [ -89.189563361060266, 14.913818671394552 ], [ -89.192715624226651, 14.920691636709648 ], [ -89.194110887307602, 14.922965399833345 ], [ -89.195118577660196, 14.925239162956984 ], [ -89.196436327274682, 14.927512926080681 ], [ -89.199356044645754, 14.934540920127347 ], [ -89.203180101380553, 14.941413886341763 ], [ -89.204730394092394, 14.943532619834514 ], [ -89.206332363647618, 14.945341294964749 ], [ -89.208115201255509, 14.94694326452003 ], [ -89.210027229173249, 14.948235174813476 ], [ -89.212585212237741, 14.949320380431175 ], [ -89.217856207997556, 14.948545234075254 ], [ -89.225452643724509, 14.946426500582504 ], [ -89.247544318015855, 14.935471096114156 ], [ -89.254236416177662, 14.930975246710261 ], [ -89.258344692853257, 14.927202866818845 ], [ -89.263512335825624, 14.919606431991213 ], [ -89.268163214860465, 14.914490464962967 ], [ -89.274286872241362, 14.909632880353115 ], [ -89.286172451797199, 14.905808824517635 ], [ -89.293691372258991, 14.905498766155119 ], [ -89.300099249580683, 14.909787909084741 ], [ -89.304130011890493, 14.914903876112987 ], [ -89.319762132916082, 14.919658107935334 ], [ -89.369113125370404, 14.903483385449874 ], [ -89.385391202442008, 14.903483385449874 ], [ -89.399162970594602, 14.912578437045227 ], [ -89.421073777732659, 14.919037991210303 ], [ -89.429342007027969, 14.919244696785313 ], [ -89.44866899267987, 14.913818671394552 ], [ -89.509104579912389, 14.86674144116455 ], [ -89.524323289787958, 14.863175766848144 ], [ -89.577860074183036, 14.864157620577714 ], [ -89.59258785674416, 14.867464911576405 ], [ -89.624678921095324, 14.882657782130934 ], [ -89.658656174942507, 14.899607651871634 ], [ -89.670412564188496, 14.901054591795969 ], [ -89.687517462660765, 14.888238837152585 ], [ -89.71035844578563, 14.867258206001395 ], [ -89.71170203292246, 14.862245591760654 ], [ -89.7086272859205, 14.837802639080508 ], [ -89.712683884853391, 14.821369534176654 ], [ -89.73635169117756, 14.779873358968302 ], [ -89.747720506795929, 14.782922268447919 ], [ -89.763636847762314, 14.785299384359064 ], [ -89.790431077931885, 14.785299384359064 ], [ -89.793660854564791, 14.785712795509085 ], [ -89.799448615161452, 14.79217235057348 ], [ -89.8076910060351, 14.803592841236593 ], [ -89.823633186322468, 14.833203436889107 ], [ -89.83290910507111, 14.84596751648769 ], [ -89.838851895298717, 14.856199448745542 ], [ -89.841719936725667, 14.859816799006069 ], [ -89.833994309789546, 14.876508287227637 ], [ -89.811592577135684, 14.901054591795969 ], [ -89.799009365589711, 14.906428941242609 ], [ -89.777563646445117, 14.90704905796764 ], [ -89.772680223413545, 14.907875881166945 ], [ -89.768675300424775, 14.90952952756561 ], [ -89.766685757241873, 14.914283759387956 ], [ -89.764567022849803, 14.934024156189821 ], [ -89.767047492447773, 14.937228095300327 ], [ -89.772111782632635, 14.940225327936503 ], [ -89.784927538175339, 14.941982327122673 ], [ -89.797123176093692, 14.948235174813476 ], [ -89.805107185448207, 14.959242255225888 ], [ -89.849083827556569, 15.017998359436717 ], [ -89.85179684115127, 15.022752590359744 ], [ -89.852727017138136, 15.026679998982729 ], [ -89.848696254828269, 15.02823029169457 ], [ -89.843942023005923, 15.02885040931892 ], [ -89.795572883381851, 15.029832262149171 ], [ -89.796554735312782, 15.043268134416849 ], [ -89.841048143157252, 15.108483791893491 ], [ -89.877996792118267, 15.159850165053058 ], [ -89.850530769279544, 15.171735745508215 ], [ -89.840117967170443, 15.17318268543255 ], [ -89.817044440048846, 15.172355862233246 ], [ -89.782033658326668, 15.159333401115532 ], [ -89.770251430658959, 15.156956285204387 ], [ -89.706611905215254, 15.166361396061575 ], [ -89.67467586869634, 15.164294338512889 ], [ -89.605506965074369, 15.179900621116758 ], [ -89.564656745012769, 15.184551500151599 ], [ -89.549799771242419, 15.187755439262105 ], [ -89.43130571178915, 15.22638357214413 ], [ -89.314284430681937, 15.272117214337982 ], [ -89.288187831603125, 15.291056627261526 ], [ -89.273718430561132, 15.298032945364127 ], [ -89.25051571312963, 15.302890529973979 ], [ -89.219871588702858, 15.299944973281868 ], [ -89.209872198643041, 15.297619534214107 ], [ -89.186591965946434, 15.285346381030649 ], [ -89.183723925418803, 15.283486029956293 ], [ -89.180519986308298, 15.280773017260913 ], [ -89.175559048011621, 15.275605374288602 ], [ -89.173207771421517, 15.272168891181366 ], [ -89.171605800966915, 15.269042467335964 ], [ -89.170830654610995, 15.266251939375479 ], [ -89.170365566617591, 15.259869900475508 ], [ -89.172587652897846, 15.234832669492107 ], [ -89.173750372881386, 15.22832143848359 ], [ -89.174628872024812, 15.226073512882294 ], [ -89.177109340723462, 15.221603501900063 ], [ -89.178788824644528, 15.219588121194818 ], [ -89.180571662252419, 15.218011990061257 ], [ -89.184679938028694, 15.215247301421812 ], [ -89.197211472731283, 15.21038971591264 ], [ -89.198296678348981, 15.20633311608043 ], [ -89.198193325561533, 15.199692694762064 ], [ -89.19039018425957, 15.167911688773415 ], [ -89.190028449053671, 15.161710517026734 ], [ -89.190648565778645, 15.152098699695216 ], [ -89.189149949910245, 15.136389065203161 ], [ -89.183207159682638, 15.108173733530975 ], [ -89.181243455820834, 15.102592678509268 ], [ -89.161787278959764, 15.079855048171908 ], [ -89.157420619865718, 15.076857815535732 ], [ -89.150185920243985, 15.073757229212731 ], [ -89.147472906649284, 15.071690172563422 ], [ -89.146940319140413, 15.071284391261656 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-RE", "NAME_1": "Retalhuleu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -91.658500845474649, 14.117349342936476 ], [ -91.762557670999911, 14.180174112000088 ], [ -91.908192511999914, 14.28384023600006 ], [ -92.049590623999904, 14.408026434000078 ], [ -92.162394631747958, 14.487325889609581 ], [ -92.16232764410546, 14.487436427748946 ], [ -92.160699836128515, 14.490123602921926 ], [ -92.157986823433134, 14.491053778908736 ], [ -92.153981900444307, 14.491777249320592 ], [ -92.143517422391085, 14.489296779722565 ], [ -92.138530646572065, 14.489658514928522 ], [ -92.133543870752987, 14.491828925264656 ], [ -92.124681363154366, 14.497978420167954 ], [ -92.115741340290583, 14.505936591100806 ], [ -92.112356534026787, 14.507228502293515 ], [ -92.107473110995272, 14.508210354224445 ], [ -92.097447883413054, 14.507538559756711 ], [ -92.087965258190081, 14.505626531838971 ], [ -92.08272009995261, 14.503766180764615 ], [ -92.07987789604806, 14.503352768715274 ], [ -92.07677730972506, 14.503197739983705 ], [ -92.073960944242174, 14.503559475189604 ], [ -92.070266078716543, 14.505109767901445 ], [ -92.066338670992877, 14.507796943074425 ], [ -92.055176560949519, 14.519785875417824 ], [ -92.046494921403507, 14.523713284040809 ], [ -92.016625943332599, 14.530947984561806 ], [ -92.008538581190578, 14.536425685896688 ], [ -92.003345099796491, 14.538647773076264 ], [ -92.000942146362945, 14.539112861069668 ], [ -91.996730516000468, 14.537975979507848 ], [ -91.937948575166615, 14.513481349984318 ], [ -91.926657273914032, 14.511724350798147 ], [ -91.897460090310915, 14.514308173183622 ], [ -91.855783047049954, 14.523454902521735 ], [ -91.824596320263936, 14.56882680950963 ], [ -91.814777798256785, 14.579937241810228 ], [ -91.812555711976529, 14.5840713569076 ], [ -91.810230272009449, 14.59058258701674 ], [ -91.806716275435747, 14.604948635271285 ], [ -91.803253953906847, 14.614043686866637 ], [ -91.798835618868679, 14.623138739361309 ], [ -91.780903897197106, 14.649183660697361 ], [ -91.776408046893835, 14.658795478028878 ], [ -91.767726407347823, 14.686235663345144 ], [ -91.761034309186016, 14.696519273345757 ], [ -91.725248379309221, 14.713469143086456 ], [ -91.711709154254038, 14.727938544128506 ], [ -91.704293585680432, 14.734139715875187 ], [ -91.700056118694931, 14.736878566992232 ], [ -91.69731726757783, 14.738325506916624 ], [ -91.694320034941654, 14.739514065321828 ], [ -91.690056728635113, 14.740134182046859 ], [ -91.686620246427196, 14.739927476471848 ], [ -91.683933072153536, 14.738997301384359 ], [ -91.682227748911487, 14.736568507730453 ], [ -91.68109086824893, 14.734398098293582 ], [ -91.682615323438426, 14.722150784431165 ], [ -91.69692969395021, 14.689129544093191 ], [ -91.699746060332416, 14.671611233571582 ], [ -91.697084723581099, 14.66882070651036 ], [ -91.692097947762079, 14.66634023691239 ], [ -91.679669765846995, 14.664118149732815 ], [ -91.673856166828614, 14.662412828289405 ], [ -91.666001349582586, 14.661999417139384 ], [ -91.656622077147119, 14.670681056685396 ], [ -91.653702358876728, 14.677347317324802 ], [ -91.651583625383978, 14.678845933193259 ], [ -91.648276332586647, 14.680292874016914 ], [ -91.642462735366905, 14.678639228517568 ], [ -91.636287401142624, 14.675228582932732 ], [ -91.633548550025523, 14.675228582932732 ], [ -91.630008715030158, 14.676468818181377 ], [ -91.622489793669047, 14.68447866505835 ], [ -91.61752885627169, 14.691351630373447 ], [ -91.616469489075655, 14.693522039810262 ], [ -91.610759243744099, 14.702100328367464 ], [ -91.607348599058582, 14.705614324941109 ], [ -91.604635586363202, 14.706699530558865 ], [ -91.60091488331517, 14.70700958892138 ], [ -91.590476243683668, 14.704374091491104 ], [ -91.584455939090276, 14.702255357099034 ], [ -91.57897823775545, 14.700963446805588 ], [ -91.57569678427916, 14.700860094018083 ], [ -91.570890875613372, 14.702358709886539 ], [ -91.564948086285142, 14.705200913791145 ], [ -91.544510056593822, 14.718585110114702 ], [ -91.538360561690524, 14.720445461189058 ], [ -91.526268276559676, 14.719463609258128 ], [ -91.510506965224238, 14.712952379148987 ], [ -91.540582647970837, 14.687114163387889 ], [ -91.563242763942412, 14.6623094755019 ], [ -91.565904099794352, 14.658330390035474 ], [ -91.568978847695632, 14.652232571076297 ], [ -91.569650642163367, 14.649390367171691 ], [ -91.570219082044957, 14.638176581184268 ], [ -91.569418098166693, 14.625412502485005 ], [ -91.568875494908127, 14.615593980477797 ], [ -91.608356289411233, 14.537149156308487 ], [ -91.608795538982918, 14.530896307718422 ], [ -91.608666347773692, 14.527640693563114 ], [ -91.608278775045392, 14.524746811915804 ], [ -91.616236945078924, 14.466145738235241 ], [ -91.61541012187962, 14.460151272063513 ], [ -91.613911506011164, 14.454931952247762 ], [ -91.611921962828319, 14.449919338007021 ], [ -91.599287076237545, 14.428008530868965 ], [ -91.598692797034914, 14.420567124772958 ], [ -91.603266160804651, 14.355506496927262 ], [ -91.602594367236236, 14.342225654290473 ], [ -91.603085292752041, 14.335714423282013 ], [ -91.603937954373066, 14.331115221090556 ], [ -91.615306769991435, 14.314682115287383 ], [ -91.627760790328182, 14.277785142270488 ], [ -91.632359991620319, 14.248019516987085 ], [ -91.634427050068268, 14.215153307179378 ], [ -91.635589769152489, 14.208848781745871 ], [ -91.636700813191965, 14.206626695465616 ], [ -91.665226203226666, 14.165388901776396 ], [ -91.659257574577396, 14.125494697022646 ], [ -91.658500845474649, 14.117349342936476 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-SU", "NAME_1": "Suchitepéquez" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -91.551869269999941, 14.05727773600006 ], [ -91.637115037999934, 14.104437567000048 ], [ -91.658500845474649, 14.117349342936476 ], [ -91.659257574577396, 14.125494697022646 ], [ -91.665226203226666, 14.165388901776396 ], [ -91.636700813191965, 14.206626695465616 ], [ -91.635589769152489, 14.208848781745871 ], [ -91.634427050068268, 14.215153307179378 ], [ -91.632359991620319, 14.248019516987085 ], [ -91.627760790328182, 14.277785142270488 ], [ -91.615306769991435, 14.314682115287383 ], [ -91.603937954373066, 14.331115221090556 ], [ -91.603085292752041, 14.335714423282013 ], [ -91.602594367236236, 14.342225654290473 ], [ -91.603266160804651, 14.355506496927262 ], [ -91.598692797034914, 14.420567124772958 ], [ -91.599287076237545, 14.428008530868965 ], [ -91.611921962828319, 14.449919338007021 ], [ -91.613911506011164, 14.454931952247762 ], [ -91.61541012187962, 14.460151272063513 ], [ -91.616236945078924, 14.466145738235241 ], [ -91.608278775045392, 14.524746811915804 ], [ -91.608666347773692, 14.527640693563114 ], [ -91.608795538982918, 14.530896307718422 ], [ -91.608356289411233, 14.537149156308487 ], [ -91.568875494908127, 14.615593980477797 ], [ -91.569418098166693, 14.625412502485005 ], [ -91.570219082044957, 14.638176581184268 ], [ -91.569650642163367, 14.649390367171691 ], [ -91.568978847695632, 14.652232571076297 ], [ -91.565904099794352, 14.658330390035474 ], [ -91.563242763942412, 14.6623094755019 ], [ -91.540582647970837, 14.687114163387889 ], [ -91.510506965224238, 14.712952379148987 ], [ -91.469682582685039, 14.739565741265949 ], [ -91.464824998974507, 14.733777981568608 ], [ -91.4619827950699, 14.729127102533766 ], [ -91.449528774733153, 14.696932685395097 ], [ -91.448417730693677, 14.691454983160952 ], [ -91.448133510752882, 14.688044338475436 ], [ -91.452887742575228, 14.673988349482727 ], [ -91.476607224843519, 14.629856675944836 ], [ -91.461879442282395, 14.616214098102148 ], [ -91.41632666724189, 14.610116279142972 ], [ -91.402994146862397, 14.606498927983125 ], [ -91.397981534420239, 14.620193183568574 ], [ -91.397077195955831, 14.627892971183655 ], [ -91.39780066636763, 14.640502021151349 ], [ -91.397542283949235, 14.643395901000019 ], [ -91.396612107962369, 14.646238104904626 ], [ -91.395061815250529, 14.64897695602167 ], [ -91.392322964133484, 14.651664130295387 ], [ -91.387465380422952, 14.654971422193341 ], [ -91.383977219573012, 14.656831773267697 ], [ -91.377879400613836, 14.658795478028878 ], [ -91.370102097733593, 14.658072008516342 ], [ -91.355219286440899, 14.651250719145366 ], [ -91.343824633300187, 14.638176581184268 ], [ -91.342971970779786, 14.637608141302678 ], [ -91.320596075648382, 14.639520169220418 ], [ -91.309278937772717, 14.641948961075684 ], [ -91.305532396303022, 14.641328844350653 ], [ -91.302586839610967, 14.640502021151349 ], [ -91.292199876822849, 14.629546617582321 ], [ -91.263131882630262, 14.604535224121264 ], [ -91.258584357282245, 14.599264228361449 ], [ -91.256724006207889, 14.595078437320012 ], [ -91.255173712596729, 14.58691355991283 ], [ -91.254863654234214, 14.577663478686588 ], [ -91.25522538944017, 14.574614570106291 ], [ -91.257628342873716, 14.563297431331364 ], [ -91.257654182194756, 14.560300197795868 ], [ -91.257189094201294, 14.557406317947198 ], [ -91.254191860665799, 14.555390937241953 ], [ -91.251375495182913, 14.553943997317617 ], [ -91.228818731998842, 14.557096258685362 ], [ -91.201068488320061, 14.571255601364896 ], [ -91.192257656665504, 14.572392482926716 ], [ -91.18194820824317, 14.572134101407642 ], [ -91.176082933280725, 14.571048895789886 ], [ -91.166393601583422, 14.567586575160306 ], [ -91.153112758946634, 14.559473375495884 ], [ -91.11414872928043, 14.530431219725017 ], [ -91.107198248700172, 14.524281724821719 ], [ -91.100790371378537, 14.517563788238249 ], [ -91.097224697961451, 14.512964586046792 ], [ -91.095390184409439, 14.503197739983705 ], [ -91.09717302111801, 14.480718492064739 ], [ -91.09717302111801, 14.46764435500296 ], [ -91.111332363797544, 14.430437322724231 ], [ -91.139573533891451, 14.373954983435738 ], [ -91.146188116788153, 14.356901760008213 ], [ -91.149056159114423, 14.308997708377547 ], [ -91.150089687888794, 14.303364976512455 ], [ -91.151484951869008, 14.299437567889413 ], [ -91.156032478116344, 14.292926336880953 ], [ -91.164920824136686, 14.275976467140254 ], [ -91.171096158361024, 14.272049058517212 ], [ -91.287729864941298, 14.280420641499404 ], [ -91.294086066318869, 14.281970933311925 ], [ -91.289125128921569, 14.30594879799861 ], [ -91.299951342180691, 14.316387436730793 ], [ -91.31819312221478, 14.296647039928928 ], [ -91.326280484356857, 14.291892808106581 ], [ -91.336254035095635, 14.291634425688187 ], [ -91.342765266104152, 14.292616279417757 ], [ -91.346589321939632, 14.294269924017783 ], [ -91.351627773702774, 14.297215480709838 ], [ -91.355891079109995, 14.301194566176264 ], [ -91.357983975080344, 14.304346829342705 ], [ -91.358991665432995, 14.30729238513544 ], [ -91.35927588627311, 14.310186265883431 ], [ -91.358991665432995, 14.313131822575542 ], [ -91.356872931940245, 14.321451727814974 ], [ -91.357053799093535, 14.32465566692548 ], [ -91.358061490345506, 14.327859605136666 ], [ -91.362919074055981, 14.334370836145183 ], [ -91.364366013980316, 14.336902980787897 ], [ -91.365244514023061, 14.339228419855658 ], [ -91.365296189967182, 14.341967270972759 ], [ -91.364572719555326, 14.344602769302355 ], [ -91.363539190781012, 14.3469798852135 ], [ -91.356278652737615, 14.357418524845059 ], [ -91.356433682368504, 14.361242581579859 ], [ -91.358268195021139, 14.366203518077896 ], [ -91.364727749186272, 14.375970364140983 ], [ -91.369068569858598, 14.379225979195553 ], [ -91.372918464115799, 14.380724595963329 ], [ -91.381057502201941, 14.378192450421238 ], [ -91.385734218759183, 14.375763658565972 ], [ -91.414233772170803, 14.355351467296373 ], [ -91.417799444688626, 14.351837469823352 ], [ -91.419168871146496, 14.349770413174042 ], [ -91.421210090273405, 14.345016181351696 ], [ -91.423328823766212, 14.336644599268823 ], [ -91.423638882128671, 14.330443427522141 ], [ -91.423070441347761, 14.32408722614457 ], [ -91.421365119005031, 14.315353908855798 ], [ -91.419427252665571, 14.310392971458441 ], [ -91.41459550737676, 14.301504625438099 ], [ -91.413691168912294, 14.299127509526954 ], [ -91.413381109650459, 14.296543687141423 ], [ -91.415396491255024, 14.293649807292752 ], [ -91.418781298418196, 14.290807603388146 ], [ -91.425809291565542, 14.28667348919015 ], [ -91.429917569140457, 14.285743313203341 ], [ -91.432656420257558, 14.286518460458581 ], [ -91.434025844916789, 14.288688869895395 ], [ -91.43655798955956, 14.296388658409853 ], [ -91.440071987931901, 14.301039537444694 ], [ -91.447978482021313, 14.30651723877952 ], [ -91.45831376796599, 14.300264391088774 ], [ -91.45986406067783, 14.296957099190763 ], [ -91.4615952223416, 14.290084132976347 ], [ -91.462189500644911, 14.277940171901378 ], [ -91.461724412651506, 14.269878648181077 ], [ -91.45792619523769, 14.246262518700291 ], [ -91.455600756169929, 14.206006577841265 ], [ -91.456918504885095, 14.189883531299927 ], [ -91.463067999788336, 14.181925361266394 ], [ -91.468287319604087, 14.176757717394707 ], [ -91.473041551426434, 14.169212958511196 ], [ -91.481232266356017, 14.151901353564597 ], [ -91.529808111555099, 14.08218984578474 ], [ -91.531978521891233, 14.076608792561728 ], [ -91.532908697878099, 14.071957913526887 ], [ -91.529523891614303, 14.056506658755268 ], [ -91.528516202160972, 14.048290107202661 ], [ -91.551869269999941, 14.05727773600006 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-ES", "NAME_1": "Escuintla" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.627334706133965, 13.920671995960658 ], [ -90.638018794999937, 13.922358034000069 ], [ -90.707277735999924, 13.928888581000081 ], [ -90.784614825999938, 13.921538447000046 ], [ -90.79624657599993, 13.918160508000085 ], [ -90.910333200999901, 13.911135082000044 ], [ -91.043740423999907, 13.913584837000087 ], [ -91.165760870999918, 13.926703192000048 ], [ -91.316461251999897, 13.955679359000044 ], [ -91.551869269999941, 14.05727773600006 ], [ -91.528516202160972, 14.048290107202661 ], [ -91.529523891614303, 14.056506658755268 ], [ -91.532908697878099, 14.071957913526887 ], [ -91.531978521891233, 14.076608792561728 ], [ -91.529808111555099, 14.08218984578474 ], [ -91.481232266356017, 14.151901353564597 ], [ -91.473041551426434, 14.169212958511196 ], [ -91.468287319604087, 14.176757717394707 ], [ -91.463067999788336, 14.181925361266394 ], [ -91.456918504885095, 14.189883531299927 ], [ -91.455600756169929, 14.206006577841265 ], [ -91.45792619523769, 14.246262518700291 ], [ -91.461724412651506, 14.269878648181077 ], [ -91.462189500644911, 14.277940171901378 ], [ -91.4615952223416, 14.290084132976347 ], [ -91.45986406067783, 14.296957099190763 ], [ -91.45831376796599, 14.300264391088774 ], [ -91.447978482021313, 14.30651723877952 ], [ -91.440071987931901, 14.301039537444694 ], [ -91.43655798955956, 14.296388658409853 ], [ -91.434025844916789, 14.288688869895395 ], [ -91.432656420257558, 14.286518460458581 ], [ -91.429917569140457, 14.285743313203341 ], [ -91.425809291565542, 14.28667348919015 ], [ -91.418781298418196, 14.290807603388146 ], [ -91.415396491255024, 14.293649807292752 ], [ -91.413381109650459, 14.296543687141423 ], [ -91.413691168912294, 14.299127509526954 ], [ -91.41459550737676, 14.301504625438099 ], [ -91.419427252665571, 14.310392971458441 ], [ -91.421365119005031, 14.315353908855798 ], [ -91.423070441347761, 14.32408722614457 ], [ -91.423638882128671, 14.330443427522141 ], [ -91.423328823766212, 14.336644599268823 ], [ -91.421210090273405, 14.345016181351696 ], [ -91.419168871146496, 14.349770413174042 ], [ -91.417799444688626, 14.351837469823352 ], [ -91.414233772170803, 14.355351467296373 ], [ -91.385734218759183, 14.375763658565972 ], [ -91.381057502201941, 14.378192450421238 ], [ -91.372918464115799, 14.380724595963329 ], [ -91.369068569858598, 14.379225979195553 ], [ -91.364727749186272, 14.375970364140983 ], [ -91.358268195021139, 14.366203518077896 ], [ -91.356433682368504, 14.361242581579859 ], [ -91.356278652737615, 14.357418524845059 ], [ -91.363539190781012, 14.3469798852135 ], [ -91.364572719555326, 14.344602769302355 ], [ -91.365296189967182, 14.341967270972759 ], [ -91.365244514023061, 14.339228419855658 ], [ -91.364366013980316, 14.336902980787897 ], [ -91.362919074055981, 14.334370836145183 ], [ -91.358061490345506, 14.327859605136666 ], [ -91.357053799093535, 14.32465566692548 ], [ -91.356872931940245, 14.321451727814974 ], [ -91.358991665432995, 14.313131822575542 ], [ -91.35927588627311, 14.310186265883431 ], [ -91.358991665432995, 14.30729238513544 ], [ -91.357983975080344, 14.304346829342705 ], [ -91.355891079109995, 14.301194566176264 ], [ -91.351627773702774, 14.297215480709838 ], [ -91.346589321939632, 14.294269924017783 ], [ -91.342765266104152, 14.292616279417757 ], [ -91.336254035095635, 14.291634425688187 ], [ -91.326280484356857, 14.291892808106581 ], [ -91.31819312221478, 14.296647039928928 ], [ -91.299951342180691, 14.316387436730793 ], [ -91.289125128921569, 14.30594879799861 ], [ -91.294086066318869, 14.281970933311925 ], [ -91.287729864941298, 14.280420641499404 ], [ -91.171096158361024, 14.272049058517212 ], [ -91.164920824136686, 14.275976467140254 ], [ -91.156032478116344, 14.292926336880953 ], [ -91.151484951869008, 14.299437567889413 ], [ -91.150089687888794, 14.303364976512455 ], [ -91.149056159114423, 14.308997708377547 ], [ -91.146188116788153, 14.356901760008213 ], [ -91.139573533891451, 14.373954983435738 ], [ -91.111332363797544, 14.430437322724231 ], [ -91.097405565114741, 14.420412096041389 ], [ -91.094899257994371, 14.418138332917692 ], [ -91.090196703015408, 14.415916245738117 ], [ -91.085700852712137, 14.415296129013143 ], [ -91.076657477960225, 14.416226304999952 ], [ -91.072084113291169, 14.417466539349277 ], [ -91.068518438974763, 14.418810126486107 ], [ -91.055237596337975, 14.426251532582171 ], [ -91.052757127639325, 14.427233385412364 ], [ -91.049889086212318, 14.428008530868965 ], [ -91.046866014255158, 14.428421942918305 ], [ -91.042421840795271, 14.42676829741896 ], [ -91.037176682557856, 14.423564358308454 ], [ -91.027306484606584, 14.414986069751308 ], [ -91.021389532800697, 14.411058661128266 ], [ -91.015989345831599, 14.408733222060562 ], [ -91.008651293422417, 14.409353338785536 ], [ -91.004930590374443, 14.410593573134861 ], [ -91.002140062413957, 14.412298896376967 ], [ -90.997024095385655, 14.417879950499298 ], [ -90.993251716393559, 14.420877183135474 ], [ -90.990693732429804, 14.42160065444665 ], [ -90.988058234100208, 14.419843655260479 ], [ -90.985577766300878, 14.415916245738117 ], [ -90.983510707852872, 14.399741523252658 ], [ -90.983433194386407, 14.391628322688916 ], [ -90.982813076762056, 14.388321030790905 ], [ -90.981236944729176, 14.385633857416565 ], [ -90.978472256089731, 14.38284332945608 ], [ -90.971340909255559, 14.386253974141596 ], [ -90.952220629178669, 14.423822739827585 ], [ -90.946355354216223, 14.438343817713019 ], [ -90.945037604601737, 14.440927639199174 ], [ -90.938087124021536, 14.449402574069495 ], [ -90.91718400813545, 14.468729559721396 ], [ -90.890544806697449, 14.489296779722565 ], [ -90.861089239776561, 14.464492091836576 ], [ -90.853053555377244, 14.456120509753703 ], [ -90.85204586502465, 14.453691717898437 ], [ -90.851348233034514, 14.450901190837271 ], [ -90.843751797307561, 14.435191555445897 ], [ -90.83124610102675, 14.415089423438133 ], [ -90.824967414014907, 14.40806142849209 ], [ -90.82021318219256, 14.404909166225025 ], [ -90.793780687228889, 14.42697500209465 ], [ -90.787062750645418, 14.434416409089977 ], [ -90.785486620411177, 14.436431789795222 ], [ -90.780577358957942, 14.4452684598715 ], [ -90.77587480307966, 14.451159573255666 ], [ -90.773575202433619, 14.453278306748416 ], [ -90.77166317361656, 14.454621893885303 ], [ -90.763007371592892, 14.459324448864209 ], [ -90.748512133028498, 14.459324448864209 ], [ -90.742724372431837, 14.462735094449044 ], [ -90.737763435034481, 14.470176500545051 ], [ -90.731097175294394, 14.472140204406912 ], [ -90.727247281037194, 14.469453030133195 ], [ -90.725774501791818, 14.467282619797061 ], [ -90.714689907912884, 14.444028225522175 ], [ -90.650507779210614, 14.468729559721396 ], [ -90.637743699612031, 14.431522529241306 ], [ -90.623015917050907, 14.418913479273613 ], [ -90.61479936369966, 14.416226304999952 ], [ -90.601828579425387, 14.416536363362468 ], [ -90.598831345889892, 14.416122952212447 ], [ -90.596350878090561, 14.415089423438133 ], [ -90.592165087049125, 14.401808579902024 ], [ -90.585550503253103, 14.350390529899016 ], [ -90.586325649609023, 14.317265936773538 ], [ -90.583173387341958, 14.305328681273579 ], [ -90.571029426266989, 14.277888495057994 ], [ -90.564931607307813, 14.256236070338389 ], [ -90.579659389868937, 14.24238678602137 ], [ -90.585705532883992, 14.231121324089827 ], [ -90.588831956729393, 14.220320950151688 ], [ -90.588651088676784, 14.215515042385277 ], [ -90.587204148752448, 14.212414456062277 ], [ -90.584930385628752, 14.211380927287962 ], [ -90.580744594587372, 14.210089016095196 ], [ -90.567205370431509, 14.207556871452425 ], [ -90.560745816266376, 14.207143460302461 ], [ -90.554337938045364, 14.207350164978095 ], [ -90.551392382252629, 14.207866929814941 ], [ -90.535889452436265, 14.213447983937272 ], [ -90.532013718858025, 14.213758043199107 ], [ -90.527466192610689, 14.212931219999803 ], [ -90.518784553064677, 14.20879710490243 ], [ -90.51630408436597, 14.205438137060355 ], [ -90.51570980516334, 14.202544257211684 ], [ -90.528086311134359, 14.187093004238761 ], [ -90.544338548884923, 14.172210191147371 ], [ -90.550772263728959, 14.168179429736881 ], [ -90.553356086114491, 14.167094224119126 ], [ -90.571856248566974, 14.16430369705796 ], [ -90.57854834672878, 14.161254788477663 ], [ -90.578393317097891, 14.147353827317261 ], [ -90.574801805259085, 14.14079092036468 ], [ -90.572941454184729, 14.138723862815993 ], [ -90.55849789066508, 14.125598048910831 ], [ -90.55656002522494, 14.121463934712779 ], [ -90.55617245159732, 14.118208320557528 ], [ -90.557438524368365, 14.116037909322017 ], [ -90.560435757004541, 14.112058823855648 ], [ -90.564208136895957, 14.108854884745142 ], [ -90.577437302689361, 14.10131012586163 ], [ -90.582449916930102, 14.096452542151098 ], [ -90.589968838291213, 14.08239655225907 ], [ -90.592991910248429, 14.072578030251861 ], [ -90.595369025260311, 14.071131090327526 ], [ -90.598417934739871, 14.069684150403191 ], [ -90.609580043883909, 14.068030504004525 ], [ -90.620845506714772, 14.065136624155855 ], [ -90.625031297756152, 14.060847480326913 ], [ -90.627124192827239, 14.055886542030294 ], [ -90.627434252089017, 13.931708074767812 ], [ -90.627334706133965, 13.920671995960658 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-SR", "NAME_1": "Santa Rosa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.240563423844662, 13.788715510162957 ], [ -90.245553207999933, 13.79072571100005 ], [ -90.401159453999924, 13.858588018000091 ], [ -90.500208785999916, 13.894699659000082 ], [ -90.580412887999898, 13.913267343000086 ], [ -90.627334706133965, 13.920671995960658 ], [ -90.627434252089017, 13.931708074767812 ], [ -90.627124192827239, 14.055886542030294 ], [ -90.625031297756152, 14.060847480326913 ], [ -90.620845506714772, 14.065136624155855 ], [ -90.609580043883909, 14.068030504004525 ], [ -90.598417934739871, 14.069684150403191 ], [ -90.595369025260311, 14.071131090327526 ], [ -90.592991910248429, 14.072578030251861 ], [ -90.589968838291213, 14.08239655225907 ], [ -90.582449916930102, 14.096452542151098 ], [ -90.577437302689361, 14.10131012586163 ], [ -90.564208136895957, 14.108854884745142 ], [ -90.560435757004541, 14.112058823855648 ], [ -90.557438524368365, 14.116037909322017 ], [ -90.55617245159732, 14.118208320557528 ], [ -90.55656002522494, 14.121463934712779 ], [ -90.55849789066508, 14.125598048910831 ], [ -90.572941454184729, 14.138723862815993 ], [ -90.574801805259085, 14.14079092036468 ], [ -90.578393317097891, 14.147353827317261 ], [ -90.57854834672878, 14.161254788477663 ], [ -90.571856248566974, 14.16430369705796 ], [ -90.553356086114491, 14.167094224119126 ], [ -90.550772263728959, 14.168179429736881 ], [ -90.544338548884923, 14.172210191147371 ], [ -90.528086311134359, 14.187093004238761 ], [ -90.51570980516334, 14.202544257211684 ], [ -90.51630408436597, 14.205438137060355 ], [ -90.518784553064677, 14.20879710490243 ], [ -90.527466192610689, 14.212931219999803 ], [ -90.532013718858025, 14.213758043199107 ], [ -90.535889452436265, 14.213447983937272 ], [ -90.551392382252629, 14.207866929814941 ], [ -90.554337938045364, 14.207350164978095 ], [ -90.560745816266376, 14.207143460302461 ], [ -90.567205370431509, 14.207556871452425 ], [ -90.580744594587372, 14.210089016095196 ], [ -90.584930385628752, 14.211380927287962 ], [ -90.587204148752448, 14.212414456062277 ], [ -90.588651088676784, 14.215515042385277 ], [ -90.588831956729393, 14.220320950151688 ], [ -90.585705532883992, 14.231121324089827 ], [ -90.579659389868937, 14.24238678602137 ], [ -90.564931607307813, 14.256236070338389 ], [ -90.53635454042967, 14.266209621976486 ], [ -90.528628912594229, 14.271325588105412 ], [ -90.509663662148284, 14.288430488376321 ], [ -90.490336677395703, 14.297370510340784 ], [ -90.482430183306292, 14.300264391088774 ], [ -90.476564908343846, 14.301504625438099 ], [ -90.474006924380035, 14.302434801424909 ], [ -90.47217241082808, 14.303675034874971 ], [ -90.463878343111048, 14.313493556882122 ], [ -90.460777757687367, 14.316077379267597 ], [ -90.457651332942646, 14.317937730341953 ], [ -90.454964158668986, 14.318867906328819 ], [ -90.452638718701905, 14.320004787890639 ], [ -90.450571662052539, 14.321451727814974 ], [ -90.448762986922304, 14.323053697370199 ], [ -90.443827887946668, 14.328583075548465 ], [ -90.442406786443996, 14.34103709588527 ], [ -90.447755296569653, 14.387907620540261 ], [ -90.429384325326339, 14.433486233103167 ], [ -90.388275722846288, 14.496531480243618 ], [ -90.371300014683925, 14.50407623912713 ], [ -90.367217577329313, 14.50448965117647 ], [ -90.359646980024081, 14.502474270471168 ], [ -90.356985643272822, 14.499787096197508 ], [ -90.355073615355025, 14.496789863561332 ], [ -90.353549161064905, 14.484749254374549 ], [ -90.352670661022159, 14.482165431989074 ], [ -90.351533780359659, 14.479995022552259 ], [ -90.34980261869589, 14.478134670578584 ], [ -90.345306770191257, 14.479271552140403 ], [ -90.338743863238676, 14.483198960763389 ], [ -90.319701096628307, 14.500097154560024 ], [ -90.31414588092764, 14.505936591100806 ], [ -90.305955165998114, 14.508830470949476 ], [ -90.297144335242876, 14.508830470949476 ], [ -90.285207078843598, 14.514308173183622 ], [ -90.27270138166341, 14.50138906485347 ], [ -90.270686000958165, 14.498701891479072 ], [ -90.266810269178563, 14.495911363518587 ], [ -90.264639858842372, 14.494774481956767 ], [ -90.25076473700301, 14.496531480243618 ], [ -90.237948980560986, 14.498908596154763 ], [ -90.12800737214252, 14.519062405005968 ], [ -90.122891405114217, 14.495497952368567 ], [ -90.113977219772835, 14.481752020839053 ], [ -90.078294643582922, 14.453123277117527 ], [ -90.051887987040971, 14.433486233103167 ], [ -90.069948899921769, 14.378450832839633 ], [ -90.083953212970357, 14.376900540127792 ], [ -90.080930141912518, 14.357935288782528 ], [ -90.082015346630897, 14.354834703358847 ], [ -90.084263272232192, 14.353852851427916 ], [ -90.089301723995334, 14.355558172871383 ], [ -90.094107631761801, 14.357883612838464 ], [ -90.105166389017597, 14.358452052720054 ], [ -90.139970466064142, 14.351785793879287 ], [ -90.142166713922677, 14.350132148379942 ], [ -90.155473395880506, 14.338918362392519 ], [ -90.191052619282914, 14.252928779339697 ], [ -90.176634895084305, 14.24274852122727 ], [ -90.130255296844439, 14.229984443427327 ], [ -90.124519213091219, 14.22771068030363 ], [ -90.120643480412298, 14.224713446768135 ], [ -90.113770515097201, 14.217840481453038 ], [ -90.082712978621032, 14.192932440779487 ], [ -90.058295865261982, 14.169729723348041 ], [ -90.053464118174475, 14.159756170810624 ], [ -90.05493689741985, 14.137845364571888 ], [ -90.05033769432913, 14.098157864493828 ], [ -90.050466884638979, 14.095108954114949 ], [ -90.051526251835014, 14.089269517574166 ], [ -90.054394294161341, 14.080742905860404 ], [ -90.059665289921156, 14.069580796716366 ], [ -90.077054410132916, 14.045447903298111 ], [ -90.082738817042753, 14.039350084338935 ], [ -90.085064257009833, 14.038471585195509 ], [ -90.098525966799912, 14.035991116496803 ], [ -90.110023972728129, 14.032787177386297 ], [ -90.115682543014941, 14.029531562331726 ], [ -90.119170702066242, 14.026999416789636 ], [ -90.125449388178708, 14.015837306746278 ], [ -90.141055670782578, 13.987311916711576 ], [ -90.15668779180811, 13.976769924292569 ], [ -90.159943406862737, 13.976201484410979 ], [ -90.164129197904117, 13.975943101093208 ], [ -90.174102748642895, 13.979818833772129 ], [ -90.213402675992711, 13.989068914998427 ], [ -90.218518643020957, 13.991032619759608 ], [ -90.237871467094521, 14.006897283882552 ], [ -90.265957607557539, 14.022710272960694 ], [ -90.284121874125162, 14.017749335563394 ], [ -90.29024553060674, 14.013253486159442 ], [ -90.291692471430395, 14.009739487787101 ], [ -90.292855191413935, 14.004003404033881 ], [ -90.292648484939605, 13.998784085117393 ], [ -90.29200252979291, 13.995166733957603 ], [ -90.28854020916333, 13.987932034335927 ], [ -90.285258754787662, 13.98390127202606 ], [ -90.280246141446241, 13.978785304997814 ], [ -90.278644171891017, 13.974702866743883 ], [ -90.271409471369964, 13.933413398009918 ], [ -90.27022091296476, 13.931036282098717 ], [ -90.268567268364734, 13.929227606968482 ], [ -90.266500209916728, 13.927780667044146 ], [ -90.261461758153587, 13.925455227077066 ], [ -90.258516202360852, 13.92070099525472 ], [ -90.255131395197736, 13.912691148377803 ], [ -90.245442064399754, 13.877757880122033 ], [ -90.232548793591945, 13.855020249784673 ], [ -90.230817633726815, 13.849955960499187 ], [ -90.23012000173668, 13.84515005093408 ], [ -90.2305075753643, 13.82721832926245 ], [ -90.236992967051776, 13.802310289488275 ], [ -90.240563423844662, 13.788715510162957 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-CM", "NAME_1": "Chimaltenango" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.765229457873147, 14.777909654207178 ], [ -90.780861578898737, 14.750262763315845 ], [ -90.783781298068448, 14.737705390191593 ], [ -90.778226080569141, 14.708818264051615 ], [ -90.77491878867113, 14.699309801306242 ], [ -90.771818203247449, 14.681533108366239 ], [ -90.771559820829054, 14.675435289407062 ], [ -90.77186988009089, 14.67093943910379 ], [ -90.77473792241716, 14.666030178549875 ], [ -90.780784063633632, 14.658692125241373 ], [ -90.794090745591404, 14.630683499144141 ], [ -90.819308844627471, 14.612906806204137 ], [ -90.864396531674572, 14.56422760731823 ], [ -90.886074794815897, 14.523713284040809 ], [ -90.891474981784938, 14.496221421881103 ], [ -90.890854865059964, 14.490433661284442 ], [ -90.890544806697449, 14.489296779722565 ], [ -90.91718400813545, 14.468729559721396 ], [ -90.938087124021536, 14.449402574069495 ], [ -90.945037604601737, 14.440927639199174 ], [ -90.946355354216223, 14.438343817713019 ], [ -90.952220629178669, 14.423822739827585 ], [ -90.971340909255559, 14.386253974141596 ], [ -90.978472256089731, 14.38284332945608 ], [ -90.981236944729176, 14.385633857416565 ], [ -90.982813076762056, 14.388321030790905 ], [ -90.983433194386407, 14.391628322688916 ], [ -90.983510707852872, 14.399741523252658 ], [ -90.985577766300878, 14.415916245738117 ], [ -90.988058234100208, 14.419843655260479 ], [ -90.990693732429804, 14.42160065444665 ], [ -90.993251716393559, 14.420877183135474 ], [ -90.997024095385655, 14.417879950499298 ], [ -91.002140062413957, 14.412298896376967 ], [ -91.004930590374443, 14.410593573134861 ], [ -91.008651293422417, 14.409353338785536 ], [ -91.015989345831599, 14.408733222060562 ], [ -91.021389532800697, 14.411058661128266 ], [ -91.027306484606584, 14.414986069751308 ], [ -91.037176682557856, 14.423564358308454 ], [ -91.042421840795271, 14.42676829741896 ], [ -91.046866014255158, 14.428421942918305 ], [ -91.049889086212318, 14.428008530868965 ], [ -91.052757127639325, 14.427233385412364 ], [ -91.055237596337975, 14.426251532582171 ], [ -91.068518438974763, 14.418810126486107 ], [ -91.072084113291169, 14.417466539349277 ], [ -91.076657477960225, 14.416226304999952 ], [ -91.085700852712137, 14.415296129013143 ], [ -91.090196703015408, 14.415916245738117 ], [ -91.094899257994371, 14.418138332917692 ], [ -91.097405565114741, 14.420412096041389 ], [ -91.111332363797544, 14.430437322724231 ], [ -91.09717302111801, 14.46764435500296 ], [ -91.09717302111801, 14.480718492064739 ], [ -91.095390184409439, 14.503197739983705 ], [ -91.097224697961451, 14.512964586046792 ], [ -91.100790371378537, 14.517563788238249 ], [ -91.107198248700172, 14.524281724821719 ], [ -91.11414872928043, 14.530431219725017 ], [ -91.105802984719958, 14.610116279142972 ], [ -91.105725471253493, 14.632440497430991 ], [ -91.102728237717997, 14.641638901813849 ], [ -91.09466671399764, 14.652645982226261 ], [ -91.074099493996414, 14.700446681968799 ], [ -91.07616655064578, 14.721892402012713 ], [ -91.07539140518918, 14.725406399485735 ], [ -91.068828498236599, 14.744836737925084 ], [ -91.084951544777937, 14.819819241464813 ], [ -91.087432014375963, 14.82627879473057 ], [ -91.060766975415561, 14.838939521541647 ], [ -91.05345475873014, 14.844933986813999 ], [ -91.030897997344709, 14.906583970873555 ], [ -91.024593471911203, 14.916557522511653 ], [ -91.022578091205901, 14.918262843955063 ], [ -91.020717740131602, 14.919554755147828 ], [ -91.010950894068515, 14.92420563418267 ], [ -90.99387183311859, 14.928649806743181 ], [ -90.977154507374621, 14.938623359280598 ], [ -90.95896440328454, 14.935264391438523 ], [ -90.893955451382965, 14.936814683251043 ], [ -90.882199063036296, 14.939295151949693 ], [ -90.868375617140998, 14.941568915073333 ], [ -90.852898525746355, 14.941878974335168 ], [ -90.805123664425537, 14.92823639649248 ], [ -90.753602260735704, 14.92823639649248 ], [ -90.736704067838446, 14.92596263336884 ], [ -90.707274340238598, 14.916195787305753 ], [ -90.671385056675035, 14.908909409941316 ], [ -90.657613287623121, 14.903948473443279 ], [ -90.660248785952717, 14.888497219571036 ], [ -90.660791389211226, 14.886016750872329 ], [ -90.661850756407262, 14.883071194180275 ], [ -90.663090989857267, 14.880745754213194 ], [ -90.664977180252663, 14.878006903995413 ], [ -90.668491176826308, 14.875009670459917 ], [ -90.672987027129579, 14.871909085036236 ], [ -90.684045782586793, 14.86829173387639 ], [ -90.688877529674244, 14.865501206815225 ], [ -90.704096238650493, 14.853925686521222 ], [ -90.709005500103729, 14.851961981760041 ], [ -90.712984584670835, 14.851548569710701 ], [ -90.715490891791205, 14.852582099384392 ], [ -90.718410610960916, 14.852788804959346 ], [ -90.721046109290512, 14.852375392910062 ], [ -90.723423225201657, 14.851290188191626 ], [ -90.727609016243093, 14.84844798428702 ], [ -90.731820644806874, 14.844882309970615 ], [ -90.737634243825255, 14.835115464806847 ], [ -90.746910162573954, 14.805143133948434 ], [ -90.765229457873147, 14.777909654207178 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-SA", "NAME_1": "Sacatepéquez" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.890544806697449, 14.489296779722565 ], [ -90.890854865059964, 14.490433661284442 ], [ -90.891474981784938, 14.496221421881103 ], [ -90.886074794815897, 14.523713284040809 ], [ -90.864396531674572, 14.56422760731823 ], [ -90.819308844627471, 14.612906806204137 ], [ -90.794090745591404, 14.630683499144141 ], [ -90.780784063633632, 14.658692125241373 ], [ -90.77473792241716, 14.666030178549875 ], [ -90.77186988009089, 14.67093943910379 ], [ -90.771559820829054, 14.675435289407062 ], [ -90.771818203247449, 14.681533108366239 ], [ -90.77491878867113, 14.699309801306242 ], [ -90.778226080569141, 14.708818264051615 ], [ -90.783781298068448, 14.737705390191593 ], [ -90.780861578898737, 14.750262763315845 ], [ -90.765229457873147, 14.777909654207178 ], [ -90.741949226075917, 14.757394111049393 ], [ -90.728797573749034, 14.749849351266505 ], [ -90.719263271682621, 14.747782293717876 ], [ -90.709780647358969, 14.74747223625468 ], [ -90.697585007641976, 14.749487616060605 ], [ -90.694510260640016, 14.749435940116541 ], [ -90.691590542369624, 14.74881582339151 ], [ -90.681513637944022, 14.739514065321828 ], [ -90.651334602409975, 14.702048652423343 ], [ -90.642497932333697, 14.673419907802497 ], [ -90.629113736010083, 14.658485418767043 ], [ -90.619476081156222, 14.647581692041456 ], [ -90.618158332441055, 14.645307928917759 ], [ -90.617589890760826, 14.637814845978369 ], [ -90.623015917050907, 14.619573065944223 ], [ -90.621052212289726, 14.607894191963396 ], [ -90.629423794372599, 14.598747463524603 ], [ -90.63464311418835, 14.58655182470693 ], [ -90.641877813810027, 14.506246650362584 ], [ -90.650507779210614, 14.468729559721396 ], [ -90.714689907912884, 14.444028225522175 ], [ -90.725774501791818, 14.467282619797061 ], [ -90.727247281037194, 14.469453030133195 ], [ -90.731097175294394, 14.472140204406912 ], [ -90.737763435034481, 14.470176500545051 ], [ -90.742724372431837, 14.462735094449044 ], [ -90.748512133028498, 14.459324448864209 ], [ -90.763007371592892, 14.459324448864209 ], [ -90.77166317361656, 14.454621893885303 ], [ -90.773575202433619, 14.453278306748416 ], [ -90.77587480307966, 14.451159573255666 ], [ -90.780577358957942, 14.4452684598715 ], [ -90.785486620411177, 14.436431789795222 ], [ -90.787062750645418, 14.434416409089977 ], [ -90.793780687228889, 14.42697500209465 ], [ -90.82021318219256, 14.404909166225025 ], [ -90.824967414014907, 14.40806142849209 ], [ -90.83124610102675, 14.415089423438133 ], [ -90.843751797307561, 14.435191555445897 ], [ -90.851348233034514, 14.450901190837271 ], [ -90.85204586502465, 14.453691717898437 ], [ -90.853053555377244, 14.456120509753703 ], [ -90.861089239776561, 14.464492091836576 ], [ -90.890544806697449, 14.489296779722565 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-GU", "NAME_1": "Guatemala" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.709780647358969, 14.74747223625468 ], [ -90.719263271682621, 14.747782293717876 ], [ -90.728797573749034, 14.749849351266505 ], [ -90.741949226075917, 14.757394111049393 ], [ -90.765229457873147, 14.777909654207178 ], [ -90.746910162573954, 14.805143133948434 ], [ -90.737634243825255, 14.835115464806847 ], [ -90.731820644806874, 14.844882309970615 ], [ -90.727609016243093, 14.84844798428702 ], [ -90.723423225201657, 14.851290188191626 ], [ -90.721046109290512, 14.852375392910062 ], [ -90.718410610960916, 14.852788804959346 ], [ -90.715490891791205, 14.852582099384392 ], [ -90.712984584670835, 14.851548569710701 ], [ -90.709005500103729, 14.851961981760041 ], [ -90.704096238650493, 14.853925686521222 ], [ -90.688877529674244, 14.865501206815225 ], [ -90.684045782586793, 14.86829173387639 ], [ -90.672987027129579, 14.871909085036236 ], [ -90.668491176826308, 14.875009670459917 ], [ -90.664977180252663, 14.878006903995413 ], [ -90.663090989857267, 14.880745754213194 ], [ -90.661850756407262, 14.883071194180275 ], [ -90.660791389211226, 14.886016750872329 ], [ -90.660248785952717, 14.888497219571036 ], [ -90.657613287623121, 14.903948473443279 ], [ -90.621982388276592, 14.891339423475586 ], [ -90.607099576084579, 14.894078273693367 ], [ -90.599425625092522, 14.885810045297319 ], [ -90.59415462933265, 14.883536282173679 ], [ -90.589917162347149, 14.884828193366388 ], [ -90.585395473622214, 14.887256985221654 ], [ -90.579194301875532, 14.887256985221654 ], [ -90.563975592899283, 14.884931545254574 ], [ -90.538835008229, 14.889995836338755 ], [ -90.513384366095579, 14.898780829571592 ], [ -90.497235480233201, 14.907772529278816 ], [ -90.489794074137194, 14.907772529278816 ], [ -90.484988166370783, 14.898574123996639 ], [ -90.477495083431336, 14.894233303324256 ], [ -90.467805751734033, 14.893148097706501 ], [ -90.456281908283415, 14.894078273693367 ], [ -90.443052740691428, 14.897488919278203 ], [ -90.4390219801802, 14.902449855776183 ], [ -90.436619024948016, 14.90818594042878 ], [ -90.428350795652705, 14.913973700126121 ], [ -90.41207272037974, 14.917022610505057 ], [ -90.404295416600178, 14.910769761914992 ], [ -90.399928758405451, 14.899039211090724 ], [ -90.41225358843235, 14.877645168789513 ], [ -90.4147598946534, 14.875061347303301 ], [ -90.417602097658687, 14.870875556261922 ], [ -90.417602097658687, 14.86694814673956 ], [ -90.416594408205356, 14.861418769460613 ], [ -90.4151216298593, 14.858163154406043 ], [ -90.413338793150785, 14.855941067226468 ], [ -90.411452602755389, 14.854390774514627 ], [ -90.409333869262639, 14.853098863321861 ], [ -90.406750047776484, 14.852117011390931 ], [ -90.400574713552146, 14.851238512247505 ], [ -90.39429602743968, 14.851858628972536 ], [ -90.380240038446971, 14.855682684808016 ], [ -90.357399055322105, 14.857336331206682 ], [ -90.350138516379388, 14.854855862508032 ], [ -90.348588222768228, 14.852685452171841 ], [ -90.344014858998548, 14.843590400576488 ], [ -90.33494564492554, 14.818475654327983 ], [ -90.331147426612404, 14.794084376692638 ], [ -90.332594367436116, 14.785919501084095 ], [ -90.333860440207104, 14.784214178741365 ], [ -90.335281541709776, 14.782818914761094 ], [ -90.339363979963707, 14.777444566213717 ], [ -90.343394742273517, 14.770416572167051 ], [ -90.344634975723523, 14.765765693132209 ], [ -90.344273241416943, 14.761528225247389 ], [ -90.343317227008413, 14.759202786179628 ], [ -90.338847216026181, 14.750986232828382 ], [ -90.317866583975672, 14.729282131265336 ], [ -90.308487312439524, 14.72225413721867 ], [ -90.250247972166164, 14.701686917217444 ], [ -90.236708747110981, 14.695072333421422 ], [ -90.230662604995189, 14.690111396024065 ], [ -90.219733038948561, 14.677760728474823 ], [ -90.209087693742049, 14.674298406945923 ], [ -90.218182746236721, 14.651974189557166 ], [ -90.222833625271562, 14.644842840924355 ], [ -90.224771490711703, 14.643292548212514 ], [ -90.233298103324785, 14.637969876508578 ], [ -90.265802577926593, 14.611511542223866 ], [ -90.271616176944974, 14.587792059955575 ], [ -90.272081264938436, 14.572082424564201 ], [ -90.27466508732391, 14.563917548056395 ], [ -90.277093879179176, 14.559370021809059 ], [ -90.281021287802162, 14.556321113228762 ], [ -90.282726610144948, 14.550171617426201 ], [ -90.283579270866653, 14.545210680028845 ], [ -90.285207078843598, 14.514308173183622 ], [ -90.297144335242876, 14.508830470949476 ], [ -90.305955165998114, 14.508830470949476 ], [ -90.31414588092764, 14.505936591100806 ], [ -90.319701096628307, 14.500097154560024 ], [ -90.338743863238676, 14.483198960763389 ], [ -90.345306770191257, 14.479271552140403 ], [ -90.34980261869589, 14.478134670578584 ], [ -90.351533780359659, 14.479995022552259 ], [ -90.352670661022159, 14.482165431989074 ], [ -90.353549161064905, 14.484749254374549 ], [ -90.355073615355025, 14.496789863561332 ], [ -90.356985643272822, 14.499787096197508 ], [ -90.359646980024081, 14.502474270471168 ], [ -90.367217577329313, 14.50448965117647 ], [ -90.371300014683925, 14.50407623912713 ], [ -90.388275722846288, 14.496531480243618 ], [ -90.429384325326339, 14.433486233103167 ], [ -90.447755296569653, 14.387907620540261 ], [ -90.442406786443996, 14.34103709588527 ], [ -90.443827887946668, 14.328583075548465 ], [ -90.448762986922304, 14.323053697370199 ], [ -90.450571662052539, 14.321451727814974 ], [ -90.452638718701905, 14.320004787890639 ], [ -90.454964158668986, 14.318867906328819 ], [ -90.457651332942646, 14.317937730341953 ], [ -90.460777757687367, 14.316077379267597 ], [ -90.463878343111048, 14.313493556882122 ], [ -90.47217241082808, 14.303675034874971 ], [ -90.474006924380035, 14.302434801424909 ], [ -90.476564908343846, 14.301504625438099 ], [ -90.482430183306292, 14.300264391088774 ], [ -90.490336677395703, 14.297370510340784 ], [ -90.509663662148284, 14.288430488376321 ], [ -90.528628912594229, 14.271325588105412 ], [ -90.53635454042967, 14.266209621976486 ], [ -90.564931607307813, 14.256236070338389 ], [ -90.571029426266989, 14.277888495057994 ], [ -90.583173387341958, 14.305328681273579 ], [ -90.586325649609023, 14.317265936773538 ], [ -90.585550503253103, 14.350390529899016 ], [ -90.592165087049125, 14.401808579902024 ], [ -90.596350878090561, 14.415089423438133 ], [ -90.598831345889892, 14.416122952212447 ], [ -90.601828579425387, 14.416536363362468 ], [ -90.61479936369966, 14.416226304999952 ], [ -90.623015917050907, 14.418913479273613 ], [ -90.637743699612031, 14.431522529241306 ], [ -90.650507779210614, 14.468729559721396 ], [ -90.641877813810027, 14.506246650362584 ], [ -90.63464311418835, 14.58655182470693 ], [ -90.629423794372599, 14.598747463524603 ], [ -90.621052212289726, 14.607894191963396 ], [ -90.623015917050907, 14.619573065944223 ], [ -90.617589890760826, 14.637814845978369 ], [ -90.618158332441055, 14.645307928917759 ], [ -90.619476081156222, 14.647581692041456 ], [ -90.629113736010083, 14.658485418767043 ], [ -90.642497932333697, 14.673419907802497 ], [ -90.651334602409975, 14.702048652423343 ], [ -90.681513637944022, 14.739514065321828 ], [ -90.691590542369624, 14.74881582339151 ], [ -90.694510260640016, 14.749435940116541 ], [ -90.697585007641976, 14.749487616060605 ], [ -90.709780647358969, 14.74747223625468 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-JA", "NAME_1": "Jalapa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.285207078843598, 14.514308173183622 ], [ -90.283579270866653, 14.545210680028845 ], [ -90.282726610144948, 14.550171617426201 ], [ -90.281021287802162, 14.556321113228762 ], [ -90.277093879179176, 14.559370021809059 ], [ -90.27466508732391, 14.563917548056395 ], [ -90.272081264938436, 14.572082424564201 ], [ -90.271616176944974, 14.587792059955575 ], [ -90.265802577926593, 14.611511542223866 ], [ -90.233298103324785, 14.637969876508578 ], [ -90.224771490711703, 14.643292548212514 ], [ -90.222833625271562, 14.644842840924355 ], [ -90.218182746236721, 14.651974189557166 ], [ -90.209087693742049, 14.674298406945923 ], [ -90.207304857033535, 14.674970201413657 ], [ -90.200251023665771, 14.677915758105712 ], [ -90.184231329911938, 14.686855780070175 ], [ -90.180355598132337, 14.697552802120128 ], [ -90.179296230936302, 14.704064032229269 ], [ -90.177513394227731, 14.706957912977259 ], [ -90.173534308761305, 14.709438380776646 ], [ -90.147179328163475, 14.719256904582494 ], [ -90.11351213267875, 14.730263984095586 ], [ -90.098370938068342, 14.728455308065975 ], [ -90.086123623306548, 14.722615872424569 ], [ -90.078139614851352, 14.720083725983159 ], [ -90.073462897394791, 14.722357489106798 ], [ -90.069716355925095, 14.72628489772984 ], [ -90.038555466661421, 14.782612210085404 ], [ -90.015430263595761, 14.789330145769611 ], [ -89.981763068111093, 14.793154202504411 ], [ -89.951584031677726, 14.80395457644255 ], [ -89.922412685596953, 14.819302475728648 ], [ -89.887505255762903, 14.861883857454018 ], [ -89.87396603070772, 14.873769436110592 ], [ -89.868333299741948, 14.875939846446727 ], [ -89.862519700723567, 14.877128403952668 ], [ -89.849626430815135, 14.877645168789513 ], [ -89.833994309789546, 14.876508287227637 ], [ -89.841719936725667, 14.859816799006069 ], [ -89.838851895298717, 14.856199448745542 ], [ -89.83290910507111, 14.84596751648769 ], [ -89.823633186322468, 14.833203436889107 ], [ -89.8076910060351, 14.803592841236593 ], [ -89.799448615161452, 14.79217235057348 ], [ -89.793660854564791, 14.785712795509085 ], [ -89.790431077931885, 14.785299384359064 ], [ -89.763636847762314, 14.785299384359064 ], [ -89.747720506795929, 14.782922268447919 ], [ -89.73635169117756, 14.779873358968302 ], [ -89.6889644025851, 14.782250474879504 ], [ -89.676045295154211, 14.778633123719658 ], [ -89.67082597533846, 14.77057160089862 ], [ -89.66700191860366, 14.759874578848724 ], [ -89.664986537898415, 14.748350735398105 ], [ -89.665089890685863, 14.745146796287599 ], [ -89.667182786656269, 14.733054511156752 ], [ -89.668035448277294, 14.730212307252145 ], [ -89.668629726580605, 14.72726675145941 ], [ -89.66893978584244, 14.721323961231803 ], [ -89.6677770658589, 14.715742906210153 ], [ -89.664133877176653, 14.707423000970721 ], [ -89.660232306975388, 14.695692450146453 ], [ -89.696044074374527, 14.598954169099613 ], [ -89.699609747791612, 14.577611802742467 ], [ -89.696173264684376, 14.577146714749063 ], [ -89.685502081955519, 14.577611802742467 ], [ -89.677853970284502, 14.555235906711687 ], [ -89.677698940653556, 14.545417384704535 ], [ -89.678396572643692, 14.542213447392669 ], [ -89.699971482997512, 14.52986277894405 ], [ -89.762344936569548, 14.500458888866604 ], [ -89.764360318174113, 14.50138906485347 ], [ -89.775393236108926, 14.509863999723791 ], [ -89.782059495849012, 14.516426907575692 ], [ -89.785289273381238, 14.520302639355293 ], [ -89.789087490795055, 14.523403224778974 ], [ -89.796244676050947, 14.52469513597174 ], [ -89.815726691333737, 14.519475816155989 ], [ -89.83213395871519, 14.508727118161971 ], [ -89.851280077213801, 14.496428127456113 ], [ -89.87164059074064, 14.482940579244314 ], [ -89.880012172823513, 14.47089997005753 ], [ -89.885257331060984, 14.436483465739343 ], [ -89.929828254170559, 14.470589910795752 ], [ -89.932877162750856, 14.471933498831902 ], [ -89.9356160138679, 14.472863673919392 ], [ -89.938561570560012, 14.473483792443062 ], [ -89.942592332869822, 14.473793849906258 ], [ -89.947088182273774, 14.473483792443062 ], [ -89.953986986010591, 14.472140204406912 ], [ -89.957785204323727, 14.470796617270082 ], [ -89.960653245750677, 14.469298001401626 ], [ -89.964761522426329, 14.464905503885859 ], [ -89.988558519060405, 14.434313056302472 ], [ -90.051887987040971, 14.433486233103167 ], [ -90.078294643582922, 14.453123277117527 ], [ -90.113977219772835, 14.481752020839053 ], [ -90.122891405114217, 14.495497952368567 ], [ -90.12800737214252, 14.519062405005968 ], [ -90.237948980560986, 14.498908596154763 ], [ -90.25076473700301, 14.496531480243618 ], [ -90.264639858842372, 14.494774481956767 ], [ -90.266810269178563, 14.495911363518587 ], [ -90.270686000958165, 14.498701891479072 ], [ -90.27270138166341, 14.50138906485347 ], [ -90.285207078843598, 14.514308173183622 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-PR", "NAME_1": "El Progreso" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.400574713552146, 14.851238512247505 ], [ -90.406750047776484, 14.852117011390931 ], [ -90.409333869262639, 14.853098863321861 ], [ -90.411452602755389, 14.854390774514627 ], [ -90.413338793150785, 14.855941067226468 ], [ -90.4151216298593, 14.858163154406043 ], [ -90.416594408205356, 14.861418769460613 ], [ -90.417602097658687, 14.86694814673956 ], [ -90.417602097658687, 14.870875556261922 ], [ -90.4147598946534, 14.875061347303301 ], [ -90.41225358843235, 14.877645168789513 ], [ -90.399928758405451, 14.899039211090724 ], [ -90.387371385281199, 14.887256985221654 ], [ -90.354298468999104, 14.881520901468434 ], [ -90.303397182933622, 14.889582424289415 ], [ -90.298436244636946, 14.905653794886689 ], [ -90.282571581413322, 14.954488023403542 ], [ -90.123873257045148, 15.061251532032543 ], [ -90.038452114773236, 15.116752021188802 ], [ -89.999953173100437, 15.142073473012374 ], [ -89.97300391329992, 15.156542874054367 ], [ -89.923833787998888, 15.151065171820221 ], [ -89.907193976620704, 15.152408758957051 ], [ -89.877996792118267, 15.159850165053058 ], [ -89.841048143157252, 15.108483791893491 ], [ -89.796554735312782, 15.043268134416849 ], [ -89.795572883381851, 15.029832262149171 ], [ -89.843942023005923, 15.02885040931892 ], [ -89.848696254828269, 15.02823029169457 ], [ -89.852727017138136, 15.026679998982729 ], [ -89.85179684115127, 15.022752590359744 ], [ -89.849083827556569, 15.017998359436717 ], [ -89.805107185448207, 14.959242255225888 ], [ -89.797123176093692, 14.948235174813476 ], [ -89.784927538175339, 14.941982327122673 ], [ -89.772111782632635, 14.940225327936503 ], [ -89.767047492447773, 14.937228095300327 ], [ -89.764567022849803, 14.934024156189821 ], [ -89.766685757241873, 14.914283759387956 ], [ -89.768675300424775, 14.90952952756561 ], [ -89.772680223413545, 14.907875881166945 ], [ -89.777563646445117, 14.90704905796764 ], [ -89.799009365589711, 14.906428941242609 ], [ -89.811592577135684, 14.901054591795969 ], [ -89.833994309789546, 14.876508287227637 ], [ -89.849626430815135, 14.877645168789513 ], [ -89.862519700723567, 14.877128403952668 ], [ -89.868333299741948, 14.875939846446727 ], [ -89.87396603070772, 14.873769436110592 ], [ -89.887505255762903, 14.861883857454018 ], [ -89.922412685596953, 14.819302475728648 ], [ -89.951584031677726, 14.80395457644255 ], [ -89.981763068111093, 14.793154202504411 ], [ -90.015430263595761, 14.789330145769611 ], [ -90.038555466661421, 14.782612210085404 ], [ -90.069716355925095, 14.72628489772984 ], [ -90.073462897394791, 14.722357489106798 ], [ -90.078139614851352, 14.720083725983159 ], [ -90.086123623306548, 14.722615872424569 ], [ -90.098370938068342, 14.728455308065975 ], [ -90.11351213267875, 14.730263984095586 ], [ -90.147179328163475, 14.719256904582494 ], [ -90.173534308761305, 14.709438380776646 ], [ -90.177513394227731, 14.706957912977259 ], [ -90.179296230936302, 14.704064032229269 ], [ -90.180355598132337, 14.697552802120128 ], [ -90.184231329911938, 14.686855780070175 ], [ -90.200251023665771, 14.677915758105712 ], [ -90.207304857033535, 14.674970201413657 ], [ -90.209087693742049, 14.674298406945923 ], [ -90.219733038948561, 14.677760728474823 ], [ -90.230662604995189, 14.690111396024065 ], [ -90.236708747110981, 14.695072333421422 ], [ -90.250247972166164, 14.701686917217444 ], [ -90.308487312439524, 14.72225413721867 ], [ -90.317866583975672, 14.729282131265336 ], [ -90.338847216026181, 14.750986232828382 ], [ -90.343317227008413, 14.759202786179628 ], [ -90.344273241416943, 14.761528225247389 ], [ -90.344634975723523, 14.765765693132209 ], [ -90.343394742273517, 14.770416572167051 ], [ -90.339363979963707, 14.777444566213717 ], [ -90.335281541709776, 14.782818914761094 ], [ -90.333860440207104, 14.784214178741365 ], [ -90.332594367436116, 14.785919501084095 ], [ -90.331147426612404, 14.794084376692638 ], [ -90.33494564492554, 14.818475654327983 ], [ -90.344014858998548, 14.843590400576488 ], [ -90.348588222768228, 14.852685452171841 ], [ -90.350138516379388, 14.854855862508032 ], [ -90.357399055322105, 14.857336331206682 ], [ -90.380240038446971, 14.855682684808016 ], [ -90.39429602743968, 14.851858628972536 ], [ -90.400574713552146, 14.851238512247505 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-SO", "NAME_1": "Sololá" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -91.087432014375963, 14.82627879473057 ], [ -91.084951544777937, 14.819819241464813 ], [ -91.068828498236599, 14.744836737925084 ], [ -91.07539140518918, 14.725406399485735 ], [ -91.07616655064578, 14.721892402012713 ], [ -91.074099493996414, 14.700446681968799 ], [ -91.09466671399764, 14.652645982226261 ], [ -91.102728237717997, 14.641638901813849 ], [ -91.105725471253493, 14.632440497430991 ], [ -91.105802984719958, 14.610116279142972 ], [ -91.11414872928043, 14.530431219725017 ], [ -91.153112758946634, 14.559473375495884 ], [ -91.166393601583422, 14.567586575160306 ], [ -91.176082933280725, 14.571048895789886 ], [ -91.18194820824317, 14.572134101407642 ], [ -91.192257656665504, 14.572392482926716 ], [ -91.201068488320061, 14.571255601364896 ], [ -91.228818731998842, 14.557096258685362 ], [ -91.251375495182913, 14.553943997317617 ], [ -91.254191860665799, 14.555390937241953 ], [ -91.257189094201294, 14.557406317947198 ], [ -91.257654182194756, 14.560300197795868 ], [ -91.257628342873716, 14.563297431331364 ], [ -91.25522538944017, 14.574614570106291 ], [ -91.254863654234214, 14.577663478686588 ], [ -91.255173712596729, 14.58691355991283 ], [ -91.256724006207889, 14.595078437320012 ], [ -91.258584357282245, 14.599264228361449 ], [ -91.263131882630262, 14.604535224121264 ], [ -91.292199876822849, 14.629546617582321 ], [ -91.302586839610967, 14.640502021151349 ], [ -91.305532396303022, 14.641328844350653 ], [ -91.309278937772717, 14.641948961075684 ], [ -91.320596075648382, 14.639520169220418 ], [ -91.342971970779786, 14.637608141302678 ], [ -91.343824633300187, 14.638176581184268 ], [ -91.355219286440899, 14.651250719145366 ], [ -91.370102097733593, 14.658072008516342 ], [ -91.377879400613836, 14.658795478028878 ], [ -91.383977219573012, 14.656831773267697 ], [ -91.387465380422952, 14.654971422193341 ], [ -91.392322964133484, 14.651664130295387 ], [ -91.395061815250529, 14.64897695602167 ], [ -91.396612107962369, 14.646238104904626 ], [ -91.397542283949235, 14.643395901000019 ], [ -91.39780066636763, 14.640502021151349 ], [ -91.397077195955831, 14.627892971183655 ], [ -91.397981534420239, 14.620193183568574 ], [ -91.402994146862397, 14.606498927983125 ], [ -91.41632666724189, 14.610116279142972 ], [ -91.461879442282395, 14.616214098102148 ], [ -91.476607224843519, 14.629856675944836 ], [ -91.452887742575228, 14.673988349482727 ], [ -91.448133510752882, 14.688044338475436 ], [ -91.448417730693677, 14.691454983160952 ], [ -91.449528774733153, 14.696932685395097 ], [ -91.4619827950699, 14.729127102533766 ], [ -91.464824998974507, 14.733777981568608 ], [ -91.469682582685039, 14.739565741265949 ], [ -91.440485399081865, 14.778478094988088 ], [ -91.428289761163512, 14.817648831128622 ], [ -91.424414029383911, 14.821059474914819 ], [ -91.37870622381314, 14.858783271131017 ], [ -91.369972907423744, 14.861677150979745 ], [ -91.358139003811971, 14.863279120534969 ], [ -91.335091315112095, 14.859868475849453 ], [ -91.325918749150958, 14.857336331206682 ], [ -91.320208502920082, 14.854855862508032 ], [ -91.313051316764813, 14.854029039308728 ], [ -91.292458259241243, 14.862607326966554 ], [ -91.27868649018933, 14.862607326966554 ], [ -91.271658495243344, 14.861367091717909 ], [ -91.255742154276959, 14.856251126488303 ], [ -91.252641567953958, 14.855837714438962 ], [ -91.246104499423097, 14.855682684808016 ], [ -91.240652634711296, 14.856716213582388 ], [ -91.229619716776483, 14.860023505480399 ], [ -91.215847947724569, 14.873252672173066 ], [ -91.202567105087837, 14.891752835524926 ], [ -91.182981737017542, 14.910666409127487 ], [ -91.170786099099189, 14.9051370300499 ], [ -91.165721808914327, 14.89180451146899 ], [ -91.156265022113075, 14.875319728822433 ], [ -91.150089687888794, 14.870875556261922 ], [ -91.147221645562468, 14.870358792324396 ], [ -91.144482795344686, 14.870255439536891 ], [ -91.14014197467236, 14.869531969125035 ], [ -91.134690110859935, 14.868136705144821 ], [ -91.123062913722492, 14.863847561315879 ], [ -91.11854122589682, 14.860540269417868 ], [ -91.116680873923201, 14.857336331206682 ], [ -91.117249314704111, 14.854855862508032 ], [ -91.11988481303365, 14.850101629786366 ], [ -91.122830369725762, 14.84596751648769 ], [ -91.131150274965194, 14.837079169568028 ], [ -91.132442186157959, 14.834908759231837 ], [ -91.133294846879664, 14.830981349709532 ], [ -91.133294846879664, 14.825607001162155 ], [ -91.13187374537705, 14.814858303168137 ], [ -91.129755011884299, 14.810207424133296 ], [ -91.127093675132983, 14.80741689707213 ], [ -91.124148119340191, 14.807106837810295 ], [ -91.121125048282352, 14.80721019149712 ], [ -91.11854122589682, 14.808140367483929 ], [ -91.11647416924751, 14.809483953721497 ], [ -91.114949714058014, 14.811344305695116 ], [ -91.1135802876002, 14.813359687299737 ], [ -91.112443406937643, 14.815633450423377 ], [ -91.108541835837059, 14.829224351422681 ], [ -91.103916796123201, 14.832014879383166 ], [ -91.087432014375963, 14.82627879473057 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-QZ", "NAME_1": "Quezaltenango" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -91.428289761163512, 14.817648831128622 ], [ -91.440485399081865, 14.778478094988088 ], [ -91.469682582685039, 14.739565741265949 ], [ -91.510506965224238, 14.712952379148987 ], [ -91.526268276559676, 14.719463609258128 ], [ -91.538360561690524, 14.720445461189058 ], [ -91.544510056593822, 14.718585110114702 ], [ -91.564948086285142, 14.705200913791145 ], [ -91.570890875613372, 14.702358709886539 ], [ -91.57569678427916, 14.700860094018083 ], [ -91.57897823775545, 14.700963446805588 ], [ -91.584455939090276, 14.702255357099034 ], [ -91.590476243683668, 14.704374091491104 ], [ -91.60091488331517, 14.70700958892138 ], [ -91.604635586363202, 14.706699530558865 ], [ -91.607348599058582, 14.705614324941109 ], [ -91.610759243744099, 14.702100328367464 ], [ -91.616469489075655, 14.693522039810262 ], [ -91.61752885627169, 14.691351630373447 ], [ -91.622489793669047, 14.68447866505835 ], [ -91.630008715030158, 14.676468818181377 ], [ -91.633548550025523, 14.675228582932732 ], [ -91.636287401142624, 14.675228582932732 ], [ -91.642462735366905, 14.678639228517568 ], [ -91.648276332586647, 14.680292874016914 ], [ -91.651583625383978, 14.678845933193259 ], [ -91.653702358876728, 14.677347317324802 ], [ -91.656622077147119, 14.670681056685396 ], [ -91.666001349582586, 14.661999417139384 ], [ -91.673856166828614, 14.662412828289405 ], [ -91.679669765846995, 14.664118149732815 ], [ -91.692097947762079, 14.66634023691239 ], [ -91.697084723581099, 14.66882070651036 ], [ -91.699746060332416, 14.671611233571582 ], [ -91.69692969395021, 14.689129544093191 ], [ -91.682615323438426, 14.722150784431165 ], [ -91.68109086824893, 14.734398098293582 ], [ -91.682227748911487, 14.736568507730453 ], [ -91.683933072153536, 14.738997301384359 ], [ -91.686620246427196, 14.739927476471848 ], [ -91.690056728635113, 14.740134182046859 ], [ -91.694320034941654, 14.739514065321828 ], [ -91.69731726757783, 14.738325506916624 ], [ -91.700056118694931, 14.736878566992232 ], [ -91.704293585680432, 14.734139715875187 ], [ -91.711709154254038, 14.727938544128506 ], [ -91.725248379309221, 14.713469143086456 ], [ -91.761034309186016, 14.696519273345757 ], [ -91.767726407347823, 14.686235663345144 ], [ -91.776408046893835, 14.658795478028878 ], [ -91.780903897197106, 14.649183660697361 ], [ -91.798835618868679, 14.623138739361309 ], [ -91.803253953906847, 14.614043686866637 ], [ -91.806716275435747, 14.604948635271285 ], [ -91.810230272009449, 14.59058258701674 ], [ -91.812555711976529, 14.5840713569076 ], [ -91.814777798256785, 14.579937241810228 ], [ -91.824596320263936, 14.56882680950963 ], [ -91.855783047049954, 14.523454902521735 ], [ -91.897460090310915, 14.514308173183622 ], [ -91.926657273914032, 14.511724350798147 ], [ -91.937948575166615, 14.513481349984318 ], [ -91.996730516000468, 14.537975979507848 ], [ -92.000942146362945, 14.539112861069668 ], [ -92.003345099796491, 14.538647773076264 ], [ -92.008538581190578, 14.536425685896688 ], [ -92.016625943332599, 14.530947984561806 ], [ -92.040474615910796, 14.599212551518008 ], [ -92.049543829983747, 14.616420802777839 ], [ -92.052153489891623, 14.617557685238978 ], [ -92.060680100706065, 14.619624741888288 ], [ -92.119797940122794, 14.625515855272511 ], [ -92.125094774304387, 14.626859443308661 ], [ -92.133698900383934, 14.630063381519847 ], [ -92.136773648285214, 14.633008938211901 ], [ -92.137962205791155, 14.635954494904013 ], [ -92.134086473112234, 14.642052313863189 ], [ -92.099669968793989, 14.680396225905099 ], [ -92.072436489952054, 14.701790269105629 ], [ -92.06075761597117, 14.707526352858906 ], [ -92.039311896826575, 14.711505439224652 ], [ -91.951487800221798, 14.736103419736992 ], [ -91.888830125809648, 14.729592190527171 ], [ -91.86074398534663, 14.728041896916011 ], [ -91.850667080021708, 14.72897207290282 ], [ -91.841933762732936, 14.732382716689017 ], [ -91.832141079147448, 14.738480536547513 ], [ -91.819221970817296, 14.761528225247389 ], [ -91.81679317896203, 14.7648355171454 ], [ -91.812245652714694, 14.7697964545427 ], [ -91.79906816286541, 14.779253241344009 ], [ -91.795347459817378, 14.782973945291303 ], [ -91.792944506383833, 14.786694648339335 ], [ -91.791885139187798, 14.789743556919575 ], [ -91.764961716909681, 14.845140693288329 ], [ -91.763308072309655, 14.847621161087716 ], [ -91.755763313426144, 14.860695299048814 ], [ -91.749148728730802, 14.898160711947298 ], [ -91.739976161870345, 14.910408026709035 ], [ -91.738322517270319, 14.919968167197169 ], [ -91.739045986782855, 14.926944485299714 ], [ -91.737728238067689, 14.931078600397086 ], [ -91.736488002819044, 14.933765773771427 ], [ -91.728529832785512, 14.938468328750332 ], [ -91.720778368327046, 14.941775621547663 ], [ -91.691607022246274, 14.96947418928238 ], [ -91.683390468895027, 14.980171210433014 ], [ -91.679669765846995, 14.990403144489505 ], [ -91.673287726947024, 15.033191229991246 ], [ -91.677370165200955, 15.0492625996892 ], [ -91.696412930012684, 15.064765530404884 ], [ -91.708376023934363, 15.092464098139601 ], [ -91.699125942708065, 15.122384752154574 ], [ -91.679850633000285, 15.149411526320876 ], [ -91.661660528910261, 15.168428452710884 ], [ -91.627011480595343, 15.195584418086412 ], [ -91.620681119438075, 15.201940619463983 ], [ -91.616107753869755, 15.220880032387583 ], [ -91.548902554109588, 15.204007677012669 ], [ -91.541357795226077, 15.198064886785062 ], [ -91.541719530431976, 15.188298040721975 ], [ -91.538412237634645, 15.178970445129949 ], [ -91.51882686956435, 15.155974433273457 ], [ -91.536319342563615, 15.15044505509519 ], [ -91.587479011047492, 15.131014715756521 ], [ -91.589701097327747, 15.129877835094021 ], [ -91.591871507663939, 15.12848257111375 ], [ -91.593886888369184, 15.120266017762503 ], [ -91.588770922240258, 15.091430569365286 ], [ -91.564147102406821, 15.000531724859172 ], [ -91.560219692884516, 14.985907294186291 ], [ -91.552726609945069, 14.976243800910652 ], [ -91.536035121723444, 14.961619371137033 ], [ -91.536293505041215, 14.949940497156206 ], [ -91.53833472416818, 14.944566147709509 ], [ -91.538412237634645, 14.938364975962884 ], [ -91.536500209716905, 14.931647040278676 ], [ -91.520609707172241, 14.913508613032036 ], [ -91.519343635300515, 14.911389879539286 ], [ -91.517819180111076, 14.9093228219906 ], [ -91.511075406005148, 14.907152410755145 ], [ -91.491645066666479, 14.9093228219906 ], [ -91.470483568361999, 14.910149644290641 ], [ -91.461879442282395, 14.890667629007851 ], [ -91.458856371224556, 14.860695299048814 ], [ -91.447978482021313, 14.850980128929791 ], [ -91.428289761163512, 14.817648831128622 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-BV", "NAME_1": "Baja Verapaz" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -90.399928758405451, 14.899039211090724 ], [ -90.404295416600178, 14.910769761914992 ], [ -90.41207272037974, 14.917022610505057 ], [ -90.428350795652705, 14.913973700126121 ], [ -90.436619024948016, 14.90818594042878 ], [ -90.4390219801802, 14.902449855776183 ], [ -90.443052740691428, 14.897488919278203 ], [ -90.456281908283415, 14.894078273693367 ], [ -90.467805751734033, 14.893148097706501 ], [ -90.477495083431336, 14.894233303324256 ], [ -90.484988166370783, 14.898574123996639 ], [ -90.489794074137194, 14.907772529278816 ], [ -90.497235480233201, 14.907772529278816 ], [ -90.513384366095579, 14.898780829571592 ], [ -90.538835008229, 14.889995836338755 ], [ -90.563975592899283, 14.884931545254574 ], [ -90.579194301875532, 14.887256985221654 ], [ -90.585395473622214, 14.887256985221654 ], [ -90.589917162347149, 14.884828193366388 ], [ -90.59415462933265, 14.883536282173679 ], [ -90.599425625092522, 14.885810045297319 ], [ -90.607099576084579, 14.894078273693367 ], [ -90.621982388276592, 14.891339423475586 ], [ -90.657613287623121, 14.903948473443279 ], [ -90.669007940763834, 14.92957998272999 ], [ -90.673477952645385, 14.939036770430619 ], [ -90.680816005953886, 14.945703030170705 ], [ -90.687404751328188, 14.949940497156206 ], [ -90.694277716643285, 14.955676580909483 ], [ -90.712157762370794, 14.973763333111322 ], [ -90.707739427332683, 14.995519111517751 ], [ -90.707274340238598, 15.000221666496714 ], [ -90.797243007858526, 15.054947008397733 ], [ -90.871915453035683, 15.148481350334009 ], [ -90.865662605344937, 15.256846829417611 ], [ -90.85739437515025, 15.252686875898576 ], [ -90.691564703947904, 15.214937242159976 ], [ -90.574362555687401, 15.20997630476262 ], [ -90.541315476927707, 15.212508450304711 ], [ -90.503772548764118, 15.262195339543268 ], [ -90.480569831332616, 15.261135973246553 ], [ -90.45770300978603, 15.260980942716344 ], [ -90.424113328667147, 15.260128281994582 ], [ -90.400548876029802, 15.260980942716344 ], [ -90.378922288832541, 15.254314682976201 ], [ -90.323835211725623, 15.218089504427098 ], [ -90.313164028996709, 15.207805894426485 ], [ -90.310270148248719, 15.207056586492286 ], [ -90.306316901204013, 15.20752167448569 ], [ -90.29621415925601, 15.21287018551061 ], [ -90.292312588155426, 15.216849270077716 ], [ -90.280091111815352, 15.231654567903945 ], [ -90.275336879993006, 15.235659490892772 ], [ -90.268567268364734, 15.24509044017168 ], [ -90.260505743745057, 15.275967109494502 ], [ -90.259756435810857, 15.282168280341864 ], [ -90.258903775089152, 15.284338691577318 ], [ -90.256371630446381, 15.289118760922065 ], [ -90.254821336835221, 15.291056627261526 ], [ -90.253090176070771, 15.292787787126656 ], [ -90.248775193820109, 15.295707506296367 ], [ -90.235235968764925, 15.294932359041127 ], [ -90.187176886603993, 15.283718573053704 ], [ -90.078010423642127, 15.268835760861634 ], [ -90.038813849979192, 15.270153510476121 ], [ -90.006050992059613, 15.282788397966158 ], [ -89.997007616408325, 15.284855455514844 ], [ -89.952100795615195, 15.288498643297714 ], [ -89.948741827773119, 15.287826849729299 ], [ -89.945098639990249, 15.28674164501092 ], [ -89.937657232994866, 15.282478338704379 ], [ -89.926417608585723, 15.272194728703766 ], [ -89.921715053606817, 15.266561997737995 ], [ -89.919312100173272, 15.262143662699884 ], [ -89.917374233833812, 15.257182725302528 ], [ -89.918149380189732, 15.247054144932804 ], [ -89.928846402239628, 15.217934474796152 ], [ -89.97300391329992, 15.156542874054367 ], [ -89.999953173100437, 15.142073473012374 ], [ -90.038452114773236, 15.116752021188802 ], [ -90.123873257045148, 15.061251532032543 ], [ -90.282571581413322, 14.954488023403542 ], [ -90.298436244636946, 14.905653794886689 ], [ -90.303397182933622, 14.889582424289415 ], [ -90.354298468999104, 14.881520901468434 ], [ -90.387371385281199, 14.887256985221654 ], [ -90.399928758405451, 14.899039211090724 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "GT-TO", "NAME_1": "Totonicapán" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -91.511075406005148, 14.907152410755145 ], [ -91.517819180111076, 14.9093228219906 ], [ -91.519343635300515, 14.911389879539286 ], [ -91.520609707172241, 14.913508613032036 ], [ -91.536500209716905, 14.931647040278676 ], [ -91.538412237634645, 14.938364975962884 ], [ -91.53833472416818, 14.944566147709509 ], [ -91.536293505041215, 14.949940497156206 ], [ -91.536035121723444, 14.961619371137033 ], [ -91.552726609945069, 14.976243800910652 ], [ -91.560219692884516, 14.985907294186291 ], [ -91.564147102406821, 15.000531724859172 ], [ -91.588770922240258, 15.091430569365286 ], [ -91.593886888369184, 15.120266017762503 ], [ -91.591871507663939, 15.12848257111375 ], [ -91.589701097327747, 15.129877835094021 ], [ -91.587479011047492, 15.131014715756521 ], [ -91.536319342563615, 15.15044505509519 ], [ -91.51882686956435, 15.155974433273457 ], [ -91.485185513400722, 15.157731432459627 ], [ -91.481413132609987, 15.159385077059653 ], [ -91.47704647531458, 15.161813869814239 ], [ -91.47645219611195, 15.164862779293799 ], [ -91.474204271409974, 15.190003363964081 ], [ -91.473506639419838, 15.192664699816021 ], [ -91.467563850091608, 15.203878485803443 ], [ -91.454386359343005, 15.222688707517818 ], [ -91.450820685925919, 15.22638357214413 ], [ -91.445782233263458, 15.228786526476995 ], [ -91.43580868162536, 15.231499539172376 ], [ -91.392477993764373, 15.241240545914422 ], [ -91.376923387104625, 15.252325140692676 ], [ -91.352790493686314, 15.262815457167619 ], [ -91.341111619705487, 15.264908352238649 ], [ -91.31535091831023, 15.263151353052478 ], [ -91.320001797345071, 15.235220242220407 ], [ -91.32015682697596, 15.217081814074447 ], [ -91.315195888679284, 15.201630561101524 ], [ -91.301656663624101, 15.195119330093007 ], [ -91.2985302397787, 15.18824636477791 ], [ -91.270676643312413, 15.160470281778089 ], [ -91.263803677097997, 15.157576401929418 ], [ -91.25886857812236, 15.138042710702507 ], [ -91.249127569581674, 15.124555162490765 ], [ -91.247732307400042, 15.110705878173746 ], [ -91.240807665241562, 15.108483791893491 ], [ -91.234554815752119, 15.097218329062628 ], [ -91.234503139808055, 15.092050686090261 ], [ -91.235407478272464, 15.081922104821274 ], [ -91.237758754862625, 15.078046373041673 ], [ -91.240678474032336, 15.075927639548922 ], [ -91.251142951186239, 15.075720933074592 ], [ -91.25543209501518, 15.074687405199597 ], [ -91.260470546778265, 15.07256867080747 ], [ -91.268532071397942, 15.06641917590423 ], [ -91.271865200818354, 15.061716620026004 ], [ -91.274242315830179, 15.055153713073366 ], [ -91.275017463085419, 15.047402249514164 ], [ -91.274862434353849, 15.044301663191163 ], [ -91.274423183882789, 15.041304430554987 ], [ -91.273182950432783, 15.038927313744523 ], [ -91.271477627190734, 15.037066961770847 ], [ -91.2607806060401, 15.030400702030761 ], [ -91.243003913100097, 15.017429917756488 ], [ -91.240988532394852, 15.014484361064376 ], [ -91.23822384285603, 15.00936839403613 ], [ -91.233547126298845, 14.991488349207941 ], [ -91.226596645718587, 14.980739651213923 ], [ -91.210163539915413, 14.969577542069885 ], [ -91.207243821645022, 14.963996487048234 ], [ -91.206933763282507, 14.957743639357432 ], [ -91.212488979882494, 14.941155503923369 ], [ -91.214685227741029, 14.934850979389182 ], [ -91.182981737017542, 14.910666409127487 ], [ -91.202567105087837, 14.891752835524926 ], [ -91.215847947724569, 14.873252672173066 ], [ -91.229619716776483, 14.860023505480399 ], [ -91.240652634711296, 14.856716213582388 ], [ -91.246104499423097, 14.855682684808016 ], [ -91.252641567953958, 14.855837714438962 ], [ -91.255742154276959, 14.856251126488303 ], [ -91.271658495243344, 14.861367091717909 ], [ -91.27868649018933, 14.862607326966554 ], [ -91.292458259241243, 14.862607326966554 ], [ -91.313051316764813, 14.854029039308728 ], [ -91.320208502920082, 14.854855862508032 ], [ -91.325918749150958, 14.857336331206682 ], [ -91.335091315112095, 14.859868475849453 ], [ -91.358139003811971, 14.863279120534969 ], [ -91.369972907423744, 14.861677150979745 ], [ -91.37870622381314, 14.858783271131017 ], [ -91.424414029383911, 14.821059474914819 ], [ -91.428289761163512, 14.817648831128622 ], [ -91.447978482021313, 14.850980128929791 ], [ -91.458856371224556, 14.860695299048814 ], [ -91.461879442282395, 14.890667629007851 ], [ -91.470483568361999, 14.910149644290641 ], [ -91.491645066666479, 14.9093228219906 ], [ -91.511075406005148, 14.907152410755145 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/haiti.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/haiti.geojson new file mode 100644 index 0000000000000..3b520e3c33847 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/haiti.geojson @@ -0,0 +1,16 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "HT-NE", "NAME_1": "Nord-Est" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.757435675999943, 19.710109768000052 ], [ -71.748613240999902, 19.682598165000073 ], [ -71.745047566999943, 19.664898987000058 ], [ -71.746041408999929, 19.649017002000036 ], [ -71.747683064999961, 19.622782695000026 ], [ -71.743083862999924, 19.600070903000059 ], [ -71.715126912999921, 19.53746490500005 ], [ -71.703189656999967, 19.459278463000103 ], [ -71.703861450999852, 19.414630025000079 ], [ -71.715281942999951, 19.391659851000028 ], [ -71.720811320999957, 19.385949606000068 ], [ -71.733472046999907, 19.355460511000089 ], [ -71.742980508999977, 19.348380839000058 ], [ -71.769955607999918, 19.333808085 ], [ -71.776518514999907, 19.327503561000086 ], [ -71.771557576999953, 19.307556457000075 ], [ -71.753729206999907, 19.28378529900003 ], [ -71.749517077051451, 19.279707722733178 ], [ -71.749981859275351, 19.279650377462929 ], [ -71.78390743717847, 19.275464586421492 ], [ -71.819254115684885, 19.278358466270163 ], [ -71.837650926249239, 19.277118231920838 ], [ -71.86044023343004, 19.28125234611889 ], [ -71.887622036327912, 19.28486969727868 ], [ -71.906225551567957, 19.299752509470693 ], [ -71.94327755421574, 19.315772203224583 ], [ -71.978882616039868, 19.335770982444842 ], [ -71.995522427418052, 19.387344062078796 ], [ -72.045958624590867, 19.435764879445628 ], [ -72.064613816674296, 19.440932522417938 ], [ -72.08301062723865, 19.445686754240285 ], [ -72.073088752443937, 19.460414536801409 ], [ -72.069988166120936, 19.486924547030185 ], [ -72.087041388649141, 19.512969469265556 ], [ -72.097273321806369, 19.542528388074629 ], [ -72.110735033395088, 19.566144517555415 ], [ -72.113706427609543, 19.589657294248696 ], [ -72.109779018986501, 19.602369697003894 ], [ -72.110502489398357, 19.616115628533407 ], [ -72.098384365845789, 19.623660387416919 ], [ -72.082338832770915, 19.626864324728786 ], [ -72.060996467313089, 19.656526598124003 ], [ -72.056526455431538, 19.695077215740923 ], [ -72.052728238017778, 19.702621975523755 ], [ -72.047915174375632, 19.712042611329856 ], [ -72.04124915299991, 19.708970445000091 ], [ -72.02765865799995, 19.699611721000053 ], [ -72.018544074999909, 19.697455145000049 ], [ -72.010812954999949, 19.700873114000046 ], [ -72.005726691999939, 19.708319403000075 ], [ -71.999338344999899, 19.71556224200009 ], [ -71.987863735999952, 19.718573309000078 ], [ -71.968861456999946, 19.732326565000051 ], [ -71.940500454999949, 19.732123114000046 ], [ -71.891590949999909, 19.718573309000078 ], [ -71.864735480999911, 19.715073960000041 ], [ -71.857574022999927, 19.710028387000079 ], [ -71.863636847999942, 19.697455145000049 ], [ -71.872303839999915, 19.69212474200009 ], [ -71.884185350999928, 19.690252997000073 ], [ -71.912098761999914, 19.690619208000044 ], [ -71.901600714999915, 19.672308661000045 ], [ -71.884266730999911, 19.670396226000037 ], [ -71.86546790299991, 19.675360419000071 ], [ -71.850656704999949, 19.677639065000051 ], [ -71.832590298999946, 19.663275458000044 ], [ -71.821441209999932, 19.656683661000045 ], [ -71.816517706999946, 19.659857489000046 ], [ -71.811146613999938, 19.673570054000038 ], [ -71.813303188999953, 19.680731512000079 ], [ -71.835357225999928, 19.68618398600006 ], [ -71.84243730399993, 19.692328192000048 ], [ -71.84601803299995, 19.701117255000042 ], [ -71.84439042899993, 19.711127020000049 ], [ -71.836740688999953, 19.717352606000077 ], [ -71.825306769999941, 19.716620184000078 ], [ -71.799427863999938, 19.711127020000049 ], [ -71.757435675999943, 19.710109768000052 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HT-CE", "NAME_1": "Centre" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.749517077051451, 19.279707722733178 ], [ -71.716522176999888, 19.247766825000028 ], [ -71.651732717191123, 19.21792388447966 ], [ -71.63911088099988, 19.212110088000045 ], [ -71.64365840699989, 19.15247548400005 ], [ -71.648774373999885, 19.135293071000078 ], [ -71.661383422999904, 19.117593893000063 ], [ -71.695283161999924, 19.094546204 ], [ -71.710424356999937, 19.081652934000104 ], [ -71.740345011999864, 19.041887919000075 ], [ -71.783701537999946, 18.996309306000015 ], [ -71.796827351999923, 18.988609518000104 ], [ -71.848142048999961, 18.975483704000041 ], [ -71.865401977999852, 18.964424948000058 ], [ -71.862456421999951, 18.947087504000038 ], [ -71.844524698999891, 18.949748841000044 ], [ -71.819668334999932, 18.957810364000053 ], [ -71.796258910999967, 18.957061056000057 ], [ -71.787112182999891, 18.950033061000042 ], [ -71.772952839999931, 18.921714376000054 ], [ -71.763806111999941, 18.911508281000053 ], [ -71.740913452999933, 18.891612854000059 ], [ -71.733472046999907, 18.882569479 ], [ -71.727942668999901, 18.864069316000084 ], [ -71.726909139999918, 18.82352915500006 ], [ -71.71884761599992, 18.784229228000086 ], [ -71.72034623299993, 18.76544484500009 ], [ -71.725255492999878, 18.746970520000062 ], [ -71.732076782999911, 18.730072327000059 ], [ -71.744065714999891, 18.711442973000104 ], [ -71.758070027999878, 18.700513407000031 ], [ -71.784897638415259, 18.684730212729107 ], [ -71.79177913299992, 18.680681698000072 ], [ -71.792123989630397, 18.68108226213667 ], [ -71.798841926213925, 18.688885403438576 ], [ -71.836669074318309, 18.710279445739786 ], [ -71.87852698383324, 18.720666409427224 ], [ -71.912116664952123, 18.732241929721283 ], [ -71.946223110907852, 18.74350739255209 ], [ -72.026683315782407, 18.729554755447566 ], [ -72.105877447885916, 18.705060125924035 ], [ -72.182126024196634, 18.730019843441028 ], [ -72.242329068331799, 18.78650218452816 ], [ -72.272146368659946, 18.806035874855752 ], [ -72.306252813716355, 18.814200751363558 ], [ -72.339067349378638, 18.833837795377917 ], [ -72.365189785080531, 18.867014065346837 ], [ -72.318396775690644, 18.869701238721177 ], [ -72.270957811154062, 18.864430242961305 ], [ -72.247445033561462, 18.877142645716503 ], [ -72.243672654569366, 18.908045152561726 ], [ -72.229926723939172, 18.940549628062854 ], [ -72.232794766265442, 18.96705963829163 ], [ -72.238892585224619, 19.017082424314424 ], [ -72.225120816172705, 19.067880356693081 ], [ -72.231890427800977, 19.097490953244858 ], [ -72.234060838137168, 19.121778876294115 ], [ -72.224707404123365, 19.143069565807821 ], [ -72.251579148658777, 19.168494371318161 ], [ -72.245868903327221, 19.240893053371678 ], [ -72.200057745868264, 19.301922918907565 ], [ -72.170550503003312, 19.292104396900356 ], [ -72.148639695865256, 19.271382148167561 ], [ -72.1394671290048, 19.258308010206463 ], [ -72.120062628987114, 19.260065009392633 ], [ -72.050919561988167, 19.30088939103257 ], [ -71.978882616039868, 19.335770982444842 ], [ -71.94327755421574, 19.315772203224583 ], [ -71.906225551567957, 19.299752509470693 ], [ -71.887622036327912, 19.28486969727868 ], [ -71.86044023343004, 19.28125234611889 ], [ -71.837650926249239, 19.277118231920838 ], [ -71.819254115684885, 19.278358466270163 ], [ -71.78390743717847, 19.275464586421492 ], [ -71.749981859275351, 19.279650377462929 ], [ -71.749517077051451, 19.279707722733178 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HT-OU", "NAME_1": "Ouest" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -71.79177913299992, 18.680681698000072 ], [ -71.794346883999935, 18.679171041000032 ], [ -71.807989460999949, 18.664649964000077 ], [ -71.828556680999924, 18.631292827000024 ], [ -71.841579141999972, 18.617986145000103 ], [ -71.88028479099998, 18.605402934 ], [ -71.955474, 18.618606262000085 ], [ -71.992629353999916, 18.61113901800006 ], [ -72.009837605999905, 18.598814189 ], [ -72.000949259999885, 18.582458598000059 ], [ -71.910515502999914, 18.494272766 ], [ -71.904055949999957, 18.484790141000119 ], [ -71.901575479999877, 18.469778138000052 ], [ -71.906898152999929, 18.464300436000045 ], [ -71.914391235999858, 18.460217997000044 ], [ -71.918163615999873, 18.449236755000058 ], [ -71.912169148999851, 18.430736593000049 ], [ -71.897182983999897, 18.422881775000107 ], [ -71.858167277999883, 18.413554179000059 ], [ -71.8497440189999, 18.406448670000131 ], [ -71.834551147999946, 18.38508046500003 ], [ -71.826437947999864, 18.37616628100001 ], [ -71.788714152999916, 18.352214254 ], [ -71.734970662999899, 18.332938945000066 ], [ -71.720707967999942, 18.323973083000041 ], [ -71.711509562999936, 18.316144105000106 ], [ -71.709339151999927, 18.313250224000015 ], [ -71.721111735999841, 18.293973823000087 ], [ -71.722050746644641, 18.293819077788214 ], [ -71.809538947364501, 18.279401352690286 ], [ -71.861267055730025, 18.310045478016377 ], [ -71.928653124442121, 18.315006415413734 ], [ -72.012730678677883, 18.313972887538739 ], [ -72.09918534972411, 18.332628078722848 ], [ -72.18607927124134, 18.349629625306932 ], [ -72.271267870415898, 18.344565335122127 ], [ -72.354053514358213, 18.349319566045097 ], [ -72.367851121831791, 18.36404735040486 ], [ -72.380020922227743, 18.379912014527804 ], [ -72.408959724311842, 18.377793281035053 ], [ -72.428028326645972, 18.386991685417911 ], [ -72.454254116034633, 18.39934235296721 ], [ -72.490272589908102, 18.401512763303344 ], [ -72.523448858977645, 18.386733302999517 ], [ -72.548150194076186, 18.358517971327274 ], [ -72.558227097602469, 18.351179918018772 ], [ -72.570319382733317, 18.350818182812873 ], [ -72.594865689100232, 18.340792955230711 ], [ -72.618016729688293, 18.33805410411361 ], [ -72.631297574123721, 18.336503811401769 ], [ -72.642640550421049, 18.327305406119592 ], [ -72.66176082959862, 18.324928290208391 ], [ -72.681191168937289, 18.32415314385247 ], [ -72.692844203597133, 18.314644680207834 ], [ -72.703799608065424, 18.304774482256562 ], [ -72.721162888956144, 18.307151598167707 ], [ -72.736872525246838, 18.315316473776249 ], [ -72.739559698621179, 18.300950426421025 ], [ -72.745037400855381, 18.288496406084278 ], [ -72.757233038773734, 18.279349676746165 ], [ -72.76503618007564, 18.265293686854136 ], [ -72.798109097256997, 18.273251857786988 ], [ -72.832060512682517, 18.284207262255336 ], [ -72.848958705579776, 18.274543768979754 ], [ -72.860275845254023, 18.262968247786375 ], [ -72.881799078764459, 18.273355211473813 ], [ -72.893090380016986, 18.289064845965868 ], [ -72.907869839421551, 18.289891669165172 ], [ -72.92347612202542, 18.290925197939544 ], [ -72.950089484142381, 18.285344142917836 ], [ -72.971302660189622, 18.282605291800735 ], [ -72.983317430055365, 18.304567775782232 ], [ -72.997735155153293, 18.322757879872256 ], [ -73.013393113701227, 18.34151642474319 ], [ -73.020757005431449, 18.365804347792391 ], [ -73.038042771956327, 18.382392483226511 ], [ -73.063028326995664, 18.383374335157441 ], [ -73.06527625169764, 18.410246079692797 ], [ -73.049747484358932, 18.435205797209733 ], [ -73.05023840987468, 18.447298082340637 ], [ -73.055945009354673, 18.45845306255876 ], [ -72.985585089999915, 18.470404364000046 ], [ -72.898996548999946, 18.450506903000075 ], [ -72.904164191999939, 18.434149481000077 ], [ -72.88508053299995, 18.437689520000049 ], [ -72.858306443999936, 18.446682033000059 ], [ -72.840646938999953, 18.446763414000088 ], [ -72.826039191999939, 18.440822658000059 ], [ -72.754994269999941, 18.429388739000046 ], [ -72.716460740999935, 18.437730210000041 ], [ -72.689320441999939, 18.459662177000041 ], [ -72.669341600999928, 18.490464585000041 ], [ -72.65257727799991, 18.525580145000049 ], [ -72.628285285999937, 18.55414459800005 ], [ -72.596547003999945, 18.56085846600007 ], [ -72.429758266999897, 18.546698309000078 ], [ -72.423695441999939, 18.548814195000091 ], [ -72.421131964999915, 18.553534247000073 ], [ -72.419504360999952, 18.558254299000055 ], [ -72.416086391999897, 18.560370184000078 ], [ -72.409820115999935, 18.559149481000077 ], [ -72.40689042899993, 18.556626695000091 ], [ -72.40493730399993, 18.554103908000059 ], [ -72.401763475999928, 18.552923895000049 ], [ -72.380970831999946, 18.53070709800005 ], [ -72.37140865799995, 18.525580145000049 ], [ -72.35383053299995, 18.530096747000073 ], [ -72.345692511999914, 18.546861070000091 ], [ -72.343413865999935, 18.570135809000078 ], [ -72.345082160999937, 18.631008205000057 ], [ -72.343413865999935, 18.642279364000046 ], [ -72.336415167999917, 18.655829169000071 ], [ -72.328684048999946, 18.663885809000078 ], [ -72.325062628999945, 18.671372789000088 ], [ -72.330433722999942, 18.683294989000046 ], [ -72.339426235999952, 18.689439195000091 ], [ -72.38508053299995, 18.710598049000055 ], [ -72.397368943999936, 18.712632554000038 ], [ -72.421701626999948, 18.713364976000037 ], [ -72.433461066999939, 18.716782945000091 ], [ -72.453724738999938, 18.733343817000048 ], [ -72.471750454999949, 18.754095770000049 ], [ -72.491078253999945, 18.768500067000048 ], [ -72.515370245999918, 18.765814520000049 ], [ -72.549549933999913, 18.785630601000037 ], [ -72.558094855999911, 18.794623114000046 ], [ -72.566517706999946, 18.813625393000052 ], [ -72.617787238999938, 18.889349677000041 ], [ -72.631947394999941, 18.90306224200009 ], [ -72.651966925999943, 18.91860586100006 ], [ -72.673003709999932, 18.931301174000055 ], [ -72.69009355399993, 18.936509507000039 ], [ -72.7060447007661, 18.944241285750444 ], [ -72.692017381297092, 18.961168524907464 ], [ -72.675274217131403, 18.972847397989028 ], [ -72.611531338000816, 18.970573634865332 ], [ -72.536006232101897, 18.960393378551544 ], [ -72.512493456307936, 18.957809557065389 ], [ -72.487740445265331, 18.958894761783824 ], [ -72.476940070427872, 18.944425360741775 ], [ -72.466914841946391, 18.929025783712916 ], [ -72.441955126228095, 18.918793850555744 ], [ -72.415548468786767, 18.908665269286757 ], [ -72.388625047408027, 18.889958401259207 ], [ -72.365189785080531, 18.867014065346837 ], [ -72.339067349378638, 18.833837795377917 ], [ -72.306252813716355, 18.814200751363558 ], [ -72.272146368659946, 18.806035874855752 ], [ -72.242329068331799, 18.78650218452816 ], [ -72.182126024196634, 18.730019843441028 ], [ -72.105877447885916, 18.705060125924035 ], [ -72.026683315782407, 18.729554755447566 ], [ -71.946223110907852, 18.74350739255209 ], [ -71.912116664952123, 18.732241929721283 ], [ -71.87852698383324, 18.720666409427224 ], [ -71.836669074318309, 18.710279445739786 ], [ -71.798841926213925, 18.688885403438576 ], [ -71.792123989630397, 18.68108226213667 ], [ -71.79177913299992, 18.680681698000072 ] ] ], [ [ [ -73.258656378999945, 18.878485419000071 ], [ -73.277333136999914, 18.891099351000037 ], [ -73.282582160999937, 18.895493882000039 ], [ -73.289906378999945, 18.904201565000051 ], [ -73.296538865999935, 18.914496161000045 ], [ -73.299631313999953, 18.925523179000038 ], [ -73.296213344999899, 18.936509507000039 ], [ -73.28384355399993, 18.949693101000037 ], [ -73.266346808999913, 18.960842190000051 ], [ -73.245961066999939, 18.968410549000055 ], [ -73.224476691999939, 18.971258856000077 ], [ -73.200795050999943, 18.968695380000042 ], [ -73.061919725999928, 18.913316148000035 ], [ -72.993397589999915, 18.89203522300005 ], [ -72.917225714999915, 18.855454820000091 ], [ -72.846099412999934, 18.827093817000048 ], [ -72.81704667899993, 18.793117580000057 ], [ -72.809478318999936, 18.771470445000091 ], [ -72.805897589999915, 18.745672919000071 ], [ -72.808745897999927, 18.720404364000046 ], [ -72.820464647999927, 18.700669664000088 ], [ -72.831125454999949, 18.696437893000052 ], [ -72.83820553299995, 18.70258209800005 ], [ -72.847157355999911, 18.720526434000078 ], [ -72.85570227799991, 18.727687893000052 ], [ -72.863352016999897, 18.729641018000052 ], [ -72.885894334999932, 18.731024481000077 ], [ -72.975005662999934, 18.749904690000051 ], [ -73.005441860999952, 18.752142645000049 ], [ -73.03742428299995, 18.759588934000078 ], [ -73.125559048999946, 18.813625393000052 ], [ -73.214588995999918, 18.836615302000041 ], [ -73.23851477799991, 18.851507880000042 ], [ -73.258656378999945, 18.878485419000071 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HT-SE", "NAME_1": "Sud-Est" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.721111735999841, 18.293973823000087 ], [ -71.721708773141359, 18.292996236786905 ], [ -71.766131551999877, 18.220258484000041 ], [ -71.77403804599993, 18.201474101000045 ], [ -71.776828572999875, 18.181785380000079 ], [ -71.775329955999979, 18.172328593000131 ], [ -71.764581257999851, 18.143674011000044 ], [ -71.762204141999916, 18.132486064000105 ], [ -71.762875935999887, 18.115846253000072 ], [ -71.760653849999898, 18.086804097000098 ], [ -71.764271199999968, 18.069492493000084 ], [ -71.776234503999945, 18.039252020000063 ], [ -71.792591925999943, 18.049872137000079 ], [ -71.862456834999932, 18.136542059000078 ], [ -71.892974412999934, 18.162787177000041 ], [ -71.928089972999942, 18.183783270000049 ], [ -72.006743943999936, 18.209458726000037 ], [ -72.03929602799991, 18.225653387000079 ], [ -72.071766730999911, 18.237534898000092 ], [ -72.110707160999937, 18.237616278000075 ], [ -72.190541144999941, 18.224839585000041 ], [ -72.294545050999943, 18.225775458000044 ], [ -72.440297003999945, 18.223944403000075 ], [ -72.518788214999915, 18.210353908000059 ], [ -72.538889126999948, 18.220445054000038 ], [ -72.550933397999927, 18.224758205000057 ], [ -72.556304490999935, 18.220851955000057 ], [ -72.549549933999913, 18.18235911700009 ], [ -72.558990037999934, 18.172552802000041 ], [ -72.570668097999942, 18.172308661000045 ], [ -72.59797115799995, 18.18235911700009 ], [ -72.613270636999914, 18.18500397300005 ], [ -72.730865037999934, 18.174709377000056 ], [ -72.754994269999941, 18.176174221000053 ], [ -72.753000454999949, 18.171576239000046 ], [ -72.750111456999946, 18.160305080000057 ], [ -72.748158331999946, 18.15570709800005 ], [ -72.763010219999899, 18.156724351000037 ], [ -72.768950975999928, 18.158270575000074 ], [ -72.77603105399993, 18.163153387000079 ], [ -72.803700324999909, 18.146144924000055 ], [ -72.858876105999911, 18.151312567000048 ], [ -72.885894334999932, 18.141424872000073 ], [ -72.912180141999897, 18.155910549000055 ], [ -72.94749915299991, 18.169094143000052 ], [ -72.985340949999909, 18.178656317000048 ], [ -73.008043724859107, 18.181064983390439 ], [ -73.006933560435471, 18.185970364440777 ], [ -73.010059984280815, 18.203385322174881 ], [ -73.012462937714417, 18.220903631797171 ], [ -73.014426643374861, 18.242866115778611 ], [ -73.014504156841326, 18.264828599760051 ], [ -73.001688402197999, 18.293095608275678 ], [ -72.997735155153293, 18.322757879872256 ], [ -72.983317430055365, 18.304567775782232 ], [ -72.971302660189622, 18.282605291800735 ], [ -72.950089484142381, 18.285344142917836 ], [ -72.92347612202542, 18.290925197939544 ], [ -72.907869839421551, 18.289891669165172 ], [ -72.893090380016986, 18.289064845965868 ], [ -72.881799078764459, 18.273355211473813 ], [ -72.860275845254023, 18.262968247786375 ], [ -72.848958705579776, 18.274543768979754 ], [ -72.832060512682517, 18.284207262255336 ], [ -72.798109097256997, 18.273251857786988 ], [ -72.76503618007564, 18.265293686854136 ], [ -72.757233038773734, 18.279349676746165 ], [ -72.745037400855381, 18.288496406084278 ], [ -72.739559698621179, 18.300950426421025 ], [ -72.736872525246838, 18.315316473776249 ], [ -72.721162888956144, 18.307151598167707 ], [ -72.703799608065424, 18.304774482256562 ], [ -72.692844203597133, 18.314644680207834 ], [ -72.681191168937289, 18.32415314385247 ], [ -72.66176082959862, 18.324928290208391 ], [ -72.642640550421049, 18.327305406119592 ], [ -72.631297574123721, 18.336503811401769 ], [ -72.618016729688293, 18.33805410411361 ], [ -72.594865689100232, 18.340792955230711 ], [ -72.570319382733317, 18.350818182812873 ], [ -72.558227097602469, 18.351179918018772 ], [ -72.548150194076186, 18.358517971327274 ], [ -72.523448858977645, 18.386733302999517 ], [ -72.490272589908102, 18.401512763303344 ], [ -72.454254116034633, 18.39934235296721 ], [ -72.428028326645972, 18.386991685417911 ], [ -72.408959724311842, 18.377793281035053 ], [ -72.380020922227743, 18.379912014527804 ], [ -72.367851121831791, 18.36404735040486 ], [ -72.354053514358213, 18.349319566045097 ], [ -72.271267870415898, 18.344565335122127 ], [ -72.18607927124134, 18.349629625306932 ], [ -72.09918534972411, 18.332628078722848 ], [ -72.012730678677883, 18.313972887538739 ], [ -71.928653124442121, 18.315006415413734 ], [ -71.861267055730025, 18.310045478016377 ], [ -71.809538947364501, 18.279401352690286 ], [ -71.722050746644641, 18.293819077788214 ], [ -71.721111735999841, 18.293973823000087 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HT-SD", "NAME_1": "Sud" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -73.628895636999914, 18.094224351000037 ], [ -73.612049933999913, 18.093247789000088 ], [ -73.592274542999917, 18.089341539000088 ], [ -73.577992316999939, 18.081122137000079 ], [ -73.577992316999939, 18.066961981000077 ], [ -73.590443488999938, 18.059393622000073 ], [ -73.610829230999911, 18.057562567000048 ], [ -73.649728969999899, 18.059475002000056 ], [ -73.667225714999915, 18.06313711100006 ], [ -73.682525193999936, 18.072007554000038 ], [ -73.70767167899993, 18.094224351000037 ], [ -73.704457160999937, 18.104193427000041 ], [ -73.699940558999913, 18.108303127000056 ], [ -73.694243943999936, 18.10687897300005 ], [ -73.687855597999942, 18.100490627000056 ], [ -73.676380988999938, 18.108099677000041 ], [ -73.670887824999909, 18.105373440000051 ], [ -73.666900193999936, 18.098578192000048 ], [ -73.659982876999948, 18.094224351000037 ], [ -73.628895636999914, 18.094224351000037 ] ] ], [ [ [ -73.008043724859107, 18.181064983390439 ], [ -73.090809699999909, 18.189846096000053 ], [ -73.117258266999897, 18.188625393000052 ], [ -73.125559048999946, 18.189846096000053 ], [ -73.154652472999942, 18.207505601000037 ], [ -73.163400844999899, 18.210353908000059 ], [ -73.296213344999899, 18.23078034100007 ], [ -73.355865037999934, 18.22492096600007 ], [ -73.365101691999939, 18.227362372000073 ], [ -73.359852667999917, 18.240383205000057 ], [ -73.346587693999936, 18.245347398000092 ], [ -73.310454881999931, 18.245062567000048 ], [ -73.310454881999931, 18.251288153000075 ], [ -73.37726803299995, 18.25812409100007 ], [ -73.458241339999915, 18.257513739000046 ], [ -73.481800910999937, 18.251288153000075 ], [ -73.51398678299995, 18.23314036700009 ], [ -73.526193813999953, 18.23078034100007 ], [ -73.534169074999909, 18.234767971000053 ], [ -73.542795376999948, 18.253119208000044 ], [ -73.550119594999899, 18.258734442000048 ], [ -73.563465949999909, 18.251044012000079 ], [ -73.570708787999934, 18.231512762000079 ], [ -73.578114386999914, 18.216864325000074 ], [ -73.591664191999939, 18.223944403000075 ], [ -73.59788977799991, 18.223944403000075 ], [ -73.60968990799995, 18.216782945000091 ], [ -73.619618292999917, 18.221909898000092 ], [ -73.624012824999909, 18.234849351000037 ], [ -73.619007941999939, 18.251288153000075 ], [ -73.633208787999934, 18.247259833000044 ], [ -73.645619269999941, 18.221096096000053 ], [ -73.659982876999948, 18.210353908000059 ], [ -73.659291144999941, 18.223822333000044 ], [ -73.655995245999918, 18.235825914000088 ], [ -73.646311001999948, 18.258734442000048 ], [ -73.654164191999939, 18.25267161700009 ], [ -73.665435350999928, 18.238511460000041 ], [ -73.673573370999918, 18.23078034100007 ], [ -73.674387173999946, 18.233221747000073 ], [ -73.680246548999946, 18.235419012000079 ], [ -73.690988735999952, 18.237616278000075 ], [ -73.694569464999915, 18.235907294000071 ], [ -73.694162563999953, 18.231919664000088 ], [ -73.692982550999943, 18.227443752000056 ], [ -73.694081183999913, 18.223944403000075 ], [ -73.737782355999911, 18.190741278000075 ], [ -73.809315558999913, 18.159165757000039 ], [ -73.827463344999899, 18.14203522300005 ], [ -73.844878709999932, 18.11469147300005 ], [ -73.802805141999897, 18.071926174000055 ], [ -73.796498175999943, 18.056341864000046 ], [ -73.791411912999934, 18.036688544000071 ], [ -73.793812628999945, 18.028998114000046 ], [ -73.807036912999934, 18.025946356000077 ], [ -73.87328040299991, 18.026190497000073 ], [ -73.882964647999927, 18.027736721000053 ], [ -73.892689581999946, 18.032171942000048 ], [ -73.899973110999952, 18.039129950000074 ], [ -73.903797980999911, 18.053859768000052 ], [ -73.967762824999909, 18.141424872000073 ], [ -73.97093665299991, 18.143703518000052 ], [ -73.978505011999914, 18.146877346000053 ], [ -73.982045050999943, 18.148871161000045 ], [ -73.985585089999915, 18.15265534100007 ], [ -73.986398891999897, 18.15570709800005 ], [ -73.986887173999946, 18.158880927000041 ], [ -73.989572719999899, 18.163153387000079 ], [ -74.008208787999934, 18.179754950000074 ], [ -74.105051235999952, 18.247626044000071 ], [ -74.122425910999937, 18.255682684000078 ], [ -74.152943488999938, 18.260565497000073 ], [ -74.165760870999918, 18.265611070000091 ], [ -74.176665818999936, 18.273179429000038 ], [ -74.181304490999935, 18.282619533000059 ], [ -74.183420376999948, 18.29328034100007 ], [ -74.189076300999943, 18.296535549000055 ], [ -74.19758053299995, 18.297064520000049 ], [ -74.207997199999909, 18.299709377000056 ], [ -74.233794725999928, 18.309271552000041 ], [ -74.242176886999914, 18.313950914000088 ], [ -74.248931443999936, 18.306545315000051 ], [ -74.26781165299991, 18.312974351000037 ], [ -74.287831183999913, 18.304917710000041 ], [ -74.308949347999942, 18.292466539000088 ], [ -74.330922003999945, 18.286037502000056 ], [ -74.349354620999918, 18.28969961100006 ], [ -74.372181769999941, 18.298488674000055 ], [ -74.391590949999909, 18.308783270000049 ], [ -74.399769660999937, 18.317084052000041 ], [ -74.408314581999946, 18.328273830000057 ], [ -74.445912238999938, 18.346380927000041 ], [ -74.452648045966384, 18.360980548059175 ], [ -74.448809373553729, 18.362652086424646 ], [ -74.424857347288707, 18.365080878279912 ], [ -74.397081265188206, 18.360119940882555 ], [ -74.341684129718772, 18.365339259798986 ], [ -74.287010463761874, 18.376398017054839 ], [ -74.186654833353884, 18.395931708281694 ], [ -74.085317349216268, 18.403631496796152 ], [ -74.043123542017838, 18.393761297945503 ], [ -74.001498175600318, 18.380428779364649 ], [ -73.953800828645285, 18.367509670135178 ], [ -73.906310187265319, 18.36384064393053 ], [ -73.908015509608049, 18.387560126198821 ], [ -73.89416622619035, 18.407300523000742 ], [ -73.87106686064709, 18.407817287837531 ], [ -73.84794165668211, 18.407868963781652 ], [ -73.815979784439492, 18.416137193076963 ], [ -73.784043748819954, 18.424715480734847 ], [ -73.751590949262891, 18.420426336905905 ], [ -73.718440517715692, 18.42187327683024 ], [ -73.698364224129648, 18.412261461297362 ], [ -73.681440191911292, 18.406990465537547 ], [ -73.658754239316693, 18.425077215940746 ], [ -73.626663174066209, 18.429314683825567 ], [ -73.599403855903233, 18.427040919802607 ], [ -73.581885546280944, 18.412778225234888 ], [ -73.567441982761295, 18.395828355494189 ], [ -73.545117763573899, 18.385079657500171 ], [ -73.554083624859402, 18.367819729396956 ], [ -73.56405717559818, 18.346270657464856 ], [ -73.513362596006971, 18.334023341803743 ], [ -73.449619716876441, 18.343738511922766 ], [ -73.418071254884467, 18.346632391771436 ], [ -73.386496955370205, 18.345598862997122 ], [ -73.350607672705905, 18.354487209916783 ], [ -73.319343430654783, 18.366631170991752 ], [ -73.2672794264044, 18.359758206575975 ], [ -73.214336921211952, 18.360740058506906 ], [ -73.188111130923915, 18.357742824971353 ], [ -73.162841355943783, 18.355003973854309 ], [ -73.140077888084079, 18.361515203963449 ], [ -73.115867479400663, 18.355107327541134 ], [ -73.077936977609397, 18.325755113407752 ], [ -73.046000942889179, 18.297488104892125 ], [ -73.037939419168822, 18.254028224922649 ], [ -73.012462937714417, 18.220903631797171 ], [ -73.010059984280815, 18.203385322174881 ], [ -73.006933560435471, 18.185970364440777 ], [ -73.008043724859107, 18.181064983390439 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HT-GA", "NAME_1": "Grand'Anse" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -73.796498175999943, 18.628648179000038 ], [ -73.772694464999915, 18.639349677000041 ], [ -73.739979620999918, 18.636867580000057 ], [ -73.714955206999946, 18.623480536000045 ], [ -73.714588995999918, 18.601304429000038 ], [ -73.737619594999899, 18.58820221600007 ], [ -73.769520636999914, 18.588364976000037 ], [ -73.794422980999911, 18.60187409100007 ], [ -73.796498175999943, 18.628648179000038 ] ] ], [ [ [ -74.452648045966384, 18.360980548059175 ], [ -74.454416469999899, 18.364813544000071 ], [ -74.456654425999943, 18.384344794000071 ], [ -74.46320553299995, 18.398179429000038 ], [ -74.489165818999936, 18.429388739000046 ], [ -74.454416469999899, 18.477769273000092 ], [ -74.457427537999934, 18.481756903000075 ], [ -74.461822068999936, 18.491441148000092 ], [ -74.443511522999927, 18.503810940000051 ], [ -74.431752081999946, 18.550116278000075 ], [ -74.416859503999945, 18.560370184000078 ], [ -74.414133266999897, 18.565578518000052 ], [ -74.415842251999948, 18.577297268000052 ], [ -74.419789191999939, 18.589829820000091 ], [ -74.423695441999939, 18.597601630000042 ], [ -74.426258917999917, 18.608221747000073 ], [ -74.418527798999946, 18.61749909100007 ], [ -74.384632941999939, 18.636297919000071 ], [ -74.340199347999942, 18.653387762000079 ], [ -74.321278449999909, 18.65656159100007 ], [ -74.298207160999937, 18.651190497000073 ], [ -74.287993943999936, 18.651516018000052 ], [ -74.283762173999946, 18.659654039000088 ], [ -74.278797980999911, 18.666571356000077 ], [ -74.267689581999946, 18.669623114000046 ], [ -74.255930141999897, 18.670314846000053 ], [ -74.199777798999946, 18.667303778000075 ], [ -74.159982876999948, 18.659165757000039 ], [ -74.029123501999948, 18.603745835000041 ], [ -73.971547003999945, 18.601304429000038 ], [ -73.969471808999913, 18.599798895000049 ], [ -73.962961391999897, 18.592840887000079 ], [ -73.96157792899993, 18.590765692000048 ], [ -73.95929928299995, 18.582993882000039 ], [ -73.953724738999938, 18.583563544000071 ], [ -73.946766730999911, 18.586981512000079 ], [ -73.940500454999949, 18.587632554000038 ], [ -73.911447719999899, 18.573187567000048 ], [ -73.898548956999946, 18.568793036000045 ], [ -73.853586391999897, 18.567206122000073 ], [ -73.842925584999932, 18.565252997000073 ], [ -73.831206834999932, 18.560370184000078 ], [ -73.809681769999941, 18.542792059000078 ], [ -73.803334113999938, 18.539252020000049 ], [ -73.793039516999897, 18.53851959800005 ], [ -73.788075324999909, 18.54132721600007 ], [ -73.784738735999952, 18.544867255000042 ], [ -73.779408331999946, 18.546698309000078 ], [ -73.769439256999931, 18.545152085000041 ], [ -73.757069464999915, 18.53937409100007 ], [ -73.748117641999897, 18.539252020000049 ], [ -73.742014126999948, 18.541937567000048 ], [ -73.739352953478388, 18.543810558507932 ], [ -73.739395311344538, 18.543726305024961 ], [ -73.74771521658397, 18.527293199221731 ], [ -73.765052659952289, 18.508482978406732 ], [ -73.760169236920717, 18.494530341302209 ], [ -73.743710292695823, 18.487192287993707 ], [ -73.766008674360819, 18.46331777609447 ], [ -73.784043748819954, 18.424715480734847 ], [ -73.815979784439492, 18.416137193076963 ], [ -73.84794165668211, 18.407868963781652 ], [ -73.87106686064709, 18.407817287837531 ], [ -73.89416622619035, 18.407300523000742 ], [ -73.908015509608049, 18.387560126198821 ], [ -73.906310187265319, 18.36384064393053 ], [ -73.953800828645285, 18.367509670135178 ], [ -74.001498175600318, 18.380428779364649 ], [ -74.043123542017838, 18.393761297945503 ], [ -74.085317349216268, 18.403631496796152 ], [ -74.186654833353884, 18.395931708281694 ], [ -74.287010463761874, 18.376398017054839 ], [ -74.341684129718772, 18.365339259798986 ], [ -74.397081265188206, 18.360119940882555 ], [ -74.424857347288707, 18.365080878279912 ], [ -74.448809373553729, 18.362652086424646 ], [ -74.452648045966384, 18.360980548059175 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HT-NO", "NAME_1": "Nord-Ouest" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -72.850575324999909, 20.08852773600006 ], [ -72.821685350999928, 20.089789130000042 ], [ -72.802398240999935, 20.087225653000075 ], [ -72.785145636999914, 20.080023505000042 ], [ -72.762440558999913, 20.067368882000039 ], [ -72.667795376999948, 20.032294012000079 ], [ -72.627552863999938, 20.008246161000045 ], [ -72.63890540299991, 19.984849351000037 ], [ -72.655140753999945, 19.991400458000044 ], [ -72.739857550999943, 20.002427476000037 ], [ -72.779164191999939, 20.016994533000059 ], [ -72.827748175999943, 20.027329820000091 ], [ -72.844309048999946, 20.034491278000075 ], [ -72.85578365799995, 20.032416083000044 ], [ -72.867665167999917, 20.028225002000056 ], [ -72.878488735999952, 20.026434637000079 ], [ -72.899403449999909, 20.030422268000052 ], [ -72.923898891999897, 20.038153387000079 ], [ -72.946115688999953, 20.048773505000042 ], [ -72.960357225999928, 20.061224677000041 ], [ -72.955962693999936, 20.06118398600006 ], [ -72.953195766999897, 20.062486070000091 ], [ -72.947377081999946, 20.067368882000039 ], [ -72.901112433999913, 20.082017320000091 ], [ -72.850575324999909, 20.08852773600006 ] ] ], [ [ [ -73.120799824652181, 19.62909590874915 ], [ -73.122141079999949, 19.62921784100007 ], [ -73.12718665299991, 19.626939195000091 ], [ -73.131825324999909, 19.622056382000039 ], [ -73.138417120999918, 19.617132880000042 ], [ -73.14907792899993, 19.614935614000046 ], [ -73.163929816999939, 19.618394273000035 ], [ -73.186024542999917, 19.627101955000057 ], [ -73.207590298999946, 19.638413804000038 ], [ -73.221099412999934, 19.649644273000035 ], [ -73.241281704999949, 19.631048895000049 ], [ -73.284250454999949, 19.62571849200009 ], [ -73.37954667899993, 19.630275783000059 ], [ -73.398426886999914, 19.634955145000049 ], [ -73.409494594999899, 19.635972398000035 ], [ -73.416574673999946, 19.640326239000046 ], [ -73.43423417899993, 19.659084377000056 ], [ -73.443959113999938, 19.663316148000035 ], [ -73.457834438999953, 19.67218659100007 ], [ -73.463368292999917, 19.69212474200009 ], [ -73.465240037999934, 19.713080145000049 ], [ -73.468129035999937, 19.724798895000049 ], [ -73.432443813999953, 19.778957424000055 ], [ -73.427154100999928, 19.790269273000035 ], [ -73.417347785999937, 19.790513414000088 ], [ -73.365101691999939, 19.813544012000079 ], [ -73.365101691999939, 19.820990302000041 ], [ -73.420318162999934, 19.820990302000041 ], [ -73.404164191999939, 19.832505601000037 ], [ -73.385121222999942, 19.834418036000045 ], [ -73.364735480999911, 19.832831122000073 ], [ -73.344593878999945, 19.834051825000074 ], [ -73.222767706999946, 19.886948960000041 ], [ -73.187123175999943, 19.911444403000075 ], [ -73.167103644999941, 19.937689520000049 ], [ -73.155140753999945, 19.923976955000057 ], [ -73.143706834999932, 19.920314846000053 ], [ -73.115305141999897, 19.923407294000071 ], [ -73.100697394999941, 19.921372789000088 ], [ -73.074330206999946, 19.912339585000041 ], [ -73.060373501999948, 19.910345770000049 ], [ -73.048451300999943, 19.910589911000045 ], [ -73.041818813999953, 19.911525783000059 ], [ -73.021839972999942, 19.916571356000077 ], [ -73.007069464999915, 19.918402411000045 ], [ -72.991769985999952, 19.917181708000044 ], [ -72.977894660999937, 19.912298895000049 ], [ -72.967274542999917, 19.902899481000077 ], [ -72.960113084999932, 19.918402411000045 ], [ -72.941273566999939, 19.92804596600007 ], [ -72.918324347999942, 19.930161851000037 ], [ -72.898996548999946, 19.923407294000071 ], [ -72.872303839999915, 19.933783270000049 ], [ -72.840443488999938, 19.941636460000041 ], [ -72.807118292999917, 19.94562409100007 ], [ -72.77603105399993, 19.943915106000077 ], [ -72.673980272999927, 19.921372789000088 ], [ -72.648833787999934, 19.906642971000053 ], [ -72.628041144999941, 19.897284247000073 ], [ -72.568714972999942, 19.879868882000039 ], [ -72.565176999019286, 19.875720913589248 ], [ -72.573239101903027, 19.870260321856335 ], [ -72.583160976697684, 19.856204331964307 ], [ -72.589568854019376, 19.844112046833459 ], [ -72.597862921736464, 19.838014227874282 ], [ -72.609025030880446, 19.828092353079626 ], [ -72.622125007263264, 19.817240302298103 ], [ -72.632692837204672, 19.818480535748108 ], [ -72.642563036055265, 19.824423325975715 ], [ -72.658582729809098, 19.82835073549802 ], [ -72.672535366014301, 19.824785061181615 ], [ -72.675842657912312, 19.812796128838272 ], [ -72.675584276393238, 19.80674998582316 ], [ -72.705995855924016, 19.810780748133027 ], [ -72.730542162290931, 19.794089259911402 ], [ -72.747181972769795, 19.78499420831605 ], [ -72.768162603921041, 19.779826565343683 ], [ -72.830303514395666, 19.729597072846616 ], [ -72.905776944350464, 19.717039699722363 ], [ -72.946627162613424, 19.724222724299295 ], [ -72.987916633146085, 19.727426663409744 ], [ -73.028224249949176, 19.736831773367612 ], [ -73.066774867566096, 19.733266099950526 ], [ -73.113826260273697, 19.686395575295535 ], [ -73.121810268728893, 19.631773587081341 ], [ -73.120799824652181, 19.62909590874915 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HT-ND", "NAME_1": "Nord" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -72.565176999019286, 19.875720913589248 ], [ -72.544341600999928, 19.851263739000046 ], [ -72.517567511999914, 19.834133205000057 ], [ -72.489735480999911, 19.824652411000045 ], [ -72.474436001999948, 19.834051825000074 ], [ -72.456206834999932, 19.82485586100006 ], [ -72.425933397999927, 19.813788153000075 ], [ -72.397572394999941, 19.80695221600007 ], [ -72.38508053299995, 19.810451565000051 ], [ -72.378732876999948, 19.794663804000038 ], [ -72.330433722999942, 19.752101955000057 ], [ -72.330433722999942, 19.745835679000038 ], [ -72.335194464999915, 19.747870184000078 ], [ -72.350900844999899, 19.752101955000057 ], [ -72.338246222999942, 19.72296784100007 ], [ -72.333851691999939, 19.718573309000078 ], [ -72.316151495999918, 19.714829820000091 ], [ -72.312408006999931, 19.716131903000075 ], [ -72.316151495999918, 19.724798895000049 ], [ -72.303089972999942, 19.739081122000073 ], [ -72.306385870999918, 19.739243882000039 ], [ -72.312896287999934, 19.738755601000037 ], [ -72.316151495999918, 19.739081122000073 ], [ -72.315907355999911, 19.740301825000074 ], [ -72.313832160999937, 19.744533596000053 ], [ -72.311390753999945, 19.747788804000038 ], [ -72.309925910999937, 19.745835679000038 ], [ -72.309925910999937, 19.752101955000057 ], [ -72.312245245999918, 19.755194403000075 ], [ -72.316151495999918, 19.765692450000074 ], [ -72.309925910999937, 19.765692450000074 ], [ -72.295074022999927, 19.758042710000041 ], [ -72.274647589999915, 19.756252346000053 ], [ -72.256418423999946, 19.761867580000057 ], [ -72.248443162999934, 19.776597398000035 ], [ -72.238392706999946, 19.786444403000075 ], [ -72.218658006999931, 19.786932684000078 ], [ -72.205230272999927, 19.776190497000073 ], [ -72.213734503999945, 19.752101955000057 ], [ -72.196766730999911, 19.74249909100007 ], [ -72.180409308999913, 19.74087148600006 ], [ -72.14085852799991, 19.747463283000059 ], [ -72.137440558999913, 19.747219143000052 ], [ -72.131825324999909, 19.745835679000038 ], [ -72.124908006999931, 19.741441148000035 ], [ -72.110503709999932, 19.727687893000052 ], [ -72.100819464999915, 19.724798895000049 ], [ -72.066314256999931, 19.724798895000049 ], [ -72.058216925999943, 19.722642320000091 ], [ -72.053781704999949, 19.717962958000044 ], [ -72.050607876999948, 19.713283596000053 ], [ -72.047915174375632, 19.712042611329856 ], [ -72.052728238017778, 19.702621975523755 ], [ -72.056526455431538, 19.695077215740923 ], [ -72.060996467313089, 19.656526598124003 ], [ -72.082338832770915, 19.626864324728786 ], [ -72.098384365845789, 19.623660387416919 ], [ -72.110502489398357, 19.616115628533407 ], [ -72.109779018986501, 19.602369697003894 ], [ -72.113706427609543, 19.589657294248696 ], [ -72.110735033395088, 19.566144517555415 ], [ -72.097273321806369, 19.542528388074629 ], [ -72.087041388649141, 19.512969469265556 ], [ -72.069988166120936, 19.486924547030185 ], [ -72.073088752443937, 19.460414536801409 ], [ -72.08301062723865, 19.445686754240285 ], [ -72.064613816674296, 19.440932522417938 ], [ -72.045958624590867, 19.435764879445628 ], [ -71.995522427418052, 19.387344062078796 ], [ -71.978882616039868, 19.335770982444842 ], [ -72.050919561988167, 19.30088939103257 ], [ -72.120062628987114, 19.260065009392633 ], [ -72.1394671290048, 19.258308010206463 ], [ -72.148639695865256, 19.271382148167561 ], [ -72.170550503003312, 19.292104396900356 ], [ -72.200057745868264, 19.301922918907565 ], [ -72.210522223921487, 19.328846340286361 ], [ -72.227213711243792, 19.357268378432877 ], [ -72.231967943066081, 19.385742092523515 ], [ -72.226800300093771, 19.413440660258232 ], [ -72.243620977725925, 19.449149074869865 ], [ -72.28379940511843, 19.467804266953351 ], [ -72.32237586115707, 19.501652330490629 ], [ -72.327207608244521, 19.565162664725165 ], [ -72.346457078631261, 19.574464422794847 ], [ -72.361029833360135, 19.58149241774089 ], [ -72.378186407776468, 19.580045477816554 ], [ -72.396634894284944, 19.56335399049425 ], [ -72.416530320717698, 19.563974107219281 ], [ -72.416633674404522, 19.538084215514118 ], [ -72.446657681207, 19.528989163019446 ], [ -72.482391934240354, 19.543045152012155 ], [ -72.512648485039563, 19.566092840712031 ], [ -72.54034705277428, 19.591931057372392 ], [ -72.556831835420837, 19.632652086224766 ], [ -72.570603603573431, 19.672442939090331 ], [ -72.594788173835127, 19.682261461097539 ], [ -72.607268032593595, 19.699418036413249 ], [ -72.597862921736464, 19.733214423107142 ], [ -72.618714361678428, 19.74778717693664 ], [ -72.640289272931568, 19.744996649875475 ], [ -72.643183152780239, 19.767320868163495 ], [ -72.663724535259064, 19.782565416460784 ], [ -72.675584276393238, 19.80674998582316 ], [ -72.675842657912312, 19.812796128838272 ], [ -72.672535366014301, 19.824785061181615 ], [ -72.658582729809098, 19.82835073549802 ], [ -72.642563036055265, 19.824423325975715 ], [ -72.632692837204672, 19.818480535748108 ], [ -72.622125007263264, 19.817240302298103 ], [ -72.609025030880446, 19.828092353079626 ], [ -72.597862921736464, 19.838014227874282 ], [ -72.589568854019376, 19.844112046833459 ], [ -72.583160976697684, 19.856204331964307 ], [ -72.573239101903027, 19.870260321856335 ], [ -72.565176999019286, 19.875720913589248 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HT-AR", "NAME_1": "L'Artibonite" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -72.7060447007661, 18.944241285750444 ], [ -72.708729620999918, 18.945542710000041 ], [ -72.813547329999949, 19.052923895000049 ], [ -72.818348761999914, 19.078558661000045 ], [ -72.77603105399993, 19.094794012000079 ], [ -72.737660285999937, 19.097235419000071 ], [ -72.716460740999935, 19.103949286000045 ], [ -72.707183397999927, 19.118638414000088 ], [ -72.71312415299991, 19.13743724200009 ], [ -72.727691209999932, 19.14720286700009 ], [ -72.745838995999918, 19.153794664000088 ], [ -72.762440558999913, 19.163072007000039 ], [ -72.773019985999952, 19.175767320000091 ], [ -72.797027147999927, 19.216009833000044 ], [ -72.80337480399993, 19.231919664000088 ], [ -72.796538865999935, 19.236558335000041 ], [ -72.795765753999945, 19.238348700000074 ], [ -72.796864386999914, 19.240301825000074 ], [ -72.795969204999949, 19.245591539000088 ], [ -72.786203579999949, 19.254299221000053 ], [ -72.775217251999948, 19.277329820000091 ], [ -72.768625454999949, 19.28656647300005 ], [ -72.757679816999939, 19.291693427000041 ], [ -72.741810675999943, 19.294663804000038 ], [ -72.725697394999941, 19.295314846000053 ], [ -72.713978644999941, 19.293402411000045 ], [ -72.728342251999948, 19.320379950000074 ], [ -72.738677537999934, 19.325873114000046 ], [ -72.758697068999936, 19.32758209800005 ], [ -72.770578579999949, 19.336167710000041 ], [ -72.774484829999949, 19.355698960000041 ], [ -72.772938605999911, 19.376450914000088 ], [ -72.768625454999949, 19.38898346600007 ], [ -72.762318488999938, 19.382757880000042 ], [ -72.753977016999897, 19.377346096000053 ], [ -72.74437415299991, 19.37445709800005 ], [ -72.734486456999946, 19.375921942000048 ], [ -72.723459438999953, 19.383490302000041 ], [ -72.72288977799991, 19.390814520000049 ], [ -72.726429816999939, 19.39907461100006 ], [ -72.728098110999952, 19.422064520000049 ], [ -72.730620897999927, 19.42641836100006 ], [ -72.728342251999948, 19.425604559000078 ], [ -72.713978644999941, 19.423163153000075 ], [ -72.708973761999914, 19.420152085000041 ], [ -72.701975063999953, 19.414496161000045 ], [ -72.692372199999909, 19.409735419000071 ], [ -72.679839647999927, 19.409491278000075 ], [ -72.699126756999931, 19.445868231000077 ], [ -72.70921790299991, 19.451239325000074 ], [ -72.760894334999932, 19.454331773000035 ], [ -72.773996548999946, 19.463364976000037 ], [ -72.782785610999952, 19.476711330000057 ], [ -72.795969204999949, 19.492010809000078 ], [ -72.81476803299995, 19.504828192000048 ], [ -72.878488735999952, 19.532375393000052 ], [ -72.931548631999931, 19.563462632000039 ], [ -72.950510219999899, 19.567775783000059 ], [ -72.966908331999946, 19.575018622000073 ], [ -73.00218665299991, 19.603461005000042 ], [ -73.008859829999949, 19.604966539000088 ], [ -73.018869594999899, 19.600734768000052 ], [ -73.080799933999913, 19.622381903000075 ], [ -73.091053839999915, 19.623480536000045 ], [ -73.110747850999928, 19.628119208000044 ], [ -73.120799824652181, 19.62909590874915 ], [ -73.121810268728893, 19.631773587081341 ], [ -73.113826260273697, 19.686395575295535 ], [ -73.066774867566096, 19.733266099950526 ], [ -73.028224249949176, 19.736831773367612 ], [ -72.987916633146085, 19.727426663409744 ], [ -72.946627162613424, 19.724222724299295 ], [ -72.905776944350464, 19.717039699722363 ], [ -72.830303514395666, 19.729597072846616 ], [ -72.768162603921041, 19.779826565343683 ], [ -72.747181972769795, 19.78499420831605 ], [ -72.730542162290931, 19.794089259911402 ], [ -72.705995855924016, 19.810780748133027 ], [ -72.675584276393238, 19.80674998582316 ], [ -72.663724535259064, 19.782565416460784 ], [ -72.643183152780239, 19.767320868163495 ], [ -72.640289272931568, 19.744996649875475 ], [ -72.618714361678428, 19.74778717693664 ], [ -72.597862921736464, 19.733214423107142 ], [ -72.607268032593595, 19.699418036413249 ], [ -72.594788173835127, 19.682261461097539 ], [ -72.570603603573431, 19.672442939090331 ], [ -72.556831835420837, 19.632652086224766 ], [ -72.54034705277428, 19.591931057372392 ], [ -72.512648485039563, 19.566092840712031 ], [ -72.482391934240354, 19.543045152012155 ], [ -72.446657681207, 19.528989163019446 ], [ -72.416633674404522, 19.538084215514118 ], [ -72.416530320717698, 19.563974107219281 ], [ -72.396634894284944, 19.56335399049425 ], [ -72.378186407776468, 19.580045477816554 ], [ -72.361029833360135, 19.58149241774089 ], [ -72.346457078631261, 19.574464422794847 ], [ -72.327207608244521, 19.565162664725165 ], [ -72.32237586115707, 19.501652330490629 ], [ -72.28379940511843, 19.467804266953351 ], [ -72.243620977725925, 19.449149074869865 ], [ -72.226800300093771, 19.413440660258232 ], [ -72.231967943066081, 19.385742092523515 ], [ -72.227213711243792, 19.357268378432877 ], [ -72.210522223921487, 19.328846340286361 ], [ -72.200057745868264, 19.301922918907565 ], [ -72.245868903327221, 19.240893053371678 ], [ -72.251579148658777, 19.168494371318161 ], [ -72.224707404123365, 19.143069565807821 ], [ -72.234060838137168, 19.121778876294115 ], [ -72.231890427800977, 19.097490953244858 ], [ -72.225120816172705, 19.067880356693081 ], [ -72.238892585224619, 19.017082424314424 ], [ -72.232794766265442, 18.96705963829163 ], [ -72.229926723939172, 18.940549628062854 ], [ -72.243672654569366, 18.908045152561726 ], [ -72.247445033561462, 18.877142645716503 ], [ -72.270957811154062, 18.864430242961305 ], [ -72.318396775690644, 18.869701238721177 ], [ -72.365189785080531, 18.867014065346837 ], [ -72.388625047408027, 18.889958401259207 ], [ -72.415548468786767, 18.908665269286757 ], [ -72.441955126228095, 18.918793850555744 ], [ -72.466914841946391, 18.929025783712916 ], [ -72.476940070427872, 18.944425360741775 ], [ -72.487740445265331, 18.958894761783824 ], [ -72.512493456307936, 18.957809557065389 ], [ -72.536006232101897, 18.960393378551544 ], [ -72.611531338000816, 18.970573634865332 ], [ -72.675274217131403, 18.972847397989028 ], [ -72.692017381297092, 18.961168524907464 ], [ -72.7060447007661, 18.944241285750444 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HT-NI", "NAME_1": "Nippes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -73.739352953478388, 18.543810558507932 ], [ -73.729237433999913, 18.550930080000057 ], [ -73.725087042999917, 18.552923895000049 ], [ -73.723866339999915, 18.55532461100006 ], [ -73.71117102799991, 18.570257880000042 ], [ -73.704457160999937, 18.573472398000092 ], [ -73.696522589999915, 18.573797919000071 ], [ -73.688303188999953, 18.573146877000056 ], [ -73.680409308999913, 18.573431708000044 ], [ -73.63508053299995, 18.585923570000091 ], [ -73.622059699999909, 18.587632554000038 ], [ -73.586415167999917, 18.579169012000079 ], [ -73.585845506999931, 18.561997789000088 ], [ -73.60610917899993, 18.549017645000049 ], [ -73.632639126999948, 18.552923895000049 ], [ -73.632639126999948, 18.546698309000078 ], [ -73.654204881999931, 18.553615627000056 ], [ -73.673451300999943, 18.55609772300005 ], [ -73.692779100999928, 18.554022528000075 ], [ -73.714588995999918, 18.546698309000078 ], [ -73.707997199999909, 18.54242584800005 ], [ -73.691395636999914, 18.534002997000073 ], [ -73.674916144999941, 18.530178127000056 ], [ -73.673817511999914, 18.524318752000056 ], [ -73.674224412999934, 18.516669012000079 ], [ -73.669829881999931, 18.508856512000079 ], [ -73.652211066999939, 18.501369533000059 ], [ -73.620432094999899, 18.505764065000051 ], [ -73.604725714999915, 18.498277085000041 ], [ -73.569650844999899, 18.518377997000073 ], [ -73.526682094999899, 18.523504950000074 ], [ -73.368519660999937, 18.511948960000041 ], [ -73.34829667899993, 18.507635809000078 ], [ -73.308461066999939, 18.488348700000074 ], [ -73.286244269999941, 18.484035549000055 ], [ -73.206125454999949, 18.486802476000037 ], [ -73.166981574999909, 18.483547268000052 ], [ -73.131703253999945, 18.47101471600007 ], [ -73.113148566999939, 18.460760809000078 ], [ -73.098011847999942, 18.455267645000049 ], [ -73.081166144999941, 18.454169012000079 ], [ -73.055945009354673, 18.45845306255876 ], [ -73.05023840987468, 18.447298082340637 ], [ -73.049747484358932, 18.435205797209733 ], [ -73.06527625169764, 18.410246079692797 ], [ -73.063028326995664, 18.383374335157441 ], [ -73.038042771956327, 18.382392483226511 ], [ -73.020757005431449, 18.365804347792391 ], [ -73.013393113701227, 18.34151642474319 ], [ -72.997735155153293, 18.322757879872256 ], [ -73.001688402197999, 18.293095608275678 ], [ -73.014504156841326, 18.264828599760051 ], [ -73.014426643374861, 18.242866115778611 ], [ -73.012462937714417, 18.220903631797171 ], [ -73.037939419168822, 18.254028224922649 ], [ -73.046000942889179, 18.297488104892125 ], [ -73.077936977609397, 18.325755113407752 ], [ -73.115867479400663, 18.355107327541134 ], [ -73.140077888084079, 18.361515203963449 ], [ -73.162841355943783, 18.355003973854309 ], [ -73.188111130923915, 18.357742824971353 ], [ -73.214336921211952, 18.360740058506906 ], [ -73.2672794264044, 18.359758206575975 ], [ -73.319343430654783, 18.366631170991752 ], [ -73.350607672705905, 18.354487209916783 ], [ -73.386496955370205, 18.345598862997122 ], [ -73.418071254884467, 18.346632391771436 ], [ -73.449619716876441, 18.343738511922766 ], [ -73.513362596006971, 18.334023341803743 ], [ -73.56405717559818, 18.346270657464856 ], [ -73.554083624859402, 18.367819729396956 ], [ -73.545117763573899, 18.385079657500171 ], [ -73.567441982761295, 18.395828355494189 ], [ -73.581885546280944, 18.412778225234888 ], [ -73.599403855903233, 18.427040919802607 ], [ -73.626663174066209, 18.429314683825567 ], [ -73.658754239316693, 18.425077215940746 ], [ -73.681440191911292, 18.406990465537547 ], [ -73.698364224129648, 18.412261461297362 ], [ -73.718440517715692, 18.42187327683024 ], [ -73.751590949262891, 18.420426336905905 ], [ -73.784043748819954, 18.424715480734847 ], [ -73.766008674360819, 18.46331777609447 ], [ -73.743710292695823, 18.487192287993707 ], [ -73.760169236920717, 18.494530341302209 ], [ -73.765052659952289, 18.508482978406732 ], [ -73.74771521658397, 18.527293199221731 ], [ -73.739395311344538, 18.543726305024961 ], [ -73.739352953478388, 18.543810558507932 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/honduras.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/honduras.geojson new file mode 100644 index 0000000000000..921c5d956b1df --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/honduras.geojson @@ -0,0 +1,24 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "HN-OC", "NAME_1": "Ocotepeque" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.346206290288023, 14.413075726263742 ], [ -89.36162084999998, 14.415477804000062 ], [ -89.363791259999886, 14.44656117800011 ], [ -89.361982584999879, 14.462400004000102 ], [ -89.355497192999934, 14.475448303000064 ], [ -89.345265258999945, 14.481959534000026 ], [ -89.323044392999918, 14.487463074000118 ], [ -89.31480200199988, 14.495963847000041 ], [ -89.304854288999962, 14.513352966000056 ], [ -89.290927489999973, 14.528003235000128 ], [ -89.259611571999869, 14.554254862000064 ], [ -89.250542358999894, 14.565184428000038 ], [ -89.245684774999887, 14.572987570000066 ], [ -89.238114176999915, 14.577948507000102 ], [ -89.221086791999909, 14.580093079000093 ], [ -89.208813639999875, 14.577948507000102 ], [ -89.183698893999946, 14.569525248000019 ], [ -89.172149210999919, 14.570403747000057 ], [ -89.16039282299991, 14.581281637000103 ], [ -89.155741943999942, 14.59784393400011 ], [ -89.155225179999917, 14.615594788000038 ], [ -89.159410970999943, 14.665979309000122 ], [ -89.155845295999967, 14.672257995000038 ], [ -89.145225789999898, 14.683445943000066 ], [ -89.142693644999895, 14.691274923 ], [ -89.144502319999901, 14.708302308000029 ], [ -89.14621323435324, 14.710857663850106 ], [ -89.13103980174543, 14.715071113541057 ], [ -89.098664516554152, 14.724476223498925 ], [ -89.08556454107071, 14.728920396059436 ], [ -89.02564571777566, 14.720807197294278 ], [ -89.010271980067785, 14.699981593975394 ], [ -89.00308895459159, 14.669854234385411 ], [ -88.994562343777147, 14.655643214862437 ], [ -88.930561083127486, 14.608565986431131 ], [ -88.92425655769398, 14.594871730845682 ], [ -88.924824999374209, 14.568723455822806 ], [ -88.923223028919608, 14.561282049726799 ], [ -88.909916347861156, 14.540869859356519 ], [ -88.892656419757941, 14.523248196047405 ], [ -88.874802211552776, 14.515910141839584 ], [ -88.861211310553529, 14.512551173997451 ], [ -88.849196539788466, 14.502680976046179 ], [ -88.836820034716823, 14.500303860135034 ], [ -88.826665615925435, 14.50330109277121 ], [ -88.824030117595839, 14.50500641511394 ], [ -88.82483110237348, 14.508313707011951 ], [ -88.827208218284625, 14.511414293334951 ], [ -88.827621630333965, 14.515496730689563 ], [ -88.827724982222151, 14.527433987088841 ], [ -88.824340175958355, 14.535185452446683 ], [ -88.817079637015638, 14.539991360213094 ], [ -88.800594855268344, 14.545985826384765 ], [ -88.790983038836146, 14.54856964787092 ], [ -88.781810471975689, 14.550016587795255 ], [ -88.773774786677052, 14.54991323500775 ], [ -88.754318609815982, 14.546760972740685 ], [ -88.730521613181907, 14.54877635344593 ], [ -88.721297370377329, 14.545262355972909 ], [ -88.718687709570133, 14.543350328055169 ], [ -88.715328741728058, 14.528054103813815 ], [ -88.741399502385093, 14.453795070685942 ], [ -88.743750779874574, 14.442167874447819 ], [ -88.74713558613837, 14.438085435294568 ], [ -88.752690802738357, 14.433227851584093 ], [ -88.760648972771833, 14.428783678124205 ], [ -88.789587774855931, 14.419378567267074 ], [ -88.810749274059731, 14.42237579990325 ], [ -88.817389696277417, 14.426871650206465 ], [ -88.819456752926783, 14.42656159094463 ], [ -88.820877855328717, 14.424236151876869 ], [ -88.823177455974815, 14.414934393807187 ], [ -88.82348751523665, 14.408009752548026 ], [ -88.822970751299124, 14.403152167038854 ], [ -88.810645922171545, 14.386822414922506 ], [ -88.836406622667482, 14.386357326929101 ], [ -88.847852952651635, 14.391421617113906 ], [ -88.853278978042397, 14.396537584142152 ], [ -88.862864956052874, 14.40769969328619 ], [ -88.870099656573871, 14.407803046073695 ], [ -88.875629034752137, 14.405891018155955 ], [ -88.877954474719218, 14.396124172092868 ], [ -88.879194709068543, 14.383153387818595 ], [ -88.885499233602729, 14.369252428456775 ], [ -88.890666876575096, 14.360777492687134 ], [ -88.923403896972275, 14.345998033282569 ], [ -88.939397753203707, 14.344241034096456 ], [ -88.945960660156345, 14.339796861535945 ], [ -88.952110155059586, 14.332872219377407 ], [ -88.960765957083254, 14.319229641534719 ], [ -88.96683793762071, 14.312615057738697 ], [ -88.973891770988416, 14.306775621197971 ], [ -88.977870855555523, 14.301401271751274 ], [ -88.978878546807493, 14.293804836024322 ], [ -88.971204596714756, 14.269310208299487 ], [ -88.969060024800285, 14.236960761529929 ], [ -88.970228476163243, 14.210176262024845 ], [ -88.970791991999903, 14.214844056000047 ], [ -88.974564371999918, 14.227375590000051 ], [ -88.983530232999868, 14.242129211000062 ], [ -88.992754475999874, 14.252955424000106 ], [ -89.018127604999876, 14.27168813100009 ], [ -89.02262345399987, 14.28065399200004 ], [ -89.026602539999942, 14.311298117000149 ], [ -89.032984578999901, 14.323674622000027 ], [ -89.048978434999924, 14.331451925000039 ], [ -89.083084879999916, 14.335327657000079 ], [ -89.094479532999912, 14.34486195900007 ], [ -89.090552123999942, 14.354706320000048 ], [ -89.089673624999904, 14.364886577000021 ], [ -89.091844035999884, 14.374834290000109 ], [ -89.096830810999847, 14.384006856000013 ], [ -89.10256689499991, 14.391525777000055 ], [ -89.107476155999933, 14.395969951000069 ], [ -89.113341430999924, 14.397055156000064 ], [ -89.122178100999918, 14.394678040000102 ], [ -89.130110432999885, 14.38674570700006 ], [ -89.144502319999901, 14.35971893300011 ], [ -89.153984944999962, 14.351295675000117 ], [ -89.200157836999921, 14.36467987000006 ], [ -89.225530965999923, 14.382146505 ], [ -89.276535604999964, 14.392740173000078 ], [ -89.30756730199991, 14.407054546000069 ], [ -89.346206290288023, 14.413075726263742 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-LE", "NAME_1": "Lempira" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.957175252999889, 14.18518178300009 ], [ -88.965986083999979, 14.19138295500008 ], [ -88.969241699999969, 14.202002462000067 ], [ -88.970228476163243, 14.210176262024845 ], [ -88.969060024800285, 14.236960761529929 ], [ -88.971204596714756, 14.269310208299487 ], [ -88.978878546807493, 14.293804836024322 ], [ -88.977870855555523, 14.301401271751274 ], [ -88.973891770988416, 14.306775621197971 ], [ -88.96683793762071, 14.312615057738697 ], [ -88.960765957083254, 14.319229641534719 ], [ -88.952110155059586, 14.332872219377407 ], [ -88.945960660156345, 14.339796861535945 ], [ -88.939397753203707, 14.344241034096456 ], [ -88.923403896972275, 14.345998033282569 ], [ -88.890666876575096, 14.360777492687134 ], [ -88.885499233602729, 14.369252428456775 ], [ -88.879194709068543, 14.383153387818595 ], [ -88.877954474719218, 14.396124172092868 ], [ -88.875629034752137, 14.405891018155955 ], [ -88.870099656573871, 14.407803046073695 ], [ -88.862864956052874, 14.40769969328619 ], [ -88.853278978042397, 14.396537584142152 ], [ -88.847852952651635, 14.391421617113906 ], [ -88.836406622667482, 14.386357326929101 ], [ -88.810645922171545, 14.386822414922506 ], [ -88.822970751299124, 14.403152167038854 ], [ -88.82348751523665, 14.408009752548026 ], [ -88.823177455974815, 14.414934393807187 ], [ -88.820877855328717, 14.424236151876869 ], [ -88.819456752926783, 14.42656159094463 ], [ -88.817389696277417, 14.426871650206465 ], [ -88.810749274059731, 14.42237579990325 ], [ -88.789587774855931, 14.419378567267074 ], [ -88.760648972771833, 14.428783678124205 ], [ -88.752690802738357, 14.433227851584093 ], [ -88.74713558613837, 14.438085435294568 ], [ -88.743750779874574, 14.442167874447819 ], [ -88.741399502385093, 14.453795070685942 ], [ -88.715328741728058, 14.528054103813815 ], [ -88.718687709570133, 14.543350328055169 ], [ -88.721297370377329, 14.545262355972909 ], [ -88.730521613181907, 14.54877635344593 ], [ -88.733596361083187, 14.609237779100226 ], [ -88.745559455004809, 14.630270087094857 ], [ -88.752768317104142, 14.640760403569743 ], [ -88.783283251221064, 14.668975735241986 ], [ -88.794109462681547, 14.694452215797128 ], [ -88.794703741884177, 14.698586330894443 ], [ -88.792843390809821, 14.713520819929897 ], [ -88.778089768927657, 14.718223374908803 ], [ -88.728196174114146, 14.712487291155526 ], [ -88.692048509031451, 14.715071113541057 ], [ -88.663729824571703, 14.723080960417974 ], [ -88.655900844848077, 14.723856105874574 ], [ -88.654970668861267, 14.729747219258741 ], [ -88.655513272119777, 14.735483303012018 ], [ -88.659776576627678, 14.753570055213856 ], [ -88.67006018842693, 14.775945950345317 ], [ -88.676803961633482, 14.787004705802531 ], [ -88.677811651986133, 14.801887518893864 ], [ -88.676313036117733, 14.815013332799083 ], [ -88.673832567419026, 14.823281562094394 ], [ -88.669543422690765, 14.830877996922027 ], [ -88.664117398199323, 14.835890611162768 ], [ -88.656856859256607, 14.844572252507419 ], [ -88.654815640129698, 14.84901642506793 ], [ -88.656624315259933, 14.859765123061948 ], [ -88.643317634201424, 14.869273585807321 ], [ -88.639286871891613, 14.895783596036097 ], [ -88.644609545394189, 14.927357896449735 ], [ -88.609262865089136, 14.937693183293732 ], [ -88.601692267783903, 14.941672267860838 ], [ -88.555105963969027, 14.934799303445061 ], [ -88.533220995252691, 14.878368639201312 ], [ -88.505625780305479, 14.834443671238432 ], [ -88.487306485006286, 14.811912747375402 ], [ -88.479632534913549, 14.814393215174732 ], [ -88.463716193047844, 14.827415676292389 ], [ -88.453587612678177, 14.843228665370589 ], [ -88.442347989168354, 14.853874010577101 ], [ -88.433640510301302, 14.854545803246197 ], [ -88.422400885892159, 14.849843248267291 ], [ -88.420230475555968, 14.847569485143595 ], [ -88.407776455219221, 14.830619615402895 ], [ -88.381033901893034, 14.831188056183805 ], [ -88.360518357835929, 14.819199123840463 ], [ -88.388837043194997, 14.772225247297285 ], [ -88.383049282598279, 14.765817369076331 ], [ -88.367003750422725, 14.739514065321828 ], [ -88.352508510959012, 14.731814276807427 ], [ -88.335739509270923, 14.729695543314676 ], [ -88.32336300329996, 14.731194159183076 ], [ -88.316800096347379, 14.719515286101569 ], [ -88.322277797682204, 14.688922838518181 ], [ -88.34377519367024, 14.654299627725607 ], [ -88.333879157297247, 14.636006170848077 ], [ -88.322510341678935, 14.573167629282636 ], [ -88.342224900958399, 14.538234361026923 ], [ -88.348064338398501, 14.519320787424363 ], [ -88.350053880682026, 14.507641913443535 ], [ -88.360492520313528, 14.491002102065352 ], [ -88.388036058417356, 14.476894436229259 ], [ -88.411574672633037, 14.473587144331248 ], [ -88.457049934207078, 14.474052232324652 ], [ -88.481544562831289, 14.466817531803656 ], [ -88.498236050153594, 14.456378892172097 ], [ -88.501465826786443, 14.448627427713632 ], [ -88.494618699893067, 14.407079576561216 ], [ -88.474723272560936, 14.38113800711335 ], [ -88.454259406246592, 14.363671373435125 ], [ -88.432374436630937, 14.360984198262145 ], [ -88.428834601635515, 14.357521876733188 ], [ -88.422375048369759, 14.348995265918745 ], [ -88.411729702263926, 14.299075833582833 ], [ -88.413409187084312, 14.280989081380994 ], [ -88.423046841038854, 14.260525214167274 ], [ -88.423925341081599, 14.253393866433782 ], [ -88.421496548327013, 14.2479161650989 ], [ -88.416742315605347, 14.244402166726616 ], [ -88.4112129383264, 14.241301581302935 ], [ -88.40467586889622, 14.238407701454264 ], [ -88.398578049937043, 14.234376939144397 ], [ -88.392712774974541, 14.231328030564157 ], [ -88.387984381573915, 14.229674384165492 ], [ -88.383979457685825, 14.229467677691161 ], [ -88.379121873975294, 14.230501207364796 ], [ -88.374031745368711, 14.230759588883927 ], [ -88.367804735200366, 14.230346177733907 ], [ -88.346100632738001, 14.22579865238589 ], [ -88.328168911066371, 14.215618394273463 ], [ -88.326541103988745, 14.20533478427285 ], [ -88.327910528647976, 14.201355698806424 ], [ -88.327936367969016, 14.191692206430162 ], [ -88.32832394069726, 14.187506415388725 ], [ -88.326773647985476, 14.166060696244131 ], [ -88.320055712301269, 14.122032376393065 ], [ -88.322277797682204, 14.107873032814211 ], [ -88.3256367664236, 14.105030828909605 ], [ -88.331011114970977, 14.099294745156328 ], [ -88.332561407682817, 14.094747218908992 ], [ -88.333517422091347, 14.088649399949816 ], [ -88.333517422091347, 14.080897935491294 ], [ -88.336204597264327, 14.076815497237419 ], [ -88.338995124325493, 14.075213528581457 ], [ -88.34377519367024, 14.074076646120318 ], [ -88.352999437374137, 14.070459295859791 ], [ -88.375297818139757, 14.050667223113862 ], [ -88.431211716647397, 14.018731187494268 ], [ -88.463509488372154, 14.004571844814791 ], [ -88.480149298851018, 13.992169501321428 ], [ -88.483043178699745, 13.98757029912997 ], [ -88.483766649111544, 13.984986476744496 ], [ -88.494928758255583, 13.970362046970877 ], [ -88.497085348999917, 13.969068092000015 ], [ -88.496505696999918, 13.969561870000106 ], [ -88.49619563899995, 13.971990662000067 ], [ -88.495420491999937, 13.97514292400011 ], [ -88.50436051499986, 13.983695374000135 ], [ -88.514049845999892, 13.987648621000119 ], [ -88.558104003999858, 13.990904236000105 ], [ -88.633861653999958, 14.014468689000097 ], [ -88.659338135999889, 14.016122335000148 ], [ -88.684814615999898, 14.012298279000021 ], [ -88.690938272999858, 14.009998678000088 ], [ -88.690811757999967, 14.011789871000062 ], [ -88.690447346999917, 14.016949157000084 ], [ -88.692695272999941, 14.025294902000056 ], [ -88.697656209999877, 14.032012838000071 ], [ -88.704865071999848, 14.038033142000103 ], [ -88.709515950999901, 14.039686788000054 ], [ -88.730961669999942, 14.042477316000117 ], [ -88.746645466999894, 14.052476705000032 ], [ -88.746077026999842, 14.066558533000062 ], [ -88.740056722999896, 14.083017477000041 ], [ -88.73922989999997, 14.099941508000128 ], [ -88.746387085999913, 14.111336162000029 ], [ -88.755120401999903, 14.110457662000087 ], [ -88.765429850999908, 14.104256490000097 ], [ -88.777341268999919, 14.099734802000071 ], [ -88.821188720999942, 14.102938741000045 ], [ -88.838758707999915, 14.100406596000056 ], [ -88.845321614999904, 14.128621928000115 ], [ -88.860333618999874, 14.158516744000053 ], [ -88.881262572999873, 14.184199931000123 ], [ -88.906015584999892, 14.199573670000092 ], [ -88.921647704999941, 14.199883728000088 ], [ -88.935626180999947, 14.194018453000083 ], [ -88.94748592199997, 14.187274679000055 ], [ -88.957175252999889, 14.18518178300009 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-IN", "NAME_1": "Intibucá" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.497900960999914, 13.968373311000079 ], [ -88.497085348999917, 13.969068092000015 ], [ -88.494928758255583, 13.970362046970877 ], [ -88.483766649111544, 13.984986476744496 ], [ -88.483043178699745, 13.98757029912997 ], [ -88.480149298851018, 13.992169501321428 ], [ -88.463509488372154, 14.004571844814791 ], [ -88.431211716647397, 14.018731187494268 ], [ -88.375297818139757, 14.050667223113862 ], [ -88.352999437374137, 14.070459295859791 ], [ -88.34377519367024, 14.074076646120318 ], [ -88.338995124325493, 14.075213528581457 ], [ -88.336204597264327, 14.076815497237419 ], [ -88.333517422091347, 14.080897935491294 ], [ -88.333517422091347, 14.088649399949816 ], [ -88.332561407682817, 14.094747218908992 ], [ -88.331011114970977, 14.099294745156328 ], [ -88.3256367664236, 14.105030828909605 ], [ -88.322277797682204, 14.107873032814211 ], [ -88.320055712301269, 14.122032376393065 ], [ -88.326773647985476, 14.166060696244131 ], [ -88.32832394069726, 14.187506415388725 ], [ -88.327936367969016, 14.191692206430162 ], [ -88.327910528647976, 14.201355698806424 ], [ -88.326541103988745, 14.20533478427285 ], [ -88.328168911066371, 14.215618394273463 ], [ -88.346100632738001, 14.22579865238589 ], [ -88.367804735200366, 14.230346177733907 ], [ -88.374031745368711, 14.230759588883927 ], [ -88.379121873975294, 14.230501207364796 ], [ -88.383979457685825, 14.229467677691161 ], [ -88.387984381573915, 14.229674384165492 ], [ -88.392712774974541, 14.231328030564157 ], [ -88.398578049937043, 14.234376939144397 ], [ -88.40467586889622, 14.238407701454264 ], [ -88.4112129383264, 14.241301581302935 ], [ -88.416742315605347, 14.244402166726616 ], [ -88.421496548327013, 14.2479161650989 ], [ -88.423925341081599, 14.253393866433782 ], [ -88.423046841038854, 14.260525214167274 ], [ -88.413409187084312, 14.280989081380994 ], [ -88.411729702263926, 14.299075833582833 ], [ -88.422375048369759, 14.348995265918745 ], [ -88.428834601635515, 14.357521876733188 ], [ -88.432374436630937, 14.360984198262145 ], [ -88.454259406246592, 14.363671373435125 ], [ -88.474723272560936, 14.38113800711335 ], [ -88.494618699893067, 14.407079576561216 ], [ -88.501465826786443, 14.448627427713632 ], [ -88.498236050153594, 14.456378892172097 ], [ -88.481544562831289, 14.466817531803656 ], [ -88.457049934207078, 14.474052232324652 ], [ -88.411574672633037, 14.473587144331248 ], [ -88.388036058417356, 14.476894436229259 ], [ -88.360492520313528, 14.491002102065352 ], [ -88.350053880682026, 14.507641913443535 ], [ -88.348064338398501, 14.519320787424363 ], [ -88.342224900958399, 14.538234361026923 ], [ -88.322510341678935, 14.573167629282636 ], [ -88.333879157297247, 14.636006170848077 ], [ -88.34377519367024, 14.654299627725607 ], [ -88.265950487125281, 14.64877025044666 ], [ -88.207452766232166, 14.654764715719068 ], [ -88.16321773990677, 14.658640448397932 ], [ -88.129628058787887, 14.652025865501287 ], [ -88.100430874285394, 14.649287014384186 ], [ -88.093351203395287, 14.654454657356553 ], [ -88.074954392830932, 14.664841620144614 ], [ -88.061311814988244, 14.64649648732302 ], [ -88.056144172015934, 14.64417104735594 ], [ -88.04622229722122, 14.641173813820444 ], [ -88.038729214281773, 14.640295315576338 ], [ -88.00420935717608, 14.631561998287566 ], [ -87.987337001801166, 14.619469713156718 ], [ -87.969146897711141, 14.613061834935706 ], [ -87.959767626174994, 14.600917873860794 ], [ -87.951602748767812, 14.585880032037835 ], [ -87.950646735258601, 14.582159328989803 ], [ -87.949639044906007, 14.571824042145806 ], [ -87.947365281782311, 14.56536448798073 ], [ -87.940983242882339, 14.553065497274872 ], [ -87.933257615946218, 14.546916002371574 ], [ -87.909021368841081, 14.535237128390747 ], [ -87.902691005885174, 14.530276190993391 ], [ -87.899047818102304, 14.525987047164506 ], [ -87.898763597262189, 14.515910141839584 ], [ -87.899745450092439, 14.506505031881716 ], [ -87.887937384902386, 14.495549628312688 ], [ -87.855820482129502, 14.455965481022133 ], [ -87.848224047301926, 14.441754462398478 ], [ -87.847784796830865, 14.438188788082073 ], [ -87.848146532036822, 14.435088201759072 ], [ -87.848999192758527, 14.432814439534752 ], [ -87.853107469434178, 14.42909373648672 ], [ -87.897652554122033, 14.397002672135613 ], [ -87.909589809621991, 14.390491441127097 ], [ -87.921992154014674, 14.38537547499817 ], [ -87.932482468690978, 14.385272122210665 ], [ -87.940363125257988, 14.386977444553395 ], [ -87.9471585762073, 14.389561266039607 ], [ -87.952067836761216, 14.389302882721836 ], [ -87.955142584662553, 14.383876858230394 ], [ -87.957390510263792, 14.370596014694286 ], [ -87.953308072009918, 14.340106919898403 ], [ -87.969405280129536, 14.310444648301882 ], [ -87.974702115210448, 14.30383006450586 ], [ -87.984313930743269, 14.297318834396663 ], [ -87.996225348720827, 14.292771308149327 ], [ -88.002349006101724, 14.287913723539475 ], [ -88.005863002675426, 14.275304674471158 ], [ -88.00519121000633, 14.267656561900822 ], [ -88.013459439301641, 14.253703924796298 ], [ -88.055420701604078, 14.252205308028522 ], [ -88.089733853134817, 14.224351711562235 ], [ -88.10596025336298, 14.208332016909026 ], [ -88.114641892908992, 14.187558092232166 ], [ -88.12291012220436, 14.176034246982908 ], [ -88.125648973321461, 14.173398749552632 ], [ -88.154381069830492, 14.159394436504044 ], [ -88.165233119712695, 14.149524238552772 ], [ -88.219674241672919, 14.090716458397821 ], [ -88.225952927785386, 14.085238756163676 ], [ -88.229621954889296, 14.086375636826176 ], [ -88.232231614797172, 14.083585109765011 ], [ -88.232205777274771, 14.078727525155159 ], [ -88.225694546266254, 14.068702297572941 ], [ -88.219312507366283, 14.0621910674638 ], [ -88.210294969237395, 14.043380845749425 ], [ -88.219157477735394, 13.993358058827312 ], [ -88.217736376232779, 13.990929266972103 ], [ -88.217658813303558, 13.990796705103833 ], [ -88.220062622999905, 13.991317647000116 ], [ -88.235074625999886, 13.992867941000043 ], [ -88.244893147999875, 13.989250591000058 ], [ -88.245358235999902, 13.98589162200004 ], [ -88.244376383999935, 13.966099548000059 ], [ -88.242309326999958, 13.962533875000091 ], [ -88.233369303999922, 13.954498190000024 ], [ -88.231586466999943, 13.951811015000075 ], [ -88.236366536999952, 13.938142599000074 ], [ -88.2427744149999, 13.936695658000076 ], [ -88.251636921999904, 13.938090922000058 ], [ -88.263600015999941, 13.93310414600009 ], [ -88.27016292299993, 13.926024475000077 ], [ -88.274170772999895, 13.919119724000055 ], [ -88.277526814999931, 13.913337911000028 ], [ -88.28543330899987, 13.905974019000027 ], [ -88.296311197999842, 13.902356669000142 ], [ -88.308429321999938, 13.901478170000104 ], [ -88.319255533999865, 13.89760243700006 ], [ -88.326206014999855, 13.885070903000056 ], [ -88.332613891999898, 13.887706401000059 ], [ -88.340572062999854, 13.890031840000091 ], [ -88.348556071999923, 13.891375427000057 ], [ -88.355067301999895, 13.890962016000046 ], [ -88.358193725999854, 13.887396343000077 ], [ -88.358917195999936, 13.881195170000098 ], [ -88.358917195999936, 13.87527821900008 ], [ -88.360105753999875, 13.872384338000103 ], [ -88.36741796899986, 13.873107809000089 ], [ -88.383360148999884, 13.879257304000063 ], [ -88.392946126999902, 13.879774068000103 ], [ -88.433227905999843, 13.871066590000041 ], [ -88.451443847999883, 13.863573507000098 ], [ -88.470150715999864, 13.852488912000098 ], [ -88.496815755342823, 13.851197002439676 ], [ -88.48800492399991, 13.865330506000078 ], [ -88.48867671699989, 13.881350200000043 ], [ -88.499502930999938, 13.907601827000065 ], [ -88.502293457999912, 13.917110291000057 ], [ -88.500226399999946, 13.931863912000068 ], [ -88.496815754999915, 13.944033712000063 ], [ -88.496092285999907, 13.955686747000129 ], [ -88.501198105999947, 13.966600438000029 ], [ -88.502293457999912, 13.968941752000134 ], [ -88.498182576999938, 13.968409755000081 ], [ -88.497900960999914, 13.968373311000079 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-LP", "NAME_1": "La Paz" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.177532918999958, 13.985193990000056 ], [ -88.193475097999908, 13.985555725000054 ], [ -88.217658813303558, 13.990796705103833 ], [ -88.217736376232779, 13.990929266972103 ], [ -88.219157477735394, 13.993358058827312 ], [ -88.210294969237395, 14.043380845749425 ], [ -88.219312507366283, 14.0621910674638 ], [ -88.225694546266254, 14.068702297572941 ], [ -88.232205777274771, 14.078727525155159 ], [ -88.232231614797172, 14.083585109765011 ], [ -88.229621954889296, 14.086375636826176 ], [ -88.225952927785386, 14.085238756163676 ], [ -88.219674241672919, 14.090716458397821 ], [ -88.165233119712695, 14.149524238552772 ], [ -88.154381069830492, 14.159394436504044 ], [ -88.125648973321461, 14.173398749552632 ], [ -88.12291012220436, 14.176034246982908 ], [ -88.114641892908992, 14.187558092232166 ], [ -88.10596025336298, 14.208332016909026 ], [ -88.089733853134817, 14.224351711562235 ], [ -88.055420701604078, 14.252205308028522 ], [ -88.013459439301641, 14.253703924796298 ], [ -88.00519121000633, 14.267656561900822 ], [ -88.005863002675426, 14.275304674471158 ], [ -88.002349006101724, 14.287913723539475 ], [ -87.996225348720827, 14.292771308149327 ], [ -87.984313930743269, 14.297318834396663 ], [ -87.974702115210448, 14.30383006450586 ], [ -87.969405280129536, 14.310444648301882 ], [ -87.953308072009918, 14.340106919898403 ], [ -87.957390510263792, 14.370596014694286 ], [ -87.955142584662553, 14.383876858230394 ], [ -87.952067836761216, 14.389302882721836 ], [ -87.9471585762073, 14.389561266039607 ], [ -87.940363125257988, 14.386977444553395 ], [ -87.932482468690978, 14.385272122210665 ], [ -87.921992154014674, 14.38537547499817 ], [ -87.909589809621991, 14.390491441127097 ], [ -87.897652554122033, 14.397002672135613 ], [ -87.853107469434178, 14.42909373648672 ], [ -87.842875536276949, 14.414314277082212 ], [ -87.829129604747436, 14.400361639977689 ], [ -87.789545458356201, 14.389871324402066 ], [ -87.788744472679241, 14.387855942797501 ], [ -87.779442714609559, 14.378347480052128 ], [ -87.776522997238487, 14.377210598490308 ], [ -87.746033902442605, 14.371267808262701 ], [ -87.735259366026924, 14.365635077296986 ], [ -87.714976365966493, 14.358503730462758 ], [ -87.70430518323758, 14.357728583207518 ], [ -87.696114468308053, 14.355454820083878 ], [ -87.651155971570802, 14.373438219498212 ], [ -87.646582607801065, 14.369820868338365 ], [ -87.634464484248554, 14.344189358152335 ], [ -87.631648118765668, 14.336386216850428 ], [ -87.62818579813603, 14.317059231198527 ], [ -87.634929572241958, 14.306362210047951 ], [ -87.626635505424247, 14.298559067846668 ], [ -87.629942797322201, 14.285639960415836 ], [ -87.639477097589975, 14.273702704016557 ], [ -87.644102139102415, 14.270395413017866 ], [ -87.652912970756972, 14.266933092388285 ], [ -87.668648443670747, 14.263625800490274 ], [ -87.68373796323641, 14.265692857139641 ], [ -87.696837937820533, 14.256081040707443 ], [ -87.706088019946151, 14.251740220934437 ], [ -87.727662930299971, 14.244143785207484 ], [ -87.740065273793334, 14.241198228515429 ], [ -87.755852423550493, 14.238976142235174 ], [ -87.775851202770752, 14.24062978773452 ], [ -87.813239102202772, 14.231689764870737 ], [ -87.819104377165274, 14.234066880781882 ], [ -87.820706345821179, 14.234170234468706 ], [ -87.82360022656917, 14.233653468732598 ], [ -87.825770636905361, 14.232206528808263 ], [ -87.828716192698096, 14.225281887549045 ], [ -87.825641445696135, 14.20554148984786 ], [ -87.791121588590443, 14.191382148067646 ], [ -87.777117276441118, 14.175362454313813 ], [ -87.782078212939155, 14.159652818023119 ], [ -87.784326137641131, 14.155622057511948 ], [ -87.785798915987186, 14.150557766427767 ], [ -87.784558681637805, 14.146682033748846 ], [ -87.780967169799055, 14.14311636033176 ], [ -87.764275681577431, 14.136915187685759 ], [ -87.754121262786043, 14.134951483823897 ], [ -87.742778285589395, 14.130662339994956 ], [ -87.731926235707192, 14.12440949140489 ], [ -87.714304572398078, 14.109785060731951 ], [ -87.703685064713966, 14.104204005710301 ], [ -87.696579556301458, 14.095160630958333 ], [ -87.690688442917292, 14.084773668170214 ], [ -87.689629075721257, 14.051028958319762 ], [ -87.663609991907606, 14.075730292518983 ], [ -87.650613369211612, 14.085032049689346 ], [ -87.615240852283478, 14.088494371218246 ], [ -87.596585660200049, 13.957287909009779 ], [ -87.598316820065179, 13.938167628932888 ], [ -87.6060424470013, 13.902924303214036 ], [ -87.608832974062466, 13.896206365731189 ], [ -87.611520148336183, 13.892175605220018 ], [ -87.619374965582153, 13.868817857258307 ], [ -87.647047695794527, 13.834194648264372 ], [ -87.668415899674017, 13.834194648264372 ], [ -87.692858853253483, 13.849904282756427 ], [ -87.734096646043383, 13.848405666888027 ], [ -87.749528722999912, 13.845627388000096 ], [ -87.765335855999865, 13.858870952000117 ], [ -87.771433674999912, 13.862126567000104 ], [ -87.785412150999917, 13.86739756200005 ], [ -87.790605631999938, 13.870472310000082 ], [ -87.798718831999935, 13.882332051000105 ], [ -87.808459839999898, 13.908635356000048 ], [ -87.817890787999943, 13.915870057000106 ], [ -87.832902791999913, 13.915249939000134 ], [ -87.842953857999959, 13.907110901000038 ], [ -87.851222087999901, 13.896878968000053 ], [ -87.860911417999944, 13.890186870000036 ], [ -87.87054907299995, 13.889566752000064 ], [ -87.890108602999959, 13.893545837000147 ], [ -87.900107991999874, 13.894140117000106 ], [ -87.907885294999886, 13.891530457000101 ], [ -87.920752725999904, 13.881866963000078 ], [ -87.925326090999931, 13.879619039000062 ], [ -87.932173217999889, 13.881556905000096 ], [ -87.946926839999918, 13.890910339000129 ], [ -87.952594894338858, 13.892029035511541 ], [ -87.954781656999842, 13.892460633000056 ], [ -87.969741984999899, 13.888533223000081 ], [ -88.015320597999903, 13.866364035000061 ], [ -88.023640502999854, 13.891168722000103 ], [ -88.039970255999975, 13.910133972000054 ], [ -88.058392903999902, 13.926489563000104 ], [ -88.072888143999933, 13.94341359500001 ], [ -88.087538411999901, 13.980543112000092 ], [ -88.09903641799994, 13.98981903100011 ], [ -88.125391397999891, 13.991265971000104 ], [ -88.177532918999958, 13.985193990000056 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-VA", "NAME_1": "Valle" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -87.769159911999907, 13.506360168000057 ], [ -87.779469360999911, 13.509977519000131 ], [ -87.789933838999843, 13.53281850200004 ], [ -87.784068563999938, 13.560465394000047 ], [ -87.760090698999932, 13.616947734000092 ], [ -87.757816935999926, 13.635163676000047 ], [ -87.758643757999948, 13.672267355000116 ], [ -87.755026407999964, 13.689914857000119 ], [ -87.746318929999887, 13.702188009000054 ], [ -87.73629370099988, 13.711463929000075 ], [ -87.731358602999933, 13.72221262700009 ], [ -87.737843993999888, 13.738774923000094 ], [ -87.732805541999937, 13.75510467600013 ], [ -87.712625895999849, 13.800450745000148 ], [ -87.703608357999883, 13.814997661000106 ], [ -87.721204183999873, 13.821896464000076 ], [ -87.749528722999912, 13.845627388000096 ], [ -87.734096646043383, 13.848405666888027 ], [ -87.692858853253483, 13.849904282756427 ], [ -87.668415899674017, 13.834194648264372 ], [ -87.647047695794527, 13.834194648264372 ], [ -87.647280239791201, 13.804790758186925 ], [ -87.649398973283951, 13.761227525429945 ], [ -87.641854214400439, 13.749858709811576 ], [ -87.60102983276056, 13.722676906913705 ], [ -87.570308193967946, 13.716889146317044 ], [ -87.551988897769377, 13.71874949829072 ], [ -87.548397385930627, 13.717302558366384 ], [ -87.543694830951665, 13.714512030405842 ], [ -87.540749274259611, 13.710998032932878 ], [ -87.505144213334745, 13.684643053234311 ], [ -87.479021775834269, 13.668623359480421 ], [ -87.468789841777777, 13.665832831519936 ], [ -87.46114173010676, 13.670173652192261 ], [ -87.459126350300835, 13.667899889068622 ], [ -87.441504686092401, 13.653585516758199 ], [ -87.433055589643743, 13.649348048873321 ], [ -87.426260138694431, 13.644542141106911 ], [ -87.42181596613392, 13.637824205422703 ], [ -87.424373949198355, 13.598033352557138 ], [ -87.419800585428675, 13.590695299248637 ], [ -87.415718146275424, 13.582582099584215 ], [ -87.414555427191203, 13.575915838944809 ], [ -87.400266893302444, 13.545530096936432 ], [ -87.364429286582265, 13.519381821913555 ], [ -87.367684903435531, 13.498814601912329 ], [ -87.366263801033597, 13.489512843842647 ], [ -87.360682746011889, 13.474475002019688 ], [ -87.349546475289571, 13.453339342136928 ], [ -87.347789476103401, 13.432978826811393 ], [ -87.358719042150085, 13.408484198187182 ], [ -87.37902787973286, 13.393291326733333 ], [ -87.379017706999946, 13.393133856000077 ], [ -87.393788214999915, 13.406439520000049 ], [ -87.40062415299991, 13.411159572000088 ], [ -87.409779425999943, 13.413031317000048 ], [ -87.429839647999927, 13.409369208000044 ], [ -87.437774217999902, 13.411037502000056 ], [ -87.447295701999906, 13.420477606000077 ], [ -87.464385545999903, 13.408270575000074 ], [ -87.469634568999936, 13.40298086100006 ], [ -87.474598761999914, 13.393133856000077 ], [ -87.476429816999939, 13.379706122000073 ], [ -87.473052537999934, 13.372463283000059 ], [ -87.472279425999943, 13.367010809000078 ], [ -87.482045050999943, 13.359035549000055 ], [ -87.488270636999914, 13.358303127000056 ], [ -87.522979295999903, 13.359035549000055 ], [ -87.538604295999903, 13.355292059000078 ], [ -87.547596808999913, 13.35500722900008 ], [ -87.557158982999908, 13.359035549000055 ], [ -87.557158982999908, 13.36587148600006 ], [ -87.542836066999939, 13.36587148600006 ], [ -87.542836066999939, 13.372015692000048 ], [ -87.561797654999907, 13.376003322000088 ], [ -87.581328904999907, 13.382879950000074 ], [ -87.598866339999915, 13.384344794000071 ], [ -87.611805792999917, 13.372015692000048 ], [ -87.618560350999928, 13.372015692000048 ], [ -87.616729295999903, 13.381862697000088 ], [ -87.605580206999946, 13.406805731000077 ], [ -87.619252081999946, 13.412014065000051 ], [ -87.622425910999937, 13.423000393000052 ], [ -87.618560350999928, 13.451198635000083 ], [ -87.624012824999909, 13.46625397300005 ], [ -87.636463995999918, 13.463690497000073 ], [ -87.650380011999914, 13.452297268000052 ], [ -87.660145636999914, 13.44094472900008 ], [ -87.650990363999938, 13.412543036000045 ], [ -87.665679490999935, 13.386013088000084 ], [ -87.692779100999928, 13.366481838000084 ], [ -87.720977342999902, 13.359035549000055 ], [ -87.738880988999938, 13.362372137000079 ], [ -87.762237107999908, 13.376369533000059 ], [ -87.781361456999946, 13.382595119000086 ], [ -87.782948370999918, 13.389431057000081 ], [ -87.782948370999918, 13.396266994000086 ], [ -87.786488410999937, 13.399359442000048 ], [ -87.796254035999937, 13.39984772300005 ], [ -87.803008592999902, 13.401393947000088 ], [ -87.817168748999904, 13.40656159100007 ], [ -87.738412434999958, 13.441687113000071 ], [ -87.721152506999942, 13.460833232000084 ], [ -87.718801228999922, 13.473674825000074 ], [ -87.720584065999901, 13.486981507000081 ], [ -87.725725871999913, 13.498970439000047 ], [ -87.733425659999909, 13.507703756000112 ], [ -87.747972574999949, 13.513233135000107 ], [ -87.769159911999907, 13.506360168000057 ] ] ], [ [ [ -87.615142381999931, 13.290106512000079 ], [ -87.61196855399993, 13.282863674000055 ], [ -87.613880988999938, 13.267320054000038 ], [ -87.624338344999899, 13.252915757000039 ], [ -87.646555141999897, 13.249172268000052 ], [ -87.658558722999942, 13.250962632000039 ], [ -87.66274980399993, 13.252752997000073 ], [ -87.667062954999949, 13.256008205000057 ], [ -87.667062954999949, 13.262193101000037 ], [ -87.660145636999914, 13.262193101000037 ], [ -87.663970506999931, 13.267482815000051 ], [ -87.670033331999946, 13.278550523000092 ], [ -87.673817511999914, 13.283880927000041 ], [ -87.657622850999928, 13.289129950000074 ], [ -87.64484615799995, 13.290838934000078 ], [ -87.615142381999931, 13.290106512000079 ] ] ], [ [ [ -87.622303839999915, 13.368882554000038 ], [ -87.612416144999941, 13.366034247000073 ], [ -87.585438605999911, 13.37173086100006 ], [ -87.570790167999917, 13.372015692000048 ], [ -87.570790167999917, 13.36587148600006 ], [ -87.58812415299991, 13.357977606000077 ], [ -87.576283331999946, 13.318548895000049 ], [ -87.591297980999911, 13.304388739000046 ], [ -87.637562628999945, 13.319159247000073 ], [ -87.659006313999896, 13.331691799000055 ], [ -87.65648352799991, 13.34906647300005 ], [ -87.643462693999936, 13.367743231000077 ], [ -87.634429490999935, 13.373480536000045 ], [ -87.622303839999915, 13.368882554000038 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-OL", "NAME_1": "Olancho" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -84.999948289999907, 14.742015988000105 ], [ -85.001990316999951, 14.740677592000026 ], [ -85.015658732999867, 14.728171896000035 ], [ -85.024547078999973, 14.712539775000081 ], [ -85.029792236999896, 14.675539449000027 ], [ -85.033047851999896, 14.669570821 ], [ -85.038215494999889, 14.667219544000062 ], [ -85.053925130999858, 14.66305959100012 ], [ -85.048524943999979, 14.653318583000086 ], [ -85.020206257999888, 14.633733215000063 ], [ -85.042220418999875, 14.61347605400006 ], [ -85.048163207999892, 14.605776266000063 ], [ -85.022221639999941, 14.605802104000077 ], [ -85.02365718199988, 14.602540872000063 ], [ -85.029637206999951, 14.5889555870001 ], [ -85.065242268999839, 14.554254862000064 ], [ -85.086377929999884, 14.544539693000033 ], [ -85.103353637999902, 14.556864522000083 ], [ -85.119321655999926, 14.573969422000033 ], [ -85.13753759899987, 14.578491109000055 ], [ -85.145469929999933, 14.564254252000083 ], [ -85.149810750999904, 14.536504008000051 ], [ -85.15182613199994, 14.485964457000108 ], [ -85.155391805999926, 14.479479065000049 ], [ -85.178491170999905, 14.455604553000072 ], [ -85.179679728999929, 14.449248352000041 ], [ -85.177354288999908, 14.433977966000086 ], [ -85.178491170999905, 14.427647603000068 ], [ -85.205828002999937, 14.407157899000097 ], [ -85.189730794999946, 14.396848450000093 ], [ -85.171876587999918, 14.381009623000097 ], [ -85.15903499399991, 14.361062520000075 ], [ -85.158027302999926, 14.338273214000083 ], [ -85.169628662999884, 14.321762594000091 ], [ -85.190195882999973, 14.309644470000109 ], [ -85.215207274999869, 14.301582947000028 ], [ -85.239960286999917, 14.297319641000058 ], [ -85.277813273999897, 14.297319641000058 ], [ -85.288200236999899, 14.295149231000067 ], [ -85.311971394999972, 14.283651225000142 ], [ -85.321350666999905, 14.28132578600011 ], [ -85.326828369999902, 14.275744731000088 ], [ -85.330884968999897, 14.26900095700006 ], [ -85.337964639999939, 14.260681050000102 ], [ -85.3408068439999, 14.253368836000021 ], [ -85.343623209999862, 14.250113221000035 ], [ -85.347809000999916, 14.249234721000093 ], [ -85.358531860999932, 14.250888367000044 ], [ -85.362872680999914, 14.250113221000035 ], [ -85.37251033599992, 14.241095683000083 ], [ -85.384008341999845, 14.226445414000096 ], [ -85.393620157999948, 14.210761617000045 ], [ -85.400880696999934, 14.18518178300009 ], [ -85.409123087999973, 14.166164856000123 ], [ -85.420156005999871, 14.146863708000083 ], [ -85.431731526999897, 14.132833557000069 ], [ -85.457621419999839, 14.113041483000089 ], [ -85.474674641999883, 14.103403829000072 ], [ -85.510641438999954, 14.093792013000055 ], [ -85.51640336199992, 14.080537008000064 ], [ -85.518625447999909, 14.064594828000025 ], [ -85.527953043999872, 14.050900574000096 ], [ -85.546634074999929, 14.044906108000077 ], [ -85.563145912999914, 14.042012281000098 ], [ -85.563273077690383, 14.042347316975111 ], [ -85.575649583661345, 14.074955146163063 ], [ -85.58014543306524, 14.079295965936069 ], [ -85.587793544736257, 14.085187079320235 ], [ -85.5959325828224, 14.089579575936682 ], [ -85.605802781672992, 14.097227688507019 ], [ -85.609704352773633, 14.104875800178036 ], [ -85.61140967511642, 14.114797674972692 ], [ -85.61140967511642, 14.126476548953576 ], [ -85.615492113370294, 14.147353827317261 ], [ -85.621564093907807, 14.159704494866503 ], [ -85.631279263127453, 14.170349840073072 ], [ -85.646911384153043, 14.183423977134851 ], [ -85.655437994967485, 14.186007799520326 ], [ -85.660295579577337, 14.18492259390257 ], [ -85.662155930651636, 14.177429510963123 ], [ -85.665230678552973, 14.176395982188808 ], [ -85.672129483189053, 14.177067775757223 ], [ -85.710111660025063, 14.188746649738107 ], [ -85.75747311109518, 14.198720201376204 ], [ -85.763725958785926, 14.197893378176843 ], [ -85.768015102614868, 14.193552558403837 ], [ -85.779771490961537, 14.170401516017137 ], [ -85.784396531574657, 14.166629137025041 ], [ -85.790546027377218, 14.165130520257264 ], [ -85.803749355648222, 14.167507636168466 ], [ -85.813593716077094, 14.172468573565823 ], [ -85.826771205926377, 14.181356920485484 ], [ -85.8364863760454, 14.18301056598483 ], [ -85.844857958128273, 14.18202871315458 ], [ -85.849172940378878, 14.179289862936798 ], [ -85.853022833736759, 14.175827542307218 ], [ -85.857518684040031, 14.173037014346733 ], [ -85.867802294040644, 14.168437812155275 ], [ -85.871316290614288, 14.165543932306605 ], [ -85.873745083368874, 14.16182322835931 ], [ -85.875450405711661, 14.157120673380348 ], [ -85.87640642012019, 14.146837063379735 ], [ -85.877491624838626, 14.14234121307652 ], [ -85.880178799112286, 14.138103746091019 ], [ -85.885372281405637, 14.134383043042988 ], [ -85.892658657870754, 14.131850898400216 ], [ -85.906275397291722, 14.131334133563371 ], [ -85.913070848241034, 14.132781073487763 ], [ -85.924543015747588, 14.141824449138994 ], [ -85.944412604657941, 14.167507636168466 ], [ -85.982730679177507, 14.18450918185323 ], [ -85.990507982057693, 14.190968736018363 ], [ -85.99531388982416, 14.198720201376204 ], [ -85.99699337374517, 14.207815252971557 ], [ -86.000765753636585, 14.221457830814245 ], [ -86.006760219808257, 14.234635322462168 ], [ -86.019317592932566, 14.254634100783107 ], [ -86.029601202933179, 14.263419094015944 ], [ -86.040298224983076, 14.268896796250147 ], [ -86.05791988829219, 14.272772528929067 ], [ -86.062312384908637, 14.272927558559957 ], [ -86.066549851894138, 14.271739000154696 ], [ -86.070012173423038, 14.269000149037652 ], [ -86.072699347696698, 14.265692857139641 ], [ -86.07623918269212, 14.257321275056768 ], [ -86.080140753792762, 14.253393866433782 ], [ -86.088460659931513, 14.252877102496257 ], [ -86.113782110855709, 14.258613186249534 ], [ -86.142178310580562, 14.268948473093531 ], [ -86.149232143948268, 14.276441555133658 ], [ -86.175974698173775, 14.323570461307725 ], [ -86.184940558559902, 14.334009100939227 ], [ -86.193725551792738, 14.338453274399058 ], [ -86.206592984178883, 14.34103709588527 ], [ -86.232482875883989, 14.341398831091169 ], [ -86.242766485884601, 14.340106919898403 ], [ -86.26199011874894, 14.334732571351083 ], [ -86.276640387843599, 14.327601222718215 ], [ -86.287311570572513, 14.3211933462959 ], [ -86.292970139959948, 14.319384670266288 ], [ -86.298706223713225, 14.316852524724197 ], [ -86.303641323588181, 14.313338528150553 ], [ -86.313098111288809, 14.304656886805844 ], [ -86.335732387939345, 14.290962633019092 ], [ -86.342863735672836, 14.288068752271101 ], [ -86.354465095287878, 14.286363429928315 ], [ -86.428155686735522, 14.290755927444081 ], [ -86.437354092017699, 14.293753160080257 ], [ -86.442134162261766, 14.297732245546683 ], [ -86.447818570070922, 14.311478176176877 ], [ -86.452521125049884, 14.318041083129458 ], [ -86.457120327241284, 14.323157050157704 ], [ -86.47577552022409, 14.336644599268823 ], [ -86.498978237655535, 14.34279409417212 ], [ -86.502647263860126, 14.345119534139201 ], [ -86.522904426398156, 14.364859930941066 ], [ -86.578921677693245, 14.380104478338978 ], [ -86.599953985687876, 14.382429918306059 ], [ -86.607317878317417, 14.38113800711335 ], [ -86.611942918930538, 14.382378241462675 ], [ -86.615689460400233, 14.38651235655999 ], [ -86.62065039689827, 14.396744289717162 ], [ -86.630701463801472, 14.40806142849209 ], [ -86.635093960417919, 14.410438544403291 ], [ -86.638892177831735, 14.411058661128266 ], [ -86.649356655884958, 14.409456692472361 ], [ -86.652586433417127, 14.408113105335531 ], [ -86.655712857262529, 14.406459458936865 ], [ -86.665660569579586, 14.405529282950056 ], [ -86.671319138967078, 14.406407782093481 ], [ -86.714210578155644, 14.423822739827585 ], [ -86.713564623008949, 14.437827052876173 ], [ -86.726147833655602, 14.471571764525322 ], [ -86.729300095922667, 14.485317695155516 ], [ -86.731057095108838, 14.500407212922539 ], [ -86.734700283791028, 14.507641913443535 ], [ -86.745113085000867, 14.523661607197425 ], [ -86.747516039333732, 14.532963365267051 ], [ -86.748601244052168, 14.541438300137429 ], [ -86.744415453010731, 14.557457993891262 ], [ -86.743717821020596, 14.575338040518147 ], [ -86.76247636589153, 14.598799140368044 ], [ -86.797306281359795, 14.630321763938241 ], [ -86.806633876951821, 14.639830227582934 ], [ -86.826064216290547, 14.644481105718455 ], [ -86.834952562310889, 14.651509101563761 ], [ -86.848336757735183, 14.66592682486305 ], [ -86.860170661346899, 14.687579251381351 ], [ -86.891357388132917, 14.762200018815804 ], [ -86.899470587797396, 14.799096990933378 ], [ -86.907170376311797, 14.809949041714901 ], [ -86.909909227428898, 14.820697739708919 ], [ -86.912415533649948, 14.8476728379311 ], [ -86.916988898319005, 14.858318183137612 ], [ -86.923706834902475, 14.86906688113163 ], [ -86.927272508319561, 14.876249904809242 ], [ -86.933292812912953, 14.897333888747937 ], [ -86.923551805271586, 14.905395413367614 ], [ -86.915490281551229, 14.932525540321421 ], [ -86.906136848436802, 14.940173651992438 ], [ -86.908358933817738, 14.942860826266099 ], [ -86.912234667395978, 14.946116441320669 ], [ -86.926652390695267, 14.953506171472611 ], [ -86.938124559101084, 14.965288398240943 ], [ -86.961637335794421, 14.977277330584343 ], [ -86.970654873023932, 14.985855618242169 ], [ -86.980964322345585, 14.998102932104644 ], [ -86.984995082856756, 15.00476919184473 ], [ -86.987475551555463, 15.015879625044647 ], [ -86.973316209775248, 15.040580960143188 ], [ -86.969569668305553, 15.043784898354374 ], [ -86.96349768776804, 15.047608954189855 ], [ -86.959131028673994, 15.047453925458285 ], [ -86.951250373006303, 15.04600698553395 ], [ -86.920993822207095, 15.053965155567482 ], [ -86.901020881408556, 15.071535142033156 ], [ -86.886163906738886, 15.081560370514694 ], [ -86.88066036698234, 15.090552070221861 ], [ -86.879161750214564, 15.098303533781063 ], [ -86.879006720583675, 15.10460805921457 ], [ -86.878231574227755, 15.11111929022303 ], [ -86.875802782372489, 15.118095608325632 ], [ -86.871487800121884, 15.127242335865105 ], [ -86.864537320440945, 15.137991033859123 ], [ -86.862444423571276, 15.143778795355104 ], [ -86.862599453202165, 15.147602851190641 ], [ -86.863193732404795, 15.15158193575769 ], [ -86.862987026829785, 15.154630846136627 ], [ -86.855132208684495, 15.17163239182139 ], [ -86.862909511564681, 15.23193878784474 ], [ -86.862056850842976, 15.240051988408538 ], [ -86.85887875015419, 15.253591213463721 ], [ -86.855545619834459, 15.257673651717653 ], [ -86.851437344058183, 15.260619208409707 ], [ -86.844616054687151, 15.262014472389978 ], [ -86.829707404073417, 15.269765936848501 ], [ -86.826219245022116, 15.271109523985331 ], [ -86.817692634207674, 15.277259018888572 ], [ -86.815315518296529, 15.28537221945237 ], [ -86.768729213582333, 15.295294094247026 ], [ -86.738136765998945, 15.27090281841032 ], [ -86.729661831128567, 15.268680732130065 ], [ -86.71875810440298, 15.266820380156389 ], [ -86.70064551467874, 15.266923732943894 ], [ -86.692739020589329, 15.268629055286681 ], [ -86.686356980790038, 15.271936347184635 ], [ -86.676280077263755, 15.279274400493193 ], [ -86.666358201569722, 15.282323309972753 ], [ -86.659743618673019, 15.296586005439792 ], [ -86.651837123684288, 15.305939439453539 ], [ -86.64186357294551, 15.331260891277111 ], [ -86.63822038426332, 15.337203681504661 ], [ -86.632949387604128, 15.340872707709252 ], [ -86.628789435883732, 15.340355942872463 ], [ -86.624138556848891, 15.339115709422458 ], [ -86.618790045823914, 15.338753974216502 ], [ -86.611322801306244, 15.341492825333603 ], [ -86.526547614181027, 15.386244614697205 ], [ -86.514067756321879, 15.3892418482327 ], [ -86.503034838387066, 15.389293525076084 ], [ -86.47918616401023, 15.382317206074163 ], [ -86.464742601389901, 15.374669094403146 ], [ -86.451978521791318, 15.366400865107835 ], [ -86.442754278986797, 15.358494371018367 ], [ -86.434486049691429, 15.349864407416476 ], [ -86.429680141925019, 15.342836412470433 ], [ -86.426605394023682, 15.336841946298762 ], [ -86.420404222277, 15.331881008002085 ], [ -86.409112921923793, 15.328263657741616 ], [ -86.385264248446276, 15.32795360027842 ], [ -86.371957567387824, 15.329400540202755 ], [ -86.346067673884022, 15.341596178121108 ], [ -86.290515509683019, 15.374152330465677 ], [ -86.27764807819625, 15.378544827082067 ], [ -86.232896287933329, 15.409757392289805 ], [ -86.171633876602129, 15.378079739088662 ], [ -86.148560350379853, 15.37301544800448 ], [ -86.125667691310866, 15.378234767820288 ], [ -86.106805792753107, 15.38732982031496 ], [ -86.090191819796644, 15.390430405738641 ], [ -86.081329312197965, 15.394151108786616 ], [ -86.063345912783632, 15.396683254328707 ], [ -86.053656581985649, 15.395856432028722 ], [ -86.045543382321227, 15.393582668905026 ], [ -86.03828284427783, 15.39037872979452 ], [ -86.031668259582489, 15.39037872979452 ], [ -86.027508307862092, 15.396579902440521 ], [ -85.969940762056524, 15.426655585187063 ], [ -85.909143438718729, 15.484223130992689 ], [ -85.884597134150397, 15.523083807871444 ], [ -85.879946255115556, 15.52856151010559 ], [ -85.87312496574458, 15.531352037166755 ], [ -85.866277838851147, 15.53031850839244 ], [ -85.859611579111061, 15.52799306932468 ], [ -85.847855190764449, 15.520603339172737 ], [ -85.8368739487737, 15.519983222447763 ], [ -85.817262743181061, 15.531868801104281 ], [ -85.79579118471537, 15.548715318057475 ], [ -85.787858853103558, 15.557810370552147 ], [ -85.784551561205546, 15.565045071073143 ], [ -85.786308560391717, 15.574295152299442 ], [ -85.764139369935947, 15.584992174349338 ], [ -85.759126756594526, 15.584268703937539 ], [ -85.752382981589335, 15.581478175976997 ], [ -85.745561693117622, 15.575845445011282 ], [ -85.73587236231964, 15.571866360444176 ], [ -85.727836677021003, 15.573313300368511 ], [ -85.717837286961185, 15.577034003416486 ], [ -85.709362352090864, 15.581529852820438 ], [ -85.688304205674513, 15.577189032148112 ], [ -85.607714809590789, 15.534866033740457 ], [ -85.505240444790672, 15.449496568311986 ], [ -85.395944789720261, 15.408930569090501 ], [ -85.360417243161237, 15.381076971724838 ], [ -85.307113002762833, 15.305267645885124 ], [ -85.249312913859853, 15.236641343723022 ], [ -85.232647264059949, 15.226667792084925 ], [ -85.092681647040365, 15.166774807211596 ], [ -85.059634569179991, 15.137060858771576 ], [ -84.999948289881672, 15.06874461497199 ], [ -84.999948289881672, 14.980998032732998 ], [ -84.999948289881672, 14.742769680376455 ], [ -84.999948289999907, 14.742015988000105 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-GD", "NAME_1": "Gracias a Dios" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -84.984368651999944, 14.752227275000067 ], [ -84.999948289999907, 14.742015988000105 ], [ -84.999948289881672, 14.742769680376455 ], [ -84.999948289881672, 14.980998032732998 ], [ -84.999948289881672, 15.06874461497199 ], [ -84.999948697274533, 15.987941798774955 ], [ -84.950774182999908, 15.972006975000056 ], [ -84.85446430099995, 15.929750654000088 ], [ -84.733589441999925, 15.895029350000073 ], [ -84.67655175099992, 15.876203025000052 ], [ -84.662276815999917, 15.865637092000043 ], [ -84.668480615999897, 15.853211763000047 ], [ -84.680854078999914, 15.83491673900005 ], [ -84.680939234999926, 15.819181622000087 ], [ -84.681079925999938, 15.794266759000038 ], [ -84.660053913999946, 15.774494092000054 ], [ -84.640297128999919, 15.771775004000062 ], [ -84.615713245999927, 15.77951835600004 ], [ -84.612188505999939, 15.799820681000085 ], [ -84.60940910599993, 15.808983062000038 ], [ -84.599870326999906, 15.808277578000059 ], [ -84.593129224999927, 15.795787892000078 ], [ -84.575485152999931, 15.783895482000048 ], [ -84.55025536699992, 15.787693059000048 ], [ -84.526432806999935, 15.784936377000065 ], [ -84.477436545999922, 15.778755998000065 ], [ -84.468516404999946, 15.789188903000081 ], [ -84.452811170999951, 15.795647751000047 ], [ -84.473867337999934, 15.804293073000053 ], [ -84.499033204999932, 15.809683259000053 ], [ -84.577974540999946, 15.822580437000056 ], [ -84.607887389999917, 15.835195009000074 ], [ -84.633054966999907, 15.847125321000078 ], [ -84.641829709999911, 15.862907079000081 ], [ -84.601645592999944, 15.854824790000066 ], [ -84.464167581999902, 15.829792031000068 ], [ -84.374315457999899, 15.820715618000065 ], [ -84.315041911999913, 15.81770380200004 ], [ -84.294638382999949, 15.811010146000058 ], [ -84.240394391999928, 15.767350999000087 ], [ -84.167070508999927, 15.709697431000052 ], [ -84.058306091999896, 15.620248106000076 ], [ -83.952933206999944, 15.532886512000061 ], [ -83.894170739999936, 15.485180693000075 ], [ -83.817534959999932, 15.439886786000045 ], [ -83.79906165299991, 15.429348049000055 ], [ -83.780873175999943, 15.421535549000055 ], [ -83.745676235999952, 15.415838934000078 ], [ -83.736805792999917, 15.411322333000044 ], [ -83.729969855999911, 15.401556708000044 ], [ -83.729359503999945, 15.393744208000044 ], [ -83.735910610999952, 15.388617255000042 ], [ -83.750803188999896, 15.386786200000074 ], [ -83.768299933999913, 15.393377997000073 ], [ -83.806223110999952, 15.422349351000037 ], [ -83.834462042999917, 15.431789455000057 ], [ -83.853423631999931, 15.44476959800005 ], [ -83.862782355999911, 15.448879299000055 ], [ -83.893137173999946, 15.449164130000042 ], [ -83.906361456999946, 15.451971747000073 ], [ -83.918080206999946, 15.463120835000041 ], [ -83.913400844999899, 15.464829820000091 ], [ -83.909169074999909, 15.467840887000079 ], [ -83.904408331999946, 15.46938711100006 ], [ -83.913075324999909, 15.481838283000059 ], [ -83.94595292899993, 15.517767645000049 ], [ -83.952788865999935, 15.517767645000049 ], [ -83.963734503999945, 15.512518622000073 ], [ -83.977162238999938, 15.520209052000041 ], [ -83.991200324999909, 15.531683661000045 ], [ -84.004017706999946, 15.537583726000037 ], [ -84.024525519999941, 15.535101630000042 ], [ -84.033924933999913, 15.528876044000071 ], [ -84.041167772999927, 15.520209052000041 ], [ -84.055246548999946, 15.510931708000044 ], [ -84.061594204999949, 15.51508209800005 ], [ -84.089344855999911, 15.524603583000044 ], [ -84.076568162999934, 15.535549221000053 ], [ -84.071156378999945, 15.54165273600006 ], [ -84.068837042999917, 15.548163153000075 ], [ -84.073638475999928, 15.550482489000046 ], [ -84.084380662999934, 15.55219147300005 ], [ -84.096180792999917, 15.552639065000051 ], [ -84.103627081999946, 15.551214911000045 ], [ -84.106434699999909, 15.540432033000059 ], [ -84.100005662999934, 15.523260809000078 ], [ -84.088368292999917, 15.504868882000039 ], [ -84.075754360999952, 15.490423895000049 ], [ -84.078236456999946, 15.488226630000042 ], [ -84.079335089999915, 15.487534898000092 ], [ -84.08031165299991, 15.486395575000074 ], [ -84.082508917999917, 15.482977606000077 ], [ -84.089344855999911, 15.482977606000077 ], [ -84.119292772999927, 15.539292710000041 ], [ -84.130360480999911, 15.551214911000045 ], [ -84.141753709999932, 15.553127346000053 ], [ -84.154896613999938, 15.550685940000051 ], [ -84.171945766999897, 15.545070705000057 ], [ -84.18382727799991, 15.545884507000039 ], [ -84.200998501999948, 15.549872137000079 ], [ -84.212880011999914, 15.551214911000045 ], [ -84.205148891999897, 15.528509833000044 ], [ -84.198719855999911, 15.520738023000092 ], [ -84.180409308999913, 15.514471747000073 ], [ -84.180165167999917, 15.50617096600007 ], [ -84.183461066999939, 15.494940497000073 ], [ -84.185536261999914, 15.482977606000077 ], [ -84.178700324999909, 15.482977606000077 ], [ -84.175607876999948, 15.498277085000041 ], [ -84.155588344999899, 15.507391669000071 ], [ -84.146555141999897, 15.535101630000042 ], [ -84.137115037999934, 15.538072007000039 ], [ -84.127797003999945, 15.532619533000059 ], [ -84.114247199999909, 15.499904690000051 ], [ -84.098052537999934, 15.473456122000073 ], [ -84.092152472999942, 15.450913804000038 ], [ -84.11359615799995, 15.441392320000091 ], [ -84.124175584999932, 15.430243231000077 ], [ -84.116525844999899, 15.404974677000041 ], [ -84.099517381999931, 15.37759023600006 ], [ -84.082508917999917, 15.36009349200009 ], [ -84.056711391999897, 15.346828518000052 ], [ -84.03538977799991, 15.341864325000074 ], [ -84.025868292999917, 15.351223049000055 ], [ -84.03538977799991, 15.380560614000046 ], [ -84.021962042999917, 15.370306708000044 ], [ -84.01008053299995, 15.356756903000075 ], [ -84.005360480999911, 15.341294664000088 ], [ -84.013579881999931, 15.325344143000052 ], [ -83.999908006999931, 15.308823960000041 ], [ -83.980620897999927, 15.305731512000079 ], [ -83.931752081999946, 15.311672268000052 ], [ -83.931752081999946, 15.304877020000049 ], [ -83.941395636999914, 15.305243231000077 ], [ -83.94790605399993, 15.303412177000041 ], [ -83.958973761999914, 15.298041083000044 ], [ -83.958973761999914, 15.291815497000073 ], [ -83.950672980999911, 15.274807033000059 ], [ -83.938384568999936, 15.25922272300005 ], [ -83.921986456999946, 15.247870184000078 ], [ -83.900990363999938, 15.243394273000092 ], [ -83.882801886999914, 15.24555084800005 ], [ -83.859527147999927, 15.251288153000075 ], [ -83.837147589999915, 15.259995835000041 ], [ -83.821888800999943, 15.270697333000044 ], [ -83.834543423999946, 15.282619533000059 ], [ -83.877064581999946, 15.304877020000049 ], [ -83.884266730999911, 15.311712958000044 ], [ -83.887603318999936, 15.318345445000091 ], [ -83.891672329999949, 15.323391018000052 ], [ -83.900990363999938, 15.325344143000052 ], [ -83.911732550999943, 15.326117255000042 ], [ -83.988148566999939, 15.352362372000073 ], [ -84.000599738999938, 15.36009349200009 ], [ -84.023793097999942, 15.392564195000091 ], [ -84.03538977799991, 15.401068427000041 ], [ -84.026519334999932, 15.408677476000037 ], [ -84.016713019999941, 15.413723049000055 ], [ -83.99437415299991, 15.421535549000055 ], [ -83.905140753999945, 15.38353099200009 ], [ -83.890736456999946, 15.363226630000042 ], [ -83.88508053299995, 15.352606512000079 ], [ -83.87132727799991, 15.342840887000079 ], [ -83.854400193999936, 15.335598049000055 ], [ -83.825917120999918, 15.329738674000055 ], [ -83.814076300999943, 15.321682033000059 ], [ -83.803863084999932, 15.310492255000042 ], [ -83.79515540299991, 15.298041083000044 ], [ -83.801828579999949, 15.29368724200009 ], [ -83.809925910999937, 15.286688544000071 ], [ -83.815663214999915, 15.284369208000044 ], [ -83.815663214999915, 15.278143622000073 ], [ -83.799224412999934, 15.274603583000044 ], [ -83.785308397999927, 15.284409898000092 ], [ -83.774525519999941, 15.285711981000077 ], [ -83.767201300999943, 15.256415106000077 ], [ -83.769439256999931, 15.219224351000037 ], [ -83.767201300999943, 15.20929596600007 ], [ -83.759836391999897, 15.202093817000048 ], [ -83.75226803299995, 15.202541408000059 ], [ -83.747181769999941, 15.20970286700009 ], [ -83.747385219999899, 15.222886460000041 ], [ -83.739898240999935, 15.222886460000041 ], [ -83.731027798999946, 15.20343659100007 ], [ -83.722645636999914, 15.208075262000079 ], [ -83.705799933999913, 15.237209377000056 ], [ -83.690256313999896, 15.245917059000078 ], [ -83.669545050999943, 15.251898505000042 ], [ -83.633778449999909, 15.256415106000077 ], [ -83.629383917999917, 15.261135158000059 ], [ -83.631459113999938, 15.28384023600006 ], [ -83.630034959999932, 15.291815497000073 ], [ -83.62336178299995, 15.296087958000044 ], [ -83.617014126999948, 15.295599677000041 ], [ -83.609486456999946, 15.29328034100007 ], [ -83.544667120999918, 15.280991929000038 ], [ -83.52765865799995, 15.284369208000044 ], [ -83.52765865799995, 15.278143622000073 ], [ -83.533599412999934, 15.272162177000041 ], [ -83.532948370999918, 15.268133856000077 ], [ -83.529652472999942, 15.263739325000074 ], [ -83.52765865799995, 15.256415106000077 ], [ -83.52765865799995, 15.226304429000038 ], [ -83.532866990999935, 15.21124909100007 ], [ -83.544422980999911, 15.204982815000051 ], [ -83.555897589999915, 15.20929596600007 ], [ -83.561146613999938, 15.226304429000038 ], [ -83.564808722999942, 15.231390692000048 ], [ -83.573475714999915, 15.234767971000053 ], [ -83.583851691999939, 15.23663971600007 ], [ -83.592518683999913, 15.237209377000056 ], [ -83.598500128999945, 15.233099677000041 ], [ -83.603911912999934, 15.224025783000059 ], [ -83.610218878999945, 15.20929596600007 ], [ -83.614735480999911, 15.204087632000039 ], [ -83.619130011999914, 15.200873114000046 ], [ -83.622466600999928, 15.19594961100006 ], [ -83.623850063999896, 15.185370184000078 ], [ -83.621449347999942, 15.176174221000053 ], [ -83.615793423999946, 15.174505927000041 ], [ -83.608998175999943, 15.177394924000055 ], [ -83.603382941999939, 15.18195221600007 ], [ -83.608469204999949, 15.190415757000039 ], [ -83.609486456999946, 15.196926174000055 ], [ -83.607492641999897, 15.202826239000046 ], [ -83.603382941999939, 15.20929596600007 ], [ -83.59593665299991, 15.20929596600007 ], [ -83.593861456999946, 15.184759833000044 ], [ -83.587025519999941, 15.167181708000044 ], [ -83.57445227799991, 15.16046784100007 ], [ -83.55492102799991, 15.16828034100007 ], [ -83.549549933999913, 15.174017645000049 ], [ -83.540435350999928, 15.188666083000044 ], [ -83.534494594999899, 15.195013739000046 ], [ -83.526600714999915, 15.199896552000041 ], [ -83.481800910999937, 15.21556224200009 ], [ -83.482167120999918, 15.21906159100007 ], [ -83.486683722999942, 15.229722398000092 ], [ -83.49087480399993, 15.235907294000071 ], [ -83.496571417999917, 15.240464585000041 ], [ -83.502308722999942, 15.246283270000049 ], [ -83.50649980399993, 15.256415106000077 ], [ -83.509877081999946, 15.270575262000079 ], [ -83.517201300999943, 15.28969961100006 ], [ -83.52961178299995, 15.301011460000041 ], [ -83.548166469999899, 15.291815497000073 ], [ -83.577870245999918, 15.309068101000037 ], [ -83.592640753999945, 15.312241929000038 ], [ -83.610218878999945, 15.304877020000049 ], [ -83.616363084999932, 15.311672268000052 ], [ -83.614125128999945, 15.315415757000039 ], [ -83.610218878999945, 15.325344143000052 ], [ -83.626332160999937, 15.327460028000075 ], [ -83.669585740999935, 15.342922268000052 ], [ -83.678456183999913, 15.349269924000055 ], [ -83.688954230999911, 15.360581773000092 ], [ -83.709828253999945, 15.367092190000051 ], [ -83.725331183999913, 15.375881252000056 ], [ -83.71939042899993, 15.394232489000046 ], [ -83.702992316999939, 15.402004299000055 ], [ -83.687408006999931, 15.393744208000044 ], [ -83.673329230999911, 15.380601304000038 ], [ -83.661366339999915, 15.37376536700009 ], [ -83.65062415299991, 15.370306708000044 ], [ -83.542591925999943, 15.315741278000075 ], [ -83.408029751999948, 15.266424872000073 ], [ -83.356312628999945, 15.229722398000092 ], [ -83.344553188999896, 15.210882880000042 ], [ -83.32843990799995, 15.146633205000057 ], [ -83.31086178299995, 15.106431382000039 ], [ -83.284291144999941, 15.068345445000091 ], [ -83.253814256999931, 15.044623114000046 ], [ -83.130444472447948, 14.997012021272383 ], [ -83.143654134999935, 14.994899801000088 ], [ -83.177398843999896, 14.996811829000109 ], [ -83.191325642999885, 14.994253845000117 ], [ -83.21773230099987, 14.982497457000122 ], [ -83.262019002999892, 14.98319508900002 ], [ -83.266153116999902, 14.982497457000122 ], [ -83.278322916999912, 14.987122498000076 ], [ -83.285660970999913, 14.992109274000128 ], [ -83.2848858239999, 14.997380269000075 ], [ -83.272974405999946, 15.003038839000098 ], [ -83.317054402999929, 15.007560526000134 ], [ -83.334236816999919, 15.00644948300004 ], [ -83.349352172999915, 14.996811829000109 ], [ -83.354545653999935, 15.010066834000028 ], [ -83.364984293999868, 15.016345521000119 ], [ -83.377825886999943, 15.021254781000053 ], [ -83.390305745999939, 15.030969950000099 ], [ -83.399891723999929, 15.013632508000086 ], [ -83.41547216799998, 14.996941020000051 ], [ -83.435729329999873, 14.985184631000052 ], [ -83.45919042999995, 14.982497457000122 ], [ -83.468388834999956, 14.987406719000063 ], [ -83.48055863499988, 15.005545146000088 ], [ -83.485855468999915, 15.010480245000039 ], [ -83.499007120999892, 15.012650655000115 ], [ -83.509084024999908, 15.011539612000107 ], [ -83.512468831999939, 15.006501160000141 ], [ -83.505725056999893, 14.996811829000109 ], [ -83.510996052999928, 14.99017140700002 ], [ -83.51262386099998, 14.984021911000042 ], [ -83.513218139999935, 14.96885487900002 ], [ -83.523036661999896, 14.977691548000024 ], [ -83.528617716999918, 14.973402405000058 ], [ -83.529909627999871, 14.961775207000088 ], [ -83.526860717999938, 14.94836517400006 ], [ -83.532493448999872, 14.951026509000073 ], [ -83.547350423999916, 14.955212301000103 ], [ -83.545128336999909, 14.952163391000084 ], [ -83.542441161999875, 14.945083720000056 ], [ -83.540477458999931, 14.941569723000015 ], [ -83.55486934399994, 14.937409770000073 ], [ -83.579777384999915, 14.918108623000123 ], [ -83.604272013999974, 14.90919443700011 ], [ -83.609181274999912, 14.89836822500007 ], [ -83.611300008999876, 14.884906514000107 ], [ -83.615614990999859, 14.872685038000085 ], [ -83.623056396999885, 14.872685038000085 ], [ -83.631557169999979, 14.883201192000044 ], [ -83.649953979999879, 14.888498027000082 ], [ -83.672149007999906, 14.88963490800009 ], [ -83.691966918999896, 14.886973572000073 ], [ -83.710622110999878, 14.878343607000119 ], [ -83.714497843999936, 14.867233175000109 ], [ -83.705015218999847, 14.83852691700011 ], [ -83.712430785999857, 14.83852691700011 ], [ -83.7162031659999, 14.847053528000032 ], [ -83.723618733999899, 14.851575216000057 ], [ -83.733928181999914, 14.852970480000039 ], [ -83.746563069999922, 14.852195333000026 ], [ -83.744521851999878, 14.836666565000101 ], [ -83.76529577699992, 14.828785909000061 ], [ -83.821054646999869, 14.825478618000062 ], [ -83.813923299999942, 14.81377390600008 ], [ -83.808988199999902, 14.808890483000056 ], [ -83.801210896999891, 14.803774516000061 ], [ -83.819659383999891, 14.803619486000031 ], [ -83.83950313299988, 14.797418315000044 ], [ -83.857305664999927, 14.787780661000028 ], [ -83.869475463999919, 14.77710947700011 ], [ -83.875263224999912, 14.784266663000068 ], [ -83.878751383999941, 14.786747132000045 ], [ -83.882678791999922, 14.78783233700004 ], [ -83.889939330999908, 14.790726216000024 ], [ -83.885004231999858, 14.781346944000077 ], [ -83.883763997999921, 14.77710947700011 ], [ -83.896553914999885, 14.780442606000122 ], [ -83.912651122999961, 14.797185771000073 ], [ -83.924717569999927, 14.803774516000061 ], [ -83.929652669999882, 14.780881857000054 ], [ -83.929859375999939, 14.771657613000045 ], [ -83.924717569999927, 14.763441061 ], [ -84.023574584999892, 14.758325094000028 ], [ -84.040756998999967, 14.76034047400006 ], [ -84.042669026999903, 14.768066101000059 ], [ -84.047810832999886, 14.770804952000105 ], [ -84.064683186999872, 14.770262349000063 ], [ -84.075199340999916, 14.771631775000031 ], [ -84.078971720999874, 14.77517161100009 ], [ -84.081555541999961, 14.779796651000055 ], [ -84.104448201999872, 14.793930156000087 ], [ -84.111760416999857, 14.793413392000048 ], [ -84.122715820999929, 14.784525045000038 ], [ -84.111114461999904, 14.761038106000058 ], [ -84.104189819999903, 14.751865540000068 ], [ -84.095430663999934, 14.743597310000027 ], [ -84.095430663999934, 14.736104228000073 ], [ -84.102277791999882, 14.731866760000031 ], [ -84.106515258999934, 14.732331848000058 ], [ -84.111217814999918, 14.734708964000092 ], [ -84.119615234999912, 14.736104228000073 ], [ -84.128736124999875, 14.734192200000066 ], [ -84.13385209199987, 14.73003224700004 ], [ -84.137882853999969, 14.725226339000116 ], [ -84.143799804999873, 14.721867371000101 ], [ -84.168191081999908, 14.714968567000128 ], [ -84.182893026999892, 14.713857523000044 ], [ -84.195011148999896, 14.718715108000055 ], [ -84.218678955999906, 14.743442282000075 ], [ -84.226378743999902, 14.749772644000089 ], [ -84.235396280999851, 14.754733582000128 ], [ -84.249219726999911, 14.759410298000105 ], [ -84.261802938999921, 14.758531799000068 ], [ -84.267332316999841, 14.746672058000058 ], [ -84.262164672999916, 14.699749858000104 ], [ -84.26728063999991, 14.677735698000021 ], [ -84.287796183999887, 14.667219544000062 ], [ -84.298880777999898, 14.667994690000072 ], [ -84.323168701999919, 14.673317363000109 ], [ -84.338387410999928, 14.674686788000088 ], [ -84.346035522999927, 14.679983622000037 ], [ -84.353192708999956, 14.705976868000093 ], [ -84.362933715999901, 14.715614523000113 ], [ -84.376137044999894, 14.696726787000074 ], [ -84.390012166999952, 14.671482849000114 ], [ -84.408434814999879, 14.649417013000033 ], [ -84.445719360999902, 14.636678772000067 ], [ -84.47160925299994, 14.622622783000054 ], [ -84.48269384799994, 14.619470520000093 ], [ -84.498015909999907, 14.623914693000089 ], [ -84.508480387999867, 14.632622172000069 ], [ -84.519048217999938, 14.638280742000092 ], [ -84.534215250999949, 14.633733215000063 ], [ -84.531218017999919, 14.653318583000086 ], [ -84.527419799999905, 14.6603982540001 ], [ -84.600438598999943, 14.662516989000082 ], [ -84.622969523999956, 14.667219544000062 ], [ -84.661701009999888, 14.683445943000066 ], [ -84.680847127999897, 14.685461325000119 ], [ -84.699321451999907, 14.674686788000088 ], [ -84.714410970999921, 14.708922424000093 ], [ -84.72484960999995, 14.725639750000127 ], [ -84.745287637999894, 14.739101461000089 ], [ -84.744279947999928, 14.752408142000107 ], [ -84.747044637999892, 14.764474590000091 ], [ -84.766940063999897, 14.766903381000049 ], [ -84.766397461999929, 14.768867086000085 ], [ -84.758568481999902, 14.778659770000047 ], [ -84.755467895999857, 14.781476135000105 ], [ -84.770169840999955, 14.805143942000129 ], [ -84.792132324999926, 14.821060283000065 ], [ -84.818099731999979, 14.828656718000033 ], [ -84.844428873999931, 14.827545675000124 ], [ -84.904218506999882, 14.81697784400005 ], [ -84.920625772999927, 14.807701925000032 ], [ -84.966462768999889, 14.764629618000129 ], [ -84.984368651999944, 14.752227275000067 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-EP", "NAME_1": "El Paraíso" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -85.563145912999914, 14.042012281000098 ], [ -85.571697143999927, 14.04051361100008 ], [ -85.593607950999882, 14.033459778000065 ], [ -85.603064737999944, 14.019532980000079 ], [ -85.612805745999907, 14.009740295000114 ], [ -85.647868204999924, 13.999301657000089 ], [ -85.644612589999952, 13.988785503000116 ], [ -85.647661499999884, 13.98780365000006 ], [ -85.650400350999917, 13.987855327000076 ], [ -85.651950643999839, 13.986692607000066 ], [ -85.651485555999926, 13.981990052000086 ], [ -85.657660888999885, 13.981990052000086 ], [ -85.666187500999911, 13.984470520000059 ], [ -85.686496337999927, 13.967339783000099 ], [ -85.699234578999892, 13.961500346000022 ], [ -85.716985433999923, 13.962688904000046 ], [ -85.727346557999937, 13.965014344000068 ], [ -85.732204142999933, 13.959536641000085 ], [ -85.733392699999882, 13.937625834000116 ], [ -85.743288737999961, 13.907550151000052 ], [ -85.747448689999885, 13.88827484200003 ], [ -85.74367630999987, 13.879567363000149 ], [ -85.728690144999888, 13.87501983700011 ], [ -85.723005737999955, 13.863418478000071 ], [ -85.725124471999919, 13.847941386000059 ], [ -85.733392699999882, 13.831792501000066 ], [ -85.740293111999904, 13.825639142000043 ], [ -85.742461913999932, 13.823705139000069 ], [ -85.743114602999924, 13.823958222000059 ], [ -85.744994059999925, 13.824686991000135 ], [ -85.758300740999942, 13.83928558400001 ], [ -85.778661254999889, 13.84093923000006 ], [ -85.802019001999923, 13.840215760000063 ], [ -85.824162353999839, 13.847683004000089 ], [ -85.840104532999959, 13.866570740000029 ], [ -85.849871378999921, 13.887086283000087 ], [ -85.861601928999903, 13.904423727000108 ], [ -85.883564412999874, 13.913854675000067 ], [ -85.897206990999877, 13.913027853000045 ], [ -85.906302042999954, 13.909358826000044 ], [ -85.91550044799996, 13.907446798000123 ], [ -85.929401407999933, 13.912097677000091 ], [ -85.936119344999952, 13.918195496000052 ], [ -85.957771768999947, 13.94610076900004 ], [ -86.028413452999928, 13.996071879000098 ], [ -86.0312556559999, 14.022581889000023 ], [ -86.020455281999972, 14.044079284000048 ], [ -86.020196899999888, 14.055163879000062 ], [ -86.096729695999898, 14.044079284000048 ], [ -86.110475626999914, 14.037128805000066 ], [ -86.121689412999871, 14.027206930000062 ], [ -86.12690873199989, 14.018551127000109 ], [ -86.130836141999879, 14.008913473000092 ], [ -86.138019165999907, 13.996175232000041 ], [ -86.14969803999989, 13.984263815000091 ], [ -86.161790324999885, 13.978114319000028 ], [ -86.173572550999978, 13.973670146000117 ], [ -86.184062866999909, 13.966874695000072 ], [ -86.218582722999912, 13.91437144000011 ], [ -86.284108439999898, 13.845719299000052 ], [ -86.299921427999891, 13.82132802300012 ], [ -86.307776244999843, 13.791691589000081 ], [ -86.313564005999922, 13.776602072000074 ], [ -86.325191202999861, 13.76376047800008 ], [ -86.34012569199993, 13.756654968000063 ], [ -86.358470825999916, 13.752262472000069 ], [ -86.410095580999922, 13.749032695000082 ], [ -86.417071899999939, 13.750014547000148 ], [ -86.426528686999916, 13.752985942000066 ], [ -86.432471476999922, 13.757120056000076 ], [ -86.448232788999888, 13.772958883000086 ], [ -86.462857218999972, 13.770943502000137 ], [ -86.476293091999935, 13.764018860000064 ], [ -86.490814168999862, 13.759497172000124 ], [ -86.508539184999876, 13.764380595000148 ], [ -86.541663777999901, 13.78213145000008 ], [ -86.581144571999914, 13.77985768700006 ], [ -86.66268998299995, 13.764690654000049 ], [ -86.706304891999906, 13.770013326000083 ], [ -86.727233846999894, 13.768256327000103 ], [ -86.749919799999873, 13.757120056000076 ], [ -86.7614436449999, 13.749342753000064 ], [ -86.766197876999883, 13.745260315000067 ], [ -86.76790319899996, 13.739162496000105 ], [ -86.770228637999878, 13.72523569800012 ], [ -86.771167593109908, 13.70789040401894 ], [ -86.771881476748717, 13.707587389146681 ], [ -86.786247525003262, 13.701489570187505 ], [ -86.794205695036794, 13.700145982151355 ], [ -86.80120785156106, 13.694306544711253 ], [ -86.809191860915632, 13.681852525273825 ], [ -86.815987311864944, 13.6806122909245 ], [ -86.823609585114241, 13.6809740261304 ], [ -86.84071448358651, 13.679372057474438 ], [ -86.848827684150308, 13.676374823039623 ], [ -86.887352465144147, 13.651880195314732 ], [ -86.891383225655318, 13.659218247723913 ], [ -86.921148850938721, 13.656531073450253 ], [ -86.926135626757741, 13.658701483786444 ], [ -86.932853563341268, 13.6605618348608 ], [ -86.935075649621524, 13.657202867018668 ], [ -86.937943691947794, 13.638909410141139 ], [ -86.942517055717531, 13.629504299283951 ], [ -86.950010138656978, 13.618703925345869 ], [ -86.965952318045026, 13.601857408392675 ], [ -86.976933560035775, 13.593330797578233 ], [ -86.984736701337681, 13.588421536124997 ], [ -86.999516160742189, 13.583874009877661 ], [ -87.010574917098722, 13.573797105452059 ], [ -87.014166428937529, 13.56568390488826 ], [ -87.016543544848673, 13.550697739908742 ], [ -87.039203660820249, 13.525479640872732 ], [ -87.069873622769478, 13.508116359982012 ], [ -87.076617397774669, 13.505790920014931 ], [ -87.088916389379847, 13.507341212726772 ], [ -87.106615567054746, 13.520880439580594 ], [ -87.115116340346788, 13.539742336339714 ], [ -87.115607265862593, 13.549147447196901 ], [ -87.124004686367186, 13.555555325417913 ], [ -87.170125902188602, 13.558190822848189 ], [ -87.184285243968816, 13.566304023411931 ], [ -87.186894903876691, 13.578603014117789 ], [ -87.191287401392458, 13.597516587720349 ], [ -87.197591925926645, 13.60289093716699 ], [ -87.20632524321536, 13.612244371180793 ], [ -87.217280645885069, 13.615810045497199 ], [ -87.224127773677822, 13.628625800140526 ], [ -87.214231737304829, 13.671103827279808 ], [ -87.182683275312911, 13.68112905486197 ], [ -87.134753384361204, 13.660871894122579 ], [ -87.130205858113868, 13.660045070923275 ], [ -87.129844122907912, 13.664334214752216 ], [ -87.127027758324346, 13.681594142855374 ], [ -87.119508836963234, 13.697613837508584 ], [ -87.111628181295487, 13.70831085955848 ], [ -87.111163093302082, 13.724020494050535 ], [ -87.122557746442851, 13.744587714051761 ], [ -87.128681402924371, 13.752132472935273 ], [ -87.131549445250698, 13.76267446535428 ], [ -87.132272914763178, 13.776782131190373 ], [ -87.131652798038203, 13.790941473869907 ], [ -87.129895798852033, 13.798744615171813 ], [ -87.128190477408566, 13.802465318219845 ], [ -87.1215500560902, 13.810320136365192 ], [ -87.106486375845577, 13.80349884699416 ], [ -87.083800422351601, 13.783706773348911 ], [ -87.075687221787859, 13.779727687882485 ], [ -87.051218430685992, 13.775180162534468 ], [ -87.035534633716338, 13.775386868109479 ], [ -87.030547857897318, 13.779004218369948 ], [ -87.013933884940798, 13.8004499375146 ], [ -86.995071988181678, 13.84592519818932 ], [ -86.990989549028427, 13.891865545958183 ], [ -86.992488165796203, 13.911605942760048 ], [ -86.989904344310048, 13.924473375146135 ], [ -86.984995082856756, 13.934291897153344 ], [ -86.984219937400155, 13.942818507967729 ], [ -86.985150113387022, 13.950053209388102 ], [ -86.989258389163297, 13.964522610430095 ], [ -86.954583503325978, 13.958424791470918 ], [ -86.93827958873203, 13.966899726341296 ], [ -86.926729905960372, 13.978992011472144 ], [ -86.915955370443953, 13.999300849054919 ], [ -86.912286343340043, 14.038936672289594 ], [ -86.914250048101223, 14.049995429545447 ], [ -86.917118090427493, 14.056248277236193 ], [ -86.924740362777527, 14.06043406827763 ], [ -86.952232224937234, 14.080277817867 ], [ -86.978277147172605, 14.114745999028628 ], [ -86.984297451765997, 14.132626043856817 ], [ -86.963006761352915, 14.140842597208064 ], [ -86.949157477935216, 14.140842597208064 ], [ -86.933215297647848, 14.137845364571888 ], [ -86.912182989653218, 14.140842597208064 ], [ -86.901873542130261, 14.160996405159949 ], [ -86.903036262113801, 14.164820460995486 ], [ -86.906860317949281, 14.169574692817832 ], [ -86.912389696127548, 14.172675279140833 ], [ -86.920657925422915, 14.174897366320408 ], [ -86.921923998193961, 14.178566392524999 ], [ -86.91993445501106, 14.18357900586642 ], [ -86.908927374598647, 14.198668525432083 ], [ -86.89686092788952, 14.229932766583886 ], [ -86.848130052160172, 14.271687323311312 ], [ -86.829138964191827, 14.30496694606768 ], [ -86.821697557196501, 14.337781479931323 ], [ -86.788934699276922, 14.368270574727205 ], [ -86.714210578155644, 14.423822739827585 ], [ -86.671319138967078, 14.406407782093481 ], [ -86.665660569579586, 14.405529282950056 ], [ -86.655712857262529, 14.406459458936865 ], [ -86.652586433417127, 14.408113105335531 ], [ -86.649356655884958, 14.409456692472361 ], [ -86.638892177831735, 14.411058661128266 ], [ -86.635093960417919, 14.410438544403291 ], [ -86.630701463801472, 14.40806142849209 ], [ -86.62065039689827, 14.396744289717162 ], [ -86.615689460400233, 14.38651235655999 ], [ -86.611942918930538, 14.382378241462675 ], [ -86.607317878317417, 14.38113800711335 ], [ -86.599953985687876, 14.382429918306059 ], [ -86.578921677693245, 14.380104478338978 ], [ -86.522904426398156, 14.364859930941066 ], [ -86.502647263860126, 14.345119534139201 ], [ -86.498978237655535, 14.34279409417212 ], [ -86.47577552022409, 14.336644599268823 ], [ -86.457120327241284, 14.323157050157704 ], [ -86.452521125049884, 14.318041083129458 ], [ -86.447818570070922, 14.311478176176877 ], [ -86.442134162261766, 14.297732245546683 ], [ -86.437354092017699, 14.293753160080257 ], [ -86.428155686735522, 14.290755927444081 ], [ -86.354465095287878, 14.286363429928315 ], [ -86.342863735672836, 14.288068752271101 ], [ -86.335732387939345, 14.290962633019092 ], [ -86.313098111288809, 14.304656886805844 ], [ -86.303641323588181, 14.313338528150553 ], [ -86.298706223713225, 14.316852524724197 ], [ -86.292970139959948, 14.319384670266288 ], [ -86.287311570572513, 14.3211933462959 ], [ -86.276640387843599, 14.327601222718215 ], [ -86.26199011874894, 14.334732571351083 ], [ -86.242766485884601, 14.340106919898403 ], [ -86.232482875883989, 14.341398831091169 ], [ -86.206592984178883, 14.34103709588527 ], [ -86.193725551792738, 14.338453274399058 ], [ -86.184940558559902, 14.334009100939227 ], [ -86.175974698173775, 14.323570461307725 ], [ -86.149232143948268, 14.276441555133658 ], [ -86.142178310580562, 14.268948473093531 ], [ -86.113782110855709, 14.258613186249534 ], [ -86.088460659931513, 14.252877102496257 ], [ -86.080140753792762, 14.253393866433782 ], [ -86.07623918269212, 14.257321275056768 ], [ -86.072699347696698, 14.265692857139641 ], [ -86.070012173423038, 14.269000149037652 ], [ -86.066549851894138, 14.271739000154696 ], [ -86.062312384908637, 14.272927558559957 ], [ -86.05791988829219, 14.272772528929067 ], [ -86.040298224983076, 14.268896796250147 ], [ -86.029601202933179, 14.263419094015944 ], [ -86.019317592932566, 14.254634100783107 ], [ -86.006760219808257, 14.234635322462168 ], [ -86.000765753636585, 14.221457830814245 ], [ -85.99699337374517, 14.207815252971557 ], [ -85.99531388982416, 14.198720201376204 ], [ -85.990507982057693, 14.190968736018363 ], [ -85.982730679177507, 14.18450918185323 ], [ -85.944412604657941, 14.167507636168466 ], [ -85.924543015747588, 14.141824449138994 ], [ -85.913070848241034, 14.132781073487763 ], [ -85.906275397291722, 14.131334133563371 ], [ -85.892658657870754, 14.131850898400216 ], [ -85.885372281405637, 14.134383043042988 ], [ -85.880178799112286, 14.138103746091019 ], [ -85.877491624838626, 14.14234121307652 ], [ -85.87640642012019, 14.146837063379735 ], [ -85.875450405711661, 14.157120673380348 ], [ -85.873745083368874, 14.16182322835931 ], [ -85.871316290614288, 14.165543932306605 ], [ -85.867802294040644, 14.168437812155275 ], [ -85.857518684040031, 14.173037014346733 ], [ -85.853022833736759, 14.175827542307218 ], [ -85.849172940378878, 14.179289862936798 ], [ -85.844857958128273, 14.18202871315458 ], [ -85.8364863760454, 14.18301056598483 ], [ -85.826771205926377, 14.181356920485484 ], [ -85.813593716077094, 14.172468573565823 ], [ -85.803749355648222, 14.167507636168466 ], [ -85.790546027377218, 14.165130520257264 ], [ -85.784396531574657, 14.166629137025041 ], [ -85.779771490961537, 14.170401516017137 ], [ -85.768015102614868, 14.193552558403837 ], [ -85.763725958785926, 14.197893378176843 ], [ -85.75747311109518, 14.198720201376204 ], [ -85.710111660025063, 14.188746649738107 ], [ -85.672129483189053, 14.177067775757223 ], [ -85.665230678552973, 14.176395982188808 ], [ -85.662155930651636, 14.177429510963123 ], [ -85.660295579577337, 14.18492259390257 ], [ -85.655437994967485, 14.186007799520326 ], [ -85.646911384153043, 14.183423977134851 ], [ -85.631279263127453, 14.170349840073072 ], [ -85.621564093907807, 14.159704494866503 ], [ -85.615492113370294, 14.147353827317261 ], [ -85.61140967511642, 14.126476548953576 ], [ -85.61140967511642, 14.114797674972692 ], [ -85.609704352773633, 14.104875800178036 ], [ -85.605802781672992, 14.097227688507019 ], [ -85.5959325828224, 14.089579575936682 ], [ -85.587793544736257, 14.085187079320235 ], [ -85.58014543306524, 14.079295965936069 ], [ -85.575649583661345, 14.074955146163063 ], [ -85.563273077690383, 14.042347316975111 ], [ -85.563145912999914, 14.042012281000098 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-CH", "NAME_1": "Choluteca" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -86.732715272291955, 13.268469503364884 ], [ -86.739842895999942, 13.26371348100011 ], [ -86.74929968299989, 13.26128468800006 ], [ -86.758653117999927, 13.264178569000052 ], [ -86.816220662999882, 13.291928813000084 ], [ -86.833428914999871, 13.293349915000078 ], [ -86.84950028499992, 13.288828227000053 ], [ -86.862729451999911, 13.279939880000128 ], [ -86.910788533999977, 13.239580587000063 ], [ -86.918850057999862, 13.229762065000088 ], [ -86.925981404999902, 13.216352031000056 ], [ -86.933216104999872, 13.18818837500001 ], [ -86.934921427999939, 13.185527038000075 ], [ -86.933061076999934, 13.1797134400001 ], [ -86.925516317999978, 13.163642070000037 ], [ -86.923707641999897, 13.161135763000047 ], [ -86.932337605999919, 13.108529155000056 ], [ -86.929805460999944, 13.102224630000137 ], [ -86.924172729999924, 13.099795838000077 ], [ -86.920245320999953, 13.096178487000103 ], [ -86.922932494999969, 13.08638580400013 ], [ -86.927996785999937, 13.081243998000048 ], [ -86.942724568999949, 13.074060975000094 ], [ -86.9484089769999, 13.06969431600001 ], [ -86.97181840099995, 13.033882548000079 ], [ -86.983187214999958, 13.021867777000111 ], [ -87.008767049999904, 13.00608062800012 ], [ -87.029618489999876, 12.996081238000102 ], [ -87.035044515999942, 12.979777324000068 ], [ -87.04685257999995, 12.980552470000077 ], [ -87.069848592999904, 12.994375915000134 ], [ -87.084653890999931, 12.995926209000061 ], [ -87.314035610999952, 12.98155345300006 ], [ -87.313628709999932, 12.981838283000059 ], [ -87.303944464999915, 12.988470770000049 ], [ -87.300811326999906, 13.001247463000084 ], [ -87.293568488999938, 13.011053778000075 ], [ -87.282826300999943, 13.01821523600006 ], [ -87.269154425999943, 13.023220119000086 ], [ -87.269154425999943, 13.029445705000057 ], [ -87.296783006999931, 13.030340887000079 ], [ -87.316680467999902, 13.034206447000088 ], [ -87.331776495999918, 13.042669989000046 ], [ -87.344838019999941, 13.057318427000041 ], [ -87.351348436999899, 13.067206122000073 ], [ -87.352813279999907, 13.072536526000079 ], [ -87.351063605999911, 13.088405666000085 ], [ -87.344715949999909, 13.090765692000048 ], [ -87.314076300999943, 13.095404364000046 ], [ -87.303944464999915, 13.098334052000041 ], [ -87.361805792999917, 13.113348700000074 ], [ -87.394561326999906, 13.116848049000055 ], [ -87.4131160149999, 13.111354885000083 ], [ -87.419341600999928, 13.111354885000083 ], [ -87.42210852799991, 13.14992910400008 ], [ -87.43578040299991, 13.189398505000042 ], [ -87.455067511999914, 13.224310614000046 ], [ -87.474598761999914, 13.249172268000052 ], [ -87.480824347999942, 13.26516347900008 ], [ -87.482045050999943, 13.26593659100007 ], [ -87.484527147999927, 13.270086981000077 ], [ -87.490345831999946, 13.269720770000049 ], [ -87.496978318999936, 13.268337307000081 ], [ -87.501942511999914, 13.269598700000074 ], [ -87.508900519999941, 13.278631903000075 ], [ -87.512237107999908, 13.286688544000071 ], [ -87.510487433999913, 13.294948635000083 ], [ -87.501942511999914, 13.304388739000046 ], [ -87.493438279999907, 13.309759833000044 ], [ -87.476673956999946, 13.317328192000048 ], [ -87.467762824999909, 13.324896552000041 ], [ -87.447783982999908, 13.352565822000088 ], [ -87.440419074999909, 13.359035549000055 ], [ -87.426909959999932, 13.356024481000077 ], [ -87.411122199999909, 13.359808661000045 ], [ -87.379017706999946, 13.372015692000048 ], [ -87.380401170999903, 13.380438544000071 ], [ -87.380360480999911, 13.386297919000071 ], [ -87.379017706999946, 13.393133856000077 ], [ -87.37902787973286, 13.393291326733333 ], [ -87.358719042150085, 13.408484198187182 ], [ -87.347789476103401, 13.432978826811393 ], [ -87.349546475289571, 13.453339342136928 ], [ -87.360682746011889, 13.474475002019688 ], [ -87.366263801033597, 13.489512843842647 ], [ -87.367684903435531, 13.498814601912329 ], [ -87.364429286582265, 13.519381821913555 ], [ -87.400266893302444, 13.545530096936432 ], [ -87.414555427191203, 13.575915838944809 ], [ -87.415718146275424, 13.582582099584215 ], [ -87.419800585428675, 13.590695299248637 ], [ -87.424373949198355, 13.598033352557138 ], [ -87.42181596613392, 13.637824205422703 ], [ -87.426260138694431, 13.644542141106911 ], [ -87.433055589643743, 13.649348048873321 ], [ -87.441504686092401, 13.653585516758199 ], [ -87.459126350300835, 13.667899889068622 ], [ -87.46114173010676, 13.670173652192261 ], [ -87.465250006782355, 13.683506170773171 ], [ -87.465405036413301, 13.697820543083594 ], [ -87.459901495757379, 13.719472967803199 ], [ -87.457524379846234, 13.745414537251065 ], [ -87.454372117579169, 13.756886704757619 ], [ -87.443339199644356, 13.760297349443135 ], [ -87.42390886120495, 13.760607407805594 ], [ -87.412229987224123, 13.757506822381913 ], [ -87.40101620213602, 13.754974676839822 ], [ -87.396546190254469, 13.756008206513513 ], [ -87.390732591236088, 13.756111558401699 ], [ -87.386727668247261, 13.755078030526647 ], [ -87.387606167390686, 13.750892239485268 ], [ -87.394815030389339, 13.733942368845248 ], [ -87.392825487206437, 13.721126614201864 ], [ -87.373601854342098, 13.702781480480951 ], [ -87.360088466809259, 13.690120754569136 ], [ -87.31947079074439, 13.694874986391483 ], [ -87.307533535244431, 13.688777167432306 ], [ -87.29771501323728, 13.684332993972475 ], [ -87.263427701027581, 13.688415432226407 ], [ -87.214231737304829, 13.671103827279808 ], [ -87.224127773677822, 13.628625800140526 ], [ -87.217280645885069, 13.615810045497199 ], [ -87.20632524321536, 13.612244371180793 ], [ -87.197591925926645, 13.60289093716699 ], [ -87.191287401392458, 13.597516587720349 ], [ -87.186894903876691, 13.578603014117789 ], [ -87.184285243968816, 13.566304023411931 ], [ -87.170125902188602, 13.558190822848189 ], [ -87.124004686367186, 13.555555325417913 ], [ -87.115607265862593, 13.549147447196901 ], [ -87.115116340346788, 13.539742336339714 ], [ -87.106615567054746, 13.520880439580594 ], [ -87.088916389379847, 13.507341212726772 ], [ -87.076617397774669, 13.505790920014931 ], [ -87.069873622769478, 13.508116359982012 ], [ -87.039203660820249, 13.525479640872732 ], [ -87.016543544848673, 13.550697739908742 ], [ -87.014166428937529, 13.56568390488826 ], [ -87.010574917098722, 13.573797105452059 ], [ -86.999516160742189, 13.583874009877661 ], [ -86.984736701337681, 13.588421536124997 ], [ -86.976933560035775, 13.593330797578233 ], [ -86.965952318045026, 13.601857408392675 ], [ -86.950010138656978, 13.618703925345869 ], [ -86.942517055717531, 13.629504299283951 ], [ -86.937943691947794, 13.638909410141139 ], [ -86.935075649621524, 13.657202867018668 ], [ -86.932853563341268, 13.6605618348608 ], [ -86.926135626757741, 13.658701483786444 ], [ -86.921148850938721, 13.656531073450253 ], [ -86.891383225655318, 13.659218247723913 ], [ -86.887352465144147, 13.651880195314732 ], [ -86.848827684150308, 13.676374823039623 ], [ -86.84071448358651, 13.679372057474438 ], [ -86.823609585114241, 13.6809740261304 ], [ -86.815987311864944, 13.6806122909245 ], [ -86.809191860915632, 13.681852525273825 ], [ -86.80120785156106, 13.694306544711253 ], [ -86.794205695036794, 13.700145982151355 ], [ -86.786247525003262, 13.701489570187505 ], [ -86.771881476748717, 13.707587389146681 ], [ -86.771167593109908, 13.70789040401894 ], [ -86.77405269399992, 13.654594015000029 ], [ -86.772140665999899, 13.645524801000064 ], [ -86.768213256999843, 13.640357158000057 ], [ -86.764129565327153, 13.637335555191726 ], [ -86.755397501999965, 13.630874532000078 ], [ -86.751573445999924, 13.624414978000033 ], [ -86.750901651999925, 13.608421122000081 ], [ -86.757102823999929, 13.576407573000083 ], [ -86.756586059999876, 13.559380188000148 ], [ -86.724288289999919, 13.439413351000056 ], [ -86.725941935999856, 13.423832906000115 ], [ -86.738654337999918, 13.396211853000111 ], [ -86.740204630999926, 13.381923320000041 ], [ -86.736380574999885, 13.371949768000121 ], [ -86.730437784999879, 13.368900858000103 ], [ -86.723616496999909, 13.367324727000067 ], [ -86.71715694199986, 13.361640320000035 ], [ -86.709922241999891, 13.348902079000069 ], [ -86.707803507999927, 13.342830099000111 ], [ -86.701860717999921, 13.314201355000137 ], [ -86.704031128999901, 13.298827616000068 ], [ -86.711782592999896, 13.285675965000081 ], [ -86.725476847999914, 13.273299459000029 ], [ -86.732715272291955, 13.268469503364884 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-CR", "NAME_1": "Cortés" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.241585855999858, 15.688242493000089 ], [ -88.234919596999958, 15.701575013000095 ], [ -88.23574641999997, 15.71242706300005 ], [ -88.232619995999926, 15.721418762 ], [ -88.22093665299991, 15.725653387000079 ], [ -88.21507727799991, 15.723211981000077 ], [ -88.169748501999948, 15.691961981000077 ], [ -88.145253058999913, 15.684515692000048 ], [ -88.118885870999918, 15.695868231000077 ], [ -88.060902472999942, 15.755764065000051 ], [ -88.036284959999932, 15.77094147300005 ], [ -88.041615363999938, 15.786688544000071 ], [ -88.031605597999942, 15.789862372000073 ], [ -87.992258266999897, 15.78461334800005 ], [ -87.93390865799995, 15.818793036000045 ], [ -87.926665818999936, 15.83234284100007 ], [ -87.924549933999913, 15.842189846000053 ], [ -87.930165167999917, 15.846747137000079 ], [ -87.941314256999931, 15.849839585000041 ], [ -87.950428839999915, 15.856919664000088 ], [ -87.954579230999911, 15.86399974200009 ], [ -87.950998501999948, 15.867173570000091 ], [ -87.908762173999946, 15.868068752000056 ], [ -87.891957160999937, 15.872951565000051 ], [ -87.875559048999946, 15.884263414000088 ], [ -87.846058722999942, 15.893866278000075 ], [ -87.76008053299995, 15.899562893000052 ], [ -87.742095506999931, 15.904486395000049 ], [ -87.736317511999914, 15.91860586100006 ], [ -87.728357527078174, 15.921021546507177 ], [ -87.725156623179601, 15.897324530202866 ], [ -87.730686001357867, 15.887867743401614 ], [ -87.740530361786739, 15.882028306860832 ], [ -87.751614955665673, 15.872209783954361 ], [ -87.757376878739933, 15.862804673996493 ], [ -87.766446091913622, 15.838620102835478 ], [ -87.773732469278002, 15.828491523365074 ], [ -87.789493780613441, 15.81283356391782 ], [ -87.794868130060138, 15.803893541054038 ], [ -87.794661423585808, 15.79335154953435 ], [ -87.77952022987472, 15.776453354838452 ], [ -87.775437791620789, 15.763224189045047 ], [ -87.767376267900431, 15.765291245694414 ], [ -87.76117509615375, 15.760433661084562 ], [ -87.757867805155058, 15.751131903914199 ], [ -87.758410406614928, 15.739814765139272 ], [ -87.764275681577431, 15.729686183870285 ], [ -87.773241542862877, 15.724621893685423 ], [ -87.787581752695701, 15.721004544324273 ], [ -87.817967494704078, 15.701367499410537 ], [ -87.823548549725786, 15.691548977403386 ], [ -87.805461799322586, 15.687879950299475 ], [ -87.819750332311969, 15.671601874127191 ], [ -87.803446417717964, 15.653566798768736 ], [ -87.777349820437848, 15.63320628524184 ], [ -87.762208624928064, 15.610158596541964 ], [ -87.76463741678333, 15.606851305543273 ], [ -87.772001309412872, 15.581168118513858 ], [ -87.771252000579352, 15.577757472929022 ], [ -87.777763230688549, 15.574036769880991 ], [ -87.78486874089964, 15.574863593080352 ], [ -87.790837368649647, 15.577085680259927 ], [ -87.793912115651608, 15.577654120141517 ], [ -87.800423346660125, 15.564114895086334 ], [ -87.804505784913999, 15.547785142070609 ], [ -87.809776780673872, 15.533677476234516 ], [ -87.819931200364579, 15.52706289333787 ], [ -87.830938279877671, 15.50851105404189 ], [ -87.82747595924809, 15.494455064149861 ], [ -87.818639289171813, 15.482259426231508 ], [ -87.813549159665968, 15.469133613225665 ], [ -87.816417201992238, 15.451563625860615 ], [ -87.82437537292509, 15.45301056578495 ], [ -87.835124070919107, 15.460348619093509 ], [ -87.84633785690653, 15.460451971880957 ], [ -87.852719895806501, 15.4516669777488 ], [ -87.84597612170063, 15.445879218051459 ], [ -87.833728806938893, 15.439729723148162 ], [ -87.823781093722459, 15.429962877085075 ], [ -87.820189581883653, 15.416268622399002 ], [ -87.823858608987621, 15.408052069947075 ], [ -87.83848303876124, 15.396114814447117 ], [ -87.863003505807114, 15.356375637525616 ], [ -87.869953986387372, 15.347952379498679 ], [ -87.873907233432078, 15.345006821907305 ], [ -87.8785581115676, 15.342681382839544 ], [ -87.887627325640551, 15.335808417524447 ], [ -87.893570115868158, 15.332501126525756 ], [ -87.90687679692661, 15.32893545220935 ], [ -87.911579352804893, 15.32661001224227 ], [ -87.913310512670023, 15.323406073131764 ], [ -87.912587043157487, 15.320253810864642 ], [ -87.911269294442377, 15.316998195810072 ], [ -87.911140103233151, 15.313535875180492 ], [ -87.913749763141027, 15.308833320201529 ], [ -87.92576453300677, 15.296430975808846 ], [ -87.924110886608105, 15.289816392012881 ], [ -87.924059210664041, 15.282891750753663 ], [ -87.92553198901004, 15.276070461382687 ], [ -87.928374192914646, 15.26971426000506 ], [ -87.926462164996906, 15.259120592541308 ], [ -87.935117967020517, 15.244754544286764 ], [ -87.930725471303447, 15.237313137291437 ], [ -87.926849737725206, 15.237829902128283 ], [ -87.921036139606144, 15.240465400457822 ], [ -87.918374802854828, 15.239070136477608 ], [ -87.917496303711403, 15.237778225284842 ], [ -87.917186245348944, 15.225840968885564 ], [ -87.920596890034403, 15.211578274317901 ], [ -87.919795905256819, 15.204653632159363 ], [ -87.922974005945605, 15.194938462939717 ], [ -87.92310319715483, 15.190804347842345 ], [ -87.918374802854828, 15.187807115206169 ], [ -87.897755906909538, 15.193284817440372 ], [ -87.878713142097808, 15.191837877516036 ], [ -87.867861091316286, 15.18935740791801 ], [ -87.853081631012458, 15.178195298774028 ], [ -87.848689134396011, 15.173802802157581 ], [ -87.846079475387455, 15.16930695185431 ], [ -87.845149299400646, 15.165172838555634 ], [ -87.842565477015114, 15.160418605833968 ], [ -87.836932746049399, 15.159591783533983 ], [ -87.822153285745514, 15.159850165053058 ], [ -87.817864142815949, 15.157989813978702 ], [ -87.814427659708713, 15.154785874868196 ], [ -87.810991176601476, 15.153700670149817 ], [ -87.799803229935094, 15.153390610887982 ], [ -87.796521775559484, 15.149204819846545 ], [ -87.794067146181817, 15.139593004313667 ], [ -87.788434414316725, 15.137474269921597 ], [ -87.783395961654264, 15.136854153196623 ], [ -87.767686327162266, 15.139696357101172 ], [ -87.738359952349924, 15.11111929022303 ], [ -87.737300585153889, 15.104556383270449 ], [ -87.733321498788143, 15.094376126057341 ], [ -87.732313809334812, 15.08646963106861 ], [ -87.732158779703923, 15.081457016827869 ], [ -87.733786586781548, 15.077684637835773 ], [ -87.737429776363058, 15.075152493193002 ], [ -87.740065273793334, 15.067866115828565 ], [ -87.741279669720939, 15.061458238506873 ], [ -87.735879482751898, 15.016551419512382 ], [ -87.735801968386113, 14.983788559794164 ], [ -87.740685391417685, 14.962497870280458 ], [ -87.757221849109044, 14.947925116450961 ], [ -87.802593756996259, 14.915523992837961 ], [ -87.821455654654699, 14.906583970873555 ], [ -87.84367652105459, 14.901416327001868 ], [ -87.847423061624966, 14.898832506415033 ], [ -87.869437221550527, 14.876818346489472 ], [ -87.883674078595845, 14.858214830350107 ], [ -87.96297156438618, 14.803541165292529 ], [ -87.973668586436077, 14.81046580745101 ], [ -87.980283169332779, 14.820129298928009 ], [ -87.985812548410365, 14.836407375999613 ], [ -87.987879605059732, 14.877645168789513 ], [ -87.995631070417573, 14.900847887120278 ], [ -88.026972825935161, 14.928494778011554 ], [ -88.048909470595561, 14.929166572479346 ], [ -88.053586188052122, 14.930820217079315 ], [ -88.056712612796844, 14.94694326452003 ], [ -88.049555426641632, 14.98895620456517 ], [ -88.043974371619925, 14.997327785748723 ], [ -88.030745204927257, 15.04254466400505 ], [ -88.018136155858883, 15.055825507541101 ], [ -88.022296109377919, 15.063008531218713 ], [ -88.029065721006191, 15.065644029548309 ], [ -88.036016201586392, 15.071948554082496 ], [ -88.043018358110714, 15.075255845980507 ], [ -88.065342577298111, 15.082697252076514 ], [ -88.094048835385422, 15.101042384898108 ], [ -88.10593441404194, 15.114271552490152 ], [ -88.113530849768892, 15.130859687024895 ], [ -88.10805314843401, 15.149824937470896 ], [ -88.067125414006625, 15.192354641453505 ], [ -88.061518520563254, 15.207754218482364 ], [ -88.081439785417729, 15.213800361497476 ], [ -88.094513923378827, 15.222016913050084 ], [ -88.102187872572244, 15.227908027333569 ], [ -88.123814459769505, 15.270747788779431 ], [ -88.130945808402316, 15.367951157819675 ], [ -88.134330613766792, 15.37301544800448 ], [ -88.158954433600229, 15.377666327039321 ], [ -88.169083014869216, 15.382162177342593 ], [ -88.182544724659294, 15.39115387615044 ], [ -88.197634244224957, 15.403401190912234 ], [ -88.227115647768926, 15.420557766227887 ], [ -88.233678554721507, 15.427172350023909 ], [ -88.238096889759618, 15.433476874558096 ], [ -88.240112271364239, 15.439161282367252 ], [ -88.241145799239234, 15.445052394852098 ], [ -88.240680712145149, 15.452132065742205 ], [ -88.238329433756348, 15.464017646197419 ], [ -88.238665331439904, 15.469236965113851 ], [ -88.240654872824109, 15.478487047239412 ], [ -88.239802212102404, 15.486806952478844 ], [ -88.240939093664224, 15.490734361101886 ], [ -88.2477862205576, 15.496212063336031 ], [ -88.261997240080575, 15.504015203738675 ], [ -88.356565110791223, 15.532385565941127 ], [ -88.409921027133691, 15.540447088762107 ], [ -88.466816779370845, 15.520758367904364 ], [ -88.467433936427028, 15.520739666502379 ], [ -88.398992269999923, 15.572797343000033 ], [ -88.352560994999919, 15.616903178000101 ], [ -88.322304443999911, 15.667261861000085 ], [ -88.316671712999948, 15.674599914000069 ], [ -88.295587728999948, 15.675013326000098 ], [ -88.279697224999921, 15.680749410000047 ], [ -88.264995279999937, 15.688604228000074 ], [ -88.247761190999938, 15.695683899000088 ], [ -88.241585855999858, 15.688242493000089 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-SB", "NAME_1": "Santa Bárbara" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.76089940199995, 15.299961814000071 ], [ -88.674195108999896, 15.365058086000076 ], [ -88.587378702999928, 15.430299581 ], [ -88.500019693999974, 15.495954489000027 ], [ -88.467433936427028, 15.520739666502379 ], [ -88.466816779370845, 15.520758367904364 ], [ -88.409921027133691, 15.540447088762107 ], [ -88.356565110791223, 15.532385565941127 ], [ -88.261997240080575, 15.504015203738675 ], [ -88.2477862205576, 15.496212063336031 ], [ -88.240939093664224, 15.490734361101886 ], [ -88.239802212102404, 15.486806952478844 ], [ -88.240654872824109, 15.478487047239412 ], [ -88.238665331439904, 15.469236965113851 ], [ -88.238329433756348, 15.464017646197419 ], [ -88.240680712145149, 15.452132065742205 ], [ -88.241145799239234, 15.445052394852098 ], [ -88.240112271364239, 15.439161282367252 ], [ -88.238096889759618, 15.433476874558096 ], [ -88.233678554721507, 15.427172350023909 ], [ -88.227115647768926, 15.420557766227887 ], [ -88.197634244224957, 15.403401190912234 ], [ -88.182544724659294, 15.39115387615044 ], [ -88.169083014869216, 15.382162177342593 ], [ -88.158954433600229, 15.377666327039321 ], [ -88.134330613766792, 15.37301544800448 ], [ -88.130945808402316, 15.367951157819675 ], [ -88.123814459769505, 15.270747788779431 ], [ -88.102187872572244, 15.227908027333569 ], [ -88.094513923378827, 15.222016913050084 ], [ -88.081439785417729, 15.213800361497476 ], [ -88.061518520563254, 15.207754218482364 ], [ -88.067125414006625, 15.192354641453505 ], [ -88.10805314843401, 15.149824937470896 ], [ -88.113530849768892, 15.130859687024895 ], [ -88.10593441404194, 15.114271552490152 ], [ -88.094048835385422, 15.101042384898108 ], [ -88.065342577298111, 15.082697252076514 ], [ -88.043018358110714, 15.075255845980507 ], [ -88.036016201586392, 15.071948554082496 ], [ -88.029065721006191, 15.065644029548309 ], [ -88.022296109377919, 15.063008531218713 ], [ -88.018136155858883, 15.055825507541101 ], [ -88.030745204927257, 15.04254466400505 ], [ -88.043974371619925, 14.997327785748723 ], [ -88.049555426641632, 14.98895620456517 ], [ -88.056712612796844, 14.94694326452003 ], [ -88.053586188052122, 14.930820217079315 ], [ -88.048909470595561, 14.929166572479346 ], [ -88.026972825935161, 14.928494778011554 ], [ -87.995631070417573, 14.900847887120278 ], [ -87.987879605059732, 14.877645168789513 ], [ -87.985812548410365, 14.836407375999613 ], [ -87.98705278186037, 14.792585760824181 ], [ -88.02252865337465, 14.786281236289994 ], [ -88.052966071327091, 14.755378730344091 ], [ -88.058417935139573, 14.751968084759312 ], [ -88.069812588280286, 14.747213852936966 ], [ -88.074773525677642, 14.742459622013939 ], [ -88.077331508742134, 14.735224921492943 ], [ -88.077874112000643, 14.721375637175925 ], [ -88.071595424988857, 14.710885322499621 ], [ -88.06224199097511, 14.68561554572085 ], [ -88.074954392830932, 14.664841620144614 ], [ -88.093351203395287, 14.654454657356553 ], [ -88.100430874285394, 14.649287014384186 ], [ -88.129628058787887, 14.652025865501287 ], [ -88.16321773990677, 14.658640448397932 ], [ -88.207452766232166, 14.654764715719068 ], [ -88.265950487125281, 14.64877025044666 ], [ -88.34377519367024, 14.654299627725607 ], [ -88.322277797682204, 14.688922838518181 ], [ -88.316800096347379, 14.719515286101569 ], [ -88.32336300329996, 14.731194159183076 ], [ -88.335739509270923, 14.729695543314676 ], [ -88.352508510959012, 14.731814276807427 ], [ -88.367003750422725, 14.739514065321828 ], [ -88.383049282598279, 14.765817369076331 ], [ -88.388837043194997, 14.772225247297285 ], [ -88.360518357835929, 14.819199123840463 ], [ -88.381033901893034, 14.831188056183805 ], [ -88.407776455219221, 14.830619615402895 ], [ -88.420230475555968, 14.847569485143595 ], [ -88.422400885892159, 14.849843248267291 ], [ -88.433640510301302, 14.854545803246197 ], [ -88.442347989168354, 14.853874010577101 ], [ -88.453587612678177, 14.843228665370589 ], [ -88.463716193047844, 14.827415676292389 ], [ -88.479632534913549, 14.814393215174732 ], [ -88.487306485006286, 14.811912747375402 ], [ -88.505625780305479, 14.834443671238432 ], [ -88.533220995252691, 14.878368639201312 ], [ -88.555105963969027, 14.934799303445061 ], [ -88.601692267783903, 14.941672267860838 ], [ -88.609262865089136, 14.937693183293732 ], [ -88.644609545394189, 14.927357896449735 ], [ -88.679878710434139, 14.920950019128043 ], [ -88.68587317570649, 14.922913722989904 ], [ -88.692436082659071, 14.926944485299714 ], [ -88.695381639351183, 14.932525540321421 ], [ -88.697552048787998, 14.938830063956289 ], [ -88.699877488755078, 14.943532619834514 ], [ -88.70225460466628, 14.952369289910791 ], [ -88.689413010701855, 14.98513214783037 ], [ -88.679361944697973, 15.019496975305174 ], [ -88.677708299198628, 15.037428696976747 ], [ -88.668974981909855, 15.056393948322068 ], [ -88.644583706073149, 15.077012844267358 ], [ -88.642361619792894, 15.084144192000849 ], [ -88.642620002211288, 15.091482245309351 ], [ -88.644945441279049, 15.097270005906012 ], [ -88.652981126577686, 15.109362291036859 ], [ -88.657399461615853, 15.114426581221721 ], [ -88.66391069172505, 15.139541327470283 ], [ -88.651715053806697, 15.155095933230712 ], [ -88.652671068215227, 15.158558253860292 ], [ -88.654660611398072, 15.162795721745169 ], [ -88.662722134219109, 15.168273423979315 ], [ -88.679103563178899, 15.175663154131257 ], [ -88.699696620702468, 15.196798814014016 ], [ -88.718041755322758, 15.217159329339552 ], [ -88.716491461711598, 15.230905259969745 ], [ -88.715173712996432, 15.237313137291437 ], [ -88.715793829721463, 15.245271308224289 ], [ -88.758013475341613, 15.295655829452926 ], [ -88.76089940199995, 15.299961814000071 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-CP", "NAME_1": "Copán" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -89.146940319140413, 15.071284391261656 ], [ -89.140523234999904, 15.076393534000132 ], [ -89.109827433999868, 15.09145721400003 ], [ -89.008283243999898, 15.124400940000086 ], [ -88.97342749099991, 15.140394796000123 ], [ -88.847026936999868, 15.235298564000104 ], [ -88.76089940199995, 15.299961814000071 ], [ -88.758013475341613, 15.295655829452926 ], [ -88.715793829721463, 15.245271308224289 ], [ -88.715173712996432, 15.237313137291437 ], [ -88.716491461711598, 15.230905259969745 ], [ -88.718041755322758, 15.217159329339552 ], [ -88.699696620702468, 15.196798814014016 ], [ -88.679103563178899, 15.175663154131257 ], [ -88.662722134219109, 15.168273423979315 ], [ -88.654660611398072, 15.162795721745169 ], [ -88.652671068215227, 15.158558253860292 ], [ -88.651715053806697, 15.155095933230712 ], [ -88.66391069172505, 15.139541327470283 ], [ -88.657399461615853, 15.114426581221721 ], [ -88.652981126577686, 15.109362291036859 ], [ -88.644945441279049, 15.097270005906012 ], [ -88.642620002211288, 15.091482245309351 ], [ -88.642361619792894, 15.084144192000849 ], [ -88.644583706073149, 15.077012844267358 ], [ -88.668974981909855, 15.056393948322068 ], [ -88.677708299198628, 15.037428696976747 ], [ -88.679361944697973, 15.019496975305174 ], [ -88.689413010701855, 14.98513214783037 ], [ -88.70225460466628, 14.952369289910791 ], [ -88.699877488755078, 14.943532619834514 ], [ -88.697552048787998, 14.938830063956289 ], [ -88.695381639351183, 14.932525540321421 ], [ -88.692436082659071, 14.926944485299714 ], [ -88.68587317570649, 14.922913722989904 ], [ -88.679878710434139, 14.920950019128043 ], [ -88.644609545394189, 14.927357896449735 ], [ -88.639286871891613, 14.895783596036097 ], [ -88.643317634201424, 14.869273585807321 ], [ -88.656624315259933, 14.859765123061948 ], [ -88.654815640129698, 14.84901642506793 ], [ -88.656856859256607, 14.844572252507419 ], [ -88.664117398199323, 14.835890611162768 ], [ -88.669543422690765, 14.830877996922027 ], [ -88.673832567419026, 14.823281562094394 ], [ -88.676313036117733, 14.815013332799083 ], [ -88.677811651986133, 14.801887518893864 ], [ -88.676803961633482, 14.787004705802531 ], [ -88.67006018842693, 14.775945950345317 ], [ -88.659776576627678, 14.753570055213856 ], [ -88.655513272119777, 14.735483303012018 ], [ -88.654970668861267, 14.729747219258741 ], [ -88.655900844848077, 14.723856105874574 ], [ -88.663729824571703, 14.723080960417974 ], [ -88.692048509031451, 14.715071113541057 ], [ -88.728196174114146, 14.712487291155526 ], [ -88.778089768927657, 14.718223374908803 ], [ -88.792843390809821, 14.713520819929897 ], [ -88.794703741884177, 14.698586330894443 ], [ -88.794109462681547, 14.694452215797128 ], [ -88.783283251221064, 14.668975735241986 ], [ -88.752768317104142, 14.640760403569743 ], [ -88.745559455004809, 14.630270087094857 ], [ -88.733596361083187, 14.609237779100226 ], [ -88.730521613181907, 14.54877635344593 ], [ -88.754318609815982, 14.546760972740685 ], [ -88.773774786677052, 14.54991323500775 ], [ -88.781810471975689, 14.550016587795255 ], [ -88.790983038836146, 14.54856964787092 ], [ -88.800594855268344, 14.545985826384765 ], [ -88.817079637015638, 14.539991360213094 ], [ -88.824340175958355, 14.535185452446683 ], [ -88.827724982222151, 14.527433987088841 ], [ -88.827621630333965, 14.515496730689563 ], [ -88.827208218284625, 14.511414293334951 ], [ -88.82483110237348, 14.508313707011951 ], [ -88.824030117595839, 14.50500641511394 ], [ -88.826665615925435, 14.50330109277121 ], [ -88.836820034716823, 14.500303860135034 ], [ -88.849196539788466, 14.502680976046179 ], [ -88.861211310553529, 14.512551173997451 ], [ -88.874802211552776, 14.515910141839584 ], [ -88.892656419757941, 14.523248196047405 ], [ -88.909916347861156, 14.540869859356519 ], [ -88.923223028919608, 14.561282049726799 ], [ -88.924824999374209, 14.568723455822806 ], [ -88.92425655769398, 14.594871730845682 ], [ -88.930561083127486, 14.608565986431131 ], [ -88.994562343777147, 14.655643214862437 ], [ -89.00308895459159, 14.669854234385411 ], [ -89.010271980067785, 14.699981593975394 ], [ -89.02564571777566, 14.720807197294278 ], [ -89.08556454107071, 14.728920396059436 ], [ -89.098664516554152, 14.724476223498925 ], [ -89.13103980174543, 14.715071113541057 ], [ -89.14621323435324, 14.710857663850106 ], [ -89.150522624999923, 14.717294007000064 ], [ -89.159669352999913, 14.725122986000088 ], [ -89.170547240999952, 14.738791403000107 ], [ -89.189409139999896, 14.783000590000114 ], [ -89.198814249999941, 14.798090108000025 ], [ -89.218968058999934, 14.821680400000034 ], [ -89.227675537999886, 14.83457367000004 ], [ -89.232429768999879, 14.848500468000026 ], [ -89.231447916999912, 14.867310690000124 ], [ -89.223618937999902, 14.879015401000103 ], [ -89.198814249999941, 14.899815165000064 ], [ -89.189214955999915, 14.913059034000113 ], [ -89.181528482999852, 14.923663839000127 ], [ -89.169151977999888, 14.952060038000056 ], [ -89.169100300999872, 14.97841501900011 ], [ -89.18858231699997, 14.996088359000026 ], [ -89.172769328999976, 15.042209575000058 ], [ -89.16080623499991, 15.060244649000055 ], [ -89.146940319140413, 15.071284391261656 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-CL", "NAME_1": "Colón" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -86.437868288390803, 15.790846896267226 ], [ -86.414662238999938, 15.776434637000079 ], [ -86.399037238999938, 15.772406317000048 ], [ -86.374745245999918, 15.77094147300005 ], [ -86.354969855999911, 15.773993231000077 ], [ -86.338286912999934, 15.781398830000057 ], [ -86.243234829999949, 15.83860911700009 ], [ -86.218495245999918, 15.865057684000078 ], [ -86.207142706999946, 15.874009507000039 ], [ -86.172596808999913, 15.887518622000073 ], [ -86.137806769999941, 15.895656643000052 ], [ -85.994862433999913, 15.90070221600007 ], [ -85.982289191999939, 15.904201565000051 ], [ -85.972157355999911, 15.909165757000039 ], [ -85.933257615999935, 15.936672268000052 ], [ -85.912180141999897, 15.95929596600007 ], [ -85.903187628999945, 15.983465887000079 ], [ -85.919178839999915, 16.003729559000078 ], [ -85.982492641999897, 16.012518622000073 ], [ -86.012766079999949, 16.019964911000045 ], [ -86.007923956999946, 16.031073309000078 ], [ -85.981841600999928, 16.033148505000042 ], [ -85.904551557999923, 16.018383360000087 ], [ -85.851004879999948, 16.008733665000079 ], [ -85.813465949999909, 16.00454336100006 ], [ -85.766331744999945, 15.991582225000059 ], [ -85.719349738999938, 15.979722398000092 ], [ -85.703195766999897, 15.976467190000051 ], [ -85.69204667899993, 15.971502997000073 ], [ -85.689442511999914, 15.960028387000079 ], [ -85.689605272999927, 15.946437893000052 ], [ -85.687001105999911, 15.935492255000042 ], [ -85.679554816999939, 15.935492255000042 ], [ -85.680083787999934, 15.942206122000073 ], [ -85.67804928299995, 15.945379950000074 ], [ -85.675038214999915, 15.947088934000078 ], [ -85.672718878999945, 15.949164130000042 ], [ -85.656220702999917, 15.948768477000044 ], [ -85.647334405999914, 15.935942688000068 ], [ -85.629563115999929, 15.922042590000046 ], [ -85.608463942999947, 15.907071985000073 ], [ -85.564054792999912, 15.888874601000055 ], [ -85.488577667999948, 15.869566580000082 ], [ -85.436394406999909, 15.873762960000079 ], [ -85.361990541999944, 15.881110034000073 ], [ -85.254250156999944, 15.884084998000048 ], [ -85.196354780999911, 15.90744777000009 ], [ -85.123782968999933, 15.958574594000083 ], [ -85.0757802359999, 15.986247321000064 ], [ -84.999948697274533, 15.987941798774955 ], [ -84.999948289881672, 15.06874461497199 ], [ -85.059634569179991, 15.137060858771576 ], [ -85.092681647040365, 15.166774807211596 ], [ -85.232647264059949, 15.226667792084925 ], [ -85.249312913859853, 15.236641343723022 ], [ -85.307113002762833, 15.305267645885124 ], [ -85.360417243161237, 15.381076971724838 ], [ -85.395944789720261, 15.408930569090501 ], [ -85.505240444790672, 15.449496568311986 ], [ -85.607714809590789, 15.534866033740457 ], [ -85.688304205674513, 15.577189032148112 ], [ -85.709362352090864, 15.581529852820438 ], [ -85.717837286961185, 15.577034003416486 ], [ -85.727836677021003, 15.573313300368511 ], [ -85.73587236231964, 15.571866360444176 ], [ -85.745561693117622, 15.575845445011282 ], [ -85.752382981589335, 15.581478175976997 ], [ -85.759126756594526, 15.584268703937539 ], [ -85.764139369935947, 15.584992174349338 ], [ -85.786308560391717, 15.574295152299442 ], [ -85.784551561205546, 15.565045071073143 ], [ -85.787858853103558, 15.557810370552147 ], [ -85.79579118471537, 15.548715318057475 ], [ -85.817262743181061, 15.531868801104281 ], [ -85.8368739487737, 15.519983222447763 ], [ -85.847855190764449, 15.520603339172737 ], [ -85.859611579111061, 15.52799306932468 ], [ -85.866277838851147, 15.53031850839244 ], [ -85.87312496574458, 15.531352037166755 ], [ -85.879946255115556, 15.52856151010559 ], [ -85.884597134150397, 15.523083807871444 ], [ -85.909143438718729, 15.484223130992689 ], [ -85.969940762056524, 15.426655585187063 ], [ -86.027508307862092, 15.396579902440521 ], [ -86.031668259582489, 15.39037872979452 ], [ -86.03828284427783, 15.39037872979452 ], [ -86.045543382321227, 15.393582668905026 ], [ -86.053656581985649, 15.395856432028722 ], [ -86.063345912783632, 15.396683254328707 ], [ -86.081329312197965, 15.394151108786616 ], [ -86.090191819796644, 15.390430405738641 ], [ -86.106805792753107, 15.38732982031496 ], [ -86.125667691310866, 15.378234767820288 ], [ -86.148560350379853, 15.37301544800448 ], [ -86.171633876602129, 15.378079739088662 ], [ -86.232896287933329, 15.409757392289805 ], [ -86.234446580645169, 15.436060696044251 ], [ -86.241061164441192, 15.449341539580359 ], [ -86.241681281166166, 15.454405828865902 ], [ -86.235583462206989, 15.499312648759712 ], [ -86.237392137337224, 15.512541816351757 ], [ -86.240260178764231, 15.520861720691869 ], [ -86.243283250721447, 15.523497219021408 ], [ -86.247624071393773, 15.524117335746439 ], [ -86.250156216036544, 15.522722073564807 ], [ -86.251758185591768, 15.520086575235268 ], [ -86.252895067153588, 15.518742988098381 ], [ -86.254264492712139, 15.518794664042503 ], [ -86.25565975579309, 15.520138251179333 ], [ -86.25775265176344, 15.521688543891173 ], [ -86.260181443618706, 15.522773749508929 ], [ -86.263540412360101, 15.523290514345717 ], [ -86.266330939421323, 15.524272366276648 ], [ -86.269147304904209, 15.526236070138509 ], [ -86.272532111168005, 15.53031850839244 ], [ -86.275374315072554, 15.532695624303585 ], [ -86.277906459715325, 15.534142564227921 ], [ -86.280748663619931, 15.535331121733861 ], [ -86.282996589221227, 15.535796209727266 ], [ -86.288810188239552, 15.535589504152256 ], [ -86.314105800742084, 15.541790675898937 ], [ -86.362061530115511, 15.539930324824638 ], [ -86.372345140116124, 15.540653795236437 ], [ -86.377383591879266, 15.542410794422608 ], [ -86.37976070779041, 15.546234850258145 ], [ -86.391232876196284, 15.559670722525823 ], [ -86.420946824636246, 15.582821764013204 ], [ -86.39903601839751, 15.595534165869026 ], [ -86.37552324080491, 15.604422511889425 ], [ -86.366014777160217, 15.613620917171602 ], [ -86.361673957387211, 15.626540025501754 ], [ -86.361906501383942, 15.648915919733895 ], [ -86.363456794095782, 15.672170314908101 ], [ -86.366014777160217, 15.675529282750176 ], [ -86.369502937110838, 15.678939928335012 ], [ -86.37591081443253, 15.678268133867277 ], [ -86.379605679058841, 15.678474840341607 ], [ -86.384902513240377, 15.681110337771884 ], [ -86.394333461619965, 15.684417628770518 ], [ -86.397434047942966, 15.68968862632903 ], [ -86.408777025139557, 15.714183254053921 ], [ -86.41774288642506, 15.722916572242013 ], [ -86.432108933780228, 15.734492092536016 ], [ -86.43833594394863, 15.741933499531342 ], [ -86.441539883059136, 15.750046698296501 ], [ -86.443296882245306, 15.764102688188473 ], [ -86.444692146225577, 15.77025218309177 ], [ -86.446423306090708, 15.775471502907521 ], [ -86.447250129290012, 15.779088853168048 ], [ -86.446319953303203, 15.781414293135128 ], [ -86.444821337434746, 15.782189439491049 ], [ -86.437715827223656, 15.782551173797629 ], [ -86.437868288390803, 15.790846896267226 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-AT", "NAME_1": "Atlántida" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -87.728357527078174, 15.921021546507177 ], [ -87.722157355999911, 15.922919012000079 ], [ -87.704335089999915, 15.920721747000073 ], [ -87.687489386999914, 15.914984442000048 ], [ -87.643055792999917, 15.889227606000077 ], [ -87.626047329999949, 15.887681382000039 ], [ -87.626047329999949, 15.893947658000059 ], [ -87.636301235999952, 15.903509833000044 ], [ -87.625965949999909, 15.914943752000056 ], [ -87.591297980999911, 15.935492255000042 ], [ -87.610422329999949, 15.910101630000042 ], [ -87.617298956999946, 15.894598700000074 ], [ -87.608631964999915, 15.887681382000039 ], [ -87.603138800999943, 15.880764065000051 ], [ -87.509632941999939, 15.798651434000078 ], [ -87.479400193999936, 15.786037502000056 ], [ -87.447336391999897, 15.792141018000052 ], [ -87.441761847999942, 15.797756252000056 ], [ -87.431548631999931, 15.813950914000088 ], [ -87.426828579999949, 15.818793036000045 ], [ -87.417144334999932, 15.819525458000044 ], [ -87.391184048999946, 15.818426825000074 ], [ -87.385853644999941, 15.822495835000041 ], [ -87.379953579999949, 15.839504299000055 ], [ -87.364979620999918, 15.848334052000041 ], [ -87.345082160999937, 15.85032786700009 ], [ -87.241769985999952, 15.827378648000092 ], [ -87.151722785999937, 15.796861070000091 ], [ -87.058990037999934, 15.787014065000051 ], [ -86.952504035999937, 15.763332424000055 ], [ -86.916859503999945, 15.76040273600006 ], [ -86.878732876999948, 15.764146226000037 ], [ -86.817372199999909, 15.78188711100006 ], [ -86.799631313999896, 15.78461334800005 ], [ -86.796864386999914, 15.787583726000037 ], [ -86.780181443999936, 15.800197658000059 ], [ -86.776356574999909, 15.801988023000092 ], [ -86.770659959999932, 15.806545315000051 ], [ -86.75845292899993, 15.802313544000071 ], [ -86.746449347999942, 15.795599677000041 ], [ -86.741566535999937, 15.792141018000052 ], [ -86.699086066999939, 15.788641669000071 ], [ -86.503814256999931, 15.805080471000053 ], [ -86.470570441999939, 15.804185289000088 ], [ -86.439930792999917, 15.792141018000052 ], [ -86.437868288390803, 15.790846896267226 ], [ -86.437715827223656, 15.782551173797629 ], [ -86.444821337434746, 15.782189439491049 ], [ -86.446319953303203, 15.781414293135128 ], [ -86.447250129290012, 15.779088853168048 ], [ -86.446423306090708, 15.775471502907521 ], [ -86.444692146225577, 15.77025218309177 ], [ -86.443296882245306, 15.764102688188473 ], [ -86.441539883059136, 15.750046698296501 ], [ -86.43833594394863, 15.741933499531342 ], [ -86.432108933780228, 15.734492092536016 ], [ -86.41774288642506, 15.722916572242013 ], [ -86.408777025139557, 15.714183254053921 ], [ -86.397434047942966, 15.68968862632903 ], [ -86.394333461619965, 15.684417628770518 ], [ -86.384902513240377, 15.681110337771884 ], [ -86.379605679058841, 15.678474840341607 ], [ -86.37591081443253, 15.678268133867277 ], [ -86.369502937110838, 15.678939928335012 ], [ -86.366014777160217, 15.675529282750176 ], [ -86.363456794095782, 15.672170314908101 ], [ -86.361906501383942, 15.648915919733895 ], [ -86.361673957387211, 15.626540025501754 ], [ -86.366014777160217, 15.613620917171602 ], [ -86.37552324080491, 15.604422511889425 ], [ -86.39903601839751, 15.595534165869026 ], [ -86.420946824636246, 15.582821764013204 ], [ -86.44278011830778, 15.592123521183566 ], [ -86.470401170777393, 15.596464341855892 ], [ -86.49561926981346, 15.593467109219716 ], [ -86.502802294390335, 15.591813462821051 ], [ -86.509313523600213, 15.589436346909849 ], [ -86.517685105683086, 15.587989406985514 ], [ -86.526392585449457, 15.58871287739737 ], [ -86.53685706260336, 15.592846990696046 ], [ -86.546753098976296, 15.594293932419021 ], [ -86.583340012731412, 15.592020169295381 ], [ -86.619177618552214, 15.601735338515027 ], [ -86.636256680401459, 15.604629218363698 ], [ -86.647961391904687, 15.602458808027563 ], [ -86.669562140680227, 15.595740872343356 ], [ -86.690594448674858, 15.586749171736869 ], [ -86.732142299827274, 15.564166571929718 ], [ -86.757205370131715, 15.555639960215956 ], [ -86.778935310116424, 15.550679022818656 ], [ -86.810018684114937, 15.550575670031151 ], [ -86.824979010672791, 15.548870347688364 ], [ -86.843763393965446, 15.553004461886417 ], [ -86.85580400315223, 15.569282538058644 ], [ -86.927117478688672, 15.550679022818656 ], [ -86.972360196266038, 15.551764228436355 ], [ -86.990627813822528, 15.54881867084498 ], [ -87.028325771617062, 15.516882636124762 ], [ -87.044578010266946, 15.499002590397197 ], [ -87.054163988277423, 15.49156118430119 ], [ -87.072095709949053, 15.481639309506534 ], [ -87.137259690582255, 15.458798326381668 ], [ -87.167567919124167, 15.437972723962048 ], [ -87.177696498594514, 15.429446113147606 ], [ -87.18245073131618, 15.426552232399615 ], [ -87.22368852410608, 15.427172350023909 ], [ -87.294872810231993, 15.443502102140314 ], [ -87.305208096176671, 15.443347073408688 ], [ -87.314664882977922, 15.444897366120529 ], [ -87.323940802625941, 15.451408596229726 ], [ -87.335387132610037, 15.455439358539536 ], [ -87.342751024340259, 15.456421210470467 ], [ -87.349468960024467, 15.454560859396111 ], [ -87.354739955784339, 15.451046861023826 ], [ -87.360631070067825, 15.449341539580359 ], [ -87.364868537053326, 15.445672512476449 ], [ -87.370759650437492, 15.442985338202789 ], [ -87.375720587834849, 15.441228339016618 ], [ -87.381973436424914, 15.442158515003428 ], [ -87.387192756240665, 15.443657130871884 ], [ -87.402023891589295, 15.45047842024286 ], [ -87.410498827358992, 15.455904446532941 ], [ -87.416699999105674, 15.460762030243473 ], [ -87.42408972925756, 15.46980540589476 ], [ -87.430755988098383, 15.480657457575603 ], [ -87.436156175067424, 15.505617174193219 ], [ -87.436698778325933, 15.518432928836603 ], [ -87.4384040997694, 15.52897492125561 ], [ -87.455560675984373, 15.539930324824638 ], [ -87.46475908126655, 15.540653795236437 ], [ -87.469926724238917, 15.538741767318697 ], [ -87.508864916382777, 15.517399400062232 ], [ -87.52336015494717, 15.519104723304338 ], [ -87.56534725567127, 15.508097641992549 ], [ -87.609995694046006, 15.504428615787958 ], [ -87.625550299806491, 15.510784817165586 ], [ -87.665418667037841, 15.553572903566646 ], [ -87.668674282991731, 15.558585516908067 ], [ -87.671516485997017, 15.564683335867244 ], [ -87.676994188231163, 15.595534165869026 ], [ -87.678001878583814, 15.61010691969858 ], [ -87.687200283865991, 15.644678452748394 ], [ -87.697897305016625, 15.663695380037723 ], [ -87.714588793238192, 15.67211863896398 ], [ -87.787581752695701, 15.721004544324273 ], [ -87.773241542862877, 15.724621893685423 ], [ -87.764275681577431, 15.729686183870285 ], [ -87.758410406614928, 15.739814765139272 ], [ -87.757867805155058, 15.751131903914199 ], [ -87.76117509615375, 15.760433661084562 ], [ -87.767376267900431, 15.765291245694414 ], [ -87.775437791620789, 15.763224189045047 ], [ -87.77952022987472, 15.776453354838452 ], [ -87.794661423585808, 15.79335154953435 ], [ -87.794868130060138, 15.803893541054038 ], [ -87.789493780613441, 15.81283356391782 ], [ -87.773732469278002, 15.828491523365074 ], [ -87.766446091913622, 15.838620102835478 ], [ -87.757376878739933, 15.862804673996493 ], [ -87.751614955665673, 15.872209783954361 ], [ -87.740530361786739, 15.882028306860832 ], [ -87.730686001357867, 15.887867743401614 ], [ -87.725156623179601, 15.897324530202866 ], [ -87.728357527078174, 15.921021546507177 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-IB", "NAME_1": "Islas de la Bahía" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -86.878732876999948, 16.12726471600007 ], [ -86.872547980999911, 16.120998440000051 ], [ -86.88117428299995, 16.104559637000079 ], [ -86.878732876999948, 16.093166408000059 ], [ -86.897572394999941, 16.093817450000074 ], [ -86.913197394999941, 16.09015534100007 ], [ -86.940174933999913, 16.079494533000059 ], [ -86.963720509999916, 16.066387834000068 ], [ -86.978935229999934, 16.077789236000058 ], [ -86.997404698999901, 16.083959264000043 ], [ -86.988735173999942, 16.095466383000087 ], [ -86.944251203999897, 16.116508342000088 ], [ -86.918365037999934, 16.122056382000039 ], [ -86.903920050999943, 16.124172268000052 ], [ -86.890533006999931, 16.127834377000056 ], [ -86.878732876999948, 16.12726471600007 ] ] ], [ [ [ -86.606542220999927, 16.285029102000067 ], [ -86.599332887999935, 16.309298272000092 ], [ -86.570446806999939, 16.332440401000042 ], [ -86.530681582999932, 16.356180794000068 ], [ -86.499999801999934, 16.368908871000087 ], [ -86.440390430999912, 16.396545291000052 ], [ -86.3754442259999, 16.417332689000091 ], [ -86.3321254949999, 16.429448093000076 ], [ -86.302047367999933, 16.432903318000058 ], [ -86.262351476999925, 16.43058202800006 ], [ -86.23107686599991, 16.428835329000037 ], [ -86.181750880999914, 16.428225143000077 ], [ -86.202208966999933, 16.422471073000054 ], [ -86.223870070999908, 16.412101045000043 ], [ -86.243112175999897, 16.417881076000072 ], [ -86.273185837999904, 16.410972052000091 ], [ -86.294341600999928, 16.415269273000092 ], [ -86.312123175999943, 16.412502346000053 ], [ -86.318918423999946, 16.409328518000052 ], [ -86.33267167899993, 16.400458075000074 ], [ -86.338856574999909, 16.397853908000059 ], [ -86.347767706999946, 16.397528387000079 ], [ -86.362205888999938, 16.394254366000041 ], [ -86.380253568999933, 16.381557601000054 ], [ -86.416959740999914, 16.364231547000088 ], [ -86.453071272999921, 16.351511373000051 ], [ -86.491021777999947, 16.325487820000092 ], [ -86.525265547999936, 16.315212384000063 ], [ -86.548152687999902, 16.312852734000046 ], [ -86.563799277999919, 16.298390453000081 ], [ -86.580649961999939, 16.282767 ], [ -86.60050418499992, 16.269449111000085 ], [ -86.606542220999927, 16.285029102000067 ] ] ], [ [ [ -85.911472683999932, 16.462042911000083 ], [ -85.895569831999921, 16.48874459600006 ], [ -85.884144660999937, 16.502834377000056 ], [ -85.851131208999902, 16.517217619000064 ], [ -85.832128226999941, 16.510497688000044 ], [ -85.816949995999948, 16.498308834000056 ], [ -85.822061113999951, 16.486163010000041 ], [ -85.844254139999919, 16.483778923000045 ], [ -85.849366857999939, 16.469205087000091 ], [ -85.862720490999948, 16.452220959000044 ], [ -85.882362561999912, 16.451046980000058 ], [ -85.895699535999938, 16.436496074000047 ], [ -85.947068220999938, 16.403189644000065 ], [ -85.950847252999949, 16.412307873000088 ], [ -85.940679118999924, 16.429902700000071 ], [ -85.926691276999918, 16.454782230000092 ], [ -85.911472683999932, 16.462042911000083 ] ] ], [ [ [ -83.941151495999918, 17.418646552000041 ], [ -83.933583136999914, 17.417873440000051 ], [ -83.926136847999942, 17.41632721600007 ], [ -83.918934699999909, 17.414048570000091 ], [ -83.91234290299991, 17.411118882000039 ], [ -83.921945766999897, 17.409084377000056 ], [ -83.93032792899993, 17.409409898000092 ], [ -83.936879035999937, 17.412543036000045 ], [ -83.941151495999918, 17.418646552000041 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-CM", "NAME_1": "Comayagua" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -88.074954392830932, 14.664841620144614 ], [ -88.06224199097511, 14.68561554572085 ], [ -88.071595424988857, 14.710885322499621 ], [ -88.077874112000643, 14.721375637175925 ], [ -88.077331508742134, 14.735224921492943 ], [ -88.074773525677642, 14.742459622013939 ], [ -88.069812588280286, 14.747213852936966 ], [ -88.058417935139573, 14.751968084759312 ], [ -88.052966071327091, 14.755378730344091 ], [ -88.02252865337465, 14.786281236289994 ], [ -87.98705278186037, 14.792585760824181 ], [ -87.985812548410365, 14.836407375999613 ], [ -87.980283169332779, 14.820129298928009 ], [ -87.973668586436077, 14.81046580745101 ], [ -87.96297156438618, 14.803541165292529 ], [ -87.883674078595845, 14.858214830350107 ], [ -87.869437221550527, 14.876818346489472 ], [ -87.847423061624966, 14.898832506415033 ], [ -87.84367652105459, 14.901416327001868 ], [ -87.821455654654699, 14.906583970873555 ], [ -87.802593756996259, 14.915523992837961 ], [ -87.757221849109044, 14.947925116450961 ], [ -87.740685391417685, 14.962497870280458 ], [ -87.735801968386113, 14.983788559794164 ], [ -87.735879482751898, 15.016551419512382 ], [ -87.642345139916245, 15.017946681694013 ], [ -87.631183030772263, 15.016603095456503 ], [ -87.587413093339592, 15.026266587832765 ], [ -87.58387325744485, 15.034741522703087 ], [ -87.554727748886478, 15.055618801066828 ], [ -87.551342942622682, 15.057014065047042 ], [ -87.548268194721402, 15.057634181772073 ], [ -87.54359147816416, 15.056497301109516 ], [ -87.537571173570768, 15.054068508354987 ], [ -87.524729579606401, 15.045490220697104 ], [ -87.516848923938653, 15.037687079395198 ], [ -87.506410285206471, 15.022649238471558 ], [ -87.503232185417005, 15.013864244339402 ], [ -87.500467494978921, 15.001565252734224 ], [ -87.498658819848629, 14.997172756117777 ], [ -87.496436733568373, 14.993452053069802 ], [ -87.491604987380242, 14.989266262028366 ], [ -87.486669888404606, 14.985803941398785 ], [ -87.47713558633825, 14.982600002288279 ], [ -87.473182339293487, 14.980222887276398 ], [ -87.469099901039613, 14.974590155411306 ], [ -87.463751390014636, 14.972006333925151 ], [ -87.460676643012675, 14.965908514965975 ], [ -87.459436407763974, 14.960999254412059 ], [ -87.460263230963335, 14.951645820398255 ], [ -87.460134039754109, 14.946994941363414 ], [ -87.458738775773838, 14.941362210397699 ], [ -87.455638190350214, 14.934282537708953 ], [ -87.454552984732459, 14.929941717935947 ], [ -87.451788296092957, 14.923740546189265 ], [ -87.451710781727172, 14.921363430278063 ], [ -87.452020840089688, 14.918779608791908 ], [ -87.452020840089688, 14.916454168824828 ], [ -87.449437018603533, 14.913922024182057 ], [ -87.444269374731846, 14.91087311380312 ], [ -87.433572353581212, 14.90875438120969 ], [ -87.418637865445135, 14.90854767473536 ], [ -87.394065720656442, 14.920846666340537 ], [ -87.374687059060534, 14.938830063956289 ], [ -87.350657518429728, 14.937279771244448 ], [ -87.314897426974653, 14.927978014074085 ], [ -87.310556607201647, 14.925807602838574 ], [ -87.30285681778787, 14.919554755147828 ], [ -87.297198249299754, 14.916660875299158 ], [ -87.291746384587952, 14.918314520798504 ], [ -87.285235155378075, 14.92420563418267 ], [ -87.27900814520973, 14.923017075777409 ], [ -87.272677782253822, 14.921260077490558 ], [ -87.245806036819147, 14.897747300797278 ], [ -87.228391079085043, 14.889995836338755 ], [ -87.224670376037011, 14.886946925959876 ], [ -87.219425217799539, 14.881469225524313 ], [ -87.218262498715319, 14.874286200048061 ], [ -87.208340623920662, 14.859455063800112 ], [ -87.224541184827785, 14.847466132356089 ], [ -87.24544430161319, 14.845502428494285 ], [ -87.248364020782901, 14.844572252507419 ], [ -87.251361254318397, 14.841781725446253 ], [ -87.254487678163798, 14.836614081574567 ], [ -87.257252366803243, 14.82689891235492 ], [ -87.25820838121183, 14.811292628851731 ], [ -87.253609178121053, 14.795738023091303 ], [ -87.249449226400657, 14.761838284509224 ], [ -87.255417854150608, 14.738325506916624 ], [ -87.266244065611147, 14.71083364475686 ], [ -87.267019212866387, 14.706544500927976 ], [ -87.266011521614416, 14.705045885059519 ], [ -87.266089036879521, 14.703133857141779 ], [ -87.268104417584766, 14.700756741230634 ], [ -87.275519986158429, 14.695744126989837 ], [ -87.280403409189944, 14.693367011078692 ], [ -87.285105964168906, 14.691610011892521 ], [ -87.288749151951777, 14.690679835905712 ], [ -87.291978928584683, 14.689336248768825 ], [ -87.300738085194439, 14.682876695503069 ], [ -87.306293300895106, 14.681068020372834 ], [ -87.310014003943138, 14.680602932379429 ], [ -87.312261928645057, 14.679259345242599 ], [ -87.313347134262813, 14.676417141337993 ], [ -87.313812222256217, 14.670267646434695 ], [ -87.315052455706223, 14.667632148105156 ], [ -87.318669806866069, 14.666598619330784 ], [ -87.320555996362145, 14.667942206467615 ], [ -87.322106289073986, 14.66959585196696 ], [ -87.323656581785826, 14.670629380741332 ], [ -87.325051845766041, 14.66959585196696 ], [ -87.32582699302128, 14.665978501706491 ], [ -87.324173346622615, 14.658433742822979 ], [ -87.3235015530542, 14.652697659069702 ], [ -87.32347571463248, 14.647271632779621 ], [ -87.327144741736447, 14.633525702149427 ], [ -87.342130906715965, 14.607790839175891 ], [ -87.353215502393482, 14.608410955900865 ], [ -87.357272102225693, 14.609237779100226 ], [ -87.36130286273692, 14.610529690292935 ], [ -87.36455847869081, 14.612028307060712 ], [ -87.36590206582764, 14.613940334978452 ], [ -87.366987271445396, 14.618022773232383 ], [ -87.368382535425667, 14.619573065944223 ], [ -87.371121384744072, 14.619883124306739 ], [ -87.374170295123008, 14.619728095575113 ], [ -87.377735969439414, 14.619883124306739 ], [ -87.38192175958153, 14.620813300293548 ], [ -87.386365933041361, 14.62262197542384 ], [ -87.390629239347902, 14.62489573854748 ], [ -87.395202603117639, 14.626497708102704 ], [ -87.39869076216894, 14.626756090521155 ], [ -87.40197221564523, 14.62468903207315 ], [ -87.403729213932081, 14.620709947506043 ], [ -87.403419155569566, 14.605878811258094 ], [ -87.40403927319386, 14.600091051560753 ], [ -87.405357021909026, 14.594561672483167 ], [ -87.406028814578121, 14.589549058242426 ], [ -87.415046352707009, 14.571513983783291 ], [ -87.46592180035077, 14.522214667273033 ], [ -87.463002082080379, 14.506815090244231 ], [ -87.460495774960009, 14.498960272998204 ], [ -87.456335822340293, 14.489606838085081 ], [ -87.451064825681158, 14.482372138463404 ], [ -87.435225999979878, 14.472088528462791 ], [ -87.411894091339207, 14.451934718712266 ], [ -87.408974372169496, 14.448214016563611 ], [ -87.406958990564931, 14.44356313752877 ], [ -87.407372402614271, 14.433951321096572 ], [ -87.409852871312921, 14.429817205999257 ], [ -87.413186000733333, 14.427026678938091 ], [ -87.412359178433348, 14.423822739827585 ], [ -87.410679693612963, 14.421135566453188 ], [ -87.386262580253856, 14.402635403101385 ], [ -87.382748582780835, 14.395297349792827 ], [ -87.393187222412394, 14.374006659379802 ], [ -87.419413010901735, 14.339486803173429 ], [ -87.424554816351701, 14.336024482543792 ], [ -87.432047899291092, 14.333285631426747 ], [ -87.44434688999695, 14.339176743911594 ], [ -87.450134649694292, 14.340106919898403 ], [ -87.454708015262668, 14.339900214323393 ], [ -87.459281379032404, 14.338039863249094 ], [ -87.46207190609357, 14.332252101753056 ], [ -87.463854742802141, 14.321606757445863 ], [ -87.462046067671849, 14.282177638886935 ], [ -87.459875658235035, 14.271790676098817 ], [ -87.456568366337024, 14.265744533983025 ], [ -87.450599737687753, 14.259336655762013 ], [ -87.44491533077786, 14.254220688733767 ], [ -87.440419481373965, 14.251223456097591 ], [ -87.437060512632513, 14.249673163385751 ], [ -87.433727383212158, 14.248639635510756 ], [ -87.431401944144397, 14.24734772431799 ], [ -87.429877488954958, 14.245539049187755 ], [ -87.426931932262846, 14.239337877441073 ], [ -87.425691697913521, 14.234945379925307 ], [ -87.42545915391679, 14.229054267440461 ], [ -87.429644944958227, 14.222749742006954 ], [ -87.437086351054234, 14.218874010227353 ], [ -87.46320878765539, 14.213189602418197 ], [ -87.482949185356574, 14.201097317287349 ], [ -87.493542853719703, 14.179858302818388 ], [ -87.494266324131559, 14.174432278326947 ], [ -87.500674200553874, 14.166732488913226 ], [ -87.512585619430752, 14.159601142079055 ], [ -87.541214362253015, 14.146785387435671 ], [ -87.573305426604122, 14.14332306590677 ], [ -87.579532436772524, 14.143529771481781 ], [ -87.585707770996805, 14.140325833270595 ], [ -87.593433397033607, 14.133762926317956 ], [ -87.614336513819069, 14.109113267163536 ], [ -87.615240852283478, 14.088494371218246 ], [ -87.650613369211612, 14.085032049689346 ], [ -87.663609991907606, 14.075730292518983 ], [ -87.689629075721257, 14.051028958319762 ], [ -87.690688442917292, 14.084773668170214 ], [ -87.696579556301458, 14.095160630958333 ], [ -87.703685064713966, 14.104204005710301 ], [ -87.714304572398078, 14.109785060731951 ], [ -87.731926235707192, 14.12440949140489 ], [ -87.742778285589395, 14.130662339994956 ], [ -87.754121262786043, 14.134951483823897 ], [ -87.764275681577431, 14.136915187685759 ], [ -87.780967169799055, 14.14311636033176 ], [ -87.784558681637805, 14.146682033748846 ], [ -87.785798915987186, 14.150557766427767 ], [ -87.784326137641131, 14.155622057511948 ], [ -87.782078212939155, 14.159652818023119 ], [ -87.777117276441118, 14.175362454313813 ], [ -87.791121588590443, 14.191382148067646 ], [ -87.825641445696135, 14.20554148984786 ], [ -87.828716192698096, 14.225281887549045 ], [ -87.825770636905361, 14.232206528808263 ], [ -87.82360022656917, 14.233653468732598 ], [ -87.820706345821179, 14.234170234468706 ], [ -87.819104377165274, 14.234066880781882 ], [ -87.813239102202772, 14.231689764870737 ], [ -87.775851202770752, 14.24062978773452 ], [ -87.755852423550493, 14.238976142235174 ], [ -87.740065273793334, 14.241198228515429 ], [ -87.727662930299971, 14.244143785207484 ], [ -87.706088019946151, 14.251740220934437 ], [ -87.696837937820533, 14.256081040707443 ], [ -87.68373796323641, 14.265692857139641 ], [ -87.668648443670747, 14.263625800490274 ], [ -87.652912970756972, 14.266933092388285 ], [ -87.644102139102415, 14.270395413017866 ], [ -87.639477097589975, 14.273702704016557 ], [ -87.629942797322201, 14.285639960415836 ], [ -87.626635505424247, 14.298559067846668 ], [ -87.634929572241958, 14.306362210047951 ], [ -87.62818579813603, 14.317059231198527 ], [ -87.631648118765668, 14.336386216850428 ], [ -87.634464484248554, 14.344189358152335 ], [ -87.646582607801065, 14.369820868338365 ], [ -87.651155971570802, 14.373438219498212 ], [ -87.696114468308053, 14.355454820083878 ], [ -87.70430518323758, 14.357728583207518 ], [ -87.714976365966493, 14.358503730462758 ], [ -87.735259366026924, 14.365635077296986 ], [ -87.746033902442605, 14.371267808262701 ], [ -87.776522997238487, 14.377210598490308 ], [ -87.779442714609559, 14.378347480052128 ], [ -87.788744472679241, 14.387855942797501 ], [ -87.789545458356201, 14.389871324402066 ], [ -87.829129604747436, 14.400361639977689 ], [ -87.842875536276949, 14.414314277082212 ], [ -87.853107469434178, 14.42909373648672 ], [ -87.848999192758527, 14.432814439534752 ], [ -87.848146532036822, 14.435088201759072 ], [ -87.847784796830865, 14.438188788082073 ], [ -87.848224047301926, 14.441754462398478 ], [ -87.855820482129502, 14.455965481022133 ], [ -87.887937384902386, 14.495549628312688 ], [ -87.899745450092439, 14.506505031881716 ], [ -87.898763597262189, 14.515910141839584 ], [ -87.899047818102304, 14.525987047164506 ], [ -87.902691005885174, 14.530276190993391 ], [ -87.909021368841081, 14.535237128390747 ], [ -87.933257615946218, 14.546916002371574 ], [ -87.940983242882339, 14.553065497274872 ], [ -87.947365281782311, 14.56536448798073 ], [ -87.949639044906007, 14.571824042145806 ], [ -87.950646735258601, 14.582159328989803 ], [ -87.951602748767812, 14.585880032037835 ], [ -87.959767626174994, 14.600917873860794 ], [ -87.969146897711141, 14.613061834935706 ], [ -87.987337001801166, 14.619469713156718 ], [ -88.00420935717608, 14.631561998287566 ], [ -88.038729214281773, 14.640295315576338 ], [ -88.04622229722122, 14.641173813820444 ], [ -88.056144172015934, 14.64417104735594 ], [ -88.061311814988244, 14.64649648732302 ], [ -88.074954392830932, 14.664841620144614 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-YO", "NAME_1": "Yoro" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -87.787581752695701, 15.721004544324273 ], [ -87.714588793238192, 15.67211863896398 ], [ -87.697897305016625, 15.663695380037723 ], [ -87.687200283865991, 15.644678452748394 ], [ -87.678001878583814, 15.61010691969858 ], [ -87.676994188231163, 15.595534165869026 ], [ -87.671516485997017, 15.564683335867244 ], [ -87.668674282991731, 15.558585516908067 ], [ -87.665418667037841, 15.553572903566646 ], [ -87.625550299806491, 15.510784817165586 ], [ -87.609995694046006, 15.504428615787958 ], [ -87.56534725567127, 15.508097641992549 ], [ -87.52336015494717, 15.519104723304338 ], [ -87.508864916382777, 15.517399400062232 ], [ -87.469926724238917, 15.538741767318697 ], [ -87.46475908126655, 15.540653795236437 ], [ -87.455560675984373, 15.539930324824638 ], [ -87.4384040997694, 15.52897492125561 ], [ -87.436698778325933, 15.518432928836603 ], [ -87.436156175067424, 15.505617174193219 ], [ -87.430755988098383, 15.480657457575603 ], [ -87.42408972925756, 15.46980540589476 ], [ -87.416699999105674, 15.460762030243473 ], [ -87.410498827358992, 15.455904446532941 ], [ -87.402023891589295, 15.45047842024286 ], [ -87.387192756240665, 15.443657130871884 ], [ -87.381973436424914, 15.442158515003428 ], [ -87.375720587834849, 15.441228339016618 ], [ -87.370759650437492, 15.442985338202789 ], [ -87.364868537053326, 15.445672512476449 ], [ -87.360631070067825, 15.449341539580359 ], [ -87.354739955784339, 15.451046861023826 ], [ -87.349468960024467, 15.454560859396111 ], [ -87.342751024340259, 15.456421210470467 ], [ -87.335387132610037, 15.455439358539536 ], [ -87.323940802625941, 15.451408596229726 ], [ -87.314664882977922, 15.444897366120529 ], [ -87.305208096176671, 15.443347073408688 ], [ -87.294872810231993, 15.443502102140314 ], [ -87.22368852410608, 15.427172350023909 ], [ -87.18245073131618, 15.426552232399615 ], [ -87.177696498594514, 15.429446113147606 ], [ -87.167567919124167, 15.437972723962048 ], [ -87.137259690582255, 15.458798326381668 ], [ -87.072095709949053, 15.481639309506534 ], [ -87.054163988277423, 15.49156118430119 ], [ -87.044578010266946, 15.499002590397197 ], [ -87.028325771617062, 15.516882636124762 ], [ -86.990627813822528, 15.54881867084498 ], [ -86.972360196266038, 15.551764228436355 ], [ -86.927117478688672, 15.550679022818656 ], [ -86.85580400315223, 15.569282538058644 ], [ -86.843763393965446, 15.553004461886417 ], [ -86.824979010672791, 15.548870347688364 ], [ -86.810018684114937, 15.550575670031151 ], [ -86.778935310116424, 15.550679022818656 ], [ -86.757205370131715, 15.555639960215956 ], [ -86.732142299827274, 15.564166571929718 ], [ -86.690594448674858, 15.586749171736869 ], [ -86.669562140680227, 15.595740872343356 ], [ -86.647961391904687, 15.602458808027563 ], [ -86.636256680401459, 15.604629218363698 ], [ -86.619177618552214, 15.601735338515027 ], [ -86.583340012731412, 15.592020169295381 ], [ -86.546753098976296, 15.594293932419021 ], [ -86.53685706260336, 15.592846990696046 ], [ -86.526392585449457, 15.58871287739737 ], [ -86.517685105683086, 15.587989406985514 ], [ -86.509313523600213, 15.589436346909849 ], [ -86.502802294390335, 15.591813462821051 ], [ -86.49561926981346, 15.593467109219716 ], [ -86.470401170777393, 15.596464341855892 ], [ -86.44278011830778, 15.592123521183566 ], [ -86.420946824636246, 15.582821764013204 ], [ -86.391232876196284, 15.559670722525823 ], [ -86.37976070779041, 15.546234850258145 ], [ -86.377383591879266, 15.542410794422608 ], [ -86.372345140116124, 15.540653795236437 ], [ -86.362061530115511, 15.539930324824638 ], [ -86.314105800742084, 15.541790675898937 ], [ -86.288810188239552, 15.535589504152256 ], [ -86.282996589221227, 15.535796209727266 ], [ -86.280748663619931, 15.535331121733861 ], [ -86.277906459715325, 15.534142564227921 ], [ -86.275374315072554, 15.532695624303585 ], [ -86.272532111168005, 15.53031850839244 ], [ -86.269147304904209, 15.526236070138509 ], [ -86.266330939421323, 15.524272366276648 ], [ -86.263540412360101, 15.523290514345717 ], [ -86.260181443618706, 15.522773749508929 ], [ -86.25775265176344, 15.521688543891173 ], [ -86.25565975579309, 15.520138251179333 ], [ -86.254264492712139, 15.518794664042503 ], [ -86.252895067153588, 15.518742988098381 ], [ -86.251758185591768, 15.520086575235268 ], [ -86.250156216036544, 15.522722073564807 ], [ -86.247624071393773, 15.524117335746439 ], [ -86.243283250721447, 15.523497219021408 ], [ -86.240260178764231, 15.520861720691869 ], [ -86.237392137337224, 15.512541816351757 ], [ -86.235583462206989, 15.499312648759712 ], [ -86.241681281166166, 15.454405828865902 ], [ -86.241061164441192, 15.449341539580359 ], [ -86.234446580645169, 15.436060696044251 ], [ -86.232896287933329, 15.409757392289805 ], [ -86.27764807819625, 15.378544827082067 ], [ -86.290515509683019, 15.374152330465677 ], [ -86.346067673884022, 15.341596178121108 ], [ -86.371957567387824, 15.329400540202755 ], [ -86.385264248446276, 15.32795360027842 ], [ -86.409112921923793, 15.328263657741616 ], [ -86.420404222277, 15.331881008002085 ], [ -86.426605394023682, 15.336841946298762 ], [ -86.429680141925019, 15.342836412470433 ], [ -86.434486049691429, 15.349864407416476 ], [ -86.442754278986797, 15.358494371018367 ], [ -86.451978521791318, 15.366400865107835 ], [ -86.464742601389901, 15.374669094403146 ], [ -86.47918616401023, 15.382317206074163 ], [ -86.503034838387066, 15.389293525076084 ], [ -86.514067756321879, 15.3892418482327 ], [ -86.526547614181027, 15.386244614697205 ], [ -86.611322801306244, 15.341492825333603 ], [ -86.618790045823914, 15.338753974216502 ], [ -86.624138556848891, 15.339115709422458 ], [ -86.628789435883732, 15.340355942872463 ], [ -86.632949387604128, 15.340872707709252 ], [ -86.63822038426332, 15.337203681504661 ], [ -86.64186357294551, 15.331260891277111 ], [ -86.651837123684288, 15.305939439453539 ], [ -86.659743618673019, 15.296586005439792 ], [ -86.666358201569722, 15.282323309972753 ], [ -86.676280077263755, 15.279274400493193 ], [ -86.686356980790038, 15.271936347184635 ], [ -86.692739020589329, 15.268629055286681 ], [ -86.70064551467874, 15.266923732943894 ], [ -86.71875810440298, 15.266820380156389 ], [ -86.729661831128567, 15.268680732130065 ], [ -86.738136765998945, 15.27090281841032 ], [ -86.768729213582333, 15.295294094247026 ], [ -86.815315518296529, 15.28537221945237 ], [ -86.817692634207674, 15.277259018888572 ], [ -86.826219245022116, 15.271109523985331 ], [ -86.829707404073417, 15.269765936848501 ], [ -86.844616054687151, 15.262014472389978 ], [ -86.851437344058183, 15.260619208409707 ], [ -86.855545619834459, 15.257673651717653 ], [ -86.85887875015419, 15.253591213463721 ], [ -86.862056850842976, 15.240051988408538 ], [ -86.862909511564681, 15.23193878784474 ], [ -86.855132208684495, 15.17163239182139 ], [ -86.862987026829785, 15.154630846136627 ], [ -86.863193732404795, 15.15158193575769 ], [ -86.862599453202165, 15.147602851190641 ], [ -86.862444423571276, 15.143778795355104 ], [ -86.864537320440945, 15.137991033859123 ], [ -86.871487800121884, 15.127242335865105 ], [ -86.875802782372489, 15.118095608325632 ], [ -86.878231574227755, 15.11111929022303 ], [ -86.879006720583675, 15.10460805921457 ], [ -86.879161750214564, 15.098303533781063 ], [ -86.88066036698234, 15.090552070221861 ], [ -86.886163906738886, 15.081560370514694 ], [ -86.901020881408556, 15.071535142033156 ], [ -86.920993822207095, 15.053965155567482 ], [ -86.951250373006303, 15.04600698553395 ], [ -86.959131028673994, 15.047453925458285 ], [ -86.96349768776804, 15.047608954189855 ], [ -86.969569668305553, 15.043784898354374 ], [ -86.973316209775248, 15.040580960143188 ], [ -86.987475551555463, 15.015879625044647 ], [ -87.021039395151945, 15.023062648722259 ], [ -87.074705369856929, 15.020892239285388 ], [ -87.090053270042347, 15.025078030326824 ], [ -87.098088955340984, 15.029057114893931 ], [ -87.109690314056706, 15.03133087801757 ], [ -87.119379645754009, 15.031899318798537 ], [ -87.167025315865601, 15.02595652947025 ], [ -87.184827847227325, 15.011383774741375 ], [ -87.184233568024752, 15.001048488796698 ], [ -87.185525479217461, 14.980481268795529 ], [ -87.186894903876691, 14.974590155411306 ], [ -87.190202195774702, 14.96911245407648 ], [ -87.210149299050897, 14.952265937123286 ], [ -87.220277880319884, 14.937796536081237 ], [ -87.22655656643235, 14.923947251764218 ], [ -87.245806036819147, 14.897747300797278 ], [ -87.272677782253822, 14.921260077490558 ], [ -87.27900814520973, 14.923017075777409 ], [ -87.285235155378075, 14.92420563418267 ], [ -87.291746384587952, 14.918314520798504 ], [ -87.297198249299754, 14.916660875299158 ], [ -87.30285681778787, 14.919554755147828 ], [ -87.310556607201647, 14.925807602838574 ], [ -87.314897426974653, 14.927978014074085 ], [ -87.350657518429728, 14.937279771244448 ], [ -87.374687059060534, 14.938830063956289 ], [ -87.394065720656442, 14.920846666340537 ], [ -87.418637865445135, 14.90854767473536 ], [ -87.433572353581212, 14.90875438120969 ], [ -87.444269374731846, 14.91087311380312 ], [ -87.449437018603533, 14.913922024182057 ], [ -87.452020840089688, 14.916454168824828 ], [ -87.452020840089688, 14.918779608791908 ], [ -87.451710781727172, 14.921363430278063 ], [ -87.451788296092957, 14.923740546189265 ], [ -87.454552984732459, 14.929941717935947 ], [ -87.455638190350214, 14.934282537708953 ], [ -87.458738775773838, 14.941362210397699 ], [ -87.460134039754109, 14.946994941363414 ], [ -87.460263230963335, 14.951645820398255 ], [ -87.459436407763974, 14.960999254412059 ], [ -87.460676643012675, 14.965908514965975 ], [ -87.463751390014636, 14.972006333925151 ], [ -87.469099901039613, 14.974590155411306 ], [ -87.473182339293487, 14.980222887276398 ], [ -87.47713558633825, 14.982600002288279 ], [ -87.486669888404606, 14.985803941398785 ], [ -87.491604987380242, 14.989266262028366 ], [ -87.496436733568373, 14.993452053069802 ], [ -87.498658819848629, 14.997172756117777 ], [ -87.500467494978921, 15.001565252734224 ], [ -87.503232185417005, 15.013864244339402 ], [ -87.506410285206471, 15.022649238471558 ], [ -87.516848923938653, 15.037687079395198 ], [ -87.524729579606401, 15.045490220697104 ], [ -87.537571173570768, 15.054068508354987 ], [ -87.54359147816416, 15.056497301109516 ], [ -87.548268194721402, 15.057634181772073 ], [ -87.551342942622682, 15.057014065047042 ], [ -87.554727748886478, 15.055618801066828 ], [ -87.58387325744485, 15.034741522703087 ], [ -87.587413093339592, 15.026266587832765 ], [ -87.631183030772263, 15.016603095456503 ], [ -87.642345139916245, 15.017946681694013 ], [ -87.735879482751898, 15.016551419512382 ], [ -87.741279669720939, 15.061458238506873 ], [ -87.740065273793334, 15.067866115828565 ], [ -87.737429776363058, 15.075152493193002 ], [ -87.733786586781548, 15.077684637835773 ], [ -87.732158779703923, 15.081457016827869 ], [ -87.732313809334812, 15.08646963106861 ], [ -87.733321498788143, 15.094376126057341 ], [ -87.737300585153889, 15.104556383270449 ], [ -87.738359952349924, 15.11111929022303 ], [ -87.767686327162266, 15.139696357101172 ], [ -87.783395961654264, 15.136854153196623 ], [ -87.788434414316725, 15.137474269921597 ], [ -87.794067146181817, 15.139593004313667 ], [ -87.796521775559484, 15.149204819846545 ], [ -87.799803229935094, 15.153390610887982 ], [ -87.810991176601476, 15.153700670149817 ], [ -87.814427659708713, 15.154785874868196 ], [ -87.817864142815949, 15.157989813978702 ], [ -87.822153285745514, 15.159850165053058 ], [ -87.836932746049399, 15.159591783533983 ], [ -87.842565477015114, 15.160418605833968 ], [ -87.845149299400646, 15.165172838555634 ], [ -87.846079475387455, 15.16930695185431 ], [ -87.848689134396011, 15.173802802157581 ], [ -87.853081631012458, 15.178195298774028 ], [ -87.867861091316286, 15.18935740791801 ], [ -87.878713142097808, 15.191837877516036 ], [ -87.897755906909538, 15.193284817440372 ], [ -87.918374802854828, 15.187807115206169 ], [ -87.92310319715483, 15.190804347842345 ], [ -87.922974005945605, 15.194938462939717 ], [ -87.919795905256819, 15.204653632159363 ], [ -87.920596890034403, 15.211578274317901 ], [ -87.917186245348944, 15.225840968885564 ], [ -87.917496303711403, 15.237778225284842 ], [ -87.918374802854828, 15.239070136477608 ], [ -87.921036139606144, 15.240465400457822 ], [ -87.926849737725206, 15.237829902128283 ], [ -87.930725471303447, 15.237313137291437 ], [ -87.935117967020517, 15.244754544286764 ], [ -87.926462164996906, 15.259120592541308 ], [ -87.928374192914646, 15.26971426000506 ], [ -87.92553198901004, 15.276070461382687 ], [ -87.924059210664041, 15.282891750753663 ], [ -87.924110886608105, 15.289816392012881 ], [ -87.92576453300677, 15.296430975808846 ], [ -87.913749763141027, 15.308833320201529 ], [ -87.911140103233151, 15.313535875180492 ], [ -87.911269294442377, 15.316998195810072 ], [ -87.912587043157487, 15.320253810864642 ], [ -87.913310512670023, 15.323406073131764 ], [ -87.911579352804893, 15.32661001224227 ], [ -87.90687679692661, 15.32893545220935 ], [ -87.893570115868158, 15.332501126525756 ], [ -87.887627325640551, 15.335808417524447 ], [ -87.8785581115676, 15.342681382839544 ], [ -87.873907233432078, 15.345006821907305 ], [ -87.869953986387372, 15.347952379498679 ], [ -87.863003505807114, 15.356375637525616 ], [ -87.83848303876124, 15.396114814447117 ], [ -87.823858608987621, 15.408052069947075 ], [ -87.820189581883653, 15.416268622399002 ], [ -87.823781093722459, 15.429962877085075 ], [ -87.833728806938893, 15.439729723148162 ], [ -87.84597612170063, 15.445879218051459 ], [ -87.852719895806501, 15.4516669777488 ], [ -87.84633785690653, 15.460451971880957 ], [ -87.835124070919107, 15.460348619093509 ], [ -87.82437537292509, 15.45301056578495 ], [ -87.816417201992238, 15.451563625860615 ], [ -87.813549159665968, 15.469133613225665 ], [ -87.818639289171813, 15.482259426231508 ], [ -87.82747595924809, 15.494455064149861 ], [ -87.830938279877671, 15.50851105404189 ], [ -87.819931200364579, 15.52706289333787 ], [ -87.809776780673872, 15.533677476234516 ], [ -87.804505784913999, 15.547785142070609 ], [ -87.800423346660125, 15.564114895086334 ], [ -87.793912115651608, 15.577654120141517 ], [ -87.790837368649647, 15.577085680259927 ], [ -87.78486874089964, 15.574863593080352 ], [ -87.777763230688549, 15.574036769880991 ], [ -87.771252000579352, 15.577757472929022 ], [ -87.772001309412872, 15.581168118513858 ], [ -87.76463741678333, 15.606851305543273 ], [ -87.762208624928064, 15.610158596541964 ], [ -87.777349820437848, 15.63320628524184 ], [ -87.803446417717964, 15.653566798768736 ], [ -87.819750332311969, 15.671601874127191 ], [ -87.805461799322586, 15.687879950299475 ], [ -87.823548549725786, 15.691548977403386 ], [ -87.817967494704078, 15.701367499410537 ], [ -87.787581752695701, 15.721004544324273 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "HN-FM", "NAME_1": "Francisco Morazán" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -87.318669806866069, 14.666598619330784 ], [ -87.315052455706223, 14.667632148105156 ], [ -87.313812222256217, 14.670267646434695 ], [ -87.313347134262813, 14.676417141337993 ], [ -87.312261928645057, 14.679259345242599 ], [ -87.310014003943138, 14.680602932379429 ], [ -87.306293300895106, 14.681068020372834 ], [ -87.300738085194439, 14.682876695503069 ], [ -87.291978928584683, 14.689336248768825 ], [ -87.288749151951777, 14.690679835905712 ], [ -87.285105964168906, 14.691610011892521 ], [ -87.280403409189944, 14.693367011078692 ], [ -87.275519986158429, 14.695744126989837 ], [ -87.268104417584766, 14.700756741230634 ], [ -87.266089036879521, 14.703133857141779 ], [ -87.266011521614416, 14.705045885059519 ], [ -87.267019212866387, 14.706544500927976 ], [ -87.266244065611147, 14.71083364475686 ], [ -87.255417854150608, 14.738325506916624 ], [ -87.249449226400657, 14.761838284509224 ], [ -87.253609178121053, 14.795738023091303 ], [ -87.25820838121183, 14.811292628851731 ], [ -87.257252366803243, 14.82689891235492 ], [ -87.254487678163798, 14.836614081574567 ], [ -87.251361254318397, 14.841781725446253 ], [ -87.248364020782901, 14.844572252507419 ], [ -87.24544430161319, 14.845502428494285 ], [ -87.224541184827785, 14.847466132356089 ], [ -87.208340623920662, 14.859455063800112 ], [ -87.218262498715319, 14.874286200048061 ], [ -87.219425217799539, 14.881469225524313 ], [ -87.224670376037011, 14.886946925959876 ], [ -87.228391079085043, 14.889995836338755 ], [ -87.245806036819147, 14.897747300797278 ], [ -87.22655656643235, 14.923947251764218 ], [ -87.220277880319884, 14.937796536081237 ], [ -87.210149299050897, 14.952265937123286 ], [ -87.190202195774702, 14.96911245407648 ], [ -87.186894903876691, 14.974590155411306 ], [ -87.185525479217461, 14.980481268795529 ], [ -87.184233568024752, 15.001048488796698 ], [ -87.184827847227325, 15.011383774741375 ], [ -87.167025315865601, 15.02595652947025 ], [ -87.119379645754009, 15.031899318798537 ], [ -87.109690314056706, 15.03133087801757 ], [ -87.098088955340984, 15.029057114893931 ], [ -87.090053270042347, 15.025078030326824 ], [ -87.074705369856929, 15.020892239285388 ], [ -87.021039395151945, 15.023062648722259 ], [ -86.987475551555463, 15.015879625044647 ], [ -86.984995082856756, 15.00476919184473 ], [ -86.980964322345585, 14.998102932104644 ], [ -86.970654873023932, 14.985855618242169 ], [ -86.961637335794421, 14.977277330584343 ], [ -86.938124559101084, 14.965288398240943 ], [ -86.926652390695267, 14.953506171472611 ], [ -86.912234667395978, 14.946116441320669 ], [ -86.908358933817738, 14.942860826266099 ], [ -86.906136848436802, 14.940173651992438 ], [ -86.915490281551229, 14.932525540321421 ], [ -86.923551805271586, 14.905395413367614 ], [ -86.933292812912953, 14.897333888747937 ], [ -86.927272508319561, 14.876249904809242 ], [ -86.923706834902475, 14.86906688113163 ], [ -86.916988898319005, 14.858318183137612 ], [ -86.912415533649948, 14.8476728379311 ], [ -86.909909227428898, 14.820697739708919 ], [ -86.907170376311797, 14.809949041714901 ], [ -86.899470587797396, 14.799096990933378 ], [ -86.891357388132917, 14.762200018815804 ], [ -86.860170661346899, 14.687579251381351 ], [ -86.848336757735183, 14.66592682486305 ], [ -86.834952562310889, 14.651509101563761 ], [ -86.826064216290547, 14.644481105718455 ], [ -86.806633876951821, 14.639830227582934 ], [ -86.797306281359795, 14.630321763938241 ], [ -86.76247636589153, 14.598799140368044 ], [ -86.743717821020596, 14.575338040518147 ], [ -86.744415453010731, 14.557457993891262 ], [ -86.748601244052168, 14.541438300137429 ], [ -86.747516039333732, 14.532963365267051 ], [ -86.745113085000867, 14.523661607197425 ], [ -86.734700283791028, 14.507641913443535 ], [ -86.731057095108838, 14.500407212922539 ], [ -86.729300095922667, 14.485317695155516 ], [ -86.726147833655602, 14.471571764525322 ], [ -86.713564623008949, 14.437827052876173 ], [ -86.714210578155644, 14.423822739827585 ], [ -86.788934699276922, 14.368270574727205 ], [ -86.821697557196501, 14.337781479931323 ], [ -86.829138964191827, 14.30496694606768 ], [ -86.848130052160172, 14.271687323311312 ], [ -86.89686092788952, 14.229932766583886 ], [ -86.908927374598647, 14.198668525432083 ], [ -86.91993445501106, 14.18357900586642 ], [ -86.921923998193961, 14.178566392524999 ], [ -86.920657925422915, 14.174897366320408 ], [ -86.912389696127548, 14.172675279140833 ], [ -86.906860317949281, 14.169574692817832 ], [ -86.903036262113801, 14.164820460995486 ], [ -86.901873542130261, 14.160996405159949 ], [ -86.912182989653218, 14.140842597208064 ], [ -86.933215297647848, 14.137845364571888 ], [ -86.949157477935216, 14.140842597208064 ], [ -86.963006761352915, 14.140842597208064 ], [ -86.984297451765997, 14.132626043856817 ], [ -86.978277147172605, 14.114745999028628 ], [ -86.952232224937234, 14.080277817867 ], [ -86.924740362777527, 14.06043406827763 ], [ -86.917118090427493, 14.056248277236193 ], [ -86.914250048101223, 14.049995429545447 ], [ -86.912286343340043, 14.038936672289594 ], [ -86.915955370443953, 13.999300849054919 ], [ -86.926729905960372, 13.978992011472144 ], [ -86.93827958873203, 13.966899726341296 ], [ -86.954583503325978, 13.958424791470918 ], [ -86.989258389163297, 13.964522610430095 ], [ -86.985150113387022, 13.950053209388102 ], [ -86.984219937400155, 13.942818507967729 ], [ -86.984995082856756, 13.934291897153344 ], [ -86.989904344310048, 13.924473375146135 ], [ -86.992488165796203, 13.911605942760048 ], [ -86.990989549028427, 13.891865545958183 ], [ -86.995071988181678, 13.84592519818932 ], [ -87.013933884940798, 13.8004499375146 ], [ -87.030547857897318, 13.779004218369948 ], [ -87.035534633716338, 13.775386868109479 ], [ -87.051218430685992, 13.775180162534468 ], [ -87.075687221787859, 13.779727687882485 ], [ -87.083800422351601, 13.783706773348911 ], [ -87.106486375845577, 13.80349884699416 ], [ -87.1215500560902, 13.810320136365192 ], [ -87.128190477408566, 13.802465318219845 ], [ -87.129895798852033, 13.798744615171813 ], [ -87.131652798038203, 13.790941473869907 ], [ -87.132272914763178, 13.776782131190373 ], [ -87.131549445250698, 13.76267446535428 ], [ -87.128681402924371, 13.752132472935273 ], [ -87.122557746442851, 13.744587714051761 ], [ -87.111163093302082, 13.724020494050535 ], [ -87.111628181295487, 13.70831085955848 ], [ -87.119508836963234, 13.697613837508584 ], [ -87.127027758324346, 13.681594142855374 ], [ -87.129844122907912, 13.664334214752216 ], [ -87.130205858113868, 13.660045070923275 ], [ -87.134753384361204, 13.660871894122579 ], [ -87.182683275312911, 13.68112905486197 ], [ -87.214231737304829, 13.671103827279808 ], [ -87.263427701027581, 13.688415432226407 ], [ -87.29771501323728, 13.684332993972475 ], [ -87.307533535244431, 13.688777167432306 ], [ -87.31947079074439, 13.694874986391483 ], [ -87.360088466809259, 13.690120754569136 ], [ -87.373601854342098, 13.702781480480951 ], [ -87.392825487206437, 13.721126614201864 ], [ -87.394815030389339, 13.733942368845248 ], [ -87.387606167390686, 13.750892239485268 ], [ -87.386727668247261, 13.755078030526647 ], [ -87.390732591236088, 13.756111558401699 ], [ -87.396546190254469, 13.756008206513513 ], [ -87.40101620213602, 13.754974676839822 ], [ -87.412229987224123, 13.757506822381913 ], [ -87.42390886120495, 13.760607407805594 ], [ -87.443339199644356, 13.760297349443135 ], [ -87.454372117579169, 13.756886704757619 ], [ -87.457524379846234, 13.745414537251065 ], [ -87.459901495757379, 13.719472967803199 ], [ -87.465405036413301, 13.697820543083594 ], [ -87.465250006782355, 13.683506170773171 ], [ -87.46114173010676, 13.670173652192261 ], [ -87.468789841777777, 13.665832831519936 ], [ -87.479021775834269, 13.668623359480421 ], [ -87.505144213334745, 13.684643053234311 ], [ -87.540749274259611, 13.710998032932878 ], [ -87.543694830951665, 13.714512030405842 ], [ -87.548397385930627, 13.717302558366384 ], [ -87.551988897769377, 13.71874949829072 ], [ -87.570308193967946, 13.716889146317044 ], [ -87.60102983276056, 13.722676906913705 ], [ -87.641854214400439, 13.749858709811576 ], [ -87.649398973283951, 13.761227525429945 ], [ -87.647280239791201, 13.804790758186925 ], [ -87.647047695794527, 13.834194648264372 ], [ -87.619374965582153, 13.868817857258307 ], [ -87.611520148336183, 13.892175605220018 ], [ -87.608832974062466, 13.896206365731189 ], [ -87.6060424470013, 13.902924303214036 ], [ -87.598316820065179, 13.938167628932888 ], [ -87.596585660200049, 13.957287909009779 ], [ -87.615240852283478, 14.088494371218246 ], [ -87.614336513819069, 14.109113267163536 ], [ -87.593433397033607, 14.133762926317956 ], [ -87.585707770996805, 14.140325833270595 ], [ -87.579532436772524, 14.143529771481781 ], [ -87.573305426604122, 14.14332306590677 ], [ -87.541214362253015, 14.146785387435671 ], [ -87.512585619430752, 14.159601142079055 ], [ -87.500674200553874, 14.166732488913226 ], [ -87.494266324131559, 14.174432278326947 ], [ -87.493542853719703, 14.179858302818388 ], [ -87.482949185356574, 14.201097317287349 ], [ -87.46320878765539, 14.213189602418197 ], [ -87.437086351054234, 14.218874010227353 ], [ -87.429644944958227, 14.222749742006954 ], [ -87.42545915391679, 14.229054267440461 ], [ -87.425691697913521, 14.234945379925307 ], [ -87.426931932262846, 14.239337877441073 ], [ -87.429877488954958, 14.245539049187755 ], [ -87.431401944144397, 14.24734772431799 ], [ -87.433727383212158, 14.248639635510756 ], [ -87.437060512632513, 14.249673163385751 ], [ -87.440419481373965, 14.251223456097591 ], [ -87.44491533077786, 14.254220688733767 ], [ -87.450599737687753, 14.259336655762013 ], [ -87.456568366337024, 14.265744533983025 ], [ -87.459875658235035, 14.271790676098817 ], [ -87.462046067671849, 14.282177638886935 ], [ -87.463854742802141, 14.321606757445863 ], [ -87.46207190609357, 14.332252101753056 ], [ -87.459281379032404, 14.338039863249094 ], [ -87.454708015262668, 14.339900214323393 ], [ -87.450134649694292, 14.340106919898403 ], [ -87.44434688999695, 14.339176743911594 ], [ -87.432047899291092, 14.333285631426747 ], [ -87.424554816351701, 14.336024482543792 ], [ -87.419413010901735, 14.339486803173429 ], [ -87.393187222412394, 14.374006659379802 ], [ -87.382748582780835, 14.395297349792827 ], [ -87.386262580253856, 14.402635403101385 ], [ -87.410679693612963, 14.421135566453188 ], [ -87.412359178433348, 14.423822739827585 ], [ -87.413186000733333, 14.427026678938091 ], [ -87.409852871312921, 14.429817205999257 ], [ -87.407372402614271, 14.433951321096572 ], [ -87.406958990564931, 14.44356313752877 ], [ -87.408974372169496, 14.448214016563611 ], [ -87.411894091339207, 14.451934718712266 ], [ -87.435225999979878, 14.472088528462791 ], [ -87.451064825681158, 14.482372138463404 ], [ -87.456335822340293, 14.489606838085081 ], [ -87.460495774960009, 14.498960272998204 ], [ -87.463002082080379, 14.506815090244231 ], [ -87.46592180035077, 14.522214667273033 ], [ -87.415046352707009, 14.571513983783291 ], [ -87.406028814578121, 14.589549058242426 ], [ -87.405357021909026, 14.594561672483167 ], [ -87.40403927319386, 14.600091051560753 ], [ -87.403419155569566, 14.605878811258094 ], [ -87.403729213932081, 14.620709947506043 ], [ -87.40197221564523, 14.62468903207315 ], [ -87.39869076216894, 14.626756090521155 ], [ -87.395202603117639, 14.626497708102704 ], [ -87.390629239347902, 14.62489573854748 ], [ -87.386365933041361, 14.62262197542384 ], [ -87.38192175958153, 14.620813300293548 ], [ -87.377735969439414, 14.619883124306739 ], [ -87.374170295123008, 14.619728095575113 ], [ -87.371121384744072, 14.619883124306739 ], [ -87.368382535425667, 14.619573065944223 ], [ -87.366987271445396, 14.618022773232383 ], [ -87.36590206582764, 14.613940334978452 ], [ -87.36455847869081, 14.612028307060712 ], [ -87.36130286273692, 14.610529690292935 ], [ -87.357272102225693, 14.609237779100226 ], [ -87.353215502393482, 14.608410955900865 ], [ -87.342130906715965, 14.607790839175891 ], [ -87.327144741736447, 14.633525702149427 ], [ -87.32347571463248, 14.647271632779621 ], [ -87.3235015530542, 14.652697659069702 ], [ -87.324173346622615, 14.658433742822979 ], [ -87.32582699302128, 14.665978501706491 ], [ -87.325051845766041, 14.66959585196696 ], [ -87.323656581785826, 14.670629380741332 ], [ -87.322106289073986, 14.66959585196696 ], [ -87.320555996362145, 14.667942206467615 ], [ -87.318669806866069, 14.666598619330784 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/latvia.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/latvia.geojson new file mode 100644 index 0000000000000..90dc6ddd50c4c --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/latvia.geojson @@ -0,0 +1,125 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "LV-084", "NAME_1": "Rujienas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.263501424000111, 58.075138449000079 ], [ 25.281691528000067, 58.073407288000013 ], [ 25.299571574000112, 58.065604147 ], [ 25.30639286300007, 58.058731181000027 ], [ 25.318278443000111, 58.040618592 ], [ 25.324582967000111, 58.034753317000096 ], [ 25.333678019000104, 58.03180776 ], [ 25.33987919100008, 58.03258290600003 ], [ 25.346390421000137, 58.034443258000024 ], [ 25.356519002000084, 58.034753317000096 ], [ 25.396619914000098, 58.02317779600007 ], [ 25.419731367148021, 58.008250005422155 ], [ 25.406834255496449, 57.991310424136714 ], [ 25.403702900668293, 57.97095661685438 ], [ 25.370823673173959, 57.969390939440302 ], [ 25.345772833649335, 57.966259584612089 ], [ 25.341075801407101, 57.985047714480402 ], [ 25.326984703781022, 57.991310424136714 ], [ 25.301933864256398, 57.97095661685438 ], [ 25.278448702145852, 57.953734165299466 ], [ 25.261226250590994, 57.938077390259309 ], [ 25.270620315075462, 57.913026550734685 ], [ 25.30036818684232, 57.905198163664295 ], [ 25.336378769164867, 57.903632486250217 ], [ 25.358298253861335, 57.881713001553749 ], [ 25.381783415971825, 57.883278678967827 ], [ 25.406834255496449, 57.847268096645337 ], [ 25.417793997395052, 57.815954547464344 ], [ 25.452238902303463, 57.815954547464344 ], [ 25.455370257131619, 57.789338030525641 ], [ 25.378652061143669, 57.787772353111563 ], [ 25.31289360705432, 57.78307532086933 ], [ 25.270620315075462, 57.778378287727776 ], [ 25.267488960247306, 57.79560074018201 ], [ 25.245569475550838, 57.800297772424244 ], [ 25.250266507793071, 57.820651579706634 ], [ 25.247135152964916, 57.851965128887571 ], [ 25.217387281198057, 57.872318936169961 ], [ 25.212690248955823, 57.887975711210061 ], [ 25.195467796501589, 57.905198163664295 ], [ 25.167285602148809, 57.914592228148763 ], [ 25.134406374654475, 57.930249003188919 ], [ 25.12501231016995, 57.95060281047131 ], [ 25.137537729482631, 57.956865520127621 ], [ 25.13284069724034, 57.977219327410012 ], [ 25.10465850288756, 57.981916359652246 ], [ 25.095264438403092, 58.003835844348714 ], [ 25.10465850288756, 58.025755329045182 ], [ 25.109355535129851, 58.044543458913495 ], [ 25.094209432000127, 58.067309469000051 ], [ 25.141028280000057, 58.068007101000049 ], [ 25.166969848000093, 58.058731181000027 ], [ 25.180715780000128, 58.038163961000052 ], [ 25.189914184000116, 58.013514303000036 ], [ 25.20210982200004, 57.991965230000076 ], [ 25.216785930000128, 57.985376486000106 ], [ 25.232495565000107, 57.985376486000106 ], [ 25.264534953000094, 57.994187318000101 ], [ 25.284378703000101, 58.008139954000072 ], [ 25.277557414000057, 58.024107972000124 ], [ 25.249548788000141, 58.051186422000072 ], [ 25.250685669000035, 58.068498027 ], [ 25.263501424000111, 58.075138449000079 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-060", "NAME_1": "Mazsalacas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.034856819000083, 58.048574085000027 ], [ 25.048837524000106, 58.056199036000052 ], [ 25.070644978000132, 58.063614604000051 ], [ 25.094209432000127, 58.067309469000051 ], [ 25.109355535129851, 58.044543458913495 ], [ 25.10465850288756, 58.025755329045182 ], [ 25.095264438403092, 58.003835844348714 ], [ 25.10465850288756, 57.981916359652246 ], [ 25.13284069724034, 57.977219327410012 ], [ 25.137537729482631, 57.956865520127621 ], [ 25.12501231016995, 57.95060281047131 ], [ 25.134406374654475, 57.930249003188919 ], [ 25.167285602148809, 57.914592228148763 ], [ 25.195467796501589, 57.905198163664295 ], [ 25.212690248955823, 57.887975711210061 ], [ 25.217387281198057, 57.872318936169961 ], [ 25.247135152964916, 57.851965128887571 ], [ 25.250266507793071, 57.820651579706634 ], [ 25.245569475550838, 57.800297772424244 ], [ 25.223649990854369, 57.804994804666478 ], [ 25.157891536764964, 57.833176999918578 ], [ 25.142234762624184, 57.844136741817181 ], [ 25.112486889958006, 57.837874032160812 ], [ 25.123446632755872, 57.826914289362946 ], [ 25.13284069724034, 57.808126160393954 ], [ 25.128143664998106, 57.798732095010166 ], [ 25.112486889958006, 57.800297772424244 ], [ 25.092133083574936, 57.812823192636188 ], [ 25.06081953349468, 57.812823192636188 ], [ 25.034203016555978, 57.814388870050266 ], [ 25.017469133393774, 57.796470091421554 ], [ 25.007445510202103, 57.801381741474188 ], [ 24.965690951676038, 57.808306382733349 ], [ 24.953288609082051, 57.800089830281422 ], [ 24.946002231717614, 57.817530626437247 ], [ 24.941971470307067, 57.818615831155682 ], [ 24.938250767259092, 57.819055080727367 ], [ 24.933134800230846, 57.81755646395959 ], [ 24.926158482128244, 57.817091375966186 ], [ 24.909363641119114, 57.820657050282591 ], [ 24.901147087767868, 57.825514634892443 ], [ 24.895721063276426, 57.831199041802336 ], [ 24.893395623309345, 57.843368842198288 ], [ 24.887814569187015, 57.858535875230416 ], [ 24.885179070857419, 57.87153249792641 ], [ 24.883473747615369, 57.883753974266483 ], [ 24.885024041226529, 57.889076646869739 ], [ 24.881923455802848, 57.893004055492725 ], [ 24.873396844089086, 57.898016668834146 ], [ 24.864043410075283, 57.900316271278882 ], [ 24.842339307612917, 57.900936388003856 ], [ 24.82761152505185, 57.980130520107366 ], [ 24.827417479000076, 57.981876936000091 ], [ 24.848332967000118, 57.992146098000049 ], [ 24.872517537000078, 58.000440165 ], [ 24.949308716000047, 58.006434631000033 ], [ 24.9748368730001, 58.015839742000068 ], [ 25.034856819000083, 58.048574085000027 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-005", "NAME_1": "Alojas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.816810344000146, 57.976669007000041 ], [ 24.827417479000076, 57.981876936000091 ], [ 24.82761152505185, 57.980130520107366 ], [ 24.842339307612917, 57.900936388003856 ], [ 24.864043410075283, 57.900316271278882 ], [ 24.873396844089086, 57.898016668834146 ], [ 24.881923455802848, 57.893004055492725 ], [ 24.885024041226529, 57.889076646869739 ], [ 24.883473747615369, 57.883753974266483 ], [ 24.885179070857419, 57.87153249792641 ], [ 24.887814569187015, 57.858535875230416 ], [ 24.893395623309345, 57.843368842198288 ], [ 24.895721063276426, 57.831199041802336 ], [ 24.901147087767868, 57.825514634892443 ], [ 24.909363641119114, 57.820657050282591 ], [ 24.926158482128244, 57.817091375966186 ], [ 24.933134800230846, 57.81755646395959 ], [ 24.938250767259092, 57.819055080727367 ], [ 24.941971470307067, 57.818615831155682 ], [ 24.946002231717614, 57.817530626437247 ], [ 24.953288609082051, 57.800089830281422 ], [ 24.965690951676038, 57.808306382733349 ], [ 25.007445510202103, 57.801381741474188 ], [ 25.017469133393774, 57.796470091421554 ], [ 25.077260369870146, 57.767171942730954 ], [ 25.083616571247774, 57.75414948251256 ], [ 25.098706089014797, 57.736011054366656 ], [ 25.090902947712834, 57.73125682254431 ], [ 25.087182244664859, 57.727174384290379 ], [ 25.080205925662938, 57.721231594062772 ], [ 25.07617516425239, 57.714513658378621 ], [ 25.075710077158305, 57.705935370720738 ], [ 25.082221307267503, 57.696891995069507 ], [ 25.092453241323994, 57.688236192146519 ], [ 25.085321892691184, 57.674619452725551 ], [ 25.093745150718121, 57.653122056737516 ], [ 25.067028435813654, 57.654982407811815 ], [ 25.062222528047187, 57.65239858722498 ], [ 25.063307732765622, 57.648109443396095 ], [ 25.075865105889932, 57.638704332538907 ], [ 25.083306511985938, 57.63410513034745 ], [ 25.084701775966153, 57.629764308775805 ], [ 25.067803582169574, 57.626457017777113 ], [ 25.061602411322212, 57.623950711556063 ], [ 25.042378777558497, 57.625836900152819 ], [ 25.03302534444407, 57.630177720825145 ], [ 25.027599318153989, 57.634260159079076 ], [ 25.024033643837583, 57.637360745402077 ], [ 25.019072707339546, 57.638135890858621 ], [ 25.005740186960054, 57.636120510153376 ], [ 25.000159132837666, 57.635862127734981 ], [ 24.991477492392335, 57.636482246258652 ], [ 24.966311069300389, 57.628420722538294 ], [ 24.93453006421106, 57.612039293578505 ], [ 24.881437081755905, 57.624673657663152 ], [ 24.892562524640766, 57.652487264875333 ], [ 24.831372589673265, 57.666394068031764 ], [ 24.824419188095021, 57.699770395787084 ], [ 24.828591229401695, 57.719239921285293 ], [ 24.799386942053729, 57.733146724441724 ], [ 24.747931768935985, 57.731756044305996 ], [ 24.707602039602421, 57.749834888769101 ], [ 24.692304555410885, 57.760960331653962 ], [ 24.649193464906489, 57.770695093503718 ], [ 24.597738292688064, 57.870824078568319 ], [ 24.5740967267825, 57.881949520553917 ], [ 24.59078489110982, 57.894465643574563 ], [ 24.588003529938931, 57.920888570650959 ], [ 24.582445250259351, 57.946010847151072 ], [ 24.624057251000096, 57.943957825000055 ], [ 24.684828735000082, 57.94757517500004 ], [ 24.700435018000121, 57.954189758000027 ], [ 24.718831828000134, 57.981836650000034 ], [ 24.733507935000119, 57.992197774000047 ], [ 24.764720500000095, 57.987908631 ], [ 24.790765421000089, 57.978994446000073 ], [ 24.816810344000146, 57.976669007000041 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-064", "NAME_1": "Nauksenu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.551815984000143, 57.949859510000024 ], [ 25.552114298000049, 57.948815410000051 ], [ 25.552941122000078, 57.942174988000048 ], [ 25.55831547000011, 57.934242656000023 ], [ 25.579399455000072, 57.919463196 ], [ 25.601516968000055, 57.912202658000112 ], [ 25.625081421000061, 57.910290630000091 ], [ 25.650092814000061, 57.911427511000014 ], [ 25.703799772000053, 57.921326524000065 ], [ 25.666077060707778, 57.914373651522794 ], [ 25.660474006470224, 57.892672743452295 ], [ 25.657342650742692, 57.878581646725593 ], [ 25.65336801961837, 57.863651497818353 ], [ 25.613503682249132, 57.866056226513592 ], [ 25.582810907197597, 57.883133857541452 ], [ 25.574129265852946, 57.880834255996092 ], [ 25.565912713400962, 57.879929918430946 ], [ 25.5566109562306, 57.880033271218451 ], [ 25.546534050905734, 57.876881008951386 ], [ 25.535010206555796, 57.87440054025268 ], [ 25.522297803800598, 57.86887116207447 ], [ 25.501213819861903, 57.868225206028399 ], [ 25.469461354757698, 57.873884613584039 ], [ 25.466329999030222, 57.85979351685728 ], [ 25.511135694656559, 57.840991726287086 ], [ 25.526018507747892, 57.829958808352274 ], [ 25.542348259864298, 57.820657050282591 ], [ 25.555370720981955, 57.816057848091191 ], [ 25.560176628748422, 57.807582913220813 ], [ 25.555060662619439, 57.799573066343896 ], [ 25.552890252283305, 57.792390041766964 ], [ 25.494512194282322, 57.789338030525641 ], [ 25.455370257131619, 57.789338030525641 ], [ 25.452238902303463, 57.815954547464344 ], [ 25.417793997395052, 57.815954547464344 ], [ 25.406834255496449, 57.847268096645337 ], [ 25.381783415971825, 57.883278678967827 ], [ 25.358298253861335, 57.881713001553749 ], [ 25.336378769164867, 57.903632486250217 ], [ 25.30036818684232, 57.905198163664295 ], [ 25.270620315075462, 57.913026550734685 ], [ 25.261226250590994, 57.938077390259309 ], [ 25.278448702145852, 57.953734165299466 ], [ 25.301933864256398, 57.97095661685438 ], [ 25.326984703781022, 57.991310424136714 ], [ 25.341075801407101, 57.985047714480402 ], [ 25.345772833649335, 57.966259584612089 ], [ 25.370823673173959, 57.969390939440302 ], [ 25.403702900668293, 57.97095661685438 ], [ 25.406834255496449, 57.991310424136714 ], [ 25.419731367148021, 58.008250005422155 ], [ 25.457184692000055, 57.984058736000051 ], [ 25.496613810000071, 57.970597026000078 ], [ 25.531960489000056, 57.966437073000051 ], [ 25.541675659000106, 57.962819723000067 ], [ 25.550253947000044, 57.955326640000024 ], [ 25.551815984000143, 57.949859510000024 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-085", "NAME_1": "Salacgrivas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.553880656000103, 57.947420146000084 ], [ 24.582445250259351, 57.946010847151072 ], [ 24.588003529938931, 57.920888570650959 ], [ 24.59078489110982, 57.894465643574563 ], [ 24.5740967267825, 57.881949520553917 ], [ 24.597738292688064, 57.870824078568319 ], [ 24.649193464906489, 57.770695093503718 ], [ 24.599128972823792, 57.752616249040614 ], [ 24.608863735572925, 57.715067879978676 ], [ 24.562971283897639, 57.717849240250189 ], [ 24.558799242590965, 57.688644953801543 ], [ 24.564361964033424, 57.673347469610007 ], [ 24.54072039812786, 57.666394068031764 ], [ 24.515688152086511, 57.678910191052466 ], [ 24.4183405281928, 57.670566109338438 ], [ 24.426684610806149, 57.620501616356478 ], [ 24.423903249635259, 57.589906648872727 ], [ 24.43502869252012, 57.588515968736942 ], [ 24.433638012384336, 57.567655764002268 ], [ 24.460060938561469, 57.564874402831379 ], [ 24.478139783024574, 57.567655764002268 ], [ 24.497609307623406, 57.555139640981622 ], [ 24.49065590604522, 57.544014198096761 ], [ 24.553236521148506, 57.541232836925872 ], [ 24.529594956142319, 57.521763312326982 ], [ 24.549064480741151, 57.489777664707447 ], [ 24.565752644169152, 57.474480181415231 ], [ 24.578268768089174, 57.464745418666098 ], [ 24.558799242590965, 57.452229295645452 ], [ 24.511516111679214, 57.448057254338778 ], [ 24.501781348930081, 57.427197049604104 ], [ 24.486483864738545, 57.416071606719242 ], [ 24.447544815540766, 57.407727525005271 ], [ 24.394893257192049, 57.400012509164952 ], [ 24.381602410000085, 57.469427802000041 ], [ 24.379893425000091, 57.506537177000041 ], [ 24.375173373000052, 57.528550523000035 ], [ 24.364512566000087, 57.538397528000075 ], [ 24.358571811000047, 57.550360419000071 ], [ 24.36296634200005, 57.576605536000045 ], [ 24.37476647200009, 57.613470770000049 ], [ 24.36304772200009, 57.672267971000053 ], [ 24.357676629000082, 57.685492255000042 ], [ 24.313731316000087, 57.725043036000045 ], [ 24.299571160000085, 57.743841864000046 ], [ 24.299571160000085, 57.761908270000049 ], [ 24.28882897200009, 57.80890534100007 ], [ 24.285980665000068, 57.832586981000077 ], [ 24.28882897200009, 57.845282294000071 ], [ 24.296153191000087, 57.857367255000042 ], [ 24.306158734238295, 57.868186255842957 ], [ 24.349655395000127, 57.858640036000068 ], [ 24.378180786000087, 57.859441020000091 ], [ 24.401538533000121, 57.866469014000089 ], [ 24.412700643000051, 57.876571757000036 ], [ 24.429133748000112, 57.900342916000099 ], [ 24.441639445000106, 57.908094381000083 ], [ 24.481326945000092, 57.91930816700004 ], [ 24.533830200000068, 57.945068868000035 ], [ 24.553880656000103, 57.947420146000084 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-009", "NAME_1": "Apes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.430678413000066, 57.561764252 ], [ 26.430923706000016, 57.561707255000087 ], [ 26.447563517000049, 57.552922262 ], [ 26.481049846000133, 57.527135722000097 ], [ 26.499550008000057, 57.515818583000012 ], [ 26.515052938000082, 57.517265524000024 ], [ 26.528695516000084, 57.523880107000096 ], [ 26.542234741000073, 57.528169251000079 ], [ 26.551743205000065, 57.526825664000015 ], [ 26.570243367000074, 57.519590963000056 ], [ 26.579855183000092, 57.517833965000065 ], [ 26.590087118000071, 57.520366109000051 ], [ 26.594841349000063, 57.526489767000029 ], [ 26.598355347000108, 57.53385365900003 ], [ 26.604763224000067, 57.540313213000061 ], [ 26.634322144000095, 57.554420879000091 ], [ 26.666981649000064, 57.564859518000034 ], [ 26.700467976000141, 57.570750631000053 ], [ 26.778085978000064, 57.568476868000019 ], [ 26.795759318000137, 57.571319071000104 ], [ 26.806003385248005, 57.55384266750508 ], [ 26.808281793370043, 57.51966654837247 ], [ 26.808281793370043, 57.503717693316844 ], [ 26.758156820081183, 57.503717693316844 ], [ 26.721702292826535, 57.490047245483936 ], [ 26.714867069359741, 57.464984758839535 ], [ 26.703475029648871, 57.423973416240131 ], [ 26.687526174593245, 57.417138192773336 ], [ 26.644236424771179, 57.417138192773336 ], [ 26.614617121882645, 57.419416600895374 ], [ 26.594222040214959, 57.391303412422531 ], [ 26.567712029986183, 57.397427069803427 ], [ 26.544405958867912, 57.395618395572455 ], [ 26.531073439387683, 57.398874009727763 ], [ 26.525802442728548, 57.401871243263258 ], [ 26.52022138770684, 57.406470445454659 ], [ 26.475831332649875, 57.405075182373764 ], [ 26.480637241315605, 57.387401842221209 ], [ 26.479241978234711, 57.382389227980468 ], [ 26.474746127931439, 57.375051175571286 ], [ 26.446840854621712, 57.369160061287744 ], [ 26.43314659993564, 57.361408595929902 ], [ 26.421054314804792, 57.357946275300321 ], [ 26.397024774173985, 57.35427724909573 ], [ 26.393924187850985, 57.350711574779325 ], [ 26.394699334206905, 57.347145901362239 ], [ 26.399040154879231, 57.344019477516838 ], [ 26.404466180269992, 57.342236639909004 ], [ 26.411132440010078, 57.342856757533298 ], [ 26.424154901127793, 57.346990871731293 ], [ 26.430046013612639, 57.34600901980042 ], [ 26.430046013612639, 57.339704495266233 ], [ 26.423534784402761, 57.332159736382721 ], [ 26.359456007588676, 57.322547919051203 ], [ 26.276153598809515, 57.331022853921525 ], [ 26.277548861890466, 57.364715887827913 ], [ 26.286230503235117, 57.365826930968069 ], [ 26.302043491413997, 57.374844469096956 ], [ 26.301423373789646, 57.379831244915977 ], [ 26.299097934721885, 57.389468898870575 ], [ 26.302818637769917, 57.396135159509981 ], [ 26.309794955872519, 57.402207140047437 ], [ 26.312740512564574, 57.409726061408605 ], [ 26.315065951632334, 57.418097643491421 ], [ 26.320491977922416, 57.423782050401257 ], [ 26.318941685210575, 57.429001370217009 ], [ 26.315065951632334, 57.433135484415061 ], [ 26.308554722422457, 57.436158556372277 ], [ 26.300803257064615, 57.438974920955786 ], [ 26.293516879700235, 57.442695624003818 ], [ 26.296152378029831, 57.450007839789919 ], [ 26.304523960112647, 57.455356349915576 ], [ 26.312740512564574, 57.458663641813587 ], [ 26.325969679257298, 57.467603665576689 ], [ 26.311035191121164, 57.469774075013504 ], [ 26.311500278215249, 57.499332993822577 ], [ 26.361781446656437, 57.512820542933696 ], [ 26.362866652274192, 57.515636909315901 ], [ 26.362556593911677, 57.519848537879682 ], [ 26.354495070191319, 57.522819932993457 ], [ 26.349844191156478, 57.52966705988689 ], [ 26.344263137034147, 57.533232734203295 ], [ 26.341162550711147, 57.537780260450631 ], [ 26.344108107403201, 57.542379461742712 ], [ 26.345658400115042, 57.551913763809125 ], [ 26.352169631123559, 57.560879625094572 ], [ 26.356975538889969, 57.57069814710178 ], [ 26.352634719116963, 57.576227525280046 ], [ 26.351325149735828, 57.580203000867755 ], [ 26.430678413000066, 57.561764252 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-101", "NAME_1": "Valkas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.714998413000103, 57.923390605000051 ], [ 25.730294637000071, 57.923132223 ], [ 25.745384155000067, 57.909179586000093 ], [ 25.754685913000088, 57.888896586000087 ], [ 25.767501668000079, 57.868923646000056 ], [ 25.792616415000083, 57.855978699000033 ], [ 26.002732788000088, 57.845979310000118 ], [ 26.014515015000086, 57.842827047000057 ], [ 26.021956421000112, 57.837943624000033 ], [ 26.025263713000101, 57.828409322000041 ], [ 26.021749715000055, 57.822414856000123 ], [ 26.016065308000094, 57.816472067000106 ], [ 26.013068074000074, 57.807299500000013 ], [ 26.016065308000094, 57.786680603000022 ], [ 26.024746948000143, 57.774355774000057 ], [ 26.135231161000092, 57.724772238000085 ], [ 26.168510783000016, 57.704049988000051 ], [ 26.26318200700004, 57.62082509400004 ], [ 26.297185099000075, 57.599146830000066 ], [ 26.33862959800004, 57.583152975000118 ], [ 26.351325149735828, 57.580203000867755 ], [ 26.352634719116963, 57.576227525280046 ], [ 26.356975538889969, 57.57069814710178 ], [ 26.352169631123559, 57.560879625094572 ], [ 26.345658400115042, 57.551913763809125 ], [ 26.344108107403201, 57.542379461742712 ], [ 26.341162550711147, 57.537780260450631 ], [ 26.344263137034147, 57.533232734203295 ], [ 26.349844191156478, 57.52966705988689 ], [ 26.354495070191319, 57.522819932993457 ], [ 26.362556593911677, 57.519848537879682 ], [ 26.362866652274192, 57.515636909315901 ], [ 26.361781446656437, 57.512820542933696 ], [ 26.311500278215249, 57.499332993822577 ], [ 26.301609569426091, 57.527702810136532 ], [ 26.282074370036128, 57.525260909763119 ], [ 26.24544587073035, 57.522819010289084 ], [ 26.240562070882845, 57.54235420967899 ], [ 26.184398373086424, 57.547238009526495 ], [ 26.155095574001507, 57.547238009526495 ], [ 26.123350875442554, 57.569215108390495 ], [ 26.094048076357637, 57.559447508695541 ], [ 26.050093877730262, 57.559447508695541 ], [ 25.97683688001797, 57.549679909000588 ], [ 25.945092181458961, 57.530144709610624 ], [ 25.896254182984137, 57.530144709610624 ], [ 25.888928482763276, 57.549679909000588 ], [ 25.903579882305678, 57.569215108390495 ], [ 25.901137982831642, 57.588750307780458 ], [ 25.876718983594174, 57.603401707322917 ], [ 25.932882681390595, 57.608285507170365 ], [ 25.959743581001419, 57.620495006339468 ], [ 25.979278780391382, 57.649797805424328 ], [ 25.989046380086336, 57.671774905187704 ], [ 25.859625684577679, 57.68398440435675 ], [ 25.857183784204267, 57.703519603746713 ], [ 25.82788098511935, 57.705961504120069 ], [ 25.847416184509314, 57.752357602221537 ], [ 25.735088788017151, 57.730380503357537 ], [ 25.688656200823004, 57.737670674062315 ], [ 25.660474006470224, 57.750196093374996 ], [ 25.616635037077288, 57.758024480445386 ], [ 25.596281229794897, 57.773681255485542 ], [ 25.564827507783264, 57.782649034125598 ], [ 25.552890252283305, 57.792390041766964 ], [ 25.555060662619439, 57.799573066343896 ], [ 25.560176628748422, 57.807582913220813 ], [ 25.555370720981955, 57.816057848091191 ], [ 25.542348259864298, 57.820657050282591 ], [ 25.526018507747892, 57.829958808352274 ], [ 25.511135694656559, 57.840991726287086 ], [ 25.466329999030222, 57.85979351685728 ], [ 25.469461354757698, 57.873884613584039 ], [ 25.501213819861903, 57.868225206028399 ], [ 25.522297803800598, 57.86887116207447 ], [ 25.535010206555796, 57.87440054025268 ], [ 25.546534050905734, 57.876881008951386 ], [ 25.5566109562306, 57.880033271218451 ], [ 25.565912713400962, 57.879929918430946 ], [ 25.574129265852946, 57.880834255996092 ], [ 25.582810907197597, 57.883133857541452 ], [ 25.613503682249132, 57.866056226513592 ], [ 25.65336801961837, 57.863651497818353 ], [ 25.657342650742692, 57.878581646725593 ], [ 25.660474006470224, 57.892672743452295 ], [ 25.666077060707778, 57.914373651522794 ], [ 25.703799772000053, 57.921326524000065 ], [ 25.714998413000103, 57.923390605000051 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-007", "NAME_1": "Aluksne" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.87265384900013, 57.627181295000085 ], [ 26.884952840000096, 57.622091166000089 ], [ 26.896114950000111, 57.614985657000048 ], [ 26.911617880000023, 57.61343536400004 ], [ 26.929187866000092, 57.615554098000118 ], [ 26.946551148000111, 57.615347392000061 ], [ 26.981071004000086, 57.608991191000129 ], [ 27.004635458000109, 57.598914286000095 ], [ 27.041325724000075, 57.56845103000002 ], [ 27.061531209000066, 57.555661113000056 ], [ 27.085354045000116, 57.549434103000053 ], [ 27.165659220000066, 57.546695252000106 ], [ 27.319965047000068, 57.516128642000083 ], [ 27.352934611000137, 57.527600810000123 ], [ 27.528169393000042, 57.528479309000048 ], [ 27.522795044000077, 57.492021587000053 ], [ 27.525637248000066, 57.468379619000032 ], [ 27.514836873000036, 57.447889913000054 ], [ 27.511322876000065, 57.430397441000096 ], [ 27.536282593000067, 57.415695496000112 ], [ 27.640824015000049, 57.389004618000072 ], [ 27.694408720000069, 57.356375287 ], [ 27.688522169962141, 57.332573147532685 ], [ 27.681855910222055, 57.326759549413623 ], [ 27.672347445678042, 57.320222479983443 ], [ 27.662270542151759, 57.318413804853208 ], [ 27.652348667357103, 57.313685411452525 ], [ 27.600207146942239, 57.297794908008598 ], [ 27.587339714556151, 57.282550361509948 ], [ 27.571216668014813, 57.276969306488297 ], [ 27.555558708567503, 57.258908392708122 ], [ 27.526826612957791, 57.259864407116652 ], [ 27.51892011886838, 57.259347643179183 ], [ 27.501711866709286, 57.264773668569944 ], [ 27.487087436935667, 57.273868720165297 ], [ 27.46073245633778, 57.274178779427075 ], [ 27.406265496855156, 57.263068346227158 ], [ 27.354899122796269, 57.284772446890884 ], [ 27.326011996656291, 57.277434394481702 ], [ 27.275885857846049, 57.246686917267368 ], [ 27.248135614167268, 57.248960680391065 ], [ 27.24100426643372, 57.246428534848974 ], [ 27.234182977062744, 57.242811183689128 ], [ 27.228911981302872, 57.238987127853648 ], [ 27.220488722376615, 57.23438792656151 ], [ 27.20111005988133, 57.234801336812211 ], [ 27.184366895715641, 57.228109239549724 ], [ 27.156564976092739, 57.226378078785274 ], [ 27.056157667941989, 57.24870229797267 ], [ 27.045925733885497, 57.250304267527895 ], [ 27.046545850610471, 57.253353176108135 ], [ 27.048561232215093, 57.256427924009472 ], [ 27.060085076565031, 57.263223374958784 ], [ 27.066906365936006, 57.268701077192929 ], [ 27.059930046934085, 57.27275767702514 ], [ 27.020810987636935, 57.286736152551384 ], [ 26.988513217710818, 57.304409491804563 ], [ 26.905520868193491, 57.303737698236148 ], [ 26.865006544916071, 57.299526068773048 ], [ 26.849348586368137, 57.315261541686766 ], [ 26.845472852789896, 57.315933336154501 ], [ 26.840046828298455, 57.3162950713604 ], [ 26.836171094720214, 57.315313219429527 ], [ 26.790230746951408, 57.318413804853208 ], [ 26.7607235040864, 57.321669419907778 ], [ 26.747701042968743, 57.318956407212397 ], [ 26.714783156317594, 57.306476549353249 ], [ 26.682227003973026, 57.320015774408432 ], [ 26.681451856717786, 57.323684801512343 ], [ 26.677576124938184, 57.334330145819536 ], [ 26.6331860689819, 57.350298162729985 ], [ 26.61814822805826, 57.362493801547657 ], [ 26.594222040214959, 57.391303412422531 ], [ 26.614617121882645, 57.419416600895374 ], [ 26.644236424771179, 57.417138192773336 ], [ 26.687526174593245, 57.417138192773336 ], [ 26.703475029648871, 57.423973416240131 ], [ 26.714867069359741, 57.464984758839535 ], [ 26.721702292826535, 57.490047245483936 ], [ 26.758156820081183, 57.503717693316844 ], [ 26.808281793370043, 57.503717693316844 ], [ 26.808281793370043, 57.51966654837247 ], [ 26.806003385248005, 57.55384266750508 ], [ 26.795759318000137, 57.571319071000104 ], [ 26.816326538000055, 57.581189270000081 ], [ 26.828315471000082, 57.595038555000045 ], [ 26.838547404000082, 57.609869690000082 ], [ 26.854153687000121, 57.622556254000116 ], [ 26.87265384900013, 57.627181295000085 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-108", "NAME_1": "Vilakas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 27.694408720000069, 57.356375287 ], [ 27.707951701000098, 57.348128561000053 ], [ 27.809134155000095, 57.313944601000074 ], [ 27.827737671000136, 57.304952902000124 ], [ 27.840295044000072, 57.290638529000049 ], [ 27.846134481000036, 57.267306621 ], [ 27.841173543000082, 57.211211853000052 ], [ 27.833938842000123, 57.180490215000091 ], [ 27.824327027000038, 57.159070333000088 ], [ 27.794044637000098, 57.143386536000023 ], [ 27.700975383000099, 57.118788555000052 ], [ 27.682216838000102, 57.103699036000037 ], [ 27.696066121000058, 57.085457256000083 ], [ 27.722059367000043, 57.077990011000068 ], [ 27.745468791000093, 57.06799062100005 ], [ 27.750739786000111, 57.042359111000067 ], [ 27.745778848914711, 57.031455382559841 ], [ 27.690025652961481, 57.022973625432428 ], [ 27.637622271550583, 57.018416809188352 ], [ 27.630787048083789, 57.038922480488054 ], [ 27.589775705484385, 57.04347929673213 ], [ 27.553321179129114, 57.038922480488054 ], [ 27.541929139418244, 57.07765541496542 ], [ 27.514588244651748, 57.079933823087458 ], [ 27.455349638874736, 57.114109941320692 ], [ 27.402946257463782, 57.159678099264852 ], [ 27.425730335986202, 57.212081481575069 ], [ 27.446236007285904, 57.243979191686321 ], [ 27.487087436935667, 57.273868720165297 ], [ 27.501711866709286, 57.264773668569944 ], [ 27.51892011886838, 57.259347643179183 ], [ 27.526826612957791, 57.259864407116652 ], [ 27.555558708567503, 57.258908392708122 ], [ 27.571216668014813, 57.276969306488297 ], [ 27.587339714556151, 57.282550361509948 ], [ 27.600207146942239, 57.297794908008598 ], [ 27.652348667357103, 57.313685411452525 ], [ 27.662270542151759, 57.318413804853208 ], [ 27.672347445678042, 57.320222479983443 ], [ 27.681855910222055, 57.326759549413623 ], [ 27.688522169962141, 57.332573147532685 ], [ 27.694408720000069, 57.356375287 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-014", "NAME_1": "Baltinavas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 27.745778848914711, 57.031455382559841 ], [ 27.729552450000057, 57.009854635000053 ], [ 27.723351278000081, 56.998795878000053 ], [ 27.72076745600009, 56.988667298000095 ], [ 27.718545369000083, 56.968720195000074 ], [ 27.715134724000052, 56.957403056 ], [ 27.648730510000092, 56.879268291000059 ], [ 27.628369995000071, 56.844154155000027 ], [ 27.644379265690532, 56.841771673423978 ], [ 27.637155795903254, 56.836608588215768 ], [ 27.614986607246124, 56.845006008720304 ], [ 27.60082726366727, 56.852447414816311 ], [ 27.581293573339735, 56.857615057788678 ], [ 27.571836785639107, 56.863816230434679 ], [ 27.567650994597727, 56.867330227008324 ], [ 27.561604851582615, 56.87074087169384 ], [ 27.549615920138592, 56.866942654280024 ], [ 27.529927199280792, 56.862886054447813 ], [ 27.51814497161314, 56.857976792994577 ], [ 27.446701919957604, 56.852663522803311 ], [ 27.434843967575034, 56.883990742578703 ], [ 27.41661670439737, 56.902218005756311 ], [ 27.443957599163866, 56.915888453589218 ], [ 27.494082573352046, 56.91361004546718 ], [ 27.537372323174168, 56.934115716766883 ], [ 27.519145059996504, 56.954621388066585 ], [ 27.612559784006805, 56.984240690955119 ], [ 27.664963166317079, 56.988797506299875 ], [ 27.637622271550583, 57.018416809188352 ], [ 27.690025652961481, 57.022973625432428 ], [ 27.745778848914711, 57.031455382559841 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-044", "NAME_1": "Karsavas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 27.644379265690532, 56.841771673423978 ], [ 27.661184530000099, 56.839270732 ], [ 27.744073527000097, 56.864798890000046 ], [ 27.7863965250001, 56.871258443000087 ], [ 27.830838257000096, 56.864282125000088 ], [ 27.852232300000111, 56.854308573000068 ], [ 27.891506388000067, 56.829710592000097 ], [ 27.913520548000065, 56.820150452000107 ], [ 27.918894897000115, 56.805887757000036 ], [ 27.900084676000091, 56.783046774000113 ], [ 27.876106811000085, 56.759430644000091 ], [ 27.86546146677324, 56.742687480242978 ], [ 27.843812261626567, 56.743357570495448 ], [ 27.820513392279224, 56.727824990930571 ], [ 27.820513392279224, 56.688993542917672 ], [ 27.802392049453488, 56.665694674469648 ], [ 27.760971838179785, 56.691582306178475 ], [ 27.644477494141029, 56.686404779656812 ], [ 27.592702229824056, 56.655339621426378 ], [ 27.58020836772198, 56.619438382275519 ], [ 27.551631300843837, 56.636749986322798 ], [ 27.541554396418235, 56.645069892461549 ], [ 27.524811232252546, 56.6517878281457 ], [ 27.512408887859863, 56.654836738524637 ], [ 27.501815220396111, 56.655766912712807 ], [ 27.488017612023157, 56.653312283335197 ], [ 27.476390414885714, 56.658454087885843 ], [ 27.472049595112708, 56.663259996551574 ], [ 27.470344272769978, 56.674215400120602 ], [ 27.480266147564635, 56.680829983017247 ], [ 27.486312289680427, 56.693387356141557 ], [ 27.471030359263636, 56.740768807234645 ], [ 27.45549777969876, 56.771833965465134 ], [ 27.403722515381787, 56.784777781769208 ], [ 27.339861280973309, 56.782684231092389 ], [ 27.347922803794347, 56.784312039069334 ], [ 27.344822219269986, 56.801597804694893 ], [ 27.348387891787752, 56.807204698138264 ], [ 27.348077834324556, 56.815137031548716 ], [ 27.355209181158784, 56.821648260758593 ], [ 27.362495557623845, 56.824593818350024 ], [ 27.368696730269846, 56.824464627140799 ], [ 27.371332227700123, 56.822009995964493 ], [ 27.376603224359314, 56.820614731984278 ], [ 27.38342451283097, 56.821364040817798 ], [ 27.394948358080228, 56.828030301457204 ], [ 27.390917595770418, 56.831906033236805 ], [ 27.395723504436148, 56.835962633069016 ], [ 27.412156610239379, 56.84531606708282 ], [ 27.427814568787312, 56.85125885731037 ], [ 27.446701919957604, 56.852663522803311 ], [ 27.51814497161314, 56.857976792994577 ], [ 27.529927199280792, 56.862886054447813 ], [ 27.549615920138592, 56.866942654280024 ], [ 27.561604851582615, 56.87074087169384 ], [ 27.567650994597727, 56.867330227008324 ], [ 27.571836785639107, 56.863816230434679 ], [ 27.581293573339735, 56.857615057788678 ], [ 27.60082726366727, 56.852447414816311 ], [ 27.614986607246124, 56.845006008720304 ], [ 27.637155795903254, 56.836608588215768 ], [ 27.644379265690532, 56.841771673423978 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-023", "NAME_1": "Ciblas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 27.86546146677324, 56.742687480242978 ], [ 27.882618042000047, 56.725479228000083 ], [ 27.981009969000098, 56.687006124000035 ], [ 27.991345255000084, 56.66997874 ], [ 27.992172079000113, 56.624994406000084 ], [ 27.997443074000046, 56.603832906000022 ], [ 28.010982299000119, 56.58755483 ], [ 28.028655640000125, 56.576754456000074 ], [ 28.108650757000078, 56.555179546000019 ], [ 28.126117391000037, 56.547763977000088 ], [ 28.132215210000084, 56.535981751000079 ], [ 28.125238892000084, 56.527145081000086 ], [ 28.099245647000117, 56.513399150000041 ], [ 28.093251180000095, 56.501591086000033 ], [ 28.053502081255999, 56.518135171301083 ], [ 27.988783000634953, 56.523312697822746 ], [ 27.94477402610039, 56.502602591736206 ], [ 27.918886394391563, 56.481892486548986 ], [ 27.88523247290027, 56.497425065214543 ], [ 27.864522366813731, 56.528490224344353 ], [ 27.812747102496758, 56.551789092792376 ], [ 27.776504417744661, 56.541434039749106 ], [ 27.755794311658121, 56.520723934561886 ], [ 27.724729153427688, 56.533667749966639 ], [ 27.691075231936395, 56.567321672357252 ], [ 27.657421310445102, 56.567321672357252 ], [ 27.603057282867269, 56.575087962139719 ], [ 27.56113976358921, 56.575926826361922 ], [ 27.561449822851046, 56.599646307730893 ], [ 27.58020836772198, 56.619438382275519 ], [ 27.592702229824056, 56.655339621426378 ], [ 27.644477494141029, 56.686404779656812 ], [ 27.760971838179785, 56.691582306178475 ], [ 27.802392049453488, 56.665694674469648 ], [ 27.820513392279224, 56.688993542917672 ], [ 27.820513392279224, 56.727824990930571 ], [ 27.843812261626567, 56.743357570495448 ], [ 27.86546146677324, 56.742687480242978 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-058", "NAME_1": "Ludzas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 28.093251180000095, 56.501591086000033 ], [ 28.096455119000069, 56.491953431000027 ], [ 28.104516642000135, 56.483065084000017 ], [ 28.156503133000086, 56.446219788000107 ], [ 28.16425459800007, 56.437951559000041 ], [ 28.167871947832111, 56.427125345957904 ], [ 28.118221160977782, 56.422350932449547 ], [ 28.069034660820932, 56.422350932449547 ], [ 28.022436923025566, 56.437883512014423 ], [ 27.978427948491003, 56.432705985492817 ], [ 27.991371763895756, 56.40422958962381 ], [ 28.012081869982296, 56.383519484436647 ], [ 27.991371763895756, 56.37575319465418 ], [ 27.95512907914366, 56.378341957914984 ], [ 27.913708867869957, 56.355043088567641 ], [ 27.877466183117861, 56.331744220119617 ], [ 27.841223498365764, 56.321389167076347 ], [ 27.864522366813731, 56.285146482324251 ], [ 27.91629763113076, 56.285146482324251 ], [ 27.931830210695637, 56.308445350772274 ], [ 28.00431558019983, 56.331744220119617 ], [ 28.043147028212786, 56.313622877293938 ], [ 28.094922292529759, 56.298090298628324 ], [ 28.120809924238586, 56.274791429280981 ], [ 28.089744766008153, 56.238548744528885 ], [ 28.070411003964637, 56.208507392502156 ], [ 28.0650883322607, 56.203288071787028 ], [ 28.06126427642522, 56.20354645420548 ], [ 28.056096632553533, 56.206957098890996 ], [ 28.052685987868017, 56.211065375566591 ], [ 28.048035108833176, 56.214398504987003 ], [ 28.039818556381249, 56.215690416179712 ], [ 28.031446974298433, 56.214476020252107 ], [ 28.020904981879369, 56.209644273164656 ], [ 28.00131961380913, 56.203288071787028 ], [ 27.913056267632612, 56.18370270371679 ], [ 27.898483513803114, 56.183237617522025 ], [ 27.88757978707747, 56.186648261308164 ], [ 27.852853224396767, 56.181945706329259 ], [ 27.838435500198159, 56.182307441535158 ], [ 27.822415806444269, 56.185666409377291 ], [ 27.810943638038452, 56.196260077740362 ], [ 27.778490837582069, 56.195639960116011 ], [ 27.743919305431575, 56.199774075213384 ], [ 27.722473586286981, 56.20664704052848 ], [ 27.701854689442371, 56.219488634492848 ], [ 27.687126905981927, 56.225095527036899 ], [ 27.667593214755016, 56.240236720748044 ], [ 27.683561231665465, 56.24726471569403 ], [ 27.692552931372688, 56.249822700557161 ], [ 27.700459426361419, 56.255016181051872 ], [ 27.698909132750259, 56.258065091430808 ], [ 27.694258253715418, 56.260752264805149 ], [ 27.686816846720092, 56.262870999197219 ], [ 27.686816846720092, 56.276306871464897 ], [ 27.715497267285059, 56.298476061021347 ], [ 27.711001417881107, 56.311136786933162 ], [ 27.698909132750259, 56.321988836815365 ], [ 27.690227492304928, 56.332375800502746 ], [ 27.687591993975332, 56.347258612694816 ], [ 27.689607374680577, 56.354700018790822 ], [ 27.689917433043092, 56.360616969697389 ], [ 27.670383741816238, 56.371804918162411 ], [ 27.640411410957825, 56.378781236265013 ], [ 27.62242801334213, 56.392475490951142 ], [ 27.623978306053971, 56.401079617030689 ], [ 27.620412631737565, 56.407151598467465 ], [ 27.62180789571778, 56.420690823522648 ], [ 27.607958612300081, 56.420484117048318 ], [ 27.60253258601, 56.418572089130578 ], [ 27.596486443894264, 56.418985501179918 ], [ 27.591060417604183, 56.421827704185148 ], [ 27.592145623221938, 56.424385688148959 ], [ 27.589665155422551, 56.428313096771944 ], [ 27.581603630802874, 56.433609930953537 ], [ 27.571681756008218, 56.442808336235714 ], [ 27.559692823664875, 56.457096870124417 ], [ 27.55938276530236, 56.464460760955319 ], [ 27.549925977601788, 56.478568426791412 ], [ 27.508688184811888, 56.460171617126377 ], [ 27.49638919410603, 56.477922472544037 ], [ 27.495459019018483, 56.488025214492041 ], [ 27.487087436935667, 56.499497381998538 ], [ 27.486002232217231, 56.508850816012341 ], [ 27.486777377673832, 56.514896959027396 ], [ 27.493753695776434, 56.520865586777404 ], [ 27.506827833737532, 56.52807444887668 ], [ 27.525121290615061, 56.529288844804341 ], [ 27.538453810095234, 56.53153677040558 ], [ 27.551166212850433, 56.535102443822723 ], [ 27.566565789879292, 56.541717026719368 ], [ 27.574317254337814, 56.556961575016658 ], [ 27.56113976358921, 56.575926826361922 ], [ 27.603057282867269, 56.575087962139719 ], [ 27.657421310445102, 56.567321672357252 ], [ 27.691075231936395, 56.567321672357252 ], [ 27.724729153427688, 56.533667749966639 ], [ 27.755794311658121, 56.520723934561886 ], [ 27.776504417744661, 56.541434039749106 ], [ 27.812747102496758, 56.551789092792376 ], [ 27.864522366813731, 56.528490224344353 ], [ 27.88523247290027, 56.497425065214543 ], [ 27.918886394391563, 56.481892486548986 ], [ 27.94477402610039, 56.502602591736206 ], [ 27.988783000634953, 56.523312697822746 ], [ 28.053502081255999, 56.518135171301083 ], [ 28.093251180000095, 56.501591086000033 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-110", "NAME_1": "Zilupes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 28.167871947832111, 56.427125345957904 ], [ 28.16425459800007, 56.392812195 ], [ 28.167148478000058, 56.369867859000053 ], [ 28.174434855000129, 56.349636536000062 ], [ 28.214794148000095, 56.281371969000091 ], [ 28.217274617000072, 56.270726624000119 ], [ 28.215310913000053, 56.255998841000022 ], [ 28.209419800000063, 56.24814402300008 ], [ 28.201358276000065, 56.24168446900002 ], [ 28.193141724000043, 56.231039124000048 ], [ 28.184408406000045, 56.207526347000041 ], [ 28.17862064600007, 56.183910218000037 ], [ 28.169112182000106, 56.161741028 ], [ 28.148906697000115, 56.142414043000045 ], [ 28.110976196000109, 56.156805929000072 ], [ 28.068239787000095, 56.147581686000066 ], [ 28.051100037936408, 56.140665997038127 ], [ 28.050928988681846, 56.14112132379006 ], [ 28.047259963376575, 56.150888169853147 ], [ 28.04369428906017, 56.158019518485958 ], [ 28.06260786266273, 56.182100735060828 ], [ 28.077542351698128, 56.196725164834447 ], [ 28.070411003964637, 56.208507392502156 ], [ 28.089744766008153, 56.238548744528885 ], [ 28.120809924238586, 56.274791429280981 ], [ 28.094922292529759, 56.298090298628324 ], [ 28.043147028212786, 56.313622877293938 ], [ 28.00431558019983, 56.331744220119617 ], [ 27.931830210695637, 56.308445350772274 ], [ 27.91629763113076, 56.285146482324251 ], [ 27.864522366813731, 56.285146482324251 ], [ 27.841223498365764, 56.321389167076347 ], [ 27.877466183117861, 56.331744220119617 ], [ 27.913708867869957, 56.355043088567641 ], [ 27.95512907914366, 56.378341957914984 ], [ 27.991371763895756, 56.37575319465418 ], [ 28.012081869982296, 56.383519484436647 ], [ 27.991371763895756, 56.40422958962381 ], [ 27.978427948491003, 56.432705985492817 ], [ 28.022436923025566, 56.437883512014423 ], [ 28.069034660820932, 56.422350932449547 ], [ 28.118221160977782, 56.422350932449547 ], [ 28.167871947832111, 56.427125345957904 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-065", "NAME_1": "Neretas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.349085703000128, 56.159876323000091 ], [ 25.10919559700011, 56.183083395 ], [ 25.073125447000109, 56.197811178 ], [ 25.043979940000071, 56.227990214 ], [ 25.026203247000041, 56.260184632000048 ], [ 25.016488077000105, 56.269899801000079 ], [ 24.983208456000057, 56.290492859 ], [ 24.973183228000039, 56.300750631000071 ], [ 24.962124471000038, 56.319276632000097 ], [ 24.936286255000113, 56.379918925000069 ], [ 24.910137980000115, 56.421957703000018 ], [ 24.892257934000071, 56.438726706000054 ], [ 24.8709672446426, 56.442602437352548 ], [ 24.877635972122391, 56.454549473879069 ], [ 24.900877881109295, 56.459912991891031 ], [ 24.911604916233898, 56.472427865753389 ], [ 24.920544112620689, 56.486730579252821 ], [ 25.013511748568305, 56.495669774740293 ], [ 25.027814462067738, 56.459912991891031 ], [ 25.051056371054642, 56.463488670265917 ], [ 25.074298280041546, 56.4027021378933 ], [ 25.133296972777032, 56.413429173017903 ], [ 25.29357791508869, 56.407900906401665 ], [ 25.298228794123531, 56.377075913922283 ], [ 25.298538853385367, 56.365552070471665 ], [ 25.302104525903133, 56.349377346187566 ], [ 25.298228794123531, 56.342504380872469 ], [ 25.296213413418286, 56.336949164272482 ], [ 25.299158970110341, 56.334158637211317 ], [ 25.305360141857022, 56.330670478160016 ], [ 25.361377394051487, 56.334752916413947 ], [ 25.370265740971149, 56.327311510317941 ], [ 25.362927686763328, 56.3226606312831 ], [ 25.341998731556203, 56.317027900317328 ], [ 25.324325392302967, 56.30932811090355 ], [ 25.31094119597941, 56.297752591508868 ], [ 25.310476108885325, 56.28736562782143 ], [ 25.33750288305157, 56.275893460314933 ], [ 25.356416456654131, 56.261630763948574 ], [ 25.37222944483301, 56.255791328307112 ], [ 25.403442010040692, 56.231555081202032 ], [ 25.395535515951281, 56.202099514281144 ], [ 25.408092889075533, 56.182462470266785 ], [ 25.408557977068995, 56.178586738487184 ], [ 25.403752069302527, 56.175486152164183 ], [ 25.37181603368299, 56.174142565027353 ], [ 25.359517042977131, 56.168199774799746 ], [ 25.349543491339034, 56.160241603866893 ], [ 25.349085703000128, 56.159876323000091 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-107", "NAME_1": "Viesites" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.454807577000111, 56.149648743000014 ], [ 25.349085703000128, 56.159876323000091 ], [ 25.349543491339034, 56.160241603866893 ], [ 25.359517042977131, 56.168199774799746 ], [ 25.37181603368299, 56.174142565027353 ], [ 25.403752069302527, 56.175486152164183 ], [ 25.408557977068995, 56.178586738487184 ], [ 25.408092889075533, 56.182462470266785 ], [ 25.395535515951281, 56.202099514281144 ], [ 25.403442010040692, 56.231555081202032 ], [ 25.37222944483301, 56.255791328307112 ], [ 25.356416456654131, 56.261630763948574 ], [ 25.33750288305157, 56.275893460314933 ], [ 25.310476108885325, 56.28736562782143 ], [ 25.31094119597941, 56.297752591508868 ], [ 25.324325392302967, 56.30932811090355 ], [ 25.341998731556203, 56.317027900317328 ], [ 25.362927686763328, 56.3226606312831 ], [ 25.370265740971149, 56.327311510317941 ], [ 25.361377394051487, 56.334752916413947 ], [ 25.305360141857022, 56.330670478160016 ], [ 25.299158970110341, 56.334158637211317 ], [ 25.296213413418286, 56.336949164272482 ], [ 25.298228794123531, 56.342504380872469 ], [ 25.302104525903133, 56.349377346187566 ], [ 25.298538853385367, 56.365552070471665 ], [ 25.298228794123531, 56.377075913922283 ], [ 25.29357791508869, 56.407900906401665 ], [ 25.296213413418286, 56.420820013832554 ], [ 25.331301711304889, 56.421285101825958 ], [ 25.393520135246035, 56.410975654303002 ], [ 25.455583529556236, 56.413352770214146 ], [ 25.476202427300166, 56.418882148392413 ], [ 25.505399610903282, 56.436400458014703 ], [ 25.523538039049242, 56.444823716940959 ], [ 25.547774286154379, 56.444875392885024 ], [ 25.566687859756883, 56.447614244002125 ], [ 25.573819206591111, 56.452859402239596 ], [ 25.583431023922572, 56.458569648470473 ], [ 25.590717401287009, 56.460843410694793 ], [ 25.594644809910051, 56.467147936128299 ], [ 25.615928578241267, 56.446736111782116 ], [ 25.611476223648765, 56.431152872507027 ], [ 25.635964172108856, 56.408891100443896 ], [ 25.658225943272669, 56.393307860269488 ], [ 25.676035360743299, 56.36659373541255 ], [ 25.727237434959648, 56.368819911809453 ], [ 25.733915966848372, 56.351010495238143 ], [ 25.736142143245274, 56.328748723175011 ], [ 25.733915966848372, 56.299808421021794 ], [ 25.680487715335801, 56.29312988913307 ], [ 25.693844778213929, 56.228570752038536 ], [ 25.693844778213929, 56.208535158171003 ], [ 25.67380918344702, 56.184047209710911 ], [ 25.649679402582365, 56.143809306554203 ], [ 25.590044800000044, 56.141122131000017 ], [ 25.572888224000081, 56.143034159000123 ], [ 25.522762085000068, 56.156573385000101 ], [ 25.454807577000111, 56.149648743000014 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-105", "NAME_1": "Vecumnieku" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.8709672446426, 56.442602437352548 ], [ 24.857117960000096, 56.43536773700005 ], [ 24.853397257000097, 56.424722393000067 ], [ 24.852157023000075, 56.413663635000049 ], [ 24.845852498000056, 56.404930319000087 ], [ 24.837687622000118, 56.403948466000017 ], [ 24.815570109000106, 56.408806051000042 ], [ 24.805544881000088, 56.408547669000072 ], [ 24.715039531000059, 56.386252988000038 ], [ 24.678627563000106, 56.37728342700008 ], [ 24.639146770000082, 56.359971822000077 ], [ 24.572772161366768, 56.309810859570966 ], [ 24.529007335520078, 56.322249375808042 ], [ 24.480735677909195, 56.309734501945684 ], [ 24.468220804046837, 56.331188572194833 ], [ 24.491462713033741, 56.343703446057134 ], [ 24.505765426533173, 56.361581837931453 ], [ 24.452130251809649, 56.366945355044095 ], [ 24.446766733797688, 56.381248068543528 ], [ 24.514704622020645, 56.397338620780715 ], [ 24.530795174257889, 56.409853494643016 ], [ 24.51291678328289, 56.454549473879069 ], [ 24.473584321159478, 56.483154900877935 ], [ 24.437827538310216, 56.474215704491144 ], [ 24.42710050318567, 56.493881936002538 ], [ 24.40028291582388, 56.509972488239725 ], [ 24.380616685211862, 56.529638718851743 ], [ 24.387768041961522, 56.552880627838704 ], [ 24.34843557983811, 56.565395501701005 ], [ 24.321617992476376, 56.56360766296325 ], [ 24.309103118614019, 56.611879320574133 ], [ 24.368101810450185, 56.619030677323849 ], [ 24.355358623901338, 56.661563541524174 ], [ 24.374047479407636, 56.659590969447663 ], [ 24.372962273789881, 56.666308906031134 ], [ 24.376062860112881, 56.66840180110222 ], [ 24.383659294940514, 56.670856432278526 ], [ 24.414975212935701, 56.674267076064666 ], [ 24.42789432126591, 56.677677720750182 ], [ 24.443397251082274, 56.684240627702764 ], [ 24.482361280748478, 56.704704494916484 ], [ 24.521893752094968, 56.713644517780267 ], [ 24.556051873095441, 56.706978258040124 ], [ 24.600907017045188, 56.707029933984245 ], [ 24.634083286114731, 56.676850898450198 ], [ 24.58974490700183, 56.661037910271318 ], [ 24.59284549332483, 56.643028673334584 ], [ 24.599666781796543, 56.620678615725524 ], [ 24.617185093217472, 56.607191067513725 ], [ 24.629897495073294, 56.601454982861128 ], [ 24.656769239608707, 56.599801337361782 ], [ 24.662505324261303, 56.596855781569047 ], [ 24.662970412254708, 56.593961899921737 ], [ 24.660334913925112, 56.5904995792921 ], [ 24.661420118643548, 56.588329168955966 ], [ 24.666070997678389, 56.587166449871745 ], [ 24.673667433405285, 56.586546332247394 ], [ 24.691185743926951, 56.581662910115199 ], [ 24.697128534154501, 56.578872382154657 ], [ 24.697231886942006, 56.576236883825118 ], [ 24.681418897863807, 56.571327623271145 ], [ 24.671341994337524, 56.566780097023809 ], [ 24.664365676234979, 56.556832383807432 ], [ 24.657079298870542, 56.543577378693044 ], [ 24.732475212660916, 56.544249173160779 ], [ 24.949987336346453, 56.578568175680743 ], [ 24.956300895469951, 56.551092789100892 ], [ 24.995633356694043, 56.551092789100892 ], [ 25.013511748568305, 56.495669774740293 ], [ 24.920544112620689, 56.486730579252821 ], [ 24.911604916233898, 56.472427865753389 ], [ 24.900877881109295, 56.459912991891031 ], [ 24.877635972122391, 56.454549473879069 ], [ 24.8709672446426, 56.442602437352548 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-088", "NAME_1": "Saldus" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 22.214901977000096, 56.39038340300003 ], [ 22.195264933000146, 56.394853414000053 ], [ 22.158161255000095, 56.410252991000036 ], [ 22.139144328000015, 56.415704854000111 ], [ 22.094082479000065, 56.417410177000065 ], [ 21.983173071000039, 56.388353479000031 ], [ 21.982668897951271, 56.388780626324831 ], [ 21.980808546876915, 56.390356757458335 ], [ 21.945565220258686, 56.416711738056222 ], [ 21.951352979956027, 56.421130073094389 ], [ 21.961584914012576, 56.426271878544355 ], [ 21.976932814197994, 56.429114081549585 ], [ 21.987784864979517, 56.432524726235101 ], [ 21.99538130070647, 56.439320177184413 ], [ 21.989490187322247, 56.446115628133725 ], [ 21.954608595010654, 56.4706360951796 ], [ 21.957554151702709, 56.480842189915109 ], [ 21.953988478285623, 56.48781850891703 ], [ 21.956468946984273, 56.493606269513691 ], [ 21.966700881040822, 56.506628729732086 ], [ 21.99786176940512, 56.50593109774195 ], [ 22.009695672117573, 56.507972316868916 ], [ 22.024268425947071, 56.50745555293139 ], [ 22.037445915796354, 56.504044908245874 ], [ 22.056049431935719, 56.509057522486671 ], [ 22.05744469591599, 56.523268541110269 ], [ 22.049073113833117, 56.529056300807611 ], [ 22.018222283831335, 56.542595526762113 ], [ 22.011711052822818, 56.547504788215349 ], [ 22.011400995359622, 56.555049547098918 ], [ 22.060596958183055, 56.564506333900169 ], [ 22.099974399898599, 56.56853709620998 ], [ 22.121265090311624, 56.576340237511943 ], [ 22.126070998078092, 56.582205512474388 ], [ 22.123435499748496, 56.58763153696583 ], [ 22.118577915138644, 56.592359931265776 ], [ 22.115373976028138, 56.603806261249929 ], [ 22.112531773022909, 56.609516507480805 ], [ 22.109276157068962, 56.613624783257137 ], [ 22.111911655398558, 56.625691229966264 ], [ 22.111446567405153, 56.646671861117454 ], [ 22.103540073315742, 56.672871812983772 ], [ 22.112221713761073, 56.682948717409374 ], [ 22.125450881353061, 56.69013174108693 ], [ 22.155991652093064, 56.700311998300037 ], [ 22.166998731606157, 56.708218492389506 ], [ 22.173975050608078, 56.715969956848028 ], [ 22.181003044654744, 56.72852732997228 ], [ 22.188909538744213, 56.735658677705771 ], [ 22.189219598006048, 56.741756497564268 ], [ 22.185963982951421, 56.748112698042576 ], [ 22.174491815444924, 56.765889390982579 ], [ 22.162657911833151, 56.795034897742312 ], [ 22.204877556553981, 56.795215765794921 ], [ 22.230302362064322, 56.80906505011194 ], [ 22.251127963584622, 56.823095201582248 ], [ 22.269731479723987, 56.82970978537827 ], [ 22.305749952698136, 56.838623968921013 ], [ 22.316602004378979, 56.843662421583474 ], [ 22.34130333767888, 56.847486477418954 ], [ 22.342026808090679, 56.864229640685323 ], [ 22.329469434966427, 56.87477163400365 ], [ 22.32032270742701, 56.880404364969422 ], [ 22.310555861363866, 56.883763332811554 ], [ 22.30388960072446, 56.884512640745754 ], [ 22.295518018641644, 56.883298244818093 ], [ 22.287869906970627, 56.883091539243139 ], [ 22.269731479723987, 56.888052477539759 ], [ 22.26399539597071, 56.893943590024605 ], [ 22.267406039756906, 56.898542792216062 ], [ 22.287869906970627, 56.905777492737059 ], [ 22.290247022881772, 56.91006663746532 ], [ 22.304354688717865, 56.919730129841582 ], [ 22.328384230247991, 56.916836249093592 ], [ 22.335670606713109, 56.913012193258112 ], [ 22.338512810617715, 56.908025418338354 ], [ 22.338151076311078, 56.904072171293649 ], [ 22.348744744674207, 56.896424058723312 ], [ 22.392307977431187, 56.885882066304305 ], [ 22.417784457986329, 56.889344386933885 ], [ 22.432357211815884, 56.898542792216062 ], [ 22.443364292228296, 56.903555406456803 ], [ 22.454888135678914, 56.917094632411306 ], [ 22.492405226320102, 56.920091865047482 ], [ 22.511938918446333, 56.917404689874502 ], [ 22.526563348219952, 56.912960517313991 ], [ 22.529198845650171, 56.908774726272554 ], [ 22.524392937883761, 56.905105699168644 ], [ 22.520982293198244, 56.900299791402233 ], [ 22.52113732282919, 56.88464183195498 ], [ 22.518966913392319, 56.876838691552337 ], [ 22.514626091820674, 56.871981106043165 ], [ 22.506564568999636, 56.86748525753859 ], [ 22.500466750040459, 56.862989407235318 ], [ 22.490854932708942, 56.851517238829501 ], [ 22.462810392185816, 56.805420994483256 ], [ 22.442234072844144, 56.771127128913861 ], [ 22.460524134780997, 56.736833262445089 ], [ 22.487959227236558, 56.723115716217308 ], [ 22.497104258654588, 56.684249334938841 ], [ 22.501676773464283, 56.638524180546483 ], [ 22.535970639933055, 56.620234119509007 ], [ 22.549688186160836, 56.579081479926344 ], [ 22.574837020312202, 56.567650192002759 ], [ 22.60455837107196, 56.599657799268016 ], [ 22.654856041173332, 56.604230314977031 ], [ 22.693722422451799, 56.588226511344374 ], [ 22.712074313678613, 56.565372530317973 ], [ 22.701436395073529, 56.493296210251856 ], [ 22.741330600726599, 56.475442002946068 ], [ 22.744896275043061, 56.46812978805923 ], [ 22.748151890097631, 56.455701606144203 ], [ 22.742880894337759, 56.44926789040079 ], [ 22.736628044848374, 56.443790188166645 ], [ 22.726551141322091, 56.424540716880529 ], [ 22.767530551693596, 56.421827704185148 ], [ 22.785979038202015, 56.418417060399008 ], [ 22.821842482444595, 56.402707425007634 ], [ 22.858532748987159, 56.397229722773432 ], [ 22.859602845994516, 56.397069961809279 ], [ 22.822926880000097, 56.382864482000073 ], [ 22.681436808000058, 56.350308330000033 ], [ 22.666347290000147, 56.34909393400001 ], [ 22.649087361000085, 56.353098857000091 ], [ 22.604748982000018, 56.379092102000058 ], [ 22.578221703000111, 56.3870029160001 ], [ 22.575810180000076, 56.387722067000098 ], [ 22.511731404000045, 56.395964458000051 ], [ 22.214901977000096, 56.39038340300003 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-081", "NAME_1": "Rucavas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.485493169569811, 56.265791916040953 ], [ 21.419291626000131, 56.237395325000065 ], [ 21.403685343000092, 56.234475607000078 ], [ 21.35831343600006, 56.233235373000028 ], [ 21.327617635000109, 56.224372864000017 ], [ 21.290410603000112, 56.206932068000086 ], [ 21.254857218000041, 56.185202128000086 ], [ 21.229639119000097, 56.163187968 ], [ 21.212585897000054, 56.13099355100006 ], [ 21.205351196000095, 56.103424174000068 ], [ 21.190365031000113, 56.084458924 ], [ 21.150160767000102, 56.078180237000097 ], [ 21.091352986000118, 56.077896017000015 ], [ 21.053396030000044, 56.072617906000062 ], [ 21.053396030000044, 56.072943427000041 ], [ 21.052582227000073, 56.077541408000059 ], [ 21.04273522200009, 56.114569403000075 ], [ 21.028819207000083, 56.147406317000048 ], [ 20.98406009200005, 56.210435289000031 ], [ 20.973399285000085, 56.232001044000071 ], [ 20.969086134000065, 56.253485419000071 ], [ 20.971039259000065, 56.259670315000051 ], [ 21.034466751639286, 56.266395796628672 ], [ 21.055786793225934, 56.168323604250929 ], [ 21.083502847378497, 56.166191600362026 ], [ 21.083502847378497, 56.191775649726424 ], [ 21.085634852166663, 56.228019721233125 ], [ 21.109086897642214, 56.219491704778306 ], [ 21.16451900684666, 56.264263792739825 ], [ 21.179443035867394, 56.28771583821532 ], [ 21.183707044544462, 56.323959909722021 ], [ 21.179443035867394, 56.355939972551653 ], [ 21.226347127717759, 56.351675963874584 ], [ 21.26259119922446, 56.326091913610924 ], [ 21.379851429300004, 56.32822391839909 ], [ 21.452339571414086, 56.302639868135373 ], [ 21.485493169569811, 56.265791916040953 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-074", "NAME_1": "Priekules" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.736514296197203, 56.323732366476086 ], [ 21.684495076000076, 56.310104066000022 ], [ 21.596025025000131, 56.307881979000015 ], [ 21.558921346000147, 56.297288310000042 ], [ 21.485493169569811, 56.265791916040953 ], [ 21.452339571414086, 56.302639868135373 ], [ 21.379851429300004, 56.32822391839909 ], [ 21.416095500806705, 56.353807968662807 ], [ 21.437415542393353, 56.407108073079087 ], [ 21.386247441865919, 56.464672186172436 ], [ 21.384115437977073, 56.490256236436153 ], [ 21.354267379036287, 56.503048261567983 ], [ 21.407567483452567, 56.520104294477562 ], [ 21.399039466997806, 56.558480369873166 ], [ 21.433151533716284, 56.545688344741279 ], [ 21.473659613900054, 56.520104294477562 ], [ 21.482187630354815, 56.511576278022801 ], [ 21.52909172220518, 56.513708281911647 ], [ 21.499243664163771, 56.552084357307194 ], [ 21.52909172220518, 56.571272395004996 ], [ 21.571731806277796, 56.560612373762012 ], [ 21.584523831409683, 56.549952353418348 ], [ 21.661275982200777, 56.560612373762012 ], [ 21.712444082728211, 56.549952353418348 ], [ 21.708180074051143, 56.505180265456886 ], [ 21.73376412431486, 56.498784252890914 ], [ 21.73376412431486, 56.473200202627197 ], [ 21.680464019898579, 56.464672186172436 ], [ 21.684728027676329, 56.432692123342804 ], [ 21.665539989978527, 56.417768093422751 ], [ 21.701784061485228, 56.396448051836103 ], [ 21.723104103071876, 56.38152402281537 ], [ 21.750820158123759, 56.38152402281537 ], [ 21.750820158123759, 56.36873199768354 ], [ 21.725236107860098, 56.355939972551653 ], [ 21.736514296197203, 56.323732366476086 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-100", "NAME_1": "Vainodes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.965321874000068, 56.383676718000046 ], [ 21.736514296197203, 56.323732366476086 ], [ 21.725236107860098, 56.355939972551653 ], [ 21.750820158123759, 56.36873199768354 ], [ 21.750820158123759, 56.38152402281537 ], [ 21.723104103071876, 56.38152402281537 ], [ 21.701784061485228, 56.396448051836103 ], [ 21.665539989978527, 56.417768093422751 ], [ 21.684728027676329, 56.432692123342804 ], [ 21.680464019898579, 56.464672186172436 ], [ 21.73376412431486, 56.473200202627197 ], [ 21.73376412431486, 56.498784252890914 ], [ 21.708180074051143, 56.505180265456886 ], [ 21.712444082728211, 56.549952353418348 ], [ 21.752952162012662, 56.562744378550178 ], [ 21.795393507604274, 56.573343003976447 ], [ 21.793223097268083, 56.554377753530446 ], [ 21.807485792735122, 56.538461412564118 ], [ 21.818027785154129, 56.530839138415502 ], [ 21.833065626977088, 56.523966173100405 ], [ 21.850790643073708, 56.521149806718199 ], [ 21.866138543259126, 56.520426337205663 ], [ 21.893475375787943, 56.523010158691818 ], [ 21.904172397837897, 56.521511541924099 ], [ 21.908358188879276, 56.517454942091888 ], [ 21.910063511222063, 56.512054755122847 ], [ 21.912388950289824, 56.507920640924794 ], [ 21.920605502741751, 56.506938788094544 ], [ 21.956934034977735, 56.514173489514917 ], [ 21.966700881040822, 56.506628729732086 ], [ 21.956468946984273, 56.493606269513691 ], [ 21.953988478285623, 56.48781850891703 ], [ 21.957554151702709, 56.480842189915109 ], [ 21.954608595010654, 56.4706360951796 ], [ 21.989490187322247, 56.446115628133725 ], [ 21.99538130070647, 56.439320177184413 ], [ 21.987784864979517, 56.432524726235101 ], [ 21.976932814197994, 56.429114081549585 ], [ 21.961584914012576, 56.426271878544355 ], [ 21.951352979956027, 56.421130073094389 ], [ 21.945565220258686, 56.416711738056222 ], [ 21.980808546876915, 56.390356757458335 ], [ 21.982668897951271, 56.388780626324831 ], [ 21.983173071000039, 56.388353479000031 ], [ 21.965321874000068, 56.383676718000046 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-010", "NAME_1": "Auces" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.062292114000059, 56.304161276000102 ], [ 23.01671350100014, 56.32384999600005 ], [ 22.981366822000069, 56.373175151000041 ], [ 22.95697554500012, 56.401984762000083 ], [ 22.924522746, 56.41211334300003 ], [ 22.888969360000146, 56.408444316000029 ], [ 22.859602845994516, 56.397069961809279 ], [ 22.858532748987159, 56.397229722773432 ], [ 22.821842482444595, 56.402707425007634 ], [ 22.785979038202015, 56.418417060399008 ], [ 22.767530551693596, 56.421827704185148 ], [ 22.726551141322091, 56.424540716880529 ], [ 22.736628044848374, 56.443790188166645 ], [ 22.742880894337759, 56.44926789040079 ], [ 22.748151890097631, 56.455701606144203 ], [ 22.744896275043061, 56.46812978805923 ], [ 22.741330600726599, 56.475442002946068 ], [ 22.701436395073529, 56.493296210251856 ], [ 22.712074313678613, 56.565372530317973 ], [ 22.732287225075368, 56.565281481155409 ], [ 22.735904575335894, 56.565539863573804 ], [ 22.755128208200233, 56.562025865201463 ], [ 22.773421665077763, 56.567503567435665 ], [ 22.798123000176304, 56.56833038973565 ], [ 22.82340877409564, 56.561819824225495 ], [ 22.834135809220186, 56.540365753976346 ], [ 22.848438522719619, 56.538577914339271 ], [ 22.862741235319731, 56.552880627838704 ], [ 22.896710179431238, 56.56718334133808 ], [ 22.930679123542689, 56.568971180075891 ], [ 22.925315606430104, 56.588637411587229 ], [ 22.961072389279309, 56.601152285449587 ], [ 22.980738620790703, 56.577910376462683 ], [ 23.021858921651869, 56.59042525032504 ], [ 23.041525152263944, 56.577910376462683 ], [ 23.066554899988603, 56.551092789100892 ], [ 23.088008970237752, 56.545729271088987 ], [ 23.086221131499997, 56.524275201739158 ], [ 23.089796809874883, 56.479579222503105 ], [ 23.121977914349259, 56.470640026116257 ], [ 23.129129271098975, 56.445610278391598 ], [ 23.148795501710993, 56.43309540362992 ], [ 23.118402235974372, 56.409853494643016 ], [ 23.152371180085879, 56.390187264030999 ], [ 23.172569619592252, 56.357956441436613 ], [ 23.154172811000109, 56.351393534000024 ], [ 23.162854451000072, 56.341006572000097 ], [ 23.112728312000058, 56.310879212000017 ], [ 23.062292114000059, 56.304161276000102 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-016", "NAME_1": "Bauska" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.572772161366768, 56.309810859570966 ], [ 24.557911417000099, 56.29858022100008 ], [ 24.538997843000061, 56.287624817 ], [ 24.481326945000092, 56.268840435000087 ], [ 24.447220499000139, 56.260520528000043 ], [ 24.414354289000102, 56.265507304 ], [ 24.350792277000039, 56.291552226000064 ], [ 24.31854618400007, 56.29858022100008 ], [ 24.287643677000091, 56.295531311000062 ], [ 24.166824178000041, 56.260313823000089 ], [ 24.140421618000062, 56.257600226000093 ], [ 24.138918905000082, 56.257445780000111 ], [ 24.108636516000047, 56.260701396000101 ], [ 24.075150187000133, 56.271191712000032 ], [ 23.981305786000036, 56.312403666000037 ], [ 24.008746138723325, 56.322249375808042 ], [ 24.035563726984378, 56.331188572194833 ], [ 24.04092724409702, 56.35085480280685 ], [ 24.073108348571395, 56.363369676669208 ], [ 24.06774483145881, 56.383035907281283 ], [ 24.090986740445715, 56.383035907281283 ], [ 24.126743524194296, 56.36873319378185 ], [ 24.155348950293785, 56.386611585656112 ], [ 24.114228649432619, 56.400914299155545 ], [ 24.064169153083924, 56.415217012654978 ], [ 24.03735156572219, 56.425944047779581 ], [ 24.035563726984378, 56.447398117129353 ], [ 24.030200208972474, 56.477791382865973 ], [ 24.017743371059737, 56.502013034873642 ], [ 24.031742790897056, 56.501719469178113 ], [ 24.042904900940414, 56.502830512318269 ], [ 24.080938754619808, 56.527454332151706 ], [ 24.078871697970442, 56.535464179028622 ], [ 24.105289453945147, 56.529638718851743 ], [ 24.1499854331812, 56.524275201739158 ], [ 24.173227342168104, 56.517123844989442 ], [ 24.194681412417253, 56.509972488239725 ], [ 24.234013873641345, 56.501033291852934 ], [ 24.251892265515608, 56.518911683727197 ], [ 24.300163923126547, 56.535002235964384 ], [ 24.34485990146328, 56.536790075601459 ], [ 24.380616685211862, 56.529638718851743 ], [ 24.40028291582388, 56.509972488239725 ], [ 24.42710050318567, 56.493881936002538 ], [ 24.437827538310216, 56.474215704491144 ], [ 24.473584321159478, 56.483154900877935 ], [ 24.51291678328289, 56.454549473879069 ], [ 24.530795174257889, 56.409853494643016 ], [ 24.514704622020645, 56.397338620780715 ], [ 24.446766733797688, 56.381248068543528 ], [ 24.452130251809649, 56.366945355044095 ], [ 24.505765426533173, 56.361581837931453 ], [ 24.491462713033741, 56.343703446057134 ], [ 24.468220804046837, 56.331188572194833 ], [ 24.480735677909195, 56.309734501945684 ], [ 24.529007335520078, 56.322249375808042 ], [ 24.572772161366768, 56.309810859570966 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-098", "NAME_1": "Tervetes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.37803970300007, 56.354629849000034 ], [ 23.31064904800013, 56.37059132900005 ], [ 23.288428182000075, 56.373045960000113 ], [ 23.172569619592252, 56.357956441436613 ], [ 23.152371180085879, 56.390187264030999 ], [ 23.118402235974372, 56.409853494643016 ], [ 23.148795501710993, 56.43309540362992 ], [ 23.172037410697953, 56.45097379550424 ], [ 23.214945551196195, 56.454549473879069 ], [ 23.275732082669435, 56.454549473879069 ], [ 23.309701026780942, 56.459912991891031 ], [ 23.288246956531793, 56.468852187378502 ], [ 23.273944243032361, 56.490306257627651 ], [ 23.315064543893584, 56.513548166614555 ], [ 23.35618484475475, 56.545729271088987 ], [ 23.383002432116541, 56.545729271088987 ], [ 23.393729467241087, 56.518911683727197 ], [ 23.415087925167597, 56.493296210251856 ], [ 23.430745883715531, 56.477586574860538 ], [ 23.427800327023476, 56.472884019881576 ], [ 23.42593997594912, 56.46893077283687 ], [ 23.415397984429433, 56.461463528319143 ], [ 23.413072543563032, 56.459448146714578 ], [ 23.418808628215629, 56.4494487584534 ], [ 23.430900913346477, 56.445185452146859 ], [ 23.439427525060239, 56.436658841332417 ], [ 23.449504428586465, 56.421879381028589 ], [ 23.462061801710774, 56.407151598467465 ], [ 23.46237186007329, 56.397953193185288 ], [ 23.456945834682529, 56.391648667751781 ], [ 23.449969516579927, 56.38627431920446 ], [ 23.442373080852974, 56.382062689741304 ], [ 23.430435825353015, 56.377902737121588 ], [ 23.420203892195843, 56.375887356416342 ], [ 23.384805535946725, 56.360746161805878 ], [ 23.378345981781592, 56.354906725265153 ], [ 23.37803970300007, 56.354629849000034 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-JEL", "NAME_1": "Jelgava" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.517561482000133, 56.328655904000058 ], [ 23.481594686000079, 56.330102845000042 ], [ 23.37803970300007, 56.354629849000034 ], [ 23.378345981781592, 56.354906725265153 ], [ 23.384805535946725, 56.360746161805878 ], [ 23.420203892195843, 56.375887356416342 ], [ 23.430435825353015, 56.377902737121588 ], [ 23.442373080852974, 56.382062689741304 ], [ 23.449969516579927, 56.38627431920446 ], [ 23.456945834682529, 56.391648667751781 ], [ 23.46237186007329, 56.397953193185288 ], [ 23.462061801710774, 56.407151598467465 ], [ 23.449504428586465, 56.421879381028589 ], [ 23.439427525060239, 56.436658841332417 ], [ 23.430900913346477, 56.445185452146859 ], [ 23.418808628215629, 56.4494487584534 ], [ 23.413072543563032, 56.459448146714578 ], [ 23.415397984429433, 56.461463528319143 ], [ 23.42593997594912, 56.46893077283687 ], [ 23.427800327023476, 56.472884019881576 ], [ 23.430745883715531, 56.477586574860538 ], [ 23.415087925167597, 56.493296210251856 ], [ 23.437877232348399, 56.499264838001864 ], [ 23.44748904788122, 56.505621039379434 ], [ 23.459271274649609, 56.529831448062851 ], [ 23.458651157025258, 56.544817613042369 ], [ 23.445938755169379, 56.556393134235748 ], [ 23.434466586763563, 56.564092922750149 ], [ 23.432141147695802, 56.57083669685602 ], [ 23.436792025831323, 56.577063707024422 ], [ 23.448419223868086, 56.579079087729667 ], [ 23.477151320377118, 56.586933905875014 ], [ 23.480251905800799, 56.599542954943388 ], [ 23.405941195829485, 56.606441759579525 ], [ 23.412917514831406, 56.616027736690683 ], [ 23.424699740700476, 56.622125556549179 ], [ 23.438187289811538, 56.634450384777381 ], [ 23.444543491189165, 56.641555894988528 ], [ 23.476066114759362, 56.656180324762147 ], [ 23.485367872829045, 56.660288601437799 ], [ 23.484282668110609, 56.664913642050919 ], [ 23.479786817807394, 56.676773383185036 ], [ 23.481492140150124, 56.680416571867283 ], [ 23.478236525095554, 56.684809068483673 ], [ 23.462991977697584, 56.692534695419852 ], [ 23.442683140114809, 56.696798000827073 ], [ 23.417413364235358, 56.706823229308554 ], [ 23.436481968368128, 56.723876450937439 ], [ 23.459271274649609, 56.734573472987336 ], [ 23.502886183350654, 56.746872463693194 ], [ 23.525262079381434, 56.763667303803004 ], [ 23.50552168078093, 56.808212389390235 ], [ 23.48660810717837, 56.815912177005316 ], [ 23.461958448923269, 56.884228420804959 ], [ 23.506761916029575, 56.894615384492397 ], [ 23.587635532054151, 56.891204738907561 ], [ 23.600813022802754, 56.889292710989764 ], [ 23.626237827413775, 56.8892410350457 ], [ 23.669542677752361, 56.874900825212876 ], [ 23.70726647306924, 56.852137356453795 ], [ 23.718428582213278, 56.835962633069016 ], [ 23.734086540761211, 56.822009995964493 ], [ 23.769639926641275, 56.800047511983053 ], [ 23.759718051846619, 56.771883857154251 ], [ 23.764213901250514, 56.768266506893724 ], [ 23.756307407161103, 56.744133613475469 ], [ 23.701237802982178, 56.737028061895501 ], [ 23.701237802982178, 56.720937509658313 ], [ 23.670844537245557, 56.715573991646352 ], [ 23.683359411107915, 56.697695599772089 ], [ 23.710176999369025, 56.70663479615888 ], [ 23.731209870339228, 56.690498589838 ], [ 23.683804230181067, 56.674098589877985 ], [ 23.644412690693116, 56.677963454250005 ], [ 23.617950646704969, 56.669543712572249 ], [ 23.631181668699014, 56.650298589508282 ], [ 23.676992949365115, 56.629895770073688 ], [ 23.670992949664878, 56.601501410361777 ], [ 23.707587308907137, 56.591887308752291 ], [ 23.739007050035298, 56.6076591070821 ], [ 23.778804230530795, 56.6175788486849 ], [ 23.769818331450836, 56.636687308972114 ], [ 23.791941897500578, 56.646880719669468 ], [ 23.82817438394062, 56.627969872811377 ], [ 23.865719006427014, 56.615454998949019 ], [ 23.912202824400822, 56.608303642199303 ], [ 23.940808251399687, 56.579698215200438 ], [ 23.964050160386591, 56.554668467475778 ], [ 23.969413677499176, 56.518911683727197 ], [ 23.99231367413671, 56.502546292377474 ], [ 23.962651400741549, 56.497843736499192 ], [ 23.95009402761724, 56.488025214492041 ], [ 23.932110630001546, 56.482754217832849 ], [ 23.920018344870698, 56.472728990250687 ], [ 23.886015251702474, 56.466114407353984 ], [ 23.875008172189382, 56.462858792299414 ], [ 23.861675652709209, 56.44849274404487 ], [ 23.847516310029675, 56.438829250769288 ], [ 23.840695020658643, 56.434178371734447 ], [ 23.841005079920478, 56.43035431589891 ], [ 23.842710402263208, 56.427408759206855 ], [ 23.850151808359271, 56.423377996896988 ], [ 23.85046186672173, 56.418468736343073 ], [ 23.84798139802308, 56.411750799759545 ], [ 23.843020460625723, 56.401828924964889 ], [ 23.838679639953398, 56.397023017198478 ], [ 23.836664260147472, 56.393250637307062 ], [ 23.836199172154068, 56.387850450337965 ], [ 23.873922966571627, 56.389478258314966 ], [ 23.879348992861708, 56.384284776021559 ], [ 23.873612909108431, 56.373768622024272 ], [ 23.870822381147946, 56.36715403912757 ], [ 23.868651970811811, 56.34327952722839 ], [ 23.871029086722956, 56.332427477346187 ], [ 23.871106924844696, 56.332072130024756 ], [ 23.85810917200007, 56.334391989000025 ], [ 23.825036255000072, 56.33490875300005 ], [ 23.756099894000045, 56.325968730000042 ], [ 23.724990682000112, 56.328810934 ], [ 23.723647094000029, 56.332118226 ], [ 23.72478397600014, 56.338396912000107 ], [ 23.723543742000118, 56.345812480000021 ], [ 23.715068807000108, 56.352737122000107 ], [ 23.706697225000113, 56.354442444000071 ], [ 23.679412069000108, 56.351858622000051 ], [ 23.609855591000013, 56.353822327 ], [ 23.577712850000097, 56.348603007000079 ], [ 23.517561482000133, 56.328655904000058 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-083", "NAME_1": "Rundales" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.981305786000036, 56.312403666000037 ], [ 23.871106924844696, 56.332072130024756 ], [ 23.871029086722956, 56.332427477346187 ], [ 23.868651970811811, 56.34327952722839 ], [ 23.870822381147946, 56.36715403912757 ], [ 23.873612909108431, 56.373768622024272 ], [ 23.879348992861708, 56.384284776021559 ], [ 23.873922966571627, 56.389478258314966 ], [ 23.836199172154068, 56.387850450337965 ], [ 23.836664260147472, 56.393250637307062 ], [ 23.838679639953398, 56.397023017198478 ], [ 23.843020460625723, 56.401828924964889 ], [ 23.84798139802308, 56.411750799759545 ], [ 23.85046186672173, 56.418468736343073 ], [ 23.850151808359271, 56.423377996896988 ], [ 23.842710402263208, 56.427408759206855 ], [ 23.841005079920478, 56.43035431589891 ], [ 23.840695020658643, 56.434178371734447 ], [ 23.847516310029675, 56.438829250769288 ], [ 23.861675652709209, 56.44849274404487 ], [ 23.875008172189382, 56.462858792299414 ], [ 23.886015251702474, 56.466114407353984 ], [ 23.920018344870698, 56.472728990250687 ], [ 23.932110630001546, 56.482754217832849 ], [ 23.95009402761724, 56.488025214492041 ], [ 23.962651400741549, 56.497843736499192 ], [ 23.99231367413671, 56.502546292377474 ], [ 24.017743371059737, 56.502013034873642 ], [ 24.030200208972474, 56.477791382865973 ], [ 24.035563726984378, 56.447398117129353 ], [ 24.03735156572219, 56.425944047779581 ], [ 24.064169153083924, 56.415217012654978 ], [ 24.114228649432619, 56.400914299155545 ], [ 24.155348950293785, 56.386611585656112 ], [ 24.126743524194296, 56.36873319378185 ], [ 24.090986740445715, 56.383035907281283 ], [ 24.06774483145881, 56.383035907281283 ], [ 24.073108348571395, 56.363369676669208 ], [ 24.04092724409702, 56.35085480280685 ], [ 24.035563726984378, 56.331188572194833 ], [ 24.008746138723325, 56.322249375808042 ], [ 23.981305786000036, 56.312403666000037 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-004", "NAME_1": "Aknistes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.795496034000053, 56.040130340000061 ], [ 25.766261434000114, 56.058646546 ], [ 25.708797241000099, 56.081048279000086 ], [ 25.69660160300009, 56.087895406000044 ], [ 25.687816610000112, 56.098334046000062 ], [ 25.669213094000071, 56.132027080000043 ], [ 25.661875041000059, 56.140812073000021 ], [ 25.649679402582365, 56.143809306554203 ], [ 25.67380918344702, 56.184047209710911 ], [ 25.693844778213929, 56.208535158171003 ], [ 25.693844778213929, 56.228570752038536 ], [ 25.756177738012184, 56.230796929334815 ], [ 25.800701280339808, 56.23524928392726 ], [ 25.838546291678028, 56.226344574742313 ], [ 25.876391303016192, 56.221892221049131 ], [ 25.896426897783101, 56.201856626282222 ], [ 25.905331606068728, 56.170690146832783 ], [ 25.94762897199945, 56.157333083954654 ], [ 25.976569275051986, 56.148428375668971 ], [ 25.976569275051986, 56.128392780902061 ], [ 25.98547398333767, 56.110583363431431 ], [ 26.012188109093927, 56.108357187034528 ], [ 26.025522902060288, 56.079419663786439 ], [ 26.007694533176164, 56.087274481931786 ], [ 25.989556105030204, 56.080530706926538 ], [ 25.982218051721702, 56.075879828791017 ], [ 25.954467808042864, 56.06288320609508 ], [ 25.941755405287722, 56.06172048611154 ], [ 25.926200798627917, 56.070686347396986 ], [ 25.915968866370065, 56.080065619832453 ], [ 25.83127119271137, 56.122853705334194 ], [ 25.834681838296206, 56.109624539540846 ], [ 25.838092482082345, 56.104276028515869 ], [ 25.850959913569113, 56.093139756894232 ], [ 25.853905470261225, 56.088669745912 ], [ 25.859796583645391, 56.081848456541024 ], [ 25.848789504132299, 56.074872138438423 ], [ 25.844603713090862, 56.065441189159515 ], [ 25.83762739408894, 56.058103135851013 ], [ 25.810600619922639, 56.04820709947802 ], [ 25.795717807730625, 56.040248928545168 ], [ 25.795496034000053, 56.040130340000061 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-036", "NAME_1": "Ilukstes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.961251118000064, 55.958458834000069 ], [ 25.871267944000067, 55.992138977000124 ], [ 25.795496034000053, 56.040130340000061 ], [ 25.795717807730625, 56.040248928545168 ], [ 25.810600619922639, 56.04820709947802 ], [ 25.83762739408894, 56.058103135851013 ], [ 25.844603713090862, 56.065441189159515 ], [ 25.848789504132299, 56.074872138438423 ], [ 25.859796583645391, 56.081848456541024 ], [ 25.853905470261225, 56.088669745912 ], [ 25.850959913569113, 56.093139756894232 ], [ 25.838092482082345, 56.104276028515869 ], [ 25.834681838296206, 56.109624539540846 ], [ 25.83127119271137, 56.122853705334194 ], [ 25.915968866370065, 56.080065619832453 ], [ 25.926200798627917, 56.070686347396986 ], [ 25.941755405287722, 56.06172048611154 ], [ 25.954467808042864, 56.06288320609508 ], [ 25.982218051721702, 56.075879828791017 ], [ 25.989556105030204, 56.080530706926538 ], [ 26.007694533176164, 56.087274481931786 ], [ 26.025522902060288, 56.079419663786439 ], [ 26.036995069566785, 56.068567613004916 ], [ 26.046296827636468, 56.06634552672466 ], [ 26.058905876704841, 56.067740789805555 ], [ 26.079369744817825, 56.078799547061408 ], [ 26.092392205935539, 56.089599920999547 ], [ 26.097559848907906, 56.096007799220558 ], [ 26.108566929320318, 56.101485501454704 ], [ 26.120504184820277, 56.100710354199464 ], [ 26.129340854896498, 56.098384915131703 ], [ 26.152440220439814, 56.109185289069785 ], [ 26.153060337164789, 56.118280341564457 ], [ 26.151355014822059, 56.121019191782239 ], [ 26.138952671328695, 56.131096096207841 ], [ 26.205821974304627, 56.163600571708969 ], [ 26.219671257722325, 56.166029365362874 ], [ 26.243390740889936, 56.167062893237926 ], [ 26.25718834836357, 56.162076118318168 ], [ 26.282199740925307, 56.158949693573447 ], [ 26.304989048106052, 56.153471992238622 ], [ 26.313050570927089, 56.150371405915621 ], [ 26.317546421230361, 56.14592723245579 ], [ 26.320698682598106, 56.141534735839343 ], [ 26.31863162594874, 56.134997667308483 ], [ 26.315065951632334, 56.130734361001942 ], [ 26.316306186880979, 56.122724514125025 ], [ 26.345348341752526, 56.093449815256747 ], [ 26.348399284599282, 56.073187567052571 ], [ 26.357025587061173, 56.055446681519129 ], [ 26.369639519448242, 56.043768621424704 ], [ 26.365489128420506, 56.02167389573367 ], [ 26.376556836628708, 55.997748114383967 ], [ 26.392967022310188, 55.977725237829418 ], [ 26.372580424846717, 55.953827283302473 ], [ 26.33783624264845, 55.965408677068751 ], [ 26.317982424249465, 55.950518313269527 ], [ 26.291510666683905, 55.940591404070005 ], [ 26.286547212084145, 55.924046555703967 ], [ 26.303092060450183, 55.917428616537393 ], [ 26.319636909715598, 55.907501707337872 ], [ 26.27662030288468, 55.881029949772312 ], [ 26.336181758081636, 55.839667827508208 ], [ 26.349417636414785, 55.809887100809021 ], [ 26.291510666683905, 55.806578130776074 ], [ 26.258420969052452, 55.804923646209261 ], [ 26.226905151551478, 55.796931254273943 ], [ 26.203754110000091, 55.827446187000064 ], [ 26.178639364000077, 55.849589539000092 ], [ 26.07942061300011, 55.898139547000071 ], [ 26.017615600000113, 55.937361959000029 ], [ 25.961251118000064, 55.958458834000069 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-DGV", "NAME_1": "Daugavpils" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.594531291000067, 55.666990866000063 ], [ 26.537480509000062, 55.669523010000077 ], [ 26.481049846000133, 55.678308005000062 ], [ 26.342350301000067, 55.716341858000092 ], [ 26.279718466000134, 55.743239441000085 ], [ 26.226905151551478, 55.796931254273943 ], [ 26.258420969052452, 55.804923646209261 ], [ 26.291510666683905, 55.806578130776074 ], [ 26.349417636414785, 55.809887100809021 ], [ 26.336181758081636, 55.839667827508208 ], [ 26.27662030288468, 55.881029949772312 ], [ 26.319636909715598, 55.907501707337872 ], [ 26.303092060450183, 55.917428616537393 ], [ 26.286547212084145, 55.924046555703967 ], [ 26.291510666683905, 55.940591404070005 ], [ 26.317982424249465, 55.950518313269527 ], [ 26.33783624264845, 55.965408677068751 ], [ 26.372580424846717, 55.953827283302473 ], [ 26.392967022310188, 55.977725237829418 ], [ 26.376556836628708, 55.997748114383967 ], [ 26.365489128420506, 56.02167389573367 ], [ 26.369639519448242, 56.043768621424704 ], [ 26.357025587061173, 56.055446681519129 ], [ 26.348399284599282, 56.073187567052571 ], [ 26.345348341752526, 56.093449815256747 ], [ 26.342609490635482, 56.107893377877076 ], [ 26.340749138661806, 56.134248359374283 ], [ 26.33656334762037, 56.149441229928811 ], [ 26.328295119224379, 56.162670397520799 ], [ 26.300803257064615, 56.18334096941021 ], [ 26.33542646695787, 56.189748846731845 ], [ 26.380850050789206, 56.196906032887057 ], [ 26.41655846540084, 56.183547674985164 ], [ 26.455367466335474, 56.180447089561483 ], [ 26.484512973994526, 56.167786362750405 ], [ 26.507508985851018, 56.132336331456486 ], [ 26.54084028455145, 56.133912461690727 ], [ 26.543940870874451, 56.142103175720933 ], [ 26.556549919942825, 56.156572578561622 ], [ 26.570657585778918, 56.153962917754427 ], [ 26.576238640800625, 56.14804596594854 ], [ 26.609621616344498, 56.132207140247317 ], [ 26.62062869585759, 56.1249466013046 ], [ 26.624814486899027, 56.121122545469063 ], [ 26.647913853341663, 56.135281887249278 ], [ 26.687342970101952, 56.12551504208551 ], [ 26.700365431219666, 56.118693752714478 ], [ 26.718503859365626, 56.111252345719151 ], [ 26.748166130962147, 56.111097316987582 ], [ 26.774727817135044, 56.115076402454008 ], [ 26.807283970378933, 56.127323717215745 ], [ 26.823251987289382, 56.12951996507428 ], [ 26.836791213243885, 56.129390773865111 ], [ 26.847643263126088, 56.12396474937367 ], [ 26.872292922280508, 56.12722036442824 ], [ 26.888467644765967, 56.128874009927586 ], [ 26.890793083833728, 56.105051174871789 ], [ 26.931100702435458, 56.058697415053643 ], [ 26.968669468121448, 56.060196030922043 ], [ 26.951926303955759, 56.041024074901088 ], [ 26.953631626298488, 56.034306139216937 ], [ 26.958282505333329, 56.027123115539325 ], [ 26.969444613578048, 56.013635566428206 ], [ 26.967739292134581, 56.007847804932226 ], [ 26.932650995147299, 56.003300279584209 ], [ 26.943503045029502, 55.966790880194935 ], [ 26.947120396189291, 55.960072944510728 ], [ 26.955647007003734, 55.950280260025977 ], [ 26.944484897859752, 55.941650296424029 ], [ 26.935596550940033, 55.932193508723401 ], [ 26.954561802285355, 55.927594306532001 ], [ 26.946345248934051, 55.911316230359716 ], [ 26.937818638119609, 55.90387482426371 ], [ 26.934356316590709, 55.892764391063793 ], [ 26.934201287859139, 55.873902493405296 ], [ 26.97797122619113, 55.864213161707994 ], [ 26.980606723621406, 55.855350654109372 ], [ 26.981536899608216, 55.844653632059419 ], [ 26.979986606896375, 55.838917548306199 ], [ 26.97874637164773, 55.827083644694426 ], [ 26.979056430909566, 55.826721910387846 ], [ 26.979425814849435, 55.826290963357224 ], [ 26.957816610000094, 55.81858368000006 ], [ 26.900145711000107, 55.778715312000045 ], [ 26.842784872000038, 55.719339092 ], [ 26.822837769000103, 55.706109925000092 ], [ 26.743049357000132, 55.68285553 ], [ 26.72010502100008, 55.681873678000031 ], [ 26.66687829600005, 55.693965963000025 ], [ 26.64010990400007, 55.695567933000049 ], [ 26.615615275000096, 55.687971497000078 ], [ 26.594531291000067, 55.666990866000063 ] ], [ [ 26.51841105512608, 55.826555912625224 ], [ 26.532466108823826, 55.832177934464085 ], [ 26.556359700739563, 55.837799956302888 ], [ 26.581658797215709, 55.840610967222347 ], [ 26.597119357272504, 55.85326051546042 ], [ 26.601817253763215, 55.873724676752374 ], [ 26.616709831693356, 55.881170965267813 ], [ 26.6249292322982, 55.888861395437004 ], [ 26.631927930929237, 55.897406317347645 ], [ 26.61117441097025, 55.903858709311976 ], [ 26.61679643280911, 55.923535784848582 ], [ 26.612579916429979, 55.94602387130459 ], [ 26.609768905510577, 55.958673419542663 ], [ 26.594919269308832, 55.962130279488804 ], [ 26.54110825823949, 55.92708533342136 ], [ 26.471864215361222, 55.933230279553754 ], [ 26.437917514181891, 55.914618231546115 ], [ 26.449310742796513, 55.90570709850374 ], [ 26.485769076881354, 55.892889715188176 ], [ 26.48748993591181, 55.868721074617895 ], [ 26.490300946831212, 55.85326051546042 ], [ 26.504356000528958, 55.840610967222347 ], [ 26.51841105512608, 55.826555912625224 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-024", "NAME_1": "Dagdas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 28.051100037936408, 56.140665997038127 ], [ 28.023798055000015, 56.12964996400008 ], [ 27.981009969000098, 56.118022767000028 ], [ 27.939668823000147, 56.113061829000074 ], [ 27.927059774000043, 56.109366964000074 ], [ 27.911453491000088, 56.100246074 ], [ 27.901531617000103, 56.089342346000038 ], [ 27.892746622000118, 56.077095032 ], [ 27.880654337000124, 56.063865866000114 ], [ 27.812544800000126, 56.03451365100004 ], [ 27.781228882000107, 56.016375224000015 ], [ 27.776991414000065, 55.99239736 ], [ 27.76006402003836, 55.975416227688804 ], [ 27.724729153427688, 55.99520500250884 ], [ 27.680720178893125, 56.008148818812913 ], [ 27.654832547184299, 56.021092635116986 ], [ 27.641888730880225, 56.015915108595379 ], [ 27.644477494141029, 55.987438713625693 ], [ 27.618589862432202, 55.990027476886496 ], [ 27.571992124636836, 55.997793765769643 ], [ 27.460675306220367, 56.036625214681862 ], [ 27.414077568425, 56.036625214681862 ], [ 27.38560117345537, 56.021092635116986 ], [ 27.367479830629634, 56.023681398377789 ], [ 27.3752461204121, 56.057335319869082 ], [ 27.370068593890494, 56.080634189216426 ], [ 27.315704566312661, 56.080634189216426 ], [ 27.263929301995688, 56.072867899433959 ], [ 27.240630433547665, 56.111699347446915 ], [ 27.307938276530194, 56.124643163750989 ], [ 27.339003435660004, 56.140175742416545 ], [ 27.331237145877537, 56.160885848503085 ], [ 27.300171987647104, 56.181595953690305 ], [ 27.295936313909749, 56.203029690267954 ], [ 27.339086134617389, 56.21026439078895 ], [ 27.412001580608433, 56.207163805365326 ], [ 27.420683221053764, 56.210574449151466 ], [ 27.447865024851012, 56.209385890746205 ], [ 27.44068200027408, 56.223674425534284 ], [ 27.447244907226661, 56.229901434803367 ], [ 27.466933628084462, 56.233467109119772 ], [ 27.488947788009966, 56.235017401831612 ], [ 27.508998244073666, 56.241115220790789 ], [ 27.523570997903221, 56.24824656852428 ], [ 27.528066847307116, 56.257393296963073 ], [ 27.535043166309038, 56.261114000011048 ], [ 27.548220656158321, 56.24824656852428 ], [ 27.551631300843837, 56.245481878985515 ], [ 27.568116081691812, 56.24230377919605 ], [ 27.651573521001183, 56.249745185292056 ], [ 27.667593214755016, 56.240236720748044 ], [ 27.687126905981927, 56.225095527036899 ], [ 27.701854689442371, 56.219488634492848 ], [ 27.722473586286981, 56.20664704052848 ], [ 27.743919305431575, 56.199774075213384 ], [ 27.778490837582069, 56.195639960116011 ], [ 27.810943638038452, 56.196260077740362 ], [ 27.822415806444269, 56.185666409377291 ], [ 27.838435500198159, 56.182307441535158 ], [ 27.852853224396767, 56.181945706329259 ], [ 27.88757978707747, 56.186648261308164 ], [ 27.898483513803114, 56.183237617522025 ], [ 27.913056267632612, 56.18370270371679 ], [ 28.00131961380913, 56.203288071787028 ], [ 28.020904981879369, 56.209644273164656 ], [ 28.031446974298433, 56.214476020252107 ], [ 28.039818556381249, 56.215690416179712 ], [ 28.048035108833176, 56.214398504987003 ], [ 28.052685987868017, 56.211065375566591 ], [ 28.056096632553533, 56.206957098890996 ], [ 28.06126427642522, 56.20354645420548 ], [ 28.0650883322607, 56.203288071787028 ], [ 28.070411003964637, 56.208507392502156 ], [ 28.077542351698128, 56.196725164834447 ], [ 28.06260786266273, 56.182100735060828 ], [ 28.04369428906017, 56.158019518485958 ], [ 28.047259963376575, 56.150888169853147 ], [ 28.050928988681846, 56.14112132379006 ], [ 28.051100037936408, 56.140665997038127 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-047", "NAME_1": "Kraslavas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 27.76006402003836, 55.975416227688804 ], [ 27.74443526200011, 55.959737854000124 ], [ 27.645009806000104, 55.922840881000084 ], [ 27.617156209000115, 55.878554179000062 ], [ 27.610128214000014, 55.830960185000023 ], [ 27.601498251000066, 55.809617819000024 ], [ 27.592713256000081, 55.794244080000041 ], [ 27.564601278000055, 55.792228699000091 ], [ 27.438820842000069, 55.798739929000064 ], [ 27.405851277000124, 55.804346823000103 ], [ 27.374587036000037, 55.814837138000044 ], [ 27.349627319000035, 55.831218567000107 ], [ 27.329163452000074, 55.817575990000094 ], [ 27.282447957000073, 55.791866964000107 ], [ 27.263017619000095, 55.787216085000054 ], [ 27.235525757000033, 55.795846050000094 ], [ 27.173203980000096, 55.825740865000014 ], [ 27.151448201000079, 55.832458802000033 ], [ 27.110778849000042, 55.836282858000075 ], [ 26.981071004000086, 55.826877747000125 ], [ 26.979425814849435, 55.826290963357224 ], [ 26.979056430909566, 55.826721910387846 ], [ 26.97874637164773, 55.827083644694426 ], [ 26.979986606896375, 55.838917548306199 ], [ 26.981536899608216, 55.844653632059419 ], [ 26.980606723621406, 55.855350654109372 ], [ 26.97797122619113, 55.864213161707994 ], [ 26.934201287859139, 55.873902493405296 ], [ 26.934356316590709, 55.892764391063793 ], [ 26.937818638119609, 55.90387482426371 ], [ 26.946345248934051, 55.911316230359716 ], [ 26.954561802285355, 55.927594306532001 ], [ 26.935596550940033, 55.932193508723401 ], [ 26.944484897859752, 55.941650296424029 ], [ 26.955647007003734, 55.950280260025977 ], [ 26.947120396189291, 55.960072944510728 ], [ 26.943503045029502, 55.966790880194935 ], [ 26.932650995147299, 56.003300279584209 ], [ 26.967739292134581, 56.007847804932226 ], [ 26.999875454788366, 55.990027476886496 ], [ 27.041295666062126, 55.982261187104086 ], [ 27.103425983422369, 55.987438713625693 ], [ 27.147434957956932, 55.98484995036489 ], [ 27.194032695752298, 56.010737582073716 ], [ 27.188855169230635, 56.054746556608279 ], [ 27.263929301995688, 56.072867899433959 ], [ 27.315704566312661, 56.080634189216426 ], [ 27.370068593890494, 56.080634189216426 ], [ 27.3752461204121, 56.057335319869082 ], [ 27.367479830629634, 56.023681398377789 ], [ 27.38560117345537, 56.021092635116986 ], [ 27.414077568425, 56.036625214681862 ], [ 27.460675306220367, 56.036625214681862 ], [ 27.571992124636836, 55.997793765769643 ], [ 27.618589862432202, 55.990027476886496 ], [ 27.644477494141029, 55.987438713625693 ], [ 27.641888730880225, 56.015915108595379 ], [ 27.654832547184299, 56.021092635116986 ], [ 27.680720178893125, 56.008148818812913 ], [ 27.724729153427688, 55.99520500250884 ], [ 27.76006402003836, 55.975416227688804 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-066", "NAME_1": "Nicas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 20.971039259000065, 56.259670315000051 ], [ 20.98023522200009, 56.279282945000034 ], [ 20.982676629000082, 56.290757554000038 ], [ 20.982676629000082, 56.301459052000041 ], [ 20.981455925000091, 56.310492255000042 ], [ 20.970957879000082, 56.349839585000041 ], [ 20.968597852000073, 56.369818427000041 ], [ 20.970550977000073, 56.38898346600007 ], [ 20.979014519000089, 56.404364325000074 ], [ 20.992523634000065, 56.417914130000042 ], [ 20.998383009000065, 56.425685940000051 ], [ 21.003184441000087, 56.434800523000035 ], [ 21.005381707000083, 56.445868231000077 ], [ 21.019539950008664, 56.447081045853565 ], [ 21.022017119994075, 56.456989723097195 ], [ 21.02399885526296, 56.4713573046958 ], [ 21.035817904772443, 56.473944403311521 ], [ 21.04468834700009, 56.462103583000044 ], [ 21.030528191000087, 56.448431708000044 ], [ 21.037445509000065, 56.444647528000075 ], [ 21.04468834700009, 56.442206122000073 ], [ 21.04468834700009, 56.427964585000041 ], [ 21.04468834700009, 56.421128648000035 ], [ 21.030528191000087, 56.408107815000051 ], [ 21.053396030000044, 56.389960028000075 ], [ 21.061778191000087, 56.38703034100007 ], [ 21.070160352000073, 56.389349677000041 ], [ 21.077159050000091, 56.395209052000041 ], [ 21.07976321700005, 56.403062242000033 ], [ 21.068614129000082, 56.424058335000041 ], [ 21.066661004000082, 56.441839911000045 ], [ 21.06812584700009, 56.458807684000078 ], [ 21.072113477000073, 56.469549872000073 ], [ 21.067637566000087, 56.476385809000078 ], [ 21.063243035000085, 56.493963934000078 ], [ 21.128274935339959, 56.498784252890914 ], [ 21.147462973037761, 56.430560118554581 ], [ 21.211423098697026, 56.432692123342804 ], [ 21.226347127717759, 56.351675963874584 ], [ 21.179443035867394, 56.355939972551653 ], [ 21.183707044544462, 56.323959909722021 ], [ 21.179443035867394, 56.28771583821532 ], [ 21.16451900684666, 56.264263792739825 ], [ 21.109086897642214, 56.219491704778306 ], [ 21.085634852166663, 56.228019721233125 ], [ 21.083502847378497, 56.191775649726424 ], [ 21.083502847378497, 56.166191600362026 ], [ 21.055786793225934, 56.168323604250929 ], [ 21.034466751639286, 56.266395796628672 ], [ 20.971039259000065, 56.259670315000051 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-LPX", "NAME_1": "Liepāja" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 21.005381707000083, 56.445868231000077 ], [ 21.00554446700005, 56.465521552000041 ], [ 21.010590040000068, 56.475734768000052 ], [ 21.00326582100007, 56.492580471000053 ], [ 21.000498894000089, 56.510646877000056 ], [ 21.006358269000089, 56.519964911000045 ], [ 21.024261915000068, 56.510484117000033 ], [ 21.030528191000087, 56.500148830000057 ], [ 21.035817904772443, 56.473944403311521 ], [ 21.02399885526296, 56.4713573046958 ], [ 21.022017119994075, 56.456989723097195 ], [ 21.019539950008664, 56.447081045853565 ], [ 21.005381707000083, 56.445868231000077 ] ] ], [ [ [ 21.052907747694405, 56.511053778209259 ], [ 21.048106316000087, 56.515611070000034 ], [ 21.030528191000087, 56.524155992000033 ], [ 21.019541863000086, 56.527085679000038 ], [ 21.010508660000085, 56.527777411000045 ], [ 21.003103061000047, 56.530015367000033 ], [ 20.996348504000082, 56.537827867000033 ], [ 20.992198113000086, 56.548895575000074 ], [ 20.995127800000091, 56.55337148600006 ], [ 21.000336134000065, 56.557684637000079 ], [ 21.010508660000085, 56.598700262000079 ], [ 21.020642330455665, 56.615046011826529 ], [ 21.067247716508916, 56.605743150925662 ], [ 21.077412097989907, 56.562825341816051 ], [ 21.093761415756717, 56.568770547622648 ], [ 21.103220320461389, 56.532770547622647 ], [ 21.072706622012959, 56.523284245971126 ], [ 21.052907747694405, 56.511053778209259 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-032", "NAME_1": "Grobinas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.063243035000085, 56.493963934000078 ], [ 21.05836022200009, 56.503648179000038 ], [ 21.052907747694405, 56.511053778209259 ], [ 21.072706622012959, 56.523284245971126 ], [ 21.103220320461389, 56.532770547622647 ], [ 21.093761415756717, 56.568770547622648 ], [ 21.077412097989907, 56.562825341816051 ], [ 21.067247716508916, 56.605743150925662 ], [ 21.020642330455665, 56.615046011826529 ], [ 21.046153190717177, 56.656195380312511 ], [ 21.05791879711478, 56.643760537119078 ], [ 21.121878922774044, 56.63523252066426 ], [ 21.153858985603677, 56.682136612514626 ], [ 21.211423098697026, 56.645892541907244 ], [ 21.258327190547391, 56.656552562250909 ], [ 21.281779236922205, 56.611780474289446 ], [ 21.254063182769642, 56.588328428813895 ], [ 21.256195186658545, 56.530764315720546 ], [ 21.347871366470372, 56.543556340852433 ], [ 21.354267379036287, 56.503048261567983 ], [ 21.384115437977073, 56.490256236436153 ], [ 21.386247441865919, 56.464672186172436 ], [ 21.437415542393353, 56.407108073079087 ], [ 21.416095500806705, 56.353807968662807 ], [ 21.379851429300004, 56.32822391839909 ], [ 21.26259119922446, 56.326091913610924 ], [ 21.226347127717759, 56.351675963874584 ], [ 21.211423098697026, 56.432692123342804 ], [ 21.147462973037761, 56.430560118554581 ], [ 21.128274935339959, 56.498784252890914 ], [ 21.063243035000085, 56.493963934000078 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-071", "NAME_1": "Pavilostas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.046153190717177, 56.656195380312511 ], [ 21.05836022200009, 56.688666083000044 ], [ 21.065196160000085, 56.774318752000056 ], [ 21.061208530000044, 56.794134833000044 ], [ 21.054209832000083, 56.81195709800005 ], [ 21.052744988000086, 56.828924872000073 ], [ 21.065196160000085, 56.84634023600006 ], [ 21.147227410000085, 56.87641022300005 ], [ 21.156748894000089, 56.885565497000073 ], [ 21.222911004000082, 56.907700914000031 ], [ 21.240977410000085, 56.91828034100007 ], [ 21.277598504000082, 56.949123440000051 ], [ 21.287771030000044, 56.955511786000045 ], [ 21.30014082100007, 56.959540106000077 ], [ 21.328187478569248, 56.97362864854324 ], [ 21.331752556635138, 56.97362864854324 ], [ 21.362603386636977, 56.966704007284079 ], [ 21.384772577092747, 56.956523749171652 ], [ 21.39583133344928, 56.942416083335559 ], [ 21.391490512776954, 56.934483750824427 ], [ 21.397226597429494, 56.929393622217844 ], [ 21.406063266606452, 56.923450832889614 ], [ 21.447301060295672, 56.912082018170565 ], [ 21.493396436796104, 56.903813787975935 ], [ 21.473707716837623, 56.887587389546354 ], [ 21.467971633084403, 56.878905748201703 ], [ 21.436449008614829, 56.867588609426775 ], [ 21.439547546282199, 56.83990492277394 ], [ 21.40969948824079, 56.831376905419802 ], [ 21.345739362581526, 56.820716885076138 ], [ 21.320155312317809, 56.807924859944308 ], [ 21.324419320994878, 56.758888763305777 ], [ 21.31589130364074, 56.739700725607975 ], [ 21.292439258165189, 56.756756759416874 ], [ 21.260459195335557, 56.739700725607975 ], [ 21.273251220467444, 56.707720662778343 ], [ 21.288175249488177, 56.682136612514626 ], [ 21.258327190547391, 56.656552562250909 ], [ 21.211423098697026, 56.645892541907244 ], [ 21.153858985603677, 56.682136612514626 ], [ 21.121878922774044, 56.63523252066426 ], [ 21.05791879711478, 56.643760537119078 ], [ 21.046153190717177, 56.656195380312511 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-VEN", "NAME_1": "Ventspils" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.328187478569248, 56.97362864854324 ], [ 21.360118035000085, 56.98969147300005 ], [ 21.38249759200005, 57.008937893000052 ], [ 21.401621941000087, 57.037502346000053 ], [ 21.413584832000083, 57.073187567000048 ], [ 21.414805535000085, 57.113836981000077 ], [ 21.41187584700009, 57.12445709800005 ], [ 21.401052280000044, 57.151312567000048 ], [ 21.403168165000068, 57.162054755000042 ], [ 21.412608269000089, 57.176214911000045 ], [ 21.414805535000085, 57.184881903000075 ], [ 21.412608269000089, 57.250067450000074 ], [ 21.414805535000085, 57.270900783000059 ], [ 21.421397332000083, 57.288723049000055 ], [ 21.433604363000086, 57.306463934000078 ], [ 21.449473504000082, 57.320013739000046 ], [ 21.46656334700009, 57.325506903000075 ], [ 21.48023522200009, 57.333644924000055 ], [ 21.511533772406381, 57.378657806634251 ], [ 21.527651608135216, 57.358248103966787 ], [ 21.541985133307264, 57.340963559620548 ], [ 21.565593292096764, 57.342228281609891 ], [ 21.591730896663535, 57.360777549744114 ], [ 21.626367638655609, 57.35455976751922 ], [ 21.621475510186656, 57.389416618582061 ], [ 21.674789213251586, 57.400881341500678 ], [ 21.642327994241498, 57.45695071840089 ], [ 21.632631786327863, 57.466646927213901 ], [ 21.621669658996623, 57.473236291939322 ], [ 21.699229363000086, 57.55532461100006 ], [ 21.729665561000047, 57.573797919000071 ], [ 21.771657748000052, 57.586127020000049 ], [ 21.955902540000068, 57.592962958000044 ], [ 21.999278191000087, 57.600327867000033 ], [ 22.194509311000047, 57.657619533000059 ], [ 22.206427850165142, 57.626870428927134 ], [ 22.212939081173658, 57.620927638699527 ], [ 22.223791131055862, 57.623149725879102 ], [ 22.235625033768258, 57.619739081193586 ], [ 22.247097202174132, 57.599585273241757 ], [ 22.245391879831345, 57.588319811310214 ], [ 22.250352817228702, 57.576046658126756 ], [ 22.25903445767409, 57.564290269780088 ], [ 22.268491245374662, 57.55545359970381 ], [ 22.272056918791748, 57.549097399225559 ], [ 22.274227329127939, 57.517316393236911 ], [ 22.271901890060178, 57.507239487911988 ], [ 22.203792351835546, 57.483907579271317 ], [ 22.189529657267826, 57.476388657910206 ], [ 22.174491815444924, 57.471892809405574 ], [ 22.177282341606769, 57.465123195978663 ], [ 22.177437372136978, 57.459128729806991 ], [ 22.166688674142961, 57.45101553014257 ], [ 22.137853223947104, 57.437527981031451 ], [ 22.077960239073775, 57.423161932776964 ], [ 22.151650832320058, 57.404610094380303 ], [ 22.186429070944826, 57.401587023322463 ], [ 22.244926791837941, 57.407090563079009 ], [ 22.259573101217654, 57.397945550546694 ], [ 22.276707797826589, 57.387246813489639 ], [ 22.28213382321735, 57.381355699206154 ], [ 22.286009555896271, 57.351150825250329 ], [ 22.286009555896271, 57.334278468976152 ], [ 22.294897901916613, 57.321462714332768 ], [ 22.308850539021137, 57.288854885144815 ], [ 22.304199659986296, 57.286477770132933 ], [ 22.30140913292513, 57.276452542550771 ], [ 22.297068312252804, 57.271129869048195 ], [ 22.273762241134477, 57.265032050089019 ], [ 22.233092889125544, 57.243379625369414 ], [ 22.194025505772458, 57.212373765736686 ], [ 22.188134393287612, 57.198731187893998 ], [ 22.190304802724427, 57.195320543208481 ], [ 22.204102411097381, 57.19082469290521 ], [ 22.206427850165142, 57.177853909530256 ], [ 22.199606560794109, 57.166123358705988 ], [ 22.196350945739539, 57.157545071048162 ], [ 22.195575799383619, 57.153385118428446 ], [ 22.195110711390214, 57.149070136177841 ], [ 22.195265741021103, 57.132094428015421 ], [ 22.194335565034294, 57.128089505026594 ], [ 22.192475213060618, 57.124575507553629 ], [ 22.172734816258753, 57.116565659777336 ], [ 22.095168491232869, 57.101631170741882 ], [ 22.075324740744179, 57.101992905947839 ], [ 22.015276727139224, 57.113723455872787 ], [ 21.996466506324168, 57.107367255394479 ], [ 21.951973096681058, 57.098427232530753 ], [ 21.936573520551519, 57.097238675024812 ], [ 21.86009240114339, 57.099305732573498 ], [ 21.849860467086842, 57.098427232530753 ], [ 21.839938592292185, 57.093001207139991 ], [ 21.82190351693373, 57.085275580203813 ], [ 21.783094516898416, 57.085198065838028 ], [ 21.789502394220108, 57.095274970263631 ], [ 21.789812452582623, 57.099822496510967 ], [ 21.789192335857592, 57.104111640339909 ], [ 21.766971470357078, 57.107057197031963 ], [ 21.711574333988324, 57.116849881516771 ], [ 21.692350702023248, 57.114214383187232 ], [ 21.664083692608301, 57.116307278258262 ], [ 21.653851760350449, 57.116152249526692 ], [ 21.641449415957766, 57.114214383187232 ], [ 21.626256545403237, 57.104059964395788 ], [ 21.593028598590934, 57.087265123386715 ], [ 21.573804965726595, 57.085611476988049 ], [ 21.539026727101771, 57.07057363516509 ], [ 21.506160516394687, 57.075612087827551 ], [ 21.503008254127622, 57.058274645358551 ], [ 21.489210645754667, 57.051014106415835 ], [ 21.484869825981662, 57.028509020075205 ], [ 21.473552687206734, 57.0129544134154 ], [ 21.474947951187005, 56.986444404085944 ], [ 21.472002393595574, 56.971354885419601 ], [ 21.454329054342395, 56.960296129063067 ], [ 21.446680941772001, 56.949650783856555 ], [ 21.39583133344928, 56.942416083335559 ], [ 21.384772577092747, 56.956523749171652 ], [ 21.362603386636977, 56.966704007284079 ], [ 21.331752556635138, 56.97362864854324 ], [ 21.328187478569248, 56.97362864854324 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-VEN", "NAME_1": "Ventspils" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.511533772406381, 57.378657806634251 ], [ 21.517751498000052, 57.387600002000056 ], [ 21.589121941000087, 57.438788153000075 ], [ 21.621669658996623, 57.473236291939322 ], [ 21.632631786327863, 57.466646927213901 ], [ 21.642327994241498, 57.45695071840089 ], [ 21.674789213251586, 57.400881341500678 ], [ 21.621475510186656, 57.389416618582061 ], [ 21.626367638655609, 57.35455976751922 ], [ 21.591730896663535, 57.360777549744114 ], [ 21.565593292096764, 57.342228281609891 ], [ 21.541985133307264, 57.340963559620548 ], [ 21.527651608135216, 57.358248103966787 ], [ 21.511533772406381, 57.378657806634251 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-027", "NAME_1": "Dundagas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 22.194509311000047, 57.657619533000059 ], [ 22.48373457100007, 57.74249909100007 ], [ 22.526133660000085, 57.749660549000055 ], [ 22.549082879000082, 57.75063711100006 ], [ 22.56031334700009, 57.752752997000073 ], [ 22.572601759000065, 57.756822007000039 ], [ 22.585785352000073, 57.759711005000042 ], [ 22.600271030000044, 57.758042710000041 ], [ 22.610362175000091, 57.754624742000033 ], [ 22.610118035000085, 57.753485419000071 ], [ 22.604991082000083, 57.751044012000079 ], [ 22.600271030000044, 57.743841864000046 ], [ 22.590830925000091, 57.706122137000079 ], [ 22.58716881558837, 57.66498444187846 ], [ 22.567978247198312, 57.674198927038844 ], [ 22.570264505502507, 57.617042483823525 ], [ 22.609130886780974, 57.578176102545058 ], [ 22.61141714418585, 57.541595979570786 ], [ 22.625134690413631, 57.502729598292319 ], [ 22.54740192785664, 57.498157082583248 ], [ 22.503963031768478, 57.461576959608976 ], [ 22.476527938413597, 57.413565546912423 ], [ 22.423944010907348, 57.420424320026314 ], [ 22.380505114819186, 57.411279289507604 ], [ 22.34849750665461, 57.411279289507604 ], [ 22.325634929908063, 57.434141866254095 ], [ 22.282196032920581, 57.427283093140204 ], [ 22.259573101217654, 57.397945550546694 ], [ 22.244926791837941, 57.407090563079009 ], [ 22.186429070944826, 57.401587023322463 ], [ 22.151650832320058, 57.404610094380303 ], [ 22.077960239073775, 57.423161932776964 ], [ 22.137853223947104, 57.437527981031451 ], [ 22.166688674142961, 57.45101553014257 ], [ 22.177437372136978, 57.459128729806991 ], [ 22.177282341606769, 57.465123195978663 ], [ 22.174491815444924, 57.471892809405574 ], [ 22.189529657267826, 57.476388657910206 ], [ 22.203792351835546, 57.483907579271317 ], [ 22.271901890060178, 57.507239487911988 ], [ 22.274227329127939, 57.517316393236911 ], [ 22.272056918791748, 57.549097399225559 ], [ 22.268491245374662, 57.55545359970381 ], [ 22.25903445767409, 57.564290269780088 ], [ 22.250352817228702, 57.576046658126756 ], [ 22.245391879831345, 57.588319811310214 ], [ 22.247097202174132, 57.599585273241757 ], [ 22.235625033768258, 57.619739081193586 ], [ 22.223791131055862, 57.623149725879102 ], [ 22.212939081173658, 57.620927638699527 ], [ 22.206427850165142, 57.626870428927134 ], [ 22.194509311000047, 57.657619533000059 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-079", "NAME_1": "Rojas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 22.58716881558837, 57.66498444187846 ], [ 22.590993686000047, 57.644761460000041 ], [ 22.600759311000047, 57.630113023000035 ], [ 22.656097852000073, 57.585760809000078 ], [ 22.878916863000086, 57.481268622000073 ], [ 22.950368686000047, 57.432806708000044 ], [ 22.994593607347898, 57.411893115396275 ], [ 22.949783286869149, 57.402134258988838 ], [ 22.933779482337229, 57.376985423938152 ], [ 22.894913101058762, 57.374699165633956 ], [ 22.846901689261529, 57.388416712761057 ], [ 22.824039111615718, 57.408993032102728 ], [ 22.741733834249032, 57.459290701304781 ], [ 22.705153710375441, 57.43642812455829 ], [ 22.677718617919879, 57.457004443899962 ], [ 22.693722422451799, 57.482153278950648 ], [ 22.625134690413631, 57.502729598292319 ], [ 22.61141714418585, 57.541595979570786 ], [ 22.609130886780974, 57.578176102545058 ], [ 22.570264505502507, 57.617042483823525 ], [ 22.567978247198312, 57.674198927038844 ], [ 22.58716881558837, 57.66498444187846 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-097", "NAME_1": "Talsi" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 22.994593607347898, 57.411893115396275 ], [ 23.031423372590552, 57.394476629792621 ], [ 23.006939729185149, 57.367840392520066 ], [ 22.968073347906682, 57.351836588887465 ], [ 22.920061936109448, 57.333546526950613 ], [ 22.954355801678901, 57.296966403976342 ], [ 23.018371018008054, 57.290107630862451 ], [ 23.054951141881702, 57.283248856849241 ], [ 23.061809914995536, 57.258100022697874 ], [ 23.080379673283289, 57.238470363916122 ], [ 23.039865350005869, 57.210203356299814 ], [ 22.977491896433833, 57.187052313913114 ], [ 22.967259963276661, 57.183538316440149 ], [ 22.948914828656427, 57.167880356992839 ], [ 22.946744419219556, 57.160335598109327 ], [ 22.941473422560364, 57.152454942441636 ], [ 22.930931431040676, 57.144574286773889 ], [ 22.911242710182933, 57.137184557521266 ], [ 22.831299269245847, 57.140078437369937 ], [ 22.80804487497096, 57.136616115841036 ], [ 22.801998731955905, 57.131345120081221 ], [ 22.793265414667133, 57.126022447477965 ], [ 22.76086429195351, 57.112328192791836 ], [ 22.669603713140816, 57.097703762118897 ], [ 22.6415434102002, 57.094732367904442 ], [ 22.649449904289611, 57.041660672402088 ], [ 22.635807326446923, 57.015848294163391 ], [ 22.591417271389957, 57.022385361794989 ], [ 22.559584587658549, 57.008381048746401 ], [ 22.508218215398301, 57.013832913458145 ], [ 22.480002882826739, 57.017760322081187 ], [ 22.412668490958083, 57.014763089445012 ], [ 22.382386101737211, 57.019672349998928 ], [ 22.372619255674067, 57.035769558118602 ], [ 22.362697380879411, 57.042409980336288 ], [ 22.35959679455641, 57.051453355987576 ], [ 22.359286737093214, 57.056465969328997 ], [ 22.363007440141246, 57.078738512572272 ], [ 22.354170770064968, 57.102664700415573 ], [ 22.348899774305096, 57.11010610651158 ], [ 22.327609083892071, 57.120415554034537 ], [ 22.297998488239614, 57.128761297695689 ], [ 22.262755160722065, 57.145013536345573 ], [ 22.249887730134617, 57.155271307924465 ], [ 22.24182620641426, 57.166691800386275 ], [ 22.234694857781449, 57.170541693744156 ], [ 22.206427850165142, 57.177853909530256 ], [ 22.204102411097381, 57.19082469290521 ], [ 22.190304802724427, 57.195320543208481 ], [ 22.188134393287612, 57.198731187893998 ], [ 22.194025505772458, 57.212373765736686 ], [ 22.233092889125544, 57.243379625369414 ], [ 22.273762241134477, 57.265032050089019 ], [ 22.297068312252804, 57.271129869048195 ], [ 22.30140913292513, 57.276452542550771 ], [ 22.304199659986296, 57.286477770132933 ], [ 22.308850539021137, 57.288854885144815 ], [ 22.294897901916613, 57.321462714332768 ], [ 22.286009555896271, 57.334278468976152 ], [ 22.286009555896271, 57.351150825250329 ], [ 22.28213382321735, 57.381355699206154 ], [ 22.276707797826589, 57.387246813489639 ], [ 22.259573101217654, 57.397945550546694 ], [ 22.282196032920581, 57.427283093140204 ], [ 22.325634929908063, 57.434141866254095 ], [ 22.34849750665461, 57.411279289507604 ], [ 22.380505114819186, 57.411279289507604 ], [ 22.423944010907348, 57.420424320026314 ], [ 22.476527938413597, 57.413565546912423 ], [ 22.503963031768478, 57.461576959608976 ], [ 22.54740192785664, 57.498157082583248 ], [ 22.625134690413631, 57.502729598292319 ], [ 22.693722422451799, 57.482153278950648 ], [ 22.677718617919879, 57.457004443899962 ], [ 22.705153710375441, 57.43642812455829 ], [ 22.741733834249032, 57.459290701304781 ], [ 22.824039111615718, 57.408993032102728 ], [ 22.846901689261529, 57.388416712761057 ], [ 22.894913101058762, 57.374699165633956 ], [ 22.933779482337229, 57.376985423938152 ], [ 22.949783286869149, 57.402134258988838 ], [ 22.994593607347898, 57.411893115396275 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-063", "NAME_1": "Mersraga" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.031423372590552, 57.394476629792621 ], [ 23.08334394600007, 57.378241278000075 ], [ 23.117523634000065, 57.373928127000056 ], [ 23.13021894600007, 57.370794989000046 ], [ 23.133148634000065, 57.362982489000046 ], [ 23.133555535000085, 57.353094794000071 ], [ 23.13803144600007, 57.343166408000059 ], [ 23.160151242985478, 57.318606927967323 ], [ 23.128025344294201, 57.312315985894031 ], [ 23.120842318817949, 57.305184638160483 ], [ 23.114641147970588, 57.29335073544803 ], [ 23.112780795996912, 57.265290432507413 ], [ 23.080379673283289, 57.238470363916122 ], [ 23.061809914995536, 57.258100022697874 ], [ 23.054951141881702, 57.283248856849241 ], [ 23.018371018008054, 57.290107630862451 ], [ 22.954355801678901, 57.296966403976342 ], [ 22.920061936109448, 57.333546526950613 ], [ 22.968073347906682, 57.351836588887465 ], [ 23.006939729185149, 57.367840392520066 ], [ 23.031423372590552, 57.394476629792621 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-029", "NAME_1": "Engures" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.160151242985478, 57.318606927967323 ], [ 23.164561394000089, 57.313666083000044 ], [ 23.174571160000085, 57.297349351000037 ], [ 23.182383660000085, 57.27765534100007 ], [ 23.190196160000085, 57.24249909100007 ], [ 23.198741082000083, 57.224188544000071 ], [ 23.213552280000044, 57.21625397300005 ], [ 23.22242272200009, 57.207017320000034 ], [ 23.250498894000089, 57.114447333000044 ], [ 23.260915561000047, 57.098944403000075 ], [ 23.274912957000083, 57.092718817000048 ], [ 23.29265384200005, 57.088934637000079 ], [ 23.340098504000082, 57.058579820000034 ], [ 23.422862175000091, 57.040228583000044 ], [ 23.508555535000085, 57.031236070000034 ], [ 23.52084394600007, 57.025580145000049 ], [ 23.56967207100007, 56.986273505000042 ], [ 23.578603263929494, 56.982092082883298 ], [ 23.575853306185138, 56.980527452280057 ], [ 23.499785597027653, 56.961381333781503 ], [ 23.483817580117204, 56.949650783856555 ], [ 23.473430617329086, 56.943475450531594 ], [ 23.475135938772553, 56.940684923470428 ], [ 23.477151320377118, 56.936473294007271 ], [ 23.442001124852027, 56.926539013064996 ], [ 23.372275396991938, 56.910448460827752 ], [ 23.277519921407247, 56.915811977940393 ], [ 23.200642837696762, 56.930114691439826 ], [ 23.148795501710993, 56.921175495952355 ], [ 23.141644144961276, 56.935478208552468 ], [ 23.177400928709858, 56.955144439164485 ], [ 23.197067159321932, 56.967659313926163 ], [ 23.168461732323067, 56.985537705800482 ], [ 23.177400928709858, 57.012355293162216 ], [ 23.21315771155912, 57.039172880524006 ], [ 23.231036103433382, 57.06599046788574 ], [ 23.204218516071649, 57.105322929109889 ], [ 23.150583341348124, 57.123201320984151 ], [ 23.113038718861787, 57.137504034483584 ], [ 23.10052384410011, 57.155382425458527 ], [ 23.120190075611504, 57.171472978595034 ], [ 23.132704949473805, 57.209017601081371 ], [ 23.129129271098975, 57.242986545192878 ], [ 23.112780795996912, 57.265290432507413 ], [ 23.114641147970588, 57.29335073544803 ], [ 23.120842318817949, 57.305184638160483 ], [ 23.128025344294201, 57.312315985894031 ], [ 23.160151242985478, 57.318606927967323 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-JUR", "NAME_1": "Jurmala" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.578603263929494, 56.982092082883298 ], [ 23.585134311000047, 56.979071356000077 ], [ 23.632009311000047, 56.970933335000041 ], [ 23.695160352000073, 56.967271226000037 ], [ 23.866058790000068, 56.990179755000042 ], [ 23.926931186000047, 57.006333726000037 ], [ 23.92869998531603, 57.005900580047694 ], [ 23.934281040337737, 56.996986396504951 ], [ 23.95445041645354, 56.991383791928399 ], [ 23.937232573024801, 56.973022831038804 ], [ 23.903263628913351, 56.962295795914201 ], [ 23.863931166789882, 56.955144439164485 ], [ 23.801356796578887, 56.9497809220519 ], [ 23.779902726329738, 56.956932278801617 ], [ 23.76738785246738, 56.942629565302184 ], [ 23.706601320994139, 56.931902530177581 ], [ 23.672632376882689, 56.928326851802751 ], [ 23.638663432771182, 56.928326851802751 ], [ 23.613633684147203, 56.931902530177581 ], [ 23.590391775160299, 56.92296333469011 ], [ 23.549271474299076, 56.924751173427865 ], [ 23.492034132569131, 56.934638780455316 ], [ 23.477151320377118, 56.936473294007271 ], [ 23.475135938772553, 56.940684923470428 ], [ 23.473430617329086, 56.943475450531594 ], [ 23.483817580117204, 56.949650783856555 ], [ 23.499785597027653, 56.961381333781503 ], [ 23.575853306185138, 56.980527452280057 ], [ 23.578603263929494, 56.982092082883298 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-RIX", "NAME_1": "Riga" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.926931186000047, 57.006333726000037 ], [ 23.95289147200009, 57.013251044000071 ], [ 23.991221550000091, 57.031236070000034 ], [ 24.009287957000083, 57.045599677000041 ], [ 24.021983269000089, 57.059027411000045 ], [ 24.035655144000089, 57.06899648600006 ], [ 24.074554884000065, 57.074937242000033 ], [ 24.113025617338337, 57.0887232661658 ], [ 24.15168379117398, 57.055587470185571 ], [ 24.162383007569701, 57.052823973147838 ], [ 24.181294385927174, 57.047939358514554 ], [ 24.224444206634814, 57.021636053860789 ], [ 24.249920688988595, 57.012644355052942 ], [ 24.274415316713487, 57.006365668041099 ], [ 24.287902865824606, 56.999880276353622 ], [ 24.302527297396864, 56.99099193033328 ], [ 24.320200636650043, 56.96902944635184 ], [ 24.299064975867907, 56.955541897240721 ], [ 24.258447299803038, 56.946007595174365 ], [ 24.246510044303079, 56.940969143411223 ], [ 24.234676140691306, 56.930401313469815 ], [ 24.236691522295928, 56.904123847237713 ], [ 24.258718295213157, 56.872992254289102 ], [ 24.197004022217811, 56.882058010468768 ], [ 24.155404494222012, 56.902392687372583 ], [ 24.132718539828716, 56.898361925062773 ], [ 24.112254672615052, 56.892625841309496 ], [ 24.104038120163125, 56.883608303180608 ], [ 24.099387241128284, 56.878492337051682 ], [ 24.088146223669241, 56.876134365908229 ], [ 24.070810174250141, 56.872497870880011 ], [ 24.066252713192171, 56.886115998854223 ], [ 24.062128533804753, 56.898439440327877 ], [ 24.040269402610818, 56.9100407990436 ], [ 24.026575147924746, 56.919626777054077 ], [ 24.002390577662993, 56.923709215308008 ], [ 23.97148807081777, 56.933243517374422 ], [ 23.942652622420553, 56.938669541865863 ], [ 23.94916385342907, 56.946782742429605 ], [ 23.988592970189416, 56.964688626578834 ], [ 23.994174025211066, 56.973163561449155 ], [ 24.000995313682779, 56.979261380408332 ], [ 23.992778761230852, 56.984532376168204 ], [ 23.967767367769795, 56.987684638435269 ], [ 23.95445041645354, 56.991383791928399 ], [ 23.934281040337737, 56.996986396504951 ], [ 23.92869998531603, 57.005900580047694 ], [ 23.926931186000047, 57.006333726000037 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-020", "NAME_1": "Carnikavas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.113025617338337, 57.0887232661658 ], [ 24.210785352000073, 57.123724677000041 ], [ 24.219248894000089, 57.138006903000075 ], [ 24.238617384000065, 57.149562893000052 ], [ 24.261241082000083, 57.157456773000035 ], [ 24.278575066000087, 57.161037502000056 ], [ 24.278819207000083, 57.171779690000051 ], [ 24.28874759200005, 57.178900458000044 ], [ 24.312673373000052, 57.188299872000073 ], [ 24.330845177757187, 57.199754558993163 ], [ 24.34880651151127, 57.183827989869826 ], [ 24.341853109933083, 57.162967784235832 ], [ 24.337681068626409, 57.128200776344727 ], [ 24.320992904299089, 57.112903292153192 ], [ 24.26536569077399, 57.098996488996761 ], [ 24.258412289195746, 57.075354923091197 ], [ 24.247286846310885, 57.060057439798982 ], [ 24.23198936301867, 57.072573562819628 ], [ 24.162383007569701, 57.052823973147838 ], [ 24.15168379117398, 57.055587470185571 ], [ 24.113025617338337, 57.0887232661658 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-089", "NAME_1": "Saulkrastu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.330845177757187, 57.199754558993163 ], [ 24.379161004000082, 57.230210679000038 ], [ 24.400645379000082, 57.25812409100007 ], [ 24.408864780000044, 57.298163153000075 ], [ 24.405528191000087, 57.344468492000033 ], [ 24.404836854466101, 57.34807919696572 ], [ 24.40515669092855, 57.347895209296439 ], [ 24.410789421894265, 57.344665431764213 ], [ 24.425568882198149, 57.333968411512956 ], [ 24.429289585246124, 57.328542385222875 ], [ 24.432390170669805, 57.320222479983443 ], [ 24.430219761232991, 57.308388577270989 ], [ 24.426188998923124, 57.298828436782912 ], [ 24.426809115648155, 57.294590968898092 ], [ 24.42789432126591, 57.291387030686906 ], [ 24.45021853955393, 57.295831204146737 ], [ 24.461287311660101, 57.294765899626555 ], [ 24.476749102888789, 57.270050170878676 ], [ 24.48787454577365, 57.238064523259141 ], [ 24.444763455269253, 57.235283162088251 ], [ 24.372448077416834, 57.182437309734041 ], [ 24.34880651151127, 57.183827989869826 ], [ 24.330845177757187, 57.199754558993163 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-054", "NAME_1": "Limbaži" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.404836854466101, 57.34807919696572 ], [ 24.394893257192049, 57.400012509164952 ], [ 24.447544815540766, 57.407727525005271 ], [ 24.486483864738545, 57.416071606719242 ], [ 24.501781348930081, 57.427197049604104 ], [ 24.511516111679214, 57.448057254338778 ], [ 24.558799242590965, 57.452229295645452 ], [ 24.578268768089174, 57.464745418666098 ], [ 24.565752644169152, 57.474480181415231 ], [ 24.549064480741151, 57.489777664707447 ], [ 24.529594956142319, 57.521763312326982 ], [ 24.553236521148506, 57.541232836925872 ], [ 24.49065590604522, 57.544014198096761 ], [ 24.497609307623406, 57.555139640981622 ], [ 24.478139783024574, 57.567655764002268 ], [ 24.460060938561469, 57.564874402831379 ], [ 24.433638012384336, 57.567655764002268 ], [ 24.43502869252012, 57.588515968736942 ], [ 24.423903249635259, 57.589906648872727 ], [ 24.426684610806149, 57.620501616356478 ], [ 24.4183405281928, 57.670566109338438 ], [ 24.515688152086511, 57.678910191052466 ], [ 24.54072039812786, 57.666394068031764 ], [ 24.564361964033424, 57.673347469610007 ], [ 24.558799242590965, 57.688644953801543 ], [ 24.562971283897639, 57.717849240250189 ], [ 24.608863735572925, 57.715067879978676 ], [ 24.599128972823792, 57.752616249040614 ], [ 24.649193464906489, 57.770695093503718 ], [ 24.692304555410885, 57.760960331653962 ], [ 24.707602039602421, 57.749834888769101 ], [ 24.747931768935985, 57.731756044305996 ], [ 24.799386942053729, 57.733146724441724 ], [ 24.828591229401695, 57.719239921285293 ], [ 24.824419188095021, 57.699770395787084 ], [ 24.831372589673265, 57.666394068031764 ], [ 24.892562524640766, 57.652487264875333 ], [ 24.881437081755905, 57.624673657663152 ], [ 24.88004640162012, 57.582953247294483 ], [ 24.894945916021186, 57.567158312106415 ], [ 24.916184929590827, 57.555789496488046 ], [ 24.9329797705999, 57.55643545253406 ], [ 24.984346143759524, 57.563902696152468 ], [ 25.004344923879103, 57.562197373809738 ], [ 25.022328322394173, 57.555298570072921 ], [ 25.046409538969044, 57.535351467696046 ], [ 25.051370477265721, 57.524499416914523 ], [ 25.051370477265721, 57.518349921111962 ], [ 25.047029656593338, 57.51576610052507 ], [ 25.047804802949258, 57.514086615704741 ], [ 25.053850945964371, 57.511761175737661 ], [ 25.066718376551819, 57.51269135172447 ], [ 25.080826043287232, 57.510830999750794 ], [ 25.087078891877354, 57.507239487911988 ], [ 25.087802362289153, 57.503725491338344 ], [ 25.079585808937907, 57.500211493865322 ], [ 25.061912468785408, 57.498221951581797 ], [ 25.05323082923934, 57.491839911782449 ], [ 25.045634392613124, 57.482796536131218 ], [ 25.01256147633103, 57.476104437969411 ], [ 25.002949659898889, 57.467500311889864 ], [ 24.988841994062739, 57.461299140143183 ], [ 24.980315383248296, 57.452875882116246 ], [ 24.886884393200148, 57.420888170552587 ], [ 24.875877312787736, 57.41303335240724 ], [ 24.84668012918462, 57.412206529207936 ], [ 24.812677036016396, 57.419027818578911 ], [ 24.799499546167112, 57.417115789761851 ], [ 24.799964634160517, 57.411431382852015 ], [ 24.83164228736166, 57.395515041885631 ], [ 24.750713130106874, 57.396602082120353 ], [ 24.747931768935985, 57.410508885276784 ], [ 24.688132515003531, 57.389648680542166 ], [ 24.702039318159962, 57.349318950309282 ], [ 24.683960473696914, 57.328458745574608 ], [ 24.636677341885786, 57.320114662961316 ], [ 24.647802784770704, 57.300645138362427 ], [ 24.685351153832642, 57.286738335205996 ], [ 24.706211359466636, 57.242236563666438 ], [ 24.71309655106495, 57.227049872353689 ], [ 24.681573928394073, 57.223070786887263 ], [ 24.643281691396908, 57.237178452723413 ], [ 24.622146029715509, 57.265574653347528 ], [ 24.601527133770162, 57.278984687193542 ], [ 24.589124790276855, 57.285340888571113 ], [ 24.578066033920322, 57.28875153325663 ], [ 24.575430535590726, 57.29087026585006 ], [ 24.573725213247997, 57.295727851359231 ], [ 24.566283807151933, 57.310042222770335 ], [ 24.550005730979706, 57.316346747304522 ], [ 24.472232700378811, 57.293712469754666 ], [ 24.461287311660101, 57.294765899626555 ], [ 24.45021853955393, 57.295831204146737 ], [ 24.42789432126591, 57.291387030686906 ], [ 24.426809115648155, 57.294590968898092 ], [ 24.426188998923124, 57.298828436782912 ], [ 24.430219761232991, 57.308388577270989 ], [ 24.432390170669805, 57.320222479983443 ], [ 24.429289585246124, 57.328542385222875 ], [ 24.425568882198149, 57.333968411512956 ], [ 24.410789421894265, 57.344665431764213 ], [ 24.40515669092855, 57.347895209296439 ], [ 24.404836854466101, 57.34807919696572 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-094", "NAME_1": "Smiltenes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.311500278215249, 57.499332993822577 ], [ 26.311035191121164, 57.469774075013504 ], [ 26.325969679257298, 57.467603665576689 ], [ 26.312740512564574, 57.458663641813587 ], [ 26.304523960112647, 57.455356349915576 ], [ 26.296152378029831, 57.450007839789919 ], [ 26.293516879700235, 57.442695624003818 ], [ 26.300803257064615, 57.438974920955786 ], [ 26.308554722422457, 57.436158556372277 ], [ 26.315065951632334, 57.433135484415061 ], [ 26.318941685210575, 57.429001370217009 ], [ 26.320491977922416, 57.423782050401257 ], [ 26.315065951632334, 57.418097643491421 ], [ 26.312740512564574, 57.409726061408605 ], [ 26.309794955872519, 57.402207140047437 ], [ 26.302818637769917, 57.396135159509981 ], [ 26.299097934721885, 57.389468898870575 ], [ 26.301423373789646, 57.379831244915977 ], [ 26.302043491413997, 57.374844469096956 ], [ 26.286230503235117, 57.365826930968069 ], [ 26.277548861890466, 57.364715887827913 ], [ 26.276153598809515, 57.331022853921525 ], [ 26.277083774796324, 57.322961331100544 ], [ 26.280339389850951, 57.317871202493961 ], [ 26.27568851081611, 57.308336900427605 ], [ 26.264991488766157, 57.300947171174982 ], [ 26.266645135164822, 57.288854885144815 ], [ 26.261994256129981, 57.281930243885597 ], [ 26.130271029984044, 57.276478380073172 ], [ 26.101280551955881, 57.278157863994181 ], [ 26.075804071400739, 57.274127102583691 ], [ 26.058595819241646, 57.265290432507413 ], [ 26.043713006150313, 57.279966539124473 ], [ 26.027848342027369, 57.281646023045482 ], [ 26.012965528935979, 57.28782135726982 ], [ 25.991726515366395, 57.290017605128355 ], [ 25.910697869710873, 57.286736152551384 ], [ 25.904186638702413, 57.288441473994794 ], [ 25.891319207215645, 57.288312282785569 ], [ 25.880312126803176, 57.286296902080323 ], [ 25.769871138342353, 57.278712291539023 ], [ 25.754273309365715, 57.277641100056712 ], [ 25.745126580926922, 57.275108954514621 ], [ 25.736910027575675, 57.284669094103378 ], [ 25.733034294896754, 57.296606350502657 ], [ 25.738770378650031, 57.313065293828231 ], [ 25.736599969213216, 57.319395656784081 ], [ 25.740165642630302, 57.326423651730124 ], [ 25.753343133378905, 57.329679266784694 ], [ 25.751637811036119, 57.337689114560987 ], [ 25.722182245014551, 57.361305244041773 ], [ 25.704922316012073, 57.383784491960682 ], [ 25.713965691663304, 57.400992744119833 ], [ 25.667095167907632, 57.452514146910346 ], [ 25.657948438569576, 57.464606432041194 ], [ 25.675776808353021, 57.472719631705615 ], [ 25.680117629025347, 57.479592597020712 ], [ 25.718404072589863, 57.496556342401277 ], [ 25.776334139608821, 57.499687698128753 ], [ 25.835206685340211, 57.493516211204167 ], [ 25.896254182984137, 57.486190510983249 ], [ 25.935324581764007, 57.476422911288296 ], [ 25.959743581001419, 57.495958110678259 ], [ 25.959743581001419, 57.515493310068166 ], [ 25.945092181458961, 57.530144709610624 ], [ 25.97683688001797, 57.549679909000588 ], [ 26.050093877730262, 57.559447508695541 ], [ 26.094048076357637, 57.559447508695541 ], [ 26.123350875442554, 57.569215108390495 ], [ 26.155095574001507, 57.547238009526495 ], [ 26.184398373086424, 57.547238009526495 ], [ 26.240562070882845, 57.54235420967899 ], [ 26.24544587073035, 57.522819010289084 ], [ 26.282074370036128, 57.525260909763119 ], [ 26.301609569426091, 57.527702810136532 ], [ 26.311500278215249, 57.499332993822577 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-015", "NAME_1": "Balvu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 27.354899122796269, 57.284772446890884 ], [ 27.406265496855156, 57.263068346227158 ], [ 27.46073245633778, 57.274178779427075 ], [ 27.487087436935667, 57.273868720165297 ], [ 27.446236007285904, 57.243979191686321 ], [ 27.425730335986202, 57.212081481575069 ], [ 27.402946257463782, 57.159678099264852 ], [ 27.455349638874736, 57.114109941320692 ], [ 27.514588244651748, 57.079933823087458 ], [ 27.541929139418244, 57.07765541496542 ], [ 27.553321179129114, 57.038922480488054 ], [ 27.589775705484385, 57.04347929673213 ], [ 27.630787048083789, 57.038922480488054 ], [ 27.637622271550583, 57.018416809188352 ], [ 27.664963166317079, 56.988797506299875 ], [ 27.612559784006805, 56.984240690955119 ], [ 27.519145059996504, 56.954621388066585 ], [ 27.537372323174168, 56.934115716766883 ], [ 27.494082573352046, 56.91361004546718 ], [ 27.443957599163866, 56.915888453589218 ], [ 27.41661670439737, 56.902218005756311 ], [ 27.434843967575034, 56.883990742578703 ], [ 27.446701919957604, 56.852663522803311 ], [ 27.427814568787312, 56.85125885731037 ], [ 27.412156610239379, 56.84531606708282 ], [ 27.395723504436148, 56.835962633069016 ], [ 27.390917595770418, 56.831906033236805 ], [ 27.394948358080228, 56.828030301457204 ], [ 27.38342451283097, 56.821364040817798 ], [ 27.376603224359314, 56.820614731984278 ], [ 27.371332227700123, 56.822009995964493 ], [ 27.368696730269846, 56.824464627140799 ], [ 27.362495557623845, 56.824593818350024 ], [ 27.355209181158784, 56.821648260758593 ], [ 27.348077834324556, 56.815137031548716 ], [ 27.348387891787752, 56.807204698138264 ], [ 27.344822219269986, 56.801597804694893 ], [ 27.347922803794347, 56.784312039069334 ], [ 27.339861280973309, 56.782684231092389 ], [ 27.243174675870591, 56.789195462100849 ], [ 27.186072218957747, 56.793794664292307 ], [ 27.160750767134175, 56.81136465075798 ], [ 27.133155552186963, 56.808212389390235 ], [ 27.121373325418631, 56.81061534282378 ], [ 27.095586785601654, 56.80924591726523 ], [ 27.067526482661037, 56.805318509541564 ], [ 27.057914666228839, 56.800357571244888 ], [ 27.032283156042809, 56.801339423175818 ], [ 27.017555372582365, 56.806507066148129 ], [ 26.984017368306866, 56.805938626266538 ], [ 26.966188999422741, 56.809555976527065 ], [ 26.928465204105862, 56.831105048459165 ], [ 26.94401980986629, 56.840251776897958 ], [ 26.953324130104477, 56.846677123550364 ], [ 26.980761753252295, 56.865624905564914 ], [ 26.983707309944407, 56.870792548537281 ], [ 26.985102573025301, 56.878233953733968 ], [ 27.03612258399005, 56.883990742578703 ], [ 27.083969150056191, 56.874877110989871 ], [ 27.165991835254999, 56.861206664056283 ], [ 27.200167953488233, 56.861206664056283 ], [ 27.225230440132691, 56.895382782289516 ], [ 27.266241782732095, 56.915888453589218 ], [ 27.291304269376496, 56.927280493300088 ], [ 27.332315611975901, 56.93639412488892 ], [ 27.314088348798236, 56.979683874711043 ], [ 27.28674745403174, 56.972848651244249 ], [ 27.261684966488019, 56.972848651244249 ], [ 27.254849743021225, 56.993354322543951 ], [ 27.289025862153778, 57.000189546010688 ], [ 27.314088348798236, 57.025252032655146 ], [ 27.325480388509106, 57.061706559909794 ], [ 27.304974717209404, 57.06626337525455 ], [ 27.270798598076794, 57.063984967132512 ], [ 27.197889545366195, 57.07765541496542 ], [ 27.147764571178016, 57.08904745467629 ], [ 27.118145269188801, 57.084490638432214 ], [ 27.097639597889099, 57.091325861898952 ], [ 27.097639597889099, 57.114109941320692 ], [ 27.049793031822958, 57.111831533198654 ], [ 27.008103809043519, 57.114503838081646 ], [ 27.065046013962331, 57.155736395917927 ], [ 27.091245964929328, 57.170102444172414 ], [ 27.130209994595532, 57.199635525459087 ], [ 27.156564976092739, 57.226378078785274 ], [ 27.184366895715641, 57.228109239549724 ], [ 27.20111005988133, 57.234801336812211 ], [ 27.220488722376615, 57.23438792656151 ], [ 27.228911981302872, 57.238987127853648 ], [ 27.234182977062744, 57.242811183689128 ], [ 27.24100426643372, 57.246428534848974 ], [ 27.248135614167268, 57.248960680391065 ], [ 27.275885857846049, 57.246686917267368 ], [ 27.326011996656291, 57.277434394481702 ], [ 27.354899122796269, 57.284772446890884 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-096", "NAME_1": "Strencu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.729363815387728, 57.570143184460392 ], [ 25.710575685519473, 57.576405894116704 ], [ 25.724666782246175, 57.588931313429327 ], [ 25.707444330691317, 57.603022411055406 ], [ 25.694918910479316, 57.61554783036803 ], [ 25.66360536129838, 57.618679186095505 ], [ 25.630726133803989, 57.62024486350964 ], [ 25.591234165224535, 57.614106350227871 ], [ 25.571022764688848, 57.619461199674618 ], [ 25.533304885112329, 57.629454251312609 ], [ 25.509895461206554, 57.646197415478298 ], [ 25.530204298789329, 57.659064846065746 ], [ 25.600978262037131, 57.668780865144811 ], [ 25.600978262037131, 57.696963059497591 ], [ 25.611938004835054, 57.707922801396137 ], [ 25.621332069319521, 57.718882544194059 ], [ 25.67143374836877, 57.720448221608137 ], [ 25.688656200823004, 57.737670674062315 ], [ 25.735088788017151, 57.730380503357537 ], [ 25.847416184509314, 57.752357602221537 ], [ 25.82788098511935, 57.705961504120069 ], [ 25.857183784204267, 57.703519603746713 ], [ 25.859625684577679, 57.68398440435675 ], [ 25.989046380086336, 57.671774905187704 ], [ 25.979278780391382, 57.649797805424328 ], [ 25.959743581001419, 57.620495006339468 ], [ 25.932882681390595, 57.608285507170365 ], [ 25.876718983594174, 57.603401707322917 ], [ 25.901137982831642, 57.588750307780458 ], [ 25.903579882305678, 57.569215108390495 ], [ 25.888928482763276, 57.549679909000588 ], [ 25.896254182984137, 57.530144709610624 ], [ 25.945092181458961, 57.530144709610624 ], [ 25.959743581001419, 57.515493310068166 ], [ 25.959743581001419, 57.495958110678259 ], [ 25.935324581764007, 57.476422911288296 ], [ 25.896254182984137, 57.486190510983249 ], [ 25.835206685340211, 57.493516211204167 ], [ 25.776334139608821, 57.499687698128753 ], [ 25.821738785516516, 57.524738537653377 ], [ 25.809213366203892, 57.537263956966001 ], [ 25.779006690006725, 57.529797199880818 ], [ 25.743454912114487, 57.534132602137845 ], [ 25.734060847630019, 57.546658022349845 ], [ 25.771637106467267, 57.548223699763923 ], [ 25.78259684926519, 57.552920732006157 ], [ 25.752848977498275, 57.570143184460392 ], [ 25.729363815387728, 57.570143184460392 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-017", "NAME_1": "Beverinas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.630726133803989, 57.62024486350964 ], [ 25.66360536129838, 57.618679186095505 ], [ 25.694918910479316, 57.61554783036803 ], [ 25.707444330691317, 57.603022411055406 ], [ 25.724666782246175, 57.588931313429327 ], [ 25.710575685519473, 57.576405894116704 ], [ 25.729363815387728, 57.570143184460392 ], [ 25.752848977498275, 57.570143184460392 ], [ 25.78259684926519, 57.552920732006157 ], [ 25.771637106467267, 57.548223699763923 ], [ 25.734060847630019, 57.546658022349845 ], [ 25.743454912114487, 57.534132602137845 ], [ 25.779006690006725, 57.529797199880818 ], [ 25.809213366203892, 57.537263956966001 ], [ 25.821738785516516, 57.524738537653377 ], [ 25.776334139608821, 57.499687698128753 ], [ 25.718404072589863, 57.496556342401277 ], [ 25.680117629025347, 57.479592597020712 ], [ 25.675776808353021, 57.472719631705615 ], [ 25.657948438569576, 57.464606432041194 ], [ 25.602396275267893, 57.468637193451684 ], [ 25.561106804735232, 57.45101553014257 ], [ 25.547619255624113, 57.441558743341318 ], [ 25.526793654103813, 57.438199775499186 ], [ 25.519352248007806, 57.441248684079483 ], [ 25.509430373213149, 57.447010607153743 ], [ 25.500438674405302, 57.450137030999144 ], [ 25.474497104957436, 57.442540595272249 ], [ 25.420960320562301, 57.447449855826164 ], [ 25.398791131005851, 57.441248684079483 ], [ 25.392743157870427, 57.465242793220284 ], [ 25.378652061143669, 57.484030923088596 ], [ 25.377086383729591, 57.509081762613221 ], [ 25.395874512698583, 57.509081762613221 ], [ 25.431885095021073, 57.505950407785065 ], [ 25.452238902303463, 57.515344472269533 ], [ 25.456935934545697, 57.537263956966001 ], [ 25.480421096656244, 57.548223699763923 ], [ 25.507037613594946, 57.567011828732859 ], [ 25.536785485361861, 57.584234281187094 ], [ 25.569664712856195, 57.592062668257483 ], [ 25.591234165224535, 57.614106350227871 ], [ 25.630726133803989, 57.62024486350964 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-019", "NAME_1": "Burtnieku" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.552890252283305, 57.792390041766964 ], [ 25.564827507783264, 57.782649034125598 ], [ 25.596281229794897, 57.773681255485542 ], [ 25.616635037077288, 57.758024480445386 ], [ 25.660474006470224, 57.750196093374996 ], [ 25.688656200823004, 57.737670674062315 ], [ 25.67143374836877, 57.720448221608137 ], [ 25.621332069319521, 57.718882544194059 ], [ 25.611938004835054, 57.707922801396137 ], [ 25.600978262037131, 57.696963059497591 ], [ 25.600978262037131, 57.668780865144811 ], [ 25.530204298789329, 57.659064846065746 ], [ 25.509895461206554, 57.646197415478298 ], [ 25.533304885112329, 57.629454251312609 ], [ 25.571022764688848, 57.619461199674618 ], [ 25.591234165224535, 57.614106350227871 ], [ 25.569664712856195, 57.592062668257483 ], [ 25.536785485361861, 57.584234281187094 ], [ 25.507037613594946, 57.567011828732859 ], [ 25.480421096656244, 57.548223699763923 ], [ 25.456935934545697, 57.537263956966001 ], [ 25.43971348209152, 57.556052086834313 ], [ 25.41153128773874, 57.556052086834313 ], [ 25.378652061143669, 57.549789377178001 ], [ 25.352035544204966, 57.567011828732859 ], [ 25.31289360705432, 57.585799958601172 ], [ 25.278448702145852, 57.593628346570881 ], [ 25.269054637661384, 57.61554783036803 ], [ 25.231478377924759, 57.639032992478576 ], [ 25.225215668268447, 57.64842705786242 ], [ 25.198599151329745, 57.654689767518732 ], [ 25.189205086845277, 57.673477897387045 ], [ 25.156325859350886, 57.662518154589122 ], [ 25.121880955341794, 57.653124090104654 ], [ 25.093745150718121, 57.653122056737516 ], [ 25.085321892691184, 57.674619452725551 ], [ 25.092453241323994, 57.688236192146519 ], [ 25.082221307267503, 57.696891995069507 ], [ 25.075710077158305, 57.705935370720738 ], [ 25.07617516425239, 57.714513658378621 ], [ 25.080205925662938, 57.721231594062772 ], [ 25.087182244664859, 57.727174384290379 ], [ 25.090902947712834, 57.73125682254431 ], [ 25.098706089014797, 57.736011054366656 ], [ 25.083616571247774, 57.75414948251256 ], [ 25.077260369870146, 57.767171942730954 ], [ 25.017469133393774, 57.796470091421554 ], [ 25.034203016555978, 57.814388870050266 ], [ 25.06081953349468, 57.812823192636188 ], [ 25.092133083574936, 57.812823192636188 ], [ 25.112486889958006, 57.800297772424244 ], [ 25.128143664998106, 57.798732095010166 ], [ 25.13284069724034, 57.808126160393954 ], [ 25.123446632755872, 57.826914289362946 ], [ 25.112486889958006, 57.837874032160812 ], [ 25.142234762624184, 57.844136741817181 ], [ 25.157891536764964, 57.833176999918578 ], [ 25.223649990854369, 57.804994804666478 ], [ 25.245569475550838, 57.800297772424244 ], [ 25.267488960247306, 57.79560074018201 ], [ 25.270620315075462, 57.778378287727776 ], [ 25.31289360705432, 57.78307532086933 ], [ 25.378652061143669, 57.787772353111563 ], [ 25.455370257131619, 57.789338030525641 ], [ 25.494512194282322, 57.789338030525641 ], [ 25.552890252283305, 57.792390041766964 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-045", "NAME_1": "Kocenu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.916184929590827, 57.555789496488046 ], [ 24.894945916021186, 57.567158312106415 ], [ 24.88004640162012, 57.582953247294483 ], [ 24.881437081755905, 57.624673657663152 ], [ 24.93453006421106, 57.612039293578505 ], [ 24.966311069300389, 57.628420722538294 ], [ 24.991477492392335, 57.636482246258652 ], [ 25.000159132837666, 57.635862127734981 ], [ 25.005740186960054, 57.636120510153376 ], [ 25.019072707339546, 57.638135890858621 ], [ 25.024033643837583, 57.637360745402077 ], [ 25.027599318153989, 57.634260159079076 ], [ 25.03302534444407, 57.630177720825145 ], [ 25.042378777558497, 57.625836900152819 ], [ 25.061602411322212, 57.623950711556063 ], [ 25.067803582169574, 57.626457017777113 ], [ 25.084701775966153, 57.629764308775805 ], [ 25.083306511985938, 57.63410513034745 ], [ 25.075865105889932, 57.638704332538907 ], [ 25.063307732765622, 57.648109443396095 ], [ 25.062222528047187, 57.65239858722498 ], [ 25.067028435813654, 57.654982407811815 ], [ 25.093745150718121, 57.653122056737516 ], [ 25.121880955341794, 57.653124090104654 ], [ 25.156325859350886, 57.662518154589122 ], [ 25.189205086845277, 57.673477897387045 ], [ 25.198599151329745, 57.654689767518732 ], [ 25.225215668268447, 57.64842705786242 ], [ 25.231478377924759, 57.639032992478576 ], [ 25.269054637661384, 57.61554783036803 ], [ 25.278448702145852, 57.593628346570881 ], [ 25.31289360705432, 57.585799958601172 ], [ 25.352035544204966, 57.567011828732859 ], [ 25.378652061143669, 57.549789377178001 ], [ 25.372389350588037, 57.527869892481533 ], [ 25.377086383729591, 57.509081762613221 ], [ 25.378652061143669, 57.484030923088596 ], [ 25.392743157870427, 57.465242793220284 ], [ 25.398791131005851, 57.441248684079483 ], [ 25.404682245289393, 57.434995836388737 ], [ 25.402511834053882, 57.433548896464345 ], [ 25.391814812903249, 57.428045355808479 ], [ 25.398636102274281, 57.4111213244895 ], [ 25.397085808663121, 57.404532579115198 ], [ 25.392900017621685, 57.398202216159348 ], [ 25.39321007688352, 57.39068329479818 ], [ 25.386853874606629, 57.386058255084379 ], [ 25.35734663264094, 57.385076402254128 ], [ 25.348975050558124, 57.388900458089665 ], [ 25.334867384722031, 57.397323717015922 ], [ 25.328976271337808, 57.403447374396762 ], [ 25.322775098691807, 57.405488593523728 ], [ 25.301174350815643, 57.403679918393493 ], [ 25.272803988613191, 57.404920151843498 ], [ 25.238180779619256, 57.415048733112542 ], [ 25.21074059430299, 57.416650703567086 ], [ 25.196891309985972, 57.421844184061797 ], [ 25.184643996123498, 57.430086574935444 ], [ 25.159684278606562, 57.448250841503125 ], [ 25.140563999428991, 57.461764228136587 ], [ 25.140874057791507, 57.475019233250976 ], [ 25.123045688907382, 57.49494049720613 ], [ 25.097775913027931, 57.487964179103528 ], [ 25.079585808937907, 57.500211493865322 ], [ 25.087802362289153, 57.503725491338344 ], [ 25.087078891877354, 57.507239487911988 ], [ 25.080826043287232, 57.510830999750794 ], [ 25.066718376551819, 57.51269135172447 ], [ 25.053850945964371, 57.511761175737661 ], [ 25.047804802949258, 57.514086615704741 ], [ 25.047029656593338, 57.51576610052507 ], [ 25.051370477265721, 57.518349921111962 ], [ 25.051370477265721, 57.524499416914523 ], [ 25.046409538969044, 57.535351467696046 ], [ 25.022328322394173, 57.555298570072921 ], [ 25.004344923879103, 57.562197373809738 ], [ 24.984346143759524, 57.563902696152468 ], [ 24.9329797705999, 57.55643545253406 ], [ 24.916184929590827, 57.555789496488046 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-REZ", "NAME_1": "Rezeknes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.928465204105862, 56.831105048459165 ], [ 26.966188999422741, 56.809555976527065 ], [ 26.984017368306866, 56.805938626266538 ], [ 27.017555372582365, 56.806507066148129 ], [ 27.032283156042809, 56.801339423175818 ], [ 27.057914666228839, 56.800357571244888 ], [ 27.067526482661037, 56.805318509541564 ], [ 27.095586785601654, 56.80924591726523 ], [ 27.121373325418631, 56.81061534282378 ], [ 27.133155552186963, 56.808212389390235 ], [ 27.160750767134175, 56.81136465075798 ], [ 27.186072218957747, 56.793794664292307 ], [ 27.243174675870591, 56.789195462100849 ], [ 27.339861280973309, 56.782684231092389 ], [ 27.403722515381787, 56.784777781769208 ], [ 27.45549777969876, 56.771833965465134 ], [ 27.471030359263636, 56.740768807234645 ], [ 27.486312289680427, 56.693387356141557 ], [ 27.480266147564635, 56.680829983017247 ], [ 27.470344272769978, 56.674215400120602 ], [ 27.472049595112708, 56.663259996551574 ], [ 27.476390414885714, 56.658454087885843 ], [ 27.488017612023157, 56.653312283335197 ], [ 27.501815220396111, 56.655766912712807 ], [ 27.512408887859863, 56.654836738524637 ], [ 27.524811232252546, 56.6517878281457 ], [ 27.541554396418235, 56.645069892461549 ], [ 27.551631300843837, 56.636749986322798 ], [ 27.58020836772198, 56.619438382275519 ], [ 27.561449822851046, 56.599646307730893 ], [ 27.56113976358921, 56.575926826361922 ], [ 27.574317254337814, 56.556961575016658 ], [ 27.566565789879292, 56.541717026719368 ], [ 27.551166212850433, 56.535102443822723 ], [ 27.538453810095234, 56.53153677040558 ], [ 27.525121290615061, 56.529288844804341 ], [ 27.506827833737532, 56.52807444887668 ], [ 27.493753695776434, 56.520865586777404 ], [ 27.486777377673832, 56.514896959027396 ], [ 27.486002232217231, 56.508850816012341 ], [ 27.487087436935667, 56.499497381998538 ], [ 27.495459019018483, 56.488025214492041 ], [ 27.49638919410603, 56.477922472544037 ], [ 27.508688184811888, 56.460171617126377 ], [ 27.549925977601788, 56.478568426791412 ], [ 27.55938276530236, 56.464460760955319 ], [ 27.559692823664875, 56.457096870124417 ], [ 27.571681756008218, 56.442808336235714 ], [ 27.581603630802874, 56.433609930953537 ], [ 27.589665155422551, 56.428313096771944 ], [ 27.592145623221938, 56.424385688148959 ], [ 27.591060417604183, 56.421827704185148 ], [ 27.596486443894264, 56.418985501179918 ], [ 27.60253258601, 56.418572089130578 ], [ 27.607958612300081, 56.420484117048318 ], [ 27.62180789571778, 56.420690823522648 ], [ 27.620412631737565, 56.407151598467465 ], [ 27.623978306053971, 56.401079617030689 ], [ 27.62242801334213, 56.392475490951142 ], [ 27.640411410957825, 56.378781236265013 ], [ 27.670383741816238, 56.371804918162411 ], [ 27.689917433043092, 56.360616969697389 ], [ 27.689607374680577, 56.354700018790822 ], [ 27.687591993975332, 56.347258612694816 ], [ 27.690227492304928, 56.332375800502746 ], [ 27.698909132750259, 56.321988836815365 ], [ 27.711001417881107, 56.311136786933162 ], [ 27.715497267285059, 56.298476061021347 ], [ 27.686816846720092, 56.276306871464897 ], [ 27.686816846720092, 56.262870999197219 ], [ 27.694258253715418, 56.260752264805149 ], [ 27.698909132750259, 56.258065091430808 ], [ 27.700459426361419, 56.255016181051872 ], [ 27.692552931372688, 56.249822700557161 ], [ 27.683561231665465, 56.24726471569403 ], [ 27.667593214755016, 56.240236720748044 ], [ 27.651573521001183, 56.249745185292056 ], [ 27.568116081691812, 56.24230377919605 ], [ 27.551631300843837, 56.245481878985515 ], [ 27.548220656158321, 56.24824656852428 ], [ 27.535043166309038, 56.261114000011048 ], [ 27.528066847307116, 56.257393296963073 ], [ 27.523570997903221, 56.24824656852428 ], [ 27.508998244073666, 56.241115220790789 ], [ 27.488947788009966, 56.235017401831612 ], [ 27.466933628084462, 56.233467109119772 ], [ 27.447244907226661, 56.229901434803367 ], [ 27.44068200027408, 56.223674425534284 ], [ 27.447865024851012, 56.209385890746205 ], [ 27.420683221053764, 56.210574449151466 ], [ 27.412001580608433, 56.207163805365326 ], [ 27.339086134617389, 56.21026439078895 ], [ 27.295936313909749, 56.203029690267954 ], [ 27.173049757840033, 56.208300686027826 ], [ 27.162301059846016, 56.210781154726476 ], [ 27.150828892339518, 56.208429877236995 ], [ 27.125869174822526, 56.195846665691022 ], [ 27.102408074972686, 56.18907705316343 ], [ 27.099617547012144, 56.18638987888977 ], [ 27.097602166306899, 56.181997382273323 ], [ 27.09822228393125, 56.179568590418114 ], [ 27.101632927717446, 56.17075775786418 ], [ 27.07760338708664, 56.170912787495126 ], [ 27.054193963180865, 56.173315741827992 ], [ 27.044065382811141, 56.175951240157588 ], [ 27.038019239796085, 56.180111191877984 ], [ 27.034608595110569, 56.186648261308164 ], [ 27.035693800728325, 56.198120428814718 ], [ 27.034298536748054, 56.2077839220903 ], [ 27.028872512256612, 56.215432033761317 ], [ 27.015695020608689, 56.22416535105009 ], [ 27.001587354772596, 56.230573229271101 ], [ 26.99724653499959, 56.238583076148018 ], [ 26.988513217710818, 56.247936510161765 ], [ 26.986187777743737, 56.263232734403118 ], [ 26.95983279804517, 56.284032498401075 ], [ 26.949135775995273, 56.297752591508868 ], [ 26.946500277665677, 56.304315497562129 ], [ 26.944329868228806, 56.312945462063396 ], [ 26.950841099237323, 56.319663397747604 ], [ 26.975800815854939, 56.320128485741009 ], [ 26.991148716040414, 56.33149730135932 ], [ 26.966499057785256, 56.359066676985549 ], [ 26.951771275224132, 56.372631741361772 ], [ 26.89761437320476, 56.411311551087181 ], [ 26.899939813171841, 56.418468736343073 ], [ 26.910016716698124, 56.425083320139095 ], [ 26.914667595732965, 56.433403225378527 ], [ 26.925364617782861, 56.447614244002125 ], [ 26.992109165005957, 56.450827327419177 ], [ 27.033529377178979, 56.448238564158373 ], [ 27.041295666062126, 56.46635990698411 ], [ 27.007641744570833, 56.523312697822746 ], [ 27.00505298131003, 56.562144145835646 ], [ 26.981754112862006, 56.593209304066079 ], [ 26.9144462689801, 56.600975593848545 ], [ 26.883381110749667, 56.637218278600642 ], [ 26.852315952519177, 56.657928384687182 ], [ 26.808306977984614, 56.665694674469648 ], [ 26.772557406798853, 56.681010851069914 ], [ 26.782944369586971, 56.707391669190145 ], [ 26.907536247999417, 56.817979234554002 ], [ 26.928465204105862, 56.831105048459165 ] ], [ [ 27.339069016921599, 56.47490562749266 ], [ 27.355497216923027, 56.494984539005259 ], [ 27.360973283290377, 56.520539517784471 ], [ 27.365536672679298, 56.538793073541456 ], [ 27.363711316923741, 56.555221273542884 ], [ 27.340169016386994, 56.560760606316876 ], [ 27.310056339128721, 56.553347928164328 ], [ 27.274284355038958, 56.515546408040279 ], [ 27.284639408082171, 56.489658775432133 ], [ 27.339069016921599, 56.47490562749266 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-104", "NAME_1": "Vecpiebalgas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.745126580926922, 57.275108954514621 ], [ 25.754273309365715, 57.277641100056712 ], [ 25.769871138342353, 57.278712291539023 ], [ 25.760677364568721, 57.255442011639502 ], [ 25.752848977498275, 57.244482269740899 ], [ 25.745020589528565, 57.213168719660644 ], [ 25.771637106467267, 57.199077622933942 ], [ 25.763808719396877, 57.169329751167027 ], [ 25.774768461295423, 57.153672976126927 ], [ 25.804516333961601, 57.134884846258615 ], [ 25.83896123797075, 57.120793748632593 ], [ 25.862446400081296, 57.120793748632593 ], [ 25.881234529949552, 57.097308586522047 ], [ 25.923100213204236, 57.097445379700503 ], [ 25.907597284287249, 57.0700051952835 ], [ 25.906202020306978, 57.061426906726354 ], [ 25.899535759667572, 57.05016144479481 ], [ 25.896745232606406, 57.037552394827117 ], [ 25.895660027887971, 57.026261095373229 ], [ 25.904341668333302, 57.013962103768051 ], [ 25.911162956805015, 57.006753242568038 ], [ 25.919999626881236, 57.000086981928632 ], [ 25.923565301197698, 56.992955634195141 ], [ 25.920774774136476, 56.981896877838608 ], [ 25.917829217444421, 56.975230618098522 ], [ 25.886358269818288, 56.964223537686109 ], [ 25.854060499892114, 56.962569892186764 ], [ 25.850339796844139, 56.9663681104999 ], [ 25.844913770554058, 56.970269679801845 ], [ 25.841813185130377, 56.973835354118251 ], [ 25.837472365357371, 56.976780910810362 ], [ 25.833906691040966, 56.979726468401793 ], [ 25.829720899999529, 56.982413641776134 ], [ 25.822589553165301, 56.984997464161609 ], [ 25.813701206245639, 56.986754462448459 ], [ 25.796027866093141, 56.984997464161609 ], [ 25.787501255278698, 56.981690172263598 ], [ 25.779439731558341, 56.981018377795863 ], [ 25.769517856763684, 56.983498847393889 ], [ 25.754893426090746, 56.99329153097932 ], [ 25.727143182411908, 56.998691717948418 ], [ 25.705439080848862, 56.99367910370762 ], [ 25.69732588118444, 56.986134344824109 ], [ 25.629526401322323, 56.963086656124233 ], [ 25.63355716273287, 56.974868882892622 ], [ 25.639138217754521, 56.984480699324763 ], [ 25.636967808317706, 56.99021678307804 ], [ 25.638518101029547, 56.992955634195141 ], [ 25.638518101029547, 56.994764309325376 ], [ 25.634022250726275, 56.994712633381312 ], [ 25.602706332731032, 56.984377346537258 ], [ 25.582345819204193, 56.981896877838608 ], [ 25.565137567045042, 56.982103583413618 ], [ 25.517181837671671, 56.995126044531276 ], [ 25.50399548410428, 56.994820478282406 ], [ 25.510168968423159, 57.008064971221415 ], [ 25.492946516868244, 57.026853101089728 ], [ 25.507037613594946, 57.036247165574196 ], [ 25.528957098291414, 57.020590390534096 ], [ 25.547745228159727, 57.020590390534096 ], [ 25.58688716441111, 57.050338262300954 ], [ 25.616635037077288, 57.065995037341054 ], [ 25.618200714491365, 57.080086134967132 ], [ 25.594715552380819, 57.10983400673399 ], [ 25.564967680613961, 57.112965361562146 ], [ 25.541482518503415, 57.122359426945991 ], [ 25.563402002300563, 57.147410266470615 ], [ 25.572796067684351, 57.170895428581161 ], [ 25.575927422512507, 57.203774655176176 ], [ 25.560270647472407, 57.222562785044488 ], [ 25.575927422512507, 57.23665388177119 ], [ 25.599412584623053, 57.247613624569112 ], [ 25.600978262037131, 57.26483607702329 ], [ 25.638554521773756, 57.26483607702329 ], [ 25.669868070954692, 57.274230141507815 ], [ 25.709010008105395, 57.266401754437368 ], [ 25.745126580926922, 57.275108954514621 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-076", "NAME_1": "Raunas" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 25.657948438569576, 57.464606432041194 ], [ 25.667095167907632, 57.452514146910346 ], [ 25.713965691663304, 57.400992744119833 ], [ 25.704922316012073, 57.383784491960682 ], [ 25.722182245014551, 57.361305244041773 ], [ 25.751637811036119, 57.337689114560987 ], [ 25.753343133378905, 57.329679266784694 ], [ 25.740165642630302, 57.326423651730124 ], [ 25.736599969213216, 57.319395656784081 ], [ 25.738770378650031, 57.313065293828231 ], [ 25.733034294896754, 57.296606350502657 ], [ 25.736910027575675, 57.284669094103378 ], [ 25.745126580926922, 57.275108954514621 ], [ 25.709010008105395, 57.266401754437368 ], [ 25.669868070954692, 57.274230141507815 ], [ 25.638554521773756, 57.26483607702329 ], [ 25.600978262037131, 57.26483607702329 ], [ 25.597846907208975, 57.28518988340636 ], [ 25.579058777340663, 57.296149626204283 ], [ 25.555573615230117, 57.305543690688751 ], [ 25.547745228159727, 57.321200465728907 ], [ 25.533654130533705, 57.338422918183085 ], [ 25.513300323251315, 57.346251305253531 ], [ 25.511734645837237, 57.360342402879553 ], [ 25.546179550745649, 57.377564854434468 ], [ 25.575927422512507, 57.380696209262624 ], [ 25.602543939451209, 57.377564854434468 ], [ 25.605675294279365, 57.39635298430278 ], [ 25.626029101561755, 57.405747049686568 ], [ 25.649514263672302, 57.44019195369566 ], [ 25.657948438569576, 57.464606432041194 ] ] ], [ [ [ 25.991726515366395, 57.290017605128355 ], [ 26.012965528935979, 57.28782135726982 ], [ 26.027848342027369, 57.281646023045482 ], [ 26.043713006150313, 57.279966539124473 ], [ 26.058595819241646, 57.265290432507413 ], [ 26.058595819241646, 57.251286119458825 ], [ 26.049139032440394, 57.24999420826606 ], [ 26.01436079291625, 57.249865017056891 ], [ 26.008469678632764, 57.246738593211489 ], [ 26.004128858859758, 57.243844713362819 ], [ 26.013430616929384, 57.221055406182018 ], [ 25.989266276017815, 57.206906010004332 ], [ 25.945427306624879, 57.191249234964175 ], [ 25.893759949262233, 57.184986525307863 ], [ 25.868709109737608, 57.184986525307863 ], [ 25.849920980768616, 57.195946268105786 ], [ 25.81860743068836, 57.206906010004332 ], [ 25.798253623405969, 57.20847168741841 ], [ 25.771637106467267, 57.199077622933942 ], [ 25.745020589528565, 57.213168719660644 ], [ 25.752848977498275, 57.244482269740899 ], [ 25.760677364568721, 57.255442011639502 ], [ 25.769871138342353, 57.278712291539023 ], [ 25.880312126803176, 57.286296902080323 ], [ 25.891319207215645, 57.288312282785569 ], [ 25.904186638702413, 57.288441473994794 ], [ 25.910697869710873, 57.286736152551384 ], [ 25.991726515366395, 57.290017605128355 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-075", "NAME_1": "Priekulu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.602396275267893, 57.468637193451684 ], [ 25.657948438569576, 57.464606432041194 ], [ 25.649514263672302, 57.44019195369566 ], [ 25.626029101561755, 57.405747049686568 ], [ 25.605675294279365, 57.39635298430278 ], [ 25.602543939451209, 57.377564854434468 ], [ 25.575927422512507, 57.380696209262624 ], [ 25.546179550745649, 57.377564854434468 ], [ 25.511734645837237, 57.360342402879553 ], [ 25.513300323251315, 57.346251305253531 ], [ 25.533654130533705, 57.338422918183085 ], [ 25.547745228159727, 57.321200465728907 ], [ 25.555573615230117, 57.305543690688751 ], [ 25.579058777340663, 57.296149626204283 ], [ 25.597846907208975, 57.28518988340636 ], [ 25.600978262037131, 57.26483607702329 ], [ 25.599412584623053, 57.247613624569112 ], [ 25.575927422512507, 57.23665388177119 ], [ 25.560270647472407, 57.222562785044488 ], [ 25.546179550745649, 57.213168719660644 ], [ 25.522694388635102, 57.20847168741841 ], [ 25.500774903938634, 57.216300075388119 ], [ 25.500774903938634, 57.24917930198319 ], [ 25.489815161140768, 57.263270399609212 ], [ 25.466329999030222, 57.277361496335971 ], [ 25.427188062778839, 57.289886916547914 ], [ 25.394308835284505, 57.302412335860595 ], [ 25.362995286103569, 57.296149626204283 ], [ 25.331681736922576, 57.291452593961992 ], [ 25.311327929640242, 57.296149626204283 ], [ 25.323853348952866, 57.308675045516907 ], [ 25.311327929640242, 57.31337207865846 ], [ 25.273751669903618, 57.318069110900694 ], [ 25.254963540035305, 57.325897497971141 ], [ 25.231478377924759, 57.330594530213375 ], [ 25.245569475550838, 57.347816982667609 ], [ 25.286277090115618, 57.360342402879553 ], [ 25.319156316710632, 57.355645369737999 ], [ 25.3567325764472, 57.357211047152077 ], [ 25.377086383729591, 57.369736467364078 ], [ 25.386853874606629, 57.386058255084379 ], [ 25.39321007688352, 57.39068329479818 ], [ 25.392900017621685, 57.398202216159348 ], [ 25.397085808663121, 57.404532579115198 ], [ 25.398636102274281, 57.4111213244895 ], [ 25.391814812903249, 57.428045355808479 ], [ 25.402511834053882, 57.433548896464345 ], [ 25.404682245289393, 57.434995836388737 ], [ 25.398791131005851, 57.441248684079483 ], [ 25.420960320562301, 57.447449855826164 ], [ 25.474497104957436, 57.442540595272249 ], [ 25.500438674405302, 57.450137030999144 ], [ 25.509430373213149, 57.447010607153743 ], [ 25.519352248007806, 57.441248684079483 ], [ 25.526793654103813, 57.438199775499186 ], [ 25.547619255624113, 57.441558743341318 ], [ 25.561106804735232, 57.45101553014257 ], [ 25.602396275267893, 57.468637193451684 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-070", "NAME_1": "Pargaujas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.079585808937907, 57.500211493865322 ], [ 25.097775913027931, 57.487964179103528 ], [ 25.123045688907382, 57.49494049720613 ], [ 25.140874057791507, 57.475019233250976 ], [ 25.140563999428991, 57.461764228136587 ], [ 25.159684278606562, 57.448250841503125 ], [ 25.184643996123498, 57.430086574935444 ], [ 25.196891309985972, 57.421844184061797 ], [ 25.21074059430299, 57.416650703567086 ], [ 25.238180779619256, 57.415048733112542 ], [ 25.272803988613191, 57.404920151843498 ], [ 25.301174350815643, 57.403679918393493 ], [ 25.322775098691807, 57.405488593523728 ], [ 25.328976271337808, 57.403447374396762 ], [ 25.334867384722031, 57.397323717015922 ], [ 25.348975050558124, 57.388900458089665 ], [ 25.35734663264094, 57.385076402254128 ], [ 25.386853874606629, 57.386058255084379 ], [ 25.377086383729591, 57.369736467364078 ], [ 25.3567325764472, 57.357211047152077 ], [ 25.319156316710632, 57.355645369737999 ], [ 25.286277090115618, 57.360342402879553 ], [ 25.245569475550838, 57.347816982667609 ], [ 25.231478377924759, 57.330594530213375 ], [ 25.231478377924759, 57.296149626204283 ], [ 25.231478377924759, 57.28518988340636 ], [ 25.206427538400135, 57.26483607702329 ], [ 25.165719924734731, 57.263270399609212 ], [ 25.131275019826262, 57.266401754437368 ], [ 25.090567405261538, 57.247613624569112 ], [ 25.048294114181999, 57.241350914912744 ], [ 24.980969982678516, 57.238219559185268 ], [ 24.933134800230846, 57.246221829273964 ], [ 24.939646030339986, 57.257978216721312 ], [ 24.942126499038693, 57.267512518787669 ], [ 24.935770297661065, 57.278261216781686 ], [ 24.915099724872391, 57.289371649981661 ], [ 24.898046502344187, 57.302600815775008 ], [ 24.888744745173824, 57.30921540047035 ], [ 24.889364861898855, 57.312212633106526 ], [ 24.900216912680378, 57.318930568790677 ], [ 24.902852411009917, 57.323116359832113 ], [ 24.903317498104059, 57.32771556292289 ], [ 24.880993279815982, 57.337224026567526 ], [ 24.878822870379167, 57.342934271899082 ], [ 24.87076134575949, 57.350556546047756 ], [ 24.854276564012196, 57.372725734704886 ], [ 24.83164228736166, 57.395515041885631 ], [ 24.799964634160517, 57.411431382852015 ], [ 24.799499546167112, 57.417115789761851 ], [ 24.812677036016396, 57.419027818578911 ], [ 24.84668012918462, 57.412206529207936 ], [ 24.875877312787736, 57.41303335240724 ], [ 24.886884393200148, 57.420888170552587 ], [ 24.980315383248296, 57.452875882116246 ], [ 24.988841994062739, 57.461299140143183 ], [ 25.002949659898889, 57.467500311889864 ], [ 25.01256147633103, 57.476104437969411 ], [ 25.045634392613124, 57.482796536131218 ], [ 25.05323082923934, 57.491839911782449 ], [ 25.061912468785408, 57.498221951581797 ], [ 25.079585808937907, 57.500211493865322 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-048", "NAME_1": "Krimuldas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.83164228736166, 57.395515041885631 ], [ 24.854276564012196, 57.372725734704886 ], [ 24.87076134575949, 57.350556546047756 ], [ 24.878822870379167, 57.342934271899082 ], [ 24.880993279815982, 57.337224026567526 ], [ 24.903317498104059, 57.32771556292289 ], [ 24.902852411009917, 57.323116359832113 ], [ 24.900216912680378, 57.318930568790677 ], [ 24.889364861898855, 57.312212633106526 ], [ 24.888744745173824, 57.30921540047035 ], [ 24.898046502344187, 57.302600815775008 ], [ 24.915099724872391, 57.289371649981661 ], [ 24.935770297661065, 57.278261216781686 ], [ 24.942126499038693, 57.267512518787669 ], [ 24.939646030339986, 57.257978216721312 ], [ 24.933134800230846, 57.246221829273964 ], [ 24.923471306955207, 57.236041572060856 ], [ 24.900371942311267, 57.218678290270873 ], [ 24.884218442926795, 57.199125473162042 ], [ 24.861967557157016, 57.189390711312228 ], [ 24.823028507959236, 57.182437309734041 ], [ 24.804949663496132, 57.165749145406721 ], [ 24.79660558088284, 57.142107579501157 ], [ 24.77991741745484, 57.135154177922971 ], [ 24.772964014977276, 57.147670300943616 ], [ 24.736806326950386, 57.147670300943616 ], [ 24.700648638024234, 57.137935538194483 ], [ 24.665881629233809, 57.125419415173837 ], [ 24.675616391083565, 57.149060981079401 ], [ 24.67422571094778, 57.169921186713395 ], [ 24.65753754751978, 57.179655948563152 ], [ 24.619989177558466, 57.176874588291582 ], [ 24.615817137151168, 57.203297514468716 ], [ 24.66031890779135, 57.210250916046903 ], [ 24.681573928394073, 57.223070786887263 ], [ 24.71309655106495, 57.227049872353689 ], [ 24.706211359466636, 57.242236563666438 ], [ 24.685351153832642, 57.286738335205996 ], [ 24.647802784770704, 57.300645138362427 ], [ 24.636677341885786, 57.320114662961316 ], [ 24.683960473696914, 57.328458745574608 ], [ 24.702039318159962, 57.349318950309282 ], [ 24.688132515003531, 57.389648680542166 ], [ 24.747931768935985, 57.410508885276784 ], [ 24.750713130106874, 57.396602082120353 ], [ 24.83164228736166, 57.395515041885631 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-033", "NAME_1": "Gulbene" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.130271029984044, 57.276478380073172 ], [ 26.261994256129981, 57.281930243885597 ], [ 26.266645135164822, 57.288854885144815 ], [ 26.264991488766157, 57.300947171174982 ], [ 26.27568851081611, 57.308336900427605 ], [ 26.280339389850951, 57.317871202493961 ], [ 26.277083774796324, 57.322961331100544 ], [ 26.276153598809515, 57.331022853921525 ], [ 26.359456007588676, 57.322547919051203 ], [ 26.423534784402761, 57.332159736382721 ], [ 26.430046013612639, 57.339704495266233 ], [ 26.430046013612639, 57.34600901980042 ], [ 26.424154901127793, 57.346990871731293 ], [ 26.411132440010078, 57.342856757533298 ], [ 26.404466180269992, 57.342236639909004 ], [ 26.399040154879231, 57.344019477516838 ], [ 26.394699334206905, 57.347145901362239 ], [ 26.393924187850985, 57.350711574779325 ], [ 26.397024774173985, 57.35427724909573 ], [ 26.421054314804792, 57.357946275300321 ], [ 26.43314659993564, 57.361408595929902 ], [ 26.446840854621712, 57.369160061287744 ], [ 26.474746127931439, 57.375051175571286 ], [ 26.479241978234711, 57.382389227980468 ], [ 26.480637241315605, 57.387401842221209 ], [ 26.475831332649875, 57.405075182373764 ], [ 26.52022138770684, 57.406470445454659 ], [ 26.525802442728548, 57.401871243263258 ], [ 26.531073439387683, 57.398874009727763 ], [ 26.544405958867912, 57.395618395572455 ], [ 26.567712029986183, 57.397427069803427 ], [ 26.594222040214959, 57.391303412422531 ], [ 26.61814822805826, 57.362493801547657 ], [ 26.6331860689819, 57.350298162729985 ], [ 26.677576124938184, 57.334330145819536 ], [ 26.681451856717786, 57.323684801512343 ], [ 26.682227003973026, 57.320015774408432 ], [ 26.714783156317594, 57.306476549353249 ], [ 26.747701042968743, 57.318956407212397 ], [ 26.7607235040864, 57.321669419907778 ], [ 26.790230746951408, 57.318413804853208 ], [ 26.836171094720214, 57.315313219429527 ], [ 26.840046828298455, 57.3162950713604 ], [ 26.845472852789896, 57.315933336154501 ], [ 26.849348586368137, 57.315261541686766 ], [ 26.865006544916071, 57.299526068773048 ], [ 26.905520868193491, 57.303737698236148 ], [ 26.988513217710818, 57.304409491804563 ], [ 27.020810987636935, 57.286736152551384 ], [ 27.059930046934085, 57.27275767702514 ], [ 27.066906365936006, 57.268701077192929 ], [ 27.060085076565031, 57.263223374958784 ], [ 27.048561232215093, 57.256427924009472 ], [ 27.046545850610471, 57.253353176108135 ], [ 27.045925733885497, 57.250304267527895 ], [ 27.056157667941989, 57.24870229797267 ], [ 27.156564976092739, 57.226378078785274 ], [ 27.130209994595532, 57.199635525459087 ], [ 27.091245964929328, 57.170102444172414 ], [ 27.065046013962331, 57.155736395917927 ], [ 27.008103809043519, 57.114503838081646 ], [ 26.995179478350224, 57.105145169114223 ], [ 26.979056430909566, 57.095585029525466 ], [ 26.953166538305084, 57.064837551411813 ], [ 26.929550408824298, 57.04979971048823 ], [ 26.901955193877086, 57.039257718069223 ], [ 26.860510694612856, 57.018018704499582 ], [ 26.868417188702267, 57.005900580047694 ], [ 26.871207716662752, 57.002644964993124 ], [ 26.860045606619451, 56.983007920978764 ], [ 26.795811801973059, 56.989131578359604 ], [ 26.78154910740534, 56.99254222304512 ], [ 26.757622917763399, 56.992955634195141 ], [ 26.734833612381294, 56.988201402372795 ], [ 26.725996942305017, 56.982620348250464 ], [ 26.703776075905182, 56.974197089324207 ], [ 26.697419875426874, 56.973473618912351 ], [ 26.691063674049303, 56.978202013212297 ], [ 26.635201449687145, 56.96499868404203 ], [ 26.603678827016211, 56.953604030901261 ], [ 26.568177117979587, 56.94841055040655 ], [ 26.559650506265825, 56.978899645202432 ], [ 26.544250929236966, 57.009233710367425 ], [ 26.532933791361359, 57.025253404121258 ], [ 26.512624952879264, 57.044063625835634 ], [ 26.497277052693789, 57.055794175760582 ], [ 26.46203372607556, 57.061271877994727 ], [ 26.369377883282652, 57.044632065717224 ], [ 26.328915235949353, 57.071865546357856 ], [ 26.321318801121777, 57.097910467693907 ], [ 26.27165774940562, 57.087110093755769 ], [ 26.21517540921775, 57.08912547536039 ], [ 26.183187696754771, 57.082614244351873 ], [ 26.116783481772245, 57.078066718104537 ], [ 26.133216586676099, 57.097083645393866 ], [ 26.139882847315505, 57.108452460112915 ], [ 26.161328565560837, 57.128838812960794 ], [ 26.165824415864108, 57.134238999929892 ], [ 26.168149854931869, 57.143437405212069 ], [ 26.131666293964258, 57.172014472090211 ], [ 26.102520786305206, 57.201263333436088 ], [ 26.089291619612538, 57.209893297037979 ], [ 26.076114128863935, 57.21472504322611 ], [ 26.062161492658731, 57.217179674402416 ], [ 26.013430616929384, 57.221055406182018 ], [ 26.004128858859758, 57.243844713362819 ], [ 26.008469678632764, 57.246738593211489 ], [ 26.01436079291625, 57.249865017056891 ], [ 26.049139032440394, 57.24999420826606 ], [ 26.058595819241646, 57.251286119458825 ], [ 26.058595819241646, 57.265290432507413 ], [ 26.075804071400739, 57.274127102583691 ], [ 26.101280551955881, 57.278157863994181 ], [ 26.130271029984044, 57.276478380073172 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-082", "NAME_1": "Rugaju" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.860045606619451, 56.983007920978764 ], [ 26.871207716662752, 57.002644964993124 ], [ 26.868417188702267, 57.005900580047694 ], [ 26.860510694612856, 57.018018704499582 ], [ 26.901955193877086, 57.039257718069223 ], [ 26.929550408824298, 57.04979971048823 ], [ 26.953166538305084, 57.064837551411813 ], [ 26.979056430909566, 57.095585029525466 ], [ 26.995179478350224, 57.105145169114223 ], [ 27.008103809043519, 57.114503838081646 ], [ 27.049793031822958, 57.111831533198654 ], [ 27.097639597889099, 57.114109941320692 ], [ 27.097639597889099, 57.091325861898952 ], [ 27.118145269188801, 57.084490638432214 ], [ 27.147764571178016, 57.08904745467629 ], [ 27.197889545366195, 57.07765541496542 ], [ 27.270798598076794, 57.063984967132512 ], [ 27.304974717209404, 57.06626337525455 ], [ 27.325480388509106, 57.061706559909794 ], [ 27.314088348798236, 57.025252032655146 ], [ 27.289025862153778, 57.000189546010688 ], [ 27.254849743021225, 56.993354322543951 ], [ 27.261684966488019, 56.972848651244249 ], [ 27.28674745403174, 56.972848651244249 ], [ 27.314088348798236, 56.979683874711043 ], [ 27.332315611975901, 56.93639412488892 ], [ 27.291304269376496, 56.927280493300088 ], [ 27.266241782732095, 56.915888453589218 ], [ 27.225230440132691, 56.895382782289516 ], [ 27.200167953488233, 56.861206664056283 ], [ 27.165991835254999, 56.861206664056283 ], [ 27.083969150056191, 56.874877110989871 ], [ 27.03612258399005, 56.883990742578703 ], [ 26.985102573025301, 56.878233953733968 ], [ 26.971149936820098, 56.890920518966766 ], [ 26.962468296374766, 56.913270576575826 ], [ 26.953941684661004, 56.920711981772513 ], [ 26.92396935380259, 56.931719062184925 ], [ 26.911411980678338, 56.939315497012558 ], [ 26.911101922315822, 56.947712918416414 ], [ 26.914822625363854, 56.957867337207801 ], [ 26.917148065330935, 56.969339504714355 ], [ 26.911877068671743, 56.973835354118251 ], [ 26.90257531060206, 56.977969469215623 ], [ 26.878184034765354, 56.978357041943923 ], [ 26.869812452682538, 56.976264146872836 ], [ 26.860045606619451, 56.983007920978764 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-039", "NAME_1": "Jaunpiebalgas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.013430616929384, 57.221055406182018 ], [ 26.062161492658731, 57.217179674402416 ], [ 26.076114128863935, 57.21472504322611 ], [ 26.089291619612538, 57.209893297037979 ], [ 26.102520786305206, 57.201263333436088 ], [ 26.131666293964258, 57.172014472090211 ], [ 26.168149854931869, 57.143437405212069 ], [ 26.165824415864108, 57.134238999929892 ], [ 26.161328565560837, 57.128838812960794 ], [ 26.139882847315505, 57.108452460112915 ], [ 26.133216586676099, 57.097083645393866 ], [ 26.116783481772245, 57.078066718104537 ], [ 26.089601677975054, 57.086128241824895 ], [ 26.077044304850745, 57.088221136895925 ], [ 26.064952019719897, 57.08871206331105 ], [ 26.056270379274565, 57.084422919482108 ], [ 26.052859734589049, 57.080262966862392 ], [ 26.048828973178558, 57.076774806911772 ], [ 26.038390334446376, 57.076852322176876 ], [ 26.022577345368177, 57.079513658028873 ], [ 25.949661900276453, 57.100390937291877 ], [ 25.923100213204236, 57.097445379700503 ], [ 25.881234529949552, 57.097308586522047 ], [ 25.862446400081296, 57.120793748632593 ], [ 25.83896123797075, 57.120793748632593 ], [ 25.804516333961601, 57.134884846258615 ], [ 25.774768461295423, 57.153672976126927 ], [ 25.763808719396877, 57.169329751167027 ], [ 25.771637106467267, 57.199077622933942 ], [ 25.798253623405969, 57.20847168741841 ], [ 25.81860743068836, 57.206906010004332 ], [ 25.849920980768616, 57.195946268105786 ], [ 25.868709109737608, 57.184986525307863 ], [ 25.893759949262233, 57.184986525307863 ], [ 25.945427306624879, 57.191249234964175 ], [ 25.989266276017815, 57.206906010004332 ], [ 26.013430616929384, 57.221055406182018 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-001", "NAME_1": "Aglonas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 27.038019239796085, 56.180111191877984 ], [ 27.044065382811141, 56.175951240157588 ], [ 27.054193963180865, 56.173315741827992 ], [ 27.07760338708664, 56.170912787495126 ], [ 27.101632927717446, 56.17075775786418 ], [ 27.09822228393125, 56.179568590418114 ], [ 27.097602166306899, 56.181997382273323 ], [ 27.099617547012144, 56.18638987888977 ], [ 27.102408074972686, 56.18907705316343 ], [ 27.125869174822526, 56.195846665691022 ], [ 27.150828892339518, 56.208429877236995 ], [ 27.162301059846016, 56.210781154726476 ], [ 27.173049757840033, 56.208300686027826 ], [ 27.295936313909749, 56.203029690267954 ], [ 27.300171987647104, 56.181595953690305 ], [ 27.331237145877537, 56.160885848503085 ], [ 27.339003435660004, 56.140175742416545 ], [ 27.307938276530194, 56.124643163750989 ], [ 27.240630433547665, 56.111699347446915 ], [ 27.263929301995688, 56.072867899433959 ], [ 27.188855169230635, 56.054746556608279 ], [ 27.194032695752298, 56.010737582073716 ], [ 27.147434957956932, 55.98484995036489 ], [ 27.103425983422369, 55.987438713625693 ], [ 27.041295666062126, 55.982261187104086 ], [ 26.999875454788366, 55.990027476886496 ], [ 26.967739292134581, 56.007847804932226 ], [ 26.969444613578048, 56.013635566428206 ], [ 26.958282505333329, 56.027123115539325 ], [ 26.953631626298488, 56.034306139216937 ], [ 26.951926303955759, 56.041024074901088 ], [ 26.968669468121448, 56.060196030922043 ], [ 26.931100702435458, 56.058697415053643 ], [ 26.890793083833728, 56.105051174871789 ], [ 26.888467644765967, 56.128874009927586 ], [ 26.928487338220066, 56.124239223361428 ], [ 26.936759761953454, 56.135820618027083 ], [ 26.920214913587358, 56.145747527226547 ], [ 26.931796307353693, 56.157328920992882 ], [ 26.968194974118717, 56.168910314759216 ], [ 26.999630187183357, 56.17056480022535 ], [ 27.038019239796085, 56.180111191877984 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-078", "NAME_1": "Riebinu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.925364617782861, 56.447614244002125 ], [ 26.914667595732965, 56.433403225378527 ], [ 26.910016716698124, 56.425083320139095 ], [ 26.899939813171841, 56.418468736343073 ], [ 26.89761437320476, 56.411311551087181 ], [ 26.951771275224132, 56.372631741361772 ], [ 26.966499057785256, 56.359066676985549 ], [ 26.991148716040414, 56.33149730135932 ], [ 26.975800815854939, 56.320128485741009 ], [ 26.950841099237323, 56.319663397747604 ], [ 26.944329868228806, 56.312945462063396 ], [ 26.946500277665677, 56.304315497562129 ], [ 26.949135775995273, 56.297752591508868 ], [ 26.95983279804517, 56.284032498401075 ], [ 26.986187777743737, 56.263232734403118 ], [ 26.988513217710818, 56.247936510161765 ], [ 26.99724653499959, 56.238583076148018 ], [ 27.001587354772596, 56.230573229271101 ], [ 27.015695020608689, 56.22416535105009 ], [ 27.028872512256612, 56.215432033761317 ], [ 27.034298536748054, 56.2077839220903 ], [ 27.035693800728325, 56.198120428814718 ], [ 27.034608595110569, 56.186648261308164 ], [ 27.038019239796085, 56.180111191877984 ], [ 26.999630187183357, 56.17056480022535 ], [ 26.968194974118717, 56.168910314759216 ], [ 26.931796307353693, 56.157328920992882 ], [ 26.920214913587358, 56.145747527226547 ], [ 26.936759761953454, 56.135820618027083 ], [ 26.928487338220066, 56.124239223361428 ], [ 26.888467644765967, 56.128874009927586 ], [ 26.882428558730965, 56.152052055358013 ], [ 26.861750720319492, 56.162390974563777 ], [ 26.826598394300447, 56.176865461271973 ], [ 26.801784988386487, 56.185136597176211 ], [ 26.834869530204628, 56.199611083884406 ], [ 26.839005097707059, 56.214085570592601 ], [ 26.814191691793098, 56.253373464114077 ], [ 26.783174933276541, 56.282322438429787 ], [ 26.741819256453482, 56.290593573434649 ], [ 26.702531362932064, 56.313339196047025 ], [ 26.665311253611435, 56.321610331051886 ], [ 26.65083676690324, 56.336084818659401 ], [ 26.669446821113866, 56.369169360477599 ], [ 26.710802498836244, 56.383643847185795 ], [ 26.733548121448621, 56.396050550592406 ], [ 26.685989092022965, 56.429135091511228 ], [ 26.623955576788433, 56.449812930822077 ], [ 26.590871034970291, 56.445677362420327 ], [ 26.576396548262096, 56.433270659912978 ], [ 26.559854277352997, 56.439474011616312 ], [ 26.537108654740621, 56.445677362420327 ], [ 26.537108654740621, 56.466355201731119 ], [ 26.540530226188991, 56.489678859991386 ], [ 26.559495476634936, 56.486164863417685 ], [ 26.59639244965183, 56.488800360847961 ], [ 26.597012567276124, 56.494536445500557 ], [ 26.59732262473932, 56.495569973375552 ], [ 26.593136833697884, 56.496603502149867 ], [ 26.593756952221554, 56.501590277968944 ], [ 26.595152215302448, 56.506551215366244 ], [ 26.627760043591138, 56.543732408323933 ], [ 26.706411574234721, 56.546083685813414 ], [ 26.722276239257042, 56.543112290699639 ], [ 26.743670281558252, 56.558847765411997 ], [ 26.771110466874518, 56.556083075873232 ], [ 26.815655551562429, 56.540011705275958 ], [ 26.826094191193931, 56.524172879574678 ], [ 26.775451288446163, 56.512003079178726 ], [ 26.800927769001305, 56.507248847356379 ], [ 26.807594027842072, 56.498489692545263 ], [ 26.82030643059727, 56.495518297431431 ], [ 26.833225538927479, 56.494794827019632 ], [ 26.847333204763572, 56.495518297431431 ], [ 26.85787519718258, 56.492546902317656 ], [ 26.865936720003617, 56.485751451368344 ], [ 26.902265252239602, 56.479162705994042 ], [ 26.952701450311679, 56.476914781292123 ], [ 26.958437534064899, 56.461101793113244 ], [ 26.949755893619567, 56.458156236421132 ], [ 26.933116082241384, 56.454926458888963 ], [ 26.925364617782861, 56.447614244002125 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-109", "NAME_1": "Vilanu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.833225538927479, 56.494794827019632 ], [ 26.82030643059727, 56.495518297431431 ], [ 26.807594027842072, 56.498489692545263 ], [ 26.800927769001305, 56.507248847356379 ], [ 26.775451288446163, 56.512003079178726 ], [ 26.826094191193931, 56.524172879574678 ], [ 26.815655551562429, 56.540011705275958 ], [ 26.771110466874518, 56.556083075873232 ], [ 26.743670281558252, 56.558847765411997 ], [ 26.729252557359644, 56.578303941373747 ], [ 26.736538933824704, 56.587295641080971 ], [ 26.749716423673988, 56.595822251895356 ], [ 26.788835483870457, 56.607061876304499 ], [ 26.792401157287543, 56.610291652937406 ], [ 26.788525424608622, 56.615485134331436 ], [ 26.779688755431721, 56.621453762081444 ], [ 26.777208285833694, 56.632615872124745 ], [ 26.780928988881726, 56.644966538774725 ], [ 26.778138461820561, 56.655921943243072 ], [ 26.77751834509553, 56.663725084544978 ], [ 26.771317173348848, 56.677471015175172 ], [ 26.772557406798853, 56.681010851069914 ], [ 26.808306977984614, 56.665694674469648 ], [ 26.852315952519177, 56.657928384687182 ], [ 26.883381110749667, 56.637218278600642 ], [ 26.9144462689801, 56.600975593848545 ], [ 26.981754112862006, 56.593209304066079 ], [ 27.00505298131003, 56.562144145835646 ], [ 27.007641744570833, 56.523312697822746 ], [ 27.041295666062126, 56.46635990698411 ], [ 27.033529377178979, 56.448238564158373 ], [ 26.992109165005957, 56.450827327419177 ], [ 26.925364617782861, 56.447614244002125 ], [ 26.933116082241384, 56.454926458888963 ], [ 26.949755893619567, 56.458156236421132 ], [ 26.958437534064899, 56.461101793113244 ], [ 26.952701450311679, 56.476914781292123 ], [ 26.902265252239602, 56.479162705994042 ], [ 26.865936720003617, 56.485751451368344 ], [ 26.85787519718258, 56.492546902317656 ], [ 26.847333204763572, 56.495518297431431 ], [ 26.833225538927479, 56.494794827019632 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-012", "NAME_1": "Babites" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.95445041645354, 56.991383791928399 ], [ 23.967767367769795, 56.987684638435269 ], [ 23.992778761230852, 56.984532376168204 ], [ 24.000995313682779, 56.979261380408332 ], [ 23.994174025211066, 56.973163561449155 ], [ 23.988592970189416, 56.964688626578834 ], [ 23.94916385342907, 56.946782742429605 ], [ 23.942652622420553, 56.938669541865863 ], [ 23.917566341513407, 56.928326851802751 ], [ 23.899687950538464, 56.914024139202638 ], [ 23.856779810040166, 56.897933586066131 ], [ 23.822810865928716, 56.883630873466018 ], [ 23.844264936177865, 56.847874089717436 ], [ 23.854991971302411, 56.826420019468287 ], [ 23.824598705565791, 56.803178110481383 ], [ 23.781690565067493, 56.821056502355646 ], [ 23.769639926641275, 56.800047511983053 ], [ 23.734086540761211, 56.822009995964493 ], [ 23.718428582213278, 56.835962633069016 ], [ 23.70726647306924, 56.852137356453795 ], [ 23.669542677752361, 56.874900825212876 ], [ 23.626237827413775, 56.8892410350457 ], [ 23.600813022802754, 56.889292710989764 ], [ 23.587635532054151, 56.891204738907561 ], [ 23.506761916029575, 56.894615384492397 ], [ 23.492034132569131, 56.934638780455316 ], [ 23.549271474299076, 56.924751173427865 ], [ 23.590391775160299, 56.92296333469011 ], [ 23.613633684147203, 56.931902530177581 ], [ 23.638663432771182, 56.928326851802751 ], [ 23.672632376882689, 56.928326851802751 ], [ 23.706601320994139, 56.931902530177581 ], [ 23.76738785246738, 56.942629565302184 ], [ 23.779902726329738, 56.956932278801617 ], [ 23.801356796578887, 56.9497809220519 ], [ 23.863931166789882, 56.955144439164485 ], [ 23.903263628913351, 56.962295795914201 ], [ 23.937232573024801, 56.973022831038804 ], [ 23.95445041645354, 56.991383791928399 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-031", "NAME_1": "Garkalnes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.320200636650043, 56.96902944635184 ], [ 24.302527297396864, 56.99099193033328 ], [ 24.287902865824606, 56.999880276353622 ], [ 24.274415316713487, 57.006365668041099 ], [ 24.249920688988595, 57.012644355052942 ], [ 24.224444206634814, 57.021636053860789 ], [ 24.181294385927174, 57.047939358514554 ], [ 24.162383007569701, 57.052823973147838 ], [ 24.23198936301867, 57.072573562819628 ], [ 24.247286846310885, 57.060057439798982 ], [ 24.261193650366636, 57.041978595335877 ], [ 24.290397936815339, 57.030853152451016 ], [ 24.320992904299089, 57.028071791280126 ], [ 24.362713314667701, 57.057276078628092 ], [ 24.407215086207259, 57.061448119934767 ], [ 24.458670258425684, 57.072573562819628 ], [ 24.501781348930081, 57.094824447690087 ], [ 24.508734750508324, 57.105949890574948 ], [ 24.514297471950727, 57.079526964397871 ], [ 24.550455160876936, 57.083699004805226 ], [ 24.565530100633623, 57.060001151232143 ], [ 24.546093907607712, 57.061024109375126 ], [ 24.521064159883053, 57.052084912988335 ], [ 24.53179119410828, 57.00202541663964 ], [ 24.451338432023022, 57.00202541663964 ], [ 24.401278935674327, 56.994874059889924 ], [ 24.395915417662366, 56.968056472528133 ], [ 24.371677488825014, 56.944417404939259 ], [ 24.352011258212997, 56.956932278801617 ], [ 24.320200636650043, 56.96902944635184 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-052", "NAME_1": "Kekavas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.155404494222012, 56.902392687372583 ], [ 24.197004022217811, 56.882058010468768 ], [ 24.176803020542934, 56.86754032032951 ], [ 24.189317894405292, 56.851449768092323 ], [ 24.217923321404157, 56.828207859105362 ], [ 24.259043622265324, 56.824632180730532 ], [ 24.310890957351774, 56.824632180730532 ], [ 24.34198507914806, 56.851135707746664 ], [ 24.386241081260891, 56.842108465932938 ], [ 24.420367069484655, 56.839829503828526 ], [ 24.444017367807248, 56.837667955411803 ], [ 24.452182245214431, 56.837926336930877 ], [ 24.457763299336762, 56.837538764202577 ], [ 24.475850050639281, 56.832216092498641 ], [ 24.505305616660849, 56.818521836913192 ], [ 24.512695346812791, 56.817100735410577 ], [ 24.522978956813404, 56.795293281060026 ], [ 24.536983269861992, 56.777490749698302 ], [ 24.537603386587023, 56.770385240386531 ], [ 24.53310753808239, 56.759223131242493 ], [ 24.525459426411373, 56.75240184187146 ], [ 24.466432964409762, 56.763845649257291 ], [ 24.414585629323312, 56.776360523119592 ], [ 24.346647741100355, 56.787087558244195 ], [ 24.294800405114586, 56.78887539788127 ], [ 24.253680104253363, 56.78529971950644 ], [ 24.26261930064021, 56.762057809620217 ], [ 24.269770656490607, 56.745967257382972 ], [ 24.253680104253363, 56.738815900633256 ], [ 24.228650356528703, 56.751330775394933 ], [ 24.194681412417253, 56.740603740270387 ], [ 24.188165019300186, 56.717943050531346 ], [ 24.145576920538417, 56.728209824323926 ], [ 24.035563726984378, 56.720937509658313 ], [ 24.00812666231559, 56.709975491575676 ], [ 23.998204786621613, 56.721602687813743 ], [ 23.996344434647938, 56.730491034733461 ], [ 24.004357805068651, 56.737649103123601 ], [ 24.005170461247758, 56.762057809620217 ], [ 24.035563726984378, 56.767421327632121 ], [ 24.085623223333073, 56.762057809620217 ], [ 24.087411062070828, 56.779936201494479 ], [ 24.114228649432619, 56.801390271743628 ], [ 24.12316784581941, 56.821056502355646 ], [ 24.103501615207335, 56.835359215855078 ], [ 24.090986740445715, 56.846086250979681 ], [ 24.088146223669241, 56.876134365908229 ], [ 24.099387241128284, 56.878492337051682 ], [ 24.104038120163125, 56.883608303180608 ], [ 24.112254672615052, 56.892625841309496 ], [ 24.132718539828716, 56.898361925062773 ], [ 24.155404494222012, 56.902392687372583 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-062", "NAME_1": "Marupes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.942652622420553, 56.938669541865863 ], [ 23.97148807081777, 56.933243517374422 ], [ 24.002390577662993, 56.923709215308008 ], [ 24.026575147924746, 56.919626777054077 ], [ 24.040269402610818, 56.9100407990436 ], [ 24.062128533804753, 56.898439440327877 ], [ 24.066252713192171, 56.886115998854223 ], [ 24.035563726984378, 56.86754032032951 ], [ 24.012321817098154, 56.851449768092323 ], [ 23.967625838761421, 56.849661929354511 ], [ 23.885385237039031, 56.842510572604795 ], [ 23.854991971302411, 56.826420019468287 ], [ 23.844264936177865, 56.847874089717436 ], [ 23.822810865928716, 56.883630873466018 ], [ 23.856779810040166, 56.897933586066131 ], [ 23.899687950538464, 56.914024139202638 ], [ 23.917566341513407, 56.928326851802751 ], [ 23.942652622420553, 56.938669541865863 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-068", "NAME_1": "Olaines" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 24.066252713192171, 56.886115998854223 ], [ 24.070810174250141, 56.872497870880011 ], [ 24.088146223669241, 56.876134365908229 ], [ 24.090986740445715, 56.846086250979681 ], [ 24.103501615207335, 56.835359215855078 ], [ 24.12316784581941, 56.821056502355646 ], [ 24.114228649432619, 56.801390271743628 ], [ 24.087411062070828, 56.779936201494479 ], [ 24.085623223333073, 56.762057809620217 ], [ 24.035563726984378, 56.767421327632121 ], [ 24.005170461247758, 56.762057809620217 ], [ 24.004357805068651, 56.737649103123601 ], [ 23.996344434647938, 56.730491034733461 ], [ 23.941412388071228, 56.728579006815664 ], [ 23.935211216324547, 56.731240343566981 ], [ 23.924979282268055, 56.734108384993931 ], [ 23.919553256877293, 56.742144070292568 ], [ 23.912886997137207, 56.745425522869539 ], [ 23.900898064793864, 56.745838934918879 ], [ 23.828292678064599, 56.738139147303798 ], [ 23.818215772739677, 56.735503648074882 ], [ 23.811239454637132, 56.73255809228209 ], [ 23.801265902999035, 56.729535021224194 ], [ 23.783902622108315, 56.732093004288686 ], [ 23.767469517204461, 56.737932440829468 ], [ 23.756307407161103, 56.744133613475469 ], [ 23.764213901250514, 56.768266506893724 ], [ 23.759718051846619, 56.771883857154251 ], [ 23.769639926641275, 56.800047511983053 ], [ 23.781690565067493, 56.821056502355646 ], [ 23.824598705565791, 56.803178110481383 ], [ 23.854991971302411, 56.826420019468287 ], [ 23.885385237039031, 56.842510572604795 ], [ 23.967625838761421, 56.849661929354511 ], [ 24.012321817098154, 56.851449768092323 ], [ 24.035563726984378, 56.86754032032951 ], [ 24.066252713192171, 56.886115998854223 ] ] ], [ [ [ 24.230455055756181, 56.699422996873807 ], [ 24.209096307348659, 56.693464871406661 ], [ 24.195867139756672, 56.691527005067201 ], [ 24.184705030612633, 56.692560532942196 ], [ 24.179434034852818, 56.690441800348765 ], [ 24.173697951099541, 56.685119126846189 ], [ 24.172457716750216, 56.678504543949543 ], [ 24.160210401988422, 56.67010712344495 ], [ 24.148583204850979, 56.668065904317984 ], [ 24.131013218385306, 56.668272609892995 ], [ 24.117990757267592, 56.671373196215995 ], [ 24.08713992726581, 56.682070218265949 ], [ 24.033913202132567, 56.68821971316919 ], [ 24.000685256219583, 56.695635280843533 ], [ 24.00812666231559, 56.709975491575676 ], [ 24.035563726984378, 56.720937509658313 ], [ 24.145576920538417, 56.728209824323926 ], [ 24.188165019300186, 56.717943050531346 ], [ 24.20540844664248, 56.713786152908597 ], [ 24.230455055756181, 56.699422996873807 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-087", "NAME_1": "Salaspils" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.258718295213157, 56.872992254289102 ], [ 24.236691522295928, 56.904123847237713 ], [ 24.234676140691306, 56.930401313469815 ], [ 24.296588244751661, 56.921175495952355 ], [ 24.325193670851206, 56.915811977940393 ], [ 24.335920705975809, 56.896145747328376 ], [ 24.353799097850072, 56.910448460827752 ], [ 24.405646432936521, 56.926539013064996 ], [ 24.428888342822745, 56.924751173427865 ], [ 24.457349888186798, 56.886838079813515 ], [ 24.439831576765812, 56.887484035859529 ], [ 24.435645785724432, 56.884021715229949 ], [ 24.437816196060567, 56.878233953733968 ], [ 24.444482455800653, 56.872368678771466 ], [ 24.448203158848685, 56.86554739029981 ], [ 24.447583042123654, 56.857563381844557 ], [ 24.442932163088813, 56.845290229560419 ], [ 24.444017367807248, 56.837667955411803 ], [ 24.420367069484655, 56.839829503828526 ], [ 24.386241081260891, 56.842108465932938 ], [ 24.34198507914806, 56.851135707746664 ], [ 24.310890957351774, 56.824632180730532 ], [ 24.259043622265324, 56.824632180730532 ], [ 24.217923321404157, 56.828207859105362 ], [ 24.189317894405292, 56.851449768092323 ], [ 24.176803020542934, 56.86754032032951 ], [ 24.197004022217811, 56.882058010468768 ], [ 24.258718295213157, 56.872992254289102 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-095", "NAME_1": "Stopinu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.234676140691306, 56.930401313469815 ], [ 24.246510044303079, 56.940969143411223 ], [ 24.258447299803038, 56.946007595174365 ], [ 24.299064975867907, 56.955541897240721 ], [ 24.320200636650043, 56.96902944635184 ], [ 24.352011258212997, 56.956932278801617 ], [ 24.371677488825014, 56.944417404939259 ], [ 24.405646432936521, 56.926539013064996 ], [ 24.353799097850072, 56.910448460827752 ], [ 24.335920705975809, 56.896145747328376 ], [ 24.325193670851206, 56.915811977940393 ], [ 24.296588244751661, 56.921175495952355 ], [ 24.234676140691306, 56.930401313469815 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-090", "NAME_1": "Sejas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.550005730979706, 57.316346747304522 ], [ 24.566283807151933, 57.310042222770335 ], [ 24.573725213247997, 57.295727851359231 ], [ 24.575430535590726, 57.29087026585006 ], [ 24.578066033920322, 57.28875153325663 ], [ 24.589124790276855, 57.285340888571113 ], [ 24.601527133770162, 57.278984687193542 ], [ 24.622146029715509, 57.265574653347528 ], [ 24.643281691396908, 57.237178452723413 ], [ 24.681573928394073, 57.223070786887263 ], [ 24.66031890779135, 57.210250916046903 ], [ 24.615817137151168, 57.203297514468716 ], [ 24.619989177558466, 57.176874588291582 ], [ 24.65753754751978, 57.179655948563152 ], [ 24.67422571094778, 57.169921186713395 ], [ 24.675616391083565, 57.149060981079401 ], [ 24.665881629233809, 57.125419415173837 ], [ 24.618598497422681, 57.132372816752081 ], [ 24.568534005340041, 57.137935538194483 ], [ 24.553236521148506, 57.124028735038053 ], [ 24.508734750508324, 57.105949890574948 ], [ 24.467014340139656, 57.182437309734041 ], [ 24.425293929771044, 57.181046628698937 ], [ 24.394698962287237, 57.178265268427367 ], [ 24.372448077416834, 57.182437309734041 ], [ 24.444763455269253, 57.235283162088251 ], [ 24.48787454577365, 57.238064523259141 ], [ 24.476749102888789, 57.270050170878676 ], [ 24.461287311660101, 57.294765899626555 ], [ 24.472232700378811, 57.293712469754666 ], [ 24.550005730979706, 57.316346747304522 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-061", "NAME_1": "Malpils" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.984036086296328, 57.079927070078213 ], [ 24.9893070820562, 57.060600084426312 ], [ 25.01070112525673, 57.049437975282331 ], [ 25.040363396853252, 57.037914130033073 ], [ 25.048114862211094, 57.029103299277836 ], [ 25.055711297038727, 57.0249433457588 ], [ 25.063152704034053, 57.024245713768664 ], [ 25.092143182062159, 57.016003322895017 ], [ 25.100721469720042, 57.009802151148335 ], [ 25.125991244700174, 57.001585597797089 ], [ 25.147540316632274, 56.989389959878736 ], [ 25.138083529831022, 56.980062364286653 ], [ 25.142579380134293, 56.950787665418375 ], [ 25.036332635442761, 56.933992825308621 ], [ 25.000159132837666, 56.939573880330272 ], [ 24.976594679301002, 56.935413926811236 ], [ 24.954838900894515, 56.940607408205324 ], [ 24.938250767259092, 56.939108792336867 ], [ 24.918820427920366, 56.934638780455316 ], [ 24.890450066617291, 56.922675686533694 ], [ 24.877272576768007, 56.921487128128433 ], [ 24.840323927806992, 56.926034654375769 ], [ 24.807406040256524, 56.933889472521116 ], [ 24.816057621761843, 56.966268633790378 ], [ 24.817845460499598, 56.989510542777282 ], [ 24.845279392829696, 56.984960700775673 ], [ 24.889781164369197, 57.011383627852126 ], [ 24.88004640162012, 57.037806554029203 ], [ 24.888390483334149, 57.055885398492308 ], [ 24.86613959846369, 57.093433767554302 ], [ 24.878655721484336, 57.104559210439163 ], [ 24.89951592621901, 57.087871046111843 ], [ 24.93567361514522, 57.080917644533656 ], [ 24.984036086296328, 57.079927070078213 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-091", "NAME_1": "Siguldas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.147540316632274, 56.989389959878736 ], [ 25.125991244700174, 57.001585597797089 ], [ 25.100721469720042, 57.009802151148335 ], [ 25.092143182062159, 57.016003322895017 ], [ 25.063152704034053, 57.024245713768664 ], [ 25.055711297038727, 57.0249433457588 ], [ 25.048114862211094, 57.029103299277836 ], [ 25.040363396853252, 57.037914130033073 ], [ 25.01070112525673, 57.049437975282331 ], [ 24.9893070820562, 57.060600084426312 ], [ 24.984036086296328, 57.079927070078213 ], [ 24.93567361514522, 57.080917644533656 ], [ 24.89951592621901, 57.087871046111843 ], [ 24.878655721484336, 57.104559210439163 ], [ 24.86613959846369, 57.093433767554302 ], [ 24.888390483334149, 57.055885398492308 ], [ 24.88004640162012, 57.037806554029203 ], [ 24.889781164369197, 57.011383627852126 ], [ 24.845279392829696, 56.984960700775673 ], [ 24.817845460499598, 56.989510542777282 ], [ 24.774937320900619, 56.998449738264753 ], [ 24.726665663289737, 56.989510542777282 ], [ 24.669454810191326, 57.012752451764186 ], [ 24.630122348067914, 57.061024109375126 ], [ 24.650584145042217, 57.073964242955412 ], [ 24.678397752254455, 57.060057439798982 ], [ 24.707602039602421, 57.062838800070551 ], [ 24.759057211820846, 57.078136284262087 ], [ 24.749322449971089, 57.098996488996761 ], [ 24.766010613399089, 57.115684653324081 ], [ 24.77991741745484, 57.135154177922971 ], [ 24.79660558088284, 57.142107579501157 ], [ 24.804949663496132, 57.165749145406721 ], [ 24.823028507959236, 57.182437309734041 ], [ 24.861967557157016, 57.189390711312228 ], [ 24.884218442926795, 57.199125473162042 ], [ 24.900371942311267, 57.218678290270873 ], [ 24.934375033680851, 57.20839468027026 ], [ 24.967396274918144, 57.185011094786148 ], [ 24.973132358671421, 57.177750555843431 ], [ 24.975664504213455, 57.170670884953324 ], [ 24.978248324800347, 57.158733629453423 ], [ 24.983570998302923, 57.145013536345573 ], [ 24.984036086296328, 57.140750230938352 ], [ 24.987446730082524, 57.124678860341078 ], [ 25.026374629485531, 57.119228071218458 ], [ 25.067082243150992, 57.114531038976224 ], [ 25.112486889958006, 57.10983400673399 ], [ 25.137537729482631, 57.0894801994516 ], [ 25.168851279562887, 57.067560714755132 ], [ 25.13284069724034, 57.051903940614352 ], [ 25.150063149694574, 57.03311581074604 ], [ 25.168851279562887, 57.014327680877727 ], [ 25.167285602148809, 56.998670905837628 ], [ 25.147540316632274, 56.989389959878736 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-059", "NAME_1": "Madona" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.953324130104477, 56.846677123550364 ], [ 26.94401980986629, 56.840251776897958 ], [ 26.928465204105862, 56.831105048459165 ], [ 26.907536247999417, 56.817979234554002 ], [ 26.782944369586971, 56.707391669190145 ], [ 26.772557406798853, 56.681010851069914 ], [ 26.74392281748402, 56.696495154128058 ], [ 26.711043590889005, 56.707454896026604 ], [ 26.707912236060849, 56.723111671066761 ], [ 26.682861396536225, 56.721545993652683 ], [ 26.648416491627756, 56.716848960511072 ], [ 26.626497007830608, 56.704323541198448 ], [ 26.607708877962352, 56.69023244357237 ], [ 26.57639532788204, 56.691798120986448 ], [ 26.535687714216635, 56.677707024259746 ], [ 26.388514030997726, 56.677707024259746 ], [ 26.375579054130014, 56.635923163123437 ], [ 26.350774367143288, 56.60998159457489 ], [ 26.342712844322307, 56.60383209877233 ], [ 26.291346470263363, 56.58670136187834 ], [ 26.284215121630552, 56.605795803533454 ], [ 26.281269565837761, 56.610911770561756 ], [ 26.261994256129981, 56.616570339949192 ], [ 26.224632196019002, 56.609878241787385 ], [ 26.198225538577731, 56.6271381698906 ], [ 26.204891799217137, 56.635251370454341 ], [ 26.19109419084424, 56.642331041344448 ], [ 26.170010206905488, 56.645018216517428 ], [ 26.156470981850305, 56.650134181747035 ], [ 26.131046177239284, 56.653906562537827 ], [ 26.09223717630465, 56.643881334056289 ], [ 26.058130731248241, 56.629954536272805 ], [ 26.039992303102281, 56.626466376322185 ], [ 26.022887403730692, 56.629308580226791 ], [ 26.002113478154456, 56.639695543014852 ], [ 25.983613315701916, 56.665637112462719 ], [ 25.93209191291146, 56.637835191041233 ], [ 25.929818149787764, 56.64984996180624 ], [ 25.925115593909538, 56.654268296844407 ], [ 25.916278923833261, 56.659022529566073 ], [ 25.913798456033874, 56.664810289263414 ], [ 25.91565880710823, 56.668866889095625 ], [ 25.926975945883157, 56.671476549003501 ], [ 25.933332147260785, 56.675920722463331 ], [ 25.93570926317193, 56.681553453429103 ], [ 25.906822137031952, 56.697263088820478 ], [ 25.83437177903437, 56.712275092221716 ], [ 25.825535108958093, 56.740774644734017 ], [ 25.826930372938364, 56.74932709397018 ], [ 25.837317335726425, 56.756587632912897 ], [ 25.843828565835622, 56.764442451058244 ], [ 25.850804884837544, 56.77033356444241 ], [ 25.842743361117186, 56.789247138044971 ], [ 25.827705519294284, 56.800951850447518 ], [ 25.81199588390291, 56.801804511169223 ], [ 25.806259800149633, 56.804750067861335 ], [ 25.797113070811577, 56.811829738751442 ], [ 25.785795932935912, 56.818702704066538 ], [ 25.765487095353137, 56.82818533018883 ], [ 25.757546009740565, 56.851497223518038 ], [ 25.748151944356721, 56.867153998558138 ], [ 25.768505751639111, 56.879679417870818 ], [ 25.774768461295423, 56.890639160668684 ], [ 25.807647688789814, 56.895336192910975 ], [ 25.835829883142594, 56.900033225153209 ], [ 25.85931504525314, 56.906295934809521 ], [ 25.890628594434077, 56.900033225153209 ], [ 25.915679433958701, 56.906295934809521 ], [ 25.946992984038957, 56.906295934809521 ], [ 25.953255693695269, 56.925084064677833 ], [ 25.943861629210801, 56.932912452647543 ], [ 25.920376467100255, 56.943872194546088 ], [ 25.886358269818288, 56.964223537686109 ], [ 25.917829217444421, 56.975230618098522 ], [ 25.920774774136476, 56.981896877838608 ], [ 25.923565301197698, 56.992955634195141 ], [ 25.919999626881236, 57.000086981928632 ], [ 25.911162956805015, 57.006753242568038 ], [ 25.904341668333302, 57.013962103768051 ], [ 25.895660027887971, 57.026261095373229 ], [ 25.896745232606406, 57.037552394827117 ], [ 25.899535759667572, 57.05016144479481 ], [ 25.906202020306978, 57.061426906726354 ], [ 25.907597284287249, 57.0700051952835 ], [ 25.923100213204236, 57.097445379700503 ], [ 25.949661900276453, 57.100390937291877 ], [ 26.022577345368177, 57.079513658028873 ], [ 26.038390334446376, 57.076852322176876 ], [ 26.048828973178558, 57.076774806911772 ], [ 26.052859734589049, 57.080262966862392 ], [ 26.056270379274565, 57.084422919482108 ], [ 26.064952019719897, 57.08871206331105 ], [ 26.077044304850745, 57.088221136895925 ], [ 26.089601677975054, 57.086128241824895 ], [ 26.116783481772245, 57.078066718104537 ], [ 26.183187696754771, 57.082614244351873 ], [ 26.186541637386654, 57.058166650270664 ], [ 26.175581894588731, 57.034681488160118 ], [ 26.177147572002809, 57.006499293807337 ], [ 26.186541637386654, 56.984579809110869 ], [ 26.172450539760575, 56.965791679242557 ], [ 26.170884862346497, 56.953266259030613 ], [ 26.18184460514442, 56.953266259030613 ], [ 26.200632734113356, 56.951700581616535 ], [ 26.222552218809824, 56.928215419505989 ], [ 26.242906026092214, 56.929781096920067 ], [ 26.267956865616839, 56.931346774334145 ], [ 26.286744995485151, 56.940740839717932 ], [ 26.325886932635797, 56.931346774334145 ], [ 26.358766159230868, 56.931346774334145 ], [ 26.352503449574499, 56.948569226788379 ], [ 26.374422934270967, 56.956397614758089 ], [ 26.39321106413928, 56.970488711484847 ], [ 26.405736483451903, 56.989276841353103 ], [ 26.383816998755492, 57.004933616393259 ], [ 26.375988611685045, 57.031550133331962 ], [ 26.369377883282652, 57.044632065717224 ], [ 26.46203372607556, 57.061271877994727 ], [ 26.497277052693789, 57.055794175760582 ], [ 26.512624952879264, 57.044063625835634 ], [ 26.532933791361359, 57.025253404121258 ], [ 26.544250929236966, 57.009233710367425 ], [ 26.559650506265825, 56.978899645202432 ], [ 26.568177117979587, 56.94841055040655 ], [ 26.473060614955386, 56.854628578346194 ], [ 26.504374164136323, 56.832709093649726 ], [ 26.516899584348323, 56.824880706579336 ], [ 26.512202552106089, 56.812355286367335 ], [ 26.535687714216635, 56.801395544468789 ], [ 26.56073855374126, 56.809223931539179 ], [ 26.577961005296117, 56.804526899296945 ], [ 26.60927455537643, 56.818617996922967 ], [ 26.620234297274976, 56.832709093649726 ], [ 26.6734673320517, 56.867153998558138 ], [ 26.679730041708012, 56.884376450113052 ], [ 26.712609268303083, 56.903164579981365 ], [ 26.726700365929105, 56.890639160668684 ], [ 26.8002872070889, 56.895336192910975 ], [ 26.837863465926205, 56.900033225153209 ], [ 26.861348628036751, 56.900033225153209 ], [ 26.883268112733219, 56.88594212842645 ], [ 26.884833790147297, 56.873416708214506 ], [ 26.909884630571241, 56.873416708214506 ], [ 26.933369792681788, 56.86558832114406 ], [ 26.953324130104477, 56.846677123550364 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-057", "NAME_1": "Lubanas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.985102573025301, 56.878233953733968 ], [ 26.983707309944407, 56.870792548537281 ], [ 26.980761753252295, 56.865624905564914 ], [ 26.953324130104477, 56.846677123550364 ], [ 26.933369792681788, 56.86558832114406 ], [ 26.909884630571241, 56.873416708214506 ], [ 26.884833790147297, 56.873416708214506 ], [ 26.883268112733219, 56.88594212842645 ], [ 26.861348628036751, 56.900033225153209 ], [ 26.837863465926205, 56.900033225153209 ], [ 26.8002872070889, 56.895336192910975 ], [ 26.726700365929105, 56.890639160668684 ], [ 26.712609268303083, 56.903164579981365 ], [ 26.679730041708012, 56.884376450113052 ], [ 26.6734673320517, 56.867153998558138 ], [ 26.620234297274976, 56.832709093649726 ], [ 26.60927455537643, 56.818617996922967 ], [ 26.577961005296117, 56.804526899296945 ], [ 26.56073855374126, 56.809223931539179 ], [ 26.535687714216635, 56.801395544468789 ], [ 26.512202552106089, 56.812355286367335 ], [ 26.516899584348323, 56.824880706579336 ], [ 26.504374164136323, 56.832709093649726 ], [ 26.473060614955386, 56.854628578346194 ], [ 26.568177117979587, 56.94841055040655 ], [ 26.603678827016211, 56.953604030901261 ], [ 26.635201449687145, 56.96499868404203 ], [ 26.691063674049303, 56.978202013212297 ], [ 26.697419875426874, 56.973473618912351 ], [ 26.703776075905182, 56.974197089324207 ], [ 26.725996942305017, 56.982620348250464 ], [ 26.734833612381294, 56.988201402372795 ], [ 26.757622917763399, 56.992955634195141 ], [ 26.78154910740534, 56.99254222304512 ], [ 26.795811801973059, 56.989131578359604 ], [ 26.860045606619451, 56.983007920978764 ], [ 26.869812452682538, 56.976264146872836 ], [ 26.878184034765354, 56.978357041943923 ], [ 26.90257531060206, 56.977969469215623 ], [ 26.911877068671743, 56.973835354118251 ], [ 26.917148065330935, 56.969339504714355 ], [ 26.914822625363854, 56.957867337207801 ], [ 26.911101922315822, 56.947712918416414 ], [ 26.911411980678338, 56.939315497012558 ], [ 26.92396935380259, 56.931719062184925 ], [ 26.953941684661004, 56.920711981772513 ], [ 26.962468296374766, 56.913270576575826 ], [ 26.971149936820098, 56.890920518966766 ], [ 26.985102573025301, 56.878233953733968 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-102", "NAME_1": "Varaklanu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.772557406798853, 56.681010851069914 ], [ 26.771317173348848, 56.677471015175172 ], [ 26.77751834509553, 56.663725084544978 ], [ 26.778138461820561, 56.655921943243072 ], [ 26.780928988881726, 56.644966538774725 ], [ 26.777208285833694, 56.632615872124745 ], [ 26.779688755431721, 56.621453762081444 ], [ 26.788525424608622, 56.615485134331436 ], [ 26.792401157287543, 56.610291652937406 ], [ 26.788835483870457, 56.607061876304499 ], [ 26.749716423673988, 56.595822251895356 ], [ 26.736538933824704, 56.587295641080971 ], [ 26.729252557359644, 56.578303941373747 ], [ 26.743670281558252, 56.558847765411997 ], [ 26.722276239257042, 56.543112290699639 ], [ 26.706411574234721, 56.546083685813414 ], [ 26.627760043591138, 56.543732408323933 ], [ 26.608536410726742, 56.544714260254864 ], [ 26.595927361658369, 56.547039700221944 ], [ 26.586625603588743, 56.551432196838391 ], [ 26.583369989433436, 56.563524481969239 ], [ 26.593756952221554, 56.595150458326941 ], [ 26.522546827673921, 56.599853014205223 ], [ 26.484512973994526, 56.60613170031769 ], [ 26.401365593946991, 56.633856106474127 ], [ 26.375579054130014, 56.635923163123437 ], [ 26.388514030997726, 56.677707024259746 ], [ 26.535687714216635, 56.677707024259746 ], [ 26.57639532788204, 56.691798120986448 ], [ 26.607708877962352, 56.69023244357237 ], [ 26.626497007830608, 56.704323541198448 ], [ 26.648416491627756, 56.716848960511072 ], [ 26.682861396536225, 56.721545993652683 ], [ 26.707912236060849, 56.723111671066761 ], [ 26.711043590889005, 56.707454896026604 ], [ 26.74392281748402, 56.696495154128058 ], [ 26.772557406798853, 56.681010851069914 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-008", "NAME_1": "Amatas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.503922960975842, 56.994818797449511 ], [ 25.488191358744189, 56.99445425096286 ], [ 25.47263675298376, 56.989028225572099 ], [ 25.468761021204159, 56.988356432003684 ], [ 25.446901890010224, 56.99158620953591 ], [ 25.447366978003629, 56.981922716260328 ], [ 25.450157505064794, 56.977426865957057 ], [ 25.452637973763444, 56.96962372555447 ], [ 25.426696405214898, 56.948668931925624 ], [ 25.395845575213116, 56.937300117206632 ], [ 25.37222944483301, 56.941434231404628 ], [ 25.371609328107979, 56.94804881520065 ], [ 25.370265740971149, 56.952983914176286 ], [ 25.367165154648148, 56.959572659550588 ], [ 25.361687453313323, 56.966833198493305 ], [ 25.354556104680455, 56.97362864854324 ], [ 25.343704053898932, 56.977426865957057 ], [ 25.327425977726648, 56.977245998803767 ], [ 25.284121128287438, 56.964817816888683 ], [ 25.274819370217756, 56.958539129876897 ], [ 25.261796909100042, 56.952854722967061 ], [ 25.256991001333631, 56.947221992001289 ], [ 25.247327508058049, 56.942674465753953 ], [ 25.246707391333018, 56.939625556274393 ], [ 25.248412712776428, 56.937145087575686 ], [ 25.251668328730375, 56.934871324452047 ], [ 25.23399498857782, 56.934302884570457 ], [ 25.142579380134293, 56.950787665418375 ], [ 25.138083529831022, 56.980062364286653 ], [ 25.147540316632274, 56.989389959878736 ], [ 25.167285602148809, 56.998670905837628 ], [ 25.168851279562887, 57.014327680877727 ], [ 25.150063149694574, 57.03311581074604 ], [ 25.13284069724034, 57.051903940614352 ], [ 25.168851279562887, 57.067560714755132 ], [ 25.137537729482631, 57.0894801994516 ], [ 25.112486889958006, 57.10983400673399 ], [ 25.137537729482631, 57.111399684148068 ], [ 25.173548311805121, 57.11766239380438 ], [ 25.195467796501589, 57.133319168844537 ], [ 25.212690248955823, 57.145844589056537 ], [ 25.189205086845277, 57.163067040611395 ], [ 25.178245344047355, 57.181855170479707 ], [ 25.171982634391043, 57.206906010004332 ], [ 25.159457214179099, 57.227259817286722 ], [ 25.139103407796028, 57.233522526943034 ], [ 25.10465850288756, 57.233522526943034 ], [ 25.090567405261538, 57.247613624569112 ], [ 25.131275019826262, 57.266401754437368 ], [ 25.165719924734731, 57.263270399609212 ], [ 25.206427538400135, 57.26483607702329 ], [ 25.231478377924759, 57.28518988340636 ], [ 25.231478377924759, 57.296149626204283 ], [ 25.287842767529696, 57.280492851164126 ], [ 25.319156316710632, 57.258573366467658 ], [ 25.317590639296554, 57.231956849528956 ], [ 25.359863931275413, 57.231956849528956 ], [ 25.369257995759881, 57.219431430216275 ], [ 25.364560963517647, 57.205340332590254 ], [ 25.380217738557747, 57.188117880136019 ], [ 25.41153128773874, 57.186552202721941 ], [ 25.444410514333754, 57.170895428581161 ], [ 25.458501611959832, 57.156804330955083 ], [ 25.4960778716964, 57.152107298712849 ], [ 25.508603291009081, 57.156804330955083 ], [ 25.53208845311957, 57.156804330955083 ], [ 25.563402002300563, 57.147410266470615 ], [ 25.541482518503415, 57.122359426945991 ], [ 25.564967680613961, 57.112965361562146 ], [ 25.594715552380819, 57.10983400673399 ], [ 25.618200714491365, 57.080086134967132 ], [ 25.616635037077288, 57.065995037341054 ], [ 25.58688716441111, 57.050338262300954 ], [ 25.547745228159727, 57.020590390534096 ], [ 25.528957098291414, 57.020590390534096 ], [ 25.507037613594946, 57.036247165574196 ], [ 25.492946516868244, 57.026853101089728 ], [ 25.510168968423159, 57.008064971221415 ], [ 25.50399548410428, 56.994820478282406 ], [ 25.503922960975842, 56.994818797449511 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-030", "NAME_1": "Erglu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.488191358744189, 56.99445425096286 ], [ 25.503922960975842, 56.994818797449511 ], [ 25.50399548410428, 56.994820478282406 ], [ 25.517181837671671, 56.995126044531276 ], [ 25.565137567045042, 56.982103583413618 ], [ 25.582345819204193, 56.981896877838608 ], [ 25.602706332731032, 56.984377346537258 ], [ 25.634022250726275, 56.994712633381312 ], [ 25.638518101029547, 56.994764309325376 ], [ 25.638518101029547, 56.992955634195141 ], [ 25.636967808317706, 56.99021678307804 ], [ 25.639138217754521, 56.984480699324763 ], [ 25.63355716273287, 56.974868882892622 ], [ 25.629526401322323, 56.963086656124233 ], [ 25.69732588118444, 56.986134344824109 ], [ 25.705439080848862, 56.99367910370762 ], [ 25.727143182411908, 56.998691717948418 ], [ 25.754893426090746, 56.99329153097932 ], [ 25.769517856763684, 56.983498847393889 ], [ 25.779439731558341, 56.981018377795863 ], [ 25.787501255278698, 56.981690172263598 ], [ 25.796027866093141, 56.984997464161609 ], [ 25.813701206245639, 56.986754462448459 ], [ 25.822589553165301, 56.984997464161609 ], [ 25.829720899999529, 56.982413641776134 ], [ 25.833906691040966, 56.979726468401793 ], [ 25.837472365357371, 56.976780910810362 ], [ 25.841813185130377, 56.973835354118251 ], [ 25.844913770554058, 56.970269679801845 ], [ 25.850339796844139, 56.9663681104999 ], [ 25.854060499892114, 56.962569892186764 ], [ 25.886358269818288, 56.964223537686109 ], [ 25.920376467100255, 56.943872194546088 ], [ 25.943861629210801, 56.932912452647543 ], [ 25.953255693695269, 56.925084064677833 ], [ 25.946992984038957, 56.906295934809521 ], [ 25.915679433958701, 56.906295934809521 ], [ 25.890628594434077, 56.900033225153209 ], [ 25.85931504525314, 56.906295934809521 ], [ 25.835829883142594, 56.900033225153209 ], [ 25.807647688789814, 56.895336192910975 ], [ 25.774768461295423, 56.890639160668684 ], [ 25.768505751639111, 56.879679417870818 ], [ 25.748151944356721, 56.867153998558138 ], [ 25.757546009740565, 56.851497223518038 ], [ 25.765487095353137, 56.82818533018883 ], [ 25.746366815276303, 56.825937405486854 ], [ 25.73970055463684, 56.818366808181622 ], [ 25.748382195981549, 56.814671943555311 ], [ 25.748847283974953, 56.808832506115209 ], [ 25.746366815276303, 56.801132718500128 ], [ 25.734274530145456, 56.789350490832476 ], [ 25.730243767835589, 56.782322495886433 ], [ 25.692209914156194, 56.77048859317398 ], [ 25.668800490250419, 56.788988756525839 ], [ 25.641618687352548, 56.792115180371241 ], [ 25.605186802329058, 56.802476304737638 ], [ 25.561726922359583, 56.802579658424463 ], [ 25.505399610903282, 56.81309581242175 ], [ 25.506484815621718, 56.826712550943455 ], [ 25.504779494178308, 56.833068753220346 ], [ 25.501058791130276, 56.841957099240688 ], [ 25.492067092322429, 56.846246243069629 ], [ 25.483953891758688, 56.853842677897262 ], [ 25.484884066846178, 56.857046617007768 ], [ 25.483643833396172, 56.867175198276755 ], [ 25.55568078024379, 56.873944810804346 ], [ 25.53408003056893, 56.884951891216758 ], [ 25.527723830090679, 56.890067857345684 ], [ 25.520747511988077, 56.894201972443057 ], [ 25.51594160332229, 56.897922675491031 ], [ 25.516251661684805, 56.903193671250904 ], [ 25.519197219276236, 56.907896227129129 ], [ 25.524003127042647, 56.913632310882406 ], [ 25.532219678595254, 56.921409613762648 ], [ 25.53159956187028, 56.932649238171791 ], [ 25.522762891794002, 56.943501288053994 ], [ 25.516871779309156, 56.956317044495961 ], [ 25.508345167595394, 56.964481920104504 ], [ 25.507725050870363, 56.972750149399872 ], [ 25.49268720904746, 56.981276760214257 ], [ 25.488191358744189, 56.99445425096286 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-021", "NAME_1": "Cesvaines" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.321318801121777, 57.097910467693907 ], [ 26.328915235949353, 57.071865546357856 ], [ 26.369377883282652, 57.044632065717224 ], [ 26.375988611685045, 57.031550133331962 ], [ 26.383816998755492, 57.004933616393259 ], [ 26.405736483451903, 56.989276841353103 ], [ 26.39321106413928, 56.970488711484847 ], [ 26.374422934270967, 56.956397614758089 ], [ 26.352503449574499, 56.948569226788379 ], [ 26.358766159230868, 56.931346774334145 ], [ 26.325886932635797, 56.931346774334145 ], [ 26.286744995485151, 56.940740839717932 ], [ 26.267956865616839, 56.931346774334145 ], [ 26.242906026092214, 56.929781096920067 ], [ 26.222552218809824, 56.928215419505989 ], [ 26.200632734113356, 56.951700581616535 ], [ 26.18184460514442, 56.953266259030613 ], [ 26.170884862346497, 56.953266259030613 ], [ 26.172450539760575, 56.965791679242557 ], [ 26.186541637386654, 56.984579809110869 ], [ 26.177147572002809, 57.006499293807337 ], [ 26.175581894588731, 57.034681488160118 ], [ 26.186541637386654, 57.058166650270664 ], [ 26.183187696754771, 57.082614244351873 ], [ 26.21517540921775, 57.08912547536039 ], [ 26.27165774940562, 57.087110093755769 ], [ 26.321318801121777, 57.097910467693907 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-067", "NAME_1": "Ogre" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.468761021204159, 56.988356432003684 ], [ 25.47263675298376, 56.989028225572099 ], [ 25.488191358744189, 56.99445425096286 ], [ 25.49268720904746, 56.981276760214257 ], [ 25.507725050870363, 56.972750149399872 ], [ 25.508345167595394, 56.964481920104504 ], [ 25.516871779309156, 56.956317044495961 ], [ 25.522762891794002, 56.943501288053994 ], [ 25.53159956187028, 56.932649238171791 ], [ 25.532219678595254, 56.921409613762648 ], [ 25.524003127042647, 56.913632310882406 ], [ 25.519197219276236, 56.907896227129129 ], [ 25.516251661684805, 56.903193671250904 ], [ 25.51594160332229, 56.897922675491031 ], [ 25.520747511988077, 56.894201972443057 ], [ 25.527723830090679, 56.890067857345684 ], [ 25.53408003056893, 56.884951891216758 ], [ 25.55568078024379, 56.873944810804346 ], [ 25.483643833396172, 56.867175198276755 ], [ 25.484884066846178, 56.857046617007768 ], [ 25.483953891758688, 56.853842677897262 ], [ 25.492067092322429, 56.846246243069629 ], [ 25.501058791130276, 56.841957099240688 ], [ 25.504779494178308, 56.833068753220346 ], [ 25.506484815621718, 56.826712550943455 ], [ 25.505399610903282, 56.81309581242175 ], [ 25.437445103208915, 56.775191148152942 ], [ 25.391194696178275, 56.761264350369458 ], [ 25.378017206328991, 56.760049954441797 ], [ 25.365098097099462, 56.762840481503019 ], [ 25.353470899962019, 56.762530423140504 ], [ 25.353935987955481, 56.759326484029998 ], [ 25.356106398291615, 56.753383693802391 ], [ 25.326030714645754, 56.757982896893168 ], [ 25.29528323743142, 56.754520576263531 ], [ 25.26815310957835, 56.745218818193905 ], [ 25.257094354121136, 56.736123765699176 ], [ 25.293112827095285, 56.723359686999913 ], [ 25.298073765391962, 56.719328924690103 ], [ 25.296523471780802, 56.716280016109806 ], [ 25.295593295793935, 56.713024400155916 ], [ 25.278385043634842, 56.696849676771137 ], [ 25.217716913304912, 56.708218492389506 ], [ 25.215546502069401, 56.70522125885401 ], [ 25.200456984302377, 56.697805691179667 ], [ 25.176298666150501, 56.703333667314894 ], [ 25.153483106859881, 56.708554389173685 ], [ 25.148987258355248, 56.714523016923692 ], [ 25.097465854665415, 56.737157294473548 ], [ 25.074967533025188, 56.753948557080207 ], [ 25.059384292850837, 56.769531797254615 ], [ 25.041574875380149, 56.789567392021524 ], [ 25.005956041338209, 56.79401974571465 ], [ 24.968111029999989, 56.798472100307151 ], [ 24.943623081539954, 56.809602985889057 ], [ 24.923587487672421, 56.800698277603374 ], [ 24.885742476334201, 56.814055340481559 ], [ 24.843445110403479, 56.827412403359688 ], [ 24.816730984647222, 56.834090934349092 ], [ 24.805600099065316, 56.807376808592835 ], [ 24.778885973309002, 56.800698277603374 ], [ 24.783338327002184, 56.780662682836521 ], [ 24.761076555838372, 56.758400911672709 ], [ 24.724864128776517, 56.736436264821748 ], [ 24.704112175436535, 56.753037828033314 ], [ 24.697520378662546, 56.756903387581247 ], [ 24.678635353139043, 56.760212482619977 ], [ 24.661062045477024, 56.76329173342674 ], [ 24.652842643972804, 56.767523505005727 ], [ 24.645762565689836, 56.773138738761759 ], [ 24.625417514206902, 56.783148504300016 ], [ 24.618418815575865, 56.784857488682121 ], [ 24.596202019507587, 56.806423243937502 ], [ 24.587657097596946, 56.812201238796092 ], [ 24.616611454355109, 56.824632180730532 ], [ 24.666670950703804, 56.853237607729397 ], [ 24.700639894815254, 56.838934894229965 ], [ 24.736396678563835, 56.865752481591699 ], [ 24.702427734452385, 56.874691677079227 ], [ 24.693273497573841, 56.895471531885676 ], [ 24.715887079025435, 56.897147529135111 ], [ 24.738056267682566, 56.909394842997585 ], [ 24.760277134082457, 56.914975898019236 ], [ 24.807406040256524, 56.933889472521116 ], [ 24.840323927806992, 56.926034654375769 ], [ 24.877272576768007, 56.921487128128433 ], [ 24.890450066617291, 56.922675686533694 ], [ 24.918820427920366, 56.934638780455316 ], [ 24.938250767259092, 56.939108792336867 ], [ 24.954838900894515, 56.940607408205324 ], [ 24.976594679301002, 56.935413926811236 ], [ 25.000159132837666, 56.939573880330272 ], [ 25.036332635442761, 56.933992825308621 ], [ 25.142579380134293, 56.950787665418375 ], [ 25.23399498857782, 56.934302884570457 ], [ 25.251668328730375, 56.934871324452047 ], [ 25.248412712776428, 56.937145087575686 ], [ 25.246707391333018, 56.939625556274393 ], [ 25.247327508058049, 56.942674465753953 ], [ 25.256991001333631, 56.947221992001289 ], [ 25.261796909100042, 56.952854722967061 ], [ 25.274819370217756, 56.958539129876897 ], [ 25.284121128287438, 56.964817816888683 ], [ 25.327425977726648, 56.977245998803767 ], [ 25.343704053898932, 56.977426865957057 ], [ 25.354556104680455, 56.97362864854324 ], [ 25.361687453313323, 56.966833198493305 ], [ 25.367165154648148, 56.959572659550588 ], [ 25.370265740971149, 56.952983914176286 ], [ 25.371609328107979, 56.94804881520065 ], [ 25.37222944483301, 56.941434231404628 ], [ 25.395845575213116, 56.937300117206632 ], [ 25.426696405214898, 56.948668931925624 ], [ 25.452637973763444, 56.96962372555447 ], [ 25.450157505064794, 56.977426865957057 ], [ 25.447366978003629, 56.981922716260328 ], [ 25.446901890010224, 56.99158620953591 ], [ 25.468761021204159, 56.988356432003684 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-080", "NAME_1": "Ropazu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.807406040256524, 56.933889472521116 ], [ 24.760277134082457, 56.914975898019236 ], [ 24.738056267682566, 56.909394842997585 ], [ 24.715887079025435, 56.897147529135111 ], [ 24.693273497573841, 56.895471531885676 ], [ 24.574345330872291, 56.886657213559545 ], [ 24.520188428852919, 56.900067247405502 ], [ 24.507010939003635, 56.896475735566696 ], [ 24.511351759675961, 56.877872219427331 ], [ 24.507786086258875, 56.873014634817537 ], [ 24.499879592169407, 56.87035329896554 ], [ 24.491818068449106, 56.871619370837266 ], [ 24.485616895803105, 56.875365912306961 ], [ 24.479725783318202, 56.880481879335207 ], [ 24.469287143686699, 56.884176743961518 ], [ 24.457349888186798, 56.886838079813515 ], [ 24.428888342822745, 56.924751173427865 ], [ 24.405646432936521, 56.926539013064996 ], [ 24.371677488825014, 56.944417404939259 ], [ 24.395915417662366, 56.968056472528133 ], [ 24.401278935674327, 56.994874059889924 ], [ 24.451338432023022, 57.00202541663964 ], [ 24.53179119410828, 57.00202541663964 ], [ 24.521064159883053, 57.052084912988335 ], [ 24.546093907607712, 57.061024109375126 ], [ 24.565530100633623, 57.060001151232143 ], [ 24.580062851719219, 57.059236269738051 ], [ 24.630122348067914, 57.061024109375126 ], [ 24.669454810191326, 57.012752451764186 ], [ 24.726665663289737, 56.989510542777282 ], [ 24.774937320900619, 56.998449738264753 ], [ 24.817845460499598, 56.989510542777282 ], [ 24.816057621761843, 56.966268633790378 ], [ 24.807406040256524, 56.933889472521116 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-035", "NAME_1": "Ikskiles" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.512695346812791, 56.817100735410577 ], [ 24.505305616660849, 56.818521836913192 ], [ 24.475850050639281, 56.832216092498641 ], [ 24.457763299336762, 56.837538764202577 ], [ 24.452182245214431, 56.837926336930877 ], [ 24.444017367807248, 56.837667955411803 ], [ 24.442932163088813, 56.845290229560419 ], [ 24.447583042123654, 56.857563381844557 ], [ 24.448203158848685, 56.86554739029981 ], [ 24.444482455800653, 56.872368678771466 ], [ 24.437816196060567, 56.878233953733968 ], [ 24.435645785724432, 56.884021715229949 ], [ 24.439831576765812, 56.887484035859529 ], [ 24.457349888186798, 56.886838079813515 ], [ 24.469287143686699, 56.884176743961518 ], [ 24.479725783318202, 56.880481879335207 ], [ 24.485616895803105, 56.875365912306961 ], [ 24.491818068449106, 56.871619370837266 ], [ 24.499879592169407, 56.87035329896554 ], [ 24.507786086258875, 56.873014634817537 ], [ 24.511351759675961, 56.877872219427331 ], [ 24.507010939003635, 56.896475735566696 ], [ 24.520188428852919, 56.900067247405502 ], [ 24.574345330872291, 56.886657213559545 ], [ 24.693273497573841, 56.895471531885676 ], [ 24.702427734452385, 56.874691677079227 ], [ 24.736396678563835, 56.865752481591699 ], [ 24.700639894815254, 56.838934894229965 ], [ 24.666670950703804, 56.853237607729397 ], [ 24.616611454355109, 56.824632180730532 ], [ 24.587657097596946, 56.812201238796092 ], [ 24.565928581239007, 56.816433009475759 ], [ 24.525563998679559, 56.814276434309988 ], [ 24.512695346812791, 56.817100735410577 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-013", "NAME_1": "Baldones" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.525459426411373, 56.75240184187146 ], [ 24.521893752094968, 56.713644517780267 ], [ 24.482361280748478, 56.704704494916484 ], [ 24.443397251082274, 56.684240627702764 ], [ 24.42789432126591, 56.677677720750182 ], [ 24.414975212935701, 56.674267076064666 ], [ 24.383659294940514, 56.670856432278526 ], [ 24.376062860112881, 56.66840180110222 ], [ 24.372962273789881, 56.666308906031134 ], [ 24.374047479407636, 56.659590969447663 ], [ 24.355358623901338, 56.661563541524174 ], [ 24.335858595197976, 56.663621730858154 ], [ 24.294569125564692, 56.675455634469927 ], [ 24.274725375975322, 56.683956406862649 ], [ 24.263408237200395, 56.690441800348765 ], [ 24.257827183078007, 56.701190497443463 ], [ 24.245683221103775, 56.70367096614217 ], [ 24.230455055756181, 56.699422996873807 ], [ 24.20540844664248, 56.713786152908597 ], [ 24.188165019300186, 56.717943050531346 ], [ 24.194681412417253, 56.740603740270387 ], [ 24.228650356528703, 56.751330775394933 ], [ 24.253680104253363, 56.738815900633256 ], [ 24.269770656490607, 56.745967257382972 ], [ 24.26261930064021, 56.762057809620217 ], [ 24.253680104253363, 56.78529971950644 ], [ 24.294800405114586, 56.78887539788127 ], [ 24.346647741100355, 56.787087558244195 ], [ 24.414585629323312, 56.776360523119592 ], [ 24.466432964409762, 56.763845649257291 ], [ 24.525459426411373, 56.75240184187146 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-051", "NAME_1": "Keguma" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.521893752094968, 56.713644517780267 ], [ 24.525459426411373, 56.75240184187146 ], [ 24.53310753808239, 56.759223131242493 ], [ 24.537603386587023, 56.770385240386531 ], [ 24.536983269861992, 56.777490749698302 ], [ 24.522978956813404, 56.795293281060026 ], [ 24.512695346812791, 56.817100735410577 ], [ 24.525563998679559, 56.814276434309988 ], [ 24.565928581239007, 56.816433009475759 ], [ 24.587657097596946, 56.812201238796092 ], [ 24.596202019507587, 56.806423243937502 ], [ 24.618418815575865, 56.784857488682121 ], [ 24.625417514206902, 56.783148504300016 ], [ 24.645762565689836, 56.773138738761759 ], [ 24.652842643972804, 56.767523505005727 ], [ 24.661062045477024, 56.76329173342674 ], [ 24.678635353139043, 56.760212482619977 ], [ 24.697520378662546, 56.756903387581247 ], [ 24.704112175436535, 56.753037828033314 ], [ 24.724864128776517, 56.736436264821748 ], [ 24.761076555838372, 56.758400911672709 ], [ 24.783338327002184, 56.780662682836521 ], [ 24.778885973309002, 56.800698277603374 ], [ 24.805600099065316, 56.807376808592835 ], [ 24.816730984647222, 56.834090934349092 ], [ 24.843445110403479, 56.827412403359688 ], [ 24.885742476334201, 56.814055340481559 ], [ 24.923587487672421, 56.800698277603374 ], [ 24.903551892905512, 56.787341214725245 ], [ 24.872385413456072, 56.767305619958393 ], [ 24.852349818689163, 56.762853266265211 ], [ 24.845671287699759, 56.738365317805119 ], [ 24.818957161943445, 56.729460608620172 ], [ 24.799754982406512, 56.715212373352301 ], [ 24.817773611862663, 56.711897095474569 ], [ 24.834564649638878, 56.708807684127294 ], [ 24.852389025533057, 56.701708144515237 ], [ 24.868174675221042, 56.695420639650763 ], [ 24.878173388990717, 56.682521200393069 ], [ 24.905202670466849, 56.647650457502607 ], [ 24.919688347439262, 56.640204168987168 ], [ 24.938080274684921, 56.638210354024579 ], [ 24.957106048605226, 56.631887675775602 ], [ 24.975142934298958, 56.625893627788685 ], [ 24.991709831343599, 56.620388087939887 ], [ 25.024343703099419, 56.624554348404445 ], [ 25.026669142167179, 56.620058499000493 ], [ 25.019382764802742, 56.608121243500534 ], [ 25.049510125292045, 56.611996975280135 ], [ 25.056796501757105, 56.601325792551279 ], [ 25.042223747927608, 56.590034492198015 ], [ 24.968946566730665, 56.581559557327694 ], [ 24.949987336346453, 56.578568175680743 ], [ 24.732475212660916, 56.544249173160779 ], [ 24.657079298870542, 56.543577378693044 ], [ 24.664365676234979, 56.556832383807432 ], [ 24.671341994337524, 56.566780097023809 ], [ 24.681418897863807, 56.571327623271145 ], [ 24.697231886942006, 56.576236883825118 ], [ 24.697128534154501, 56.578872382154657 ], [ 24.691185743926951, 56.581662910115199 ], [ 24.673667433405285, 56.586546332247394 ], [ 24.666070997678389, 56.587166449871745 ], [ 24.661420118643548, 56.588329168955966 ], [ 24.660334913925112, 56.5904995792921 ], [ 24.662970412254708, 56.593961899921737 ], [ 24.662505324261303, 56.596855781569047 ], [ 24.656769239608707, 56.599801337361782 ], [ 24.629897495073294, 56.601454982861128 ], [ 24.617185093217472, 56.607191067513725 ], [ 24.599666781796543, 56.620678615725524 ], [ 24.59284549332483, 56.643028673334584 ], [ 24.58974490700183, 56.661037910271318 ], [ 24.634083286114731, 56.676850898450198 ], [ 24.600907017045188, 56.707029933984245 ], [ 24.556051873095441, 56.706978258040124 ], [ 24.521893752094968, 56.713644517780267 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-034", "NAME_1": "Iecavas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.245683221103775, 56.70367096614217 ], [ 24.257827183078007, 56.701190497443463 ], [ 24.263408237200395, 56.690441800348765 ], [ 24.274725375975322, 56.683956406862649 ], [ 24.294569125564692, 56.675455634469927 ], [ 24.335858595197976, 56.663621730858154 ], [ 24.355358623901338, 56.661563541524174 ], [ 24.368101810450185, 56.619030677323849 ], [ 24.309103118614019, 56.611879320574133 ], [ 24.321617992476376, 56.56360766296325 ], [ 24.34843557983811, 56.565395501701005 ], [ 24.387768041961522, 56.552880627838704 ], [ 24.380616685211862, 56.529638718851743 ], [ 24.34485990146328, 56.536790075601459 ], [ 24.300163923126547, 56.535002235964384 ], [ 24.251892265515608, 56.518911683727197 ], [ 24.234013873641345, 56.501033291852934 ], [ 24.194681412417253, 56.509972488239725 ], [ 24.173227342168104, 56.517123844989442 ], [ 24.1499854331812, 56.524275201739158 ], [ 24.105289453945147, 56.529638718851743 ], [ 24.078871697970442, 56.535464179028622 ], [ 24.088380160715815, 56.550760403269976 ], [ 24.10527835541177, 56.5639637324403 ], [ 24.11023929190975, 56.574944973531672 ], [ 24.106673617593344, 56.580370998922433 ], [ 24.094271274999301, 56.581766262003384 ], [ 24.081558872244159, 56.581895454111873 ], [ 24.055617302796293, 56.58574534836913 ], [ 24.040889520235169, 56.592411607209897 ], [ 24.026575147924746, 56.602746894053894 ], [ 24.02647179513724, 56.607837023559739 ], [ 24.030037468554326, 56.608793037069006 ], [ 24.039339226624008, 56.608793037069006 ], [ 24.049106072687096, 56.610989284927541 ], [ 24.057477654769912, 56.619076647069562 ], [ 24.055152214802831, 56.623779202048524 ], [ 24.051896599748261, 56.627964993089904 ], [ 24.050346307036421, 56.631840724869505 ], [ 24.050966423761452, 56.635251370454341 ], [ 24.046160515994984, 56.637757677574712 ], [ 24.036393669931897, 56.641478379723424 ], [ 24.009987013389946, 56.658867499035807 ], [ 24.006731398335376, 56.664758613319293 ], [ 24.00890180777219, 56.666205553243685 ], [ 24.017738477848468, 56.662743231714728 ], [ 24.023474561601745, 56.658505763829908 ], [ 24.034533318857541, 56.659487617559478 ], [ 24.042129753685174, 56.661244614947009 ], [ 24.033913202132567, 56.68821971316919 ], [ 24.08713992726581, 56.682070218265949 ], [ 24.117990757267592, 56.671373196215995 ], [ 24.131013218385306, 56.668272609892995 ], [ 24.148583204850979, 56.668065904317984 ], [ 24.160210401988422, 56.67010712344495 ], [ 24.172457716750216, 56.678504543949543 ], [ 24.173697951099541, 56.685119126846189 ], [ 24.179434034852818, 56.690441800348765 ], [ 24.184705030612633, 56.692560532942196 ], [ 24.195867139756672, 56.691527005067201 ], [ 24.209096307348659, 56.693464871406661 ], [ 24.230455055756181, 56.699422996873807 ], [ 24.245683221103775, 56.70367096614217 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-072", "NAME_1": "Plavinu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.765487095353137, 56.82818533018883 ], [ 25.785795932935912, 56.818702704066538 ], [ 25.797113070811577, 56.811829738751442 ], [ 25.806259800149633, 56.804750067861335 ], [ 25.81199588390291, 56.801804511169223 ], [ 25.827705519294284, 56.800951850447518 ], [ 25.842743361117186, 56.789247138044971 ], [ 25.850804884837544, 56.77033356444241 ], [ 25.843828565835622, 56.764442451058244 ], [ 25.837317335726425, 56.756587632912897 ], [ 25.826930372938364, 56.74932709397018 ], [ 25.825535108958093, 56.740774644734017 ], [ 25.83437177903437, 56.712275092221716 ], [ 25.906822137031952, 56.697263088820478 ], [ 25.93570926317193, 56.681553453429103 ], [ 25.933332147260785, 56.675920722463331 ], [ 25.926975945883157, 56.671476549003501 ], [ 25.91565880710823, 56.668866889095625 ], [ 25.913798456033874, 56.664810289263414 ], [ 25.916278923833261, 56.659022529566073 ], [ 25.925115593909538, 56.654268296844407 ], [ 25.929818149787764, 56.64984996180624 ], [ 25.93209191291146, 56.637835191041233 ], [ 25.883257684394607, 56.623572496473514 ], [ 25.830961135248174, 56.613237210528837 ], [ 25.788276400735299, 56.609309801006475 ], [ 25.756908806795991, 56.612255356799267 ], [ 25.744041375309223, 56.617267971040008 ], [ 25.711330194233085, 56.605847480376895 ], [ 25.688334180577954, 56.600783190192033 ], [ 25.646734652582154, 56.596390693575643 ], [ 25.601466099281026, 56.578924058998098 ], [ 25.579400261612761, 56.576288561567821 ], [ 25.569788446079883, 56.576701971818522 ], [ 25.509043815819439, 56.578802801607992 ], [ 25.493581576728388, 56.589056707900738 ], [ 25.498789909526693, 56.602362371825961 ], [ 25.495534701864983, 56.611843166029246 ], [ 25.520202960797974, 56.61369939730929 ], [ 25.53133384637988, 56.642639700361826 ], [ 25.582535920596229, 56.676032357107545 ], [ 25.5691788577181, 56.711651192048862 ], [ 25.615928578241267, 56.716103545741987 ], [ 25.615928578241267, 56.738365317805119 ], [ 25.595892983474414, 56.751722380683304 ], [ 25.600345338066859, 56.765079443561433 ], [ 25.627059463823173, 56.762853266265211 ], [ 25.655999766875709, 56.753948557080207 ], [ 25.692209914156194, 56.77048859317398 ], [ 25.730243767835589, 56.782322495886433 ], [ 25.734274530145456, 56.789350490832476 ], [ 25.746366815276303, 56.801132718500128 ], [ 25.748847283974953, 56.808832506115209 ], [ 25.748382195981549, 56.814671943555311 ], [ 25.73970055463684, 56.818366808181622 ], [ 25.746366815276303, 56.825937405486854 ], [ 25.765487095353137, 56.82818533018883 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-046", "NAME_1": "Kokneses" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.505399610903282, 56.81309581242175 ], [ 25.561726922359583, 56.802579658424463 ], [ 25.605186802329058, 56.802476304737638 ], [ 25.641618687352548, 56.792115180371241 ], [ 25.668800490250419, 56.788988756525839 ], [ 25.692209914156194, 56.77048859317398 ], [ 25.655999766875709, 56.753948557080207 ], [ 25.627059463823173, 56.762853266265211 ], [ 25.600345338066859, 56.765079443561433 ], [ 25.595892983474414, 56.751722380683304 ], [ 25.615928578241267, 56.738365317805119 ], [ 25.615928578241267, 56.716103545741987 ], [ 25.5691788577181, 56.711651192048862 ], [ 25.582535920596229, 56.676032357107545 ], [ 25.53133384637988, 56.642639700361826 ], [ 25.520202960797974, 56.61369939730929 ], [ 25.495534701864983, 56.611843166029246 ], [ 25.487233919809512, 56.613470769860101 ], [ 25.464772982986744, 56.612901108699191 ], [ 25.423106316103599, 56.627305406019616 ], [ 25.398448112490371, 56.630723374783884 ], [ 25.366709831493495, 56.614365952326807 ], [ 25.330170117756722, 56.597601629811322 ], [ 25.293373786970676, 56.591109263881378 ], [ 25.293132892768767, 56.631508814779977 ], [ 25.293132892768767, 56.676032357107545 ], [ 25.278385043634842, 56.696849676771137 ], [ 25.295593295793935, 56.713024400155916 ], [ 25.296523471780802, 56.716280016109806 ], [ 25.298073765391962, 56.719328924690103 ], [ 25.293112827095285, 56.723359686999913 ], [ 25.257094354121136, 56.736123765699176 ], [ 25.26815310957835, 56.745218818193905 ], [ 25.29528323743142, 56.754520576263531 ], [ 25.326030714645754, 56.757982896893168 ], [ 25.356106398291615, 56.753383693802391 ], [ 25.353935987955481, 56.759326484029998 ], [ 25.353470899962019, 56.762530423140504 ], [ 25.365098097099462, 56.762840481503019 ], [ 25.378017206328991, 56.760049954441797 ], [ 25.391194696178275, 56.761264350369458 ], [ 25.437445103208915, 56.775191148152942 ], [ 25.505399610903282, 56.81309581242175 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-002", "NAME_1": "Aizkraukles" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.217716913304912, 56.708218492389506 ], [ 25.278385043634842, 56.696849676771137 ], [ 25.293132892768767, 56.676032357107545 ], [ 25.293132892768767, 56.631508814779977 ], [ 25.293373786970676, 56.591109263881378 ], [ 25.235362175723822, 56.585638739136471 ], [ 25.215342643747988, 56.5888939476975 ], [ 25.188987085785357, 56.601004367657424 ], [ 25.163096550165619, 56.612901108699191 ], [ 25.13860087922717, 56.619146840953931 ], [ 25.179597858754164, 56.640413523065604 ], [ 25.181824035151067, 56.660449117832513 ], [ 25.168466973172258, 56.680484711700046 ], [ 25.176298666150501, 56.703333667314894 ], [ 25.200456984302377, 56.697805691179667 ], [ 25.215546502069401, 56.70522125885401 ], [ 25.217716913304912, 56.708218492389506 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-092", "NAME_1": "Skriveru" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.097465854665415, 56.737157294473548 ], [ 25.148987258355248, 56.714523016923692 ], [ 25.153483106859881, 56.708554389173685 ], [ 25.176298666150501, 56.703333667314894 ], [ 25.168466973172258, 56.680484711700046 ], [ 25.181824035151067, 56.660449117832513 ], [ 25.179597858754164, 56.640413523065604 ], [ 25.13860087922717, 56.619146840953931 ], [ 25.118093295069514, 56.624375717865064 ], [ 25.080179878598528, 56.621497567158997 ], [ 25.049510125292045, 56.611996975280135 ], [ 25.019382764802742, 56.608121243500534 ], [ 25.026669142167179, 56.620058499000493 ], [ 25.024343703099419, 56.624554348404445 ], [ 25.021243116776418, 56.632124945709677 ], [ 25.01488691629811, 56.640935777364234 ], [ 25.017367384996817, 56.671683255477831 ], [ 25.016902297003412, 56.681501777485039 ], [ 25.019537795332951, 56.687547918701455 ], [ 25.024498731830988, 56.69054515223695 ], [ 25.032715285182235, 56.692818915360647 ], [ 25.041758660833523, 56.694162503396797 ], [ 25.055246209045265, 56.701371365496072 ], [ 25.053695916333481, 56.706099758896755 ], [ 25.046564568599933, 56.708218492389506 ], [ 25.041913689565092, 56.7130760769993 ], [ 25.036125928968431, 56.716796780047332 ], [ 25.036642693805277, 56.720775865513758 ], [ 25.028684522872425, 56.727132065992009 ], [ 25.097465854665415, 56.737157294473548 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-053", "NAME_1": "Lielvardes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.097465854665415, 56.737157294473548 ], [ 25.028684522872425, 56.727132065992009 ], [ 25.036642693805277, 56.720775865513758 ], [ 25.036125928968431, 56.716796780047332 ], [ 25.041913689565092, 56.7130760769993 ], [ 25.046564568599933, 56.708218492389506 ], [ 25.053695916333481, 56.706099758896755 ], [ 25.055246209045265, 56.701371365496072 ], [ 25.041758660833523, 56.694162503396797 ], [ 25.032715285182235, 56.692818915360647 ], [ 25.024498731830988, 56.69054515223695 ], [ 25.019537795332951, 56.687547918701455 ], [ 25.016902297003412, 56.681501777485039 ], [ 25.017367384996817, 56.671683255477831 ], [ 25.01488691629811, 56.640935777364234 ], [ 25.021243116776418, 56.632124945709677 ], [ 25.024343703099419, 56.624554348404445 ], [ 24.991709831343599, 56.620388087939887 ], [ 24.975142934298958, 56.625893627788685 ], [ 24.957106048605226, 56.631887675775602 ], [ 24.938080274684921, 56.638210354024579 ], [ 24.919688347439262, 56.640204168987168 ], [ 24.905202670466849, 56.647650457502607 ], [ 24.878173388990717, 56.682521200393069 ], [ 24.868174675221042, 56.695420639650763 ], [ 24.852389025533057, 56.701708144515237 ], [ 24.834564649638878, 56.708807684127294 ], [ 24.817773611862663, 56.711897095474569 ], [ 24.799754982406512, 56.715212373352301 ], [ 24.818957161943445, 56.729460608620172 ], [ 24.845671287699759, 56.738365317805119 ], [ 24.852349818689163, 56.762853266265211 ], [ 24.872385413456072, 56.767305619958393 ], [ 24.903551892905512, 56.787341214725245 ], [ 24.923587487672421, 56.800698277603374 ], [ 24.943623081539954, 56.809602985889057 ], [ 24.968111029999989, 56.798472100307151 ], [ 25.005956041338209, 56.79401974571465 ], [ 25.041574875380149, 56.789567392021524 ], [ 25.059384292850837, 56.769531797254615 ], [ 25.074967533025188, 56.753948557080207 ], [ 25.097465854665415, 56.737157294473548 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-038", "NAME_1": "Jaunjelgavas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.949987336346453, 56.578568175680743 ], [ 24.968946566730665, 56.581559557327694 ], [ 25.042223747927608, 56.590034492198015 ], [ 25.056796501757105, 56.601325792551279 ], [ 25.049510125292045, 56.611996975280135 ], [ 25.080179878598528, 56.621497567158997 ], [ 25.118093295069514, 56.624375717865064 ], [ 25.13860087922717, 56.619146840953931 ], [ 25.163096550165619, 56.612901108699191 ], [ 25.188987085785357, 56.601004367657424 ], [ 25.215342643747988, 56.5888939476975 ], [ 25.235362175723822, 56.585638739136471 ], [ 25.293373786970676, 56.591109263881378 ], [ 25.330170117756722, 56.597601629811322 ], [ 25.366709831493495, 56.614365952326807 ], [ 25.398448112490371, 56.630723374783884 ], [ 25.423106316103599, 56.627305406019616 ], [ 25.464772982986744, 56.612901108699191 ], [ 25.487233919809512, 56.613470769860101 ], [ 25.495534701864983, 56.611843166029246 ], [ 25.498789909526693, 56.602362371825961 ], [ 25.493581576728388, 56.589056707900738 ], [ 25.509043815819439, 56.578802801607992 ], [ 25.569788446079883, 56.576701971818522 ], [ 25.560331659278631, 56.573859767913916 ], [ 25.580175408868001, 56.569157212935011 ], [ 25.599450717676461, 56.57029409449683 ], [ 25.607202183034303, 56.567710273010675 ], [ 25.605806919054032, 56.562025865201463 ], [ 25.598675571320541, 56.551819770466011 ], [ 25.575989617826565, 56.539701646913443 ], [ 25.558626336036582, 56.510659492041896 ], [ 25.566067743031908, 56.498308824492653 ], [ 25.580020379237112, 56.48838694879862 ], [ 25.594644809910051, 56.467147936128299 ], [ 25.590717401287009, 56.460843410694793 ], [ 25.583431023922572, 56.458569648470473 ], [ 25.573819206591111, 56.452859402239596 ], [ 25.566687859756883, 56.447614244002125 ], [ 25.547774286154379, 56.444875392885024 ], [ 25.523538039049242, 56.444823716940959 ], [ 25.505399610903282, 56.436400458014703 ], [ 25.476202427300166, 56.418882148392413 ], [ 25.455583529556236, 56.413352770214146 ], [ 25.393520135246035, 56.410975654303002 ], [ 25.331301711304889, 56.421285101825958 ], [ 25.296213413418286, 56.420820013832554 ], [ 25.29357791508869, 56.407900906401665 ], [ 25.133296972777032, 56.413429173017903 ], [ 25.074298280041546, 56.4027021378933 ], [ 25.051056371054642, 56.463488670265917 ], [ 25.027814462067738, 56.459912991891031 ], [ 25.013511748568305, 56.495669774740293 ], [ 24.995633356694043, 56.551092789100892 ], [ 24.956300895469951, 56.551092789100892 ], [ 24.949987336346453, 56.578568175680743 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-073", "NAME_1": "Preilu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.748166130962147, 56.111097316987582 ], [ 26.718503859365626, 56.111252345719151 ], [ 26.700365431219666, 56.118693752714478 ], [ 26.687342970101952, 56.12551504208551 ], [ 26.647913853341663, 56.135281887249278 ], [ 26.617752225085098, 56.149984271157166 ], [ 26.603277738376903, 56.166526542066208 ], [ 26.646701199400809, 56.164458757865361 ], [ 26.671514605314769, 56.176865461271973 ], [ 26.673582389515673, 56.218221138994352 ], [ 26.659107901908101, 56.259576815817354 ], [ 26.640497847697475, 56.276119086726453 ], [ 26.601209954175999, 56.282322438429787 ], [ 26.590871034970291, 56.319542547750359 ], [ 26.570193196558762, 56.321610331051886 ], [ 26.514363032128188, 56.334017034458554 ], [ 26.460600651898574, 56.358830440372515 ], [ 26.479210707008519, 56.391914982190656 ], [ 26.541244222243051, 56.375372711281557 ], [ 26.576396548262096, 56.433270659912978 ], [ 26.590871034970291, 56.445677362420327 ], [ 26.623955576788433, 56.449812930822077 ], [ 26.685989092022965, 56.429135091511228 ], [ 26.733548121448621, 56.396050550592406 ], [ 26.710802498836244, 56.383643847185795 ], [ 26.669446821113866, 56.369169360477599 ], [ 26.65083676690324, 56.336084818659401 ], [ 26.665311253611435, 56.321610331051886 ], [ 26.702531362932064, 56.313339196047025 ], [ 26.741819256453482, 56.290593573434649 ], [ 26.783174933276541, 56.282322438429787 ], [ 26.814191691793098, 56.253373464114077 ], [ 26.839005097707059, 56.214085570592601 ], [ 26.834869530204628, 56.199611083884406 ], [ 26.801784988386487, 56.185136597176211 ], [ 26.826598394300447, 56.176865461271973 ], [ 26.861750720319492, 56.162390974563777 ], [ 26.882428558730965, 56.152052055358013 ], [ 26.888467644765967, 56.128874009927586 ], [ 26.872292922280508, 56.12722036442824 ], [ 26.847643263126088, 56.12396474937367 ], [ 26.836791213243885, 56.129390773865111 ], [ 26.823251987289382, 56.12951996507428 ], [ 26.807283970378933, 56.127323717215745 ], [ 26.774727817135044, 56.115076402454008 ], [ 26.748166130962147, 56.111097316987582 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-056", "NAME_1": "Livanu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.33542646695787, 56.189748846731845 ], [ 26.300803257064615, 56.18334096941021 ], [ 26.264268019253677, 56.210781154726476 ], [ 26.249436883005728, 56.216465563434951 ], [ 26.239204949848556, 56.217447415365882 ], [ 26.219361200259186, 56.22168488235144 ], [ 26.208147414271707, 56.222666734282313 ], [ 26.193522983598768, 56.22607737896783 ], [ 26.189027134194873, 56.234733180991498 ], [ 26.19109419084424, 56.257393296963073 ], [ 26.19243777798107, 56.262612616778824 ], [ 26.195279981885619, 56.268762112581385 ], [ 26.197708774640205, 56.275893460314933 ], [ 26.197915480215215, 56.28411001186754 ], [ 26.196210157872486, 56.283334866410939 ], [ 26.191714307569214, 56.285401923060249 ], [ 26.186908399802803, 56.28855418622669 ], [ 26.184272902372527, 56.290931301238516 ], [ 26.183187696754771, 56.296047268266761 ], [ 26.184272902372527, 56.315477606706168 ], [ 26.181068963262021, 56.320800279309424 ], [ 26.166961297425928, 56.337181708269213 ], [ 26.163809035158806, 56.342452704029029 ], [ 26.162878859171997, 56.36332998329209 ], [ 26.160760124779927, 56.372270006155816 ], [ 26.156987745787831, 56.380331528976853 ], [ 26.144688755081972, 56.389245714318236 ], [ 26.108876986783514, 56.405859687274699 ], [ 26.088516473256618, 56.406428128055666 ], [ 26.153370396426624, 56.429269111180531 ], [ 26.191249219575809, 56.457872016480337 ], [ 26.199465772927056, 56.473039049512522 ], [ 26.232848747571609, 56.498825589329442 ], [ 26.25718834836357, 56.512003079178726 ], [ 26.290416294276554, 56.517894192562892 ], [ 26.309174839147488, 56.515620429439252 ], [ 26.315686069256685, 56.511951402335342 ], [ 26.320802036284931, 56.50688711215048 ], [ 26.323282504983581, 56.498179633283428 ], [ 26.353099806211048, 56.474537665380922 ], [ 26.362556593911677, 56.450844021534351 ], [ 26.412372674359403, 56.465313422576344 ], [ 26.43583377510862, 56.475932929361193 ], [ 26.445600620272387, 56.482650865045343 ], [ 26.45800296376575, 56.488903714534786 ], [ 26.475211215924844, 56.494071357507096 ], [ 26.498982375036576, 56.495931708581452 ], [ 26.529058057783118, 56.493606269513691 ], [ 26.540530226188991, 56.489678859991386 ], [ 26.537108654740621, 56.466355201731119 ], [ 26.537108654740621, 56.445677362420327 ], [ 26.559854277352997, 56.439474011616312 ], [ 26.576396548262096, 56.433270659912978 ], [ 26.541244222243051, 56.375372711281557 ], [ 26.479210707008519, 56.391914982190656 ], [ 26.460600651898574, 56.358830440372515 ], [ 26.514363032128188, 56.334017034458554 ], [ 26.570193196558762, 56.321610331051886 ], [ 26.590871034970291, 56.319542547750359 ], [ 26.601209954175999, 56.282322438429787 ], [ 26.561922060654581, 56.267847950822272 ], [ 26.510227464625757, 56.267847950822272 ], [ 26.441990597687891, 56.265780167520688 ], [ 26.402702704166472, 56.282322438429787 ], [ 26.379957081554039, 56.313339196047025 ], [ 26.355143675640079, 56.311271411846178 ], [ 26.353075891439232, 56.27405130252555 ], [ 26.293110159506227, 56.284390221731314 ], [ 26.311720214616173, 56.226492273999213 ], [ 26.33542646695787, 56.189748846731845 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-103", "NAME_1": "Varkavas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.507508985851018, 56.132336331456486 ], [ 26.484512973994526, 56.167786362750405 ], [ 26.455367466335474, 56.180447089561483 ], [ 26.41655846540084, 56.183547674985164 ], [ 26.380850050789206, 56.196906032887057 ], [ 26.33542646695787, 56.189748846731845 ], [ 26.311720214616173, 56.226492273999213 ], [ 26.293110159506227, 56.284390221731314 ], [ 26.353075891439232, 56.27405130252555 ], [ 26.355143675640079, 56.311271411846178 ], [ 26.379957081554039, 56.313339196047025 ], [ 26.402702704166472, 56.282322438429787 ], [ 26.441990597687891, 56.265780167520688 ], [ 26.510227464625757, 56.267847950822272 ], [ 26.561922060654581, 56.267847950822272 ], [ 26.601209954175999, 56.282322438429787 ], [ 26.640497847697475, 56.276119086726453 ], [ 26.659107901908101, 56.259576815817354 ], [ 26.673582389515673, 56.218221138994352 ], [ 26.671514605314769, 56.176865461271973 ], [ 26.646701199400809, 56.164458757865361 ], [ 26.603277738376903, 56.166526542066208 ], [ 26.617752225085098, 56.149984271157166 ], [ 26.647913853341663, 56.135281887249278 ], [ 26.624814486899027, 56.121122545469063 ], [ 26.62062869585759, 56.1249466013046 ], [ 26.609621616344498, 56.132207140247317 ], [ 26.576238640800625, 56.14804596594854 ], [ 26.570657585778918, 56.153962917754427 ], [ 26.556549919942825, 56.156572578561622 ], [ 26.543940870874451, 56.142103175720933 ], [ 26.54084028455145, 56.133912461690727 ], [ 26.507508985851018, 56.132336331456486 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-JKB", "NAME_1": "Jekabpils" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.088516473256618, 56.406428128055666 ], [ 26.108876986783514, 56.405859687274699 ], [ 26.144688755081972, 56.389245714318236 ], [ 26.156987745787831, 56.380331528976853 ], [ 26.160760124779927, 56.372270006155816 ], [ 26.162878859171997, 56.36332998329209 ], [ 26.163809035158806, 56.342452704029029 ], [ 26.166961297425928, 56.337181708269213 ], [ 26.181068963262021, 56.320800279309424 ], [ 26.184272902372527, 56.315477606706168 ], [ 26.183187696754771, 56.296047268266761 ], [ 26.184272902372527, 56.290931301238516 ], [ 26.186908399802803, 56.28855418622669 ], [ 26.191714307569214, 56.285401923060249 ], [ 26.196210157872486, 56.283334866410939 ], [ 26.197915480215215, 56.28411001186754 ], [ 26.197708774640205, 56.275893460314933 ], [ 26.195279981885619, 56.268762112581385 ], [ 26.19243777798107, 56.262612616778824 ], [ 26.19109419084424, 56.257393296963073 ], [ 26.189027134194873, 56.234733180991498 ], [ 26.193522983598768, 56.22607737896783 ], [ 26.208147414271707, 56.222666734282313 ], [ 26.219361200259186, 56.22168488235144 ], [ 26.239204949848556, 56.217447415365882 ], [ 26.249436883005728, 56.216465563434951 ], [ 26.264268019253677, 56.210781154726476 ], [ 26.300803257064615, 56.18334096941021 ], [ 26.328295119224379, 56.162670397520799 ], [ 26.33656334762037, 56.149441229928811 ], [ 26.340749138661806, 56.134248359374283 ], [ 26.342609490635482, 56.107893377877076 ], [ 26.345348341752526, 56.093449815256747 ], [ 26.316306186880979, 56.122724514125025 ], [ 26.315065951632334, 56.130734361001942 ], [ 26.31863162594874, 56.134997667308483 ], [ 26.320698682598106, 56.141534735839343 ], [ 26.317546421230361, 56.14592723245579 ], [ 26.313050570927089, 56.150371405915621 ], [ 26.304989048106052, 56.153471992238622 ], [ 26.282199740925307, 56.158949693573447 ], [ 26.25718834836357, 56.162076118318168 ], [ 26.243390740889936, 56.167062893237926 ], [ 26.219671257722325, 56.166029365362874 ], [ 26.205821974304627, 56.163600571708969 ], [ 26.138952671328695, 56.131096096207841 ], [ 26.151355014822059, 56.121019191782239 ], [ 26.153060337164789, 56.118280341564457 ], [ 26.152440220439814, 56.109185289069785 ], [ 26.129340854896498, 56.098384915131703 ], [ 26.120504184820277, 56.100710354199464 ], [ 26.108566929320318, 56.101485501454704 ], [ 26.097559848907906, 56.096007799220558 ], [ 26.092392205935539, 56.089599920999547 ], [ 26.079369744817825, 56.078799547061408 ], [ 26.058905876704841, 56.067740789805555 ], [ 26.046296827636468, 56.06634552672466 ], [ 26.036995069566785, 56.068567613004916 ], [ 26.025522902060288, 56.079419663786439 ], [ 26.012188109093927, 56.108357187034528 ], [ 25.98547398333767, 56.110583363431431 ], [ 25.976569275051986, 56.128392780902061 ], [ 25.976569275051986, 56.148428375668971 ], [ 25.94762897199945, 56.157333083954654 ], [ 25.905331606068728, 56.170690146832783 ], [ 25.896426897783101, 56.201856626282222 ], [ 25.876391303016192, 56.221892221049131 ], [ 25.838546291678028, 56.226344574742313 ], [ 25.800701280339808, 56.23524928392726 ], [ 25.756177738012184, 56.230796929334815 ], [ 25.693844778213929, 56.228570752038536 ], [ 25.680487715335801, 56.29312988913307 ], [ 25.733915966848372, 56.299808421021794 ], [ 25.736142143245274, 56.328748723175011 ], [ 25.733915966848372, 56.351010495238143 ], [ 25.794022749350404, 56.359915203523769 ], [ 25.842998646270473, 56.413343455036397 ], [ 25.809605989524755, 56.444509934485836 ], [ 25.820736875106661, 56.486807300416558 ], [ 25.845224823566753, 56.477902592130874 ], [ 25.883069834904916, 56.475676414834652 ], [ 25.876556836728639, 56.495306707638406 ], [ 25.925696060424855, 56.483753711764336 ], [ 26.043223503361958, 56.456122137226828 ], [ 26.055267774588117, 56.451361395212189 ], [ 26.06405683725319, 56.436835028413782 ], [ 26.080332878259696, 56.417914129833207 ], [ 26.088516473256618, 56.406428128055666 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-049", "NAME_1": "Krustpils" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.362556593911677, 56.450844021534351 ], [ 26.353099806211048, 56.474537665380922 ], [ 26.323282504983581, 56.498179633283428 ], [ 26.320802036284931, 56.50688711215048 ], [ 26.315686069256685, 56.511951402335342 ], [ 26.309174839147488, 56.515620429439252 ], [ 26.290416294276554, 56.517894192562892 ], [ 26.25718834836357, 56.512003079178726 ], [ 26.232848747571609, 56.498825589329442 ], [ 26.199465772927056, 56.473039049512522 ], [ 26.191249219575809, 56.457872016480337 ], [ 26.153370396426624, 56.429269111180531 ], [ 26.088516473256618, 56.406428128055666 ], [ 26.080332878259696, 56.417914129833207 ], [ 26.06405683725319, 56.436835028413782 ], [ 26.055267774588117, 56.451361395212189 ], [ 26.043223503361958, 56.456122137226828 ], [ 25.925696060424855, 56.483753711764336 ], [ 25.876556836728639, 56.495306707638406 ], [ 25.925367200835638, 56.513521426172872 ], [ 25.918688668946913, 56.529104666347223 ], [ 25.889748365894377, 56.522426134458499 ], [ 25.878617480312471, 56.535783197336684 ], [ 25.854129531852379, 56.535783197336684 ], [ 25.826426628486104, 56.527167059012527 ], [ 25.79973392008435, 56.527696030347499 ], [ 25.786875846942792, 56.530340887921625 ], [ 25.7692163419606, 56.554144597994764 ], [ 25.748057487662891, 56.566351629424105 ], [ 25.756108922788542, 56.592025575919592 ], [ 25.756908806795991, 56.612255356799267 ], [ 25.788276400735299, 56.609309801006475 ], [ 25.830961135248174, 56.613237210528837 ], [ 25.883257684394607, 56.623572496473514 ], [ 25.93209191291146, 56.637835191041233 ], [ 25.983613315701916, 56.665637112462719 ], [ 26.002113478154456, 56.639695543014852 ], [ 26.022887403730692, 56.629308580226791 ], [ 26.039992303102281, 56.626466376322185 ], [ 26.058130731248241, 56.629954536272805 ], [ 26.09223717630465, 56.643881334056289 ], [ 26.131046177239284, 56.653906562537827 ], [ 26.156470981850305, 56.650134181747035 ], [ 26.170010206905488, 56.645018216517428 ], [ 26.19109419084424, 56.642331041344448 ], [ 26.204891799217137, 56.635251370454341 ], [ 26.198225538577731, 56.6271381698906 ], [ 26.224632196019002, 56.609878241787385 ], [ 26.261994256129981, 56.616570339949192 ], [ 26.281269565837761, 56.610911770561756 ], [ 26.284215121630552, 56.605795803533454 ], [ 26.291346470263363, 56.58670136187834 ], [ 26.342712844322307, 56.60383209877233 ], [ 26.350774367143288, 56.60998159457489 ], [ 26.375579054130014, 56.635923163123437 ], [ 26.401365593946991, 56.633856106474127 ], [ 26.484512973994526, 56.60613170031769 ], [ 26.522546827673921, 56.599853014205223 ], [ 26.593756952221554, 56.595150458326941 ], [ 26.583369989433436, 56.563524481969239 ], [ 26.586625603588743, 56.551432196838391 ], [ 26.595927361658369, 56.547039700221944 ], [ 26.608536410726742, 56.544714260254864 ], [ 26.627760043591138, 56.543732408323933 ], [ 26.595152215302448, 56.506551215366244 ], [ 26.593756952221554, 56.501590277968944 ], [ 26.593136833697884, 56.496603502149867 ], [ 26.59732262473932, 56.495569973375552 ], [ 26.597012567276124, 56.494536445500557 ], [ 26.59639244965183, 56.488800360847961 ], [ 26.559495476634936, 56.486164863417685 ], [ 26.540530226188991, 56.489678859991386 ], [ 26.529058057783118, 56.493606269513691 ], [ 26.498982375036576, 56.495931708581452 ], [ 26.475211215924844, 56.494071357507096 ], [ 26.45800296376575, 56.488903714534786 ], [ 26.445600620272387, 56.482650865045343 ], [ 26.43583377510862, 56.475932929361193 ], [ 26.412372674359403, 56.465313422576344 ], [ 26.362556593911677, 56.450844021534351 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-086", "NAME_1": "Salas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.744041375309223, 56.617267971040008 ], [ 25.756908806795991, 56.612255356799267 ], [ 25.756108922788542, 56.592025575919592 ], [ 25.748057487662891, 56.566351629424105 ], [ 25.7692163419606, 56.554144597994764 ], [ 25.786875846942792, 56.530340887921625 ], [ 25.79973392008435, 56.527696030347499 ], [ 25.826426628486104, 56.527167059012527 ], [ 25.820736875106661, 56.486807300416558 ], [ 25.809605989524755, 56.444509934485836 ], [ 25.842998646270473, 56.413343455036397 ], [ 25.794022749350404, 56.359915203523769 ], [ 25.733915966848372, 56.351010495238143 ], [ 25.727237434959648, 56.368819911809453 ], [ 25.676035360743299, 56.36659373541255 ], [ 25.658225943272669, 56.393307860269488 ], [ 25.635964172108856, 56.408891100443896 ], [ 25.611476223648765, 56.431152872507027 ], [ 25.615928578241267, 56.446736111782116 ], [ 25.594644809910051, 56.467147936128299 ], [ 25.580020379237112, 56.48838694879862 ], [ 25.566067743031908, 56.498308824492653 ], [ 25.558626336036582, 56.510659492041896 ], [ 25.575989617826565, 56.539701646913443 ], [ 25.598675571320541, 56.551819770466011 ], [ 25.605806919054032, 56.562025865201463 ], [ 25.607202183034303, 56.567710273010675 ], [ 25.599450717676461, 56.57029409449683 ], [ 25.580175408868001, 56.569157212935011 ], [ 25.560331659278631, 56.573859767913916 ], [ 25.569788446079883, 56.576701971818522 ], [ 25.579400261612761, 56.576288561567821 ], [ 25.601466099281026, 56.578924058998098 ], [ 25.646734652582154, 56.596390693575643 ], [ 25.688334180577954, 56.600783190192033 ], [ 25.711330194233085, 56.605847480376895 ], [ 25.744041375309223, 56.617267971040008 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-003", "NAME_1": "Aizputes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.436449008614829, 56.867588609426775 ], [ 21.493086379332908, 56.864694729578105 ], [ 21.515772331927565, 56.84397247994599 ], [ 21.526004265984056, 56.842034614505849 ], [ 21.566673617993047, 56.842215480759819 ], [ 21.593028598590934, 56.84513519992953 ], [ 21.608686558038187, 56.832887885167736 ], [ 21.610288526694148, 56.822733466376349 ], [ 21.622535842355205, 56.81136465075798 ], [ 21.629667189189433, 56.799892483251483 ], [ 21.644239943018931, 56.791159165962711 ], [ 21.651681349114938, 56.790073961244275 ], [ 21.673747185883883, 56.790590725181801 ], [ 21.680103387261511, 56.791572578012051 ], [ 21.738446079422999, 56.764132391796409 ], [ 21.761235385704481, 56.741188055884038 ], [ 21.762785679315641, 56.731989651501181 ], [ 21.770537143774163, 56.723023790215734 ], [ 21.771777378123488, 56.713024400155916 ], [ 21.767591587082052, 56.704782010181589 ], [ 21.776118197896494, 56.698658351901372 ], [ 21.801439649720066, 56.690648505024456 ], [ 21.822988721652166, 56.68785797796329 ], [ 21.809346143809478, 56.66933197708903 ], [ 21.815237258092964, 56.661916409414744 ], [ 21.824383985632437, 56.647136949110859 ], [ 21.820508253852836, 56.639152939756343 ], [ 21.813841994112749, 56.62964447701097 ], [ 21.802989943331227, 56.622849026061658 ], [ 21.776738316420165, 56.613702298522242 ], [ 21.777720168351095, 56.6101883001499 ], [ 21.790587598938544, 56.597062486244738 ], [ 21.795238477973385, 56.588639228217801 ], [ 21.793688185261544, 56.58341990840205 ], [ 21.795393507604274, 56.573343003976447 ], [ 21.752952162012662, 56.562744378550178 ], [ 21.712444082728211, 56.549952353418348 ], [ 21.661275982200777, 56.560612373762012 ], [ 21.584523831409683, 56.549952353418348 ], [ 21.571731806277796, 56.560612373762012 ], [ 21.618635898128161, 56.588328428813895 ], [ 21.618635898128161, 56.613912479077612 ], [ 21.607975876885178, 56.643760537119078 ], [ 21.571731806277796, 56.658684567039131 ], [ 21.518431701861516, 56.652288554473159 ], [ 21.490715646809633, 56.652288554473159 ], [ 21.452339571414086, 56.645892541907244 ], [ 21.431019529827438, 56.673608596059807 ], [ 21.403303475674818, 56.671476592170961 ], [ 21.399039466997806, 56.692796633757609 ], [ 21.337211346126708, 56.718380684021326 ], [ 21.31589130364074, 56.739700725607975 ], [ 21.324419320994878, 56.758888763305777 ], [ 21.320155312317809, 56.807924859944308 ], [ 21.345739362581526, 56.820716885076138 ], [ 21.40969948824079, 56.831376905419802 ], [ 21.439547546282199, 56.83990492277394 ], [ 21.436449008614829, 56.867588609426775 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-050", "NAME_1": "Kuldigas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.526004265984056, 56.842034614505849 ], [ 21.515772331927565, 56.84397247994599 ], [ 21.493086379332908, 56.864694729578105 ], [ 21.436449008614829, 56.867588609426775 ], [ 21.467971633084403, 56.878905748201703 ], [ 21.473707716837623, 56.887587389546354 ], [ 21.493396436796104, 56.903813787975935 ], [ 21.518585955377546, 56.910588849495753 ], [ 21.564311109769903, 56.910588849495753 ], [ 21.584887429111575, 56.931165168837424 ], [ 21.639757614022642, 56.9334514262423 ], [ 21.664906449073328, 56.949455230774277 ], [ 21.706059087756671, 56.956314003888167 ], [ 21.69234154152889, 56.997466642571453 ], [ 21.655761418554619, 57.008897931394415 ], [ 21.632898840908751, 57.034046766445101 ], [ 21.639757614022642, 57.047764312672882 ], [ 21.60546374845319, 57.061481858900663 ], [ 21.573804965726595, 57.085611476988049 ], [ 21.593028598590934, 57.087265123386715 ], [ 21.626256545403237, 57.104059964395788 ], [ 21.641449415957766, 57.114214383187232 ], [ 21.653851760350449, 57.116152249526692 ], [ 21.664083692608301, 57.116307278258262 ], [ 21.692350702023248, 57.114214383187232 ], [ 21.711574333988324, 57.116849881516771 ], [ 21.766971470357078, 57.107057197031963 ], [ 21.789192335857592, 57.104111640339909 ], [ 21.789812452582623, 57.099822496510967 ], [ 21.789502394220108, 57.095274970263631 ], [ 21.783094516898416, 57.085198065838028 ], [ 21.82190351693373, 57.085275580203813 ], [ 21.839938592292185, 57.093001207139991 ], [ 21.849860467086842, 57.098427232530753 ], [ 21.86009240114339, 57.099305732573498 ], [ 21.936573520551519, 57.097238675024812 ], [ 21.951973096681058, 57.098427232530753 ], [ 21.996466506324168, 57.107367255394479 ], [ 22.015276727139224, 57.113723455872787 ], [ 22.075324740744179, 57.101992905947839 ], [ 22.095168491232869, 57.101631170741882 ], [ 22.172734816258753, 57.116565659777336 ], [ 22.192475213060618, 57.124575507553629 ], [ 22.194335565034294, 57.128089505026594 ], [ 22.195265741021103, 57.132094428015421 ], [ 22.195110711390214, 57.149070136177841 ], [ 22.195575799383619, 57.153385118428446 ], [ 22.196350945739539, 57.157545071048162 ], [ 22.199606560794109, 57.166123358705988 ], [ 22.206427850165142, 57.177853909530256 ], [ 22.234694857781449, 57.170541693744156 ], [ 22.24182620641426, 57.166691800386275 ], [ 22.249887730134617, 57.155271307924465 ], [ 22.262755160722065, 57.145013536345573 ], [ 22.297998488239614, 57.128761297695689 ], [ 22.327609083892071, 57.120415554034537 ], [ 22.348899774305096, 57.11010610651158 ], [ 22.354170770064968, 57.102664700415573 ], [ 22.363007440141246, 57.078738512572272 ], [ 22.359286737093214, 57.056465969328997 ], [ 22.35959679455641, 57.051453355987576 ], [ 22.362697380879411, 57.042409980336288 ], [ 22.372619255674067, 57.035769558118602 ], [ 22.382386101737211, 57.019672349998928 ], [ 22.412668490958083, 57.014763089445012 ], [ 22.480002882826739, 57.017760322081187 ], [ 22.508218215398301, 57.013832913458145 ], [ 22.472406447099843, 56.982465317720198 ], [ 22.455921665352548, 56.940400703529633 ], [ 22.445379672933541, 56.938540351555957 ], [ 22.454888135678914, 56.917094632411306 ], [ 22.443364292228296, 56.903555406456803 ], [ 22.432357211815884, 56.898542792216062 ], [ 22.417784457986329, 56.889344386933885 ], [ 22.392307977431187, 56.885882066304305 ], [ 22.348744744674207, 56.896424058723312 ], [ 22.338151076311078, 56.904072171293649 ], [ 22.338512810617715, 56.908025418338354 ], [ 22.335670606713109, 56.913012193258112 ], [ 22.328384230247991, 56.916836249093592 ], [ 22.304354688717865, 56.919730129841582 ], [ 22.290247022881772, 56.91006663746532 ], [ 22.287869906970627, 56.905777492737059 ], [ 22.267406039756906, 56.898542792216062 ], [ 22.26399539597071, 56.893943590024605 ], [ 22.269731479723987, 56.888052477539759 ], [ 22.287869906970627, 56.883091539243139 ], [ 22.295518018641644, 56.883298244818093 ], [ 22.30388960072446, 56.884512640745754 ], [ 22.310555861363866, 56.883763332811554 ], [ 22.32032270742701, 56.880404364969422 ], [ 22.329469434966427, 56.87477163400365 ], [ 22.342026808090679, 56.864229640685323 ], [ 22.34130333767888, 56.847486477418954 ], [ 22.316602004378979, 56.843662421583474 ], [ 22.305749952698136, 56.838623968921013 ], [ 22.269731479723987, 56.82970978537827 ], [ 22.251127963584622, 56.823095201582248 ], [ 22.230302362064322, 56.80906505011194 ], [ 22.204877556553981, 56.795215765794921 ], [ 22.162657911833151, 56.795034897742312 ], [ 22.113012961578875, 56.807707251888132 ], [ 22.09243664223726, 56.823711056420109 ], [ 22.030707684212246, 56.823711056420109 ], [ 21.982696271515692, 56.821424798115913 ], [ 21.934684859718459, 56.798562221369366 ], [ 21.959833694769202, 56.732260747635394 ], [ 21.930112344009444, 56.718543201407613 ], [ 21.886673447921282, 56.720829458812432 ], [ 21.840948293528925, 56.704825654280512 ], [ 21.822988721652166, 56.68785797796329 ], [ 21.801439649720066, 56.690648505024456 ], [ 21.776118197896494, 56.698658351901372 ], [ 21.767591587082052, 56.704782010181589 ], [ 21.771777378123488, 56.713024400155916 ], [ 21.770537143774163, 56.723023790215734 ], [ 21.762785679315641, 56.731989651501181 ], [ 21.761235385704481, 56.741188055884038 ], [ 21.738446079422999, 56.764132391796409 ], [ 21.680103387261511, 56.791572578012051 ], [ 21.673747185883883, 56.790590725181801 ], [ 21.651681349114938, 56.790073961244275 ], [ 21.644239943018931, 56.791159165962711 ], [ 21.629667189189433, 56.799892483251483 ], [ 21.622535842355205, 56.81136465075798 ], [ 21.610288526694148, 56.822733466376349 ], [ 21.608686558038187, 56.832887885167736 ], [ 21.593028598590934, 56.84513519992953 ], [ 21.566673617993047, 56.842215480759819 ], [ 21.526004265984056, 56.842034614505849 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-006", "NAME_1": "Alsungas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.493396436796104, 56.903813787975935 ], [ 21.447301060295672, 56.912082018170565 ], [ 21.406063266606452, 56.923450832889614 ], [ 21.397226597429494, 56.929393622217844 ], [ 21.391490512776954, 56.934483750824427 ], [ 21.39583133344928, 56.942416083335559 ], [ 21.446680941772001, 56.949650783856555 ], [ 21.454329054342395, 56.960296129063067 ], [ 21.472002393595574, 56.971354885419601 ], [ 21.474947951187005, 56.986444404085944 ], [ 21.473552687206734, 57.0129544134154 ], [ 21.484869825981662, 57.028509020075205 ], [ 21.489210645754667, 57.051014106415835 ], [ 21.503008254127622, 57.058274645358551 ], [ 21.506160516394687, 57.075612087827551 ], [ 21.539026727101771, 57.07057363516509 ], [ 21.573804965726595, 57.085611476988049 ], [ 21.60546374845319, 57.061481858900663 ], [ 21.639757614022642, 57.047764312672882 ], [ 21.632898840908751, 57.034046766445101 ], [ 21.655761418554619, 57.008897931394415 ], [ 21.69234154152889, 56.997466642571453 ], [ 21.706059087756671, 56.956314003888167 ], [ 21.664906449073328, 56.949455230774277 ], [ 21.639757614022642, 56.9334514262423 ], [ 21.584887429111575, 56.931165168837424 ], [ 21.564311109769903, 56.910588849495753 ], [ 21.518585955377546, 56.910588849495753 ], [ 21.493396436796104, 56.903813787975935 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-093", "NAME_1": "Skrundas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.866138543259126, 56.520426337205663 ], [ 21.850790643073708, 56.521149806718199 ], [ 21.833065626977088, 56.523966173100405 ], [ 21.818027785154129, 56.530839138415502 ], [ 21.807485792735122, 56.538461412564118 ], [ 21.793223097268083, 56.554377753530446 ], [ 21.795393507604274, 56.573343003976447 ], [ 21.793688185261544, 56.58341990840205 ], [ 21.795238477973385, 56.588639228217801 ], [ 21.790587598938544, 56.597062486244738 ], [ 21.777720168351095, 56.6101883001499 ], [ 21.776738316420165, 56.613702298522242 ], [ 21.802989943331227, 56.622849026061658 ], [ 21.813841994112749, 56.62964447701097 ], [ 21.820508253852836, 56.639152939756343 ], [ 21.824383985632437, 56.647136949110859 ], [ 21.815237258092964, 56.661916409414744 ], [ 21.809346143809478, 56.66933197708903 ], [ 21.822988721652166, 56.68785797796329 ], [ 21.840948293528925, 56.704825654280512 ], [ 21.886673447921282, 56.720829458812432 ], [ 21.930112344009444, 56.718543201407613 ], [ 21.959833694769202, 56.732260747635394 ], [ 21.934684859718459, 56.798562221369366 ], [ 21.982696271515692, 56.821424798115913 ], [ 22.030707684212246, 56.823711056420109 ], [ 22.09243664223726, 56.823711056420109 ], [ 22.113012961578875, 56.807707251888132 ], [ 22.162657911833151, 56.795034897742312 ], [ 22.174491815444924, 56.765889390982579 ], [ 22.185963982951421, 56.748112698042576 ], [ 22.189219598006048, 56.741756497564268 ], [ 22.188909538744213, 56.735658677705771 ], [ 22.181003044654744, 56.72852732997228 ], [ 22.173975050608078, 56.715969956848028 ], [ 22.166998731606157, 56.708218492389506 ], [ 22.155991652093064, 56.700311998300037 ], [ 22.125450881353061, 56.69013174108693 ], [ 22.112221713761073, 56.682948717409374 ], [ 22.103540073315742, 56.672871812983772 ], [ 22.111446567405153, 56.646671861117454 ], [ 22.111911655398558, 56.625691229966264 ], [ 22.109276157068962, 56.613624783257137 ], [ 22.112531773022909, 56.609516507480805 ], [ 22.115373976028138, 56.603806261249929 ], [ 22.118577915138644, 56.592359931265776 ], [ 22.123435499748496, 56.58763153696583 ], [ 22.126070998078092, 56.582205512474388 ], [ 22.121265090311624, 56.576340237511943 ], [ 22.099974399898599, 56.56853709620998 ], [ 22.060596958183055, 56.564506333900169 ], [ 22.011400995359622, 56.555049547098918 ], [ 22.011711052822818, 56.547504788215349 ], [ 22.018222283831335, 56.542595526762113 ], [ 22.049073113833117, 56.529056300807611 ], [ 22.05744469591599, 56.523268541110269 ], [ 22.056049431935719, 56.509057522486671 ], [ 22.037445915796354, 56.504044908245874 ], [ 22.024268425947071, 56.50745555293139 ], [ 22.009695672117573, 56.507972316868916 ], [ 21.99786176940512, 56.50593109774195 ], [ 21.966700881040822, 56.506628729732086 ], [ 21.956934034977735, 56.514173489514917 ], [ 21.920605502741751, 56.506938788094544 ], [ 21.912388950289824, 56.507920640924794 ], [ 21.910063511222063, 56.512054755122847 ], [ 21.908358188879276, 56.517454942091888 ], [ 21.904172397837897, 56.521511541924099 ], [ 21.893475375787943, 56.523010158691818 ], [ 21.866138543259126, 56.520426337205663 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-043", "NAME_1": "Kandavas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 22.454888135678914, 56.917094632411306 ], [ 22.445379672933541, 56.938540351555957 ], [ 22.455921665352548, 56.940400703529633 ], [ 22.472406447099843, 56.982465317720198 ], [ 22.508218215398301, 57.013832913458145 ], [ 22.559584587658549, 57.008381048746401 ], [ 22.591417271389957, 57.022385361794989 ], [ 22.635807326446923, 57.015848294163391 ], [ 22.649449904289611, 57.041660672402088 ], [ 22.6415434102002, 57.094732367904442 ], [ 22.669603713140816, 57.097703762118897 ], [ 22.76086429195351, 57.112328192791836 ], [ 22.793265414667133, 57.126022447477965 ], [ 22.801998731955905, 57.131345120081221 ], [ 22.80804487497096, 57.136616115841036 ], [ 22.831299269245847, 57.140078437369937 ], [ 22.911242710182933, 57.137184557521266 ], [ 22.930931431040676, 57.144574286773889 ], [ 22.955708872166724, 57.126776999358981 ], [ 22.941406158667291, 57.11426212549668 ], [ 22.912800732567746, 57.103535090372077 ], [ 22.896710179431238, 57.089232376872644 ], [ 22.841287165969902, 57.078505341748098 ], [ 22.855589879469335, 57.057051271498949 ], [ 22.866316913694618, 57.037385040886875 ], [ 22.878831788456239, 57.019506649911932 ], [ 22.862741235319731, 57.010567453525141 ], [ 22.830560130845356, 57.006991775150254 ], [ 22.818045256982998, 56.974810670675879 ], [ 22.830560130845356, 56.9497809220519 ], [ 22.873468270444334, 56.924751173427865 ], [ 22.916376410942576, 56.915811977940393 ], [ 22.918164249680387, 56.888994390578659 ], [ 22.923527767692292, 56.874691677079227 ], [ 22.943193998304366, 56.855025446467153 ], [ 22.907437214555785, 56.853237607729397 ], [ 22.875256110081409, 56.858601124841982 ], [ 22.835923647957998, 56.849661929354511 ], [ 22.846650683082544, 56.828207859105362 ], [ 22.816257417345923, 56.813905145605929 ], [ 22.788924594894127, 56.803871567818589 ], [ 22.718799675964249, 56.802011216744233 ], [ 22.679060499942125, 56.809555976527065 ], [ 22.642008498193604, 56.808212389390235 ], [ 22.645884229973205, 56.816351427476377 ], [ 22.634257032835762, 56.82412873035662 ], [ 22.586301304361712, 56.837151191474277 ], [ 22.527648552938331, 56.841595364034788 ], [ 22.490854932708942, 56.851517238829501 ], [ 22.500466750040459, 56.862989407235318 ], [ 22.506564568999636, 56.86748525753859 ], [ 22.514626091820674, 56.871981106043165 ], [ 22.518966913392319, 56.876838691552337 ], [ 22.52113732282919, 56.88464183195498 ], [ 22.520982293198244, 56.900299791402233 ], [ 22.524392937883761, 56.905105699168644 ], [ 22.529198845650171, 56.908774726272554 ], [ 22.526563348219952, 56.912960517313991 ], [ 22.511938918446333, 56.917404689874502 ], [ 22.492405226320102, 56.920091865047482 ], [ 22.454888135678914, 56.917094632411306 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-099", "NAME_1": "Tukums" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.492034132569131, 56.934638780455316 ], [ 23.506761916029575, 56.894615384492397 ], [ 23.461958448923269, 56.884228420804959 ], [ 23.48660810717837, 56.815912177005316 ], [ 23.451674838922656, 56.799401556836358 ], [ 23.408835076577532, 56.792399400312036 ], [ 23.397207879440089, 56.792244371580466 ], [ 23.389456414082247, 56.793975532344916 ], [ 23.375038689883638, 56.800770982394909 ], [ 23.321966994381285, 56.782115790311423 ], [ 23.315920851366172, 56.774157620277947 ], [ 23.314990676278683, 56.765475978933239 ], [ 23.325222609435855, 56.749456285179406 ], [ 23.299642775193888, 56.715349840122997 ], [ 23.272305941765808, 56.710285549938135 ], [ 23.215823601577938, 56.711060696294055 ], [ 23.193654412920807, 56.704962877334879 ], [ 23.171743604883432, 56.692405504210626 ], [ 23.123322788415919, 56.698813382431638 ], [ 23.093372487350393, 56.720937509658313 ], [ 23.070130578363489, 56.760269970882405 ], [ 23.055827865763376, 56.794238914993912 ], [ 23.036161634251982, 56.80675378885627 ], [ 22.975375102778742, 56.801390271743628 ], [ 22.932466963179763, 56.810329467231099 ], [ 22.923527767692292, 56.833571376218003 ], [ 22.943193998304366, 56.855025446467153 ], [ 22.923527767692292, 56.874691677079227 ], [ 22.918164249680387, 56.888994390578659 ], [ 22.916376410942576, 56.915811977940393 ], [ 22.873468270444334, 56.924751173427865 ], [ 22.830560130845356, 56.9497809220519 ], [ 22.818045256982998, 56.974810670675879 ], [ 22.830560130845356, 57.006991775150254 ], [ 22.862741235319731, 57.010567453525141 ], [ 22.878831788456239, 57.019506649911932 ], [ 22.866316913694618, 57.037385040886875 ], [ 22.855589879469335, 57.057051271498949 ], [ 22.841287165969902, 57.078505341748098 ], [ 22.896710179431238, 57.089232376872644 ], [ 22.912800732567746, 57.103535090372077 ], [ 22.941406158667291, 57.11426212549668 ], [ 22.955708872166724, 57.126776999358981 ], [ 22.930931431040676, 57.144574286773889 ], [ 22.941473422560364, 57.152454942441636 ], [ 22.946744419219556, 57.160335598109327 ], [ 22.948914828656427, 57.167880356992839 ], [ 22.967259963276661, 57.183538316440149 ], [ 22.977491896433833, 57.187052313913114 ], [ 23.039865350005869, 57.210203356299814 ], [ 23.080379673283289, 57.238470363916122 ], [ 23.112780795996912, 57.265290432507413 ], [ 23.129129271098975, 57.242986545192878 ], [ 23.132704949473805, 57.209017601081371 ], [ 23.120190075611504, 57.171472978595034 ], [ 23.10052384410011, 57.155382425458527 ], [ 23.113038718861787, 57.137504034483584 ], [ 23.150583341348124, 57.123201320984151 ], [ 23.204218516071649, 57.105322929109889 ], [ 23.231036103433382, 57.06599046788574 ], [ 23.21315771155912, 57.039172880524006 ], [ 23.177400928709858, 57.012355293162216 ], [ 23.168461732323067, 56.985537705800482 ], [ 23.197067159321932, 56.967659313926163 ], [ 23.177400928709858, 56.955144439164485 ], [ 23.141644144961276, 56.935478208552468 ], [ 23.148795501710993, 56.921175495952355 ], [ 23.200642837696762, 56.930114691439826 ], [ 23.277519921407247, 56.915811977940393 ], [ 23.372275396991938, 56.910448460827752 ], [ 23.442001124852027, 56.926539013064996 ], [ 23.477151320377118, 56.936473294007271 ], [ 23.492034132569131, 56.934638780455316 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-026", "NAME_1": "Dobele" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.397207879440089, 56.792244371580466 ], [ 23.408835076577532, 56.792399400312036 ], [ 23.451674838922656, 56.799401556836358 ], [ 23.48660810717837, 56.815912177005316 ], [ 23.50552168078093, 56.808212389390235 ], [ 23.525262079381434, 56.763667303803004 ], [ 23.502886183350654, 56.746872463693194 ], [ 23.459271274649609, 56.734573472987336 ], [ 23.436481968368128, 56.723876450937439 ], [ 23.417413364235358, 56.706823229308554 ], [ 23.442683140114809, 56.696798000827073 ], [ 23.462991977697584, 56.692534695419852 ], [ 23.478236525095554, 56.684809068483673 ], [ 23.481492140150124, 56.680416571867283 ], [ 23.479786817807394, 56.676773383185036 ], [ 23.484282668110609, 56.664913642050919 ], [ 23.485367872829045, 56.660288601437799 ], [ 23.476066114759362, 56.656180324762147 ], [ 23.444543491189165, 56.641555894988528 ], [ 23.438187289811538, 56.634450384777381 ], [ 23.424699740700476, 56.622125556549179 ], [ 23.412917514831406, 56.616027736690683 ], [ 23.405941195829485, 56.606441759579525 ], [ 23.480251905800799, 56.599542954943388 ], [ 23.477151320377118, 56.586933905875014 ], [ 23.448419223868086, 56.579079087729667 ], [ 23.436792025831323, 56.577063707024422 ], [ 23.432141147695802, 56.57083669685602 ], [ 23.434466586763563, 56.564092922750149 ], [ 23.445938755169379, 56.556393134235748 ], [ 23.458651157025258, 56.544817613042369 ], [ 23.459271274649609, 56.529831448062851 ], [ 23.44748904788122, 56.505621039379434 ], [ 23.437877232348399, 56.499264838001864 ], [ 23.415087925167597, 56.493296210251856 ], [ 23.393729467241087, 56.518911683727197 ], [ 23.383002432116541, 56.545729271088987 ], [ 23.35618484475475, 56.545729271088987 ], [ 23.315064543893584, 56.513548166614555 ], [ 23.273944243032361, 56.490306257627651 ], [ 23.288246956531793, 56.468852187378502 ], [ 23.309701026780942, 56.459912991891031 ], [ 23.275732082669435, 56.454549473879069 ], [ 23.214945551196195, 56.454549473879069 ], [ 23.172037410697953, 56.45097379550424 ], [ 23.148795501710993, 56.43309540362992 ], [ 23.129129271098975, 56.445610278391598 ], [ 23.121977914349259, 56.470640026116257 ], [ 23.089796809874883, 56.479579222503105 ], [ 23.086221131499997, 56.524275201739158 ], [ 23.088008970237752, 56.545729271088987 ], [ 23.066554899988603, 56.551092789100892 ], [ 23.041525152263944, 56.577910376462683 ], [ 23.021858921651869, 56.59042525032504 ], [ 22.980738620790703, 56.577910376462683 ], [ 22.961072389279309, 56.601152285449587 ], [ 22.925315606430104, 56.588637411587229 ], [ 22.930679123542689, 56.568971180075891 ], [ 22.896710179431238, 56.56718334133808 ], [ 22.862741235319731, 56.552880627838704 ], [ 22.848438522719619, 56.538577914339271 ], [ 22.834135809220186, 56.540365753976346 ], [ 22.82340877409564, 56.561819824225495 ], [ 22.798123000176304, 56.56833038973565 ], [ 22.791921828429622, 56.578975734942162 ], [ 22.788614535632291, 56.581352850853364 ], [ 22.784428744590855, 56.585771185891474 ], [ 22.778692660837635, 56.58781240501844 ], [ 22.776987339394168, 56.591791490484866 ], [ 22.776677280132333, 56.596649075094717 ], [ 22.776987339394168, 56.601351630073623 ], [ 22.780863071173769, 56.606105861895969 ], [ 22.793162061879627, 56.60729442030123 ], [ 22.817191603409753, 56.607346096245294 ], [ 22.829283887641282, 56.610498359411736 ], [ 22.840756056047155, 56.617190457573543 ], [ 22.854295282001658, 56.630858872938632 ], [ 22.859256219399015, 56.644243069262188 ], [ 22.837810500254363, 56.658454087885843 ], [ 22.828663770916251, 56.671579901791006 ], [ 22.805254347010475, 56.678375352740318 ], [ 22.800138380881549, 56.696022854471153 ], [ 22.826028272586711, 56.698089912019782 ], [ 22.875224237208784, 56.70904531468949 ], [ 22.90343956888097, 56.711629137074965 ], [ 22.986173536879221, 56.71075063703222 ], [ 23.028703240861887, 56.694937648853397 ], [ 23.083945346700375, 56.690648505024456 ], [ 23.099293246885793, 56.691578681011265 ], [ 23.123322788415919, 56.698813382431638 ], [ 23.171743604883432, 56.692405504210626 ], [ 23.193654412920807, 56.704962877334879 ], [ 23.215823601577938, 56.711060696294055 ], [ 23.272305941765808, 56.710285549938135 ], [ 23.299642775193888, 56.715349840122997 ], [ 23.325222609435855, 56.749456285179406 ], [ 23.314990676278683, 56.765475978933239 ], [ 23.315920851366172, 56.774157620277947 ], [ 23.321966994381285, 56.782115790311423 ], [ 23.375038689883638, 56.800770982394909 ], [ 23.389456414082247, 56.793975532344916 ], [ 23.397207879440089, 56.792244371580466 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-040", "NAME_1": "Jaunpils" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.083945346700375, 56.690648505024456 ], [ 23.028703240861887, 56.694937648853397 ], [ 22.986173536879221, 56.71075063703222 ], [ 22.90343956888097, 56.711629137074965 ], [ 22.875224237208784, 56.70904531468949 ], [ 22.826028272586711, 56.698089912019782 ], [ 22.818431837759078, 56.708218492389506 ], [ 22.814866164341993, 56.711060696294055 ], [ 22.814401076348588, 56.715246487335492 ], [ 22.818896925752483, 56.717830308821647 ], [ 22.824788039136706, 56.719794013582828 ], [ 22.828663770916251, 56.725969346907789 ], [ 22.826648390211005, 56.733746649788031 ], [ 22.82060224809527, 56.771547960370071 ], [ 22.787684359645482, 56.796791896928482 ], [ 22.788924594894127, 56.803871567818589 ], [ 22.816257417345923, 56.813905145605929 ], [ 22.846650683082544, 56.828207859105362 ], [ 22.835923647957998, 56.849661929354511 ], [ 22.875256110081409, 56.858601124841982 ], [ 22.907437214555785, 56.853237607729397 ], [ 22.943193998304366, 56.855025446467153 ], [ 22.923527767692292, 56.833571376218003 ], [ 22.932466963179763, 56.810329467231099 ], [ 22.975375102778742, 56.801390271743628 ], [ 23.036161634251982, 56.80675378885627 ], [ 23.055827865763376, 56.794238914993912 ], [ 23.070130578363489, 56.760269970882405 ], [ 23.093372487350393, 56.720937509658313 ], [ 23.123322788415919, 56.698813382431638 ], [ 23.099293246885793, 56.691578681011265 ], [ 23.083945346700375, 56.690648505024456 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-018", "NAME_1": "Brocenu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 22.788924594894127, 56.803871567818589 ], [ 22.787684359645482, 56.796791896928482 ], [ 22.82060224809527, 56.771547960370071 ], [ 22.826648390211005, 56.733746649788031 ], [ 22.828663770916251, 56.725969346907789 ], [ 22.824788039136706, 56.719794013582828 ], [ 22.818896925752483, 56.717830308821647 ], [ 22.814401076348588, 56.715246487335492 ], [ 22.814866164341993, 56.711060696294055 ], [ 22.818431837759078, 56.708218492389506 ], [ 22.826028272586711, 56.698089912019782 ], [ 22.800138380881549, 56.696022854471153 ], [ 22.805254347010475, 56.678375352740318 ], [ 22.828663770916251, 56.671579901791006 ], [ 22.837810500254363, 56.658454087885843 ], [ 22.859256219399015, 56.644243069262188 ], [ 22.854295282001658, 56.630858872938632 ], [ 22.840756056047155, 56.617190457573543 ], [ 22.829283887641282, 56.610498359411736 ], [ 22.817191603409753, 56.607346096245294 ], [ 22.793162061879627, 56.60729442030123 ], [ 22.780863071173769, 56.606105861895969 ], [ 22.776987339394168, 56.601351630073623 ], [ 22.776677280132333, 56.596649075094717 ], [ 22.776987339394168, 56.591791490484866 ], [ 22.778692660837635, 56.58781240501844 ], [ 22.784428744590855, 56.585771185891474 ], [ 22.788614535632291, 56.581352850853364 ], [ 22.791921828429622, 56.578975734942162 ], [ 22.798123000176304, 56.56833038973565 ], [ 22.773421665077763, 56.567503567435665 ], [ 22.755128208200233, 56.562025865201463 ], [ 22.735904575335894, 56.565539863573804 ], [ 22.732287225075368, 56.565281481155409 ], [ 22.712074313678613, 56.565372530317973 ], [ 22.693722422451799, 56.588226511344374 ], [ 22.654856041173332, 56.604230314977031 ], [ 22.60455837107196, 56.599657799268016 ], [ 22.574837020312202, 56.567650192002759 ], [ 22.549688186160836, 56.579081479926344 ], [ 22.535970639933055, 56.620234119509007 ], [ 22.501676773464283, 56.638524180546483 ], [ 22.497104258654588, 56.684249334938841 ], [ 22.487959227236558, 56.723115716217308 ], [ 22.460524134780997, 56.736833262445089 ], [ 22.442234072844144, 56.771127128913861 ], [ 22.462810392185816, 56.805420994483256 ], [ 22.490854932708942, 56.851517238829501 ], [ 22.527648552938331, 56.841595364034788 ], [ 22.586301304361712, 56.837151191474277 ], [ 22.634257032835762, 56.82412873035662 ], [ 22.645884229973205, 56.816351427476377 ], [ 22.642008498193604, 56.808212389390235 ], [ 22.679060499942125, 56.809555976527065 ], [ 22.718799675964249, 56.802011216744233 ], [ 22.788924594894127, 56.803871567818589 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-069", "NAME_1": "Ozolnieku" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.996344434647938, 56.730491034733461 ], [ 23.998204786621613, 56.721602687813743 ], [ 24.00812666231559, 56.709975491575676 ], [ 24.000685256219583, 56.695635280843533 ], [ 24.033913202132567, 56.68821971316919 ], [ 24.042129753685174, 56.661244614947009 ], [ 24.034533318857541, 56.659487617559478 ], [ 24.023474561601745, 56.658505763829908 ], [ 24.017738477848468, 56.662743231714728 ], [ 24.00890180777219, 56.666205553243685 ], [ 24.006731398335376, 56.664758613319293 ], [ 24.009987013389946, 56.658867499035807 ], [ 24.036393669931897, 56.641478379723424 ], [ 24.046160515994984, 56.637757677574712 ], [ 24.050966423761452, 56.635251370454341 ], [ 24.050346307036421, 56.631840724869505 ], [ 24.051896599748261, 56.627964993089904 ], [ 24.055152214802831, 56.623779202048524 ], [ 24.057477654769912, 56.619076647069562 ], [ 24.049106072687096, 56.610989284927541 ], [ 24.039339226624008, 56.608793037069006 ], [ 24.030037468554326, 56.608793037069006 ], [ 24.02647179513724, 56.607837023559739 ], [ 24.026575147924746, 56.602746894053894 ], [ 24.040889520235169, 56.592411607209897 ], [ 24.055617302796293, 56.58574534836913 ], [ 24.081558872244159, 56.581895454111873 ], [ 24.094271274999301, 56.581766262003384 ], [ 24.106673617593344, 56.580370998922433 ], [ 24.11023929190975, 56.574944973531672 ], [ 24.10527835541177, 56.5639637324403 ], [ 24.088380160715815, 56.550760403269976 ], [ 24.078871697970442, 56.535464179028622 ], [ 24.080938754619808, 56.527454332151706 ], [ 24.042904900940414, 56.502830512318269 ], [ 24.031742790897056, 56.501719469178113 ], [ 24.017743371059737, 56.502013034873642 ], [ 23.99231367413671, 56.502546292377474 ], [ 23.969413677499176, 56.518911683727197 ], [ 23.964050160386591, 56.554668467475778 ], [ 23.940808251399687, 56.579698215200438 ], [ 23.912202824400822, 56.608303642199303 ], [ 23.865719006427014, 56.615454998949019 ], [ 23.82817438394062, 56.627969872811377 ], [ 23.791941897500578, 56.646880719669468 ], [ 23.807818331051124, 56.65419577011869 ], [ 23.793615510647271, 56.681498590287674 ], [ 23.731209870339228, 56.690498589838 ], [ 23.710176999369025, 56.70663479615888 ], [ 23.683359411107915, 56.697695599772089 ], [ 23.670844537245557, 56.715573991646352 ], [ 23.701237802982178, 56.720937509658313 ], [ 23.701237802982178, 56.737028061895501 ], [ 23.756307407161103, 56.744133613475469 ], [ 23.767469517204461, 56.737932440829468 ], [ 23.783902622108315, 56.732093004288686 ], [ 23.801265902999035, 56.729535021224194 ], [ 23.811239454637132, 56.73255809228209 ], [ 23.818215772739677, 56.735503648074882 ], [ 23.828292678064599, 56.738139147303798 ], [ 23.900898064793864, 56.745838934918879 ], [ 23.912886997137207, 56.745425522869539 ], [ 23.919553256877293, 56.742144070292568 ], [ 23.924979282268055, 56.734108384993931 ], [ 23.935211216324547, 56.731240343566981 ], [ 23.941412388071228, 56.728579006815664 ], [ 23.996344434647938, 56.730491034733461 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-JEL", "NAME_1": "Jelgava" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 23.683804230181067, 56.674098589877985 ], [ 23.731209870339228, 56.690498589838 ], [ 23.793615510647271, 56.681498590287674 ], [ 23.807818331051124, 56.65419577011869 ], [ 23.791941897500578, 56.646880719669468 ], [ 23.769818331450836, 56.636687308972114 ], [ 23.778804230530795, 56.6175788486849 ], [ 23.739007050035298, 56.6076591070821 ], [ 23.707587308907137, 56.591887308752291 ], [ 23.670992949664878, 56.601501410361777 ], [ 23.676992949365115, 56.629895770073688 ], [ 23.631181668699014, 56.650298589508282 ], [ 23.617950646704969, 56.669543712572249 ], [ 23.644412690693116, 56.677963454250005 ], [ 23.683804230181067, 56.674098589877985 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-DGV", "NAME_1": "Daugavpils" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 26.594919269308832, 55.962130279488804 ], [ 26.609768905510577, 55.958673419542663 ], [ 26.612579916429979, 55.94602387130459 ], [ 26.61679643280911, 55.923535784848582 ], [ 26.61117441097025, 55.903858709311976 ], [ 26.631927930929237, 55.897406317347645 ], [ 26.6249292322982, 55.888861395437004 ], [ 26.616709831693356, 55.881170965267813 ], [ 26.601817253763215, 55.873724676752374 ], [ 26.597119357272504, 55.85326051546042 ], [ 26.581658797215709, 55.840610967222347 ], [ 26.556359700739563, 55.837799956302888 ], [ 26.532466108823826, 55.832177934464085 ], [ 26.51841105512608, 55.826555912625224 ], [ 26.504356000528958, 55.840610967222347 ], [ 26.490300946831212, 55.85326051546042 ], [ 26.48748993591181, 55.868721074617895 ], [ 26.485769076881354, 55.892889715188176 ], [ 26.449310742796513, 55.90570709850374 ], [ 26.437917514181891, 55.914618231546115 ], [ 26.471864215361222, 55.933230279553754 ], [ 26.54110825823949, 55.92708533342136 ], [ 26.594919269308832, 55.962130279488804 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-REZ", "NAME_1": "Rezekne" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 27.340169016386994, 56.560760606316876 ], [ 27.363711316923741, 56.555221273542884 ], [ 27.365536672679298, 56.538793073541456 ], [ 27.360973283290377, 56.520539517784471 ], [ 27.355497216923027, 56.494984539005259 ], [ 27.339069016921599, 56.47490562749266 ], [ 27.284639408082171, 56.489658775432133 ], [ 27.274284355038958, 56.515546408040279 ], [ 27.310056339128721, 56.553347928164328 ], [ 27.340169016386994, 56.560760606316876 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-028", "NAME_1": "Durbes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 21.292439258165189, 56.756756759416874 ], [ 21.31589130364074, 56.739700725607975 ], [ 21.337211346126708, 56.718380684021326 ], [ 21.399039466997806, 56.692796633757609 ], [ 21.403303475674818, 56.671476592170961 ], [ 21.431019529827438, 56.673608596059807 ], [ 21.452339571414086, 56.645892541907244 ], [ 21.490715646809633, 56.652288554473159 ], [ 21.518431701861516, 56.652288554473159 ], [ 21.571731806277796, 56.658684567039131 ], [ 21.607975876885178, 56.643760537119078 ], [ 21.618635898128161, 56.613912479077612 ], [ 21.618635898128161, 56.588328428813895 ], [ 21.571731806277796, 56.560612373762012 ], [ 21.52909172220518, 56.571272395004996 ], [ 21.499243664163771, 56.552084357307194 ], [ 21.52909172220518, 56.513708281911647 ], [ 21.482187630354815, 56.511576278022801 ], [ 21.473659613900054, 56.520104294477562 ], [ 21.433151533716284, 56.545688344741279 ], [ 21.399039466997806, 56.558480369873166 ], [ 21.407567483452567, 56.520104294477562 ], [ 21.354267379036287, 56.503048261567983 ], [ 21.347871366470372, 56.543556340852433 ], [ 21.256195186658545, 56.530764315720546 ], [ 21.254063182769642, 56.588328428813895 ], [ 21.281779236922205, 56.611780474289446 ], [ 21.258327190547391, 56.656552562250909 ], [ 21.288175249488177, 56.682136612514626 ], [ 21.273251220467444, 56.707720662778343 ], [ 21.260459195335557, 56.739700725607975 ], [ 21.292439258165189, 56.756756759416874 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-037", "NAME_1": "Incukalna" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.630122348067914, 57.061024109375126 ], [ 24.580062851719219, 57.059236269738051 ], [ 24.565530100633623, 57.060001151232143 ], [ 24.550455160876936, 57.083699004805226 ], [ 24.514297471950727, 57.079526964397871 ], [ 24.508734750508324, 57.105949890574948 ], [ 24.553236521148506, 57.124028735038053 ], [ 24.568534005340041, 57.137935538194483 ], [ 24.618598497422681, 57.132372816752081 ], [ 24.665881629233809, 57.125419415173837 ], [ 24.700648638024234, 57.137935538194483 ], [ 24.736806326950386, 57.147670300943616 ], [ 24.772964014977276, 57.147670300943616 ], [ 24.77991741745484, 57.135154177922971 ], [ 24.766010613399089, 57.115684653324081 ], [ 24.749322449971089, 57.098996488996761 ], [ 24.759057211820846, 57.078136284262087 ], [ 24.707602039602421, 57.062838800070551 ], [ 24.678397752254455, 57.060057439798982 ], [ 24.650584145042217, 57.073964242955412 ], [ 24.630122348067914, 57.061024109375126 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-011", "NAME_1": "Ādaži" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.34880651151127, 57.183827989869826 ], [ 24.372448077416834, 57.182437309734041 ], [ 24.394698962287237, 57.178265268427367 ], [ 24.425293929771044, 57.181046628698937 ], [ 24.467014340139656, 57.182437309734041 ], [ 24.508734750508324, 57.105949890574948 ], [ 24.501781348930081, 57.094824447690087 ], [ 24.458670258425684, 57.072573562819628 ], [ 24.407215086207259, 57.061448119934767 ], [ 24.362713314667701, 57.057276078628092 ], [ 24.320992904299089, 57.028071791280126 ], [ 24.290397936815339, 57.030853152451016 ], [ 24.261193650366636, 57.041978595335877 ], [ 24.247286846310885, 57.060057439798982 ], [ 24.258412289195746, 57.075354923091197 ], [ 24.26536569077399, 57.098996488996761 ], [ 24.320992904299089, 57.112903292153192 ], [ 24.337681068626409, 57.128200776344727 ], [ 24.341853109933083, 57.162967784235832 ], [ 24.34880651151127, 57.183827989869826 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-VMR", "NAME_1": "Valmiera" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.456935934545697, 57.537263956966001 ], [ 25.452238902303463, 57.515344472269533 ], [ 25.431885095021073, 57.505950407785065 ], [ 25.395874512698583, 57.509081762613221 ], [ 25.377086383729591, 57.509081762613221 ], [ 25.372389350588037, 57.527869892481533 ], [ 25.378652061143669, 57.549789377178001 ], [ 25.41153128773874, 57.556052086834313 ], [ 25.43971348209152, 57.556052086834313 ], [ 25.456935934545697, 57.537263956966001 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-022", "NAME_1": "Cesu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.231478377924759, 57.296149626204283 ], [ 25.231478377924759, 57.330594530213375 ], [ 25.254963540035305, 57.325897497971141 ], [ 25.273751669903618, 57.318069110900694 ], [ 25.311327929640242, 57.31337207865846 ], [ 25.323853348952866, 57.308675045516907 ], [ 25.311327929640242, 57.296149626204283 ], [ 25.331681736922576, 57.291452593961992 ], [ 25.362995286103569, 57.296149626204283 ], [ 25.394308835284505, 57.302412335860595 ], [ 25.427188062778839, 57.289886916547914 ], [ 25.466329999030222, 57.277361496335971 ], [ 25.489815161140768, 57.263270399609212 ], [ 25.500774903938634, 57.24917930198319 ], [ 25.500774903938634, 57.216300075388119 ], [ 25.522694388635102, 57.20847168741841 ], [ 25.546179550745649, 57.213168719660644 ], [ 25.560270647472407, 57.222562785044488 ], [ 25.575927422512507, 57.203774655176176 ], [ 25.572796067684351, 57.170895428581161 ], [ 25.563402002300563, 57.147410266470615 ], [ 25.53208845311957, 57.156804330955083 ], [ 25.508603291009081, 57.156804330955083 ], [ 25.4960778716964, 57.152107298712849 ], [ 25.458501611959832, 57.156804330955083 ], [ 25.444410514333754, 57.170895428581161 ], [ 25.41153128773874, 57.186552202721941 ], [ 25.380217738557747, 57.188117880136019 ], [ 25.364560963517647, 57.205340332590254 ], [ 25.369257995759881, 57.219431430216275 ], [ 25.359863931275413, 57.231956849528956 ], [ 25.317590639296554, 57.231956849528956 ], [ 25.319156316710632, 57.258573366467658 ], [ 25.287842767529696, 57.280492851164126 ], [ 25.231478377924759, 57.296149626204283 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-055", "NAME_1": "Ligatnes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 24.980969982678516, 57.238219559185268 ], [ 25.048294114181999, 57.241350914912744 ], [ 25.090567405261538, 57.247613624569112 ], [ 25.10465850288756, 57.233522526943034 ], [ 25.139103407796028, 57.233522526943034 ], [ 25.159457214179099, 57.227259817286722 ], [ 25.171982634391043, 57.206906010004332 ], [ 25.178245344047355, 57.181855170479707 ], [ 25.189205086845277, 57.163067040611395 ], [ 25.212690248955823, 57.145844589056537 ], [ 25.195467796501589, 57.133319168844537 ], [ 25.173548311805121, 57.11766239380438 ], [ 25.137537729482631, 57.111399684148068 ], [ 25.112486889958006, 57.10983400673399 ], [ 25.067082243150992, 57.114531038976224 ], [ 25.026374629485531, 57.119228071218458 ], [ 24.987446730082524, 57.124678860341078 ], [ 24.984036086296328, 57.140750230938352 ], [ 24.983570998302923, 57.145013536345573 ], [ 24.978248324800347, 57.158733629453423 ], [ 24.975664504213455, 57.170670884953324 ], [ 24.973132358671421, 57.177750555843431 ], [ 24.967396274918144, 57.185011094786148 ], [ 24.934375033680851, 57.20839468027026 ], [ 24.900371942311267, 57.218678290270873 ], [ 24.923471306955207, 57.236041572060856 ], [ 24.933134800230846, 57.246221829273964 ], [ 24.980969982678516, 57.238219559185268 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "LV-JKB", "NAME_1": "Jekabpils" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 25.820736875106661, 56.486807300416558 ], [ 25.826426628486104, 56.527167059012527 ], [ 25.854129531852379, 56.535783197336684 ], [ 25.878617480312471, 56.535783197336684 ], [ 25.889748365894377, 56.522426134458499 ], [ 25.918688668946913, 56.529104666347223 ], [ 25.925367200835638, 56.513521426172872 ], [ 25.876556836728639, 56.495306707638406 ], [ 25.883069834904916, 56.475676414834652 ], [ 25.845224823566753, 56.477902592130874 ], [ 25.820736875106661, 56.486807300416558 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/nicaragua.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/nicaragua.geojson new file mode 100644 index 0000000000000..cdb45cff58121 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/nicaragua.geojson @@ -0,0 +1,23 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "NI-SJ", "NAME_1": "Rio San Juan" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -84.19160050499994, 10.781720276000044 ], [ -84.19687150099989, 10.788515727000089 ], [ -84.218885660999973, 10.80595652300012 ], [ -84.221159423999978, 10.809418844000078 ], [ -84.225241862999894, 10.81368214900003 ], [ -84.227102213999899, 10.819314881000068 ], [ -84.222658040999903, 10.827040507000063 ], [ -84.218523925999875, 10.829831035000026 ], [ -84.204648803999902, 10.836988220000066 ], [ -84.208369506999901, 10.860966085000072 ], [ -84.225655273999905, 10.875306295000073 ], [ -84.244723877999888, 10.88491811100009 ], [ -84.253663900999925, 10.89471079600014 ], [ -84.264283406999908, 10.901816305000082 ], [ -84.310740519999939, 10.919412130000055 ], [ -84.321308349999896, 10.9291531370001 ], [ -84.324098876999955, 10.936181132000115 ], [ -84.337405558999876, 10.952665914000093 ], [ -84.341798055999874, 10.959900615000066 ], [ -84.343865112999936, 10.972277121000033 ], [ -84.343658406999879, 10.982379863000062 ], [ -84.3459838469999, 10.989898784000019 ], [ -84.355466471999875, 10.994627177000098 ], [ -84.363967244999884, 10.989614563000131 ], [ -84.417762410999899, 10.955043030000041 ], [ -84.427245035999874, 10.951115621000071 ], [ -84.438200439999946, 10.952200826000066 ], [ -84.448871623999963, 10.956334941000094 ], [ -84.457837483999896, 10.961347555000145 ], [ -84.46638993399992, 10.968453064000087 ], [ -84.489127563999887, 10.996358337000061 ], [ -84.493313354999941, 10.999407248000097 ], [ -84.498170939999852, 11.001991069000098 ], [ -84.503338582999874, 11.004032288000047 ], [ -84.508738769999923, 11.005530904000054 ], [ -84.558606526999966, 11.027209168000056 ], [ -84.581680053999946, 11.034469706000024 ], [ -84.603229125999889, 11.033281149000089 ], [ -84.620669921999934, 11.035761617000077 ], [ -84.658729614999885, 11.062736715000099 ], [ -84.676454630999899, 11.070410665000082 ], [ -84.707770548999918, 11.063046774000085 ], [ -84.781771199999923, 11.014884339000091 ], [ -84.884969034999955, 10.947679138000041 ], [ -84.941792114414511, 10.980111229149884 ], [ -85.027331267523948, 11.008624280486117 ], [ -85.161749936310514, 11.057503796163246 ], [ -85.210629451987586, 11.077870261403405 ], [ -85.300241897245769, 11.110456604888384 ], [ -85.340974827726086, 11.147116241421372 ], [ -85.101518317116643, 11.631460882713554 ], [ -85.083302374604898, 11.662208359927831 ], [ -85.080873582749632, 11.665128079097542 ], [ -85.076687791708196, 11.668926296511358 ], [ -85.061184861891832, 11.676522732238311 ], [ -85.041160244249852, 11.690346178133609 ], [ -85.031987678288715, 11.695307115530966 ], [ -85.025708991276929, 11.697761745807895 ], [ -85.021058112242088, 11.696004747521044 ], [ -85.018551805121717, 11.695384629896751 ], [ -85.013694221411185, 11.69592723225594 ], [ -84.9950390293277, 11.702826035992757 ], [ -84.988992886312644, 11.706288357521657 ], [ -84.985685594414633, 11.708639635011139 ], [ -84.982378303415942, 11.714194850711749 ], [ -84.977804937847566, 11.720137640939356 ], [ -84.970828619744964, 11.727475694247858 ], [ -84.96943335576475, 11.729284369378149 ], [ -84.968451503833819, 11.731506456557725 ], [ -84.966901211121979, 11.733831894726166 ], [ -84.962741257602943, 11.738405260294485 ], [ -84.960777553741082, 11.741324978564876 ], [ -84.959795701810151, 11.745355739975423 ], [ -84.959769864287807, 11.746518459958963 ], [ -84.956979336327265, 11.753029690068104 ], [ -84.942122361657653, 11.775612290774575 ], [ -84.899360113678313, 11.784810696056752 ], [ -84.874271205851471, 11.801062933807316 ], [ -84.808228726074844, 11.860800889949076 ], [ -84.804973111020217, 11.865606797715543 ], [ -84.800167202354487, 11.867053738539198 ], [ -84.794973720960456, 11.867828883995799 ], [ -84.721308967035156, 11.866924547329972 ], [ -84.700870938243213, 11.870490220747058 ], [ -84.696504279149167, 11.870541896691179 ], [ -84.688029344278789, 11.868164780779978 ], [ -84.683998582868298, 11.867854723316839 ], [ -84.668909064201955, 11.869327500763518 ], [ -84.665524257938159, 11.868862412770113 ], [ -84.661751878946063, 11.868009752048408 ], [ -84.656945970280276, 11.866071885708948 ], [ -84.645706345871133, 11.863746445741867 ], [ -84.607414109773345, 11.862506212291862 ], [ -84.587156949033954, 11.793621527711309 ], [ -84.57219662067746, 11.766568915123344 ], [ -84.563928392281468, 11.759773464174032 ], [ -84.557598029325561, 11.753262234064835 ], [ -84.555220913414416, 11.746906032687264 ], [ -84.556357794976236, 11.734891261922201 ], [ -84.55506588378347, 11.708820502164428 ], [ -84.544265509845388, 11.683524888762577 ], [ -84.534291958207291, 11.652131456401605 ], [ -84.534782883723096, 11.644095771102968 ], [ -84.536514045386866, 11.63295950038065 ], [ -84.546384243338139, 11.610118516356408 ], [ -84.560517747595952, 11.562007758251411 ], [ -84.563308274657118, 11.542654934177847 ], [ -84.563644172340673, 11.529658311481853 ], [ -84.556280279711132, 11.491030177700509 ], [ -84.5525595766631, 11.45237620729614 ], [ -84.486129523258853, 11.428243312978509 ], [ -84.457190721174811, 11.410880032087789 ], [ -84.377453985812792, 11.361994126727552 ], [ -84.361976895317468, 11.346801256173023 ], [ -84.356111620354966, 11.333132839009295 ], [ -84.355388149943167, 11.320730496415251 ], [ -84.353346930816201, 11.307914739973285 ], [ -84.345828010354353, 11.292721869418699 ], [ -84.336836310647186, 11.283471788192458 ], [ -84.327560390999224, 11.276883042818156 ], [ -84.280534837612663, 11.25306020776236 ], [ -84.241079882430597, 11.225051580765808 ], [ -84.212683681806482, 11.197042955567952 ], [ -84.204002041361093, 11.185958359890378 ], [ -84.183589850990813, 11.1528337667649 ], [ -84.178551398328352, 11.147020167746518 ], [ -84.174417284130357, 11.144358831894579 ], [ -84.171420050594861, 11.144539699947188 ], [ -84.16793189244288, 11.143738715169548 ], [ -84.164133674129744, 11.141955878461033 ], [ -84.157777472752173, 11.138235175413001 ], [ -84.154857753582462, 11.13722748506035 ], [ -84.149250861038411, 11.135754705815032 ], [ -84.141731939677243, 11.132964178753809 ], [ -84.138863898250293, 11.132499090760405 ], [ -84.136590135126596, 11.132344062028835 ], [ -84.126332364447023, 11.133661810743945 ], [ -84.119950323748412, 11.13373932510973 ], [ -84.117211472631368, 11.133506781113056 ], [ -84.11082943373134, 11.132034002767 ], [ -84.094448004771607, 11.125522773557122 ], [ -84.081968146013139, 11.121414495982208 ], [ -84.050238816867875, 11.125445258292018 ], [ -84.043779262702799, 11.124825141567044 ], [ -84.040575323592293, 11.123042303959153 ], [ -84.041376309269253, 11.117461248937502 ], [ -84.041505499579102, 11.114567369088775 ], [ -84.041040411585698, 11.111931870759236 ], [ -84.039670986926467, 11.109838974788829 ], [ -84.02874142087984, 11.098599351279006 ], [ -84.018922898872688, 11.090589504402089 ], [ -84.013600227168752, 11.088031521337598 ], [ -84.009569464858885, 11.087488918079089 ], [ -84.000965338779338, 11.092010605904704 ], [ -83.994686651767552, 11.093405869884975 ], [ -83.992412888643855, 11.094181016240896 ], [ -83.987968716083344, 11.096506456207976 ], [ -83.985979173799819, 11.097979234554032 ], [ -83.980940721137358, 11.100847275980982 ], [ -83.977271694932767, 11.102242539961253 ], [ -83.969881964780825, 11.103482774310578 ], [ -83.963758308299248, 11.102475083957927 ], [ -83.954172329389451, 11.098909410540841 ], [ -83.94957312719805, 11.098289292916547 ], [ -83.945826585728355, 11.098444322547437 ], [ -83.943552822604659, 11.099607042530977 ], [ -83.940994838640847, 11.100537218517786 ], [ -83.938669399573143, 11.101622423236222 ], [ -83.936524827658673, 11.103017686317173 ], [ -83.928644171990925, 11.106118271740854 ], [ -83.919058193980447, 11.107358506989499 ], [ -83.914174770948932, 11.108598741338824 ], [ -83.900247972266072, 11.115109972347341 ], [ -83.897302415574018, 11.114567369088775 ], [ -83.895622931652952, 11.112707017115156 ], [ -83.895416226077941, 11.109606431691475 ], [ -83.896992357211502, 11.091054592395494 ], [ -83.896837327580613, 11.087876491706709 ], [ -83.895571254809568, 11.082450466315947 ], [ -83.894434374147011, 11.080047511983082 ], [ -83.89154049339902, 11.076016751471911 ], [ -83.888155687135225, 11.072528591521291 ], [ -83.886631231945785, 11.07059072518183 ], [ -83.88559770407079, 11.068110256483124 ], [ -83.885132616077328, 11.065164699791069 ], [ -83.884977587345759, 11.058550115995047 ], [ -83.88422827761292, 11.054674384215446 ], [ -83.882652147378678, 11.050798652435844 ], [ -83.878337165128073, 11.045605170142494 ], [ -83.874874843599116, 11.043744819068138 ], [ -83.871980963750445, 11.043667303803034 ], [ -83.8695780103169, 11.044674994155628 ], [ -83.867510951868894, 11.045992742870794 ], [ -83.865107998435349, 11.047155462854334 ], [ -83.858002489123578, 11.047388006851008 ], [ -83.84668535034865, 11.046535346129303 ], [ -83.807307908633049, 11.038938910402408 ], [ -83.799866503436363, 11.036535956069486 ], [ -83.797592740312723, 11.034985663357645 ], [ -83.794130418783766, 11.031704209881354 ], [ -83.775914476272021, 11.008294785975579 ], [ -83.761419236808308, 10.984704494916514 ], [ -83.735529344203883, 10.957160955913366 ], [ -83.718251105999911, 10.94399648600006 ], [ -83.710316535999937, 10.922674872000073 ], [ -83.692738410999937, 10.925930080000057 ], [ -83.696522589999915, 10.936590887000079 ], [ -83.696499785854115, 10.936594144736317 ], [ -83.688754410845718, 10.93458680566807 ], [ -83.680976324785831, 10.917119398852687 ], [ -83.678799709060002, 10.916154380185779 ], [ -83.676850114500567, 10.910298763549688 ], [ -83.679831847356198, 10.897010590307339 ], [ -83.669854510493167, 10.891717678072528 ], [ -83.669306803999945, 10.869751078000064 ], [ -83.660134236999852, 10.834171855000093 ], [ -83.66302811699984, 10.807015889000112 ], [ -83.698142252999872, 10.789161682000071 ], [ -83.763818115413699, 10.773683167843899 ], [ -83.768964802999932, 10.772470195000039 ], [ -83.835343180999956, 10.747613831000081 ], [ -83.855807047999917, 10.723997701000059 ], [ -83.859527750999916, 10.721775615000055 ], [ -83.886864583999852, 10.72714996400012 ], [ -83.893556681999968, 10.724927877000113 ], [ -83.907483479999968, 10.715367737000108 ], [ -83.917276163999929, 10.7134815470001 ], [ -83.92657792199995, 10.714902649000095 ], [ -83.933321695999979, 10.718054911000053 ], [ -83.99362809299987, 10.765002950000095 ], [ -83.998201456999908, 10.782056173000043 ], [ -84.00923437599991, 10.789445903000043 ], [ -84.022696085999968, 10.78722381700004 ], [ -84.034555826999878, 10.775519104000068 ], [ -84.051634887999938, 10.779549866000053 ], [ -84.076439574999966, 10.763814393000075 ], [ -84.088557698999864, 10.775519104000068 ], [ -84.095430663999934, 10.775519104000068 ], [ -84.106928670999935, 10.766914978000031 ], [ -84.118426676999974, 10.771229960000099 ], [ -84.137004354999931, 10.789161682000071 ], [ -84.149019124999882, 10.787172140000038 ], [ -84.15772972504675, 10.788424645281168 ], [ -84.164832112999875, 10.789445903000043 ], [ -84.180412557999915, 10.789755961000125 ], [ -84.19160050499994, 10.781720276000044 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-AN", "NAME_1": "Atlántico Norte" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -85.048163207999892, 14.605776266000063 ], [ -85.042220418999875, 14.61347605400006 ], [ -85.020206257999888, 14.633733215000063 ], [ -85.048524943999979, 14.653318583000086 ], [ -85.053925130999858, 14.66305959100012 ], [ -85.038215494999889, 14.667219544000062 ], [ -85.033047851999896, 14.669570821 ], [ -85.029792236999896, 14.675539449000027 ], [ -85.024547078999973, 14.712539775000081 ], [ -85.015658732999867, 14.728171896000035 ], [ -85.001990316999951, 14.740677592000026 ], [ -84.999948289999907, 14.742015988000105 ], [ -84.984368651999944, 14.752227275000067 ], [ -84.966462768999889, 14.764629618000129 ], [ -84.920625772999927, 14.807701925000032 ], [ -84.904218506999882, 14.81697784400005 ], [ -84.844428873999931, 14.827545675000124 ], [ -84.818099731999979, 14.828656718000033 ], [ -84.792132324999926, 14.821060283000065 ], [ -84.770169840999955, 14.805143942000129 ], [ -84.755467895999857, 14.781476135000105 ], [ -84.758568481999902, 14.778659770000047 ], [ -84.766397461999929, 14.768867086000085 ], [ -84.766940063999897, 14.766903381000049 ], [ -84.747044637999892, 14.764474590000091 ], [ -84.744279947999928, 14.752408142000107 ], [ -84.745287637999894, 14.739101461000089 ], [ -84.72484960999995, 14.725639750000127 ], [ -84.714410970999921, 14.708922424000093 ], [ -84.699321451999907, 14.674686788000088 ], [ -84.680847127999897, 14.685461325000119 ], [ -84.661701009999888, 14.683445943000066 ], [ -84.622969523999956, 14.667219544000062 ], [ -84.600438598999943, 14.662516989000082 ], [ -84.527419799999905, 14.6603982540001 ], [ -84.531218017999919, 14.653318583000086 ], [ -84.534215250999949, 14.633733215000063 ], [ -84.519048217999938, 14.638280742000092 ], [ -84.508480387999867, 14.632622172000069 ], [ -84.498015909999907, 14.623914693000089 ], [ -84.48269384799994, 14.619470520000093 ], [ -84.47160925299994, 14.622622783000054 ], [ -84.445719360999902, 14.636678772000067 ], [ -84.408434814999879, 14.649417013000033 ], [ -84.390012166999952, 14.671482849000114 ], [ -84.376137044999894, 14.696726787000074 ], [ -84.362933715999901, 14.715614523000113 ], [ -84.353192708999956, 14.705976868000093 ], [ -84.346035522999927, 14.679983622000037 ], [ -84.338387410999928, 14.674686788000088 ], [ -84.323168701999919, 14.673317363000109 ], [ -84.298880777999898, 14.667994690000072 ], [ -84.287796183999887, 14.667219544000062 ], [ -84.26728063999991, 14.677735698000021 ], [ -84.262164672999916, 14.699749858000104 ], [ -84.267332316999841, 14.746672058000058 ], [ -84.261802938999921, 14.758531799000068 ], [ -84.249219726999911, 14.759410298000105 ], [ -84.235396280999851, 14.754733582000128 ], [ -84.226378743999902, 14.749772644000089 ], [ -84.218678955999906, 14.743442282000075 ], [ -84.195011148999896, 14.718715108000055 ], [ -84.182893026999892, 14.713857523000044 ], [ -84.168191081999908, 14.714968567000128 ], [ -84.143799804999873, 14.721867371000101 ], [ -84.137882853999969, 14.725226339000116 ], [ -84.13385209199987, 14.73003224700004 ], [ -84.128736124999875, 14.734192200000066 ], [ -84.119615234999912, 14.736104228000073 ], [ -84.111217814999918, 14.734708964000092 ], [ -84.106515258999934, 14.732331848000058 ], [ -84.102277791999882, 14.731866760000031 ], [ -84.095430663999934, 14.736104228000073 ], [ -84.095430663999934, 14.743597310000027 ], [ -84.104189819999903, 14.751865540000068 ], [ -84.111114461999904, 14.761038106000058 ], [ -84.122715820999929, 14.784525045000038 ], [ -84.111760416999857, 14.793413392000048 ], [ -84.104448201999872, 14.793930156000087 ], [ -84.081555541999961, 14.779796651000055 ], [ -84.078971720999874, 14.77517161100009 ], [ -84.075199340999916, 14.771631775000031 ], [ -84.064683186999872, 14.770262349000063 ], [ -84.047810832999886, 14.770804952000105 ], [ -84.042669026999903, 14.768066101000059 ], [ -84.040756998999967, 14.76034047400006 ], [ -84.023574584999892, 14.758325094000028 ], [ -83.924717569999927, 14.763441061 ], [ -83.929859375999939, 14.771657613000045 ], [ -83.929652669999882, 14.780881857000054 ], [ -83.924717569999927, 14.803774516000061 ], [ -83.912651122999961, 14.797185771000073 ], [ -83.896553914999885, 14.780442606000122 ], [ -83.883763997999921, 14.77710947700011 ], [ -83.885004231999858, 14.781346944000077 ], [ -83.889939330999908, 14.790726216000024 ], [ -83.882678791999922, 14.78783233700004 ], [ -83.878751383999941, 14.786747132000045 ], [ -83.875263224999912, 14.784266663000068 ], [ -83.869475463999919, 14.77710947700011 ], [ -83.857305664999927, 14.787780661000028 ], [ -83.83950313299988, 14.797418315000044 ], [ -83.819659383999891, 14.803619486000031 ], [ -83.801210896999891, 14.803774516000061 ], [ -83.808988199999902, 14.808890483000056 ], [ -83.813923299999942, 14.81377390600008 ], [ -83.821054646999869, 14.825478618000062 ], [ -83.76529577699992, 14.828785909000061 ], [ -83.744521851999878, 14.836666565000101 ], [ -83.746563069999922, 14.852195333000026 ], [ -83.733928181999914, 14.852970480000039 ], [ -83.723618733999899, 14.851575216000057 ], [ -83.7162031659999, 14.847053528000032 ], [ -83.712430785999857, 14.83852691700011 ], [ -83.705015218999847, 14.83852691700011 ], [ -83.714497843999936, 14.867233175000109 ], [ -83.710622110999878, 14.878343607000119 ], [ -83.691966918999896, 14.886973572000073 ], [ -83.672149007999906, 14.88963490800009 ], [ -83.649953979999879, 14.888498027000082 ], [ -83.631557169999979, 14.883201192000044 ], [ -83.623056396999885, 14.872685038000085 ], [ -83.615614990999859, 14.872685038000085 ], [ -83.611300008999876, 14.884906514000107 ], [ -83.609181274999912, 14.89836822500007 ], [ -83.604272013999974, 14.90919443700011 ], [ -83.579777384999915, 14.918108623000123 ], [ -83.55486934399994, 14.937409770000073 ], [ -83.540477458999931, 14.941569723000015 ], [ -83.542441161999875, 14.945083720000056 ], [ -83.545128336999909, 14.952163391000084 ], [ -83.547350423999916, 14.955212301000103 ], [ -83.532493448999872, 14.951026509000073 ], [ -83.526860717999938, 14.94836517400006 ], [ -83.529909627999871, 14.961775207000088 ], [ -83.528617716999918, 14.973402405000058 ], [ -83.523036661999896, 14.977691548000024 ], [ -83.513218139999935, 14.96885487900002 ], [ -83.51262386099998, 14.984021911000042 ], [ -83.510996052999928, 14.99017140700002 ], [ -83.505725056999893, 14.996811829000109 ], [ -83.512468831999939, 15.006501160000141 ], [ -83.509084024999908, 15.011539612000107 ], [ -83.499007120999892, 15.012650655000115 ], [ -83.485855468999915, 15.010480245000039 ], [ -83.48055863499988, 15.005545146000088 ], [ -83.468388834999956, 14.987406719000063 ], [ -83.45919042999995, 14.982497457000122 ], [ -83.435729329999873, 14.985184631000052 ], [ -83.41547216799998, 14.996941020000051 ], [ -83.399891723999929, 15.013632508000086 ], [ -83.390305745999939, 15.030969950000099 ], [ -83.377825886999943, 15.021254781000053 ], [ -83.364984293999868, 15.016345521000119 ], [ -83.354545653999935, 15.010066834000028 ], [ -83.349352172999915, 14.996811829000109 ], [ -83.334236816999919, 15.00644948300004 ], [ -83.317054402999929, 15.007560526000134 ], [ -83.272974405999946, 15.003038839000098 ], [ -83.2848858239999, 14.997380269000075 ], [ -83.285660970999913, 14.992109274000128 ], [ -83.278322916999912, 14.987122498000076 ], [ -83.266153116999902, 14.982497457000122 ], [ -83.262019002999892, 14.98319508900002 ], [ -83.21773230099987, 14.982497457000122 ], [ -83.191325642999885, 14.994253845000117 ], [ -83.177398843999896, 14.996811829000109 ], [ -83.143654134999935, 14.994899801000088 ], [ -83.130444472447948, 14.997012021272383 ], [ -83.137766079999949, 14.986721096000053 ], [ -83.156076626999948, 14.978461005000042 ], [ -83.165150519999941, 14.96906159100007 ], [ -83.179839647999927, 14.985988674000055 ], [ -83.191883917999917, 14.974269924000055 ], [ -83.20148678299995, 14.953070380000042 ], [ -83.208892381999931, 14.94171784100007 ], [ -83.221669074999909, 14.935695705000057 ], [ -83.233876105999911, 14.92133209800005 ], [ -83.242909308999913, 14.904364325000074 ], [ -83.246449347999942, 14.890570380000042 ], [ -83.249094204999949, 14.885891018000052 ], [ -83.261830206999946, 14.87376536700009 ], [ -83.266957160999937, 14.86664459800005 ], [ -83.269520636999914, 14.856919664000088 ], [ -83.271351691999939, 14.835516669000071 ], [ -83.273793097999942, 14.825669664000088 ], [ -83.281971808999913, 14.813177802000041 ], [ -83.294016079999949, 14.804266669000071 ], [ -83.32843990799995, 14.790961005000042 ], [ -83.325998501999948, 14.796942450000074 ], [ -83.323231574999909, 14.801703192000048 ], [ -83.31476803299995, 14.811428127000056 ], [ -83.31476803299995, 14.803941148000092 ], [ -83.311390753999945, 14.809515692000048 ], [ -83.309437628999945, 14.814113674000055 ], [ -83.308583136999914, 14.819037177000041 ], [ -83.308501756999931, 14.825669664000088 ], [ -83.316273566999939, 14.82103099200009 ], [ -83.319488084999932, 14.820257880000042 ], [ -83.32843990799995, 14.825669664000088 ], [ -83.32843990799995, 14.831854559000078 ], [ -83.316477016999897, 14.83734772300005 ], [ -83.305083787999934, 14.838771877000056 ], [ -83.295074022999927, 14.835191148000092 ], [ -83.28742428299995, 14.825669664000088 ], [ -83.288197394999941, 14.844549872000073 ], [ -83.298939581999946, 14.870428778000075 ], [ -83.301665818999936, 14.890570380000042 ], [ -83.307850714999915, 14.910589911000045 ], [ -83.322173631999931, 14.913885809000078 ], [ -83.338368292999917, 14.908026434000078 ], [ -83.350168423999946, 14.900824286000045 ], [ -83.369862433999913, 14.883002020000049 ], [ -83.414133266999897, 14.827704169000071 ], [ -83.424631313999896, 14.803941148000092 ], [ -83.414865688999896, 14.81391022300005 ], [ -83.411529100999928, 14.818264065000051 ], [ -83.397816535999937, 14.807603257000039 ], [ -83.38695227799991, 14.766546942000048 ], [ -83.380238410999937, 14.757391669000071 ], [ -83.367054816999939, 14.749701239000046 ], [ -83.352650519999941, 14.736232815000051 ], [ -83.337513800999943, 14.731431382000039 ], [ -83.322173631999931, 14.749945380000042 ], [ -83.329457160999937, 14.756089585000041 ], [ -83.34788977799991, 14.767075914000088 ], [ -83.356312628999945, 14.770453192000048 ], [ -83.345041469999899, 14.776556708000044 ], [ -83.333485480999911, 14.773260809000078 ], [ -83.322987433999913, 14.763413804000038 ], [ -83.31476803299995, 14.749945380000042 ], [ -83.315419074999909, 14.772772528000075 ], [ -83.308176235999952, 14.779852606000077 ], [ -83.299224412999934, 14.771185614000046 ], [ -83.260121222999942, 14.59601471600007 ], [ -83.257964647999927, 14.590399481000077 ], [ -83.248605923999946, 14.57172272300005 ], [ -83.240305141999897, 14.523993231000077 ], [ -83.191802537999934, 14.386908270000049 ], [ -83.186594204999949, 14.347642320000091 ], [ -83.191395636999914, 14.313421942000048 ], [ -83.218576626999948, 14.25031159100007 ], [ -83.301665818999936, 14.119940497000073 ], [ -83.337513800999943, 14.077541408000059 ], [ -83.342640753999945, 14.060980536000045 ], [ -83.349680141999897, 14.048773505000042 ], [ -83.397287563999896, 14.016302802000041 ], [ -83.417388475999928, 13.98859284100007 ], [ -83.431263800999943, 13.956732489000046 ], [ -83.45531165299991, 13.86391836100006 ], [ -83.493804490999935, 13.73773834800005 ], [ -83.517486131999931, 13.62368398600006 ], [ -83.516021287999934, 13.574652411000045 ], [ -83.52017167899993, 13.550767320000091 ], [ -83.520375128999945, 13.531642971000053 ], [ -83.54133053299995, 13.48187897300005 ], [ -83.559152798999946, 13.415838934000078 ], [ -83.570139126999948, 13.287095445000091 ], [ -83.568226691999939, 13.263006903000075 ], [ -83.561146613999938, 13.249172268000052 ], [ -83.56859290299991, 13.24290599200009 ], [ -83.562977667999917, 13.230658270000049 ], [ -83.529571092999902, 13.032619533000059 ], [ -83.529650437717521, 13.032589830356358 ], [ -83.547969733016771, 13.030264391288597 ], [ -83.598173387092118, 13.033364975812958 ], [ -83.638946091888613, 13.031504624738602 ], [ -83.657291225609583, 13.037447414966209 ], [ -83.755734828999152, 13.093645535213284 ], [ -83.830924038113835, 13.147285671496547 ], [ -83.835239021263817, 13.151290595384637 ], [ -83.838158738634888, 13.155786444788589 ], [ -83.839037237778257, 13.161031602126741 ], [ -83.838339605788178, 13.166690172413496 ], [ -83.836143357929586, 13.172400417745052 ], [ -83.832551846090837, 13.178136502397649 ], [ -83.813664110010677, 13.200796617469905 ], [ -83.81002092222775, 13.206765245219856 ], [ -83.807824672570575, 13.212501328973133 ], [ -83.807204555845544, 13.218159898360625 ], [ -83.810925258893576, 13.222759101451345 ], [ -83.818625048307297, 13.226557318865162 ], [ -83.835859137988791, 13.231208197000683 ], [ -83.84629777672103, 13.235419827363103 ], [ -83.854126757343977, 13.240044867076961 ], [ -83.864307013657765, 13.244204819696677 ], [ -83.883530645622784, 13.247150377288051 ], [ -83.964559292177569, 13.250302639555173 ], [ -83.979752162732098, 13.251568712326218 ], [ -83.983808762564308, 13.254255885700559 ], [ -83.994273240617531, 13.256038723308393 ], [ -83.98869218559588, 13.244437363693351 ], [ -83.987606980877445, 13.234463812954573 ], [ -83.991456875134645, 13.230122992282247 ], [ -84.000500250785933, 13.235549018572328 ], [ -84.007321540156909, 13.235549018572328 ], [ -84.016390754229917, 13.230536404331588 ], [ -84.021015794843038, 13.230975653903272 ], [ -84.02781124489303, 13.235549018572328 ], [ -84.036105312610061, 13.214516710577698 ], [ -84.04806840743106, 13.212087917823112 ], [ -84.063493821982263, 13.217824002475709 ], [ -84.082433234006544, 13.221260483784306 ], [ -84.077265591034177, 13.215886135236929 ], [ -84.071839565643415, 13.205860906755447 ], [ -84.068764817742135, 13.201416734194936 ], [ -84.084448614711789, 13.204439806152095 ], [ -84.108607346551764, 13.197308458418604 ], [ -84.117185635108967, 13.201416734194936 ], [ -84.123619350852323, 13.202682806965981 ], [ -84.129277920239815, 13.208987332399431 ], [ -84.133334520072026, 13.216144516756003 ], [ -84.152609828880486, 13.275391547382014 ], [ -84.155193651265961, 13.280326646357651 ], [ -84.163100145355429, 13.282342027062896 ], [ -84.176613531988892, 13.280636704720109 ], [ -84.236894089590521, 13.264203598916936 ], [ -84.246635098131264, 13.263841863711036 ], [ -84.258339809634492, 13.267123318086647 ], [ -84.265212774949589, 13.271515814703093 ], [ -84.271517300383096, 13.274538885760933 ], [ -84.276891648930416, 13.27588247289782 ], [ -84.284488084657369, 13.27663178083202 ], [ -84.290973477244165, 13.276295884947103 ], [ -84.298440720862573, 13.273918769035959 ], [ -84.3089827141809, 13.267123318086647 ], [ -84.321230028043317, 13.254100856968932 ], [ -84.333684048380121, 13.249708360352543 ], [ -84.35347612202537, 13.247150377288051 ], [ -84.492924974208165, 13.246530260563077 ], [ -84.751436326625139, 13.215731106505359 ], [ -84.769755621924389, 13.2426803654065 ], [ -84.86962032681663, 13.366626287772931 ], [ -84.875511441100116, 13.376754869041974 ], [ -84.878922084886312, 13.380398057724165 ], [ -84.883107875927692, 13.381534939285984 ], [ -84.973774177336395, 13.298775132866069 ], [ -84.982843391409347, 13.295209459448984 ], [ -84.998242966639566, 13.293736681102928 ], [ -85.064621344999068, 13.295131944183879 ], [ -85.097952643699557, 13.292160549070047 ], [ -85.123351609888857, 13.277484443352364 ], [ -85.13632239506245, 13.259449367993909 ], [ -85.144487270670993, 13.241440131057175 ], [ -85.156269497439325, 13.206739406798192 ], [ -85.168671840932689, 13.181469630918741 ], [ -85.177327643855676, 13.171728624176637 ], [ -85.187094489019444, 13.164416409289856 ], [ -85.21572323274097, 13.151368109750479 ], [ -85.241845669342126, 13.145192776425461 ], [ -85.252439337705255, 13.146588040405732 ], [ -85.283264330184693, 13.159248766317489 ], [ -85.290395677018864, 13.169093125847041 ], [ -85.302307094996422, 13.170540065771377 ], [ -85.304167446970098, 13.172477932110837 ], [ -85.305407681319423, 13.18144379339634 ], [ -85.307371385181284, 13.184725246872631 ], [ -85.310833705810865, 13.187050685940392 ], [ -85.324889695702893, 13.193871975311424 ], [ -85.332460293008126, 13.198936266395549 ], [ -85.336491055317936, 13.20012482300217 ], [ -85.339824184738291, 13.200176499845554 ], [ -85.345301886972493, 13.198652045555434 ], [ -85.35142554435339, 13.197928575143635 ], [ -85.35450029225467, 13.198083603875205 ], [ -85.357445848047405, 13.198471178402144 ], [ -85.359926316746112, 13.199504706277139 ], [ -85.362200079869751, 13.200951646201474 ], [ -85.390828823591335, 13.226815701283556 ], [ -85.396358201769601, 13.231053168269113 ], [ -85.401112433591948, 13.233688665699333 ], [ -85.414574144281289, 13.238959662358525 ], [ -85.43444373229238, 13.258002428069574 ], [ -85.485370855880262, 13.325052599098171 ], [ -85.506377326352492, 13.370579534817637 ], [ -85.506118943934098, 13.406081243854317 ], [ -85.500434536124942, 13.4192328961812 ], [ -85.469351162126429, 13.446233831925781 ], [ -85.415039232274751, 13.480417792247295 ], [ -85.404057990284002, 13.489331976689357 ], [ -85.400647345598486, 13.497212633256424 ], [ -85.399381272827441, 13.506488552005067 ], [ -85.399794684876781, 13.511397813458302 ], [ -85.399329596883376, 13.529484564760821 ], [ -85.388813442886089, 13.56051626191595 ], [ -85.390441249963715, 13.570076402404027 ], [ -85.395221320207725, 13.58343476030592 ], [ -85.401939256791252, 13.594622707871679 ], [ -85.41000077961229, 13.611572576713058 ], [ -85.410879278755715, 13.620564277319545 ], [ -85.409122281368184, 13.626713772222786 ], [ -85.398709479259026, 13.633302516697768 ], [ -85.391578132424854, 13.641389878839846 ], [ -85.383774991122948, 13.653430488026572 ], [ -85.374886644203229, 13.677408351813995 ], [ -85.37010657395922, 13.686477565886946 ], [ -85.365093959718422, 13.691903591277708 ], [ -85.284659593265587, 13.702781480480951 ], [ -85.282566698194557, 13.70332408284014 ], [ -85.160610318111651, 13.777479763180509 ], [ -85.156889615063676, 13.778539130376544 ], [ -85.061339890623458, 13.735518499978753 ], [ -85.056792365275442, 13.737533881583374 ], [ -85.05175391261298, 13.742572333346516 ], [ -84.924810756711054, 13.940725612896699 ], [ -84.864039272694242, 14.040280260325744 ], [ -84.854840868311385, 14.059503892290763 ], [ -84.85282548670682, 14.071311957480816 ], [ -84.862075567933118, 14.107769680026706 ], [ -84.858949144087717, 14.154252631054078 ], [ -84.837115852214765, 14.268715929096857 ], [ -84.835462205816157, 14.292900499358552 ], [ -84.838046027302312, 14.306775621197971 ], [ -84.927420416618929, 14.312434189686087 ], [ -84.9345259259307, 14.314268704137362 ], [ -84.939667731380666, 14.317498480770269 ], [ -84.954033779635211, 14.334396674566847 ], [ -84.97080278222262, 14.349615383543096 ], [ -84.989561327093554, 14.373438219498212 ], [ -84.992429369419824, 14.380672919119888 ], [ -84.992816942148124, 14.387365017281695 ], [ -84.990879075808664, 14.393902085812613 ], [ -84.983127611350142, 14.4075188261329 ], [ -84.981990728889002, 14.412505601052658 ], [ -84.982972581719253, 14.434338893824872 ], [ -84.981577317738981, 14.440695095202443 ], [ -84.97038937017328, 14.459401964129313 ], [ -84.968606534364028, 14.469142970871417 ], [ -84.97023434144171, 14.476971951494363 ], [ -84.973774177336395, 14.483147283920005 ], [ -84.978270025841027, 14.487203883752215 ], [ -84.99312700140996, 14.495084540319283 ], [ -85.006485358412533, 14.50539398784224 ], [ -85.008113166389478, 14.507771103753441 ], [ -85.00896582711124, 14.510716661344816 ], [ -85.008294034442144, 14.520018419414498 ], [ -85.00857825438294, 14.528674221438166 ], [ -85.008061490445414, 14.534617010766397 ], [ -85.006175300050018, 14.544848944822945 ], [ -85.005813564844118, 14.549422309492002 ], [ -85.005968593575744, 14.555365098820232 ], [ -85.004444139285567, 14.561256212204398 ], [ -84.999224820369136, 14.575648097981343 ], [ -84.999483201888268, 14.582288520199029 ], [ -85.001085171443492, 14.588541367889775 ], [ -85.003178067413842, 14.592727158931211 ], [ -85.005529344004003, 14.596422024456842 ], [ -85.008733283114509, 14.598824977890388 ], [ -85.011523811074994, 14.600297756236444 ], [ -85.018861864383496, 14.602003079478493 ], [ -85.02365718199988, 14.602540872000063 ], [ -85.022221639999941, 14.605802104000077 ], [ -85.048163207999892, 14.605776266000063 ] ] ], [ [ [ -82.767323370999918, 14.414129950000074 ], [ -82.751047329999949, 14.422023830000057 ], [ -82.737782355999911, 14.421942450000074 ], [ -82.728993292999917, 14.413763739000046 ], [ -82.725697394999941, 14.397406317000048 ], [ -82.732533331999946, 14.369574286000045 ], [ -82.750843878999945, 14.361476955000057 ], [ -82.803944464999915, 14.36595286700009 ], [ -82.808257615999935, 14.366359768000052 ], [ -82.804351365999935, 14.366359768000052 ], [ -82.803700324999909, 14.36631907800006 ], [ -82.801625128999945, 14.366848049000055 ], [ -82.800445115999935, 14.369289455000057 ], [ -82.800852016999897, 14.373236395000049 ], [ -82.784779425999943, 14.381984768000052 ], [ -82.778228318999936, 14.39321523600006 ], [ -82.774647589999915, 14.404689846000053 ], [ -82.767323370999918, 14.414129950000074 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-JI", "NAME_1": "Jinotega" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -85.086377929999884, 14.544539693000033 ], [ -85.065242268999839, 14.554254862000064 ], [ -85.029637206999951, 14.5889555870001 ], [ -85.02365718199988, 14.602540872000063 ], [ -85.018861864383496, 14.602003079478493 ], [ -85.011523811074994, 14.600297756236444 ], [ -85.008733283114509, 14.598824977890388 ], [ -85.005529344004003, 14.596422024456842 ], [ -85.003178067413842, 14.592727158931211 ], [ -85.001085171443492, 14.588541367889775 ], [ -84.999483201888268, 14.582288520199029 ], [ -84.999224820369136, 14.575648097981343 ], [ -85.004444139285567, 14.561256212204398 ], [ -85.005968593575744, 14.555365098820232 ], [ -85.005813564844118, 14.549422309492002 ], [ -85.006175300050018, 14.544848944822945 ], [ -85.008061490445414, 14.534617010766397 ], [ -85.00857825438294, 14.528674221438166 ], [ -85.008294034442144, 14.520018419414498 ], [ -85.00896582711124, 14.510716661344816 ], [ -85.008113166389478, 14.507771103753441 ], [ -85.006485358412533, 14.50539398784224 ], [ -84.99312700140996, 14.495084540319283 ], [ -84.978270025841027, 14.487203883752215 ], [ -84.973774177336395, 14.483147283920005 ], [ -84.97023434144171, 14.476971951494363 ], [ -84.968606534364028, 14.469142970871417 ], [ -84.97038937017328, 14.459401964129313 ], [ -84.981577317738981, 14.440695095202443 ], [ -84.982972581719253, 14.434338893824872 ], [ -84.981990728889002, 14.412505601052658 ], [ -84.983127611350142, 14.4075188261329 ], [ -84.990879075808664, 14.393902085812613 ], [ -84.992816942148124, 14.387365017281695 ], [ -84.992429369419824, 14.380672919119888 ], [ -84.989561327093554, 14.373438219498212 ], [ -84.97080278222262, 14.349615383543096 ], [ -84.954033779635211, 14.334396674566847 ], [ -84.939667731380666, 14.317498480770269 ], [ -84.9345259259307, 14.314268704137362 ], [ -84.927420416618929, 14.312434189686087 ], [ -84.838046027302312, 14.306775621197971 ], [ -84.835462205816157, 14.292900499358552 ], [ -84.837115852214765, 14.268715929096857 ], [ -84.858949144087717, 14.154252631054078 ], [ -84.862075567933118, 14.107769680026706 ], [ -84.85282548670682, 14.071311957480816 ], [ -84.854840868311385, 14.059503892290763 ], [ -84.864039272694242, 14.040280260325744 ], [ -84.924810756711054, 13.940725612896699 ], [ -85.05175391261298, 13.742572333346516 ], [ -85.056792365275442, 13.737533881583374 ], [ -85.061339890623458, 13.735518499978753 ], [ -85.156889615063676, 13.778539130376544 ], [ -85.160610318111651, 13.777479763180509 ], [ -85.282566698194557, 13.70332408284014 ], [ -85.284659593265587, 13.702781480480951 ], [ -85.365093959718422, 13.691903591277708 ], [ -85.37010657395922, 13.686477565886946 ], [ -85.374886644203229, 13.677408351813995 ], [ -85.383774991122948, 13.653430488026572 ], [ -85.391578132424854, 13.641389878839846 ], [ -85.398709479259026, 13.633302516697768 ], [ -85.409122281368184, 13.626713772222786 ], [ -85.410879278755715, 13.620564277319545 ], [ -85.41000077961229, 13.611572576713058 ], [ -85.401939256791252, 13.594622707871679 ], [ -85.395221320207725, 13.58343476030592 ], [ -85.390441249963715, 13.570076402404027 ], [ -85.388813442886089, 13.56051626191595 ], [ -85.399329596883376, 13.529484564760821 ], [ -85.399794684876781, 13.511397813458302 ], [ -85.399381272827441, 13.506488552005067 ], [ -85.400647345598486, 13.497212633256424 ], [ -85.404057990284002, 13.489331976689357 ], [ -85.415039232274751, 13.480417792247295 ], [ -85.469351162126429, 13.446233831925781 ], [ -85.500434536124942, 13.4192328961812 ], [ -85.506118943934098, 13.406081243854317 ], [ -85.506377326352492, 13.370579534817637 ], [ -85.562084520184442, 13.335129503523774 ], [ -85.581540697045511, 13.327791449315896 ], [ -85.604975959373007, 13.327713934950111 ], [ -85.625930752102533, 13.313864651532413 ], [ -85.639883389207057, 13.298155016141095 ], [ -85.65455949582406, 13.275107327441219 ], [ -85.672129483189053, 13.245858466095342 ], [ -85.745019090758433, 13.162220160531945 ], [ -85.782536179600982, 13.130258287390063 ], [ -85.793439908125265, 13.12397960037822 ], [ -85.83974199109997, 13.084989732290296 ], [ -85.896482713706234, 13.032615667878758 ], [ -85.918316005579186, 13.017526150111735 ], [ -85.928418749325829, 13.014193019792003 ], [ -85.941079475237586, 13.012487698348593 ], [ -85.97735632973081, 13.013934638272929 ], [ -85.989371101395193, 13.012100124720973 ], [ -85.994383714736614, 13.009619656022267 ], [ -86.007457851798392, 12.993935859052613 ], [ -86.041745164907411, 13.019619045182765 ], [ -86.057222256302055, 13.034992783789903 ], [ -86.071691657344104, 13.043364365872776 ], [ -86.080735032995335, 13.047162584185912 ], [ -86.094455126103185, 13.046826687401676 ], [ -86.09951941628799, 13.047007555454286 ], [ -86.11517737483598, 13.065662747537772 ], [ -86.159050665955476, 13.091010036883688 ], [ -86.234446580645169, 13.164571438021426 ], [ -86.241422898747771, 13.175113430440433 ], [ -86.247856615390447, 13.189143581910741 ], [ -86.236151902987899, 13.208134669879087 ], [ -86.23310299260902, 13.22477448215659 ], [ -86.235686814994494, 13.237254340015738 ], [ -86.221243252374165, 13.278828030489194 ], [ -86.230389980812959, 13.32171946877844 ], [ -86.230054084028723, 13.343035996713866 ], [ -86.227263556967557, 13.359804999301275 ], [ -86.221475796370896, 13.375256252274198 ], [ -86.212949184657134, 13.390345770940542 ], [ -86.176207242170449, 13.428767198247613 ], [ -86.159980841942286, 13.442693996930416 ], [ -86.144038661654918, 13.445536199935646 ], [ -86.130008511083929, 13.446104640716555 ], [ -86.11765784443395, 13.44098867368831 ], [ -86.108097703945873, 13.451711534159983 ], [ -86.069237027067118, 13.481968084959135 ], [ -86.059676886579041, 13.493285223734063 ], [ -86.050039231725123, 13.5047832305616 ], [ -86.03885128505874, 13.509124050334663 ], [ -86.028283454218013, 13.496282457269558 ], [ -86.018516608154926, 13.500726629830069 ], [ -85.966245897430213, 13.505093288924115 ], [ -85.948985969326998, 13.503930568940575 ], [ -85.93784969770536, 13.497626044406388 ], [ -85.929400601256702, 13.490107123045277 ], [ -85.92009884318702, 13.485172024069641 ], [ -85.906740485285127, 13.486851507990707 ], [ -85.89968665191742, 13.491864122231448 ], [ -85.882840134964226, 13.515196030872119 ], [ -85.860464239832766, 13.531344915835177 ], [ -85.842222459798677, 13.540233262754839 ], [ -85.83129289375205, 13.553384915081779 ], [ -85.832972377673059, 13.612864487905767 ], [ -85.829871792249378, 13.637746690157599 ], [ -85.820750902232362, 13.660794378857474 ], [ -85.791812100148263, 13.709215196224307 ], [ -85.787497117897658, 13.721384995720939 ], [ -85.784551561205546, 13.734588323991943 ], [ -85.783078782859548, 13.781898098218619 ], [ -85.777032639844435, 13.798202012812624 ], [ -85.767136604370762, 13.809648341897457 ], [ -85.743114602999924, 13.823958222000059 ], [ -85.742461913999932, 13.823705139000069 ], [ -85.740293111999904, 13.825639142000043 ], [ -85.733392699999882, 13.831792501000066 ], [ -85.725124471999919, 13.847941386000059 ], [ -85.723005737999955, 13.863418478000071 ], [ -85.728690144999888, 13.87501983700011 ], [ -85.74367630999987, 13.879567363000149 ], [ -85.747448689999885, 13.88827484200003 ], [ -85.743288737999961, 13.907550151000052 ], [ -85.733392699999882, 13.937625834000116 ], [ -85.732204142999933, 13.959536641000085 ], [ -85.727346557999937, 13.965014344000068 ], [ -85.716985433999923, 13.962688904000046 ], [ -85.699234578999892, 13.961500346000022 ], [ -85.686496337999927, 13.967339783000099 ], [ -85.666187500999911, 13.984470520000059 ], [ -85.657660888999885, 13.981990052000086 ], [ -85.651485555999926, 13.981990052000086 ], [ -85.651950643999839, 13.986692607000066 ], [ -85.650400350999917, 13.987855327000076 ], [ -85.647661499999884, 13.98780365000006 ], [ -85.644612589999952, 13.988785503000116 ], [ -85.647868204999924, 13.999301657000089 ], [ -85.612805745999907, 14.009740295000114 ], [ -85.603064737999944, 14.019532980000079 ], [ -85.593607950999882, 14.033459778000065 ], [ -85.571697143999927, 14.04051361100008 ], [ -85.563145912999914, 14.042012281000098 ], [ -85.546634074999929, 14.044906108000077 ], [ -85.527953043999872, 14.050900574000096 ], [ -85.518625447999909, 14.064594828000025 ], [ -85.51640336199992, 14.080537008000064 ], [ -85.510641438999954, 14.093792013000055 ], [ -85.474674641999883, 14.103403829000072 ], [ -85.457621419999839, 14.113041483000089 ], [ -85.431731526999897, 14.132833557000069 ], [ -85.420156005999871, 14.146863708000083 ], [ -85.409123087999973, 14.166164856000123 ], [ -85.400880696999934, 14.18518178300009 ], [ -85.393620157999948, 14.210761617000045 ], [ -85.384008341999845, 14.226445414000096 ], [ -85.37251033599992, 14.241095683000083 ], [ -85.362872680999914, 14.250113221000035 ], [ -85.358531860999932, 14.250888367000044 ], [ -85.347809000999916, 14.249234721000093 ], [ -85.343623209999862, 14.250113221000035 ], [ -85.3408068439999, 14.253368836000021 ], [ -85.337964639999939, 14.260681050000102 ], [ -85.330884968999897, 14.26900095700006 ], [ -85.326828369999902, 14.275744731000088 ], [ -85.321350666999905, 14.28132578600011 ], [ -85.311971394999972, 14.283651225000142 ], [ -85.288200236999899, 14.295149231000067 ], [ -85.277813273999897, 14.297319641000058 ], [ -85.239960286999917, 14.297319641000058 ], [ -85.215207274999869, 14.301582947000028 ], [ -85.190195882999973, 14.309644470000109 ], [ -85.169628662999884, 14.321762594000091 ], [ -85.158027302999926, 14.338273214000083 ], [ -85.15903499399991, 14.361062520000075 ], [ -85.171876587999918, 14.381009623000097 ], [ -85.189730794999946, 14.396848450000093 ], [ -85.205828002999937, 14.407157899000097 ], [ -85.178491170999905, 14.427647603000068 ], [ -85.177354288999908, 14.433977966000086 ], [ -85.179679728999929, 14.449248352000041 ], [ -85.178491170999905, 14.455604553000072 ], [ -85.155391805999926, 14.479479065000049 ], [ -85.15182613199994, 14.485964457000108 ], [ -85.149810750999904, 14.536504008000051 ], [ -85.145469929999933, 14.564254252000083 ], [ -85.13753759899987, 14.578491109000055 ], [ -85.119321655999926, 14.573969422000033 ], [ -85.103353637999902, 14.556864522000083 ], [ -85.086377929999884, 14.544539693000033 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-NS", "NAME_1": "Nueva Segovia" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -86.020196899999888, 14.055163879000062 ], [ -86.020455281999972, 14.044079284000048 ], [ -86.0312556559999, 14.022581889000023 ], [ -86.028413452999928, 13.996071879000098 ], [ -85.957771768999947, 13.94610076900004 ], [ -85.936119344999952, 13.918195496000052 ], [ -85.929401407999933, 13.912097677000091 ], [ -85.91550044799996, 13.907446798000123 ], [ -85.906302042999954, 13.909358826000044 ], [ -85.897206990999877, 13.913027853000045 ], [ -85.883564412999874, 13.913854675000067 ], [ -85.861601928999903, 13.904423727000108 ], [ -85.849871378999921, 13.887086283000087 ], [ -85.840104532999959, 13.866570740000029 ], [ -85.824162353999839, 13.847683004000089 ], [ -85.802019001999923, 13.840215760000063 ], [ -85.778661254999889, 13.84093923000006 ], [ -85.758300740999942, 13.83928558400001 ], [ -85.744994059999925, 13.824686991000135 ], [ -85.743114602999924, 13.823958222000059 ], [ -85.767136604370762, 13.809648341897457 ], [ -85.777032639844435, 13.798202012812624 ], [ -85.783078782859548, 13.781898098218619 ], [ -85.784551561205546, 13.734588323991943 ], [ -85.787497117897658, 13.721384995720939 ], [ -85.791812100148263, 13.709215196224307 ], [ -85.820750902232362, 13.660794378857474 ], [ -85.829871792249378, 13.637746690157599 ], [ -85.832972377673059, 13.612864487905767 ], [ -85.83129289375205, 13.553384915081779 ], [ -85.842222459798677, 13.540233262754839 ], [ -85.860464239832766, 13.531344915835177 ], [ -85.882840134964226, 13.515196030872119 ], [ -85.89968665191742, 13.491864122231448 ], [ -85.906740485285127, 13.486851507990707 ], [ -85.92009884318702, 13.485172024069641 ], [ -85.929400601256702, 13.490107123045277 ], [ -85.93784969770536, 13.497626044406388 ], [ -85.948985969326998, 13.503930568940575 ], [ -85.966245897430213, 13.505093288924115 ], [ -86.018516608154926, 13.500726629830069 ], [ -86.028283454218013, 13.496282457269558 ], [ -86.03885128505874, 13.509124050334663 ], [ -86.050039231725123, 13.5047832305616 ], [ -86.059676886579041, 13.493285223734063 ], [ -86.089881761434128, 13.528786932770743 ], [ -86.111999274147195, 13.56723419849942 ], [ -86.121740281788561, 13.57901642526781 ], [ -86.129853482352303, 13.586974596200662 ], [ -86.164425015402117, 13.614518134304433 ], [ -86.183881192263186, 13.608187771348582 ], [ -86.205869513767027, 13.59966116053414 ], [ -86.208711716772314, 13.595165310230868 ], [ -86.211889818360419, 13.588654080121671 ], [ -86.21785844611037, 13.560361233184324 ], [ -86.226901821761658, 13.549302475928528 ], [ -86.25739091655754, 13.562505805098795 ], [ -86.276795416575226, 13.574210517501342 ], [ -86.292324184813253, 13.578680528483574 ], [ -86.304028897215801, 13.58017914525135 ], [ -86.345550909946496, 13.575063178223104 ], [ -86.37764197519698, 13.574675605494804 ], [ -86.433452520917115, 13.592219753538757 ], [ -86.505282762189722, 13.593382473522297 ], [ -86.515204636984379, 13.592219753538757 ], [ -86.53778723769085, 13.5865095082072 ], [ -86.547838303694732, 13.577001044562564 ], [ -86.563522101563706, 13.569482123201396 ], [ -86.576001960322174, 13.580101629986245 ], [ -86.587448290306327, 13.586742052203931 ], [ -86.604320644781922, 13.592917385528892 ], [ -86.615301886772613, 13.600565497199909 ], [ -86.624138556848891, 13.609970608057097 ], [ -86.628531052566018, 13.618471381349138 ], [ -86.648323127110586, 13.647229316279891 ], [ -86.718344693252959, 13.659864202870665 ], [ -86.740462205966026, 13.66014842371078 ], [ -86.745035569735762, 13.656841131812769 ], [ -86.748136156058763, 13.653611355179862 ], [ -86.755758430207379, 13.64340526044441 ], [ -86.764129565327153, 13.637335555191726 ], [ -86.768213256999843, 13.640357158000057 ], [ -86.772140665999899, 13.645524801000064 ], [ -86.77405269399992, 13.654594015000029 ], [ -86.771167593109908, 13.70789040401894 ], [ -86.770228637999878, 13.72523569800012 ], [ -86.76790319899996, 13.739162496000105 ], [ -86.766197876999883, 13.745260315000067 ], [ -86.7614436449999, 13.749342753000064 ], [ -86.749919799999873, 13.757120056000076 ], [ -86.727233846999894, 13.768256327000103 ], [ -86.706304891999906, 13.770013326000083 ], [ -86.66268998299995, 13.764690654000049 ], [ -86.581144571999914, 13.77985768700006 ], [ -86.541663777999901, 13.78213145000008 ], [ -86.508539184999876, 13.764380595000148 ], [ -86.490814168999862, 13.759497172000124 ], [ -86.476293091999935, 13.764018860000064 ], [ -86.462857218999972, 13.770943502000137 ], [ -86.448232788999888, 13.772958883000086 ], [ -86.432471476999922, 13.757120056000076 ], [ -86.426528686999916, 13.752985942000066 ], [ -86.417071899999939, 13.750014547000148 ], [ -86.410095580999922, 13.749032695000082 ], [ -86.358470825999916, 13.752262472000069 ], [ -86.34012569199993, 13.756654968000063 ], [ -86.325191202999861, 13.76376047800008 ], [ -86.313564005999922, 13.776602072000074 ], [ -86.307776244999843, 13.791691589000081 ], [ -86.299921427999891, 13.82132802300012 ], [ -86.284108439999898, 13.845719299000052 ], [ -86.218582722999912, 13.91437144000011 ], [ -86.184062866999909, 13.966874695000072 ], [ -86.173572550999978, 13.973670146000117 ], [ -86.161790324999885, 13.978114319000028 ], [ -86.14969803999989, 13.984263815000091 ], [ -86.138019165999907, 13.996175232000041 ], [ -86.130836141999879, 14.008913473000092 ], [ -86.12690873199989, 14.018551127000109 ], [ -86.121689412999871, 14.027206930000062 ], [ -86.110475626999914, 14.037128805000066 ], [ -86.096729695999898, 14.044079284000048 ], [ -86.020196899999888, 14.055163879000062 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-CI", "NAME_1": "Chinandega" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -86.74929968299989, 13.26128468800006 ], [ -86.739842895999942, 13.26371348100011 ], [ -86.732715272291955, 13.268469503364884 ], [ -86.731573859046364, 13.266787421302411 ], [ -86.712634447022083, 13.26293752704521 ], [ -86.706846687324742, 13.25854503042882 ], [ -86.70390112973331, 13.250147609924227 ], [ -86.702712572227426, 13.242654526984836 ], [ -86.703203497743232, 13.236608384869044 ], [ -86.704753791354392, 13.231234036321723 ], [ -86.705890672916212, 13.228805243567137 ], [ -86.714934047668123, 13.200357366998901 ], [ -86.725476040087187, 13.191158961716724 ], [ -86.726406216073997, 13.189970405110103 ], [ -86.728938360716768, 13.18084951419371 ], [ -86.732219815092378, 13.149662787407692 ], [ -86.720695969843121, 13.090234890527768 ], [ -86.710954963101074, 13.056335151046369 ], [ -86.689819302318938, 13.008611964770353 ], [ -86.676254238842034, 12.987037055315852 ], [ -86.663903571292792, 12.959157620427845 ], [ -86.65460181322311, 12.838234768219991 ], [ -86.657573208336885, 12.806970527068131 ], [ -86.670001390251969, 12.778755195395945 ], [ -86.687855597557757, 12.767928982136823 ], [ -86.695710414803784, 12.764905911078927 ], [ -86.709921434326702, 12.761340236762521 ], [ -86.782010057118441, 12.752115993957943 ], [ -86.793042975952574, 12.746199042152057 ], [ -86.800200161208465, 12.73935191525868 ], [ -86.814075283947204, 12.712996933761474 ], [ -86.833324755233264, 12.690362657110938 ], [ -86.852806769616734, 12.681629339822166 ], [ -86.877301398240945, 12.655636095329498 ], [ -86.902752041273686, 12.628738512372422 ], [ -86.922156542190635, 12.610600084226519 ], [ -86.92610978923534, 12.604088853218002 ], [ -86.933783739328078, 12.584374293938481 ], [ -86.953937548179283, 12.552412420796543 ], [ -87.005794846854656, 12.499650784556025 ], [ -87.015303311398668, 12.493914699903485 ], [ -87.032227341818327, 12.484173692262061 ], [ -87.049383918033357, 12.47665477090095 ], [ -87.098657396121894, 12.471332099197014 ], [ -87.120749071312559, 12.458438829288525 ], [ -87.120843412540935, 12.45838376929831 ], [ -87.122670050999943, 12.460353908000059 ], [ -87.135487433999913, 12.470485744000086 ], [ -87.149322068999936, 12.474514065000051 ], [ -87.157866990999935, 12.481024481000077 ], [ -87.180409308999913, 12.52297597900008 ], [ -87.186634894999941, 12.52297597900008 ], [ -87.17642167899993, 12.485907294000071 ], [ -87.192738410999937, 12.499904690000051 ], [ -87.218861456999946, 12.532253322000088 ], [ -87.238067186999899, 12.55023834800005 ], [ -87.250477667999917, 12.55532461100006 ], [ -87.312977667999917, 12.602809963000084 ], [ -87.321278449999909, 12.611232815000051 ], [ -87.325795050999943, 12.621608791000085 ], [ -87.331206834999932, 12.63898346600007 ], [ -87.334014451999906, 12.633571682000081 ], [ -87.341786261999914, 12.624090887000079 ], [ -87.344838019999941, 12.619167385000083 ], [ -87.454864061999899, 12.743801174000055 ], [ -87.467762824999909, 12.769964911000045 ], [ -87.463490363999938, 12.76516347900008 ], [ -87.459339972999942, 12.762396552000041 ], [ -87.447295701999906, 12.756293036000045 ], [ -87.447295701999906, 12.762518622000073 ], [ -87.452056443999936, 12.764186916000085 ], [ -87.460926886999914, 12.769964911000045 ], [ -87.460926886999914, 12.776190497000073 ], [ -87.463490363999938, 12.786322333000044 ], [ -87.480254686999899, 12.799994208000044 ], [ -87.502919074999909, 12.81195709800005 ], [ -87.522979295999903, 12.817165432000081 ], [ -87.522979295999903, 12.810939846000053 ], [ -87.496449347999942, 12.793850002000056 ], [ -87.482533331999946, 12.781195380000042 ], [ -87.482045050999943, 12.769964911000045 ], [ -87.492217576999906, 12.771389065000051 ], [ -87.506988084999932, 12.782416083000044 ], [ -87.529204881999931, 12.803493557000081 ], [ -87.646514451999906, 12.872381903000075 ], [ -87.6709285149999, 12.893500067000048 ], [ -87.685658331999946, 12.91828034100007 ], [ -87.685821092999902, 12.94757721600007 ], [ -87.6670222649999, 12.982245184000078 ], [ -87.638824022999927, 13.00649648600006 ], [ -87.609974738999938, 13.02407461100006 ], [ -87.588775193999936, 13.04633209800005 ], [ -87.583851691999939, 13.084662177000041 ], [ -87.577626105999911, 13.084662177000041 ], [ -87.580433722999942, 13.063177802000041 ], [ -87.583851691999939, 13.057318427000041 ], [ -87.572621222999942, 13.057318427000041 ], [ -87.559071417999917, 13.055568752000056 ], [ -87.547637498999904, 13.052150783000059 ], [ -87.542836066999939, 13.047430731000077 ], [ -87.5381160149999, 13.044501044000071 ], [ -87.5127253899999, 13.023220119000086 ], [ -87.506377732999908, 13.019680080000057 ], [ -87.488270636999914, 12.995917059000078 ], [ -87.483876105999911, 12.992621161000045 ], [ -87.471058722999942, 12.985052802000041 ], [ -87.467762824999909, 12.982245184000078 ], [ -87.466908331999946, 12.975734768000052 ], [ -87.46898352799991, 12.960638739000046 ], [ -87.467762824999909, 12.954291083000044 ], [ -87.435047980999911, 12.922390041000085 ], [ -87.392486131999931, 12.913397528000075 ], [ -87.289580857999908, 12.919582424000055 ], [ -87.289580857999908, 12.927028713000084 ], [ -87.341664191999939, 12.925726630000042 ], [ -87.367787238999938, 12.928534247000073 ], [ -87.379017706999946, 12.937567450000074 ], [ -87.368926561999899, 12.953558661000045 ], [ -87.320586717999902, 12.97719961100006 ], [ -87.314035610999952, 12.98155345300006 ], [ -87.084653890999931, 12.995926209000061 ], [ -87.069848592999904, 12.994375915000134 ], [ -87.04685257999995, 12.980552470000077 ], [ -87.035044515999942, 12.979777324000068 ], [ -87.029618489999876, 12.996081238000102 ], [ -87.008767049999904, 13.00608062800012 ], [ -86.983187214999958, 13.021867777000111 ], [ -86.97181840099995, 13.033882548000079 ], [ -86.9484089769999, 13.06969431600001 ], [ -86.942724568999949, 13.074060975000094 ], [ -86.927996785999937, 13.081243998000048 ], [ -86.922932494999969, 13.08638580400013 ], [ -86.920245320999953, 13.096178487000103 ], [ -86.924172729999924, 13.099795838000077 ], [ -86.929805460999944, 13.102224630000137 ], [ -86.932337605999919, 13.108529155000056 ], [ -86.923707641999897, 13.161135763000047 ], [ -86.925516317999978, 13.163642070000037 ], [ -86.933061076999934, 13.1797134400001 ], [ -86.934921427999939, 13.185527038000075 ], [ -86.933216104999872, 13.18818837500001 ], [ -86.925981404999902, 13.216352031000056 ], [ -86.918850057999862, 13.229762065000088 ], [ -86.910788533999977, 13.239580587000063 ], [ -86.862729451999911, 13.279939880000128 ], [ -86.84950028499992, 13.288828227000053 ], [ -86.833428914999871, 13.293349915000078 ], [ -86.816220662999882, 13.291928813000084 ], [ -86.758653117999927, 13.264178569000052 ], [ -86.74929968299989, 13.26128468800006 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-MD", "NAME_1": "Madriz" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -86.732715272291955, 13.268469503364884 ], [ -86.725476847999914, 13.273299459000029 ], [ -86.711782592999896, 13.285675965000081 ], [ -86.704031128999901, 13.298827616000068 ], [ -86.701860717999921, 13.314201355000137 ], [ -86.707803507999927, 13.342830099000111 ], [ -86.709922241999891, 13.348902079000069 ], [ -86.71715694199986, 13.361640320000035 ], [ -86.723616496999909, 13.367324727000067 ], [ -86.730437784999879, 13.368900858000103 ], [ -86.736380574999885, 13.371949768000121 ], [ -86.740204630999926, 13.381923320000041 ], [ -86.738654337999918, 13.396211853000111 ], [ -86.725941935999856, 13.423832906000115 ], [ -86.724288289999919, 13.439413351000056 ], [ -86.756586059999876, 13.559380188000148 ], [ -86.757102823999929, 13.576407573000083 ], [ -86.750901651999925, 13.608421122000081 ], [ -86.751573445999924, 13.624414978000033 ], [ -86.755397501999965, 13.630874532000078 ], [ -86.764129565327153, 13.637335555191726 ], [ -86.755758430207379, 13.64340526044441 ], [ -86.748136156058763, 13.653611355179862 ], [ -86.745035569735762, 13.656841131812769 ], [ -86.740462205966026, 13.66014842371078 ], [ -86.718344693252959, 13.659864202870665 ], [ -86.648323127110586, 13.647229316279891 ], [ -86.628531052566018, 13.618471381349138 ], [ -86.624138556848891, 13.609970608057097 ], [ -86.615301886772613, 13.600565497199909 ], [ -86.604320644781922, 13.592917385528892 ], [ -86.587448290306327, 13.586742052203931 ], [ -86.576001960322174, 13.580101629986245 ], [ -86.563522101563706, 13.569482123201396 ], [ -86.547838303694732, 13.577001044562564 ], [ -86.53778723769085, 13.5865095082072 ], [ -86.515204636984379, 13.592219753538757 ], [ -86.505282762189722, 13.593382473522297 ], [ -86.433452520917115, 13.592219753538757 ], [ -86.37764197519698, 13.574675605494804 ], [ -86.345550909946496, 13.575063178223104 ], [ -86.304028897215801, 13.58017914525135 ], [ -86.292324184813253, 13.578680528483574 ], [ -86.276795416575226, 13.574210517501342 ], [ -86.25739091655754, 13.562505805098795 ], [ -86.226901821761658, 13.549302475928528 ], [ -86.21785844611037, 13.560361233184324 ], [ -86.211889818360419, 13.588654080121671 ], [ -86.208711716772314, 13.595165310230868 ], [ -86.205869513767027, 13.59966116053414 ], [ -86.183881192263186, 13.608187771348582 ], [ -86.164425015402117, 13.614518134304433 ], [ -86.129853482352303, 13.586974596200662 ], [ -86.121740281788561, 13.57901642526781 ], [ -86.111999274147195, 13.56723419849942 ], [ -86.089881761434128, 13.528786932770743 ], [ -86.059676886579041, 13.493285223734063 ], [ -86.069237027067118, 13.481968084959135 ], [ -86.108097703945873, 13.451711534159983 ], [ -86.11765784443395, 13.44098867368831 ], [ -86.130008511083929, 13.446104640716555 ], [ -86.144038661654918, 13.445536199935646 ], [ -86.159980841942286, 13.442693996930416 ], [ -86.176207242170449, 13.428767198247613 ], [ -86.212949184657134, 13.390345770940542 ], [ -86.221010708377491, 13.403755804786556 ], [ -86.230906744750428, 13.425718288767996 ], [ -86.234937507060295, 13.432203681354792 ], [ -86.25374772787535, 13.438120632261359 ], [ -86.309377408240778, 13.435459296409363 ], [ -86.386116910067301, 13.411326402091788 ], [ -86.428388230732253, 13.40437592241085 ], [ -86.471227993976697, 13.42424551042194 ], [ -86.485800746906932, 13.431221829423862 ], [ -86.496291063381875, 13.434451606056768 ], [ -86.522826911133052, 13.430446682168622 ], [ -86.562772792730186, 13.396805325105674 ], [ -86.60388139521018, 13.326396186235002 ], [ -86.612278814815454, 13.308826198869951 ], [ -86.630959846219923, 13.28296214378787 ], [ -86.714934047668123, 13.200357366998901 ], [ -86.705890672916212, 13.228805243567137 ], [ -86.704753791354392, 13.231234036321723 ], [ -86.703203497743232, 13.236608384869044 ], [ -86.702712572227426, 13.242654526984836 ], [ -86.70390112973331, 13.250147609924227 ], [ -86.706846687324742, 13.25854503042882 ], [ -86.712634447022083, 13.26293752704521 ], [ -86.731573859046364, 13.266787421302411 ], [ -86.732715272291955, 13.268469503364884 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-RI", "NAME_1": "Rivas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -85.236478239279279, 11.05309661721509 ], [ -85.272361409999917, 11.066199036000043 ], [ -85.407417765999895, 11.115446676000118 ], [ -85.508626058999909, 11.152421163000071 ], [ -85.540949666999978, 11.17032704600004 ], [ -85.569164998999952, 11.195390117000045 ], [ -85.597793741999936, 11.209937032000099 ], [ -85.631150879999893, 11.196216939000067 ], [ -85.659314534999851, 11.158829041000018 ], [ -85.677582153999907, 11.119632467000059 ], [ -85.701735565999883, 11.080880181000097 ], [ -85.702422654999907, 11.081203518000052 ], [ -85.752308722999942, 11.101711330000057 ], [ -85.77171790299991, 11.104681708000044 ], [ -85.78579667899993, 11.112250067000048 ], [ -85.793690558999913, 11.130031643000052 ], [ -85.803089972999942, 11.166083075000074 ], [ -85.8213191399999, 11.19281647300005 ], [ -85.928008592999902, 11.310736395000049 ], [ -85.936797654999907, 11.316961981000077 ], [ -85.941517706999946, 11.319118557000081 ], [ -85.956817186999899, 11.329779364000046 ], [ -85.960113084999932, 11.334011135000083 ], [ -85.994862433999913, 11.343654690000051 ], [ -86.010365363999938, 11.357977606000077 ], [ -86.043934699999909, 11.398098049000055 ], [ -86.070586717999902, 11.411688544000071 ], [ -86.104725714999915, 11.447292385000083 ], [ -86.148304816999939, 11.471747137000079 ], [ -86.16274980399993, 11.484523830000057 ], [ -86.16665605399993, 11.492621161000045 ], [ -86.175200963732777, 11.519466114006992 ], [ -86.17512203565343, 11.519607245477971 ], [ -86.146260748834493, 11.57182628025862 ], [ -86.139723680303575, 11.584047755699373 ], [ -86.136623093980575, 11.587923489277614 ], [ -86.101689825724861, 11.610816148346544 ], [ -86.07812537308746, 11.604718329387367 ], [ -86.070580614203948, 11.605777696583402 ], [ -86.067066616730983, 11.609317532478144 ], [ -86.039316372152825, 11.623166815895843 ], [ -86.03556983068313, 11.625750637381998 ], [ -86.024691942379206, 11.643320623847671 ], [ -86.009085659775337, 11.676212672976476 ], [ -86.006165940605683, 11.679132392146187 ], [ -86.003375414443781, 11.680837714488916 ], [ -86.000920783267532, 11.681044420063927 ], [ -85.999189623402401, 11.680966904798822 ], [ -85.99415117073994, 11.679752508871161 ], [ -85.989810350067557, 11.67706533549682 ], [ -85.985934618288013, 11.67303457318701 ], [ -85.976064419437364, 11.663061021548913 ], [ -85.971336026036738, 11.661484890415352 ], [ -85.926997646923837, 11.672724513925175 ], [ -85.894363980213484, 11.682052110416521 ], [ -85.522913784943228, 11.680527655227081 ], [ -85.101518317116643, 11.631460882713554 ], [ -85.340974827726086, 11.147116241421372 ], [ -85.300241897245769, 11.110456604888384 ], [ -85.210629451987586, 11.077870261403405 ], [ -85.161749936310514, 11.057503796163246 ], [ -85.027331267523948, 11.008624280486117 ], [ -84.941792114414511, 10.980111229149884 ], [ -84.884969034999955, 10.947679138000041 ], [ -84.908404296999919, 10.939359233000076 ], [ -84.931400309999873, 10.941891378000065 ], [ -85.092837483999915, 11.000647482000119 ], [ -85.236478239279279, 11.05309661721509 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-AS", "NAME_1": "Atlántico Sur" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -83.529571092999902, 13.032619533000059 ], [ -83.507679816999939, 12.902777411000045 ], [ -83.54133053299995, 12.63898346600007 ], [ -83.54133053299995, 12.580633856000077 ], [ -83.537993943999936, 12.57103099200009 ], [ -83.523508266999897, 12.542303778000075 ], [ -83.513824022999927, 12.51048411700009 ], [ -83.485910610999952, 12.472154039000088 ], [ -83.479237433999913, 12.447211005000042 ], [ -83.481800910999937, 12.41665273600006 ], [ -83.492298956999946, 12.400336005000042 ], [ -83.512562628999945, 12.393784898000092 ], [ -83.544748501999948, 12.392564195000091 ], [ -83.569243943999936, 12.387640692000048 ], [ -83.594227667999917, 12.378810940000051 ], [ -83.617583787999934, 12.375148830000057 ], [ -83.637521938999896, 12.385728257000039 ], [ -83.629994269999941, 12.39288971600007 ], [ -83.609364386999914, 12.407212632000039 ], [ -83.603382941999939, 12.413723049000055 ], [ -83.602528449999909, 12.425441799000055 ], [ -83.606312628999945, 12.441148179000038 ], [ -83.612700975999928, 12.454901434000078 ], [ -83.634632941999939, 12.474107164000088 ], [ -83.632883266999897, 12.539536851000037 ], [ -83.637521938999896, 12.564520575000074 ], [ -83.633859829999949, 12.566473700000074 ], [ -83.632679816999939, 12.566595770000049 ], [ -83.632069464999915, 12.56712474200009 ], [ -83.630034959999932, 12.570746161000045 ], [ -83.623850063999896, 12.570746161000045 ], [ -83.588449673999946, 12.559637762000079 ], [ -83.563791469999899, 12.590887762000079 ], [ -83.555409308999913, 12.635891018000052 ], [ -83.56859290299991, 12.66632721600007 ], [ -83.56859290299991, 12.673773505000042 ], [ -83.559966600999928, 12.683254299000055 ], [ -83.556548631999931, 12.69672272300005 ], [ -83.55492102799991, 12.75259023600006 ], [ -83.553130662999934, 12.754706122000073 ], [ -83.54906165299991, 12.758042710000041 ], [ -83.544422980999911, 12.763088283000059 ], [ -83.54133053299995, 12.769964911000045 ], [ -83.544667120999918, 12.796779690000051 ], [ -83.564035610999952, 12.812689520000049 ], [ -83.590809699999909, 12.81907786700009 ], [ -83.616363084999932, 12.81712474200009 ], [ -83.63703365799995, 12.80532461100006 ], [ -83.645904100999928, 12.786851304000038 ], [ -83.645334438999896, 12.766506252000056 ], [ -83.637521938999896, 12.748846747000073 ], [ -83.61554928299995, 12.737290757000039 ], [ -83.613270636999914, 12.735256252000056 ], [ -83.613392706999946, 12.73187897300005 ], [ -83.611683722999942, 12.714911200000074 ], [ -83.610218878999945, 12.707912502000056 ], [ -83.605946417999917, 12.701076565000051 ], [ -83.601307745999918, 12.698228257000039 ], [ -83.597482876999948, 12.694322007000039 ], [ -83.59593665299991, 12.684027411000045 ], [ -83.596424933999913, 12.667141018000052 ], [ -83.598622199999909, 12.660223700000074 ], [ -83.603382941999939, 12.65265534100007 ], [ -83.599436001999948, 12.647935289000088 ], [ -83.589100714999915, 12.632147528000075 ], [ -83.620472785999937, 12.614243882000039 ], [ -83.673695441999939, 12.570461330000057 ], [ -83.705799933999913, 12.557074286000045 ], [ -83.749012824999909, 12.552557684000078 ], [ -83.767201300999943, 12.546698309000078 ], [ -83.774647589999915, 12.53351471600007 ], [ -83.774647589999915, 12.481431382000039 ], [ -83.773426886999914, 12.480292059000078 ], [ -83.769439256999931, 12.482489325000074 ], [ -83.761057094999899, 12.482001044000071 ], [ -83.749012824999909, 12.479478257000039 ], [ -83.740956183999913, 12.479722398000092 ], [ -83.734242316999939, 12.477687893000052 ], [ -83.726226365999935, 12.468329169000071 ], [ -83.71939042899993, 12.423651434000078 ], [ -83.723378058999913, 12.402289130000042 ], [ -83.730376756999931, 12.382066148000092 ], [ -83.733713344999899, 12.362982489000046 ], [ -83.726226365999935, 12.344794012000079 ], [ -83.70767167899993, 12.335882880000042 ], [ -83.676340298999946, 12.342474677000041 ], [ -83.671009894999941, 12.327093817000048 ], [ -83.67218990799995, 12.317084052000041 ], [ -83.677316860999952, 12.29751211100006 ], [ -83.678456183999913, 12.286118882000039 ], [ -83.676380988999938, 12.279852606000077 ], [ -83.671742316999939, 12.288967190000051 ], [ -83.655873175999943, 12.340277411000045 ], [ -83.649769660999937, 12.353176174000055 ], [ -83.64093990799995, 12.358465887000079 ], [ -83.621205206999946, 12.355658270000049 ], [ -83.617014126999948, 12.348049221000053 ], [ -83.663726365999935, 12.256089585000041 ], [ -83.685902472999942, 12.13743724200009 ], [ -83.678578253999945, 12.009426174000055 ], [ -83.671009894999941, 11.987941799000055 ], [ -83.677845831999946, 11.983872789000088 ], [ -83.685292120999918, 11.98110586100006 ], [ -83.681223110999952, 12.001654364000046 ], [ -83.688303188999896, 12.018744208000044 ], [ -83.713246222999942, 12.049302476000037 ], [ -83.723744269999941, 12.074652411000045 ], [ -83.715240037999934, 12.08539459800005 ], [ -83.700672980999911, 12.095200914000088 ], [ -83.692738410999937, 12.118231512000079 ], [ -83.697865363999938, 12.135199286000045 ], [ -83.711008266999897, 12.154730536000045 ], [ -83.728627081999946, 12.171576239000046 ], [ -83.747385219999899, 12.18032461100006 ], [ -83.777740037999934, 12.177150783000059 ], [ -83.776275193999936, 12.162298895000049 ], [ -83.760324673999946, 12.15306224200009 ], [ -83.747385219999899, 12.16665273600006 ], [ -83.739898240999935, 12.16665273600006 ], [ -83.723052537999934, 12.149359442000048 ], [ -83.716135219999899, 12.138902085000041 ], [ -83.713246222999942, 12.125677802000041 ], [ -83.716908331999946, 12.108791408000059 ], [ -83.732045050999943, 12.087062893000052 ], [ -83.733713344999899, 12.07103099200009 ], [ -83.739369269999941, 12.051947333000044 ], [ -83.757313605999911, 12.051336981000077 ], [ -83.798573370999918, 12.063625393000052 ], [ -83.803944464999915, 12.060288804000038 ], [ -83.791737433999913, 12.052964585000041 ], [ -83.767201300999943, 12.043158270000049 ], [ -83.761301235999952, 12.035345770000049 ], [ -83.757232225999928, 12.024644273000092 ], [ -83.754953579999949, 12.012274481000077 ], [ -83.75422115799995, 11.999090887000079 ], [ -83.756255662999934, 11.990057684000078 ], [ -83.765207485999952, 11.971625067000048 ], [ -83.767201300999943, 11.96430084800005 ], [ -83.765533006999931, 11.958807684000078 ], [ -83.762115037999934, 11.953070380000042 ], [ -83.759836391999897, 11.946844794000071 ], [ -83.761057094999899, 11.940130927000041 ], [ -83.76626542899993, 11.933986721000053 ], [ -83.771880662999934, 11.931057033000059 ], [ -83.777088995999918, 11.929266669000071 ], [ -83.780873175999943, 11.926459052000041 ], [ -83.799387173999946, 11.902899481000077 ], [ -83.805083787999934, 11.899115302000041 ], [ -83.813710089999915, 11.896185614000046 ], [ -83.823475714999915, 11.88898346600007 ], [ -83.831857876999948, 11.879868882000039 ], [ -83.836089647999927, 11.871242580000057 ], [ -83.822987433999913, 11.862534898000092 ], [ -83.80695553299995, 11.848211981000077 ], [ -83.793365037999934, 11.83274974200009 ], [ -83.784779425999943, 11.813544012000079 ], [ -83.777495897999927, 11.808294989000046 ], [ -83.767730272999927, 11.804836330000057 ], [ -83.757639126999948, 11.803615627000056 ], [ -83.742909308999913, 11.805243231000077 ], [ -83.741810675999943, 11.809759833000044 ], [ -83.745961066999939, 11.816310940000051 ], [ -83.747385219999899, 11.824042059000078 ], [ -83.740589972999942, 11.843451239000046 ], [ -83.735096808999913, 11.853664455000057 ], [ -83.726226365999935, 11.857570705000057 ], [ -83.709543423999946, 11.85814036700009 ], [ -83.699940558999913, 11.84992096600007 ], [ -83.653635219999899, 11.667466539000088 ], [ -83.651193813999896, 11.63226959800005 ], [ -83.651722785999937, 11.619370835000041 ], [ -83.65298417899993, 11.611517645000049 ], [ -83.656809048999946, 11.605414130000042 ], [ -83.664784308999913, 11.598089911000045 ], [ -83.666737433999913, 11.600978908000059 ], [ -83.680897589999915, 11.598130601000037 ], [ -83.694732225999928, 11.593654690000051 ], [ -83.695871548999946, 11.59125397300005 ], [ -83.70376542899993, 11.587958075000074 ], [ -83.713734503999945, 11.573472398000092 ], [ -83.722808397999927, 11.570217190000051 ], [ -83.734934048999946, 11.569973049000055 ], [ -83.744699673999946, 11.568508205000057 ], [ -83.753041144999941, 11.564601955000057 ], [ -83.761057094999899, 11.557114976000037 ], [ -83.771229620999918, 11.52610911700009 ], [ -83.780913865999935, 11.479315497000073 ], [ -83.794422980999911, 11.44399648600006 ], [ -83.815663214999915, 11.447251695000091 ], [ -83.821888800999943, 11.447251695000091 ], [ -83.853627081999946, 11.407416083000044 ], [ -83.862782355999911, 11.39203522300005 ], [ -83.868031378999945, 11.374904690000051 ], [ -83.867909308999913, 11.273667710000041 ], [ -83.837269660999937, 11.142523505000042 ], [ -83.815663214999915, 11.090399481000077 ], [ -83.785633917999917, 11.044826565000051 ], [ -83.775949673999946, 11.01984284100007 ], [ -83.752064581999946, 10.982245184000078 ], [ -83.743641730999911, 10.974310614000046 ], [ -83.725453253999945, 10.96320221600007 ], [ -83.718251105999911, 10.94399648600006 ], [ -83.735529344203883, 10.957160955913366 ], [ -83.761419236808308, 10.984704494916514 ], [ -83.775914476272021, 11.008294785975579 ], [ -83.794130418783766, 11.031704209881354 ], [ -83.797592740312723, 11.034985663357645 ], [ -83.799866503436363, 11.036535956069486 ], [ -83.807307908633049, 11.038938910402408 ], [ -83.84668535034865, 11.046535346129303 ], [ -83.858002489123578, 11.047388006851008 ], [ -83.865107998435349, 11.047155462854334 ], [ -83.867510951868894, 11.045992742870794 ], [ -83.8695780103169, 11.044674994155628 ], [ -83.871980963750445, 11.043667303803034 ], [ -83.874874843599116, 11.043744819068138 ], [ -83.878337165128073, 11.045605170142494 ], [ -83.882652147378678, 11.050798652435844 ], [ -83.88422827761292, 11.054674384215446 ], [ -83.884977587345759, 11.058550115995047 ], [ -83.885132616077328, 11.065164699791069 ], [ -83.88559770407079, 11.068110256483124 ], [ -83.886631231945785, 11.07059072518183 ], [ -83.888155687135225, 11.072528591521291 ], [ -83.89154049339902, 11.076016751471911 ], [ -83.894434374147011, 11.080047511983082 ], [ -83.895571254809568, 11.082450466315947 ], [ -83.896837327580613, 11.087876491706709 ], [ -83.896992357211502, 11.091054592395494 ], [ -83.895416226077941, 11.109606431691475 ], [ -83.895622931652952, 11.112707017115156 ], [ -83.897302415574018, 11.114567369088775 ], [ -83.900247972266072, 11.115109972347341 ], [ -83.914174770948932, 11.108598741338824 ], [ -83.919058193980447, 11.107358506989499 ], [ -83.928644171990925, 11.106118271740854 ], [ -83.936524827658673, 11.103017686317173 ], [ -83.938669399573143, 11.101622423236222 ], [ -83.940994838640847, 11.100537218517786 ], [ -83.943552822604659, 11.099607042530977 ], [ -83.945826585728355, 11.098444322547437 ], [ -83.94957312719805, 11.098289292916547 ], [ -83.954172329389451, 11.098909410540841 ], [ -83.963758308299248, 11.102475083957927 ], [ -83.969881964780825, 11.103482774310578 ], [ -83.977271694932767, 11.102242539961253 ], [ -83.980940721137358, 11.100847275980982 ], [ -83.985979173799819, 11.097979234554032 ], [ -83.987968716083344, 11.096506456207976 ], [ -83.992412888643855, 11.094181016240896 ], [ -83.994686651767552, 11.093405869884975 ], [ -84.000965338779338, 11.092010605904704 ], [ -84.009569464858885, 11.087488918079089 ], [ -84.013600227168752, 11.088031521337598 ], [ -84.018922898872688, 11.090589504402089 ], [ -84.02874142087984, 11.098599351279006 ], [ -84.039670986926467, 11.109838974788829 ], [ -84.041040411585698, 11.111931870759236 ], [ -84.041505499579102, 11.114567369088775 ], [ -84.041376309269253, 11.117461248937502 ], [ -84.040575323592293, 11.123042303959153 ], [ -84.043779262702799, 11.124825141567044 ], [ -84.050238816867875, 11.125445258292018 ], [ -84.081968146013139, 11.121414495982208 ], [ -84.094448004771607, 11.125522773557122 ], [ -84.11082943373134, 11.132034002767 ], [ -84.117211472631368, 11.133506781113056 ], [ -84.119950323748412, 11.13373932510973 ], [ -84.126332364447023, 11.133661810743945 ], [ -84.136590135126596, 11.132344062028835 ], [ -84.138863898250293, 11.132499090760405 ], [ -84.141731939677243, 11.132964178753809 ], [ -84.149250861038411, 11.135754705815032 ], [ -84.154857753582462, 11.13722748506035 ], [ -84.157777472752173, 11.138235175413001 ], [ -84.164133674129744, 11.141955878461033 ], [ -84.16793189244288, 11.143738715169548 ], [ -84.171420050594861, 11.144539699947188 ], [ -84.174417284130357, 11.144358831894579 ], [ -84.178551398328352, 11.147020167746518 ], [ -84.183589850990813, 11.1528337667649 ], [ -84.204002041361093, 11.185958359890378 ], [ -84.212683681806482, 11.197042955567952 ], [ -84.241079882430597, 11.225051580765808 ], [ -84.280534837612663, 11.25306020776236 ], [ -84.327560390999224, 11.276883042818156 ], [ -84.336836310647186, 11.283471788192458 ], [ -84.345828010354353, 11.292721869418699 ], [ -84.353346930816201, 11.307914739973285 ], [ -84.355388149943167, 11.320730496415251 ], [ -84.356111620354966, 11.333132839009295 ], [ -84.361976895317468, 11.346801256173023 ], [ -84.377453985812792, 11.361994126727552 ], [ -84.457190721174811, 11.410880032087789 ], [ -84.486129523258853, 11.428243312978509 ], [ -84.5525595766631, 11.45237620729614 ], [ -84.556280279711132, 11.491030177700509 ], [ -84.563644172340673, 11.529658311481853 ], [ -84.563308274657118, 11.542654934177847 ], [ -84.560517747595952, 11.562007758251411 ], [ -84.546384243338139, 11.610118516356408 ], [ -84.536514045386866, 11.63295950038065 ], [ -84.534782883723096, 11.644095771102968 ], [ -84.534291958207291, 11.652131456401605 ], [ -84.544265509845388, 11.683524888762577 ], [ -84.55506588378347, 11.708820502164428 ], [ -84.556357794976236, 11.734891261922201 ], [ -84.555220913414416, 11.746906032687264 ], [ -84.557598029325561, 11.753262234064835 ], [ -84.563928392281468, 11.759773464174032 ], [ -84.57219662067746, 11.766568915123344 ], [ -84.587156949033954, 11.793621527711309 ], [ -84.607414109773345, 11.862506212291862 ], [ -84.612581752745655, 11.87919769871479 ], [ -84.619713101378522, 11.892426866306835 ], [ -84.620720790831797, 11.895320746155505 ], [ -84.621573451553559, 11.899635728406111 ], [ -84.613615282419346, 11.906508693721207 ], [ -84.574625414331365, 11.922528388374417 ], [ -84.702421230955053, 11.982731432509581 ], [ -84.709320034691814, 11.99293752724509 ], [ -84.772701178616501, 12.150033881158663 ], [ -84.785982022152609, 12.209694322035318 ], [ -84.787403123655224, 12.242689723951571 ], [ -84.781098599121037, 12.265168971870537 ], [ -84.784225022966439, 12.280284328958601 ], [ -84.819649216737957, 12.341960151439821 ], [ -84.825540331021443, 12.348238837552287 ], [ -84.83277503064312, 12.354181626880575 ], [ -84.839596320014152, 12.361493841767356 ], [ -84.846934374221973, 12.37356028937586 ], [ -84.852153693138405, 12.389864203070488 ], [ -84.856339484179841, 12.422136135474261 ], [ -84.855150925774581, 12.439163520480065 ], [ -84.852360398713415, 12.451462511185923 ], [ -84.846650153381859, 12.464975897819443 ], [ -84.845332403767429, 12.470815335259488 ], [ -84.847347785371994, 12.47758494688776 ], [ -84.853678148327845, 12.488075263362703 ], [ -84.867010667808074, 12.500813502740925 ], [ -84.887862107750038, 12.531793524851253 ], [ -84.90972123894403, 12.579490871806286 ], [ -84.915612352328196, 12.589180203503588 ], [ -84.944499477568797, 12.615250963261303 ], [ -84.968529019098924, 12.649512437049339 ], [ -84.973774177336395, 12.654654242499305 ], [ -84.985298020787013, 12.660416165573565 ], [ -84.986383226404769, 12.663749294094657 ], [ -84.986848314398173, 12.668193468453808 ], [ -84.983928596127782, 12.683722235792516 ], [ -84.985220507320548, 12.702144883879271 ], [ -84.989613003037618, 12.714779771369365 ], [ -84.998217129117222, 12.730696113235012 ], [ -85.004289109654678, 12.737724107281736 ], [ -85.010206062359885, 12.742917589575086 ], [ -85.019171922746011, 12.747697658919833 ], [ -85.027078416835479, 12.760048326469075 ], [ -85.031987678288715, 12.7620378687526 ], [ -85.061391568366162, 12.783845323103151 ], [ -85.079917569240422, 12.793663845110359 ], [ -85.098572761323851, 12.793224596437938 ], [ -85.117718878923085, 12.776248888275575 ], [ -85.122886521895452, 12.764337470298017 ], [ -85.126452196211858, 12.736328844200784 ], [ -85.1307671775632, 12.721626899162061 ], [ -85.133686895833534, 12.72196279504692 ], [ -85.142006801972343, 12.71700185854894 ], [ -85.149241503392659, 12.710904038690444 ], [ -85.148776415399254, 12.707958481998332 ], [ -85.15213538324133, 12.706098130923976 ], [ -85.165519578665624, 12.693695787430613 ], [ -85.155339322351836, 12.677546902467554 ], [ -85.154279955155801, 12.662689927797942 ], [ -85.162315639555118, 12.654964300861764 ], [ -85.179187994930032, 12.660157782255851 ], [ -85.205052049112737, 12.714521388950914 ], [ -85.212803513571259, 12.748395290909912 ], [ -85.217118495821921, 12.75958323847567 ], [ -85.226807826619904, 12.77865184170912 ], [ -85.227893033136979, 12.788056952566308 ], [ -85.226187709894873, 12.797875474573459 ], [ -85.222311978115272, 12.805756130241207 ], [ -85.215568203110081, 12.812319037193788 ], [ -85.206809048298908, 12.816737372231955 ], [ -85.192132940782585, 12.817874253793775 ], [ -85.181048346903651, 12.816349799503655 ], [ -85.169085252982029, 12.81603974024182 ], [ -85.159395922184046, 12.819217840930605 ], [ -85.148027105666358, 12.829191392568703 ], [ -85.144590624357818, 12.838803209000901 ], [ -85.144797329033509, 12.85459035875806 ], [ -85.141335008403871, 12.859422104946191 ], [ -85.131258103978325, 12.860843207348125 ], [ -85.122731493163883, 12.85918956094946 ], [ -85.105006477067263, 12.853944404510628 ], [ -85.094025235076515, 12.852704169261983 ], [ -85.081958788367388, 12.853117581311324 ], [ -85.067954475318743, 12.855701401898159 ], [ -85.040643480312326, 12.863685411252732 ], [ -85.030592414308444, 12.864848131236272 ], [ -84.971293707738425, 12.854745388388949 ], [ -84.958245409098311, 12.850714626978458 ], [ -84.95436967641939, 12.855262153225794 ], [ -84.942044847291868, 12.863168647315206 ], [ -84.935869513966907, 12.868723863015873 ], [ -84.925663418332078, 12.8838650585256 ], [ -84.918506232176867, 12.900375677795296 ], [ -84.898352424224981, 12.89660329790388 ], [ -84.875666469831685, 12.911822007779449 ], [ -84.854711677102216, 12.931536567058913 ], [ -84.839983893641772, 12.941329251543721 ], [ -84.828149990929319, 12.942595323415446 ], [ -84.809365606737344, 12.947633775178588 ], [ -84.795593837685431, 12.948176378437097 ], [ -84.782752244620383, 12.944998276848992 ], [ -84.776783616870432, 12.94070913302005 ], [ -84.77151262111056, 12.94014069313846 ], [ -84.760841438381647, 12.948176378437097 ], [ -84.755337896826461, 12.950346787873968 ], [ -84.751022914575856, 12.949416611887102 ], [ -84.748180711570569, 12.950346787873968 ], [ -84.746217006809388, 12.965307115331086 ], [ -84.741953702301487, 12.975254828547463 ], [ -84.740971848571917, 12.978587957967875 ], [ -84.739809130387016, 12.993005683065803 ], [ -84.73353044337523, 13.026388657710356 ], [ -84.729292976389729, 13.03478607821495 ], [ -84.708234829074058, 13.057575385395694 ], [ -84.707614712349084, 13.05811798775494 ], [ -84.700870938243213, 13.063311469148971 ], [ -84.697124395874141, 13.065714423481836 ], [ -84.696452603205046, 13.066386217050251 ], [ -84.699165615900426, 13.066747952256151 ], [ -84.701801114230022, 13.066541245781877 ], [ -84.704617478813589, 13.065946967478567 ], [ -84.707072109989895, 13.064939277125916 ], [ -84.718234219133876, 13.058428046117399 ], [ -84.720998907773378, 13.05773041412732 ], [ -84.724021978831217, 13.057265326133859 ], [ -84.727329270729228, 13.057291165454899 ], [ -84.730429857052229, 13.057807929392425 ], [ -84.733091192904226, 13.05866059011413 ], [ -84.735390795348906, 13.059926662885175 ], [ -84.737432013576552, 13.061451117175295 ], [ -84.740739304575243, 13.065120144279206 ], [ -84.743529833435048, 13.069047552902248 ], [ -84.758050910421161, 13.09837392771459 ], [ -84.764329597432948, 13.117804267053259 ], [ -84.765492315617848, 13.120103867699299 ], [ -84.77324378097569, 13.129870713762443 ], [ -84.777222867341436, 13.133048814451229 ], [ -84.779393276778308, 13.134340724744618 ], [ -84.781873744577638, 13.135374254418309 ], [ -84.784664273437443, 13.136123562352509 ], [ -84.787067226870988, 13.13713125180584 ], [ -84.789392665938749, 13.138371487054485 ], [ -84.796679043303186, 13.145089422738636 ], [ -84.798771939273536, 13.146277981143896 ], [ -84.800864834344623, 13.147182318709042 ], [ -84.797738409599901, 13.153977768759034 ], [ -84.794508632966995, 13.159171251052385 ], [ -84.751436326625139, 13.215731106505359 ], [ -84.492924974208165, 13.246530260563077 ], [ -84.35347612202537, 13.247150377288051 ], [ -84.333684048380121, 13.249708360352543 ], [ -84.321230028043317, 13.254100856968932 ], [ -84.3089827141809, 13.267123318086647 ], [ -84.298440720862573, 13.273918769035959 ], [ -84.290973477244165, 13.276295884947103 ], [ -84.284488084657369, 13.27663178083202 ], [ -84.276891648930416, 13.27588247289782 ], [ -84.271517300383096, 13.274538885760933 ], [ -84.265212774949589, 13.271515814703093 ], [ -84.258339809634492, 13.267123318086647 ], [ -84.246635098131264, 13.263841863711036 ], [ -84.236894089590521, 13.264203598916936 ], [ -84.176613531988892, 13.280636704720109 ], [ -84.163100145355429, 13.282342027062896 ], [ -84.155193651265961, 13.280326646357651 ], [ -84.152609828880486, 13.275391547382014 ], [ -84.133334520072026, 13.216144516756003 ], [ -84.129277920239815, 13.208987332399431 ], [ -84.123619350852323, 13.202682806965981 ], [ -84.117185635108967, 13.201416734194936 ], [ -84.108607346551764, 13.197308458418604 ], [ -84.084448614711789, 13.204439806152095 ], [ -84.068764817742135, 13.201416734194936 ], [ -84.071839565643415, 13.205860906755447 ], [ -84.077265591034177, 13.215886135236929 ], [ -84.082433234006544, 13.221260483784306 ], [ -84.063493821982263, 13.217824002475709 ], [ -84.04806840743106, 13.212087917823112 ], [ -84.036105312610061, 13.214516710577698 ], [ -84.02781124489303, 13.235549018572328 ], [ -84.021015794843038, 13.230975653903272 ], [ -84.016390754229917, 13.230536404331588 ], [ -84.007321540156909, 13.235549018572328 ], [ -84.000500250785933, 13.235549018572328 ], [ -83.991456875134645, 13.230122992282247 ], [ -83.987606980877445, 13.234463812954573 ], [ -83.98869218559588, 13.244437363693351 ], [ -83.994273240617531, 13.256038723308393 ], [ -83.983808762564308, 13.254255885700559 ], [ -83.979752162732098, 13.251568712326218 ], [ -83.964559292177569, 13.250302639555173 ], [ -83.883530645622784, 13.247150377288051 ], [ -83.864307013657765, 13.244204819696677 ], [ -83.854126757343977, 13.240044867076961 ], [ -83.84629777672103, 13.235419827363103 ], [ -83.835859137988791, 13.231208197000683 ], [ -83.818625048307297, 13.226557318865162 ], [ -83.810925258893576, 13.222759101451345 ], [ -83.807204555845544, 13.218159898360625 ], [ -83.807824672570575, 13.212501328973133 ], [ -83.81002092222775, 13.206765245219856 ], [ -83.813664110010677, 13.200796617469905 ], [ -83.832551846090837, 13.178136502397649 ], [ -83.836143357929586, 13.172400417745052 ], [ -83.838339605788178, 13.166690172413496 ], [ -83.839037237778257, 13.161031602126741 ], [ -83.838158738634888, 13.155786444788589 ], [ -83.835239021263817, 13.151290595384637 ], [ -83.830924038113835, 13.147285671496547 ], [ -83.755734828999152, 13.093645535213284 ], [ -83.657291225609583, 13.037447414966209 ], [ -83.638946091888613, 13.031504624738602 ], [ -83.598173387092118, 13.033364975812958 ], [ -83.547969733016771, 13.030264391288597 ], [ -83.529650437717521, 13.032589830356358 ], [ -83.529571092999902, 13.032619533000059 ] ] ], [ [ [ -83.726226365999935, 11.878648179000038 ], [ -83.733794725999928, 11.905829169000071 ], [ -83.736073370999918, 11.941799221000053 ], [ -83.728993292999917, 11.973334052000041 ], [ -83.708404100999928, 11.987290757000039 ], [ -83.706857876999948, 11.98704661700009 ], [ -83.705677863999938, 11.986232815000051 ], [ -83.70531165299991, 11.984320380000042 ], [ -83.705799933999913, 11.98110586100006 ], [ -83.712391730999911, 11.970851955000057 ], [ -83.719309048999946, 11.95453522300005 ], [ -83.724517381999931, 11.936346747000073 ], [ -83.726226365999935, 11.92023346600007 ], [ -83.720366990999935, 11.883693752000056 ], [ -83.719838019999941, 11.870306708000044 ], [ -83.726226365999935, 11.878648179000038 ] ] ], [ [ [ -83.053944464999915, 12.143866278000075 ], [ -83.055978969999899, 12.166205145000049 ], [ -83.046457485999952, 12.183742580000057 ], [ -83.032541469999899, 12.190822658000059 ], [ -83.021148240999935, 12.181789455000057 ], [ -83.025054490999935, 12.175197658000059 ], [ -83.053944464999915, 12.143866278000075 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-LE", "NAME_1": "León" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -86.670720801317927, 12.000522848093718 ], [ -86.689808722999942, 12.02407461100006 ], [ -86.7275691399999, 12.088283596000053 ], [ -86.762684699999909, 12.18227773600006 ], [ -86.772572394999941, 12.197414455000057 ], [ -86.79751542899993, 12.218532619000086 ], [ -87.002227342999902, 12.341376044000071 ], [ -87.015044725999928, 12.356838283000059 ], [ -87.071400519999941, 12.388698635000083 ], [ -87.101958787999934, 12.420965887000079 ], [ -87.171009894999941, 12.451442776000079 ], [ -87.173573370999918, 12.474514065000051 ], [ -87.162098761999914, 12.45962148600006 ], [ -87.142486131999931, 12.446844794000071 ], [ -87.119618292999917, 12.437689520000049 ], [ -87.097808397999927, 12.433539130000042 ], [ -87.120843412540935, 12.45838376929831 ], [ -87.120749071312559, 12.458438829288525 ], [ -87.098657396121894, 12.471332099197014 ], [ -87.049383918033357, 12.47665477090095 ], [ -87.032227341818327, 12.484173692262061 ], [ -87.015303311398668, 12.493914699903485 ], [ -87.005794846854656, 12.499650784556025 ], [ -86.953937548179283, 12.552412420796543 ], [ -86.933783739328078, 12.584374293938481 ], [ -86.92610978923534, 12.604088853218002 ], [ -86.922156542190635, 12.610600084226519 ], [ -86.902752041273686, 12.628738512372422 ], [ -86.877301398240945, 12.655636095329498 ], [ -86.852806769616734, 12.681629339822166 ], [ -86.833324755233264, 12.690362657110938 ], [ -86.814075283947204, 12.712996933761474 ], [ -86.800200161208465, 12.73935191525868 ], [ -86.793042975952574, 12.746199042152057 ], [ -86.782010057118441, 12.752115993957943 ], [ -86.709921434326702, 12.761340236762521 ], [ -86.695710414803784, 12.764905911078927 ], [ -86.687855597557757, 12.767928982136823 ], [ -86.670001390251969, 12.778755195395945 ], [ -86.657573208336885, 12.806970527068131 ], [ -86.65460181322311, 12.838234768219991 ], [ -86.663903571292792, 12.959157620427845 ], [ -86.676254238842034, 12.987037055315852 ], [ -86.689819302318938, 13.008611964770353 ], [ -86.710954963101074, 13.056335151046369 ], [ -86.720695969843121, 13.090234890527768 ], [ -86.703358527374121, 13.09703034147708 ], [ -86.693772549363644, 13.097831326254664 ], [ -86.680543381771656, 13.097572943836269 ], [ -86.664652880126312, 13.092327786498117 ], [ -86.645248379209306, 13.083026028428435 ], [ -86.633414475597533, 13.083878689150197 ], [ -86.613053962070694, 13.088297024188307 ], [ -86.547088995760532, 13.109949448907912 ], [ -86.491175096353572, 13.121524970101291 ], [ -86.479056972801061, 13.11824351572568 ], [ -86.471486376395148, 13.114522813576968 ], [ -86.453373785771589, 13.096668606271123 ], [ -86.427070482017143, 13.053958035135224 ], [ -86.416916063225699, 13.040418809180665 ], [ -86.411722581831668, 13.031814683101118 ], [ -86.404720425307346, 13.006906643326886 ], [ -86.406839158800096, 12.975513210066595 ], [ -86.428853318725658, 12.937298489233854 ], [ -86.430222744284208, 12.925748806462252 ], [ -86.429938524343413, 12.917299710013594 ], [ -86.419964972705316, 12.899755561070265 ], [ -86.386349453164712, 12.883296616845371 ], [ -86.263902146666737, 12.848518378220547 ], [ -86.266847704258112, 12.823713691233877 ], [ -86.278681606970565, 12.724598294275836 ], [ -86.288810188239552, 12.636464138409224 ], [ -86.328342657787402, 12.612615464931764 ], [ -86.34255367731032, 12.599257107029871 ], [ -86.350976936236577, 12.588120836307553 ], [ -86.353715785555039, 12.582358914132556 ], [ -86.354878506437899, 12.577346299891815 ], [ -86.354620124019505, 12.57380646399713 ], [ -86.356325446362234, 12.563522853996517 ], [ -86.356325446362234, 12.55987966621359 ], [ -86.355808682424765, 12.55701162388732 ], [ -86.35609290236556, 12.552412420796543 ], [ -86.35741065108067, 12.546107896262413 ], [ -86.363456794095782, 12.528512071374962 ], [ -86.364412807604992, 12.523809516396057 ], [ -86.363921882089187, 12.521018988435571 ], [ -86.362139045380616, 12.515903022306645 ], [ -86.36105383976286, 12.513525906395444 ], [ -86.351467861752383, 12.500115872549486 ], [ -86.351183640912268, 12.499805813287651 ], [ -86.345292528427422, 12.494689846259405 ], [ -86.344052294078097, 12.492829495185049 ], [ -86.343277146822857, 12.490297348743638 ], [ -86.343122118091287, 12.483941148265387 ], [ -86.342579514832721, 12.480711370733161 ], [ -86.341416795748501, 12.476913154218664 ], [ -86.342812058829452, 12.473838406317384 ], [ -86.346842821139262, 12.469110012017438 ], [ -86.444149542967011, 12.374878038090969 ], [ -86.510915494054814, 12.308861395836743 ], [ -86.524842291838297, 12.289741115759853 ], [ -86.526418422971801, 12.274186509999424 ], [ -86.526547614181027, 12.203260606291906 ], [ -86.525229864566597, 12.196516832186035 ], [ -86.522516852770536, 12.190625718801869 ], [ -86.51835690015082, 12.187215074116352 ], [ -86.513344285910023, 12.184321194267682 ], [ -86.506910570166667, 12.176879788171675 ], [ -86.505515306186396, 12.158922227179005 ], [ -86.518253547363315, 12.131120307556159 ], [ -86.537709724224385, 12.109002793943773 ], [ -86.575459357063664, 12.080761623849867 ], [ -86.581092088928756, 12.077996934311045 ], [ -86.584037644721491, 12.07789358242286 ], [ -86.598196988300344, 12.080839138215651 ], [ -86.612459682868064, 12.086110133975467 ], [ -86.614268357998299, 12.086394354815582 ], [ -86.616852180383773, 12.086497708502407 ], [ -86.619642707444996, 12.086187649240628 ], [ -86.622355720140376, 12.085490017250493 ], [ -86.637341885119895, 12.08021902149062 ], [ -86.644395717588282, 12.078746243144565 ], [ -86.648038907169791, 12.077066759223555 ], [ -86.650751918965852, 12.075335598459105 ], [ -86.652198858890188, 12.073320216854484 ], [ -86.653154873298774, 12.070865587476874 ], [ -86.653284063608623, 12.067997545150547 ], [ -86.652844814936259, 12.065129502824277 ], [ -86.651268683802698, 12.059703477433516 ], [ -86.644344041644217, 12.045880032437537 ], [ -86.639589809821871, 12.040298977415887 ], [ -86.638375413894209, 12.038154405501416 ], [ -86.637419400384999, 12.034588731185011 ], [ -86.637496913851464, 12.032237453695529 ], [ -86.637987841165909, 12.029601956265253 ], [ -86.642302823416571, 12.022134710848206 ], [ -86.645842658411937, 12.0181556262811 ], [ -86.670595668555222, 12.00061147733777 ], [ -86.670720801317927, 12.000522848093718 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-MN", "NAME_1": "Managua" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -86.502340697627318, 11.766775283401987 ], [ -86.515614386999914, 11.783107815000051 ], [ -86.542388475999928, 11.842352606000077 ], [ -86.553212042999917, 11.851345119000086 ], [ -86.563262498999904, 11.856634833000044 ], [ -86.589629686999899, 11.882839260000083 ], [ -86.605213995999918, 11.904689846000053 ], [ -86.622222459999932, 11.936102606000077 ], [ -86.625477667999917, 11.950995184000078 ], [ -86.630360480999911, 11.964911200000074 ], [ -86.641875779999907, 11.976507880000042 ], [ -86.666493292999917, 11.995306708000044 ], [ -86.670720801317927, 12.000522848093718 ], [ -86.670595668555222, 12.00061147733777 ], [ -86.645842658411937, 12.0181556262811 ], [ -86.642302823416571, 12.022134710848206 ], [ -86.637987841165909, 12.029601956265253 ], [ -86.637496913851464, 12.032237453695529 ], [ -86.637419400384999, 12.034588731185011 ], [ -86.638375413894209, 12.038154405501416 ], [ -86.639589809821871, 12.040298977415887 ], [ -86.644344041644217, 12.045880032437537 ], [ -86.651268683802698, 12.059703477433516 ], [ -86.652844814936259, 12.065129502824277 ], [ -86.653284063608623, 12.067997545150547 ], [ -86.653154873298774, 12.070865587476874 ], [ -86.652198858890188, 12.073320216854484 ], [ -86.650751918965852, 12.075335598459105 ], [ -86.648038907169791, 12.077066759223555 ], [ -86.644395717588282, 12.078746243144565 ], [ -86.637341885119895, 12.08021902149062 ], [ -86.622355720140376, 12.085490017250493 ], [ -86.619642707444996, 12.086187649240628 ], [ -86.616852180383773, 12.086497708502407 ], [ -86.614268357998299, 12.086394354815582 ], [ -86.612459682868064, 12.086110133975467 ], [ -86.598196988300344, 12.080839138215651 ], [ -86.584037644721491, 12.07789358242286 ], [ -86.581092088928756, 12.077996934311045 ], [ -86.575459357063664, 12.080761623849867 ], [ -86.537709724224385, 12.109002793943773 ], [ -86.518253547363315, 12.131120307556159 ], [ -86.505515306186396, 12.158922227179005 ], [ -86.506910570166667, 12.176879788171675 ], [ -86.513344285910023, 12.184321194267682 ], [ -86.51835690015082, 12.187215074116352 ], [ -86.522516852770536, 12.190625718801869 ], [ -86.525229864566597, 12.196516832186035 ], [ -86.526547614181027, 12.203260606291906 ], [ -86.526418422971801, 12.274186509999424 ], [ -86.524842291838297, 12.289741115759853 ], [ -86.510915494054814, 12.308861395836743 ], [ -86.444149542967011, 12.374878038090969 ], [ -86.346842821139262, 12.469110012017438 ], [ -86.342812058829452, 12.473838406317384 ], [ -86.341416795748501, 12.476913154218664 ], [ -86.342579514832721, 12.480711370733161 ], [ -86.343122118091287, 12.483941148265387 ], [ -86.343277146822857, 12.490297348743638 ], [ -86.344052294078097, 12.492829495185049 ], [ -86.345292528427422, 12.494689846259405 ], [ -86.351183640912268, 12.499805813287651 ], [ -86.351467861752383, 12.500115872549486 ], [ -86.36105383976286, 12.513525906395444 ], [ -86.362139045380616, 12.515903022306645 ], [ -86.363921882089187, 12.521018988435571 ], [ -86.364412807604992, 12.523809516396057 ], [ -86.363456794095782, 12.528512071374962 ], [ -86.35741065108067, 12.546107896262413 ], [ -86.35609290236556, 12.552412420796543 ], [ -86.355808682424765, 12.55701162388732 ], [ -86.356325446362234, 12.55987966621359 ], [ -86.356325446362234, 12.563522853996517 ], [ -86.354620124019505, 12.57380646399713 ], [ -86.354878506437899, 12.577346299891815 ], [ -86.353715785555039, 12.582358914132556 ], [ -86.350976936236577, 12.588120836307553 ], [ -86.34255367731032, 12.599257107029871 ], [ -86.328342657787402, 12.612615464931764 ], [ -86.288810188239552, 12.636464138409224 ], [ -86.118898077883955, 12.59961884223577 ], [ -86.101147224264992, 12.594115302479224 ], [ -86.086212735229537, 12.580653590890506 ], [ -86.070942349409904, 12.563781236414911 ], [ -86.06001278426254, 12.555047919126139 ], [ -86.050323451665918, 12.548588364961063 ], [ -85.988518438874848, 12.525256456320392 ], [ -85.972266202023604, 12.522078354732287 ], [ -85.978364020982781, 12.504560045109997 ], [ -85.974359097094634, 12.470867011203609 ], [ -85.969630702794689, 12.456655992579954 ], [ -85.962809414322976, 12.445261339439242 ], [ -85.950148688411218, 12.428569851217674 ], [ -85.924956427796872, 12.401646429838877 ], [ -85.921442430323907, 12.39611705255993 ], [ -85.920253871918646, 12.389941718335592 ], [ -85.922295091045612, 12.370304674321233 ], [ -85.922501796620622, 12.353613186099665 ], [ -85.920822312699556, 12.346404324000332 ], [ -85.91761837358905, 12.341133328240517 ], [ -85.830207689033614, 12.260130520107396 ], [ -85.828063117119143, 12.256797389787721 ], [ -85.829820116305314, 12.250983792567979 ], [ -85.846304898052608, 12.226308294991782 ], [ -85.851498379446639, 12.198764756888011 ], [ -85.869300909909043, 12.206051134252448 ], [ -85.876793992848491, 12.206180325461617 ], [ -85.885062222143802, 12.203157253504457 ], [ -85.91648149292655, 12.180833035216381 ], [ -86.000507372117511, 12.143806870990318 ], [ -86.018361579423356, 12.148328558815933 ], [ -86.023787604814117, 12.151248277086324 ], [ -86.025570440623312, 12.151894233132339 ], [ -86.028722703789754, 12.152281805860639 ], [ -86.045750087896238, 12.149956365893559 ], [ -86.080037401005256, 12.13631378805087 ], [ -86.109027879932682, 12.131275336287729 ], [ -86.127114631235202, 12.11796865522922 ], [ -86.187911952774357, 12.059057522286821 ], [ -86.184656337719787, 12.046319281109902 ], [ -86.170161099155393, 12.031720688858684 ], [ -86.164760912186352, 12.024227606818613 ], [ -86.162047898591652, 12.018310655012726 ], [ -86.163365648206081, 11.99603811356809 ], [ -86.174501918928399, 11.978235582206366 ], [ -86.180160489215211, 11.971672675253728 ], [ -86.186361660062573, 11.966014105866293 ], [ -86.194319830995369, 11.961750800459072 ], [ -86.203673265009172, 11.959218654916981 ], [ -86.211553920676863, 11.958495185404445 ], [ -86.223439501132077, 11.961621609249846 ], [ -86.230389980812959, 11.964773871516968 ], [ -86.25775265176344, 11.985521959570747 ], [ -86.281420458087666, 11.956996567737406 ], [ -86.293280199221783, 11.939245714118385 ], [ -86.35586035836883, 11.889248766517369 ], [ -86.375213182442394, 11.858165390720217 ], [ -86.382499558907512, 11.851189073516935 ], [ -86.409552172394797, 11.831396999871629 ], [ -86.419939134283595, 11.81638499647039 ], [ -86.432418993042063, 11.804628608123778 ], [ -86.436320563243385, 11.802716580205981 ], [ -86.441772427055867, 11.800675361079016 ], [ -86.453192918618299, 11.797910671540251 ], [ -86.459290737577476, 11.79710968676261 ], [ -86.467197231666887, 11.796799628400095 ], [ -86.477170783304985, 11.790805162228423 ], [ -86.502259691131826, 11.766853135963458 ], [ -86.502340697627318, 11.766775283401987 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-CA", "NAME_1": "Carazo" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -86.175200963732777, 11.519466114006992 ], [ -86.176136847999942, 11.522406317000048 ], [ -86.207142706999946, 11.536037502000056 ], [ -86.24437415299991, 11.571600653000075 ], [ -86.336455857999908, 11.611354885000083 ], [ -86.352080857999908, 11.622626044000071 ], [ -86.365386522999927, 11.637966213000084 ], [ -86.376616990999935, 11.66946035400008 ], [ -86.496367967999902, 11.759426174000055 ], [ -86.502340697627318, 11.766775283401987 ], [ -86.502259691131826, 11.766853135963458 ], [ -86.477170783304985, 11.790805162228423 ], [ -86.467197231666887, 11.796799628400095 ], [ -86.459290737577476, 11.79710968676261 ], [ -86.453192918618299, 11.797910671540251 ], [ -86.441772427055867, 11.800675361079016 ], [ -86.436320563243385, 11.802716580205981 ], [ -86.432418993042063, 11.804628608123778 ], [ -86.419939134283595, 11.81638499647039 ], [ -86.409552172394797, 11.831396999871629 ], [ -86.382499558907512, 11.851189073516935 ], [ -86.375213182442394, 11.858165390720217 ], [ -86.35586035836883, 11.889248766517369 ], [ -86.293280199221783, 11.939245714118385 ], [ -86.281420458087666, 11.956996567737406 ], [ -86.270516729563383, 11.944232489038143 ], [ -86.179075283597456, 11.907981472067263 ], [ -86.149748907885794, 11.894364731746975 ], [ -86.136597255558854, 11.876484686918729 ], [ -86.134297654912814, 11.87403005574248 ], [ -86.081122605723635, 11.858501288403716 ], [ -86.072466803700024, 11.856175849335955 ], [ -86.077350226731539, 11.845530504129442 ], [ -86.09781409394526, 11.809021103840848 ], [ -86.103472663332752, 11.783906358491663 ], [ -86.099984504281451, 11.759308377079947 ], [ -86.095669522030789, 11.742410183283312 ], [ -86.09551449329922, 11.730679633358363 ], [ -86.097865769889324, 11.721842963282143 ], [ -86.109828863811003, 11.705590725531522 ], [ -86.119104784358285, 11.687193914967168 ], [ -86.123213060134617, 11.656291409021321 ], [ -86.121998664206956, 11.641847846400992 ], [ -86.119440681142521, 11.632804469850385 ], [ -86.101689825724861, 11.610816148346544 ], [ -86.136623093980575, 11.587923489277614 ], [ -86.139723680303575, 11.584047755699373 ], [ -86.146260748834493, 11.57182628025862 ], [ -86.17512203565343, 11.519607245477971 ], [ -86.175200963732777, 11.519466114006992 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-MT", "NAME_1": "Matagalpa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -85.29587337925301, 12.652716376159844 ], [ -85.290447353862248, 12.677908636774134 ], [ -85.289052089882034, 12.680647487891235 ], [ -85.29626095198131, 12.686073513281997 ], [ -85.312203132268735, 12.687029526791207 ], [ -85.331090868348895, 12.697028916851025 ], [ -85.364112107787548, 12.708165188472663 ], [ -85.370985074001965, 12.711679185046364 ], [ -85.374473233053266, 12.721342678321946 ], [ -85.382844815136082, 12.731238714694939 ], [ -85.392947557084085, 12.738990180052781 ], [ -85.401706712794521, 12.742090766375782 ], [ -85.407623663701088, 12.743253486359322 ], [ -85.415245937849761, 12.737724107281736 ], [ -85.416744553718161, 12.735734564998154 ], [ -85.418346524172762, 12.731703802688344 ], [ -85.420594448874681, 12.727207953284392 ], [ -85.423772548664147, 12.723254706239686 ], [ -85.425658739059543, 12.721549383896956 ], [ -85.430025397254269, 12.718836371201576 ], [ -85.434598761923326, 12.716743476130489 ], [ -85.442427740747632, 12.714392197741745 ], [ -85.444959886289723, 12.713126125870019 ], [ -85.446691047054173, 12.711369127583168 ], [ -85.447750414250208, 12.709017849194367 ], [ -85.45335730679426, 12.707183336541732 ], [ -85.463537564007368, 12.706149806868098 ], [ -85.527538824657029, 12.709482937187772 ], [ -85.530768602189198, 12.708888657985142 ], [ -85.533404099619474, 12.707803453266763 ], [ -85.535316128436534, 12.706149806868098 ], [ -85.536892258670775, 12.704237778950301 ], [ -85.549888882266089, 12.67878713591756 ], [ -85.552886114902265, 12.674575507353779 ], [ -85.556787686002906, 12.673076891485323 ], [ -85.562704636909473, 12.672275905808419 ], [ -85.582005785038916, 12.672146715498513 ], [ -85.586656664073757, 12.671371568243273 ], [ -85.595674201303325, 12.666694850786712 ], [ -85.61603471572954, 12.662896633372895 ], [ -85.627894456863658, 12.660726223036761 ], [ -85.640115933203731, 12.650752672297983 ], [ -85.644120856192558, 12.648892320324308 ], [ -85.646988897619508, 12.648995673111813 ], [ -85.65285417438065, 12.652096259434813 ], [ -85.668718837604274, 12.655015976805885 ], [ -85.681870489931157, 12.658529975178226 ], [ -85.855735847331459, 12.623002427719825 ], [ -85.871936408238639, 12.614940903999525 ], [ -85.889532233126033, 12.57879323981615 ], [ -85.937358771290235, 12.552644964793274 ], [ -85.942707282315212, 12.548588364961063 ], [ -85.972266202023604, 12.522078354732287 ], [ -85.988518438874848, 12.525256456320392 ], [ -86.050323451665918, 12.548588364961063 ], [ -86.06001278426254, 12.555047919126139 ], [ -86.070942349409904, 12.563781236414911 ], [ -86.086212735229537, 12.580653590890506 ], [ -86.101147224264992, 12.594115302479224 ], [ -86.118898077883955, 12.59961884223577 ], [ -86.288810188239552, 12.636464138409224 ], [ -86.278681606970565, 12.724598294275836 ], [ -86.266847704258112, 12.823713691233877 ], [ -86.263902146666737, 12.848518378220547 ], [ -86.25832109164503, 12.884485175250632 ], [ -86.242430589999685, 12.91683462202019 ], [ -86.238890754105, 12.920968736218185 ], [ -86.231165127168879, 12.928255113582622 ], [ -86.208944260768988, 12.940605780232545 ], [ -86.197187873321695, 12.944636542542412 ], [ -86.171582200658008, 12.950114243877238 ], [ -86.15889563722385, 12.954455064549563 ], [ -86.150575731085098, 12.96019114830284 ], [ -86.146131557625267, 12.965539659327817 ], [ -86.143702765770001, 12.970991523140242 ], [ -86.137217373183205, 12.996726386113835 ], [ -86.09951941628799, 13.047007555454286 ], [ -86.094455126103185, 13.046826687401676 ], [ -86.080735032995335, 13.047162584185912 ], [ -86.071691657344104, 13.043364365872776 ], [ -86.057222256302055, 13.034992783789903 ], [ -86.041745164907411, 13.019619045182765 ], [ -86.007457851798392, 12.993935859052613 ], [ -85.994383714736614, 13.009619656022267 ], [ -85.989371101395193, 13.012100124720973 ], [ -85.97735632973081, 13.013934638272929 ], [ -85.941079475237586, 13.012487698348593 ], [ -85.928418749325829, 13.014193019792003 ], [ -85.918316005579186, 13.017526150111735 ], [ -85.896482713706234, 13.032615667878758 ], [ -85.83974199109997, 13.084989732290296 ], [ -85.793439908125265, 13.12397960037822 ], [ -85.782536179600982, 13.130258287390063 ], [ -85.745019090758433, 13.162220160531945 ], [ -85.672129483189053, 13.245858466095342 ], [ -85.65455949582406, 13.275107327441219 ], [ -85.639883389207057, 13.298155016141095 ], [ -85.625930752102533, 13.313864651532413 ], [ -85.604975959373007, 13.327713934950111 ], [ -85.581540697045511, 13.327791449315896 ], [ -85.562084520184442, 13.335129503523774 ], [ -85.506377326352492, 13.370579534817637 ], [ -85.485370855880262, 13.325052599098171 ], [ -85.43444373229238, 13.258002428069574 ], [ -85.414574144281289, 13.238959662358525 ], [ -85.401112433591948, 13.233688665699333 ], [ -85.396358201769601, 13.231053168269113 ], [ -85.390828823591335, 13.226815701283556 ], [ -85.362200079869751, 13.200951646201474 ], [ -85.359926316746112, 13.199504706277139 ], [ -85.357445848047405, 13.198471178402144 ], [ -85.35450029225467, 13.198083603875205 ], [ -85.35142554435339, 13.197928575143635 ], [ -85.345301886972493, 13.198652045555434 ], [ -85.339824184738291, 13.200176499845554 ], [ -85.336491055317936, 13.20012482300217 ], [ -85.332460293008126, 13.198936266395549 ], [ -85.324889695702893, 13.193871975311424 ], [ -85.310833705810865, 13.187050685940392 ], [ -85.307371385181284, 13.184725246872631 ], [ -85.305407681319423, 13.18144379339634 ], [ -85.304167446970098, 13.172477932110837 ], [ -85.302307094996422, 13.170540065771377 ], [ -85.290395677018864, 13.169093125847041 ], [ -85.283264330184693, 13.159248766317489 ], [ -85.252439337705255, 13.146588040405732 ], [ -85.241845669342126, 13.145192776425461 ], [ -85.21572323274097, 13.151368109750479 ], [ -85.187094489019444, 13.164416409289856 ], [ -85.177327643855676, 13.171728624176637 ], [ -85.168671840932689, 13.181469630918741 ], [ -85.156269497439325, 13.206739406798192 ], [ -85.144487270670993, 13.241440131057175 ], [ -85.13632239506245, 13.259449367993909 ], [ -85.123351609888857, 13.277484443352364 ], [ -85.097952643699557, 13.292160549070047 ], [ -85.064621344999068, 13.295131944183879 ], [ -84.998242966639566, 13.293736681102928 ], [ -84.982843391409347, 13.295209459448984 ], [ -84.973774177336395, 13.298775132866069 ], [ -84.883107875927692, 13.381534939285984 ], [ -84.878922084886312, 13.380398057724165 ], [ -84.875511441100116, 13.376754869041974 ], [ -84.86962032681663, 13.366626287772931 ], [ -84.769755621924389, 13.2426803654065 ], [ -84.751436326625139, 13.215731106505359 ], [ -84.794508632966995, 13.159171251052385 ], [ -84.797738409599901, 13.153977768759034 ], [ -84.800864834344623, 13.147182318709042 ], [ -84.798771939273536, 13.146277981143896 ], [ -84.796679043303186, 13.145089422738636 ], [ -84.789392665938749, 13.138371487054485 ], [ -84.787067226870988, 13.13713125180584 ], [ -84.784664273437443, 13.136123562352509 ], [ -84.781873744577638, 13.135374254418309 ], [ -84.779393276778308, 13.134340724744618 ], [ -84.777222867341436, 13.133048814451229 ], [ -84.77324378097569, 13.129870713762443 ], [ -84.765492315617848, 13.120103867699299 ], [ -84.764329597432948, 13.117804267053259 ], [ -84.758050910421161, 13.09837392771459 ], [ -84.743529833435048, 13.069047552902248 ], [ -84.740739304575243, 13.065120144279206 ], [ -84.737432013576552, 13.061451117175295 ], [ -84.735390795348906, 13.059926662885175 ], [ -84.733091192904226, 13.05866059011413 ], [ -84.730429857052229, 13.057807929392425 ], [ -84.727329270729228, 13.057291165454899 ], [ -84.724021978831217, 13.057265326133859 ], [ -84.720998907773378, 13.05773041412732 ], [ -84.718234219133876, 13.058428046117399 ], [ -84.707072109989895, 13.064939277125916 ], [ -84.704617478813589, 13.065946967478567 ], [ -84.701801114230022, 13.066541245781877 ], [ -84.699165615900426, 13.066747952256151 ], [ -84.696452603205046, 13.066386217050251 ], [ -84.697124395874141, 13.065714423481836 ], [ -84.700870938243213, 13.063311469148971 ], [ -84.707614712349084, 13.05811798775494 ], [ -84.708234829074058, 13.057575385395694 ], [ -84.729292976389729, 13.03478607821495 ], [ -84.73353044337523, 13.026388657710356 ], [ -84.739809130387016, 12.993005683065803 ], [ -84.740971848571917, 12.978587957967875 ], [ -84.741953702301487, 12.975254828547463 ], [ -84.746217006809388, 12.965307115331086 ], [ -84.748180711570569, 12.950346787873968 ], [ -84.751022914575856, 12.949416611887102 ], [ -84.755337896826461, 12.950346787873968 ], [ -84.760841438381647, 12.948176378437097 ], [ -84.77151262111056, 12.94014069313846 ], [ -84.776783616870432, 12.94070913302005 ], [ -84.782752244620383, 12.944998276848992 ], [ -84.795593837685431, 12.948176378437097 ], [ -84.809365606737344, 12.947633775178588 ], [ -84.828149990929319, 12.942595323415446 ], [ -84.839983893641772, 12.941329251543721 ], [ -84.854711677102216, 12.931536567058913 ], [ -84.875666469831685, 12.911822007779449 ], [ -84.898352424224981, 12.89660329790388 ], [ -84.918506232176867, 12.900375677795296 ], [ -84.925663418332078, 12.8838650585256 ], [ -84.935869513966907, 12.868723863015873 ], [ -84.942044847291868, 12.863168647315206 ], [ -84.95436967641939, 12.855262153225794 ], [ -84.958245409098311, 12.850714626978458 ], [ -84.971293707738425, 12.854745388388949 ], [ -85.030592414308444, 12.864848131236272 ], [ -85.040643480312326, 12.863685411252732 ], [ -85.067954475318743, 12.855701401898159 ], [ -85.081958788367388, 12.853117581311324 ], [ -85.094025235076515, 12.852704169261983 ], [ -85.105006477067263, 12.853944404510628 ], [ -85.122731493163883, 12.85918956094946 ], [ -85.131258103978325, 12.860843207348125 ], [ -85.141335008403871, 12.859422104946191 ], [ -85.144797329033509, 12.85459035875806 ], [ -85.144590624357818, 12.838803209000901 ], [ -85.148027105666358, 12.829191392568703 ], [ -85.159395922184046, 12.819217840930605 ], [ -85.169085252982029, 12.81603974024182 ], [ -85.181048346903651, 12.816349799503655 ], [ -85.192132940782585, 12.817874253793775 ], [ -85.206809048298908, 12.816737372231955 ], [ -85.215568203110081, 12.812319037193788 ], [ -85.222311978115272, 12.805756130241207 ], [ -85.226187709894873, 12.797875474573459 ], [ -85.227893033136979, 12.788056952566308 ], [ -85.226807826619904, 12.77865184170912 ], [ -85.217118495821921, 12.75958323847567 ], [ -85.212803513571259, 12.748395290909912 ], [ -85.205052049112737, 12.714521388950914 ], [ -85.179187994930032, 12.660157782255851 ], [ -85.178412848574112, 12.649357408317712 ], [ -85.179498054191811, 12.639797267829636 ], [ -85.182133551622087, 12.631735745008598 ], [ -85.186009284301008, 12.625405382052747 ], [ -85.192830572772721, 12.625405382052747 ], [ -85.197713995804236, 12.629720364303353 ], [ -85.207041592295639, 12.635895696728994 ], [ -85.21608496794687, 12.639332179836231 ], [ -85.220141567779137, 12.63566315453096 ], [ -85.223009610105407, 12.625844630725112 ], [ -85.229495001792884, 12.627549953967161 ], [ -85.260759242944687, 12.661811427755197 ], [ -85.272050544197214, 12.663516750997246 ], [ -85.289052089882034, 12.652716376159844 ], [ -85.29587337925301, 12.652716376159844 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-BO", "NAME_1": "Boaco" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -85.407623663701088, 12.743253486359322 ], [ -85.401706712794521, 12.742090766375782 ], [ -85.392947557084085, 12.738990180052781 ], [ -85.382844815136082, 12.731238714694939 ], [ -85.374473233053266, 12.721342678321946 ], [ -85.370985074001965, 12.711679185046364 ], [ -85.364112107787548, 12.708165188472663 ], [ -85.331090868348895, 12.697028916851025 ], [ -85.312203132268735, 12.687029526791207 ], [ -85.29626095198131, 12.686073513281997 ], [ -85.289052089882034, 12.680647487891235 ], [ -85.290447353862248, 12.677908636774134 ], [ -85.29587337925301, 12.652716376159844 ], [ -85.289052089882034, 12.652716376159844 ], [ -85.272050544197214, 12.663516750997246 ], [ -85.260759242944687, 12.661811427755197 ], [ -85.229495001792884, 12.627549953967161 ], [ -85.223009610105407, 12.625844630725112 ], [ -85.220141567779137, 12.63566315453096 ], [ -85.21608496794687, 12.639332179836231 ], [ -85.207041592295639, 12.635895696728994 ], [ -85.197713995804236, 12.629720364303353 ], [ -85.192830572772721, 12.625405382052747 ], [ -85.186009284301008, 12.625405382052747 ], [ -85.182133551622087, 12.631735745008598 ], [ -85.179498054191811, 12.639797267829636 ], [ -85.178412848574112, 12.649357408317712 ], [ -85.179187994930032, 12.660157782255851 ], [ -85.162315639555118, 12.654964300861764 ], [ -85.154279955155801, 12.662689927797942 ], [ -85.155339322351836, 12.677546902467554 ], [ -85.165519578665624, 12.693695787430613 ], [ -85.15213538324133, 12.706098130923976 ], [ -85.148776415399254, 12.707958481998332 ], [ -85.149241503392659, 12.710904038690444 ], [ -85.142006801972343, 12.71700185854894 ], [ -85.133686895833534, 12.72196279504692 ], [ -85.1307671775632, 12.721626899162061 ], [ -85.126452196211858, 12.736328844200784 ], [ -85.122886521895452, 12.764337470298017 ], [ -85.117718878923085, 12.776248888275575 ], [ -85.098572761323851, 12.793224596437938 ], [ -85.079917569240422, 12.793663845110359 ], [ -85.061391568366162, 12.783845323103151 ], [ -85.031987678288715, 12.7620378687526 ], [ -85.027078416835479, 12.760048326469075 ], [ -85.019171922746011, 12.747697658919833 ], [ -85.010206062359885, 12.742917589575086 ], [ -85.004289109654678, 12.737724107281736 ], [ -84.998217129117222, 12.730696113235012 ], [ -84.989613003037618, 12.714779771369365 ], [ -84.985220507320548, 12.702144883879271 ], [ -84.983928596127782, 12.683722235792516 ], [ -84.986848314398173, 12.668193468453808 ], [ -84.986383226404769, 12.663749294094657 ], [ -84.985298020787013, 12.660416165573565 ], [ -84.973774177336395, 12.654654242499305 ], [ -84.968529019098924, 12.649512437049339 ], [ -84.981215583432402, 12.624449368543537 ], [ -85.019275274634197, 12.569672348899758 ], [ -85.023228521678902, 12.561714178866225 ], [ -85.025708991276929, 12.553652655145925 ], [ -85.027130092779544, 12.542464708479486 ], [ -85.027621019194669, 12.505645249828376 ], [ -85.030437384677555, 12.494560655050179 ], [ -85.035656703593986, 12.483191840331131 ], [ -85.05229651587149, 12.462547105064857 ], [ -85.063303596283902, 12.451850083914223 ], [ -85.078005541322682, 12.440868841923475 ], [ -85.107383592079088, 12.426631984878213 ], [ -85.121723801911912, 12.424384060176237 ], [ -85.127744107404624, 12.424125677757786 ], [ -85.137950202140075, 12.425365912107168 ], [ -85.148621384868989, 12.422962957774246 ], [ -85.163710904434652, 12.417046006867736 ], [ -85.222234462850167, 12.377487697998845 ], [ -85.234145880827725, 12.371053982255489 ], [ -85.275047776833446, 12.357437241935145 ], [ -85.329049649221929, 12.351442775763473 ], [ -85.400854051173496, 12.338885403538541 ], [ -85.443719651940341, 12.340719916191176 ], [ -85.47283932207705, 12.341210841706982 ], [ -85.497592333119655, 12.345164088751687 ], [ -85.508547735789364, 12.345525823957587 ], [ -85.522810432155723, 12.34134003291615 ], [ -85.560560064995002, 12.323124091303782 ], [ -85.586346604811922, 12.304675604795307 ], [ -85.591074999111925, 12.30010224012625 ], [ -85.599110684410562, 12.289379381453273 ], [ -85.601100226694086, 12.284495958421758 ], [ -85.602262945778307, 12.278088080200746 ], [ -85.602107917046737, 12.253774318729825 ], [ -85.599704962713815, 12.23558421553912 ], [ -85.599937506710546, 12.228943793321378 ], [ -85.602082078625017, 12.221967475218776 ], [ -85.622132534688717, 12.176802272906571 ], [ -85.623295253772937, 12.175174464929626 ], [ -85.624457973756478, 12.173236599489485 ], [ -85.625879076158412, 12.171376248415129 ], [ -85.63525834769456, 12.156570949689581 ], [ -85.640038417938626, 12.146984972578423 ], [ -85.65665239089509, 12.046474310740848 ], [ -85.731479864803873, 12.041332506190201 ], [ -85.785094163564793, 12.114971421693724 ], [ -85.812301804884385, 12.138122463181105 ], [ -85.828347337959258, 12.144297797405386 ], [ -85.836796434407916, 12.150318101099458 ], [ -85.842119107011172, 12.15672597932047 ], [ -85.843746914088797, 12.164348253469086 ], [ -85.845271369278237, 12.179489447180231 ], [ -85.851498379446639, 12.198764756888011 ], [ -85.846304898052608, 12.226308294991782 ], [ -85.829820116305314, 12.250983792567979 ], [ -85.828063117119143, 12.256797389787721 ], [ -85.830207689033614, 12.260130520107396 ], [ -85.91761837358905, 12.341133328240517 ], [ -85.920822312699556, 12.346404324000332 ], [ -85.922501796620622, 12.353613186099665 ], [ -85.922295091045612, 12.370304674321233 ], [ -85.920253871918646, 12.389941718335592 ], [ -85.921442430323907, 12.39611705255993 ], [ -85.924956427796872, 12.401646429838877 ], [ -85.950148688411218, 12.428569851217674 ], [ -85.962809414322976, 12.445261339439242 ], [ -85.969630702794689, 12.456655992579954 ], [ -85.974359097094634, 12.470867011203609 ], [ -85.978364020982781, 12.504560045109997 ], [ -85.972266202023604, 12.522078354732287 ], [ -85.942707282315212, 12.548588364961063 ], [ -85.937358771290235, 12.552644964793274 ], [ -85.889532233126033, 12.57879323981615 ], [ -85.871936408238639, 12.614940903999525 ], [ -85.855735847331459, 12.623002427719825 ], [ -85.681870489931157, 12.658529975178226 ], [ -85.668718837604274, 12.655015976805885 ], [ -85.65285417438065, 12.652096259434813 ], [ -85.646988897619508, 12.648995673111813 ], [ -85.644120856192558, 12.648892320324308 ], [ -85.640115933203731, 12.650752672297983 ], [ -85.627894456863658, 12.660726223036761 ], [ -85.61603471572954, 12.662896633372895 ], [ -85.595674201303325, 12.666694850786712 ], [ -85.586656664073757, 12.671371568243273 ], [ -85.582005785038916, 12.672146715498513 ], [ -85.562704636909473, 12.672275905808419 ], [ -85.556787686002906, 12.673076891485323 ], [ -85.552886114902265, 12.674575507353779 ], [ -85.549888882266089, 12.67878713591756 ], [ -85.536892258670775, 12.704237778950301 ], [ -85.535316128436534, 12.706149806868098 ], [ -85.533404099619474, 12.707803453266763 ], [ -85.530768602189198, 12.708888657985142 ], [ -85.527538824657029, 12.709482937187772 ], [ -85.463537564007368, 12.706149806868098 ], [ -85.45335730679426, 12.707183336541732 ], [ -85.447750414250208, 12.709017849194367 ], [ -85.446691047054173, 12.711369127583168 ], [ -85.444959886289723, 12.713126125870019 ], [ -85.442427740747632, 12.714392197741745 ], [ -85.434598761923326, 12.716743476130489 ], [ -85.430025397254269, 12.718836371201576 ], [ -85.425658739059543, 12.721549383896956 ], [ -85.423772548664147, 12.723254706239686 ], [ -85.420594448874681, 12.727207953284392 ], [ -85.418346524172762, 12.731703802688344 ], [ -85.416744553718161, 12.735734564998154 ], [ -85.415245937849761, 12.737724107281736 ], [ -85.407623663701088, 12.743253486359322 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-CO", "NAME_1": "Chontales" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -85.127744107404624, 12.424125677757786 ], [ -85.121723801911912, 12.424384060176237 ], [ -85.107383592079088, 12.426631984878213 ], [ -85.078005541322682, 12.440868841923475 ], [ -85.063303596283902, 12.451850083914223 ], [ -85.05229651587149, 12.462547105064857 ], [ -85.035656703593986, 12.483191840331131 ], [ -85.030437384677555, 12.494560655050179 ], [ -85.027621019194669, 12.505645249828376 ], [ -85.027130092779544, 12.542464708479486 ], [ -85.025708991276929, 12.553652655145925 ], [ -85.023228521678902, 12.561714178866225 ], [ -85.019275274634197, 12.569672348899758 ], [ -84.981215583432402, 12.624449368543537 ], [ -84.968529019098924, 12.649512437049339 ], [ -84.944499477568797, 12.615250963261303 ], [ -84.915612352328196, 12.589180203503588 ], [ -84.90972123894403, 12.579490871806286 ], [ -84.887862107750038, 12.531793524851253 ], [ -84.867010667808074, 12.500813502740925 ], [ -84.853678148327845, 12.488075263362703 ], [ -84.847347785371994, 12.47758494688776 ], [ -84.845332403767429, 12.470815335259488 ], [ -84.846650153381859, 12.464975897819443 ], [ -84.852360398713415, 12.451462511185923 ], [ -84.855150925774581, 12.439163520480065 ], [ -84.856339484179841, 12.422136135474261 ], [ -84.852153693138405, 12.389864203070488 ], [ -84.846934374221973, 12.37356028937586 ], [ -84.839596320014152, 12.361493841767356 ], [ -84.83277503064312, 12.354181626880575 ], [ -84.825540331021443, 12.348238837552287 ], [ -84.819649216737957, 12.341960151439821 ], [ -84.784225022966439, 12.280284328958601 ], [ -84.781098599121037, 12.265168971870537 ], [ -84.787403123655224, 12.242689723951571 ], [ -84.785982022152609, 12.209694322035318 ], [ -84.772701178616501, 12.150033881158663 ], [ -84.709320034691814, 11.99293752724509 ], [ -84.702421230955053, 11.982731432509581 ], [ -84.574625414331365, 11.922528388374417 ], [ -84.613615282419346, 11.906508693721207 ], [ -84.621573451553559, 11.899635728406111 ], [ -84.620720790831797, 11.895320746155505 ], [ -84.619713101378522, 11.892426866306835 ], [ -84.612581752745655, 11.87919769871479 ], [ -84.607414109773345, 11.862506212291862 ], [ -84.645706345871133, 11.863746445741867 ], [ -84.656945970280276, 11.866071885708948 ], [ -84.661751878946063, 11.868009752048408 ], [ -84.665524257938159, 11.868862412770113 ], [ -84.668909064201955, 11.869327500763518 ], [ -84.683998582868298, 11.867854723316839 ], [ -84.688029344278789, 11.868164780779978 ], [ -84.696504279149167, 11.870541896691179 ], [ -84.700870938243213, 11.870490220747058 ], [ -84.721308967035156, 11.866924547329972 ], [ -84.794973720960456, 11.867828883995799 ], [ -84.800167202354487, 11.867053738539198 ], [ -84.804973111020217, 11.865606797715543 ], [ -84.808228726074844, 11.860800889949076 ], [ -84.874271205851471, 11.801062933807316 ], [ -84.899360113678313, 11.784810696056752 ], [ -84.942122361657653, 11.775612290774575 ], [ -84.956979336327265, 11.753029690068104 ], [ -84.959769864287807, 11.746518459958963 ], [ -84.959795701810151, 11.745355739975423 ], [ -84.960777553741082, 11.741324978564876 ], [ -84.962741257602943, 11.738405260294485 ], [ -84.966901211121979, 11.733831894726166 ], [ -84.968451503833819, 11.731506456557725 ], [ -84.96943335576475, 11.729284369378149 ], [ -84.970828619744964, 11.727475694247858 ], [ -84.977804937847566, 11.720137640939356 ], [ -84.982378303415942, 11.714194850711749 ], [ -84.985685594414633, 11.708639635011139 ], [ -84.988992886312644, 11.706288357521657 ], [ -84.9950390293277, 11.702826035992757 ], [ -85.013694221411185, 11.69592723225594 ], [ -85.018551805121717, 11.695384629896751 ], [ -85.021058112242088, 11.696004747521044 ], [ -85.025708991276929, 11.697761745807895 ], [ -85.031987678288715, 11.695307115530966 ], [ -85.041160244249852, 11.690346178133609 ], [ -85.061184861891832, 11.676522732238311 ], [ -85.076687791708196, 11.668926296511358 ], [ -85.080873582749632, 11.665128079097542 ], [ -85.083302374604898, 11.662208359927831 ], [ -85.101518317116643, 11.631460882713554 ], [ -85.522913784943228, 11.680527655227081 ], [ -85.65665239089509, 12.046474310740848 ], [ -85.640038417938626, 12.146984972578423 ], [ -85.63525834769456, 12.156570949689581 ], [ -85.625879076158412, 12.171376248415129 ], [ -85.624457973756478, 12.173236599489485 ], [ -85.623295253772937, 12.175174464929626 ], [ -85.622132534688717, 12.176802272906571 ], [ -85.602082078625017, 12.221967475218776 ], [ -85.599937506710546, 12.228943793321378 ], [ -85.599704962713815, 12.23558421553912 ], [ -85.602107917046737, 12.253774318729825 ], [ -85.602262945778307, 12.278088080200746 ], [ -85.601100226694086, 12.284495958421758 ], [ -85.599110684410562, 12.289379381453273 ], [ -85.591074999111925, 12.30010224012625 ], [ -85.586346604811922, 12.304675604795307 ], [ -85.560560064995002, 12.323124091303782 ], [ -85.522810432155723, 12.34134003291615 ], [ -85.508547735789364, 12.345525823957587 ], [ -85.497592333119655, 12.345164088751687 ], [ -85.47283932207705, 12.341210841706982 ], [ -85.443719651940341, 12.340719916191176 ], [ -85.400854051173496, 12.338885403538541 ], [ -85.329049649221929, 12.351442775763473 ], [ -85.275047776833446, 12.357437241935145 ], [ -85.234145880827725, 12.371053982255489 ], [ -85.222234462850167, 12.377487697998845 ], [ -85.163710904434652, 12.417046006867736 ], [ -85.148621384868989, 12.422962957774246 ], [ -85.137950202140075, 12.425365912107168 ], [ -85.127744107404624, 12.424125677757786 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-ES", "NAME_1": "Estelí" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -86.09951941628799, 13.047007555454286 ], [ -86.137217373183205, 12.996726386113835 ], [ -86.143702765770001, 12.970991523140242 ], [ -86.146131557625267, 12.965539659327817 ], [ -86.150575731085098, 12.96019114830284 ], [ -86.15889563722385, 12.954455064549563 ], [ -86.171582200658008, 12.950114243877238 ], [ -86.197187873321695, 12.944636542542412 ], [ -86.208944260768988, 12.940605780232545 ], [ -86.231165127168879, 12.928255113582622 ], [ -86.238890754105, 12.920968736218185 ], [ -86.242430589999685, 12.91683462202019 ], [ -86.25832109164503, 12.884485175250632 ], [ -86.263902146666737, 12.848518378220547 ], [ -86.386349453164712, 12.883296616845371 ], [ -86.419964972705316, 12.899755561070265 ], [ -86.429938524343413, 12.917299710013594 ], [ -86.430222744284208, 12.925748806462252 ], [ -86.428853318725658, 12.937298489233854 ], [ -86.406839158800096, 12.975513210066595 ], [ -86.404720425307346, 13.006906643326886 ], [ -86.411722581831668, 13.031814683101118 ], [ -86.416916063225699, 13.040418809180665 ], [ -86.427070482017143, 13.053958035135224 ], [ -86.453373785771589, 13.096668606271123 ], [ -86.471486376395148, 13.114522813576968 ], [ -86.479056972801061, 13.11824351572568 ], [ -86.491175096353572, 13.121524970101291 ], [ -86.547088995760532, 13.109949448907912 ], [ -86.613053962070694, 13.088297024188307 ], [ -86.633414475597533, 13.083878689150197 ], [ -86.645248379209306, 13.083026028428435 ], [ -86.664652880126312, 13.092327786498117 ], [ -86.680543381771656, 13.097572943836269 ], [ -86.693772549363644, 13.097831326254664 ], [ -86.703358527374121, 13.09703034147708 ], [ -86.720695969843121, 13.090234890527768 ], [ -86.732219815092378, 13.149662787407692 ], [ -86.728938360716768, 13.18084951419371 ], [ -86.726406216073997, 13.189970405110103 ], [ -86.725476040087187, 13.191158961716724 ], [ -86.714934047668123, 13.200357366998901 ], [ -86.630959846219923, 13.28296214378787 ], [ -86.612278814815454, 13.308826198869951 ], [ -86.60388139521018, 13.326396186235002 ], [ -86.562772792730186, 13.396805325105674 ], [ -86.522826911133052, 13.430446682168622 ], [ -86.496291063381875, 13.434451606056768 ], [ -86.485800746906932, 13.431221829423862 ], [ -86.471227993976697, 13.42424551042194 ], [ -86.428388230732253, 13.40437592241085 ], [ -86.386116910067301, 13.411326402091788 ], [ -86.309377408240778, 13.435459296409363 ], [ -86.25374772787535, 13.438120632261359 ], [ -86.234937507060295, 13.432203681354792 ], [ -86.230906744750428, 13.425718288767996 ], [ -86.221010708377491, 13.403755804786556 ], [ -86.212949184657134, 13.390345770940542 ], [ -86.221475796370896, 13.375256252274198 ], [ -86.227263556967557, 13.359804999301275 ], [ -86.230054084028723, 13.343035996713866 ], [ -86.230389980812959, 13.32171946877844 ], [ -86.221243252374165, 13.278828030489194 ], [ -86.235686814994494, 13.237254340015738 ], [ -86.23310299260902, 13.22477448215659 ], [ -86.236151902987899, 13.208134669879087 ], [ -86.247856615390447, 13.189143581910741 ], [ -86.241422898747771, 13.175113430440433 ], [ -86.234446580645169, 13.164571438021426 ], [ -86.159050665955476, 13.091010036883688 ], [ -86.11517737483598, 13.065662747537772 ], [ -86.09951941628799, 13.047007555454286 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-GR", "NAME_1": "Granada" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -85.851498379446639, 12.198764756888011 ], [ -85.845271369278237, 12.179489447180231 ], [ -85.843746914088797, 12.164348253469086 ], [ -85.842119107011172, 12.15672597932047 ], [ -85.836796434407916, 12.150318101099458 ], [ -85.828347337959258, 12.144297797405386 ], [ -85.812301804884385, 12.138122463181105 ], [ -85.785094163564793, 12.114971421693724 ], [ -85.731479864803873, 12.041332506190201 ], [ -85.65665239089509, 12.046474310740848 ], [ -85.522913784943228, 11.680527655227081 ], [ -85.894363980213484, 11.682052110416521 ], [ -85.926997646923837, 11.672724513925175 ], [ -85.971336026036738, 11.661484890415352 ], [ -85.976064419437364, 11.663061021548913 ], [ -85.985934618288013, 11.67303457318701 ], [ -85.989810350067557, 11.67706533549682 ], [ -85.99415117073994, 11.679752508871161 ], [ -85.999189623402401, 11.680966904798822 ], [ -86.000920783267532, 11.681044420063927 ], [ -86.003375414443781, 11.680837714488916 ], [ -86.006165940605683, 11.679132392146187 ], [ -86.009085659775337, 11.676212672976476 ], [ -86.024691942379206, 11.643320623847671 ], [ -86.03556983068313, 11.625750637381998 ], [ -86.039316372152825, 11.623166815895843 ], [ -86.067066616730983, 11.609317532478144 ], [ -86.070580614203948, 11.605777696583402 ], [ -86.07812537308746, 11.604718329387367 ], [ -86.101689825724861, 11.610816148346544 ], [ -86.119440681142521, 11.632804469850385 ], [ -86.121998664206956, 11.641847846400992 ], [ -86.123213060134617, 11.656291409021321 ], [ -86.119104784358285, 11.687193914967168 ], [ -86.109828863811003, 11.705590725531522 ], [ -86.097865769889324, 11.721842963282143 ], [ -86.09551449329922, 11.730679633358363 ], [ -86.095669522030789, 11.742410183283312 ], [ -86.099984504281451, 11.759308377079947 ], [ -86.103472663332752, 11.783906358491663 ], [ -86.09781409394526, 11.809021103840848 ], [ -86.077350226731539, 11.845530504129442 ], [ -86.072466803700024, 11.856175849335955 ], [ -86.053346523623134, 11.89772370048837 ], [ -86.043838059978441, 11.918394273277102 ], [ -86.040349900927197, 11.925887356216492 ], [ -86.004460619162217, 12.004099636389071 ], [ -85.964049648672358, 12.091381129735339 ], [ -85.967305263726928, 12.106703193297733 ], [ -86.000507372117511, 12.143806870990318 ], [ -85.91648149292655, 12.180833035216381 ], [ -85.885062222143802, 12.203157253504457 ], [ -85.876793992848491, 12.206180325461617 ], [ -85.869300909909043, 12.206051134252448 ], [ -85.851498379446639, 12.198764756888011 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "NI-MS", "NAME_1": "Masaya" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -86.000507372117511, 12.143806870990318 ], [ -85.967305263726928, 12.106703193297733 ], [ -85.964049648672358, 12.091381129735339 ], [ -86.004460619162217, 12.004099636389071 ], [ -86.040349900927197, 11.925887356216492 ], [ -86.043838059978441, 11.918394273277102 ], [ -86.053346523623134, 11.89772370048837 ], [ -86.072466803700024, 11.856175849335955 ], [ -86.081122605723635, 11.858501288403716 ], [ -86.134297654912814, 11.87403005574248 ], [ -86.136597255558854, 11.876484686918729 ], [ -86.149748907885794, 11.894364731746975 ], [ -86.179075283597456, 11.907981472067263 ], [ -86.270516729563383, 11.944232489038143 ], [ -86.281420458087666, 11.956996567737406 ], [ -86.25775265176344, 11.985521959570747 ], [ -86.230389980812959, 11.964773871516968 ], [ -86.223439501132077, 11.961621609249846 ], [ -86.211553920676863, 11.958495185404445 ], [ -86.203673265009172, 11.959218654916981 ], [ -86.194319830995369, 11.961750800459072 ], [ -86.186361660062573, 11.966014105866293 ], [ -86.180160489215211, 11.971672675253728 ], [ -86.174501918928399, 11.978235582206366 ], [ -86.163365648206081, 11.99603811356809 ], [ -86.162047898591652, 12.018310655012726 ], [ -86.164760912186352, 12.024227606818613 ], [ -86.170161099155393, 12.031720688858684 ], [ -86.184656337719787, 12.046319281109902 ], [ -86.187911952774357, 12.059057522286821 ], [ -86.127114631235202, 12.11796865522922 ], [ -86.109027879932682, 12.131275336287729 ], [ -86.080037401005256, 12.13631378805087 ], [ -86.045750087896238, 12.149956365893559 ], [ -86.028722703789754, 12.152281805860639 ], [ -86.025570440623312, 12.151894233132339 ], [ -86.023787604814117, 12.151248277086324 ], [ -86.018361579423356, 12.148328558815933 ], [ -86.000507372117511, 12.143806870990318 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/panama.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/panama.geojson new file mode 100644 index 0000000000000..82a1cfadf7138 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/panama.geojson @@ -0,0 +1,18 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "PA-1", "NAME_1": "Bocas del Toro" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -82.829022175999938, 9.6027224730001 ], [ -82.771092895999885, 9.579855652000091 ], [ -82.729364176999951, 9.544896546000089 ], [ -82.719726521999945, 9.541330872000032 ], [ -82.711690836999963, 9.544999899000118 ], [ -82.701458903999878, 9.53355356900002 ], [ -82.688668986999915, 9.509446513000057 ], [ -82.678049479999913, 9.497767639000088 ], [ -82.668205118999936, 9.493168437000037 ], [ -82.650712646999892, 9.487845764000085 ], [ -82.632134969999925, 9.484667663000039 ], [ -82.618854125999917, 9.486708883000077 ], [ -82.612394572999875, 9.499498800000055 ], [ -82.608208781999934, 9.537868551000088 ], [ -82.601103271999904, 9.548668925000115 ], [ -82.585884562999865, 9.546240133000055 ], [ -82.570614176999925, 9.538230285000083 ], [ -82.562836873999913, 9.53869537300011 ], [ -82.573597785999937, 9.576198635000083 ], [ -82.561879035999937, 9.56907786700009 ], [ -82.465646938999896, 9.493963934000078 ], [ -82.406605597999942, 9.435248114000046 ], [ -82.368967251999948, 9.414943752000056 ], [ -82.342762824999909, 9.432521877000056 ], [ -82.345082160999937, 9.415432033000059 ], [ -82.349598761999914, 9.402044989000046 ], [ -82.376779751999948, 9.355169989000046 ], [ -82.379465298999946, 9.343817450000074 ], [ -82.376291469999899, 9.330064195000091 ], [ -82.367787238999938, 9.320746161000045 ], [ -82.356434699999909, 9.313421942000048 ], [ -82.348133917999917, 9.305568752000056 ], [ -82.348947719999899, 9.294745184000078 ], [ -82.362456834999932, 9.284125067000048 ], [ -82.387603318999936, 9.286078192000048 ], [ -82.389963344999899, 9.27484772300005 ], [ -82.394927537999934, 9.267075914000088 ], [ -82.393666144999941, 9.262111721000053 ], [ -82.388783331999946, 9.26007721600007 ], [ -82.38304602799991, 9.261216539000088 ], [ -82.373199022999927, 9.25454336100006 ], [ -82.364491339999915, 9.242865302000041 ], [ -82.358143683999913, 9.229437567000048 ], [ -82.355824347999942, 9.216782945000091 ], [ -82.350575324999909, 9.207261460000041 ], [ -82.314808722999942, 9.185492255000042 ], [ -82.307972785999937, 9.185492255000042 ], [ -82.300445115999935, 9.197088934000078 ], [ -82.288238084999932, 9.198553778000075 ], [ -82.282460089999915, 9.202093817000048 ], [ -82.294300910999937, 9.220282294000071 ], [ -82.280995245999918, 9.216620184000078 ], [ -82.275949673999946, 9.206447658000059 ], [ -82.273060675999943, 9.194484768000052 ], [ -82.266428188999896, 9.185492255000042 ], [ -82.255482550999943, 9.182603257000039 ], [ -82.247914191999939, 9.186997789000088 ], [ -82.24445553299995, 9.19757721600007 ], [ -82.245961066999939, 9.213446356000077 ], [ -82.239084438999896, 9.213446356000077 ], [ -82.238148566999939, 9.200262762000079 ], [ -82.231068488999938, 9.193752346000053 ], [ -82.223052537999934, 9.192775783000059 ], [ -82.219227667999917, 9.196356512000079 ], [ -82.218739386999914, 9.208644924000055 ], [ -82.216867641999897, 9.217474677000041 ], [ -82.212513800999943, 9.220038153000075 ], [ -82.204945441999939, 9.213446356000077 ], [ -82.203968878999945, 9.216538804000038 ], [ -82.204009568999936, 9.219224351000037 ], [ -82.202788865999935, 9.220689195000091 ], [ -82.198109503999945, 9.220282294000071 ], [ -82.196197068999936, 9.211167710000041 ], [ -82.193430141999897, 9.204087632000039 ], [ -82.189605272999927, 9.198309637000079 ], [ -82.184437628999945, 9.192938544000071 ], [ -82.177642381999931, 9.192938544000071 ], [ -82.177642381999931, 9.199774481000077 ], [ -82.170806443999936, 9.199774481000077 ], [ -82.173451300999943, 9.184759833000044 ], [ -82.171701626999948, 9.157416083000044 ], [ -82.177642381999931, 9.14516836100006 ], [ -82.208119269999941, 9.163763739000046 ], [ -82.224110480999911, 9.169663804000038 ], [ -82.249623175999943, 9.171820380000042 ], [ -82.260731574999909, 9.164048570000091 ], [ -82.263783331999946, 9.146551825000074 ], [ -82.260731574999909, 9.127875067000048 ], [ -82.253407355999911, 9.116603908000059 ], [ -82.253407355999911, 9.110419012000079 ], [ -82.258941209999932, 9.11273834800005 ], [ -82.273833787999934, 9.116603908000059 ], [ -82.268462693999936, 9.102362372000073 ], [ -82.244536912999934, 9.089911200000074 ], [ -82.239084438999896, 9.079331773000092 ], [ -82.245961066999939, 9.014146226000037 ], [ -82.250477667999917, 9.015204169000071 ], [ -82.253488735999952, 9.016302802000041 ], [ -82.256214972999942, 9.017971096000053 ], [ -82.260161912999934, 9.020982164000088 ], [ -82.243031378999945, 9.004461981000077 ], [ -82.218820766999897, 8.993353583000044 ], [ -82.194691535999937, 8.99095286700009 ], [ -82.177642381999931, 9.000555731000077 ], [ -82.141753709999932, 8.988959052000041 ], [ -82.129017706999946, 8.981390692000048 ], [ -82.12922115799995, 8.973211981000077 ], [ -82.114409959999932, 8.950751044000071 ], [ -82.109364386999914, 8.945298570000091 ], [ -82.107004360999952, 8.941880601000037 ], [ -82.105376756999931, 8.935207424000055 ], [ -82.101918097999942, 8.931626695000091 ], [ -82.097808397999927, 8.930609442000048 ], [ -82.086659308999913, 8.931708075000074 ], [ -82.067616339999915, 8.930731512000079 ], [ -82.020008917999917, 8.945298570000091 ], [ -82.006746764256462, 8.946581223250567 ], [ -82.006771817365461, 8.946508490274596 ], [ -82.008373786021366, 8.941857612139074 ], [ -82.015892707382534, 8.919378363320789 ], [ -82.034625413831748, 8.908112901389302 ], [ -82.06087704074281, 8.90248017042353 ], [ -82.10214067285375, 8.90248017042353 ], [ -82.132138841234507, 8.900619819349174 ], [ -82.150871547683778, 8.891240546014387 ], [ -82.16399736158894, 8.870621650069097 ], [ -82.169630092554712, 8.848116562829091 ], [ -82.179009365889499, 8.844370022258715 ], [ -82.186502447929627, 8.855609645768538 ], [ -82.192135178895398, 8.88186127447824 ], [ -82.195881721264413, 8.891240546014387 ], [ -82.209007534270256, 8.898733628953778 ], [ -82.210893723766333, 8.917492173824769 ], [ -82.199628261834789, 8.92498525586484 ], [ -82.195881721264413, 8.941883450560795 ], [ -82.201514452230185, 8.954983425144917 ], [ -82.225879889645171, 8.969995429445476 ], [ -82.26151078989102, 8.977488512384923 ], [ -82.272750414300162, 8.98686778392107 ], [ -82.280269334761954, 8.998107408330213 ], [ -82.300888230707244, 9.001879788221629 ], [ -82.321507127551854, 9.009372870261757 ], [ -82.32339331704793, 9.024359036140595 ], [ -82.317760586082159, 9.039371039541834 ], [ -82.30274858268092, 9.050610663051657 ], [ -82.289648607197421, 9.067483018426572 ], [ -82.280269334761954, 9.080608832331734 ], [ -82.287762416802082, 9.08438121222315 ], [ -82.308381313646692, 9.091874294263278 ], [ -82.315874395686819, 9.099367377202668 ], [ -82.310267504042088, 9.114379381503227 ], [ -82.314014044612463, 9.12561900501305 ], [ -82.32339331704793, 9.127505195408446 ], [ -82.338379482926769, 9.112493191107887 ], [ -82.351505296831988, 9.086241563297506 ], [ -82.353391486328007, 9.061876125882463 ], [ -82.379643114138389, 9.039371039541834 ], [ -82.392768928043552, 9.026245224737295 ], [ -82.426513637894061, 9.013119411731452 ], [ -82.439639451799223, 8.99999359782629 ], [ -82.4283998282894, 8.988753974316467 ], [ -82.407755093023127, 8.981235052955299 ], [ -82.370263840803602, 8.968109239050136 ], [ -82.347758755362236, 8.949376531701546 ], [ -82.334632940557753, 8.92498525586484 ], [ -82.330886399987378, 8.90436635991955 ], [ -82.338379482926769, 8.889354356518311 ], [ -82.347758755362236, 8.857495836163878 ], [ -82.355251838301683, 8.827497666883801 ], [ -82.362951625916764, 8.808790797956931 ], [ -82.44594397723273, 8.846514594173186 ], [ -82.492271897729893, 8.861268215155974 ], [ -82.529711473105976, 8.86297353839808 ], [ -82.540770230361829, 8.884780991849254 ], [ -82.551622281143352, 8.893695177190637 ], [ -82.567693650841306, 8.899741319306429 ], [ -82.624951138284416, 8.902790228785989 ], [ -82.692750617247157, 8.894315293915668 ], [ -82.714532233175987, 8.916200263531323 ], [ -82.720156710164019, 8.92023775007209 ], [ -82.719364786999847, 8.921523743000108 ], [ -82.72334387199993, 8.930928854000072 ], [ -82.749130411999914, 8.974078674000097 ], [ -82.762695475999919, 8.98299285900012 ], [ -82.80817073599988, 8.9983665970001 ], [ -82.854085246999944, 9.031982117000041 ], [ -82.876564494999855, 9.041929830000129 ], [ -82.882429769999931, 9.04534047500006 ], [ -82.88687394299987, 9.051489970000119 ], [ -82.889690307999928, 9.059370626000074 ], [ -82.893281819999885, 9.066941224000033 ], [ -82.900232299999885, 9.072057190000109 ], [ -82.90945654399988, 9.072005514000097 ], [ -82.939377197999931, 9.059577332000032 ], [ -82.93952108499991, 9.070641889000072 ], [ -82.941650960999937, 9.234424540000134 ], [ -82.94320125399986, 9.354313863000101 ], [ -82.944286458999869, 9.437151185000118 ], [ -82.941702636999935, 9.45634897900004 ], [ -82.933305216999969, 9.470327454000127 ], [ -82.914624186999902, 9.476864522000099 ], [ -82.861294108999914, 9.484099223000072 ], [ -82.846385457999958, 9.492548320000068 ], [ -82.844783488999923, 9.500687358000079 ], [ -82.849382690999875, 9.503477885000038 ], [ -82.855919758999846, 9.505441590000075 ], [ -82.860208902999915, 9.511203512000037 ], [ -82.867133544999888, 9.538643697000097 ], [ -82.879251668999899, 9.55990854900007 ], [ -82.877391316999876, 9.569184469000092 ], [ -82.866048340999896, 9.585074972000101 ], [ -82.847470662999854, 9.600655416000052 ], [ -82.829022175999938, 9.6027224730001 ] ] ], [ [ [ -82.123036261999914, 9.322658596000053 ], [ -82.097727016999897, 9.31118398600006 ], [ -82.085275844999899, 9.302679755000042 ], [ -82.074615037999934, 9.28851959800005 ], [ -82.09398352799991, 9.291245835000041 ], [ -82.114165818999936, 9.283270575000074 ], [ -82.130197719999899, 9.268255927000041 ], [ -82.138824022999927, 9.245306708000044 ], [ -82.143625454999949, 9.247137762000079 ], [ -82.154408331999946, 9.258368231000077 ], [ -82.153960740999935, 9.259182033000059 ], [ -82.151722785999937, 9.259914455000057 ], [ -82.150298631999931, 9.264349677000041 ], [ -82.150257941999939, 9.287258205000057 ], [ -82.154042120999918, 9.296291408000059 ], [ -82.163970506999931, 9.30219147300005 ], [ -82.163970506999931, 9.308417059000078 ], [ -82.150298631999931, 9.30219147300005 ], [ -82.159331834999932, 9.323146877000056 ], [ -82.174305792999917, 9.33038971600007 ], [ -82.192616339999915, 9.333889065000051 ], [ -82.211781378999945, 9.343166408000059 ], [ -82.211781378999945, 9.349351304000038 ], [ -82.206166144999941, 9.354193427000041 ], [ -82.200998501999948, 9.35618724200009 ], [ -82.196034308999913, 9.354803778000075 ], [ -82.191314256999931, 9.349351304000038 ], [ -82.182484503999945, 9.345851955000057 ], [ -82.174387173999946, 9.34406159100007 ], [ -82.166005011999914, 9.344956773000092 ], [ -82.15656490799995, 9.349351304000038 ], [ -82.14671790299991, 9.344631252000056 ], [ -82.123036261999914, 9.322658596000053 ] ] ], [ [ [ -82.328480597999942, 9.412054755000042 ], [ -82.301665818999936, 9.432318427000041 ], [ -82.285511847999942, 9.438869533000059 ], [ -82.266428188999896, 9.439357815000051 ], [ -82.238758917999917, 9.39874909100007 ], [ -82.231800910999937, 9.37335846600007 ], [ -82.245961066999939, 9.356838283000059 ], [ -82.245961066999939, 9.349351304000038 ], [ -82.241566535999937, 9.344549872000073 ], [ -82.240142381999931, 9.341945705000057 ], [ -82.241688605999911, 9.338080145000049 ], [ -82.245961066999939, 9.330064195000091 ], [ -82.259673631999931, 9.353176174000055 ], [ -82.280751105999911, 9.374701239000046 ], [ -82.328480597999942, 9.412054755000042 ] ] ], [ [ [ -82.04723834999993, 9.172568781000052 ], [ -82.052409657999931, 9.177661002000093 ], [ -82.051840272999925, 9.182192803000078 ], [ -82.045522753999933, 9.179368136000051 ], [ -82.04149825099995, 9.173142195000082 ], [ -82.035755631999905, 9.169750291000071 ], [ -82.028866885999946, 9.169192132000092 ], [ -82.025414816999898, 9.160700151000071 ], [ -82.023113219999914, 9.153905700000053 ], [ -82.016223891999914, 9.15108183600006 ], [ -82.008760620999908, 9.147692229000086 ], [ -82.010477109999897, 9.141459268000062 ], [ -82.019655841999906, 9.137482707000061 ], [ -82.02711256799995, 9.13294146700008 ], [ -82.032853613999919, 9.134633315000087 ], [ -82.042043214999921, 9.140852517000042 ], [ -82.050083914999902, 9.145940624000048 ], [ -82.055257578999942, 9.153864964000093 ], [ -82.054690857999901, 9.16179681400007 ], [ -82.04723834999993, 9.172568781000052 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-4", "NAME_1": "Chiriquí" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -82.989193277999874, 8.264457907000093 ], [ -82.995523640999892, 8.264819641000088 ], [ -83.001104695999885, 8.269237976000085 ], [ -83.010768188999918, 8.283371480000127 ], [ -83.016065023999943, 8.289004211000062 ], [ -83.044073649999859, 8.305359803000101 ], [ -83.053246216999952, 8.315100810000047 ], [ -83.052109334999869, 8.327632345000055 ], [ -83.043298502999875, 8.334737854000082 ], [ -82.997771565999898, 8.360162659000096 ], [ -82.953510701999875, 8.402098084000087 ], [ -82.924778604999858, 8.41674835200007 ], [ -82.896511596999886, 8.425352478000107 ], [ -82.870414998999877, 8.438116557000072 ], [ -82.848297485999865, 8.46516916900012 ], [ -82.838918213999932, 8.494624736000034 ], [ -82.835972656999928, 8.52976471000008 ], [ -82.841863769999918, 8.599476217000117 ], [ -82.849796102999875, 8.629861959000067 ], [ -82.862224284999854, 8.655700176000096 ], [ -82.878941609999913, 8.679057923000045 ], [ -82.910335042999918, 8.713913676000104 ], [ -82.919223388999939, 8.72706532800008 ], [ -82.924158488999893, 8.741198832000123 ], [ -82.92296992999988, 8.756159160000081 ], [ -82.914882568999957, 8.764789124000032 ], [ -82.885116943999975, 8.78318593400013 ], [ -82.875789347999842, 8.793908793000043 ], [ -82.875634318999914, 8.807525533000046 ], [ -82.883566650999853, 8.812383118000071 ], [ -82.888320882999949, 8.816930644000095 ], [ -82.8785798749999, 8.829772238000089 ], [ -82.866926839999934, 8.838066304000051 ], [ -82.763780679999911, 8.879950053000115 ], [ -82.733860025999974, 8.897985128000116 ], [ -82.720156710164019, 8.92023775007209 ], [ -82.714532233175987, 8.916200263531323 ], [ -82.692750617247157, 8.894315293915668 ], [ -82.624951138284416, 8.902790228785989 ], [ -82.567693650841306, 8.899741319306429 ], [ -82.551622281143352, 8.893695177190637 ], [ -82.540770230361829, 8.884780991849254 ], [ -82.529711473105976, 8.86297353839808 ], [ -82.492271897729893, 8.861268215155974 ], [ -82.44594397723273, 8.846514594173186 ], [ -82.362951625916764, 8.808790797956931 ], [ -82.36114295078653, 8.807963974757627 ], [ -82.317786423604559, 8.791117458703752 ], [ -82.299777187567145, 8.782125758996585 ], [ -82.281690437163945, 8.777009792867659 ], [ -82.250865444684507, 8.772281399466976 ], [ -82.223502773734026, 8.768948269147302 ], [ -82.218076748343265, 8.770343533127516 ], [ -82.203994920928835, 8.772436428198603 ], [ -82.196165941205209, 8.771583767476898 ], [ -82.154850633150204, 8.762592067769674 ], [ -82.153222826072522, 8.762617906191394 ], [ -82.139631924173955, 8.703732612569979 ], [ -82.149011196609422, 8.61937083569552 ], [ -82.15650427864955, 8.589811916886447 ], [ -82.152757738079117, 8.568727932048432 ], [ -82.142913377650245, 8.557255764541878 ], [ -82.175262824419804, 8.482479967476479 ], [ -82.180172084973719, 8.457881985165443 ], [ -82.16399736158894, 8.448735255827387 ], [ -82.132836473224643, 8.449200343820792 ], [ -82.10025448335773, 8.458114529162174 ], [ -82.083718023867675, 8.464341539330576 ], [ -82.074002854648029, 8.467493800698321 ], [ -82.064494391902656, 8.46149933542597 ], [ -82.053383958702739, 8.44684906723063 ], [ -82.036744147324498, 8.418039456355814 ], [ -82.021499599926585, 8.401864732071715 ], [ -82.01775305935621, 8.370910549282428 ], [ -81.99713416161228, 8.339982204914804 ], [ -81.949100917873068, 8.327786566996451 ], [ -81.856496751923544, 8.326856391009642 ], [ -81.830012580116488, 8.318407294560984 ], [ -81.813372768738247, 8.287478949294041 ], [ -81.784304776344356, 8.264043686966545 ], [ -81.732059903141987, 8.262157498369845 ], [ -81.715885178857889, 8.278099676858574 ], [ -81.704619716926402, 8.294997869755889 ], [ -81.689633551946827, 8.296858221729565 ], [ -81.680486822608771, 8.277376207346094 ], [ -81.655888841197054, 8.281846218328326 ], [ -81.633616298853099, 8.297090765726239 ], [ -81.624004483320221, 8.313730577104423 ], [ -81.609793463797303, 8.347811183739111 ], [ -81.592120123644747, 8.371866562791638 ], [ -81.547833422274607, 8.385690008686936 ], [ -81.522486132029371, 8.379333808208685 ], [ -81.51933386886293, 8.341739203201655 ], [ -81.513210212381409, 8.310707506046526 ], [ -81.510471361264308, 8.281226100703975 ], [ -81.513106858694584, 8.251047065169928 ], [ -81.51550981302745, 8.246086126873251 ], [ -81.517137621004395, 8.243760687805491 ], [ -81.522951219123456, 8.239032294404865 ], [ -81.573180711620523, 8.176116238473639 ], [ -81.597907884241465, 8.152060859421113 ], [ -81.601886969707891, 8.145058701997471 ], [ -81.606124436693392, 8.134904283206083 ], [ -81.631755947778743, 8.034987901470458 ], [ -81.633771327584668, 8.022714749186321 ], [ -81.638008796368865, 8.011242580780447 ], [ -81.64247880735104, 8.0030001899068 ], [ -81.662555100937141, 7.99765167888188 ], [ -81.663574609280772, 7.997287569465755 ], [ -81.670521613999938, 8.006781317000048 ], [ -81.684803839999915, 8.044623114000046 ], [ -81.691029425999943, 8.054632880000042 ], [ -81.697132941999939, 8.039129950000074 ], [ -81.698353644999941, 8.031032619000086 ], [ -81.697865363999938, 8.021063544000071 ], [ -81.708363410999937, 8.031317450000074 ], [ -81.708526170999903, 8.045843817000048 ], [ -81.710357225999928, 8.059841213000084 ], [ -81.725738084999932, 8.068264065000051 ], [ -81.725738084999932, 8.07571035400008 ], [ -81.717274542999917, 8.070827541000085 ], [ -81.709462042999917, 8.068630276000079 ], [ -81.702870245999918, 8.069973049000055 ], [ -81.697865363999938, 8.07571035400008 ], [ -81.691029425999943, 8.07571035400008 ], [ -81.687611456999946, 8.072780666000085 ], [ -81.685414191999939, 8.071600653000075 ], [ -81.677357550999943, 8.068264065000051 ], [ -81.711455857999908, 8.13031647300005 ], [ -81.733550584999932, 8.15766022300005 ], [ -81.743438279999907, 8.173163153000075 ], [ -81.746245897999927, 8.191799221000053 ], [ -81.752471482999908, 8.191799221000053 ], [ -81.758208787999934, 8.180609442000048 ], [ -81.760650193999936, 8.169582424000055 ], [ -81.757476365999935, 8.161159572000088 ], [ -81.746245897999927, 8.15766022300005 ], [ -81.752430792999917, 8.148993231000077 ], [ -81.767486131999931, 8.132757880000042 ], [ -81.774199998999904, 8.123480536000045 ], [ -81.780384894999941, 8.123480536000045 ], [ -81.798329230999911, 8.137111721000053 ], [ -81.876576300999943, 8.167873440000051 ], [ -81.885365363999938, 8.17328522300005 ], [ -81.927032029999907, 8.183172919000071 ], [ -81.941151495999918, 8.184963283000059 ], [ -81.95181230399993, 8.191433010000083 ], [ -81.947865363999938, 8.206244208000044 ], [ -81.931182420999903, 8.233343817000048 ], [ -81.943267381999931, 8.229641018000052 ], [ -81.956695115999935, 8.22101471600007 ], [ -81.967640753999945, 8.209051825000074 ], [ -81.972198045999903, 8.195502020000049 ], [ -81.978382941999939, 8.192531643000052 ], [ -81.992176886999914, 8.201117255000042 ], [ -82.013172980999911, 8.21906159100007 ], [ -82.027862107999908, 8.208278713000084 ], [ -82.060292120999918, 8.210272528000075 ], [ -82.093129035999937, 8.220363674000055 ], [ -82.109364386999914, 8.233343817000048 ], [ -82.115589972999942, 8.233343817000048 ], [ -82.117298956999946, 8.21515534100007 ], [ -82.142404751999948, 8.160060940000051 ], [ -82.144561326999906, 8.161891994000086 ], [ -82.148915167999917, 8.164089260000083 ], [ -82.150298631999931, 8.164496161000045 ], [ -82.150298631999931, 8.15766022300005 ], [ -82.156524217999902, 8.15766022300005 ], [ -82.147206183999913, 8.180934963000084 ], [ -82.147572394999941, 8.188299872000073 ], [ -82.156524217999902, 8.184963283000059 ], [ -82.155384894999941, 8.193182684000078 ], [ -82.153797980999911, 8.199286200000074 ], [ -82.150380011999914, 8.203314520000049 ], [ -82.143462693999936, 8.20538971600007 ], [ -82.143462693999936, 8.212917385000083 ], [ -82.15689042899993, 8.211737372000073 ], [ -82.174102342999902, 8.201727606000077 ], [ -82.187896287999934, 8.199245510000083 ], [ -82.196522589999915, 8.202175197000088 ], [ -82.209258592999902, 8.215521552000041 ], [ -82.219227667999917, 8.21906159100007 ], [ -82.219227667999917, 8.225897528000075 ], [ -82.214100714999915, 8.227443752000056 ], [ -82.209584113999938, 8.231146552000041 ], [ -82.204945441999939, 8.233343817000048 ], [ -82.216542120999918, 8.264227606000077 ], [ -82.217559373999904, 8.278225002000056 ], [ -82.211781378999945, 8.287990627000056 ], [ -82.211781378999945, 8.294826565000051 ], [ -82.217640753999945, 8.299343166000085 ], [ -82.218780076999906, 8.304348049000055 ], [ -82.216420050999943, 8.309759833000044 ], [ -82.211781378999945, 8.315252997000073 ], [ -82.210601365999935, 8.312648830000057 ], [ -82.210845506999931, 8.309881903000075 ], [ -82.209828253999945, 8.30805084800005 ], [ -82.204945441999939, 8.308498440000051 ], [ -82.209828253999945, 8.321844794000071 ], [ -82.208648240999935, 8.332098700000074 ], [ -82.200550910999937, 8.33930084800005 ], [ -82.184437628999945, 8.34320709800005 ], [ -82.207875128999945, 8.343939520000049 ], [ -82.220122850999928, 8.342962958000044 ], [ -82.225453253999945, 8.339504299000055 ], [ -82.241444464999915, 8.306708075000074 ], [ -82.242461717999902, 8.301052151000079 ], [ -82.26195227799991, 8.302801825000074 ], [ -82.277088995999918, 8.309271552000041 ], [ -82.284413214999915, 8.322211005000042 ], [ -82.280059373999904, 8.34320709800005 ], [ -82.296498175999943, 8.336208401000079 ], [ -82.313954230999911, 8.330837307000081 ], [ -82.331654425999943, 8.329779364000046 ], [ -82.348907029999907, 8.335760809000078 ], [ -82.347075975999928, 8.329169012000079 ], [ -82.344960089999915, 8.315008856000077 ], [ -82.342762824999909, 8.308498440000051 ], [ -82.358672654999907, 8.30609772300005 ], [ -82.387196417999917, 8.291449286000045 ], [ -82.400135870999918, 8.287990627000056 ], [ -82.418934699999909, 8.293036200000074 ], [ -82.433257615999935, 8.304348049000055 ], [ -82.435332811999899, 8.316107489000046 ], [ -82.417225714999915, 8.322780666000085 ], [ -82.417225714999915, 8.328924872000073 ], [ -82.425689256999931, 8.332302151000079 ], [ -82.430287238999938, 8.338161526000079 ], [ -82.431752081999946, 8.346218166000085 ], [ -82.430897589999915, 8.356268622000073 ], [ -82.441029425999943, 8.348700262000079 ], [ -82.442616339999915, 8.336330471000053 ], [ -82.447010870999918, 8.323553778000075 ], [ -82.465606248999904, 8.315252997000073 ], [ -82.465606248999904, 8.308498440000051 ], [ -82.461415167999917, 8.302923895000049 ], [ -82.457427537999934, 8.296047268000052 ], [ -82.4541316399999, 8.28851959800005 ], [ -82.452015753999945, 8.281154690000051 ], [ -82.470855272999927, 8.277126369000086 ], [ -82.477772589999915, 8.277411200000074 ], [ -82.486114061999899, 8.281154690000051 ], [ -82.511708136999914, 8.276434637000079 ], [ -82.552642381999931, 8.287380276000079 ], [ -82.622670050999943, 8.315252997000073 ], [ -82.658924933999913, 8.322780666000085 ], [ -82.698597785999937, 8.322821356000077 ], [ -82.738026495999918, 8.317450262000079 ], [ -82.808705206999946, 8.295681057000081 ], [ -82.839019334999932, 8.278509833000044 ], [ -82.862456834999932, 8.254055080000057 ], [ -82.87718665299991, 8.21906159100007 ], [ -82.879872199999909, 8.177883205000057 ], [ -82.872832811999899, 8.135891018000052 ], [ -82.849232550999943, 8.068264065000051 ], [ -82.849232550999943, 8.06203847900008 ], [ -82.862090623999904, 8.048895575000074 ], [ -82.8681941399999, 8.032375393000052 ], [ -82.876942511999914, 8.023871161000045 ], [ -82.897629258999899, 8.034748020000023 ], [ -82.891369791999892, 8.057545471000068 ], [ -82.886408854999928, 8.102193909000093 ], [ -82.939092977999849, 8.216838074000052 ], [ -82.943666341999887, 8.248567403000067 ], [ -82.95051346899993, 8.258825175000055 ], [ -82.968005940999888, 8.267971904000134 ], [ -82.977126830999879, 8.269237976000085 ], [ -82.989193277999874, 8.264457907000093 ] ] ], [ [ [ -82.211781378999945, 8.199204820000091 ], [ -82.233021613999938, 8.205308335000041 ], [ -82.247059699999909, 8.206732489000046 ], [ -82.253407355999911, 8.202337958000044 ], [ -82.253325975999928, 8.193264065000051 ], [ -82.25259355399993, 8.188381252000056 ], [ -82.245961066999939, 8.171291408000059 ], [ -82.273833787999934, 8.191799221000053 ], [ -82.281361456999946, 8.193548895000049 ], [ -82.301380988999938, 8.196112372000073 ], [ -82.307972785999937, 8.199204820000091 ], [ -82.315663214999915, 8.214911200000074 ], [ -82.306467251999948, 8.22406647300005 ], [ -82.273833787999934, 8.233343817000048 ], [ -82.259592251999948, 8.227036851000037 ], [ -82.238880988999938, 8.220648505000042 ], [ -82.220122850999928, 8.212062893000052 ], [ -82.211781378999945, 8.199204820000091 ] ] ], [ [ [ -82.342762824999909, 8.259995835000041 ], [ -82.314808722999942, 8.240179755000042 ], [ -82.334868943999936, 8.23509349200009 ], [ -82.369699673999946, 8.216864325000074 ], [ -82.386463995999918, 8.212876695000091 ], [ -82.398345506999931, 8.21820709800005 ], [ -82.412505662999934, 8.231024481000077 ], [ -82.424712693999936, 8.246568101000037 ], [ -82.430897589999915, 8.259995835000041 ], [ -82.424672003999945, 8.259995835000041 ], [ -82.401926235999952, 8.257147528000075 ], [ -82.350005662999934, 8.293646552000041 ], [ -82.328480597999942, 8.287990627000056 ], [ -82.316517706999946, 8.277329820000091 ], [ -82.317209438999896, 8.267564195000091 ], [ -82.327056443999936, 8.262884833000044 ], [ -82.342762824999909, 8.267523505000042 ], [ -82.342762824999909, 8.259995835000041 ] ] ], [ [ [ -82.362049933999913, 8.086859442000048 ], [ -82.359242316999939, 8.099025783000059 ], [ -82.352447068999936, 8.11204661700009 ], [ -82.343129035999937, 8.12335846600007 ], [ -82.33234615799995, 8.129706122000073 ], [ -82.320708787999934, 8.13031647300005 ], [ -82.318348761999914, 8.123968817000048 ], [ -82.319447394999941, 8.113104559000078 ], [ -82.318226691999939, 8.09992096600007 ], [ -82.336537238999938, 8.091864325000074 ], [ -82.347482876999948, 8.088283596000053 ], [ -82.362049933999913, 8.086859442000048 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-KY", "NAME_1": "Kuna Yala" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -77.373524542999917, 8.664740302000041 ], [ -77.374936483999932, 8.6509459440001 ], [ -77.385375121999857, 8.643633728000111 ], [ -77.401549845999853, 8.642031759000076 ], [ -77.417672892999946, 8.638466085000104 ], [ -77.434002644999879, 8.628259989000043 ], [ -77.435036173999947, 8.620637716000061 ], [ -77.430230264999949, 8.610457459000102 ], [ -77.429093384999931, 8.592629090000059 ], [ -77.441133992999909, 8.567669372000069 ], [ -77.46937330143669, 8.537811606220657 ], [ -77.469787766592162, 8.538316352517654 ], [ -77.495884365670918, 8.570097358506302 ], [ -77.508415900373507, 8.573740546289173 ], [ -77.546268886899611, 8.590096136827242 ], [ -77.558929612811369, 8.606477565787031 ], [ -77.568799810762641, 8.639912218174288 ], [ -77.579160936028359, 8.654820867888702 ], [ -77.609779222033467, 8.684224757966206 ], [ -77.626160650993256, 8.70662649241865 ], [ -77.653600837208842, 8.730526841840287 ], [ -77.678767259401468, 8.748768621874376 ], [ -77.68613115113169, 8.757915351212489 ], [ -77.691583014944172, 8.766855374076215 ], [ -77.692513190031661, 8.772410589776882 ], [ -77.694838629998742, 8.786079006041291 ], [ -77.701143155432248, 8.800290025564209 ], [ -77.712408617363792, 8.813855089041112 ], [ -77.752044439699091, 8.850106106011992 ], [ -77.76418840167338, 8.859097804819839 ], [ -77.779226244395659, 8.866539210915846 ], [ -77.806718105656046, 8.885711167836121 ], [ -77.823667976296065, 8.893385117928858 ], [ -77.833693202978907, 8.90036143603146 ], [ -77.840359462718993, 8.911316840499751 ], [ -77.84648312009989, 8.924261786352361 ], [ -77.856663378212318, 8.941263332936444 ], [ -77.911905484050862, 8.996970526768393 ], [ -77.94208451958491, 9.020715847458405 ], [ -78.015335863259452, 9.073244941500832 ], [ -78.042543504579044, 9.073244941500832 ], [ -78.06504859091973, 9.107842312073046 ], [ -78.072386644228231, 9.112803250369723 ], [ -78.083290370953819, 9.118694362854569 ], [ -78.152330085165261, 9.134998277448517 ], [ -78.158841315274458, 9.139959214845874 ], [ -78.160805020035639, 9.145385240236635 ], [ -78.150469733191642, 9.161224066837178 ], [ -78.145818854156801, 9.172773748709517 ], [ -78.150831468397541, 9.194271144697552 ], [ -78.158686285643569, 9.203030300408045 ], [ -78.165610927802049, 9.205665797838265 ], [ -78.169564174846755, 9.202255154052125 ], [ -78.171347011555326, 9.197681790282388 ], [ -78.174034186728306, 9.192720851985712 ], [ -78.178400844923033, 9.190085354555436 ], [ -78.186694911740744, 9.189387722565357 ], [ -78.209122483715646, 9.192720851985712 ], [ -78.234650642013492, 9.193108424714012 ], [ -78.257000698723232, 9.190860500911356 ], [ -78.26472632476009, 9.196053982305443 ], [ -78.270772467775146, 9.204890652381664 ], [ -78.280435961050728, 9.231581528864467 ], [ -78.284854296088895, 9.248583075448551 ], [ -78.289091763074396, 9.255714423182098 ], [ -78.295602993183593, 9.257342231159043 ], [ -78.331208055007721, 9.239978949369004 ], [ -78.339011197208947, 9.237498481569673 ], [ -78.346917691298415, 9.238015245507142 ], [ -78.36606380889765, 9.241761786077575 ], [ -78.394873419772466, 9.240599066993354 ], [ -78.408748541611885, 9.243622138051194 ], [ -78.414303758211872, 9.247885444357735 ], [ -78.416835903753963, 9.254784247195232 ], [ -78.415776536557928, 9.261915594928723 ], [ -78.416525845391448, 9.269537869077396 ], [ -78.419703946080233, 9.278917141512864 ], [ -78.424742397843374, 9.287443752327306 ], [ -78.430323451965705, 9.291939601731201 ], [ -78.437739019640048, 9.294600938482517 ], [ -78.441718106005794, 9.298399155896334 ], [ -78.445257941001159, 9.304445298911389 ], [ -78.448952805627471, 9.312196764269231 ], [ -78.457686122916243, 9.320413315821838 ], [ -78.465075853068129, 9.321033433446189 ], [ -78.472000495226666, 9.317235216032373 ], [ -78.479493578166057, 9.311344101748887 ], [ -78.486418220324595, 9.30870860431861 ], [ -78.490759040097601, 9.311654161010722 ], [ -78.495099859870606, 9.328888250692216 ], [ -78.500189989376508, 9.337957464765168 ], [ -78.512876552810667, 9.349688014690116 ], [ -78.521816575674393, 9.351238308301276 ], [ -78.52835364510463, 9.347956854824986 ], [ -78.537164475859868, 9.335011908073113 ], [ -78.542047898891383, 9.331368720290186 ], [ -78.594525316090426, 9.319173082371833 ], [ -78.610079921850911, 9.317777818391619 ], [ -78.627701586059345, 9.321421007073809 ], [ -78.641783412574398, 9.330206000306646 ], [ -78.677052577614347, 9.357051907319658 ], [ -78.698860032864218, 9.370772000427451 ], [ -78.709712083645741, 9.374182644213647 ], [ -78.714879726618051, 9.371237087521536 ], [ -78.716998461010178, 9.353796292265088 ], [ -78.721003383998948, 9.34702667883812 ], [ -78.72818640767656, 9.34454621013947 ], [ -78.741751472052783, 9.350773220307872 ], [ -78.758778856159267, 9.368601589191996 ], [ -78.765419278376953, 9.371547145884051 ], [ -78.77058692134932, 9.371469631518266 ], [ -78.777795783448653, 9.370616969897242 ], [ -78.781645676806534, 9.368214016463696 ], [ -78.787485114246635, 9.363408107797909 ], [ -78.795908373172892, 9.358679714397283 ], [ -78.808982510234671, 9.356741848057823 ], [ -78.839988368968022, 9.361082667830829 ], [ -78.857041592395547, 9.360927639099259 ], [ -78.87135596380665, 9.359377346387419 ], [ -78.878306444386908, 9.355734157705228 ], [ -78.890786302246056, 9.344468695773685 ], [ -78.900113897838082, 9.341213079819738 ], [ -78.915358446135372, 9.341058051088169 ], [ -78.92633968812612, 9.345243842129605 ], [ -78.932773403869476, 9.346329046848041 ], [ -78.937165899586603, 9.34454621013947 ], [ -78.937941046841843, 9.340282903832929 ], [ -78.937656826001728, 9.333384100995431 ], [ -78.939413825187842, 9.327803045973781 ], [ -78.945666672878644, 9.324676622128379 ], [ -78.956131150931867, 9.328035589970511 ], [ -78.964657761746309, 9.328888250692216 ], [ -78.97274512388833, 9.327725530708676 ], [ -78.997084723780972, 9.317157700767268 ], [ -79.002820808433569, 9.312661851363316 ], [ -79.005637173017135, 9.30638316525085 ], [ -79.004164394671079, 9.299949449507494 ], [ -79.000650397198058, 9.294135850489113 ], [ -78.998169929398728, 9.288373928314115 ], [ -78.998169929398728, 9.284188137272679 ], [ -79.002200689909898, 9.280467434224704 ], [ -79.011140712773681, 9.277599391898377 ], [ -79.056796840601692, 9.276359158448372 ], [ -79.07180884490225, 9.277366847901703 ], [ -79.078242560645663, 9.282250270933218 ], [ -79.085038010695598, 9.289769192294386 ], [ -79.093642136775202, 9.297546495174572 ], [ -79.115372076759911, 9.306305649985745 ], [ -79.12865292029602, 9.30909617794623 ], [ -79.143303189390679, 9.310103868298881 ], [ -79.156713223236636, 9.309871324302151 ], [ -79.170536669131934, 9.307778429231121 ], [ -79.239162971294093, 9.286436061974655 ], [ -79.27205502042284, 9.279537258237838 ], [ -79.280064867299757, 9.286513577239759 ], [ -79.281046719230687, 9.293024807348957 ], [ -79.279031337626122, 9.303360094192954 ], [ -79.272494269994525, 9.314289659340318 ], [ -79.266112230195233, 9.321576035805379 ], [ -79.246991950118399, 9.330748603565212 ], [ -79.243477952645378, 9.320568346352104 ], [ -79.239318000025662, 9.320490831087 ], [ -79.220352748680398, 9.335554511331623 ], [ -79.192680020266721, 9.352685248225612 ], [ -79.176246913564171, 9.360152492743339 ], [ -79.157074958442536, 9.366586209386014 ], [ -79.148083258735369, 9.372012233877456 ], [ -79.142062954142034, 9.377851671317558 ], [ -79.139143235871643, 9.38351023980573 ], [ -79.137282883897967, 9.389943956448406 ], [ -79.135577561555181, 9.405524399731235 ], [ -79.132218593713105, 9.415239569850257 ], [ -79.120875617415777, 9.431517646022542 ], [ -79.11263322564281, 9.439449978533673 ], [ -79.102220425332348, 9.445883694277029 ], [ -79.095502488748821, 9.447744045351385 ], [ -79.087001716356099, 9.448751735704036 ], [ -79.078914354214078, 9.450999661305332 ], [ -79.074986944691716, 9.457278347417798 ], [ -79.074547696019351, 9.541278388187038 ], [ -79.074532601798481, 9.562041560085573 ], [ -79.048455651999916, 9.564218877000087 ], [ -79.012902007999912, 9.570225582000091 ], [ -78.970582971999931, 9.573313287000076 ], [ -78.957311407999953, 9.565283566000062 ], [ -78.957362509999939, 9.554032607000067 ], [ -78.97451246299994, 9.544735453000044 ], [ -78.986858370999926, 9.547135568000044 ], [ -78.996871111999951, 9.539680668000074 ], [ -79.007806002999928, 9.538792274000059 ], [ -79.038230630999919, 9.535170273000062 ], [ -79.054873438999948, 9.531958770000074 ], [ -79.065858829999911, 9.513720207000063 ], [ -79.063152069999944, 9.49029209400004 ], [ -79.058060022999939, 9.457931447000078 ], [ -79.040498114999934, 9.452233634000038 ], [ -79.024323598999899, 9.455913990000056 ], [ -79.013890376999939, 9.451183411000045 ], [ -79.001049694999949, 9.453471043000093 ], [ -78.988212133999923, 9.455289557000071 ], [ -78.977277268999899, 9.457115774000044 ], [ -78.966362218999905, 9.45472499400006 ], [ -78.95259004199994, 9.454663080000046 ], [ -78.935050173999912, 9.447556342000041 ], [ -78.924618639999949, 9.44423117000008 ], [ -78.915679490999935, 9.436835028000075 ], [ -78.908070441999939, 9.430812893000052 ], [ -78.903309699999909, 9.422919012000079 ], [ -78.89574330399995, 9.424421061000089 ], [ -78.882912972999918, 9.425295124000058 ], [ -78.874841132999904, 9.424788310000054 ], [ -78.864878247999911, 9.422397982000064 ], [ -78.852544202999923, 9.423753852000061 ], [ -78.847235740999906, 9.433084454000038 ], [ -78.836335919999897, 9.435384427000088 ], [ -78.817844768999919, 9.431080468000062 ], [ -78.78938426499991, 9.436570632000041 ], [ -78.781136414999935, 9.445882047000055 ], [ -78.764105287999939, 9.442521953000039 ], [ -78.752649044999941, 9.444333833000087 ], [ -78.741595066999935, 9.44848875100007 ], [ -78.728222884999923, 9.454983637000055 ], [ -78.717884894999941, 9.441839911000045 ], [ -78.701656968999941, 9.434259603000044 ], [ -78.688869084999908, 9.43555350400004 ], [ -78.655600285999924, 9.426498389000074 ], [ -78.63326473099994, 9.428733218000048 ], [ -78.620027581999921, 9.418825435000088 ], [ -78.603899646999935, 9.416394068000045 ], [ -78.58962149599995, 9.422402190000071 ], [ -78.578087387999915, 9.43189831300009 ], [ -78.561318325999935, 9.438040165000075 ], [ -78.546407441999918, 9.434370216000048 ], [ -78.527122645999953, 9.421502986000064 ], [ -78.512820123999916, 9.415992034000055 ], [ -78.479889665999906, 9.416002824000088 ], [ -78.463449673999946, 9.40460846600007 ], [ -78.452606688999936, 9.40883344000008 ], [ -78.437712497999939, 9.404351060000067 ], [ -78.427261341999952, 9.393895709000049 ], [ -78.415951381999946, 9.38430978100007 ], [ -78.388730732999932, 9.371848899000042 ], [ -78.378321713999924, 9.365750006000042 ], [ -78.364224503999935, 9.36119855700008 ], [ -78.33833926199992, 9.356006656000091 ], [ -78.317512241999907, 9.344662242000084 ], [ -78.302727033999929, 9.333313626000063 ], [ -78.287072173999945, 9.326287320000063 ], [ -78.277486314999919, 9.321878839000078 ], [ -78.267910993999919, 9.320943162000049 ], [ -78.254861620999918, 9.317389616000071 ], [ -78.241857412999934, 9.309545141000058 ], [ -78.226236340999947, 9.300807706000057 ], [ -78.208024793999925, 9.290335613000082 ], [ -78.192353942999944, 9.287610808000068 ], [ -78.176654083999949, 9.290058988000055 ], [ -78.167086290999919, 9.286516887000062 ], [ -78.154922565999925, 9.279491061000044 ], [ -78.141905495999936, 9.277709576000063 ], [ -78.123706892999905, 9.266364628000076 ], [ -78.114003058999913, 9.253810940000051 ], [ -78.088159299999916, 9.247983673000078 ], [ -78.055992348999951, 9.243438130000072 ], [ -78.036901178999926, 9.23639165700007 ], [ -78.024566209999932, 9.226467190000051 ], [ -78.020822719999899, 9.21360911700009 ], [ -77.999256964999915, 9.190822658000059 ], [ -77.986254645999907, 9.188899939000066 ], [ -77.968658006999931, 9.180609442000048 ], [ -77.935408951999932, 9.142888937000066 ], [ -77.918527798999946, 9.116603908000059 ], [ -77.905028417999915, 9.099310445000071 ], [ -77.890152348999948, 9.077213285000084 ], [ -77.855743596999901, 9.054290580000043 ], [ -77.860838441999931, 9.068091029000072 ], [ -77.865223761999914, 9.080267645000049 ], [ -77.876442099999906, 9.103554690000067 ], [ -77.877661019999948, 9.11888756500008 ], [ -77.860096808999913, 9.110419012000079 ], [ -77.847258796999938, 9.087558109000042 ], [ -77.83919444299994, 9.076501573000087 ], [ -77.811865107999949, 9.058039561000044 ], [ -77.808172351999929, 9.035333090000051 ], [ -77.798238538999897, 9.024263803000053 ], [ -77.785813840999936, 9.016871380000055 ], [ -77.770741339999915, 9.003973700000074 ], [ -77.767241990999935, 8.992336330000057 ], [ -77.758534308999913, 8.981512762000079 ], [ -77.747547980999911, 8.972560940000051 ], [ -77.744415965999906, 8.963576305000061 ], [ -77.754205715999944, 8.945658706000074 ], [ -77.734730597999942, 8.923488674000055 ], [ -77.720772329999932, 8.892290262000074 ], [ -77.710320862999936, 8.881281909000052 ], [ -77.701056068999947, 8.889259806000041 ], [ -77.696736843999929, 8.887426389000041 ], [ -77.695519647999902, 8.87331922900006 ], [ -77.676292523999905, 8.861628296000049 ], [ -77.655851862999953, 8.843200133000039 ], [ -77.63345292899993, 8.817450262000079 ], [ -77.614328579999949, 8.808742580000057 ], [ -77.61945553299995, 8.816961981000077 ], [ -77.626047329999949, 8.823146877000056 ], [ -77.631743943999936, 8.829901434000078 ], [ -77.634185350999928, 8.839789130000042 ], [ -77.629058397999927, 8.84446849200009 ], [ -77.617990688999953, 8.835191148000092 ], [ -77.607411261999914, 8.822170315000051 ], [ -77.60383053299995, 8.815578518000052 ], [ -77.574072649999948, 8.792754063000075 ], [ -77.577873707999913, 8.775030270000059 ], [ -77.559342152999932, 8.75970760000007 ], [ -77.553622633999908, 8.776756090000049 ], [ -77.543688488999919, 8.774885415000085 ], [ -77.535099402999947, 8.757744993000074 ], [ -77.538342776999912, 8.741314829000089 ], [ -77.540290285999902, 8.726078971000049 ], [ -77.544749517999946, 8.714603511000064 ], [ -77.532137328999909, 8.703201771000067 ], [ -77.500721808999913, 8.681830145000049 ], [ -77.476958787999934, 8.669907945000091 ], [ -77.444203253999945, 8.66437409100007 ], [ -77.413197394999941, 8.666693427000041 ], [ -77.394602016999897, 8.678412177000041 ], [ -77.390695766999897, 8.673529364000046 ], [ -77.385812954999949, 8.669582424000055 ], [ -77.380034959999932, 8.66665273600006 ], [ -77.373524542999917, 8.664740302000041 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-EM", "NAME_1": "Emberá" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -77.46937330143669, 8.537811606220657 ], [ -77.480356404999952, 8.526199036 ], [ -77.488676309999931, 8.496536764000055 ], [ -77.488727986999947, 8.473644104000115 ], [ -77.479684610999897, 8.467856343000051 ], [ -77.449608927999918, 8.470646871000014 ], [ -77.432710734999915, 8.465065816000092 ], [ -77.422323770999895, 8.456410014000141 ], [ -77.405787313999895, 8.428453064000053 ], [ -77.391266235999865, 8.393545634000063 ], [ -77.382998005999923, 8.324945171000124 ], [ -77.374368042999976, 8.289314270000133 ], [ -77.363205932999932, 8.27208018000006 ], [ -77.350493530999898, 8.267403463000093 ], [ -77.337161010999864, 8.26662831600008 ], [ -77.324345255999873, 8.261202291000103 ], [ -77.316903849999875, 8.250841166000086 ], [ -77.295199747999874, 8.205495097000068 ], [ -77.269434250999922, 8.167700643000046 ], [ -77.270032518386017, 8.167537949916436 ], [ -77.38338477238932, 8.136712958336318 ], [ -77.4045462706938, 8.133250636807418 ], [ -77.425320197169356, 8.127643744263366 ], [ -77.43909196622127, 8.11903961818382 ], [ -77.44524146202383, 8.109996243431851 ], [ -77.452527839388267, 8.101082058090469 ], [ -77.463224859639524, 8.096663723052359 ], [ -77.486401740447945, 8.092865504739223 ], [ -77.492783780247237, 8.094028224722763 ], [ -77.498984951094599, 8.096043606327385 ], [ -77.519991420667509, 8.092658800063532 ], [ -77.538620775228594, 8.08165172055044 ], [ -77.552573412333118, 8.084829820339905 ], [ -77.571900397085642, 8.110564683313498 ], [ -77.581072963946099, 8.11927216218055 ], [ -77.60135596400653, 8.125447496404831 ], [ -77.611174486013681, 8.14079539569093 ], [ -77.607350430178201, 8.15702179591915 ], [ -77.625540534268225, 8.199680691110984 ], [ -77.663548550425276, 8.230531521112823 ], [ -77.691634690888236, 8.243941554958781 ], [ -77.720831875390729, 8.251021225848888 ], [ -77.731683926172252, 8.258255927269204 ], [ -77.735818041269567, 8.272156887530343 ], [ -77.734862026861038, 8.280140895985539 ], [ -77.735223762066937, 8.287556464559202 ], [ -77.740494757826809, 8.290011094836132 ], [ -77.746515062420201, 8.290837918035493 ], [ -77.756591965946484, 8.295747179488728 ], [ -77.762974005745775, 8.304713039874855 ], [ -77.76268978490566, 8.310190741209738 ], [ -77.764343431304269, 8.313653061839318 ], [ -77.771526454981881, 8.324453437576096 ], [ -77.777469245209488, 8.331300564469473 ], [ -77.786951870432461, 8.34011139612403 ], [ -77.793282233388368, 8.348327948575957 ], [ -77.797261318854794, 8.36129873285023 ], [ -77.800051845915959, 8.374863796327134 ], [ -77.817363450862558, 8.401322129712526 ], [ -77.817027554078322, 8.409719550217062 ], [ -77.815813158150718, 8.417341824365678 ], [ -77.812402512565882, 8.42429230404656 ], [ -77.808940191936301, 8.434989325197193 ], [ -77.810387131860637, 8.446048082453046 ], [ -77.815167202104703, 8.455763250773373 ], [ -77.840230272409144, 8.48175649706468 ], [ -77.840126918722319, 8.487208359977842 ], [ -77.837052171720359, 8.492091783009357 ], [ -77.840101081199919, 8.498577174696834 ], [ -77.851263190343957, 8.50178111380734 ], [ -77.860875006776155, 8.505475979332971 ], [ -77.873380703056966, 8.517749132516428 ], [ -77.875757818968168, 8.521573188351965 ], [ -77.875757818968168, 8.523278509795375 ], [ -77.876016201386562, 8.525784816915746 ], [ -77.869504971277365, 8.537360338109124 ], [ -77.872192144651763, 8.555912177405048 ], [ -77.88583472429309, 8.568443712107637 ], [ -77.898495450204848, 8.583817449815456 ], [ -77.905316738676561, 8.601129054762055 ], [ -77.908598192152851, 8.62167043724088 ], [ -77.897100186224577, 8.641591702095354 ], [ -77.877488979732618, 8.652702135295272 ], [ -77.84725826735513, 8.694818427228597 ], [ -77.835786098949313, 8.716083279219959 ], [ -77.821807624322389, 8.732852280908048 ], [ -77.806253017662641, 8.737348131211263 ], [ -77.790129971121246, 8.740138658272429 ], [ -77.778296068408793, 8.749362901077006 ], [ -77.769278531179282, 8.762307847828879 ], [ -77.74721269441028, 8.773366604185412 ], [ -77.722743903308469, 8.776622219240039 ], [ -77.701711595313839, 8.771687120264403 ], [ -77.692513190031661, 8.772410589776882 ], [ -77.691583014944172, 8.766855374076215 ], [ -77.68613115113169, 8.757915351212489 ], [ -77.678767259401468, 8.748768621874376 ], [ -77.653600837208842, 8.730526841840287 ], [ -77.626160650993256, 8.70662649241865 ], [ -77.609779222033467, 8.684224757966206 ], [ -77.579160936028359, 8.654820867888702 ], [ -77.568799810762641, 8.639912218174288 ], [ -77.558929612811369, 8.606477565787031 ], [ -77.546268886899611, 8.590096136827242 ], [ -77.508415900373507, 8.573740546289173 ], [ -77.495884365670918, 8.570097358506302 ], [ -77.469787766592162, 8.538316352517654 ], [ -77.46937330143669, 8.537811606220657 ] ] ], [ [ [ -78.183439296686174, 8.093563136729358 ], [ -78.1673420885665, 8.081935940491235 ], [ -78.137163052133133, 8.039819648557909 ], [ -78.127422045391086, 8.029174303351397 ], [ -78.118197800787868, 8.016177679756083 ], [ -78.111609056312886, 7.986696275312852 ], [ -78.101790534305678, 7.978221340442474 ], [ -78.091868658611702, 7.972640286320143 ], [ -78.083109503800529, 7.917734076366514 ], [ -78.059209154378948, 7.931324978265138 ], [ -78.034998744796212, 7.950884507913713 ], [ -78.016214362402877, 7.931350815787482 ], [ -77.985311855557654, 7.835646064414334 ], [ -77.980971034885329, 7.803968411213191 ], [ -77.970997484146551, 7.797922268198079 ], [ -77.961695726076869, 7.794382432303394 ], [ -77.953039924053257, 7.779215400170585 ], [ -77.948466560283521, 7.762007148011435 ], [ -77.952161424010512, 7.748752142897047 ], [ -77.955907966379527, 7.739166164886569 ], [ -77.94479753317961, 7.651626288222587 ], [ -77.949706793733526, 7.618785915937281 ], [ -77.968361985816955, 7.60160350219985 ], [ -77.990892909680042, 7.590260525003202 ], [ -78.004561326843771, 7.605840969185351 ], [ -78.018901536676537, 7.617726548741246 ], [ -78.038176846384317, 7.607442938740633 ], [ -78.048331265175761, 7.589898789797303 ], [ -78.072438321071672, 7.601525986934746 ], [ -78.081223314304509, 7.644856675694996 ], [ -78.090008308436666, 7.652117213738393 ], [ -78.106028002190556, 7.65653554877656 ], [ -78.121220872745084, 7.667826850029087 ], [ -78.138325772116673, 7.67733531277446 ], [ -78.179563564906573, 7.665320542908717 ], [ -78.197004361062397, 7.677852078510625 ], [ -78.24506344322333, 7.730923774012922 ], [ -78.2695063950041, 7.772135728381159 ], [ -78.284595912771124, 7.819445501708515 ], [ -78.303897060900624, 7.8596497657241 ], [ -78.310899217424947, 7.862001044112901 ], [ -78.321182827425559, 7.867917995918788 ], [ -78.327203132018894, 7.879803575474625 ], [ -78.331078863798496, 7.892851874114683 ], [ -78.332499966200487, 7.915951238758623 ], [ -78.329606086351816, 7.936079210087485 ], [ -78.334489509383332, 7.945148424160436 ], [ -78.329321866410965, 7.959747016411654 ], [ -78.313379686123596, 7.964475408912961 ], [ -78.295835537180267, 7.965793158527447 ], [ -78.278084682661984, 7.982743028268146 ], [ -78.257439948294973, 7.996075547748319 ], [ -78.225736456672109, 7.984448349711556 ], [ -78.201991135982098, 8.001217353198285 ], [ -78.205815191817635, 8.012818711914008 ], [ -78.211861334832747, 8.024575100260677 ], [ -78.210259366176786, 8.033980211117864 ], [ -78.212791510819557, 8.04250682193225 ], [ -78.227725999855011, 8.050232448868428 ], [ -78.225452236731314, 8.069326890523541 ], [ -78.200079108064358, 8.08066986682087 ], [ -78.183439296686174, 8.093563136729358 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-5", "NAME_1": "Darién" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -77.269434250999922, 8.167700643000046 ], [ -77.260111449999926, 8.154025371000088 ], [ -77.231069294999941, 8.098731588000064 ], [ -77.209623575999899, 8.020700175000059 ], [ -77.207763223999905, 7.996567281000097 ], [ -77.201200317999906, 7.98199452700004 ], [ -77.191536824999901, 7.972847799000064 ], [ -77.180839803999902, 7.965148010000064 ], [ -77.171072957999939, 7.954916077000078 ], [ -77.163269815999911, 7.939258117000037 ], [ -77.169005899999974, 7.935072326000096 ], [ -77.20605790299993, 7.935485738000096 ], [ -77.236133585999909, 7.92923289 ], [ -77.269723266999932, 7.918122457000081 ], [ -77.300419067999968, 7.90210276300013 ], [ -77.321606404999841, 7.881018779000016 ], [ -77.347186238999882, 7.82381296800007 ], [ -77.376641805999981, 7.786605937000061 ], [ -77.379897420999953, 7.774410299000039 ], [ -77.36651322499992, 7.745109762000084 ], [ -77.345997680999858, 7.725731099000114 ], [ -77.339744832999969, 7.707230937000091 ], [ -77.369097045999922, 7.680772603 ], [ -77.509346883999939, 7.594111227000056 ], [ -77.554925496999914, 7.548480937000051 ], [ -77.57998856699993, 7.528378805000088 ], [ -77.602674519999908, 7.526053365000067 ], [ -77.613319865999898, 7.537473857000066 ], [ -77.625463826999891, 7.587444967000039 ], [ -77.633060261999873, 7.60067413400013 ], [ -77.660758829999878, 7.63803619400008 ], [ -77.663394327999896, 7.639948222000015 ], [ -77.671869262999905, 7.64196360300005 ], [ -77.674814819999909, 7.644650778000084 ], [ -77.674763142999979, 7.64842315700011 ], [ -77.670629028999969, 7.65731150400012 ], [ -77.670215617999958, 7.659947001000134 ], [ -77.679930786999904, 7.670954081000033 ], [ -77.729901896999962, 7.713328756000053 ], [ -77.740237182999891, 7.718858134000044 ], [ -77.764215047999897, 7.705732320000081 ], [ -77.770519571999898, 7.6689903770001 ], [ -77.765817016999932, 7.626460674000043 ], [ -77.756825317999898, 7.595558167000135 ], [ -77.734242716999944, 7.551788228000049 ], [ -77.731245483999942, 7.530342509000121 ], [ -77.740237182999891, 7.504607645000121 ], [ -77.755119994999916, 7.486107483000097 ], [ -77.774240274999926, 7.474738668000029 ], [ -77.796306111999911, 7.471276347000071 ], [ -77.820180623999903, 7.476547343000107 ], [ -77.855010538999863, 7.365391337000105 ], [ -77.895839150733224, 7.235098056585514 ], [ -77.896555141999897, 7.235296942000048 ], [ -77.918812628999945, 7.24164459800005 ], [ -77.947621222999942, 7.267645575000074 ], [ -77.99046790299991, 7.32094961100006 ], [ -78.006459113999938, 7.332464911000045 ], [ -78.014393683999913, 7.341009833000044 ], [ -78.01781165299991, 7.35228099200009 ], [ -78.015533006999931, 7.36273834800005 ], [ -78.011545376999948, 7.373195705000057 ], [ -78.009755011999914, 7.383490302000041 ], [ -78.014393683999913, 7.393540757000039 ], [ -78.020090298999946, 7.397853908000059 ], [ -78.022857225999928, 7.395982164000088 ], [ -78.024891730999911, 7.39203522300005 ], [ -78.02798417899993, 7.389837958000044 ], [ -78.035878058999913, 7.393011786000045 ], [ -78.038156704999949, 7.399400132000039 ], [ -78.036122199999909, 7.40460846600007 ], [ -78.03148352799991, 7.404120184000078 ], [ -78.043446417999917, 7.422308661000045 ], [ -78.049956834999932, 7.425930080000057 ], [ -78.059396938999953, 7.417792059000078 ], [ -78.065541144999941, 7.417792059000078 ], [ -78.089711066999939, 7.445217190000051 ], [ -78.105620897999927, 7.459418036000045 ], [ -78.11742102799991, 7.46556224200009 ], [ -78.120676235999952, 7.469916083000044 ], [ -78.123158331999946, 7.479478257000039 ], [ -78.127919074999909, 7.489162502000056 ], [ -78.137847459999932, 7.493475653000075 ], [ -78.144154425999943, 7.497870184000078 ], [ -78.14907792899993, 7.507879950000074 ], [ -78.155588344999899, 7.52765534100007 ], [ -78.161773240999935, 7.52765534100007 ], [ -78.166086391999897, 7.512640692000048 ], [ -78.168324347999942, 7.522406317000048 ], [ -78.169260219999899, 7.557440497000073 ], [ -78.174224412999934, 7.575425523000092 ], [ -78.184803839999915, 7.579413153000075 ], [ -78.194447394999941, 7.571437893000052 ], [ -78.196522589999915, 7.553697007000039 ], [ -78.202015753999945, 7.566839911000045 ], [ -78.200306769999941, 7.576157945000091 ], [ -78.196644660999937, 7.584906317000048 ], [ -78.196522589999915, 7.595892645000049 ], [ -78.200306769999941, 7.606431382000039 ], [ -78.204457160999937, 7.612127997000073 ], [ -78.216420050999943, 7.622544664000088 ], [ -78.237700975999928, 7.649888414000088 ], [ -78.252349412999934, 7.660956122000073 ], [ -78.271636522999927, 7.663560289000088 ], [ -78.269276495999918, 7.67454661700009 ], [ -78.273589647999927, 7.682806708000044 ], [ -78.282134568999936, 7.688462632000039 ], [ -78.292144334999932, 7.691473700000074 ], [ -78.282582160999937, 7.710638739000046 ], [ -78.277495897999927, 7.724351304000038 ], [ -78.278146938999953, 7.737372137000079 ], [ -78.285267706999946, 7.754136460000041 ], [ -78.315337693999936, 7.799872137000079 ], [ -78.320057745999918, 7.81126536700009 ], [ -78.329416469999899, 7.843247789000088 ], [ -78.351144985999952, 7.870184637000079 ], [ -78.375965949999909, 7.894191799000055 ], [ -78.394520636999914, 7.91742584800005 ], [ -78.407582160999937, 7.948228257000039 ], [ -78.415638800999943, 7.980129299000055 ], [ -78.416005011999914, 7.992173570000091 ], [ -78.413644985999952, 8.003648179000038 ], [ -78.415638800999943, 8.013617255000042 ], [ -78.433583136999914, 8.045803127000056 ], [ -78.436146613999938, 8.058294989000046 ], [ -78.430816209999932, 8.077134507000039 ], [ -78.419056769999941, 8.095404364000046 ], [ -78.407297329999949, 8.10219961100006 ], [ -78.395741339999915, 8.069891669000071 ], [ -78.381337042999917, 8.063625393000052 ], [ -78.365223761999914, 8.065985419000071 ], [ -78.353586391999897, 8.075669664000088 ], [ -78.325184699999909, 8.060939846000053 ], [ -78.286447719999899, 8.08071523600006 ], [ -78.25218665299991, 8.11749909100007 ], [ -78.237456834999932, 8.153957424000055 ], [ -78.239369269999941, 8.174383856000077 ], [ -78.244740363999938, 8.186916408000059 ], [ -78.253285285999937, 8.195786851000037 ], [ -78.264800584999932, 8.20538971600007 ], [ -78.294056769999941, 8.239203192000048 ], [ -78.305775519999941, 8.24640534100007 ], [ -78.305775519999941, 8.253851630000042 ], [ -78.278635219999899, 8.250962632000039 ], [ -78.270090298999946, 8.252386786000045 ], [ -78.257394985999952, 8.259995835000041 ], [ -78.257394985999952, 8.267523505000042 ], [ -78.263172980999911, 8.270331122000073 ], [ -78.266102667999917, 8.273260809000078 ], [ -78.268177863999938, 8.276678778000075 ], [ -78.271636522999927, 8.281154690000051 ], [ -78.263661261999914, 8.284328518000052 ], [ -78.261301235999952, 8.284735419000071 ], [ -78.257394985999952, 8.294826565000051 ], [ -78.248931443999936, 8.289211330000057 ], [ -78.237456834999932, 8.278509833000044 ], [ -78.23070227799991, 8.274359442000048 ], [ -78.221913214999915, 8.271918036000045 ], [ -78.214222785999937, 8.272162177000041 ], [ -78.199696417999917, 8.274359442000048 ], [ -78.198109503999945, 8.278306382000039 ], [ -78.18586178299995, 8.295111395000049 ], [ -78.182932094999899, 8.297919012000079 ], [ -78.184396938999953, 8.325344143000052 ], [ -78.182932094999899, 8.335760809000078 ], [ -78.180043097999942, 8.337591864000046 ], [ -78.161773240999935, 8.356268622000073 ], [ -78.157541469999899, 8.36554596600007 ], [ -78.155751105999911, 8.374335028000075 ], [ -78.155588344999899, 8.394110419000071 ], [ -78.151356574999909, 8.399481512000079 ], [ -78.141916469999899, 8.404038804000038 ], [ -78.132476365999935, 8.405340887000079 ], [ -78.128285285999937, 8.400946356000077 ], [ -78.12328040299991, 8.364488023000092 ], [ -78.120838995999918, 8.356268622000073 ], [ -78.110951300999943, 8.34796784100007 ], [ -78.094553188999953, 8.339056708000044 ], [ -78.076649542999917, 8.331854559000078 ], [ -78.062489386999914, 8.328924872000073 ], [ -78.05101477799991, 8.322495835000041 ], [ -78.042469855999911, 8.30735911700009 ], [ -78.024891730999911, 8.259711005000042 ], [ -78.015126105999911, 8.246527411000045 ], [ -78.002552863999938, 8.237005927000041 ], [ -77.987416144999941, 8.233343817000048 ], [ -77.98265540299991, 8.235337632000039 ], [ -77.972035285999937, 8.238470770000049 ], [ -77.961293097999942, 8.238023179000038 ], [ -77.953521287999934, 8.223781643000052 ], [ -77.946603969999899, 8.218410549000055 ], [ -77.93773352799991, 8.214422919000071 ], [ -77.929066535999937, 8.212876695000091 ], [ -77.915394660999937, 8.212876695000091 ], [ -77.915394660999937, 8.21906159100007 ], [ -77.930734829999949, 8.222398179000038 ], [ -77.944732225999928, 8.230536200000074 ], [ -77.955881313999953, 8.24164459800005 ], [ -77.962554490999935, 8.253851630000042 ], [ -77.912587042999917, 8.244330145000049 ], [ -77.885975714999915, 8.23468659100007 ], [ -77.869007941999939, 8.21548086100006 ], [ -77.845082160999937, 8.20258209800005 ], [ -77.839670376999948, 8.195502020000049 ], [ -77.838734503999945, 8.180650132000039 ], [ -77.835560675999943, 8.170111395000049 ], [ -77.829253709999932, 8.162787177000041 ], [ -77.819203253999945, 8.15766022300005 ], [ -77.808420376999948, 8.163763739000046 ], [ -77.797271287999934, 8.157700914000088 ], [ -77.788563605999911, 8.14398834800005 ], [ -77.785023566999939, 8.126898505000042 ], [ -77.778146938999953, 8.115790106000077 ], [ -77.762603318999936, 8.111883856000077 ], [ -77.74640865799995, 8.116359768000052 ], [ -77.737212693999936, 8.13031647300005 ], [ -77.765126105999911, 8.130072333000044 ], [ -77.801869269999941, 8.174383856000077 ], [ -77.819203253999945, 8.171291408000059 ], [ -77.870594855999911, 8.23578522300005 ], [ -77.880686001999948, 8.243312893000052 ], [ -77.895415818999936, 8.251532294000071 ], [ -77.984283006999931, 8.267523505000042 ], [ -78.005930141999897, 8.27602773600006 ], [ -78.023182745999918, 8.29047272300005 ], [ -78.034738735999952, 8.309637762000079 ], [ -78.038929816999939, 8.33234284100007 ], [ -78.060699022999927, 8.375921942000048 ], [ -78.06704667899993, 8.402736721000053 ], [ -78.051909959999932, 8.417669989000046 ], [ -78.06273352799991, 8.424709377000056 ], [ -78.074777798999946, 8.434515692000048 ], [ -78.085926886999914, 8.446356512000079 ], [ -78.094146287999934, 8.45929596600007 ], [ -78.098540818999936, 8.475775458000044 ], [ -78.095570441999939, 8.485174872000073 ], [ -78.089995897999927, 8.491888739000046 ], [ -78.086659308999913, 8.500230210000041 ], [ -78.08812415299991, 8.512762762000079 ], [ -78.093861456999946, 8.51593659100007 ], [ -78.102894660999937, 8.518052476000037 ], [ -78.114003058999913, 8.527573960000041 ], [ -78.118885870999918, 8.538763739000046 ], [ -78.119943813999953, 8.54828522300005 ], [ -78.123117641999897, 8.556057033000059 ], [ -78.134429490999935, 8.561712958000044 ], [ -78.130360480999911, 8.552476304000038 ], [ -78.12954667899993, 8.527289130000042 ], [ -78.124501105999911, 8.517645575000074 ], [ -78.111195441999939, 8.509019273000092 ], [ -78.106190558999913, 8.508042710000041 ], [ -78.105824347999942, 8.505031643000052 ], [ -78.106516079999949, 8.47211334800005 ], [ -78.104807094999899, 8.463364976000037 ], [ -78.090931769999941, 8.430853583000044 ], [ -78.089588995999918, 8.420396226000037 ], [ -78.094146287999934, 8.41087474200009 ], [ -78.100331183999913, 8.41087474200009 ], [ -78.119252081999946, 8.442531643000052 ], [ -78.131418423999946, 8.458075262000079 ], [ -78.14126542899993, 8.466131903000075 ], [ -78.156849738999938, 8.466213283000059 ], [ -78.17015540299991, 8.45766836100006 ], [ -78.179432745999918, 8.442084052000041 ], [ -78.182932094999899, 8.421087958000044 ], [ -78.188872850999928, 8.405747789000088 ], [ -78.20376542899993, 8.393947658000059 ], [ -78.222564256999931, 8.386297919000071 ], [ -78.240589972999942, 8.38353099200009 ], [ -78.249134894999941, 8.386908270000049 ], [ -78.252837693999936, 8.394720770000049 ], [ -78.253041144999941, 8.403794664000088 ], [ -78.251128709999932, 8.41087474200009 ], [ -78.245350714999915, 8.417669989000046 ], [ -78.216420050999943, 8.43195221600007 ], [ -78.212513800999943, 8.428656317000048 ], [ -78.209828253999945, 8.426988023000092 ], [ -78.202748175999943, 8.424505927000041 ], [ -78.201527472999942, 8.45734284100007 ], [ -78.206695115999935, 8.48773834800005 ], [ -78.223255988999938, 8.541815497000073 ], [ -78.23070227799991, 8.541815497000073 ], [ -78.237700975999928, 8.527533270000049 ], [ -78.232818162999934, 8.518377997000073 ], [ -78.22329667899993, 8.510565497000073 ], [ -78.216420050999943, 8.500230210000041 ], [ -78.217844204999949, 8.482489325000074 ], [ -78.225575324999909, 8.468247789000088 ], [ -78.230458136999914, 8.456447658000059 ], [ -78.223255988999938, 8.44562409100007 ], [ -78.223255988999938, 8.438177802000041 ], [ -78.226389126999948, 8.435980536000045 ], [ -78.229847785999937, 8.434393622000073 ], [ -78.237456834999932, 8.43195221600007 ], [ -78.241851365999935, 8.440008856000077 ], [ -78.247873501999948, 8.444525458000044 ], [ -78.253570115999935, 8.447821356000077 ], [ -78.257394985999952, 8.451849677000041 ], [ -78.260650193999936, 8.460638739000046 ], [ -78.258941209999932, 8.46165599200009 ], [ -78.254953579999949, 8.461371161000045 ], [ -78.251128709999932, 8.466131903000075 ], [ -78.240386522999927, 8.485296942000048 ], [ -78.241566535999937, 8.49477773600006 ], [ -78.257394985999952, 8.500230210000041 ], [ -78.25259355399993, 8.48773834800005 ], [ -78.254750128999945, 8.48187897300005 ], [ -78.26008053299995, 8.478420315000051 ], [ -78.264800584999932, 8.47296784100007 ], [ -78.278472459999932, 8.44562409100007 ], [ -78.294545050999943, 8.443264065000051 ], [ -78.303334113999938, 8.454291083000044 ], [ -78.312611456999946, 8.486558335000041 ], [ -78.320057745999918, 8.47915273600006 ], [ -78.321034308999913, 8.46625397300005 ], [ -78.334828253999945, 8.446193752000056 ], [ -78.353016730999911, 8.428900458000044 ], [ -78.367258266999897, 8.424505927000041 ], [ -78.376454230999911, 8.441310940000051 ], [ -78.386870897999927, 8.500474351000037 ], [ -78.394520636999914, 8.520697333000044 ], [ -78.390736456999946, 8.527492580000057 ], [ -78.388335740999935, 8.534369208000044 ], [ -78.394520636999914, 8.534369208000044 ], [ -78.394520636999914, 8.527573960000041 ], [ -78.401966925999943, 8.527573960000041 ], [ -78.401966925999943, 8.548041083000044 ], [ -78.408192511999914, 8.548041083000044 ], [ -78.412017381999931, 8.523504950000074 ], [ -78.393788214999915, 8.473863023000092 ], [ -78.384103969999899, 8.425970770000049 ], [ -78.365345831999946, 8.410630601000037 ], [ -78.360991990999935, 8.394110419000071 ], [ -78.388335740999935, 8.335760809000078 ], [ -78.392323370999918, 8.34438711100006 ], [ -78.399484829999949, 8.348822333000044 ], [ -78.407826300999943, 8.351996161000045 ], [ -78.409698045999903, 8.353013414000088 ], [ -78.413244391915157, 8.39754974982111 ], [ -78.429599981553906, 8.455634060463524 ], [ -78.432390510413711, 8.477674057911429 ], [ -78.445232102579439, 8.508318183237577 ], [ -78.44910783615768, 8.533536282273587 ], [ -78.447945116174139, 8.546274522551187 ], [ -78.451329922437935, 8.553715929546513 ], [ -78.454921434276741, 8.556583970973463 ], [ -78.458461270171483, 8.56038218838728 ], [ -78.457841153446452, 8.568624579260927 ], [ -78.452105068793855, 8.598105983704158 ], [ -78.448125983327429, 8.638749498190748 ], [ -78.44507707384787, 8.653580634438697 ], [ -78.441537237953128, 8.665052801945251 ], [ -78.435620287046618, 8.676447455085963 ], [ -78.431718715945976, 8.68717031555758 ], [ -78.428230556894675, 8.70259573010884 ], [ -78.428773159253865, 8.714481308765357 ], [ -78.433398199867042, 8.738381659086258 ], [ -78.436912198239327, 8.748303533880971 ], [ -78.448410204167601, 8.805948594951701 ], [ -78.451174892807046, 8.819694526481214 ], [ -78.446033088256399, 8.82535309496933 ], [ -78.438875902101188, 8.830003974004171 ], [ -78.393038907119831, 8.84542938945475 ], [ -78.379034593171923, 8.8448092718304 ], [ -78.362317268327274, 8.841708686406719 ], [ -78.338158534688603, 8.833027045062067 ], [ -78.331724819844567, 8.827368476573895 ], [ -78.321699592262348, 8.812072252332541 ], [ -78.30901302792887, 8.806723741307621 ], [ -78.299633754594083, 8.809126694741167 ], [ -78.290331997423721, 8.816025499377304 ], [ -78.285810309598105, 8.82457794771409 ], [ -78.284699265558629, 8.832949529796963 ], [ -78.281004400932318, 8.842561347128481 ], [ -78.271289231712672, 8.852664089076427 ], [ -78.242660488890408, 8.865996609455976 ], [ -78.221860724892508, 8.870337429228982 ], [ -78.205014207939314, 8.870880032487491 ], [ -78.185919766284201, 8.869329738876331 ], [ -78.174990200237517, 8.871965237205927 ], [ -78.167083706148105, 8.877727159380868 ], [ -78.154035406608727, 8.899663804940644 ], [ -78.137214728077197, 8.914262397191862 ], [ -78.119722255977308, 8.922091376016169 ], [ -78.094840053725477, 8.927827459769446 ], [ -78.084065518209059, 8.934364529199627 ], [ -78.079182095177543, 8.943743800735774 ], [ -78.081662563876193, 8.958704128192949 ], [ -78.082127651869598, 8.976713365129683 ], [ -78.079879727167679, 9.001078803443988 ], [ -78.075332200920343, 9.019785671471539 ], [ -78.068536749971031, 9.034590969297767 ], [ -78.048202073966536, 9.06128184757921 ], [ -78.042543504579044, 9.073244941500832 ], [ -78.015335863259452, 9.073244941500832 ], [ -77.94208451958491, 9.020715847458405 ], [ -77.911905484050862, 8.996970526768393 ], [ -77.856663378212318, 8.941263332936444 ], [ -77.84648312009989, 8.924261786352361 ], [ -77.840359462718993, 8.911316840499751 ], [ -77.833693202978907, 8.90036143603146 ], [ -77.823667976296065, 8.893385117928858 ], [ -77.806718105656046, 8.885711167836121 ], [ -77.779226244395659, 8.866539210915846 ], [ -77.76418840167338, 8.859097804819839 ], [ -77.752044439699091, 8.850106106011992 ], [ -77.712408617363792, 8.813855089041112 ], [ -77.701143155432248, 8.800290025564209 ], [ -77.694838629998742, 8.786079006041291 ], [ -77.692513190031661, 8.772410589776882 ], [ -77.701711595313839, 8.771687120264403 ], [ -77.722743903308469, 8.776622219240039 ], [ -77.74721269441028, 8.773366604185412 ], [ -77.769278531179282, 8.762307847828879 ], [ -77.778296068408793, 8.749362901077006 ], [ -77.790129971121246, 8.740138658272429 ], [ -77.806253017662641, 8.737348131211263 ], [ -77.821807624322389, 8.732852280908048 ], [ -77.835786098949313, 8.716083279219959 ], [ -77.84725826735513, 8.694818427228597 ], [ -77.877488979732618, 8.652702135295272 ], [ -77.897100186224577, 8.641591702095354 ], [ -77.908598192152851, 8.62167043724088 ], [ -77.905316738676561, 8.601129054762055 ], [ -77.898495450204848, 8.583817449815456 ], [ -77.88583472429309, 8.568443712107637 ], [ -77.872192144651763, 8.555912177405048 ], [ -77.869504971277365, 8.537360338109124 ], [ -77.876016201386562, 8.525784816915746 ], [ -77.875757818968168, 8.523278509795375 ], [ -77.875757818968168, 8.521573188351965 ], [ -77.873380703056966, 8.517749132516428 ], [ -77.860875006776155, 8.505475979332971 ], [ -77.851263190343957, 8.50178111380734 ], [ -77.840101081199919, 8.498577174696834 ], [ -77.837052171720359, 8.492091783009357 ], [ -77.840126918722319, 8.487208359977842 ], [ -77.840230272409144, 8.48175649706468 ], [ -77.815167202104703, 8.455763250773373 ], [ -77.810387131860637, 8.446048082453046 ], [ -77.808940191936301, 8.434989325197193 ], [ -77.812402512565882, 8.42429230404656 ], [ -77.815813158150718, 8.417341824365678 ], [ -77.817027554078322, 8.409719550217062 ], [ -77.817363450862558, 8.401322129712526 ], [ -77.800051845915959, 8.374863796327134 ], [ -77.797261318854794, 8.36129873285023 ], [ -77.793282233388368, 8.348327948575957 ], [ -77.786951870432461, 8.34011139612403 ], [ -77.777469245209488, 8.331300564469473 ], [ -77.771526454981881, 8.324453437576096 ], [ -77.764343431304269, 8.313653061839318 ], [ -77.76268978490566, 8.310190741209738 ], [ -77.762974005745775, 8.304713039874855 ], [ -77.756591965946484, 8.295747179488728 ], [ -77.746515062420201, 8.290837918035493 ], [ -77.740494757826809, 8.290011094836132 ], [ -77.735223762066937, 8.287556464559202 ], [ -77.734862026861038, 8.280140895985539 ], [ -77.735818041269567, 8.272156887530343 ], [ -77.731683926172252, 8.258255927269204 ], [ -77.720831875390729, 8.251021225848888 ], [ -77.691634690888236, 8.243941554958781 ], [ -77.663548550425276, 8.230531521112823 ], [ -77.625540534268225, 8.199680691110984 ], [ -77.607350430178201, 8.15702179591915 ], [ -77.611174486013681, 8.14079539569093 ], [ -77.60135596400653, 8.125447496404831 ], [ -77.581072963946099, 8.11927216218055 ], [ -77.571900397085642, 8.110564683313498 ], [ -77.552573412333118, 8.084829820339905 ], [ -77.538620775228594, 8.08165172055044 ], [ -77.519991420667509, 8.092658800063532 ], [ -77.498984951094599, 8.096043606327385 ], [ -77.492783780247237, 8.094028224722763 ], [ -77.486401740447945, 8.092865504739223 ], [ -77.463224859639524, 8.096663723052359 ], [ -77.452527839388267, 8.101082058090469 ], [ -77.44524146202383, 8.109996243431851 ], [ -77.43909196622127, 8.11903961818382 ], [ -77.425320197169356, 8.127643744263366 ], [ -77.4045462706938, 8.133250636807418 ], [ -77.38338477238932, 8.136712958336318 ], [ -77.270032518386017, 8.167537949916436 ], [ -77.269434250999922, 8.167700643000046 ] ], [ [ -78.083109503800529, 7.917734076366514 ], [ -78.091868658611702, 7.972640286320143 ], [ -78.101790534305678, 7.978221340442474 ], [ -78.111609056312886, 7.986696275312852 ], [ -78.118197800787868, 8.016177679756083 ], [ -78.127422045391086, 8.029174303351397 ], [ -78.137163052133133, 8.039819648557909 ], [ -78.1673420885665, 8.081935940491235 ], [ -78.183439296686174, 8.093563136729358 ], [ -78.200079108064358, 8.08066986682087 ], [ -78.225452236731314, 8.069326890523541 ], [ -78.227725999855011, 8.050232448868428 ], [ -78.212791510819557, 8.04250682193225 ], [ -78.210259366176786, 8.033980211117864 ], [ -78.211861334832747, 8.024575100260677 ], [ -78.205815191817635, 8.012818711914008 ], [ -78.201991135982098, 8.001217353198285 ], [ -78.225736456672109, 7.984448349711556 ], [ -78.257439948294973, 7.996075547748319 ], [ -78.278084682661984, 7.982743028268146 ], [ -78.295835537180267, 7.965793158527447 ], [ -78.313379686123596, 7.964475408912961 ], [ -78.329321866410965, 7.959747016411654 ], [ -78.334489509383332, 7.945148424160436 ], [ -78.329606086351816, 7.936079210087485 ], [ -78.332499966200487, 7.915951238758623 ], [ -78.331078863798496, 7.892851874114683 ], [ -78.327203132018894, 7.879803575474625 ], [ -78.321182827425559, 7.867917995918788 ], [ -78.310899217424947, 7.862001044112901 ], [ -78.303897060900624, 7.8596497657241 ], [ -78.284595912771124, 7.819445501708515 ], [ -78.2695063950041, 7.772135728381159 ], [ -78.24506344322333, 7.730923774012922 ], [ -78.197004361062397, 7.677852078510625 ], [ -78.179563564906573, 7.665320542908717 ], [ -78.138325772116673, 7.67733531277446 ], [ -78.121220872745084, 7.667826850029087 ], [ -78.106028002190556, 7.65653554877656 ], [ -78.090008308436666, 7.652117213738393 ], [ -78.081223314304509, 7.644856675694996 ], [ -78.072438321071672, 7.601525986934746 ], [ -78.048331265175761, 7.589898789797303 ], [ -78.038176846384317, 7.607442938740633 ], [ -78.018901536676537, 7.617726548741246 ], [ -78.004561326843771, 7.605840969185351 ], [ -77.990892909680042, 7.590260525003202 ], [ -77.968361985816955, 7.60160350219985 ], [ -77.949706793733526, 7.618785915937281 ], [ -77.94479753317961, 7.651626288222587 ], [ -77.955907966379527, 7.739166164886569 ], [ -77.952161424010512, 7.748752142897047 ], [ -77.948466560283521, 7.762007148011435 ], [ -77.953039924053257, 7.779215400170585 ], [ -77.961695726076869, 7.794382432303394 ], [ -77.970997484146551, 7.797922268198079 ], [ -77.980971034885329, 7.803968411213191 ], [ -77.985311855557654, 7.835646064414334 ], [ -78.016214362402877, 7.931350815787482 ], [ -78.034998744796212, 7.950884507913713 ], [ -78.059209154378948, 7.931324978265138 ], [ -78.083109503800529, 7.917734076366514 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-8", "NAME_1": "Panama" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -78.409698045999903, 8.353013414000088 ], [ -78.415638800999943, 8.356268622000073 ], [ -78.438710089999915, 8.384426174000055 ], [ -78.449777798999946, 8.391017971000053 ], [ -78.444406704999949, 8.403225002000056 ], [ -78.445179816999939, 8.421087958000044 ], [ -78.449940558999913, 8.439154364000046 ], [ -78.456654425999943, 8.451849677000041 ], [ -78.464019334999932, 8.446234442000048 ], [ -78.468088344999899, 8.440130927000041 ], [ -78.469960089999915, 8.433010158000059 ], [ -78.470855272999927, 8.424505927000041 ], [ -78.475493943999936, 8.434027411000045 ], [ -78.486398891999897, 8.447821356000077 ], [ -78.490793423999946, 8.45929596600007 ], [ -78.491363084999932, 8.47337474200009 ], [ -78.483957485999952, 8.507066148000092 ], [ -78.490793423999946, 8.524481512000079 ], [ -78.520008917999917, 8.563462632000039 ], [ -78.531727667999917, 8.575995184000078 ], [ -78.516713019999941, 8.575262762000079 ], [ -78.505767381999931, 8.571966864000046 ], [ -78.495920376999948, 8.570746161000045 ], [ -78.483957485999952, 8.575995184000078 ], [ -78.50031490799995, 8.588690497000073 ], [ -78.505848761999914, 8.59906647300005 ], [ -78.504383917999917, 8.634019273000092 ], [ -78.566477016999897, 8.651068427000041 ], [ -78.561268683999913, 8.666449286000045 ], [ -78.558990037999934, 8.670965887000079 ], [ -78.565581834999932, 8.671779690000051 ], [ -78.56899980399993, 8.67023346600007 ], [ -78.573312954999949, 8.664740302000041 ], [ -78.581532355999911, 8.670111395000049 ], [ -78.589222785999937, 8.669582424000055 ], [ -78.596547003999945, 8.666489976000037 ], [ -78.60374915299991, 8.664740302000041 ], [ -78.612538214999915, 8.669745184000078 ], [ -78.618885870999918, 8.681463934000078 ], [ -78.627919074999909, 8.70571523600006 ], [ -78.613677537999934, 8.717230536000045 ], [ -78.608387824999909, 8.735337632000039 ], [ -78.609486456999946, 8.755926825000074 ], [ -78.614247199999909, 8.774603583000044 ], [ -78.621693488999938, 8.774603583000044 ], [ -78.623117641999897, 8.758490302000041 ], [ -78.619130011999914, 8.737860419000071 ], [ -78.619740363999938, 8.723537502000056 ], [ -78.634755011999914, 8.726223049000055 ], [ -78.651519334999932, 8.707953192000048 ], [ -78.682199673999946, 8.747748114000046 ], [ -78.709868943999936, 8.747300523000092 ], [ -78.729400193999936, 8.759344794000071 ], [ -78.749379035999937, 8.801825262000079 ], [ -78.765126105999911, 8.815578518000052 ], [ -78.765126105999911, 8.822414455000057 ], [ -78.757639126999948, 8.822414455000057 ], [ -78.757639126999948, 8.829250393000052 ], [ -78.772450324999909, 8.833563544000071 ], [ -78.781809048999946, 8.842840887000079 ], [ -78.789621548999946, 8.853908596000053 ], [ -78.799875454999949, 8.863348700000074 ], [ -78.791900193999936, 8.846665757000039 ], [ -78.790150519999941, 8.833563544000071 ], [ -78.796457485999952, 8.823472398000092 ], [ -78.812855597999942, 8.815578518000052 ], [ -78.827870245999918, 8.81313711100006 ], [ -78.838002081999946, 8.816961981000077 ], [ -78.857574022999927, 8.839789130000042 ], [ -78.864572719999899, 8.855617580000057 ], [ -78.868560350999928, 8.874904690000051 ], [ -78.873890753999945, 8.891180731000077 ], [ -79.005279100999928, 8.959540106000077 ], [ -79.057606574999909, 8.97101471600007 ], [ -79.082997199999909, 8.988836981000077 ], [ -79.087228969999899, 8.994330145000049 ], [ -79.088490363999938, 9.004095770000049 ], [ -79.085682745999918, 9.009751695000091 ], [ -79.081776495999918, 9.015326239000046 ], [ -79.079823370999918, 9.024725653000075 ], [ -79.079335089999915, 9.045396226000037 ], [ -79.080881313999953, 9.06281159100007 ], [ -79.088856574999909, 9.073797919000071 ], [ -79.10773678299995, 9.07562897300005 ], [ -79.10773678299995, 9.083075262000079 ], [ -79.086293097999942, 9.08462148600006 ], [ -79.069894985999952, 9.093329169000071 ], [ -79.058583136999914, 9.107163804000038 ], [ -79.052479620999918, 9.124009507000039 ], [ -79.046254035999937, 9.124009507000039 ], [ -79.03742428299995, 9.110500393000052 ], [ -79.027699347999942, 9.111029364000046 ], [ -79.011545376999948, 9.124009507000039 ], [ -78.991200324999909, 9.13117096600007 ], [ -78.982167120999918, 9.136419989000046 ], [ -78.977365688999953, 9.14516836100006 ], [ -78.983754035999937, 9.141994533000059 ], [ -78.997181769999941, 9.14093659100007 ], [ -79.005279100999928, 9.138332424000055 ], [ -79.01195227799991, 9.13312409100007 ], [ -79.024728969999899, 9.119370835000041 ], [ -79.028920050999943, 9.116603908000059 ], [ -79.036936001999948, 9.119614976000037 ], [ -79.039540167999917, 9.125921942000048 ], [ -79.042632615999935, 9.131089585000041 ], [ -79.052479620999918, 9.130845445000091 ], [ -79.058664516999897, 9.12563711100006 ], [ -79.070871548999946, 9.107489325000074 ], [ -79.076649542999917, 9.103583075000074 ], [ -79.079009568999936, 9.101467190000051 ], [ -79.082183397999927, 9.096747137000079 ], [ -79.087798631999931, 9.092027085000041 ], [ -79.097482876999948, 9.089911200000074 ], [ -79.106760219999899, 9.089422919000071 ], [ -79.114165818999936, 9.087551174000055 ], [ -79.119048631999931, 9.083197333000044 ], [ -79.120716925999943, 9.07562897300005 ], [ -79.114572719999899, 9.068793036000045 ], [ -79.101673956999946, 9.065008856000077 ], [ -79.089995897999927, 9.056382554000038 ], [ -79.087228969999899, 9.035305080000057 ], [ -79.091786261999914, 9.023016669000071 ], [ -79.102121548999946, 9.006008205000057 ], [ -79.116078253999945, 8.994126695000091 ], [ -79.131581183999913, 8.997463283000059 ], [ -79.138091600999928, 9.000799872000073 ], [ -79.16234290299991, 9.007391669000071 ], [ -79.163400844999899, 9.011786200000074 ], [ -79.16828365799995, 9.01984284100007 ], [ -79.173491990999935, 9.022528387000079 ], [ -79.17601477799991, 9.010728257000039 ], [ -79.192982550999943, 9.005194403000075 ], [ -79.273345506999931, 9.019273179000038 ], [ -79.29946855399993, 9.014146226000037 ], [ -79.305734829999949, 9.014146226000037 ], [ -79.305734829999949, 9.020982164000088 ], [ -79.33031165299991, 9.013413804000038 ], [ -79.386830206999946, 9.018866278000075 ], [ -79.409331834999932, 9.007391669000071 ], [ -79.41820227799991, 9.014146226000037 ], [ -79.427479620999918, 9.013373114000046 ], [ -79.437123175999943, 9.009588934000078 ], [ -79.454457160999937, 9.006293036000045 ], [ -79.466908331999946, 9.001654364000046 ], [ -79.474517381999931, 9.000555731000077 ], [ -79.482004360999952, 8.99835846600007 ], [ -79.484038865999935, 8.993719794000071 ], [ -79.48468990799995, 8.98899974200009 ], [ -79.487904425999943, 8.986883856000077 ], [ -79.491078253999945, 8.983465887000079 ], [ -79.519195115999935, 8.966376044000071 ], [ -79.521229620999918, 8.957424221000053 ], [ -79.520253058999913, 8.948879299000055 ], [ -79.522206183999913, 8.942287502000056 ], [ -79.532866990999935, 8.939113674000055 ], [ -79.515533006999931, 8.909979559000078 ], [ -79.511830206999946, 8.898138739000046 ], [ -79.524973110999952, 8.907294012000079 ], [ -79.541127081999946, 8.92328522300005 ], [ -79.554676886999914, 8.942084052000041 ], [ -79.560170050999943, 8.959540106000077 ], [ -79.566395636999914, 8.959540106000077 ], [ -79.565012173999946, 8.95376211100006 ], [ -79.563221808999913, 8.950018622000073 ], [ -79.560170050999943, 8.945298570000091 ], [ -79.560170050999943, 8.939113674000055 ], [ -79.566395636999914, 8.939113674000055 ], [ -79.559193488999938, 8.914292710000041 ], [ -79.563872850999928, 8.892767645000049 ], [ -79.578480597999942, 8.88226959800005 ], [ -79.601185675999943, 8.890692450000074 ], [ -79.646839972999942, 8.882635809000078 ], [ -79.661203579999949, 8.875230210000041 ], [ -79.655751105999911, 8.863348700000074 ], [ -79.655751105999911, 8.857123114000046 ], [ -79.666859503999945, 8.860825914000088 ], [ -79.673980272999927, 8.86554596600007 ], [ -79.680653449999909, 8.867621161000045 ], [ -79.690541144999941, 8.863348700000074 ], [ -79.693470831999946, 8.86664459800005 ], [ -79.694650844999899, 8.868312893000052 ], [ -79.697010870999918, 8.869208075000074 ], [ -79.703602667999917, 8.870184637000079 ], [ -79.703602667999917, 8.863348700000074 ], [ -79.700795050999943, 8.859930731000077 ], [ -79.699208136999914, 8.854803778000075 ], [ -79.696766730999911, 8.849676825000074 ], [ -79.713937954999949, 8.852606512000079 ], [ -79.730213995999918, 8.844305731000077 ], [ -79.743560350999928, 8.830064195000091 ], [ -79.752023891999897, 8.815578518000052 ], [ -79.756255662999934, 8.796291408000059 ], [ -79.752023891999897, 8.736761786000045 ], [ -79.749867316999939, 8.731024481000077 ], [ -79.745187954999949, 8.728013414000088 ], [ -79.74046790299991, 8.725978908000059 ], [ -79.738352016999897, 8.722805080000057 ], [ -79.739328579999949, 8.716498114000046 ], [ -79.741363084999932, 8.711127020000049 ], [ -79.744536912999934, 8.70571523600006 ], [ -79.746815558999913, 8.697943427000041 ], [ -79.750803188999953, 8.689601955000057 ], [ -79.756011522999927, 8.681586005000042 ], [ -79.76195227799991, 8.674709377000056 ], [ -79.76593990799995, 8.671820380000042 ], [ -79.778391079999949, 8.665838934000078 ], [ -79.791005011999914, 8.663234768000052 ], [ -79.791737433999913, 8.659491278000075 ], [ -79.790516730999911, 8.65501536700009 ], [ -79.792958136999914, 8.651068427000041 ], [ -79.810018632999913, 8.646601108000084 ], [ -79.826310674999945, 8.638520066000069 ], [ -79.813690615999917, 8.626059908000059 ], [ -79.779608045999908, 8.618409940000049 ], [ -79.747351025999933, 8.631258633000073 ], [ -79.717304992999914, 8.646310358000051 ], [ -79.705803937999917, 8.652550776000055 ], [ -79.702093589999947, 8.657320823000077 ], [ -79.697269139999946, 8.657323396000038 ], [ -79.69689726799993, 8.648887585000068 ], [ -79.700607138999942, 8.641550643000073 ], [ -79.734365124999897, 8.615498574000071 ], [ -79.774395956999911, 8.579550130000086 ], [ -79.793673171999899, 8.572207498000068 ], [ -79.826298354999949, 8.561552820000088 ], [ -79.864117993999912, 8.552357599000061 ], [ -79.871525425999948, 8.542819456000075 ], [ -79.86978105399993, 8.531805731000077 ], [ -79.87173417899993, 8.52415599200009 ], [ -79.874867316999939, 8.520697333000044 ], [ -79.879994269999941, 8.518622137000079 ], [ -79.891224738999938, 8.516302802000041 ], [ -79.895375128999945, 8.514553127000056 ], [ -79.910552537999934, 8.500474351000037 ], [ -79.917632615999935, 8.495428778000075 ], [ -79.926747199999909, 8.493394273000092 ], [ -79.932118292999917, 8.489162502000056 ], [ -79.941802537999934, 8.470404364000046 ], [ -79.946888800999943, 8.466131903000075 ], [ -79.948963995999918, 8.462307033000059 ], [ -79.970204230999911, 8.44407786700009 ], [ -80.040801561999899, 8.39797597900008 ], [ -80.081721361151892, 8.445557156037921 ], [ -80.086475592974239, 8.455272325257567 ], [ -80.092030808674849, 8.470852769439773 ], [ -80.095622321412975, 8.52663747853677 ], [ -80.104665697064263, 8.551312974314328 ], [ -80.104407314645812, 8.583042304358855 ], [ -80.103089565930702, 8.591878974435133 ], [ -80.106784430557013, 8.626424669063226 ], [ -80.112546352731954, 8.643012804497289 ], [ -80.137609423036452, 8.755357367248678 ], [ -80.163680182794167, 8.830701605994307 ], [ -80.164507005993528, 8.854446925784998 ], [ -80.161768154876427, 8.872275295568443 ], [ -80.155696174338971, 8.888889268524906 ], [ -80.13311357273318, 8.922246404747796 ], [ -80.137454393405505, 8.949247341391697 ], [ -80.0926509262992, 8.983689683232285 ], [ -80.050172899159975, 8.96834178304681 ], [ -80.022241787428527, 8.966171372710676 ], [ -79.985396491255074, 8.977798569848119 ], [ -79.955940925233506, 8.996970526768393 ], [ -79.95061825173093, 9.007977607180806 ], [ -79.945192227239488, 9.023738918516244 ], [ -79.945502284702684, 9.039086818701719 ], [ -79.948990444653305, 9.050739854260826 ], [ -79.9573361883144, 9.066165268812085 ], [ -79.962684699339377, 9.083476873758684 ], [ -79.920671760193557, 9.175176703042382 ], [ -79.905943976733113, 9.190627956914682 ], [ -79.889252489410865, 9.193961086335037 ], [ -79.857988247359685, 9.179284979718034 ], [ -79.830005458784854, 9.173238836702922 ], [ -79.819050056115202, 9.167890326577322 ], [ -79.808559739640259, 9.158123481413497 ], [ -79.789542813250193, 9.126239121738081 ], [ -79.778225673575946, 9.114353543081563 ], [ -79.756237352072105, 9.10923757605326 ], [ -79.704741786803993, 9.110012722409181 ], [ -79.687921109171839, 9.115981350159188 ], [ -79.669756842604215, 9.128151150555141 ], [ -79.641567349353693, 9.16261932991813 ], [ -79.635159471132681, 9.189852810558762 ], [ -79.629345873013619, 9.193573512707417 ], [ -79.622292039645913, 9.198999538997498 ], [ -79.604747890702583, 9.20713857708364 ], [ -79.58774634501782, 9.212125352003397 ], [ -79.573716192648135, 9.218249010283557 ], [ -79.568781093672499, 9.22390757877173 ], [ -79.567515020901453, 9.230961412139436 ], [ -79.57193335593962, 9.248815619445281 ], [ -79.56999548960016, 9.26362091727151 ], [ -79.565060390624524, 9.284575710000979 ], [ -79.551908739196961, 9.318320420750808 ], [ -79.547542080102914, 9.333926703354678 ], [ -79.547180344896958, 9.344468695773685 ], [ -79.549893357592339, 9.348344428452606 ], [ -79.550590989582474, 9.355579128074282 ], [ -79.548498093612125, 9.365888577395935 ], [ -79.522504849119457, 9.454255276359902 ], [ -79.485194464952599, 9.469396470970366 ], [ -79.440778570574537, 9.479008287402507 ], [ -79.416128913218756, 9.472497057293367 ], [ -79.399721645837246, 9.46614085501642 ], [ -79.391220873444524, 9.459526272119774 ], [ -79.384606288749239, 9.45092214604017 ], [ -79.381195644963043, 9.445263577552055 ], [ -79.371247931746666, 9.432525336375136 ], [ -79.369697639034825, 9.428262030068595 ], [ -79.371402961377555, 9.425393987742325 ], [ -79.376028001990676, 9.422913519942995 ], [ -79.388352831118254, 9.417565008918018 ], [ -79.393753018087295, 9.414154364232502 ], [ -79.397267014660997, 9.409012558782536 ], [ -79.398791469850437, 9.40296641756612 ], [ -79.396130133998497, 9.395912584198413 ], [ -79.391427578120215, 9.393974717858953 ], [ -79.384477098439334, 9.394904892946442 ], [ -79.368147346322985, 9.400563463233254 ], [ -79.358793911409862, 9.402501329572715 ], [ -79.334893561988281, 9.402346299941769 ], [ -79.328614874976495, 9.403896593552929 ], [ -79.318176236244312, 9.412216497893041 ], [ -79.307789272556874, 9.414851996222637 ], [ -79.29016760924776, 9.415084540219368 ], [ -79.266939053394594, 9.407307237339126 ], [ -79.256707119338046, 9.402423814307554 ], [ -79.252082078724925, 9.396610216188492 ], [ -79.253761562645991, 9.391339220428677 ], [ -79.261513028003833, 9.380952256741239 ], [ -79.261616380791338, 9.375655422559703 ], [ -79.257068853644682, 9.372244777874187 ], [ -79.248077154836835, 9.368911648453775 ], [ -79.242728644711178, 9.363563137428855 ], [ -79.239343838447382, 9.356741848057823 ], [ -79.238103604098058, 9.34973969243282 ], [ -79.238672044878967, 9.344081122146065 ], [ -79.239808926440787, 9.339740302373059 ], [ -79.246991950118399, 9.330748603565212 ], [ -79.266112230195233, 9.321576035805379 ], [ -79.272494269994525, 9.314289659340318 ], [ -79.279031337626122, 9.303360094192954 ], [ -79.281046719230687, 9.293024807348957 ], [ -79.280064867299757, 9.286513577239759 ], [ -79.27205502042284, 9.279537258237838 ], [ -79.239162971294093, 9.286436061974655 ], [ -79.170536669131934, 9.307778429231121 ], [ -79.156713223236636, 9.309871324302151 ], [ -79.143303189390679, 9.310103868298881 ], [ -79.12865292029602, 9.30909617794623 ], [ -79.115372076759911, 9.306305649985745 ], [ -79.093642136775202, 9.297546495174572 ], [ -79.085038010695598, 9.289769192294386 ], [ -79.078242560645663, 9.282250270933218 ], [ -79.07180884490225, 9.277366847901703 ], [ -79.056796840601692, 9.276359158448372 ], [ -79.011140712773681, 9.277599391898377 ], [ -79.002200689909898, 9.280467434224704 ], [ -78.998169929398728, 9.284188137272679 ], [ -78.998169929398728, 9.288373928314115 ], [ -79.000650397198058, 9.294135850489113 ], [ -79.004164394671079, 9.299949449507494 ], [ -79.005637173017135, 9.30638316525085 ], [ -79.002820808433569, 9.312661851363316 ], [ -78.997084723780972, 9.317157700767268 ], [ -78.97274512388833, 9.327725530708676 ], [ -78.964657761746309, 9.328888250692216 ], [ -78.956131150931867, 9.328035589970511 ], [ -78.945666672878644, 9.324676622128379 ], [ -78.939413825187842, 9.327803045973781 ], [ -78.937656826001728, 9.333384100995431 ], [ -78.937941046841843, 9.340282903832929 ], [ -78.937165899586603, 9.34454621013947 ], [ -78.932773403869476, 9.346329046848041 ], [ -78.92633968812612, 9.345243842129605 ], [ -78.915358446135372, 9.341058051088169 ], [ -78.900113897838082, 9.341213079819738 ], [ -78.890786302246056, 9.344468695773685 ], [ -78.878306444386908, 9.355734157705228 ], [ -78.87135596380665, 9.359377346387419 ], [ -78.857041592395547, 9.360927639099259 ], [ -78.839988368968022, 9.361082667830829 ], [ -78.808982510234671, 9.356741848057823 ], [ -78.795908373172892, 9.358679714397283 ], [ -78.787485114246635, 9.363408107797909 ], [ -78.781645676806534, 9.368214016463696 ], [ -78.777795783448653, 9.370616969897242 ], [ -78.77058692134932, 9.371469631518266 ], [ -78.765419278376953, 9.371547145884051 ], [ -78.758778856159267, 9.368601589191996 ], [ -78.741751472052783, 9.350773220307872 ], [ -78.72818640767656, 9.34454621013947 ], [ -78.721003383998948, 9.34702667883812 ], [ -78.716998461010178, 9.353796292265088 ], [ -78.714879726618051, 9.371237087521536 ], [ -78.709712083645741, 9.374182644213647 ], [ -78.698860032864218, 9.370772000427451 ], [ -78.677052577614347, 9.357051907319658 ], [ -78.641783412574398, 9.330206000306646 ], [ -78.627701586059345, 9.321421007073809 ], [ -78.610079921850911, 9.317777818391619 ], [ -78.594525316090426, 9.319173082371833 ], [ -78.542047898891383, 9.331368720290186 ], [ -78.537164475859868, 9.335011908073113 ], [ -78.52835364510463, 9.347956854824986 ], [ -78.521816575674393, 9.351238308301276 ], [ -78.512876552810667, 9.349688014690116 ], [ -78.500189989376508, 9.337957464765168 ], [ -78.495099859870606, 9.328888250692216 ], [ -78.490759040097601, 9.311654161010722 ], [ -78.486418220324595, 9.30870860431861 ], [ -78.479493578166057, 9.311344101748887 ], [ -78.472000495226666, 9.317235216032373 ], [ -78.465075853068129, 9.321033433446189 ], [ -78.457686122916243, 9.320413315821838 ], [ -78.448952805627471, 9.312196764269231 ], [ -78.445257941001159, 9.304445298911389 ], [ -78.441718106005794, 9.298399155896334 ], [ -78.437739019640048, 9.294600938482517 ], [ -78.430323451965705, 9.291939601731201 ], [ -78.424742397843374, 9.287443752327306 ], [ -78.419703946080233, 9.278917141512864 ], [ -78.416525845391448, 9.269537869077396 ], [ -78.415776536557928, 9.261915594928723 ], [ -78.416835903753963, 9.254784247195232 ], [ -78.414303758211872, 9.247885444357735 ], [ -78.408748541611885, 9.243622138051194 ], [ -78.394873419772466, 9.240599066993354 ], [ -78.36606380889765, 9.241761786077575 ], [ -78.346917691298415, 9.238015245507142 ], [ -78.339011197208947, 9.237498481569673 ], [ -78.331208055007721, 9.239978949369004 ], [ -78.295602993183593, 9.257342231159043 ], [ -78.289091763074396, 9.255714423182098 ], [ -78.284854296088895, 9.248583075448551 ], [ -78.280435961050728, 9.231581528864467 ], [ -78.270772467775146, 9.204890652381664 ], [ -78.26472632476009, 9.196053982305443 ], [ -78.257000698723232, 9.190860500911356 ], [ -78.234650642013492, 9.193108424714012 ], [ -78.209122483715646, 9.192720851985712 ], [ -78.186694911740744, 9.189387722565357 ], [ -78.178400844923033, 9.190085354555436 ], [ -78.174034186728306, 9.192720851985712 ], [ -78.171347011555326, 9.197681790282388 ], [ -78.169564174846755, 9.202255154052125 ], [ -78.165610927802049, 9.205665797838265 ], [ -78.158686285643569, 9.203030300408045 ], [ -78.150831468397541, 9.194271144697552 ], [ -78.145818854156801, 9.172773748709517 ], [ -78.150469733191642, 9.161224066837178 ], [ -78.160805020035639, 9.145385240236635 ], [ -78.158841315274458, 9.139959214845874 ], [ -78.152330085165261, 9.134998277448517 ], [ -78.083290370953819, 9.118694362854569 ], [ -78.072386644228231, 9.112803250369723 ], [ -78.06504859091973, 9.107842312073046 ], [ -78.042543504579044, 9.073244941500832 ], [ -78.048202073966536, 9.06128184757921 ], [ -78.068536749971031, 9.034590969297767 ], [ -78.075332200920343, 9.019785671471539 ], [ -78.079879727167679, 9.001078803443988 ], [ -78.082127651869598, 8.976713365129683 ], [ -78.081662563876193, 8.958704128192949 ], [ -78.079182095177543, 8.943743800735774 ], [ -78.084065518209059, 8.934364529199627 ], [ -78.094840053725477, 8.927827459769446 ], [ -78.119722255977308, 8.922091376016169 ], [ -78.137214728077197, 8.914262397191862 ], [ -78.154035406608727, 8.899663804940644 ], [ -78.167083706148105, 8.877727159380868 ], [ -78.174990200237517, 8.871965237205927 ], [ -78.185919766284201, 8.869329738876331 ], [ -78.205014207939314, 8.870880032487491 ], [ -78.221860724892508, 8.870337429228982 ], [ -78.242660488890408, 8.865996609455976 ], [ -78.271289231712672, 8.852664089076427 ], [ -78.281004400932318, 8.842561347128481 ], [ -78.284699265558629, 8.832949529796963 ], [ -78.285810309598105, 8.82457794771409 ], [ -78.290331997423721, 8.816025499377304 ], [ -78.299633754594083, 8.809126694741167 ], [ -78.30901302792887, 8.806723741307621 ], [ -78.321699592262348, 8.812072252332541 ], [ -78.331724819844567, 8.827368476573895 ], [ -78.338158534688603, 8.833027045062067 ], [ -78.362317268327274, 8.841708686406719 ], [ -78.379034593171923, 8.8448092718304 ], [ -78.393038907119831, 8.84542938945475 ], [ -78.438875902101188, 8.830003974004171 ], [ -78.446033088256399, 8.82535309496933 ], [ -78.451174892807046, 8.819694526481214 ], [ -78.448410204167601, 8.805948594951701 ], [ -78.436912198239327, 8.748303533880971 ], [ -78.433398199867042, 8.738381659086258 ], [ -78.428773159253865, 8.714481308765357 ], [ -78.428230556894675, 8.70259573010884 ], [ -78.431718715945976, 8.68717031555758 ], [ -78.435620287046618, 8.676447455085963 ], [ -78.441537237953128, 8.665052801945251 ], [ -78.44507707384787, 8.653580634438697 ], [ -78.448125983327429, 8.638749498190748 ], [ -78.452105068793855, 8.598105983704158 ], [ -78.457841153446452, 8.568624579260927 ], [ -78.458461270171483, 8.56038218838728 ], [ -78.454921434276741, 8.556583970973463 ], [ -78.451329922437935, 8.553715929546513 ], [ -78.447945116174139, 8.546274522551187 ], [ -78.44910783615768, 8.533536282273587 ], [ -78.445232102579439, 8.508318183237577 ], [ -78.432390510413711, 8.477674057911429 ], [ -78.429599981553906, 8.455634060463524 ], [ -78.413244391915157, 8.39754974982111 ], [ -78.409698045999903, 8.353013414000088 ] ] ], [ [ [ -79.09406490799995, 8.308498440000051 ], [ -79.087505018999934, 8.295776164000074 ], [ -79.083001288999924, 8.274186322000048 ], [ -79.075863760999937, 8.265991063000058 ], [ -79.070992048999926, 8.264492413000085 ], [ -79.065741008999908, 8.260760089000087 ], [ -79.069859950999899, 8.257050825000078 ], [ -79.080390841999929, 8.254828134000093 ], [ -79.09127787299991, 8.259680790000061 ], [ -79.103788038999937, 8.252959415000078 ], [ -79.104527957999949, 8.244402237000088 ], [ -79.098447140999951, 8.238471424000068 ], [ -79.098509926999952, 8.229879634000042 ], [ -79.104887160999908, 8.228778713000054 ], [ -79.108681894999904, 8.22392517600008 ], [ -79.109519565999904, 8.210469238000087 ], [ -79.122708963999912, 8.208981766000079 ], [ -79.140002596999921, 8.244395848000067 ], [ -79.136972714999899, 8.25743809800008 ], [ -79.130564049999919, 8.256690183000046 ], [ -79.129804721999903, 8.264141881000057 ], [ -79.125649834999933, 8.277552791000062 ], [ -79.129410938999911, 8.287243020000062 ], [ -79.124499671999899, 8.303261001000067 ], [ -79.112430808999932, 8.317408727000043 ], [ -79.104886923999914, 8.318517622000059 ], [ -79.100372740999944, 8.317396915000074 ], [ -79.094878709999932, 8.311753648000092 ], [ -79.09406490799995, 8.308498440000051 ] ] ], [ [ [ -79.084393131999946, 8.38249055700004 ], [ -79.092844204999949, 8.377183335000041 ], [ -79.112175363999938, 8.391497737000066 ], [ -79.130098166999915, 8.404869682000083 ], [ -79.118237902999908, 8.429110441000091 ], [ -79.105018183999903, 8.418740701000047 ], [ -79.094838019999941, 8.406480210000041 ], [ -79.090148768999939, 8.410278495000057 ], [ -79.087942970999904, 8.419543644000044 ], [ -79.082437647999939, 8.415996564000068 ], [ -79.086283909999906, 8.403453466000087 ], [ -79.078867673999923, 8.398554347000072 ], [ -79.080251867999948, 8.390929745000051 ], [ -79.084393131999946, 8.38249055700004 ] ] ], [ [ [ -78.892244474999927, 8.458046989000081 ], [ -78.893713354999932, 8.469273655000052 ], [ -78.889929614999915, 8.474136485000088 ], [ -78.88018061799994, 8.468460590000063 ], [ -78.869130011999914, 8.46165599200009 ], [ -78.862782355999911, 8.453680731000077 ], [ -78.858225063999953, 8.442938544000071 ], [ -78.855376756999931, 8.431341864000046 ], [ -78.854481574999909, 8.421087958000044 ], [ -78.854683346999934, 8.413287151000077 ], [ -78.842228961999922, 8.411064086000067 ], [ -78.835510272999898, 8.397995399000081 ], [ -78.83733826699995, 8.386865516000057 ], [ -78.845670493999933, 8.381269455000051 ], [ -78.847959188999937, 8.368606294000074 ], [ -78.834476484999925, 8.342810923000059 ], [ -78.843207130999929, 8.320457840000074 ], [ -78.852298044999941, 8.312268477000089 ], [ -78.852281255999912, 8.303331914000069 ], [ -78.858021613999938, 8.295843817000048 ], [ -78.87041456299994, 8.296650181000075 ], [ -78.875343353999938, 8.301494433000073 ], [ -78.882503159999942, 8.300386780000053 ], [ -78.889230923999946, 8.29913971600007 ], [ -78.896399369999926, 8.297429279000085 ], [ -78.899051896999936, 8.302641950000066 ], [ -78.901325136999901, 8.308967386000063 ], [ -78.904690625999933, 8.302649751000047 ], [ -78.912197316999936, 8.293727235000063 ], [ -78.920475972999952, 8.282565959000067 ], [ -78.920117176999952, 8.274001963000046 ], [ -78.922775145999935, 8.265446118000057 ], [ -78.912987238999904, 8.253881356000079 ], [ -78.911139844999923, 8.234147619000055 ], [ -78.90511446499994, 8.22929004100007 ], [ -78.89757411699992, 8.228897258000075 ], [ -78.897578898999939, 8.224426574000063 ], [ -78.903985470999942, 8.219221605000087 ], [ -78.917924441999901, 8.227084176000062 ], [ -78.928454176999935, 8.235667604000071 ], [ -78.926937611999904, 8.249817786000051 ], [ -78.933656070999916, 8.273271306000083 ], [ -78.940042924999943, 8.282589941000083 ], [ -78.957997199999909, 8.290432033000059 ], [ -78.964344855999911, 8.294826565000051 ], [ -78.969897972999945, 8.305098917000066 ], [ -78.965412144999902, 8.320765975000086 ], [ -78.958237339999926, 8.329105164000055 ], [ -78.954776936999906, 8.346514341000045 ], [ -78.958485480999911, 8.352850653000075 ], [ -78.96727762699993, 8.362430036000092 ], [ -78.969907833999912, 8.369891318000043 ], [ -78.965753005999943, 8.377316386000075 ], [ -78.961602310999922, 8.383618156000068 ], [ -78.9612179209999, 8.390315085000054 ], [ -78.965717357999949, 8.408223900000053 ], [ -78.964344855999911, 8.417669989000046 ], [ -78.974711849999949, 8.444368241000063 ], [ -78.97092155699994, 8.458449965000057 ], [ -78.958126855999922, 8.458806186000061 ], [ -78.949104439999928, 8.452789919000054 ], [ -78.908777396999938, 8.470040703000052 ], [ -78.899769660999937, 8.461615302000041 ], [ -78.896962042999917, 8.456691799000055 ], [ -78.895415818999936, 8.451849677000041 ], [ -78.892244474999927, 8.458046989000081 ] ] ], [ [ [ -79.57039255199993, 8.798575963000076 ], [ -79.563339603999907, 8.80463886800004 ], [ -79.556894653999905, 8.802516973000081 ], [ -79.553827177999949, 8.803426325000089 ], [ -79.553211499999918, 8.800395163000076 ], [ -79.555357465999919, 8.797970274000079 ], [ -79.55259222199993, 8.791908401000057 ], [ -79.547988696999937, 8.788877806000073 ], [ -79.541852668999923, 8.786756789000037 ], [ -79.541236750999929, 8.781302357000072 ], [ -79.543380957999943, 8.775544614000069 ], [ -79.547980846999906, 8.774028666000049 ], [ -79.551357553999935, 8.779179747000057 ], [ -79.555347572999949, 8.782815983000091 ], [ -79.56270948699995, 8.781299764000039 ], [ -79.569153707999931, 8.78311735300008 ], [ -79.57161263799992, 8.789178986000081 ], [ -79.57039255199993, 8.798575963000076 ] ] ], [ [ [ -79.132576381999854, 8.956866310000066 ], [ -79.130530568999859, 8.959460533000026 ], [ -79.129509377999852, 8.958450242000197 ], [ -79.128782136999916, 8.954844397000045 ], [ -79.123091317999865, 8.951523107000185 ], [ -79.127034967999919, 8.948786364000171 ], [ -79.127039227999944, 8.943306586000062 ], [ -79.131418931999917, 8.943021518000137 ], [ -79.132585597999935, 8.944608663000054 ], [ -79.129955001999861, 8.948356008000076 ], [ -79.130683270999896, 8.950519661000101 ], [ -79.132434140999919, 8.951818870000068 ], [ -79.132723536999947, 8.955280099 ], [ -79.132576381999854, 8.956866310000066 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-2", "NAME_1": "Coclé" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -80.040801561999899, 8.39797597900008 ], [ -80.080881313999896, 8.371771552000041 ], [ -80.125843878999945, 8.348618882000039 ], [ -80.19554602799991, 8.312933661000045 ], [ -80.224964972999942, 8.301052151000079 ], [ -80.272735154999907, 8.294826565000051 ], [ -80.281605597999942, 8.295925197000088 ], [ -80.294463670999903, 8.300441799000055 ], [ -80.300038214999915, 8.301052151000079 ], [ -80.30882727799991, 8.298651434000078 ], [ -80.326283331999946, 8.290309963000084 ], [ -80.33421790299991, 8.287990627000056 ], [ -80.361480272999927, 8.294826565000051 ], [ -80.374663865999935, 8.30337148600006 ], [ -80.380726691999939, 8.310370184000078 ], [ -80.375762498999904, 8.315252997000073 ], [ -80.3857722649999, 8.311346747000073 ], [ -80.386260545999903, 8.30695221600007 ], [ -80.384755011999914, 8.301581122000073 ], [ -80.388783331999946, 8.294826565000051 ], [ -80.407012498999904, 8.283026434000078 ], [ -80.470244920999903, 8.220648505000042 ], [ -80.478179490999935, 8.202337958000044 ], [ -80.47484290299991, 8.106472072000088 ], [ -80.476104295999903, 8.094875393000052 ], [ -80.478464321999923, 8.091376044000071 ], [ -80.491437954098274, 8.095190944706303 ], [ -80.514563158063254, 8.110513007369377 ], [ -80.526448736719829, 8.11637828233188 ], [ -80.532184821372368, 8.115344753557508 ], [ -80.543553636091417, 8.106740627477961 ], [ -80.549470587897304, 8.106120509853611 ], [ -80.558488125126871, 8.112838446437138 ], [ -80.57732418526291, 8.132811388135053 ], [ -80.59122514462473, 8.13854747188833 ], [ -80.609725307976589, 8.137307237538948 ], [ -80.646415575418473, 8.125292466773885 ], [ -80.662745326635502, 8.12405223242456 ], [ -80.687007412162302, 8.132604682560043 ], [ -80.734058803970584, 8.16353302692761 ], [ -80.738089566280451, 8.180689602243319 ], [ -80.711941291257574, 8.227069200483186 ], [ -80.697446051793861, 8.277195339293485 ], [ -80.693466966327435, 8.309312242066312 ], [ -80.717987434272686, 8.348896389356867 ], [ -80.756667243098775, 8.450208035072762 ], [ -80.78007666700455, 8.491419989440942 ], [ -80.800514695796551, 8.51857595481647 ], [ -80.822089606150371, 8.537747910837425 ], [ -80.810255703437974, 8.548289903256432 ], [ -80.77873307986772, 8.553328355019573 ], [ -80.751318732073798, 8.58637543377921 ], [ -80.73940731499556, 8.615236721497467 ], [ -80.715791184615455, 8.613841458416573 ], [ -80.705688442667508, 8.629912828114527 ], [ -80.694991420617555, 8.641772569248644 ], [ -80.692588467184009, 8.652004503305193 ], [ -80.694836391885985, 8.66326996523668 ], [ -80.696102464657031, 8.675439764733369 ], [ -80.69491390715109, 8.693759060032562 ], [ -80.685327928241293, 8.715101427289028 ], [ -80.677498949416986, 8.738304144720473 ], [ -80.666982795419642, 8.752334296190782 ], [ -80.651686571178288, 8.767010402807841 ], [ -80.640188565250071, 8.772126369836087 ], [ -80.630421719186984, 8.773909207443978 ], [ -80.612024908622629, 8.770266017862411 ], [ -80.600811122635207, 8.769335841875602 ], [ -80.586135016917467, 8.769723416402542 ], [ -80.569391852751778, 8.774606838534737 ], [ -80.555077481340675, 8.781583157536659 ], [ -80.542468431372981, 8.790962429072806 ], [ -80.535853847577016, 8.80587107968654 ], [ -80.532675746888174, 8.821167303927893 ], [ -80.534691127593476, 8.852431545079753 ], [ -80.537920905125645, 8.861268215155974 ], [ -80.541409064176946, 8.866461697449381 ], [ -80.543424444882191, 8.870802517222387 ], [ -80.542184211432186, 8.880595200807875 ], [ -80.530970425444764, 8.916975408987923 ], [ -80.523942429599458, 8.924881903976654 ], [ -80.51564836278169, 8.926587226319441 ], [ -80.424516975178221, 8.892687485938723 ], [ -80.411442837217123, 8.884625963117685 ], [ -80.389687058810694, 8.878347276105899 ], [ -80.364753180614798, 8.874678249901308 ], [ -80.355477260966779, 8.871887721940823 ], [ -80.341731330336586, 8.876564439397328 ], [ -80.325530769429463, 8.888811754159121 ], [ -80.246517503579923, 8.9635358752804 ], [ -80.232823248893794, 8.973302721343487 ], [ -80.222074550899777, 8.978418687472413 ], [ -80.214581467960386, 8.985782579202635 ], [ -80.207605149857784, 8.998443305114449 ], [ -80.202385830042033, 9.02730459193333 ], [ -80.192231411250589, 9.047484239206256 ], [ -80.178227098202001, 9.021801052176784 ], [ -80.177322760636855, 9.010845649507132 ], [ -80.170501472165199, 8.976325792401383 ], [ -80.164248622675757, 8.965706284717271 ], [ -80.157479011047485, 8.959479275448189 ], [ -80.149779221633764, 8.954518337151512 ], [ -80.137454393405505, 8.949247341391697 ], [ -80.13311357273318, 8.922246404747796 ], [ -80.155696174338971, 8.888889268524906 ], [ -80.161768154876427, 8.872275295568443 ], [ -80.164507005993528, 8.854446925784998 ], [ -80.163680182794167, 8.830701605994307 ], [ -80.137609423036452, 8.755357367248678 ], [ -80.112546352731954, 8.643012804497289 ], [ -80.106784430557013, 8.626424669063226 ], [ -80.103089565930702, 8.591878974435133 ], [ -80.104407314645812, 8.583042304358855 ], [ -80.104665697064263, 8.551312974314328 ], [ -80.095622321412975, 8.52663747853677 ], [ -80.092030808674849, 8.470852769439773 ], [ -80.086475592974239, 8.455272325257567 ], [ -80.081721361151892, 8.445557156037921 ], [ -80.040801561999899, 8.39797597900008 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-9", "NAME_1": "Veraguas" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -81.807728644999941, 7.28742096600007 ], [ -81.798003709999932, 7.291083075000074 ], [ -81.789906378999945, 7.290106512000079 ], [ -81.780506964999915, 7.28782786700009 ], [ -81.766713019999941, 7.28742096600007 ], [ -81.779042120999918, 7.277492580000057 ], [ -81.792388475999928, 7.251654364000046 ], [ -81.800892706999946, 7.23899974200009 ], [ -81.796986456999946, 7.233954169000071 ], [ -81.793446417999917, 7.225978908000059 ], [ -81.800892706999946, 7.225978908000059 ], [ -81.816232876999948, 7.271307684000078 ], [ -81.814564581999946, 7.279974677000041 ], [ -81.818755662999934, 7.285630601000094 ], [ -81.819162563999896, 7.288723049000055 ], [ -81.814564581999946, 7.294256903000075 ], [ -81.81078040299991, 7.294134833000044 ], [ -81.808257615999935, 7.293443101000094 ], [ -81.807199673999946, 7.291571356000077 ], [ -81.807728644999941, 7.28742096600007 ] ] ], [ [ [ -81.149159308999913, 7.56118398600006 ], [ -81.135568813999896, 7.568182684000078 ], [ -81.118072068999936, 7.57453034100007 ], [ -81.087717251999948, 7.581610419000071 ], [ -81.075021938999896, 7.577337958000044 ], [ -81.061594204999949, 7.575588283000059 ], [ -81.033070441999939, 7.575425523000092 ], [ -81.044992641999897, 7.55414459800005 ], [ -81.052845831999946, 7.544623114000046 ], [ -81.064116990999935, 7.540676174000055 ], [ -81.075021938999896, 7.535345770000049 ], [ -81.082753058999913, 7.53384023600006 ], [ -81.091420050999943, 7.537543036000045 ], [ -81.097767706999946, 7.542547919000071 ], [ -81.103342251999948, 7.54555898600006 ], [ -81.109852667999917, 7.547064520000049 ], [ -81.119048631999931, 7.54751211100006 ], [ -81.129261847999942, 7.545314846000053 ], [ -81.134388800999943, 7.539943752000056 ], [ -81.137847459999932, 7.533392645000049 ], [ -81.142974412999934, 7.52765534100007 ], [ -81.170887824999909, 7.513373114000046 ], [ -81.184925910999937, 7.496975002000056 ], [ -81.190744594999899, 7.493475653000075 ], [ -81.199126756999931, 7.493475653000075 ], [ -81.208566860999952, 7.495591539000088 ], [ -81.215809699999909, 7.498277085000041 ], [ -81.218088344999899, 7.499701239000046 ], [ -81.245676235999952, 7.490057684000078 ], [ -81.251942511999914, 7.490423895000049 ], [ -81.242583787999934, 7.503404039000088 ], [ -81.232899542999917, 7.513373114000046 ], [ -81.222727016999897, 7.521063544000071 ], [ -81.210438605999911, 7.525946356000077 ], [ -81.174387173999946, 7.531439520000049 ], [ -81.164051886999914, 7.540513414000088 ], [ -81.157622850999928, 7.551581122000073 ], [ -81.149159308999913, 7.56118398600006 ] ] ], [ [ [ -81.66437740799995, 7.397284247000073 ], [ -81.652495897999927, 7.391017971000053 ], [ -81.622059699999909, 7.393866278000075 ], [ -81.61587480399993, 7.386704820000091 ], [ -81.588002081999946, 7.335191148000092 ], [ -81.606678839999915, 7.32758209800005 ], [ -81.628163214999915, 7.321600653000075 ], [ -81.649403449999909, 7.321519273000092 ], [ -81.68423417899993, 7.341376044000071 ], [ -81.727121548999946, 7.344427802000041 ], [ -81.746245897999927, 7.348863023000092 ], [ -81.756703253999945, 7.35773346600007 ], [ -81.780751105999911, 7.38422272300005 ], [ -81.800038214999915, 7.395575262000079 ], [ -81.841867641999897, 7.430812893000052 ], [ -81.864654100999928, 7.478461005000042 ], [ -81.872873501999948, 7.486029364000046 ], [ -81.875111456999946, 7.490423895000049 ], [ -81.882801886999914, 7.516791083000044 ], [ -81.878895636999914, 7.517482815000051 ], [ -81.85806230399993, 7.517523505000042 ], [ -81.848703579999949, 7.520209052000041 ], [ -81.848947719999899, 7.524115302000041 ], [ -81.83625240799995, 7.546698309000078 ], [ -81.834380662999934, 7.54751211100006 ], [ -81.831776495999918, 7.559271552000041 ], [ -81.831410285999937, 7.568182684000078 ], [ -81.829986131999931, 7.576157945000091 ], [ -81.82445227799991, 7.585353908000059 ], [ -81.816802537999934, 7.590399481000077 ], [ -81.798329230999911, 7.594224351000037 ], [ -81.770130988999938, 7.614813544000071 ], [ -81.760365363999938, 7.620184637000079 ], [ -81.759917772999927, 7.616400458000044 ], [ -81.752512173999946, 7.616400458000044 ], [ -81.755238410999937, 7.624009507000039 ], [ -81.757313605999911, 7.636419989000046 ], [ -81.759917772999927, 7.644273179000038 ], [ -81.752512173999946, 7.644273179000038 ], [ -81.752512173999946, 7.636867580000057 ], [ -81.746245897999927, 7.636867580000057 ], [ -81.746815558999913, 7.641831773000092 ], [ -81.745350714999915, 7.64329661700009 ], [ -81.74242102799991, 7.643459377000056 ], [ -81.738840298999946, 7.644273179000038 ], [ -81.716175910999937, 7.579657294000071 ], [ -81.715199347999942, 7.568019924000055 ], [ -81.713286912999934, 7.565904039000088 ], [ -81.70531165299991, 7.553697007000039 ], [ -81.704823370999918, 7.55109284100007 ], [ -81.705922003999945, 7.543117580000057 ], [ -81.70531165299991, 7.540676174000055 ], [ -81.702137824999909, 7.540187893000052 ], [ -81.693837042999917, 7.541408596000053 ], [ -81.691029425999943, 7.540676174000055 ], [ -81.682036912999934, 7.534572658000059 ], [ -81.675648566999939, 7.532131252000056 ], [ -81.671783006999931, 7.526353257000039 ], [ -81.670521613999938, 7.510239976000094 ], [ -81.676380988999938, 7.505519924000055 ], [ -81.708363410999937, 7.493475653000075 ], [ -81.709339972999942, 7.48663971600007 ], [ -81.716786261999914, 7.457505601000094 ], [ -81.71898352799991, 7.452541408000059 ], [ -81.712717251999948, 7.44009023600006 ], [ -81.694732225999928, 7.423976955000057 ], [ -81.691029425999943, 7.414048570000091 ], [ -81.689198370999918, 7.403794664000088 ], [ -81.684437628999945, 7.395005601000094 ], [ -81.677886522999927, 7.391587632000039 ], [ -81.670521613999938, 7.397284247000073 ], [ -81.66437740799995, 7.397284247000073 ] ] ], [ [ [ -81.213072785999941, 8.791808601000071 ], [ -81.17478467299992, 8.796765778000065 ], [ -81.130340235999938, 8.801736471000083 ], [ -81.087717251999948, 8.808742580000057 ], [ -81.079904751999948, 8.804836330000057 ], [ -81.070708787999934, 8.806830145000049 ], [ -81.061512824999909, 8.813177802000041 ], [ -81.053578253999945, 8.822414455000057 ], [ -80.97513893799993, 8.848088992000044 ], [ -80.898923209999907, 8.879635169000039 ], [ -80.881717073999937, 8.885697916000083 ], [ -80.862597200663629, 8.885066039578389 ], [ -80.861983811803441, 8.876900336181563 ], [ -80.861725430284366, 8.874161485064462 ], [ -80.860330166304095, 8.853594265063293 ], [ -80.856842007252794, 8.844111639840321 ], [ -80.851183437865359, 8.832716986699552 ], [ -80.840693122289736, 8.820857245565435 ], [ -80.833432583347019, 8.814552721031248 ], [ -80.815087449626105, 8.802615465531289 ], [ -80.797827520623571, 8.794553940911612 ], [ -80.78025753415784, 8.788895372423497 ], [ -80.769017909748698, 8.784063626235366 ], [ -80.761524827708627, 8.779490261566309 ], [ -80.740440842870612, 8.755744940876298 ], [ -80.733542040033115, 8.74458283083294 ], [ -80.728193529008138, 8.730139268212668 ], [ -80.732921923308083, 8.714868883292297 ], [ -80.73863216774032, 8.70282827410557 ], [ -80.741965298060052, 8.690813503340507 ], [ -80.738115403802851, 8.672494208041257 ], [ -80.733361171980505, 8.66443268522022 ], [ -80.727935146589743, 8.658619086201838 ], [ -80.725790574675273, 8.653038031180188 ], [ -80.723904385179196, 8.64611338992097 ], [ -80.73940731499556, 8.615236721497467 ], [ -80.751318732073798, 8.58637543377921 ], [ -80.77873307986772, 8.553328355019573 ], [ -80.810255703437974, 8.548289903256432 ], [ -80.822089606150371, 8.537747910837425 ], [ -80.800514695796551, 8.51857595481647 ], [ -80.78007666700455, 8.491419989440942 ], [ -80.756667243098775, 8.450208035072762 ], [ -80.717987434272686, 8.348896389356867 ], [ -80.693466966327435, 8.309312242066312 ], [ -80.697446051793861, 8.277195339293485 ], [ -80.711941291257574, 8.227069200483186 ], [ -80.738089566280451, 8.180689602243319 ], [ -80.734058803970584, 8.16353302692761 ], [ -80.687007412162302, 8.132604682560043 ], [ -80.709745043399039, 8.130718492164647 ], [ -80.71876257972923, 8.132966416866623 ], [ -80.732379320049574, 8.133353990494243 ], [ -80.742042813325156, 8.129788316177837 ], [ -80.764702928397412, 8.102554836436525 ], [ -80.780955166147976, 8.087956244185307 ], [ -80.817025315965566, 8.073616034352483 ], [ -80.853560553776504, 8.059947618088074 ], [ -80.837980108695035, 8.015893459815288 ], [ -80.839194506421336, 8.00036469247658 ], [ -80.849943202616714, 7.980831000350349 ], [ -80.857772183239661, 7.969565538418863 ], [ -80.886349250117803, 7.944347439382796 ], [ -80.907407395634777, 7.92186819146383 ], [ -80.93290971461164, 7.915408637298754 ], [ -80.93774146169909, 7.911067817525748 ], [ -80.943425868608927, 7.90145600019423 ], [ -80.946991542925332, 7.788413805452763 ], [ -80.942754075939831, 7.765831203846972 ], [ -80.919499680765625, 7.771799832496242 ], [ -80.909474453183464, 7.767691554921328 ], [ -80.904771898204501, 7.76327321988316 ], [ -80.897563036105225, 7.753247992300999 ], [ -80.891671922721059, 7.737435004122119 ], [ -80.884928147715812, 7.708651230769647 ], [ -80.879217902384255, 7.695318712188794 ], [ -80.802064989407711, 7.58116547340785 ], [ -80.772299364124365, 7.563647161986921 ], [ -80.751861335332364, 7.559228826948811 ], [ -80.745737677951468, 7.55574066789751 ], [ -80.719692755716096, 7.529592392874633 ], [ -80.722069871627241, 7.50173879640829 ], [ -80.715067715102975, 7.458899034063165 ], [ -80.699254726924096, 7.410710760693064 ], [ -80.673468187107119, 7.37595836048996 ], [ -80.667137824151268, 7.352523098162465 ], [ -80.666595221792022, 7.337795314702021 ], [ -80.668765632128213, 7.327304999126397 ], [ -80.668068000138078, 7.322809149722445 ], [ -80.653366055099355, 7.318003241056715 ], [ -80.644245165082282, 7.312577216565273 ], [ -80.623497077028446, 7.297203477058815 ], [ -80.613290982292995, 7.285808823918103 ], [ -80.606779751284478, 7.271830349291179 ], [ -80.6040750717072, 7.236721022557106 ], [ -80.71312415299991, 7.216457424000055 ], [ -80.793365037999934, 7.213568427000041 ], [ -80.813994920999903, 7.219142971000053 ], [ -80.820790167999917, 7.219142971000053 ], [ -80.825957811999899, 7.213324286000045 ], [ -80.8310847649999, 7.211371161000045 ], [ -80.836211717999902, 7.213324286000045 ], [ -80.841297980999911, 7.219142971000053 ], [ -80.848133917999917, 7.219142971000053 ], [ -80.861805792999917, 7.20571523600006 ], [ -80.873076951999906, 7.212551174000055 ], [ -80.889068162999934, 7.239040432000081 ], [ -80.894439256999931, 7.243434963000084 ], [ -80.901763475999928, 7.248114325000074 ], [ -80.910552537999934, 7.251776434000078 ], [ -80.920074022999927, 7.253322658000059 ], [ -80.929717576999906, 7.25649648600006 ], [ -80.930165167999917, 7.263576565000051 ], [ -80.925567186999899, 7.270575262000079 ], [ -80.920074022999927, 7.27374909100007 ], [ -80.916005011999914, 7.278143622000073 ], [ -80.917144334999932, 7.299627997000073 ], [ -80.916371222999942, 7.307928778000075 ], [ -80.9111628899999, 7.315008856000077 ], [ -80.899932420999903, 7.323513088000084 ], [ -80.895985480999911, 7.328395901000079 ], [ -80.892364061999899, 7.341742255000042 ], [ -80.891590949999909, 7.360174872000073 ], [ -80.895659959999932, 7.376613674000055 ], [ -80.921172654999907, 7.39203522300005 ], [ -80.920806443999936, 7.41079336100006 ], [ -80.910186326999906, 7.441677151000079 ], [ -80.9150691399999, 7.454657294000071 ], [ -80.951161261999914, 7.493475653000075 ], [ -80.954619920999903, 7.495510158000059 ], [ -80.962188279999907, 7.502468166000085 ], [ -80.966908331999946, 7.509914455000057 ], [ -80.954701300999943, 7.516913153000075 ], [ -80.952748175999943, 7.525458075000074 ], [ -80.951649542999917, 7.535589911000045 ], [ -80.947743292999917, 7.544094143000052 ], [ -80.9463191399999, 7.555690822000088 ], [ -80.95571855399993, 7.569647528000075 ], [ -80.96898352799991, 7.582058010000083 ], [ -80.979115363999938, 7.589056708000044 ], [ -80.979115363999938, 7.595892645000049 ], [ -80.971669074999909, 7.595892645000049 ], [ -80.971669074999909, 7.602728583000044 ], [ -81.020049607999908, 7.650539455000057 ], [ -81.02993730399993, 7.656073309000078 ], [ -81.037505662999934, 7.658270575000074 ], [ -81.041289842999902, 7.661688544000071 ], [ -81.039906378999945, 7.671047268000052 ], [ -81.035186326999906, 7.679958401000079 ], [ -81.027821417999917, 7.68618398600006 ], [ -81.017852342999902, 7.688421942000048 ], [ -81.005767381999931, 7.685329494000086 ], [ -81.010609503999945, 7.693915106000077 ], [ -81.021839972999942, 7.70266347900008 ], [ -81.034453904999907, 7.70929596600007 ], [ -81.043324347999942, 7.711981512000079 ], [ -81.044829881999931, 7.716701565000051 ], [ -81.026234503999945, 7.74673086100006 ], [ -81.037139451999906, 7.745998440000051 ], [ -81.046864386999914, 7.747219143000052 ], [ -81.054839647999927, 7.750026760000083 ], [ -81.061024542999917, 7.754177151000079 ], [ -81.057606574999909, 7.754950262000079 ], [ -81.054798956999946, 7.754828192000048 ], [ -81.053252732999908, 7.755926825000074 ], [ -81.053578253999945, 7.76040273600006 ], [ -81.076690232999908, 7.764797268000052 ], [ -81.086089647999927, 7.779120184000078 ], [ -81.085438605999911, 7.794338283000059 ], [ -81.078114386999914, 7.801336981000077 ], [ -81.07249915299991, 7.803534247000073 ], [ -81.067494269999941, 7.808172919000071 ], [ -81.060821092999902, 7.812892971000053 ], [ -81.050160285999937, 7.815008856000077 ], [ -81.037627732999908, 7.815008856000077 ], [ -81.02757727799991, 7.816799221000053 ], [ -81.021270311999899, 7.822699286000045 ], [ -81.020049607999908, 7.835516669000071 ], [ -81.026234503999945, 7.835516669000071 ], [ -81.048858201999906, 7.822699286000045 ], [ -81.055897589999915, 7.849391994000086 ], [ -81.053578253999945, 7.911200262000079 ], [ -81.0752253899999, 7.871283270000049 ], [ -81.090443488999938, 7.857855536000045 ], [ -81.101958787999934, 7.877101955000057 ], [ -81.108184373999904, 7.877101955000057 ], [ -81.105946417999917, 7.866400458000044 ], [ -81.102162238999938, 7.858587958000044 ], [ -81.096302863999938, 7.85305410400008 ], [ -81.087676561999899, 7.849188544000071 ], [ -81.087676561999899, 7.842311916000085 ], [ -81.13304602799991, 7.842311916000085 ], [ -81.142364061999899, 7.844427802000041 ], [ -81.154815232999908, 7.85382721600007 ], [ -81.167144334999932, 7.855983791000085 ], [ -81.1924128899999, 7.863348700000074 ], [ -81.197377081999946, 7.879055080000057 ], [ -81.199940558999913, 7.893622137000079 ], [ -81.218047654999907, 7.897528387000079 ], [ -81.208159959999932, 7.893459377000056 ], [ -81.205230272999927, 7.889919338000084 ], [ -81.204375779999907, 7.883327541000085 ], [ -81.217640753999945, 7.878973700000074 ], [ -81.215199347999942, 7.870998440000051 ], [ -81.197539842999902, 7.855983791000085 ], [ -81.180205857999908, 7.846869208000044 ], [ -81.177113410999937, 7.845729885000083 ], [ -81.178700324999909, 7.836859442000048 ], [ -81.181630011999914, 7.829657294000071 ], [ -81.183257615999935, 7.82367584800005 ], [ -81.16470292899993, 7.789007880000042 ], [ -81.174427863999938, 7.763006903000075 ], [ -81.196685350999928, 7.74172597900008 ], [ -81.218047654999907, 7.726263739000046 ], [ -81.222401495999918, 7.734401760000083 ], [ -81.223174607999908, 7.739203192000048 ], [ -81.221465623999904, 7.742702541000085 ], [ -81.218047654999907, 7.74673086100006 ], [ -81.218047654999907, 7.754177151000079 ], [ -81.232045050999943, 7.755031643000052 ], [ -81.245961066999939, 7.754177151000079 ], [ -81.245961066999939, 7.74673086100006 ], [ -81.2353816399999, 7.743841864000046 ], [ -81.229481574999909, 7.73781972900008 ], [ -81.218047654999907, 7.719427802000041 ], [ -81.231556769999941, 7.71438222900008 ], [ -81.237416144999941, 7.715114651000079 ], [ -81.245961066999939, 7.719427802000041 ], [ -81.238677537999934, 7.707464911000045 ], [ -81.231678839999915, 7.698919989000046 ], [ -81.225493943999936, 7.698919989000046 ], [ -81.212147589999915, 7.706122137000079 ], [ -81.197539842999902, 7.711981512000079 ], [ -81.193267381999931, 7.700751044000071 ], [ -81.197539842999902, 7.657375393000052 ], [ -81.195464647999927, 7.645697333000044 ], [ -81.195179816999939, 7.638861395000049 ], [ -81.197539842999902, 7.630072333000044 ], [ -81.201324022999927, 7.625189520000049 ], [ -81.213408982999908, 7.615423895000049 ], [ -81.218047654999907, 7.608954169000071 ], [ -81.225493943999936, 7.608954169000071 ], [ -81.234038865999935, 7.615261135000083 ], [ -81.266224738999938, 7.632391669000071 ], [ -81.273304816999939, 7.633490302000041 ], [ -81.278716600999928, 7.646063544000071 ], [ -81.291167772999927, 7.650661526000079 ], [ -81.314239061999899, 7.650539455000057 ], [ -81.396962042999917, 7.673529364000046 ], [ -81.424102342999902, 7.671047268000052 ], [ -81.428212042999917, 7.682562567000048 ], [ -81.434925910999937, 7.692653713000084 ], [ -81.442901170999903, 7.700466213000084 ], [ -81.450795050999943, 7.705145575000074 ], [ -81.473907029999907, 7.699408270000049 ], [ -81.503448045999903, 7.701971747000073 ], [ -81.525786912999934, 7.711452541000085 ], [ -81.527129686999899, 7.726263739000046 ], [ -81.518666144999941, 7.728908596000053 ], [ -81.499989386999914, 7.738674221000053 ], [ -81.488758917999917, 7.749212958000044 ], [ -81.528065558999913, 7.760565497000073 ], [ -81.539051886999914, 7.75735097900008 ], [ -81.540191209999932, 7.739935614000046 ], [ -81.563221808999913, 7.756293036000045 ], [ -81.574940558999913, 7.76040273600006 ], [ -81.574940558999913, 7.767238674000055 ], [ -81.568389451999906, 7.77602773600006 ], [ -81.573882615999935, 7.784328518000052 ], [ -81.583119269999941, 7.793402411000045 ], [ -81.588002081999946, 7.804470119000086 ], [ -81.586293097999942, 7.820868231000077 ], [ -81.581776495999918, 7.83156972900008 ], [ -81.567494269999941, 7.849188544000071 ], [ -81.567494269999941, 7.855983791000085 ], [ -81.574615037999934, 7.860663153000075 ], [ -81.581898566999939, 7.862494208000044 ], [ -81.588978644999941, 7.861110744000086 ], [ -81.595448370999918, 7.855983791000085 ], [ -81.601592576999906, 7.855983791000085 ], [ -81.609120245999918, 7.86281972900008 ], [ -81.609120245999918, 7.870266018000052 ], [ -81.599761522999927, 7.877834377000056 ], [ -81.599883592999902, 7.885036526000079 ], [ -81.608021613999938, 7.889837958000044 ], [ -81.622710740999935, 7.89008209800005 ], [ -81.619618292999917, 7.905340887000079 ], [ -81.618682420999903, 7.922023830000057 ], [ -81.612945115999935, 7.931423244000086 ], [ -81.595448370999918, 7.924872137000079 ], [ -81.598011847999942, 7.933783270000049 ], [ -81.602080857999908, 7.940008856000077 ], [ -81.61587480399993, 7.952175197000088 ], [ -81.611236131999931, 7.95962148600006 ], [ -81.612945115999935, 7.974188544000071 ], [ -81.609120245999918, 7.986354885000083 ], [ -81.62132727799991, 7.981350002000056 ], [ -81.627105272999927, 7.982814846000053 ], [ -81.628895636999914, 7.981838283000059 ], [ -81.628936326999906, 7.969265041000085 ], [ -81.624134894999941, 7.95538971600007 ], [ -81.622588670999903, 7.947943427000041 ], [ -81.625884568999936, 7.944728908000059 ], [ -81.633290167999917, 7.945868231000077 ], [ -81.638457811999899, 7.949245510000083 ], [ -81.641590949999909, 7.954657294000071 ], [ -81.642608201999906, 7.962103583000044 ], [ -81.645904100999928, 7.973089911000045 ], [ -81.663574609280772, 7.997287569465755 ], [ -81.662555100937141, 7.99765167888188 ], [ -81.64247880735104, 8.0030001899068 ], [ -81.638008796368865, 8.011242580780447 ], [ -81.633771327584668, 8.022714749186321 ], [ -81.631755947778743, 8.034987901470458 ], [ -81.606124436693392, 8.134904283206083 ], [ -81.601886969707891, 8.145058701997471 ], [ -81.597907884241465, 8.152060859421113 ], [ -81.573180711620523, 8.176116238473639 ], [ -81.522951219123456, 8.239032294404865 ], [ -81.517137621004395, 8.243760687805491 ], [ -81.51550981302745, 8.246086126873251 ], [ -81.513106858694584, 8.251047065169928 ], [ -81.510471361264308, 8.281226100703975 ], [ -81.513210212381409, 8.310707506046526 ], [ -81.51933386886293, 8.341739203201655 ], [ -81.522486132029371, 8.379333808208685 ], [ -81.526671923070751, 8.429201565499852 ], [ -81.525715908662221, 8.443851833695135 ], [ -81.522511969551715, 8.460465807550975 ], [ -81.49930925212027, 8.516095486117763 ], [ -81.490317552413103, 8.555886338983328 ], [ -81.488612230070373, 8.596943263720618 ], [ -81.463161587037575, 8.583972480345665 ], [ -81.432362433879177, 8.576686102981228 ], [ -81.42122616225754, 8.571880195214817 ], [ -81.415231696085868, 8.568081976901681 ], [ -81.410529141106963, 8.558521837312924 ], [ -81.363477749298681, 8.554956162996518 ], [ -81.337484503906694, 8.560227158756334 ], [ -81.328518642621248, 8.558056749319519 ], [ -81.282345750855711, 8.52221914349866 ], [ -81.265550909846581, 8.511599635814548 ], [ -81.225139940256042, 8.500954291507355 ], [ -81.203254970640387, 8.492195135796862 ], [ -81.192041184652908, 8.489404608735697 ], [ -81.183617926625971, 8.489404608735697 ], [ -81.15607438762288, 8.495528266116594 ], [ -81.171603155860964, 8.510979519089517 ], [ -81.180258958783895, 8.526559963271666 ], [ -81.183824632200981, 8.535706691710459 ], [ -81.188320481604933, 8.544104112214995 ], [ -81.195916918231148, 8.552320665566242 ], [ -81.204546881833096, 8.565291448941196 ], [ -81.210541348004767, 8.586297919413425 ], [ -81.214520432571874, 8.62322072995272 ], [ -81.211238979994903, 8.683837185237905 ], [ -81.22273698592312, 8.757760321581543 ], [ -81.215915696552145, 8.782900906251825 ], [ -81.215941534973865, 8.788249417276745 ], [ -81.213072785999941, 8.791808601000071 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-3", "NAME_1": "Colón" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -80.57933726999994, 9.08068731700007 ], [ -80.506772714999897, 9.110891244000072 ], [ -80.408315861999938, 9.14226211600004 ], [ -80.292591925999943, 9.151353257000039 ], [ -80.277455206999946, 9.156398830000057 ], [ -80.24478105399993, 9.175116278000075 ], [ -80.234934048999946, 9.179266669000071 ], [ -80.199940558999913, 9.183172919000071 ], [ -80.162912563999896, 9.192938544000071 ], [ -80.129709438999896, 9.206203518000052 ], [ -80.100819464999915, 9.222316799000055 ], [ -80.065200701999913, 9.262480813000082 ], [ -80.026193813999896, 9.296616929000038 ], [ -80.000823381999908, 9.320515588000092 ], [ -79.99850467899995, 9.331796456000063 ], [ -79.978943743999935, 9.36335312600005 ], [ -79.953731057999903, 9.373433893000083 ], [ -79.947436411999945, 9.372848822000037 ], [ -79.943755662999934, 9.36359284100007 ], [ -79.945912238999938, 9.325873114000046 ], [ -79.943755662999934, 9.31586334800005 ], [ -79.938221808999913, 9.309149481000077 ], [ -79.929432745999918, 9.30414459800005 ], [ -79.919178839999915, 9.303168036000045 ], [ -79.909047003999945, 9.308417059000078 ], [ -79.901600714999915, 9.326646226000037 ], [ -79.900257941999939, 9.346828518000052 ], [ -79.894683397999927, 9.356431382000039 ], [ -79.874867316999939, 9.343166408000059 ], [ -79.877064581999946, 9.351629950000074 ], [ -79.879505988999938, 9.368801174000055 ], [ -79.881703253999945, 9.37726471600007 ], [ -79.879302537999934, 9.375433661000045 ], [ -79.874867316999939, 9.371079820000091 ], [ -79.868031378999945, 9.37726471600007 ], [ -79.880401583999912, 9.39464028000009 ], [ -79.871211531999904, 9.404204787000083 ], [ -79.85978611999991, 9.399083630000064 ], [ -79.840898126999946, 9.400709095000082 ], [ -79.818623143999901, 9.39103205400005 ], [ -79.800363735999952, 9.36078522300005 ], [ -79.792958136999914, 9.349351304000038 ], [ -79.796986456999946, 9.371283270000049 ], [ -79.802154100999928, 9.386664130000042 ], [ -79.802723761999914, 9.400580145000049 ], [ -79.792958136999914, 9.418198960000041 ], [ -79.778146938999896, 9.431586005000042 ], [ -79.74828040299991, 9.442531643000052 ], [ -79.731516079999949, 9.453029690000051 ], [ -79.729359503999945, 9.455959377000056 ], [ -79.726633266999897, 9.463364976000037 ], [ -79.724720831999946, 9.466701565000051 ], [ -79.721302863999938, 9.469224351000037 ], [ -79.714654536999944, 9.479844922000041 ], [ -79.705462690999923, 9.485459786000092 ], [ -79.690629719999947, 9.495799408000039 ], [ -79.6842831539999, 9.521478175000084 ], [ -79.677374585999928, 9.545607528000062 ], [ -79.6596830229999, 9.552373618000047 ], [ -79.651662453999904, 9.55969390000007 ], [ -79.656484815999931, 9.564962828000091 ], [ -79.66772035799994, 9.560802323000075 ], [ -79.676503058999913, 9.558417059000078 ], [ -79.682157668999935, 9.564526740000076 ], [ -79.675731972999927, 9.568706321000093 ], [ -79.66984326599993, 9.572886580000045 ], [ -79.664484856999934, 9.583370031000072 ], [ -79.650031054999943, 9.589606428000081 ], [ -79.638852935999921, 9.598508694000088 ], [ -79.630335196999908, 9.608473537000066 ], [ -79.612210227999924, 9.613666727000066 ], [ -79.596242733999929, 9.611521288000063 ], [ -79.576548929999944, 9.617789961000085 ], [ -79.550968549999936, 9.629292480000061 ], [ -79.532866990999935, 9.624335028000075 ], [ -79.52798417899993, 9.612453518000052 ], [ -79.522613084999932, 9.602850653000075 ], [ -79.522450324999909, 9.595282294000071 ], [ -79.532866990999935, 9.589544989000046 ], [ -79.532866990999935, 9.583319403000075 ], [ -79.523060675999943, 9.579046942000048 ], [ -79.522816535999937, 9.576727606000077 ], [ -79.519195115999935, 9.56907786700009 ], [ -79.51431230399993, 9.572495835000041 ], [ -79.510731574999909, 9.57453034100007 ], [ -79.507883266999897, 9.577378648000092 ], [ -79.504994269999941, 9.583319403000075 ], [ -79.498158331999946, 9.583319403000075 ], [ -79.492014126999948, 9.578680731000077 ], [ -79.483876105999911, 9.575018622000073 ], [ -79.463978644999941, 9.56907786700009 ], [ -79.463490363999938, 9.577704169000071 ], [ -79.456532355999911, 9.596380927000041 ], [ -79.451242641999897, 9.587388414000088 ], [ -79.444569464999915, 9.583807684000078 ], [ -79.437245245999918, 9.58470286700009 ], [ -79.429839647999927, 9.589544989000046 ], [ -79.391892219999932, 9.580501864000041 ], [ -79.336046023999927, 9.574359218000041 ], [ -79.272749655999917, 9.557021313000064 ], [ -79.2397089829999, 9.545515083000055 ], [ -79.193757228999914, 9.53960210200006 ], [ -79.175003644999947, 9.549403746000053 ], [ -79.156274363999898, 9.554955061000044 ], [ -79.133276086999899, 9.553404717000092 ], [ -79.116036741999949, 9.551889715000073 ], [ -79.098771641999917, 9.556032194000068 ], [ -79.080066530999943, 9.56157950000005 ], [ -79.074532601798481, 9.562041560085573 ], [ -79.074547696019351, 9.541278388187038 ], [ -79.074986944691716, 9.457278347417798 ], [ -79.078914354214078, 9.450999661305332 ], [ -79.087001716356099, 9.448751735704036 ], [ -79.095502488748821, 9.447744045351385 ], [ -79.102220425332348, 9.445883694277029 ], [ -79.11263322564281, 9.439449978533673 ], [ -79.120875617415777, 9.431517646022542 ], [ -79.132218593713105, 9.415239569850257 ], [ -79.135577561555181, 9.405524399731235 ], [ -79.137282883897967, 9.389943956448406 ], [ -79.139143235871643, 9.38351023980573 ], [ -79.142062954142034, 9.377851671317558 ], [ -79.148083258735369, 9.372012233877456 ], [ -79.157074958442536, 9.366586209386014 ], [ -79.176246913564171, 9.360152492743339 ], [ -79.192680020266721, 9.352685248225612 ], [ -79.220352748680398, 9.335554511331623 ], [ -79.239318000025662, 9.320490831087 ], [ -79.243477952645378, 9.320568346352104 ], [ -79.246991950118399, 9.330748603565212 ], [ -79.239808926440787, 9.339740302373059 ], [ -79.238672044878967, 9.344081122146065 ], [ -79.238103604098058, 9.34973969243282 ], [ -79.239343838447382, 9.356741848057823 ], [ -79.242728644711178, 9.363563137428855 ], [ -79.248077154836835, 9.368911648453775 ], [ -79.257068853644682, 9.372244777874187 ], [ -79.261616380791338, 9.375655422559703 ], [ -79.261513028003833, 9.380952256741239 ], [ -79.253761562645991, 9.391339220428677 ], [ -79.252082078724925, 9.396610216188492 ], [ -79.256707119338046, 9.402423814307554 ], [ -79.266939053394594, 9.407307237339126 ], [ -79.29016760924776, 9.415084540219368 ], [ -79.307789272556874, 9.414851996222637 ], [ -79.318176236244312, 9.412216497893041 ], [ -79.328614874976495, 9.403896593552929 ], [ -79.334893561988281, 9.402346299941769 ], [ -79.358793911409862, 9.402501329572715 ], [ -79.368147346322985, 9.400563463233254 ], [ -79.384477098439334, 9.394904892946442 ], [ -79.391427578120215, 9.393974717858953 ], [ -79.396130133998497, 9.395912584198413 ], [ -79.398791469850437, 9.40296641756612 ], [ -79.397267014660997, 9.409012558782536 ], [ -79.393753018087295, 9.414154364232502 ], [ -79.388352831118254, 9.417565008918018 ], [ -79.376028001990676, 9.422913519942995 ], [ -79.371402961377555, 9.425393987742325 ], [ -79.369697639034825, 9.428262030068595 ], [ -79.371247931746666, 9.432525336375136 ], [ -79.381195644963043, 9.445263577552055 ], [ -79.384606288749239, 9.45092214604017 ], [ -79.391220873444524, 9.459526272119774 ], [ -79.399721645837246, 9.46614085501642 ], [ -79.416128913218756, 9.472497057293367 ], [ -79.440778570574537, 9.479008287402507 ], [ -79.485194464952599, 9.469396470970366 ], [ -79.522504849119457, 9.454255276359902 ], [ -79.548498093612125, 9.365888577395935 ], [ -79.550590989582474, 9.355579128074282 ], [ -79.549893357592339, 9.348344428452606 ], [ -79.547180344896958, 9.344468695773685 ], [ -79.547542080102914, 9.333926703354678 ], [ -79.551908739196961, 9.318320420750808 ], [ -79.565060390624524, 9.284575710000979 ], [ -79.56999548960016, 9.26362091727151 ], [ -79.57193335593962, 9.248815619445281 ], [ -79.567515020901453, 9.230961412139436 ], [ -79.568781093672499, 9.22390757877173 ], [ -79.573716192648135, 9.218249010283557 ], [ -79.58774634501782, 9.212125352003397 ], [ -79.604747890702583, 9.20713857708364 ], [ -79.622292039645913, 9.198999538997498 ], [ -79.629345873013619, 9.193573512707417 ], [ -79.635159471132681, 9.189852810558762 ], [ -79.641567349353693, 9.16261932991813 ], [ -79.669756842604215, 9.128151150555141 ], [ -79.687921109171839, 9.115981350159188 ], [ -79.704741786803993, 9.110012722409181 ], [ -79.756237352072105, 9.10923757605326 ], [ -79.778225673575946, 9.114353543081563 ], [ -79.789542813250193, 9.126239121738081 ], [ -79.808559739640259, 9.158123481413497 ], [ -79.819050056115202, 9.167890326577322 ], [ -79.830005458784854, 9.173238836702922 ], [ -79.857988247359685, 9.179284979718034 ], [ -79.889252489410865, 9.193961086335037 ], [ -79.905943976733113, 9.190627956914682 ], [ -79.920671760193557, 9.175176703042382 ], [ -79.962684699339377, 9.083476873758684 ], [ -79.9573361883144, 9.066165268812085 ], [ -79.948990444653305, 9.050739854260826 ], [ -79.945502284702684, 9.039086818701719 ], [ -79.945192227239488, 9.023738918516244 ], [ -79.95061825173093, 9.007977607180806 ], [ -79.955940925233506, 8.996970526768393 ], [ -79.985396491255074, 8.977798569848119 ], [ -80.022241787428527, 8.966171372710676 ], [ -80.050172899159975, 8.96834178304681 ], [ -80.0926509262992, 8.983689683232285 ], [ -80.137454393405505, 8.949247341391697 ], [ -80.149779221633764, 8.954518337151512 ], [ -80.157479011047485, 8.959479275448189 ], [ -80.164248622675757, 8.965706284717271 ], [ -80.170501472165199, 8.976325792401383 ], [ -80.177322760636855, 9.010845649507132 ], [ -80.178227098202001, 9.021801052176784 ], [ -80.192231411250589, 9.047484239206256 ], [ -80.202385830042033, 9.02730459193333 ], [ -80.207605149857784, 8.998443305114449 ], [ -80.214581467960386, 8.985782579202635 ], [ -80.222074550899777, 8.978418687472413 ], [ -80.232823248893794, 8.973302721343487 ], [ -80.246517503579923, 8.9635358752804 ], [ -80.325530769429463, 8.888811754159121 ], [ -80.341731330336586, 8.876564439397328 ], [ -80.355477260966779, 8.871887721940823 ], [ -80.364753180614798, 8.874678249901308 ], [ -80.389687058810694, 8.878347276105899 ], [ -80.411442837217123, 8.884625963117685 ], [ -80.424516975178221, 8.892687485938723 ], [ -80.51564836278169, 8.926587226319441 ], [ -80.523942429599458, 8.924881903976654 ], [ -80.530970425444764, 8.916975408987923 ], [ -80.542184211432186, 8.880595200807875 ], [ -80.543424444882191, 8.870802517222387 ], [ -80.541409064176946, 8.866461697449381 ], [ -80.537920905125645, 8.861268215155974 ], [ -80.534691127593476, 8.852431545079753 ], [ -80.532675746888174, 8.821167303927893 ], [ -80.535853847577016, 8.80587107968654 ], [ -80.542468431372981, 8.790962429072806 ], [ -80.555077481340675, 8.781583157536659 ], [ -80.569391852751778, 8.774606838534737 ], [ -80.586135016917467, 8.769723416402542 ], [ -80.600811122635207, 8.769335841875602 ], [ -80.612024908622629, 8.770266017862411 ], [ -80.630421719186984, 8.773909207443978 ], [ -80.640188565250071, 8.772126369836087 ], [ -80.651686571178288, 8.767010402807841 ], [ -80.666982795419642, 8.752334296190782 ], [ -80.677498949416986, 8.738304144720473 ], [ -80.685327928241293, 8.715101427289028 ], [ -80.69491390715109, 8.693759060032562 ], [ -80.696102464657031, 8.675439764733369 ], [ -80.694836391885985, 8.66326996523668 ], [ -80.692588467184009, 8.652004503305193 ], [ -80.694991420617555, 8.641772569248644 ], [ -80.705688442667508, 8.629912828114527 ], [ -80.715791184615455, 8.613841458416573 ], [ -80.73940731499556, 8.615236721497467 ], [ -80.723904385179196, 8.64611338992097 ], [ -80.725790574675273, 8.653038031180188 ], [ -80.727935146589743, 8.658619086201838 ], [ -80.733361171980505, 8.66443268522022 ], [ -80.738115403802851, 8.672494208041257 ], [ -80.741965298060052, 8.690813503340507 ], [ -80.73863216774032, 8.70282827410557 ], [ -80.732921923308083, 8.714868883292297 ], [ -80.728193529008138, 8.730139268212668 ], [ -80.733542040033115, 8.74458283083294 ], [ -80.740440842870612, 8.755744940876298 ], [ -80.761524827708627, 8.779490261566309 ], [ -80.769017909748698, 8.784063626235366 ], [ -80.78025753415784, 8.788895372423497 ], [ -80.797827520623571, 8.794553940911612 ], [ -80.815087449626105, 8.802615465531289 ], [ -80.833432583347019, 8.814552721031248 ], [ -80.840693122289736, 8.820857245565435 ], [ -80.851183437865359, 8.832716986699552 ], [ -80.856842007252794, 8.844111639840321 ], [ -80.860330166304095, 8.853594265063293 ], [ -80.861725430284366, 8.874161485064462 ], [ -80.861983811803441, 8.876900336181563 ], [ -80.862597200663629, 8.885066039578389 ], [ -80.844856945999936, 8.884479757000065 ], [ -80.822417772999927, 8.890692450000074 ], [ -80.812899456999901, 8.902669580000065 ], [ -80.804292363999934, 8.912369333000072 ], [ -80.783558722999942, 8.939195054000038 ], [ -80.772572394999941, 8.95343659100007 ], [ -80.762521938999896, 8.959540106000077 ], [ -80.759144660999937, 8.962713934000078 ], [ -80.755848761999914, 8.969794012000079 ], [ -80.75064042899993, 8.97687409100007 ], [ -80.741688605999911, 8.980047919000071 ], [ -80.726826289999906, 8.997221549000074 ], [ -80.703484622999952, 9.008107912000071 ], [ -80.667103644999941, 9.029730536000045 ], [ -80.653228318999936, 9.035305080000057 ], [ -80.637117868999951, 9.051671743000043 ], [ -80.57933726999994, 9.08068731700007 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-NB", "NAME_1": "Ngöbe Buglé" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -82.006746764256462, 8.946581223250567 ], [ -81.997710740999935, 8.947455145000049 ], [ -81.985218878999945, 8.942328192000048 ], [ -81.974720831999946, 8.935207424000055 ], [ -81.958566860999952, 8.931626695000091 ], [ -81.943959113999938, 8.935126044000071 ], [ -81.929432745999918, 8.943833726000037 ], [ -81.920765753999945, 8.955145575000074 ], [ -81.923736131999931, 8.966376044000071 ], [ -81.912464972999942, 8.971096096000053 ], [ -81.903716600999928, 8.971136786000045 ], [ -81.889637824999909, 8.966376044000071 ], [ -81.887684699999909, 8.962591864000046 ], [ -81.878041144999941, 8.954250393000052 ], [ -81.867339647999927, 8.949286200000074 ], [ -81.862375454999949, 8.95579661700009 ], [ -81.852284308999913, 8.958319403000075 ], [ -81.793446417999917, 8.931626695000091 ], [ -81.775542772999927, 8.940252997000073 ], [ -81.770578579999949, 8.957464911000045 ], [ -81.774240688999896, 8.997463283000059 ], [ -81.841867641999897, 9.035305080000057 ], [ -81.877064581999946, 9.087307033000059 ], [ -81.886219855999911, 9.096136786000045 ], [ -81.899281378999945, 9.10187409100007 ], [ -81.917836066999939, 9.114976304000038 ], [ -81.933420376999948, 9.12921784100007 ], [ -81.937408006999931, 9.138332424000055 ], [ -81.922027147999927, 9.13812897300005 ], [ -81.896636522999927, 9.131781317000048 ], [ -81.872873501999948, 9.12954336100006 ], [ -81.862375454999949, 9.141750393000052 ], [ -81.89476477799991, 9.156927802000041 ], [ -81.910308397999927, 9.168117580000057 ], [ -81.903309699999909, 9.179266669000071 ], [ -81.882801886999914, 9.179510809000078 ], [ -81.86546790299991, 9.16665273600006 ], [ -81.841867641999897, 9.138332424000055 ], [ -81.818755662999934, 9.121079820000091 ], [ -81.814564581999946, 9.116603908000059 ], [ -81.816029425999943, 9.10805898600006 ], [ -81.824208136999914, 9.105454820000091 ], [ -81.834380662999934, 9.107001044000071 ], [ -81.841867641999897, 9.110419012000079 ], [ -81.841867641999897, 9.103583075000074 ], [ -81.833729620999918, 9.093817450000074 ], [ -81.825831389999905, 9.085286054000051 ], [ -81.820880853999938, 9.070647428000086 ], [ -81.813465567999913, 9.06780531000004 ], [ -81.800285577999944, 9.067811131000042 ], [ -81.776807034999933, 9.064972420000061 ], [ -81.761971321999908, 9.063750226000082 ], [ -81.736887173999946, 9.036932684000078 ], [ -81.721171869999921, 9.03202187100004 ], [ -81.706450975999928, 8.999172268000052 ], [ -81.701568162999934, 8.994330145000049 ], [ -81.687489386999914, 8.984198309000078 ], [ -81.627552863999938, 8.899115302000041 ], [ -81.587310350999928, 8.856350002000056 ], [ -81.567494269999941, 8.843491929000038 ], [ -81.561594204999949, 8.834377346000053 ], [ -81.550770636999914, 8.822821356000077 ], [ -81.539051886999914, 8.812933661000045 ], [ -81.530262824999909, 8.808742580000057 ], [ -81.521473761999914, 8.806789455000057 ], [ -81.503292085999931, 8.800959842000054 ], [ -81.491196938999906, 8.800984727000071 ], [ -81.473474338999949, 8.806593814000053 ], [ -81.421506346999934, 8.796426828000051 ], [ -81.40943074899991, 8.800099720000048 ], [ -81.381546644999901, 8.800120439000068 ], [ -81.357980923999946, 8.785101630000042 ], [ -81.304463159999898, 8.781882361000044 ], [ -81.266224148999925, 8.789234831000044 ], [ -81.213072785999941, 8.791808601000071 ], [ -81.215941534973865, 8.788249417276745 ], [ -81.215915696552145, 8.782900906251825 ], [ -81.22273698592312, 8.757760321581543 ], [ -81.211238979994903, 8.683837185237905 ], [ -81.214520432571874, 8.62322072995272 ], [ -81.210541348004767, 8.586297919413425 ], [ -81.204546881833096, 8.565291448941196 ], [ -81.195916918231148, 8.552320665566242 ], [ -81.188320481604933, 8.544104112214995 ], [ -81.183824632200981, 8.535706691710459 ], [ -81.180258958783895, 8.526559963271666 ], [ -81.171603155860964, 8.510979519089517 ], [ -81.15607438762288, 8.495528266116594 ], [ -81.183617926625971, 8.489404608735697 ], [ -81.192041184652908, 8.489404608735697 ], [ -81.203254970640387, 8.492195135796862 ], [ -81.225139940256042, 8.500954291507355 ], [ -81.265550909846581, 8.511599635814548 ], [ -81.282345750855711, 8.52221914349866 ], [ -81.328518642621248, 8.558056749319519 ], [ -81.337484503906694, 8.560227158756334 ], [ -81.363477749298681, 8.554956162996518 ], [ -81.410529141106963, 8.558521837312924 ], [ -81.415231696085868, 8.568081976901681 ], [ -81.42122616225754, 8.571880195214817 ], [ -81.432362433879177, 8.576686102981228 ], [ -81.463161587037575, 8.583972480345665 ], [ -81.488612230070373, 8.596943263720618 ], [ -81.490317552413103, 8.555886338983328 ], [ -81.49930925212027, 8.516095486117763 ], [ -81.522511969551715, 8.460465807550975 ], [ -81.525715908662221, 8.443851833695135 ], [ -81.526671923070751, 8.429201565499852 ], [ -81.522486132029371, 8.379333808208685 ], [ -81.547833422274607, 8.385690008686936 ], [ -81.592120123644747, 8.371866562791638 ], [ -81.609793463797303, 8.347811183739111 ], [ -81.624004483320221, 8.313730577104423 ], [ -81.633616298853099, 8.297090765726239 ], [ -81.655888841197054, 8.281846218328326 ], [ -81.680486822608771, 8.277376207346094 ], [ -81.689633551946827, 8.296858221729565 ], [ -81.704619716926402, 8.294997869755889 ], [ -81.715885178857889, 8.278099676858574 ], [ -81.732059903141987, 8.262157498369845 ], [ -81.784304776344356, 8.264043686966545 ], [ -81.813372768738247, 8.287478949294041 ], [ -81.830012580116488, 8.318407294560984 ], [ -81.856496751923544, 8.326856391009642 ], [ -81.949100917873068, 8.327786566996451 ], [ -81.99713416161228, 8.339982204914804 ], [ -82.01775305935621, 8.370910549282428 ], [ -82.021499599926585, 8.401864732071715 ], [ -82.036744147324498, 8.418039456355814 ], [ -82.053383958702739, 8.44684906723063 ], [ -82.064494391902656, 8.46149933542597 ], [ -82.074002854648029, 8.467493800698321 ], [ -82.083718023867675, 8.464341539330576 ], [ -82.10025448335773, 8.458114529162174 ], [ -82.132836473224643, 8.449200343820792 ], [ -82.16399736158894, 8.448735255827387 ], [ -82.180172084973719, 8.457881985165443 ], [ -82.175262824419804, 8.482479967476479 ], [ -82.142913377650245, 8.557255764541878 ], [ -82.152757738079117, 8.568727932048432 ], [ -82.15650427864955, 8.589811916886447 ], [ -82.149011196609422, 8.61937083569552 ], [ -82.139631924173955, 8.703732612569979 ], [ -82.153222826072522, 8.762617906191394 ], [ -82.154850633150204, 8.762592067769674 ], [ -82.196165941205209, 8.771583767476898 ], [ -82.203994920928835, 8.772436428198603 ], [ -82.218076748343265, 8.770343533127516 ], [ -82.223502773734026, 8.768948269147302 ], [ -82.250865444684507, 8.772281399466976 ], [ -82.281690437163945, 8.777009792867659 ], [ -82.299777187567145, 8.782125758996585 ], [ -82.317786423604559, 8.791117458703752 ], [ -82.36114295078653, 8.807963974757627 ], [ -82.362951625916764, 8.808790797956931 ], [ -82.355251838301683, 8.827497666883801 ], [ -82.347758755362236, 8.857495836163878 ], [ -82.338379482926769, 8.889354356518311 ], [ -82.330886399987378, 8.90436635991955 ], [ -82.334632940557753, 8.92498525586484 ], [ -82.347758755362236, 8.949376531701546 ], [ -82.370263840803602, 8.968109239050136 ], [ -82.407755093023127, 8.981235052955299 ], [ -82.4283998282894, 8.988753974316467 ], [ -82.439639451799223, 8.99999359782629 ], [ -82.426513637894061, 9.013119411731452 ], [ -82.392768928043552, 9.026245224737295 ], [ -82.379643114138389, 9.039371039541834 ], [ -82.353391486328007, 9.061876125882463 ], [ -82.351505296831988, 9.086241563297506 ], [ -82.338379482926769, 9.112493191107887 ], [ -82.32339331704793, 9.127505195408446 ], [ -82.314014044612463, 9.12561900501305 ], [ -82.310267504042088, 9.114379381503227 ], [ -82.315874395686819, 9.099367377202668 ], [ -82.308381313646692, 9.091874294263278 ], [ -82.287762416802082, 9.08438121222315 ], [ -82.280269334761954, 9.080608832331734 ], [ -82.289648607197421, 9.067483018426572 ], [ -82.30274858268092, 9.050610663051657 ], [ -82.317760586082159, 9.039371039541834 ], [ -82.32339331704793, 9.024359036140595 ], [ -82.321507127551854, 9.009372870261757 ], [ -82.300888230707244, 9.001879788221629 ], [ -82.280269334761954, 8.998107408330213 ], [ -82.272750414300162, 8.98686778392107 ], [ -82.26151078989102, 8.977488512384923 ], [ -82.225879889645171, 8.969995429445476 ], [ -82.201514452230185, 8.954983425144917 ], [ -82.195881721264413, 8.941883450560795 ], [ -82.199628261834789, 8.92498525586484 ], [ -82.210893723766333, 8.917492173824769 ], [ -82.209007534270256, 8.898733628953778 ], [ -82.195881721264413, 8.891240546014387 ], [ -82.192135178895398, 8.88186127447824 ], [ -82.186502447929627, 8.855609645768538 ], [ -82.179009365889499, 8.844370022258715 ], [ -82.169630092554712, 8.848116562829091 ], [ -82.16399736158894, 8.870621650069097 ], [ -82.150871547683778, 8.891240546014387 ], [ -82.132138841234507, 8.900619819349174 ], [ -82.10214067285375, 8.90248017042353 ], [ -82.06087704074281, 8.90248017042353 ], [ -82.034625413831748, 8.908112901389302 ], [ -82.015892707382534, 8.919378363320789 ], [ -82.008373786021366, 8.941857612139074 ], [ -82.006771817365461, 8.946508490274596 ], [ -82.006746764256462, 8.946581223250567 ] ] ], [ [ [ -81.568268647999901, 9.10824946200006 ], [ -81.565492825999911, 9.105496117000087 ], [ -81.559925119999946, 9.103965966000089 ], [ -81.55774703499992, 9.106106241000077 ], [ -81.553102241999909, 9.10579937600005 ], [ -81.547220925999909, 9.102740545000074 ], [ -81.541947594999897, 9.099070472000051 ], [ -81.537911337999901, 9.095094040000049 ], [ -81.53666944899993, 9.091423836000047 ], [ -81.533871900999941, 9.088669683000091 ], [ -81.53449179699993, 9.085917258000052 ], [ -81.538840968999921, 9.085920190000081 ], [ -81.543811262999952, 9.088369729000078 ], [ -81.552189354999939, 9.089596845000074 ], [ -81.56241366799992, 9.09082288400009 ], [ -81.567044062999912, 9.090822599000091 ], [ -81.571671307999907, 9.089598507000062 ], [ -81.572927660999937, 9.096020901000088 ], [ -81.575098658999934, 9.100606581000079 ], [ -81.577258588999939, 9.10458133800006 ], [ -81.575396136999927, 9.107638619000056 ], [ -81.568268647999901, 9.10824946200006 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-7", "NAME_1": "Los Santos" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -80.375509229307141, 7.997222803254876 ], [ -80.348866339999915, 7.989284572000088 ], [ -80.327748175999943, 7.953314520000049 ], [ -80.313343878999945, 7.911444403000075 ], [ -80.300038214999915, 7.883327541000085 ], [ -80.204457160999937, 7.807562567000048 ], [ -80.143788214999915, 7.752752997000073 ], [ -80.052398240999935, 7.637111721000053 ], [ -80.005767381999931, 7.55227285400008 ], [ -79.993519660999937, 7.522772528000075 ], [ -79.994658982999908, 7.50344472900008 ], [ -80.010039842999902, 7.465236721000053 ], [ -80.017852342999902, 7.456813869000086 ], [ -80.030059373999904, 7.453924872000073 ], [ -80.056792772999927, 7.452541408000059 ], [ -80.064971482999908, 7.450995184000078 ], [ -80.135528123999904, 7.424627997000073 ], [ -80.198516404999907, 7.424709377000056 ], [ -80.210682745999918, 7.417792059000078 ], [ -80.222808397999927, 7.42336660400008 ], [ -80.249663865999935, 7.429632880000042 ], [ -80.259063279999907, 7.438259182000081 ], [ -80.265899217999902, 7.438259182000081 ], [ -80.274810350999928, 7.433864651000079 ], [ -80.30687415299991, 7.424627997000073 ], [ -80.30687415299991, 7.417792059000078 ], [ -80.2939753899999, 7.419256903000075 ], [ -80.283558722999942, 7.421820380000042 ], [ -80.274525519999941, 7.425685940000051 ], [ -80.265899217999902, 7.430812893000052 ], [ -80.259063279999907, 7.424627997000073 ], [ -80.330962693999936, 7.401190497000073 ], [ -80.357574022999927, 7.382025458000044 ], [ -80.361480272999927, 7.355739651000079 ], [ -80.34439042899993, 7.327419338000084 ], [ -80.347564256999931, 7.318264065000051 ], [ -80.372344529999907, 7.31476471600007 ], [ -80.379261847999942, 7.312770901000079 ], [ -80.387115037999934, 7.30805084800005 ], [ -80.3935847649999, 7.302394924000055 ], [ -80.396270311999899, 7.297674872000073 ], [ -80.398833787999934, 7.28664785400008 ], [ -80.405384894999941, 7.282782294000071 ], [ -80.414418097999942, 7.280340887000079 ], [ -80.424183722999942, 7.27374909100007 ], [ -80.428496873999904, 7.265448309000078 ], [ -80.428130662999934, 7.258490302000041 ], [ -80.429107225999928, 7.252346096000053 ], [ -80.437245245999918, 7.246486721000053 ], [ -80.444813605999911, 7.245876369000086 ], [ -80.463734503999945, 7.251654364000046 ], [ -80.474476691999939, 7.253322658000059 ], [ -80.596831834999932, 7.238063869000086 ], [ -80.6040750717072, 7.236721022557106 ], [ -80.606779751284478, 7.271830349291179 ], [ -80.613290982292995, 7.285808823918103 ], [ -80.623497077028446, 7.297203477058815 ], [ -80.644245165082282, 7.312577216565273 ], [ -80.653366055099355, 7.318003241056715 ], [ -80.668068000138078, 7.322809149722445 ], [ -80.668765632128213, 7.327304999126397 ], [ -80.666595221792022, 7.337795314702021 ], [ -80.667137824151268, 7.352523098162465 ], [ -80.673468187107119, 7.37595836048996 ], [ -80.699254726924096, 7.410710760693064 ], [ -80.715067715102975, 7.458899034063165 ], [ -80.722069871627241, 7.50173879640829 ], [ -80.719692755716096, 7.529592392874633 ], [ -80.664605678609178, 7.583180854113095 ], [ -80.613936937439689, 7.663098455729141 ], [ -80.608097499999587, 7.668240261179108 ], [ -80.59528174535626, 7.669687201103443 ], [ -80.588150396723393, 7.672503567485649 ], [ -80.579882168327401, 7.678937283229004 ], [ -80.567350632725493, 7.690797024363178 ], [ -80.556782802784085, 7.708883774766377 ], [ -80.552855394161099, 7.722061265514981 ], [ -80.553113775680174, 7.733559272342518 ], [ -80.554276495663714, 7.741155707170151 ], [ -80.557583787561725, 7.748907172527993 ], [ -80.570528734313598, 7.766063747843702 ], [ -80.5732934229531, 7.773505153939709 ], [ -80.574817878142539, 7.782496852747556 ], [ -80.574507818880704, 7.789654038902768 ], [ -80.575386318923449, 7.805311998350021 ], [ -80.579959682693186, 7.811306464521692 ], [ -80.578771125187245, 7.815259711566398 ], [ -80.573784349368225, 7.82146088331308 ], [ -80.560658534563686, 7.829522406134117 ], [ -80.546240811264397, 7.84133047132417 ], [ -80.534536098861849, 7.855825709888563 ], [ -80.504202032797537, 7.911222846257317 ], [ -80.49141211567661, 7.92341848417567 ], [ -80.459010992962931, 7.932565211715144 ], [ -80.427514207814397, 7.931247462999977 ], [ -80.414750129115134, 7.933960475695358 ], [ -80.404466519114578, 7.941866969784826 ], [ -80.393071865973809, 7.956930650029449 ], [ -80.388679369357419, 7.975224106906978 ], [ -80.381961432773892, 7.983466497780626 ], [ -80.375509229307141, 7.997222803254876 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PA-6", "NAME_1": "Herrera" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -80.478464321999923, 8.091376044000071 ], [ -80.484405076999906, 8.082546291000085 ], [ -80.468169725999928, 8.07485586100006 ], [ -80.460926886999914, 8.055731512000079 ], [ -80.4560847649999, 8.036200262000079 ], [ -80.447173631999931, 8.027289130000042 ], [ -80.432403123999904, 8.024237372000073 ], [ -80.394276495999918, 8.007635809000078 ], [ -80.382598436999899, 7.999335028000075 ], [ -80.375509229307141, 7.997222803254876 ], [ -80.381961432773892, 7.983466497780626 ], [ -80.388679369357419, 7.975224106906978 ], [ -80.393071865973809, 7.956930650029449 ], [ -80.404466519114578, 7.941866969784826 ], [ -80.414750129115134, 7.933960475695358 ], [ -80.427514207814397, 7.931247462999977 ], [ -80.459010992962931, 7.932565211715144 ], [ -80.49141211567661, 7.92341848417567 ], [ -80.504202032797537, 7.911222846257317 ], [ -80.534536098861849, 7.855825709888563 ], [ -80.546240811264397, 7.84133047132417 ], [ -80.560658534563686, 7.829522406134117 ], [ -80.573784349368225, 7.82146088331308 ], [ -80.578771125187245, 7.815259711566398 ], [ -80.579959682693186, 7.811306464521692 ], [ -80.575386318923449, 7.805311998350021 ], [ -80.574507818880704, 7.789654038902768 ], [ -80.574817878142539, 7.782496852747556 ], [ -80.5732934229531, 7.773505153939709 ], [ -80.570528734313598, 7.766063747843702 ], [ -80.557583787561725, 7.748907172527993 ], [ -80.554276495663714, 7.741155707170151 ], [ -80.553113775680174, 7.733559272342518 ], [ -80.552855394161099, 7.722061265514981 ], [ -80.556782802784085, 7.708883774766377 ], [ -80.567350632725493, 7.690797024363178 ], [ -80.579882168327401, 7.678937283229004 ], [ -80.588150396723393, 7.672503567485649 ], [ -80.59528174535626, 7.669687201103443 ], [ -80.608097499999587, 7.668240261179108 ], [ -80.613936937439689, 7.663098455729141 ], [ -80.664605678609178, 7.583180854113095 ], [ -80.719692755716096, 7.529592392874633 ], [ -80.745737677951468, 7.55574066789751 ], [ -80.751861335332364, 7.559228826948811 ], [ -80.772299364124365, 7.563647161986921 ], [ -80.802064989407711, 7.58116547340785 ], [ -80.879217902384255, 7.695318712188794 ], [ -80.884928147715812, 7.708651230769647 ], [ -80.891671922721059, 7.737435004122119 ], [ -80.897563036105225, 7.753247992300999 ], [ -80.904771898204501, 7.76327321988316 ], [ -80.909474453183464, 7.767691554921328 ], [ -80.919499680765625, 7.771799832496242 ], [ -80.942754075939831, 7.765831203846972 ], [ -80.946991542925332, 7.788413805452763 ], [ -80.943425868608927, 7.90145600019423 ], [ -80.93774146169909, 7.911067817525748 ], [ -80.93290971461164, 7.915408637298754 ], [ -80.907407395634777, 7.92186819146383 ], [ -80.886349250117803, 7.944347439382796 ], [ -80.857772183239661, 7.969565538418863 ], [ -80.849943202616714, 7.980831000350349 ], [ -80.839194506421336, 8.00036469247658 ], [ -80.837980108695035, 8.015893459815288 ], [ -80.853560553776504, 8.059947618088074 ], [ -80.817025315965566, 8.073616034352483 ], [ -80.780955166147976, 8.087956244185307 ], [ -80.764702928397412, 8.102554836436525 ], [ -80.742042813325156, 8.129788316177837 ], [ -80.732379320049574, 8.133353990494243 ], [ -80.71876257972923, 8.132966416866623 ], [ -80.709745043399039, 8.130718492164647 ], [ -80.687007412162302, 8.132604682560043 ], [ -80.662745326635502, 8.12405223242456 ], [ -80.646415575418473, 8.125292466773885 ], [ -80.609725307976589, 8.137307237538948 ], [ -80.59122514462473, 8.13854747188833 ], [ -80.57732418526291, 8.132811388135053 ], [ -80.558488125126871, 8.112838446437138 ], [ -80.549470587897304, 8.106120509853611 ], [ -80.543553636091417, 8.106740627477961 ], [ -80.532184821372368, 8.115344753557508 ], [ -80.526448736719829, 8.11637828233188 ], [ -80.514563158063254, 8.110513007369377 ], [ -80.491437954098274, 8.095190944706303 ], [ -80.478464321999923, 8.091376044000071 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/papua new guinea.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/papua new guinea.geojson new file mode 100644 index 0000000000000..ef69aa98e70c5 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/papua new guinea.geojson @@ -0,0 +1,28 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "PG-NSB", "NAME_1": "Bougainville" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 155.832229614257812, -6.803332805633488 ], [ 155.835632324219091, -6.80604887008667 ], [ 155.834442138671875, -6.808332920074463 ], [ 155.830551147461165, -6.805276870727482 ], [ 155.832229614257812, -6.803332805633488 ] ] ], [ [ [ 155.828048706054688, -6.803888797759896 ], [ 155.824447631836165, -6.803332805633488 ], [ 155.824172973632926, -6.798056125640812 ], [ 155.828018188476562, -6.800387859344482 ], [ 155.828048706054688, -6.803888797759896 ] ] ], [ [ [ 155.978485107421989, -6.681222915649357 ], [ 155.983078002929688, -6.683187961578369 ], [ 155.973190307617188, -6.683783054351807 ], [ 155.975753784180142, -6.680797100067139 ], [ 155.978485107421989, -6.681222915649357 ] ] ], [ [ [ 155.973327636718864, -6.462777137756348 ], [ 155.970550537109602, -6.458333015441838 ], [ 155.97059631347679, -6.455799102783146 ], [ 155.974441528320312, -6.459444999694824 ], [ 155.973327636718864, -6.462777137756348 ] ] ], [ [ [ 155.850860595703239, -6.304103851318246 ], [ 155.849304199218864, -6.303813934326115 ], [ 155.847946166992415, -6.302528858184814 ], [ 155.850875854492301, -6.302317142486515 ], [ 155.850860595703239, -6.304103851318246 ] ] ], [ [ [ 155.826080322265739, -6.303907871246338 ], [ 155.826126098632812, -6.300658226013184 ], [ 155.829849243164176, -6.300699234008732 ], [ 155.829040527343864, -6.302470207214355 ], [ 155.826080322265739, -6.303907871246338 ] ] ], [ [ [ 155.840560913086051, -6.29999923706049 ], [ 155.836944580078239, -6.300833225250244 ], [ 155.833053588867415, -6.295555114746094 ], [ 155.835556030273665, -6.294167041778508 ], [ 155.840560913086051, -6.29999923706049 ] ] ], [ [ [ 155.122665405273779, -6.282333850860596 ], [ 155.123794555664176, -6.284900188445988 ], [ 155.120925903320426, -6.284873008728027 ], [ 155.120407104492188, -6.283178806304875 ], [ 155.122665405273779, -6.282333850860596 ] ] ], [ [ [ 155.121002197265625, -6.280416965484505 ], [ 155.121810913086165, -6.282083034515324 ], [ 155.119018554687614, -6.283497810363713 ], [ 155.118148803711165, -6.281528949737549 ], [ 155.121002197265625, -6.280416965484505 ] ] ], [ [ [ 155.705307006836051, -6.248538970947266 ], [ 155.706146240234375, -6.249424934387207 ], [ 155.705886840820312, -6.25002908706665 ], [ 155.704406738281591, -6.249456882476807 ], [ 155.705307006836051, -6.248538970947266 ] ] ], [ [ [ 155.030090332031705, -6.247611045837346 ], [ 155.026672363281364, -6.243054866790771 ], [ 155.02780151367233, -6.241722106933537 ], [ 155.031417846679915, -6.243780136108342 ], [ 155.030090332031705, -6.247611045837346 ] ] ], [ [ [ 155.66094970703125, -6.185554981231633 ], [ 155.67610168457054, -6.20822095870966 ], [ 155.66302490234375, -6.217484951019287 ], [ 155.647949218750341, -6.197558879852238 ], [ 155.66094970703125, -6.185554981231633 ] ] ], [ [ [ 155.676177978515966, -6.185339927673283 ], [ 155.666213989257812, -6.185338020324707 ], [ 155.667083740234602, -6.178548812866154 ], [ 155.67359924316429, -6.17946004867548 ], [ 155.676177978515966, -6.185339927673283 ] ] ], [ [ [ 155.634048461914062, -6.16484880447382 ], [ 155.632354736328125, -6.165112972259521 ], [ 155.629852294921875, -6.162644863128662 ], [ 155.635040283203352, -6.16192722320551 ], [ 155.634048461914062, -6.16484880447382 ] ] ], [ [ [ 155.57073974609375, -6.146265029907227 ], [ 155.56842041015625, -6.144521236419678 ], [ 155.568542480468864, -6.141465187072754 ], [ 155.56951904296875, -6.141465187072754 ], [ 155.57073974609375, -6.146265029907227 ] ] ], [ [ [ 155.575531005859602, -6.118831157684326 ], [ 155.572784423828239, -6.117499828338623 ], [ 155.573303222656705, -6.116157054901123 ], [ 155.575271606445426, -6.117499828338623 ], [ 155.575531005859602, -6.118831157684326 ] ] ], [ [ [ 155.520492553710938, -6.069722175598145 ], [ 155.523895263672102, -6.071665763854924 ], [ 155.523895263672102, -6.074789047241154 ], [ 155.52082824707054, -6.072778224944955 ], [ 155.520492553710938, -6.069722175598145 ] ] ], [ [ [ 155.511383056640966, -6.06333398818964 ], [ 155.508285522460938, -6.061902046203613 ], [ 155.508895874023551, -6.05805492401123 ], [ 155.510284423828125, -6.058888912200928 ], [ 155.511383056640966, -6.06333398818964 ] ] ], [ [ [ 155.280761718750114, -5.888261795043945 ], [ 155.280487060546989, -5.88951301574707 ], [ 155.279235839843864, -5.88861083984375 ], [ 155.279510498047102, -5.887497901916504 ], [ 155.280761718750114, -5.888261795043945 ] ] ], [ [ [ 154.605560302734489, -5.733611106872559 ], [ 154.601669311523665, -5.731389045715332 ], [ 154.604721069336165, -5.728332996368408 ], [ 154.607223510742415, -5.730833053588867 ], [ 154.605560302734489, -5.733611106872559 ] ] ], [ [ [ 154.5689697265625, -5.729403972625676 ], [ 154.567794799804801, -5.729125976562443 ], [ 154.566955566406477, -5.727250099182015 ], [ 154.567718505859602, -5.7271790504455 ], [ 154.5689697265625, -5.729403972625676 ] ] ], [ [ [ 154.644729614257812, -5.707499027252197 ], [ 154.647216796875, -5.710277080535889 ], [ 154.643051147461051, -5.713334083557129 ], [ 154.641387939453239, -5.709444999694767 ], [ 154.644729614257812, -5.707499027252197 ] ] ], [ [ [ 155.136108398437727, -5.69277811050415 ], [ 155.136947631836051, -5.694166183471623 ], [ 155.13478088378929, -5.695116996765137 ], [ 155.134399414062727, -5.694006919860783 ], [ 155.136108398437727, -5.69277811050415 ] ] ], [ [ [ 154.627777099609602, -5.608890056610107 ], [ 154.625488281250227, -5.607048034667912 ], [ 154.625976562500114, -5.605694770812988 ], [ 154.6282958984375, -5.606736183166504 ], [ 154.627777099609602, -5.608890056610107 ] ] ], [ [ [ 154.65888977050804, -5.60055494308466 ], [ 154.660003662109602, -5.603889942169189 ], [ 154.65583801269554, -5.604443073272705 ], [ 154.655548095703239, -5.602499008178654 ], [ 154.65888977050804, -5.60055494308466 ] ] ], [ [ [ 154.714172363281477, -5.593332767486572 ], [ 154.710830688476562, -5.599722862243652 ], [ 154.703887939453239, -5.593889236450195 ], [ 154.705276489257926, -5.591389179229736 ], [ 154.714172363281477, -5.593332767486572 ] ] ], [ [ [ 154.695831298828125, -5.593057155609074 ], [ 154.692504882812614, -5.589444160461312 ], [ 154.694442749023551, -5.58611011505127 ], [ 154.698608398437614, -5.589444160461312 ], [ 154.695831298828125, -5.593057155609074 ] ] ], [ [ [ 154.711914062500227, -5.585903167724609 ], [ 154.710830688476562, -5.583611965179387 ], [ 154.711669921875, -5.582499980926514 ], [ 154.712783813476562, -5.583333969116154 ], [ 154.711914062500227, -5.585903167724609 ] ] ], [ [ [ 154.639999389648551, -5.573610782623291 ], [ 154.642501831054915, -5.577498912811279 ], [ 154.6361083984375, -5.57916784286499 ], [ 154.63555908203125, -5.575832843780518 ], [ 154.639999389648551, -5.573610782623291 ] ] ], [ [ [ 154.708328247070426, -5.571945190429631 ], [ 154.706390380859602, -5.57916784286499 ], [ 154.701660156250114, -5.577220916748047 ], [ 154.70582580566429, -5.572501182556096 ], [ 154.708328247070426, -5.571945190429631 ] ] ], [ [ [ 154.703887939453239, -5.569723129272404 ], [ 154.705276489257926, -5.570833206176758 ], [ 154.704162597656364, -5.572501182556096 ], [ 154.702499389648438, -5.571111202239933 ], [ 154.703887939453239, -5.569723129272404 ] ] ], [ [ [ 155.074172973632812, -5.58027791976923 ], [ 155.0736083984375, -5.575276851654053 ], [ 155.083953857421875, -5.565625190734863 ], [ 155.082229614258154, -5.573332786560059 ], [ 155.074172973632812, -5.58027791976923 ] ] ], [ [ [ 154.71498107910179, -5.562897205352726 ], [ 154.714096069336051, -5.562082767486515 ], [ 154.714447021484375, -5.56006908416748 ], [ 154.715484619140625, -5.560833930969125 ], [ 154.71498107910179, -5.562897205352726 ] ] ], [ [ [ 154.711395263671875, -5.560833930969125 ], [ 154.710281372070426, -5.559721946716252 ], [ 154.710830688476562, -5.558333873748779 ], [ 154.712493896484602, -5.559443950653019 ], [ 154.711395263671875, -5.560833930969125 ] ] ], [ [ [ 154.654037475585938, -5.557012081146183 ], [ 154.653060913086051, -5.555760860443058 ], [ 154.65486145019554, -5.554510116577148 ], [ 154.655136108398438, -5.555482864379826 ], [ 154.654037475585938, -5.557012081146183 ] ] ], [ [ [ 154.5977783203125, -5.554443836212158 ], [ 154.600006103515625, -5.557221889495736 ], [ 154.599166870117415, -5.559165954589787 ], [ 154.59722900390625, -5.556111812591553 ], [ 154.5977783203125, -5.554443836212158 ] ] ], [ [ [ 154.704162597656364, -5.553890228271484 ], [ 154.709716796875114, -5.555277824401855 ], [ 154.705551147460938, -5.560833930969125 ], [ 154.701385498046875, -5.549720764160099 ], [ 154.704162597656364, -5.553890228271484 ] ] ], [ [ [ 154.643920898437841, -5.546597003936711 ], [ 154.649169921875227, -5.548055171966496 ], [ 154.649902343750227, -5.550209045410099 ], [ 154.647781372070312, -5.551390171051025 ], [ 154.643920898437841, -5.546597003936711 ] ] ], [ [ [ 154.611389160156364, -5.546111106872559 ], [ 154.613052368164062, -5.547777175903263 ], [ 154.611663818359489, -5.549720764160099 ], [ 154.610275268554915, -5.548055171966496 ], [ 154.611389160156364, -5.546111106872559 ] ] ], [ [ [ 154.700836181640739, -5.545833110809326 ], [ 154.702224731445426, -5.546945095062256 ], [ 154.700271606445426, -5.548333168029728 ], [ 154.699172973632926, -5.546945095062256 ], [ 154.700836181640739, -5.545833110809326 ] ] ], [ [ [ 154.695281982421875, -5.54999923706049 ], [ 154.692504882812614, -5.545277118682748 ], [ 154.693328857421875, -5.544167041778564 ], [ 154.695556640625114, -5.545833110809326 ], [ 154.695281982421875, -5.54999923706049 ] ] ], [ [ [ 154.736114501953352, -5.5436110496521 ], [ 154.734451293945767, -5.54222297668457 ], [ 154.735275268554801, -5.540555000305176 ], [ 154.737228393554688, -5.541944980621338 ], [ 154.736114501953352, -5.5436110496521 ] ] ], [ [ [ 154.716110229492415, -5.536109924316293 ], [ 154.7147216796875, -5.534999847412109 ], [ 154.715835571289062, -5.533333778381291 ], [ 154.716949462890739, -5.534721851348877 ], [ 154.716110229492415, -5.536109924316293 ] ] ], [ [ [ 154.640274047851676, -5.535553932189885 ], [ 154.638885498047102, -5.53388786315918 ], [ 154.641937255859602, -5.531943798065186 ], [ 154.642227172851562, -5.532777786254883 ], [ 154.640274047851676, -5.535553932189885 ] ] ], [ [ [ 154.606109619140625, -5.53388786315918 ], [ 154.604995727539176, -5.532221794128418 ], [ 154.60638427734375, -5.53083419799799 ], [ 154.607223510742415, -5.532777786254883 ], [ 154.606109619140625, -5.53388786315918 ] ] ], [ [ [ 154.70277404785179, -5.498611927032414 ], [ 154.705276489257926, -5.500833988189697 ], [ 154.705001831054688, -5.501666069030762 ], [ 154.702499389648438, -5.500833988189697 ], [ 154.70277404785179, -5.498611927032414 ] ] ], [ [ [ 154.645004272461051, -5.490554809570312 ], [ 154.67999267578125, -5.535553932189885 ], [ 154.662780761718864, -5.587222099304199 ], [ 154.657775878906705, -5.549168109893742 ], [ 154.636672973633154, -5.518610954284611 ], [ 154.645004272461051, -5.490554809570312 ] ] ], [ [ [ 154.707778930664062, -5.480834007263127 ], [ 154.709442138672102, -5.482501029968262 ], [ 154.70889282226608, -5.485001087188664 ], [ 154.705551147460938, -5.482501029968262 ], [ 154.707778930664062, -5.480834007263127 ] ] ], [ [ [ 154.693328857421875, -5.474165916442814 ], [ 154.689437866211392, -5.474721908569279 ], [ 154.686950683593977, -5.47222185134882 ], [ 154.692779541015625, -5.468332767486515 ], [ 154.693328857421875, -5.474165916442814 ] ] ], [ [ [ 154.637771606445312, -5.455554008483887 ], [ 154.640838623046989, -5.470833778381348 ], [ 154.624450683593864, -5.476943969726562 ], [ 154.628326416015625, -5.460833072662354 ], [ 154.637771606445312, -5.455554008483887 ] ] ], [ [ [ 154.672149658203466, -5.448887825012207 ], [ 154.67333984375, -5.450277805328369 ], [ 154.673614501953239, -5.451943874359131 ], [ 154.671386718750341, -5.449999809265137 ], [ 154.672149658203466, -5.448887825012207 ] ] ], [ [ [ 154.653060913086051, -5.450833797454834 ], [ 154.651672363281705, -5.448056221008301 ], [ 154.653884887695312, -5.44666576385498 ], [ 154.654998779296875, -5.448612213134766 ], [ 154.653060913086051, -5.450833797454834 ] ] ], [ [ [ 154.648605346679915, -5.44083309173584 ], [ 154.651672363281705, -5.443890094757023 ], [ 154.645828247070654, -5.445000171661377 ], [ 154.64649963378929, -5.441423892974854 ], [ 154.648605346679915, -5.44083309173584 ] ] ], [ [ [ 154.668609619140739, -5.450833797454834 ], [ 154.663055419922102, -5.443612098693791 ], [ 154.667770385742188, -5.439445018768311 ], [ 154.668884277343864, -5.444168090820256 ], [ 154.668609619140739, -5.450833797454834 ] ] ], [ [ [ 154.572784423828125, -5.431666851043644 ], [ 154.571670532226562, -5.429165840148926 ], [ 154.573608398437727, -5.424722194671574 ], [ 154.574447631835938, -5.426387786865234 ], [ 154.572784423828125, -5.431666851043644 ] ] ], [ [ [ 154.715835571289062, -5.407917976379395 ], [ 154.814010620117188, -5.506303787231388 ], [ 154.837600708007926, -5.496629238128605 ], [ 154.854171752929915, -5.527222156524601 ], [ 154.877914428710938, -5.528123855590763 ], [ 154.881942749023551, -5.547777175903263 ], [ 154.890853881836392, -5.528413772582951 ], [ 155.006668090820426, -5.533609867095947 ], [ 155.014999389648665, -5.558609962463322 ], [ 155.032119750976562, -5.53325700759882 ], [ 155.065826416015966, -5.541110992431641 ], [ 155.056945800781364, -5.566389083862191 ], [ 155.050552368164176, -5.560277938842717 ], [ 155.04583740234375, -5.561110019683838 ], [ 155.05194091796875, -5.575832843780518 ], [ 155.074310302734602, -5.583192825317383 ], [ 155.088058471679915, -5.635834217071533 ], [ 155.133056640625227, -5.706666946411076 ], [ 155.171386718750114, -5.725831985473576 ], [ 155.168334960937614, -5.794166088104248 ], [ 155.191665649414062, -5.823056221008301 ], [ 155.1925048828125, -5.855834007263127 ], [ 155.207504272460938, -5.86722278594965 ], [ 155.224136352539404, -5.85319709777832 ], [ 155.297500610352017, -5.911387920379639 ], [ 155.312774658203239, -5.948610782623234 ], [ 155.350555419921875, -5.94305515289301 ], [ 155.404449462890852, -5.988056182861214 ], [ 155.419723510742301, -6.094086170196476 ], [ 155.454727172851676, -6.146111965179387 ], [ 155.513717651367188, -6.177467823028451 ], [ 155.528335571289176, -6.17604207992548 ], [ 155.529159545898438, -6.155557155609017 ], [ 155.545013427734602, -6.188562870025578 ], [ 155.560836791992188, -6.19083309173584 ], [ 155.54833984375, -6.206943988800049 ], [ 155.583160400390852, -6.221658229827881 ], [ 155.593048095703125, -6.208056926727181 ], [ 155.624114990234375, -6.21884822845459 ], [ 155.611114501953239, -6.185554981231633 ], [ 155.628097534179801, -6.166141033172607 ], [ 155.634140014648665, -6.21688985824585 ], [ 155.659652709961165, -6.223333835601807 ], [ 155.666671752929688, -6.249999046325627 ], [ 155.710479736328239, -6.273983001708984 ], [ 155.754043579101562, -6.334819793701172 ], [ 155.819183349609375, -6.362801074981689 ], [ 155.864578247070312, -6.468948841094971 ], [ 155.924316406250114, -6.513771057128906 ], [ 155.921661376953125, -6.597498893737736 ], [ 155.965560913085938, -6.690000057220459 ], [ 155.952224731445312, -6.756389141082707 ], [ 155.915832519531477, -6.801387786865234 ], [ 155.901657104492188, -6.777536869049015 ], [ 155.921035766601562, -6.753324031829834 ], [ 155.913604736328125, -6.716944217681885 ], [ 155.875717163085938, -6.781445980071965 ], [ 155.863327026367188, -6.783332824707031 ], [ 155.85267639160179, -6.75471019744873 ], [ 155.820846557617415, -6.762929916381779 ], [ 155.73455810546875, -6.838260173797607 ], [ 155.708404541015739, -6.88042688369751 ], [ 155.654205322265625, -6.850604057311955 ], [ 155.603179931640625, -6.861822128295898 ], [ 155.522216796875, -6.839167118072453 ], [ 155.339996337890739, -6.728518009185734 ], [ 155.248886108398438, -6.634444236755371 ], [ 155.157211303710938, -6.520174980163517 ], [ 155.166671752929801, -6.511388778686523 ], [ 155.199707031250114, -6.527605056762695 ], [ 155.229995727539176, -6.443334102630615 ], [ 155.230880737304915, -6.420362949371338 ], [ 155.19610595703125, -6.394721984863281 ], [ 155.223892211914176, -6.348888874053955 ], [ 155.207687377929688, -6.308613777160645 ], [ 155.164352416992415, -6.275576114654541 ], [ 155.039718627929688, -6.248120784759521 ], [ 155.02491760253929, -6.222308158874512 ], [ 154.9697265625, -6.196668148040771 ], [ 154.966949462890852, -6.132777214050236 ], [ 154.947021484375, -6.09833383560175 ], [ 154.815826416015625, -6.022500991821232 ], [ 154.802505493164176, -5.984722137451172 ], [ 154.74110412597679, -5.934999942779541 ], [ 154.730834960937614, -5.888332843780518 ], [ 154.74749755859375, -5.848889827728271 ], [ 154.695007324218864, -5.744999885559082 ], [ 154.717498779296875, -5.707221031188965 ], [ 154.71368408203125, -5.645321846008244 ], [ 154.73805236816429, -5.601110935211125 ], [ 154.718887329101562, -5.563610076904297 ], [ 154.73638916015625, -5.560555934905949 ], [ 154.751388549804801, -5.584166049957275 ], [ 154.755004882812614, -5.547221183776799 ], [ 154.773056030273438, -5.546111106872559 ], [ 154.754714965820426, -5.537222862243596 ], [ 154.7469482421875, -5.497499942779541 ], [ 154.727783203125114, -5.496665000915471 ], [ 154.701950073242188, -5.457778930664006 ], [ 154.67083740234375, -5.441668033599854 ], [ 154.715835571289062, -5.407917976379395 ] ] ], [ [ [ 154.578887939453125, -5.384167194366398 ], [ 154.577499389648438, -5.392499923705998 ], [ 154.573883056640625, -5.394999980926514 ], [ 154.571945190430142, -5.384723186492863 ], [ 154.578887939453125, -5.384167194366398 ] ] ], [ [ [ 154.563613891601676, -5.341666221618652 ], [ 154.564727783203125, -5.354444980621338 ], [ 154.552505493164176, -5.320831775665283 ], [ 154.555831909179688, -5.323888778686523 ], [ 154.563613891601676, -5.341666221618652 ] ] ], [ [ [ 154.538604736328239, -5.29777717590332 ], [ 154.549728393554688, -5.304722785949707 ], [ 154.55055236816429, -5.309999942779541 ], [ 154.533340454101562, -5.304998874664193 ], [ 154.538604736328239, -5.29777717590332 ] ] ], [ [ [ 154.559997558594091, -5.29423713684082 ], [ 154.558471679687841, -5.2933349609375 ], [ 154.559722900390852, -5.291875839233398 ], [ 154.560562133789176, -5.293056964874268 ], [ 154.559997558594091, -5.29423713684082 ] ] ], [ [ [ 154.5594482421875, -5.291388034820557 ], [ 154.558334350585938, -5.291110038757324 ], [ 154.558609008789176, -5.289721965789795 ], [ 154.559722900390852, -5.289721965789795 ], [ 154.5594482421875, -5.291388034820557 ] ] ], [ [ [ 154.557495117187614, -5.283889770507812 ], [ 154.556945800781591, -5.287499904632512 ], [ 154.553680419921989, -5.285347938537598 ], [ 154.555831909179688, -5.28055477142334 ], [ 154.557495117187614, -5.283889770507812 ] ] ], [ [ [ 154.520828247070767, -5.194167137145939 ], [ 154.528335571289404, -5.19999885559082 ], [ 154.533050537109489, -5.21083402633667 ], [ 154.515548706054801, -5.206943988800049 ], [ 154.520828247070767, -5.194167137145939 ] ] ], [ [ [ 154.542221069335938, -5.171111106872502 ], [ 154.542221069335938, -5.175556182861328 ], [ 154.537216186523665, -5.173890113830566 ], [ 154.538330078125114, -5.171946048736515 ], [ 154.542221069335938, -5.171111106872502 ] ] ], [ [ [ 154.512466430664062, -5.166909217834473 ], [ 154.516113281250114, -5.169999122619572 ], [ 154.515655517578352, -5.174343109130859 ], [ 154.50917053222679, -5.166388988494873 ], [ 154.512466430664062, -5.166909217834473 ] ] ], [ [ [ 154.562774658203352, -5.151944160461426 ], [ 154.560760498047216, -5.151526927947998 ], [ 154.560836791992301, -5.15055608749384 ], [ 154.562774658203352, -5.150000095367375 ], [ 154.562774658203352, -5.151944160461426 ] ] ], [ [ [ 154.55055236816429, -5.123333930969238 ], [ 154.55194091796875, -5.125833988189697 ], [ 154.548339843750114, -5.128056049346924 ], [ 154.547775268554801, -5.125555992126465 ], [ 154.55055236816429, -5.123333930969238 ] ] ], [ [ [ 154.555557250976676, -5.122777938842773 ], [ 154.55360412597679, -5.121111869811955 ], [ 154.555831909179688, -5.119442939758244 ], [ 154.556671142578352, -5.122221946716309 ], [ 154.555557250976676, -5.122777938842773 ] ] ], [ [ [ 154.557785034179801, -5.112223148345947 ], [ 154.559997558594091, -5.114445209503174 ], [ 154.557785034179801, -5.118332862854004 ], [ 154.55610656738304, -5.114445209503174 ], [ 154.557785034179801, -5.112223148345947 ] ] ], [ [ [ 154.562225341796989, -5.106388092041016 ], [ 154.560531616210938, -5.10579776763916 ], [ 154.561737060546875, -5.104410171508732 ], [ 154.562225341796989, -5.104444026947021 ], [ 154.562225341796989, -5.106388092041016 ] ] ], [ [ [ 154.6219482421875, -5.002707958221322 ], [ 154.649032592773438, -5.015666961669865 ], [ 154.678924560547102, -5.085564136505127 ], [ 154.674072265625, -5.155706882476807 ], [ 154.712692260742415, -5.1843581199646 ], [ 154.681106567382926, -5.420759201049748 ], [ 154.654159545898551, -5.443890094757023 ], [ 154.648330688476562, -5.408332824707031 ], [ 154.618331909179801, -5.461111068725586 ], [ 154.598617553711165, -5.412981986999512 ], [ 154.613891601562727, -5.428331851959229 ], [ 154.615829467773551, -5.418056011199951 ], [ 154.577774047851562, -5.3561110496521 ], [ 154.555282592773438, -5.271944999694824 ], [ 154.550827026367301, -5.219723224639893 ], [ 154.571945190430142, -5.205555915832463 ], [ 154.556396484375, -5.136944770812988 ], [ 154.570281982421989, -5.109167098998967 ], [ 154.554443359375114, -5.09833383560175 ], [ 154.515838623047102, -5.124444007873535 ], [ 154.551116943359489, -5.065555095672494 ], [ 154.6219482421875, -5.002707958221322 ] ] ], [ [ [ 155.467224121093977, -4.815001010894662 ], [ 155.469955444335938, -4.817523956298828 ], [ 155.463333129882812, -4.817777156829834 ], [ 155.466110229492642, -4.813333034515324 ], [ 155.467224121093977, -4.815001010894662 ] ] ], [ [ [ 155.471084594726676, -4.777369976043701 ], [ 155.470840454101676, -4.781109809875375 ], [ 155.464447021484489, -4.786388874053955 ], [ 155.462493896484489, -4.77861213684082 ], [ 155.471084594726676, -4.777369976043701 ] ] ], [ [ [ 157.033340454101676, -4.767222881317082 ], [ 157.037506103515625, -4.775834083557072 ], [ 157.024444580078125, -4.780831813812199 ], [ 157.032226562500227, -4.76444482803339 ], [ 157.033340454101676, -4.767222881317082 ] ] ], [ [ [ 157.036972045898665, -4.765114784240723 ], [ 157.035034179687727, -4.764907836914062 ], [ 157.034820556640625, -4.76462984085083 ], [ 157.037506103515625, -4.763446807861328 ], [ 157.036972045898665, -4.765114784240723 ] ] ], [ [ [ 157.035293579101676, -4.756967067718449 ], [ 157.03765869140625, -4.758218765258732 ], [ 157.032501220703125, -4.758889198303109 ], [ 157.033432006836051, -4.755993843078556 ], [ 157.035293579101676, -4.756967067718449 ] ] ], [ [ [ 157.03315734863304, -4.754199981689453 ], [ 157.032821655273551, -4.753159046173096 ], [ 157.036911010742188, -4.751420021057072 ], [ 157.03620910644554, -4.753365993499699 ], [ 157.03315734863304, -4.754199981689453 ] ] ], [ [ [ 157.036560058593977, -4.750236988067627 ], [ 157.033645629882812, -4.752114772796574 ], [ 157.032196044921989, -4.750968933105469 ], [ 157.032821655273551, -4.750308036804199 ], [ 157.036560058593977, -4.750236988067627 ] ] ], [ [ [ 157.031433105468864, -4.74523210525507 ], [ 157.033645629882812, -4.743909835815373 ], [ 157.03413391113304, -4.74412012100214 ], [ 157.031906127929801, -4.746553897857666 ], [ 157.02996826171875, -4.744885921478271 ], [ 157.031433105468864, -4.74523210525507 ] ] ], [ [ [ 157.031845092773665, -4.740087985992432 ], [ 157.029006958007926, -4.741963863372803 ], [ 157.028381347656364, -4.741895198821965 ], [ 157.0284423828125, -4.740227222442627 ], [ 157.031845092773665, -4.740087985992432 ] ] ], [ [ [ 157.028717041015625, -4.737724781036377 ], [ 157.030319213867415, -4.736958980560246 ], [ 157.03108215332054, -4.737308025360107 ], [ 157.027618408203239, -4.739738941192627 ], [ 157.028717041015625, -4.737724781036377 ] ] ], [ [ [ 157.026855468750114, -4.736611843109131 ], [ 157.025680541992188, -4.735775947570744 ], [ 157.028930664062727, -4.733691215515137 ], [ 157.029205322265625, -4.734525203704834 ], [ 157.026855468750114, -4.736611843109131 ] ] ], [ [ [ 157.027206420898438, -4.733900070190373 ], [ 157.025741577148665, -4.735219955444336 ], [ 157.024841308593864, -4.73473405838007 ], [ 157.025253295898438, -4.733691215515137 ], [ 157.027206420898438, -4.733900070190373 ] ] ], [ [ [ 155.306671142578239, -4.723055839538517 ], [ 155.309722900390739, -4.725833892822209 ], [ 155.306396484375, -4.728056907653809 ], [ 155.304992675781364, -4.725555896759033 ], [ 155.306671142578239, -4.723055839538517 ] ] ], [ [ [ 155.43556213378929, -4.715555191040039 ], [ 155.43611145019554, -4.717220783233643 ], [ 155.43251037597679, -4.718550205230656 ], [ 155.432678222656477, -4.716455936431828 ], [ 155.43556213378929, -4.715555191040039 ] ] ], [ [ [ 155.429504394531364, -4.71290922164917 ], [ 155.428726196289517, -4.71260404586792 ], [ 155.426925659179688, -4.708103179931584 ], [ 155.43072509765625, -4.709121227264404 ], [ 155.429504394531364, -4.71290922164917 ] ] ], [ [ [ 156.93756103515625, -4.704438209533691 ], [ 156.936737060546989, -4.703533172607365 ], [ 156.939437866210938, -4.702221870422306 ], [ 156.9390869140625, -4.703671932220402 ], [ 156.93756103515625, -4.704438209533691 ] ] ], [ [ [ 155.336044311523551, -4.668369770049992 ], [ 155.334426879882812, -4.666180133819466 ], [ 155.33575439453125, -4.664566993713322 ], [ 155.33758544921875, -4.666116237640381 ], [ 155.336044311523551, -4.668369770049992 ] ] ], [ [ [ 154.203674316406364, -4.514444828033447 ], [ 154.202499389648551, -4.513887882232666 ], [ 154.203048706054915, -4.512292861938363 ], [ 154.204162597656364, -4.512777805328312 ], [ 154.203674316406364, -4.514444828033447 ] ] ], [ [ [ 154.168212890625114, -4.503141880035344 ], [ 154.165557861328466, -4.50083398818964 ], [ 154.165649414062727, -4.488195896148682 ], [ 154.168548583984489, -4.491462230682373 ], [ 154.168212890625114, -4.503141880035344 ] ] ], [ [ [ 154.166381835937727, -4.460834980010929 ], [ 154.163665771484375, -4.468417167663517 ], [ 154.1658935546875, -4.479289054870549 ], [ 154.159164428711165, -4.462501049041748 ], [ 154.166381835937727, -4.460834980010929 ] ] ], [ [ [ 154.183090209961051, -4.449097156524601 ], [ 154.229583740234489, -4.471593856811523 ], [ 154.249069213867301, -4.532028198242188 ], [ 154.236877441406364, -4.574854850768986 ], [ 154.205825805664062, -4.572776794433537 ], [ 154.164993286132812, -4.519166946411133 ], [ 154.169723510742301, -4.507778167724609 ], [ 154.201385498046989, -4.560555934906006 ], [ 154.197784423828239, -4.539721965789795 ], [ 154.233474731445312, -4.569056987762394 ], [ 154.216598510742415, -4.48359918594349 ], [ 154.165283203125227, -4.456943988799935 ], [ 154.183090209961051, -4.449097156524601 ] ] ], [ [ [ 154.108337402344091, -4.380279064178467 ], [ 154.105834960937614, -4.378888130187988 ], [ 154.106109619140852, -4.376944065093937 ], [ 154.108612060546989, -4.379166126251221 ], [ 154.108337402344091, -4.380279064178467 ] ] ], [ [ [ 154.100479125976562, -4.369361877441349 ], [ 154.102142333984602, -4.369917869567814 ], [ 154.102691650390739, -4.37325382232666 ], [ 154.099777221679688, -4.371098041534367 ], [ 154.100479125976562, -4.369361877441349 ] ] ], [ [ [ 154.135482788086165, -4.36123609542841 ], [ 154.148330688476676, -4.438333034515381 ], [ 154.14277648925804, -4.445555210113525 ], [ 154.126937866211165, -4.370833873748779 ], [ 154.10749816894554, -4.366942882537842 ], [ 154.135482788086165, -4.36123609542841 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-CPM", "NAME_1": "Central" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 149.580429077148551, -10.405835151672363 ], [ 149.579803466796989, -10.406524658203011 ], [ 149.576797485351676, -10.40562725067133 ], [ 149.57826232910179, -10.404490470886174 ], [ 149.580429077148551, -10.405835151672363 ] ] ], [ [ [ 149.363891601562614, -10.409167289733773 ], [ 149.360092163086165, -10.406002998352051 ], [ 149.362152099609602, -10.402752876281738 ], [ 149.363433837890625, -10.403489112853947 ], [ 149.363891601562614, -10.409167289733773 ] ] ], [ [ [ 149.460281372070312, -10.39333438873291 ], [ 149.455139160156364, -10.396478652954102 ], [ 149.451385498046875, -10.39333438873291 ], [ 149.457229614257812, -10.389445304870605 ], [ 149.460281372070312, -10.39333438873291 ] ] ], [ [ [ 149.358612060546875, -10.38273811340332 ], [ 149.361389160156477, -10.382779121398869 ], [ 149.359420776367529, -10.395148277282601 ], [ 149.35017395019554, -10.388641357421875 ], [ 149.358612060546875, -10.38273811340332 ] ] ], [ [ [ 149.601516723632812, -10.358221054077035 ], [ 149.602920532227017, -10.359270095825082 ], [ 149.604003906250227, -10.36297607421875 ], [ 149.598419189453125, -10.361594200134277 ], [ 149.601516723632812, -10.358221054077035 ] ] ], [ [ [ 149.346298217773438, -10.345357894897461 ], [ 149.34254455566429, -10.344498634338379 ], [ 149.341186523437614, -10.341830253601017 ], [ 149.346588134765739, -10.342035293579102 ], [ 149.346298217773438, -10.345357894897461 ] ] ], [ [ [ 149.326156616211165, -10.330224037170353 ], [ 149.319015502929688, -10.324614524841309 ], [ 149.320587158203239, -10.321827888488713 ], [ 149.324722290039062, -10.324275970458984 ], [ 149.326156616211165, -10.330224037170353 ] ] ], [ [ [ 149.393051147461165, -10.307223320007211 ], [ 149.39111328125, -10.305832862853947 ], [ 149.391387939453352, -10.304445266723633 ], [ 149.393890380859489, -10.305832862853947 ], [ 149.393051147461165, -10.307223320007211 ] ] ], [ [ [ 147.277496337890739, -9.538612365722656 ], [ 147.276107788086051, -9.537777900695801 ], [ 147.276107788086051, -9.535555839538574 ], [ 147.277496337890739, -9.535834312438965 ], [ 147.277496337890739, -9.538612365722656 ] ] ], [ [ [ 147.290557861328125, -9.533612251281738 ], [ 147.291381835937727, -9.53416633605957 ], [ 147.293060302734602, -9.543332099914551 ], [ 147.289718627929688, -9.538612365722656 ], [ 147.290557861328125, -9.533612251281738 ] ] ], [ [ [ 147.28334045410179, -9.521110534667912 ], [ 147.285827636718864, -9.522500991821232 ], [ 147.287216186523551, -9.528888702392578 ], [ 147.281951904296875, -9.522223472595158 ], [ 147.28334045410179, -9.521110534667912 ] ] ], [ [ [ 147.03999328613304, -9.452221870422363 ], [ 147.03083801269554, -9.449445724487248 ], [ 147.034729003906364, -9.433334350585938 ], [ 147.042221069335938, -9.442222595214844 ], [ 147.03999328613304, -9.452221870422363 ] ] ], [ [ [ 146.889160156250114, -9.425556182861271 ], [ 146.885833740234375, -9.428890228271428 ], [ 146.881942749023551, -9.427778244018555 ], [ 146.887771606445426, -9.42249870300293 ], [ 146.889160156250114, -9.425556182861271 ] ] ], [ [ [ 146.877853393554801, -9.240498542785645 ], [ 146.876449584960938, -9.243212699890137 ], [ 146.871414184570426, -9.242252349853459 ], [ 146.876312255859602, -9.23822021484375 ], [ 146.877853393554801, -9.240498542785645 ] ] ], [ [ [ 146.941375732422102, -9.127150535583496 ], [ 146.936660766601562, -9.129167556762695 ], [ 146.933258056640739, -9.127873420715332 ], [ 146.938507080078239, -9.126667976379395 ], [ 146.941375732422102, -9.127150535583496 ] ] ], [ [ [ 146.921951293945767, -9.120554924011174 ], [ 146.925277709960938, -9.122220993041992 ], [ 146.927215576171875, -9.124443054199219 ], [ 146.923049926757926, -9.124999046325684 ], [ 146.921951293945767, -9.120554924011174 ] ] ], [ [ [ 146.908523559570312, -9.120345115661564 ], [ 146.912200927734602, -9.121929168701172 ], [ 146.913360595703352, -9.123815536499023 ], [ 146.906112670898665, -9.120782852172852 ], [ 146.908523559570312, -9.120345115661564 ] ] ], [ [ [ 146.911346435546875, -9.108577728271484 ], [ 146.912200927734602, -9.109589576721191 ], [ 146.908050537109489, -9.11191463470459 ], [ 146.907501220703239, -9.109992980956974 ], [ 146.911346435546875, -9.108577728271484 ] ] ], [ [ [ 146.980834960937727, -9.046113967895508 ], [ 146.98274230957054, -9.05157470703125 ], [ 146.969497680664176, -9.055825233459416 ], [ 146.969390869140852, -9.050192832946777 ], [ 146.980834960937727, -9.046113967895508 ] ] ], [ [ [ 146.947525024414176, -9.010478973388672 ], [ 146.948120117187614, -9.011692047119141 ], [ 146.946929931640852, -9.012510299682617 ], [ 146.946701049804801, -9.010760307312012 ], [ 146.947525024414176, -9.010478973388672 ] ] ], [ [ [ 146.603469848632926, -8.815481185913086 ], [ 146.602783203125, -8.814652442932072 ], [ 146.604598999023438, -8.814282417297306 ], [ 146.604598999023438, -8.815112113952637 ], [ 146.603469848632926, -8.815481185913086 ] ] ], [ [ [ 146.595703125, -8.815732002258301 ], [ 146.595138549804688, -8.816007614135685 ], [ 146.600555419922102, -8.808611869811955 ], [ 146.600585937500114, -8.812926292419434 ], [ 146.595703125, -8.815732002258301 ] ] ], [ [ [ 146.529846191406364, -8.804290771484375 ], [ 146.548858642578352, -8.824715614318848 ], [ 146.541610717773665, -8.841582298278752 ], [ 146.511108398437955, -8.774444580078125 ], [ 146.529846191406364, -8.804290771484375 ] ] ], [ [ [ 146.555633544921875, -8.77422904968256 ], [ 146.554306030273438, -8.77395057678217 ], [ 146.554367065429801, -8.773053169250488 ], [ 146.555206298828239, -8.772913932800293 ], [ 146.555633544921875, -8.77422904968256 ] ] ], [ [ [ 146.723312377929688, -7.911736011505127 ], [ 146.739807128906364, -7.952634811401367 ], [ 146.784210205078352, -7.933434963226318 ], [ 146.820205688476562, -7.989436149597168 ], [ 146.863311767578125, -7.988033771514893 ], [ 146.903411865234489, -7.960034847259521 ], [ 146.974807739257812, -7.983933925628605 ], [ 147.366012573242188, -8.359833717346135 ], [ 147.461715698242415, -8.348434448242188 ], [ 147.64271545410179, -8.527835845947266 ], [ 147.649414062500455, -8.545034408569336 ], [ 147.633407592773551, -8.565534591674805 ], [ 147.445205688476904, -8.723333358764592 ], [ 147.46051025390625, -8.789134025573674 ], [ 147.500411987304801, -8.827235221862793 ], [ 147.501617431640625, -8.873633384704533 ], [ 147.542419433593864, -8.899934768676701 ], [ 147.553619384765739, -8.95063400268549 ], [ 147.635208129882812, -8.977034568786564 ], [ 147.693008422851562, -9.043934822082463 ], [ 147.747314453125114, -9.1651353836059 ], [ 147.827117919922102, -9.169335365295353 ], [ 147.873718261719205, -9.274435043334904 ], [ 147.90911865234375, -9.293135643005371 ], [ 147.955215454101676, -9.291033744812012 ], [ 147.986114501953239, -9.31363391876215 ], [ 147.983917236328239, -9.353534698486328 ], [ 148.033309936523665, -9.390434265136719 ], [ 148.053207397461051, -9.431235313415527 ], [ 148.052017211914176, -9.467233657836914 ], [ 148.026611328125, -9.511835098266488 ], [ 148.043319702148551, -9.556035995483398 ], [ 148.104415893554688, -9.610434532165471 ], [ 148.214508056640852, -9.664933204650879 ], [ 148.245117187500114, -9.746733665466252 ], [ 148.353713989257812, -9.753334045410099 ], [ 148.392608642578125, -9.741435050964355 ], [ 148.444305419921875, -9.757035255432129 ], [ 148.565719604492301, -9.875433921813965 ], [ 148.709014892578466, -9.936736106872559 ], [ 148.780319213867301, -9.944234848022461 ], [ 148.805419921875114, -9.97723388671875 ], [ 148.846710205078239, -9.940635681152287 ], [ 148.970214843750114, -9.905334472656193 ], [ 148.972106933593977, -9.867136001586914 ], [ 148.942916870117415, -9.807834625244141 ], [ 148.966705322265625, -9.744834899902287 ], [ 149.023513793945426, -9.800736427307129 ], [ 149.134918212890739, -9.758234024047795 ], [ 149.177505493164062, -9.795333862304688 ], [ 149.324615478515852, -9.856535911560059 ], [ 149.319915771484489, -9.935934066772347 ], [ 149.385116577148551, -9.943234443664494 ], [ 149.521011352539062, -10.028834342956486 ], [ 149.653106689453125, -10.038134574890137 ], [ 149.664520263672102, -10.073233604431152 ], [ 149.660919189453239, -10.33293437957758 ], [ 149.604446411133267, -10.351110458374023 ], [ 149.561218261719091, -10.346529006958008 ], [ 149.541885375977017, -10.364514350891113 ], [ 149.509368896484375, -10.346156120300293 ], [ 149.495010375976676, -10.358430862426758 ], [ 149.523895263672102, -10.367777824401742 ], [ 149.485290527343864, -10.365239143371525 ], [ 149.495407104492301, -10.345482826232853 ], [ 149.48428344726608, -10.331950187683105 ], [ 149.460296630859489, -10.335840225219727 ], [ 149.460556030273438, -10.359998703002873 ], [ 149.429992675781591, -10.354166984558105 ], [ 149.448226928711165, -10.333134651184082 ], [ 149.428237915039062, -10.311742782592717 ], [ 149.41499328613304, -10.328055381774902 ], [ 149.405197143555029, -10.292577743530217 ], [ 149.390014648437614, -10.30112361907959 ], [ 149.365798950195426, -10.276935577392578 ], [ 149.32441711425804, -10.314071655273438 ], [ 149.097091674805142, -10.23077201843256 ], [ 149.023864746093864, -10.247262001037541 ], [ 148.964675903320426, -10.288251876831055 ], [ 148.897415161132812, -10.237221717834473 ], [ 148.79611206054733, -10.248862266540527 ], [ 148.77204895019554, -10.229581832885742 ], [ 148.744293212890739, -10.236841201782227 ], [ 148.734329223632926, -10.200265884399357 ], [ 148.780426025390739, -10.205370903015023 ], [ 148.72088623046875, -10.191349983215332 ], [ 148.756591796875114, -10.164546966552678 ], [ 148.770767211914062, -10.164955139160099 ], [ 148.77789306640625, -10.161364555358887 ], [ 148.779006958007926, -10.163022041320801 ], [ 148.771041870117188, -10.17212963104248 ], [ 148.771316528320767, -10.175168037414494 ], [ 148.787902832031477, -10.178252220153752 ], [ 148.772140502929801, -10.17420768737793 ], [ 148.780319213867301, -10.163266181945687 ], [ 148.779754638671989, -10.160642623901367 ], [ 148.762237548828125, -10.163022041320801 ], [ 148.791961669921989, -10.140539169311523 ], [ 148.804397583007812, -10.148139953613224 ], [ 148.807327270507926, -10.14689826965332 ], [ 148.808166503906364, -10.145240783691406 ], [ 148.799728393554915, -10.138333320617676 ], [ 148.783615112304688, -10.141388893127441 ], [ 148.78083801269554, -10.123889923095703 ], [ 148.738906860351676, -10.167044639587402 ], [ 148.72222900390625, -10.143333435058594 ], [ 148.708053588867301, -10.147665977477971 ], [ 148.708023071289062, -10.131130218505859 ], [ 148.732559204101676, -10.127743721008301 ], [ 148.73785400390625, -10.122535705566406 ], [ 148.737228393554801, -10.121110916137638 ], [ 148.70916748046875, -10.129721641540471 ], [ 148.697235107421875, -10.111420631408691 ], [ 148.684371948242188, -10.114998817443791 ], [ 148.699722290039062, -10.116945266723633 ], [ 148.703613281250114, -10.136666297912598 ], [ 148.697784423828125, -10.139722824096623 ], [ 148.697784423828125, -10.133888244628906 ], [ 148.691665649414062, -10.133609771728516 ], [ 148.693328857421875, -10.130000114440861 ], [ 148.692504882812614, -10.126387596130314 ], [ 148.68777465820358, -10.129165649414006 ], [ 148.68580627441429, -10.12456226348877 ], [ 148.683990478515625, -10.126495361328068 ], [ 148.697219848632812, -10.140555381774902 ], [ 148.70472717285179, -10.138333320617676 ], [ 148.703338623046875, -10.144166946411133 ], [ 148.689727783203239, -10.153887748718262 ], [ 148.683349609375114, -10.141070365905705 ], [ 148.684188842773551, -10.149350166320801 ], [ 148.692184448242188, -10.15806770324707 ], [ 148.668334960937614, -10.171111106872502 ], [ 148.653320312500341, -10.160408020019531 ], [ 148.66523742675804, -10.177117347717285 ], [ 148.648818969726676, -10.192209243774414 ], [ 148.6138916015625, -10.178611755371094 ], [ 148.582443237304801, -10.187732696533146 ], [ 148.563217163086165, -10.1703844070434 ], [ 148.513168334960938, -10.197409629821777 ], [ 148.400848388672102, -10.208009719848576 ], [ 148.388351440429688, -10.188091278076172 ], [ 148.340270996093864, -10.175832748413086 ], [ 148.336105346679801, -10.138056755065918 ], [ 148.3553466796875, -10.17343807220459 ], [ 148.357376098632926, -10.175024032592773 ], [ 148.359542846679688, -10.174677848815918 ], [ 148.36463928222679, -10.169709205627441 ], [ 148.3477783203125, -10.158887863159123 ], [ 148.346939086914176, -10.133055686950627 ], [ 148.30110168457054, -10.126667976379395 ], [ 148.274230957031477, -10.139706611633244 ], [ 148.258010864257926, -10.111661911010685 ], [ 148.219451904296875, -10.094325065612793 ], [ 148.178634643554688, -10.101129531860352 ], [ 148.181076049804688, -10.070444107055664 ], [ 148.21186828613304, -10.056012153625488 ], [ 148.239959716796875, -10.02157020568842 ], [ 148.230392456055142, -10.01756572723383 ], [ 148.201950073242415, -10.020000457763558 ], [ 148.1683349609375, -10.077500343322697 ], [ 148.156387329102017, -10.070278167724609 ], [ 148.149291992187614, -10.072900772094727 ], [ 148.17138671875, -10.087223052978459 ], [ 148.125900268554688, -10.125826835632267 ], [ 148.028671264648438, -10.131134986877441 ], [ 148.004714965820426, -10.160555839538574 ], [ 147.971710205078239, -10.161417961120605 ], [ 147.967926025390852, -10.143471717834473 ], [ 147.944564819335938, -10.13502311706543 ], [ 147.959213256836051, -10.120000839233398 ], [ 147.93836975097679, -10.097546577453556 ], [ 147.855270385742301, -10.101389884948674 ], [ 147.887496948242301, -10.098055839538517 ], [ 147.899368286132812, -10.080287933349609 ], [ 147.880538940429801, -10.045149803161564 ], [ 147.889175415039176, -10.035595893859863 ], [ 147.860000610351676, -10.052778244018555 ], [ 147.85194396972679, -10.096945762634277 ], [ 147.8255615234375, -10.058333396911621 ], [ 147.784912109375, -10.049908638000488 ], [ 147.750000000000341, -10.065554618835392 ], [ 147.725006103515739, -10.103334426879883 ], [ 147.708053588867188, -10.017778396606445 ], [ 147.619445800781477, -9.983611106872502 ], [ 147.516662597656705, -9.873332977294922 ], [ 147.515838623047102, -9.810832023620549 ], [ 147.478607177734375, -9.739167213439828 ], [ 147.414169311523438, -9.684722900390625 ], [ 147.396392822265625, -9.641666412353459 ], [ 147.350830078125, -9.597222328186035 ], [ 147.362228393554801, -9.581110954284668 ], [ 147.31304931640625, -9.560556411743107 ], [ 147.324996948242188, -9.539166450500431 ], [ 147.285827636718864, -9.515277862548828 ], [ 147.286407470703239, -9.44273567199707 ], [ 147.271209716796875, -9.40423393249506 ], [ 147.169906616211392, -9.357535362243596 ], [ 147.095306396484602, -9.396434783935547 ], [ 147.081939697265739, -9.428055763244572 ], [ 147.0927734375, -9.446925163269043 ], [ 147.058334350586051, -9.446623802185002 ], [ 147.007217407226676, -9.376666069030762 ], [ 146.988327026367642, -9.293889999389592 ], [ 146.997772216796875, -9.278332710266056 ], [ 146.984161376953125, -9.287499427795353 ], [ 146.938613891601904, -9.266389846801758 ], [ 146.925003051758267, -9.282501220703068 ], [ 146.897994995117188, -9.26875114440918 ], [ 146.926177978515625, -9.248126983642578 ], [ 146.9022216796875, -9.222776412963754 ], [ 146.907501220703239, -9.164443969726506 ], [ 146.916946411132926, -9.159443855285645 ], [ 146.916946411132926, -9.146944999694824 ], [ 146.924972534179915, -9.155819892883301 ], [ 146.93695068359375, -9.153055191039982 ], [ 146.918334960937614, -9.144722938537541 ], [ 146.925003051758267, -9.138609886169434 ], [ 146.926391601562614, -9.133609771728516 ], [ 146.911117553711051, -9.154165267944336 ], [ 146.89031982421875, -9.124492645263615 ], [ 146.901107788086165, -9.119167327880859 ], [ 146.910781860351562, -9.125313758850098 ], [ 146.934722900390852, -9.131668090820312 ], [ 146.95472717285179, -9.132222175598088 ], [ 146.96527099609375, -9.126111030578556 ], [ 146.967773437500114, -9.128890037536621 ], [ 146.96527099609375, -9.125276565551701 ], [ 146.948883056640739, -9.130277633666992 ], [ 146.942779541015739, -9.126111030578556 ], [ 146.932495117187614, -9.125555038452148 ], [ 146.923614501953352, -9.119167327880859 ], [ 146.963272094726562, -9.098325729370117 ], [ 146.969451904296989, -9.07055473327631 ], [ 147.016113281250227, -9.082777976989689 ], [ 146.971115112304801, -9.063888549804688 ], [ 146.991668701171875, -9.049444198608398 ], [ 147.00471496582054, -9.059721946716195 ], [ 147.018325805664176, -9.050000190734863 ], [ 147.004165649414176, -9.058055877685547 ], [ 146.991744995117415, -9.043682098388672 ], [ 146.988891601562727, -9.048334121704045 ], [ 146.979446411132812, -9.044443130493164 ], [ 146.971786499023551, -9.048959732055664 ], [ 146.977157592773438, -9.030176162719727 ], [ 146.96980285644554, -9.00771522521967 ], [ 146.946395874023438, -9.007779121398869 ], [ 146.971115112304801, -9.030278205871525 ], [ 146.957504272460938, -9.046389579772949 ], [ 146.945007324218977, -9.040263175964299 ], [ 146.963058471679688, -9.059165954589787 ], [ 146.950836181640625, -9.085000038146973 ], [ 146.881988525390625, -9.114723205566406 ], [ 146.827499389648551, -9.091667175292912 ], [ 146.809173583984602, -9.062223434448242 ], [ 146.62971496582054, -9.026944160461369 ], [ 146.59138488769554, -8.996212005615178 ], [ 146.565612792968977, -8.94175910949707 ], [ 146.56983947753929, -8.91401290893549 ], [ 146.5478515625, -8.885414123535043 ], [ 146.563934326172102, -8.850235939025822 ], [ 146.590179443359375, -8.854366302490234 ], [ 146.619338989257812, -8.791317939758301 ], [ 146.603057861328239, -8.813887596130371 ], [ 146.60028076171875, -8.799445152282658 ], [ 146.58888244628929, -8.820279121398869 ], [ 146.562774658203352, -8.813610076904297 ], [ 146.571670532226562, -8.801667213439941 ], [ 146.572616577148438, -8.786442756652775 ], [ 146.547271728515625, -8.77027702331543 ], [ 146.559387207031364, -8.749047279357853 ], [ 146.544036865234375, -8.769742965698242 ], [ 146.531524658203239, -8.759805679321289 ], [ 146.523132324218864, -8.715496063232422 ], [ 146.435272216796875, -8.616095542907715 ], [ 146.382568359375114, -8.587371826171818 ], [ 146.386016845703125, -7.920834064483643 ], [ 146.486419677734375, -7.9082350730896 ], [ 146.541107177734489, -7.825333118438721 ], [ 146.652511596680029, -7.772534847259521 ], [ 146.735107421875, -7.829336166381779 ], [ 146.723312377929688, -7.911736011505127 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-CPK", "NAME_1": "Chimbu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 145.109817504882926, -5.804034233093205 ], [ 145.16461181640625, -5.876634120941162 ], [ 145.124114990234375, -5.991734981536865 ], [ 145.13140869140625, -6.079433917999268 ], [ 145.189605712890625, -6.128933906555119 ], [ 145.25032043457054, -6.127735137939396 ], [ 145.269515991210938, -6.284033775329533 ], [ 145.245208740234489, -6.32743501663208 ], [ 145.182617187500227, -6.352435111999512 ], [ 145.188217163086051, -6.399334907531738 ], [ 145.1715087890625, -6.420235157012939 ], [ 145.022109985351904, -6.398334980010929 ], [ 144.991607666015625, -6.439936161041203 ], [ 144.988113403320426, -6.511233806610107 ], [ 145.017318725586051, -6.542435169219914 ], [ 145.104217529297102, -6.57083606719965 ], [ 145.201110839843977, -6.679935932159367 ], [ 145.303909301757926, -6.684333801269418 ], [ 145.343109130859489, -6.716034889221191 ], [ 145.3502197265625, -6.733934879302979 ], [ 145.29512023925804, -6.868734836578312 ], [ 145.203414916992415, -6.813035011291504 ], [ 145.155319213867415, -6.838734149932804 ], [ 144.994216918945426, -6.796134948730469 ], [ 144.913619995117188, -6.725635051727295 ], [ 144.851806640625, -6.747634887695256 ], [ 144.761917114257926, -6.709134101867619 ], [ 144.697814941406364, -6.710334777831974 ], [ 144.557006835937727, -6.647833824157715 ], [ 144.557907104492188, -6.60433387756342 ], [ 144.539215087890625, -6.581234931945744 ], [ 144.442306518554688, -6.563635826110783 ], [ 144.422210693359375, -6.544333934783936 ], [ 144.438613891601562, -6.460936069488469 ], [ 144.542205810546989, -6.433334827423039 ], [ 144.559814453125, -6.36993408203125 ], [ 144.602111816406591, -6.387733936309758 ], [ 144.64491271972679, -6.30973577499384 ], [ 144.682113647461051, -6.300836086273193 ], [ 144.688110351562614, -6.268733978271484 ], [ 144.725814819336165, -6.243435859680176 ], [ 144.741714477539176, -6.164634227752629 ], [ 144.72991943359375, -6.11573600769043 ], [ 144.751312255859375, -6.093635082244873 ], [ 144.694213867187614, -6.036633968353158 ], [ 144.778610229492415, -5.970334053039494 ], [ 144.802505493164517, -5.931334972381592 ], [ 144.816314697265625, -5.895534992217961 ], [ 144.79200744628929, -5.835433959960881 ], [ 144.8297119140625, -5.783133983612061 ], [ 144.867813110351562, -5.808834075927678 ], [ 145.026412963867415, -5.775935173034554 ], [ 145.079910278320312, -5.782635211944523 ], [ 145.109817504882926, -5.804034233093205 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-EBR", "NAME_1": "East New Britain" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 150.916381835937614, -6.037499904632568 ], [ 150.917770385742188, -6.038055896759033 ], [ 150.925277709961165, -6.045556068420353 ], [ 150.917221069336165, -6.046110153198242 ], [ 150.916381835937614, -6.037499904632568 ] ] ], [ [ [ 150.898056030273551, -6.024445056915283 ], [ 150.896392822265625, -6.02555513381958 ], [ 150.894439697265739, -6.024167060852051 ], [ 150.897506713867529, -6.022500991821232 ], [ 150.898056030273551, -6.024445056915283 ] ] ], [ [ [ 151.46827697753929, -5.688774108886662 ], [ 151.469467163086051, -5.689190864562931 ], [ 151.470230102539176, -5.689957141876221 ], [ 151.466064453125114, -5.688634872436467 ], [ 151.46827697753929, -5.688774108886662 ] ] ], [ [ [ 151.491149902343864, -5.626969814300537 ], [ 151.491149902343864, -5.627283096313477 ], [ 151.487686157226562, -5.627499103546143 ], [ 151.488372802734489, -5.626553058624268 ], [ 151.491149902343864, -5.626969814300537 ] ] ], [ [ [ 151.748611450195312, -5.570555210113525 ], [ 151.750000000000227, -5.573888778686467 ], [ 151.745834350586051, -5.573888778686467 ], [ 151.744720458984489, -5.571667194366398 ], [ 151.748611450195312, -5.570555210113525 ] ] ], [ [ [ 151.744720458984489, -5.576389789581299 ], [ 151.739166259765739, -5.571667194366398 ], [ 151.740280151367415, -5.563056945800781 ], [ 151.74249267578125, -5.565555095672551 ], [ 151.744720458984489, -5.576389789581299 ] ] ], [ [ [ 151.64735412597679, -5.55215311050415 ], [ 151.645004272460938, -5.543333053588867 ], [ 151.64666748046875, -5.538610935211182 ], [ 151.651947021484489, -5.546389102935791 ], [ 151.64735412597679, -5.55215311050415 ] ] ], [ [ [ 152.347900390625, -4.267350196838322 ], [ 152.3499755859375, -4.270257949829102 ], [ 152.338378906250227, -4.271755218505859 ], [ 152.344467163085938, -4.266406059265137 ], [ 152.347900390625, -4.267350196838322 ] ] ], [ [ [ 152.416702270507926, -4.241387844085693 ], [ 152.423812866210938, -4.242096900939828 ], [ 152.41413879394554, -4.246724128723145 ], [ 152.408401489257926, -4.238293170928955 ], [ 152.416702270507926, -4.241387844085693 ] ] ], [ [ [ 152.397247314453239, -4.234067916870117 ], [ 152.40634155273483, -4.236446857452336 ], [ 152.388092041015739, -4.23773193359375 ], [ 152.389633178710938, -4.2343430519104 ], [ 152.397247314453239, -4.234067916870117 ] ] ], [ [ [ 152.438903808593977, -4.22888708114624 ], [ 152.442001342773665, -4.228431224822998 ], [ 152.44691467285179, -4.229754924774056 ], [ 152.441299438476676, -4.23443698883051 ], [ 152.438903808593977, -4.22888708114624 ] ] ], [ [ [ 152.461151123047216, -4.22442722320551 ], [ 152.466598510742415, -4.232007026672363 ], [ 152.449707031250341, -4.233882904052734 ], [ 152.454269409179801, -4.224957942962646 ], [ 152.461151123047216, -4.22442722320551 ] ] ], [ [ [ 152.464599609375, -4.217082977294808 ], [ 152.467926025390852, -4.217432022094727 ], [ 152.465560913085938, -4.220832824707031 ], [ 152.463134765625114, -4.220346927642822 ], [ 152.464599609375, -4.217082977294808 ] ] ], [ [ [ 151.810546875000114, -4.213358879089355 ], [ 151.808944702148665, -4.213150024414006 ], [ 151.808593750000114, -4.212386131286507 ], [ 151.810119628906364, -4.212594032287541 ], [ 151.810546875000114, -4.213358879089355 ] ] ], [ [ [ 151.73628234863304, -4.203595161437988 ], [ 151.735519409179915, -4.203247070312443 ], [ 151.735992431640625, -4.202065944671631 ], [ 151.736968994140625, -4.202691078185978 ], [ 151.73628234863304, -4.203595161437988 ] ] ], [ [ [ 152.414566040039062, -4.201935768127385 ], [ 152.43255615234375, -4.223141193389893 ], [ 152.432235717773551, -4.233559131622258 ], [ 152.396591186523665, -4.219143867492676 ], [ 152.414566040039062, -4.201935768127385 ] ] ], [ [ [ 152.42555236816429, -4.204720973968392 ], [ 152.424163818359375, -4.204720973968392 ], [ 152.421661376953239, -4.201388835906982 ], [ 152.424438476562727, -4.20111083984375 ], [ 152.42555236816429, -4.204720973968392 ] ] ], [ [ [ 151.795562744140739, -4.199722766876164 ], [ 151.794723510742529, -4.199722766876164 ], [ 151.79444885253929, -4.198054790496826 ], [ 151.796112060546875, -4.198332786560002 ], [ 151.795562744140739, -4.199722766876164 ] ] ], [ [ [ 151.940368652343977, -4.17858695983881 ], [ 151.946624755859489, -4.183596134185791 ], [ 151.944305419921875, -4.188353061676025 ], [ 151.9342041015625, -4.182775974273625 ], [ 151.940368652343977, -4.17858695983881 ] ] ], [ [ [ 151.573074340820426, -4.158741950988656 ], [ 151.576644897461392, -4.160048007965088 ], [ 151.577728271484602, -4.163647174835205 ], [ 151.567779541015625, -4.156112194061222 ], [ 151.573074340820426, -4.158741950988656 ] ] ], [ [ [ 151.568878173828239, -4.146534919738656 ], [ 151.567489624023892, -4.145700931549015 ], [ 151.567626953125227, -4.144588947296086 ], [ 151.569366455078352, -4.145840167999211 ], [ 151.568878173828239, -4.146534919738656 ] ] ], [ [ [ 152.194839477539062, -4.163527965545654 ], [ 152.234573364257812, -4.244133949279785 ], [ 152.208709716797102, -4.25089693069458 ], [ 152.196395874023551, -4.226666927337646 ], [ 152.184677124023665, -4.247994899749699 ], [ 152.177215576172102, -4.203888893127441 ], [ 152.160598754882812, -4.205523967742863 ], [ 152.148910522461051, -4.228633880615234 ], [ 152.172195434570312, -4.261407852172852 ], [ 152.156112670898551, -4.283269882202148 ], [ 152.168228149414062, -4.303809165954533 ], [ 152.212188720703239, -4.293382167816105 ], [ 152.278076171875, -4.342771053314209 ], [ 152.391662597656364, -4.321665763854924 ], [ 152.404769897461051, -4.336120128631592 ], [ 152.381942749023551, -4.397500038146973 ], [ 152.355407714843977, -4.416094779968262 ], [ 152.359741210937727, -4.440909862518311 ], [ 152.331497192382812, -4.496329784393311 ], [ 152.382431030273438, -4.615058898925781 ], [ 152.382751464843864, -4.67837381362915 ], [ 152.365386962890739, -4.768818855285645 ], [ 152.328186035156364, -4.818107128143311 ], [ 152.333801269531477, -4.83523511886591 ], [ 152.221466064453352, -4.96998405456543 ], [ 152.160568237304688, -4.97334623336792 ], [ 152.14324951171875, -4.989083766937199 ], [ 152.027770996093864, -4.965278148651123 ], [ 152.006057739258154, -4.98958683013916 ], [ 151.998214721679801, -4.971992015838566 ], [ 151.970550537109489, -4.969165802001953 ], [ 151.952758789062727, -4.990168094634953 ], [ 151.950439453125114, -5.022334098815861 ], [ 151.96832275390625, -5.043666839599609 ], [ 151.942810058593864, -5.097107887268066 ], [ 151.949813842773438, -5.141892910003605 ], [ 151.993896484375, -5.196389198303223 ], [ 152.020736694336051, -5.196723937988281 ], [ 152.055053710937614, -5.223379135131836 ], [ 152.13337707519554, -5.329991817474365 ], [ 152.133895874023438, -5.36583423614502 ], [ 152.085159301757926, -5.425864219665527 ], [ 152.086547851562841, -5.447021007537785 ], [ 152.056106567382926, -5.445257186889592 ], [ 152.010330200195426, -5.468760013580322 ], [ 151.959716796875, -5.518332958221379 ], [ 151.915832519531364, -5.525834083557015 ], [ 151.888336181640625, -5.54999923706049 ], [ 151.860549926757812, -5.542500972747746 ], [ 151.811950683593977, -5.587500095367432 ], [ 151.755554199219205, -5.560277938842717 ], [ 151.72138977050804, -5.515276908874455 ], [ 151.658340454101676, -5.512500762939453 ], [ 151.622222900390852, -5.567777156829777 ], [ 151.5836181640625, -5.528612136840763 ], [ 151.471115112304915, -5.521667003631535 ], [ 151.44476318359375, -5.571070194244328 ], [ 151.455307006836165, -5.629885196685734 ], [ 151.512771606445312, -5.635834217071533 ], [ 151.5130615234375, -5.671667098998967 ], [ 151.491394042968864, -5.69277811050415 ], [ 151.47860717773483, -5.69388818740839 ], [ 151.452499389648438, -5.685277938842717 ], [ 151.408615112304801, -5.703054904937687 ], [ 151.426391601562614, -5.710555076599121 ], [ 151.389450073242188, -5.735833168029671 ], [ 151.40167236328125, -5.750556945800724 ], [ 151.375000000000114, -5.808125019073486 ], [ 151.209716796875114, -5.901668071746826 ], [ 151.215560913086165, -5.923055171966553 ], [ 151.186325073242188, -5.956014156341496 ], [ 151.166107177734375, -5.960556030273381 ], [ 151.150558471679801, -5.940001010894775 ], [ 151.125839233398438, -5.963332176208382 ], [ 151.109024047851676, -5.955275058746281 ], [ 151.009262084961051, -6.033789157867375 ], [ 150.985488891601562, -6.007362842559814 ], [ 150.954650878906477, -6.019651889800969 ], [ 150.907226562500114, -6.010000228881836 ], [ 150.827774047851676, -6.046666145324707 ], [ 150.814163208007812, -6.022500991821232 ], [ 150.788391113281364, -6.022847175598145 ], [ 150.795272827148779, -6.017221927642822 ], [ 150.796112060546989, -6.014165878295898 ], [ 150.786117553711279, -6.00222110748291 ], [ 150.794479370117301, -6.016091823577881 ], [ 150.76861572265625, -6.038611888885498 ], [ 150.780181884765739, -6.07494401931757 ], [ 150.606811523437614, -5.919235229492188 ], [ 150.594207763671989, -5.73863410949707 ], [ 150.729217529296989, -5.732833862304631 ], [ 150.814514160156364, -5.748035907745361 ], [ 150.945816040039062, -5.702435016632023 ], [ 150.954818725586165, -5.673435211181584 ], [ 150.939010620117415, -5.626934051513672 ], [ 150.950515747070426, -5.599034786224365 ], [ 151.030319213867415, -5.609535217285099 ], [ 151.212509155273665, -5.474934101104736 ], [ 151.213607788085938, -5.432634830474854 ], [ 151.152908325195312, -5.421435832977238 ], [ 151.142211914062614, -5.39533519744873 ], [ 151.265213012695426, -5.150934219360295 ], [ 151.342208862304915, -5.039535045623779 ], [ 151.429611206054688, -4.981234073638916 ], [ 151.690017700195312, -4.97843599319458 ], [ 151.645706176757926, -4.934734821319466 ], [ 151.68550109863304, -4.867275238037053 ], [ 151.691390991210938, -4.797221183776855 ], [ 151.657501220703352, -4.765776157379094 ], [ 151.66717529296875, -4.674827098846379 ], [ 151.656875610351562, -4.612627029418945 ], [ 151.611312866211051, -4.564597129821777 ], [ 151.62158203125, -4.47567892074585 ], [ 151.558258056640625, -4.39619779586792 ], [ 151.533050537109375, -4.387845039367676 ], [ 151.534057617187727, -4.341302871703988 ], [ 151.508743286133267, -4.309707164764404 ], [ 151.520217895507812, -4.289424896240234 ], [ 151.490097045898551, -4.210516929626465 ], [ 151.52239990234375, -4.185382843017578 ], [ 151.55731201171875, -4.189073085784855 ], [ 151.571838378906364, -4.206385135650635 ], [ 151.633895874023438, -4.189722061157227 ], [ 151.634719848632812, -4.200078964233398 ], [ 151.706481933593977, -4.200108051299992 ], [ 151.719406127929688, -4.219678878784123 ], [ 151.765289306640739, -4.204090118408146 ], [ 151.833007812500114, -4.218915939330998 ], [ 151.853286743164062, -4.235957145690918 ], [ 151.839706420898551, -4.271603107452393 ], [ 151.8504638671875, -4.289158821105957 ], [ 151.946533203125114, -4.341112136840707 ], [ 151.988006591797102, -4.317158222198486 ], [ 152.031661987304688, -4.259168148040715 ], [ 151.983352661132926, -4.213062763214054 ], [ 151.98519897460983, -4.197357177734375 ], [ 152.124160766601562, -4.208333969116154 ], [ 152.166183471679915, -4.132823944091797 ], [ 152.194839477539062, -4.163527965545654 ] ] ], [ [ [ 152.450332641601562, -4.121941089630127 ], [ 152.496063232421875, -4.16053581237793 ], [ 152.470458984375, -4.215741157531681 ], [ 152.468093872070426, -4.213890075683594 ], [ 152.473007202148438, -4.203651905059701 ], [ 152.472213745117529, -4.191467761993408 ], [ 152.456130981445426, -4.21296501159668 ], [ 152.430648803710938, -4.212770938873291 ], [ 152.441024780273665, -4.181049823760873 ], [ 152.411041259765625, -4.164589881896973 ], [ 152.446670532226562, -4.144444942474308 ], [ 152.450332641601562, -4.121941089630127 ] ] ], [ [ [ 152.441940307617188, -4.116944789886475 ], [ 152.441390991211051, -4.117498874664307 ], [ 152.439361572265625, -4.114811897277832 ], [ 152.441406250000227, -4.115334033966008 ], [ 152.441940307617188, -4.116944789886475 ] ] ], [ [ [ 152.4381103515625, -4.113141059875431 ], [ 152.43695068359375, -4.114445209503117 ], [ 152.434570312500455, -4.112096786498967 ], [ 152.436996459961165, -4.112167835235539 ], [ 152.4381103515625, -4.113141059875431 ] ] ], [ [ [ 152.42312622070358, -4.117535114288216 ], [ 152.43055725097679, -4.121127128601074 ], [ 152.434112548828125, -4.131944179534855 ], [ 152.406753540039062, -4.115664005279484 ], [ 152.42312622070358, -4.117535114288216 ] ] ], [ [ [ 152.075378417968864, -4.088070869445744 ], [ 152.091201782226676, -4.106321811675969 ], [ 152.082427978515739, -4.131063938140869 ], [ 152.056396484375114, -4.120276927947884 ], [ 152.057220458984375, -4.096110820770207 ], [ 152.075378417968864, -4.088070869445744 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-ESW", "NAME_1": "East Sepik" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 144.50111389160179, -3.950553894042969 ], [ 144.509994506835938, -3.960555076599121 ], [ 144.504440307617301, -3.962498903274479 ], [ 144.496673583984375, -3.976109981536808 ], [ 144.488891601562727, -3.954722881317139 ], [ 144.50111389160179, -3.950553894042969 ] ] ], [ [ [ 144.509445190429688, -3.944721937179565 ], [ 144.52471923828125, -3.95194506645197 ], [ 144.5191650390625, -3.965555906295776 ], [ 144.502777099609375, -3.945833921432495 ], [ 144.509445190429688, -3.944721937179565 ] ] ], [ [ [ 144.481048583984375, -3.932004928588867 ], [ 144.494720458984489, -3.944999933242798 ], [ 144.485839843750227, -3.95194506645197 ], [ 144.475555419922102, -3.941112041473389 ], [ 144.481048583984375, -3.932004928588867 ] ] ], [ [ [ 144.251159667969091, -3.813108921051025 ], [ 144.260787963867415, -3.814095973968392 ], [ 144.264724731445312, -3.818054914474487 ], [ 144.25250244140625, -3.825555086135807 ], [ 144.251159667969091, -3.813108921051025 ] ] ], [ [ [ 144.21846008300804, -3.811835050582886 ], [ 144.244094848632926, -3.821944952011108 ], [ 144.237258911132812, -3.834621906280518 ], [ 144.220962524414176, -3.827138900756779 ], [ 144.21846008300804, -3.811835050582886 ] ] ], [ [ [ 144.126663208007812, -3.811666011810303 ], [ 144.125839233398551, -3.809999942779484 ], [ 144.12611389160179, -3.806665897369328 ], [ 144.126937866211051, -3.809165954589787 ], [ 144.126663208007812, -3.811666011810303 ] ] ], [ [ [ 144.35731506347679, -3.811985015869141 ], [ 144.35346984863304, -3.811358928680363 ], [ 144.352401733398438, -3.801898002624455 ], [ 144.355865478515739, -3.805584907531681 ], [ 144.35731506347679, -3.811985015869141 ] ] ], [ [ [ 144.363616943359602, -3.802500009536686 ], [ 144.361373901367301, -3.799837112426758 ], [ 144.366271972656477, -3.797255039215088 ], [ 144.366668701172102, -3.798610925674438 ], [ 144.363616943359602, -3.802500009536686 ] ] ], [ [ [ 144.352783203125, -3.797236919403019 ], [ 144.349716186523551, -3.803889989852848 ], [ 144.349716186523551, -3.809721946716252 ], [ 144.326660156250114, -3.821110963821411 ], [ 144.352783203125, -3.797236919403019 ] ] ], [ [ [ 144.368057250976676, -3.796667098999023 ], [ 144.366775512695312, -3.796875 ], [ 144.366500854492301, -3.794508934020996 ], [ 144.367782592773551, -3.794723033905029 ], [ 144.368057250976676, -3.796667098999023 ] ] ], [ [ [ 144.252777099609602, -3.789722919464054 ], [ 144.271667480468977, -3.800554990768433 ], [ 144.236404418945767, -3.817861080169678 ], [ 144.230560302734716, -3.80555605888361 ], [ 144.252777099609602, -3.789722919464054 ] ] ], [ [ [ 144.184570312500114, -3.791234016418457 ], [ 144.191665649414062, -3.798888921737671 ], [ 144.179992675781364, -3.8125 ], [ 144.182495117187841, -3.805278062820435 ], [ 144.177780151367188, -3.793333053588867 ], [ 144.184570312500114, -3.791234016418457 ] ] ], [ [ [ 144.167007446289062, -3.788674116134644 ], [ 144.180557250976676, -3.805278062820435 ], [ 144.175247192383154, -3.814479112625122 ], [ 144.158615112304688, -3.804166078567505 ], [ 144.167007446289062, -3.788674116134644 ] ] ], [ [ [ 144.252258300781364, -3.787079095840454 ], [ 144.242630004882812, -3.790278911590519 ], [ 144.235000610351562, -3.789166927337646 ], [ 144.238891601562614, -3.785136938095093 ], [ 144.252258300781364, -3.787079095840454 ] ] ], [ [ [ 144.1905517578125, -3.777499914169312 ], [ 144.267501831054801, -3.778889894485474 ], [ 144.271163940429801, -3.787463903427067 ], [ 144.231674194336051, -3.784166097640991 ], [ 144.224166870117415, -3.813055992126408 ], [ 144.218521118164176, -3.803728103637695 ], [ 144.190826416015739, -3.812777996063176 ], [ 144.195281982421875, -3.797498941421509 ], [ 144.185379028320312, -3.782743930816537 ], [ 144.1905517578125, -3.777499914169312 ] ] ], [ [ [ 144.5938720703125, -3.611123085021916 ], [ 144.583129882812727, -3.61213493347168 ], [ 144.584106445312727, -3.601794004440194 ], [ 144.591873168945312, -3.60235691070551 ], [ 144.5938720703125, -3.611123085021916 ] ] ], [ [ [ 144.820007324218977, -3.596944093704224 ], [ 144.83367919921875, -3.615334987640324 ], [ 144.81939697265625, -3.625736951828003 ], [ 144.803970336914062, -3.6146080493927 ], [ 144.820007324218977, -3.596944093704224 ] ] ], [ [ [ 144.588058471679688, -3.513334035873356 ], [ 144.585815429687727, -3.51067399978632 ], [ 144.586395263672102, -3.50888991355896 ], [ 144.588607788085938, -3.512778043746891 ], [ 144.588058471679688, -3.513334035873356 ] ] ], [ [ [ 143.604171752929801, -3.506942987442017 ], [ 143.601943969726562, -3.506390094757023 ], [ 143.603332519531477, -3.504167079925537 ], [ 143.605560302734375, -3.505554914474487 ], [ 143.604171752929801, -3.506942987442017 ] ] ], [ [ [ 144.604171752929688, -3.496388912200928 ], [ 144.62318420410179, -3.50957798957819 ], [ 144.61763000488304, -3.518471002578679 ], [ 144.589935302734375, -3.51294207572937 ], [ 144.604171752929688, -3.496388912200928 ] ] ], [ [ [ 143.49063110351608, -3.409612894058114 ], [ 143.482284545898551, -3.405694961547852 ], [ 143.485092163086165, -3.400899887084961 ], [ 143.490814208984602, -3.402834892272949 ], [ 143.49063110351608, -3.409612894058114 ] ] ], [ [ [ 143.44465637207054, -3.389448881149292 ], [ 143.453506469726904, -3.392023086547852 ], [ 143.461227416992415, -3.397479057312012 ], [ 143.436370849609375, -3.391844987869263 ], [ 143.44465637207054, -3.389448881149292 ] ] ], [ [ [ 144.413604736328239, -3.38277792930603 ], [ 144.424758911132812, -3.398967027664185 ], [ 144.383895874023551, -3.398612022399846 ], [ 144.398605346679688, -3.38388800621027 ], [ 144.413604736328239, -3.38277792930603 ] ] ], [ [ [ 143.553390502929801, -3.384227991104126 ], [ 143.594543457031364, -3.392268896102848 ], [ 143.636108398437727, -3.419203996658325 ], [ 143.56843566894554, -3.448012113571167 ], [ 143.545791625976676, -3.434252977371216 ], [ 143.559448242187614, -3.429444074630737 ], [ 143.550735473632926, -3.415019035339242 ], [ 143.574386596679801, -3.413183927536011 ], [ 143.536804199218864, -3.386810064315796 ], [ 143.553390502929801, -3.384227991104126 ] ] ], [ [ [ 143.121948242187614, -3.354166030883789 ], [ 143.201950073242188, -3.368055105209351 ], [ 143.236663818359375, -3.391944885253849 ], [ 143.420272827148551, -3.409722089767456 ], [ 143.46388244628929, -3.438610076904297 ], [ 143.51361083984375, -3.44166707992548 ], [ 143.557006835937955, -3.474510908126774 ], [ 143.574172973633267, -3.513056039810124 ], [ 143.596343994140739, -3.517442941665593 ], [ 143.593338012695312, -3.539443969726562 ], [ 143.61305236816429, -3.55666708946228 ], [ 143.632781982421989, -3.548332929611149 ], [ 143.631668090820312, -3.566112041473389 ], [ 143.676940917968864, -3.579998970031738 ], [ 143.703048706054688, -3.551110982894841 ], [ 143.695556640625, -3.585555076599121 ], [ 143.707504272461051, -3.599723100662231 ], [ 143.783050537109489, -3.620277881622258 ], [ 143.824722290039062, -3.647778034210205 ], [ 143.828613281250455, -3.675833940505981 ], [ 143.925277709961051, -3.715958118438721 ], [ 143.974716186523892, -3.789722919464054 ], [ 144.016281127929915, -3.79562592506403 ], [ 143.997955322265852, -3.797076940536499 ], [ 144.00250244140625, -3.819444894790649 ], [ 144.02333068847679, -3.819166898727417 ], [ 144.03277587890625, -3.795833110809212 ], [ 144.009170532226562, -3.798888921737671 ], [ 144.019638061523438, -3.794450044631958 ], [ 144.174728393554688, -3.778611898422241 ], [ 144.14971923828125, -3.798610925674438 ], [ 144.117156982421989, -3.799504995346069 ], [ 144.091384887695312, -3.813055992126408 ], [ 144.086669921875227, -3.826942920684758 ], [ 144.118057250976562, -3.802221059799137 ], [ 144.126388549804801, -3.824999094009343 ], [ 144.180831909179688, -3.846389055252018 ], [ 144.204162597656477, -3.814421892166138 ], [ 144.215270996093864, -3.853888988494816 ], [ 144.26300048828125, -3.868385076522827 ], [ 144.24305725097679, -3.841109991073608 ], [ 144.288116455078239, -3.816250085830688 ], [ 144.27583312988304, -3.798610925674438 ], [ 144.302505493164062, -3.805000066757202 ], [ 144.316680908203352, -3.830190896987915 ], [ 144.35652160644554, -3.814929962158203 ], [ 144.369766235351676, -3.827138900756779 ], [ 144.365585327148551, -3.831732034683228 ], [ 144.36476135253929, -3.838222980499268 ], [ 144.38330078125, -3.877825021743774 ], [ 144.339843750000114, -3.878259897232056 ], [ 144.360565185547102, -3.887468099594059 ], [ 144.385528564453352, -3.879344940185547 ], [ 144.367630004883267, -3.831814050674438 ], [ 144.411117553711392, -3.8247230052948 ], [ 144.432785034179688, -3.804444074630737 ], [ 144.43055725097679, -3.798888921737671 ], [ 144.408889770507926, -3.8247230052948 ], [ 144.366943359375, -3.823889017104989 ], [ 144.35749816894554, -3.808056116104126 ], [ 144.37249755859375, -3.8002769947052 ], [ 144.370834350586051, -3.794167041778564 ], [ 144.365615844726562, -3.793881893157845 ], [ 144.3558349609375, -3.80472207069397 ], [ 144.35382080078125, -3.796471118927002 ], [ 144.350311279296989, -3.794061899185181 ], [ 144.324172973632812, -3.816111087799015 ], [ 144.309448242187727, -3.802500009536686 ], [ 144.315551757812727, -3.786662101745549 ], [ 144.296112060546989, -3.799166917800903 ], [ 144.282501220703125, -3.780277967453003 ], [ 144.319442749023779, -3.784444093704167 ], [ 144.320678710937727, -3.792999982833862 ], [ 144.324707031250227, -3.797522068023625 ], [ 144.323059082031364, -3.785217046737671 ], [ 144.376388549804915, -3.784444093704167 ], [ 144.535888671875, -3.818093061447144 ], [ 144.52777099609375, -3.857414960861149 ], [ 144.545776367187955, -3.852014064788818 ], [ 144.562606811523551, -3.880758047103882 ], [ 144.547363281250114, -3.906836032867432 ], [ 144.542068481445312, -3.904804944992009 ], [ 144.555099487304915, -3.883447885513306 ], [ 144.556274414062614, -3.875654935836735 ], [ 144.548889160156364, -3.868887901306152 ], [ 144.55426025390625, -3.883099079132023 ], [ 144.514160156250114, -3.944165945053101 ], [ 144.479995727539176, -3.921387910842896 ], [ 144.466094970703239, -3.92430305480957 ], [ 144.480560302734489, -3.925278902053833 ], [ 144.474441528320767, -3.9375 ], [ 144.472778320312614, -3.953054904937687 ], [ 144.447494506836165, -3.941665887832642 ], [ 144.511199951172102, -3.994075059890747 ], [ 144.497772216796989, -3.976387977600041 ], [ 144.509445190429688, -3.967221975326538 ], [ 144.508926391601676, -3.964694023132267 ], [ 144.505981445312841, -3.962291955947819 ], [ 144.512222290039176, -3.962776899337712 ], [ 144.518051147460938, -3.968333959579468 ], [ 144.519729614257812, -3.975831985473576 ], [ 144.526947021484489, -3.983889102935791 ], [ 144.515655517578239, -4.004267215728703 ], [ 144.525695800781477, -4.008264064788705 ], [ 144.528610229492642, -3.985832929611206 ], [ 144.5191650390625, -3.970278024673348 ], [ 144.52777099609375, -3.95777702331543 ], [ 144.522506713867642, -3.941387891769409 ], [ 144.544860839843864, -3.907910108566284 ], [ 144.544250488281705, -3.959467887878361 ], [ 144.57588195800804, -3.997989892959595 ], [ 144.574218750000114, -4.58783483505249 ], [ 144.03211975097679, -4.993134021759033 ], [ 143.353912353515739, -5.136535167694092 ], [ 143.317810058593977, -5.158234119415283 ], [ 143.251617431640852, -5.120835781097412 ], [ 143.100311279296875, -5.10373592376709 ], [ 143.051818847656591, -5.105134963989258 ], [ 143.007507324218864, -5.128935813903752 ], [ 142.85101318359375, -5.029835224151611 ], [ 142.787017822265739, -5.026834964752197 ], [ 142.750717163086165, -5.042234897613469 ], [ 142.66511535644554, -4.982234954833984 ], [ 142.560806274414176, -4.991934776306152 ], [ 142.452117919921989, -4.96263408660883 ], [ 142.389816284179688, -4.993134021759033 ], [ 142.324310302734489, -4.941134929656982 ], [ 142.322616577148551, -4.636435031890869 ], [ 142.309616088867301, -4.613533973693791 ], [ 141.383010864258267, -4.613433837890625 ], [ 141.347610473632812, -4.602034091949406 ], [ 141.340118408203239, -4.259035110473633 ], [ 141.36660766601608, -4.235033988952637 ], [ 141.71630859375, -3.99073600769043 ], [ 141.762817382812614, -4.00083398818964 ], [ 141.772720336914176, -4.025834083557129 ], [ 141.834716796875114, -4.059733867645264 ], [ 142.528320312500227, -4.05703592300415 ], [ 142.539718627929688, -3.93013596534729 ], [ 142.616714477539062, -3.920536041259766 ], [ 142.628906250000114, -3.90603399276722 ], [ 142.638519287109375, -3.792335033416748 ], [ 142.609619140625227, -3.667733907699528 ], [ 142.615615844726562, -3.555334091186523 ], [ 142.642013549804801, -3.516834974288884 ], [ 142.619613647461279, -3.44013500213623 ], [ 142.695709228515739, -3.444534063339177 ], [ 142.772308349609602, -3.401532888412476 ], [ 142.856719970703125, -3.471934080123901 ], [ 142.958419799804688, -3.495135068893376 ], [ 143.039215087890739, -3.538434028625488 ], [ 143.0841064453125, -3.529634952545109 ], [ 143.08941650390625, -3.369136095046997 ], [ 143.121948242187614, -3.354166030883789 ] ] ], [ [ [ 144.20106506347679, -3.347440004348755 ], [ 144.214996337890852, -3.351111888885441 ], [ 144.221313476562727, -3.362726926803589 ], [ 144.195175170898665, -3.36004900932312 ], [ 144.20106506347679, -3.347440004348755 ] ] ], [ [ [ 143.537506103515852, -3.309722900390568 ], [ 143.606384277343977, -3.350833892822209 ], [ 143.61610412597679, -3.367777109146118 ], [ 143.570831298828125, -3.378887891769409 ], [ 143.510284423828239, -3.355556011199951 ], [ 143.50166320800804, -3.33250093460083 ], [ 143.51361083984375, -3.340832948684579 ], [ 143.521118164062727, -3.324166059494019 ], [ 143.509719848632926, -3.31722092628479 ], [ 143.537506103515852, -3.309722900390568 ] ] ], [ [ [ 143.337783813476562, -3.241666078567505 ], [ 143.335830688476562, -3.24222207069397 ], [ 143.334228515625455, -3.240693092346191 ], [ 143.336395263672216, -3.239722013473511 ], [ 143.337783813476562, -3.241666078567505 ] ] ], [ [ [ 143.297851562500114, -3.213730096817017 ], [ 143.317764282226562, -3.233092069625798 ], [ 143.333053588867415, -3.241666078567505 ], [ 143.303146362304801, -3.243773937225342 ], [ 143.273727416992301, -3.220746040344238 ], [ 143.297851562500114, -3.213730096817017 ] ] ], [ [ [ 143.254928588867301, -3.192914962768555 ], [ 143.269439697265739, -3.214999914169255 ], [ 143.255493164062614, -3.221096992492676 ], [ 143.246322631836051, -3.199819087982121 ], [ 143.254928588867301, -3.192914962768555 ] ] ], [ [ [ 144.089996337890625, -3.189166069030705 ], [ 144.133056640625, -3.228332996368408 ], [ 144.088912963867415, -3.253799915313721 ], [ 144.062500000000114, -3.21526908874506 ], [ 144.089996337890625, -3.189166069030705 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-EHG", "NAME_1": "Eastern Highlands" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 145.295211791992301, -5.884734153747502 ], [ 145.37481689453125, -5.861333847045842 ], [ 145.420318603515739, -5.934535026550293 ], [ 145.479812622070426, -5.978434085845947 ], [ 145.527114868164176, -5.973533153533879 ], [ 145.584518432617642, -5.905334949493408 ], [ 145.6588134765625, -5.921934127807617 ], [ 145.663818359375227, -5.981535911560002 ], [ 145.820617675781477, -5.975334167480469 ], [ 145.862106323242529, -5.996534824371338 ], [ 145.8878173828125, -6.048133850097599 ], [ 145.930908203125114, -6.084135055541935 ], [ 146.134017944336165, -6.206134796142521 ], [ 146.0294189453125, -6.689435005187988 ], [ 145.987411499023551, -6.740635871887207 ], [ 146.015609741210938, -6.841134071350041 ], [ 146.00660705566429, -6.886936187744141 ], [ 145.927413940429915, -6.984435081481934 ], [ 145.900909423828239, -7.098834037780762 ], [ 145.797119140625, -7.085134029388428 ], [ 145.74201965332054, -7.158435821533203 ], [ 145.693618774414517, -7.145033836364746 ], [ 145.29512023925804, -6.868734836578312 ], [ 145.3502197265625, -6.733934879302979 ], [ 145.327407836914517, -6.700533866882324 ], [ 145.303909301757926, -6.684333801269418 ], [ 145.201110839843977, -6.679935932159367 ], [ 145.104217529297102, -6.57083606719965 ], [ 144.990005493164176, -6.521335124969426 ], [ 144.990509033203125, -6.443735122680607 ], [ 145.022109985351904, -6.398334980010929 ], [ 145.1715087890625, -6.420235157012939 ], [ 145.188217163086051, -6.399334907531738 ], [ 145.182617187500227, -6.352435111999512 ], [ 145.262619018554801, -6.308835029602051 ], [ 145.25032043457054, -6.127735137939396 ], [ 145.189605712890625, -6.128933906555119 ], [ 145.13140869140625, -6.079433917999268 ], [ 145.124114990234375, -5.991734981536865 ], [ 145.16461181640625, -5.876634120941162 ], [ 145.230209350585938, -5.852434158325195 ], [ 145.26960754394554, -5.858233928680363 ], [ 145.295211791992301, -5.884734153747502 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-EPW", "NAME_1": "Enga" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 144.134613037109489, -5.148035049438477 ], [ 144.181320190429801, -5.191036224365178 ], [ 144.245819091797216, -5.218733787536621 ], [ 144.235519409180029, -5.340535163879281 ], [ 144.140518188476676, -5.351035118103027 ], [ 144.11811828613304, -5.380434036254883 ], [ 144.046112060546989, -5.413335800170898 ], [ 144.03211975097679, -5.454235076904297 ], [ 143.994415283203239, -5.478233814239388 ], [ 143.990417480468864, -5.558934211730957 ], [ 144.022216796875114, -5.594035148620549 ], [ 144.025619506836165, -5.665833950042668 ], [ 144.0537109375, -5.748233795166016 ], [ 143.954910278320312, -5.793735027313232 ], [ 143.910919189453125, -5.781233787536621 ], [ 143.867919921875114, -5.821033954620361 ], [ 143.80531311035179, -5.8211350440979 ], [ 143.770919799804688, -5.838435173034668 ], [ 143.830917358398551, -5.937035083770695 ], [ 143.709014892578352, -5.903035163879395 ], [ 143.517517089843977, -5.975135803222656 ], [ 143.355712890625, -5.877433776855469 ], [ 143.254608154296875, -5.751334190368652 ], [ 142.775115966796875, -5.594634056091252 ], [ 142.75190734863304, -5.573634147643986 ], [ 142.750717163086165, -5.042234897613469 ], [ 142.77131652832054, -5.029335021972656 ], [ 142.85101318359375, -5.029835224151611 ], [ 143.007507324218864, -5.128935813903752 ], [ 143.051818847656591, -5.105134963989258 ], [ 143.100311279296875, -5.10373592376709 ], [ 143.251617431640852, -5.120835781097412 ], [ 143.317810058593977, -5.158234119415283 ], [ 143.353912353515739, -5.136535167694092 ], [ 143.9691162109375, -5.010334014892521 ], [ 144.032913208007926, -5.066133975982666 ], [ 144.098312377930142, -5.078934192657471 ], [ 144.134613037109489, -5.148035049438477 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-GPK", "NAME_1": "Gulf" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 145.732772827148551, -7.94166707992548 ], [ 145.734725952148438, -7.943055152893066 ], [ 145.728881835937727, -7.945556163787728 ], [ 145.730270385742188, -7.943333148956299 ], [ 145.732772827148551, -7.94166707992548 ] ] ], [ [ [ 145.419128417968977, -7.941180229187012 ], [ 145.419403076171989, -7.939583778381234 ], [ 145.422058105468864, -7.940070152282715 ], [ 145.421920776367188, -7.940279006958008 ], [ 145.419128417968977, -7.941180229187012 ] ] ], [ [ [ 145.425277709961051, -7.942777156829834 ], [ 145.421951293945312, -7.94389009475708 ], [ 145.418502807617188, -7.942011833190861 ], [ 145.428329467773551, -7.938889026641789 ], [ 145.425277709961051, -7.942777156829834 ] ] ], [ [ [ 145.742584228515852, -7.935894012451172 ], [ 145.738983154297102, -7.938363075256348 ], [ 145.73591613769554, -7.938653945922738 ], [ 145.738403320312614, -7.936159133911076 ], [ 145.742584228515852, -7.935894012451172 ] ] ], [ [ [ 145.787445068359602, -7.926775932312012 ], [ 145.787506103515739, -7.925000190734863 ], [ 145.7904052734375, -7.923326969146729 ], [ 145.789993286132926, -7.925834178924561 ], [ 145.787445068359602, -7.926775932312012 ] ] ], [ [ [ 145.362777709960938, -7.878054141998291 ], [ 145.386383056640739, -7.899444103240967 ], [ 145.38667297363304, -7.906945228576603 ], [ 145.39222717285179, -7.914444923400879 ], [ 145.391387939453125, -7.918612003326359 ], [ 145.362777709960938, -7.878054141998291 ] ] ], [ [ [ 145.035003662109602, -7.82722282409668 ], [ 145.032775878906364, -7.82611083984375 ], [ 145.033340454101676, -7.823331832885685 ], [ 145.034439086914517, -7.825000762939396 ], [ 145.035003662109602, -7.82722282409668 ] ] ], [ [ [ 145.205825805664062, -7.82222223281849 ], [ 145.213607788086279, -7.827778816223088 ], [ 145.211669921875114, -7.835277080535832 ], [ 145.203887939453125, -7.825000762939396 ], [ 145.205825805664062, -7.82222223281849 ] ] ], [ [ [ 145.082778930664062, -7.816112041473332 ], [ 145.083053588867415, -7.818888187408447 ], [ 145.077987670898551, -7.821599960327148 ], [ 145.07916259765625, -7.818888187408447 ], [ 145.082778930664062, -7.816112041473332 ] ] ], [ [ [ 145.009735107421875, -7.819211959838867 ], [ 145.008285522461165, -7.823384761810303 ], [ 145.003936767578239, -7.821137905120793 ], [ 145.0089111328125, -7.815636157989502 ], [ 145.009735107421875, -7.819211959838867 ] ] ], [ [ [ 145.18110656738304, -7.821109771728459 ], [ 145.179443359375114, -7.815556049346924 ], [ 145.181945800781591, -7.809998989105225 ], [ 145.183883666992188, -7.814444065093994 ], [ 145.18110656738304, -7.821109771728459 ] ] ], [ [ [ 144.957504272460938, -7.812222003936711 ], [ 144.960281372070426, -7.815278053283691 ], [ 144.955001831054688, -7.813055992126408 ], [ 144.954437255859375, -7.806110858917236 ], [ 144.957504272460938, -7.812222003936711 ] ] ], [ [ [ 145.191665649414176, -7.799445152282715 ], [ 145.209716796875227, -7.844721794128361 ], [ 145.217224121093864, -7.850278854370117 ], [ 145.195281982421989, -7.86027717590332 ], [ 145.18110656738304, -7.827778816223088 ], [ 145.191665649414176, -7.799445152282715 ] ] ], [ [ [ 145.035827636718864, -7.829722881317139 ], [ 145.034439086914517, -7.843887805938664 ], [ 145.007873535156477, -7.837919235229435 ], [ 145.020828247070312, -7.838890075683594 ], [ 145.008895874023551, -7.828332901000977 ], [ 145.021667480468864, -7.797223091125488 ], [ 145.03179931640625, -7.827106952667179 ], [ 145.035827636718864, -7.829722881317139 ] ] ], [ [ [ 144.96534729003929, -7.79957723617548 ], [ 144.963699340820426, -7.798150062560978 ], [ 144.963897705078125, -7.796726226806641 ], [ 144.967300415039517, -7.798367023468018 ], [ 144.96534729003929, -7.79957723617548 ] ] ], [ [ [ 143.880828857422102, -7.85205602645874 ], [ 143.845046997070312, -7.801837921142521 ], [ 143.853713989257812, -7.779764175414982 ], [ 143.883041381836279, -7.831090927124023 ], [ 143.880828857422102, -7.85205602645874 ] ] ], [ [ [ 145.086624145507812, -7.779770851135254 ], [ 145.095535278320426, -7.786148071289062 ], [ 145.096923828125, -7.790279865264893 ], [ 145.08831787109375, -7.788116931915226 ], [ 145.086624145507812, -7.779770851135254 ] ] ], [ [ [ 144.204788208007926, -7.749704837799072 ], [ 144.249725341797102, -7.753055095672607 ], [ 144.272171020507812, -7.779123783111572 ], [ 144.248703002929688, -7.797749042510929 ], [ 144.194442749023892, -7.804166793823185 ], [ 144.185272216797102, -7.764999866485596 ], [ 144.191604614257926, -7.746205806732178 ], [ 144.204788208007926, -7.749704837799072 ] ] ], [ [ [ 144.868057250976562, -7.730834007263184 ], [ 144.875000000000114, -7.73305606842041 ], [ 144.874450683593864, -7.739721775054875 ], [ 144.866943359375227, -7.733612060546875 ], [ 144.868057250976562, -7.730834007263184 ] ] ], [ [ [ 144.85888671875, -7.728055000305119 ], [ 144.878326416015625, -7.758056163787785 ], [ 144.897781372070312, -7.76694393157959 ], [ 144.880828857421875, -7.78277683258051 ], [ 144.831939697265739, -7.743331909179688 ], [ 144.85888671875, -7.728055000305119 ] ] ], [ [ [ 144.399444580078239, -7.761943817138672 ], [ 144.415802001953125, -7.769712924957275 ], [ 144.365280151367188, -7.757474899291992 ], [ 144.361602783203125, -7.723396778106689 ], [ 144.399444580078239, -7.761943817138672 ] ] ], [ [ [ 143.908340454102017, -7.745697975158635 ], [ 143.973876953125, -7.786656856536865 ], [ 143.98976135253929, -7.836350917816162 ], [ 143.913955688476562, -7.799143791198674 ], [ 143.856781005859375, -7.721951961517277 ], [ 143.908340454102017, -7.745697975158635 ] ] ], [ [ [ 144.430068969726904, -7.684628963470459 ], [ 144.463607788086051, -7.713610172271729 ], [ 144.472778320312614, -7.749721050262451 ], [ 144.51690673828125, -7.803572177886963 ], [ 144.478607177734602, -7.80000114440918 ], [ 144.47528076171875, -7.780276775360051 ], [ 144.41450500488304, -7.71632719039917 ], [ 144.41424560546875, -7.685637950897217 ], [ 144.430068969726904, -7.684628963470459 ] ] ], [ [ [ 144.306945800781477, -7.647777080535889 ], [ 144.338058471679915, -7.707777976989689 ], [ 144.326110839843864, -7.717501163482609 ], [ 144.299728393555142, -7.711666107177734 ], [ 144.283340454101676, -7.663053989410287 ], [ 144.306945800781477, -7.647777080535889 ] ] ], [ [ [ 144.361801147460938, -7.637643814086857 ], [ 144.363494873046989, -7.63792181015009 ], [ 144.363769531250227, -7.638651847839242 ], [ 144.360458374023438, -7.638955116271916 ], [ 144.361801147460938, -7.637643814086857 ] ] ], [ [ [ 144.399993896484375, -7.605278015136662 ], [ 144.414993286132926, -7.632222175598145 ], [ 144.430282592773438, -7.638332843780518 ], [ 144.431671142578352, -7.652222156524601 ], [ 144.426940917968977, -7.68083381652832 ], [ 144.411941528320426, -7.685555934906006 ], [ 144.41082763671875, -7.718332767486515 ], [ 144.431671142578352, -7.736388206481877 ], [ 144.403335571289176, -7.756112098693848 ], [ 144.363052368164517, -7.703333854675293 ], [ 144.385833740234375, -7.659999847412109 ], [ 144.365005493164176, -7.625 ], [ 144.399993896484375, -7.605278015136662 ] ] ], [ [ [ 144.669998168945426, -7.605000019073429 ], [ 144.676361083984375, -7.64653491973877 ], [ 144.645004272461051, -7.651666164398137 ], [ 144.667495727539062, -7.637222766876164 ], [ 144.669998168945426, -7.605000019073429 ] ] ], [ [ [ 144.416671752929801, -7.603333950042725 ], [ 144.441116333007926, -7.611111164092961 ], [ 144.46583557128929, -7.656112194061222 ], [ 144.455276489257812, -7.699166774749699 ], [ 144.434173583984602, -7.683609962463322 ], [ 144.432785034179688, -7.637779235839844 ], [ 144.405273437500341, -7.606110095977783 ], [ 144.416671752929801, -7.603333950042725 ] ] ], [ [ [ 144.267776489257812, -7.593610763549748 ], [ 144.287506103515852, -7.63972282409668 ], [ 144.253616333007926, -7.653888225555363 ], [ 144.244720458984375, -7.610001087188721 ], [ 144.267776489257812, -7.593610763549748 ] ] ], [ [ [ 144.245834350585938, -7.592776775360051 ], [ 144.242492675781477, -7.61250114440918 ], [ 144.246948242187614, -7.650000095367432 ], [ 144.250534057617301, -7.655829906463509 ], [ 144.262771606445426, -7.659165859222412 ], [ 144.212493896484375, -7.671111106872559 ], [ 144.203048706054801, -7.657499790191594 ], [ 144.220840454101562, -7.633331775665226 ], [ 144.218338012695426, -7.613055229187012 ], [ 144.245834350585938, -7.592776775360051 ] ] ], [ [ [ 144.283050537109375, -7.590555191039982 ], [ 144.307220458984489, -7.607779026031494 ], [ 144.297500610351676, -7.64611101150507 ], [ 144.270965576171989, -7.591667175292969 ], [ 144.283050537109375, -7.590555191039982 ] ] ], [ [ [ 144.31648254394554, -7.57699012756342 ], [ 144.312774658203125, -7.575833797454777 ], [ 144.314437866211051, -7.572500228881836 ], [ 144.315917968750227, -7.574633121490422 ], [ 144.31648254394554, -7.57699012756342 ] ] ], [ [ [ 144.291671752929915, -7.572222232818604 ], [ 144.352493286132812, -7.599165916442814 ], [ 144.341659545898665, -7.632222175598145 ], [ 144.3780517578125, -7.655000209808293 ], [ 144.356384277343864, -7.684721946716309 ], [ 144.322784423828352, -7.645555019378605 ], [ 144.315002441406364, -7.605929851531926 ], [ 144.286666870117188, -7.584722995758 ], [ 144.291671752929915, -7.572222232818604 ] ] ], [ [ [ 144.386001586914176, -7.551719188690186 ], [ 144.398391723632926, -7.559063911437931 ], [ 144.415634155273438, -7.555460929870549 ], [ 144.433151245117188, -7.598157882690373 ], [ 144.4007568359375, -7.598989963531494 ], [ 144.399353027343864, -7.576255798339844 ], [ 144.386001586914176, -7.551719188690186 ] ] ], [ [ [ 143.747970581054801, -7.546935081481934 ], [ 143.766754150390625, -7.56040716171259 ], [ 143.787597656250227, -7.624787807464486 ], [ 143.752548217773551, -7.598413944244385 ], [ 143.747970581054801, -7.546935081481934 ] ] ], [ [ [ 144.381668090820312, -7.559444904327393 ], [ 144.378890991211051, -7.555278778076172 ], [ 144.380004882812727, -7.54666614532465 ], [ 144.381942749023551, -7.551109790801945 ], [ 144.381668090820312, -7.559444904327393 ] ] ], [ [ [ 144.709716796875, -7.535554885864258 ], [ 144.747772216796989, -7.554444789886475 ], [ 144.766662597656364, -7.586111068725586 ], [ 144.754165649414062, -7.629444122314453 ], [ 144.697219848633267, -7.582500934600773 ], [ 144.709716796875, -7.535554885864258 ] ] ], [ [ [ 144.542495727539176, -7.534722805023193 ], [ 144.571945190429801, -7.550556182861214 ], [ 144.586395263672102, -7.548888206481877 ], [ 144.586105346679688, -7.553331851959229 ], [ 144.593887329101676, -7.56472110748291 ], [ 144.601394653320312, -7.565277099609375 ], [ 144.576950073242188, -7.622777938842717 ], [ 144.542495727539176, -7.534722805023193 ] ] ], [ [ [ 144.651672363281364, -7.532498836517334 ], [ 144.632217407226676, -7.568056106567269 ], [ 144.653060913085938, -7.554165840148926 ], [ 144.66278076171875, -7.586389064788818 ], [ 144.651382446289062, -7.585833072662354 ], [ 144.640548706054915, -7.591942787170353 ], [ 144.661392211914062, -7.58916711807251 ], [ 144.667221069336165, -7.603888034820557 ], [ 144.654724121093864, -7.609445095062256 ], [ 144.654998779296875, -7.598889827728271 ], [ 144.651672363281364, -7.595555782318115 ], [ 144.643051147461392, -7.601109981536808 ], [ 144.639999389648892, -7.605556011199894 ], [ 144.652496337890625, -7.596943855285645 ], [ 144.652496337890625, -7.608889102935791 ], [ 144.658889770507926, -7.611945152282658 ], [ 144.666107177734602, -7.611389160156193 ], [ 144.666671752929915, -7.63555717468256 ], [ 144.641937255859375, -7.642776966094914 ], [ 144.636672973632812, -7.629166126251221 ], [ 144.633331298828239, -7.648890018463135 ], [ 144.604446411132812, -7.651944160461369 ], [ 144.599166870117415, -7.63555717468256 ], [ 144.57861328125, -7.63555717468256 ], [ 144.603607177734489, -7.578887939453125 ], [ 144.602783203125227, -7.564445018768254 ], [ 144.587219238281364, -7.547222137451172 ], [ 144.651672363281364, -7.532498836517334 ] ] ], [ [ [ 144.674163818359489, -7.527779102325439 ], [ 144.696670532226676, -7.5411119461059 ], [ 144.693603515625114, -7.560554981231633 ], [ 144.666946411132926, -7.558054924011174 ], [ 144.663055419922102, -7.53055477142334 ], [ 144.674163818359489, -7.527779102325439 ] ] ], [ [ [ 143.729751586914062, -7.513453960418701 ], [ 143.743377685546989, -7.515428066253662 ], [ 143.74983215332054, -7.521505832672062 ], [ 143.71510314941429, -7.520173072814941 ], [ 143.729751586914062, -7.513453960418701 ] ] ], [ [ [ 144.699172973632926, -7.495555877685547 ], [ 144.699172973632926, -7.529167175292912 ], [ 144.66278076171875, -7.497499942779541 ], [ 144.682495117187614, -7.492221832275391 ], [ 144.69000244140625, -7.480277061462402 ], [ 144.699172973632926, -7.495555877685547 ] ] ], [ [ [ 144.630310058593864, -7.458053112030029 ], [ 144.670562744140739, -7.526388168334961 ], [ 144.616668701171875, -7.536388874053955 ], [ 144.616394042968864, -7.516943931579533 ], [ 144.608337402344205, -7.50333309173584 ], [ 144.620559692382926, -7.478332996368408 ], [ 144.610275268554688, -7.469721794128361 ], [ 144.630310058593864, -7.458053112030029 ] ] ], [ [ [ 144.750839233398551, -7.453610897064209 ], [ 144.744171142578125, -7.47138786315918 ], [ 144.756942749023551, -7.510554790496769 ], [ 144.731643676757812, -7.503098011016846 ], [ 144.737930297851562, -7.485436916351262 ], [ 144.714172363281477, -7.534444808959961 ], [ 144.697784423828352, -7.466944217681828 ], [ 144.750839233398551, -7.453610897064209 ] ] ], [ [ [ 144.571105957031364, -7.443056106567383 ], [ 144.591461181640625, -7.475752830505314 ], [ 144.586395263672102, -7.503055095672607 ], [ 144.612777709961051, -7.517221927642765 ], [ 144.576950073242188, -7.549722194671574 ], [ 144.560562133789062, -7.538610935211182 ], [ 144.574447631836051, -7.530001163482609 ], [ 144.581115722656364, -7.519721984863224 ], [ 144.581390380859602, -7.516111850738525 ], [ 144.561111450195312, -7.535554885864258 ], [ 144.539443969726676, -7.529445171356144 ], [ 144.5655517578125, -7.479444980621281 ], [ 144.556671142578239, -7.452498912811222 ], [ 144.571105957031364, -7.443056106567383 ] ] ], [ [ [ 144.597229003906477, -7.433611869811898 ], [ 144.617782592773438, -7.456944942474365 ], [ 144.608673095703352, -7.471176147460881 ], [ 144.618331909179688, -7.479444980621281 ], [ 144.603332519531477, -7.508333206176701 ], [ 144.584442138672102, -7.451944828033447 ], [ 144.576660156250227, -7.44388818740839 ], [ 144.597229003906477, -7.433611869811898 ] ] ], [ [ [ 144.553329467773438, -7.410833835601807 ], [ 144.583892822265852, -7.435555934905949 ], [ 144.555831909179915, -7.451666831970215 ], [ 144.54499816894554, -7.44388818740839 ], [ 144.552505493164176, -7.435555934905949 ], [ 144.553329467773438, -7.410833835601807 ] ] ], [ [ [ 144.558609008789176, -7.399167060852051 ], [ 144.547775268554688, -7.404720783233586 ], [ 144.544448852539176, -7.411665916442814 ], [ 144.537780761718864, -7.397777080535889 ], [ 144.54804992675804, -7.393332004547062 ], [ 144.556106567382812, -7.386387825012207 ], [ 144.558609008789176, -7.399167060852051 ] ] ], [ [ [ 144.703109741211165, -6.712035179138127 ], [ 144.761917114257926, -6.709134101867619 ], [ 144.851806640625, -6.747634887695256 ], [ 144.913619995117188, -6.725635051727295 ], [ 144.982406616211051, -6.791234970092773 ], [ 145.142318725585938, -6.836434841156006 ], [ 145.207214355468977, -6.814233779907227 ], [ 145.693618774414517, -7.145033836364746 ], [ 145.74201965332054, -7.158435821533203 ], [ 146.054519653320312, -7.368636131286564 ], [ 146.075210571289062, -7.395433902740422 ], [ 146.079711914062614, -7.49693489074707 ], [ 146.117309570312841, -7.552834987640381 ], [ 146.412612915039062, -7.609135150909424 ], [ 146.652511596680029, -7.772534847259521 ], [ 146.541107177734489, -7.825333118438721 ], [ 146.486419677734375, -7.9082350730896 ], [ 146.395309448242415, -7.913435935974121 ], [ 146.383316040039517, -7.928234100341797 ], [ 146.382568359375114, -8.587371826171818 ], [ 146.269729614257812, -8.410278320312443 ], [ 146.267227172851904, -8.353887557983398 ], [ 146.278884887695312, -8.350000381469727 ], [ 146.248336791992301, -8.319167137145939 ], [ 146.234970092773551, -8.27141284942627 ], [ 146.246948242187614, -8.303888320922795 ], [ 146.253067016601676, -8.309855461120605 ], [ 146.249725341796875, -8.295277595519963 ], [ 146.281509399414176, -8.31196117401123 ], [ 146.289031982422102, -8.308637619018555 ], [ 146.251388549804801, -8.291945457458496 ], [ 146.231323242187614, -8.260352134704476 ], [ 146.197784423828239, -8.236666679382267 ], [ 146.155960083008267, -8.224585533142033 ], [ 146.168609619140739, -8.2124986648559 ], [ 146.171112060546875, -8.190834045410099 ], [ 146.16944885253929, -8.1875 ], [ 146.159439086914176, -8.184166908264103 ], [ 146.168060302734375, -8.180832862853947 ], [ 146.15777587890625, -8.182223320007267 ], [ 146.159439086914176, -8.1875 ], [ 146.169723510742188, -8.191665649414062 ], [ 146.15777587890625, -8.218609809875431 ], [ 146.112228393554915, -8.185555458068848 ], [ 146.092651367187614, -8.157453536987305 ], [ 146.082839965820312, -8.135579109191895 ], [ 146.11083984375, -8.164443969726562 ], [ 146.10292053222679, -8.129028320312443 ], [ 146.130889892578125, -8.136522293090763 ], [ 146.105834960937614, -8.124030113220215 ], [ 146.095230102539062, -8.135449409484806 ], [ 146.074996948242188, -8.117778778076115 ], [ 146.073059082031591, -8.098054885864258 ], [ 146.095367431640739, -8.10081672668457 ], [ 146.095932006836051, -8.091262817382756 ], [ 146.071105957031364, -8.094445228576603 ], [ 146.007171630859602, -8.059165954589844 ], [ 145.827774047851904, -8.030834197998047 ], [ 145.759445190429801, -7.961111068725586 ], [ 145.799728393554801, -7.960555076599121 ], [ 145.796112060547216, -7.975555896759033 ], [ 145.80860900878929, -7.986391067504883 ], [ 145.817214965820767, -7.985279083251953 ], [ 145.797500610351562, -7.974443912506104 ], [ 145.801940917968977, -7.959935188293457 ], [ 145.775283813476562, -7.939999103546143 ], [ 145.793884277343977, -7.926943778991642 ], [ 145.794174194336051, -7.91944408416748 ], [ 145.812774658203352, -7.905001163482552 ], [ 145.81304931640625, -7.900278091430664 ], [ 145.768890380859375, -7.94166707992548 ], [ 145.746109008789176, -7.932778835296631 ], [ 145.755554199218977, -7.925278186798096 ], [ 145.756393432617301, -7.911666870117188 ], [ 145.725708007812614, -7.9443039894104 ], [ 145.717102050781364, -7.946940898895264 ], [ 145.707504272461051, -7.938889026641789 ], [ 145.69561767578125, -7.940762996673584 ], [ 145.717391967773438, -7.948609828948975 ], [ 145.731109619140625, -7.946944236755314 ], [ 145.747222900390739, -7.938333034515324 ], [ 145.75917053222679, -7.946390151977539 ], [ 145.716110229492415, -7.958889007568303 ], [ 145.652221679687727, -7.956943988800049 ], [ 145.626113891601676, -7.936110973358097 ], [ 145.418243408203239, -7.950353145599308 ], [ 145.414718627929915, -7.946944236755314 ], [ 145.427780151367301, -7.942777156829834 ], [ 145.434753417968864, -7.932468891143799 ], [ 145.404449462890852, -7.945556163787728 ], [ 145.387771606445312, -7.899444103240967 ], [ 145.370285034179801, -7.88027715682972 ], [ 145.341949462890739, -7.863890171050969 ], [ 145.279449462890625, -7.85001897811884 ], [ 145.226394653320312, -7.858611106872559 ], [ 145.223541259765625, -7.842775821685791 ], [ 145.196945190430142, -7.801667213439885 ], [ 145.161392211914062, -7.783889770507756 ], [ 145.191116333007812, -7.767083168029785 ], [ 145.158050537109489, -7.776389122009277 ], [ 145.178482055664176, -7.849024772643986 ], [ 145.105270385742529, -7.820278167724609 ], [ 145.097778320312614, -7.783889770507756 ], [ 145.061950683593864, -7.766387939453125 ], [ 145.100280761718864, -7.800555229186955 ], [ 145.06111145019554, -7.826944828033447 ], [ 145.091949462890625, -7.809720993041992 ], [ 145.070556640625341, -7.836668014526367 ], [ 145.043212890625455, -7.844719886779785 ], [ 145.016403198242188, -7.769686222076416 ], [ 144.998062133789176, -7.755277156829834 ], [ 145.01972961425804, -7.788611888885498 ], [ 144.99972534179733, -7.820480823516846 ], [ 144.953826904297216, -7.781576156616154 ], [ 144.962219238281591, -7.745278835296631 ], [ 144.946395874023438, -7.773889064788818 ], [ 144.927215576172102, -7.765833854675293 ], [ 144.930282592773665, -7.736388206481877 ], [ 144.926116943359489, -7.713888168334961 ], [ 144.938613891601562, -7.703889846801758 ], [ 144.936386108398665, -7.702777862548828 ], [ 144.927780151367301, -7.707499980926457 ], [ 144.923049926758267, -7.718057155609017 ], [ 144.921951293945426, -7.756668090820312 ], [ 144.9281005859375, -7.769498825073242 ], [ 144.958892822265852, -7.798611164092961 ], [ 144.966629028320312, -7.800514221191293 ], [ 144.9561767578125, -7.804787158966008 ], [ 144.87648010253929, -7.75242805480957 ], [ 144.895202636719205, -7.721333980560303 ], [ 144.880340576171989, -7.727090835571289 ], [ 144.880477905273551, -7.715168952941838 ], [ 144.887023925781364, -7.707684993743896 ], [ 144.889801025390625, -7.701444149017277 ], [ 144.897171020507926, -7.672611236572209 ], [ 144.878677368164404, -7.715168952941838 ], [ 144.879516601562727, -7.728894233703556 ], [ 144.8619384765625, -7.723610877990723 ], [ 144.871383666992301, -7.706389904022217 ], [ 144.852218627929688, -7.655000209808293 ], [ 144.875000000000114, -7.656112194061222 ], [ 144.884994506835938, -7.650278091430664 ], [ 144.886947631836165, -7.638888835906982 ], [ 144.89166259765625, -7.642498970031681 ], [ 144.906661987304801, -7.63972282409668 ], [ 144.91499328613304, -7.631944179534912 ], [ 144.886672973632926, -7.636944770812988 ], [ 144.874725341796875, -7.65472221374506 ], [ 144.850601196289062, -7.652976036071777 ], [ 144.852218627929688, -7.630556106567383 ], [ 144.866104125976562, -7.630832195281926 ], [ 144.880828857421875, -7.626944065093994 ], [ 144.899444580078239, -7.616388797759953 ], [ 144.852783203125, -7.628888130187988 ], [ 144.84864807128929, -7.612771987914982 ], [ 144.876937866211051, -7.58055400848383 ], [ 144.885833740234602, -7.582778930664006 ], [ 144.889450073242415, -7.593332767486515 ], [ 144.89739990234375, -7.596041202545166 ], [ 144.886672973632926, -7.580278873443604 ], [ 144.873611450195426, -7.578609943389893 ], [ 144.874725341796875, -7.572222232818604 ], [ 144.871109008789062, -7.567221164703369 ], [ 144.890853881836051, -7.556663990020695 ], [ 144.881103515625114, -7.555553913116455 ], [ 144.863891601562727, -7.571944236755371 ], [ 144.85333251953125, -7.55916690826416 ], [ 144.845001220703239, -7.558332920074406 ], [ 144.8619384765625, -7.552499771118107 ], [ 144.84722900390625, -7.552499771118107 ], [ 144.84388732910179, -7.5602769851684 ], [ 144.862503051757812, -7.572778224945012 ], [ 144.873336791992529, -7.572778224945012 ], [ 144.851181030273551, -7.583497047424316 ], [ 144.813690185546875, -7.551013946533146 ], [ 144.84388732910179, -7.595409870147705 ], [ 144.833892822265625, -7.627222061157227 ], [ 144.828048706054915, -7.619166851043701 ], [ 144.811660766602017, -7.623055934905949 ], [ 144.813049316406364, -7.611389160156193 ], [ 144.80305480957054, -7.604722023010197 ], [ 144.811386108398438, -7.624444007873535 ], [ 144.836395263671875, -7.634165763854924 ], [ 144.81805419921875, -7.681387901306152 ], [ 144.778884887695312, -7.673611164093018 ], [ 144.796386718750227, -7.656112194061222 ], [ 144.756668090820312, -7.663053989410287 ], [ 144.770553588867188, -7.564445018768254 ], [ 144.784729003906364, -7.565277099609375 ], [ 144.796386718750227, -7.540833950042668 ], [ 144.794174194336051, -7.537776947021371 ], [ 144.790832519531364, -7.536666870117188 ], [ 144.78277587890625, -7.538888931274414 ], [ 144.794998168945312, -7.540833950042668 ], [ 144.781982421875, -7.544962882995605 ], [ 144.784439086914176, -7.563889026641789 ], [ 144.755828857421989, -7.541665077209473 ], [ 144.773056030273438, -7.528057098388672 ], [ 144.78582763671875, -7.497499942779541 ], [ 144.794723510742301, -7.498610019683781 ], [ 144.800827026367301, -7.492221832275391 ], [ 144.785003662109489, -7.496387958526554 ], [ 144.754714965820312, -7.540555000305119 ], [ 144.761276245117415, -7.569625854492131 ], [ 144.751480102539062, -7.553059101104736 ], [ 144.722503662109375, -7.534722805023193 ], [ 144.730560302734489, -7.507777214050236 ], [ 144.745285034180142, -7.515833854675293 ], [ 144.759719848632812, -7.510554790496769 ], [ 144.752548217773551, -7.441336154937744 ], [ 144.714050292968864, -7.441948890685978 ], [ 144.68861389160179, -7.469443798065186 ], [ 144.68305969238304, -7.46083402633667 ], [ 144.675277709961165, -7.459167957305908 ], [ 144.67388916015625, -7.453888893127441 ], [ 144.69305419921875, -7.449722766876221 ], [ 144.698257446289062, -7.443397998809814 ], [ 144.691238403320312, -7.432861804962101 ], [ 144.673583984375114, -7.423298835754395 ], [ 144.6795654296875, -7.407771110534668 ], [ 144.676635742187614, -7.399730205535889 ], [ 144.672195434570426, -7.422741889953613 ], [ 144.696395874023438, -7.444722175598031 ], [ 144.673049926757926, -7.452776908874455 ], [ 144.682220458984716, -7.487220764160099 ], [ 144.661392211914062, -7.490555763244629 ], [ 144.595932006836165, -7.414475917816105 ], [ 144.58917236328125, -7.434442996978703 ], [ 144.573883056640966, -7.423333168029728 ], [ 144.588882446289517, -7.404720783233586 ], [ 144.592498779297102, -7.377499103546143 ], [ 144.573745727539062, -7.349321842193604 ], [ 144.589447021484602, -7.379446029663086 ], [ 144.571105957031364, -7.422777175903263 ], [ 144.568328857421989, -7.400555133819466 ], [ 144.54804992675804, -7.40861177444458 ], [ 144.56027221679733, -7.400277137756291 ], [ 144.560562133789062, -7.378055095672607 ], [ 144.531951904296875, -7.398333072662354 ], [ 144.526107788086165, -7.387499809265137 ], [ 144.536117553711279, -7.38361215591425 ], [ 144.536239624023892, -7.354893207550049 ], [ 144.525558471680142, -7.361112117767334 ], [ 144.524993896484489, -7.389443874359131 ], [ 144.548919677734375, -7.431629180908146 ], [ 144.521392822265625, -7.434999942779484 ], [ 144.5574951171875, -7.475000858306885 ], [ 144.52955627441429, -7.50599479675293 ], [ 144.51277160644554, -7.503611087799072 ], [ 144.524444580078125, -7.575555801391545 ], [ 144.508605957031364, -7.620276927947998 ], [ 144.485549926757926, -7.592220783233586 ], [ 144.500549316406477, -7.571387767791748 ], [ 144.503936767578125, -7.54185676574707 ], [ 144.496139526367415, -7.537836074829102 ], [ 144.474746704101562, -7.532003879547062 ], [ 144.503448486328239, -7.54455995559681 ], [ 144.481674194336165, -7.549722194671574 ], [ 144.47027587890625, -7.561944961547795 ], [ 144.467773437500114, -7.559444904327393 ], [ 144.471389770508267, -7.551109790801945 ], [ 144.46888732910179, -7.538610935211182 ], [ 144.464447021484375, -7.536110877990723 ], [ 144.458328247070312, -7.537776947021371 ], [ 144.45166015625, -7.534166812896729 ], [ 144.458328247070312, -7.539166927337646 ], [ 144.467773437500114, -7.539445877075082 ], [ 144.470001220703352, -7.547778129577637 ], [ 144.46638488769554, -7.559444904327393 ], [ 144.468338012695767, -7.562499046325684 ], [ 144.496109008789062, -7.556666851043701 ], [ 144.498886108398438, -7.566946029663086 ], [ 144.48388671875, -7.585277080535889 ], [ 144.484161376953352, -7.596943855285645 ], [ 144.55389404296875, -7.679165840148926 ], [ 144.518890380859489, -7.684999942779541 ], [ 144.475830078125114, -7.603055953979379 ], [ 144.446670532226562, -7.581387996673527 ], [ 144.441116333007926, -7.53694486618042 ], [ 144.397216796875114, -7.553331851959229 ], [ 144.388885498046875, -7.537498950958195 ], [ 144.376937866211051, -7.539999008178654 ], [ 144.396667480468864, -7.575277805328369 ], [ 144.398895263672102, -7.602221965789738 ], [ 144.3619384765625, -7.559444904327393 ], [ 144.353881835937727, -7.560554981231633 ], [ 144.342498779296989, -7.568056106567269 ], [ 144.335281372070312, -7.568334102630615 ], [ 144.32833862304733, -7.561666965484562 ], [ 144.330001831054915, -7.558332920074406 ], [ 144.339172363281364, -7.563055038452148 ], [ 144.3427734375, -7.56138896942133 ], [ 144.3427734375, -7.557222843170166 ], [ 144.33749389648483, -7.548056125640869 ], [ 144.341659545898665, -7.560832977294865 ], [ 144.33111572265625, -7.556944847106934 ], [ 144.327774047851676, -7.558888912200814 ], [ 144.326110839843864, -7.564167022705021 ], [ 144.336944580078239, -7.570278167724553 ], [ 144.346664428711051, -7.568056106567269 ], [ 144.36083984375, -7.5602769851684 ], [ 144.383895874023551, -7.59944391250599 ], [ 144.354171752929688, -7.635831832885685 ], [ 144.343612670898551, -7.629444122314453 ], [ 144.355560302734602, -7.594442844390869 ], [ 144.321670532226676, -7.580832004547062 ], [ 144.316390991211279, -7.563611030578556 ], [ 144.303604125976676, -7.576387882232666 ], [ 144.28138732910179, -7.562499046325684 ], [ 144.279998779296875, -7.583333015441895 ], [ 144.255828857422102, -7.591667175292969 ], [ 144.2459716796875, -7.58882999420166 ], [ 144.242095947265852, -7.570213794708138 ], [ 144.233917236328352, -7.557511806488037 ], [ 144.227523803710938, -7.552799224853516 ], [ 144.24421691894554, -7.58828687667841 ], [ 144.220550537109602, -7.607501029968262 ], [ 144.215744018554688, -7.597115039825439 ], [ 144.206390380859375, -7.594168186187687 ], [ 144.218612670898665, -7.629444122314453 ], [ 144.197784423828125, -7.64611101150507 ], [ 144.17304992675804, -7.605000019073429 ], [ 144.191390991211392, -7.606110095977783 ], [ 144.195007324218977, -7.599721908569336 ], [ 144.187774658203239, -7.571944236755371 ], [ 144.176940917968864, -7.565277099609375 ], [ 144.193328857421875, -7.602221965789738 ], [ 144.173889160156364, -7.602221965789738 ], [ 144.162200927734602, -7.617351055145264 ], [ 144.172775268554688, -7.610001087188721 ], [ 144.206390380859375, -7.676390171050969 ], [ 144.256393432617301, -7.685277938842773 ], [ 144.258331298828352, -7.710278034210148 ], [ 144.2288818359375, -7.740277767181283 ], [ 144.20472717285179, -7.741387844085637 ], [ 144.153610229492415, -7.6875 ], [ 144.143890380859602, -7.695555210113469 ], [ 144.180557250976676, -7.741109848022461 ], [ 144.171356201172102, -7.763377189636174 ], [ 144.155838012695312, -7.741943836212101 ], [ 144.124160766601562, -7.726110935211182 ], [ 144.171356201172102, -7.768246173858643 ], [ 144.150054931640739, -7.79797887802124 ], [ 144.107833862304915, -7.778800010681152 ], [ 144.08123779296875, -7.722352981567326 ], [ 144.036392211914404, -7.717223167419377 ], [ 144.080551147461165, -7.731871128082275 ], [ 144.078887939453125, -7.771944999694767 ], [ 143.988815307617415, -7.726801872253418 ], [ 143.905380249023438, -7.712495803833008 ], [ 143.825836181640625, -7.65472221374506 ], [ 143.765548706055029, -7.526356220245361 ], [ 143.749542236328125, -7.514832973480225 ], [ 143.731185913086051, -7.510601043701172 ], [ 143.695510864257812, -7.515478134155217 ], [ 143.700607299804915, -7.533194065093994 ], [ 143.746063232421989, -7.543087959289551 ], [ 143.744232177734375, -7.591330051422062 ], [ 143.820358276367415, -7.713730812072697 ], [ 143.841812133789176, -7.770157814025879 ], [ 143.838973999023551, -7.812693119049072 ], [ 143.911911010742415, -7.952212810516301 ], [ 143.891220092773551, -7.944035053253117 ], [ 143.05610656738304, -7.083835124969482 ], [ 142.995513916015625, -6.999135017394963 ], [ 142.99472045898483, -6.822734832763672 ], [ 143.934707641601676, -6.822734832763672 ], [ 144.703109741211165, -6.712035179138127 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-HLA", "NAME_1": "Hela" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 142.389816284179688, -4.993134021759033 ], [ 142.452117919921989, -4.96263408660883 ], [ 142.560806274414176, -4.991934776306152 ], [ 142.66511535644554, -4.982234954833984 ], [ 142.706405639648438, -5.001235961914062 ], [ 142.750717163086165, -5.042234897613469 ], [ 142.755615234375, -5.581134796142578 ], [ 143.254608154296875, -5.751334190368652 ], [ 143.331207275390625, -5.85403394699091 ], [ 143.396316528320312, -5.909033775329533 ], [ 143.394012451171875, -6.070633888244572 ], [ 143.417007446289517, -6.093635082244873 ], [ 143.375808715820767, -6.094034194946232 ], [ 143.376007080078239, -6.155035018920898 ], [ 143.17181396484375, -6.165235996246338 ], [ 143.16120910644554, -6.293034076690617 ], [ 143.080413818359489, -6.30323600769043 ], [ 143.080215454101676, -6.358434200286865 ], [ 142.886520385742415, -6.242636203765812 ], [ 142.683517456054688, -6.18023490905756 ], [ 142.627212524414176, -6.179833889007568 ], [ 142.626007080078352, -5.903635025024414 ], [ 142.570114135742415, -5.882334232330265 ], [ 142.06697082519554, -5.469642162322998 ], [ 142.081817626953352, -5.412435054778996 ], [ 142.1815185546875, -5.32333517074585 ], [ 142.303115844727017, -5.325634002685433 ], [ 142.321105957031364, -5.186134815216064 ], [ 142.290512084961165, -5.109734058380013 ], [ 142.320816040039176, -5.069036006927377 ], [ 142.324310302734489, -4.941134929656982 ], [ 142.389816284179688, -4.993134021759033 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-JWK", "NAME_1": "Jiwaka" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 144.75701904296875, -5.494135856628418 ], [ 144.779510498046875, -5.536135196685734 ], [ 144.879608154296989, -5.601233959197884 ], [ 144.91731262207054, -5.650634765624943 ], [ 144.9840087890625, -5.661633968353215 ], [ 144.994720458984602, -5.719933986663818 ], [ 145.026412963867415, -5.775935173034554 ], [ 144.881820678711165, -5.809534072875977 ], [ 144.8297119140625, -5.783133983612061 ], [ 144.81031799316429, -5.805533885955811 ], [ 144.79200744628929, -5.835433959960881 ], [ 144.816314697265625, -5.895534992217961 ], [ 144.802505493164517, -5.931334972381592 ], [ 144.778610229492415, -5.970334053039494 ], [ 144.694213867187614, -6.036633968353158 ], [ 144.751312255859375, -6.093635082244873 ], [ 144.72991943359375, -6.11573600769043 ], [ 144.741714477539176, -6.164634227752629 ], [ 144.725814819336165, -6.243435859680176 ], [ 144.688110351562614, -6.268733978271484 ], [ 144.682113647461051, -6.300836086273193 ], [ 144.64491271972679, -6.30973577499384 ], [ 144.592910766601676, -6.389835834503117 ], [ 144.416809082031477, -6.279036045074463 ], [ 144.370315551757926, -6.232935905456429 ], [ 144.479705810546875, -6.161435127258244 ], [ 144.4757080078125, -6.003835201263428 ], [ 144.419113159179915, -5.993934154510441 ], [ 144.376510620117188, -6.023734092712402 ], [ 144.325408935546875, -6.023134231567383 ], [ 144.274505615234602, -5.921333789825439 ], [ 144.3004150390625, -5.860835075378418 ], [ 144.370010375976562, -5.811334133148193 ], [ 144.383209228515625, -5.75353479385376 ], [ 144.489013671875, -5.762633800506592 ], [ 144.513916015625227, -5.711733818054142 ], [ 144.50971984863304, -5.679834842681885 ], [ 144.469711303711051, -5.659835815429688 ], [ 144.462814331054801, -5.523235797882023 ], [ 144.298110961914062, -5.514035224914551 ], [ 144.302810668945312, -5.457933902740422 ], [ 144.375411987304801, -5.321434020996037 ], [ 144.282516479492415, -5.219533920288029 ], [ 144.506713867187614, -5.291035175323486 ], [ 144.581115722656364, -5.369033813476562 ], [ 144.75701904296875, -5.494135856628418 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-MPM", "NAME_1": "Madang" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 145.780838012695426, -5.299445152282658 ], [ 145.778610229492188, -5.298333168029785 ], [ 145.781387329101562, -5.295001029968262 ], [ 145.781951904296989, -5.296111106872502 ], [ 145.780838012695426, -5.299445152282658 ] ] ], [ [ [ 145.787658691406364, -5.254936218261662 ], [ 145.787826538086165, -5.257168769836369 ], [ 145.785400390625114, -5.258316040039062 ], [ 145.784713745117188, -5.256082057952881 ], [ 145.787658691406364, -5.254936218261662 ] ] ], [ [ [ 145.79119873046875, -5.244953155517464 ], [ 145.790313720703352, -5.246356964111271 ], [ 145.790863037109602, -5.243291854858398 ], [ 145.791748046875, -5.243835926055908 ], [ 145.79119873046875, -5.244953155517464 ] ] ], [ [ [ 145.797256469726904, -5.207542896270752 ], [ 145.796478271484489, -5.206942081451359 ], [ 145.7974853515625, -5.205537796020508 ], [ 145.798141479492642, -5.206971168518066 ], [ 145.797256469726904, -5.207542896270752 ] ] ], [ [ [ 147.093048095703239, -5.203889846801701 ], [ 147.134719848632812, -5.242500782012939 ], [ 147.188888549804688, -5.264165878295842 ], [ 147.179168701171875, -5.298333168029785 ], [ 147.21833801269554, -5.351666927337646 ], [ 147.200561523437727, -5.362220764160099 ], [ 147.217773437500227, -5.403611183166504 ], [ 147.164657592773438, -5.413952827453556 ], [ 147.134170532226562, -5.442221164703312 ], [ 146.994995117187727, -5.35027885437006 ], [ 146.997619628906477, -5.244856834411621 ], [ 147.031661987304801, -5.244166851043644 ], [ 147.093048095703239, -5.203889846801701 ] ] ], [ [ [ 145.807495117187614, -5.197220802307129 ], [ 145.80555725097679, -5.195001125335637 ], [ 145.806671142578352, -5.193889141082707 ], [ 145.807785034179688, -5.196389198303223 ], [ 145.807495117187614, -5.197220802307129 ] ] ], [ [ [ 145.82666015625, -5.195001125335637 ], [ 145.8175048828125, -5.207777976989746 ], [ 145.81304931640625, -5.205277919769287 ], [ 145.825836181640739, -5.187778949737549 ], [ 145.82666015625, -5.195001125335637 ] ] ], [ [ [ 145.806671142578352, -5.188333034515324 ], [ 145.804718017578125, -5.187222957611084 ], [ 145.80555725097679, -5.184443950653019 ], [ 145.807220458984375, -5.185834884643555 ], [ 145.806671142578352, -5.188333034515324 ] ] ], [ [ [ 145.829437255859489, -5.180555820465088 ], [ 145.827774047851904, -5.180277824401855 ], [ 145.830001831054801, -5.173890113830566 ], [ 145.83222961425804, -5.173055171966496 ], [ 145.829437255859489, -5.180555820465088 ] ] ], [ [ [ 145.839996337890625, -5.171946048736515 ], [ 145.83833312988304, -5.170833110809269 ], [ 145.840560913085938, -5.166944980621338 ], [ 145.842498779296875, -5.170833110809269 ], [ 145.839996337890625, -5.171946048736515 ] ] ], [ [ [ 145.791427612304801, -5.153297901153508 ], [ 145.790191650390739, -5.15262508392334 ], [ 145.791168212890625, -5.151315212249699 ], [ 145.792098999023551, -5.152629852294865 ], [ 145.791427612304801, -5.153297901153508 ] ] ], [ [ [ 145.80952453613304, -5.144303798675537 ], [ 145.808197021484602, -5.146958827972412 ], [ 145.807235717773665, -5.146684169769287 ], [ 145.806655883789062, -5.144676208496094 ], [ 145.80952453613304, -5.144303798675537 ] ] ], [ [ [ 145.813705444335938, -5.137173175811711 ], [ 145.81292724609375, -5.138031959533691 ], [ 145.811737060546989, -5.13754415512085 ], [ 145.813339233398665, -5.136598110198975 ], [ 145.813705444335938, -5.137173175811711 ] ] ], [ [ [ 145.822219848632926, -5.136944770812988 ], [ 145.820556640625, -5.135001182556152 ], [ 145.821395874023665, -5.133889198303223 ], [ 145.822784423828239, -5.135557174682617 ], [ 145.822219848632926, -5.136944770812988 ] ] ], [ [ [ 145.806076049804688, -5.13489818572998 ], [ 145.80555725097679, -5.135279178619385 ], [ 145.803466796875227, -5.133609771728516 ], [ 145.805038452148438, -5.133297920226994 ], [ 145.806076049804688, -5.13489818572998 ] ] ], [ [ [ 145.813690185546875, -5.131461143493652 ], [ 145.813995361328239, -5.133314132690373 ], [ 145.8114013671875, -5.131461143493652 ], [ 145.81195068359375, -5.130504131317139 ], [ 145.813690185546875, -5.131461143493652 ] ] ], [ [ [ 145.80548095703125, -5.132153987884465 ], [ 145.804229736328352, -5.131597995758 ], [ 145.80694580078125, -5.130138874053898 ], [ 145.806533813477017, -5.131388187408447 ], [ 145.80548095703125, -5.132153987884465 ] ] ], [ [ [ 145.80726623535179, -5.121312141418457 ], [ 145.80780029296875, -5.123844146728516 ], [ 145.804809570312727, -5.123874187469482 ], [ 145.8056640625, -5.121868133544922 ], [ 145.80726623535179, -5.121312141418457 ] ] ], [ [ [ 145.806854248047102, -5.112436771392765 ], [ 145.805679321289062, -5.113039016723633 ], [ 145.805603027343864, -5.111547946929932 ], [ 145.806976318359489, -5.11132097244257 ], [ 145.806854248047102, -5.112436771392765 ] ] ], [ [ [ 145.805252075195426, -5.098566055297852 ], [ 145.803741455078466, -5.098354816436711 ], [ 145.804367065429688, -5.096825122833195 ], [ 145.80538940429733, -5.097592830657959 ], [ 145.805252075195426, -5.098566055297852 ] ] ], [ [ [ 146.959350585937614, -5.091061115264893 ], [ 146.976348876953239, -5.110335826873779 ], [ 146.959396362304801, -5.133674144744873 ], [ 146.939834594726676, -5.113733768463135 ], [ 146.959350585937614, -5.091061115264893 ] ] ], [ [ [ 145.819168090820426, -5.075555801391602 ], [ 145.822784423828239, -5.083889007568359 ], [ 145.822494506836165, -5.1058349609375 ], [ 145.814727783203352, -5.078887939453068 ], [ 145.819168090820426, -5.075555801391602 ] ] ], [ [ [ 145.7965087890625, -5.010763168334904 ], [ 145.79560852050804, -5.010207176208439 ], [ 145.796096801757926, -5.009094238281193 ], [ 145.796661376953239, -5.00923299789423 ], [ 145.7965087890625, -5.010763168334904 ] ] ], [ [ [ 145.796310424804688, -5.008123874664307 ], [ 145.795471191406705, -5.008123874664307 ], [ 145.795333862304801, -5.006665229797363 ], [ 145.79623413085983, -5.0068039894104 ], [ 145.796310424804688, -5.008123874664307 ] ] ], [ [ [ 145.7947998046875, -4.988418102264404 ], [ 145.793960571289176, -4.987304210662842 ], [ 145.794662475586165, -4.985427856445256 ], [ 145.795074462890852, -4.986261844634953 ], [ 145.7947998046875, -4.988418102264404 ] ] ], [ [ [ 145.70361328125, -4.77027702331543 ], [ 145.701385498047102, -4.770555973052922 ], [ 145.699722290039517, -4.768610954284668 ], [ 145.703048706054688, -4.769167900085449 ], [ 145.70361328125, -4.77027702331543 ] ] ], [ [ [ 146.23883056640625, -4.762860774993896 ], [ 146.256912231445426, -4.80616903305048 ], [ 146.241928100586165, -4.822244167327881 ], [ 146.228012084961165, -4.80835485458374 ], [ 146.231887817382926, -4.828641891479492 ], [ 146.213562011719205, -4.82755708694458 ], [ 146.199401855468977, -4.781435966491642 ], [ 146.23883056640625, -4.762860774993896 ] ] ], [ [ [ 145.993835449219205, -4.521083831787053 ], [ 146.062225341796875, -4.582499980926457 ], [ 146.068328857421875, -4.650001049041748 ], [ 146.053894042968977, -4.705554962158089 ], [ 145.995178222656364, -4.743017196655273 ], [ 145.925384521484489, -4.753864765167236 ], [ 145.887466430664176, -4.72855281829834 ], [ 145.880661010742188, -4.644320964813232 ], [ 145.917785644531364, -4.567738056182804 ], [ 145.993835449219205, -4.521083831787053 ] ] ], [ [ [ 144.942535400390625, -4.23003101348877 ], [ 144.94174194335983, -4.228332996368351 ], [ 144.943054199218977, -4.227499008178654 ], [ 144.944808959961051, -4.228868961334172 ], [ 144.942535400390625, -4.23003101348877 ] ] ], [ [ [ 144.873474121093864, -4.175020217895508 ], [ 144.872558593750114, -4.173456192016488 ], [ 144.874343872070312, -4.169704914093018 ], [ 144.874069213867301, -4.174339771270695 ], [ 144.873474121093864, -4.175020217895508 ] ] ], [ [ [ 145.040481567382812, -4.033036231994572 ], [ 145.073745727539176, -4.050741195678711 ], [ 145.079284667968864, -4.084305763244629 ], [ 145.067626953125455, -4.112383842468262 ], [ 145.026138305664062, -4.124133110046387 ], [ 144.99972534179733, -4.111110210418644 ], [ 144.989440917968864, -4.065557003021183 ], [ 144.995590209961051, -4.04393291473383 ], [ 145.040481567382812, -4.033036231994572 ] ] ], [ [ [ 144.57861328125, -4.0 ], [ 144.661392211914062, -4.011666774749699 ], [ 144.662338256836051, -4.023490905761605 ], [ 144.85638427734375, -4.113333225250244 ], [ 144.868331909179801, -4.136943817138615 ], [ 144.844451904297102, -4.147221088409424 ], [ 144.851943969726676, -4.183055877685547 ], [ 144.884170532226562, -4.20111083984375 ], [ 144.91139221191429, -4.191666126251221 ], [ 144.93499755859375, -4.229721069335938 ], [ 144.975830078125227, -4.255833148956299 ], [ 144.970840454101562, -4.296666145324707 ], [ 144.991104125976676, -4.29555606842041 ], [ 145.032852172851562, -4.348848819732552 ], [ 145.103897094726562, -4.382452964782715 ], [ 145.168151855468864, -4.384764194488469 ], [ 145.185394287109375, -4.403883934020882 ], [ 145.22100830078125, -4.382352828979492 ], [ 145.322204589843977, -4.385091781616211 ], [ 145.365249633789062, -4.434384822845459 ], [ 145.358825683593977, -4.446434974670353 ], [ 145.414443969726676, -4.463684082031193 ], [ 145.420135498046875, -4.500501155853271 ], [ 145.453704833984375, -4.492603778839054 ], [ 145.528076171875114, -4.587175846099854 ], [ 145.546066284179688, -4.581357955932617 ], [ 145.597366333008154, -4.675765991210881 ], [ 145.670562744140739, -4.75579118728632 ], [ 145.805801391601562, -4.847601890563908 ], [ 145.77944946289108, -4.943713188171387 ], [ 145.814727783203352, -5.068334102630558 ], [ 145.774749755859716, -5.075568199157715 ], [ 145.806396484375114, -5.089445114135685 ], [ 145.7869873046875, -5.124404907226506 ], [ 145.806396484375114, -5.125833988189697 ], [ 145.799163818359716, -5.134167194366455 ], [ 145.802474975586165, -5.155960083007756 ], [ 145.790557861328239, -5.147500038146916 ], [ 145.788055419921989, -5.152222156524658 ], [ 145.80694580078125, -5.162222862243596 ], [ 145.791671752929801, -5.195555210113525 ], [ 145.806671142578352, -5.202499866485539 ], [ 145.798889160156477, -5.202221870422306 ], [ 145.792922973632812, -5.206943988800049 ], [ 145.791107177734489, -5.218332767486572 ], [ 145.810272216796875, -5.207221984863281 ], [ 145.815551757812614, -5.218610763549805 ], [ 145.777496337890852, -5.256112098693791 ], [ 145.743606567382926, -5.325554847717228 ], [ 145.755554199218977, -5.320831775665283 ], [ 145.760559082031477, -5.351388931274414 ], [ 145.73194885253929, -5.422500133514347 ], [ 145.760284423828125, -5.477777957916203 ], [ 145.795562744140625, -5.494444847106934 ], [ 145.851669311523438, -5.472499847411996 ], [ 145.869186401367188, -5.492032051086426 ], [ 145.91676330566429, -5.496956825256348 ], [ 145.932266235351676, -5.474729061126595 ], [ 145.983337402343977, -5.469442844390869 ], [ 146.000274658203352, -5.496942996978703 ], [ 146.07861328125, -5.506666183471623 ], [ 146.119171142578239, -5.541110992431641 ], [ 146.1602783203125, -5.531943798065186 ], [ 146.186386108398438, -5.560833930969125 ], [ 146.26666259765625, -5.573054790496826 ], [ 146.284729003906364, -5.595832824707031 ], [ 146.341110229492415, -5.573332786560059 ], [ 146.378326416015852, -5.614999771118107 ], [ 146.460830688476562, -5.606112003326416 ], [ 146.479446411133267, -5.645833015441895 ], [ 146.540069580078352, -5.666914939880314 ], [ 146.630554199218864, -5.761944770812931 ], [ 146.70027160644554, -5.772500038146973 ], [ 146.755889892578466, -5.808039188384953 ], [ 146.768112182617188, -5.840333938598633 ], [ 146.716812133789062, -5.884635925292969 ], [ 146.674011230468864, -5.891334056854191 ], [ 146.498611450195312, -5.993234157562199 ], [ 145.862106323242529, -5.996534824371338 ], [ 145.820617675781477, -5.975334167480469 ], [ 145.663818359375227, -5.981535911560002 ], [ 145.6588134765625, -5.921934127807617 ], [ 145.584518432617642, -5.905334949493408 ], [ 145.527114868164176, -5.973533153533879 ], [ 145.479812622070426, -5.978434085845947 ], [ 145.420318603515739, -5.934535026550293 ], [ 145.3712158203125, -5.859635829925537 ], [ 145.302719116210938, -5.884833812713566 ], [ 145.26960754394554, -5.858233928680363 ], [ 145.230209350585938, -5.852434158325195 ], [ 145.16461181640625, -5.876634120941162 ], [ 145.139007568359489, -5.829033851623535 ], [ 145.090606689453125, -5.78893518447876 ], [ 145.026412963867415, -5.775935173034554 ], [ 144.994720458984602, -5.719933986663818 ], [ 144.9840087890625, -5.661633968353215 ], [ 144.91731262207054, -5.650634765624943 ], [ 144.879608154296989, -5.601233959197884 ], [ 144.779510498046875, -5.536135196685734 ], [ 144.741714477539176, -5.478033065795898 ], [ 144.581115722656364, -5.369033813476562 ], [ 144.506713867187614, -5.291035175323486 ], [ 144.181320190429801, -5.191036224365178 ], [ 144.14100646972679, -5.158635139465275 ], [ 144.098312377930142, -5.078934192657471 ], [ 144.012115478515739, -5.054034233093262 ], [ 143.9691162109375, -5.010334014892521 ], [ 144.034820556640739, -4.991835117340088 ], [ 144.10491943359375, -4.943534851074219 ], [ 144.574218750000114, -4.58783483505249 ], [ 144.57861328125, -4.0 ] ] ], [ [ [ 144.96632385253929, -3.990691900253239 ], [ 144.970916748047102, -3.996014118194523 ], [ 144.967315673828239, -4.001597881317139 ], [ 144.956573486328352, -3.993212938308716 ], [ 144.96632385253929, -3.990691900253239 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-MRL", "NAME_1": "Manus" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 145.307220458984375, -0.756389021873474 ], [ 145.307220458984375, -0.760555028915405 ], [ 145.302505493164062, -0.756667017936707 ], [ 145.302993774414176, -0.755904018878937 ], [ 145.307220458984375, -0.756389021873474 ] ] ], [ [ [ 145.565826416015739, -0.87201398611063 ], [ 145.568328857421989, -0.877777993679047 ], [ 145.544097900390739, -0.901112020015603 ], [ 145.54888916015625, -0.881944000720978 ], [ 145.565826416015739, -0.87201398611063 ] ] ], [ [ [ 145.531112670898551, -0.908334970474243 ], [ 145.528884887695312, -0.907500028610229 ], [ 145.532226562500114, -0.904999971389771 ], [ 145.533050537109375, -0.906665980815831 ], [ 145.531112670898551, -0.908334970474243 ] ] ], [ [ [ 143.000274658203239, -1.000277042388859 ], [ 143.0, -1.000555038452092 ], [ 142.999725341796875, -1.000277042388859 ], [ 143.0, -0.999998986721039 ], [ 143.000274658203239, -1.000277042388859 ] ] ], [ [ [ 144.398605346679688, -1.079399943351632 ], [ 144.396392822265739, -1.075500011444092 ], [ 144.398193359375, -1.073758959770146 ], [ 144.399642944336051, -1.074872970580941 ], [ 144.398605346679688, -1.079399943351632 ] ] ], [ [ [ 144.401718139648665, -1.080724000930786 ], [ 144.404998779296989, -1.0938880443573 ], [ 144.396942138671875, -1.094092965125981 ], [ 144.39617919921875, -1.080862998962402 ], [ 144.401718139648665, -1.080724000930786 ] ] ], [ [ [ 144.417083740234375, -1.102753996849003 ], [ 144.412796020507926, -1.099246025085449 ], [ 144.412582397460938, -1.096670985221806 ], [ 144.415908813476676, -1.098273038864079 ], [ 144.417083740234375, -1.102753996849003 ] ] ], [ [ [ 144.41925048828125, -1.108623027801514 ], [ 144.418136596679801, -1.10869300365448 ], [ 144.416625976562614, -1.104096055030823 ], [ 144.418838500976562, -1.104861974716187 ], [ 144.41925048828125, -1.108623027801514 ] ] ], [ [ [ 144.49690246582054, -1.111690044403019 ], [ 144.499206542968864, -1.11868500709528 ], [ 144.481674194336051, -1.11489295959467 ], [ 144.487976074218864, -1.107790946960392 ], [ 144.49690246582054, -1.111690044403019 ] ] ], [ [ [ 144.42034912109375, -1.113361001014653 ], [ 144.418350219726676, -1.112733960151616 ], [ 144.419311523437614, -1.109390974044743 ], [ 144.4208984375, -1.111271023750248 ], [ 144.42034912109375, -1.113361001014653 ] ] ], [ [ [ 144.5035400390625, -1.114685058593636 ], [ 144.500778198242301, -1.114336013793888 ], [ 144.49932861328125, -1.110298037528992 ], [ 144.503265380859489, -1.111271023750248 ], [ 144.5035400390625, -1.114685058593636 ] ] ], [ [ [ 144.4197998046875, -1.122483968734684 ], [ 144.418960571289176, -1.122203946113586 ], [ 144.419586181640625, -1.114197015762329 ], [ 144.421661376953125, -1.11642396450037 ], [ 144.4197998046875, -1.122483968734684 ] ] ], [ [ [ 144.507415771484489, -1.117678046226388 ], [ 144.505477905273665, -1.116704940795842 ], [ 144.505767822265625, -1.115309953689575 ], [ 144.507705688476562, -1.115867972373962 ], [ 144.507415771484489, -1.117678046226388 ] ] ], [ [ [ 144.500228881835938, -1.141216993331909 ], [ 144.496826171875, -1.139613986015263 ], [ 144.504928588867301, -1.118792057037354 ], [ 144.509918212890739, -1.131744980812073 ], [ 144.500228881835938, -1.141216993331909 ] ] ], [ [ [ 144.476837158203125, -1.124781966209412 ], [ 144.474746704101562, -1.124503970146179 ], [ 144.476760864257812, -1.119696974754277 ], [ 144.477661132812614, -1.120046019554138 ], [ 144.476837158203125, -1.124781966209412 ] ] ], [ [ [ 144.403549194335938, -1.165765047073307 ], [ 144.399932861328125, -1.164335966110229 ], [ 144.4188232421875, -1.127218008041382 ], [ 144.420974731445312, -1.151383996009827 ], [ 144.403549194335938, -1.165765047073307 ] ] ], [ [ [ 144.480422973632812, -1.132509946823063 ], [ 144.496078491210938, -1.139474987983704 ], [ 144.495925903320312, -1.140938997268677 ], [ 144.481536865234375, -1.135365962982178 ], [ 144.478912353515625, -1.130839943885803 ], [ 144.480422973632812, -1.132509946823063 ] ] ], [ [ [ 144.395645141601676, -1.167677044868412 ], [ 144.391693115234375, -1.166424036025944 ], [ 144.399108886718864, -1.165169954299927 ], [ 144.398757934570312, -1.166982054710388 ], [ 144.395645141601676, -1.167677044868412 ] ] ], [ [ [ 144.380554199218977, -1.164168000221196 ], [ 144.381942749023551, -1.165555953979435 ], [ 144.380279541015625, -1.166668057441655 ], [ 144.379165649414062, -1.165555953979435 ], [ 144.380554199218977, -1.164168000221196 ] ] ], [ [ [ 144.385559082031364, -1.164721012115365 ], [ 144.388885498046875, -1.166668057441655 ], [ 144.390548706054688, -1.167222023010197 ], [ 144.382507324218864, -1.166668057441655 ], [ 144.385559082031364, -1.164721012115365 ] ] ], [ [ [ 144.370040893554688, -1.207509994506779 ], [ 144.369827270507812, -1.205490946769714 ], [ 144.374526977539062, -1.20173001289362 ], [ 144.373214721679688, -1.205003023147583 ], [ 144.370040893554688, -1.207509994506779 ] ] ], [ [ [ 144.271743774414062, -1.216632962226811 ], [ 144.275070190429915, -1.218026041984501 ], [ 144.275772094726562, -1.224920034408512 ], [ 144.26531982421875, -1.223108053207341 ], [ 144.271743774414062, -1.216632962226811 ] ] ], [ [ [ 144.225448608398438, -1.223873972892704 ], [ 144.220596313476676, -1.22484898567194 ], [ 144.217559814453125, -1.22331798076624 ], [ 144.230712890625, -1.218394994735604 ], [ 144.225448608398438, -1.223873972892704 ] ] ], [ [ [ 144.297576904297102, -1.220173001289311 ], [ 144.292373657226562, -1.223945021629333 ], [ 144.284210205078125, -1.221508026123047 ], [ 144.287261962890625, -1.219625949859562 ], [ 144.297576904297102, -1.220173001289311 ] ] ], [ [ [ 144.354049682617301, -1.227146983146667 ], [ 144.353012084960938, -1.22484898567194 ], [ 144.355224609375114, -1.223667025565987 ], [ 144.355712890625, -1.224781036376953 ], [ 144.354049682617301, -1.227146983146667 ] ] ], [ [ [ 144.316192626953125, -1.237107038497811 ], [ 144.31549072265625, -1.238847970962468 ], [ 144.313690185546875, -1.237941026687622 ], [ 144.314941406250227, -1.236757993698063 ], [ 144.316192626953125, -1.237107038497811 ] ] ], [ [ [ 144.357986450195312, -1.244905948638859 ], [ 144.354736328125, -1.244207978248596 ], [ 144.355148315429688, -1.242328047752324 ], [ 144.357299804687614, -1.242050051689091 ], [ 144.357986450195312, -1.244905948638859 ] ] ], [ [ [ 144.357818603515625, -1.267752051353398 ], [ 144.3568115234375, -1.266144990921021 ], [ 144.358871459961051, -1.25929403305048 ], [ 144.359649658203125, -1.264027953147831 ], [ 144.357818603515625, -1.267752051353398 ] ] ], [ [ [ 144.299362182617301, -1.265447974205017 ], [ 144.297286987304688, -1.265308976173287 ], [ 144.297500610351562, -1.263149976730347 ], [ 144.299789428710938, -1.263149976730347 ], [ 144.299362182617301, -1.265447974205017 ] ] ], [ [ [ 144.332931518554801, -1.27192497253418 ], [ 144.330856323242188, -1.272003054618779 ], [ 144.330795288086051, -1.270329952239933 ], [ 144.332382202148438, -1.269773960113525 ], [ 144.332931518554801, -1.27192497253418 ] ] ], [ [ [ 144.35418701171875, -1.278470993041935 ], [ 144.352523803711051, -1.278331995010376 ], [ 144.356323242187727, -1.270671963691711 ], [ 144.356674194335938, -1.275127053260803 ], [ 144.35418701171875, -1.278470993041935 ] ] ], [ [ [ 144.353179931640625, -1.283565044403019 ], [ 144.352493286132812, -1.28286695480341 ], [ 144.354080200195426, -1.279664993286133 ], [ 144.354278564453239, -1.282101035118046 ], [ 144.353179931640625, -1.283565044403019 ] ] ], [ [ [ 144.347061157226562, -1.286486029624939 ], [ 144.347961425781364, -1.30047595500946 ], [ 144.339370727539176, -1.314404010772705 ], [ 144.345947265625, -1.296298027038574 ], [ 144.347061157226562, -1.286486029624939 ] ] ], [ [ [ 144.263381958007812, -1.292538046836853 ], [ 144.262069702148438, -1.29222297668457 ], [ 144.260955810547102, -1.290518045425358 ], [ 144.263931274414062, -1.290725946426392 ], [ 144.263381958007812, -1.292538046836853 ] ] ], [ [ [ 143.583450317382812, -1.313063025474491 ], [ 143.578536987304801, -1.311254024505558 ], [ 143.578735351562614, -1.307492971420231 ], [ 143.583175659179688, -1.307353973388672 ], [ 143.583450317382812, -1.313063025474491 ] ] ], [ [ [ 144.28912353515625, -1.31275999546051 ], [ 144.28759765625, -1.312103986740112 ], [ 144.287429809570312, -1.310634016990662 ], [ 144.289810180664176, -1.310711026191711 ], [ 144.28912353515625, -1.31275999546051 ] ] ], [ [ [ 144.335464477539062, -1.324695944786072 ], [ 144.334640502929801, -1.32420802116394 ], [ 144.339126586914062, -1.316828966140747 ], [ 144.336715698242301, -1.323443055152893 ], [ 144.335464477539062, -1.324695944786072 ] ] ], [ [ [ 144.1522216796875, -1.318302989006042 ], [ 144.16731262207054, -1.327844023704415 ], [ 144.168350219726562, -1.331743001937866 ], [ 144.154983520507926, -1.326241016387939 ], [ 144.1522216796875, -1.318302989006042 ] ] ], [ [ [ 144.174438476562614, -1.365308046340942 ], [ 144.17359924316429, -1.362174034118652 ], [ 144.175537109375114, -1.357228994369507 ], [ 144.175964355468864, -1.358901023864632 ], [ 144.174438476562614, -1.365308046340942 ] ] ], [ [ [ 144.190567016601562, -1.408759951591435 ], [ 144.215560913086165, -1.40103101730341 ], [ 144.181015014648438, -1.412520051002502 ], [ 144.171463012695312, -1.398594975471497 ], [ 144.172744750976562, -1.386127948760986 ], [ 144.190567016601562, -1.408759951591435 ] ] ], [ [ [ 144.083068847656364, -1.391003012657166 ], [ 144.088821411132812, -1.39392697811121 ], [ 144.087158203125, -1.400056004524174 ], [ 144.082382202148438, -1.39330005645752 ], [ 144.083068847656364, -1.391003012657166 ] ] ], [ [ [ 144.082595825195312, -1.395320057868901 ], [ 144.082534790039062, -1.396088004112187 ], [ 144.07746887207054, -1.397549033164978 ], [ 144.079193115234602, -1.392117977142277 ], [ 144.082595825195312, -1.395320057868901 ] ] ], [ [ [ 144.519332885742188, -1.404304027557259 ], [ 144.51593017578125, -1.412312984466553 ], [ 144.505477905273665, -1.417812943458557 ], [ 144.506927490234375, -1.400666952133122 ], [ 144.519332885742188, -1.404304027557259 ] ] ], [ [ [ 144.052886962890739, -1.469380021095219 ], [ 144.060775756835938, -1.482959032058716 ], [ 144.05108642578125, -1.490479946136475 ], [ 144.041259765625114, -1.452386975288391 ], [ 144.052886962890739, -1.469380021095219 ] ] ], [ [ [ 143.055831909179688, -1.454167008399963 ], [ 143.072784423828125, -1.458333015441895 ], [ 143.082138061523438, -1.46402204036707 ], [ 143.049163818359375, -1.476667046546822 ], [ 143.055831909179688, -1.454167008399963 ] ] ], [ [ [ 145.124160766601562, -1.473055958747807 ], [ 145.126663208007812, -1.475278973579407 ], [ 145.123611450195312, -1.478610992431527 ], [ 145.121948242187614, -1.474166035652161 ], [ 145.124160766601562, -1.473055958747807 ] ] ], [ [ [ 145.016662597656364, -1.486945986747685 ], [ 145.014450073242188, -1.487776994705143 ], [ 145.009445190429801, -1.486111044883671 ], [ 145.016937255859375, -1.484722971916199 ], [ 145.016662597656364, -1.486945986747685 ] ] ], [ [ [ 145.004165649414062, -1.485972046852112 ], [ 145.00502014160179, -1.486013054847604 ], [ 145.006393432617301, -1.487776994705143 ], [ 145.003326416015739, -1.487498998641911 ], [ 145.004165649414062, -1.485972046852112 ] ] ], [ [ [ 145.078887939453239, -1.503054022788888 ], [ 145.077499389648665, -1.502223014831486 ], [ 145.078399658203125, -1.499444007873535 ], [ 145.079925537109375, -1.500764012336674 ], [ 145.078887939453239, -1.503054022788888 ] ] ], [ [ [ 145.083328247070312, -1.506389021873417 ], [ 145.095977783203125, -1.519029021263066 ], [ 145.078887939453239, -1.514999032020569 ], [ 145.067214965820426, -1.547222018241825 ], [ 145.04083251953125, -1.538054943084717 ], [ 145.083328247070312, -1.506389021873417 ] ] ], [ [ [ 145.004440307617415, -1.528331995010319 ], [ 145.00062561035179, -1.529306054115239 ], [ 144.998687744140625, -1.521309971809387 ], [ 145.002227783203239, -1.523609995841923 ], [ 145.004440307617415, -1.528331995010319 ] ] ], [ [ [ 145.031661987304688, -1.532222986221257 ], [ 145.0352783203125, -1.538054943084717 ], [ 145.016113281250114, -1.554721951484623 ], [ 145.015838623046875, -1.547500014305058 ], [ 145.031661987304688, -1.532222986221257 ] ] ], [ [ [ 145.004440307617415, -1.536388993263245 ], [ 145.014999389648551, -1.546388030052128 ], [ 145.013885498046875, -1.548056006431523 ], [ 145.000274658203239, -1.539167046546936 ], [ 145.004440307617415, -1.536388993263245 ] ] ], [ [ [ 144.969131469726562, -1.566066026687565 ], [ 144.970657348632812, -1.570659995079041 ], [ 144.974472045898438, -1.577206015586739 ], [ 144.969818115234375, -1.571913957595825 ], [ 144.966918945312614, -1.563698053359929 ], [ 144.969131469726562, -1.566066026687565 ] ] ], [ [ [ 144.987548828125, -1.58820998668665 ], [ 144.99737548828125, -1.591689944267159 ], [ 144.987823486328125, -1.590437054634037 ], [ 144.9752197265625, -1.578737974166813 ], [ 144.987548828125, -1.58820998668665 ] ] ], [ [ [ 144.027694702148665, -1.655588030815125 ], [ 144.023681640625227, -1.641453027725106 ], [ 144.025833129882926, -1.64068496227253 ], [ 144.032333374023551, -1.645979046821594 ], [ 144.027694702148665, -1.655588030815125 ] ] ], [ [ [ 144.017105102539062, -1.660045981407109 ], [ 144.021530151367188, -1.659209012985229 ], [ 144.022369384765739, -1.659765958786011 ], [ 144.017456054687614, -1.661856055259705 ], [ 144.013580322265852, -1.658514022827092 ], [ 144.017105102539062, -1.660045981407109 ] ] ], [ [ [ 142.845520019531477, -1.727622032165527 ], [ 142.881332397460938, -1.728561043739262 ], [ 142.873580932617301, -1.751757979393005 ], [ 142.84942626953125, -1.739964008331299 ], [ 142.828765869140739, -1.760316014289856 ], [ 142.83111572265625, -1.720000982284489 ], [ 142.845520019531477, -1.727622032165527 ] ] ], [ [ [ 146.580001831054688, -1.902500033378601 ], [ 146.58583068847679, -1.903609991073495 ], [ 146.586227416992301, -1.905336022376957 ], [ 146.579193115234489, -1.905472040176392 ], [ 146.580001831054688, -1.902500033378601 ] ] ], [ [ [ 146.875000000000114, -1.905557036399784 ], [ 146.897506713867301, -1.916946053504944 ], [ 146.898071289062614, -1.918071031570378 ], [ 146.88250732421875, -1.914723038673401 ], [ 146.875000000000114, -1.905557036399784 ] ] ], [ [ [ 146.601669311523551, -1.906388998031559 ], [ 146.605270385742188, -1.906110048294011 ], [ 146.607101440429688, -1.908709049224854 ], [ 146.598785400390625, -1.907050013542175 ], [ 146.601669311523551, -1.906388998031559 ] ] ], [ [ [ 146.662506103515852, -1.928609967231694 ], [ 146.668060302734489, -1.930835008621159 ], [ 146.673049926757926, -1.932222962379456 ], [ 146.662994384765625, -1.9322429895401 ], [ 146.662506103515852, -1.928609967231694 ] ] ], [ [ [ 146.998336791992188, -1.933889031410217 ], [ 147.006393432617415, -1.938333034515381 ], [ 147.006942749023438, -1.940276980400085 ], [ 147.001449584961051, -1.939445018768311 ], [ 146.998336791992188, -1.933889031410217 ] ] ], [ [ [ 146.599716186523438, -1.93416702747345 ], [ 146.604446411132812, -1.936944961547852 ], [ 146.603607177734489, -1.939998984336853 ], [ 146.596389770507926, -1.938055038452148 ], [ 146.599716186523438, -1.93416702747345 ] ] ], [ [ [ 147.019439697265625, -1.938333034515381 ], [ 147.020553588867301, -1.939723014831543 ], [ 147.017227172851562, -1.939167022705078 ], [ 147.017227172851562, -1.938611030578613 ], [ 147.019439697265625, -1.938333034515381 ] ] ], [ [ [ 147.103057861328125, -1.938611030578613 ], [ 147.104446411132926, -1.943333029747009 ], [ 147.097229003906364, -1.940554976463318 ], [ 147.099716186523551, -1.938889026641846 ], [ 147.103057861328125, -1.938611030578613 ] ] ], [ [ [ 147.132217407226562, -1.942221045493966 ], [ 147.136108398437614, -1.944442987442017 ], [ 147.136672973632926, -1.945834040641728 ], [ 147.129165649414062, -1.943055033683777 ], [ 147.132217407226562, -1.942221045493966 ] ] ], [ [ [ 146.6119384765625, -1.944167971610909 ], [ 146.626647949218977, -1.954033970832768 ], [ 146.623748779296875, -1.959864020347482 ], [ 146.6119384765625, -1.953888058662415 ], [ 146.6119384765625, -1.944167971610909 ] ] ], [ [ [ 146.494171142578125, -1.949444055557251 ], [ 146.493606567382812, -1.951388001441956 ], [ 146.491104125976676, -1.950834035873356 ], [ 146.49249267578125, -1.948609948158207 ], [ 146.494171142578125, -1.949444055557251 ] ] ], [ [ [ 147.189437866210938, -1.948609948158207 ], [ 147.19000244140625, -1.950278043746891 ], [ 147.187225341796989, -1.949722051620483 ], [ 147.187774658203125, -1.948609948158207 ], [ 147.189437866210938, -1.948609948158207 ] ] ], [ [ [ 146.839996337890625, -1.951110005378723 ], [ 146.97528076171875, -1.976943969726562 ], [ 147.109451293945426, -1.973611950874272 ], [ 147.140213012695312, -2.008317947387638 ], [ 147.153884887695426, -1.982777953147888 ], [ 147.266265869140625, -2.017549037933293 ], [ 147.318511962890625, -2.050409078597966 ], [ 147.334716796875114, -2.02594089508051 ], [ 147.346939086914062, -2.040556907653752 ], [ 147.337783813476562, -2.060277938842717 ], [ 147.29638671875, -2.061666011810303 ], [ 147.303604125976676, -2.07694506645197 ], [ 147.278060913086051, -2.10055494308466 ], [ 147.264724731445312, -2.093332052230778 ], [ 147.286117553710938, -2.077498912811222 ], [ 147.270004272461051, -2.078888893127441 ], [ 147.259994506835938, -2.100832939147892 ], [ 147.2611083984375, -2.106389999389648 ], [ 147.278335571289062, -2.115000009536629 ], [ 147.256805419921875, -2.151108026504517 ], [ 147.183609008789176, -2.208122968673649 ], [ 147.116256713867415, -2.174026966094914 ], [ 147.062500000000114, -2.205554962158203 ], [ 147.026947021484375, -2.208055019378662 ], [ 147.030548095703125, -2.194721937179565 ], [ 147.007217407226676, -2.192500114440861 ], [ 146.971939086914176, -2.214720964431763 ], [ 146.875549316406477, -2.203888893127385 ], [ 146.856948852539062, -2.184998989105168 ], [ 146.782867431640739, -2.180182933807316 ], [ 146.7388916015625, -2.15305495262146 ], [ 146.737503051757926, -2.127499103546029 ], [ 146.710281372070312, -2.141665935516301 ], [ 146.696105957031364, -2.123054981231689 ], [ 146.694442749023438, -2.14416599273676 ], [ 146.684722900390625, -2.126389026641846 ], [ 146.669998168945426, -2.132220983505249 ], [ 146.679412841796875, -2.154267072677612 ], [ 146.716659545898438, -2.170000076293945 ], [ 146.701385498046875, -2.197499990463257 ], [ 146.648330688476562, -2.208055019378662 ], [ 146.633895874023665, -2.184444904327393 ], [ 146.598892211914062, -2.183054924011174 ], [ 146.573059082031364, -2.218333959579468 ], [ 146.574066162109489, -2.248399972915593 ], [ 146.553604125976676, -2.255831956863403 ], [ 146.511108398437614, -2.214168071746712 ], [ 146.507781982421875, -2.17750096321106 ], [ 146.520828247070426, -2.166110038757324 ], [ 146.505554199218864, -2.154999017715397 ], [ 146.534500122070312, -2.134653091430607 ], [ 146.526809692382812, -2.117778062820378 ], [ 146.546951293945426, -2.131942987442017 ], [ 146.596389770507926, -2.12944507598877 ], [ 146.610275268554801, -2.113611936569214 ], [ 146.562591552734489, -2.042871952056885 ], [ 146.570281982421875, -1.985556960105896 ], [ 146.601394653320312, -2.025554895401001 ], [ 146.636672973632812, -1.969998955726567 ], [ 146.696670532226676, -1.999168038368225 ], [ 146.716949462890625, -1.985556960105896 ], [ 146.751663208007812, -1.996945023536625 ], [ 146.839996337890625, -1.951110005378723 ] ] ], [ [ [ 146.581665039062614, -1.953333973884526 ], [ 146.585281372070426, -1.959166049957275 ], [ 146.580825805664062, -1.961666941642761 ], [ 146.578048706054801, -1.957779049873352 ], [ 146.581665039062614, -1.953333973884526 ] ] ], [ [ [ 147.211669921875114, -1.954236984252873 ], [ 147.229446411132812, -1.963889002799988 ], [ 147.245559692382812, -1.963889002799988 ], [ 147.227218627929688, -1.967499017715397 ], [ 147.211669921875114, -1.954236984252873 ] ] ], [ [ [ 146.479095458984375, -1.959581017494145 ], [ 146.477783203125, -1.959792971610966 ], [ 146.478500366211051, -1.957587003707886 ], [ 146.479324340820312, -1.95807504653925 ], [ 146.479095458984375, -1.959581017494145 ] ] ], [ [ [ 147.288055419921875, -1.958610057830811 ], [ 147.291381835937614, -1.960832953453064 ], [ 147.279724121093864, -1.962501049041748 ], [ 147.283889770507812, -1.958888053894043 ], [ 147.288055419921875, -1.958610057830811 ] ] ], [ [ [ 147.318328857421875, -1.959166049957275 ], [ 147.336395263671989, -1.965276956558114 ], [ 147.34027099609375, -1.971390008926335 ], [ 147.322219848632812, -1.96722304821003 ], [ 147.318328857421875, -1.959166049957275 ] ] ], [ [ [ 146.799026489257812, -1.963564991950989 ], [ 146.798049926757812, -1.962242960929871 ], [ 146.79840087890625, -1.960572957992497 ], [ 146.799499511718864, -1.961964964866638 ], [ 146.799026489257812, -1.963564991950989 ] ] ], [ [ [ 146.906692504882926, -1.964421987533569 ], [ 146.906417846679688, -1.966122031211853 ], [ 146.905838012695312, -1.966109037399235 ], [ 146.905563354492301, -1.964714050292969 ], [ 146.906692504882926, -1.964421987533569 ] ] ], [ [ [ 146.477218627929688, -1.972777009010258 ], [ 146.476104736328125, -1.970201969146729 ], [ 146.477279663085938, -1.967442035674992 ], [ 146.47784423828125, -1.969799041748047 ], [ 146.477218627929688, -1.972777009010258 ] ] ], [ [ [ 147.34722900390625, -1.969720959663334 ], [ 147.3538818359375, -1.971390008926335 ], [ 147.355560302734375, -1.977221965789795 ], [ 147.342498779296989, -1.973333954811039 ], [ 147.34722900390625, -1.969720959663334 ] ] ], [ [ [ 146.655929565429688, -1.971367001533451 ], [ 146.655380249023438, -1.972522020339909 ], [ 146.654220581054688, -1.972509026527405 ], [ 146.653961181640739, -1.971631050109863 ], [ 146.655929565429688, -1.971367001533451 ] ] ], [ [ [ 148.07025146484375, -1.97438204288477 ], [ 148.068374633789062, -1.975842952728271 ], [ 148.064163208007812, -1.9734770059585 ], [ 148.068099975585938, -1.971526026725769 ], [ 148.07025146484375, -1.97438204288477 ] ] ], [ [ [ 147.377029418945426, -2.073939085006714 ], [ 147.410552978515625, -2.06555700302124 ], [ 147.41485595703125, -2.031692981719971 ], [ 147.402572631836051, -2.041889905929509 ], [ 147.405487060546875, -2.011459112167302 ], [ 147.366744995117301, -1.972844004631042 ], [ 147.419723510742301, -1.999721050262451 ], [ 147.439727783203125, -2.031666040420475 ], [ 147.419998168945312, -2.04222297668457 ], [ 147.423049926757812, -2.080276966094914 ], [ 147.314437866211051, -2.077776908874398 ], [ 147.345977783203125, -2.06555700302124 ], [ 147.351104736328239, -2.037777900695801 ], [ 147.4085693359375, -2.051376104354858 ], [ 147.377029418945426, -2.073939085006714 ] ] ], [ [ [ 148.032943725586051, -1.986081004142761 ], [ 148.028656005859375, -1.986081004142761 ], [ 148.026992797851562, -1.983641982078552 ], [ 148.032318115234375, -1.982597947120667 ], [ 148.032943725586051, -1.986081004142761 ] ] ], [ [ [ 146.695648193359375, -1.986929059028625 ], [ 146.696487426757926, -1.989449024200439 ], [ 146.693939208984375, -1.989433050155583 ], [ 146.693954467773438, -1.987514019012451 ], [ 146.695648193359375, -1.986929059028625 ] ] ], [ [ [ 146.608612060546875, -1.995833039283752 ], [ 146.606109619140739, -1.9911110401153 ], [ 146.609725952148551, -1.988888978958073 ], [ 146.611114501953125, -1.991667032241764 ], [ 146.608612060546875, -1.995833039283752 ] ] ], [ [ [ 147.930526733398551, -2.001473903656006 ], [ 147.928802490234489, -1.998886942863464 ], [ 147.929565429687614, -1.996940970420837 ], [ 147.931396484375, -1.999999046325684 ], [ 147.930526733398551, -2.001473903656006 ] ] ], [ [ [ 147.771209716796875, -2.034992933273315 ], [ 147.795562744140625, -2.049721002578622 ], [ 147.777770996093864, -2.06833291053772 ], [ 147.70953369140625, -2.052779912948608 ], [ 147.714996337890739, -2.041085004806519 ], [ 147.751312255859375, -2.049931049346867 ], [ 147.727493286132812, -2.027307987213078 ], [ 147.754089355468864, -2.04596304893488 ], [ 147.767791748046875, -2.036581993102914 ], [ 147.763442993164176, -2.003499984741211 ], [ 147.771209716796875, -2.034992933273315 ] ] ], [ [ [ 147.284729003906364, -2.015554904937687 ], [ 147.283889770507812, -2.015554904937687 ], [ 147.283615112304688, -2.013889074325562 ], [ 147.285278320312614, -2.014167070388794 ], [ 147.284729003906364, -2.015554904937687 ] ] ], [ [ [ 147.31298828125, -2.028194904327336 ], [ 147.311843872070312, -2.02827000617981 ], [ 147.311950683593977, -2.024442911148071 ], [ 147.313888549804801, -2.025832891464177 ], [ 147.31298828125, -2.028194904327336 ] ] ], [ [ [ 147.3094482421875, -2.031110048294067 ], [ 147.30999755859375, -2.032778024673405 ], [ 147.30694580078125, -2.034166097640991 ], [ 147.307357788085938, -2.031527042388916 ], [ 147.3094482421875, -2.031110048294067 ] ] ], [ [ [ 146.460556030273551, -2.05472207069397 ], [ 146.462493896484489, -2.056387901306096 ], [ 146.461105346679801, -2.059165954589844 ], [ 146.459030151367301, -2.05604100227356 ], [ 146.460556030273551, -2.05472207069397 ] ] ], [ [ [ 147.32049560546875, -2.064913988113403 ], [ 147.315933227539062, -2.067210912704468 ], [ 147.312606811523438, -2.065263032913151 ], [ 147.320571899414176, -2.063659906387329 ], [ 147.32049560546875, -2.064913988113403 ] ] ], [ [ [ 147.65692138671875, -2.066837072372437 ], [ 147.650375366211051, -2.088677883148137 ], [ 147.581390380859375, -2.091109991073608 ], [ 147.587493896484375, -2.083333969116211 ], [ 147.65692138671875, -2.066837072372437 ] ] ], [ [ [ 147.591888427734375, -2.080517053604069 ], [ 147.589736938476562, -2.080096960067692 ], [ 147.589462280273438, -2.078566074371338 ], [ 147.59222412109375, -2.078427076339665 ], [ 147.591888427734375, -2.080517053604069 ] ] ], [ [ [ 146.552780151367188, -2.084444046020508 ], [ 146.556671142578239, -2.087500095367432 ], [ 146.555557250976676, -2.093056917190552 ], [ 146.550277709960938, -2.088609933853149 ], [ 146.552780151367188, -2.084444046020508 ] ] ], [ [ [ 146.426391601562614, -2.087222099304086 ], [ 146.431396484375114, -2.096667051315251 ], [ 146.423889160156477, -2.10166692733759 ], [ 146.420272827148665, -2.091387987136841 ], [ 146.426391601562614, -2.087222099304086 ] ] ], [ [ [ 146.569824218750114, -2.095367908477783 ], [ 146.570831298828239, -2.096667051315251 ], [ 146.568893432617301, -2.098054885864201 ], [ 146.567779541015739, -2.096667051315251 ], [ 146.569824218750114, -2.095367908477783 ] ] ], [ [ [ 146.390838623046875, -2.100276947021428 ], [ 146.404449462890739, -2.10944390296936 ], [ 146.400833129882926, -2.118887901306152 ], [ 146.390838623046875, -2.115210056304875 ], [ 146.390838623046875, -2.100276947021428 ] ] ], [ [ [ 147.284713745117301, -2.103274106979313 ], [ 147.283187866211051, -2.102857112884521 ], [ 147.284027099609375, -2.100908041000366 ], [ 147.2847900390625, -2.101952075958252 ], [ 147.284713745117301, -2.103274106979313 ] ] ], [ [ [ 146.556671142578239, -2.118887901306152 ], [ 146.554992675781364, -2.11972188949585 ], [ 146.553054809570426, -2.117500066757145 ], [ 146.555770874023438, -2.117639064788818 ], [ 146.556671142578239, -2.118887901306152 ] ] ], [ [ [ 146.272872924804801, -2.159049034118652 ], [ 146.272109985351676, -2.159049034118652 ], [ 146.271209716796875, -2.157588005065861 ], [ 146.272872924804801, -2.158076047897339 ], [ 146.272872924804801, -2.159049034118652 ] ] ], [ [ [ 145.923553466796875, -2.160362005233765 ], [ 145.92529296875, -2.160571098327637 ], [ 145.925643920898438, -2.161756992340031 ], [ 145.923492431640625, -2.161336898803711 ], [ 145.923553466796875, -2.160362005233765 ] ] ], [ [ [ 146.293060302734489, -2.16416597366333 ], [ 146.290283203125, -2.164026975631657 ], [ 146.289581298828125, -2.162847995758057 ], [ 146.292221069335938, -2.162777900695744 ], [ 146.293060302734489, -2.16416597366333 ] ] ], [ [ [ 146.508605957031364, -2.162777900695744 ], [ 146.510284423828125, -2.164999961853027 ], [ 146.506103515625227, -2.167222023010254 ], [ 146.505004882812614, -2.164443969726562 ], [ 146.508605957031364, -2.162777900695744 ] ] ], [ [ [ 146.498611450195312, -2.166944026947021 ], [ 146.500000000000227, -2.170207977294865 ], [ 146.499160766601562, -2.170834064483643 ], [ 146.497772216796989, -2.168610095977783 ], [ 146.498611450195312, -2.166944026947021 ] ] ], [ [ [ 147.726943969726562, -2.18416690826416 ], [ 147.735549926757812, -2.191109895706177 ], [ 147.726943969726562, -2.201387882232666 ], [ 147.716949462890739, -2.196111917495728 ], [ 147.726943969726562, -2.18416690826416 ] ] ], [ [ [ 147.745285034179688, -2.189722061157227 ], [ 147.744171142578239, -2.18861198425293 ], [ 147.745895385742301, -2.186875104904061 ], [ 147.7469482421875, -2.18861198425293 ], [ 147.745285034179688, -2.189722061157227 ] ] ], [ [ [ 147.753326416015739, -2.190278053283691 ], [ 147.759445190429801, -2.197777986526489 ], [ 147.757781982421875, -2.204998970031738 ], [ 147.753326416015739, -2.199444055557194 ], [ 147.753326416015739, -2.190278053283691 ] ] ], [ [ [ 147.766113281250114, -2.194721937179565 ], [ 147.781951904296989, -2.205554962158203 ], [ 147.783340454101562, -2.228888988494873 ], [ 147.764724731445312, -2.202501058578434 ], [ 147.766113281250114, -2.194721937179565 ] ] ], [ [ [ 146.60882568359375, -2.197231054305973 ], [ 146.610015869140625, -2.199040889739933 ], [ 146.608474731445312, -2.200989961624089 ], [ 146.605712890625114, -2.198067903518677 ], [ 146.60882568359375, -2.197231054305973 ] ] ], [ [ [ 147.149581909179688, -2.200417995452881 ], [ 147.149444580078352, -2.198610067367497 ], [ 147.150283813476562, -2.198055982589722 ], [ 147.1507568359375, -2.199515104293823 ], [ 147.149581909179688, -2.200417995452881 ] ] ], [ [ [ 147.762161254882812, -2.202018022537231 ], [ 147.760894775390625, -2.201733112335205 ], [ 147.762771606445312, -2.199023008346501 ], [ 147.762710571289176, -2.199928045272827 ], [ 147.762161254882812, -2.202018022537231 ] ] ], [ [ [ 146.335006713867415, -2.202223062515259 ], [ 146.333953857421875, -2.201387882232666 ], [ 146.334716796875, -2.199444055557194 ], [ 146.335632324218864, -2.200692892074528 ], [ 146.335006713867415, -2.202223062515259 ] ] ], [ [ [ 147.151229858398551, -2.202239036560059 ], [ 147.150741577148438, -2.200778007507267 ], [ 147.153030395507812, -2.199594974517822 ], [ 147.153717041015625, -2.20042896270752 ], [ 147.151229858398551, -2.202239036560059 ] ] ], [ [ [ 147.743606567382926, -2.20055699348444 ], [ 147.7530517578125, -2.204444885253849 ], [ 147.756668090820312, -2.211389064788818 ], [ 147.743606567382926, -2.205832958221379 ], [ 147.743606567382926, -2.20055699348444 ] ] ], [ [ [ 147.1484375, -2.201191902160645 ], [ 147.14996337890625, -2.201749086379948 ], [ 147.149688720703239, -2.202583074569588 ], [ 147.147323608398438, -2.202166080474854 ], [ 147.1484375, -2.201191902160645 ] ] ], [ [ [ 146.23333740234375, -2.201041936874333 ], [ 146.236663818359489, -2.201109886169434 ], [ 146.237228393554801, -2.201667070388794 ], [ 146.23388671875, -2.202779054641667 ], [ 146.23333740234375, -2.201041936874333 ] ] ], [ [ [ 148.2005615234375, -2.204998970031738 ], [ 148.208328247070312, -2.21389007568348 ], [ 148.202499389648551, -2.222500085830632 ], [ 148.191390991210938, -2.211389064788818 ], [ 148.2005615234375, -2.204998970031738 ] ] ], [ [ [ 146.588470458984375, -2.206101894378605 ], [ 146.588165283203239, -2.207159042358342 ], [ 146.58648681640625, -2.206346035003662 ], [ 146.58648681640625, -2.206011056900024 ], [ 146.588470458984375, -2.206101894378605 ] ] ], [ [ [ 146.733337402343864, -2.210277080535889 ], [ 146.731674194335938, -2.212223052978516 ], [ 146.726669311523438, -2.209444999694767 ], [ 146.731948852539176, -2.207500934600773 ], [ 146.733337402343864, -2.210277080535889 ] ] ], [ [ [ 146.275833129882812, -2.208333015441895 ], [ 146.284439086914062, -2.211945056915283 ], [ 146.290283203125, -2.218055963516235 ], [ 146.270278930664062, -2.210555076599121 ], [ 146.275833129882812, -2.208333015441895 ] ] ], [ [ [ 147.234939575195426, -2.216041088104191 ], [ 147.2388916015625, -2.223056077957096 ], [ 147.224716186523438, -2.222500085830632 ], [ 147.229446411132812, -2.218055963516235 ], [ 147.234939575195426, -2.216041088104191 ] ] ], [ [ [ 147.217498779296875, -2.231667041778564 ], [ 147.214721679687614, -2.223887920379582 ], [ 147.224441528320426, -2.217777967453003 ], [ 147.217773437500114, -2.227778911590519 ], [ 147.217498779296875, -2.231667041778564 ] ] ], [ [ [ 146.980743408203125, -2.222743988037053 ], [ 146.980819702148438, -2.227406978607178 ], [ 146.98858642578125, -2.229495048522892 ], [ 146.981033325195426, -2.229703903198242 ], [ 146.978118896484375, -2.226640939712468 ], [ 146.980743408203125, -2.222743988037053 ] ] ], [ [ [ 147.798339843750114, -2.237498998641968 ], [ 147.796951293945312, -2.236944913864136 ], [ 147.794998168945312, -2.231667041778564 ], [ 147.798248291015625, -2.235630035400334 ], [ 147.798339843750114, -2.237498998641968 ] ] ], [ [ [ 147.737228393554688, -2.346667051315308 ], [ 147.704345703125114, -2.370276927947941 ], [ 147.726394653320312, -2.319998979568481 ], [ 147.736175537109489, -2.331880092620793 ], [ 147.782501220703239, -2.314445018768311 ], [ 147.787216186523438, -2.271389961242619 ], [ 147.811111450195426, -2.249166011810303 ], [ 147.801391601562614, -2.238054990768433 ], [ 147.878616333007812, -2.293055057525635 ], [ 147.869461059570312, -2.309807062149048 ], [ 147.847778320312614, -2.310278892517033 ], [ 147.858062744140739, -2.328612089157048 ], [ 147.849090576171989, -2.330564975738469 ], [ 147.83111572265625, -2.346389055251962 ], [ 147.737228393554688, -2.346667051315308 ] ] ], [ [ [ 146.574798583984489, -2.249098062515259 ], [ 146.577499389648551, -2.251110076904297 ], [ 146.578338623046875, -2.259444952011108 ], [ 146.573333740234375, -2.256944894790649 ], [ 146.574798583984489, -2.249098062515259 ] ] ], [ [ [ 146.829437255859489, -2.265554904937744 ], [ 146.831939697265739, -2.267498970031681 ], [ 146.830551147461051, -2.271389961242619 ], [ 146.824447631836051, -2.268054962158146 ], [ 146.829437255859489, -2.265554904937744 ] ] ], [ [ [ 147.557357788085938, -2.269375085830688 ], [ 147.55389404296875, -2.278609991073608 ], [ 147.544174194335938, -2.277777910232544 ], [ 147.551391601562614, -2.267498970031681 ], [ 147.557357788085938, -2.269375085830688 ] ] ], [ [ [ 146.798614501953125, -2.271111965179387 ], [ 146.799240112304688, -2.273890018463135 ], [ 146.79638671875, -2.273888111114388 ], [ 146.796112060546875, -2.27222204208374 ], [ 146.798614501953125, -2.271111965179387 ] ] ], [ [ [ 147.553039550781477, -2.280736923217773 ], [ 147.551803588867188, -2.28129506111145 ], [ 147.550750732422102, -2.280875921249333 ], [ 147.552627563476562, -2.279344081878605 ], [ 147.553039550781477, -2.280736923217773 ] ] ], [ [ [ 147.857437133789062, -2.281524896621647 ], [ 147.855422973632926, -2.282080888748112 ], [ 147.855010986328239, -2.280968904495239 ], [ 147.8568115234375, -2.280133008956852 ], [ 147.857437133789062, -2.281524896621647 ] ] ], [ [ [ 147.545761108398438, -2.281737089157104 ], [ 147.548049926757812, -2.282222986221257 ], [ 147.548049926757812, -2.282778978347665 ], [ 147.545837402343864, -2.284167051315251 ], [ 147.545761108398438, -2.281737089157104 ] ] ], [ [ [ 147.550598144531364, -2.297916889190617 ], [ 147.549804687500114, -2.298125982284489 ], [ 147.548065185546875, -2.296525955200082 ], [ 147.55035400390625, -2.297221899032593 ], [ 147.550598144531364, -2.297916889190617 ] ] ], [ [ [ 147.553604125976562, -2.301111936569214 ], [ 147.551940917968864, -2.299165964126587 ], [ 147.553054809570426, -2.297499895095825 ], [ 147.554855346679688, -2.298887968063354 ], [ 147.553604125976562, -2.301111936569214 ] ] ], [ [ [ 147.537261962890739, -2.312340974807739 ], [ 147.535598754882812, -2.30976390838623 ], [ 147.53961181640625, -2.309207916259766 ], [ 147.538772583007926, -2.311644077301025 ], [ 147.537261962890739, -2.312340974807739 ] ] ], [ [ [ 146.86083984375, -2.311944961547795 ], [ 146.863616943359375, -2.313889026641846 ], [ 146.8619384765625, -2.31583309173584 ], [ 146.859451293945312, -2.313611030578613 ], [ 146.86083984375, -2.311944961547795 ] ] ], [ [ [ 146.861801147460938, -2.336041927337646 ], [ 146.864715576171989, -2.33611011505127 ], [ 146.865280151367301, -2.337223052978516 ], [ 146.861114501953239, -2.337501049041748 ], [ 146.859939575195426, -2.333542108535767 ], [ 146.861801147460938, -2.336041927337646 ] ] ], [ [ [ 146.869445800781477, -2.339720964431763 ], [ 146.871383666992301, -2.34249901771534 ], [ 146.868331909179801, -2.347223997116032 ], [ 146.866668701171875, -2.343888998031616 ], [ 146.869445800781477, -2.339720964431763 ] ] ], [ [ [ 147.839508056640625, -2.343560934066716 ], [ 147.838638305664176, -2.343590974807739 ], [ 147.839218139648438, -2.341036081314087 ], [ 147.840072631835938, -2.341551065444946 ], [ 147.839508056640625, -2.343560934066716 ] ] ], [ [ [ 147.377426147461051, -2.372987031936646 ], [ 147.4215087890625, -2.383104085922241 ], [ 147.333190917968864, -2.407181024551392 ], [ 147.304443359375, -2.442779064178467 ], [ 147.317535400390739, -2.401335000991821 ], [ 147.288864135742188, -2.386131048202458 ], [ 147.309844970703125, -2.354249954223633 ], [ 147.333389282226562, -2.377151012420541 ], [ 147.33990478515625, -2.365575075149479 ], [ 147.360046386718864, -2.375159025192204 ], [ 147.359649658203239, -2.341298103332463 ], [ 147.378067016601562, -2.342271089553833 ], [ 147.377426147461051, -2.372987031936646 ] ] ], [ [ [ 147.467071533203239, -2.379534959793091 ], [ 147.461395263671875, -2.384824991226196 ], [ 147.430923461914062, -2.366168022155648 ], [ 147.45556640625, -2.345285892486572 ], [ 147.480224609375114, -2.351830005645752 ], [ 147.467071533203239, -2.379534959793091 ] ] ], [ [ [ 146.828887939453239, -2.364722967147827 ], [ 146.829727172851562, -2.37388896942133 ], [ 146.817779541015739, -2.378334045410156 ], [ 146.816665649414176, -2.376389980316162 ], [ 146.828887939453239, -2.364722967147827 ] ] ], [ [ [ 147.697219848632812, -2.37611198425293 ], [ 147.696670532226676, -2.373332977294865 ], [ 147.699996948242188, -2.370832920074349 ], [ 147.700836181640625, -2.373332977294865 ], [ 147.697219848632812, -2.37611198425293 ] ] ], [ [ [ 146.837295532226562, -2.377917051315251 ], [ 146.835830688476562, -2.377222061157227 ], [ 146.835830688476562, -2.37611198425293 ], [ 146.83778381347679, -2.376667976379395 ], [ 146.837295532226562, -2.377917051315251 ] ] ], [ [ [ 147.474029541015625, -2.381117105484009 ], [ 147.503387451171875, -2.404057979583683 ], [ 147.483169555664062, -2.423549890518132 ], [ 147.462661743164176, -2.391388893127385 ], [ 147.474029541015625, -2.381117105484009 ] ] ], [ [ [ 146.839172363281364, -2.381665945053101 ], [ 146.838333129882812, -2.379722118377572 ], [ 146.839447021484375, -2.378887891769409 ], [ 146.839935302734489, -2.379513978958073 ], [ 146.839172363281364, -2.381665945053101 ] ] ], [ [ [ 146.82611083984375, -2.381665945053101 ], [ 146.832504272461051, -2.385555982589722 ], [ 146.829727172851562, -2.39166688919056 ], [ 146.822494506835938, -2.387222051620483 ], [ 146.82611083984375, -2.381665945053101 ] ] ], [ [ [ 146.842498779296875, -2.388609886169434 ], [ 146.842224121093864, -2.386110067367497 ], [ 146.843826293945312, -2.385416984558049 ], [ 146.84388732910179, -2.38805699348444 ], [ 146.842498779296875, -2.388609886169434 ] ] ], [ [ [ 147.46405029296875, -2.398657083511353 ], [ 147.458999633789062, -2.402208089828434 ], [ 147.455261230468864, -2.40012001991272 ], [ 147.463363647460938, -2.396910905837956 ], [ 147.46405029296875, -2.398657083511353 ] ] ], [ [ [ 147.09027099609375, -2.43055605888361 ], [ 147.09027099609375, -2.434165954589787 ], [ 147.083892822265739, -2.432221889495736 ], [ 147.086944580078239, -2.430624008178711 ], [ 147.09027099609375, -2.43055605888361 ] ] ], [ [ [ 147.108261108398551, -2.435026884078979 ], [ 147.107315063476676, -2.434864997863713 ], [ 147.10786437988304, -2.432985067367554 ], [ 147.10870361328125, -2.43333196640009 ], [ 147.108261108398551, -2.435026884078979 ] ] ], [ [ [ 147.398330688476562, -2.452498912811279 ], [ 147.400283813476676, -2.454998970031681 ], [ 147.395278930664062, -2.456943035125676 ], [ 147.39472961425804, -2.454166889190674 ], [ 147.398330688476562, -2.452498912811279 ] ] ], [ [ [ 147.414443969726676, -2.456667900085392 ], [ 147.412216186523438, -2.456943035125676 ], [ 147.413055419921989, -2.454444885253906 ], [ 147.413894653320312, -2.455276966094857 ], [ 147.414443969726676, -2.456667900085392 ] ] ], [ [ [ 147.307785034179801, -2.45638990402216 ], [ 147.310272216796989, -2.458333969116154 ], [ 147.308609008789062, -2.46083402633667 ], [ 147.305557250976562, -2.458889961242619 ], [ 147.307785034179801, -2.45638990402216 ] ] ], [ [ [ 147.3397216796875, -2.498043060302734 ], [ 147.337493896484375, -2.494165897369385 ], [ 147.341384887695426, -2.492222070693913 ], [ 147.3427734375, -2.49472188949585 ], [ 147.3397216796875, -2.498043060302734 ] ] ], [ [ [ 147.331558227539062, -2.508435964584351 ], [ 147.327270507812614, -2.505791902542001 ], [ 147.333084106445312, -2.501823902130127 ], [ 147.334472656250114, -2.505165100097656 ], [ 147.331558227539062, -2.508435964584351 ] ] ], [ [ [ 147.267547607421989, -2.51173210144043 ], [ 147.277511596679688, -2.542484045028687 ], [ 147.302291870117301, -2.54192590713501 ], [ 147.286239624023551, -2.576314926147404 ], [ 147.262969970703239, -2.571304082870483 ], [ 147.265335083007812, -2.551964998245239 ], [ 147.23736572265625, -2.53651309013361 ], [ 147.267547607421989, -2.51173210144043 ] ] ], [ [ [ 147.305252075195312, -2.535933971404916 ], [ 147.303375244140739, -2.535865068435612 ], [ 147.306976318359375, -2.532453060150033 ], [ 147.307327270507812, -2.534679889678955 ], [ 147.305252075195312, -2.535933971404916 ] ] ], [ [ [ 147.295379638671989, -2.536148071289062 ], [ 147.295440673828125, -2.538444995880127 ], [ 147.29302978515625, -2.53587007522583 ], [ 147.29510498046875, -2.535660028457642 ], [ 147.295379638671989, -2.536148071289062 ] ] ], [ [ [ 147.347671508789176, -2.730638027191162 ], [ 147.349075317382812, -2.730671882629395 ], [ 147.349334716797102, -2.731477022171021 ], [ 147.3465576171875, -2.730916023254395 ], [ 147.347671508789176, -2.730638027191162 ] ] ], [ [ [ 146.236114501953125, -2.840833902358952 ], [ 146.238128662109489, -2.841665983200073 ], [ 146.235137939453239, -2.842916965484619 ], [ 146.234451293945312, -2.841387987136841 ], [ 146.236114501953125, -2.840833902358952 ] ] ], [ [ [ 146.23388671875, -2.848889112472477 ], [ 146.232498168945312, -2.851388931274414 ], [ 146.228057861328239, -2.84833288192749 ], [ 146.233062744140625, -2.846388101577759 ], [ 146.23388671875, -2.848889112472477 ] ] ], [ [ [ 146.457504272461051, -2.867500066757202 ], [ 146.45916748046875, -2.868334054946899 ], [ 146.466949462890625, -2.87388801574707 ], [ 146.456939697265739, -2.871665954589844 ], [ 146.457504272461051, -2.867500066757202 ] ] ], [ [ [ 147.0574951171875, -2.903888940811157 ], [ 147.056671142578125, -2.893333911895752 ], [ 147.06056213378929, -2.885833024978638 ], [ 147.062225341796875, -2.891665935516357 ], [ 147.0574951171875, -2.903888940811157 ] ] ], [ [ [ 146.402770996093864, -2.894999980926514 ], [ 146.405273437500114, -2.897222042083683 ], [ 146.403335571289176, -2.899722099304142 ], [ 146.400558471679688, -2.896666049957219 ], [ 146.402770996093864, -2.894999980926514 ] ] ], [ [ [ 146.357070922851562, -2.932179927825928 ], [ 146.359359741210938, -2.924243927001953 ], [ 146.362258911132812, -2.921946048736515 ], [ 146.357910156250114, -2.929743051528931 ], [ 146.357070922851562, -2.932179927825928 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-MBA", "NAME_1": "Milne Bay" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 153.51690673828125, -11.615481376647949 ], [ 153.508621215820312, -11.619959831237793 ], [ 153.506759643555029, -11.619292259216309 ], [ 153.515090942382926, -11.608474731445312 ], [ 153.51690673828125, -11.615481376647949 ] ] ], [ [ [ 153.571807861328125, -11.479016304016056 ], [ 153.57012939453125, -11.478189468383732 ], [ 153.570190429687727, -11.476605415344238 ], [ 153.572433471679915, -11.477639198303223 ], [ 153.571807861328125, -11.479016304016056 ] ] ], [ [ [ 153.165420532226676, -11.464864730834847 ], [ 153.162246704101562, -11.462795257568303 ], [ 153.161849975586051, -11.46163272857666 ], [ 153.168380737304801, -11.46356296539301 ], [ 153.165420532226676, -11.464864730834847 ] ] ], [ [ [ 154.39778137207054, -11.450555801391488 ], [ 154.39472961425804, -11.448612213134766 ], [ 154.397216796875227, -11.445278167724609 ], [ 154.399719238281364, -11.448056221008187 ], [ 154.39778137207054, -11.450555801391488 ] ] ], [ [ [ 153.230438232421875, -11.454758644104004 ], [ 153.228424072265739, -11.450098037719727 ], [ 153.238754272461051, -11.444993019103947 ], [ 153.238449096679688, -11.452369689941406 ], [ 153.230438232421875, -11.454758644104004 ] ] ], [ [ [ 154.285232543945426, -11.390815734863281 ], [ 154.283767700195312, -11.389302253723088 ], [ 154.284881591797102, -11.386754035949707 ], [ 154.286834716796989, -11.387578964233342 ], [ 154.285232543945426, -11.390815734863281 ] ] ], [ [ [ 153.336303710937727, -11.359085083007812 ], [ 153.3353271484375, -11.357193946838379 ], [ 153.336578369140625, -11.35493278503418 ], [ 153.339797973633267, -11.357372283935547 ], [ 153.336303710937727, -11.359085083007812 ] ] ], [ [ [ 153.203887939453125, -11.323422431945801 ], [ 153.263900756836051, -11.366751670837289 ], [ 153.289794921875227, -11.363666534423828 ], [ 153.496109008789062, -11.464443206787109 ], [ 153.692962646484375, -11.513125419616642 ], [ 153.708908081054801, -11.544005393981877 ], [ 153.746673583984489, -11.561665534973145 ], [ 153.775390625000114, -11.613405227661133 ], [ 153.763671875000114, -11.626899719238281 ], [ 153.724716186523551, -11.617778778076115 ], [ 153.698043823242301, -11.632749557495117 ], [ 153.673202514648892, -11.620876312255859 ], [ 153.670242309570312, -11.640362739562988 ], [ 153.634719848632926, -11.61805534362793 ], [ 153.586669921875114, -11.617263793945312 ], [ 153.550933837890852, -11.655380249023438 ], [ 153.526382446289176, -11.635556221008301 ], [ 153.556198120117188, -11.633316040039006 ], [ 153.555587768555029, -11.601767539978027 ], [ 153.532028198242415, -11.617211341857853 ], [ 153.505264282226562, -11.586693763732853 ], [ 153.450592041015852, -11.58806324005127 ], [ 153.471343994140852, -11.577095985412598 ], [ 153.456390380859489, -11.548890113830566 ], [ 153.439620971680029, -11.566054344177189 ], [ 153.411529541015739, -11.542951583862248 ], [ 153.415969848633154, -11.569561004638672 ], [ 153.358078002929915, -11.558357238769474 ], [ 153.34780883789108, -11.52137565612793 ], [ 153.359680175781364, -11.493135452270508 ], [ 153.306549072265852, -11.487515449523869 ], [ 153.268035888671989, -11.50407695770258 ], [ 153.300155639648438, -11.473365783691349 ], [ 153.263702392578239, -11.461607933044377 ], [ 153.245056152343864, -11.42835807800293 ], [ 153.224411010742301, -11.44100379943842 ], [ 153.205154418945426, -11.413942337036133 ], [ 153.214828491211051, -11.400161743164062 ], [ 153.185714721679688, -11.392017364501896 ], [ 153.1756591796875, -11.34536075592041 ], [ 153.203887939453125, -11.323422431945801 ] ] ], [ [ [ 153.116195678711165, -11.324403762817383 ], [ 153.114166259765739, -11.322786331176758 ], [ 153.116210937500114, -11.318444252014103 ], [ 153.119674682617415, -11.322150230407715 ], [ 153.116195678711165, -11.324403762817383 ] ] ], [ [ [ 153.406387329101562, -11.312432289123478 ], [ 153.441360473632812, -11.314120292663574 ], [ 153.480895996093864, -11.344844818115121 ], [ 153.416152954101676, -11.332935333251953 ], [ 153.406387329101562, -11.312432289123478 ] ] ], [ [ [ 152.30140686035179, -11.305086135864201 ], [ 152.299346923828239, -11.302654266357365 ], [ 152.30230712890625, -11.301813125610352 ], [ 152.303207397461051, -11.303462982177734 ], [ 152.30140686035179, -11.305086135864201 ] ] ], [ [ [ 154.031112670898438, -11.301667213439828 ], [ 154.027496337890625, -11.308055877685547 ], [ 154.008331298828239, -11.303333282470646 ], [ 154.011672973632812, -11.301944732666016 ], [ 154.031112670898438, -11.301667213439828 ] ] ], [ [ [ 153.257446289062614, -11.293543815612793 ], [ 153.244827270507926, -11.321766853332463 ], [ 153.233612060546989, -11.316219329833928 ], [ 153.247772216796875, -11.307626724243164 ], [ 153.242584228515739, -11.292795181274357 ], [ 153.257446289062614, -11.293543815612793 ] ] ], [ [ [ 154.211395263672102, -11.293332099914494 ], [ 154.262496948242188, -11.327501296997013 ], [ 154.28334045410179, -11.372221946716309 ], [ 154.285003662109375, -11.37944507598877 ], [ 154.283050537109716, -11.382223129272461 ], [ 154.284164428711051, -11.393888473510685 ], [ 154.250839233398438, -11.418334007263127 ], [ 154.149673461914176, -11.388504981994629 ], [ 154.150558471679915, -11.404444694519043 ], [ 154.129714965820312, -11.415555953979379 ], [ 154.112228393554801, -11.387778282165527 ], [ 154.103881835937955, -11.419721603393498 ], [ 154.050552368164062, -11.420277595519963 ], [ 154.016113281250227, -11.40916728973383 ], [ 153.996948242187841, -11.379166603088322 ], [ 153.9727783203125, -11.377498626708984 ], [ 153.979171752929688, -11.361944198608342 ], [ 154.009445190429915, -11.361390113830566 ], [ 154.011947631836392, -11.3397216796875 ], [ 154.042343139648779, -11.364945411682129 ], [ 154.047500610351562, -11.353055000305119 ], [ 154.122390747070426, -11.348893165588379 ], [ 154.06361389160179, -11.325277328491211 ], [ 154.08416748046875, -11.319723129272461 ], [ 154.057220458984716, -11.296667098999023 ], [ 154.114715576171989, -11.295832633972168 ], [ 154.123657226562727, -11.307975769042969 ], [ 154.135833740234375, -11.297779083251953 ], [ 154.128936767578466, -11.32658672332758 ], [ 154.150558471679915, -11.298054695129395 ], [ 154.211395263672102, -11.293332099914494 ] ] ], [ [ [ 152.371719360351562, -11.281917572021484 ], [ 152.370254516601676, -11.278404235839844 ], [ 152.378204345703125, -11.275468826293945 ], [ 152.3758544921875, -11.27993106842041 ], [ 152.371719360351562, -11.281917572021484 ] ] ], [ [ [ 152.355468750000114, -11.286123275756779 ], [ 152.353561401367301, -11.2815647125243 ], [ 152.358978271484602, -11.274042129516602 ], [ 152.360488891601562, -11.282597541809082 ], [ 152.355468750000114, -11.286123275756779 ] ] ], [ [ [ 152.38954162597679, -11.276680946349984 ], [ 152.381576538085938, -11.277310371398869 ], [ 152.381210327148551, -11.276213645935002 ], [ 152.392074584961051, -11.273681640624943 ], [ 152.38954162597679, -11.276680946349984 ] ] ], [ [ [ 152.139785766601562, -11.262415885925236 ], [ 152.134552001953239, -11.253896713256779 ], [ 152.137832641601676, -11.247124671936035 ], [ 152.140228271484489, -11.252057075500431 ], [ 152.139785766601562, -11.262415885925236 ] ] ], [ [ [ 153.100219726562727, -11.246892929077148 ], [ 153.105682373046875, -11.263183593749943 ], [ 153.09754943847679, -11.269082069396973 ], [ 153.0902099609375, -11.247257232665959 ], [ 153.100219726562727, -11.246892929077148 ] ] ], [ [ [ 153.100982666015852, -11.242345809936467 ], [ 153.10041809082054, -11.242345809936467 ], [ 153.098602294921875, -11.24041843414301 ], [ 153.101196289062614, -11.240107536315804 ], [ 153.100982666015852, -11.242345809936467 ] ] ], [ [ [ 152.176910400390625, -11.244659423828125 ], [ 152.174224853515739, -11.240923881530762 ], [ 152.174667358398779, -11.238726615905762 ], [ 152.17718505859375, -11.240617752075138 ], [ 152.176910400390625, -11.244659423828125 ] ] ], [ [ [ 153.107238769531477, -11.233877182006779 ], [ 153.105636596679801, -11.233395576477051 ], [ 153.105422973632926, -11.23236083984375 ], [ 153.107666015625227, -11.231947898864746 ], [ 153.107238769531477, -11.233877182006779 ] ] ], [ [ [ 153.094360351562614, -11.2127809524535 ], [ 153.089065551757812, -11.212388992309513 ], [ 153.09278869628929, -11.207466125488281 ], [ 153.095443725586165, -11.209506034851074 ], [ 153.094360351562614, -11.2127809524535 ] ] ], [ [ [ 152.027999877929688, -11.194232940673771 ], [ 152.027236938476562, -11.187260627746582 ], [ 152.030792236328239, -11.184272766113281 ], [ 152.033020019531477, -11.188847541808968 ], [ 152.027999877929688, -11.194232940673771 ] ] ], [ [ [ 152.017929077148438, -11.185661315917912 ], [ 152.011978149414062, -11.186302185058594 ], [ 152.011901855469205, -11.185118675231934 ], [ 152.01454162597679, -11.182561874389592 ], [ 152.017929077148438, -11.185661315917912 ] ] ], [ [ [ 151.997650146484489, -11.184823036193791 ], [ 151.99542236328125, -11.184426307678166 ], [ 151.99282836914108, -11.181384086608887 ], [ 151.99720764160179, -11.182584762573242 ], [ 151.997650146484489, -11.184823036193791 ] ] ], [ [ [ 153.097930908203352, -11.183327674865723 ], [ 153.115371704101904, -11.180298805236816 ], [ 153.241867065429688, -11.262625694274902 ], [ 153.188095092773438, -11.29368782043457 ], [ 153.16729736328125, -11.275593757629338 ], [ 153.185821533203352, -11.274263381958008 ], [ 153.167587280273438, -11.25283241271967 ], [ 153.13356018066429, -11.24848556518549 ], [ 153.116790771484489, -11.224056243896484 ], [ 153.103637695312727, -11.224120140075684 ], [ 153.106231689453125, -11.227713584899902 ], [ 153.10052490234375, -11.238697052001839 ], [ 153.102203369140739, -11.20953464508051 ], [ 153.0762939453125, -11.196754455566406 ], [ 153.097930908203352, -11.183327674865723 ] ] ], [ [ [ 151.343551635742415, -11.178819656372013 ], [ 151.34236145019554, -11.178334236144963 ], [ 151.344665527343864, -11.177374839782715 ], [ 151.3446044921875, -11.177854537963867 ], [ 151.343551635742415, -11.178819656372013 ] ] ], [ [ [ 153.08795166015625, -11.179651260375977 ], [ 153.086456298828239, -11.179018020629826 ], [ 153.084930419921989, -11.176289558410645 ], [ 153.089874267578352, -11.17839336395258 ], [ 153.08795166015625, -11.179651260375977 ] ] ], [ [ [ 151.95753479003929, -11.176881790161133 ], [ 151.95648193359375, -11.175960540771484 ], [ 151.957153320312727, -11.174347877502328 ], [ 151.958496093750455, -11.175285339355469 ], [ 151.95753479003929, -11.176881790161133 ] ] ], [ [ [ 151.816665649414062, -11.175833702087402 ], [ 151.816116333007812, -11.174167633056641 ], [ 151.817504882812614, -11.174167633056641 ], [ 151.818328857421875, -11.175000190734806 ], [ 151.816665649414062, -11.175833702087402 ] ] ], [ [ [ 152.950378417968864, -11.174949645996094 ], [ 152.952056884765625, -11.176125526428166 ], [ 152.949295043945312, -11.17693901062006 ], [ 152.949035644531364, -11.173984527587891 ], [ 152.950378417968864, -11.174949645996094 ] ] ], [ [ [ 151.974136352539517, -11.174698829650822 ], [ 151.97271728515625, -11.174429893493652 ], [ 151.97146606445358, -11.173337936401367 ], [ 151.974609375, -11.172109603881836 ], [ 151.974136352539517, -11.174698829650822 ] ] ], [ [ [ 152.970336914062727, -11.170845031738281 ], [ 152.969543457031364, -11.17523193359375 ], [ 152.963546752930029, -11.171751976013184 ], [ 152.966979980469091, -11.169511795043832 ], [ 152.970336914062727, -11.170845031738281 ] ] ], [ [ [ 152.945755004882926, -11.166730880737248 ], [ 152.950180053711051, -11.171998023986816 ], [ 152.930938720703125, -11.177534103393555 ], [ 152.937667846679915, -11.166921615600529 ], [ 152.945755004882926, -11.166730880737248 ] ] ], [ [ [ 152.918930053710938, -11.159298896789551 ], [ 152.927810668945767, -11.16389274597168 ], [ 152.923385620117301, -11.183581352233887 ], [ 152.902587890625114, -11.162406921386605 ], [ 152.918930053710938, -11.159298896789551 ] ] ], [ [ [ 152.89111328125, -11.159723281860352 ], [ 152.889617919921989, -11.158920288085938 ], [ 152.89166259765625, -11.157221794128361 ], [ 152.892227172851562, -11.158887863159123 ], [ 152.89111328125, -11.159723281860352 ] ] ], [ [ [ 152.901535034179801, -11.15955638885498 ], [ 152.898986816406477, -11.154461860656738 ], [ 152.902587890625114, -11.149806022644043 ], [ 152.903747558593977, -11.152422904968262 ], [ 152.901535034179801, -11.15955638885498 ] ] ], [ [ [ 153.020553588867301, -11.148612022399846 ], [ 153.044998168945312, -11.152777671813965 ], [ 153.023895263671989, -11.19194507598877 ], [ 153.03472900390625, -11.208332061767578 ], [ 152.969161987304801, -11.186944961547795 ], [ 152.99249267578125, -11.173055648803711 ], [ 152.995559692382926, -11.15110969543457 ], [ 153.020553588867301, -11.148612022399846 ] ] ], [ [ [ 152.790191650390625, -11.155496597290039 ], [ 152.773788452148438, -11.161986351013127 ], [ 152.768356323242642, -11.153643608093262 ], [ 152.787643432617188, -11.148552894592285 ], [ 152.790191650390625, -11.155496597290039 ] ] ], [ [ [ 152.692092895507812, -11.151041030883789 ], [ 152.691024780273438, -11.14951229095459 ], [ 152.69195556640625, -11.14723968505848 ], [ 152.692703247070654, -11.149612426757756 ], [ 152.692092895507812, -11.151041030883789 ] ] ], [ [ [ 152.82612609863304, -11.157267570495605 ], [ 152.820877075195654, -11.155904769897461 ], [ 152.83099365234375, -11.147067070007324 ], [ 152.831039428710938, -11.154582977294808 ], [ 152.82612609863304, -11.157267570495605 ] ] ], [ [ [ 153.078048706054915, -11.144998550414925 ], [ 153.090560913086051, -11.166666984558049 ], [ 153.051391601562727, -11.16833305358881 ], [ 153.051666259765966, -11.1522216796875 ], [ 153.078048706054915, -11.144998550414925 ] ] ], [ [ [ 151.256576538086165, -11.155081748962402 ], [ 151.253387451171989, -11.151568412780705 ], [ 151.256759643554915, -11.144887924194279 ], [ 151.259201049804915, -11.15173435211176 ], [ 151.256576538086165, -11.155081748962402 ] ] ], [ [ [ 152.869461059570426, -11.151424407958928 ], [ 152.875274658203125, -11.162152290344238 ], [ 152.868347167968864, -11.166685104370117 ], [ 152.860351562500114, -11.15449047088623 ], [ 152.869461059570426, -11.151424407958928 ] ] ], [ [ [ 152.789489746093864, -11.148160934448242 ], [ 152.78887939453125, -11.147862434387207 ], [ 152.791748046875, -11.141939163207951 ], [ 152.792999267578239, -11.143681526184082 ], [ 152.789489746093864, -11.148160934448242 ] ] ], [ [ [ 152.762908935546875, -11.142567634582463 ], [ 152.761749267578466, -11.141426086425668 ], [ 152.764968872070426, -11.140873908996468 ], [ 152.764602661132926, -11.141590118408146 ], [ 152.762908935546875, -11.142567634582463 ] ] ], [ [ [ 152.814056396484375, -11.145668983459473 ], [ 152.812744140625227, -11.145694732665959 ], [ 152.813140869140739, -11.139934539794922 ], [ 152.81549072265625, -11.144372940063477 ], [ 152.814056396484375, -11.145668983459473 ] ] ], [ [ [ 152.767913818359602, -11.140028953552189 ], [ 152.766204833984602, -11.138861656188965 ], [ 152.7681884765625, -11.13636589050293 ], [ 152.769638061523665, -11.138136863708439 ], [ 152.767913818359602, -11.140028953552189 ] ] ], [ [ [ 152.796279907226562, -11.143986701965275 ], [ 152.800338745117415, -11.135224342346135 ], [ 152.802291870117415, -11.134695053100529 ], [ 152.80134582519554, -11.142088890075684 ], [ 152.796279907226562, -11.143986701965275 ] ] ], [ [ [ 152.811203002929688, -11.132175445556527 ], [ 152.814239501953125, -11.136634826660099 ], [ 152.807434082031477, -11.137908935546875 ], [ 152.808685302734375, -11.132612228393555 ], [ 152.811203002929688, -11.132175445556527 ] ] ], [ [ [ 152.714096069335938, -11.138748168945256 ], [ 152.712707519531364, -11.137016296386662 ], [ 152.720779418945312, -11.131008148193303 ], [ 152.721893310546875, -11.134129524230957 ], [ 152.714096069335938, -11.138748168945256 ] ] ], [ [ [ 152.333160400390739, -11.132728576660099 ], [ 152.349349975586051, -11.135975837707463 ], [ 152.335144042968977, -11.139225959777775 ], [ 152.316970825195312, -11.127407073974496 ], [ 152.333160400390739, -11.132728576660099 ] ] ], [ [ [ 152.659866333007926, -11.140691757202092 ], [ 152.65289306640625, -11.134061813354492 ], [ 152.660171508789176, -11.122602462768555 ], [ 152.66421508789108, -11.128999710083008 ], [ 152.659866333007926, -11.140691757202092 ] ] ], [ [ [ 153.08534240722679, -11.122133255004883 ], [ 153.089538574218977, -11.123579978942871 ], [ 153.09010314941429, -11.124337196350098 ], [ 153.084014892578352, -11.121856689453068 ], [ 153.08534240722679, -11.122133255004883 ] ] ], [ [ [ 152.689636230468864, -11.11841964721674 ], [ 152.710754394531705, -11.13349437713623 ], [ 152.678756713867301, -11.150411605834904 ], [ 152.66761779785179, -11.137790679931584 ], [ 152.689636230468864, -11.11841964721674 ] ] ], [ [ [ 152.760742187500114, -11.126341819763184 ], [ 152.758163452148438, -11.12073802947998 ], [ 152.76374816894554, -11.117196083068791 ], [ 152.764099121093977, -11.117586135864258 ], [ 152.760742187500114, -11.126341819763184 ] ] ], [ [ [ 152.306671142578125, -11.123619079589844 ], [ 152.299209594726676, -11.123128890991154 ], [ 152.300460815429915, -11.117118835449219 ], [ 152.306594848632926, -11.120114326477051 ], [ 152.306671142578125, -11.123619079589844 ] ] ], [ [ [ 152.73699951171875, -11.121784210205078 ], [ 152.740234375, -11.132485389709359 ], [ 152.726409912109489, -11.137751579284611 ], [ 152.728164672851676, -11.114706993103027 ], [ 152.73699951171875, -11.121784210205078 ] ] ], [ [ [ 153.066970825195312, -11.108921051025391 ], [ 153.103271484375227, -11.120329856872559 ], [ 153.123992919921875, -11.14162635803217 ], [ 153.101135253906477, -11.123450279235783 ], [ 153.066970825195312, -11.108921051025391 ] ] ], [ [ [ 151.551818847656477, -11.108975410461426 ], [ 151.549743652343977, -11.108040809631291 ], [ 151.54879760742233, -11.104813575744572 ], [ 151.549987792968864, -11.104997634887695 ], [ 151.551818847656477, -11.108975410461426 ] ] ], [ [ [ 152.635955810547102, -11.111003875732308 ], [ 152.634902954101676, -11.10976409912098 ], [ 152.6400146484375, -11.104523658752385 ], [ 152.639053344726676, -11.108296394348145 ], [ 152.635955810547102, -11.111003875732308 ] ] ], [ [ [ 153.061203002930029, -11.104800224304199 ], [ 153.064208984375, -11.105487823486328 ], [ 153.0650634765625, -11.106864929199162 ], [ 153.058410644531477, -11.104867935180664 ], [ 153.061203002930029, -11.104800224304199 ] ] ], [ [ [ 152.497772216797216, -11.103335380554142 ], [ 152.505828857421875, -11.109167098999023 ], [ 152.507171630859375, -11.111943244934025 ], [ 152.493896484375114, -11.108888626098633 ], [ 152.497772216797216, -11.103335380554142 ] ] ], [ [ [ 152.607498168945312, -11.09666633605957 ], [ 152.609588623046875, -11.098213195800724 ], [ 152.606353759765625, -11.104190826416016 ], [ 152.603729248047102, -11.101359367370605 ], [ 152.607498168945312, -11.09666633605957 ] ] ], [ [ [ 151.13240051269554, -11.101332664489689 ], [ 151.12953186035179, -11.099334716796818 ], [ 151.133880615234375, -11.095384597778263 ], [ 151.135131835937614, -11.098570823669377 ], [ 151.13240051269554, -11.101332664489689 ] ] ], [ [ [ 151.148330688476562, -11.091389656066895 ], [ 151.146942138671875, -11.090555191040039 ], [ 151.147506713867301, -11.088889122009277 ], [ 151.148895263672216, -11.089999198913461 ], [ 151.148330688476562, -11.091389656066895 ] ] ], [ [ [ 152.313766479492188, -11.081418037414551 ], [ 152.313964843750227, -11.083211898803711 ], [ 152.311386108398438, -11.083279609680176 ], [ 152.311584472656364, -11.082521438598576 ], [ 152.313766479492188, -11.081418037414551 ] ] ], [ [ [ 152.542892456054915, -11.079569816589299 ], [ 152.53791809082054, -11.085189819335938 ], [ 152.532516479492188, -11.080642700195256 ], [ 152.533798217773551, -11.078838348388615 ], [ 152.542892456054915, -11.079569816589299 ] ] ], [ [ [ 152.355560302734489, -11.079002380371094 ], [ 152.358337402343864, -11.080833435058537 ], [ 152.352264404296875, -11.077898979187012 ], [ 152.353744506836051, -11.078106880187931 ], [ 152.355560302734489, -11.079002380371094 ] ] ], [ [ [ 152.562973022461051, -11.071619987487793 ], [ 152.58648681640625, -11.076393127441406 ], [ 152.59393310546875, -11.096032142639103 ], [ 152.563446044922102, -11.100720405578556 ], [ 152.547760009765625, -11.075252532958984 ], [ 152.562973022461051, -11.071619987487793 ] ] ], [ [ [ 151.541305541992415, -11.073799133300724 ], [ 151.540832519531364, -11.064998626708928 ], [ 151.53901672363304, -11.061341285705453 ], [ 151.542266845703239, -11.065647125244141 ], [ 151.541305541992415, -11.073799133300724 ] ] ], [ [ [ 152.53326416015625, -11.061375617980957 ], [ 152.538604736328125, -11.068333625793457 ], [ 152.533920288086165, -11.071903228759652 ], [ 152.528640747070426, -11.062574386596623 ], [ 152.53326416015625, -11.061375617980957 ] ] ], [ [ [ 152.5872802734375, -11.067964553833008 ], [ 152.58332824707054, -11.060555458068791 ], [ 152.584167480468864, -11.059445381164551 ], [ 152.586685180664062, -11.061875343322697 ], [ 152.5872802734375, -11.067964553833008 ] ] ], [ [ [ 151.532318115234375, -11.064202308654671 ], [ 151.530593872070312, -11.062620162963867 ], [ 151.531188964843977, -11.058502197265625 ], [ 151.534332275390625, -11.062815666198617 ], [ 151.532318115234375, -11.064202308654671 ] ] ], [ [ [ 152.51666259765625, -11.053056716918888 ], [ 152.514450073242301, -11.052779197692814 ], [ 152.515594482421989, -11.050244331359806 ], [ 152.517410278320426, -11.051898956298828 ], [ 152.51666259765625, -11.053056716918888 ] ] ], [ [ [ 152.49664306640625, -11.047778129577637 ], [ 152.499038696289517, -11.048514366149789 ], [ 152.4998779296875, -11.050462722778263 ], [ 152.495086669921989, -11.049216270446777 ], [ 152.49664306640625, -11.047778129577637 ] ] ], [ [ [ 152.452606201171875, -11.050754547119141 ], [ 152.447402954101676, -11.057464599609318 ], [ 152.434341430664176, -11.051135063171387 ], [ 152.459243774414404, -11.043445587158146 ], [ 152.452606201171875, -11.050754547119141 ] ] ], [ [ [ 152.403060913086051, -11.039164543151742 ], [ 152.405838012695654, -11.040834426879826 ], [ 152.401382446289517, -11.044721603393555 ], [ 152.401107788085938, -11.040555953979435 ], [ 152.403060913086051, -11.039164543151742 ] ] ], [ [ [ 152.490707397461051, -11.042763710021973 ], [ 152.491943359375114, -11.049145698547363 ], [ 152.47975158691429, -11.040452957153263 ], [ 152.481719970703239, -11.03866004943842 ], [ 152.490707397461051, -11.042763710021973 ] ] ], [ [ [ 152.559494018554915, -11.037996292114144 ], [ 152.560760498046875, -11.038265228271484 ], [ 152.560836791992642, -11.039443969726506 ], [ 152.558334350586165, -11.039509773254395 ], [ 152.559494018554915, -11.037996292114144 ] ] ], [ [ [ 152.383895874023551, -11.036667823791504 ], [ 152.384719848632812, -11.039164543151742 ], [ 152.381942749023551, -11.041943550109806 ], [ 152.381103515625227, -11.039164543151742 ], [ 152.383895874023551, -11.036667823791504 ] ] ], [ [ [ 152.516326904296875, -11.048215866088867 ], [ 152.508895874023665, -11.038612365722599 ], [ 152.511077880859375, -11.035482406616154 ], [ 152.517868041992415, -11.044021606445256 ], [ 152.516326904296875, -11.048215866088867 ] ] ], [ [ [ 152.545562744140852, -11.035277366638184 ], [ 152.544723510742188, -11.033611297607422 ], [ 152.546386718750114, -11.031389236450138 ], [ 152.546951293945426, -11.033332824707031 ], [ 152.545562744140852, -11.035277366638184 ] ] ], [ [ [ 151.319168090820426, -11.029998779296818 ], [ 151.316116333007926, -11.028332710266056 ], [ 151.317504882812841, -11.02500057220459 ], [ 151.32000732421875, -11.026389122009164 ], [ 151.319168090820426, -11.029998779296818 ] ] ], [ [ [ 152.79086303710983, -10.97815990447998 ], [ 152.789535522461051, -10.977084159850961 ], [ 152.79176330566429, -10.975627899169922 ], [ 152.79241943359375, -10.977051734924316 ], [ 152.79086303710983, -10.97815990447998 ] ] ], [ [ [ 151.083328247070312, -10.965556144714355 ], [ 151.082077026367301, -10.96507453918457 ], [ 151.081115722656705, -10.963890075683594 ], [ 151.083343505859602, -10.964160919189453 ], [ 151.083328247070312, -10.965556144714355 ] ] ], [ [ [ 152.700271606445426, -10.963334083557129 ], [ 152.701385498047102, -10.964165687561035 ], [ 152.70083618164108, -10.965277671813965 ], [ 152.698883056640739, -10.964165687561035 ], [ 152.700271606445426, -10.963334083557129 ] ] ], [ [ [ 152.6219482421875, -10.956942558288517 ], [ 152.624725341797102, -10.958889961242619 ], [ 152.621383666992188, -10.961943626403809 ], [ 152.6199951171875, -10.959721565246582 ], [ 152.6219482421875, -10.956942558288517 ] ] ], [ [ [ 152.716796875000227, -10.958929061889592 ], [ 152.716033935547102, -10.959550857543945 ], [ 152.715560913086051, -10.956667900085392 ], [ 152.71630859375, -10.957356452941838 ], [ 152.716796875000227, -10.958929061889592 ] ] ], [ [ [ 151.07557678222679, -10.954492568969727 ], [ 151.08753967285179, -10.957182884216309 ], [ 151.044998168945312, -10.961943626403809 ], [ 151.049438476562727, -10.958612442016602 ], [ 151.07557678222679, -10.954492568969727 ] ] ], [ [ [ 151.03582763671875, -10.952220916748047 ], [ 151.036666870117415, -10.954167366027832 ], [ 151.033615112304915, -10.954723358154297 ], [ 151.03285217285179, -10.952781677246037 ], [ 151.03582763671875, -10.952220916748047 ] ] ], [ [ [ 152.743087768554688, -10.954324722289982 ], [ 152.738143920898438, -10.956874847412053 ], [ 152.735687255859602, -10.955534934997559 ], [ 152.740524291992301, -10.950879096984806 ], [ 152.743087768554688, -10.954324722289982 ] ] ], [ [ [ 152.697494506835938, -10.954167366027832 ], [ 152.695831298828239, -10.953055381774902 ], [ 152.696945190429688, -10.950554847717285 ], [ 152.698333740234602, -10.951389312744141 ], [ 152.697494506835938, -10.954167366027832 ] ] ], [ [ [ 152.717987060547102, -10.946331977844238 ], [ 152.717010498046989, -10.944193840026855 ], [ 152.717926025390625, -10.943296432495004 ], [ 152.718856811523438, -10.94423866271967 ], [ 152.717987060547102, -10.946331977844238 ] ] ], [ [ [ 152.712783813476562, -10.943610191345101 ], [ 152.713333129882812, -10.945000648498535 ], [ 152.710052490234489, -10.9434814453125 ], [ 152.711380004882926, -10.942931175231877 ], [ 152.712783813476562, -10.943610191345101 ] ] ], [ [ [ 152.709197998047102, -10.942475318908635 ], [ 152.705490112304688, -10.946040153503418 ], [ 152.704330444336051, -10.945281028747559 ], [ 152.706039428711051, -10.941681861877441 ], [ 152.709197998047102, -10.942475318908635 ] ] ], [ [ [ 151.015670776367415, -10.942960739135742 ], [ 151.014480590820312, -10.941371917724609 ], [ 151.015258789062727, -10.93964672088623 ], [ 151.016372680664062, -10.942338943481388 ], [ 151.015670776367415, -10.942960739135742 ] ] ], [ [ [ 152.667495727539176, -10.924166679382324 ], [ 152.666381835937841, -10.922779083251953 ], [ 152.66888427734375, -10.921944618225098 ], [ 152.668655395507926, -10.923374176025391 ], [ 152.667495727539176, -10.924166679382324 ] ] ], [ [ [ 152.596817016601562, -10.922582626342717 ], [ 152.596038818359375, -10.922500610351562 ], [ 152.594772338867415, -10.920470237731934 ], [ 152.597229003906364, -10.921667098999023 ], [ 152.596817016601562, -10.922582626342717 ] ] ], [ [ [ 152.679992675781477, -10.91805362701416 ], [ 152.684234619140852, -10.919941902160645 ], [ 152.684585571289176, -10.922218322753906 ], [ 152.678894042968977, -10.920276641845703 ], [ 152.679992675781477, -10.91805362701416 ] ] ], [ [ [ 150.78890991210983, -10.922151565551758 ], [ 150.785324096679801, -10.92043399810791 ], [ 150.785171508789062, -10.917672157287598 ], [ 150.788146972656705, -10.91679859161377 ], [ 150.78890991210983, -10.922151565551758 ] ] ], [ [ [ 150.783065795898779, -10.912610054016113 ], [ 150.781463623047102, -10.9119615554809 ], [ 150.781173706054688, -10.910168647766056 ], [ 150.782623291015739, -10.910004615783691 ], [ 150.783065795898779, -10.912610054016113 ] ] ], [ [ [ 150.75794982910179, -10.905501365661621 ], [ 150.75666809082054, -10.904422760009709 ], [ 150.75811767578125, -10.902338027954102 ], [ 150.760162353515739, -10.904017448425236 ], [ 150.75794982910179, -10.905501365661621 ] ] ], [ [ [ 150.74639892578125, -10.90346622467041 ], [ 150.742660522460938, -10.897544860839787 ], [ 150.745666503906364, -10.895910263061523 ], [ 150.74932861328125, -10.899555206298771 ], [ 150.74639892578125, -10.90346622467041 ] ] ], [ [ [ 153.109191894531477, -10.893561363220215 ], [ 153.106597900390966, -10.892730712890625 ], [ 153.105422973632926, -10.891421318054142 ], [ 153.108139038085938, -10.891835212707463 ], [ 153.109191894531477, -10.893561363220215 ] ] ], [ [ [ 153.099411010742415, -10.890042304992619 ], [ 153.092224121094205, -10.890385627746582 ], [ 153.091094970703239, -10.88452243804926 ], [ 153.097671508789062, -10.886866569518929 ], [ 153.099411010742415, -10.890042304992619 ] ] ], [ [ [ 153.159408569336051, -10.884590148925724 ], [ 153.159164428711165, -10.883527755737305 ], [ 153.161148071289404, -10.882450103759766 ], [ 153.161300659179688, -10.88334846496582 ], [ 153.159408569336051, -10.884590148925724 ] ] ], [ [ [ 152.576950073242188, -10.879721641540527 ], [ 152.581665039062614, -10.883609771728459 ], [ 152.580551147461279, -10.884721755981388 ], [ 152.575836181640625, -10.881668090820312 ], [ 152.576950073242188, -10.879721641540527 ] ] ], [ [ [ 150.984283447265739, -10.876912117004395 ], [ 150.98512268066429, -10.877740859985352 ], [ 150.983367919921875, -10.877809524536133 ], [ 150.983230590820426, -10.876843452453613 ], [ 150.984283447265739, -10.876912117004395 ] ] ], [ [ [ 150.978057861328352, -10.878567695617676 ], [ 150.975006103515852, -10.878334045410156 ], [ 150.976470947265966, -10.87373161315918 ], [ 150.979263305664517, -10.876423835754281 ], [ 150.978057861328352, -10.878567695617676 ] ] ], [ [ [ 153.05195617675804, -10.86240291595459 ], [ 153.050415039062614, -10.86240291595459 ], [ 153.049377441406591, -10.861021041870117 ], [ 153.05181884765625, -10.859971046447754 ], [ 153.05195617675804, -10.86240291595459 ] ] ], [ [ [ 153.028427124023438, -10.859466552734375 ], [ 153.039886474609375, -10.860432624816895 ], [ 153.04219055175804, -10.861883163452148 ], [ 153.025344848633154, -10.861399650573617 ], [ 153.022064208984375, -10.857258796691895 ], [ 153.028427124023438, -10.859466552734375 ] ] ], [ [ [ 153.048049926757812, -10.854912757873535 ], [ 153.046905517578125, -10.85456657409668 ], [ 153.0484619140625, -10.852497100830078 ], [ 153.049377441406591, -10.853361129760685 ], [ 153.048049926757812, -10.854912757873535 ] ] ], [ [ [ 152.438522338867415, -10.844000816345215 ], [ 152.437408447265852, -10.843173027038517 ], [ 152.439880371093977, -10.843351364135629 ], [ 152.439804077148438, -10.843626976013127 ], [ 152.438522338867415, -10.844000816345215 ] ] ], [ [ [ 151.873336791992188, -10.834721565246525 ], [ 151.871948242187614, -10.83416557312006 ], [ 151.87689208984375, -10.833886146545296 ], [ 151.876129150390625, -10.834715843200684 ], [ 151.873336791992188, -10.834721565246525 ] ] ], [ [ [ 152.956939697265852, -10.832500457763615 ], [ 152.976943969726562, -10.839445114135629 ], [ 153.003936767578125, -10.857331275939885 ], [ 152.95916748046875, -10.841667175292912 ], [ 152.956939697265852, -10.832500457763615 ] ] ], [ [ [ 152.54833984375, -10.829722404479924 ], [ 152.552505493164176, -10.83166599273676 ], [ 152.553054809570426, -10.832221984863224 ], [ 152.547225952148438, -10.832221984863224 ], [ 152.54833984375, -10.829722404479924 ] ] ], [ [ [ 152.545272827148438, -10.828887939453068 ], [ 152.545562744140852, -10.830834388732796 ], [ 152.543060302734489, -10.829722404479924 ], [ 152.54388427734375, -10.828887939453068 ], [ 152.545272827148438, -10.828887939453068 ] ] ], [ [ [ 152.520553588867301, -10.829443931579533 ], [ 152.5191650390625, -10.829166412353459 ], [ 152.520278930664404, -10.825834274291992 ], [ 152.521118164062614, -10.826665878295785 ], [ 152.520553588867301, -10.829443931579533 ] ] ], [ [ [ 151.840545654296875, -10.825350761413461 ], [ 151.842498779297102, -10.825834274291992 ], [ 151.843048095703352, -10.826390266418457 ], [ 151.838058471679688, -10.824999809265137 ], [ 151.840545654296875, -10.825350761413461 ] ] ], [ [ [ 152.209869384765852, -10.824248313903809 ], [ 152.208160400390852, -10.822948455810547 ], [ 152.208648681640625, -10.82177734375 ], [ 152.209869384765852, -10.823351860046273 ], [ 152.209869384765852, -10.824248313903809 ] ] ], [ [ [ 151.8304443359375, -10.821330070495549 ], [ 151.827499389648551, -10.821260452270508 ], [ 151.827041625976676, -10.820076942443848 ], [ 151.829162597656477, -10.819998741149846 ], [ 151.8304443359375, -10.821330070495549 ] ] ], [ [ [ 152.498672485351676, -10.819450378417912 ], [ 152.506332397461051, -10.821736335754395 ], [ 152.489379882812841, -10.817655563354492 ], [ 152.491058349609375, -10.817033767700082 ], [ 152.498672485351676, -10.819450378417912 ] ] ], [ [ [ 152.995346069336051, -10.818563461303711 ], [ 152.994003295898551, -10.816892623901367 ], [ 152.995269775390852, -10.815395355224609 ], [ 152.996078491211165, -10.817466735839844 ], [ 152.995346069336051, -10.818563461303711 ] ] ], [ [ [ 152.216232299804801, -10.817817687988224 ], [ 152.217437744140625, -10.815359115600586 ], [ 152.218902587890739, -10.814739227294922 ], [ 152.218612670898551, -10.816110610961914 ], [ 152.216232299804801, -10.817817687988224 ] ] ], [ [ [ 152.180847167968864, -10.812683105468693 ], [ 152.190444946289176, -10.812406539916992 ], [ 152.191650390625, -10.813081741333008 ], [ 152.175338745117415, -10.814372062683049 ], [ 152.180847167968864, -10.812683105468693 ] ] ], [ [ [ 152.239624023437727, -10.813073158264103 ], [ 152.23849487304733, -10.813348770141602 ], [ 152.234466552734602, -10.805953025817871 ], [ 152.23695373535179, -10.807438850402775 ], [ 152.239624023437727, -10.813073158264103 ] ] ], [ [ [ 152.202499389648551, -10.806112289428711 ], [ 152.194473266601676, -10.810383796691895 ], [ 152.193557739257812, -10.810315132141056 ], [ 152.196563720703125, -10.807210922241097 ], [ 152.206634521484602, -10.804869651794434 ], [ 152.202499389648551, -10.806112289428711 ] ] ], [ [ [ 152.99110412597679, -10.805000305175781 ], [ 152.994445800781591, -10.808609962463322 ], [ 152.993896484375, -10.810278892517033 ], [ 152.988891601562614, -10.806112289428711 ], [ 152.99110412597679, -10.805000305175781 ] ] ], [ [ [ 152.232635498046989, -10.805113792419377 ], [ 152.221908569336051, -10.808675765991211 ], [ 152.212142944336165, -10.806303977966309 ], [ 152.229202270507926, -10.801856994628906 ], [ 152.232635498046989, -10.805113792419377 ] ] ], [ [ [ 151.92451477050804, -10.80997276306141 ], [ 151.920166015625114, -10.809878349304142 ], [ 151.918472290039062, -10.80142879486084 ], [ 151.929931640625114, -10.807079315185547 ], [ 151.92451477050804, -10.80997276306141 ] ] ], [ [ [ 151.908493041992415, -10.800902366638127 ], [ 151.908569335937614, -10.802194595336914 ], [ 151.898117065429688, -10.799725532531681 ], [ 151.900222778320312, -10.798160552978459 ], [ 151.908493041992415, -10.800902366638127 ] ] ], [ [ [ 152.488815307617188, -10.795564651489201 ], [ 152.487701416015625, -10.79175758361805 ], [ 152.488204956054801, -10.789877891540414 ], [ 152.4896240234375, -10.793834686279297 ], [ 152.488815307617188, -10.795564651489201 ] ] ], [ [ [ 152.395492553710938, -10.793891906738224 ], [ 152.389328002929801, -10.794111251830998 ], [ 152.387008666992188, -10.791601181030273 ], [ 152.392303466796875, -10.787932395935002 ], [ 152.395492553710938, -10.793891906738224 ] ] ], [ [ [ 152.001388549804915, -10.789723396301213 ], [ 151.998886108398551, -10.785000801086426 ], [ 152.007781982421875, -10.786666870117188 ], [ 152.005004882812727, -10.789167404174748 ], [ 152.001388549804915, -10.789723396301213 ] ] ], [ [ [ 150.426330566406364, -10.78477954864502 ], [ 150.425216674804801, -10.784296989440918 ], [ 150.425354003906477, -10.783398628234863 ], [ 150.426895141602017, -10.783742904663029 ], [ 150.426330566406364, -10.78477954864502 ] ] ], [ [ [ 151.829421997070426, -10.783334732055607 ], [ 151.827911376953466, -10.782997131347599 ], [ 151.826568603515739, -10.781081199645939 ], [ 151.830276489257926, -10.782113075256348 ], [ 151.829421997070426, -10.783334732055607 ] ] ], [ [ [ 151.881576538086165, -10.783147811889592 ], [ 151.878616333007926, -10.77944374084467 ], [ 151.879165649414176, -10.778610229492131 ], [ 151.882034301757812, -10.780209541320801 ], [ 151.881576538086165, -10.783147811889592 ] ] ], [ [ [ 150.430526733398551, -10.778154373168945 ], [ 150.43185424804733, -10.778085708618107 ], [ 150.431915283203239, -10.779741287231332 ], [ 150.429824829101904, -10.778429985046273 ], [ 150.430099487304801, -10.776775360107422 ], [ 150.430526733398551, -10.778154373168945 ] ] ], [ [ [ 150.426391601562841, -10.772506713867131 ], [ 150.4288330078125, -10.775068283080941 ], [ 150.428314208984375, -10.776176452636719 ], [ 150.42512512207054, -10.776060104370117 ], [ 150.426391601562841, -10.772506713867131 ] ] ], [ [ [ 151.870285034179688, -10.773056030273438 ], [ 151.871383666992301, -10.774443626403809 ], [ 151.860382080078125, -10.769924163818359 ], [ 151.866104125976562, -10.766432762145996 ], [ 151.870285034179688, -10.773056030273438 ] ] ], [ [ [ 151.688247680664062, -10.766947746276855 ], [ 151.699142456054801, -10.765865325927621 ], [ 151.706924438476676, -10.769707679748421 ], [ 151.677230834961279, -10.765849113464355 ], [ 151.688247680664062, -10.766947746276855 ] ] ], [ [ [ 150.676391601562614, -10.764445304870605 ], [ 150.681716918945767, -10.769774436950684 ], [ 150.681289672851676, -10.771875381469727 ], [ 150.676696777343977, -10.768825531005746 ], [ 150.676391601562614, -10.764445304870605 ] ] ], [ [ [ 151.7711181640625, -10.764720916747933 ], [ 151.770004272461051, -10.76361083984375 ], [ 151.77166748046875, -10.761944770812931 ], [ 151.771942138672102, -10.764166831970215 ], [ 151.7711181640625, -10.764720916747933 ] ] ], [ [ [ 152.445724487304688, -10.757413864135685 ], [ 152.443344116211392, -10.756851196289062 ], [ 152.44313049316429, -10.756022453307992 ], [ 152.444717407226676, -10.756110191345158 ], [ 152.445724487304688, -10.757413864135685 ] ] ], [ [ [ 150.420837402343864, -10.767498970031681 ], [ 150.411788940429801, -10.767759323120117 ], [ 150.409072875976562, -10.754356384277344 ], [ 150.420486450195312, -10.760547637939453 ], [ 150.420837402343864, -10.767498970031681 ] ] ], [ [ [ 152.40283203125, -10.755214691162109 ], [ 152.415756225586279, -10.782511711120549 ], [ 152.377395629882926, -10.776201248168888 ], [ 152.395477294921989, -10.75456523895258 ], [ 152.40283203125, -10.755214691162109 ] ] ], [ [ [ 151.833221435546989, -10.750859260559082 ], [ 151.829971313476562, -10.753874778747559 ], [ 151.828109741210938, -10.752780914306584 ], [ 151.829040527343864, -10.751151084899846 ], [ 151.833221435546989, -10.750859260559082 ] ] ], [ [ [ 150.39837646484375, -10.749794960021973 ], [ 150.384246826171875, -10.761762619018555 ], [ 150.359725952148665, -10.767498970031681 ], [ 150.383529663085938, -10.751941680908089 ], [ 150.39837646484375, -10.749794960021973 ] ] ], [ [ [ 151.314865112304688, -10.747644424438477 ], [ 151.317108154296989, -10.757694244384766 ], [ 151.304534912109716, -10.746354103088379 ], [ 151.306686401367188, -10.745083808898869 ], [ 151.314865112304688, -10.747644424438477 ] ] ], [ [ [ 151.721725463867188, -10.746328353881779 ], [ 151.72149658203125, -10.735962867736816 ], [ 151.730117797851562, -10.738742828369141 ], [ 151.728927612304688, -10.741061210632324 ], [ 151.721725463867188, -10.746328353881779 ] ] ], [ [ [ 151.819442749023665, -10.732222557067871 ], [ 151.83111572265625, -10.743612289428711 ], [ 151.829162597656477, -10.747777938842717 ], [ 151.816390991211165, -10.733332633972168 ], [ 151.819442749023665, -10.732222557067871 ] ] ], [ [ [ 150.684188842773665, -10.734716415405217 ], [ 150.682632446289176, -10.734365463256836 ], [ 150.682815551757926, -10.732028961181641 ], [ 150.684005737305142, -10.732753753662053 ], [ 150.684188842773665, -10.734716415405217 ] ] ], [ [ [ 151.737945556640852, -10.734025955200138 ], [ 151.737030029297102, -10.73367881774891 ], [ 151.743606567383154, -10.726710319518986 ], [ 151.743606567383154, -10.727469444274846 ], [ 151.737945556640852, -10.734025955200138 ] ] ], [ [ [ 150.233154296875114, -10.72817325592041 ], [ 150.23231506347679, -10.72822284698475 ], [ 150.230911254882812, -10.726343154907227 ], [ 150.233795166015625, -10.725497245788517 ], [ 150.233154296875114, -10.72817325592041 ] ] ], [ [ [ 150.755096435547102, -10.726433753967285 ], [ 150.753479003906364, -10.72544002532959 ], [ 150.756790161132812, -10.725411415100098 ], [ 150.756591796875, -10.725918769836369 ], [ 150.755096435547102, -10.726433753967285 ] ] ], [ [ [ 152.414733886719205, -10.729941368103027 ], [ 152.412109375000114, -10.727516174316349 ], [ 152.41400146484375, -10.722773551940918 ], [ 152.418792724609489, -10.72594165802002 ], [ 152.414733886719205, -10.729941368103027 ] ] ], [ [ [ 151.787506103515625, -10.721112251281738 ], [ 151.789169311523551, -10.7227783203125 ], [ 151.788894653320426, -10.723609924316349 ], [ 151.785278320312727, -10.721112251281738 ], [ 151.787506103515625, -10.721112251281738 ] ] ], [ [ [ 150.302719116211165, -10.722046852111816 ], [ 150.301971435546989, -10.73103141784668 ], [ 150.28096008300804, -10.729160308837891 ], [ 150.290740966796875, -10.720615386962891 ], [ 150.302719116211165, -10.722046852111816 ] ] ], [ [ [ 151.747222900390739, -10.723008155822754 ], [ 151.74806213378929, -10.719444274902344 ], [ 151.754241943359375, -10.718135833740234 ], [ 151.753906250000341, -10.71903133392334 ], [ 151.747222900390739, -10.723008155822754 ] ] ], [ [ [ 151.777374267578125, -10.718465805053711 ], [ 151.77113342285179, -10.719120025634709 ], [ 151.768234252929688, -10.717909812927246 ], [ 151.771102905273438, -10.715446472167969 ], [ 151.777374267578125, -10.718465805053711 ] ] ], [ [ [ 150.640518188477017, -10.717739105224609 ], [ 150.636962890625341, -10.717652320861816 ], [ 150.636032104492188, -10.713013648986816 ], [ 150.639144897461051, -10.714529991149846 ], [ 150.640518188477017, -10.717739105224609 ] ] ], [ [ [ 150.632369995117301, -10.710787773132267 ], [ 150.630966186523665, -10.714269638061523 ], [ 150.628479003906477, -10.713946342468205 ], [ 150.628707885742301, -10.711419105529728 ], [ 150.632369995117301, -10.710787773132267 ] ] ], [ [ [ 151.241668701171989, -10.709453582763672 ], [ 151.251617431640852, -10.713569641113224 ], [ 151.231338500976562, -10.714802742004395 ], [ 151.238723754882926, -10.709718704223576 ], [ 151.241668701171989, -10.709453582763672 ] ] ], [ [ [ 150.437698364257812, -10.702808380126896 ], [ 150.438339233398892, -10.70472335815424 ], [ 150.434722900390739, -10.70141410827631 ], [ 150.437149047851676, -10.700512886047363 ], [ 150.437698364257812, -10.702808380126896 ] ] ], [ [ [ 150.740234375000114, -10.704062461853027 ], [ 150.73738098144554, -10.704998970031738 ], [ 150.734481811523438, -10.699920654296875 ], [ 150.736770629882812, -10.699353218078613 ], [ 150.740234375000114, -10.704062461853027 ] ] ], [ [ [ 150.258300781250114, -10.697065353393555 ], [ 150.27593994140625, -10.709808349609375 ], [ 150.251678466797216, -10.705092430114632 ], [ 150.235931396484489, -10.722842216491699 ], [ 150.258300781250114, -10.697065353393555 ] ] ], [ [ [ 150.687011718750114, -10.695957183837834 ], [ 150.685943603515625, -10.695737838745117 ], [ 150.684936523437727, -10.694092750549316 ], [ 150.687728881835938, -10.694643974304199 ], [ 150.687011718750114, -10.695957183837834 ] ] ], [ [ [ 152.874099731445312, -10.690876960754395 ], [ 152.875839233398438, -10.69111156463623 ], [ 152.87611389160179, -10.691665649414006 ], [ 152.873672485351562, -10.691843032836914 ], [ 152.874099731445312, -10.690876960754395 ] ] ], [ [ [ 152.850555419922102, -10.691665649414006 ], [ 152.848327636718864, -10.690555572509766 ], [ 152.848617553711051, -10.689722061157227 ], [ 152.850830078125, -10.69111156463623 ], [ 152.850555419922102, -10.691665649414006 ] ] ], [ [ [ 150.434570312500114, -10.687351226806584 ], [ 150.441543579101676, -10.692892074584961 ], [ 150.436309814453466, -10.699261665344238 ], [ 150.432800292968977, -10.69437313079834 ], [ 150.434570312500114, -10.687351226806584 ] ] ], [ [ [ 150.732345581054688, -10.700045585632324 ], [ 150.711746215820312, -10.710320472717285 ], [ 150.697662353515625, -10.699466705322209 ], [ 150.719665527343977, -10.686760902404785 ], [ 150.732345581054688, -10.700045585632324 ] ] ], [ [ [ 152.88592529296875, -10.685381889343262 ], [ 152.888015747070654, -10.688828468322697 ], [ 152.883163452148665, -10.691328048705998 ], [ 152.881698608398551, -10.685076713562012 ], [ 152.88592529296875, -10.685381889343262 ] ] ], [ [ [ 150.676986694336051, -10.685057640075627 ], [ 150.681289672851676, -10.687148094177189 ], [ 150.682815551757926, -10.690632820129338 ], [ 150.67449951171875, -10.68828105926508 ], [ 150.676986694336051, -10.685057640075627 ] ] ], [ [ [ 150.313522338867188, -10.675083160400391 ], [ 150.3140869140625, -10.67619514465332 ], [ 150.312423706054915, -10.676470756530705 ], [ 150.312423706054915, -10.675639152526855 ], [ 150.313522338867188, -10.675083160400391 ] ] ], [ [ [ 151.123672485351562, -10.672902107238713 ], [ 151.120040893554801, -10.670166969299316 ], [ 151.120346069336165, -10.668662071227914 ], [ 151.12397766113304, -10.670660972595158 ], [ 151.123672485351562, -10.672902107238713 ] ] ], [ [ [ 151.111267089843864, -10.678222656249886 ], [ 151.10791015625, -10.676513671875 ], [ 151.109832763671875, -10.66776180267334 ], [ 151.115646362304801, -10.670987129211369 ], [ 151.111267089843864, -10.678222656249886 ] ] ], [ [ [ 151.066116333008154, -10.676944732666016 ], [ 151.06086730957054, -10.678214073181152 ], [ 151.056396484375, -10.670000076293945 ], [ 151.060714721679801, -10.668402671813965 ], [ 151.066116333008154, -10.676944732666016 ] ] ], [ [ [ 150.67599487304733, -10.670322418212891 ], [ 150.674331665039176, -10.669216156005859 ], [ 150.673828125, -10.667351722717228 ], [ 150.67599487304733, -10.669216156005859 ], [ 150.67599487304733, -10.670322418212891 ] ] ], [ [ [ 150.895660400390852, -10.666893959045353 ], [ 150.901046752929915, -10.673615455627441 ], [ 150.877166748047102, -10.6656236648559 ], [ 150.887512207031477, -10.661439895629883 ], [ 150.895660400390852, -10.666893959045353 ] ] ], [ [ [ 152.376358032226676, -10.661925315856934 ], [ 152.413391113281477, -10.691542625427189 ], [ 152.411071777343864, -10.724182128906193 ], [ 152.38507080078125, -10.700925827026367 ], [ 152.341690063476676, -10.707945823669377 ], [ 152.353195190430029, -10.667244911193791 ], [ 152.376358032226676, -10.661925315856934 ] ] ], [ [ [ 150.467773437500114, -10.659445762634277 ], [ 150.469299316406364, -10.660916328430176 ], [ 150.469421386718977, -10.662276268005257 ], [ 150.466659545898438, -10.661390304565316 ], [ 150.467773437500114, -10.659445762634277 ] ] ], [ [ [ 150.79959106445358, -10.659974098205566 ], [ 150.800079345703125, -10.661285400390625 ], [ 150.79841613769554, -10.659075736999512 ], [ 150.799041748046875, -10.659075736999512 ], [ 150.79959106445358, -10.659974098205566 ] ] ], [ [ [ 150.924118041992415, -10.659672737121582 ], [ 150.934158325195312, -10.670987129211369 ], [ 150.934234619140852, -10.681562423706055 ], [ 150.917236328125114, -10.673735618591309 ], [ 150.924118041992415, -10.659672737121582 ] ] ], [ [ [ 151.098007202148438, -10.658291816711369 ], [ 151.100936889648665, -10.672349929809513 ], [ 151.075561523437727, -10.664999961853027 ], [ 151.079513549804688, -10.657822608947697 ], [ 151.098007202148438, -10.658291816711369 ] ] ], [ [ [ 150.797821044922102, -10.65738487243641 ], [ 150.797286987304915, -10.657902717590275 ], [ 150.796310424804801, -10.654590606689453 ], [ 150.797286987304915, -10.655006408691406 ], [ 150.797821044922102, -10.65738487243641 ] ] ], [ [ [ 150.081512451171989, -10.653022766113224 ], [ 150.082550048828125, -10.653988838195744 ], [ 150.082000732421989, -10.655092239379826 ], [ 150.080398559570654, -10.653853416442814 ], [ 150.081512451171989, -10.653022766113224 ] ] ], [ [ [ 150.675003051757926, -10.648056983947754 ], [ 150.674438476562727, -10.649997711181527 ], [ 150.671951293945426, -10.64777946472168 ], [ 150.673614501953125, -10.646665573120117 ], [ 150.675003051757926, -10.648056983947754 ] ] ], [ [ [ 151.112991333007812, -10.649613380432072 ], [ 151.107223510742415, -10.649167060852051 ], [ 151.108459472656591, -10.642581939697266 ], [ 151.114257812500114, -10.647830963134766 ], [ 151.112991333007812, -10.649613380432072 ] ] ], [ [ [ 150.7430419921875, -10.641053199767953 ], [ 150.740798950195426, -10.640294075012093 ], [ 150.740737915039062, -10.639052391052246 ], [ 150.741363525390852, -10.638913154602051 ], [ 150.7430419921875, -10.641053199767953 ] ] ], [ [ [ 150.020614624023665, -10.63329029083252 ], [ 150.019729614257926, -10.63305473327631 ], [ 150.019500732421989, -10.631134033203125 ], [ 150.021179199218977, -10.631340980529785 ], [ 150.020614624023665, -10.63329029083252 ] ] ], [ [ [ 150.571823120117415, -10.629472732543945 ], [ 150.569671630859375, -10.631076812744084 ], [ 150.566604614257812, -10.626258850097656 ], [ 150.567626953125227, -10.625907897949219 ], [ 150.571823120117415, -10.629472732543945 ] ] ], [ [ [ 150.025894165039062, -10.625199317932072 ], [ 150.025833129882926, -10.626944541931152 ], [ 150.022781372070426, -10.626944541931152 ], [ 150.023605346679688, -10.625556945800724 ], [ 150.025894165039062, -10.625199317932072 ] ] ], [ [ [ 150.70668029785179, -10.626673698425236 ], [ 150.705062866210938, -10.625571250915527 ], [ 150.705551147461165, -10.624879837036133 ], [ 150.706954956054801, -10.625019073486328 ], [ 150.70668029785179, -10.626673698425236 ] ] ], [ [ [ 150.855865478515739, -10.623416900634766 ], [ 150.857803344726676, -10.625361442565861 ], [ 150.856689453125341, -10.626749038696232 ], [ 150.854476928711051, -10.624526977539006 ], [ 150.855865478515739, -10.623416900634766 ] ] ], [ [ [ 150.910903930664062, -10.622920036315918 ], [ 150.9095458984375, -10.622191429138127 ], [ 150.911361694336392, -10.620451927185059 ], [ 150.911804199218864, -10.621777534484806 ], [ 150.910903930664062, -10.622920036315918 ] ] ], [ [ [ 150.801773071289062, -10.622093200683594 ], [ 150.800567626953125, -10.622368812561035 ], [ 150.801513671875114, -10.618687629699707 ], [ 150.803085327148551, -10.620794296264648 ], [ 150.801773071289062, -10.622093200683594 ] ] ], [ [ [ 150.0167236328125, -10.617972373962402 ], [ 150.015396118164062, -10.618523597717228 ], [ 150.015045166015852, -10.617488861083984 ], [ 150.015884399414062, -10.617108345031681 ], [ 150.0167236328125, -10.617972373962402 ] ] ], [ [ [ 151.369003295898779, -10.619179725646916 ], [ 151.366912841796875, -10.6181383132934 ], [ 151.368881225586165, -10.616506576538086 ], [ 151.370193481445312, -10.617123603820801 ], [ 151.369003295898779, -10.619179725646916 ] ] ], [ [ [ 151.281997680664176, -10.618015289306584 ], [ 151.303833007812727, -10.619194030761605 ], [ 151.305267333984489, -10.626270294189453 ], [ 151.272277832031364, -10.620981216430664 ], [ 151.281997680664176, -10.618015289306584 ] ] ], [ [ [ 150.793807983398665, -10.619510650634766 ], [ 150.792633056640625, -10.618200302124023 ], [ 150.793960571289062, -10.616130828857365 ], [ 150.795074462890739, -10.618751525878906 ], [ 150.793807983398665, -10.619510650634766 ] ] ], [ [ [ 150.626113891601562, -10.616109848022461 ], [ 150.65625, -10.63227367401123 ], [ 150.672241210937614, -10.665988922119084 ], [ 150.634643554687614, -10.641925811767578 ], [ 150.626113891601562, -10.616109848022461 ] ] ], [ [ [ 150.020599365234602, -10.613869667053166 ], [ 150.019088745117415, -10.614353179931641 ], [ 150.018753051757812, -10.613799095153752 ], [ 150.019439697265739, -10.613249778747502 ], [ 150.020599365234602, -10.613869667053166 ] ] ], [ [ [ 150.893692016601904, -10.614143371582031 ], [ 150.893066406250114, -10.613315582275391 ], [ 150.894943237304915, -10.612900733947697 ], [ 150.895156860351676, -10.613452911376896 ], [ 150.893692016601904, -10.614143371582031 ] ] ], [ [ [ 150.62428283691429, -10.614242553710938 ], [ 150.62257385253929, -10.612709999084416 ], [ 150.62249755859375, -10.61139011383051 ], [ 150.625061035156477, -10.612216949462834 ], [ 150.62428283691429, -10.614242553710938 ] ] ], [ [ [ 150.0198974609375, -10.610015869140568 ], [ 150.019165039062614, -10.611577033996525 ], [ 150.017227172851562, -10.610834121704045 ], [ 150.017639160156364, -10.610138893127385 ], [ 150.0198974609375, -10.610015869140568 ] ] ], [ [ [ 152.792648315430029, -10.609356880187931 ], [ 152.878875732421875, -10.672062873840332 ], [ 152.83770751953125, -10.694956779479924 ], [ 152.768753051757926, -10.697096824645996 ], [ 152.759780883789176, -10.718280792236214 ], [ 152.682830810546875, -10.698370933532715 ], [ 152.648178100586165, -10.673517227172852 ], [ 152.623260498046989, -10.682223320007324 ], [ 152.518112182617642, -10.624959945678597 ], [ 152.542785644531591, -10.610224723815918 ], [ 152.684158325195312, -10.658238410949707 ], [ 152.792648315430029, -10.609356880187931 ] ] ], [ [ [ 150.665466308593864, -10.611691474914551 ], [ 150.666656494140739, -10.616314888000488 ], [ 150.660156250000227, -10.611759185791016 ], [ 150.661834716796989, -10.608725547790527 ], [ 150.665466308593864, -10.611691474914551 ] ] ], [ [ [ 150.633392333984375, -10.612928390502873 ], [ 150.638229370117642, -10.613651275634709 ], [ 150.63201904296875, -10.615758895874023 ], [ 150.627120971679801, -10.608771324157601 ], [ 150.633392333984375, -10.612928390502873 ] ] ], [ [ [ 150.011703491211051, -10.608379364013615 ], [ 150.010787963867188, -10.608102798461914 ], [ 150.010787963867188, -10.607136726379395 ], [ 150.012390136718864, -10.607688903808594 ], [ 150.011703491211051, -10.608379364013615 ] ] ], [ [ [ 150.653732299804801, -10.604721069335938 ], [ 150.652893066406477, -10.605411529541016 ], [ 150.652053833007812, -10.603894233703613 ], [ 150.652969360351676, -10.603754997253418 ], [ 150.653732299804801, -10.604721069335938 ] ] ], [ [ [ 150.01008605957054, -10.603820800781193 ], [ 150.011123657226562, -10.604651451110783 ], [ 150.009445190430029, -10.605685234069767 ], [ 150.009109497070312, -10.604442596435547 ], [ 150.01008605957054, -10.603820800781193 ] ] ], [ [ [ 151.380828857422216, -10.604124069213867 ], [ 151.37940979003929, -10.608025550842228 ], [ 151.371185302734489, -10.615691184997559 ], [ 151.373443603515625, -10.604434013366699 ], [ 151.380828857422216, -10.604124069213867 ] ] ], [ [ [ 151.369445800781477, -10.603333473205566 ], [ 151.368057250976562, -10.602223396301213 ], [ 151.368057250976562, -10.601111412048283 ], [ 151.369171142578239, -10.601111412048283 ], [ 151.369445800781477, -10.603333473205566 ] ] ], [ [ [ 151.305236816406364, -10.602390289306584 ], [ 151.303771972656591, -10.601185798644963 ], [ 151.30464172363304, -10.599866867065373 ], [ 151.306304931640625, -10.601056098937988 ], [ 151.305236816406364, -10.602390289306584 ] ] ], [ [ [ 151.226943969726562, -10.598054885864201 ], [ 151.245788574219091, -10.605570793151855 ], [ 151.256469726562841, -10.61878585815424 ], [ 151.230270385742642, -10.612500190734863 ], [ 151.226943969726562, -10.598054885864201 ] ] ], [ [ [ 149.935180664062955, -10.59576225280756 ], [ 149.934280395507926, -10.59451961517334 ], [ 149.935882568359602, -10.593484878539982 ], [ 149.93629455566429, -10.594244003295842 ], [ 149.935180664062955, -10.59576225280756 ] ] ], [ [ [ 150.68450927734375, -10.59691143035883 ], [ 150.682052612304801, -10.595598220825195 ], [ 150.682403564453125, -10.591595649719238 ], [ 150.68450927734375, -10.596287727355957 ], [ 150.68450927734375, -10.59691143035883 ] ] ], [ [ [ 150.022216796875114, -10.589165687560978 ], [ 150.022781372070426, -10.59083366394043 ], [ 150.019729614257926, -10.59416675567627 ], [ 150.019729614257926, -10.590554237365723 ], [ 150.022216796875114, -10.589165687560978 ] ] ], [ [ [ 151.041671752929801, -10.587571144104004 ], [ 151.039718627929915, -10.587778091430664 ], [ 151.039718627929915, -10.586668014526367 ], [ 151.042358398437614, -10.586112022399902 ], [ 151.041671752929801, -10.587571144104004 ] ] ], [ [ [ 150.64680480957054, -10.588855743408146 ], [ 150.641052246093864, -10.58641529083252 ], [ 150.640533447265739, -10.583245277404728 ], [ 150.642059326171989, -10.58348560333252 ], [ 150.64680480957054, -10.588855743408146 ] ] ], [ [ [ 150.734222412109489, -10.583434104919434 ], [ 150.736160278320312, -10.59121036529541 ], [ 150.727279663086165, -10.595657348632812 ], [ 150.728103637695426, -10.584821701049805 ], [ 150.734222412109489, -10.583434104919434 ] ] ], [ [ [ 151.367767333984602, -10.59458065032959 ], [ 151.361694335937614, -10.584076881408691 ], [ 151.362594604492301, -10.582939147949162 ], [ 151.371765136718977, -10.58728981018055 ], [ 151.367767333984602, -10.59458065032959 ] ] ], [ [ [ 151.20375061035179, -10.588580131530762 ], [ 151.211395263671989, -10.597500801086426 ], [ 151.185760498046875, -10.584987640380859 ], [ 151.194900512695312, -10.579777717590332 ], [ 151.20375061035179, -10.588580131530762 ] ] ], [ [ [ 151.280654907226562, -10.583161354064885 ], [ 151.280639648437614, -10.579925537109375 ], [ 151.28364562988304, -10.57895565032959 ], [ 151.282928466796989, -10.581884384155273 ], [ 151.280654907226562, -10.583161354064885 ] ] ], [ [ [ 149.917221069336165, -10.578888893127441 ], [ 149.916671752929915, -10.579721450805607 ], [ 149.913558959960938, -10.579463958740234 ], [ 149.913833618164176, -10.578634262084961 ], [ 149.917221069336165, -10.578888893127441 ] ] ], [ [ [ 150.620147705078239, -10.581191062927189 ], [ 150.61343383789108, -10.585082054138184 ], [ 150.611984252929688, -10.582346916198674 ], [ 150.6165771484375, -10.578380584716797 ], [ 150.620147705078239, -10.581191062927189 ] ] ], [ [ [ 151.027496337890852, -10.58552169799799 ], [ 151.041381835937727, -10.60916805267334 ], [ 151.06939697265625, -10.594119071960449 ], [ 151.073272705078352, -10.617301940917969 ], [ 151.049179077148438, -10.619464874267521 ], [ 151.037811279297102, -10.641597747802678 ], [ 151.069122314453125, -10.648754119872933 ], [ 151.042327880859375, -10.664096832275334 ], [ 151.051239013672216, -10.672992706298828 ], [ 151.010086059570312, -10.671465873718262 ], [ 150.987899780273551, -10.633910179138184 ], [ 150.971847534179688, -10.645620346069279 ], [ 150.934906005859375, -10.632609367370549 ], [ 150.905166625976562, -10.656510353088379 ], [ 150.900558471680029, -10.626388549804688 ], [ 150.919662475585938, -10.604207992553711 ], [ 151.027496337890852, -10.58552169799799 ] ] ], [ [ [ 149.933883666992301, -10.580555915832463 ], [ 149.933929443359375, -10.582989692687988 ], [ 149.929534912109375, -10.577153205871525 ], [ 149.931945800781364, -10.576389312744141 ], [ 149.933883666992301, -10.580555915832463 ] ] ], [ [ [ 150.90333557128929, -10.585277557373047 ], [ 150.893615722656477, -10.584444046020508 ], [ 150.908615112304688, -10.574444770812988 ], [ 150.907501220703239, -10.581386566162109 ], [ 150.90333557128929, -10.585277557373047 ] ] ], [ [ [ 150.706665039062614, -10.586321830749512 ], [ 150.724960327148665, -10.588102340698242 ], [ 150.716430664062955, -10.609092712402344 ], [ 150.754302978515625, -10.605063438415527 ], [ 150.73262023925804, -10.618071556091309 ], [ 150.758331298828352, -10.623332977294922 ], [ 150.757537841796875, -10.634099006652832 ], [ 150.685836791992188, -10.612221717834416 ], [ 150.701370239257926, -10.573434829711857 ], [ 150.706665039062614, -10.586321830749512 ] ] ], [ [ [ 151.198547363281477, -10.575897216796761 ], [ 151.197036743164176, -10.574296951293888 ], [ 151.198287963867301, -10.572450637817383 ], [ 151.199874877929688, -10.57413291931141 ], [ 151.198547363281477, -10.575897216796761 ] ] ], [ [ [ 150.71583557128929, -10.571389198303223 ], [ 150.717498779296875, -10.574444770812988 ], [ 150.713882446289062, -10.57722091674799 ], [ 150.713058471679801, -10.573055267333984 ], [ 150.71583557128929, -10.571389198303223 ] ] ], [ [ [ 150.730529785156477, -10.570308685302734 ], [ 150.72822570800804, -10.574397087097168 ], [ 150.725616455078125, -10.573884010314885 ], [ 150.725631713867301, -10.571235656738281 ], [ 150.730529785156477, -10.570308685302734 ] ] ], [ [ [ 150.802032470703239, -10.567609786987248 ], [ 150.800552368164176, -10.573326110839844 ], [ 150.794464111328125, -10.569803237914982 ], [ 150.795349121093864, -10.564590454101562 ], [ 150.802032470703239, -10.567609786987248 ] ] ], [ [ [ 151.259170532226562, -10.56385612487793 ], [ 151.256454467773551, -10.561788558959961 ], [ 151.258560180664176, -10.560076713562012 ], [ 151.260223388671989, -10.561945915222054 ], [ 151.259170532226562, -10.56385612487793 ] ] ], [ [ [ 151.902496337890625, -10.5625 ], [ 151.901107788085938, -10.560277938842717 ], [ 151.903060913086279, -10.559165954589844 ], [ 151.90388488769554, -10.561112403869572 ], [ 151.902496337890625, -10.5625 ] ] ], [ [ [ 150.775283813476562, -10.566665649414062 ], [ 150.773605346679801, -10.57166671752924 ], [ 150.75381469726608, -10.580500602722168 ], [ 150.75555419921875, -10.557222366332951 ], [ 150.775283813476562, -10.566665649414062 ] ] ], [ [ [ 150.722610473632812, -10.553103446960449 ], [ 150.728713989257812, -10.562019348144531 ], [ 150.725357055664176, -10.567648887634221 ], [ 150.71504211425804, -10.562680244445801 ], [ 150.722610473632812, -10.553103446960449 ] ] ], [ [ [ 150.710678100586165, -10.552695274352914 ], [ 150.712493896484716, -10.555069923400879 ], [ 150.709350585937727, -10.558423042297363 ], [ 150.706832885742415, -10.553869247436523 ], [ 150.710678100586165, -10.552695274352914 ] ] ], [ [ [ 151.121673583984375, -10.552221298217773 ], [ 151.120285034180029, -10.552221298217773 ], [ 151.120285034180029, -10.550555229187012 ], [ 151.122222900390625, -10.55111122131342 ], [ 151.121673583984375, -10.552221298217773 ] ] ], [ [ [ 151.828598022461165, -10.550030708312988 ], [ 151.828338623046875, -10.547875404357853 ], [ 151.829940795898892, -10.546094894409066 ], [ 151.829956054687614, -10.548439979553166 ], [ 151.828598022461165, -10.550030708312988 ] ] ], [ [ [ 151.213394165039062, -10.534917831420842 ], [ 151.211456298828466, -10.534189224243164 ], [ 151.212417602539062, -10.532272338867188 ], [ 151.214263916015739, -10.53344821929926 ], [ 151.213394165039062, -10.534917831420842 ] ] ], [ [ [ 149.853332519531477, -10.533887863159066 ], [ 149.85139465332054, -10.532777786254883 ], [ 149.852783203125455, -10.531665802001953 ], [ 149.853332519531477, -10.53209400177002 ], [ 149.853332519531477, -10.533887863159066 ] ] ], [ [ [ 151.246139526367301, -10.53944015502924 ], [ 151.243499755859716, -10.532595634460449 ], [ 151.245559692382812, -10.529765129089355 ], [ 151.247207641601676, -10.534392356872559 ], [ 151.246139526367301, -10.53944015502924 ] ] ], [ [ [ 150.864501953125114, -10.529520988464242 ], [ 150.901046752929915, -10.558303833007812 ], [ 150.883331298828239, -10.571110725402832 ], [ 150.896209716796875, -10.655139923095646 ], [ 150.813888549804915, -10.639444351196232 ], [ 150.794769287109602, -10.652419090270939 ], [ 150.784896850586165, -10.624303817749023 ], [ 150.760787963867188, -10.623269081115723 ], [ 150.764160156250114, -10.603660583496094 ], [ 150.835494995117301, -10.631745338439941 ], [ 150.838150024414062, -10.639469146728459 ], [ 150.872314453125114, -10.635919570922795 ], [ 150.860702514648438, -10.614056587219181 ], [ 150.828979492187614, -10.607134819030705 ], [ 150.834167480468864, -10.595834732055664 ], [ 150.789306640625114, -10.542819976806641 ], [ 150.807189941406477, -10.532607078552246 ], [ 150.839096069335938, -10.545596122741699 ], [ 150.845947265625114, -10.565773010253849 ], [ 150.849029541015739, -10.548953056335392 ], [ 150.865524291992415, -10.563913345336857 ], [ 150.864501953125114, -10.529520988464242 ] ] ], [ [ [ 151.086746215820312, -10.530268669128361 ], [ 151.085159301757926, -10.529281616210938 ], [ 151.085205078125, -10.526554107665959 ], [ 151.088531494140852, -10.528643608093205 ], [ 151.086746215820312, -10.530268669128361 ] ] ], [ [ [ 151.269195556640739, -10.532184600830021 ], [ 151.268325805664062, -10.526943206787053 ], [ 151.269805908203239, -10.525714874267521 ], [ 151.270828247070312, -10.530555725097656 ], [ 151.269195556640739, -10.532184600830021 ] ] ], [ [ [ 149.982131958007812, -10.5191650390625 ], [ 149.981155395507926, -10.517646789550781 ], [ 149.983673095703239, -10.518198013305664 ], [ 149.983673095703239, -10.518752098083496 ], [ 149.982131958007812, -10.5191650390625 ] ] ], [ [ [ 149.822448730468977, -10.516807556152344 ], [ 149.821914672851562, -10.52291202545166 ], [ 149.820404052734489, -10.523955345153752 ], [ 149.817794799804688, -10.516608238220215 ], [ 149.822448730468977, -10.516807556152344 ] ] ], [ [ [ 149.825149536132812, -10.482430458068791 ], [ 149.823425292968864, -10.480731964111328 ], [ 149.824340820312727, -10.479682922363281 ], [ 149.825469970703239, -10.480647087097168 ], [ 149.825149536132812, -10.482430458068791 ] ] ], [ [ [ 150.659439086914176, -10.480278015136719 ], [ 150.655654907226904, -10.480861663818359 ], [ 150.655273437500341, -10.477499961853027 ], [ 150.656387329101676, -10.477222442626953 ], [ 150.659439086914176, -10.480278015136719 ] ] ], [ [ [ 149.842498779296989, -10.478334426879883 ], [ 149.86468505859375, -10.49193096160883 ], [ 149.846954345703125, -10.524920463561955 ], [ 149.841751098632812, -10.505948066711426 ], [ 149.823944091796989, -10.507349967956543 ], [ 149.827255249023438, -10.478856086730957 ], [ 149.842498779296989, -10.478334426879883 ] ] ], [ [ [ 150.11250305175804, -10.458490371704102 ], [ 150.108337402343977, -10.457777976989689 ], [ 150.110549926757812, -10.451944351196232 ], [ 150.112426757812614, -10.45366001129139 ], [ 150.11250305175804, -10.458490371704102 ] ] ], [ [ [ 150.101104736328352, -10.445834159851074 ], [ 150.099716186523438, -10.464722633361703 ], [ 150.113327026367642, -10.470832824707031 ], [ 150.08721923828125, -10.475833892822209 ], [ 150.101104736328352, -10.445834159851074 ] ] ], [ [ [ 151.221298217773665, -10.432756423950195 ], [ 151.218368530273438, -10.430234909057617 ], [ 151.219879150390625, -10.428402900695801 ], [ 151.223052978515625, -10.429713249206543 ], [ 151.221298217773665, -10.432756423950195 ] ] ], [ [ [ 151.315826416015625, -10.424669265747013 ], [ 151.31721496582054, -10.42722225189209 ], [ 151.310836791992188, -10.427778244018555 ], [ 151.311752319336051, -10.422294616699219 ], [ 151.315826416015625, -10.424669265747013 ] ] ], [ [ [ 151.440277099609489, -10.407501220703125 ], [ 151.443328857421989, -10.409723281860352 ], [ 151.442779541015625, -10.410833358764592 ], [ 151.438888549804801, -10.408611297607365 ], [ 151.440277099609489, -10.407501220703125 ] ] ], [ [ [ 151.436660766601676, -10.406389236450195 ], [ 151.431015014648438, -10.402091979980469 ], [ 151.432327270508154, -10.399929046630803 ], [ 151.438705444336051, -10.402083396911564 ], [ 151.436660766601676, -10.406389236450195 ] ] ], [ [ [ 152.101028442382926, -10.390153884887638 ], [ 152.112686157226562, -10.38979434967041 ], [ 152.12080383300804, -10.392767906188851 ], [ 152.091888427734716, -10.401068687438965 ], [ 152.101028442382926, -10.390153884887638 ] ] ], [ [ [ 151.184509277343864, -10.394095420837346 ], [ 151.181106567382926, -10.390726089477482 ], [ 151.184326171875, -10.388174057006836 ], [ 151.186355590820426, -10.390334129333496 ], [ 151.184509277343864, -10.394095420837346 ] ] ], [ [ [ 151.421356201172102, -10.399979591369629 ], [ 151.411285400390739, -10.394040107726994 ], [ 151.412322998046875, -10.38630485534668 ], [ 151.421936035156477, -10.391058921813965 ], [ 151.421356201172102, -10.399979591369629 ] ] ], [ [ [ 150.359359741211165, -10.357138633728027 ], [ 150.360473632812614, -10.358250617980957 ], [ 150.358810424804801, -10.358804702758789 ], [ 150.358245849609489, -10.357417106628418 ], [ 150.359359741211165, -10.357138633728027 ] ] ], [ [ [ 150.626403808594205, -10.3560791015625 ], [ 150.625213623046989, -10.356425285339299 ], [ 150.623535156250227, -10.355941772460881 ], [ 150.625701904296989, -10.35428524017334 ], [ 150.626403808594205, -10.3560791015625 ] ] ], [ [ [ 151.413330078125114, -10.354166984558105 ], [ 151.416671752929801, -10.358055114746037 ], [ 151.415237426757926, -10.360127449035645 ], [ 151.41146850585983, -10.356123924255314 ], [ 151.413330078125114, -10.354166984558105 ] ] ], [ [ [ 150.617446899414176, -10.354652404785156 ], [ 150.617126464844091, -10.355549812316895 ], [ 150.616088867187727, -10.354375839233342 ], [ 150.616928100586051, -10.353963851928711 ], [ 150.617446899414176, -10.354652404785156 ] ] ], [ [ [ 150.362136840820312, -10.352999687194711 ], [ 150.36212158203125, -10.355469703674316 ], [ 150.35877990722679, -10.355221748351994 ], [ 150.35877990722679, -10.354616165161133 ], [ 150.362136840820312, -10.352999687194711 ] ] ], [ [ [ 151.385498046875227, -10.355413436889648 ], [ 151.384445190429801, -10.354998588561898 ], [ 151.384994506836051, -10.351944923400879 ], [ 151.386383056640625, -10.354166984558105 ], [ 151.385498046875227, -10.355413436889648 ] ] ], [ [ [ 150.662872314453239, -10.352069854736214 ], [ 150.662918090820312, -10.350551605224609 ], [ 150.664077758789062, -10.350241661071777 ], [ 150.66413879394554, -10.351172447204533 ], [ 150.662872314453239, -10.352069854736214 ] ] ], [ [ [ 150.377975463867188, -10.34908390045166 ], [ 150.377975463867188, -10.350193977355957 ], [ 150.376861572265852, -10.350472450256234 ], [ 150.376861572265852, -10.348806381225586 ], [ 150.377975463867188, -10.34908390045166 ] ] ], [ [ [ 150.647216796875, -10.352545738220215 ], [ 150.643051147461051, -10.355833053588754 ], [ 150.640975952148438, -10.355124473571777 ], [ 150.644912719726676, -10.346784591674805 ], [ 150.647216796875, -10.352545738220215 ] ] ], [ [ [ 150.367691040039062, -10.343500137329045 ], [ 150.36964416503929, -10.345722198486328 ], [ 150.367965698242301, -10.349057197570801 ], [ 150.366027832031477, -10.348501205444336 ], [ 150.367691040039062, -10.343500137329045 ] ] ], [ [ [ 151.125000000000114, -10.342499732971191 ], [ 151.126388549805029, -10.343890190124512 ], [ 151.125549316406477, -10.345556259155273 ], [ 151.123611450195426, -10.343609809875488 ], [ 151.125000000000114, -10.342499732971191 ] ] ], [ [ [ 150.671661376953239, -10.341943740844727 ], [ 150.677719116211051, -10.344259262084904 ], [ 150.67860412597679, -10.347222328185978 ], [ 150.67274475097679, -10.345300674438477 ], [ 150.671661376953239, -10.341943740844727 ] ] ], [ [ [ 150.6484375, -10.339856147766056 ], [ 150.648712158203352, -10.342063903808594 ], [ 150.648132324218977, -10.342616081237793 ], [ 150.646789550781477, -10.340408325195256 ], [ 150.6484375, -10.339856147766056 ] ] ], [ [ [ 150.654998779297102, -10.343609809875488 ], [ 150.653335571289176, -10.340000152587891 ], [ 150.661392211914062, -10.3397216796875 ], [ 150.661117553711392, -10.340833663940373 ], [ 150.654998779297102, -10.343609809875488 ] ] ], [ [ [ 151.877456665039062, -10.331171989440918 ], [ 151.883255004882812, -10.336991310119572 ], [ 151.868667602539176, -10.341943740844727 ], [ 151.874252319336051, -10.330698013305664 ], [ 151.877456665039062, -10.331171989440918 ] ] ], [ [ [ 150.962707519531364, -10.323500633239689 ], [ 150.96087646484375, -10.321776390075627 ], [ 150.961090087890852, -10.321294784545842 ], [ 150.96241760253929, -10.321706771850586 ], [ 150.962707519531364, -10.323500633239689 ] ] ], [ [ [ 150.378585815429915, -10.320674896240178 ], [ 150.379150390625227, -10.322123527526855 ], [ 150.376449584960938, -10.321086883544922 ], [ 150.377746582031364, -10.320535659789982 ], [ 150.378585815429915, -10.320674896240178 ] ] ], [ [ [ 150.923004150390739, -10.30702018737793 ], [ 150.918991088867642, -10.306977272033635 ], [ 150.921340942382926, -10.301156044006291 ], [ 150.924545288085938, -10.304686546325684 ], [ 150.923004150390739, -10.30702018737793 ] ] ], [ [ [ 151.04829406738304, -10.310020446777344 ], [ 151.046249389648551, -10.302463531494084 ], [ 151.04876708984375, -10.300399780273438 ], [ 151.05134582519554, -10.304727554321289 ], [ 151.04829406738304, -10.310020446777344 ] ] ], [ [ [ 150.928741455078125, -10.28538703918457 ], [ 150.928344726562614, -10.280267715454045 ], [ 150.932174682617188, -10.27955245971674 ], [ 150.933303833007926, -10.28354454040516 ], [ 150.928741455078125, -10.28538703918457 ] ] ], [ [ [ 151.050399780273665, -10.291072845458984 ], [ 151.047546386719205, -10.287182807922363 ], [ 151.045944213867188, -10.27911472320551 ], [ 151.050247192382812, -10.282271385192871 ], [ 151.050399780273665, -10.291072845458984 ] ] ], [ [ [ 151.033447265625114, -10.267210960388184 ], [ 151.037506103515966, -10.284998893737679 ], [ 151.015060424804915, -10.292841911315918 ], [ 151.018569946289176, -10.309117317199707 ], [ 151.016525268555029, -10.313353538513184 ], [ 150.997558593750227, -10.272750854492188 ], [ 151.033447265625114, -10.267210960388184 ] ] ], [ [ [ 151.850830078125, -10.255210876464844 ], [ 151.849716186523665, -10.255832672119084 ], [ 151.848052978515852, -10.254999160766545 ], [ 151.850204467773551, -10.253829956054631 ], [ 151.850830078125, -10.255210876464844 ] ] ], [ [ [ 151.858886718750114, -10.262222290039006 ], [ 151.853866577148438, -10.258005142211914 ], [ 151.86334228515625, -10.249504089355469 ], [ 151.866149902343977, -10.253306388854924 ], [ 151.858886718750114, -10.262222290039006 ] ] ], [ [ [ 151.860549926757812, -10.243610382080021 ], [ 151.860412597656364, -10.242232322692871 ], [ 151.862640380859375, -10.240921020507812 ], [ 151.862228393554801, -10.242160797119141 ], [ 151.860549926757812, -10.243610382080021 ] ] ], [ [ [ 151.863937377929801, -10.238774299621525 ], [ 151.862869262695312, -10.237629890441838 ], [ 151.864440917968977, -10.234999656677189 ], [ 151.865264892578239, -10.237280845642033 ], [ 151.863937377929801, -10.238774299621525 ] ] ], [ [ [ 150.608612060547102, -10.226667404174805 ], [ 150.60444641113304, -10.240278244018555 ], [ 150.588607788086165, -10.238333702087346 ], [ 150.597503662109375, -10.229446411132812 ], [ 150.608612060547102, -10.226667404174805 ] ] ], [ [ [ 151.866378784179801, -10.227946281433049 ], [ 151.865325927734375, -10.226245880126896 ], [ 151.86726379394554, -10.221774101257211 ], [ 151.869140625, -10.224384307861328 ], [ 151.866378784179801, -10.227946281433049 ] ] ], [ [ [ 150.885086059570426, -10.225601196289006 ], [ 150.87921142578125, -10.226257324218693 ], [ 150.878784179687614, -10.222438812255803 ], [ 150.885116577148438, -10.220906257629395 ], [ 150.885086059570426, -10.225601196289006 ] ] ], [ [ [ 150.905380249023438, -10.208294868469238 ], [ 150.907714843750227, -10.209472656249943 ], [ 150.903839111328125, -10.21099758148182 ], [ 150.903213500976676, -10.209329605102482 ], [ 150.905380249023438, -10.208294868469238 ] ] ], [ [ [ 151.213363647461279, -10.209275245666504 ], [ 151.21112060546875, -10.20770263671875 ], [ 151.210815429687955, -10.205044746398926 ], [ 151.213714599609489, -10.207069396972656 ], [ 151.213363647461279, -10.209275245666504 ] ] ], [ [ [ 151.20416259765625, -10.198055267333984 ], [ 151.206939697265852, -10.200277328491154 ], [ 151.206390380859489, -10.201666831970215 ], [ 151.20222473144554, -10.199723243713379 ], [ 151.20416259765625, -10.198055267333984 ] ] ], [ [ [ 150.910461425781364, -10.019832611083984 ], [ 150.90882873535179, -10.018486022949219 ], [ 150.90882873535179, -10.017107963561955 ], [ 150.910156250000227, -10.01779842376709 ], [ 150.910461425781364, -10.019832611083984 ] ] ], [ [ [ 150.956146240234489, -10.016216278076172 ], [ 150.955245971679801, -10.016491889953556 ], [ 150.954269409179915, -10.015597343444824 ], [ 150.955169677734602, -10.015458106994629 ], [ 150.956146240234489, -10.016216278076172 ] ] ], [ [ [ 150.915039062500114, -10.015381813049316 ], [ 150.913223266601676, -10.014966964721623 ], [ 150.916015625, -10.011448860168457 ], [ 150.917495727539062, -10.012690544128418 ], [ 150.915039062500114, -10.015381813049316 ] ] ], [ [ [ 150.94166564941429, -10.00694465637207 ], [ 150.94500732421875, -10.016665458679199 ], [ 150.93556213378929, -10.019167900085449 ], [ 150.938888549804801, -10.007779121398926 ], [ 150.94166564941429, -10.00694465637207 ] ] ], [ [ [ 151.14642333984375, -9.981095314025822 ], [ 151.146438598632812, -9.982809066772461 ], [ 151.145538330078239, -9.98282337188715 ], [ 151.145538330078239, -9.98137092590332 ], [ 151.14642333984375, -9.981095314025822 ] ] ], [ [ [ 150.849014282226562, -9.954789161682072 ], [ 150.851577758789062, -9.955390930175781 ], [ 150.846237182617188, -9.959400177001953 ], [ 150.846755981445426, -9.955481529235783 ], [ 150.849014282226562, -9.954789161682072 ] ] ], [ [ [ 150.935272216797216, -9.845696449279785 ], [ 150.934722900390625, -9.84486198425293 ], [ 150.934997558593977, -9.843474388122559 ], [ 150.935836791992301, -9.843751907348633 ], [ 150.935272216797216, -9.845696449279785 ] ] ], [ [ [ 150.931961059570767, -9.835042953491211 ], [ 150.933319091796875, -9.835375785827637 ], [ 150.933319091796875, -9.835859298705998 ], [ 150.932022094726676, -9.836441040039062 ], [ 150.931961059570767, -9.835042953491211 ] ] ], [ [ [ 150.805847167968864, -9.817644119262638 ], [ 150.804870605468977, -9.817644119262638 ], [ 150.804595947265739, -9.816815376281738 ], [ 150.8057861328125, -9.816678047180119 ], [ 150.805847167968864, -9.817644119262638 ] ] ], [ [ [ 150.801528930664062, -9.815367698669434 ], [ 150.803756713867415, -9.817720413208008 ], [ 150.798614501953352, -9.820279121398926 ], [ 150.79833984375, -9.817776679992676 ], [ 150.801528930664062, -9.815367698669434 ] ] ], [ [ [ 150.803863525390625, -9.814536094665471 ], [ 150.802719116210938, -9.814328193664551 ], [ 150.80264282226608, -9.81259822845459 ], [ 150.804534912109602, -9.813013076782227 ], [ 150.803863525390625, -9.814536094665471 ] ] ], [ [ [ 149.889633178711051, -9.772000312805176 ], [ 149.890304565429915, -9.77582931518549 ], [ 149.884765625000227, -9.778111457824707 ], [ 149.886978149414176, -9.770355224609375 ], [ 149.889633178711051, -9.772000312805176 ] ] ], [ [ [ 150.889190673828239, -9.76346492767334 ], [ 150.887603759765625, -9.76170825958252 ], [ 150.888778686523438, -9.760316848754883 ], [ 150.890472412109375, -9.761659622192383 ], [ 150.889190673828239, -9.76346492767334 ] ] ], [ [ [ 150.873291015625, -9.741457939147949 ], [ 150.886581420898551, -9.762958526611271 ], [ 150.859207153320312, -9.766087532043457 ], [ 150.851165771484375, -9.741927146911621 ], [ 150.873291015625, -9.741457939147949 ] ] ], [ [ [ 150.739822387695312, -9.730889320373535 ], [ 150.738922119140852, -9.7322998046875 ], [ 150.737854003906364, -9.732007980346623 ], [ 150.739547729492301, -9.729256629943848 ], [ 150.739822387695312, -9.730889320373535 ] ] ], [ [ [ 150.898345947265739, -9.73951339721674 ], [ 150.891860961914176, -9.736015319824219 ], [ 150.894638061523551, -9.726268768310433 ], [ 150.899978637695426, -9.728815078735352 ], [ 150.898345947265739, -9.73951339721674 ] ] ], [ [ [ 150.90467834472679, -9.728833198547306 ], [ 150.903366088867301, -9.725689888000431 ], [ 150.906097412109375, -9.718132972717285 ], [ 150.910720825195312, -9.721455574035645 ], [ 150.90467834472679, -9.728833198547306 ] ] ], [ [ [ 150.759628295898438, -9.711709976196232 ], [ 150.818664550781705, -9.735564231872502 ], [ 150.846115112304915, -9.796950340270996 ], [ 150.899627685546875, -9.813596725463867 ], [ 150.991943359375, -9.916666030883732 ], [ 151.051605224609489, -9.941926002502441 ], [ 151.057296752929688, -9.962929725646973 ], [ 151.032531738281364, -9.945015907287598 ], [ 151.031845092773665, -9.986293792724609 ], [ 151.108688354492188, -10.040748596191406 ], [ 151.144989013672102, -10.034247398376408 ], [ 151.147262573242301, -9.989227294921875 ], [ 151.182785034179801, -9.93751335144043 ], [ 151.273681640625, -9.917057991027832 ], [ 151.294387817382812, -9.981977462768498 ], [ 151.267578125, -10.069696426391602 ], [ 151.237823486328125, -10.109890937805176 ], [ 151.229217529296875, -10.139814376830998 ], [ 151.240829467773779, -10.1522216796875 ], [ 151.222976684570426, -10.150107383728027 ], [ 151.229156494140625, -10.166494369506836 ], [ 151.212310791015852, -10.169466018676701 ], [ 151.22108459472679, -10.191325187683049 ], [ 151.19416809082054, -10.15361213684082 ], [ 151.155914306640625, -10.154430389404297 ], [ 151.151184082031591, -10.140447616577148 ], [ 151.113861083984602, -10.139934539794922 ], [ 151.062271118164176, -10.11309623718256 ], [ 150.956878662109375, -10.100440025329533 ], [ 150.946990966796989, -10.014899253845158 ], [ 150.97052001953125, -10.011919975280762 ], [ 150.960556030273665, -10.025522232055664 ], [ 150.972198486328352, -10.032094955444336 ], [ 150.984909057617188, -9.998377799987793 ], [ 150.946807861328352, -9.96125316619873 ], [ 150.948287963867188, -10.003738403320312 ], [ 150.91250610351608, -10.007223129272461 ], [ 150.890014648437614, -9.990571975707951 ], [ 150.874221801757926, -9.883955955505314 ], [ 150.849227905273551, -9.841447830200195 ], [ 150.795242309570426, -9.797810554504338 ], [ 150.767776489257926, -9.801945686340332 ], [ 150.786407470703352, -9.803016662597599 ], [ 150.773895263671989, -9.812221527099609 ], [ 150.759445190429688, -9.80003833770752 ], [ 150.739837646484602, -9.73437595367426 ], [ 150.759628295898438, -9.711709976196232 ] ] ], [ [ [ 150.99383544921875, -9.670831680297852 ], [ 150.995162963867529, -9.66817569732666 ], [ 150.997406005859375, -9.669403076171818 ], [ 150.996765136718864, -9.670213699340763 ], [ 150.99383544921875, -9.670831680297852 ] ] ], [ [ [ 150.81170654296875, -9.665387153625488 ], [ 150.811431884765739, -9.666492462158203 ], [ 150.809494018554915, -9.665925025939828 ], [ 150.809494018554915, -9.665370941162109 ], [ 150.81170654296875, -9.665387153625488 ] ] ], [ [ [ 150.998336791992642, -9.647603034973088 ], [ 150.998336791992642, -9.648721694946289 ], [ 150.998886108398665, -9.64982891082758 ], [ 150.996948242187727, -9.648419380187988 ], [ 150.998336791992642, -9.647603034973088 ] ] ], [ [ [ 151.00103759765625, -9.640722274780273 ], [ 151.00299072265625, -9.642242431640568 ], [ 150.998611450195312, -9.643716812133732 ], [ 150.998321533203352, -9.641242027282658 ], [ 151.00103759765625, -9.640722274780273 ] ] ], [ [ [ 150.930969238281364, -9.637921333312988 ], [ 150.930221557617415, -9.636772155761719 ], [ 150.931411743164062, -9.636062622070312 ], [ 150.931823730468864, -9.637324333190918 ], [ 150.930969238281364, -9.637921333312988 ] ] ], [ [ [ 150.930023193359602, -9.630949020385629 ], [ 150.929473876953352, -9.633175849914551 ], [ 150.926956176757926, -9.633148193359375 ], [ 150.927810668945426, -9.630965232849064 ], [ 150.930023193359602, -9.630949020385629 ] ] ], [ [ [ 150.02166748046875, -9.631388664245605 ], [ 150.019729614257926, -9.630276679992676 ], [ 150.023056030273665, -9.628610610961914 ], [ 150.023895263671875, -9.62944507598877 ], [ 150.02166748046875, -9.631388664245605 ] ] ], [ [ [ 149.838928222656591, -9.615680694580078 ], [ 149.840301513671875, -9.61594295501709 ], [ 149.840576171875455, -9.617008209228516 ], [ 149.838668823242642, -9.616786956786996 ], [ 149.838928222656591, -9.615680694580078 ] ] ], [ [ [ 149.771240234375, -9.605398178100586 ], [ 149.770019531250114, -9.603186607360783 ], [ 149.77267456054733, -9.601107597351017 ], [ 149.773010253906364, -9.603609085083008 ], [ 149.771240234375, -9.605398178100586 ] ] ], [ [ [ 149.7838134765625, -9.601254463195744 ], [ 149.781875610351676, -9.600424766540471 ], [ 149.781723022460938, -9.599455833435059 ], [ 149.782699584960938, -9.599455833435059 ], [ 149.7838134765625, -9.601254463195744 ] ] ], [ [ [ 149.77552795410179, -9.601023674011174 ], [ 149.773437500000455, -9.599547386169434 ], [ 149.773910522460938, -9.598035812377873 ], [ 149.777130126953466, -9.598842620849553 ], [ 149.77552795410179, -9.601023674011174 ] ] ], [ [ [ 149.781112670898551, -9.590277671813965 ], [ 149.795272827148438, -9.619166374206543 ], [ 149.838333129882926, -9.611667633056641 ], [ 149.830551147460938, -9.620834350585938 ], [ 149.879867553711392, -9.643044471740723 ], [ 150.01222229003929, -9.629722595214787 ], [ 150.012298583984489, -9.665233612060433 ], [ 150.057220458984602, -9.683889389038086 ], [ 150.055831909179688, -9.72389030456543 ], [ 150.012344360351562, -9.726114273071232 ], [ 149.995559692382812, -9.746943473815918 ], [ 149.952499389648551, -9.746943473815918 ], [ 149.925033569336051, -9.769989967346191 ], [ 149.892623901367415, -9.758950233459473 ], [ 149.875305175781364, -9.775803565979004 ], [ 149.769439697265739, -9.784763336181641 ], [ 149.713668823242188, -9.809018135070801 ], [ 149.715698242187614, -9.848771095275879 ], [ 149.758056640625341, -9.899162292480412 ], [ 149.809997558593977, -9.912500381469727 ], [ 149.82795715332054, -9.958764076232853 ], [ 149.86270141601608, -9.99040508270258 ], [ 149.85945129394554, -10.01722240447998 ], [ 149.89430236816429, -10.01777458190918 ], [ 149.929336547851904, -10.059962272644043 ], [ 150.00091552734375, -10.085470199584847 ], [ 150.093002319335938, -10.08620643615717 ], [ 150.12237548828125, -10.119779586791935 ], [ 150.18011474609375, -10.091977119445801 ], [ 150.204833984375114, -10.131487846374512 ], [ 150.246383666992188, -10.13416576385498 ], [ 150.294815063476562, -10.18610954284668 ], [ 150.360183715820426, -10.202178001403809 ], [ 150.425994873046989, -10.21359920501709 ], [ 150.460662841796989, -10.199616432189941 ], [ 150.51899719238304, -10.231644630432015 ], [ 150.545761108398551, -10.205608367919922 ], [ 150.586944580078125, -10.208612442016602 ], [ 150.597793579102017, -10.218320846557617 ], [ 150.567291259765739, -10.247936248779297 ], [ 150.598327636718864, -10.252221107482853 ], [ 150.612319946289062, -10.284957885742188 ], [ 150.653579711914062, -10.283462524414006 ], [ 150.703048706054915, -10.25555515289301 ], [ 150.779724121093977, -10.269444465637207 ], [ 150.837326049804915, -10.228116989135685 ], [ 150.874877929687727, -10.225442886352482 ], [ 150.760955810546875, -10.301300048828068 ], [ 150.734725952148665, -10.296943664550668 ], [ 150.718017578125114, -10.316129684448185 ], [ 150.650283813476676, -10.333333015441895 ], [ 150.632431030273438, -10.351620674133301 ], [ 150.588333129882812, -10.354957580566406 ], [ 150.410003662109375, -10.297779083251896 ], [ 150.343139648437727, -10.334395408630314 ], [ 150.34315490722679, -10.397128105163517 ], [ 150.426269531250227, -10.406169891357422 ], [ 150.595977783203125, -10.470512390136605 ], [ 150.651016235351676, -10.476724624633732 ], [ 150.693603515625114, -10.563887596130371 ], [ 150.658798217773665, -10.585308074951115 ], [ 150.648590087890739, -10.579071998596191 ], [ 150.616104125977017, -10.577776908874398 ], [ 150.554916381836051, -10.630660057067871 ], [ 150.472915649414176, -10.619669914245605 ], [ 150.466033935546989, -10.657586097717285 ], [ 150.418624877929688, -10.664162635803223 ], [ 150.427505493164176, -10.692221641540414 ], [ 150.411621093750227, -10.678358078002873 ], [ 150.362289428711051, -10.68602466583252 ], [ 150.354995727539176, -10.659721374511605 ], [ 150.324172973632812, -10.647223472595215 ], [ 150.30520629882858, -10.681070327758789 ], [ 150.288055419921989, -10.674722671508732 ], [ 150.255569458007926, -10.693015098571777 ], [ 150.241455078125114, -10.668927192687988 ], [ 150.24604797363304, -10.686260223388672 ], [ 150.202499389648438, -10.702778816223145 ], [ 150.205551147460938, -10.684445381164437 ], [ 150.183609008789062, -10.691944122314396 ], [ 150.172836303711392, -10.679012298583984 ], [ 150.198593139648551, -10.661827087402344 ], [ 150.19111633300804, -10.649444580078125 ], [ 150.138900756836051, -10.650403976440373 ], [ 150.115753173828352, -10.673899650573674 ], [ 150.103607177734489, -10.641943931579533 ], [ 150.08222961425804, -10.640000343322697 ], [ 150.080062866210938, -10.652201652526855 ], [ 150.056671142578352, -10.621945381164494 ], [ 150.039718627929801, -10.636112213134766 ], [ 150.033294677734375, -10.618828773498478 ], [ 150.01466369628929, -10.626708030700684 ], [ 150.036117553711051, -10.593963623046875 ], [ 150.019165039062614, -10.573888778686523 ], [ 150.000549316406477, -10.602505683898869 ], [ 149.9791259765625, -10.597979545593205 ], [ 149.975509643554688, -10.579837799072266 ], [ 149.960403442382926, -10.596231460571232 ], [ 149.969390869140966, -10.549868583679199 ], [ 149.952346801758267, -10.583765029907113 ], [ 149.949447631836051, -10.55805587768549 ], [ 149.930282592773551, -10.559165954589844 ], [ 149.926940917968864, -10.578332901000977 ], [ 149.905670166015739, -10.542224884033146 ], [ 149.903335571289176, -10.564722061157227 ], [ 149.881103515625, -10.573055267333984 ], [ 149.876480102539176, -10.55362510681141 ], [ 149.854171752929801, -10.552777290344238 ], [ 149.904861450195426, -10.524171829223633 ], [ 149.86457824707054, -10.526106834411621 ], [ 149.879592895507812, -10.502943992614746 ], [ 149.915542602539176, -10.521060943603402 ], [ 149.956390380859489, -10.51143836975092 ], [ 149.977432250976562, -10.52383899688715 ], [ 150.032211303711165, -10.498688697814941 ], [ 150.035552978515739, -10.513889312744084 ], [ 150.042221069336051, -10.51722335815424 ], [ 150.053222656250227, -10.473479270935059 ], [ 150.087478637695312, -10.47990894317627 ], [ 150.11447143554733, -10.47413444519043 ], [ 150.11468505859375, -10.466132164001465 ], [ 150.102874755859489, -10.464761734008789 ], [ 150.113327026367642, -10.459723472595215 ], [ 150.118835449218977, -10.449790000915471 ], [ 150.102081298828239, -10.439267158508301 ], [ 150.116622924804801, -10.422975540161019 ], [ 150.064407348632812, -10.466349601745605 ], [ 150.023056030273665, -10.464722633361703 ], [ 149.952987670898779, -10.42241096496582 ], [ 149.936096191406364, -10.441153526306152 ], [ 149.932785034179688, -10.431943893432617 ], [ 149.925827026367415, -10.433332443237248 ], [ 149.930465698242301, -10.44793701171875 ], [ 149.942413330078352, -10.44521427154541 ], [ 149.928100585937727, -10.492142677307129 ], [ 149.914306640625, -10.496242523193303 ], [ 149.871902465820426, -10.410915374755859 ], [ 149.800811767578125, -10.367812156677246 ], [ 149.750549316406705, -10.345556259155273 ], [ 149.64144897460983, -10.344300270080566 ], [ 149.66261291503929, -10.317034721374455 ], [ 149.664520263672102, -10.073233604431152 ], [ 149.653106689453125, -10.038134574890137 ], [ 149.521011352539062, -10.028834342956486 ], [ 149.385116577148551, -9.943234443664494 ], [ 149.319915771484489, -9.935934066772347 ], [ 149.324615478515852, -9.856535911560059 ], [ 149.177505493164062, -9.795333862304688 ], [ 149.134918212890739, -9.758234024047795 ], [ 149.023513793945426, -9.800736427307129 ], [ 148.966705322265625, -9.744834899902287 ], [ 148.978118896484489, -9.71253490447998 ], [ 149.005020141601676, -9.696434974670353 ], [ 149.087219238281364, -9.707134246826172 ], [ 149.441925048828352, -9.597958564758301 ], [ 149.456970214843864, -9.613333702087402 ], [ 149.47969055175804, -9.597801208496037 ], [ 149.546951293945312, -9.597776412963867 ], [ 149.616485595703125, -9.622769355773926 ], [ 149.644287109375227, -9.603155136108398 ], [ 149.692749023437727, -9.615399360656738 ], [ 149.744720458984375, -9.592499732971191 ], [ 149.771942138671875, -9.595277786254826 ], [ 149.775115966796989, -9.618110656738224 ], [ 149.781112670898551, -9.590277671813965 ] ] ], [ [ [ 149.77357482910179, -9.594234466552734 ], [ 149.770202636718864, -9.591777801513615 ], [ 149.775680541992301, -9.58994102478016 ], [ 149.774993896484375, -9.593111038208008 ], [ 149.77357482910179, -9.594234466552734 ] ] ], [ [ [ 151.004180908203125, -9.57655143737793 ], [ 151.031829833984375, -9.590825080871582 ], [ 151.022781372070312, -9.595493316650334 ], [ 151.024765014648438, -9.60095310211176 ], [ 151.024658203125455, -9.595631599426213 ], [ 151.036926269531364, -9.596529960632267 ], [ 151.019729614257812, -9.628072738647404 ], [ 151.045043945312727, -9.654148101806584 ], [ 151.025177001953352, -9.669267654418888 ], [ 151.00711059570358, -9.668852806091309 ], [ 151.022109985351562, -9.661110877990723 ], [ 151.013671875, -9.645628929138127 ], [ 151.000625610352017, -9.654191970825138 ], [ 151.006896972656477, -9.642864227294922 ], [ 151.003311157226676, -9.634154319763184 ], [ 150.952468872070312, -9.612910270690918 ], [ 150.963180541992415, -9.583267211914062 ], [ 151.004180908203125, -9.57655143737793 ] ] ], [ [ [ 152.480560302734375, -9.562221527099553 ], [ 152.489868164062727, -9.567703247070312 ], [ 152.490829467773665, -9.569722175598145 ], [ 152.47833251953125, -9.563334465026799 ], [ 152.480560302734375, -9.562221527099553 ] ] ], [ [ [ 150.47027587890625, -9.566111564636174 ], [ 150.469451904296875, -9.566944122314453 ], [ 150.46417236328125, -9.566944122314453 ], [ 150.467773437500114, -9.561389923095703 ], [ 150.47027587890625, -9.566111564636174 ] ] ], [ [ [ 152.43505859375, -9.550742149352971 ], [ 152.445587158203239, -9.549315452575627 ], [ 152.473617553711165, -9.562221527099553 ], [ 152.415283203125227, -9.568054199218636 ], [ 152.43505859375, -9.550742149352971 ] ] ], [ [ [ 150.369720458984489, -9.490556716918888 ], [ 150.376937866211051, -9.498611450195256 ], [ 150.358062744140625, -9.503054618835392 ], [ 150.356674194336165, -9.4977769851684 ], [ 150.369720458984489, -9.490556716918888 ] ] ], [ [ [ 150.989959716796989, -9.466279029846191 ], [ 150.98304748535179, -9.474041938781681 ], [ 150.97222900390625, -9.469850540161076 ], [ 150.978317260742301, -9.46653938293457 ], [ 150.989959716796989, -9.466279029846191 ] ] ], [ [ [ 150.95416259765625, -9.453333854675293 ], [ 150.966110229492301, -9.459444046020451 ], [ 150.970550537109489, -9.469166755676213 ], [ 150.956954956054801, -9.462944984436035 ], [ 150.95416259765625, -9.453333854675293 ] ] ], [ [ [ 151.940551757812727, -9.390276908874512 ], [ 151.938888549804801, -9.389445304870605 ], [ 151.938125610351676, -9.385255813598576 ], [ 151.941421508789062, -9.387352943420353 ], [ 151.940551757812727, -9.390276908874512 ] ] ], [ [ [ 152.063613891601562, -9.383056640625 ], [ 152.062637329102017, -9.381662368774414 ], [ 152.064163208008267, -9.380558967590275 ], [ 152.064880371093864, -9.381864547729492 ], [ 152.063613891601562, -9.383056640625 ] ] ], [ [ [ 151.946670532227017, -9.382500648498535 ], [ 151.945068359375, -9.380096435546875 ], [ 151.948059082031364, -9.37891960144043 ], [ 151.948715209961165, -9.379836082458439 ], [ 151.946670532227017, -9.382500648498535 ] ] ], [ [ [ 150.392776489257812, -9.380398750305176 ], [ 150.391159057617188, -9.377589225769043 ], [ 150.398910522461051, -9.375408172607365 ], [ 150.396438598632926, -9.37885570526123 ], [ 150.392776489257812, -9.380398750305176 ] ] ], [ [ [ 150.40765380859375, -9.367671966552678 ], [ 150.406005859375, -9.371833801269531 ], [ 150.40240478515625, -9.373520851135197 ], [ 150.401535034179801, -9.371005058288574 ], [ 150.40765380859375, -9.367671966552678 ] ] ], [ [ [ 150.408355712890739, -9.366827011108398 ], [ 150.40850830078125, -9.367128372192326 ], [ 150.407958984375227, -9.367294311523381 ], [ 150.407913208007812, -9.366851806640625 ], [ 150.408355712890739, -9.366827011108398 ] ] ], [ [ [ 150.408355712890739, -9.366827011108398 ], [ 150.4090576171875, -9.365179061889648 ], [ 150.413192749023438, -9.362955093383732 ], [ 150.412658691406591, -9.365511894226074 ], [ 150.408355712890739, -9.366827011108398 ] ] ], [ [ [ 152.026260375976676, -9.346529006957951 ], [ 152.024444580078239, -9.34666633605957 ], [ 152.022781372070426, -9.344443321228027 ], [ 152.024932861328239, -9.343900680541992 ], [ 152.026260375976676, -9.346529006957951 ] ] ], [ [ [ 152.49456787109375, -9.340914726257324 ], [ 152.496597290039176, -9.34105396270752 ], [ 152.496948242187614, -9.341388702392578 ], [ 152.494995117187614, -9.343055725097599 ], [ 152.49456787109375, -9.340914726257324 ] ] ], [ [ [ 150.880310058593864, -9.333539962768555 ], [ 150.884231567382926, -9.334912300109863 ], [ 150.884201049804688, -9.335463523864746 ], [ 150.880615234375114, -9.336029052734375 ], [ 150.880310058593864, -9.333539962768555 ] ] ], [ [ [ 150.689865112304915, -9.333745002746525 ], [ 150.691574096679915, -9.337139129638615 ], [ 150.686141967773551, -9.337321281433049 ], [ 150.68695068359375, -9.332815170288029 ], [ 150.689865112304915, -9.333745002746525 ] ] ], [ [ [ 150.713363647461165, -9.335345268249512 ], [ 150.71144104003929, -9.33371639251709 ], [ 150.712982177734602, -9.332039833068791 ], [ 150.714248657226562, -9.332788467407227 ], [ 150.713363647461165, -9.335345268249512 ] ] ], [ [ [ 150.487442016601562, -9.327259063720703 ], [ 150.623336791992415, -9.387777328491211 ], [ 150.63722229003929, -9.419999122619629 ], [ 150.662368774414062, -9.430809020996037 ], [ 150.737533569335938, -9.425236701965332 ], [ 150.763885498046989, -9.399722099304199 ], [ 150.7979736328125, -9.414087295532227 ], [ 150.84222412109375, -9.487500190734863 ], [ 150.89222717285179, -9.5138902664184 ], [ 150.885559082031477, -9.566944122314453 ], [ 150.864715576171875, -9.58083343505848 ], [ 150.902770996093977, -9.594721794128361 ], [ 150.905624389648665, -9.63243293762207 ], [ 150.92274475097679, -9.628890991210881 ], [ 150.93719482421875, -9.650186538696232 ], [ 150.930145263671875, -9.678268432617131 ], [ 150.910400390625227, -9.694404602050724 ], [ 150.881134033203125, -9.678653717040959 ], [ 150.844665527343864, -9.721624374389592 ], [ 150.855468750000227, -9.666799545288029 ], [ 150.843795776367301, -9.656744003295898 ], [ 150.805221557617188, -9.661463737487736 ], [ 150.803436279296875, -9.677727699279728 ], [ 150.780548095703125, -9.683333396911621 ], [ 150.748947143554688, -9.660610198974609 ], [ 150.692428588867188, -9.671945571899357 ], [ 150.635833740234375, -9.659444808959904 ], [ 150.555145263671875, -9.623397827148438 ], [ 150.460800170898551, -9.642222404479924 ], [ 150.436813354492642, -9.631380081176758 ], [ 150.438690185547102, -9.595788955688477 ], [ 150.523056030273438, -9.552779197692871 ], [ 150.511383056640852, -9.505833625793457 ], [ 150.45887756347679, -9.479319572448674 ], [ 150.426132202148892, -9.417906761169377 ], [ 150.425628662109716, -9.370401382446232 ], [ 150.487442016601562, -9.327259063720703 ] ] ], [ [ [ 152.006988525390739, -9.320899963378906 ], [ 152.004440307617415, -9.319443702697697 ], [ 152.005996704101676, -9.31793022155756 ], [ 152.006973266601562, -9.319106101989689 ], [ 152.006988525390739, -9.320899963378906 ] ] ], [ [ [ 152.52949523925804, -9.314725875854492 ], [ 152.527221679687614, -9.315277099609375 ], [ 152.526382446289404, -9.313611030578556 ], [ 152.527618408203352, -9.313332557678166 ], [ 152.52949523925804, -9.314725875854492 ] ] ], [ [ [ 150.875198364257812, -9.319960594177189 ], [ 150.871093750000227, -9.317021369934082 ], [ 150.877487182617188, -9.312815666198674 ], [ 150.881500244140625, -9.317961692810002 ], [ 150.875198364257812, -9.319960594177189 ] ] ], [ [ [ 153.644027709961051, -9.309033393859806 ], [ 153.641937255859489, -9.306388854980469 ], [ 153.646942138671989, -9.303332328796387 ], [ 153.647506713867301, -9.305555343627816 ], [ 153.644027709961051, -9.309033393859806 ] ] ], [ [ [ 153.670379638671989, -9.305349349975529 ], [ 153.669174194336165, -9.305555343627816 ], [ 153.667770385742188, -9.303332328796387 ], [ 153.670700073242415, -9.303417205810547 ], [ 153.670379638671989, -9.305349349975529 ] ] ], [ [ [ 153.673339843750227, -9.305555343627816 ], [ 153.671951293945312, -9.305555343627816 ], [ 153.671539306640739, -9.302992820739689 ], [ 153.674102783203352, -9.303068161010685 ], [ 153.673339843750227, -9.305555343627816 ] ] ], [ [ [ 153.677505493164062, -9.305555343627816 ], [ 153.675460815429915, -9.302620887756348 ], [ 153.678390502929801, -9.301734924316406 ], [ 153.678329467773665, -9.304722785949707 ], [ 153.677505493164062, -9.305555343627816 ] ] ], [ [ [ 153.665283203125, -9.301110267639103 ], [ 153.664718627929688, -9.303332328796387 ], [ 153.654449462890852, -9.303332328796387 ], [ 153.658340454101676, -9.301943778991642 ], [ 153.665283203125, -9.301110267639103 ] ] ], [ [ [ 152.833053588867301, -9.29416561126709 ], [ 152.835830688476676, -9.295833587646484 ], [ 152.831665039062727, -9.297842025756836 ], [ 152.83088684082054, -9.29552173614502 ], [ 152.833053588867301, -9.29416561126709 ] ] ], [ [ [ 151.968460083007926, -9.295385360717773 ], [ 151.975723266601676, -9.300224304199219 ], [ 151.976104736328239, -9.301943778991642 ], [ 151.964172363281364, -9.29555606842041 ], [ 151.961395263671989, -9.288889884948617 ], [ 151.968460083007926, -9.295385360717773 ] ] ], [ [ [ 150.707626342773665, -9.302153587341309 ], [ 150.712295532226676, -9.31107234954834 ], [ 150.721054077148551, -9.311106681823674 ], [ 150.712677001953239, -9.315170288085938 ], [ 150.692901611328125, -9.295931816101017 ], [ 150.705612182617301, -9.287625312805176 ], [ 150.707626342773665, -9.302153587341309 ] ] ], [ [ [ 153.684997558593977, -9.28083324432373 ], [ 153.698608398437614, -9.287220954894906 ], [ 153.690002441406364, -9.302223205566406 ], [ 153.684722900390625, -9.296666145324707 ], [ 153.684997558593977, -9.28083324432373 ] ] ], [ [ [ 150.789215087890625, -9.279390335082951 ], [ 150.801193237304688, -9.293206214904728 ], [ 150.78065490722679, -9.304338455200195 ], [ 150.779235839843864, -9.286307334899846 ], [ 150.789215087890625, -9.279390335082951 ] ] ], [ [ [ 150.896728515625114, -9.264641761779785 ], [ 150.89759826660179, -9.265441894531193 ], [ 150.898162841796989, -9.268277168273926 ], [ 150.895339965820767, -9.265482902526855 ], [ 150.896728515625114, -9.264641761779785 ] ] ], [ [ [ 151.897506713867301, -9.262221336364746 ], [ 151.927764892578352, -9.284625053405762 ], [ 151.95166015625, -9.282007217407227 ], [ 151.959854125976562, -9.292307853698674 ], [ 151.927505493164062, -9.287776947021484 ], [ 151.906387329101676, -9.27500057220459 ], [ 151.871948242187614, -9.285277366638184 ], [ 151.897506713867301, -9.262221336364746 ] ] ], [ [ [ 150.757247924805142, -9.26175594329834 ], [ 150.772750854492301, -9.287153244018555 ], [ 150.757644653320426, -9.302758216857853 ], [ 150.73397827148483, -9.276068687438965 ], [ 150.757247924805142, -9.26175594329834 ] ] ], [ [ [ 152.90834045410179, -9.258889198303166 ], [ 152.907226562500114, -9.264444351196232 ], [ 152.901382446289062, -9.263334274291992 ], [ 152.903884887695312, -9.25999927520752 ], [ 152.90834045410179, -9.258889198303166 ] ] ], [ [ [ 153.675827026367301, -9.263055801391602 ], [ 153.688613891601676, -9.274443626403809 ], [ 153.687500000000227, -9.276389122009221 ], [ 153.666946411132926, -9.261945724487248 ], [ 153.675827026367301, -9.263055801391602 ] ] ], [ [ [ 152.943603515625114, -9.254166603088379 ], [ 152.941940307617301, -9.254722595214844 ], [ 152.939727783203125, -9.251667022705078 ], [ 152.94497680664108, -9.251173973083496 ], [ 152.943603515625114, -9.254166603088379 ] ] ], [ [ [ 152.557220458984489, -9.250832557678223 ], [ 152.55543518066429, -9.252223014831543 ], [ 152.553604125976676, -9.251529693603402 ], [ 152.556289672851562, -9.249760627746582 ], [ 152.557220458984489, -9.250832557678223 ] ] ], [ [ [ 150.755096435547102, -9.254584312438965 ], [ 150.753082275390625, -9.251585006713867 ], [ 150.754669189453125, -9.249073028564453 ], [ 150.75579833984375, -9.252767562866211 ], [ 150.755096435547102, -9.254584312438965 ] ] ], [ [ [ 150.783859252929688, -9.243362426757812 ], [ 150.782333374023438, -9.240362167358398 ], [ 150.78631591796875, -9.239147186279297 ], [ 150.786819458007926, -9.240578651428166 ], [ 150.783859252929688, -9.243362426757812 ] ] ], [ [ [ 150.754638671875114, -9.240829467773381 ], [ 150.753387451171989, -9.240241050720158 ], [ 150.753280639648551, -9.238263130187931 ], [ 150.755096435547102, -9.239059448242188 ], [ 150.754638671875114, -9.240829467773381 ] ] ], [ [ [ 150.789337158203239, -9.237543106079045 ], [ 150.788360595703125, -9.236264228820744 ], [ 150.79023742675804, -9.234034538268986 ], [ 150.791564941406477, -9.236318588256722 ], [ 150.789337158203239, -9.237543106079045 ] ] ], [ [ [ 152.931671142578239, -9.235834121704045 ], [ 152.930282592773665, -9.234721183776742 ], [ 152.930831909179915, -9.233888626098633 ], [ 152.932785034179801, -9.234721183776742 ], [ 152.931671142578239, -9.235834121704045 ] ] ], [ [ [ 152.765838623046989, -9.240555763244572 ], [ 152.75750732421875, -9.245555877685547 ], [ 152.754440307617301, -9.23972225189209 ], [ 152.764114379882926, -9.23254489898676 ], [ 152.765838623046989, -9.240555763244572 ] ] ], [ [ [ 150.907226562500114, -9.230513572692814 ], [ 150.921981811523665, -9.252113342285156 ], [ 150.89617919921875, -9.26408576965332 ], [ 150.896987915039062, -9.235447883605957 ], [ 150.907226562500114, -9.230513572692814 ] ] ], [ [ [ 150.788528442383267, -9.232643127441349 ], [ 150.787139892578352, -9.232008934020996 ], [ 150.786621093750455, -9.230355262756291 ], [ 150.788513183593977, -9.230098724365234 ], [ 150.788528442383267, -9.232643127441349 ] ] ], [ [ [ 153.1129150390625, -9.218753814697266 ], [ 153.110275268554688, -9.228610992431584 ], [ 153.105560302734602, -9.230554580688477 ], [ 153.100280761718864, -9.22166633605957 ], [ 153.1129150390625, -9.218753814697266 ] ] ], [ [ [ 150.859725952148551, -9.204167366027832 ], [ 150.86518859863304, -9.209839820861816 ], [ 150.884735107421875, -9.211820602416992 ], [ 150.867568969726562, -9.225518226623421 ], [ 150.859725952148551, -9.204167366027832 ] ] ], [ [ [ 150.823638916015739, -9.215794563293457 ], [ 150.8162841796875, -9.214593887329102 ], [ 150.815460205078239, -9.2021484375 ], [ 150.819580078125114, -9.204874038696289 ], [ 150.823638916015739, -9.215794563293457 ] ] ], [ [ [ 152.438049316406364, -9.204998970031681 ], [ 152.435836791992188, -9.204998970031681 ], [ 152.435562133789176, -9.200277328491211 ], [ 152.43695068359375, -9.200833320617676 ], [ 152.438049316406364, -9.204998970031681 ] ] ], [ [ [ 150.23194885253929, -9.195832252502385 ], [ 150.336944580078125, -9.271112442016545 ], [ 150.362503051757812, -9.369998931884766 ], [ 150.386672973632812, -9.386944770812931 ], [ 150.333328247070312, -9.46277904510498 ], [ 150.365554809570312, -9.472223281860295 ], [ 150.340835571289176, -9.521110534667912 ], [ 150.30999755859375, -9.521666526794377 ], [ 150.299728393554801, -9.501944541931152 ], [ 150.246109008789062, -9.483612060546875 ], [ 150.243057250976562, -9.452500343322754 ], [ 150.19721984863304, -9.453056335449219 ], [ 150.158050537109375, -9.425833702087346 ], [ 150.125274658203125, -9.372500419616642 ], [ 150.104995727539176, -9.370555877685547 ], [ 150.095001220703352, -9.3102769851684 ], [ 150.124160766601676, -9.249444961547795 ], [ 150.195007324218864, -9.199444770812988 ], [ 150.23194885253929, -9.195832252502385 ] ] ], [ [ [ 150.204010009765625, -9.175276756286564 ], [ 150.205505371093864, -9.183328628540039 ], [ 150.194290161132812, -9.17780876159668 ], [ 150.19992065429733, -9.17370700836176 ], [ 150.204010009765625, -9.175276756286564 ] ] ], [ [ [ 152.42333984375, -9.159166336059457 ], [ 152.422225952148551, -9.158056259155273 ], [ 152.424438476562727, -9.156111717224064 ], [ 152.42500305175804, -9.157221794128418 ], [ 152.42333984375, -9.159166336059457 ] ] ], [ [ [ 152.681976318359375, -9.09945011138916 ], [ 152.682098388671989, -9.10206413269043 ], [ 152.680130004882812, -9.102825164794865 ], [ 152.679244995117301, -9.09945011138916 ], [ 152.681976318359375, -9.09945011138916 ] ] ], [ [ [ 152.423614501953125, -9.112221717834359 ], [ 152.422225952148551, -9.10805606842041 ], [ 152.424163818359375, -9.096667289733887 ], [ 152.427780151367188, -9.092223167419377 ], [ 152.423614501953125, -9.112221717834359 ] ] ], [ [ [ 151.979873657226676, -8.951555252075195 ], [ 152.000411987304801, -8.969754219055176 ], [ 151.99128723144554, -8.989350318908691 ], [ 151.956939697265852, -8.966776847839355 ], [ 151.979873657226676, -8.951555252075195 ] ] ], [ [ [ 152.456619262695312, -8.946816444396973 ], [ 152.512771606445767, -8.993612289428711 ], [ 152.615829467773551, -8.983611106872502 ], [ 152.736938476562614, -9.025278091430664 ], [ 152.793029785156591, -9.003748893737793 ], [ 152.834442138671875, -9.032831192016602 ], [ 152.835556030273551, -9.071879386901855 ], [ 152.889739990234375, -9.085618019104004 ], [ 152.918334960937614, -9.067776679992619 ], [ 152.949447631835938, -9.083332061767578 ], [ 152.94805908203125, -9.125832557678166 ], [ 152.977783203125455, -9.120833396911564 ], [ 153.023605346679801, -9.16139030456543 ], [ 152.991668701171989, -9.16250038146967 ], [ 152.995559692382926, -9.183611869812012 ], [ 152.979721069335938, -9.199723243713379 ], [ 152.947494506836051, -9.174445152282658 ], [ 152.908050537109375, -9.195279121398869 ], [ 152.966659545898665, -9.225001335144043 ], [ 152.965560913086165, -9.256111145019531 ], [ 152.936386108398665, -9.225278854370117 ], [ 152.831665039062727, -9.26249885559082 ], [ 152.80917358398483, -9.255832672119141 ], [ 152.794448852539176, -9.228055000305176 ], [ 152.783340454101562, -9.236944198608398 ], [ 152.783889770507812, -9.211668014526367 ], [ 152.757781982421875, -9.223610877990609 ], [ 152.743896484375114, -9.179443359375 ], [ 152.734161376953352, -9.173054695129338 ], [ 152.727783203125114, -9.211387634277344 ], [ 152.751937866211165, -9.223610877990609 ], [ 152.735412597656364, -9.260133743286076 ], [ 152.718338012695426, -9.226388931274357 ], [ 152.655548095703125, -9.204998970031681 ], [ 152.642379760742188, -9.182324409484863 ], [ 152.662841796875114, -9.164228439331055 ], [ 152.651947021484602, -9.18194580078125 ], [ 152.670272827148551, -9.198332786560059 ], [ 152.710006713867301, -9.175832748413029 ], [ 152.693893432617188, -9.146666526794377 ], [ 152.664993286132926, -9.138888359069824 ], [ 152.700271606445426, -9.088056564331055 ], [ 152.683059692382926, -9.08861064910883 ], [ 152.65083312988304, -9.115276336669922 ], [ 152.529159545898665, -9.036110877990666 ], [ 152.471115112304688, -9.044722557067814 ], [ 152.509719848633267, -8.994999885559025 ], [ 152.447021484375114, -8.963109970092773 ], [ 152.437774658203239, -8.980001449584961 ], [ 152.422775268554688, -8.97389030456543 ], [ 152.429443359375, -9.010832786560059 ], [ 152.424728393554688, -9.084721565246525 ], [ 152.391937255859375, -8.988888740539494 ], [ 152.456619262695312, -8.946816444396973 ] ] ], [ [ [ 151.914718627929688, -8.901389122009221 ], [ 151.925277709961165, -8.916387557983398 ], [ 151.912780761718864, -8.928056716918888 ], [ 151.901947021484375, -8.912776947021428 ], [ 151.914718627929688, -8.901389122009221 ] ] ], [ [ [ 151.133056640625114, -8.799166679382267 ], [ 151.185272216796989, -8.84194374084467 ], [ 151.197494506835938, -8.870278358459473 ], [ 151.1119384765625, -8.875276565551758 ], [ 151.17333984375, -8.852223396301213 ], [ 151.133056640625114, -8.799166679382267 ] ] ], [ [ [ 151.920562744140625, -8.795832633972111 ], [ 151.92416381835983, -8.802498817443848 ], [ 151.912506103515852, -8.807499885559025 ], [ 151.912216186523779, -8.798054695129338 ], [ 151.920562744140625, -8.795832633972111 ] ] ], [ [ [ 151.031661987304915, -8.794445037841797 ], [ 151.02999877929733, -8.79305362701416 ], [ 151.030838012695312, -8.791666030883789 ], [ 151.03277587890625, -8.79333305358881 ], [ 151.031661987304915, -8.794445037841797 ] ] ], [ [ [ 150.96221923828125, -8.740556716918945 ], [ 150.963333129882812, -8.741945266723633 ], [ 150.959716796875, -8.743611335754338 ], [ 150.95916748046875, -8.742222785949707 ], [ 150.96221923828125, -8.740556716918945 ] ] ], [ [ [ 151.004165649414062, -8.75361156463623 ], [ 151.002777099609489, -8.737778663635197 ], [ 151.0302734375, -8.713054656982365 ], [ 151.019439697265625, -8.726112365722656 ], [ 151.004165649414062, -8.75361156463623 ] ] ], [ [ [ 151.676666259765625, -8.692222595214844 ], [ 151.684432983398438, -8.701464653015137 ], [ 151.671386718750227, -8.71250057220459 ], [ 151.6663818359375, -8.705555915832463 ], [ 151.676666259765625, -8.692222595214844 ] ] ], [ [ [ 150.881668090820426, -8.636944770812988 ], [ 150.887496948242415, -8.639445304870605 ], [ 150.868331909179688, -8.637777328491154 ], [ 150.87445068359375, -8.636944770812988 ], [ 150.881668090820426, -8.636944770812988 ] ] ], [ [ [ 151.305831909179688, -8.632779121398869 ], [ 151.303894042969205, -8.63055419921875 ], [ 151.304992675781364, -8.629165649414062 ], [ 151.306915283203352, -8.630839347839299 ], [ 151.305831909179688, -8.632779121398869 ] ] ], [ [ [ 150.78694152832054, -8.61944580078125 ], [ 150.783615112304801, -8.618056297302189 ], [ 150.789443969726676, -8.615554809570312 ], [ 150.790283203125114, -8.616943359374943 ], [ 150.78694152832054, -8.61944580078125 ] ] ], [ [ [ 150.741943359375114, -8.606389045715275 ], [ 150.740554809570312, -8.605278968811035 ], [ 150.742431640625114, -8.603889465331918 ], [ 150.74311828613304, -8.604997634887695 ], [ 150.741943359375114, -8.606389045715275 ] ] ], [ [ [ 151.356109619140739, -8.593055725097656 ], [ 151.352783203125114, -8.635001182556152 ], [ 151.322494506835938, -8.649168014526367 ], [ 151.309417724609602, -8.620500564575138 ], [ 151.356109619140739, -8.593055725097656 ] ] ], [ [ [ 150.848617553711051, -8.584166526794434 ], [ 150.87110900878929, -8.598334312438851 ], [ 150.87110900878929, -8.609723091125431 ], [ 150.848892211914062, -8.590556144714355 ], [ 150.845840454101562, -8.580000877380314 ], [ 150.848617553711051, -8.584166526794434 ] ] ], [ [ [ 150.844161987304915, -8.574166297912598 ], [ 150.845840454101562, -8.575556755065918 ], [ 150.844451904296989, -8.576945304870549 ], [ 150.843048095703352, -8.575556755065918 ], [ 150.844161987304915, -8.574166297912598 ] ] ], [ [ [ 151.091949462890739, -8.566944122314453 ], [ 151.1058349609375, -8.580000877380314 ], [ 151.100006103515739, -8.606389045715275 ], [ 151.093338012695426, -8.602500915527344 ], [ 151.091949462890739, -8.566944122314453 ] ] ], [ [ [ 150.832778930664517, -8.560555458068848 ], [ 150.840270996093864, -8.569443702697754 ], [ 150.83917236328125, -8.57166576385498 ], [ 150.832504272460938, -8.568887710571289 ], [ 150.832778930664517, -8.560555458068848 ] ] ], [ [ [ 150.28277587890625, -8.565278053283635 ], [ 150.278610229492188, -8.56389045715332 ], [ 150.281951904296989, -8.558889389038029 ], [ 150.2852783203125, -8.56389045715332 ], [ 150.28277587890625, -8.565278053283635 ] ] ], [ [ [ 150.326385498046989, -8.553333282470646 ], [ 150.322784423828125, -8.553333282470646 ], [ 150.321105957031591, -8.550554275512695 ], [ 150.324447631836165, -8.549165725707951 ], [ 150.326385498046989, -8.553333282470646 ] ] ], [ [ [ 150.823883056640966, -8.536667823791447 ], [ 150.817779541015966, -8.538056373596191 ], [ 150.816665649414062, -8.535834312438908 ], [ 150.823883056640966, -8.53055477142334 ], [ 150.823883056640966, -8.536667823791447 ] ] ], [ [ [ 150.296112060546989, -8.519444465637207 ], [ 150.302215576171989, -8.521388053894043 ], [ 150.300827026367301, -8.527776718139648 ], [ 150.294998168945312, -8.52722263336176 ], [ 150.296112060546989, -8.519444465637207 ] ] ], [ [ [ 150.957229614257812, -8.47722339630127 ], [ 150.975006103515852, -8.497501373291016 ], [ 150.97138977050804, -8.557777404785156 ], [ 150.92166137695358, -8.579167366027832 ], [ 150.935363769531477, -8.540044784545898 ], [ 150.924728393554801, -8.509167671203613 ], [ 150.957229614257812, -8.47722339630127 ] ] ], [ [ [ 150.882949829101676, -8.45768928527832 ], [ 150.886672973632812, -8.465554237365723 ], [ 150.884368896484375, -8.47381591796875 ], [ 150.876937866210938, -8.45694446563715 ], [ 150.882949829101676, -8.45768928527832 ] ] ], [ [ [ 150.440277099609375, -8.421388626098576 ], [ 150.438888549804915, -8.41833305358881 ], [ 150.443603515625, -8.41250038146967 ], [ 150.443054199218977, -8.41944503784174 ], [ 150.440277099609375, -8.421388626098576 ] ] ], [ [ [ 150.451660156250227, -8.41250038146967 ], [ 150.45582580566429, -8.416945457458382 ], [ 150.453887939453125, -8.419722557067871 ], [ 150.450836181640625, -8.416389465331974 ], [ 150.451660156250227, -8.41250038146967 ] ] ], [ [ [ 150.889724731445312, -8.409999847412053 ], [ 150.893325805664062, -8.416389465331974 ], [ 150.893325805664062, -8.42722129821766 ], [ 150.886383056640739, -8.403889656066895 ], [ 150.889724731445312, -8.409999847412053 ] ] ], [ [ [ 151.114334106445312, -8.400589942932015 ], [ 151.130279541015739, -8.41472339630127 ], [ 151.127777099609375, -8.487500190734863 ], [ 151.107772827148551, -8.50555515289301 ], [ 151.151672363281477, -8.566944122314453 ], [ 151.146942138671875, -8.600831985473633 ], [ 151.120559692382926, -8.632223129272461 ], [ 151.102493286132926, -8.748332977294922 ], [ 151.126663208007926, -8.799445152282658 ], [ 151.041946411132812, -8.724720954894963 ], [ 151.096389770507926, -8.667498588562012 ], [ 151.133331298828239, -8.589999198913574 ], [ 151.108337402343977, -8.577501296997013 ], [ 151.095550537109602, -8.547499656677189 ], [ 151.018051147461279, -8.550278663635254 ], [ 150.994171142578125, -8.531389236450195 ], [ 151.034164428711165, -8.43638801574707 ], [ 151.114334106445312, -8.400589942932015 ] ] ], [ [ [ 149.926467895507926, -8.390846252441406 ], [ 149.927932739258267, -8.391054153442326 ], [ 149.9278564453125, -8.39216136932373 ], [ 149.925628662109602, -8.39112377166748 ], [ 149.926467895507926, -8.390846252441406 ] ] ], [ [ [ 150.649078369140852, -8.388735771179199 ], [ 150.649932861328466, -8.393027305603027 ], [ 150.644210815430029, -8.394827842712402 ], [ 150.644561767578239, -8.390811920165959 ], [ 150.649078369140852, -8.388735771179199 ] ] ], [ [ [ 150.195556640625, -8.386387825012207 ], [ 150.197784423828239, -8.388609886169377 ], [ 150.196945190429688, -8.390001296997013 ], [ 150.19416809082054, -8.388056755065918 ], [ 150.195556640625, -8.386387825012207 ] ] ], [ [ [ 150.663650512695426, -8.370526313781681 ], [ 150.665161132812614, -8.373230934143066 ], [ 150.66181945800804, -8.373714447021484 ], [ 150.66314697265625, -8.370737075805607 ], [ 150.663650512695426, -8.370526313781681 ] ] ], [ [ [ 150.175003051758154, -8.364444732666016 ], [ 150.177291870117529, -8.366040229797306 ], [ 150.177505493164062, -8.367499351501465 ], [ 150.174163818359602, -8.365833282470646 ], [ 150.175003051758154, -8.364444732666016 ] ] ], [ [ [ 150.596389770507812, -8.350000381469727 ], [ 150.599441528320312, -8.352778434753418 ], [ 150.599166870117301, -8.353055953979492 ], [ 150.593887329101562, -8.350277900695801 ], [ 150.596389770507812, -8.350000381469727 ] ] ], [ [ [ 150.117660522461165, -8.345342636108398 ], [ 150.115570068359489, -8.344928741455078 ], [ 150.114868164062614, -8.343403816223145 ], [ 150.1177978515625, -8.344790458679199 ], [ 150.117660522461165, -8.345342636108398 ] ] ], [ [ [ 150.426666259765739, -8.341667175292969 ], [ 150.425003051757926, -8.341667175292969 ], [ 150.4244384765625, -8.340555191040039 ], [ 150.426666259765739, -8.340276718139648 ], [ 150.426666259765739, -8.341667175292969 ] ] ], [ [ [ 150.84527587890625, -8.325278282165471 ], [ 150.863327026367188, -8.341944694519043 ], [ 150.881668090820426, -8.385554313659611 ], [ 150.882217407226676, -8.396389007568359 ], [ 150.84527587890625, -8.325278282165471 ] ] ], [ [ [ 150.71888732910179, -8.32833194732666 ], [ 150.717773437500114, -8.325278282165471 ], [ 150.719451904297102, -8.323612213134766 ], [ 150.720550537109375, -8.326665878295898 ], [ 150.71888732910179, -8.32833194732666 ] ] ], [ [ [ 150.573883056640625, -8.323056221008187 ], [ 150.577774047851676, -8.325278282165471 ], [ 150.589447021484489, -8.337498664855957 ], [ 150.58416748046875, -8.337498664855957 ], [ 150.573883056640625, -8.323056221008187 ] ] ], [ [ [ 150.822219848632812, -8.316389083862248 ], [ 150.828338623047102, -8.319998741149902 ], [ 150.830215454101562, -8.323105812072754 ], [ 150.816116333007812, -8.318611145019474 ], [ 150.822219848632812, -8.316389083862248 ] ] ], [ [ [ 150.111114501953125, -8.306387901306096 ], [ 150.108886718750227, -8.306387901306096 ], [ 150.109725952148438, -8.301112174987793 ], [ 150.111938476562727, -8.303609848022404 ], [ 150.111114501953125, -8.306387901306096 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-MPL", "NAME_1": "Morobe" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 147.724838256835938, -7.922231197357121 ], [ 147.724777221679688, -7.923367977142277 ], [ 147.722915649414404, -7.923062801361027 ], [ 147.723159790039062, -7.921690940856877 ], [ 147.724838256835938, -7.922231197357121 ] ] ], [ [ [ 147.71148681640625, -7.879811763763428 ], [ 147.712600708007926, -7.883593082427979 ], [ 147.709793090820312, -7.885832786560002 ], [ 147.709259033203239, -7.879504203796387 ], [ 147.71148681640625, -7.879811763763428 ] ] ], [ [ [ 147.627410888671875, -7.746890068054142 ], [ 147.626281738281477, -7.746890068054142 ], [ 147.625839233398438, -7.745554924011174 ], [ 147.627838134765852, -7.746475219726562 ], [ 147.627410888671875, -7.746890068054142 ] ] ], [ [ [ 147.610015869140625, -7.733489036560059 ], [ 147.6129150390625, -7.738214015960693 ], [ 147.604232788085938, -7.7376708984375 ], [ 147.60614013671875, -7.731783866882324 ], [ 147.610015869140625, -7.733489036560059 ] ] ], [ [ [ 147.59461975097679, -7.726353168487549 ], [ 147.596618652343864, -7.726418972015324 ], [ 147.596786499023551, -7.727055072784424 ], [ 147.593109130859489, -7.72684288024891 ], [ 147.59461975097679, -7.726353168487549 ] ] ], [ [ [ 147.623657226562727, -7.722755908966064 ], [ 147.618606567382812, -7.724349975585938 ], [ 147.615890502929801, -7.722073078155518 ], [ 147.622116088867415, -7.719192028045654 ], [ 147.623657226562727, -7.722755908966064 ] ] ], [ [ [ 147.610977172851562, -7.720046997070312 ], [ 147.608993530273551, -7.719350814819336 ], [ 147.608047485351562, -7.717562198638916 ], [ 147.611053466797102, -7.717576026916504 ], [ 147.610977172851562, -7.720046997070312 ] ] ], [ [ [ 147.633026123046989, -7.717596054077148 ], [ 147.626800537109375, -7.718902111053467 ], [ 147.63970947265625, -7.706980228424072 ], [ 147.641616821289062, -7.709462165832406 ], [ 147.633026123046989, -7.717596054077148 ] ] ], [ [ [ 147.540451049804915, -7.696845054626465 ], [ 147.536254882812727, -7.697196006774846 ], [ 147.534896850585938, -7.696412086486816 ], [ 147.537948608398438, -7.69476413726801 ], [ 147.540451049804915, -7.696845054626465 ] ] ], [ [ [ 147.532073974609489, -7.693367004394531 ], [ 147.532867431640852, -7.701550960540715 ], [ 147.523788452148779, -7.695704936981201 ], [ 147.527755737304688, -7.693626880645752 ], [ 147.532073974609489, -7.693367004394531 ] ] ], [ [ [ 147.537948608398438, -7.642877101898137 ], [ 147.5291748046875, -7.643000125884953 ], [ 147.529495239257926, -7.637582778930664 ], [ 147.531738281250114, -7.636985778808594 ], [ 147.537948608398438, -7.642877101898137 ] ] ], [ [ [ 147.496368408203125, -7.604026794433537 ], [ 147.497406005859489, -7.604787826538086 ], [ 147.494171142578239, -7.603333950042725 ], [ 147.495285034179915, -7.603055953979379 ], [ 147.496368408203125, -7.604026794433537 ] ] ], [ [ [ 147.433883666992642, -7.565279960632267 ], [ 147.43305969238304, -7.565555095672607 ], [ 147.432495117187727, -7.565141201019287 ], [ 147.433883666992642, -7.563891887664738 ], [ 147.433883666992642, -7.565279960632267 ] ] ], [ [ [ 147.434249877929915, -7.562437057495117 ], [ 147.433746337890739, -7.562644958496037 ], [ 147.434310913086051, -7.560842037200928 ], [ 147.434722900390625, -7.561256885528564 ], [ 147.434249877929915, -7.562437057495117 ] ] ], [ [ [ 147.406082153320426, -7.55128288269043 ], [ 147.405136108398551, -7.549620151519775 ], [ 147.407058715820654, -7.548151969909668 ], [ 147.407760620117301, -7.549190998077393 ], [ 147.406082153320426, -7.55128288269043 ] ] ], [ [ [ 147.39688110351608, -7.511722087860051 ], [ 147.395904541015852, -7.51082181930542 ], [ 147.396957397460938, -7.509244918823242 ], [ 147.398559570312614, -7.510612010955811 ], [ 147.39688110351608, -7.511722087860051 ] ] ], [ [ [ 147.425704956054688, -7.508313179016056 ], [ 147.423248291015739, -7.508307933807373 ], [ 147.421768188476562, -7.507402896881047 ], [ 147.42567443847679, -7.506155967712346 ], [ 147.425704956054688, -7.508313179016056 ] ] ], [ [ [ 147.328262329101676, -7.495965957641602 ], [ 147.328002929687727, -7.502054214477482 ], [ 147.326568603515966, -7.504290103912354 ], [ 147.324645996093864, -7.4945969581604 ], [ 147.328262329101676, -7.495965957641602 ] ] ], [ [ [ 147.402099609375341, -7.493076801300049 ], [ 147.402938842773551, -7.493907928466683 ], [ 147.402801513671989, -7.495154857635498 ], [ 147.401062011718977, -7.49328422546381 ], [ 147.402099609375341, -7.493076801300049 ] ] ], [ [ [ 147.36573791503929, -7.467359066009521 ], [ 147.369064331054688, -7.472664833068734 ], [ 147.361007690429915, -7.472095012664795 ], [ 147.35963439941429, -7.469051837921143 ], [ 147.36573791503929, -7.467359066009521 ] ] ], [ [ [ 147.237350463867188, -7.463509082794189 ], [ 147.236282348633267, -7.46383810043335 ], [ 147.236175537109375, -7.463030815124512 ], [ 147.237365722656477, -7.462337970733586 ], [ 147.237350463867188, -7.463509082794189 ] ] ], [ [ [ 147.325592041015739, -7.443674087524357 ], [ 147.324203491211165, -7.443437099456787 ], [ 147.321426391601562, -7.438835144042969 ], [ 147.326614379882812, -7.441707134246769 ], [ 147.325592041015739, -7.443674087524357 ] ] ], [ [ [ 147.306442260742415, -7.438180923461914 ], [ 147.305145263671989, -7.437785148620549 ], [ 147.305282592773551, -7.436742782592773 ], [ 147.306396484375, -7.437089920043888 ], [ 147.306442260742415, -7.438180923461914 ] ] ], [ [ [ 147.302886962890739, -7.43434476852417 ], [ 147.300628662109716, -7.433004856109562 ], [ 147.301284790039176, -7.431357860565186 ], [ 147.305145263671989, -7.432765960693303 ], [ 147.302886962890739, -7.43434476852417 ] ] ], [ [ [ 147.348342895507812, -7.432319164276123 ], [ 147.350738525390739, -7.440162181854248 ], [ 147.340011596679915, -7.439334869384709 ], [ 147.340789794922102, -7.43341588973999 ], [ 147.348342895507812, -7.432319164276123 ] ] ], [ [ [ 147.270996093750455, -7.431931972503605 ], [ 147.267547607422102, -7.429931163787842 ], [ 147.270492553711279, -7.426266193389893 ], [ 147.272430419921875, -7.43062782287592 ], [ 147.270996093750455, -7.431931972503605 ] ] ], [ [ [ 147.253982543945426, -7.396389007568359 ], [ 147.247482299804915, -7.405550956726017 ], [ 147.275329589843977, -7.399630069732609 ], [ 147.279052734375114, -7.414384841918888 ], [ 147.256240844726562, -7.43360519409174 ], [ 147.23225402832054, -7.411275863647461 ], [ 147.253982543945426, -7.396389007568359 ] ] ], [ [ [ 147.249099731445426, -7.384912967681885 ], [ 147.256011962890625, -7.385453224182129 ], [ 147.256607055664062, -7.386868953704834 ], [ 147.24690246582054, -7.391276836395207 ], [ 147.249099731445426, -7.384912967681885 ] ] ], [ [ [ 147.223937988281364, -7.377755165100041 ], [ 147.220626831054915, -7.374780178070068 ], [ 147.22161865234375, -7.372243881225529 ], [ 147.225997924804801, -7.374950885772705 ], [ 147.223937988281364, -7.377755165100041 ] ] ], [ [ [ 147.224365234375, -7.34819221496582 ], [ 147.217346191406477, -7.35298490524292 ], [ 147.211105346680142, -7.353486061096191 ], [ 147.2169189453125, -7.348121166229248 ], [ 147.224365234375, -7.34819221496582 ] ] ], [ [ [ 147.205566406250227, -7.343903064727726 ], [ 147.206832885742188, -7.339312076568604 ], [ 147.210922241211051, -7.340589046478215 ], [ 147.210739135742301, -7.342764854431152 ], [ 147.205566406250227, -7.343903064727726 ] ] ], [ [ [ 147.160202026367188, -7.244668960571289 ], [ 147.154846191406364, -7.245639801025334 ], [ 147.153472900390852, -7.244720935821476 ], [ 147.156112670898665, -7.240979194641113 ], [ 147.160202026367188, -7.244668960571289 ] ] ], [ [ [ 147.910507202148665, -6.761181831359863 ], [ 147.911941528320312, -6.764791965484619 ], [ 147.910552978515625, -6.766111850738469 ], [ 147.906784057617529, -6.763659954070988 ], [ 147.910507202148665, -6.761181831359863 ] ] ], [ [ [ 147.903060913086165, -6.756872177124023 ], [ 147.904281616211051, -6.762835025787354 ], [ 147.89582824707054, -6.761202812194824 ], [ 147.899841308593977, -6.757160186767521 ], [ 147.903060913086165, -6.756872177124023 ] ] ], [ [ [ 147.918502807617301, -6.760283946990967 ], [ 147.915924072265739, -6.758854866027832 ], [ 147.916915893554688, -6.756567001342717 ], [ 147.918365478515739, -6.757481098174992 ], [ 147.918502807617301, -6.760283946990967 ] ] ], [ [ [ 147.794219970703239, -6.698039054870549 ], [ 147.793182373046989, -6.697761058807316 ], [ 147.793258666992188, -6.697068214416504 ], [ 147.79450988769554, -6.697206974029541 ], [ 147.794219970703239, -6.698039054870549 ] ] ], [ [ [ 147.860900878906364, -6.653679847717285 ], [ 147.86317443847679, -6.655407905578613 ], [ 147.86317443847679, -6.656239032745361 ], [ 147.858810424804915, -6.655901908874512 ], [ 147.860900878906364, -6.653679847717285 ] ] ], [ [ [ 147.859161376953352, -6.647221088409367 ], [ 147.858642578125227, -6.646913051605225 ], [ 147.859725952148438, -6.645555019378548 ], [ 147.860076904296875, -6.646317958831673 ], [ 147.859161376953352, -6.647221088409367 ] ] ], [ [ [ 147.863250732421875, -6.645360946655217 ], [ 147.8638916015625, -6.64770603179926 ], [ 147.862777709960938, -6.64874792098999 ], [ 147.861953735351676, -6.645571231841984 ], [ 147.863250732421875, -6.645360946655217 ] ] ], [ [ [ 147.866622924804801, -6.631700038909855 ], [ 147.867782592773665, -6.634160995483398 ], [ 147.862854003906364, -6.642653942108154 ], [ 147.863113403320312, -6.639460086822453 ], [ 147.866622924804801, -6.631700038909855 ] ] ], [ [ [ 147.863845825195426, -6.628026008605957 ], [ 147.862045288086051, -6.627779960632324 ], [ 147.861663818359489, -6.619722843170109 ], [ 147.86273193359375, -6.625662803649902 ], [ 147.863845825195426, -6.628026008605957 ] ] ], [ [ [ 147.60592651367233, -6.09333610534668 ], [ 147.603637695312955, -6.091877937316895 ], [ 147.603805541992415, -6.090384960174561 ], [ 147.605865478515852, -6.09201717376709 ], [ 147.60592651367233, -6.09333610534668 ] ] ], [ [ [ 147.59846496582054, -6.08316707611084 ], [ 147.594985961914062, -6.080252170562744 ], [ 147.595062255859489, -6.078378200530949 ], [ 147.596038818359375, -6.079101085662785 ], [ 147.59846496582054, -6.08316707611084 ] ] ], [ [ [ 148.117767333984375, -5.973957061767578 ], [ 148.116455078125, -5.974166870117188 ], [ 148.116394042968864, -5.97333288192749 ], [ 148.117492675781364, -5.972846984863281 ], [ 148.117767333984375, -5.973957061767578 ] ] ], [ [ [ 148.184097290039176, -5.97333288192749 ], [ 148.182785034179688, -5.97333288192749 ], [ 148.182296752929915, -5.972498893737793 ], [ 148.183197021484375, -5.971806049346924 ], [ 148.184097290039176, -5.97333288192749 ] ] ], [ [ [ 148.120559692382812, -5.960694789886418 ], [ 148.119232177734489, -5.960416793823185 ], [ 148.119445800781364, -5.959166049957275 ], [ 148.120071411132812, -5.959236145019474 ], [ 148.120559692382812, -5.960694789886418 ] ] ], [ [ [ 148.039093017578239, -5.946874141693058 ], [ 148.032424926757926, -5.950276851654053 ], [ 148.026855468750227, -5.963877201080265 ], [ 148.022750854492529, -5.956669807434025 ], [ 148.029861450195312, -5.948265075683537 ], [ 148.039093017578239, -5.946874141693058 ] ] ], [ [ [ 148.129791259765625, -5.915903091430607 ], [ 148.128540039062955, -5.915278911590462 ], [ 148.129165649414176, -5.91395902633667 ], [ 148.130493164062614, -5.914722919464054 ], [ 148.129791259765625, -5.915903091430607 ] ] ], [ [ [ 147.333053588867529, -5.915555000305176 ], [ 147.331939697265625, -5.911387920379639 ], [ 147.333618164062614, -5.910555839538574 ], [ 147.334716796875114, -5.912221908569336 ], [ 147.333053588867529, -5.915555000305176 ] ] ], [ [ [ 148.090759277343977, -5.911873817443791 ], [ 148.089447021484489, -5.911387920379639 ], [ 148.089233398437727, -5.910346984863281 ], [ 148.090347290039176, -5.910417079925537 ], [ 148.090759277343977, -5.911873817443791 ] ] ], [ [ [ 148.038330078125114, -5.908611774444523 ], [ 148.03778076171875, -5.909790992736816 ], [ 148.033813476562841, -5.90826416015625 ], [ 148.033950805664176, -5.907567977905273 ], [ 148.038330078125114, -5.908611774444523 ] ] ], [ [ [ 148.01333618164108, -5.904097080230599 ], [ 148.013885498047102, -5.901668071746826 ], [ 148.017700195312727, -5.901875019073486 ], [ 148.01673889160179, -5.903021812438965 ], [ 148.01333618164108, -5.904097080230599 ] ] ], [ [ [ 148.051116943359489, -5.895833015441838 ], [ 148.05104064941429, -5.896249771118107 ], [ 148.049377441406477, -5.895902156829834 ], [ 148.050765991211051, -5.895348072051945 ], [ 148.051116943359489, -5.895833015441838 ] ] ], [ [ [ 147.945297241211051, -5.895281791687012 ], [ 147.945144653320312, -5.899951934814453 ], [ 147.931976318359375, -5.898234844207764 ], [ 147.942352294922102, -5.890498161315918 ], [ 147.945297241211051, -5.895281791687012 ] ] ], [ [ [ 147.927322387695426, -5.846471786498967 ], [ 147.926147460937727, -5.845513820648137 ], [ 147.926773071289062, -5.844089984893799 ], [ 147.92823791503929, -5.845056056976318 ], [ 147.927322387695426, -5.846471786498967 ] ] ], [ [ [ 147.931671142578352, -5.840555191039982 ], [ 147.930557250977017, -5.839723110198975 ], [ 147.930557250977017, -5.838333129882812 ], [ 147.931945800781364, -5.838889122009277 ], [ 147.931671142578352, -5.840555191039982 ] ] ], [ [ [ 147.990280151367188, -5.839723110198975 ], [ 147.988616943359375, -5.838611125946045 ], [ 147.989440917968977, -5.837223052978516 ], [ 147.991394042968977, -5.838333129882812 ], [ 147.990280151367188, -5.839723110198975 ] ] ], [ [ [ 148.03472900390625, -5.834929943084717 ], [ 148.033843994140625, -5.833332061767578 ], [ 148.03472900390625, -5.832847118377629 ], [ 148.035278320312614, -5.833611011505127 ], [ 148.03472900390625, -5.834929943084717 ] ] ], [ [ [ 146.774505615234602, -5.843875885009766 ], [ 146.798614501953466, -5.858057022094727 ], [ 146.833694458007926, -5.83567476272583 ], [ 146.865280151367415, -5.836111068725586 ], [ 146.90249633789108, -5.855978012084961 ], [ 146.931671142578352, -5.90388822555542 ], [ 146.999450683593864, -5.938610076904297 ], [ 147.051177978515625, -5.910324096679631 ], [ 147.090698242187727, -5.959664821624699 ], [ 147.140930175781364, -5.948050022125187 ], [ 147.208465576171875, -5.962103843688965 ], [ 147.268890380859602, -5.915555000305176 ], [ 147.316207885742301, -5.937957763671818 ], [ 147.339080810547102, -5.918111801147461 ], [ 147.371948242187614, -5.958889961242619 ], [ 147.445327758789517, -5.966475009918213 ], [ 147.624481201171989, -6.109792232513428 ], [ 147.711883544921875, -6.271092891693115 ], [ 147.773635864257926, -6.291243076324463 ], [ 147.810974121093864, -6.324722766876221 ], [ 147.807907104492415, -6.354538917541504 ], [ 147.852951049804688, -6.431487083435002 ], [ 147.830825805664062, -6.525767803192139 ], [ 147.851104736328125, -6.575139045715275 ], [ 147.819091796875, -6.587868213653564 ], [ 147.855941772461051, -6.592597007751465 ], [ 147.85791015625, -6.624859809875488 ], [ 147.863616943359489, -6.629649162292424 ], [ 147.8104248046875, -6.692864894866943 ], [ 147.765777587890739, -6.697498798370304 ], [ 147.74781799316429, -6.70835018157959 ], [ 147.667602539062841, -6.6966872215271 ], [ 147.647552490234489, -6.711020946502629 ], [ 147.581558227539176, -6.708716869354191 ], [ 147.56867980957054, -6.730445861816406 ], [ 147.577133178711051, -6.74721097946167 ], [ 147.392562866211279, -6.718891143798828 ], [ 147.342987060546875, -6.747253894805851 ], [ 147.20173645019554, -6.737579822540283 ], [ 147.149536132812614, -6.703573226928711 ], [ 147.080490112304801, -6.706124782562256 ], [ 147.032714843750227, -6.736964225769043 ], [ 146.97833251953125, -6.737222194671631 ], [ 146.967330932617415, -6.742928981781006 ], [ 146.969223022461165, -6.747276782989445 ], [ 146.96333312988304, -6.746943950653019 ], [ 146.958618164062614, -6.755506992340031 ], [ 146.95391845703125, -6.755842208862305 ], [ 146.952804565429801, -6.758479118347111 ], [ 146.95440673828125, -6.756466865539551 ], [ 146.957839965820312, -6.756340980529728 ], [ 146.961639404296989, -6.753368854522648 ], [ 146.946685791015852, -6.965589046478215 ], [ 147.039962768554915, -7.058537006378117 ], [ 147.070281982422102, -7.013609886169377 ], [ 147.04591369628929, -7.06144189834589 ], [ 147.047332763672216, -7.076912879943848 ], [ 147.070953369140739, -7.081467151641846 ], [ 147.0736083984375, -7.113334178924561 ], [ 147.055313110351676, -7.146286010742131 ], [ 147.092330932617301, -7.167283058166447 ], [ 147.133941650390625, -7.220541954040471 ], [ 147.125091552734489, -7.299276828765869 ], [ 147.152221679687614, -7.305555820465088 ], [ 147.129028320312727, -7.327003002166634 ], [ 147.156372070312614, -7.34290885925293 ], [ 147.143371582031477, -7.377570152282715 ], [ 147.168609619140739, -7.385025024414062 ], [ 147.17958068847679, -7.426072120666504 ], [ 147.199920654297216, -7.428854942321777 ], [ 147.179931640625, -7.463823795318547 ], [ 147.224060058593977, -7.463366031646729 ], [ 147.221298217773438, -7.495037078857365 ], [ 147.265090942382926, -7.461441993713379 ], [ 147.261993408203239, -7.476381778717041 ], [ 147.292175292968864, -7.477549076080265 ], [ 147.266281127929801, -7.496270179748535 ], [ 147.283889770507812, -7.503849983215218 ], [ 147.300491333007812, -7.489425182342529 ], [ 147.303680419922216, -7.51445484161377 ], [ 147.364166259765625, -7.507777214050236 ], [ 147.345932006836165, -7.529497146606388 ], [ 147.375000000000114, -7.525379180908089 ], [ 147.388153076171989, -7.575813770294133 ], [ 147.413604736328352, -7.554444789886475 ], [ 147.433883666992642, -7.582778930664006 ], [ 147.466094970703352, -7.589176177978459 ], [ 147.444595336914062, -7.594101905822754 ], [ 147.44721984863304, -7.608057022094727 ], [ 147.434249877929915, -7.606465816497746 ], [ 147.434906005859716, -7.588719844818058 ], [ 147.433380126953466, -7.610879898071289 ], [ 147.471939086914062, -7.608889102935791 ], [ 147.508895874023551, -7.643603801727238 ], [ 147.516647338867415, -7.668172836303654 ], [ 147.487594604492188, -7.676030158996582 ], [ 147.504348754882812, -7.684124946594238 ], [ 147.498184204101562, -7.696485042571965 ], [ 147.577056884765625, -7.709963798522892 ], [ 147.591110229492301, -7.742778778076172 ], [ 147.573303222656477, -7.759106159210148 ], [ 147.59222412109375, -7.785417079925537 ], [ 147.595672607421989, -7.756218910217285 ], [ 147.608474731445654, -7.777159214019775 ], [ 147.664550781250341, -7.791488170623779 ], [ 147.678878784179688, -7.821646213531437 ], [ 147.663055419921875, -7.829998970031681 ], [ 147.687423706054801, -7.830358982086182 ], [ 147.69281005859375, -7.908874988555908 ], [ 147.714965820312727, -7.942296028137207 ], [ 147.76191711425804, -7.954988956451416 ], [ 147.786422729492301, -7.930871009826603 ], [ 147.832489013672102, -7.954973220825195 ], [ 147.866134643554801, -7.940064907073918 ], [ 147.961044311523665, -8.010536193847656 ], [ 147.264205932617188, -8.004534721374512 ], [ 147.203613281250227, -8.032334327697754 ], [ 147.161712646484489, -8.005234718322754 ], [ 147.004119873046989, -8.004434585571232 ], [ 146.911117553711051, -7.959935188293457 ], [ 146.863311767578125, -7.988033771514893 ], [ 146.820205688476562, -7.989436149597168 ], [ 146.784210205078352, -7.933434963226318 ], [ 146.73760986328125, -7.950435161590576 ], [ 146.721618652343977, -7.900935173034668 ], [ 146.731811523437614, -7.824034214019662 ], [ 146.490707397461051, -7.651533126831055 ], [ 146.409118652343864, -7.60783576965332 ], [ 146.111206054687841, -7.548233985900879 ], [ 146.07861328125, -7.493234157562256 ], [ 146.063018798828352, -7.376335144042969 ], [ 145.74201965332054, -7.158435821533203 ], [ 145.793411254882926, -7.086533069610596 ], [ 145.905319213867415, -7.095035076141301 ], [ 145.927413940429915, -6.984435081481934 ], [ 146.003509521484602, -6.896535873413086 ], [ 146.015609741210938, -6.841134071350041 ], [ 145.987411499023551, -6.740635871887207 ], [ 146.0294189453125, -6.689435005187988 ], [ 146.136215209960938, -6.220036029815674 ], [ 146.11091613769554, -6.182134151458683 ], [ 145.903717041015625, -6.064033031463566 ], [ 145.862106323242529, -5.996534824371338 ], [ 146.498611450195312, -5.993234157562199 ], [ 146.674011230468864, -5.891334056854191 ], [ 146.716812133789062, -5.884635925292969 ], [ 146.767868041992188, -5.832235813140869 ], [ 146.774505615234602, -5.843875885009766 ] ] ], [ [ [ 148.00416564941429, -5.831805229186955 ], [ 148.006668090820426, -5.832429885864201 ], [ 148.00721740722679, -5.833611011505127 ], [ 148.003753662109489, -5.834167003631592 ], [ 148.00416564941429, -5.831805229186955 ] ] ], [ [ [ 147.99000549316429, -5.833611011505127 ], [ 147.988616943359375, -5.832500934600773 ], [ 147.989715576171875, -5.830834865570068 ], [ 147.991104125976562, -5.832222938537541 ], [ 147.99000549316429, -5.833611011505127 ] ] ], [ [ [ 148.017761230468864, -5.8301100730896 ], [ 148.022262573242301, -5.830733776092529 ], [ 148.02203369140625, -5.832759857177734 ], [ 148.017227172851562, -5.833332061767578 ], [ 148.017761230468864, -5.8301100730896 ] ] ], [ [ [ 147.988143920898665, -5.827219963073674 ], [ 147.98309326171875, -5.82166576385498 ], [ 147.983367919922102, -5.810657024383488 ], [ 147.990264892578239, -5.821741104125977 ], [ 147.988143920898665, -5.827219963073674 ] ] ], [ [ [ 147.984756469726562, -5.804977893829346 ], [ 147.985321044921875, -5.806128978729248 ], [ 147.983871459960938, -5.806671142578125 ], [ 147.983871459960938, -5.804977893829346 ], [ 147.984756469726562, -5.804977893829346 ] ] ], [ [ [ 147.978820800781364, -5.80479097366333 ], [ 147.97651672363304, -5.803850173950138 ], [ 147.976394653320426, -5.801691055297852 ], [ 147.980224609375, -5.80401420593256 ], [ 147.978820800781364, -5.80479097366333 ] ] ], [ [ [ 148.040023803711165, -5.800036907196045 ], [ 148.039459228515852, -5.801437854766846 ], [ 148.038284301757926, -5.800868034362793 ], [ 148.039657592773892, -5.799204826354867 ], [ 148.040023803711165, -5.800036907196045 ] ] ], [ [ [ 147.972579956054801, -5.804257869720459 ], [ 147.969223022461165, -5.800342082977238 ], [ 147.969970703125, -5.79796314239502 ], [ 147.97357177734375, -5.802742004394474 ], [ 147.972579956054801, -5.804257869720459 ] ] ], [ [ [ 148.05194091796875, -5.798612117767334 ], [ 148.050491333007926, -5.797500133514291 ], [ 148.051330566406364, -5.796543121337834 ], [ 148.052154541015625, -5.796944141387883 ], [ 148.05194091796875, -5.798612117767334 ] ] ], [ [ [ 147.967224121093864, -5.797778129577637 ], [ 147.96638488769554, -5.797500133514291 ], [ 147.965560913085938, -5.794722080230713 ], [ 147.9677734375, -5.794722080230713 ], [ 147.967224121093864, -5.797778129577637 ] ] ], [ [ [ 147.944534301757926, -5.789875984191838 ], [ 147.943618774414062, -5.787825107574406 ], [ 147.94476318359375, -5.78673601150507 ], [ 147.946044921875114, -5.788413047790471 ], [ 147.944534301757926, -5.789875984191838 ] ] ], [ [ [ 148.113052368164176, -5.526390075683594 ], [ 148.108901977539176, -5.527567863464299 ], [ 148.114822387695426, -5.513453006744328 ], [ 148.116668701171989, -5.521083831787109 ], [ 148.113052368164176, -5.526390075683594 ] ] ], [ [ [ 147.79035949707054, -5.461064815521183 ], [ 147.843536376953239, -5.465350151062012 ], [ 147.898025512695312, -5.526619911193848 ], [ 147.99090576171875, -5.542810916900578 ], [ 148.048034667968977, -5.582787036895752 ], [ 148.084716796875114, -5.634444236755371 ], [ 148.058258056640625, -5.765340805053711 ], [ 148.034439086914062, -5.818333148956299 ], [ 148.017745971679688, -5.810713768005314 ], [ 148.020721435547102, -5.827950954437199 ], [ 147.99798583984375, -5.831352233886662 ], [ 147.97151184082054, -5.788788795471191 ], [ 147.861694335937727, -5.742736816406193 ], [ 147.858016967773665, -5.696619033813477 ], [ 147.79925537109375, -5.669793128967285 ], [ 147.759826660156477, -5.611560821533203 ], [ 147.749237060547216, -5.501802921295109 ], [ 147.771926879882926, -5.460289955139103 ], [ 147.79035949707054, -5.461064815521183 ] ] ], [ [ [ 147.744522094726562, -5.420785903930664 ], [ 147.744796752929801, -5.421619892120361 ], [ 147.74305725097679, -5.421759128570557 ], [ 147.743133544922216, -5.420993804931584 ], [ 147.744522094726562, -5.420785903930664 ] ] ], [ [ [ 148.080490112304801, -5.37388801574707 ], [ 148.104995727539062, -5.385276794433594 ], [ 148.11555480957054, -5.415555000305119 ], [ 148.087783813476676, -5.447778224945068 ], [ 148.051116943359489, -5.423888206481934 ], [ 148.058334350586165, -5.381667137145939 ], [ 148.080490112304801, -5.37388801574707 ] ] ], [ [ [ 147.543060302734375, -5.298333168029785 ], [ 147.5413818359375, -5.296945095062199 ], [ 147.542495727539062, -5.295557022094727 ], [ 147.543609619140739, -5.296945095062199 ], [ 147.543060302734375, -5.298333168029785 ] ] ], [ [ [ 147.591979980468977, -5.282991886138916 ], [ 147.613082885742188, -5.28488111495966 ], [ 147.628250122070426, -5.314393997192326 ], [ 147.604156494140852, -5.342862129211426 ], [ 147.579299926757812, -5.345884799957219 ], [ 147.55340576171875, -5.330926895141488 ], [ 147.555053710937614, -5.298227787017709 ], [ 147.591979980468977, -5.282991886138916 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-NCD", "NAME_1": "National Capital District" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 147.180282592773438, -9.492222785949707 ], [ 147.143890380859375, -9.48430347442627 ], [ 147.156143188476676, -9.460613250732422 ], [ 147.127227783203125, -9.419999122619629 ], [ 147.084594726562727, -9.422065734863281 ], [ 147.101119995117188, -9.390834808349553 ], [ 147.179519653320312, -9.356835365295353 ], [ 147.271209716796875, -9.40423393249506 ], [ 147.287414550781364, -9.462735176086426 ], [ 147.276947021484375, -9.510556221008244 ], [ 147.260833740234602, -9.484999656677246 ], [ 147.242782592773551, -9.486388206481877 ], [ 147.239715576171989, -9.504443168640137 ], [ 147.258895874023438, -9.521110534667912 ], [ 147.243331909179801, -9.540278434753304 ], [ 147.180282592773438, -9.492222785949707 ] ] ], [ [ [ 147.1246337890625, -9.43253231048584 ], [ 147.1295166015625, -9.436819076538086 ], [ 147.125885009765625, -9.441933631896973 ], [ 147.122116088867188, -9.436540603637695 ], [ 147.1246337890625, -9.43253231048584 ] ] ], [ [ [ 147.0927734375, -9.446925163269043 ], [ 147.110275268554688, -9.433055877685547 ], [ 147.112777709960938, -9.47611141204834 ], [ 147.093612670898551, -9.478886604309025 ], [ 147.092498779296875, -9.461943626403809 ], [ 147.07666015625, -9.46833324432373 ], [ 147.058334350586051, -9.446623802185002 ], [ 147.0927734375, -9.446925163269043 ] ] ], [ [ [ 147.118331909179688, -9.472498893737793 ], [ 147.118606567382926, -9.487777709960938 ], [ 147.117218017578239, -9.488333702087402 ], [ 147.113052368164176, -9.48305606842041 ], [ 147.118331909179688, -9.472498893737793 ] ] ], [ [ [ 147.11749267578125, -9.497501373291016 ], [ 147.11639404296875, -9.49555492401123 ], [ 147.119171142578239, -9.490832328796387 ], [ 147.120559692382812, -9.49305534362793 ], [ 147.11749267578125, -9.497501373291016 ] ] ], [ [ [ 147.047500610351562, -9.508055686950684 ], [ 147.06361389160179, -9.516387939453125 ], [ 147.081390380859489, -9.512778282165471 ], [ 147.063049316406364, -9.523056983947697 ], [ 147.038894653320312, -9.514165878295898 ], [ 147.047500610351562, -9.508055686950684 ] ] ], [ [ [ 147.178604125976562, -9.519166946411076 ], [ 147.17500305175804, -9.514165878295898 ], [ 147.177505493164176, -9.509444236755314 ], [ 147.179718017578125, -9.512222290039062 ], [ 147.178604125976562, -9.519166946411076 ] ] ], [ [ [ 147.091659545898551, -9.51249980926508 ], [ 147.095840454101562, -9.515556335449219 ], [ 147.086395263671875, -9.514721870422363 ], [ 147.086944580078239, -9.514165878295898 ], [ 147.091659545898551, -9.51249980926508 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-NIK", "NAME_1": "New Ireland" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 152.90943908691429, -4.833610057830754 ], [ 152.907226562500114, -4.83055591583252 ], [ 152.908889770507926, -4.826943874359131 ], [ 152.911666870117529, -4.829165935516357 ], [ 152.90943908691429, -4.833610057830754 ] ] ], [ [ [ 152.849700927734375, -4.824644088745117 ], [ 152.845611572265739, -4.822768211364746 ], [ 152.8453369140625, -4.820265769958496 ], [ 152.848129272461051, -4.821097850799504 ], [ 152.849700927734375, -4.824644088745117 ] ] ], [ [ [ 152.85772705078125, -4.799308776855469 ], [ 152.858398437500114, -4.813086032867375 ], [ 152.830230712890625, -4.801795959472656 ], [ 152.847991943359375, -4.78679704666132 ], [ 152.85772705078125, -4.799308776855469 ] ] ], [ [ [ 152.776000976562614, -4.725646972656193 ], [ 152.772949218750114, -4.722589015960693 ], [ 152.773025512695312, -4.717177867889291 ], [ 152.776916503906477, -4.720543861389103 ], [ 152.776000976562614, -4.725646972656193 ] ] ], [ [ [ 152.764495849609489, -4.686642169952393 ], [ 152.771469116211051, -4.693966865539551 ], [ 152.77102661132858, -4.710562229156437 ], [ 152.761184692382812, -4.697495937347412 ], [ 152.764495849609489, -4.686642169952393 ] ] ], [ [ [ 153.070831298828352, -4.209166049957275 ], [ 153.068893432617415, -4.208055973052922 ], [ 153.07000732421875, -4.206111907958928 ], [ 153.072494506835938, -4.207499980926457 ], [ 153.070831298828352, -4.209166049957275 ] ] ], [ [ [ 152.981674194335938, -4.069167137145996 ], [ 152.985839843750114, -4.072778224945068 ], [ 152.986114501953352, -4.074443817138672 ], [ 152.978332519531477, -4.070834159851017 ], [ 152.981674194335938, -4.069167137145996 ] ] ], [ [ [ 153.616668701171875, -4.025832176208439 ], [ 153.613052368164062, -4.025269031524658 ], [ 153.621017456054688, -4.022530078887883 ], [ 153.620391845703125, -4.024336814880371 ], [ 153.616668701171875, -4.025832176208439 ] ] ], [ [ [ 153.64471435546875, -4.011177062988224 ], [ 153.662796020507812, -4.104515075683537 ], [ 153.625274658203352, -4.139388084411621 ], [ 153.568893432617188, -4.086667060852051 ], [ 153.64471435546875, -4.011177062988224 ] ] ], [ [ [ 153.70611572265625, -3.998611927032357 ], [ 153.726104736328466, -3.999444007873478 ], [ 153.743057250976676, -4.030279159545842 ], [ 153.718338012695312, -4.043055057525635 ], [ 153.69374084472679, -4.020471096038705 ], [ 153.6553955078125, -4.024037837982178 ], [ 153.70611572265625, -3.998611927032357 ] ] ], [ [ [ 152.347381591797102, -3.699464082717896 ], [ 152.3470458984375, -3.698071956634521 ], [ 152.3486328125, -3.697864055633488 ], [ 152.348907470703352, -3.698837995529175 ], [ 152.347381591797102, -3.699464082717896 ] ] ], [ [ [ 153.193450927734602, -3.532619953155461 ], [ 153.208694458007812, -3.533318042755127 ], [ 153.210067749023665, -3.537769079208374 ], [ 153.198852539062614, -3.545283079147339 ], [ 153.193450927734602, -3.532619953155461 ] ] ], [ [ [ 153.188598632812614, -3.522742033004761 ], [ 153.1865234375, -3.521627902984505 ], [ 153.1865234375, -3.519959926605168 ], [ 153.189010620117188, -3.520098924636841 ], [ 153.188598632812614, -3.522742033004761 ] ] ], [ [ [ 153.20722961425804, -3.507009983062687 ], [ 153.210693359375, -3.508472919464111 ], [ 153.21200561523483, -3.510767936706429 ], [ 153.207244873046989, -3.51049900054926 ], [ 153.20722961425804, -3.507009983062687 ] ] ], [ [ [ 153.210342407226676, -3.506036043167114 ], [ 153.20895385742233, -3.505687952041569 ], [ 153.20895385742233, -3.504921913146973 ], [ 153.209655761718977, -3.5047829151153 ], [ 153.210342407226676, -3.506036043167114 ] ] ], [ [ [ 153.188735961914517, -3.503259897231999 ], [ 153.186248779297102, -3.514863014221191 ], [ 153.171005249023551, -3.504652976989689 ], [ 153.190124511718864, -3.49755597114563 ], [ 153.188735961914517, -3.503259897231999 ] ] ], [ [ [ 152.231674194336051, -3.454165935516357 ], [ 152.23500061035179, -3.457221984863281 ], [ 152.233612060546875, -3.459166049957162 ], [ 152.230560302734375, -3.45638990402216 ], [ 152.231674194336051, -3.454165935516357 ] ] ], [ [ [ 153.215011596679801, -3.430829048156738 ], [ 153.245681762695312, -3.47974705696106 ], [ 153.244812011719205, -3.498899936675969 ], [ 153.197463989257926, -3.492965936660767 ], [ 153.172531127929801, -3.458385944366455 ], [ 153.215011596679801, -3.430829048156738 ] ] ], [ [ [ 154.723236083984489, -3.383727073669377 ], [ 154.725463867187727, -3.383760929107666 ], [ 154.727157592773551, -3.387482881546021 ], [ 154.723800659179688, -3.387830972671509 ], [ 154.723236083984489, -3.383727073669377 ] ] ], [ [ [ 154.727401733398551, -3.376907110214177 ], [ 154.74568176269554, -3.416007995605469 ], [ 154.751708984375, -3.440010070800724 ], [ 154.731201171875227, -3.465682029724121 ], [ 154.74859619140625, -3.435281038284302 ], [ 154.726638793945426, -3.378577947616577 ], [ 154.721511840820312, -3.380527019500732 ], [ 154.722198486328239, -3.359028100967407 ], [ 154.727401733398551, -3.376907110214177 ] ] ], [ [ [ 153.296112060547102, -3.362222909927368 ], [ 153.341964721680029, -3.380572080612183 ], [ 153.330474853515625, -3.415044069290161 ], [ 153.29888916015625, -3.384166002273503 ], [ 153.280319213867188, -3.395842075347787 ], [ 153.242218017578125, -3.38611102104187 ], [ 153.247680664062614, -3.37062406539917 ], [ 153.296112060547102, -3.362222909927368 ] ] ], [ [ [ 151.808074951172216, -3.353410005569401 ], [ 151.8067626953125, -3.352714061737061 ], [ 151.807312011719091, -3.35174107551569 ], [ 151.808349609375114, -3.35174107551569 ], [ 151.808074951172216, -3.353410005569401 ] ] ], [ [ [ 154.695602416992301, -3.363759040832406 ], [ 154.687637329101562, -3.359445095062199 ], [ 154.687210083007926, -3.351651906967163 ], [ 154.697891235351676, -3.360487937927246 ], [ 154.695602416992301, -3.363759040832406 ] ] ], [ [ [ 154.722061157226676, -3.346506118774357 ], [ 154.721649169922102, -3.344208955764771 ], [ 154.722900390625, -3.343791961669865 ], [ 154.723861694335938, -3.344903945922738 ], [ 154.722061157226676, -3.346506118774357 ] ] ], [ [ [ 154.723373413086165, -3.343303918838501 ], [ 154.721237182617415, -3.34260892868042 ], [ 154.72137451171875, -3.34066009521473 ], [ 154.723724365234489, -3.341981887817383 ], [ 154.723373413086165, -3.343303918838501 ] ] ], [ [ [ 154.673568725586051, -3.340869903564453 ], [ 154.66920471191429, -3.339338064193726 ], [ 154.669067382812614, -3.334328889846745 ], [ 154.674530029297102, -3.335999011993295 ], [ 154.673568725586051, -3.340869903564453 ] ] ], [ [ [ 151.774307250976676, -3.330164909362793 ], [ 151.773483276367642, -3.329957008361816 ], [ 151.773498535156364, -3.328617095947209 ], [ 151.774856567382926, -3.329344034194946 ], [ 151.774307250976676, -3.330164909362793 ] ] ], [ [ [ 154.662689208984489, -3.326328992843628 ], [ 154.660537719726562, -3.322711944580021 ], [ 154.664138793945654, -3.319370985031128 ], [ 154.664764404296875, -3.321458101272526 ], [ 154.662689208984489, -3.326328992843628 ] ] ], [ [ [ 154.716171264648438, -3.322362899780217 ], [ 154.713150024414176, -3.325946092605591 ], [ 154.712432861328125, -3.318258047103882 ], [ 154.714233398437955, -3.319094896316528 ], [ 154.716171264648438, -3.322362899780217 ] ] ], [ [ [ 154.717483520507926, -3.315892934799194 ], [ 154.714782714843977, -3.316380023956299 ], [ 154.71437072753929, -3.315685033798161 ], [ 154.716384887695426, -3.31352710723877 ], [ 154.717483520507926, -3.315892934799194 ] ] ], [ [ [ 154.658187866210938, -3.317075967788639 ], [ 154.656036376953352, -3.316170930862427 ], [ 154.656036376953352, -3.312693119049072 ], [ 154.659851074218977, -3.31443190574646 ], [ 154.658187866210938, -3.317075967788639 ] ] ], [ [ [ 154.715057373046989, -3.305943965911808 ], [ 154.71652221679733, -3.307960987090951 ], [ 154.71284484863304, -3.311022043228149 ], [ 154.713882446289062, -3.305735111236572 ], [ 154.715057373046989, -3.305943965911808 ] ] ], [ [ [ 154.715057373046989, -3.302257061004639 ], [ 154.713958740234375, -3.301213026046696 ], [ 154.714645385742188, -3.297802925109863 ], [ 154.715484619140625, -3.299057006835881 ], [ 154.715057373046989, -3.302257061004639 ] ] ], [ [ [ 154.642257690429688, -3.282845020294133 ], [ 154.639694213867301, -3.27811598777771 ], [ 154.64031982421875, -3.276236057281437 ], [ 154.64155578613304, -3.276654958724919 ], [ 154.642257690429688, -3.282845020294133 ] ] ], [ [ [ 154.715408325195312, -3.291820049285775 ], [ 154.710693359375, -3.281455039978027 ], [ 154.71319580078125, -3.27386999130249 ], [ 154.718811035156705, -3.283611059188843 ], [ 154.715408325195312, -3.291820049285775 ] ] ], [ [ [ 154.706893920898438, -3.269208908081055 ], [ 154.708343505859375, -3.270462989807072 ], [ 154.707229614257926, -3.271713972091675 ], [ 154.705535888671875, -3.268723964691162 ], [ 154.706893920898438, -3.269208908081055 ] ] ], [ [ [ 154.517684936523438, -3.180712938308716 ], [ 154.514343261719205, -3.179532051086426 ], [ 154.522613525390966, -3.173757076263428 ], [ 154.521499633789062, -3.177999973297062 ], [ 154.517684936523438, -3.180712938308716 ] ] ], [ [ [ 154.509521484375227, -3.17577409744257 ], [ 154.506607055664062, -3.173965930938607 ], [ 154.50611877441429, -3.171912908554077 ], [ 154.51007080078125, -3.174940109252873 ], [ 154.509521484375227, -3.17577409744257 ] ] ], [ [ [ 154.46607971191429, -3.143491983413696 ], [ 154.464691162109602, -3.14314603805542 ], [ 154.463516235351562, -3.141125917434636 ], [ 154.46455383300804, -3.140986919403076 ], [ 154.46607971191429, -3.143491983413696 ] ] ], [ [ [ 154.508483886718864, -3.136465072631836 ], [ 154.506256103515625, -3.135214090347233 ], [ 154.5028076171875, -3.128706932067814 ], [ 154.50459289550804, -3.128395080566406 ], [ 154.508483886718864, -3.136465072631836 ] ] ], [ [ [ 154.497955322265739, -3.126029014587346 ], [ 154.496841430664176, -3.125195026397705 ], [ 154.497116088867415, -3.124428987502995 ], [ 154.498367309570426, -3.124778032302743 ], [ 154.497955322265739, -3.126029014587346 ] ] ], [ [ [ 154.484085083008154, -3.124289989471436 ], [ 154.483261108398551, -3.12387299537653 ], [ 154.484710693359375, -3.121925115585213 ], [ 154.485076904296875, -3.123802900314331 ], [ 154.484085083008154, -3.124289989471436 ] ] ], [ [ [ 154.460403442382926, -3.115314960479623 ], [ 154.460052490234716, -3.117611885070744 ], [ 154.456176757812614, -3.115453958511353 ], [ 154.458328247070426, -3.113646984100285 ], [ 154.460403442382926, -3.115314960479623 ] ] ], [ [ [ 154.442733764648438, -3.113785982131958 ], [ 154.443008422852017, -3.111836910247803 ], [ 154.444259643554688, -3.110862016677856 ], [ 154.444747924804688, -3.11155891418457 ], [ 154.442733764648438, -3.113785982131958 ] ] ], [ [ [ 154.440933227539062, -3.115036964416447 ], [ 154.443145751953352, -3.119489908218327 ], [ 154.433807373046989, -3.109610080718937 ], [ 154.440521240234602, -3.112114906311035 ], [ 154.440933227539062, -3.115036964416447 ] ] ], [ [ [ 154.44024658203125, -3.105295896530095 ], [ 154.445297241211392, -3.10710597038269 ], [ 154.44537353515625, -3.110166072845402 ], [ 154.438919067382812, -3.1088449954986 ], [ 154.44024658203125, -3.105295896530095 ] ] ], [ [ [ 151.637985229492188, -3.042984008789006 ], [ 151.637084960937727, -3.041943073272648 ], [ 151.638259887695426, -3.041316032409668 ], [ 151.638473510742188, -3.042289018630981 ], [ 151.637985229492188, -3.042984008789006 ] ] ], [ [ [ 152.627426147460938, -3.03159308433527 ], [ 152.641387939453239, -3.067776918411198 ], [ 152.633926391601676, -3.114866018295288 ], [ 152.658340454101676, -3.118611097335702 ], [ 152.662353515625114, -3.137846946716252 ], [ 152.644165039062727, -3.220000028610173 ], [ 152.625549316406364, -3.227500915527344 ], [ 152.583053588867188, -3.176944971084538 ], [ 152.552780151367301, -3.165555953979492 ], [ 152.561111450195312, -3.14083194732666 ], [ 152.521942138671989, -3.091944932937565 ], [ 152.554718017578352, -3.050833940505925 ], [ 152.627426147460938, -3.03159308433527 ] ] ], [ [ [ 152.658615112304688, -3.027777910232487 ], [ 152.663055419922102, -3.029443979263249 ], [ 152.664443969726676, -3.035001039505005 ], [ 152.656951904297102, -3.032778024673462 ], [ 152.658615112304688, -3.027777910232487 ] ] ], [ [ [ 152.678070068359375, -3.026635885238647 ], [ 152.692504882812614, -3.029721975326481 ], [ 152.693893432617188, -3.035001039505005 ], [ 152.668060302734375, -3.030555963516179 ], [ 152.678070068359375, -3.026635885238647 ] ] ], [ [ [ 150.735839843750114, -2.9788880348205 ], [ 150.731948852539404, -2.998611927032471 ], [ 150.719299316406364, -3.000966072082463 ], [ 150.730560302734489, -2.983333110809326 ], [ 150.735839843750114, -2.9788880348205 ] ] ], [ [ [ 150.837570190429688, -2.971412897109929 ], [ 150.83056640625, -2.969628095626774 ], [ 150.830886840820426, -2.965652942657414 ], [ 150.839370727539062, -2.965926885604858 ], [ 150.837570190429688, -2.971412897109929 ] ] ], [ [ [ 152.657775878906364, -2.933610916137695 ], [ 152.671951293945312, -2.954722881317139 ], [ 152.649169921875, -2.966110944747868 ], [ 152.642501831054688, -2.953609943389893 ], [ 152.657775878906364, -2.933610916137695 ] ] ], [ [ [ 151.132293701171989, -2.903542041778564 ], [ 151.134567260742301, -2.906466007232666 ], [ 151.130569458007926, -2.911243915557861 ], [ 151.127777099609375, -2.904166936874333 ], [ 151.132293701171989, -2.903542041778564 ] ] ], [ [ [ 150.881942749023551, -2.90305495262146 ], [ 150.938049316406477, -2.926388025283813 ], [ 150.95916748046875, -2.957777023315373 ], [ 151.003890991210938, -2.966667890548649 ], [ 150.982223510742188, -2.979166030883675 ], [ 150.962783813476562, -2.965276956558171 ], [ 150.90028381347679, -2.97777795791626 ], [ 150.895416259765625, -2.962842941284123 ], [ 150.852493286133154, -2.972222089767342 ], [ 150.85945129394554, -2.962223052978459 ], [ 150.820556640625227, -2.952222108840942 ], [ 150.823883056640966, -2.970556020736694 ], [ 150.744445800781477, -2.985279083251953 ], [ 150.773330688476676, -2.952500104904175 ], [ 150.79499816894554, -2.957777023315373 ], [ 150.811660766601676, -2.933888912200928 ], [ 150.881942749023551, -2.90305495262146 ] ] ], [ [ [ 152.6552734375, -2.76583194732666 ], [ 152.672225952148892, -2.785834074020386 ], [ 152.65155029296875, -2.799235105514526 ], [ 152.641937255859489, -2.777498960494938 ], [ 152.6552734375, -2.76583194732666 ] ] ], [ [ [ 150.787506103515625, -2.737221956252995 ], [ 150.786117553711279, -2.735555887222176 ], [ 150.787216186523438, -2.734165906906071 ], [ 150.788192749023551, -2.735555887222176 ], [ 150.787506103515625, -2.737221956252995 ] ] ], [ [ [ 150.714721679687614, -2.721111059188843 ], [ 150.713333129882926, -2.722498893737793 ], [ 150.711944580078125, -2.722223043441772 ], [ 150.713897705078352, -2.719238042831421 ], [ 150.714721679687614, -2.721111059188843 ] ] ], [ [ [ 150.631942749023551, -2.705277919769287 ], [ 150.678054809570426, -2.718055009841919 ], [ 150.714065551757812, -2.750716924667358 ], [ 150.653976440429688, -2.740343093872013 ], [ 150.628982543945312, -2.72143292427063 ], [ 150.631942749023551, -2.705277919769287 ] ] ], [ [ [ 151.920562744140625, -2.701666116714421 ], [ 151.977355957031477, -2.721179962158203 ], [ 152.006942749023892, -2.75527811050415 ], [ 151.993896484375, -2.766109943389893 ], [ 152.009719848632812, -2.776945114135742 ], [ 152.005279541015739, -2.797223091125488 ], [ 151.980026245117415, -2.803139925002995 ], [ 151.98500061035179, -2.817222118377686 ], [ 152.001388549804915, -2.802499055862427 ], [ 152.004165649414062, -2.818331956863346 ], [ 151.995834350586051, -2.831945896148682 ], [ 151.966110229492415, -2.830832958221436 ], [ 152.005859375000114, -2.893439054489136 ], [ 152.057785034179688, -2.908611059188843 ], [ 152.076385498046989, -2.930001020431519 ], [ 152.07208251953125, -2.973449945449715 ], [ 152.050003051757926, -2.998889923095703 ], [ 152.002502441406477, -2.964998960494938 ], [ 151.990554809570426, -2.905833005905151 ], [ 151.962493896484602, -2.905555009841919 ], [ 151.941940307617301, -2.884166955947819 ], [ 151.95960998535179, -2.841536045074406 ], [ 151.9410400390625, -2.850619077682495 ], [ 151.9122314453125, -2.821971893310547 ], [ 151.923400878906705, -2.810647010803223 ], [ 151.905563354492188, -2.789484977722111 ], [ 151.934173583984375, -2.754164934158268 ], [ 151.908615112304688, -2.711666107177734 ], [ 151.920562744140625, -2.701666116714421 ] ] ], [ [ [ 150.643615722656364, -2.693888902664128 ], [ 150.647506713867188, -2.699721097946167 ], [ 150.639450073242188, -2.704721927642822 ], [ 150.63722229003929, -2.699443101882935 ], [ 150.643615722656364, -2.693888902664128 ] ] ], [ [ [ 150.763351440430142, -2.695826053619328 ], [ 150.760284423828352, -2.690001010894719 ], [ 150.765518188476904, -2.685944080352726 ], [ 150.766967773437727, -2.691414117813054 ], [ 150.763351440430142, -2.695826053619328 ] ] ], [ [ [ 150.753890991210938, -2.684165954589844 ], [ 150.752777099609375, -2.683887958526611 ], [ 150.754440307617301, -2.682777881622314 ], [ 150.75471496582054, -2.683887958526611 ], [ 150.753890991210938, -2.684165954589844 ] ] ], [ [ [ 150.717773437500114, -2.675833940505981 ], [ 150.734161376953352, -2.698889970779419 ], [ 150.698333740234375, -2.725554943084717 ], [ 150.68695068359375, -2.688611030578613 ], [ 150.717773437500114, -2.675833940505981 ] ] ], [ [ [ 150.6319580078125, -2.674396038055363 ], [ 150.639511108398665, -2.675378084182739 ], [ 150.640762329101676, -2.681957960128784 ], [ 150.631820678710938, -2.68261194229126 ], [ 150.6319580078125, -2.674396038055363 ] ] ], [ [ [ 150.734451293945312, -2.67222094535822 ], [ 150.741104125976904, -2.679444074630624 ], [ 150.73333740234375, -2.685000896453857 ], [ 150.728057861328352, -2.674721956253052 ], [ 150.734451293945312, -2.67222094535822 ] ] ], [ [ [ 150.772537231445312, -2.677896022796631 ], [ 150.770828247070426, -2.673748016357365 ], [ 150.772323608398551, -2.67024302482605 ], [ 150.773574829101562, -2.672843933105469 ], [ 150.772537231445312, -2.677896022796631 ] ] ], [ [ [ 150.325363159179915, -2.673955917358342 ], [ 150.321380615234489, -2.674359083175602 ], [ 150.318450927734375, -2.671881914138794 ], [ 150.327178955078239, -2.669486045837402 ], [ 150.325363159179915, -2.673955917358342 ] ] ], [ [ [ 150.61648559570358, -2.677779912948552 ], [ 150.612533569336051, -2.675497055053654 ], [ 150.616333007812614, -2.669014930725098 ], [ 150.619842529296875, -2.673393011093083 ], [ 150.61648559570358, -2.677779912948552 ] ] ], [ [ [ 150.582504272461165, -2.664722919464111 ], [ 150.586669921875227, -2.66833305358881 ], [ 150.580825805664176, -2.675277948379517 ], [ 150.576950073242415, -2.668611049652043 ], [ 150.582504272461165, -2.664722919464111 ] ] ], [ [ [ 150.538330078125114, -2.664444923400879 ], [ 150.607391357421989, -2.683820009231511 ], [ 150.587265014648551, -2.730407953262329 ], [ 150.55877685546875, -2.691847085952702 ], [ 150.52362060546875, -2.680659055709839 ], [ 150.538330078125114, -2.664444923400879 ] ] ], [ [ [ 150.7342529296875, -2.665400028228703 ], [ 150.732559204101562, -2.665122032165471 ], [ 150.732421875000227, -2.66402792930603 ], [ 150.734771728515625, -2.663841009139958 ], [ 150.7342529296875, -2.665400028228703 ] ] ], [ [ [ 150.336944580078125, -2.672498941421452 ], [ 150.333312988281591, -2.670535087585449 ], [ 150.333206176757926, -2.662293910980225 ], [ 150.336441040039176, -2.664537906646672 ], [ 150.336944580078125, -2.672498941421452 ] ] ], [ [ [ 150.471115112304915, -2.660001039504891 ], [ 150.486389160156477, -2.668611049652043 ], [ 150.466384887695426, -2.677500009536743 ], [ 150.462493896484375, -2.661945104598942 ], [ 150.471115112304915, -2.660001039504891 ] ] ], [ [ [ 150.519882202148438, -2.65842604637146 ], [ 150.518646240234489, -2.658215999603215 ], [ 150.520858764648438, -2.655988931655827 ], [ 150.521057128906477, -2.657104015350342 ], [ 150.519882202148438, -2.65842604637146 ] ] ], [ [ [ 150.455551147461051, -2.654165983200073 ], [ 150.457504272460938, -2.66944503784174 ], [ 150.439437866211051, -2.669720888137761 ], [ 150.43499755859375, -2.658888101577759 ], [ 150.455551147461051, -2.654165983200073 ] ] ], [ [ [ 150.686386108398438, -2.664166927337646 ], [ 150.676940917968977, -2.664444923400879 ], [ 150.683700561523438, -2.651665925979614 ], [ 150.690551757812614, -2.656944036483765 ], [ 150.686386108398438, -2.664166927337646 ] ] ], [ [ [ 150.663909912109375, -2.659547090530396 ], [ 150.661575317382812, -2.655966997146606 ], [ 150.664382934570312, -2.651505947113037 ], [ 150.667221069336392, -2.655303001403752 ], [ 150.663909912109375, -2.659547090530396 ] ] ], [ [ [ 150.774993896484489, -2.651387929916382 ], [ 150.774169921875227, -2.650000095367432 ], [ 150.775558471680142, -2.649722099304199 ], [ 150.776107788086165, -2.650278091430664 ], [ 150.774993896484489, -2.651387929916382 ] ] ], [ [ [ 150.564422607421989, -2.651823043823242 ], [ 150.563140869140739, -2.650232076644897 ], [ 150.565414428711051, -2.649643898010197 ], [ 150.565567016601676, -2.651309967040959 ], [ 150.564422607421989, -2.651823043823242 ] ] ], [ [ [ 150.527221679687955, -2.651665925979614 ], [ 150.526947021484375, -2.649722099304199 ], [ 150.528823852539062, -2.648890018463078 ], [ 150.528610229492301, -2.650000095367432 ], [ 150.527221679687955, -2.651665925979614 ] ] ], [ [ [ 150.640838623047102, -2.647778034210205 ], [ 150.649169921875341, -2.659167051315251 ], [ 150.632507324219205, -2.668889045715275 ], [ 150.628890991211051, -2.654443979263306 ], [ 150.640838623047102, -2.647778034210205 ] ] ], [ [ [ 150.5755615234375, -2.643889904022103 ], [ 150.579162597656364, -2.649166107177734 ], [ 150.574172973632812, -2.657222032546997 ], [ 150.569717407226676, -2.650834083557129 ], [ 150.5755615234375, -2.643889904022103 ] ] ], [ [ [ 150.713058471679801, -2.641388893127441 ], [ 150.729919433593977, -2.642543077468872 ], [ 150.733016967773665, -2.650166034698486 ], [ 150.720321655273438, -2.651971101760807 ], [ 150.713058471679801, -2.641388893127441 ] ] ], [ [ [ 150.84492492675804, -2.640240907669011 ], [ 150.843887329101676, -2.638889074325448 ], [ 150.845993041992301, -2.638431072235051 ], [ 150.8458251953125, -2.639775991439762 ], [ 150.84492492675804, -2.640240907669011 ] ] ], [ [ [ 150.4954833984375, -2.636632919311523 ], [ 150.501342773437614, -2.659432888031006 ], [ 150.498641967773438, -2.663604021072388 ], [ 150.483337402343977, -2.648890018463078 ], [ 150.4954833984375, -2.636632919311523 ] ] ], [ [ [ 150.641693115234375, -2.639339923858529 ], [ 150.640090942382926, -2.637923002243042 ], [ 150.643127441406477, -2.636051893234139 ], [ 150.643173217773665, -2.637883901596012 ], [ 150.641693115234375, -2.639339923858529 ] ] ], [ [ [ 149.661392211914062, -2.631944894790649 ], [ 149.666244506836392, -2.633820056915283 ], [ 149.664718627930142, -2.640554904937744 ], [ 149.656112670898665, -2.63305401802063 ], [ 149.661392211914062, -2.631944894790649 ] ] ], [ [ [ 150.769714355469091, -2.641756057739144 ], [ 150.763092041015625, -2.637633085250854 ], [ 150.764556884765739, -2.631043910980168 ], [ 150.7701416015625, -2.63820290565485 ], [ 150.769714355469091, -2.641756057739144 ] ] ], [ [ [ 149.679718017578125, -2.623889923095703 ], [ 149.682983398437614, -2.625622034072819 ], [ 149.671035766601562, -2.633332967758179 ], [ 149.67195129394554, -2.627429962158203 ], [ 149.679718017578125, -2.623889923095703 ] ] ], [ [ [ 150.626449584961051, -2.637212038040047 ], [ 150.629440307617415, -2.624531030654907 ], [ 150.638671875000114, -2.619591951370239 ], [ 150.63874816894554, -2.621090888977051 ], [ 150.626449584961051, -2.637212038040047 ] ] ], [ [ [ 150.534774780273438, -2.637706041336003 ], [ 150.527847290039176, -2.625448942184448 ], [ 150.531372070312614, -2.619008064269963 ], [ 150.540496826171875, -2.627213001251164 ], [ 150.534774780273438, -2.637706041336003 ] ] ], [ [ [ 150.453781127929915, -2.632539033889657 ], [ 150.448333740234375, -2.624722003936711 ], [ 150.451553344726676, -2.615062952041512 ], [ 150.456558227539062, -2.625763893127441 ], [ 150.453781127929915, -2.632539033889657 ] ] ], [ [ [ 150.455184936523551, -2.618139982223454 ], [ 150.45429992675804, -2.616939067840576 ], [ 150.455596923828125, -2.614918947219849 ], [ 150.456954956054688, -2.616252899169922 ], [ 150.455184936523551, -2.618139982223454 ] ] ], [ [ [ 150.738052368164404, -2.616389036178589 ], [ 150.737228393554801, -2.616389036178589 ], [ 150.73638916015625, -2.614721059799194 ], [ 150.738052368164404, -2.615277051925659 ], [ 150.738052368164404, -2.616389036178589 ] ] ], [ [ [ 150.447052001953352, -2.616334915161133 ], [ 150.444549560546875, -2.616125106811523 ], [ 150.445037841796875, -2.614176034927368 ], [ 150.445724487304915, -2.613966941833496 ], [ 150.447052001953352, -2.616334915161133 ] ] ], [ [ [ 150.459991455078125, -2.619831085205078 ], [ 150.456817626953352, -2.618550062179565 ], [ 150.460311889648551, -2.613600015640259 ], [ 150.461273193359489, -2.618289947509766 ], [ 150.459991455078125, -2.619831085205078 ] ] ], [ [ [ 150.673461914062727, -2.621504068374634 ], [ 150.675964355468977, -2.615433931350651 ], [ 150.680984497070312, -2.613053083419743 ], [ 150.68055725097679, -2.61581110954279 ], [ 150.673461914062727, -2.621504068374634 ] ] ], [ [ [ 150.478790283203239, -2.620330095291138 ], [ 150.476959228515625, -2.616967916488591 ], [ 150.479644775390625, -2.61230993270874 ], [ 150.481597900390739, -2.617398977279663 ], [ 150.478790283203239, -2.620330095291138 ] ] ], [ [ [ 150.45033264160179, -2.611355066299438 ], [ 150.451873779297102, -2.614268064498901 ], [ 150.446395874023551, -2.613610982894897 ], [ 150.44667053222679, -2.611110925674438 ], [ 150.45033264160179, -2.611355066299438 ] ] ], [ [ [ 150.610855102539062, -2.640500068664551 ], [ 150.608322143554801, -2.658854007720947 ], [ 150.573333740234489, -2.625277996063176 ], [ 150.596435546875227, -2.606770992279053 ], [ 150.610855102539062, -2.640500068664551 ] ] ], [ [ [ 150.45062255859375, -2.607404947280884 ], [ 150.448501586914176, -2.605823040008488 ], [ 150.451263427734489, -2.604646921157837 ], [ 150.452026367187614, -2.606229066848755 ], [ 150.45062255859375, -2.607404947280884 ] ] ], [ [ [ 150.453338623046875, -2.605000972747746 ], [ 150.451950073242529, -2.6038880348205 ], [ 150.453048706054688, -2.602499961853027 ], [ 150.454162597656477, -2.603610038757267 ], [ 150.453338623046875, -2.605000972747746 ] ] ], [ [ [ 150.589172363281364, -2.601387977600041 ], [ 150.56721496582054, -2.631387948989811 ], [ 150.546951293945312, -2.636945009231567 ], [ 150.562774658203125, -2.631109952926579 ], [ 150.589172363281364, -2.601387977600041 ] ] ], [ [ [ 149.706939697265966, -2.600555896759033 ], [ 149.71638488769554, -2.608889102935791 ], [ 149.69610595703125, -2.623333930969238 ], [ 149.703887939453466, -2.600833892822266 ], [ 149.706939697265966, -2.600555896759033 ] ] ], [ [ [ 150.768325805664176, -2.606667041778564 ], [ 150.767257690429688, -2.603575944900456 ], [ 150.768890380859489, -2.599026918411198 ], [ 150.771118164062727, -2.604722976684513 ], [ 150.768325805664176, -2.606667041778564 ] ] ], [ [ [ 151.97944641113304, -2.591667890548706 ], [ 152.019165039062614, -2.608333110809326 ], [ 152.027221679687614, -2.636945009231567 ], [ 152.014999389648551, -2.660554885864258 ], [ 151.943603515625227, -2.658888101577759 ], [ 151.947769165039176, -2.624025106429997 ], [ 151.97944641113304, -2.591667890548706 ] ] ], [ [ [ 150.463668823242301, -2.590471029281559 ], [ 150.463638305664062, -2.59856200218195 ], [ 150.452362060546875, -2.596781969070435 ], [ 150.455352783203239, -2.591308116912785 ], [ 150.463668823242301, -2.590471029281559 ] ] ], [ [ [ 150.538604736328352, -2.580276966094914 ], [ 150.55024719238304, -2.592431068420296 ], [ 150.54351806640625, -2.610799074172974 ], [ 150.523880004882812, -2.603327989578247 ], [ 150.538604736328352, -2.580276966094914 ] ] ], [ [ [ 150.783050537109489, -2.566665887832642 ], [ 150.784729003906364, -2.572777986526489 ], [ 150.778884887695312, -2.586667060852051 ], [ 150.771942138671989, -2.581666946411076 ], [ 150.783050537109489, -2.566665887832642 ] ] ], [ [ [ 150.490539550781477, -2.566143989562988 ], [ 150.494049072265739, -2.574275970458928 ], [ 150.486968994140852, -2.588202953338623 ], [ 150.476730346679801, -2.57431697845459 ], [ 150.490539550781477, -2.566143989562988 ] ] ], [ [ [ 150.48695373535179, -2.564604997634888 ], [ 150.486480712890625, -2.562549114227295 ], [ 150.489578247070312, -2.563292026519775 ], [ 150.488510131836051, -2.564153909683171 ], [ 150.48695373535179, -2.564604997634888 ] ] ], [ [ [ 150.798828125000455, -2.553205013275146 ], [ 150.847885131836051, -2.607379913329964 ], [ 150.930633544921989, -2.651823043823242 ], [ 150.950836181640852, -2.683887958526611 ], [ 151.021392822265852, -2.687222957611027 ], [ 151.053894042968864, -2.74555492401123 ], [ 151.080535888672102, -2.74025106430048 ], [ 151.122772216796875, -2.779375076293832 ], [ 151.156661987304801, -2.776388883590585 ], [ 151.186386108398665, -2.80472111701954 ], [ 151.184448242187614, -2.852222919464111 ], [ 151.214340209960938, -2.873032093048096 ], [ 151.300277709961051, -2.866944074630737 ], [ 151.32916259765625, -2.876389026641789 ], [ 151.342498779296875, -2.90500092506403 ], [ 151.413604736328239, -2.900835037231388 ], [ 151.482452392578125, -2.973366022109985 ], [ 151.51055908203125, -2.970000028610229 ], [ 151.541107177734602, -2.997499942779541 ], [ 151.563049316406477, -2.993333101272583 ], [ 151.582138061523551, -3.021915912628117 ], [ 151.672500610351562, -3.045277118682861 ], [ 151.71296691894554, -3.117927074432316 ], [ 151.74580383300804, -3.140463113784733 ], [ 151.772018432617301, -3.128134965896606 ], [ 151.771835327148779, -3.159363985061646 ], [ 151.802688598632812, -3.191649913787785 ], [ 151.858245849609375, -3.18480396270752 ], [ 151.880416870117188, -3.200598001480103 ], [ 151.939010620117415, -3.202599048614502 ], [ 151.957260131835938, -3.238279104232788 ], [ 151.993423461914062, -3.22890305519104 ], [ 152.021408081054915, -3.247392892837411 ], [ 152.047897338867415, -3.24199199676508 ], [ 152.048080444336165, -3.279870986938477 ], [ 152.104827880859489, -3.31892204284668 ], [ 152.202117919921989, -3.45183610916132 ], [ 152.351150512695312, -3.533580064773503 ], [ 152.3499755859375, -3.584161043167114 ], [ 152.391342163086279, -3.599570035934391 ], [ 152.416305541992301, -3.671366930007935 ], [ 152.477233886718977, -3.63596510887146 ], [ 152.492324829101676, -3.640706062316781 ], [ 152.544174194335938, -3.743055105209351 ], [ 152.531951904296875, -3.782500028610173 ], [ 152.553604125976676, -3.811666011810303 ], [ 152.638229370117301, -3.821908950805607 ], [ 152.684768676757926, -3.872152090072632 ], [ 152.746917724609375, -3.890182018280029 ], [ 152.791900634765625, -3.855499029159546 ], [ 152.820968627929915, -3.863190889358521 ], [ 152.825637817382926, -3.936125040054264 ], [ 152.851119995117415, -3.976382017135563 ], [ 152.900421142578125, -3.997499942779484 ], [ 152.933914184570767, -3.977674007415771 ], [ 152.943603515625114, -4.037498950958195 ], [ 152.994445800781591, -4.095276832580566 ], [ 153.006393432617642, -4.097220897674561 ], [ 153.016326904296989, -4.140431880950871 ], [ 153.038894653320312, -4.155556201934758 ], [ 153.033615112304915, -4.189166069030762 ], [ 153.060180664062955, -4.21083402633667 ], [ 153.090301513672102, -4.219204902648812 ], [ 153.104644775390625, -4.242837905883789 ], [ 153.11604309082054, -4.273412227630615 ], [ 153.102218627929688, -4.340834140777474 ], [ 153.118896484375227, -4.375 ], [ 153.052780151367301, -4.427948951721135 ], [ 153.025100708007926, -4.477415084838867 ], [ 153.033172607421875, -4.509377956390381 ], [ 153.062744140625, -4.529520988464355 ], [ 153.060562133789517, -4.598054885864258 ], [ 153.017089843750114, -4.635731220245304 ], [ 153.015243530273438, -4.683358192443734 ], [ 152.990356445312727, -4.685588836669865 ], [ 152.966949462890739, -4.748333930969238 ], [ 152.922119140625, -4.781452178955021 ], [ 152.928329467773665, -4.798056125640869 ], [ 152.894058227539176, -4.788510799407959 ], [ 152.897872924804801, -4.829925060272217 ], [ 152.878616333007926, -4.851665019989014 ], [ 152.858413696289062, -4.770492076873779 ], [ 152.832885742187614, -4.770566940307617 ], [ 152.808288574219091, -4.735227108001652 ], [ 152.790283203125227, -4.737777233123666 ], [ 152.802215576171875, -4.725833892822209 ], [ 152.770065307617415, -4.679481029510441 ], [ 152.724731445312614, -4.667931079864502 ], [ 152.707992553710938, -4.572451114654484 ], [ 152.676864624023551, -4.552985191345215 ], [ 152.674407958984375, -4.497439861297551 ], [ 152.649917602539176, -4.453497886657715 ], [ 152.67445373535179, -4.426073074340763 ], [ 152.684692382812841, -4.374653816223031 ], [ 152.690185546875, -4.295265197753849 ], [ 152.67140197753929, -4.208229064941406 ], [ 152.685516357422102, -4.180573940277043 ], [ 152.614166259765625, -4.089723110198975 ], [ 152.612060546875, -4.034658908843994 ], [ 152.564727783203125, -3.95194506645197 ], [ 152.533828735351562, -3.928544998168888 ], [ 152.50250244140625, -3.856664896011296 ], [ 152.446487426757812, -3.82443189620966 ], [ 152.357299804687727, -3.711474895477295 ], [ 152.342025756836051, -3.687028884887695 ], [ 152.344451904296875, -3.643606901168823 ], [ 152.297058105468864, -3.617356061935368 ], [ 152.265823364257926, -3.566948890686035 ], [ 152.22950744628929, -3.555130958557072 ], [ 152.22430419921875, -3.533761978149414 ], [ 152.143508911133267, -3.482561111450195 ], [ 152.070236206054915, -3.479933023452759 ], [ 152.0, -3.443438053131104 ], [ 151.977874755859375, -3.459646940231323 ], [ 151.907348632812727, -3.433001041412297 ], [ 151.800460815429688, -3.341722011566105 ], [ 151.769485473632926, -3.323215961456185 ], [ 151.717529296875, -3.302552938461304 ], [ 151.623168945312727, -3.181358098983765 ], [ 151.466537475586165, -3.117628097534123 ], [ 151.426986694336279, -3.056335926055908 ], [ 151.342391967773665, -3.003879070281926 ], [ 151.292221069336051, -2.991389036178589 ], [ 151.170272827148438, -2.901109933853093 ], [ 151.142501831054915, -2.904444932937565 ], [ 151.096664428710938, -2.841871023178044 ], [ 151.026107788085938, -2.829720973968506 ], [ 150.979476928710938, -2.779498100280762 ], [ 150.9244384765625, -2.776110887527352 ], [ 150.903640747070312, -2.757556915283146 ], [ 150.908676147461165, -2.768289089202824 ], [ 150.81182861328125, -2.788510084152165 ], [ 150.719497680664176, -2.751703977584839 ], [ 150.70166015625, -2.731112003326359 ], [ 150.714004516601676, -2.725548982620239 ], [ 150.729095458984375, -2.707887887954655 ], [ 150.786621093750455, -2.738106966018563 ], [ 150.78889465332054, -2.736943960189762 ], [ 150.792221069336279, -2.730278015136662 ], [ 150.789718627929801, -2.717777013778687 ], [ 150.812805175781364, -2.713635921478215 ], [ 150.821350097656364, -2.69060301780695 ], [ 150.87416076660179, -2.700278043746891 ], [ 150.856384277343864, -2.692223072052002 ], [ 150.889724731445312, -2.680834054946899 ], [ 150.860549926757812, -2.670277118682861 ], [ 150.862777709961051, -2.684443950653076 ], [ 150.847503662109489, -2.691111087799072 ], [ 150.856521606445312, -2.682499885559082 ], [ 150.841384887695312, -2.663888931274414 ], [ 150.867218017578125, -2.655832052230835 ], [ 150.869720458984602, -2.640832901000977 ], [ 150.850830078125, -2.648612022399846 ], [ 150.848052978515739, -2.6372230052948 ], [ 150.844451904296989, -2.635277032852059 ], [ 150.822250366211051, -2.649701118469238 ], [ 150.776107788086165, -2.616667985916138 ], [ 150.798828125000455, -2.553205013275146 ] ] ], [ [ [ 149.944442749023438, -2.483125925064087 ], [ 149.943054199218864, -2.483334064483643 ], [ 149.940826416015625, -2.480277061462402 ], [ 149.942230224609602, -2.479861974716187 ], [ 149.944442749023438, -2.483125925064087 ] ] ], [ [ [ 150.513458251953352, -2.483141899108887 ], [ 150.544342041015739, -2.546983003616276 ], [ 150.545761108398551, -2.571979999542179 ], [ 150.48847961425804, -2.479717016220036 ], [ 150.513458251953352, -2.483141899108887 ] ] ], [ [ [ 150.490829467773551, -2.475001096725407 ], [ 150.478057861328239, -2.473889112472534 ], [ 150.48193359375, -2.461244106292725 ], [ 150.49305725097679, -2.465277910232487 ], [ 150.490829467773551, -2.475001096725407 ] ] ], [ [ [ 150.356674194336165, -2.436111927032357 ], [ 150.35861206054733, -2.438055992126408 ], [ 150.358062744140625, -2.439722061157227 ], [ 150.355331420898551, -2.43769192695612 ], [ 150.356674194336165, -2.436111927032357 ] ] ], [ [ [ 150.009246826171989, -2.429126977920532 ], [ 150.001235961914176, -2.435395956039372 ], [ 149.997497558593977, -2.432499885558968 ], [ 150.000839233398551, -2.428745985031128 ], [ 150.009246826171989, -2.429126977920532 ] ] ], [ [ [ 150.447219848632812, -2.433056116104126 ], [ 150.477218627929915, -2.453054904937744 ], [ 150.477081298828125, -2.469585895538216 ], [ 150.432785034179915, -2.425832986831665 ], [ 150.447219848632812, -2.433056116104126 ] ] ], [ [ [ 150.331939697265625, -2.426110982894897 ], [ 150.330551147461165, -2.424444913864079 ], [ 150.332916259765739, -2.42361307144165 ], [ 150.333343505859375, -2.424823999404907 ], [ 150.331939697265625, -2.426110982894897 ] ] ], [ [ [ 150.035278320312614, -2.422498941421509 ], [ 150.038604736328239, -2.425554990768433 ], [ 150.034439086914062, -2.427221059799081 ], [ 150.033340454101562, -2.424998998641968 ], [ 150.035278320312614, -2.422498941421509 ] ] ], [ [ [ 150.007781982421875, -2.422223091125488 ], [ 150.00917053222679, -2.423610925674438 ], [ 150.005004882812614, -2.42638897895813 ], [ 150.003890991211051, -2.423054933547974 ], [ 150.007781982421875, -2.422223091125488 ] ] ], [ [ [ 150.021926879882926, -2.419392108917179 ], [ 150.022033691406591, -2.413003921508789 ], [ 150.023956298828125, -2.412060022354126 ], [ 150.025161743164176, -2.414627075195256 ], [ 150.021926879882926, -2.419392108917179 ] ] ], [ [ [ 150.41749572753929, -2.411943912506104 ], [ 150.42860412597679, -2.420279026031494 ], [ 150.431594848632812, -2.428960084915161 ], [ 150.410827636718864, -2.418055057525635 ], [ 150.41749572753929, -2.411943912506104 ] ] ], [ [ [ 150.040802001953239, -2.406392097473145 ], [ 150.037261962890739, -2.402715921401921 ], [ 150.04365539550804, -2.398663997650146 ], [ 150.045074462890625, -2.400305032730046 ], [ 150.040802001953239, -2.406392097473145 ] ] ], [ [ [ 150.063613891601904, -2.393610954284611 ], [ 150.062088012695654, -2.392918109893799 ], [ 150.063903808593977, -2.391381978988647 ], [ 150.064727783203239, -2.39250111579895 ], [ 150.063613891601904, -2.393610954284611 ] ] ], [ [ [ 150.098968505859602, -2.385445117950383 ], [ 150.093536376953239, -2.381819009780827 ], [ 150.094406127929801, -2.37813496589655 ], [ 150.105102539062727, -2.380673885345459 ], [ 150.098968505859602, -2.385445117950383 ] ] ], [ [ [ 150.238250732422102, -2.378281116485539 ], [ 150.235504150390625, -2.374869108200016 ], [ 150.241775512695312, -2.372113943099976 ], [ 150.24371337890625, -2.375633001327515 ], [ 150.238250732422102, -2.378281116485539 ] ] ], [ [ [ 150.341110229492301, -2.366945028304997 ], [ 150.343612670898779, -2.369167089462223 ], [ 150.342773437500227, -2.370554924011117 ], [ 150.339447021484375, -2.368611097335759 ], [ 150.341110229492301, -2.366945028304997 ] ] ], [ [ [ 150.120635986328239, -2.363054037094116 ], [ 150.125625610351562, -2.366381883621159 ], [ 150.117752075195426, -2.370805978775024 ], [ 150.11427307128929, -2.365875959396249 ], [ 150.120635986328239, -2.363054037094116 ] ] ], [ [ [ 150.202499389648438, -2.366945028304997 ], [ 150.258346557617301, -2.392250061035156 ], [ 150.267669677734489, -2.412111043930054 ], [ 150.340637207031364, -2.43113899230957 ], [ 150.423736572265625, -2.481323003768864 ], [ 150.441345214843864, -2.477108955383244 ], [ 150.43939208984375, -2.558155059814396 ], [ 150.451934814453239, -2.527503013610783 ], [ 150.463516235352017, -2.540751934051514 ], [ 150.438552856445312, -2.61929988861084 ], [ 150.448059082031477, -2.65305590629572 ], [ 150.343399047851676, -2.68022608757019 ], [ 150.374588012695426, -2.66106104850769 ], [ 150.344802856445312, -2.670007944106999 ], [ 150.335586547851676, -2.652400016784668 ], [ 150.315628051757812, -2.672993898391724 ], [ 150.2618408203125, -2.658607959747314 ], [ 150.171951293945654, -2.681008100509644 ], [ 150.099716186523438, -2.61972188949585 ], [ 150.062103271484375, -2.532802104949951 ], [ 150.02166748046875, -2.501667022705078 ], [ 150.010772705078239, -2.513057947158813 ], [ 149.959716796875, -2.503055095672607 ], [ 149.946334838867188, -2.481288909912053 ], [ 149.959121704101562, -2.452316999435425 ], [ 149.970306396484375, -2.491887092590275 ], [ 149.998748779296989, -2.452547073364144 ], [ 150.048049926757926, -2.434443950653019 ], [ 150.068603515625, -2.403901100158691 ], [ 150.087570190429915, -2.417203903198242 ], [ 150.10638427734375, -2.39527702331543 ], [ 150.14349365234375, -2.40581107139576 ], [ 150.142776489257812, -2.381387948989868 ], [ 150.167953491210938, -2.390512943267822 ], [ 150.168121337890739, -2.368766069412175 ], [ 150.202499389648438, -2.366945028304997 ] ] ], [ [ [ 150.143585205078125, -2.352658987045288 ], [ 150.140701293945312, -2.34922194480896 ], [ 150.147109985351562, -2.348177909851074 ], [ 150.147216796875227, -2.350845098495427 ], [ 150.143585205078125, -2.352658987045288 ] ] ], [ [ [ 150.308883666992301, -2.340832948684692 ], [ 150.315277099609489, -2.346389055251962 ], [ 150.31166076660179, -2.357222080230713 ], [ 150.301666259765625, -2.347776889801025 ], [ 150.308883666992301, -2.340832948684692 ] ] ], [ [ [ 150.026672363281477, -1.681112051010132 ], [ 150.025711059570312, -1.679587006568909 ], [ 150.0302734375, -1.675554990768376 ], [ 150.03054809570358, -1.677220940589848 ], [ 150.026672363281477, -1.681112051010132 ] ] ], [ [ [ 149.942855834961051, -1.675209045410156 ], [ 149.94500732421875, -1.676390051841736 ], [ 149.943328857422102, -1.678056001663208 ], [ 149.941665649414517, -1.675832986831551 ], [ 149.942855834961051, -1.675209045410156 ] ] ], [ [ [ 149.905273437500114, -1.674792051315251 ], [ 149.909439086914176, -1.678889989852848 ], [ 149.904449462890852, -1.682778000831604 ], [ 149.901672363281364, -1.678123950958195 ], [ 149.905273437500114, -1.674792051315251 ] ] ], [ [ [ 149.945831298828352, -1.673784971237183 ], [ 149.935607910156364, -1.675181984901428 ], [ 149.938430786132926, -1.691898941993713 ], [ 149.911117553711165, -1.679165959358215 ], [ 149.919967651367301, -1.667919993400574 ], [ 149.907058715820312, -1.650210976600647 ], [ 149.945831298828352, -1.673784971237183 ] ] ], [ [ [ 150.673889160156477, -1.653056025505009 ], [ 150.670562744140625, -1.650833964347783 ], [ 150.671951293945426, -1.644999027252197 ], [ 150.676376342773892, -1.648064017295724 ], [ 150.673889160156477, -1.653056025505009 ] ] ], [ [ [ 149.945831298828352, -1.673784971237183 ], [ 149.955932617187614, -1.622807025909367 ], [ 149.978683471679801, -1.638296008110046 ], [ 149.982666015625227, -1.667070031166077 ], [ 150.026458740234375, -1.670377016067391 ], [ 150.006393432617529, -1.688133955001831 ], [ 149.945831298828352, -1.673784971237183 ] ] ], [ [ [ 149.61396789550804, -1.574331998825073 ], [ 149.612243652343977, -1.573912978172245 ], [ 149.614318847656364, -1.572103023528939 ], [ 149.615005493164404, -1.572939991950989 ], [ 149.61396789550804, -1.574331998825073 ] ] ], [ [ [ 149.573150634765852, -1.566715002059937 ], [ 149.601455688476676, -1.574934005737305 ], [ 149.59980773925804, -1.58482301235199 ], [ 149.58346557617233, -1.586493968963623 ], [ 149.573150634765852, -1.566715002059937 ] ] ], [ [ [ 149.589950561523892, -1.560682058334294 ], [ 149.588165283203125, -1.55747997760767 ], [ 149.594253540039062, -1.553442001342773 ], [ 149.596267700195312, -1.55594897270197 ], [ 149.589950561523892, -1.560682058334294 ] ] ], [ [ [ 149.622909545898551, -1.554275989532471 ], [ 149.638275146484716, -1.559429049491825 ], [ 149.661239624023551, -1.595152020454407 ], [ 149.602478027343977, -1.557618975639343 ], [ 149.622909545898551, -1.554275989532471 ] ] ], [ [ [ 149.659591674804688, -1.55692195892334 ], [ 149.655014038085938, -1.55594897270197 ], [ 149.656951904296989, -1.550237059593087 ], [ 149.661666870117642, -1.553509950637817 ], [ 149.659591674804688, -1.55692195892334 ] ] ], [ [ [ 149.645599365234489, -1.545642018318119 ], [ 149.638549804687614, -1.547868967056274 ], [ 149.654953002929801, -1.531016945838928 ], [ 149.656326293945767, -1.536241054534855 ], [ 149.645599365234489, -1.545642018318119 ] ] ], [ [ [ 149.66290283203125, -1.534500002861023 ], [ 149.659591674804688, -1.530042052268982 ], [ 149.662216186523665, -1.525864005088749 ], [ 149.66595458984375, -1.529207944869995 ], [ 149.66290283203125, -1.534500002861023 ] ] ], [ [ [ 149.586776733398779, -1.52642202377308 ], [ 149.587738037109375, -1.529485940933228 ], [ 149.57916259765625, -1.52642202377308 ], [ 149.581787109375114, -1.523776054382267 ], [ 149.586776733398779, -1.52642202377308 ] ] ], [ [ [ 149.657302856445312, -1.518831014633122 ], [ 149.657714843750114, -1.512217044830265 ], [ 149.662490844726676, -1.510822057723999 ], [ 149.660003662109489, -1.517508983611947 ], [ 149.657302856445312, -1.518831014633122 ] ] ], [ [ [ 149.604003906250227, -1.519286036491394 ], [ 149.596282958984489, -1.515979051589966 ], [ 149.593063354492301, -1.50988495349884 ], [ 149.603378295898438, -1.511904001235962 ], [ 149.604003906250227, -1.519286036491394 ] ] ], [ [ [ 149.585311889648665, -1.50347805023182 ], [ 149.581298828125, -1.502156019210815 ], [ 149.579849243164176, -1.499022960662842 ], [ 149.583236694336051, -1.49804699420929 ], [ 149.585311889648665, -1.50347805023182 ] ] ], [ [ [ 149.568923950195426, -1.319321990013066 ], [ 149.681243896484375, -1.387773990631047 ], [ 149.717376708984489, -1.492020964622498 ], [ 149.748519897461279, -1.526491045951786 ], [ 149.721603393554801, -1.535683035850468 ], [ 149.705474853515852, -1.521476984023991 ], [ 149.690383911132812, -1.542366981506348 ], [ 149.658172607422102, -1.495015978813115 ], [ 149.653839111328352, -1.517369985580444 ], [ 149.626296997070312, -1.521198987960759 ], [ 149.549392700195654, -1.451979041099548 ], [ 149.514022827148665, -1.440140962600651 ], [ 149.50537109375, -1.418346047401371 ], [ 149.546142578125114, -1.357691049575692 ], [ 149.54226684570358, -1.318972945213318 ], [ 149.568923950195426, -1.319321990013066 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-NPP", "NAME_1": "Oro" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 149.442687988281477, -9.587521553039494 ], [ 149.441848754882812, -9.588834762573242 ], [ 149.4403076171875, -9.586763381957951 ], [ 149.4417724609375, -9.58648490905756 ], [ 149.442687988281477, -9.587521553039494 ] ] ], [ [ [ 148.892501831055029, -9.0644273757934 ], [ 148.889999389648551, -9.063114166259766 ], [ 148.8936767578125, -9.059547424316349 ], [ 148.893814086914176, -9.06058406829834 ], [ 148.892501831055029, -9.0644273757934 ] ] ], [ [ [ 148.325134277343977, -8.6109361648559 ], [ 148.326553344726562, -8.615341186523438 ], [ 148.32594299316429, -8.616570472717228 ], [ 148.322753906250114, -8.611220359802246 ], [ 148.325134277343977, -8.6109361648559 ] ] ], [ [ [ 148.237091064453125, -8.485573768615723 ], [ 148.23583984375, -8.486109733581543 ], [ 148.234268188476676, -8.484086036682129 ], [ 148.237213134765739, -8.483443260192871 ], [ 148.237091064453125, -8.485573768615723 ] ] ], [ [ [ 148.235290527343977, -8.48278903961176 ], [ 148.235000610351562, -8.481403350830021 ], [ 148.236129760742301, -8.480833053588867 ], [ 148.23638916015625, -8.48277473449707 ], [ 148.235290527343977, -8.48278903961176 ] ] ], [ [ [ 148.009185791015739, -8.059800148010254 ], [ 148.004730224609602, -8.057711601257324 ], [ 148.003890991210938, -8.0543212890625 ], [ 148.008071899414062, -8.056467056274414 ], [ 148.009185791015739, -8.059800148010254 ] ] ], [ [ [ 147.999374389648551, -8.05192661285389 ], [ 148.000839233398438, -8.052242279052734 ], [ 148.002944946289062, -8.05631160736084 ], [ 147.99763488769554, -8.053241729736328 ], [ 147.999374389648551, -8.05192661285389 ] ] ], [ [ [ 147.281707763671875, -8.004035949707031 ], [ 147.939407348632812, -8.005334854125977 ], [ 147.961044311523665, -8.010536193847656 ], [ 147.994445800781477, -8.072220802307072 ], [ 147.994995117187727, -8.055277824401799 ], [ 148.011108398437614, -8.0625 ], [ 148.041946411133267, -8.05341625213623 ], [ 148.053329467773665, -8.062778472900391 ], [ 148.08082580566429, -8.055556297302246 ], [ 148.101943969726562, -8.06500053405756 ], [ 148.123886108398438, -8.056112289428654 ], [ 148.119445800781364, -8.077220916748047 ], [ 148.133056640625227, -8.078055381774902 ], [ 148.150558471679688, -8.134167671203613 ], [ 148.139999389648551, -8.148611068725586 ], [ 148.165496826171989, -8.175798416137638 ], [ 148.1663818359375, -8.222499847412053 ], [ 148.206115722656477, -8.305554389953613 ], [ 148.205001831054915, -8.391944885253906 ], [ 148.225006103515739, -8.428334236144963 ], [ 148.22389221191429, -8.476388931274414 ], [ 148.23611450195358, -8.488887786865234 ], [ 148.230560302734602, -8.513055801391602 ], [ 148.216659545898892, -8.514165878295842 ], [ 148.222778320312614, -8.556111335754338 ], [ 148.279449462890739, -8.611666679382267 ], [ 148.302215576171875, -8.61944580078125 ], [ 148.342773437500114, -8.618056297302189 ], [ 148.437225341796875, -8.680277824401855 ], [ 148.473052978515739, -8.741666793823242 ], [ 148.474716186523665, -8.823332786560059 ], [ 148.493057250976562, -8.87944507598877 ], [ 148.484161376953125, -8.896665573120117 ], [ 148.508895874023438, -8.898429870605469 ], [ 148.50555419921875, -8.919721603393555 ], [ 148.52333068847679, -8.914164543151799 ], [ 148.505966186523551, -8.94679069519043 ], [ 148.52777099609375, -8.956945419311523 ], [ 148.52603149414108, -9.002663612365723 ], [ 148.540557861328125, -9.024168014526367 ], [ 148.610000610351676, -9.08777904510498 ], [ 148.761947631836165, -9.112221717834359 ], [ 148.742218017578125, -9.113887786865178 ], [ 148.743331909179801, -9.117222785949707 ], [ 148.746948242187614, -9.117831230163574 ], [ 148.878326416015739, -9.079443931579533 ], [ 148.895004272460938, -9.088889122009221 ], [ 148.882217407226562, -9.06944465637207 ], [ 148.899993896484375, -9.067501068115234 ], [ 148.90138244628929, -9.047221183776799 ], [ 149.015609741211051, -9.061659812927246 ], [ 149.032562255859602, -9.048947334289551 ], [ 149.065719604492188, -9.055769920349121 ], [ 149.061676025390739, -9.042839050292912 ], [ 149.088058471679688, -9.062223434448242 ], [ 149.08082580566429, -9.022500038146973 ], [ 149.096389770507926, -9.034167289733887 ], [ 149.106399536132926, -9.00597953796381 ], [ 149.13812255859375, -8.989233016967773 ], [ 149.141937255859375, -9.031109809875488 ], [ 149.161117553711165, -9.013054847717285 ], [ 149.167221069336165, -9.031109809875488 ], [ 149.17608642578125, -9.011726379394531 ], [ 149.187973022460938, -9.027424812316838 ], [ 149.18367004394554, -9.009914398193359 ], [ 149.20440673828125, -9.003679275512695 ], [ 149.225280761718864, -9.014445304870605 ], [ 149.234222412109602, -9.002113342285099 ], [ 149.233978271484602, -9.010290145873967 ], [ 149.237503051757812, -9.01500129699707 ], [ 149.249862670898665, -8.997082710266056 ], [ 149.239410400390625, -9.038318634033203 ], [ 149.257766723632812, -9.010821342468262 ], [ 149.259445190429801, -9.02944374084467 ], [ 149.269027709960938, -9.007781028747559 ], [ 149.278610229492415, -9.012777328491097 ], [ 149.269439697265625, -9.037222862243652 ], [ 149.293807983398779, -9.014470100402718 ], [ 149.315750122070312, -9.038761138915959 ], [ 149.30305480957054, -9.048055648803654 ], [ 149.319442749023551, -9.055000305175781 ], [ 149.290695190429801, -9.081378936767521 ], [ 149.326065063476562, -9.062788009643555 ], [ 149.328887939453239, -9.078612327575684 ], [ 149.302169799804801, -9.084284782409668 ], [ 149.286941528320654, -9.093610763549805 ], [ 149.32281494140625, -9.085396766662541 ], [ 149.315750122070312, -9.106609344482422 ], [ 149.272506713867415, -9.111109733581486 ], [ 149.328048706054915, -9.112221717834359 ], [ 149.328964233398665, -9.134897232055664 ], [ 149.297225952148551, -9.13416576385498 ], [ 149.323455810546989, -9.142623901367188 ], [ 149.317413330078125, -9.156246185302678 ], [ 149.301666259765625, -9.14888858795166 ], [ 149.313049316406364, -9.165555953979379 ], [ 149.285675048828352, -9.154644012451172 ], [ 149.291625976562727, -9.176204681396484 ], [ 149.272216796875, -9.162825584411621 ], [ 149.260833740234375, -9.173054695129338 ], [ 149.223052978515625, -9.3102769851684 ], [ 149.180297851562614, -9.339536666870117 ], [ 149.182220458984489, -9.401665687561035 ], [ 149.2386474609375, -9.497957229614258 ], [ 149.357604980468977, -9.518432617187443 ], [ 149.380828857421875, -9.548054695129395 ], [ 149.436813354492188, -9.571563720703068 ], [ 149.441925048828352, -9.597958564758301 ], [ 149.087219238281364, -9.707134246826172 ], [ 148.991210937500227, -9.702835083007812 ], [ 148.943618774414404, -9.79483509063715 ], [ 148.972106933593977, -9.867136001586914 ], [ 148.970214843750114, -9.905334472656193 ], [ 148.846710205078239, -9.940635681152287 ], [ 148.809005737304688, -9.97723388671875 ], [ 148.780319213867301, -9.944234848022461 ], [ 148.709014892578466, -9.936736106872559 ], [ 148.565719604492301, -9.875433921813965 ], [ 148.444305419921875, -9.757035255432129 ], [ 148.392608642578125, -9.741435050964355 ], [ 148.353713989257812, -9.753334045410099 ], [ 148.245117187500114, -9.746733665466252 ], [ 148.214508056640852, -9.664933204650879 ], [ 148.104415893554688, -9.610434532165471 ], [ 148.043319702148551, -9.556035995483398 ], [ 148.026611328125, -9.511835098266488 ], [ 148.052017211914176, -9.467233657836914 ], [ 148.053207397461051, -9.431235313415527 ], [ 148.033309936523665, -9.390434265136719 ], [ 147.983917236328239, -9.353534698486328 ], [ 147.986114501953239, -9.31363391876215 ], [ 147.955215454101676, -9.291033744812012 ], [ 147.90911865234375, -9.293135643005371 ], [ 147.873718261719205, -9.274435043334904 ], [ 147.827117919922102, -9.169335365295353 ], [ 147.747314453125114, -9.1651353836059 ], [ 147.693008422851562, -9.043934822082463 ], [ 147.635208129882812, -8.977034568786564 ], [ 147.553619384765739, -8.95063400268549 ], [ 147.542419433593864, -8.899934768676701 ], [ 147.501617431640625, -8.873633384704533 ], [ 147.500411987304801, -8.827235221862793 ], [ 147.46051025390625, -8.789134025573674 ], [ 147.445205688476904, -8.723333358764592 ], [ 147.633407592773551, -8.565534591674805 ], [ 147.646713256836165, -8.532934188842773 ], [ 147.461715698242415, -8.348434448242188 ], [ 147.366012573242188, -8.359833717346135 ], [ 147.004119873046989, -8.004434585571232 ], [ 147.161712646484489, -8.005234718322754 ], [ 147.203613281250227, -8.032334327697754 ], [ 147.281707763671875, -8.004035949707031 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-SAN", "NAME_1": "Sandaun" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 142.489761352539062, -3.158368110656738 ], [ 142.490829467773438, -3.160964012145882 ], [ 142.486389160156477, -3.158890008926392 ], [ 142.486862182617529, -3.157700061798096 ], [ 142.489761352539062, -3.158368110656738 ] ] ], [ [ [ 142.487777709960938, -3.151667118072453 ], [ 142.480895996093864, -3.143654108047429 ], [ 142.489501953125114, -3.139763116836491 ], [ 142.490280151367301, -3.149445056915226 ], [ 142.487777709960938, -3.151667118072453 ] ] ], [ [ [ 142.474166870117301, -3.122776985168457 ], [ 142.474166870117301, -3.128055095672551 ], [ 142.463607788085938, -3.132499933242741 ], [ 142.470550537109602, -3.12166690826416 ], [ 142.474166870117301, -3.122776985168457 ] ] ], [ [ [ 142.398025512695312, -3.116327047347966 ], [ 142.401672363281477, -3.123610973358154 ], [ 142.396392822265739, -3.128055095672551 ], [ 142.393035888671875, -3.12077093124384 ], [ 142.398025512695312, -3.116327047347966 ] ] ], [ [ [ 142.081344604492301, -3.031605005264225 ], [ 142.079971313476676, -3.030895948410034 ], [ 142.082305908203239, -3.028857946395874 ], [ 142.082717895507812, -3.029721975326481 ], [ 142.081344604492301, -3.031605005264225 ] ] ], [ [ [ 142.085830688476676, -3.031666040420532 ], [ 142.082504272461279, -3.027777910232487 ], [ 142.086105346679801, -3.025000095367432 ], [ 142.086944580078125, -3.026112079620304 ], [ 142.085830688476676, -3.031666040420532 ] ] ], [ [ [ 142.076385498046989, -3.019444942474365 ], [ 142.083053588867301, -3.023890018463078 ], [ 142.080001831054801, -3.028333902358895 ], [ 142.076385498046989, -3.024444103240967 ], [ 142.076385498046989, -3.019444942474365 ] ] ], [ [ [ 141.328796386718977, -2.696196079254094 ], [ 141.329071044921989, -2.697295904159546 ], [ 141.327682495117415, -2.697902917861882 ], [ 141.327697753906705, -2.696474075317326 ], [ 141.328796386718977, -2.696196079254094 ] ] ], [ [ [ 141.038330078125227, -2.604703903198242 ], [ 141.155746459960938, -2.6372230052948 ], [ 141.204788208007812, -2.632430076599064 ], [ 141.232589721680029, -2.656791925430298 ], [ 141.278076171875227, -2.661278963088989 ], [ 141.269241333007812, -2.676496982574463 ], [ 141.287506103515739, -2.688056945800668 ], [ 141.30555725097679, -2.66833305358881 ], [ 141.307220458984375, -2.694444894790593 ], [ 141.33917236328125, -2.713263988494873 ], [ 141.44667053222679, -2.739166021347046 ], [ 141.439727783203466, -2.750555038452092 ], [ 141.448883056640966, -2.741667032241821 ], [ 141.635345458984602, -2.841320037841797 ], [ 141.824752807617642, -2.915026903152409 ], [ 141.875839233398665, -2.971874952316284 ], [ 141.98638916015625, -2.962013959884587 ], [ 142.011535644531364, -2.97252893447876 ], [ 142.080001831054801, -3.015554904937744 ], [ 142.058334350585938, -3.021943092346135 ], [ 142.074722290039062, -3.026112079620304 ], [ 142.067779541015625, -3.050002098083496 ], [ 142.083618164062614, -3.06805491447443 ], [ 142.134445190429688, -3.060208082199097 ], [ 142.092498779297102, -3.032222032546997 ], [ 142.085006713867188, -3.020833015441895 ], [ 142.173614501953239, -3.08916711807251 ], [ 142.345550537109375, -3.123332977294922 ], [ 142.354721069335938, -3.146389007568303 ], [ 142.532775878906364, -3.232223033905029 ], [ 142.625274658203239, -3.246943950653076 ], [ 142.861663818359375, -3.327778100967407 ], [ 143.041671752929688, -3.364166975021305 ], [ 143.096572875977017, -3.357927083969116 ], [ 143.0841064453125, -3.529634952545109 ], [ 143.039215087890739, -3.538434028625488 ], [ 142.958419799804688, -3.495135068893376 ], [ 142.856719970703125, -3.471934080123901 ], [ 142.772308349609602, -3.401532888412476 ], [ 142.695709228515739, -3.444534063339177 ], [ 142.619613647461279, -3.44013500213623 ], [ 142.642013549804801, -3.516834974288884 ], [ 142.615615844726562, -3.555334091186523 ], [ 142.609619140625227, -3.667733907699528 ], [ 142.638519287109375, -3.792335033416748 ], [ 142.628906250000114, -3.90603399276722 ], [ 142.616714477539062, -3.920536041259766 ], [ 142.539718627929688, -3.93013596534729 ], [ 142.528320312500227, -4.05703592300415 ], [ 141.834716796875114, -4.059733867645264 ], [ 141.772720336914176, -4.025834083557129 ], [ 141.762817382812614, -4.00083398818964 ], [ 141.71630859375, -3.99073600769043 ], [ 141.340118408203239, -4.259035110473633 ], [ 141.339218139648438, -4.574234962463322 ], [ 141.357315063476676, -4.609535217285156 ], [ 142.31640625, -4.617634773254338 ], [ 142.321914672851562, -5.052135944366455 ], [ 142.290512084961165, -5.109734058380013 ], [ 142.320816040039176, -5.198235034942513 ], [ 142.29450988769554, -5.332633972167969 ], [ 142.187911987305142, -5.320334911346436 ], [ 142.129913330078352, -5.370535850524902 ], [ 142.110641479492415, -5.378980159759408 ], [ 142.122573852539062, -5.370335102081299 ], [ 140.999710083007812, -4.993766784667969 ], [ 141.000167846679801, -2.606300115585327 ], [ 141.038330078125227, -2.604703903198242 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-SHM", "NAME_1": "Southern Highlands" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 143.884918212890739, -5.975834846496582 ], [ 143.883117675781477, -6.048635959625244 ], [ 144.005416870117415, -5.999034881591797 ], [ 144.559814453125, -6.36993408203125 ], [ 144.542205810546989, -6.433334827423039 ], [ 144.438613891601562, -6.460936069488469 ], [ 144.423812866210938, -6.489834785461426 ], [ 144.424713134765739, -6.552534103393555 ], [ 144.539215087890625, -6.581234931945744 ], [ 144.557907104492188, -6.60433387756342 ], [ 144.557006835937727, -6.647833824157715 ], [ 144.688110351562614, -6.705434799194279 ], [ 144.626510620117301, -6.729135036468506 ], [ 143.934707641601676, -6.822734832763672 ], [ 142.665008544922216, -6.823635101318303 ], [ 142.631607055664176, -6.809134960174504 ], [ 142.627212524414176, -6.179833889007568 ], [ 142.683517456054688, -6.18023490905756 ], [ 142.886520385742415, -6.242636203765812 ], [ 143.077011108398438, -6.359333992004338 ], [ 143.080413818359489, -6.30323600769043 ], [ 143.16120910644554, -6.293034076690617 ], [ 143.17181396484375, -6.165235996246338 ], [ 143.376007080078239, -6.155035018920898 ], [ 143.375808715820767, -6.094034194946232 ], [ 143.417007446289517, -6.093635082244873 ], [ 143.394012451171875, -6.070633888244572 ], [ 143.396316528320312, -5.909033775329533 ], [ 143.528015136719205, -5.975735187530461 ], [ 143.719818115234375, -5.90273380279541 ], [ 143.867706298828352, -5.950634956359863 ], [ 143.884918212890739, -5.975834846496582 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-WBK", "NAME_1": "West New Britain" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 149.502227783203239, -6.320833206176701 ], [ 149.504714965820312, -6.323332786560002 ], [ 149.500549316406364, -6.325832843780461 ], [ 149.49945068359375, -6.322776794433537 ], [ 149.502227783203239, -6.320833206176701 ] ] ], [ [ [ 149.873336791992301, -6.316666126251221 ], [ 149.878890991211165, -6.320833206176701 ], [ 149.8719482421875, -6.324722766876221 ], [ 149.86860656738304, -6.320833206176701 ], [ 149.873336791992301, -6.316666126251221 ] ] ], [ [ [ 149.809921264648551, -6.314436912536621 ], [ 149.813629150390852, -6.31879711151123 ], [ 149.812271118164062, -6.320236206054688 ], [ 149.806503295898779, -6.318531036376953 ], [ 149.809921264648551, -6.314436912536621 ] ] ], [ [ [ 149.890777587890739, -6.314414978027344 ], [ 149.88972473144554, -6.314102172851506 ], [ 149.890136718750227, -6.313061237335148 ], [ 149.891220092773438, -6.313406944274846 ], [ 149.890777587890739, -6.314414978027344 ] ] ], [ [ [ 149.790557861328239, -6.306389808654728 ], [ 149.797775268554688, -6.311388015747013 ], [ 149.79402160644554, -6.316894054412842 ], [ 149.783615112305029, -6.313888072967472 ], [ 149.790557861328239, -6.306389808654728 ] ] ], [ [ [ 149.504714965820312, -6.311944007873478 ], [ 149.503326416015852, -6.306667804717961 ], [ 149.5050048828125, -6.300833225250244 ], [ 149.507217407226676, -6.305277824401855 ], [ 149.504714965820312, -6.311944007873478 ] ] ], [ [ [ 149.744842529296989, -6.303383827209473 ], [ 149.743316650390739, -6.302134990692139 ], [ 149.744293212890739, -6.300397872924748 ], [ 149.745330810546875, -6.30310583114624 ], [ 149.744842529296989, -6.303383827209473 ] ] ], [ [ [ 149.824737548828352, -6.306299209594727 ], [ 149.824661254882812, -6.299953937530518 ], [ 149.828964233398438, -6.298850059509277 ], [ 149.830352783203125, -6.3032932281493 ], [ 149.824737548828352, -6.306299209594727 ] ] ], [ [ [ 149.882781982421989, -6.297704219818115 ], [ 149.883956909179688, -6.300412178039551 ], [ 149.88117980957054, -6.30082893371582 ], [ 149.880905151367188, -6.29749679565424 ], [ 149.882781982421989, -6.297704219818115 ] ] ], [ [ [ 150.307113647461392, -6.297177791595345 ], [ 150.309082031250114, -6.300496101379338 ], [ 150.319091796875114, -6.302050113677922 ], [ 150.307662963867415, -6.302923202514648 ], [ 150.307113647461392, -6.297177791595345 ] ] ], [ [ [ 149.904876708984375, -6.297369003295842 ], [ 149.91000366210983, -6.29999923706049 ], [ 149.901947021484489, -6.307499885559082 ], [ 149.901107788086279, -6.298333168029785 ], [ 149.904876708984375, -6.297369003295842 ] ] ], [ [ [ 149.926895141601562, -6.299164772033635 ], [ 149.926071166992301, -6.299718856811523 ], [ 149.923339843750227, -6.298333168029785 ], [ 149.926666259765966, -6.296111106872559 ], [ 149.926895141601562, -6.299164772033635 ] ] ], [ [ [ 149.74000549316429, -6.296249866485596 ], [ 149.742492675781364, -6.296667098999023 ], [ 149.74305725097679, -6.297501087188664 ], [ 149.738891601562727, -6.29888916015625 ], [ 149.74000549316429, -6.296249866485596 ] ] ], [ [ [ 150.0645751953125, -6.298061847686768 ], [ 150.062911987304915, -6.297505855560303 ], [ 150.062911987304915, -6.295980930328369 ], [ 150.064651489257926, -6.296257019042912 ], [ 150.0645751953125, -6.298061847686768 ] ] ], [ [ [ 149.732711791992188, -6.288541793823242 ], [ 149.73138427734375, -6.288887977600098 ], [ 149.731109619140739, -6.287197113037053 ], [ 149.732849121093864, -6.287154197692871 ], [ 149.732711791992188, -6.288541793823242 ] ] ], [ [ [ 150.073333740234489, -6.286665916442871 ], [ 150.080978393554688, -6.291454792022705 ], [ 150.078887939453125, -6.311944007873478 ], [ 150.067703247070426, -6.298132896423283 ], [ 150.073333740234489, -6.286665916442871 ] ] ], [ [ [ 150.300735473632812, -6.286299228668156 ], [ 150.299621582031477, -6.28715181350708 ], [ 150.298522949218977, -6.285764217376709 ], [ 150.299606323242188, -6.285764217376709 ], [ 150.300735473632812, -6.286299228668156 ] ] ], [ [ [ 150.329299926757926, -6.285346984863281 ], [ 150.32666015625, -6.29444503784174 ], [ 150.315490722656477, -6.293790817260742 ], [ 150.320281982421989, -6.285277843475285 ], [ 150.329299926757926, -6.285346984863281 ] ] ], [ [ [ 149.966659545898551, -6.283094882965088 ], [ 149.970275878906705, -6.28916597366333 ], [ 149.943603515625, -6.303334236144963 ], [ 149.946670532226676, -6.296945095062256 ], [ 149.966659545898551, -6.283094882965088 ] ] ], [ [ [ 150.310699462890739, -6.289976119995117 ], [ 150.30323791503929, -6.297701835632324 ], [ 150.282135009765739, -6.29046106338501 ], [ 150.311248779297102, -6.281607151031494 ], [ 150.310699462890739, -6.289976119995117 ] ] ], [ [ [ 150.294097900390739, -6.281302928924561 ], [ 150.296295166015739, -6.28272819519043 ], [ 150.29632568359375, -6.283266067504769 ], [ 150.293792724609375, -6.283266067504769 ], [ 150.294097900390739, -6.281302928924561 ] ] ], [ [ [ 149.979797363281477, -6.28113222122181 ], [ 149.977844238281477, -6.28029823303217 ], [ 149.977569580078239, -6.279326915740967 ], [ 149.979446411132926, -6.279883861541748 ], [ 149.979797363281477, -6.28113222122181 ] ] ], [ [ [ 149.879440307617301, -6.277221202850342 ], [ 149.884719848632812, -6.283055782318058 ], [ 149.869171142578352, -6.281112194061279 ], [ 149.874725341796989, -6.280000209808293 ], [ 149.879440307617301, -6.277221202850342 ] ] ], [ [ [ 150.281555175781705, -6.277139186859074 ], [ 150.284347534179688, -6.2777161598205 ], [ 150.283538818359375, -6.281045913696232 ], [ 150.279907226562841, -6.278785228729191 ], [ 150.281555175781705, -6.277139186859074 ] ] ], [ [ [ 150.276107788085938, -6.279444217681828 ], [ 150.281112670898665, -6.285151004791203 ], [ 150.281021118164176, -6.28715181350708 ], [ 150.26722717285179, -6.280834197997933 ], [ 150.276107788085938, -6.279444217681828 ] ] ], [ [ [ 150.39971923828125, -6.27972221374506 ], [ 150.393325805664517, -6.280556201934758 ], [ 150.405548095703239, -6.274445056915226 ], [ 150.404724121093864, -6.278056144714355 ], [ 150.39971923828125, -6.27972221374506 ] ] ], [ [ [ 150.312683105468864, -6.274098873138314 ], [ 150.316284179687614, -6.276856899261418 ], [ 150.316314697265739, -6.277688980102539 ], [ 150.313232421875114, -6.277966976165771 ], [ 150.312683105468864, -6.274098873138314 ] ] ], [ [ [ 150.403060913086051, -6.274721145629883 ], [ 150.398895263671989, -6.277221202850342 ], [ 150.39361572265625, -6.275833129882812 ], [ 150.401672363281364, -6.273055076599064 ], [ 150.403060913086051, -6.274721145629883 ] ] ], [ [ [ 149.930557250976676, -6.2754869461059 ], [ 149.929519653320426, -6.275140762329045 ], [ 149.928329467773551, -6.273197174072209 ], [ 149.929794311523551, -6.273475170135441 ], [ 149.930557250976676, -6.2754869461059 ] ] ], [ [ [ 150.409454345703125, -6.273609161376953 ], [ 150.410827636718864, -6.273333072662297 ], [ 150.41139221191429, -6.273889064788762 ], [ 150.409439086914062, -6.274999141693115 ], [ 150.409454345703125, -6.273609161376953 ] ] ], [ [ [ 149.926666259765966, -6.271667003631478 ], [ 149.929168701171875, -6.276525974273682 ], [ 149.92242431640625, -6.276803970336914 ], [ 149.924926757812614, -6.272572040557861 ], [ 149.926666259765966, -6.271667003631478 ] ] ], [ [ [ 150.401275634765852, -6.271615028381348 ], [ 150.400451660156591, -6.272994041442871 ], [ 150.397949218750114, -6.272690773010254 ], [ 150.398223876953352, -6.271596908569279 ], [ 150.401275634765852, -6.271615028381348 ] ] ], [ [ [ 150.298278808593977, -6.272731781005859 ], [ 150.296569824218977, -6.27102518081665 ], [ 150.296539306640625, -6.269637107849064 ], [ 150.297988891601562, -6.271010875701904 ], [ 150.298278808593977, -6.272731781005859 ] ] ], [ [ [ 150.029159545898665, -6.268610954284668 ], [ 150.030838012695312, -6.270277023315373 ], [ 150.028060913086165, -6.272221088409424 ], [ 150.026382446289062, -6.269722938537598 ], [ 150.029159545898665, -6.268610954284668 ] ] ], [ [ [ 149.964752197265739, -6.271276950836182 ], [ 149.963058471679688, -6.269722938537598 ], [ 149.963790893555142, -6.267808914184513 ], [ 149.965591430664062, -6.269279003143254 ], [ 149.964752197265739, -6.271276950836182 ] ] ], [ [ [ 150.305618286132812, -6.269581794738713 ], [ 150.30215454101608, -6.270275115966797 ], [ 150.299789428710938, -6.266528129577637 ], [ 150.301040649414062, -6.266042232513428 ], [ 150.305618286132812, -6.269581794738713 ] ] ], [ [ [ 150.419036865234489, -6.263833999633789 ], [ 150.416259765625114, -6.268287181854248 ], [ 150.41462707519554, -6.268270969390812 ], [ 150.415695190429801, -6.265494823455811 ], [ 150.419036865234489, -6.263833999633789 ] ] ], [ [ [ 150.324722290039176, -6.25972223281849 ], [ 150.328231811523665, -6.261139869689941 ], [ 150.325561523437727, -6.265554904937744 ], [ 150.322692871093977, -6.263428211212158 ], [ 150.324722290039176, -6.25972223281849 ] ] ], [ [ [ 150.429565429687955, -6.259695053100529 ], [ 150.42988586425804, -6.260779857635441 ], [ 150.436798095703352, -6.259915828704834 ], [ 150.437072753906591, -6.260779857635441 ], [ 150.424621582031364, -6.262712001800537 ], [ 150.429565429687955, -6.259695053100529 ] ] ], [ [ [ 150.447357177734489, -6.259389877319279 ], [ 150.446258544921875, -6.262184143066406 ], [ 150.441574096679915, -6.262444019317627 ], [ 150.44209289550804, -6.260221004486084 ], [ 150.447357177734489, -6.259389877319279 ] ] ], [ [ [ 150.492782592773438, -6.265000820159912 ], [ 150.488052368164062, -6.265832901000977 ], [ 150.490554809570426, -6.258887767791634 ], [ 150.491668701171875, -6.25972223281849 ], [ 150.492782592773438, -6.265000820159912 ] ] ], [ [ [ 149.552185058594205, -6.254168033599797 ], [ 149.562210083007812, -6.26439189910883 ], [ 149.562210083007812, -6.273344993591252 ], [ 149.549743652343864, -6.26226615905756 ], [ 149.552185058594205, -6.254168033599797 ] ] ], [ [ [ 150.475280761718977, -6.253612041473332 ], [ 150.467773437500114, -6.255556106567383 ], [ 150.466110229492188, -6.249443054199162 ], [ 150.472503662109375, -6.247776985168457 ], [ 150.475280761718977, -6.253612041473332 ] ] ], [ [ [ 149.542465209961051, -6.238900184631348 ], [ 149.549423217773438, -6.24778223037714 ], [ 149.546707153320426, -6.252501964569092 ], [ 149.539169311523551, -6.245041847229004 ], [ 149.542465209961051, -6.238900184631348 ] ] ], [ [ [ 149.538055419922102, -6.222588062286377 ], [ 149.544158935547102, -6.229252815246525 ], [ 149.540267944335938, -6.235361099243107 ], [ 149.534713745117188, -6.2305650711059 ], [ 149.538055419922102, -6.222588062286377 ] ] ], [ [ [ 148.913467407226676, -6.1806960105896 ], [ 148.912780761718977, -6.178055763244629 ], [ 148.918441772461279, -6.177105903625488 ], [ 148.915832519531477, -6.178194999694711 ], [ 148.913467407226676, -6.1806960105896 ] ] ], [ [ [ 148.928329467773551, -6.177639007568303 ], [ 148.926116943359375, -6.178334236144963 ], [ 148.924301147461051, -6.177221775054875 ], [ 148.928329467773551, -6.176805019378605 ], [ 148.928329467773551, -6.177639007568303 ] ] ], [ [ [ 148.954025268554915, -6.179027080535889 ], [ 148.945831298828352, -6.185554981231633 ], [ 148.929992675781477, -6.177221775054875 ], [ 148.956253051757812, -6.170278072357178 ], [ 148.954025268554915, -6.179027080535889 ] ] ], [ [ [ 149.043609619140625, -6.167221069335881 ], [ 149.049728393554915, -6.178055763244629 ], [ 149.048889160156364, -6.185000896453857 ], [ 149.038604736328466, -6.179443836212101 ], [ 149.043609619140625, -6.167221069335881 ] ] ], [ [ [ 150.559997558593977, -6.166388988494873 ], [ 150.562225341796875, -6.168055057525578 ], [ 150.560211181640852, -6.170070171356144 ], [ 150.558334350585938, -6.16833305358881 ], [ 150.559997558593977, -6.166388988494873 ] ] ], [ [ [ 149.014144897460938, -6.159199237823486 ], [ 149.028839111328125, -6.167216777801457 ], [ 149.02937316894554, -6.169651031494141 ], [ 149.01519775390625, -6.166903972625732 ], [ 149.014144897460938, -6.159199237823486 ] ] ], [ [ [ 149.003051757812727, -6.146389961242562 ], [ 149.008331298828125, -6.155279159545842 ], [ 148.996734619140852, -6.160000801086369 ], [ 148.993606567382812, -6.150556087493896 ], [ 149.003051757812727, -6.146389961242562 ] ] ], [ [ [ 149.02471923828125, -6.145555973052922 ], [ 149.022216796875, -6.143335819244385 ], [ 149.023895263671989, -6.139720916748047 ], [ 149.025283813476562, -6.140832901000977 ], [ 149.02471923828125, -6.145555973052922 ] ] ], [ [ [ 149.011016845703352, -6.139347076416016 ], [ 149.024444580078125, -6.14722204208374 ], [ 149.02166748046875, -6.153332233428898 ], [ 149.00166320800804, -6.14305591583252 ], [ 149.011016845703352, -6.139347076416016 ] ] ], [ [ [ 149.057739257812727, -6.134943962097168 ], [ 149.055114746093977, -6.138294219970703 ], [ 149.05262756347679, -6.134466171264592 ], [ 149.054229736328239, -6.13360595703125 ], [ 149.057739257812727, -6.134943962097168 ] ] ], [ [ [ 148.993896484375227, -6.137082099914551 ], [ 149.001129150390852, -6.143139839172306 ], [ 148.994445800781477, -6.148056030273381 ], [ 148.98944091796875, -6.133333206176701 ], [ 148.993896484375227, -6.137082099914551 ] ] ], [ [ [ 149.057998657226676, -6.130510807037354 ], [ 149.058334350586051, -6.13054084777832 ], [ 149.058395385742188, -6.130818843841553 ], [ 149.058059692383154, -6.13074779510498 ], [ 149.057998657226676, -6.130510807037354 ] ] ], [ [ [ 149.055831909179915, -6.13042497634882 ], [ 149.055755615234489, -6.13074779510498 ], [ 149.055557250976676, -6.130609035491943 ], [ 149.055831909179915, -6.13042497634882 ] ] ], [ [ [ 149.057998657226676, -6.130510807037354 ], [ 149.055831909179915, -6.13042497634882 ], [ 149.055557250976676, -6.129916191101017 ], [ 149.057434082031364, -6.129706859588623 ], [ 149.057998657226676, -6.130510807037354 ] ] ], [ [ [ 149.050003051757812, -6.129167079925537 ], [ 149.05389404296875, -6.130001068115234 ], [ 149.054443359375, -6.132917881011963 ], [ 149.050827026367188, -6.134167194366398 ], [ 149.050003051757812, -6.129167079925537 ] ] ], [ [ [ 148.953048706054801, -6.128057003021183 ], [ 148.971527099609602, -6.136388778686467 ], [ 148.958892822265625, -6.167359828948918 ], [ 148.965774536132812, -6.139653205871582 ], [ 148.953048706054801, -6.128057003021183 ] ] ], [ [ [ 150.708053588867301, -6.12722206115717 ], [ 150.711669921875114, -6.128334999084416 ], [ 150.710830688476562, -6.132501125335693 ], [ 150.706115722656477, -6.130833148956185 ], [ 150.708053588867301, -6.12722206115717 ] ] ], [ [ [ 148.998062133789176, -6.119167804717961 ], [ 149.006454467773551, -6.126485824584961 ], [ 149.007431030273665, -6.133772850036621 ], [ 148.99249267578125, -6.128334999084416 ], [ 148.998062133789176, -6.119167804717961 ] ] ], [ [ [ 149.007904052734375, -6.111886024475098 ], [ 149.011520385742529, -6.116187095642033 ], [ 149.011108398437614, -6.117646217346191 ], [ 149.006805419921875, -6.114106178283691 ], [ 149.007904052734375, -6.111886024475098 ] ] ], [ [ [ 149.029647827148438, -6.109457015991211 ], [ 149.029998779296989, -6.110983848571777 ], [ 149.028335571289062, -6.111398220062199 ], [ 149.028610229492415, -6.110013008117676 ], [ 149.029647827148438, -6.109457015991211 ] ] ], [ [ [ 148.988067626953125, -6.107157230377197 ], [ 148.990005493164062, -6.11333322525013 ], [ 148.985275268554801, -6.116943836212158 ], [ 148.981948852539176, -6.111667156219482 ], [ 148.988067626953125, -6.107157230377197 ] ] ], [ [ [ 148.982086181640739, -6.109445095062256 ], [ 148.979171752929801, -6.109167098999023 ], [ 148.979721069335938, -6.10694503784174 ], [ 148.980972290039176, -6.10736179351801 ], [ 148.982086181640739, -6.109445095062256 ] ] ], [ [ [ 148.959304809570312, -6.107068061828556 ], [ 148.958892822265625, -6.107915878295898 ], [ 148.957916259765739, -6.107223033904972 ], [ 148.958618164062955, -6.1061110496521 ], [ 148.959304809570312, -6.107068061828556 ] ] ], [ [ [ 149.029998779296989, -6.107165813446045 ], [ 149.02825927734375, -6.106542110443115 ], [ 149.029159545898665, -6.105014801025391 ], [ 149.030273437500227, -6.105848789215088 ], [ 149.029998779296989, -6.107165813446045 ] ] ], [ [ [ 149.011596679687614, -6.104680061340275 ], [ 149.0128173828125, -6.107523918151799 ], [ 149.011383056640625, -6.109885215759221 ], [ 149.007995605468977, -6.106553077697754 ], [ 149.011596679687614, -6.104680061340275 ] ] ], [ [ [ 149.038818359375, -6.104454040527344 ], [ 149.04437255859375, -6.109694004058781 ], [ 149.036666870117301, -6.114155769348031 ], [ 149.035003662109375, -6.107461929321289 ], [ 149.038818359375, -6.104454040527344 ] ] ], [ [ [ 148.998199462890625, -6.104444980621281 ], [ 148.999450683593864, -6.106389045715332 ], [ 148.997909545898892, -6.107501029968205 ], [ 148.996383666992642, -6.105833053588867 ], [ 148.998199462890625, -6.104444980621281 ] ] ], [ [ [ 149.033569335937727, -6.101908206939697 ], [ 149.036087036132812, -6.103321075439396 ], [ 149.034973144531364, -6.106917858123779 ], [ 149.032485961914176, -6.103011131286564 ], [ 149.033569335937727, -6.101908206939697 ] ] ], [ [ [ 149.455825805664176, -6.102778911590576 ], [ 149.454727172851676, -6.101109981536865 ], [ 149.456466674804688, -6.100831985473633 ], [ 149.457214355468864, -6.10208082199091 ], [ 149.455825805664176, -6.102778911590576 ] ] ], [ [ [ 149.01690673828125, -6.099437236785889 ], [ 149.016616821289176, -6.100757122039738 ], [ 149.013916015625227, -6.100212097167969 ], [ 149.014434814453125, -6.098580837249756 ], [ 149.01690673828125, -6.099437236785889 ] ] ], [ [ [ 149.020431518554801, -6.097891807556096 ], [ 149.027908325195426, -6.108553886413517 ], [ 149.018814086914062, -6.114729881286621 ], [ 149.015274047851676, -6.103369235992432 ], [ 149.020431518554801, -6.097891807556096 ] ] ], [ [ [ 149.415283203125114, -6.096943855285645 ], [ 149.416671752929688, -6.099443912506104 ], [ 149.413330078125455, -6.099443912506104 ], [ 149.41278076171875, -6.098609924316406 ], [ 149.415283203125114, -6.096943855285645 ] ] ], [ [ [ 148.960693359375227, -6.095417022705021 ], [ 148.966110229492301, -6.099721908569336 ], [ 148.960968017578239, -6.103474140167236 ], [ 148.956390380859489, -6.098609924316406 ], [ 148.960693359375227, -6.095417022705021 ] ] ], [ [ [ 148.94305419921875, -6.098055839538517 ], [ 148.941940307617188, -6.096111774444523 ], [ 148.943603515625114, -6.094861030578556 ], [ 148.944168090820426, -6.097221851348877 ], [ 148.94305419921875, -6.098055839538517 ] ] ], [ [ [ 148.9486083984375, -6.09597110748291 ], [ 148.952224731445312, -6.096527099609375 ], [ 148.94805908203125, -6.102778911590576 ], [ 148.945831298828352, -6.09833383560175 ], [ 148.9486083984375, -6.09597110748291 ] ] ], [ [ [ 148.972229003906591, -6.096943855285645 ], [ 148.97138977050804, -6.09638786315918 ], [ 148.972229003906591, -6.093612194061222 ], [ 148.973892211914176, -6.095277786254826 ], [ 148.972229003906591, -6.096943855285645 ] ] ], [ [ [ 149.444900512695312, -6.091944217681828 ], [ 149.453048706054801, -6.093887805938721 ], [ 149.456390380859489, -6.097361087799072 ], [ 149.446014404297216, -6.094320774078312 ], [ 149.444900512695312, -6.091944217681828 ] ] ], [ [ [ 148.988189697265739, -6.091666221618596 ], [ 148.990692138671875, -6.098749160766602 ], [ 148.980270385742188, -6.101387977600098 ], [ 148.978607177734489, -6.095277786254826 ], [ 148.988189697265739, -6.091666221618596 ] ] ], [ [ [ 149.047271728515739, -6.091963768005314 ], [ 149.044418334961165, -6.102403163909855 ], [ 149.034927368164176, -6.101222038268986 ], [ 149.04267883300804, -6.089425086975041 ], [ 149.047271728515739, -6.091963768005314 ] ] ], [ [ [ 149.44091796875, -6.090229988098145 ], [ 149.438980102539062, -6.09078407287592 ], [ 149.437026977539176, -6.090158939361459 ], [ 149.4378662109375, -6.089395999908334 ], [ 149.44091796875, -6.090229988098145 ] ] ], [ [ [ 148.999588012695426, -6.084473133087101 ], [ 149.004119873046875, -6.091364860534668 ], [ 149.000839233398779, -6.093605041503849 ], [ 148.996185302734602, -6.090164184570256 ], [ 148.999588012695426, -6.084473133087101 ] ] ], [ [ [ 148.994583129882812, -6.08805513381958 ], [ 148.989303588867415, -6.087915897369385 ], [ 148.991943359375227, -6.081110954284554 ], [ 148.993881225586165, -6.0813889503479 ], [ 148.994583129882812, -6.08805513381958 ] ] ], [ [ [ 149.020553588867415, -6.076388835906982 ], [ 149.037780761718864, -6.079722881317139 ], [ 149.043060302734602, -6.088612079620361 ], [ 149.007781982421989, -6.087499141693115 ], [ 149.020553588867415, -6.076388835906982 ] ] ], [ [ [ 148.950302124023438, -6.07305717468256 ], [ 148.955001831054801, -6.074443817138615 ], [ 148.955825805664404, -6.078125 ], [ 148.945968627929915, -6.074305057525578 ], [ 148.950302124023438, -6.07305717468256 ] ] ], [ [ [ 148.985549926757926, -6.071387767791691 ], [ 148.993606567382812, -6.076528072357178 ], [ 148.988754272461392, -6.082084178924561 ], [ 148.979446411132926, -6.076666831970215 ], [ 148.985549926757926, -6.071387767791691 ] ] ], [ [ [ 148.946945190429801, -6.061943054199162 ], [ 148.948745727539176, -6.063124179840088 ], [ 148.945693969726676, -6.066666126251221 ], [ 148.942779541015852, -6.062777996063176 ], [ 148.946945190429801, -6.061943054199162 ] ] ], [ [ [ 148.953964233398438, -6.061389923095646 ], [ 148.955413818359489, -6.062794208526611 ], [ 148.953338623046989, -6.063611984252873 ], [ 148.951950073242301, -6.061943054199162 ], [ 148.953964233398438, -6.061389923095646 ] ] ], [ [ [ 148.995422363281477, -6.060694217681885 ], [ 148.999160766601562, -6.061665058135929 ], [ 148.994445800781477, -6.068056106567383 ], [ 148.99249267578125, -6.065556049346924 ], [ 148.995422363281477, -6.060694217681885 ] ] ], [ [ [ 148.984451293945312, -6.057776927947998 ], [ 148.980270385742188, -6.056666851043701 ], [ 148.986251831054915, -6.05111122131342 ], [ 148.987716674804688, -6.054234981536865 ], [ 148.984451293945312, -6.057776927947998 ] ] ], [ [ [ 148.865280151367188, -6.02555513381958 ], [ 148.862503051757926, -6.023333072662354 ], [ 148.867919921875, -6.01805591583252 ], [ 148.868331909179688, -6.023889064788818 ], [ 148.865280151367188, -6.02555513381958 ] ] ], [ [ [ 148.868331909179688, -6.009722232818604 ], [ 148.871383666992188, -6.012777805328369 ], [ 148.865829467773438, -6.016387939453125 ], [ 148.864440917968864, -6.011665821075439 ], [ 148.868331909179688, -6.009722232818604 ] ] ], [ [ [ 148.858184814453125, -6.003606796264648 ], [ 148.856994628906364, -6.008845806121826 ], [ 148.852508544922102, -6.007771015167236 ], [ 148.852508544922102, -6.005652904510441 ], [ 148.858184814453125, -6.003606796264648 ] ] ], [ [ [ 148.876296997070312, -6.001349925994873 ], [ 148.88470458984375, -6.001905918121338 ], [ 148.884490966797216, -6.009192943572941 ], [ 148.873870849609602, -6.006694793701172 ], [ 148.876296997070312, -6.001349925994873 ] ] ], [ [ [ 148.869934082031364, -5.995347023010254 ], [ 148.873275756835938, -5.997222900390625 ], [ 148.873886108398551, -5.998332977294865 ], [ 148.869171142578239, -5.998332977294865 ], [ 148.869934082031364, -5.995347023010254 ] ] ], [ [ [ 148.871246337890852, -5.982638835906982 ], [ 148.883056640625227, -5.994166851043701 ], [ 148.881668090820312, -5.997500896453857 ], [ 148.865005493164176, -5.99027776718134 ], [ 148.871246337890852, -5.982638835906982 ] ] ], [ [ [ 148.713409423828125, -5.953402042388802 ], [ 148.711944580078352, -5.953333854675293 ], [ 148.712493896484375, -5.950832843780518 ], [ 148.713470458984602, -5.95111083984375 ], [ 148.713409423828125, -5.953402042388802 ] ] ], [ [ [ 148.696533203125227, -5.953333854675293 ], [ 148.694717407226562, -5.951666831970158 ], [ 148.698883056640739, -5.948888778686467 ], [ 148.699172973632926, -5.95111083984375 ], [ 148.696533203125227, -5.953333854675293 ] ] ], [ [ [ 148.734558105468864, -5.94838285446167 ], [ 148.733932495117642, -5.94817399978632 ], [ 148.733856201171875, -5.947203159332162 ], [ 148.735107421875, -5.947619915008545 ], [ 148.734558105468864, -5.94838285446167 ] ] ], [ [ [ 148.73211669921875, -5.94677019119257 ], [ 148.73066711425804, -5.944477081298828 ], [ 148.73309326171875, -5.942045211791992 ], [ 148.734024047851562, -5.942777156829777 ], [ 148.73211669921875, -5.94677019119257 ] ] ], [ [ [ 148.629760742187727, -5.837337017059269 ], [ 148.628936767578125, -5.837268829345646 ], [ 148.629058837890625, -5.8361558914184 ], [ 148.630187988281364, -5.836573123931828 ], [ 148.629760742187727, -5.837337017059269 ] ] ], [ [ [ 149.72222900390625, -5.548889160156136 ], [ 149.720550537109602, -5.547499179840031 ], [ 149.723327636718864, -5.546667098999023 ], [ 149.723617553711051, -5.547777175903263 ], [ 149.72222900390625, -5.548889160156136 ] ] ], [ [ [ 149.491836547851562, -5.526976108551025 ], [ 149.490829467773551, -5.525992870330811 ], [ 149.491882324218977, -5.524901866912842 ], [ 149.492675781250455, -5.5260910987854 ], [ 149.491836547851562, -5.526976108551025 ] ] ], [ [ [ 149.443450927734602, -5.514013767242375 ], [ 149.435791015625114, -5.523055076599121 ], [ 149.428161621093864, -5.515243053436279 ], [ 149.440689086914062, -5.512257099151554 ], [ 149.443450927734602, -5.514013767242375 ] ] ], [ [ [ 149.452743530273438, -5.51170110702509 ], [ 149.45375061035179, -5.514388084411621 ], [ 149.449462890625, -5.513545036315861 ], [ 149.449935913086165, -5.511956214904785 ], [ 149.452743530273438, -5.51170110702509 ] ] ], [ [ [ 149.713088989257812, -5.507778167724553 ], [ 149.710906982421875, -5.506526947021428 ], [ 149.716629028320312, -5.502354145049992 ], [ 149.715499877929801, -5.507041931152344 ], [ 149.713088989257812, -5.507778167724553 ] ] ], [ [ [ 150.104934692383267, -5.499934196472111 ], [ 150.105560302734489, -5.502222061157227 ], [ 150.102401733398665, -5.502586841583252 ], [ 150.103683471679688, -5.500279903411808 ], [ 150.104934692383267, -5.499934196472111 ] ] ], [ [ [ 149.761947631836051, -5.50111198425293 ], [ 149.76055908203125, -5.498889923095646 ], [ 149.761108398437841, -5.496111869811955 ], [ 149.762771606445426, -5.496942996978703 ], [ 149.761947631836051, -5.50111198425293 ] ] ], [ [ [ 149.084793090820312, -5.497220993041935 ], [ 149.084442138672102, -5.496111869811955 ], [ 149.086944580078239, -5.495554924011117 ], [ 149.086105346679688, -5.497220993041935 ], [ 149.084793090820312, -5.497220993041935 ] ] ], [ [ [ 149.621383666992301, -5.486945152282658 ], [ 149.620834350586165, -5.483057022094727 ], [ 149.623886108398665, -5.481110095977783 ], [ 149.62554931640625, -5.484723091125431 ], [ 149.621383666992301, -5.486945152282658 ] ] ], [ [ [ 150.862808227539062, -5.479138851165771 ], [ 150.862121582031477, -5.478860855102539 ], [ 150.862335205078352, -5.477748870849609 ], [ 150.863159179687614, -5.477955818176213 ], [ 150.862808227539062, -5.479138851165771 ] ] ], [ [ [ 149.090026855468977, -5.478994846343994 ], [ 149.089324951171989, -5.478371143341064 ], [ 149.090942382812614, -5.477714061737004 ], [ 149.090988159180142, -5.478507041931152 ], [ 149.090026855468977, -5.478994846343994 ] ] ], [ [ [ 150.855880737304688, -5.479000091552734 ], [ 150.855178833007812, -5.478929042816162 ], [ 150.855392456054688, -5.477191925048828 ], [ 150.856155395507812, -5.477610111236515 ], [ 150.855880737304688, -5.479000091552734 ] ] ], [ [ [ 148.883270263672102, -5.473055839538574 ], [ 148.881942749023892, -5.471943855285588 ], [ 148.883895874023551, -5.469998836517334 ], [ 148.883819580078352, -5.47222185134882 ], [ 148.883270263672102, -5.473055839538574 ] ] ], [ [ [ 148.499053955078125, -5.470859050750676 ], [ 148.498214721679688, -5.470581054687443 ], [ 148.498764038086051, -5.469192981719971 ], [ 148.499740600585938, -5.469677925109863 ], [ 148.499053955078125, -5.470859050750676 ] ] ], [ [ [ 149.688888549804915, -5.46527719497675 ], [ 149.696945190429915, -5.473988056182861 ], [ 149.695617675781705, -5.479425907134896 ], [ 149.688812255859489, -5.472446918487549 ], [ 149.688888549804915, -5.46527719497675 ] ] ], [ [ [ 148.882919311523438, -5.464445114135742 ], [ 148.881942749023892, -5.464583873748779 ], [ 148.881042480468864, -5.463857173919564 ], [ 148.882080078125227, -5.463055133819523 ], [ 148.882919311523438, -5.464445114135742 ] ] ], [ [ [ 149.710556030273551, -5.464723110198975 ], [ 149.709167480468864, -5.464999198913574 ], [ 149.708328247070312, -5.464445114135742 ], [ 149.711105346679801, -5.462777137756291 ], [ 149.710556030273551, -5.464723110198975 ] ] ], [ [ [ 148.942489624023438, -5.461503028869629 ], [ 148.94110107421875, -5.461835861205998 ], [ 148.94110107421875, -5.461000919341984 ], [ 148.942733764648665, -5.460696220397949 ], [ 148.942489624023438, -5.461503028869629 ] ] ], [ [ [ 149.682495117187614, -5.438333034515381 ], [ 149.681671142578352, -5.436666965484562 ], [ 149.683609008789176, -5.435000896453801 ], [ 149.68417358398483, -5.436388969421387 ], [ 149.682495117187614, -5.438333034515381 ] ] ], [ [ [ 150.791107177734375, -5.428887844085693 ], [ 150.79194641113304, -5.426943778991699 ], [ 150.794448852539176, -5.427499771118107 ], [ 150.793334960937614, -5.428609848022461 ], [ 150.791107177734375, -5.428887844085693 ] ] ], [ [ [ 148.972259521484375, -5.424708843231087 ], [ 148.971282958984375, -5.424081802368107 ], [ 148.97247314453125, -5.422623157501164 ], [ 148.973373413086279, -5.423317909240723 ], [ 148.972259521484375, -5.424708843231087 ] ] ], [ [ [ 150.80722045898483, -5.413332939147892 ], [ 150.808456420898438, -5.414467811584473 ], [ 150.807464599609489, -5.415753841400146 ], [ 150.806106567382812, -5.41416692733759 ], [ 150.80722045898483, -5.413332939147892 ] ] ], [ [ [ 150.060592651367188, -5.368010044097844 ], [ 150.059722900390852, -5.369721889495793 ], [ 150.05810546875, -5.367195129394474 ], [ 150.059555053711051, -5.367125988006592 ], [ 150.060592651367188, -5.368010044097844 ] ] ], [ [ [ 150.057785034179801, -5.359999179840031 ], [ 150.060073852539176, -5.361664772033691 ], [ 150.060073852539176, -5.362218856811523 ], [ 150.056594848632812, -5.361811161041203 ], [ 150.057785034179801, -5.359999179840031 ] ] ], [ [ [ 150.494720458984375, -5.343887805938721 ], [ 150.49444580078125, -5.355555057525635 ], [ 150.488327026367301, -5.359167098999023 ], [ 150.487258911132812, -5.344338893890324 ], [ 150.494720458984375, -5.343887805938721 ] ] ], [ [ [ 150.05360412597679, -5.339909076690674 ], [ 150.053680419921989, -5.341506004333439 ], [ 150.052429199218977, -5.341923236846867 ], [ 150.0523681640625, -5.340117931365853 ], [ 150.05360412597679, -5.339909076690674 ] ] ], [ [ [ 150.057800292968977, -5.32863187789917 ], [ 150.056900024414062, -5.32791614532465 ], [ 150.058395385742642, -5.326662063598633 ], [ 150.058609008789062, -5.327498912811222 ], [ 150.057800292968977, -5.32863187789917 ] ] ], [ [ [ 150.050003051758267, -5.318056106567383 ], [ 150.049163818359375, -5.318056106567383 ], [ 150.048538208007926, -5.316181182861271 ], [ 150.05055236816429, -5.316666126251164 ], [ 150.050003051758267, -5.318056106567383 ] ] ], [ [ [ 150.10467529296875, -5.295286178588867 ], [ 150.10369873046875, -5.294867992401123 ], [ 150.103561401367301, -5.293201923370304 ], [ 150.105575561523779, -5.29389476776123 ], [ 150.10467529296875, -5.295286178588867 ] ] ], [ [ [ 150.093505859375114, -5.295429229736328 ], [ 150.091232299804688, -5.293315887451172 ], [ 150.092773437500114, -5.292222023010254 ], [ 150.094970703125114, -5.293922901153564 ], [ 150.093505859375114, -5.295429229736328 ] ] ], [ [ [ 150.026779174804801, -5.288547992706185 ], [ 150.026214599609489, -5.289867877960148 ], [ 150.023239135742415, -5.288755893707219 ], [ 150.02400207519554, -5.287783145904541 ], [ 150.026779174804801, -5.288547992706185 ] ] ], [ [ [ 150.075836181640625, -5.286665916442814 ], [ 150.088027954101904, -5.302546977996826 ], [ 150.070724487304688, -5.318206787109375 ], [ 150.05476379394554, -5.305905818939152 ], [ 150.075836181640625, -5.286665916442814 ] ] ], [ [ [ 150.043548583984375, -5.284893035888615 ], [ 150.045288085937614, -5.28565597534174 ], [ 150.043487548828352, -5.287185192108097 ], [ 150.042160034179915, -5.285865783691293 ], [ 150.043548583984375, -5.284893035888615 ] ] ], [ [ [ 150.069122314453239, -5.275010108947697 ], [ 150.069122314453239, -5.275842189788818 ], [ 150.067810058594091, -5.27521800994873 ], [ 150.068023681640625, -5.274384021759033 ], [ 150.069122314453239, -5.275010108947697 ] ] ], [ [ [ 150.101425170898438, -5.234457969665527 ], [ 150.099334716796875, -5.23452615737915 ], [ 150.099411010742301, -5.233416080474854 ], [ 150.101837158203239, -5.232371807098389 ], [ 150.101425170898438, -5.234457969665527 ] ] ], [ [ [ 150.375549316406364, -5.209166049957275 ], [ 150.374374389648438, -5.204236030578556 ], [ 150.37646484375, -5.203165054321289 ], [ 150.37847900390625, -5.206638813018799 ], [ 150.375549316406364, -5.209166049957275 ] ] ], [ [ [ 150.202301025390625, -5.093002796173096 ], [ 150.200973510742188, -5.092517852783203 ], [ 150.201828002930142, -5.090435028076115 ], [ 150.202926635742301, -5.092030048370361 ], [ 150.202301025390625, -5.093002796173096 ] ] ], [ [ [ 150.193328857421875, -5.085000991821289 ], [ 150.196395874023438, -5.088055133819523 ], [ 150.194641113281364, -5.089914798736515 ], [ 150.192825317382926, -5.089294910430851 ], [ 150.193328857421875, -5.085000991821289 ] ] ], [ [ [ 151.210006713867301, -4.954995155334473 ], [ 151.210281372070426, -4.959447860717717 ], [ 151.206939697265852, -4.960281848907414 ], [ 151.206390380859489, -4.955560207366943 ], [ 151.210006713867301, -4.954995155334473 ] ] ], [ [ [ 151.3646240234375, -4.917444229125977 ], [ 151.475830078125, -4.950832843780461 ], [ 151.531448364257926, -4.923934936523381 ], [ 151.583587646484375, -4.965909004211369 ], [ 151.646469116211051, -4.932185173034611 ], [ 151.690017700195312, -4.97843599319458 ], [ 151.429611206054688, -4.981234073638916 ], [ 151.342208862304915, -5.039535045623779 ], [ 151.265213012695426, -5.150934219360295 ], [ 151.142211914062614, -5.39533519744873 ], [ 151.152908325195312, -5.421435832977238 ], [ 151.213607788085938, -5.432634830474854 ], [ 151.212509155273665, -5.474934101104736 ], [ 151.030319213867415, -5.609535217285099 ], [ 150.950515747070426, -5.599034786224365 ], [ 150.939010620117415, -5.626934051513672 ], [ 150.954818725586165, -5.673435211181584 ], [ 150.945816040039062, -5.702435016632023 ], [ 150.814514160156364, -5.748035907745361 ], [ 150.729217529296989, -5.732833862304631 ], [ 150.594207763671989, -5.73863410949707 ], [ 150.606811523437614, -5.919235229492188 ], [ 150.780181884765739, -6.075234889984074 ], [ 150.746673583984375, -6.126666069030705 ], [ 150.73388671875, -6.110555171966553 ], [ 150.623016357421989, -6.156857967376652 ], [ 150.626663208008154, -6.128610134124756 ], [ 150.61236572265625, -6.134583950042725 ], [ 150.605560302734602, -6.119999885559082 ], [ 150.605560302734602, -6.138610839843693 ], [ 150.586044311523438, -6.152778148651123 ], [ 150.570281982421989, -6.143611907958984 ], [ 150.575942993164062, -6.159893989562988 ], [ 150.559448242187727, -6.150556087493896 ], [ 150.463333129882926, -6.248054981231689 ], [ 150.421661376953125, -6.253890037536564 ], [ 150.383895874023438, -6.278056144714355 ], [ 150.350555419921989, -6.25666618347168 ], [ 150.324722290039176, -6.280000209808293 ], [ 150.319427490234375, -6.274406909942627 ], [ 150.330276489257812, -6.266287803649846 ], [ 150.328887939453125, -6.260831832885685 ], [ 150.325195312500114, -6.257500171661377 ], [ 150.31129455566429, -6.272411823272705 ], [ 150.308334350585938, -6.265000820159912 ], [ 150.288085937500114, -6.264412879943848 ], [ 150.289993286132926, -6.274721145629883 ], [ 150.226394653320426, -6.281387805938664 ], [ 150.225006103515625, -6.25083398818964 ], [ 150.207778930664176, -6.260831832885685 ], [ 150.189163208007812, -6.23375415802002 ], [ 150.16194152832054, -6.238057136535645 ], [ 150.1683349609375, -6.222776889801025 ], [ 150.167221069335938, -6.217501163482666 ], [ 150.153884887695312, -6.25083398818964 ], [ 150.083892822265852, -6.286943912506104 ], [ 150.06719970703125, -6.247820854187012 ], [ 150.047866821289176, -6.240231037139893 ], [ 150.035018920898438, -6.257638931274414 ], [ 150.050003051758267, -6.262500762939396 ], [ 150.021072387695426, -6.265933036804086 ], [ 150.01861572265625, -6.274445056915226 ], [ 150.038330078125114, -6.287777900695801 ], [ 149.998886108398892, -6.31694507598877 ], [ 150.011672973632926, -6.28916597366333 ], [ 150.002563476562614, -6.266452789306641 ], [ 150.004196166992415, -6.283618927001953 ], [ 149.991394042968977, -6.285555839538517 ], [ 149.953887939453239, -6.252778053283691 ], [ 149.938613891602017, -6.272499084472656 ], [ 149.933624267578352, -6.266425132751465 ], [ 149.913986206054915, -6.271990776062012 ], [ 149.899444580078125, -6.294723033904972 ], [ 149.888412475586051, -6.267380237579289 ], [ 149.86138916015625, -6.258056163787842 ], [ 149.851943969726562, -6.285555839538517 ], [ 149.74806213378929, -6.268332958221436 ], [ 149.703063964843864, -6.271527767181396 ], [ 149.669448852539176, -6.293055057525635 ], [ 149.659866333007812, -6.281390190124512 ], [ 149.607772827148438, -6.291388988494816 ], [ 149.553756713867301, -6.241651058196965 ], [ 149.539993286132926, -6.189723014831486 ], [ 149.533615112304688, -6.213889122009277 ], [ 149.49360656738304, -6.138054847717285 ], [ 149.469528198242188, -6.125061988830566 ], [ 149.469726562500227, -6.09333419799799 ], [ 149.333328247070312, -6.054444789886418 ], [ 149.252578735351676, -6.057149887084847 ], [ 149.228546142578239, -6.093471050262451 ], [ 149.181671142578125, -6.091944217681828 ], [ 149.181396484375455, -6.079034805297852 ], [ 149.15167236328125, -6.092500209808293 ], [ 149.153549194336392, -6.080416202545109 ], [ 149.141113281250114, -6.074443817138615 ], [ 149.149444580078125, -6.090556144714355 ], [ 149.121948242187614, -6.140832901000977 ], [ 149.102783203125227, -6.151666164398193 ], [ 149.068054199218864, -6.139720916748047 ], [ 149.038345336914517, -6.161616802215576 ], [ 149.030807495117188, -6.135561943054142 ], [ 149.045837402343864, -6.149188995361328 ], [ 149.061248779296989, -6.132773876190186 ], [ 149.059585571289404, -6.127500057220402 ], [ 149.038192749023551, -6.123610019683781 ], [ 149.059204101562841, -6.111837863922119 ], [ 149.046661376953125, -6.108333110809326 ], [ 149.052764892578125, -6.091372013091984 ], [ 149.030410766601562, -6.069028854370117 ], [ 149.005004882812614, -6.071527004241887 ], [ 149.033737182617415, -6.041240215301457 ], [ 149.0328369140625, -6.015212059020882 ], [ 149.009994506836279, -6.043056011199894 ], [ 149.008346557617415, -6.025833129882812 ], [ 148.913894653320312, -6.010278224945012 ], [ 148.865997314453125, -5.976455211639404 ], [ 148.846786499023665, -5.993813037872314 ], [ 148.842758178710938, -5.974356174468937 ], [ 148.866638183593864, -5.955499172210693 ], [ 148.813049316406364, -5.911387920379639 ], [ 148.774444580078125, -5.911943912506104 ], [ 148.775482177734602, -5.928472995758057 ], [ 148.746902465820767, -5.942441940307617 ], [ 148.767501831055142, -5.912221908569336 ], [ 148.749664306640625, -5.863173007965031 ], [ 148.71630859375, -5.872972965240422 ], [ 148.697311401367642, -5.851208209991398 ], [ 148.650024414062614, -5.852757930755558 ], [ 148.604263305664062, -5.804876804351807 ], [ 148.573028564453125, -5.816949844360352 ], [ 148.5689697265625, -5.838066101074219 ], [ 148.54872131347679, -5.834379196166992 ], [ 148.506912231445426, -5.796977996826172 ], [ 148.39784240722679, -5.77036714553833 ], [ 148.346343994140852, -5.730488777160588 ], [ 148.309997558594091, -5.658333778381348 ], [ 148.326934814453125, -5.600527763366642 ], [ 148.318603515625, -5.564723014831543 ], [ 148.348114013671989, -5.483745098114014 ], [ 148.415039062500114, -5.443070888519287 ], [ 148.492568969726562, -5.472900867462158 ], [ 148.519638061523438, -5.497378826141244 ], [ 148.521041870117415, -5.526931762695256 ], [ 148.557098388672102, -5.538535118102971 ], [ 148.650894165039062, -5.476984977722168 ], [ 148.731842041015739, -5.481948852539062 ], [ 148.797393798828352, -5.531920909881592 ], [ 148.84986877441429, -5.518847942352295 ], [ 148.876937866211051, -5.480278015136719 ], [ 148.897445678711051, -5.486854076385441 ], [ 148.976211547851676, -5.457078933715763 ], [ 149.048675537109375, -5.498382091522217 ], [ 149.070297241210938, -5.488365173339844 ], [ 149.085845947265739, -5.509693145751839 ], [ 149.115097045898438, -5.506971836090031 ], [ 149.180709838867188, -5.537470817565918 ], [ 149.178436279296875, -5.556922912597656 ], [ 149.199539184570312, -5.546717166900635 ], [ 149.210250854492301, -5.583265781402531 ], [ 149.263641357421989, -5.573348999023438 ], [ 149.258331298828466, -5.592223167419377 ], [ 149.292984008789176, -5.560628890991211 ], [ 149.330551147461392, -5.567777156829777 ], [ 149.361648559570426, -5.554773807525635 ], [ 149.375839233398438, -5.570555210113525 ], [ 149.406707763671989, -5.540073871612549 ], [ 149.424621582031364, -5.558008193969727 ], [ 149.440765380859602, -5.557107925414982 ], [ 149.44630432128929, -5.536186218261662 ], [ 149.487915039062614, -5.558201789855957 ], [ 149.504272460937614, -5.53067684173584 ], [ 149.527496337890625, -5.534721851348877 ], [ 149.516616821289062, -5.528069972991943 ], [ 149.57757568359375, -5.496207237243596 ], [ 149.603149414062614, -5.49037504196167 ], [ 149.60150146484375, -5.505498886108398 ], [ 149.6697998046875, -5.491849899291992 ], [ 149.66131591796875, -5.447894096374512 ], [ 149.685516357421989, -5.476587772369385 ], [ 149.673553466796989, -5.540067195892334 ], [ 149.728134155273438, -5.550938129425049 ], [ 149.729629516601676, -5.532049179077092 ], [ 149.775207519531364, -5.519064903259277 ], [ 149.781845092773551, -5.482657909393254 ], [ 149.875839233398665, -5.518332958221379 ], [ 149.940536499023551, -5.468136787414437 ], [ 149.96626281738304, -5.413581848144531 ], [ 149.963821411132812, -5.395048141479492 ], [ 149.928985595703125, -5.385315895080566 ], [ 149.901870727539404, -5.336665153503361 ], [ 149.952880859375114, -5.270842075347844 ], [ 150.000000000000227, -5.257222175598145 ], [ 150.026107788086165, -5.204167842864933 ], [ 149.997802734375114, -5.134904861450195 ], [ 150.029861450195312, -5.099583148956299 ], [ 150.027023315429688, -5.027993202209416 ], [ 150.039352416992188, -5.009679794311523 ], [ 150.093612670898438, -4.997499942779484 ], [ 150.163894653320312, -5.025279045104924 ], [ 150.19232177734375, -5.056291103363037 ], [ 150.180282592773551, -5.088055133819523 ], [ 150.072296142578352, -5.134239196777344 ], [ 150.058334350586165, -5.174446105956974 ], [ 150.080551147460938, -5.217501163482666 ], [ 150.069168090820312, -5.241666793823242 ], [ 150.080245971679688, -5.255968093871957 ], [ 150.018051147460938, -5.286943912506047 ], [ 150.046615600586051, -5.305016994476318 ], [ 150.04888916015625, -5.343887805938721 ], [ 150.057769775390852, -5.352013111114502 ], [ 150.046447753906591, -5.360977172851562 ], [ 150.080490112304915, -5.400086879730225 ], [ 150.102386474609375, -5.479787826538029 ], [ 150.093643188476676, -5.517468929290771 ], [ 150.153671264648438, -5.551902770996094 ], [ 150.226058959961051, -5.538910865783691 ], [ 150.287384033203125, -5.558839797973576 ], [ 150.413131713867415, -5.437722206115723 ], [ 150.452392578125227, -5.425284862518311 ], [ 150.520278930664062, -5.435554981231689 ], [ 150.578521728515852, -5.478977203369084 ], [ 150.598922729492415, -5.541502952575627 ], [ 150.680282592773438, -5.546667098999023 ], [ 150.721542358398551, -5.517461776733342 ], [ 150.748748779296875, -5.474999904632512 ], [ 150.7369384765625, -5.462501049041748 ], [ 150.757110595703239, -5.449818134307861 ], [ 150.81646728515625, -5.44478797912592 ], [ 150.835891723632926, -5.485200881957951 ], [ 150.873123168945312, -5.490647792816105 ], [ 150.90657043457054, -5.481588840484562 ], [ 150.909500122070426, -5.457063198089543 ], [ 150.953170776367301, -5.445977210998478 ], [ 151.008331298828125, -5.370833873748779 ], [ 151.007507324218864, -5.30388879776001 ], [ 151.08583068847679, -5.143332958221436 ], [ 151.165222167968977, -5.088570117950439 ], [ 151.262329101562614, -4.982932090759221 ], [ 151.3460693359375, -4.95359992980957 ], [ 151.346496582031591, -4.913833141326904 ], [ 151.3646240234375, -4.917444229125977 ] ] ], [ [ [ 151.37179565429733, -4.907692909240723 ], [ 151.367416381836051, -4.912841796875 ], [ 151.362106323242301, -4.911366939544621 ], [ 151.36891174316429, -4.901984214782658 ], [ 151.37179565429733, -4.907692909240723 ] ] ], [ [ [ 151.06976318359375, -4.901861190795842 ], [ 151.067810058593864, -4.900322914123535 ], [ 151.068695068359602, -4.899034976959229 ], [ 151.070495605468864, -4.900259017944336 ], [ 151.06976318359375, -4.901861190795842 ] ] ], [ [ [ 151.050521850585938, -4.902830123901367 ], [ 151.046310424804688, -4.902953147888184 ], [ 151.044036865234375, -4.897730827331543 ], [ 151.049682617187614, -4.896758079528809 ], [ 151.050521850585938, -4.902830123901367 ] ] ], [ [ [ 151.176742553711279, -4.883553028106689 ], [ 151.233764648437614, -4.920450210571232 ], [ 151.208206176757926, -4.948867797851562 ], [ 151.162216186523551, -4.958057880401611 ], [ 151.111663818359375, -4.925899028778076 ], [ 151.176742553711279, -4.883553028106689 ] ] ], [ [ [ 149.129241943359375, -4.867638111114502 ], [ 149.127288818359489, -4.869651794433537 ], [ 149.126663208007926, -4.868888854980412 ], [ 149.128326416015739, -4.866944789886418 ], [ 149.129241943359375, -4.867638111114502 ] ] ], [ [ [ 149.143890380859716, -4.860556125640812 ], [ 149.163055419922102, -4.864165782928467 ], [ 149.176116943359489, -4.89083194732666 ], [ 149.135833740234375, -4.923611164093018 ], [ 149.108337402343977, -4.888055801391602 ], [ 149.143890380859716, -4.860556125640812 ] ] ], [ [ [ 149.503616333008154, -4.679444789886418 ], [ 149.506164550781477, -4.680800914764404 ], [ 149.506149291992188, -4.682623863220158 ], [ 149.50152587890625, -4.680650234222412 ], [ 149.503616333008154, -4.679444789886418 ] ] ], [ [ [ 149.496368408203466, -4.641404151916504 ], [ 149.548049926757926, -4.673332214355469 ], [ 149.537368774414176, -4.715266227722168 ], [ 149.505828857422102, -4.702221870422306 ], [ 149.510986328125455, -4.668145179748535 ], [ 149.496566772460938, -4.656470775604248 ], [ 149.46882629394554, -4.669860839843693 ], [ 149.489898681640625, -4.70489597320551 ], [ 149.430282592773665, -4.691944122314453 ], [ 149.446105957031477, -4.659166812896672 ], [ 149.496368408203466, -4.641404151916504 ] ] ], [ [ [ 149.313888549804688, -4.638333797454777 ], [ 149.315826416015739, -4.64305591583252 ], [ 149.314437866210938, -4.644165992736816 ], [ 149.311111450195426, -4.642221927642822 ], [ 149.313888549804688, -4.638333797454777 ] ] ], [ [ [ 149.288330078125, -4.631667137145996 ], [ 149.297775268554688, -4.637221813201904 ], [ 149.29750061035179, -4.642499923706055 ], [ 149.290283203125227, -4.639999866485596 ], [ 149.288330078125, -4.631667137145996 ] ] ], [ [ [ 149.383895874023665, -4.618611812591496 ], [ 149.343338012695426, -4.633055210113525 ], [ 149.319168090820426, -4.626667022705021 ], [ 149.350555419922102, -4.616943836212101 ], [ 149.383895874023665, -4.618611812591496 ] ] ], [ [ [ 149.288604736328239, -4.613612174987793 ], [ 149.291107177734489, -4.615834236144963 ], [ 149.291107177734489, -4.618333816528263 ], [ 149.286941528320654, -4.614721775054875 ], [ 149.288604736328239, -4.613612174987793 ] ] ], [ [ [ 149.113800048828125, -4.546926975250244 ], [ 149.104766845703239, -4.542849063873291 ], [ 149.10755920410179, -4.535851955413818 ], [ 149.11634826660179, -4.540287971496525 ], [ 149.113800048828125, -4.546926975250244 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-WHM", "NAME_1": "Western Highlands" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 144.254913330078239, -5.221435070037842 ], [ 144.282516479492415, -5.219533920288029 ], [ 144.322509765625, -5.277634143829346 ], [ 144.374511718750114, -5.314033985137939 ], [ 144.302810668945312, -5.457933902740422 ], [ 144.298110961914062, -5.514035224914551 ], [ 144.462814331054801, -5.523235797882023 ], [ 144.469711303711051, -5.659835815429688 ], [ 144.513916015625227, -5.68683385848999 ], [ 144.51171875, -5.727735996246281 ], [ 144.489013671875, -5.762633800506592 ], [ 144.383209228515625, -5.75353479385376 ], [ 144.370010375976562, -5.811334133148193 ], [ 144.3004150390625, -5.860835075378418 ], [ 144.274505615234602, -5.921333789825439 ], [ 144.325408935546875, -6.023134231567383 ], [ 144.376510620117188, -6.023734092712402 ], [ 144.430908203125227, -5.992634773254338 ], [ 144.46601867675804, -5.996235847473145 ], [ 144.481719970703125, -6.01463508605957 ], [ 144.479705810546875, -6.161435127258244 ], [ 144.370315551757926, -6.232935905456429 ], [ 144.23211669921875, -6.159035205841008 ], [ 144.001510620117188, -5.997233867645264 ], [ 143.883117675781477, -6.048635959625244 ], [ 143.881805419922102, -5.964734077453613 ], [ 143.830917358398551, -5.937035083770695 ], [ 143.770919799804688, -5.838435173034668 ], [ 143.80531311035179, -5.8211350440979 ], [ 143.867919921875114, -5.821033954620361 ], [ 143.910919189453125, -5.781233787536621 ], [ 143.954910278320312, -5.793735027313232 ], [ 144.0537109375, -5.748233795166016 ], [ 144.025619506836165, -5.665833950042668 ], [ 144.022216796875114, -5.594035148620549 ], [ 143.990417480468864, -5.558934211730957 ], [ 143.994415283203239, -5.478233814239388 ], [ 144.03211975097679, -5.454235076904297 ], [ 144.046112060546989, -5.413335800170898 ], [ 144.11811828613304, -5.380434036254883 ], [ 144.140518188476676, -5.351035118103027 ], [ 144.233306884765852, -5.34393405914301 ], [ 144.24871826171875, -5.278436183929387 ], [ 144.241409301757926, -5.231833934783936 ], [ 144.254913330078239, -5.221435070037842 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PG-WPD", "NAME_1": "Western" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 141.569122314453352, -9.523050308227539 ], [ 141.568893432617188, -9.519166946411076 ], [ 141.573333740234602, -9.51249980926508 ], [ 141.574645996093977, -9.517151832580453 ], [ 141.569122314453352, -9.523050308227539 ] ] ], [ [ [ 142.661331176757926, -9.428422927856445 ], [ 142.658279418945426, -9.428867340087891 ], [ 142.653671264648665, -9.428190231323185 ], [ 142.662109375, -9.428190231323185 ], [ 142.661331176757926, -9.428422927856445 ] ] ], [ [ [ 142.744735717773779, -9.418585777282658 ], [ 142.74427795410179, -9.418885231018066 ], [ 142.747268676757812, -9.415566444396916 ], [ 142.746078491210938, -9.417434692382756 ], [ 142.744735717773779, -9.418585777282658 ] ] ], [ [ [ 142.533187866211051, -9.411385536193791 ], [ 142.538101196289517, -9.410627365112248 ], [ 142.543075561523551, -9.419412612914982 ], [ 142.552505493164062, -9.420276641845703 ], [ 142.548995971679801, -9.423785209655762 ], [ 142.53085327148483, -9.414399147033691 ], [ 142.528778076171989, -9.427544593811035 ], [ 142.527908325195312, -9.411348342895508 ], [ 142.533187866211051, -9.411385536193791 ] ] ], [ [ [ 142.599609375, -9.40929985046381 ], [ 142.596588134765625, -9.403185844421387 ], [ 142.600082397461165, -9.396608352661076 ], [ 142.597656250000114, -9.403989791870117 ], [ 142.599609375, -9.40929985046381 ] ] ], [ [ [ 142.631576538086051, -9.369168281555176 ], [ 142.629608154297102, -9.368770599365234 ], [ 142.629516601562614, -9.367729187011719 ], [ 142.633483886718864, -9.367620468139592 ], [ 142.631576538086051, -9.369168281555176 ] ] ], [ [ [ 142.654556274414062, -9.365497589111328 ], [ 142.670761108398438, -9.375241279601994 ], [ 142.706436157226562, -9.381782531738224 ], [ 142.743164062500114, -9.366120338439941 ], [ 142.794403076172102, -9.370869636535645 ], [ 142.799560546875114, -9.373188018798771 ], [ 142.801040649414062, -9.376838684081974 ], [ 142.744812011718977, -9.370169639587402 ], [ 142.703063964843977, -9.384859085083008 ], [ 142.646865844726676, -9.368320465087834 ], [ 142.600021362304688, -9.395412445068303 ], [ 142.60867309570358, -9.380365371704102 ], [ 142.654556274414062, -9.365497589111328 ] ] ], [ [ [ 142.666717529296989, -9.361317634582463 ], [ 142.670120239257812, -9.363975524902344 ], [ 142.66529846191429, -9.367181777954102 ], [ 142.66279602050804, -9.362628936767521 ], [ 142.666717529296989, -9.361317634582463 ] ] ], [ [ [ 142.690536499023551, -9.358120918273926 ], [ 142.71441650390625, -9.362845420837402 ], [ 142.724929809570312, -9.368817329406738 ], [ 142.66737365722679, -9.371517181396484 ], [ 142.690536499023551, -9.358120918273926 ] ] ], [ [ [ 142.721908569335938, -9.308305740356388 ], [ 142.725189208984602, -9.309160232543888 ], [ 142.717926025390739, -9.309996604919434 ], [ 142.720504760742301, -9.307789802551213 ], [ 142.721908569335938, -9.308305740356388 ] ] ], [ [ [ 142.23779296875, -9.2882080078125 ], [ 142.238906860351904, -9.28939056396473 ], [ 142.2364501953125, -9.288117408752441 ], [ 142.23779296875, -9.2882080078125 ] ] ], [ [ [ 142.23500061035179, -9.288332939147949 ], [ 142.2320556640625, -9.288612365722599 ], [ 142.2296142578125, -9.288076400756779 ], [ 142.23554992675804, -9.288052558898869 ], [ 142.23500061035179, -9.288332939147949 ] ] ], [ [ [ 142.774063110351676, -9.283808708190861 ], [ 142.77076721191429, -9.280080795288029 ], [ 142.772262573242188, -9.277545928955021 ], [ 142.775512695312727, -9.282045364379883 ], [ 142.774063110351676, -9.283808708190861 ] ] ], [ [ [ 142.74787902832054, -9.27794075012207 ], [ 142.748748779296875, -9.280659675598145 ], [ 142.743438720703125, -9.27924919128418 ], [ 142.74493408203125, -9.277373313903809 ], [ 142.74787902832054, -9.27794075012207 ] ] ], [ [ [ 142.742660522460938, -9.278395652770939 ], [ 142.740707397461051, -9.277074813842773 ], [ 142.741973876953352, -9.275590896606388 ], [ 142.743072509765625, -9.276479721069336 ], [ 142.742660522460938, -9.278395652770939 ] ] ], [ [ [ 142.292709350585938, -9.2714586257934 ], [ 142.292343139648438, -9.271853446960449 ], [ 142.292709350585938, -9.271047592163086 ], [ 142.292709350585938, -9.2714586257934 ] ] ], [ [ [ 142.12971496582054, -9.261389732360783 ], [ 142.1280517578125, -9.263611793518066 ], [ 142.125549316406364, -9.262778282165527 ], [ 142.126251220703352, -9.261863708496094 ], [ 142.12971496582054, -9.261389732360783 ] ] ], [ [ [ 142.138748168945426, -9.235529899597168 ], [ 142.137588500976562, -9.234212875366154 ], [ 142.138839721679915, -9.233358383178654 ], [ 142.139724731445654, -9.234807968139648 ], [ 142.138748168945426, -9.235529899597168 ] ] ], [ [ [ 142.223495483398438, -9.230155944824162 ], [ 142.244995117187614, -9.256111145019531 ], [ 142.26625061035179, -9.249738693237248 ], [ 142.276672363281591, -9.251388549804688 ], [ 142.293609619140625, -9.259443283081055 ], [ 142.29432678222679, -9.265646934509277 ], [ 142.243316650390625, -9.259199142455998 ], [ 142.22181701660179, -9.232499122619629 ], [ 142.130661010742415, -9.267311096191406 ], [ 142.223495483398438, -9.230155944824162 ] ] ], [ [ [ 142.151901245117301, -9.231920242309513 ], [ 142.148376464843977, -9.235749244689941 ], [ 142.14668273925804, -9.235516548156681 ], [ 142.152557373046875, -9.226446151733398 ], [ 142.151901245117301, -9.231920242309513 ] ] ], [ [ [ 142.151382446289062, -9.226710319518929 ], [ 142.14794921875, -9.231202125549316 ], [ 142.144134521484375, -9.231520652770996 ], [ 142.14460754394554, -9.225918769836426 ], [ 142.151382446289062, -9.226710319518929 ] ] ], [ [ [ 142.157241821289176, -9.228055000305176 ], [ 142.16157531738304, -9.226503372192383 ], [ 142.153930664062727, -9.238263130187931 ], [ 142.155532836914176, -9.224808692932129 ], [ 142.157241821289176, -9.228055000305176 ] ] ], [ [ [ 142.167831420898665, -9.223043441772404 ], [ 142.177444458007926, -9.223799705505371 ], [ 142.188613891601562, -9.232464790344181 ], [ 142.167190551758154, -9.225159645080566 ], [ 142.155334472656364, -9.247236251831055 ], [ 142.167831420898665, -9.223043441772404 ] ] ], [ [ [ 142.14785766601608, -9.225824356079045 ], [ 142.144760131836165, -9.223957061767521 ], [ 142.152206420898551, -9.2222642898559 ], [ 142.151672363281705, -9.225213050842228 ], [ 142.14785766601608, -9.225824356079045 ] ] ], [ [ [ 142.23941040039108, -9.220879554748535 ], [ 142.250946044921875, -9.228588104248047 ], [ 142.250762939453125, -9.233658790588379 ], [ 142.231918334961165, -9.223686218261719 ], [ 142.23941040039108, -9.220879554748535 ] ] ], [ [ [ 142.277770996093864, -9.195556640625 ], [ 142.30805969238304, -9.204998970031681 ], [ 142.316223144531477, -9.213686943054199 ], [ 142.30574035644554, -9.219354629516602 ], [ 142.277770996093864, -9.195556640625 ] ] ], [ [ [ 142.055313110351676, -9.180896759033203 ], [ 142.07244873046875, -9.18709659576416 ], [ 142.064666748047102, -9.201765060424748 ], [ 142.029312133789062, -9.19951343536377 ], [ 142.055313110351676, -9.180896759033203 ] ] ], [ [ [ 142.012939453125, -9.180007934570312 ], [ 142.021286010742188, -9.191593170166016 ], [ 141.965560913086051, -9.19999885559082 ], [ 141.974166870117529, -9.183055877685433 ], [ 142.012939453125, -9.180007934570312 ] ] ], [ [ [ 142.022811889648438, -9.17801570892334 ], [ 142.032684326171875, -9.181888580322209 ], [ 142.024810791015852, -9.189400672912598 ], [ 142.014205932617301, -9.179532051086369 ], [ 142.022811889648438, -9.17801570892334 ] ] ], [ [ [ 143.248062133789176, -9.093889236450195 ], [ 143.273681640625, -9.101122856140137 ], [ 143.263885498046989, -9.140831947326546 ], [ 143.19917297363304, -9.132778167724553 ], [ 143.248062133789176, -9.093889236450195 ] ] ], [ [ [ 143.210784912109489, -9.066450119018498 ], [ 143.236938476562727, -9.081944465637207 ], [ 143.192504882812727, -9.100555419921818 ], [ 143.182159423828352, -9.082289695739689 ], [ 143.210784912109489, -9.066450119018498 ] ] ], [ [ [ 143.436660766601676, -8.966665267944336 ], [ 143.451110839843864, -8.981666564941406 ], [ 143.436111450195312, -9.026390075683594 ], [ 143.416183471679688, -9.019030570983887 ], [ 143.401870727539062, -9.038821220397892 ], [ 143.376449584961279, -9.022190093994141 ], [ 143.391113281250114, -8.991666793823185 ], [ 143.436660766601676, -8.966665267944336 ] ] ], [ [ [ 143.541671752929688, -8.864962577819767 ], [ 143.546829223632812, -8.87147045135498 ], [ 143.545516967773665, -8.874100685119629 ], [ 143.540420532226676, -8.864406585693303 ], [ 143.541671752929688, -8.864962577819767 ] ] ], [ [ [ 143.654281616211392, -8.754575729370117 ], [ 143.652618408203239, -8.752361297607365 ], [ 143.652755737305142, -8.7509765625 ], [ 143.654556274414062, -8.753191947936955 ], [ 143.654281616211392, -8.754575729370117 ] ] ], [ [ [ 143.66000366210983, -8.748611450195312 ], [ 143.66583251953125, -8.756112098693791 ], [ 143.665557861328239, -8.757499694824162 ], [ 143.658615112304915, -8.752499580383301 ], [ 143.66000366210983, -8.748611450195312 ] ] ], [ [ [ 143.654449462890852, -8.744444847106934 ], [ 143.654998779297102, -8.746666908264103 ], [ 143.65083312988304, -8.746110916137638 ], [ 143.652496337890625, -8.744723320007211 ], [ 143.654449462890852, -8.744444847106934 ] ] ], [ [ [ 143.418060302734375, -8.710835456848145 ], [ 143.426391601562614, -8.718610763549805 ], [ 143.426666259765625, -8.731944084167367 ], [ 143.418884277343977, -8.724167823791447 ], [ 143.418060302734375, -8.710835456848145 ] ] ], [ [ [ 143.439437866210938, -8.702221870422306 ], [ 143.459442138671875, -8.734722137451115 ], [ 143.444442749023665, -8.774721145629826 ], [ 143.427215576171875, -8.706110000610352 ], [ 143.439437866210938, -8.702221870422306 ] ] ], [ [ [ 143.35194396972679, -8.670556068420353 ], [ 143.368057250976904, -8.682499885559082 ], [ 143.407501220703125, -8.702500343322697 ], [ 143.383895874023438, -8.706388473510742 ], [ 143.35194396972679, -8.670556068420353 ] ] ], [ [ [ 143.360275268554688, -8.650278091430607 ], [ 143.397506713867415, -8.657222747802734 ], [ 143.423339843750114, -8.690833091735783 ], [ 143.366668701171989, -8.663888931274357 ], [ 143.360275268554688, -8.650278091430607 ] ] ], [ [ [ 143.33193969726608, -8.650278091430607 ], [ 143.330001831054915, -8.650555610656738 ], [ 143.329437255859602, -8.645556449890137 ], [ 143.332778930664062, -8.648612022399902 ], [ 143.33193969726608, -8.650278091430607 ] ] ], [ [ [ 143.292221069336165, -8.60583305358881 ], [ 143.294723510742415, -8.606666564941406 ], [ 143.294723510742415, -8.610833168029785 ], [ 143.291381835937841, -8.608332633972111 ], [ 143.292221069336165, -8.60583305358881 ] ] ], [ [ [ 143.259719848633154, -8.520000457763672 ], [ 143.316940307617529, -8.547222137451115 ], [ 143.345275878906477, -8.603056907653809 ], [ 143.301116943359375, -8.574443817138672 ], [ 143.259719848633154, -8.520000457763672 ] ] ], [ [ [ 143.282226562500341, -8.507498741149902 ], [ 143.287506103515739, -8.509720802307129 ], [ 143.294174194336392, -8.517499923705998 ], [ 143.274169921875114, -8.51027774810791 ], [ 143.282226562500341, -8.507498741149902 ] ] ], [ [ [ 143.78089904785179, -8.50715255737299 ], [ 143.780624389648438, -8.505208969116154 ], [ 143.781738281250114, -8.503542900085449 ], [ 143.784515380859489, -8.502709388732853 ], [ 143.78089904785179, -8.50715255737299 ] ] ], [ [ [ 143.80389404296875, -8.491109848022404 ], [ 143.820007324218977, -8.521388053894043 ], [ 143.79902648925804, -8.541161537170296 ], [ 143.784164428711165, -8.513055801391602 ], [ 143.80389404296875, -8.491109848022404 ] ] ], [ [ [ 143.20222473144554, -8.467222213745117 ], [ 143.211669921875, -8.471111297607365 ], [ 143.229446411132812, -8.493331909179631 ], [ 143.210281372070312, -8.48639011383051 ], [ 143.20222473144554, -8.467222213745117 ] ] ], [ [ [ 143.63055419921875, -8.458612442016602 ], [ 143.6572265625, -8.468056678771973 ], [ 143.673889160156364, -8.501667022705078 ], [ 143.638061523437727, -8.536390304565373 ], [ 143.596389770507812, -8.498611450195312 ], [ 143.601669311523438, -8.467222213745117 ], [ 143.63055419921875, -8.458612442016602 ] ] ], [ [ [ 143.31361389160179, -8.454721450805664 ], [ 143.324996948242188, -8.461943626403752 ], [ 143.300277709961392, -8.45916557312006 ], [ 143.302215576171875, -8.45694446563715 ], [ 143.31361389160179, -8.454721450805664 ] ] ], [ [ [ 143.16273498535179, -8.462706565856877 ], [ 143.178329467773438, -8.467779159545898 ], [ 143.225555419921989, -8.518610000610352 ], [ 143.168609619140625, -8.487500190734863 ], [ 143.142776489257926, -8.451945304870492 ], [ 143.16273498535179, -8.462706565856877 ] ] ], [ [ [ 143.298339843750227, -8.446945190429688 ], [ 143.307785034180029, -8.451389312744084 ], [ 143.276107788086051, -8.450554847717228 ], [ 143.278060913085938, -8.449444770812988 ], [ 143.298339843750227, -8.446945190429688 ] ] ], [ [ [ 143.728607177734375, -8.434721946716309 ], [ 143.77667236328125, -8.453888893127385 ], [ 143.790557861328125, -8.481389999389535 ], [ 143.783050537109489, -8.500556945800781 ], [ 143.71833801269554, -8.462499618530217 ], [ 143.728607177734375, -8.434721946716309 ] ] ], [ [ [ 143.701873779296875, -8.4393053054809 ], [ 143.692703247070312, -8.438749313354435 ], [ 143.692703247070312, -8.437639236450195 ], [ 143.699371337890625, -8.434028625488224 ], [ 143.701873779296875, -8.4393053054809 ] ] ], [ [ [ 143.327224731445426, -8.414166450500488 ], [ 143.341384887695312, -8.422223091125431 ], [ 143.34027099609375, -8.435000419616699 ], [ 143.33193969726608, -8.43194580078125 ], [ 143.327224731445426, -8.414166450500488 ] ] ], [ [ [ 143.572494506836051, -8.404166221618539 ], [ 143.607772827148438, -8.446110725402832 ], [ 143.583343505859489, -8.490557670593205 ], [ 143.565826416015739, -8.482777595519963 ], [ 143.585556030273438, -8.494722366332951 ], [ 143.575836181640852, -8.509443283081055 ], [ 143.4403076171875, -8.432827949523926 ], [ 143.47833251953125, -8.41805458068842 ], [ 143.506683349609375, -8.436884880065918 ], [ 143.537506103515852, -8.441945075988713 ], [ 143.55694580078125, -8.43194580078125 ], [ 143.572494506836051, -8.404166221618539 ] ] ], [ [ [ 143.210067749023551, -8.402986526489201 ], [ 143.271942138671875, -8.459721565246582 ], [ 143.384994506835938, -8.481943130493107 ], [ 143.475006103515739, -8.524723052978459 ], [ 143.58917236328125, -8.624444007873535 ], [ 143.633056640625227, -8.64000129699707 ], [ 143.637771606445312, -8.689723014831543 ], [ 143.61610412597679, -8.702221870422306 ], [ 143.582778930664176, -8.659444808959961 ], [ 143.403335571289176, -8.580556869506779 ], [ 143.351669311523438, -8.520556449890137 ], [ 143.263061523437727, -8.484722137451172 ], [ 143.188339233398551, -8.426945686340332 ], [ 143.210067749023551, -8.402986526489201 ] ] ], [ [ [ 143.134445190429688, -8.407221794128418 ], [ 143.12666320800804, -8.399167060852051 ], [ 143.143325805664176, -8.396666526794434 ], [ 143.14111328125, -8.40333366394043 ], [ 143.134445190429688, -8.407221794128418 ] ] ], [ [ [ 143.156524658203239, -8.407777786254883 ], [ 143.152923583984375, -8.398611068725472 ], [ 143.16542053222679, -8.398332595825195 ], [ 143.16542053222679, -8.400277137756291 ], [ 143.156524658203239, -8.407777786254883 ] ] ], [ [ [ 143.288894653320426, -8.39527702331543 ], [ 143.320556640625114, -8.409999847412053 ], [ 143.33111572265625, -8.43388843536377 ], [ 143.295272827148665, -8.423333168029785 ], [ 143.288894653320426, -8.39527702331543 ] ] ], [ [ [ 143.665283203125, -8.393889427185059 ], [ 143.68611145019554, -8.414443969726562 ], [ 143.678054809570312, -8.424445152282658 ], [ 143.653060913085938, -8.428334236144963 ], [ 143.631942749023665, -8.411109924316406 ], [ 143.665283203125, -8.393889427185059 ] ] ], [ [ [ 143.260284423828239, -8.391388893127441 ], [ 143.274444580078125, -8.401667594909611 ], [ 143.298889160156477, -8.439443588256836 ], [ 143.253326416015852, -8.428611755371094 ], [ 143.241943359375, -8.398611068725472 ], [ 143.260284423828239, -8.391388893127441 ] ] ], [ [ [ 143.074172973632812, -8.382778167724609 ], [ 143.063613891601676, -8.402223587036076 ], [ 143.023056030273438, -8.408056259155273 ], [ 142.984451293945312, -8.403889656066895 ], [ 142.973388671875, -8.387309074401855 ], [ 143.074172973632812, -8.382778167724609 ] ] ], [ [ [ 143.575836181640852, -8.375555992126351 ], [ 143.605834960937955, -8.401111602783146 ], [ 143.625549316406591, -8.435277938842773 ], [ 143.571105957031477, -8.399721145629826 ], [ 143.575836181640852, -8.375555992126351 ] ] ], [ [ [ 143.114028930664062, -8.380000114440918 ], [ 143.109298706054915, -8.376943588256779 ], [ 143.130966186523551, -8.363888740539551 ], [ 143.14263916015625, -8.366110801696721 ], [ 143.114028930664062, -8.380000114440918 ] ] ], [ [ [ 143.103881835937614, -8.386361122131291 ], [ 143.091110229492529, -8.390542984008789 ], [ 143.094726562500114, -8.361666679382324 ], [ 143.102951049804688, -8.365121841430607 ], [ 143.103881835937614, -8.386361122131291 ] ] ], [ [ [ 143.089447021484375, -8.359722137451115 ], [ 143.082229614257926, -8.370833396911621 ], [ 143.062240600586392, -8.367996215820312 ], [ 143.062942504882812, -8.360795974731445 ], [ 143.089447021484375, -8.359722137451115 ] ] ], [ [ [ 143.036392211914062, -8.355555534362793 ], [ 143.044998168945312, -8.361388206481934 ], [ 143.019515991211392, -8.371945381164494 ], [ 143.023605346679688, -8.354999542236328 ], [ 143.036392211914062, -8.355555534362793 ] ] ], [ [ [ 143.334716796875, -8.345832824707031 ], [ 143.376937866211165, -8.367501258850098 ], [ 143.561386108398665, -8.35888767242426 ], [ 143.57000732421875, -8.400554656982365 ], [ 143.538894653320426, -8.439443588256836 ], [ 143.480560302734489, -8.416389465331974 ], [ 143.408615112305142, -8.424999237060547 ], [ 143.315277099609375, -8.369998931884766 ], [ 143.334716796875, -8.345832824707031 ] ] ], [ [ [ 142.94721984863304, -8.345276832580453 ], [ 142.954727172851676, -8.348055839538517 ], [ 142.936386108398438, -8.348334312438965 ], [ 142.941390991210938, -8.3455553054809 ], [ 142.94721984863304, -8.345276832580453 ] ] ], [ [ [ 142.930831909179801, -8.339166641235295 ], [ 142.935836791992301, -8.341944694519043 ], [ 142.929443359375227, -8.345832824707031 ], [ 142.927505493164062, -8.340276718139648 ], [ 142.930831909179801, -8.339166641235295 ] ] ], [ [ [ 143.357772827148438, -8.34416675567627 ], [ 143.355270385742301, -8.342498779296875 ], [ 143.35455322265625, -8.339207649230957 ], [ 143.358062744140852, -8.341388702392578 ], [ 143.357772827148438, -8.34416675567627 ] ] ], [ [ [ 143.309722900390625, -8.336944580078068 ], [ 143.320831298828352, -8.34305477142334 ], [ 143.306396484375114, -8.357500076293888 ], [ 143.300552368164062, -8.352499961853027 ], [ 143.309722900390625, -8.336944580078068 ] ] ], [ [ [ 143.387283325195312, -8.332839965820256 ], [ 143.437774658203352, -8.34305477142334 ], [ 143.446395874023551, -8.349444389343262 ], [ 143.361938476562614, -8.349167823791447 ], [ 143.359161376953352, -8.338889122009277 ], [ 143.387283325195312, -8.332839965820256 ] ] ], [ [ [ 143.32861328125, -8.328887939453125 ], [ 143.336395263672216, -8.333057403564453 ], [ 143.312500000000114, -8.334348678588867 ], [ 143.318054199218864, -8.330555915832463 ], [ 143.32861328125, -8.328887939453125 ] ] ], [ [ [ 143.57472229003929, -8.326944351196289 ], [ 143.640548706055142, -8.336944580078068 ], [ 143.663604736328352, -8.355832099914494 ], [ 143.671951293945312, -8.394445419311523 ], [ 143.657775878906364, -8.392223358154297 ], [ 143.651382446289176, -8.394166946411133 ], [ 143.628616333007812, -8.409166336059513 ], [ 143.574996948242301, -8.355555534362793 ], [ 143.528060913086051, -8.34000110626215 ], [ 143.57472229003929, -8.326944351196289 ] ] ], [ [ [ 142.899719238281477, -8.32499980926508 ], [ 142.9244384765625, -8.336667060851994 ], [ 142.926116943359489, -8.3455553054809 ], [ 142.88916015625, -8.327777862548771 ], [ 142.899719238281477, -8.32499980926508 ] ] ], [ [ [ 143.357772827148438, -8.32388973236084 ], [ 143.377227783203125, -8.32944393157959 ], [ 143.38166809082054, -8.332221984863281 ], [ 143.342773437500114, -8.329999923706055 ], [ 143.357772827148438, -8.32388973236084 ] ] ], [ [ [ 143.120605468750455, -8.33464527130127 ], [ 143.064437866210938, -8.355278015136719 ], [ 143.033813476562727, -8.345346450805664 ], [ 143.044525146484489, -8.329774856567383 ], [ 143.138336181640852, -8.321111679077148 ], [ 143.120605468750455, -8.33464527130127 ] ] ], [ [ [ 143.300842285156477, -8.323158264160156 ], [ 143.268188476562727, -8.356388092040959 ], [ 143.21417236328125, -8.365925788879395 ], [ 143.117919921875227, -8.346542358398438 ], [ 143.167083740234375, -8.328056335449162 ], [ 143.300842285156477, -8.323158264160156 ] ] ], [ [ [ 143.383331298828125, -8.303609848022404 ], [ 143.485000610351562, -8.308610916137695 ], [ 143.494995117187727, -8.318888664245549 ], [ 143.470840454101676, -8.333888053894043 ], [ 143.303329467773892, -8.317776679992619 ], [ 143.383331298828125, -8.303609848022404 ] ] ], [ [ [ 143.212783813476676, -8.301112174987793 ], [ 143.238327026367301, -8.30694389343256 ], [ 143.177780151367415, -8.306110382080078 ], [ 143.186660766601676, -8.301943778991699 ], [ 143.212783813476676, -8.301112174987793 ] ] ], [ [ [ 143.23500061035179, -8.291110992431641 ], [ 143.236114501953125, -8.295556068420353 ], [ 143.229995727539062, -8.293889999389592 ], [ 143.230834960937727, -8.291945457458496 ], [ 143.23500061035179, -8.291110992431641 ] ] ], [ [ [ 143.394729614257926, -8.28972339630127 ], [ 143.389160156250455, -8.293333053588867 ], [ 143.38166809082054, -8.291110992431641 ], [ 143.382507324218864, -8.28972339630127 ], [ 143.394729614257926, -8.28972339630127 ] ] ], [ [ [ 143.636688232422102, -8.088068008422795 ], [ 143.680480957031591, -8.111944198608398 ], [ 143.691040039062727, -8.144444465637207 ], [ 143.639648437500114, -8.174445152282715 ], [ 143.586318969726562, -8.130555152893066 ], [ 143.579376220703239, -8.104167938232422 ], [ 143.636688232422102, -8.088068008422795 ] ] ], [ [ [ 143.546600341796875, -8.064723014831486 ], [ 143.542984008789062, -8.056389808654728 ], [ 143.543533325195654, -8.050276756286621 ], [ 143.546600341796875, -8.053890228271428 ], [ 143.546600341796875, -8.064723014831486 ] ] ], [ [ [ 143.597778320312727, -8.012776374816895 ], [ 143.66680908203125, -8.041367530822754 ], [ 143.701385498047102, -8.095555305480957 ], [ 143.651382446289176, -8.074444770812988 ], [ 143.571105957031477, -8.07833290100092 ], [ 143.543609619140852, -8.0272216796875 ], [ 143.597778320312727, -8.012776374816895 ] ] ], [ [ [ 143.397109985351562, -7.984169006347599 ], [ 143.395736694335938, -7.984169006347599 ], [ 143.393524169922102, -7.985568046569767 ], [ 143.393798828125114, -7.983323097228947 ], [ 143.397109985351562, -7.984169006347599 ] ] ], [ [ [ 143.412139892578125, -7.931124210357609 ], [ 143.431808471679688, -7.935035228729191 ], [ 143.461029052734489, -8.013050079345703 ], [ 143.537246704101562, -8.039809226989746 ], [ 143.548248291015739, -8.078791618347168 ], [ 143.570358276367642, -8.110816001891976 ], [ 143.470840454101676, -8.074444770812988 ], [ 143.450271606445312, -8.022223472595215 ], [ 143.414443969726562, -8.01500129699707 ], [ 143.39404296875, -7.988327980041504 ], [ 143.409637451172216, -7.976107120513916 ], [ 143.384353637695426, -7.955300807952824 ], [ 143.388519287109375, -7.934464931488037 ], [ 143.412139892578125, -7.931124210357609 ] ] ], [ [ [ 141.002410888671875, -4.987235069274846 ], [ 142.122573852539062, -5.370335102081299 ], [ 142.078506469726562, -5.417335033416691 ], [ 142.06697082519554, -5.469642162322998 ], [ 142.570114135742415, -5.882334232330265 ], [ 142.626007080078352, -5.903635025024414 ], [ 142.631607055664176, -6.809134960174504 ], [ 142.665008544922216, -6.823635101318303 ], [ 142.99472045898483, -6.822734832763672 ], [ 142.995513916015625, -6.999135017394963 ], [ 143.049118041992301, -7.075735092163029 ], [ 143.696807861328352, -7.756535053253117 ], [ 143.868118286132926, -7.927834987640324 ], [ 143.91552734375, -7.9542942047118 ], [ 143.924163818359602, -7.988889217376652 ], [ 143.906112670898551, -8.003611564636174 ], [ 143.853195190429915, -7.953901767730656 ], [ 143.815063476562727, -7.959982872009277 ], [ 143.782501220703239, -7.935832977294865 ], [ 143.787216186523665, -7.904167175292912 ], [ 143.780914306640852, -7.888368129730168 ], [ 143.751663208007812, -7.896666049957275 ], [ 143.744171142578239, -7.906667232513371 ], [ 143.77874755859375, -7.890340805053711 ], [ 143.780593872070426, -7.94196796417225 ], [ 143.814422607421875, -7.96829891204834 ], [ 143.851913452148438, -7.963387966156006 ], [ 143.875000000000114, -8.018889427185059 ], [ 143.861114501953125, -8.04749870300293 ], [ 143.730560302734602, -8.04305458068842 ], [ 143.604537963867301, -7.988643169403019 ], [ 143.543334960937614, -8.007499694824219 ], [ 143.486389160156477, -8.000834465026799 ], [ 143.437103271484716, -7.910748958587646 ], [ 143.366455078125227, -7.907995223999023 ], [ 143.346801757812727, -7.83418083190918 ], [ 143.31927490234375, -7.837701797485352 ], [ 143.309234619140852, -7.879158020019474 ], [ 143.259460449219205, -7.879902839660645 ], [ 143.260147094726562, -7.793570995330811 ], [ 143.256729125976562, -7.88607215881342 ], [ 143.314025878906364, -7.886102199554443 ], [ 143.338119506835938, -7.8458251953125 ], [ 143.357772827148438, -7.925278186798096 ], [ 143.382629394531477, -7.934587955474854 ], [ 143.383377075195312, -7.958621978759709 ], [ 143.406631469726562, -7.97695779800415 ], [ 143.391159057617188, -7.983095169067269 ], [ 143.39027404785179, -7.994872093200684 ], [ 143.415283203125227, -8.022223472595215 ], [ 143.445007324218864, -8.026667594909611 ], [ 143.465270996093864, -8.08055591583252 ], [ 143.536117553710938, -8.105554580688477 ], [ 143.630828857421989, -8.185832977294922 ], [ 143.704437255859602, -8.17500114440918 ], [ 143.709167480468977, -8.216387748718148 ], [ 143.635833740234489, -8.238055229187012 ], [ 143.541107177734375, -8.238611221313477 ], [ 143.537780761718864, -8.226110458374023 ], [ 143.34944152832054, -8.243333816528263 ], [ 142.98583984375, -8.336388587951603 ], [ 142.899169921875114, -8.318888664245549 ], [ 142.859771728515625, -8.32088565826416 ], [ 142.845001220703239, -8.367780685424748 ], [ 142.923339843750227, -8.417778968811035 ], [ 143.117782592773551, -8.460556030273438 ], [ 143.2550048828125, -8.571390151977482 ], [ 143.39277648925804, -8.741389274597168 ], [ 143.420272827148551, -8.961944580078125 ], [ 143.372772216796989, -9.008056640624886 ], [ 143.330322265625, -9.02656078338623 ], [ 143.283050537109375, -9.016944885253906 ], [ 143.184982299804688, -9.037659645080566 ], [ 143.233337402343864, -9.015555381774846 ], [ 143.235549926757812, -9.00916671752924 ], [ 143.245834350585938, -8.999444007873535 ], [ 143.247772216797102, -8.99416542053217 ], [ 143.235275268554801, -9.007500648498478 ], [ 143.231384277343864, -9.015276908874455 ], [ 143.172210693359375, -9.039918899536133 ], [ 143.13861083984375, -9.071666717529183 ], [ 143.010284423828125, -9.1036119461059 ], [ 142.92730712890625, -9.175140380859261 ], [ 142.78118896484375, -9.263046264648381 ], [ 142.765716552734716, -9.259292602539062 ], [ 142.638916015625, -9.333086967468262 ], [ 142.568664550781364, -9.323000907897892 ], [ 142.479995727539404, -9.25000095367426 ], [ 142.41560363769554, -9.218884468078613 ], [ 142.297836303711051, -9.196345329284668 ], [ 142.20269775390625, -9.130989074707031 ], [ 142.170135498046989, -9.158251762390137 ], [ 142.080917358398551, -9.178321838378906 ], [ 141.959167480468977, -9.171111106872445 ], [ 141.9244384765625, -9.19666671752924 ], [ 141.884445190429915, -9.201666831970215 ], [ 141.771118164062614, -9.179999351501465 ], [ 141.625839233398551, -9.212222099304199 ], [ 141.521118164062614, -9.195000648498421 ], [ 141.4505615234375, -9.143889427185059 ], [ 141.348892211914176, -9.141944885253849 ], [ 141.340270996093977, -9.130000114440861 ], [ 141.233062744140852, -9.214444160461369 ], [ 141.138885498046989, -9.234721183776742 ], [ 141.020828247070426, -9.131943702697697 ], [ 141.026107788086051, -9.118055343627873 ], [ 141.006820678710938, -9.121541976928711 ], [ 141.011764526367188, -7.999898910522461 ], [ 140.982391357421875, -6.891974925994873 ], [ 140.951217651367188, -6.876529216766357 ], [ 140.936355590820426, -6.895720005035344 ], [ 140.925994873047102, -6.878479957580566 ], [ 140.936248779296875, -6.84686899185175 ], [ 140.923446655273438, -6.860859870910588 ], [ 140.897811889648438, -6.856439113616943 ], [ 140.8841552734375, -6.835978984832764 ], [ 140.902603149414176, -6.805129051208439 ], [ 140.858093261718977, -6.780619144439584 ], [ 140.885437011718864, -6.740618228912354 ], [ 140.836395263671875, -6.713048934936523 ], [ 140.8343505859375, -6.676589965820256 ], [ 140.864257812500114, -6.67130517959589 ], [ 140.856399536132926, -6.630125045776367 ], [ 140.893905639648438, -6.623135089874268 ], [ 140.894317626953352, -6.588254928588867 ], [ 140.918701171875, -6.551150798797607 ], [ 140.931884765625114, -6.553237915039062 ], [ 140.922027587890739, -6.488733768463135 ], [ 140.956970214843864, -6.476916790008545 ], [ 140.940017700195312, -6.439035892486572 ], [ 140.956451416015625, -6.363737106323185 ], [ 140.973236083984375, -6.35559606552124 ], [ 140.957015991210938, -6.341135025024357 ], [ 141.000213623046989, -6.313239097595215 ], [ 141.002410888671875, -4.987235069274846 ] ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/paraguay.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/paraguay.geojson new file mode 100644 index 0000000000000..05b79bb85928a --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/paraguay.geojson @@ -0,0 +1,24 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "PY-19", "NAME_1": "Boquerón" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -62.275599731999932, -22.513508401999985 ], [ -62.281387491999908, -22.512061463 ], [ -62.283816284999972, -22.504826761999936 ], [ -62.283609578999915, -22.493768005999925 ], [ -62.284539753999866, -22.488703714999943 ], [ -62.2872269289999, -22.483949482999961 ], [ -62.29451330599997, -22.479815368999937 ], [ -62.305727091999927, -22.476714781999902 ], [ -62.341356966999911, -22.472261048 ], [ -62.3487218839999, -22.471340433999927 ], [ -62.368255574999921, -22.464415791999954 ], [ -62.438070434999872, -22.419664000999902 ], [ -62.454968627999875, -22.403851013 ], [ -62.461944946999949, -22.388761493999894 ], [ -62.470574910999915, -22.381836852999911 ], [ -62.510727498999927, -22.370157978999941 ], [ -62.523388224999877, -22.364886982999906 ], [ -62.547624470999949, -22.335328063999967 ], [ -62.564677693999982, -22.321995543999947 ], [ -62.588293822999901, -22.316414488999939 ], [ -62.599610961999872, -22.315174254999903 ], [ -62.613150186999945, -22.31145355199989 ], [ -62.625294148999842, -22.305045674999946 ], [ -62.63268387899987, -22.295950622999968 ], [ -62.630823526999848, -22.28768239399993 ], [ -62.624208943999946, -22.278897398999945 ], [ -62.620281534999975, -22.268458760999906 ], [ -62.626431030999953, -22.255022887999957 ], [ -62.619609740999891, -22.255022887999957 ], [ -62.624829060999929, -22.247271422999944 ], [ -62.631805378999928, -22.240760192999886 ], [ -62.640383667999942, -22.236212666999862 ], [ -62.650357218999943, -22.234455667999967 ], [ -62.627516234999945, -22.184536233999907 ], [ -62.599404256999918, -22.089865010999887 ], [ -62.572842569999892, -22.000774840999966 ], [ -62.529227661999954, -21.865072529999907 ], [ -62.492795776999941, -21.751797789999927 ], [ -62.446183634999983, -21.60689707399986 ], [ -62.411973836999977, -21.500857034999939 ], [ -62.375490275999965, -21.384481709999932 ], [ -62.340401977999932, -21.272860615999903 ], [ -62.307897501999918, -21.169301045999958 ], [ -62.275703084999861, -21.06656829799995 ], [ -62.271879027999915, -21.000939229999915 ], [ -62.271885774109194, -21.00042365282934 ], [ -62.273791056999926, -20.854798277999905 ], [ -62.275031290999976, -20.758680115 ], [ -62.276168172999888, -20.670726826999982 ], [ -62.277305053999896, -20.579776305999886 ], [ -62.268830118999887, -20.553111266999935 ], [ -62.232398234999891, -20.501021422999983 ], [ -62.210573102366766, -20.471305463076646 ], [ -62.189661824999888, -20.442833760999875 ], [ -62.144961710999922, -20.382062275999957 ], [ -62.100209920999873, -20.321187438999928 ], [ -62.055509806999936, -20.26041595399991 ], [ -62.010809692999885, -20.199541116999882 ], [ -61.994169880999948, -20.175666604999975 ], [ -61.977581746999959, -20.151792093999902 ], [ -61.960941935999926, -20.128020934999938 ], [ -61.944250447999906, -20.104146422999946 ], [ -61.931383016999916, -20.078308206999935 ], [ -61.924739799402232, -20.065127638529702 ], [ -61.911486781789563, -20.076138604013352 ], [ -61.818701747787429, -20.131897474688685 ], [ -59.951037971125459, -20.651607353796351 ], [ -59.881765712917286, -20.679357599273771 ], [ -59.85546240916284, -20.698167820088827 ], [ -59.875848762010776, -20.776044202577907 ], [ -59.875667893958109, -20.780385024149552 ], [ -59.874350145243, -20.786379489421904 ], [ -59.870551926929863, -20.79227060280607 ], [ -59.849803839775404, -20.817850437048037 ], [ -59.837995774585295, -20.837797539424912 ], [ -59.832414719563644, -20.850975030173515 ], [ -59.826161871872898, -20.874436130023412 ], [ -59.825619268614332, -20.883737888093037 ], [ -59.826006843141272, -20.891954440545021 ], [ -59.829727546189304, -20.918309421142851 ], [ -59.829029914199168, -20.926474297650714 ], [ -59.826316900604468, -20.93391570374672 ], [ -59.805801358346002, -20.967970472859065 ], [ -59.752083705898315, -21.037888686213876 ], [ -59.746450974932543, -21.047190444283558 ], [ -59.736890835343786, -21.068687838472954 ], [ -59.695756395341391, -21.325364679136612 ], [ -59.69549801292294, -21.334873141881985 ], [ -59.696221483334796, -21.343451429539869 ], [ -59.697771776046636, -21.350272718910844 ], [ -59.699477098389366, -21.355440361883211 ], [ -59.701905891143952, -21.359729505712096 ], [ -59.705109829355138, -21.363140151296932 ], [ -59.710432501958394, -21.367377618282489 ], [ -59.811459926834175, -21.424583428882158 ], [ -59.826678635810367, -21.435848890813645 ], [ -59.841303067382626, -21.450731703005715 ], [ -59.847349208599098, -21.459671725869441 ], [ -59.851767543637209, -21.469645277507539 ], [ -59.941891241787346, -21.845332939763352 ], [ -59.955973070101095, -21.885123792628917 ], [ -59.95816931795963, -21.89809457780251 ], [ -59.95816931795963, -21.907706394234708 ], [ -59.941994594574851, -21.999742120302585 ], [ -59.940961065800536, -22.030231215098524 ], [ -59.938170538739371, -22.040463149155016 ], [ -59.929178839931524, -22.043822116997092 ], [ -59.836678025870185, -22.041548353873452 ], [ -59.781590948763267, -22.033538506996479 ], [ -59.420424364392886, -22.046509291270752 ], [ -59.391563075775309, -22.055139254872699 ], [ -59.342289597686772, -22.083044529081747 ], [ -59.307072110389583, -22.182056573252282 ], [ -59.304204068063257, -22.195647475150849 ], [ -59.307588874327053, -22.201435234848191 ], [ -59.322600877728291, -22.213785903296809 ], [ -59.384741787303653, -22.249390964221618 ], [ -59.408590460781113, -22.259932956640625 ], [ -59.413990647750211, -22.26039804463403 ], [ -59.420553554702792, -22.258537692660411 ], [ -59.428770108054039, -22.253990167312395 ], [ -59.436521571613241, -22.248719170653203 ], [ -59.445875007425627, -22.240347588570387 ], [ -59.45365231030587, -22.235128268754579 ], [ -59.464065110616332, -22.230219008200663 ], [ -59.477604335671572, -22.23326791768028 ], [ -59.491763679250369, -22.238073825446691 ], [ -59.59452226399128, -22.295641371252259 ], [ -59.607854784370772, -22.307526950808153 ], [ -59.616252203976046, -22.318534031220565 ], [ -59.621600715000966, -22.329696139465284 ], [ -59.623564418862827, -22.33538054817376 ], [ -59.625114711574668, -22.345664158174372 ], [ -59.624830491633872, -22.353157240214443 ], [ -59.622634242876018, -22.361115411147296 ], [ -59.609560105814239, -22.384938246203092 ], [ -59.608113165889904, -22.391294447580719 ], [ -59.609250046552404, -22.398890883307615 ], [ -59.61648474797272, -22.412016697212835 ], [ -59.627440152441068, -22.418217868959516 ], [ -59.642555507730492, -22.421266777539756 ], [ -59.700045539170276, -22.421473484014086 ], [ -59.716349452864961, -22.423902275869352 ], [ -59.731051397903684, -22.430930270815338 ], [ -59.737252569650366, -22.43925017695409 ], [ -59.739087084101641, -22.450567314829698 ], [ -59.732963425821424, -22.496921074647901 ], [ -59.732808397089855, -22.50110686568928 ], [ -59.7348237777951, -22.51635141398657 ], [ -59.740973272698341, -22.529012139898327 ], [ -59.934449835691339, -22.795765883188949 ], [ -59.943906623391968, -22.815454604046749 ], [ -59.947368944021548, -22.831681004274913 ], [ -59.947368944021548, -22.857312513561681 ], [ -59.949694383089309, -22.870541681153668 ], [ -59.959047818002375, -22.902219333455491 ], [ -59.960959845920172, -22.913639825017924 ], [ -59.9572133035511, -22.964127699034066 ], [ -59.959564581939901, -23.009809666183173 ], [ -59.952329881418905, -23.057248629820435 ], [ -59.954448614911655, -23.073836765254498 ], [ -59.95971961067147, -23.094403985255724 ], [ -59.987004767256224, -23.162616876267805 ], [ -59.986694708893708, -23.169128105477682 ], [ -59.984575975400958, -23.176156100423725 ], [ -59.976333583627991, -23.194087822994618 ], [ -59.973388027835199, -23.205198256194592 ], [ -59.976617805367425, -23.222199801879356 ], [ -59.987547369615413, -23.251293633594344 ], [ -60.032686734405274, -23.335836276722773 ], [ -60.045140753842702, -23.371699720965353 ], [ -60.054390835069, -23.410870457105887 ], [ -60.063615077873521, -23.499857272794884 ], [ -60.064157681132087, -23.500477389519915 ], [ -60.071960822433994, -23.505386650973151 ], [ -60.171541307385439, -23.554634290640024 ], [ -60.195209112810289, -23.563109225510345 ], [ -60.230168220387043, -23.569362074100468 ], [ -60.553998583068164, -23.586001885478652 ], [ -60.567615321589813, -23.588534031020743 ], [ -60.581206224387756, -23.593805026780558 ], [ -60.612470466438879, -23.609566339015316 ], [ -60.648153041729472, -23.623622328008025 ], [ -60.720086635789585, -23.634371026002043 ], [ -60.733806728897434, -23.638505141099358 ], [ -60.750498216219682, -23.646411635188826 ], [ -60.759412400661745, -23.654938246003269 ], [ -60.765070970049237, -23.66377491607949 ], [ -60.771969773785997, -23.69927662511617 ], [ -60.775819668043255, -23.710748792622667 ], [ -60.788919644426016, -23.731936130248243 ], [ -60.791891038640529, -23.738292331625814 ], [ -60.792666184996449, -23.745010268209342 ], [ -60.787782761964877, -23.873271172826378 ], [ -60.787776137999884, -23.873445156999935 ], [ -60.816851562999972, -23.874097187999965 ], [ -60.837625487999929, -23.871823424999945 ], [ -60.866357584999918, -23.855907083999924 ], [ -60.899947265999856, -23.830482279999927 ], [ -60.936663370999923, -23.813842467999905 ], [ -60.974826416999917, -23.82407440199998 ], [ -61.006349039999861, -23.805470885999924 ], [ -61.015805826999923, -23.796685892999932 ], [ -61.030223550999949, -23.774620055999947 ], [ -61.036243855999885, -23.768832295999871 ], [ -61.038052530999977, -23.755396422999922 ], [ -61.04998978699993, -23.734725850999908 ], [ -61.066216186999924, -23.715708922999937 ], [ -61.092519490999877, -23.701859638999878 ], [ -61.109650227999936, -23.675608011999941 ], [ -61.118848632999942, -23.666409606999935 ], [ -61.10975358099995, -23.649976500999884 ], [ -61.106239583999923, -23.627238871999907 ], [ -61.109856933999907, -23.606981709999985 ], [ -61.122233439999945, -23.598196715999904 ], [ -61.139493367999933, -23.592719013999925 ], [ -61.154453694999916, -23.580316670999949 ], [ -61.167812051999931, -23.566570738999914 ], [ -61.180240233999911, -23.557165628999954 ], [ -61.187733316999953, -23.556235453999903 ], [ -61.207680420999878, -23.557579040999968 ], [ -61.21439835599989, -23.557165628999954 ], [ -61.223570922999983, -23.55127451599995 ], [ -61.24292374699985, -23.533084411999923 ], [ -61.251941283999912, -23.529260354999877 ], [ -61.272611856999902, -23.52357594799993 ], [ -61.282947143999934, -23.509933369999928 ], [ -61.288967448999955, -23.494120380999931 ], [ -61.296951456999921, -23.481407979999886 ], [ -61.361779540999947, -23.454742940999935 ], [ -61.384853067999899, -23.453709411999952 ], [ -61.398676513999959, -23.450092061999968 ], [ -61.408727579999891, -23.443580830999906 ], [ -61.420509806999888, -23.433658955999903 ], [ -61.435702677999927, -23.423737080999913 ], [ -61.451929077999921, -23.417432555999895 ], [ -61.470300048999917, -23.414125264999896 ], [ -61.491849121999877, -23.413195088999942 ], [ -61.501073363999893, -23.407820739999892 ], [ -61.510375122999903, -23.384359638999911 ], [ -61.526343139999938, -23.374747823 ], [ -61.52546463999991, -23.364722594999961 ], [ -61.520787923999933, -23.353250426999949 ], [ -61.51605952999995, -23.344982197999911 ], [ -61.533965413999937, -23.344568785999897 ], [ -61.545773478999934, -23.342605082999867 ], [ -61.554635985999937, -23.33836761499991 ], [ -61.605149699999885, -23.289275003999961 ], [ -61.619619100999898, -23.282867125999928 ], [ -61.666851359999924, -23.282867125999928 ], [ -61.680313069999983, -23.279249775999943 ], [ -61.688762166999879, -23.274495543999947 ], [ -61.704420124999842, -23.258372497999886 ], [ -61.71852779199989, -23.249277444999905 ], [ -61.732997192999903, -23.243386331999901 ], [ -61.744262654999972, -23.234808043999877 ], [ -61.748810180999897, -23.217341410999921 ], [ -61.749481974999895, -23.198841246999905 ], [ -61.752272501999926, -23.187059020999897 ], [ -61.75847367399993, -23.177447204999893 ], [ -61.769274048999961, -23.165561624999953 ], [ -61.78002274699989, -23.156879984999904 ], [ -61.802657022999938, -23.144994404999878 ], [ -61.814284219999905, -23.135175882999903 ], [ -61.836970174999948, -23.104686787999924 ], [ -61.84498002199993, -23.097245381999898 ], [ -61.956446085999914, -23.034406839999917 ], [ -61.992051147999888, -22.998129984999963 ], [ -62.005900430999958, -22.978906351999939 ], [ -62.006055460999903, -22.974358824999911 ], [ -62.008949340999976, -22.969707945999943 ], [ -62.003781697999983, -22.946350198999895 ], [ -62.006055460999903, -22.93684173599992 ], [ -62.017165893999902, -22.921752217999909 ], [ -62.035821085999885, -22.884855244999898 ], [ -62.050445515999854, -22.864494730999951 ], [ -62.071632853999915, -22.843927510999961 ], [ -62.080831258999922, -22.832351988999918 ], [ -62.084603637999948, -22.820156350999909 ], [ -62.08935786999993, -22.819949645999955 ], [ -62.099228068999906, -22.81374847399988 ], [ -62.107858031999854, -22.80651377399991 ], [ -62.108788207999908, -22.80299977599995 ], [ -62.115867879999939, -22.799795836999877 ], [ -62.119743611999894, -22.792147724999907 ], [ -62.122534139999942, -22.783156026999862 ], [ -62.126151489999927, -22.775714619999931 ], [ -62.153488322999948, -22.747809345999954 ], [ -62.159741169999847, -22.737164000999954 ], [ -62.164081990999932, -22.725898538999985 ], [ -62.170799926999877, -22.717320250999961 ], [ -62.184184122999909, -22.713702900999891 ], [ -62.188266560999892, -22.70832855299993 ], [ -62.175915893999843, -22.684867451999949 ], [ -62.195036173999938, -22.67360198999998 ], [ -62.194622762999927, -22.660579528999861 ], [ -62.187646443999938, -22.638565368999963 ], [ -62.192969116999876, -22.628230081999959 ], [ -62.196586466999861, -22.626473083999983 ], [ -62.202529256999895, -22.627196552999891 ], [ -62.214931599999943, -22.624302672999903 ], [ -62.239736287999904, -22.613760680999931 ], [ -62.25281042499995, -22.603632100999974 ], [ -62.252965454999895, -22.59112640299989 ], [ -62.238857788999951, -22.573039651999878 ], [ -62.233225056999913, -22.556296487999916 ], [ -62.241183227999983, -22.538416442999861 ], [ -62.263352416999908, -22.51443857799994 ], [ -62.268830118999887, -22.512991638999949 ], [ -62.275599731999932, -22.513508401999985 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-15", "NAME_1": "Presidente Hayes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -60.689675862999934, -23.89363087999989 ], [ -60.699416870999869, -23.891253763999927 ], [ -60.719854898999927, -23.875027363999919 ], [ -60.729285848999979, -23.872133483999932 ], [ -60.787776137999884, -23.873445156999935 ], [ -60.787782761964877, -23.873271172826378 ], [ -60.792666184996449, -23.745010268209342 ], [ -60.791891038640529, -23.738292331625814 ], [ -60.788919644426016, -23.731936130248243 ], [ -60.775819668043255, -23.710748792622667 ], [ -60.771969773785997, -23.69927662511617 ], [ -60.765070970049237, -23.66377491607949 ], [ -60.759412400661745, -23.654938246003269 ], [ -60.750498216219682, -23.646411635188826 ], [ -60.733806728897434, -23.638505141099358 ], [ -60.720086635789585, -23.634371026002043 ], [ -60.648153041729472, -23.623622328008025 ], [ -60.612470466438879, -23.609566339015316 ], [ -60.581206224387756, -23.593805026780558 ], [ -60.567615321589813, -23.588534031020743 ], [ -60.553998583068164, -23.586001885478652 ], [ -60.230168220387043, -23.569362074100468 ], [ -60.195209112810289, -23.563109225510345 ], [ -60.171541307385439, -23.554634290640024 ], [ -60.071960822433994, -23.505386650973151 ], [ -60.064157681132087, -23.500477389519915 ], [ -60.063615077873521, -23.499857272794884 ], [ -60.054390835069, -23.410870457105887 ], [ -60.045140753842702, -23.371699720965353 ], [ -60.032686734405274, -23.335836276722773 ], [ -59.987547369615413, -23.251293633594344 ], [ -59.976617805367425, -23.222199801879356 ], [ -59.973388027835199, -23.205198256194592 ], [ -59.976333583627991, -23.194087822994618 ], [ -59.984575975400958, -23.176156100423725 ], [ -59.986694708893708, -23.169128105477682 ], [ -59.987004767256224, -23.162616876267805 ], [ -59.95971961067147, -23.094403985255724 ], [ -59.954448614911655, -23.073836765254498 ], [ -59.952329881418905, -23.057248629820435 ], [ -59.959564581939901, -23.009809666183173 ], [ -59.9572133035511, -22.964127699034066 ], [ -59.960959845920172, -22.913639825017924 ], [ -59.959047818002375, -22.902219333455491 ], [ -59.949694383089309, -22.870541681153668 ], [ -59.947368944021548, -22.857312513561681 ], [ -59.947368944021548, -22.831681004274913 ], [ -59.943906623391968, -22.815454604046749 ], [ -59.934449835691339, -22.795765883188949 ], [ -59.740973272698341, -22.529012139898327 ], [ -59.7348237777951, -22.51635141398657 ], [ -59.732808397089855, -22.50110686568928 ], [ -59.732963425821424, -22.496921074647901 ], [ -59.739087084101641, -22.450567314829698 ], [ -59.737252569650366, -22.43925017695409 ], [ -59.731051397903684, -22.430930270815338 ], [ -59.716349452864961, -22.423902275869352 ], [ -59.700045539170276, -22.421473484014086 ], [ -59.642555507730492, -22.421266777539756 ], [ -59.627440152441068, -22.418217868959516 ], [ -59.61648474797272, -22.412016697212835 ], [ -59.609250046552404, -22.398890883307615 ], [ -59.608113165889904, -22.391294447580719 ], [ -59.609560105814239, -22.384938246203092 ], [ -59.622634242876018, -22.361115411147296 ], [ -59.624830491633872, -22.353157240214443 ], [ -59.625114711574668, -22.345664158174372 ], [ -59.623564418862827, -22.33538054817376 ], [ -59.621600715000966, -22.329696139465284 ], [ -59.616252203976046, -22.318534031220565 ], [ -59.607854784370772, -22.307526950808153 ], [ -59.59452226399128, -22.295641371252259 ], [ -59.491763679250369, -22.238073825446691 ], [ -59.477604335671572, -22.23326791768028 ], [ -59.464065110616332, -22.230219008200663 ], [ -59.45365231030587, -22.235128268754579 ], [ -59.445875007425627, -22.240347588570387 ], [ -59.436521571613241, -22.248719170653203 ], [ -59.428770108054039, -22.253990167312395 ], [ -59.420553554702792, -22.258537692660411 ], [ -59.413990647750211, -22.26039804463403 ], [ -59.408590460781113, -22.259932956640625 ], [ -59.384741787303653, -22.249390964221618 ], [ -59.322600877728291, -22.213785903296809 ], [ -59.307588874327053, -22.201435234848191 ], [ -59.304204068063257, -22.195647475150849 ], [ -59.307072110389583, -22.182056573252282 ], [ -59.342289597686772, -22.083044529081747 ], [ -59.230151739611074, -22.14092213324983 ], [ -59.192402105872475, -22.155288180605055 ], [ -59.168811814813409, -22.161024265257652 ], [ -59.15261125300691, -22.162212822763536 ], [ -58.998434618262991, -22.156838474216215 ], [ -58.785062628837238, -22.17352996153852 ], [ -58.732972785265815, -22.168103936147759 ], [ -58.263234016236879, -22.198024591062051 ], [ -58.237654181994913, -22.204639173958697 ], [ -58.223494839315379, -22.214509372809289 ], [ -58.216363490682568, -22.262103366976817 ], [ -58.20830196786153, -22.272231948245803 ], [ -58.194090949237932, -22.280913587791872 ], [ -57.848969896143785, -22.423023776725927 ], [ -57.843414680443118, -22.446019788582362 ], [ -57.830573085579431, -22.559191175432431 ], [ -57.816103685436701, -22.589990329490092 ], [ -57.79065304240396, -22.617378838862351 ], [ -57.779671800413269, -22.634018650240534 ], [ -57.775150112587596, -22.655464368485809 ], [ -57.78471025307573, -22.665282892291657 ], [ -57.806905280154524, -22.665747978486422 ], [ -57.850235968914831, -22.658926690014709 ], [ -57.895814582377056, -22.664869480242317 ], [ -57.92922339544333, -22.686470229017857 ], [ -57.940204637434078, -22.716339207088765 ], [ -57.918526374292753, -22.747035006560282 ], [ -57.908862881017114, -22.751220797601718 ], [ -57.885970221948185, -22.756956882254315 ], [ -57.877546963021928, -22.761917819651671 ], [ -57.872043423265382, -22.771788017602944 ], [ -57.867030809024584, -22.795300795195544 ], [ -57.860803798856239, -22.806307874708637 ], [ -57.851760423204951, -22.810441989806009 ], [ -57.828867764136021, -22.809253432300068 ], [ -57.819514330122217, -22.813129164079669 ], [ -57.811943731917665, -22.821294040587532 ], [ -57.808920660859826, -22.826410006716458 ], [ -57.802435269172349, -22.843876642193266 ], [ -57.792358363847427, -22.856847425568219 ], [ -57.788379279280321, -22.866045830850396 ], [ -57.789412808054635, -22.877983087249675 ], [ -57.798068610078303, -22.887956637988452 ], [ -57.81127193924857, -22.896948336796299 ], [ -57.821038784412337, -22.905940036503466 ], [ -57.819514330122217, -22.915861912197499 ], [ -57.786002163369119, -22.944749036538781 ], [ -57.772928026307341, -22.960717055247926 ], [ -57.767682868069926, -22.981646009555675 ], [ -57.789412808054635, -23.021385185577856 ], [ -57.774374966231676, -23.034821058744853 ], [ -57.729881558387206, -23.054819837965169 ], [ -57.720528124373459, -23.066395359158491 ], [ -57.714068570208326, -23.085153904029426 ], [ -57.698178066764342, -23.090683282207692 ], [ -57.658464728264562, -23.090889987782703 ], [ -57.639861213024574, -23.098796481872171 ], [ -57.632058071722611, -23.111147148522093 ], [ -57.630636970219996, -23.127993665475287 ], [ -57.631127895735801, -23.148922620682413 ], [ -57.624616664727284, -23.165304049642202 ], [ -57.608596970973451, -23.179980157158525 ], [ -57.58849483896563, -23.192072442289373 ], [ -57.550926073279641, -23.208815605555742 ], [ -57.544363166327059, -23.213156427127387 ], [ -57.535552333773182, -23.220649509167515 ], [ -57.511161057936476, -23.250208428875908 ], [ -57.500567389573348, -23.257856540546925 ], [ -57.484030930982669, -23.273049412000773 ], [ -57.480310227934638, -23.278992200429684 ], [ -57.480181036725469, -23.30054127416048 ], [ -57.482093064643209, -23.306380710701262 ], [ -57.48713151730567, -23.316819349433445 ], [ -57.495528936910887, -23.330255221701123 ], [ -57.501445888716773, -23.336714775866199 ], [ -57.503667974997029, -23.343536065237231 ], [ -57.500799932670759, -23.35779876070427 ], [ -57.494779628976687, -23.367720635498927 ], [ -57.477183804089293, -23.382706800478445 ], [ -57.470388353139981, -23.393868909622483 ], [ -57.456719936875572, -23.403894138103965 ], [ -57.453619350552572, -23.409320163494726 ], [ -57.452740851409146, -23.417330011271019 ], [ -57.446177945355885, -23.447198988442551 ], [ -57.442457241408533, -23.45743092159978 ], [ -57.442173020568418, -23.46471729896416 ], [ -57.446177945355885, -23.474484145027247 ], [ -57.448245002005251, -23.485956312533801 ], [ -57.457029995238088, -23.504663180561352 ], [ -57.459820523198573, -23.515463556298073 ], [ -57.459639655145963, -23.527710870160547 ], [ -57.454859584901897, -23.548898206886747 ], [ -57.453619350552572, -23.559853610455775 ], [ -57.450415412341385, -23.573806247560299 ], [ -57.425688238821181, -23.617886244254748 ], [ -57.397989671086464, -23.645636488832906 ], [ -57.325875209873004, -23.682791842469555 ], [ -57.295334439133057, -23.707234796049022 ], [ -57.280348273254219, -23.723409518534481 ], [ -57.275826586327867, -23.731522719098223 ], [ -57.275490688644368, -23.742013034673789 ], [ -57.281175095554204, -23.751314792743472 ], [ -57.299003465337648, -23.757670994121099 ], [ -57.302801682751465, -23.765267428948675 ], [ -57.299416877386989, -23.774982599067698 ], [ -57.291923794447541, -23.782062269957805 ], [ -57.284430710608774, -23.787695000923577 ], [ -57.281071742766699, -23.793224379101844 ], [ -57.281588507603544, -23.800975843560309 ], [ -57.288513149762025, -23.830741468843712 ], [ -57.291303676823247, -23.861850681263945 ], [ -57.295334439133057, -23.871720880114538 ], [ -57.318149583836203, -23.885931898738136 ], [ -57.322051154037524, -23.889084161005201 ], [ -57.3254101218796, -23.894096775245998 ], [ -57.332903204819047, -23.901538180442685 ], [ -57.340396287758438, -23.911305026505772 ], [ -57.34375525560057, -23.923242282905051 ], [ -57.338561774206482, -23.930476982526727 ], [ -57.326443650653971, -23.932233981712898 ], [ -57.312749395967842, -23.932182305768777 ], [ -57.302801682751465, -23.933784274424738 ], [ -57.284482388351535, -23.954041436063449 ], [ -57.279883185260758, -23.978794448005374 ], [ -57.278048671708802, -24.00509775175982 ], [ -57.268049281649041, -24.030005791534052 ], [ -57.248360561690561, -24.023649591055801 ], [ -57.231772427155761, -24.033364760275447 ], [ -57.22389177058875, -24.050728041166167 ], [ -57.230480515963052, -24.06695444049501 ], [ -57.236733363653798, -24.075842786515409 ], [ -57.237870246114937, -24.086178074258726 ], [ -57.233581102286053, -24.094704685073168 ], [ -57.223659226592019, -24.098270358490254 ], [ -57.187924973558665, -24.096203301840887 ], [ -57.178649054810023, -24.098270358490254 ], [ -57.163016933784434, -24.117442314511209 ], [ -57.172189500644947, -24.137079359424888 ], [ -57.189681972744836, -24.156768080282689 ], [ -57.197821010830978, -24.173562921291762 ], [ -57.215907762133497, -24.192631523625892 ], [ -57.219731817969034, -24.197902520285083 ], [ -57.220713669899965, -24.202036634483079 ], [ -57.221101244426904, -24.207979424710686 ], [ -57.219809333234139, -24.22079518025339 ], [ -57.216863775642707, -24.229321791067832 ], [ -57.212548794291422, -24.236711521219718 ], [ -57.193402675792868, -24.255935154084113 ], [ -57.185599535390224, -24.26642546965968 ], [ -57.174850837396207, -24.285028984899725 ], [ -57.170949266295622, -24.297999770073318 ], [ -57.165239020064689, -24.359908135651949 ], [ -57.157410041240382, -24.389518731304406 ], [ -57.1466096673023, -24.460677179008599 ], [ -57.141958788267459, -24.474939873576318 ], [ -57.130538295805707, -24.500106295768944 ], [ -57.132191942204372, -24.509873141832031 ], [ -57.141183641012219, -24.541912530239074 ], [ -57.14565365289377, -24.58289194061058 ], [ -57.144904344060251, -24.602994072618344 ], [ -57.141080288224714, -24.616326592997893 ], [ -57.133974778912886, -24.628832289278705 ], [ -57.126610887182665, -24.641441339246398 ], [ -57.113175014914987, -24.64898609812991 ], [ -57.097517056367053, -24.66154347125422 ], [ -57.090669928574357, -24.677459812220548 ], [ -57.112141486140672, -24.717509046605244 ], [ -57.116663173966288, -24.736422621107067 ], [ -57.12232174335378, -24.752028903710936 ], [ -57.137695481960918, -24.762415866499055 ], [ -57.149374355941745, -24.763035984123348 ], [ -57.158081834808797, -24.759625338538569 ], [ -57.16681515209757, -24.757661634676708 ], [ -57.178649054810023, -24.762415866499055 ], [ -57.181904669864593, -24.769495538288481 ], [ -57.197149217262563, -24.826753024832215 ], [ -57.248670620053076, -24.891451917472011 ], [ -57.248438076056345, -24.897239678967992 ], [ -57.240092333294513, -24.906438084250169 ], [ -57.231178147953131, -24.907368258438396 ], [ -57.222522345929519, -24.901942233946954 ], [ -57.216011114921002, -24.901373793166044 ], [ -57.213427294334167, -24.916980075769857 ], [ -57.215623542192702, -24.928193861757336 ], [ -57.218956671613114, -24.937392267039513 ], [ -57.218698290093982, -24.946590670523051 ], [ -57.210016648749331, -24.957959487040682 ], [ -57.198492805298713, -24.969741712909752 ], [ -57.194797939773082, -24.978113294992568 ], [ -57.199526333173708, -24.984211113951744 ], [ -57.213427294334167, -24.988965345774091 ], [ -57.234666307004431, -24.986433201131319 ], [ -57.261873949223343, -24.980025322910308 ], [ -57.285386725017361, -24.982454115664893 ], [ -57.295334439133057, -25.006018569201615 ], [ -57.34375525560057, -25.064671318826299 ], [ -57.354116379966968, -25.07200937303412 ], [ -57.366131150732031, -25.078520603143318 ], [ -57.377965054343804, -25.083326510909728 ], [ -57.387835252295076, -25.085186862883404 ], [ -57.396206835277212, -25.089424329868905 ], [ -57.414862027360641, -25.10823455158328 ], [ -57.422277595034984, -25.112472018568781 ], [ -57.454988776111122, -25.112472018568781 ], [ -57.483720872620154, -25.112472018568781 ], [ -57.511781174661451, -25.106994317233955 ], [ -57.52377010790417, -25.109164726670826 ], [ -57.52873104530147, -25.122703952625329 ], [ -57.532270881196212, -25.148077081292286 ], [ -57.541520962422453, -25.175620618496737 ], [ -57.554595100383551, -25.201613864788044 ], [ -57.569684618150575, -25.222336113520839 ], [ -57.583456387202489, -25.234428398651687 ], [ -57.595884569117572, -25.240216160147668 ], [ -57.624306607264089, -25.248432712599595 ], [ -57.639163581034438, -25.256184177058117 ], [ -57.65053239575343, -25.265485935127799 ], [ -57.671975553999886, -25.289830980999923 ], [ -57.702338826999949, -25.270911152999901 ], [ -57.721769164999927, -25.246106465999958 ], [ -57.754066934999912, -25.18089080799993 ], [ -57.76600419199994, -25.167868346999896 ], [ -57.797320109999959, -25.153915709999907 ], [ -57.812409627999955, -25.143683776999922 ], [ -57.85648962399992, -25.096761575999977 ], [ -57.870700643999982, -25.085289407999952 ], [ -57.890492715999869, -25.078674824999965 ], [ -57.9697643639999, -25.078468119999911 ], [ -57.983768676999915, -25.074230651999954 ], [ -57.989866495999962, -25.064102070999908 ], [ -57.993638875999892, -25.052733255999911 ], [ -58.000460164999936, -25.044361673999944 ], [ -58.009813598999898, -25.042501322999939 ], [ -58.032137816999949, -25.045085143999941 ], [ -58.042059692999942, -25.044361673999944 ], [ -58.111512817999909, -25.012322285999929 ], [ -58.124018514999932, -25.012942402999911 ], [ -58.133888712999891, -24.997852884999901 ], [ -58.224064087999892, -24.941215514999911 ], [ -58.242512572999914, -24.94173227899995 ], [ -58.259152384999936, -24.952997741999923 ], [ -58.287264363999981, -24.979766133999888 ], [ -58.299304972999948, -24.987724303999954 ], [ -58.311965698999899, -24.993615416999944 ], [ -58.32328283699988, -24.995269064 ], [ -58.335995238999914, -24.991858418999882 ], [ -58.34131791199988, -24.986174010999932 ], [ -58.34436682099988, -24.978319193999894 ], [ -58.350567992999885, -24.968604023999958 ], [ -58.414801798999918, -24.903078307999948 ], [ -58.438521280999879, -24.872795918999927 ], [ -58.450768595999904, -24.861737161999926 ], [ -58.473402872999941, -24.851298522999883 ], [ -58.694216267999934, -24.812024434999913 ], [ -58.699383911999945, -24.807270202999916 ], [ -58.701916055999845, -24.79931203199996 ], [ -58.708117227999935, -24.795074564999908 ], [ -58.715972045999962, -24.791870625999934 ], [ -58.723258423999937, -24.786702982999927 ], [ -58.737469441999906, -24.782775572999967 ], [ -58.788474080999947, -24.781638691999959 ], [ -58.809196329999878, -24.776781106999934 ], [ -59.000915893999974, -24.644179381999905 ], [ -59.032696899999905, -24.637048034999879 ], [ -59.042412068999852, -24.630536803999902 ], [ -59.062462524999916, -24.612346699999961 ], [ -59.072177693999947, -24.606765644999939 ], [ -59.078327189999925, -24.605628762999928 ], [ -59.097189087999936, -24.605422057999888 ], [ -59.116981160999927, -24.598807474999973 ], [ -59.154394897999879, -24.57627654999996 ], [ -59.177907674999886, -24.568731790999905 ], [ -59.20648474199993, -24.550231628999981 ], [ -59.248084269999936, -24.537209167999947 ], [ -59.257644408999937, -24.530181172999932 ], [ -59.263122111999934, -24.523463235999913 ], [ -59.270460164999918, -24.518192239999877 ], [ -59.28560135999993, -24.516125182999915 ], [ -59.295058145999889, -24.512921244999944 ], [ -59.308080606999937, -24.498761901999984 ], [ -59.34097265699998, -24.487599792999958 ], [ -59.357405761999928, -24.468996276999917 ], [ -59.377766276999864, -24.43354624399997 ], [ -59.387093871999895, -24.423831074999939 ], [ -59.426032064999902, -24.392515156999934 ], [ -59.450268310999974, -24.382386575999888 ], [ -59.453808146999933, -24.374531758999936 ], [ -59.45628861499992, -24.365436705999883 ], [ -59.45972509799995, -24.358512064999985 ], [ -59.465900431999927, -24.353551126999946 ], [ -59.487656208999937, -24.344766132999951 ], [ -59.51041967799992, -24.33267384799997 ], [ -59.521142537999935, -24.325025736999891 ], [ -59.532020426999878, -24.314070332999918 ], [ -59.539978597999948, -24.308799335999893 ], [ -59.558427082999856, -24.305388691999951 ], [ -59.575402791999863, -24.295880228999877 ], [ -59.600517537999906, -24.292882994999957 ], [ -59.610516927999925, -24.289575703999958 ], [ -59.617725789999952, -24.283477884999911 ], [ -59.635321614999953, -24.261463724999928 ], [ -59.673639688999856, -24.225393574999927 ], [ -60.033669392999883, -24.007008971999895 ], [ -60.0517303069999, -24.002874857999956 ], [ -60.072375040999901, -24.004838561999904 ], [ -60.119297241999845, -24.020238138999972 ], [ -60.143249267999863, -24.025199075999922 ], [ -60.218128418999896, -24.027369486999916 ], [ -60.296418212999868, -24.016414082999944 ], [ -60.328018350999855, -24.017964375999952 ], [ -60.337371785999892, -24.016414082999944 ], [ -60.348042968999891, -24.010833027999922 ], [ -60.367576659999912, -23.994709980999943 ], [ -60.378351196999944, -23.988508809999956 ], [ -60.387420410999908, -23.987165221999902 ], [ -60.423051310999881, -23.988508809999956 ], [ -60.484882161999877, -23.977346699999927 ], [ -60.517722533999915, -23.955745951999958 ], [ -60.535964314999944, -23.947581074999931 ], [ -60.571750243999901, -23.946030781999923 ], [ -60.577538004999951, -23.944170430999918 ], [ -60.593583536999915, -23.912234394999928 ], [ -60.594617065999898, -23.906549987999895 ], [ -60.603841308999904, -23.904689635999972 ], [ -60.621152913999907, -23.895801289999966 ], [ -60.632159993999892, -23.89228729299991 ], [ -60.643709676999947, -23.891357116999956 ], [ -60.689675862999934, -23.89363087999989 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-11", "NAME_1": "Central" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -57.638776814999886, -25.615799661999901 ], [ -57.623067179999907, -25.61538625099989 ], [ -57.616297566999975, -25.609185078999914 ], [ -57.611646687999894, -25.585930683999976 ], [ -57.600691283999936, -25.578799336999865 ], [ -57.587152058999948, -25.575698750999905 ], [ -57.575318156999941, -25.56443328899995 ], [ -57.570047159999916, -25.54665659599992 ], [ -57.556921345999939, -25.459840189999923 ], [ -57.558109904999952, -25.443510436999901 ], [ -57.565292927999906, -25.430384622999924 ], [ -57.57872879999988, -25.416742044999921 ], [ -57.597541973109344, -25.403364485000488 ], [ -57.574018824309292, -25.383359189874739 ], [ -57.549115211897515, -25.358455577462905 ], [ -57.53915376693277, -25.318609797604097 ], [ -57.544134489415171, -25.281254378986375 ], [ -57.559076656862203, -25.256350766574599 ], [ -57.583456387202489, -25.234428398651687 ], [ -57.569684618150575, -25.222336113520839 ], [ -57.554595100383551, -25.201613864788044 ], [ -57.541520962422453, -25.175620618496737 ], [ -57.532270881196212, -25.148077081292286 ], [ -57.52873104530147, -25.122703952625329 ], [ -57.52377010790417, -25.109164726670826 ], [ -57.511781174661451, -25.106994317233955 ], [ -57.483720872620154, -25.112472018568781 ], [ -57.454988776111122, -25.112472018568781 ], [ -57.432251145773762, -25.143064467051488 ], [ -57.429021369140855, -25.145906670956094 ], [ -57.388791265804286, -25.169367770805991 ], [ -57.379153611849688, -25.178101088094763 ], [ -57.348509488322236, -25.225850111893124 ], [ -57.318227098201987, -25.255925794639722 ], [ -57.305669725077735, -25.273237399586321 ], [ -57.300243699686973, -25.286053155129025 ], [ -57.297479011047528, -25.301039321007863 ], [ -57.291303676823247, -25.320262952972882 ], [ -57.256628790985928, -25.377830498778508 ], [ -57.246629400926111, -25.39018116542843 ], [ -57.240144009238634, -25.394832044463271 ], [ -57.233090175870927, -25.397364190005362 ], [ -57.226217210555831, -25.397312514061298 ], [ -57.220093553174934, -25.395813897293522 ], [ -57.216295335761117, -25.393333428594872 ], [ -57.209344855180916, -25.387442315210706 ], [ -57.204099696943445, -25.384186700156079 ], [ -57.199681362804654, -25.383049818594259 ], [ -57.193402675792868, -25.38366993621861 ], [ -57.182111376338923, -25.395038750937601 ], [ -57.161750861013445, -25.425321140158474 ], [ -57.202626918597389, -25.448368828858349 ], [ -57.231643235946592, -25.47208831112664 ], [ -57.238335334108399, -25.479684746853593 ], [ -57.32256791887437, -25.602622978867373 ], [ -57.355072394375497, -25.636884453554671 ], [ -57.390703293722027, -25.66830372523674 ], [ -57.402640550121305, -25.683496595791269 ], [ -57.413518439324491, -25.703598727799033 ], [ -57.425998298082959, -25.738118584904782 ], [ -57.429796516396095, -25.767625827769734 ], [ -57.42832373715072, -25.789950046057754 ], [ -57.40504350355485, -25.858421318588967 ], [ -57.40310563811471, -25.876094658741522 ], [ -57.407007209215351, -25.897798761203887 ], [ -57.433775600963202, -25.943997490491768 ], [ -57.456694099353172, -25.970610853508106 ], [ -57.503590460631244, -26.011073499942086 ], [ -57.516716275435783, -25.982754814583018 ], [ -57.541960211994194, -25.952885838310806 ], [ -57.547515427694805, -25.943067314504958 ], [ -57.550486822808637, -25.934437350903011 ], [ -57.552037116419797, -25.923895358484003 ], [ -57.555344408317808, -25.917694186737322 ], [ -57.559607712825652, -25.913094984545921 ], [ -57.579942389729467, -25.905085137668948 ], [ -57.590458543726811, -25.899762465065692 ], [ -57.616865200268762, -25.879350273796092 ], [ -57.640222948230473, -25.865759372796845 ], [ -57.662237108156035, -25.848241062275179 ], [ -57.675724657267097, -25.835115247470696 ], [ -57.68926388232228, -25.818733818510907 ], [ -57.697196213934092, -25.81263599955173 ], [ -57.703836636151834, -25.80974211970306 ], [ -57.71008948384258, -25.809845472490565 ], [ -57.731225144624716, -25.814237970006332 ], [ -57.737426317270717, -25.814806409887922 ], [ -57.74424760574243, -25.81377288201287 ], [ -57.764246384962689, -25.807106622272784 ], [ -57.769362351990935, -25.806589857435995 ], [ -57.774064906969897, -25.807416680635299 ], [ -57.778121506802108, -25.8105172669583 ], [ -57.780524461134974, -25.814961439518811 ], [ -57.781299608390214, -25.823177991970738 ], [ -57.780111049984953, -25.840024508923932 ], [ -57.780421109246788, -25.847000827925854 ], [ -57.781583828331009, -25.851238294911411 ], [ -57.787139044930996, -25.85444223402186 ], [ -57.792255011959242, -25.856147555465327 ], [ -57.816336229433432, -25.85134164769886 ], [ -57.819661966426622, -25.849779220434698 ], [ -57.812823039999955, -25.845243021999948 ], [ -57.801867634999979, -25.831393737999889 ], [ -57.817060506999923, -25.797493997999965 ], [ -57.820626179999891, -25.778270364999941 ], [ -57.805588338999911, -25.769898782999874 ], [ -57.787243204999925, -25.764111022999899 ], [ -57.767916219999876, -25.75067514999995 ], [ -57.751069702999899, -25.734862161999956 ], [ -57.740372680999883, -25.722149759999908 ], [ -57.751121378999898, -25.719565937999903 ], [ -57.760578165999874, -25.715638528999932 ], [ -57.768484659999928, -25.709954121999985 ], [ -57.774582478999974, -25.701685891999944 ], [ -57.753705199999899, -25.672747089999888 ], [ -57.74125118099991, -25.66189503899993 ], [ -57.719908812999932, -25.653833516999939 ], [ -57.70869502799988, -25.652903340999984 ], [ -57.698204711999921, -25.653626810999882 ], [ -57.688334513999848, -25.652696634999927 ], [ -57.678981079999915, -25.647012226999976 ], [ -57.675260375999898, -25.639260762999882 ], [ -57.670041056999963, -25.616936543999913 ], [ -57.668077351999926, -25.612285664999945 ], [ -57.638776814999886, -25.615799661999901 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-ASU", "NAME_1": "Asunción" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -57.597541973109344, -25.403364485000488 ], [ -57.640792195999921, -25.372610371999926 ], [ -57.641205607999922, -25.360518086999946 ], [ -57.671487996999957, -25.290134785999925 ], [ -57.671975553999886, -25.289830980999923 ], [ -57.65053239575343, -25.265485935127799 ], [ -57.639163581034438, -25.256184177058117 ], [ -57.624306607264089, -25.248432712599595 ], [ -57.595884569117572, -25.240216160147668 ], [ -57.583456387202489, -25.234428398651687 ], [ -57.559076656862203, -25.256350766574599 ], [ -57.544134489415171, -25.281254378986375 ], [ -57.53915376693277, -25.318609797604097 ], [ -57.549115211897515, -25.358455577462905 ], [ -57.574018824309292, -25.383359189874739 ], [ -57.597541973109344, -25.403364485000488 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-10", "NAME_1": "Alto Paraná" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -54.60020261299988, -25.574944883999891 ], [ -54.602217976999924, -25.592441914999952 ], [ -54.58624995999989, -25.624688008999925 ], [ -54.583356078999913, -25.6448418169999 ], [ -54.598497273999925, -25.653833516999939 ], [ -54.633714762999972, -25.652076516999955 ], [ -54.642887329999979, -25.661584980999947 ], [ -54.643145710999931, -25.687939961999902 ], [ -54.624929768999891, -25.740236510999921 ], [ -54.622061726999931, -25.759976908999889 ], [ -54.617152465999879, -25.773516133999948 ], [ -54.594518188999928, -25.798734232999905 ], [ -54.587903604999923, -25.810826517999899 ], [ -54.589557250999889, -25.832944029999908 ], [ -54.599220743999922, -25.850720722999938 ], [ -54.610072794999951, -25.866533711999935 ], [ -54.615240437999972, -25.882863464999957 ], [ -54.607333943999919, -25.927925312999918 ], [ -54.60640376799995, -25.946632181999902 ], [ -54.615240437999972, -25.961721699999899 ], [ -54.623689533999965, -25.964305520999901 ], [ -54.647951619999873, -25.96564910899987 ], [ -54.656194010999883, -25.969163105999911 ], [ -54.662265990999941, -25.97991180399994 ], [ -54.66159419799996, -25.989937031999958 ], [ -54.658261067999945, -26.000375670999901 ], [ -54.653325968999923, -26.030761412999951 ], [ -54.642525594999967, -26.06280080199987 ], [ -54.643145710999931, -26.085228373999954 ], [ -54.66381628399995, -26.149203796999927 ], [ -54.65994055199991, -26.164396666999963 ], [ -54.641853800999911, -26.184033710999898 ], [ -54.638288126999925, -26.196952819999908 ], [ -54.644696004999872, -26.208218281999876 ], [ -54.656194010999883, -26.22299774199989 ], [ -54.664333048999907, -26.236226908999882 ], [ -54.664973817999908, -26.238863213999963 ], [ -54.665598314110923, -26.238863213566447 ], [ -54.667432826763559, -26.238863213566447 ], [ -54.724457770209938, -26.23467742252501 ], [ -54.735542364988135, -26.232300306613865 ], [ -54.741562668682207, -26.226099134867184 ], [ -54.743500535920987, -26.219639580702108 ], [ -54.743707240596677, -26.2132833802238 ], [ -54.742518683090736, -26.206307061221878 ], [ -54.742518683090736, -26.201346123824578 ], [ -54.743552211865051, -26.197160332783142 ], [ -54.745981003720317, -26.194111423303525 ], [ -54.749908413242679, -26.19059742583056 ], [ -54.755024380270925, -26.187341810775933 ], [ -54.77419633629188, -26.178453463856272 ], [ -54.788820766964818, -26.173492526458915 ], [ -54.807811855832483, -26.170081881773399 ], [ -54.823340624070511, -26.170288588247729 ], [ -54.831298794104043, -26.1724589976846 ], [ -54.839773728974421, -26.176593112781916 ], [ -54.853209601242099, -26.187031751514098 ], [ -54.859023200260481, -26.190442397098934 ], [ -54.864604255282131, -26.192509453748301 ], [ -54.872174851688044, -26.192716160222631 ], [ -54.879900478624165, -26.190442397098934 ], [ -54.889202236693848, -26.183621107727959 ], [ -54.89157935170573, -26.178453463856272 ], [ -54.890959234980699, -26.171632174485239 ], [ -54.886695929573477, -26.157317803973456 ], [ -54.886075811949183, -26.152150160101826 ], [ -54.886747606416918, -26.147550957910369 ], [ -54.888478766282049, -26.144760430849203 ], [ -54.891605191026713, -26.143468519656437 ], [ -54.896075202008944, -26.143313490924868 ], [ -54.902353889020731, -26.145690605936693 ], [ -54.907056443999693, -26.14894622189064 ], [ -54.912689174965465, -26.154992364006375 ], [ -54.919975552329845, -26.164655857282014 ], [ -54.935090907619269, -26.189512221112125 ], [ -54.939250861138305, -26.194266452934471 ], [ -54.946123827352721, -26.200260919106142 ], [ -54.952945115824434, -26.204136650885744 ], [ -54.959042934783611, -26.206513766796888 ], [ -54.972582159838794, -26.209407646645559 ], [ -55.005655077020208, -26.212198174606101 ], [ -55.012217983972789, -26.218554375983672 ], [ -55.016145391696455, -26.223205255018513 ], [ -55.01911678681023, -26.23028492590862 ], [ -55.020951301261562, -26.232610365875701 ], [ -55.023431769060892, -26.234522393793441 ], [ -55.027255824896372, -26.236951185648707 ], [ -55.03343115912071, -26.236331068923676 ], [ -55.041363490732522, -26.232920424238216 ], [ -55.056763067761381, -26.222378431819152 ], [ -55.067253384236267, -26.216849053640942 ], [ -55.09949947821832, -26.209407646645559 ], [ -55.124795090720852, -26.199640801481792 ], [ -55.134639452049043, -26.197160332783142 ], [ -55.142752651713522, -26.195765068802871 ], [ -55.162544725358771, -26.194834893715381 ], [ -55.23675208164326, -26.198245537501577 ], [ -55.257500168797719, -26.180313815829948 ], [ -55.291451585122559, -26.083317153264034 ], [ -55.23920671192019, -26.05546355589837 ], [ -55.230938482624879, -26.048228854478054 ], [ -55.226390957276863, -26.038875420464308 ], [ -55.226675178116977, -26.030503839280755 ], [ -55.232979701751844, -26.023114109128812 ], [ -55.239387579972856, -26.019703463544033 ], [ -55.246880662912247, -26.017894789313061 ], [ -55.266104294877323, -26.016499526232167 ], [ -55.274036628287774, -26.013864027902571 ], [ -55.280392828766026, -26.009368177599299 ], [ -55.285715502268602, -26.004045504996043 ], [ -55.289126146054798, -25.999911390798047 ], [ -55.293337774618578, -25.995673922913227 ], [ -55.29933224079025, -25.991591484659295 ], [ -55.305275031017857, -25.990661309571806 ], [ -55.337004361062384, -25.999291274073016 ], [ -55.354677700315619, -26.002391859496697 ], [ -55.383203091249641, -26.004045504996043 ], [ -55.407361823089673, -26.003167005852617 ], [ -55.41575924269489, -26.004407241101319 ], [ -55.429014247809278, -26.010298353586165 ], [ -55.436455654804604, -26.00905811923684 ], [ -55.444387987315736, -26.006267592175618 ], [ -55.45779802116175, -25.999704685223037 ], [ -55.499165005160876, -25.984563490612629 ], [ -55.503867560139781, -25.981359551502123 ], [ -55.509629483214098, -25.97355641020016 ], [ -55.513117642265399, -25.962756036262078 ], [ -55.509655320736442, -25.935264174102372 ], [ -55.509577806370658, -25.925910740088568 ], [ -55.516166550845639, -25.905705255293299 ], [ -55.516528286051539, -25.895938409230212 ], [ -55.513169318209464, -25.884879652873678 ], [ -55.516218227689023, -25.87506112996715 ], [ -55.521101650720595, -25.868859959119845 ], [ -55.526295132114626, -25.860746758556047 ], [ -55.526191779327121, -25.850256442980481 ], [ -55.51962887237454, -25.832324721308851 ], [ -55.499888474673355, -25.79258554528667 ], [ -55.496865403615459, -25.788813164495934 ], [ -55.475988125251774, -25.77274179479798 ], [ -55.469761115083372, -25.765662123008553 ], [ -55.465394456888646, -25.756308688994807 ], [ -55.449684820598009, -25.712125338613475 ], [ -55.446300015233533, -25.698327732039218 ], [ -55.444853075309197, -25.675745130433427 ], [ -55.43891028508159, -25.662205906277563 ], [ -55.431339687776358, -25.651870618534247 ], [ -55.405966559109402, -25.630941664226441 ], [ -55.400049608202835, -25.622983494192908 ], [ -55.39821509465088, -25.616265557609381 ], [ -55.399532844265366, -25.608875827457496 ], [ -55.403977016825877, -25.602209567717352 ], [ -55.416999477943534, -25.58660328511354 ], [ -55.421030239354081, -25.577249851099737 ], [ -55.422761400118532, -25.568826593072799 ], [ -55.422968105693542, -25.561333510133409 ], [ -55.425371060026407, -25.555339043961737 ], [ -55.430331997423707, -25.550481458452566 ], [ -55.444103765576301, -25.54707081466637 ], [ -55.453405523645984, -25.546347345153833 ], [ -55.489243130366162, -25.555597425480812 ], [ -55.25641496407934, -25.261300144086363 ], [ -55.226830206848547, -25.231276137283885 ], [ -55.215332200920329, -25.2315861956464 ], [ -55.196806200046069, -25.243471775202238 ], [ -55.171278041748224, -25.266726169477124 ], [ -55.160916918281146, -25.271945489292875 ], [ -55.137068243904309, -25.280007013013233 ], [ -55.124304165205047, -25.282797540074398 ], [ -55.113193732005129, -25.282074069662599 ], [ -55.114098069570275, -25.272410577286337 ], [ -55.1195499333827, -25.252618503641031 ], [ -55.120144211686011, -25.242128188065408 ], [ -55.113813848730103, -25.248277682968705 ], [ -55.104202033197282, -25.262385348804798 ], [ -55.098026698972944, -25.268896579813315 ], [ -55.090120204883533, -25.273805841266551 ], [ -55.082162034850001, -25.276337985909322 ], [ -55.065057136377732, -25.279283542601434 ], [ -55.051052822429824, -25.284709567992195 ], [ -55.043223842706198, -25.293442885280911 ], [ -55.039399786870661, -25.304760024055895 ], [ -55.037591111740426, -25.318402601898583 ], [ -55.024155238573371, -25.339899997886619 ], [ -54.998627082074165, -25.343310641672758 ], [ -54.972117071845389, -25.343982436140493 ], [ -54.949405279929692, -25.337729587550427 ], [ -54.949611986404022, -25.325327244057064 ], [ -54.950645515178394, -25.319849541822919 ], [ -54.952531703775094, -25.314888603526242 ], [ -54.955063849317185, -25.310496107809115 ], [ -54.961368373851371, -25.302331231301309 ], [ -54.964107224968473, -25.297938734684863 ], [ -54.966277635304607, -25.293236178806637 ], [ -54.967414516866427, -25.287810153415876 ], [ -54.967311164078978, -25.281712334456699 ], [ -54.965037400955282, -25.263625584053443 ], [ -54.966096768151317, -25.258406264237692 ], [ -54.969016486421708, -25.254323825983761 ], [ -54.973434820560499, -25.251533298023276 ], [ -55.000125697942622, -25.241921481591078 ], [ -55.005396694601757, -25.239130954529912 ], [ -55.009169073593853, -25.236288750625363 ], [ -55.012373012704359, -25.232568047577331 ], [ -55.014465907775389, -25.228330579692511 ], [ -55.014595098984614, -25.223214613563584 ], [ -55.008445604081373, -25.203784275124178 ], [ -55.007722133669517, -25.197686456165002 ], [ -55.008290575349747, -25.191950371512462 ], [ -55.011081102410913, -25.187919610101915 ], [ -55.015008511033955, -25.184508965416398 ], [ -55.098956874959811, -25.1294218892088 ], [ -55.179546271043591, -25.059968763847394 ], [ -55.185359870061973, -25.052062269757926 ], [ -55.188693000381647, -25.048548272284961 ], [ -55.193292201673785, -25.046636243467844 ], [ -55.198821580751371, -25.04679127399811 ], [ -55.204557665403911, -25.047463066667206 ], [ -55.210061205160457, -25.047463066667206 ], [ -55.214841275404524, -25.045757745223739 ], [ -55.218717007184125, -25.042657158900738 ], [ -55.222205166235426, -25.038936455852763 ], [ -55.226080898914347, -25.035577488010688 ], [ -55.230964321945919, -25.033510430462002 ], [ -55.23675208164326, -25.032580254475192 ], [ -55.254993862576669, -25.034905693542953 ], [ -55.26158260795097, -25.034957371285657 ], [ -55.268481410788468, -25.034440605549491 ], [ -55.274630906591085, -25.033045342468597 ], [ -55.280237800034456, -25.031081637707416 ], [ -55.284940355013362, -25.028291110646251 ], [ -55.289126146054798, -25.025293878010075 ], [ -55.296257493788289, -25.018214207119968 ], [ -55.29935808011129, -25.014338473541727 ], [ -55.302071091907351, -25.010152682500291 ], [ -55.306463589423117, -25.000075778974008 ], [ -55.310235969314533, -24.990929049635952 ], [ -55.315041877080944, -24.981989027671489 ], [ -55.327521734940092, -24.965917657074215 ], [ -55.329717983698004, -24.959664808484149 ], [ -55.330338101322297, -24.950156344839456 ], [ -55.326591558953282, -24.938012383764487 ], [ -55.326203986224982, -24.92995086004413 ], [ -55.326720751061828, -24.92364633551 ], [ -55.328426073404557, -24.918530368481697 ], [ -55.329614630910498, -24.912794284728477 ], [ -55.329769659642068, -24.906024672200886 ], [ -55.328296882195332, -24.890418389597016 ], [ -55.328581102136127, -24.884062188219389 ], [ -55.329769659642068, -24.878739515616132 ], [ -55.331733364403249, -24.873985283793843 ], [ -55.333542040432803, -24.867835788890545 ], [ -55.334110480314393, -24.860962822676129 ], [ -55.333180305226904, -24.850420831156441 ], [ -55.326565721430882, -24.843702894572914 ], [ -55.316204597064484, -24.829130140743416 ], [ -55.314654304352644, -24.820086765092128 ], [ -55.31519690581257, -24.811198419071786 ], [ -55.323930223101286, -24.78737558401599 ], [ -55.328451910926958, -24.768565362301615 ], [ -55.326359015855871, -24.757661634676708 ], [ -55.322405767911846, -24.751460462930027 ], [ -55.31480933308427, -24.746809583895185 ], [ -55.307703822873123, -24.741021824197844 ], [ -55.301037564032356, -24.729187920586071 ], [ -55.298892992117885, -24.717250665086112 ], [ -55.300210740832995, -24.676219577871223 ], [ -55.2961024641574, -24.666659438282466 ], [ -55.285431281428487, -24.649451186123372 ], [ -55.284320238288387, -24.64092457351029 ], [ -55.285586310160056, -24.630692641252381 ], [ -55.291606614753448, -24.608420098908425 ], [ -55.292976040311999, -24.593433933029587 ], [ -55.291580777231104, -24.583718763809884 ], [ -55.288531866852168, -24.575502210458637 ], [ -55.283803474350862, -24.568680921986982 ], [ -55.253443569864828, -24.535866388123338 ], [ -55.227527838838682, -24.50217335421695 ], [ -55.116759406321535, -24.467498467480311 ], [ -55.09531368717694, -24.472717787296062 ], [ -55.099551154162441, -24.509563083469516 ], [ -55.098388434178901, -24.520725192613554 ], [ -55.093685879199938, -24.532765801800338 ], [ -55.079035611004656, -24.545788262917995 ], [ -55.064592048384327, -24.551524346671272 ], [ -55.051517910423229, -24.553539726477197 ], [ -55.039296434083155, -24.551162611465372 ], [ -55.01568030460237, -24.542170911758149 ], [ -55.000745815566916, -24.53974211990294 ], [ -54.992322556640659, -24.539587091171313 ], [ -54.915712246023304, -24.562014662246895 ], [ -54.896462774737245, -24.571884861097487 ], [ -54.884835577599802, -24.582633559091505 ], [ -54.882923549682062, -24.591625257899352 ], [ -54.883336960832082, -24.598704928789459 ], [ -54.884706387289953, -24.60428598381111 ], [ -54.886902635148488, -24.609712009201871 ], [ -54.887316047197828, -24.614827976230117 ], [ -54.885404019280031, -24.620202324777495 ], [ -54.878815273905786, -24.626351820580055 ], [ -54.871012131704504, -24.628987318909651 ], [ -54.862563036155166, -24.630227553258976 ], [ -54.826234503919238, -24.631467786708981 ], [ -54.811971807552879, -24.633173109951088 ], [ -54.803910284731842, -24.636583753737227 ], [ -54.800241257627931, -24.639684340060228 ], [ -54.800292935370692, -24.644335219095069 ], [ -54.800964728039787, -24.65032968526674 ], [ -54.801016404883171, -24.659011325712129 ], [ -54.795667893858194, -24.666039320658115 ], [ -54.790603603673389, -24.668674818987711 ], [ -54.784479946292493, -24.668364759725876 ], [ -54.779338140842526, -24.666194350289061 ], [ -54.774067145082654, -24.66309376396606 ], [ -54.768925339632688, -24.658442884931219 ], [ -54.764403652706392, -24.653481947533862 ], [ -54.758047451328821, -24.644231866307564 ], [ -54.753267381084754, -24.639684340060228 ], [ -54.746032680563758, -24.634878432293817 ], [ -54.733992072276294, -24.633948256307008 ], [ -54.725155402200016, -24.635963637012253 ], [ -54.71388994026853, -24.641131279984563 ], [ -54.706371018907362, -24.64361174868327 ], [ -54.69807695208965, -24.644851983032595 ], [ -54.691643236346295, -24.643921807945105 ], [ -54.67704464409502, -24.639891045635238 ], [ -54.668363002750368, -24.638805840916802 ], [ -54.663634610249062, -24.640304456785259 ], [ -54.659422979886585, -24.644645277457585 ], [ -54.648829312422833, -24.669760023706147 ], [ -54.643067390247836, -24.678079928945579 ], [ -54.63619442403342, -24.685314629466575 ], [ -54.626530930757838, -24.689190362145496 ], [ -54.549972296983924, -24.699577324933614 ], [ -54.521085170843946, -24.707483819023025 ], [ -54.49323157437766, -24.718180841072979 ], [ -54.469744636106043, -24.722676689577554 ], [ -54.444836595432548, -24.72283172010782 ], [ -54.421401333105052, -24.720609632928245 ], [ -54.395666470131459, -24.720454604196618 ], [ -54.381610480239488, -24.722159925640085 ], [ -54.358976202689576, -24.731203302190636 ], [ -54.358429465247639, -24.73142174661632 ], [ -54.371120971999943, -24.766652526999891 ], [ -54.399749715999917, -24.804789733999939 ], [ -54.407294474999873, -24.821222838999915 ], [ -54.453286498999944, -25.002813821999951 ], [ -54.462278197999893, -25.0372303259999 ], [ -54.464190225999914, -25.055937194999984 ], [ -54.463311726999876, -25.072783711999961 ], [ -54.45519852699988, -25.09211069699991 ], [ -54.429722045999966, -25.130557962999958 ], [ -54.426621460999911, -25.149471537 ], [ -54.435664835999972, -25.16704152399997 ], [ -54.469409545999952, -25.195463561999901 ], [ -54.481450154999919, -25.213240253999928 ], [ -54.503567667999931, -25.278662617999899 ], [ -54.528475708999906, -25.314319355999899 ], [ -54.547079223999845, -25.336643574999954 ], [ -54.575656290999916, -25.360311380999889 ], [ -54.597980509999871, -25.397518411999982 ], [ -54.609814412999896, -25.432761738999972 ], [ -54.611829792999941, -25.444027200999926 ], [ -54.612449910999914, -25.46552459699997 ], [ -54.608522501999943, -25.487642109999882 ], [ -54.598497273999925, -25.505832213999923 ], [ -54.591469278999909, -25.524745788999965 ], [ -54.594156453999943, -25.548620300999943 ], [ -54.599944214999908, -25.572701516999899 ], [ -54.60020261299988, -25.574944883999891 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-7", "NAME_1": "Itapúa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -54.664973817999908, -26.238863213999963 ], [ -54.666141723999885, -26.243668314999908 ], [ -54.663661254999909, -26.263305358999929 ], [ -54.663661254999909, -26.308367207999979 ], [ -54.679060831999919, -26.33988983199994 ], [ -54.680430257999973, -26.34526418 ], [ -54.683401651999901, -26.350845234999923 ], [ -54.693065144999906, -26.411926777999923 ], [ -54.697664347999961, -26.428153177999931 ], [ -54.706475178999938, -26.441795755999934 ], [ -54.737170980999906, -26.473215026999881 ], [ -54.76530879799995, -26.494092305999942 ], [ -54.780346639999919, -26.510422057999889 ], [ -54.789829264999895, -26.528508808999987 ], [ -54.788769897999913, -26.542564798999919 ], [ -54.783498901999877, -26.55672414199995 ], [ -54.780346639999919, -26.575224303999889 ], [ -54.781276814999984, -26.598168639999926 ], [ -54.784945841999871, -26.622766621999901 ], [ -54.793059041999896, -26.644987487999941 ], [ -54.807011678999885, -26.661213886999946 ], [ -54.817321126999872, -26.665761413999888 ], [ -54.822824666999878, -26.663280944999912 ], [ -54.827423868999915, -26.658113301999904 ], [ -54.834968627999871, -26.654392598999905 ], [ -54.879358683999925, -26.654392598999905 ], [ -54.903336548999846, -26.659870299999895 ], [ -54.919898844999949, -26.674132995999869 ], [ -54.930725056999876, -26.693976744999944 ], [ -54.943876708999966, -26.739968770999951 ], [ -54.951137247999924, -26.757538756999921 ], [ -54.961007445999911, -26.772318216999935 ], [ -54.975270141999886, -26.787821145999942 ], [ -54.991780761999877, -26.794642435999904 ], [ -55.040744181999884, -26.798466491999946 ], [ -55.060897989999944, -26.805184427999876 ], [ -55.125777750999873, -26.863578795999928 ], [ -55.132676554999961, -26.880632018999876 ], [ -55.118878946999899, -26.920009460999964 ], [ -55.122315429999844, -26.941713561999876 ], [ -55.138360962999911, -26.953702493999927 ], [ -55.161563679999915, -26.957319844999901 ], [ -55.201199503999874, -26.955459492999907 ], [ -55.216650756999883, -26.95122202599994 ], [ -55.235176757999909, -26.942230326 ], [ -55.256544962999925, -26.934582213999931 ], [ -55.280600341999843, -26.934272155999935 ], [ -55.329408731999905, -26.958456725999909 ], [ -55.37622757999992, -26.963831074999874 ], [ -55.396329711999982, -26.969308776999952 ], [ -55.414003051999885, -26.979850768999924 ], [ -55.430849568999889, -26.996387226999914 ], [ -55.4427609869999, -27.01550750699991 ], [ -55.448832966999959, -27.035868021999946 ], [ -55.451313435999936, -27.082066751999903 ], [ -55.461855428999911, -27.097983092999925 ], [ -55.486401733999884, -27.100050149999973 ], [ -55.51399694899996, -27.097466328999886 ], [ -55.533840698999938, -27.099430033999923 ], [ -55.545364542999977, -27.115243021999916 ], [ -55.549524495999918, -27.135810241999906 ], [ -55.555338094999911, -27.153793639999975 ], [ -55.571745361999945, -27.161545104999902 ], [ -55.598281209999953, -27.167539570999921 ], [ -55.598978841999951, -27.182629089999921 ], [ -55.574871785999903, -27.223556823999942 ], [ -55.570582641999948, -27.235339049999936 ], [ -55.568670613999927, -27.245984394999937 ], [ -55.570711832999876, -27.256423034999969 ], [ -55.58407019099991, -27.276783549 ], [ -55.583243367999984, -27.283501484999931 ], [ -55.580762898999893, -27.29166636099994 ], [ -55.581641397999931, -27.305515645999918 ], [ -55.591330728999964, -27.328356627999923 ], [ -55.60747961499996, -27.345513203999886 ], [ -55.628718628999934, -27.356365254999929 ], [ -55.653626667999902, -27.360085957999942 ], [ -55.681712809999937, -27.379412943999895 ], [ -55.71749873899995, -27.417343444999901 ], [ -55.754731607999872, -27.443698424999951 ], [ -55.815167195999891, -27.414139505999927 ], [ -55.842090616999911, -27.407421569999897 ], [ -55.854157063999878, -27.401220397999921 ], [ -55.862787027999929, -27.391091816999875 ], [ -55.877850708999915, -27.353574726999881 ], [ -55.892836873999983, -27.334867858999885 ], [ -55.913094034999915, -27.327839863999969 ], [ -55.936374267999923, -27.32825327499998 ], [ -55.960662190999926, -27.331560566999897 ], [ -55.966094416224337, -27.331723069164298 ], [ -55.984846760999886, -27.332284036999894 ], [ -56.006893544999912, -27.328250904999962 ], [ -56.073756062999848, -27.304895527999946 ], [ -56.074245977999908, -27.304811111999882 ], [ -56.098948323999906, -27.300554706999961 ], [ -56.124553995999946, -27.298901061999914 ], [ -56.149978799999957, -27.311820169999919 ], [ -56.168892374999899, -27.324739277999939 ], [ -56.205427612999927, -27.362153014999905 ], [ -56.228010212999948, -27.371248066999968 ], [ -56.256768147999878, -27.378276061999969 ], [ -56.279841674999943, -27.389644876999881 ], [ -56.285319376999922, -27.411348977999879 ], [ -56.281469482999881, -27.438634134999887 ], [ -56.285319376999922, -27.460958352999938 ], [ -56.296998250999906, -27.480905456999963 ], [ -56.3164802659999, -27.50043914799997 ], [ -56.335988118999893, -27.525657246999927 ], [ -56.349656534999923, -27.556353047999963 ], [ -56.367536580999882, -27.580640970999966 ], [ -56.39973099799991, -27.586842142999942 ], [ -56.400298629999895, -27.586636240999965 ], [ -56.431356974999915, -27.575369976999937 ], [ -56.461484334999909, -27.553872577999897 ], [ -56.48732255099992, -27.527207538999861 ], [ -56.506210286999959, -27.500129088999898 ], [ -56.546440388999883, -27.455067240999938 ], [ -56.5469333449999, -27.455002941999865 ], [ -56.612999633999948, -27.446385598999896 ], [ -56.638015875432302, -27.45291157480932 ], [ -56.638037854863114, -27.452615009874819 ], [ -56.64322954031104, -27.382566012611392 ], [ -56.642299364324174, -27.37677825291405 ], [ -56.638216926070299, -27.368871758824639 ], [ -56.635245530956468, -27.364582614995697 ], [ -56.631912400636793, -27.358536471980585 ], [ -56.631628180695998, -27.353162122533945 ], [ -56.635400559688094, -27.345410658075423 ], [ -56.640206468353824, -27.339726251165587 ], [ -56.675320603762827, -27.309960625882184 ], [ -56.682296921865429, -27.302570895730241 ], [ -56.688472256089767, -27.293992608072415 ], [ -56.690255092798282, -27.277507825425801 ], [ -56.687309536106227, -27.25611378312459 ], [ -56.673873663838492, -27.215134372753084 ], [ -56.66477861224314, -27.199476414205151 ], [ -56.654960090235988, -27.189244480148659 ], [ -56.645167405751181, -27.184335218695367 ], [ -56.636640794037419, -27.177358900592765 ], [ -56.610725063910536, -27.151210625569888 ], [ -56.60137162899747, -27.146042982597578 ], [ -56.594136929375793, -27.143510837954807 ], [ -56.543338996097759, -27.13777475420153 ], [ -56.534114753293238, -27.120979913192457 ], [ -56.531970181378767, -27.086408380142643 ], [ -56.572251959760138, -26.722399590968337 ], [ -56.496907721913828, -26.737282403160407 ], [ -56.490422329327032, -26.740641371002482 ], [ -56.459235601641694, -26.763895766176688 ], [ -56.444352790349001, -26.77257740662202 ], [ -56.428720669323411, -26.775988051307536 ], [ -56.411667446795207, -26.775626316101636 ], [ -56.295679693562988, -26.734956964092646 ], [ -56.209922655406217, -26.69335743609679 ], [ -56.148970303336796, -26.675529067212665 ], [ -56.118352017331745, -26.671291598428525 ], [ -56.102383998622656, -26.665142103525284 ], [ -56.094865078160808, -26.657752374272661 ], [ -56.085589159412166, -26.626746514639933 ], [ -56.07933630992278, -26.617444756570251 ], [ -56.070913051895843, -26.608814792968303 ], [ -56.056495326797858, -26.59796274218678 ], [ -56.044868129660472, -26.585922133000054 ], [ -56.035230474806554, -26.572589613519824 ], [ -56.025954556057911, -26.548146660839734 ], [ -56.021071133026339, -26.538379814776647 ], [ -55.99895362031333, -26.508200779242543 ], [ -55.984070808121317, -26.498020522029492 ], [ -55.933918829989977, -26.483447768199937 ], [ -55.864620734259461, -26.471975599794121 ], [ -55.847050746894467, -26.464637545586243 ], [ -55.831108568405682, -26.4549740541093 ], [ -55.784548102113206, -26.410428968522069 ], [ -55.765737881298151, -26.396217949898471 ], [ -55.758916591927175, -26.388466484540629 ], [ -55.750415818635133, -26.36846770621969 ], [ -55.739873827115446, -26.356892185026311 ], [ -55.681066046960495, -26.334154554688951 ], [ -55.63876888697456, -26.322992445544912 ], [ -55.617865770189155, -26.320873712052162 ], [ -55.6001924300366, -26.321132093571237 ], [ -55.586136441043891, -26.324129327106789 ], [ -55.572468023880162, -26.323199151119923 ], [ -55.551668259882263, -26.319736829591022 ], [ -55.483791265654361, -26.296585789002961 ], [ -55.465704515251161, -26.287439059664848 ], [ -55.381601121694416, -26.227649427579024 ], [ -55.340130784907785, -26.19116586661147 ], [ -55.331991746821643, -26.182639254897708 ], [ -55.325971442228251, -26.173699232933245 ], [ -55.323180915167086, -26.165172621219483 ], [ -55.324162767098017, -26.117320244633561 ], [ -55.322560798442112, -26.109155369025075 ], [ -55.320312872840816, -26.102334079654042 ], [ -55.319331020909885, -26.096287936638987 ], [ -55.31938269685395, -26.089673353742285 ], [ -55.317754889776324, -26.081766859652873 ], [ -55.31558447944019, -26.078666274229192 ], [ -55.312096320388889, -26.077581068611437 ], [ -55.308220587709968, -26.078976331692331 ], [ -55.304370694352031, -26.080940036453512 ], [ -55.291451585122559, -26.083317153264034 ], [ -55.257500168797719, -26.180313815829948 ], [ -55.23675208164326, -26.198245537501577 ], [ -55.162544725358771, -26.194834893715381 ], [ -55.142752651713522, -26.195765068802871 ], [ -55.134639452049043, -26.197160332783142 ], [ -55.124795090720852, -26.199640801481792 ], [ -55.09949947821832, -26.209407646645559 ], [ -55.067253384236267, -26.216849053640942 ], [ -55.056763067761381, -26.222378431819152 ], [ -55.041363490732522, -26.232920424238216 ], [ -55.03343115912071, -26.236331068923676 ], [ -55.027255824896372, -26.236951185648707 ], [ -55.023431769060892, -26.234522393793441 ], [ -55.020951301261562, -26.232610365875701 ], [ -55.01911678681023, -26.23028492590862 ], [ -55.016145391696455, -26.223205255018513 ], [ -55.012217983972789, -26.218554375983672 ], [ -55.005655077020208, -26.212198174606101 ], [ -54.972582159838794, -26.209407646645559 ], [ -54.959042934783611, -26.206513766796888 ], [ -54.952945115824434, -26.204136650885744 ], [ -54.946123827352721, -26.200260919106142 ], [ -54.939250861138305, -26.194266452934471 ], [ -54.935090907619269, -26.189512221112125 ], [ -54.919975552329845, -26.164655857282014 ], [ -54.912689174965465, -26.154992364006375 ], [ -54.907056443999693, -26.14894622189064 ], [ -54.902353889020731, -26.145690605936693 ], [ -54.896075202008944, -26.143313490924868 ], [ -54.891605191026713, -26.143468519656437 ], [ -54.888478766282049, -26.144760430849203 ], [ -54.886747606416918, -26.147550957910369 ], [ -54.886075811949183, -26.152150160101826 ], [ -54.886695929573477, -26.157317803973456 ], [ -54.890959234980699, -26.171632174485239 ], [ -54.89157935170573, -26.178453463856272 ], [ -54.889202236693848, -26.183621107727959 ], [ -54.879900478624165, -26.190442397098934 ], [ -54.872174851688044, -26.192716160222631 ], [ -54.864604255282131, -26.192509453748301 ], [ -54.859023200260481, -26.190442397098934 ], [ -54.853209601242099, -26.187031751514098 ], [ -54.839773728974421, -26.176593112781916 ], [ -54.831298794104043, -26.1724589976846 ], [ -54.823340624070511, -26.170288588247729 ], [ -54.807811855832483, -26.170081881773399 ], [ -54.788820766964818, -26.173492526458915 ], [ -54.77419633629188, -26.178453463856272 ], [ -54.755024380270925, -26.187341810775933 ], [ -54.749908413242679, -26.19059742583056 ], [ -54.745981003720317, -26.194111423303525 ], [ -54.743552211865051, -26.197160332783142 ], [ -54.742518683090736, -26.201346123824578 ], [ -54.742518683090736, -26.206307061221878 ], [ -54.743707240596677, -26.2132833802238 ], [ -54.743500535920987, -26.219639580702108 ], [ -54.741562668682207, -26.226099134867184 ], [ -54.735542364988135, -26.232300306613865 ], [ -54.724457770209938, -26.23467742252501 ], [ -54.667432826763559, -26.238863213566447 ], [ -54.665598314110923, -26.238863213566447 ], [ -54.664973817999908, -26.238863213999963 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-12", "NAME_1": "Ñeembucú" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -58.124018514999932, -26.201913756999957 ], [ -58.115233520999936, -26.190958352999886 ], [ -58.1062934979999, -26.170287780999956 ], [ -58.096681680999893, -26.136698099999933 ], [ -58.08650142399992, -26.127189635999954 ], [ -58.021595825999981, -26.105692239999911 ], [ -57.988212849999911, -26.088535664999952 ], [ -57.872716023999942, -26.010297546 ], [ -57.859693562999894, -25.994277851999939 ], [ -57.859590210999954, -25.980945332999923 ], [ -57.905840617999843, -25.968646341999971 ], [ -57.898244181999871, -25.953556822999886 ], [ -57.863310913999982, -25.927615254999921 ], [ -57.857109741999892, -25.919863788999919 ], [ -57.851373656999925, -25.908391621999911 ], [ -57.852407185999908, -25.897952981999964 ], [ -57.875351521999875, -25.89020151799987 ], [ -57.878193725999921, -25.883173522999954 ], [ -57.875351521999875, -25.876145527999938 ], [ -57.854215860999915, -25.86891082699988 ], [ -57.8332352299999, -25.858782246999922 ], [ -57.819661966426622, -25.849779220434698 ], [ -57.816336229433432, -25.85134164769886 ], [ -57.792255011959242, -25.856147555465327 ], [ -57.787139044930996, -25.85444223402186 ], [ -57.781583828331009, -25.851238294911411 ], [ -57.780421109246788, -25.847000827925854 ], [ -57.780111049984953, -25.840024508923932 ], [ -57.781299608390214, -25.823177991970738 ], [ -57.780524461134974, -25.814961439518811 ], [ -57.778121506802108, -25.8105172669583 ], [ -57.774064906969897, -25.807416680635299 ], [ -57.769362351990935, -25.806589857435995 ], [ -57.764246384962689, -25.807106622272784 ], [ -57.74424760574243, -25.81377288201287 ], [ -57.737426317270717, -25.814806409887922 ], [ -57.731225144624716, -25.814237970006332 ], [ -57.71008948384258, -25.809845472490565 ], [ -57.703836636151834, -25.80974211970306 ], [ -57.697196213934092, -25.81263599955173 ], [ -57.68926388232228, -25.818733818510907 ], [ -57.675724657267097, -25.835115247470696 ], [ -57.662237108156035, -25.848241062275179 ], [ -57.640222948230473, -25.865759372796845 ], [ -57.616865200268762, -25.879350273796092 ], [ -57.590458543726811, -25.899762465065692 ], [ -57.579942389729467, -25.905085137668948 ], [ -57.559607712825652, -25.913094984545921 ], [ -57.555344408317808, -25.917694186737322 ], [ -57.552037116419797, -25.923895358484003 ], [ -57.550486822808637, -25.934437350903011 ], [ -57.547515427694805, -25.943067314504958 ], [ -57.541960211994194, -25.952885838310806 ], [ -57.516716275435783, -25.982754814583018 ], [ -57.503590460631244, -26.011073499942086 ], [ -57.475736864164958, -26.156852715980051 ], [ -57.476977097614963, -26.167188001924728 ], [ -57.481240403921504, -26.174319349658276 ], [ -57.614152187573382, -26.294105320304311 ], [ -57.652780321354726, -26.361698092792778 ], [ -57.664510871279674, -26.377304376295911 ], [ -57.685904913580885, -26.392187187588661 ], [ -57.70549028165118, -26.412496026070755 ], [ -57.634822761261432, -26.780845635917387 ], [ -57.628647427037095, -26.798363945539677 ], [ -57.619733241695712, -26.818000990453356 ], [ -57.536818407443548, -26.923730971207362 ], [ -57.421734991776418, -27.044292088209318 ], [ -57.414293585680412, -27.047857760727084 ], [ -57.232185838305782, -27.072714124557194 ], [ -57.203557094584255, -27.080000501921631 ], [ -57.195908982913238, -27.095658460469565 ], [ -57.202058477816479, -27.133847344679225 ], [ -57.291355352767312, -27.361533704616761 ], [ -57.309648809644841, -27.427989596442728 ], [ -57.310115750241664, -27.429207702073768 ], [ -57.326289429999889, -27.414862975999924 ], [ -57.33522945099989, -27.409488626999874 ], [ -57.356466096999952, -27.404342991999911 ], [ -57.360395874999938, -27.403390807999912 ], [ -57.386699177999901, -27.403494160999927 ], [ -57.487674926999915, -27.416413268999946 ], [ -57.513358113999914, -27.414139505999927 ], [ -57.519937904999949, -27.412098551999904 ], [ -57.535682332999954, -27.40721486399994 ], [ -57.69779130099991, -27.33352427199992 ], [ -57.698183455999953, -27.333398221999886 ], [ -57.709366821999964, -27.329803568999907 ], [ -57.811582803999926, -27.310683288999911 ], [ -57.811912929999977, -27.310582987999879 ], [ -57.854784301999871, -27.297557474999863 ], [ -57.855088470999902, -27.29749900199991 ], [ -57.89950352199989, -27.288960658999898 ], [ -57.913385375999979, -27.286292012999894 ], [ -57.944029500999903, -27.274613138999911 ], [ -57.944356433999872, -27.274551133999935 ], [ -58.003664133999933, -27.263303121999911 ], [ -58.02195755999989, -27.259833678999897 ], [ -58.022046212999953, -27.259831356999982 ], [ -58.053531860999954, -27.259006855999885 ], [ -58.113993285999896, -27.268928730999875 ], [ -58.128824422999912, -27.269652200999957 ], [ -58.238223428999845, -27.257043151999937 ], [ -58.510764932999905, -27.278437194999952 ], [ -58.600165160999893, -27.312957051999931 ], [ -58.604195923403154, -27.31626434282515 ], [ -58.604134633999877, -27.315548077999907 ], [ -58.599906779999912, -27.266138203999915 ], [ -58.601560424999974, -27.245674336999954 ], [ -58.614014444999953, -27.226657409999888 ], [ -58.63871577999987, -27.210120950999894 ], [ -58.652358357999873, -27.198028665999914 ], [ -58.658404499999904, -27.185109557999894 ], [ -58.653288533999927, -27.156274108999952 ], [ -58.638819132999885, -27.135913594999934 ], [ -58.616133178999917, -27.12382130999994 ], [ -58.565490274999974, -27.115966490999909 ], [ -58.560529337999924, -27.10552785299997 ], [ -58.562389689999918, -27.090128275999888 ], [ -58.562182982999872, -27.0721448769999 ], [ -58.559702514999913, -27.063359883999922 ], [ -58.556395223999914, -27.055505065999881 ], [ -58.55169266799993, -27.048167011999894 ], [ -58.545439819999928, -27.041035664999953 ], [ -58.536258596999915, -27.03629371399991 ], [ -58.536034708999864, -27.036178079999928 ], [ -58.530505330999858, -27.040518900999913 ], [ -58.528024861999882, -27.047753600999968 ], [ -58.528024861999882, -27.051681009999939 ], [ -58.527043009999915, -27.054161478999916 ], [ -58.520032093999902, -27.05836802799989 ], [ -58.519808308999956, -27.058502298999898 ], [ -58.511540079999918, -27.060155944999948 ], [ -58.50756099499992, -27.05509165499997 ], [ -58.506734171999909, -27.038451842999862 ], [ -58.504873819999915, -27.031527200999875 ], [ -58.501359822999945, -27.023672383999937 ], [ -58.49236812399991, -27.009719746999934 ], [ -58.474539754999853, -26.990082702999914 ], [ -58.466633260999913, -26.975923359999868 ], [ -58.48161942599998, -26.963831074999874 ], [ -58.483686482999929, -26.950601907999967 ], [ -58.475469930999907, -26.937992858999863 ], [ -58.459811970999851, -26.928174336999888 ], [ -58.415525268999914, -26.917528991999902 ], [ -58.39387284299994, -26.90967417399996 ], [ -58.384674438999951, -26.897065124999926 ], [ -58.374700886999932, -26.887556660999863 ], [ -58.351274896203968, -26.885811609526552 ], [ -58.3289155679999, -26.884146015999917 ], [ -58.315789753999923, -26.874120788999903 ], [ -58.322145955999957, -26.856757506999969 ], [ -58.340387736999901, -26.844458515999932 ], [ -58.352376667999863, -26.830505879999947 ], [ -58.340026001999917, -26.808595071999903 ], [ -58.323334512999878, -26.803840839999907 ], [ -58.305506143999935, -26.809111836999932 ], [ -58.288556274999934, -26.811488952999881 ], [ -58.274810343999889, -26.798363138999918 ], [ -58.2784793699999, -26.790198261999905 ], [ -58.28654089399987, -26.778726094999882 ], [ -58.287936157999951, -26.768597513999921 ], [ -58.271399698999858, -26.76425669399994 ], [ -58.259255736999961, -26.764463398999908 ], [ -58.251762654999936, -26.763223164999957 ], [ -58.24793859899998, -26.758158874999893 ], [ -58.245199747999948, -26.680230814999916 ], [ -58.240652221999909, -26.661213886999946 ], [ -58.235536254999914, -26.649845072999952 ], [ -58.232280639999942, -26.648604837999926 ], [ -58.227164672999947, -26.652015482999943 ], [ -58.195693725999888, -26.657493183999932 ], [ -58.183859822999892, -26.656769714999939 ], [ -58.178640502999968, -26.650671894999888 ], [ -58.181379353999915, -26.64157684299991 ], [ -58.18716711499988, -26.633618671999955 ], [ -58.192076375999903, -26.624626973999909 ], [ -58.192283081999875, -26.612844746999912 ], [ -58.188510701999945, -26.609744160999966 ], [ -58.17150915499991, -26.598582050999937 ], [ -58.164946248999939, -26.592277526999922 ], [ -58.170527302999858, -26.586799824999929 ], [ -58.179312296999939, -26.572640482999887 ], [ -58.1854101159999, -26.564992369999914 ], [ -58.207992716999939, -26.550212910999889 ], [ -58.213367065999904, -26.544528502999938 ], [ -58.217346150999873, -26.527578632999933 ], [ -58.214193888999915, -26.512385762999912 ], [ -58.208716186999936, -26.496882832999901 ], [ -58.205925659999878, -26.479416197999868 ], [ -58.202721719999914, -26.471561380999916 ], [ -58.188665730999901, -26.462052916999937 ], [ -58.1854101159999, -26.451717630999923 ], [ -58.209594686999964, -26.431253762999873 ], [ -58.213057006999918, -26.418644713999939 ], [ -58.206184041999848, -26.402728372999917 ], [ -58.172697713999952, -26.349294942999904 ], [ -58.16763342299987, -26.33503224699993 ], [ -58.164946248999939, -26.31859914099995 ], [ -58.170010538999918, -26.286559752999949 ], [ -58.169958862999891, -26.270333353999945 ], [ -58.161845662999895, -26.263305358999929 ], [ -58.145980997999885, -26.260101419999955 ], [ -58.123295043999917, -26.251523131999932 ], [ -58.105983438999914, -26.239534199999881 ], [ -58.106603556999886, -26.226098326999931 ], [ -58.121227986999969, -26.216693216999971 ], [ -58.137144327999891, -26.209458516999902 ], [ -58.148926554999889, -26.199329935999955 ], [ -58.151303669999919, -26.181449889999982 ], [ -58.141175089999876, -26.184757181999899 ], [ -58.133216918999921, -26.188994649999941 ], [ -58.127635864999917, -26.194679055999899 ], [ -58.124018514999932, -26.201913756999957 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-8", "NAME_1": "Misiones" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -57.108990030999934, -27.49062062599991 ], [ -57.148160766999865, -27.488966979999958 ], [ -57.156687377999901, -27.487726745999922 ], [ -57.180096801999952, -27.487313333999907 ], [ -57.180452506999899, -27.487214066999869 ], [ -57.191207234999865, -27.484212747999962 ], [ -57.200405639999872, -27.478941751999926 ], [ -57.227070678999922, -27.458684590999923 ], [ -57.23709590699994, -27.454240417999927 ], [ -57.237587623999843, -27.454120240999927 ], [ -57.283026316999894, -27.443014888999883 ], [ -57.292493041999904, -27.440701192999938 ], [ -57.302983357999949, -27.435533548999942 ], [ -57.310115750241664, -27.429207702073768 ], [ -57.309648809644841, -27.427989596442728 ], [ -57.291355352767312, -27.361533704616761 ], [ -57.202058477816479, -27.133847344679225 ], [ -57.195908982913238, -27.095658460469565 ], [ -57.203557094584255, -27.080000501921631 ], [ -57.232185838305782, -27.072714124557194 ], [ -57.414293585680412, -27.047857760727084 ], [ -57.421734991776418, -27.044292088209318 ], [ -57.536818407443548, -26.923730971207362 ], [ -57.619733241695712, -26.818000990453356 ], [ -57.628647427037095, -26.798363945539677 ], [ -57.634822761261432, -26.780845635917387 ], [ -57.70549028165118, -26.412496026070755 ], [ -57.671487189382276, -26.42820566146213 ], [ -57.654847378004092, -26.449237969456703 ], [ -57.64802608863306, -26.453578790129086 ], [ -57.636528082704842, -26.459366549826427 ], [ -57.630559454954891, -26.466291191984908 ], [ -57.62531429671742, -26.475747978786217 ], [ -57.618208788304912, -26.49352467172622 ], [ -57.614694789932628, -26.500500990728142 ], [ -57.60813188297999, -26.507477308830744 ], [ -57.582758755212353, -26.520758151467533 ], [ -57.575937465841378, -26.527372735263498 ], [ -57.569736294094696, -26.536106051652951 ], [ -57.562191535211184, -26.544167576272628 ], [ -57.54878150136517, -26.550627129538384 ], [ -57.476098599370857, -26.564993177792928 ], [ -57.462740240569644, -26.571349379170499 ], [ -57.455944789620332, -26.579720961253372 ], [ -57.445790370828945, -26.588816012848724 ], [ -57.431656866571132, -26.595482272588811 ], [ -57.404991827610729, -26.601890150809822 ], [ -57.38884294264767, -26.612173760810435 ], [ -57.367113002662961, -26.621010430886656 ], [ -57.340551317389384, -26.623232517166912 ], [ -57.252365484679387, -26.605714206645303 ], [ -57.200844081888874, -26.589436129573699 ], [ -57.187769944827096, -26.581632989171112 ], [ -57.181077846665289, -26.571866144007345 ], [ -57.179579229897513, -26.560342298758087 ], [ -57.179501716431048, -26.545046074516733 ], [ -57.178028937185672, -26.531765231879945 ], [ -57.172396206219958, -26.522618503441208 ], [ -57.163869595405515, -26.51662403726948 ], [ -57.149141811945071, -26.51145639429717 ], [ -57.142036301733924, -26.506185397637978 ], [ -57.138186408376043, -26.502051282540663 ], [ -57.136610277242482, -26.497400405304461 ], [ -57.133302985344471, -26.492491143851225 ], [ -57.128006151162936, -26.486134941574278 ], [ -57.117257453168918, -26.481484062539437 ], [ -57.112322354193282, -26.476006362103931 ], [ -57.108524135880145, -26.468771660683615 ], [ -57.10573360881898, -26.459469902613932 ], [ -57.100100876953888, -26.447377617483085 ], [ -57.090747442940142, -26.434406834108131 ], [ -57.079146084224419, -26.423399753695662 ], [ -57.063488124777109, -26.412289320495745 ], [ -57.057416144239653, -26.409343763803633 ], [ -57.049819709412077, -26.406449883954963 ], [ -57.039303555414733, -26.403969415256313 ], [ -57.029071621358241, -26.402832532795173 ], [ -57.019692348922774, -26.403039239269503 ], [ -57.010907354790561, -26.404537856037223 ], [ -57.0036209783255, -26.406863295104984 ], [ -56.944193081445519, -26.4349235980456 ], [ -56.922979906297655, -26.447997735107379 ], [ -56.889829474750456, -26.472750746150041 ], [ -56.871148444245307, -26.483189385781543 ], [ -56.852415737796036, -26.485308119274293 ], [ -56.840685186971768, -26.482259209794677 ], [ -56.828127813847516, -26.485979912842708 ], [ -56.819342820614679, -26.489803968678189 ], [ -56.783427700428035, -26.540756930687792 ], [ -56.754488898343993, -26.557138359647581 ], [ -56.748597784959827, -26.563649590656098 ], [ -56.73978695330527, -26.575896904518515 ], [ -56.731802944850017, -26.59010792404149 ], [ -56.713380295863942, -26.61703134452091 ], [ -56.696895515016024, -26.630777276050424 ], [ -56.654495002242527, -26.656460463079895 ], [ -56.639663865994635, -26.662558282039072 ], [ -56.625142788109201, -26.665297133156173 ], [ -56.593620165438267, -26.665762221149578 ], [ -56.576592780432463, -26.670361422441715 ], [ -56.567936978408795, -26.678629652636346 ], [ -56.565973272748352, -26.687311293081734 ], [ -56.568143683084486, -26.695941256683625 ], [ -56.572717047753542, -26.706586601890194 ], [ -56.573957282102867, -26.711547540186814 ], [ -56.574215663621999, -26.713872979254575 ], [ -56.572251959760138, -26.722399590968337 ], [ -56.531970181378767, -27.086408380142643 ], [ -56.534114753293238, -27.120979913192457 ], [ -56.543338996097759, -27.13777475420153 ], [ -56.594136929375793, -27.143510837954807 ], [ -56.60137162899747, -27.146042982597578 ], [ -56.610725063910536, -27.151210625569888 ], [ -56.636640794037419, -27.177358900592765 ], [ -56.645167405751181, -27.184335218695367 ], [ -56.654960090235988, -27.189244480148659 ], [ -56.66477861224314, -27.199476414205151 ], [ -56.673873663838492, -27.215134372753084 ], [ -56.687309536106227, -27.25611378312459 ], [ -56.690255092798282, -27.277507825425801 ], [ -56.688472256089767, -27.293992608072415 ], [ -56.682296921865429, -27.302570895730241 ], [ -56.675320603762827, -27.309960625882184 ], [ -56.640206468353824, -27.339726251165587 ], [ -56.635400559688094, -27.345410658075423 ], [ -56.631628180695998, -27.353162122533945 ], [ -56.631912400636793, -27.358536471980585 ], [ -56.635245530956468, -27.364582614995697 ], [ -56.638216926070299, -27.368871758824639 ], [ -56.642299364324174, -27.37677825291405 ], [ -56.64322954031104, -27.382566012611392 ], [ -56.638037854863114, -27.452615009874819 ], [ -56.638015875432302, -27.45291157480932 ], [ -56.683124552999914, -27.464679056999955 ], [ -56.734232543999894, -27.50043914799997 ], [ -56.771155354999934, -27.506743671999885 ], [ -56.771510649999925, -27.506548448999908 ], [ -56.807458048999905, -27.486796569999868 ], [ -56.869263061999902, -27.431502786999943 ], [ -56.904351358999918, -27.418687031999951 ], [ -56.90444715299995, -27.418695948999897 ], [ -56.940989949999874, -27.422097675999893 ], [ -56.977318481999959, -27.435326842999885 ], [ -57.076227173999939, -27.484006042999908 ], [ -57.108990030999934, -27.49062062599991 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-16", "NAME_1": "Alto Paraguay" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -58.158796752999962, -20.165124612999918 ], [ -58.158331664999935, -20.181144307999972 ], [ -58.152337198999902, -20.184658304999928 ], [ -58.144068969999864, -20.18352142399992 ], [ -58.137040974999962, -20.185588479999879 ], [ -58.129909626999932, -20.192513121999951 ], [ -58.120504516999858, -20.203881937999952 ], [ -58.118540812999925, -20.21442392999991 ], [ -58.155282755999906, -20.226412861999876 ], [ -58.162672485999934, -20.243156025999923 ], [ -58.156316284999889, -20.261656187999861 ], [ -58.137040974999962, -20.274368590999899 ], [ -58.130943155999915, -20.272818298999979 ], [ -58.126240600999921, -20.267030537999915 ], [ -58.120039428999945, -20.261346129999964 ], [ -58.109755818999929, -20.260726012999982 ], [ -58.103089559999944, -20.26444671599991 ], [ -58.095079712999876, -20.272198180999908 ], [ -58.090325480999866, -20.2817066449999 ], [ -58.099937296999968, -20.309198506999877 ], [ -58.097715209999876, -20.334623310999874 ], [ -58.090790568999893, -20.359427998999919 ], [ -58.082987427999882, -20.376171161999963 ], [ -58.067122762999958, -20.393534443999968 ], [ -58.045625366999928, -20.409347431999976 ], [ -58.023146118999904, -20.420716246999874 ], [ -58.004180867999963, -20.425160420999973 ], [ -57.989401407999935, -20.433118591999929 ], [ -57.992140258999882, -20.450895283999955 ], [ -58.007901570999962, -20.479834085999926 ], [ -58.010020304999955, -20.500091246999929 ], [ -58.008935099999945, -20.525722756999897 ], [ -58.004749308999919, -20.549803974999932 ], [ -57.993328816999906, -20.573781839999953 ], [ -57.992553670999911, -20.585047301999921 ], [ -57.993638875999892, -20.606751403999908 ], [ -57.990951700999858, -20.620600686999879 ], [ -57.977825887999899, -20.640134378999889 ], [ -57.973123331999915, -20.65119313599989 ], [ -57.973588419999942, -20.661941832999915 ], [ -57.981081502999899, -20.681165465999925 ], [ -57.980616414999957, -20.69274098699988 ], [ -57.974415242999953, -20.704006448999934 ], [ -57.965010131999918, -20.711034443999949 ], [ -57.956380167999953, -20.709897561999938 ], [ -57.947181762999975, -20.675067646999963 ], [ -57.934004272999886, -20.667419534999894 ], [ -57.918087930999974, -20.669796650999942 ], [ -57.90429032399993, -20.678995055999934 ], [ -57.900207885999919, -20.685196227999924 ], [ -57.894471801999941, -20.699975687999938 ], [ -57.8906477459999, -20.706383564999982 ], [ -57.884343221999899, -20.711964619999904 ], [ -57.868943644999916, -20.722196552999975 ], [ -57.860210326999947, -20.730258076999874 ], [ -57.857678182999848, -20.739869892999891 ], [ -57.865274617999916, -20.747414651999932 ], [ -57.877005167999897, -20.752375589999886 ], [ -57.898760945999925, -20.756613056999925 ], [ -57.906667439999865, -20.762194111999946 ], [ -57.917932902999922, -20.774079690999969 ], [ -57.933074096999945, -20.784621683999944 ], [ -57.940412150999919, -20.793613382999894 ], [ -57.93395259599987, -20.799711201999941 ], [ -57.90801102699993, -20.80198496499996 ], [ -57.887650512999898, -20.805912373999931 ], [ -57.870700643999982, -20.816454365999988 ], [ -57.859641885999878, -20.831647236999913 ], [ -57.857109741999892, -20.849733987999926 ], [ -57.867393351999908, -20.860069274999944 ], [ -57.9086828209999, -20.881566670999888 ], [ -57.917932902999922, -20.894382425999964 ], [ -57.914832315999973, -20.905647888999923 ], [ -57.90801102699993, -20.910505472999944 ], [ -57.901138061999859, -20.912365823999949 ], [ -57.898089151999926, -20.914846292999925 ], [ -57.893024861999947, -20.914846292999925 ], [ -57.869925495999979, -20.93272633899997 ], [ -57.847032836999858, -20.955980732999905 ], [ -57.840314900999942, -20.955980732999905 ], [ -57.836025756999874, -20.938514098999946 ], [ -57.817577269999873, -20.953603616999956 ], [ -57.81602697799994, -20.975411070999968 ], [ -57.825380411999873, -20.998562113999881 ], [ -57.852458862999924, -21.037836201999937 ], [ -57.851735391999938, -21.051995543999894 ], [ -57.836025756999874, -21.082484638999873 ], [ -57.829876261999914, -21.127029723999968 ], [ -57.833958699999897, -21.173848571999898 ], [ -57.847859660999887, -21.216223245999913 ], [ -57.870700643999982, -21.247642516999946 ], [ -57.89901932799998, -21.267176207999867 ], [ -57.90429032399993, -21.274927672999951 ], [ -57.904910441999903, -21.28743336999996 ], [ -57.899949503999949, -21.29508148099994 ], [ -57.89364497999992, -21.30035247799988 ], [ -57.8906477459999, -21.305933531999884 ], [ -57.882327840999949, -21.316372171999916 ], [ -57.866308145999909, -21.320919697999955 ], [ -57.85555944799998, -21.33073821999993 ], [ -57.863310913999982, -21.356886494999927 ], [ -57.929921834999874, -21.453108011999873 ], [ -57.945269734999954, -21.487214456999936 ], [ -57.949145467999898, -21.50829844099988 ], [ -57.948111938999915, -21.53051930799991 ], [ -57.939792032999947, -21.548192646999908 ], [ -57.921601928999934, -21.555427346999878 ], [ -57.912093464999941, -21.564005635999905 ], [ -57.9193281659999, -21.583952737999923 ], [ -57.932143920999891, -21.606690368999907 ], [ -57.939016886999951, -21.623743590999936 ], [ -57.934831095999925, -21.640693460999941 ], [ -57.924340779999881, -21.658676858999925 ], [ -57.911783406999859, -21.673042907999928 ], [ -57.901138061999859, -21.678934020999932 ], [ -57.895608682999864, -21.688442484999911 ], [ -57.939016886999951, -21.755311787999887 ], [ -57.93844844599991, -21.774638772999936 ], [ -57.934779419999899, -21.792932229999906 ], [ -57.935709594999963, -21.812052509999901 ], [ -57.948938760999852, -21.833859964999931 ], [ -57.955915079999954, -21.851119893999922 ], [ -57.946664998999921, -21.865485941999921 ], [ -57.932764037999874, -21.881919046999982 ], [ -57.925374308999949, -21.904966735999949 ], [ -57.929921834999874, -21.917369079999915 ], [ -57.95322790499992, -21.958193460999908 ], [ -57.96263301599987, -21.966978454999904 ], [ -57.964855102999877, -21.976693623999935 ], [ -57.986817585999944, -22.035294697999959 ], [ -57.98836787999997, -22.04904062899989 ], [ -57.988006144999957, -22.064130146999986 ], [ -57.986249145999892, -22.074465433999904 ], [ -57.973133663999874, -22.081048493999958 ], [ -57.973251716193715, -22.081184177108071 ], [ -57.981209886227248, -22.090330905546864 ], [ -57.974156052859541, -22.132188815961115 ], [ -57.966921353237865, -22.148363538446517 ], [ -57.977256639182542, -22.210633640130368 ], [ -57.973768480131241, -22.234353123297979 ], [ -57.965732794832604, -22.256832371216944 ], [ -57.956146816822127, -22.269131361922803 ], [ -57.940747239793268, -22.27429900489517 ], [ -57.915399950447352, -22.275332532770165 ], [ -57.896718919042883, -22.279259942292526 ], [ -57.88739132255148, -22.289801934711534 ], [ -57.877546963021928, -22.323133232512646 ], [ -57.831193203203782, -22.37718678174457 ], [ -57.826671516277429, -22.388607273307002 ], [ -57.845275030618154, -22.404471937429946 ], [ -57.851631231995725, -22.411861667581888 ], [ -57.848969896143785, -22.423023776725927 ], [ -58.194090949237932, -22.280913587791872 ], [ -58.20830196786153, -22.272231948245803 ], [ -58.216363490682568, -22.262103366976817 ], [ -58.223494839315379, -22.214509372809289 ], [ -58.237654181994913, -22.204639173958697 ], [ -58.263234016236879, -22.198024591062051 ], [ -58.732972785265815, -22.168103936147759 ], [ -58.785062628837238, -22.17352996153852 ], [ -58.998434618262991, -22.156838474216215 ], [ -59.15261125300691, -22.162212822763536 ], [ -59.168811814813409, -22.161024265257652 ], [ -59.192402105872475, -22.155288180605055 ], [ -59.230151739611074, -22.14092213324983 ], [ -59.342289597686772, -22.083044529081747 ], [ -59.391563075775309, -22.055139254872699 ], [ -59.420424364392886, -22.046509291270752 ], [ -59.781590948763267, -22.033538506996479 ], [ -59.836678025870185, -22.041548353873452 ], [ -59.929178839931524, -22.043822116997092 ], [ -59.938170538739371, -22.040463149155016 ], [ -59.940961065800536, -22.030231215098524 ], [ -59.941994594574851, -21.999742120302585 ], [ -59.95816931795963, -21.907706394234708 ], [ -59.95816931795963, -21.89809457780251 ], [ -59.955973070101095, -21.885123792628917 ], [ -59.941891241787346, -21.845332939763352 ], [ -59.851767543637209, -21.469645277507539 ], [ -59.847349208599098, -21.459671725869441 ], [ -59.841303067382626, -21.450731703005715 ], [ -59.826678635810367, -21.435848890813645 ], [ -59.811459926834175, -21.424583428882158 ], [ -59.710432501958394, -21.367377618282489 ], [ -59.705109829355138, -21.363140151296932 ], [ -59.701905891143952, -21.359729505712096 ], [ -59.699477098389366, -21.355440361883211 ], [ -59.697771776046636, -21.350272718910844 ], [ -59.696221483334796, -21.343451429539869 ], [ -59.69549801292294, -21.334873141881985 ], [ -59.695756395341391, -21.325364679136612 ], [ -59.736890835343786, -21.068687838472954 ], [ -59.746450974932543, -21.047190444283558 ], [ -59.752083705898315, -21.037888686213876 ], [ -59.805801358346002, -20.967970472859065 ], [ -59.826316900604468, -20.93391570374672 ], [ -59.829029914199168, -20.926474297650714 ], [ -59.829727546189304, -20.918309421142851 ], [ -59.826006843141272, -20.891954440545021 ], [ -59.825619268614332, -20.883737888093037 ], [ -59.826161871872898, -20.874436130023412 ], [ -59.832414719563644, -20.850975030173515 ], [ -59.837995774585295, -20.837797539424912 ], [ -59.849803839775404, -20.817850437048037 ], [ -59.870551926929863, -20.79227060280607 ], [ -59.874350145243, -20.786379489421904 ], [ -59.875667893958109, -20.780385024149552 ], [ -59.875848762010776, -20.776044202577907 ], [ -59.85546240916284, -20.698167820088827 ], [ -59.881765712917286, -20.679357599273771 ], [ -59.951037971125459, -20.651607353796351 ], [ -61.818701747787429, -20.131897474688685 ], [ -61.911486781789563, -20.076138604013352 ], [ -61.924739799402232, -20.065127638529702 ], [ -61.918412231999895, -20.052573343999939 ], [ -61.905544799999888, -20.026735127999913 ], [ -61.892574015999855, -20.000896910999899 ], [ -61.864410359999908, -19.927413024999936 ], [ -61.836298380999978, -19.853825784999941 ], [ -61.808186400999944, -19.780341897999875 ], [ -61.780074421999899, -19.706961363999937 ], [ -61.761212524999877, -19.657765400999963 ], [ -61.753202677999894, -19.645879821999941 ], [ -61.737234659999871, -19.639575296999922 ], [ -61.648222005999884, -19.626759541999945 ], [ -61.62672460999994, -19.623658954999897 ], [ -61.579544026999912, -19.616837666999942 ], [ -61.532285929999972, -19.610016377999983 ], [ -61.510840210999845, -19.606915790999949 ], [ -61.172359578999874, -19.537462666999971 ], [ -60.833930623999919, -19.467906188999891 ], [ -60.495475829999862, -19.398453063999909 ], [ -60.156995198999908, -19.328999938999942 ], [ -60.006384236999878, -19.298097431999935 ], [ -59.924322062999892, -19.29706390399987 ], [ -59.735858113999967, -19.294790140999936 ], [ -59.547497517999886, -19.292413024999902 ], [ -59.359085245999893, -19.290139261999883 ], [ -59.170724649999926, -19.287762145999935 ], [ -59.089540974999863, -19.286728616999952 ], [ -59.069645548999858, -19.291482848999948 ], [ -59.039673217999905, -19.311636657999927 ], [ -59.011096150999947, -19.330963643999965 ], [ -58.960659952999947, -19.3605225619999 ], [ -58.867435668999917, -19.415299580999985 ], [ -58.774108032999948, -19.470076598999881 ], [ -58.680832071999902, -19.52475026399992 ], [ -58.587504434999857, -19.579423929999891 ], [ -58.494280151999931, -19.634200947999958 ], [ -58.401004190999885, -19.688874612999925 ], [ -58.307779907999958, -19.74365163199991 ], [ -58.214452270999885, -19.798325296999863 ], [ -58.175281534999954, -19.821372984999925 ], [ -58.164429483999896, -19.83294850699987 ], [ -58.161173868999924, -19.84721120199994 ], [ -58.164222778999942, -19.880284117999921 ], [ -58.162207397999907, -19.912323506999925 ], [ -58.145154175999949, -19.969580992999894 ], [ -58.141846883999875, -20.000896910999899 ], [ -58.144482381999893, -20.023117777999929 ], [ -58.143138793999924, -20.065285746999891 ], [ -58.144740762999845, -20.086163024999877 ], [ -58.159520223999948, -20.139079691999939 ], [ -58.158796752999962, -20.165124612999918 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-1", "NAME_1": "Concepción" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -57.973133663999874, -22.081048493999958 ], [ -57.972864949999945, -22.08118336999992 ], [ -57.961392781999933, -22.09007171599994 ], [ -57.952452758999897, -22.105988056999962 ], [ -57.939998738999918, -22.118390400999928 ], [ -57.906254028999854, -22.128932392999985 ], [ -57.895505330999924, -22.128932392999985 ], [ -57.878193725999921, -22.122111103999941 ], [ -57.871372436999877, -22.121180928999891 ], [ -57.862845825999955, -22.125831806999955 ], [ -57.848686482999909, -22.140301207999897 ], [ -57.843880574999901, -22.143711852999914 ], [ -57.831788289999906, -22.141128030999909 ], [ -57.815768594999952, -22.128312276999935 ], [ -57.805484984999879, -22.128622334999918 ], [ -57.795304727999905, -22.130999450999951 ], [ -57.787501587999884, -22.129655863999901 ], [ -57.7754093019999, -22.12397145599995 ], [ -57.777786417999948, -22.122317809999899 ], [ -57.777424682999936, -22.117046813999963 ], [ -57.775616007999957, -22.111155699999969 ], [ -57.77365230299992, -22.107745055999942 ], [ -57.769931599999921, -22.107434996999956 ], [ -57.760268106999888, -22.110742288999958 ], [ -57.756185669999894, -22.11063893599993 ], [ -57.736341918999898, -22.103714293999943 ], [ -57.723267781999937, -22.104747822999926 ], [ -57.70993526299992, -22.108468525999939 ], [ -57.689626423999897, -22.109295348999964 ], [ -57.678515991999888, -22.106401468999977 ], [ -57.670816202999873, -22.102370706999892 ], [ -57.663684855999946, -22.100613709 ], [ -57.654486449999951, -22.104541116999968 ], [ -57.638931844999917, -22.144538675999939 ], [ -57.627201294999935, -22.165105895999929 ], [ -57.614075480999958, -22.176991474999866 ], [ -57.596712198999853, -22.181022236999951 ], [ -57.572734333999932, -22.177714944999948 ], [ -57.564001017999942, -22.17440765399995 ], [ -57.559970255999957, -22.171617125999902 ], [ -57.554699259999921, -22.170273538999936 ], [ -57.54229691599997, -22.171513772999958 ], [ -57.534597127999888, -22.17440765399995 ], [ -57.511187703999923, -22.188773701999949 ], [ -57.472482055999905, -22.180298766999954 ], [ -57.463955444999982, -22.180402119999982 ], [ -57.443181518999921, -22.187946878999938 ], [ -57.432277791999866, -22.188670348999935 ], [ -57.417860066999935, -22.193837991999928 ], [ -57.384993855999909, -22.213268330999909 ], [ -57.378637654999892, -22.213371683999938 ], [ -57.375020303999918, -22.207273864999891 ], [ -57.366648721999923, -22.2091342169999 ], [ -57.351249145999958, -22.217195738999891 ], [ -57.339932006999874, -22.216989033999923 ], [ -57.334816039999879, -22.211718037999987 ], [ -57.333059041999917, -22.205413512999968 ], [ -57.331767130999964, -22.202416279999866 ], [ -57.316315877999955, -22.203656513999903 ], [ -57.271667439999931, -22.213785094999949 ], [ -57.252443807999896, -22.210581156999893 ], [ -57.227484090999923, -22.191254170999926 ], [ -57.213789835999904, -22.188153584999981 ], [ -57.209449015999922, -22.192080992999948 ], [ -57.206400105999904, -22.207480569999944 ], [ -57.199527140999919, -22.212854919999899 ], [ -57.189967, -22.213578388999906 ], [ -57.183610799999911, -22.210891214999961 ], [ -57.177926391999875, -22.207377216999916 ], [ -57.17038163299992, -22.205723571999954 ], [ -57.154155232999898, -22.207997334999973 ], [ -57.124182901999859, -22.218539326999945 ], [ -57.115036173999954, -22.222880146999927 ], [ -57.114622761999954, -22.225050557999921 ], [ -57.113279174999889, -22.229391376999985 ], [ -57.10847326699988, -22.233525492999917 ], [ -57.090748250999866, -22.236419371999901 ], [ -57.085063842999915, -22.238073018999955 ], [ -57.079224405999952, -22.238589782999981 ], [ -57.07162796999998, -22.235695902999908 ], [ -57.059484008999874, -22.232698668999902 ], [ -57.027651326999916, -22.235075784999935 ], [ -57.011166544999952, -22.233835550999899 ], [ -56.986465210999938, -22.241380309999954 ], [ -56.975716512999924, -22.24169036899994 ], [ -56.96455440299988, -22.234869079999982 ], [ -56.965484578999934, -22.250888772999929 ], [ -56.96052364099998, -22.254816182 ], [ -56.952100382999902, -22.253575947999963 ], [ -56.942591918999909, -22.253989359999977 ], [ -56.92494441799991, -22.262360941999944 ], [ -56.914789998999964, -22.262877705999898 ], [ -56.903679565999937, -22.236936136999944 ], [ -56.892000691999954, -22.252232360999898 ], [ -56.881717081999881, -22.277243753999898 ], [ -56.87954667199989, -22.289956156999949 ], [ -56.85605973299991, -22.293160094999919 ], [ -56.842856404999907, -22.289025981 ], [ -56.834096441597467, -22.298276868682535 ], [ -56.622610642567111, -22.347162774042772 ], [ -56.582018805823225, -22.361993910290721 ], [ -56.58594621444621, -22.365146172557843 ], [ -56.609381475874386, -22.376721693751165 ], [ -56.614910854951972, -22.380442396799197 ], [ -56.657698941353033, -22.437028089774515 ], [ -56.664933640974766, -22.442919203158681 ], [ -56.697076382169314, -22.463073012009886 ], [ -56.702424893194234, -22.468188979038132 ], [ -56.706481493026502, -22.47377003316052 ], [ -56.709323696931051, -22.479609469701245 ], [ -56.710047167342907, -22.486585788703167 ], [ -56.70544796425213, -22.508238213422828 ], [ -56.706481493026502, -22.515886325993165 ], [ -56.709892136812641, -22.521415704171432 ], [ -56.71973649814089, -22.527875257437188 ], [ -56.722191128417819, -22.53314625409638 ], [ -56.721906907577704, -22.540329277773935 ], [ -56.716739264605394, -22.560534762569262 ], [ -56.716170823824427, -22.566322524065242 ], [ -56.717126838233014, -22.585184420824362 ], [ -56.714723883900092, -22.603994642538737 ], [ -56.715188971893554, -22.615363458157049 ], [ -56.716868455814563, -22.624613538484027 ], [ -56.71973649814089, -22.632675063103704 ], [ -56.721596849215189, -22.643785496303622 ], [ -56.719555630088223, -22.653087253473984 ], [ -56.714878912631718, -22.660373629939102 ], [ -56.705499641095571, -22.671690768714029 ], [ -56.70353593633439, -22.679132174810036 ], [ -56.70389767064097, -22.686160169756022 ], [ -56.707049932908092, -22.701249687523045 ], [ -56.704776169784395, -22.708174329681583 ], [ -56.700021938861369, -22.712670179984798 ], [ -56.694440883839718, -22.715874119095304 ], [ -56.689195725602247, -22.7196464980874 ], [ -56.68273617233649, -22.726622817089321 ], [ -56.674235399044449, -22.739438571732705 ], [ -56.666225552167475, -22.759282322221395 ], [ -56.658474086809633, -22.79964161496855 ], [ -56.652221239118887, -22.81757333664018 ], [ -56.653306443837323, -22.828063653115123 ], [ -56.657931485349764, -22.834781588799274 ], [ -56.68004899806283, -22.848114109178823 ], [ -56.686689419381196, -22.855193780068873 ], [ -56.692192959137742, -22.86304859821422 ], [ -56.694647590314048, -22.875192560188509 ], [ -56.693820767114687, -22.878551528030584 ], [ -56.690022548801551, -22.879688408693085 ], [ -56.683976405786495, -22.879326673487185 ], [ -56.670463019152976, -22.879533379961515 ], [ -56.651911179857052, -22.877828057618785 ], [ -56.646562668832075, -22.876122735275999 ], [ -56.6420668203275, -22.873487236946403 ], [ -56.634289517447257, -22.866510918843858 ], [ -56.629767828722322, -22.864288831664226 ], [ -56.623437465766415, -22.865425714125422 ], [ -56.616926235657218, -22.869456475535912 ], [ -56.608089565580997, -22.878138115981244 ], [ -56.601655849837584, -22.882995700591096 ], [ -56.595428839669182, -22.886716403639127 ], [ -56.589305183187662, -22.888266697250288 ], [ -56.582768113757425, -22.889041842706888 ], [ -56.576902838794979, -22.888266697250288 ], [ -56.571554327770002, -22.887026462001643 ], [ -56.552227342118158, -22.87886158549378 ], [ -56.540806850555725, -22.876432793638514 ], [ -56.536052618733379, -22.87405567772737 ], [ -56.532357754107068, -22.870386650623459 ], [ -56.52447709843932, -22.855452161588005 ], [ -56.513986781964434, -22.842946466206456 ], [ -56.511092902115706, -22.838140557540726 ], [ -56.509180874197966, -22.832301120999944 ], [ -56.505951096665797, -22.812922458504659 ], [ -56.504349128009835, -22.807031345120492 ], [ -56.50078345369343, -22.798194675044215 ], [ -56.499775764240098, -22.796282647126475 ], [ -56.498535528991454, -22.794577324783688 ], [ -56.492411871610557, -22.788634534556138 ], [ -56.48380774643033, -22.782743422071292 ], [ -56.47882096971199, -22.780417983003531 ], [ -56.473834194792232, -22.778557631029855 ], [ -56.420865851178064, -22.769772637797018 ], [ -56.415388149843238, -22.768274021029242 ], [ -56.405595466257751, -22.763778170726027 ], [ -56.40135799837293, -22.760832614933236 ], [ -56.397637295324898, -22.757111911885204 ], [ -56.390996874006532, -22.748843682589893 ], [ -56.379292161603985, -22.730291843293912 ], [ -56.376036545650038, -22.726106052252533 ], [ -56.372264166657942, -22.722385349204501 ], [ -56.367742478832326, -22.719594822143335 ], [ -56.362368130284949, -22.717579440538771 ], [ -56.350818446614028, -22.715098971840064 ], [ -56.345779994850886, -22.713135267978259 ], [ -56.341154955137085, -22.710551445592728 ], [ -56.315859340835914, -22.692361341502703 ], [ -56.311156785856952, -22.690087579278384 ], [ -56.305859950776096, -22.689002373660628 ], [ -56.300614794337264, -22.689105726448133 ], [ -56.294568651322209, -22.690552667271788 ], [ -56.279866706283485, -22.69597869176323 ], [ -56.275086636039418, -22.701404718053311 ], [ -56.271572638566397, -22.707089124963147 ], [ -56.128144700917233, -23.052494398897409 ], [ -56.127369553661993, -23.05869557064409 ], [ -56.129229905635611, -23.069806003844008 ], [ -56.130392625619152, -23.105566095299082 ], [ -56.131477831236907, -23.111302179052302 ], [ -56.133725755039563, -23.11610808681877 ], [ -56.137368943721754, -23.119622084291734 ], [ -56.14214901396582, -23.12168914184042 ], [ -56.148014288928266, -23.12184417057199 ], [ -56.153362799953243, -23.120397230647654 ], [ -56.16310380669529, -23.11610808681877 ], [ -56.168013068148582, -23.115642998825365 ], [ -56.171992153615008, -23.117813409161499 ], [ -56.174627651944547, -23.122102552990441 ], [ -56.175712856662983, -23.127683608012092 ], [ -56.175583666353134, -23.133884779758773 ], [ -56.173697475957738, -23.144530124965286 ], [ -56.174731003832733, -23.148870944738292 ], [ -56.178606737410973, -23.151558119012009 ], [ -56.18354183638661, -23.153676852504759 ], [ -56.187727627428046, -23.15677743882776 ], [ -56.190699021642502, -23.160859877081691 ], [ -56.192740240769467, -23.166027520054001 ], [ -56.194238858436563, -23.171453545444763 ], [ -56.195014003893164, -23.17832651075986 ], [ -56.194781459896433, -23.186698092842732 ], [ -56.190905728116832, -23.200857435522209 ], [ -56.190543992910932, -23.208918959242567 ], [ -56.192585212037898, -23.214396660577449 ], [ -56.19669348781423, -23.217342218168824 ], [ -56.235218267908749, -23.236617526977284 ], [ -56.243977423619185, -23.242353610730561 ], [ -56.247982346608012, -23.245505872997626 ], [ -56.251651373711923, -23.248968193627263 ], [ -56.254364387306623, -23.253464043930478 ], [ -56.25875688302375, -23.262972506675851 ], [ -56.262322557340156, -23.266693210623203 ], [ -56.271443447357228, -23.271809176752129 ], [ -56.275551724032823, -23.274961439918513 ], [ -56.279117398349229, -23.278527114234919 ], [ -56.28221798377291, -23.28260955158953 ], [ -56.284388394109101, -23.287518813042766 ], [ -56.285835334033436, -23.292996515276968 ], [ -56.289090949088006, -23.317542819845244 ], [ -56.291571417786713, -23.327309665908331 ], [ -56.292579108139307, -23.329945164237927 ], [ -56.294568651322209, -23.333459160811628 ], [ -56.296273972765619, -23.335939629510278 ], [ -56.301028204587965, -23.33966033255831 ], [ -56.333584356932533, -23.352114352895057 ], [ -56.346090054112722, -23.366170342787086 ], [ -56.354151576933702, -23.378831068698844 ], [ -56.367690802888262, -23.388391209186977 ], [ -56.38112667515594, -23.400225111899374 ], [ -56.404897834267615, -23.411387221043412 ], [ -56.412339240363622, -23.412265720186838 ], [ -56.41851457368864, -23.411800632193433 ], [ -56.424870775066211, -23.410767103419118 ], [ -56.433707445142488, -23.410405369112482 ], [ -56.473705002683744, -23.4204305966947 ], [ -56.518172573005813, -23.44120452227088 ], [ -56.52522640637352, -23.443633315025465 ], [ -56.534760708439933, -23.443633315025465 ], [ -56.549204271060262, -23.445028578106417 ], [ -56.5811661442022, -23.451746514689887 ], [ -56.596152310081038, -23.453245130558344 ], [ -56.605350715363215, -23.452314954571477 ], [ -56.612068651047423, -23.445183607737306 ], [ -56.620336880342734, -23.443013198300491 ], [ -56.632558355783488, -23.442031344570921 ], [ -56.658603278018859, -23.444718519743901 ], [ -56.671858283133247, -23.444770195687965 ], [ -56.68157345235295, -23.443840019701156 ], [ -56.705602992983756, -23.431747734570308 ], [ -56.715705735831023, -23.430249118701852 ], [ -56.730045945663846, -23.429629001976878 ], [ -56.788181932250382, -23.432574557769613 ], [ -56.838514776635634, -23.42172250698809 ], [ -56.862699347796649, -23.419035332714429 ], [ -56.871458502607823, -23.41981047907035 ], [ -56.877995572038003, -23.422032566249925 ], [ -56.886728889326776, -23.429473971446612 ], [ -56.893033412961643, -23.433814793018314 ], [ -56.89954464397016, -23.435675144092613 ], [ -56.908045417262201, -23.436295260817644 ], [ -56.933392706608117, -23.434744968105804 ], [ -56.943934699027125, -23.436140232086018 ], [ -56.957654792134917, -23.439344171196524 ], [ -56.977085129675004, -23.447509046805067 ], [ -56.984552375092051, -23.448955986729402 ], [ -56.991011929257127, -23.448645929266206 ], [ -56.998815069659713, -23.446113782824796 ], [ -57.006644050282659, -23.444460138224827 ], [ -57.016798469074104, -23.443374932607071 ], [ -57.024110683960885, -23.444150078962991 ], [ -57.030079311710836, -23.446165459668237 ], [ -57.034626837958172, -23.448904310785338 ], [ -57.038605923424598, -23.452159925839908 ], [ -57.045892299889715, -23.456087334462893 ], [ -57.089972296584222, -23.469109795580607 ], [ -57.161518317016714, -23.47939340558122 ], [ -57.208156296775655, -23.47897999353188 ], [ -57.218569098884814, -23.48016855193714 ], [ -57.226139696190046, -23.482493991904221 ], [ -57.24316708029653, -23.491072279562047 ], [ -57.263269212304294, -23.498151950452154 ], [ -57.274017910298312, -23.500270684844224 ], [ -57.281588507603544, -23.50078744878175 ], [ -57.28401730035813, -23.500322360788346 ], [ -57.35047319218404, -23.504766534248176 ], [ -57.357113614401783, -23.504146416623826 ], [ -57.368146532336596, -23.50171762476856 ], [ -57.372849087315501, -23.500115655213335 ], [ -57.398454759079868, -23.486989841308116 ], [ -57.40369991731734, -23.484871107815366 ], [ -57.408454149139686, -23.482390639116716 ], [ -57.420494758326413, -23.477739760081874 ], [ -57.446177945355885, -23.474484145027247 ], [ -57.442173020568418, -23.46471729896416 ], [ -57.442457241408533, -23.45743092159978 ], [ -57.446177945355885, -23.447198988442551 ], [ -57.452740851409146, -23.417330011271019 ], [ -57.453619350552572, -23.409320163494726 ], [ -57.456719936875572, -23.403894138103965 ], [ -57.470388353139981, -23.393868909622483 ], [ -57.477183804089293, -23.382706800478445 ], [ -57.494779628976687, -23.367720635498927 ], [ -57.500799932670759, -23.35779876070427 ], [ -57.503667974997029, -23.343536065237231 ], [ -57.501445888716773, -23.336714775866199 ], [ -57.495528936910887, -23.330255221701123 ], [ -57.48713151730567, -23.316819349433445 ], [ -57.482093064643209, -23.306380710701262 ], [ -57.480181036725469, -23.30054127416048 ], [ -57.480310227934638, -23.278992200429684 ], [ -57.484030930982669, -23.273049412000773 ], [ -57.500567389573348, -23.257856540546925 ], [ -57.511161057936476, -23.250208428875908 ], [ -57.535552333773182, -23.220649509167515 ], [ -57.544363166327059, -23.213156427127387 ], [ -57.550926073279641, -23.208815605555742 ], [ -57.58849483896563, -23.192072442289373 ], [ -57.608596970973451, -23.179980157158525 ], [ -57.624616664727284, -23.165304049642202 ], [ -57.631127895735801, -23.148922620682413 ], [ -57.630636970219996, -23.127993665475287 ], [ -57.632058071722611, -23.111147148522093 ], [ -57.639861213024574, -23.098796481872171 ], [ -57.658464728264562, -23.090889987782703 ], [ -57.698178066764342, -23.090683282207692 ], [ -57.714068570208326, -23.085153904029426 ], [ -57.720528124373459, -23.066395359158491 ], [ -57.729881558387206, -23.054819837965169 ], [ -57.774374966231676, -23.034821058744853 ], [ -57.789412808054635, -23.021385185577856 ], [ -57.767682868069926, -22.981646009555675 ], [ -57.772928026307341, -22.960717055247926 ], [ -57.786002163369119, -22.944749036538781 ], [ -57.819514330122217, -22.915861912197499 ], [ -57.821038784412337, -22.905940036503466 ], [ -57.81127193924857, -22.896948336796299 ], [ -57.798068610078303, -22.887956637988452 ], [ -57.789412808054635, -22.877983087249675 ], [ -57.788379279280321, -22.866045830850396 ], [ -57.792358363847427, -22.856847425568219 ], [ -57.802435269172349, -22.843876642193266 ], [ -57.808920660859826, -22.826410006716458 ], [ -57.811943731917665, -22.821294040587532 ], [ -57.819514330122217, -22.813129164079669 ], [ -57.828867764136021, -22.809253432300068 ], [ -57.851760423204951, -22.810441989806009 ], [ -57.860803798856239, -22.806307874708637 ], [ -57.867030809024584, -22.795300795195544 ], [ -57.872043423265382, -22.771788017602944 ], [ -57.877546963021928, -22.761917819651671 ], [ -57.885970221948185, -22.756956882254315 ], [ -57.908862881017114, -22.751220797601718 ], [ -57.918526374292753, -22.747035006560282 ], [ -57.940204637434078, -22.716339207088765 ], [ -57.92922339544333, -22.686470229017857 ], [ -57.895814582377056, -22.664869480242317 ], [ -57.850235968914831, -22.658926690014709 ], [ -57.806905280154524, -22.665747978486422 ], [ -57.78471025307573, -22.665282892291657 ], [ -57.775150112587596, -22.655464368485809 ], [ -57.779671800413269, -22.634018650240534 ], [ -57.79065304240396, -22.617378838862351 ], [ -57.816103685436701, -22.589990329490092 ], [ -57.830573085579431, -22.559191175432431 ], [ -57.843414680443118, -22.446019788582362 ], [ -57.848969896143785, -22.423023776725927 ], [ -57.851631231995725, -22.411861667581888 ], [ -57.845275030618154, -22.404471937429946 ], [ -57.826671516277429, -22.388607273307002 ], [ -57.831193203203782, -22.37718678174457 ], [ -57.877546963021928, -22.323133232512646 ], [ -57.88739132255148, -22.289801934711534 ], [ -57.896718919042883, -22.279259942292526 ], [ -57.915399950447352, -22.275332532770165 ], [ -57.940747239793268, -22.27429900489517 ], [ -57.956146816822127, -22.269131361922803 ], [ -57.965732794832604, -22.256832371216944 ], [ -57.973768480131241, -22.234353123297979 ], [ -57.977256639182542, -22.210633640130368 ], [ -57.966921353237865, -22.148363538446517 ], [ -57.974156052859541, -22.132188815961115 ], [ -57.981209886227248, -22.090330905546864 ], [ -57.973251716193715, -22.081184177108071 ], [ -57.973133663999874, -22.081048493999958 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-13", "NAME_1": "Amambay" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -56.421796834999924, -22.074465433999904 ], [ -56.407637491999964, -22.075809020999955 ], [ -56.397302205999949, -22.086247660999987 ], [ -56.370843872999956, -22.147329202999899 ], [ -56.347331095999976, -22.180402119999982 ], [ -56.316841999999895, -22.207687275999902 ], [ -56.26108313099985, -22.238589782999981 ], [ -56.231524210999908, -22.265358173999871 ], [ -56.21426428299992, -22.275383401999889 ], [ -56.196797647999887, -22.279310811999949 ], [ -56.024715128999929, -22.28737233399994 ], [ -56.011356770999896, -22.283858337999987 ], [ -55.998566853999932, -22.277243753999898 ], [ -55.985234334999916, -22.28323821999993 ], [ -55.970868286999888, -22.293883564999916 ], [ -55.955262003999877, -22.301324970999943 ], [ -55.892940225999922, -22.306802673999925 ], [ -55.874388386999982, -22.317344664999979 ], [ -55.872011270999934, -22.310213316999949 ], [ -55.861030029999938, -22.289542744999935 ], [ -55.810774698999893, -22.353104756999912 ], [ -55.770157023999872, -22.38142344099991 ], [ -55.760235147999964, -22.391965433999957 ], [ -55.751579345999914, -22.41625335699996 ], [ -55.748297892999915, -22.500899352999866 ], [ -55.741269897999928, -22.537176208999924 ], [ -55.723932453999907, -22.569629006999932 ], [ -55.697913371999931, -22.59557057699989 ], [ -55.66468542599992, -22.612727151999948 ], [ -55.644350748999983, -22.61954844199991 ], [ -55.631199096999921, -22.62678314199988 ], [ -55.623680175999965, -22.638668721999906 ], [ -55.620476237999895, -22.659339293999921 ], [ -55.621509765999889, -22.667090758999919 ], [ -55.627013305999867, -22.683627217999913 ], [ -55.62778845299988, -22.692102151999919 ], [ -55.625669718999916, -22.700783792999886 ], [ -55.619184325999953, -22.71690683999995 ], [ -55.618331665999904, -22.725691833999946 ], [ -55.628589436999903, -22.758971455999884 ], [ -55.645926879999905, -22.78791025799994 ], [ -55.659001017999856, -22.818296 ], [ -55.656572224999906, -22.85570973699997 ], [ -55.634299682999938, -22.932810973999921 ], [ -55.634351359999954, -22.950070901999908 ], [ -55.639984089999899, -22.98376393599996 ], [ -55.637813679999908, -23.000713805999879 ], [ -55.611458699999844, -23.029135843999896 ], [ -55.600684163999915, -23.044535419999974 ], [ -55.595232299999935, -23.064069111999885 ], [ -55.600141561999862, -23.100552672999896 ], [ -55.599392252999877, -23.11708913199989 ], [ -55.588669392999947, -23.130111591999921 ], [ -55.560867472999888, -23.145924579999928 ], [ -55.557146769999889, -23.154709574999913 ], [ -55.535235962999934, -23.229123635999926 ], [ -55.535649373999945, -23.245866800999877 ], [ -55.559007120999894, -23.291342060999938 ], [ -55.562159383999955, -23.307878519999932 ], [ -55.555596476999966, -23.330306090999926 ], [ -55.524874836999913, -23.360485126999919 ], [ -55.513867757999918, -23.379398701999961 ], [ -55.515547241999883, -23.410197855999925 ], [ -55.542470662999904, -23.465801696999932 ], [ -55.539912678999912, -23.500528259999967 ], [ -55.533795620999854, -23.530444136999861 ], [ -55.534330817413263, -23.530811455584228 ], [ -55.543968472267181, -23.537426038480874 ], [ -55.553838670218454, -23.552153822840637 ], [ -55.571692878423619, -23.596905613103559 ], [ -55.579909430875546, -23.635559583507984 ], [ -55.586653204981417, -23.645894871251301 ], [ -55.597841153446495, -23.655661715515748 ], [ -55.638898078183729, -23.677779229128134 ], [ -55.647450528319212, -23.680879814551815 ], [ -55.656571418336284, -23.683050225787269 ], [ -55.684580044433517, -23.683515312881411 ], [ -55.699204474207136, -23.689303073478072 ], [ -55.720624355829329, -23.701136977089845 ], [ -55.824158087825481, -23.771158543232161 ], [ -55.866842821439036, -23.793224379101844 ], [ -55.87697140180876, -23.802267754753075 ], [ -55.890975714857348, -23.825160413822061 ], [ -55.897099372238245, -23.831464939255568 ], [ -55.906581996561897, -23.837356051740414 ], [ -55.932265183591369, -23.846916192228491 ], [ -55.957173224264864, -23.852393893563317 ], [ -55.992907477298218, -23.855339451154748 ], [ -56.000813972287006, -23.858078302271849 ], [ -56.009082200682997, -23.86210906278302 ], [ -56.014404873286253, -23.864072767544201 ], [ -56.019908413042799, -23.865054619475131 ], [ -56.026316291263811, -23.864279474018531 ], [ -56.032439947745388, -23.862419122044855 ], [ -56.047141892784111, -23.856062920667284 ], [ -56.05907914918339, -23.848518161783716 ], [ -56.051327683825548, -23.847226250591007 ], [ -56.042025925755866, -23.843505547542975 ], [ -56.008307054327076, -23.820612887574725 ], [ -56.006110805569222, -23.818442478137854 ], [ -56.004198777651482, -23.815031833452338 ], [ -55.998876105048225, -23.798236992443265 ], [ -55.981461148213384, -23.768212985640787 ], [ -55.977172004384499, -23.758291110846073 ], [ -55.975673386717403, -23.752813408611928 ], [ -55.975001594048308, -23.74666391370863 ], [ -55.974639858842409, -23.720980726679215 ], [ -55.977533738691079, -23.696641126786574 ], [ -55.98236548487921, -23.681189873813651 ], [ -55.982830572872615, -23.676280613259678 ], [ -55.980892707432474, -23.672043144475538 ], [ -55.958620165088519, -23.644654636002656 ], [ -55.947948980561023, -23.633905938008638 ], [ -55.94190283934455, -23.625792739243536 ], [ -55.935107388395238, -23.611271660458783 ], [ -55.933763801258408, -23.605742283179836 ], [ -55.933092006790673, -23.59985116979567 ], [ -55.9367093570512, -23.56300587272284 ], [ -55.935830857907774, -23.550138442135392 ], [ -55.933479580418293, -23.538717949673639 ], [ -55.933634610049182, -23.533912041907229 ], [ -55.936244269057738, -23.530191338859197 ], [ -55.946243659117556, -23.528796074878983 ], [ -55.960041265691871, -23.529209486928266 ], [ -56.021148648291501, -23.540423272016369 ], [ -56.030036994311843, -23.543833916701885 ], [ -56.034119431666454, -23.546882826181502 ], [ -56.035230474806554, -23.552205498784758 ], [ -56.034791226134189, -23.566726575770872 ], [ -56.036005622061793, -23.575511569903028 ], [ -56.038382737972995, -23.581867771280599 ], [ -56.0419484122894, -23.586622003102946 ], [ -56.047296922415057, -23.590032646889142 ], [ -56.058562385245864, -23.595148613917388 ], [ -56.065538703348466, -23.599489434589714 ], [ -56.08086076511222, -23.611168307671278 ], [ -56.086441820133871, -23.613907158788322 ], [ -56.091557787162117, -23.614010511575827 ], [ -56.101686366632521, -23.607292575891677 ], [ -56.114140387868588, -23.594580173136478 ], [ -56.132020432696777, -23.565279635846537 ], [ -56.140133633260575, -23.548484795736726 ], [ -56.145172085023717, -23.535307305887443 ], [ -56.147497524990797, -23.526625664542792 ], [ -56.147755907409191, -23.519804376071079 ], [ -56.14424190903685, -23.514843437774459 ], [ -56.061533780359696, -23.452056573052403 ], [ -56.053162197377503, -23.443013198300491 ], [ -56.046521776059137, -23.433918144906443 ], [ -56.044144660147936, -23.428647149146627 ], [ -56.042956101742675, -23.423376152487435 ], [ -56.043214484161126, -23.41965544943946 ], [ -56.044738939350566, -23.414126072160514 ], [ -56.047917040039351, -23.407046401270406 ], [ -56.052102831080788, -23.400845228624405 ], [ -56.055978562860389, -23.396814467213915 ], [ -56.072825079813583, -23.383171888471907 ], [ -56.07739844358332, -23.37686736393772 ], [ -56.078819545985255, -23.372009780227188 ], [ -56.077320930116798, -23.366583753937107 ], [ -56.072204963088552, -23.356558525455569 ], [ -56.069724494389902, -23.350098972189812 ], [ -56.069440274449107, -23.344362887537216 ], [ -56.071584846363578, -23.337851657428075 ], [ -56.076390754129989, -23.330978692112978 ], [ -56.0842972482194, -23.32420907958533 ], [ -56.092927211821348, -23.31960987649461 ], [ -56.107344936919276, -23.316044203077524 ], [ -56.149487067274322, -23.313873792741333 ], [ -56.162638718701885, -23.311806736092024 ], [ -56.178425869358364, -23.307362562632136 ], [ -56.183464322020825, -23.307982680256487 ], [ -56.192662726403682, -23.312426852816998 ], [ -56.203747321181936, -23.315062351146594 ], [ -56.224650437967341, -23.3179045550512 ], [ -56.243589849991565, -23.322555434086041 ], [ -56.266895921109892, -23.334079277536659 ], [ -56.27803219273153, -23.341675714162875 ], [ -56.286222906761736, -23.345396417210907 ], [ -56.290486213068277, -23.346688327504296 ], [ -56.301028204587965, -23.33966033255831 ], [ -56.296273972765619, -23.335939629510278 ], [ -56.294568651322209, -23.333459160811628 ], [ -56.292579108139307, -23.329945164237927 ], [ -56.291571417786713, -23.327309665908331 ], [ -56.289090949088006, -23.317542819845244 ], [ -56.285835334033436, -23.292996515276968 ], [ -56.284388394109101, -23.287518813042766 ], [ -56.28221798377291, -23.28260955158953 ], [ -56.279117398349229, -23.278527114234919 ], [ -56.275551724032823, -23.274961439918513 ], [ -56.271443447357228, -23.271809176752129 ], [ -56.262322557340156, -23.266693210623203 ], [ -56.25875688302375, -23.262972506675851 ], [ -56.254364387306623, -23.253464043930478 ], [ -56.251651373711923, -23.248968193627263 ], [ -56.247982346608012, -23.245505872997626 ], [ -56.243977423619185, -23.242353610730561 ], [ -56.235218267908749, -23.236617526977284 ], [ -56.19669348781423, -23.217342218168824 ], [ -56.192585212037898, -23.214396660577449 ], [ -56.190543992910932, -23.208918959242567 ], [ -56.190905728116832, -23.200857435522209 ], [ -56.194781459896433, -23.186698092842732 ], [ -56.195014003893164, -23.17832651075986 ], [ -56.194238858436563, -23.171453545444763 ], [ -56.192740240769467, -23.166027520054001 ], [ -56.190699021642502, -23.160859877081691 ], [ -56.187727627428046, -23.15677743882776 ], [ -56.18354183638661, -23.153676852504759 ], [ -56.178606737410973, -23.151558119012009 ], [ -56.174731003832733, -23.148870944738292 ], [ -56.173697475957738, -23.144530124965286 ], [ -56.175583666353134, -23.133884779758773 ], [ -56.175712856662983, -23.127683608012092 ], [ -56.174627651944547, -23.122102552990441 ], [ -56.171992153615008, -23.117813409161499 ], [ -56.168013068148582, -23.115642998825365 ], [ -56.16310380669529, -23.11610808681877 ], [ -56.153362799953243, -23.120397230647654 ], [ -56.148014288928266, -23.12184417057199 ], [ -56.14214901396582, -23.12168914184042 ], [ -56.137368943721754, -23.119622084291734 ], [ -56.133725755039563, -23.11610808681877 ], [ -56.131477831236907, -23.111302179052302 ], [ -56.130392625619152, -23.105566095299082 ], [ -56.129229905635611, -23.069806003844008 ], [ -56.127369553661993, -23.05869557064409 ], [ -56.128144700917233, -23.052494398897409 ], [ -56.271572638566397, -22.707089124963147 ], [ -56.275086636039418, -22.701404718053311 ], [ -56.279866706283485, -22.69597869176323 ], [ -56.294568651322209, -22.690552667271788 ], [ -56.300614794337264, -22.689105726448133 ], [ -56.305859950776096, -22.689002373660628 ], [ -56.311156785856952, -22.690087579278384 ], [ -56.315859340835914, -22.692361341502703 ], [ -56.341154955137085, -22.710551445592728 ], [ -56.345779994850886, -22.713135267978259 ], [ -56.350818446614028, -22.715098971840064 ], [ -56.362368130284949, -22.717579440538771 ], [ -56.367742478832326, -22.719594822143335 ], [ -56.372264166657942, -22.722385349204501 ], [ -56.376036545650038, -22.726106052252533 ], [ -56.379292161603985, -22.730291843293912 ], [ -56.390996874006532, -22.748843682589893 ], [ -56.397637295324898, -22.757111911885204 ], [ -56.40135799837293, -22.760832614933236 ], [ -56.405595466257751, -22.763778170726027 ], [ -56.415388149843238, -22.768274021029242 ], [ -56.420865851178064, -22.769772637797018 ], [ -56.473834194792232, -22.778557631029855 ], [ -56.47882096971199, -22.780417983003531 ], [ -56.48380774643033, -22.782743422071292 ], [ -56.492411871610557, -22.788634534556138 ], [ -56.498535528991454, -22.794577324783688 ], [ -56.499775764240098, -22.796282647126475 ], [ -56.50078345369343, -22.798194675044215 ], [ -56.504349128009835, -22.807031345120492 ], [ -56.505951096665797, -22.812922458504659 ], [ -56.509180874197966, -22.832301120999944 ], [ -56.511092902115706, -22.838140557540726 ], [ -56.513986781964434, -22.842946466206456 ], [ -56.52447709843932, -22.855452161588005 ], [ -56.532357754107068, -22.870386650623459 ], [ -56.536052618733379, -22.87405567772737 ], [ -56.540806850555725, -22.876432793638514 ], [ -56.552227342118158, -22.87886158549378 ], [ -56.571554327770002, -22.887026462001643 ], [ -56.576902838794979, -22.888266697250288 ], [ -56.582768113757425, -22.889041842706888 ], [ -56.589305183187662, -22.888266697250288 ], [ -56.595428839669182, -22.886716403639127 ], [ -56.601655849837584, -22.882995700591096 ], [ -56.608089565580997, -22.878138115981244 ], [ -56.616926235657218, -22.869456475535912 ], [ -56.623437465766415, -22.865425714125422 ], [ -56.629767828722322, -22.864288831664226 ], [ -56.634289517447257, -22.866510918843858 ], [ -56.6420668203275, -22.873487236946403 ], [ -56.646562668832075, -22.876122735275999 ], [ -56.651911179857052, -22.877828057618785 ], [ -56.670463019152976, -22.879533379961515 ], [ -56.683976405786495, -22.879326673487185 ], [ -56.690022548801551, -22.879688408693085 ], [ -56.693820767114687, -22.878551528030584 ], [ -56.694647590314048, -22.875192560188509 ], [ -56.692192959137742, -22.86304859821422 ], [ -56.686689419381196, -22.855193780068873 ], [ -56.68004899806283, -22.848114109178823 ], [ -56.657931485349764, -22.834781588799274 ], [ -56.653306443837323, -22.828063653115123 ], [ -56.652221239118887, -22.81757333664018 ], [ -56.658474086809633, -22.79964161496855 ], [ -56.666225552167475, -22.759282322221395 ], [ -56.674235399044449, -22.739438571732705 ], [ -56.68273617233649, -22.726622817089321 ], [ -56.689195725602247, -22.7196464980874 ], [ -56.694440883839718, -22.715874119095304 ], [ -56.700021938861369, -22.712670179984798 ], [ -56.704776169784395, -22.708174329681583 ], [ -56.707049932908092, -22.701249687523045 ], [ -56.70389767064097, -22.686160169756022 ], [ -56.70353593633439, -22.679132174810036 ], [ -56.705499641095571, -22.671690768714029 ], [ -56.714878912631718, -22.660373629939102 ], [ -56.719555630088223, -22.653087253473984 ], [ -56.721596849215189, -22.643785496303622 ], [ -56.71973649814089, -22.632675063103704 ], [ -56.716868455814563, -22.624613538484027 ], [ -56.715188971893554, -22.615363458157049 ], [ -56.714723883900092, -22.603994642538737 ], [ -56.717126838233014, -22.585184420824362 ], [ -56.716170823824427, -22.566322524065242 ], [ -56.716739264605394, -22.560534762569262 ], [ -56.721906907577704, -22.540329277773935 ], [ -56.722191128417819, -22.53314625409638 ], [ -56.71973649814089, -22.527875257437188 ], [ -56.709892136812641, -22.521415704171432 ], [ -56.706481493026502, -22.515886325993165 ], [ -56.70544796425213, -22.508238213422828 ], [ -56.710047167342907, -22.486585788703167 ], [ -56.709323696931051, -22.479609469701245 ], [ -56.706481493026502, -22.47377003316052 ], [ -56.702424893194234, -22.468188979038132 ], [ -56.697076382169314, -22.463073012009886 ], [ -56.664933640974766, -22.442919203158681 ], [ -56.657698941353033, -22.437028089774515 ], [ -56.614910854951972, -22.380442396799197 ], [ -56.609381475874386, -22.376721693751165 ], [ -56.58594621444621, -22.365146172557843 ], [ -56.582018805823225, -22.361993910290721 ], [ -56.622610642567111, -22.347162774042772 ], [ -56.834096441597467, -22.298276868682535 ], [ -56.842856404999907, -22.289025981 ], [ -56.819653686999914, -22.265461526999985 ], [ -56.813142455999952, -22.256159769999968 ], [ -56.811902221999901, -22.249648538999907 ], [ -56.808284871999916, -22.247994893999945 ], [ -56.794564778999899, -22.252542419999983 ], [ -56.786994180999926, -22.251818948999897 ], [ -56.754360514999888, -22.242620543999891 ], [ -56.746789916999916, -22.243964130999956 ], [ -56.745601358999892, -22.248408304999955 ], [ -56.743534301999944, -22.250372008999904 ], [ -56.733199015999929, -22.244067484999974 ], [ -56.728548135999858, -22.237452900999884 ], [ -56.720538289999894, -22.2194695029999 ], [ -56.715370646999872, -22.215438741 ], [ -56.698601643999922, -22.223500263999895 ], [ -56.66457271299987, -22.25998382599991 ], [ -56.648811401999893, -22.263497822999867 ], [ -56.644134684999926, -22.255436299999971 ], [ -56.654702514999912, -22.237349547999955 ], [ -56.648346313999866, -22.231355081999922 ], [ -56.637184204999926, -22.228254495999892 ], [ -56.629174356999954, -22.224740497999932 ], [ -56.595739705999875, -22.201486103999912 ], [ -56.584965168999958, -22.190530700999929 ], [ -56.567911946999914, -22.16231536899997 ], [ -56.565302286999895, -22.159938252999922 ], [ -56.558015909999938, -22.156424254999962 ], [ -56.554605265999896, -22.15208343499998 ], [ -56.549075886999901, -22.136270446999987 ], [ -56.545975300999942, -22.130069274999911 ], [ -56.530679077999906, -22.109088643999911 ], [ -56.521635701999941, -22.099890237999915 ], [ -56.511300414999937, -22.091415303999909 ], [ -56.493833781999882, -22.086557718999885 ], [ -56.421796834999924, -22.074465433999904 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-14", "NAME_1": "Canindeyú" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -55.533795620999854, -23.530444136999861 ], [ -55.533065551999954, -23.534014586999959 ], [ -55.533892374999965, -23.569981383999945 ], [ -55.53053340699995, -23.60346771199994 ], [ -55.511309773999926, -23.629409280999894 ], [ -55.466971395999877, -23.673230896 ], [ -55.445318969999903, -23.735449319999901 ], [ -55.430177774999976, -23.928564147999879 ], [ -55.420669311999916, -23.954505715999915 ], [ -55.398035033999946, -23.976829935999973 ], [ -55.367184203999955, -23.989645690999879 ], [ -55.304345662999907, -23.994089863999974 ], [ -55.272719685999903, -24.000394388999979 ], [ -55.272668008999887, -24.000497741999922 ], [ -55.272564656999862, -24.000497741999922 ], [ -55.272409627999934, -24.000601094999936 ], [ -55.23683040399996, -24.012693379999931 ], [ -55.200863606999889, -24.019514667999971 ], [ -55.165439412999945, -24.016827493999955 ], [ -55.131281290999965, -24.000601094999936 ], [ -55.131203776999939, -24.000601094999936 ], [ -55.131074584999908, -24.000601094999936 ], [ -55.131074584999908, -24.000394388999979 ], [ -55.105572265999882, -23.988508809999956 ], [ -55.042294473999902, -23.989025573999896 ], [ -55.011495320999927, -23.980550638999901 ], [ -54.994571289999925, -23.973109232999974 ], [ -54.961059122999927, -23.971765644999905 ], [ -54.94364416499991, -23.969181823999904 ], [ -54.926745971999907, -23.959880065999883 ], [ -54.90488684099995, -23.933008320999889 ], [ -54.891916056999946, -23.920605976999909 ], [ -54.827423868999915, -23.887016296999974 ], [ -54.696837523999932, -23.845158385999909 ], [ -54.679784301999916, -23.836683450999914 ], [ -54.654592040999944, -23.811465351999956 ], [ -54.639218302999979, -23.804437356999941 ], [ -54.612553263999928, -23.81115529399996 ], [ -54.443157918999901, -23.899935403999891 ], [ -54.422900756999894, -23.913784688999954 ], [ -54.367606974999973, -23.984684753999915 ], [ -54.273607543999844, -24.03646453799989 ], [ -54.245749848376818, -24.050393385446398 ], [ -54.245288858999942, -24.050623880999936 ], [ -54.266217814999919, -24.06592010499989 ], [ -54.301047729999908, -24.08989796999991 ], [ -54.324767211999927, -24.118216653999909 ], [ -54.334637410999932, -24.148912454999945 ], [ -54.331846882999884, -24.165035501999924 ], [ -54.318979451999951, -24.196764830999939 ], [ -54.314121866999955, -24.234178567999905 ], [ -54.306267048999928, -24.246684264999914 ], [ -54.282650919999895, -24.275313008999973 ], [ -54.274331013999927, -24.298257344999925 ], [ -54.261050170999937, -24.329469909 ], [ -54.262187051999945, -24.358512064999985 ], [ -54.271695515999909, -24.38941457099989 ], [ -54.284097859999889, -24.411325377999944 ], [ -54.322906859999932, -24.464345397999949 ], [ -54.334534057999889, -24.496694843999933 ], [ -54.334792439999973, -24.527287292999944 ], [ -54.320684773999943, -24.595913593999896 ], [ -54.321304890999897, -24.628366393999912 ], [ -54.358429465247639, -24.73142174661632 ], [ -54.358976202689576, -24.731203302190636 ], [ -54.381610480239488, -24.722159925640085 ], [ -54.395666470131459, -24.720454604196618 ], [ -54.421401333105052, -24.720609632928245 ], [ -54.444836595432548, -24.72283172010782 ], [ -54.469744636106043, -24.722676689577554 ], [ -54.49323157437766, -24.718180841072979 ], [ -54.521085170843946, -24.707483819023025 ], [ -54.549972296983924, -24.699577324933614 ], [ -54.626530930757838, -24.689190362145496 ], [ -54.63619442403342, -24.685314629466575 ], [ -54.643067390247836, -24.678079928945579 ], [ -54.648829312422833, -24.669760023706147 ], [ -54.659422979886585, -24.644645277457585 ], [ -54.663634610249062, -24.640304456785259 ], [ -54.668363002750368, -24.638805840916802 ], [ -54.67704464409502, -24.639891045635238 ], [ -54.691643236346295, -24.643921807945105 ], [ -54.69807695208965, -24.644851983032595 ], [ -54.706371018907362, -24.64361174868327 ], [ -54.71388994026853, -24.641131279984563 ], [ -54.725155402200016, -24.635963637012253 ], [ -54.733992072276294, -24.633948256307008 ], [ -54.746032680563758, -24.634878432293817 ], [ -54.753267381084754, -24.639684340060228 ], [ -54.758047451328821, -24.644231866307564 ], [ -54.764403652706392, -24.653481947533862 ], [ -54.768925339632688, -24.658442884931219 ], [ -54.774067145082654, -24.66309376396606 ], [ -54.779338140842526, -24.666194350289061 ], [ -54.784479946292493, -24.668364759725876 ], [ -54.790603603673389, -24.668674818987711 ], [ -54.795667893858194, -24.666039320658115 ], [ -54.801016404883171, -24.659011325712129 ], [ -54.800964728039787, -24.65032968526674 ], [ -54.800292935370692, -24.644335219095069 ], [ -54.800241257627931, -24.639684340060228 ], [ -54.803910284731842, -24.636583753737227 ], [ -54.811971807552879, -24.633173109951088 ], [ -54.826234503919238, -24.631467786708981 ], [ -54.862563036155166, -24.630227553258976 ], [ -54.871012131704504, -24.628987318909651 ], [ -54.878815273905786, -24.626351820580055 ], [ -54.885404019280031, -24.620202324777495 ], [ -54.887316047197828, -24.614827976230117 ], [ -54.886902635148488, -24.609712009201871 ], [ -54.884706387289953, -24.60428598381111 ], [ -54.883336960832082, -24.598704928789459 ], [ -54.882923549682062, -24.591625257899352 ], [ -54.884835577599802, -24.582633559091505 ], [ -54.896462774737245, -24.571884861097487 ], [ -54.915712246023304, -24.562014662246895 ], [ -54.992322556640659, -24.539587091171313 ], [ -55.000745815566916, -24.53974211990294 ], [ -55.01568030460237, -24.542170911758149 ], [ -55.039296434083155, -24.551162611465372 ], [ -55.051517910423229, -24.553539726477197 ], [ -55.064592048384327, -24.551524346671272 ], [ -55.079035611004656, -24.545788262917995 ], [ -55.093685879199938, -24.532765801800338 ], [ -55.098388434178901, -24.520725192613554 ], [ -55.099551154162441, -24.509563083469516 ], [ -55.09531368717694, -24.472717787296062 ], [ -55.116759406321535, -24.467498467480311 ], [ -55.227527838838682, -24.50217335421695 ], [ -55.489682379937904, -24.542791030281819 ], [ -55.509784511945668, -24.548888849240996 ], [ -55.522806973063325, -24.555710137712708 ], [ -55.632361008753549, -24.663507175116024 ], [ -55.682151251678931, -24.698543796159242 ], [ -55.696310594358408, -24.713168226832181 ], [ -55.724474250086587, -24.753320814903702 ], [ -55.750829229785097, -24.782673028137765 ], [ -55.804262661392727, -24.753630873266218 ], [ -55.814236213030824, -24.745672703232685 ], [ -55.8206957671959, -24.735182386757742 ], [ -55.827930466817577, -24.720764661659814 ], [ -55.836818813737239, -24.697716973859258 ], [ -55.856119960967419, -24.678803398458058 ], [ -55.872888962655509, -24.666039320658115 ], [ -55.902447883263221, -24.64898609812991 ], [ -55.913609992407203, -24.635033461025387 ], [ -55.924203660770331, -24.613277682618957 ], [ -55.93862138496894, -24.571626478679036 ], [ -55.960092943434574, -24.531525566551636 ], [ -56.013112962093544, -24.463726087588896 ], [ -56.033809374203258, -24.419801120525278 ], [ -56.03846025233878, -24.413651624722718 ], [ -56.044299688879505, -24.408690688224681 ], [ -56.051870287084057, -24.405228366695781 ], [ -56.070654670376712, -24.399337254210934 ], [ -56.079853074759569, -24.395203139113562 ], [ -56.088017951267432, -24.389983819297811 ], [ -56.096441210193689, -24.38249073725774 ], [ -56.10339168987457, -24.374480889481447 ], [ -56.109024420840342, -24.364869073049306 ], [ -56.114372931865319, -24.352776787918458 ], [ -56.118507046063314, -24.337325534945478 ], [ -56.122822028313976, -24.304717705757525 ], [ -56.125431688221852, -24.293503919770103 ], [ -56.129565803319167, -24.284253838543805 ], [ -56.135043503754673, -24.278672783522154 ], [ -56.156592576586149, -24.26161956099395 ], [ -56.158478766082169, -24.248855483194006 ], [ -56.158504605403209, -24.229786879061237 ], [ -56.152613491119723, -24.18301970809307 ], [ -56.153543667106533, -24.160798841693179 ], [ -56.148841112127627, -24.14539926466432 ], [ -56.145792201748691, -24.140386650423579 ], [ -56.126361864208661, -24.116202081061203 ], [ -56.122124396323841, -24.113101494738203 ], [ -56.11768022286401, -24.110465997307927 ], [ -56.112590095156747, -24.108192234184287 ], [ -56.088224656842442, -24.103179619943489 ], [ -56.08313452823586, -24.101009209607355 ], [ -56.07912960524709, -24.097908624183674 ], [ -56.066313848805066, -24.0821989887923 ], [ -56.043576219367026, -24.061890151209525 ], [ -56.030915492555948, -24.046077162131326 ], [ -56.015877651632309, -24.032486261132021 ], [ -56.011459316594198, -24.030005791534052 ], [ -56.007299363974482, -24.028455498822211 ], [ -56.002906867358035, -24.028300470090642 ], [ -56.000400560237665, -24.028455498822211 ], [ -55.994147711647543, -24.029850762802482 ], [ -55.992364874939028, -24.022719415068934 ], [ -55.997532517911338, -23.999826755100685 ], [ -56.05907914918339, -23.848518161783716 ], [ -56.047141892784111, -23.856062920667284 ], [ -56.032439947745388, -23.862419122044855 ], [ -56.026316291263811, -23.864279474018531 ], [ -56.019908413042799, -23.865054619475131 ], [ -56.014404873286253, -23.864072767544201 ], [ -56.009082200682997, -23.86210906278302 ], [ -56.000813972287006, -23.858078302271849 ], [ -55.992907477298218, -23.855339451154748 ], [ -55.957173224264864, -23.852393893563317 ], [ -55.932265183591369, -23.846916192228491 ], [ -55.906581996561897, -23.837356051740414 ], [ -55.897099372238245, -23.831464939255568 ], [ -55.890975714857348, -23.825160413822061 ], [ -55.87697140180876, -23.802267754753075 ], [ -55.866842821439036, -23.793224379101844 ], [ -55.824158087825481, -23.771158543232161 ], [ -55.720624355829329, -23.701136977089845 ], [ -55.699204474207136, -23.689303073478072 ], [ -55.684580044433517, -23.683515312881411 ], [ -55.656571418336284, -23.683050225787269 ], [ -55.647450528319212, -23.680879814551815 ], [ -55.638898078183729, -23.677779229128134 ], [ -55.597841153446495, -23.655661715515748 ], [ -55.586653204981417, -23.645894871251301 ], [ -55.579909430875546, -23.635559583507984 ], [ -55.571692878423619, -23.596905613103559 ], [ -55.553838670218454, -23.552153822840637 ], [ -55.543968472267181, -23.537426038480874 ], [ -55.534330817413263, -23.530811455584228 ], [ -55.533795620999854, -23.530444136999861 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-2", "NAME_1": "San Pedro" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -55.750829229785097, -24.782673028137765 ], [ -55.868909878088402, -24.811508476534982 ], [ -55.949370082962957, -24.841945896286063 ], [ -55.969911465441783, -24.857087090896528 ], [ -55.984561733637065, -24.873468519856317 ], [ -56.028435024756561, -24.952791843169052 ], [ -56.03711666520195, -24.964367363463055 ], [ -56.045746628803897, -24.971498712095865 ], [ -56.054428270148549, -24.967881361835396 ], [ -56.1008853827542, -24.928193861757336 ], [ -56.134965990288208, -24.893002211083171 ], [ -56.14155473476319, -24.888092949629936 ], [ -56.147885097719097, -24.884785657731925 ], [ -56.193773770443158, -24.868920993608981 ], [ -56.20377315870428, -24.862564793130673 ], [ -56.210775316127922, -24.855691826916257 ], [ -56.213591681610808, -24.848405449551876 ], [ -56.214315152022664, -24.840240573943333 ], [ -56.213436651979919, -24.832954196578896 ], [ -56.209380052147708, -24.817606295494159 ], [ -56.210155199402948, -24.80685759929878 ], [ -56.214496019175954, -24.794713636425172 ], [ -56.227260097875217, -24.784274997692989 ], [ -56.236329311948168, -24.78334482170618 ], [ -56.247129685886307, -24.788667494309436 ], [ -56.256663987952663, -24.797814222748173 ], [ -56.264932217248031, -24.808097832748786 ], [ -56.271675991353902, -24.820448500298028 ], [ -56.276559414385474, -24.832489108585492 ], [ -56.285680305301867, -24.846235040115005 ], [ -56.298806118307709, -24.858534030820863 ], [ -56.342110968646296, -24.881736749151628 ], [ -56.352678798587704, -24.89026335996607 ], [ -56.358750780024479, -24.900288587548289 ], [ -56.363298306271815, -24.910623875291606 ], [ -56.370739712367822, -24.922147718742224 ], [ -56.380687424684879, -24.93150115275597 ], [ -56.411176520380081, -24.946849053840765 ], [ -56.421692674377425, -24.953360283949962 ], [ -56.494504766681644, -25.021728203693669 ], [ -56.531866827691942, -25.006587009083205 ], [ -56.536621060413609, -25.002917982878614 ], [ -56.54163367375503, -24.999972426186503 ], [ -56.578608161137709, -24.961835218820283 ], [ -56.595738898031698, -24.951344903244717 ], [ -56.689273240867351, -24.916980075769857 ], [ -56.704724493840331, -24.915274753427127 ], [ -56.772188076018892, -24.922406101160618 ], [ -56.826965094763295, -24.936823826258603 ], [ -56.984810756611125, -24.963747246738023 ], [ -56.998401659409069, -24.96777800904789 ], [ -57.006178962289255, -24.971447035252481 ], [ -57.015351529149768, -24.976873060643243 ], [ -57.018607144204339, -24.980283704429439 ], [ -57.02038998091291, -24.983746025958339 ], [ -57.021578539318114, -24.989533786555 ], [ -57.021966112046414, -24.994856459158257 ], [ -57.021552699997073, -24.998370456631278 ], [ -57.019873216076064, -25.004881686740475 ], [ -57.019769863288559, -25.008757419419396 ], [ -57.020312465647748, -25.013098240091722 ], [ -57.022172817621424, -25.018059176589702 ], [ -57.027702195799691, -25.02405364276143 ], [ -57.038605923424598, -25.031081637707416 ], [ -57.058708055432419, -25.037592868715933 ], [ -57.076872321100723, -25.038936455852763 ], [ -57.095605028449313, -25.037127780722528 ], [ -57.129763150349106, -25.027929375440351 ], [ -57.195030483769813, -25.000592542911534 ], [ -57.213427294334167, -24.988965345774091 ], [ -57.199526333173708, -24.984211113951744 ], [ -57.194797939773082, -24.978113294992568 ], [ -57.198492805298713, -24.969741712909752 ], [ -57.210016648749331, -24.957959487040682 ], [ -57.218698290093982, -24.946590670523051 ], [ -57.218956671613114, -24.937392267039513 ], [ -57.215623542192702, -24.928193861757336 ], [ -57.213427294334167, -24.916980075769857 ], [ -57.216011114921002, -24.901373793166044 ], [ -57.222522345929519, -24.901942233946954 ], [ -57.231178147953131, -24.907368258438396 ], [ -57.240092333294513, -24.906438084250169 ], [ -57.248438076056345, -24.897239678967992 ], [ -57.248670620053076, -24.891451917472011 ], [ -57.197149217262563, -24.826753024832215 ], [ -57.181904669864593, -24.769495538288481 ], [ -57.178649054810023, -24.762415866499055 ], [ -57.16681515209757, -24.757661634676708 ], [ -57.158081834808797, -24.759625338538569 ], [ -57.149374355941745, -24.763035984123348 ], [ -57.137695481960918, -24.762415866499055 ], [ -57.12232174335378, -24.752028903710936 ], [ -57.116663173966288, -24.736422621107067 ], [ -57.112141486140672, -24.717509046605244 ], [ -57.090669928574357, -24.677459812220548 ], [ -57.097517056367053, -24.66154347125422 ], [ -57.113175014914987, -24.64898609812991 ], [ -57.126610887182665, -24.641441339246398 ], [ -57.133974778912886, -24.628832289278705 ], [ -57.141080288224714, -24.616326592997893 ], [ -57.144904344060251, -24.602994072618344 ], [ -57.14565365289377, -24.58289194061058 ], [ -57.141183641012219, -24.541912530239074 ], [ -57.132191942204372, -24.509873141832031 ], [ -57.130538295805707, -24.500106295768944 ], [ -57.141958788267459, -24.474939873576318 ], [ -57.1466096673023, -24.460677179008599 ], [ -57.157410041240382, -24.389518731304406 ], [ -57.165239020064689, -24.359908135651949 ], [ -57.170949266295622, -24.297999770073318 ], [ -57.174850837396207, -24.285028984899725 ], [ -57.185599535390224, -24.26642546965968 ], [ -57.193402675792868, -24.255935154084113 ], [ -57.212548794291422, -24.236711521219718 ], [ -57.216863775642707, -24.229321791067832 ], [ -57.219809333234139, -24.22079518025339 ], [ -57.221101244426904, -24.207979424710686 ], [ -57.220713669899965, -24.202036634483079 ], [ -57.219731817969034, -24.197902520285083 ], [ -57.215907762133497, -24.192631523625892 ], [ -57.197821010830978, -24.173562921291762 ], [ -57.189681972744836, -24.156768080282689 ], [ -57.172189500644947, -24.137079359424888 ], [ -57.163016933784434, -24.117442314511209 ], [ -57.178649054810023, -24.098270358490254 ], [ -57.187924973558665, -24.096203301840887 ], [ -57.223659226592019, -24.098270358490254 ], [ -57.233581102286053, -24.094704685073168 ], [ -57.237870246114937, -24.086178074258726 ], [ -57.236733363653798, -24.075842786515409 ], [ -57.230480515963052, -24.06695444049501 ], [ -57.22389177058875, -24.050728041166167 ], [ -57.231772427155761, -24.033364760275447 ], [ -57.248360561690561, -24.023649591055801 ], [ -57.268049281649041, -24.030005791534052 ], [ -57.278048671708802, -24.00509775175982 ], [ -57.279883185260758, -23.978794448005374 ], [ -57.284482388351535, -23.954041436063449 ], [ -57.302801682751465, -23.933784274424738 ], [ -57.312749395967842, -23.932182305768777 ], [ -57.326443650653971, -23.932233981712898 ], [ -57.338561774206482, -23.930476982526727 ], [ -57.34375525560057, -23.923242282905051 ], [ -57.340396287758438, -23.911305026505772 ], [ -57.332903204819047, -23.901538180442685 ], [ -57.3254101218796, -23.894096775245998 ], [ -57.322051154037524, -23.889084161005201 ], [ -57.318149583836203, -23.885931898738136 ], [ -57.295334439133057, -23.871720880114538 ], [ -57.291303676823247, -23.861850681263945 ], [ -57.288513149762025, -23.830741468843712 ], [ -57.281588507603544, -23.800975843560309 ], [ -57.281071742766699, -23.793224379101844 ], [ -57.284430710608774, -23.787695000923577 ], [ -57.291923794447541, -23.782062269957805 ], [ -57.299416877386989, -23.774982599067698 ], [ -57.302801682751465, -23.765267428948675 ], [ -57.299003465337648, -23.757670994121099 ], [ -57.281175095554204, -23.751314792743472 ], [ -57.275490688644368, -23.742013034673789 ], [ -57.275826586327867, -23.731522719098223 ], [ -57.280348273254219, -23.723409518534481 ], [ -57.295334439133057, -23.707234796049022 ], [ -57.325875209873004, -23.682791842469555 ], [ -57.397989671086464, -23.645636488832906 ], [ -57.425688238821181, -23.617886244254748 ], [ -57.450415412341385, -23.573806247560299 ], [ -57.453619350552572, -23.559853610455775 ], [ -57.454859584901897, -23.548898206886747 ], [ -57.459639655145963, -23.527710870160547 ], [ -57.459820523198573, -23.515463556298073 ], [ -57.457029995238088, -23.504663180561352 ], [ -57.448245002005251, -23.485956312533801 ], [ -57.446177945355885, -23.474484145027247 ], [ -57.420494758326413, -23.477739760081874 ], [ -57.408454149139686, -23.482390639116716 ], [ -57.40369991731734, -23.484871107815366 ], [ -57.398454759079868, -23.486989841308116 ], [ -57.372849087315501, -23.500115655213335 ], [ -57.368146532336596, -23.50171762476856 ], [ -57.357113614401783, -23.504146416623826 ], [ -57.35047319218404, -23.504766534248176 ], [ -57.28401730035813, -23.500322360788346 ], [ -57.281588507603544, -23.50078744878175 ], [ -57.274017910298312, -23.500270684844224 ], [ -57.263269212304294, -23.498151950452154 ], [ -57.24316708029653, -23.491072279562047 ], [ -57.226139696190046, -23.482493991904221 ], [ -57.218569098884814, -23.48016855193714 ], [ -57.208156296775655, -23.47897999353188 ], [ -57.161518317016714, -23.47939340558122 ], [ -57.089972296584222, -23.469109795580607 ], [ -57.045892299889715, -23.456087334462893 ], [ -57.038605923424598, -23.452159925839908 ], [ -57.034626837958172, -23.448904310785338 ], [ -57.030079311710836, -23.446165459668237 ], [ -57.024110683960885, -23.444150078962991 ], [ -57.016798469074104, -23.443374932607071 ], [ -57.006644050282659, -23.444460138224827 ], [ -56.998815069659713, -23.446113782824796 ], [ -56.991011929257127, -23.448645929266206 ], [ -56.984552375092051, -23.448955986729402 ], [ -56.977085129675004, -23.447509046805067 ], [ -56.957654792134917, -23.439344171196524 ], [ -56.943934699027125, -23.436140232086018 ], [ -56.933392706608117, -23.434744968105804 ], [ -56.908045417262201, -23.436295260817644 ], [ -56.89954464397016, -23.435675144092613 ], [ -56.893033412961643, -23.433814793018314 ], [ -56.886728889326776, -23.429473971446612 ], [ -56.877995572038003, -23.422032566249925 ], [ -56.871458502607823, -23.41981047907035 ], [ -56.862699347796649, -23.419035332714429 ], [ -56.838514776635634, -23.42172250698809 ], [ -56.788181932250382, -23.432574557769613 ], [ -56.730045945663846, -23.429629001976878 ], [ -56.715705735831023, -23.430249118701852 ], [ -56.705602992983756, -23.431747734570308 ], [ -56.68157345235295, -23.443840019701156 ], [ -56.671858283133247, -23.444770195687965 ], [ -56.658603278018859, -23.444718519743901 ], [ -56.632558355783488, -23.442031344570921 ], [ -56.620336880342734, -23.443013198300491 ], [ -56.612068651047423, -23.445183607737306 ], [ -56.605350715363215, -23.452314954571477 ], [ -56.596152310081038, -23.453245130558344 ], [ -56.5811661442022, -23.451746514689887 ], [ -56.549204271060262, -23.445028578106417 ], [ -56.534760708439933, -23.443633315025465 ], [ -56.52522640637352, -23.443633315025465 ], [ -56.518172573005813, -23.44120452227088 ], [ -56.473705002683744, -23.4204305966947 ], [ -56.433707445142488, -23.410405369112482 ], [ -56.424870775066211, -23.410767103419118 ], [ -56.41851457368864, -23.411800632193433 ], [ -56.412339240363622, -23.412265720186838 ], [ -56.404897834267615, -23.411387221043412 ], [ -56.38112667515594, -23.400225111899374 ], [ -56.367690802888262, -23.388391209186977 ], [ -56.354151576933702, -23.378831068698844 ], [ -56.346090054112722, -23.366170342787086 ], [ -56.333584356932533, -23.352114352895057 ], [ -56.301028204587965, -23.33966033255831 ], [ -56.290486213068277, -23.346688327504296 ], [ -56.286222906761736, -23.345396417210907 ], [ -56.27803219273153, -23.341675714162875 ], [ -56.266895921109892, -23.334079277536659 ], [ -56.243589849991565, -23.322555434086041 ], [ -56.224650437967341, -23.3179045550512 ], [ -56.203747321181936, -23.315062351146594 ], [ -56.192662726403682, -23.312426852816998 ], [ -56.183464322020825, -23.307982680256487 ], [ -56.178425869358364, -23.307362562632136 ], [ -56.162638718701885, -23.311806736092024 ], [ -56.149487067274322, -23.313873792741333 ], [ -56.107344936919276, -23.316044203077524 ], [ -56.092927211821348, -23.31960987649461 ], [ -56.0842972482194, -23.32420907958533 ], [ -56.076390754129989, -23.330978692112978 ], [ -56.071584846363578, -23.337851657428075 ], [ -56.069440274449107, -23.344362887537216 ], [ -56.069724494389902, -23.350098972189812 ], [ -56.072204963088552, -23.356558525455569 ], [ -56.077320930116798, -23.366583753937107 ], [ -56.078819545985255, -23.372009780227188 ], [ -56.07739844358332, -23.37686736393772 ], [ -56.072825079813583, -23.383171888471907 ], [ -56.055978562860389, -23.396814467213915 ], [ -56.052102831080788, -23.400845228624405 ], [ -56.047917040039351, -23.407046401270406 ], [ -56.044738939350566, -23.414126072160514 ], [ -56.043214484161126, -23.41965544943946 ], [ -56.042956101742675, -23.423376152487435 ], [ -56.044144660147936, -23.428647149146627 ], [ -56.046521776059137, -23.433918144906443 ], [ -56.053162197377503, -23.443013198300491 ], [ -56.061533780359696, -23.452056573052403 ], [ -56.14424190903685, -23.514843437774459 ], [ -56.147755907409191, -23.519804376071079 ], [ -56.147497524990797, -23.526625664542792 ], [ -56.145172085023717, -23.535307305887443 ], [ -56.140133633260575, -23.548484795736726 ], [ -56.132020432696777, -23.565279635846537 ], [ -56.114140387868588, -23.594580173136478 ], [ -56.101686366632521, -23.607292575891677 ], [ -56.091557787162117, -23.614010511575827 ], [ -56.086441820133871, -23.613907158788322 ], [ -56.08086076511222, -23.611168307671278 ], [ -56.065538703348466, -23.599489434589714 ], [ -56.058562385245864, -23.595148613917388 ], [ -56.047296922415057, -23.590032646889142 ], [ -56.0419484122894, -23.586622003102946 ], [ -56.038382737972995, -23.581867771280599 ], [ -56.036005622061793, -23.575511569903028 ], [ -56.034791226134189, -23.566726575770872 ], [ -56.035230474806554, -23.552205498784758 ], [ -56.034119431666454, -23.546882826181502 ], [ -56.030036994311843, -23.543833916701885 ], [ -56.021148648291501, -23.540423272016369 ], [ -55.960041265691871, -23.529209486928266 ], [ -55.946243659117556, -23.528796074878983 ], [ -55.936244269057738, -23.530191338859197 ], [ -55.933634610049182, -23.533912041907229 ], [ -55.933479580418293, -23.538717949673639 ], [ -55.935830857907774, -23.550138442135392 ], [ -55.9367093570512, -23.56300587272284 ], [ -55.933092006790673, -23.59985116979567 ], [ -55.933763801258408, -23.605742283179836 ], [ -55.935107388395238, -23.611271660458783 ], [ -55.94190283934455, -23.625792739243536 ], [ -55.947948980561023, -23.633905938008638 ], [ -55.958620165088519, -23.644654636002656 ], [ -55.980892707432474, -23.672043144475538 ], [ -55.982830572872615, -23.676280613259678 ], [ -55.98236548487921, -23.681189873813651 ], [ -55.977533738691079, -23.696641126786574 ], [ -55.974639858842409, -23.720980726679215 ], [ -55.975001594048308, -23.74666391370863 ], [ -55.975673386717403, -23.752813408611928 ], [ -55.977172004384499, -23.758291110846073 ], [ -55.981461148213384, -23.768212985640787 ], [ -55.998876105048225, -23.798236992443265 ], [ -56.004198777651482, -23.815031833452338 ], [ -56.006110805569222, -23.818442478137854 ], [ -56.008307054327076, -23.820612887574725 ], [ -56.042025925755866, -23.843505547542975 ], [ -56.051327683825548, -23.847226250591007 ], [ -56.05907914918339, -23.848518161783716 ], [ -55.997532517911338, -23.999826755100685 ], [ -55.992364874939028, -24.022719415068934 ], [ -55.994147711647543, -24.029850762802482 ], [ -56.000400560237665, -24.028455498822211 ], [ -56.002906867358035, -24.028300470090642 ], [ -56.007299363974482, -24.028455498822211 ], [ -56.011459316594198, -24.030005791534052 ], [ -56.015877651632309, -24.032486261132021 ], [ -56.030915492555948, -24.046077162131326 ], [ -56.043576219367026, -24.061890151209525 ], [ -56.066313848805066, -24.0821989887923 ], [ -56.07912960524709, -24.097908624183674 ], [ -56.08313452823586, -24.101009209607355 ], [ -56.088224656842442, -24.103179619943489 ], [ -56.112590095156747, -24.108192234184287 ], [ -56.11768022286401, -24.110465997307927 ], [ -56.122124396323841, -24.113101494738203 ], [ -56.126361864208661, -24.116202081061203 ], [ -56.145792201748691, -24.140386650423579 ], [ -56.148841112127627, -24.14539926466432 ], [ -56.153543667106533, -24.160798841693179 ], [ -56.152613491119723, -24.18301970809307 ], [ -56.158504605403209, -24.229786879061237 ], [ -56.158478766082169, -24.248855483194006 ], [ -56.156592576586149, -24.26161956099395 ], [ -56.135043503754673, -24.278672783522154 ], [ -56.129565803319167, -24.284253838543805 ], [ -56.125431688221852, -24.293503919770103 ], [ -56.122822028313976, -24.304717705757525 ], [ -56.118507046063314, -24.337325534945478 ], [ -56.114372931865319, -24.352776787918458 ], [ -56.109024420840342, -24.364869073049306 ], [ -56.10339168987457, -24.374480889481447 ], [ -56.096441210193689, -24.38249073725774 ], [ -56.088017951267432, -24.389983819297811 ], [ -56.079853074759569, -24.395203139113562 ], [ -56.070654670376712, -24.399337254210934 ], [ -56.051870287084057, -24.405228366695781 ], [ -56.044299688879505, -24.408690688224681 ], [ -56.03846025233878, -24.413651624722718 ], [ -56.033809374203258, -24.419801120525278 ], [ -56.013112962093544, -24.463726087588896 ], [ -55.960092943434574, -24.531525566551636 ], [ -55.93862138496894, -24.571626478679036 ], [ -55.924203660770331, -24.613277682618957 ], [ -55.913609992407203, -24.635033461025387 ], [ -55.902447883263221, -24.64898609812991 ], [ -55.872888962655509, -24.666039320658115 ], [ -55.856119960967419, -24.678803398458058 ], [ -55.836818813737239, -24.697716973859258 ], [ -55.827930466817577, -24.720764661659814 ], [ -55.8206957671959, -24.735182386757742 ], [ -55.814236213030824, -24.745672703232685 ], [ -55.804262661392727, -24.753630873266218 ], [ -55.750829229785097, -24.782673028137765 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-5", "NAME_1": "Caaguazú" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -56.045746628803897, -24.971498712095865 ], [ -56.03711666520195, -24.964367363463055 ], [ -56.028435024756561, -24.952791843169052 ], [ -55.984561733637065, -24.873468519856317 ], [ -55.969911465441783, -24.857087090896528 ], [ -55.949370082962957, -24.841945896286063 ], [ -55.868909878088402, -24.811508476534982 ], [ -55.750829229785097, -24.782673028137765 ], [ -55.724474250086587, -24.753320814903702 ], [ -55.696310594358408, -24.713168226832181 ], [ -55.682151251678931, -24.698543796159242 ], [ -55.632361008753549, -24.663507175116024 ], [ -55.522806973063325, -24.555710137712708 ], [ -55.509784511945668, -24.548888849240996 ], [ -55.489682379937904, -24.542791030281819 ], [ -55.227527838838682, -24.50217335421695 ], [ -55.253443569864828, -24.535866388123338 ], [ -55.283803474350862, -24.568680921986982 ], [ -55.288531866852168, -24.575502210458637 ], [ -55.291580777231104, -24.583718763809884 ], [ -55.292976040311999, -24.593433933029587 ], [ -55.291606614753448, -24.608420098908425 ], [ -55.285586310160056, -24.630692641252381 ], [ -55.284320238288387, -24.64092457351029 ], [ -55.285431281428487, -24.649451186123372 ], [ -55.2961024641574, -24.666659438282466 ], [ -55.300210740832995, -24.676219577871223 ], [ -55.298892992117885, -24.717250665086112 ], [ -55.301037564032356, -24.729187920586071 ], [ -55.307703822873123, -24.741021824197844 ], [ -55.31480933308427, -24.746809583895185 ], [ -55.322405767911846, -24.751460462930027 ], [ -55.326359015855871, -24.757661634676708 ], [ -55.328451910926958, -24.768565362301615 ], [ -55.323930223101286, -24.78737558401599 ], [ -55.31519690581257, -24.811198419071786 ], [ -55.314654304352644, -24.820086765092128 ], [ -55.316204597064484, -24.829130140743416 ], [ -55.326565721430882, -24.843702894572914 ], [ -55.333180305226904, -24.850420831156441 ], [ -55.334110480314393, -24.860962822676129 ], [ -55.333542040432803, -24.867835788890545 ], [ -55.331733364403249, -24.873985283793843 ], [ -55.329769659642068, -24.878739515616132 ], [ -55.328581102136127, -24.884062188219389 ], [ -55.328296882195332, -24.890418389597016 ], [ -55.329769659642068, -24.906024672200886 ], [ -55.329614630910498, -24.912794284728477 ], [ -55.328426073404557, -24.918530368481697 ], [ -55.326720751061828, -24.92364633551 ], [ -55.326203986224982, -24.92995086004413 ], [ -55.326591558953282, -24.938012383764487 ], [ -55.330338101322297, -24.950156344839456 ], [ -55.329717983698004, -24.959664808484149 ], [ -55.327521734940092, -24.965917657074215 ], [ -55.315041877080944, -24.981989027671489 ], [ -55.310235969314533, -24.990929049635952 ], [ -55.306463589423117, -25.000075778974008 ], [ -55.302071091907351, -25.010152682500291 ], [ -55.29935808011129, -25.014338473541727 ], [ -55.296257493788289, -25.018214207119968 ], [ -55.289126146054798, -25.025293878010075 ], [ -55.284940355013362, -25.028291110646251 ], [ -55.280237800034456, -25.031081637707416 ], [ -55.274630906591085, -25.033045342468597 ], [ -55.268481410788468, -25.034440605549491 ], [ -55.26158260795097, -25.034957371285657 ], [ -55.254993862576669, -25.034905693542953 ], [ -55.23675208164326, -25.032580254475192 ], [ -55.230964321945919, -25.033510430462002 ], [ -55.226080898914347, -25.035577488010688 ], [ -55.222205166235426, -25.038936455852763 ], [ -55.218717007184125, -25.042657158900738 ], [ -55.214841275404524, -25.045757745223739 ], [ -55.210061205160457, -25.047463066667206 ], [ -55.204557665403911, -25.047463066667206 ], [ -55.198821580751371, -25.04679127399811 ], [ -55.193292201673785, -25.046636243467844 ], [ -55.188693000381647, -25.048548272284961 ], [ -55.185359870061973, -25.052062269757926 ], [ -55.179546271043591, -25.059968763847394 ], [ -55.098956874959811, -25.1294218892088 ], [ -55.015008511033955, -25.184508965416398 ], [ -55.011081102410913, -25.187919610101915 ], [ -55.008290575349747, -25.191950371512462 ], [ -55.007722133669517, -25.197686456165002 ], [ -55.008445604081373, -25.203784275124178 ], [ -55.014595098984614, -25.223214613563584 ], [ -55.014465907775389, -25.228330579692511 ], [ -55.012373012704359, -25.232568047577331 ], [ -55.009169073593853, -25.236288750625363 ], [ -55.005396694601757, -25.239130954529912 ], [ -55.000125697942622, -25.241921481591078 ], [ -54.973434820560499, -25.251533298023276 ], [ -54.969016486421708, -25.254323825983761 ], [ -54.966096768151317, -25.258406264237692 ], [ -54.965037400955282, -25.263625584053443 ], [ -54.967311164078978, -25.281712334456699 ], [ -54.967414516866427, -25.287810153415876 ], [ -54.966277635304607, -25.293236178806637 ], [ -54.964107224968473, -25.297938734684863 ], [ -54.961368373851371, -25.302331231301309 ], [ -54.955063849317185, -25.310496107809115 ], [ -54.952531703775094, -25.314888603526242 ], [ -54.950645515178394, -25.319849541822919 ], [ -54.949611986404022, -25.325327244057064 ], [ -54.949405279929692, -25.337729587550427 ], [ -54.972117071845389, -25.343982436140493 ], [ -54.998627082074165, -25.343310641672758 ], [ -55.024155238573371, -25.339899997886619 ], [ -55.037591111740426, -25.318402601898583 ], [ -55.039399786870661, -25.304760024055895 ], [ -55.043223842706198, -25.293442885280911 ], [ -55.051052822429824, -25.284709567992195 ], [ -55.065057136377732, -25.279283542601434 ], [ -55.082162034850001, -25.276337985909322 ], [ -55.090120204883533, -25.273805841266551 ], [ -55.098026698972944, -25.268896579813315 ], [ -55.104202033197282, -25.262385348804798 ], [ -55.113813848730103, -25.248277682968705 ], [ -55.120144211686011, -25.242128188065408 ], [ -55.1195499333827, -25.252618503641031 ], [ -55.114098069570275, -25.272410577286337 ], [ -55.113193732005129, -25.282074069662599 ], [ -55.124304165205047, -25.282797540074398 ], [ -55.137068243904309, -25.280007013013233 ], [ -55.160916918281146, -25.271945489292875 ], [ -55.171278041748224, -25.266726169477124 ], [ -55.196806200046069, -25.243471775202238 ], [ -55.215332200920329, -25.2315861956464 ], [ -55.226830206848547, -25.231276137283885 ], [ -55.25641496407934, -25.261300144086363 ], [ -55.489243130366162, -25.555597425480812 ], [ -55.505676236169336, -25.579006850285907 ], [ -55.507769131240423, -25.591357516935886 ], [ -55.507484911299628, -25.596008395970728 ], [ -55.509629483214098, -25.603294772435788 ], [ -55.514435390980509, -25.6100643858627 ], [ -55.52386634025936, -25.619986260657413 ], [ -55.529344041594243, -25.627169285234345 ], [ -55.538826666817215, -25.634403984856021 ], [ -55.550117967170422, -25.640398451027693 ], [ -55.59923641562807, -25.657606703186786 ], [ -55.624635382716747, -25.650320325822406 ], [ -55.636236742331789, -25.637349541548133 ], [ -55.641533575614005, -25.635489189574457 ], [ -55.650447760955387, -25.634972425636931 ], [ -55.710650804191232, -25.657761732817733 ], [ -55.771215582633033, -25.674659925714991 ], [ -55.80273820710255, -25.678483981550528 ], [ -55.828188849235971, -25.676830336051182 ], [ -55.841547207137864, -25.67000904668015 ], [ -55.854285448314783, -25.659777113522978 ], [ -55.875136888256804, -25.636832777610607 ], [ -55.886454027031732, -25.626342462034984 ], [ -55.899967413665195, -25.617505791958706 ], [ -55.920405443356515, -25.609961033075194 ], [ -55.938776414599829, -25.607118829170645 ], [ -56.046134203330837, -25.609806003444305 ], [ -56.061533780359696, -25.607118829170645 ], [ -56.073755255800393, -25.601641126936443 ], [ -56.082049322618161, -25.594044692108866 ], [ -56.093185594239799, -25.588463637087159 ], [ -56.174007534320253, -25.58562143318261 ], [ -56.203359747554316, -25.580815524516822 ], [ -56.218035855070639, -25.580247083735912 ], [ -56.246225349220481, -25.582520846859609 ], [ -56.359060838386995, -25.577766615936582 ], [ -56.378827073610523, -25.579471938279312 ], [ -56.395957811403889, -25.584277846045779 ], [ -56.42618852378132, -25.601744479723948 ], [ -56.437634853765474, -25.606240330027219 ], [ -56.450631475562147, -25.609650973813416 ], [ -56.481999071300095, -25.614611912110036 ], [ -56.49907813225002, -25.620296319019928 ], [ -56.512488166095977, -25.628099461221154 ], [ -56.559952969054279, -25.668768813230145 ], [ -56.569952359114097, -25.674453220139981 ], [ -56.62509111216508, -25.698482760770787 ], [ -56.646795212828806, -25.710368341225944 ], [ -56.678989630866738, -25.706492607647704 ], [ -56.68482906830684, -25.703908787060868 ], [ -56.693278163856178, -25.699257908026027 ], [ -56.714930588575783, -25.674298190509091 ], [ -56.746324021836131, -25.653472588988791 ], [ -56.749915533674937, -25.645721123630949 ], [ -56.750716519351897, -25.643395684563188 ], [ -56.808619961042382, -25.535030205479586 ], [ -56.813839280858133, -25.522317803623764 ], [ -56.814743618423222, -25.512964368710641 ], [ -56.809265917088396, -25.506143080238985 ], [ -56.56380286331148, -25.349253431900365 ], [ -56.5437782456695, -25.286983331115835 ], [ -56.494504766681644, -25.021728203693669 ], [ -56.421692674377425, -24.953360283949962 ], [ -56.411176520380081, -24.946849053840765 ], [ -56.380687424684879, -24.93150115275597 ], [ -56.370739712367822, -24.922147718742224 ], [ -56.363298306271815, -24.910623875291606 ], [ -56.358750780024479, -24.900288587548289 ], [ -56.352678798587704, -24.89026335996607 ], [ -56.342110968646296, -24.881736749151628 ], [ -56.298806118307709, -24.858534030820863 ], [ -56.285680305301867, -24.846235040115005 ], [ -56.276559414385474, -24.832489108585492 ], [ -56.271675991353902, -24.820448500298028 ], [ -56.264932217248031, -24.808097832748786 ], [ -56.256663987952663, -24.797814222748173 ], [ -56.247129685886307, -24.788667494309436 ], [ -56.236329311948168, -24.78334482170618 ], [ -56.227260097875217, -24.784274997692989 ], [ -56.214496019175954, -24.794713636425172 ], [ -56.210155199402948, -24.80685759929878 ], [ -56.209380052147708, -24.817606295494159 ], [ -56.213436651979919, -24.832954196578896 ], [ -56.214315152022664, -24.840240573943333 ], [ -56.213591681610808, -24.848405449551876 ], [ -56.210775316127922, -24.855691826916257 ], [ -56.20377315870428, -24.862564793130673 ], [ -56.193773770443158, -24.868920993608981 ], [ -56.147885097719097, -24.884785657731925 ], [ -56.14155473476319, -24.888092949629936 ], [ -56.134965990288208, -24.893002211083171 ], [ -56.1008853827542, -24.928193861757336 ], [ -56.054428270148549, -24.967881361835396 ], [ -56.045746628803897, -24.971498712095865 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-3", "NAME_1": "Cordillera" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -56.494504766681644, -25.021728203693669 ], [ -56.5437782456695, -25.286983331115835 ], [ -56.56380286331148, -25.349253431900365 ], [ -56.809265917088396, -25.506143080238985 ], [ -56.814743618423222, -25.512964368710641 ], [ -56.813839280858133, -25.522317803623764 ], [ -56.808619961042382, -25.535030205479586 ], [ -56.750716519351897, -25.643395684563188 ], [ -56.749915533674937, -25.645721123630949 ], [ -56.746324021836131, -25.653472588988791 ], [ -56.788078578563557, -25.638589775897458 ], [ -56.795494147137163, -25.637452895234901 ], [ -56.806010301134506, -25.637039483185617 ], [ -56.817069058390302, -25.642000420582974 ], [ -56.826525845191611, -25.647736505235514 ], [ -56.833631353604062, -25.653110853782891 ], [ -56.839961716559969, -25.656883232774987 ], [ -56.84709306519278, -25.660242200617063 ], [ -56.854508632867123, -25.662102552590738 ], [ -56.861459113447324, -25.662670994270968 ], [ -56.892103237874096, -25.660655612666403 ], [ -56.90031979032608, -25.658278496755202 ], [ -56.907451138059571, -25.654351088132216 ], [ -56.910319180385841, -25.647736505235514 ], [ -56.909595709974042, -25.643860771657273 ], [ -56.9060558740793, -25.640088392665177 ], [ -56.893498500955047, -25.630063165083016 ], [ -56.881354539880078, -25.617815851220541 ], [ -56.878460659132088, -25.612751560136417 ], [ -56.877323777570268, -25.608100681101575 ], [ -56.877504644723558, -25.603708184485129 ], [ -56.878874071181428, -25.599780775862143 ], [ -56.884997727663006, -25.587843519462865 ], [ -56.88776241720177, -25.580350436523418 ], [ -56.893059252282683, -25.554977308755781 ], [ -56.896702440065553, -25.54650237388546 ], [ -56.9025935525504, -25.539422702995353 ], [ -56.915486823358208, -25.536735527822373 ], [ -56.925796270881165, -25.536425469459857 ], [ -57.000210333639984, -25.540507907713788 ], [ -57.0085819157228, -25.539836114145373 ], [ -57.026358608662861, -25.536425469459857 ], [ -57.049483811728521, -25.529294121726366 ], [ -57.0614210681278, -25.527278741021064 ], [ -57.088163622353306, -25.52609018261586 ], [ -57.103511521639405, -25.516323337452036 ], [ -57.112606574134077, -25.508468520206065 ], [ -57.161750861013445, -25.425321140158474 ], [ -57.182111376338923, -25.395038750937601 ], [ -57.193402675792868, -25.38366993621861 ], [ -57.199681362804654, -25.383049818594259 ], [ -57.204099696943445, -25.384186700156079 ], [ -57.209344855180916, -25.387442315210706 ], [ -57.216295335761117, -25.393333428594872 ], [ -57.220093553174934, -25.395813897293522 ], [ -57.226217210555831, -25.397312514061298 ], [ -57.233090175870927, -25.397364190005362 ], [ -57.240144009238634, -25.394832044463271 ], [ -57.246629400926111, -25.39018116542843 ], [ -57.256628790985928, -25.377830498778508 ], [ -57.291303676823247, -25.320262952972882 ], [ -57.297479011047528, -25.301039321007863 ], [ -57.300243699686973, -25.286053155129025 ], [ -57.305669725077735, -25.273237399586321 ], [ -57.318227098201987, -25.255925794639722 ], [ -57.348509488322236, -25.225850111893124 ], [ -57.379153611849688, -25.178101088094763 ], [ -57.388791265804286, -25.169367770805991 ], [ -57.429021369140855, -25.145906670956094 ], [ -57.432251145773762, -25.143064467051488 ], [ -57.454988776111122, -25.112472018568781 ], [ -57.422277595034984, -25.112472018568781 ], [ -57.414862027360641, -25.10823455158328 ], [ -57.396206835277212, -25.089424329868905 ], [ -57.387835252295076, -25.085186862883404 ], [ -57.377965054343804, -25.083326510909728 ], [ -57.366131150732031, -25.078520603143318 ], [ -57.354116379966968, -25.07200937303412 ], [ -57.34375525560057, -25.064671318826299 ], [ -57.295334439133057, -25.006018569201615 ], [ -57.285386725017361, -24.982454115664893 ], [ -57.261873949223343, -24.980025322910308 ], [ -57.234666307004431, -24.986433201131319 ], [ -57.213427294334167, -24.988965345774091 ], [ -57.195030483769813, -25.000592542911534 ], [ -57.129763150349106, -25.027929375440351 ], [ -57.095605028449313, -25.037127780722528 ], [ -57.076872321100723, -25.038936455852763 ], [ -57.058708055432419, -25.037592868715933 ], [ -57.038605923424598, -25.031081637707416 ], [ -57.027702195799691, -25.02405364276143 ], [ -57.022172817621424, -25.018059176589702 ], [ -57.020312465647748, -25.013098240091722 ], [ -57.019769863288559, -25.008757419419396 ], [ -57.019873216076064, -25.004881686740475 ], [ -57.021552699997073, -24.998370456631278 ], [ -57.021966112046414, -24.994856459158257 ], [ -57.021578539318114, -24.989533786555 ], [ -57.02038998091291, -24.983746025958339 ], [ -57.018607144204339, -24.980283704429439 ], [ -57.015351529149768, -24.976873060643243 ], [ -57.006178962289255, -24.971447035252481 ], [ -56.998401659409069, -24.96777800904789 ], [ -56.984810756611125, -24.963747246738023 ], [ -56.826965094763295, -24.936823826258603 ], [ -56.772188076018892, -24.922406101160618 ], [ -56.704724493840331, -24.915274753427127 ], [ -56.689273240867351, -24.916980075769857 ], [ -56.595738898031698, -24.951344903244717 ], [ -56.578608161137709, -24.961835218820283 ], [ -56.54163367375503, -24.999972426186503 ], [ -56.536621060413609, -25.002917982878614 ], [ -56.531866827691942, -25.006587009083205 ], [ -56.494504766681644, -25.021728203693669 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-6", "NAME_1": "Caazapá" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -55.59923641562807, -25.657606703186786 ], [ -55.550117967170422, -25.640398451027693 ], [ -55.538826666817215, -25.634403984856021 ], [ -55.529344041594243, -25.627169285234345 ], [ -55.52386634025936, -25.619986260657413 ], [ -55.514435390980509, -25.6100643858627 ], [ -55.509629483214098, -25.603294772435788 ], [ -55.507484911299628, -25.596008395970728 ], [ -55.507769131240423, -25.591357516935886 ], [ -55.505676236169336, -25.579006850285907 ], [ -55.489243130366162, -25.555597425480812 ], [ -55.453405523645984, -25.546347345153833 ], [ -55.444103765576301, -25.54707081466637 ], [ -55.430331997423707, -25.550481458452566 ], [ -55.425371060026407, -25.555339043961737 ], [ -55.422968105693542, -25.561333510133409 ], [ -55.422761400118532, -25.568826593072799 ], [ -55.421030239354081, -25.577249851099737 ], [ -55.416999477943534, -25.58660328511354 ], [ -55.403977016825877, -25.602209567717352 ], [ -55.399532844265366, -25.608875827457496 ], [ -55.39821509465088, -25.616265557609381 ], [ -55.400049608202835, -25.622983494192908 ], [ -55.405966559109402, -25.630941664226441 ], [ -55.431339687776358, -25.651870618534247 ], [ -55.43891028508159, -25.662205906277563 ], [ -55.444853075309197, -25.675745130433427 ], [ -55.446300015233533, -25.698327732039218 ], [ -55.449684820598009, -25.712125338613475 ], [ -55.465394456888646, -25.756308688994807 ], [ -55.469761115083372, -25.765662123008553 ], [ -55.475988125251774, -25.77274179479798 ], [ -55.496865403615459, -25.788813164495934 ], [ -55.499888474673355, -25.79258554528667 ], [ -55.51962887237454, -25.832324721308851 ], [ -55.526191779327121, -25.850256442980481 ], [ -55.526295132114626, -25.860746758556047 ], [ -55.521101650720595, -25.868859959119845 ], [ -55.516218227689023, -25.87506112996715 ], [ -55.513169318209464, -25.884879652873678 ], [ -55.516528286051539, -25.895938409230212 ], [ -55.516166550845639, -25.905705255293299 ], [ -55.509577806370658, -25.925910740088568 ], [ -55.509655320736442, -25.935264174102372 ], [ -55.513117642265399, -25.962756036262078 ], [ -55.509629483214098, -25.97355641020016 ], [ -55.503867560139781, -25.981359551502123 ], [ -55.499165005160876, -25.984563490612629 ], [ -55.45779802116175, -25.999704685223037 ], [ -55.444387987315736, -26.006267592175618 ], [ -55.436455654804604, -26.00905811923684 ], [ -55.429014247809278, -26.010298353586165 ], [ -55.41575924269489, -26.004407241101319 ], [ -55.407361823089673, -26.003167005852617 ], [ -55.383203091249641, -26.004045504996043 ], [ -55.354677700315619, -26.002391859496697 ], [ -55.337004361062384, -25.999291274073016 ], [ -55.305275031017857, -25.990661309571806 ], [ -55.29933224079025, -25.991591484659295 ], [ -55.293337774618578, -25.995673922913227 ], [ -55.289126146054798, -25.999911390798047 ], [ -55.285715502268602, -26.004045504996043 ], [ -55.280392828766026, -26.009368177599299 ], [ -55.274036628287774, -26.013864027902571 ], [ -55.266104294877323, -26.016499526232167 ], [ -55.246880662912247, -26.017894789313061 ], [ -55.239387579972856, -26.019703463544033 ], [ -55.232979701751844, -26.023114109128812 ], [ -55.226675178116977, -26.030503839280755 ], [ -55.226390957276863, -26.038875420464308 ], [ -55.230938482624879, -26.048228854478054 ], [ -55.23920671192019, -26.05546355589837 ], [ -55.291451585122559, -26.083317153264034 ], [ -55.304370694352031, -26.080940036453512 ], [ -55.308220587709968, -26.078976331692331 ], [ -55.312096320388889, -26.077581068611437 ], [ -55.31558447944019, -26.078666274229192 ], [ -55.317754889776324, -26.081766859652873 ], [ -55.31938269685395, -26.089673353742285 ], [ -55.319331020909885, -26.096287936638987 ], [ -55.320312872840816, -26.102334079654042 ], [ -55.322560798442112, -26.109155369025075 ], [ -55.324162767098017, -26.117320244633561 ], [ -55.323180915167086, -26.165172621219483 ], [ -55.325971442228251, -26.173699232933245 ], [ -55.331991746821643, -26.182639254897708 ], [ -55.340130784907785, -26.19116586661147 ], [ -55.381601121694416, -26.227649427579024 ], [ -55.465704515251161, -26.287439059664848 ], [ -55.483791265654361, -26.296585789002961 ], [ -55.551668259882263, -26.319736829591022 ], [ -55.572468023880162, -26.323199151119923 ], [ -55.586136441043891, -26.324129327106789 ], [ -55.6001924300366, -26.321132093571237 ], [ -55.617865770189155, -26.320873712052162 ], [ -55.63876888697456, -26.322992445544912 ], [ -55.681066046960495, -26.334154554688951 ], [ -55.739873827115446, -26.356892185026311 ], [ -55.750415818635133, -26.36846770621969 ], [ -55.758916591927175, -26.388466484540629 ], [ -55.765737881298151, -26.396217949898471 ], [ -55.784548102113206, -26.410428968522069 ], [ -55.831108568405682, -26.4549740541093 ], [ -55.847050746894467, -26.464637545586243 ], [ -55.864620734259461, -26.471975599794121 ], [ -55.933918829989977, -26.483447768199937 ], [ -55.984070808121317, -26.498020522029492 ], [ -55.99895362031333, -26.508200779242543 ], [ -56.021071133026339, -26.538379814776647 ], [ -56.025954556057911, -26.548146660839734 ], [ -56.035230474806554, -26.572589613519824 ], [ -56.044868129660472, -26.585922133000054 ], [ -56.056495326797858, -26.59796274218678 ], [ -56.070913051895843, -26.608814792968303 ], [ -56.07933630992278, -26.617444756570251 ], [ -56.085589159412166, -26.626746514639933 ], [ -56.094865078160808, -26.657752374272661 ], [ -56.102383998622656, -26.665142103525284 ], [ -56.118352017331745, -26.671291598428525 ], [ -56.148970303336796, -26.675529067212665 ], [ -56.209922655406217, -26.69335743609679 ], [ -56.295679693562988, -26.734956964092646 ], [ -56.411667446795207, -26.775626316101636 ], [ -56.428720669323411, -26.775988051307536 ], [ -56.444352790349001, -26.77257740662202 ], [ -56.459235601641694, -26.763895766176688 ], [ -56.490422329327032, -26.740641371002482 ], [ -56.496907721913828, -26.737282403160407 ], [ -56.572251959760138, -26.722399590968337 ], [ -56.574215663621999, -26.713872979254575 ], [ -56.573957282102867, -26.711547540186814 ], [ -56.572717047753542, -26.706586601890194 ], [ -56.568143683084486, -26.695941256683625 ], [ -56.565973272748352, -26.687311293081734 ], [ -56.567936978408795, -26.678629652636346 ], [ -56.576592780432463, -26.670361422441715 ], [ -56.593620165438267, -26.665762221149578 ], [ -56.625142788109201, -26.665297133156173 ], [ -56.639663865994635, -26.662558282039072 ], [ -56.654495002242527, -26.656460463079895 ], [ -56.696895515016024, -26.630777276050424 ], [ -56.713380295863942, -26.61703134452091 ], [ -56.731802944850017, -26.59010792404149 ], [ -56.73978695330527, -26.575896904518515 ], [ -56.748597784959827, -26.563649590656098 ], [ -56.754488898343993, -26.557138359647581 ], [ -56.783427700428035, -26.540756930687792 ], [ -56.773428311267537, -26.518277682768826 ], [ -56.759449835741293, -26.507580661618249 ], [ -56.74746090429727, -26.500500990728142 ], [ -56.728237271432931, -26.485514824849304 ], [ -56.719607306931664, -26.473732598980234 ], [ -56.715188971893554, -26.461175225855982 ], [ -56.714103766275798, -26.449909763025119 ], [ -56.710202196074476, -26.438334241831797 ], [ -56.704052700271916, -26.430272719010759 ], [ -56.690771856735807, -26.417973728304901 ], [ -56.68617265544367, -26.407380059941829 ], [ -56.685164964191756, -26.397716566666247 ], [ -56.687542080102901, -26.388776543802464 ], [ -56.688162196827932, -26.379216404213707 ], [ -56.686301845753576, -26.373015231567706 ], [ -56.682581142705544, -26.367847588595339 ], [ -56.66193640833859, -26.354463393171045 ], [ -56.657130499672803, -26.346815280600708 ], [ -56.654598355030032, -26.337823581792861 ], [ -56.651084356657748, -26.301856784762833 ], [ -56.640826585978175, -26.264339695020908 ], [ -56.633385178982792, -26.25260914509596 ], [ -56.598865321877099, -26.216849053640942 ], [ -56.594033575688968, -26.207909030777159 ], [ -56.586514655227177, -26.175869643269436 ], [ -56.554320238088508, -26.176024672001006 ], [ -56.529076300630777, -26.178815199062171 ], [ -56.514916957951243, -26.17380258572075 ], [ -56.506597052711811, -26.165482679581999 ], [ -56.499775764240098, -26.121351006943428 ], [ -56.493316210075022, -26.104349461258607 ], [ -56.482567512081005, -26.087813001768609 ], [ -56.471999681240277, -26.080061537310087 ], [ -56.457762824194958, -26.076030775899596 ], [ -56.408876918834721, -26.074067071138415 ], [ -56.392469652352588, -26.068744398535159 ], [ -56.384330614266446, -26.061044610020758 ], [ -56.38037736722174, -26.049934176820784 ], [ -56.378749559244739, -26.037996920421563 ], [ -56.375183884928333, -26.026473076970944 ], [ -56.367148199629696, -26.013967379790756 ], [ -56.358905808756049, -26.010246676742725 ], [ -56.352368740225188, -26.01040170727299 ], [ -56.345857510115991, -26.013967379790756 ], [ -56.338829515170005, -26.015672703032806 ], [ -56.329476081156201, -26.015207615039401 ], [ -56.280280117433449, -25.995570571025041 ], [ -56.265733202025672, -25.9920565726527 ], [ -56.253821784048114, -25.991901543921131 ], [ -56.245579393174467, -25.995673922913227 ], [ -56.240928514139625, -25.998464450873712 ], [ -56.213488328823303, -26.018773288456487 ], [ -56.173800828745243, -26.042182713261582 ], [ -56.155248989449319, -26.043991387492554 ], [ -56.098895839571355, -26.018514906937412 ], [ -56.074116991006349, -26.003425388271069 ], [ -56.072437507085283, -26.001151625147372 ], [ -56.071429815833312, -25.999446302804643 ], [ -56.068355068831352, -25.991126396665891 ], [ -56.047374436780842, -25.91381845495772 ], [ -56.042413500282805, -25.904413344100533 ], [ -56.033499314941423, -25.894026381312472 ], [ -56.020941941817171, -25.888807060597344 ], [ -55.988179083897592, -25.880435478514528 ], [ -55.975415005198329, -25.873304131680356 ], [ -55.956630621905674, -25.858317965801461 ], [ -55.9447708807715, -25.853563734878492 ], [ -55.908881599006577, -25.846742445507459 ], [ -55.897719488963219, -25.842039889629177 ], [ -55.873069830708118, -25.824779961526019 ], [ -55.859685635283824, -25.817493585060902 ], [ -55.770156216336318, -25.784162285461093 ], [ -55.756978725587715, -25.777392672933502 ], [ -55.751888596981132, -25.771811618811171 ], [ -55.74144995824895, -25.752174573897491 ], [ -55.734111904940448, -25.743286227877093 ], [ -55.71933244463662, -25.731555677952201 ], [ -55.709178025845233, -25.729075209253494 ], [ -55.699772914988046, -25.729695325978525 ], [ -55.690858731445303, -25.732382501151505 ], [ -55.681582810898021, -25.733105970664042 ], [ -55.669438848923733, -25.730057061184425 ], [ -55.66034379732838, -25.721530449470663 ], [ -55.654090948738315, -25.711505221888501 ], [ -55.641068487620601, -25.679465833481459 ], [ -55.633420375949584, -25.665513198175574 ], [ -55.630526496100913, -25.661275730290697 ], [ -55.624635382716747, -25.650320325822406 ], [ -55.59923641562807, -25.657606703186786 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-9", "NAME_1": "Paraguarí" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -56.746324021836131, -25.653472588988791 ], [ -56.714930588575783, -25.674298190509091 ], [ -56.693278163856178, -25.699257908026027 ], [ -56.68482906830684, -25.703908787060868 ], [ -56.678989630866738, -25.706492607647704 ], [ -56.646795212828806, -25.710368341225944 ], [ -56.663538376994495, -25.724579359849599 ], [ -56.670618048783922, -25.742562757465294 ], [ -56.672478399858278, -25.759099216055972 ], [ -56.671289842352337, -25.776565850633517 ], [ -56.665424567389891, -25.807106622272784 ], [ -56.655218471755063, -25.838319186581202 ], [ -56.648345506439966, -25.853512058035051 ], [ -56.64090410034396, -25.864984225541605 ], [ -56.617132941232228, -25.892837822907211 ], [ -56.608606330417786, -25.907823988786049 ], [ -56.599046189929709, -25.93557423246483 ], [ -56.599020352407308, -25.950508721500285 ], [ -56.603852097696119, -25.960792331500897 ], [ -56.613748134968432, -25.965546562423924 ], [ -56.656510382947829, -25.975106702912001 ], [ -56.663099128322131, -25.978517347597517 ], [ -56.668835212075351, -25.98533863696855 ], [ -56.669997932058891, -25.991539808715174 ], [ -56.669507004744446, -25.996965834105936 ], [ -56.668757696810246, -25.999136243542807 ], [ -56.663331672318805, -26.037221774964962 ], [ -56.659145881277368, -26.051691176006955 ], [ -56.653203091049818, -26.064713637124669 ], [ -56.586514655227177, -26.175869643269436 ], [ -56.594033575688968, -26.207909030777159 ], [ -56.598865321877099, -26.216849053640942 ], [ -56.633385178982792, -26.25260914509596 ], [ -56.640826585978175, -26.264339695020908 ], [ -56.651084356657748, -26.301856784762833 ], [ -56.654598355030032, -26.337823581792861 ], [ -56.657130499672803, -26.346815280600708 ], [ -56.66193640833859, -26.354463393171045 ], [ -56.682581142705544, -26.367847588595339 ], [ -56.686301845753576, -26.373015231567706 ], [ -56.688162196827932, -26.379216404213707 ], [ -56.687542080102901, -26.388776543802464 ], [ -56.685164964191756, -26.397716566666247 ], [ -56.68617265544367, -26.407380059941829 ], [ -56.690771856735807, -26.417973728304901 ], [ -56.704052700271916, -26.430272719010759 ], [ -56.710202196074476, -26.438334241831797 ], [ -56.714103766275798, -26.449909763025119 ], [ -56.715188971893554, -26.461175225855982 ], [ -56.719607306931664, -26.473732598980234 ], [ -56.728237271432931, -26.485514824849304 ], [ -56.74746090429727, -26.500500990728142 ], [ -56.759449835741293, -26.507580661618249 ], [ -56.773428311267537, -26.518277682768826 ], [ -56.783427700428035, -26.540756930687792 ], [ -56.819342820614679, -26.489803968678189 ], [ -56.828127813847516, -26.485979912842708 ], [ -56.840685186971768, -26.482259209794677 ], [ -56.852415737796036, -26.485308119274293 ], [ -56.871148444245307, -26.483189385781543 ], [ -56.889829474750456, -26.472750746150041 ], [ -56.922979906297655, -26.447997735107379 ], [ -56.944193081445519, -26.4349235980456 ], [ -57.0036209783255, -26.406863295104984 ], [ -57.010907354790561, -26.404537856037223 ], [ -57.019692348922774, -26.403039239269503 ], [ -57.029071621358241, -26.402832532795173 ], [ -57.039303555414733, -26.403969415256313 ], [ -57.049819709412077, -26.406449883954963 ], [ -57.057416144239653, -26.409343763803633 ], [ -57.063488124777109, -26.412289320495745 ], [ -57.079146084224419, -26.423399753695662 ], [ -57.090747442940142, -26.434406834108131 ], [ -57.100100876953888, -26.447377617483085 ], [ -57.10573360881898, -26.459469902613932 ], [ -57.108524135880145, -26.468771660683615 ], [ -57.112322354193282, -26.476006362103931 ], [ -57.117257453168918, -26.481484062539437 ], [ -57.128006151162936, -26.486134941574278 ], [ -57.133302985344471, -26.492491143851225 ], [ -57.136610277242482, -26.497400405304461 ], [ -57.138186408376043, -26.502051282540663 ], [ -57.142036301733924, -26.506185397637978 ], [ -57.149141811945071, -26.51145639429717 ], [ -57.163869595405515, -26.51662403726948 ], [ -57.172396206219958, -26.522618503441208 ], [ -57.178028937185672, -26.531765231879945 ], [ -57.179501716431048, -26.545046074516733 ], [ -57.179579229897513, -26.560342298758087 ], [ -57.181077846665289, -26.571866144007345 ], [ -57.187769944827096, -26.581632989171112 ], [ -57.200844081888874, -26.589436129573699 ], [ -57.252365484679387, -26.605714206645303 ], [ -57.340551317389384, -26.623232517166912 ], [ -57.367113002662961, -26.621010430886656 ], [ -57.38884294264767, -26.612173760810435 ], [ -57.404991827610729, -26.601890150809822 ], [ -57.431656866571132, -26.595482272588811 ], [ -57.445790370828945, -26.588816012848724 ], [ -57.455944789620332, -26.579720961253372 ], [ -57.462740240569644, -26.571349379170499 ], [ -57.476098599370857, -26.564993177792928 ], [ -57.54878150136517, -26.550627129538384 ], [ -57.562191535211184, -26.544167576272628 ], [ -57.569736294094696, -26.536106051652951 ], [ -57.575937465841378, -26.527372735263498 ], [ -57.582758755212353, -26.520758151467533 ], [ -57.60813188297999, -26.507477308830744 ], [ -57.614694789932628, -26.500500990728142 ], [ -57.618208788304912, -26.49352467172622 ], [ -57.62531429671742, -26.475747978786217 ], [ -57.630559454954891, -26.466291191984908 ], [ -57.636528082704842, -26.459366549826427 ], [ -57.64802608863306, -26.453578790129086 ], [ -57.654847378004092, -26.449237969456703 ], [ -57.671487189382276, -26.42820566146213 ], [ -57.70549028165118, -26.412496026070755 ], [ -57.685904913580885, -26.392187187588661 ], [ -57.664510871279674, -26.377304376295911 ], [ -57.652780321354726, -26.361698092792778 ], [ -57.614152187573382, -26.294105320304311 ], [ -57.481240403921504, -26.174319349658276 ], [ -57.476977097614963, -26.167188001924728 ], [ -57.475736864164958, -26.156852715980051 ], [ -57.503590460631244, -26.011073499942086 ], [ -57.456694099353172, -25.970610853508106 ], [ -57.433775600963202, -25.943997490491768 ], [ -57.407007209215351, -25.897798761203887 ], [ -57.40310563811471, -25.876094658741522 ], [ -57.40504350355485, -25.858421318588967 ], [ -57.42832373715072, -25.789950046057754 ], [ -57.429796516396095, -25.767625827769734 ], [ -57.425998298082959, -25.738118584904782 ], [ -57.413518439324491, -25.703598727799033 ], [ -57.402640550121305, -25.683496595791269 ], [ -57.390703293722027, -25.66830372523674 ], [ -57.355072394375497, -25.636884453554671 ], [ -57.32256791887437, -25.602622978867373 ], [ -57.238335334108399, -25.479684746853593 ], [ -57.231643235946592, -25.47208831112664 ], [ -57.202626918597389, -25.448368828858349 ], [ -57.161750861013445, -25.425321140158474 ], [ -57.112606574134077, -25.508468520206065 ], [ -57.103511521639405, -25.516323337452036 ], [ -57.088163622353306, -25.52609018261586 ], [ -57.0614210681278, -25.527278741021064 ], [ -57.049483811728521, -25.529294121726366 ], [ -57.026358608662861, -25.536425469459857 ], [ -57.0085819157228, -25.539836114145373 ], [ -57.000210333639984, -25.540507907713788 ], [ -56.925796270881165, -25.536425469459857 ], [ -56.915486823358208, -25.536735527822373 ], [ -56.9025935525504, -25.539422702995353 ], [ -56.896702440065553, -25.54650237388546 ], [ -56.893059252282683, -25.554977308755781 ], [ -56.88776241720177, -25.580350436523418 ], [ -56.884997727663006, -25.587843519462865 ], [ -56.878874071181428, -25.599780775862143 ], [ -56.877504644723558, -25.603708184485129 ], [ -56.877323777570268, -25.608100681101575 ], [ -56.878460659132088, -25.612751560136417 ], [ -56.881354539880078, -25.617815851220541 ], [ -56.893498500955047, -25.630063165083016 ], [ -56.9060558740793, -25.640088392665177 ], [ -56.909595709974042, -25.643860771657273 ], [ -56.910319180385841, -25.647736505235514 ], [ -56.907451138059571, -25.654351088132216 ], [ -56.90031979032608, -25.658278496755202 ], [ -56.892103237874096, -25.660655612666403 ], [ -56.861459113447324, -25.662670994270968 ], [ -56.854508632867123, -25.662102552590738 ], [ -56.84709306519278, -25.660242200617063 ], [ -56.839961716559969, -25.656883232774987 ], [ -56.833631353604062, -25.653110853782891 ], [ -56.826525845191611, -25.647736505235514 ], [ -56.817069058390302, -25.642000420582974 ], [ -56.806010301134506, -25.637039483185617 ], [ -56.795494147137163, -25.637452895234901 ], [ -56.788078578563557, -25.638589775897458 ], [ -56.746324021836131, -25.653472588988791 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "PY-4", "NAME_1": "Guairá" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -56.359060838386995, -25.577766615936582 ], [ -56.246225349220481, -25.582520846859609 ], [ -56.218035855070639, -25.580247083735912 ], [ -56.203359747554316, -25.580815524516822 ], [ -56.174007534320253, -25.58562143318261 ], [ -56.093185594239799, -25.588463637087159 ], [ -56.082049322618161, -25.594044692108866 ], [ -56.073755255800393, -25.601641126936443 ], [ -56.061533780359696, -25.607118829170645 ], [ -56.046134203330837, -25.609806003444305 ], [ -55.938776414599829, -25.607118829170645 ], [ -55.920405443356515, -25.609961033075194 ], [ -55.899967413665195, -25.617505791958706 ], [ -55.886454027031732, -25.626342462034984 ], [ -55.875136888256804, -25.636832777610607 ], [ -55.854285448314783, -25.659777113522978 ], [ -55.841547207137864, -25.67000904668015 ], [ -55.828188849235971, -25.676830336051182 ], [ -55.80273820710255, -25.678483981550528 ], [ -55.771215582633033, -25.674659925714991 ], [ -55.710650804191232, -25.657761732817733 ], [ -55.650447760955387, -25.634972425636931 ], [ -55.641533575614005, -25.635489189574457 ], [ -55.636236742331789, -25.637349541548133 ], [ -55.624635382716747, -25.650320325822406 ], [ -55.630526496100913, -25.661275730290697 ], [ -55.633420375949584, -25.665513198175574 ], [ -55.641068487620601, -25.679465833481459 ], [ -55.654090948738315, -25.711505221888501 ], [ -55.66034379732838, -25.721530449470663 ], [ -55.669438848923733, -25.730057061184425 ], [ -55.681582810898021, -25.733105970664042 ], [ -55.690858731445303, -25.732382501151505 ], [ -55.699772914988046, -25.729695325978525 ], [ -55.709178025845233, -25.729075209253494 ], [ -55.71933244463662, -25.731555677952201 ], [ -55.734111904940448, -25.743286227877093 ], [ -55.74144995824895, -25.752174573897491 ], [ -55.751888596981132, -25.771811618811171 ], [ -55.756978725587715, -25.777392672933502 ], [ -55.770156216336318, -25.784162285461093 ], [ -55.859685635283824, -25.817493585060902 ], [ -55.873069830708118, -25.824779961526019 ], [ -55.897719488963219, -25.842039889629177 ], [ -55.908881599006577, -25.846742445507459 ], [ -55.9447708807715, -25.853563734878492 ], [ -55.956630621905674, -25.858317965801461 ], [ -55.975415005198329, -25.873304131680356 ], [ -55.988179083897592, -25.880435478514528 ], [ -56.020941941817171, -25.888807060597344 ], [ -56.033499314941423, -25.894026381312472 ], [ -56.042413500282805, -25.904413344100533 ], [ -56.047374436780842, -25.91381845495772 ], [ -56.068355068831352, -25.991126396665891 ], [ -56.071429815833312, -25.999446302804643 ], [ -56.072437507085283, -26.001151625147372 ], [ -56.074116991006349, -26.003425388271069 ], [ -56.098895839571355, -26.018514906937412 ], [ -56.155248989449319, -26.043991387492554 ], [ -56.173800828745243, -26.042182713261582 ], [ -56.213488328823303, -26.018773288456487 ], [ -56.240928514139625, -25.998464450873712 ], [ -56.245579393174467, -25.995673922913227 ], [ -56.253821784048114, -25.991901543921131 ], [ -56.265733202025672, -25.9920565726527 ], [ -56.280280117433449, -25.995570571025041 ], [ -56.329476081156201, -26.015207615039401 ], [ -56.338829515170005, -26.015672703032806 ], [ -56.345857510115991, -26.013967379790756 ], [ -56.352368740225188, -26.01040170727299 ], [ -56.358905808756049, -26.010246676742725 ], [ -56.367148199629696, -26.013967379790756 ], [ -56.375183884928333, -26.026473076970944 ], [ -56.378749559244739, -26.037996920421563 ], [ -56.38037736722174, -26.049934176820784 ], [ -56.384330614266446, -26.061044610020758 ], [ -56.392469652352588, -26.068744398535159 ], [ -56.408876918834721, -26.074067071138415 ], [ -56.457762824194958, -26.076030775899596 ], [ -56.471999681240277, -26.080061537310087 ], [ -56.482567512081005, -26.087813001768609 ], [ -56.493316210075022, -26.104349461258607 ], [ -56.499775764240098, -26.121351006943428 ], [ -56.506597052711811, -26.165482679581999 ], [ -56.514916957951243, -26.17380258572075 ], [ -56.529076300630777, -26.178815199062171 ], [ -56.554320238088508, -26.176024672001006 ], [ -56.586514655227177, -26.175869643269436 ], [ -56.653203091049818, -26.064713637124669 ], [ -56.659145881277368, -26.051691176006955 ], [ -56.663331672318805, -26.037221774964962 ], [ -56.668757696810246, -25.999136243542807 ], [ -56.669507004744446, -25.996965834105936 ], [ -56.669997932058891, -25.991539808715174 ], [ -56.668835212075351, -25.98533863696855 ], [ -56.663099128322131, -25.978517347597517 ], [ -56.656510382947829, -25.975106702912001 ], [ -56.613748134968432, -25.965546562423924 ], [ -56.603852097696119, -25.960792331500897 ], [ -56.599020352407308, -25.950508721500285 ], [ -56.599046189929709, -25.93557423246483 ], [ -56.608606330417786, -25.907823988786049 ], [ -56.617132941232228, -25.892837822907211 ], [ -56.64090410034396, -25.864984225541605 ], [ -56.648345506439966, -25.853512058035051 ], [ -56.655218471755063, -25.838319186581202 ], [ -56.665424567389891, -25.807106622272784 ], [ -56.671289842352337, -25.776565850633517 ], [ -56.672478399858278, -25.759099216055972 ], [ -56.670618048783922, -25.742562757465294 ], [ -56.663538376994495, -25.724579359849599 ], [ -56.646795212828806, -25.710368341225944 ], [ -56.62509111216508, -25.698482760770787 ], [ -56.569952359114097, -25.674453220139981 ], [ -56.559952969054279, -25.668768813230145 ], [ -56.512488166095977, -25.628099461221154 ], [ -56.49907813225002, -25.620296319019928 ], [ -56.481999071300095, -25.614611912110036 ], [ -56.450631475562147, -25.609650973813416 ], [ -56.437634853765474, -25.606240330027219 ], [ -56.42618852378132, -25.601744479723948 ], [ -56.395957811403889, -25.584277846045779 ], [ -56.378827073610523, -25.579471938279312 ], [ -56.359060838386995, -25.577766615936582 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/puerto rico.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/puerto rico.geojson new file mode 100644 index 0000000000000..f4a0603c53f9e --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/puerto rico.geojson @@ -0,0 +1,7 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "US-PR", "NAME_1": "Puerto Rico" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -67.855865037999934, 18.11469147300005 ], [ -67.844349738999938, 18.104559637000079 ], [ -67.844146287999934, 18.097560940000051 ], [ -67.849761522999927, 18.090643622000073 ], [ -67.859934048999946, 18.073146877000056 ], [ -67.864165818999936, 18.068752346000053 ], [ -67.867543097999942, 18.064195054000038 ], [ -67.868885870999918, 18.056341864000046 ], [ -67.873158331999946, 18.05345286700009 ], [ -67.882557745999918, 18.052557684000078 ], [ -67.891957160999937, 18.05345286700009 ], [ -67.896229620999918, 18.056341864000046 ], [ -67.902699347999942, 18.065415757000039 ], [ -67.931141730999911, 18.080511786000045 ], [ -67.93781490799995, 18.094224351000037 ], [ -67.931304490999935, 18.108710028000075 ], [ -67.919748501999948, 18.114488023000092 ], [ -67.861887173999946, 18.116115627000056 ], [ -67.855865037999934, 18.11469147300005 ] ] ], [ [ [ -65.347727016999954, 18.11469147300005 ], [ -65.356597459999932, 18.122870184000078 ], [ -65.371205206999946, 18.119533596000053 ], [ -65.390248175999943, 18.11196523600006 ], [ -65.468576626999948, 18.094427802000041 ], [ -65.484242316999939, 18.08734772300005 ], [ -65.504872199999909, 18.093654690000051 ], [ -65.536000128999945, 18.090073960000041 ], [ -65.56509355399993, 18.093939520000049 ], [ -65.580433722999942, 18.122137762000079 ], [ -65.564930792999917, 18.122626044000071 ], [ -65.559925910999937, 18.122137762000079 ], [ -65.540150519999941, 18.12376536700009 ], [ -65.520253058999913, 18.130926825000074 ], [ -65.50218665299991, 18.14126211100006 ], [ -65.487945115999935, 18.152289130000042 ], [ -65.478505011999914, 18.157049872000073 ], [ -65.398548956999946, 18.169338283000059 ], [ -65.385812954999949, 18.167181708000044 ], [ -65.351063605999911, 18.15570709800005 ], [ -65.298573370999918, 18.153713283000059 ], [ -65.285552537999934, 18.148871161000045 ], [ -65.275746222999942, 18.137152411000045 ], [ -65.283070441999939, 18.133490302000041 ], [ -65.309803839999915, 18.135199286000045 ], [ -65.316558397999927, 18.132798570000091 ], [ -65.335560675999943, 18.120266018000052 ], [ -65.340809699999909, 18.11469147300005 ], [ -65.347727016999954, 18.11469147300005 ] ] ], [ [ [ -65.278797980999911, 18.279201565000051 ], [ -65.292591925999943, 18.299953518000052 ], [ -65.334339972999942, 18.337103583000044 ], [ -65.334055141999954, 18.340643622000073 ], [ -65.309437628999945, 18.340765692000048 ], [ -65.280913865999935, 18.335272528000075 ], [ -65.256662563999953, 18.323919989000046 ], [ -65.244618292999917, 18.306545315000051 ], [ -65.247547980999911, 18.305853583000044 ], [ -65.258290167999917, 18.306545315000051 ], [ -65.251454230999911, 18.299709377000056 ], [ -65.262115037999934, 18.299221096000053 ], [ -65.270415818999936, 18.30141836100006 ], [ -65.27603105399993, 18.306341864000046 ], [ -65.278797980999911, 18.313950914000088 ], [ -65.285552537999934, 18.313950914000088 ], [ -65.276519334999932, 18.296942450000074 ], [ -65.274810350999928, 18.289007880000042 ], [ -65.278797980999911, 18.279201565000051 ] ] ], [ [ [ -65.628814256999931, 18.279201565000051 ], [ -65.632923956999946, 18.266913153000075 ], [ -65.625803188999953, 18.259833075000074 ], [ -65.617591109999921, 18.256343797000056 ], [ -65.603701908999938, 18.262860527000043 ], [ -65.606586998999944, 18.25360994600004 ], [ -65.60377320799995, 18.246339934000048 ], [ -65.5917638869999, 18.230884786000047 ], [ -65.602112122999927, 18.223753350000038 ], [ -65.603532549999954, 18.215270496000073 ], [ -65.612442619999911, 18.214503295000043 ], [ -65.622218243999953, 18.22926327600004 ], [ -65.633363362999944, 18.22918349400004 ], [ -65.636994766999919, 18.21857009900009 ], [ -65.62723464499993, 18.205928744000062 ], [ -65.63683059899995, 18.198096500000077 ], [ -65.648734771999898, 18.200131146000047 ], [ -65.665516730999911, 18.20844147300005 ], [ -65.682972785999937, 18.202826239000046 ], [ -65.701283331999946, 18.194240627000056 ], [ -65.72101803299995, 18.189846096000053 ], [ -65.737538214999915, 18.182684637000079 ], [ -65.754872199999909, 18.166245835000041 ], [ -65.790289178999899, 18.113972511000043 ], [ -65.793142091999925, 18.087630827000055 ], [ -65.806996222999942, 18.070298570000091 ], [ -65.812163865999935, 18.067287502000056 ], [ -65.835275844999899, 18.062486070000091 ], [ -65.84048417899993, 18.056341864000046 ], [ -65.830269476999945, 18.026906814000085 ], [ -65.849745717999951, 18.009711121000066 ], [ -65.887177814999916, 17.987726979000058 ], [ -65.939116990999935, 17.970526434000078 ], [ -65.961659308999913, 17.97101471600007 ], [ -65.984527147999927, 17.975653387000079 ], [ -66.004994269999941, 17.977525132000039 ], [ -66.017079230999911, 17.975083726000037 ], [ -66.046538865999935, 17.963853257000039 ], [ -66.053578253999945, 17.963120835000041 ], [ -66.084095831999946, 17.963853257000039 ], [ -66.104644334999932, 17.958929755000042 ], [ -66.163238084999932, 17.92914459800005 ], [ -66.175607876999948, 17.928208726000037 ], [ -66.186634894999941, 17.928615627000056 ], [ -66.196278449999909, 17.927720445000091 ], [ -66.204213019999941, 17.922919012000079 ], [ -66.208566860999952, 17.92914459800005 ], [ -66.209828253999945, 17.931870835000041 ], [ -66.210438605999911, 17.936590887000079 ], [ -66.199574347999942, 17.939601955000057 ], [ -66.197010870999918, 17.944403387000079 ], [ -66.201161261999914, 17.950506903000075 ], [ -66.210438605999911, 17.957098700000074 ], [ -66.229888475999928, 17.940415757000039 ], [ -66.241363084999932, 17.937323309000078 ], [ -66.255523240999935, 17.940659898000092 ], [ -66.283070441999939, 17.943426825000074 ], [ -66.292591925999943, 17.945746161000045 ], [ -66.297718878999945, 17.951402085000041 ], [ -66.301380988999938, 17.958197333000044 ], [ -66.306630011999914, 17.963853257000039 ], [ -66.319162563999953, 17.970363674000055 ], [ -66.328114386999914, 17.972316799000055 ], [ -66.344471808999913, 17.97134023600006 ], [ -66.367665167999917, 17.966009833000044 ], [ -66.396148240999935, 17.947251695000091 ], [ -66.416493292999917, 17.949611721000053 ], [ -66.435902472999942, 17.964016018000052 ], [ -66.452137824999909, 17.982163804000038 ], [ -66.469146287999934, 17.992661851000037 ], [ -66.487799859999939, 17.988853697000081 ], [ -66.501969120999945, 17.987115356000061 ], [ -66.512521938999953, 17.982001044000071 ], [ -66.527007615999935, 17.979315497000073 ], [ -66.559885219999899, 17.977525132000039 ], [ -66.570423956999946, 17.972357489000046 ], [ -66.580637173999946, 17.965806382000039 ], [ -66.592518683999913, 17.963568427000041 ], [ -66.608265753999945, 17.97134023600006 ], [ -66.615305141999954, 17.966742255000042 ], [ -66.622547980999911, 17.963853257000039 ], [ -66.629383917999917, 17.975165106000077 ], [ -66.646595831999946, 17.976629950000074 ], [ -66.687408006999931, 17.97134023600006 ], [ -66.694976365999935, 17.973089911000045 ], [ -66.724964972999942, 17.984361070000091 ], [ -66.76593990799995, 17.984361070000091 ], [ -66.765126105999911, 17.998032945000091 ], [ -66.774037238999938, 18.002183335000041 ], [ -66.787464972999942, 17.999335028000075 ], [ -66.800119594999899, 17.991848049000055 ], [ -66.800119594999899, 17.984361070000091 ], [ -66.786447719999899, 17.984361070000091 ], [ -66.797963019999941, 17.969305731000077 ], [ -66.817697719999899, 17.958970445000091 ], [ -66.840565558999913, 17.952704169000071 ], [ -66.861480272999927, 17.949611721000053 ], [ -66.892648891999954, 17.950669664000088 ], [ -66.907826300999943, 17.949204820000091 ], [ -66.919016079999949, 17.950140692000048 ], [ -66.924224412999934, 17.949611721000053 ], [ -66.928212042999917, 17.945542710000041 ], [ -66.92992102799991, 17.938625393000052 ], [ -66.930409308999913, 17.92914459800005 ], [ -66.949126756999931, 17.931219794000071 ], [ -66.963246222999942, 17.941066799000055 ], [ -66.985707160999937, 17.963853257000039 ], [ -67.005959401999917, 17.964910772000053 ], [ -67.028528302999916, 17.968537713000046 ], [ -67.052712969999902, 17.968166438000083 ], [ -67.067005988999938, 17.972560940000051 ], [ -67.080922003999945, 17.96124909100007 ], [ -67.097320115999935, 17.952866929000038 ], [ -67.11196855399993, 17.949611721000053 ], [ -67.124012824999909, 17.951157945000091 ], [ -67.15855980099991, 17.954568756000072 ], [ -67.1804672479999, 17.966118460000075 ], [ -67.191221363999944, 17.957993996000084 ], [ -67.184192353999947, 17.935072253000044 ], [ -67.195073253999908, 17.935682387000043 ], [ -67.209610209999937, 17.956889788000069 ], [ -67.2147711799999, 17.966335022000067 ], [ -67.214349170999924, 17.994143776000044 ], [ -67.190500454999949, 18.004828192000048 ], [ -67.183338995999918, 18.00853099200009 ], [ -67.174224412999934, 18.01117584800005 ], [ -67.166493292999917, 18.015041408000059 ], [ -67.163197394999941, 18.022528387000079 ], [ -67.167225714999915, 18.027899481000077 ], [ -67.176869269999941, 18.032700914000088 ], [ -67.190075598999954, 18.030314326000052 ], [ -67.202875123999945, 18.035716432000072 ], [ -67.202134046999902, 18.054357831000061 ], [ -67.195400258999939, 18.063768118000041 ], [ -67.185692598999935, 18.07042742100009 ], [ -67.189740674999939, 18.080609646000084 ], [ -67.193876796999916, 18.097302159000037 ], [ -67.183244559999935, 18.107688841000083 ], [ -67.183778284999903, 18.139945037000075 ], [ -67.173695441999939, 18.176174221000053 ], [ -67.165908946999934, 18.184074226000064 ], [ -67.157535861999918, 18.191734409000048 ], [ -67.151857830999916, 18.203392396000083 ], [ -67.158465121999939, 18.213957881000056 ], [ -67.171198295999943, 18.22487028200004 ], [ -67.187082485999952, 18.272772528000075 ], [ -67.196511528999906, 18.291338513000085 ], [ -67.218828784999914, 18.295573695000087 ], [ -67.236906282999939, 18.29986180800006 ], [ -67.252774233999901, 18.329337017000057 ], [ -67.262600709999901, 18.343812572000047 ], [ -67.270842180999921, 18.361826454000038 ], [ -67.268824856999913, 18.368899978000059 ], [ -67.240267343999903, 18.376812365000092 ], [ -67.217355923999946, 18.38617584800005 ], [ -67.198394334999932, 18.393703518000052 ], [ -67.184315558999913, 18.402085679000038 ], [ -67.159451107999928, 18.420910746000061 ], [ -67.158117998999899, 18.443110832000059 ], [ -67.168698741999947, 18.460604676000059 ], [ -67.170006635999925, 18.486019825000085 ], [ -67.151682094999899, 18.508937893000052 ], [ -67.101714647999927, 18.522772528000075 ], [ -67.048451300999943, 18.521144924000055 ], [ -67.01235917899993, 18.505764065000051 ], [ -66.907315639999922, 18.485324843000058 ], [ -66.803456183999913, 18.498277085000041 ], [ -66.789214647999927, 18.496527411000045 ], [ -66.751698370999918, 18.484035549000055 ], [ -66.736805792999917, 18.48314036700009 ], [ -66.697661912999934, 18.491441148000092 ], [ -66.64085852799991, 18.49640534100007 ], [ -66.614328579999949, 18.493231512000079 ], [ -66.587798631999931, 18.484035549000055 ], [ -66.571441209999932, 18.487005927000041 ], [ -66.507069464999915, 18.486395575000074 ], [ -66.46743730399993, 18.475287177000041 ], [ -66.382394985999952, 18.491441148000092 ], [ -66.303863084999932, 18.468817450000074 ], [ -66.25812740799995, 18.481512762000079 ], [ -66.205189581999946, 18.465399481000077 ], [ -66.193988621999949, 18.473586567000041 ], [ -66.180897589999915, 18.471502997000073 ], [ -66.173695441999939, 18.462958075000074 ], [ -66.170074022999927, 18.45734284100007 ], [ -66.161584084999902, 18.453298221000068 ], [ -66.152007595999919, 18.458723638000038 ], [ -66.144085162999943, 18.468702418000078 ], [ -66.134144660999937, 18.465887762000079 ], [ -66.137470201999918, 18.452755932000059 ], [ -66.118080620999933, 18.443026868000061 ], [ -66.114857550999943, 18.433172919000071 ], [ -66.108469204999949, 18.42064036700009 ], [ -66.093169725999928, 18.419826565000051 ], [ -66.060210740999935, 18.429388739000046 ], [ -66.060210740999935, 18.436835028000075 ], [ -66.076771613999938, 18.438869533000059 ], [ -66.094960089999915, 18.447699286000045 ], [ -66.109364386999914, 18.461411851000037 ], [ -66.121631156999911, 18.473470242000076 ], [ -66.055897589999915, 18.453802802000041 ], [ -66.03970292899993, 18.450506903000075 ], [ -66.028184650999947, 18.446870575000048 ], [ -66.012099753999905, 18.44396181500008 ], [ -65.997717399999942, 18.450184941000089 ], [ -65.988880988999938, 18.463080145000049 ], [ -65.966216600999928, 18.45844147300005 ], [ -65.920438427999954, 18.445889431000069 ], [ -65.90482604999994, 18.45592492600008 ], [ -65.89281165299991, 18.453599351000037 ], [ -65.880523240999935, 18.444810289000088 ], [ -65.84829667899993, 18.437892971000053 ], [ -65.830799933999913, 18.428697007000039 ], [ -65.81260562999995, 18.410405382000079 ], [ -65.801625815999898, 18.415443225000047 ], [ -65.794168806999949, 18.425405872000056 ], [ -65.788347260999899, 18.423249257000066 ], [ -65.78714832199995, 18.41830708100008 ], [ -65.792317702999924, 18.41276352400007 ], [ -65.796307176999903, 18.405028206000054 ], [ -65.788777103999905, 18.406737253000074 ], [ -65.778372095999941, 18.410669300000052 ], [ -65.772027141999899, 18.414570150000088 ], [ -65.755002426999908, 18.391041037000036 ], [ -65.738107160999903, 18.382365176000064 ], [ -65.72484854399994, 18.391266958000074 ], [ -65.698014782999905, 18.371110745000067 ], [ -65.663200287999928, 18.366413598000065 ], [ -65.645741339999915, 18.378404039000088 ], [ -65.637766079999949, 18.385687567000048 ], [ -65.629383917999917, 18.391058661000045 ], [ -65.62140865799995, 18.389064846000053 ], [ -65.621001756999931, 18.38226959800005 ], [ -65.630767381999931, 18.332831122000073 ], [ -65.632964647999927, 18.291001695000091 ], [ -65.628814256999931, 18.279201565000051 ] ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/saint barthelemy.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/saint barthelemy.geojson new file mode 100644 index 0000000000000..d4ebeabfa1bfa --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/saint barthelemy.geojson @@ -0,0 +1,7 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "BL-X00~", "NAME_1": "Saint Barthélemy" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -62.838856574999909, 17.881984768000052 ], [ -62.850941535999937, 17.890448309000078 ], [ -62.861317511999914, 17.905422268000052 ], [ -62.867339647999927, 17.920396226000037 ], [ -62.866118943999936, 17.92914459800005 ], [ -62.857411261999914, 17.925034898000092 ], [ -62.79165605399993, 17.91547272300005 ], [ -62.798939581999946, 17.904486395000049 ], [ -62.810129360999952, 17.892279364000046 ], [ -62.823841925999943, 17.883246161000045 ], [ -62.838856574999909, 17.881984768000052 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/saint martin.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/saint martin.geojson new file mode 100644 index 0000000000000..6f23bfaee0271 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/saint martin.geojson @@ -0,0 +1,7 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "MF-X00~", "NAME_1": "St. Martin" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -63.017568585288387, 18.033391472351283 ], [ -63.085886190999901, 18.058511251000098 ], [ -63.107004360999952, 18.062119859000063 ], [ -63.107004360999952, 18.066961981000077 ], [ -63.115305141999954, 18.065375067000048 ], [ -63.130523240999935, 18.060248114000046 ], [ -63.134348110999952, 18.059475002000056 ], [ -63.143869594999899, 18.064683335000041 ], [ -63.146839972999942, 18.070298570000091 ], [ -63.143625454999949, 18.074164130000042 ], [ -63.113758917999917, 18.074652411000045 ], [ -63.096099412999934, 18.078802802000041 ], [ -63.083811001999948, 18.087958075000074 ], [ -63.079090949999909, 18.104193427000041 ], [ -63.070871548999946, 18.11001211100006 ], [ -63.052113410999937, 18.116848049000055 ], [ -63.031402147999927, 18.121893622000073 ], [ -63.017648891999954, 18.122137762000079 ], [ -63.017933722999942, 18.100531317000048 ], [ -63.011097785999937, 18.070746161000045 ], [ -63.010731574999909, 18.040838934000078 ], [ -63.017568585288387, 18.033391472351283 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/turkey.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/turkey.geojson new file mode 100644 index 0000000000000..8e0d83a404a2f --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/turkey.geojson @@ -0,0 +1,87 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "TR-01", "NAME_1": "Adana" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 35.279026031494084,36.64069366455101 ], [ 35.28180694580078,36.6390266418457 ], [ 35.282917022705135,36.636806488037166 ], [ 35.27819442749029,36.640140533447266 ], [ 35.279026031494084,36.64069366455101 ] ] ], [ [ [ 35.27152633666998,36.64485931396507 ], [ 35.274028778076456,36.64319610595709 ], [ 35.274028778076456,36.64208221435558 ], [ 35.27125167846697,36.64319610595709 ], [ 35.27152633666998,36.64485931396507 ] ] ], [ [ [ 35.20735931396513,36.65069580078119 ], [ 35.2093048095706,36.64986038208025 ], [ 35.20958328247099,36.64930725097685 ], [ 35.206249237060604,36.649028778076456 ], [ 35.20735931396513,36.65069580078119 ] ] ], [ [ [ 35.21180725097656,36.65541839599638 ], [ 35.212081909179744,36.65319442749046 ], [ 35.21152877807634,36.6529159545899 ], [ 35.20958328247099,36.65513992309582 ], [ 35.21180725097656,36.65541839599638 ] ] ], [ [ [ 35.21347045898466,36.659862518310774 ], [ 35.21402740478527,36.65874862670927 ], [ 35.21069335937517,36.65902709960943 ], [ 35.21097183227556,36.659862518310774 ], [ 35.21347045898466,36.659862518310774 ] ] ], [ [ [ 35.20958328247099,36.67874908447283 ], [ 35.212360382080135,36.677639007568644 ], [ 35.212360382080135,36.67680740356468 ], [ 35.20847320556646,36.6781959533692 ], [ 35.20958328247099,36.67874908447283 ] ] ], [ [ [ 35.5912513732913,36.704029083252124 ], [ 35.5915260314942,36.6995849609375 ], [ 35.59069442749018,36.6995849609375 ], [ 35.589862823486385,36.70319366455078 ], [ 35.5912513732913,36.704029083252124 ] ] ], [ [ [ 35.60680389404291,36.70541763305687 ], [ 35.60625076293951,36.700973510742415 ], [ 35.6012496948245,36.70019912719721 ], [ 35.60514068603533,36.70541763305687 ], [ 35.60680389404291,36.70541763305687 ] ] ], [ [ [ 35.68264007568365,36.716251373291016 ], [ 35.67958450317383,36.71263885498075 ], [ 35.67736053466825,36.7140274047851 ], [ 35.680973052978516,36.716251373291016 ], [ 35.68264007568365,36.716251373291016 ] ] ], [ [ [ 35.69708251953142,36.72735977172874 ], [ 35.70291519165045,36.724304199219034 ], [ 35.70291519165045,36.72347259521507 ], [ 35.69736099243181,36.72375106811546 ], [ 35.69708251953142,36.72735977172874 ] ] ], [ [ [ 36.329639434814624,37.92000961303711 ], [ 36.31517028808622,37.88559722900396 ], [ 36.31903839111345,37.83251953125 ], [ 36.36219787597662,37.75340270996094 ], [ 36.302368164062614,37.651248931884936 ], [ 36.153835296630916,37.63694381713884 ], [ 36.033290863037166,37.57089233398443 ], [ 35.88317108154325,37.35688018798834 ], [ 35.881771087646484,37.241584777832145 ], [ 35.904296875000114,37.20827102661144 ], [ 35.85282516479492,37.12870788574219 ], [ 35.87482452392595,37.121696472168026 ], [ 36.000972747802734,37.17415237426786 ], [ 36.03230667114258,37.15906143188488 ], [ 36.061447143554744,37.108856201171875 ], [ 36.04160690307617,37.025554656982536 ], [ 35.94699859619146,36.95690536499052 ], [ 35.91258621215826,36.90350723266613 ], [ 35.93404769897478,36.87985992431646 ], [ 35.84180450439453,36.795139312744254 ], [ 35.7945823669433,36.765693664551065 ], [ 35.666805267333984,36.76708221435547 ], [ 35.6270828247072,36.74569320678734 ], [ 35.60930633544939,36.71430587768549 ], [ 35.61291503906244,36.73208236694336 ], [ 35.60319519042969,36.727085113525334 ], [ 35.5995826721192,36.69985961914091 ], [ 35.5915260314942,36.71097183227562 ], [ 35.563194274902344,36.71263885498075 ], [ 35.55430603027372,36.6995849609375 ], [ 35.570137023926065,36.70652770996122 ], [ 35.584583282470646,36.67958450317394 ], [ 35.6295814514163,36.721527099609375 ], [ 35.62430572509794,36.733749389648665 ], [ 35.654304504394474,36.739860534668026 ], [ 35.64541625976568,36.70763778686518 ], [ 35.65680694580095,36.72902679443365 ], [ 35.65402603149414,36.70791625976557 ], [ 35.70652770996122,36.71319580078131 ], [ 35.704303741455135,36.72319412231468 ], [ 35.7234725952149,36.71263885498075 ], [ 35.64513778686529,36.66847229003906 ], [ 35.62180709838884,36.604305267334155 ], [ 35.581806182861385,36.59069442749052 ], [ 35.565971374512,36.56486129760748 ], [ 35.41819381713873,36.590137481689396 ], [ 35.339027404785156,36.538471221924 ], [ 35.329582214355526,36.56791687011713 ], [ 35.32208251953142,36.572360992431754 ], [ 35.34624862670904,36.60347366333036 ], [ 35.285137176513615,36.62680435180664 ], [ 35.28791809082048,36.64347076416033 ], [ 35.27097320556658,36.65208435058611 ], [ 35.2640266418457,36.639305114746264 ], [ 35.24902725219738,36.654026031494254 ], [ 35.27152633666998,36.66180419921875 ], [ 35.25097274780302,36.6781959533692 ], [ 35.18069458007841,36.69291687011719 ], [ 35.163471221924,36.67597198486351 ], [ 35.17597198486345,36.66152954101574 ], [ 35.273471832275675,36.60874938964861 ], [ 35.3245849609375,36.55875015258812 ], [ 34.997917175293026,36.713470458984546 ], [ 34.91521453857422,36.724861145019645 ], [ 34.949817657470646,36.7540168762207 ], [ 35.034801483154354,36.770996093750284 ], [ 35.06715011596697,36.81790924072271 ], [ 35.06958389282255,36.8526496887207 ], [ 35.05463027954107,36.97039413452154 ], [ 35.00078582763683,37.041458129882926 ], [ 34.92519378662115,37.0896911621096 ], [ 34.90010833740263,37.17629623413086 ], [ 34.78625869750982,37.379280090332145 ], [ 34.78827667236334,37.465160369873104 ], [ 34.860763549804744,37.525032043456974 ], [ 34.85847854614258,37.57877349853527 ], [ 34.81658554077154,37.65838241577154 ], [ 34.826660156250284,37.684917449951286 ], [ 34.86949157714844,37.71004486083979 ], [ 35.02579116821306,37.69889450073242 ], [ 35.08160018920927,37.718662261963004 ], [ 35.21365356445324,37.83214187622076 ], [ 35.20755767822294,37.91330337524414 ], [ 35.24167633056646,37.95356369018572 ], [ 35.45680999755865,37.91956710815424 ], [ 35.621017456054744,37.95576095581066 ], [ 35.680976867676065,38.05966186523432 ], [ 36.01338195800787,38.185642242431584 ], [ 36.161430358887,38.4135093688966 ], [ 36.30536651611334,38.463748931884766 ], [ 36.37761306762707,38.46636962890625 ], [ 36.42207336425781,38.442195892333984 ], [ 36.49144363403326,38.31632614135742 ], [ 36.42615890502947,38.25278854370117 ], [ 36.33535766601574,37.99667358398449 ], [ 36.329639434814624,37.92000961303711 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-02", "NAME_1": "Adıyaman" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 38.65533828735357,38.09172439575201 ], [ 38.85887527465832,38.09242630004883 ], [ 39.00511550903326,38.11749267578125 ], [ 39.074615478515796,38.14497375488281 ], [ 39.11173629760748,38.18469238281273 ], [ 39.160182952880916,38.17333602905296 ], [ 39.20501708984369,38.19129943847656 ], [ 39.24630737304693,38.16666030883812 ], [ 39.210086822509766,38.05253982543945 ], [ 39.073436737060604,37.99180603027361 ], [ 38.99199676513689,37.91375732421875 ], [ 38.976436614990234,37.88441848754894 ], [ 38.97814941406256,37.795402526855696 ], [ 38.95181274414068,37.74911117553711 ], [ 38.83071136474615,37.69311904907238 ], [ 38.83985519409174,37.658622741699276 ], [ 38.8294410705567,37.6424446105957 ], [ 38.615886688232536,37.57777023315424 ], [ 38.47832489013666,37.48891067504883 ], [ 38.330547332763786,37.48437881469732 ], [ 38.15669631958025,37.406925201416016 ], [ 38.06077194213867,37.4311904907226 ], [ 37.98249435424833,37.496170043945426 ], [ 37.7957878112793,37.5446510314942 ], [ 37.679069519043026,37.512031555175895 ], [ 37.62296295166021,37.51213455200224 ], [ 37.5731277465822,37.55051803588867 ], [ 37.45948791503912,37.58237457275396 ], [ 37.416450500488395,37.61639785766624 ], [ 37.422187805176065,37.703323364257926 ], [ 37.59421539306652,37.82491683959972 ], [ 37.73728942871122,37.83412933349632 ], [ 37.76950454711931,37.86634826660179 ], [ 37.83566284179693,37.882831573486385 ], [ 37.980312347412166,37.860988616943644 ], [ 38.18105316162115,37.91896057128906 ], [ 38.13481521606451,38.089435577392635 ], [ 38.39860153198248,38.19963455200201 ], [ 38.5370826721192,38.23062896728521 ], [ 38.634452819824276,38.19916915893566 ], [ 38.62433242797846,38.169216156006144 ], [ 38.562923431396484,38.12447357177746 ], [ 38.65533828735357,38.09172439575201 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-03", "NAME_1": "Afyon" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 31.362766265869197,39.16468429565424 ], [ 31.386358261108683,39.11867141723644 ], [ 31.4598522186281,39.088176727295206 ], [ 31.696891784668253,39.09305953979515 ], [ 31.708700180053995,38.95373535156273 ], [ 31.6233043670656,38.817733764648665 ], [ 31.58945655822771,38.72563552856445 ], [ 31.6107826232913,38.67497253417963 ], [ 31.679281234741325,38.63260269165045 ], [ 31.260772705078296,38.427665710449276 ], [ 31.20930480957037,38.439853668213004 ], [ 31.12550926208496,38.51361846923828 ], [ 31.088424682617244,38.5123291015625 ], [ 30.799964904785327,38.2902374267581 ], [ 30.640510559082202,38.245807647705135 ], [ 30.517358779907283,38.18640518188471 ], [ 30.366300582886026,38.07125473022461 ], [ 30.265552520752237,38.016117095947266 ], [ 30.22363090515165,37.98092269897472 ], [ 30.18260765075712,37.9011611938476 ], [ 30.19958305358915,37.84968566894531 ], [ 30.167104721069393,37.81391525268555 ], [ 30.09053611755371,37.776737213134766 ], [ 29.966999053955135,37.78396606445335 ], [ 29.845273971557788,37.76081848144531 ], [ 29.81536865234392,37.81905364990257 ], [ 29.72046852111822,37.852550506591854 ], [ 29.663770675659237,37.852550506591854 ], [ 29.665998458862475,37.98868942260748 ], [ 29.924520492553825,38.10348129272478 ], [ 30.020292282104776,38.17622375488281 ], [ 30.041278839111328,38.22135543823259 ], [ 30.03680038452154,38.251564025878906 ], [ 29.922199249267862,38.41290664672874 ], [ 29.755413055419922,38.45410919189453 ], [ 29.77183532714872,38.50595855712919 ], [ 29.87275886535673,38.64421844482433 ], [ 29.894367218017862,38.70968246459984 ], [ 30.074789047241268,38.78848648071295 ], [ 30.115364074706974,38.820873260498104 ], [ 30.27036857605009,39.08821105957054 ], [ 30.384635925293253,39.12631988525396 ], [ 30.43370437622076,39.16427230834972 ], [ 30.45332908630388,39.20599746704107 ], [ 30.50550842285162,39.189422607421875 ], [ 30.542961120605753,39.13069152832031 ], [ 30.6117458343507,39.07914733886719 ], [ 30.639776229858512,39.076957702636946 ], [ 30.766630172729776,39.12854385375999 ], [ 30.799478530883846,39.172389984130916 ], [ 30.885963439941577,39.21287155151373 ], [ 30.989156723022518,39.15921020507824 ], [ 31.141860961914347,39.218502044677734 ], [ 31.24177551269537,39.28451919555664 ], [ 31.30526924133318,39.273185729980526 ], [ 31.362766265869197,39.16468429565424 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-04", "NAME_1": "Ağrı" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 43.39566040039057,39.925796508789176 ], [ 43.39422988891596,39.79460525512701 ], [ 43.456417083740234,39.767475128173885 ], [ 43.47832870483427,39.766723632812614 ], [ 43.5319442749024,39.820419311523494 ], [ 43.62248992919939,39.82235717773443 ], [ 43.74055480957048,39.79948043823242 ], [ 43.999706268310604,39.68526458740246 ], [ 44.15977859497082,39.69419860839855 ], [ 44.23257827758795,39.671707153320426 ], [ 44.3003501892091,39.67086791992193 ], [ 44.380176544189624,39.69319534301769 ], [ 44.49647140502958,39.69598007202171 ], [ 44.489604949951456,39.630126953125114 ], [ 44.43618774414068,39.560661315918196 ], [ 44.45337677001959,39.50155639648449 ], [ 44.4333610534668,39.47306823730469 ], [ 44.441123962402514,39.435874938964844 ], [ 44.423660278320426,39.4098014831543 ], [ 44.30173492431646,39.3714714050293 ], [ 44.22431182861334,39.41028976440441 ], [ 44.17476272583025,39.40239334106445 ], [ 44.1518440246582,39.377182006835994 ], [ 44.138137817382926,39.37977981567394 ], [ 44.143608093261776,39.400177001953125 ], [ 44.069816589355526,39.40531921386719 ], [ 44.04974365234392,39.360752105712834 ], [ 44.03281784057617,39.37202072143555 ], [ 43.96207427978521,39.35651016235363 ], [ 43.716354370117244,39.37020492553734 ], [ 43.64554214477545,39.302429199218864 ], [ 43.5928192138673,39.287895202636946 ], [ 43.494350433349894,39.327377319336165 ], [ 43.42657852172857,39.38888549804682 ], [ 43.293762207031534,39.40276336669933 ], [ 43.19167327880865,39.32806777954107 ], [ 43.10197830200224,39.32246017456055 ], [ 43.07938003540056,39.30751419067394 ], [ 43.08466720581049,39.284191131592024 ], [ 43.166938781738565,39.23722457885742 ], [ 43.16763305664068,39.16597366333019 ], [ 43.14973449707037,39.139167785644645 ], [ 42.97164154052763,39.08096313476585 ], [ 42.827857971191406,39.06509017944347 ], [ 42.749843597412166,39.03714752197277 ], [ 42.72988891601568,39.159004211425895 ], [ 42.672210693359375,39.24966812133812 ], [ 42.62761688232439,39.27266311645508 ], [ 42.516819000244425,39.37535095214838 ], [ 42.466396331787166,39.46373367309599 ], [ 42.463413238525675,39.48609924316412 ], [ 42.523639678955135,39.56861877441406 ], [ 42.50621795654325,39.72973632812494 ], [ 42.474822998047046,39.76498413085949 ], [ 42.285240173340014,39.81406784057623 ], [ 42.25519943237322,39.861167907714844 ], [ 42.2776527404788,39.88196563720703 ], [ 42.40620422363287,39.873390197753906 ], [ 42.566364288330135,39.94755172729515 ], [ 42.638339996337834,39.91758728027372 ], [ 42.7108917236331,39.91766357421875 ], [ 43.10322189331072,40.00832748413086 ], [ 43.3728103637697,39.960422515869084 ], [ 43.39566040039057,39.925796508789176 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-68", "NAME_1": "Aksaray" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 34.2052116394043,38.84115219116222 ], [ 34.26256942749052,38.793670654296875 ], [ 34.205261230469034,38.67776489257818 ], [ 34.273029327392635,38.62049484252958 ], [ 34.348003387451286,38.473419189453125 ], [ 34.394397735595646,38.43891906738287 ], [ 34.36829757690447,38.36765289306652 ], [ 34.36320114135748,38.2909202575683 ], [ 34.39450073242182,38.24264526367193 ], [ 34.38952255249029,38.16189575195307 ], [ 34.32982254028326,38.13497161865246 ], [ 34.26839065551758,38.05600738525402 ], [ 34.18675994873075,38.070056915283146 ], [ 34.14690780639654,38.05195236206055 ], [ 34.12569427490246,38.01376342773443 ], [ 33.77833557128912,37.95623016357433 ], [ 33.495018005371264,37.93255615234381 ], [ 33.41340637207048,37.95118713378906 ], [ 33.3625679016115,38.00362014770519 ], [ 33.240116119384936,38.21535110473644 ], [ 33.242633819580135,38.25516128540062 ], [ 33.30143737792986,38.347045898437614 ], [ 33.318119049072436,38.42950057983421 ], [ 33.38059997558611,38.562381744384766 ], [ 33.465042114257756,38.63647079467779 ], [ 33.68149948120117,38.711006164550895 ], [ 33.82563781738287,38.714866638183594 ], [ 33.923976898193416,38.78068542480486 ], [ 33.94691085815458,38.829227447509936 ], [ 33.8883056640625,38.954170227050895 ], [ 33.9267005920413,39.008110046386776 ], [ 34.07765579223633,38.90355300903332 ], [ 34.17686462402338,38.88210296630854 ], [ 34.2052116394043,38.84115219116222 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-05", "NAME_1": "Amasya" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.7025527954101,40.877315521240234 ], [ 35.840560913085994,40.86432647705101 ], [ 35.955291748046875,40.87558364868164 ], [ 36.06103515625006,40.84314727783226 ], [ 36.18094253540045,40.90474319458019 ], [ 36.20392608642584,40.98003387451172 ], [ 36.25976181030302,40.979282379150504 ], [ 36.372375488281534,40.952079772949276 ], [ 36.37617874145525,40.90769958496105 ], [ 36.4480056762697,40.86983108520536 ], [ 36.41676330566412,40.82258224487305 ], [ 36.45636749267595,40.770137786865234 ], [ 36.472808837890625,40.707481384277344 ], [ 36.44152450561552,40.63232803344738 ], [ 36.32520294189459,40.523677825927734 ], [ 36.20240020751959,40.45898437500006 ], [ 36.1100692749024,40.44609451293945 ], [ 36.03977584838873,40.45986938476557 ], [ 35.95844650268555,40.50232696533209 ], [ 35.84466171264654,40.501518249511776 ], [ 35.71618652343756,40.32625579834007 ], [ 35.5763778686524,40.27421951293945 ], [ 35.529628753662394,40.235530853271484 ], [ 35.51206970214861,40.189777374267635 ], [ 35.37136840820318,40.195156097412166 ], [ 35.33233642578119,40.228908538818416 ], [ 35.343681335449276,40.35832595825195 ], [ 35.448406219482365,40.46772384643566 ], [ 35.46423721313471,40.5735321044923 ], [ 35.42771530151373,40.615207672119254 ], [ 35.25703811645519,40.666099548340014 ], [ 35.15071868896513,40.67067337036144 ], [ 35.082084655762,40.71263122558594 ], [ 35.02510070800798,40.843399047851676 ], [ 35.04604339599604,40.852909088134766 ], [ 35.04957199096674,40.95141220092779 ], [ 35.09133148193365,41.03227615356468 ], [ 35.093154907226506,41.09054183959961 ], [ 35.48538970947271,41.012321472168026 ], [ 35.643894195556925,40.92682647705078 ], [ 35.66569137573259,40.89455795288109 ], [ 35.7025527954101,40.877315521240234 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-06", "NAME_1": "Ankara" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 33.187957763672046,40.41364669799805 ], [ 33.22098541259771,40.351249694824446 ], [ 33.2674293518067,40.331134796142805 ], [ 33.330764770507756,40.33474349975609 ], [ 33.364143371581974,40.38593292236334 ], [ 33.40986251831072,40.38897705078125 ], [ 33.72912216186518,40.27840805053711 ], [ 33.652736663818416,40.201866149902344 ], [ 33.57646942138689,40.048053741455135 ], [ 33.61725234985357,39.966354370117415 ], [ 33.616443634033374,39.91255950927757 ], [ 33.59539413452177,39.884044647217024 ], [ 33.43414688110357,39.81398773193371 ], [ 33.356254577636776,39.751121520996094 ], [ 33.31986618041992,39.64878463745117 ], [ 33.317638397216854,39.574645996094034 ], [ 33.2855339050293,39.46186065673851 ], [ 33.23331832885748,39.37669372558594 ], [ 33.28668594360357,39.33038711547863 ], [ 33.36938476562506,39.317165374755916 ], [ 33.390270233154354,39.27744674682617 ], [ 33.36560821533209,39.22562789917015 ], [ 33.41689682006836,39.16110992431652 ], [ 33.52802276611345,39.2547988891601 ], [ 33.59801483154314,39.17142486572277 ], [ 33.942905426025675,39.03599166870117 ], [ 33.8883056640625,38.954170227050895 ], [ 33.946762084960994,38.81260299682617 ], [ 33.923976898193416,38.78068542480486 ], [ 33.82899475097673,38.716121673584155 ], [ 33.68149948120117,38.711006164550895 ], [ 33.465042114257756,38.63647079467779 ], [ 33.36212921142584,38.791782379150504 ], [ 33.37403869628935,39.037906646728516 ], [ 33.18780136108427,39.276828765869084 ], [ 33.115245819091854,39.22088241577154 ], [ 33.05522155761719,39.218933105468864 ], [ 33.021648406982706,39.15932846069347 ], [ 32.96263122558622,39.126510620117244 ], [ 32.89254760742193,39.154331207275504 ], [ 32.83474731445318,39.15232849121105 ], [ 32.742153167724666,39.082061767578125 ], [ 32.70268630981451,39.03284835815441 ], [ 32.5559196472168,39.04980850219738 ], [ 32.46858978271496,38.99460601806652 ], [ 32.2944526672365,39.06810379028326 ], [ 32.129978179931925,39.0306282043457 ], [ 32.083663940429744,39.04292297363281 ], [ 31.883207321167276,39.173801422119254 ], [ 31.99277877807623,39.22740173339844 ], [ 32.011322021484546,39.38178634643572 ], [ 31.99344062805193,39.50458908081055 ], [ 31.907976150512866,39.613700866699276 ], [ 31.849052429199276,39.730388641357536 ], [ 31.847255706787166,39.76829147338873 ], [ 31.88599014282238,39.808479309082145 ], [ 31.857683181762752,39.87451553344749 ], [ 31.797164916992244,39.8831901550293 ], [ 31.695951461791992,39.98823165893566 ], [ 31.617036819458292,40.01634979248058 ], [ 31.175989151001033,40.04402542114258 ], [ 31.02343177795416,40.019157409668026 ], [ 30.94405746459978,40.02215957641607 ], [ 30.919401168823356,40.035682678222656 ], [ 30.913637161254826,40.0991401672365 ], [ 30.873971939086914,40.14034652709961 ], [ 30.955003738403605,40.22293853759777 ], [ 31.047548294067383,40.2725639343264 ], [ 31.037288665771484,40.37631988525385 ], [ 31.06073379516596,40.41575241088867 ], [ 31.14426994323742,40.39905548095703 ], [ 31.26392936706543,40.346771240234375 ], [ 31.566928863525675,40.30855178833008 ], [ 31.705093383789347,40.34394454956066 ], [ 31.79364585876482,40.33181762695318 ], [ 31.9033527374267,40.34561157226557 ], [ 32.14555358886719,40.424667358398494 ], [ 32.37283325195318,40.4155387878418 ], [ 32.47593688964861,40.5302276611331 ], [ 32.430423736572266,40.65179443359392 ], [ 32.50134658813505,40.704257965088004 ], [ 32.65491485595709,40.702560424804744 ], [ 32.955661773681925,40.59830474853527 ], [ 33.187957763672046,40.41364669799805 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-07", "NAME_1": "Antalya" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 29.63902854919462,36.12125015258795 ], [ 29.645696640014933,36.11569595336937 ], [ 29.62791633605974,36.10763931274414 ], [ 29.62874984741228,36.11125183105497 ], [ 29.63902854919462,36.12125015258795 ] ] ], [ [ [ 29.662639617920206,36.1365318298341 ], [ 29.660417556762752,36.13013839721697 ], [ 29.654581069946573,36.132915496826286 ], [ 29.65486145019537,36.13430404663103 ], [ 29.662639617920206,36.1365318298341 ] ] ], [ [ [ 29.755695343017862,36.141250610351506 ], [ 29.76625061035162,36.13152694702171 ], [ 29.738750457763615,36.12263870239269 ], [ 29.740415573120174,36.127082824707315 ], [ 29.755695343017862,36.141250610351506 ] ] ], [ [ [ 29.655416488647745,36.144306182861555 ], [ 29.656250000000284,36.14291763305681 ], [ 29.65319442749029,36.141250610351506 ], [ 29.65319442749029,36.14347076416021 ], [ 29.655416488647745,36.144306182861555 ] ] ], [ [ [ 29.624584197998104,36.153472900390796 ], [ 29.62791633605974,36.15152740478544 ], [ 29.62180519104021,36.15069580078148 ], [ 29.62208366394043,36.15236282348644 ], [ 29.624584197998104,36.153472900390796 ] ] ], [ [ [ 29.632085800170955,36.153472900390796 ], [ 29.632360458374308,36.15208435058605 ], [ 29.62874984741228,36.15152740478544 ], [ 29.62902832031267,36.15236282348644 ], [ 29.632085800170955,36.153472900390796 ] ] ], [ [ [ 29.49208259582514,36.16041564941429 ], [ 29.494581222534237,36.15708160400385 ], [ 29.496528625488338,36.159584045410156 ], [ 29.51736068725603,36.15708160400385 ], [ 29.48624992370634,36.15069580078148 ], [ 29.49208259582514,36.16041564941429 ] ] ], [ [ [ 29.626806259155558,36.16263961791998 ], [ 29.627082824706974,36.16097259521507 ], [ 29.62486076354986,36.15986251831072 ], [ 29.624027252197322,36.162082672119425 ], [ 29.626806259155558,36.16263961791998 ] ] ], [ [ [ 29.629304885864315,36.16347122192377 ], [ 29.630138397216854,36.162361145019815 ], [ 29.629583358764705,36.16041564941429 ], [ 29.62791633605974,36.161529541015625 ], [ 29.629304885864315,36.16347122192377 ] ] ], [ [ [ 29.592914581298885,36.16652679443382 ], [ 29.589860916137752,36.149860382080135 ], [ 29.60708427429205,36.144584655761946 ], [ 29.559305191040096,36.120971679687784 ], [ 29.592914581298885,36.16652679443382 ] ] ], [ [ [ 29.872915267944506,36.1690292358399 ], [ 29.873472213745117,36.167640686035384 ], [ 29.870693206787394,36.16624832153343 ], [ 29.871250152587947,36.16875076293974 ], [ 29.872915267944506,36.1690292358399 ] ] ], [ [ [ 29.836805343628214,36.17124938964844 ], [ 29.838193893432788,36.168193817138786 ], [ 29.836250305175838,36.16708374023443 ], [ 29.83402633666998,36.1690292358399 ], [ 29.836805343628214,36.17124938964844 ] ] ], [ [ [ 29.833196640014933,36.16930389404314 ], [ 29.83263969421381,36.17124938964844 ], [ 29.836250305175838,36.17208480834961 ], [ 29.835971832275504,36.17124938964844 ], [ 29.833196640014933,36.16930389404314 ] ] ], [ [ [ 29.54847145080572,36.18708419799816 ], [ 29.551807403564737,36.18402862548828 ], [ 29.551807403564737,36.18291854858393 ], [ 29.545972824096623,36.18458175659208 ], [ 29.54847145080572,36.18708419799816 ] ] ], [ [ [ 29.91263961791998,36.19152832031256 ], [ 29.912361145019645,36.188194274902344 ], [ 29.910417556762866,36.188194274902344 ], [ 29.909860610961914,36.1893043518067 ], [ 29.91263961791998,36.19152832031256 ] ] ], [ [ [ 30.407638549804744,36.19208145141596 ], [ 30.409025192261026,36.179584503174055 ], [ 30.406806945800724,36.1754150390625 ], [ 30.402639389038143,36.190971374512 ], [ 30.407638549804744,36.19208145141596 ] ] ], [ [ [ 29.91486167907715,36.19763946533209 ], [ 29.881250381469727,36.1690292358399 ], [ 29.881805419921932,36.17680740356457 ], [ 29.84069442749029,36.1690292358399 ], [ 29.91486167907715,36.19763946533209 ] ] ], [ [ [ 30.405416488647404,36.202915191650504 ], [ 30.4029159545899,36.19680404663097 ], [ 30.399305343628214,36.19763946533209 ], [ 30.401805877685717,36.2023620605471 ], [ 30.405416488647404,36.202915191650504 ] ] ], [ [ [ 29.439306259155558,36.20458221435564 ], [ 29.437084197998104,36.199306488037394 ], [ 29.43541717529314,36.19902801513683 ], [ 29.434860229492358,36.203472137451456 ], [ 29.439306259155558,36.20458221435564 ] ] ], [ [ [ 29.899305343627987,36.20652770996111 ], [ 29.903747558593807,36.20375061035185 ], [ 29.90263938903803,36.20124816894554 ], [ 29.899026870727596,36.20264053344749 ], [ 29.899305343627987,36.20652770996111 ] ] ], [ [ [ 29.90736007690424,36.21291732788103 ], [ 29.90263938903803,36.20680618286133 ], [ 29.89486122131359,36.209304809570426 ], [ 29.897361755371094,36.211528778076115 ], [ 29.90736007690424,36.21291732788103 ] ] ], [ [ [ 29.36541748046892,36.218193054199446 ], [ 29.351528167724894,36.21014022827177 ], [ 29.3462505340579,36.208751678467024 ], [ 29.347360610962085,36.214027404785384 ], [ 29.36541748046892,36.218193054199446 ] ] ], [ [ [ 29.37402725219755,36.22458267211937 ], [ 29.37347030639677,36.219860076904354 ], [ 29.367639541626033,36.220695495605696 ], [ 29.36902809143095,36.22402954101557 ], [ 29.37402725219755,36.22458267211937 ] ] ], [ [ [ 30.472917556762752,36.240695953369425 ], [ 30.4809703826906,36.232082366943644 ], [ 30.479583740234432,36.23014068603533 ], [ 30.46986389160162,36.23680496215843 ], [ 30.472917556762752,36.240695953369425 ] ] ], [ [ [ 30.1443061828615,36.26541519165062 ], [ 30.14291572570818,36.26374816894548 ], [ 30.139862060546932,36.264862060547046 ], [ 30.139862060546932,36.26541519165062 ], [ 30.1443061828615,36.26541519165062 ] ] ], [ [ [ 30.55347251892107,36.460971832275504 ], [ 30.554027557373104,36.457359313964844 ], [ 30.547082901001147,36.457359313964844 ], [ 30.550693511963175,36.460971832275504 ], [ 30.55347251892107,36.460971832275504 ] ] ], [ [ [ 31.663749694824162,36.64764022827154 ], [ 31.664306640625284,36.645973205566406 ], [ 31.66124916076666,36.64708328247093 ], [ 31.66124916076666,36.64764022827154 ], [ 31.663749694824162,36.64764022827154 ] ] ], [ [ [ 30.589305877685547,36.80430603027344 ], [ 30.5904159545899,36.803195953369084 ], [ 30.5904159545899,36.800693511963175 ], [ 30.58791732788086,36.80208206176758 ], [ 30.589305877685547,36.80430603027344 ] ] ], [ [ [ 31.449348449707315,37.344013214111385 ], [ 31.727830886840934,37.32756423950195 ], [ 31.846702575683764,37.28829956054699 ], [ 32.23294830322283,37.00030899047857 ], [ 32.29104614257841,36.85093307495117 ], [ 32.42606353759777,36.82072830200207 ], [ 32.47058486938482,36.7511253356933 ], [ 32.45649719238298,36.674057006835994 ], [ 32.50381469726568,36.561042785644645 ], [ 32.55423355102556,36.5082168579101 ], [ 32.65814208984381,36.446079254150504 ], [ 32.63582229614252,36.38359451293945 ], [ 32.64662170410156,36.28344345092768 ], [ 32.58005905151373,36.11024856567377 ], [ 32.534862518310604,36.092082977295036 ], [ 32.48791503906244,36.109027862549055 ], [ 32.295417785644815,36.2343063354495 ], [ 32.274860382080135,36.28902816772461 ], [ 32.215972900390796,36.33569335937506 ], [ 32.165973663330135,36.417083740234375 ], [ 32.02958297729498,36.53819274902344 ], [ 32.00569534301775,36.542915344238565 ], [ 32.00041580200201,36.53041839599615 ], [ 31.985696792602653,36.52736282348644 ], [ 31.96875,36.55597305297863 ], [ 31.774583816528605,36.604026794433594 ], [ 31.7459716796875,36.63819503784191 ], [ 31.672082901001033,36.64402770996088 ], [ 31.561250686645565,36.71180725097679 ], [ 31.386249542236385,36.76402664184576 ], [ 31.38708305358915,36.780693054199446 ], [ 31.329584121704386,36.80930709838884 ], [ 31.00652694702177,36.85819625854498 ], [ 30.757360458374194,36.844860076904354 ], [ 30.700138092041072,36.88458251953125 ], [ 30.622360229492358,36.850692749023665 ], [ 30.574861526489542,36.794860839843864 ], [ 30.571250915527514,36.674861907958984 ], [ 30.554582595825252,36.645973205566406 ], [ 30.55985832214367,36.61152648925787 ], [ 30.591527938843058,36.589305877685604 ], [ 30.557916641235295,36.543472290039176 ], [ 30.56541633605957,36.53263854980463 ], [ 30.541528701782397,36.522361755371094 ], [ 30.507362365722827,36.46875000000017 ], [ 30.509580612182788,36.43986129760759 ], [ 30.481252670288143,36.434028625488224 ], [ 30.491807937622127,36.42152786254877 ], [ 30.476804733276538,36.39875030517595 ], [ 30.529584884643498,36.33430480957031 ], [ 30.467081069946573,36.314304351806754 ], [ 30.46819496154791,36.29902648925781 ], [ 30.488750457763842,36.2993049621582 ], [ 30.487638473510742,36.279026031494254 ], [ 30.40569305419939,36.209304809570426 ], [ 30.408193588256893,36.27541732788097 ], [ 30.3701362609865,36.26874923706049 ], [ 30.28125190734869,36.314582824707145 ], [ 30.20041656494169,36.31541824340826 ], [ 30.14958381652849,36.30097198486351 ], [ 30.151805877685604,36.27208328247076 ], [ 30.13819313049322,36.27791595459007 ], [ 30.116529464721737,36.24736022949219 ], [ 30.06152534484869,36.25958251953148 ], [ 29.98125076293951,36.21430969238298 ], [ 29.922361373901424,36.23402786254894 ], [ 29.890972137451172,36.211528778076115 ], [ 29.886804580688533,36.193748474121264 ], [ 29.845972061157283,36.196254730224894 ], [ 29.829027175903377,36.18902969360346 ], [ 29.85041618347185,36.19319534301769 ], [ 29.800693511963175,36.1654167175293 ], [ 29.829305648803768,36.1690292358399 ], [ 29.792638778686694,36.14291763305681 ], [ 29.75986289978033,36.14014053344755 ], [ 29.78347206115734,36.15791702270536 ], [ 29.722917556762866,36.16347122192377 ], [ 29.682638168335018,36.13041687011719 ], [ 29.678195953369197,36.152915954589844 ], [ 29.654581069946573,36.147083282470874 ], [ 29.630416870117244,36.16958236694353 ], [ 29.641805648803768,36.18375015258789 ], [ 29.650417327881144,36.173473358154354 ], [ 29.64486122131342,36.196254730224894 ], [ 29.58374977111822,36.18597412109398 ], [ 29.630416870117244,36.205417633056754 ], [ 29.45875167846674,36.2212486267091 ], [ 29.44152832031267,36.21041488647461 ], [ 29.455139160156307,36.22569274902372 ], [ 29.411806106567553,36.22430419921881 ], [ 29.40430641174345,36.244304656982536 ], [ 29.417085647583292,36.26069259643583 ], [ 29.392917633056925,36.2640266418457 ], [ 29.368473052978572,36.26263809204113 ], [ 29.374862670898494,36.24874877929693 ], [ 29.353197097778605,36.229583740234375 ], [ 29.31374931335455,36.246807098388786 ], [ 29.25625228881853,36.300140380859546 ], [ 29.29875755310087,36.31876373291044 ], [ 29.32847785949724,36.40187454223644 ], [ 29.32709121704113,36.44231796264643 ], [ 29.57402038574247,36.61486434936529 ], [ 29.604988098144702,36.779148101806754 ], [ 29.6735973358156,36.87476730346697 ], [ 29.684257507324503,36.919002532958984 ], [ 29.752204895019474,36.9354133605957 ], [ 29.809103012085018,36.99095535278326 ], [ 29.848285675049,37.12187194824219 ], [ 29.920265197754077,37.18822860717785 ], [ 30.04769325256342,37.237758636474666 ], [ 30.31538772583025,37.30717086791992 ], [ 30.361600875854663,37.29970932006836 ], [ 30.39347648620611,37.24317550659191 ], [ 30.44412612915056,37.22361755371122 ], [ 30.750419616699276,37.2364311218264 ], [ 30.805181503296183,37.22457885742199 ], [ 30.881935119628906,37.36235427856451 ], [ 30.93602561950712,37.37379455566406 ], [ 30.996772766113452,37.342758178710994 ], [ 31.17972755432146,37.389701843261946 ], [ 31.238805770874023,37.42179489135759 ], [ 31.323301315307617,37.42438888549816 ], [ 31.374643325805607,37.370304107666016 ], [ 31.449348449707315,37.344013214111385 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-75", "NAME_1": "Ardahan" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 42.7628822326663,41.58436965942383 ], [ 42.83630752563505,41.58284378051758 ], [ 42.82082748413097,41.53591918945318 ], [ 42.793460845947436,41.51644134521507 ], [ 42.809623718261776,41.49266052246105 ], [ 42.85192489624052,41.47278594970709 ], [ 42.86620330810564,41.4991073608399 ], [ 42.895412445068644,41.50369644165039 ], [ 42.90453720092779,41.48081207275402 ], [ 42.96959304809582,41.45151138305687 ], [ 43.024772644043026,41.378250122070256 ], [ 43.101520538330135,41.354579925537166 ], [ 43.1296119689942,41.317916870117244 ], [ 43.2023353576663,41.30036544799805 ], [ 43.12392044067411,41.25409317016624 ], [ 43.19209671020525,41.25211334228521 ], [ 43.23177719116228,41.19274902343756 ], [ 43.226543426513956,41.17605972290045 ], [ 43.28223037719755,41.181869506835994 ], [ 43.26377487182617,41.15536499023443 ], [ 43.26222610473661,41.09014511108393 ], [ 43.22616577148443,41.03093338012718 ], [ 43.17438125610357,41.00304412841808 ], [ 43.072074890136776,40.985820770263615 ], [ 42.91522598266607,40.92750167846697 ], [ 42.87519836425798,40.85858154296881 ], [ 42.869586944580135,40.77029800415039 ], [ 42.8360137939456,40.71354293823265 ], [ 42.704601287841854,40.68149566650385 ], [ 42.61116790771479,40.64011383056635 ], [ 42.54808425903349,40.64073181152361 ], [ 42.491706848144645,40.721416473388786 ], [ 42.37902069091825,40.83445358276373 ], [ 42.332916259765796,40.924530029296875 ], [ 42.33081436157232,40.982887268066406 ], [ 42.398357391357706,41.085273742675895 ], [ 42.48964691162138,41.1560173034668 ], [ 42.557403564453296,41.185615539550724 ], [ 42.583225250244084,41.22635269165039 ], [ 42.53187179565458,41.30082321167015 ], [ 42.472846984863565,41.439739227295036 ], [ 42.520328521728686,41.44004821777338 ], [ 42.51613616943388,41.479164123535156 ], [ 42.56949996948242,41.51092529296898 ], [ 42.57986831665045,41.566108703613565 ], [ 42.60232162475603,41.583797454833984 ], [ 42.70830154418974,41.59800720214844 ], [ 42.7628822326663,41.58436965942383 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-08", "NAME_1": "Artvin" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 41.58960723876953,41.51329803466791 ], [ 41.6549530029298,41.48361206054693 ], [ 41.708831787109546,41.497718811035156 ], [ 41.7156524658206,41.47513961791998 ], [ 41.78124237060575,41.4641685485841 ], [ 41.82311248779297,41.434616088867415 ], [ 41.95518493652372,41.524646759033146 ], [ 42.04813003540045,41.49452972412115 ], [ 42.087154388427905,41.51176452636713 ], [ 42.18389511108404,41.51451492309599 ], [ 42.203910827637,41.493595123291016 ], [ 42.281776428222656,41.495216369628906 ], [ 42.3340225219726,41.47102355957037 ], [ 42.40765380859369,41.466583251953125 ], [ 42.472846984863565,41.439739227295036 ], [ 42.53187179565458,41.30082321167015 ], [ 42.583225250244084,41.22635269165039 ], [ 42.557403564453296,41.185615539550724 ], [ 42.48964691162138,41.1560173034668 ], [ 42.398357391357706,41.085273742675895 ], [ 42.33081436157232,40.982887268066406 ], [ 42.273120880127124,40.9653129577639 ], [ 42.09929656982422,40.963840484619254 ], [ 42.01268005371111,40.93065643310547 ], [ 41.973175048828125,40.85636520385742 ], [ 41.90370178222685,40.640537261963004 ], [ 41.824424743652514,40.61821365356457 ], [ 41.71423721313471,40.66050338745123 ], [ 41.64821624755865,40.661705017089844 ], [ 41.428695678710994,40.563056945800724 ], [ 41.362621307373104,40.57928466796875 ], [ 41.33960342407255,40.6501579284668 ], [ 41.39697265625017,40.74471664428722 ], [ 41.3855819702149,40.77217483520536 ], [ 41.199081420898494,40.78024673461914 ], [ 41.12230682373047,40.80845260620117 ], [ 41.33703231811529,41.031253814697266 ], [ 41.407253265380916,41.06505966186529 ], [ 41.42398071289074,41.093452453613395 ], [ 41.40925979614258,41.11717605590832 ], [ 41.36881256103521,41.11997222900402 ], [ 41.3067703247072,41.155185699462834 ], [ 41.25561904907232,41.208522796630916 ], [ 41.24785232543974,41.25560760498041 ], [ 41.21147537231445,41.30291748046869 ], [ 41.27236175537138,41.344860076904354 ], [ 41.41069412231451,41.386528015136776 ], [ 41.474029541015796,41.46152877807617 ], [ 41.52180480957037,41.482639312744254 ], [ 41.54819488525385,41.526275634765625 ], [ 41.58960723876953,41.51329803466791 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-09", "NAME_1": "Aydın" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 27.329860687256087,37.331249237060774 ], [ 27.333749771118505,37.33013916015625 ], [ 27.331527709961392,37.3218040466308 ], [ 27.325416564941463,37.32541656494146 ], [ 27.329860687256087,37.331249237060774 ] ] ], [ [ [ 27.41152763366739,37.413471221923885 ], [ 27.410692214965877,37.40902709960949 ], [ 27.407917022705533,37.40902709960949 ], [ 27.408470153808935,37.41180419921898 ], [ 27.41152763366739,37.413471221923885 ] ] ], [ [ [ 27.181804656982422,37.563472747802905 ], [ 27.18291664123535,37.56124877929716 ], [ 27.182361602783374,37.560138702392805 ], [ 27.180416107177848,37.56124877929716 ], [ 27.181804656982422,37.563472747802905 ] ] ], [ [ [ 27.140417098998967,37.61375045776373 ], [ 27.142360687256257,37.60625076293945 ], [ 27.159860610962312,37.58680725097685 ], [ 27.13902854919479,37.60736083984381 ], [ 27.140417098998967,37.61375045776373 ] ] ], [ [ [ 27.005971908569677,37.65347290039085 ], [ 27.004583358764762,37.64930725097679 ], [ 26.999860763550146,37.64930725097679 ], [ 27.001249313354492,37.65208435058594 ], [ 27.005971908569677,37.65347290039085 ] ] ], [ [ [ 27.014862060547102,37.65513992309576 ], [ 27.014028549194336,37.6523628234865 ], [ 27.009304046630973,37.65263748168968 ], [ 27.010139465332486,37.654304504394645 ], [ 27.014862060547102,37.65513992309576 ] ] ], [ [ [ 27.01847267150896,37.69263839721697 ], [ 27.0181941986084,37.69041824340826 ], [ 27.015972137451456,37.6906929016115 ], [ 27.015693664550895,37.692359924316406 ], [ 27.01847267150896,37.69263839721697 ] ] ], [ [ [ 28.815587997436808,38.03673553466808 ], [ 28.869655609131087,37.982742309570426 ], [ 28.793079376220817,37.90647888183622 ], [ 28.76422882080078,37.84311676025402 ], [ 28.849018096923828,37.763168334961165 ], [ 28.87846755981451,37.691711425781534 ], [ 28.740436553955192,37.600101470947266 ], [ 28.614013671875057,37.610515594482536 ], [ 28.573816299438533,37.591552734375114 ], [ 28.550529479980753,37.570991516113224 ], [ 28.556762695312727,37.544166564941406 ], [ 28.604200363159407,37.47769927978527 ], [ 28.461118698120117,37.497226715088004 ], [ 28.294479370117188,37.586898803710994 ], [ 28.220544815063704,37.562210083007926 ], [ 28.14990234375,37.47454833984375 ], [ 27.884967803955192,37.4570426940918 ], [ 27.698598861694563,37.49717712402338 ], [ 27.506229400634936,37.574592590332145 ], [ 27.444992065429744,37.505565643310604 ], [ 27.414861679077262,37.41570281982433 ], [ 27.368749618530614,37.39958190917969 ], [ 27.359861373901424,37.372081756591854 ], [ 27.32930564880371,37.378471374511776 ], [ 27.330415725708065,37.342639923095874 ], [ 27.28541755676315,37.35625076293951 ], [ 27.253749847412507,37.335693359375 ], [ 27.191528320312955,37.35374832153343 ], [ 27.21791648864746,37.39236068725597 ], [ 27.20902824401901,37.398750305175895 ], [ 27.23069381713873,37.40569305419922 ], [ 27.218471527099837,37.41986083984381 ], [ 27.22763824462885,37.472362518310774 ], [ 27.22513961792032,37.48791503906273 ], [ 27.181804656982422,37.47402954101568 ], [ 27.202638626099088,37.489860534668026 ], [ 27.200971603393782,37.516250610351506 ], [ 27.194583892822266,37.53263854980497 ], [ 27.18986129760765,37.49124908447294 ], [ 27.18013954162643,37.48291778564453 ], [ 27.191528320312955,37.545696258545036 ], [ 27.16791725158697,37.536251068115234 ], [ 27.159585952758732,37.58541488647478 ], [ 27.17541885376022,37.56180572509777 ], [ 27.170974731445426,37.55902862548845 ], [ 27.171249389648835,37.54930496215832 ], [ 27.174583435058707,37.54763793945335 ], [ 27.217361450195483,37.59069442749035 ], [ 27.124305725097656,37.630973815918026 ], [ 27.002916336059627,37.6590270996096 ], [ 27.031248092651424,37.69013977050787 ], [ 27.099306106567496,37.680416107177734 ], [ 27.229305267333984,37.72069549560558 ], [ 27.2665252685548,37.78569412231445 ], [ 27.267639160156534,37.815692901611385 ], [ 27.235416412353516,37.83902740478533 ], [ 27.241249084472884,37.86013793945324 ], [ 27.263193130493164,37.86597061157221 ], [ 27.26513862609886,37.891803741455135 ], [ 27.35456848144537,37.891254425049055 ], [ 27.441749572753963,37.91611480712896 ], [ 27.494209289550838,37.943946838378906 ], [ 27.523767471313477,37.98232269287132 ], [ 27.72010993957548,37.985515594482536 ], [ 27.77575492858881,37.972328186035156 ], [ 27.923608779907283,37.99508666992193 ], [ 27.938676834106502,38.018360137939396 ], [ 27.95366859436035,38.006706237793026 ], [ 28.071899414062727,38.02942657470726 ], [ 28.249021530151367,38.01900100708008 ], [ 28.57966613769537,38.110542297363395 ], [ 28.696769714355526,38.1111297607423 ], [ 28.71974372863798,38.09927368164074 ], [ 28.71170043945341,38.077957153320426 ], [ 28.815587997436808,38.03673553466808 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-10", "NAME_1": "Balıkesir" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 26.59874916076666,39.30347061157232 ], [ 26.602916717529297,39.28319549560558 ], [ 26.577360153198185,39.27708435058605 ], [ 26.590972900390966,39.30180740356457 ], [ 26.59874916076666,39.30347061157232 ] ] ], [ [ [ 26.529584884643782,39.32097244262718 ], [ 26.52736282348667,39.3204154968264 ], [ 26.52486038208002,39.32125091552757 ], [ 26.53069686889654,39.322082519531534 ], [ 26.529584884643782,39.32097244262718 ] ] ], [ [ [ 26.65930557250988,39.324584960937614 ], [ 26.65930557250988,39.32291793823248 ], [ 26.656248092651424,39.32374954223627 ], [ 26.656248092651424,39.324584960937614 ], [ 26.65930557250988,39.324584960937614 ] ] ], [ [ [ 26.539304733276765,39.33180618286133 ], [ 26.543750762939396,39.325416564941406 ], [ 26.53069686889654,39.324584960937614 ], [ 26.531806945800895,39.33180618286133 ], [ 26.539304733276765,39.33180618286133 ] ] ], [ [ [ 26.606527328491325,39.34291839599604 ], [ 26.612638473510856,39.33319473266624 ], [ 26.5951385498048,39.336250305175724 ], [ 26.6020832061771,39.342639923095646 ], [ 26.606527328491325,39.34291839599604 ] ] ], [ [ [ 26.577638626098746,39.344860076904354 ], [ 26.579862594604833,39.339305877685774 ], [ 26.572917938232536,39.33319473266624 ], [ 26.57430648803711,39.34152603149414 ], [ 26.577638626098746,39.344860076904354 ] ] ], [ [ [ 26.695138931274528,39.34958267211937 ], [ 26.696805953979492,39.343193054199446 ], [ 26.683471679687443,39.344860076904354 ], [ 26.683471679687443,39.34680557250988 ], [ 26.695138931274528,39.34958267211937 ] ] ], [ [ [ 26.5951385498048,39.35041809082031 ], [ 26.601526260376147,39.34430694580095 ], [ 26.585695266723803,39.34291839599604 ], [ 26.585695266723803,39.348751068115405 ], [ 26.5951385498048,39.35041809082031 ] ] ], [ [ [ 26.672359466552734,39.354583740234375 ], [ 26.671527862548942,39.35235977172846 ], [ 26.664861679077603,39.35208511352562 ], [ 26.66625022888178,39.35347366333019 ], [ 26.672359466552734,39.354583740234375 ] ] ], [ [ [ 26.697082519531648,39.37236022949219 ], [ 26.698749542236385,39.369304656982536 ], [ 26.695693969726904,39.36736297607422 ], [ 26.694028854370174,39.371528625488224 ], [ 26.697082519531648,39.37236022949219 ] ] ], [ [ [ 26.727081298828182,39.37930679321306 ], [ 26.727363586425952,39.37680435180664 ], [ 26.724027633667106,39.3770828247072 ], [ 26.724306106567496,39.378471374511946 ], [ 26.727081298828182,39.37930679321306 ] ] ], [ [ [ 26.768474578857422,39.3795814514163 ], [ 26.768474578857422,39.374862670898494 ], [ 26.759860992431584,39.37263870239258 ], [ 26.761249542236328,39.37597274780285 ], [ 26.768474578857422,39.3795814514163 ] ] ], [ [ [ 26.707916259765625,39.38263702392578 ], [ 26.7095832824711,39.37374877929693 ], [ 26.703195571899414,39.37402725219749 ], [ 26.702917098999023,39.37985992431646 ], [ 26.707916259765625,39.38263702392578 ] ] ], [ [ [ 26.572360992431584,39.38513946533203 ], [ 26.575416564941463,39.380973815918196 ], [ 26.5695858001709,39.378192901611555 ], [ 26.56847381591831,39.38402938842768 ], [ 26.572360992431584,39.38513946533203 ] ] ], [ [ [ 26.614583969116552,39.395973205566406 ], [ 26.670139312744197,39.389862060547046 ], [ 26.623195648193416,39.37014007568388 ], [ 26.69069480896013,39.33347320556646 ], [ 26.622638702392635,39.32652664184593 ], [ 26.60791587829607,39.35180664062523 ], [ 26.623472213745572,39.356529235839844 ], [ 26.617359161377067,39.380416870117415 ], [ 26.59874916076666,39.38569259643583 ], [ 26.614583969116552,39.395973205566406 ] ] ], [ [ [ 26.59013938903803,39.39736175537132 ], [ 26.603195190429858,39.394859313964844 ], [ 26.588193893433072,39.36763763427757 ], [ 26.575695037842024,39.389862060547046 ], [ 26.59013938903803,39.39736175537132 ] ] ], [ [ [ 26.71236038208002,39.409862518310604 ], [ 26.711526870727653,39.40625 ], [ 26.705972671509244,39.40569305419939 ], [ 26.706806182861442,39.40819549560547 ], [ 26.71236038208002,39.409862518310604 ] ] ], [ [ [ 27.79013633728067,40.37819290161133 ], [ 27.78791427612299,40.3737487792971 ], [ 27.781805038452603,40.37291717529297 ], [ 27.781251907348633,40.37569427490263 ], [ 27.79013633728067,40.37819290161133 ] ] ], [ [ [ 28.09180641174322,40.45458221435547 ], [ 28.094028472900504,40.44958496093767 ], [ 28.085971832275447,40.45208358764677 ], [ 28.09041595459007,40.45541763305664 ], [ 28.09180641174322,40.45458221435547 ] ] ], [ [ [ 28.066804885864656,40.46291732788109 ], [ 28.074861526489315,40.46097183227539 ], [ 28.080415725708292,40.45180511474638 ], [ 28.062915802002237,40.45763778686535 ], [ 28.066804885864656,40.46291732788109 ] ] ], [ [ [ 27.66319465637207,40.46680450439476 ], [ 27.667085647583463,40.4462509155274 ], [ 27.65569686889677,40.445415496826456 ], [ 27.650693893432617,40.45291519165056 ], [ 27.66319465637207,40.46680450439476 ] ] ], [ [ [ 28.09874725341814,40.46930694580101 ], [ 28.105417251587028,40.46875000000023 ], [ 28.105417251587028,40.467918395996094 ], [ 28.098194122314908,40.46597290039057 ], [ 28.09874725341814,40.46930694580101 ] ] ], [ [ [ 27.565971374511832,40.46958160400402 ], [ 27.5668048858642,40.46736145019531 ], [ 27.56430625915567,40.465415954590014 ], [ 27.561807632446573,40.468471527099666 ], [ 27.565971374511832,40.46958160400402 ] ] ], [ [ [ 27.62125015258789,40.51124954223661 ], [ 27.623750686645565,40.497638702392805 ], [ 27.651527404785554,40.49319458007841 ], [ 27.632360458374023,40.47208404541033 ], [ 27.649583816528263,40.45208358764677 ], [ 27.577917098999478,40.462638854980696 ], [ 27.582639694213924,40.482639312744425 ], [ 27.60791587829584,40.48152923584007 ], [ 27.599304199218807,40.508750915527344 ], [ 27.62125015258789,40.51124954223661 ] ] ], [ [ [ 27.709583282470703,40.5259704589846 ], [ 27.710418701171875,40.52513885498047 ], [ 27.710136413574673,40.52265167236328 ], [ 27.708196640014933,40.52458190917969 ], [ 27.709583282470703,40.5259704589846 ] ] ], [ [ [ 27.583471298217887,40.52819442749052 ], [ 27.58625030517578,40.50569534301769 ], [ 27.580415725708008,40.494583129882756 ], [ 27.572360992431754,40.498195648193416 ], [ 27.583471298217887,40.52819442749052 ] ] ], [ [ [ 27.7537517547608,40.52847290039091 ], [ 27.77736091613781,40.52624893188499 ], [ 27.784860610961914,40.50597381591825 ], [ 27.794305801392056,40.51930618286133 ], [ 27.870695114136197,40.51708221435541 ], [ 28.031805038452546,40.48125076293951 ], [ 28.00597190856928,40.43986129760748 ], [ 27.89680480957071,40.39041519165062 ], [ 27.954584121704443,40.35291671752941 ], [ 28.060693740845124,40.38236236572271 ], [ 28.215667724609546,40.39819335937506 ], [ 28.139453887939794,40.31338882446312 ], [ 28.1234397888187,40.209861755371264 ], [ 28.123510360717773,40.11376953125006 ], [ 28.138450622558594,40.078830718994254 ], [ 28.21094131469738,40.03118896484398 ], [ 28.30317497253418,39.869155883789006 ], [ 28.33790016174345,39.86425018310564 ], [ 28.52121162414562,39.76625823974632 ], [ 28.67019081115734,39.755977630615234 ], [ 28.787443161010913,39.624740600586165 ], [ 28.909473419189453,39.62299346923834 ], [ 28.947071075439453,39.605796813964844 ], [ 28.96330642700218,39.58925628662132 ], [ 28.934938430786246,39.550872802734546 ], [ 28.940580368041935,39.519817352295036 ], [ 28.883300781250227,39.366607666015625 ], [ 28.793338775634766,39.283752441406364 ], [ 28.661375045776367,39.2337074279788 ], [ 28.66218757629406,39.163825988769474 ], [ 28.60289764404297,39.1800346374514 ], [ 28.466716766357536,39.12395095825201 ], [ 28.166194915771484,39.042678833007926 ], [ 28.112621307373274,39.062858581543026 ], [ 28.057016372680835,39.172363281250114 ], [ 27.99714279174816,39.22052001953142 ], [ 27.895751953125114,39.2360725402832 ], [ 27.8823184967041,39.26954650878906 ], [ 27.917137145996037,39.329010009765625 ], [ 27.896583557128906,39.35721206665045 ], [ 27.881540298462085,39.345581054687614 ], [ 27.79146385192871,39.35728836059582 ], [ 27.679256439208984,39.34687423706055 ], [ 27.612707138061694,39.36009979248047 ], [ 27.516485214233455,39.41384506225586 ], [ 27.407686233520792,39.38151550292969 ], [ 27.176755905151424,39.42146682739258 ], [ 26.957500457763672,39.259422302246094 ], [ 26.78491020202671,39.1717643737793 ], [ 26.739028930664062,39.20041656494152 ], [ 26.71819686889654,39.25902938842779 ], [ 26.60958480834978,39.272361755371264 ], [ 26.625415802002124,39.31152725219755 ], [ 26.65041732788086,39.32347106933588 ], [ 26.65680694580078,39.30374908447271 ], [ 26.630418777465877,39.29708480834961 ], [ 26.670972824097134,39.27902603149437 ], [ 26.663749694824276,39.30513763427763 ], [ 26.689029693603572,39.313194274902344 ], [ 26.70180320739786,39.34069442749035 ], [ 26.80569458007824,39.39208221435575 ], [ 26.79708480834961,39.43236160278343 ], [ 26.854860305786133,39.439861297607706 ], [ 26.858472824096964,39.477359771728516 ], [ 26.931249618530273,39.48541641235374 ], [ 26.95347023010254,39.55180740356451 ], [ 26.922639846802042,39.5837516784668 ], [ 26.88125038147001,39.58514022827154 ], [ 26.838472366333235,39.5579185485841 ], [ 26.774583816528548,39.571250915527344 ], [ 26.662944793701286,39.55847549438482 ], [ 26.6665878295899,39.650680541992415 ], [ 26.688920974731445,39.697902679443416 ], [ 26.738092422485522,39.718643188476676 ], [ 26.845289230346737,39.71005630493164 ], [ 26.980264663696403,39.78216171264654 ], [ 27.091777801513672,39.81017303466808 ], [ 27.15715980529785,39.81030654907238 ], [ 27.264280319214095,39.7708168029788 ], [ 27.423446655273494,39.829936981201286 ], [ 27.472572326660156,39.88761520385759 ], [ 27.492630004882812,39.93980789184599 ], [ 27.487668991088924,39.96401596069347 ], [ 27.450334548950195,39.98967361450195 ], [ 27.506595611572436,40.12036132812494 ], [ 27.472787857055835,40.20105743408203 ], [ 27.575317382812614,40.27116012573242 ], [ 27.587085723877124,40.31819534301769 ], [ 27.632917404174975,40.32680511474615 ], [ 27.659584045410213,40.306804656982365 ], [ 27.760972976684513,40.30625152587896 ], [ 27.87986183166504,40.374305725097884 ], [ 27.824306488037394,40.3995819091798 ], [ 27.795139312744254,40.38402938842802 ], [ 27.78319358825678,40.40902709960943 ], [ 27.74541664123575,40.430416107177905 ], [ 27.75180625915567,40.44930648803711 ], [ 27.686527252197664,40.47236251831049 ], [ 27.685140609741325,40.503192901611385 ], [ 27.7537517547608,40.52847290039091 ] ] ], [ [ [ 27.517639160156477,40.53791809082031 ], [ 27.552917480469148,40.5212516784668 ], [ 27.523471832275447,40.500415802002124 ], [ 27.537082672119254,40.488193511962834 ], [ 27.489582061767692,40.467918395996094 ], [ 27.47819328308117,40.4940261840822 ], [ 27.517639160156477,40.53791809082031 ] ] ], [ [ [ 27.501806259155728,40.553749084472656 ], [ 27.50652694702194,40.547637939453125 ], [ 27.465139389038313,40.53902816772484 ], [ 27.46708488464361,40.547637939453125 ], [ 27.501806259155728,40.553749084472656 ] ] ], [ [ [ 27.759582519531364,40.63347244262724 ], [ 27.7587509155274,40.63124847412132 ], [ 27.756526947021882,40.63180541992193 ], [ 27.756526947021882,40.632915496826286 ], [ 27.759582519531364,40.63347244262724 ] ] ], [ [ [ 27.48541641235346,40.647083282470874 ], [ 27.489860534668082,40.64625167846708 ], [ 27.488193511962947,40.63652801513672 ], [ 27.479585647583463,40.64152908325207 ], [ 27.48541641235346,40.647083282470874 ] ] ], [ [ [ 27.679027557373388,40.664028167724894 ], [ 27.68041419982916,40.66236114501959 ], [ 27.676805496216275,40.65847396850597 ], [ 27.676527023315884,40.661251068115234 ], [ 27.679027557373388,40.664028167724894 ] ] ], [ [ [ 27.635416030884244,40.668193817138956 ], [ 27.744028091430835,40.632637023925895 ], [ 27.608749389648608,40.57430648803734 ], [ 27.529306411743562,40.59680557250982 ], [ 27.53263854980503,40.64680480957048 ], [ 27.635416030884244,40.668193817138956 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-74", "NAME_1": "Bartın" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 32.38930511474604,41.755416870117415 ], [ 32.38986206054716,41.751804351806584 ], [ 32.38874816894548,41.75125122070335 ], [ 32.38708496093756,41.75374984741211 ], [ 32.38930511474604,41.755416870117415 ] ] ], [ [ [ 32.6841583251956,41.83443832397461 ], [ 32.761165618896655,41.7322998046875 ], [ 32.827293395996094,41.595649719238395 ], [ 32.92557525634771,41.553955078125 ], [ 32.8231658935548,41.51309204101574 ], [ 32.79067993164068,41.525810241699276 ], [ 32.7556343078615,41.489173889160384 ], [ 32.69793319702154,41.46401596069336 ], [ 32.6317977905274,41.35578155517578 ], [ 32.42853927612322,41.254291534424055 ], [ 32.35403823852545,41.23849105834972 ], [ 32.30512619018572,41.306194305420036 ], [ 32.02547073364252,41.548965454101506 ], [ 32.028751373291186,41.5745849609375 ], [ 32.06208419799833,41.570137023925724 ], [ 32.052082061767635,41.58152770996105 ], [ 32.149307250976676,41.60680389404314 ], [ 32.1798629760745,41.632083892822266 ], [ 32.17347335815458,41.640693664550895 ], [ 32.22874832153332,41.670696258545036 ], [ 32.224582672119425,41.68569564819359 ], [ 32.28319549560558,41.719581604004134 ], [ 32.34041595458996,41.722915649414006 ], [ 32.38208389282232,41.75374984741211 ], [ 32.415416717529354,41.73958206176786 ], [ 32.49874877929716,41.80152893066406 ], [ 32.57291793823259,41.810974121093864 ], [ 32.58013916015631,41.82736206054693 ], [ 32.6841583251956,41.83443832397461 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-72", "NAME_1": "Batman" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 41.58572387695324,38.54240417480463 ], [ 41.63222503662115,38.50775527954113 ], [ 41.66092300415045,38.426647186279524 ], [ 41.680023193359546,38.34867858886719 ], [ 41.67819213867193,38.20679855346691 ], [ 41.6461448669433,38.102352142333984 ], [ 41.60668945312506,38.038478851318416 ], [ 41.48127746582048,38.02124786376959 ], [ 41.480823516845874,37.986244201660156 ], [ 41.432540893554744,37.95641326904308 ], [ 41.4121208190918,37.91577911376959 ], [ 41.51866149902361,37.85847473144531 ], [ 41.73163986206072,37.85505676269531 ], [ 41.73792648315447,37.8255729675293 ], [ 41.70092010498058,37.77768707275396 ], [ 41.754611968994254,37.74295043945335 ], [ 41.838973999023494,37.76421737670921 ], [ 41.8682403564456,37.75908279418951 ], [ 41.8738899230957,37.74024581909191 ], [ 41.686473846435604,37.67586898803711 ], [ 41.573192596435604,37.57748413085932 ], [ 41.4461212158206,37.55442810058594 ], [ 41.18900680542009,37.556800842285384 ], [ 41.05128097534197,37.71851730346691 ], [ 41.051792144775675,37.73957443237305 ], [ 41.09960174560547,37.76951217651367 ], [ 41.11236953735357,37.80470275878906 ], [ 41.05167770385759,37.825115203857536 ], [ 41.033123016357365,37.85990142822277 ], [ 41.105842590332315,37.91629791259771 ], [ 41.21151351928728,38.105602264404354 ], [ 41.22935867309599,38.17604446411144 ], [ 41.21520614624029,38.21622085571289 ], [ 41.21492385864275,38.333042144775504 ], [ 41.232952117920036,38.39165115356445 ], [ 41.261119842529354,38.43730926513666 ], [ 41.35118865966797,38.471626281738565 ], [ 41.42137908935547,38.47715377807623 ], [ 41.434333801269474,38.49729156494146 ], [ 41.416931152344034,38.522247314453125 ], [ 41.43031311035185,38.53088378906273 ], [ 41.58572387695324,38.54240417480463 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-69", "NAME_1": "Bayburt" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 40.50198745727539,40.524814605712834 ], [ 40.52688598632818,40.48198318481451 ], [ 40.562980651855526,40.30159378051769 ], [ 40.631130218505916,40.24741744995123 ], [ 40.78762054443365,40.227943420410156 ], [ 40.79770660400408,40.20346832275402 ], [ 40.764133453369254,40.15393447875999 ], [ 40.64613723754883,40.11261749267584 ], [ 40.4773902893067,40.02457046508789 ], [ 40.37506103515631,40.02386474609375 ], [ 40.11088943481474,40.070037841796875 ], [ 39.879669189453125,40.00830078125023 ], [ 39.78475570678705,39.931087493896484 ], [ 39.70485687255865,39.975437164306754 ], [ 39.69057846069353,40.01388931274414 ], [ 39.74072265625006,40.07666397094732 ], [ 39.801929473876896,40.115879058837834 ], [ 39.817634582519815,40.15013122558594 ], [ 39.82343292236345,40.249820709228686 ], [ 39.85456085205084,40.3255500793457 ], [ 39.88367080688482,40.3472251892091 ], [ 39.988433837890625,40.36897277832037 ], [ 40.04511260986334,40.42015075683605 ], [ 40.09298324584955,40.512348175048885 ], [ 40.20972061157221,40.50019073486334 ], [ 40.48347854614275,40.535343170166016 ], [ 40.50198745727539,40.524814605712834 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-11", "NAME_1": "Bilecik" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 30.137876510620288,40.368118286132756 ], [ 30.30372619628912,40.402862548828125 ], [ 30.465574264526424,40.38898468017584 ], [ 30.62383460998541,40.335178375244254 ], [ 30.726753234863338,40.171913146972656 ], [ 30.571363449096623,40.14687728881859 ], [ 30.523212432861612,40.00673294067394 ], [ 30.464849472045955,39.95089340209955 ], [ 30.35621070861822,39.9370231628418 ], [ 30.248657226562784,39.85490798950207 ], [ 30.12443351745634,39.86803054809593 ], [ 30.058496475219783,39.84362411499029 ], [ 29.999553680419922,39.77170181274437 ], [ 30.002939224243164,39.72935867309593 ], [ 30.044765472412166,39.693233489990234 ], [ 29.952077865600756,39.68215942382835 ], [ 29.722852706909237,39.74099349975609 ], [ 29.68674087524431,39.82540512084961 ], [ 29.69292449951189,39.87970352172863 ], [ 29.67700767517084,39.90554428100603 ], [ 29.77089500427263,39.9065055847168 ], [ 29.78856849670416,39.93006134033203 ], [ 29.789287567138956,39.967704772949276 ], [ 29.72355651855497,40.00169372558605 ], [ 29.68801116943365,40.06284332275396 ], [ 29.73137855529791,40.190849304199446 ], [ 29.799266815185717,40.23756027221674 ], [ 29.83152389526373,40.285297393799 ], [ 29.805931091308707,40.34535980224615 ], [ 29.80528068542486,40.41008758544916 ], [ 29.838851928711108,40.472503662109546 ], [ 29.891553878784464,40.5150718688966 ], [ 29.941497802734432,40.53152847290039 ], [ 29.981578826904297,40.46556854248075 ], [ 30.137876510620288,40.368118286132756 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-12", "NAME_1": "Bingöl" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 40.94224929809576,39.514541625976676 ], [ 41.02952194213884,39.46599578857439 ], [ 41.1310348510745,39.45877838134771 ], [ 41.2186927795413,39.35533905029297 ], [ 41.18736267089861,39.332496643066406 ], [ 41.171733856201286,39.28934097290062 ], [ 41.204399108886776,39.16355514526367 ], [ 41.23756408691412,39.15412902832031 ], [ 41.274139404297046,39.11057281494152 ], [ 41.274494171142635,39.02955627441406 ], [ 41.15594863891596,38.90488433837896 ], [ 41.26630401611328,38.72560119628912 ], [ 40.91010284423834,38.59239578247093 ], [ 40.52542114257824,38.61225128173828 ], [ 40.49867248535162,38.59278869628906 ], [ 40.47573471069347,38.51073837280279 ], [ 40.44480895996094,38.478462219238395 ], [ 40.29214859008806,38.47479248046898 ], [ 40.297912597656534,38.549640655517635 ], [ 40.23947143554693,38.60807037353533 ], [ 40.24125289916992,38.645938873291016 ], [ 40.28793334960943,38.726707458496264 ], [ 40.35682296752947,38.725006103515625 ], [ 40.386886596679744,38.8065643310548 ], [ 40.35352325439459,38.86205291748058 ], [ 40.320285797119254,38.86981201171898 ], [ 40.286796569824276,38.94425582885742 ], [ 40.284648895263956,39.041481018066634 ], [ 40.39783859252947,39.15583801269531 ], [ 40.38748931884771,39.195796966552734 ], [ 40.354022979736385,39.22611618041992 ], [ 40.0097732543947,39.089889526367244 ], [ 40.04188919067383,39.13946533203125 ], [ 40.03049850463873,39.19946670532232 ], [ 40.064739227295206,39.26797866821312 ], [ 40.098674774170206,39.31428146362305 ], [ 40.20206451416021,39.28889083862305 ], [ 40.390830993652344,39.382858276367244 ], [ 40.33533477783203,39.427463531494254 ], [ 40.51652145385748,39.5039901733399 ], [ 40.54322814941406,39.54778289794922 ], [ 40.68346405029314,39.51169967651373 ], [ 40.862430572509766,39.565601348876896 ], [ 40.90938568115263,39.550853729248104 ], [ 40.94224929809576,39.514541625976676 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-13", "NAME_1": "Bitlis" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 43.13637161254883,38.92792129516613 ], [ 43.197910308838004,38.8801727294923 ], [ 43.196823120117244,38.828151702880916 ], [ 43.178493499756144,38.79753494262695 ], [ 43.056091308593864,38.72330474853521 ], [ 42.964450836181754,38.61788177490246 ], [ 42.9462432861331,38.614349365234375 ], [ 42.8891716003418,38.52491760253906 ], [ 42.72961044311529,38.45822143554693 ], [ 42.68778610229509,38.42295074462902 ], [ 42.739238739013615,38.277294158935774 ], [ 42.7185440063476,38.20607376098633 ], [ 42.75567626953131,38.175254821777344 ], [ 42.79895782470709,38.16839981079107 ], [ 42.777313232421875,38.127155303955135 ], [ 42.8357009887697,38.06550598144537 ], [ 42.73911666870117,38.013481140137 ], [ 42.49808883666998,38.109996795654354 ], [ 42.371692657470646,38.13842010498058 ], [ 42.298156738281534,38.18778610229509 ], [ 42.20790863037138,38.21693801879883 ], [ 42.095233917236385,38.20076751708996 ], [ 42.025947570801065,38.12945938110357 ], [ 41.97900390625006,38.15625381469738 ], [ 41.91657638549833,38.148315429687614 ], [ 41.67486572265625,38.19519042968773 ], [ 41.67907714843767,38.35854721069359 ], [ 41.63345336914057,38.50515365600586 ], [ 41.59266662597673,38.540195465088175 ], [ 41.52218246459961,38.541912078857706 ], [ 41.57016754150408,38.58500671386719 ], [ 41.62169647216797,38.59952545166021 ], [ 41.863296508789006,38.590469360351506 ], [ 41.940517425537166,38.61808013916027 ], [ 42.056205749511776,38.69475173950195 ], [ 42.054039001464844,38.728683471679744 ], [ 41.998836517334155,38.78861618041992 ], [ 42.002147674560604,38.814769744873104 ], [ 42.136615753173885,38.823856353759766 ], [ 42.13997268676758,38.87031555175781 ], [ 42.310134887695426,38.93563461303711 ], [ 42.4895858764649,38.9266815185548 ], [ 42.56119918823248,38.94335556030279 ], [ 42.68435287475603,38.926906585693416 ], [ 42.76899337768549,38.94040298461914 ], [ 42.749843597412166,39.03714752197277 ], [ 42.827857971191406,39.06509017944347 ], [ 43.02248382568365,39.09549331665056 ], [ 43.00571441650396,38.98618316650396 ], [ 43.13637161254883,38.92792129516613 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-14", "NAME_1": "Bolu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 31.912191390991495,41.01945114135742 ], [ 32.28520965576189,41.00830078125006 ], [ 32.28196716308611,40.94109725952171 ], [ 32.50800323486328,40.862258911132926 ], [ 32.540092468261776,40.80879592895536 ], [ 32.521430969238395,40.72862625122093 ], [ 32.430423736572266,40.65179443359392 ], [ 32.47593688964861,40.5302276611331 ], [ 32.38796997070307,40.423839569091854 ], [ 32.32307052612322,40.41284942626976 ], [ 32.14555358886719,40.424667358398494 ], [ 31.9033527374267,40.34561157226557 ], [ 31.79364585876482,40.33181762695318 ], [ 31.705093383789347,40.34394454956066 ], [ 31.566928863525675,40.30855178833008 ], [ 31.26392936706543,40.346771240234375 ], [ 31.14426994323742,40.39905548095703 ], [ 31.06073379516596,40.41575241088867 ], [ 31.037288665771484,40.37631988525385 ], [ 31.047548294067383,40.2725639343264 ], [ 30.955003738403605,40.22293853759777 ], [ 30.873971939086914,40.14034652709961 ], [ 30.726753234863338,40.171913146972656 ], [ 30.636177062988338,40.30845642089844 ], [ 30.62383460998541,40.335178375244254 ], [ 30.6464271545413,40.38548660278343 ], [ 30.59591865539568,40.44455718994152 ], [ 30.676174163818644,40.51831817626959 ], [ 30.82930183410673,40.51985549926752 ], [ 30.9108257293704,40.5385627746582 ], [ 30.946756362915096,40.57278442382807 ], [ 30.954557418823242,40.682250976562614 ], [ 31.026567459106445,40.65954208374029 ], [ 31.190750122070483,40.68179702758789 ], [ 31.264896392822322,40.646827697753906 ], [ 31.36094474792492,40.66146087646496 ], [ 31.42705917358404,40.70133590698265 ], [ 31.43151664733898,40.805057525634766 ], [ 31.469253540039233,40.87095642089844 ], [ 31.60422897338873,40.8813362121582 ], [ 31.690898895263956,40.91467666625971 ], [ 31.73953056335455,40.94845199584961 ], [ 31.757904052734432,40.987693786621094 ], [ 31.75791931152355,41.01557540893549 ], [ 31.736297607421932,41.042720794677734 ], [ 31.912191390991495,41.01945114135742 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-15", "NAME_1": "Burdur" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 30.54076385498047,37.703563690185774 ], [ 30.651264190674,37.700595855712834 ], [ 30.70260238647461,37.6779670715332 ], [ 30.76529884338396,37.52559661865229 ], [ 30.907865524292163,37.398216247558594 ], [ 30.915895462036417,37.37248611450207 ], [ 30.870082855224666,37.35358428955078 ], [ 30.805181503296183,37.22457885742199 ], [ 30.750419616699276,37.23643112182623 ], [ 30.44412612915056,37.22361755371105 ], [ 30.39347648620611,37.24317550659191 ], [ 30.356336593627987,37.302886962890625 ], [ 30.288280487060547,37.305519104003906 ], [ 30.04769325256342,37.237758636474666 ], [ 29.877441406250057,37.16139221191429 ], [ 29.84602165222185,37.11684417724621 ], [ 29.8244247436524,37.01425552368187 ], [ 29.737199783325195,36.92720031738287 ], [ 29.684257507324503,36.919002532958984 ], [ 29.62462997436529,36.99750900268566 ], [ 29.546728134155217,37.027606964111555 ], [ 29.511768341064737,37.024211883545036 ], [ 29.44611740112316,36.96438980102539 ], [ 29.394460678100643,36.952030181884766 ], [ 29.4083900451663,37.01031112670927 ], [ 29.387758255004826,37.076091766357536 ], [ 29.395507812500284,37.15217590332031 ], [ 29.44138145446783,37.23631668090832 ], [ 29.523260116577433,37.31515121459961 ], [ 29.579244613647518,37.41019439697277 ], [ 29.57953453063959,37.43535614013683 ], [ 29.530990600586108,37.46260452270508 ], [ 29.526779174804858,37.5913848876956 ], [ 29.865327835083292,37.77055358886736 ], [ 29.994150161743335,37.78136062622076 ], [ 30.03392410278326,37.71933364868164 ], [ 30.08116722106928,37.703464508056584 ], [ 30.32950592041027,37.83989715576183 ], [ 30.371025085449276,37.83028030395536 ], [ 30.438201904296932,37.754367828369425 ], [ 30.54076385498047,37.703563690185774 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-16", "NAME_1": "Bursa" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 28.539026260375977,40.56708145141607 ], [ 28.555141448974837,40.564861297607365 ], [ 28.53624916076666,40.54875183105463 ], [ 28.5454158782959,40.5259704589846 ], [ 28.524583816528377,40.51124954223661 ], [ 28.517915725708065,40.565139770507926 ], [ 28.539026260375977,40.56708145141607 ] ] ], [ [ [ 29.928827285766886,40.558509826660156 ], [ 29.941497802734432,40.53152847290039 ], [ 29.856920242309855,40.48979568481451 ], [ 29.809238433837947,40.42584228515631 ], [ 29.805931091308707,40.34535980224615 ], [ 29.833244323730753,40.29028701782232 ], [ 29.799266815185717,40.23756027221674 ], [ 29.73137855529791,40.190849304199446 ], [ 29.68801116943365,40.06284332275396 ], [ 29.72355651855497,40.00169372558605 ], [ 29.789287567138956,39.967704772949276 ], [ 29.782350540161417,39.91889572143572 ], [ 29.760942459106502,39.9033012390139 ], [ 29.615415573120117,39.891330718994254 ], [ 29.53948783874506,39.89305877685547 ], [ 29.45207023620617,39.92456817626976 ], [ 29.411384582519702,39.909908294677734 ], [ 29.336360931396655,39.77615356445318 ], [ 29.267078399658203,39.692760467529354 ], [ 29.247165679931697,39.5811576843264 ], [ 29.223285675048885,39.55531311035179 ], [ 29.092315673828125,39.543609619140625 ], [ 28.99761009216303,39.566928863525504 ], [ 28.909473419189453,39.62299346923834 ], [ 28.807842254638672,39.6169128417971 ], [ 28.77256011962902,39.63481521606457 ], [ 28.67019081115734,39.755977630615234 ], [ 28.52121162414562,39.76625823974632 ], [ 28.33790016174345,39.86425018310564 ], [ 28.30317497253418,39.869155883789006 ], [ 28.21094131469738,40.03118896484398 ], [ 28.138450622558594,40.078830718994254 ], [ 28.123510360717773,40.11376953125006 ], [ 28.14102172851591,40.319377899170036 ], [ 28.215667724609546,40.39819335937506 ], [ 28.510417938232365,40.395137786865234 ], [ 28.490692138672216,40.37958145141624 ], [ 28.482360839844148,40.36319351196295 ], [ 28.51597023010254,40.394859313964844 ], [ 28.650970458984602,40.35930633544933 ], [ 28.796806335449162,40.39430618286144 ], [ 28.871250152588175,40.38486099243181 ], [ 28.92597198486328,40.35597229003906 ], [ 28.98013877868675,40.35597229003906 ], [ 29.054027557373217,40.36319351196295 ], [ 29.085971832275447,40.41764068603521 ], [ 29.154306411743335,40.42541503906256 ], [ 29.09180641174339,40.4745826721192 ], [ 29.03236198425293,40.478588104248104 ], [ 29.010364532470874,40.497295379638786 ], [ 29.045017242431754,40.559192657470874 ], [ 29.26760673522955,40.55602264404297 ], [ 29.362733840942667,40.580024719238224 ], [ 29.45255661010748,40.555171966552734 ], [ 29.564767837524414,40.55538940429699 ], [ 29.78633308410656,40.613414764404524 ], [ 29.92487716674833,40.577526092529354 ], [ 29.928827285766886,40.558509826660156 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-17", "NAME_1": "Çanakkale" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 26.0534725189209,39.84736251831055 ], [ 26.075693130493164,39.8365287780764 ], [ 26.083751678466797,39.80125045776373 ], [ 26.06180572509811,39.78708267211914 ], [ 25.962083816528377,39.8370819091798 ], [ 26.0534725189209,39.84736251831055 ] ] ], [ [ [ 26.08652687072788,39.920417785644815 ], [ 26.087360382080078,39.917640686035156 ], [ 26.081247329712312,39.9181938171389 ], [ 26.08430480957037,39.920139312744254 ], [ 26.08652687072788,39.920417785644815 ] ] ], [ [ [ 26.053194046020508,39.931526184081974 ], [ 26.053747177124478,39.92986297607439 ], [ 26.050138473511026,39.92986297607439 ], [ 26.051250457763786,39.931526184081974 ], [ 26.053194046020508,39.931526184081974 ] ] ], [ [ [ 26.060972213745174,39.940692901611555 ], [ 26.072916030884244,39.93624877929716 ], [ 26.07847213745123,39.93847274780302 ], [ 26.079860687255973,39.937362670898665 ], [ 26.067640304565487,39.931251525879134 ], [ 26.060972213745174,39.940692901611555 ] ] ], [ [ [ 25.944583892822322,40.24124908447277 ], [ 25.977083206176758,40.216251373291186 ], [ 25.965972900390625,40.15013885498047 ], [ 25.988470077514876,40.14430618286133 ], [ 26.013748168945597,40.163749694824446 ], [ 25.993749618530444,40.131526947021484 ], [ 25.739027023315487,40.09069442749018 ], [ 25.665136337280273,40.12430572509777 ], [ 25.670694351196403,40.15375137329124 ], [ 25.78513717651373,40.210414886474666 ], [ 25.84291648864746,40.21125030517601 ], [ 25.944583892822322,40.24124908447277 ] ] ], [ [ [ 26.714027404785156,40.38874816894531 ], [ 26.715414047241666,40.38124847412121 ], [ 26.70541572570812,40.383193969726506 ], [ 26.707082748413427,40.385971069336165 ], [ 26.714027404785156,40.38874816894531 ] ] ], [ [ [ 27.286527633666935,40.47513961792015 ], [ 27.333749771118335,40.41125106811529 ], [ 27.304861068725756,40.400970458984375 ], [ 27.308750152588175,40.371807098388786 ], [ 27.49319648742693,40.307083129882756 ], [ 27.580728530883732,40.31188583374029 ], [ 27.575317382812614,40.27116012573242 ], [ 27.468250274658146,40.19468688964855 ], [ 27.50711631774908,40.125858306884766 ], [ 27.450334548950195,39.98967361450195 ], [ 27.487668991088924,39.96401596069347 ], [ 27.492630004882812,39.93980789184599 ], [ 27.472572326660156,39.88761520385759 ], [ 27.423446655273494,39.829936981201286 ], [ 27.264280319214095,39.7708168029788 ], [ 27.15715980529785,39.81030654907238 ], [ 27.091777801513672,39.81017303466808 ], [ 26.980264663696403,39.78216171264654 ], [ 26.845289230346737,39.71005630493164 ], [ 26.723983764648665,39.715759277343864 ], [ 26.688920974731445,39.697902679443416 ], [ 26.669155120849837,39.65981674194347 ], [ 26.66930580139166,39.55764007568371 ], [ 26.657917022705135,39.55180740356451 ], [ 26.459581375122013,39.521251678466854 ], [ 26.37624931335455,39.49652862548828 ], [ 26.368194580078296,39.480415344238395 ], [ 26.264862060546875,39.483196258545036 ], [ 26.24180793762207,39.46374893188471 ], [ 26.229858398437784,39.474582672119254 ], [ 26.131250381469783,39.45291519165039 ], [ 26.063194274902287,39.47819519042969 ], [ 26.105693817138672,39.58541488647472 ], [ 26.142360687255916,39.612640380859375 ], [ 26.163473129272404,39.659305572509936 ], [ 26.139862060546818,39.75708389282255 ], [ 26.158472061157227,39.776527404785156 ], [ 26.163751602172795,39.81791687011719 ], [ 26.137083053588924,39.840972900390625 ], [ 26.159305572509993,39.88291549682623 ], [ 26.149858474731616,39.91569519042963 ], [ 26.1773624420166,39.98903274536127 ], [ 26.198194503784123,40.00986099243164 ], [ 26.269582748413086,40.0006942749024 ], [ 26.333194732666186,40.02763748168951 ], [ 26.365972518920955,40.10013961792015 ], [ 26.409860610961914,40.119304656982365 ], [ 26.397361755371037,40.145694732666016 ], [ 26.40875053405756,40.1548614501956 ], [ 26.403194427490405,40.19680404663086 ], [ 26.449028015136832,40.1940269470216 ], [ 26.524583816528605,40.21764373779297 ], [ 26.572639465331974,40.2801399230957 ], [ 26.606527328491325,40.28125000000023 ], [ 26.693195343017635,40.35291671752941 ], [ 26.689861297607365,40.365695953369254 ], [ 26.752359390258903,40.40291595459007 ], [ 26.91319465637207,40.406528472900504 ], [ 26.953193664550952,40.38375091552746 ], [ 27.03319358825695,40.38958358764643 ], [ 27.089860916137923,40.442081451416186 ], [ 27.155138015747127,40.4520835876466 ], [ 27.20513916015642,40.4343070983889 ], [ 27.286527633666935,40.47513961792015 ] ] ], [ [ [ 27.04261207580595,40.74805068969732 ], [ 27.029438018799055,40.59069442749029 ], [ 26.996250152588118,40.55569458007818 ], [ 26.900138854980412,40.53625106811518 ], [ 26.699306488037166,40.45430374145508 ], [ 26.70013809204113,40.41986083984392 ], [ 26.64125061035162,40.40319442749029 ], [ 26.631248474121094,40.362361907958984 ], [ 26.591249465942383,40.321250915527514 ], [ 26.509859085083065,40.28819274902355 ], [ 26.424583435058878,40.22069549560547 ], [ 26.358194351196516,40.20319366455078 ], [ 26.38097381591814,40.143196105957145 ], [ 26.224304199218807,40.04958343505871 ], [ 26.16986083984375,40.045970916748274 ], [ 26.278472900390682,40.215694427490234 ], [ 26.278749465942496,40.25374984741222 ], [ 26.22930526733421,40.28874969482433 ], [ 26.24652862548828,40.29958343505865 ], [ 26.24264144897461,40.31375122070324 ], [ 26.21846961975109,40.31958389282221 ], [ 26.308471679687443,40.365970611572266 ], [ 26.331806182861612,40.3637504577639 ], [ 26.45569419860857,40.441528320312614 ], [ 26.625415802002124,40.50847244262695 ], [ 26.703750610351562,40.51041793823265 ], [ 26.74736022949213,40.559028625488565 ], [ 26.74875068664545,40.54624938964872 ], [ 26.769584655761776,40.54513931274437 ], [ 26.834863662719783,40.58124923706083 ], [ 26.81875038146967,40.6470832824707 ], [ 26.759315490722713,40.69137954711914 ], [ 26.783828735351562,40.74620056152344 ], [ 26.85856628417963,40.744842529296875 ], [ 26.987554550170955,40.80205917358421 ], [ 27.02488708496088,40.791057586670206 ], [ 27.04261207580595,40.74805068969732 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-18", "NAME_1": "Çankırı" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 33.78607177734375,40.96249008178722 ], [ 33.82974624633795,40.91614532470703 ], [ 34.03589248657232,40.85097122192377 ], [ 34.057151794433594,40.800819396972884 ], [ 34.04485702514654,40.680839538574446 ], [ 34.10348129272472,40.520450592041016 ], [ 34.15930557250982,40.431739807129134 ], [ 34.15694808959961,40.398799896240234 ], [ 34.1071968078615,40.32553863525402 ], [ 33.96546936035162,40.260776519775504 ], [ 33.718235015869425,40.28034591674805 ], [ 33.40986251831072,40.38897705078125 ], [ 33.364143371581974,40.38593292236334 ], [ 33.330764770507756,40.33474349975609 ], [ 33.2674293518067,40.331134796142805 ], [ 33.22098541259771,40.351249694824446 ], [ 33.17174530029314,40.434806823730526 ], [ 32.96144866943371,40.59566879272484 ], [ 32.65491485595709,40.702560424804744 ], [ 32.50134658813505,40.704257965088004 ], [ 32.539924621582145,40.79755020141613 ], [ 32.519256591796875,40.83922576904308 ], [ 32.587478637695256,40.89188003540062 ], [ 32.6919403076173,40.957851409912166 ], [ 33.027935028076456,41.01646423339844 ], [ 33.07714080810564,41.088871002197266 ], [ 33.18547439575207,41.07445526123047 ], [ 33.2963294982913,41.02467346191406 ], [ 33.349895477295206,40.97469711303722 ], [ 33.40762329101591,40.95941925048828 ], [ 33.8348770141601,41.09566879272472 ], [ 33.85814666748041,41.07776641845726 ], [ 33.86064910888672,41.05282211303711 ], [ 33.791225433349666,40.99592971801752 ], [ 33.78607177734375,40.96249008178722 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-19", "NAME_1": "Çorum" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 34.819057464599666,41.20172119140631 ], [ 34.85211944580095,41.19771957397455 ], [ 34.892101287841854,41.253662109375114 ], [ 34.94060516357439,41.20204162597656 ], [ 34.97922515869146,41.0832786560058 ], [ 35.01823425292986,41.07475662231445 ], [ 35.093154907226506,41.09054183959961 ], [ 35.09133148193365,41.03227615356468 ], [ 35.04957199096674,40.95141220092779 ], [ 35.04604339599604,40.852909088134766 ], [ 35.02510070800798,40.843399047851676 ], [ 35.09455871582031,40.695533752441634 ], [ 35.16113281250006,40.66824340820335 ], [ 35.25703811645519,40.666099548340014 ], [ 35.346443176269815,40.64120483398449 ], [ 35.42771530151373,40.615207672119254 ], [ 35.46203994750982,40.578224182129134 ], [ 35.448406219482365,40.46772384643566 ], [ 35.343681335449276,40.35832595825195 ], [ 35.33233642578119,40.228908538818416 ], [ 35.288646697998104,40.213741302490234 ], [ 35.16777420043957,40.2132301330567 ], [ 35.17874526977556,40.090763092041016 ], [ 35.05699539184599,40.02979278564453 ], [ 34.91966629028349,40.05079650878906 ], [ 34.78937911987333,39.99235153198248 ], [ 34.394672393798885,39.99183654785156 ], [ 34.32065582275419,39.947689056396484 ], [ 34.154014587402514,39.93353271484398 ], [ 34.05434417724615,39.90491104125988 ], [ 34.06595611572271,39.95508575439476 ], [ 34.1991729736331,40.03972244262707 ], [ 34.14983749389677,40.07336425781256 ], [ 34.105388641357536,40.131149291992415 ], [ 34.08119583129911,40.22275161743164 ], [ 33.96546936035162,40.260776519775504 ], [ 34.1071968078615,40.32553863525402 ], [ 34.161037445068416,40.41214370727539 ], [ 34.04485702514654,40.680839538574446 ], [ 34.057151794433594,40.800819396972884 ], [ 34.03589248657232,40.85097122192377 ], [ 34.27776718139654,40.92724227905302 ], [ 34.27907180786133,40.976325988769645 ], [ 34.22607040405279,41.00858306884777 ], [ 34.210571289062614,41.040046691894645 ], [ 34.29096221923845,41.16743850708008 ], [ 34.43107604980497,41.304927825927734 ], [ 34.466541290283374,41.30647277832037 ], [ 34.521492004394815,41.27654266357433 ], [ 34.819057464599666,41.20172119140631 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-20", "NAME_1": "Denizli" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 29.85498237609869,38.42560577392584 ], [ 29.928991317749194,38.406925201416016 ], [ 30.041721343994197,38.2337265014649 ], [ 30.020292282104776,38.17622375488281 ], [ 29.924520492553825,38.10348129272478 ], [ 29.665998458862475,37.98868942260748 ], [ 29.663770675659237,37.852550506591854 ], [ 29.72046852111822,37.852550506591854 ], [ 29.81536865234392,37.81905364990257 ], [ 29.845273971557788,37.76081848144531 ], [ 29.526779174804858,37.5913848876956 ], [ 29.530990600586108,37.46260452270508 ], [ 29.57953453063959,37.43535614013683 ], [ 29.579244613647518,37.41019439697277 ], [ 29.523260116577433,37.31515121459961 ], [ 29.411666870117244,37.18967819213867 ], [ 29.387758255004826,37.076091766357536 ], [ 29.334857940673885,37.035694122314396 ], [ 29.328029632568416,36.95631408691406 ], [ 29.262014389038256,36.88135910034191 ], [ 29.19094657897955,36.88718414306652 ], [ 29.081838607788143,36.99150466918945 ], [ 29.07584381103527,37.047645568847656 ], [ 29.05659675598173,37.07457733154297 ], [ 29.063364028930664,37.104351043701286 ], [ 29.0329914093017,37.144401550293026 ], [ 28.928304672241268,37.20682525634777 ], [ 28.786222457886026,37.24433517456066 ], [ 28.74400711059576,37.35529327392578 ], [ 28.614433288574332,37.39347839355469 ], [ 28.611564636230753,37.472900390625114 ], [ 28.550529479980753,37.570991516113224 ], [ 28.60674095153837,37.60981369018549 ], [ 28.740436553955192,37.600101470947266 ], [ 28.87957382202171,37.69700241088867 ], [ 28.849018096923828,37.763168334961165 ], [ 28.76422882080078,37.84311676025402 ], [ 28.793079376220817,37.90647888183622 ], [ 28.866380691528377,37.9932594299317 ], [ 28.799518585205362,38.0478324890139 ], [ 28.70470046997076,38.087642669677734 ], [ 28.789449691772518,38.14189910888672 ], [ 28.801586151123104,38.218879699707145 ], [ 28.92095375061041,38.265453338623104 ], [ 29.22126007080078,38.195537567138956 ], [ 29.42590332031267,38.26173400878912 ], [ 29.54411315917963,38.19533920288097 ], [ 29.57591819763178,38.19177246093756 ], [ 29.594125747680607,38.27232742309593 ], [ 29.64810752868658,38.34411239624035 ], [ 29.68351745605497,38.430995941162166 ], [ 29.755413055419922,38.45410919189453 ], [ 29.85498237609869,38.42560577392584 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-21", "NAME_1": "Diyarbakır" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 41.393245697021484,38.59392929077154 ], [ 41.381370544433594,38.54735183715826 ], [ 41.433452606201456,38.49269866943365 ], [ 41.41843032836931,38.47577667236334 ], [ 41.35118865966797,38.471626281738565 ], [ 41.247844696045206,38.426227569580135 ], [ 41.21492385864275,38.333042144775504 ], [ 41.21520614624029,38.21622085571289 ], [ 41.22935867309599,38.17604446411144 ], [ 41.21151351928728,38.105602264404354 ], [ 41.105842590332315,37.91629791259771 ], [ 41.03360366821295,37.86264419555687 ], [ 41.05167770385759,37.825115203857536 ], [ 41.11236953735357,37.80470275878906 ], [ 41.09494400024431,37.765148162841854 ], [ 41.051792144775675,37.73957443237305 ], [ 40.80224990844732,37.717403411865234 ], [ 40.752021789550895,37.730331420898494 ], [ 40.715831756591854,37.761577606201286 ], [ 40.64764404296881,37.76625823974621 ], [ 40.60204696655302,37.787681579589844 ], [ 40.54299545288086,37.733390808105526 ], [ 40.535087585449276,37.67518997192394 ], [ 40.5161018371582,37.650424957275504 ], [ 40.41819000244146,37.6458854675293 ], [ 40.27312088012701,37.56756973266624 ], [ 40.09448623657255,37.589130401611555 ], [ 40.01730346679699,37.5563125610351 ], [ 39.881374359130916,37.55633163452154 ], [ 39.86167144775402,37.60364151000982 ], [ 39.86046981811552,37.746318817138786 ], [ 39.82324218750017,37.787952423095646 ], [ 39.76156616210966,37.83341598510742 ], [ 39.66156768798834,37.84016799926769 ], [ 39.41362762451183,37.995002746581974 ], [ 39.25479507446295,37.99920654296875 ], [ 39.17874908447283,38.030654907226676 ], [ 39.22737503051769,38.07843399047863 ], [ 39.24422836303711,38.172023773193416 ], [ 39.20501708984369,38.19129943847656 ], [ 39.160182952880916,38.17333602905296 ], [ 39.11173629760748,38.18469238281273 ], [ 39.14226913452154,38.27321624755865 ], [ 39.119144439697436,38.33825683593756 ], [ 39.26699066162138,38.36811065673828 ], [ 39.33853530883795,38.33818817138672 ], [ 39.39870071411161,38.33542633056652 ], [ 39.57147216796892,38.36953735351568 ], [ 39.73397445678722,38.37126541137695 ], [ 39.81111526489275,38.4249267578125 ], [ 39.86201477050787,38.49816513061546 ], [ 40.05464172363287,38.475044250488395 ], [ 40.437953948974666,38.476139068603516 ], [ 40.466030120849894,38.492721557617415 ], [ 40.497112274170206,38.5901451110841 ], [ 40.52542114257824,38.61225128173828 ], [ 40.91010284423834,38.59239578247093 ], [ 41.26630401611328,38.72560119628912 ], [ 41.371963500976506,38.6430358886721 ], [ 41.393245697021484,38.59392929077154 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-81", "NAME_1": "Düzce" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 31.339487075805778,41.13582611083979 ], [ 31.43902778625494,41.05629730224604 ], [ 31.736297607421932,41.042720794677734 ], [ 31.75791931152355,41.01557540893549 ], [ 31.757904052734432,40.987693786621094 ], [ 31.735439300537166,40.94449996948248 ], [ 31.668218612671012,40.904876708984375 ], [ 31.60422897338873,40.8813362121582 ], [ 31.469253540039233,40.87095642089844 ], [ 31.43151664733898,40.805057525634766 ], [ 31.42705917358404,40.70133590698265 ], [ 31.36094474792492,40.66146087646496 ], [ 31.264896392822322,40.646827697753906 ], [ 31.190750122070483,40.68179702758789 ], [ 31.026567459106445,40.65954208374029 ], [ 30.954557418823242,40.682250976562614 ], [ 30.986114501953296,40.72135162353527 ], [ 30.89267539978033,40.77858734130854 ], [ 30.87307357788086,40.82920074462896 ], [ 30.906887054443416,40.897171020507926 ], [ 31.00865745544445,40.961486816406364 ], [ 31.03475379943842,41.00601959228521 ], [ 30.97593688964872,41.072639465332145 ], [ 31.217081069946573,41.09791564941406 ], [ 31.339487075805778,41.13582611083979 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-22", "NAME_1": "Edirne" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 26.738752365112646,40.61902618408209 ], [ 26.740417480468807,40.61264038085932 ], [ 26.730972290039404,40.614582061767635 ], [ 26.732084274292163,40.61680603027355 ], [ 26.738752365112646,40.61902618408209 ] ] ], [ [ [ 26.75652694702154,40.62208175659174 ], [ 26.758472442627408,40.6198616027832 ], [ 26.75430488586443,40.61875152587885 ], [ 26.754581451416016,40.62152862548851 ], [ 26.75652694702154,40.62208175659174 ] ] ], [ [ [ 26.03069496154785,40.75374984741211 ], [ 26.030689239502294,40.752361297607365 ], [ 26.031805038452205,40.749584197998104 ], [ 26.030139923095703,40.75152587890625 ], [ 26.03069496154785,40.75374984741211 ] ] ], [ [ [ 26.010969161987703,40.78958892822294 ], [ 26.021804809570256,40.779304504394645 ], [ 26.026807785034407,40.77236175537132 ], [ 26.02736091613781,40.76903152465843 ], [ 26.010969161987703,40.78958892822294 ] ] ], [ [ [ 26.97304725646967,41.972370147705135 ], [ 26.988868713378906,41.91792678833019 ], [ 26.953647613525334,41.73678207397461 ], [ 26.9095973968507,41.679828643798885 ], [ 26.921703338623104,41.65630340576183 ], [ 26.997392654419002,41.62268066406273 ], [ 26.99989509582548,41.55601119995123 ], [ 26.919303894043196,41.46986007690441 ], [ 26.87914657592796,41.388225555420036 ], [ 26.898347854614258,41.34303283691406 ], [ 26.89655685424833,41.294040679931584 ], [ 26.93860054016136,41.23728561401373 ], [ 26.93921089172369,41.195243835449446 ], [ 26.89196395874029,41.13861846923834 ], [ 26.772720336914176,41.10102081298851 ], [ 26.744598388671932,41.060417175293026 ], [ 26.74397468566889,41.03450775146496 ], [ 26.783018112182617,40.999576568603516 ], [ 26.730768203735806,40.902725219726676 ], [ 26.728576660156307,40.814212799072266 ], [ 26.783828735351562,40.74620056152344 ], [ 26.759315490722713,40.69137954711914 ], [ 26.79263877868658,40.65680694580101 ], [ 26.609861373901367,40.63680648803711 ], [ 26.533750534057617,40.591251373291016 ], [ 26.461250305175724,40.61680603027355 ], [ 26.414026260376318,40.59847259521513 ], [ 26.374305725097997,40.60819625854492 ], [ 26.304027557373217,40.5904159545899 ], [ 26.124584197998047,40.59097290039085 ], [ 26.088472366333008,40.60819625854492 ], [ 26.060972213745174,40.63763809204124 ], [ 26.06236076354992,40.68319320678734 ], [ 26.031528472900618,40.73390197753935 ], [ 26.125116348267,40.754512786865234 ], [ 26.157695770263615,40.814674377441406 ], [ 26.21730995178251,40.836658477783146 ], [ 26.201379776000977,40.85223388671875 ], [ 26.228288650512695,40.89812088012695 ], [ 26.24975585937517,40.891414642333984 ], [ 26.264711380004883,40.921726226806584 ], [ 26.29023361206066,40.899761199951286 ], [ 26.301431655884073,40.91019821167015 ], [ 26.28898620605497,40.93489837646507 ], [ 26.353076934814453,40.95466613769531 ], [ 26.323467254638842,40.98362731933588 ], [ 26.35173606872553,41.00104141235363 ], [ 26.35911369323759,41.02755355834972 ], [ 26.319107055664347,41.063545227050724 ], [ 26.327295303344954,41.11148834228521 ], [ 26.309978485107422,41.1176376342774 ], [ 26.33097839355463,41.14646530151384 ], [ 26.306446075439567,41.175109863281364 ], [ 26.331590652465934,41.254291534424055 ], [ 26.410427093505803,41.258857727050724 ], [ 26.528671264648665,41.346923828125114 ], [ 26.592201232910213,41.32866668701166 ], [ 26.63687133789091,41.356079101562614 ], [ 26.63391494751005,41.4283981323245 ], [ 26.60487937927246,41.491004943847656 ], [ 26.596136093139876,41.61547088623058 ], [ 26.536483764648665,41.62702560424816 ], [ 26.496963500976562,41.669059753418026 ], [ 26.368787765503157,41.71422958374018 ], [ 26.33962821960455,41.75893020629883 ], [ 26.377365112304858,41.83274078369152 ], [ 26.54617881774925,41.84154891967796 ], [ 26.581527709960994,41.87805175781256 ], [ 26.58583641052269,41.90520477294933 ], [ 26.569192886352596,41.92753219604492 ], [ 26.623439788818644,41.976928710937614 ], [ 26.751115798950423,41.95451354980486 ], [ 26.781169891357706,41.97798538208019 ], [ 26.838518142700252,41.969402313232536 ], [ 26.865001678466797,41.98744964599621 ], [ 26.97284698486328,42.00579452514654 ], [ 26.97304725646967,41.972370147705135 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-23", "NAME_1": "Elazığ" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 40.34999847412104,39.10704803466797 ], [ 40.28809738159208,39.05596542358393 ], [ 40.28541564941412,38.95002746582031 ], [ 40.320285797119254,38.86981201171898 ], [ 40.357448577880916,38.85798263549799 ], [ 40.38602828979498,38.80131912231457 ], [ 40.35682296752947,38.725006103515625 ], [ 40.28368759155302,38.723560333252124 ], [ 40.239067077636776,38.63198089599615 ], [ 40.23947143554693,38.60807037353533 ], [ 40.29603576660156,38.55552673339855 ], [ 40.29214859008806,38.47479248046898 ], [ 40.05464172363287,38.475044250488395 ], [ 39.86201477050787,38.49816513061546 ], [ 39.81111526489275,38.4249267578125 ], [ 39.73397445678722,38.37126541137695 ], [ 39.57147216796892,38.36953735351568 ], [ 39.39870071411161,38.33542633056652 ], [ 39.33853530883795,38.33818817138672 ], [ 39.26699066162138,38.36811065673828 ], [ 38.968620300293026,38.30895233154291 ], [ 38.8217391967774,38.40439605712896 ], [ 38.684249877929744,38.41202545166021 ], [ 38.525379180908374,38.46200180053722 ], [ 38.429889678955135,38.47502899169933 ], [ 38.37929534912138,38.512310028076286 ], [ 38.34922790527361,38.57312011718744 ], [ 38.38140487670904,38.64058303833008 ], [ 38.471988677978686,38.736061096191406 ], [ 38.62973022460966,38.75020980834955 ], [ 38.631317138672046,38.876541137695426 ], [ 38.58731842041021,38.97253036499046 ], [ 38.613189697265625,39.010799407958984 ], [ 38.68186950683611,39.00462722778332 ], [ 38.753204345703296,39.03481674194336 ], [ 38.783012390136776,38.987480163574276 ], [ 38.769435882568644,38.89875411987316 ], [ 38.808502197265625,38.87729644775402 ], [ 39.048492431640625,38.89308929443382 ], [ 39.49058151245123,38.749164581299055 ], [ 39.63027191162115,38.80181884765625 ], [ 39.727626800537166,38.803623199462834 ], [ 39.80643463134783,38.83753585815441 ], [ 39.891315460205135,38.9417343139649 ], [ 39.89322280883795,38.99279022216797 ], [ 39.86791610717768,39.045005798339844 ], [ 39.9225807189942,39.08842849731445 ], [ 40.028297424316406,39.094463348388786 ], [ 40.13597869873075,39.14826583862316 ], [ 40.359775543213004,39.226669311523665 ], [ 40.39783859252947,39.15583801269531 ], [ 40.34999847412104,39.10704803466797 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-24", "NAME_1": "Erzincan" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 40.26528167724638,39.90684127807617 ], [ 40.4804420471192,39.906944274902344 ], [ 40.509937286376896,39.89397811889654 ], [ 40.53995132446295,39.844947814941406 ], [ 40.530143737793026,39.79112625122076 ], [ 40.563358306884766,39.751308441162166 ], [ 40.69152832031256,39.690715789795036 ], [ 40.6196174621582,39.579704284668026 ], [ 40.62028884887701,39.52821731567377 ], [ 40.54322814941406,39.54778289794922 ], [ 40.142089843750284,39.5576286315918 ], [ 39.986354827881144,39.51869201660179 ], [ 39.88587951660162,39.54994583129911 ], [ 39.77057266235357,39.51818084716808 ], [ 39.69773864746111,39.45171737670927 ], [ 39.66516876220709,39.441463470458984 ], [ 39.618003845215014,39.444042205810604 ], [ 39.60741424560558,39.481758117676065 ], [ 39.585163116455135,39.48873519897455 ], [ 39.477455139160156,39.4769744873048 ], [ 39.31540298461931,39.49990081787104 ], [ 39.153591156006144,39.47578430175804 ], [ 39.097686767578296,39.46172332763683 ], [ 38.96605682373064,39.37565994262695 ], [ 38.819885253906534,39.31785202026367 ], [ 38.79290771484375,39.27995681762701 ], [ 38.833896636963004,39.257617950439624 ], [ 38.92637634277344,39.25006484985357 ], [ 38.917270660400675,39.22851943969738 ], [ 38.7714576721192,39.18029785156256 ], [ 38.72623825073259,39.113128662109375 ], [ 38.753204345703296,39.03481674194336 ], [ 38.68186950683611,39.00462722778332 ], [ 38.65647125244135,39.05071258544916 ], [ 38.617038726806925,39.079467773437614 ], [ 38.52343368530268,39.11494064331055 ], [ 38.416332244873104,39.11750030517578 ], [ 38.35454559326172,39.13976669311529 ], [ 38.39357757568371,39.213386535644645 ], [ 38.39641189575195,39.41117095947277 ], [ 38.34907150268583,39.5365562438966 ], [ 38.366264343261776,39.683441162109375 ], [ 38.413822174072266,39.746189117431754 ], [ 38.43944168090826,39.75685119628906 ], [ 38.450466156005916,39.7869110107423 ], [ 38.52255249023466,39.797157287597884 ], [ 38.554382324219034,39.826526641845646 ], [ 38.52223587036144,39.84823226928722 ], [ 38.402069091797046,39.82606506347656 ], [ 38.36834716796881,39.837001800537394 ], [ 38.38290023803728,39.89551925659191 ], [ 38.447406768798885,39.96938323974615 ], [ 38.72418212890619,39.956573486328125 ], [ 38.75243377685564,39.97180938720703 ], [ 38.77371978759777,40.04879760742199 ], [ 38.92853927612333,40.062679290771484 ], [ 39.11577224731451,40.01247024536144 ], [ 39.11574554443388,40.000827789306754 ], [ 39.384086608887,39.88770294189453 ], [ 39.47190856933611,39.87245178222673 ], [ 39.75101470947271,39.911785125732365 ], [ 39.879669189453125,40.00830078125023 ], [ 40.121814727783374,40.069835662841854 ], [ 40.28641510009771,40.039066314697266 ], [ 40.24314117431652,39.947322845458984 ], [ 40.26528167724638,39.90684127807617 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-25", "NAME_1": "Erzurum" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 42.33081436157232,40.982887268066406 ], [ 42.332916259765796,40.924530029296875 ], [ 42.37902069091825,40.83445358276373 ], [ 42.491706848144645,40.721416473388786 ], [ 42.567897796630916,40.614326477050895 ], [ 42.538536071777514,40.44420623779325 ], [ 42.509208679199276,40.40768432617193 ], [ 42.271778106689624,40.31632232666021 ], [ 42.14982986450224,40.28962326049816 ], [ 42.13726806640631,40.26054382324213 ], [ 42.205627441406534,40.16657257080078 ], [ 42.36748123168974,40.13149261474615 ], [ 42.498966217041186,40.041206359863224 ], [ 42.55170440673845,39.97406005859369 ], [ 42.566364288330135,39.94755172729515 ], [ 42.40620422363287,39.873390197753906 ], [ 42.2776527404788,39.88196563720703 ], [ 42.25519943237322,39.861167907714844 ], [ 42.285240173340014,39.81406784057623 ], [ 42.49176406860357,39.75294876098633 ], [ 42.50790786743181,39.72431564331055 ], [ 42.523639678955135,39.56861877441406 ], [ 42.47146987915039,39.488586425781364 ], [ 42.32644271850597,39.459419250488395 ], [ 42.21374511718756,39.40992355346691 ], [ 42.19287490844732,39.381523132324276 ], [ 42.22022247314453,39.34602355957048 ], [ 42.218486785888786,39.32173919677746 ], [ 42.074256896972656,39.222366333007926 ], [ 41.83882522583025,39.162235260009766 ], [ 41.72012329101568,39.17336654663109 ], [ 41.64963912963867,39.20930862426752 ], [ 41.515937805176065,39.33350372314459 ], [ 41.386318206787394,39.383571624755916 ], [ 41.2186927795413,39.35533905029297 ], [ 41.1310348510745,39.45877838134771 ], [ 41.02952194213884,39.46599578857439 ], [ 40.94934082031267,39.508766174316634 ], [ 40.90058135986334,39.55487060546875 ], [ 40.856491088867244,39.56525802612305 ], [ 40.68346405029314,39.51169967651373 ], [ 40.62548446655302,39.524215698242415 ], [ 40.6196174621582,39.579704284668026 ], [ 40.69152832031256,39.690715789795036 ], [ 40.563358306884766,39.751308441162166 ], [ 40.530143737793026,39.79112625122076 ], [ 40.53995132446295,39.844947814941406 ], [ 40.509937286376896,39.89397811889654 ], [ 40.4804420471192,39.906944274902344 ], [ 40.26528167724638,39.90684127807617 ], [ 40.244785308838175,39.93095779418968 ], [ 40.28641510009771,40.039066314697266 ], [ 40.48427581787104,40.026412963867244 ], [ 40.64613723754883,40.11261749267584 ], [ 40.75914382934576,40.15104293823248 ], [ 40.79587173461931,40.198104858398494 ], [ 40.78182983398432,40.23067092895519 ], [ 40.63780975341825,40.245708465576286 ], [ 40.59257507324247,40.26642990112305 ], [ 40.58805847167969,40.29078292846674 ], [ 40.559944152832145,40.30656433105486 ], [ 40.52688598632818,40.48198318481451 ], [ 40.4984970092774,40.535331726074276 ], [ 40.82793426513683,40.65369033813488 ], [ 41.12230682373047,40.80845260620117 ], [ 41.199081420898494,40.78024673461914 ], [ 41.3855819702149,40.77217483520536 ], [ 41.39697265625017,40.74471664428722 ], [ 41.33960342407255,40.6501579284668 ], [ 41.362621307373104,40.57928466796875 ], [ 41.428695678710994,40.563056945800724 ], [ 41.65904998779314,40.66276931762695 ], [ 41.71423721313471,40.66050338745123 ], [ 41.83464050292997,40.61849594116211 ], [ 41.90903854370117,40.646457672119254 ], [ 41.973175048828125,40.85636520385742 ], [ 42.01268005371111,40.93065643310547 ], [ 42.09929656982422,40.963840484619254 ], [ 42.273120880127124,40.9653129577639 ], [ 42.33081436157232,40.982887268066406 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-26", "NAME_1": "Eskişehir" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 30.972843170166186,40.018688201904354 ], [ 31.175989151001033,40.04402542114258 ], [ 31.617036819458292,40.01634979248058 ], [ 31.695951461791992,39.98823165893566 ], [ 31.797164916992244,39.8831901550293 ], [ 31.857683181762752,39.87451553344749 ], [ 31.88599014282238,39.808479309082145 ], [ 31.847255706787166,39.76829147338873 ], [ 31.849052429199276,39.730388641357536 ], [ 31.896219253540096,39.63234329223661 ], [ 31.995899200439737,39.49590301513672 ], [ 32.0114288330081,39.312587738037166 ], [ 31.991197586059627,39.22510147094738 ], [ 31.86066818237333,39.167995452880916 ], [ 31.838905334472656,39.106754302978516 ], [ 31.77247047424345,39.07804870605469 ], [ 31.6680526733399,39.0982398986817 ], [ 31.471307754516886,39.0867462158206 ], [ 31.386358261108683,39.11867141723644 ], [ 31.30526924133318,39.273185729980526 ], [ 31.24177551269537,39.28451919555664 ], [ 31.141860961914347,39.218502044677734 ], [ 30.989156723022518,39.15921020507824 ], [ 30.885963439941577,39.21287155151373 ], [ 30.799478530883846,39.172389984130916 ], [ 30.766630172729776,39.12854385375999 ], [ 30.618543624877987,39.07700729370117 ], [ 30.533037185669002,39.139522552490234 ], [ 30.50550842285162,39.189422607421875 ], [ 30.45332908630388,39.20599746704107 ], [ 30.41478919982916,39.28709411621094 ], [ 30.321493148803654,39.361034393310604 ], [ 30.314607620239315,39.483478546142635 ], [ 30.13921356201172,39.62137222290045 ], [ 30.18699836730957,39.69670867919933 ], [ 30.044765472412166,39.693233489990234 ], [ 30.000635147094897,39.73457717895536 ], [ 30.002716064453182,39.78552246093773 ], [ 30.0730113983156,39.852836608886776 ], [ 30.136020660400675,39.86830139160179 ], [ 30.248657226562784,39.85490798950207 ], [ 30.35621070861822,39.9370231628418 ], [ 30.427679061889762,39.9382896423341 ], [ 30.482061386108683,39.96120071411133 ], [ 30.523212432861612,40.00673294067394 ], [ 30.571363449096623,40.14687728881859 ], [ 30.726753234863338,40.171913146972656 ], [ 30.859945297241154,40.14501571655285 ], [ 30.913637161254826,40.0991401672365 ], [ 30.921283721924112,40.03337478637701 ], [ 30.972843170166186,40.018688201904354 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-27", "NAME_1": "Gaziantep" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 37.91703033447283,37.511512756347656 ], [ 37.991966247558594,37.491725921631144 ], [ 38.05150604248064,37.43758773803711 ], [ 37.98842239379877,37.43914031982433 ], [ 37.93680572509794,37.40411758422874 ], [ 37.84837341308611,37.312484741210994 ], [ 37.83034515380871,37.24394226074219 ], [ 37.880939483642635,37.057415008545036 ], [ 37.97619247436552,36.97856521606451 ], [ 38.01262283325224,36.92795562744146 ], [ 38.010631561279354,36.825210571289176 ], [ 37.908031463623104,36.785701751708984 ], [ 37.79120635986334,36.74859619140642 ], [ 37.65513992309576,36.731410980224666 ], [ 37.50850296020536,36.65539550781256 ], [ 37.435653686523494,36.78142929077177 ], [ 37.24035644531256,36.86549377441406 ], [ 37.19807815551758,36.965221405029524 ], [ 37.14458847045927,37.00689315795893 ], [ 37.01332473754894,37.010478973388786 ], [ 36.97225952148466,36.993789672851676 ], [ 36.90999221801786,36.902648925781364 ], [ 36.792087554931925,36.843338012695256 ], [ 36.7839546203615,36.806518554687614 ], [ 36.6755447387697,36.84560012817383 ], [ 36.62614440917986,36.84095001220709 ], [ 36.442592620849666,36.95328521728521 ], [ 36.539062500000114,37.113624572753906 ], [ 36.728641510009936,37.27605056762695 ], [ 36.89641189575207,37.365814208984546 ], [ 36.92829513549833,37.349662780761946 ], [ 36.9666366577149,37.230720520019474 ], [ 37.01084136962908,37.217384338378906 ], [ 37.04829406738287,37.23469924926758 ], [ 37.089210510253906,37.28264236450207 ], [ 37.18589782714838,37.332862854004134 ], [ 37.59473419189459,37.39747619628923 ], [ 37.621623992920206,37.43280792236351 ], [ 37.62296295166021,37.51213455200224 ], [ 37.679069519043026,37.512031555175895 ], [ 37.77766036987299,37.54558563232433 ], [ 37.91703033447283,37.511512756347656 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-28", "NAME_1": "Giresun" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 38.43736267089861,40.92986297607422 ], [ 38.43847274780279,40.928470611572266 ], [ 38.43513870239275,40.928749084472656 ], [ 38.4356956481933,40.93069458007835 ], [ 38.43736267089861,40.92986297607422 ] ] ], [ [ [ 39.163471221923885,41.07930374145508 ], [ 39.17869949340826,41.07402801513666 ], [ 39.14806747436552,41.03693771362299 ], [ 39.11791610717802,40.95093536376959 ], [ 39.1192893981933,40.8454208374024 ], [ 39.14960861206049,40.775512695312784 ], [ 39.10797882080095,40.758464813232365 ], [ 39.02652740478533,40.75756072998058 ], [ 38.952190399170206,40.711280822753906 ], [ 38.84720993041998,40.561927795410156 ], [ 38.85500335693388,40.46141433715826 ], [ 38.983440399170206,40.42817306518555 ], [ 39.0709877014163,40.364284515380916 ], [ 39.04844284057623,40.333206176757926 ], [ 38.961185455322266,40.29854965209972 ], [ 38.909038543701286,40.25615692138666 ], [ 38.90629959106445,40.14979553222656 ], [ 38.950401306152344,40.09682083129883 ], [ 38.93473052978544,40.06813430786144 ], [ 38.86236953735346,40.04825973510765 ], [ 38.77371978759777,40.04879760742199 ], [ 38.57074737548834,40.116062164306584 ], [ 38.45939254760759,40.09647750854492 ], [ 38.251918792724666,40.19630432128906 ], [ 38.228839874267635,40.32080459594732 ], [ 38.15539932250982,40.528263092041016 ], [ 38.11658096313505,40.6118354797365 ], [ 38.00863647460943,40.748332977295206 ], [ 38.123195648193416,40.95513916015631 ], [ 38.20041656494135,40.93791580200207 ], [ 38.28319549560541,40.94513702392578 ], [ 38.35625076293951,40.90902709960966 ], [ 38.389583587646655,40.92430496215843 ], [ 38.4298629760745,40.911251068115405 ], [ 38.52902603149414,40.916526794433594 ], [ 38.62347412109369,40.97319412231457 ], [ 38.67486190795927,40.949028015136776 ], [ 38.714862823486385,40.95069503784191 ], [ 38.81652832031267,41.01152801513672 ], [ 38.87152862548834,41.01124954223633 ], [ 38.93347167968767,41.04375076293957 ], [ 39.05291748046881,41.036804199218864 ], [ 39.163471221923885,41.07930374145508 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-29", "NAME_1": "Gümüşhane" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 39.17561721801758,40.76031875610363 ], [ 39.313480377197436,40.66615295410179 ], [ 39.65062713623064,40.5599250793457 ], [ 39.72409057617193,40.57740783691423 ], [ 39.766292572021655,40.67451095581066 ], [ 39.80594635009771,40.71657562255888 ], [ 39.84022521972673,40.69247055053705 ], [ 39.831077575683594,40.618892669677905 ], [ 39.89093780517595,40.61500549316412 ], [ 39.92637252807623,40.573833465576115 ], [ 39.96866989135759,40.560638427734375 ], [ 39.99657058715826,40.591430664062614 ], [ 39.97467422485363,40.63690185546875 ], [ 40.004878997802734,40.65853500366211 ], [ 40.10813140869169,40.57054519653332 ], [ 40.07474136352539,40.466796875 ], [ 40.04135513305681,40.4155731201173 ], [ 39.988433837890625,40.36897277832037 ], [ 39.88367080688482,40.3472251892091 ], [ 39.85456085205084,40.3255500793457 ], [ 39.82343292236345,40.249820709228686 ], [ 39.82063674926758,40.15822982788086 ], [ 39.80493545532255,40.120574951171875 ], [ 39.74072265625006,40.07666397094732 ], [ 39.69057846069353,40.01388931274414 ], [ 39.7164382934572,39.96063232421898 ], [ 39.78475570678705,39.931087493896484 ], [ 39.77601242065447,39.923477172851676 ], [ 39.6178817749024,39.88530349731445 ], [ 39.438926696777344,39.87340545654314 ], [ 39.26388931274431,39.934585571289006 ], [ 39.11574554443388,40.000827789306754 ], [ 39.11577224731451,40.01247024536144 ], [ 38.92853927612333,40.062679290771484 ], [ 38.950401306152344,40.09682083129883 ], [ 38.90629959106445,40.14979553222656 ], [ 38.909038543701286,40.25615692138666 ], [ 38.961185455322266,40.29854965209972 ], [ 39.04844284057623,40.333206176757926 ], [ 39.0709877014163,40.364284515380916 ], [ 38.983440399170206,40.42817306518555 ], [ 38.85500335693388,40.46141433715826 ], [ 38.84974288940458,40.57057571411144 ], [ 38.928970336914176,40.69153594970709 ], [ 39.02652740478533,40.75756072998058 ], [ 39.10797882080095,40.758464813232365 ], [ 39.14960861206049,40.775512695312784 ], [ 39.17561721801758,40.76031875610363 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-30", "NAME_1": "Hakkari" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 44.23672103881836,37.72581100463867 ], [ 44.24645996093756,37.6920623779298 ], [ 44.21875762939459,37.64070129394537 ], [ 44.24623870849615,37.62623977661133 ], [ 44.32952880859392,37.65622329711914 ], [ 44.428737640381144,37.64877700805664 ], [ 44.51017761230486,37.6978836059572 ], [ 44.57461929321295,37.767143249511776 ], [ 44.610614776611385,37.75423049926758 ], [ 44.63830184936529,37.716304779052734 ], [ 44.58086013793951,37.64654159545921 ], [ 44.63534164428705,37.608364105224666 ], [ 44.638813018799,37.57563018798828 ], [ 44.616718292236385,37.55250549316406 ], [ 44.62445068359381,37.48171997070324 ], [ 44.6026153564456,37.444278717041016 ], [ 44.662406921386776,37.427494049072266 ], [ 44.68934249877947,37.38499069213867 ], [ 44.73342895507841,37.37773895263683 ], [ 44.82329940795904,37.307567596435604 ], [ 44.83383941650408,37.27449417114252 ], [ 44.7782096862793,37.224006652832145 ], [ 44.80496597290039,37.148143768310774 ], [ 44.77106475830078,37.16749191284174 ], [ 44.63774108886719,37.186740875244425 ], [ 44.51138305664068,37.09354782104492 ], [ 44.3506813049317,37.04928588867199 ], [ 44.365116119384936,37.026351928711165 ], [ 44.31998062133795,36.96705627441412 ], [ 44.268787384033374,36.98297119140625 ], [ 44.24353790283203,37.026706695556754 ], [ 44.246902465820256,37.05009460449213 ], [ 44.20225143432623,37.098056793213004 ], [ 44.24228286743181,37.1566619873048 ], [ 44.26858520507818,37.155235290527344 ], [ 44.29009628295927,37.17499923706055 ], [ 44.278858184814396,37.23628234863281 ], [ 44.237377166748104,37.27907180786127 ], [ 44.14183807373064,37.315654754638786 ], [ 44.03302764892584,37.32502746582037 ], [ 43.970607757568644,37.286735534668026 ], [ 43.9512672424317,37.25539779663097 ], [ 43.896213531494425,37.23456192016607 ], [ 43.66655731201189,37.23086547851574 ], [ 43.5009841918947,37.26836013793957 ], [ 43.43782043457031,37.33258056640619 ], [ 43.436573028564396,37.52254486083979 ], [ 43.49570465087896,37.72740173339838 ], [ 43.67584609985357,37.715328216552734 ], [ 43.78456878662104,37.726203918457145 ], [ 43.892715454101506,37.700431823730526 ], [ 43.96967315673834,37.7267951965332 ], [ 44.0651931762697,37.71755218505865 ], [ 44.20137023925798,37.76893234252947 ], [ 44.23672103881836,37.72581100463867 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-31", "NAME_1": "Hatay" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 36.185138702392635,36.724304199219034 ], [ 36.188751220703125,36.72319412231468 ], [ 36.188751220703125,36.72263717651373 ], [ 36.18597412109381,36.72236251831055 ], [ 36.185138702392635,36.724304199219034 ] ] ], [ [ [ 36.06156921386736,37.023487091064396 ], [ 36.254726409912166,37.008663177490405 ], [ 36.34716796875006,36.95531463623064 ], [ 36.442592620849666,36.953285217285384 ], [ 36.62614440917986,36.84095001220709 ], [ 36.66854476928711,36.836769104004134 ], [ 36.678554534912166,36.81852340698248 ], [ 36.62707138061529,36.757701873779524 ], [ 36.63688278198242,36.705108642578296 ], [ 36.588047027587834,36.63603973388672 ], [ 36.59989166259771,36.56200408935541 ], [ 36.552886962890796,36.49698257446312 ], [ 36.58913803100597,36.397804260253906 ], [ 36.62255859375006,36.39120101928705 ], [ 36.627742767334155,36.354164123535156 ], [ 36.60783767700224,36.32987976074213 ], [ 36.666233062744425,36.33023071289074 ], [ 36.6710968017581,36.3023567199707 ], [ 36.70032882690441,36.29220581054693 ], [ 36.70477294921881,36.250331878662166 ], [ 36.6183509826663,36.2165908813476 ], [ 36.58386230468756,36.23211288452177 ], [ 36.495422363281534,36.23447036743181 ], [ 36.47106552124035,36.20180130004877 ], [ 36.39754867553728,36.2232398986817 ], [ 36.40058135986334,36.1914634704591 ], [ 36.37670516967768,36.16939544677757 ], [ 36.39784240722673,36.08376312255865 ], [ 36.378593444824276,36.00100326538086 ], [ 36.3441696166995,35.99237442016596 ], [ 36.31720352172846,36.004100799560604 ], [ 36.29788970947283,35.991699218750114 ], [ 36.30253219604492,35.957408905029354 ], [ 36.212722778320426,35.95149230957031 ], [ 36.180915832519474,35.90173721313488 ], [ 36.18305206298845,35.83557128906256 ], [ 36.16907119750982,35.815425872802905 ], [ 36.11644744873041,35.865512847900504 ], [ 36.01867675781256,35.881103515625 ], [ 36.02288818359381,35.92449951171881 ], [ 36.008483886719034,35.94030761718773 ], [ 35.935798645019815,35.91867446899437 ], [ 35.918472290039006,35.93233108520508 ], [ 35.97902679443365,36.01902770996094 ], [ 35.89680480957037,36.15791702270536 ], [ 35.780418395996264,36.2987518310548 ], [ 35.780971527099666,36.32236099243164 ], [ 35.815971374511776,36.36041641235374 ], [ 35.85347366333019,36.36902618408203 ], [ 35.860416412353686,36.39569473266624 ], [ 35.895973205566406,36.41541671752941 ], [ 35.90958404541021,36.44513702392595 ], [ 35.982639312744425,36.47430419921875 ], [ 36.03680419921881,36.533748626708984 ], [ 36.14875030517578,36.59069442749052 ], [ 36.194583892822436,36.59597396850609 ], [ 36.21569442749052,36.65930557250982 ], [ 36.19263839721708,36.70513916015648 ], [ 36.20208358764654,36.727085113525334 ], [ 36.18708419799833,36.72902679443365 ], [ 36.205970764160156,36.78236007690441 ], [ 36.14847183227545,36.85514068603527 ], [ 36.129585266113565,36.853195190429744 ], [ 36.14069366455095,36.862083435058764 ], [ 36.085693359375114,36.90513992309593 ], [ 36.01708221435541,36.930137634277344 ], [ 35.93763732910162,36.8865318298341 ], [ 35.94486236572271,36.874305725097656 ], [ 35.945693969726676,36.86430740356451 ], [ 35.913639068603686,36.8955192565918 ], [ 35.95418167114269,36.96366119384777 ], [ 36.04160690307617,37.025554656982536 ], [ 36.06156921386736,37.023487091064396 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-76", "NAME_1": "Iğdır" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 43.69572830200207,40.18729782104498 ], [ 43.71363067626953,40.166362762451286 ], [ 43.655036926269815,40.14826202392578 ], [ 43.655479431152514,40.11077117919933 ], [ 43.718761444091854,40.07968521118181 ], [ 43.769920349121264,40.0795211791995 ], [ 43.90547943115263,40.01846694946289 ], [ 44.282360076904354,40.04839324951183 ], [ 44.48470687866228,39.96729660034174 ], [ 44.557548522949276,39.903785705566634 ], [ 44.601554870605526,39.82548522949213 ], [ 44.62551116943354,39.828296661377124 ], [ 44.62156677246111,39.815410614013786 ], [ 44.67524337768572,39.787746429443416 ], [ 44.69823455810564,39.793563842773494 ], [ 44.7006912231447,39.767551422119254 ], [ 44.7176055908206,39.76768493652338 ], [ 44.812736511230526,39.6770133972168 ], [ 44.82022094726591,39.62520980834984 ], [ 44.72192764282221,39.70727539062517 ], [ 44.656444549560604,39.73276519775419 ], [ 44.623455047607536,39.77722167968744 ], [ 44.49647140502958,39.69598007202171 ], [ 44.25063323974615,39.67041397094749 ], [ 44.15977859497082,39.69419860839855 ], [ 43.99331665039068,39.686500549316406 ], [ 43.74055480957048,39.79948043823242 ], [ 43.62248992919939,39.82235717773443 ], [ 43.5319442749024,39.820419311523494 ], [ 43.47832870483427,39.766723632812614 ], [ 43.39422988891596,39.79460525512701 ], [ 43.39402008056646,39.93553543090843 ], [ 43.375995635986385,39.959014892578125 ], [ 43.35047149658203,39.9627571105957 ], [ 43.34629821777361,39.99917984008789 ], [ 43.293140411376896,40.06836318969755 ], [ 43.297000885009936,40.09724807739258 ], [ 43.315303802490405,40.11288452148449 ], [ 43.38040161132807,40.11241149902344 ], [ 43.393310546875114,40.13174819946289 ], [ 43.38365554809576,40.16720962524414 ], [ 43.411888122558594,40.18202590942394 ], [ 43.563655853271655,40.18433761596691 ], [ 43.66280746459978,40.218669891357536 ], [ 43.69572830200207,40.18729782104498 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-32", "NAME_1": "Isparta" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 31.45230293273943,37.852764129638786 ], [ 31.450740814209098,37.77799987792969 ], [ 31.336086273193416,37.43759536743164 ], [ 31.323301315307617,37.42438888549816 ], [ 31.231279373169002,37.420497894287166 ], [ 31.17972755432129,37.389701843261946 ], [ 30.996772766113452,37.342758178710994 ], [ 30.915895462036417,37.37248611450207 ], [ 30.889757156372355,37.42609786987316 ], [ 30.76529884338396,37.52559661865229 ], [ 30.70260238647461,37.6779670715332 ], [ 30.651264190674,37.700595855712834 ], [ 30.50423812866211,37.7170295715332 ], [ 30.41355323791521,37.77392959594732 ], [ 30.371025085449276,37.83028030395536 ], [ 30.32089614868164,37.837131500244254 ], [ 30.08116722106928,37.703464508056584 ], [ 30.04684448242216,37.70895004272472 ], [ 30.002939224243164,37.7548828125 ], [ 30.01048660278326,37.77233886718756 ], [ 30.084434509277628,37.774665832519645 ], [ 30.173227310180835,37.81985473632824 ], [ 30.20322036743181,37.85691070556635 ], [ 30.18260765075712,37.9011611938476 ], [ 30.22363090515165,37.98092269897472 ], [ 30.265552520752237,38.016117095947266 ], [ 30.366300582886026,38.07125473022461 ], [ 30.517358779907283,38.18640518188471 ], [ 30.640510559082202,38.245807647705135 ], [ 30.799964904785327,38.2902374267581 ], [ 30.877569198608455,38.36164474487316 ], [ 31.103597640991268,38.51663589477545 ], [ 31.13091659545927,38.510589599609375 ], [ 31.20930480957037,38.439853668213004 ], [ 31.250438690185604,38.42662429809576 ], [ 31.243375778198413,38.38523483276373 ], [ 31.262851715087947,38.360977172851676 ], [ 31.615524291992358,38.11956024169922 ], [ 31.61683845520048,38.0888214111331 ], [ 31.599279403686694,38.065040588378906 ], [ 31.474828720093058,38.020690917968864 ], [ 31.42659378051775,37.97075271606451 ], [ 31.423555374145565,37.90834808349621 ], [ 31.45230293273943,37.852764129638786 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-34", "NAME_1": "İstanbul" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 29.114028930664233,40.820693969726676 ], [ 29.11430549621582,40.81763839721697 ], [ 29.11041641235397,40.820137023925895 ], [ 29.110971450805778,40.820693969726676 ], [ 29.114028930664233,40.820693969726676 ] ] ], [ [ [ 29.143749237060774,40.85597229003935 ], [ 29.148193359375,40.849582672119425 ], [ 29.148473739623967,40.846248626709155 ], [ 29.140417098999478,40.85041809082037 ], [ 29.143749237060774,40.85597229003935 ] ] ], [ [ [ 28.995695114135685,40.866527557373274 ], [ 28.995695114135685,40.86347198486345 ], [ 28.991249084473054,40.86208343505871 ], [ 28.9901390075687,40.86597061157232 ], [ 28.995695114135685,40.866527557373274 ] ] ], [ [ [ 29.129583358764762,40.875694274902344 ], [ 29.13958358764654,40.869861602783374 ], [ 29.11291885375988,40.83847045898432 ], [ 29.106805801391545,40.860973358154354 ], [ 29.129583358764762,40.875694274902344 ] ] ], [ [ [ 28.973192214965877,40.87708282470726 ], [ 28.974584579467773,40.87402725219755 ], [ 28.969305038452205,40.87402725219755 ], [ 28.969583511352596,40.875972747802905 ], [ 28.973192214965877,40.87708282470726 ] ] ], [ [ [ 29.09708595275913,40.88541793823248 ], [ 29.10430526733404,40.872917175293196 ], [ 29.074861526489315,40.86791610717785 ], [ 29.07541656494186,40.87402725219755 ], [ 29.09708595275913,40.88541793823248 ] ] ], [ [ [ 29.077638626098974,40.88652801513683 ], [ 29.079860687255916,40.884029388427734 ], [ 29.07652854919462,40.881248474121264 ], [ 29.07597160339367,40.88513946533209 ], [ 29.077638626098974,40.88652801513683 ] ] ], [ [ [ 29.06013870239292,40.886806488037394 ], [ 29.068195343017578,40.88513946533209 ], [ 29.07236099243164,40.878749847412166 ], [ 29.052917480469205,40.87652587890648 ], [ 29.06013870239292,40.886806488037394 ] ] ], [ [ [ 29.051805496215877,40.91485977172846 ], [ 29.057916641235806,40.90625 ], [ 29.045139312744368,40.902084350586165 ], [ 29.039028167725007,40.91236114501976 ], [ 29.051805496215877,40.91485977172846 ] ] ], [ [ [ 29.256526947021598,41.23541641235357 ], [ 29.588193893432674,41.16986083984381 ], [ 29.60958290100092,41.18236160278326 ], [ 29.674583435058594,41.16152954101574 ], [ 29.862083435058594,41.14374923706049 ], [ 29.882982254028377,41.09217834472656 ], [ 29.848857879638842,41.06917572021507 ], [ 29.748725891113565,41.05318450927746 ], [ 29.644767761230582,41.00930404663086 ], [ 29.496175765991495,41.035736083984375 ], [ 29.481319427490405,41.0007019042971 ], [ 29.43189430236822,40.97430038452154 ], [ 29.419984817504826,40.92051315307623 ], [ 29.348457336425952,40.891124725342024 ], [ 29.322084426879996,40.85878372192377 ], [ 29.261529922485522,40.85514068603521 ], [ 29.24763870239275,40.87208175659191 ], [ 29.144582748413143,40.90069580078125 ], [ 29.09708595275896,40.95013809204113 ], [ 29.03152847290056,40.96625137329107 ], [ 29.037639617920092,40.97958374023449 ], [ 29.02180480957037,40.978195190429915 ], [ 29.00597190856945,41.00986099243164 ], [ 29.008750915527344,41.02597045898432 ], [ 29.051527023315884,41.048194885254134 ], [ 29.06597137451172,41.10291671752941 ], [ 29.096250534057617,41.11791610717796 ], [ 29.070972442627067,41.14319610595709 ], [ 29.087083816528377,41.1787490844726 ], [ 29.165416717529467,41.224582672119254 ], [ 29.256526947021598,41.23541641235357 ] ] ], [ [ [ 28.199028015136832,41.54597091674816 ], [ 28.272918701171875,41.49569320678711 ], [ 28.63097190856962,41.35013961791992 ], [ 28.684305191040153,41.347915649414176 ], [ 28.78430557250988,41.30208206176758 ], [ 28.81125259399414,41.30541610717779 ], [ 28.96597290039074,41.25319290161144 ], [ 29.07819366455078,41.254581451416016 ], [ 29.11180686950712,41.23819351196289 ], [ 29.10958480834961,41.210140228271484 ], [ 29.037359237671126,41.15597152709961 ], [ 29.07236099243164,41.124862670898665 ], [ 29.05708312988287,41.0818061828615 ], [ 29.033193588256893,41.0498619079591 ], [ 28.975973129272518,41.02152633666992 ], [ 28.94013977050804,41.048194885254134 ], [ 28.9487495422365,41.057640075683594 ], [ 28.944026947021484,41.06458282470709 ], [ 28.93625068664562,41.045417785644474 ], [ 28.963472366333065,41.02152633666992 ], [ 28.986803054809684,41.017082214355526 ], [ 28.984863281250114,41.004859924316406 ], [ 28.9368057250976,41.00125122070318 ], [ 28.875139236450423,40.96847152709961 ], [ 28.85014152526867,40.97430419921875 ], [ 28.82430458068859,40.95402908325195 ], [ 28.76430511474615,40.98152923583979 ], [ 28.620138168334904,40.96041488647472 ], [ 28.595138549804744,40.97347259521496 ], [ 28.588472366333235,41.01763916015625 ], [ 28.564027786254883,41.017082214355526 ], [ 28.54124832153326,40.984306335449446 ], [ 28.407083511352766,41.045417785644474 ], [ 28.259582519531648,41.06236267089855 ], [ 28.233472824097134,41.07764053344749 ], [ 28.123260498046932,41.05986022949247 ], [ 28.057348251342773,41.15075302124052 ], [ 28.087570190429744,41.21114730834984 ], [ 28.15098190307623,41.24227523803734 ], [ 28.199129104614258,41.363262176513956 ], [ 28.23168945312517,41.499076843261776 ], [ 28.179122924804744,41.52955627441423 ], [ 28.199028015136832,41.54597091674816 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-35", "NAME_1": "İzmir" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 26.881528854370174,38.02430725097662 ], [ 26.884859085083065,38.02264022827171 ], [ 26.8840274810791,38.020973205566406 ], [ 26.880416870117244,38.020694732666016 ], [ 26.881528854370174,38.02430725097662 ] ] ], [ [ [ 27.014028549194336,38.04569625854492 ], [ 27.01430511474615,38.04347229003906 ], [ 27.0123615264896,38.04347229003906 ], [ 27.011806488037223,38.04486083984398 ], [ 27.014028549194336,38.04569625854492 ] ] ], [ [ [ 26.85597229003946,38.046527862548885 ], [ 26.855417251586914,38.044303894043196 ], [ 26.85375022888178,38.04486083984398 ], [ 26.85402870178217,38.04624938964872 ], [ 26.85597229003946,38.046527862548885 ] ] ], [ [ [ 26.803749084472713,38.15319442749052 ], [ 26.804027557373104,38.152084350586165 ], [ 26.80208396911638,38.149307250976506 ], [ 26.80236053466797,38.152362823486555 ], [ 26.803749084472713,38.15319442749052 ] ] ], [ [ [ 26.80569458007824,38.16263961792015 ], [ 26.803194046020735,38.158195495605526 ], [ 26.800971984863622,38.15708160400402 ], [ 26.801528930664006,38.16180419921898 ], [ 26.80569458007824,38.16263961792015 ] ] ], [ [ [ 26.438194274902685,38.18847274780285 ], [ 26.440416336059798,38.18624877929716 ], [ 26.43958282470703,38.18264007568371 ], [ 26.435972213745174,38.185138702392805 ], [ 26.438194274902685,38.18847274780285 ] ] ], [ [ [ 26.433195114136083,38.19874954223661 ], [ 26.43402862548828,38.193195343017635 ], [ 26.42791748046875,38.19430541992199 ], [ 26.428194046020906,38.19569396972656 ], [ 26.433195114136083,38.19874954223661 ] ] ], [ [ [ 26.769306182861385,38.20097351074247 ], [ 26.772083282471044,38.19958496093756 ], [ 26.77180671691906,38.19819259643566 ], [ 26.769306182861385,38.19847106933605 ], [ 26.769306182861385,38.20097351074247 ] ] ], [ [ [ 26.45180511474649,38.20124816894531 ], [ 26.448194503784634,38.19597244262695 ], [ 26.441804885864713,38.19819259643566 ], [ 26.4429168701173,38.20041656494135 ], [ 26.45180511474649,38.20124816894531 ] ] ], [ [ [ 26.208471298217887,38.29791641235357 ], [ 26.210695266723974,38.29486083984375 ], [ 26.210695266723974,38.2904167175293 ], [ 26.20791625976608,38.292915344238395 ], [ 26.208471298217887,38.29791641235357 ] ] ], [ [ [ 26.67847251892124,38.333751678467024 ], [ 26.679307937622184,38.33013916015642 ], [ 26.674303054810025,38.32930374145508 ], [ 26.674028396606445,38.33208465576172 ], [ 26.67847251892124,38.333751678467024 ] ] ], [ [ [ 26.454027175903434,38.36847305297874 ], [ 26.457916259765852,38.360694885253906 ], [ 26.452915191650845,38.359027862549 ], [ 26.445970535278377,38.36486053466797 ], [ 26.454027175903434,38.36847305297874 ] ] ], [ [ [ 26.7895832061771,38.37781143188499 ], [ 26.792083740234602,38.374862670898665 ], [ 26.783195495605582,38.36736297607439 ], [ 26.784585952758903,38.37569427490246 ], [ 26.7895832061771,38.37781143188499 ] ] ], [ [ [ 26.466249465942496,38.38208389282238 ], [ 26.466806411743278,38.375415802001896 ], [ 26.46152687072771,38.37430572509771 ], [ 26.461250305175724,38.375415802001896 ], [ 26.466249465942496,38.38208389282238 ] ] ], [ [ [ 26.449306488037223,38.39041519165045 ], [ 26.450971603393555,38.387359619140796 ], [ 26.449028015136832,38.38569259643566 ], [ 26.447639465332088,38.389583587646655 ], [ 26.449306488037223,38.39041519165045 ] ] ], [ [ [ 26.44958305358881,38.39485931396507 ], [ 26.449028015136832,38.39180374145536 ], [ 26.44680595397972,38.3909721374514 ], [ 26.447916030884073,38.39430618286127 ], [ 26.44958305358881,38.39485931396507 ] ] ], [ [ [ 26.790138244628906,38.39986038208008 ], [ 26.79236030578619,38.395694732666016 ], [ 26.784860610961914,38.393196105957315 ], [ 26.784027099609375,38.39597320556658 ], [ 26.790138244628906,38.39986038208008 ] ] ], [ [ [ 26.469305038452546,38.39791488647472 ], [ 26.46902847290039,38.395416259765625 ], [ 26.468194961548193,38.40041732788103 ], [ 26.469583511352937,38.40041732788103 ], [ 26.469305038452546,38.39791488647472 ] ] ], [ [ [ 26.46458244323736,38.40263748168974 ], [ 26.46847152709961,38.39152908325201 ], [ 26.465417861938533,38.386806488037394 ], [ 26.46152687072771,38.395416259765625 ], [ 26.46458244323736,38.40263748168974 ] ] ], [ [ [ 26.491527557373047,38.40541839599621 ], [ 26.49291610717796,38.404304504394645 ], [ 26.490417480468864,38.40347290039085 ], [ 26.489860534667912,38.404861450195426 ], [ 26.491527557373047,38.40541839599621 ] ] ], [ [ [ 26.770139694213924,38.41069412231457 ], [ 26.77375030517578,38.407360076904354 ], [ 26.76986122131393,38.404304504394645 ], [ 26.76819229126022,38.410415649414006 ], [ 26.770139694213924,38.41069412231457 ] ] ], [ [ [ 26.795692443848054,38.41541671752958 ], [ 26.799306869506893,38.407360076904354 ], [ 26.793193817138956,38.40652847290056 ], [ 26.792083740234602,38.41069412231457 ], [ 26.795692443848054,38.41541671752958 ] ] ], [ [ [ 26.782917022705192,38.41819381713884 ], [ 26.785417556762695,38.416248321533374 ], [ 26.785139083862305,38.41458511352539 ], [ 26.780416488647518,38.415973663330135 ], [ 26.782917022705192,38.41819381713884 ] ] ], [ [ [ 26.308471679687443,38.42347335815441 ], [ 26.315139770507926,38.41791534423828 ], [ 26.31347274780279,38.41430664062523 ], [ 26.308471679687443,38.41736221313505 ], [ 26.308471679687443,38.42347335815441 ] ] ], [ [ [ 26.385972976684513,38.4362487792971 ], [ 26.38958358764694,38.422084808349666 ], [ 26.372915267944677,38.42708206176769 ], [ 26.37347221374506,38.43180465698248 ], [ 26.385972976684513,38.4362487792971 ] ] ], [ [ [ 26.369583129882812,38.43791580200201 ], [ 26.374027252197436,38.434028625488395 ], [ 26.368194580078466,38.42708206176769 ], [ 26.36736106872553,38.43736267089861 ], [ 26.369583129882812,38.43791580200201 ] ] ], [ [ [ 26.97402763366705,38.44097137451172 ], [ 26.972085952758903,38.434307098388956 ], [ 26.969028472900447,38.43513870239275 ], [ 26.971805572509766,38.44180679321306 ], [ 26.97402763366705,38.44097137451172 ] ] ], [ [ [ 26.923471450806005,38.448192596435774 ], [ 26.926805496215877,38.44680404663103 ], [ 26.927639007568416,38.444862365722884 ], [ 26.923749923705998,38.445693969726676 ], [ 26.923471450806005,38.448192596435774 ] ] ], [ [ [ 26.767362594604833,38.45541763305687 ], [ 26.776250839233853,38.44097137451172 ], [ 26.764305114746207,38.43486022949219 ], [ 26.759307861328182,38.45264053344738 ], [ 26.767362594604833,38.45541763305687 ] ] ], [ [ [ 26.359861373901424,38.45624923706066 ], [ 26.35736083984375,38.428195953369425 ], [ 26.33152770996105,38.422637939453296 ], [ 26.32513809204113,38.44124984741211 ], [ 26.359861373901424,38.45624923706066 ] ] ], [ [ [ 26.85041427612333,38.5345840454101 ], [ 26.854583740234546,38.533473968505916 ], [ 26.854583740234546,38.5326385498048 ], [ 26.849027633666992,38.53430557250971 ], [ 26.85041427612333,38.5345840454101 ] ] ], [ [ [ 26.859027862548942,38.53430557250971 ], [ 26.86125183105503,38.533748626709155 ], [ 26.8626384735108,38.5351371765139 ], [ 26.86347389221197,38.53319549560575 ], [ 26.857915878296012,38.533748626709155 ], [ 26.860137939453125,38.536529541015625 ], [ 26.859027862548942,38.53430557250971 ] ] ], [ [ [ 26.698749542236385,38.54735946655279 ], [ 26.729305267334098,38.52986145019531 ], [ 26.730972290039404,38.4968070983889 ], [ 26.749584197998217,38.48180389404314 ], [ 26.74236106872553,38.45875167846708 ], [ 26.69430541992199,38.47958374023443 ], [ 26.698749542236385,38.54735946655279 ] ] ], [ [ [ 26.818471908569677,38.545696258545206 ], [ 26.826250076293945,38.53819274902372 ], [ 26.825971603393953,38.53152847290045 ], [ 26.814027786254883,38.54430389404308 ], [ 26.818471908569677,38.545696258545206 ] ] ], [ [ [ 26.5220832824711,38.654026031494425 ], [ 26.52486038208002,38.65236282348627 ], [ 26.526805877685717,38.64986038208019 ], [ 26.522361755371094,38.65208435058588 ], [ 26.5220832824711,38.654026031494425 ] ] ], [ [ [ 26.51874923706066,38.66347122192383 ], [ 26.51958274841303,38.65763854980469 ], [ 26.510694503784578,38.657081604003906 ], [ 26.514862060546818,38.662639617920036 ], [ 26.51874923706066,38.66347122192383 ] ] ], [ [ [ 26.72569465637224,38.677082061767805 ], [ 26.729585647583065,38.67402648925798 ], [ 26.727916717529354,38.67013931274414 ], [ 26.723194122314737,38.67458343505854 ], [ 26.72569465637224,38.677082061767805 ] ] ], [ [ [ 26.71819686889654,38.67819595336937 ], [ 26.71819686889654,38.67597198486345 ], [ 26.711526870727653,38.67402648925798 ], [ 26.713470458984375,38.67680740356445 ], [ 26.71819686889654,38.67819595336937 ] ] ], [ [ [ 26.70930480957054,38.702915191650334 ], [ 26.72514152526901,38.69319534301775 ], [ 26.722917556762752,38.68680572509783 ], [ 26.708749771118164,38.691806793213004 ], [ 26.70930480957054,38.702915191650334 ] ] ], [ [ [ 26.709028244018555,38.71652603149437 ], [ 26.70986175537149,38.71347045898449 ], [ 26.707916259765625,38.71097183227556 ], [ 26.70763969421381,38.71347045898449 ], [ 26.709028244018555,38.71652603149437 ] ] ], [ [ [ 26.733749389648494,38.73402786254883 ], [ 26.734306335449276,38.73180389404291 ], [ 26.7318058013916,38.732639312744254 ], [ 26.73236083984375,38.73374938964844 ], [ 26.733749389648494,38.73402786254883 ] ] ], [ [ [ 26.883193969726733,38.85652923584013 ], [ 26.88763809204113,38.847637176513786 ], [ 26.876249313354435,38.84736251831055 ], [ 26.876249313354435,38.85208511352556 ], [ 26.883193969726733,38.85652923584013 ] ] ], [ [ [ 26.892917633056697,38.86652755737316 ], [ 26.89374923706049,38.864860534668196 ], [ 26.891805648803768,38.86208343505854 ], [ 26.89125061035196,38.86430740356445 ], [ 26.892917633056697,38.86652755737316 ] ] ], [ [ [ 27.04013824462885,38.8843040466308 ], [ 27.038196563720703,38.885139465332315 ], [ 27.041250228882177,38.88652801513672 ], [ 27.041250228882177,38.88458251953119 ], [ 27.04013824462885,38.8843040466308 ] ] ], [ [ [ 26.83402824401861,38.908748626708984 ], [ 26.83930778503418,38.90402603149437 ], [ 26.839027404785213,38.90097045898466 ], [ 26.83264160156284,38.90430450439476 ], [ 26.83402824401861,38.908748626708984 ] ] ], [ [ [ 26.810695648193416,38.92763900756836 ], [ 26.825696945190543,38.92291641235357 ], [ 26.8223628997805,38.910972595214844 ], [ 26.806249618530217,38.9170837402346 ], [ 26.810695648193416,38.92763900756836 ] ] ], [ [ [ 26.804306030273494,38.93763732910156 ], [ 26.806528091430778,38.935138702392805 ], [ 26.806528091430778,38.93402862548828 ], [ 26.803472518921296,38.935695648193416 ], [ 26.804306030273494,38.93763732910156 ] ] ], [ [ [ 26.79874992370611,39.011249542236555 ], [ 26.79680633544922,38.99791717529297 ], [ 26.79236030578619,38.996250152588004 ], [ 26.79291725158697,39.008472442626896 ], [ 26.79874992370611,39.011249542236555 ] ] ], [ [ [ 26.787361145019986,39.01235961914091 ], [ 26.788473129272745,39.005973815918196 ], [ 26.784027099609375,39.000137329101676 ], [ 26.780416488647518,39.00875091552729 ], [ 26.787361145019986,39.01235961914091 ] ] ], [ [ [ 27.470958709716797,39.1718826293947 ], [ 27.504394531249943,39.11765670776373 ], [ 27.50539588928217,39.01988601684582 ], [ 27.433935165405387,38.96704864501953 ], [ 27.387517929077205,38.95204162597662 ], [ 27.37003517150879,38.9268493652346 ], [ 27.168153762817496,38.89170837402344 ], [ 27.131971359253384,38.80689239501959 ], [ 27.124540328979947,38.77974319458019 ], [ 27.231248855591275,38.73934555053705 ], [ 27.279998779296932,38.572151184082145 ], [ 27.33832931518566,38.58828735351585 ], [ 27.457939147949446,38.56347656250006 ], [ 27.56540679931652,38.48628616333025 ], [ 27.742670059204045,38.446926116943644 ], [ 27.82133483886747,38.35077285766613 ], [ 27.853576660156534,38.33378982543957 ], [ 28.001060485839787,38.399547576904524 ], [ 28.117492675781477,38.40279769897484 ], [ 28.145027160644815,38.39204025268555 ], [ 28.16123199462919,38.360778808593864 ], [ 28.22292518615734,38.33587265014654 ], [ 28.433549880981445,38.295082092285156 ], [ 28.474098205566577,38.25453948974621 ], [ 28.527257919311467,38.13525772094738 ], [ 28.559946060180778,38.108661651611385 ], [ 28.249021530151367,38.01900100708008 ], [ 28.071899414062727,38.02942657470726 ], [ 27.95366859436035,38.006706237793026 ], [ 27.938676834106502,38.018360137939396 ], [ 27.923608779907283,37.99508666992193 ], [ 27.77575492858881,37.972328186035156 ], [ 27.72010993957548,37.985515594482536 ], [ 27.531816482544002,37.983718872070426 ], [ 27.441749572753963,37.91611480712896 ], [ 27.35456848144537,37.891254425049055 ], [ 27.278308868408203,37.891544342041016 ], [ 27.260694503784237,37.912639617920036 ], [ 27.27486038208025,37.944583892822266 ], [ 27.24847030639677,37.98125076293951 ], [ 27.217082977294922,37.99236297607422 ], [ 27.14291763305664,37.98374938964838 ], [ 27.099027633666935,38.01541519165062 ], [ 27.07541656494152,38.01263809204096 ], [ 27.048194885253906,38.050140380859546 ], [ 26.983474731445426,38.07430648803711 ], [ 26.8979167938233,38.061527252197266 ], [ 26.864305496215934,38.02847290039085 ], [ 26.824306488037223,38.158195495605526 ], [ 26.7954158782959,38.1734733581543 ], [ 26.774860382080135,38.161251068115234 ], [ 26.772083282471044,38.19680404663109 ], [ 26.790416717529297,38.199028015137 ], [ 26.75736045837408,38.222084045410384 ], [ 26.73291778564453,38.20680618286127 ], [ 26.63597488403326,38.20735931396507 ], [ 26.62430572509777,38.13847351074219 ], [ 26.603195190429858,38.143470764160384 ], [ 26.61486053466797,38.110973358154524 ], [ 26.591527938842773,38.102638244628906 ], [ 26.570972442627408,38.14263916015642 ], [ 26.560417175293082,38.117362976074446 ], [ 26.52986145019537,38.12791824340843 ], [ 26.51152992248535,38.1656951904298 ], [ 26.517915725708292,38.187084197998274 ], [ 26.505416870117244,38.17514038085943 ], [ 26.48708343505899,38.18291854858427 ], [ 26.490695953369254,38.19569396972656 ], [ 26.458194732666414,38.19152832031273 ], [ 26.441804885864713,38.21875000000017 ], [ 26.419584274292447,38.22124862670927 ], [ 26.429306030273665,38.208194732666186 ], [ 26.431251525878963,38.199028015137 ], [ 26.429859161377067,38.19819259643566 ], [ 26.38903045654297,38.222915649414176 ], [ 26.40180587768583,38.24486160278343 ], [ 26.39097023010254,38.260971069335994 ], [ 26.378469467163086,38.26291656494146 ], [ 26.387361526489258,38.24736022949236 ], [ 26.36680603027372,38.22708511352539 ], [ 26.334861755371094,38.225692749023665 ], [ 26.28541755676281,38.26514053344738 ], [ 26.231527328491495,38.26625061035156 ], [ 26.233472824096623,38.29430389404297 ], [ 26.271804809570767,38.290138244629134 ], [ 26.28097152709961,38.3237495422365 ], [ 26.302639007568473,38.32069396972679 ], [ 26.28513908386242,38.34208297729492 ], [ 26.28458404541061,38.37652587890625 ], [ 26.3001384735108,38.355140686035156 ], [ 26.31597137451172,38.37625122070324 ], [ 26.318750381469783,38.33013916015642 ], [ 26.344861984252873,38.334304809570426 ], [ 26.344861984252873,38.319305419921875 ], [ 26.378469467163086,38.30902862548851 ], [ 26.384304046630803,38.348751068115234 ], [ 26.40180587768583,38.32347106933594 ], [ 26.482360839843807,38.37597274780302 ], [ 26.475694656372468,38.401527404785384 ], [ 26.451250076293945,38.428195953369425 ], [ 26.490139007568473,38.40097045898443 ], [ 26.515972137451172,38.428195953369425 ], [ 26.437915802002294,38.47680664062517 ], [ 26.39291763305664,38.44652938842785 ], [ 26.412082672119197,38.49430465698242 ], [ 26.371528625488338,38.52986145019531 ], [ 26.37513732910179,38.541805267333984 ], [ 26.38069534301792,38.52347183227539 ], [ 26.38069534301792,38.54402923584007 ], [ 26.359861373901424,38.56708526611351 ], [ 26.352916717529524,38.63874816894548 ], [ 26.36069488525436,38.65986251831055 ], [ 26.41624832153326,38.68097305297846 ], [ 26.474306106567553,38.67514038085966 ], [ 26.523471832275447,38.650142669677734 ], [ 26.52319526672386,38.630695343017805 ], [ 26.562360763549805,38.60263824462902 ], [ 26.569305419922102,38.559581756592024 ], [ 26.62513923645014,38.53125000000023 ], [ 26.64125061035162,38.469306945801065 ], [ 26.587917327880916,38.47041702270525 ], [ 26.60486030578619,38.451526641845646 ], [ 26.584583282471044,38.42652893066412 ], [ 26.611528396606502,38.422359466552905 ], [ 26.64347267150913,38.37569427490246 ], [ 26.644306182861328,38.339862823486555 ], [ 26.67375183105503,38.31208419799816 ], [ 26.703195571899414,38.319862365722656 ], [ 26.6751384735108,38.34791564941406 ], [ 26.677917480468864,38.360416412353516 ], [ 26.684860229492188,38.35041809082054 ], [ 26.688192367553654,38.351806640625284 ], [ 26.674581527710018,38.38791656494135 ], [ 26.70736122131342,38.4345817565918 ], [ 26.73652839660656,38.42874908447283 ], [ 26.76652717590332,38.36680603027344 ], [ 26.808473587036303,38.35541534423834 ], [ 27.017084121704215,38.41819381713884 ], [ 27.086805343628043,38.398471832275504 ], [ 27.1187496185305,38.410415649414006 ], [ 27.148195266723633,38.44763946533203 ], [ 27.170692443847884,38.44124984741211 ], [ 27.1590251922608,38.46680450439459 ], [ 27.111804962158203,38.448749542236385 ], [ 27.079305648803768,38.46708297729515 ], [ 27.02680778503418,38.46763992309593 ], [ 26.97430610656744,38.45513916015631 ], [ 26.94847297668474,38.43180465698248 ], [ 26.951805114746207,38.44347381591797 ], [ 26.919584274291992,38.45319366455095 ], [ 26.922361373901822,38.46763992309593 ], [ 26.884582519531648,38.507637023926065 ], [ 26.835695266723746,38.52236175537138 ], [ 26.828193664551065,38.527084350585994 ], [ 26.88791656494152,38.51069259643555 ], [ 26.882638931274357,38.53486251831066 ], [ 26.848192214966218,38.54291534423834 ], [ 26.847082138061864,38.559581756592024 ], [ 26.842639923095646,38.55041503906244 ], [ 26.822914123535497,38.55041503906244 ], [ 26.84680557250988,38.560417175293196 ], [ 26.83958244323776,38.58763885498047 ], [ 26.830417633056754,38.57819366455084 ], [ 26.79986190795944,38.61097335815424 ], [ 26.7570858001709,38.615417480468864 ], [ 26.769584655761776,38.635971069336165 ], [ 26.72236061096197,38.65152740478533 ], [ 26.753751754761197,38.66513824462896 ], [ 26.73069572448742,38.67458343505854 ], [ 26.74097061157221,38.68097305297846 ], [ 26.72652816772461,38.721527099609546 ], [ 26.743194580078296,38.73152923584007 ], [ 26.74014091491739,38.741806030273665 ], [ 26.780416488647518,38.73708343505865 ], [ 26.824028015136832,38.762359619140625 ], [ 26.835973739624137,38.742084503174055 ], [ 26.858194351196403,38.753192901611385 ], [ 26.894582748413427,38.73374938964844 ], [ 26.90708351135271,38.76652908325218 ], [ 26.92930603027355,38.75597381591825 ], [ 26.93902778625494,38.76597213745123 ], [ 26.892639160156307,38.82514190673828 ], [ 26.91402816772461,38.817359924316634 ], [ 26.944303512573526,38.8365287780764 ], [ 26.942638397216797,38.812084197998274 ], [ 26.969028472900447,38.80402755737305 ], [ 26.98430633544922,38.82263946533203 ], [ 26.962360382080533,38.83097076416044 ], [ 26.97125053405796,38.84597396850603 ], [ 27.02569580078125,38.87263870239269 ], [ 27.019582748413313,38.86208343505854 ], [ 27.034582138061864,38.855972290039006 ], [ 27.066249847412507,38.87708282470709 ], [ 27.051525115966797,38.897083282470646 ], [ 27.03736114501976,38.893470764160384 ], [ 27.057083129882926,38.91319274902338 ], [ 27.04375076293968,38.940971374511776 ], [ 27.006250381469897,38.91902923584007 ], [ 27.017915725708008,38.91347122192394 ], [ 26.969581604004077,38.92680740356457 ], [ 26.957084655761776,38.93763732910156 ], [ 26.968471527099894,38.944305419921875 ], [ 26.936805725097656,38.93763732910156 ], [ 26.939582824707315,38.925693511962834 ], [ 26.919584274291992,38.93986129760742 ], [ 26.858194351196403,38.9137496948245 ], [ 26.84986114501993,38.93375015258806 ], [ 26.801250457763615,38.95069503784197 ], [ 26.797361373901765,38.996250152588004 ], [ 26.815971374512173,39.025970458984546 ], [ 26.79874992370611,39.01514053344721 ], [ 26.799028396606502,39.03236007690447 ], [ 26.88763809204113,39.075416564941634 ], [ 26.835695266723746,39.14208221435541 ], [ 26.76458358764677,39.17321395874052 ], [ 26.957500457763672,39.259422302246094 ], [ 27.176755905151424,39.42146682739258 ], [ 27.407686233520792,39.38151550292969 ], [ 27.45876693725586,39.29547119140625 ], [ 27.470958709716797,39.1718826293947 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-46", "NAME_1": "Kahramanmaraş" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 37.039100646972656,38.5945396423341 ], [ 37.05988693237333,38.578189849853516 ], [ 37.288425445556584,38.59590911865257 ], [ 37.274082183838175,38.554397583007926 ], [ 37.19495010376005,38.49284362792969 ], [ 37.1977615356447,38.46109771728527 ], [ 37.36172103881853,38.46540832519531 ], [ 37.45554351806652,38.45201492309593 ], [ 37.69929885864275,38.358089447021484 ], [ 37.773830413818644,38.31008911132807 ], [ 37.77216720581072,38.22153472900402 ], [ 37.634899139404354,37.91677093505871 ], [ 37.52582168579107,37.77268218994146 ], [ 37.41357421875006,37.68510437011736 ], [ 37.426506042480526,37.60475921630854 ], [ 37.5731277465822,37.55051803588867 ], [ 37.62296295166021,37.51213455200224 ], [ 37.61789703369169,37.425151824951286 ], [ 37.55552673339872,37.38273620605463 ], [ 37.18589782714838,37.332862854004134 ], [ 37.089210510253906,37.28264236450207 ], [ 37.04829406738287,37.23469924926758 ], [ 37.01084136962908,37.217384338378906 ], [ 36.96500015258789,37.23295974731445 ], [ 36.9305152893067,37.34512710571289 ], [ 36.90557479858427,37.366729736328125 ], [ 36.728641510009936,37.27605056762695 ], [ 36.65103912353544,37.32998657226568 ], [ 36.582782745361385,37.40520477294933 ], [ 36.48894882202154,37.368858337402344 ], [ 36.37861633300787,37.34900283813482 ], [ 36.25526428222685,37.36342620849621 ], [ 36.212810516357536,37.51700973510748 ], [ 36.2694740295413,37.582317352295036 ], [ 36.35985565185564,37.74528121948259 ], [ 36.36010360717802,37.77470779418968 ], [ 36.31903839111345,37.83251953125 ], [ 36.31517028808622,37.88559722900396 ], [ 36.33535766601574,37.99667358398449 ], [ 36.42892074584972,38.25798416137695 ], [ 36.58495712280302,38.394802093505916 ], [ 36.67869567871122,38.50409317016607 ], [ 36.714694976806584,38.585800170898665 ], [ 36.92048263549833,38.62846374511719 ], [ 37.039100646972656,38.5945396423341 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-78", "NAME_1": "Karabük" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 32.972885131835994,41.52023315429693 ], [ 33.044803619384936,41.41645050048845 ], [ 33.01094055175798,41.37084579467779 ], [ 32.9510574340822,41.333637237549055 ], [ 32.91890335083025,41.28511047363287 ], [ 32.91732788085943,41.21456909179699 ], [ 32.92760467529314,41.195224761963175 ], [ 33.01161956787121,41.15423583984398 ], [ 33.07714080810564,41.088871002197266 ], [ 33.027935028076456,41.01646423339844 ], [ 32.6919403076173,40.957851409912166 ], [ 32.519256591796875,40.83922576904308 ], [ 32.4848175048831,40.874618530273665 ], [ 32.28196716308611,40.94109725952171 ], [ 32.28520965576189,41.00830078125006 ], [ 32.09199523925798,41.01836776733404 ], [ 32.109592437744084,41.12506103515648 ], [ 32.13407135009794,41.15750503540039 ], [ 32.202606201172046,41.19816970825195 ], [ 32.30185699462896,41.23763275146496 ], [ 32.42853927612322,41.254291534424055 ], [ 32.60932159423834,41.33967208862305 ], [ 32.656684875488565,41.3779029846192 ], [ 32.69793319702154,41.46401596069336 ], [ 32.7556343078615,41.489173889160384 ], [ 32.793640136719034,41.527175903320426 ], [ 32.8231658935548,41.51309204101574 ], [ 32.92557525634771,41.553955078125 ], [ 32.972885131835994,41.52023315429693 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-70", "NAME_1": "Karaman" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 33.82967376708996,37.38158416748058 ], [ 33.905017852783374,37.32161712646507 ], [ 33.9332160949707,37.272449493408374 ], [ 34.09875869750971,37.24098968505871 ], [ 34.19761276245134,37.17826080322277 ], [ 34.09249877929693,37.131454467773665 ], [ 33.989757537841854,37.126686096191634 ], [ 33.867404937744084,37.06111907958996 ], [ 33.75038909912104,37.02802658081066 ], [ 33.632530212402344,37.04732131958019 ], [ 33.52960968017584,37.0029754638673 ], [ 33.388763427734375,36.9991340637207 ], [ 33.11583709716814,36.85238647460943 ], [ 32.9618453979495,36.809215545654524 ], [ 33.04000473022461,36.67696380615246 ], [ 33.096580505371264,36.63430023193354 ], [ 33.217575073242244,36.58370590209978 ], [ 33.23061370849638,36.55921173095703 ], [ 33.21320724487322,36.52260971069347 ], [ 33.05472183227556,36.468769073486385 ], [ 32.795829772949276,36.431247711181754 ], [ 32.65814208984381,36.446079254150504 ], [ 32.55423355102556,36.5082168579101 ], [ 32.50381469726568,36.561042785644645 ], [ 32.45649719238298,36.674057006835994 ], [ 32.47058486938482,36.7511253356933 ], [ 32.60804748535185,36.78462219238281 ], [ 32.748134613037394,36.850887298583984 ], [ 32.80971908569347,36.9109458923341 ], [ 32.616397857666186,36.94893264770508 ], [ 32.56579208374052,36.988525390625 ], [ 32.564231872558764,37.01300811767601 ], [ 32.647991180420206,37.09346008300781 ], [ 32.68590164184576,37.157508850097656 ], [ 32.69144058227545,37.21172714233427 ], [ 32.76886367797857,37.233978271484375 ], [ 32.8411598205567,37.21237945556652 ], [ 32.900009155273494,37.213756561279524 ], [ 32.86283111572271,37.28112030029297 ], [ 32.917613983154354,37.36951446533209 ], [ 33.05659866333008,37.38821792602539 ], [ 33.11162567138672,37.448928833007756 ], [ 33.14750671386736,37.4563179016115 ], [ 33.20130920410173,37.4533424377442 ], [ 33.296306610107706,37.37743377685547 ], [ 33.353820800781534,37.375347137451286 ], [ 33.38849639892584,37.39728927612316 ], [ 33.42147827148443,37.47786331176758 ], [ 33.48609542846708,37.54191970825195 ], [ 33.64541244506853,37.604286193847884 ], [ 33.726142883301065,37.60812377929693 ], [ 33.82967376708996,37.38158416748058 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-36", "NAME_1": "Kars" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 43.59941482543974,40.98562622070335 ], [ 43.6762428283692,40.92770004272461 ], [ 43.6761093139649,40.84443664550798 ], [ 43.713020324707315,40.81192016601574 ], [ 43.74869918823248,40.73593902587896 ], [ 43.7363014221192,40.70790100097662 ], [ 43.75005340576172,40.680580139160156 ], [ 43.67522430419933,40.57935714721674 ], [ 43.64200592041021,40.55900192260759 ], [ 43.64796829223633,40.53152084350586 ], [ 43.63185882568365,40.53734588623047 ], [ 43.626861572265796,40.519538879394645 ], [ 43.545551300048885,40.47705078125 ], [ 43.61880874633795,40.41806411743164 ], [ 43.5936927795413,40.3372802734375 ], [ 43.639865875244425,40.27662277221691 ], [ 43.68171310424822,40.25849914550798 ], [ 43.681953430175724,40.22991943359381 ], [ 43.57503128051786,40.186195373535156 ], [ 43.411888122558594,40.18202590942394 ], [ 43.38365554809576,40.16720962524414 ], [ 43.393310546875114,40.13174819946289 ], [ 43.38040161132807,40.11241149902344 ], [ 43.30694961547857,40.10919952392601 ], [ 43.29211807250982,40.07103347778349 ], [ 43.34629821777361,39.99917984008789 ], [ 43.35047149658203,39.9627571105957 ], [ 43.10322189331072,40.00832748413086 ], [ 42.7108917236331,39.91766357421875 ], [ 42.627677917480526,39.92008972167963 ], [ 42.566364288330135,39.94755172729515 ], [ 42.498966217041186,40.041206359863224 ], [ 42.36748123168974,40.13149261474615 ], [ 42.205627441406534,40.16657257080078 ], [ 42.138141632080135,40.25527572631847 ], [ 42.14982986450224,40.28962326049816 ], [ 42.271778106689624,40.31632232666021 ], [ 42.51459884643572,40.41061782836914 ], [ 42.538536071777514,40.44420623779325 ], [ 42.57029724121105,40.59017562866222 ], [ 42.54808425903349,40.64073181152361 ], [ 42.61116790771479,40.64011383056635 ], [ 42.704601287841854,40.68149566650385 ], [ 42.8360137939456,40.71354293823265 ], [ 42.869586944580135,40.77029800415039 ], [ 42.87327575683611,40.85266876220709 ], [ 42.9088897705081,40.921489715576286 ], [ 42.993515014648494,40.961849212646484 ], [ 43.11260986328119,40.9844589233399 ], [ 43.21897506713884,41.02573394775402 ], [ 43.26084136962908,41.08422470092785 ], [ 43.26377487182617,41.15536499023443 ], [ 43.280563354492244,41.18324279785179 ], [ 43.36536788940441,41.20235061645525 ], [ 43.43723297119135,41.1793785095216 ], [ 43.47128295898443,41.129795074463004 ], [ 43.44977951049822,41.09215164184593 ], [ 43.47216033935547,41.02798461914085 ], [ 43.59941482543974,40.98562622070335 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-37", "NAME_1": "Kastamonu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 33.338748931884766,42.02041625976574 ], [ 33.67847061157232,41.98041534423828 ], [ 34.04680633544922,41.98208236694336 ], [ 34.22653198242193,41.95513916015648 ], [ 34.225559234619425,41.87401580810547 ], [ 34.26716613769537,41.805038452148665 ], [ 34.269077301025675,41.739074707031364 ], [ 34.4930953979495,41.72483825683594 ], [ 34.59929656982433,41.668979644775504 ], [ 34.59622573852556,41.63491439819336 ], [ 34.56705856323259,41.59246063232422 ], [ 34.46514892578131,41.540878295898494 ], [ 34.47560119628923,41.30388641357422 ], [ 34.43436813354498,41.30613327026373 ], [ 34.394657135009766,41.2771186828615 ], [ 34.29096221923845,41.16743850708008 ], [ 34.210571289062614,41.040046691894645 ], [ 34.22607040405279,41.00858306884777 ], [ 34.27907180786133,40.976325988769645 ], [ 34.27776718139654,40.92724227905302 ], [ 34.03589248657232,40.85097122192377 ], [ 33.89286422729498,40.89155578613281 ], [ 33.82385253906267,40.91936874389654 ], [ 33.78824615478521,40.95132064819336 ], [ 33.791225433349666,40.99592971801752 ], [ 33.86064910888672,41.05282211303711 ], [ 33.85814666748041,41.07776641845726 ], [ 33.82796859741228,41.09726715087902 ], [ 33.44918823242216,40.9622535705567 ], [ 33.385791778564396,40.96100616455084 ], [ 33.215167999267635,41.062389373779354 ], [ 33.14824676513672,41.087013244628906 ], [ 33.07714080810564,41.088871002197266 ], [ 32.99153137207037,41.16962051391607 ], [ 32.92760467529314,41.195224761963175 ], [ 32.913772583007926,41.275463104248274 ], [ 32.9510574340822,41.333637237549055 ], [ 33.01094055175798,41.37084579467779 ], [ 33.044803619384936,41.41645050048845 ], [ 32.95254898071295,41.546436309814624 ], [ 32.827293395996094,41.595649719238395 ], [ 32.761165618896655,41.7322998046875 ], [ 32.68097305297863,41.834583282470646 ], [ 32.914028167724666,41.87347412109381 ], [ 33.02736282348661,41.92736053466825 ], [ 33.16902923583979,41.95541763305687 ], [ 33.338748931884766,42.02041625976574 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-38", "NAME_1": "Kayseri" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.94820404052763,39.20082855224604 ], [ 36.012729644775504,39.14810180664085 ], [ 36.06792068481445,39.129901885986385 ], [ 36.30744171142578,39.130260467529524 ], [ 36.37403869628912,39.15341186523443 ], [ 36.45937347412138,39.1303596496582 ], [ 36.60339355468744,39.17564010620123 ], [ 36.77732849121122,39.175086975097656 ], [ 36.88906860351574,39.13128662109381 ], [ 36.944854736328296,39.05715942382824 ], [ 36.758411407470874,38.674396514892805 ], [ 36.7323379516601,38.591064453125 ], [ 36.69913864135748,38.57224273681646 ], [ 36.67527389526367,38.49930191040062 ], [ 36.50911712646496,38.322906494140625 ], [ 36.49144363403326,38.31632614135742 ], [ 36.47338485717802,38.336627960205135 ], [ 36.4083328247072,38.45562362670921 ], [ 36.30536651611334,38.463748931884766 ], [ 36.146896362304744,38.40219116210949 ], [ 36.00793838500982,38.18138122558594 ], [ 35.680976867676065,38.05966186523432 ], [ 35.621017456054744,37.95576095581066 ], [ 35.43716430664068,37.91958236694336 ], [ 35.26578140258795,37.959201812744254 ], [ 35.312152862548885,38.040725708007926 ], [ 35.311183929443416,38.16899108886719 ], [ 35.27957916259771,38.22149658203148 ], [ 35.236129760742244,38.254776000976506 ], [ 35.12228393554699,38.25902938842785 ], [ 35.063629150390796,38.282264709472656 ], [ 34.99367523193365,38.42170715332031 ], [ 34.92252349853521,38.43228149414068 ], [ 34.90881347656256,38.46187591552746 ], [ 34.90801239013689,38.50479125976574 ], [ 34.92678451538103,38.538246154785156 ], [ 35.018016815185604,38.565429687500114 ], [ 35.070098876953125,38.613536834716854 ], [ 35.068992614746264,38.74825668334972 ], [ 34.95324707031256,38.798259735107706 ], [ 35.002136230469034,39.013160705566406 ], [ 35.037403106689624,39.03805160522461 ], [ 35.08006668090849,39.03767395019537 ], [ 35.2412185668947,39.00565338134777 ], [ 35.482967376709155,39.099575042724666 ], [ 35.463966369628906,39.156749725341854 ], [ 35.47180557250988,39.18677139282238 ], [ 35.67707824707037,39.203239440918026 ], [ 35.81264877319347,39.29944610595703 ], [ 35.885440826416016,39.27633666992216 ], [ 35.94820404052763,39.20082855224604 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-79", "NAME_1": "Kilis" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 37.435653686523494,36.78142929077177 ], [ 37.50850296020536,36.65539550781256 ], [ 37.48497772216791,36.64108657836914 ], [ 37.14474105834972,36.66322708129883 ], [ 37.12191772460943,36.65938949584961 ], [ 37.090995788574276,36.62364578247076 ], [ 37.028041839599894,36.66057586669933 ], [ 37.0560379028322,36.72425842285162 ], [ 36.94435119628912,36.781242370605526 ], [ 36.80418395996105,36.798564910888786 ], [ 36.78188705444353,36.823947906494254 ], [ 36.80578994750982,36.8526229858399 ], [ 36.90999221801786,36.902648925781364 ], [ 36.97225952148466,36.993789672851676 ], [ 37.01332473754894,37.010478973388786 ], [ 37.124984741210994,37.01027297973644 ], [ 37.18312835693365,36.98589706420927 ], [ 37.24035644531256,36.86549377441406 ], [ 37.435653686523494,36.78142929077177 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-71", "NAME_1": "Kırıkkale" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 33.91788101196295,40.26161193847679 ], [ 34.0790176391601,40.22452926635748 ], [ 34.105388641357536,40.131149291992415 ], [ 34.198616027831974,40.03731155395508 ], [ 34.059497833252124,39.94801712036144 ], [ 34.06889724731451,39.80836868286144 ], [ 33.91082000732439,39.705814361572266 ], [ 33.85577011108393,39.563274383545036 ], [ 33.801372528076456,39.514717102050895 ], [ 33.76018142700224,39.44463348388689 ], [ 33.679565429687614,39.44376754760742 ], [ 33.58490753173834,39.38108825683594 ], [ 33.52802276611345,39.2547988891601 ], [ 33.41689682006836,39.16110992431652 ], [ 33.36560821533209,39.22562789917015 ], [ 33.390270233154354,39.27744674682617 ], [ 33.36938476562506,39.317165374755916 ], [ 33.28668594360357,39.33038711547863 ], [ 33.23331832885748,39.37669372558594 ], [ 33.2855339050293,39.46186065673851 ], [ 33.33845520019548,39.71584701538097 ], [ 33.36276245117199,39.75877761840832 ], [ 33.42865371704113,39.81058883666998 ], [ 33.60328674316435,39.89190673828142 ], [ 33.619411468506144,39.9583435058596 ], [ 33.57646942138689,40.048053741455135 ], [ 33.622394561767635,40.1554412841798 ], [ 33.70774078369146,40.2587776184082 ], [ 33.769126892090014,40.28475952148449 ], [ 33.91788101196295,40.26161193847679 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-39", "NAME_1": "Kırklareli" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 27.254264831543026,42.1054115295413 ], [ 27.32935714721691,42.0840950012207 ], [ 27.33961677551281,42.06216812133789 ], [ 27.37686729431158,42.04953002929693 ], [ 27.415891647338867,41.990142822265625 ], [ 27.509033203125,41.950714111328125 ], [ 27.551439285278548,41.89959716796875 ], [ 27.56739425659191,41.90628051757818 ], [ 27.557416915893555,41.9135856628418 ], [ 27.568567276000977,41.936641693115234 ], [ 27.668466567993107,41.952606201172046 ], [ 27.69262123107916,41.97296524047874 ], [ 27.729068756103743,41.97274398803711 ], [ 27.802497863769645,41.935733795166016 ], [ 27.82743835449247,41.945426940918026 ], [ 27.813037872314737,41.9797821044923 ], [ 27.851890563964957,41.99657440185558 ], [ 27.902822494506836,41.968566894531364 ], [ 28.03134155273466,41.98703765869152 ], [ 28.05791854858404,41.88319396972656 ], [ 28.01041793823248,41.89402770996094 ], [ 27.995695114135913,41.887638092041016 ], [ 27.970417022705192,41.86236190795904 ], [ 27.995695114135913,41.79735946655285 ], [ 28.042083740234546,41.752639770507926 ], [ 28.040973663330362,41.73125076293945 ], [ 28.105693817138842,41.66930389404308 ], [ 28.090139389038086,41.66291809082037 ], [ 28.09124946594244,41.63847351074219 ], [ 28.149583816528548,41.58051681518566 ], [ 27.977830886840934,41.54333114624018 ], [ 27.86650657653837,41.50082015991211 ], [ 27.770309448242188,41.50877761840832 ], [ 27.730844497680607,41.49436187744152 ], [ 27.67464828491228,41.4577522277832 ], [ 27.673555374145565,41.40991210937494 ], [ 27.64314651489252,41.34899902343756 ], [ 27.55360603332548,41.23656463623047 ], [ 27.520938873291016,41.22114562988281 ], [ 27.472660064697436,41.22648620605469 ], [ 27.377403259277344,41.31006622314476 ], [ 27.262168884277514,41.34740066528332 ], [ 26.914499282836857,41.33306503295921 ], [ 26.88170051574724,41.364166259765625 ], [ 26.88294029235857,41.405998229980526 ], [ 27.00078773498558,41.564857482910156 ], [ 26.997392654419002,41.62268066406273 ], [ 26.921703338623104,41.65630340576183 ], [ 26.9095973968507,41.679828643798885 ], [ 26.951318740844897,41.73140716552757 ], [ 26.96990013122553,41.812602996826286 ], [ 26.988868713378906,41.91792678833019 ], [ 26.971960067749308,41.97768783569353 ], [ 26.98307037353544,42.033229827880916 ], [ 27.01955223083496,42.05057144165045 ], [ 27.028076171875284,42.08116912841797 ], [ 27.069709777831974,42.09228515625023 ], [ 27.20951843261713,42.06493759155285 ], [ 27.20800781250017,42.083984375 ], [ 27.254264831543026,42.1054115295413 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-40", "NAME_1": "Kırşehir" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 34.22672271728521,39.74172973632841 ], [ 34.35737991333036,39.74853515625023 ], [ 34.42567825317377,39.73305511474615 ], [ 34.468528747558764,39.67209625244152 ], [ 34.544994354248104,39.622127532958984 ], [ 34.52546310424822,39.55776214599615 ], [ 34.65660095214861,39.486606597900504 ], [ 34.61058425903326,39.380512237549055 ], [ 34.60924911499029,39.327224731445426 ], [ 34.66175842285173,39.31775283813499 ], [ 34.72655868530279,39.36091613769531 ], [ 34.754566192627124,39.35155868530285 ], [ 34.686729431152514,39.26987457275385 ], [ 34.69286346435564,39.22026062011747 ], [ 34.62529754638672,39.173606872558594 ], [ 34.636188507080135,39.097076416015625 ], [ 34.56758117675787,39.0790634155274 ], [ 34.57684707641607,39.03011703491234 ], [ 34.5208091735841,38.990596771240234 ], [ 34.475379943847656,38.917903900146484 ], [ 34.473014831543026,38.88665008544933 ], [ 34.427967071533146,38.87595748901384 ], [ 34.339496612549,38.88554382324213 ], [ 34.31090545654308,38.862415313720874 ], [ 34.30298995971691,38.81587600708025 ], [ 34.26256942749052,38.793670654296875 ], [ 34.22198104858393,38.815670013427734 ], [ 34.17686462402338,38.88210296630854 ], [ 34.07765579223633,38.90355300903332 ], [ 33.98173522949247,38.965106964111385 ], [ 33.9267005920413,39.008110046386776 ], [ 33.94088363647478,39.03778457641613 ], [ 33.59801483154314,39.17142486572277 ], [ 33.52802276611345,39.2547988891601 ], [ 33.58490753173834,39.38108825683594 ], [ 33.679565429687614,39.44376754760742 ], [ 33.76018142700224,39.44463348388689 ], [ 33.801372528076456,39.514717102050895 ], [ 33.85577011108393,39.563274383545036 ], [ 33.90729522705084,39.70091247558622 ], [ 33.96332550048834,39.74765014648449 ], [ 34.06889724731451,39.80836868286144 ], [ 34.22672271728521,39.74172973632841 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-41", "NAME_1": "Kocaeli" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 30.272916793823413,41.2120819091798 ], [ 30.349306106567553,41.19291687011719 ], [ 30.37742614746088,41.162662506103516 ], [ 30.371839523315714,41.1333122253418 ], [ 30.320560455322266,41.10097122192411 ], [ 30.288484573364315,41.02032470703148 ], [ 30.36289978027372,40.95032501220726 ], [ 30.377388000488565,40.86899185180687 ], [ 30.366508483887003,40.850341796875 ], [ 30.290256500244197,40.82116317749035 ], [ 30.2994384765625,40.75570297241234 ], [ 30.22859191894537,40.62846755981451 ], [ 30.153219223022575,40.621955871582145 ], [ 30.019073486328296,40.57857131958019 ], [ 29.90131950378418,40.579971313476676 ], [ 29.766637802124308,40.61340713500999 ], [ 29.5762557983399,40.55675125122076 ], [ 29.45255661010748,40.555171966552734 ], [ 29.43100166320812,40.560283660888615 ], [ 29.432935714721737,40.679412841796875 ], [ 29.514583587646598,40.74124908447283 ], [ 29.52152824401884,40.720695495605696 ], [ 29.50736045837408,40.717361450195256 ], [ 29.56263923645048,40.68652725219738 ], [ 29.811527252197322,40.7301406860351 ], [ 29.91680526733404,40.714027404785384 ], [ 29.93680572509794,40.719860076904354 ], [ 29.940139770507812,40.755695343017805 ], [ 29.78263664245634,40.740970611572266 ], [ 29.73125076293951,40.77180480957037 ], [ 29.615139007568644,40.78263854980486 ], [ 29.57069396972662,40.76597213745123 ], [ 29.489305496215877,40.78013992309576 ], [ 29.354583740234375,40.755138397217024 ], [ 29.331806182861385,40.81624984741205 ], [ 29.257085800170955,40.802639007568416 ], [ 29.254304885864258,40.814861297607536 ], [ 29.292638778686808,40.83319473266613 ], [ 29.270696640014933,40.831806182861555 ], [ 29.265417098999023,40.8426399230957 ], [ 29.27930641174322,40.83652877807617 ], [ 29.330535888672046,40.86297988891596 ], [ 29.348457336425952,40.891124725342024 ], [ 29.419984817504826,40.92051315307623 ], [ 29.43189430236822,40.97430038452154 ], [ 29.481319427490405,41.0007019042971 ], [ 29.496175765991495,41.035736083984375 ], [ 29.652343750000057,41.01049041748058 ], [ 29.748725891113565,41.05318450927746 ], [ 29.875808715820312,41.08005142211931 ], [ 29.882820129394815,41.103969573974666 ], [ 29.863510131835994,41.14208221435558 ], [ 30.1526393890382,41.13763809204096 ], [ 30.193195343017635,41.14736175537115 ], [ 30.192361831665096,41.16208267211914 ], [ 30.22597312927263,41.16180419921875 ], [ 30.22374725341814,41.186248779296875 ], [ 30.25097274780279,41.186527252197266 ], [ 30.272916793823413,41.2120819091798 ] ] ], [ [ [ 30.264030456543026,41.21763992309593 ], [ 30.25986099243181,41.21430587768566 ], [ 30.25569534301775,41.21513748168945 ], [ 30.257360458374308,41.21763992309593 ], [ 30.264030456543026,41.21763992309593 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-42", "NAME_1": "Konya" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 33.23051834106474,39.22212600708008 ], [ 33.37403869628935,39.037906646728516 ], [ 33.36212921142584,38.791782379150504 ], [ 33.465042114257756,38.63647079467779 ], [ 33.364070892333984,38.537345886230526 ], [ 33.30143737792986,38.347045898437614 ], [ 33.240203857422046,38.24726104736351 ], [ 33.24311447143583,38.201576232910156 ], [ 33.3625679016115,38.00362014770519 ], [ 33.41840744018549,37.947883605956974 ], [ 33.495018005371264,37.93255615234381 ], [ 33.78624725341791,37.95702743530279 ], [ 34.07424926757807,38.01273727417015 ], [ 34.147918701172046,38.00718688964872 ], [ 34.326908111572436,37.856449127197266 ], [ 34.45117568969732,37.700721740722656 ], [ 34.45323562622076,37.6476287841798 ], [ 34.397258758544865,37.55559158325207 ], [ 34.380016326904354,37.47288131713867 ], [ 34.384258270263956,37.45400238037115 ], [ 34.42032623291021,37.44654464721674 ], [ 34.482170104980526,37.39559936523443 ], [ 34.51411437988298,37.333137512207145 ], [ 34.49520874023432,37.31381988525396 ], [ 34.33284759521513,37.241931915283374 ], [ 34.31916809082031,37.22196960449219 ], [ 34.19761276245134,37.17826080322277 ], [ 34.09875869750971,37.24098968505871 ], [ 33.930988311767635,37.27407455444347 ], [ 33.905017852783374,37.32161712646507 ], [ 33.82967376708996,37.38158416748058 ], [ 33.726142883301065,37.60812377929693 ], [ 33.64541244506853,37.604286193847884 ], [ 33.47241973876959,37.53235626220709 ], [ 33.406707763672046,37.454486846923885 ], [ 33.38849639892584,37.39728927612316 ], [ 33.3600692749024,37.37762451171875 ], [ 33.296306610107706,37.37743377685547 ], [ 33.20130920410173,37.4533424377442 ], [ 33.12356185913103,37.45442581176758 ], [ 33.05659866333008,37.38821792602539 ], [ 32.95408630371094,37.383758544921875 ], [ 32.89720153808622,37.35276412963867 ], [ 32.86245727539074,37.27558135986328 ], [ 32.900009155273494,37.213756561279524 ], [ 32.8411598205567,37.21237945556652 ], [ 32.76886367797857,37.233978271484375 ], [ 32.686759948730526,37.208473205566406 ], [ 32.679237365722656,37.14281845092779 ], [ 32.63539123535173,37.07808303833008 ], [ 32.567897796631144,37.01802444458008 ], [ 32.564151763916186,36.9911346435548 ], [ 32.62294769287104,36.94621276855469 ], [ 32.80971908569347,36.9109458923341 ], [ 32.748134613037394,36.850887298583984 ], [ 32.60804748535185,36.78462219238281 ], [ 32.47058486938482,36.7511253356933 ], [ 32.4174423217774,36.827526092529524 ], [ 32.29104614257841,36.85093307495117 ], [ 32.23294830322283,37.00030899047857 ], [ 31.846702575683764,37.28829956054699 ], [ 31.727830886840934,37.32756423950195 ], [ 31.459989547729435,37.34154510498041 ], [ 31.374643325805607,37.370304107666016 ], [ 31.323301315307617,37.42438888549816 ], [ 31.357999801635913,37.48129272460949 ], [ 31.365823745727823,37.54992675781273 ], [ 31.450740814209098,37.77799987792969 ], [ 31.45230293273943,37.852764129638786 ], [ 31.425519943237475,37.90036773681652 ], [ 31.424312591552905,37.96568679809582 ], [ 31.474828720093058,38.020690917968864 ], [ 31.599279403686694,38.065040588378906 ], [ 31.61876678466814,38.105682373046875 ], [ 31.586572647094897,38.14508438110357 ], [ 31.255617141723576,38.36682128906256 ], [ 31.244230270386026,38.41173171997076 ], [ 31.250438690185604,38.42662429809576 ], [ 31.679281234741325,38.63260269165045 ], [ 31.6107826232913,38.67497253417963 ], [ 31.58945655822771,38.72563552856445 ], [ 31.6233043670656,38.817733764648665 ], [ 31.708700180053995,38.95373535156273 ], [ 31.696891784668253,39.09305953979515 ], [ 31.758911132812784,39.075538635253906 ], [ 31.829113006591854,39.100021362304915 ], [ 31.86066818237333,39.167995452880916 ], [ 31.883207321167276,39.173801422119254 ], [ 31.973306655883903,39.10435485839844 ], [ 32.11332321166998,39.03137207031273 ], [ 32.2944526672365,39.06810379028326 ], [ 32.47206878662138,38.994724273681754 ], [ 32.5559196472168,39.04980850219738 ], [ 32.70268630981451,39.03284835815441 ], [ 32.742153167724666,39.082061767578125 ], [ 32.837898254394815,39.153533935546875 ], [ 32.89254760742193,39.154331207275504 ], [ 32.96263122558622,39.126510620117244 ], [ 33.021648406982706,39.15932846069347 ], [ 33.05522155761719,39.218933105468864 ], [ 33.115245819091854,39.22088241577154 ], [ 33.18780136108427,39.276828765869084 ], [ 33.23051834106474,39.22212600708008 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-43", "NAME_1": "Kütahya" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 29.562942504882926,39.89121246337896 ], [ 29.67700767517084,39.90554428100603 ], [ 29.69292449951189,39.87970352172863 ], [ 29.68674087524431,39.82540512084961 ], [ 29.722852706909237,39.74099349975609 ], [ 29.952077865600756,39.68215942382835 ], [ 30.12015342712408,39.70448303222662 ], [ 30.18699836730957,39.69670867919933 ], [ 30.137981414794922,39.62377929687523 ], [ 30.314607620239315,39.483478546142635 ], [ 30.317146301269815,39.36787796020508 ], [ 30.41478919982916,39.28709411621094 ], [ 30.45332908630388,39.20599746704107 ], [ 30.44631385803251,39.18156051635765 ], [ 30.384635925293253,39.12631988525396 ], [ 30.260791778564396,39.07954406738281 ], [ 30.17113876342802,38.902561187744254 ], [ 30.10215759277372,38.80748748779308 ], [ 29.917819976806925,38.71689987182617 ], [ 29.894367218017862,38.70968246459984 ], [ 29.89125251770048,38.79011917114258 ], [ 29.862709045410213,38.855148315429744 ], [ 29.68840217590349,38.89050674438499 ], [ 29.593931198120174,38.8758544921875 ], [ 29.50399398803728,38.83562088012707 ], [ 29.305118560791072,38.78231811523449 ], [ 29.23378944397001,38.73334121704124 ], [ 29.090955734253157,38.739379882812614 ], [ 29.03648948669445,38.72769927978521 ], [ 29.032846450805664,38.8513298034668 ], [ 29.01067733764677,38.87325668334961 ], [ 28.98968505859375,38.956939697265625 ], [ 28.95732307434082,39.008655548095646 ], [ 28.886121749877987,39.0752220153808 ], [ 28.695968627929688,39.12071228027338 ], [ 28.66218757629406,39.163825988769474 ], [ 28.661375045776367,39.2337074279788 ], [ 28.793338775634766,39.283752441406364 ], [ 28.883300781250227,39.366607666015625 ], [ 28.940580368041935,39.519817352295036 ], [ 28.934938430786246,39.550872802734546 ], [ 28.96330642700218,39.58925628662132 ], [ 29.021434783935547,39.55774688720703 ], [ 29.092315673828125,39.543609619140625 ], [ 29.229446411132983,39.55765151977539 ], [ 29.247165679931697,39.5811576843264 ], [ 29.267078399658203,39.692760467529354 ], [ 29.336360931396655,39.77615356445318 ], [ 29.406822204590014,39.90652847290045 ], [ 29.45207023620617,39.92456817626976 ], [ 29.562942504882926,39.89121246337896 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-44", "NAME_1": "Malatya" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 38.42752075195318,39.1165504455567 ], [ 38.52343368530268,39.11494064331055 ], [ 38.617038726806925,39.079467773437614 ], [ 38.65647125244135,39.05071258544916 ], [ 38.68186950683611,39.00462722778332 ], [ 38.613189697265625,39.010799407958984 ], [ 38.587699890136776,38.97869491577177 ], [ 38.631317138672046,38.876541137695426 ], [ 38.62973022460966,38.75020980834955 ], [ 38.4956245422365,38.74408340454113 ], [ 38.462364196777344,38.72850799560558 ], [ 38.34734344482439,38.5861930847168 ], [ 38.37929534912138,38.512310028076286 ], [ 38.429889678955135,38.47502899169933 ], [ 38.525379180908374,38.46200180053722 ], [ 38.684249877929744,38.41202545166021 ], [ 38.82920074462896,38.40208816528332 ], [ 38.968620300293026,38.30895233154291 ], [ 39.119144439697436,38.33825683593756 ], [ 39.142196655273494,38.285404205322266 ], [ 39.12298965454107,38.197509765625114 ], [ 39.074615478515796,38.14497375488281 ], [ 39.00511550903326,38.11749267578125 ], [ 38.85887527465832,38.09242630004883 ], [ 38.65533828735357,38.09172439575201 ], [ 38.562923431396484,38.12447357177746 ], [ 38.62433242797846,38.169216156006144 ], [ 38.634452819824276,38.19916915893566 ], [ 38.545761108398494,38.230003356933594 ], [ 38.471187591552734,38.21823120117193 ], [ 38.13481521606451,38.089435577392635 ], [ 38.18105316162115,37.91896057128906 ], [ 37.97327423095703,37.86019515991222 ], [ 37.82437133789068,37.8814582824707 ], [ 37.76950454711931,37.86634826660179 ], [ 37.73728942871122,37.83412933349632 ], [ 37.66350555419916,37.835338592529354 ], [ 37.558151245117244,37.808689117431754 ], [ 37.69754028320318,38.03805160522461 ], [ 37.77407455444353,38.22705841064459 ], [ 37.773830413818644,38.31008911132807 ], [ 37.69929885864275,38.358089447021484 ], [ 37.46228408813482,38.45021438598633 ], [ 37.36172103881853,38.46540832519531 ], [ 37.20303344726591,38.458873748779524 ], [ 37.19495010376005,38.49284362792969 ], [ 37.274082183838175,38.554397583007926 ], [ 37.29307556152372,38.59968948364269 ], [ 37.48601150512724,38.70621490478527 ], [ 37.57392501831083,38.7763786315918 ], [ 37.596317291259936,38.836570739746264 ], [ 37.5527420043947,38.92592239379883 ], [ 37.55189514160185,38.95935440063499 ], [ 37.58811187744152,39.00992202758795 ], [ 37.780391693115234,39.001106262207315 ], [ 37.93951416015625,39.059078216552734 ], [ 38.17367935180681,39.07107162475586 ], [ 38.30748748779297,39.13846969604515 ], [ 38.42752075195318,39.1165504455567 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-45", "NAME_1": "Manisa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 27.679256439208984,39.34687423706055 ], [ 27.79146385192871,39.35728836059582 ], [ 27.881540298462085,39.345581054687614 ], [ 27.896583557128906,39.35721206665045 ], [ 27.917137145996037,39.329010009765625 ], [ 27.8823184967041,39.26954650878906 ], [ 27.895751953125114,39.2360725402832 ], [ 27.978343963623274,39.22848129272484 ], [ 28.010795593261662,39.210613250732536 ], [ 28.057016372680835,39.172363281250114 ], [ 28.112621307373274,39.062858581543026 ], [ 28.15238761901861,39.045005798339844 ], [ 28.466716766357536,39.12395095825201 ], [ 28.620576858520792,39.18162918090832 ], [ 28.66218757629406,39.163825988769474 ], [ 28.70793151855463,39.11395263671898 ], [ 28.855918884277457,39.08648300170893 ], [ 28.91626358032255,39.05462646484398 ], [ 28.987447738647745,38.961959838867244 ], [ 29.03646087646507,38.83010482788097 ], [ 29.03648948669445,38.72769927978521 ], [ 28.87877845764166,38.637416839599666 ], [ 28.84781837463379,38.57641983032238 ], [ 28.840629577637003,38.49005126953148 ], [ 28.856254577636776,38.39474105834961 ], [ 28.82542800903326,38.355316162109375 ], [ 28.92095375061041,38.265453338623104 ], [ 28.801586151123104,38.218879699707145 ], [ 28.789449691772518,38.14189910888672 ], [ 28.71974372863798,38.09927368164074 ], [ 28.68299102783203,38.11477661132807 ], [ 28.559946060180778,38.108661651611385 ], [ 28.527257919311467,38.13525772094738 ], [ 28.474098205566577,38.25453948974621 ], [ 28.433549880981445,38.295082092285156 ], [ 28.22292518615734,38.33587265014654 ], [ 28.16123199462919,38.360778808593864 ], [ 28.145027160644815,38.39204025268555 ], [ 28.117492675781477,38.40279769897484 ], [ 28.001060485839787,38.399547576904524 ], [ 27.853576660156534,38.33378982543957 ], [ 27.82133483886747,38.35077285766613 ], [ 27.742670059204045,38.446926116943644 ], [ 27.56540679931652,38.48628616333025 ], [ 27.457939147949446,38.56347656250006 ], [ 27.33832931518566,38.58828735351585 ], [ 27.279998779296932,38.572151184082145 ], [ 27.22967720031761,38.741630554199446 ], [ 27.124540328979776,38.77974319458019 ], [ 27.168153762817496,38.89170837402344 ], [ 27.37003517150879,38.9268493652346 ], [ 27.387517929077205,38.95204162597662 ], [ 27.433935165405387,38.96704864501953 ], [ 27.50539588928217,39.01988601684582 ], [ 27.504394531249943,39.11765670776373 ], [ 27.470958709716797,39.1718826293947 ], [ 27.45876693725586,39.29547119140625 ], [ 27.407686233520792,39.38151550292969 ], [ 27.516485214233455,39.41384506225586 ], [ 27.612707138061694,39.36009979248047 ], [ 27.679256439208984,39.34687423706055 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-47", "NAME_1": "Mardin" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 40.80224990844732,37.717403411865234 ], [ 41.051792144775675,37.73957443237305 ], [ 41.05427551269537,37.71387100219749 ], [ 41.13343429565458,37.63745117187506 ], [ 41.18900680542009,37.556800842285384 ], [ 41.4461212158206,37.55442810058594 ], [ 41.573192596435604,37.57748413085932 ], [ 41.686473846435604,37.67586898803711 ], [ 41.8738899230957,37.74024581909191 ], [ 41.95733642578125,37.63766860961914 ], [ 41.93354797363281,37.585899353027344 ], [ 41.94921875000006,37.52552032470726 ], [ 41.90201187133795,37.49835586547857 ], [ 41.763572692871264,37.47929763793957 ], [ 41.74073028564459,37.468338012695426 ], [ 41.73814773559576,37.4432373046875 ], [ 41.73899078369158,37.33707046508789 ], [ 41.75641632080084,37.296710968017635 ], [ 41.779117584228686,37.2880554199221 ], [ 41.848300933838175,37.30717849731445 ], [ 41.86858367919933,37.276142120361385 ], [ 41.887989044189396,37.209285736083984 ], [ 41.8692359924317,37.13902282714844 ], [ 41.55814361572283,37.085227966308594 ], [ 41.27106094360357,37.07924270629883 ], [ 41.218410491943416,37.063602447509766 ], [ 41.169742584228686,37.092239379882926 ], [ 40.94995498657221,37.12441253662115 ], [ 40.885929107666186,37.124263763427734 ], [ 40.850471496582315,37.1066246032716 ], [ 40.781726837158146,37.120582580566634 ], [ 40.54626846313482,37.026714324951456 ], [ 40.438137054443416,37.00880050659174 ], [ 40.25516510009794,36.916130065918026 ], [ 40.1816139221192,36.94679260253912 ], [ 40.13233947753935,37.02339935302729 ], [ 40.11487960815458,37.130916595458984 ], [ 39.94049453735357,37.414386749267635 ], [ 39.881374359130916,37.55633163452154 ], [ 40.01730346679699,37.5563125610351 ], [ 40.09448623657255,37.589130401611555 ], [ 40.20661544799816,37.566856384277344 ], [ 40.280414581298885,37.569232940674 ], [ 40.41819000244146,37.6458854675293 ], [ 40.5161018371582,37.650424957275504 ], [ 40.535087585449276,37.67518997192394 ], [ 40.54299545288086,37.733390808105526 ], [ 40.60204696655302,37.787681579589844 ], [ 40.64764404296881,37.76625823974621 ], [ 40.715831756591854,37.761577606201286 ], [ 40.752021789550895,37.730331420898494 ], [ 40.80224990844732,37.717403411865234 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-33", "NAME_1": "Mersin" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 33.53041839599638,36.129028320312614 ], [ 33.534862518310604,36.12152862548834 ], [ 33.52875137329107,36.11930465698248 ], [ 33.53152847290039,36.124027252197266 ], [ 33.53041839599638,36.129028320312614 ] ] ], [ [ [ 33.69486236572294,36.16125106811546 ], [ 33.69819259643583,36.16041564941429 ], [ 33.69819259643583,36.159305572509766 ], [ 33.69180679321295,36.16069412231451 ], [ 33.69486236572294,36.16125106811546 ] ] ], [ [ [ 33.77958297729498,36.20097351074219 ], [ 33.77708435058588,36.18430709838884 ], [ 33.75680541992193,36.182361602783374 ], [ 33.761806488037166,36.19013977050781 ], [ 33.77958297729498,36.20097351074219 ] ] ], [ [ [ 33.828193664551065,36.26930618286161 ], [ 33.82902908325224,36.26708221435575 ], [ 33.8262481689456,36.264583587646484 ], [ 33.8256950378418,36.267360687256144 ], [ 33.828193664551065,36.26930618286161 ] ] ], [ [ [ 34.914901733398494,37.12962722778326 ], [ 34.93461608886747,37.076961517333984 ], [ 35.00078582763683,37.041458129882926 ], [ 35.05463027954107,36.97039413452154 ], [ 35.0698127746582,36.833457946777344 ], [ 35.034801483154354,36.770996093750114 ], [ 34.949817657470646,36.7540168762207 ], [ 34.90958404541021,36.72375106811546 ], [ 34.853748321533374,36.7801399230957 ], [ 34.76291656494146,36.809581756592024 ], [ 34.65402603149431,36.80764007568371 ], [ 34.560695648193644,36.76847076416021 ], [ 34.54513931274431,36.74291610717768 ], [ 34.47263717651384,36.70847320556669 ], [ 34.429862976074276,36.663749694824276 ], [ 34.27847290039074,36.585693359375 ], [ 34.168472290039006,36.466804504394645 ], [ 34.121250152588175,36.45069503784208 ], [ 34.110416412353686,36.425415039062614 ], [ 34.07930374145502,36.41041564941406 ], [ 34.07263946533209,36.31791687011736 ], [ 34.04347229003912,36.29486083984398 ], [ 33.99708175659208,36.30402755737316 ], [ 33.97652816772478,36.275970458984375 ], [ 33.99791717529325,36.28569412231457 ], [ 33.999027252197436,36.284584045410384 ], [ 33.96263885498075,36.23180389404308 ], [ 33.93763732910185,36.28958511352539 ], [ 33.87014007568388,36.31624984741205 ], [ 33.83235931396513,36.285137176513956 ], [ 33.84097290039091,36.27513885498041 ], [ 33.81486129760748,36.273750305176065 ], [ 33.80902862548834,36.2401390075683 ], [ 33.69847106933622,36.173751831054915 ], [ 33.687362670898494,36.159305572509766 ], [ 33.699859619140796,36.14319610595703 ], [ 33.6895828247072,36.13458251953142 ], [ 33.67208480834955,36.14625167846708 ], [ 33.68347167968767,36.1576385498048 ], [ 33.65930557250971,36.1601371765139 ], [ 33.661251068115405,36.18680572509777 ], [ 33.64791488647478,36.193748474121264 ], [ 33.59291839599615,36.176528930664006 ], [ 33.56097030639654,36.12541580200218 ], [ 33.474029541015796,36.159305572509766 ], [ 33.394584655761776,36.12486267089844 ], [ 33.35235977172863,36.15430450439459 ], [ 33.28930664062506,36.129028320312614 ], [ 33.14652633666998,36.137916564941634 ], [ 33.12513732910185,36.13013839721697 ], [ 33.08152770996111,36.06958389282238 ], [ 33.05180740356474,36.0948600769043 ], [ 32.9501380920413,36.10374832153349 ], [ 32.86875152587902,36.07069396972656 ], [ 32.8031959533692,36.015415191650504 ], [ 32.679306030273494,36.038471221923885 ], [ 32.566024780273494,36.099861145019474 ], [ 32.60036849975586,36.1391334533692 ], [ 32.63268661499029,36.225891113281364 ], [ 32.646808624267635,36.28602600097656 ], [ 32.63582229614252,36.38359451293945 ], [ 32.65814208984381,36.446079254150504 ], [ 32.84065246582037,36.43311691284191 ], [ 33.05472183227556,36.468769073486385 ], [ 33.21320724487322,36.52260971069347 ], [ 33.23061370849638,36.55921173095703 ], [ 33.217575073242244,36.58370590209978 ], [ 33.096580505371264,36.63430023193354 ], [ 33.04000473022461,36.67696380615246 ], [ 32.9618453979495,36.809215545654524 ], [ 33.11583709716814,36.85238647460943 ], [ 33.328708648681754,36.976009368896484 ], [ 33.39587783813505,37.00056838989269 ], [ 33.52960968017584,37.0029754638673 ], [ 33.62107849121094,37.046009063720874 ], [ 33.67952346801752,37.04685974121088 ], [ 33.740608215332315,37.026695251464844 ], [ 33.836917877197436,37.05025863647461 ], [ 33.98369598388689,37.12459564209007 ], [ 34.137424468994254,37.14317321777338 ], [ 34.31916809082031,37.22196960449219 ], [ 34.33284759521513,37.241931915283374 ], [ 34.49090576171881,37.310096740722656 ], [ 34.51411437988298,37.333137512207145 ], [ 34.50988006591825,37.34932327270508 ], [ 34.59980010986334,37.351367950439396 ], [ 34.70718383789068,37.39586639404308 ], [ 34.78332519531256,37.39600372314476 ], [ 34.914901733398494,37.12962722778326 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-48", "NAME_1": "Muğla" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 29.059860229492358,36.5420837402346 ], [ 29.061805725097656,36.54069519042986 ], [ 29.06041717529331,36.53874969482439 ], [ 29.058750152588004,36.53985977172874 ], [ 29.059860229492358,36.5420837402346 ] ] ], [ [ [ 29.07208251953125,36.55541610717785 ], [ 29.07597160339367,36.55347061157255 ], [ 29.064027786255338,36.554306030273494 ], [ 29.065694808959904,36.55541610717785 ], [ 29.07208251953125,36.55541610717785 ] ] ], [ [ [ 28.035972595214787,36.55902862548851 ], [ 28.036527633666992,36.55541610717785 ], [ 28.03513908386242,36.554584503174055 ], [ 28.03430557251005,36.55708312988281 ], [ 28.035972595214787,36.55902862548851 ] ] ], [ [ [ 28.040693283080998,36.563472747802734 ], [ 28.03847312927286,36.56124877929682 ], [ 28.035694122314794,36.56097412109398 ], [ 28.036527633666992,36.562915802002124 ], [ 28.040693283080998,36.563472747802734 ] ] ], [ [ [ 28.127082824707486,36.60069274902355 ], [ 28.129028320312614,36.595695495605526 ], [ 28.121805191040323,36.59763717651367 ], [ 28.122638702392692,36.59930419921898 ], [ 28.127082824707486,36.60069274902355 ] ] ], [ [ [ 28.056804656982877,36.619026184082145 ], [ 28.05763626098667,36.61680603027344 ], [ 28.053195953369254,36.613193511963004 ], [ 28.055414199829556,36.619026184082145 ], [ 28.056804656982877,36.619026184082145 ] ] ], [ [ [ 28.052917480468864,36.62736129760742 ], [ 28.05347251892084,36.62597274780285 ], [ 28.053749084472656,36.62319564819336 ], [ 28.050693511963345,36.62430572509771 ], [ 28.052917480468864,36.62736129760742 ] ] ], [ [ [ 28.763750076294343,36.62874984741234 ], [ 28.765138626099088,36.62680435180664 ], [ 28.761528015136662,36.62597274780285 ], [ 28.76124954223667,36.62708282470703 ], [ 28.763750076294343,36.62874984741234 ] ] ], [ [ [ 28.054582595825195,36.65013885498064 ], [ 28.05985832214361,36.649028778076456 ], [ 28.060140609741154,36.64736175537132 ], [ 28.04875183105463,36.648193359375114 ], [ 28.054582595825195,36.65013885498064 ] ] ], [ [ [ 29.1059703826906,36.65319442749046 ], [ 29.099582672119254,36.645973205566406 ], [ 29.097362518310547,36.6462516784668 ], [ 29.098196029663484,36.65263748168951 ], [ 29.1059703826906,36.65319442749046 ] ] ], [ [ [ 27.510417938232763,36.66291809082048 ], [ 27.512083053588924,36.66097259521496 ], [ 27.50930786132841,36.654582977295036 ], [ 27.5076389312747,36.65930557250982 ], [ 27.510417938232763,36.66291809082048 ] ] ], [ [ [ 29.046527862549283,36.66458511352539 ], [ 29.054304122924805,36.660415649414176 ], [ 29.043195724487248,36.65180587768555 ], [ 29.04125022888195,36.66152954101574 ], [ 29.046527862549283,36.66458511352539 ] ] ], [ [ [ 28.014303207397518,36.67013931274437 ], [ 28.014303207397518,36.6668052673341 ], [ 28.012916564941577,36.66652679443354 ], [ 28.011528015136832,36.66958236694359 ], [ 28.014303207397518,36.67013931274437 ] ] ], [ [ [ 28.895971298217944,36.67041778564476 ], [ 28.90736389160162,36.6648597717288 ], [ 28.90791702270502,36.65124893188499 ], [ 28.888748168945256,36.665973663330305 ], [ 28.895971298217944,36.67041778564476 ] ] ], [ [ [ 28.0362491607666,36.67124938964872 ], [ 28.046247482299975,36.65625000000017 ], [ 28.04152870178234,36.64958190917969 ], [ 28.027639389038143,36.659862518310774 ], [ 28.0362491607666,36.67124938964872 ] ] ], [ [ [ 29.03013801574741,36.671806335449276 ], [ 29.035972595214957,36.66875076293945 ], [ 29.036527633667333,36.6668052673341 ], [ 29.029861450195426,36.66819381713867 ], [ 29.03013801574741,36.671806335449276 ] ] ], [ [ [ 28.042083740234716,36.67319488525402 ], [ 28.041805267334325,36.66875076293945 ], [ 28.04013824462902,36.66847229003906 ], [ 28.039304733276822,36.672084808349666 ], [ 28.042083740234716,36.67319488525402 ] ] ], [ [ [ 28.91680526733404,36.68180465698265 ], [ 28.939582824707088,36.6737518310548 ], [ 28.91486167907715,36.654304504394815 ], [ 28.909305572509766,36.672084808349666 ], [ 28.91680526733404,36.68180465698265 ] ] ], [ [ [ 28.043750762939453,36.68180465698265 ], [ 28.042638778686523,36.68291854858421 ], [ 28.04513740539562,36.683471679687614 ], [ 28.04513740539562,36.68264007568365 ], [ 28.043750762939453,36.68180465698265 ] ] ], [ [ [ 28.69819450378418,36.694862365722884 ], [ 28.69819450378418,36.692638397217024 ], [ 28.690416336059684,36.69208145141607 ], [ 28.692363739013786,36.69430541992193 ], [ 28.69819450378418,36.694862365722884 ] ] ], [ [ [ 28.93291664123535,36.69736099243164 ], [ 28.93402862548868,36.69458389282249 ], [ 28.932081222534407,36.69402694702154 ], [ 28.930971145630053,36.69625091552746 ], [ 28.93291664123535,36.69736099243164 ] ] ], [ [ [ 29.00597190856945,36.699028015136946 ], [ 29.013750076294116,36.69597244262707 ], [ 29.013193130493164,36.69347381591814 ], [ 29.00597190856945,36.69374847412138 ], [ 29.00597190856945,36.699028015136946 ] ] ], [ [ [ 28.928194046020565,36.7001380920413 ], [ 28.930416107177678,36.69680404663086 ], [ 28.92597198486328,36.69291687011719 ], [ 28.923196792602937,36.698749542236555 ], [ 28.928194046020565,36.7001380920413 ] ] ], [ [ [ 27.988193511962834,36.704860687255916 ], [ 27.990415573120515,36.70264053344738 ], [ 27.98986053466797,36.700973510742415 ], [ 27.98736190795904,36.70180511474621 ], [ 27.988193511962834,36.704860687255916 ] ] ], [ [ [ 28.93486022949247,36.70875167846691 ], [ 28.935695648193416,36.70375061035156 ], [ 28.932081222534407,36.698749542236555 ], [ 28.933473587036133,36.707359313965014 ], [ 28.93486022949247,36.70875167846691 ] ] ], [ [ [ 27.997083663940828,36.710140228271484 ], [ 27.99819374084518,36.70930480957048 ], [ 27.995695114136083,36.707084655761776 ], [ 27.994583129882756,36.70902633666992 ], [ 27.997083663940828,36.710140228271484 ] ] ], [ [ [ 28.933195114135742,36.7120819091798 ], [ 28.933195114135742,36.70791625976557 ], [ 28.931804656982422,36.707359313965014 ], [ 28.92958259582531,36.709861755371094 ], [ 28.933195114135742,36.7120819091798 ] ] ], [ [ [ 28.248472213745515,36.71458435058605 ], [ 28.24735832214361,36.7120819091798 ], [ 28.242639541625977,36.713748931884936 ], [ 28.244583129883267,36.71458435058605 ], [ 28.248472213745515,36.71458435058605 ] ] ], [ [ [ 28.00180435180704,36.72013854980486 ], [ 28.004304885864713,36.71791839599632 ], [ 28.004583358765103,36.71319580078131 ], [ 27.99986076354992,36.71791839599632 ], [ 28.00180435180704,36.72013854980486 ] ] ], [ [ [ 28.033750534057674,36.72652816772478 ], [ 28.031805038452546,36.71791839599632 ], [ 28.014862060546875,36.71180725097679 ], [ 28.01513862609869,36.72236251831055 ], [ 28.033750534057674,36.72652816772478 ] ] ], [ [ [ 28.05208206176752,36.73541641235357 ], [ 28.058195114136026,36.733470916748104 ], [ 28.064027786254996,36.73485946655302 ], [ 28.0665283203125,36.733749389648665 ], [ 28.060693740845124,36.72652816772478 ], [ 28.04513740539562,36.725139617920036 ], [ 28.05208206176752,36.73541641235357 ] ] ], [ [ [ 28.93986129760748,36.73708343505888 ], [ 28.950416564941406,36.7254180908206 ], [ 28.938472747802734,36.71763992309576 ], [ 28.933750152588118,36.72402954101568 ], [ 28.93986129760748,36.73708343505888 ] ] ], [ [ [ 27.40541648864746,36.74291610717768 ], [ 27.413473129272518,36.73875045776367 ], [ 27.414028167725064,36.73764038085949 ], [ 27.404306411743107,36.74124908447294 ], [ 27.40541648864746,36.74291610717768 ] ] ], [ [ [ 27.962360382080135,36.75291824340843 ], [ 27.966247558593977,36.75208282470726 ], [ 27.965694427490575,36.74958419799816 ], [ 27.962638854980526,36.75041580200195 ], [ 27.962360382080135,36.75291824340843 ] ] ], [ [ [ 27.791528701782227,36.75319290161144 ], [ 27.792083740234375,36.75236129760765 ], [ 27.790418624878043,36.751251220703125 ], [ 27.79013633728067,36.75236129760765 ], [ 27.791528701782227,36.75319290161144 ] ] ], [ [ [ 27.76458358764654,36.75347137451183 ], [ 27.762361526489258,36.75152587890631 ], [ 27.759027481079386,36.751251220703125 ], [ 27.759860992431754,36.75263977050787 ], [ 27.76458358764654,36.75347137451183 ] ] ], [ [ [ 27.775972366333065,36.756805419921875 ], [ 27.775972366333065,36.75347137451183 ], [ 27.77375030517578,36.75208282470726 ], [ 27.773193359375,36.75485992431658 ], [ 27.775972366333065,36.756805419921875 ] ] ], [ [ [ 27.80763816833513,36.76069259643555 ], [ 27.808195114136083,36.759304046631144 ], [ 27.804582595825252,36.75763702392584 ], [ 27.80541610717819,36.760417938232706 ], [ 27.80763816833513,36.76069259643555 ] ] ], [ [ [ 28.05958366394077,36.76180648803705 ], [ 28.058471679687443,36.759304046631144 ], [ 28.055973052978914,36.759582519531364 ], [ 28.057083129883267,36.76180648803705 ], [ 28.05958366394077,36.76180648803705 ] ] ], [ [ [ 28.03430557251005,36.76235961914085 ], [ 28.03736114501953,36.76097106933594 ], [ 28.03736114501953,36.759860992431754 ], [ 28.033472061157283,36.760139465332145 ], [ 28.03430557251005,36.76235961914085 ] ] ], [ [ [ 28.12375068664545,36.762916564941406 ], [ 28.127082824707486,36.76180648803705 ], [ 28.12680625915533,36.760417938232706 ], [ 28.124305725097827,36.76097106933594 ], [ 28.12375068664545,36.762916564941406 ] ] ], [ [ [ 27.46819686889694,36.77069473266607 ], [ 27.470138549805085,36.76930618286133 ], [ 27.470138549805085,36.768196105956974 ], [ 27.467361450195426,36.76958465576172 ], [ 27.46819686889694,36.77069473266607 ] ] ], [ [ [ 27.46069526672369,36.775138854980696 ], [ 27.46458244323736,36.77236175537121 ], [ 27.464305877685547,36.77069473266607 ], [ 27.45874977111839,36.773193359375 ], [ 27.46069526672369,36.775138854980696 ] ] ], [ [ [ 28.440971374512117,36.777084350585994 ], [ 28.442638397216854,36.771526336669865 ], [ 28.430973052978743,36.77041625976568 ], [ 28.436805725097713,36.777637481689396 ], [ 28.440971374512117,36.777084350585994 ] ] ], [ [ [ 28.599027633666992,36.79763793945335 ], [ 28.597639083862248,36.795417785644815 ], [ 28.595417022705135,36.795696258545206 ], [ 28.59652709960949,36.79735946655296 ], [ 28.599027633666992,36.79763793945335 ] ] ], [ [ [ 28.258750915527287,36.809860229492244 ], [ 28.259859085083065,36.797916412353516 ], [ 28.243194580078352,36.8079185485841 ], [ 28.25319480896013,36.80736160278332 ], [ 28.258750915527287,36.809860229492244 ] ] ], [ [ [ 28.28819465637224,36.821250915527344 ], [ 28.28791618347168,36.81902694702143 ], [ 28.27819442749046,36.81958389282238 ], [ 28.278472900391023,36.82069396972673 ], [ 28.28819465637224,36.821250915527344 ] ] ], [ [ [ 28.444860458373967,36.86486053466808 ], [ 28.445972442627294,36.86291503906256 ], [ 28.445972442627294,36.862083435058764 ], [ 28.444026947021598,36.86319351196312 ], [ 28.444860458373967,36.86486053466808 ] ] ], [ [ [ 28.0262508392334,36.868751525878906 ], [ 28.027639389038143,36.865970611572266 ], [ 28.01791572570835,36.867916107177734 ], [ 28.01791572570835,36.868473052978686 ], [ 28.0262508392334,36.868751525878906 ] ] ], [ [ [ 28.03736114501953,36.871528625488395 ], [ 28.03736114501953,36.87014007568382 ], [ 28.032083511352937,36.868194580078125 ], [ 28.03430557251005,36.870693206787394 ], [ 28.03736114501953,36.871528625488395 ] ] ], [ [ [ 28.042360305786133,36.87652587890619 ], [ 28.04513740539562,36.87625122070335 ], [ 28.045415878296183,36.87458419799805 ], [ 28.042360305786133,36.8731956481933 ], [ 28.042360305786133,36.87652587890619 ] ] ], [ [ [ 28.03458404541061,36.885692596435774 ], [ 28.0362491607666,36.88402938842785 ], [ 28.03430557251005,36.882637023925724 ], [ 28.033750534057674,36.88541793823259 ], [ 28.03458404541061,36.885692596435774 ] ] ], [ [ [ 28.15569496154808,36.93763732910179 ], [ 28.1576385498048,36.93458175659191 ], [ 28.154861450195312,36.93347167968773 ], [ 28.153194427490575,36.935699462890625 ], [ 28.15569496154808,36.93763732910179 ] ] ], [ [ [ 28.15458297729532,36.94597244262718 ], [ 28.156805038452433,36.945137023926065 ], [ 28.155971527099666,36.94374847412132 ], [ 28.15402984619135,36.94402694702171 ], [ 28.15458297729532,36.94597244262718 ] ] ], [ [ [ 27.30624961853067,36.9523620605471 ], [ 27.306528091431062,36.95097351074219 ], [ 27.304582595825195,36.94985961914068 ], [ 27.303472518921012,36.95180511474615 ], [ 27.30624961853067,36.9523620605471 ] ] ], [ [ [ 28.19847488403326,36.96374893188488 ], [ 28.200138092041016,36.958751678467024 ], [ 28.18930435180704,36.95791625976591 ], [ 28.193195343017692,36.96180725097673 ], [ 28.19847488403326,36.96374893188488 ] ] ], [ [ [ 27.579305648803654,36.977085113525675 ], [ 27.577917098999478,36.97819519042963 ], [ 27.581527709961335,36.97874832153343 ], [ 27.58097267150879,36.97763824462908 ], [ 27.579305648803654,36.977085113525675 ] ] ], [ [ [ 27.65569686889677,36.979862213134936 ], [ 27.65736198425293,36.97874832153343 ], [ 27.65736198425293,36.97763824462908 ], [ 27.655136108398438,36.97902679443382 ], [ 27.65569686889677,36.979862213134936 ] ] ], [ [ [ 27.58958244323742,36.980140686035156 ], [ 27.60013961791998,36.97541809082037 ], [ 27.60208320617687,36.96652603149414 ], [ 27.591806411743505,36.96847152709984 ], [ 27.58958244323742,36.980140686035156 ] ] ], [ [ [ 27.23180580139166,36.98708343505865 ], [ 27.232639312744595,36.9859733581543 ], [ 27.233194351196403,36.98152923584007 ], [ 27.229028701782568,36.983196258545206 ], [ 27.23180580139166,36.98708343505865 ] ] ], [ [ [ 27.197639465332486,36.993751525879134 ], [ 27.199306488037053,36.99291610717802 ], [ 27.199028015136662,36.991527557373274 ], [ 27.195692062378214,36.99236297607422 ], [ 27.197639465332486,36.993751525879134 ] ] ], [ [ [ 28.20624732971197,36.99569320678728 ], [ 28.20986175537155,36.990699768066634 ], [ 28.200416564941406,36.99097061157249 ], [ 28.20180511474632,36.99347305297857 ], [ 28.20624732971197,36.99569320678728 ] ] ], [ [ [ 27.428195953369084,36.997638702392635 ], [ 27.484029769897518,36.97763824462908 ], [ 27.492639541626147,36.96736145019531 ], [ 27.476528167725007,36.95791625976591 ], [ 27.445693969726562,36.96986007690441 ], [ 27.428195953369084,36.997638702392635 ] ] ], [ [ [ 28.208751678467195,36.999584197998104 ], [ 28.209583282471158,36.997081756592024 ], [ 28.204860687255803,36.997917175293196 ], [ 28.205137252807617,36.999584197998104 ], [ 28.208751678467195,36.999584197998104 ] ] ], [ [ [ 27.385139465332315,37.00180435180664 ], [ 27.386806488037053,36.997360229492415 ], [ 27.384027481079556,36.99013900756836 ], [ 27.379583358764762,36.99486160278349 ], [ 27.385139465332315,37.00180435180664 ] ] ], [ [ [ 28.241249084472656,37.003471374511946 ], [ 28.241804122925203,37.00152587890625 ], [ 28.23791694641119,37.0020828247072 ], [ 28.23791694641119,37.0029182434082 ], [ 28.241249084472656,37.003471374511946 ] ] ], [ [ [ 27.180971145630224,37.006248474121264 ], [ 27.183471679687727,37.00569534301786 ], [ 27.183471679687727,37.00485992431652 ], [ 27.180416107177848,37.00430679321312 ], [ 27.180971145630224,37.006248474121264 ] ] ], [ [ [ 27.36013793945358,37.01069259643583 ], [ 27.362361907959098,37.00763702392601 ], [ 27.359304428100643,37.005973815918026 ], [ 27.356805801391545,37.01013946533226 ], [ 27.36013793945358,37.01069259643583 ] ] ], [ [ [ 27.21986007690475,37.01347351074213 ], [ 27.224304199218807,37.00819396972656 ], [ 27.2048606872562,36.99625015258789 ], [ 27.203193664550895,36.99874877929699 ], [ 27.21986007690475,37.01347351074213 ] ] ], [ [ [ 27.203472137451286,37.05097198486351 ], [ 27.203472137451286,37.04597091674816 ], [ 27.198192596435717,37.04902648925804 ], [ 27.200416564941406,37.05097198486351 ], [ 27.203472137451286,37.05097198486351 ] ] ], [ [ [ 27.213472366333065,37.08986282348627 ], [ 27.213750839233626,37.08430480957031 ], [ 27.204027175903263,37.082359313964844 ], [ 27.207639694214265,37.08930587768572 ], [ 27.213472366333065,37.08986282348627 ] ] ], [ [ [ 27.236803054809684,37.090694427490234 ], [ 27.240695953369084,37.08902740478533 ], [ 27.241249084473054,37.08763885498058 ], [ 27.23208427429205,37.088748931884766 ], [ 27.236803054809684,37.090694427490234 ] ] ], [ [ [ 27.47486114501953,37.124027252197436 ], [ 27.47291755676315,37.11847305297846 ], [ 27.46958351135254,37.11819458007807 ], [ 27.46902847290073,37.11958312988281 ], [ 27.47486114501953,37.124027252197436 ] ] ], [ [ [ 27.481807708740575,37.13069534301775 ], [ 27.480695724487248,37.12513732910179 ], [ 27.47708129882824,37.12513732910179 ], [ 27.47791671752975,37.129028320312614 ], [ 27.481807708740575,37.13069534301775 ] ] ], [ [ [ 27.256528854370572,37.13375091552757 ], [ 27.257917404174748,37.132915496826456 ], [ 27.257917404174748,37.13097381591791 ], [ 27.255418777466218,37.1318054199221 ], [ 27.256528854370572,37.13375091552757 ] ] ], [ [ [ 27.394027709961335,37.140415191650334 ], [ 27.389028549194734,37.13624954223633 ], [ 27.385139465332315,37.13763809204107 ], [ 27.385414123535156,37.13958358764654 ], [ 27.394027709961335,37.140415191650334 ] ] ], [ [ [ 27.53236389160162,37.165138244628906 ], [ 27.52874946594261,37.14125061035185 ], [ 27.489860534668082,37.14125061035185 ], [ 27.49458312988287,37.15680694580084 ], [ 27.53236389160162,37.165138244628906 ] ] ], [ [ [ 27.36291885376005,37.1751403808596 ], [ 27.378194808960018,37.16764068603533 ], [ 27.379028320312955,37.16319274902355 ], [ 27.367359161377294,37.16236114501976 ], [ 27.36291885376005,37.1751403808596 ] ] ], [ [ [ 27.355972290039176,37.17708206176775 ], [ 27.35958480834961,37.176250457763956 ], [ 27.360414505004996,37.1740264892581 ], [ 27.354028701782624,37.17235946655296 ], [ 27.355972290039176,37.17708206176775 ] ] ], [ [ [ 27.521249771118335,37.19736099243187 ], [ 27.522918701172046,37.196529388427734 ], [ 27.522918701172046,37.19569396972656 ], [ 27.519027709961392,37.196804046630916 ], [ 27.521249771118335,37.19736099243187 ] ] ], [ [ [ 27.55013656616211,37.202640533447436 ], [ 27.55180549621582,37.20097351074213 ], [ 27.552360534668026,37.19791793823265 ], [ 27.55069351196289,37.19847106933622 ], [ 27.55013656616211,37.202640533447436 ] ] ], [ [ [ 27.55013656616211,37.25374984741211 ], [ 27.563747406006314,37.24708175659197 ], [ 27.563747406006314,37.24458312988287 ], [ 27.54874992370617,37.25069427490263 ], [ 27.55013656616211,37.25374984741211 ] ] ], [ [ [ 27.5598602294923,37.255138397217024 ], [ 27.56097221374523,37.25430679321289 ], [ 27.56125068664562,37.25319290161133 ], [ 27.558750152587947,37.2540283203125 ], [ 27.5598602294923,37.255138397217024 ] ] ], [ [ [ 27.369581222534407,37.28291702270508 ], [ 27.365417480469148,37.27986145019537 ], [ 27.36319351196289,37.28041839599632 ], [ 27.3665275573735,37.28486251831055 ], [ 27.369581222534407,37.28291702270508 ] ] ], [ [ [ 28.478357315063647,37.4941978454591 ], [ 28.60888862609869,37.4764137268067 ], [ 28.615867614746094,37.3905487060548 ], [ 28.74400711059576,37.35529327392578 ], [ 28.786222457886026,37.24433517456066 ], [ 28.928304672241268,37.20682525634794 ], [ 29.0329914093017,37.144401550293196 ], [ 29.063364028930664,37.104351043701286 ], [ 29.05659675598173,37.07457733154297 ], [ 29.07584381103527,37.047645568847656 ], [ 29.081838607788143,36.99150466918945 ], [ 29.19094657897955,36.88718414306652 ], [ 29.266778945923136,36.884883880615234 ], [ 29.329647064209155,36.95889282226574 ], [ 29.33764457702665,37.040996551513786 ], [ 29.387758255004826,37.076091766357536 ], [ 29.408311843872355,37.02462768554693 ], [ 29.39665603637701,36.950046539306754 ], [ 29.44611740112333,36.96438980102539 ], [ 29.511768341064737,37.024211883545036 ], [ 29.546728134155217,37.027606964111555 ], [ 29.62462997436529,36.99750900268566 ], [ 29.6769447326663,36.932643890381144 ], [ 29.6735973358156,36.87476730346697 ], [ 29.604988098144702,36.779148101806754 ], [ 29.57402038574247,36.61486434936529 ], [ 29.32302856445341,36.4380264282226 ], [ 29.32847785949724,36.40187454223644 ], [ 29.29306030273466,36.31244659423851 ], [ 29.262361526489315,36.3009681701663 ], [ 29.226249694824276,36.32875061035173 ], [ 29.164863586425838,36.340972900390625 ], [ 29.13819694519077,36.35985946655279 ], [ 29.14541625976608,36.37819290161144 ], [ 29.10124969482439,36.387084960937784 ], [ 29.102916717529695,36.40458297729492 ], [ 29.131526947021882,36.41569519042997 ], [ 29.117916107177678,36.425415039062614 ], [ 29.133474349975586,36.42791748046869 ], [ 29.124860763549805,36.461528778076456 ], [ 29.100696563721158,36.47458267211914 ], [ 29.125972747802734,36.496528625488565 ], [ 29.125694274902344,36.54236221313499 ], [ 29.11208534240768,36.554584503174055 ], [ 29.09708595275913,36.54513931274431 ], [ 29.086250305175838,36.56513977050804 ], [ 29.049304962158203,36.55847167968756 ], [ 29.053474426269588,36.53874969482439 ], [ 29.008472442626953,36.543472290039176 ], [ 29.046806335449673,36.55819320678734 ], [ 29.02236175537115,36.58597183227539 ], [ 29.04013824462936,36.61986160278332 ], [ 29.07541656494186,36.61430740356474 ], [ 29.07764053344738,36.6462516784668 ], [ 29.101804733276367,36.6409721374514 ], [ 29.089582443237305,36.61986160278332 ], [ 29.115972518920955,36.62652587890642 ], [ 29.12208557128946,36.64736175537132 ], [ 29.103195190429688,36.67124938964872 ], [ 29.054304122924805,36.68152618408209 ], [ 29.03319549560547,36.70791625976557 ], [ 29.013193130493164,36.704303741455305 ], [ 29.020416259765625,36.715415954589844 ], [ 28.9959716796875,36.70819473266613 ], [ 28.97097206115734,36.730972290039176 ], [ 28.964862823486385,36.72236251831055 ], [ 28.928750991821346,36.75513839721697 ], [ 28.929859161377294,36.73430633544922 ], [ 28.894306182861385,36.7120819091798 ], [ 28.909305572509766,36.70541763305687 ], [ 28.864582061767692,36.69708251953125 ], [ 28.869028091431062,36.67097091674816 ], [ 28.850971221924055,36.663471221923885 ], [ 28.866249084472997,36.654026031494254 ], [ 28.85014152526867,36.64319610595709 ], [ 28.87041664123541,36.63347244262695 ], [ 28.880416870117188,36.648750305175895 ], [ 28.906803131103516,36.639583587646484 ], [ 28.868473052978516,36.621807098388615 ], [ 28.8756942749024,36.60180664062506 ], [ 28.845693588256893,36.58819580078125 ], [ 28.824306488037166,36.62569427490263 ], [ 28.851249694824617,36.63763809204096 ], [ 28.830694198608512,36.63874816894531 ], [ 28.818195343017635,36.65930557250982 ], [ 28.794027328491268,36.6504173278808 ], [ 28.806526184082145,36.669029235840014 ], [ 28.79013824462885,36.685974121093864 ], [ 28.727916717529297,36.71180725097679 ], [ 28.67013931274454,36.69152832031267 ], [ 28.673749923706396,36.70597076416027 ], [ 28.6479167938233,36.721805572509766 ], [ 28.632917404174748,36.69985961914091 ], [ 28.61791610717779,36.70347213745117 ], [ 28.624305725097713,36.727638244629134 ], [ 28.60708427429205,36.733749389648665 ], [ 28.632917404174748,36.75485992431658 ], [ 28.61291694641119,36.759304046631144 ], [ 28.630138397216854,36.78152847290062 ], [ 28.58763885498047,36.815418243408374 ], [ 28.549306869506893,36.830417633056925 ], [ 28.54874992370651,36.81430435180681 ], [ 28.529029846191747,36.8070831298831 ], [ 28.53597259521507,36.785694122314624 ], [ 28.489583969116268,36.79902648925787 ], [ 28.498193740844897,36.81791687011747 ], [ 28.462083816528434,36.81124877929716 ], [ 28.45069503784191,36.84569549560547 ], [ 28.469306945800895,36.862361907958984 ], [ 28.455694198608512,36.87930679321306 ], [ 28.432916641235465,36.8576393127442 ], [ 28.407360076904354,36.85402679443354 ], [ 28.402914047241552,36.86652755737322 ], [ 28.379861831665494,36.847637176513615 ], [ 28.387916564941406,36.83514022827171 ], [ 28.426805496215934,36.835693359375284 ], [ 28.398195266723746,36.78458404541027 ], [ 28.31125068664545,36.81708145141613 ], [ 28.301527023315487,36.803749084472884 ], [ 28.314029693603516,36.794860839843864 ], [ 28.2859725952153,36.79042053222679 ], [ 28.26569366455118,36.81402587890625 ], [ 28.31263732910162,36.81791687011747 ], [ 28.315416336059684,36.826805114746094 ], [ 28.277639389038086,36.85235977172863 ], [ 28.25930786132824,36.84625244140642 ], [ 28.232915878296012,36.80430984497082 ], [ 28.256526947021598,36.791805267333984 ], [ 28.249027252197322,36.7726402282716 ], [ 28.26791572570812,36.765972137451286 ], [ 28.269304275513036,36.74708175659191 ], [ 28.291805267334098,36.74902725219721 ], [ 28.303472518921353,36.730140686035384 ], [ 28.28819465637224,36.71986007690447 ], [ 28.26152992248535,36.7329177856447 ], [ 28.225694656372298,36.70236206054699 ], [ 28.224306106567383,36.68819427490257 ], [ 28.163749694824332,36.684307098388956 ], [ 28.106250762939396,36.59208297729492 ], [ 28.088752746582486,36.58208465576189 ], [ 28.06624984741211,36.59513854980497 ], [ 28.02541732788086,36.56097412109398 ], [ 28.01097106933605,36.57624816894537 ], [ 28.01791572570835,36.56458282470726 ], [ 27.97874832153326,36.55374908447294 ], [ 27.965137481689624,36.57986068725603 ], [ 27.97874832153326,36.58625030517595 ], [ 27.956249237060604,36.6012496948245 ], [ 28.062362670898835,36.604862213134766 ], [ 28.095138549804688,36.6462516784668 ], [ 28.07208251953125,36.660415649414176 ], [ 28.072917938232422,36.65847396850603 ], [ 28.0665283203125,36.64208221435558 ], [ 28.057083129883267,36.63541793823265 ], [ 28.068195343017805,36.65569305419922 ], [ 28.052639007568473,36.657638549804915 ], [ 28.072359085083065,36.67541503906273 ], [ 28.05041694641119,36.67319488525402 ], [ 28.04125022888195,36.69291687011719 ], [ 28.04041671752941,36.67402648925781 ], [ 28.02402687072771,36.66791534423845 ], [ 27.963472366333065,36.684307098388956 ], [ 28.001527786254883,36.704303741455305 ], [ 28.042360305786133,36.70375061035156 ], [ 28.061250686645508,36.72319412231468 ], [ 28.097919464111328,36.72680664062494 ], [ 28.085418701171875,36.71763992309576 ], [ 28.099029541015682,36.70513916015648 ], [ 28.112640380859318,36.72819519042969 ], [ 28.1293048858646,36.72569274902344 ], [ 28.0845832824711,36.7434730529788 ], [ 28.112361907958928,36.774581909179915 ], [ 28.128469467163086,36.754306793213175 ], [ 28.133472442627408,36.757083892822436 ], [ 28.120138168335018,36.803199768066634 ], [ 28.08208274841303,36.79624938964861 ], [ 28.078750610351562,36.775138854980696 ], [ 28.05125045776373,36.759582519531364 ], [ 28.046247482299975,36.78486251831083 ], [ 28.014303207397518,36.75847244262718 ], [ 27.95597267150879,36.76097106933594 ], [ 27.930416107178075,36.742084503173885 ], [ 27.91986083984375,36.754581451416016 ], [ 27.89458274841303,36.756805419921875 ], [ 27.89902877807623,36.74242782592796 ], [ 27.89069366455078,36.74097061157238 ], [ 27.877639770507926,36.75791549682623 ], [ 27.858472824096737,36.74124908447294 ], [ 27.816249847412166,36.7631950378418 ], [ 27.730693817138615,36.7631950378418 ], [ 27.686527252197664,36.7254180908206 ], [ 27.696250915527457,36.71097183227562 ], [ 27.675970077514762,36.70041656494146 ], [ 27.678749084472827,36.657638549804915 ], [ 27.573474884033658,36.68486022949236 ], [ 27.56125068664562,36.672359466552905 ], [ 27.51402854919462,36.67736053466808 ], [ 27.47708129882824,36.64708328247093 ], [ 27.46847152709961,36.66152954101574 ], [ 27.404861450195312,36.66236114501953 ], [ 27.40236091613781,36.680416107177734 ], [ 27.36291885376005,36.6845817565918 ], [ 27.373195648193416,36.689582824707145 ], [ 27.36291885376005,36.709861755371094 ], [ 27.398193359375,36.70041656494146 ], [ 27.42124938964878,36.713470458984546 ], [ 27.428195953369084,36.748470306396655 ], [ 27.447916030883846,36.7448616027832 ], [ 27.464305877685547,36.76235961914085 ], [ 27.479585647583463,36.74986267089872 ], [ 27.609861373901367,36.76402664184576 ], [ 27.640415191650447,36.8109703063966 ], [ 27.69680786132824,36.78513717651367 ], [ 27.771804809570256,36.78847122192394 ], [ 27.827083587646484,36.81347274780302 ], [ 28.03291893005371,36.78763961791998 ], [ 28.06041717529297,36.800971984863395 ], [ 28.065139770507926,36.82097244262695 ], [ 28.055973052978914,36.8337516784668 ], [ 28.002361297607422,36.83514022827171 ], [ 28.029861450195256,36.83708572387724 ], [ 28.031248092651424,36.839027404785384 ], [ 28.00013923645031,36.853473663330135 ], [ 28.05903053283697,36.87874984741211 ], [ 28.04041671752941,36.88430404663103 ], [ 28.05041694641119,36.897083282470874 ], [ 28.014303207397518,36.9056930541995 ], [ 28.043750762939453,36.910137176513956 ], [ 28.020694732666414,36.92569351196306 ], [ 28.099582672119084,36.94041824340826 ], [ 28.13903045654297,36.93458175659191 ], [ 28.145971298217717,36.91875076293957 ], [ 28.159027099609375,36.926532745361385 ], [ 28.159582138061523,36.90791702270525 ], [ 28.16791725158697,36.906806945801065 ], [ 28.17069435119663,36.93958282470726 ], [ 28.158193588257177,36.94541549682623 ], [ 28.20569419860874,36.95208358764654 ], [ 28.200971603393555,36.96930694580101 ], [ 28.21597290039108,36.977359771728516 ], [ 28.197082519531705,36.982360839843864 ], [ 28.215139389038143,36.98513793945335 ], [ 28.21569442749052,36.99874877929699 ], [ 28.250694274902628,36.98986053466797 ], [ 28.2451362609865,37.003192901611555 ], [ 28.268194198608683,37.01652908325218 ], [ 28.330415725708065,37.032360076904524 ], [ 28.322914123535384,37.05152893066429 ], [ 28.163749694824332,37.02847290039068 ], [ 28.10097312927263,37.03458404541021 ], [ 28.115694046020792,37.01541519165045 ], [ 28.0998592376709,37.01180648803722 ], [ 28.08764076232916,37.02875137329124 ], [ 27.97819519043003,37.03180694580095 ], [ 27.94597244262701,37.0159721374514 ], [ 27.92569351196289,37.03097152709961 ], [ 27.843748092651595,37.018470764160156 ], [ 27.79958343505865,36.99486160278349 ], [ 27.786804199218807,37.005973815918026 ], [ 27.781251907348633,36.99236297607422 ], [ 27.685140609741325,37.003471374511946 ], [ 27.64736175537115,36.997917175293196 ], [ 27.636249542236442,36.97763824462908 ], [ 27.574026107788086,36.993751525879134 ], [ 27.564582824707088,36.97458267211937 ], [ 27.518472671508846,36.99514007568371 ], [ 27.48291778564493,36.98625183105486 ], [ 27.424303054809684,37.035694122314396 ], [ 27.41263961792015,37.01680374145519 ], [ 27.395971298217887,37.029304504394474 ], [ 27.37624931335489,36.99874877929699 ], [ 27.382638931274812,37.026527404785384 ], [ 27.330974578857422,37.014583587646484 ], [ 27.340415954589844,36.99847412109375 ], [ 27.300416946411133,36.9726371765139 ], [ 27.30402755737299,36.95735931396496 ], [ 27.263471603393725,36.96402740478544 ], [ 27.25013923645065,37.03125 ], [ 27.22541427612316,37.058471679687784 ], [ 27.238750457763956,37.08319473266596 ], [ 27.293472290039062,37.110973358154354 ], [ 27.254583358764705,37.11152648925798 ], [ 27.25513839721725,37.13097381591791 ], [ 27.264028549194677,37.120140075683594 ], [ 27.273471832275504,37.140693664550724 ], [ 27.311527252197266,37.11541748046881 ], [ 27.32319450378418,37.159305572509936 ], [ 27.343193054199332,37.150138854980696 ], [ 27.34513854980503,37.13041687011736 ], [ 27.364860534668196,37.15708160400419 ], [ 27.390417098999478,37.14485931396496 ], [ 27.376529693603686,37.13402938842796 ], [ 27.386526107788086,37.120418548583984 ], [ 27.43041610717779,37.128471374512 ], [ 27.470972061157283,37.08069610595726 ], [ 27.537361145019645,37.12874984741222 ], [ 27.581527709961335,37.13680648803728 ], [ 27.57513618469244,37.13930511474638 ], [ 27.557081222534237,37.13347244262701 ], [ 27.549861907959098,37.13569259643572 ], [ 27.56097221374523,37.15458297729492 ], [ 27.541528701782454,37.15402603149437 ], [ 27.546527862549226,37.18430709838867 ], [ 27.526250839233512,37.194026947021655 ], [ 27.5548610687257,37.1929168701173 ], [ 27.570692062378043,37.211528778076286 ], [ 27.593471527099666,37.19347381591825 ], [ 27.574583053588867,37.179027557373104 ], [ 27.599861145019588,37.196250915527514 ], [ 27.610137939453523,37.18708419799833 ], [ 27.615137100220124,37.18847274780268 ], [ 27.57541847229021,37.21402740478521 ], [ 27.612916946411588,37.27986145019537 ], [ 27.556804656982422,37.27763748168951 ], [ 27.540971755981502,37.2540283203125 ], [ 27.552360534668026,37.24486160278326 ], [ 27.53486061096197,37.25152587890642 ], [ 27.52680587768549,37.22847366333036 ], [ 27.51069450378418,37.22763824462902 ], [ 27.498750686645508,37.237361907958984 ], [ 27.522361755371094,37.25041580200224 ], [ 27.518472671508846,37.27680587768572 ], [ 27.45430755615274,37.255416870117244 ], [ 27.497360229492358,37.31597137451183 ], [ 27.47791671752975,37.34430694580101 ], [ 27.470693588256893,37.3193054199221 ], [ 27.443195343017635,37.302360534668196 ], [ 27.411804199218807,37.3048629760745 ], [ 27.385414123535156,37.328193664550724 ], [ 27.383192062378043,37.3570823669433 ], [ 27.413473129272518,37.383750915527344 ], [ 27.432638168335302,37.381248474121094 ], [ 27.416358947754134,37.42242813110374 ], [ 27.444992065429744,37.505565643310604 ], [ 27.488868713378963,37.56693649291992 ], [ 27.516687393188477,37.57382965087902 ], [ 27.698598861694563,37.49717712402338 ], [ 27.884967803955192,37.45704269409197 ], [ 28.14990234375,37.47454833984375 ], [ 28.220544815063704,37.562210083007926 ], [ 28.294479370117188,37.586898803710994 ], [ 28.478357315063647,37.4941978454591 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-49", "NAME_1": "Muş" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 42.72718811035173,39.16370010375988 ], [ 42.76899337768549,38.94040298461914 ], [ 42.68435287475603,38.926906585693416 ], [ 42.56119918823248,38.94335556030279 ], [ 42.4895858764649,38.9266815185548 ], [ 42.328445434570426,38.93886566162132 ], [ 42.13997268676758,38.87031555175781 ], [ 42.139369964599894,38.824989318847884 ], [ 42.023853302002124,38.8231315612793 ], [ 41.9985084533692,38.81031799316412 ], [ 42.00059890747076,38.785957336426065 ], [ 42.054039001464844,38.728683471679744 ], [ 42.056205749511776,38.69475173950195 ], [ 41.940517425537166,38.61808013916027 ], [ 41.863296508789006,38.590469360351506 ], [ 41.632709503173885,38.60134506225609 ], [ 41.57016754150408,38.58500671386719 ], [ 41.52218246459961,38.541912078857706 ], [ 41.40530395507841,38.52570343017584 ], [ 41.381370544433594,38.54735183715826 ], [ 41.394565582275334,38.60486221313488 ], [ 41.377975463867244,38.63625335693354 ], [ 41.279525756835994,38.705539703369254 ], [ 41.15648269653349,38.89936828613304 ], [ 41.161922454834155,38.920677185058594 ], [ 41.274494171142635,39.02955627441406 ], [ 41.274139404297046,39.11057281494152 ], [ 41.23756408691412,39.15412902832031 ], [ 41.204399108886776,39.16355514526367 ], [ 41.171733856201286,39.28934097290062 ], [ 41.19566345214855,39.34185791015631 ], [ 41.255546569824276,39.369392395019645 ], [ 41.386318206787394,39.383571624755916 ], [ 41.44354248046892,39.366619110107536 ], [ 41.53429412841797,39.32184219360346 ], [ 41.66228103637701,39.20041656494152 ], [ 41.71326828002958,39.17493057250988 ], [ 41.82796478271513,39.161075592041016 ], [ 42.074256896972656,39.222366333007926 ], [ 42.218486785888786,39.32173919677746 ], [ 42.22022247314453,39.34602355957048 ], [ 42.19287490844732,39.381523132324276 ], [ 42.227268218994425,39.41969680786127 ], [ 42.32644271850597,39.459419250488395 ], [ 42.463413238525675,39.48609924316412 ], [ 42.51290893554716,39.37992477417015 ], [ 42.62761688232439,39.27266311645508 ], [ 42.6687965393067,39.25415039062523 ], [ 42.72718811035173,39.16370010375988 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-50", "NAME_1": "Nevşehir" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 34.856098175048885,39.36425018310558 ], [ 34.92192459106457,39.33542633056652 ], [ 34.89593505859369,39.227462768554744 ], [ 34.99610900878923,39.140846252441634 ], [ 35.002208709716854,39.09674072265625 ], [ 35.037403106689624,39.03805160522461 ], [ 35.00083923339838,39.010292053222656 ], [ 34.95324707031256,38.798259735107706 ], [ 35.068992614746264,38.74825668334972 ], [ 35.070098876953125,38.613536834716854 ], [ 35.018016815185604,38.565429687500114 ], [ 34.92493057250982,38.53613662719732 ], [ 34.906982421875284,38.490486145019645 ], [ 34.91961669921892,38.398212432861555 ], [ 34.87619018554693,38.364654541015625 ], [ 34.79171752929693,38.35210037231457 ], [ 34.670738220215014,38.408721923828125 ], [ 34.53929519653326,38.37565231323242 ], [ 34.458038330078296,38.399730682373104 ], [ 34.348003387451286,38.473419189453125 ], [ 34.27626037597656,38.61580276489258 ], [ 34.219444274902514,38.65495300292969 ], [ 34.206523895263615,38.69076919555664 ], [ 34.26256942749052,38.793670654296875 ], [ 34.30298995971691,38.81587600708025 ], [ 34.314521789550895,38.8675231933596 ], [ 34.339496612549,38.88554382324213 ], [ 34.427967071533146,38.87595748901384 ], [ 34.473014831543026,38.88665008544933 ], [ 34.475379943847656,38.917903900146484 ], [ 34.5208091735841,38.990596771240234 ], [ 34.57684707641607,39.03011703491234 ], [ 34.56758117675787,39.0790634155274 ], [ 34.636188507080135,39.097076416015625 ], [ 34.62529754638672,39.173606872558594 ], [ 34.69286346435564,39.22026062011747 ], [ 34.686729431152514,39.26987457275385 ], [ 34.754566192627124,39.35155868530285 ], [ 34.72655868530279,39.36091613769531 ], [ 34.66175842285173,39.31775283813499 ], [ 34.60924911499029,39.327224731445426 ], [ 34.61058425903326,39.380512237549055 ], [ 34.65660095214861,39.486606597900504 ], [ 34.79120254516607,39.4306373596192 ], [ 34.7947616577149,39.38988113403332 ], [ 34.856098175048885,39.36425018310558 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-51", "NAME_1": "Niğde" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 34.52778244018572,38.37610244750999 ], [ 34.670738220215014,38.408721923828125 ], [ 34.785182952881144,38.35391235351574 ], [ 34.82062530517595,38.35119628906273 ], [ 34.90371322631853,38.37690734863281 ], [ 34.92252349853521,38.43228149414068 ], [ 34.98105621337908,38.429912567138786 ], [ 35.06126403808622,38.28385162353521 ], [ 35.12228393554699,38.25902938842785 ], [ 35.24277496337896,38.25186920166027 ], [ 35.27957916259771,38.22149658203148 ], [ 35.312156677246264,38.16281127929699 ], [ 35.31087112426786,38.03140640258795 ], [ 35.26578140258795,37.959201812744254 ], [ 35.23033142089861,37.94804000854492 ], [ 35.20941543579096,37.91901397705084 ], [ 35.218376159668026,37.84157562255865 ], [ 35.19812774658203,37.81408691406273 ], [ 35.04302597045904,37.7019309997558 ], [ 34.87720870971697,37.710834503173885 ], [ 34.834575653076456,37.69160461425781 ], [ 34.81658554077154,37.65838241577154 ], [ 34.85847854614258,37.57877349853527 ], [ 34.860763549804744,37.525032043456974 ], [ 34.78827667236334,37.465160369873104 ], [ 34.78332519531256,37.39600372314476 ], [ 34.69614410400396,37.393993377685774 ], [ 34.591953277588004,37.350292205810604 ], [ 34.50988006591825,37.34932327270508 ], [ 34.469276428222656,37.40861129760742 ], [ 34.414676666259936,37.449813842773494 ], [ 34.384258270263956,37.45400238037115 ], [ 34.38123703002924,37.50630950927746 ], [ 34.45323562622076,37.6476287841798 ], [ 34.453449249267635,37.69588470458996 ], [ 34.266948699951456,37.914951324463004 ], [ 34.12569427490246,38.01376342773443 ], [ 34.14690780639654,38.05195236206055 ], [ 34.18675994873075,38.070056915283146 ], [ 34.26839065551758,38.05600738525402 ], [ 34.32982254028326,38.13497161865246 ], [ 34.393146514892635,38.16622543334961 ], [ 34.39450073242182,38.24264526367193 ], [ 34.36320114135748,38.2909202575683 ], [ 34.36829757690447,38.36765289306652 ], [ 34.394397735595646,38.43891906738287 ], [ 34.52778244018572,38.37610244750999 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-52", "NAME_1": "Ordu" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 37.171527862549,41.148193359375114 ], [ 37.29291534423828,41.145694732666016 ], [ 37.293472290039006,41.12402725219732 ], [ 37.38791656494158,41.107360839843864 ], [ 37.536529541015796,41.02097320556652 ], [ 37.60902786254911,41.048202514648665 ], [ 37.682640075683594,41.136806488037166 ], [ 37.704582214355526,41.114028930664176 ], [ 37.786251068115234,41.11708450317383 ], [ 37.776805877685604,41.06208419799816 ], [ 37.80819320678711,41.025699615478516 ], [ 37.8656959533692,41.01569366455078 ], [ 37.87819290161133,40.987361907958984 ], [ 38.12208175659208,40.957359313964844 ], [ 38.00863647460943,40.748332977295206 ], [ 38.11658096313505,40.6118354797365 ], [ 38.15565490722673,40.50869369506859 ], [ 38.02550125122076,40.41411972045904 ], [ 37.90161514282255,40.395137786865234 ], [ 37.82976531982433,40.34440231323242 ], [ 37.750797271728686,40.3297233581543 ], [ 37.707328796387,40.35209655761713 ], [ 37.60409545898443,40.555461883545036 ], [ 37.466255187988565,40.563144683837834 ], [ 37.34712219238298,40.627052307129134 ], [ 37.31242370605469,40.627868652343864 ], [ 37.29387283325201,40.66733932495134 ], [ 37.18733215332037,40.704162597656364 ], [ 37.078315734863565,40.68880844116222 ], [ 36.97516632080095,40.70256423950207 ], [ 36.9319686889649,40.73946380615263 ], [ 36.851066589355526,40.75009155273443 ], [ 36.688777923584155,40.81615447998041 ], [ 36.69670104980486,40.84641647338867 ], [ 36.82196426391607,40.87958145141596 ], [ 36.904468536376896,40.924163818359546 ], [ 36.996006011963175,41.04626083374052 ], [ 37.15253448486328,41.11470413208019 ], [ 37.15065002441423,41.14789581298845 ], [ 37.171527862549,41.148193359375114 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-80", "NAME_1": "Osmaniye" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 36.327865600585994,37.348400115966854 ], [ 36.48894882202154,37.368858337402344 ], [ 36.582782745361385,37.40520477294933 ], [ 36.65103912353544,37.32998657226568 ], [ 36.728641510009936,37.27605056762695 ], [ 36.532501220703296,37.10746383667009 ], [ 36.442592620849666,36.95328521728521 ], [ 36.34716796875006,36.95531463623047 ], [ 36.254726409912166,37.008663177490405 ], [ 36.04160690307617,37.025554656982536 ], [ 36.059387207031534,37.12387084960949 ], [ 36.000972747802734,37.17415237426786 ], [ 35.87482452392595,37.121696472168026 ], [ 35.85282516479492,37.12870788574219 ], [ 35.904296875000114,37.20827102661144 ], [ 35.881771087646484,37.241584777832145 ], [ 35.884262084960994,37.359619140625114 ], [ 36.023311614990405,37.562290191650504 ], [ 36.15035247802746,37.635444641113565 ], [ 36.302368164062614,37.651248931884936 ], [ 36.2121200561524,37.50016021728521 ], [ 36.24630355834978,37.37089157104498 ], [ 36.327865600585994,37.348400115966854 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-53", "NAME_1": "Rize" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 41.219917297363565,41.29500198364252 ], [ 41.24785232543974,41.25560760498041 ], [ 41.25561904907232,41.208522796630916 ], [ 41.3067703247072,41.155185699462834 ], [ 41.36881256103521,41.11997222900402 ], [ 41.40925979614258,41.11717605590832 ], [ 41.42398071289074,41.093452453613395 ], [ 41.41150665283203,41.06899642944336 ], [ 41.34373474121088,41.03704833984375 ], [ 41.12230682373047,40.80845260620117 ], [ 41.046794891357536,40.76273727416998 ], [ 40.82793426513683,40.65369033813488 ], [ 40.48347854614275,40.535343170166016 ], [ 40.47890853881836,40.628585815429915 ], [ 40.51181793212896,40.69040298461914 ], [ 40.5118942260745,40.741134643554744 ], [ 40.46595764160185,40.871932983398494 ], [ 40.421428680419865,40.94190979003906 ], [ 40.33486175537115,40.99541473388683 ], [ 40.3884735107423,41.02652740478527 ], [ 40.497917175293026,41.04124832153326 ], [ 40.5484733581543,41.028472900390625 ], [ 40.720973968505916,41.08763885498047 ], [ 40.8031959533692,41.16263961791992 ], [ 40.99763870239252,41.19458389282249 ], [ 41.06735992431635,41.22013854980463 ], [ 41.1529159545899,41.2826385498048 ], [ 41.219917297363565,41.29500198364252 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-54", "NAME_1": "Sakarya" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 30.36929130554205,41.17901229858427 ], [ 30.65263748168951,41.1290283203125 ], [ 30.755695343017692,41.08625030517578 ], [ 30.97593688964872,41.072639465332145 ], [ 31.036275863647518,41.016273498535156 ], [ 31.00865745544445,40.961486816406364 ], [ 30.906887054443416,40.897171020507926 ], [ 30.873615264892862,40.83534622192383 ], [ 30.89267539978033,40.77858734130854 ], [ 30.987047195434855,40.719253540039176 ], [ 30.949708938598803,40.669773101806584 ], [ 30.944461822509822,40.56676101684582 ], [ 30.9108257293704,40.5385627746582 ], [ 30.84126853942871,40.52185058593744 ], [ 30.676174163818644,40.51831817626959 ], [ 30.59339523315458,40.44031524658226 ], [ 30.6464271545413,40.38548660278343 ], [ 30.62383460998541,40.335178375244254 ], [ 30.378683090210245,40.402488708496094 ], [ 30.12273216247587,40.37049865722662 ], [ 29.97472190856962,40.471775054931754 ], [ 29.928827285766886,40.558509826660156 ], [ 29.92487716674833,40.577526092529354 ], [ 30.026767730712834,40.579669952392635 ], [ 30.24206924438505,40.6360816955567 ], [ 30.2994384765625,40.75570297241234 ], [ 30.290256500244197,40.82116317749035 ], [ 30.376861572265568,40.86356735229492 ], [ 30.36289978027372,40.95032501220726 ], [ 30.288484573364315,41.02032470703148 ], [ 30.320560455322266,41.10097122192411 ], [ 30.375438690185547,41.1376838684082 ], [ 30.36929130554205,41.17901229858427 ] ] ], [ [ [ 30.36929130554205,41.17901229858427 ], [ 30.368911743164062,41.17930603027355 ], [ 30.369304656982706,41.17930603027355 ], [ 30.36929130554205,41.17901229858427 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-55", "NAME_1": "Samsun" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 37.032897949219034,41.19848632812523 ], [ 37.03131103515631,41.198730468750114 ], [ 37.03131103515631,41.19927978515631 ], [ 37.0333251953125,41.199096679687784 ], [ 37.032897949219034,41.19848632812523 ] ] ], [ [ [ 37.02709960937506,41.20068359374994 ], [ 37.02990722656267,41.200073242187614 ], [ 37.03070068359392,41.19927978515631 ], [ 37.02911376953119,41.198913574219034 ], [ 37.02709960937506,41.20068359374994 ] ] ], [ [ [ 36.65551757812517,41.37872314453131 ], [ 36.65991210937517,41.380493164062784 ], [ 36.66131591796881,41.37512207031273 ], [ 36.65832519531244,41.37512207031273 ], [ 36.65551757812517,41.37872314453131 ] ] ], [ [ [ 36.65551757812517,41.37872314453131 ], [ 36.657897949219034,41.36511230468767 ], [ 36.66168212890631,41.36492919921875 ], [ 36.66271972656244,41.376892089843864 ], [ 36.66070556640631,41.381286621094034 ], [ 36.86132812500017,41.34112548828125 ], [ 36.995727539062784,41.28411865234381 ], [ 37.023925781250284,41.257080078125284 ], [ 37.017272949219034,41.21368408203125 ], [ 37.031921386718864,41.187500000000284 ], [ 37.15065002441423,41.14789581298845 ], [ 37.15253448486328,41.11470413208036 ], [ 37.000690460205135,41.05016326904308 ], [ 36.904468536376896,40.924163818359546 ], [ 36.82196426391607,40.87958145141596 ], [ 36.69670104980486,40.84641647338867 ], [ 36.69994354248064,40.880859375 ], [ 36.657619476318644,40.898769378662166 ], [ 36.453960418701115,40.8676567077639 ], [ 36.37617874145525,40.90769958496105 ], [ 36.372375488281534,40.952079772949276 ], [ 36.23618698120134,40.981094360351676 ], [ 36.20392608642584,40.98003387451172 ], [ 36.18646621704107,40.91199111938488 ], [ 36.16328430175787,40.89022445678722 ], [ 36.04716110229509,40.84297561645508 ], [ 35.955291748046875,40.87558364868164 ], [ 35.840560913085994,40.86432647705101 ], [ 35.69504547119146,40.87898635864286 ], [ 35.643894195556925,40.92682647705078 ], [ 35.47882080078119,41.01443862915039 ], [ 35.093154907226506,41.09054183959961 ], [ 34.98682022094721,41.07823944091797 ], [ 34.96025466918957,41.113548278808594 ], [ 34.94060516357439,41.20204162597656 ], [ 34.892101287841854,41.253662109375114 ], [ 34.93707275390631,41.307632446289176 ], [ 35.112976074219034,41.37586212158209 ], [ 35.23078155517584,41.26348114013689 ], [ 35.33028793334972,41.249080657959155 ], [ 35.3814315795899,41.26378631591808 ], [ 35.42044830322294,41.29426193237305 ], [ 35.45225524902355,41.357505798339844 ], [ 35.41756439209013,41.469825744628906 ], [ 35.485122680664006,41.586826324462834 ], [ 35.498935699463175,41.6419563293457 ], [ 35.56549072265631,41.63128662109381 ], [ 35.653686523437784,41.640686035156534 ], [ 35.95367431640631,41.735290527344034 ], [ 36.05609130859381,41.6875 ], [ 36.11511230468744,41.62567138671875 ], [ 36.132080078125284,41.46130371093756 ], [ 36.241516113281364,41.353515625 ], [ 36.35571289062506,41.310485839843864 ], [ 36.341308593750284,41.3118896484375 ], [ 36.3375244140625,41.294128417968864 ], [ 36.381896972656364,41.27270507812506 ], [ 36.386474609375114,41.25512695312506 ], [ 36.439880371093864,41.244506835937614 ], [ 36.51470947265619,41.25952148437523 ], [ 36.567504882812784,41.28790283203125 ], [ 36.620727539062784,41.36749267578148 ], [ 36.65551757812517,41.37872314453131 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-63", "NAME_1": "Şanlıurfa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 39.26585769653326,37.998172760009766 ], [ 39.44062423706066,37.9846305847168 ], [ 39.66156768798834,37.84016799926769 ], [ 39.76156616210966,37.83341598510742 ], [ 39.85432052612316,37.7578582763673 ], [ 39.86167144775402,37.60364151000982 ], [ 39.88358306884771,37.52904891967796 ], [ 40.11487960815458,37.130916595458984 ], [ 40.134674072265625,37.01825714111328 ], [ 40.1816139221192,36.94679260253912 ], [ 40.25516510009794,36.916130065918026 ], [ 39.84182739257824,36.75532150268549 ], [ 39.22734832763672,36.664997100830135 ], [ 39.020233154297046,36.703311920166016 ], [ 38.73147201538097,36.70748519897461 ], [ 38.56340026855469,36.83882522583019 ], [ 38.39853668212902,36.89716339111328 ], [ 38.1943435668947,36.90692138671875 ], [ 38.010631561279354,36.825210571289176 ], [ 38.01078796386747,36.936237335205305 ], [ 37.880939483642635,37.057415008545036 ], [ 37.834709167480526,37.19113159179693 ], [ 37.83034515380871,37.24394226074219 ], [ 37.84837341308611,37.312484741210994 ], [ 37.93680572509794,37.40411758422874 ], [ 38.00278091430681,37.44073867797874 ], [ 38.16900634765642,37.407279968261776 ], [ 38.330547332763786,37.48437881469732 ], [ 38.47832489013666,37.48891067504883 ], [ 38.615886688232536,37.57777023315424 ], [ 38.82369232177746,37.639743804931754 ], [ 38.83985519409174,37.658622741699276 ], [ 38.83071136474615,37.69311904907238 ], [ 38.95743942260748,37.7553596496582 ], [ 38.97814941406256,37.795402526855696 ], [ 38.97775268554693,37.890113830566406 ], [ 39.05976867675787,37.98223876953125 ], [ 39.17874908447283,38.030654907226676 ], [ 39.26585769653326,37.998172760009766 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-56", "NAME_1": "Siirt" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 42.39585113525408,38.132087707519645 ], [ 42.49808883666998,38.109996795654354 ], [ 42.72762680053711,38.01245117187523 ], [ 42.8357009887697,38.06550598144537 ], [ 42.9546012878418,38.05150604248064 ], [ 42.98358917236334,38.02978134155285 ], [ 43.03906250000006,37.9368133544923 ], [ 42.98860931396513,37.854892730713004 ], [ 42.98530578613287,37.80927276611345 ], [ 42.76489257812494,37.8343200683596 ], [ 42.680290222168026,37.877780914306754 ], [ 42.60340881347656,37.878520965576286 ], [ 42.493461608887,37.83566284179693 ], [ 42.41053771972673,37.74816131591808 ], [ 42.326351165771655,37.69716262817377 ], [ 42.15908813476591,37.68182373046875 ], [ 41.968589782714844,37.69533538818388 ], [ 41.888881683349666,37.72859573364269 ], [ 41.856918334960994,37.763187408447266 ], [ 41.754611968994254,37.74295043945335 ], [ 41.70092010498058,37.77768707275396 ], [ 41.73792648315447,37.8255729675293 ], [ 41.73163986206072,37.85505676269531 ], [ 41.51866149902361,37.85847473144531 ], [ 41.45145416259794,37.88371658325195 ], [ 41.41131591796875,37.918457031250114 ], [ 41.432540893554744,37.95641326904308 ], [ 41.480823516845874,37.986244201660156 ], [ 41.48127746582048,38.02124786376959 ], [ 41.60668945312506,38.038478851318416 ], [ 41.6461448669433,38.102352142333984 ], [ 41.67486572265625,38.19519042968773 ], [ 41.91657638549833,38.148315429687614 ], [ 41.97900390625006,38.15625381469738 ], [ 42.025947570801065,38.12945938110357 ], [ 42.095233917236385,38.20076751708996 ], [ 42.20790863037138,38.21693801879883 ], [ 42.26993179321295,38.20078659057623 ], [ 42.39585113525408,38.132087707519645 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-57", "NAME_1": "Sinop" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 34.945415496826456,42.09791564941406 ], [ 35.01625061035185,42.09319305419922 ], [ 35.05180740356457,42.059860229492415 ], [ 35.04375076293951,42.04180526733404 ], [ 35.077640533447436,42.02680587768566 ], [ 35.19319534301752,42.040138244628906 ], [ 35.206527709960994,42.01263809204124 ], [ 35.14097213745134,42.02347183227539 ], [ 35.09569549560564,41.96569442749029 ], [ 35.09013748168951,41.92180633544933 ], [ 35.12958145141607,41.85874938964844 ], [ 35.20735931396496,41.80263900756859 ], [ 35.19347381591825,41.79208374023443 ], [ 35.20819473266607,41.76736068725609 ], [ 35.264862060547046,41.73819351196295 ], [ 35.27597045898443,41.71597290039068 ], [ 35.414306640625114,41.68375015258789 ], [ 35.498935699463175,41.6419563293457 ], [ 35.485122680664006,41.586826324462834 ], [ 35.41756439209013,41.469825744628906 ], [ 35.4532356262207,41.362899780273665 ], [ 35.40052795410162,41.27267456054693 ], [ 35.33028793334972,41.249080657959155 ], [ 35.23078155517584,41.26348114013689 ], [ 35.112976074219034,41.37586212158209 ], [ 34.93707275390631,41.307632446289176 ], [ 34.8448562622072,41.19581222534174 ], [ 34.521492004394815,41.27654266357433 ], [ 34.47560119628923,41.30388641357422 ], [ 34.46514892578131,41.540878295898494 ], [ 34.56705856323259,41.59246063232422 ], [ 34.59622573852556,41.63491439819336 ], [ 34.59929656982433,41.668979644775504 ], [ 34.4930953979495,41.72483825683594 ], [ 34.269077301025675,41.739074707031364 ], [ 34.26716613769537,41.805038452148665 ], [ 34.225559234619425,41.87401580810547 ], [ 34.22653198242193,41.95513916015648 ], [ 34.30986022949236,41.94097137451189 ], [ 34.490695953369425,41.976806640625 ], [ 34.50791549682634,41.958194732666016 ], [ 34.61791610717802,41.94208145141624 ], [ 34.79819488525396,41.954582214355526 ], [ 34.90763854980469,42.02402877807617 ], [ 34.94902801513672,42.07374954223661 ], [ 34.945415496826456,42.09791564941406 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-73", "NAME_1": "Şırnak" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 42.772178649902514,37.83314132690458 ], [ 42.98530578613287,37.80927276611345 ], [ 43.0542106628418,37.7635955810548 ], [ 43.15652084350597,37.761554718017805 ], [ 43.317729949951456,37.727920532226676 ], [ 43.49570465087896,37.72740173339838 ], [ 43.436573028564396,37.52254486083979 ], [ 43.4347877502442,37.349205017089844 ], [ 43.5009841918947,37.26836013793957 ], [ 43.3700408935548,37.328636169433594 ], [ 43.325466156005916,37.30364227294922 ], [ 43.16740417480486,37.37397766113281 ], [ 43.03809738159208,37.35547637939453 ], [ 42.973693847656364,37.316524505615234 ], [ 42.849826812744425,37.34685897827154 ], [ 42.83127975463873,37.37160110473633 ], [ 42.79906082153326,37.377475738525675 ], [ 42.730808258056925,37.34506225585943 ], [ 42.74326705932617,37.31804275512695 ], [ 42.69933319091814,37.30542755126959 ], [ 42.700664520263786,37.285415649414176 ], [ 42.66455459594732,37.26198577880888 ], [ 42.59164810180681,37.147251129150504 ], [ 42.53633880615246,37.14884567260742 ], [ 42.36370849609381,37.10926055908203 ], [ 42.33525466918974,37.18570327758795 ], [ 42.35742187500006,37.22752761840832 ], [ 42.294952392578296,37.28092956542969 ], [ 42.22082901000971,37.277477264404354 ], [ 42.232196807861385,37.317359924316406 ], [ 42.05733108520536,37.18888092041021 ], [ 41.8692359924317,37.13902282714844 ], [ 41.887989044189396,37.209285736083984 ], [ 41.857463836670206,37.301559448242244 ], [ 41.779117584228686,37.2880554199221 ], [ 41.75320816040039,37.301284790039176 ], [ 41.73899078369158,37.33707046508789 ], [ 41.74073028564459,37.468338012695426 ], [ 41.90201187133795,37.49835586547857 ], [ 41.94921875000006,37.52552032470726 ], [ 41.93354797363281,37.585899353027344 ], [ 41.95733642578125,37.63766860961914 ], [ 41.888881683349666,37.72859573364269 ], [ 42.02056884765631,37.68241500854498 ], [ 42.31177520751953,37.69374847412132 ], [ 42.41053771972673,37.74816131591808 ], [ 42.493461608887,37.83566284179693 ], [ 42.59617996215849,37.87704849243164 ], [ 42.680290222168026,37.877780914306754 ], [ 42.772178649902514,37.83314132690458 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-58", "NAME_1": "Sivas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 38.22033691406256,40.3379364013673 ], [ 38.24710083007824,40.20339965820318 ], [ 38.31576156616228,40.15777206420904 ], [ 38.452972412109375,40.09781646728527 ], [ 38.57074737548834,40.116062164306584 ], [ 38.77371978759777,40.04879760742199 ], [ 38.75243377685564,39.97180938720703 ], [ 38.72418212890619,39.956573486328125 ], [ 38.447406768798885,39.96938323974615 ], [ 38.41403198242216,39.944557189941406 ], [ 38.36586761474615,39.858364105224894 ], [ 38.384220123291186,39.82737731933605 ], [ 38.52223587036144,39.84823226928722 ], [ 38.554382324219034,39.826526641845646 ], [ 38.52255249023466,39.797157287597884 ], [ 38.445766448974894,39.78325271606445 ], [ 38.43944168090826,39.75685119628906 ], [ 38.413822174072266,39.746189117431754 ], [ 38.364730834960994,39.677970886230526 ], [ 38.34907150268583,39.5365562438966 ], [ 38.39641189575195,39.41117095947277 ], [ 38.389953613281364,39.18740081787115 ], [ 38.35454559326172,39.13976669311529 ], [ 38.27381896972685,39.12646484375 ], [ 38.181423187256144,39.07257843017584 ], [ 37.93951416015625,39.059078216552734 ], [ 37.780391693115234,39.001106262207315 ], [ 37.58811187744152,39.00992202758795 ], [ 37.55189514160185,38.95935440063499 ], [ 37.5527420043947,38.92592239379883 ], [ 37.596317291259936,38.836570739746264 ], [ 37.57392501831083,38.7763786315918 ], [ 37.32717132568365,38.60868072509771 ], [ 37.05988693237333,38.578189849853516 ], [ 36.99398040771513,38.61465454101574 ], [ 36.92048263549833,38.62846374511719 ], [ 36.7323379516601,38.591064453125 ], [ 36.758411407470874,38.674396514892805 ], [ 36.944854736328296,39.05715942382824 ], [ 36.91714477539091,39.10745239257818 ], [ 36.87818527221697,39.1377525329591 ], [ 36.77732849121122,39.175086975097656 ], [ 36.61505126953125,39.17627334594738 ], [ 36.45937347412138,39.1303596496582 ], [ 36.37403869628912,39.15341186523443 ], [ 36.30744171142578,39.130260467529524 ], [ 36.057857513427905,39.1307830810548 ], [ 35.96096420288103,39.18781661987305 ], [ 35.885440826416016,39.27633666992216 ], [ 35.81264877319347,39.29944610595703 ], [ 35.838054656982706,39.337776184081974 ], [ 35.97855758666998,39.42293548584007 ], [ 36.06618118286161,39.50249099731445 ], [ 36.069194793701286,39.53652572631859 ], [ 36.1566696166995,39.67705154418945 ], [ 36.12236404418951,39.69313049316406 ], [ 36.123931884765796,39.74603652954096 ], [ 36.07004928588884,39.78324508666992 ], [ 36.047111511230526,39.85269927978527 ], [ 35.965507507324276,39.89990997314453 ], [ 35.9857711791995,39.94587326049816 ], [ 36.11804580688505,39.94603347778343 ], [ 36.22705459594732,39.977584838867244 ], [ 36.30592727661161,39.95699310302757 ], [ 36.442497253418026,39.949581146240234 ], [ 36.60661315917997,39.993495941162166 ], [ 36.67920684814459,40.03599548339855 ], [ 36.7119712829591,40.0902671813966 ], [ 36.700984954834155,40.14154052734375 ], [ 36.77357864379894,40.223766326904354 ], [ 36.96790313720703,40.18217468261719 ], [ 37.07748031616211,40.22293472290039 ], [ 37.168788909912394,40.19018936157232 ], [ 37.43417358398443,40.153423309326286 ], [ 37.47169113159208,40.23818969726574 ], [ 37.56003570556646,40.276390075683594 ], [ 37.55509185791021,40.31818771362316 ], [ 37.58262252807623,40.34762954711914 ], [ 37.58802795410173,40.408416748047046 ], [ 37.6478652954101,40.45049285888683 ], [ 37.71109008789068,40.34790039062494 ], [ 37.772056579590014,40.32857894897461 ], [ 37.82976531982433,40.34440231323242 ], [ 37.90161514282255,40.395137786865234 ], [ 38.02550125122076,40.41411972045904 ], [ 38.15565490722673,40.50869369506859 ], [ 38.182529449463004,40.46619415283203 ], [ 38.22033691406256,40.3379364013673 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-59", "NAME_1": "Tekirdağ" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 28.149583816528548,41.58051681518566 ], [ 28.18263816833496,41.57180404663103 ], [ 28.199304580688647,41.54819488525385 ], [ 28.179122924804744,41.52955627441423 ], [ 28.23168945312517,41.499076843261776 ], [ 28.15378189086914,41.24697875976574 ], [ 28.087570190429744,41.211147308349666 ], [ 28.057348251342773,41.15075302124035 ], [ 28.123260498046932,41.0598602294923 ], [ 28.013750076293945,41.034305572509766 ], [ 27.985694885254134,41.012916564941634 ], [ 27.987083435058878,40.99125289917015 ], [ 27.956806182861555,40.97680664062517 ], [ 27.964307785034237,40.96569442749046 ], [ 27.87791633605974,40.96541595459007 ], [ 27.84069442749052,40.99236297607433 ], [ 27.76347160339361,41.01402664184599 ], [ 27.511249542236555,40.97430419921875 ], [ 27.46263885498064,40.89569473266624 ], [ 27.455417633056925,40.84541702270536 ], [ 27.34458541870123,40.76680374145519 ], [ 27.309305191040153,40.70236206054693 ], [ 27.178472518920955,40.62736129760748 ], [ 27.029861450195483,40.59069442749029 ], [ 27.028583526611442,40.69945907592779 ], [ 27.04261207580595,40.74805068969732 ], [ 27.020599365234432,40.79498672485374 ], [ 26.96979522705078,40.79952239990246 ], [ 26.865480422973576,40.74710464477545 ], [ 26.82361412048334,40.74297332763672 ], [ 26.783828735351562,40.74620056152344 ], [ 26.73179054260271,40.802635192871094 ], [ 26.730768203735636,40.902725219726676 ], [ 26.783018112182617,40.999576568603516 ], [ 26.74397468566889,41.03450775146496 ], [ 26.748094558715877,41.07102966308611 ], [ 26.772720336914176,41.10102081298851 ], [ 26.89196395874029,41.13861846923834 ], [ 26.937599182129134,41.18946838378906 ], [ 26.93860054016136,41.23728561401373 ], [ 26.89655685424833,41.294040679931584 ], [ 26.898347854614258,41.34303283691406 ], [ 26.95331382751459,41.325469970703296 ], [ 27.12053489685087,41.34813308715843 ], [ 27.262168884277514,41.34740066528332 ], [ 27.377403259277344,41.31006622314476 ], [ 27.472660064697436,41.22648620605469 ], [ 27.520938873291016,41.22114562988281 ], [ 27.55360603332548,41.23656463623047 ], [ 27.64314651489252,41.34899902343756 ], [ 27.673555374145565,41.40991210937494 ], [ 27.67464828491228,41.4577522277832 ], [ 27.730844497680607,41.49436187744152 ], [ 27.770309448242188,41.50877761840832 ], [ 27.86650657653837,41.50082015991211 ], [ 27.977830886840934,41.54333114624018 ], [ 28.149583816528548,41.58051681518566 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-60", "NAME_1": "Tokat" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 36.69994354248064,40.880859375 ], [ 36.68491363525396,40.826515197753906 ], [ 36.69797897338873,40.80878448486328 ], [ 36.851066589355526,40.75009155273443 ], [ 36.9319686889649,40.73946380615263 ], [ 36.97164916992199,40.703620910644474 ], [ 37.078315734863565,40.68880844116222 ], [ 37.18733215332037,40.704162597656364 ], [ 37.29387283325201,40.66733932495134 ], [ 37.31242370605469,40.627868652343864 ], [ 37.34712219238298,40.627052307129134 ], [ 37.466255187988565,40.563144683837834 ], [ 37.61163711547857,40.551143646240234 ], [ 37.6478652954101,40.45049285888683 ], [ 37.58802795410173,40.408416748047046 ], [ 37.58262252807623,40.34762954711914 ], [ 37.55509185791021,40.31818771362316 ], [ 37.56003570556646,40.276390075683594 ], [ 37.47169113159208,40.23818969726574 ], [ 37.43417358398443,40.153423309326286 ], [ 37.168788909912394,40.19018936157232 ], [ 37.07748031616211,40.22293472290039 ], [ 36.96790313720703,40.18217468261719 ], [ 36.77357864379894,40.223766326904354 ], [ 36.700984954834155,40.14154052734375 ], [ 36.71134185791044,40.08755493164057 ], [ 36.6641273498538,40.0172958374024 ], [ 36.442497253418026,39.949581146240234 ], [ 36.30592727661161,39.95699310302757 ], [ 36.22705459594732,39.977584838867244 ], [ 36.11804580688505,39.94603347778343 ], [ 35.9857711791995,39.94587326049816 ], [ 35.96333694458019,39.986537933349894 ], [ 35.961826324463175,40.043380737304744 ], [ 35.936515808105526,40.07973480224604 ], [ 35.633205413818644,40.08720397949219 ], [ 35.51206970214861,40.189777374267635 ], [ 35.529628753662394,40.235530853271484 ], [ 35.5763778686524,40.27421951293945 ], [ 35.71618652343756,40.32625579834007 ], [ 35.84466171264654,40.501518249511776 ], [ 35.95844650268555,40.50232696533209 ], [ 36.03977584838873,40.45986938476557 ], [ 36.15447616577177,40.44520568847656 ], [ 36.32520294189459,40.523677825927734 ], [ 36.45606231689459,40.65576934814453 ], [ 36.47220230102545,40.7211151123048 ], [ 36.41676330566412,40.82258224487305 ], [ 36.4480056762697,40.86983108520536 ], [ 36.49979400634794,40.86569976806652 ], [ 36.61869049072283,40.89941406250023 ], [ 36.69994354248064,40.880859375 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-61", "NAME_1": "Trabzon" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 39.419582366943416,41.107639312744254 ], [ 39.486251831054744,41.09208297729492 ], [ 39.565971374511776,41.02597045898432 ], [ 39.64041519165056,40.99986267089844 ], [ 39.71902847290045,41.0120849609375 ], [ 39.78013992309599,41.002639770507926 ], [ 39.87347412109381,40.95402908325195 ], [ 40.035137176513786,40.95958328247076 ], [ 40.12014007568388,40.9120826721192 ], [ 40.230693817138615,40.928470611572266 ], [ 40.33458328247076,40.99514007568365 ], [ 40.36624526977545,40.98522949218756 ], [ 40.417865753174,40.94629287719738 ], [ 40.46320343017584,40.876575469970874 ], [ 40.5118942260745,40.741134643554744 ], [ 40.51181793212896,40.69040298461914 ], [ 40.47890853881836,40.628585815429915 ], [ 40.48347854614275,40.535343170166016 ], [ 40.226131439208984,40.50077056884771 ], [ 40.09298324584955,40.512348175048885 ], [ 40.10813140869169,40.57054519653332 ], [ 40.040325164795206,40.638103485107365 ], [ 40.004878997802734,40.65853500366211 ], [ 39.98151016235357,40.64609527587896 ], [ 39.97420120239275,40.62319564819347 ], [ 39.99523925781244,40.5870056152346 ], [ 39.98057937622076,40.56537628173828 ], [ 39.95221710205084,40.562820434570426 ], [ 39.89093780517595,40.61500549316412 ], [ 39.8285293579101,40.62057876586914 ], [ 39.84022521972673,40.69247055053705 ], [ 39.80594635009771,40.71657562255888 ], [ 39.766292572021655,40.67451095581066 ], [ 39.72811889648443,40.581474304199446 ], [ 39.67606353759771,40.55933380126976 ], [ 39.30743789672857,40.6691055297851 ], [ 39.13891601562506,40.78902816772478 ], [ 39.1179466247558,40.853782653808764 ], [ 39.119213104248104,40.960250854492244 ], [ 39.17869949340826,41.07402801513666 ], [ 39.284305572509936,41.0498619079591 ], [ 39.419582366943416,41.107639312744254 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-62", "NAME_1": "Tunceli" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 40.271240234375,39.54582595825195 ], [ 40.54322814941406,39.54778289794922 ], [ 40.51652145385748,39.5039901733399 ], [ 40.33533477783203,39.427463531494254 ], [ 40.390830993652344,39.382858276367244 ], [ 40.33251953125,39.351543426513786 ], [ 40.20206451416021,39.28889083862305 ], [ 40.098674774170206,39.31428146362305 ], [ 40.0318336486817,39.204952239990234 ], [ 40.04388046264654,39.15027236938482 ], [ 40.029830932617244,39.115364074707145 ], [ 40.0097732543947,39.089889526367244 ], [ 39.9225807189942,39.08842849731445 ], [ 39.869342803955135,39.04762649536133 ], [ 39.89322280883795,38.99279022216797 ], [ 39.891315460205135,38.9417343139649 ], [ 39.8397102355957,38.86560821533226 ], [ 39.77879714965832,38.81803894042969 ], [ 39.63027191162115,38.80181884765625 ], [ 39.49058151245123,38.749164581299055 ], [ 39.048492431640625,38.89308929443382 ], [ 38.9420242309572,38.893768310546875 ], [ 38.84452056884794,38.871868133545036 ], [ 38.769435882568644,38.89875411987316 ], [ 38.78187942504877,38.99327850341808 ], [ 38.72687530517595,39.115749359130916 ], [ 38.77346038818365,39.182136535644474 ], [ 38.89364624023443,39.21349716186535 ], [ 38.92637634277344,39.25006484985357 ], [ 38.833896636963004,39.257617950439624 ], [ 38.79290771484375,39.27995681762701 ], [ 38.8339462280274,39.32938766479515 ], [ 38.96605682373064,39.37565994262695 ], [ 39.097686767578296,39.46172332763683 ], [ 39.32331466674816,39.499732971191406 ], [ 39.477455139160156,39.4769744873048 ], [ 39.596000671387,39.48797607421898 ], [ 39.61517333984381,39.445877075195426 ], [ 39.66516876220709,39.441463470458984 ], [ 39.69773864746111,39.45171737670927 ], [ 39.77057266235357,39.51818084716808 ], [ 39.85518646240246,39.54473114013672 ], [ 39.88587951660162,39.54994583129911 ], [ 39.986354827881144,39.51869201660179 ], [ 40.12992477416998,39.556602478027344 ], [ 40.271240234375,39.54582595825195 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-64", "NAME_1": "Uşak" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 29.89272689819353,38.77788162231445 ], [ 29.894367218017862,38.70968246459984 ], [ 29.87275886535673,38.64421844482433 ], [ 29.77183532714872,38.50595855712919 ], [ 29.755413055419922,38.45410919189453 ], [ 29.673618316650447,38.418857574463004 ], [ 29.64810752868658,38.34411239624035 ], [ 29.594125747680607,38.27232742309593 ], [ 29.57591819763178,38.19177246093756 ], [ 29.54411315917963,38.19533920288097 ], [ 29.42590332031267,38.26173400878912 ], [ 29.22126007080078,38.195537567138956 ], [ 29.096721649170036,38.2179908752442 ], [ 28.92095375061041,38.265453338623104 ], [ 28.82542800903326,38.355316162109375 ], [ 28.85549926757841,38.388626098632926 ], [ 28.8410701751709,38.52633666992199 ], [ 28.848800659179744,38.580696105957145 ], [ 28.87877845764166,38.637416839599666 ], [ 29.022827148437443,38.725307464599666 ], [ 29.090955734253157,38.739379882812614 ], [ 29.23378944397001,38.73334121704124 ], [ 29.305118560791072,38.78231811523449 ], [ 29.668746948242244,38.88996887207031 ], [ 29.862709045410213,38.855148315429744 ], [ 29.89272689819353,38.77788162231445 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-65", "NAME_1": "Van" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 43.34183883666992,39.39789199829113 ], [ 43.42657852172857,39.38888549804682 ], [ 43.48865509033209,39.330860137939624 ], [ 43.58568572998064,39.28785705566406 ], [ 43.64554214477545,39.302429199218864 ], [ 43.716354370117244,39.37020492553734 ], [ 43.96207427978521,39.35651016235363 ], [ 44.03281784057617,39.37202072143555 ], [ 44.08853530883806,39.32948303222679 ], [ 44.08794021606445,39.29744338989258 ], [ 44.1117019653322,39.286445617676065 ], [ 44.0981178283692,39.254219055175895 ], [ 44.1150856018067,39.23867416381847 ], [ 44.11330413818365,39.20209503173834 ], [ 44.218376159668026,39.138637542724666 ], [ 44.23231124877924,39.10028457641607 ], [ 44.18688583374052,39.116287231445426 ], [ 44.152053833007926,39.09199905395519 ], [ 44.20054244995123,39.06901168823248 ], [ 44.2188453674317,39.028751373291016 ], [ 44.18151473999029,38.99415969848627 ], [ 44.224102020263956,38.891876220703125 ], [ 44.25598144531256,38.855079650878906 ], [ 44.29030227661127,38.85530471801752 ], [ 44.31613159179716,38.83385848999046 ], [ 44.31856536865246,38.80030059814453 ], [ 44.27720260620117,38.71603012084972 ], [ 44.30116653442377,38.67173767089844 ], [ 44.285503387451456,38.64738845825224 ], [ 44.33678436279314,38.62283706665039 ], [ 44.32693099975586,38.5501136779788 ], [ 44.33952713012695,38.50283050537132 ], [ 44.31733322143566,38.44160842895502 ], [ 44.31766128540045,38.38542556762701 ], [ 44.38671112060541,38.363548278808764 ], [ 44.45695495605486,38.38514709472679 ], [ 44.501117706299,38.353702545166016 ], [ 44.509529113769815,38.32789230346691 ], [ 44.42692565917997,38.27817535400396 ], [ 44.40821456909197,38.25121688842785 ], [ 44.41706848144548,38.210250854492415 ], [ 44.404792785644815,38.14494705200201 ], [ 44.36408615112333,38.12714767456055 ], [ 44.37923431396513,38.097625732421875 ], [ 44.352626800537394,38.09918594360363 ], [ 44.32249832153349,38.069694519043026 ], [ 44.31347274780279,38.029933929443416 ], [ 44.25692749023443,37.95954132080078 ], [ 44.26597976684576,37.93852996826183 ], [ 44.23886108398466,37.88711547851568 ], [ 44.27629089355469,37.86631774902344 ], [ 44.33904266357422,37.87405776977545 ], [ 44.416442871094034,37.85408401489269 ], [ 44.413669586181925,37.82162857055687 ], [ 44.44305038452177,37.79836654663109 ], [ 44.47020721435558,37.797904968261776 ], [ 44.46298980712919,37.768390655517635 ], [ 44.57461929321295,37.767143249511776 ], [ 44.479644775390796,37.67538070678722 ], [ 44.42198181152372,37.646568298339844 ], [ 44.32952880859392,37.65622329711914 ], [ 44.237655639648494,37.62777709960949 ], [ 44.21875,37.64314651489269 ], [ 44.24557495117182,37.708969116210994 ], [ 44.22552108764654,37.75441741943365 ], [ 44.20137023925798,37.76893234252947 ], [ 44.0651931762697,37.71755218505865 ], [ 43.96967315673834,37.7267951965332 ], [ 43.892715454101506,37.700431823730526 ], [ 43.78456878662104,37.726203918457145 ], [ 43.67584609985357,37.715328216552734 ], [ 43.317729949951456,37.727920532226676 ], [ 43.15652084350597,37.761554718017805 ], [ 43.04656219482433,37.765319824218864 ], [ 42.98530578613287,37.80927276611345 ], [ 42.98860931396513,37.854892730713004 ], [ 43.03906250000006,37.9368133544923 ], [ 42.98358917236334,38.02978134155285 ], [ 42.9546012878418,38.05150604248064 ], [ 42.8357009887697,38.06550598144537 ], [ 42.777313232421875,38.127155303955135 ], [ 42.79895782470709,38.16839981079107 ], [ 42.75567626953131,38.175254821777344 ], [ 42.720058441162166,38.20351028442394 ], [ 42.739238739013615,38.277294158935774 ], [ 42.68788528442394,38.39511108398449 ], [ 42.69043731689459,38.42795944213873 ], [ 42.72961044311529,38.45822143554693 ], [ 42.8891716003418,38.52491760253906 ], [ 42.9462432861331,38.614349365234375 ], [ 42.964450836181754,38.61788177490246 ], [ 43.056091308593864,38.72330474853521 ], [ 43.17415237426775,38.79370498657221 ], [ 43.196823120117244,38.828151702880916 ], [ 43.197910308838004,38.8801727294923 ], [ 43.12784957885748,38.93337631225586 ], [ 43.00352096557623,38.99146652221691 ], [ 43.02248382568365,39.09549331665056 ], [ 43.144695281982536,39.13629150390631 ], [ 43.16763305664068,39.16597366333019 ], [ 43.165607452392635,39.23989868164074 ], [ 43.08466720581049,39.284191131592024 ], [ 43.07938003540056,39.30751419067394 ], [ 43.10197830200224,39.32246017456055 ], [ 43.19167327880865,39.32806777954107 ], [ 43.290340423583984,39.401798248291016 ], [ 43.34183883666992,39.39789199829113 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-77", "NAME_1": "Yalova" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 29.394861221313647,40.70208358764654 ], [ 29.442625045776538,40.69208145141596 ], [ 29.43100166320812,40.560283660888615 ], [ 29.362733840942667,40.580024719238224 ], [ 29.26760673522955,40.55602264404297 ], [ 29.045017242431754,40.559192657470874 ], [ 29.010364532470874,40.497295379638786 ], [ 29.03236198425293,40.47847366333008 ], [ 28.97513961792015,40.45569610595703 ], [ 28.883195877075252,40.47874832153343 ], [ 28.85375022888212,40.50597381591808 ], [ 28.780139923095874,40.51847076416033 ], [ 28.79319381713873,40.55236053466808 ], [ 28.931528091430835,40.6004180908206 ], [ 28.991249084472884,40.644584655761776 ], [ 29.282085418701286,40.6601371765139 ], [ 29.394861221313647,40.70208358764654 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-66", "NAME_1": "Yozgat" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.343200683594034,40.21666336059576 ], [ 35.38194656372076,40.19127655029308 ], [ 35.51206970214861,40.189777374267635 ], [ 35.633205413818644,40.08720397949219 ], [ 35.936515808105526,40.07973480224604 ], [ 35.961826324463175,40.043380737304744 ], [ 35.96333694458019,39.986537933349894 ], [ 35.9857711791995,39.94587326049816 ], [ 35.965507507324276,39.89990997314453 ], [ 36.047111511230526,39.85269927978527 ], [ 36.07004928588884,39.78324508666992 ], [ 36.123931884765796,39.74603652954096 ], [ 36.12236404418951,39.69313049316406 ], [ 36.1566696166995,39.67705154418945 ], [ 36.069194793701286,39.53652572631859 ], [ 36.06618118286161,39.50249099731445 ], [ 35.97855758666998,39.42293548584007 ], [ 35.838054656982706,39.337776184081974 ], [ 35.80165863037115,39.287456512451286 ], [ 35.723690032959155,39.22582626342796 ], [ 35.67081451416021,39.20149993896507 ], [ 35.55098342895536,39.202976226806754 ], [ 35.47180557250988,39.18677139282238 ], [ 35.463966369628906,39.156749725341854 ], [ 35.482967376709155,39.099575042724666 ], [ 35.2412185668947,39.00565338134777 ], [ 35.037403106689624,39.03805160522461 ], [ 35.002208709716854,39.09674072265625 ], [ 34.99610900878923,39.140846252441634 ], [ 34.89593505859369,39.227462768554744 ], [ 34.9202499389649,39.33756637573248 ], [ 34.796630859375,39.38809204101574 ], [ 34.79120254516607,39.4306373596192 ], [ 34.62562561035185,39.49412536621105 ], [ 34.53654098510759,39.54788589477539 ], [ 34.52186584472685,39.57050704956066 ], [ 34.544994354248104,39.622127532958984 ], [ 34.468528747558764,39.67209625244152 ], [ 34.42567825317377,39.73305511474615 ], [ 34.35737991333036,39.74853515625023 ], [ 34.234619140625284,39.73669052124018 ], [ 34.06889724731451,39.80836868286144 ], [ 34.05434417724615,39.90491104125988 ], [ 34.08631896972673,39.9203529357913 ], [ 34.27889251709013,39.93708801269531 ], [ 34.394672393798885,39.99183654785156 ], [ 34.80086135864252,39.993850708007926 ], [ 34.90447235107433,40.04970169067383 ], [ 35.05699539184599,40.02979278564453 ], [ 35.17874526977556,40.090763092041016 ], [ 35.16777420043957,40.2132301330567 ], [ 35.288646697998104,40.213741302490234 ], [ 35.33233642578119,40.228908538818416 ], [ 35.343200683594034,40.21666336059576 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "TR-67", "NAME_1": "Zonguldak" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 32.02097702026373,41.56291580200201 ], [ 32.0411911010745,41.523483276367244 ], [ 32.30512619018572,41.306194305420036 ], [ 32.35403823852545,41.23849105834972 ], [ 32.29877471923834,41.23664093017601 ], [ 32.13407135009794,41.15750503540039 ], [ 32.09339904785162,41.076122283935604 ], [ 32.09199523925798,41.01836776733404 ], [ 31.43902778625494,41.05629730224604 ], [ 31.338193893432674,41.1367378234865 ], [ 31.409025192261026,41.21263885498058 ], [ 31.402360916137695,41.271526336670036 ], [ 31.41736221313488,41.26319503784197 ], [ 31.420694351196346,41.27402877807617 ], [ 31.391252517700195,41.2940292358399 ], [ 31.39986038208002,41.315971374511776 ], [ 31.620138168335018,41.382637023925724 ], [ 31.74819564819353,41.43986129760765 ], [ 31.754304885864315,41.45513916015625 ], [ 31.785417556762752,41.45430374145508 ], [ 31.89430809020996,41.523750305175895 ], [ 32.02097702026373,41.56291580200201 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/venezuela.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/venezuela.geojson new file mode 100644 index 0000000000000..beb432193c5f0 --- /dev/null +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/venezuela.geojson @@ -0,0 +1,32 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "ISO": "VE-Y", "NAME_1": "Delta Amacuro" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -60.020985480999911, 8.558010158000059 ], [ -59.815594848999922, 8.287763977000026 ], [ -59.829289102999951, 8.245105083000041 ], [ -59.848461059999863, 8.227741801000107 ], [ -59.939721638999856, 8.208440654000071 ], [ -59.993310098999928, 8.168520609000026 ], [ -60.019458373999925, 8.060310161000118 ], [ -60.046485148999864, 8.032921652000084 ], [ -60.129219116999934, 8.02881337500007 ], [ -60.183091796999889, 7.982666321000124 ], [ -60.231125040999927, 7.964114482000085 ], [ -60.267998436999875, 7.921262469000098 ], [ -60.544412604158367, 7.915537828507979 ], [ -60.706805793152796, 7.818256944202574 ], [ -60.784630499697812, 7.751775213954943 ], [ -60.970975714957262, 7.946026923303862 ], [ -61.024460821609637, 7.940678412278885 ], [ -61.065724452821257, 7.906158556072512 ], [ -61.130423347259637, 7.897011826734399 ], [ -61.242922939641915, 7.838953355413025 ], [ -61.312634447421829, 7.820582384169654 ], [ -61.342425910227576, 7.831977037310423 ], [ -61.609205491939917, 8.118522854246294 ], [ -61.643389452261431, 8.207974757928696 ], [ -61.635198737331848, 8.287039699722357 ], [ -62.247176887403441, 8.313808092369527 ], [ -62.597646449723868, 8.447985947893187 ], [ -62.515300056252613, 8.519428616437494 ], [ -62.435899216775397, 8.513821722994123 ], [ -62.366368577947526, 8.54570608177022 ], [ -62.32324459476223, 8.589372667314706 ], [ -62.239528774833104, 8.598002630916653 ], [ -62.181832037818253, 8.680400702130669 ], [ -62.075197720398478, 8.734402574519208 ], [ -62.06424231593013, 8.799204819946453 ], [ -62.00507280056928, 8.872843736349353 ], [ -62.008638474885686, 8.895452175477487 ], [ -62.055560676384118, 8.90511566785375 ], [ -62.084189419206325, 8.94482900635353 ], [ -62.055173101857179, 9.063710639434476 ], [ -62.088633591766836, 9.071798001576497 ], [ -62.128734503894236, 9.056450100491759 ], [ -62.145270961585595, 9.097584540494154 ], [ -62.209737311127981, 9.072366441458087 ], [ -62.266297166580955, 9.131871852703853 ], [ -62.32133256684449, 9.140553494048504 ], [ -62.304692756365625, 9.196648261508074 ], [ -62.320531582066849, 9.357336127260453 ], [ -62.38685828268359, 9.417229112133782 ], [ -62.396056687965768, 9.481385403313709 ], [ -62.443599006189174, 9.509290675724117 ], [ -62.440240038347099, 9.541020005768644 ], [ -62.378667568653384, 9.615640774102417 ], [ -62.325365804088563, 9.718851386881965 ], [ -62.318714972999942, 9.706244208000044 ], [ -62.270497199999909, 9.766669012000079 ], [ -62.242990688999953, 9.842840887000079 ], [ -62.257232225999928, 9.974351304000038 ], [ -62.221994594999899, 9.938381252000056 ], [ -62.178700324999909, 9.846136786000045 ], [ -62.175892706999946, 9.704982815000051 ], [ -62.187611456999946, 9.662665106000077 ], [ -62.215687628999945, 9.637925523000092 ], [ -62.18187415299991, 9.648871161000045 ], [ -62.154286261999914, 9.726141669000071 ], [ -62.16047115799995, 9.85024648600006 ], [ -62.195179816999939, 9.932806708000044 ], [ -62.11945553299995, 9.921454169000071 ], [ -62.088449673999946, 9.879299221000053 ], [ -62.027333136999914, 9.874416408000059 ], [ -62.089019334999932, 9.898098049000055 ], [ -62.135609503999945, 9.940619208000044 ], [ -62.221424933999913, 9.95180898600006 ], [ -62.236805792999917, 9.966945705000057 ], [ -62.19647551199995, 10.019677793000085 ], [ -62.0253828459999, 9.957357139000067 ], [ -61.831450975999928, 9.791937567000048 ], [ -61.810373501999948, 9.748195705000057 ], [ -61.845773891999954, 9.65102773600006 ], [ -61.797352667999917, 9.760891018000052 ], [ -61.780100063999953, 9.75922272300005 ], [ -61.743316209999932, 9.699408270000049 ], [ -61.743316209999932, 9.596380927000041 ], [ -61.731027798999946, 9.694037177000041 ], [ -61.763172980999911, 9.760891018000052 ], [ -61.797352667999917, 9.774562893000052 ], [ -61.828171711999914, 9.827158454000084 ], [ -61.790099552999948, 9.830667120000044 ], [ -61.592518683999913, 9.78196849200009 ], [ -61.573801235999952, 9.794582424000055 ], [ -61.578114386999914, 9.808823960000041 ], [ -61.670965672999898, 9.896498654000084 ], [ -61.636734698999931, 9.898770728000045 ], [ -61.475700638999911, 9.80170127100007 ], [ -61.422265394999954, 9.736261109000054 ], [ -61.458042396999929, 9.812458040000081 ], [ -61.503098310999917, 9.839566517000037 ], [ -61.439167779999934, 9.818411300000037 ], [ -61.236507977999906, 9.632169292000071 ], [ -61.206044074999909, 9.577378648000092 ], [ -61.191965298999946, 9.583319403000075 ], [ -61.208322719999899, 9.60382721600007 ], [ -61.184193488999938, 9.604071356000077 ], [ -61.130116339999915, 9.572495835000041 ], [ -61.053212042999917, 9.581284898000092 ], [ -60.977040167999917, 9.549627997000073 ], [ -60.955067511999914, 9.521307684000078 ], [ -60.968658006999931, 9.534979559000078 ], [ -60.968658006999931, 9.493963934000078 ], [ -60.879017706999946, 9.468898830000057 ], [ -60.797434048999946, 9.384711005000042 ], [ -60.783802863999938, 9.33860911700009 ], [ -60.797434048999946, 9.294745184000078 ], [ -60.810414191999939, 9.31586334800005 ], [ -60.821888800999943, 9.272772528000075 ], [ -60.927113410999937, 9.233303127000056 ], [ -61.066761847999942, 9.132310289000088 ], [ -61.085438605999911, 9.102443752000056 ], [ -61.112049933999913, 9.041489976000037 ], [ -60.959136522999927, 9.182521877000056 ], [ -61.006581183999913, 9.048773505000042 ], [ -61.078521287999934, 8.997463283000059 ], [ -61.099680141999954, 8.960353908000059 ], [ -61.117746548999946, 8.903713283000059 ], [ -61.112049933999913, 8.857123114000046 ], [ -61.180083787999934, 8.735825914000088 ], [ -61.209462042999917, 8.609035549000055 ], [ -61.233306443999936, 8.58930084800005 ], [ -61.348540818999936, 8.61009349200009 ], [ -61.523060675999943, 8.596625067000048 ], [ -61.625355597999942, 8.630194403000075 ], [ -61.659047003999945, 8.616522528000075 ], [ -61.651966925999943, 8.585842190000051 ], [ -61.537261522999927, 8.527573960000041 ], [ -61.499663865999935, 8.534369208000044 ], [ -61.43423417899993, 8.47915273600006 ], [ -61.359120245999918, 8.486558335000041 ], [ -61.331776495999918, 8.438177802000041 ], [ -61.284047003999945, 8.39720286700009 ], [ -61.181019660999937, 8.493394273000092 ], [ -61.026600714999915, 8.500921942000048 ], [ -61.040150519999941, 8.472845770000049 ], [ -61.077992316999939, 8.466457424000055 ], [ -61.085764126999948, 8.415594794000071 ], [ -61.071888800999943, 8.403306382000039 ], [ -61.066558397999927, 8.456284898000092 ], [ -61.020375128999945, 8.468817450000074 ], [ -60.975575324999909, 8.575995184000078 ], [ -60.692453579999949, 8.604681708000044 ], [ -60.626088019999941, 8.555487372000073 ], [ -60.478911912999934, 8.532375393000052 ], [ -60.46157792899993, 8.534369208000044 ], [ -60.403716600999928, 8.62250397300005 ], [ -60.371896938999953, 8.63540273600006 ], [ -60.197824673999946, 8.623846747000073 ], [ -60.020985480999911, 8.558010158000059 ] ] ], [ [ [ -61.016468878999945, 8.61009349200009 ], [ -60.996001756999931, 8.602687893000052 ], [ -60.992543097999942, 8.576727606000077 ], [ -61.027699347999942, 8.543117580000057 ], [ -61.050648566999939, 8.555487372000073 ], [ -61.041574673999946, 8.518540757000039 ], [ -61.270375128999945, 8.514553127000056 ], [ -61.227609829999949, 8.571600653000075 ], [ -61.180246548999946, 8.569647528000075 ], [ -61.126372850999928, 8.534369208000044 ], [ -61.137847459999932, 8.559759833000044 ], [ -61.098459438999953, 8.602687893000052 ], [ -61.016468878999945, 8.61009349200009 ] ] ], [ [ [ -60.920277472999942, 9.028469143000052 ], [ -60.875477667999917, 9.02798086100006 ], [ -60.838368292999917, 9.000555731000077 ], [ -60.865712042999917, 8.994330145000049 ], [ -60.850819464999915, 8.970648505000042 ], [ -60.864979620999918, 8.941229559000078 ], [ -60.933583136999914, 8.883937893000052 ], [ -61.091623501999948, 8.822414455000057 ], [ -61.016713019999941, 8.88031647300005 ], [ -60.920277472999942, 9.028469143000052 ] ] ], [ [ [ -61.085438605999911, 8.890692450000074 ], [ -61.096587693999936, 8.900580145000049 ], [ -61.069325324999909, 8.97882721600007 ], [ -61.00226803299995, 9.000555731000077 ], [ -60.930816209999932, 9.07562897300005 ], [ -60.852040167999917, 9.096136786000045 ], [ -60.87564042899993, 9.043646552000041 ], [ -60.942982550999943, 9.025824286000045 ], [ -61.027088995999918, 8.94867584800005 ], [ -61.043812628999945, 8.911769924000055 ], [ -61.085438605999911, 8.890692450000074 ] ] ], [ [ [ -60.873158331999946, 9.116603908000059 ], [ -60.889719204999949, 9.098578192000048 ], [ -60.961293097999942, 9.069403387000079 ], [ -60.936756964999915, 9.164618231000077 ], [ -60.853342251999948, 9.194037177000041 ], [ -60.847482876999948, 9.163031317000048 ], [ -60.873158331999946, 9.116603908000059 ] ] ], [ [ [ -60.817860480999911, 9.206000067000048 ], [ -60.757923956999946, 9.230414130000042 ], [ -60.728505011999914, 9.192938544000071 ], [ -60.797434048999946, 9.171820380000042 ], [ -60.823801235999952, 9.122300523000092 ], [ -60.845204230999911, 9.116603908000059 ], [ -60.817860480999911, 9.206000067000048 ] ] ], [ [ [ -61.390271415999905, 8.580580853000072 ], [ -61.314602598999954, 8.571314151000081 ], [ -61.302737306999916, 8.514990475000047 ], [ -61.260264111999902, 8.486377083000093 ], [ -61.263688037999941, 8.456088496000064 ], [ -61.293437943999947, 8.456939487000056 ], [ -61.338444295999921, 8.50995247700007 ], [ -61.433687591999899, 8.514154007000059 ], [ -61.540116350999938, 8.565410528000086 ], [ -61.390271415999905, 8.580580853000072 ] ] ], [ [ [ -60.745023913999944, 8.719358815000078 ], [ -60.676055937999934, 8.762917274000074 ], [ -60.687225294999905, 8.709995234000075 ], [ -60.666022013999907, 8.686417940000069 ], [ -60.611610877999908, 8.683771178000086 ], [ -60.617677110999921, 8.636722733000056 ], [ -60.808134479999921, 8.632888276000074 ], [ -60.760332588999916, 8.717707751000091 ], [ -60.745023913999944, 8.719358815000078 ] ] ], [ [ [ -60.951361150999901, 8.827825132000044 ], [ -60.883289077999905, 8.84048914300007 ], [ -60.86169945599994, 8.87024514400008 ], [ -60.778106328999911, 8.870097702000066 ], [ -60.732365478999952, 8.892149504000088 ], [ -60.737598057999946, 8.866613498000049 ], [ -60.686042885999939, 8.789014680000037 ], [ -60.76973496699992, 8.741511392000064 ], [ -60.806895744999906, 8.672588730000086 ], [ -60.846576004999918, 8.63771526000005 ], [ -61.093874137999933, 8.63374413300005 ], [ -61.169914750999908, 8.595313593000071 ], [ -61.167108220999921, 8.699385415000052 ], [ -61.12643995399992, 8.756478098000059 ], [ -61.059968972999911, 8.798163462000048 ], [ -60.951361150999901, 8.827825132000044 ] ] ], [ [ [ -62.240834113999938, 10.05149974200009 ], [ -62.235340949999909, 10.013861395000049 ], [ -62.298003709999932, 9.983710028000075 ], [ -62.286366339999915, 10.024400132000039 ], [ -62.240834113999938, 10.05149974200009 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-F", "NAME_1": "Bolívar" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -60.267998436999875, 7.921262469000098 ], [ -60.374759684999873, 7.823606263000016 ], [ -60.525758219999886, 7.813374329000027 ], [ -60.586994791999928, 7.727126363000096 ], [ -60.601257486999913, 7.633850403000054 ], [ -60.631694905999979, 7.624600322000035 ], [ -60.671149861999908, 7.566050924000123 ], [ -60.716495931999901, 7.551581523000095 ], [ -60.730577758999942, 7.525433248000084 ], [ -60.70065710499992, 7.453499655000144 ], [ -60.660633707999921, 7.436136373000124 ], [ -60.653243977999921, 7.398464254000089 ], [ -60.628981892999946, 7.38435658800006 ], [ -60.601774251999927, 7.330148011000034 ], [ -60.602239339999869, 7.306531881000112 ], [ -60.643554646999888, 7.250669658000035 ], [ -60.628413452999979, 7.191138408000057 ], [ -60.54800492399994, 7.125509338000128 ], [ -60.475322021999887, 7.188502910000054 ], [ -60.372020833999926, 7.172276509000127 ], [ -60.299932210999941, 7.121013489000106 ], [ -60.291586466999945, 7.088302307000021 ], [ -60.303575398999925, 7.054144185000041 ], [ -60.359696003999971, 7.004896546000055 ], [ -60.37734350599996, 6.938544007000118 ], [ -60.420958414999916, 6.942213034000119 ], [ -60.548728393999937, 6.863096415000129 ], [ -60.63954972399992, 6.837723287000131 ], [ -60.700347046999923, 6.76708160400004 ], [ -60.721534382999977, 6.75969187400004 ], [ -60.793519652999947, 6.793824158000106 ], [ -60.837625487999929, 6.786356913000077 ], [ -60.90756953999994, 6.815244039000035 ], [ -60.899482177999943, 6.768554383000051 ], [ -60.933821166999877, 6.73173492500004 ], [ -61.129829874999928, 6.715844421000028 ], [ -61.190187947999931, 6.632877909000072 ], [ -61.211969563999844, 6.561435242000073 ], [ -61.139751749999903, 6.441261698000105 ], [ -61.160913248999861, 6.342353007000042 ], [ -61.146702229999903, 6.294216411000065 ], [ -61.114792032999929, 6.264011536000055 ], [ -61.121561644999872, 6.18665191600013 ], [ -61.161119954999918, 6.182879537000105 ], [ -61.194477090999982, 6.132856750000116 ], [ -61.269382080999947, 6.107225240000062 ], [ -61.3380858969999, 5.986793314000039 ], [ -61.396712808999922, 5.945581360000034 ], [ -61.37960791099988, 5.905299581000094 ], [ -60.739853678999879, 5.202138367000131 ], [ -60.664302734999922, 5.170254008000072 ], [ -60.598673665999911, 4.996879578000062 ], [ -60.591929891999968, 4.949724834000051 ], [ -60.6126263029999, 4.9005805460001 ], [ -60.718149576999878, 4.784282735000104 ], [ -60.8600272219999, 4.712426656000076 ], [ -60.895813151999931, 4.708525085000119 ], [ -60.947799642999968, 4.573597921000058 ], [ -60.977281046999877, 4.534969788000069 ], [ -61.168587198999944, 4.490243835000101 ], [ -61.238066162999928, 4.515875346000072 ], [ -61.315580810999904, 4.52078460700011 ], [ -61.322944702999905, 4.508847351000071 ], [ -61.293049885999949, 4.448050029000044 ], [ -61.333228312999978, 4.423865459000069 ], [ -61.458181925999924, 4.419137064000083 ], [ -61.501874348999905, 4.401851298000096 ], [ -61.526730712999949, 4.285501811000074 ], [ -61.567270874999878, 4.248527324000037 ], [ -61.737803100999912, 4.252067159000092 ], [ -61.866890828999885, 4.157034200000069 ], [ -61.931486369999931, 4.146414693000082 ], [ -61.990190795999894, 4.166413473000119 ], [ -62.03504593999989, 4.159876404000045 ], [ -62.153591674999888, 4.09029408800005 ], [ -62.428096883999871, 4.183182475000081 ], [ -62.462978474999943, 4.174707540000071 ], [ -62.483700724999977, 4.139179993000113 ], [ -62.536979125999949, 4.125408224000083 ], [ -62.56095699099987, 4.037790833000074 ], [ -62.744356648999911, 4.034018453000058 ], [ -62.766215779999925, 4.020711772000126 ], [ -62.766267455999952, 3.964694520000108 ], [ -62.788798380999964, 3.899401347000079 ], [ -62.74042924099993, 3.741943258000092 ], [ -62.74957596899992, 3.660372010000032 ], [ -62.786317912999891, 3.604406434000026 ], [ -62.889412394999908, 3.56081736200008 ], [ -62.951062377999875, 3.570170797000117 ], [ -62.997054402999964, 3.599135437000086 ], [ -63.251199096999898, 3.886559754000089 ], [ -63.351709757999913, 3.958725891000086 ], [ -63.425400349999848, 3.968363546000106 ], [ -63.468860229999848, 3.867232768000036 ], [ -63.510666463999911, 3.854546204000087 ], [ -63.622804321999894, 3.935213114000106 ], [ -63.671586873999928, 3.946246033000094 ], [ -63.771012329999849, 3.928805237000063 ], [ -63.875140340999934, 3.949811707000066 ], [ -63.996424926999907, 3.880797832000027 ], [ -64.037662719999901, 3.882503154000077 ], [ -64.063810994999898, 3.911596985000088 ], [ -64.125099242999852, 4.088485412000054 ], [ -64.172693236999891, 4.123392843000133 ], [ -64.364981241999942, 4.151866557000076 ], [ -64.608222208999933, 4.126493429000078 ], [ -64.648024188999869, 4.207904544000115 ], [ -64.626850754658562, 4.329968573091151 ], [ -64.667700974720219, 4.558326728395798 ], [ -64.702220831825912, 4.58765310320814 ], [ -64.941999477793672, 4.625196031371729 ], [ -65.085065681136257, 4.799216417503658 ], [ -65.184103562829137, 4.999772651386763 ], [ -65.222163254930251, 5.143924058548464 ], [ -65.282288783800311, 5.226012071399964 ], [ -65.274433966554284, 5.276758327834557 ], [ -65.159040493424015, 5.293682359153536 ], [ -65.117466803849879, 5.355435696000541 ], [ -65.120231493388701, 5.378405870334632 ], [ -65.183612637313331, 5.434035548901477 ], [ -65.144416062751077, 5.473051256310441 ], [ -65.135579392674799, 5.525967922181849 ], [ -65.241826138265651, 5.613171902061595 ], [ -65.264537930181348, 5.661747748160053 ], [ -65.226426561236792, 5.719547837962352 ], [ -65.224643723628958, 5.758563544471997 ], [ -65.265933194161562, 5.773937283079135 ], [ -65.437498949117185, 5.77517751742846 ], [ -65.475093553224895, 5.765488185731158 ], [ -65.551755540685633, 5.690531521512469 ], [ -65.582012092384161, 5.689368801528929 ], [ -65.608857997598477, 5.714896958927511 ], [ -65.63673743428518, 5.789207667999449 ], [ -65.638339402941085, 5.854319972688586 ], [ -65.580255093197991, 6.080636907966891 ], [ -65.590151129570984, 6.121202908087753 ], [ -65.614128994257669, 6.140607408105382 ], [ -65.760890062226565, 6.141537584092248 ], [ -65.827113410055802, 6.110195828574604 ], [ -65.97932634093786, 5.80930980090659 ], [ -66.027462938363897, 5.782231349896847 ], [ -66.123400234633095, 5.784634304229769 ], [ -66.195876431052454, 5.741045233950388 ], [ -66.243832160425825, 5.73334544543593 ], [ -66.274863857580954, 5.781456204440246 ], [ -66.299177619051875, 5.88969249141536 ], [ -66.340777147047675, 5.924212348521053 ], [ -66.552883062803119, 5.742750556293117 ], [ -66.694941575793052, 5.699058132326911 ], [ -66.817569750343694, 5.694252224560501 ], [ -67.00001339360324, 5.619063015445818 ], [ -67.035773485058257, 5.632266343716765 ], [ -67.054893765135148, 5.694329738926285 ], [ -67.076701218586379, 5.713966782940645 ], [ -67.171217414252283, 5.705026760076919 ], [ -67.204031949015246, 5.722803453016923 ], [ -67.20178402431327, 5.782153835531062 ], [ -67.14452653687016, 5.934315090469056 ], [ -67.177961188358154, 6.099783027364822 ], [ -67.195712042876494, 6.112986354736449 ], [ -67.28829037130356, 6.116629543418696 ], [ -67.331517707276362, 6.146265977492874 ], [ -67.384537725935274, 6.119962672839051 ], [ -67.456299400197167, 6.193223721097866 ], [ -67.412391324200257, 6.240575465785128 ], [ -67.336892055823682, 6.254192206105415 ], [ -67.28234758197533, 6.362195949983118 ], [ -67.137808601186009, 6.458624171768122 ], [ -67.148841519120822, 6.528542385122989 ], [ -67.128506843116327, 6.638251451343365 ], [ -67.103392096867765, 6.701451728114762 ], [ -67.049545254110171, 6.755272732450635 ], [ -67.041793788752329, 6.782557888136012 ], [ -67.042878994370085, 6.822012844217397 ], [ -67.061895920760151, 6.851494249559948 ], [ -67.034378221078043, 6.913066718354344 ], [ -67.08155880409555, 7.023240872568181 ], [ -67.089827033390861, 7.065667222864022 ], [ -67.074194912365328, 7.093830877692824 ], [ -66.995155808993388, 7.156824448889211 ], [ -66.931154548343727, 7.169743557219363 ], [ -66.794728767218828, 7.258962917804411 ], [ -66.614533046862618, 7.322938340931671 ], [ -66.427283494937342, 7.598451239033466 ], [ -66.370723640383687, 7.639792385510191 ], [ -66.236287400642993, 7.6361233593056 ], [ -66.130893316673223, 7.683820706260576 ], [ -65.959663459401099, 7.671495876233678 ], [ -65.833986376270218, 7.75714956340164 ], [ -65.768486497953518, 7.841072088905776 ], [ -65.648157924948293, 7.89990570748239 ], [ -65.542867193765971, 7.89995738432583 ], [ -65.446774867865827, 7.861458441753655 ], [ -65.278077155236531, 7.874274197296359 ], [ -65.103695033898703, 7.834379990743969 ], [ -64.99607886364862, 7.770688788456823 ], [ -64.873063117269055, 7.666069850842916 ], [ -64.838465745797521, 7.660204575880471 ], [ -64.63705685119271, 7.771748154753539 ], [ -64.550963915352384, 7.765288601487782 ], [ -64.495463426196125, 7.790790920464588 ], [ -64.478151822148845, 7.814691269886168 ], [ -64.481562465935042, 7.843500880761042 ], [ -64.546158005787333, 7.896650092427819 ], [ -64.552514208064224, 7.925252996828306 ], [ -64.537114631035365, 7.98393158577403 ], [ -64.506237961712543, 7.99917613407132 ], [ -64.450065680786508, 7.990623683935837 ], [ -64.35239722375286, 8.008968818556127 ], [ -64.312942267671531, 8.06545115784462 ], [ -64.283254156753912, 8.081419176553766 ], [ -64.231629401175894, 8.071445624016349 ], [ -64.125563523637709, 7.965870672893232 ], [ -64.065903082761054, 7.98127024992209 ], [ -63.970792608791839, 7.969462184732038 ], [ -63.885371467419304, 8.018193061360705 ], [ -63.839896205845207, 8.110409654581872 ], [ -63.811990933434799, 8.130976874583098 ], [ -63.760727912163418, 8.12118419009829 ], [ -63.66768449574289, 8.159760647036194 ], [ -63.473561977603197, 8.150200507447437 ], [ -63.400026414887122, 8.221927395033219 ], [ -63.33080583442171, 8.213891709734582 ], [ -63.249570482291915, 8.28554108295458 ], [ -63.174639654696307, 8.313446357163627 ], [ -62.976899787195407, 8.309518948540642 ], [ -62.936359626395642, 8.270270697134947 ], [ -62.879102138952533, 8.274120592291467 ], [ -62.770607468659762, 8.375251369954753 ], [ -62.696606817950283, 8.379979763355379 ], [ -62.597646449723868, 8.447985947893187 ], [ -62.247176887403441, 8.313808092369527 ], [ -61.635198737331848, 8.287039699722357 ], [ -61.643389452261431, 8.207974757928696 ], [ -61.609205491939917, 8.118522854246294 ], [ -61.394076504227257, 7.877529812350929 ], [ -61.31919735437441, 7.820582384169654 ], [ -61.208997361738852, 7.852544257311592 ], [ -61.130423347259637, 7.897011826734399 ], [ -61.065724452821257, 7.906158556072512 ], [ -61.019215664271485, 7.942616279517665 ], [ -60.970975714957262, 7.946026923303862 ], [ -60.784630499697812, 7.751775213954943 ], [ -60.706805793152796, 7.818256944202574 ], [ -60.544412604158367, 7.915537828507979 ], [ -60.267998436999875, 7.921262469000098 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-Z", "NAME_1": "Amazonas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -64.648024188999869, 4.207904544000115 ], [ -64.699870361999928, 4.264159444000086 ], [ -64.745939900999929, 4.287620545000053 ], [ -64.791621866999947, 4.284416606000079 ], [ -64.812912557999937, 4.252790629000089 ], [ -64.801259521999953, 4.188530985000043 ], [ -64.727103841999934, 4.140781962000062 ], [ -64.642897094999938, 3.972962748000057 ], [ -64.531431030999954, 3.853512675000104 ], [ -64.434537719999923, 3.77847849600002 ], [ -64.324156859999846, 3.724114889000049 ], [ -64.202975626999915, 3.594717102000089 ], [ -64.197859659999921, 3.51508372000005 ], [ -64.245608682999887, 3.418939717000029 ], [ -64.216308146999921, 3.251430562000024 ], [ -64.222922729999937, 3.123996481000091 ], [ -64.105953125999946, 2.947211405000061 ], [ -63.997561808999905, 2.714925842000042 ], [ -64.012186238999874, 2.603769837000044 ], [ -64.057816528999865, 2.510442200000085 ], [ -64.047972168999905, 2.471323140000052 ], [ -63.831318725999921, 2.428638408000054 ], [ -63.573815063999859, 2.434374491000113 ], [ -63.364887247999889, 2.413083802000131 ], [ -63.372638712999901, 2.266839498000095 ], [ -63.41175777199993, 2.149378967000075 ], [ -63.561981160999949, 2.126357117000026 ], [ -63.617533324999954, 2.101164856000082 ], [ -63.783207967999942, 1.974996847000099 ], [ -63.920822305999934, 1.974325053000115 ], [ -63.995029662999912, 1.958021139000081 ], [ -64.036629190999918, 1.927273661000129 ], [ -64.053604899999925, 1.893709819000108 ], [ -64.072544311999877, 1.684575297000094 ], [ -64.092956502999925, 1.622615255000056 ], [ -64.129724283999906, 1.578070170000061 ], [ -64.301522583999883, 1.446657003000055 ], [ -64.352940633999964, 1.365835063000091 ], [ -64.389579223999903, 1.369297384000035 ], [ -64.394772705999912, 1.392190044000046 ], [ -64.36459366899993, 1.497093201000055 ], [ -64.409009562999898, 1.507506002000085 ], [ -64.551197265999917, 1.419526876000077 ], [ -64.604217285999937, 1.3312893680001 ], [ -64.730876220999846, 1.247573548000062 ], [ -64.839293375999915, 1.270827942000068 ], [ -64.897403523999884, 1.219668274000071 ], [ -64.966469075999953, 1.200599670000088 ], [ -65.01744787599992, 1.162979228000069 ], [ -65.022486328999975, 1.139983216000118 ], [ -65.136768758999921, 1.126909078000068 ], [ -65.160178182999886, 1.080193584000071 ], [ -65.178988402999892, 0.955395 ], [ -65.203043782999941, 0.923820699000089 ], [ -65.327196410999875, 0.910281474000016 ], [ -65.400008503999857, 0.816540426000046 ], [ -65.413883625999915, 0.741609599000085 ], [ -65.45121984899987, 0.690139872000088 ], [ -65.497831990999941, 0.658720601000056 ], [ -65.54266129599992, 0.64931549100001 ], [ -65.58521683799998, 0.691483459000068 ], [ -65.587335571999859, 0.73912913 ], [ -65.533178670999945, 0.816333720000088 ], [ -65.518502563999846, 0.886510315000052 ], [ -65.559843709999882, 0.957978821000069 ], [ -65.608109496999901, 0.985263977000088 ], [ -65.745439615999913, 0.974153545000064 ], [ -65.89176143399996, 0.895605368000119 ], [ -65.974081990999935, 0.806980286000041 ], [ -66.079191853999902, 0.777576396000057 ], [ -66.134382283999884, 0.73111928400003 ], [ -66.208744669999902, 0.76310699500003 ], [ -66.285070760999929, 0.745847066000039 ], [ -66.346203979999927, 0.759386292000016 ], [ -66.87506058799994, 1.222510478000046 ], [ -66.900898803999951, 1.288966370000097 ], [ -66.883535521999931, 1.349944560000068 ], [ -66.932731485999909, 1.424642843000072 ], [ -66.933609985999851, 1.501692403000092 ], [ -66.97417598499996, 1.580033875000083 ], [ -66.980893920999904, 1.66594594300004 ], [ -67.087295694999909, 1.93882334400007 ], [ -67.132615925999914, 1.990809835000093 ], [ -67.111170206999901, 2.048842469000064 ], [ -67.11463252799993, 2.102999370000077 ], [ -67.177832804999895, 2.15449493400007 ], [ -67.217261921999921, 2.266064351000082 ], [ -67.217675333999921, 2.284512838000097 ], [ -67.173750365999894, 2.336447652000103 ], [ -67.189718383999917, 2.394376933000046 ], [ -67.325420694999906, 2.474630432000055 ], [ -67.340613565999917, 2.510493876000098 ], [ -67.470889852999932, 2.627127584000092 ], [ -67.500293741999911, 2.675341695000085 ], [ -67.57558630399987, 2.691103007000066 ], [ -67.594293172999954, 2.776110738000071 ], [ -67.62659094299994, 2.813421122000108 ], [ -67.690411336999972, 2.80634145100008 ], [ -67.751027790999842, 2.842101542000094 ], [ -67.823323120999902, 2.827322083000084 ], [ -67.855930948999941, 2.789753316000073 ], [ -67.85525915499997, 2.858172913000061 ], [ -67.838619344999927, 2.886129863000065 ], [ -67.452182983999933, 3.243679098000101 ], [ -67.395803995999927, 3.266571757000037 ], [ -67.309452677999872, 3.383928935000114 ], [ -67.304646768999959, 3.425709331000064 ], [ -67.403917195999924, 3.504464213000063 ], [ -67.471406616999872, 3.680060730000079 ], [ -67.499828654999902, 3.717913717000059 ], [ -67.537449096999921, 3.735509542000045 ], [ -67.594809936999894, 3.730910340000094 ], [ -67.631758585999933, 3.761864523000014 ], [ -67.644419311999883, 3.834624939000079 ], [ -67.693873657999916, 3.928598531000105 ], [ -67.720642048999878, 4.074972026000083 ], [ -67.786219441999918, 4.172976380000108 ], [ -67.804926310999889, 4.268474426000054 ], [ -67.77939815299996, 4.350794983000114 ], [ -67.799862019999921, 4.398905741000092 ], [ -67.793092406999875, 4.42898142500006 ], [ -67.813504598999913, 4.443269959000048 ], [ -67.829059203999947, 4.491432394000128 ], [ -67.875051228999951, 4.532644348000119 ], [ -67.855155802999946, 4.566156515000046 ], [ -67.845647338999953, 4.689740703000027 ], [ -67.82285803299996, 4.743587545000139 ], [ -67.813504598999913, 4.840506694000084 ], [ -67.826372029999902, 4.894844462000052 ], [ -67.793092406999875, 5.063335470000112 ], [ -67.82663041299989, 5.120386251000113 ], [ -67.813504598999913, 5.186557923000095 ], [ -67.843683634999906, 5.29724884000008 ], [ -67.834588582999942, 5.339313456000099 ], [ -67.772576863999888, 5.409670919000121 ], [ -67.752112996999927, 5.409670919000121 ], [ -67.647003133999874, 5.483361511000055 ], [ -67.614291951999888, 5.55366729800005 ], [ -67.6359960529999, 5.577593485000051 ], [ -67.649070190999936, 5.656089986000083 ], [ -67.625144002999946, 5.784505921000076 ], [ -67.485204223999915, 5.944082743000124 ], [ -67.422469034999978, 5.978240865000103 ], [ -67.428566853999939, 6.038469747000079 ], [ -67.491198689999948, 6.114485779000034 ], [ -67.486961221999906, 6.166782328000039 ], [ -67.456299400197167, 6.193223721097866 ], [ -67.384537725935274, 6.119962672839051 ], [ -67.331517707276362, 6.146265977492874 ], [ -67.275087043032613, 6.112908840370665 ], [ -67.183903977686384, 6.107095242251603 ], [ -67.149616664577422, 6.00994354915548 ], [ -67.14452653687016, 5.934315090469056 ], [ -67.20178402431327, 5.782153835531062 ], [ -67.204031949015246, 5.722803453016923 ], [ -67.171217414252283, 5.705026760076919 ], [ -67.076701218586379, 5.713966782940645 ], [ -67.054893765135148, 5.694329738926285 ], [ -67.035773485058257, 5.632266343716765 ], [ -67.00001339360324, 5.619063015445818 ], [ -66.817569750343694, 5.694252224560501 ], [ -66.694941575793052, 5.699058132326911 ], [ -66.552883062803119, 5.742750556293117 ], [ -66.340777147047675, 5.924212348521053 ], [ -66.299177619051875, 5.88969249141536 ], [ -66.274863857580954, 5.781456204440246 ], [ -66.243832160425825, 5.73334544543593 ], [ -66.195876431052454, 5.741045233950388 ], [ -66.123400234633095, 5.784634304229769 ], [ -66.027462938363897, 5.782231349896847 ], [ -65.97932634093786, 5.80930980090659 ], [ -65.827113410055802, 6.110195828574604 ], [ -65.760890062226565, 6.141537584092248 ], [ -65.614128994257669, 6.140607408105382 ], [ -65.590151129570984, 6.121202908087753 ], [ -65.580255093197991, 6.080636907966891 ], [ -65.638339402941085, 5.854319972688586 ], [ -65.63673743428518, 5.789207667999449 ], [ -65.608857997598477, 5.714896958927511 ], [ -65.582012092384161, 5.689368801528929 ], [ -65.551755540685633, 5.690531521512469 ], [ -65.475093553224895, 5.765488185731158 ], [ -65.437498949117185, 5.77517751742846 ], [ -65.265933194161562, 5.773937283079135 ], [ -65.224643723628958, 5.758563544471997 ], [ -65.226426561236792, 5.719547837962352 ], [ -65.264537930181348, 5.661747748160053 ], [ -65.241826138265651, 5.613171902061595 ], [ -65.135579392674799, 5.525967922181849 ], [ -65.144416062751077, 5.473051256310441 ], [ -65.183612637313331, 5.434035548901477 ], [ -65.120231493388701, 5.378405870334632 ], [ -65.117466803849879, 5.355435696000541 ], [ -65.159040493424015, 5.293682359153536 ], [ -65.274433966554284, 5.276758327834557 ], [ -65.282288783800311, 5.226012071399964 ], [ -65.222163254930251, 5.143924058548464 ], [ -65.184103562829137, 4.999772651386763 ], [ -65.085065681136257, 4.799216417503658 ], [ -64.941999477793672, 4.625196031371729 ], [ -64.702220831825912, 4.58765310320814 ], [ -64.667700974720219, 4.558326728395798 ], [ -64.626850754658562, 4.329968573091151 ], [ -64.648024188999869, 4.207904544000115 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-V", "NAME_1": "Zulia" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -71.357629353999897, 11.850802307000023 ], [ -71.327506533469858, 11.849997690578633 ], [ -71.343861456999946, 11.807521877000056 ], [ -71.336048956999946, 11.789252020000049 ], [ -71.371449347999942, 11.783107815000051 ], [ -71.378163214999915, 11.75844961100006 ], [ -71.507069464999915, 11.709784247000073 ], [ -71.674427863999938, 11.684719143000052 ], [ -71.90070553299995, 11.621323960000041 ], [ -71.960519985999952, 11.59125397300005 ], [ -71.970122850999928, 11.511379299000055 ], [ -71.939320441999939, 11.380764065000051 ], [ -71.856922980999911, 11.216986395000049 ], [ -71.76976477799991, 11.106350002000056 ], [ -71.626454230999911, 11.014960028000075 ], [ -71.624663865999935, 11.000962632000039 ], [ -71.679310675999943, 10.987982489000046 ], [ -71.675282355999911, 11.003607489000046 ], [ -71.697132941999939, 11.025580145000049 ], [ -71.744211391999897, 11.035956122000073 ], [ -71.768666144999941, 11.015285549000055 ], [ -71.715687628999945, 10.95774974200009 ], [ -71.710438605999911, 10.878607489000046 ], [ -71.67406165299991, 10.802394924000055 ], [ -71.576283331999946, 10.721096096000053 ], [ -71.610422329999949, 10.637884833000044 ], [ -71.605580206999946, 10.581854559000078 ], [ -71.630930141999897, 10.518459377000056 ], [ -71.62954667899993, 10.454006252000056 ], [ -71.754465298999946, 10.370998440000051 ], [ -71.897694464999915, 10.139227606000077 ], [ -71.96906490799995, 10.105698960000041 ], [ -72.043690558999913, 9.929592190000051 ], [ -72.124379035999937, 9.826076565000051 ], [ -72.090240037999934, 9.75462474200009 ], [ -71.998931443999936, 9.654730536000045 ], [ -71.946848110999952, 9.541164455000057 ], [ -71.964833136999914, 9.55109284100007 ], [ -71.987863735999952, 9.610052802000041 ], [ -71.987863735999952, 9.589544989000046 ], [ -72.008290167999917, 9.575873114000046 ], [ -71.977894660999937, 9.555894273000092 ], [ -71.960519985999952, 9.51788971600007 ], [ -71.967518683999913, 9.498236395000049 ], [ -71.983713344999899, 9.497463283000059 ], [ -72.015126105999911, 9.521307684000078 ], [ -71.995228644999941, 9.459214585000041 ], [ -71.936390753999945, 9.500189520000049 ], [ -71.918934699999909, 9.480292059000078 ], [ -71.918934699999909, 9.500189520000049 ], [ -71.84439042899993, 9.439357815000051 ], [ -71.900746222999942, 9.434556382000039 ], [ -71.913807745999918, 9.412583726000037 ], [ -71.905262824999909, 9.384711005000042 ], [ -71.891590949999909, 9.425726630000042 ], [ -71.833566860999952, 9.425726630000042 ], [ -71.760853644999941, 9.364732164000088 ], [ -71.734527147999927, 9.384711005000042 ], [ -71.728016730999911, 9.348089911000045 ], [ -71.748199022999927, 9.343166408000059 ], [ -71.739979620999918, 9.28937409100007 ], [ -71.816517706999946, 9.233303127000056 ], [ -71.744699673999946, 9.237616278000075 ], [ -71.749379035999937, 9.216294664000088 ], [ -71.734527147999927, 9.206000067000048 ], [ -71.753244594999899, 9.204250393000052 ], [ -71.751820441999939, 9.190741278000075 ], [ -71.734527147999927, 9.165025132000039 ], [ -71.761870897999927, 9.130845445000091 ], [ -71.708566860999952, 9.076727606000077 ], [ -71.60220292899993, 9.042303778000075 ], [ -71.514800584999932, 9.048976955000057 ], [ -71.273548956999946, 9.13507721600007 ], [ -71.218534513694877, 9.187001923563491 ], [ -71.147382981639282, 9.127815252871585 ], [ -71.148623215988607, 9.033479926157668 ], [ -71.187096320139062, 8.992526353308563 ], [ -71.225595261811861, 9.048388576771401 ], [ -71.29634029836609, 9.013610338146577 ], [ -71.673526577389623, 8.718796291915339 ], [ -71.726029833010386, 8.617226263781049 ], [ -71.758534309410834, 8.630197048055322 ], [ -71.808066169018446, 8.619629218113914 ], [ -71.808712124165197, 8.666034653876181 ], [ -71.856797044747793, 8.668127549846531 ], [ -71.937567307984864, 8.620869452463239 ], [ -71.993842942597723, 8.532115179871653 ], [ -72.042186244699394, 8.486820787249542 ], [ -72.129829475050201, 8.456796780447064 ], [ -72.172720913339447, 8.458037013897069 ], [ -72.235326910908213, 8.399435940216449 ], [ -72.253181118214002, 8.527309272105185 ], [ -72.281189745210554, 8.54167532035973 ], [ -72.341961229227309, 8.495502427694873 ], [ -72.352968308740458, 8.454006252486522 ], [ -72.369091356181116, 8.432276313401132 ], [ -72.388108282571181, 8.435454413190598 ], [ -72.415609207199168, 8.382691114103636 ], [ -72.45627030499989, 8.403932597000079 ], [ -72.675430053999946, 8.651514384000052 ], [ -72.783072062999878, 9.059939067000116 ], [ -72.800021932999897, 9.079446920000123 ], [ -72.791030232999844, 9.113940939000102 ], [ -72.826686971999919, 9.141691182000045 ], [ -72.955309611999979, 9.103993225000096 ], [ -72.973189656999949, 9.128436178000044 ], [ -72.980062622999895, 9.216518656000076 ], [ -73.009724894999863, 9.295376892000093 ], [ -73.032669230999915, 9.294601746000083 ], [ -73.212244832999886, 9.173446350000063 ], [ -73.377816121999871, 9.164687195000084 ], [ -73.390838582999919, 9.194504496000093 ], [ -73.324382690999954, 9.255921936000078 ], [ -73.178448445999919, 9.523037415000147 ], [ -73.107651733999973, 9.577995301000087 ], [ -72.985540323999885, 9.81216705300011 ], [ -72.977633829999945, 9.838056946000052 ], [ -72.996960814999909, 9.900714620000073 ], [ -72.987710733999876, 9.999416606000082 ], [ -72.935620890999928, 10.175193991000057 ], [ -72.914898640999894, 10.432904358000073 ], [ -72.843016723999966, 10.560596822000065 ], [ -72.754391641999888, 10.674853414000012 ], [ -72.682974812999902, 10.855617575000025 ], [ -72.576469685999939, 10.957368469000073 ], [ -72.49931677299989, 11.12079518700007 ], [ -72.341341918999944, 11.162110494000103 ], [ -72.267082885999884, 11.154901632000048 ], [ -72.007925578999874, 11.624614563000065 ], [ -71.971080281999946, 11.661924948000106 ], [ -71.449458373999931, 11.795456848000086 ], [ -71.357629353999897, 11.850802307000023 ] ] ], [ [ [ -71.062446101576569, 9.617403481272083 ], [ -71.035064256999931, 9.740383205000057 ], [ -71.08617102799991, 9.811997789000088 ], [ -71.090240037999934, 9.836615302000041 ], [ -71.072824673999946, 9.841620184000078 ], [ -71.072417772999927, 9.857855536000045 ], [ -71.162464972999942, 9.970933335000041 ], [ -71.206939256999931, 9.980617580000057 ], [ -71.26781165299991, 10.151922919000071 ], [ -71.363880988999938, 10.219956773000092 ], [ -71.422596808999913, 10.343166408000059 ], [ -71.469349738999938, 10.40180084800005 ], [ -71.466297980999911, 10.502142645000049 ], [ -71.541574673999946, 10.564886786000045 ], [ -71.537464972999942, 10.59796784100007 ], [ -71.500111456999946, 10.627997137000079 ], [ -71.532866990999935, 10.67649974200009 ], [ -71.531361456999946, 10.75267161700009 ], [ -71.583119269999941, 10.80923086100006 ], [ -71.50999915299991, 10.812648830000057 ], [ -71.445912238999938, 10.796210028000075 ], [ -71.435292120999918, 10.818915106000077 ], [ -71.45335852799991, 10.871893622000073 ], [ -71.412464972999942, 10.919094143000052 ], [ -71.447661912999934, 10.920396226000037 ], [ -71.501128709999932, 10.960028387000079 ], [ -71.458322719999899, 10.97492096600007 ], [ -71.282012498999904, 10.991441148000092 ], [ -71.246007453081461, 10.908352565818234 ], [ -71.08046200181991, 10.756759752560527 ], [ -71.081004605078476, 10.638575751469716 ], [ -71.039663458601694, 10.589560654900311 ], [ -71.014832933193304, 10.518867296088843 ], [ -70.95734290175352, 10.460292059930623 ], [ -70.903134324689347, 10.442902939718863 ], [ -70.778697475907791, 10.453625800190537 ], [ -70.745185310054012, 10.415126858517681 ], [ -70.729036424191634, 10.331979478470146 ], [ -70.658084682961714, 10.304771837150554 ], [ -70.710794644157488, 10.194158433364976 ], [ -70.824999558882553, 10.121320501739774 ], [ -70.858149991329014, 10.070031642945935 ], [ -70.85481686100934, 10.043547472038199 ], [ -70.806809454792472, 9.983938707105608 ], [ -70.661159430863052, 9.904512030106105 ], [ -70.636328904555285, 9.839942327776214 ], [ -70.641289841952641, 9.791960760880386 ], [ -70.694929979135225, 9.746743883523379 ], [ -70.737692227114565, 9.761704210081234 ], [ -70.761540899692761, 9.716461493403187 ], [ -70.75689002065792, 9.692431951873061 ], [ -70.794045376093209, 9.678608506877083 ], [ -70.851354540379702, 9.602204901834739 ], [ -71.062446101576569, 9.617403481272083 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-S", "NAME_1": "Táchira" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -72.350075235999924, 8.042585144000014 ], [ -72.33384883599993, 8.065477804000125 ], [ -72.335760864999941, 8.103899231000071 ], [ -72.390537882999922, 8.234330546000095 ], [ -72.386765502999907, 8.33861358700004 ], [ -72.415609207199168, 8.382691114103636 ], [ -72.388108282571181, 8.435454413190598 ], [ -72.369091356181116, 8.432276313401132 ], [ -72.352968308740458, 8.454006252486522 ], [ -72.341961229227309, 8.495502427694873 ], [ -72.281189745210554, 8.54167532035973 ], [ -72.257366909255438, 8.536998602903168 ], [ -72.235326910908213, 8.399435940216449 ], [ -72.172720913339447, 8.458037013897069 ], [ -72.129829475050201, 8.456796780447064 ], [ -72.042186244699394, 8.486820787249542 ], [ -71.993842942597723, 8.532115179871653 ], [ -71.944931199715086, 8.611412664762668 ], [ -71.823129849263125, 8.590302843301572 ], [ -71.802665982049405, 8.570691636809556 ], [ -71.772254400719987, 8.468966579943697 ], [ -71.829641079372323, 8.395405177906639 ], [ -71.810779181713826, 8.339232896081285 ], [ -71.818530646172348, 8.310371609262347 ], [ -71.886459317243691, 8.232107652246327 ], [ -71.897104661550884, 8.175470282427568 ], [ -71.821321174132891, 8.170483507507868 ], [ -71.711353726393327, 8.049069728884888 ], [ -71.680761277910619, 8.061162014015736 ], [ -71.588854743051911, 8.057286282236134 ], [ -71.507722743709621, 8.005403144239722 ], [ -71.499945440829435, 7.969927272725442 ], [ -71.522243821595055, 7.929903875863147 ], [ -71.506094936631996, 7.829961655705858 ], [ -71.532785814014119, 7.75828644496346 ], [ -71.491212124439983, 7.712656155557113 ], [ -71.490902066077467, 7.629792996349693 ], [ -71.377963223224185, 7.524037177173966 ], [ -71.317605150357394, 7.499594224493876 ], [ -71.36067745579993, 7.486184189748542 ], [ -71.692000902319762, 7.549332791475138 ], [ -71.826721361101932, 7.535922755830484 ], [ -71.845815802757102, 7.526130072245053 ], [ -71.839640469432084, 7.490680040051814 ], [ -71.875012987259538, 7.421485297108745 ], [ -72.010870326704207, 7.363375148943931 ], [ -72.068799607715732, 7.375002346081374 ], [ -72.188533902417646, 7.449803982467813 ], [ -72.319714525305073, 7.448408718487542 ], [ -72.39581243299989, 7.407491518000143 ], [ -72.414619099999868, 7.413812155000059 ], [ -72.478697875999899, 7.484453837000061 ], [ -72.463401651999931, 7.570753479000103 ], [ -72.483348754999952, 7.649353333000064 ], [ -72.451774454999878, 7.832804667000104 ], [ -72.45864741999992, 7.893524475000106 ], [ -72.491203572999979, 7.937501119000061 ], [ -72.430122029999978, 7.990521139000066 ], [ -72.40707434199993, 8.043773702000124 ], [ -72.350075235999924, 8.042585144000014 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-C", "NAME_1": "Apure" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -72.321808227999952, 7.390040995000106 ], [ -72.39581243299989, 7.407491518000143 ], [ -72.319714525305073, 7.448408718487542 ], [ -72.188533902417646, 7.449803982467813 ], [ -72.068799607715732, 7.375002346081374 ], [ -71.990277269180638, 7.365468044015017 ], [ -71.881162482162836, 7.41603343329632 ], [ -71.829873623368997, 7.49980093006883 ], [ -71.748767463347747, 7.47827769655845 ], [ -71.715849574897959, 7.442465929159312 ], [ -71.66034908664102, 7.432156479837658 ], [ -71.63957516106484, 7.432337347890268 ], [ -71.627560391199097, 7.453395494306619 ], [ -71.607199876772881, 7.438305976539596 ], [ -71.563119880078375, 7.452594509528979 ], [ -71.520926072879945, 7.438305976539596 ], [ -71.454418505109913, 7.463885809882186 ], [ -71.267685716222786, 7.445127265011251 ], [ -71.248849656986067, 7.454532375868439 ], [ -71.189163377687692, 7.404173692162146 ], [ -71.06136756016474, 7.378723049129405 ], [ -70.946775071812112, 7.307978014373873 ], [ -70.874169685082904, 7.287488307839112 ], [ -70.795337287285975, 7.314799302845529 ], [ -70.712861700806855, 7.289942939015418 ], [ -70.630851203220459, 7.294309597210145 ], [ -70.603540209113362, 7.328441880688217 ], [ -70.547833015281412, 7.333712877347409 ], [ -70.500523241054736, 7.383683987426082 ], [ -70.471842821389089, 7.381901149818191 ], [ -70.460241461774046, 7.423061428242306 ], [ -70.368334926915338, 7.450449936715188 ], [ -70.320895962378756, 7.516879991018754 ], [ -70.288882412393377, 7.603773912536042 ], [ -70.157185024669161, 7.615013536045865 ], [ -70.133517219244254, 7.629327908356288 ], [ -70.086595017745879, 7.710744126740053 ], [ -70.013886278229165, 7.754255683552913 ], [ -69.93549313000392, 7.757769680126614 ], [ -69.862991096062217, 7.811978258090107 ], [ -69.835137498696611, 7.807637437417782 ], [ -69.733696661771489, 7.844431056747851 ], [ -69.57703955832892, 7.951039537544602 ], [ -69.440949673088937, 8.071652330490622 ], [ -69.188691169262029, 8.070670478559748 ], [ -69.133449063423541, 8.041628322788881 ], [ -69.112649299425641, 8.006850084164057 ], [ -69.054306607264095, 7.980185045203655 ], [ -68.970280728073135, 7.99938283874701 ], [ -68.945062629037068, 7.931764227836823 ], [ -68.823467984160118, 7.902515367390265 ], [ -68.72983028763764, 7.915847886870495 ], [ -68.63386715384604, 7.969358831944533 ], [ -68.485142381115963, 7.938585517207855 ], [ -68.425895352288649, 7.97935822200435 ], [ -68.374709846282371, 7.991347154347693 ], [ -68.341740281888463, 7.965896511314952 ], [ -68.275594449324387, 7.970934963078093 ], [ -68.256577521135682, 7.956517238879485 ], [ -68.054367641753231, 8.048449612159857 ], [ -67.954425421595943, 8.054650783906538 ], [ -67.88481726840223, 8.026719672175091 ], [ -67.862570562681299, 8.034807034317168 ], [ -67.605299444613649, 7.99940867806805 ], [ -67.54618160699556, 7.962511705051156 ], [ -67.538120083275203, 7.917010605954715 ], [ -67.468124355554551, 7.903833116105432 ], [ -67.395829027187858, 7.911274522201438 ], [ -67.337899746176333, 7.889079495122587 ], [ -67.304542609054181, 7.842932440879451 ], [ -67.226485357613171, 7.798516547400709 ], [ -67.139694789782709, 7.772239081168664 ], [ -67.056754116209504, 7.797457180204674 ], [ -67.015697190572894, 7.769526069372603 ], [ -66.950791592358087, 7.788387966131722 ], [ -66.764782273882815, 7.755108344274674 ], [ -66.546087612753126, 7.795209255502755 ], [ -66.54554501039388, 7.811073920525018 ], [ -66.527509935035482, 7.816344916284834 ], [ -66.456532355383899, 7.746219998254276 ], [ -66.394804856958558, 7.727874864533362 ], [ -66.352611049760128, 7.735781357723454 ], [ -66.324602423662895, 7.687593085252672 ], [ -66.330519374569462, 7.648422349112082 ], [ -66.370723640383687, 7.639792385510191 ], [ -66.427283494937342, 7.598451239033466 ], [ -66.614533046862618, 7.322938340931671 ], [ -66.794728767218828, 7.258962917804411 ], [ -66.931154548343727, 7.169743557219363 ], [ -66.995155808993388, 7.156824448889211 ], [ -67.074194912365328, 7.093830877692824 ], [ -67.089827033390861, 7.065667222864022 ], [ -67.08155880409555, 7.023240872568181 ], [ -67.034378221078043, 6.913066718354344 ], [ -67.061895920760151, 6.851494249559948 ], [ -67.042878994370085, 6.822012844217397 ], [ -67.041793788752329, 6.782557888136012 ], [ -67.049545254110171, 6.755272732450635 ], [ -67.103392096867765, 6.701451728114762 ], [ -67.128506843116327, 6.638251451343365 ], [ -67.148841519120822, 6.528542385122989 ], [ -67.131142341445866, 6.475548203986421 ], [ -67.170235562321352, 6.429375312220884 ], [ -67.28234758197533, 6.362195949983118 ], [ -67.322345140415905, 6.272511501404665 ], [ -67.355857307169003, 6.243262640958108 ], [ -67.412391324200257, 6.240575465785128 ], [ -67.450972372177205, 6.19803546276637 ], [ -67.490475219999951, 6.201638082000017 ], [ -67.573984334999949, 6.266233622000058 ], [ -67.827198852999942, 6.313414205000072 ], [ -67.868126587999967, 6.279876201000064 ], [ -67.904300089999879, 6.275147807000081 ], [ -67.924143839999971, 6.234555970000144 ], [ -67.977990682999916, 6.217838644000011 ], [ -68.146507527999887, 6.223781433000028 ], [ -68.304172322999932, 6.176988424000101 ], [ -68.4490213629999, 6.194997661000102 ], [ -68.584723673999861, 6.170012106000115 ], [ -68.635314900999902, 6.135879822000049 ], [ -68.807862507999886, 6.184326477000099 ], [ -68.892921915999892, 6.184326477000099 ], [ -69.061128702999895, 6.217838644000011 ], [ -69.246104492999876, 6.08066355400004 ], [ -69.331396443999949, 6.15636952700001 ], [ -69.443637654999947, 6.122237244000132 ], [ -70.129203043999922, 6.972547099000067 ], [ -70.195012979999888, 6.977559713000034 ], [ -70.287617146999935, 6.936942037000094 ], [ -70.31906225599991, 6.938285624000059 ], [ -70.451663981999928, 7.007687073000113 ], [ -70.510704305999866, 7.009702454000063 ], [ -70.57860713799991, 7.085821838000044 ], [ -70.63927526899991, 7.073471171000094 ], [ -70.703302368999886, 7.099929504000073 ], [ -70.895538696999921, 7.06851023300004 ], [ -70.961322794999916, 7.009444072000093 ], [ -71.011268065999872, 6.99089223200005 ], [ -71.13604081299988, 6.99213246700009 ], [ -71.18404821799993, 6.962573547000062 ], [ -71.275515503999969, 6.984381002000077 ], [ -71.292517048999883, 7.025773824000041 ], [ -71.413904988999974, 7.030993144000135 ], [ -71.467700154999903, 7.012441304000106 ], [ -71.509919799999864, 7.034610494000034 ], [ -71.5947208259999, 7.030114645000111 ], [ -71.62040401299987, 7.052128805000095 ], [ -71.65430375199989, 7.053369039000117 ], [ -71.673527384999915, 7.044222310000052 ], [ -71.669599975999944, 7.027737529000063 ], [ -71.77403804599993, 7.028926086000084 ], [ -71.777758748999929, 7.007532044000072 ], [ -71.881008259999902, 6.986603089000084 ], [ -71.99381791199994, 7.012854716000021 ], [ -72.080996052999922, 7.066598206000023 ], [ -72.164143432999907, 7.22080068000011 ], [ -72.166313843999916, 7.334075419000101 ], [ -72.20620804899994, 7.381876119000083 ], [ -72.321808227999952, 7.390040995000106 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-L", "NAME_1": "Mérida" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.218534513694877, 9.187001923563491 ], [ -71.206410285999937, 9.232163804000038 ], [ -71.151722785999937, 9.28851959800005 ], [ -71.072824673999946, 9.313544012000079 ], [ -71.033178066914218, 9.352504381072322 ], [ -70.973595140403404, 9.351264145823677 ], [ -70.917732916940565, 9.302869167777885 ], [ -70.86305925188293, 9.139003201336664 ], [ -70.789058601173508, 9.091202500694862 ], [ -70.776630419258424, 9.066759548014716 ], [ -70.731491055367883, 9.053504542900328 ], [ -70.702474738018736, 8.991596178221016 ], [ -70.677256638982669, 8.985860094467796 ], [ -70.580027432420081, 9.040223700263539 ], [ -70.541864386632142, 9.005316270429546 ], [ -70.53468136295453, 8.955345160350873 ], [ -70.57746944935559, 8.856669012964574 ], [ -70.686945969780652, 8.82362193420488 ], [ -70.727692837054747, 8.764736640583465 ], [ -70.768568894638747, 8.781479803849834 ], [ -70.837711961637694, 8.725462550756106 ], [ -70.910058966847828, 8.624125068417186 ], [ -70.929954393280639, 8.629266872967776 ], [ -70.969667730881042, 8.591930650379197 ], [ -70.9804422681961, 8.506664536838912 ], [ -71.027364467895893, 8.465323391261506 ], [ -71.038371548308305, 8.424343979990681 ], [ -71.077542284448839, 8.376336575572509 ], [ -71.065139940056156, 8.307813626197856 ], [ -71.031498582993208, 8.278952338479598 ], [ -71.011835699657809, 8.219756984697085 ], [ -71.059946458662125, 8.110047919375972 ], [ -71.253784755961703, 7.922772529028975 ], [ -71.429665493167988, 7.802263087971141 ], [ -71.462144131146715, 7.769526069372603 ], [ -71.456692268233553, 7.702424221500621 ], [ -71.483564011869646, 7.684492498929671 ], [ -71.496483120199798, 7.724696763844577 ], [ -71.532785814014119, 7.75828644496346 ], [ -71.506094936631996, 7.829961655705858 ], [ -71.522243821595055, 7.929903875863147 ], [ -71.499945440829435, 7.969927272725442 ], [ -71.507722743709621, 8.005403144239722 ], [ -71.588854743051911, 8.057286282236134 ], [ -71.680761277910619, 8.061162014015736 ], [ -71.711353726393327, 8.049069728884888 ], [ -71.821321174132891, 8.170483507507868 ], [ -71.897104661550884, 8.175470282427568 ], [ -71.886459317243691, 8.232107652246327 ], [ -71.818530646172348, 8.310371609262347 ], [ -71.810779181713826, 8.339232896081285 ], [ -71.829641079372323, 8.395405177906639 ], [ -71.771065843214103, 8.480929673865319 ], [ -71.817135383091454, 8.587047227347625 ], [ -71.944931199715086, 8.611412664762668 ], [ -71.833310105576913, 8.673166002508992 ], [ -71.802640143627741, 8.658283189417659 ], [ -71.808066169018446, 8.619629218113914 ], [ -71.758534309410834, 8.630197048055322 ], [ -71.726029833010386, 8.617226263781049 ], [ -71.673526577389623, 8.718796291915339 ], [ -71.29634029836609, 9.013610338146577 ], [ -71.225595261811861, 9.048388576771401 ], [ -71.194563564656789, 8.996247057255857 ], [ -71.157304857333315, 9.011129869447927 ], [ -71.147382981639282, 9.127815252871585 ], [ -71.218534513694877, 9.187001923563491 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-T", "NAME_1": "Trujillo" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.058672448148286, 9.337930190416188 ], [ -71.090809699999909, 9.544094143000052 ], [ -71.062446101576569, 9.617403481272083 ], [ -70.851354540379702, 9.602204901834739 ], [ -70.794045376093209, 9.678608506877083 ], [ -70.75689002065792, 9.692431951873061 ], [ -70.761540899692761, 9.716461493403187 ], [ -70.737692227114565, 9.761704210081234 ], [ -70.694929979135225, 9.746743883523379 ], [ -70.656172655043974, 9.777077947789053 ], [ -70.636328904555285, 9.839942327776214 ], [ -70.661159430863052, 9.904512030106105 ], [ -70.662012091584756, 9.955826728220927 ], [ -70.608630336820568, 10.031558538795537 ], [ -70.566410692099737, 10.030318305345475 ], [ -70.56144975470238, 9.989338894074706 ], [ -70.5167496412829, 9.92851573321451 ], [ -70.454686245174059, 9.896243800810737 ], [ -70.351643438693714, 9.92603526541518 ], [ -70.329319221305013, 9.88632192601608 ], [ -70.279658168689537, 9.873893744100997 ], [ -70.247386237185083, 9.82673900040453 ], [ -70.213331468072795, 9.84580760273866 ], [ -70.160750698985566, 9.785294501140299 ], [ -70.09413977662939, 9.775837714339048 ], [ -70.01584998209097, 9.698943182881578 ], [ -70.032825690253389, 9.668454088085696 ], [ -70.074709439089304, 9.666051133752831 ], [ -70.13480913043702, 9.610731513548501 ], [ -70.109280972139118, 9.517145493869407 ], [ -70.062152065965051, 9.492650865245196 ], [ -70.032980719884279, 9.430329088516601 ], [ -70.064580857820317, 9.356328436907802 ], [ -70.137832200595597, 9.258014023828139 ], [ -70.092331102398418, 9.239229641434804 ], [ -70.065356005075557, 9.252277940074862 ], [ -70.059361538004566, 9.236826687101939 ], [ -70.062720505846642, 9.143654080371505 ], [ -70.124112108387067, 9.020069892311653 ], [ -70.182454799649292, 9.0078742543933 ], [ -70.271312425028384, 9.023403021732065 ], [ -70.426729295920268, 9.022472845745199 ], [ -70.496079067594906, 8.999270128313754 ], [ -70.53468136295453, 8.955345160350873 ], [ -70.541864386632142, 9.005316270429546 ], [ -70.580027432420081, 9.040223700263539 ], [ -70.695162523131899, 8.985059108790836 ], [ -70.731491055367883, 9.053504542900328 ], [ -70.776630419258424, 9.066759548014716 ], [ -70.789058601173508, 9.091202500694862 ], [ -70.86305925188293, 9.139003201336664 ], [ -70.927654791735222, 9.312791043471861 ], [ -70.973595140403404, 9.351264145823677 ], [ -71.033178066914218, 9.352504381072322 ], [ -71.058672448148286, 9.337930190416188 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-I", "NAME_1": "Falcón" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -71.282012498999904, 10.991441148000092 ], [ -70.869699673999946, 11.196275132000039 ], [ -70.685617641999897, 11.248032945000091 ], [ -70.629750128999945, 11.239203192000048 ], [ -70.51390540299991, 11.253159898000092 ], [ -70.480132615999935, 11.289007880000042 ], [ -70.507435675999943, 11.261664130000042 ], [ -70.510609503999945, 11.286363023000092 ], [ -70.486439581999946, 11.295111395000049 ], [ -70.433948348999934, 11.287597019000088 ], [ -70.287953253999945, 11.357082424000055 ], [ -70.231067497999902, 11.351587093000091 ], [ -70.159006313999953, 11.401434637000079 ], [ -70.14517167899993, 11.428941148000092 ], [ -70.146003777999908, 11.454411962000052 ], [ -70.164402948999907, 11.462932823000074 ], [ -70.154466002999925, 11.469974238000077 ], [ -70.099373864999905, 11.429547051000043 ], [ -70.079009568999936, 11.45734284100007 ], [ -70.036529100999928, 11.440904039000088 ], [ -70.053909272999931, 11.506482221000056 ], [ -70.119862433999913, 11.522406317000048 ], [ -70.096301319999952, 11.531066220000071 ], [ -70.161597534999942, 11.568545162000078 ], [ -70.02437386899993, 11.51407335500005 ], [ -69.975624951999919, 11.502896389000057 ], [ -69.945977997999933, 11.519773538000038 ], [ -69.925898823999944, 11.513060548000055 ], [ -69.844604512999922, 11.436231517000067 ], [ -69.814076300999943, 11.425604559000078 ], [ -69.75999915299991, 11.468085028000075 ], [ -69.743641730999911, 11.50336334800005 ], [ -69.816029425999943, 11.69367096600007 ], [ -69.825021938999953, 11.67523834800005 ], [ -69.849517381999931, 11.69367096600007 ], [ -69.927723761999914, 11.658433335000041 ], [ -69.950062628999945, 11.656683661000045 ], [ -69.945139126999948, 11.673244533000059 ], [ -70.186512824999909, 11.602687893000052 ], [ -70.229888475999928, 11.627875067000048 ], [ -70.233143683999913, 11.652736721000053 ], [ -70.212391730999911, 11.687201239000046 ], [ -70.233143683999913, 11.74835846600007 ], [ -70.205799933999913, 11.73468659100007 ], [ -70.205922003999945, 11.762518622000073 ], [ -70.223947719999899, 11.788397528000075 ], [ -70.240589972999942, 11.761948960000041 ], [ -70.284535285999937, 11.857326565000051 ], [ -70.301991339999915, 11.85814036700009 ], [ -70.283558722999942, 11.939642645000049 ], [ -70.213246222999942, 12.056789455000057 ], [ -70.205799933999913, 12.112005927000041 ], [ -70.144276495999918, 12.117987372000073 ], [ -70.064564581999946, 12.181463934000078 ], [ -70.017730272999927, 12.198919989000046 ], [ -69.925363735999952, 12.15961334800005 ], [ -69.835316535999937, 12.015204169000071 ], [ -69.808583136999914, 11.803615627000056 ], [ -69.747141079999949, 11.63226959800005 ], [ -69.665842251999948, 11.497748114000046 ], [ -69.623605923999946, 11.467759507000039 ], [ -69.588693813999953, 11.463039455000057 ], [ -69.500070766999897, 11.508734442000048 ], [ -69.376698370999918, 11.494045315000051 ], [ -69.270415818999936, 11.536037502000056 ], [ -69.109038865999935, 11.491359768000052 ], [ -69.061879035999937, 11.453517971000053 ], [ -68.84439042899993, 11.447414455000057 ], [ -68.754383917999917, 11.374090887000079 ], [ -68.655669725999928, 11.347886460000041 ], [ -68.615223761999914, 11.303412177000041 ], [ -68.517974412999934, 11.249335028000075 ], [ -68.483509894999941, 11.206935940000051 ], [ -68.417591925999943, 11.17914459800005 ], [ -68.403309699999909, 11.200262762000079 ], [ -68.388661261999914, 11.128241278000075 ], [ -68.278431769999941, 10.925482489000046 ], [ -68.287261522999927, 10.91282786700009 ], [ -68.335072394999941, 10.939601955000057 ], [ -68.376616990999935, 10.919094143000052 ], [ -68.262684699999909, 10.903143622000073 ], [ -68.238840298999946, 10.884955145000049 ], [ -68.266184048999946, 10.858099677000041 ], [ -68.326568162999934, 10.849269924000055 ], [ -68.331939256999931, 10.829575914000088 ], [ -68.318348761999914, 10.745184637000079 ], [ -68.27375240799995, 10.63422272300005 ], [ -68.519378018280918, 10.638575751469716 ], [ -68.591389125807495, 10.678314928391217 ], [ -68.596350064104172, 10.720508734690327 ], [ -68.633582933005925, 10.73293691750473 ], [ -68.76920773025256, 10.732471829511326 ], [ -68.80928280305892, 10.686221422480628 ], [ -68.885505540947918, 10.659530544199242 ], [ -68.924107836307599, 10.697331854781282 ], [ -69.126266038846609, 10.681260484184008 ], [ -69.426092699318588, 10.7119046095101 ], [ -69.498594733260347, 10.695135606023371 ], [ -69.537197027720651, 10.742006129779043 ], [ -69.663933478047568, 10.764666245750618 ], [ -69.789868943596844, 10.701440131456877 ], [ -69.821236538435471, 10.701750189819393 ], [ -69.806069505403343, 10.720353705059438 ], [ -69.823794522399282, 10.730301418275815 ], [ -69.866582607901023, 10.698003648349697 ], [ -69.969315355119534, 10.690484726988529 ], [ -70.047217576929597, 10.645267848732203 ], [ -70.15749508303162, 10.651701565374935 ], [ -70.247179531610072, 10.558373928114293 ], [ -70.330275234814223, 10.558063869751777 ], [ -70.414533657102595, 10.483804835724584 ], [ -70.49230668770349, 10.447424628443855 ], [ -70.535378994045345, 10.363011176524537 ], [ -70.613177863067904, 10.341462103693118 ], [ -70.658084682961714, 10.304771837150554 ], [ -70.729036424191634, 10.331979478470146 ], [ -70.745185310054012, 10.415126858517681 ], [ -70.778697475907791, 10.453625800190537 ], [ -70.903134324689347, 10.442902939718863 ], [ -70.95734290175352, 10.460292059930623 ], [ -71.014832933193304, 10.518867296088843 ], [ -71.039663458601694, 10.589560654900311 ], [ -71.081004605078476, 10.638575751469716 ], [ -71.08046200181991, 10.756759752560527 ], [ -71.246007453081461, 10.908352565818234 ], [ -71.282012498999904, 10.991441148000092 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-U", "NAME_1": "Yaracuy" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.27375240799995, 10.63422272300005 ], [ -68.251739062407808, 10.595119533539616 ], [ -68.281692268283564, 10.558580633689303 ], [ -68.314351773415581, 10.539434516090012 ], [ -68.362669237095588, 10.548581244528805 ], [ -68.389540981631001, 10.493494168321206 ], [ -68.394114346300057, 10.358179430336406 ], [ -68.361609869899553, 10.260898546031058 ], [ -68.423182338693948, 10.172919419795392 ], [ -68.415146654294631, 10.073907376524176 ], [ -68.370498215919895, 9.990036526064785 ], [ -68.522556118070383, 9.895856228082437 ], [ -68.542968309339983, 9.904382838896879 ], [ -68.52829220182366, 9.923012193457964 ], [ -68.582113207058853, 9.952106025172895 ], [ -68.582242398268079, 10.00502269104436 ], [ -68.629939745223055, 10.01037120206928 ], [ -68.66970475876758, 9.9687975124952 ], [ -68.804321865661564, 9.960865179984069 ], [ -68.851786668619866, 9.860018622261578 ], [ -68.885014615432169, 9.851078599397852 ], [ -68.977722134169142, 9.857279771144533 ], [ -68.924469570614178, 9.935026964223027 ], [ -68.958808559667261, 10.000216783277892 ], [ -68.979117398149413, 10.00982859881077 ], [ -69.071954108095611, 9.958152167288688 ], [ -69.079473028557402, 9.886011868552885 ], [ -69.105311245217763, 9.882032782187139 ], [ -69.139210984699162, 9.933399156246026 ], [ -69.141510586244522, 10.005332750306195 ], [ -69.22747433087568, 10.110132555073335 ], [ -69.237551236200602, 10.14708120403435 ], [ -69.219567836786212, 10.171834215076956 ], [ -69.162077806245748, 10.128064276744965 ], [ -69.117997809551241, 10.202710883500458 ], [ -69.014980842391935, 10.24841868727259 ], [ -69.027176480310288, 10.423059190129493 ], [ -69.060559454954898, 10.419260972715676 ], [ -69.072083299304836, 10.437942003220883 ], [ -69.020096809420181, 10.554782416275486 ], [ -68.964389614688969, 10.556875312245836 ], [ -68.901137661074188, 10.598009752248231 ], [ -68.885505540947918, 10.659530544199242 ], [ -68.80928280305892, 10.686221422480628 ], [ -68.76920773025256, 10.732471829511326 ], [ -68.613713344994892, 10.727975979208054 ], [ -68.596350064104172, 10.720508734690327 ], [ -68.591389125807495, 10.678314928391217 ], [ -68.519378018280918, 10.638575751469716 ], [ -68.27375240799995, 10.63422272300005 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-G", "NAME_1": "Carabobo" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.251739062407808, 10.595119533539616 ], [ -68.209584113999938, 10.537258205000057 ], [ -68.12954667899993, 10.48773834800005 ], [ -68.006459113999938, 10.488470770000049 ], [ -67.941232876999948, 10.466457424000055 ], [ -67.87328040299991, 10.476467190000051 ], [ -67.874223599139782, 10.379444281428448 ], [ -67.818748949304563, 10.322419337982069 ], [ -67.757641567604253, 10.343606676506909 ], [ -67.671962042913947, 10.324357205220849 ], [ -67.654107835608102, 10.299836738174918 ], [ -67.670050014996207, 10.244439601806164 ], [ -67.654495409235722, 10.103931383326653 ], [ -67.687361619942806, 10.063287868840064 ], [ -67.690177985425692, 10.024349676696204 ], [ -67.662169359328459, 10.032876288409966 ], [ -67.553235440363267, 9.993989773109547 ], [ -67.529025030780531, 9.906785793229744 ], [ -67.566697150153345, 9.916888536077067 ], [ -67.597263760214332, 9.860173651892524 ], [ -67.627339443860251, 9.871568305033236 ], [ -67.699066332345353, 9.842319443687359 ], [ -67.70441484157169, 9.882962958173948 ], [ -67.736583421187902, 9.892988185756167 ], [ -67.765367193641055, 9.926267808512534 ], [ -67.799189418756669, 9.930453599553971 ], [ -67.814072231848002, 9.917586168067203 ], [ -67.788828295289591, 9.827049057867725 ], [ -67.86724728103718, 9.819659329514423 ], [ -67.98788591240492, 9.835188096853187 ], [ -68.002846238962775, 9.853946640824802 ], [ -67.986568162790491, 9.878699652766727 ], [ -67.995327317601607, 9.88934499797324 ], [ -68.072092657849851, 9.856763007207007 ], [ -68.241668871421268, 9.987013455006945 ], [ -68.253502774133722, 10.021455796847533 ], [ -68.205211147976115, 10.062900295212444 ], [ -68.241668871421268, 10.128684394369316 ], [ -68.302724575378818, 10.069799098949261 ], [ -68.338923916405633, 10.003162339970004 ], [ -68.370498215919895, 9.990036526064785 ], [ -68.390548671983595, 10.006805527752874 ], [ -68.415146654294631, 10.073907376524176 ], [ -68.423182338693948, 10.172919419795392 ], [ -68.361609869899553, 10.260898546031058 ], [ -68.394114346300057, 10.358179430336406 ], [ -68.389540981631001, 10.493494168321206 ], [ -68.362669237095588, 10.548581244528805 ], [ -68.309597540693915, 10.540364692076878 ], [ -68.251739062407808, 10.595119533539616 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-D", "NAME_1": "Aragua" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -67.869214081264829, 10.461281869062987 ], [ -67.77757727799991, 10.495998440000051 ], [ -67.391753709999932, 10.543076890000066 ], [ -67.405130785257541, 10.515301621772437 ], [ -67.339605069418383, 10.395903224754022 ], [ -67.289453091287101, 10.428097641892634 ], [ -67.238655158009124, 10.430578111490661 ], [ -67.174317999675907, 10.354846300016732 ], [ -67.186461961650195, 10.313040066445922 ], [ -67.108740606993422, 10.264851793075763 ], [ -67.134165411604442, 10.154522610130357 ], [ -67.119101732259139, 10.111476142210165 ], [ -67.088276739779701, 10.082847398488639 ], [ -67.04161292159904, 10.053133450048676 ], [ -67.002933111873631, 10.074915065977507 ], [ -66.978645188824373, 10.071581936557095 ], [ -66.92371314224772, 10.009983629341036 ], [ -66.878522100614418, 9.999829210549592 ], [ -66.791421475320817, 10.012774156402202 ], [ -66.748168300926352, 9.99112173078322 ], [ -66.612750210154047, 9.966446235005719 ], [ -66.583759732125941, 9.798782050251418 ], [ -66.622749600213865, 9.754805406344417 ], [ -66.621070116292799, 9.720983181228803 ], [ -66.54306454079591, 9.622746283414244 ], [ -66.574199591637807, 9.527713323810815 ], [ -66.556577928328693, 9.470920925260486 ], [ -66.580555793015435, 9.401932887892428 ], [ -66.67969702839514, 9.393483792343147 ], [ -66.881648526258459, 9.459888007325674 ], [ -66.997326219329523, 9.452291570699401 ], [ -66.980505540798049, 9.5093165150451 ], [ -66.898985968727459, 9.536549993887093 ], [ -66.876377529599324, 9.56176809292316 ], [ -66.855861986441482, 9.60455617932422 ], [ -66.858730027868489, 9.672252306398832 ], [ -66.948543666756791, 9.691734320782246 ], [ -66.986215786129605, 9.749999498578006 ], [ -67.101609260159194, 9.799505519763898 ], [ -67.18134599462195, 9.919834092769179 ], [ -67.26384741862347, 9.91112661390207 ], [ -67.28557735860818, 9.93138377554078 ], [ -67.340612758871714, 9.92642283814348 ], [ -67.428126797113975, 9.987401027735245 ], [ -67.534115160286433, 9.951485907548602 ], [ -67.56584448943164, 10.001844591254894 ], [ -67.662169359328459, 10.032876288409966 ], [ -67.687309943099365, 10.021378282481749 ], [ -67.687361619942806, 10.063287868840064 ], [ -67.654495409235722, 10.103931383326653 ], [ -67.670050014996207, 10.244439601806164 ], [ -67.656278245944293, 10.306141261809785 ], [ -67.681186285718525, 10.329705715346449 ], [ -67.751466234279292, 10.343296617245073 ], [ -67.818748949304563, 10.322419337982069 ], [ -67.874223599139782, 10.379444281428448 ], [ -67.869214081264829, 10.461281869062987 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-X", "NAME_1": "Vargas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -67.391753709999932, 10.543076890000066 ], [ -67.170033331999946, 10.555975653000075 ], [ -67.01235917899993, 10.611232815000051 ], [ -66.541574673999946, 10.632717190000051 ], [ -66.333973761999914, 10.611232815000051 ], [ -66.313613633996283, 10.629491642220193 ], [ -66.307988450706432, 10.592816269954881 ], [ -66.311631639388622, 10.540287176811773 ], [ -66.3250675116563, 10.530675361278895 ], [ -66.354316372102858, 10.545325629474235 ], [ -66.439737515274089, 10.537109076122931 ], [ -66.577946133107559, 10.560466824084642 ], [ -66.602544115418596, 10.544162909490694 ], [ -66.949034593171916, 10.54927887651894 ], [ -67.006834682974215, 10.575117092279982 ], [ -67.015800544259719, 10.544317939121584 ], [ -67.053240118736483, 10.525456041463144 ], [ -67.053343472423308, 10.478766383961442 ], [ -67.220154994657264, 10.416677151229521 ], [ -67.238655158009124, 10.430578111490661 ], [ -67.289453091287101, 10.428097641892634 ], [ -67.339605069418383, 10.395903224754022 ], [ -67.405130785257541, 10.515301621772437 ], [ -67.391753709999932, 10.543076890000066 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-M", "NAME_1": "Miranda" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -66.313613633996283, 10.629491642220193 ], [ -66.29515540299991, 10.646714585000041 ], [ -66.251779751999948, 10.648586330000057 ], [ -66.104400193999936, 10.584418036000045 ], [ -66.046538865999935, 10.57648346600007 ], [ -66.076161261999914, 10.548895575000074 ], [ -66.121693488999938, 10.542954820000091 ], [ -66.122222459999932, 10.507025458000044 ], [ -65.952870245999918, 10.351629950000074 ], [ -65.882069464999915, 10.309556382000039 ], [ -65.92992102799991, 10.323187567000048 ], [ -65.944162563999953, 10.309556382000039 ], [ -65.923003709999932, 10.282212632000039 ], [ -65.896962042999917, 10.287990627000056 ], [ -65.802113410999937, 10.225653387000079 ], [ -65.717640753999945, 10.22016022300005 ], [ -65.847320115999935, 10.281398830000057 ], [ -65.868478969999899, 10.309556382000039 ], [ -65.580433722999942, 10.185451565000051 ], [ -65.425770636999914, 10.143418687000064 ], [ -65.43855831631322, 10.095327257247106 ], [ -65.633300951177944, 9.972208157180717 ], [ -65.664539353908026, 9.979417019279992 ], [ -65.745412970831921, 9.939238592786808 ], [ -65.86178829589312, 9.956834418573521 ], [ -65.971032274120148, 9.92890330684213 ], [ -66.0618277658387, 9.956446844945901 ], [ -66.111695523129868, 9.94776520450057 ], [ -66.132676154281057, 9.966601263737346 ], [ -66.190476244083413, 9.948695380487379 ], [ -66.392479417890797, 10.019440416142288 ], [ -66.450124478062207, 9.981975002344484 ], [ -66.527819994297261, 9.96838410134518 ], [ -66.665925259343226, 9.973215847533311 ], [ -66.791421475320817, 10.012774156402202 ], [ -66.878522100614418, 9.999829210549592 ], [ -66.929888474673362, 10.01308421476466 ], [ -66.978645188824373, 10.071581936557095 ], [ -67.002933111873631, 10.074915065977507 ], [ -67.04161292159904, 10.053133450048676 ], [ -67.119101732259139, 10.111476142210165 ], [ -67.134113735660378, 10.162119044957933 ], [ -67.108740606993422, 10.264851793075763 ], [ -67.186461961650195, 10.313040066445922 ], [ -67.174317999675907, 10.354846300016732 ], [ -67.220154994657264, 10.416677151229521 ], [ -67.153182338893828, 10.440732530282048 ], [ -67.051483119550312, 10.394507960773751 ], [ -66.943686083046259, 10.421431383051868 ], [ -66.897435676015618, 10.416212063236117 ], [ -66.881028407734846, 10.481401882291038 ], [ -66.854285855307978, 10.511503404358621 ], [ -66.873767869691449, 10.547030950917645 ], [ -66.863200038850721, 10.552844549936026 ], [ -66.602544115418596, 10.544162909490694 ], [ -66.577946133107559, 10.560466824084642 ], [ -66.439737515274089, 10.537109076122931 ], [ -66.354316372102858, 10.545325629474235 ], [ -66.3250675116563, 10.530675361278895 ], [ -66.311631639388622, 10.540287176811773 ], [ -66.313613633996283, 10.629491642220193 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-B", "NAME_1": "Anzoátegui" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -65.425770636999914, 10.143418687000064 ], [ -65.169545050999943, 10.097316799000055 ], [ -65.080189581999946, 10.062567450000074 ], [ -65.175689256999931, 10.083644924000055 ], [ -65.148915167999917, 10.058417059000078 ], [ -65.073353644999941, 10.048895575000074 ], [ -64.963490363999938, 10.097316799000055 ], [ -64.776600714999915, 10.090399481000077 ], [ -64.728627081999946, 10.136053778000075 ], [ -64.71703040299991, 10.227606512000079 ], [ -64.67609615799995, 10.213324286000045 ], [ -64.696603969999899, 10.199693101000037 ], [ -64.667632615999935, 10.187323309000078 ], [ -64.657622850999928, 10.196682033000059 ], [ -64.66860917899993, 10.207098700000074 ], [ -64.631418423999946, 10.248114325000074 ], [ -64.572417772999927, 10.261704820000091 ], [ -64.579904751999948, 10.248114325000074 ], [ -64.536081508999928, 10.252305406000062 ], [ -64.514738735903904, 10.223510647498358 ], [ -64.445750697636583, 10.193228258277486 ], [ -64.43582882284187, 10.146228543312588 ], [ -64.347307095146334, 10.094629625256971 ], [ -64.305707567150478, 10.101373399362899 ], [ -64.246951462939649, 10.070961818932801 ], [ -64.153830532153336, 10.079281724172233 ], [ -64.045310025237484, 10.128296820741696 ], [ -63.979164190874712, 10.115119329993092 ], [ -63.948830125709719, 10.082614854491908 ], [ -64.055748663969666, 10.053805242717772 ], [ -64.061665614876233, 9.968642482864254 ], [ -64.034173753615846, 9.935647080948002 ], [ -63.988388433679233, 9.935259508219701 ], [ -63.990067919398939, 9.916190904086932 ], [ -63.922552660376994, 9.869785468324665 ], [ -63.945574509755829, 9.840846666240623 ], [ -63.964462245835989, 9.762169298074639 ], [ -63.942990689168937, 9.702043769204579 ], [ -63.846639980850398, 9.550605983779121 ], [ -63.96908728734843, 9.4110279403871 ], [ -63.973221402445745, 9.323875637350795 ], [ -63.920356410719762, 9.26514537246095 ], [ -63.906300421727053, 9.205484931584294 ], [ -63.771890021307456, 9.236284084742692 ], [ -63.633629726630545, 9.167476915427301 ], [ -63.597585415234732, 9.117970893342033 ], [ -63.418061490245577, 9.008261827121601 ], [ -63.371345995221475, 8.918654892908989 ], [ -63.338453946092727, 8.805380154170791 ], [ -63.300936856350859, 8.777914130432748 ], [ -62.949278733826475, 8.793907985764918 ], [ -62.963257209352719, 8.759362291136824 ], [ -63.024261237366204, 8.76005992312696 ], [ -63.055396288208101, 8.709106960218037 ], [ -63.040720180691778, 8.595909735845623 ], [ -62.98832027875784, 8.552604885507037 ], [ -62.742753872193418, 8.473384914981807 ], [ -62.746939663234855, 8.432353826867597 ], [ -62.685832282433864, 8.385715847108656 ], [ -62.770607468659762, 8.375251369954753 ], [ -62.84553829625537, 8.293938503459174 ], [ -62.906929897896475, 8.266885890871151 ], [ -62.961706915741559, 8.284430039814481 ], [ -62.976899787195407, 8.309518948540642 ], [ -63.174639654696307, 8.313446357163627 ], [ -63.249570482291915, 8.28554108295458 ], [ -63.33080583442171, 8.213891709734582 ], [ -63.400026414887122, 8.221927395033219 ], [ -63.473561977603197, 8.150200507447437 ], [ -63.66768449574289, 8.159760647036194 ], [ -63.760727912163418, 8.12118419009829 ], [ -63.811990933434799, 8.130976874583098 ], [ -63.839896205845207, 8.110409654581872 ], [ -63.885371467419304, 8.018193061360705 ], [ -63.981127895635893, 7.967446804026793 ], [ -64.065903082761054, 7.98127024992209 ], [ -64.125563523637709, 7.965870672893232 ], [ -64.231629401175894, 8.071445624016349 ], [ -64.283254156753912, 8.081419176553766 ], [ -64.312942267671531, 8.06545115784462 ], [ -64.35239722375286, 8.008968818556127 ], [ -64.450065680786508, 7.990623683935837 ], [ -64.506237961712543, 7.99917613407132 ], [ -64.537114631035365, 7.98393158577403 ], [ -64.552514208064224, 7.925252996828306 ], [ -64.546158005787333, 7.896650092427819 ], [ -64.481562465935042, 7.843500880761042 ], [ -64.478151822148845, 7.814691269886168 ], [ -64.495463426196125, 7.790790920464588 ], [ -64.550963915352384, 7.765288601487782 ], [ -64.63705685119271, 7.771748154753539 ], [ -64.838465745797521, 7.660204575880471 ], [ -64.873063117269055, 7.666069850842916 ], [ -64.99607886364862, 7.770688788456823 ], [ -65.103695033898703, 7.834379990743969 ], [ -65.278077155236531, 7.874274197296359 ], [ -65.35665116971569, 7.869416611787187 ], [ -65.389207322959578, 7.920602117793464 ], [ -65.484498664082082, 7.930989081480902 ], [ -65.496074185275404, 7.979642441945145 ], [ -65.480467901772215, 8.023929145113925 ], [ -65.395098436343744, 8.112993476068027 ], [ -65.365927090262971, 8.184927070128197 ], [ -65.206634487591543, 8.369360256570587 ], [ -65.150100470560233, 8.556635646917584 ], [ -65.170771044248283, 8.646630153858496 ], [ -65.145501268368832, 8.731121121042861 ], [ -65.079949714108011, 8.756881822438118 ], [ -65.008842943247203, 8.738820909557319 ], [ -64.864071417561888, 8.74099131899419 ], [ -64.845958827837649, 8.773108221767018 ], [ -64.846268887099427, 8.829590561954831 ], [ -64.789941575643184, 8.878088893687504 ], [ -64.809604458079264, 8.914934189860958 ], [ -64.885749680703213, 8.982423611360559 ], [ -64.937348598758831, 9.003765976818386 ], [ -64.945151740060737, 9.06280630097001 ], [ -64.977604539617801, 9.111537176699358 ], [ -65.073154263158699, 9.173833115905552 ], [ -65.164879929964798, 9.178639024571339 ], [ -65.258285081591225, 9.277185980748413 ], [ -65.284588386244991, 9.376559760124792 ], [ -65.206737840379049, 9.434308173083707 ], [ -65.218210007885546, 9.50683604634645 ], [ -65.369570278945218, 9.554791774820558 ], [ -65.430600145380367, 9.650522366414066 ], [ -65.488839483855088, 9.569209499918486 ], [ -65.700376959728885, 9.685817368976359 ], [ -65.664952765957366, 9.773977363264692 ], [ -65.702624885330181, 9.846272690732064 ], [ -65.696604579837469, 9.953423773888062 ], [ -65.664539353908026, 9.979417019279992 ], [ -65.638287726097644, 9.970735377935341 ], [ -65.562194180317135, 10.006262926293005 ], [ -65.448945279101338, 10.079643460277453 ], [ -65.425770636999914, 10.143418687000064 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-R", "NAME_1": "Sucre" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -64.536081508999928, 10.252305406000062 ], [ -64.49054928299995, 10.240668036000045 ], [ -64.376698370999918, 10.300767320000091 ], [ -64.382232225999928, 10.316961981000077 ], [ -64.432769334999932, 10.305975653000075 ], [ -64.470041469999899, 10.323187567000048 ], [ -64.380604620999918, 10.343695380000042 ], [ -64.380604620999918, 10.370998440000051 ], [ -64.402414516999954, 10.370998440000051 ], [ -64.381255662999934, 10.386216539000088 ], [ -64.357411261999914, 10.338690497000073 ], [ -64.339182094999899, 10.390692450000074 ], [ -64.210560675999943, 10.439276434000078 ], [ -64.188547329999949, 10.477606512000079 ], [ -64.127674933999913, 10.477606512000079 ], [ -64.051828579999949, 10.447943427000041 ], [ -63.943023240999935, 10.46039459800005 ], [ -63.863636847999942, 10.446112372000073 ], [ -63.655018683999913, 10.494533596000053 ], [ -63.729725714999915, 10.49750397300005 ], [ -63.823150193999936, 10.549383856000077 ], [ -63.923736131999931, 10.560288804000038 ], [ -63.966664191999939, 10.581366278000075 ], [ -64.045480923999946, 10.570257880000042 ], [ -64.031849738999938, 10.590073960000041 ], [ -64.08617102799991, 10.56712474200009 ], [ -64.169056769999941, 10.570257880000042 ], [ -64.233876105999911, 10.515041408000059 ], [ -64.249134894999941, 10.520453192000048 ], [ -64.297678188999953, 10.61985911700009 ], [ -64.270741339999915, 10.672674872000073 ], [ -64.240793423999946, 10.646063544000071 ], [ -64.14476477799991, 10.617417710000041 ], [ -64.048898891999954, 10.652167059000078 ], [ -64.031849738999938, 10.637884833000044 ], [ -63.915109829999949, 10.631048895000049 ], [ -63.846831834999932, 10.652167059000078 ], [ -63.812123175999943, 10.71360911700009 ], [ -63.756947394999941, 10.665594794000071 ], [ -63.553334113999938, 10.629136460000041 ], [ -63.466175910999937, 10.667629299000055 ], [ -63.404896613999938, 10.665838934000078 ], [ -63.387562628999945, 10.699367580000057 ], [ -63.339751756999931, 10.672674872000073 ], [ -63.331532355999911, 10.685370184000078 ], [ -63.251291469999899, 10.680568752000056 ], [ -63.161610480999911, 10.73468659100007 ], [ -63.137440558999913, 10.706773179000038 ], [ -63.014230923999946, 10.721096096000053 ], [ -62.928212042999917, 10.699367580000057 ], [ -62.705677863999938, 10.76203034100007 ], [ -62.638050910999937, 10.742621161000045 ], [ -62.154204881999931, 10.686346747000073 ], [ -62.102406378999945, 10.71360911700009 ], [ -62.036244269999941, 10.714016018000052 ], [ -61.982329881999931, 10.73468659100007 ], [ -61.935170050999943, 10.721096096000053 ], [ -61.845773891999954, 10.74095286700009 ], [ -61.876861131999931, 10.722723700000074 ], [ -61.886708136999914, 10.680121161000045 ], [ -61.897694464999915, 10.690375067000048 ], [ -61.962473110999952, 10.652167059000078 ], [ -62.088937954999949, 10.631293036000045 ], [ -62.17446855399993, 10.642279364000046 ], [ -62.252674933999913, 10.632391669000071 ], [ -62.334950324999909, 10.530218817000048 ], [ -62.66234290299991, 10.56704336100006 ], [ -62.923329230999911, 10.530829169000071 ], [ -63.010812954999949, 10.453558661000045 ], [ -62.894113735999952, 10.529282945000091 ], [ -62.857004360999952, 10.53156159100007 ], [ -62.841175910999937, 10.511786200000074 ], [ -62.831125454999949, 10.406805731000077 ], [ -62.866118943999936, 10.391506252000056 ], [ -62.897816535999937, 10.412014065000051 ], [ -62.995187954999949, 10.407863674000055 ], [ -63.003977016999954, 10.384670315000051 ], [ -62.975982225999928, 10.398342190000051 ], [ -62.956166144999941, 10.357367255000042 ], [ -62.997141079999949, 10.323187567000048 ], [ -62.978586391999954, 10.310980536000045 ], [ -63.003977016999954, 10.275376695000091 ], [ -62.931630011999914, 10.285630601000037 ], [ -62.957102016999954, 10.383775132000039 ], [ -62.942494269999941, 10.405178127000056 ], [ -62.879790818999936, 10.370998440000051 ], [ -62.801625128999945, 10.405178127000056 ], [ -62.764475063999953, 10.395331122000073 ], [ -62.674956834999932, 10.293361721000053 ], [ -62.674956834999932, 10.213324286000045 ], [ -62.626576300999943, 10.130804755000042 ], [ -62.656605597999942, 10.082180080000057 ], [ -62.712554490999935, 10.069322007000039 ], [ -62.777455206999946, 10.086493231000077 ], [ -62.822743292999917, 10.042059637000079 ], [ -62.851389126999948, 10.08038971600007 ], [ -62.894113735999952, 10.069322007000039 ], [ -62.901519334999932, 10.103461005000042 ], [ -62.935129360999952, 10.083644924000055 ], [ -62.963002081999946, 10.110296942000048 ], [ -62.989328579999949, 10.096258856000077 ], [ -63.030488246635286, 10.105869248766794 ], [ -63.063535326294243, 10.187259630527535 ], [ -63.102421840695399, 10.184004015472908 ], [ -63.112757128438716, 10.218678901310227 ], [ -63.191977098064626, 10.167648424035519 ], [ -63.220605841786153, 10.193848375002517 ], [ -63.379820930091853, 10.244672145802895 ], [ -63.402765266004224, 10.257952989338946 ], [ -63.40770036497986, 10.283713690734203 ], [ -63.463381721289409, 10.314667874422867 ], [ -63.532343920235746, 10.281698310028958 ], [ -63.555029872830346, 10.229634303979935 ], [ -63.730238817367535, 10.205346380930735 ], [ -63.800777147447377, 10.127754218382449 ], [ -63.948830125709719, 10.082614854491908 ], [ -63.979164190874712, 10.115119329993092 ], [ -64.037351854304632, 10.12914948236272 ], [ -64.153830532153336, 10.079281724172233 ], [ -64.246951462939649, 10.070961818932801 ], [ -64.305707567150478, 10.101373399362899 ], [ -64.347307095146334, 10.094629625256971 ], [ -64.43582882284187, 10.146228543312588 ], [ -64.445750697636583, 10.193228258277486 ], [ -64.514738735903904, 10.223510647498358 ], [ -64.536081508999928, 10.252305406000062 ] ] ], [ [ [ -62.665150519999941, 10.366359768000052 ], [ -62.649403449999909, 10.344916083000044 ], [ -62.659820115999935, 10.31000397300005 ], [ -62.710316535999937, 10.372015692000048 ], [ -62.787587042999917, 10.430121161000045 ], [ -62.781117316999939, 10.49290599200009 ], [ -62.665150519999941, 10.366359768000052 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-N", "NAME_1": "Monagas" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -63.013091600999928, 10.097398179000038 ], [ -62.982167120999918, 10.06907786700009 ], [ -62.952992316999939, 10.088080145000049 ], [ -62.936024542999917, 10.008246161000045 ], [ -62.920765753999945, 10.007961330000057 ], [ -62.931711391999954, 10.065008856000077 ], [ -62.914621548999946, 10.083644924000055 ], [ -62.911203579999949, 10.052313544000071 ], [ -62.895578579999949, 10.044012762000079 ], [ -62.853138800999943, 10.055650132000039 ], [ -62.797922329999949, 10.028998114000046 ], [ -62.80109615799995, 9.995998440000051 ], [ -62.777414516999954, 10.018459377000056 ], [ -62.784982876999948, 10.06976959800005 ], [ -62.76431230399993, 10.076157945000091 ], [ -62.716704881999931, 10.048407294000071 ], [ -62.663563605999911, 10.06085846600007 ], [ -62.618519660999937, 10.091620184000078 ], [ -62.605946417999917, 10.133246161000045 ], [ -62.626576300999943, 10.196275132000039 ], [ -62.619536912999934, 10.224432684000078 ], [ -62.579945441999939, 10.224432684000078 ], [ -62.517567511999914, 10.184149481000077 ], [ -62.429432745999918, 9.980861721000053 ], [ -62.44163977799991, 9.932806708000044 ], [ -62.396962042999917, 9.911444403000075 ], [ -62.318714972999942, 9.76829661700009 ], [ -62.32363216838985, 9.702276313201253 ], [ -62.446131150831945, 9.525413723164775 ], [ -62.430860765012312, 9.496836656286632 ], [ -62.396056687965768, 9.481385403313709 ], [ -62.374352587302042, 9.399607448824668 ], [ -62.320531582066849, 9.357336127260453 ], [ -62.304692756365625, 9.196648261508074 ], [ -62.32133256684449, 9.140553494048504 ], [ -62.266297166580955, 9.131871852703853 ], [ -62.209737311127981, 9.072366441458087 ], [ -62.145270961585595, 9.097584540494154 ], [ -62.128734503894236, 9.056450100491759 ], [ -62.088633591766836, 9.071798001576497 ], [ -62.055173101857179, 9.063710639434476 ], [ -62.084189419206325, 8.94482900635353 ], [ -62.055560676384118, 8.90511566785375 ], [ -62.008638474885686, 8.895452175477487 ], [ -62.00755327016725, 8.863800360698065 ], [ -62.06424231593013, 8.799204819946453 ], [ -62.075197720398478, 8.734402574519208 ], [ -62.181832037818253, 8.680400702130669 ], [ -62.239528774833104, 8.598002630916653 ], [ -62.32324459476223, 8.589372667314706 ], [ -62.366368577947526, 8.54570608177022 ], [ -62.435899216775397, 8.513821722994123 ], [ -62.515300056252613, 8.519428616437494 ], [ -62.685832282433864, 8.385715847108656 ], [ -62.746939663234855, 8.432353826867597 ], [ -62.742753872193418, 8.473384914981807 ], [ -62.98832027875784, 8.552604885507037 ], [ -63.040720180691778, 8.595909735845623 ], [ -63.055396288208101, 8.709106960218037 ], [ -63.024261237366204, 8.76005992312696 ], [ -62.963257209352719, 8.759362291136824 ], [ -62.949278733826475, 8.793907985764918 ], [ -63.300936856350859, 8.777914130432748 ], [ -63.338453946092727, 8.805380154170791 ], [ -63.371345995221475, 8.918654892908989 ], [ -63.418061490245577, 9.008261827121601 ], [ -63.597585415234732, 9.117970893342033 ], [ -63.633629726630545, 9.167476915427301 ], [ -63.760133632960788, 9.231788235338797 ], [ -63.839663661848533, 9.230082912996011 ], [ -63.902579718679078, 9.20292694672122 ], [ -63.920356410719762, 9.26514537246095 ], [ -63.973221402445745, 9.323875637350795 ], [ -63.966632656172123, 9.416686509774593 ], [ -63.846639980850398, 9.550605983779121 ], [ -63.942990689168937, 9.702043769204579 ], [ -63.964462245835989, 9.762169298074639 ], [ -63.945574509755829, 9.840846666240623 ], [ -63.922552660376994, 9.869785468324665 ], [ -63.990067919398939, 9.916190904086932 ], [ -63.988388433679233, 9.935259508219701 ], [ -64.034173753615846, 9.935647080948002 ], [ -64.054534268042005, 9.95218353953868 ], [ -64.055748663969666, 10.053805242717772 ], [ -63.983117437919418, 10.063597927202579 ], [ -63.800777147447377, 10.127754218382449 ], [ -63.730238817367535, 10.205346380930735 ], [ -63.555029872830346, 10.229634303979935 ], [ -63.532343920235746, 10.281698310028958 ], [ -63.463381721289409, 10.314667874422867 ], [ -63.40770036497986, 10.283713690734203 ], [ -63.402765266004224, 10.257952989338946 ], [ -63.379820930091853, 10.244672145802895 ], [ -63.220605841786153, 10.193848375002517 ], [ -63.191977098064626, 10.167648424035519 ], [ -63.112757128438716, 10.218678901310227 ], [ -63.102421840695399, 10.184004015472908 ], [ -63.063535326294243, 10.187259630527535 ], [ -63.043769090171338, 10.119925237759503 ], [ -63.013091600999928, 10.097398179000038 ] ] ], [ [ [ -62.331125454999949, 9.92055898600006 ], [ -62.316395636999914, 9.885646877000056 ], [ -62.325754360999952, 9.844183661000045 ], [ -62.349354620999918, 9.872300523000092 ], [ -62.348784959999932, 9.913723049000055 ], [ -62.331125454999949, 9.92055898600006 ] ] ], [ [ [ -62.403309699999909, 10.006293036000045 ], [ -62.391102667999917, 9.993353583000044 ], [ -62.408924933999913, 9.972560940000051 ], [ -62.43618730399993, 10.046576239000046 ], [ -62.403309699999909, 10.006293036000045 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-O", "NAME_1": "Nueva Esparta" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -63.976551886999914, 10.80923086100006 ], [ -63.903635219999899, 10.777289130000042 ], [ -63.894642706999946, 10.754584052000041 ], [ -63.909169074999909, 10.735541083000044 ], [ -63.935536261999914, 10.733710028000075 ], [ -63.956776495999918, 10.744126695000091 ], [ -63.956125454999949, 10.76203034100007 ], [ -64.004505988999938, 10.77570221600007 ], [ -63.998890753999945, 10.799261786000045 ], [ -63.976551886999914, 10.80923086100006 ] ] ], [ [ [ -63.846831834999932, 11.13540273600006 ], [ -63.787668423999946, 10.973781643000052 ], [ -63.819569464999915, 10.980536200000074 ], [ -63.819569464999915, 10.953802802000041 ], [ -63.842925584999932, 10.967759507000039 ], [ -63.898060675999943, 10.884955145000049 ], [ -63.976551886999914, 10.891099351000037 ], [ -64.059722459999932, 10.857611395000049 ], [ -64.05687415299991, 10.887111721000053 ], [ -64.096099412999934, 10.89093659100007 ], [ -64.116363084999932, 10.928615627000056 ], [ -64.175852016999954, 10.967474677000041 ], [ -64.224354620999918, 10.939357815000051 ], [ -64.408558722999942, 10.967474677000041 ], [ -64.370594855999911, 11.062486070000091 ], [ -64.220082160999937, 11.091538804000038 ], [ -64.188832160999937, 11.073635158000059 ], [ -64.181630011999914, 11.034084377000056 ], [ -64.110707160999937, 11.000189520000049 ], [ -64.04906165299991, 10.990708726000037 ], [ -64.017567511999914, 11.015285549000055 ], [ -64.017567511999914, 11.056219794000071 ], [ -63.976551886999914, 11.118312893000052 ], [ -63.935617641999954, 11.125148830000057 ], [ -63.880970831999946, 11.17914459800005 ], [ -63.846831834999932, 11.13540273600006 ] ] ], [ [ [ -64.16860917899993, 10.827948309000078 ], [ -64.155873175999943, 10.81195709800005 ], [ -64.174794074999909, 10.799221096000053 ], [ -64.22093665299991, 10.806463934000078 ], [ -64.20343990799995, 10.827297268000052 ], [ -64.16860917899993, 10.827948309000078 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-W", "NAME_1": "Dependencias Federales" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -65.227609829999949, 10.953802802000041 ], [ -65.208241339999915, 10.949896552000041 ], [ -65.204945441999939, 10.904364325000074 ], [ -65.244618292999917, 10.884955145000049 ], [ -65.237863735999952, 10.898586330000057 ], [ -65.31663977799991, 10.891099351000037 ], [ -65.388050910999937, 10.905462958000044 ], [ -65.411773240999935, 10.924750067000048 ], [ -65.376698370999918, 10.966050523000092 ], [ -65.329904751999948, 10.977606512000079 ], [ -65.227609829999949, 10.953802802000041 ] ] ], [ [ [ -66.608265753999945, 11.783107815000051 ], [ -66.587798631999931, 11.783107815000051 ], [ -66.641835089999915, 11.761460679000038 ], [ -66.704497850999928, 11.783107815000051 ], [ -66.650868292999917, 11.780178127000056 ], [ -66.615101691999939, 11.824042059000078 ], [ -66.601389126999948, 11.806708075000074 ], [ -66.608265753999945, 11.783107815000051 ] ] ], [ [ [ -66.132191535999937, 11.824042059000078 ], [ -66.102935350999928, 11.819281317000048 ], [ -66.114003058999913, 11.77993398600006 ], [ -66.143137173999946, 11.781805731000077 ], [ -66.194325324999909, 11.817694403000075 ], [ -66.132191535999937, 11.824042059000078 ] ] ], [ [ [ -64.607167120999918, 11.899115302000041 ], [ -64.556792772999927, 11.857326565000051 ], [ -64.562855597999942, 11.816595770000049 ], [ -64.648793097999942, 11.830267645000049 ], [ -64.648793097999942, 11.851304429000038 ], [ -64.607167120999918, 11.899115302000041 ] ] ], [ [ [ -66.749989386999914, 11.777573960000041 ], [ -66.728016730999911, 11.782049872000073 ], [ -66.827788865999935, 11.746242580000057 ], [ -66.854603644999941, 11.751369533000059 ], [ -66.749989386999914, 11.777573960000041 ] ] ], [ [ [ -66.733387824999909, 11.869940497000073 ], [ -66.711781378999945, 11.86790599200009 ], [ -66.817860480999911, 11.871079820000091 ], [ -66.814808722999942, 11.873236395000049 ], [ -66.733387824999909, 11.869940497000073 ] ] ], [ [ [ -67.658029751999948, 11.984930731000077 ], [ -67.648996548999946, 11.983954169000071 ], [ -67.637603318999936, 11.980047919000071 ], [ -67.665882941999939, 11.982001044000071 ], [ -67.674875454999949, 11.989650783000059 ], [ -67.658029751999948, 11.984930731000077 ] ] ], [ [ [ -67.680409308999913, 12.025051174000055 ], [ -67.681548631999931, 12.025783596000053 ], [ -67.679066535999937, 12.028143622000073 ], [ -67.680409308999913, 12.025051174000055 ] ] ], [ [ [ -67.677601691999939, 12.027818101000037 ], [ -67.677235480999911, 12.03001536700009 ], [ -67.676665818999936, 12.026922919000071 ], [ -67.677601691999939, 12.027818101000037 ] ] ], [ [ [ -67.677235480999911, 12.05023834800005 ], [ -67.674672003999945, 12.048407294000071 ], [ -67.67609615799995, 12.044419664000088 ], [ -67.676991339999915, 12.04633209800005 ], [ -67.677235480999911, 12.05023834800005 ] ] ], [ [ [ -67.681385870999918, 12.063706773000092 ], [ -67.681019660999937, 12.061835028000075 ], [ -67.684437628999945, 12.063462632000039 ], [ -67.681385870999918, 12.063706773000092 ] ] ], [ [ [ -67.687326626999948, 12.065578518000052 ], [ -67.688832160999937, 12.06899648600006 ], [ -67.687082485999952, 12.067531643000052 ], [ -67.687326626999948, 12.065578518000052 ] ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-X01~", "NAME_1": null }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -63.639881964999915, 15.69603099200009 ], [ -63.643625454999949, 15.700588283000059 ], [ -63.634592251999948, 15.700588283000059 ], [ -63.635487433999913, 15.694037177000041 ], [ -63.639881964999915, 15.69603099200009 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-J", "NAME_1": "Guárico" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -65.696604579837469, 9.953423773888062 ], [ -65.702624885330181, 9.846272690732064 ], [ -65.664952765957366, 9.773977363264692 ], [ -65.700376959728885, 9.685817368976359 ], [ -65.488839483855088, 9.569209499918486 ], [ -65.430600145380367, 9.650522366414066 ], [ -65.369570278945218, 9.554791774820558 ], [ -65.218210007885546, 9.50683604634645 ], [ -65.206737840379049, 9.434308173083707 ], [ -65.284588386244991, 9.376559760124792 ], [ -65.258285081591225, 9.277185980748413 ], [ -65.164879929964798, 9.178639024571339 ], [ -65.073154263158699, 9.173833115905552 ], [ -64.977604539617801, 9.111537176699358 ], [ -64.945151740060737, 9.06280630097001 ], [ -64.937348598758831, 9.003765976818386 ], [ -64.885749680703213, 8.982423611360559 ], [ -64.809604458079264, 8.914934189860958 ], [ -64.789941575643184, 8.878088893687504 ], [ -64.846268887099427, 8.829590561954831 ], [ -64.845958827837649, 8.773108221767018 ], [ -64.864071417561888, 8.74099131899419 ], [ -65.008842943247203, 8.738820909557319 ], [ -65.079949714108011, 8.756881822438118 ], [ -65.149377001047753, 8.724687405299505 ], [ -65.170771044248283, 8.646630153858496 ], [ -65.150100470560233, 8.556635646917584 ], [ -65.206634487591543, 8.369360256570587 ], [ -65.365927090262971, 8.184927070128197 ], [ -65.395098436343744, 8.112993476068027 ], [ -65.494343023611634, 7.991657212710209 ], [ -65.484498664082082, 7.930989081480902 ], [ -65.389207322959578, 7.920602117793464 ], [ -65.35665116971569, 7.869416611787187 ], [ -65.446774867865827, 7.861458441753655 ], [ -65.542867193765971, 7.89995738432583 ], [ -65.648157924948293, 7.89990570748239 ], [ -65.768486497953518, 7.841072088905776 ], [ -65.833986376270218, 7.75714956340164 ], [ -65.93945797370651, 7.679169827225735 ], [ -65.983796352819411, 7.669506333950153 ], [ -66.130893316673223, 7.683820706260576 ], [ -66.236287400642993, 7.6361233593056 ], [ -66.330519374569462, 7.648422349112082 ], [ -66.324602423662895, 7.687593085252672 ], [ -66.352611049760128, 7.735781357723454 ], [ -66.394804856958558, 7.727874864533362 ], [ -66.456532355383899, 7.746219998254276 ], [ -66.527509935035482, 7.816344916284834 ], [ -66.54554501039388, 7.811073920525018 ], [ -66.546087612753126, 7.795209255502755 ], [ -66.764782273882815, 7.755108344274674 ], [ -66.950791592358087, 7.788387966131722 ], [ -67.015697190572894, 7.769526069372603 ], [ -67.056754116209504, 7.797457180204674 ], [ -67.139694789782709, 7.772239081168664 ], [ -67.226485357613171, 7.798516547400709 ], [ -67.304542609054181, 7.842932440879451 ], [ -67.337899746176333, 7.889079495122587 ], [ -67.395829027187858, 7.911274522201438 ], [ -67.468124355554551, 7.903833116105432 ], [ -67.538120083275203, 7.917010605954715 ], [ -67.544217902234379, 7.958765164480724 ], [ -67.516726040074673, 7.981296088343811 ], [ -67.533624233871308, 7.993207506321369 ], [ -67.552744513948142, 7.984680893708287 ], [ -67.595093349878198, 8.047312729698717 ], [ -67.574577805821093, 8.048449612159857 ], [ -67.574577805821093, 8.082581894738667 ], [ -67.622378505563574, 8.096250311902338 ], [ -67.677413906726429, 8.209525051539856 ], [ -67.7080580311532, 8.236939399333778 ], [ -67.767873500761425, 8.239083971248249 ], [ -67.780017462735714, 8.294868679445983 ], [ -67.793685879000122, 8.274378973810599 ], [ -67.821410285156503, 8.291535549126252 ], [ -67.820996874006539, 8.315358385081367 ], [ -67.862570562681299, 8.329000962924113 ], [ -67.855749274209643, 8.376801663565914 ], [ -67.88306026921606, 8.369980374194881 ], [ -67.910371263323157, 8.404112656773691 ], [ -67.944581061167014, 8.404345200770365 ], [ -67.979643520631953, 8.448941962301717 ], [ -67.974656744812933, 8.475632838784463 ], [ -68.036487596025722, 8.538497218771624 ], [ -67.996024949591742, 8.555472926934044 ], [ -68.013336555437661, 8.599862982890329 ], [ -67.998634610398938, 8.654640000735412 ], [ -68.012716436914047, 8.749595445073737 ], [ -67.966982794720195, 8.907802843026786 ], [ -67.903265754011329, 8.9673857695376 ], [ -67.854999966275386, 9.072573147033097 ], [ -67.871045497551677, 9.182592270716725 ], [ -67.942178106834149, 9.310000515511376 ], [ -67.919337123709283, 9.378600979251758 ], [ -67.916727463801408, 9.449733588534286 ], [ -67.931636115314461, 9.504200548016854 ], [ -67.964063075550484, 9.541820990546285 ], [ -67.93140357131773, 9.568589382294135 ], [ -67.930964321746046, 9.596365465293957 ], [ -67.899157477335677, 9.630110175144466 ], [ -67.84833370563598, 9.627164618452355 ], [ -67.756297979568103, 9.682716783552678 ], [ -67.807147589689521, 9.87164582029834 ], [ -67.80748348737302, 9.92541514689151 ], [ -67.765367193641055, 9.926267808512534 ], [ -67.736583421187902, 9.892988185756167 ], [ -67.70441484157169, 9.882962958173948 ], [ -67.699066332345353, 9.842319443687359 ], [ -67.627339443860251, 9.871568305033236 ], [ -67.597263760214332, 9.860173651892524 ], [ -67.566697150153345, 9.916888536077067 ], [ -67.529025030780531, 9.906785793229744 ], [ -67.534115160286433, 9.951485907548602 ], [ -67.442828742152699, 9.985850735023405 ], [ -67.340612758871714, 9.92642283814348 ], [ -67.28557735860818, 9.93138377554078 ], [ -67.26384741862347, 9.91112661390207 ], [ -67.18134599462195, 9.919834092769179 ], [ -67.101609260159194, 9.799505519763898 ], [ -66.986215786129605, 9.749999498578006 ], [ -66.948543666756791, 9.691734320782246 ], [ -66.858730027868489, 9.672252306398832 ], [ -66.855861986441482, 9.60455617932422 ], [ -66.876377529599324, 9.56176809292316 ], [ -66.898985968727459, 9.536549993887093 ], [ -66.980505540798049, 9.5093165150451 ], [ -66.997326219329523, 9.452291570699401 ], [ -66.859453498280288, 9.456942449734242 ], [ -66.685820684876717, 9.394801541058257 ], [ -66.623188849785606, 9.391623440369472 ], [ -66.575491502830573, 9.40947764677594 ], [ -66.556577928328693, 9.470920925260486 ], [ -66.574199591637807, 9.527713323810815 ], [ -66.54306454079591, 9.622746283414244 ], [ -66.621070116292799, 9.720983181228803 ], [ -66.622749600213865, 9.754805406344417 ], [ -66.583759732125941, 9.798782050251418 ], [ -66.612750210154047, 9.966446235005719 ], [ -66.450124478062207, 9.981975002344484 ], [ -66.392479417890797, 10.019440416142288 ], [ -66.190476244083413, 9.948695380487379 ], [ -66.132676154281057, 9.966601263737346 ], [ -66.111695523129868, 9.94776520450057 ], [ -66.0618277658387, 9.956446844945901 ], [ -65.971032274120148, 9.92890330684213 ], [ -65.870547450704294, 9.956059272217601 ], [ -65.766031866777212, 9.936732286565757 ], [ -65.696604579837469, 9.953423773888062 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-H", "NAME_1": "Cojedes" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -67.788828295289591, 9.827049057867725 ], [ -67.756297979568103, 9.682716783552678 ], [ -67.84833370563598, 9.627164618452355 ], [ -67.899157477335677, 9.630110175144466 ], [ -67.930964321746046, 9.596365465293957 ], [ -67.93140357131773, 9.568589382294135 ], [ -67.964063075550484, 9.541820990546285 ], [ -67.931636115314461, 9.504200548016854 ], [ -67.916727463801408, 9.449733588534286 ], [ -67.919337123709283, 9.378600979251758 ], [ -67.942178106834149, 9.310000515511376 ], [ -67.871045497551677, 9.182592270716725 ], [ -67.853966436601752, 9.08515635857907 ], [ -67.903265754011329, 8.9673857695376 ], [ -67.963442958825453, 8.915089220391224 ], [ -67.992717657693731, 8.831140855565991 ], [ -68.013724128165961, 8.736107895962618 ], [ -67.998634610398938, 8.654640000735412 ], [ -68.013336555437661, 8.599862982890329 ], [ -67.997885300666098, 8.550744534432681 ], [ -68.024395310894874, 8.532812811861788 ], [ -68.063359340561135, 8.575420030210239 ], [ -68.16539445668883, 8.608932196063961 ], [ -68.237948168373237, 8.599397894896924 ], [ -68.386698777726394, 8.617846381405343 ], [ -68.423053148384099, 8.60373871556925 ], [ -68.502324794853394, 8.612575384746208 ], [ -68.631722581931626, 8.669212755464287 ], [ -68.682804735150398, 8.714610500873903 ], [ -68.703992071876598, 8.769077460356471 ], [ -68.750319994172401, 8.792176825000467 ], [ -68.684535895015529, 8.812976588998367 ], [ -68.663684455073508, 8.804605006915551 ], [ -68.582397426999648, 8.852793280285653 ], [ -68.636192592913801, 8.897467556182733 ], [ -68.652108933880186, 8.94544912397788 ], [ -68.605238410124514, 9.225173652442095 ], [ -68.642161220663809, 9.277676907163539 ], [ -68.821039191405532, 9.419657903989048 ], [ -68.872121344624361, 9.439527492899458 ], [ -68.992398240786144, 9.728347072959025 ], [ -68.977722134169142, 9.857279771144533 ], [ -68.858892177931637, 9.853171495368201 ], [ -68.804321865661564, 9.960865179984069 ], [ -68.66970475876758, 9.9687975124952 ], [ -68.623015103064517, 10.011378892421931 ], [ -68.582242398268079, 10.00502269104436 ], [ -68.579400194363473, 9.947842718866355 ], [ -68.52829220182366, 9.923012193457964 ], [ -68.540642870272222, 9.900197047855443 ], [ -68.503952602830338, 9.900507107117278 ], [ -68.338923916405633, 10.003162339970004 ], [ -68.302724575378818, 10.069799098949261 ], [ -68.241668871421268, 10.128684394369316 ], [ -68.205211147976115, 10.062900295212444 ], [ -68.253502774133722, 10.021455796847533 ], [ -68.241668871421268, 9.987013455006945 ], [ -68.081187710344523, 9.862499090960284 ], [ -68.06534888374398, 9.855367743226736 ], [ -67.995327317601607, 9.88934499797324 ], [ -67.986568162790491, 9.878699652766727 ], [ -68.002846238962775, 9.853946640824802 ], [ -67.977576463083267, 9.831932480899241 ], [ -67.879804654161433, 9.819116726255913 ], [ -67.788828295289591, 9.827049057867725 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-A", "NAME_1": "Distrito Capital" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -67.00536190462816, 10.575194607545086 ], [ -66.951489224348222, 10.549511420515614 ], [ -66.873767869691449, 10.547030950917645 ], [ -66.853639899261907, 10.514603989782302 ], [ -66.881028407734846, 10.481401882291038 ], [ -66.897435676015618, 10.416212063236117 ], [ -66.943686083046259, 10.421431383051868 ], [ -67.029727342043202, 10.393035183327015 ], [ -67.151115282244461, 10.430500597124819 ], [ -67.126930711982766, 10.458819281584567 ], [ -67.053343472423308, 10.478766383961442 ], [ -67.053240118736483, 10.525456041463144 ], [ -67.015800544259719, 10.544317939121584 ], [ -67.00536190462816, 10.575194607545086 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-E", "NAME_1": "Barinas" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.036487596025722, 8.538497218771624 ], [ -67.974656744812933, 8.475632838784463 ], [ -67.979643520631953, 8.448941962301717 ], [ -67.944581061167014, 8.404345200770365 ], [ -67.910371263323157, 8.404112656773691 ], [ -67.88306026921606, 8.369980374194881 ], [ -67.855749274209643, 8.376801663565914 ], [ -67.862570562681299, 8.329000962924113 ], [ -67.820996874006539, 8.315358385081367 ], [ -67.817586229321023, 8.288047390075008 ], [ -67.793685879000122, 8.274378973810599 ], [ -67.780017462735714, 8.294868679445983 ], [ -67.767873500761425, 8.239083971248249 ], [ -67.715163539565708, 8.240246690332469 ], [ -67.677413906726429, 8.209525051539856 ], [ -67.622378505563574, 8.096250311902338 ], [ -67.574577805821093, 8.082581894738667 ], [ -67.574577805821093, 8.048449612159857 ], [ -67.596876186586712, 8.054547431119033 ], [ -67.563570726307944, 7.995197047705574 ], [ -67.533624233871308, 7.993207506321369 ], [ -67.518999803198369, 7.971606757545828 ], [ -67.544217902234379, 7.958765164480724 ], [ -67.605299444613649, 7.99940867806805 ], [ -67.862570562681299, 8.034807034317168 ], [ -67.88481726840223, 8.026719672175091 ], [ -67.954425421595943, 8.054650783906538 ], [ -68.054367641753231, 8.048449612159857 ], [ -68.256577521135682, 7.956517238879485 ], [ -68.275594449324387, 7.970934963078093 ], [ -68.341740281888463, 7.965896511314952 ], [ -68.374709846282371, 7.991347154347693 ], [ -68.425895352288649, 7.97935822200435 ], [ -68.485142381115963, 7.938585517207855 ], [ -68.63386715384604, 7.969358831944533 ], [ -68.72983028763764, 7.915847886870495 ], [ -68.823467984160118, 7.902515367390265 ], [ -68.945062629037068, 7.931764227836823 ], [ -68.970280728073135, 7.99938283874701 ], [ -69.054306607264095, 7.980185045203655 ], [ -69.112649299425641, 8.006850084164057 ], [ -69.133449063423541, 8.041628322788881 ], [ -69.188691169262029, 8.070670478559748 ], [ -69.440949673088937, 8.071652330490622 ], [ -69.57703955832892, 7.951039537544602 ], [ -69.733696661771489, 7.844431056747851 ], [ -69.835137498696611, 7.807637437417782 ], [ -69.862991096062217, 7.811978258090107 ], [ -69.93549313000392, 7.757769680126614 ], [ -70.013886278229165, 7.754255683552913 ], [ -70.086595017745879, 7.710744126740053 ], [ -70.133517219244254, 7.629327908356288 ], [ -70.157185024669161, 7.615013536045865 ], [ -70.288882412393377, 7.603773912536042 ], [ -70.320895962378756, 7.516879991018754 ], [ -70.368334926915338, 7.450449936715188 ], [ -70.460241461774046, 7.423061428242306 ], [ -70.480033535419295, 7.376242581330075 ], [ -70.500523241054736, 7.383683987426082 ], [ -70.547833015281412, 7.333712877347409 ], [ -70.603540209113362, 7.328441880688217 ], [ -70.630851203220459, 7.294309597210145 ], [ -70.666895514616272, 7.287410793473327 ], [ -70.795337287285975, 7.314799302845529 ], [ -70.874169685082904, 7.287488307839112 ], [ -70.946775071812112, 7.307978014373873 ], [ -71.06136756016474, 7.378723049129405 ], [ -71.189163377687692, 7.404173692162146 ], [ -71.248849656986067, 7.454532375868439 ], [ -71.267685716222786, 7.445127265011251 ], [ -71.454418505109913, 7.463885809882186 ], [ -71.520926072879945, 7.438305976539596 ], [ -71.563119880078375, 7.452594509528979 ], [ -71.607199876772881, 7.438305976539596 ], [ -71.627560391199097, 7.453395494306619 ], [ -71.63957516106484, 7.432337347890268 ], [ -71.66034908664102, 7.432156479837658 ], [ -71.715849574897959, 7.442465929159312 ], [ -71.748767463347747, 7.47827769655845 ], [ -71.84155249734988, 7.494762478305745 ], [ -71.847107713050491, 7.509309393713522 ], [ -71.837909308667633, 7.533209744034423 ], [ -71.692000902319762, 7.549332791475138 ], [ -71.36067745579993, 7.486184189748542 ], [ -71.319775559794209, 7.496416123805034 ], [ -71.377963223224185, 7.524037177173966 ], [ -71.490902066077467, 7.629792996349693 ], [ -71.483564011869646, 7.684492498929671 ], [ -71.456692268233553, 7.702424221500621 ], [ -71.462144131146715, 7.769526069372603 ], [ -71.253784755961703, 7.922772529028975 ], [ -71.059946458662125, 8.110047919375972 ], [ -71.011835699657809, 8.219756984697085 ], [ -71.031498582993208, 8.278952338479598 ], [ -71.065139940056156, 8.307813626197856 ], [ -71.077542284448839, 8.376336575572509 ], [ -71.038371548308305, 8.424343979990681 ], [ -71.027364467895893, 8.465323391261506 ], [ -70.9804422681961, 8.506664536838912 ], [ -70.962381354415982, 8.601413276501489 ], [ -70.929954393280639, 8.629266872967776 ], [ -70.910058966847828, 8.624125068417186 ], [ -70.837711961637694, 8.725462550756106 ], [ -70.768568894638747, 8.781479803849834 ], [ -70.727692837054747, 8.764736640583465 ], [ -70.686945969780652, 8.82362193420488 ], [ -70.57746944935559, 8.856669012964574 ], [ -70.555584478840615, 8.925631211910911 ], [ -70.512460496554638, 8.983663844810565 ], [ -70.443730841605031, 9.019604804318249 ], [ -70.271312425028384, 9.023403021732065 ], [ -70.182454799649292, 9.0078742543933 ], [ -70.004067756221957, 8.847057196532376 ], [ -69.819608731357846, 8.751300767416467 ], [ -69.771084561203509, 8.750060533067142 ], [ -69.705377977311798, 8.7238347445778 ], [ -69.623109097307008, 8.777914130432748 ], [ -69.602696906037352, 8.746572374015841 ], [ -69.466865404115083, 8.670375474548507 ], [ -69.29183732763056, 8.64321950917298 ], [ -69.258738572926802, 8.58425670028646 ], [ -69.175565355356866, 8.50046336509223 ], [ -69.162465378974048, 8.441733100202384 ], [ -69.114406296813115, 8.431888738874193 ], [ -69.139340175908387, 8.378817043371839 ], [ -69.127635464405159, 8.351040961271337 ], [ -69.076320767189657, 8.292853297841418 ], [ -68.986145393095399, 8.239394028711445 ], [ -68.948395759356799, 8.186012274846576 ], [ -68.853698697436926, 8.112295844077948 ], [ -68.821039191405532, 8.126739406698221 ], [ -68.828454759079875, 8.200533351832689 ], [ -68.792203742108995, 8.317141221789939 ], [ -68.654227668272256, 8.422871202543945 ], [ -68.603636440569289, 8.499843248367199 ], [ -68.573534919401027, 8.635390530348673 ], [ -68.423053148384099, 8.60373871556925 ], [ -68.395638800590177, 8.617768866140239 ], [ -68.326237352072155, 8.601955877961359 ], [ -68.16539445668883, 8.608932196063961 ], [ -68.063359340561135, 8.575420030210239 ], [ -68.036487596025722, 8.538497218771624 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-K", "NAME_1": "Lara" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.977722134169142, 9.857279771144533 ], [ -68.980796882070422, 9.782271430082403 ], [ -69.013792283986731, 9.749534410584545 ], [ -69.066786465123243, 9.70995026329399 ], [ -69.173989224223305, 9.686695868119784 ], [ -69.223211026367778, 9.692044379144761 ], [ -69.263983731164274, 9.729122219314945 ], [ -69.278556484993771, 9.844257310026819 ], [ -69.337183397096112, 9.768603013817994 ], [ -69.378421189886012, 9.657886257244968 ], [ -69.430562710300819, 9.630575263137871 ], [ -69.591948208043334, 9.618172918745188 ], [ -69.604350552436017, 9.605770575251825 ], [ -69.625227830799759, 9.568124294300731 ], [ -69.615641851889961, 9.510556749394482 ], [ -69.62794084259582, 9.426530870203464 ], [ -69.643753831673962, 9.414748643435132 ], [ -69.706876594079517, 9.395654201779962 ], [ -69.728063930805774, 9.431801865963337 ], [ -69.763410611110828, 9.417461656130513 ], [ -69.867331915835223, 9.415058701797648 ], [ -69.859115363383296, 9.461670844034188 ], [ -69.788680386090959, 9.558900051496153 ], [ -69.841080288024841, 9.56773672157243 ], [ -69.898983730614646, 9.552388821387012 ], [ -69.926527268718473, 9.574015408584216 ], [ -70.006754929596298, 9.497611803541872 ], [ -70.032980719884279, 9.430329088516601 ], [ -70.062152065965051, 9.492650865245196 ], [ -70.109280972139118, 9.517145493869407 ], [ -70.133982307237659, 9.598148302002528 ], [ -70.118944465414756, 9.635174465329271 ], [ -70.069386765586728, 9.668066515357395 ], [ -70.0372440252915, 9.6658185897561 ], [ -70.013059455029804, 9.690494086432921 ], [ -70.089876472121489, 9.773047187277882 ], [ -70.160750698985566, 9.785294501140299 ], [ -70.213331468072795, 9.84580760273866 ], [ -70.247386237185083, 9.82673900040453 ], [ -70.279658168689537, 9.873893744100997 ], [ -70.329319221305013, 9.88632192601608 ], [ -70.351643438693714, 9.92603526541518 ], [ -70.454686245174059, 9.896243800810737 ], [ -70.5167496412829, 9.92851573321451 ], [ -70.580079108364146, 10.036519477092156 ], [ -70.623513149911901, 10.022851059928485 ], [ -70.662012091584756, 9.955826728220927 ], [ -70.661159430863052, 9.904512030106105 ], [ -70.681003181351741, 9.907793484481715 ], [ -70.806809454792472, 9.983938707105608 ], [ -70.85481686100934, 10.043547472038199 ], [ -70.858149991329014, 10.070031642945935 ], [ -70.824999558882553, 10.121320501739774 ], [ -70.710794644157488, 10.194158433364976 ], [ -70.676042243055065, 10.278597723705957 ], [ -70.63798255095395, 10.326579291501105 ], [ -70.535378994045345, 10.363011176524537 ], [ -70.470835130137118, 10.463935247713493 ], [ -70.414533657102595, 10.483804835724584 ], [ -70.323066371815571, 10.562404690424103 ], [ -70.247179531610072, 10.558373928114293 ], [ -70.15749508303162, 10.651701565374935 ], [ -70.047217576929597, 10.645267848732203 ], [ -69.969315355119534, 10.690484726988529 ], [ -69.866582607901023, 10.698003648349697 ], [ -69.823794522399282, 10.730301418275815 ], [ -69.806069505403343, 10.720353705059438 ], [ -69.821236538435471, 10.701750189819393 ], [ -69.789868943596844, 10.701440131456877 ], [ -69.663933478047568, 10.764666245750618 ], [ -69.537197027720651, 10.742006129779043 ], [ -69.498594733260347, 10.695135606023371 ], [ -69.426092699318588, 10.7119046095101 ], [ -69.126266038846609, 10.681260484184008 ], [ -68.924107836307599, 10.697331854781282 ], [ -68.885505540947918, 10.659530544199242 ], [ -68.892456020628856, 10.606148790334373 ], [ -68.964389614688969, 10.556875312245836 ], [ -69.020096809420181, 10.554782416275486 ], [ -69.048570522611499, 10.477681179243007 ], [ -69.07022294823048, 10.461454779014844 ], [ -69.068414273100188, 10.424609482841333 ], [ -69.027176480310288, 10.423059190129493 ], [ -69.014980842391935, 10.24841868727259 ], [ -69.117997809551241, 10.202710883500458 ], [ -69.162077806245748, 10.128064276744965 ], [ -69.219567836786212, 10.171834215076956 ], [ -69.237551236200602, 10.14708120403435 ], [ -69.22747433087568, 10.110132555073335 ], [ -69.141510586244522, 10.005332750306195 ], [ -69.139210984699162, 9.933399156246026 ], [ -69.097818163177692, 9.876684272061482 ], [ -69.073426887340986, 9.899964503858769 ], [ -69.071954108095611, 9.958152167288688 ], [ -68.979117398149413, 10.00982859881077 ], [ -68.958808559667261, 10.000216783277892 ], [ -68.924882981764199, 9.930763657916486 ], [ -68.977722134169142, 9.857279771144533 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VE-P", "NAME_1": "Portuguesa" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -68.980796882070422, 9.782271430082403 ], [ -68.992398240786144, 9.728347072959025 ], [ -68.872121344624361, 9.439527492899458 ], [ -68.821039191405532, 9.419657903989048 ], [ -68.642161220663809, 9.277676907163539 ], [ -68.605238410124514, 9.225173652442095 ], [ -68.652108933880186, 8.94544912397788 ], [ -68.636192592913801, 8.897467556182733 ], [ -68.582397426999648, 8.852793280285653 ], [ -68.663684455073508, 8.804605006915551 ], [ -68.684535895015529, 8.812976588998367 ], [ -68.750319994172401, 8.792176825000467 ], [ -68.703992071876598, 8.769077460356471 ], [ -68.682804735150398, 8.714610500873903 ], [ -68.648026495626254, 8.682106025372775 ], [ -68.573534919401027, 8.635390530348673 ], [ -68.574671800063527, 8.603506171572519 ], [ -68.603636440569289, 8.499843248367199 ], [ -68.654227668272256, 8.422871202543945 ], [ -68.792203742108995, 8.317141221789939 ], [ -68.828454759079875, 8.200533351832689 ], [ -68.816000738743071, 8.145032864475127 ], [ -68.841451381775812, 8.112450872809518 ], [ -68.869718391190816, 8.117799383834495 ], [ -68.889355435205175, 8.152577623358638 ], [ -68.941677822773272, 8.17996613183152 ], [ -68.986145393095399, 8.239394028711445 ], [ -69.076320767189657, 8.292853297841418 ], [ -69.127635464405159, 8.351040961271337 ], [ -69.139340175908387, 8.378817043371839 ], [ -69.114406296813115, 8.431888738874193 ], [ -69.162465378974048, 8.441733100202384 ], [ -69.175565355356866, 8.50046336509223 ], [ -69.258738572926802, 8.58425670028646 ], [ -69.29183732763056, 8.64321950917298 ], [ -69.466865404115083, 8.670375474548507 ], [ -69.602696906037352, 8.746572374015841 ], [ -69.623109097307008, 8.777914130432748 ], [ -69.705377977311798, 8.7238347445778 ], [ -69.771084561203509, 8.750060533067142 ], [ -69.819608731357846, 8.751300767416467 ], [ -70.004067756221957, 8.847057196532376 ], [ -70.182454799649292, 9.0078742543933 ], [ -70.118272670947022, 9.024100653722201 ], [ -70.062720505846642, 9.143654080371505 ], [ -70.065356005075557, 9.252277940074862 ], [ -70.092331102398418, 9.239229641434804 ], [ -70.13328467524758, 9.24933238428207 ], [ -70.135842658312015, 9.265636297976755 ], [ -70.054658983025661, 9.372994085808386 ], [ -70.006754929596298, 9.497611803541872 ], [ -69.934046190079584, 9.571612454251351 ], [ -69.898983730614646, 9.552388821387012 ], [ -69.841080288024841, 9.56773672157243 ], [ -69.788680386090959, 9.558900051496153 ], [ -69.859115363383296, 9.461670844034188 ], [ -69.867331915835223, 9.415058701797648 ], [ -69.763410611110828, 9.417461656130513 ], [ -69.728063930805774, 9.431801865963337 ], [ -69.706876594079517, 9.395654201779962 ], [ -69.62794084259582, 9.426530870203464 ], [ -69.615641851889961, 9.510556749394482 ], [ -69.625227830799759, 9.568124294300731 ], [ -69.604350552436017, 9.605770575251825 ], [ -69.591948208043334, 9.618172918745188 ], [ -69.430562710300819, 9.630575263137871 ], [ -69.378421189886012, 9.657886257244968 ], [ -69.337183397096112, 9.768603013817994 ], [ -69.278556484993771, 9.844257310026819 ], [ -69.261658291197193, 9.782038886085729 ], [ -69.267575243003023, 9.737338771766872 ], [ -69.212178106634326, 9.689228014561195 ], [ -69.066786465123243, 9.70995026329399 ], [ -68.980796882070422, 9.782271430082403 ] ] ] } } +] +} diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/images/exampleGermany.jpg b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/images/exampleGermany.jpg new file mode 100644 index 0000000000000..33855aa4e6df4 Binary files /dev/null and b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/images/exampleGermany.jpg differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/images/exampleUsa.jpg b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/images/exampleUsa.jpg new file mode 100644 index 0000000000000..0937ad09260dc Binary files /dev/null and b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/images/exampleUsa.jpg differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js index eea98d132a13f..79dd291f09a2c 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js @@ -18,6 +18,8 @@ */ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from './transformProps'; +import exampleUsa from './images/exampleUsa.jpg'; +import exampleGermany from './images/exampleGermany.jpg'; import thumbnail from './images/thumbnail.png'; import controlPanel from './controlPanel'; @@ -25,8 +27,9 @@ const metadata = new ChartMetadata({ category: t('Map'), credits: ['https://bl.ocks.org/john-guerra'], description: t( - "Visualizes how a single metric varies across a country's principal subdivisions (states, provinces, etc) on a chloropleth map. Each subdivision's value is elevated when you hover over the corresponding geographic boundary.", + "Visualizes how a single metric varies across a country's principal subdivisions (states, provinces, etc) on a choropleth map. Each subdivision's value is elevated when you hover over the corresponding geographic boundary.", ), + exampleGallery: [{ url: exampleUsa }, { url: exampleGermany }], name: t('Country Map'), tags: [ t('2D'), diff --git a/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/images/example.jpg b/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/images/example.jpg new file mode 100644 index 0000000000000..e2cfb02229a40 Binary files /dev/null and b/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/images/example.jpg differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts b/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts index fdf6fcf774f83..824f8f3dbacd3 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts @@ -18,6 +18,7 @@ */ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import thumbnail from './images/thumbnail.png'; +import example from './images/example.jpg'; import controlPanel from './controlPanel'; const metadata = new ChartMetadata({ @@ -26,6 +27,7 @@ const metadata = new ChartMetadata({ description: t( 'Compares the lengths of time different activities take in a shared timeline view.', ), + exampleGallery: [{ url: example }], name: t('Event Flow'), tags: [t('Legacy'), t('Progressive')], thumbnail, diff --git a/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/types/external.d.ts b/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/types/external.d.ts index c7f1aac5b2d28..a9b451b3153fb 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/types/external.d.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-event-flow/src/types/external.d.ts @@ -18,4 +18,5 @@ */ declare module '*.png'; +declare module '*.jpg'; declare module '@data-ui/event-flow'; diff --git a/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/Heatmap.js b/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/Heatmap.js index b0b32aba4a1ac..f2e3624f05f7f 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/Heatmap.js +++ b/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/Heatmap.js @@ -177,7 +177,7 @@ function Heatmap(element, props) { domain[d[k]] = (domain[d[k]] || 0) + d.v; actualKeys[d[k]] = d[k]; }); - // Not usgin object.keys() as it converts to strings + // Not using object.keys() as it converts to strings const keys = Object.keys(actualKeys).map(s => actualKeys[s]); if (sortMethod === 'alpha_asc') { domain = keys.sort(cmp); diff --git a/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx similarity index 82% rename from superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts rename to superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx index ab3eb2a59fa11..3032654ba267c 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import React from 'react'; import { FeatureFlag, isFeatureEnabled, @@ -26,10 +27,10 @@ import { columnChoices, ControlPanelConfig, ControlPanelState, - formatSelectOptions, formatSelectOptionsForRange, sections, - dndEntity, + sharedControls, + getStandardizedControls, } from '@superset-ui/chart-controls'; const sortAxisChoices = [ @@ -50,7 +51,7 @@ const allColumns = { }; const dndAllColumns = { - ...dndEntity, + ...sharedControls.entity, description: t('Columns to display'), }; @@ -70,7 +71,7 @@ const config: ControlPanelConfig = { name: 'all_columns_x', config: { ...columnsConfig, - label: 'X Axis', + label: t('X Axis'), }, }, ], @@ -79,7 +80,7 @@ const config: ControlPanelConfig = { name: 'all_columns_y', config: { ...columnsConfig, - label: 'Y Axis', + label: t('Y Axis'), }, }, ], @@ -146,8 +147,8 @@ const config: ControlPanelConfig = { label: t('Rendering'), renderTrigger: true, choices: [ - ['pixelated', 'pixelated (Sharp)'], - ['auto', 'auto (Smooth)'], + ['pixelated', t('pixelated (Sharp)')], + ['auto', t('auto (Smooth)')], ], default: 'pixelated', description: t( @@ -164,15 +165,28 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Normalize Across'), choices: [ - ['heatmap', 'heatmap'], - ['x', 'x'], - ['y', 'y'], + ['heatmap', t('heatmap')], + ['x', t('x')], + ['y', t('y')], ], default: 'heatmap', - description: t( - 'Color will be rendered based on a ratio ' + - 'of the cell against the sum of across this ' + - 'criteria', + description: ( + <> + <div> + {t( + 'Color will be shaded based the normalized (0% to 100%) value of a given cell against the other cells in the selected range: ', + )} + </div> + <ul> + <li>{t('x: values are normalized within each column')}</li> + <li>{t('y: values are normalized within each row')}</li> + <li> + {t( + 'heatmap: values are normalized across the entire heatmap', + )} + </li> + </ul> + </> ), }, }, @@ -185,15 +199,15 @@ const config: ControlPanelConfig = { freeForm: true, clearable: false, label: t('Left Margin'), - choices: formatSelectOptions([ - 'auto', - 50, - 75, - 100, - 125, - 150, - 200, - ]), + choices: [ + ['auto', t('auto')], + [50, '50'], + [75, '75'], + [100, '100'], + [125, '125'], + [150, '150'], + [200, '200'], + ], default: 'auto', renderTrigger: true, description: t( @@ -210,15 +224,15 @@ const config: ControlPanelConfig = { clearable: false, freeForm: true, label: t('Bottom Margin'), - choices: formatSelectOptions([ - 'auto', - 50, - 75, - 100, - 125, - 150, - 200, - ]), + choices: [ + ['auto', t('auto')], + [50, '50'], + [75, '75'], + [100, '100'], + [125, '125'], + [150, '150'], + [200, '200'], + ], default: 'auto', renderTrigger: true, description: t( @@ -329,6 +343,10 @@ const config: ControlPanelConfig = { label: t('Value Format'), }, }, + formDataOverrides: formData => ({ + ...formData, + metric: getStandardizedControls().shiftMetric(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx b/superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx index 2c07267748614..67d5f30f9022d 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx +++ b/superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx @@ -111,7 +111,7 @@ class CustomHistogram extends React.PureComponent { renderTooltip={({ datum, color }) => ( <div> <strong style={{ color }}> - {datum.bin0} to {datum.bin1} + {datum.bin0} {t('to')} {datum.bin1} </strong> <div> <strong>{t('count')} </strong> diff --git a/superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts index 26cec94749e6e..08e315ba4058c 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts @@ -16,43 +16,29 @@ * specific language governing permissions and limitations * under the License. */ -import { - FeatureFlag, - isFeatureEnabled, - t, - validateNonEmpty, -} from '@superset-ui/core'; +import { t, validateNonEmpty } from '@superset-ui/core'; import { columnChoices, ControlPanelConfig, ControlPanelState, formatSelectOptions, sections, - dndColumnsControl, + getStandardizedControls, + sharedControls, + ControlState, } from '@superset-ui/chart-controls'; -const allColumns = { - type: 'SelectControl', +const columnsConfig = { + ...sharedControls.columns, label: t('Columns'), - default: null, description: t('Select the numeric columns to draw the histogram'), - mapStateToProps: (state: ControlPanelState) => ({ + mapStateToProps: (state: ControlPanelState, controlState: ControlState) => ({ + ...(sharedControls.columns.mapStateToProps?.(state, controlState) || {}), choices: columnChoices(state.datasource), }), - multi: true, validators: [validateNonEmpty], }; -const dndAllColumns = { - ...dndColumnsControl, - description: t('Select the numeric columns to draw the histogram'), - validators: [validateNonEmpty], -}; - -const columnsConfig = isFeatureEnabled(FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP) - ? dndAllColumns - : allColumns; - const config: ControlPanelConfig = { controlPanelSections: [ sections.legacyRegularTime, @@ -160,5 +146,9 @@ const config: ControlPanelConfig = { ], }, ], + formDataOverrides: formData => ({ + ...formData, + groupby: getStandardizedControls().popAllColumns(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts index ca18b712b82f9..c81e802b3dca2 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts @@ -82,9 +82,9 @@ const config: ControlPanelConfig = { renderTrigger: true, label: t('Value Domain'), choices: [ - ['series', 'series'], - ['overall', 'overall'], - ['change', 'change'], + ['series', t('series')], + ['overall', t('overall')], + ['change', t('change')], ], default: 'series', description: t( diff --git a/superset-frontend/plugins/legacy-plugin-chart-map-box/package.json b/superset-frontend/plugins/legacy-plugin-chart-map-box/package.json index 60e5776eba190..5d739bfabd4a7 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-map-box/package.json +++ b/superset-frontend/plugins/legacy-plugin-chart-map-box/package.json @@ -2,6 +2,19 @@ "name": "@superset-ui/legacy-plugin-chart-map-box", "version": "0.18.25", "description": "Superset Legacy Chart - MapBox", + "keywords": [ + "superset" + ], + "homepage": "https://superset.apache.org/", + "bugs": { + "url": "https://github.com/apache/superset/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/apache/superset.git" + }, + "license": "Apache-2.0", + "author": "Superset", "sideEffects": [ "*.css" ], @@ -11,32 +24,19 @@ "esm", "lib" ], - "repository": { - "type": "git", - "url": "git+https://github.com/apache-superset/superset-ui.git" - }, - "keywords": [ - "superset" - ], - "author": "Superset", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/apache-superset/superset-ui/issues" - }, - "homepage": "https://github.com/apache-superset/superset-ui#readme", - "publishConfig": { - "access": "public" - }, "dependencies": { "prop-types": "^15.6.2", - "react-map-gl": "^4.0.10", + "react-map-gl": "^6.1.19", "supercluster": "^4.1.1", "viewport-mercator-project": "^6.1.1" }, "peerDependencies": { "@superset-ui/chart-controls": "*", "@superset-ui/core": "*", - "react": "^15 || ^16", - "mapbox-gl": "*" + "mapbox-gl": "*", + "react": "^15 || ^16" + }, + "publishConfig": { + "access": "public" } } diff --git a/superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts index 8642e8946fe03..1dc75d96ef444 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts @@ -23,7 +23,8 @@ import { ControlPanelState, formatSelectOptions, sections, - dndEntity, + sharedControls, + getStandardizedControls, } from '@superset-ui/chart-controls'; const allColumns = { @@ -35,16 +36,16 @@ const allColumns = { }; const columnsConfig = isFeatureEnabled(FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP) - ? dndEntity + ? sharedControls.entity : allColumns; const colorChoices = [ - ['rgb(0, 139, 139)', 'Dark Cyan'], - ['rgb(128, 0, 128)', 'Purple'], - ['rgb(255, 215, 0)', 'Gold'], - ['rgb(69, 69, 69)', 'Dim Gray'], - ['rgb(220, 20, 60)', 'Crimson'], - ['rgb(34, 139, 34)', 'Forest Green'], + ['rgb(0, 139, 139)', t('Dark Cyan')], + ['rgb(128, 0, 128)', t('Purple')], + ['rgb(255, 215, 0)', t('Gold')], + ['rgb(69, 69, 69)', t('Dim Gray')], + ['rgb(220, 20, 60)', t('Crimson')], + ['rgb(34, 139, 34)', t('Forest Green')], ]; const config: ControlPanelConfig = { @@ -123,9 +124,7 @@ const config: ControlPanelConfig = { ), mapStateToProps: state => { const datasourceChoices = columnChoices(state.datasource); - const choices: [string, string][] = formatSelectOptions([ - 'Auto', - ]); + const choices: [string, string][] = [['Auto', t('Auto')]]; return { choices: choices.concat(datasourceChoices), }; @@ -140,7 +139,11 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Point Radius Unit'), default: 'Pixels', - choices: formatSelectOptions(['Pixels', 'Miles', 'Kilometers']), + choices: [ + ['Pixels', t('Pixels')], + ['Miles', t('Miles')], + ['Kilometers', t('Kilometers')], + ], description: t( 'The unit of measure for the specified point radius', ), @@ -179,14 +182,14 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Cluster label aggregator'), clearable: false, - choices: formatSelectOptions([ - 'sum', - 'mean', - 'min', - 'max', - 'std', - 'var', - ]), + choices: [ + ['sum', t('sum')], + ['mean', t('mean')], + ['min', t('min')], + ['max', t('max')], + ['std', t('std')], + ['var', t('var')], + ], default: 'sum', description: t( 'Aggregate function applied to the list of points ' + @@ -222,15 +225,15 @@ const config: ControlPanelConfig = { clearable: false, renderTrigger: true, choices: [ - ['mapbox://styles/mapbox/streets-v9', 'Streets'], - ['mapbox://styles/mapbox/dark-v9', 'Dark'], - ['mapbox://styles/mapbox/light-v9', 'Light'], + ['mapbox://styles/mapbox/streets-v9', t('Streets')], + ['mapbox://styles/mapbox/dark-v9', t('Dark')], + ['mapbox://styles/mapbox/light-v9', t('Light')], [ 'mapbox://styles/mapbox/satellite-streets-v9', - 'Satellite Streets', + t('Satellite Streets'), ], - ['mapbox://styles/mapbox/satellite-v9', 'Satellite'], - ['mapbox://styles/mapbox/outdoors-v9', 'Outdoors'], + ['mapbox://styles/mapbox/satellite-v9', t('Satellite')], + ['mapbox://styles/mapbox/outdoors-v9', t('Outdoors')], ], default: 'mapbox://styles/mapbox/light-v9', description: t('Base layer map style'), @@ -328,6 +331,10 @@ const config: ControlPanelConfig = { ), }, }, + formDataOverrides: formData => ({ + ...formData, + groupby: getStandardizedControls().popAllColumns(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/ReactParallelCoordinates.jsx b/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/ReactParallelCoordinates.jsx index 712509e4eb0df..4a7675d555cd6 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/ReactParallelCoordinates.jsx +++ b/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/ReactParallelCoordinates.jsx @@ -23,17 +23,17 @@ import Component from './ParallelCoordinates'; const ReactComponent = reactify(Component); -const ParallelCoordianes = ({ className, ...otherProps }) => ( +const ParallelCoordinates = ({ className, ...otherProps }) => ( <div className={className}> <ReactComponent {...otherProps} /> </div> ); -ParallelCoordianes.propTypes = { +ParallelCoordinates.propTypes = { className: PropTypes.string.isRequired, }; -export default styled(ParallelCoordianes)` +export default styled(ParallelCoordinates)` ${({ theme }) => ` .superset-legacy-chart-parallel-coordinates { div.grid { diff --git a/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/images/example1.jpg b/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/images/example1.jpg new file mode 100644 index 0000000000000..6d73037214c61 Binary files /dev/null and b/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/images/example1.jpg differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/images/example2.jpg b/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/images/example2.jpg new file mode 100644 index 0000000000000..d5858bdc84c48 Binary files /dev/null and b/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/images/example2.jpg differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js b/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js index cc7975f97b42d..0a6ff7bb5aac2 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js +++ b/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js @@ -19,6 +19,8 @@ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example1 from './images/example1.jpg'; +import example2 from './images/example2.jpg'; import controlPanel from './controlPanel'; const metadata = new ChartMetadata({ @@ -27,6 +29,7 @@ const metadata = new ChartMetadata({ description: t( 'Plots the individual metrics for each row in the data vertically and links them together as a line. This chart is useful for comparing multiple metrics across all of the samples or rows in the data.', ), + exampleGallery: [{ url: example1 }, { url: example2 }], name: t('Parallel Coordinates'), tags: [t('Coordinates'), t('Directional'), t('Legacy'), t('Relational')], thumbnail, diff --git a/superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx b/superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx index 93139f7ff7b8d..f910a8bbfd4a5 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx +++ b/superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx @@ -24,7 +24,7 @@ import { D3_FORMAT_DOCS, D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, - formatSelectOptions, + getStandardizedControls, sections, } from '@superset-ui/chart-controls'; import OptionDescription from './OptionDescription'; @@ -39,7 +39,8 @@ const config: ControlPanelConfig = { ['metrics'], ['adhoc_filters'], ['groupby'], - ['limit', 'timeseries_limit_metric'], + ['limit'], + ['timeseries_limit_metric'], ['order_desc'], [ { @@ -52,7 +53,7 @@ const config: ControlPanelConfig = { }, }, ], - ['row_limit', null], + ['row_limit'], ], }, { @@ -248,13 +249,13 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Rolling Function'), default: 'None', - choices: formatSelectOptions([ - 'None', - 'mean', - 'sum', - 'std', - 'cumsum', - ]), + choices: [ + ['None', t('None')], + ['mean', t('mean')], + ['sum', t('sum')], + ['std', t('std')], + ['cumsum', t('cumsum')], + ], description: t( 'Defines a rolling window function to apply, works along ' + 'with the [Periods] text box', @@ -301,22 +302,22 @@ const config: ControlPanelConfig = { multi: true, freeForm: true, label: t('Time Shift'), - choices: formatSelectOptions([ - '1 day', - '1 week', - '28 days', - '30 days', - '52 weeks', - '1 year', - '104 weeks', - '2 years', - '156 weeks', - '3 years', - ]), + choices: [ + ['1 day', t('1 day')], + ['1 week', t('1 week')], + ['28 days', t('28 days')], + ['30 days', t('30 days')], + ['52 weeks', t('52 weeks')], + ['1 year', t('1 year')], + ['104 weeks', t('104 weeks')], + ['2 years', t('2 years')], + ['156 weeks', t('156 weeks')], + ['3 years', t('3 years')], + ], description: t( 'Overlay one or more timeseries from a ' + 'relative time period. Expects relative time deltas ' + - 'in natural language (example: 24 hours, 7 days, ' + + 'in natural language (example: 24 hours, 7 days, ' + '52 weeks, 365 days). Free text is supported.', ), }, @@ -328,10 +329,10 @@ const config: ControlPanelConfig = { label: t('Calculation type'), default: 'values', choices: [ - ['values', 'Actual Values'], - ['absolute', 'Difference'], - ['percentage', 'Percentage change'], - ['ratio', 'Ratio'], + ['values', t('Actual Values')], + ['absolute', t('Difference')], + ['percentage', t('Percentage change')], + ['ratio', t('Ratio')], ], description: t( 'How to display time shifts: as individual lines; as the ' + @@ -350,14 +351,14 @@ const config: ControlPanelConfig = { freeForm: true, label: t('Rule'), default: null, - choices: formatSelectOptions([ - '1T', - '1H', - '1D', - '7D', - '1M', - '1AS', - ]), + choices: [ + ['1T', t('1T')], + ['1H', t('1H')], + ['1D', t('1D')], + ['7D', t('7D')], + ['1M', t('1M')], + ['1AS', t('1AS')], + ], description: t('Pandas resample rule'), }, }, @@ -368,14 +369,14 @@ const config: ControlPanelConfig = { freeForm: true, label: t('Method'), default: null, - choices: formatSelectOptions([ - 'asfreq', - 'bfill', - 'ffill', - 'median', - 'mean', - 'sum', - ]), + choices: [ + ['asfreq', t('asfreq')], + ['bfill', t('bfill')], + ['ffill', t('ffill')], + ['median', t('median')], + ['mean', t('mean')], + ['sum', t('sum')], + ], description: t('Pandas resample method'), }, }, @@ -383,6 +384,11 @@ const config: ControlPanelConfig = { ], }, ], + formDataOverrides: formData => ({ + ...formData, + groupby: getStandardizedControls().popAllColumns(), + metrics: getStandardizedControls().popAllMetrics(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-partition/src/images/example.jpg b/superset-frontend/plugins/legacy-plugin-chart-partition/src/images/example.jpg new file mode 100644 index 0000000000000..7799791a27ae9 Binary files /dev/null and b/superset-frontend/plugins/legacy-plugin-chart-partition/src/images/example.jpg differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js b/superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js index 1094b21e9f387..866a18d0f00a1 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js +++ b/superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js @@ -19,11 +19,13 @@ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example from './images/example.jpg'; import controlPanel from './controlPanel'; const metadata = new ChartMetadata({ category: t('Part of a Whole'), description: t('Compare the same summarized metric across multiple groups.'), + exampleGallery: [{ url: example }], name: t('Partition Chart'), tags: [t('Categorical'), t('Comparison'), t('Legacy'), t('Proportional')], thumbnail, diff --git a/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts index e4c0b477c4827..11daca1e9429e 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts @@ -19,7 +19,6 @@ import { t } from '@superset-ui/core'; import { ControlPanelConfig, - formatSelectOptions, D3_FORMAT_DOCS, D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, @@ -52,14 +51,14 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Aggregation function'), clearable: false, - choices: formatSelectOptions([ - 'sum', - 'mean', - 'min', - 'max', - 'std', - 'var', - ]), + choices: [ + ['sum', t('sum')], + ['mean', t('mean')], + ['min', t('min')], + ['max', t('max')], + ['std', t('std')], + ['var', t('var')], + ], default: 'sum', description: t( 'Aggregate function to apply when pivoting and ' + diff --git a/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/images/example.jpg b/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/images/example.jpg new file mode 100644 index 0000000000000..b6258eeba7e34 Binary files /dev/null and b/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/images/example.jpg differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js b/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js index a141ab60531ce..9d45be2219930 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js +++ b/superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js @@ -19,6 +19,7 @@ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example from './images/example.jpg'; import controlPanel from './controlPanel'; const metadata = new ChartMetadata({ @@ -27,7 +28,8 @@ const metadata = new ChartMetadata({ t(`Used to summarize a set of data by grouping together multiple statistics along two axes. Examples: Sales numbers by region and month, tasks by status and assignee, active users by age and location. This chart is being deprecated and we recommend checking out Pivot Table V2 instead!`), - name: t('Pivot Table'), + exampleGallery: [{ url: example }], + name: t('Pivot Table (legacy)'), tags: [t('Legacy')], thumbnail, useLegacyApi: true, diff --git a/superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx b/superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx index e43da2de7237a..11bb451d57f97 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx +++ b/superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx @@ -20,11 +20,11 @@ import React from 'react'; import { t } from '@superset-ui/core'; import { ControlPanelConfig, - formatSelectOptions, D3_FORMAT_DOCS, D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, sections, + getStandardizedControls, } from '@superset-ui/chart-controls'; const config: ControlPanelConfig = { @@ -131,13 +131,13 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Rolling Function'), default: 'None', - choices: formatSelectOptions([ - 'None', - 'mean', - 'sum', - 'std', - 'cumsum', - ]), + choices: [ + ['None', t('None')], + ['mean', t('mean')], + ['sum', t('sum')], + ['std', t('std')], + ['cumsum', t('cumsum')], + ], description: t( 'Defines a rolling window function to apply, works along ' + 'with the [Periods] text box', @@ -184,18 +184,18 @@ const config: ControlPanelConfig = { multi: true, freeForm: true, label: t('Time Shift'), - choices: formatSelectOptions([ - '1 day', - '1 week', - '28 days', - '30 days', - '52 weeks', - '1 year', - '104 weeks', - '2 years', - '156 weeks', - '3 years', - ]), + choices: [ + ['1 day', t('1 day')], + ['1 week', t('1 week')], + ['28 days', t('28 days')], + ['30 days', t('30 days')], + ['52 weeks', t('52 weeks')], + ['1 year', t('1 year')], + ['104 weeks', t('104 weeks')], + ['2 years', t('2 years')], + ['156 weeks', t('156 weeks')], + ['3 years', t('3 years')], + ], description: t( 'Overlay one or more timeseries from a ' + 'relative time period. Expects relative time deltas ' + @@ -211,10 +211,10 @@ const config: ControlPanelConfig = { label: t('Calculation type'), default: 'values', choices: [ - ['values', 'Actual Values'], - ['absolute', 'Difference'], - ['percentage', 'Percentage change'], - ['ratio', 'Ratio'], + ['values', t('Actual Values')], + ['absolute', t('Difference')], + ['percentage', t('Percentage change')], + ['ratio', t('Ratio')], ], description: t( 'How to display time shifts: as individual lines; as the ' + @@ -233,14 +233,14 @@ const config: ControlPanelConfig = { freeForm: true, label: t('Rule'), default: null, - choices: formatSelectOptions([ - '1T', - '1H', - '1D', - '7D', - '1M', - '1AS', - ]), + choices: [ + ['1T', t('1T')], + ['1H', t('1H')], + ['1D', t('1D')], + ['7D', t('7D')], + ['1M', t('1M')], + ['1AS', t('1AS')], + ], description: t('Pandas resample rule'), }, }, @@ -251,14 +251,14 @@ const config: ControlPanelConfig = { freeForm: true, label: t('Method'), default: null, - choices: formatSelectOptions([ - 'asfreq', - 'bfill', - 'ffill', - 'median', - 'mean', - 'sum', - ]), + choices: [ + ['asfreq', t('asfreq')], + ['bfill', t('bfill')], + ['ffill', t('ffill')], + ['median', t('median')], + ['mean', t('mean')], + ['sum', t('sum')], + ], description: t('Pandas resample method'), }, }, @@ -266,6 +266,11 @@ const config: ControlPanelConfig = { ], }, ], + formDataOverrides: formData => ({ + ...formData, + groupby: getStandardizedControls().popAllColumns(), + metrics: getStandardizedControls().popAllMetrics(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-rose/src/images/example1.jpg b/superset-frontend/plugins/legacy-plugin-chart-rose/src/images/example1.jpg new file mode 100644 index 0000000000000..732aa8dde50c2 Binary files /dev/null and b/superset-frontend/plugins/legacy-plugin-chart-rose/src/images/example1.jpg differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-rose/src/images/example2.jpg b/superset-frontend/plugins/legacy-plugin-chart-rose/src/images/example2.jpg new file mode 100644 index 0000000000000..0424e67660f32 Binary files /dev/null and b/superset-frontend/plugins/legacy-plugin-chart-rose/src/images/example2.jpg differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js b/superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js index 6c215aea0393d..a46e0b753570c 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js +++ b/superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js @@ -19,6 +19,8 @@ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example1 from './images/example1.jpg'; +import example2 from './images/example2.jpg'; import controlPanel from './controlPanel'; const metadata = new ChartMetadata({ @@ -26,6 +28,7 @@ const metadata = new ChartMetadata({ description: t( 'A polar coordinate chart where the circle is broken into wedges of equal angle, and the value represented by any wedge is illustrated by its area, rather than its radius or sweep angle.', ), + exampleGallery: [{ url: example1 }, { url: example2 }], name: t('Nightingale Rose Chart'), tags: [ t('Legacy'), diff --git a/superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/SankeyLoop.js b/superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/SankeyLoop.js index 33a3490159615..00f47ada2666e 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/SankeyLoop.js +++ b/superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/SankeyLoop.js @@ -26,9 +26,9 @@ import { CategoricalColorNamespace, } from '@superset-ui/core'; -// a problem with 'd3-sankey-diagram' is that the sankey().extent() paramters, which +// a problem with 'd3-sankey-diagram' is that the sankey().extent() parameters, which // informs the layout of the bounding box of the sankey columns, does not account -// for labels and paths which happen to be layedout outside that rectangle. +// for labels and paths which happen to be layed out outside that rectangle. // for that reason i've selected relatively large default left/right margins, and have // made 'margin' a property. i have raised an issue in the chart repo: // diff --git a/superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts index 6ee16465cff09..38f25f05b1a12 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts @@ -17,7 +17,11 @@ * under the License. */ import { t } from '@superset-ui/core'; -import { ControlPanelConfig, sections } from '@superset-ui/chart-controls'; +import { + ControlPanelConfig, + getStandardizedControls, + sections, +} from '@superset-ui/chart-controls'; const config: ControlPanelConfig = { controlPanelSections: [ @@ -67,6 +71,11 @@ const config: ControlPanelConfig = { controlSetRows: [['color_scheme']], }, ], + formDataOverrides: formData => ({ + ...formData, + groupby: getStandardizedControls().popAllColumns(), + metric: getStandardizedControls().shiftMetric(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/Sunburst.js b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/Sunburst.js index 4418f68bbd150..1389df111cccd 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/Sunburst.js +++ b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/Sunburst.js @@ -24,6 +24,7 @@ import { NumberFormats, CategoricalColorNamespace, getSequentialSchemeRegistry, + t, } from '@superset-ui/core'; import wrapSvgText from './utils/wrapSvgText'; @@ -381,7 +382,10 @@ function Sunburst(element, props) { .append('text') .attr('class', 'path-abs-percent') .attr('y', yOffsets[offsetIndex]) - .text(`${absolutePercString} of total`); + // eslint-disable-next-line prefer-template + .text(absolutePercString + ' ' + t('of total')); + + const OF_PARENT_TEXT = t('of parent'); if (conditionalPercString) { offsetIndex += 1; @@ -389,7 +393,7 @@ function Sunburst(element, props) { .append('text') .attr('class', 'path-cond-percent') .attr('y', yOffsets[offsetIndex]) - .text(`${conditionalPercString} of parent`); + .text(`${conditionalPercString} ${OF_PARENT_TEXT}`); } offsetIndex += 1; diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts index df50be9c4d16c..32b56fb9e4af2 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts @@ -20,6 +20,7 @@ import { t } from '@superset-ui/core'; import { ControlPanelConfig, ControlPanelsContainerProps, + getStandardizedControls, sections, } from '@superset-ui/chart-controls'; @@ -96,6 +97,12 @@ const config: ControlPanelConfig = { description: t('This defines the level of the hierarchy'), }, }, + formDataOverrides: formData => ({ + ...formData, + groupby: getStandardizedControls().popAllColumns(), + metric: getStandardizedControls().shiftMetric(), + secondary_metric: getStandardizedControls().shiftMetric(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js b/superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js index 0b517d6a2d6ad..5603d7e30100f 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js +++ b/superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js @@ -37,7 +37,7 @@ const metadata = new ChartMetadata({ { url: example3 }, { url: example4 }, ], - name: t('Treemap'), + name: t('Treemap (legacy)'), tags: [ t('Categorical'), t('Legacy'), diff --git a/superset-frontend/plugins/legacy-plugin-chart-world-map/src/WorldMap.js b/superset-frontend/plugins/legacy-plugin-chart-world-map/src/WorldMap.js index 1d51a7e840513..7b56d432eaaa7 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-world-map/src/WorldMap.js +++ b/superset-frontend/plugins/legacy-plugin-chart-world-map/src/WorldMap.js @@ -24,6 +24,8 @@ import { getNumberFormatter, getSequentialSchemeRegistry, CategoricalColorNamespace, + logging, + t, } from '@superset-ui/core'; import Datamap from 'datamaps/dist/datamaps.world.min'; import { ColorBy } from './utils'; @@ -50,6 +52,8 @@ const formatter = getNumberFormatter(); function WorldMap(element, props) { const { + countryFieldtype, + entity, data, width, height, @@ -61,6 +65,8 @@ function WorldMap(element, props) { colorScheme, sliceId, theme, + onContextMenu, + inContextMenu, } = props; const div = d3.select(element); div.classed('superset-legacy-chart-world-map', true); @@ -102,6 +108,31 @@ function WorldMap(element, props) { mapData[d.country] = d; }); + const handleContextMenu = source => { + const pointerEvent = d3.event; + pointerEvent.preventDefault(); + const key = source.id || source.country; + const val = countryFieldtype === 'name' ? mapData[key]?.name : key; + if (val) { + const filters = [ + { + col: entity, + op: '==', + val, + formattedVal: val, + }, + ]; + onContextMenu(pointerEvent.clientX, pointerEvent.clientY, filters); + } else { + logging.warn( + t( + `Unable to process right-click on %s. Check you chart configuration.`, + ), + key, + ); + } + }; + const map = new Datamap({ element, width, @@ -111,8 +142,8 @@ function WorldMap(element, props) { defaultFill: theme.colors.grayscale.light2, }, geographyConfig: { - popupOnHover: true, - highlightOnHover: true, + popupOnHover: !inContextMenu, + highlightOnHover: !inContextMenu, borderWidth: 1, borderColor: theme.colors.grayscale.light5, highlightBorderColor: theme.colors.grayscale.light5, @@ -127,7 +158,7 @@ function WorldMap(element, props) { borderWidth: 1, borderOpacity: 1, borderColor: color, - popupOnHover: true, + popupOnHover: !inContextMenu, radius: null, popupTemplate: (geo, d) => `<div class="hoverinfo"><strong>${d.name}</strong><br>${formatter( @@ -135,7 +166,7 @@ function WorldMap(element, props) { )}</div>`, fillOpacity: 0.5, animate: true, - highlightOnHover: true, + highlightOnHover: !inContextMenu, highlightFillColor: color, highlightBorderColor: theme.colors.grayscale.dark2, highlightBorderWidth: 2, @@ -144,6 +175,11 @@ function WorldMap(element, props) { exitDelay: 100, key: JSON.stringify, }, + done: datamap => { + datamap.svg + .selectAll('.datamaps-subunit') + .on('contextmenu', handleContextMenu); + }, }); map.updateChoropleth(mapData); @@ -153,7 +189,8 @@ function WorldMap(element, props) { div .selectAll('circle.datamaps-bubble') .style('fill', color) - .style('stroke', color); + .style('stroke', color) + .on('contextmenu', handleContextMenu); } } diff --git a/superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts index f9f7dfb09dc2e..b0f3be22c50ec 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts +++ b/superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts @@ -20,6 +20,7 @@ import { t } from '@superset-ui/core'; import { ControlPanelConfig, formatSelectOptions, + getStandardizedControls, sections, } from '@superset-ui/chart-controls'; import { ColorBy } from './utils'; @@ -40,10 +41,10 @@ const config: ControlPanelConfig = { label: t('Country Field Type'), default: 'cca2', choices: [ - ['name', 'Full name'], - ['cioc', 'code International Olympic Committee (cioc)'], - ['cca2', 'code ISO 3166-1 alpha-2 (cca2)'], - ['cca3', 'code ISO 3166-1 alpha-3 (cca3)'], + ['name', t('Full name')], + ['cioc', t('code International Olympic Committee (cioc)')], + ['cca2', t('code ISO 3166-1 alpha-2 (cca2)')], + ['cca3', t('code ISO 3166-1 alpha-3 (cca3)')], ], description: t( 'The country code standard that Superset should expect ' + @@ -152,9 +153,10 @@ const config: ControlPanelConfig = { Boolean(controls?.color_by.value === ColorBy.country), }, }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, + entity: getStandardizedControls().shiftColumn(), + metric: getStandardizedControls().shiftMetric(), }), }; diff --git a/superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js b/superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js index d97adfadf36c9..6303caec08db7 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js +++ b/superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; +import { t, ChartMetadata, ChartPlugin, Behavior } from '@superset-ui/core'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; import example1 from './images/WorldMap1.jpg'; @@ -45,6 +45,7 @@ const metadata = new ChartMetadata({ ], thumbnail, useLegacyApi: true, + behaviors: [Behavior.DRILL_TO_DETAIL], }); export default class WorldMapChartPlugin extends ChartPlugin { diff --git a/superset-frontend/plugins/legacy-plugin-chart-world-map/src/transformProps.js b/superset-frontend/plugins/legacy-plugin-chart-world-map/src/transformProps.js index fd5f109c0d40e..6348874eaba03 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-world-map/src/transformProps.js +++ b/superset-frontend/plugins/legacy-plugin-chart-world-map/src/transformProps.js @@ -19,8 +19,12 @@ import { rgb } from 'd3-color'; export default function transformProps(chartProps) { - const { width, height, formData, queriesData } = chartProps; + const { width, height, formData, queriesData, hooks, inContextMenu } = + chartProps; + const { onContextMenu } = hooks; const { + countryFieldtype, + entity, maxBubbleSize, showBubbles, linearColorScheme, @@ -32,6 +36,8 @@ export default function transformProps(chartProps) { const { r, g, b } = colorPicker; return { + countryFieldtype, + entity, data: queriesData[0].data, width, height, @@ -42,5 +48,7 @@ export default function transformProps(chartProps) { colorBy, colorScheme, sliceId, + onContextMenu, + inContextMenu, }; } diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/package.json b/superset-frontend/plugins/legacy-preset-chart-deckgl/package.json index 7b11af60566e5..83a4a977324f6 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/package.json +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/package.json @@ -5,13 +5,13 @@ "keywords": [ "superset" ], - "homepage": "https://github.com/apache-superset/superset-ui-plugins-deckgl#readme", + "homepage": "https://superset.apache.org/", "bugs": { - "url": "https://github.com/apache-superset/superset-ui-plugins-deckgl/issues" + "url": "https://github.com/apache/superset/issues" }, "repository": { "type": "git", - "url": "git+https://github.com/apache-superset/superset-ui-plugins-deckgl.git" + "url": "git+https://github.com/apache/superset.git" }, "license": "Apache-2.0", "author": "Superset", @@ -37,17 +37,17 @@ "mousetrap": "^1.6.1", "prop-types": "^15.6.0", "react-bootstrap-slider": "2.1.5", - "underscore": "^1.8.3", + "underscore": "^1.12.1", "urijs": "^1.19.8", "xss": "^1.0.10" }, "peerDependencies": { "@superset-ui/chart-controls": "*", "@superset-ui/core": "*", + "mapbox-gl": "*", "react": "^16.13.1", "react-dom": "^16.13.1", - "react-map-gl": "^4.0.10", - "mapbox-gl": "*" + "react-map-gl": "^6.1.19" }, "publishConfig": { "access": "public" diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/components/PlaySlider.jsx b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/components/PlaySlider.jsx index eda7803f21754..1705b8f533844 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/components/PlaySlider.jsx +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/components/PlaySlider.jsx @@ -27,7 +27,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import Mousetrap from 'mousetrap'; import { t, styled } from '@superset-ui/core'; -import BootrapSliderWrapper from './BootstrapSliderWrapper'; +import BootstrapSliderWrapper from './BootstrapSliderWrapper'; const StyledSlider = styled.div` ${({ theme }) => ` @@ -210,7 +210,7 @@ export default class PlaySlider extends React.PureComponent { /> </div> <div className="play-slider-scrobbler padded"> - <BootrapSliderWrapper + <BootstrapSliderWrapper value={range ? values : values[0]} range={range} formatter={this.formatter} diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/Arc.jsx b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/Arc.jsx index a2c8e61436100..75cf8d09a18ca 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/Arc.jsx +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/Arc.jsx @@ -37,11 +37,11 @@ function setTooltipContent(formData) { return o => ( <div className="deckgl-tooltip"> <TooltipRow - label={`${t('Start (Longitude, Latitude)')}: `} + label={t('Start (Longitude, Latitude): ')} value={`${o.object.sourcePosition[0]}, ${o.object.sourcePosition[1]}`} /> <TooltipRow - label={`${t('End (Longitude, Latitude)')}: `} + label={t('End (Longitude, Latitude): ')} value={`${o.object.targetPosition[0]}, ${o.object.targetPosition[1]}`} /> {formData.dimension && ( diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/Grid.jsx b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/Grid.jsx index a010d70c19d9e..d19ef3edb1610 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/Grid.jsx +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/Grid.jsx @@ -18,10 +18,11 @@ */ import { GridLayer } from 'deck.gl'; import React from 'react'; -import { t } from '@superset-ui/core'; +import { t, CategoricalColorNamespace } from '@superset-ui/core'; import { commonLayerProps, getAggFunc } from '../common'; import sandboxedEval from '../../utils/sandbox'; +import { hexToRGB } from '../../utils/colors'; import { createDeckGLComponent } from '../../factory'; import TooltipRow from '../../TooltipRow'; @@ -29,11 +30,13 @@ function setTooltipContent(o) { return ( <div className="deckgl-tooltip"> <TooltipRow - label={`${t('Longitude and Latitude')}: `} + // eslint-disable-next-line prefer-template + label={t('Longitude and Latitude') + ': '} value={`${o.coordinate[0]}, ${o.coordinate[1]}`} /> <TooltipRow - label={`${t('Height')}: `} + // eslint-disable-next-line prefer-template + label={t('Height') + ': '} value={`${o.object.elevationValue}`} /> </div> @@ -42,11 +45,9 @@ function setTooltipContent(o) { export function getLayer(formData, payload, onAddFilter, setTooltip) { const fd = formData; - const c = fd.color_picker; - let data = payload.data.features.map(d => ({ - ...d, - color: [c.r, c.g, c.b, 255 * c.a], - })); + const colorScale = CategoricalColorNamespace.getScale(fd.color_scheme); + const colorRange = colorScale.range().map(color => hexToRGB(color)); + let data = payload.data.features; if (fd.js_data_mutator) { // Applying user defined data mutator if defined @@ -61,9 +62,8 @@ export function getLayer(formData, payload, onAddFilter, setTooltip) { data, pickable: true, cellSize: fd.grid_size, - minColor: [0, 0, 0, 0], extruded: fd.extruded, - maxColor: [c.r, c.g, c.b, 255 * c.a], + colorRange, outline: false, getElevationValue: aggFunc, getColorValue: aggFunc, diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts index a96fe21dd68a7..9b8e33d739816 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts @@ -16,7 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import { ControlPanelConfig, sections } from '@superset-ui/chart-controls'; +import { + ControlPanelConfig, + getStandardizedControls, + sections, +} from '@superset-ui/chart-controls'; import { t, validateNonEmpty } from '@superset-ui/core'; import { filterNulls, @@ -50,8 +54,10 @@ const config: ControlPanelConfig = { label: t('Map'), controlSetRows: [ [mapboxStyle, viewport], - ['color_picker', autozoom], - [gridSize, extruded], + ['color_scheme'], + [autozoom], + [gridSize], + [extruded], ], }, { @@ -71,6 +77,10 @@ const config: ControlPanelConfig = { validators: [validateNonEmpty], }, }, + formDataOverrides: formData => ({ + ...formData, + size: getStandardizedControls().shiftMetric(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/Hex.jsx b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/Hex.jsx index 46b3c59974daa..a3c430acb19fc 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/Hex.jsx +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/Hex.jsx @@ -18,10 +18,11 @@ */ import { HexagonLayer } from 'deck.gl'; import React from 'react'; -import { t } from '@superset-ui/core'; +import { t, CategoricalColorNamespace } from '@superset-ui/core'; import { commonLayerProps, getAggFunc } from '../common'; import sandboxedEval from '../../utils/sandbox'; +import { hexToRGB } from '../../utils/colors'; import { createDeckGLComponent } from '../../factory'; import TooltipRow from '../../TooltipRow'; @@ -29,11 +30,12 @@ function setTooltipContent(o) { return ( <div className="deckgl-tooltip"> <TooltipRow - label={`${t('Centroid (Longitude and Latitude)')}: `} + label={t('Centroid (Longitude and Latitude): ')} value={`(${o.coordinate[0]}, ${o.coordinate[1]})`} /> <TooltipRow - label={`${t('Height')}: `} + // eslint-disable-next-line prefer-template + label={t('Height') + ': '} value={`${o.object.elevationValue}`} /> </div> @@ -42,11 +44,9 @@ function setTooltipContent(o) { export function getLayer(formData, payload, onAddFilter, setTooltip) { const fd = formData; - const c = fd.color_picker; - let data = payload.data.features.map(d => ({ - ...d, - color: [c.r, c.g, c.b, 255 * c.a], - })); + const colorScale = CategoricalColorNamespace.getScale(fd.color_scheme); + const colorRange = colorScale.range().map(color => hexToRGB(color)); + let data = payload.data.features; if (fd.js_data_mutator) { // Applying user defined data mutator if defined @@ -60,9 +60,8 @@ export function getLayer(formData, payload, onAddFilter, setTooltip) { data, pickable: true, radius: fd.grid_size, - minColor: [0, 0, 0, 0], extruded: fd.extruded, - maxColor: [c.r, c.g, c.b, 255 * c.a], + colorRange, outline: false, getElevationValue: aggFunc, getColorValue: aggFunc, diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts index 4db5e39b964a1..2f9293c521826 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts @@ -16,9 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import { ControlPanelConfig, sections } from '@superset-ui/chart-controls'; +import { + ControlPanelConfig, + getStandardizedControls, + sections, +} from '@superset-ui/chart-controls'; import { t } from '@superset-ui/core'; -import { formatSelectOptions } from '../../utilities/utils'; import { autozoom, extruded, @@ -51,7 +54,7 @@ const config: ControlPanelConfig = { label: t('Map'), controlSetRows: [ [mapboxStyle, viewport], - ['color_picker'], + ['color_scheme'], [autozoom], [gridSize], [extruded], @@ -67,20 +70,20 @@ const config: ControlPanelConfig = { default: 'sum', clearable: false, renderTrigger: true, - choices: formatSelectOptions([ - 'sum', - 'min', - 'max', - 'mean', - 'median', - 'count', - 'variance', - 'deviation', - 'p1', - 'p5', - 'p95', - 'p99', - ]), + choices: [ + ['sum', t('sum')], + ['min', t('min')], + ['max', t('max')], + ['mean', t('mean')], + ['median', t('median')], + ['count', t('count')], + ['variance', t('variance')], + ['deviation', t('deviation')], + ['p1', t('p1')], + ['p5', t('p5')], + ['p95', t('p95')], + ['p99', t('p99')], + ], }, }, ], @@ -96,6 +99,10 @@ const config: ControlPanelConfig = { ], }, ], + formDataOverrides: formData => ({ + ...formData, + size: getStandardizedControls().shiftMetric(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts index 99866115ab029..cdbb06746bc97 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts @@ -52,8 +52,8 @@ const config: ControlPanelConfig = { config: { ...lineType.config, choices: [ - ['polyline', 'Polyline'], - ['json', 'JSON'], + ['polyline', t('Polyline')], + ['json', t('JSON')], ], }, }, diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/Polygon.jsx b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/Polygon.jsx index bdd4f66bc1161..81df4384f9da1 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/Polygon.jsx +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/Polygon.jsx @@ -22,6 +22,7 @@ /* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */ import React from 'react'; +import { t } from '@superset-ui/core'; import PropTypes from 'prop-types'; import { PolygonLayer } from 'deck.gl'; @@ -39,7 +40,7 @@ import getPointsFromPolygon from '../../utils/getPointsFromPolygon'; // eslint-disable-next-line import/extensions import fitViewport from '../../utils/fitViewport'; -const DOUBLE_CLICK_TRESHOLD = 250; // milliseconds +const DOUBLE_CLICK_THRESHOLD = 250; // milliseconds function getElevation(d, colorScaler) { /* in deck.gl 5.3.4 (used in Superset as of 2018-10-24), if a polygon has @@ -57,7 +58,11 @@ function setTooltipContent(formData) { return ( <div className="deckgl-tooltip"> {o.object.name && ( - <TooltipRow label="name: " value={`${o.object.name}`} /> + <TooltipRow + // eslint-disable-next-line prefer-template + label={t('name') + ': '} + value={`${o.object.name}`} + /> )} {o.object[formData.line_column] && ( <TooltipRow @@ -223,7 +228,7 @@ class DeckGLPolygon extends React.Component { const { formData, onAddFilter } = this.props; const now = new Date(); - const doubleClick = now - this.state.lastClick <= DOUBLE_CLICK_TRESHOLD; + const doubleClick = now - this.state.lastClick <= DOUBLE_CLICK_THRESHOLD; // toggle selected polygons const selected = [...this.state.selected]; diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts index faea2336bb48e..a226004c76f78 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts @@ -16,7 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import { ControlPanelConfig, sections } from '@superset-ui/chart-controls'; +import { + ControlPanelConfig, + getStandardizedControls, + sections, +} from '@superset-ui/chart-controls'; import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; import timeGrainSqlaAnimationOverrides from '../../utilities/controls'; import { formatSelectOptions } from '../../utilities/utils'; @@ -194,6 +198,10 @@ const config: ControlPanelConfig = { }, time_grain_sqla: timeGrainSqlaAnimationOverrides, }, + formDataOverrides: formData => ({ + ...formData, + metric: getStandardizedControls().shiftMetric(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/Scatter.jsx b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/Scatter.jsx index ca0162fa3a1cf..3ad0dcea986b8 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/Scatter.jsx +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/Scatter.jsx @@ -36,12 +36,14 @@ function setTooltipContent(formData, verboseMap) { return ( <div className="deckgl-tooltip"> <TooltipRow - label={`${t('Longitude and Latitude')}: `} + // eslint-disable-next-line prefer-template + label={t('Longitude and Latitude') + ': '} value={`${o.object.position[0]}, ${o.object.position[1]}`} /> {o.object.cat_color && ( <TooltipRow - label={`${t('Category')}: `} + // eslint-disable-next-line prefer-template + label={t('Category') + ': '} value={`${o.object.cat_color}`} /> )} diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts index 4932019bb7ad3..ef3d45a95685f 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts @@ -80,12 +80,12 @@ const config: ControlPanelConfig = { default: 'square_m', clearable: false, choices: [ - ['square_m', 'Square meters'], - ['square_km', 'Square kilometers'], - ['square_miles', 'Square miles'], - ['radius_m', 'Radius in meters'], - ['radius_km', 'Radius in kilometers'], - ['radius_miles', 'Radius in miles'], + ['square_m', t('Square meters')], + ['square_km', t('Square kilometers')], + ['square_miles', t('Square miles')], + ['radius_m', t('Radius in meters')], + ['radius_km', t('Radius in kilometers')], + ['radius_miles', t('Radius in miles')], ], description: t( 'The unit of measure for the specified point radius', @@ -119,7 +119,7 @@ const config: ControlPanelConfig = { renderTrigger: true, default: 250, description: t( - 'Maxium radius size of the circle, in pixels. As the zoom level changes, this ' + + 'Maximum radius size of the circle, in pixels. As the zoom level changes, this ' + 'insures that the circle respects this maximum radius.', ), }, diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/Screengrid.jsx b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/Screengrid.jsx index ca61ec0b81cca..7883dda17ed66 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/Screengrid.jsx +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/Screengrid.jsx @@ -40,10 +40,15 @@ function setTooltipContent(o) { return ( <div className="deckgl-tooltip"> <TooltipRow - label={`${t('Longitude and Latitude')}: `} + // eslint-disable-next-line prefer-template + label={t('Longitude and Latitude') + ': '} value={`${o.coordinate[0]}, ${o.coordinate[1]}`} /> - <TooltipRow label={`${t('Weight')}: `} value={`${o.object.cellWeight}`} /> + <TooltipRow + // eslint-disable-next-line prefer-template + label={t('Weight') + ': '} + value={`${o.object.cellWeight}`} + /> </div> ); } diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts index 733d12ca21b86..caf052581cbb5 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts @@ -16,7 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import { ControlPanelConfig, sections } from '@superset-ui/chart-controls'; +import { + ControlPanelConfig, + getStandardizedControls, + sections, +} from '@superset-ui/chart-controls'; import { t, validateNonEmpty } from '@superset-ui/core'; import timeGrainSqlaAnimationOverrides from '../../utilities/controls'; import { @@ -76,6 +80,10 @@ const config: ControlPanelConfig = { }, time_grain_sqla: timeGrainSqlaAnimationOverrides, }, + formDataOverrides: formData => ({ + ...formData, + size: getStandardizedControls().shiftMetric(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx index f665c118eaccb..3ae47ac054e8a 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx @@ -38,8 +38,8 @@ const DEFAULT_VIEWPORT = { }; const sandboxUrl = - 'https://github.com/apache/incubator-superset/' + - 'blob/master/superset-frontend/src/modules/sandbox.js'; + 'https://github.com/apache/superset/' + + 'blob/master/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/sandbox.js'; const jsFunctionInfo = ( <div> {t( @@ -121,7 +121,7 @@ export const jsColumns = { label: t('Extra data for JS'), default: [], description: t( - 'List of extra columns made available in Javascript functions', + 'List of extra columns made available in JavaScript functions', ), }, }; @@ -129,7 +129,7 @@ export const jsColumns = { export const jsDataMutator = { name: 'js_data_mutator', config: jsFunctionControl( - t('Javascript data interceptor'), + t('JavaScript data interceptor'), t( 'Define a javascript function that receives the data array used in the visualization ' + 'and is expected to return a modified version of that array. This can be used ' + @@ -141,7 +141,7 @@ export const jsDataMutator = { export const jsTooltip = { name: 'js_tooltip', config: jsFunctionControl( - t('Javascript tooltip generator'), + t('JavaScript tooltip generator'), t( 'Define a function that receives the input and outputs the content for a tooltip', ), @@ -151,7 +151,7 @@ export const jsTooltip = { export const jsOnclickHref = { name: 'js_onclick_href', config: jsFunctionControl( - t('Javascript onClick href'), + t('JavaScript onClick href'), t('Define a function that returns a URL to navigate to when user clicks'), ), }; @@ -179,11 +179,11 @@ export const legendPosition = { clearable: false, default: 'tr', choices: [ - [null, 'None'], - ['tl', 'Top left'], - ['tr', 'Top right'], - ['bl', 'Bottom left'], - ['br', 'Bottom right'], + [null, t('None')], + ['tl', t('Top left')], + ['tr', t('Top right')], + ['bl', t('Bottom left')], + ['br', t('Bottom right')], ], renderTrigger: true, }, @@ -270,7 +270,7 @@ export const extruded = { label: t('Extruded'), renderTrigger: true, default: true, - description: 'Whether to make the grid 3D', + description: t('Whether to make the grid 3D'), }, }; @@ -347,9 +347,9 @@ export const lineType = { default: 'json', description: t('The encoding format of the lines'), choices: [ - ['polyline', 'Polyline'], - ['json', 'JSON'], - ['geohash', 'geohash (square)'], + ['polyline', t('Polyline')], + ['json', t('JSON')], + ['geohash', t('geohash (square)')], ], }, }; @@ -371,12 +371,12 @@ export const mapboxStyle = { clearable: false, renderTrigger: true, choices: [ - ['mapbox://styles/mapbox/streets-v9', 'Streets'], - ['mapbox://styles/mapbox/dark-v9', 'Dark'], - ['mapbox://styles/mapbox/light-v9', 'Light'], - ['mapbox://styles/mapbox/satellite-streets-v9', 'Satellite Streets'], - ['mapbox://styles/mapbox/satellite-v9', 'Satellite'], - ['mapbox://styles/mapbox/outdoors-v9', 'Outdoors'], + ['mapbox://styles/mapbox/streets-v9', t('Streets')], + ['mapbox://styles/mapbox/dark-v9', t('Dark')], + ['mapbox://styles/mapbox/light-v9', t('Light')], + ['mapbox://styles/mapbox/satellite-streets-v9', t('Satellite Streets')], + ['mapbox://styles/mapbox/satellite-v9', t('Satellite')], + ['mapbox://styles/mapbox/outdoors-v9', t('Outdoors')], ], default: 'mapbox://styles/mapbox/light-v9', description: t('Base layer map style'), diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx index 6027b87f10204..30ffd27287ada 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx @@ -18,12 +18,12 @@ */ import { t } from '@superset-ui/core'; -import { dndEntity } from '@superset-ui/chart-controls'; +import { sharedControls } from '@superset-ui/chart-controls'; export const dndLineColumn = { name: 'line_column', config: { - ...dndEntity, + ...sharedControls.entity, label: t('Lines column'), description: t('The database columns that contains lines information'), }, @@ -32,7 +32,7 @@ export const dndLineColumn = { export const dndGeojsonColumn = { name: 'geojson', config: { - ...dndEntity, + ...sharedControls.entity, label: t('GeoJson Column'), description: t('Select the geojson column'), }, diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/explore.js b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/explore.js index 5714eb5da1052..cf1d691ff916f 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/explore.js +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/explore.js @@ -23,7 +23,7 @@ const MAX_URL_LENGTH = 8000; export function getURIDirectory(formData, endpointType = 'base') { // Building the directory part of the URI - let directory = '/superset/explore/'; + let directory = '/explore/'; if (['json', 'csv', 'query', 'results', 'samples'].includes(endpointType)) { directory = '/superset/explore_json/'; } diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/fitViewport.ts b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/fitViewport.ts index 5b5bbb6b478fb..c8e2487b90c16 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/fitViewport.ts +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/fitViewport.ts @@ -21,7 +21,7 @@ import computeBoundsFromPoints from './computeBoundsFromPoints'; import { Point } from '../types'; export type Viewport = { - longtitude: number; + longitude: number; latitude: number; zoom: number; bearing?: number; diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/time.js b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/time.js index 83cb78b494c14..6554adb7a1ddd 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/time.js +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils/time.js @@ -20,7 +20,7 @@ import moment from 'moment'; // array with the minimum values of each part of a timestamp -- note that -// months are zero-indexed in Javascript +// months are zero-indexed in JavaScript const truncatePartTo = [ 1, // year 0, // month @@ -62,13 +62,13 @@ export function truncate(timestamp, step) { function getStepSeconds(step, start) { /* Return number of seconds in a step. * - * The step might be ambigous, eg, "1 month" has a variable number of + * The step might be ambiguous, eg, "1 month" has a variable number of * seconds, which is why we need to know the start time. */ - const startMillliseconds = parseInt(moment(start).format('x'), 10); + const startMilliseconds = parseInt(moment(start).format('x'), 10); const endMilliseconds = parseInt(moment(start).add(step).format('x'), 10); - return endMilliseconds - startMillliseconds; + return endMilliseconds - startMilliseconds; } export function getPlaySliderParams(timestamps, timeGrain) { diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts index c3c08a23c0283..d06883a222f08 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts @@ -52,9 +52,9 @@ const config: ControlPanelConfig = { label: t('Stacked Style'), renderTrigger: true, choices: [ - ['stack', 'stack'], - ['stream', 'stream'], - ['expand', 'expand'], + ['stack', t('stack')], + ['stream', t('stream')], + ['expand', t('expand')], ], default: 'stack', description: '', diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js index 1b31acfd4468d..c0208b8e97865 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js @@ -38,7 +38,7 @@ const metadata = new ChartMetadata({ { url: example3, caption: t('Video game consoles') }, { url: example4, caption: t('Vehicle Types') }, ], - name: t('Area Chart'), + name: t('Area Chart (legacy)'), supportedAnnotationTypes: [ANNOTATION_TYPES.INTERVAL, ANNOTATION_TYPES.EVENT], tags: [ t('Aesthetic'), diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts index 91af47f1f7934..47fbbd442247b 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts @@ -19,6 +19,7 @@ import { t } from '@superset-ui/core'; import { ControlPanelConfig, + getStandardizedControls, sections, sharedControls, } from '@superset-ui/chart-controls'; @@ -63,7 +64,7 @@ const config: ControlPanelConfig = { controlState, ) || {}; timeserieslimitProps.value = state.controls?.limit?.value - ? controlState.value + ? controlState?.value : []; return timeserieslimitProps; }, @@ -122,10 +123,10 @@ const config: ControlPanelConfig = { timeSeriesSection[1], sections.annotations, ], - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, - groupby: formData.standardizedFormData.standardizedState.columns, + metrics: getStandardizedControls().popAllMetrics(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js index 073d533d38193..35a345fdbbaa4 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js @@ -32,7 +32,7 @@ const metadata = new ChartMetadata({ 'Visualize how a metric changes over time using bars. Add a group by column to visualize group level metrics and how they change over time.', ), exampleGallery: [{ url: example1 }, { url: example2 }, { url: example3 }], - name: t('Time-series Bar Chart'), + name: t('Time-series Bar Chart (legacy)'), supportedAnnotationTypes: [ANNOTATION_TYPES.INTERVAL, ANNOTATION_TYPES.EVENT], tags: [ t('Bar'), diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts index 33a4ea6bf02cf..773caa0fd3891 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts @@ -22,6 +22,7 @@ import { formatSelectOptions, D3_FORMAT_OPTIONS, sections, + getStandardizedControls, } from '@superset-ui/chart-controls'; import { showLegend, @@ -128,6 +129,14 @@ const config: ControlPanelConfig = { renderTrigger: false, }, }, + formDataOverrides: formData => ({ + ...formData, + series: getStandardizedControls().shiftColumn(), + entity: getStandardizedControls().shiftColumn(), + x: getStandardizedControls().shiftMetric(), + y: getStandardizedControls().shiftMetric(), + size: getStandardizedControls().shiftMetric(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/images/example.jpg b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/images/example.jpg new file mode 100644 index 0000000000000..b515822fa2c94 Binary files /dev/null and b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/images/example.jpg differ diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js index a97d9bd7b67d4..4b5a032ee6540 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js @@ -18,6 +18,7 @@ */ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from '../transformProps'; +import example from './images/example.jpg'; import thumbnail from './images/thumbnail.png'; import controlPanel from './controlPanel'; @@ -27,6 +28,7 @@ const metadata = new ChartMetadata({ description: t( 'Visualizes a metric across three dimensions of data in a single chart (X axis, Y axis, and bubble size). Bubbles from the same group can be showcased using bubble color.', ), + exampleGallery: [{ url: example }], name: t('Bubble Chart'), tags: [ t('Multi-Dimensions'), diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/images/example.jpg b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/images/example.jpg new file mode 100644 index 0000000000000..360d255eb5e35 Binary files /dev/null and b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/images/example.jpg differ diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js index 2626c42d2cdbb..4160d9277094e 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js @@ -18,6 +18,7 @@ */ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from '../transformProps'; +import example from './images/example.jpg'; import thumbnail from './images/thumbnail.png'; import controlPanel from './controlPanel'; @@ -27,6 +28,7 @@ const metadata = new ChartMetadata({ description: t( 'Showcases the progress of a single metric against a given target. The higher the fill, the closer the metric is to the target.', ), + exampleGallery: [{ url: example }], name: t('Bullet Chart'), tags: [t('Business'), t('Legacy'), t('Report'), t('nvd3')], thumbnail, diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts index db4a84fd476e3..fcae6dd397932 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts @@ -17,7 +17,11 @@ * under the License. */ import { t } from '@superset-ui/core'; -import { ControlPanelConfig, sections } from '@superset-ui/chart-controls'; +import { + ControlPanelConfig, + getStandardizedControls, + sections, +} from '@superset-ui/chart-controls'; import { xAxisLabel, yAxisLabel, @@ -62,6 +66,11 @@ const config: ControlPanelConfig = { timeSeriesSection[1], sections.annotations, ], + formDataOverrides: formData => ({ + ...formData, + groupby: getStandardizedControls().popAllColumns(), + metrics: getStandardizedControls().popAllMetrics(), + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/images/example.jpg b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/images/example.jpg new file mode 100644 index 0000000000000..375ef57a6aab9 Binary files /dev/null and b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/images/example.jpg differ diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js index e417e45e440b3..91d6bbb4f7743 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js @@ -19,6 +19,7 @@ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from '../transformProps'; import thumbnail from './images/thumbnail.png'; +import example from './images/example.jpg'; import controlPanel from './controlPanel'; const metadata = new ChartMetadata({ @@ -27,6 +28,7 @@ const metadata = new ChartMetadata({ description: t( 'Visualizes many different time-series objects in a single chart. This chart is being deprecated and we recommend using the Time-series Chart instead.', ), + exampleGallery: [{ url: example }], name: t('Time-series Percent Change'), tags: [ t('Legacy'), diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts index 5d526b43e38d9..58033938f1723 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts @@ -22,6 +22,7 @@ import { ControlPanelConfig, sections, sharedControls, + getStandardizedControls, } from '@superset-ui/chart-controls'; import { showLegend, @@ -133,14 +134,18 @@ const config: ControlPanelConfig = { rerender: ['groupby'], }, }, - denormalizeFormData: formData => { - const columns = - formData.standardizedFormData.standardizedState.columns.filter( - col => !ensureIsArray(formData.groupby).includes(col), + formDataOverrides: formData => { + const columns = getStandardizedControls().controls.columns.filter( + col => !ensureIsArray(formData.groupby).includes(col), + ); + getStandardizedControls().controls.columns = + getStandardizedControls().controls.columns.filter( + col => !columns.includes(col), ); + return { ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, + metrics: getStandardizedControls().popAllMetrics(), columns, }; }, diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js index 16b66c00b4c6d..09d289d694e80 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js @@ -16,7 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; +import { + t, + ChartMetadata, + ChartPlugin, + hasGenericChartAxes, +} from '@superset-ui/core'; import transformProps from '../transformProps'; import thumbnail from './images/thumbnail.png'; import example1 from './images/Bar_Chart.jpg'; @@ -35,7 +40,7 @@ const metadata = new ChartMetadata({ { url: example2, caption: 'Grouped style' }, { url: example3 }, ], - name: t('Bar Chart'), + name: hasGenericChartAxes ? t('Bar Chart (legacy)') : t('Bar Chart'), tags: [ t('Additive'), t('Bar'), diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/images/example.jpg b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/images/example.jpg new file mode 100644 index 0000000000000..d8a13f67e8203 Binary files /dev/null and b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/images/example.jpg differ diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js index a314c4650795a..218e45f9cd75b 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js @@ -19,6 +19,7 @@ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from '../transformProps'; import thumbnail from './images/thumbnail.png'; +import example from './images/example.jpg'; import controlPanel from './controlPanel'; const metadata = new ChartMetadata({ @@ -27,6 +28,7 @@ const metadata = new ChartMetadata({ description: t( 'Visualizes 2 metrics as line plots using the same x-axis. This chart is useful for comparing metrics across the same time range.', ), + exampleGallery: [{ url: example }], name: t('Dual Line Chart'), tags: [t('Legacy'), t('nvd3')], thumbnail, diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts index fa4738ebfd2e2..9662cc11d8388 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts @@ -17,7 +17,11 @@ * under the License. */ import { t } from '@superset-ui/core'; -import { ControlPanelConfig, sections } from '@superset-ui/chart-controls'; +import { + ControlPanelConfig, + sections, + getStandardizedControls, +} from '@superset-ui/chart-controls'; import { lineInterpolation, showBrush, @@ -96,10 +100,10 @@ const config: ControlPanelConfig = { default: 50000, }, }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, - groupby: formData.standardizedFormData.standardizedState.columns, + metrics: getStandardizedControls().popAllMetrics(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js index 3ec8f2c7fd06b..0d903ce3ca1b7 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js @@ -35,7 +35,7 @@ const metadata = new ChartMetadata({ { url: example2 }, { url: battery, caption: t('Battery level over time') }, ], - name: t('Line Chart'), + name: t('Line Chart (legacy)'), supportedAnnotationTypes: [ ANNOTATION_TYPES.TIME_SERIES, ANNOTATION_TYPES.INTERVAL, diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/images/example.jpg b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/images/example.jpg new file mode 100644 index 0000000000000..2ec8881c31b58 Binary files /dev/null and b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/images/example.jpg differ diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js index 3adcd73a289bb..ae7d194b90c94 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js @@ -19,6 +19,7 @@ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from '../transformProps'; import thumbnail from './images/thumbnail.png'; +import example from './images/example.jpg'; import controlPanel from './controlPanel'; const metadata = new ChartMetadata({ @@ -27,6 +28,7 @@ const metadata = new ChartMetadata({ description: t( 'Visualize two different time series using the same x-axis time range. This chart is being deprecated and we recommend using the Mixed Timeseries Chart instead!', ), + exampleGallery: [{ url: example }], name: t('Multiple Line Charts'), tags: [ t('Multi-Variables'), diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx index 3b53b2add08e3..a466b337425a0 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx @@ -23,7 +23,6 @@ import { t } from '@superset-ui/core'; import { ControlPanelSectionConfig, CustomControlItem, - formatSelectOptions, D3_TIME_FORMAT_OPTIONS, D3_FORMAT_DOCS, D3_FORMAT_OPTIONS, @@ -75,7 +74,15 @@ export const leftMargin: CustomControlItem = { freeForm: true, clearable: false, label: t('Left Margin'), - choices: formatSelectOptions(['auto', 50, 75, 100, 125, 150, 200]), + choices: [ + ['auto', t('auto')], + [50, '50'], + [75, '75'], + [100, '100'], + [125, '125'], + [150, '150'], + [200, '200'], + ], default: 'auto', renderTrigger: true, description: t( @@ -112,14 +119,14 @@ export const lineInterpolation: CustomControlItem = { type: 'SelectControl', label: t('Line Style'), renderTrigger: true, - choices: formatSelectOptions([ - 'linear', - 'basis', - 'cardinal', - 'monotone', - 'step-before', - 'step-after', - ]), + choices: [ + ['linear', t('linear')], + ['basis', t('basis')], + ['cardinal', t('cardinal')], + ['monotone', t('monotone')], + ['step-before', t('step-before')], + ['step-after', t('step-after')], + ], default: 'linear', description: t('Line interpolation as defined by d3.js'), }, @@ -134,9 +141,9 @@ export const showBrush: CustomControlItem = { clearable: false, default: 'auto', choices: [ - ['yes', 'Yes'], - ['no', 'No'], - ['auto', 'Auto'], + ['yes', t('Yes')], + ['no', t('No')], + ['auto', t('Auto')], ], description: t('Whether to display the time range interactive selector'), }, @@ -185,7 +192,15 @@ export const bottomMargin: CustomControlItem = { clearable: false, freeForm: true, label: t('Bottom Margin'), - choices: formatSelectOptions(['auto', 50, 75, 100, 125, 150, 200]), + choices: [ + ['auto', t('auto')], + [50, '50'], + [75, '75'], + [100, '100'], + [125, '125'], + [150, '150'], + [200, '200'], + ], default: 'auto', renderTrigger: true, description: t( @@ -199,7 +214,12 @@ export const xTicksLayout: CustomControlItem = { config: { type: 'SelectControl', label: t('X Tick Layout'), - choices: formatSelectOptions(['auto', 'flat', '45°', 'staggered']), + choices: [ + ['auto', t('auto')], + ['flat', t('flat')], + ['45°', '45°'], + ['staggered', t('staggered')], + ], default: 'auto', clearable: false, renderTrigger: true, @@ -378,13 +398,13 @@ export const timeSeriesSection: ControlPanelSectionConfig[] = [ type: 'SelectControl', label: t('Rolling Function'), default: 'None', - choices: formatSelectOptions([ - 'None', - 'mean', - 'sum', - 'std', - 'cumsum', - ]), + choices: [ + ['None', t('None')], + ['mean', t('mean')], + ['sum', t('sum')], + ['std', t('std')], + ['cumsum', t('cumsum')], + ], description: t( 'Defines a rolling window function to apply, works along ' + 'with the [Periods] text box', @@ -432,22 +452,22 @@ export const timeSeriesSection: ControlPanelSectionConfig[] = [ multi: true, freeForm: true, label: t('Time Shift'), - choices: formatSelectOptions([ - '1 day', - '1 week', - '28 days', - '30 days', - '52 weeks', - '1 year', - '104 weeks', - '2 years', - '156 weeks', - '3 years', - ]), + choices: [ + ['1 day', t('1 day')], + ['1 week', t('1 week')], + ['28 days', t('28 days')], + ['30 days', t('30 days')], + ['52 weeks', t('52 weeks')], + ['1 year', t('1 year')], + ['104 weeks', t('104 weeks')], + ['2 years', t('2 years')], + ['156 weeks', t('156 weeks')], + ['3 years', t('3 years')], + ], description: t( 'Overlay one or more timeseries from a ' + 'relative time period. Expects relative time deltas ' + - 'in natural language (example: 24 hours, 7 days, ' + + 'in natural language (example: 24 hours, 7 days, ' + '52 weeks, 365 days). Free text is supported.', ), }, @@ -461,10 +481,10 @@ export const timeSeriesSection: ControlPanelSectionConfig[] = [ label: t('Calculation type'), default: 'values', choices: [ - ['values', 'Actual Values'], - ['absolute', 'Difference'], - ['percentage', 'Percentage change'], - ['ratio', 'Ratio'], + ['values', t('Actual Values')], + ['absolute', t('Difference')], + ['percentage', t('Percentage change')], + ['ratio', t('Ratio')], ], description: t( 'How to display time shifts: as individual lines; as the ' + @@ -483,7 +503,14 @@ export const timeSeriesSection: ControlPanelSectionConfig[] = [ freeForm: true, label: t('Rule'), default: null, - choices: formatSelectOptions(['1T', '1H', '1D', '7D', '1M', '1AS']), + choices: [ + ['1T', t('1T')], + ['1H', t('1H')], + ['1D', t('1D')], + ['7D', t('7D')], + ['1M', t('1M')], + ['1AS', t('1AS')], + ], description: t('Pandas resample rule'), }, }, @@ -496,14 +523,14 @@ export const timeSeriesSection: ControlPanelSectionConfig[] = [ freeForm: true, label: t('Method'), default: null, - choices: formatSelectOptions([ - 'asfreq', - 'bfill', - 'ffill', - 'median', - 'mean', - 'sum', - ]), + choices: [ + ['asfreq', t('asfreq')], + ['bfill', t('bfill')], + ['ffill', t('ffill')], + ['median', t('median')], + ['mean', t('mean')], + ['sum', t('sum')], + ], description: t('Pandas resample method'), }, }, diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts index 9145d5a8429a2..ca4bf66062aec 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts @@ -19,7 +19,9 @@ import { t } from '@superset-ui/core'; import { ControlPanelConfig, + D3_FORMAT_DOCS, D3_FORMAT_OPTIONS, + D3_NUMBER_FORMAT_DESCRIPTION_PERCENTAGE_TEXT, } from '@superset-ui/chart-controls'; import { showLegend } from '../NVD3Controls'; @@ -48,12 +50,12 @@ const config: ControlPanelConfig = { default: 'key', renderTrigger: true, choices: [ - ['key', 'Category Name'], - ['value', 'Value'], - ['percent', 'Percentage'], - ['key_value', 'Category and Value'], - ['key_percent', 'Category and Percentage'], - ['key_value_percent', 'Category, Value and Percentage'], + ['key', t('Category Name')], + ['value', t('Value')], + ['percent', t('Percentage')], + ['key_value', t('Category and Value')], + ['key_percent', t('Category and Percentage')], + ['key_value_percent', t('Category, Value and Percentage')], ], description: t('What should be shown on the label?'), }, @@ -67,11 +69,7 @@ const config: ControlPanelConfig = { renderTrigger: true, default: 'SMART_NUMBER', choices: D3_FORMAT_OPTIONS, - description: `${t( - 'D3 format syntax: https://github.com/d3/d3-format', - )} ${t( - 'Only applies when the "Label Type" is not set to a percentage.', - )}`, + description: `${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_PERCENTAGE_TEXT}`, }, }, ], @@ -97,7 +95,7 @@ const config: ControlPanelConfig = { renderTrigger: true, default: true, description: t( - 'Whether to display the labels. Note that the label only displays when the the 5% ' + + 'Whether to display the labels. Note that the label only displays when the 5% ' + 'threshold.', ), }, diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts index 2d1f765c31f96..595d5d4b7211a 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts @@ -20,6 +20,7 @@ import { t } from '@superset-ui/core'; import { ControlPanelConfig, D3_FORMAT_OPTIONS, + getStandardizedControls, sections, } from '@superset-ui/chart-controls'; import { @@ -55,12 +56,12 @@ const config: ControlPanelConfig = { freeForm: true, clearable: false, choices: [ - ['AS', 'Year (freq=AS)'], - ['52W-MON', '52 weeks starting Monday (freq=52W-MON)'], - ['W-SUN', '1 week starting Sunday (freq=W-SUN)'], - ['W-MON', '1 week starting Monday (freq=W-MON)'], - ['D', 'Day (freq=D)'], - ['4W-MON', '4 weeks (freq=4W-MON)'], + ['AS', t('Year (freq=AS)')], + ['52W-MON', t('52 weeks starting Monday (freq=52W-MON)')], + ['W-SUN', t('1 week starting Sunday (freq=W-SUN)')], + ['W-MON', t('1 week starting Monday (freq=W-MON)')], + ['D', t('Day (freq=D)')], + ['4W-MON', t('4 weeks (freq=4W-MON)')], ], description: t( `The periodicity over which to pivot time. Users can provide @@ -123,6 +124,10 @@ const config: ControlPanelConfig = { clearable: false, }, }, + formDataOverrides: formData => ({ + ...formData, + metric: getStandardizedControls().shiftMetric, + }), }; export default config; diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/AnnotationTypes.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/AnnotationTypes.js index 384c29b3047f6..6a91617c5afcc 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/AnnotationTypes.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/AnnotationTypes.js @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ +import { t } from '@superset-ui/core'; + function extractTypes(metadata) { return Object.keys(metadata).reduce((prev, key) => { const result = prev; @@ -28,21 +30,21 @@ function extractTypes(metadata) { export const ANNOTATION_TYPES_METADATA = { FORMULA: { value: 'FORMULA', - label: 'Formula', + label: t('Formula'), }, EVENT: { value: 'EVENT', - label: 'Event', + label: t('Event'), supportNativeSource: true, }, INTERVAL: { value: 'INTERVAL', - label: 'Interval', + label: t('Interval'), supportNativeSource: true, }, TIME_SERIES: { value: 'TIME_SERIES', - label: 'Time Series', + label: t('Time Series'), }, }; diff --git a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/exploreUtils.js b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/exploreUtils.js index cb2561efb8667..c4c9c3264ec0d 100644 --- a/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/exploreUtils.js +++ b/superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/exploreUtils.js @@ -24,7 +24,7 @@ const MAX_URL_LENGTH = 8000; export function getURIDirectory(formData, endpointType = 'base') { // Building the directory part of the URI - let directory = '/superset/explore/'; + let directory = '/explore/'; if (['json', 'csv', 'query', 'results', 'samples'].includes(endpointType)) { directory = '/superset/explore_json/'; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/package.json b/superset-frontend/plugins/plugin-chart-echarts/package.json index 0c5cbcf595ae0..3326bad60ddc3 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/package.json +++ b/superset-frontend/plugins/plugin-chart-echarts/package.json @@ -27,7 +27,7 @@ }, "dependencies": { "d3-array": "^1.2.0", - "echarts": "^5.3.2", + "echarts": "^5.4.1", "lodash": "^4.17.15", "moment": "^2.26.0" }, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts index 94dd458305561..daacaa283ae28 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts @@ -21,13 +21,14 @@ import { ControlPanelConfig, D3_FORMAT_DOCS, D3_TIME_FORMAT_OPTIONS, + getStandardizedControls, sections, } from '@superset-ui/chart-controls'; import { headerFontSize, subheaderFontSize } from '../sharedControls'; export default { controlPanelSections: [ - sections.legacyTimeseriesTime, + sections.legacyRegularTime, { label: t('Query'), expanded: true, @@ -96,12 +97,8 @@ export default { label: t('Number format'), }, }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metric: formData.standardizedFormData.standardizedState.metrics[0], - }), - updateStandardizedState: (prevState, currState) => ({ - ...currState, - metrics: [currState.metrics[0], ...prevState.metrics.slice(1)], + metric: getStandardizedControls().shiftMetric(), }), } as ControlPanelConfig; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts index 3f45db74cfd95..75401411a8de7 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; +import { t, ChartMetadata, ChartPlugin, Behavior } from '@superset-ui/core'; import controlPanel from './controlPanel'; import transformProps from './transformProps'; import buildQuery from './buildQuery'; @@ -46,6 +46,7 @@ const metadata = new ChartMetadata({ t('Description'), ], thumbnail, + behaviors: [Behavior.DRILL_TO_DETAIL], }); export default class BigNumberTotalChartPlugin extends ChartPlugin< diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts index 23126739346cb..e690b1ef52bb9 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts @@ -23,11 +23,15 @@ import { extractTimegrain, QueryFormData, } from '@superset-ui/core'; -import { BigNumberTotalChartProps } from '../types'; +import { BigNumberTotalChartProps, BigNumberVizProps } from '../types'; import { getDateFormatter, parseMetricValue } from '../utils'; +import { Refs } from '../../types'; -export default function transformProps(chartProps: BigNumberTotalChartProps) { - const { width, height, queriesData, formData, rawFormData } = chartProps; +export default function transformProps( + chartProps: BigNumberTotalChartProps, +): BigNumberVizProps { + const { width, height, queriesData, formData, rawFormData, hooks } = + chartProps; const { headerFontSize, metric = 'value', @@ -37,6 +41,7 @@ export default function transformProps(chartProps: BigNumberTotalChartProps) { timeFormat, yAxisFormat, } = formData; + const refs: Refs = {}; const { data = [], coltypes = [] } = queriesData[0]; const granularity = extractTimegrain(rawFormData as QueryFormData); const metricName = getMetricLabel(metric); @@ -45,7 +50,7 @@ export default function transformProps(chartProps: BigNumberTotalChartProps) { data.length === 0 ? null : parseMetricValue(data[0][metricName]); let metricEntry; - if (chartProps.datasource && chartProps.datasource.metrics) { + if (chartProps.datasource?.metrics) { metricEntry = chartProps.datasource.metrics.find( metricItem => metricItem.metric_name === metric, ); @@ -64,6 +69,8 @@ export default function transformProps(chartProps: BigNumberTotalChartProps) { ? formatTime : getNumberFormatter(yAxisFormat ?? metricEntry?.d3format ?? undefined); + const { onContextMenu } = hooks; + return { width, height, @@ -72,5 +79,7 @@ export default function transformProps(chartProps: BigNumberTotalChartProps) { headerFontSize, subheaderFontSize, subheader: formattedSubheader, + onContextMenu, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx index d14cc7dcefa2f..669926d58ba8e 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx @@ -16,20 +16,19 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; +import React, { MouseEvent } from 'react'; import { t, getNumberFormatter, - NumberFormatter, smartDateVerboseFormatter, - TimeFormatter, computeMaxFontSize, BRAND_COLOR, styled, + BinaryQueryObjectFilterClause, } from '@superset-ui/core'; -import { EChartsCoreOption } from 'echarts'; import Echart from '../components/Echart'; -import { TimeSeriesDatum } from './types'; +import { BigNumberVizProps } from './types'; +import { EventHandlers } from '../types'; const defaultNumberFormatter = getNumberFormatter(); @@ -42,29 +41,7 @@ const PROPORTION = { TRENDLINE: 0.3, }; -type BigNumberVisProps = { - className?: string; - width: number; - height: number; - bigNumber?: number | null; - bigNumberFallback?: TimeSeriesDatum; - headerFormatter: NumberFormatter | TimeFormatter; - formatTime: TimeFormatter; - headerFontSize: number; - kickerFontSize: number; - subheader: string; - subheaderFontSize: number; - showTimestamp?: boolean; - showTrendLine?: boolean; - startYAxisAtZero?: boolean; - timeRangeFixed?: boolean; - timestamp?: number; - trendLineData?: TimeSeriesDatum[]; - mainColor: string; - echartOptions: EChartsCoreOption; -}; - -class BigNumberVis extends React.PureComponent<BigNumberVisProps> { +class BigNumberVis extends React.PureComponent<BigNumberVizProps> { static defaultProps = { className: '', headerFormatter: defaultNumberFormatter, @@ -99,7 +76,7 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps> { renderFallbackWarning() { const { bigNumberFallback, formatTime, showTimestamp } = this.props; - if (!bigNumberFallback || showTimestamp) return null; + if (!formatTime || !bigNumberFallback || showTimestamp) return null; return ( <span className="alert alert-warning" @@ -116,7 +93,13 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps> { renderKicker(maxHeight: number) { const { timestamp, showTimestamp, formatTime, width } = this.props; - if (!showTimestamp) return null; + if ( + !formatTime || + !showTimestamp || + typeof timestamp === 'string' || + typeof timestamp === 'boolean' + ) + return null; const text = timestamp === null ? '' : formatTime(timestamp); @@ -146,6 +129,7 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps> { renderHeader(maxHeight: number) { const { bigNumber, headerFormatter, width } = this.props; + // @ts-ignore const text = bigNumber === null ? t('No data') : headerFormatter(bigNumber); const container = this.createTemporaryContainer(); @@ -159,6 +143,13 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps> { }); container.remove(); + const onContextMenu = (e: MouseEvent<HTMLDivElement>) => { + if (this.props.onContextMenu) { + e.preventDefault(); + this.props.onContextMenu(e.nativeEvent.clientX, e.nativeEvent.clientY); + } + }; + return ( <div className="header-line" @@ -166,6 +157,7 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps> { fontSize, height: maxHeight, }} + onContextMenu={onContextMenu} > {text} </div> @@ -214,19 +206,48 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps> { } renderTrendline(maxHeight: number) { - const { width, trendLineData, echartOptions } = this.props; + const { width, trendLineData, echartOptions, refs } = this.props; // if can't find any non-null values, no point rendering the trendline if (!trendLineData?.some(d => d[1] !== null)) { return null; } + const eventHandlers: EventHandlers = { + contextmenu: eventParams => { + if (this.props.onContextMenu) { + eventParams.event.stop(); + const { data } = eventParams; + if (data) { + const pointerEvent = eventParams.event.event; + const filters: BinaryQueryObjectFilterClause[] = []; + filters.push({ + col: this.props.formData?.granularitySqla, + grain: this.props.formData?.timeGrainSqla, + op: '==', + val: data[0], + formattedVal: this.props.xValueFormatter?.(data[0]), + }); + this.props.onContextMenu( + pointerEvent.clientX, + pointerEvent.clientY, + filters, + ); + } + } + }, + }; + return ( - <Echart - width={Math.floor(width)} - height={maxHeight} - echartOptions={echartOptions} - /> + echartOptions && ( + <Echart + refs={refs} + width={Math.floor(width)} + height={maxHeight} + echartOptions={echartOptions} + eventHandlers={eventHandlers} + /> + ) ); } @@ -249,7 +270,9 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps> { <div className="text-container" style={{ height: allTextHeight }}> {this.renderFallbackWarning()} {this.renderKicker( - Math.ceil(kickerFontSize * (1 - PROPORTION.TRENDLINE) * height), + Math.ceil( + (kickerFontSize || 0) * (1 - PROPORTION.TRENDLINE) * height, + ), )} {this.renderHeader( Math.ceil(headerFontSize * (1 - PROPORTION.TRENDLINE) * height), @@ -268,7 +291,7 @@ class BigNumberVis extends React.PureComponent<BigNumberVisProps> { return ( <div className={className} style={{ height }}> {this.renderFallbackWarning()} - {this.renderKicker(kickerFontSize * height)} + {this.renderKicker((kickerFontSize || 0) * height)} {this.renderHeader(Math.ceil(headerFontSize * height))} {this.renderSubheader(Math.ceil(subheaderFontSize * height))} </div> @@ -283,6 +306,7 @@ export default styled(BigNumberVis)` display: flex; flex-direction: column; justify-content: center; + align-items: flex-start; &.no-trendline .subheader-line { padding-bottom: 0.3em; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/buildQuery.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/buildQuery.ts index de75b50838ad6..7a0ba462b88b2 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/buildQuery.ts @@ -18,7 +18,9 @@ */ import { buildQueryContext, - DTTM_ALIAS, + ensureIsArray, + getXAxisColumn, + isXAxisSet, QueryFormData, } from '@superset-ui/core'; import { @@ -29,25 +31,21 @@ import { } from '@superset-ui/chart-controls'; export default function buildQuery(formData: QueryFormData) { - return buildQueryContext(formData, baseQueryObject => { - const { x_axis } = formData; - const is_timeseries = x_axis === DTTM_ALIAS || !x_axis; - - return [ - { - ...baseQueryObject, - is_timeseries: true, - post_processing: [ - pivotOperator(formData, { - ...baseQueryObject, - index: x_axis, - is_timeseries, - }), - rollingWindowOperator(formData, baseQueryObject), - resampleOperator(formData, baseQueryObject), - flattenOperator(formData, baseQueryObject), - ], - }, - ]; - }); + return buildQueryContext(formData, baseQueryObject => [ + { + ...baseQueryObject, + columns: [ + ...(isXAxisSet(formData) + ? ensureIsArray(getXAxisColumn(formData)) + : []), + ], + ...(isXAxisSet(formData) ? {} : { is_timeseries: true }), + post_processing: [ + pivotOperator(formData, baseQueryObject), + rollingWindowOperator(formData, baseQueryObject), + resampleOperator(formData, baseQueryObject), + flattenOperator(formData, baseQueryObject), + ], + }, + ]); } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx index 0ea0a96229e85..81e6d2012820f 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx @@ -16,24 +16,30 @@ * specific language governing permissions and limitations * under the License. */ -import { smartDateFormatter, t } from '@superset-ui/core'; +import { hasGenericChartAxes, smartDateFormatter, t } from '@superset-ui/core'; import { ControlPanelConfig, D3_FORMAT_DOCS, D3_TIME_FORMAT_OPTIONS, - formatSelectOptions, + getStandardizedControls, sections, + temporalColumnMixin, } from '@superset-ui/chart-controls'; import React from 'react'; import { headerFontSize, subheaderFontSize } from '../sharedControls'; const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, + sections.genericTime, { label: t('Query'), expanded: true, - controlSetRows: [['metric'], ['adhoc_filters']], + controlSetRows: [ + [hasGenericChartAxes ? 'x_axis' : null], + [hasGenericChartAxes ? 'time_grain_sqla' : null], + ['metric'], + ['adhoc_filters'], + ], }, { label: t('Options'), @@ -172,13 +178,13 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Rolling Function'), default: 'None', - choices: formatSelectOptions([ - 'None', - 'mean', - 'sum', - 'std', - 'cumsum', - ]), + choices: [ + ['None', t('None')], + ['mean', t('mean')], + ['sum', t('sum')], + ['std', t('std')], + ['cumsum', t('cumsum')], + ], description: t( 'Defines a rolling window function to apply, works along ' + 'with the [Periods] text box', @@ -227,14 +233,14 @@ const config: ControlPanelConfig = { label: t('Rule'), default: null, choices: [ - ['1T', '1 minutely frequency'], - ['1H', '1 hourly frequency'], - ['1D', '1 calendar day frequency'], - ['7D', '7 calendar day frequency'], - ['1MS', '1 month start frequency'], - ['1M', '1 month end frequency'], - ['1AS', '1 year start frequency'], - ['1A', '1 year end frequency'], + ['1T', t('1 minutely frequency')], + ['1H', t('1 hourly frequency')], + ['1D', t('1 calendar day frequency')], + ['7D', t('7 calendar day frequency')], + ['1MS', t('1 month start frequency')], + ['1M', t('1 month end frequency')], + ['1AS', t('1 year start frequency')], + ['1A', t('1 year end frequency')], ], description: t('Pandas resample rule'), }, @@ -249,14 +255,14 @@ const config: ControlPanelConfig = { label: t('Fill method'), default: null, choices: [ - ['asfreq', 'Null imputation'], - ['zerofill', 'Zero imputation'], - ['linear', 'Linear interpolation'], - ['ffill', 'Forward values'], - ['bfill', 'Backward values'], - ['median', 'Median values'], - ['mean', 'Mean values'], - ['sum', 'Sum values'], + ['asfreq', t('Null imputation')], + ['zerofill', t('Zero imputation')], + ['linear', t('Linear interpolation')], + ['ffill', t('Forward values')], + ['bfill', t('Backward values')], + ['median', t('Median values')], + ['mean', t('Mean values')], + ['sum', t('Sum values')], ], description: t('Pandas resample method'), }, @@ -269,14 +275,14 @@ const config: ControlPanelConfig = { y_axis_format: { label: t('Number format'), }, + x_axis: { + label: t('TEMPORAL X-AXIS'), + ...temporalColumnMixin, + }, }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metric: formData.standardizedFormData.standardizedState.metrics[0], - }), - updateStandardizedState: (prevState, currState) => ({ - ...currState, - metrics: [currState.metrics[0], ...prevState.metrics.slice(1)], + metric: getStandardizedControls().shiftMetric(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts index e774db4824e06..8cd1d2d2881e4 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; +import { t, ChartMetadata, ChartPlugin, Behavior } from '@superset-ui/core'; import controlPanel from './controlPanel'; import transformProps from './transformProps'; import buildQuery from './buildQuery'; @@ -45,6 +45,7 @@ const metadata = new ChartMetadata({ t('Trend'), ], thumbnail, + behaviors: [Behavior.DRILL_TO_DETAIL], }); export default class BigNumberWithTrendlineChartPlugin extends ChartPlugin< diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts index 07ca77547b4ff..bd4553479e487 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts @@ -17,25 +17,27 @@ * under the License. */ import { - DTTM_ALIAS, extractTimegrain, getNumberFormatter, NumberFormats, - QueryFormData, GenericDataType, getMetricLabel, t, smartDateVerboseFormatter, NumberFormatter, TimeFormatter, + getXAxisLabel, } from '@superset-ui/core'; import { EChartsCoreOption, graphic } from 'echarts'; import { + BigNumberVizProps, BigNumberDatum, BigNumberWithTrendlineChartProps, TimeSeriesDatum, } from '../types'; import { getDateFormatter, parseMetricValue } from '../utils'; +import { getDefaultTooltip } from '../../utils/tooltip'; +import { Refs } from '../../types'; const defaultNumberFormatter = getNumberFormatter(); export function renderTooltipFactory( @@ -61,9 +63,17 @@ const formatPercentChange = getNumberFormatter( export default function transformProps( chartProps: BigNumberWithTrendlineChartProps, -) { - const { width, height, queriesData, formData, rawFormData, theme } = - chartProps; +): BigNumberVizProps { + const { + width, + height, + queriesData, + formData, + rawFormData, + theme, + hooks, + inContextMenu, + } = chartProps; const { colorPicker, compareLag: compareLag_, @@ -80,7 +90,7 @@ export default function transformProps( yAxisFormat, timeRangeFixed, } = formData; - const granularity = extractTimegrain(rawFormData as QueryFormData); + const granularity = extractTimegrain(rawFormData); const { data = [], colnames = [], @@ -88,6 +98,7 @@ export default function transformProps( from_dttm: fromDatetime, to_dttm: toDatetime, } = queriesData[0]; + const refs: Refs = {}; const metricName = getMetricLabel(metric); const compareLag = Number(compareLag_) || 0; let formattedSubheader = subheader; @@ -95,10 +106,11 @@ export default function transformProps( const { r, g, b } = colorPicker; const mainColor = `rgb(${r}, ${g}, ${b})`; - let trendLineData; + const xAxisLabel = getXAxisLabel(rawFormData) as string; + let trendLineData: TimeSeriesDatum[] | undefined; let percentChange = 0; let bigNumber = data.length === 0 ? null : data[0][metricName]; - let timestamp = data.length === 0 ? null : data[0][DTTM_ALIAS]; + let timestamp = data.length === 0 ? null : data[0][xAxisLabel]; let bigNumberFallback; const metricColtypeIndex = colnames.findIndex(name => name === metricName); @@ -107,7 +119,7 @@ export default function transformProps( if (data.length > 0) { const sortedData = (data as BigNumberDatum[]) - .map(d => [d[DTTM_ALIAS], parseMetricValue(d[metricName])]) + .map(d => [d[xAxisLabel], parseMetricValue(d[metricName])]) // sort in time descending order .sort((a, b) => (a[0] !== null && b[0] !== null ? b[0] - a[0] : 0)); @@ -136,6 +148,7 @@ export default function transformProps( } } sortedData.reverse(); + // @ts-ignore trendLineData = showTrendLine ? sortedData : undefined; } @@ -147,7 +160,7 @@ export default function transformProps( } let metricEntry; - if (chartProps.datasource && chartProps.datasource.metrics) { + if (chartProps.datasource?.metrics) { metricEntry = chartProps.datasource.metrics.find( metricEntry => metricEntry.metric_name === metric, ); @@ -187,6 +200,7 @@ export default function transformProps( type: 'line', smooth: true, symbol: 'circle', + symbolSize: 10, showSymbol: false, color: mainColor, areaStyle: { @@ -220,10 +234,9 @@ export default function transformProps( bottom: 0, }, tooltip: { - appendToBody: true, - show: true, + ...getDefaultTooltip(refs), + show: !inContextMenu, trigger: 'axis', - confine: true, formatter: renderTooltipFactory(formatTime, headerFormatter), }, aria: { @@ -234,14 +247,19 @@ export default function transformProps( }, } : {}; + + const { onContextMenu } = hooks; + return { width, height, bigNumber, + // @ts-ignore bigNumberFallback, className, headerFormatter, formatTime, + formData, headerFontSize, subheaderFontSize, mainColor, @@ -252,5 +270,8 @@ export default function transformProps( timestamp, trendLineData, echartOptions, + onContextMenu, + xValueFormatter: formatTime, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts index 49f5ea2bfd98f..90b852b01e4e8 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts @@ -17,12 +17,17 @@ * under the License. */ +import { EChartsCoreOption } from 'echarts'; import { + BinaryQueryObjectFilterClause, ChartDataResponseResult, - ChartProps, + DataRecordValue, + NumberFormatter, QueryFormData, QueryFormMetric, + TimeFormatter, } from '@superset-ui/core'; +import { BaseChartProps, Refs } from '../types'; export interface BigNumberDatum { [key: string]: number | null; @@ -43,15 +48,50 @@ export type BigNumberWithTrendlineFormData = BigNumberTotalFormData & { compareLag?: string | number; }; -export type BigNumberTotalChartProps = ChartProps & { - formData: BigNumberTotalFormData; - queriesData: (ChartDataResponseResult & { - data?: BigNumberDatum[]; - })[]; -}; +export interface BigNumberTotalChartDataResponseResult + extends ChartDataResponseResult { + data: BigNumberDatum[]; +} -export type BigNumberWithTrendlineChartProps = BigNumberTotalChartProps & { - formData: BigNumberWithTrendlineFormData; -}; +export type BigNumberTotalChartProps = + BaseChartProps<BigNumberTotalFormData> & { + formData: BigNumberTotalFormData; + queriesData: BigNumberTotalChartDataResponseResult[]; + }; + +export type BigNumberWithTrendlineChartProps = + BaseChartProps<BigNumberWithTrendlineFormData> & { + formData: BigNumberWithTrendlineFormData; + }; export type TimeSeriesDatum = [number, number | null]; + +export type BigNumberVizProps = { + className?: string; + width: number; + height: number; + bigNumber?: DataRecordValue; + bigNumberFallback?: TimeSeriesDatum; + headerFormatter: NumberFormatter | TimeFormatter; + formatTime?: TimeFormatter; + headerFontSize: number; + kickerFontSize?: number; + subheader: string; + subheaderFontSize: number; + showTimestamp?: boolean; + showTrendLine?: boolean; + startYAxisAtZero?: boolean; + timeRangeFixed?: boolean; + timestamp?: DataRecordValue; + trendLineData?: TimeSeriesDatum[]; + mainColor?: string; + echartOptions?: EChartsCoreOption; + onContextMenu?: ( + clientX: number, + clientY: number, + filters?: BinaryQueryObjectFilterClause[], + ) => void; + xValueFormatter?: TimeFormatter; + formData?: BigNumberWithTrendlineFormData; + refs: Refs; +}; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/EchartsBoxPlot.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/EchartsBoxPlot.tsx index f13396d096bcc..4c18f7f7d6205 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/EchartsBoxPlot.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/EchartsBoxPlot.tsx @@ -18,22 +18,24 @@ */ import React, { useCallback } from 'react'; import Echart from '../components/Echart'; -import { EventHandlers } from '../types'; +import { allEventHandlers } from '../utils/eventHandlers'; import { BoxPlotChartTransformedProps } from './types'; -export default function EchartsBoxPlot({ - height, - width, - echartOptions, - setDataMask, - labelMap, - groupby, - selectedValues, - formData, -}: BoxPlotChartTransformedProps) { +export default function EchartsBoxPlot(props: BoxPlotChartTransformedProps) { + const { + height, + width, + echartOptions, + setDataMask, + labelMap, + groupby, + selectedValues, + refs, + emitCrossFilters, + } = props; const handleChange = useCallback( (values: string[]) => { - if (!formData.emitFilter) { + if (!emitCrossFilters) { return; } @@ -67,20 +69,11 @@ export default function EchartsBoxPlot({ [groupby, labelMap, setDataMask, selectedValues], ); - const eventHandlers: EventHandlers = { - click: props => { - const { name } = props; - const values = Object.values(selectedValues); - if (values.includes(name)) { - handleChange(values.filter(v => v !== name)); - } else { - handleChange([name]); - } - }, - }; + const eventHandlers = allEventHandlers(props, handleChange); return ( <Echart + refs={refs} height={height} width={width} echartOptions={echartOptions} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/buildQuery.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/buildQuery.ts index 14ce144d61eab..03b9058c8a3b1 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/buildQuery.ts @@ -16,26 +16,44 @@ * specific language governing permissions and limitations * under the License. */ -import { buildQueryContext } from '@superset-ui/core'; +import { + AdhocColumn, + buildQueryContext, + ensureIsArray, + isPhysicalColumn, +} from '@superset-ui/core'; import { boxplotOperator } from '@superset-ui/chart-controls'; import { BoxPlotQueryFormData } from './types'; export default function buildQuery(formData: BoxPlotQueryFormData) { - const { columns = [], granularity_sqla, groupby = [] } = formData; - return buildQueryContext(formData, baseQueryObject => { - const distributionColumns: string[] = []; - // For now default to using the temporal column as distribution column. - // In the future this control should be made mandatory. - if (!columns.length && granularity_sqla) { - distributionColumns.push(granularity_sqla); - } - return [ - { - ...baseQueryObject, - columns: [...distributionColumns, ...columns, ...groupby], - series_columns: groupby, - post_processing: [boxplotOperator(formData, baseQueryObject)], - }, - ]; - }); + return buildQueryContext(formData, baseQueryObject => [ + { + ...baseQueryObject, + columns: [ + ...(ensureIsArray(formData.columns).length === 0 && + formData.granularity_sqla + ? [formData.granularity_sqla] // for backwards compatible: if columns control is empty and granularity_sqla was set, the time columns is default distributed column. + : ensureIsArray(formData.columns) + ).map(col => { + if ( + isPhysicalColumn(col) && + formData.time_grain_sqla && + formData?.temporal_columns_lookup?.[col] + ) { + return { + timeGrain: formData.time_grain_sqla, + columnType: 'BASE_AXIS', + sqlExpression: col, + label: col, + expressionType: 'SQL', + } as AdhocColumn; + } + return col; + }), + ...ensureIsArray(formData.groupby), + ], + series_columns: formData.groupby, + post_processing: [boxplotOperator(formData, baseQueryObject)], + }, + ]); } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts index b92c289bb43e0..da21e3cfefe3c 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts @@ -16,29 +16,67 @@ * specific language governing permissions and limitations * under the License. */ -import { ensureIsArray, t } from '@superset-ui/core'; +import { + ensureIsArray, + isAdhocColumn, + isPhysicalColumn, + t, + validateNonEmpty, +} from '@superset-ui/core'; import { D3_FORMAT_DOCS, + D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT, D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, - formatSelectOptions, sections, - emitFilterControl, ControlPanelConfig, + getStandardizedControls, + ControlState, + ControlPanelState, + getTemporalColumns, + sharedControls, } from '@superset-ui/chart-controls'; const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, + sections.legacyRegularTime, { label: t('Query'), expanded: true, controlSetRows: [ + ['columns'], + [ + { + name: 'time_grain_sqla', + config: { + ...sharedControls.time_grain_sqla, + visibility: ({ controls }) => { + const dttmLookup = Object.fromEntries( + ensureIsArray(controls?.columns?.options).map(option => [ + option.column_name, + option.is_dttm, + ]), + ); + + return ensureIsArray(controls?.columns.value) + .map(selection => { + if (isAdhocColumn(selection)) { + return true; + } + if (isPhysicalColumn(selection)) { + return !!dttmLookup[selection]; + } + return false; + }) + .some(Boolean); + }, + }, + }, + 'temporal_columns_lookup', + ], + ['groupby'], ['metrics'], ['adhoc_filters'], - emitFilterControl, - ['groupby'], - ['columns'], // TODO: this should be migrated to `series_columns` ['series_limit'], ['series_limit_metric'], [ @@ -53,12 +91,12 @@ const config: ControlPanelConfig = { description: t( 'Determines how whiskers and outliers are calculated.', ), - choices: formatSelectOptions([ - 'Tukey', - 'Min/max (no outliers)', - '2/98 percentiles', - '9/91 percentiles', - ]), + choices: [ + ['Tukey', t('Tukey')], + ['Min/max (no outliers)', t('Min/max (no outliers)')], + ['2/98 percentiles', t('2/98 percentiles')], + ['9/91 percentiles', t('9/91 percentiles')], + ], }, }, ], @@ -76,13 +114,13 @@ const config: ControlPanelConfig = { config: { type: 'SelectControl', label: t('X Tick Layout'), - choices: formatSelectOptions([ - 'auto', - 'flat', - '45°', - '90°', - 'staggered', - ]), + choices: [ + ['auto', t('auto')], + ['flat', t('flat')], + ['45°', '45°'], + ['90°', '90°'], + ['staggered', t('staggered')], + ], default: 'auto', clearable: false, renderTrigger: true, @@ -100,9 +138,7 @@ const config: ControlPanelConfig = { renderTrigger: true, default: 'SMART_NUMBER', choices: D3_FORMAT_OPTIONS, - description: `${t( - 'D3 format syntax: https://github.com/d3/d3-format', - )} ${t('Only applies when "Label Type" is set to show values.')}`, + description: `${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`, }, }, ], @@ -131,19 +167,35 @@ const config: ControlPanelConfig = { columns: { label: t('Distribute across'), multi: true, - description: t( - 'Columns to calculate distribution across. Defaults to temporal column if left empty.', - ), + description: t('Columns to calculate distribution across.'), + initialValue: ( + control: ControlState, + state: ControlPanelState | null, + ) => { + if ( + state && + (!control?.value || + (Array.isArray(control?.value) && control.value.length === 0)) + ) { + return [getTemporalColumns(state.datasource).defaultTemporalColumn]; + } + return control.value; + }, + validators: [validateNonEmpty], }, }, - denormalizeFormData: formData => { - const groupby = - formData.standardizedFormData.standardizedState.columns.filter( - col => !ensureIsArray(formData.columns).includes(col), + formDataOverrides: formData => { + const groupby = getStandardizedControls().controls.columns.filter( + col => !ensureIsArray(formData.columns).includes(col), + ); + getStandardizedControls().controls.columns = + getStandardizedControls().controls.columns.filter( + col => !groupby.includes(col), ); + return { ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, + metrics: getStandardizedControls().popAllMetrics(), groupby, }; }, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts index c97dffe5acf21..3c8620e9d86d1 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts @@ -44,7 +44,7 @@ export default class EchartsBoxPlotChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('./EchartsBoxPlot'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Distribution'), credits: ['https://echarts.apache.org'], description: t( diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts index 6f79ec6e274e1..54a1cbfd205ac 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts @@ -18,7 +18,6 @@ */ import { CategoricalColorNamespace, - DataRecordValue, getColumnLabel, getMetricLabel, getNumberFormatter, @@ -37,17 +36,27 @@ import { sanitizeHtml, } from '../utils/series'; import { convertInteger } from '../utils/convertInteger'; -import { defaultGrid, defaultTooltip, defaultYAxis } from '../defaults'; +import { defaultGrid, defaultYAxis } from '../defaults'; import { getPadding } from '../Timeseries/transformers'; import { OpacityEnum } from '../constants'; +import { getDefaultTooltip } from '../utils/tooltip'; +import { Refs } from '../types'; export default function transformProps( chartProps: EchartsBoxPlotChartProps, ): BoxPlotChartTransformedProps { - const { width, height, formData, hooks, filterState, queriesData } = - chartProps; + const { + width, + height, + formData, + hooks, + filterState, + queriesData, + inContextMenu, + emitCrossFilters, + } = chartProps; const { data = [] } = queriesData[0]; - const { setDataMask = () => {} } = hooks; + const { setDataMask = () => {}, onContextMenu } = hooks; const coltypeMapping = getColtypesMapping(queriesData[0]); const { colorScheme, @@ -56,7 +65,6 @@ export default function transformProps( numberFormat, dateFormat, xTicksLayout, - emitFilter, legendOrientation = 'top', xAxisTitle, yAxisTitle, @@ -65,6 +73,7 @@ export default function transformProps( yAxisTitlePosition, sliceId, } = formData as BoxPlotQueryFormData; + const refs: Refs = {}; const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const numberFormatter = getNumberFormatter(numberFormat); const metricLabels = metrics.map(getMetricLabel); @@ -130,6 +139,7 @@ export default function transformProps( type: 'scatter', data: outlierDatum.map(val => [name, val]), tooltip: { + ...getDefaultTooltip(refs), formatter: (param: { data: [string, number] }) => { const [outlierName, stats] = param.data; const headline = groupbyLabels.length @@ -149,21 +159,18 @@ export default function transformProps( ) .flat(2); - const labelMap = data.reduce( - (acc: Record<string, DataRecordValue[]>, datum) => { - const label = extractGroupbyLabel({ - datum, - groupby: groupbyLabels, - coltypeMapping, - timeFormatter: getTimeFormatter(dateFormat), - }); - return { - ...acc, - [label]: groupbyLabels.map(col => datum[col]), - }; - }, - {}, - ); + const labelMap = data.reduce((acc: Record<string, string[]>, datum) => { + const label = extractGroupbyLabel({ + datum, + groupby: groupbyLabels, + coltypeMapping, + timeFormatter: getTimeFormatter(dateFormat), + }); + return { + ...acc, + [label]: groupbyLabels.map(col => datum[col] as string), + }; + }, {}); const selectedValues = (filterState.selectedValues || []).reduce( (acc: Record<string, number>, selectedValue: string) => { @@ -191,6 +198,7 @@ export default function transformProps( type: 'boxplot', data: transformedData, tooltip: { + ...getDefaultTooltip(refs), formatter: (param: CallbackDataParams) => { // @ts-ignore const { @@ -267,7 +275,8 @@ export default function transformProps( nameLocation: yAxisTitlePosition === 'Left' ? 'middle' : 'end', }, tooltip: { - ...defaultTooltip, + ...getDefaultTooltip(refs), + show: !inContextMenu, trigger: 'item', axisPointer: { type: 'shadow', @@ -282,9 +291,11 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, + emitCrossFilters, labelMap, groupby, selectedValues, + onContextMenu, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/types.ts index 005d2a79f0a27..6cdc57a26de01 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/types.ts @@ -16,23 +16,21 @@ * specific language governing permissions and limitations * under the License. */ +import { QueryFormData } from '@superset-ui/core'; import { - ChartDataResponseResult, - ChartProps, - DataRecordValue, - QueryFormColumn, - QueryFormData, - SetDataMaskHook, -} from '@superset-ui/core'; -import { EChartsCoreOption } from 'echarts'; -import { EchartsTitleFormData, DEFAULT_TITLE_FORM_DATA } from '../types'; + BaseChartProps, + BaseTransformedProps, + ContextMenuTransformedProps, + CrossFilterTransformedProps, + TitleFormData, +} from '../types'; +import { DEFAULT_TITLE_FORM_DATA } from '../constants'; export type BoxPlotQueryFormData = QueryFormData & { numberFormat?: string; whiskerOptions?: BoxPlotFormDataWhiskerOptions; xTickLayout?: BoxPlotFormXTickLayout; - emitFilter: boolean; -} & EchartsTitleFormData; +} & TitleFormData; export type BoxPlotFormDataWhiskerOptions = | 'Tukey' @@ -49,24 +47,15 @@ export type BoxPlotFormXTickLayout = // @ts-ignore export const DEFAULT_FORM_DATA: BoxPlotQueryFormData = { - emitFilter: false, ...DEFAULT_TITLE_FORM_DATA, }; export interface EchartsBoxPlotChartProps - extends ChartProps<BoxPlotQueryFormData> { + extends BaseChartProps<BoxPlotQueryFormData> { formData: BoxPlotQueryFormData; - queriesData: ChartDataResponseResult[]; } -export interface BoxPlotChartTransformedProps { - formData: BoxPlotQueryFormData; - height: number; - width: number; - echartOptions: EChartsCoreOption; - emitFilter: boolean; - setDataMask: SetDataMaskHook; - labelMap: Record<string, DataRecordValue[]>; - groupby: QueryFormColumn[]; - selectedValues: Record<number, string>; -} +export type BoxPlotChartTransformedProps = + BaseTransformedProps<BoxPlotQueryFormData> & + CrossFilterTransformedProps & + ContextMenuTransformedProps; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/EchartsFunnel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/EchartsFunnel.tsx index 7b157dc8e0f23..88ccae8ecc801 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/EchartsFunnel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/EchartsFunnel.tsx @@ -19,21 +19,23 @@ import React, { useCallback } from 'react'; import { FunnelChartTransformedProps } from './types'; import Echart from '../components/Echart'; -import { EventHandlers } from '../types'; +import { allEventHandlers } from '../utils/eventHandlers'; -export default function EchartsFunnel({ - height, - width, - echartOptions, - setDataMask, - labelMap, - groupby, - selectedValues, - formData, -}: FunnelChartTransformedProps) { +export default function EchartsFunnel(props: FunnelChartTransformedProps) { + const { + height, + width, + echartOptions, + setDataMask, + labelMap, + groupby, + selectedValues, + emitCrossFilters, + refs, + } = props; const handleChange = useCallback( (values: string[]) => { - if (!formData.emitFilter) { + if (!emitCrossFilters) { return; } @@ -67,20 +69,11 @@ export default function EchartsFunnel({ [groupby, labelMap, setDataMask, selectedValues], ); - const eventHandlers: EventHandlers = { - click: props => { - const { name } = props; - const values = Object.values(selectedValues); - if (values.includes(name)) { - handleChange(values.filter(v => v !== name)); - } else { - handleChange([name]); - } - }, - }; + const eventHandlers = allEventHandlers(props, handleChange); return ( <Echart + refs={refs} height={height} width={width} echartOptions={echartOptions} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx index b23cf2ed97939..203b86e219cc5 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx @@ -21,10 +21,12 @@ import { t } from '@superset-ui/core'; import { ControlPanelConfig, D3_FORMAT_OPTIONS, + D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT, sections, sharedControls, ControlStateMapping, - emitFilterControl, + getStandardizedControls, + D3_FORMAT_DOCS, } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA, EchartsFunnelLabelTypeType } from './types'; import { legendSection } from '../controls'; @@ -44,7 +46,6 @@ const config: ControlPanelConfig = { ['groupby'], ['metric'], ['adhoc_filters'], - emitFilterControl, [ { name: 'row_limit', @@ -86,17 +87,17 @@ const config: ControlPanelConfig = { default: labelType, renderTrigger: true, choices: [ - [EchartsFunnelLabelTypeType.Key, 'Category Name'], - [EchartsFunnelLabelTypeType.Value, 'Value'], - [EchartsFunnelLabelTypeType.Percent, 'Percentage'], - [EchartsFunnelLabelTypeType.KeyValue, 'Category and Value'], + [EchartsFunnelLabelTypeType.Key, t('Category Name')], + [EchartsFunnelLabelTypeType.Value, t('Value')], + [EchartsFunnelLabelTypeType.Percent, t('Percentage')], + [EchartsFunnelLabelTypeType.KeyValue, t('Category and Value')], [ EchartsFunnelLabelTypeType.KeyPercent, - 'Category and Percentage', + t('Category and Percentage'), ], [ EchartsFunnelLabelTypeType.KeyValuePercent, - 'Category, Value and Percentage', + t('Category, Value and Percentage'), ], ], description: t('What should be shown on the label?'), @@ -113,9 +114,7 @@ const config: ControlPanelConfig = { renderTrigger: true, default: numberFormat, choices: D3_FORMAT_OPTIONS, - description: `${t( - 'D3 format syntax: https://github.com/d3/d3-format', - )} ${t('Only applies when "Label Type" is set to show values.')}`, + description: `${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`, }, }, ], @@ -143,14 +142,10 @@ const config: ControlPanelConfig = { }, }; }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metric: formData.standardizedFormData.standardizedState.metrics[0], - groupby: formData.standardizedFormData.standardizedState.columns, - }), - updateStandardizedState: (prevState, currState) => ({ - ...currState, - metrics: [currState.metrics[0], ...prevState.metrics.slice(1)], + metric: getStandardizedControls().shiftMetric(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/images/example.jpg b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/images/example.jpg new file mode 100644 index 0000000000000..43f648cbac6c5 Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/images/example.jpg differ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts index a483262419bb2..742b92151a6d5 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts @@ -21,6 +21,7 @@ import buildQuery from './buildQuery'; import controlPanel from './controlPanel'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example from './images/example.jpg'; import { EchartsFunnelChartProps, EchartsFunnelFormData } from './types'; export default class EchartsFunnelChartPlugin extends ChartPlugin< @@ -43,12 +44,13 @@ export default class EchartsFunnelChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('./EchartsFunnel'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('KPI'), credits: ['https://echarts.apache.org'], description: t( 'Showcases how a metric changes as the funnel progresses. This classic chart is useful for visualizing drop-off between stages in a pipeline or lifecycle.', ), + exampleGallery: [{ url: example }], name: t('Funnel Chart'), tags: [ t('Business'), diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts index 3d0b279cc12fd..282bc42381cab 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts @@ -18,7 +18,6 @@ */ import { CategoricalColorNamespace, - DataRecordValue, DataRecord, getMetricLabel, getNumberFormatter, @@ -35,15 +34,16 @@ import { EchartsFunnelLabelTypeType, FunnelChartTransformedProps, } from './types'; -import { DEFAULT_LEGEND_FORM_DATA } from '../types'; import { extractGroupbyLabel, getChartPadding, getLegendProps, sanitizeHtml, } from '../utils/series'; -import { defaultGrid, defaultTooltip } from '../defaults'; -import { OpacityEnum } from '../constants'; +import { defaultGrid } from '../defaults'; +import { OpacityEnum, DEFAULT_LEGEND_FORM_DATA } from '../constants'; +import { getDefaultTooltip } from '../utils/tooltip'; +import { Refs } from '../types'; const percentFormatter = getNumberFormatter(NumberFormats.PERCENT_2_POINT); @@ -83,8 +83,17 @@ export function formatFunnelLabel({ export default function transformProps( chartProps: EchartsFunnelChartProps, ): FunnelChartTransformedProps { - const { formData, height, hooks, filterState, queriesData, width, theme } = - chartProps; + const { + formData, + height, + hooks, + filterState, + queriesData, + width, + theme, + inContextMenu, + emitCrossFilters, + } = chartProps; const data: DataRecord[] = queriesData[0].data || []; const { @@ -102,34 +111,31 @@ export default function transformProps( numberFormat, showLabels, showLegend, - emitFilter, sliceId, }: EchartsFunnelFormData = { ...DEFAULT_LEGEND_FORM_DATA, ...DEFAULT_FUNNEL_FORM_DATA, ...formData, }; + const refs: Refs = {}; const metricLabel = getMetricLabel(metric); const groupbyLabels = groupby.map(getColumnLabel); const keys = data.map(datum => extractGroupbyLabel({ datum, groupby: groupbyLabels, coltypeMapping: {} }), ); - const labelMap = data.reduce( - (acc: Record<string, DataRecordValue[]>, datum) => { - const label = extractGroupbyLabel({ - datum, - groupby: groupbyLabels, - coltypeMapping: {}, - }); - return { - ...acc, - [label]: groupbyLabels.map(col => datum[col]), - }; - }, - {}, - ); + const labelMap = data.reduce((acc: Record<string, string[]>, datum) => { + const label = extractGroupbyLabel({ + datum, + groupby: groupbyLabels, + coltypeMapping: {}, + }); + return { + ...acc, + [label]: groupbyLabels.map(col => datum[col] as string), + }; + }, {}); - const { setDataMask = () => {} } = hooks; + const { setDataMask = () => {}, onContextMenu } = hooks; const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const numberFormatter = getNumberFormatter(numberFormat); @@ -209,7 +215,8 @@ export default function transformProps( ...defaultGrid, }, tooltip: { - ...defaultTooltip, + ...getDefaultTooltip(refs), + show: !inContextMenu, trigger: 'item', formatter: (params: any) => formatFunnelLabel({ @@ -231,9 +238,11 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, + emitCrossFilters, labelMap, groupby, selectedValues, + onContextMenu, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/types.ts index 398fa40d57fb3..15adbc208041c 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/types.ts @@ -16,24 +16,20 @@ * specific language governing permissions and limitations * under the License. */ -import { EChartsCoreOption } from 'echarts'; +import { QueryFormData } from '@superset-ui/core'; import { - ChartDataResponseResult, - ChartProps, - DataRecordValue, - QueryFormColumn, - QueryFormData, - SetDataMaskHook, -} from '@superset-ui/core'; -import { - DEFAULT_LEGEND_FORM_DATA, - EchartsLegendFormData, + BaseChartProps, + BaseTransformedProps, + ContextMenuTransformedProps, + CrossFilterTransformedProps, + LegendFormData, LegendOrientation, LegendType, } from '../types'; +import { DEFAULT_LEGEND_FORM_DATA } from '../constants'; export type EchartsFunnelFormData = QueryFormData & - EchartsLegendFormData & { + LegendFormData & { colorScheme?: string; groupby: QueryFormData[]; labelLine: boolean; @@ -44,7 +40,6 @@ export type EchartsFunnelFormData = QueryFormData & gap: number; sort: 'descending' | 'ascending' | 'none' | undefined; orient: 'vertical' | 'horizontal' | undefined; - emitFilter: boolean; }; export enum EchartsFunnelLabelTypeType { @@ -57,9 +52,8 @@ export enum EchartsFunnelLabelTypeType { } export interface EchartsFunnelChartProps - extends ChartProps<EchartsFunnelFormData> { + extends BaseChartProps<EchartsFunnelFormData> { formData: EchartsFunnelFormData; - queriesData: ChartDataResponseResult[]; } // @ts-ignore @@ -75,17 +69,9 @@ export const DEFAULT_FORM_DATA: EchartsFunnelFormData = { sort: 'descending', orient: 'vertical', gap: 0, - emitFilter: false, }; -export interface FunnelChartTransformedProps { - formData: EchartsFunnelFormData; - height: number; - width: number; - echartOptions: EChartsCoreOption; - emitFilter: boolean; - setDataMask: SetDataMaskHook; - labelMap: Record<string, DataRecordValue[]>; - groupby: QueryFormColumn[]; - selectedValues: Record<number, string>; -} +export type FunnelChartTransformedProps = + BaseTransformedProps<EchartsFunnelFormData> & + CrossFilterTransformedProps & + ContextMenuTransformedProps; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx index 731aadded8394..8c4ca420d90b8 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx @@ -19,21 +19,23 @@ import React, { useCallback } from 'react'; import { GaugeChartTransformedProps } from './types'; import Echart from '../components/Echart'; -import { EventHandlers } from '../types'; +import { allEventHandlers } from '../utils/eventHandlers'; -export default function EchartsGauge({ - height, - width, - echartOptions, - setDataMask, - labelMap, - groupby, - selectedValues, - formData: { emitFilter }, -}: GaugeChartTransformedProps) { +export default function EchartsGauge(props: GaugeChartTransformedProps) { + const { + height, + width, + echartOptions, + setDataMask, + labelMap, + groupby, + selectedValues, + emitCrossFilters, + refs, + } = props; const handleChange = useCallback( (values: string[]) => { - if (!emitFilter) { + if (!emitCrossFilters) { return; } @@ -67,20 +69,11 @@ export default function EchartsGauge({ [groupby, labelMap, setDataMask, selectedValues], ); - const eventHandlers: EventHandlers = { - click: props => { - const { name } = props; - const values = Object.values(selectedValues); - if (values.includes(name)) { - handleChange(values.filter(v => v !== name)); - } else { - handleChange([name]); - } - }, - }; + const eventHandlers = allEventHandlers(props, handleChange); return ( <Echart + refs={refs} height={height} width={width} echartOptions={echartOptions} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/buildQuery.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/buildQuery.ts index 7d070932f6eda..8b47fb5e725cc 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/buildQuery.ts @@ -23,7 +23,6 @@ export default function buildQuery(formData: QueryFormData) { return buildQueryContext(formData, baseQueryObject => [ { ...baseQueryObject, - groupby: formData.groupby || [], ...(sort_by_metric && { orderby: [[metric, false]] }), }, ]); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx index 28d358da99dc3..1af718a989b1c 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx @@ -23,7 +23,7 @@ import { ControlPanelConfig, D3_FORMAT_OPTIONS, sections, - emitFilterControl, + getStandardizedControls, } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA } from './types'; @@ -45,7 +45,6 @@ const config: ControlPanelConfig = { ], ['metric'], ['adhoc_filters'], - emitFilterControl, [ { name: 'row_limit', @@ -306,14 +305,10 @@ const config: ControlPanelConfig = { ], }, ], - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metric: formData.standardizedFormData.standardizedState.metrics[0], - groupby: formData.standardizedFormData.standardizedState.columns, - }), - updateStandardizedState: (prevState, currState) => ({ - ...currState, - metrics: [currState.metrics[0], ...prevState.metrics.slice(1)], + metric: getStandardizedControls().shiftMetric(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/images/example1.jpg b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/images/example1.jpg new file mode 100644 index 0000000000000..0ffad121c93c6 Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/images/example1.jpg differ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/images/example2.jpg b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/images/example2.jpg new file mode 100644 index 0000000000000..8414ea66ce45b Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/images/example2.jpg differ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts index 16a8b6a6cca53..15de1cd9bee32 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts @@ -20,6 +20,8 @@ import { t, ChartMetadata, ChartPlugin, Behavior } from '@superset-ui/core'; import controlPanel from './controlPanel'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example1 from './images/example1.jpg'; +import example2 from './images/example2.jpg'; import buildQuery from './buildQuery'; import { EchartsGaugeChartProps, EchartsGaugeFormData } from './types'; @@ -33,12 +35,13 @@ export default class EchartsGaugeChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('./EchartsGauge'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('KPI'), credits: ['https://echarts.apache.org'], description: t( 'Uses a gauge to showcase progress of a metric towards a target. The position of the dial represents the progress and the terminal value in the gauge represents the target value.', ), + exampleGallery: [{ url: example1 }, { url: example2 }], name: t('Gauge Chart'), tags: [ t('Multi-Variables'), diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts index 996164222fa3a..b2e31c3cc1885 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts @@ -23,7 +23,6 @@ import { DataRecord, getNumberFormatter, getMetricLabel, - DataRecordValue, getColumnLabel, } from '@superset-ui/core'; import { EChartsCoreOption, GaugeSeriesOption } from 'echarts'; @@ -45,6 +44,8 @@ import { FONT_SIZE_MULTIPLIERS, } from './constants'; import { OpacityEnum } from '../constants'; +import { getDefaultTooltip } from '../utils/tooltip'; +import { Refs } from '../types'; const setIntervalBoundsAndColors = ( intervals: string, @@ -90,8 +91,16 @@ const calculateMax = (data: GaugeDataItemOption[]) => export default function transformProps( chartProps: EchartsGaugeChartProps, ): GaugeChartTransformedProps { - const { width, height, formData, queriesData, hooks, filterState, theme } = - chartProps; + const { + width, + height, + formData, + queriesData, + hooks, + filterState, + theme, + emitCrossFilters, + } = chartProps; const gaugeSeriesOptions = defaultGaugeSeriesOption(theme); @@ -116,9 +125,9 @@ export default function transformProps( intervals, intervalColorIndices, valueFormatter, - emitFilter, sliceId, }: EchartsGaugeFormData = { ...DEFAULT_GAUGE_FORM_DATA, ...formData }; + const refs: Refs = {}; const data = (queriesData[0]?.data || []) as DataRecord[]; const numberFormatter = getNumberFormatter(numberFormat); const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); @@ -132,7 +141,7 @@ export default function transformProps( FONT_SIZE_MULTIPLIERS.titleOffsetFromTitle * fontSize; const detailOffsetFromTitle = FONT_SIZE_MULTIPLIERS.detailOffsetFromTitle * fontSize; - const columnsLabelMap = new Map<string, DataRecordValue[]>(); + const columnsLabelMap = new Map<string, string[]>(); const transformedData: GaugeDataItemOption[] = data.map( (data_point, index) => { @@ -141,7 +150,7 @@ export default function transformProps( .join(', '); columnsLabelMap.set( name, - groupbyLabels.map(col => data_point[col]), + groupbyLabels.map(col => data_point[col] as string), ); let item: GaugeDataItemOption = { value: data_point[getMetricLabel(metric as QueryFormMetric)] as number, @@ -190,7 +199,7 @@ export default function transformProps( }, ); - const { setDataMask = () => {} } = hooks; + const { setDataMask = () => {}, onContextMenu } = hooks; const min = minVal ?? calculateMin(transformedData); const max = maxVal ?? calculateMax(transformedData); @@ -259,6 +268,7 @@ export default function transformProps( color: gaugeSeriesOptions.detail?.color, }; const tooltip = { + ...getDefaultTooltip(refs), formatter: (params: CallbackDataParams) => { const { name, value } = params; return `${name} : ${formatValue(value as number)}`; @@ -301,6 +311,7 @@ export default function transformProps( axisTick, pointer, detail, + // @ts-ignore tooltip, radius: Math.min(width, height) / 2 - axisLabelDistance - axisTickDistance, @@ -311,7 +322,7 @@ export default function transformProps( const echartOptions: EChartsCoreOption = { tooltip: { - appendToBody: true, + ...getDefaultTooltip(refs), trigger: 'item', }, series, @@ -323,9 +334,11 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, + emitCrossFilters, labelMap: Object.fromEntries(columnsLabelMap), groupby, selectedValues: filterState.selectedValues || [], + onContextMenu, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts index d72bb283f99c0..02cda2db7f641 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts @@ -16,13 +16,14 @@ * specific language governing permissions and limitations * under the License. */ +import { QueryFormColumn, QueryFormData } from '@superset-ui/core'; import { - ChartDataResponseResult, - ChartProps, - QueryFormColumn, - QueryFormData, -} from '@superset-ui/core'; -import { DEFAULT_LEGEND_FORM_DATA, EChartTransformedProps } from '../types'; + BaseChartProps, + BaseTransformedProps, + ContextMenuTransformedProps, + CrossFilterTransformedProps, +} from '../types'; +import { DEFAULT_LEGEND_FORM_DATA } from '../constants'; export type AxisTickLineStyle = { width: number; @@ -51,7 +52,6 @@ export type EchartsGaugeFormData = QueryFormData & { intervals: string; intervalColorIndices: string; valueFormatter: string; - emitFilter: boolean; }; export const DEFAULT_FORM_DATA: Partial<EchartsGaugeFormData> = { @@ -75,14 +75,14 @@ export const DEFAULT_FORM_DATA: Partial<EchartsGaugeFormData> = { intervals: '', intervalColorIndices: '', valueFormatter: '{value}', - emitFilter: false, }; export interface EchartsGaugeChartProps - extends ChartProps<EchartsGaugeFormData> { + extends BaseChartProps<EchartsGaugeFormData> { formData: EchartsGaugeFormData; - queriesData: ChartDataResponseResult[]; } export type GaugeChartTransformedProps = - EChartTransformedProps<EchartsGaugeFormData>; + BaseTransformedProps<EchartsGaugeFormData> & + ContextMenuTransformedProps & + CrossFilterTransformedProps; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/EchartsGraph.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/EchartsGraph.tsx index 9b42c6e553576..4f83d1bcaf578 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/EchartsGraph.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/EchartsGraph.tsx @@ -17,13 +17,63 @@ * under the License. */ import React from 'react'; -import { EchartsProps } from '../types'; +import { BinaryQueryObjectFilterClause } from '@superset-ui/core'; +import { EventHandlers } from '../types'; import Echart from '../components/Echart'; +import { GraphChartTransformedProps } from './types'; + +type Event = { + name: string; + event: { stop: () => void; event: PointerEvent }; + data: { source: string; target: string }; +}; export default function EchartsGraph({ height, width, echartOptions, -}: EchartsProps) { - return <Echart height={height} width={width} echartOptions={echartOptions} />; + formData, + onContextMenu, + refs, +}: GraphChartTransformedProps) { + const eventHandlers: EventHandlers = { + contextmenu: (e: Event) => { + if (onContextMenu) { + e.event.stop(); + const pointerEvent = e.event.event; + const data = (echartOptions as any).series[0].data as { + id: string; + name: string; + }[]; + const sourceValue = data.find(item => item.id === e.data.source)?.name; + const targetValue = data.find(item => item.id === e.data.target)?.name; + if (sourceValue && targetValue) { + const filters: BinaryQueryObjectFilterClause[] = [ + { + col: formData.source, + op: '==', + val: sourceValue, + formattedVal: sourceValue, + }, + { + col: formData.target, + op: '==', + val: targetValue, + formattedVal: targetValue, + }, + ]; + onContextMenu(pointerEvent.clientX, pointerEvent.clientY, filters); + } + } + }, + }; + return ( + <Echart + refs={refs} + height={height} + width={width} + echartOptions={echartOptions} + eventHandlers={eventHandlers} + /> + ); } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx index 218b1d0335ea7..fef948f5a6665 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx @@ -20,6 +20,7 @@ import React from 'react'; import { t } from '@superset-ui/core'; import { ControlPanelConfig, + getStandardizedControls, sections, sharedControls, } from '@superset-ui/chart-controls'; @@ -320,13 +321,9 @@ const controlPanel: ControlPanelConfig = { ], }, ], - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metric: formData.standardizedFormData.standardizedState.metrics[0], - }), - updateStandardizedState: (prevState, currState) => ({ - ...currState, - metrics: [currState.metrics[0], ...prevState.metrics.slice(1)], + metric: getStandardizedControls().popAllMetrics(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/images/example.jpg b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/images/example.jpg new file mode 100644 index 0000000000000..53aa9cfafc57f Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/images/example.jpg differ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts index b354b61a2fac6..621e063d84a39 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts @@ -16,10 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; +import { t, ChartMetadata, ChartPlugin, Behavior } from '@superset-ui/core'; import controlPanel from './controlPanel'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example from './images/example.jpg'; import buildQuery from './buildQuery'; export default class EchartsGraphChartPlugin extends ChartPlugin { @@ -34,6 +35,7 @@ export default class EchartsGraphChartPlugin extends ChartPlugin { description: t( 'Displays connections between entities in a graph structure. Useful for mapping relationships and showing which nodes are important in a network. Graph charts can be configured to be force-directed or circulate. If your data has a geospatial component, try the deck.gl Arc chart.', ), + exampleGallery: [{ url: example }], name: t('Graph Chart'), tags: [ t('Aesthetic'), @@ -46,6 +48,7 @@ export default class EchartsGraphChartPlugin extends ChartPlugin { t('Transformable'), ], thumbnail, + behaviors: [Behavior.DRILL_TO_DETAIL], }), transformProps, }); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/transformProps.ts index 905ecbfa8ebdb..593b02907dfbb 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/transformProps.ts @@ -18,7 +18,6 @@ */ import { CategoricalColorNamespace, - ChartProps, getMetricLabel, DataRecord, DataRecordValue, @@ -31,10 +30,13 @@ import { EChartGraphNode, DEFAULT_FORM_DATA as DEFAULT_GRAPH_FORM_DATA, EdgeSymbol, + GraphChartTransformedProps, + EchartsGraphChartProps, } from './types'; import { DEFAULT_GRAPH_SERIES_OPTION } from './constants'; -import { EchartsProps } from '../types'; import { getChartPadding, getLegendProps, sanitizeHtml } from '../utils/series'; +import { getDefaultTooltip } from '../utils/tooltip'; +import { Refs } from '../types'; type EdgeWithStyles = GraphEdgeItemOption & { lineStyle: Exclude<GraphEdgeItemOption['lineStyle'], undefined>; @@ -157,8 +159,11 @@ function getCategoryName(columnName: string, name?: DataRecordValue) { return String(name); } -export default function transformProps(chartProps: ChartProps): EchartsProps { - const { width, height, formData, queriesData } = chartProps; +export default function transformProps( + chartProps: EchartsGraphChartProps, +): GraphChartTransformedProps { + const { width, height, formData, queriesData, hooks, inContextMenu } = + chartProps; const data: DataRecord[] = queriesData[0].data || []; const { @@ -187,6 +192,7 @@ export default function transformProps(chartProps: ChartProps): EchartsProps { sliceId, }: EchartsGraphFormData = { ...DEFAULT_GRAPH_FORM_DATA, ...formData }; + const refs: Refs = {}; const metricLabel = getMetricLabel(metric); const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const nodes: { [name: string]: number } = {}; @@ -207,7 +213,10 @@ export default function transformProps(chartProps: ChartProps): EchartsProps { value: 0, category, select: DEFAULT_GRAPH_SERIES_OPTION.select, - tooltip: DEFAULT_GRAPH_SERIES_OPTION.tooltip, + tooltip: { + ...getDefaultTooltip(refs), + ...DEFAULT_GRAPH_SERIES_OPTION.tooltip, + }, }); } const node = echartNodes[nodes[name]]; @@ -295,6 +304,8 @@ export default function transformProps(chartProps: ChartProps): EchartsProps { animationDuration: DEFAULT_GRAPH_SERIES_OPTION.animationDuration, animationEasing: DEFAULT_GRAPH_SERIES_OPTION.animationEasing, tooltip: { + ...getDefaultTooltip(refs), + show: !inContextMenu, formatter: (params: any): string => edgeFormatter( params.data.source, @@ -309,9 +320,15 @@ export default function transformProps(chartProps: ChartProps): EchartsProps { }, series, }; + + const { onContextMenu } = hooks; + return { width, height, + formData, echartOptions, + onContextMenu, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/types.ts index 9cb35c1304450..95dc386eb238a 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/types.ts @@ -20,16 +20,19 @@ import { QueryFormData } from '@superset-ui/core'; import { GraphNodeItemOption } from 'echarts/types/src/chart/graph/GraphSeries'; import { SeriesTooltipOption } from 'echarts/types/src/util/types'; import { - DEFAULT_LEGEND_FORM_DATA, - EchartsLegendFormData, + BaseChartProps, + BaseTransformedProps, + ContextMenuTransformedProps, + LegendFormData, LegendOrientation, LegendType, } from '../types'; +import { DEFAULT_LEGEND_FORM_DATA } from '../constants'; export type EdgeSymbol = 'none' | 'circle' | 'arrow'; export type EchartsGraphFormData = QueryFormData & - EchartsLegendFormData & { + LegendFormData & { source: string; target: string; sourceCategory?: string; @@ -79,3 +82,11 @@ export const DEFAULT_FORM_DATA: EchartsGraphFormData = { export type tooltipFormatParams = { data: { [name: string]: string }; }; + +export interface EchartsGraphChartProps + extends BaseChartProps<EchartsGraphFormData> { + formData: EchartsGraphFormData; +} + +export type GraphChartTransformedProps = + BaseTransformedProps<EchartsGraphFormData> & ContextMenuTransformedProps; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx index d8d4191b43dad..b532c7d9da770 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx @@ -17,6 +17,12 @@ * under the License. */ import React, { useCallback } from 'react'; +import { + AxisType, + DataRecordValue, + DTTM_ALIAS, + BinaryQueryObjectFilterClause, +} from '@superset-ui/core'; import { EchartsMixedTimeseriesChartTransformedProps } from './types'; import Echart from '../components/Echart'; import { EventHandlers } from '../types'; @@ -33,7 +39,12 @@ export default function EchartsMixedTimeseries({ groupbyB, selectedValues, formData, + emitCrossFilters, seriesBreakdown, + onContextMenu, + xValueFormatter, + xAxis, + refs, }: EchartsMixedTimeseriesChartTransformedProps) { const isFirstQuery = useCallback( (seriesIndex: number) => seriesIndex < seriesBreakdown, @@ -42,17 +53,14 @@ export default function EchartsMixedTimeseries({ const handleChange = useCallback( (values: string[], seriesIndex: number) => { - const emitFilter = isFirstQuery(seriesIndex) - ? formData.emitFilter - : formData.emitFilterB; - if (!emitFilter) { + if (!emitCrossFilters) { return; } const currentGroupBy = isFirstQuery(seriesIndex) ? groupby : groupbyB; const currentLabelMap = isFirstQuery(seriesIndex) ? labelMap : labelMapB; const groupbyValues = values - .map(value => currentLabelMap[value]) + .map(value => currentLabelMap?.[value]) .filter(value => !!value); setDataMask({ @@ -63,7 +71,9 @@ export default function EchartsMixedTimeseries({ ? [] : [ ...currentGroupBy.map((col, idx) => { - const val = groupbyValues.map(v => v[idx]); + const val: DataRecordValue[] = groupbyValues.map( + v => v[idx], + ); if (val === null || val === undefined) return { col, @@ -89,7 +99,7 @@ export default function EchartsMixedTimeseries({ const eventHandlers: EventHandlers = { click: props => { const { seriesName, seriesIndex } = props; - const values: string[] = Object.values(selectedValues); + const values: string[] = Object.values(selectedValues || {}); if (values.includes(seriesName)) { handleChange( values.filter(v => v !== seriesName), @@ -105,10 +115,53 @@ export default function EchartsMixedTimeseries({ mouseover: params => { currentSeries.name = params.seriesName; }, + contextmenu: eventParams => { + if (onContextMenu) { + eventParams.event.stop(); + const { data, seriesIndex } = eventParams; + if (data) { + const pointerEvent = eventParams.event.event; + const values = [ + ...(eventParams.name ? [eventParams.name] : []), + ...(isFirstQuery(seriesIndex) ? labelMap : labelMapB)[ + eventParams.seriesName + ], + ]; + const filters: BinaryQueryObjectFilterClause[] = []; + if (xAxis.type === AxisType.time) { + filters.push({ + col: + xAxis.label === DTTM_ALIAS + ? formData.granularitySqla + : xAxis.label, + grain: formData.timeGrainSqla, + op: '==', + val: data[0], + formattedVal: xValueFormatter(data[0]), + }); + } + [ + ...(xAxis.type === AxisType.category ? [xAxis.label] : []), + ...(isFirstQuery(seriesIndex) + ? formData.groupby + : formData.groupbyB), + ].forEach((dimension, i) => + filters.push({ + col: dimension, + op: '==', + val: values[i], + formattedVal: String(values[i]), + }), + ); + onContextMenu(pointerEvent.clientX, pointerEvent.clientY, filters); + } + } + }, }; return ( <Echart + refs={refs} height={height} width={width} echartOptions={echartOptions} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/buildQuery.ts b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/buildQuery.ts index 4bd4df0bcc26e..2173dd99085b9 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/buildQuery.ts @@ -18,12 +18,13 @@ */ import { buildQueryContext, - DTTM_ALIAS, ensureIsArray, normalizeOrderBy, PostProcessingPivot, QueryFormData, QueryObject, + isXAxisSet, + getXAxisColumn, } from '@superset-ui/core'; import { pivotOperator, @@ -41,11 +42,8 @@ import { } from '../utils/formDataSuffix'; export default function buildQuery(formData: QueryFormData) { - const { x_axis: index } = formData; - const is_timeseries = index === DTTM_ALIAS || !index; const baseFormData = { ...formData, - is_timeseries, }; const formData1 = removeFormDataSuffix(baseFormData, '_b'); @@ -55,9 +53,14 @@ export default function buildQuery(formData: QueryFormData) { buildQueryContext(fd, baseQueryObject => { const queryObject = { ...baseQueryObject, - columns: [...ensureIsArray(index), ...ensureIsArray(fd.groupby)], + columns: [ + ...(isXAxisSet(formData) + ? ensureIsArray(getXAxisColumn(formData)) + : []), + ...ensureIsArray(fd.groupby), + ], series_columns: fd.groupby, - is_timeseries, + ...(isXAxisSet(formData) ? {} : { is_timeseries: true }), }; const pivotOperatorInRuntime: PostProcessingPivot = isTimeComparison( @@ -65,12 +68,7 @@ export default function buildQuery(formData: QueryFormData) { queryObject, ) ? timeComparePivotOperator(fd, queryObject) - : pivotOperator(fd, { - ...queryObject, - columns: fd.groupby, - index, - is_timeseries, - }); + : pivotOperator(fd, queryObject); const tmpQueryObject = { ...queryObject, @@ -80,11 +78,7 @@ export default function buildQuery(formData: QueryFormData) { rollingWindowOperator(fd, queryObject), timeCompareOperator(fd, queryObject), resampleOperator(fd, queryObject), - renameOperator(fd, { - ...queryObject, - columns: fd.groupby, - is_timeseries, - }), + renameOperator(fd, queryObject), flattenOperator(fd, queryObject), ], } as QueryObject; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx index fb164f1a26e81..c1a3007785887 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx @@ -17,26 +17,21 @@ * under the License. */ import React from 'react'; -import { - ensureIsArray, - FeatureFlag, - isFeatureEnabled, - t, -} from '@superset-ui/core'; +import { ensureIsArray, hasGenericChartAxes, t } from '@superset-ui/core'; import { cloneDeep } from 'lodash'; import { ControlPanelConfig, ControlPanelSectionConfig, ControlSetRow, CustomControlItem, - emitFilterControl, + getStandardizedControls, sections, sharedControls, } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA } from './types'; import { EchartsTimeseriesSeriesType } from '../Timeseries/types'; -import { legendSection, richTooltipSection, xAxisControl } from '../controls'; +import { legendSection, richTooltipSection } from '../controls'; const { area, @@ -83,14 +78,6 @@ function createQuerySection( config: sharedControls.adhoc_filters, }, ], - emitFilterControl.length > 0 - ? [ - { - ...emitFilterControl[0], - name: `emit_filter${controlSuffix}`, - }, - ] - : [], [ { name: `limit${controlSuffix}`, @@ -151,13 +138,13 @@ function createCustomizeSection( renderTrigger: true, default: seriesType, choices: [ - [EchartsTimeseriesSeriesType.Line, 'Line'], - [EchartsTimeseriesSeriesType.Scatter, 'Scatter'], - [EchartsTimeseriesSeriesType.Smooth, 'Smooth Line'], - [EchartsTimeseriesSeriesType.Bar, 'Bar'], - [EchartsTimeseriesSeriesType.Start, 'Step - start'], - [EchartsTimeseriesSeriesType.Middle, 'Step - middle'], - [EchartsTimeseriesSeriesType.End, 'Step - end'], + [EchartsTimeseriesSeriesType.Line, t('Line')], + [EchartsTimeseriesSeriesType.Scatter, t('Scatter')], + [EchartsTimeseriesSeriesType.Smooth, t('Smooth Line')], + [EchartsTimeseriesSeriesType.Bar, t('Bar')], + [EchartsTimeseriesSeriesType.Start, t('Step - start')], + [EchartsTimeseriesSeriesType.Middle, t('Step - middle')], + [EchartsTimeseriesSeriesType.End, t('Step - end')], ], description: t('Series chart type (line, bar etc)'), }, @@ -290,12 +277,12 @@ function createAdvancedAnalyticsSection( const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, - isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + sections.genericTime, + hasGenericChartAxes ? { label: t('Shared query fields'), expanded: true, - controlSetRows: [[xAxisControl]], + controlSetRows: [['x_axis'], ['time_grain_sqla']], } : null, createQuerySection(t('Query A'), ''), @@ -449,15 +436,23 @@ const config: ControlPanelConfig = { ], }, ], - denormalizeFormData: formData => { - const groupby = - formData.standardizedFormData.standardizedState.columns.filter( - col => !ensureIsArray(formData.groupby_b).includes(col), + formDataOverrides: formData => { + const groupby = getStandardizedControls().controls.columns.filter( + col => !ensureIsArray(formData.groupby_b).includes(col), + ); + getStandardizedControls().controls.columns = + getStandardizedControls().controls.columns.filter( + col => !groupby.includes(col), ); - const metrics = - formData.standardizedFormData.standardizedState.metrics.filter( - metric => !ensureIsArray(formData.metrics_b).includes(metric), + + const metrics = getStandardizedControls().controls.metrics.filter( + metric => !ensureIsArray(formData.metrics_b).includes(metric), + ); + getStandardizedControls().controls.metrics = + getStandardizedControls().controls.metrics.filter( + col => !metrics.includes(col), ); + return { ...formData, metrics, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/images/example.jpg b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/images/example.jpg new file mode 100644 index 0000000000000..8a7edb3200fb4 Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/images/example.jpg differ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts index a5bd7ddf95a39..eb1bef3c9b713 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts @@ -21,14 +21,14 @@ import { Behavior, ChartMetadata, ChartPlugin, - FeatureFlag, - isFeatureEnabled, + hasGenericChartAxes, t, } from '@superset-ui/core'; import buildQuery from './buildQuery'; import controlPanel from './controlPanel'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example from './images/example.jpg'; import { EchartsMixedTimeseriesFormData, EchartsMixedTimeseriesProps, @@ -54,10 +54,10 @@ export default class EchartsTimeseriesChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('./EchartsMixedTimeseries'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Evolution'), credits: ['https://echarts.apache.org'], - description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + description: hasGenericChartAxes ? t( 'Visualize two different series using the same x-axis. Note that both series can be visualized with a different chart type (e.g. 1 using bars and 1 using a line).', ) @@ -70,9 +70,8 @@ export default class EchartsTimeseriesChartPlugin extends ChartPlugin< AnnotationType.Interval, AnnotationType.Timeseries, ], - name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) - ? t('Mixed Chart') - : t('Mixed Time-Series'), + exampleGallery: [{ url: example }], + name: hasGenericChartAxes ? t('Mixed Chart') : t('Mixed Time-Series'), thumbnail, tags: [ t('Advanced-Analytics'), @@ -84,6 +83,7 @@ export default class EchartsTimeseriesChartPlugin extends ChartPlugin< t('Time'), t('Transformable'), ], + queryObjectCount: 2, }), // @ts-ignore transformProps, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts index f1232cb18e9f1..98367daf9a84e 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts @@ -20,16 +20,18 @@ import { AnnotationLayer, CategoricalColorNamespace, - DataRecordValue, - DTTM_ALIAS, GenericDataType, - getColumnLabel, getNumberFormatter, isEventAnnotationLayer, isFormulaAnnotationLayer, isIntervalAnnotationLayer, isTimeseriesAnnotationLayer, + QueryFormData, + TimeseriesChartDataResponseResult, TimeseriesDataRecord, + getXAxisLabel, + isPhysicalColumn, + isDefined, } from '@superset-ui/core'; import { EChartsCoreOption, SeriesOption } from 'echarts'; import { @@ -38,9 +40,14 @@ import { EchartsMixedTimeseriesChartTransformedProps, EchartsMixedTimeseriesProps, } from './types'; -import { ForecastSeriesEnum } from '../types'; +import { + EchartsTimeseriesSeriesType, + ForecastSeriesEnum, + Refs, +} from '../types'; import { parseYAxisBound } from '../utils/controls'; import { + getOverMaxHiddenFormatter, currentSeries, dedupSeries, extractSeries, @@ -61,7 +68,7 @@ import { rebaseForecastDatum, } from '../utils/forecast'; import { convertInteger } from '../utils/convertInteger'; -import { defaultGrid, defaultTooltip, defaultYAxis } from '../defaults'; +import { defaultGrid, defaultYAxis } from '../defaults'; import { getPadding, getTooltipTimeFormatter, @@ -73,6 +80,7 @@ import { transformTimeseriesAnnotation, } from '../Timeseries/transformers'; import { TIMESERIES_CONSTANTS, TIMEGRAIN_TO_TIMESTAMP } from '../constants'; +import { getDefaultTooltip } from '../utils/tooltip'; export default function transformProps( chartProps: EchartsMixedTimeseriesProps, @@ -86,8 +94,14 @@ export default function transformProps( filterState, datasource, theme, + inContextMenu, + emitCrossFilters, } = chartProps; const { verboseMap = {} } = datasource; + const { label_map: labelMap } = + queriesData[0] as TimeseriesChartDataResponseResult; + const { label_map: labelMapB } = + queriesData[1] as TimeseriesChartDataResponseResult; const data1 = (queriesData[0].data || []) as TimeseriesDataRecord[]; const data2 = (queriesData[1].data || []) as TimeseriesDataRecord[]; const annotationData = getAnnotationData(chartProps); @@ -131,8 +145,6 @@ export default function transformProps( xAxisLabelRotation, groupby, groupbyB, - emitFilter, - emitFilterB, xAxis: xAxisOrig, xAxisTitle, yAxisTitle, @@ -144,24 +156,32 @@ export default function transformProps( percentageThreshold, }: EchartsMixedTimeseriesFormData = { ...DEFAULT_FORM_DATA, ...formData }; + const refs: Refs = {}; const colorScale = CategoricalColorNamespace.getScale(colorScheme as string); - const xAxisCol = - verboseMap[xAxisOrig] || getColumnLabel(xAxisOrig || DTTM_ALIAS); + let xAxisLabel = getXAxisLabel( + chartProps.rawFormData as QueryFormData, + ) as string; + if ( + isPhysicalColumn(chartProps.rawFormData?.x_axis) && + isDefined(verboseMap[xAxisLabel]) + ) { + xAxisLabel = verboseMap[xAxisLabel]; + } const rebasedDataA = rebaseForecastDatum(data1, verboseMap); const rawSeriesA = extractSeries(rebasedDataA, { fillNeighborValue: stack ? 0 : undefined, - xAxis: xAxisCol, + xAxis: xAxisLabel, }); const rebasedDataB = rebaseForecastDatum(data2, verboseMap); const rawSeriesB = extractSeries(rebasedDataB, { fillNeighborValue: stackB ? 0 : undefined, - xAxis: xAxisCol, + xAxis: xAxisLabel, }); const dataTypes = getColtypesMapping(queriesData[0]); - const xAxisDataType = dataTypes?.[xAxisCol] ?? dataTypes?.[xAxisOrig]; + const xAxisDataType = dataTypes?.[xAxisLabel] ?? dataTypes?.[xAxisOrig]; const xAxisType = getAxisType(xAxisDataType); const series: SeriesOption[] = []; const formatter = getNumberFormatter(contributionMode ? ',.0%' : yAxisFormat); @@ -198,7 +218,7 @@ export default function transformProps( { stack, percentageThreshold, - xAxisCol, + xAxisCol: xAxisLabel, }, ); const { @@ -207,50 +227,7 @@ export default function transformProps( } = extractDataTotalValues(rebasedDataB, { stack: Boolean(stackB), percentageThreshold, - xAxisCol, - }); - rawSeriesA.forEach(entry => { - const transformedSeries = transformSeries(entry, colorScale, { - area, - markerEnabled, - markerSize, - areaOpacity: opacity, - seriesType, - showValue, - stack: Boolean(stack), - yAxisIndex, - filterState, - seriesKey: entry.name, - sliceId, - formatter, - showValueIndexes: showValueIndexesA, - totalStackedValues, - thresholdValues, - }); - if (transformedSeries) series.push(transformedSeries); - }); - - rawSeriesB.forEach(entry => { - const transformedSeries = transformSeries(entry, colorScale, { - area: areaB, - markerEnabled: markerEnabledB, - markerSize: markerSizeB, - areaOpacity: opacityB, - seriesType: seriesTypeB, - showValue: showValueB, - stack: Boolean(stackB), - yAxisIndex: yAxisIndexB, - filterState, - seriesKey: primarySeries.has(entry.name as string) - ? `${entry.name} (1)` - : entry.name, - sliceId, - formatter: formatterSecondary, - showValueIndexes: showValueIndexesB, - totalStackedValues: totalStackedValuesB, - thresholdValues: thresholdValuesB, - }); - if (transformedSeries) series.push(transformedSeries); + xAxisCol: xAxisLabel, }); annotationLayers @@ -258,7 +235,14 @@ export default function transformProps( .forEach((layer: AnnotationLayer) => { if (isFormulaAnnotationLayer(layer)) series.push( - transformFormulaAnnotation(layer, data1, colorScale, sliceId), + transformFormulaAnnotation( + layer, + data1, + xAxisLabel, + xAxisType, + colorScale, + sliceId, + ), ); else if (isIntervalAnnotationLayer(layer)) { series.push( @@ -299,6 +283,64 @@ export default function transformProps( // yAxisBounds need to be parsed to replace incompatible values with undefined let [min, max] = (yAxisBounds || []).map(parseYAxisBound); + const maxLabelFormatter = getOverMaxHiddenFormatter({ max, formatter }); + const maxLabelFormatterSecondary = getOverMaxHiddenFormatter({ + max, + formatter: formatterSecondary, + }); + + rawSeriesA.forEach(entry => { + const transformedSeries = transformSeries(entry, colorScale, { + area, + markerEnabled, + markerSize, + areaOpacity: opacity, + seriesType, + showValue, + stack: Boolean(stack), + yAxisIndex, + filterState, + seriesKey: entry.name, + sliceId, + queryIndex: 0, + formatter: + seriesType === EchartsTimeseriesSeriesType.Bar + ? maxLabelFormatter + : formatter, + showValueIndexes: showValueIndexesA, + totalStackedValues, + thresholdValues, + }); + if (transformedSeries) series.push(transformedSeries); + }); + + rawSeriesB.forEach(entry => { + const transformedSeries = transformSeries(entry, colorScale, { + area: areaB, + markerEnabled: markerEnabledB, + markerSize: markerSizeB, + areaOpacity: opacityB, + seriesType: seriesTypeB, + showValue: showValueB, + stack: Boolean(stackB), + yAxisIndex: yAxisIndexB, + filterState, + seriesKey: primarySeries.has(entry.name as string) + ? `${entry.name} (1)` + : entry.name, + sliceId, + queryIndex: 1, + formatter: + seriesTypeB === EchartsTimeseriesSeriesType.Bar + ? maxLabelFormatterSecondary + : formatterSecondary, + showValueIndexes: showValueIndexesB, + totalStackedValues: totalStackedValuesB, + thresholdValues: thresholdValuesB, + }); + if (transformedSeries) series.push(transformedSeries); + }); + // default to 0-100% range when doing row-level contribution chart if (contributionMode === 'row' && stack) { if (min === undefined) min = 0; @@ -328,23 +370,8 @@ export default function transformProps( convertInteger(yAxisTitleMargin), convertInteger(xAxisTitleMargin), ); - const labelMap = rawSeriesA.reduce((acc, datum) => { - const label = datum.name as string; - return { - ...acc, - [label]: label.split(', '), - }; - }, {}) as Record<string, DataRecordValue[]>; - - const labelMapB = rawSeriesB.reduce((acc, datum) => { - const label = datum.name as string; - return { - ...acc, - [label]: label.split(', '), - }; - }, {}) as Record<string, DataRecordValue[]>; - const { setDataMask = () => {} } = hooks; + const { setDataMask = () => {}, onContextMenu } = hooks; const alignTicks = yAxisIndex !== yAxisIndexB; const echartOptions: EChartsCoreOption = { @@ -397,8 +424,8 @@ export default function transformProps( }, ], tooltip: { - ...defaultTooltip, - appendToBody: true, + ...getDefaultTooltip(refs), + show: !inContextMenu, trigger: richTooltip ? 'axis' : 'item', formatter: (params: any) => { const xValue: number = richTooltip @@ -476,13 +503,19 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, - emitFilterB, + emitCrossFilters, labelMap, labelMapB, groupby, groupbyB, seriesBreakdown: rawSeriesA.length, selectedValues: filterState.selectedValues || [], + onContextMenu, + xValueFormatter: tooltipFormatter, + xAxis: { + label: xAxisLabel, + type: xAxisType, + }, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/types.ts index 51938436fbb0e..3ec9b2a4b6d38 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/types.ts @@ -16,29 +16,30 @@ * specific language governing permissions and limitations * under the License. */ -import { EChartsCoreOption } from 'echarts'; import { AnnotationLayer, TimeGranularity, - DataRecordValue, - SetDataMaskHook, QueryFormData, - ChartProps, - ChartDataResponseResult, QueryFormColumn, + ContributionType, + TimeFormatter, + AxisType, } from '@superset-ui/core'; import { - DEFAULT_LEGEND_FORM_DATA, - EchartsLegendFormData, - EchartsTitleFormData, - DEFAULT_TITLE_FORM_DATA, + BaseChartProps, + BaseTransformedProps, + ContextMenuTransformedProps, + CrossFilterTransformedProps, + EchartsTimeseriesSeriesType, + LegendFormData, StackType, + TitleFormData, } from '../types'; import { + DEFAULT_LEGEND_FORM_DATA, + DEFAULT_TITLE_FORM_DATA, DEFAULT_FORM_DATA as TIMESERIES_DEFAULTS, - EchartsTimeseriesContributionType, - EchartsTimeseriesSeriesType, -} from '../Timeseries/types'; +} from '../constants'; export type EchartsMixedTimeseriesFormData = QueryFormData & { annotationLayers: AnnotationLayer[]; @@ -63,8 +64,8 @@ export type EchartsMixedTimeseriesFormData = QueryFormData & { // types specific to Query A and Query B area: boolean; areaB: boolean; - contributionMode?: EchartsTimeseriesContributionType; - contributionModeB?: EchartsTimeseriesContributionType; + contributionMode?: ContributionType; + contributionModeB?: ContributionType; markerEnabled: boolean; markerEnabledB: boolean; markerSize: number; @@ -85,9 +86,8 @@ export type EchartsMixedTimeseriesFormData = QueryFormData & { yAxisIndexB?: number; groupby: QueryFormColumn[]; groupbyB: QueryFormColumn[]; - emitFilter: boolean; -} & EchartsLegendFormData & - EchartsTitleFormData; +} & LegendFormData & + TitleFormData; // @ts-ignore export const DEFAULT_FORM_DATA: EchartsMixedTimeseriesFormData = { @@ -133,23 +133,21 @@ export const DEFAULT_FORM_DATA: EchartsMixedTimeseriesFormData = { ...DEFAULT_TITLE_FORM_DATA, }; -export interface EchartsMixedTimeseriesProps extends ChartProps { +export interface EchartsMixedTimeseriesProps + extends BaseChartProps<EchartsMixedTimeseriesFormData> { formData: EchartsMixedTimeseriesFormData; - queriesData: ChartDataResponseResult[]; } -export type EchartsMixedTimeseriesChartTransformedProps = { - formData: EchartsMixedTimeseriesFormData; - height: number; - width: number; - echartOptions: EChartsCoreOption; - emitFilter: boolean; - emitFilterB: boolean; - setDataMask: SetDataMaskHook; - groupby: QueryFormColumn[]; - groupbyB: QueryFormColumn[]; - labelMap: Record<string, DataRecordValue[]>; - labelMapB: Record<string, DataRecordValue[]>; - selectedValues: Record<number, string>; - seriesBreakdown: number; -}; +export type EchartsMixedTimeseriesChartTransformedProps = + BaseTransformedProps<EchartsMixedTimeseriesFormData> & + ContextMenuTransformedProps & + CrossFilterTransformedProps & { + groupbyB: QueryFormColumn[]; + labelMapB: Record<string, string[]>; + seriesBreakdown: number; + xValueFormatter: TimeFormatter | StringConstructor; + xAxis: { + label: string; + type: AxisType; + }; + }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/EchartsPie.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/EchartsPie.tsx index f508b17eebedd..9fecfeac0ef78 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/EchartsPie.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/EchartsPie.tsx @@ -19,21 +19,23 @@ import React, { useCallback } from 'react'; import { PieChartTransformedProps } from './types'; import Echart from '../components/Echart'; -import { EventHandlers } from '../types'; +import { allEventHandlers } from '../utils/eventHandlers'; -export default function EchartsPie({ - height, - width, - echartOptions, - setDataMask, - labelMap, - groupby, - selectedValues, - formData, -}: PieChartTransformedProps) { +export default function EchartsPie(props: PieChartTransformedProps) { + const { + height, + width, + echartOptions, + setDataMask, + labelMap, + groupby, + selectedValues, + refs, + emitCrossFilters, + } = props; const handleChange = useCallback( (values: string[]) => { - if (!formData.emitFilter) { + if (!emitCrossFilters) { return; } @@ -67,20 +69,11 @@ export default function EchartsPie({ [groupby, labelMap, setDataMask, selectedValues], ); - const eventHandlers: EventHandlers = { - click: props => { - const { name } = props; - const values = Object.values(selectedValues); - if (values.includes(name)) { - handleChange(values.filter(v => v !== name)); - } else { - handleChange([name]); - } - }, - }; + const eventHandlers = allEventHandlers(props, handleChange); return ( <Echart + refs={refs} height={height} width={width} echartOptions={echartOptions} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx index 7b948208a457c..952419e83b504 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx @@ -22,10 +22,11 @@ import { ControlPanelConfig, ControlPanelsContainerProps, D3_FORMAT_DOCS, + D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT, D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, sections, - emitFilterControl, + getStandardizedControls, } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA } from './types'; import { legendSection } from '../controls'; @@ -51,7 +52,6 @@ const config: ControlPanelConfig = { ['groupby'], ['metric'], ['adhoc_filters'], - emitFilterControl, ['row_limit'], [ { @@ -100,12 +100,12 @@ const config: ControlPanelConfig = { default: labelType, renderTrigger: true, choices: [ - ['key', 'Category Name'], - ['value', 'Value'], - ['percent', 'Percentage'], - ['key_value', 'Category and Value'], - ['key_percent', 'Category and Percentage'], - ['key_value_percent', 'Category, Value and Percentage'], + ['key', t('Category Name')], + ['value', t('Value')], + ['percent', t('Percentage')], + ['key_value', t('Category and Value')], + ['key_percent', t('Category and Percentage')], + ['key_value_percent', t('Category, Value and Percentage')], ], description: t('What should be shown on the label?'), }, @@ -121,9 +121,8 @@ const config: ControlPanelConfig = { renderTrigger: true, default: numberFormat, choices: D3_FORMAT_OPTIONS, - description: `${t( - 'D3 format syntax: https://github.com/d3/d3-format', - )} ${t('Only applies when "Label Type" is set to show values.')}`, + description: `${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`, + tokenSeparators: ['\n', '\t', ';'], }, }, ], @@ -253,17 +252,13 @@ const config: ControlPanelConfig = { default: 100, }, }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metric: formData.standardizedFormData.standardizedState.metrics[0], - groupby: formData.standardizedFormData.standardizedState.columns, + metric: getStandardizedControls().shiftMetric(), + groupby: getStandardizedControls().popAllColumns(), row_limit: ensureIsInt(formData.row_limit, 100) >= 100 ? 100 : formData.row_limit, }), - updateStandardizedState: (prevState, currState) => ({ - ...currState, - metrics: [currState.metrics[0], ...prevState.metrics.slice(1)], - }), }; export default config; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts index 873a6ac2343e4..9f5d61474a37a 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts @@ -47,7 +47,7 @@ export default class EchartsPieChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('./EchartsPie'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Part of a Whole'), credits: ['https://echarts.apache.org'], description: diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts index c0466e6bba562..4db36e864e9d8 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts @@ -18,7 +18,6 @@ */ import { CategoricalColorNamespace, - DataRecordValue, getColumnLabel, getMetricLabel, getNumberFormatter, @@ -36,7 +35,7 @@ import { EchartsPieLabelType, PieChartTransformedProps, } from './types'; -import { DEFAULT_LEGEND_FORM_DATA } from '../types'; +import { DEFAULT_LEGEND_FORM_DATA, OpacityEnum } from '../constants'; import { extractGroupbyLabel, getChartPadding, @@ -44,9 +43,10 @@ import { getLegendProps, sanitizeHtml, } from '../utils/series'; -import { defaultGrid, defaultTooltip } from '../defaults'; -import { OpacityEnum } from '../constants'; +import { defaultGrid } from '../defaults'; import { convertInteger } from '../utils/convertInteger'; +import { getDefaultTooltip } from '../utils/tooltip'; +import { Refs } from '../types'; const percentFormatter = getNumberFormatter(NumberFormats.PERCENT_2_POINT); @@ -135,8 +135,17 @@ function getTotalValuePadding({ export default function transformProps( chartProps: EchartsPieChartProps, ): PieChartTransformedProps { - const { formData, height, hooks, filterState, queriesData, width, theme } = - chartProps; + const { + formData, + height, + hooks, + filterState, + queriesData, + width, + theme, + inContextMenu, + emitCrossFilters, + } = chartProps; const { data = [] } = queriesData[0]; const coltypeMapping = getColtypesMapping(queriesData[0]); @@ -158,7 +167,6 @@ export default function transformProps( showLabels, showLegend, showLabelsThreshold, - emitFilter, sliceId, showTotal, }: EchartsPieFormData = { @@ -166,6 +174,7 @@ export default function transformProps( ...DEFAULT_PIE_FORM_DATA, ...formData, }; + const refs: Refs = {}; const metricLabel = getMetricLabel(metric); const groupbyLabels = groupby.map(getColumnLabel); const minShowLabelAngle = (showLabelsThreshold || 0) * 3.6; @@ -178,23 +187,20 @@ export default function transformProps( timeFormatter: getTimeFormatter(dateFormat), }), ); - const labelMap = data.reduce( - (acc: Record<string, DataRecordValue[]>, datum) => { - const label = extractGroupbyLabel({ - datum, - groupby: groupbyLabels, - coltypeMapping, - timeFormatter: getTimeFormatter(dateFormat), - }); - return { - ...acc, - [label]: groupbyLabels.map(col => datum[col]), - }; - }, - {}, - ); + const labelMap = data.reduce((acc: Record<string, string[]>, datum) => { + const label = extractGroupbyLabel({ + datum, + groupby: groupbyLabels, + coltypeMapping, + timeFormatter: getTimeFormatter(dateFormat), + }); + return { + ...acc, + [label]: groupbyLabels.map(col => datum[col] as string), + }; + }, {}); - const { setDataMask = () => {} } = hooks; + const { setDataMask = () => {}, onContextMenu } = hooks; const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const numberFormatter = getNumberFormatter(numberFormat); @@ -297,7 +303,8 @@ export default function transformProps( ...defaultGrid, }, tooltip: { - ...defaultTooltip, + ...getDefaultTooltip(refs), + show: !inContextMenu, trigger: 'item', formatter: (params: any) => formatPieLabel({ @@ -332,9 +339,11 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, labelMap, groupby, selectedValues, + onContextMenu, + refs, + emitCrossFilters, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/types.ts index c97afd3a7c9bb..d4acbb9517107 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/types.ts @@ -16,24 +16,20 @@ * specific language governing permissions and limitations * under the License. */ -import { EChartsCoreOption } from 'echarts'; +import { QueryFormColumn, QueryFormData } from '@superset-ui/core'; import { - ChartDataResponseResult, - ChartProps, - DataRecordValue, - QueryFormColumn, - QueryFormData, - SetDataMaskHook, -} from '@superset-ui/core'; -import { - DEFAULT_LEGEND_FORM_DATA, - EchartsLegendFormData, + BaseChartProps, + BaseTransformedProps, + ContextMenuTransformedProps, + CrossFilterTransformedProps, + LegendFormData, LegendOrientation, LegendType, } from '../types'; +import { DEFAULT_LEGEND_FORM_DATA } from '../constants'; export type EchartsPieFormData = QueryFormData & - EchartsLegendFormData & { + LegendFormData & { colorScheme?: string; currentOwnValue?: string[] | null; donut: boolean; @@ -49,7 +45,6 @@ export type EchartsPieFormData = QueryFormData & numberFormat: string; dateFormat: string; showLabelsThreshold: number; - emitFilter: boolean; }; export enum EchartsPieLabelType { @@ -61,9 +56,9 @@ export enum EchartsPieLabelType { KeyValuePercent = 'key_value_percent', } -export interface EchartsPieChartProps extends ChartProps<EchartsPieFormData> { +export interface EchartsPieChartProps + extends BaseChartProps<EchartsPieFormData> { formData: EchartsPieFormData; - queriesData: ChartDataResponseResult[]; } // @ts-ignore @@ -81,18 +76,10 @@ export const DEFAULT_FORM_DATA: EchartsPieFormData = { showLabels: true, labelsOutside: true, showLabelsThreshold: 5, - emitFilter: false, dateFormat: 'smart_date', }; -export interface PieChartTransformedProps { - formData: EchartsPieFormData; - height: number; - width: number; - echartOptions: EChartsCoreOption; - emitFilter: boolean; - setDataMask: SetDataMaskHook; - labelMap: Record<string, DataRecordValue[]>; - groupby: QueryFormColumn[]; - selectedValues: Record<number, string>; -} +export type PieChartTransformedProps = + BaseTransformedProps<EchartsPieFormData> & + ContextMenuTransformedProps & + CrossFilterTransformedProps; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/EchartsRadar.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/EchartsRadar.tsx index 5757c2a95f597..169240e8a45d0 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/EchartsRadar.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/EchartsRadar.tsx @@ -19,21 +19,23 @@ import React, { useCallback } from 'react'; import { RadarChartTransformedProps } from './types'; import Echart from '../components/Echart'; -import { EventHandlers } from '../types'; +import { allEventHandlers } from '../utils/eventHandlers'; -export default function EchartsRadar({ - height, - width, - echartOptions, - setDataMask, - labelMap, - groupby, - selectedValues, - formData, -}: RadarChartTransformedProps) { +export default function EchartsRadar(props: RadarChartTransformedProps) { + const { + height, + width, + echartOptions, + setDataMask, + labelMap, + groupby, + selectedValues, + emitCrossFilters, + refs, + } = props; const handleChange = useCallback( (values: string[]) => { - if (!formData.emitFilter) { + if (!emitCrossFilters) { return; } @@ -67,20 +69,11 @@ export default function EchartsRadar({ [groupby, labelMap, setDataMask, selectedValues], ); - const eventHandlers: EventHandlers = { - click: props => { - const { name } = props; - const values = Object.values(selectedValues); - if (values.includes(name)) { - handleChange(values.filter(v => v !== name)); - } else { - handleChange([name]); - } - }, - }; + const eventHandlers = allEventHandlers(props, handleChange); return ( <Echart + refs={refs} height={height} width={width} echartOptions={echartOptions} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/buildQuery.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/buildQuery.ts index c48f4293e1c46..604f7f2872e29 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/buildQuery.ts @@ -23,18 +23,18 @@ import { } from '@superset-ui/core'; export default function buildQuery(formData: QueryFormData) { - const { timeseries_limit_metric } = formData; - const sortByMetric = ensureIsArray(timeseries_limit_metric)[0]; + const { series_limit_metric } = formData; + const sortByMetric = ensureIsArray(series_limit_metric)[0]; return buildQueryContext(formData, baseQueryObject => { let { metrics, orderby = [] } = baseQueryObject; metrics = metrics || []; - // orverride orderby with timeseries metric + // override orderby with timeseries metric if (sortByMetric) { orderby = [[sortByMetric, false]]; } else if (metrics?.length > 0) { // default to ordering by first metric in descending order - // when no "sort by" metric is set (regargless if "SORT DESC" is set to true) + // when no "sort by" metric is set (regardless if "SORT DESC" is set to true) orderby = [[metrics[0], false]]; } return [ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx index d78d935a79109..61ac18209a49d 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx @@ -27,12 +27,13 @@ import { import { ControlPanelConfig, D3_FORMAT_DOCS, + D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT, D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, sections, sharedControls, - emitFilterControl, ControlFormItemSpec, + getStandardizedControls, } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA } from './types'; import { LABEL_POSITION } from '../constants'; @@ -50,7 +51,7 @@ const radarMetricMaxValue: { name: string; config: ControlFormItemSpec } = { 'The maximum value of metrics. It is an optional configuration', ), width: 120, - placeholder: 'auto', + placeholder: t('auto'), debounceDelay: 400, validators: [validateNumber], }, @@ -67,7 +68,6 @@ const config: ControlPanelConfig = { ['metrics'], ['timeseries_limit_metric'], ['adhoc_filters'], - emitFilterControl, [ { name: 'row_limit', @@ -107,8 +107,8 @@ const config: ControlPanelConfig = { default: labelType, renderTrigger: true, choices: [ - ['value', 'Value'], - ['key_value', 'Category and Value'], + ['value', t('Value')], + ['key_value', t('Category and Value')], ], description: t('What should be shown on the label?'), }, @@ -138,9 +138,7 @@ const config: ControlPanelConfig = { renderTrigger: true, default: numberFormat, choices: D3_FORMAT_OPTIONS, - description: `${t( - 'D3 format syntax: https://github.com/d3/d3-format. ', - )} ${t('Only applies when "Label Type" is set to show values.')}`, + description: `${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`, }, }, ], @@ -210,10 +208,10 @@ const config: ControlPanelConfig = { ], }, ], - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, - groupby: formData.standardizedFormData.standardizedState.columns, + metrics: getStandardizedControls().popAllMetrics(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/images/example1.jpg b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/images/example1.jpg new file mode 100644 index 0000000000000..056ada15086c5 Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/images/example1.jpg differ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/images/example2.jpg b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/images/example2.jpg new file mode 100644 index 0000000000000..8dd0854409c6d Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/images/example2.jpg differ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts index f57eccdafa581..69f1ee8dac5b5 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts @@ -2,7 +2,7 @@ * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information - * regardin + * regarding * g copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance @@ -22,6 +22,8 @@ import buildQuery from './buildQuery'; import controlPanel from './controlPanel'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example1 from './images/example1.jpg'; +import example2 from './images/example2.jpg'; import { EchartsRadarChartProps, EchartsRadarFormData } from './types'; export default class EchartsRadarChartPlugin extends ChartPlugin< @@ -44,12 +46,13 @@ export default class EchartsRadarChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('./EchartsRadar'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Ranking'), credits: ['https://echarts.apache.org'], description: t( 'Visualize a parallel set of metrics across multiple groups. Each group is visualized using its own line of points and each metric is represented as an edge in the chart.', ), + exampleGallery: [{ url: example1 }, { url: example2 }], name: t('Radar Chart'), tags: [ t('Business'), diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts index 01a20b82b436e..f185859f4eee5 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts @@ -18,7 +18,6 @@ */ import { CategoricalColorNamespace, - DataRecordValue, ensureIsInt, getColumnLabel, getMetricLabel, @@ -36,15 +35,16 @@ import { EchartsRadarLabelType, RadarChartTransformedProps, } from './types'; -import { DEFAULT_LEGEND_FORM_DATA } from '../types'; +import { DEFAULT_LEGEND_FORM_DATA, OpacityEnum } from '../constants'; import { extractGroupbyLabel, getChartPadding, getColtypesMapping, getLegendProps, } from '../utils/series'; -import { defaultGrid, defaultTooltip } from '../defaults'; -import { OpacityEnum } from '../constants'; +import { defaultGrid } from '../defaults'; +import { Refs } from '../types'; +import { getDefaultTooltip } from '../utils/tooltip'; export function formatLabel({ params, @@ -71,8 +71,18 @@ export function formatLabel({ export default function transformProps( chartProps: EchartsRadarChartProps, ): RadarChartTransformedProps { - const { formData, height, hooks, filterState, queriesData, width, theme } = - chartProps; + const { + formData, + height, + hooks, + filterState, + queriesData, + width, + theme, + inContextMenu, + emitCrossFilters, + } = chartProps; + const refs: Refs = {}; const { data = [] } = queriesData[0]; const coltypeMapping = getColtypesMapping(queriesData[0]); @@ -97,7 +107,7 @@ export default function transformProps( ...DEFAULT_RADAR_FORM_DATA, ...formData, }; - const { setDataMask = () => {} } = hooks; + const { setDataMask = () => {}, onContextMenu } = hooks; const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const numberFormatter = getNumberFormatter(numberFormat); @@ -112,7 +122,7 @@ export default function transformProps( const groupbyLabels = groupby.map(getColumnLabel); const metricLabelAndMaxValueMap = new Map<string, number>(); - const columnsLabelMap = new Map<string, DataRecordValue[]>(); + const columnsLabelMap = new Map<string, string[]>(); const transformedData: RadarSeriesDataItemOption[] = []; data.forEach(datum => { const joinedName = extractGroupbyLabel({ @@ -124,7 +134,7 @@ export default function transformProps( // map(joined_name: [columnLabel_1, columnLabel_2, ...]) columnsLabelMap.set( joinedName, - groupbyLabels.map(col => datum[col]), + groupbyLabels.map(col => datum[col] as string), ); // put max value of series into metricLabelAndMaxValueMap @@ -222,7 +232,8 @@ export default function transformProps( ...defaultGrid, }, tooltip: { - ...defaultTooltip, + ...getDefaultTooltip(refs), + show: !inContextMenu, trigger: 'item', }, legend: { @@ -241,9 +252,12 @@ export default function transformProps( width, height, echartOptions, + emitCrossFilters, setDataMask, labelMap: Object.fromEntries(columnsLabelMap), groupby, selectedValues, + onContextMenu, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/types.ts index 9b053b6264554..ca7cdbd2c2db9 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/types.ts @@ -16,28 +16,27 @@ * specific language governing permissions and limitations * under the License. */ -import { EChartsCoreOption } from 'echarts'; import { - ChartDataResponseResult, - ChartProps, - DataRecordValue, QueryFormColumn, QueryFormData, QueryFormMetric, - SetDataMaskHook, } from '@superset-ui/core'; import { - DEFAULT_LEGEND_FORM_DATA, - EchartsLegendFormData, + BaseChartProps, + BaseTransformedProps, + ContextMenuTransformedProps, + CrossFilterTransformedProps, + LegendFormData, LabelPositionEnum, LegendOrientation, LegendType, } from '../types'; +import { DEFAULT_LEGEND_FORM_DATA } from '../constants'; type RadarColumnConfig = Record<string, { radarMetricMaxValue?: number }>; export type EchartsRadarFormData = QueryFormData & - EchartsLegendFormData & { + LegendFormData & { colorScheme?: string; columnConfig?: RadarColumnConfig; currentOwnValue?: string[] | null; @@ -51,7 +50,6 @@ export type EchartsRadarFormData = QueryFormData & isCircle: boolean; numberFormat: string; dateFormat: string; - emitFilter: boolean; }; export enum EchartsRadarLabelType { @@ -59,9 +57,9 @@ export enum EchartsRadarLabelType { KeyValue = 'key_value', } -export interface EchartsRadarChartProps extends ChartProps { +export interface EchartsRadarChartProps + extends BaseChartProps<EchartsRadarFormData> { formData: EchartsRadarFormData; - queriesData: ChartDataResponseResult[]; } // @ts-ignore @@ -74,18 +72,11 @@ export const DEFAULT_FORM_DATA: EchartsRadarFormData = { legendType: LegendType.Scroll, numberFormat: 'SMART_NUMBER', showLabels: true, - emitFilter: false, dateFormat: 'smart_date', isCircle: false, }; -export interface RadarChartTransformedProps { - formData: EchartsRadarFormData; - height: number; - width: number; - echartOptions: EChartsCoreOption; - setDataMask: SetDataMaskHook; - labelMap: Record<string, DataRecordValue[]>; - groupby: QueryFormColumn[]; - selectedValues: Record<number, string>; -} +export type RadarChartTransformedProps = + BaseTransformedProps<EchartsRadarFormData> & + ContextMenuTransformedProps & + CrossFilterTransformedProps; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx new file mode 100644 index 0000000000000..390c830c45296 --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx @@ -0,0 +1,127 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useCallback } from 'react'; +import { BinaryQueryObjectFilterClause } from '@superset-ui/core'; +import { SunburstTransformedProps } from './types'; +import Echart from '../components/Echart'; +import { EventHandlers, TreePathInfo } from '../types'; + +export const extractTreePathInfo = (treePathInfo: TreePathInfo[] | undefined) => + (treePathInfo ?? []) + .map(pathInfo => pathInfo?.name || '') + .filter(path => path !== ''); + +export default function EchartsSunburst(props: SunburstTransformedProps) { + const { + height, + width, + echartOptions, + setDataMask, + labelMap, + selectedValues, + formData, + onContextMenu, + refs, + emitCrossFilters, + } = props; + + const { columns } = formData; + + const handleChange = useCallback( + (values: string[]) => { + if (!emitCrossFilters) { + return; + } + + const labels = values.map(value => labelMap[value]); + + setDataMask({ + extraFormData: { + filters: + values.length === 0 || !columns + ? [] + : columns.map((col, idx) => { + const val = labels.map(v => v[idx]); + if (val === null || val === undefined) + return { + col, + op: 'IS NULL', + }; + return { + col, + op: 'IN', + val: val as (string | number | boolean)[], + }; + }), + }, + filterState: { + value: labels.length ? labels : null, + selectedValues: values.length ? values : null, + }, + }); + }, + [emitCrossFilters, setDataMask, columns, labelMap], + ); + + const eventHandlers: EventHandlers = { + click: props => { + const { treePathInfo } = props; + const treePath = extractTreePathInfo(treePathInfo); + const name = treePath.join(','); + const values = Object.values(selectedValues); + if (values.includes(name)) { + handleChange(values.filter(v => v !== name)); + } else { + handleChange([name]); + } + }, + contextmenu: eventParams => { + if (onContextMenu) { + eventParams.event.stop(); + const { data } = eventParams; + const { records } = data; + const treePath = extractTreePathInfo(eventParams.treePathInfo); + const pointerEvent = eventParams.event.event; + const filters: BinaryQueryObjectFilterClause[] = []; + if (columns?.length) { + treePath.forEach((path, i) => + filters.push({ + col: columns[i], + op: '==', + val: records[i], + formattedVal: path, + }), + ); + } + onContextMenu(pointerEvent.clientX, pointerEvent.clientY, filters); + } + }, + }; + + return ( + <Echart + refs={refs} + height={height} + width={width} + echartOptions={echartOptions} + eventHandlers={eventHandlers} + selectedValues={selectedValues} + /> + ); +} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/buildQuery.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/buildQuery.ts new file mode 100644 index 0000000000000..8b47fb5e725cc --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/buildQuery.ts @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { buildQueryContext, QueryFormData } from '@superset-ui/core'; + +export default function buildQuery(formData: QueryFormData) { + const { metric, sort_by_metric } = formData; + return buildQueryContext(formData, baseQueryObject => [ + { + ...baseQueryObject, + ...(sort_by_metric && { orderby: [[metric, false]] }), + }, + ]); +} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx new file mode 100644 index 0000000000000..1187fee0a8d3c --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx @@ -0,0 +1,205 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { t } from '@superset-ui/core'; +import { + ControlPanelConfig, + ControlPanelsContainerProps, + D3_FORMAT_DOCS, + D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT, + D3_FORMAT_OPTIONS, + D3_TIME_FORMAT_OPTIONS, + getStandardizedControls, + sections, +} from '@superset-ui/chart-controls'; +import { DEFAULT_FORM_DATA } from './types'; + +const { labelType, numberFormat, showLabels } = DEFAULT_FORM_DATA; + +const config: ControlPanelConfig = { + controlPanelSections: [ + sections.legacyRegularTime, + { + label: t('Query'), + expanded: true, + controlSetRows: [ + ['columns'], + ['metric'], + ['secondary_metric'], + ['adhoc_filters'], + ['row_limit'], + [ + { + name: 'sort_by_metric', + config: { + type: 'CheckboxControl', + label: t('Sort by metric'), + description: t( + 'Whether to sort results by the selected metric in descending order.', + ), + }, + }, + ], + ], + }, + { + label: t('Chart Options'), + expanded: true, + controlSetRows: [ + ['color_scheme'], + ['linear_color_scheme'], + [<div className="section-header">{t('Labels')}</div>], + [ + { + name: 'show_labels', + config: { + type: 'CheckboxControl', + label: t('Show Labels'), + renderTrigger: true, + default: showLabels, + description: t('Whether to display the labels.'), + }, + }, + ], + [ + { + name: 'show_labels_threshold', + config: { + type: 'TextControl', + label: t('Percentage threshold'), + renderTrigger: true, + isFloat: true, + default: 5, + description: t( + 'Minimum threshold in percentage points for showing labels.', + ), + }, + }, + ], + [ + { + name: 'show_total', + config: { + type: 'CheckboxControl', + label: t('Show Total'), + default: false, + renderTrigger: true, + description: t('Whether to display the aggregate count'), + }, + }, + ], + [ + { + name: 'label_type', + config: { + type: 'SelectControl', + label: t('Label Type'), + default: labelType, + renderTrigger: true, + choices: [ + ['key', t('Category Name')], + ['value', t('Value')], + ['key_value', t('Category and Value')], + ], + description: t('What should be shown on the label?'), + }, + }, + ], + [ + { + name: 'number_format', + config: { + type: 'SelectControl', + freeForm: true, + label: t('Number format'), + renderTrigger: true, + default: numberFormat, + choices: D3_FORMAT_OPTIONS, + description: `${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`, + }, + }, + ], + [ + { + name: 'date_format', + config: { + type: 'SelectControl', + freeForm: true, + label: t('Date format'), + renderTrigger: true, + choices: D3_TIME_FORMAT_OPTIONS, + default: 'smart_date', + description: D3_FORMAT_DOCS, + }, + }, + ], + ], + }, + ], + controlOverrides: { + metric: { + label: t('Primary Metric'), + description: t( + 'The primary metric is used to define the arc segment sizes', + ), + }, + secondary_metric: { + label: t('Secondary Metric'), + default: null, + description: t( + '[optional] this secondary metric is used to ' + + 'define the color as a ratio against the primary metric. ' + + 'When omitted, the color is categorical and based on labels', + ), + }, + color_scheme: { + description: t( + 'When only a primary metric is provided, a categorical color scale is used.', + ), + visibility: ({ controls }: ControlPanelsContainerProps) => + Boolean( + !controls?.secondary_metric?.value || + controls?.secondary_metric?.value === controls?.metric.value, + ), + }, + linear_color_scheme: { + description: t( + 'When a secondary metric is provided, a linear color scale is used.', + ), + visibility: ({ controls }: ControlPanelsContainerProps) => + Boolean( + controls?.secondary_metric?.value && + controls?.secondary_metric?.value !== controls?.metric.value, + ), + }, + columns: { + label: t('Hierarchy'), + description: t(`Sets the hierarchy levels of the chart. Each level is + represented by one ring with the innermost circle as the top of the hierarchy.`), + }, + }, + formDataOverrides: formData => ({ + ...formData, + groupby: getStandardizedControls().popAllColumns(), + metric: getStandardizedControls().shiftMetric(), + secondary_metric: getStandardizedControls().shiftMetric(), + }), +}; + +export default config; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/images/Sunburst1.png b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/images/Sunburst1.png new file mode 100644 index 0000000000000..87c140e7c3ed2 Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/images/Sunburst1.png differ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/images/Sunburst2.png b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/images/Sunburst2.png new file mode 100644 index 0000000000000..677b2a1966658 Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/images/Sunburst2.png differ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/images/thumbnail.png b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/images/thumbnail.png new file mode 100644 index 0000000000000..87c140e7c3ed2 Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/images/thumbnail.png differ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts new file mode 100644 index 0000000000000..5ca8d5a8fc462 --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { t, ChartMetadata, ChartPlugin, Behavior } from '@superset-ui/core'; +import transformProps from './transformProps'; +import thumbnail from './images/thumbnail.png'; +import controlPanel from './controlPanel'; +import buildQuery from './buildQuery'; +import example1 from './images/Sunburst1.png'; +import example2 from './images/Sunburst2.png'; + +export default class EchartsSunburstChartPlugin extends ChartPlugin { + constructor() { + super({ + buildQuery, + controlPanel, + loadChart: () => import('./EchartsSunburst'), + metadata: new ChartMetadata({ + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], + category: t('Part of a Whole'), + credits: ['https://echarts.apache.org'], + description: t( + 'Uses circles to visualize the flow of data through different stages of a system. Hover over individual paths in the visualization to understand the stages a value took. Useful for multi-stage, multi-group visualizing funnels and pipelines.', + ), + exampleGallery: [{ url: example1 }, { url: example2 }], + name: t('Sunburst Chart v2'), + tags: [ + t('ECharts'), + t('Aesthetic'), + t('Multi-Levels'), + t('Proportional'), + ], + thumbnail, + }), + transformProps, + }); + } +} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts new file mode 100644 index 0000000000000..51e89f8c6c73e --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts @@ -0,0 +1,381 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + CategoricalColorNamespace, + DataRecordValue, + getColumnLabel, + getMetricLabel, + getNumberFormatter, + getSequentialSchemeRegistry, + getTimeFormatter, + NumberFormats, + NumberFormatter, + SupersetTheme, + t, +} from '@superset-ui/core'; +import { EChartsCoreOption } from 'echarts'; +import { CallbackDataParams } from 'echarts/types/src/util/types'; +import { OpacityEnum } from '../constants'; +import { defaultGrid } from '../defaults'; +import { Refs } from '../types'; +import { formatSeriesName, getColtypesMapping } from '../utils/series'; +import { treeBuilder, TreeNode } from '../utils/treeBuilder'; +import { + EchartsSunburstChartProps, + EchartsSunburstLabelType, + NodeItemOption, + SunburstTransformedProps, +} from './types'; +import { getDefaultTooltip } from '../utils/tooltip'; + +export function getLinearDomain( + treeData: TreeNode[], + callback: (treeNode: TreeNode) => number, +) { + let min = 0; + let max = 0; + let temp = null; + function traverse(tree: TreeNode[]) { + tree.forEach(treeNode => { + if (treeNode.children?.length) { + traverse(treeNode.children); + } + temp = callback(treeNode); + if (temp !== null) { + if (min > temp) min = temp; + if (max < temp) max = temp; + } + }); + } + traverse(treeData); + return [min, max]; +} + +export function formatLabel({ + params, + labelType, + numberFormatter, +}: { + params: CallbackDataParams; + labelType: EchartsSunburstLabelType; + numberFormatter: NumberFormatter; +}): string { + const { name = '', value } = params; + const formattedValue = numberFormatter(value as number); + + switch (labelType) { + case EchartsSunburstLabelType.Key: + return name; + case EchartsSunburstLabelType.Value: + return formattedValue; + case EchartsSunburstLabelType.KeyValue: + return `${name}: ${formattedValue}`; + default: + return name; + } +} + +export function formatTooltip({ + params, + numberFormatter, + colorByCategory, + totalValue, + metricLabel, + secondaryMetricLabel, + theme, +}: { + params: CallbackDataParams & { + treePathInfo: { + name: string; + dataIndex: number; + value: number; + }[]; + }; + numberFormatter: NumberFormatter; + colorByCategory: boolean; + totalValue: number; + metricLabel: string; + secondaryMetricLabel?: string; + theme: SupersetTheme; +}): string { + const { data, treePathInfo = [] } = params; + const node = data as TreeNode; + const formattedValue = numberFormatter(node.value); + const formattedSecondaryValue = numberFormatter(node.secondaryValue); + + const percentFormatter = getNumberFormatter(NumberFormats.PERCENT_2_POINT); + const compareValuePercentage = percentFormatter( + node.secondaryValue / node.value, + ); + const absolutePercentage = percentFormatter(node.value / totalValue); + const parentNode = + treePathInfo.length > 2 ? treePathInfo[treePathInfo.length - 2] : undefined; + + const result = [ + `<div style=" + font-size: ${theme.typography.sizes.m}px; + color: ${theme.colors.grayscale.base}" + >`, + `<div style="font-weight: ${theme.typography.weights.bold}"> + ${node.name} + </div>`, + `<div"> + ${absolutePercentage} of total + </div>`, + ]; + if (parentNode) { + const conditionalPercentage = percentFormatter( + node.value / parentNode.value, + ); + result.push(` + <div> + ${conditionalPercentage} of ${parentNode.name} + </div>`); + } + result.push( + `<div> + ${metricLabel}: ${formattedValue}${ + colorByCategory + ? '' + : `, ${secondaryMetricLabel}: ${formattedSecondaryValue}` + } + </div>`, + colorByCategory + ? '' + : `<div>${metricLabel}/${secondaryMetricLabel}: ${compareValuePercentage}</div>`, + ); + result.push('</div>'); + return result.join('\n'); +} + +export default function transformProps( + chartProps: EchartsSunburstChartProps, +): SunburstTransformedProps { + const { + formData, + height, + hooks, + filterState, + queriesData, + width, + theme, + inContextMenu, + emitCrossFilters, + } = chartProps; + const { data = [] } = queriesData[0]; + const coltypeMapping = getColtypesMapping(queriesData[0]); + const { + groupby = [], + columns = [], + metric = '', + secondaryMetric = '', + colorScheme, + linearColorScheme, + labelType, + numberFormat, + dateFormat, + showLabels, + showLabelsThreshold, + showTotal, + sliceId, + } = formData; + const refs: Refs = {}; + const numberFormatter = getNumberFormatter(numberFormat); + const formatter = (params: CallbackDataParams) => + formatLabel({ + params, + numberFormatter, + labelType, + }); + const minShowLabelAngle = (showLabelsThreshold || 0) * 3.6; + const padding = { + top: theme.gridUnit * 3, + right: theme.gridUnit, + bottom: theme.gridUnit * 3, + left: theme.gridUnit, + }; + const containerWidth = width; + const containerHeight = height; + const visWidth = containerWidth - padding.left - padding.right; + const visHeight = containerHeight - padding.top - padding.bottom; + const radius = Math.min(visWidth, visHeight) / 2; + const { setDataMask = () => {}, onContextMenu } = hooks; + const columnsLabelMap = new Map<string, string[]>(); + const metricLabel = getMetricLabel(metric); + const secondaryMetricLabel = secondaryMetric + ? getMetricLabel(secondaryMetric) + : undefined; + const columnLabels = columns.map(getColumnLabel); + const treeData = treeBuilder( + data, + columnLabels, + metricLabel, + secondaryMetricLabel, + ); + const totalValue = treeData.reduce( + (result, treeNode) => result + treeNode.value, + 0, + ); + const totalSecondaryValue = treeData.reduce( + (result, treeNode) => result + treeNode.secondaryValue, + 0, + ); + + const categoricalColorScale = CategoricalColorNamespace.getScale( + colorScheme as string, + ); + let linearColorScale: any; + let colorByCategory = true; + if (secondaryMetric && metric !== secondaryMetric) { + const domain = getLinearDomain( + treeData, + node => node.secondaryValue / node.value, + ); + colorByCategory = false; + linearColorScale = getSequentialSchemeRegistry() + ?.get(linearColorScheme) + ?.createLinearScale(domain); + } + + // add a base color to keep feature parity + if (colorByCategory) { + categoricalColorScale(metricLabel, sliceId); + } else { + linearColorScale(totalSecondaryValue / totalValue); + } + + const traverse = ( + treeNodes: TreeNode[], + path: string[], + pathRecords?: DataRecordValue[], + ) => + treeNodes.map(treeNode => { + const { name: nodeName, value, secondaryValue, groupBy } = treeNode; + const records = [...(pathRecords || []), nodeName]; + let name = formatSeriesName(nodeName, { + numberFormatter, + timeFormatter: getTimeFormatter(dateFormat), + ...(coltypeMapping[groupBy] && { + coltype: coltypeMapping[groupBy], + }), + }); + const newPath = path.concat(name); + let item: NodeItemOption = { + records, + name, + value, + secondaryValue, + itemStyle: { + color: colorByCategory + ? categoricalColorScale(name, sliceId) + : linearColorScale(secondaryValue / value), + }, + }; + if (treeNode.children?.length) { + item.children = traverse(treeNode.children, newPath, records); + } else { + name = newPath.join(','); + } + columnsLabelMap.set(name, newPath); + if (filterState.selectedValues?.[0]?.includes(name) === false) { + item = { + ...item, + itemStyle: { + ...item.itemStyle, + opacity: OpacityEnum.SemiTransparent, + }, + label: { + color: `rgba(0, 0, 0, ${OpacityEnum.SemiTransparent})`, + }, + }; + } + return item; + }); + + const echartOptions: EChartsCoreOption = { + grid: { + ...defaultGrid, + }, + tooltip: { + ...getDefaultTooltip(refs), + show: !inContextMenu, + trigger: 'item', + formatter: (params: any) => + formatTooltip({ + params, + numberFormatter, + colorByCategory, + totalValue, + metricLabel, + secondaryMetricLabel, + theme, + }), + }, + series: [ + { + type: 'sunburst', + ...padding, + nodeClick: false, + emphasis: { + focus: 'ancestor', + label: { + show: showLabels, + }, + }, + label: { + width: (radius * 0.6) / (columns.length || 1), + show: showLabels, + formatter, + color: theme.colors.grayscale.dark2, + minAngle: minShowLabelAngle, + overflow: 'breakAll', + }, + radius: [radius * 0.3, radius], + data: traverse(treeData, []), + }, + ], + graphic: showTotal + ? { + type: 'text', + top: 'center', + left: 'center', + style: { + text: t('Total: %s', numberFormatter(totalValue)), + fontSize: 16, + fontWeight: 'bold', + }, + z: 10, + } + : null, + }; + + return { + formData, + width, + height, + echartOptions, + setDataMask, + emitCrossFilters, + labelMap: Object.fromEntries(columnsLabelMap), + groupby, + selectedValues: filterState.selectedValues || [], + onContextMenu, + refs, + }; +} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/types.ts new file mode 100644 index 0000000000000..37844addea496 --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/types.ts @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + ChartDataResponseResult, + ChartProps, + DataRecordValue, + QueryFormColumn, + QueryFormData, + QueryFormMetric, +} from '@superset-ui/core'; +import { SunburstSeriesNodeItemOption } from 'echarts/types/src/chart/sunburst/SunburstSeries'; +import { + BaseTransformedProps, + ContextMenuTransformedProps, + CrossFilterTransformedProps, +} from '../types'; + +export type EchartsSunburstFormData = QueryFormData & { + groupby: QueryFormColumn[]; + metric: QueryFormMetric; + secondaryMetric?: QueryFormMetric; + colorScheme?: string; + linearColorScheme?: string; +}; + +export enum EchartsSunburstLabelType { + Key = 'key', + Value = 'value', + KeyValue = 'key_value', +} + +export const DEFAULT_FORM_DATA: Partial<EchartsSunburstFormData> = { + groupby: [], + numberFormat: 'SMART_NUMBER', + labelType: EchartsSunburstLabelType.Key, + showLabels: false, + dateFormat: 'smart_date', +}; + +export interface EchartsSunburstChartProps + extends ChartProps<EchartsSunburstFormData> { + formData: EchartsSunburstFormData; + queriesData: ChartDataResponseResult[]; +} + +export type SunburstTransformedProps = + BaseTransformedProps<EchartsSunburstFormData> & + ContextMenuTransformedProps & + CrossFilterTransformedProps; + +export type NodeItemOption = SunburstSeriesNodeItemOption & { + records: DataRecordValue[]; + secondaryValue: number; +}; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx index c8922dd11e58b..82ca0b585d67c 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx @@ -17,32 +17,27 @@ * under the License. */ import React from 'react'; -import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; +import { t } from '@superset-ui/core'; import { ControlPanelConfig, ControlPanelsContainerProps, D3_TIME_FORMAT_DOCS, - emitFilterControl, + getStandardizedControls, sections, sharedControls, } from '@superset-ui/chart-controls'; -import { - DEFAULT_FORM_DATA, - EchartsTimeseriesContributionType, - EchartsTimeseriesSeriesType, -} from '../types'; +import { EchartsTimeseriesSeriesType } from '../types'; +import { DEFAULT_FORM_DATA, TIME_SERIES_DESCRIPTION_TEXT } from '../constants'; import { legendSection, onlyTotalControl, showValueControl, richTooltipSection, - xAxisControl, } from '../../controls'; import { AreaChartExtraControlsOptions } from '../../constants'; const { - contributionMode, logAxis, markerEnabled, markerSize, @@ -57,39 +52,8 @@ const { } = DEFAULT_FORM_DATA; const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, - { - label: t('Query'), - expanded: true, - controlSetRows: [ - isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) ? [xAxisControl] : [], - ['metrics'], - ['groupby'], - [ - { - name: 'contributionMode', - config: { - type: 'SelectControl', - label: t('Contribution Mode'), - default: contributionMode, - choices: [ - [null, 'None'], - [EchartsTimeseriesContributionType.Row, 'Row'], - [EchartsTimeseriesContributionType.Column, 'Series'], - ], - description: t('Calculate contribution per series or row'), - }, - }, - ], - ['adhoc_filters'], - emitFilterControl, - ['limit'], - ['timeseries_limit_metric'], - ['order_desc'], - ['row_limit'], - ['truncate_metric'], - ], - }, + sections.genericTime, + sections.echartsTimeSeriesQuery, sections.advancedAnalyticsControls, sections.annotationsAndLayersControls, sections.forecastIntervalControls, @@ -108,11 +72,11 @@ const config: ControlPanelConfig = { renderTrigger: true, default: seriesType, choices: [ - [EchartsTimeseriesSeriesType.Line, 'Line'], - [EchartsTimeseriesSeriesType.Smooth, 'Smooth Line'], - [EchartsTimeseriesSeriesType.Start, 'Step - start'], - [EchartsTimeseriesSeriesType.Middle, 'Step - middle'], - [EchartsTimeseriesSeriesType.End, 'Step - end'], + [EchartsTimeseriesSeriesType.Line, t('Line')], + [EchartsTimeseriesSeriesType.Smooth, t('Smooth Line')], + [EchartsTimeseriesSeriesType.Start, t('Step - start')], + [EchartsTimeseriesSeriesType.Middle, t('Step - middle')], + [EchartsTimeseriesSeriesType.End, t('Step - end')], ], description: t('Series chart type (line, bar etc)'), }, @@ -218,9 +182,7 @@ const config: ControlPanelConfig = { config: { ...sharedControls.x_axis_time_format, default: 'smart_date', - description: `${D3_TIME_FORMAT_DOCS}. ${t( - 'When using other than adaptive formatting, labels may overlap.', - )}`, + description: `${D3_TIME_FORMAT_DOCS}. ${TIME_SERIES_DESCRIPTION_TEXT}`, }, }, ], @@ -313,10 +275,10 @@ const config: ControlPanelConfig = { default: rowLimit, }, }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, - groupby: formData.standardizedFormData.standardizedState.columns, + metrics: getStandardizedControls().popAllMetrics(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts index ee7c89993cb7e..b560cf0b4f795 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts @@ -22,8 +22,7 @@ import { ChartPlugin, AnnotationType, Behavior, - isFeatureEnabled, - FeatureFlag, + hasGenericChartAxes, } from '@superset-ui/core'; import buildQuery from '../buildQuery'; import controlPanel from './controlPanel'; @@ -51,10 +50,10 @@ export default class EchartsAreaChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('../EchartsTimeseries'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Evolution'), credits: ['https://echarts.apache.org'], - description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + description: hasGenericChartAxes ? t( 'Area charts are similar to line charts in that they represent variables with the same scale, but area charts stack the metrics on top of each other.', ) @@ -68,8 +67,8 @@ export default class EchartsAreaChartPlugin extends ChartPlugin< AnnotationType.Interval, AnnotationType.Timeseries, ], - name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) - ? t('Area Chart v2') + name: hasGenericChartAxes + ? t('Area Chart') : t('Time-series Area Chart'), tags: [ t('ECharts'), diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx index a9947e0d5520e..0cf7f3cf192cd 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx @@ -16,7 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useCallback, useRef } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { + DTTM_ALIAS, + BinaryQueryObjectFilterClause, + AxisType, +} from '@superset-ui/core'; import { ViewRootGroup } from 'echarts/types/src/util/types'; import GlobalModel from 'echarts/types/src/model/Global'; import ComponentModel from 'echarts/types/src/model/Component'; @@ -40,12 +45,25 @@ export default function EchartsTimeseries({ setDataMask, setControlValue, legendData = [], + onContextMenu, + xValueFormatter, + xAxis, + refs, + emitCrossFilters, }: TimeseriesChartTransformedProps) { - const { emitFilter, stack } = formData; + const { stack } = formData; const echartRef = useRef<EchartsHandler | null>(null); + // eslint-disable-next-line no-param-reassign + refs.echartRef = echartRef; const lastTimeRef = useRef(Date.now()); const lastSelectedLegend = useRef(''); const clickTimer = useRef<ReturnType<typeof setTimeout>>(); + const extraControlRef = useRef<HTMLDivElement>(null); + const [extraControlHeight, setExtraControlHeight] = useState(0); + useEffect(() => { + const updatedHeight = extraControlRef.current?.offsetHeight || 0; + setExtraControlHeight(updatedHeight); + }, [formData.showExtraControls]); const handleDoubleClickChange = useCallback( (name?: string) => { @@ -92,7 +110,7 @@ export default function EchartsTimeseries({ const handleChange = useCallback( (values: string[]) => { - if (!emitFilter) { + if (!emitCrossFilters) { return; } const groupbyValues = values.map(value => labelMap[value]); @@ -123,7 +141,7 @@ export default function EchartsTimeseries({ }, }); }, - [groupby, labelMap, setDataMask, emitFilter], + [groupby, labelMap, setDataMask, emitCrossFilters], ); const eventHandlers: EventHandlers = { @@ -167,6 +185,45 @@ export default function EchartsTimeseries({ handleDoubleClickChange(); } }, + contextmenu: eventParams => { + if (onContextMenu) { + eventParams.event.stop(); + const { data } = eventParams; + if (data) { + const pointerEvent = eventParams.event.event; + const values = [ + ...(eventParams.name ? [eventParams.name] : []), + ...labelMap[eventParams.seriesName], + ]; + const filters: BinaryQueryObjectFilterClause[] = []; + if (xAxis.type === AxisType.time) { + filters.push({ + col: + // if the xAxis is '__timestamp', granularity_sqla will be the column of filter + xAxis.label === DTTM_ALIAS + ? formData.granularitySqla + : xAxis.label, + grain: formData.timeGrainSqla, + op: '==', + val: data[0], + formattedVal: xValueFormatter(data[0]), + }); + } + [ + ...(xAxis.type === AxisType.category ? [xAxis.label] : []), + ...formData.groupby, + ].forEach((dimension, i) => + filters.push({ + col: dimension, + op: '==', + val: values[i], + formattedVal: String(values[i]), + }), + ); + onContextMenu(pointerEvent.clientX, pointerEvent.clientY, filters); + } + } + }, }; const zrEventHandlers: EventHandlers = { @@ -199,10 +256,12 @@ export default function EchartsTimeseries({ return ( <> - <ExtraControls formData={formData} setControlValue={setControlValue} /> + <div ref={extraControlRef}> + <ExtraControls formData={formData} setControlValue={setControlValue} /> + </div> <Echart - ref={echartRef} - height={height} + refs={refs} + height={height - extraControlHeight} width={width} echartOptions={echartOptions} eventHandlers={eventHandlers} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx index 1992f4a45609e..509dc6c815f60 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx @@ -17,36 +17,33 @@ * under the License. */ import React from 'react'; -import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; +import { t } from '@superset-ui/core'; import { ControlPanelConfig, ControlPanelsContainerProps, ControlSetRow, ControlStateMapping, D3_TIME_FORMAT_DOCS, - emitFilterControl, formatSelectOptions, + getStandardizedControls, sections, sharedControls, } from '@superset-ui/chart-controls'; +import { OrientationType } from '../../types'; import { DEFAULT_FORM_DATA, - EchartsTimeseriesContributionType, - OrientationType, -} from '../../types'; + TIME_SERIES_DESCRIPTION_TEXT, +} from '../../constants'; import { legendSection, richTooltipSection, showValueSection, - xAxisControl, } from '../../../controls'; const { - contributionMode, logAxis, minorSplitLine, - rowLimit, truncateYAxis, yAxisBounds, zoomable, @@ -58,7 +55,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] { const isXAxis = axis === 'x'; const isVertical = (controls: ControlStateMapping) => Boolean(controls?.orientation.value === OrientationType.vertical); - const isHorizental = (controls: ControlStateMapping) => + const isHorizontal = (controls: ControlStateMapping) => Boolean(controls?.orientation.value === OrientationType.horizontal); return [ [ @@ -71,7 +68,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] { default: '', description: t('Changing this control takes effect instantly'), visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isVertical(controls) : isHorizental(controls), + isXAxis ? isVertical(controls) : isHorizontal(controls), }, }, ], @@ -88,7 +85,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] { choices: formatSelectOptions(sections.TITLE_MARGIN_OPTIONS), description: t('Changing this control takes effect instantly'), visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isVertical(controls) : isHorizental(controls), + isXAxis ? isVertical(controls) : isHorizontal(controls), }, }, ], @@ -102,7 +99,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] { default: '', description: t('Changing this control takes effect instantly'), visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isHorizental(controls) : isVertical(controls), + isXAxis ? isHorizontal(controls) : isVertical(controls), }, }, ], @@ -119,7 +116,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] { choices: formatSelectOptions(sections.TITLE_MARGIN_OPTIONS), description: t('Changing this control takes effect instantly'), visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isHorizental(controls) : isVertical(controls), + isXAxis ? isHorizontal(controls) : isVertical(controls), }, }, ], @@ -132,11 +129,11 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] { clearable: false, label: t('AXIS TITLE POSITION'), renderTrigger: true, - default: sections.TITLE_POSITION_OPTIONS[0], - choices: formatSelectOptions(sections.TITLE_POSITION_OPTIONS), + default: sections.TITLE_POSITION_OPTIONS[0][0], + choices: sections.TITLE_POSITION_OPTIONS, description: t('Changing this control takes effect instantly'), visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isHorizental(controls) : isVertical(controls), + isXAxis ? isHorizontal(controls) : isVertical(controls), }, }, ], @@ -147,7 +144,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] { const isXAxis = axis === 'x'; const isVertical = (controls: ControlStateMapping) => Boolean(controls?.orientation.value === OrientationType.vertical); - const isHorizental = (controls: ControlStateMapping) => + const isHorizontal = (controls: ControlStateMapping) => Boolean(controls?.orientation.value === OrientationType.horizontal); return [ [ @@ -156,11 +153,9 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] { config: { ...sharedControls.x_axis_time_format, default: 'smart_date', - description: `${D3_TIME_FORMAT_DOCS}. ${t( - 'When using other than adaptive formatting, labels may overlap.', - )}`, + description: `${D3_TIME_FORMAT_DOCS}. ${TIME_SERIES_DESCRIPTION_TEXT}`, visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isVertical(controls) : isHorizental(controls), + isXAxis ? isVertical(controls) : isHorizontal(controls), }, }, ], @@ -182,7 +177,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] { 'Input field supports custom rotation. e.g. 30 for 30°', ), visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isVertical(controls) : isHorizental(controls), + isXAxis ? isVertical(controls) : isHorizontal(controls), }, }, ], @@ -193,7 +188,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] { ...sharedControls.y_axis_format, label: t('Axis Format'), visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isHorizental(controls) : isVertical(controls), + isXAxis ? isHorizontal(controls) : isVertical(controls), }, }, ], @@ -207,7 +202,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] { default: logAxis, description: t('Logarithmic axis'), visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isHorizental(controls) : isVertical(controls), + isXAxis ? isHorizontal(controls) : isVertical(controls), }, }, ], @@ -221,7 +216,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] { default: minorSplitLine, description: t('Draw split lines for minor axis ticks'), visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isHorizental(controls) : isVertical(controls), + isXAxis ? isHorizontal(controls) : isVertical(controls), }, }, ], @@ -235,7 +230,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] { renderTrigger: true, description: t('It’s not recommended to truncate axis in Bar chart.'), visibility: ({ controls }: ControlPanelsContainerProps) => - isXAxis ? isHorizental(controls) : isVertical(controls), + isXAxis ? isHorizontal(controls) : isVertical(controls), }, }, ], @@ -255,7 +250,7 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] { ), visibility: ({ controls }: ControlPanelsContainerProps) => Boolean(controls?.truncateYAxis?.value) && - (isXAxis ? isHorizental(controls) : isVertical(controls)), + (isXAxis ? isHorizontal(controls) : isVertical(controls)), }, }, ], @@ -264,39 +259,8 @@ function createAxisControl(axis: 'x' | 'y'): ControlSetRow[] { const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, - { - label: t('Query'), - expanded: true, - controlSetRows: [ - isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) ? [xAxisControl] : [], - ['metrics'], - ['groupby'], - [ - { - name: 'contributionMode', - config: { - type: 'SelectControl', - label: t('Contribution Mode'), - default: contributionMode, - choices: [ - [null, 'None'], - [EchartsTimeseriesContributionType.Row, 'Row'], - [EchartsTimeseriesContributionType.Column, 'Series'], - ], - description: t('Calculate contribution per series or row'), - }, - }, - ], - ['adhoc_filters'], - emitFilterControl, - ['limit'], - ['timeseries_limit_metric'], - ['order_desc'], - ['row_limit'], - ['truncate_metric'], - ], - }, + sections.genericTime, + sections.echartsTimeSeriesQueryWithXAxisSort, sections.advancedAnalyticsControls, sections.annotationsAndLayersControls, sections.forecastIntervalControls, @@ -360,15 +324,10 @@ const config: ControlPanelConfig = { ], }, ], - controlOverrides: { - row_limit: { - default: rowLimit, - }, - }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, - groupby: formData.standardizedFormData.standardizedState.columns, + metrics: getStandardizedControls().popAllMetrics(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts index 0ffc09098c70b..de0050edaa94b 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts @@ -21,19 +21,18 @@ import { Behavior, ChartMetadata, ChartPlugin, - FeatureFlag, - isFeatureEnabled, + hasGenericChartAxes, t, } from '@superset-ui/core'; -import buildQuery from '../../buildQuery'; -import controlPanel from './controlPanel'; -import transformProps from '../../transformProps'; -import thumbnail from './images/thumbnail.png'; import { EchartsTimeseriesChartProps, EchartsTimeseriesFormData, EchartsTimeseriesSeriesType, } from '../../types'; +import buildQuery from '../../buildQuery'; +import controlPanel from './controlPanel'; +import transformProps from '../../transformProps'; +import thumbnail from './images/thumbnail.png'; import example1 from './images/Bar1.png'; import example2 from './images/Bar2.png'; import example3 from './images/Bar3.png'; @@ -57,10 +56,10 @@ export default class EchartsTimeseriesBarChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('../../EchartsTimeseries'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Evolution'), credits: ['https://echarts.apache.org'], - description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + description: hasGenericChartAxes ? t('Bar Charts are used to show metrics as a series of bars.') : t( 'Time-series Bar Charts are used to show the changes in a metric over time as a series of bars.', @@ -76,9 +75,7 @@ export default class EchartsTimeseriesBarChartPlugin extends ChartPlugin< AnnotationType.Interval, AnnotationType.Timeseries, ], - name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) - ? t('Bar Chart v2') - : t('Time-series Bar Chart v2'), + name: hasGenericChartAxes ? t('Bar Chart') : t('Time-series Bar Chart'), tags: [ t('ECharts'), t('Predictive'), diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx similarity index 78% rename from superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx rename to superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx index d039a059c590a..0ceb518b88343 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx @@ -17,31 +17,29 @@ * under the License. */ import React from 'react'; -import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; +import { t } from '@superset-ui/core'; import { ControlPanelConfig, ControlPanelsContainerProps, D3_TIME_FORMAT_DOCS, + getStandardizedControls, sections, sharedControls, - emitFilterControl, } from '@superset-ui/chart-controls'; +import { EchartsTimeseriesSeriesType } from '../../types'; import { DEFAULT_FORM_DATA, - EchartsTimeseriesContributionType, - EchartsTimeseriesSeriesType, -} from './types'; + TIME_SERIES_DESCRIPTION_TEXT, +} from '../../constants'; import { legendSection, richTooltipSection, showValueSection, - xAxisControl, -} from '../controls'; +} from '../../../controls'; const { area, - contributionMode, logAxis, markerEnabled, markerSize, @@ -56,39 +54,8 @@ const { } = DEFAULT_FORM_DATA; const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, - { - label: t('Query'), - expanded: true, - controlSetRows: [ - isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) ? [xAxisControl] : [], - ['metrics'], - ['groupby'], - [ - { - name: 'contributionMode', - config: { - type: 'SelectControl', - label: t('Contribution Mode'), - default: contributionMode, - choices: [ - [null, 'None'], - [EchartsTimeseriesContributionType.Row, 'Row'], - [EchartsTimeseriesContributionType.Column, 'Series'], - ], - description: t('Calculate contribution per series or row'), - }, - }, - ], - ['adhoc_filters'], - emitFilterControl, - ['limit'], - ['timeseries_limit_metric'], - ['order_desc'], - ['row_limit'], - ['truncate_metric'], - ], - }, + sections.genericTime, + sections.echartsTimeSeriesQuery, sections.advancedAnalyticsControls, sections.annotationsAndLayersControls, sections.forecastIntervalControls, @@ -107,13 +74,13 @@ const config: ControlPanelConfig = { renderTrigger: true, default: seriesType, choices: [ - [EchartsTimeseriesSeriesType.Line, 'Line'], - [EchartsTimeseriesSeriesType.Scatter, 'Scatter'], - [EchartsTimeseriesSeriesType.Smooth, 'Smooth Line'], - [EchartsTimeseriesSeriesType.Bar, 'Bar'], - [EchartsTimeseriesSeriesType.Start, 'Step - start'], - [EchartsTimeseriesSeriesType.Middle, 'Step - middle'], - [EchartsTimeseriesSeriesType.End, 'Step - end'], + [EchartsTimeseriesSeriesType.Line, t('Line')], + [EchartsTimeseriesSeriesType.Scatter, t('Scatter')], + [EchartsTimeseriesSeriesType.Smooth, t('Smooth Line')], + [EchartsTimeseriesSeriesType.Bar, t('Bar')], + [EchartsTimeseriesSeriesType.Start, t('Step - start')], + [EchartsTimeseriesSeriesType.Middle, t('Step - middle')], + [EchartsTimeseriesSeriesType.End, t('Step - end')], ], description: t('Series chart type (line, bar etc)'), }, @@ -205,9 +172,7 @@ const config: ControlPanelConfig = { config: { ...sharedControls.x_axis_time_format, default: 'smart_date', - description: `${D3_TIME_FORMAT_DOCS}. ${t( - 'When using other than adaptive formatting, labels may overlap.', - )}`, + description: `${D3_TIME_FORMAT_DOCS}. ${TIME_SERIES_DESCRIPTION_TEXT}`, }, }, ], @@ -300,10 +265,10 @@ const config: ControlPanelConfig = { default: rowLimit, }, }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, - groupby: formData.standardizedFormData.standardizedState.columns, + metrics: getStandardizedControls().popAllMetrics(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts index 6f4a780c36fc3..b6f7f1fceb2bf 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts @@ -21,19 +21,18 @@ import { Behavior, ChartMetadata, ChartPlugin, - FeatureFlag, - isFeatureEnabled, + hasGenericChartAxes, t, } from '@superset-ui/core'; -import buildQuery from '../../buildQuery'; -import controlPanel from '../controlPanel'; -import transformProps from '../../transformProps'; -import thumbnail from './images/thumbnail.png'; import { EchartsTimeseriesChartProps, EchartsTimeseriesFormData, EchartsTimeseriesSeriesType, } from '../../types'; +import buildQuery from '../../buildQuery'; +import controlPanel from './controlPanel'; +import transformProps from '../../transformProps'; +import thumbnail from './images/thumbnail.png'; import example1 from './images/Line1.png'; import example2 from './images/Line2.png'; @@ -56,10 +55,10 @@ export default class EchartsTimeseriesLineChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('../../EchartsTimeseries'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Evolution'), credits: ['https://echarts.apache.org'], - description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + description: hasGenericChartAxes ? t( 'Line chart is used to visualize measurements taken over a given category. Line chart is a type of chart which displays information as a series of data points connected by straight line segments. It is a basic type of chart common in many fields.', ) @@ -73,7 +72,7 @@ export default class EchartsTimeseriesLineChartPlugin extends ChartPlugin< AnnotationType.Interval, AnnotationType.Timeseries, ], - name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + name: hasGenericChartAxes ? t('Line Chart') : t('Time-series Line Chart'), tags: [ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx index fd2fa79651305..9e36db0d3b3a3 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx @@ -17,22 +17,24 @@ * under the License. */ import React from 'react'; -import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; +import { t } from '@superset-ui/core'; import { ControlPanelConfig, ControlPanelsContainerProps, D3_TIME_FORMAT_DOCS, - emitFilterControl, + getStandardizedControls, sections, sharedControls, } from '@superset-ui/chart-controls'; -import { DEFAULT_FORM_DATA } from '../../types'; +import { + DEFAULT_FORM_DATA, + TIME_SERIES_DESCRIPTION_TEXT, +} from '../../constants'; import { legendSection, richTooltipSection, showValueSection, - xAxisControl, } from '../../../controls'; const { @@ -48,23 +50,8 @@ const { } = DEFAULT_FORM_DATA; const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, - { - label: t('Query'), - expanded: true, - controlSetRows: [ - isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) ? [xAxisControl] : [], - ['metrics'], - ['groupby'], - ['adhoc_filters'], - emitFilterControl, - ['limit'], - ['timeseries_limit_metric'], - ['order_desc'], - ['row_limit'], - ['truncate_metric'], - ], - }, + sections.genericTime, + sections.echartsTimeSeriesQuery, sections.advancedAnalyticsControls, sections.annotationsAndLayersControls, sections.forecastIntervalControls, @@ -128,9 +115,7 @@ const config: ControlPanelConfig = { config: { ...sharedControls.x_axis_time_format, default: 'smart_date', - description: `${D3_TIME_FORMAT_DOCS}. ${t( - 'When using other than adaptive formatting, labels may overlap.', - )}`, + description: `${D3_TIME_FORMAT_DOCS}. ${TIME_SERIES_DESCRIPTION_TEXT}`, }, }, ], @@ -224,10 +209,10 @@ const config: ControlPanelConfig = { default: rowLimit, }, }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, - groupby: formData.standardizedFormData.standardizedState.columns, + metrics: getStandardizedControls().popAllMetrics(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts index 7c77868a58451..489983cfa6066 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts @@ -21,19 +21,18 @@ import { Behavior, ChartMetadata, ChartPlugin, - FeatureFlag, - isFeatureEnabled, + hasGenericChartAxes, t, } from '@superset-ui/core'; -import buildQuery from '../../buildQuery'; -import controlPanel from './controlPanel'; -import transformProps from '../../transformProps'; -import thumbnail from './images/thumbnail.png'; import { EchartsTimeseriesChartProps, EchartsTimeseriesFormData, EchartsTimeseriesSeriesType, } from '../../types'; +import buildQuery from '../../buildQuery'; +import controlPanel from './controlPanel'; +import transformProps from '../../transformProps'; +import thumbnail from './images/thumbnail.png'; import example1 from './images/Scatter1.png'; const scatterTransformProps = (chartProps: EchartsTimeseriesChartProps) => @@ -55,10 +54,10 @@ export default class EchartsTimeseriesScatterChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('../../EchartsTimeseries'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Evolution'), credits: ['https://echarts.apache.org'], - description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + description: hasGenericChartAxes ? t( 'Scatter Plot has the horizontal axis in linear units, and the points are connected in order. It shows a statistical relationship between two variables.', ) @@ -72,7 +71,7 @@ export default class EchartsTimeseriesScatterChartPlugin extends ChartPlugin< AnnotationType.Interval, AnnotationType.Timeseries, ], - name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + name: hasGenericChartAxes ? t('Scatter Plot') : t('Time-series Scatter Plot'), tags: [ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx similarity index 79% rename from superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx rename to superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx index 8dc34861b1335..bfb7671ddbf30 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx @@ -17,26 +17,27 @@ * under the License. */ import React from 'react'; -import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; +import { t } from '@superset-ui/core'; import { ControlPanelConfig, ControlPanelsContainerProps, D3_TIME_FORMAT_DOCS, - emitFilterControl, + getStandardizedControls, sections, sharedControls, } from '@superset-ui/chart-controls'; -import { DEFAULT_FORM_DATA, EchartsTimeseriesContributionType } from '../types'; +import { + DEFAULT_FORM_DATA, + TIME_SERIES_DESCRIPTION_TEXT, +} from '../../constants'; import { legendSection, richTooltipSection, showValueSectionWithoutStack, - xAxisControl, -} from '../../controls'; +} from '../../../controls'; const { - contributionMode, logAxis, markerEnabled, markerSize, @@ -49,39 +50,8 @@ const { } = DEFAULT_FORM_DATA; const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, - { - label: t('Query'), - expanded: true, - controlSetRows: [ - isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) ? [xAxisControl] : [], - ['metrics'], - ['groupby'], - [ - { - name: 'contributionMode', - config: { - type: 'SelectControl', - label: t('Contribution Mode'), - default: contributionMode, - choices: [ - [null, 'None'], - [EchartsTimeseriesContributionType.Row, 'Row'], - [EchartsTimeseriesContributionType.Column, 'Series'], - ], - description: t('Calculate contribution per series or row'), - }, - }, - ], - ['adhoc_filters'], - emitFilterControl, - ['limit'], - ['timeseries_limit_metric'], - ['order_desc'], - ['row_limit'], - ['truncate_metric'], - ], - }, + sections.genericTime, + sections.echartsTimeSeriesQuery, sections.advancedAnalyticsControls, sections.annotationsAndLayersControls, sections.forecastIntervalControls, @@ -144,9 +114,7 @@ const config: ControlPanelConfig = { config: { ...sharedControls.x_axis_time_format, default: 'smart_date', - description: `${D3_TIME_FORMAT_DOCS}. ${t( - 'When using other than adaptive formatting, labels may overlap.', - )}`, + description: `${D3_TIME_FORMAT_DOCS}. ${TIME_SERIES_DESCRIPTION_TEXT}`, }, }, ], @@ -241,10 +209,10 @@ const config: ControlPanelConfig = { default: rowLimit, }, }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, - groupby: formData.standardizedFormData.standardizedState.columns, + metrics: getStandardizedControls().popAllMetrics(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts index ee348b272cd45..ae6dc7ad30bc2 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts @@ -21,19 +21,18 @@ import { Behavior, ChartMetadata, ChartPlugin, - FeatureFlag, - isFeatureEnabled, + hasGenericChartAxes, t, } from '@superset-ui/core'; -import buildQuery from '../../buildQuery'; -import controlPanel from '../controlPanel'; -import transformProps from '../../transformProps'; -import thumbnail from './images/thumbnail.png'; import { EchartsTimeseriesChartProps, EchartsTimeseriesFormData, EchartsTimeseriesSeriesType, } from '../../types'; +import buildQuery from '../../buildQuery'; +import controlPanel from './controlPanel'; +import transformProps from '../../transformProps'; +import thumbnail from './images/thumbnail.png'; import example1 from './images/SmoothLine1.png'; const smoothTransformProps = (chartProps: EchartsTimeseriesChartProps) => @@ -55,10 +54,10 @@ export default class EchartsTimeseriesSmoothLineChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('../../EchartsTimeseries'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Evolution'), credits: ['https://echarts.apache.org'], - description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + description: hasGenericChartAxes ? t( 'Smooth-line is a variation of the line chart. Without angles and hard edges, Smooth-line sometimes looks smarter and more professional.', ) @@ -72,7 +71,7 @@ export default class EchartsTimeseriesSmoothLineChartPlugin extends ChartPlugin< AnnotationType.Interval, AnnotationType.Timeseries, ], - name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + name: hasGenericChartAxes ? t('Smooth Line') : t('Time-series Smooth Line'), tags: [ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx index 2902937333860..6a8e6eef1778b 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx @@ -17,31 +17,26 @@ * under the License. */ import React from 'react'; -import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; +import { t } from '@superset-ui/core'; import { ControlPanelConfig, ControlPanelsContainerProps, D3_TIME_FORMAT_DOCS, + getStandardizedControls, sections, sharedControls, - emitFilterControl, } from '@superset-ui/chart-controls'; -import { - DEFAULT_FORM_DATA, - EchartsTimeseriesContributionType, - EchartsTimeseriesSeriesType, -} from '../types'; +import { EchartsTimeseriesSeriesType } from '../../types'; +import { DEFAULT_FORM_DATA, TIME_SERIES_DESCRIPTION_TEXT } from '../constants'; import { legendSection, richTooltipSection, showValueSection, - xAxisControl, } from '../../controls'; const { area, - contributionMode, logAxis, markerEnabled, markerSize, @@ -55,39 +50,8 @@ const { } = DEFAULT_FORM_DATA; const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, - { - label: t('Query'), - expanded: true, - controlSetRows: [ - isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) ? [xAxisControl] : [], - ['metrics'], - ['groupby'], - [ - { - name: 'contributionMode', - config: { - type: 'SelectControl', - label: t('Contribution Mode'), - default: contributionMode, - choices: [ - [null, 'None'], - [EchartsTimeseriesContributionType.Row, 'Row'], - [EchartsTimeseriesContributionType.Column, 'Series'], - ], - description: t('Calculate contribution per series or row'), - }, - }, - ], - ['adhoc_filters'], - emitFilterControl, - ['limit'], - ['timeseries_limit_metric'], - ['order_desc'], - ['row_limit'], - ['truncate_metric'], - ], - }, + sections.genericTime, + sections.echartsTimeSeriesQuery, sections.advancedAnalyticsControls, sections.annotationsAndLayersControls, sections.forecastIntervalControls, @@ -106,9 +70,9 @@ const config: ControlPanelConfig = { renderTrigger: true, default: EchartsTimeseriesSeriesType.Start, choices: [ - [EchartsTimeseriesSeriesType.Start, 'Start'], - [EchartsTimeseriesSeriesType.Middle, 'Middle'], - [EchartsTimeseriesSeriesType.End, 'End'], + [EchartsTimeseriesSeriesType.Start, t('Start')], + [EchartsTimeseriesSeriesType.Middle, t('Middle')], + [EchartsTimeseriesSeriesType.End, t('End')], ], description: t( 'Defines whether the step should appear at the beginning, middle or end between two data points', @@ -202,9 +166,7 @@ const config: ControlPanelConfig = { config: { ...sharedControls.x_axis_time_format, default: 'smart_date', - description: `${D3_TIME_FORMAT_DOCS}. ${t( - 'When using other than adaptive formatting, labels may overlap.', - )}`, + description: `${D3_TIME_FORMAT_DOCS}. ${TIME_SERIES_DESCRIPTION_TEXT}`, }, }, ], @@ -297,10 +259,10 @@ const config: ControlPanelConfig = { default: rowLimit, }, }, - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, - groupby: formData.standardizedFormData.standardizedState.columns, + metrics: getStandardizedControls().popAllMetrics(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts index 2a24b708419ef..3fdeb5aa832a4 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts @@ -21,18 +21,17 @@ import { Behavior, ChartMetadata, ChartPlugin, - FeatureFlag, - isFeatureEnabled, + hasGenericChartAxes, t, } from '@superset-ui/core'; +import { + EchartsTimeseriesChartProps, + EchartsTimeseriesFormData, +} from '@superset-ui/plugin-chart-echarts'; import buildQuery from '../buildQuery'; import controlPanel from './controlPanel'; import transformProps from '../transformProps'; import thumbnail from './images/thumbnail.png'; -import { - EchartsTimeseriesChartProps, - EchartsTimeseriesFormData, -} from '../types'; import example1 from './images/Step1.png'; import example2 from './images/Step2.png'; @@ -46,10 +45,10 @@ export default class EchartsTimeseriesStepChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('../EchartsTimeseries'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Evolution'), credits: ['https://echarts.apache.org'], - description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + description: hasGenericChartAxes ? t( 'Stepped-line graph (also called step chart) is a variation of line chart but with the line forming a series of steps between data points. A step chart can be useful when you want to show the changes that occur at irregular intervals.', ) @@ -63,7 +62,7 @@ export default class EchartsTimeseriesStepChartPlugin extends ChartPlugin< AnnotationType.Interval, AnnotationType.Timeseries, ], - name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + name: hasGenericChartAxes ? t('Stepped Line') : t('Time-series Stepped Line'), tags: [ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/buildQuery.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/buildQuery.ts index 085635209ac20..ad021f92b9189 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/buildQuery.ts @@ -18,11 +18,12 @@ */ import { buildQueryContext, - DTTM_ALIAS, ensureIsArray, normalizeOrderBy, PostProcessingPivot, QueryFormData, + getXAxisColumn, + isXAxisSet, } from '@superset-ui/core'; import { rollingWindowOperator, @@ -35,11 +36,11 @@ import { prophetOperator, timeComparePivotOperator, flattenOperator, + sortOperator, } from '@superset-ui/chart-controls'; export default function buildQuery(formData: QueryFormData) { - const { x_axis, groupby } = formData; - const is_timeseries = x_axis === DTTM_ALIAS || !x_axis; + const { groupby } = formData; return buildQueryContext(formData, baseQueryObject => { /* the `pivotOperatorInRuntime` determines how to pivot the dataframe returned from the raw query. 1. If it's a time compared query, there will return a pivoted dataframe that append time compared metrics. for instance: @@ -66,18 +67,19 @@ export default function buildQuery(formData: QueryFormData) { baseQueryObject, ) ? timeComparePivotOperator(formData, baseQueryObject) - : pivotOperator(formData, { - ...baseQueryObject, - index: x_axis, - is_timeseries, - }); + : pivotOperator(formData, baseQueryObject); return [ { ...baseQueryObject, - columns: [...ensureIsArray(x_axis), ...ensureIsArray(groupby)], + columns: [ + ...(isXAxisSet(formData) + ? ensureIsArray(getXAxisColumn(formData)) + : []), + ...ensureIsArray(groupby), + ], series_columns: groupby, - is_timeseries, + ...(isXAxisSet(formData) ? {} : { is_timeseries: true }), // todo: move `normalizeOrderBy to extractQueryFields` orderby: normalizeOrderBy(baseQueryObject).orderby, time_offsets: isTimeComparison(formData, baseQueryObject) @@ -92,11 +94,9 @@ export default function buildQuery(formData: QueryFormData) { rollingWindowOperator(formData, baseQueryObject), timeCompareOperator(formData, baseQueryObject), resampleOperator(formData, baseQueryObject), - renameOperator(formData, { - ...baseQueryObject, - is_timeseries, - }), + renameOperator(formData, baseQueryObject), contributionOperator(formData, baseQueryObject), + sortOperator(formData, baseQueryObject), flattenOperator(formData, baseQueryObject), // todo: move prophet before flatten prophetOperator(formData, baseQueryObject), diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/constants.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/constants.ts new file mode 100644 index 0000000000000..1d7b87194493f --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/constants.ts @@ -0,0 +1,70 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { sections } from '@superset-ui/chart-controls'; +import { t } from '@superset-ui/core'; +import { + OrientationType, + EchartsTimeseriesSeriesType, + EchartsTimeseriesFormData, +} from './types'; +import { + DEFAULT_LEGEND_FORM_DATA, + DEFAULT_TITLE_FORM_DATA, +} from '../constants'; + +// @ts-ignore +export const DEFAULT_FORM_DATA: EchartsTimeseriesFormData = { + ...DEFAULT_LEGEND_FORM_DATA, + ...DEFAULT_TITLE_FORM_DATA, + annotationLayers: sections.annotationLayers, + area: false, + forecastEnabled: sections.FORECAST_DEFAULT_DATA.forecastEnabled, + forecastInterval: sections.FORECAST_DEFAULT_DATA.forecastInterval, + forecastPeriods: sections.FORECAST_DEFAULT_DATA.forecastPeriods, + forecastSeasonalityDaily: + sections.FORECAST_DEFAULT_DATA.forecastSeasonalityDaily, + forecastSeasonalityWeekly: + sections.FORECAST_DEFAULT_DATA.forecastSeasonalityWeekly, + forecastSeasonalityYearly: + sections.FORECAST_DEFAULT_DATA.forecastSeasonalityYearly, + logAxis: false, + markerEnabled: false, + markerSize: 6, + minorSplitLine: false, + opacity: 0.2, + orderDesc: true, + rowLimit: 10000, + seriesType: EchartsTimeseriesSeriesType.Line, + stack: false, + tooltipTimeFormat: 'smart_date', + truncateYAxis: false, + yAxisBounds: [null, null], + zoomable: false, + richTooltip: true, + xAxisLabelRotation: 0, + groupby: [], + showValue: false, + onlyTotal: false, + percentageThreshold: 0, + orientation: OrientationType.vertical, +}; + +export const TIME_SERIES_DESCRIPTION_TEXT: string = t( + 'When using other than adaptive formatting, labels may overlap', +); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts index 062d741402ff7..c8210cd981911 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts @@ -21,12 +21,11 @@ import { Behavior, ChartMetadata, ChartPlugin, - FeatureFlag, - isFeatureEnabled, + hasGenericChartAxes, t, } from '@superset-ui/core'; import buildQuery from './buildQuery'; -import controlPanel from './controlPanel'; +import controlPanel from './Regular/Line/controlPanel'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; import { @@ -45,15 +44,15 @@ export default class EchartsTimeseriesChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('./EchartsTimeseries'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Evolution'), credits: ['https://echarts.apache.org'], - description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) + description: hasGenericChartAxes ? t( - 'Swiss army knife for visualizing data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.', + 'Swiss army knife for visualizing data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.', ) : t( - 'Swiss army knife for visualizing time series data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.', + 'Swiss army knife for visualizing time series data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.', ), exampleGallery: [{ url: example }], supportedAnnotationTypes: [ @@ -62,9 +61,7 @@ export default class EchartsTimeseriesChartPlugin extends ChartPlugin< AnnotationType.Interval, AnnotationType.Timeseries, ], - name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) - ? t('Generic Chart') - : t('Time-series Chart'), + name: hasGenericChartAxes ? t('Generic Chart') : t('Time-series Chart'), tags: [ t('Advanced-Analytics'), t('Aesthetic'), diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts index bf20dc516611f..eadded44a9ac5 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts @@ -20,10 +20,7 @@ import { AnnotationLayer, CategoricalColorNamespace, - DataRecordValue, - DTTM_ALIAS, GenericDataType, - getColumnLabel, getNumberFormatter, isEventAnnotationLayer, isFormulaAnnotationLayer, @@ -31,19 +28,23 @@ import { isTimeseriesAnnotationLayer, TimeseriesChartDataResponseResult, t, + AxisType, + getXAxisLabel, + isPhysicalColumn, + isDefined, } from '@superset-ui/core'; import { isDerivedSeries } from '@superset-ui/chart-controls'; import { EChartsCoreOption, SeriesOption } from 'echarts'; import { ZRLineType } from 'echarts/types/src/util/types'; import { - DEFAULT_FORM_DATA, EchartsTimeseriesChartProps, EchartsTimeseriesFormData, EchartsTimeseriesSeriesType, TimeseriesChartTransformedProps, OrientationType, } from './types'; -import { ForecastSeriesEnum, ForecastValue } from '../types'; +import { DEFAULT_FORM_DATA } from './constants'; +import { ForecastSeriesEnum, ForecastValue, Refs } from '../types'; import { parseYAxisBound } from '../utils/controls'; import { currentSeries, @@ -67,7 +68,7 @@ import { rebaseForecastDatum, } from '../utils/forecast'; import { convertInteger } from '../utils/convertInteger'; -import { defaultGrid, defaultTooltip, defaultYAxis } from '../defaults'; +import { defaultGrid, defaultYAxis } from '../defaults'; import { getPadding, getTooltipTimeFormatter, @@ -83,6 +84,7 @@ import { TIMESERIES_CONSTANTS, TIMEGRAIN_TO_TIMESTAMP, } from '../constants'; +import { getDefaultTooltip } from '../utils/tooltip'; export default function transformProps( chartProps: EchartsTimeseriesChartProps, @@ -96,10 +98,13 @@ export default function transformProps( queriesData, datasource, theme, + inContextMenu, + emitCrossFilters, } = chartProps; const { verboseMap = {} } = datasource; const [queryData] = queriesData; - const { data = [] } = queryData as TimeseriesChartDataResponseResult; + const { data = [], label_map: labelMap } = + queryData as TimeseriesChartDataResponseResult; const dataTypes = getColtypesMapping(queryData); const annotationData = getAnnotationData(chartProps); @@ -130,7 +135,6 @@ export default function transformProps( richTooltip, xAxis: xAxisOrig, xAxisLabelRotation, - emitFilter, groupby, showValue, onlyTotal, @@ -144,23 +148,29 @@ export default function transformProps( timeGrainSqla, orientation, }: EchartsTimeseriesFormData = { ...DEFAULT_FORM_DATA, ...formData }; + const refs: Refs = {}; const colorScale = CategoricalColorNamespace.getScale(colorScheme as string); const rebasedData = rebaseForecastDatum(data, verboseMap); - const xAxisCol = - verboseMap[xAxisOrig] || getColumnLabel(xAxisOrig || DTTM_ALIAS); + let xAxisLabel = getXAxisLabel(chartProps.rawFormData) as string; + if ( + isPhysicalColumn(chartProps.rawFormData?.x_axis) && + isDefined(verboseMap[xAxisLabel]) + ) { + xAxisLabel = verboseMap[xAxisLabel]; + } const isHorizontal = orientation === OrientationType.horizontal; const { totalStackedValues, thresholdValues } = extractDataTotalValues( rebasedData, { stack, percentageThreshold, - xAxisCol, + xAxisCol: xAxisLabel, }, ); const rawSeries = extractSeries(rebasedData, { fillNeighborValue: stack && !forecastEnabled ? 0 : undefined, - xAxis: xAxisCol, + xAxis: xAxisLabel, removeNulls: seriesType === EchartsTimeseriesSeriesType.Scatter, stack, totalStackedValues, @@ -175,7 +185,7 @@ export default function transformProps( Object.values(rawSeries).map(series => series.name as string), ); const isAreaExpand = stack === AreaChartExtraControlsValue.Expand; - const xAxisDataType = dataTypes?.[xAxisCol] ?? dataTypes?.[xAxisOrig]; + const xAxisDataType = dataTypes?.[xAxisLabel] ?? dataTypes?.[xAxisOrig]; const xAxisType = getAxisType(xAxisDataType); const series: SeriesOption[] = []; @@ -226,7 +236,14 @@ export default function transformProps( .forEach((layer: AnnotationLayer) => { if (isFormulaAnnotationLayer(layer)) series.push( - transformFormulaAnnotation(layer, data, colorScale, sliceId), + transformFormulaAnnotation( + layer, + data, + xAxisLabel, + xAxisType, + colorScale, + sliceId, + ), ); else if (isIntervalAnnotationLayer(layer)) { series.push( @@ -282,20 +299,10 @@ export default function transformProps( ? getXAxisFormatter(xAxisTimeFormat) : String; - const labelMap = series.reduce( - (acc: Record<string, DataRecordValue[]>, datum) => { - const name: string = datum.name as string; - return { - ...acc, - [name]: [name], - }; - }, - {}, - ); - const { setDataMask = () => {}, - setControlValue = (...args: unknown[]) => {}, + setControlValue = () => {}, + onContextMenu, } = hooks; const addYAxisLabelOffset = !!yAxisTitle; @@ -332,13 +339,23 @@ export default function transformProps( rotate: xAxisLabelRotation, }, minInterval: - xAxisType === 'time' && timeGrainSqla + xAxisType === AxisType.time && timeGrainSqla ? TIMEGRAIN_TO_TIMESTAMP[timeGrainSqla] : 0, }; + + if (xAxisType === AxisType.time) { + /** + * Overriding default behavior (false) for time axis regardless of the granilarity. + * Not including this in the initial declaration above so if echarts changes the default + * behavior for other axist types we won't unintentionally override it + */ + xAxis.axisLabel.showMaxLabel = null; + } + let yAxis: any = { ...defaultYAxis, - type: logAxis ? 'log' : 'value', + type: logAxis ? AxisType.log : AxisType.value, min, max, minorTick: { show: true }, @@ -364,8 +381,8 @@ export default function transformProps( xAxis, yAxis, tooltip: { - ...defaultTooltip, - appendToBody: true, + ...getDefaultTooltip(refs), + show: !inContextMenu, trigger: richTooltip ? 'axis' : 'item', formatter: (params: any) => { const [xIndex, yIndex] = isHorizontal ? [1, 0] : [0, 1]; @@ -431,7 +448,7 @@ export default function transformProps( return { echartOptions, - emitFilter, + emitCrossFilters, formData, groupby, height, @@ -441,5 +458,12 @@ export default function transformProps( setControlValue, width, legendData, + onContextMenu, + xValueFormatter: tooltipFormatter, + xAxis: { + label: xAxisLabel, + type: xAxisType, + }, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformers.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformers.ts index 420662647d9db..b49f9f546bd28 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformers.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformers.ts @@ -33,6 +33,7 @@ import { TimeFormatter, TimeseriesAnnotationLayer, TimeseriesDataRecord, + AxisType, } from '@superset-ui/core'; import { SeriesOption } from 'echarts'; import { @@ -92,6 +93,7 @@ export function transformSeries( sliceId?: number; isHorizontal?: boolean; lineStyle?: LineStyleOption; + queryIndex?: number; }, ): SeriesOption | undefined { const { name } = series; @@ -115,6 +117,7 @@ export function transformSeries( seriesKey, sliceId, isHorizontal = false, + queryIndex = 0, } = opts; const contexts = seriesContexts[name || ''] || []; const hasForecast = @@ -192,6 +195,7 @@ export function transformSeries( : { ...opts.lineStyle, opacity }; return { ...series, + queryIndex, yAxisIndex, name: forecastSeries.name, itemStyle, @@ -204,6 +208,7 @@ export function transformSeries( ? seriesType : undefined, stack: stackId, + stackStrategy: isConfidenceBand ? 'all' : 'samesign', lineStyle, areaStyle: area || forecastSeries.type === ForecastSeriesEnum.ForecastUpper @@ -253,6 +258,8 @@ export function transformSeries( export function transformFormulaAnnotation( layer: FormulaAnnotationLayer, data: TimeseriesDataRecord[], + xAxisCol: string, + xAxisType: AxisType, colorScale: CategoricalColorScale, sliceId?: number, ): SeriesOption { @@ -270,7 +277,7 @@ export function transformFormulaAnnotation( }, type: 'line', smooth: true, - data: evalFormula(layer, data), + data: evalFormula(layer, data, xAxisCol, xAxisType), symbolSize: 0, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/types.ts index d9b7708146df3..56527ebd63bf9 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/types.ts @@ -16,29 +16,26 @@ * specific language governing permissions and limitations * under the License. */ +import { OptionName } from 'echarts/types/src/util/types'; import { AnnotationLayer, - ChartDataResponseResult, - ChartProps, + AxisType, + ContributionType, QueryFormColumn, QueryFormData, + TimeFormatter, TimeGranularity, } from '@superset-ui/core'; -import { sections } from '@superset-ui/chart-controls'; import { - DEFAULT_LEGEND_FORM_DATA, - EchartsLegendFormData, - EChartTransformedProps, - EchartsTitleFormData, - DEFAULT_TITLE_FORM_DATA, + BaseChartProps, + BaseTransformedProps, + ContextMenuTransformedProps, + CrossFilterTransformedProps, + LegendFormData, StackType, + TitleFormData, } from '../types'; -export enum EchartsTimeseriesContributionType { - Row = 'row', - Column = 'column', -} - export enum OrientationType { vertical = 'vertical', horizontal = 'horizontal', @@ -58,7 +55,7 @@ export type EchartsTimeseriesFormData = QueryFormData & { annotationLayers: AnnotationLayer[]; area: boolean; colorScheme?: string; - contributionMode?: EchartsTimeseriesContributionType; + contributionMode?: ContributionType; forecastEnabled: boolean; forecastPeriods: number; forecastInterval: number; @@ -83,59 +80,28 @@ export type EchartsTimeseriesFormData = QueryFormData & { zoomable: boolean; richTooltip: boolean; xAxisLabelRotation: number; - emitFilter: boolean; groupby: QueryFormColumn[]; showValue: boolean; onlyTotal: boolean; showExtraControls: boolean; percentageThreshold: number; orientation?: OrientationType; -} & EchartsLegendFormData & - EchartsTitleFormData; - -// @ts-ignore -export const DEFAULT_FORM_DATA: EchartsTimeseriesFormData = { - ...DEFAULT_LEGEND_FORM_DATA, - annotationLayers: sections.annotationLayers, - area: false, - forecastEnabled: sections.FORECAST_DEFAULT_DATA.forecastEnabled, - forecastInterval: sections.FORECAST_DEFAULT_DATA.forecastInterval, - forecastPeriods: sections.FORECAST_DEFAULT_DATA.forecastPeriods, - forecastSeasonalityDaily: - sections.FORECAST_DEFAULT_DATA.forecastSeasonalityDaily, - forecastSeasonalityWeekly: - sections.FORECAST_DEFAULT_DATA.forecastSeasonalityWeekly, - forecastSeasonalityYearly: - sections.FORECAST_DEFAULT_DATA.forecastSeasonalityYearly, - logAxis: false, - markerEnabled: false, - markerSize: 6, - minorSplitLine: false, - opacity: 0.2, - orderDesc: true, - rowLimit: 10000, - seriesType: EchartsTimeseriesSeriesType.Line, - stack: false, - tooltipTimeFormat: 'smart_date', - truncateYAxis: false, - yAxisBounds: [null, null], - zoomable: false, - richTooltip: true, - xAxisLabelRotation: 0, - emitFilter: false, - groupby: [], - showValue: false, - onlyTotal: false, - percentageThreshold: 0, - orientation: OrientationType.vertical, - ...DEFAULT_TITLE_FORM_DATA, -}; +} & LegendFormData & + TitleFormData; export interface EchartsTimeseriesChartProps - extends ChartProps<EchartsTimeseriesFormData> { + extends BaseChartProps<EchartsTimeseriesFormData> { formData: EchartsTimeseriesFormData; - queriesData: ChartDataResponseResult[]; } export type TimeseriesChartTransformedProps = - EChartTransformedProps<EchartsTimeseriesFormData>; + BaseTransformedProps<EchartsTimeseriesFormData> & + ContextMenuTransformedProps & + CrossFilterTransformedProps & { + legendData?: OptionName[]; + xValueFormatter: TimeFormatter | StringConstructor; + xAxis: { + label: string; + type: AxisType; + }; + }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Tree/EchartsTree.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Tree/EchartsTree.tsx index 9b42c6e553576..b1b3f8e896e04 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Tree/EchartsTree.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Tree/EchartsTree.tsx @@ -21,9 +21,17 @@ import { EchartsProps } from '../types'; import Echart from '../components/Echart'; export default function EchartsGraph({ + echartOptions, height, + refs, width, - echartOptions, }: EchartsProps) { - return <Echart height={height} width={width} echartOptions={echartOptions} />; + return ( + <Echart + refs={refs} + height={height} + width={width} + echartOptions={echartOptions} + /> + ); } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Tree/constants.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Tree/constants.ts index 463835966cc71..35567c3fc5939 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Tree/constants.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Tree/constants.ts @@ -17,6 +17,7 @@ * under the License. */ import { TreeSeriesOption } from 'echarts'; +import { EchartsTreeFormData } from './types'; export const DEFAULT_TREE_SERIES_OPTION: TreeSeriesOption = { label: { @@ -28,3 +29,18 @@ export const DEFAULT_TREE_SERIES_OPTION: TreeSeriesOption = { animationEasing: 'cubicOut', lineStyle: { color: 'source', width: 1.5 }, }; + +export const DEFAULT_FORM_DATA: Partial<EchartsTreeFormData> = { + id: '', + parent: '', + name: '', + rootNodeId: '', + layout: 'orthogonal', + orient: 'LR', + symbol: 'emptyCircle', + symbolSize: 7, + roam: true, + nodeLabelPosition: 'left', + childLabelPosition: 'bottom', + emphasis: 'descendant', +}; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx index c115f5c5c20d7..a6ee81589a283 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx @@ -20,10 +20,11 @@ import React from 'react'; import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; import { ControlPanelConfig, + getStandardizedControls, sections, sharedControls, } from '@superset-ui/chart-controls'; -import { DEFAULT_FORM_DATA } from './types'; +import { DEFAULT_FORM_DATA } from './constants'; const requiredEntity = { ...sharedControls.entity, @@ -160,7 +161,7 @@ const controlPanel: ControlPanelConfig = { ['right', t('right')], ['bottom', t('bottom')], ], - description: t('Position of intermidiate node label on tree'), + description: t('Position of intermediate node label on tree'), }, }, ], @@ -285,13 +286,9 @@ const controlPanel: ControlPanelConfig = { ], }, ], - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metric: formData.standardizedFormData.standardizedState.metrics[0], - }), - updateStandardizedState: (prevState, currState) => ({ - ...currState, - metrics: [currState.metrics[0], ...prevState.metrics.slice(1)], + metric: getStandardizedControls().shiftMetric(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Tree/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Tree/transformProps.ts index c89fbe8b37049..ca3a4a9341f8a 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Tree/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Tree/transformProps.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { ChartProps, getMetricLabel, DataRecordValue } from '@superset-ui/core'; +import { getMetricLabel, DataRecordValue } from '@superset-ui/core'; import { EChartsCoreOption, TreeSeriesOption } from 'echarts'; import { TreeSeriesCallbackDataParams, @@ -24,12 +24,14 @@ import { } from 'echarts/types/src/chart/tree/TreeSeries'; import { OptionName } from 'echarts/types/src/util/types'; import { + EchartsTreeChartProps, EchartsTreeFormData, - DEFAULT_FORM_DATA as DEFAULT_GRAPH_FORM_DATA, TreeDataRecord, + TreeTransformedProps, } from './types'; -import { DEFAULT_TREE_SERIES_OPTION } from './constants'; -import { EchartsProps } from '../types'; +import { DEFAULT_FORM_DATA, DEFAULT_TREE_SERIES_OPTION } from './constants'; +import { Refs } from '../types'; +import { getDefaultTooltip } from '../utils/tooltip'; export function formatTooltip({ params, @@ -49,8 +51,11 @@ export function formatTooltip({ ].join(''); } -export default function transformProps(chartProps: ChartProps): EchartsProps { +export default function transformProps( + chartProps: EchartsTreeChartProps, +): TreeTransformedProps { const { width, height, formData, queriesData } = chartProps; + const refs: Refs = {}; const data: TreeDataRecord[] = queriesData[0].data || []; const { @@ -67,7 +72,7 @@ export default function transformProps(chartProps: ChartProps): EchartsProps { nodeLabelPosition, childLabelPosition, emphasis, - }: EchartsTreeFormData = { ...DEFAULT_GRAPH_FORM_DATA, ...formData }; + }: EchartsTreeFormData = { ...DEFAULT_FORM_DATA, ...formData }; const metricLabel = getMetricLabel(metric); const nameColumn = name || id; @@ -201,6 +206,7 @@ export default function transformProps(chartProps: ChartProps): EchartsProps { animationEasing: DEFAULT_TREE_SERIES_OPTION.animationEasing, series, tooltip: { + ...getDefaultTooltip(refs), trigger: 'item', triggerOn: 'mousemove', formatter: (params: any) => @@ -212,8 +218,10 @@ export default function transformProps(chartProps: ChartProps): EchartsProps { }; return { + formData, width, height, echartOptions, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Tree/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Tree/types.ts index 81db2d59508fd..0fde0cde2a177 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Tree/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Tree/types.ts @@ -16,9 +16,12 @@ * specific language governing permissions and limitations * under the License. */ +import { OptionName } from 'echarts/types/src/util/types'; +import { ChartDataResponseResult, QueryFormData } from '@superset-ui/core'; import { TreeSeriesNodeItemOption } from 'echarts/types/src/chart/tree/TreeSeries'; +import { BaseChartProps, BaseTransformedProps } from '../types'; -export type EchartsTreeFormData = { +export type EchartsTreeFormData = QueryFormData & { id: string; parent: string; name: string; @@ -35,21 +38,18 @@ export type EchartsTreeFormData = { emphasis: 'none' | 'ancestor' | 'descendant'; }; -export const DEFAULT_FORM_DATA: EchartsTreeFormData = { - id: '', - parent: '', - name: '', - rootNodeId: '', - layout: 'orthogonal', - orient: 'LR', - symbol: 'emptyCircle', - symbolSize: 7, - roam: true, - nodeLabelPosition: 'left', - childLabelPosition: 'bottom', - emphasis: 'descendant', -}; +export interface TreeChartDataResponseResult extends ChartDataResponseResult { + data: TreeDataRecord[]; +} + +export interface EchartsTreeChartProps + extends BaseChartProps<EchartsTreeFormData> { + formData: EchartsTreeFormData; + queriesData: TreeChartDataResponseResult[]; +} -export type TreeDataRecord = Record<string, string | number> & { - children: TreeSeriesNodeItemOption[]; +export type TreeDataRecord = Record<string, OptionName> & { + children?: TreeSeriesNodeItemOption[]; }; + +export type TreeTransformedProps = BaseTransformedProps<EchartsTreeFormData>; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx index 2932dc327ddc7..0a2f01b4049c9 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx @@ -16,25 +16,32 @@ * specific language governing permissions and limitations * under the License. */ +import { + DataRecordValue, + BinaryQueryObjectFilterClause, +} from '@superset-ui/core'; import React, { useCallback } from 'react'; import Echart from '../components/Echart'; +import { NULL_STRING } from '../constants'; import { EventHandlers } from '../types'; import { extractTreePathInfo } from './constants'; import { TreemapTransformedProps } from './types'; export default function EchartsTreemap({ - height, - width, echartOptions, - setDataMask, - labelMap, + emitCrossFilters, groupby, + height, + labelMap, + onContextMenu, + refs, + setDataMask, selectedValues, - formData, + width, }: TreemapTransformedProps) { const handleChange = useCallback( (values: string[]) => { - if (!formData.emitFilter) { + if (!emitCrossFilters) { return; } @@ -46,7 +53,7 @@ export default function EchartsTreemap({ values.length === 0 ? [] : groupby.map((col, idx) => { - const val = groupbyValues.map(v => v[idx]); + const val: DataRecordValue[] = groupbyValues.map(v => v[idx]); if (val === null || val === undefined) return { col, @@ -71,7 +78,7 @@ export default function EchartsTreemap({ const eventHandlers: EventHandlers = { click: props => { const { data, treePathInfo } = props; - // do noting when clicking the parent node + // do nothing when clicking on the parent node if (data?.children) { return; } @@ -84,10 +91,30 @@ export default function EchartsTreemap({ handleChange([name]); } }, + contextmenu: eventParams => { + if (onContextMenu) { + eventParams.event.stop(); + const { treePath } = extractTreePathInfo(eventParams.treePathInfo); + if (treePath.length > 0) { + const pointerEvent = eventParams.event.event; + const filters: BinaryQueryObjectFilterClause[] = []; + treePath.forEach((path, i) => + filters.push({ + col: groupby[i], + op: '==', + val: path === 'null' ? NULL_STRING : path, + formattedVal: path, + }), + ); + onContextMenu(pointerEvent.clientX, pointerEvent.clientY, filters); + } + } + }, }; return ( <Echart + refs={refs} height={height} width={width} echartOptions={echartOptions} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/constants.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/constants.ts index 080565229ac26..2cc660f35f5a6 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/constants.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/constants.ts @@ -17,7 +17,7 @@ * under the License. */ -import { TreePathInfo } from './types'; +import { TreePathInfo } from '../types'; export const COLOR_SATURATION = [0.7, 0.4]; export const LABEL_FONTSIZE = 11; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx index e7cca1af263d6..e5f4704701434 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx @@ -21,10 +21,11 @@ import { t } from '@superset-ui/core'; import { ControlPanelConfig, D3_FORMAT_DOCS, + D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT, D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, sections, - emitFilterControl, + getStandardizedControls, } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA } from './types'; @@ -54,7 +55,6 @@ const config: ControlPanelConfig = { }, ], ['adhoc_filters'], - emitFilterControl, ], }, { @@ -96,9 +96,9 @@ const config: ControlPanelConfig = { default: labelType, renderTrigger: true, choices: [ - ['Key', 'Key'], - ['value', 'Value'], - ['key_value', 'Category and Value'], + ['Key', t('Key')], + ['value', t('Value')], + ['key_value', t('Category and Value')], ], description: t('What should be shown on the label?'), }, @@ -114,9 +114,7 @@ const config: ControlPanelConfig = { renderTrigger: true, default: numberFormat, choices: D3_FORMAT_OPTIONS, - description: `${t( - 'D3 format syntax: https://github.com/d3/d3-format. ', - )} ${t('Only applies when "Label Type" is set to show values.')}`, + description: `${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`, }, }, ], @@ -137,14 +135,10 @@ const config: ControlPanelConfig = { ], }, ], - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metric: formData.standardizedFormData.standardizedState.metrics[0], - groupby: formData.standardizedFormData.standardizedState.columns, - }), - updateStandardizedState: (prevState, currState) => ({ - ...currState, - metrics: [currState.metrics[0], ...prevState.metrics.slice(1)], + metric: getStandardizedControls().shiftMetric(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts index 575bb41fb9ee6..ec6d2d38230c5 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts @@ -2,7 +2,7 @@ * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information - * regardin + * regarding * g copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance @@ -46,14 +46,14 @@ export default class EchartsTreemapChartPlugin extends ChartPlugin< controlPanel, loadChart: () => import('./EchartsTreemap'), metadata: new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Part of a Whole'), credits: ['https://echarts.apache.org'], description: t( - 'Show hierarchical relationships of data, with with the value represented by area, showing proportion and contribution to the whole.', + 'Show hierarchical relationships of data, with the value represented by area, showing proportion and contribution to the whole.', ), exampleGallery: [{ url: example1 }, { url: example2 }], - name: t('Treemap v2'), + name: t('Treemap'), tags: [ t('Aesthetic'), t('Categorical'), diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts index 5dd7d55467f72..b220b55b3d3c1 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts @@ -18,8 +18,6 @@ */ import { CategoricalColorNamespace, - DataRecord, - DataRecordValue, getColumnLabel, getMetricLabel, getNumberFormatter, @@ -27,7 +25,6 @@ import { NumberFormats, NumberFormatter, } from '@superset-ui/core'; -import { groupBy, isNumber, transform } from 'lodash'; import { TreemapSeriesNodeItemOption } from 'echarts/types/src/chart/treemap/TreemapSeries'; import { EChartsCoreOption, TreemapSeriesOption } from 'echarts'; import { @@ -39,7 +36,6 @@ import { TreemapTransformedProps, } from './types'; import { formatSeriesName, getColtypesMapping } from '../utils/series'; -import { defaultTooltip } from '../defaults'; import { COLOR_SATURATION, BORDER_WIDTH, @@ -49,6 +45,9 @@ import { BORDER_COLOR, } from './constants'; import { OpacityEnum } from '../constants'; +import { getDefaultTooltip } from '../utils/tooltip'; +import { Refs } from '../types'; +import { treeBuilder, TreeNode } from '../utils/treeBuilder'; export function formatLabel({ params, @@ -109,10 +108,19 @@ export function formatTooltip({ export default function transformProps( chartProps: EchartsTreemapChartProps, ): TreemapTransformedProps { - const { formData, height, queriesData, width, hooks, filterState, theme } = - chartProps; + const { + formData, + height, + queriesData, + width, + hooks, + filterState, + theme, + inContextMenu, + emitCrossFilters, + } = chartProps; const { data = [] } = queriesData[0]; - const { setDataMask = () => {} } = hooks; + const { setDataMask = () => {}, onContextMenu } = hooks; const coltypeMapping = getColtypesMapping(queriesData[0]); const { @@ -126,13 +134,12 @@ export default function transformProps( showLabels, showUpperLabels, dashboardId, - emitFilter, sliceId, }: EchartsTreemapFormData = { ...DEFAULT_TREEMAP_FORM_DATA, ...formData, }; - + const refs: Refs = {}; const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const numberFormatter = getNumberFormatter(numberFormat); const formatter = (params: TreemapSeriesCallbackDataParams) => @@ -142,111 +149,73 @@ export default function transformProps( labelType, }); - const columnsLabelMap = new Map<string, DataRecordValue[]>(); - - const transformer = ( - data: DataRecord[], - groupbyLabels: string[], - metric: string, - depth: number, - path: string[], - ): TreemapSeriesNodeItemOption[] => { - const [currGroupby, ...restGroupby] = groupbyLabels; - const currGrouping = groupBy(data, currGroupby); - if (!restGroupby.length) { - return transform( - currGrouping, - (result, value, key) => { - (value ?? []).forEach(datum => { - const name = formatSeriesName(key, { - numberFormatter, - timeFormatter: getTimeFormatter(dateFormat), - ...(coltypeMapping[currGroupby] && { - coltype: coltypeMapping[currGroupby], - }), - }); - const item: TreemapSeriesNodeItemOption = { - name, - value: isNumber(datum[metric]) ? (datum[metric] as number) : 0, - }; - const joinedName = path.concat(name).join(','); - // map(joined_name: [columnLabel_1, columnLabel_2, ...]) - columnsLabelMap.set(joinedName, path.concat(name)); - if ( - filterState.selectedValues && - !filterState.selectedValues.includes(joinedName) - ) { - item.itemStyle = { - colorAlpha: OpacityEnum.SemiTransparent, - }; - item.label = { - color: `rgba(0, 0, 0, ${OpacityEnum.SemiTransparent})`, - }; - } - result.push(item); - }); - }, - [] as TreemapSeriesNodeItemOption[], - ); - } - const sortedData = transform( - currGrouping, - (result, value, key) => { - const name = formatSeriesName(key, { - numberFormatter, - timeFormatter: getTimeFormatter(dateFormat), - ...(coltypeMapping[currGroupby] && { - coltype: coltypeMapping[currGroupby], - }), - }); - const children = transformer( - value, - restGroupby, - metric, - depth + 1, - path.concat(name), - ); - result.push({ - name, - children, - value: children.reduce( - (prev, cur) => prev + (cur.value as number), - 0, - ), - }); - result.sort((a, b) => (b.value as number) - (a.value as number)); - }, - [] as TreemapSeriesNodeItemOption[], - ); - // sort according to the area and then take the color value in order - return sortedData.map(child => ({ - ...child, - colorSaturation: COLOR_SATURATION, - itemStyle: { - borderColor: BORDER_COLOR, - color: colorFn(`${child.name}`, sliceId), - borderWidth: BORDER_WIDTH, - gapWidth: GAP_WIDTH, - }, - })); - }; - + const columnsLabelMap = new Map<string, string[]>(); const metricLabel = getMetricLabel(metric); const groupbyLabels = groupby.map(getColumnLabel); - const initialDepth = 1; + const treeData = treeBuilder(data, groupbyLabels, metricLabel); + const traverse = (treeNodes: TreeNode[], path: string[]) => + treeNodes.map(treeNode => { + const { name: nodeName, value, groupBy } = treeNode; + const name = formatSeriesName(nodeName, { + numberFormatter, + timeFormatter: getTimeFormatter(dateFormat), + ...(coltypeMapping[groupBy] && { + coltype: coltypeMapping[groupBy], + }), + }); + const newPath = path.concat(name); + let item: TreemapSeriesNodeItemOption = { + name, + value, + }; + if (treeNode.children?.length) { + item = { + ...item, + children: traverse(treeNode.children, newPath), + colorSaturation: COLOR_SATURATION, + itemStyle: { + borderColor: BORDER_COLOR, + color: colorFn(name, sliceId), + borderWidth: BORDER_WIDTH, + gapWidth: GAP_WIDTH, + }, + }; + } else { + const joinedName = newPath.join(','); + // map(joined_name: [columnLabel_1, columnLabel_2, ...]) + columnsLabelMap.set(joinedName, newPath); + if ( + filterState.selectedValues && + !filterState.selectedValues.includes(joinedName) + ) { + item = { + ...item, + itemStyle: { + colorAlpha: OpacityEnum.SemiTransparent, + }, + label: { + color: `rgba(0, 0, 0, ${OpacityEnum.SemiTransparent})`, + }, + }; + } + } + return item; + }); + const transformedData: TreemapSeriesNodeItemOption[] = [ { name: metricLabel, colorSaturation: COLOR_SATURATION, itemStyle: { borderColor: BORDER_COLOR, + color: colorFn(`${metricLabel}`, sliceId), borderWidth: BORDER_WIDTH, gapWidth: GAP_WIDTH, }, upperLabel: { show: false, }, - children: transformer(data, groupbyLabels, metricLabel, initialDepth, []), + children: traverse(treeData, []), }, ]; @@ -301,7 +270,8 @@ export default function transformProps( const echartOptions: EChartsCoreOption = { tooltip: { - ...defaultTooltip, + ...getDefaultTooltip(refs), + show: !inContextMenu, trigger: 'item', formatter: (params: any) => formatTooltip({ @@ -318,9 +288,11 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, + emitCrossFilters, labelMap: Object.fromEntries(columnsLabelMap), groupby, selectedValues: filterState.selectedValues || [], + onContextMenu, + refs, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/types.ts index f4ed29cc7316c..1d42988389182 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/types.ts @@ -19,15 +19,18 @@ import { ChartDataResponseResult, ChartProps, - DataRecordValue, QueryFormColumn, QueryFormData, QueryFormMetric, - SetDataMaskHook, } from '@superset-ui/core'; -import { EChartsCoreOption } from 'echarts'; import { CallbackDataParams } from 'echarts/types/src/util/types'; -import { LabelPositionEnum } from '../types'; +import { + BaseTransformedProps, + ContextMenuTransformedProps, + CrossFilterTransformedProps, + LabelPositionEnum, + TreePathInfo, +} from '../types'; export type EchartsTreemapFormData = QueryFormData & { colorScheme?: string; @@ -40,7 +43,6 @@ export type EchartsTreemapFormData = QueryFormData & { numberFormat: string; dateFormat: string; dashboardId?: number; - emitFilter: boolean; }; export enum EchartsTreemapLabelType { @@ -63,26 +65,12 @@ export const DEFAULT_FORM_DATA: Partial<EchartsTreemapFormData> = { showLabels: true, showUpperLabels: true, dateFormat: 'smart_date', - emitFilter: false, }; - -export interface TreePathInfo { - name: string; - dataIndex: number; - value: number | number[]; -} export interface TreemapSeriesCallbackDataParams extends CallbackDataParams { treePathInfo?: TreePathInfo[]; } -export interface TreemapTransformedProps { - formData: EchartsTreemapFormData; - height: number; - width: number; - echartOptions: EChartsCoreOption; - emitFilter: boolean; - setDataMask: SetDataMaskHook; - labelMap: Record<string, DataRecordValue[]>; - groupby: QueryFormColumn[]; - selectedValues: Record<number, string>; -} +export type TreemapTransformedProps = + BaseTransformedProps<EchartsTreemapFormData> & + ContextMenuTransformedProps & + CrossFilterTransformedProps; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx index 51ea5d5796923..011d62abacec4 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx @@ -22,6 +22,8 @@ import React, { useMemo, forwardRef, useImperativeHandle, + useLayoutEffect, + useCallback, } from 'react'; import { styled } from '@superset-ui/core'; import { ECharts, init } from 'echarts'; @@ -40,10 +42,15 @@ function Echart( eventHandlers, zrEventHandlers, selectedValues = {}, + refs, }: EchartsProps, ref: React.Ref<EchartsHandler>, ) { const divRef = useRef<HTMLDivElement>(null); + if (refs) { + // eslint-disable-next-line no-param-reassign + refs.divRef = divRef; + } const chartRef = useRef<ECharts>(); const currentSelection = useMemo( () => Object.keys(selectedValues) || [], @@ -92,11 +99,24 @@ function Echart( previousSelection.current = currentSelection; }, [currentSelection]); + const handleSizeChange = useCallback( + ({ width, height }: { width: number; height: number }) => { + if (chartRef.current) { + chartRef.current.resize({ width, height }); + } + }, + [], + ); + + // did mount useEffect(() => { - if (chartRef.current) { - chartRef.current.resize({ width, height }); - } - }, [width, height]); + handleSizeChange({ width, height }); + return () => chartRef.current?.dispose(); + }, []); + + useLayoutEffect(() => { + handleSizeChange({ width, height }); + }, [width, height, handleSizeChange]); return <Styles ref={divRef} height={height} width={width} />; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/constants.ts b/superset-frontend/plugins/plugin-chart-echarts/src/constants.ts index 513a0bebc1843..1c20128b67c64 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/constants.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/constants.ts @@ -19,13 +19,19 @@ import { JsonValue, t, TimeGranularity } from '@superset-ui/core'; import { ReactNode } from 'react'; -import { LabelPositionEnum } from './types'; +import { + LegendFormData, + TitleFormData, + LabelPositionEnum, + LegendOrientation, + LegendType, +} from './types'; // eslint-disable-next-line import/prefer-default-export export const NULL_STRING = '<NULL>'; export const TIMESERIES_CONSTANTS = { - gridOffsetRight: 40, + gridOffsetRight: 20, gridOffsetLeft: 20, gridOffsetTop: 20, gridOffsetBottom: 20, @@ -84,3 +90,27 @@ export const TIMEGRAIN_TO_TIMESTAMP = { [TimeGranularity.QUARTER]: 3600 * 1000 * 24 * 31 * 3, [TimeGranularity.YEAR]: 3600 * 1000 * 24 * 31 * 12, }; + +export const DEFAULT_LEGEND_FORM_DATA: LegendFormData = { + legendMargin: null, + legendOrientation: LegendOrientation.Top, + legendType: LegendType.Scroll, + showLegend: true, +}; + +export const DEFAULT_TITLE_FORM_DATA: TitleFormData = { + xAxisTitle: '', + xAxisTitleMargin: 0, + yAxisTitle: '', + yAxisTitleMargin: 0, + yAxisTitlePosition: 'Top', +}; + +export { DEFAULT_FORM_DATA } from './Timeseries/constants'; + +// How far away from the mouse should the tooltip be +export const TOOLTIP_POINTER_MARGIN = 10; + +// If no satisfactory position can be found, how far away +// from the edge of the window should the tooltip be kept +export const TOOLTIP_OVERFLOW_MARGIN = 5; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx index b8d54fc09a41a..ff74cd171d3db 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx @@ -17,22 +17,15 @@ * under the License. */ import React from 'react'; -import { - FeatureFlag, - isFeatureEnabled, - t, - validateNonEmpty, -} from '@superset-ui/core'; +import { t } from '@superset-ui/core'; import { ControlPanelsContainerProps, - ControlPanelState, ControlSetItem, ControlSetRow, - ControlState, sharedControls, } from '@superset-ui/chart-controls'; -import { DEFAULT_LEGEND_FORM_DATA } from './types'; -import { DEFAULT_FORM_DATA } from './Timeseries/types'; +import { DEFAULT_LEGEND_FORM_DATA } from './constants'; +import { DEFAULT_FORM_DATA } from './Timeseries/constants'; const { legendMargin, legendOrientation, legendType, showLegend } = DEFAULT_LEGEND_FORM_DATA; @@ -67,10 +60,10 @@ const legendTypeControl: ControlSetItem = { config: { type: 'SelectControl', freeForm: false, - label: 'Type', + label: t('Type'), choices: [ - ['scroll', 'Scroll'], - ['plain', 'Plain'], + ['scroll', t('Scroll')], + ['plain', t('Plain')], ], default: legendType, renderTrigger: true, @@ -85,16 +78,16 @@ const legendOrientationControl: ControlSetItem = { config: { type: 'SelectControl', freeForm: false, - label: 'Orientation', + label: t('Orientation'), choices: [ - ['top', 'Top'], - ['bottom', 'Bottom'], - ['left', 'Left'], - ['right', 'Right'], + ['top', t('Top')], + ['bottom', t('Bottom')], + ['left', t('Left')], + ['right', t('Right')], ], default: legendOrientation, renderTrigger: true, - description: t('Legend type'), + description: t('Legend Orientation'), visibility: ({ controls }: ControlPanelsContainerProps) => Boolean(controls?.show_legend?.value), }, @@ -145,33 +138,6 @@ export const onlyTotalControl: ControlSetItem = { }, }; -export const xAxisControl: ControlSetItem = { - name: 'x_axis', - config: { - ...sharedControls.groupby, - label: t('X-axis'), - default: ( - control: ControlState, - controlPanel: Partial<ControlPanelState>, - ) => { - // default to the chosen time column if x-axis is unset and the - // GENERIC_CHART_AXES feature flag is enabled - const { value } = control; - if (value) { - return value; - } - const timeColumn = controlPanel?.form_data?.granularity_sqla; - if (isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) && timeColumn) { - return timeColumn; - } - return null; - }, - multi: false, - description: t('Dimension to use on x-axis.'), - validators: [validateNonEmpty], - }, -}; - const percentageThresholdControl: ControlSetItem = { name: 'percentage_threshold', config: { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/defaults.ts b/superset-frontend/plugins/plugin-chart-echarts/src/defaults.ts index c74e3d78a0434..c5ada14932ebf 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/defaults.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/defaults.ts @@ -1,5 +1,3 @@ -import { LegendOrientation } from './types'; - /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,14 +16,12 @@ import { LegendOrientation } from './types'; * specific language governing permissions and limitations * under the License. */ +import { LegendOrientation } from './types'; + export const defaultGrid = { containLabel: true, }; -export const defaultTooltip = { - confine: true, -}; - export const defaultYAxis = { scale: true, }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/index.ts index 84a1a3a3dcc39..0301f265b051a 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/index.ts @@ -33,6 +33,7 @@ export { default as EchartsFunnelChartPlugin } from './Funnel'; export { default as EchartsTreeChartPlugin } from './Tree'; export { default as EchartsTreemapChartPlugin } from './Treemap'; export { BigNumberChartPlugin, BigNumberTotalChartPlugin } from './BigNumber'; +export { default as EchartsSunburstChartPlugin } from './Sunburst'; export { default as BoxPlotTransformProps } from './BoxPlot/transformProps'; export { default as FunnelTransformProps } from './Funnel/transformProps'; @@ -44,8 +45,9 @@ export { default as RadarTransformProps } from './Radar/transformProps'; export { default as TimeseriesTransformProps } from './Timeseries/transformProps'; export { default as TreeTransformProps } from './Tree/transformProps'; export { default as TreemapTransformProps } from './Treemap/transformProps'; +export { default as SunburstTransformProps } from './Sunburst/transformProps'; -export { DEFAULT_FORM_DATA as TimeseriesDefaultFormData } from './Timeseries/types'; +export { DEFAULT_FORM_DATA as TimeseriesDefaultFormData } from './Timeseries/constants'; export * from './types'; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/types.ts index d84b7079c4794..c24e2d84f46d1 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/types.ts @@ -16,15 +16,18 @@ * specific language governing permissions and limitations * under the License. */ +import React, { RefObject } from 'react'; import { - DataRecordValue, + BinaryQueryObjectFilterClause, + ChartDataResponseResult, + ChartProps, HandlerFunction, + PlainObject, QueryFormColumn, SetDataMaskHook, } from '@superset-ui/core'; import { EChartsCoreOption, ECharts } from 'echarts'; import { TooltipMarker } from 'echarts/types/src/util/format'; -import { OptionName } from 'echarts/types/src/util/types'; import { AreaChartExtraControlsValue } from './constants'; export type EchartsStylesProps = { @@ -32,6 +35,11 @@ export type EchartsStylesProps = { width: number; }; +export type Refs = { + echartRef?: React.Ref<EchartsHandler>; + divRef?: RefObject<HTMLDivElement>; +}; + export interface EchartsProps { height: number; width: number; @@ -40,6 +48,7 @@ export interface EchartsProps { zrEventHandlers?: EventHandlers; selectedValues?: Record<number, string>; forceClear?: boolean; + refs: Refs; } export interface EchartsHandler { @@ -78,20 +87,13 @@ export type ForecastValue = { forecastUpper?: number; }; -export type EchartsLegendFormData = { +export type LegendFormData = { legendMargin: number | null | string; legendOrientation: LegendOrientation; legendType: LegendType; showLegend: boolean; }; -export const DEFAULT_LEGEND_FORM_DATA: EchartsLegendFormData = { - legendMargin: null, - legendOrientation: LegendOrientation.Top, - legendType: LegendType.Scroll, - showLegend: true, -}; - export type EventHandlers = Record<string, { (props: any): void }>; export enum LabelPositionEnum { @@ -110,21 +112,41 @@ export enum LabelPositionEnum { InsideBottomRight = 'insideBottomRight', } -export interface EChartTransformedProps<F> { +export interface BaseChartProps<T extends PlainObject> extends ChartProps<T> { + queriesData: ChartDataResponseResult[]; +} + +export interface BaseTransformedProps<F> { + echartOptions: EChartsCoreOption; formData: F; height: number; + onContextMenu?: ( + clientX: number, + clientY: number, + filters?: BinaryQueryObjectFilterClause[], + ) => void; + refs: Refs; width: number; - echartOptions: EChartsCoreOption; - emitFilter: boolean; - setDataMask: SetDataMaskHook; - setControlValue?: HandlerFunction; - labelMap: Record<string, DataRecordValue[]>; +} + +export type CrossFilterTransformedProps = { groupby: QueryFormColumn[]; + labelMap: Record<string, string[]>; + setControlValue?: HandlerFunction; + setDataMask: SetDataMaskHook; selectedValues: Record<number, string>; - legendData?: OptionName[]; -} + emitCrossFilters?: boolean; +}; + +export type ContextMenuTransformedProps = { + onContextMenu?: ( + clientX: number, + clientY: number, + filters?: BinaryQueryObjectFilterClause[], + ) => void; +}; -export interface EchartsTitleFormData { +export interface TitleFormData { xAxisTitle: string; xAxisTitleMargin: number; yAxisTitle: string; @@ -132,14 +154,12 @@ export interface EchartsTitleFormData { yAxisTitlePosition: string; } -export const DEFAULT_TITLE_FORM_DATA: EchartsTitleFormData = { - xAxisTitle: '', - xAxisTitleMargin: 0, - yAxisTitle: '', - yAxisTitleMargin: 0, - yAxisTitlePosition: 'Top', -}; - export type StackType = boolean | null | Partial<AreaChartExtraControlsValue>; +export interface TreePathInfo { + name: string; + dataIndex: number; + value: number | number[]; +} + export * from './Timeseries/types'; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/utils/annotation.ts b/superset-frontend/plugins/plugin-chart-echarts/src/utils/annotation.ts index 3a95082863126..d3d858d9792a4 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/utils/annotation.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/annotation.ts @@ -25,26 +25,32 @@ import { AnnotationLayer, AnnotationOpacity, AnnotationType, + DataRecord, evalExpression, FormulaAnnotationLayer, isRecordAnnotationResult, isTableAnnotationLayer, isTimeseriesAnnotationResult, - TimeseriesDataRecord, + AxisType, } from '@superset-ui/core'; import { EchartsTimeseriesChartProps } from '../types'; import { EchartsMixedTimeseriesProps } from '../MixedTimeseries/types'; export function evalFormula( formula: FormulaAnnotationLayer, - data: TimeseriesDataRecord[], -): [number, number][] { + data: DataRecord[], + xAxis: string, + xAxisType: AxisType, +): [any, number][] { const { value: expression } = formula; - return data.map(row => [ - Number(row.__timestamp), - evalExpression(expression, row.__timestamp as number), - ]); + return data.map(row => { + let value = row[xAxis]; + if (xAxisType === 'time') { + value = new Date(value as string).getTime(); + } + return [value, evalExpression(expression, (value || 0) as number)]; + }); } export function parseAnnotationOpacity(opacity?: AnnotationOpacity): number { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/utils/eventHandlers.ts b/superset-frontend/plugins/plugin-chart-echarts/src/utils/eventHandlers.ts new file mode 100644 index 0000000000000..0d26b92d08df4 --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/eventHandlers.ts @@ -0,0 +1,82 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { BinaryQueryObjectFilterClause } from '@superset-ui/core'; +import { + BaseTransformedProps, + CrossFilterTransformedProps, + EventHandlers, +} from '../types'; + +export type Event = { + name: string; + event: { stop: () => void; event: PointerEvent }; +}; + +export const clickEventHandler = + ( + selectedValues: Record<number, string>, + handleChange: (values: string[]) => void, + ) => + ({ name }: { name: string }) => { + const values = Object.values(selectedValues); + if (values.includes(name)) { + handleChange(values.filter(v => v !== name)); + } else { + handleChange([name]); + } + }; + +export const contextMenuEventHandler = + ( + groupby: (BaseTransformedProps<any> & + CrossFilterTransformedProps)['groupby'], + onContextMenu: BaseTransformedProps<any>['onContextMenu'], + labelMap: Record<string, string[]>, + ) => + (e: Event) => { + if (onContextMenu) { + e.event.stop(); + const pointerEvent = e.event.event; + const filters: BinaryQueryObjectFilterClause[] = []; + if (groupby.length > 0) { + const values = labelMap[e.name]; + groupby.forEach((dimension, i) => + filters.push({ + col: dimension, + op: '==', + val: values[i], + formattedVal: String(values[i]), + }), + ); + } + onContextMenu(pointerEvent.clientX, pointerEvent.clientY, filters); + } + }; + +export const allEventHandlers = ( + transformedProps: BaseTransformedProps<any> & CrossFilterTransformedProps, + handleChange: (values: string[]) => void, +) => { + const { groupby, selectedValues, onContextMenu, labelMap } = transformedProps; + const eventHandlers: EventHandlers = { + click: clickEventHandler(selectedValues, handleChange), + contextmenu: contextMenuEventHandler(groupby, onContextMenu, labelMap), + }; + return eventHandlers; +}; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts index 8d93ce3f34312..c1b61233b6c62 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts @@ -24,8 +24,10 @@ import { DTTM_ALIAS, ensureIsArray, GenericDataType, + NumberFormats, NumberFormatter, TimeFormatter, + AxisType, } from '@superset-ui/core'; import { format, LegendComponentOption, SeriesOption } from 'echarts'; import { @@ -320,14 +322,30 @@ export const currentSeries = { legend: '', }; -export function getAxisType( - dataType?: GenericDataType, -): 'time' | 'value' | 'category' { +export function getAxisType(dataType?: GenericDataType): AxisType { if (dataType === GenericDataType.TEMPORAL) { - return 'time'; + return AxisType.time; } - if (dataType === GenericDataType.NUMERIC) { - return 'value'; - } - return 'category'; + return AxisType.category; +} + +export function getOverMaxHiddenFormatter( + config: { + max?: number; + formatter?: NumberFormatter; + } = {}, +) { + const { max, formatter } = config; + // Only apply this logic if there's a MAX set in the controls + const shouldHideIfOverMax = !!max || max === 0; + + return new NumberFormatter({ + formatFunc: value => + `${ + shouldHideIfOverMax && value > max + ? '' + : formatter?.format(value) || value + }`, + id: NumberFormats.OVER_MAX_HIDDEN, + }); } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/utils/tooltip.ts b/superset-frontend/plugins/plugin-chart-echarts/src/utils/tooltip.ts new file mode 100644 index 0000000000000..c1fd7ac0a3f7f --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/tooltip.ts @@ -0,0 +1,79 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CallbackDataParams } from 'echarts/types/src/util/types'; +import { TOOLTIP_OVERFLOW_MARGIN, TOOLTIP_POINTER_MARGIN } from '../constants'; +import { Refs } from '../types'; + +export function getDefaultTooltip(refs: Refs) { + return { + appendToBody: true, + position: ( + canvasMousePos: [number, number], + params: CallbackDataParams, + tooltipDom: HTMLDivElement | null, + rect: any, + sizes: { contentSize: [number, number]; viewSize: [number, number] }, + ) => { + // algorithm partially based on this snippet: + // https://github.com/apache/echarts/issues/5004#issuecomment-559668309 + + // The chart canvas position + const divRect = refs.divRef?.current?.getBoundingClientRect(); + + // The mouse coordinates relative to the whole window + // The first parameter to the position function is the mouse position relative to the canvas + const mouseX = canvasMousePos[0] + (divRect?.x || 0); + const mouseY = canvasMousePos[1] + (divRect?.y || 0); + + // The width and height of the tooltip dom element + const tooltipWidth = sizes.contentSize[0]; + const tooltipHeight = sizes.contentSize[1]; + + // Start by placing the tooltip top and right relative to the mouse position + let xPos = mouseX + TOOLTIP_POINTER_MARGIN; + let yPos = mouseY - TOOLTIP_POINTER_MARGIN - tooltipHeight; + + // The tooltip is overflowing past the right edge of the window + if (xPos + tooltipWidth >= document.documentElement.clientWidth) { + // Attempt to place the tooltip to the left of the mouse position + xPos = mouseX - TOOLTIP_POINTER_MARGIN - tooltipWidth; + + // The tooltip is overflowing past the left edge of the window + if (xPos <= 0) + // Place the tooltip a fixed distance from the left edge of the window + xPos = TOOLTIP_OVERFLOW_MARGIN; + } + + // The tooltip is overflowing past the top edge of the window + if (yPos <= 0) { + // Attempt to place the tooltip to the bottom of the mouse position + yPos = mouseY + TOOLTIP_POINTER_MARGIN; + + // The tooltip is overflowing past the bottom edge of the window + if (yPos + tooltipHeight >= document.documentElement.clientHeight) + // Place the tooltip a fixed distance from the top edge of the window + yPos = TOOLTIP_OVERFLOW_MARGIN; + } + + // Return the position (converted back to a relative position on the canvas) + return [xPos - (divRect?.x || 0), yPos - (divRect?.y || 0)]; + }, + }; +} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/utils/treeBuilder.ts b/superset-frontend/plugins/plugin-chart-echarts/src/utils/treeBuilder.ts new file mode 100644 index 0000000000000..97916997d4d4c --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/treeBuilder.ts @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { DataRecord, DataRecordValue } from '@superset-ui/core'; +import _ from 'lodash'; + +export type TreeNode = { + name: DataRecordValue; + value: number; + secondaryValue: number; + groupBy: string; + children?: TreeNode[]; +}; + +function getMetricValue(datum: DataRecord, metric: string) { + return _.isNumber(datum[metric]) ? (datum[metric] as number) : 0; +} + +export function treeBuilder( + data: DataRecord[], + groupBy: string[], + metric: string, + secondaryMetric?: string, +): TreeNode[] { + const [curGroupBy, ...restGroupby] = groupBy; + const curData = _.groupBy(data, curGroupBy); + return _.transform( + curData, + (result, value, key) => { + const name = curData[key][0][curGroupBy]!; + if (!restGroupby.length) { + (value ?? []).forEach(datum => { + const metricValue = getMetricValue(datum, metric); + const secondaryValue = secondaryMetric + ? getMetricValue(datum, secondaryMetric) + : metricValue; + const item = { + name, + value: metricValue, + secondaryValue, + groupBy: curGroupBy, + }; + result.push(item); + }); + } else { + const children = treeBuilder( + value, + restGroupby, + metric, + secondaryMetric, + ); + const metricValue = children.reduce( + (prev, cur) => prev + (cur.value as number), + 0, + ); + const secondaryValue = secondaryMetric + ? children.reduce( + (prev, cur) => prev + (cur.secondaryValue as number), + 0, + ) + : metricValue; + result.push({ + name, + children, + value: metricValue, + secondaryValue, + groupBy: curGroupBy, + }); + } + }, + [] as TreeNode[], + ); +} diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts index 6529c2dafabf7..ce00bb71906f1 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts @@ -25,6 +25,7 @@ import transformProps from '../../src/BigNumber/BigNumberWithTrendline/transform import { BigNumberDatum, BigNumberWithTrendlineChartProps, + BigNumberWithTrendlineFormData, } from '../../src/BigNumber/types'; const formData = { @@ -36,14 +37,17 @@ const formData = { a: 1, }, compareLag: 1, - timeGrainSqla: 'P3M' as TimeGranularity, + timeGrainSqla: TimeGranularity.QUARTER, + granularitySqla: 'ds', compareSuffix: 'over last quarter', viz_type: 'big_number', yAxisFormat: '.3s', datasource: 'test_datasource', }; -const rawFormData = { +const rawFormData: BigNumberWithTrendlineFormData = { + colorPicker: { b: 0, g: 0, r: 0 }, + datasource: '1__table', metric: 'value', color_picker: { r: 0, @@ -52,7 +56,8 @@ const rawFormData = { a: 1, }, compare_lag: 1, - time_grain_sqla: 'P3M' as TimeGranularity, + time_grain_sqla: TimeGranularity.QUARTER, + granularity_sqla: 'ds', compare_suffix: 'over last quarter', viz_type: 'big_number', y_axis_format: '.3s', @@ -126,7 +131,8 @@ describe('BigNumberWithTrendline', () => { expect(transformed.bigNumber).toStrictEqual(1.2345); expect(transformed.bigNumberFallback).not.toBeNull(); - // should successfully formatTime by ganularity + // should successfully formatTime by granularity + // @ts-ignore expect(transformed.formatTime(new Date('2020-01-01'))).toStrictEqual( '2020-01-01 00:00:00', ); @@ -147,6 +153,7 @@ describe('BigNumberWithTrendline', () => { }, }; const transformed = transformProps(propsWithDatasource); + // @ts-ignore expect(transformed.headerFormatter(transformed.bigNumber)).toStrictEqual( '1.23', ); diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/BoxPlot/buildQuery.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/BoxPlot/buildQuery.test.ts index 6859248713442..0d0f2f838990f 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/BoxPlot/buildQuery.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/BoxPlot/buildQuery.test.ts @@ -20,14 +20,13 @@ import { isPostProcessingBoxplot, PostProcessingBoxplot, } from '@superset-ui/core'; -import { DEFAULT_TITLE_FORM_DATA } from '../../src/types'; +import { DEFAULT_TITLE_FORM_DATA } from '../../src/constants'; import buildQuery from '../../src/BoxPlot/buildQuery'; import { BoxPlotQueryFormData } from '../../src/BoxPlot/types'; describe('BoxPlot buildQuery', () => { const formData: BoxPlotQueryFormData = { ...DEFAULT_TITLE_FORM_DATA, - emitFilter: false, columns: [], datasource: '5__table', granularity_sqla: 'ds', diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/Gauge/buildQuery.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/Gauge/buildQuery.test.ts index 77f1322f9be95..7eb975dafecd8 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/Gauge/buildQuery.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/Gauge/buildQuery.test.ts @@ -29,20 +29,20 @@ describe('Gauge buildQuery', () => { const formData = { ...baseFormData, groupby: undefined }; const queryContext = buildQuery(formData); const [query] = queryContext.queries; - expect(query.groupby).toEqual([]); + expect(query.columns).toEqual([]); }); it('should build query fields with single group by column', () => { const formData = { ...baseFormData, groupby: ['foo'] }; const queryContext = buildQuery(formData); const [query] = queryContext.queries; - expect(query.groupby).toEqual(['foo']); + expect(query.columns).toEqual(['foo']); }); it('should build query fields with multiple group by columns', () => { const formData = { ...baseFormData, groupby: ['foo', 'bar'] }; const queryContext = buildQuery(formData); const [query] = queryContext.queries; - expect(query.groupby).toEqual(['foo', 'bar']); + expect(query.columns).toEqual(['foo', 'bar']); }); }); diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/Graph/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/Graph/transformProps.test.ts index 480f4828f3378..61adda8a98c74 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/Graph/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/Graph/transformProps.test.ts @@ -16,13 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -import { ChartProps, supersetTheme } from '@superset-ui/core'; +import { ChartProps, SqlaFormData, supersetTheme } from '@superset-ui/core'; import transformProps from '../../src/Graph/transformProps'; import { DEFAULT_GRAPH_SERIES_OPTION } from '../../src/Graph/constants'; +import { EchartsGraphChartProps } from '../../src/Graph/types'; describe('EchartsGraph transformProps', () => { it('should transform chart props for viz without category', () => { - const formData = { + const formData: SqlaFormData = { colorScheme: 'bnbColors', datasource: '3__table', granularity_sqla: 'ds', @@ -30,6 +31,7 @@ describe('EchartsGraph transformProps', () => { source: 'source_column', target: 'target_column', category: null, + viz_type: 'graph', }; const queriesData = [ { @@ -57,7 +59,7 @@ describe('EchartsGraph transformProps', () => { }; const chartProps = new ChartProps(chartPropsConfig); - expect(transformProps(chartProps)).toEqual( + expect(transformProps(chartProps as EchartsGraphChartProps)).toEqual( expect.objectContaining({ width: 800, height: 600, @@ -78,7 +80,11 @@ describe('EchartsGraph transformProps', () => { label: { fontWeight: 'bolder' }, }, symbolSize: 50, - tooltip: { formatter: '{b}: {c}' }, + tooltip: { + appendToBody: true, + formatter: '{b}: {c}', + position: expect.anything(), + }, value: 6, }, { @@ -91,7 +97,11 @@ describe('EchartsGraph transformProps', () => { label: { fontWeight: 'bolder' }, }, symbolSize: 50, - tooltip: { formatter: '{b}: {c}' }, + tooltip: { + appendToBody: true, + formatter: '{b}: {c}', + position: expect.anything(), + }, value: 6, }, { @@ -104,7 +114,11 @@ describe('EchartsGraph transformProps', () => { label: { fontWeight: 'bolder' }, }, symbolSize: 10, - tooltip: { formatter: '{b}: {c}' }, + tooltip: { + appendToBody: true, + formatter: '{b}: {c}', + position: expect.anything(), + }, value: 5, }, { @@ -117,7 +131,11 @@ describe('EchartsGraph transformProps', () => { label: { fontWeight: 'bolder' }, }, symbolSize: 10, - tooltip: { formatter: '{b}: {c}' }, + tooltip: { + appendToBody: true, + formatter: '{b}: {c}', + position: expect.anything(), + }, value: 5, }, ], @@ -151,7 +169,7 @@ describe('EchartsGraph transformProps', () => { }); it('should transform chart props for viz with category and falsey normalization', () => { - const formData = { + const formData: SqlaFormData = { colorScheme: 'bnbColors', datasource: '3__table', granularity_sqla: 'ds', @@ -160,6 +178,7 @@ describe('EchartsGraph transformProps', () => { target: 'target_column', sourceCategory: 'source_category_column', targetCategory: 'target_category_column', + viz_type: 'graph', }; const queriesData = [ { @@ -197,7 +216,7 @@ describe('EchartsGraph transformProps', () => { }; const chartProps = new ChartProps(chartPropsConfig); - expect(transformProps(chartProps)).toEqual( + expect(transformProps(chartProps as EchartsGraphChartProps)).toEqual( expect.objectContaining({ width: 800, height: 600, @@ -215,7 +234,11 @@ describe('EchartsGraph transformProps', () => { symbolSize: 10, category: 'category_value_1', select: DEFAULT_GRAPH_SERIES_OPTION.select, - tooltip: DEFAULT_GRAPH_SERIES_OPTION.tooltip, + tooltip: { + appendToBody: true, + formatter: '{b}: {c}', + position: expect.anything(), + }, label: { show: true }, }, { @@ -225,7 +248,11 @@ describe('EchartsGraph transformProps', () => { symbolSize: 10, category: 'category_value_2', select: DEFAULT_GRAPH_SERIES_OPTION.select, - tooltip: DEFAULT_GRAPH_SERIES_OPTION.tooltip, + tooltip: { + appendToBody: true, + formatter: '{b}: {c}', + position: expect.anything(), + }, label: { show: true }, }, ], diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/MixedTimeseries/buildQuery.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/MixedTimeseries/buildQuery.test.ts index 0b766c2dc4e43..15d9e2cbb6e17 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/MixedTimeseries/buildQuery.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/MixedTimeseries/buildQuery.test.ts @@ -17,7 +17,7 @@ * under the License. */ import { - ComparisionType, + ComparisonType, FreeFormAdhocFilter, RollingType, TimeGranularity, @@ -46,8 +46,8 @@ const formDataMixedChart = { row_limit: 10, timeseries_limit_metric: 'count', order_desc: true, - emit_filter: true, truncate_metric: true, + show_empty_columns: true, // -- query b groupby_b: [], metrics_b: ['count'], @@ -62,8 +62,8 @@ const formDataMixedChart = { row_limit_b: 100, timeseries_limit_metric_b: undefined, order_desc_b: false, - emit_filter_b: undefined, truncate_metric_b: true, + show_empty_columns_b: true, // chart configs show_value: false, show_valueB: undefined, @@ -72,14 +72,14 @@ const formDataMixedChartWithAA = { ...formDataMixedChart, rolling_type: RollingType.Cumsum, time_compare: ['1 years ago'], - comparison_type: ComparisionType.Values, + comparison_type: ComparisonType.Values, resample_rule: '1AS', resample_method: 'zerofill', rolling_type_b: RollingType.Sum, rolling_periods_b: 1, min_periods_b: 1, - comparison_type_b: ComparisionType.Difference, + comparison_type_b: ComparisonType.Difference, time_compare_b: ['3 years ago'], resample_rule_b: '1A', resample_method_b: 'asfreq', @@ -95,7 +95,6 @@ test('should compile query object A', () => { filters: [], extras: { having: '', - having_druid: [], time_grain_sqla: 'P1W', where: "(foo in ('a', 'b'))", }, @@ -106,9 +105,8 @@ test('should compile query object A', () => { row_limit: 10, row_offset: undefined, series_columns: ['foo'], - series_limit: undefined, + series_limit: 5, series_limit_metric: undefined, - timeseries_limit: 5, url_params: {}, custom_params: {}, custom_form_data: {}, @@ -125,9 +123,7 @@ test('should compile query object A', () => { }, columns: ['foo'], drop_missing_columns: false, - flatten_columns: false, index: ['__timestamp'], - reset_index: false, }, }, { @@ -158,7 +154,6 @@ test('should compile query object B', () => { filters: [], extras: { having: '', - having_druid: [], time_grain_sqla: 'P1W', where: "(name in ('c', 'd'))", }, @@ -169,9 +164,8 @@ test('should compile query object B', () => { row_limit: 100, row_offset: undefined, series_columns: [], - series_limit: undefined, + series_limit: 0, series_limit_metric: undefined, - timeseries_limit: 0, url_params: {}, custom_params: {}, custom_form_data: {}, @@ -188,9 +182,7 @@ test('should compile query object B', () => { }, columns: [], drop_missing_columns: false, - flatten_columns: false, index: ['__timestamp'], - reset_index: false, }, }, { @@ -206,6 +198,21 @@ test('should compile AA in query A', () => { // time comparison expect(query.time_offsets).toEqual(['1 years ago']); + // pivot + expect( + query.post_processing?.find(operator => operator?.operation === 'pivot'), + ).toEqual({ + operation: 'pivot', + options: { + index: ['__timestamp'], + columns: ['foo'], + drop_missing_columns: false, + aggregates: { + 'sum(sales)': { operator: 'mean' }, + 'sum(sales)__1 years ago': { operator: 'mean' }, + }, + }, + }); // cumsum expect( // prettier-ignore @@ -271,7 +278,22 @@ test('should compile AA in query B', () => { }); }); -test('should compile query objects with x-axis', () => { +test('should convert a queryObject with x-axis although FF is disabled', () => { + let windowSpy: any; + + beforeAll(() => { + // @ts-ignore + windowSpy = jest.spyOn(window, 'window', 'get').mockImplementation(() => ({ + featureFlags: { + GENERIC_CHART_AXES: false, + }, + })); + }); + + afterAll(() => { + windowSpy.mockRestore(); + }); + const { queries } = buildQuery({ ...formDataMixedChart, x_axis: 'my_index', @@ -284,24 +306,29 @@ test('should compile query objects with x-axis', () => { filters: [], extras: { having: '', - having_druid: [], - time_grain_sqla: 'P1W', where: "(foo in ('a', 'b'))", }, applied_time_extras: {}, - columns: ['my_index', 'foo'], + columns: [ + { + columnType: 'BASE_AXIS', + expressionType: 'SQL', + label: 'my_index', + sqlExpression: 'my_index', + timeGrain: 'P1W', + }, + 'foo', + ], metrics: ['sum(sales)'], annotation_layers: [], row_limit: 10, row_offset: undefined, series_columns: ['foo'], - series_limit: undefined, + series_limit: 5, series_limit_metric: undefined, - timeseries_limit: 5, url_params: {}, custom_params: {}, custom_form_data: {}, - is_timeseries: false, time_offsets: [], post_processing: [ { @@ -314,9 +341,7 @@ test('should compile query objects with x-axis', () => { }, columns: ['foo'], drop_missing_columns: false, - flatten_columns: false, index: ['my_index'], - reset_index: false, }, }, { @@ -339,8 +364,16 @@ test('should compile query objects with x-axis', () => { // check the main props on the second query expect(queries[1]).toEqual( expect.objectContaining({ - is_timeseries: false, - columns: ['my_index'], + columns: [ + { + columnType: 'BASE_AXIS', + expressionType: 'SQL', + label: 'my_index', + sqlExpression: 'my_index', + timeGrain: 'P1W', + }, + ], + granularity: 'ds', series_columns: [], metrics: ['count'], post_processing: [ @@ -354,9 +387,7 @@ test('should compile query objects with x-axis', () => { }, columns: [], drop_missing_columns: false, - flatten_columns: false, index: ['my_index'], - reset_index: false, }, }, { @@ -366,3 +397,120 @@ test('should compile query objects with x-axis', () => { }), ); }); + +test("shouldn't convert a queryObject with axis although FF is enabled", () => { + const windowSpy = jest + .spyOn(window, 'window', 'get') + // @ts-ignore + .mockImplementation(() => ({ + featureFlags: { + GENERIC_CHART_AXES: true, + }, + })); + + const { queries } = buildQuery(formDataMixedChart); + expect(queries[0]).toEqual( + expect.objectContaining({ + granularity: 'ds', + columns: ['foo'], + series_columns: ['foo'], + metrics: ['sum(sales)'], + is_timeseries: true, + extras: { + time_grain_sqla: 'P1W', + having: '', + where: "(foo in ('a', 'b'))", + }, + post_processing: [ + { + operation: 'pivot', + options: { + aggregates: { + 'sum(sales)': { + operator: 'mean', + }, + }, + columns: ['foo'], + drop_missing_columns: false, + index: ['__timestamp'], + }, + }, + { + operation: 'rename', + options: { columns: { 'sum(sales)': null }, inplace: true, level: 0 }, + }, + { + operation: 'flatten', + }, + ], + }), + ); + expect(queries[1]).toEqual( + expect.objectContaining({ + granularity: 'ds', + columns: [], + series_columns: [], + metrics: ['count'], + is_timeseries: true, + extras: { + time_grain_sqla: 'P1W', + having: '', + where: "(name in ('c', 'd'))", + }, + post_processing: [ + { + operation: 'pivot', + options: { + aggregates: { + count: { + operator: 'mean', + }, + }, + columns: [], + drop_missing_columns: false, + index: ['__timestamp'], + }, + }, + { + operation: 'flatten', + }, + ], + }), + ); + + windowSpy.mockRestore(); +}); + +test('ensure correct pivot columns with GENERIC_CHART_AXES enabled', () => { + const windowSpy = jest + .spyOn(window, 'window', 'get') + // @ts-ignore + .mockImplementation(() => ({ + featureFlags: { + GENERIC_CHART_AXES: true, + }, + })); + + const query = buildQuery({ ...formDataMixedChartWithAA, x_axis: 'ds' }) + .queries[0]; + + expect(query.time_offsets).toEqual(['1 years ago']); + + // pivot + expect( + query.post_processing?.find(operator => operator?.operation === 'pivot'), + ).toEqual({ + operation: 'pivot', + options: { + index: ['ds'], + columns: ['foo'], + drop_missing_columns: false, + aggregates: { + 'sum(sales)': { operator: 'mean' }, + 'sum(sales)__1 years ago': { operator: 'mean' }, + }, + }, + }); + + windowSpy.mockRestore(); +}); diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/Timeseries/buildQuery.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/Timeseries/buildQuery.test.ts index 7c0787dc0241d..611f021af16f7 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/Timeseries/buildQuery.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/Timeseries/buildQuery.test.ts @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import { SqlaFormData } from '@superset-ui/core'; import buildQuery from '../../src/Timeseries/buildQuery'; describe('Timeseries buildQuery', () => { @@ -40,7 +41,7 @@ describe('Timeseries buildQuery', () => { }); const [query] = queryContext.queries; expect(query.metrics).toEqual(['bar', 'baz']); - expect(query.timeseries_limit_metric).toEqual('bar'); + expect(query.series_limit_metric).toEqual('bar'); expect(query.order_desc).toEqual(true); expect(query.orderby).toEqual([['bar', false]]); }); @@ -54,8 +55,186 @@ describe('Timeseries buildQuery', () => { }); const [query] = queryContext.queries; expect(query.metrics).toEqual(['bar', 'baz']); - expect(query.timeseries_limit_metric).toEqual('bar'); + expect(query.series_limit_metric).toEqual('bar'); expect(query.order_desc).toEqual(true); expect(query.orderby).toEqual([['foo', true]]); }); }); + +describe('GENERIC_CHART_AXES is enabled', () => { + let windowSpy: any; + + beforeAll(() => { + // @ts-ignore + windowSpy = jest.spyOn(window, 'window', 'get').mockImplementation(() => ({ + featureFlags: { + GENERIC_CHART_AXES: true, + }, + })); + }); + + afterAll(() => { + windowSpy.mockRestore(); + }); + + const formData: SqlaFormData = { + datasource: '5__table', + viz_type: 'table', + granularity_sqla: 'time_column', + time_grain_sqla: 'P1Y', + time_range: '1 year ago : 2013', + groupby: ['col1'], + metrics: ['count(*)'], + }; + + it("shouldn't convert queryObject", () => { + const { queries } = buildQuery(formData); + expect(queries[0]).toEqual( + expect.objectContaining({ + granularity: 'time_column', + time_range: '1 year ago : 2013', + extras: { time_grain_sqla: 'P1Y', having: '', where: '' }, + columns: ['col1'], + series_columns: ['col1'], + metrics: ['count(*)'], + is_timeseries: true, + post_processing: [ + { + operation: 'pivot', + options: { + aggregates: { 'count(*)': { operator: 'mean' } }, + columns: ['col1'], + drop_missing_columns: true, + index: ['__timestamp'], + }, + }, + { operation: 'flatten' }, + ], + }), + ); + }); + + it('should convert queryObject', () => { + const { queries } = buildQuery({ ...formData, x_axis: 'time_column' }); + expect(queries[0]).toEqual( + expect.objectContaining({ + granularity: 'time_column', + time_range: '1 year ago : 2013', + extras: { having: '', where: '' }, + columns: [ + { + columnType: 'BASE_AXIS', + expressionType: 'SQL', + label: 'time_column', + sqlExpression: 'time_column', + timeGrain: 'P1Y', + }, + 'col1', + ], + series_columns: ['col1'], + metrics: ['count(*)'], + post_processing: [ + { + operation: 'pivot', + options: { + aggregates: { 'count(*)': { operator: 'mean' } }, + columns: ['col1'], + drop_missing_columns: true, + index: ['time_column'], + }, + }, + { operation: 'flatten' }, + ], + }), + ); + }); +}); + +describe('GENERIC_CHART_AXES is disabled', () => { + let windowSpy: any; + + beforeAll(() => { + // @ts-ignore + windowSpy = jest.spyOn(window, 'window', 'get').mockImplementation(() => ({ + featureFlags: { + GENERIC_CHART_AXES: false, + }, + })); + }); + + afterAll(() => { + windowSpy.mockRestore(); + }); + + const formData: SqlaFormData = { + datasource: '5__table', + viz_type: 'table', + granularity_sqla: 'time_column', + time_grain_sqla: 'P1Y', + time_range: '1 year ago : 2013', + groupby: ['col1'], + metrics: ['count(*)'], + }; + + it("shouldn't convert queryObject", () => { + const { queries } = buildQuery(formData); + expect(queries[0]).toEqual( + expect.objectContaining({ + granularity: 'time_column', + time_range: '1 year ago : 2013', + extras: { time_grain_sqla: 'P1Y', having: '', where: '' }, + columns: ['col1'], + series_columns: ['col1'], + metrics: ['count(*)'], + is_timeseries: true, + post_processing: [ + { + operation: 'pivot', + options: { + aggregates: { 'count(*)': { operator: 'mean' } }, + columns: ['col1'], + drop_missing_columns: true, + index: ['__timestamp'], + }, + }, + { operation: 'flatten' }, + ], + }), + ); + }); + + it('should convert queryObject', () => { + const { queries } = buildQuery({ ...formData, x_axis: 'time_column' }); + expect(queries[0]).toEqual( + expect.objectContaining({ + granularity: 'time_column', + time_range: '1 year ago : 2013', + extras: { having: '', where: '' }, + columns: [ + { + columnType: 'BASE_AXIS', + expressionType: 'SQL', + label: 'time_column', + sqlExpression: 'time_column', + timeGrain: 'P1Y', + }, + 'col1', + ], + series_columns: ['col1'], + metrics: ['count(*)'], + post_processing: [ + { + operation: 'pivot', + options: { + aggregates: { 'count(*)': { operator: 'mean' } }, + columns: ['col1'], + drop_missing_columns: true, + index: ['time_column'], + }, + }, + { operation: 'flatten' }, + ], + }), + ); + }); +}); diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/Tree/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/Tree/transformProps.test.ts index ad06455cb11f7..6a56c997c22b6 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/Tree/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/Tree/transformProps.test.ts @@ -18,6 +18,7 @@ */ import { ChartProps, supersetTheme } from '@superset-ui/core'; import transformProps from '../../src/Tree/transformProps'; +import { EchartsTreeChartProps } from '../../src/Tree/types'; describe('EchartsTree transformProps', () => { const formData = { @@ -70,7 +71,7 @@ describe('EchartsTree transformProps', () => { ]; const chartProps = new ChartProps({ ...chartPropsConfig, queriesData }); - expect(transformProps(chartProps)).toEqual( + expect(transformProps(chartProps as EchartsTreeChartProps)).toEqual( expect.objectContaining({ width: 800, height: 600, @@ -137,7 +138,7 @@ describe('EchartsTree transformProps', () => { ]; const chartProps = new ChartProps({ ...chartPropsConfig, queriesData }); - expect(transformProps(chartProps)).toEqual( + expect(transformProps(chartProps as EchartsTreeChartProps)).toEqual( expect.objectContaining({ width: 800, height: 600, @@ -223,7 +224,7 @@ describe('EchartsTree transformProps', () => { ]; const chartProps = new ChartProps({ ...chartPropsConfig, queriesData }); - expect(transformProps(chartProps)).toEqual( + expect(transformProps(chartProps as EchartsTreeChartProps)).toEqual( expect.objectContaining({ width: 800, height: 600, @@ -299,7 +300,7 @@ describe('EchartsTree transformProps', () => { ]; const chartProps = new ChartProps({ ...chartPropsConfig, queriesData }); - expect(transformProps(chartProps)).toEqual( + expect(transformProps(chartProps as EchartsTreeChartProps)).toEqual( expect.objectContaining({ width: 800, height: 600, @@ -385,7 +386,7 @@ describe('EchartsTree transformProps', () => { ]; const chartProps = new ChartProps({ ...chartPropsConfig, queriesData }); - expect(transformProps(chartProps)).toEqual( + expect(transformProps(chartProps as EchartsTreeChartProps)).toEqual( expect.objectContaining({ width: 800, height: 600, diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/utils/annotation.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/utils/annotation.test.ts index 4d6b164924141..bef98483be20d 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/utils/annotation.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/utils/annotation.test.ts @@ -17,12 +17,14 @@ * under the License. */ import { - AnnotationLayer, AnnotationData, + AnnotationLayer, AnnotationOpacity, AnnotationSourceType, AnnotationStyle, AnnotationType, + AxisType, + DataRecord, FormulaAnnotationLayer, TimeseriesDataRecord, } from '@superset-ui/core'; @@ -160,7 +162,7 @@ describe('evalFormula', () => { { __timestamp: 10 }, ]; - expect(evalFormula(layer, data)).toEqual([ + expect(evalFormula(layer, data, '__timestamp', AxisType.time)).toEqual([ [0, 1], [10, 11], ]); @@ -172,9 +174,32 @@ describe('evalFormula', () => { { __timestamp: 10 }, ]; - expect(evalFormula({ ...layer, value: 'y = x* 2 -1' }, data)).toEqual([ + expect( + evalFormula( + { ...layer, value: 'y = x* 2 -1' }, + data, + '__timestamp', + AxisType.time, + ), + ).toEqual([ [0, -1], [10, 19], ]); }); + + it('Should evaluate a formula if axis type is category', () => { + const data: DataRecord[] = [{ gender: 'boy' }, { gender: 'girl' }]; + + expect( + evalFormula( + { ...layer, value: 'y = 1000' }, + data, + 'gender', + AxisType.category, + ), + ).toEqual([ + ['boy', 1000], + ['girl', 1000], + ]); + }); }); diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts index 3f20e0d5f8a37..3bd949d8ad63d 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts @@ -26,6 +26,7 @@ import { getLegendProps, sanitizeHtml, extractShowValueIndexes, + getOverMaxHiddenFormatter, } from '../../src/utils/series'; import { LegendOrientation, LegendType } from '../../src/types'; import { defaultLegendPadding } from '../../src/defaults'; @@ -536,4 +537,16 @@ describe('formatSeriesName', () => { expect(sanitizeHtml(NULL_STRING)).toEqual('<NULL>'); }); }); + + describe('getOverMaxHiddenFormatter', () => { + it('should hide value if greater than max', () => { + const formatter = getOverMaxHiddenFormatter({ max: 81000 }); + expect(formatter.format(84500)).toEqual(''); + }); + it('should show value if less or equal than max', () => { + const formatter = getOverMaxHiddenFormatter({ max: 81000 }); + expect(formatter.format(81000)).toEqual('81000'); + expect(formatter.format(50000)).toEqual('50000'); + }); + }); }); diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/utils/treeBuilder.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/utils/treeBuilder.test.ts new file mode 100644 index 0000000000000..b91349a895358 --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/test/utils/treeBuilder.test.ts @@ -0,0 +1,274 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { treeBuilder } from '../../src/utils/treeBuilder'; + +describe('test treeBuilder', () => { + const data = [ + { + foo: 'a-1', + bar: 'a', + count: 2, + count2: 3, + }, + { + foo: 'a-2', + bar: 'a', + count: 2, + count2: 3, + }, + { + foo: 'b-1', + bar: 'b', + count: 2, + count2: 3, + }, + { + foo: 'b-2', + bar: 'b', + count: 2, + count2: 3, + }, + { + foo: 'c-1', + bar: 'c', + count: 2, + count2: 3, + }, + { + foo: 'c-2', + bar: 'c', + count: 2, + count2: 3, + }, + { + foo: 'd-1', + bar: 'd', + count: 2, + count2: 3, + }, + ]; + it('should build tree as expected', () => { + const tree = treeBuilder(data, ['foo', 'bar'], 'count'); + expect(tree).toEqual([ + { + children: [ + { + groupBy: 'bar', + name: 'a', + secondaryValue: 2, + value: 2, + }, + ], + groupBy: 'foo', + name: 'a-1', + secondaryValue: 2, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'a', + secondaryValue: 2, + value: 2, + }, + ], + groupBy: 'foo', + name: 'a-2', + secondaryValue: 2, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'b', + secondaryValue: 2, + value: 2, + }, + ], + groupBy: 'foo', + name: 'b-1', + secondaryValue: 2, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'b', + secondaryValue: 2, + value: 2, + }, + ], + groupBy: 'foo', + name: 'b-2', + secondaryValue: 2, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'c', + secondaryValue: 2, + value: 2, + }, + ], + groupBy: 'foo', + name: 'c-1', + secondaryValue: 2, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'c', + secondaryValue: 2, + value: 2, + }, + ], + groupBy: 'foo', + name: 'c-2', + secondaryValue: 2, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'd', + secondaryValue: 2, + value: 2, + }, + ], + groupBy: 'foo', + name: 'd-1', + secondaryValue: 2, + value: 2, + }, + ]); + }); + + it('should build tree with secondaryValue as expected', () => { + const tree = treeBuilder(data, ['foo', 'bar'], 'count', 'count2'); + expect(tree).toEqual([ + { + children: [ + { + groupBy: 'bar', + name: 'a', + secondaryValue: 3, + value: 2, + }, + ], + groupBy: 'foo', + name: 'a-1', + secondaryValue: 3, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'a', + secondaryValue: 3, + value: 2, + }, + ], + groupBy: 'foo', + name: 'a-2', + secondaryValue: 3, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'b', + secondaryValue: 3, + value: 2, + }, + ], + groupBy: 'foo', + name: 'b-1', + secondaryValue: 3, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'b', + secondaryValue: 3, + value: 2, + }, + ], + groupBy: 'foo', + name: 'b-2', + secondaryValue: 3, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'c', + secondaryValue: 3, + value: 2, + }, + ], + groupBy: 'foo', + name: 'c-1', + secondaryValue: 3, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'c', + secondaryValue: 3, + value: 2, + }, + ], + groupBy: 'foo', + name: 'c-2', + secondaryValue: 3, + value: 2, + }, + { + children: [ + { + groupBy: 'bar', + name: 'd', + secondaryValue: 3, + value: 2, + }, + ], + groupBy: 'foo', + name: 'd-1', + secondaryValue: 3, + value: 2, + }, + ]); + }); +}); diff --git a/superset-frontend/plugins/plugin-chart-handlebars/package.json b/superset-frontend/plugins/plugin-chart-handlebars/package.json index da88ada90bae1..0a14440b5bd7e 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/package.json +++ b/superset-frontend/plugins/plugin-chart-handlebars/package.json @@ -1,6 +1,6 @@ { "name": "@superset-ui/plugin-chart-handlebars", - "version": "0.0.0", + "version": "0.18.25", "description": "Superset Chart - Write a handlebars template to render the data", "sideEffects": false, "main": "lib/index.js", @@ -26,7 +26,8 @@ "access": "public" }, "dependencies": { - "handlebars": "^4.7.7" + "handlebars": "^4.7.7", + "just-handlebars-helpers": "^1.0.19" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -35,12 +36,12 @@ "lodash": "^4.17.11", "moment": "^2.26.0", "react": "^16.13.1", - "react-ace": "^9.4.4", + "react-ace": "^10.1.0", "react-dom": "^16.13.1" }, "devDependencies": { - "@types/lodash": "^4.14.149", "@types/jest": "^26.0.0", + "@types/lodash": "^4.14.149", "jest": "^26.0.1" } } diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/components/Handlebars/HandlebarsViewer.tsx b/superset-frontend/plugins/plugin-chart-handlebars/src/components/Handlebars/HandlebarsViewer.tsx index b1ec9597ac26f..371b4f48f91a6 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/components/Handlebars/HandlebarsViewer.tsx +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/components/Handlebars/HandlebarsViewer.tsx @@ -16,11 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import { SafeMarkdown, styled } from '@superset-ui/core'; +import { SafeMarkdown, styled, t } from '@superset-ui/core'; import Handlebars from 'handlebars'; import moment from 'moment'; import React, { useMemo, useState } from 'react'; import { isPlainObject } from 'lodash'; +import Helpers from 'just-handlebars-helpers'; export interface HandlebarsViewerProps { templateSource: string; @@ -70,7 +71,7 @@ export const HandlebarsViewer = ({ /> ); } - return <p>Loading...</p>; + return <p>{t('Loading...')}</p>; }; // usage: {{dateFormat my_date format="MMMM YYYY"}} @@ -86,3 +87,5 @@ Handlebars.registerHelper('stringify', (obj: any, obj2: any) => { throw Error('Please call with an object. Example: `stringify myObj`'); return isPlainObject(obj) ? JSON.stringify(obj) : String(obj); }); + +Helpers.registerHelpers(Handlebars); diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/consts.ts b/superset-frontend/plugins/plugin-chart-handlebars/src/consts.ts index 562f654431b53..e566fd66b2790 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/consts.ts +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/consts.ts @@ -18,10 +18,7 @@ */ import { debounce } from 'lodash'; import { formatSelectOptions } from '@superset-ui/chart-controls'; -import { addLocaleData, SLOW_DEBOUNCE, t } from '@superset-ui/core'; -import i18n from './i18n'; - -addLocaleData(i18n); +import { SLOW_DEBOUNCE, t } from '@superset-ui/core'; export const PAGE_SIZE_OPTIONS = formatSelectOptions<number>([ [0, t('page_size.all')], diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/i18n.ts b/superset-frontend/plugins/plugin-chart-handlebars/src/i18n.ts deleted file mode 100644 index 5d015b5665975..0000000000000 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/i18n.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { Locale } from '@superset-ui/core'; - -const en = { - 'Query Mode': [''], - Aggregate: [''], - 'Raw Records': [''], - 'Emit Filter Events': [''], - 'Show Cell Bars': [''], - 'page_size.show': ['Show'], - 'page_size.all': ['All'], - 'page_size.entries': ['entries'], - 'table.previous_page': ['Previous'], - 'table.next_page': ['Next'], - 'search.num_records': ['%s record', '%s records...'], -}; - -const translations: Partial<Record<Locale, typeof en>> = { - en, - fr: { - 'Query Mode': [''], - Aggregate: [''], - 'Raw Records': [''], - 'Emit Filter Events': [''], - 'Show Cell Bars': [''], - 'page_size.show': ['Afficher'], - 'page_size.all': ['tous'], - 'page_size.entries': ['entrées'], - 'table.previous_page': ['Précédent'], - 'table.next_page': ['Suivante'], - 'search.num_records': ['%s enregistrement', '%s enregistrements...'], - }, - zh: { - 'Query Mode': ['查询模式'], - Aggregate: ['分组聚合'], - 'Raw Records': ['原始数据'], - 'Emit Filter Events': ['关联看板过滤器'], - 'Show Cell Bars': ['为指标添加条状图背景'], - 'page_size.show': ['每页显示'], - 'page_size.all': ['全部'], - 'page_size.entries': ['条'], - 'table.previous_page': ['上一页'], - 'table.next_page': ['下一页'], - 'search.num_records': ['%s条记录...'], - }, -}; - -export default translations; diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/images/example1.jpg b/superset-frontend/plugins/plugin-chart-handlebars/src/images/example1.jpg new file mode 100644 index 0000000000000..2307cec80d2d0 Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-handlebars/src/images/example1.jpg differ diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/images/example2.jpg b/superset-frontend/plugins/plugin-chart-handlebars/src/images/example2.jpg new file mode 100644 index 0000000000000..94dc10538511b Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-handlebars/src/images/example2.jpg differ diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/buildQuery.ts b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/buildQuery.ts index 3dc7bf87a3a74..c741e6c465777 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/buildQuery.ts @@ -23,13 +23,10 @@ import { } from '@superset-ui/core'; export default function buildQuery(formData: QueryFormData) { - const { groupby } = formData; - return buildQueryContext(formData, baseQueryObject => [ { ...baseQueryObject, orderby: normalizeOrderBy(baseQueryObject).orderby, - ...(groupby && { groupby }), }, ]); } diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx index aa4efe62122ac..03904e54c83fc 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx @@ -18,11 +18,10 @@ */ import { ControlPanelConfig, - emitFilterControl, + getStandardizedControls, sections, } from '@superset-ui/chart-controls'; -import { addLocaleData, t } from '@superset-ui/core'; -import i18n from '../i18n'; +import { t } from '@superset-ui/core'; import { allColumnsControlSetItem } from './controls/columns'; import { groupByControlSetItem } from './controls/groupBy'; import { handlebarsTemplateControlSetItem } from './controls/handlebarTemplate'; @@ -47,11 +46,9 @@ import { import { queryModeControlSetItem } from './controls/queryMode'; import { styleControlSetItem } from './controls/style'; -addLocaleData(i18n); - const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, + sections.genericTime, { label: t('Query'), expanded: true, @@ -67,7 +64,6 @@ const config: ControlPanelConfig = { [includeTimeControlSetItem], [showTotalsControlSetItem], ['adhoc_filters'], - emitFilterControl, ], }, { @@ -79,6 +75,11 @@ const config: ControlPanelConfig = { ], }, ], + formDataOverrides: formData => ({ + ...formData, + groupby: getStandardizedControls().popAllColumns(), + metrics: getStandardizedControls().popAllMetrics(), + }), }; export default config; diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx index 3aec61dc4060a..3c2434ac4063c 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx @@ -49,7 +49,7 @@ const allColumns: typeof sharedControls.groupby = { options: datasource?.columns || [], queryMode: getQueryMode(controls), externalValidationErrors: - isRawMode({ controls }) && ensureIsArray(controlState.value).length === 0 + isRawMode({ controls }) && ensureIsArray(controlState?.value).length === 0 ? [t('must have a value')] : [], }), @@ -74,7 +74,7 @@ const dndAllColumns: typeof sharedControls.groupby = { } newState.queryMode = getQueryMode(controls); newState.externalValidationErrors = - isRawMode({ controls }) && ensureIsArray(controlState.value).length === 0 + isRawMode({ controls }) && ensureIsArray(controlState?.value).length === 0 ? [t('must have a value')] : []; return newState; diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx index 96eab55f92974..c6aad5e320ba3 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx @@ -46,7 +46,7 @@ const percentMetrics: typeof sharedControls.metrics = { externalValidationErrors: validateAggControlValues(controls, [ controls.groupby?.value, controls.metrics?.value, - controlState.value, + controlState?.value, ]), }), rerender: ['groupby', 'metrics'], diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/index.ts b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/index.ts index db5ad528f8f6a..41249f2d71622 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/index.ts +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/index.ts @@ -18,6 +18,8 @@ */ import { ChartMetadata, ChartPlugin, t } from '@superset-ui/core'; import thumbnail from '../images/thumbnail.png'; +import example1 from '../images/example1.jpg'; +import example2 from '../images/example2.jpg'; import buildQuery from './buildQuery'; import controlPanel from './controlPanel'; import transformProps from './transformProps'; @@ -35,9 +37,10 @@ export default class HandlebarsChartPlugin extends ChartPlugin { */ constructor() { const metadata = new ChartMetadata({ - description: 'Write a handlebars template to render the data', + description: t('Write a handlebars template to render the data'), name: t('Handlebars'), thumbnail, + exampleGallery: [{ url: example1 }, { url: example2 }], }); super({ diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/types.ts b/superset-frontend/plugins/plugin-chart-handlebars/src/types.ts index 2a363059fa7d8..741d3b982c48b 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/types.ts +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/types.ts @@ -51,7 +51,6 @@ export type HandlebarsQueryFormData = QueryFormData & all_columns?: QueryFormMetric[] | null; order_desc?: boolean; table_timestamp_format?: string; - emit_filter?: boolean; granularitySqla?: string; time_grain_sqla?: TimeGranularity; column_config?: Record<string, ColumnConfig>; diff --git a/superset-frontend/plugins/plugin-chart-handlebars/test/plugin/buildQuery.test.ts b/superset-frontend/plugins/plugin-chart-handlebars/test/plugin/buildQuery.test.ts index 217ee50485f8a..6f84b6afe4bc0 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/test/plugin/buildQuery.test.ts +++ b/superset-frontend/plugins/plugin-chart-handlebars/test/plugin/buildQuery.test.ts @@ -32,6 +32,6 @@ describe('Handlebars buildQuery', () => { it('should build groupby with series in form data', () => { const queryContext = buildQuery(formData); const [query] = queryContext.queries; - expect(query.groupby).toEqual(['foo']); + expect(query.columns).toEqual(['foo']); }); }); diff --git a/superset-frontend/plugins/plugin-chart-handlebars/test/plugin/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-handlebars/test/plugin/transformProps.test.ts index 62903ad73f424..5910ea0f493ec 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/test/plugin/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-handlebars/test/plugin/transformProps.test.ts @@ -20,7 +20,7 @@ import { ChartProps, QueryFormData, supersetTheme } from '@superset-ui/core'; import { HandlebarsQueryFormData } from '../../src/types'; import transformProps from '../../src/plugin/transformProps'; -describe('Handlebars tranformProps', () => { +describe('Handlebars transformProps', () => { const formData: HandlebarsQueryFormData = { colorScheme: 'bnbColors', datasource: '3__table', @@ -40,7 +40,7 @@ describe('Handlebars tranformProps', () => { theme: supersetTheme, }); - it('should tranform chart props for viz', () => { + it('should transform chart props for viz', () => { expect(transformProps(chartProps)).toEqual( expect.objectContaining({ width: 800, diff --git a/superset-frontend/plugins/plugin-chart-handlebars/types/external.d.ts b/superset-frontend/plugins/plugin-chart-handlebars/types/external.d.ts index 8f7985ceaf135..ae61945f05350 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/types/external.d.ts +++ b/superset-frontend/plugins/plugin-chart-handlebars/types/external.d.ts @@ -20,3 +20,5 @@ declare module '*.png' { const value: any; export default value; } +declare module '*.jpg'; +declare module 'just-handlebars-helpers'; diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/package.json b/superset-frontend/plugins/plugin-chart-pivot-table/package.json index a796b90836e96..bed12a2e7250e 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/package.json +++ b/superset-frontend/plugins/plugin-chart-pivot-table/package.json @@ -32,7 +32,8 @@ "@ant-design/icons": "^4.2.2", "react": "^16.13.1", "react-dom": "^16.13.1", - "prop-types": "*" + "prop-types": "*", + "lodash": "^4.17.11" }, "devDependencies": { "@babel/types": "^7.13.12", diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx b/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx index 1cd079044d884..d9653686e11d6 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx @@ -27,8 +27,10 @@ import { NumberFormatter, styled, useTheme, + isAdhocColumn, + BinaryQueryObjectFilterClause, + t, } from '@superset-ui/core'; -import { isAdhocColumn } from '@superset-ui/chart-controls'; import { PivotTable, sortAs, aggregatorTemplates } from './react-pivottable'; import { FilterType, @@ -54,7 +56,7 @@ const PivotTableWrapper = styled.div` overflow: auto; `; -const METRIC_KEY = 'metric'; +const METRIC_KEY = t('metric'); const vals = ['value']; const StyledPlusSquareOutlined = styled(PlusSquareOutlined)` @@ -134,7 +136,7 @@ export default function PivotTableChart(props: PivotTableProps) { colTotals, rowTotals, valueFormat, - emitFilter, + emitCrossFilters, setDataMask, selectedFilters, verboseMap, @@ -142,6 +144,8 @@ export default function PivotTableChart(props: PivotTableProps) { metricsLayout, metricColorFormatters, dateFormatters, + onContextMenu, + timeGrainSqla, } = props; const theme = useTheme(); @@ -284,7 +288,7 @@ export default function PivotTableChart(props: PivotTableProps) { isSubtotal: boolean, isGrandTotal: boolean, ) => { - if (isSubtotal || isGrandTotal || !emitFilter) { + if (isSubtotal || isGrandTotal || !emitCrossFilters) { return; } @@ -324,7 +328,7 @@ export default function PivotTableChart(props: PivotTableProps) { } handleChange(updatedFilters); }, - [emitFilter, selectedFilters, handleChange], + [emitCrossFilters, selectedFilters, handleChange], ); const tableOptions = useMemo( @@ -333,7 +337,7 @@ export default function PivotTableChart(props: PivotTableProps) { clickColumnHeaderCallback: toggleFilter, colTotals, rowTotals, - highlightHeaderCellsOnHover: emitFilter, + highlightHeaderCellsOnHover: emitCrossFilters, highlightedHeaderCells: selectedFilters, omittedHighlightHeaderGroups: [METRIC_KEY], cellColorFormatters: { [METRIC_KEY]: metricColorFormatters }, @@ -342,7 +346,7 @@ export default function PivotTableChart(props: PivotTableProps) { [ colTotals, dateFormatters, - emitFilter, + emitCrossFilters, metricColorFormatters, rowTotals, selectedFilters, @@ -360,6 +364,52 @@ export default function PivotTableChart(props: PivotTableProps) { [colSubtotalPosition, rowSubtotalPosition], ); + const handleContextMenu = useCallback( + ( + e: MouseEvent, + colKey: (string | number | boolean)[] | undefined, + rowKey: (string | number | boolean)[] | undefined, + ) => { + if (onContextMenu) { + e.preventDefault(); + e.stopPropagation(); + const filters: BinaryQueryObjectFilterClause[] = []; + if (colKey && colKey.length > 1) { + colKey.forEach((val, i) => { + const col = cols[i]; + const formatter = dateFormatters[col]; + const formattedVal = formatter?.(val as number) || String(val); + if (i > 0) { + filters.push({ + col, + op: '==', + val, + formattedVal, + grain: formatter ? timeGrainSqla : undefined, + }); + } + }); + } + if (rowKey) { + rowKey.forEach((val, i) => { + const col = rows[i]; + const formatter = dateFormatters[col]; + const formattedVal = formatter?.(val as number) || String(val); + filters.push({ + col, + op: '==', + val, + formattedVal, + grain: formatter ? timeGrainSqla : undefined, + }); + }); + } + onContextMenu(e.clientX, e.clientY, filters); + } + }, + [cols, dateFormatters, onContextMenu, rows, timeGrainSqla], + ); + return ( <Styles height={height} width={width} margin={theme.gridUnit * 4}> <PivotTableWrapper> @@ -378,6 +428,7 @@ export default function PivotTableChart(props: PivotTableProps) { tableOptions={tableOptions} subtotalOptions={subtotalOptions} namesMapping={verboseMap} + onContextMenu={handleContextMenu} /> </PivotTableWrapper> </Styles> diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/images/example.jpg b/superset-frontend/plugins/plugin-chart-pivot-table/src/images/example.jpg new file mode 100644 index 0000000000000..e4f534ed0a134 Binary files /dev/null and b/superset-frontend/plugins/plugin-chart-pivot-table/src/images/example.jpg differ diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/buildQuery.ts b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/buildQuery.ts index 677902b796800..6e33b41cc7909 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/buildQuery.ts @@ -16,9 +16,14 @@ * specific language governing permissions and limitations * under the License. */ +import omit from 'lodash/omit'; + import { + AdhocColumn, buildQueryContext, ensureIsArray, + hasGenericChartAxes, + isPhysicalColumn, QueryFormColumn, QueryFormOrderBy, } from '@superset-ui/core'; @@ -27,10 +32,29 @@ import { PivotTableQueryFormData } from '../types'; export default function buildQuery(formData: PivotTableQueryFormData) { const { groupbyColumns = [], groupbyRows = [] } = formData; // TODO: add deduping of AdhocColumns - const groupbySet = new Set([ - ...ensureIsArray<QueryFormColumn>(groupbyColumns), - ...ensureIsArray<QueryFormColumn>(groupbyRows), - ]); + const columns = Array.from( + new Set([ + ...ensureIsArray<QueryFormColumn>(groupbyColumns), + ...ensureIsArray<QueryFormColumn>(groupbyRows), + ]), + ).map(col => { + if ( + isPhysicalColumn(col) && + formData.time_grain_sqla && + hasGenericChartAxes && + formData?.temporal_columns_lookup?.[col] + ) { + return { + timeGrain: formData.time_grain_sqla, + columnType: 'BASE_AXIS', + sqlExpression: col, + label: col, + expressionType: 'SQL', + } as AdhocColumn; + } + return col; + }); + return buildQueryContext(formData, baseQueryObject => { const { series_limit_metric, metrics, order_desc } = baseQueryObject; let orderBy: QueryFormOrderBy[] | undefined; @@ -41,9 +65,11 @@ export default function buildQuery(formData: PivotTableQueryFormData) { } return [ { - ...baseQueryObject, + ...(hasGenericChartAxes + ? omit(baseQueryObject, ['extras.time_grain_sqla']) + : baseQueryObject), orderby: orderBy, - columns: [...groupbySet], + columns, }, ]; }); diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx index ce09ae1345ae1..1b01e37a4c110 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx @@ -19,6 +19,9 @@ import React from 'react'; import { ensureIsArray, + hasGenericChartAxes, + isAdhocColumn, + isPhysicalColumn, QueryFormMetric, smartDateFormatter, t, @@ -27,17 +30,16 @@ import { import { ControlPanelConfig, D3_TIME_FORMAT_OPTIONS, - formatSelectOptions, sections, sharedControls, - emitFilterControl, Dataset, + getStandardizedControls, } from '@superset-ui/chart-controls'; import { MetricsLayoutEnum } from '../types'; const config: ControlPanelConfig = { controlPanelSections: [ - { ...sections.legacyTimeseriesTime, expanded: false }, + { ...sections.genericTime, expanded: false }, { label: t('Query'), expanded: true, @@ -62,6 +64,39 @@ const config: ControlPanelConfig = { }, }, ], + [ + hasGenericChartAxes + ? { + name: 'time_grain_sqla', + config: { + ...sharedControls.time_grain_sqla, + visibility: ({ controls }) => { + const dttmLookup = Object.fromEntries( + ensureIsArray(controls?.groupbyColumns?.options).map( + option => [option.column_name, option.is_dttm], + ), + ); + + return [ + ...ensureIsArray(controls?.groupbyColumns.value), + ...ensureIsArray(controls?.groupbyRows.value), + ] + .map(selection => { + if (isAdhocColumn(selection)) { + return true; + } + if (isPhysicalColumn(selection)) { + return !!dttmLookup[selection]; + } + return false; + }) + .some(Boolean); + }, + }, + } + : null, + hasGenericChartAxes ? 'temporal_columns_lookup' : null, + ], [ { name: 'metrics', @@ -91,7 +126,6 @@ const config: ControlPanelConfig = { }, ], ['adhoc_filters'], - emitFilterControl, ['series_limit'], [ { @@ -141,26 +175,29 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Aggregation function'), clearable: false, - choices: formatSelectOptions([ - 'Count', - 'Count Unique Values', - 'List Unique Values', - 'Sum', - 'Average', - 'Median', - 'Sample Variance', - 'Sample Standard Deviation', - 'Minimum', - 'Maximum', - 'First', - 'Last', - 'Sum as Fraction of Total', - 'Sum as Fraction of Rows', - 'Sum as Fraction of Columns', - 'Count as Fraction of Total', - 'Count as Fraction of Rows', - 'Count as Fraction of Columns', - ]), + choices: [ + ['Count', t('Count')], + ['Count Unique Values', t('Count Unique Values')], + ['List Unique Values', t('List Unique Values')], + ['Sum', t('Sum')], + ['Average', t('Average')], + ['Median', t('Median')], + ['Sample Variance', t('Sample Variance')], + ['Sample Standard Deviation', t('Sample Standard Deviation')], + ['Minimum', t('Minimum')], + ['Maximum', t('Maximum')], + ['First', t('First')], + ['Last', t('Last')], + ['Sum as Fraction of Total', t('Sum as Fraction of Total')], + ['Sum as Fraction of Rows', t('Sum as Fraction of Rows')], + ['Sum as Fraction of Columns', t('Sum as Fraction of Columns')], + ['Count as Fraction of Total', t('Count as Fraction of Total')], + ['Count as Fraction of Rows', t('Count as Fraction of Rows')], + [ + 'Count as Fraction of Columns', + t('Count as Fraction of Columns'), + ], + ], default: 'Sum', description: t( 'Aggregate function to apply when pivoting and computing the total rows and columns', @@ -373,14 +410,17 @@ const config: ControlPanelConfig = { ], }, ], - denormalizeFormData: formData => { - const groupbyColumns = - formData.standardizedFormData.standardizedState.columns.filter( - col => !ensureIsArray(formData.groupbyRows).includes(col), + formDataOverrides: formData => { + const groupbyColumns = getStandardizedControls().controls.columns.filter( + col => !ensureIsArray(formData.groupbyRows).includes(col), + ); + getStandardizedControls().controls.columns = + getStandardizedControls().controls.columns.filter( + col => !groupbyColumns.includes(col), ); return { ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, + metrics: getStandardizedControls().popAllMetrics(), groupbyColumns, }; }, diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts index 423ac596251bc..b2d355f0fff29 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts @@ -28,6 +28,7 @@ import buildQuery from './buildQuery'; import controlPanel from './controlPanel'; import transformProps from './transformProps'; import thumbnail from '../images/thumbnail.png'; +import example from '../images/example.jpg'; import { PivotTableQueryFormData } from '../types'; export default class PivotTableChartPlugin extends ChartPlugin< @@ -46,12 +47,13 @@ export default class PivotTableChartPlugin extends ChartPlugin< */ constructor() { const metadata = new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Table'), description: t( 'Used to summarize a set of data by grouping together multiple statistics along two axes. Examples: Sales numbers by region and month, tasks by status and assignee, active users by age and location. Not the most visually stunning visualization, but highly informative and versatile.', ), - name: t('Pivot Table v2'), + exampleGallery: [{ url: example }], + name: t('Pivot Table'), tags: [t('Additive'), t('Report'), t('Tabular'), t('Popular')], thumbnail, }); diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts index 8666705b7a6a1..43d73e6193ea4 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts @@ -77,9 +77,10 @@ export default function transformProps(chartProps: ChartProps<QueryFormData>) { queriesData, formData, rawFormData, - hooks: { setDataMask = () => {} }, + hooks: { setDataMask = () => {}, onContextMenu }, filterState, datasource: { verboseMap = {}, columnFormats = {} }, + emitCrossFilters, } = chartProps; const { data, colnames, coltypes } = queriesData[0]; const { @@ -98,9 +99,9 @@ export default function transformProps(chartProps: ChartProps<QueryFormData>) { rowTotals, valueFormat, dateFormat, - emitFilter, metricsLayout, conditionalFormatting, + timeGrainSqla, } = formData; const { selectedFilters } = filterState; const granularity = extractTimegrain(rawFormData); @@ -156,7 +157,7 @@ export default function transformProps(chartProps: ChartProps<QueryFormData>) { colTotals, rowTotals, valueFormat, - emitFilter, + emitCrossFilters, setDataMask, selectedFilters, verboseMap, @@ -164,5 +165,7 @@ export default function transformProps(chartProps: ChartProps<QueryFormData>) { metricsLayout, metricColorFormatters, dateFormatters, + onContextMenu, + timeGrainSqla, }; } diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/PivotTable.jsx b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/PivotTable.jsx index bb79069d90192..610e80c0c3fe0 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/PivotTable.jsx +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/PivotTable.jsx @@ -18,7 +18,6 @@ */ import React from 'react'; -import { PivotData } from './utilities'; import { TableRenderer } from './TableRenderers'; class PivotTable extends React.PureComponent { @@ -27,7 +26,7 @@ class PivotTable extends React.PureComponent { } } -PivotTable.propTypes = PivotData.propTypes; -PivotTable.defaultProps = PivotData.defaultProps; +PivotTable.propTypes = TableRenderer.propTypes; +PivotTable.defaultProps = TableRenderer.defaultProps; export default PivotTable; diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/Styles.js b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/Styles.js index 1360e0dc921ad..5393e4f610f06 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/Styles.js +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/Styles.js @@ -20,9 +20,9 @@ import { css, styled } from '@superset-ui/core'; export const Styles = styled.div` - ${({ theme }) => css` + ${({ theme, isDashboardEditMode }) => css` table.pvtTable { - position: relative; + position: ${isDashboardEditMode ? 'inherit' : 'relative'}; font-size: ${theme.typography.sizes.s}px; text-align: left; margin: ${theme.gridUnit}px; @@ -32,7 +32,7 @@ export const Styles = styled.div` } table thead { - position: sticky; + position: ${isDashboardEditMode ? 'inherit' : 'sticky'}; top: 0; } @@ -51,7 +51,7 @@ export const Styles = styled.div` } table.pvtTable tbody tr.pvtRowTotals { - position: sticky; + position: ${isDashboardEditMode ? 'inherit' : 'sticky'}; bottom: 0; } diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx index fe0c2fb0d522c..576325a21ddec 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx @@ -18,6 +18,7 @@ */ import React from 'react'; +import { t } from '@superset-ui/core'; import PropTypes from 'prop-types'; import { PivotData, flatKey } from './utilities'; import { Styles } from './Styles'; @@ -462,7 +463,7 @@ export class TableRenderer extends React.Component { true, )} > - Subtotal + {t('Subtotal')} </th>, ); } @@ -486,7 +487,9 @@ export class TableRenderer extends React.Component { true, )} > - {`Total (${this.props.aggregatorName})`} + {t('Total (%(aggregatorName)s)', { + aggregatorName: t(this.props.aggregatorName), + })} </th> ) : null; @@ -549,7 +552,9 @@ export class TableRenderer extends React.Component { )} > {colAttrs.length === 0 - ? `Total (${this.props.aggregatorName})` + ? t('Total (%(aggregatorName)s)', { + aggregatorName: t(this.props.aggregatorName), + }) : null} </th> </tr> @@ -658,7 +663,7 @@ export class TableRenderer extends React.Component { true, )} > - Subtotal + {t('Subtotal')} </th> ) : null; @@ -700,6 +705,7 @@ export class TableRenderer extends React.Component { className="pvtVal" key={`pvtVal-${flatColKey}`} onClick={rowClickHandlers[flatColKey]} + onContextMenu={e => this.props.onContextMenu(e, colKey, rowKey)} style={style} > {agg.format(aggValue)} @@ -717,6 +723,7 @@ export class TableRenderer extends React.Component { key="total" className="pvtTotal" onClick={rowTotalCallbacks[flatRowKey]} + onContextMenu={e => this.props.onContextMenu(e, undefined, rowKey)} > {agg.format(aggValue)} </td> @@ -761,7 +768,9 @@ export class TableRenderer extends React.Component { true, )} > - {`Total (${this.props.aggregatorName})`} + {t('Total (%(aggregatorName)s)', { + aggregatorName: t(this.props.aggregatorName), + })} </th> ); @@ -776,6 +785,7 @@ export class TableRenderer extends React.Component { className="pvtTotal pvtRowTotal" key={`total-${flatColKey}`} onClick={colTotalCallbacks[flatColKey]} + onContextMenu={e => this.props.onContextMenu(e, colKey, undefined)} style={{ padding: '5px' }} > {agg.format(aggValue)} @@ -793,6 +803,7 @@ export class TableRenderer extends React.Component { key="total" className="pvtGrandTotal pvtRowTotal" onClick={grandTotalCallback} + onContextMenu={e => this.props.onContextMenu(e, undefined, undefined)} > {agg.format(aggValue)} </td> @@ -822,6 +833,10 @@ export class TableRenderer extends React.Component { ); } + isDashboardEditMode() { + return document.contains(document.querySelector('.dashboard--editing')); + } + render() { if (this.cachedProps !== this.props) { this.cachedProps = this.props; @@ -863,7 +878,7 @@ export class TableRenderer extends React.Component { }; return ( - <Styles> + <Styles isDashboardEditMode={this.isDashboardEditMode()}> <table className="pvtTable" role="grid"> <thead> {colAttrs.map((c, j) => @@ -886,5 +901,6 @@ export class TableRenderer extends React.Component { TableRenderer.propTypes = { ...PivotData.propTypes, tableOptions: PropTypes.object, + onContextMenu: PropTypes.func, }; TableRenderer.defaultProps = { ...PivotData.defaultProps, tableOptions: {} }; diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.js b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.js index 9ae5888819777..9b47132936b4e 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.js +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.js @@ -231,7 +231,7 @@ const baseAggregatorTemplates = { return { sum: 0, push(record) { - if (Number.isNaN(parseFloat(record[attr]))) { + if (Number.isNaN(Number(record[attr]))) { this.sum = record[attr]; } else { this.sum += parseFloat(record[attr]); @@ -259,7 +259,7 @@ const baseAggregatorTemplates = { push(record) { const x = record[attr]; if (['min', 'max'].includes(mode)) { - const coercedValue = parseFloat(x); + const coercedValue = Number(x); if (Number.isNaN(coercedValue)) { this.val = !this.val || @@ -308,7 +308,7 @@ const baseAggregatorTemplates = { strMap: {}, push(record) { const val = record[attr]; - const x = parseFloat(val); + const x = Number(val); if (Number.isNaN(x)) { this.strMap[val] = (this.strMap[val] || 0) + 1; @@ -354,7 +354,7 @@ const baseAggregatorTemplates = { s: 0.0, strValue: null, push(record) { - const x = parseFloat(record[attr]); + const x = Number(record[attr]); if (Number.isNaN(x)) { this.strValue = typeof record[attr] === 'string' ? record[attr] : this.strValue; @@ -405,10 +405,10 @@ const baseAggregatorTemplates = { sumNum: 0, sumDenom: 0, push(record) { - if (!Number.isNaN(parseFloat(record[num]))) { + if (!Number.isNaN(Number(record[num]))) { this.sumNum += parseFloat(record[num]); } - if (!Number.isNaN(parseFloat(record[denom]))) { + if (!Number.isNaN(Number(record[denom]))) { this.sumDenom += parseFloat(record[denom]); } }, diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/types.ts b/superset-frontend/plugins/plugin-chart-pivot-table/src/types.ts index 38d725e922b3a..24d78e2dcaec5 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/types.ts +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/types.ts @@ -26,6 +26,8 @@ import { NumberFormatter, QueryFormMetric, QueryFormColumn, + BinaryQueryObjectFilterClause, + TimeGranularity, } from '@superset-ui/core'; import { ColorFormatters } from '@superset-ui/chart-controls'; @@ -63,7 +65,7 @@ interface PivotTableCustomizeProps { rowTotals: boolean; valueFormat: string; setDataMask: SetDataMaskHook; - emitFilter?: boolean; + emitCrossFilters?: boolean; selectedFilters?: SelectedFiltersType; verboseMap: JsonObject; columnFormats: JsonObject; @@ -72,6 +74,12 @@ interface PivotTableCustomizeProps { dateFormatters: Record<string, DateFormatter | undefined>; legacy_order_by: QueryFormMetric[] | QueryFormMetric | null; order_desc: boolean; + onContextMenu?: ( + clientX: number, + clientY: number, + filters?: BinaryQueryObjectFilterClause[], + ) => void; + timeGrainSqla?: TimeGranularity; } export type PivotTableQueryFormData = QueryFormData & diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/transformProps.test.ts index 26c938e371bcb..3edb4619afce0 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/transformProps.test.ts @@ -38,7 +38,6 @@ describe('PivotTableChart transformProps', () => { colTotals: true, rowTotals: true, valueFormat: 'SMART_NUMBER', - emitFilter: false, metricsLayout: MetricsLayoutEnum.COLUMNS, viz_type: '', datasource: '', @@ -83,13 +82,13 @@ describe('PivotTableChart transformProps', () => { rowTotals: true, valueFormat: 'SMART_NUMBER', data: [{ name: 'Hulk', sum__num: 1, __timestamp: 599616000000 }], - emitFilter: false, setDataMask, selectedFilters: {}, verboseMap: {}, metricsLayout: MetricsLayoutEnum.COLUMNS, metricColorFormatters: [], dateFormatters: {}, + emitCrossFilters: false, columnFormats: {}, }); }); diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/types/external.d.ts b/superset-frontend/plugins/plugin-chart-pivot-table/types/external.d.ts index a273f3a2ba3ed..ecdf68a7452ce 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/types/external.d.ts +++ b/superset-frontend/plugins/plugin-chart-pivot-table/types/external.d.ts @@ -21,3 +21,5 @@ declare module '*.png' { const value: any; export default value; } + +declare module '*.jpg'; diff --git a/superset-frontend/plugins/plugin-chart-table/package.json b/superset-frontend/plugins/plugin-chart-table/package.json index 0577c731a6ba5..293413805d136 100644 --- a/superset-frontend/plugins/plugin-chart-table/package.json +++ b/superset-frontend/plugins/plugin-chart-table/package.json @@ -28,8 +28,9 @@ "dependencies": { "@react-icons/all-files": "^4.1.0", "@types/d3-array": "^2.9.0", - "@types/react-table": "^7.0.29", "@types/enzyme": "^3.10.5", + "@types/react-table": "^7.0.29", + "classnames": "^2.3.2", "d3-array": "^2.4.0", "match-sorter": "^6.3.0", "memoize-one": "^5.1.1", @@ -37,10 +38,14 @@ "regenerator-runtime": "^0.13.7", "xss": "^1.0.10" }, + "devDependencies": { + "@testing-library/react": "^11.2.0" + }, "peerDependencies": { - "@types/react": "*", "@superset-ui/chart-controls": "*", "@superset-ui/core": "*", + "@types/classnames": "*", + "@types/react": "*", "react": "^16.13.1", "react-dom": "^16.13.1" } diff --git a/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx b/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx index 85580e7b63a3d..941887afd1962 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx @@ -23,6 +23,7 @@ import React, { HTMLProps, MutableRefObject, CSSProperties, + MouseEvent, } from 'react'; import { useTable, @@ -66,6 +67,7 @@ export interface DataTableProps<D extends object> extends TableOptions<D> { rowCount: number; wrapperRef?: MutableRefObject<HTMLDivElement>; onColumnOrderChange: () => void; + onContextMenu?: (value: D, clientX: number, clientY: number) => void; } export interface RenderHTMLCellProps extends HTMLProps<HTMLTableCellElement> { @@ -98,6 +100,7 @@ export default typedMemo(function DataTable<D extends object>({ serverPagination, wrapperRef: userWrapperRef, onColumnOrderChange, + onContextMenu, ...moreUseTableOptions }: DataTableProps<D>): JSX.Element { const tableHooks: PluginHook<D>[] = [ @@ -270,7 +273,21 @@ export default typedMemo(function DataTable<D extends object>({ prepareRow(row); const { key: rowKey, ...rowProps } = row.getRowProps(); return ( - <tr key={rowKey || row.id} {...rowProps}> + <tr + key={rowKey || row.id} + {...rowProps} + onContextMenu={(e: MouseEvent) => { + if (onContextMenu) { + e.preventDefault(); + e.stopPropagation(); + onContextMenu( + row.original, + e.nativeEvent.clientX, + e.nativeEvent.clientY, + ); + } + }} + > {row.cells.map(cell => cell.render('Cell', { key: cell.column.id }), )} diff --git a/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx b/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx index 989b121a3352a..48d4b9a66874e 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx @@ -17,6 +17,7 @@ * under the License. */ import React from 'react'; +import { t } from '@superset-ui/core'; import { formatSelectOptions } from '@superset-ui/chart-controls'; export type SizeOption = [number, string]; @@ -34,7 +35,7 @@ function DefaultSelectRenderer({ }: SelectPageSizeRendererProps) { return ( <span className="dt-select-page-size form-inline"> - Show{' '} + {t('Show')}{' '} <select className="form-control input-sm" value={current} @@ -54,7 +55,7 @@ function DefaultSelectRenderer({ ); })} </select>{' '} - entries + {t('entries')} </span> ); } diff --git a/superset-frontend/plugins/plugin-chart-table/src/DataTable/hooks/useSticky.tsx b/superset-frontend/plugins/plugin-chart-table/src/DataTable/hooks/useSticky.tsx index 6fd4d839ce661..067d071ee1926 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/DataTable/hooks/useSticky.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/DataTable/hooks/useSticky.tsx @@ -237,7 +237,7 @@ function StickyWrap({ const colWidths = columnWidths?.slice(0, columnCount); if (colWidths && bodyHeight) { - const bodyColgroup = ( + const colgroup = ( <colgroup> {colWidths.map((w, i) => ( // eslint-disable-next-line react/no-array-index-key @@ -246,23 +246,6 @@ function StickyWrap({ </colgroup> ); - // header columns do not have vertical scroll bars, - // so we add scroll bar size to the last column - const headerColgroup = - sticky.hasVerticalScroll && scrollBarSize ? ( - <colgroup> - {colWidths.map((x, i) => ( - // eslint-disable-next-line react/no-array-index-key - <col - key={i} - width={x + (i === colWidths.length - 1 ? scrollBarSize : 0)} - /> - ))} - </colgroup> - ) : ( - bodyColgroup - ); - headerTable = ( <div key="header" @@ -274,7 +257,7 @@ function StickyWrap({ {React.cloneElement( table, mergeStyleProp(table, fixedTableLayout), - headerColgroup, + colgroup, thead, )} {headerTable} @@ -292,7 +275,7 @@ function StickyWrap({ {React.cloneElement( table, mergeStyleProp(table, fixedTableLayout), - headerColgroup, + colgroup, tfoot, )} {footerTable} @@ -320,7 +303,7 @@ function StickyWrap({ {React.cloneElement( table, mergeStyleProp(table, fixedTableLayout), - bodyColgroup, + colgroup, tbody, )} </div> diff --git a/superset-frontend/plugins/plugin-chart-table/src/Styles.tsx b/superset-frontend/plugins/plugin-chart-table/src/Styles.tsx index 59a40b20bbf8c..9219b6f0030d2 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/Styles.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/Styles.tsx @@ -82,6 +82,17 @@ export default styled.div` float: right; } + .dt-truncate-cell { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .dt-truncate-cell:hover { + overflow: visible; + white-space: normal; + height: auto; + } + .dt-pagination { text-align: right; /* use padding instead of margin so clientHeight can capture it */ diff --git a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx index 73a639df01361..e114a823d6dfc 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx @@ -16,7 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import React, { CSSProperties, useCallback, useMemo, useState } from 'react'; +import React, { + CSSProperties, + useCallback, + useLayoutEffect, + useMemo, + useState, +} from 'react'; import { ColumnInstance, ColumnWithLooseAccessor, @@ -26,6 +32,7 @@ import { extent as d3Extent, max as d3Max } from 'd3-array'; import { FaSort } from '@react-icons/all-files/fa/FaSort'; import { FaSortDown as FaSortDesc } from '@react-icons/all-files/fa/FaSortDown'; import { FaSortUp as FaSortAsc } from '@react-icons/all-files/fa/FaSortUp'; +import cx from 'classnames'; import { DataRecord, DataRecordValue, @@ -33,7 +40,9 @@ import { ensureIsArray, GenericDataType, getTimeFormatterForGranularity, + BinaryQueryObjectFilterClause, styled, + css, t, tn, } from '@superset-ui/core'; @@ -50,9 +59,15 @@ import Styles from './Styles'; import { formatColumnValue } from './utils/formatValue'; import { PAGE_SIZE_OPTIONS } from './consts'; import { updateExternalFormData } from './DataTable/utils/externalAPIs'; +import getScrollBarSize from './DataTable/utils/getScrollBarSize'; type ValueRange = [number, number]; +interface TableSize { + width: number; + height: number; +} + /** * Return sortType based on data type */ @@ -67,44 +82,64 @@ function getSortTypeByDataType(dataType: GenericDataType): DefaultSortTypes { } /** - * Cell background to render columns as horizontal bar chart + * Cell background width calculation for horizontal bar chart */ -function cellBar({ +function cellWidth({ value, valueRange, - colorPositiveNegative = false, alignPositiveNegative, }: { value: number; valueRange: ValueRange; - colorPositiveNegative: boolean; alignPositiveNegative: boolean; }) { const [minValue, maxValue] = valueRange; - const r = colorPositiveNegative && value < 0 ? 150 : 0; if (alignPositiveNegative) { const perc = Math.abs(Math.round((value / maxValue) * 100)); - // The 0.01 to 0.001 is a workaround for what appears to be a - // CSS rendering bug on flat, transparent colors - return ( - `linear-gradient(to right, rgba(${r},0,0,0.2), rgba(${r},0,0,0.2) ${perc}%, ` + - `rgba(0,0,0,0.01) ${perc}%, rgba(0,0,0,0.001) 100%)` - ); + return perc; } const posExtent = Math.abs(Math.max(maxValue, 0)); const negExtent = Math.abs(Math.min(minValue, 0)); const tot = posExtent + negExtent; - const perc1 = Math.round( - (Math.min(negExtent + value, negExtent) / tot) * 100, - ); const perc2 = Math.round((Math.abs(value) / tot) * 100); - // The 0.01 to 0.001 is a workaround for what appears to be a - // CSS rendering bug on flat, transparent colors - return ( - `linear-gradient(to right, rgba(0,0,0,0.01), rgba(0,0,0,0.001) ${perc1}%, ` + - `rgba(${r},0,0,0.2) ${perc1}%, rgba(${r},0,0,0.2) ${perc1 + perc2}%, ` + - `rgba(0,0,0,0.01) ${perc1 + perc2}%, rgba(0,0,0,0.001) 100%)` - ); + return perc2; +} + +/** + * Cell left margin (offset) calculation for horizontal bar chart elements + * when alignPositiveNegative is not set + */ +function cellOffset({ + value, + valueRange, + alignPositiveNegative, +}: { + value: number; + valueRange: ValueRange; + alignPositiveNegative: boolean; +}) { + if (alignPositiveNegative) { + return 0; + } + const [minValue, maxValue] = valueRange; + const posExtent = Math.abs(Math.max(maxValue, 0)); + const negExtent = Math.abs(Math.min(minValue, 0)); + const tot = posExtent + negExtent; + return Math.round((Math.min(negExtent + value, negExtent) / tot) * 100); +} + +/** + * Cell background color calculation for horizontal bar chart + */ +function cellBackground({ + value, + colorPositiveNegative = false, +}: { + value: number; + colorPositiveNegative: boolean; +}) { + const r = colorPositiveNegative && value < 0 ? 150 : 0; + return `rgba(${r},0,0,0.2)`; } function SortIcon<D extends object>({ column }: { column: ColumnInstance<D> }) { @@ -163,7 +198,7 @@ function SelectPageSize({ } const getNoResultsMessage = (filter: string) => - t(filter ? 'No matching records found' : 'No records found'); + filter ? t('No matching records found') : t('No records found'); export default function TableChart<D extends DataRecord = DataRecord>( props: TableChartTransformedProps<D> & { @@ -187,24 +222,28 @@ export default function TableChart<D extends DataRecord = DataRecord>( serverPaginationData, setDataMask, showCellBars = true, - emitFilter = false, sortDesc = false, filters, sticky = true, // whether to use sticky header columnColorFormatters, allowRearrangeColumns = false, + onContextMenu, + emitCrossFilters, } = props; const timestampFormatter = useCallback( value => getTimeFormatterForGranularity(timeGrain)(value), [timeGrain], ); - + const [tableSize, setTableSize] = useState<TableSize>({ + width: 0, + height: 0, + }); // keep track of whether column order changed, so that column widths can too const [columnOrderToggle, setColumnOrderToggle] = useState(false); const handleChange = useCallback( (filters: { [x: string]: DataRecordValue[] }) => { - if (!emitFilter) { + if (!emitCrossFilters) { return; } @@ -250,7 +289,7 @@ export default function TableChart<D extends DataRecord = DataRecord>( }, }); }, - [emitFilter, setDataMask], + [emitCrossFilters, setDataMask], ); // only take relevant page size options @@ -283,27 +322,21 @@ export default function TableChart<D extends DataRecord = DataRecord>( [filters], ); - function getEmitTarget(col: string) { - const meta = columnsMeta?.find(x => x.key === col); - return meta?.config?.emitTarget || col; - } - const toggleFilter = useCallback( function toggleFilter(key: string, val: DataRecordValue) { let updatedFilters = { ...(filters || {}) }; - const target = getEmitTarget(key); - if (filters && isActiveFilterValue(target, val)) { + if (filters && isActiveFilterValue(key, val)) { updatedFilters = {}; } else { updatedFilters = { - [target]: [val], + [key]: [val], }; } if ( - Array.isArray(updatedFilters[target]) && - updatedFilters[target].length === 0 + Array.isArray(updatedFilters[key]) && + updatedFilters[key].length === 0 ) { - delete updatedFilters[target]; + delete updatedFilters[key]; } handleChange(updatedFilters); }, @@ -341,6 +374,8 @@ export default function TableChart<D extends DataRecord = DataRecord>( ? defaultColorPN : config.colorPositiveNegative; + const { truncateLongCells } = config; + const hasColumnColorFormatters = isNumeric && Array.isArray(columnColorFormatters) && @@ -355,7 +390,7 @@ export default function TableChart<D extends DataRecord = DataRecord>( getValueRange(key, alignPositiveNegative); let className = ''; - if (emitFilter) { + if (emitCrossFilters) { className += ' dt-is-filter'; } @@ -374,9 +409,9 @@ export default function TableChart<D extends DataRecord = DataRecord>( columnColorFormatters! .filter(formatter => formatter.column === column.key) .forEach(formatter => { - const formatterResult = formatter.getColorFromValue( - value as number, - ); + const formatterResult = value + ? formatter.getColorFromValue(value as number) + : false; if (formatterResult) { backgroundColor = formatterResult; } @@ -385,23 +420,40 @@ export default function TableChart<D extends DataRecord = DataRecord>( const StyledCell = styled.td` text-align: ${sharedStyle.textAlign}; - background: ${backgroundColor || - (valueRange - ? cellBar({ + white-space: ${value instanceof Date ? 'nowrap' : undefined}; + position: relative; + background: ${backgroundColor || undefined}; + `; + + const cellBarStyles = css` + position: absolute; + height: 100%; + display: block; + top: 0; + ${valueRange && + ` + width: ${`${cellWidth({ value: value as number, valueRange, alignPositiveNegative, + })}%`}; + left: ${`${cellOffset({ + value: value as number, + valueRange, + alignPositiveNegative, + })}%`}; + background-color: ${cellBackground({ + value: value as number, colorPositiveNegative, - }) - : undefined)}; - white-space: ${value instanceof Date ? 'nowrap' : undefined}; + })}; + `} `; const cellProps = { // show raw number in title in case of numeric values title: typeof value === 'number' ? String(value) : undefined, onClick: - emitFilter && !valueRange + emitCrossFilters && !valueRange ? () => toggleFilter(key, value) : undefined, className: [ @@ -411,16 +463,51 @@ export default function TableChart<D extends DataRecord = DataRecord>( ].join(' '), }; if (html) { + if (truncateLongCells) { + // eslint-disable-next-line react/no-danger + return ( + <StyledCell {...cellProps}> + <div + className="dt-truncate-cell" + style={columnWidth ? { width: columnWidth } : undefined} + dangerouslySetInnerHTML={html} + /> + </StyledCell> + ); + } // eslint-disable-next-line react/no-danger return <StyledCell {...cellProps} dangerouslySetInnerHTML={html} />; } - // If cellProps renderes textContent already, then we don't have to + // If cellProps renders textContent already, then we don't have to // render `Cell`. This saves some time for large tables. - return <StyledCell {...cellProps}>{text}</StyledCell>; + return ( + <StyledCell {...cellProps}> + {valueRange && ( + <div + /* The following classes are added to support custom CSS styling */ + className={cx( + 'cell-bar', + value && value < 0 ? 'negative' : 'positive', + )} + css={cellBarStyles} + /> + )} + {truncateLongCells ? ( + <div + className="dt-truncate-cell" + style={columnWidth ? { width: columnWidth } : undefined} + > + {text} + </div> + ) : ( + text + )} + </StyledCell> + ); }, Header: ({ column: col, onClick, style, onDragStart, onDrop }) => ( <th - title="Shift + Click to sort by multiple columns" + title={t('Shift + Click to sort by multiple columns')} className={[className, col.isSorted ? 'is-sorted' : ''].join(' ')} style={{ ...sharedStyle, @@ -474,7 +561,7 @@ export default function TableChart<D extends DataRecord = DataRecord>( [ defaultAlignPN, defaultColorPN, - emitFilter, + emitCrossFilters, getValueRange, isActiveFilterValue, isRawRecords, @@ -499,6 +586,60 @@ export default function TableChart<D extends DataRecord = DataRecord>( [setDataMask], ); + const handleSizeChange = useCallback( + ({ width, height }: { width: number; height: number }) => { + setTableSize({ width, height }); + }, + [], + ); + + useLayoutEffect(() => { + // After initial load the table should resize only when the new sizes + // Are not only scrollbar updates, otherwise, the table would twicth + const scrollBarSize = getScrollBarSize(); + const { width: tableWidth, height: tableHeight } = tableSize; + // Table is increasing its original size + if ( + width - tableWidth > scrollBarSize || + height - tableHeight > scrollBarSize + ) { + handleSizeChange({ + width: width - scrollBarSize, + height: height - scrollBarSize, + }); + } else if ( + tableWidth - width > scrollBarSize || + tableHeight - height > scrollBarSize + ) { + // Table is decreasing its original size + handleSizeChange({ + width, + height, + }); + } + }, [width, height, handleSizeChange, tableSize]); + + const { width: widthFromState, height: heightFromState } = tableSize; + + const handleContextMenu = + onContextMenu && !isRawRecords + ? (value: D, clientX: number, clientY: number) => { + const filters: BinaryQueryObjectFilterClause[] = []; + columnsMeta.forEach(col => { + if (!col.isMetric) { + const dataRecordValue = value[col.key]; + filters.push({ + col: col.key, + op: '==', + val: dataRecordValue as string | number | boolean, + formattedVal: formatColumnValue(col, dataRecordValue)[1], + }); + } + }); + onContextMenu(clientX, clientY, filters); + } + : undefined; + return ( <Styles> <DataTable<D> @@ -509,8 +650,8 @@ export default function TableChart<D extends DataRecord = DataRecord>( pageSize={pageSize} serverPaginationData={serverPaginationData} pageSizeOptions={pageSizeOptions} - width={width} - height={height} + width={widthFromState} + height={heightFromState} serverPagination={serverPagination} onServerPaginationChange={handleServerPaginationChange} onColumnOrderChange={() => setColumnOrderToggle(!columnOrderToggle)} @@ -521,6 +662,7 @@ export default function TableChart<D extends DataRecord = DataRecord>( selectPageSize={pageSize !== null && SelectPageSize} // not in use in Superset, but needed for unit tests sticky={sticky} + onContextMenu={handleContextMenu} /> </Styles> ); diff --git a/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts b/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts index 99a0da8ca9baa..211070f8bcc4a 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts @@ -17,9 +17,12 @@ * under the License. */ import { + AdhocColumn, buildQueryContext, ensureIsArray, getMetricLabel, + hasGenericChartAxes, + isPhysicalColumn, QueryMode, QueryObject, removeDuplicates, @@ -63,17 +66,17 @@ const buildQuery: BuildQuery<TableChartFormData> = ( } return buildQueryContext(formDataCopy, baseQueryObject => { - let { metrics, orderby = [] } = baseQueryObject; + let { metrics, orderby = [], columns = [] } = baseQueryObject; let postProcessing: PostProcessingRule[] = []; if (queryMode === QueryMode.aggregate) { metrics = metrics || []; - // orverride orderby with timeseries metric when in aggregation mode + // override orderby with timeseries metric when in aggregation mode if (sortByMetric) { orderby = [[sortByMetric, !orderDesc]]; } else if (metrics?.length > 0) { // default to ordering by first metric in descending order - // when no "sort by" metric is set (regargless if "SORT DESC" is set to true) + // when no "sort by" metric is set (regardless if "SORT DESC" is set to true) orderby = [[metrics[0], false]]; } // add postprocessing for percent metrics only when in aggregation mode @@ -95,6 +98,24 @@ const buildQuery: BuildQuery<TableChartFormData> = ( }, ]; } + + columns = columns.map(col => { + if ( + isPhysicalColumn(col) && + formData.time_grain_sqla && + hasGenericChartAxes && + formData?.temporal_columns_lookup?.[col] + ) { + return { + timeGrain: formData.time_grain_sqla, + columnType: 'BASE_AXIS', + sqlExpression: col, + label: col, + expressionType: 'SQL', + } as AdhocColumn; + } + return col; + }); } const moreProps: Partial<QueryObject> = {}; @@ -108,6 +129,7 @@ const buildQuery: BuildQuery<TableChartFormData> = ( let queryObject = { ...baseQueryObject, + columns, orderby, metrics, post_processing: postProcessing, diff --git a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx index ca097f5349c0f..bb8b09e645d6c 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx @@ -19,12 +19,14 @@ */ import React from 'react'; import { - addLocaleData, ChartDataResponseResult, ensureIsArray, FeatureFlag, GenericDataType, + hasGenericChartAxes, + isAdhocColumn, isFeatureEnabled, + isPhysicalColumn, QueryFormColumn, QueryMode, smartDateFormatter, @@ -41,19 +43,15 @@ import { sections, sharedControls, ControlPanelState, - ExtraControlProps, ControlState, - emitFilterControl, Dataset, ColumnMeta, defineSavedMetrics, + getStandardizedControls, } from '@superset-ui/chart-controls'; -import i18n from './i18n'; import { PAGE_SIZE_OPTIONS } from './consts'; -addLocaleData(i18n); - function getQueryMode(controls: ControlStateMapping): QueryMode { const mode = controls?.query_mode?.value; if (mode === QueryMode.aggregate || mode === QueryMode.raw) { @@ -99,15 +97,14 @@ const queryMode: ControlConfig<'RadioButtonControl'> = { rerender: ['all_columns', 'groupby', 'metrics', 'percent_metrics'], }; -const all_columns: typeof sharedControls.groupby = { - type: 'SelectControl', +const allColumnsControl: typeof sharedControls.groupby = { + ...sharedControls.groupby, label: t('Columns'), description: t('Columns to display'), multi: true, freeForm: true, allowAll: true, commaChoosesOption: false, - default: [], optionRenderer: c => <ColumnOption showType column={c} />, valueRenderer: c => <ColumnOption column={c} />, valueKey: 'column_name', @@ -115,7 +112,7 @@ const all_columns: typeof sharedControls.groupby = { options: datasource?.columns || [], queryMode: getQueryMode(controls), externalValidationErrors: - isRawMode({ controls }) && ensureIsArray(controlState.value).length === 0 + isRawMode({ controls }) && ensureIsArray(controlState?.value).length === 0 ? [t('must have a value')] : [], }), @@ -123,37 +120,12 @@ const all_columns: typeof sharedControls.groupby = { resetOnHide: false, }; -const dnd_all_columns: typeof sharedControls.groupby = { - type: 'DndColumnSelect', - label: t('Columns'), - description: t('Columns to display'), - default: [], - mapStateToProps({ datasource, controls }, controlState) { - const newState: ExtraControlProps = {}; - if (datasource?.columns[0]?.hasOwnProperty('column_name')) { - const options = (datasource as Dataset).columns; - newState.options = Object.fromEntries( - options.map((option: ColumnMeta) => [option.column_name, option]), - ); - } else newState.options = datasource?.columns; - newState.queryMode = getQueryMode(controls); - newState.externalValidationErrors = - isRawMode({ controls }) && ensureIsArray(controlState.value).length === 0 - ? [t('must have a value')] - : []; - return newState; - }, - visibility: isRawMode, - resetOnHide: false, -}; - -const percent_metrics: typeof sharedControls.metrics = { - type: 'MetricsControl', +const percentMetricsControl: typeof sharedControls.metrics = { + ...sharedControls.metrics, label: t('Percentage metrics'), description: t( 'Metrics for which percentage of total are to be displayed. Calculated from only data within the row limit.', ), - multi: true, visibility: isAggMode, resetOnHide: false, mapStateToProps: ({ datasource, controls }, controlState) => ({ @@ -165,7 +137,7 @@ const percent_metrics: typeof sharedControls.metrics = { externalValidationErrors: validateAggControlValues(controls, [ controls.groupby?.value, controls.metrics?.value, - controlState.value, + controlState?.value, ]), }), rerender: ['groupby', 'metrics'], @@ -173,14 +145,9 @@ const percent_metrics: typeof sharedControls.metrics = { validators: [], }; -const dnd_percent_metrics = { - ...percent_metrics, - type: 'DndMetricSelect', -}; - const config: ControlPanelConfig = { controlPanelSections: [ - sections.legacyTimeseriesTime, + sections.genericTime, { label: t('Query'), expanded: true, @@ -221,6 +188,37 @@ const config: ControlPanelConfig = { }, }, ], + [ + hasGenericChartAxes && isAggMode + ? { + name: 'time_grain_sqla', + config: { + ...sharedControls.time_grain_sqla, + visibility: ({ controls }) => { + const dttmLookup = Object.fromEntries( + ensureIsArray(controls?.groupby?.options).map(option => [ + option.column_name, + option.is_dttm, + ]), + ); + + return ensureIsArray(controls?.groupby.value) + .map(selection => { + if (isAdhocColumn(selection)) { + return true; + } + if (isPhysicalColumn(selection)) { + return !!dttmLookup[selection]; + } + return false; + }) + .some(Boolean); + }, + }, + } + : null, + hasGenericChartAxes && isAggMode ? 'temporal_columns_lookup' : null, + ], [ { name: 'metrics', @@ -254,19 +252,13 @@ const config: ControlPanelConfig = { }, { name: 'all_columns', - config: isFeatureEnabled(FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP) - ? dnd_all_columns - : all_columns, + config: allColumnsControl, }, ], [ { name: 'percent_metrics', - config: { - ...(isFeatureEnabled(FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP) - ? dnd_percent_metrics - : percent_metrics), - }, + config: percentMetricsControl, }, ], ['adhoc_filters'], @@ -316,6 +308,7 @@ const config: ControlPanelConfig = { { name: 'row_limit', override: { + default: 1000, visibility: ({ controls }: ControlPanelsContainerProps) => !controls?.server_pagination?.value, }, @@ -375,7 +368,6 @@ const config: ControlPanelConfig = { }, }, ], - emitFilterControl, ], }, { @@ -493,7 +485,6 @@ const config: ControlPanelConfig = { queryResponse: chart?.queriesResponse?.[0] as | ChartDataResponseResult | undefined, - emitFilter: explore?.controls?.table_filter?.value, }; }, }, @@ -543,10 +534,10 @@ const config: ControlPanelConfig = { ], }, ], - denormalizeFormData: formData => ({ + formDataOverrides: formData => ({ ...formData, - metrics: formData.standardizedFormData.standardizedState.metrics, - groupby: formData.standardizedFormData.standardizedState.columns, + metrics: getStandardizedControls().popAllMetrics(), + groupby: getStandardizedControls().popAllColumns(), }), }; diff --git a/superset-frontend/plugins/plugin-chart-table/src/index.ts b/superset-frontend/plugins/plugin-chart-table/src/index.ts index bce2112d922df..4e862fc5a55d4 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/index.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/index.ts @@ -31,7 +31,7 @@ export { default as __hack__ } from './types'; export * from './types'; const metadata = new ChartMetadata({ - behaviors: [Behavior.INTERACTIVE_CHART], + behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL], category: t('Table'), canBeAnnotationTypes: ['EVENT', 'INTERVAL'], description: t( diff --git a/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts b/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts index 5cf4fd1e83c43..2fae16c31c87e 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts @@ -204,7 +204,12 @@ const transformProps = ( queriesData = [], filterState, ownState: serverPaginationData, - hooks: { onAddFilter: onChangeFilter, setDataMask = () => {} }, + hooks: { + onAddFilter: onChangeFilter, + setDataMask = () => {}, + onContextMenu, + }, + emitCrossFilters, } = chartProps; const { @@ -213,7 +218,6 @@ const transformProps = ( show_cell_bars: showCellBars = true, include_search: includeSearch = false, page_length: pageLength, - emit_filter: emitFilter, server_pagination: serverPagination = false, server_page_length: serverPageLength = 10, order_desc: sortDesc = false, @@ -269,11 +273,12 @@ const transformProps = ( ? serverPageLength : getPageSize(pageLength, data.length, columns.length), filters: filterState.filters, - emitFilter, + emitCrossFilters, onChangeFilter, columnColorFormatters, timeGrain, allowRearrangeColumns, + onContextMenu, }; }; diff --git a/superset-frontend/plugins/plugin-chart-table/src/types.ts b/superset-frontend/plugins/plugin-chart-table/src/types.ts index f5b83fa8bfd7e..3a591e8682ed1 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/types.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/types.ts @@ -30,6 +30,7 @@ import { ChartDataResponseResult, QueryFormData, SetDataMaskHook, + BinaryQueryObjectFilterClause, } from '@superset-ui/core'; import { ColorFormatters, ColumnConfig } from '@superset-ui/chart-controls'; @@ -68,7 +69,6 @@ export type TableChartFormData = QueryFormData & { order_desc?: boolean; show_cell_bars?: boolean; table_timestamp_format?: string; - emit_filter?: boolean; time_grain_sqla?: TimeGranularity; column_config?: Record<string, ColumnConfig>; allow_rearrange_columns?: boolean; @@ -107,10 +107,15 @@ export interface TableChartTransformedProps<D extends DataRecord = DataRecord> { // These are dashboard filters, don't be confused with in-chart search filter // enabled by `includeSearch` filters?: DataRecordFilters; - emitFilter?: boolean; + emitCrossFilters?: boolean; onChangeFilter?: ChartProps['hooks']['onAddFilter']; columnColorFormatters?: ColorFormatters; allowRearrangeColumns?: boolean; + onContextMenu?: ( + clientX: number, + clientY: number, + filters?: BinaryQueryObjectFilterClause[], + ) => void; } export default {}; diff --git a/superset-frontend/plugins/plugin-chart-table/test/TableChart.test.tsx b/superset-frontend/plugins/plugin-chart-table/test/TableChart.test.tsx index 867b6e6799c3a..d8d76b5c8f626 100644 --- a/superset-frontend/plugins/plugin-chart-table/test/TableChart.test.tsx +++ b/superset-frontend/plugins/plugin-chart-table/test/TableChart.test.tsx @@ -18,11 +18,12 @@ */ import React from 'react'; import { CommonWrapper } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import TableChart from '../src/TableChart'; import transformProps from '../src/transformProps'; import DateWithFormatter from '../src/utils/DateWithFormatter'; import testData from './testData'; -import { mount } from './enzyme'; +import { mount, ProviderWrapper } from './enzyme'; describe('plugin-chart-table', () => { describe('transformProps', () => { @@ -105,5 +106,77 @@ describe('plugin-chart-table', () => { tree = wrap.render(); expect(tree.text()).toContain('No records found'); }); + + it('render color with column color formatter', () => { + render( + ProviderWrapper({ + children: ( + <TableChart + {...transformProps({ + ...testData.advanced, + rawFormData: { + ...testData.advanced.rawFormData, + conditional_formatting: [ + { + colorScheme: '#ACE1C4', + column: 'sum__num', + operator: '>', + targetValue: 2467, + }, + ], + }, + })} + /> + ), + }), + ); + + expect(getComputedStyle(screen.getByTitle('2467063')).background).toBe( + 'rgba(172, 225, 196, 1)', + ); + expect(getComputedStyle(screen.getByTitle('2467')).background).toBe(''); + }); + + it('render cell without color', () => { + const dataWithEmptyCell = testData.advanced.queriesData[0]; + dataWithEmptyCell.data.push({ + __timestamp: null, + name: 'Noah', + sum__num: null, + '%pct_nice': 0.643, + 'abc.com': 'bazzinga', + }); + + render( + ProviderWrapper({ + children: ( + <TableChart + {...transformProps({ + ...testData.advanced, + queriesData: [dataWithEmptyCell], + rawFormData: { + ...testData.advanced.rawFormData, + conditional_formatting: [ + { + colorScheme: '#ACE1C4', + column: 'sum__num', + operator: '<', + targetValue: 12342, + }, + ], + }, + })} + /> + ), + }), + ); + expect(getComputedStyle(screen.getByTitle('2467')).background).toBe( + 'rgba(172, 225, 196, 0.812)', + ); + expect(getComputedStyle(screen.getByTitle('2467063')).background).toBe( + '', + ); + expect(getComputedStyle(screen.getByText('N/A')).background).toBe(''); + }); }); }); diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/package.json b/superset-frontend/plugins/plugin-chart-word-cloud/package.json index 35d514b79917d..cdf87a66a4240 100644 --- a/superset-frontend/plugins/plugin-chart-word-cloud/package.json +++ b/superset-frontend/plugins/plugin-chart-word-cloud/package.json @@ -36,6 +36,7 @@ }, "peerDependencies": { "@types/react": "*", + "@types/lodash": "*", "@superset-ui/chart-controls": "*", "@superset-ui/core": "*", "react": "^16.13.1" diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/chart/WordCloud.tsx b/superset-frontend/plugins/plugin-chart-word-cloud/src/chart/WordCloud.tsx index 61f3e7977a1a9..2cedd648aa23b 100644 --- a/superset-frontend/plugins/plugin-chart-word-cloud/src/chart/WordCloud.tsx +++ b/superset-frontend/plugins/plugin-chart-word-cloud/src/chart/WordCloud.tsx @@ -31,6 +31,7 @@ import { seed, CategoricalColorScale, } from '@superset-ui/core'; +import { isEqual } from 'lodash'; const seedRandom = seed('superset-ui'); export const ROTATION = { @@ -134,8 +135,8 @@ class WordCloud extends React.PureComponent< const { data, encoding, width, height, rotation } = this.props; if ( - prevProps.data !== data || - prevProps.encoding !== encoding || + !isEqual(prevProps.data, data) || + !isEqual(prevProps.encoding, encoding) || prevProps.width !== width || prevProps.height !== height || prevProps.rotation !== rotation diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts b/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts index fce23133830f5..f40a9c19af5a2 100644 --- a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts +++ b/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts @@ -17,7 +17,11 @@ * under the License. */ import { t, validateNonEmpty } from '@superset-ui/core'; -import { ControlPanelConfig, sections } from '@superset-ui/chart-controls'; +import { + ControlPanelConfig, + getStandardizedControls, + sections, +} from '@superset-ui/chart-controls'; const config: ControlPanelConfig = { controlPanelSections: [ @@ -79,9 +83,9 @@ const config: ControlPanelConfig = { type: 'SelectControl', label: t('Word Rotation'), choices: [ - ['random', 'random'], - ['flat', 'flat'], - ['square', 'square'], + ['random', t('random')], + ['flat', t('flat')], + ['square', t('square')], ], renderTrigger: true, default: 'square', @@ -103,6 +107,11 @@ const config: ControlPanelConfig = { default: 100, }, }, + formDataOverrides: formData => ({ + ...formData, + series: getStandardizedControls().shiftColumn(), + metric: getStandardizedControls().shiftMetric(), + }), }; export default config; diff --git a/superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts b/superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts index 6d98bf19e581a..10587b382f978 100644 --- a/superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts +++ b/superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts @@ -17,11 +17,7 @@ * under the License. */ import { t } from '@superset-ui/core'; -import { - ControlPanelConfig, - formatSelectOptions, - sections, -} from '@superset-ui/chart-controls'; +import { ControlPanelConfig, sections } from '@superset-ui/chart-controls'; const config: ControlPanelConfig = { controlPanelSections: [ @@ -47,12 +43,12 @@ const config: ControlPanelConfig = { description: t( 'Determines how whiskers and outliers are calculated.', ), - choices: formatSelectOptions([ - 'Tukey', - 'Min/max (no outliers)', - '2/98 percentiles', - '9/91 percentiles', - ]), + choices: [ + ['Tukey', t('Tukey')], + ['Min/max (no outliers)', t('Min/max (no outliers)')], + ['2/98 percentiles', t('2/98 percentiles')], + ['9/91 percentiles', t('9/91 percentiles')], + ], }, }, { @@ -60,12 +56,12 @@ const config: ControlPanelConfig = { config: { type: 'SelectControl', label: t('X Tick Layout'), - choices: formatSelectOptions([ - 'auto', - 'flat', - '45°', - 'staggered', - ]), + choices: [ + ['auto', t('auto')], + ['flat', t('flat')], + ['45°', '45°'], + ['staggered', t('staggered')], + ], default: 'auto', clearable: false, renderTrigger: true, diff --git a/superset-frontend/plugins/preset-chart-xy/src/utils/convertScaleToDataUIScaleShape.ts b/superset-frontend/plugins/preset-chart-xy/src/utils/convertScaleToDataUIScaleShape.ts index 4d756e138ba88..972f01f9092d2 100644 --- a/superset-frontend/plugins/preset-chart-xy/src/utils/convertScaleToDataUIScaleShape.ts +++ b/superset-frontend/plugins/preset-chart-xy/src/utils/convertScaleToDataUIScaleShape.ts @@ -43,7 +43,7 @@ function isCompatibleDomainOrRange( } /** - * Convert encodeable scale object into @data-ui's scale config + * Convert encodable scale object into @data-ui's scale config * @param scale */ export default function convertScaleToDataUIScale<Output extends Value>( diff --git a/superset-frontend/spec/fixtures/mockChartQueries.js b/superset-frontend/spec/fixtures/mockChartQueries.js index e4fa224ad8263..dc29d71abbf28 100644 --- a/superset-frontend/spec/fixtures/mockChartQueries.js +++ b/superset-frontend/spec/fixtures/mockChartQueries.js @@ -33,33 +33,17 @@ export default { triggerQuery: false, lastRendered: 0, form_data: { - slice_id: sliceId, - viz_type: 'pie', - row_limit: 50000, - metric: 'sum__num', - since: '100 years ago', - groupby: ['gender'], - metrics: ['sum__num'], - compare_lag: '10', - limit: '25', - until: 'now', - granularity: 'ds', - markup_type: 'markdown', - where: '', - compare_suffix: 'o10Y', - datasource: datasourceId, - }, - formData: { datasource: datasourceId, viz_type: 'pie', slice_id: sliceId, - granularity_sqla: null, - time_grain_sqla: null, + slice_name: 'Genders', + granularity_sqla: undefined, + time_grain_sqla: undefined, since: '100 years ago', until: 'now', metrics: ['sum__num'], groupby: ['gender'], - limit: '25', + limit: 25, pie_label_type: 'key', donut: false, show_legend: true, diff --git a/superset-frontend/spec/fixtures/mockCharts.ts b/superset-frontend/spec/fixtures/mockCharts.ts new file mode 100644 index 0000000000000..570d52cdc0612 --- /dev/null +++ b/superset-frontend/spec/fixtures/mockCharts.ts @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export interface ChartListChart { + id: number; + slice_name: string; + url: string; + last_saved_at: null | string; + last_saved_by: null | { id: number; first_name: string; last_name: string }; + owners: { + id: number; + first_name: string; + last_name: string; + username: string; + }[]; + dashboards: { id: number; dashboard_title: string }[]; +} + +const CHART_ID = 1; +const MOCK_CHART: ChartListChart = { + id: CHART_ID, + slice_name: 'Sample chart', + url: `/explore/?slice_id=${CHART_ID}`, + last_saved_at: null, + dashboards: [], + last_saved_by: null, + owners: [], +}; + +/** + * Get mock charts as would be returned by the /api/v1/chart list endpoint. + */ +export const getMockChart = ( + overrides: Partial<ChartListChart> = {}, +): ChartListChart => ({ + ...MOCK_CHART, + ...(overrides.id ? { url: `/explore/?slice_id=${overrides.id}` } : null), + ...overrides, +}); diff --git a/superset-frontend/spec/fixtures/mockDashboardInfo.js b/superset-frontend/spec/fixtures/mockDashboardInfo.js index c11ec7f88a35d..b2f9f11832232 100644 --- a/superset-frontend/spec/fixtures/mockDashboardInfo.js +++ b/superset-frontend/spec/fixtures/mockDashboardInfo.js @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ +import { FilterBarOrientation } from 'src/dashboard/types'; + export default { id: 1234, slug: 'dashboardSlug', @@ -36,4 +38,5 @@ export default { flash_messages: [], conf: { SUPERSET_WEBSERVER_TIMEOUT: 60 }, }, + filterBarOrientation: FilterBarOrientation.VERTICAL, }; diff --git a/superset-frontend/spec/fixtures/mockDashboardState.js b/superset-frontend/spec/fixtures/mockDashboardState.js index 49b71053710a8..0895ccf386955 100644 --- a/superset-frontend/spec/fixtures/mockDashboardState.js +++ b/superset-frontend/spec/fixtures/mockDashboardState.js @@ -1,3 +1,4 @@ +/* eslint-disable theme-colors/no-literal-colors */ /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -30,3 +31,88 @@ export default { focusedFilterField: null, refreshFrequency: 0, }; + +export const overwriteConfirmMetadata = { + updatedAt: '2022-10-07T16:35:30.924212', + updatedBy: 'Superset Admin', + overwriteConfirmItems: [ + { + keyPath: 'css', + oldValue: '', + newValue: ` + .navbar { + transition: opacity 0.5s ease; + } +`, + }, + { + keyPath: 'json_metadata.filter_scopes', + oldValue: `{ + "122": { + "ethnic_minority": { + "scope": ["ROOT_ID"], + "immune": [] + }, + "gender": { + "scope": ["ROOT_ID"], + "immune": [] + }, + "developer_type": { + "scope": ["ROOT_ID"], + "immune": [] + }, + "lang_at_home": { + "scope": ["ROOT_ID"], + "immune": [] + }, + "country_live": { + "scope": ["ROOT_ID"], + "immune": [] + } + } +}`, + newValue: `{ + "122": { + "ethnic_minority": { + "scope": ["ROOT_ID"], + "immune": [ + 131, + 115, + 123, + 89, + 94, + 71 + ] + }, + "gender": { + "scope": ["ROOT_ID"], + "immune": [] + }, + "developer_type": { + "scope": ["ROOT_ID"], + "immune": [] + }, + "lang_at_home": { + "scope": ["ROOT_ID"], + "immune": [] + }, + "country_live": { + "scope": ["ROOT_ID"], + "immune": [] + } + } +}`, + }, + ], + dashboardId: 9, + data: { + certified_by: '', + certification_details: '', + css: ".navbar {\n transition: opacity 0.5s ease;\n opacity: 0.05;\n}\n.navbar:hover {\n opacity: 1;\n}\n.chart-header .header{\n font-weight: @font-weight-normal;\n font-size: 12px;\n}\n/*\nvar bnbColors = [\n //rausch hackb kazan babu lima beach tirol\n '#ff5a5f', '#7b0051', '#007A87', '#00d1c1', '#8ce071', '#ffb400', '#b4a76c',\n '#ff8083', '#cc0086', '#00a1b3', '#00ffeb', '#bbedab', '#ffd266', '#cbc29a',\n '#ff3339', '#ff1ab1', '#005c66', '#00b3a5', '#55d12e', '#b37e00', '#988b4e',\n ];\n*/\n", + dashboard_title: 'FCC New Coder Survey 2018', + slug: null, + owners: [], + json_metadata: + '{"timed_refresh_immune_slices":[],"expanded_slices":{},"refresh_frequency":0,"default_filters":"{}","color_scheme":"supersetColors","label_colors":{"0":"#FCC700","1":"#A868B7","15":"#3CCCCB","30":"#A38F79","45":"#8FD3E4","age":"#1FA8C9","Yes,":"#1FA8C9","Female":"#454E7C","Prefer":"#5AC189","No,":"#FF7F44","Male":"#666666","Prefer not to say":"#E04355","Ph.D.":"#FCC700","associate\'s degree":"#A868B7","bachelor\'s degree":"#3CCCCB","high school diploma or equivalent (GED)":"#A38F79","master\'s degree (non-professional)":"#8FD3E4","no high school (secondary school)":"#A1A6BD","professional degree (MBA, MD, JD, etc.)":"#ACE1C4","some college credit, no degree":"#FEC0A1","some high school":"#B2B2B2","trade, technical, or vocational training":"#EFA1AA","No, not an ethnic minority":"#1FA8C9","Yes, an ethnic minority":"#454E7C","<NULL>":"#5AC189","Yes":"#FF7F44","No":"#666666","last_yr_income":"#E04355","More":"#A1A6BD","Less":"#ACE1C4","I":"#FEC0A1","expected_earn":"#B2B2B2","Yes: Willing To":"#EFA1AA","No: Not Willing to":"#FDE380","No Answer":"#D3B3DA","In an Office (with Other Developers)":"#9EE5E5","No Preference":"#D1C6BC","From Home":"#1FA8C9"},"show_native_filters":true,"color_scheme_domain":["#1FA8C9","#454E7C","#5AC189","#FF7F44","#666666","#E04355","#FCC700","#A868B7","#3CCCCB","#A38F79","#8FD3E4","#A1A6BD","#ACE1C4","#FEC0A1","#B2B2B2","#EFA1AA","#FDE380","#D3B3DA","#9EE5E5","#D1C6BC"],"shared_label_colors":{"Male":"#5ac19e","Female":"#1f86c9","<NULL>":"#5AC189","Prefer not to say":"#47457c","No Answer":"#e05043","Yes, an ethnic minority":"#666666","No, not an ethnic minority":"#ffa444","age":"#1FA8C9"},"cross_filters_enabled":false,"filter_scopes":{},"chart_configuration":{},"positions":{}}', + }, +}; diff --git a/superset-frontend/spec/fixtures/mockDatasource.js b/superset-frontend/spec/fixtures/mockDatasource.js index 30513fc126748..21a5805519b67 100644 --- a/superset-frontend/spec/fixtures/mockDatasource.js +++ b/superset-frontend/spec/fixtures/mockDatasource.js @@ -171,7 +171,6 @@ export default { name: 'birth_names', owners: [{ first_name: 'joe', last_name: 'man', id: 1 }], database: { - allow_multi_schema_metadata_fetch: null, name: 'main', backend: 'sqlite', }, diff --git a/superset-frontend/spec/fixtures/mockNativeFilters.ts b/superset-frontend/spec/fixtures/mockNativeFilters.ts index 3cb4925e90894..dea5cfb8fd025 100644 --- a/superset-frontend/spec/fixtures/mockNativeFilters.ts +++ b/superset-frontend/spec/fixtures/mockNativeFilters.ts @@ -145,6 +145,7 @@ export const singleNativeFiltersState = { inverseSelection: false, allowsMultipleValues: false, isRequired: false, + chartsInScope: [230], }, }, }; diff --git a/superset-frontend/spec/fixtures/mockSliceEntities.js b/superset-frontend/spec/fixtures/mockSliceEntities.js index 69570c5c8f874..cb6d84ea347ad 100644 --- a/superset-frontend/spec/fixtures/mockSliceEntities.js +++ b/superset-frontend/spec/fixtures/mockSliceEntities.js @@ -26,7 +26,7 @@ export const sliceEntitiesForChart = { slices: { [sliceId]: { slice_id: sliceId, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%2018%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%2018%7D', slice_name: 'Genders', form_data: { slice_id: sliceId, @@ -62,7 +62,7 @@ export const sliceEntitiesForDashboard = { slices: { [filterId]: { slice_id: filterId, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20127%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20127%7D', slice_name: 'Region Filter', form_data: { instant_filtering: true, @@ -86,7 +86,7 @@ export const sliceEntitiesForDashboard = { }, 128: { slice_id: 128, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20128%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20128%7D', slice_name: "World's Population", form_data: {}, viz_type: 'big_number', @@ -98,7 +98,7 @@ export const sliceEntitiesForDashboard = { }, 129: { slice_id: 129, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20129%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20129%7D', slice_name: 'Most Populated Countries', form_data: {}, viz_type: 'table', @@ -110,7 +110,7 @@ export const sliceEntitiesForDashboard = { }, 130: { slice_id: 130, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20130%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20130%7D', slice_name: 'Growth Rate', form_data: {}, viz_type: 'line', @@ -122,7 +122,7 @@ export const sliceEntitiesForDashboard = { }, 131: { slice_id: 131, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20131%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20131%7D', slice_name: '% Rural', form_data: {}, viz_type: 'world_map', @@ -134,7 +134,7 @@ export const sliceEntitiesForDashboard = { }, 132: { slice_id: 132, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20132%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20132%7D', slice_name: 'Life Expectancy VS Rural %', form_data: {}, viz_type: 'bubble', @@ -146,7 +146,7 @@ export const sliceEntitiesForDashboard = { }, 133: { slice_id: 133, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20133%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20133%7D', slice_name: 'Rural Breakdown', form_data: {}, viz_type: 'sunburst', @@ -158,7 +158,7 @@ export const sliceEntitiesForDashboard = { }, 134: { slice_id: 134, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20134%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20134%7D', slice_name: "World's Pop Growth", form_data: {}, viz_type: 'area', @@ -170,7 +170,7 @@ export const sliceEntitiesForDashboard = { }, 135: { slice_id: 135, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20135%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20135%7D', slice_name: 'Box plot', form_data: {}, viz_type: 'box_plot', @@ -182,7 +182,7 @@ export const sliceEntitiesForDashboard = { }, 136: { slice_id: 136, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20136%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20136%7D', slice_name: 'Treemap', form_data: {}, viz_type: 'treemap', diff --git a/superset-frontend/spec/fixtures/mockStore.js b/superset-frontend/spec/fixtures/mockStore.js index 5fe8f54022eb7..119e19a0847d5 100644 --- a/superset-frontend/spec/fixtures/mockStore.js +++ b/superset-frontend/spec/fixtures/mockStore.js @@ -20,6 +20,7 @@ import { createStore, applyMiddleware, compose } from 'redux'; import thunk from 'redux-thunk'; import { rootReducer } from 'src/views/store'; +import { FilterBarOrientation } from 'src/dashboard/types'; import mockState from './mockState'; import { @@ -71,60 +72,67 @@ export const mockStoreWithChartsInTabsAndRoot = export const sliceIdWithAppliedFilter = sliceId + 1; export const sliceIdWithRejectedFilter = sliceId + 2; +export const stateWithFilters = { + ...mockState, + dashboardFilters, + dataMask: dataMaskWith2Filters, + charts: { + ...mockState.charts, + [sliceIdWithAppliedFilter]: { + ...mockState.charts[sliceId], + queryResponse: { + status: 'success', + applied_filters: [{ column: 'region' }], + rejected_filters: [], + }, + }, + [sliceIdWithRejectedFilter]: { + ...mockState.charts[sliceId], + queryResponse: { + status: 'success', + applied_filters: [], + rejected_filters: [{ column: 'region', reason: 'not_in_datasource' }], + }, + }, + }, +}; + // has one chart with a filter that has been applied, // one chart with a filter that has been rejected, // and one chart with no filters set. export const getMockStoreWithFilters = () => - createStore(rootReducer, { - ...mockState, - dashboardFilters, - dataMask: dataMaskWith2Filters, - charts: { - ...mockState.charts, - [sliceIdWithAppliedFilter]: { - ...mockState.charts[sliceId], - queryResponse: { - status: 'success', - applied_filters: [{ column: 'region' }], - rejected_filters: [], - }, + createStore(rootReducer, stateWithFilters); + +export const stateWithNativeFilters = { + ...mockState, + nativeFilters, + dataMask: dataMaskWith2Filters, + charts: { + ...mockState.charts, + [sliceIdWithAppliedFilter]: { + ...mockState.charts[sliceId], + queryResponse: { + status: 'success', + applied_filters: [{ column: 'region' }], + rejected_filters: [], }, - [sliceIdWithRejectedFilter]: { - ...mockState.charts[sliceId], - queryResponse: { - status: 'success', - applied_filters: [], - rejected_filters: [{ column: 'region', reason: 'not_in_datasource' }], - }, + }, + [sliceIdWithRejectedFilter]: { + ...mockState.charts[sliceId], + queryResponse: { + status: 'success', + applied_filters: [], + rejected_filters: [{ column: 'region', reason: 'not_in_datasource' }], }, }, - }); + }, + dashboardInfo: { + filterBarOrientation: FilterBarOrientation.VERTICAL, + }, +}; export const getMockStoreWithNativeFilters = () => - createStore(rootReducer, { - ...mockState, - nativeFilters, - dataMask: dataMaskWith2Filters, - charts: { - ...mockState.charts, - [sliceIdWithAppliedFilter]: { - ...mockState.charts[sliceId], - queryResponse: { - status: 'success', - applied_filters: [{ column: 'region' }], - rejected_filters: [], - }, - }, - [sliceIdWithRejectedFilter]: { - ...mockState.charts[sliceId], - queryResponse: { - status: 'success', - applied_filters: [], - rejected_filters: [{ column: 'region', reason: 'not_in_datasource' }], - }, - }, - }, - }); + createStore(rootReducer, stateWithNativeFilters); export const stateWithoutNativeFilters = { ...mockState, @@ -149,6 +157,7 @@ export const stateWithoutNativeFilters = { }, dashboardInfo: { dash_edit_perm: true, + filterBarOrientation: FilterBarOrientation.VERTICAL, metadata: { native_filter_configuration: [], }, diff --git a/superset-frontend/spec/helpers/reducerIndex.ts b/superset-frontend/spec/helpers/reducerIndex.ts index 5599b38ddc2bd..459a112e22017 100644 --- a/superset-frontend/spec/helpers/reducerIndex.ts +++ b/superset-frontend/spec/helpers/reducerIndex.ts @@ -31,12 +31,18 @@ import explore from 'src/explore/reducers/exploreReducer'; import sqlLab from 'src/SqlLab/reducers/sqlLab'; import localStorageUsageInKilobytes from 'src/SqlLab/reducers/localStorageUsage'; import reports from 'src/reports/reducers/reports'; +import getBootstrapData from 'src/utils/getBootstrapData'; const impressionId = (state = '') => state; -const container = document.getElementById('app'); -const bootstrap = JSON.parse(container?.getAttribute('data-bootstrap') ?? '{}'); -const common = { ...bootstrap.common }; +const bootstrapData = getBootstrapData(); +const common = { ...bootstrapData.common }; +const user = { ...bootstrapData.user }; + +const noopReducer = + (initialState: unknown) => + (state = initialState) => + state; export default { charts, @@ -55,5 +61,6 @@ export default { sqlLab, localStorageUsageInKilobytes, reports, - common: () => common, + common: noopReducer(common), + user: noopReducer(user), }; diff --git a/superset-frontend/spec/helpers/setup.ts b/superset-frontend/spec/helpers/setup.ts index c2c991f95621d..281ab4ae4bb1c 100644 --- a/superset-frontend/spec/helpers/setup.ts +++ b/superset-frontend/spec/helpers/setup.ts @@ -19,9 +19,11 @@ import 'jest-enzyme'; import './shim'; import { configure as configureTestingLibrary } from '@testing-library/react'; +import { matchers } from '@emotion/jest'; configureTestingLibrary({ testIdAttribute: 'data-test', }); -document.body.innerHTML = '<div id="app" data-bootstrap="{}"></div>'; +document.body.innerHTML = '<div id="app" data-bootstrap=""></div>'; +expect.extend(matchers); diff --git a/superset-frontend/spec/helpers/shim.tsx b/superset-frontend/spec/helpers/shim.tsx index 2f014fe7e1e14..152fcc370cfc2 100644 --- a/superset-frontend/spec/helpers/shim.tsx +++ b/superset-frontend/spec/helpers/shim.tsx @@ -54,6 +54,7 @@ g.window.performance = { now: () => new Date().getTime() }; g.window.Worker = Worker; g.window.IntersectionObserver = IntersectionObserver; g.window.ResizeObserver = ResizeObserver; +g.window.featureFlags = {}; g.URL.createObjectURL = () => ''; g.caches = new CacheStorage(); @@ -88,4 +89,34 @@ jest.mock('react-markdown', () => (props: any) => <>{props.children}</>); jest.mock('rehype-sanitize', () => () => jest.fn()); jest.mock('rehype-raw', () => () => jest.fn()); +// Mocks the Icon component due to its async nature +// Tests should override this when needed +jest.mock('src/components/Icons/Icon', () => ({ + __esModule: true, + default: ({ + fileName, + role, + 'aria-label': ariaLabel, + ...rest + }: { + fileName: string; + role: string; + 'aria-label': React.AriaAttributes['aria-label']; + }) => ( + <span + role={role ?? 'img'} + aria-label={ariaLabel || fileName.replace('_', '-')} + {...rest} + /> + ), + StyledIcon: ({ + role, + 'aria-label': ariaLabel, + ...rest + }: { + role: string; + 'aria-label': React.AriaAttributes['aria-label']; + }) => <span role={role ?? 'img'} aria-label={ariaLabel} {...rest} />, +})); + process.env.WEBPACK_MODE = 'test'; diff --git a/superset-frontend/spec/helpers/testing-library.tsx b/superset-frontend/spec/helpers/testing-library.tsx index 56489cce84714..25b0324fe1864 100644 --- a/superset-frontend/spec/helpers/testing-library.tsx +++ b/superset-frontend/spec/helpers/testing-library.tsx @@ -22,30 +22,41 @@ import { render, RenderOptions } from '@testing-library/react'; import { ThemeProvider, supersetTheme } from '@superset-ui/core'; import { BrowserRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; -import { combineReducers, createStore, applyMiddleware, compose } from 'redux'; +import { + combineReducers, + createStore, + applyMiddleware, + compose, + Store, +} from 'redux'; import thunk from 'redux-thunk'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; import reducerIndex from 'spec/helpers/reducerIndex'; import { QueryParamProvider } from 'use-query-params'; +import QueryProvider from 'src/views/QueryProvider'; type Options = Omit<RenderOptions, 'queries'> & { useRedux?: boolean; useDnd?: boolean; useQueryParams?: boolean; useRouter?: boolean; + useQuery?: boolean; initialState?: {}; reducers?: {}; + store?: Store; }; -function createWrapper(options?: Options) { +export function createWrapper(options?: Options) { const { useDnd, useRedux, useQueryParams, + useQuery = true, useRouter, initialState, reducers, + store, } = options || {}; return ({ children }: { children?: ReactNode }) => { @@ -58,13 +69,15 @@ function createWrapper(options?: Options) { } if (useRedux) { - const store = createStore( - combineReducers(reducers || reducerIndex), - initialState || {}, - compose(applyMiddleware(thunk)), - ); + const mockStore = + store ?? + createStore( + combineReducers(reducers || reducerIndex), + initialState || {}, + compose(applyMiddleware(thunk)), + ); - result = <Provider store={store}>{result}</Provider>; + result = <Provider store={mockStore}>{result}</Provider>; } if (useQueryParams) { @@ -75,6 +88,10 @@ function createWrapper(options?: Options) { result = <BrowserRouter>{result}</BrowserRouter>; } + if (useQuery) { + result = <QueryProvider>{result}</QueryProvider>; + } + return result; }; } diff --git a/superset-frontend/src/GlobalStyles.tsx b/superset-frontend/src/GlobalStyles.tsx index 1e2cf449ff637..50f54ba88fa6e 100644 --- a/superset-frontend/src/GlobalStyles.tsx +++ b/superset-frontend/src/GlobalStyles.tsx @@ -19,6 +19,7 @@ import React from 'react'; import { css } from '@superset-ui/core'; import { Global } from '@emotion/react'; +import { mix } from 'polished'; export const GlobalStyles = () => ( <Global @@ -33,6 +34,38 @@ export const GlobalStyles = () => ( th { font-weight: ${theme.typography.weights.bold}; } + // TODO: Remove when on Ant Design 5. + // Check src/components/Modal for more info. + .modal-functions-ok-button { + border-radius: ${theme.borderRadius}px; + background: ${theme.colors.primary.base}; + border: none; + text-transform: uppercase; + color: ${theme.colors.grayscale.light5}; + line-height: 1.5715; + font-size: ${theme.typography.sizes.s}px; + font-weight: ${theme.typography.weights.bold}; + &:hover { + background: ${theme.colors.primary.dark1}; + } + } + .modal-functions-cancel-button { + border-radius: ${theme.borderRadius}px; + background: ${theme.colors.primary.light4}; + border: none; + text-transform: uppercase; + color: ${theme.colors.primary.dark1}; + line-height: 1.5715; + font-size: ${theme.typography.sizes.s}px; + font-weight: ${theme.typography.weights.bold}; + &:hover { + background: ${mix( + 0.1, + theme.colors.primary.base, + theme.colors.primary.light4, + )}; + } + } `} /> ); diff --git a/superset-frontend/src/SqlLab/App.jsx b/superset-frontend/src/SqlLab/App.jsx index 02a4df2a6f8d9..b75ea5c624bb6 100644 --- a/superset-frontend/src/SqlLab/App.jsx +++ b/superset-frontend/src/SqlLab/App.jsx @@ -23,11 +23,15 @@ import thunkMiddleware from 'redux-thunk'; import { hot } from 'react-hot-loader/root'; import { ThemeProvider } from '@superset-ui/core'; import { GlobalStyles } from 'src/GlobalStyles'; +import QueryProvider from 'src/views/QueryProvider'; import { initFeatureFlags, isFeatureEnabled, FeatureFlag, } from 'src/featureFlags'; +import setupExtensions from 'src/setup/setupExtensions'; +import getBootstrapData from 'src/utils/getBootstrapData'; +import logger from 'src/middleware/loggerMiddleware'; import getInitialState from './reducers/getInitialState'; import rootReducer from './reducers/index'; import { initEnhancer } from '../reduxUtils'; @@ -39,14 +43,14 @@ import { import { BYTES_PER_CHAR, KB_STORAGE } from './constants'; import setupApp from '../setup/setupApp'; -import './main.less'; import '../assets/stylesheets/reactable-pagination.less'; import { theme } from '../preamble'; +import { SqlLabGlobalStyles } from './SqlLabGlobalStyles'; setupApp(); +setupExtensions(); -const appContainer = document.getElementById('app'); -const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap')); +const bootstrapData = getBootstrapData(); initFeatureFlags(bootstrapData.common.feature_flags); @@ -67,6 +71,9 @@ const sqlLabPersistStateConfig = { ...state[path], queries: emptyQueryResults(state[path].queries), queryEditors: clearQueryEditors(state[path].queryEditors), + unsavedQueryEditor: clearQueryEditors([ + state[path].unsavedQueryEditor, + ])[0], }; } }); @@ -91,6 +98,12 @@ const sqlLabPersistStateConfig = { const result = { ...initialState, ...persistedState, + sqlLab: { + ...(persistedState?.sqlLab || {}), + // Overwrite initialState over persistedState for sqlLab + // since a logic in getInitialState overrides the value from persistedState + ...initialState.sqlLab, + }, }; // Filter out any user data that may have been persisted in an older version. // Get user from bootstrap data instead, every time @@ -104,7 +117,7 @@ const store = createStore( rootReducer, initialState, compose( - applyMiddleware(thunkMiddleware), + applyMiddleware(thunkMiddleware, logger), initEnhancer( !isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE), sqlLabPersistStateConfig, @@ -125,12 +138,15 @@ if (sqlLabMenu) { } const Application = () => ( - <Provider store={store}> - <ThemeProvider theme={theme}> - <GlobalStyles /> - <App /> - </ThemeProvider> - </Provider> + <QueryProvider> + <Provider store={store}> + <ThemeProvider theme={theme}> + <GlobalStyles /> + <SqlLabGlobalStyles /> + <App /> + </ThemeProvider> + </Provider> + </QueryProvider> ); export default hot(Application); diff --git a/superset-frontend/src/SqlLab/SqlLabGlobalStyles.tsx b/superset-frontend/src/SqlLab/SqlLabGlobalStyles.tsx new file mode 100644 index 0000000000000..f1398e3be9ac4 --- /dev/null +++ b/superset-frontend/src/SqlLab/SqlLabGlobalStyles.tsx @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { Global } from '@emotion/react'; +import { css } from '@superset-ui/core'; + +export const SqlLabGlobalStyles = () => ( + <Global + styles={theme => css` + body { + min-height: max( + 100vh, + ${theme.gridUnit * 125}px + ); // Set a min height so the gutter is always visible when resizing + overflow: hidden; + } + `} + /> +); diff --git a/superset-frontend/src/SqlLab/actions/sqlLab.js b/superset-frontend/src/SqlLab/actions/sqlLab.js index 04707d6ae67a8..ab8abe0edca21 100644 --- a/superset-frontend/src/SqlLab/actions/sqlLab.js +++ b/superset-frontend/src/SqlLab/actions/sqlLab.js @@ -17,8 +17,8 @@ * under the License. */ import shortid from 'shortid'; -import JSONbig from 'json-bigint'; -import { t, SupersetClient } from '@superset-ui/core'; +import rison from 'rison'; +import { SupersetClient, t } from '@superset-ui/core'; import invert from 'lodash/invert'; import mapKeys from 'lodash/mapKeys'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; @@ -32,6 +32,7 @@ import { } from 'src/components/MessageToasts/actions'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; import COMMON_ERR_MESSAGES from 'src/utils/errorMessages'; +import { newQueryTabName } from '../utils/newQueryTabName'; export const RESET_STATE = 'RESET_STATE'; export const ADD_QUERY_EDITOR = 'ADD_QUERY_EDITOR'; @@ -40,7 +41,7 @@ export const QUERY_EDITOR_SAVED = 'QUERY_EDITOR_SAVED'; export const CLONE_QUERY_TO_NEW_TAB = 'CLONE_QUERY_TO_NEW_TAB'; export const REMOVE_QUERY_EDITOR = 'REMOVE_QUERY_EDITOR'; export const MERGE_TABLE = 'MERGE_TABLE'; -export const REMOVE_TABLE = 'REMOVE_TABLE'; +export const REMOVE_TABLES = 'REMOVE_TABLES'; export const END_QUERY = 'END_QUERY'; export const REMOVE_QUERY = 'REMOVE_QUERY'; export const EXPAND_TABLE = 'EXPAND_TABLE'; @@ -111,8 +112,8 @@ const ERR_MSG_CANT_LOAD_QUERY = t("The query couldn't be loaded"); const queryClientMapping = { id: 'remoteId', db_id: 'dbId', - client_id: 'id', - label: 'title', + label: 'name', + template_parameters: 'templateParams', }; const queryServerMapping = invert(queryClientMapping); @@ -120,8 +121,19 @@ const queryServerMapping = invert(queryClientMapping); const fieldConverter = mapping => obj => mapKeys(obj, (value, key) => (key in mapping ? mapping[key] : key)); -const convertQueryToServer = fieldConverter(queryServerMapping); -const convertQueryToClient = fieldConverter(queryClientMapping); +export const convertQueryToServer = fieldConverter(queryServerMapping); +export const convertQueryToClient = fieldConverter(queryClientMapping); + +export function getUpToDateQuery(rootState, queryEditor, key) { + const { + sqlLab: { unsavedQueryEditor }, + } = rootState; + const id = key ?? queryEditor.id; + return { + ...queryEditor, + ...(id === unsavedQueryEditor.id && unsavedQueryEditor), + }; +} export function resetState() { return { type: RESET_STATE }; @@ -167,24 +179,26 @@ export function scheduleQuery(query) { ); } -export function estimateQueryCost(query) { - const { dbId, schema, sql, templateParams } = query; - const endpoint = - schema === null - ? `/superset/estimate_query_cost/${dbId}/` - : `/superset/estimate_query_cost/${dbId}/${schema}/`; - return dispatch => - Promise.all([ - dispatch({ type: COST_ESTIMATE_STARTED, query }), +export function estimateQueryCost(queryEditor) { + return (dispatch, getState) => { + const { dbId, schema, sql, selectedText, templateParams } = + getUpToDateQuery(getState(), queryEditor); + const requestSql = selectedText || sql; + const endpoint = + schema === null + ? `/superset/estimate_query_cost/${dbId}/` + : `/superset/estimate_query_cost/${dbId}/${schema}/`; + return Promise.all([ + dispatch({ type: COST_ESTIMATE_STARTED, query: queryEditor }), SupersetClient.post({ endpoint, postPayload: { - sql, + sql: requestSql, templateParams: JSON.parse(templateParams || '{}'), }, }) .then(({ json }) => - dispatch({ type: COST_ESTIMATE_RETURNED, query, json }), + dispatch({ type: COST_ESTIMATE_RETURNED, query: queryEditor, json }), ) .catch(response => getClientErrorObject(response).then(error => { @@ -194,12 +208,13 @@ export function estimateQueryCost(query) { t('Failed at retrieving results'); return dispatch({ type: COST_ESTIMATE_FAILED, - query, + query: queryEditor, error: message, }); }), ), ]); + }; } export function startQuery(query) { @@ -215,11 +230,13 @@ export function startQuery(query) { export function querySuccess(query, results) { return function (dispatch) { + const sqlEditorId = results?.query?.sqlEditorId; const sync = + sqlEditorId && !query.isDataPreview && isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE) ? SupersetClient.put({ - endpoint: encodeURI(`/tabstateview/${results.query.sqlEditorId}`), + endpoint: encodeURI(`/tabstateview/${sqlEditorId}`), postPayload: { latest_query_id: query.id }, }) : Promise.resolve(); @@ -289,14 +306,16 @@ export function fetchQueryResults(query, displayLimit) { return function (dispatch) { dispatch(requestQueryResults(query)); + const queryParams = rison.encode({ + key: query.resultsKey, + rows: displayLimit || null, + }); + return SupersetClient.get({ - endpoint: `/superset/results/${query.resultsKey}/?rows=${displayLimit}`, - parseMethod: 'text', + endpoint: `/api/v1/sqllab/results/?q=${queryParams}`, + parseMethod: 'json-bigint', }) - .then(({ text = '{}' }) => { - const bigIntJson = JSONbig.parse(text); - return dispatch(querySuccess(query, bigIntJson)); - }) + .then(({ json }) => dispatch(querySuccess(query, json))) .catch(response => getClientErrorObject(response).then(error => { const message = @@ -334,20 +353,23 @@ export function runQuery(query) { const search = window.location.search || ''; return SupersetClient.post({ - endpoint: `/superset/sql_json/${search}`, + endpoint: `/api/v1/sqllab/execute/${search}`, body: JSON.stringify(postPayload), headers: { 'Content-Type': 'application/json' }, - parseMethod: 'text', + parseMethod: 'json-bigint', }) - .then(({ text = '{}' }) => { + .then(({ json }) => { if (!query.runAsync) { - const bigIntJson = JSONbig.parse(text); - dispatch(querySuccess(query, bigIntJson)); + dispatch(querySuccess(query, json)); } }) .catch(response => getClientErrorObject(response).then(error => { - let message = error.error || error.statusText || t('Unknown error'); + let message = + error.error || + error.message || + error.statusText || + t('Unknown error'); if (message.includes('CSRF token')) { message = t(COMMON_ERR_MESSAGES.SESSION_TIMED_OUT); } @@ -357,6 +379,34 @@ export function runQuery(query) { }; } +export function runQueryFromSqlEditor( + database, + queryEditor, + defaultQueryLimit, + tempTable, + ctas, + ctasMethod, +) { + return function (dispatch, getState) { + const qe = getUpToDateQuery(getState(), queryEditor, queryEditor.id); + const query = { + dbId: qe.dbId, + sql: qe.selectedText || qe.sql, + sqlEditorId: qe.id, + tab: qe.name, + schema: qe.schema, + tempTable, + templateParams: qe.templateParams, + queryLimit: qe.queryLimit || defaultQueryLimit, + runAsync: database ? database.allow_run_async : false, + ctas, + ctas_method: ctasMethod, + updateTabState: !qe.selectedText, + }; + dispatch(runQuery(query)); + }; +} + export function reRunQuery(query) { // run Query with a new id return function (dispatch) { @@ -364,8 +414,23 @@ export function reRunQuery(query) { }; } -export function validateQuery(query) { - return function (dispatch) { +export function validateQuery(queryEditor, sql) { + return function (dispatch, getState) { + const { + sqlLab: { unsavedQueryEditor }, + } = getState(); + const qe = { + ...queryEditor, + ...(queryEditor.id === unsavedQueryEditor.id && unsavedQueryEditor), + }; + + const query = { + dbId: qe.dbId, + sql, + sqlEditorId: qe.id, + schema: qe.schema, + templateParams: qe.templateParams, + }; dispatch(startQueryValidation(query)); const postPayload = { @@ -375,7 +440,7 @@ export function validateQuery(query) { }; return SupersetClient.post({ - endpoint: `/api/v1/database/${query.dbId}/validate_sql`, + endpoint: `/api/v1/database/${query.dbId}/validate_sql/`, body: JSON.stringify(postPayload), headers: { 'Content-Type': 'application/json' }, }) @@ -395,9 +460,9 @@ export function validateQuery(query) { export function postStopQuery(query) { return function (dispatch) { return SupersetClient.post({ - endpoint: '/superset/stop_query/', - postPayload: { client_id: query.id }, - stringify: false, + endpoint: '/api/v1/query/stop', + body: JSON.stringify({ client_id: query.id }), + headers: { 'Content-Type': 'application/json' }, }) .then(() => dispatch(stopQuery(query))) .then(() => dispatch(addSuccessToast(t('Query was stopped.')))) @@ -533,6 +598,50 @@ export function addQueryEditor(queryEditor) { }; } +export function addNewQueryEditor() { + return function (dispatch, getState) { + const { + sqlLab: { + queryEditors, + tabHistory, + unsavedQueryEditor, + defaultDbId, + databases, + }, + common, + } = getState(); + const activeQueryEditor = queryEditors.find( + qe => qe.id === tabHistory[tabHistory.length - 1], + ); + const dbIds = Object.values(databases).map(database => database.id); + const firstDbId = dbIds.length > 0 ? Math.min(...dbIds) : undefined; + const { dbId, schema, queryLimit, autorun } = { + ...queryEditors[0], + ...activeQueryEditor, + ...(unsavedQueryEditor.id === activeQueryEditor?.id && + unsavedQueryEditor), + }; + const warning = isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE) + ? '' + : t( + '-- Note: Unless you save your query, these tabs will NOT persist if you clear your cookies or change browsers.\n\n', + ); + + const name = newQueryTabName(queryEditors || []); + + return dispatch( + addQueryEditor({ + dbId: dbId || defaultDbId || firstDbId, + schema: schema ?? null, + autorun: autorun ?? false, + sql: `${warning}SELECT ...`, + queryLimit: queryLimit || common.conf.DEFAULT_SQLLAB_LIMIT, + name, + }), + ); + }; +} + export function cloneQueryToNewTab(query, autorun) { return function (dispatch, getState) { const state = getState(); @@ -541,7 +650,7 @@ export function cloneQueryToNewTab(query, autorun) { qe => qe.id === tabHistory[tabHistory.length - 1], ); const queryEditor = { - title: t('Copy of %s', sourceQueryEditor.title), + name: t('Copy of %s', sourceQueryEditor.name), dbId: query.dbId ? query.dbId : null, schema: query.schema ? query.schema : null, autorun, @@ -620,6 +729,7 @@ export function switchQueryEditor(queryEditor, displayLimit) { return function (dispatch) { if ( isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE) && + queryEditor && !queryEditor.loaded ) { SupersetClient.get({ @@ -629,7 +739,7 @@ export function switchQueryEditor(queryEditor, displayLimit) { const loadedQueryEditor = { id: json.id.toString(), loaded: true, - title: json.label, + name: json.label, sql: json.sql, selectedText: null, latestQueryId: json.latest_query?.id, @@ -723,6 +833,17 @@ export function removeQueryEditor(queryEditor) { }; } +export function removeAllOtherQueryEditors(queryEditor) { + return function (dispatch, getState) { + const { sqlLab } = getState(); + sqlLab.queryEditors?.forEach(otherQueryEditor => { + if (otherQueryEditor.id !== queryEditor.id) { + dispatch(removeQueryEditor(otherQueryEditor)); + } + }); + }; +} + export function removeQuery(query) { return function (dispatch) { const sync = isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE) @@ -834,24 +955,28 @@ export function queryEditorSetAutorun(queryEditor, autorun) { }; } -export function queryEditorSetTitle(queryEditor, title) { +export function queryEditorSetTitle(queryEditor, name, id) { return function (dispatch) { const sync = isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE) ? SupersetClient.put({ - endpoint: encodeURI(`/tabstateview/${queryEditor.id}`), - postPayload: { label: title }, + endpoint: encodeURI(`/tabstateview/${id}`), + postPayload: { label: name }, }) : Promise.resolve(); return sync .then(() => - dispatch({ type: QUERY_EDITOR_SET_TITLE, queryEditor, title }), + dispatch({ + type: QUERY_EDITOR_SET_TITLE, + queryEditor: { ...queryEditor, id }, + name, + }), ) .catch(() => dispatch( addDangerToast( t( - 'An error occurred while setting the tab title. Please contact your administrator.', + 'An error occurred while setting the tab name. Please contact your administrator.', ), ), ), @@ -859,21 +984,26 @@ export function queryEditorSetTitle(queryEditor, title) { }; } -export function saveQuery(query) { +export function saveQuery(query, clientId) { + const { id, ...payload } = convertQueryToServer(query); + return dispatch => SupersetClient.post({ - endpoint: '/savedqueryviewapi/api/create', - postPayload: convertQueryToServer(query), - stringify: false, + endpoint: '/api/v1/saved_query/', + jsonPayload: convertQueryToServer(payload), }) .then(result => { - const savedQuery = convertQueryToClient(result.json.item); + const savedQuery = convertQueryToClient({ + id: result.json.id, + ...result.json.result, + }); dispatch({ type: QUERY_EDITOR_SAVED, query, + clientId, result: savedQuery, }); - dispatch(queryEditorSetTitle(query, query.title)); + dispatch(queryEditorSetTitle(query, query.name, clientId)); return savedQuery; }) .catch(() => @@ -899,20 +1029,24 @@ export const addSavedQueryToTabState = }); }; -export function updateSavedQuery(query) { +export function updateSavedQuery(query, clientId) { + const { id, ...payload } = convertQueryToServer(query); + return dispatch => SupersetClient.put({ - endpoint: `/savedqueryviewapi/api/update/${query.remoteId}`, - postPayload: convertQueryToServer(query), - stringify: false, + endpoint: `/api/v1/saved_query/${query.remoteId}`, + jsonPayload: convertQueryToServer(payload), }) .then(() => { dispatch(addSuccessToast(t('Your query was updated'))); - dispatch(queryEditorSetTitle(query, query.title)); + dispatch(queryEditorSetTitle(query, query.name, clientId)); + }) + .catch(e => { + const message = t('Your query could not be updated'); + // eslint-disable-next-line no-console + console.error(message, e); + dispatch(addDangerToast(message)); }) - .catch(() => - dispatch(addDangerToast(t('Your query could not be updated'))), - ) .then(() => dispatch(updateQueryEditor(query))); } @@ -920,8 +1054,9 @@ export function queryEditorSetSql(queryEditor, sql) { return { type: QUERY_EDITOR_SET_SQL, queryEditor, sql }; } -export function queryEditorSetAndSaveSql(queryEditor, sql) { - return function (dispatch) { +export function queryEditorSetAndSaveSql(targetQueryEditor, sql) { + return function (dispatch, getState) { + const queryEditor = getUpToDateQuery(getState(), targetQueryEditor); // saved query and set tab state use this action dispatch(queryEditorSetSql(queryEditor, sql)); if (isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE)) { @@ -965,7 +1100,7 @@ export function queryEditorSetQueryLimit(queryEditor, queryLimit) { dispatch( addDangerToast( t( - 'An error occurred while setting the tab title. Please contact your administrator.', + 'An error occurred while setting the tab name. Please contact your administrator.', ), ), ), @@ -1066,8 +1201,9 @@ function getTableExtendedMetadata(table, query, dispatch) { ); } -export function addTable(query, database, tableName, schemaName) { - return function (dispatch) { +export function addTable(queryEditor, database, tableName, schemaName) { + return function (dispatch, getState) { + const query = getUpToDateQuery(getState(), queryEditor, queryEditor.id); const table = { dbId: query.dbId, queryEditorId: query.id, @@ -1213,16 +1349,21 @@ export function collapseTable(table) { }; } -export function removeTable(table) { +export function removeTables(tables) { return function (dispatch) { + const tablesToRemove = tables?.filter(Boolean) ?? []; const sync = isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE) - ? SupersetClient.delete({ - endpoint: encodeURI(`/tableschemaview/${table.id}`), - }) + ? Promise.all( + tablesToRemove.map(table => + SupersetClient.delete({ + endpoint: encodeURI(`/tableschemaview/${table.id}`), + }), + ), + ) : Promise.resolve(); return sync - .then(() => dispatch({ type: REMOVE_TABLE, table })) + .then(() => dispatch({ type: REMOVE_TABLES, tables: tablesToRemove })) .catch(() => dispatch( addDangerToast( @@ -1259,11 +1400,12 @@ export function popStoredQuery(urlId) { .then(({ json }) => dispatch( addQueryEditor({ - title: json.title ? json.title : t('Shared query'), + name: json.name ? json.name : t('Shared query'), dbId: json.dbId ? parseInt(json.dbId, 10) : null, schema: json.schema ? json.schema : null, autorun: json.autorun ? json.autorun : false, sql: json.sql ? json.sql : 'SELECT ...', + templateParams: json.templateParams, }), ), ) @@ -1273,11 +1415,12 @@ export function popStoredQuery(urlId) { export function popSavedQuery(saveQueryId) { return function (dispatch) { return SupersetClient.get({ - endpoint: `/savedqueryviewapi/api/get/${saveQueryId}`, + endpoint: `/api/v1/saved_query/${saveQueryId}`, }) .then(({ json }) => { const queryEditorProps = { ...convertQueryToClient(json.result), + dbId: json.result?.database?.id, loaded: true, autorun: false, }; @@ -1297,7 +1440,7 @@ export function popQuery(queryId) { dbId: queryData.database.id, schema: queryData.schema, sql: queryData.sql, - title: `Copy of ${queryData.tab_name}`, + name: t('Copy of %s', queryData.tab_name), autorun: false, }; return dispatch(addQueryEditor(queryEditorProps)); @@ -1307,17 +1450,19 @@ export function popQuery(queryId) { } export function popDatasourceQuery(datasourceKey, sql) { return function (dispatch) { + const QUERY_TEXT = t('Query'); + const datasetId = datasourceKey.split('__')[0]; return SupersetClient.get({ - endpoint: `/superset/fetch_datasource_metadata?datasourceKey=${datasourceKey}`, + endpoint: `/api/v1/dataset/${datasetId}?q=(keys:!(none))`, }) .then(({ json }) => dispatch( addQueryEditor({ - title: `Query ${json.name}`, - dbId: json.database.id, - schema: json.schema, + name: `${QUERY_TEXT} ${json.result.name}`, + dbId: json.result.database.id, + schema: json.result.schema, autorun: sql !== undefined, - sql: sql || json.select_star, + sql: sql || json.result.select_star, }), ), ) @@ -1349,7 +1494,10 @@ export function createDatasource(vizOptions) { return Promise.resolve(json); }) - .catch(() => { + .catch(error => { + getClientErrorObject(error).then(e => { + dispatch(addDangerToast(e.error)); + }); dispatch( createDatasourceFailed( t('An error occurred while creating the data source'), @@ -1365,13 +1513,13 @@ export function createCtasDatasource(vizOptions) { return dispatch => { dispatch(createDatasourceStarted()); return SupersetClient.post({ - endpoint: '/superset/get_or_create_table/', - postPayload: { data: vizOptions }, + endpoint: '/api/v1/dataset/get_or_create/', + jsonPayload: vizOptions, }) .then(({ json }) => { - dispatch(createDatasourceSuccess(json)); + dispatch(createDatasourceSuccess(json.result)); - return json; + return json.result; }) .catch(() => { const errorMsg = t('An error occurred while creating the data source'); diff --git a/superset-frontend/src/SqlLab/actions/sqlLab.test.js b/superset-frontend/src/SqlLab/actions/sqlLab.test.js index 440df74bf937f..63711550b2485 100644 --- a/superset-frontend/src/SqlLab/actions/sqlLab.test.js +++ b/superset-frontend/src/SqlLab/actions/sqlLab.test.js @@ -24,7 +24,13 @@ import thunk from 'redux-thunk'; import shortid from 'shortid'; import * as featureFlags from 'src/featureFlags'; import * as actions from 'src/SqlLab/actions/sqlLab'; -import { defaultQueryEditor, query } from '../fixtures'; +import { + defaultQueryEditor, + query, + initialState, + queryId, +} from 'src/SqlLab/fixtures'; +import { QueryState } from '@superset-ui/core'; const middlewares = [thunk]; const mockStore = configureMockStore(middlewares); @@ -32,13 +38,12 @@ const mockStore = configureMockStore(middlewares); describe('async actions', () => { const mockBigNumber = '9223372036854775807'; const queryEditor = { + ...defaultQueryEditor, id: 'abcd', autorun: false, - dbId: null, latestQueryId: null, - selectedText: null, sql: 'SELECT *\nFROM\nWHERE', - title: 'Untitled Query 1', + name: 'Untitled Query 1', schemaOptions: [{ value: 'main', label: 'main', title: 'main' }], }; @@ -50,40 +55,42 @@ describe('async actions', () => { afterEach(fetchMock.resetHistory); - const fetchQueryEndpoint = 'glob:*/superset/results/*'; + const fetchQueryEndpoint = 'glob:*/api/v1/sqllab/results/*'; fetchMock.get( fetchQueryEndpoint, JSON.stringify({ data: mockBigNumber, query: { sqlEditorId: 'dfsadfs' } }), ); - const runQueryEndpoint = 'glob:*/superset/sql_json/'; + const runQueryEndpoint = 'glob:*/api/v1/sqllab/execute/'; fetchMock.post(runQueryEndpoint, `{ "data": ${mockBigNumber} }`); describe('saveQuery', () => { - const saveQueryEndpoint = 'glob:*/savedqueryviewapi/api/create'; + const saveQueryEndpoint = 'glob:*/api/v1/saved_query/'; fetchMock.post(saveQueryEndpoint, { results: { json: {} } }); const makeRequest = () => { - const request = actions.saveQuery(query); - return request(dispatch); + const request = actions.saveQuery(query, queryId); + return request(dispatch, () => initialState); }; it('posts to the correct url', () => { expect.assertions(1); - const store = mockStore({}); - return store.dispatch(actions.saveQuery(query)).then(() => { + const store = mockStore(initialState); + return store.dispatch(actions.saveQuery(query, queryId)).then(() => { expect(fetchMock.calls(saveQueryEndpoint)).toHaveLength(1); }); }); it('posts the correct query object', () => { - const store = mockStore({}); - return store.dispatch(actions.saveQuery(query)).then(() => { + const store = mockStore(initialState); + return store.dispatch(actions.saveQuery(query, queryId)).then(() => { const call = fetchMock.calls(saveQueryEndpoint)[0]; - const formData = call[1].body; - Object.keys(query).forEach(key => { - expect(formData.get(key)).toBeDefined(); + const formData = JSON.parse(call[1].body); + const mappedQueryToServer = actions.convertQueryToServer(query); + + Object.keys(mappedQueryToServer).forEach(key => { + expect(formData[key]).toBeDefined(); }); }); }); @@ -107,7 +114,7 @@ describe('async actions', () => { it('onSave calls QUERY_EDITOR_SAVED and QUERY_EDITOR_SET_TITLE', () => { expect.assertions(1); - const store = mockStore({}); + const store = mockStore(initialState); const expectedActionTypes = [ actions.QUERY_EDITOR_SAVED, actions.QUERY_EDITOR_SET_TITLE, @@ -191,7 +198,7 @@ describe('async actions', () => { describe('runQuery without query params', () => { const makeRequest = () => { const request = actions.runQuery(query); - return request(dispatch); + return request(dispatch, () => initialState); }; it('makes the fetch request', () => { @@ -224,7 +231,9 @@ describe('async actions', () => { const store = mockStore({}); const expectedActionTypes = [actions.START_QUERY, actions.QUERY_SUCCESS]; - return store.dispatch(actions.runQuery(query)).then(() => { + const { dispatch } = store; + const request = actions.runQuery(query); + return request(dispatch, () => initialState).then(() => { expect(store.getActions().map(a => a.type)).toEqual( expectedActionTypes, ); @@ -242,7 +251,9 @@ describe('async actions', () => { const store = mockStore({}); const expectedActionTypes = [actions.START_QUERY, actions.QUERY_FAILED]; - return store.dispatch(actions.runQuery(query)).then(() => { + const { dispatch } = store; + const request = actions.runQuery(query); + return request(dispatch, () => initialState).then(() => { expect(store.getActions().map(a => a.type)).toEqual( expectedActionTypes, ); @@ -265,15 +276,20 @@ describe('async actions', () => { const makeRequest = () => { const request = actions.runQuery(query); - return request(dispatch); + return request(dispatch, () => initialState); }; - it('makes the fetch request', () => - makeRequest().then(() => { - expect( - fetchMock.calls('glob:*/superset/sql_json/?foo=bar'), - ).toHaveLength(1); - })); + it('makes the fetch request', async () => { + const runQueryEndpointWithParams = + 'glob:*/api/v1/sqllab/execute/?foo=bar'; + fetchMock.post( + runQueryEndpointWithParams, + `{ "data": ${mockBigNumber} }`, + ); + await makeRequest().then(() => { + expect(fetchMock.calls(runQueryEndpointWithParams)).toHaveLength(1); + }); + }); }); describe('reRunQuery', () => { @@ -290,21 +306,27 @@ describe('async actions', () => { const state = { sqlLab: { tabHistory: [id], - queryEditors: [{ id, title: 'Dummy query editor' }], + queryEditors: [{ id, name: 'Dummy query editor' }], + unsavedQueryEditor: {}, }, }; const store = mockStore(state); - store.dispatch(actions.reRunQuery(query)); + const request = actions.reRunQuery(query); + request(store.dispatch, store.getState); expect(store.getActions()[0].query.id).toEqual('abcd'); }); }); describe('postStopQuery', () => { - const stopQueryEndpoint = 'glob:*/superset/stop_query/*'; + const stopQueryEndpoint = 'glob:*/api/v1/query/stop'; fetchMock.post(stopQueryEndpoint, {}); + const baseQuery = { + ...query, + id: 'test_foo', + }; const makeRequest = () => { - const request = actions.postStopQuery(query); + const request = actions.postStopQuery(baseQuery); return request(dispatch); }; @@ -329,7 +351,8 @@ describe('async actions', () => { return makeRequest().then(() => { const call = fetchMock.calls(stopQueryEndpoint)[0]; - expect(call[1].body.get('client_id')).toBe(query.id); + const body = JSON.parse(call[1].body); + expect(body.client_id).toBe(baseQuery.id); }); }); }); @@ -350,7 +373,8 @@ describe('async actions', () => { const state = { sqlLab: { tabHistory: [id], - queryEditors: [{ id, title: 'Dummy query editor' }], + queryEditors: [{ id, name: 'Dummy query editor' }], + unsavedQueryEditor: {}, }, }; const store = mockStore(state); @@ -358,22 +382,22 @@ describe('async actions', () => { { type: actions.ADD_QUERY_EDITOR, queryEditor: { - title: 'Copy of Dummy query editor', + name: 'Copy of Dummy query editor', dbId: 1, - schema: null, + schema: query.schema, autorun: true, sql: 'SELECT * FROM something', queryLimit: undefined, maxRow: undefined, id: 'abcd', + templateParams: undefined, }, }, ]; - return store - .dispatch(actions.cloneQueryToNewTab(query, true)) - .then(() => { - expect(store.getActions()).toEqual(expectedActions); - }); + const request = actions.cloneQueryToNewTab(query, true); + return request(store.dispatch, store.getState).then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); }); }); @@ -389,18 +413,45 @@ describe('async actions', () => { it('creates new query editor', () => { expect.assertions(1); - const store = mockStore({}); + const store = mockStore(initialState); const expectedActions = [ { type: actions.ADD_QUERY_EDITOR, queryEditor, }, ]; - return store - .dispatch(actions.addQueryEditor(defaultQueryEditor)) - .then(() => { + const request = actions.addQueryEditor(defaultQueryEditor); + return request(store.dispatch, store.getState).then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + describe('addNewQueryEditor', () => { + it('creates new query editor with new tab name', () => { + const store = mockStore(initialState); + const expectedActions = [ + { + type: actions.ADD_QUERY_EDITOR, + queryEditor: { + id: 'abcd', + sql: expect.stringContaining('SELECT ...'), + name: `Untitled Query ${ + store.getState().sqlLab.queryEditors.length + 1 + }`, + dbId: defaultQueryEditor.dbId, + schema: defaultQueryEditor.schema, + autorun: false, + queryLimit: + defaultQueryEditor.queryLimit || + initialState.common.conf.DEFAULT_SQLLAB_LIMIT, + }, + }, + ]; + const request = actions.addNewQueryEditor(); + return request(store.dispatch, store.getState).then(() => { expect(store.getActions()).toEqual(expectedActions); }); + }); }); }); @@ -464,6 +515,7 @@ describe('async actions', () => { const results = { data: mockBigNumber, query: { sqlEditorId: 'abcd' }, + status: QueryState.SUCCESS, query_id: 'efgh', }; fetchMock.get(fetchQueryEndpoint, JSON.stringify(results), { @@ -487,6 +539,35 @@ describe('async actions', () => { expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(1); }); }); + + it("doesn't update the tab state in the backend on stoppped query", () => { + expect.assertions(2); + + const results = { + status: QueryState.STOPPED, + query_id: 'efgh', + }; + fetchMock.get(fetchQueryEndpoint, JSON.stringify(results), { + overwriteRoutes: true, + }); + const store = mockStore({}); + const expectedActions = [ + { + type: actions.REQUEST_QUERY_RESULTS, + query, + }, + // missing below + { + type: actions.QUERY_SUCCESS, + query, + results, + }, + ]; + return store.dispatch(actions.fetchQueryResults(query)).then(() => { + expect(store.getActions()).toEqual(expectedActions); + expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(0); + }); + }); }); describe('addQueryEditor', () => { @@ -617,17 +698,19 @@ describe('async actions', () => { it('updates the tab state in the backend', () => { expect.assertions(2); - const title = 'title'; + const name = 'name'; const store = mockStore({}); const expectedActions = [ { type: actions.QUERY_EDITOR_SET_TITLE, queryEditor, - title, + name, }, ]; return store - .dispatch(actions.queryEditorSetTitle(queryEditor, title)) + .dispatch( + actions.queryEditorSetTitle(queryEditor, name, queryEditor.id), + ) .then(() => { expect(store.getActions()).toEqual(expectedActions); expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(1); @@ -648,14 +731,12 @@ describe('async actions', () => { it('updates the tab state in the backend', () => { expect.assertions(2); - const store = mockStore({}); - - return store - .dispatch(actions.queryEditorSetAndSaveSql(queryEditor, sql)) - .then(() => { - expect(store.getActions()).toEqual(expectedActions); - expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(1); - }); + const store = mockStore(initialState); + const request = actions.queryEditorSetAndSaveSql(queryEditor, sql); + return request(store.dispatch, store.getState).then(() => { + expect(store.getActions()).toEqual(expectedActions); + expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(1); + }); }); }); describe('with backend persistence flag off', () => { @@ -666,9 +747,9 @@ describe('async actions', () => { feature => !(feature === 'SQLLAB_BACKEND_PERSISTENCE'), ); - const store = mockStore({}); - - store.dispatch(actions.queryEditorSetAndSaveSql(queryEditor, sql)); + const store = mockStore(initialState); + const request = actions.queryEditorSetAndSaveSql(queryEditor, sql); + request(store.dispatch, store.getState); expect(store.getActions()).toEqual(expectedActions); expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(0); @@ -730,29 +811,71 @@ describe('async actions', () => { const database = { disable_data_preview: true }; const tableName = 'table'; const schemaName = 'schema'; - const store = mockStore({}); + const store = mockStore(initialState); const expectedActionTypes = [ actions.MERGE_TABLE, // addTable actions.MERGE_TABLE, // getTableMetadata actions.MERGE_TABLE, // getTableExtendedMetadata actions.MERGE_TABLE, // addTable ]; - return store - .dispatch(actions.addTable(query, database, tableName, schemaName)) - .then(() => { - expect(store.getActions().map(a => a.type)).toEqual( - expectedActionTypes, - ); - expect(store.getActions()[0].prepend).toBeTruthy(); - expect(fetchMock.calls(updateTableSchemaEndpoint)).toHaveLength(1); - expect(fetchMock.calls(getTableMetadataEndpoint)).toHaveLength(1); - expect(fetchMock.calls(getExtraTableMetadataEndpoint)).toHaveLength( - 1, - ); + const request = actions.addTable( + query, + database, + tableName, + schemaName, + ); + return request(store.dispatch, store.getState).then(() => { + expect(store.getActions().map(a => a.type)).toEqual( + expectedActionTypes, + ); + expect(store.getActions()[0].prepend).toBeTruthy(); + expect(fetchMock.calls(updateTableSchemaEndpoint)).toHaveLength(1); + expect(fetchMock.calls(getTableMetadataEndpoint)).toHaveLength(1); + expect(fetchMock.calls(getExtraTableMetadataEndpoint)).toHaveLength( + 1, + ); - // tab state is not updated, since no query was run - expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(0); - }); + // tab state is not updated, since no query was run + expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(0); + }); + }); + + it('fetches table schema state from unsaved change', () => { + const database = { disable_data_preview: true }; + const tableName = 'table'; + const schemaName = 'schema'; + const expectedDbId = 473892; + const store = mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: query.id, + dbId: expectedDbId, + }, + }, + }); + const request = actions.addTable( + query, + database, + tableName, + schemaName, + ); + return request(store.dispatch, store.getState).then(() => { + expect( + fetchMock.calls( + `glob:**/api/v1/database/${expectedDbId}/table/*/*/`, + ), + ).toHaveLength(1); + expect( + fetchMock.calls( + `glob:**/api/v1/database/${expectedDbId}/table_extra/*/*/`, + ), + ).toHaveLength(1); + + // tab state is not updated, since no query was run + expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(0); + }); }); it('updates and runs data preview query when configured', () => { @@ -770,7 +893,7 @@ describe('async actions', () => { const database = { disable_data_preview: false, id: 1 }; const tableName = 'table'; const schemaName = 'schema'; - const store = mockStore({}); + const store = mockStore(initialState); const expectedActionTypes = [ actions.MERGE_TABLE, // addTable actions.MERGE_TABLE, // getTableMetadata @@ -780,20 +903,24 @@ describe('async actions', () => { actions.MERGE_TABLE, // addTable actions.QUERY_SUCCESS, // querySuccess ]; - return store - .dispatch(actions.addTable(query, database, tableName, schemaName)) - .then(() => { - expect(store.getActions().map(a => a.type)).toEqual( - expectedActionTypes, - ); - expect(fetchMock.calls(updateTableSchemaEndpoint)).toHaveLength(1); - expect(fetchMock.calls(getTableMetadataEndpoint)).toHaveLength(1); - expect(fetchMock.calls(getExtraTableMetadataEndpoint)).toHaveLength( - 1, - ); - // tab state is not updated, since the query is a data preview - expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(0); - }); + const request = actions.addTable( + query, + database, + tableName, + schemaName, + ); + return request(store.dispatch, store.getState).then(() => { + expect(store.getActions().map(a => a.type)).toEqual( + expectedActionTypes, + ); + expect(fetchMock.calls(updateTableSchemaEndpoint)).toHaveLength(1); + expect(fetchMock.calls(getTableMetadataEndpoint)).toHaveLength(1); + expect(fetchMock.calls(getExtraTableMetadataEndpoint)).toHaveLength( + 1, + ); + // tab state is not updated, since the query is a data preview + expect(fetchMock.calls(updateTabStateEndpoint)).toHaveLength(0); + }); }); }); @@ -835,7 +962,7 @@ describe('async actions', () => { }); }); - describe('removeTable', () => { + describe('removeTables', () => { it('updates the table schema state in the backend', () => { expect.assertions(2); @@ -843,15 +970,32 @@ describe('async actions', () => { const store = mockStore({}); const expectedActions = [ { - type: actions.REMOVE_TABLE, - table, + type: actions.REMOVE_TABLES, + tables: [table], }, ]; - return store.dispatch(actions.removeTable(table)).then(() => { + return store.dispatch(actions.removeTables([table])).then(() => { expect(store.getActions()).toEqual(expectedActions); expect(fetchMock.calls(updateTableSchemaEndpoint)).toHaveLength(1); }); }); + + it('deletes multiple tables and updates the table schema state in the backend', () => { + expect.assertions(2); + + const tables = [{ id: 1 }, { id: 2 }]; + const store = mockStore({}); + const expectedActions = [ + { + type: actions.REMOVE_TABLES, + tables, + }, + ]; + return store.dispatch(actions.removeTables(tables)).then(() => { + expect(store.getActions()).toEqual(expectedActions); + expect(fetchMock.calls(updateTableSchemaEndpoint)).toHaveLength(2); + }); + }); }); describe('migrateQueryEditorFromLocalStorage', () => { diff --git a/superset-frontend/src/SqlLab/components/AceEditorWrapper/AceEditorWrapper.test.tsx b/superset-frontend/src/SqlLab/components/AceEditorWrapper/AceEditorWrapper.test.tsx new file mode 100644 index 0000000000000..7638003e9025c --- /dev/null +++ b/superset-frontend/src/SqlLab/components/AceEditorWrapper/AceEditorWrapper.test.tsx @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { render, waitFor } from 'spec/helpers/testing-library'; +import { QueryEditor } from 'src/SqlLab/types'; +import { Store } from 'redux'; +import { initialState, defaultQueryEditor } from 'src/SqlLab/fixtures'; +import AceEditorWrapper from 'src/SqlLab/components/AceEditorWrapper'; +import { AsyncAceEditorProps } from 'src/components/AsyncAceEditor'; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); + +jest.mock('src/components/DeprecatedSelect', () => () => ( + <div data-test="mock-deprecated-select" /> +)); +jest.mock('src/components/Select/Select', () => () => ( + <div data-test="mock-deprecated-select-select" /> +)); +jest.mock('src/components/Select/AsyncSelect', () => () => ( + <div data-test="mock-deprecated-async-select" /> +)); + +jest.mock('src/components/AsyncAceEditor', () => ({ + FullSQLEditor: (props: AsyncAceEditorProps) => ( + <div data-test="react-ace">{JSON.stringify(props)}</div> + ), +})); + +const setup = (queryEditor: QueryEditor, store?: Store) => + render( + <AceEditorWrapper + queryEditorId={queryEditor.id} + height="100px" + hotkeys={[]} + database={{}} + onChange={jest.fn()} + onBlur={jest.fn()} + autocomplete + />, + { + useRedux: true, + ...(store && { store }), + }, + ); + +describe('AceEditorWrapper', () => { + it('renders ace editor including sql value', async () => { + const { getByTestId } = setup(defaultQueryEditor, mockStore(initialState)); + await waitFor(() => expect(getByTestId('react-ace')).toBeInTheDocument()); + + expect(getByTestId('react-ace')).toHaveTextContent( + JSON.stringify({ value: defaultQueryEditor.sql }).slice(1, -1), + ); + }); + + it('renders current sql for unrelated unsaved changes', () => { + const expectedSql = 'SELECT updated_column\nFROM updated_table\nWHERE'; + const { getByTestId } = setup( + defaultQueryEditor, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: `${defaultQueryEditor.id}-other`, + sql: expectedSql, + }, + }, + }), + ); + + expect(getByTestId('react-ace')).not.toHaveTextContent( + JSON.stringify({ value: expectedSql }).slice(1, -1), + ); + expect(getByTestId('react-ace')).toHaveTextContent( + JSON.stringify({ value: defaultQueryEditor.sql }).slice(1, -1), + ); + }); +}); diff --git a/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx b/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx index 53ec3f808a62f..0dd3385ea57e6 100644 --- a/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx +++ b/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx @@ -16,9 +16,18 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; +import React, { useState, useEffect, useRef } from 'react'; +import { useDispatch } from 'react-redux'; +import { css, styled } from '@superset-ui/core'; + +import { usePrevious } from 'src/hooks/usePrevious'; import { areArraysShallowEqual } from 'src/reduxUtils'; import sqlKeywords from 'src/SqlLab/utils/sqlKeywords'; +import { + queryEditorSetSelectedText, + queryEditorSetFunctionNames, + addTable, +} from 'src/SqlLab/actions/sqlLab'; import { SCHEMA_AUTOCOMPLETE_SCORE, TABLE_AUTOCOMPLETE_SCORE, @@ -30,7 +39,7 @@ import { AceCompleterKeyword, FullSQLEditor as AceEditor, } from 'src/components/AsyncAceEditor'; -import { QueryEditor } from 'src/SqlLab/types'; +import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; type HotKey = { key: string; @@ -39,109 +48,123 @@ type HotKey = { func: () => void; }; -interface Props { - actions: { - queryEditorSetSelectedText: (edit: any, text: null | string) => void; - queryEditorSetFunctionNames: (queryEditor: object, dbId: number) => void; - addTable: ( - queryEditor: any, - database: any, - value: any, - schema: any, - ) => void; - }; +type AceEditorWrapperProps = { autocomplete: boolean; onBlur: (sql: string) => void; - sql: string; + onChange: (sql: string) => void; + queryEditorId: string; database: any; - schemas: any[]; - tables: any[]; - functionNames: string[]; - extendedTables: Array<{ name: string; columns: any[] }>; - queryEditor: QueryEditor; + extendedTables?: Array<{ name: string; columns: any[] }>; height: string; hotkeys: HotKey[]; - onChange: (sql: string) => void; -} - -interface State { - sql: string; - words: AceCompleterKeyword[]; -} - -class AceEditorWrapper extends React.PureComponent<Props, State> { - static defaultProps = { - onBlur: () => {}, - onChange: () => {}, - schemas: [], - tables: [], - functionNames: [], - extendedTables: [], - }; +}; - private currentSelectionCache; +const StyledAceEditor = styled(AceEditor)` + ${({ theme }) => css` + && { + // double class is better than !important + border: 1px solid ${theme.colors.grayscale.light2}; + font-feature-settings: 'liga' off, 'calt' off; + // Fira Code causes problem with Ace under Firefox + font-family: 'Menlo', 'Consolas', 'Courier New', 'Ubuntu Mono', + 'source-code-pro', 'Lucida Console', monospace; - constructor(props: Props) { - super(props); - this.state = { - sql: props.sql, - words: [], - }; + &.ace_autocomplete { + // Use !important because Ace Editor applies extra CSS at the last second + // when opening the autocomplete. + width: ${theme.gridUnit * 130}px !important; + } + + .ace_scroller { + background-color: ${theme.colors.grayscale.light4}; + } + } + `} +`; +const AceEditorWrapper = ({ + autocomplete, + onBlur = () => {}, + onChange = () => {}, + queryEditorId, + database, + extendedTables = [], + height, + hotkeys, +}: AceEditorWrapperProps) => { + const dispatch = useDispatch(); + + const queryEditor = useQueryEditor(queryEditorId, [ + 'id', + 'dbId', + 'sql', + 'functionNames', + 'schemaOptions', + 'tableOptions', + 'validationResult', + 'schema', + ]); + const currentSql = queryEditor.sql ?? ''; + const functionNames = queryEditor.functionNames ?? []; + const schemas = queryEditor.schemaOptions ?? []; + const tables = queryEditor.tableOptions ?? []; - // The editor changeSelection is called multiple times in a row, - // faster than React reconciliation process, so the selected text - // needs to be stored out of the state to ensure changes to it - // get saved immediately - this.currentSelectionCache = ''; - this.onChange = this.onChange.bind(this); - } + const [sql, setSql] = useState(currentSql); + const [words, setWords] = useState<AceCompleterKeyword[]>([]); - componentDidMount() { + // The editor changeSelection is called multiple times in a row, + // faster than React reconciliation process, so the selected text + // needs to be stored out of the state to ensure changes to it + // get saved immediately + const currentSelectionCache = useRef(''); + + useEffect(() => { // Making sure no text is selected from previous mount - this.props.actions.queryEditorSetSelectedText(this.props.queryEditor, null); - if (this.props.queryEditor.dbId) { - this.props.actions.queryEditorSetFunctionNames( - this.props.queryEditor, - this.props.queryEditor.dbId, - ); + dispatch(queryEditorSetSelectedText(queryEditor, null)); + if (queryEditor.dbId) { + dispatch(queryEditorSetFunctionNames(queryEditor, queryEditor.dbId)); } - this.setAutoCompleter(this.props); - } + setAutoCompleter(); + }, []); + + const prevTables = usePrevious(tables) ?? []; + const prevSchemas = usePrevious(schemas) ?? []; + const prevExtendedTables = usePrevious(extendedTables) ?? []; + const prevSql = usePrevious(currentSql); - UNSAFE_componentWillReceiveProps(nextProps: Props) { + useEffect(() => { if ( - !areArraysShallowEqual(this.props.tables, nextProps.tables) || - !areArraysShallowEqual(this.props.schemas, nextProps.schemas) || - !areArraysShallowEqual( - this.props.extendedTables, - nextProps.extendedTables, - ) + !areArraysShallowEqual(tables, prevTables) || + !areArraysShallowEqual(schemas, prevSchemas) || + !areArraysShallowEqual(extendedTables, prevExtendedTables) ) { - this.setAutoCompleter(nextProps); + setAutoCompleter(); } - if (nextProps.sql !== this.props.sql) { - this.setState({ sql: nextProps.sql }); + }, [tables, schemas, extendedTables]); + + useEffect(() => { + if (currentSql !== prevSql) { + setSql(currentSql); } - } + }, [currentSql]); - onBlur() { - this.props.onBlur(this.state.sql); - } + const onBlurSql = () => { + onBlur(sql); + }; - onAltEnter() { - this.props.onBlur(this.state.sql); - } + const onAltEnter = () => { + onBlur(sql); + }; - onEditorLoad(editor: any) { + const onEditorLoad = (editor: any) => { editor.commands.addCommand({ name: 'runQuery', bindKey: { win: 'Alt-enter', mac: 'Alt-enter' }, exec: () => { - this.onAltEnter(); + onAltEnter(); }, }); - this.props.hotkeys.forEach(keyConfig => { + hotkeys.forEach(keyConfig => { editor.commands.addCommand({ name: keyConfig.name, bindKey: { win: keyConfig.key, mac: keyConfig.key }, @@ -155,27 +178,23 @@ class AceEditorWrapper extends React.PureComponent<Props, State> { // Backspace trigger 1 character selection, ignoring if ( - selectedText !== this.currentSelectionCache && + selectedText !== currentSelectionCache.current && selectedText.length !== 1 ) { - this.props.actions.queryEditorSetSelectedText( - this.props.queryEditor, - selectedText, - ); + dispatch(queryEditorSetSelectedText(queryEditor, selectedText)); } - this.currentSelectionCache = selectedText; + currentSelectionCache.current = selectedText; }); - } + }; - onChange(text: string) { - this.setState({ sql: text }); - this.props.onChange(text); - } + const onChangeText = (text: string) => { + setSql(text); + onChange(text); + }; - setAutoCompleter(props: Props) { + const setAutoCompleter = () => { // Loading schema, table and column names as auto-completable words - const schemas = props.schemas || []; const schemaWords = schemas.map(s => ({ name: s.label, value: s.value, @@ -184,13 +203,10 @@ class AceEditorWrapper extends React.PureComponent<Props, State> { })); const columns = {}; - const tables = props.tables || []; - const extendedTables = props.extendedTables || []; - const tableWords = tables.map(t => { const tableName = t.value; const extendedTable = extendedTables.find(et => et.name === tableName); - const cols = (extendedTable && extendedTable.columns) || []; + const cols = extendedTable?.columns || []; cols.forEach(col => { columns[col.name] = null; // using an object as a unique set }); @@ -210,7 +226,7 @@ class AceEditorWrapper extends React.PureComponent<Props, State> { meta: 'column', })); - const functionWords = props.functionNames.map(func => ({ + const functionWords = functionNames.map(func => ({ name: func, value: func, score: SQL_FUNCTIONS_AUTOCOMPLETE_SCORE, @@ -220,11 +236,8 @@ class AceEditorWrapper extends React.PureComponent<Props, State> { const completer = { insertMatch: (editor: Editor, data: any) => { if (data.meta === 'table') { - this.props.actions.addTable( - this.props.queryEditor, - this.props.database, - data.value, - this.props.queryEditor.schema, + dispatch( + addTable(queryEditor, database, data.value, queryEditor.schema), ); } @@ -250,11 +263,11 @@ class AceEditorWrapper extends React.PureComponent<Props, State> { completer, })); - this.setState({ words }); - } + setWords(words); + }; - getAceAnnotations() { - const { validationResult } = this.props.queryEditor; + const getAceAnnotations = () => { + const { validationResult } = queryEditor; const resultIsReady = validationResult?.completed; if (resultIsReady && validationResult?.errors?.length) { const errors = validationResult.errors.map((err: any) => ({ @@ -266,24 +279,22 @@ class AceEditorWrapper extends React.PureComponent<Props, State> { return errors; } return []; - } - - render() { - return ( - <AceEditor - keywords={this.state.words} - onLoad={this.onEditorLoad.bind(this)} - onBlur={this.onBlur.bind(this)} - height={this.props.height} - onChange={this.onChange} - width="100%" - editorProps={{ $blockScrolling: true }} - enableLiveAutocompletion={this.props.autocomplete} - value={this.state.sql} - annotations={this.getAceAnnotations()} - /> - ); - } -} + }; + + return ( + <StyledAceEditor + keywords={words} + onLoad={onEditorLoad} + onBlur={onBlurSql} + height={height} + onChange={onChangeText} + width="100%" + editorProps={{ $blockScrolling: true }} + enableLiveAutocompletion={autocomplete} + value={sql} + annotations={getAceAnnotations()} + /> + ); +}; export default AceEditorWrapper; diff --git a/superset-frontend/src/SqlLab/components/App/App.test.jsx b/superset-frontend/src/SqlLab/components/App/App.test.jsx index 0629de27d5d6c..c06262915637a 100644 --- a/superset-frontend/src/SqlLab/components/App/App.test.jsx +++ b/superset-frontend/src/SqlLab/components/App/App.test.jsx @@ -19,21 +19,29 @@ import React from 'react'; import configureStore from 'redux-mock-store'; import thunk from 'redux-thunk'; - -import { shallow } from 'enzyme'; +import { render } from 'spec/helpers/testing-library'; import App from 'src/SqlLab/components/App'; -import TabbedSqlEditors from 'src/SqlLab/components/TabbedSqlEditors'; import sqlLabReducer from 'src/SqlLab/reducers/index'; +import { LOCALSTORAGE_MAX_USAGE_KB } from 'src/SqlLab/constants'; +import { LOG_EVENT } from 'src/logger/actions'; + +jest.mock('src/SqlLab/components/TabbedSqlEditors', () => () => ( + <div data-test="mock-tabbed-sql-editors" /> +)); +jest.mock('src/SqlLab/components/QueryAutoRefresh', () => () => ( + <div data-test="mock-query-auto-refresh" /> +)); describe('SqlLab App', () => { const middlewares = [thunk]; const mockStore = configureStore(middlewares); const store = mockStore(sqlLabReducer(undefined, {}), {}); - let wrapper; - beforeEach(() => { - wrapper = shallow(<App store={store} />).dive(); + jest.useFakeTimers(); + }); + afterEach(() => { + jest.useRealTimers(); }); it('is valid', () => { @@ -41,8 +49,31 @@ describe('SqlLab App', () => { }); it('should render', () => { - const inner = wrapper.dive(); - expect(inner.find('.SqlLab')).toHaveLength(1); - expect(inner.find(TabbedSqlEditors)).toHaveLength(1); + const { getByTestId } = render(<App />, { useRedux: true, store }); + expect(getByTestId('SqlLabApp')).toBeInTheDocument(); + expect(getByTestId('mock-tabbed-sql-editors')).toBeInTheDocument(); + }); + + it('logs current usage warning', async () => { + const localStorageUsageInKilobytes = LOCALSTORAGE_MAX_USAGE_KB + 10; + const storeExceedLocalStorage = mockStore( + sqlLabReducer( + { + localStorageUsageInKilobytes, + }, + {}, + ), + ); + + const { rerender } = render(<App />, { + useRedux: true, + store: storeExceedLocalStorage, + }); + rerender(<App updated />); + expect(storeExceedLocalStorage.getActions()).toContainEqual( + expect.objectContaining({ + type: LOG_EVENT, + }), + ); }); }); diff --git a/superset-frontend/src/SqlLab/components/App/index.jsx b/superset-frontend/src/SqlLab/components/App/index.jsx index 8a0ade9509ac6..4689f8ec21912 100644 --- a/superset-frontend/src/SqlLab/components/App/index.jsx +++ b/superset-frontend/src/SqlLab/components/App/index.jsx @@ -20,7 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { t } from '@superset-ui/core'; +import { css, styled, t } from '@superset-ui/core'; import throttle from 'lodash/throttle'; import ToastContainer from 'src/components/MessageToasts/ToastContainer'; import { @@ -29,9 +29,74 @@ import { LOCALSTORAGE_WARNING_MESSAGE_THROTTLE_MS, } from 'src/SqlLab/constants'; import * as Actions from 'src/SqlLab/actions/sqlLab'; +import { logEvent } from 'src/logger/actions'; +import { LOG_ACTIONS_SQLLAB_WARN_LOCAL_STORAGE_USAGE } from 'src/logger/LogUtils'; import TabbedSqlEditors from '../TabbedSqlEditors'; import QueryAutoRefresh from '../QueryAutoRefresh'; +const SqlLabStyles = styled.div` + ${({ theme }) => css` + &.SqlLab { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: 0 ${theme.gridUnit * 2}px; + + pre { + padding: 0 !important; + margin: 0; + border: none; + font-size: ${theme.typography.sizes.s}px; + background: transparent !important; + } + + .north-pane { + display: flex; + flex-direction: column; + } + + .ace_editor { + flex-grow: 1; + } + + .ace_content { + height: 100%; + } + + .ant-tabs-content-holder { + /* This is needed for Safari */ + height: 100%; + } + + .ant-tabs-content { + height: 100%; + position: relative; + background-color: ${theme.colors.grayscale.light5}; + overflow-x: auto; + overflow-y: auto; + + > .ant-tabs-tabpane { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + } + } + + .ResultsModal .ant-modal-body { + min-height: ${theme.gridUnit * 140}px; + } + + .ant-modal-body { + overflow: auto; + } + } + `}; +`; + class App extends React.PureComponent { constructor(props) { super(props); @@ -62,6 +127,7 @@ class App extends React.PureComponent { ) { this.showLocalStorageUsageWarning( this.props.localStorageUsageInKilobytes, + this.props.queries?.lenghth || 0, ); } } @@ -77,7 +143,7 @@ class App extends React.PureComponent { this.setState({ hash: window.location.hash }); } - showLocalStorageUsageWarning(currentUsage) { + showLocalStorageUsageWarning(currentUsage, queryCount) { this.props.actions.addDangerToast( t( "SQL Lab uses your browser's local storage to store queries and results." + @@ -91,18 +157,31 @@ class App extends React.PureComponent { }, ), ); + const eventData = { + current_usage: currentUsage, + query_count: queryCount, + }; + this.props.actions.logEvent( + LOG_ACTIONS_SQLLAB_WARN_LOCAL_STORAGE_USAGE, + eventData, + ); } render() { + const { queries, actions, queriesLastUpdate } = this.props; if (this.state.hash && this.state.hash === '#search') { return window.location.replace('/superset/sqllab/history/'); } return ( - <div className="App SqlLab"> - <QueryAutoRefresh /> + <SqlLabStyles data-test="SqlLabApp" className="App SqlLab"> + <QueryAutoRefresh + queries={queries} + refreshQueries={actions?.refreshQueries} + queriesLastUpdate={queriesLastUpdate} + /> <TabbedSqlEditors /> <ToastContainer /> - </div> + </SqlLabStyles> ); } } @@ -114,16 +193,18 @@ App.propTypes = { }; function mapStateToProps(state) { - const { common, localStorageUsageInKilobytes } = state; + const { common, localStorageUsageInKilobytes, sqlLab } = state; return { common, localStorageUsageInKilobytes, + queries: sqlLab?.queries, + queriesLastUpdate: sqlLab?.queriesLastUpdate, }; } function mapDispatchToProps(dispatch) { return { - actions: bindActionCreators(Actions, dispatch), + actions: bindActionCreators({ ...Actions, logEvent }, dispatch), }; } diff --git a/superset-frontend/src/SqlLab/components/ColumnElement/index.tsx b/superset-frontend/src/SqlLab/components/ColumnElement/index.tsx index 481c1067f13fc..2b341b0bd17eb 100644 --- a/superset-frontend/src/SqlLab/components/ColumnElement/index.tsx +++ b/superset-frontend/src/SqlLab/components/ColumnElement/index.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; import { ClassNames } from '@emotion/react'; -import { styled, useTheme } from '@superset-ui/core'; +import { styled, useTheme, t } from '@superset-ui/core'; import { Tooltip } from 'src/components/Tooltip'; const StyledTooltip = (props: any) => { @@ -60,9 +60,9 @@ const iconMap = { }; const tooltipTitleMap = { - pk: 'Primary key', - fk: 'Foreign key', - index: 'Index', + pk: t('Primary key'), + fk: t('Foreign key'), + index: t('Index'), }; export type ColumnKeyTypeType = keyof typeof tooltipTitleMap; diff --git a/superset-frontend/src/SqlLab/components/EstimateQueryCostButton/EstimateQueryCostButton.test.tsx b/superset-frontend/src/SqlLab/components/EstimateQueryCostButton/EstimateQueryCostButton.test.tsx new file mode 100644 index 0000000000000..5b2cae174166b --- /dev/null +++ b/superset-frontend/src/SqlLab/components/EstimateQueryCostButton/EstimateQueryCostButton.test.tsx @@ -0,0 +1,93 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { render } from 'spec/helpers/testing-library'; +import { Store } from 'redux'; +import { + initialState, + defaultQueryEditor, + extraQueryEditor1, +} from 'src/SqlLab/fixtures'; + +import EstimateQueryCostButton, { + EstimateQueryCostButtonProps, +} from 'src/SqlLab/components/EstimateQueryCostButton'; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); + +jest.mock('src/components/DeprecatedSelect', () => () => ( + <div data-test="mock-deprecated-select" /> +)); +jest.mock('src/components/Select/Select', () => () => ( + <div data-test="mock-deprecated-select-select" /> +)); +jest.mock('src/components/Select/AsyncSelect', () => () => ( + <div data-test="mock-deprecated-async-select" /> +)); + +const setup = (props: Partial<EstimateQueryCostButtonProps>, store?: Store) => + render( + <EstimateQueryCostButton + queryEditorId={defaultQueryEditor.id} + getEstimate={jest.fn()} + {...props} + />, + { + useRedux: true, + ...(store && { store }), + }, + ); + +describe('EstimateQueryCostButton', () => { + it('renders EstimateQueryCostButton', async () => { + const { queryByText } = setup({}, mockStore(initialState)); + + expect(queryByText('Estimate cost')).toBeTruthy(); + }); + + it('renders label for selected query', async () => { + const { queryByText } = setup( + { queryEditorId: extraQueryEditor1.id }, + mockStore(initialState), + ); + + expect(queryByText('Estimate selected query cost')).toBeTruthy(); + }); + + it('renders label for selected query from unsaved', async () => { + const { queryByText } = setup( + {}, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + selectedText: 'SELECT', + }, + }, + }), + ); + + expect(queryByText('Estimate selected query cost')).toBeTruthy(); + }); +}); diff --git a/superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx b/superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx index d7f2d7dd6dd43..4dd5c489582a6 100644 --- a/superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx +++ b/superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx @@ -17,30 +17,44 @@ * under the License. */ import React, { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import { css, styled, t } from '@superset-ui/core'; + import Alert from 'src/components/Alert'; -import { t } from '@superset-ui/core'; import TableView from 'src/components/TableView'; import Button from 'src/components/Button'; import Loading from 'src/components/Loading'; import ModalTrigger from 'src/components/ModalTrigger'; import { EmptyWrapperType } from 'src/components/TableView/TableView'; +import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; +import { SqlLabRootState, QueryCostEstimate } from 'src/SqlLab/types'; -interface EstimateQueryCostButtonProps { +export interface EstimateQueryCostButtonProps { getEstimate: Function; - queryCostEstimate: Record<string, any>; - selectedText?: string; + queryEditorId: string; tooltip?: string; disabled?: boolean; } +const CostEstimateModalStyles = styled.div` + ${({ theme }) => css` + font-size: ${theme.typography.sizes.s}; + `} +`; + const EstimateQueryCostButton = ({ getEstimate, - queryCostEstimate = {}, - selectedText, + queryEditorId, tooltip = '', disabled = false, }: EstimateQueryCostButtonProps) => { - const { cost } = queryCostEstimate; + const queryCostEstimate = useSelector< + SqlLabRootState, + QueryCostEstimate | undefined + >(state => state.sqlLab.queryCostEstimates?.[queryEditorId]); + + const { selectedText } = useQueryEditor(queryEditorId, ['selectedText']); + const { cost } = queryCostEstimate || {}; const tableData = useMemo(() => (Array.isArray(cost) ? cost : []), [cost]); const columns = useMemo( () => @@ -57,24 +71,25 @@ const EstimateQueryCostButton = ({ }; const renderModalBody = () => { - if (queryCostEstimate.error !== null) { + if (queryCostEstimate?.error) { return ( <Alert key="query-estimate-error" type="error" - message={queryCostEstimate.error} + message={queryCostEstimate?.error} /> ); } - if (queryCostEstimate.completed) { + if (queryCostEstimate?.completed) { return ( - <TableView - columns={columns} - data={tableData} - withPagination={false} - emptyWrapperType={EmptyWrapperType.Small} - className="cost-estimate" - /> + <CostEstimateModalStyles> + <TableView + columns={columns} + data={tableData} + withPagination={false} + emptyWrapperType={EmptyWrapperType.Small} + /> + </CostEstimateModalStyles> ); } return <Loading position="normal" />; diff --git a/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx b/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx index fbcdc15bc5a37..a4c71139c0d3c 100644 --- a/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx +++ b/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx @@ -17,19 +17,19 @@ * under the License. */ import React from 'react'; -import { useSelector } from 'react-redux'; -import { t } from '@superset-ui/core'; +import { useSelector, useDispatch } from 'react-redux'; +import { t, JsonObject } from '@superset-ui/core'; +import { + createCtasDatasource, + addInfoToast, + addDangerToast, +} from 'src/SqlLab/actions/sqlLab'; import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; import Button from 'src/components/Button'; import { exploreChart } from 'src/explore/exploreUtils'; import { SqlLabRootState } from 'src/SqlLab/types'; interface ExploreCtasResultsButtonProps { - actions: { - createCtasDatasource: Function; - addInfoToast: Function; - addDangerToast: Function; - }; table: string; schema?: string | null; dbId: number; @@ -37,26 +37,25 @@ interface ExploreCtasResultsButtonProps { } const ExploreCtasResultsButton = ({ - actions, table, schema, dbId, templateParams, }: ExploreCtasResultsButtonProps) => { - const { createCtasDatasource, addInfoToast, addDangerToast } = actions; const errorMessage = useSelector( (state: SqlLabRootState) => state.sqlLab.errorMessage, ); + const dispatch = useDispatch<(dispatch: any) => Promise<JsonObject>>(); const buildVizOptions = { - datasourceName: table, + table_name: table, schema, - dbId, - templateParams, + database_id: dbId, + template_params: templateParams, }; const visualize = () => { - createCtasDatasource(buildVizOptions) + dispatch(createCtasDatasource(buildVizOptions)) .then((data: { table_id: number }) => { const formData = { datasource: `${data.table_id}__table`, @@ -67,12 +66,14 @@ const ExploreCtasResultsButton = ({ all_columns: [], row_limit: 1000, }; - addInfoToast(t('Creating a data source and creating a new tab')); + dispatch( + addInfoToast(t('Creating a data source and creating a new tab')), + ); // open new window for data visualization exploreChart(formData); }) .catch(() => { - addDangerToast(errorMessage || t('An error occurred')); + dispatch(addDangerToast(errorMessage || t('An error occurred'))); }); }; @@ -85,7 +86,7 @@ const ExploreCtasResultsButton = ({ <InfoTooltipWithTrigger icon="line-chart" placement="top" - label="explore" + label={t('explore')} />{' '} {t('Explore')} </Button> diff --git a/superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx b/superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx index 24d5e8686f71b..b3ee748218e6c 100644 --- a/superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx +++ b/superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx @@ -39,11 +39,12 @@ const ExploreResultsButton = ({ onClick={onClick} disabled={!allowsSubquery} tooltip={t('Explore the result set in the data exploration view')} + data-test="explore-results-button" > <InfoTooltipWithTrigger icon="line-chart" placement="top" - label="explore" + label={t('explore')} />{' '} {t('Create Chart')} </Button> diff --git a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.jsx b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.jsx deleted file mode 100644 index 06bf187e1185a..0000000000000 --- a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.jsx +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import { shallow } from 'enzyme'; -import sinon from 'sinon'; -import thunk from 'redux-thunk'; -import configureStore from 'redux-mock-store'; -import QueryAutoRefresh from 'src/SqlLab/components/QueryAutoRefresh'; -import { initialState, runningQuery } from 'src/SqlLab/fixtures'; - -describe('QueryAutoRefresh', () => { - const middlewares = [thunk]; - const mockStore = configureStore(middlewares); - const sqlLab = { - ...initialState.sqlLab, - queries: { - ryhMUZCGb: runningQuery, - }, - }; - const state = { - ...initialState, - sqlLab, - }; - const store = mockStore(state); - const getWrapper = () => - shallow(<QueryAutoRefresh store={store} />) - .dive() - .dive(); - let wrapper; - - it('shouldCheckForQueries', () => { - wrapper = getWrapper(); - expect(wrapper.instance().shouldCheckForQueries()).toBe(true); - }); - - it('setUserOffline', () => { - wrapper = getWrapper(); - const spy = sinon.spy(wrapper.instance().props.actions, 'setUserOffline'); - - // state not changed - wrapper.setState({ - offline: false, - }); - expect(spy.called).toBe(false); - - // state is changed - wrapper.setState({ - offline: true, - }); - expect(spy.callCount).toBe(1); - }); -}); diff --git a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.tsx b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.tsx new file mode 100644 index 0000000000000..32bf401f22139 --- /dev/null +++ b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.tsx @@ -0,0 +1,133 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render } from '@testing-library/react'; +import QueryAutoRefresh, { + isQueryRunning, + shouldCheckForQueries, +} from 'src/SqlLab/components/QueryAutoRefresh'; +import { successfulQuery, runningQuery } from 'src/SqlLab/fixtures'; +import { QueryDictionary } from 'src/SqlLab/types'; + +// NOTE: The uses of @ts-ignore in this file is to enable testing of bad inputs to verify the +// function / component handles bad data elegantly +describe('QueryAutoRefresh', () => { + const runningQueries: QueryDictionary = {}; + runningQueries[runningQuery.id] = runningQuery; + + const successfulQueries: QueryDictionary = {}; + successfulQueries[successfulQuery.id] = successfulQuery; + + const refreshQueries = jest.fn(); + + const queriesLastUpdate = Date.now(); + + it('isQueryRunning returns true for valid running query', () => { + const running = isQueryRunning(runningQuery); + expect(running).toBe(true); + }); + + it('isQueryRunning returns false for valid not-running query', () => { + const running = isQueryRunning(successfulQuery); + expect(running).toBe(false); + }); + + it('isQueryRunning returns false for invalid query', () => { + // @ts-ignore + let running = isQueryRunning(null); + expect(running).toBe(false); + // @ts-ignore + running = isQueryRunning(undefined); + expect(running).toBe(false); + // @ts-ignore + running = isQueryRunning('I Should Be An Object'); + expect(running).toBe(false); + // @ts-ignore + running = isQueryRunning({ state: { badFormat: true } }); + expect(running).toBe(false); + }); + + it('shouldCheckForQueries is true for valid running query', () => { + expect(shouldCheckForQueries(runningQueries)).toBe(true); + }); + + it('shouldCheckForQueries is false for valid completed query', () => { + expect(shouldCheckForQueries(successfulQueries)).toBe(false); + }); + + it('shouldCheckForQueries is false for invalid inputs', () => { + // @ts-ignore + expect(shouldCheckForQueries(null)).toBe(false); + // @ts-ignore + expect(shouldCheckForQueries(undefined)).toBe(false); + expect( + // @ts-ignore + shouldCheckForQueries({ + // @ts-ignore + '1234': null, + // @ts-ignore + '23425': 'hello world', + // @ts-ignore + '345': [], + // @ts-ignore + '57346': undefined, + }), + ).toBe(false); + }); + + it('Attempts to refresh when given pending query', () => { + render( + <QueryAutoRefresh + queries={runningQueries} + refreshQueries={refreshQueries} + queriesLastUpdate={queriesLastUpdate} + />, + ); + setTimeout(() => { + expect(refreshQueries).toHaveBeenCalled(); + }, 1000); + }); + + it('Does not fail and attempts to refresh when given pending query and invlaid query', () => { + render( + <QueryAutoRefresh + // @ts-ignore + queries={{ ...runningQueries, g324t: null }} + refreshQueries={refreshQueries} + queriesLastUpdate={queriesLastUpdate} + />, + ); + setTimeout(() => { + expect(refreshQueries).toHaveBeenCalled(); + }, 1000); + }); + + it('Does NOT Attempt to refresh when given only completed queries', () => { + render( + <QueryAutoRefresh + queries={successfulQueries} + refreshQueries={refreshQueries} + queriesLastUpdate={queriesLastUpdate} + />, + ); + setTimeout(() => { + expect(refreshQueries).not.toHaveBeenCalled(); + }, 1000); + }); +}); diff --git a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.jsx b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.jsx deleted file mode 100644 index b54936b691efe..0000000000000 --- a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.jsx +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { SupersetClient } from '@superset-ui/core'; -import * as Actions from 'src/SqlLab/actions/sqlLab'; - -const QUERY_UPDATE_FREQ = 2000; -const QUERY_UPDATE_BUFFER_MS = 5000; -const MAX_QUERY_AGE_TO_POLL = 21600000; -const QUERY_TIMEOUT_LIMIT = 10000; - -class QueryAutoRefresh extends React.PureComponent { - constructor(props) { - super(props); - this.state = { - offline: props.offline, - }; - } - - UNSAFE_componentWillMount() { - this.startTimer(); - } - - componentDidUpdate(prevProps) { - if (prevProps.offline !== this.state.offline) { - this.props.actions.setUserOffline(this.state.offline); - } - } - - componentWillUnmount() { - this.stopTimer(); - } - - shouldCheckForQueries() { - // if there are started or running queries, this method should return true - const { queries } = this.props; - const now = new Date().getTime(); - const isQueryRunning = q => - ['running', 'started', 'pending', 'fetching'].indexOf(q.state) >= 0; - - return Object.values(queries).some( - q => isQueryRunning(q) && now - q.startDttm < MAX_QUERY_AGE_TO_POLL, - ); - } - - startTimer() { - if (!this.timer) { - this.timer = setInterval(this.stopwatch.bind(this), QUERY_UPDATE_FREQ); - } - } - - stopTimer() { - clearInterval(this.timer); - this.timer = null; - } - - stopwatch() { - // only poll /superset/queries/ if there are started or running queries - if (this.shouldCheckForQueries()) { - SupersetClient.get({ - endpoint: `/superset/queries/${ - this.props.queriesLastUpdate - QUERY_UPDATE_BUFFER_MS - }`, - timeout: QUERY_TIMEOUT_LIMIT, - }) - .then(({ json }) => { - if (Object.keys(json).length > 0) { - this.props.actions.refreshQueries(json); - } - this.setState({ offline: false }); - }) - .catch(() => { - this.setState({ offline: true }); - }); - } else { - this.setState({ offline: false }); - } - } - - render() { - return null; - } -} -QueryAutoRefresh.propTypes = { - offline: PropTypes.bool.isRequired, - queries: PropTypes.object.isRequired, - actions: PropTypes.object.isRequired, - queriesLastUpdate: PropTypes.number.isRequired, -}; - -function mapStateToProps({ sqlLab }) { - return { - offline: sqlLab.offline, - queries: sqlLab.queries, - queriesLastUpdate: sqlLab.queriesLastUpdate, - }; -} - -function mapDispatchToProps(dispatch) { - return { - actions: bindActionCreators(Actions, dispatch), - }; -} - -export default connect(mapStateToProps, mapDispatchToProps)(QueryAutoRefresh); diff --git a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.tsx b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.tsx new file mode 100644 index 0000000000000..2d01e724e2479 --- /dev/null +++ b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.tsx @@ -0,0 +1,110 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useState } from 'react'; +import { isObject } from 'lodash'; +import rison from 'rison'; +import { + SupersetClient, + Query, + runningQueryStateList, + QueryResponse, +} from '@superset-ui/core'; +import { QueryDictionary } from 'src/SqlLab/types'; +import useInterval from 'src/SqlLab/utils/useInterval'; + +const QUERY_UPDATE_FREQ = 2000; +const QUERY_UPDATE_BUFFER_MS = 5000; +const MAX_QUERY_AGE_TO_POLL = 21600000; +const QUERY_TIMEOUT_LIMIT = 10000; + +interface RefreshQueriesFunc { + (alteredQueries: any): any; +} + +export interface QueryAutoRefreshProps { + queries: QueryDictionary; + refreshQueries: RefreshQueriesFunc; + queriesLastUpdate: number; +} + +// returns true if the Query.state matches one of the specifc values indicating the query is still processing on server +export const isQueryRunning = (q: Query): boolean => + runningQueryStateList.includes(q?.state); + +// returns true if at least one query is running and within the max age to poll timeframe +export const shouldCheckForQueries = (queryList: QueryDictionary): boolean => { + let shouldCheck = false; + const now = Date.now(); + if (isObject(queryList)) { + shouldCheck = Object.values(queryList).some( + q => isQueryRunning(q) && now - q?.startDttm < MAX_QUERY_AGE_TO_POLL, + ); + } + return shouldCheck; +}; + +function QueryAutoRefresh({ + queries, + refreshQueries, + queriesLastUpdate, +}: QueryAutoRefreshProps) { + // We do not want to spam requests in the case of slow connections and potentially receive responses out of order + // pendingRequest check ensures we only have one active http call to check for query statuses + const [pendingRequest, setPendingRequest] = useState(false); + + const checkForRefresh = () => { + if (!pendingRequest && shouldCheckForQueries(queries)) { + const params = rison.encode({ + last_updated_ms: queriesLastUpdate - QUERY_UPDATE_BUFFER_MS, + }); + + setPendingRequest(true); + SupersetClient.get({ + endpoint: `/api/v1/query/updated_since?q=${params}`, + timeout: QUERY_TIMEOUT_LIMIT, + }) + .then(({ json }) => { + if (json) { + const jsonPayload = json as { result?: QueryResponse[] }; + const queries = + jsonPayload?.result?.reduce((acc, current) => { + acc[current.id] = current; + return acc; + }, {}) ?? {}; + refreshQueries?.(queries); + } + }) + .catch(() => {}) + .finally(() => { + setPendingRequest(false); + }); + } + }; + + // Solves issue where direct usage of setInterval in function components + // uses stale props / state from closure + // See comments in the useInterval.ts file for more information + useInterval(() => { + checkForRefresh(); + }, QUERY_UPDATE_FREQ); + + return null; +} + +export default QueryAutoRefresh; diff --git a/superset-frontend/src/SqlLab/components/QueryHistory/QueryHistory.test.tsx b/superset-frontend/src/SqlLab/components/QueryHistory/QueryHistory.test.tsx index 8d25fca910124..6fd84a0d2a290 100644 --- a/superset-frontend/src/SqlLab/components/QueryHistory/QueryHistory.test.tsx +++ b/superset-frontend/src/SqlLab/components/QueryHistory/QueryHistory.test.tsx @@ -20,16 +20,8 @@ import React from 'react'; import { render, screen } from 'spec/helpers/testing-library'; import QueryHistory from 'src/SqlLab/components/QueryHistory'; -const NOOP = () => {}; const mockedProps = { queries: [], - actions: { - queryEditorSetAndSaveSql: NOOP, - cloneQueryToNewTab: NOOP, - fetchQueryResults: NOOP, - clearQueryResults: NOOP, - removeQuery: NOOP, - }, displayLimit: 1000, latestQueryId: 'yhMUZCGb', }; diff --git a/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx b/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx index 86f28069209da..cab1160144a3d 100644 --- a/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx +++ b/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx @@ -23,13 +23,6 @@ import QueryTable from 'src/SqlLab/components/QueryTable'; interface QueryHistoryProps { queries: QueryResponse[]; - actions: { - queryEditorSetAndSaveSql: Function; - cloneQueryToNewTab: Function; - fetchQueryResults: Function; - clearQueryResults: Function; - removeQuery: Function; - }; displayLimit: number; latestQueryId: string | undefined; } @@ -47,7 +40,6 @@ const StyledEmptyStateWrapper = styled.div` const QueryHistory = ({ queries, - actions, displayLimit, latestQueryId, }: QueryHistoryProps) => @@ -64,7 +56,6 @@ const QueryHistory = ({ 'actions', ]} queries={queries} - actions={actions} displayLimit={displayLimit} latestQueryId={latestQueryId} /> diff --git a/superset-frontend/src/SqlLab/components/QueryLimitSelect/QueryLimitSelect.test.tsx b/superset-frontend/src/SqlLab/components/QueryLimitSelect/QueryLimitSelect.test.tsx new file mode 100644 index 0000000000000..adf0780e32043 --- /dev/null +++ b/superset-frontend/src/SqlLab/components/QueryLimitSelect/QueryLimitSelect.test.tsx @@ -0,0 +1,144 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { Store } from 'redux'; + +import { render, fireEvent, waitFor } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { initialState, defaultQueryEditor } from 'src/SqlLab/fixtures'; +import QueryLimitSelect, { + LIMIT_DROPDOWN, + QueryLimitSelectProps, + convertToNumWithSpaces, +} from 'src/SqlLab/components/QueryLimitSelect'; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); + +jest.mock('src/components/DeprecatedSelect', () => () => ( + <div data-test="mock-deprecated-select" /> +)); +jest.mock('src/components/Select/Select', () => () => ( + <div data-test="mock-deprecated-select-select" /> +)); +jest.mock('src/components/Select/AsyncSelect', () => () => ( + <div data-test="mock-deprecated-async-select" /> +)); + +const defaultQueryLimit = 100; + +const setup = (props?: Partial<QueryLimitSelectProps>, store?: Store) => + render( + <QueryLimitSelect + queryEditorId={defaultQueryEditor.id} + maxRow={100000} + defaultQueryLimit={defaultQueryLimit} + {...props} + />, + { + useRedux: true, + ...(store && { store }), + }, + ); + +describe('QueryLimitSelect', () => { + it('renders current query limit size', () => { + const queryLimit = 10; + const { getByText } = setup( + { + queryEditorId: defaultQueryEditor.id, + }, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + queryEditors: [ + { + ...defaultQueryEditor, + queryLimit, + }, + ], + }, + }), + ); + expect(getByText(queryLimit)).toBeInTheDocument(); + }); + + it('renders default query limit for initial queryEditor', () => { + const { getByText } = setup({}, mockStore(initialState)); + expect(getByText(defaultQueryLimit)).toBeInTheDocument(); + }); + + it('renders queryLimit from unsavedQueryEditor', () => { + const queryLimit = 10000; + const { getByText } = setup( + {}, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + queryLimit, + }, + }, + }), + ); + expect(getByText(convertToNumWithSpaces(queryLimit))).toBeInTheDocument(); + }); + + it('renders dropdown select', async () => { + const { baseElement, getByRole } = setup({}, mockStore(initialState)); + const dropdown = baseElement.getElementsByClassName( + 'ant-dropdown-trigger', + )[0]; + + userEvent.click(dropdown); + await waitFor(() => expect(getByRole('menu')).toBeInTheDocument()); + }); + + it('dispatches QUERY_EDITOR_SET_QUERY_LIMIT action on dropdown menu click', async () => { + const store = mockStore(initialState); + const expectedIndex = 1; + const { baseElement, getAllByRole, getByRole } = setup({}, store); + const dropdown = baseElement.getElementsByClassName( + 'ant-dropdown-trigger', + )[0]; + + userEvent.click(dropdown); + await waitFor(() => expect(getByRole('menu')).toBeInTheDocument()); + + const menu = getAllByRole('menuitem')[expectedIndex]; + expect(store.getActions()).toEqual([]); + fireEvent.click(menu); + await waitFor(() => + expect(store.getActions()).toEqual([ + { + type: 'QUERY_EDITOR_SET_QUERY_LIMIT', + queryLimit: LIMIT_DROPDOWN[expectedIndex], + queryEditor: { + id: defaultQueryEditor.id, + }, + }, + ]), + ); + }); +}); diff --git a/superset-frontend/src/SqlLab/components/QueryLimitSelect/index.tsx b/superset-frontend/src/SqlLab/components/QueryLimitSelect/index.tsx new file mode 100644 index 0000000000000..44e180bb274ac --- /dev/null +++ b/superset-frontend/src/SqlLab/components/QueryLimitSelect/index.tsx @@ -0,0 +1,112 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { useDispatch } from 'react-redux'; +import { styled, useTheme, t } from '@superset-ui/core'; +import { AntdDropdown } from 'src/components'; +import { Menu } from 'src/components/Menu'; +import Icons from 'src/components/Icons'; +import { queryEditorSetQueryLimit } from 'src/SqlLab/actions/sqlLab'; +import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; + +export interface QueryLimitSelectProps { + queryEditorId: string; + maxRow: number; + defaultQueryLimit: number; +} + +export const LIMIT_DROPDOWN = [10, 100, 1000, 10000, 100000]; + +export function convertToNumWithSpaces(num: number) { + return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1 '); +} + +const LimitSelectStyled = styled.span` + ${({ theme }) => ` + .ant-dropdown-trigger { + align-items: center; + color: ${theme.colors.grayscale.dark2}; + display: flex; + font-size: 12px; + margin-right: ${theme.gridUnit * 2}px; + text-decoration: none; + border: 0; + background: transparent; + span { + display: inline-block; + margin-right: ${theme.gridUnit * 2}px; + &:last-of-type: { + margin-right: ${theme.gridUnit * 4}px; + } + } + } + `} +`; + +function renderQueryLimit( + maxRow: number, + setQueryLimit: (limit: number) => void, +) { + // Adding SQL_MAX_ROW value to dropdown + LIMIT_DROPDOWN.push(maxRow); + + return ( + <Menu> + {[...new Set(LIMIT_DROPDOWN)].map(limit => ( + <Menu.Item key={`${limit}`} onClick={() => setQueryLimit(limit)}> + {/* // eslint-disable-line no-use-before-define */} + <a role="button">{convertToNumWithSpaces(limit)}</a>{' '} + </Menu.Item> + ))} + </Menu> + ); +} + +const QueryLimitSelect = ({ + queryEditorId, + maxRow, + defaultQueryLimit, +}: QueryLimitSelectProps) => { + const theme = useTheme(); + const dispatch = useDispatch(); + + const queryEditor = useQueryEditor(queryEditorId, ['id', 'queryLimit']); + const queryLimit = queryEditor.queryLimit || defaultQueryLimit; + const setQueryLimit = (updatedQueryLimit: number) => + dispatch(queryEditorSetQueryLimit(queryEditor, updatedQueryLimit)); + + return ( + <LimitSelectStyled> + <AntdDropdown + overlay={renderQueryLimit(maxRow, setQueryLimit)} + trigger={['click']} + > + <button type="button" onClick={e => e.preventDefault()}> + <span>{t('LIMIT')}:</span> + <span className="limitDropdown"> + {convertToNumWithSpaces(queryLimit)} + </span> + <Icons.TriangleDown iconColor={theme.colors.grayscale.base} /> + </button> + </AntdDropdown> + </LimitSelectStyled> + ); +}; + +export default QueryLimitSelect; diff --git a/superset-frontend/src/SqlLab/components/QuerySearch/QuerySearch.test.jsx b/superset-frontend/src/SqlLab/components/QuerySearch/QuerySearch.test.jsx deleted file mode 100644 index a1efdc06c02e6..0000000000000 --- a/superset-frontend/src/SqlLab/components/QuerySearch/QuerySearch.test.jsx +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import thunk from 'redux-thunk'; -import configureStore from 'redux-mock-store'; -import fetchMock from 'fetch-mock'; -import QuerySearch from 'src/SqlLab/components/QuerySearch'; -import { Provider } from 'react-redux'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; -import { fireEvent, render, screen, act } from '@testing-library/react'; -import '@testing-library/jest-dom/extend-expect'; -import userEvent from '@testing-library/user-event'; -import { user } from 'src/SqlLab/fixtures'; - -const mockStore = configureStore([thunk]); -const store = mockStore({ - sqlLab: user, -}); - -const SEARCH_ENDPOINT = 'glob:*/superset/search_queries?*'; -const USER_ENDPOINT = 'glob:*/api/v1/query/related/user'; -const DATABASE_ENDPOINT = 'glob:*/api/v1/database/?*'; - -fetchMock.get(SEARCH_ENDPOINT, []); -fetchMock.get(USER_ENDPOINT, []); -fetchMock.get(DATABASE_ENDPOINT, []); - -describe('QuerySearch', () => { - const mockedProps = { - actions: { addDangerToast: jest.fn() }, - displayLimit: 50, - }; - - it('is valid', () => { - expect( - React.isValidElement( - <ThemeProvider theme={supersetTheme}> - <Provider store={store}> - <QuerySearch {...mockedProps} /> - </Provider> - </ThemeProvider>, - ), - ).toBe(true); - }); - - beforeEach(async () => { - // You need this await function in order to change state in the app. In fact you need it everytime you re-render. - await act(async () => { - render( - <ThemeProvider theme={supersetTheme}> - <Provider store={store}> - <QuerySearch {...mockedProps} /> - </Provider> - </ThemeProvider>, - ); - }); - }); - - it('should have three Selects', () => { - expect(screen.getByText(/28 days ago/i)).toBeInTheDocument(); - expect(screen.getByText(/now/i)).toBeInTheDocument(); - expect(screen.getByText(/success/i)).toBeInTheDocument(); - }); - - it('updates fromTime on user selects from time', () => { - const role = screen.getByText(/28 days ago/i); - fireEvent.keyDown(role, { key: 'ArrowDown', keyCode: 40 }); - userEvent.click(screen.getByText(/1 hour ago/i)); - expect(screen.getByText(/1 hour ago/i)).toBeInTheDocument(); - }); - - it('updates toTime on user selects on time', () => { - const role = screen.getByText(/now/i); - fireEvent.keyDown(role, { key: 'ArrowDown', keyCode: 40 }); - userEvent.click(screen.getByText(/1 hour ago/i)); - expect(screen.getByText(/1 hour ago/i)).toBeInTheDocument(); - }); - - it('updates status on user selects status', () => { - const role = screen.getByText(/success/i); - fireEvent.keyDown(role, { key: 'ArrowDown', keyCode: 40 }); - userEvent.click(screen.getByText(/failed/i)); - expect(screen.getByText(/failed/i)).toBeInTheDocument(); - }); - - it('should have one input for searchText', () => { - expect( - screen.getByPlaceholderText(/Query search string/i), - ).toBeInTheDocument(); - }); - - it('updates search text on user inputs search text', () => { - const search = screen.getByPlaceholderText(/Query search string/i); - userEvent.type(search, 'text'); - expect(search.value).toBe('text'); - }); - - it('should have one Button', () => { - const button = screen.getAllByRole('button'); - expect(button.length).toEqual(1); - }); - - it('should call API when search button is pressed', async () => { - fetchMock.resetHistory(); - const button = screen.getByRole('button'); - await act(async () => { - userEvent.click(button); - }); - expect(fetchMock.calls(SEARCH_ENDPOINT)).toHaveLength(1); - }); - - it('should call API when (only)enter key is pressed', async () => { - fetchMock.resetHistory(); - const search = screen.getByPlaceholderText(/Query search string/i); - await act(async () => { - userEvent.type(search, 'a'); - }); - expect(fetchMock.calls(SEARCH_ENDPOINT)).toHaveLength(0); - await act(async () => { - userEvent.type(search, '{enter}'); - }); - expect(fetchMock.calls(SEARCH_ENDPOINT)).toHaveLength(1); - }); -}); diff --git a/superset-frontend/src/SqlLab/components/QuerySearch/index.tsx b/superset-frontend/src/SqlLab/components/QuerySearch/index.tsx deleted file mode 100644 index 635603e255f14..0000000000000 --- a/superset-frontend/src/SqlLab/components/QuerySearch/index.tsx +++ /dev/null @@ -1,292 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React, { useState, useEffect } from 'react'; -import Button from 'src/components/Button'; -import Select from 'src/components/Select'; -import { styled, t, SupersetClient, QueryResponse } from '@superset-ui/core'; -import { debounce } from 'lodash'; -import Loading from 'src/components/Loading'; -import { - now, - epochTimeXHoursAgo, - epochTimeXDaysAgo, - epochTimeXYearsAgo, -} from 'src/utils/dates'; -import AsyncSelect from 'src/components/AsyncSelect'; -import { STATUS_OPTIONS, TIME_OPTIONS } from 'src/SqlLab/constants'; -import QueryTable from '../QueryTable'; - -interface QuerySearchProps { - actions: { - addDangerToast: (msg: string) => void; - setDatabases: (data: Record<string, any>) => Record<string, any>; - queryEditorSetAndSaveSql: Function; - cloneQueryToNewTab: Function; - fetchQueryResults: Function; - clearQueryResults: Function; - removeQuery: Function; - }; - displayLimit: number; -} - -interface UserMutatorProps { - value: number; - text: string; -} - -interface DbMutatorProps { - id: number; - database_name: string; -} - -const TableWrapper = styled.div` - display: flex; - flex-direction: column; - flex: 1; - height: 100%; -`; - -const TableStyles = styled.div` - table { - background-color: ${({ theme }) => theme.colors.grayscale.light4}; - } - - .table > thead > tr > th { - border-bottom: ${({ theme }) => theme.gridUnit / 2}px solid - ${({ theme }) => theme.colors.grayscale.light2}; - background: ${({ theme }) => theme.colors.grayscale.light4}; - } -`; - -const StyledTableStylesContainer = styled.div` - overflow: auto; -`; -function QuerySearch({ actions, displayLimit }: QuerySearchProps) { - const [databaseId, setDatabaseId] = useState<string>(''); - const [userId, setUserId] = useState<string>(''); - const [searchText, setSearchText] = useState<string>(''); - const [from, setFrom] = useState<string>('28 days ago'); - const [to, setTo] = useState<string>('now'); - const [status, setStatus] = useState<string>('success'); - const [queriesArray, setQueriesArray] = useState<QueryResponse[]>([]); - const [queriesLoading, setQueriesLoading] = useState<boolean>(true); - - const getTimeFromSelection = (selection: string) => { - switch (selection) { - case 'now': - return now(); - case '1 hour ago': - return epochTimeXHoursAgo(1); - case '1 day ago': - return epochTimeXDaysAgo(1); - case '7 days ago': - return epochTimeXDaysAgo(7); - case '28 days ago': - return epochTimeXDaysAgo(28); - case '90 days ago': - return epochTimeXDaysAgo(90); - case '1 year ago': - return epochTimeXYearsAgo(1); - default: - return null; - } - }; - - const insertParams = (baseUrl: string, params: string[]) => { - const validParams = params.filter(function (p) { - return p !== ''; - }); - return `${baseUrl}?${validParams.join('&')}`; - }; - - const refreshQueries = async () => { - setQueriesLoading(true); - const params = [ - userId && `user_id=${userId}`, - databaseId && `database_id=${databaseId}`, - searchText && `search_text=${searchText}`, - status && `status=${status}`, - from && `from=${getTimeFromSelection(from)}`, - to && `to=${getTimeFromSelection(to)}`, - ]; - - try { - const response = await SupersetClient.get({ - endpoint: insertParams('/superset/search_queries', params), - }); - const queries = Object.values(response.json); - setQueriesArray(queries); - } catch (err) { - actions.addDangerToast(t('An error occurred when refreshing queries')); - } finally { - setQueriesLoading(false); - } - }; - useEffect(() => { - refreshQueries(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const onUserClicked = (userId: string) => { - setUserId(userId); - refreshQueries(); - }; - - const onDbClicked = (dbId: string) => { - setDatabaseId(dbId); - refreshQueries(); - }; - - const onKeyDown = (event: React.KeyboardEvent) => { - if (event.keyCode === 13) { - refreshQueries(); - } - }; - - const onChange = (e: React.ChangeEvent) => { - e.persist(); - const handleChange = debounce(e => { - setSearchText(e.target.value); - }, 200); - handleChange(e); - }; - - const userMutator = ({ result }: { result: UserMutatorProps[] }) => - result.map(({ value, text }: UserMutatorProps) => ({ - label: text, - value, - })); - - const dbMutator = ({ result }: { result: DbMutatorProps[] }) => { - const options = result.map(({ id, database_name }: DbMutatorProps) => ({ - value: id, - label: database_name, - })); - actions.setDatabases(result); - if (result.length === 0) { - actions.addDangerToast( - t("It seems you don't have access to any database"), - ); - } - return options; - }; - - return ( - <TableWrapper> - <div id="search-header" className="row space-1"> - <div className="col-sm-2"> - <AsyncSelect - dataEndpoint="api/v1/query/related/user" - mutator={userMutator} - value={userId} - onChange={(selected: any) => setUserId(selected?.value)} - placeholder={t('Filter by user')} - /> - </div> - <div className="col-sm-2"> - <AsyncSelect - onChange={(db: any) => setDatabaseId(db?.value)} - dataEndpoint="/api/v1/database/?q=(filters:!((col:expose_in_sqllab,opr:eq,value:!t)))" - value={databaseId} - mutator={dbMutator} - placeholder={t('Filter by database')} - /> - </div> - <div className="col-sm-4"> - <input - type="text" - onChange={onChange} - onKeyDown={onKeyDown} - className="form-control input-sm" - placeholder={t('Query search string')} - /> - </div> - <div className="col-sm-4 search-date-filter-container"> - <Select - name="select-from" - placeholder={t('[From]-')} - options={TIME_OPTIONS.slice(1, TIME_OPTIONS.length).map(xt => ({ - value: xt, - label: xt, - }))} - value={{ value: from, label: from }} - autosize={false} - onChange={(selected: any) => setFrom(selected?.value)} - /> - - <Select - name="select-to" - placeholder={t('[To]-')} - options={TIME_OPTIONS.map(xt => ({ value: xt, label: xt }))} - value={{ value: to, label: to }} - autosize={false} - onChange={(selected: any) => setTo(selected?.value)} - /> - - <Select - name="select-status" - placeholder={t('Filter by status')} - options={Object.keys(STATUS_OPTIONS).map(s => ({ - value: s, - label: s, - }))} - value={{ value: status, label: status }} - isLoading={false} - autosize={false} - onChange={(selected: any) => setStatus(selected?.value)} - /> - - <Button - buttonSize="small" - buttonStyle="success" - onClick={refreshQueries} - > - {t('Search')} - </Button> - </div> - </div> - <StyledTableStylesContainer> - {queriesLoading ? ( - <Loading /> - ) : ( - <TableStyles> - <QueryTable - columns={[ - 'state', - 'db', - 'user', - 'time', - 'progress', - 'rows', - 'sql', - 'querylink', - ]} - onUserClicked={onUserClicked} - onDbClicked={onDbClicked} - queries={queriesArray} - actions={actions} - displayLimit={displayLimit} - /> - </TableStyles> - )} - </StyledTableStylesContainer> - </TableWrapper> - ); -} -export default QuerySearch; diff --git a/superset-frontend/src/SqlLab/components/QueryStateLabel/QueryStateLabel.test.jsx b/superset-frontend/src/SqlLab/components/QueryStateLabel/QueryStateLabel.test.jsx index a53225d96abcd..a14e08a9fe722 100644 --- a/superset-frontend/src/SqlLab/components/QueryStateLabel/QueryStateLabel.test.jsx +++ b/superset-frontend/src/SqlLab/components/QueryStateLabel/QueryStateLabel.test.jsx @@ -17,8 +17,7 @@ * under the License. */ import React from 'react'; -import { shallow } from 'enzyme'; - +import { styledMount as mount } from 'spec/helpers/theming'; import Label from 'src/components/Label'; import QueryStateLabel from 'src/SqlLab/components/QueryStateLabel'; @@ -34,7 +33,7 @@ describe('SavedQuery', () => { ); }); it('has an Overlay and a Popover', () => { - const wrapper = shallow(<QueryStateLabel {...mockedProps} />); + const wrapper = mount(<QueryStateLabel {...mockedProps} />); expect(wrapper.find(Label)).toExist(); }); }); diff --git a/superset-frontend/src/SqlLab/components/QueryStateLabel/index.tsx b/superset-frontend/src/SqlLab/components/QueryStateLabel/index.tsx index 6168a2af713a4..0ae092ef5efe3 100644 --- a/superset-frontend/src/SqlLab/components/QueryStateLabel/index.tsx +++ b/superset-frontend/src/SqlLab/components/QueryStateLabel/index.tsx @@ -18,17 +18,21 @@ */ import React from 'react'; import Label from 'src/components/Label'; -import { STATE_TYPE_MAP } from 'src/SqlLab/constants'; -import { Query } from '@superset-ui/core'; +import { STATE_TYPE_MAP, STATE_TYPE_MAP_LOCALIZED } from 'src/SqlLab/constants'; +import { styled, Query } from '@superset-ui/core'; interface QueryStateLabelProps { query: Query; } +const StyledLabel = styled(Label)` + margin-right: ${({ theme }) => theme.gridUnit}px; +`; + export default function QueryStateLabel({ query }: QueryStateLabelProps) { return ( - <Label className="m-r-3" type={STATE_TYPE_MAP[query.state]}> - {query.state} - </Label> + <StyledLabel type={STATE_TYPE_MAP[query.state]}> + {STATE_TYPE_MAP_LOCALIZED[query.state]} + </StyledLabel> ); } diff --git a/superset-frontend/src/SqlLab/components/QueryTable/QueryTable.test.jsx b/superset-frontend/src/SqlLab/components/QueryTable/QueryTable.test.jsx index f77e631ae2f5c..76784695a8140 100644 --- a/superset-frontend/src/SqlLab/components/QueryTable/QueryTable.test.jsx +++ b/superset-frontend/src/SqlLab/components/QueryTable/QueryTable.test.jsx @@ -25,13 +25,11 @@ import TableView from 'src/components/TableView'; import TableCollection from 'src/components/TableCollection'; import { Provider } from 'react-redux'; import { queries, user } from 'src/SqlLab/fixtures'; -import * as actions from 'src/SqlLab/actions/sqlLab'; describe('QueryTable', () => { const mockedProps = { queries, displayLimit: 100, - actions, latestQueryId: 'ryhMUZCGb', }; it('is valid', () => { diff --git a/superset-frontend/src/SqlLab/components/QueryTable/index.tsx b/superset-frontend/src/SqlLab/components/QueryTable/index.tsx index 54edb7f97e8d3..96e1f4568da66 100644 --- a/superset-frontend/src/SqlLab/components/QueryTable/index.tsx +++ b/superset-frontend/src/SqlLab/components/QueryTable/index.tsx @@ -22,7 +22,15 @@ import Card from 'src/components/Card'; import ProgressBar from 'src/components/ProgressBar'; import Label from 'src/components/Label'; import { t, useTheme, QueryResponse } from '@superset-ui/core'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; + +import { + queryEditorSetAndSaveSql, + cloneQueryToNewTab, + fetchQueryResults, + clearQueryResults, + removeQuery, +} from 'src/SqlLab/actions/sqlLab'; import TableView from 'src/components/TableView'; import Button from 'src/components/Button'; import { fDuration } from 'src/utils/dates'; @@ -45,13 +53,6 @@ interface QueryTableQuery interface QueryTableProps { columns?: string[]; - actions: { - queryEditorSetAndSaveSql: Function; - cloneQueryToNewTab: Function; - fetchQueryResults: Function; - clearQueryResults: Function; - removeQuery: Function; - }; queries?: QueryResponse[]; onUserClicked?: Function; onDbClicked?: Function; @@ -66,7 +67,6 @@ const openQuery = (id: number) => { const QueryTable = ({ columns = ['started', 'duration', 'rows'], - actions, queries = [], onUserClicked = () => undefined, onDbClicked = () => undefined, @@ -74,6 +74,18 @@ const QueryTable = ({ latestQueryId, }: QueryTableProps) => { const theme = useTheme(); + const dispatch = useDispatch(); + + const QUERY_HISTORY_TABLE_HEADERS_LOCALIZED = { + state: t('State'), + started: t('Started'), + duration: t('Duration'), + progress: t('Progress'), + rows: t('Rows'), + sql: t('SQL'), + results: t('Results'), + actions: t('Actions'), + }; const setHeaders = (column: string) => { if (column === 'sql') { @@ -81,11 +93,13 @@ const QueryTable = ({ } return column.charAt(0).toUpperCase().concat(column.slice(1)); }; + const columnsOfTable = useMemo( () => columns.map(column => ({ accessor: column, - Header: () => setHeaders(column), + Header: + QUERY_HISTORY_TABLE_HEADERS_LOCALIZED[column] || setHeaders(column), disableSortBy: true, })), [columns], @@ -93,25 +107,17 @@ const QueryTable = ({ const user = useSelector<SqlLabRootState, User>(state => state.sqlLab.user); - const { - queryEditorSetAndSaveSql, - cloneQueryToNewTab, - fetchQueryResults, - clearQueryResults, - removeQuery, - } = actions; - const data = useMemo(() => { const restoreSql = (query: QueryResponse) => { - queryEditorSetAndSaveSql({ id: query.sqlEditorId }, query.sql); + dispatch(queryEditorSetAndSaveSql({ id: query.sqlEditorId }, query.sql)); }; const openQueryInNewTab = (query: QueryResponse) => { - cloneQueryToNewTab(query, true); + dispatch(cloneQueryToNewTab(query, true)); }; const openAsyncResults = (query: QueryResponse, displayLimit: number) => { - fetchQueryResults(query, displayLimit); + dispatch(fetchQueryResults(query, displayLimit)); }; const statusAttributes = { @@ -239,13 +245,12 @@ const QueryTable = ({ } modalTitle={t('Data preview')} beforeOpen={() => openAsyncResults(query, displayLimit)} - onExit={() => clearQueryResults(query)} + onExit={() => dispatch(clearQueryResults(query))} modalBody={ <ResultSet showSql user={user} query={query} - actions={actions} height={400} displayLimit={displayLimit} defaultQueryLimit={1000} @@ -294,7 +299,7 @@ const QueryTable = ({ {q.id !== latestQueryId && ( <StyledTooltip tooltip={t('Remove query from log')} - onClick={() => removeQuery(query)} + onClick={() => dispatch(removeQuery(query))} > <Icons.Trash iconSize="xl" /> </StyledTooltip> @@ -304,19 +309,7 @@ const QueryTable = ({ return q; }) .reverse(); - }, [ - queries, - onUserClicked, - onDbClicked, - user, - displayLimit, - actions, - clearQueryResults, - cloneQueryToNewTab, - fetchQueryResults, - queryEditorSetAndSaveSql, - removeQuery, - ]); + }, [queries, onUserClicked, onDbClicked, user, displayLimit]); return ( <div className="QueryTable"> diff --git a/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.jsx b/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.jsx deleted file mode 100644 index c04e236133b72..0000000000000 --- a/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.jsx +++ /dev/null @@ -1,219 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import { shallow } from 'enzyme'; -import { styledMount } from 'spec/helpers/theming'; -import { render, screen } from 'spec/helpers/testing-library'; -import { Provider } from 'react-redux'; -import sinon from 'sinon'; -import Alert from 'src/components/Alert'; -import ProgressBar from 'src/components/ProgressBar'; -import Loading from 'src/components/Loading'; -import configureStore from 'redux-mock-store'; -import thunk from 'redux-thunk'; -import fetchMock from 'fetch-mock'; -import FilterableTable from 'src/components/FilterableTable'; -import ExploreResultsButton from 'src/SqlLab/components/ExploreResultsButton'; -import ResultSet from 'src/SqlLab/components/ResultSet'; -import ErrorMessageWithStackTrace from 'src/components/ErrorMessage/ErrorMessageWithStackTrace'; -import { - cachedQuery, - failedQueryWithErrorMessage, - failedQueryWithErrors, - queries, - runningQuery, - stoppedQuery, - initialState, - user, - queryWithNoQueryLimit, -} from 'src/SqlLab/fixtures'; - -const mockStore = configureStore([thunk]); -const store = mockStore(initialState); -const clearQuerySpy = sinon.spy(); -const fetchQuerySpy = sinon.spy(); -const reRunQuerySpy = sinon.spy(); -const mockedProps = { - actions: { - clearQueryResults: clearQuerySpy, - fetchQueryResults: fetchQuerySpy, - reRunQuery: reRunQuerySpy, - }, - cache: true, - query: queries[0], - height: 140, - database: { allows_virtual_table_explore: true }, - user, - defaultQueryLimit: 1000, -}; -const stoppedQueryProps = { ...mockedProps, query: stoppedQuery }; -const runningQueryProps = { ...mockedProps, query: runningQuery }; -const fetchingQueryProps = { - ...mockedProps, - query: { - dbId: 1, - cached: false, - ctas: false, - id: 'ryhHUZCGb', - progress: 100, - state: 'fetching', - startDttm: Date.now() - 500, - }, -}; -const cachedQueryProps = { ...mockedProps, query: cachedQuery }; -const failedQueryWithErrorMessageProps = { - ...mockedProps, - query: failedQueryWithErrorMessage, -}; -const failedQueryWithErrorsProps = { - ...mockedProps, - query: failedQueryWithErrors, -}; -const newProps = { - query: { - cached: false, - resultsKey: 'new key', - results: { - data: [{ a: 1 }], - }, - }, -}; -fetchMock.get('glob:*/api/v1/dataset?*', { result: [] }); - -test('is valid', () => { - expect(React.isValidElement(<ResultSet {...mockedProps} />)).toBe(true); -}); - -test('renders a Table', () => { - const wrapper = shallow(<ResultSet {...mockedProps} />); - expect(wrapper.find(FilterableTable)).toExist(); -}); - -describe('componentDidMount', () => { - const propsWithError = { - ...mockedProps, - query: { ...queries[0], errorMessage: 'Your session timed out' }, - }; - let spy; - beforeEach(() => { - reRunQuerySpy.resetHistory(); - spy = sinon.spy(ResultSet.prototype, 'componentDidMount'); - }); - afterEach(() => { - spy.restore(); - }); - it('should call reRunQuery if timed out', () => { - shallow(<ResultSet {...propsWithError} />); - expect(reRunQuerySpy.callCount).toBe(1); - }); - - it('should not call reRunQuery if no error', () => { - shallow(<ResultSet {...mockedProps} />); - expect(reRunQuerySpy.callCount).toBe(0); - }); -}); - -describe('UNSAFE_componentWillReceiveProps', () => { - const wrapper = shallow(<ResultSet {...mockedProps} />); - let spy; - beforeEach(() => { - clearQuerySpy.resetHistory(); - fetchQuerySpy.resetHistory(); - spy = sinon.spy(ResultSet.prototype, 'UNSAFE_componentWillReceiveProps'); - }); - afterEach(() => { - spy.restore(); - }); - it('should update cached data', () => { - wrapper.setProps(newProps); - - expect(wrapper.state().data).toEqual(newProps.query.results.data); - expect(clearQuerySpy.callCount).toBe(1); - expect(clearQuerySpy.getCall(0).args[0]).toEqual(newProps.query); - expect(fetchQuerySpy.callCount).toBe(1); - expect(fetchQuerySpy.getCall(0).args[0]).toEqual(newProps.query); - }); -}); - -test('should render success query', () => { - const wrapper = shallow(<ResultSet {...mockedProps} />); - const filterableTable = wrapper.find(FilterableTable); - expect(filterableTable.props().data).toBe(mockedProps.query.results.data); - expect(wrapper.find(ExploreResultsButton)).toExist(); -}); -test('should render empty results', () => { - const props = { - ...mockedProps, - query: { ...mockedProps.query, results: { data: [] } }, - }; - const wrapper = styledMount( - <Provider store={store}> - <ResultSet {...props} /> - </Provider>, - ); - expect(wrapper.find(FilterableTable)).not.toExist(); - expect(wrapper.find(Alert)).toExist(); - expect(wrapper.find(Alert).render().text()).toBe( - 'The query returned no data', - ); -}); - -test('should render cached query', () => { - const wrapper = shallow(<ResultSet {...cachedQueryProps} />); - const cachedData = [{ col1: 'a', col2: 'b' }]; - wrapper.setState({ data: cachedData }); - const filterableTable = wrapper.find(FilterableTable); - expect(filterableTable.props().data).toBe(cachedData); -}); - -test('should render stopped query', () => { - const wrapper = shallow(<ResultSet {...stoppedQueryProps} />); - expect(wrapper.find(Alert)).toExist(); -}); - -test('should render running/pending/fetching query', () => { - const wrapper = shallow(<ResultSet {...runningQueryProps} />); - expect(wrapper.find(ProgressBar)).toExist(); -}); - -test('should render fetching w/ 100 progress query', () => { - const wrapper = shallow(<ResultSet {...fetchingQueryProps} />); - expect(wrapper.find(Loading)).toExist(); -}); - -test('should render a failed query with an error message', () => { - const wrapper = shallow(<ResultSet {...failedQueryWithErrorMessageProps} />); - expect(wrapper.find(ErrorMessageWithStackTrace)).toExist(); -}); - -test('should render a failed query with an errors object', () => { - const wrapper = shallow(<ResultSet {...failedQueryWithErrorsProps} />); - expect(wrapper.find(ErrorMessageWithStackTrace)).toExist(); -}); - -test('renders if there is no limit in query.results but has queryLimit', () => { - render(<ResultSet {...mockedProps} />, { useRedux: true }); - expect(screen.getByRole('grid')).toBeInTheDocument(); -}); - -test('renders if there is a limit in query.results but not queryLimit', () => { - const props = { ...mockedProps, query: queryWithNoQueryLimit }; - render(<ResultSet {...props} />, { useRedux: true }); - expect(screen.getByRole('grid')).toBeInTheDocument(); -}); diff --git a/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx b/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx new file mode 100644 index 0000000000000..7869a87ab1b61 --- /dev/null +++ b/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx @@ -0,0 +1,271 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import configureStore from 'redux-mock-store'; +import { Store } from 'redux'; +import thunk from 'redux-thunk'; +import fetchMock from 'fetch-mock'; +import ResultSet from 'src/SqlLab/components/ResultSet'; +import { + cachedQuery, + failedQueryWithErrorMessage, + failedQueryWithErrors, + queries, + runningQuery, + stoppedQuery, + initialState, + user, + queryWithNoQueryLimit, +} from 'src/SqlLab/fixtures'; + +const mockedProps = { + cache: true, + query: queries[0], + height: 140, + database: { allows_virtual_table_explore: true }, + user, + defaultQueryLimit: 1000, +}; +const stoppedQueryProps = { ...mockedProps, query: stoppedQuery }; +const runningQueryProps = { ...mockedProps, query: runningQuery }; +const fetchingQueryProps = { + ...mockedProps, + query: { + dbId: 1, + cached: false, + ctas: false, + id: 'ryhHUZCGb', + progress: 100, + state: 'fetching', + startDttm: Date.now() - 500, + }, +}; +const cachedQueryProps = { ...mockedProps, query: cachedQuery }; +const failedQueryWithErrorMessageProps = { + ...mockedProps, + query: failedQueryWithErrorMessage, +}; +const failedQueryWithErrorsProps = { + ...mockedProps, + query: failedQueryWithErrors, +}; +const newProps = { + query: { + cached: false, + resultsKey: 'new key', + results: { + data: [{ a: 1 }], + }, + }, +}; +const asyncQueryProps = { + ...mockedProps, + database: { allow_run_async: true }, +}; +const asyncRefetchDataPreviewProps = { + ...asyncQueryProps, + query: { + state: 'success', + results: undefined, + isDataPreview: true, + }, +}; +const asyncRefetchResultsTableProps = { + ...asyncQueryProps, + query: { + state: 'success', + results: undefined, + resultsKey: 'async results key', + }, +}; +fetchMock.get('glob:*/api/v1/dataset?*', { result: [] }); + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); +const setup = (props?: any, store?: Store) => + render(<ResultSet {...props} />, { + useRedux: true, + ...(store && { store }), + }); + +describe('ResultSet', () => { + test('renders a Table', async () => { + const { getByTestId } = setup(mockedProps, mockStore(initialState)); + const table = getByTestId('table-container'); + expect(table).toBeInTheDocument(); + }); + + test('should render success query', async () => { + const { queryAllByText, getByTestId } = setup( + mockedProps, + mockStore(initialState), + ); + + const table = getByTestId('table-container'); + expect(table).toBeInTheDocument(); + + const firstColumn = queryAllByText( + mockedProps.query.results?.columns[0].name ?? '', + )[0]; + const secondColumn = queryAllByText( + mockedProps.query.results?.columns[1].name ?? '', + )[0]; + expect(firstColumn).toBeInTheDocument(); + expect(secondColumn).toBeInTheDocument(); + + const exploreButton = getByTestId('explore-results-button'); + expect(exploreButton).toBeInTheDocument(); + }); + + test('should render empty results', async () => { + const props = { + ...mockedProps, + query: { ...mockedProps.query, results: { data: [] } }, + }; + await waitFor(() => { + setup(props, mockStore(initialState)); + }); + + const alert = screen.getByRole('alert'); + expect(alert).toBeInTheDocument(); + expect(alert).toHaveTextContent('The query returned no data'); + }); + + test('should call reRunQuery if timed out', async () => { + const store = mockStore(initialState); + const propsWithError = { + ...mockedProps, + query: { ...queries[0], errorMessage: 'Your session timed out' }, + }; + + setup(propsWithError, store); + expect(store.getActions()).toHaveLength(1); + expect(store.getActions()[0].query.errorMessage).toEqual( + 'Your session timed out', + ); + expect(store.getActions()[0].type).toEqual('START_QUERY'); + }); + + test('should not call reRunQuery if no error', async () => { + const store = mockStore(initialState); + setup(mockedProps, store); + expect(store.getActions()).toEqual([]); + }); + + test('should render cached query', async () => { + const store = mockStore(initialState); + const { rerender } = setup(cachedQueryProps, store); + + // @ts-ignore + rerender(<ResultSet {...newProps} />); + expect(store.getActions()).toHaveLength(2); + expect(store.getActions()[0].query.results).toEqual( + cachedQueryProps.query.results, + ); + expect(store.getActions()[0].type).toEqual('CLEAR_QUERY_RESULTS'); + }); + + test('should render stopped query', async () => { + await waitFor(() => { + setup(stoppedQueryProps, mockStore(initialState)); + }); + + const alert = screen.getByRole('alert'); + expect(alert).toBeInTheDocument(); + }); + + test('should render running/pending/fetching query', async () => { + const { getByTestId } = setup(runningQueryProps, mockStore(initialState)); + const progressBar = getByTestId('progress-bar'); + expect(progressBar).toBeInTheDocument(); + }); + + test('should render fetching w/ 100 progress query', async () => { + const { getByRole, getByText } = setup( + fetchingQueryProps, + mockStore(initialState), + ); + const loading = getByRole('status'); + expect(loading).toBeInTheDocument(); + expect(getByText('fetching')).toBeInTheDocument(); + }); + + test('should render a failed query with an error message', async () => { + await waitFor(() => { + setup(failedQueryWithErrorMessageProps, mockStore(initialState)); + }); + + expect(screen.getByText('Database error')).toBeInTheDocument(); + expect(screen.getByText('Something went wrong')).toBeInTheDocument(); + }); + + test('should render a failed query with an errors object', async () => { + await waitFor(() => { + setup(failedQueryWithErrorsProps, mockStore(initialState)); + }); + expect(screen.getByText('Database error')).toBeInTheDocument(); + }); + + test('renders if there is no limit in query.results but has queryLimit', async () => { + const { getByRole } = setup(mockedProps, mockStore(initialState)); + expect(getByRole('grid')).toBeInTheDocument(); + }); + + test('renders if there is a limit in query.results but not queryLimit', async () => { + const props = { ...mockedProps, query: queryWithNoQueryLimit }; + const { getByRole } = setup(props, mockStore(initialState)); + expect(getByRole('grid')).toBeInTheDocument(); + }); + + test('Async queries - renders "Fetch data preview" button when data preview has no results', () => { + setup(asyncRefetchDataPreviewProps, mockStore(initialState)); + expect( + screen.getByRole('button', { + name: /fetch data preview/i, + }), + ).toBeVisible(); + expect(screen.queryByRole('grid')).toBe(null); + }); + + test('Async queries - renders "Refetch results" button when a query has no results', () => { + setup(asyncRefetchResultsTableProps, mockStore(initialState)); + expect( + screen.getByRole('button', { + name: /refetch results/i, + }), + ).toBeVisible(); + expect(screen.queryByRole('grid')).toBe(null); + }); + + test('Async queries - renders on the first call', () => { + setup(asyncQueryProps, mockStore(initialState)); + expect(screen.getByRole('grid')).toBeVisible(); + expect( + screen.queryByRole('button', { + name: /fetch data preview/i, + }), + ).toBe(null); + expect( + screen.queryByRole('button', { + name: /refetch results/i, + }), + ).toBe(null); + }); +}); diff --git a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx index 339303ba57928..fad6c98bc94b8 100644 --- a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx +++ b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx @@ -16,23 +16,47 @@ * specific language governing permissions and limitations * under the License. */ -import React, { CSSProperties } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useDispatch } from 'react-redux'; import ButtonGroup from 'src/components/ButtonGroup'; import Alert from 'src/components/Alert'; import Button from 'src/components/Button'; import shortid from 'shortid'; -import { styled, t, QueryResponse } from '@superset-ui/core'; +import { + QueryResponse, + QueryState, + styled, + t, + useTheme, +} from '@superset-ui/core'; +import { usePrevious } from 'src/hooks/usePrevious'; import ErrorMessageWithStackTrace from 'src/components/ErrorMessage/ErrorMessageWithStackTrace'; -import { SaveDatasetModal } from 'src/SqlLab/components/SaveDatasetModal'; +import { + ISaveableDatasource, + ISimpleColumn, + SaveDatasetModal, +} from 'src/SqlLab/components/SaveDatasetModal'; import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; +import { EXPLORE_CHART_DEFAULT } from 'src/SqlLab/types'; +import { mountExploreUrl } from 'src/explore/exploreUtils'; +import { postFormData } from 'src/explore/exploreUtils/formData'; import ProgressBar from 'src/components/ProgressBar'; import Loading from 'src/components/Loading'; import FilterableTable, { MAX_COLUMNS_FOR_TABLE, } from 'src/components/FilterableTable'; import CopyToClipboard from 'src/components/CopyToClipboard'; +import { addDangerToast } from 'src/components/MessageToasts/actions'; import { prepareCopyToClipboardTabularData } from 'src/utils/common'; -import { CtasEnum } from 'src/SqlLab/actions/sqlLab'; +import { + addQueryEditor, + clearQueryResults, + CtasEnum, + fetchQueryResults, + reFetchQueryResults, + reRunQuery, +} from 'src/SqlLab/actions/sqlLab'; +import { URL_PARAMS } from 'src/constants'; import ExploreCtasResultsButton from '../ExploreCtasResultsButton'; import ExploreResultsButton from '../ExploreResultsButton'; import HighlightedSql from '../HighlightedSql'; @@ -45,11 +69,7 @@ enum LIMITING_FACTOR { NOT_LIMITED = 'NOT_LIMITED', } -const LOADING_STYLES: CSSProperties = { position: 'relative', minHeight: 100 }; - -interface ResultSetProps { - showControls?: boolean; - actions: Record<string, any>; +export interface ResultSetProps { cache?: boolean; csv?: boolean; database?: Record<string, any>; @@ -63,13 +83,16 @@ interface ResultSetProps { defaultQueryLimit: number; } -interface ResultSetState { - searchText: string; - showExploreResultsButton: boolean; - data: Record<string, any>[]; - showSaveDatasetModal: boolean; - alertIsOpen: boolean; -} +const ResultlessStyles = styled.div` + position: relative; + min-height: ${({ theme }) => theme.gridUnit * 25}px; + [role='alert'] { + margin-top: ${({ theme }) => theme.gridUnit * 2}px; + } + .sql-result-track-job { + margin-top: ${({ theme }) => theme.gridUnit * 2}px; + } +`; // Making text render line breaks/tabs as is as monospace, // but wrapping text too so text doesn't overflow @@ -82,8 +105,8 @@ const MonospaceDiv = styled.div` `; const ReturnedRows = styled.div` - font-size: 13px; - line-height: 24px; + font-size: ${({ theme }) => theme.typography.sizes.s}px; + line-height: ${({ theme }) => theme.gridUnit * 6}px; `; const ResultSetControls = styled.div` @@ -98,150 +121,146 @@ const ResultSetButtons = styled.div` padding-right: ${({ theme }) => 2 * theme.gridUnit}px; `; -const ResultSetErrorMessage = styled.div` - padding-top: ${({ theme }) => 4 * theme.gridUnit}px; +const LimitMessage = styled.span` + color: ${({ theme }) => theme.colors.secondary.light1}; + margin-left: ${({ theme }) => theme.gridUnit * 2}px; `; -export default class ResultSet extends React.PureComponent< - ResultSetProps, - ResultSetState -> { - static defaultProps = { - cache: false, - csv: true, - database: {}, - search: true, - showSql: false, - visualize: true, - }; - - constructor(props: ResultSetProps) { - super(props); - this.state = { - searchText: '', - showExploreResultsButton: false, - data: [], - showSaveDatasetModal: false, - alertIsOpen: false, - }; - this.changeSearch = this.changeSearch.bind(this); - this.fetchResults = this.fetchResults.bind(this); - this.popSelectStar = this.popSelectStar.bind(this); - this.reFetchQueryResults = this.reFetchQueryResults.bind(this); - this.toggleExploreResultsButton = - this.toggleExploreResultsButton.bind(this); - } +const ResultSet = ({ + cache = false, + csv = true, + database = {}, + displayLimit, + height, + query, + search = true, + showSql = false, + visualize = true, + user, + defaultQueryLimit, +}: ResultSetProps) => { + const theme = useTheme(); + const [searchText, setSearchText] = useState(''); + const [cachedData, setCachedData] = useState<Record<string, unknown>[]>([]); + const [showSaveDatasetModal, setShowSaveDatasetModal] = useState(false); + const [alertIsOpen, setAlertIsOpen] = useState(false); + + const dispatch = useDispatch(); + + const reRunQueryIfSessionTimeoutErrorOnMount = useCallback(() => { + if ( + query.errorMessage && + query.errorMessage.indexOf('session timed out') > 0 + ) { + dispatch(reRunQuery(query)); + } + }, []); - async componentDidMount() { + useEffect(() => { // only do this the first time the component is rendered/mounted - this.reRunQueryIfSessionTimeoutErrorOnMount(); - } + reRunQueryIfSessionTimeoutErrorOnMount(); + }, [reRunQueryIfSessionTimeoutErrorOnMount]); - UNSAFE_componentWillReceiveProps(nextProps: ResultSetProps) { - // when new results comes in, save them locally and clear in store - if ( - this.props.cache && - !nextProps.query.cached && - nextProps.query.results && - nextProps.query.results.data && - nextProps.query.results.data.length > 0 - ) { - this.setState({ data: nextProps.query.results.data }, () => - this.clearQueryResults(nextProps.query), - ); + const fetchResults = (query: QueryResponse) => { + dispatch(fetchQueryResults(query, displayLimit)); + }; + + const prevQuery = usePrevious(query); + useEffect(() => { + if (cache && query.cached && query?.results?.data?.length > 0) { + setCachedData(query.results.data); + dispatch(clearQueryResults(query)); } - if ( - nextProps.query.resultsKey && - nextProps.query.resultsKey !== this.props.query.resultsKey - ) { - this.fetchResults(nextProps.query); + if (query.resultsKey && query.resultsKey !== prevQuery?.resultsKey) { + fetchResults(query); } - } + }, [query, cache]); - calculateAlertRefHeight = (alertElement: HTMLElement | null) => { + const calculateAlertRefHeight = (alertElement: HTMLElement | null) => { if (alertElement) { - this.setState({ alertIsOpen: true }); + setAlertIsOpen(true); } else { - this.setState({ alertIsOpen: false }); + setAlertIsOpen(false); } }; - clearQueryResults(query: QueryResponse) { - this.props.actions.clearQueryResults(query); - } - - popSelectStar(tempSchema: string | null, tempTable: string) { + const popSelectStar = (tempSchema: string | null, tempTable: string) => { const qe = { id: shortid.generate(), - title: tempTable, + name: tempTable, autorun: false, - dbId: this.props.query.dbId, + dbId: query.dbId, sql: `SELECT * FROM ${tempSchema ? `${tempSchema}.` : ''}${tempTable}`, }; - this.props.actions.addQueryEditor(qe); - } - - toggleExploreResultsButton() { - this.setState(prevState => ({ - showExploreResultsButton: !prevState.showExploreResultsButton, - })); - } - - changeSearch(event: React.ChangeEvent<HTMLInputElement>) { - this.setState({ searchText: event.target.value }); - } - - fetchResults(query: QueryResponse) { - this.props.actions.fetchQueryResults(query, this.props.displayLimit); - } + dispatch(addQueryEditor(qe)); + }; - reFetchQueryResults(query: QueryResponse) { - this.props.actions.reFetchQueryResults(query); - } + const changeSearch = (event: React.ChangeEvent<HTMLInputElement>) => { + setSearchText(event.target.value); + }; - reRunQueryIfSessionTimeoutErrorOnMount() { - const { query } = this.props; - if ( - query.errorMessage && - query.errorMessage.indexOf('session timed out') > 0 - ) { - this.props.actions.reRunQuery(query); + const createExploreResultsOnClick = async () => { + const { results } = query; + + if (results?.query_id) { + const key = await postFormData(results.query_id, 'query', { + ...EXPLORE_CHART_DEFAULT, + datasource: `${results.query_id}__query`, + ...{ + all_columns: results.columns.map(column => column.name), + }, + }); + const url = mountExploreUrl(null, { + [URL_PARAMS.formDataKey.name]: key, + }); + window.open(url, '_blank', 'noreferrer'); + } else { + addDangerToast(t('Unable to create chart without a query id.')); } - } + }; - renderControls() { - if (this.props.search || this.props.visualize || this.props.csv) { - let { data } = this.props.query.results; - if (this.props.cache && this.props.query.cached) { - ({ data } = this.state); + const getExportCsvUrl = (clientId: string) => + `/api/v1/sqllab/export/${clientId}/`; + + const renderControls = () => { + if (search || visualize || csv) { + let { data } = query.results; + if (cache && query.cached) { + data = cachedData; } - const { columns } = this.props.query.results; + const { columns } = query.results; // Added compute logic to stop user from being able to Save & Explore - const { showSaveDatasetModal } = this.state; - const { query } = this.props; + + const datasource: ISaveableDatasource = { + columns: query.results.columns as ISimpleColumn[], + name: query?.tab || 'Untitled', + dbId: query?.dbId, + sql: query?.sql, + templateParams: query?.templateParams, + schema: query?.schema, + }; return ( <ResultSetControls> <SaveDatasetModal visible={showSaveDatasetModal} - onHide={() => this.setState({ showSaveDatasetModal: false })} + onHide={() => setShowSaveDatasetModal(false)} buttonTextOnSave={t('Save & Explore')} buttonTextOnOverwrite={t('Overwrite & Explore')} modalDescription={t( 'Save this query as a virtual dataset to continue exploring', )} - datasource={query} + datasource={datasource} /> <ResultSetButtons> - {this.props.visualize && - this.props.database?.allows_virtual_table_explore && ( - <ExploreResultsButton - database={this.props.database} - onClick={() => this.setState({ showSaveDatasetModal: true })} - /> - )} - {this.props.csv && ( - <Button buttonSize="small" href={`/superset/csv/${query.id}`}> + {visualize && database?.allows_virtual_table_explore && ( + <ExploreResultsButton + database={database} + onClick={createExploreResultsOnClick} + /> + )} + {csv && ( + <Button buttonSize="small" href={getExportCsvUrl(query.id)}> <i className="fa fa-file-text-o" /> {t('Download to CSV')} </Button> )} @@ -257,11 +276,11 @@ export default class ResultSet extends React.PureComponent< hideTooltip /> </ResultSetButtons> - {this.props.search && ( + {search && ( <input type="text" - onChange={this.changeSearch} - value={this.state.searchText} + onChange={changeSearch} + value={searchText} className="form-control input-sm" disabled={columns.length > MAX_COLUMNS_FOR_TABLE} placeholder={ @@ -275,14 +294,14 @@ export default class ResultSet extends React.PureComponent< ); } return <div />; - } + }; - renderRowsReturned() { - const { results, rows, queryLimit, limitingFactor } = this.props.query; + const renderRowsReturned = () => { + const { results, rows, queryLimit, limitingFactor } = query; let limitMessage; const limitReached = results?.displayLimitReached; const limit = queryLimit || results.query.limit; - const isAdmin = !!this.props.user?.roles?.Admin; + const isAdmin = !!user?.roles?.Admin; const rowsCount = Math.min(rows || 0, results?.data?.length || 0); const displayMaxRowsReachedMessage = { @@ -300,10 +319,10 @@ export default class ResultSet extends React.PureComponent< ), }; const shouldUseDefaultDropdownAlert = - limit === this.props.defaultQueryLimit && + limit === defaultQueryLimit && limitingFactor === LIMITING_FACTOR.DROPDOWN; - if (limitingFactor === LIMITING_FACTOR.QUERY && this.props.csv) { + if (limitingFactor === LIMITING_FACTOR.QUERY && csv) { limitMessage = t( 'The number of rows displayed is limited to %(rows)d by the query', { rows }, @@ -334,27 +353,27 @@ export default class ResultSet extends React.PureComponent< {!limitReached && !shouldUseDefaultDropdownAlert && ( <span title={tooltipText}> {rowsReturnedMessage} - <span>{limitMessage}</span> + <LimitMessage>{limitMessage}</LimitMessage> </span> )} {!limitReached && shouldUseDefaultDropdownAlert && ( - <div ref={this.calculateAlertRefHeight}> + <div ref={calculateAlertRefHeight}> <Alert type="warning" message={t('%(rows)d rows returned', { rows })} - onClose={() => this.setState({ alertIsOpen: false })} + onClose={() => setAlertIsOpen(false)} description={t( - 'The number of rows displayed is limited to %s by the dropdown.', - rows, + 'The number of rows displayed is limited to %(rows)d by the dropdown.', + { rows }, )} /> </div> )} {limitReached && ( - <div ref={this.calculateAlertRefHeight}> + <div ref={calculateAlertRefHeight}> <Alert type="warning" - onClose={() => this.setState({ alertIsOpen: false })} + onClose={() => setAlertIsOpen(false)} message={t('%(rows)d rows returned', { rows: rowsCount })} description={ isAdmin @@ -366,186 +385,193 @@ export default class ResultSet extends React.PureComponent< )} </ReturnedRows> ); + }; + + const limitReached = query?.results?.displayLimitReached; + let sql; + let exploreDBId = query.dbId; + if (database?.explore_database_id) { + exploreDBId = database.explore_database_id; } - render() { - const { query } = this.props; - const limitReached = query?.results?.displayLimitReached; - let sql; - let exploreDBId = query.dbId; - if (this.props.database && this.props.database.explore_database_id) { - exploreDBId = this.props.database.explore_database_id; - } + let trackingUrl; + if ( + query.trackingUrl && + query.state !== QueryState.SUCCESS && + query.state !== QueryState.FETCHING + ) { + trackingUrl = ( + <Button + className="sql-result-track-job" + buttonSize="small" + href={query.trackingUrl} + target="_blank" + > + {query.state === QueryState.RUNNING + ? t('Track job') + : t('See query details')} + </Button> + ); + } - if (this.props.showSql) sql = <HighlightedSql sql={query.sql} />; + if (showSql) { + sql = <HighlightedSql sql={query.sql} />; + } + + if (query.state === QueryState.STOPPED) { + return <Alert type="warning" message={t('Query was stopped')} />; + } + + if (query.state === QueryState.FAILED) { + return ( + <ResultlessStyles> + <ErrorMessageWithStackTrace + title={t('Database error')} + error={query?.errors?.[0]} + subtitle={<MonospaceDiv>{query.errorMessage}</MonospaceDiv>} + copyText={query.errorMessage || undefined} + link={query.link} + source="sqllab" + /> + {trackingUrl} + </ResultlessStyles> + ); + } - if (query.state === 'stopped') { - return <Alert type="warning" message={t('Query was stopped')} />; + if (query.state === QueryState.SUCCESS && query.ctas) { + const { tempSchema, tempTable } = query; + let object = 'Table'; + if (query.ctas_method === CtasEnum.VIEW) { + object = 'View'; } - if (query.state === 'failed') { - return ( - <ResultSetErrorMessage> - <ErrorMessageWithStackTrace - title={t('Database error')} - error={query?.errors?.[0]} - subtitle={<MonospaceDiv>{query.errorMessage}</MonospaceDiv>} - copyText={query.errorMessage || undefined} - link={query.link} - source="sqllab" - /> - </ResultSetErrorMessage> - ); + return ( + <div> + <Alert + type="info" + message={ + <> + {t(object)} [ + <strong> + {tempSchema ? `${tempSchema}.` : ''} + {tempTable} + </strong> + ] {t('was created')}   + <ButtonGroup> + <Button + buttonSize="small" + css={{ marginRight: theme.gridUnit }} + onClick={() => popSelectStar(tempSchema, tempTable)} + > + {t('Query in a new tab')} + </Button> + <ExploreCtasResultsButton + table={tempTable} + schema={tempSchema} + dbId={exploreDBId} + /> + </ButtonGroup> + </> + } + /> + </div> + ); + } + + if (query.state === QueryState.SUCCESS && query.results) { + const { results } = query; + // Accounts for offset needed for height of ResultSetRowsReturned component if !limitReached + const rowMessageHeight = !limitReached ? 32 : 0; + // Accounts for offset needed for height of Alert if this.state.alertIsOpen + const alertContainerHeight = 70; + // We need to calculate the height of this.renderRowsReturned() + // if we want results panel to be proper height because the + // FilterTable component needs an explicit height to render + // react-virtualized Table component + const rowsHeight = alertIsOpen + ? height - alertContainerHeight + : height - rowMessageHeight; + let data; + if (cache && query.cached) { + data = cachedData; + } else if (results?.data) { + ({ data } = results); } - if (query.state === 'success' && query.ctas) { - const { tempSchema, tempTable } = query; - let object = 'Table'; - if (query.ctas_method === CtasEnum.VIEW) { - object = 'View'; - } + if (data && data.length > 0) { + const expandedColumns = results.expanded_columns + ? results.expanded_columns.map(col => col.name) + : []; return ( - <div> - <Alert - type="info" - message={ - <> - {t(object)} [ - <strong> - {tempSchema ? `${tempSchema}.` : ''} - {tempTable} - </strong> - ] {t('was created')}   - <ButtonGroup> - <Button - buttonSize="small" - className="m-r-5" - onClick={() => this.popSelectStar(tempSchema, tempTable)} - > - {t('Query in a new tab')} - </Button> - <ExploreCtasResultsButton - // @ts-ignore Redux types are difficult to work with, ignoring for now - actions={this.props.actions} - table={tempTable} - schema={tempSchema} - dbId={exploreDBId} - /> - </ButtonGroup> - </> - } + <> + {renderControls()} + {renderRowsReturned()} + {sql} + <FilterableTable + data={data} + orderedColumnKeys={results.columns.map(col => col.name)} + height={rowsHeight} + filterText={searchText} + expandedColumns={expandedColumns} /> - </div> + </> ); } - if (query.state === 'success' && query.results) { - const { results } = query; - // Accounts for offset needed for height of ResultSetRowsReturned component if !limitReached - const rowMessageHeight = !limitReached ? 32 : 0; - // Accounts for offset needed for height of Alert if this.state.alertIsOpen - const alertContainerHeight = 70; - // We need to calculate the height of this.renderRowsReturned() - // if we want results panel to be propper height because the - // FilterTable component nedds an explcit height to render - // react-virtualized Table component - const height = this.state.alertIsOpen - ? this.props.height - alertContainerHeight - : this.props.height - rowMessageHeight; - let data; - if (this.props.cache && query.cached) { - ({ data } = this.state); - } else if (results && results.data) { - ({ data } = results); - } - if (data && data.length > 0) { - const expandedColumns = results.expanded_columns - ? results.expanded_columns.map(col => col.name) - : []; - return ( - <> - {this.renderControls()} - {this.renderRowsReturned()} - {sql} - <FilterableTable - data={data} - orderedColumnKeys={results.columns.map(col => col.name)} - height={height} - filterText={this.state.searchText} - expandedColumns={expandedColumns} - /> - </> - ); - } - if (data && data.length === 0) { - return ( - <Alert type="warning" message={t('The query returned no data')} /> - ); - } + if (data && data.length === 0) { + return <Alert type="warning" message={t('The query returned no data')} />; } - if (query.cached || (query.state === 'success' && !query.results)) { - if (query.isDataPreview) { - return ( - <Button - buttonSize="small" - buttonStyle="primary" - onClick={() => - this.reFetchQueryResults({ + } + + if (query.cached || (query.state === QueryState.SUCCESS && !query.results)) { + if (query.isDataPreview) { + return ( + <Button + buttonSize="small" + buttonStyle="primary" + onClick={() => + dispatch( + reFetchQueryResults({ ...query, isDataPreview: true, - }) - } - > - {t('Fetch data preview')} - </Button> - ); - } - if (query.resultsKey) { - return ( - <Button - buttonSize="small" - buttonStyle="primary" - onClick={() => this.fetchResults(query)} - > - {t('Refetch results')} - </Button> - ); - } - } - let trackingUrl; - let progressBar; - if (query.progress > 0) { - progressBar = ( - <ProgressBar - percent={parseInt(query.progress.toFixed(0), 10)} - striped - /> + }), + ) + } + > + {t('Fetch data preview')} + </Button> ); } - if (query.trackingUrl) { - trackingUrl = ( + if (query.resultsKey) { + return ( <Button buttonSize="small" - onClick={() => query.trackingUrl && window.open(query.trackingUrl)} + buttonStyle="primary" + onClick={() => fetchResults(query)} > - {t('Track job')} + {t('Refetch results')} </Button> ); } - const progressMsg = - query && query.extra && query.extra.progress - ? query.extra.progress - : null; + } - return ( - <div style={LOADING_STYLES}> - <div>{!progressBar && <Loading position="normal" />}</div> - {/* show loading bar whenever progress bar is completed but needs time to render */} - <div>{query.progress === 100 && <Loading position="normal" />}</div> - <QueryStateLabel query={query} /> - <div> - {progressMsg && <Alert type="success" message={progressMsg} />} - </div> - <div>{query.progress !== 100 && progressBar}</div> - <div>{trackingUrl}</div> - </div> + let progressBar; + if (query.progress > 0) { + progressBar = ( + <ProgressBar percent={parseInt(query.progress.toFixed(0), 10)} striped /> ); } -} + + const progressMsg = query?.extra?.progress ?? null; + + return ( + <ResultlessStyles> + <div>{!progressBar && <Loading position="normal" />}</div> + {/* show loading bar whenever progress bar is completed but needs time to render */} + <div>{query.progress === 100 && <Loading position="normal" />}</div> + <QueryStateLabel query={query} /> + <div>{progressMsg && <Alert type="success" message={progressMsg} />}</div> + <div>{query.progress !== 100 && progressBar}</div> + {trackingUrl && <div>{trackingUrl}</div>} + </ResultlessStyles> + ); +}; + +export default ResultSet; diff --git a/superset-frontend/src/SqlLab/components/RunQueryActionButton/RunQueryActionButton.test.jsx b/superset-frontend/src/SqlLab/components/RunQueryActionButton/RunQueryActionButton.test.jsx deleted file mode 100644 index 823f10741ac09..0000000000000 --- a/superset-frontend/src/SqlLab/components/RunQueryActionButton/RunQueryActionButton.test.jsx +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import { mount } from 'enzyme'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; -import RunQueryActionButton from 'src/SqlLab/components/RunQueryActionButton'; -import Button from 'src/components/Button'; - -describe('RunQueryActionButton', () => { - let wrapper; - const defaultProps = { - allowAsync: false, - dbId: 1, - queryState: 'pending', - runQuery: () => {}, // eslint-disable-line - selectedText: null, - stopQuery: () => {}, // eslint-disable-line - sql: '', - }; - - beforeEach(() => { - wrapper = mount(<RunQueryActionButton {...defaultProps} />, { - wrappingComponent: ThemeProvider, - wrappingComponentProps: { theme: supersetTheme }, - }); - }); - - it('is a valid react element', () => { - expect( - React.isValidElement(<RunQueryActionButton {...defaultProps} />), - ).toBe(true); - }); - - it('renders a single Button', () => { - expect(wrapper.find(Button)).toExist(); - }); -}); diff --git a/superset-frontend/src/SqlLab/components/RunQueryActionButton/RunQueryActionButton.test.tsx b/superset-frontend/src/SqlLab/components/RunQueryActionButton/RunQueryActionButton.test.tsx new file mode 100644 index 0000000000000..276f9b7d19675 --- /dev/null +++ b/superset-frontend/src/SqlLab/components/RunQueryActionButton/RunQueryActionButton.test.tsx @@ -0,0 +1,160 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { Store } from 'redux'; + +import { render, fireEvent, waitFor } from 'spec/helpers/testing-library'; +import { initialState, defaultQueryEditor } from 'src/SqlLab/fixtures'; +import RunQueryActionButton, { + RunQueryActionButtonProps, +} from 'src/SqlLab/components/RunQueryActionButton'; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); + +jest.mock('src/components/DeprecatedSelect', () => () => ( + <div data-test="mock-deprecated-select" /> +)); +jest.mock('src/components/Select/Select', () => () => ( + <div data-test="mock-deprecated-select-select" /> +)); +jest.mock('src/components/Select/AsyncSelect', () => () => ( + <div data-test="mock-deprecated-async-select" /> +)); + +const defaultProps = { + queryEditorId: defaultQueryEditor.id, + allowAsync: false, + dbId: 1, + queryState: 'ready', + runQuery: () => {}, + selectedText: null, + stopQuery: () => {}, + overlayCreateAsMenu: null, +}; + +const setup = (props?: Partial<RunQueryActionButtonProps>, store?: Store) => + render(<RunQueryActionButton {...defaultProps} {...props} />, { + useRedux: true, + ...(store && { store }), + }); + +it('renders a single Button', () => { + const { getByRole } = setup({}, mockStore(initialState)); + expect(getByRole('button')).toBeInTheDocument(); +}); + +it('renders a label for Run Query', () => { + const { getByText } = setup({}, mockStore(initialState)); + expect(getByText('Run')).toBeInTheDocument(); +}); + +it('renders a label for Selected Query', () => { + const { getByText } = setup( + {}, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + selectedText: 'select * from\n-- this is comment\nwhere', + }, + }, + }), + ); + expect(getByText('Run selection')).toBeInTheDocument(); +}); + +it('disable button when sql from unsaved changes is empty', () => { + const { getByRole } = setup( + {}, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + sql: '', + }, + }, + }), + ); + const button = getByRole('button'); + expect(button).toBeDisabled(); +}); + +it('disable button when selectedText only contains blank contents', () => { + const { getByRole } = setup( + {}, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + selectedText: '-- this is comment\n\n \t', + }, + }, + }), + ); + const button = getByRole('button'); + expect(button).toBeDisabled(); +}); + +it('enable default button for unrelated unsaved changes', () => { + const { getByRole } = setup( + {}, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: `${defaultQueryEditor.id}-other`, + sql: '', + }, + }, + }), + ); + const button = getByRole('button'); + expect(button).toBeEnabled(); +}); + +it('dispatch runQuery on click', async () => { + const runQuery = jest.fn(); + const { getByRole } = setup({ runQuery }, mockStore(initialState)); + const button = getByRole('button'); + expect(runQuery).toHaveBeenCalledTimes(0); + fireEvent.click(button); + await waitFor(() => expect(runQuery).toHaveBeenCalledTimes(1)); +}); + +it('dispatch stopQuery on click while running state', async () => { + const stopQuery = jest.fn(); + const { getByRole } = setup( + { queryState: 'running', stopQuery }, + mockStore(initialState), + ); + const button = getByRole('button'); + expect(stopQuery).toHaveBeenCalledTimes(0); + fireEvent.click(button); + await waitFor(() => expect(stopQuery).toHaveBeenCalledTimes(1)); +}); diff --git a/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx b/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx index 9da467685b492..9a94fb81c3c9d 100644 --- a/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx +++ b/superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx @@ -20,26 +20,22 @@ import React, { useMemo } from 'react'; import { t, styled, useTheme } from '@superset-ui/core'; import { Menu } from 'src/components/Menu'; -import Button, { ButtonProps } from 'src/components/Button'; +import Button from 'src/components/Button'; import Icons from 'src/components/Icons'; -import { - DropdownButton, - DropdownButtonProps, -} from 'src/components/DropdownButton'; +import { DropdownButton } from 'src/components/DropdownButton'; import { detectOS } from 'src/utils/common'; +import { QueryButtonProps } from 'src/SqlLab/types'; +import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; -interface Props { +export interface RunQueryActionButtonProps { + queryEditorId: string; allowAsync: boolean; queryState?: string; runQuery: (c?: boolean) => void; - selectedText?: string; stopQuery: () => void; - sql: string; overlayCreateAsMenu: typeof Menu | null; } -type QueryButtonProps = DropdownButtonProps | ButtonProps; - const buildText = ( shouldShowStopButton: boolean, selectedText: string | undefined, @@ -80,24 +76,27 @@ const StyledButton = styled.span` } span[name='caret-down'] { display: flex; - margin-right: ${({ theme }) => theme.gridUnit * -2}px; + margin-left: ${({ theme }) => theme.gridUnit * 1}px; } } `; const RunQueryActionButton = ({ allowAsync = false, + queryEditorId, queryState, - selectedText, - sql = '', overlayCreateAsMenu, runQuery, stopQuery, -}: Props) => { +}: RunQueryActionButtonProps) => { const theme = useTheme(); - const userOS = detectOS(); + const { selectedText, sql } = useQueryEditor(queryEditorId, [ + 'selectedText', + 'sql', + ]); + const shouldShowStopBtn = !!queryState && ['running', 'pending'].indexOf(queryState) > -1; @@ -105,7 +104,10 @@ const RunQueryActionButton = ({ ? (DropdownButton as React.FC) : Button; - const isDisabled = !sql.trim(); + const sqlContent = selectedText || sql || ''; + const isDisabled = + !sqlContent || + !sqlContent.replace(/(\/\*[^*]*\*\/)|(\/\/[^*]*)|(--[^.].*)/gm, '').trim(); const stopButtonTooltipText = useMemo( () => @@ -118,6 +120,7 @@ const RunQueryActionButton = ({ return ( <StyledButton> <ButtonComponent + data-test="run-query-action" onClick={() => onClick(shouldShowStopBtn, allowAsync, runQuery, stopQuery) } diff --git a/superset-frontend/src/SqlLab/components/SaveDatasetActionButton/SaveDatasetActionButton.test.tsx b/superset-frontend/src/SqlLab/components/SaveDatasetActionButton/SaveDatasetActionButton.test.tsx new file mode 100644 index 0000000000000..316404e3e4f3a --- /dev/null +++ b/superset-frontend/src/SqlLab/components/SaveDatasetActionButton/SaveDatasetActionButton.test.tsx @@ -0,0 +1,68 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { Menu } from 'src/components/Menu'; +import SaveDatasetActionButton from 'src/SqlLab/components/SaveDatasetActionButton'; + +const overlayMenu = ( + <Menu> + <Menu.Item>Save dataset</Menu.Item> + </Menu> +); + +describe('SaveDatasetActionButton', () => { + test('renders a split save button', async () => { + render( + <SaveDatasetActionButton + setShowSave={() => true} + overlayMenu={overlayMenu} + />, + ); + + const saveBtn = screen.getByRole('button', { name: /save/i }); + const caretBtn = screen.getByRole('button', { name: /caret-down/i }); + + expect( + await screen.findByRole('button', { name: /save/i }), + ).toBeInTheDocument(); + expect(saveBtn).toBeVisible(); + expect(caretBtn).toBeVisible(); + }); + + test('renders a "save dataset" dropdown menu item when user clicks caret button', async () => { + render( + <SaveDatasetActionButton + setShowSave={() => true} + overlayMenu={overlayMenu} + />, + ); + + const caretBtn = screen.getByRole('button', { name: /caret-down/i }); + expect( + await screen.findByRole('button', { name: /caret-down/i }), + ).toBeInTheDocument(); + userEvent.click(caretBtn); + + const saveDatasetMenuItem = screen.getByText(/save dataset/i); + + expect(saveDatasetMenuItem).toBeInTheDocument(); + }); +}); diff --git a/superset-frontend/src/SqlLab/components/SaveDatasetActionButton/index.tsx b/superset-frontend/src/SqlLab/components/SaveDatasetActionButton/index.tsx new file mode 100644 index 0000000000000..dbb25b138a58e --- /dev/null +++ b/superset-frontend/src/SqlLab/components/SaveDatasetActionButton/index.tsx @@ -0,0 +1,85 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { t, useTheme, styled } from '@superset-ui/core'; +import Icons from 'src/components/Icons'; +import { DropdownButton } from 'src/components/DropdownButton'; +import Button from 'src/components/Button'; +import { DropdownButtonProps } from 'antd/lib/dropdown'; + +interface SaveDatasetActionButtonProps { + setShowSave: (arg0: boolean) => void; + overlayMenu: JSX.Element | null; +} + +const SaveDatasetActionButton = ({ + setShowSave, + overlayMenu, +}: SaveDatasetActionButtonProps) => { + const theme = useTheme(); + + const StyledDropdownButton = styled( + DropdownButton as React.FC<DropdownButtonProps>, + )` + &.ant-dropdown-button button.ant-btn.ant-btn-default { + &:first-of-type { + width: ${theme.gridUnit * 16}px; + } + font-weight: ${theme.gridUnit * 150}; + background-color: ${theme.colors.primary.light4}; + color: ${theme.colors.primary.dark1}; + &:nth-child(2) { + &:before, + &:hover:before { + border-left: 2px solid ${theme.colors.primary.dark2}; + } + } + } + span[name='caret-down'] { + margin-left: ${theme.gridUnit * 1}px; + color: ${theme.colors.primary.dark2}; + } + `; + + return !overlayMenu ? ( + <Button + onClick={() => setShowSave(true)} + buttonStyle="primary" + css={{ width: theme.gridUnit * 25 }} + > + {t('Save')} + </Button> + ) : ( + <StyledDropdownButton + onClick={() => setShowSave(true)} + overlay={overlayMenu} + icon={ + <Icons.CaretDown + iconColor={theme.colors.grayscale.light5} + name="caret-down" + /> + } + trigger={['click']} + > + {t('Save')} + </StyledDropdownButton> + ); +}; + +export default SaveDatasetActionButton; diff --git a/superset-frontend/src/SqlLab/components/SaveDatasetModal/SaveDatasetModal.test.tsx b/superset-frontend/src/SqlLab/components/SaveDatasetModal/SaveDatasetModal.test.tsx index c35b5eb2b6022..f707998d1df67 100644 --- a/superset-frontend/src/SqlLab/components/SaveDatasetModal/SaveDatasetModal.test.tsx +++ b/superset-frontend/src/SqlLab/components/SaveDatasetModal/SaveDatasetModal.test.tsx @@ -17,25 +17,43 @@ * under the License. */ import React from 'react'; -import { QueryResponse, testQuery } from '@superset-ui/core'; +import * as reactRedux from 'react-redux'; +import { render, screen, cleanup, waitFor } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import fetchMock from 'fetch-mock'; import { SaveDatasetModal } from 'src/SqlLab/components/SaveDatasetModal'; -import { render, screen } from 'spec/helpers/testing-library'; +import { user, testQuery, mockdatasets } from 'src/SqlLab/fixtures'; const mockedProps = { visible: true, onHide: () => {}, buttonTextOnSave: 'Save', buttonTextOnOverwrite: 'Overwrite', - datasource: testQuery as QueryResponse, + datasource: testQuery, }; -describe('SaveDatasetModal RTL', () => { +fetchMock.get('glob:*/api/v1/dataset?*', { + result: mockdatasets, + dataset_count: 3, +}); + +jest.useFakeTimers(); + +// Mock the user +const useSelectorMock = jest.spyOn(reactRedux, 'useSelector'); +beforeEach(() => { + useSelectorMock.mockClear(); + cleanup(); +}); + +describe('SaveDatasetModal', () => { it('renders a "Save as new" field', () => { render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); const saveRadioBtn = screen.getByRole('radio', { name: /save as new unimportant/i, }); + const fieldLabel = screen.getByText(/save as new/i); const inputField = screen.getByRole('textbox'); const inputFieldText = screen.getByDisplayValue(/unimportant/i); @@ -50,7 +68,7 @@ describe('SaveDatasetModal RTL', () => { render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); const overwriteRadioBtn = screen.getByRole('radio', { - name: /overwrite existing select or type dataset name/i, + name: /overwrite existing/i, }); const fieldLabel = screen.getByText(/overwrite existing/i); const inputField = screen.getByRole('combobox'); @@ -62,15 +80,99 @@ describe('SaveDatasetModal RTL', () => { expect(placeholderText).toBeVisible(); }); - it('renders a save button', () => { + it('renders a close button', () => { + render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); + + expect(screen.getByRole('button', { name: /close/i })).toBeVisible(); + }); + + it('renders a save button when "Save as new" is selected', () => { render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); + // "Save as new" is selected when the modal opens by default expect(screen.getByRole('button', { name: /save/i })).toBeVisible(); }); - it('renders a close button', () => { + it('renders an overwrite button when "Overwrite existing" is selected', () => { + render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); + + // Click the overwrite radio button to reveal the overwrite confirmation and back buttons + const overwriteRadioBtn = screen.getByRole('radio', { + name: /overwrite existing/i, + }); + userEvent.click(overwriteRadioBtn); + + expect(screen.getByRole('button', { name: /overwrite/i })).toBeVisible(); + }); + + it('renders the overwrite button as disabled until an existing dataset is selected', async () => { + useSelectorMock.mockReturnValue({ ...user }); render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); + // Click the overwrite radio button + const overwriteRadioBtn = screen.getByRole('radio', { + name: /overwrite existing/i, + }); + userEvent.click(overwriteRadioBtn); + + // Overwrite confirmation button should be disabled at this point + const overwriteConfirmationBtn = screen.getByRole('button', { + name: /overwrite/i, + }); + expect(overwriteConfirmationBtn).toBeDisabled(); + + // Click the overwrite select component + const select = screen.getByRole('combobox', { name: /existing dataset/i })!; + userEvent.click(select); + + await waitFor(() => + expect(screen.queryByText('Loading...')).not.toBeVisible(), + ); + + // Select the first "existing dataset" from the listbox + const option = screen.getAllByText('coolest table 0')[1]; + userEvent.click(option); + + // Overwrite button should now be enabled + expect(overwriteConfirmationBtn).toBeEnabled(); + }); + + it('renders a confirm overwrite screen when overwrite is clicked', async () => { + useSelectorMock.mockReturnValue({ ...user }); + render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); + + // Click the overwrite radio button + const overwriteRadioBtn = screen.getByRole('radio', { + name: /overwrite existing/i, + }); + userEvent.click(overwriteRadioBtn); + + // Click the overwrite select component + const select = screen.getByRole('combobox', { name: /existing dataset/i }); + userEvent.click(select); + + await waitFor(() => + expect(screen.queryByText('Loading...')).not.toBeVisible(), + ); + + // Select the first "existing dataset" from the listbox + const option = screen.getAllByText('coolest table 0')[1]; + userEvent.click(option); + + // Click the overwrite button to access the confirmation screen + const overwriteConfirmationBtn = screen.getByRole('button', { + name: /overwrite/i, + }); + userEvent.click(overwriteConfirmationBtn); + + // Overwrite screen text + expect(screen.getByText(/save or overwrite dataset/i)).toBeVisible(); + expect( + screen.getByText(/are you sure you want to overwrite this dataset\?/i), + ).toBeVisible(); + // Overwrite screen buttons expect(screen.getByRole('button', { name: /close/i })).toBeVisible(); + expect(screen.getByRole('button', { name: /back/i })).toBeVisible(); + expect(screen.getByRole('button', { name: /overwrite/i })).toBeVisible(); }); }); diff --git a/superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx b/superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx index 94b67a6fb309f..949323b9aa75c 100644 --- a/superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx +++ b/superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx @@ -17,9 +17,9 @@ * under the License. */ -import React, { FunctionComponent, useState } from 'react'; +import React, { useCallback, useState } from 'react'; import { Radio } from 'src/components/Radio'; -import { AutoComplete, RadioChangeEvent } from 'src/components'; +import { RadioChangeEvent, AsyncSelect } from 'src/components'; import { Input } from 'src/components/Input'; import StyledModal from 'src/components/Modal'; import Button from 'src/components/Button'; @@ -27,10 +27,10 @@ import { styled, t, SupersetClient, - makeApi, JsonResponse, JsonObject, QueryResponse, + QueryFormData, } from '@superset-ui/core'; import { useSelector, useDispatch } from 'react-redux'; import moment from 'moment'; @@ -42,12 +42,45 @@ import { DatasetRadioState, EXPLORE_CHART_DEFAULT, DatasetOwner, - DatasetOptionAutocomplete, SqlLabExploreRootState, getInitialState, - ExploreDatasource, + SqlLabRootState, } from 'src/SqlLab/types'; -import { exploreChart } from 'src/explore/exploreUtils'; +import { mountExploreUrl } from 'src/explore/exploreUtils'; +import { postFormData } from 'src/explore/exploreUtils/formData'; +import { URL_PARAMS } from 'src/constants'; +import { SelectValue } from 'antd/lib/select'; +import { isEmpty, isString } from 'lodash'; + +interface QueryDatabase { + id?: number; +} + +export type ExploreQuery = QueryResponse & { + database?: QueryDatabase | null | undefined; +}; + +export interface ISimpleColumn { + name?: string | null; + type?: string | null; + is_dttm?: boolean | null; +} + +export type Database = { + backend: string; + id: number; + parameter: object; +}; + +export interface ISaveableDatasource { + columns: ISimpleColumn[]; + name: string; + dbId: number; + sql: string; + templateParams?: string | object | null; + schema?: string | null; + database?: Database; +} interface SaveDatasetModalProps { visible: boolean; @@ -55,7 +88,9 @@ interface SaveDatasetModalProps { buttonTextOnSave: string; buttonTextOnOverwrite: string; modalDescription?: string; - datasource: ExploreDatasource; + datasource: ISaveableDatasource; + openWindow?: boolean; + formData?: Omit<QueryFormData, 'datasource'>; } const Styles = styled.div` @@ -67,8 +102,8 @@ const Styles = styled.div` width: 401px; } .sdm-autocomplete { - margin-left: 8px; width: 401px; + align-self: center; } .sdm-radio { display: block; @@ -79,6 +114,10 @@ const Styles = styled.div` .sdm-overwrite-msg { margin: 7px; } + .sdm-overwrite-container { + flex: 1 1 auto; + display: flex; + } `; const updateDataset = async ( @@ -106,76 +145,101 @@ const updateDataset = async ( return data.json.result; }; -// eslint-disable-next-line no-empty-pattern -export const SaveDatasetModal: FunctionComponent<SaveDatasetModalProps> = ({ +const UNTITLED = t('Untitled Dataset'); + +export const SaveDatasetModal = ({ visible, onHide, buttonTextOnSave, buttonTextOnOverwrite, modalDescription, datasource, -}) => { - const query = datasource as QueryResponse; + openWindow = true, + formData = {}, +}: SaveDatasetModalProps) => { + const defaultVizType = useSelector<SqlLabRootState, string>( + state => state.common?.conf?.DEFAULT_VIZ_TYPE || 'table', + ); + const getDefaultDatasetName = () => - `${query.tab} ${moment().format('MM/DD/YYYY HH:mm:ss')}`; + `${datasource?.name || UNTITLED} ${moment().format('MM/DD/YYYY HH:mm:ss')}`; const [datasetName, setDatasetName] = useState(getDefaultDatasetName()); const [newOrOverwrite, setNewOrOverwrite] = useState( DatasetRadioState.SAVE_NEW, ); const [shouldOverwriteDataset, setShouldOverwriteDataset] = useState(false); - const [userDatasetOptions, setUserDatasetOptions] = useState< - DatasetOptionAutocomplete[] - >([]); const [datasetToOverwrite, setDatasetToOverwrite] = useState< Record<string, any> >({}); - const [autocompleteValue, setAutocompleteValue] = useState(''); + const [selectedDatasetToOverwrite, setSelectedDatasetToOverwrite] = useState< + SelectValue | undefined + >(undefined); const user = useSelector<SqlLabExploreRootState, User>(user => getInitialState(user), ); const dispatch = useDispatch<(dispatch: any) => Promise<JsonObject>>(); + const createWindow = (url: string) => { + if (openWindow) { + window.open(url, '_blank', 'noreferrer'); + } else { + window.location.href = url; + } + }; + const formDataWithDefaults = { + ...EXPLORE_CHART_DEFAULT, + ...(formData || {}), + }; const handleOverwriteDataset = async () => { - await updateDataset( - query.dbId, - datasetToOverwrite.datasetId, - query.sql, - query.results.selected_columns.map( - (d: { name: string; type: string; is_dttm: boolean }) => ({ - column_name: d.name, - type: d.type, - is_dttm: d.is_dttm, - }), + // if user wants to overwrite a dataset we need to prompt them + if (!shouldOverwriteDataset) { + setShouldOverwriteDataset(true); + return; + } + const [, key] = await Promise.all([ + updateDataset( + datasource?.dbId, + datasetToOverwrite?.datasetid, + datasource?.sql, + datasource?.columns?.map( + (d: { name: string; type: string; is_dttm: boolean }) => ({ + column_name: d.name, + type: d.type, + is_dttm: d.is_dttm, + }), + ), + datasetToOverwrite?.owners?.map((o: DatasetOwner) => o.id), + true, ), - datasetToOverwrite.owners.map((o: DatasetOwner) => o.id), - true, - ); + postFormData(datasetToOverwrite.datasetid, 'table', { + ...formDataWithDefaults, + datasource: `${datasetToOverwrite.datasetid}__table`, + ...(defaultVizType === 'table' && { + all_columns: datasource?.columns?.map(column => column.name), + }), + }), + ]); + + const url = mountExploreUrl(null, { + [URL_PARAMS.formDataKey.name]: key, + }); + createWindow(url); setShouldOverwriteDataset(false); - setDatasetToOverwrite({}); setDatasetName(getDefaultDatasetName()); - - exploreChart({ - ...EXPLORE_CHART_DEFAULT, - datasource: `${datasetToOverwrite.datasetId}__table`, - all_columns: query.results.selected_columns.map( - (d: { name: string; type: string; is_dttm: boolean }) => d.name, - ), - }); + onHide(); }; - const getUserDatasets = async (searchText = '') => { - // Making sure that autocomplete input has a value before rendering the dropdown - // Transforming the userDatasetsOwned data for SaveModalComponent) - const { userId } = user; - if (userId) { + const loadDatasetOverwriteOptions = useCallback( + async (input = '') => { + const { userId } = user; const queryParams = rison.encode({ filters: [ { col: 'table_name', opr: 'ct', - value: searchText, + value: input, }, { col: 'owners', @@ -187,85 +251,78 @@ export const SaveDatasetModal: FunctionComponent<SaveDatasetModalProps> = ({ order_direction: 'desc', }); - const response = await makeApi({ - method: 'GET', - endpoint: '/api/v1/dataset', - })(`q=${queryParams}`); - - return response.result.map( - (r: { table_name: string; id: number; owners: [DatasetOwner] }) => ({ - value: r.table_name, - datasetId: r.id, - owners: r.owners, - }), - ); - } - - return null; - }; + return SupersetClient.get({ + endpoint: `/api/v1/dataset?q=${queryParams}`, + }).then(response => ({ + data: response.json.result.map( + (r: { table_name: string; id: number; owners: [DatasetOwner] }) => ({ + value: r.table_name, + label: r.table_name, + datasetid: r.id, + owners: r.owners, + }), + ), + totalCount: response.json.count, + })); + }, + [user], + ); const handleSaveInDataset = () => { - // if user wants to overwrite a dataset we need to prompt them - if (newOrOverwrite === DatasetRadioState.OVERWRITE_DATASET) { - setShouldOverwriteDataset(true); - return; - } - - const selectedColumns = query.results.selected_columns || []; + const selectedColumns = datasource?.columns ?? []; // The filters param is only used to test jinja templates. // Remove the special filters entry from the templateParams // before saving the dataset. - if (query.templateParams) { - const p = JSON.parse(query.templateParams); + let templateParams; + if (isString(datasource?.templateParams)) { + const p = JSON.parse(datasource.templateParams); /* eslint-disable-next-line no-underscore-dangle */ if (p._filters) { /* eslint-disable-next-line no-underscore-dangle */ delete p._filters; // eslint-disable-next-line no-param-reassign - query.templateParams = JSON.stringify(p); + templateParams = JSON.stringify(p); } } dispatch( createDatasource({ - schema: query.schema, - sql: query.sql, - dbId: query.dbId, - templateParams: query.templateParams, + schema: datasource.schema, + sql: datasource.sql, + dbId: datasource.dbId || datasource?.database?.id, + templateParams, datasourceName: datasetName, columns: selectedColumns, }), ) - .then((data: { table_id: number }) => { - exploreChart({ + .then((data: { table_id: number }) => + postFormData(data.table_id, 'table', { + ...formDataWithDefaults, datasource: `${data.table_id}__table`, - metrics: [], - groupby: [], - time_range: 'No filter', - viz_type: 'table', - all_columns: selectedColumns.map(c => c.name), - row_limit: 1000, + ...(defaultVizType === 'table' && { + all_columns: selectedColumns.map(column => column.name), + }), + }), + ) + .then((key: string) => { + const url = mountExploreUrl(null, { + [URL_PARAMS.formDataKey.name]: key, }); + createWindow(url); + setDatasetName(getDefaultDatasetName()); + onHide(); }) .catch(() => { addDangerToast(t('An error occurred saving dataset')); }); - - setDatasetName(getDefaultDatasetName()); - onHide(); }; - const handleSaveDatasetModalSearch = async (searchText: string) => { - const userDatasetsOwned = await getUserDatasets(searchText); - setUserDatasetOptions(userDatasetsOwned); + const handleOverwriteDatasetOption = (value: SelectValue, option: any) => { + setDatasetToOverwrite(option); + setSelectedDatasetToOverwrite(value); }; - const handleOverwriteDatasetOption = ( - _data: string, - option: Record<string, any>, - ) => setDatasetToOverwrite(option); - const handleDatasetNameChange = (e: React.FormEvent<HTMLInputElement>) => { // @ts-expect-error setDatasetName(e.target.value); @@ -280,12 +337,11 @@ export const SaveDatasetModal: FunctionComponent<SaveDatasetModalProps> = ({ (newOrOverwrite === DatasetRadioState.SAVE_NEW && datasetName.length === 0) || (newOrOverwrite === DatasetRadioState.OVERWRITE_DATASET && - Object.keys(datasetToOverwrite).length === 0 && - autocompleteValue.length === 0); + isEmpty(selectedDatasetToOverwrite)); const filterAutocompleteOption = ( inputValue: string, - option: { value: string; datasetId: number }, + option: { value: string; datasetid: number }, ) => option.value.toLowerCase().includes(inputValue.toLowerCase()); return ( @@ -295,7 +351,7 @@ export const SaveDatasetModal: FunctionComponent<SaveDatasetModalProps> = ({ onHide={onHide} footer={ <> - {!shouldOverwriteDataset && ( + {newOrOverwrite === DatasetRadioState.SAVE_NEW && ( <Button disabled={disableSaveAndExploreBtn} buttonStyle="primary" @@ -304,9 +360,11 @@ export const SaveDatasetModal: FunctionComponent<SaveDatasetModalProps> = ({ {buttonTextOnSave} </Button> )} - {shouldOverwriteDataset && ( + {newOrOverwrite === DatasetRadioState.OVERWRITE_DATASET && ( <> - <Button onClick={handleOverwriteCancel}>Back</Button> + {shouldOverwriteDataset && ( + <Button onClick={handleOverwriteCancel}>{t('Back')}</Button> + )} <Button className="md" buttonStyle="primary" @@ -336,28 +394,30 @@ export const SaveDatasetModal: FunctionComponent<SaveDatasetModalProps> = ({ {t('Save as new')} <Input className="sdm-input" - defaultValue={datasetName} + value={datasetName} onChange={handleDatasetNameChange} disabled={newOrOverwrite !== 1} /> </Radio> - <Radio className="sdm-radio" value={2}> - {t('Overwrite existing')} - <AutoComplete - className="sdm-autocomplete" - options={userDatasetOptions} - onSelect={handleOverwriteDatasetOption} - onSearch={handleSaveDatasetModalSearch} - onChange={value => { - setDatasetToOverwrite({}); - setAutocompleteValue(value); - }} - placeholder={t('Select or type dataset name')} - filterOption={filterAutocompleteOption} - disabled={newOrOverwrite !== 2} - value={autocompleteValue} - /> - </Radio> + <div className="sdm-overwrite-container"> + <Radio className="sdm-radio" value={2}> + {t('Overwrite existing')} + </Radio> + <div className="sdm-autocomplete"> + <AsyncSelect + allowClear + showSearch + placeholder={t('Select or type dataset name')} + ariaLabel={t('Existing dataset')} + onChange={handleOverwriteDatasetOption} + options={input => loadDatasetOverwriteOptions(input)} + value={selectedDatasetToOverwrite} + filterOption={filterAutocompleteOption} + disabled={newOrOverwrite !== 2} + getPopupContainer={() => document.body} + /> + </div> + </div> </Radio.Group> </div> )} diff --git a/superset-frontend/src/SqlLab/components/SaveQuery/SaveQuery.test.jsx b/superset-frontend/src/SqlLab/components/SaveQuery/SaveQuery.test.jsx deleted file mode 100644 index 76f6ca8260a60..0000000000000 --- a/superset-frontend/src/SqlLab/components/SaveQuery/SaveQuery.test.jsx +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import { shallow } from 'enzyme'; -import * as sinon from 'sinon'; -import SaveQuery from 'src/SqlLab/components/SaveQuery'; -import Modal from 'src/components/Modal'; -import Button from 'src/components/Button'; -import { FormItem } from 'src/components/Form'; - -describe('SavedQuery', () => { - const mockedProps = { - query: { - dbId: 1, - schema: 'main', - sql: 'SELECT * FROM t', - }, - defaultLabel: 'untitled', - animation: false, - }; - it('is valid', () => { - expect(React.isValidElement(<SaveQuery />)).toBe(true); - }); - it('is valid with props', () => { - expect(React.isValidElement(<SaveQuery {...mockedProps} />)).toBe(true); - }); - it('has a Modal', () => { - const wrapper = shallow(<SaveQuery {...mockedProps} />); - expect(wrapper.find(Modal)).toExist(); - }); - // TODO: eschutho convert test to RTL - // eslint-disable-next-line jest/no-disabled-tests - it.skip('has a cancel button', () => { - const wrapper = shallow(<SaveQuery {...mockedProps} />); - const modal = wrapper.find(Modal); - - expect(modal.find('[data-test="cancel-query"]')).toHaveLength(1); - }); - it('has 2 FormItem', () => { - const wrapper = shallow(<SaveQuery {...mockedProps} />); - const modal = wrapper.find(Modal); - - expect(modal.find(FormItem)).toHaveLength(2); - }); - // eslint-disable-next-line jest/no-disabled-tests - it.skip('has a save button if this is a new query', () => { - const saveSpy = sinon.spy(); - const wrapper = shallow(<SaveQuery {...mockedProps} onSave={saveSpy} />); - const modal = wrapper.find(Modal); - - expect(modal.find(Button)).toHaveLength(2); - modal.find(Button).at(0).simulate('click'); - expect(saveSpy.calledOnce).toBe(true); - }); - // eslint-disable-next-line jest/no-disabled-tests - it.skip('has an update button if this is an existing query', () => { - const updateSpy = sinon.spy(); - const props = { - ...mockedProps, - query: { - ...mockedProps.query, - remoteId: '42', - }, - }; - const wrapper = shallow(<SaveQuery {...props} onUpdate={updateSpy} />); - const modal = wrapper.find(Modal); - - expect(modal.find(Button)).toHaveLength(3); - modal.find(Button).at(0).simulate('click'); - expect(updateSpy.calledOnce).toBe(true); - }); -}); diff --git a/superset-frontend/src/SqlLab/components/SaveQuery/SaveQuery.test.tsx b/superset-frontend/src/SqlLab/components/SaveQuery/SaveQuery.test.tsx new file mode 100644 index 0000000000000..f321a54ec4dbe --- /dev/null +++ b/superset-frontend/src/SqlLab/components/SaveQuery/SaveQuery.test.tsx @@ -0,0 +1,225 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import SaveQuery from 'src/SqlLab/components/SaveQuery'; +import { initialState, databases } from 'src/SqlLab/fixtures'; + +const mockedProps = { + queryEditorId: '123', + animation: false, + database: databases.result[0], + onUpdate: () => {}, + onSave: () => {}, + saveQueryWarning: null, + columns: [], +}; + +const mockState = { + ...initialState, + sqlLab: { + ...initialState.sqlLab, + queryEditors: [ + { + id: mockedProps.queryEditorId, + dbId: 1, + schema: 'main', + sql: 'SELECT * FROM t', + }, + ], + }, +}; + +const splitSaveBtnProps = { + ...mockedProps, + database: { + ...mockedProps.database, + allows_virtual_table_explore: true, + }, +}; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); + +describe('SavedQuery', () => { + it('renders a non-split save button when allows_virtual_table_explore is not enabled', () => { + render(<SaveQuery {...mockedProps} />, { + useRedux: true, + store: mockStore(mockState), + }); + + const saveBtn = screen.getByRole('button', { name: /save/i }); + + expect(saveBtn).toBeVisible(); + }); + + it('renders a save query modal when user clicks save button', () => { + render(<SaveQuery {...mockedProps} />, { + useRedux: true, + store: mockStore(mockState), + }); + + const saveBtn = screen.getByRole('button', { name: /save/i }); + userEvent.click(saveBtn); + + const saveQueryModalHeader = screen.getByRole('heading', { + name: /save query/i, + }); + + expect(saveQueryModalHeader).toBeVisible(); + }); + + it('renders the save query modal UI', () => { + render(<SaveQuery {...mockedProps} />, { + useRedux: true, + store: mockStore(mockState), + }); + + const saveBtn = screen.getByRole('button', { name: /save/i }); + userEvent.click(saveBtn); + + const closeBtn = screen.getByRole('button', { name: /close/i }); + const saveQueryModalHeader = screen.getByRole('heading', { + name: /save query/i, + }); + const nameLabel = screen.getByText(/name/i); + const descriptionLabel = screen.getByText(/description/i); + const textBoxes = screen.getAllByRole('textbox'); + const nameTextbox = textBoxes[0]; + const descriptionTextbox = textBoxes[1]; + // There are now two save buttons, the initial save button and the modal save button + const saveBtns = screen.getAllByRole('button', { name: /save/i }); + const cancelBtn = screen.getByRole('button', { name: /cancel/i }); + + expect(closeBtn).toBeVisible(); + expect(saveQueryModalHeader).toBeVisible(); + expect(nameLabel).toBeVisible(); + expect(descriptionLabel).toBeVisible(); + expect(textBoxes.length).toBe(2); + expect(nameTextbox).toBeVisible(); + expect(descriptionTextbox).toBeVisible(); + expect(saveBtns.length).toBe(2); + expect(saveBtns[0]).toBeVisible(); + expect(saveBtns[1]).toBeVisible(); + expect(cancelBtn).toBeVisible(); + }); + + it('renders a "save as new" and "update" button if query already exists', () => { + render(<SaveQuery {...mockedProps} />, { + useRedux: true, + store: mockStore({ + ...mockState, + sqlLab: { + ...mockState.sqlLab, + unsavedQueryEditor: { + id: mockedProps.queryEditorId, + remoteId: '42', + }, + }, + }), + }); + + const saveBtn = screen.getByRole('button', { name: /save/i }); + userEvent.click(saveBtn); + + const saveAsNewBtn = screen.getByRole('button', { name: /save as new/i }); + const updateBtn = screen.getByRole('button', { name: /update/i }); + + expect(saveAsNewBtn).toBeVisible(); + expect(updateBtn).toBeVisible(); + }); + + it('renders a split save button when allows_virtual_table_explore is enabled', async () => { + render(<SaveQuery {...splitSaveBtnProps} />, { + useRedux: true, + store: mockStore(mockState), + }); + + await waitFor(() => { + const saveBtn = screen.getByRole('button', { name: /save/i }); + const caretBtn = screen.getByRole('button', { name: /caret-down/i }); + + expect(saveBtn).toBeVisible(); + expect(caretBtn).toBeVisible(); + }); + }); + + it('renders a save dataset modal when user clicks "save dataset" menu item', async () => { + render(<SaveQuery {...splitSaveBtnProps} />, { + useRedux: true, + store: mockStore(mockState), + }); + + await waitFor(() => { + const caretBtn = screen.getByRole('button', { name: /caret-down/i }); + userEvent.click(caretBtn); + + const saveDatasetMenuItem = screen.getByText(/save dataset/i); + userEvent.click(saveDatasetMenuItem); + }); + + const saveDatasetHeader = screen.getByText(/save or overwrite dataset/i); + + expect(saveDatasetHeader).toBeVisible(); + }); + + it('renders the save dataset modal UI', async () => { + render(<SaveQuery {...splitSaveBtnProps} />, { + useRedux: true, + store: mockStore(mockState), + }); + + await waitFor(() => { + const caretBtn = screen.getByRole('button', { name: /caret-down/i }); + userEvent.click(caretBtn); + + const saveDatasetMenuItem = screen.getByText(/save dataset/i); + userEvent.click(saveDatasetMenuItem); + }); + + const closeBtn = screen.getByRole('button', { name: /close/i }); + const saveDatasetHeader = screen.getByText(/save or overwrite dataset/i); + const saveRadio = screen.getByRole('radio', { + name: /save as new untitled/i, + }); + const saveLabel = screen.getByText(/save as new/i); + const saveTextbox = screen.getByRole('textbox'); + const overwriteRadio = screen.getByRole('radio', { + name: /overwrite existing/i, + }); + const overwriteLabel = screen.getByText(/overwrite existing/i); + const overwriteCombobox = screen.getByRole('combobox'); + const overwritePlaceholderText = screen.getByText( + /select or type dataset name/i, + ); + + expect(saveDatasetHeader).toBeVisible(); + expect(closeBtn).toBeVisible(); + expect(saveRadio).toBeVisible(); + expect(saveLabel).toBeVisible(); + expect(saveTextbox).toBeVisible(); + expect(overwriteRadio).toBeVisible(); + expect(overwriteLabel).toBeVisible(); + expect(overwriteCombobox).toBeVisible(); + expect(overwritePlaceholderText).toBeVisible(); + }); +}); diff --git a/superset-frontend/src/SqlLab/components/SaveQuery/index.tsx b/superset-frontend/src/SqlLab/components/SaveQuery/index.tsx index 2b57ce0cdcc59..684c4ed39c425 100644 --- a/superset-frontend/src/SqlLab/components/SaveQuery/index.tsx +++ b/superset-frontend/src/SqlLab/components/SaveQuery/index.tsx @@ -16,14 +16,38 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useMemo } from 'react'; import { Row, Col } from 'src/components'; import { Input, TextArea } from 'src/components/Input'; import { t, styled } from '@superset-ui/core'; import Button from 'src/components/Button'; +import { Menu } from 'src/components/Menu'; import { Form, FormItem } from 'src/components/Form'; import Modal from 'src/components/Modal'; -import Icons from 'src/components/Icons'; +import SaveDatasetActionButton from 'src/SqlLab/components/SaveDatasetActionButton'; +import { + SaveDatasetModal, + ISaveableDatasource, +} from 'src/SqlLab/components/SaveDatasetModal'; +import { getDatasourceAsSaveableDataset } from 'src/utils/datasourceUtils'; +import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; +import { QueryEditor } from 'src/SqlLab/types'; + +interface SaveQueryProps { + queryEditorId: string; + columns: ISaveableDatasource['columns']; + onSave: (arg0: QueryPayload, id: string) => void; + onUpdate: (arg0: QueryPayload, id: string) => void; + saveQueryWarning: string | null; + database: Record<string, any>; +} + +type QueryPayload = { + name: string; + description?: string; + id?: string; + remoteId?: number; +} & Pick<QueryEditor, 'dbId' | 'schema' | 'sql'>; const Styles = styled.span` span[role='img'] { @@ -37,76 +61,77 @@ const Styles = styled.span` } `; -interface SaveQueryProps { - query: any; - defaultLabel: string; - onSave: (arg0: QueryPayload) => void; - onUpdate: (arg0: QueryPayload) => void; - saveQueryWarning: string | null; -} - -type QueryPayload = { - autorun: boolean; - dbId: number; - description?: string; - id?: string; - latestQueryId: string; - queryLimit: number; - remoteId: number; - schema: string; - schemaOptions: Array<{ - label: string; - title: string; - value: string; - }>; - selectedText: string | null; - sql: string; - tableOptions: Array<{ - label: string; - schema: string; - title: string; - type: string; - value: string; - }>; - title: string; -}; - -export default function SaveQuery({ - query, - defaultLabel = t('Undefined'), +const SaveQuery = ({ + queryEditorId, onSave = () => {}, onUpdate, saveQueryWarning = null, -}: SaveQueryProps) { + database, + columns, +}: SaveQueryProps) => { + const queryEditor = useQueryEditor(queryEditorId, [ + 'autorun', + 'name', + 'description', + 'remoteId', + 'dbId', + 'latestQueryId', + 'queryLimit', + 'schema', + 'schemaOptions', + 'selectedText', + 'sql', + 'tableOptions', + 'templateParams', + ]); + const query = useMemo( + () => ({ + ...queryEditor, + columns, + }), + [queryEditor, columns], + ); + const defaultLabel = query.name || query.description || t('Undefined'); const [description, setDescription] = useState<string>( query.description || '', ); const [label, setLabel] = useState<string>(defaultLabel); const [showSave, setShowSave] = useState<boolean>(false); + const [showSaveDatasetModal, setShowSaveDatasetModal] = useState(false); const isSaved = !!query.remoteId; + const canExploreDatabase = !!database?.allows_virtual_table_explore; + + const overlayMenu = ( + <Menu> + <Menu.Item onClick={() => setShowSaveDatasetModal(true)}> + {t('Save dataset')} + </Menu.Item> + </Menu> + ); const queryPayload = () => ({ - ...query, - title: label, + name: label, description, + dbId: query.dbId ?? 0, + sql: query.sql, + schema: query.schema, + templateParams: query.templateParams, + remoteId: query?.remoteId || undefined, }); useEffect(() => { - if (!isSaved) { - setLabel(defaultLabel); - } + if (!isSaved) setLabel(defaultLabel); }, [defaultLabel]); - const close = () => { - setShowSave(false); - }; + + const close = () => setShowSave(false); const onSaveWrapper = () => { - onSave(queryPayload()); + onSave(queryPayload(), query.id); close(); }; const onUpdateWrapper = () => { - onUpdate(queryPayload()); + onUpdate(queryPayload(), query.id); close(); }; @@ -118,10 +143,6 @@ export default function SaveQuery({ setDescription(e.target.value); }; - const toggleSave = () => { - setShowSave(!showSave); - }; - const renderModalBody = () => ( <Form layout="vertical"> <Row> @@ -161,10 +182,17 @@ export default function SaveQuery({ return ( <Styles className="SaveQuery"> - <Button buttonSize="small" onClick={toggleSave}> - <Icons.Save iconSize="xl" /> - {isSaved ? t('Save') : t('Save as')} - </Button> + <SaveDatasetActionButton + setShowSave={setShowSave} + overlayMenu={canExploreDatabase ? overlayMenu : null} + /> + <SaveDatasetModal + visible={showSaveDatasetModal} + onHide={() => setShowSaveDatasetModal(false)} + buttonTextOnSave={t('Save & Explore')} + buttonTextOnOverwrite={t('Overwrite & Explore')} + datasource={getDatasourceAsSaveableDataset(query)} + /> <Modal className="save-query-modal" onHandledPrimaryAction={onSaveWrapper} @@ -173,7 +201,7 @@ export default function SaveQuery({ width="620px" show={showSave} title={<h4>{t('Save query')}</h4>} - footer={[ + footer={ <> <Button onClick={close} data-test="cancel-query" cta> {t('Cancel')} @@ -196,11 +224,13 @@ export default function SaveQuery({ {t('Update')} </Button> )} - </>, - ]} + </> + } > {renderModalBody()} </Modal> </Styles> ); -} +}; + +export default SaveQuery; diff --git a/superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx b/superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx index facb23461c353..d0a381638d9a2 100644 --- a/superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx +++ b/superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx @@ -16,20 +16,18 @@ * specific language governing permissions and limitations * under the License. */ -import React, { FunctionComponent, useState } from 'react'; +import React, { FunctionComponent, useState, useRef } from 'react'; import SchemaForm, { FormProps, FormValidation } from 'react-jsonschema-form'; import { Row, Col } from 'src/components'; import { Input, TextArea } from 'src/components/Input'; import { t, styled } from '@superset-ui/core'; import * as chrono from 'chrono-node'; -import ModalTrigger from 'src/components/ModalTrigger'; +import ModalTrigger, { ModalTriggerRef } from 'src/components/ModalTrigger'; import { Form, FormItem } from 'src/components/Form'; import Button from 'src/components/Button'; +import getBootstrapData from 'src/utils/getBootstrapData'; -const appContainer = document.getElementById('app'); -const bootstrapData = JSON.parse( - appContainer?.getAttribute('data-bootstrap') || '{}', -); +const bootstrapData = getBootstrapData(); const scheduledQueriesConf = bootstrapData?.common?.conf?.SCHEDULED_QUERIES; const validators = { @@ -101,7 +99,9 @@ export const StyledButtonComponent = styled(Button)` color: ${theme.colors.grayscale.dark2}; font-size: 14px; font-weight: ${theme.typography.weights.normal}; + margin-left: 0; &:disabled { + margin-left: 0; background: none; color: ${theme.colors.grayscale.dark2}; &:hover { @@ -143,7 +143,7 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({ const [description, setDescription] = useState(''); const [label, setLabel] = useState(defaultLabel); const [showSchedule, setShowSchedule] = useState(false); - let saveModal: ModalTrigger | null; + const saveModal: ModalTriggerRef | null = useRef() as ModalTriggerRef; const onScheduleSubmit = ({ formData, @@ -159,7 +159,7 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({ extra_json: JSON.stringify({ schedule_info: formData }), }; onSchedule(query); - saveModal?.close(); + saveModal?.current?.close(); }; const renderModalBody = () => ( @@ -197,7 +197,7 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({ <StyledJsonSchema> <SchemaForm schema={getJSONSchema()} - uiSchema={getUISchema} + uiSchema={getUISchema()} onSubmit={onScheduleSubmit} validate={getValidator()} > @@ -206,7 +206,7 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({ htmlType="submit" css={{ float: 'right' }} > - Submit + {t('Submit')} </Button> </SchemaForm> </StyledJsonSchema> @@ -225,9 +225,7 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({ return ( <span className="ScheduleQueryButton"> <ModalTrigger - ref={ref => { - saveModal = ref; - }} + ref={saveModal} modalTitle={t('Schedule query')} modalBody={renderModalBody()} triggerNode={ diff --git a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.jsx b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx similarity index 65% rename from superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.jsx rename to superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx index 8a68d386a56a4..6e9775c3a5bae 100644 --- a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.jsx +++ b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx @@ -28,29 +28,69 @@ import '@testing-library/jest-dom/extend-expect'; import userEvent from '@testing-library/user-event'; import * as utils from 'src/utils/common'; import ShareSqlLabQuery from 'src/SqlLab/components/ShareSqlLabQuery'; +import { initialState } from 'src/SqlLab/fixtures'; const mockStore = configureStore([thunk]); -const store = mockStore({}); -let isFeatureEnabledMock; +const defaultProps = { + queryEditorId: 'qe1', + addDangerToast: jest.fn(), +}; +const mockQueryEditor = { + id: defaultProps.queryEditorId, + dbId: 0, + name: 'query title', + schema: 'query_schema', + autorun: false, + sql: 'SELECT * FROM ...', + remoteId: 999, +}; +const disabled = { + id: 'disabledEditorId', + remoteId: undefined, +}; + +const mockState = { + ...initialState, + sqlLab: { + ...initialState.sqlLab, + queryEditors: [mockQueryEditor, disabled], + }, +}; +const store = mockStore(mockState); +let isFeatureEnabledMock: jest.SpyInstance; -const standardProvider = ({ children }) => ( +const standardProvider: React.FC = ({ children }) => ( <ThemeProvider theme={supersetTheme}> <Provider store={store}>{children}</Provider> </ThemeProvider> ); -const defaultProps = { - queryEditor: { - dbId: 0, - title: 'query title', - schema: 'query_schema', - autorun: false, - sql: 'SELECT * FROM ...', - remoteId: 999, - }, - addDangerToast: jest.fn(), +const unsavedQueryEditor = { + id: defaultProps.queryEditorId, + dbId: 9888, + name: 'query title changed', + schema: 'query_schema_updated', + sql: 'SELECT * FROM Updated Limit 100', + autorun: true, + templateParams: '{ "my_value": "foo" }', }; +const standardProviderWithUnsaved: React.FC = ({ children }) => ( + <ThemeProvider theme={supersetTheme}> + <Provider + store={mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor, + }, + })} + > + {children} + </Provider> + </ThemeProvider> +); + describe('ShareSqlLabQuery', () => { const storeQueryUrl = 'glob:*/kv/store/'; const storeQueryMockId = '123'; @@ -73,7 +113,7 @@ describe('ShareSqlLabQuery', () => { }); afterAll(() => { - isFeatureEnabledMock.restore(); + isFeatureEnabledMock.mockReset(); }); it('calls storeQuery() with the query when getCopyUrl() is called', async () => { @@ -83,9 +123,26 @@ describe('ShareSqlLabQuery', () => { }); }); const button = screen.getByRole('button'); + const { id, remoteId, ...expected } = mockQueryEditor; + const storeQuerySpy = jest.spyOn(utils, 'storeQuery'); + userEvent.click(button); + expect(storeQuerySpy.mock.calls).toHaveLength(1); + expect(storeQuerySpy).toBeCalledWith(expected); + storeQuerySpy.mockRestore(); + }); + + it('calls storeQuery() with unsaved changes', async () => { + await act(async () => { + render(<ShareSqlLabQuery {...defaultProps} />, { + wrapper: standardProviderWithUnsaved, + }); + }); + const button = screen.getByRole('button'); + const { id, ...expected } = unsavedQueryEditor; const storeQuerySpy = jest.spyOn(utils, 'storeQuery'); userEvent.click(button); expect(storeQuerySpy.mock.calls).toHaveLength(1); + expect(storeQuerySpy).toBeCalledWith(expected); storeQuerySpy.mockRestore(); }); }); @@ -98,7 +155,7 @@ describe('ShareSqlLabQuery', () => { }); afterAll(() => { - isFeatureEnabledMock.restore(); + isFeatureEnabledMock.mockReset(); }); it('does not call storeQuery() with the query when getCopyUrl() is called and feature is not enabled', async () => { @@ -116,10 +173,7 @@ describe('ShareSqlLabQuery', () => { it('button is disabled and there is a request to save the query', async () => { const updatedProps = { - queryEditor: { - ...defaultProps.queryEditor, - remoteId: undefined, - }, + queryEditorId: disabled.id, }; render(<ShareSqlLabQuery {...updatedProps} />, { diff --git a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx index 5f473c642fd31..73a774964678e 100644 --- a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx +++ b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx @@ -25,10 +25,10 @@ import CopyToClipboard from 'src/components/CopyToClipboard'; import { storeQuery } from 'src/utils/common'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; -import { QueryEditor } from 'src/SqlLab/types'; +import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; -interface ShareSqlLabQueryPropTypes { - queryEditor: QueryEditor; +interface ShareSqlLabQueryProps { + queryEditorId: string; addDangerToast: (msg: string) => void; } @@ -42,15 +42,25 @@ const StyledIcon = styled(Icons.Link)` } `; -function ShareSqlLabQuery({ - queryEditor, +const ShareSqlLabQuery = ({ + queryEditorId, addDangerToast, -}: ShareSqlLabQueryPropTypes) { +}: ShareSqlLabQueryProps) => { const theme = useTheme(); + const { dbId, name, schema, autorun, sql, remoteId, templateParams } = + useQueryEditor(queryEditorId, [ + 'dbId', + 'name', + 'schema', + 'autorun', + 'sql', + 'remoteId', + 'templateParams', + ]); + const getCopyUrlForKvStore = (callback: Function) => { - const { dbId, title, schema, autorun, sql } = queryEditor; - const sharedQuery = { dbId, title, schema, autorun, sql }; + const sharedQuery = { dbId, name, schema, autorun, sql, templateParams }; return storeQuery(sharedQuery) .then(shortUrl => { @@ -66,10 +76,10 @@ function ShareSqlLabQuery({ const getCopyUrlForSavedQuery = (callback: Function) => { let savedQueryToastContent; - if (queryEditor.remoteId) { + if (remoteId) { savedQueryToastContent = `${ window.location.origin + window.location.pathname - }?savedQueryId=${queryEditor.remoteId}`; + }?savedQueryId=${remoteId}`; callback(savedQueryToastContent); } else { savedQueryToastContent = t('Please save the query to enable sharing'); @@ -101,8 +111,7 @@ function ShareSqlLabQuery({ }; const canShare = - !!queryEditor.remoteId || - isFeatureEnabled(FeatureFlag.SHARE_QUERIES_VIA_KV_STORE); + !!remoteId || isFeatureEnabled(FeatureFlag.SHARE_QUERIES_VIA_KV_STORE); return ( <> @@ -117,6 +126,6 @@ function ShareSqlLabQuery({ )} </> ); -} +}; export default withToasts(ShareSqlLabQuery); diff --git a/superset-frontend/src/SqlLab/components/SouthPane/SouthPane.test.jsx b/superset-frontend/src/SqlLab/components/SouthPane/SouthPane.test.jsx index 6dfca33dbc06b..519e729c41847 100644 --- a/superset-frontend/src/SqlLab/components/SouthPane/SouthPane.test.jsx +++ b/superset-frontend/src/SqlLab/components/SouthPane/SouthPane.test.jsx @@ -19,123 +19,120 @@ import React from 'react'; import configureStore from 'redux-mock-store'; import thunk from 'redux-thunk'; -import { styledShallow as shallow } from 'spec/helpers/theming'; -import { render, screen, act } from 'spec/helpers/testing-library'; -import SouthPaneContainer from 'src/SqlLab/components/SouthPane/state'; -import ResultSet from 'src/SqlLab/components/ResultSet'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import SouthPane from 'src/SqlLab/components/SouthPane'; import '@testing-library/jest-dom/extend-expect'; import { STATUS_OPTIONS } from 'src/SqlLab/constants'; -import { initialState } from 'src/SqlLab/fixtures'; -import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; - -const NOOP = () => {}; +import { initialState, table, defaultQueryEditor } from 'src/SqlLab/fixtures'; const mockedProps = { - editorQueries: [ - { - cached: false, - changedOn: Date.now(), - db: 'main', - dbId: 1, - id: 'LCly_kkIN', - startDttm: Date.now(), - }, - { - cached: false, - changedOn: 1559238500401, - db: 'main', - dbId: 1, - id: 'lXJa7F9_r', - startDttm: 1559238500401, - }, - { - cached: false, - changedOn: 1559238506925, - db: 'main', - dbId: 1, - id: '2g2_iRFMl', - startDttm: 1559238506925, - }, - { - cached: false, - changedOn: 1559238516395, - db: 'main', - dbId: 1, - id: 'erWdqEWPm', - startDttm: 1559238516395, - }, - ], + queryEditorId: defaultQueryEditor.id, latestQueryId: 'LCly_kkIN', - dataPreviewQueries: [], - actions: {}, - activeSouthPaneTab: '', height: 1, displayLimit: 1, - databases: {}, - offline: false, + defaultQueryLimit: 100, }; const mockedEmptyProps = { - editorQueries: [], + queryEditorId: 'random_id', latestQueryId: '', - dataPreviewQueries: [], - actions: { - queryEditorSetAndSaveSql: NOOP, - cloneQueryToNewTab: NOOP, - fetchQueryResults: NOOP, - clearQueryResults: NOOP, - removeQuery: NOOP, - setActiveSouthPaneTab: NOOP, - }, - activeSouthPaneTab: '', height: 100, - databases: '', - offline: false, displayLimit: 100, - user: UserWithPermissionsAndRoles, defaultQueryLimit: 100, }; +const latestQueryProgressMsg = 'LATEST QUERY MESSAGE - LCly_kkIN'; + const middlewares = [thunk]; const mockStore = configureStore(middlewares); -const store = mockStore(initialState); -const setup = (overrides = {}) => ( - <SouthPaneContainer store={store} {...mockedProps} {...overrides} /> -); - -describe('SouthPane - Enzyme', () => { - const getWrapper = () => shallow(setup()).dive(); +const store = mockStore({ + ...initialState, + sqlLab: { + ...initialState, + offline: false, + tables: [ + { + ...table, + dataPreviewQueryId: '2g2_iRFMl', + queryEditorId: defaultQueryEditor.id, + }, + ], + databases: {}, + queries: { + LCly_kkIN: { + cached: false, + changedOn: Date.now(), + db: 'main', + dbId: 1, + id: 'LCly_kkIN', + startDttm: Date.now(), + sqlEditorId: defaultQueryEditor.id, + extra: { progress: latestQueryProgressMsg }, + }, + lXJa7F9_r: { + cached: false, + changedOn: 1559238500401, + db: 'main', + dbId: 1, + id: 'lXJa7F9_r', + startDttm: 1559238500401, + sqlEditorId: defaultQueryEditor.id, + }, + '2g2_iRFMl': { + cached: false, + changedOn: 1559238506925, + db: 'main', + dbId: 1, + id: '2g2_iRFMl', + startDttm: 1559238506925, + sqlEditorId: defaultQueryEditor.id, + }, + erWdqEWPm: { + cached: false, + changedOn: 1559238516395, + db: 'main', + dbId: 1, + id: 'erWdqEWPm', + startDttm: 1559238516395, + sqlEditorId: defaultQueryEditor.id, + }, + }, + }, +}); +const setup = (props, store) => + render(<SouthPane {...props} />, { + useRedux: true, + ...(store && { store }), + }); - let wrapper; +describe('SouthPane', () => { + const renderAndWait = (props, store) => + waitFor(async () => setup(props, store)); - it('should render offline when the state is offline', () => { - wrapper = getWrapper().dive(); - wrapper.setProps({ offline: true }); - expect(wrapper.childAt(0).text()).toBe(STATUS_OPTIONS.offline); + it('Renders an empty state for results', async () => { + await renderAndWait(mockedEmptyProps, store); + const emptyStateText = screen.getByText(/run a query to display results/i); + expect(emptyStateText).toBeVisible(); }); - it('should pass latest query down to ResultSet component', () => { - wrapper = getWrapper().dive(); - expect(wrapper.find(ResultSet)).toExist(); - expect(wrapper.find(ResultSet).props().query.id).toEqual( - mockedProps.latestQueryId, + it('should render offline when the state is offline', async () => { + await renderAndWait( + mockedEmptyProps, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + offline: true, + }, + }), ); - }); -}); -describe('SouthPane - RTL', () => { - const renderAndWait = overrides => { - const mounted = act(async () => { - render(setup(overrides)); - }); + expect(screen.getByText(STATUS_OPTIONS.offline)).toBeVisible(); + }); - return mounted; - }; - it('Renders an empty state for results', async () => { - await renderAndWait(mockedEmptyProps); + it('should pass latest query down to ResultSet component', async () => { + await renderAndWait(mockedProps, store); - const emptyStateText = screen.getByText(/run a query to display results/i); - - expect(emptyStateText).toBeVisible(); + expect(screen.getByText(latestQueryProgressMsg)).toBeVisible(); }); }); diff --git a/superset-frontend/src/SqlLab/components/SouthPane/index.tsx b/superset-frontend/src/SqlLab/components/SouthPane/index.tsx index ddcd972f9828b..0b389dfb39838 100644 --- a/superset-frontend/src/SqlLab/components/SouthPane/index.tsx +++ b/superset-frontend/src/SqlLab/components/SouthPane/index.tsx @@ -17,48 +17,38 @@ * under the License. */ import React, { createRef } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import shortid from 'shortid'; import Alert from 'src/components/Alert'; import Tabs from 'src/components/Tabs'; import { EmptyStateMedium } from 'src/components/EmptyState'; import { t, styled } from '@superset-ui/core'; +import { setActiveSouthPaneTab } from 'src/SqlLab/actions/sqlLab'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import Label from 'src/components/Label'; -import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; +import { SqlLabRootState } from 'src/SqlLab/types'; import QueryHistory from '../QueryHistory'; import ResultSet from '../ResultSet'; import { STATUS_OPTIONS, STATE_TYPE_MAP, LOCALSTORAGE_MAX_QUERY_AGE_MS, + STATUS_OPTIONS_LOCALIZED, } from '../../constants'; const TAB_HEIGHT = 140; /* editorQueries are queries executed by users passed from SqlEditor component - dataPrebiewQueries are all queries executed for preview of table data (from SqlEditorLeft) + dataPreviewQueries are all queries executed for preview of table data (from SqlEditorLeft) */ -interface SouthPanePropTypes { - editorQueries: any[]; +export interface SouthPaneProps { + queryEditorId: string; latestQueryId?: string; - dataPreviewQueries: any[]; - actions: { - queryEditorSetAndSaveSql: Function; - cloneQueryToNewTab: Function; - fetchQueryResults: Function; - clearQueryResults: Function; - removeQuery: Function; - setActiveSouthPaneTab: Function; - }; - activeSouthPaneTab?: string; height: number; - databases: Record<string, any>; - offline?: boolean; displayLimit: number; - user: UserWithPermissionsAndRoles; defaultQueryLimit: number; } @@ -110,27 +100,53 @@ const StyledEmptyStateWrapper = styled.div` } `; -export default function SouthPane({ - editorQueries, +const SouthPane = ({ + queryEditorId, latestQueryId, - dataPreviewQueries, - actions, - activeSouthPaneTab = 'Results', height, - databases, - offline = false, displayLimit, - user, defaultQueryLimit, -}: SouthPanePropTypes) { +}: SouthPaneProps) => { + const dispatch = useDispatch(); + + const { editorQueries, dataPreviewQueries, databases, offline, user } = + useSelector(({ sqlLab }: SqlLabRootState) => { + const { databases, offline, user, queries, tables } = sqlLab; + const dataPreviewQueries = tables + .filter( + ({ dataPreviewQueryId, queryEditorId: qeId }) => + dataPreviewQueryId && + queryEditorId === qeId && + queries[dataPreviewQueryId], + ) + .map(({ name, dataPreviewQueryId }) => ({ + ...queries[dataPreviewQueryId], + tableName: name, + })); + const editorQueries = Object.values(queries).filter( + ({ sqlEditorId }) => sqlEditorId === queryEditorId, + ); + return { + editorQueries, + dataPreviewQueries, + databases, + offline: offline ?? false, + user, + }; + }); + + const activeSouthPaneTab = + useSelector<SqlLabRootState, string>( + state => state.sqlLab.activeSouthPaneTab as string, + ) ?? 'Results'; const innerTabContentHeight = height - TAB_HEIGHT; const southPaneRef = createRef<HTMLDivElement>(); const switchTab = (id: string) => { - actions.setActiveSouthPaneTab(id); + dispatch(setActiveSouthPaneTab(id)); }; const renderOfflineStatus = () => ( <Label className="m-r-3" type={STATE_TYPE_MAP[STATUS_OPTIONS.offline]}> - {STATUS_OPTIONS.offline} + {STATUS_OPTIONS_LOCALIZED.offline} </Label> ); @@ -164,10 +180,8 @@ export default function SouthPane({ if (Date.now() - latestQuery.startDttm <= LOCALSTORAGE_MAX_QUERY_AGE_MS) { results = ( <ResultSet - showControls search query={latestQuery} - actions={actions} user={user} height={innerTabContentHeight + EXTRA_HEIGHT_RESULTS} database={databases[latestQuery.dbId]} @@ -199,7 +213,6 @@ export default function SouthPane({ query={query} visualize={false} csv={false} - actions={actions} cache user={user} height={innerTabContentHeight} @@ -211,7 +224,12 @@ export default function SouthPane({ return offline ? ( renderOfflineStatus() ) : ( - <StyledPane className="SouthPane" height={height} ref={southPaneRef}> + <StyledPane + data-test="south-pane" + className="SouthPane" + height={height} + ref={southPaneRef} + > <Tabs activeKey={activeSouthPaneTab} className="SouthPaneTabs" @@ -226,7 +244,6 @@ export default function SouthPane({ <Tabs.TabPane tab={t('Query history')} key="History"> <QueryHistory queries={editorQueries} - actions={actions} displayLimit={displayLimit} latestQueryId={latestQueryId} /> @@ -235,4 +252,6 @@ export default function SouthPane({ </Tabs> </StyledPane> ); -} +}; + +export default SouthPane; diff --git a/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.jsx b/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.jsx index d946c675cc8c4..9dcc37fdd188a 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.jsx +++ b/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.jsx @@ -18,6 +18,7 @@ */ import React from 'react'; import { mount } from 'enzyme'; +import { fireEvent, render, waitFor } from 'spec/helpers/testing-library'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; @@ -29,49 +30,69 @@ import { SQL_TOOLBAR_HEIGHT, } from 'src/SqlLab/constants'; import AceEditorWrapper from 'src/SqlLab/components/AceEditorWrapper'; -import ConnectedSouthPane from 'src/SqlLab/components/SouthPane/state'; +import SouthPane from 'src/SqlLab/components/SouthPane'; import SqlEditor from 'src/SqlLab/components/SqlEditor'; -import SqlEditorLeftBar from 'src/SqlLab/components/SqlEditorLeftBar'; -import { AntdDropdown } from 'src/components'; -import { - queryEditorSetFunctionNames, - queryEditorSetSelectedText, - queryEditorSetSchemaOptions, -} from 'src/SqlLab/actions/sqlLab'; -import { EmptyStateBig } from 'src/components/EmptyState'; +import QueryProvider from 'src/views/QueryProvider'; import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; -import { initialState, queries, table } from 'src/SqlLab/fixtures'; +import { + initialState, + queries, + table, + defaultQueryEditor, +} from 'src/SqlLab/fixtures'; + +jest.mock('src/components/AsyncAceEditor', () => ({ + ...jest.requireActual('src/components/AsyncAceEditor'), + FullSQLEditor: props => ( + <div data-test="react-ace">{JSON.stringify(props)}</div> + ), +})); +jest.mock('src/SqlLab/components/SqlEditorLeftBar', () => () => ( + <div data-test="mock-sql-editor-left-bar" /> +)); const MOCKED_SQL_EDITOR_HEIGHT = 500; fetchMock.get('glob:*/api/v1/database/*', { result: [] }); +fetchMock.get('glob:*/api/v1/database/*/tables/*', { options: [] }); +fetchMock.post('glob:*/sqllab/execute/*', { result: [] }); const middlewares = [thunk]; const mockStore = configureStore(middlewares); -const store = mockStore(initialState); +const store = mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + databases: { + dbid1: { + allow_ctas: false, + allow_cvas: false, + allow_dml: false, + allow_file_upload: false, + allow_run_async: false, + backend: 'postgresql', + database_name: 'examples', + expose_in_sqllab: true, + force_ctas_schema: null, + id: 1, + }, + }, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + dbId: 'dbid1', + }, + }, +}); + +const setup = (props = {}, store) => + render(<SqlEditor {...props} />, { + useRedux: true, + ...(store && { store }), + }); describe('SqlEditor', () => { const mockedProps = { - actions: { - queryEditorSetFunctionNames, - queryEditorSetSelectedText, - queryEditorSetSchemaOptions, - addDangerToast: jest.fn(), - }, - database: { - allow_ctas: false, - allow_cvas: false, - allow_dml: false, - allow_file_upload: false, - allow_multi_schema_metadata_fetch: false, - allow_run_async: false, - backend: 'postgresql', - database_name: 'examples', - expose_in_sqllab: true, - force_ctas_schema: null, - id: 1, - }, - queryEditorId: initialState.sqlLab.queryEditors[0].id, + queryEditor: initialState.sqlLab.queryEditors[0], latestQuery: queries[0], tables: [table], getHeight: () => '100px', @@ -84,36 +105,120 @@ describe('SqlEditor', () => { const buildWrapper = (props = {}) => mount( - <Provider store={store}> - <SqlEditor {...mockedProps} {...props} /> - </Provider>, + <QueryProvider> + <Provider store={store}> + <SqlEditor {...mockedProps} {...props} /> + </Provider> + </QueryProvider>, { wrappingComponent: ThemeProvider, wrappingComponentProps: { theme: supersetTheme }, }, ); - it('does not render SqlEditor if no db selected', () => { - const database = {}; - const updatedProps = { ...mockedProps, database }; - const wrapper = buildWrapper(updatedProps); - expect(wrapper.find(EmptyStateBig)).toExist(); + it('does not render SqlEditor if no db selected', async () => { + const queryEditor = initialState.sqlLab.queryEditors[1]; + const { findByText } = setup({ ...mockedProps, queryEditor }, store); + expect( + await findByText('Select a database to write a query'), + ).toBeInTheDocument(); }); + it('render a SqlEditorLeftBar', async () => { - const wrapper = buildWrapper(); - await waitForComponentToPaint(wrapper); - expect(wrapper.find(SqlEditorLeftBar)).toExist(); + const { getByTestId } = setup(mockedProps, store); + await waitFor(() => + expect(getByTestId('mock-sql-editor-left-bar')).toBeInTheDocument(), + ); }); + it('render an AceEditorWrapper', async () => { - const wrapper = buildWrapper(); - await waitForComponentToPaint(wrapper); - expect(wrapper.find(AceEditorWrapper)).toExist(); + const { findByTestId } = setup(mockedProps, store); + expect(await findByTestId('react-ace')).toBeInTheDocument(); }); + + it('renders sql from unsaved change', async () => { + const expectedSql = 'SELECT updated_column\nFROM updated_table\nWHERE'; + const { findByTestId } = setup( + mockedProps, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + databases: { + dbid1: { + allow_ctas: false, + allow_cvas: false, + allow_dml: false, + allow_file_upload: false, + allow_run_async: false, + backend: 'postgresql', + database_name: 'examples', + expose_in_sqllab: true, + force_ctas_schema: null, + id: 1, + }, + }, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + dbId: 'dbid1', + sql: expectedSql, + }, + }, + }), + ); + + expect(await findByTestId('react-ace')).toHaveTextContent( + JSON.stringify({ value: expectedSql }).slice(1, -1), + ); + }); + it('render a SouthPane', async () => { - const wrapper = buildWrapper(); - await waitForComponentToPaint(wrapper); - expect(wrapper.find(ConnectedSouthPane)).toExist(); + const { findByText } = setup(mockedProps, store); + expect( + await findByText(/run a query to display results/i), + ).toBeInTheDocument(); }); + + it('runs query action with ctas false', async () => { + const expectedStore = mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + databases: { + 5667: { + allow_ctas: false, + allow_cvas: false, + allow_dml: false, + allow_file_upload: false, + allow_run_async: true, + backend: 'postgresql', + database_name: 'examples', + expose_in_sqllab: true, + force_ctas_schema: null, + id: 1, + }, + }, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + dbId: 5667, + sql: 'expectedSql', + }, + }, + }); + const { findByTestId } = setup(mockedProps, expectedStore); + const runButton = await findByTestId('run-query-action'); + fireEvent.click(runButton); + await waitFor(() => + expect(expectedStore.getActions()).toContainEqual({ + type: 'START_QUERY', + query: expect.objectContaining({ + ctas: false, + sqlEditorId: defaultQueryEditor.id, + }), + }), + ); + }); + // TODO eschutho convert tests to RTL // eslint-disable-next-line jest/no-disabled-tests it.skip('does not overflow the editor window', async () => { @@ -121,12 +226,13 @@ describe('SqlEditor', () => { await waitForComponentToPaint(wrapper); const totalSize = parseFloat(wrapper.find(AceEditorWrapper).props().height) + - wrapper.find(ConnectedSouthPane).props().height + + wrapper.find(SouthPane).props().height + SQL_TOOLBAR_HEIGHT + SQL_EDITOR_GUTTER_MARGIN * 2 + SQL_EDITOR_GUTTER_HEIGHT; expect(totalSize).toEqual(MOCKED_SQL_EDITOR_HEIGHT); }); + // eslint-disable-next-line jest/no-disabled-tests it.skip('does not overflow the editor window after resizing', async () => { const wrapper = buildWrapper(); @@ -134,17 +240,18 @@ describe('SqlEditor', () => { await waitForComponentToPaint(wrapper); const totalSize = parseFloat(wrapper.find(AceEditorWrapper).props().height) + - wrapper.find(ConnectedSouthPane).props().height + + wrapper.find(SouthPane).props().height + SQL_TOOLBAR_HEIGHT + SQL_EDITOR_GUTTER_MARGIN * 2 + SQL_EDITOR_GUTTER_HEIGHT; expect(totalSize).toEqual(450); }); + it('render a Limit Dropdown', async () => { const defaultQueryLimit = 101; const updatedProps = { ...mockedProps, defaultQueryLimit }; - const wrapper = buildWrapper(updatedProps); - await waitForComponentToPaint(wrapper); - expect(wrapper.find(AntdDropdown)).toExist(); + const { findByText } = setup(updatedProps, store); + fireEvent.click(await findByText('LIMIT:')); + expect(await findByText('10 000')).toBeInTheDocument(); }); }); diff --git a/superset-frontend/src/SqlLab/components/SqlEditor/index.jsx b/superset-frontend/src/SqlLab/components/SqlEditor/index.jsx index d40ca65f2f665..2a93cad2706e9 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditor/index.jsx +++ b/superset-frontend/src/SqlLab/components/SqlEditor/index.jsx @@ -18,36 +18,41 @@ */ /* eslint-disable jsx-a11y/anchor-is-valid */ /* eslint-disable jsx-a11y/no-static-element-interactions */ -import React from 'react'; +import React, { + useState, + useEffect, + useMemo, + useRef, + useCallback, +} from 'react'; import { CSSTransition } from 'react-transition-group'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; +import { useDispatch, useSelector } from 'react-redux'; import PropTypes from 'prop-types'; import Split from 'react-split'; -import { t, styled, withTheme } from '@superset-ui/core'; +import { css, t, styled, useTheme } from '@superset-ui/core'; import debounce from 'lodash/debounce'; import throttle from 'lodash/throttle'; -import StyledModal from 'src/components/Modal'; +import Modal from 'src/components/Modal'; import Mousetrap from 'mousetrap'; import Button from 'src/components/Button'; import Timer from 'src/components/Timer'; +import ResizableSidebar from 'src/components/ResizableSidebar'; import { AntdDropdown, AntdSwitch } from 'src/components'; import { Input } from 'src/components/Input'; import { Menu } from 'src/components/Menu'; import Icons from 'src/components/Icons'; import { detectOS } from 'src/utils/common'; import { - addQueryEditor, + addNewQueryEditor, CtasEnum, estimateQueryCost, persistEditorHeight, postStopQuery, queryEditorSetAutorun, - queryEditorSetQueryLimit, queryEditorSetSql, queryEditorSetAndSaveSql, queryEditorSetTemplateParams, - runQuery, + runQueryFromSqlEditor, saveQuery, addSavedQueryToTabState, scheduleQuery, @@ -60,6 +65,13 @@ import { SQL_EDITOR_GUTTER_HEIGHT, SQL_EDITOR_GUTTER_MARGIN, SQL_TOOLBAR_HEIGHT, + SQL_EDITOR_LEFTBAR_WIDTH, + SQL_EDITOR_PADDING, + INITIAL_NORTH_PERCENT, + INITIAL_SOUTH_PERCENT, + SET_QUERY_EDITOR_SQL_DEBOUNCE_MS, + VALIDATION_DEBOUNCE_MS, + WINDOW_RESIZE_THROTTLE_MS, } from 'src/SqlLab/constants'; import { getItem, @@ -68,9 +80,10 @@ import { } from 'src/utils/localStorageHelpers'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import { EmptyStateBig } from 'src/components/EmptyState'; +import getBootstrapData from 'src/utils/getBootstrapData'; import { isEmpty } from 'lodash'; import TemplateParamsEditor from '../TemplateParamsEditor'; -import ConnectedSouthPane from '../SouthPane/state'; +import SouthPane from '../SouthPane'; import SaveQuery from '../SaveQuery'; import ScheduleQueryButton from '../ScheduleQueryButton'; import EstimateQueryCostButton from '../EstimateQueryCostButton'; @@ -78,44 +91,13 @@ import ShareSqlLabQuery from '../ShareSqlLabQuery'; import SqlEditorLeftBar from '../SqlEditorLeftBar'; import AceEditorWrapper from '../AceEditorWrapper'; import RunQueryActionButton from '../RunQueryActionButton'; -import { newQueryTabName } from '../../utils/newQueryTabName'; - -const LIMIT_DROPDOWN = [10, 100, 1000, 10000, 100000]; -const SQL_EDITOR_PADDING = 10; -const INITIAL_NORTH_PERCENT = 30; -const INITIAL_SOUTH_PERCENT = 70; -const SET_QUERY_EDITOR_SQL_DEBOUNCE_MS = 2000; -const VALIDATION_DEBOUNCE_MS = 600; -const WINDOW_RESIZE_THROTTLE_MS = 100; - -const appContainer = document.getElementById('app'); -const bootstrapData = JSON.parse( - appContainer.getAttribute('data-bootstrap') || '{}', -); +import QueryLimitSelect from '../QueryLimitSelect'; + +const bootstrapData = getBootstrapData(); const validatorMap = bootstrapData?.common?.conf?.SQL_VALIDATORS_BY_ENGINE || {}; const scheduledQueriesConf = bootstrapData?.common?.conf?.SCHEDULED_QUERIES; -const LimitSelectStyled = styled.span` - ${({ theme }) => ` - .ant-dropdown-trigger { - align-items: center; - color: ${theme.colors.grayscale.dark2}; - display: flex; - font-size: 12px; - margin-right: ${theme.gridUnit * 2}px; - text-decoration: none; - span { - display: inline-block; - margin-right: ${theme.gridUnit * 2}px; - &:last-of-type: { - margin-right: ${theme.gridUnit * 4}px; - } - } - } - `} -`; - const StyledToolbar = styled.div` padding: ${({ theme }) => theme.gridUnit * 2}px; background: ${({ theme }) => theme.colors.grayscale.light5}; @@ -147,186 +129,187 @@ const StyledToolbar = styled.div` } `; -const propTypes = { - actions: PropTypes.object.isRequired, - database: PropTypes.object, - latestQuery: PropTypes.object, - tables: PropTypes.array.isRequired, - editorQueries: PropTypes.array.isRequired, - dataPreviewQueries: PropTypes.array.isRequired, - queryEditorId: PropTypes.string.isRequired, - hideLeftBar: PropTypes.bool, - defaultQueryLimit: PropTypes.number.isRequired, - maxRow: PropTypes.number.isRequired, - displayLimit: PropTypes.number.isRequired, - saveQueryWarning: PropTypes.string, - scheduleQueryWarning: PropTypes.string, -}; +const StyledSidebar = styled.div` + flex: 0 0 ${({ width }) => width}px; + width: ${({ width }) => width}px; + padding: ${({ theme, hide }) => (hide ? 0 : theme.gridUnit * 2.5)}px; + border-right: 1px solid + ${({ theme, hide }) => + hide ? 'transparent' : theme.colors.grayscale.light2}; +`; -const defaultProps = { - database: null, - latestQuery: null, - hideLeftBar: false, - scheduleQueryWarning: null, -}; +const StyledSqlEditor = styled.div` + ${({ theme }) => css` + display: flex; + flex-direction: row; + height: 100%; -class SqlEditor extends React.PureComponent { - constructor(props) { - super(props); - this.state = { - autorun: props.queryEditor.autorun, - ctas: '', - northPercent: props.queryEditor.northPercent || INITIAL_NORTH_PERCENT, - southPercent: props.queryEditor.southPercent || INITIAL_SOUTH_PERCENT, - autocompleteEnabled: getItem( - LocalStorageKeys.sqllab__is_autocomplete_enabled, - true, - ), - showCreateAsModal: false, - createAs: '', - showEmptyState: false, - }; - this.sqlEditorRef = React.createRef(); - this.northPaneRef = React.createRef(); - - this.elementStyle = this.elementStyle.bind(this); - this.onResizeStart = this.onResizeStart.bind(this); - this.onResizeEnd = this.onResizeEnd.bind(this); - this.canValidateQuery = this.canValidateQuery.bind(this); - this.runQuery = this.runQuery.bind(this); - this.setEmptyState = this.setEmptyState.bind(this); - this.stopQuery = this.stopQuery.bind(this); - this.saveQuery = this.saveQuery.bind(this); - this.onSqlChanged = this.onSqlChanged.bind(this); - this.setQueryEditorAndSaveSql = this.setQueryEditorAndSaveSql.bind(this); - this.setQueryEditorAndSaveSqlWithDebounce = debounce( - this.setQueryEditorAndSaveSql.bind(this), - SET_QUERY_EDITOR_SQL_DEBOUNCE_MS, - ); - this.queryPane = this.queryPane.bind(this); - this.getHotkeyConfig = this.getHotkeyConfig.bind(this); - this.renderQueryLimit = this.renderQueryLimit.bind(this); - this.getAceEditorAndSouthPaneHeights = - this.getAceEditorAndSouthPaneHeights.bind(this); - this.getSqlEditorHeight = this.getSqlEditorHeight.bind(this); - this.requestValidation = debounce( - this.requestValidation.bind(this), - VALIDATION_DEBOUNCE_MS, - ); - this.getQueryCostEstimate = this.getQueryCostEstimate.bind(this); - this.handleWindowResize = throttle( - this.handleWindowResize.bind(this), - WINDOW_RESIZE_THROTTLE_MS, - ); + .schemaPane { + transition: transform ${theme.transitionTiming}s ease-in-out; + } - this.onBeforeUnload = this.onBeforeUnload.bind(this); - this.renderDropdown = this.renderDropdown.bind(this); - } + .queryPane { + flex: 1 1 auto; + padding: ${theme.gridUnit * 2}px; + overflow-y: auto; + overflow-x: scroll; + } - UNSAFE_componentWillMount() { - if (this.state.autorun) { - this.setState({ autorun: false }); - this.props.queryEditorSetAutorun(this.props.queryEditor, false); - this.startQuery(); + .schemaPane-enter-done, + .schemaPane-exit { + transform: translateX(0); + z-index: 7; } - } - componentDidMount() { - // We need to measure the height of the sql editor post render to figure the height of - // the south pane so it gets rendered properly - // eslint-disable-next-line react/no-did-mount-set-state - const db = this.props.database; - this.setState({ height: this.getSqlEditorHeight() }); - if (!db || isEmpty(db)) { - this.setEmptyState(true); + .schemaPane-exit-active { + transform: translateX(-120%); + } + + .schemaPane-enter-active { + transform: translateX(0); + max-width: ${theme.gridUnit * 75}px; } - window.addEventListener('resize', this.handleWindowResize); - window.addEventListener('beforeunload', this.onBeforeUnload); + .schemaPane-enter, + .schemaPane-exit-done { + max-width: 0; + transform: translateX(-120%); + overflow: hidden; + } - // setup hotkeys - const hotkeys = this.getHotkeyConfig(); - hotkeys.forEach(keyConfig => { - Mousetrap.bind([keyConfig.key], keyConfig.func); - }); - } + .schemaPane-exit-done + .queryPane { + margin-left: 0; + } - componentWillUnmount() { - window.removeEventListener('resize', this.handleWindowResize); - window.removeEventListener('beforeunload', this.onBeforeUnload); - } + .gutter { + border-top: 1px solid ${theme.colors.grayscale.light2}; + border-bottom: 1px solid ${theme.colors.grayscale.light2}; + width: 3%; + margin: ${SQL_EDITOR_GUTTER_MARGIN}px 47%; + } - onResizeStart() { - // Set the heights on the ace editor and the ace content area after drag starts - // to smooth out the visual transition to the new heights when drag ends - document.getElementsByClassName('ace_content')[0].style.height = '100%'; - } + .gutter.gutter-vertical { + cursor: row-resize; + } + `} +`; + +const propTypes = { + tables: PropTypes.array.isRequired, + queryEditor: PropTypes.object.isRequired, + defaultQueryLimit: PropTypes.number.isRequired, + maxRow: PropTypes.number.isRequired, + displayLimit: PropTypes.number.isRequired, + saveQueryWarning: PropTypes.string, + scheduleQueryWarning: PropTypes.string, +}; + +const SqlEditor = ({ + tables, + queryEditor, + defaultQueryLimit, + maxRow, + displayLimit, + saveQueryWarning, + scheduleQueryWarning = null, +}) => { + const theme = useTheme(); + const dispatch = useDispatch(); + + const { database, latestQuery, hideLeftBar } = useSelector( + ({ sqlLab: { unsavedQueryEditor, databases, queries } }) => { + let { dbId, latestQueryId, hideLeftBar } = queryEditor; + if (unsavedQueryEditor.id === queryEditor.id) { + dbId = unsavedQueryEditor.dbId || dbId; + latestQueryId = unsavedQueryEditor.latestQueryId || latestQueryId; + hideLeftBar = unsavedQueryEditor.hideLeftBar || hideLeftBar; + } + return { + database: databases[dbId], + latestQuery: queries[latestQueryId], + hideLeftBar, + }; + }, + ); + + const [height, setHeight] = useState(0); + const [autorun, setAutorun] = useState(queryEditor.autorun); + const [ctas, setCtas] = useState(''); + const [northPercent, setNorthPercent] = useState( + queryEditor.northPercent || INITIAL_NORTH_PERCENT, + ); + const [southPercent, setSouthPercent] = useState( + queryEditor.southPercent || INITIAL_SOUTH_PERCENT, + ); + const [autocompleteEnabled, setAutocompleteEnabled] = useState( + getItem(LocalStorageKeys.sqllab__is_autocomplete_enabled, true), + ); + const [showCreateAsModal, setShowCreateAsModal] = useState(false); + const [createAs, setCreateAs] = useState(''); + const [showEmptyState, setShowEmptyState] = useState(false); - onResizeEnd([northPercent, southPercent]) { - this.setState({ northPercent, southPercent }); + const sqlEditorRef = useRef(null); + const northPaneRef = useRef(null); - if (this.northPaneRef.current && this.northPaneRef.current.clientHeight) { - this.props.persistEditorHeight( - this.props.queryEditor, - northPercent, - southPercent, + const startQuery = useCallback( + (ctasArg = false, ctas_method = CtasEnum.TABLE) => { + if (!database) { + return; + } + + dispatch( + runQueryFromSqlEditor( + database, + queryEditor, + defaultQueryLimit, + ctasArg ? ctas : '', + ctasArg, + ctas_method, + ), ); + dispatch(setActiveSouthPaneTab('Results')); + }, + [ctas, database, defaultQueryLimit, dispatch, queryEditor], + ); + + const stopQuery = useCallback(() => { + if (latestQuery && ['running', 'pending'].indexOf(latestQuery.state) >= 0) { + dispatch(postStopQuery(latestQuery)); } - } + return false; + }, [dispatch, latestQuery]); - onBeforeUnload(event) { - if ( - this.props.database?.extra_json?.cancel_query_on_windows_unload && - this.props.latestQuery?.state === 'running' - ) { - event.preventDefault(); - this.stopQuery(); + const runQuery = () => { + if (database) { + startQuery(); } - } + }; - onSqlChanged(sql) { - this.props.queryEditorSetSql(this.props.queryEditor, sql); - this.setQueryEditorAndSaveSqlWithDebounce(sql); - // Request server-side validation of the query text - if (this.canValidateQuery()) { - // NB. requestValidation is debounced - this.requestValidation(sql); + useEffect(() => { + if (autorun) { + setAutorun(false); + dispatch(queryEditorSetAutorun(queryEditor, false)); + startQuery(); } - } + }, [autorun, dispatch, queryEditor, startQuery]); // One layer of abstraction for easy spying in unit tests - getSqlEditorHeight() { - return this.sqlEditorRef.current - ? this.sqlEditorRef.current.clientHeight - SQL_EDITOR_PADDING * 2 + const getSqlEditorHeight = () => + sqlEditorRef.current + ? sqlEditorRef.current.clientHeight - SQL_EDITOR_PADDING * 2 : 0; - } - - // Return the heights for the ace editor and the south pane as an object - // given the height of the sql editor, north pane percent and south pane percent. - getAceEditorAndSouthPaneHeights(height, northPercent, southPercent) { - return { - aceEditorHeight: - (height * northPercent) / 100 - - (SQL_EDITOR_GUTTER_HEIGHT / 2 + SQL_EDITOR_GUTTER_MARGIN) - - SQL_TOOLBAR_HEIGHT, - southPaneHeight: - (height * southPercent) / 100 - - (SQL_EDITOR_GUTTER_HEIGHT / 2 + SQL_EDITOR_GUTTER_MARGIN), - }; - } - getHotkeyConfig() { + const getHotkeyConfig = useCallback(() => { // Get the user's OS const userOS = detectOS(); - const base = [ { name: 'runQuery1', key: 'ctrl+r', descr: t('Run query'), func: () => { - if (this.props.queryEditor.sql.trim() !== '') { - this.runQuery(); + if (queryEditor.sql.trim() !== '') { + startQuery(); } }, }, @@ -335,8 +318,8 @@ class SqlEditor extends React.PureComponent { key: 'ctrl+enter', descr: t('Run query'), func: () => { - if (this.props.queryEditor.sql.trim() !== '') { - this.runQuery(); + if (queryEditor.sql.trim() !== '') { + startQuery(); } }, }, @@ -345,18 +328,14 @@ class SqlEditor extends React.PureComponent { key: userOS === 'Windows' ? 'ctrl+q' : 'ctrl+t', descr: t('New tab'), func: () => { - const title = newQueryTabName(this.props.queryEditors || []); - this.props.addQueryEditor({ - ...this.props.queryEditor, - title, - }); + dispatch(addNewQueryEditor()); }, }, { name: 'stopQuery', key: userOS === 'MacOS' ? 'ctrl+x' : 'ctrl+e', descr: t('Stop query'), - func: this.stopQuery, + func: stopQuery, }, ]; @@ -372,201 +351,186 @@ class SqlEditor extends React.PureComponent { } return base; - } + }, [dispatch, queryEditor.sql, startQuery, stopQuery]); - setEmptyState(bool) { - this.setState({ showEmptyState: bool }); - } + const handleWindowResize = useCallback(() => { + setHeight(getSqlEditorHeight()); + }, []); - setQueryEditorAndSaveSql(sql) { - this.props.queryEditorSetAndSaveSql(this.props.queryEditor, sql); - } + const handleWindowResizeWithThrottle = useMemo( + () => throttle(handleWindowResize, WINDOW_RESIZE_THROTTLE_MS), + [handleWindowResize], + ); - setQueryLimit(queryLimit) { - this.props.queryEditorSetQueryLimit(this.props.queryEditor, queryLimit); - } + const onBeforeUnload = useCallback( + event => { + if ( + database?.extra_json?.cancel_query_on_windows_unload && + latestQuery?.state === 'running' + ) { + event.preventDefault(); + stopQuery(); + } + }, + [ + database?.extra_json?.cancel_query_on_windows_unload, + latestQuery?.state, + stopQuery, + ], + ); - getQueryCostEstimate() { - if (this.props.database) { - const qe = this.props.queryEditor; - const query = { - dbId: qe.dbId, - sql: qe.selectedText ? qe.selectedText : this.props.queryEditor.sql, - sqlEditorId: qe.id, - schema: qe.schema, - templateParams: qe.templateParams, - }; - this.props.estimateQueryCost(query); + useEffect(() => { + // We need to measure the height of the sql editor post render to figure the height of + // the south pane so it gets rendered properly + setHeight(getSqlEditorHeight()); + if (!database || isEmpty(database)) { + setShowEmptyState(true); } - } - handleToggleAutocompleteEnabled = () => { - this.setState(prevState => { - setItem( - LocalStorageKeys.sqllab__is_autocomplete_enabled, - !prevState.autocompleteEnabled, - ); - return { - autocompleteEnabled: !prevState.autocompleteEnabled, - }; + window.addEventListener('resize', handleWindowResizeWithThrottle); + window.addEventListener('beforeunload', onBeforeUnload); + + return () => { + window.removeEventListener('resize', handleWindowResizeWithThrottle); + window.removeEventListener('beforeunload', onBeforeUnload); + }; + }, [database, handleWindowResizeWithThrottle, onBeforeUnload]); + + useEffect(() => { + // setup hotkeys + Mousetrap.reset(); + const hotkeys = getHotkeyConfig(); + hotkeys.forEach(keyConfig => { + Mousetrap.bind([keyConfig.key], keyConfig.func); }); - }; + }, [getHotkeyConfig, latestQuery]); - handleWindowResize() { - this.setState({ height: this.getSqlEditorHeight() }); - } + const onResizeStart = () => { + // Set the heights on the ace editor and the ace content area after drag starts + // to smooth out the visual transition to the new heights when drag ends + document.getElementsByClassName('ace_content')[0].style.height = '100%'; + }; - elementStyle(dimension, elementSize, gutterSize) { - return { - [dimension]: `calc(${elementSize}% - ${ - gutterSize + SQL_EDITOR_GUTTER_MARGIN - }px)`, - }; - } + const onResizeEnd = ([northPercent, southPercent]) => { + setNorthPercent(northPercent); + setSouthPercent(southPercent); - requestValidation(sql) { - if (this.props.database) { - const qe = this.props.queryEditor; - const query = { - dbId: qe.dbId, - sql, - sqlEditorId: qe.id, - schema: qe.schema, - templateParams: qe.templateParams, - }; - this.props.validateQuery(query); + if (northPaneRef.current?.clientHeight) { + dispatch(persistEditorHeight(queryEditor, northPercent, southPercent)); } - } + }; - canValidateQuery() { + const setQueryEditorAndSaveSql = useCallback( + sql => { + dispatch(queryEditorSetAndSaveSql(queryEditor, sql)); + }, + [dispatch, queryEditor], + ); + + const setQueryEditorAndSaveSqlWithDebounce = useMemo( + () => debounce(setQueryEditorAndSaveSql, SET_QUERY_EDITOR_SQL_DEBOUNCE_MS), + [setQueryEditorAndSaveSql], + ); + + const canValidateQuery = () => { // Check whether or not we can validate the current query based on whether // or not the backend has a validator configured for it. - if (this.props.database) { - return validatorMap.hasOwnProperty(this.props.database.backend); + if (database) { + return validatorMap.hasOwnProperty(database.backend); } return false; - } + }; - runQuery() { - if (this.props.database) { - this.startQuery(); - } - } + const requestValidation = useCallback( + sql => { + if (database) { + dispatch(validateQuery(queryEditor, sql)); + } + }, + [database, dispatch, queryEditor], + ); - convertToNumWithSpaces(num) { - return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1 '); - } + const requestValidationWithDebounce = useMemo( + () => debounce(requestValidation, VALIDATION_DEBOUNCE_MS), + [requestValidation], + ); - startQuery(ctas = false, ctas_method = CtasEnum.TABLE) { - const qe = this.props.queryEditor; - const query = { - dbId: qe.dbId, - sql: qe.selectedText ? qe.selectedText : qe.sql, - sqlEditorId: qe.id, - tab: qe.title, - schema: qe.schema, - tempTable: ctas ? this.state.ctas : '', - templateParams: qe.templateParams, - queryLimit: qe.queryLimit || this.props.defaultQueryLimit, - runAsync: this.props.database - ? this.props.database.allow_run_async - : false, - ctas, - ctas_method, - updateTabState: !qe.selectedText, - }; - this.props.runQuery(query); - this.props.setActiveSouthPaneTab('Results'); - } + const onSqlChanged = sql => { + dispatch(queryEditorSetSql(queryEditor, sql)); + setQueryEditorAndSaveSqlWithDebounce(sql); + // Request server-side validation of the query text + if (canValidateQuery()) { + // NB. requestValidation is debounced + requestValidationWithDebounce(sql); + } + }; - stopQuery() { - if ( - this.props.latestQuery && - ['running', 'pending'].indexOf(this.props.latestQuery.state) >= 0 - ) { - this.props.postStopQuery(this.props.latestQuery); + // Return the heights for the ace editor and the south pane as an object + // given the height of the sql editor, north pane percent and south pane percent. + const getAceEditorAndSouthPaneHeights = ( + height, + northPercent, + southPercent, + ) => ({ + aceEditorHeight: + (height * northPercent) / (theme.gridUnit * 25) - + (SQL_EDITOR_GUTTER_HEIGHT / 2 + SQL_EDITOR_GUTTER_MARGIN) - + SQL_TOOLBAR_HEIGHT, + southPaneHeight: + (height * southPercent) / (theme.gridUnit * 25) - + (SQL_EDITOR_GUTTER_HEIGHT / 2 + SQL_EDITOR_GUTTER_MARGIN), + }); + + const getQueryCostEstimate = () => { + if (database) { + dispatch(estimateQueryCost(queryEditor)); } - } + }; - createTableAs() { - this.startQuery(true, CtasEnum.TABLE); - this.setState({ showCreateAsModal: false, ctas: '' }); - } + const handleToggleAutocompleteEnabled = () => { + setItem( + LocalStorageKeys.sqllab__is_autocomplete_enabled, + !autocompleteEnabled, + ); + setAutocompleteEnabled(!autocompleteEnabled); + }; - createViewAs() { - this.startQuery(true, CtasEnum.VIEW); - this.setState({ showCreateAsModal: false, ctas: '' }); - } + const elementStyle = (dimension, elementSize, gutterSize) => ({ + [dimension]: `calc(${elementSize}% - ${ + gutterSize + SQL_EDITOR_GUTTER_MARGIN + }px)`, + }); - ctasChanged(event) { - this.setState({ ctas: event.target.value }); - } + const createTableAs = () => { + startQuery(true, CtasEnum.TABLE); + setShowCreateAsModal(false); + setCtas(''); + }; - queryPane() { - const hotkeys = this.getHotkeyConfig(); - const { aceEditorHeight, southPaneHeight } = - this.getAceEditorAndSouthPaneHeights( - this.state.height, - this.state.northPercent, - this.state.southPercent, - ); - return ( - <Split - expandToMin - className="queryPane" - sizes={[this.state.northPercent, this.state.southPercent]} - elementStyle={this.elementStyle} - minSize={200} - direction="vertical" - gutterSize={SQL_EDITOR_GUTTER_HEIGHT} - onDragStart={this.onResizeStart} - onDragEnd={this.onResizeEnd} - > - <div ref={this.northPaneRef} className="north-pane"> - <AceEditorWrapper - actions={this.props.actions} - autocomplete={this.state.autocompleteEnabled} - onBlur={this.setQueryEditorSql} - onChange={this.onSqlChanged} - queryEditor={this.props.queryEditor} - sql={this.props.queryEditor.sql} - database={this.props.database} - schemas={this.props.queryEditor.schemaOptions} - tables={this.props.queryEditor.tableOptions} - functionNames={this.props.queryEditor.functionNames} - extendedTables={this.props.tables} - height={`${aceEditorHeight}px`} - hotkeys={hotkeys} - /> - {this.renderEditorBottomBar(hotkeys)} - </div> - <ConnectedSouthPane - editorQueries={this.props.editorQueries} - latestQueryId={this.props.latestQuery && this.props.latestQuery.id} - dataPreviewQueries={this.props.dataPreviewQueries} - actions={this.props.actions} - height={southPaneHeight} - displayLimit={this.props.displayLimit} - defaultQueryLimit={this.props.defaultQueryLimit} - /> - </Split> - ); - } + const createViewAs = () => { + startQuery(true, CtasEnum.VIEW); + setShowCreateAsModal(false); + setCtas(''); + }; - renderDropdown() { - const qe = this.props.queryEditor; - const successful = this.props.latestQuery?.state === 'success'; + const ctasChanged = event => { + setCtas(event.target.value); + }; + + const renderDropdown = () => { + const qe = queryEditor; + const successful = latestQuery?.state === 'success'; const scheduleToolTip = successful ? t('Schedule the query periodically') : t('You must run the query successfully first'); return ( - <Menu onClick={this.handleMenuClick} style={{ width: 176 }}> - <Menu.Item style={{ display: 'flex', justifyContent: 'space-between' }}> + <Menu css={{ width: theme.gridUnit * 44 }}> + <Menu.Item css={{ display: 'flex', justifyContent: 'space-between' }}> {' '} <span>{t('Autocomplete')}</span>{' '} <AntdSwitch - checked={this.state.autocompleteEnabled} - onChange={this.handleToggleAutocompleteEnabled} + checked={autocompleteEnabled} + onChange={handleToggleAutocompleteEnabled} name="autocomplete-switch" />{' '} </Menu.Item> @@ -575,21 +539,21 @@ class SqlEditor extends React.PureComponent { <TemplateParamsEditor language="json" onChange={params => { - this.props.actions.queryEditorSetTemplateParams(qe, params); + dispatch(queryEditorSetTemplateParams(qe, params)); }} - code={qe.templateParams} + queryEditorId={qe.id} /> </Menu.Item> )} {scheduledQueriesConf && ( <Menu.Item> <ScheduleQueryButton - defaultLabel={qe.title} + defaultLabel={qe.name} sql={qe.sql} - onSchedule={this.props.actions.scheduleQuery} + onSchedule={query => dispatch(scheduleQuery(query))} schema={qe.schema} dbId={qe.dbId} - scheduleQueryWarning={this.props.scheduleQueryWarning} + scheduleQueryWarning={scheduleQueryWarning} tooltip={scheduleToolTip} disabled={!successful} /> @@ -597,50 +561,24 @@ class SqlEditor extends React.PureComponent { )} </Menu> ); - } - - renderQueryLimit() { - // Adding SQL_MAX_ROW value to dropdown - const { maxRow } = this.props; - LIMIT_DROPDOWN.push(maxRow); - - return ( - <Menu> - {[...new Set(LIMIT_DROPDOWN)].map(limit => ( - <Menu.Item key={`${limit}`} onClick={() => this.setQueryLimit(limit)}> - {/* // eslint-disable-line no-use-before-define */} - <a role="button" styling="link"> - {this.convertToNumWithSpaces(limit)} - </a>{' '} - </Menu.Item> - ))} - </Menu> - ); - } - - async saveQuery(query) { - const { queryEditor: qe, actions } = this.props; - const savedQuery = await actions.saveQuery(query); - actions.addSavedQueryToTabState(qe, savedQuery); - } + }; - renderEditorBottomBar() { - const { queryEditor: qe } = this.props; + const onSaveQuery = async (query, clientId) => { + const savedQuery = await dispatch(saveQuery(query, clientId)); + dispatch(addSavedQueryToTabState(queryEditor, savedQuery)); + }; - const { allow_ctas: allowCTAS, allow_cvas: allowCVAS } = - this.props.database || {}; + const renderEditorBottomBar = () => { + const { allow_ctas: allowCTAS, allow_cvas: allowCVAS } = database || {}; const showMenu = allowCTAS || allowCVAS; - const { theme } = this.props; const runMenuBtn = ( <Menu> {allowCTAS && ( <Menu.Item onClick={() => { - this.setState({ - showCreateAsModal: true, - createAs: CtasEnum.TABLE, - }); + setShowCreateAsModal(true); + setCreateAs(CtasEnum.TABLE); }} key="1" > @@ -650,10 +588,8 @@ class SqlEditor extends React.PureComponent { {allowCVAS && ( <Menu.Item onClick={() => { - this.setState({ - showCreateAsModal: true, - createAs: CtasEnum.VIEW, - }); + setShowCreateAsModal(true); + setCreateAs(CtasEnum.VIEW); }} key="2" > @@ -668,197 +604,188 @@ class SqlEditor extends React.PureComponent { <div className="leftItems"> <span> <RunQueryActionButton - allowAsync={ - this.props.database - ? this.props.database.allow_run_async - : false - } - queryState={this.props.latestQuery?.state} - runQuery={this.runQuery} - selectedText={qe.selectedText} - stopQuery={this.stopQuery} - sql={this.props.queryEditor.sql} + allowAsync={database ? database.allow_run_async : false} + queryEditorId={queryEditor.id} + queryState={latestQuery?.state} + runQuery={runQuery} + stopQuery={stopQuery} overlayCreateAsMenu={showMenu ? runMenuBtn : null} /> </span> {isFeatureEnabled(FeatureFlag.ESTIMATE_QUERY_COST) && - this.props.database && - this.props.database.allows_cost_estimate && ( + database?.allows_cost_estimate && ( <span> <EstimateQueryCostButton - getEstimate={this.getQueryCostEstimate} - queryCostEstimate={qe.queryCostEstimate} - selectedText={qe.selectedText} + getEstimate={getQueryCostEstimate} + queryEditorId={queryEditor.id} tooltip={t('Estimate the cost before running a query')} /> </span> )} <span> - <LimitSelectStyled> - <AntdDropdown overlay={this.renderQueryLimit()} trigger="click"> - <a onClick={e => e.preventDefault()}> - <span>LIMIT:</span> - <span className="limitDropdown"> - {this.convertToNumWithSpaces( - this.props.queryEditor.queryLimit || - this.props.defaultQueryLimit, - )} - </span> - <Icons.TriangleDown iconColor={theme.colors.grayscale.base} /> - </a> - </AntdDropdown> - </LimitSelectStyled> + <QueryLimitSelect + queryEditorId={queryEditor.id} + maxRow={maxRow} + defaultQueryLimit={defaultQueryLimit} + /> </span> - {this.props.latestQuery && ( + {latestQuery && ( <Timer - startTime={this.props.latestQuery.startDttm} - endTime={this.props.latestQuery.endDttm} - state={STATE_TYPE_MAP[this.props.latestQuery.state]} - isRunning={this.props.latestQuery.state === 'running'} + startTime={latestQuery.startDttm} + endTime={latestQuery.endDttm} + state={STATE_TYPE_MAP[latestQuery.state]} + isRunning={latestQuery.state === 'running'} /> )} </div> <div className="rightItems"> <span> <SaveQuery - query={qe} - defaultLabel={qe.title || qe.description} - onSave={this.saveQuery} - onUpdate={this.props.actions.updateSavedQuery} - saveQueryWarning={this.props.saveQueryWarning} + queryEditorId={queryEditor.id} + columns={latestQuery?.results?.columns || []} + onSave={onSaveQuery} + onUpdate={(query, remoteId, id) => + dispatch(updateSavedQuery(query, remoteId, id)) + } + saveQueryWarning={saveQueryWarning} + database={database} /> </span> <span> - <ShareSqlLabQuery queryEditor={qe} /> + <ShareSqlLabQuery queryEditorId={queryEditor.id} /> </span> - <AntdDropdown overlay={this.renderDropdown()} trigger="click"> + <AntdDropdown overlay={renderDropdown()} trigger="click"> <Icons.MoreHoriz iconColor={theme.colors.grayscale.base} /> </AntdDropdown> </div> </StyledToolbar> ); - } - - render() { - const createViewModalTitle = - this.state.createAs === CtasEnum.VIEW - ? 'CREATE VIEW AS' - : 'CREATE TABLE AS'; - - const createModalPlaceHolder = - this.state.createAs === CtasEnum.VIEW - ? 'Specify name to CREATE VIEW AS schema in: public' - : 'Specify name to CREATE TABLE AS schema in: public'; + }; - const leftBarStateClass = this.props.hideLeftBar - ? 'schemaPane-exit-done' - : 'schemaPane-enter-done'; + const queryPane = () => { + const hotkeys = getHotkeyConfig(); + const { aceEditorHeight, southPaneHeight } = + getAceEditorAndSouthPaneHeights(height, northPercent, southPercent); return ( - <div ref={this.sqlEditorRef} className="SqlEditor"> - <CSSTransition - classNames="schemaPane" - in={!this.props.hideLeftBar} - timeout={300} + <Split + expandToMin + className="queryPane" + sizes={[northPercent, southPercent]} + elementStyle={elementStyle} + minSize={200} + direction="vertical" + gutterSize={SQL_EDITOR_GUTTER_HEIGHT} + onDragStart={onResizeStart} + onDragEnd={onResizeEnd} + > + <div ref={northPaneRef} className="north-pane"> + <AceEditorWrapper + autocomplete={autocompleteEnabled} + onBlur={setQueryEditorAndSaveSql} + onChange={onSqlChanged} + queryEditorId={queryEditor.id} + database={database} + extendedTables={tables} + height={`${aceEditorHeight}px`} + hotkeys={hotkeys} + /> + {renderEditorBottomBar(hotkeys)} + </div> + <SouthPane + queryEditorId={queryEditor.id} + latestQueryId={latestQuery?.id} + height={southPaneHeight} + displayLimit={displayLimit} + defaultQueryLimit={defaultQueryLimit} + /> + </Split> + ); + }; + + const createViewModalTitle = + createAs === CtasEnum.VIEW ? 'CREATE VIEW AS' : 'CREATE TABLE AS'; + + const createModalPlaceHolder = + createAs === CtasEnum.VIEW + ? t('Specify name to CREATE VIEW AS schema in: public') + : t('Specify name to CREATE TABLE AS schema in: public'); + + const leftBarStateClass = hideLeftBar + ? 'schemaPane-exit-done' + : 'schemaPane-enter-done'; + return ( + <StyledSqlEditor ref={sqlEditorRef} className="SqlEditor"> + <CSSTransition classNames="schemaPane" in={!hideLeftBar} timeout={300}> + <ResizableSidebar + id={`sqllab:${queryEditor.id}`} + minWidth={SQL_EDITOR_LEFTBAR_WIDTH} + initialWidth={SQL_EDITOR_LEFTBAR_WIDTH} + enable={!hideLeftBar} > - <div className={`schemaPane ${leftBarStateClass}`}> - <SqlEditorLeftBar - database={this.props.database} - queryEditor={this.props.queryEditor} - tables={this.props.tables} - actions={this.props.actions} - setEmptyState={this.setEmptyState} - /> - </div> - </CSSTransition> - {this.state.showEmptyState ? ( - <EmptyStateBig - image="vector.svg" - title={t('Select a database to write a query')} - description={t( - 'Choose one of the available databases from the panel on the left.', + {adjustedWidth => ( + <StyledSidebar + className={`schemaPane ${leftBarStateClass}`} + width={adjustedWidth} + hide={hideLeftBar} + > + <SqlEditorLeftBar + database={database} + queryEditorId={queryEditor.id} + tables={tables} + setEmptyState={bool => setShowEmptyState(bool)} + /> + </StyledSidebar> + )} + </ResizableSidebar> + </CSSTransition> + {showEmptyState ? ( + <EmptyStateBig + image="vector.svg" + title={t('Select a database to write a query')} + description={t( + 'Choose one of the available databases from the panel on the left.', + )} + /> + ) : ( + queryPane() + )} + <Modal + visible={showCreateAsModal} + title={t(createViewModalTitle)} + onHide={() => setShowCreateAsModal(false)} + footer={ + <> + <Button onClick={() => setShowCreateAsModal(false)}> + {t('Cancel')} + </Button> + {createAs === CtasEnum.TABLE && ( + <Button + buttonStyle="primary" + disabled={ctas.length === 0} + onClick={createTableAs} + > + {t('Create')} + </Button> )} - /> - ) : ( - this.queryPane() - )} - <StyledModal - visible={this.state.showCreateAsModal} - title={t(createViewModalTitle)} - onHide={() => { - this.setState({ showCreateAsModal: false }); - }} - footer={ - <> + {createAs === CtasEnum.VIEW && ( <Button - onClick={() => this.setState({ showCreateAsModal: false })} + buttonStyle="primary" + disabled={ctas.length === 0} + onClick={createViewAs} > - Cancel + {t('Create')} </Button> - {this.state.createAs === CtasEnum.TABLE && ( - <Button - buttonStyle="primary" - disabled={this.state.ctas.length === 0} - onClick={this.createTableAs.bind(this)} - > - Create - </Button> - )} - {this.state.createAs === CtasEnum.VIEW && ( - <Button - buttonStyle="primary" - disabled={this.state.ctas.length === 0} - onClick={this.createViewAs.bind(this)} - > - Create - </Button> - )} - </> - } - > - <span>Name</span> - <Input - placeholder={createModalPlaceHolder} - onChange={this.ctasChanged.bind(this)} - /> - </StyledModal> - </div> - ); - } -} -SqlEditor.defaultProps = defaultProps; -SqlEditor.propTypes = propTypes; - -function mapStateToProps({ sqlLab }, props) { - const queryEditor = sqlLab.queryEditors.find( - editor => editor.id === props.queryEditorId, + )} + </> + } + > + <span>{t('Name')}</span> + <Input placeholder={createModalPlaceHolder} onChange={ctasChanged} /> + </Modal> + </StyledSqlEditor> ); +}; - return { sqlLab, ...props, queryEditor, queryEditors: sqlLab.queryEditors }; -} - -function mapDispatchToProps(dispatch) { - return bindActionCreators( - { - addQueryEditor, - estimateQueryCost, - persistEditorHeight, - postStopQuery, - queryEditorSetAutorun, - queryEditorSetQueryLimit, - queryEditorSetSql, - queryEditorSetAndSaveSql, - queryEditorSetTemplateParams, - runQuery, - saveQuery, - addSavedQueryToTabState, - scheduleQuery, - setActiveSouthPaneTab, - updateSavedQuery, - validateQuery, - }, - dispatch, - ); -} +SqlEditor.propTypes = propTypes; -const themedSqlEditor = withTheme(SqlEditor); -export default connect(mapStateToProps, mapDispatchToProps)(themedSqlEditor); +export default SqlEditor; diff --git a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/SqlEditorLeftBar.test.jsx b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/SqlEditorLeftBar.test.jsx index 5e1e368b1c690..2c816d0e8447b 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/SqlEditorLeftBar.test.jsx +++ b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/SqlEditorLeftBar.test.jsx @@ -19,101 +19,176 @@ import React from 'react'; import configureStore from 'redux-mock-store'; import fetchMock from 'fetch-mock'; -import { shallow } from 'enzyme'; -import { render, screen } from 'spec/helpers/testing-library'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import { Provider } from 'react-redux'; import '@testing-library/jest-dom/extend-expect'; import thunk from 'redux-thunk'; import SqlEditorLeftBar from 'src/SqlLab/components/SqlEditorLeftBar'; -import TableElement from 'src/SqlLab/components/TableElement'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; -import { - table, - initialState, - databases, - defaultQueryEditor, - mockedActions, -} from 'src/SqlLab/fixtures'; +import { table, initialState, defaultQueryEditor } from 'src/SqlLab/fixtures'; const mockedProps = { - actions: mockedActions, tables: [table], - queryEditor: defaultQueryEditor, - database: databases, + queryEditorId: defaultQueryEditor.id, + database: { + id: 1, + database_name: 'main', + backend: 'mysql', + }, height: 0, }; const middlewares = [thunk]; const mockStore = configureStore(middlewares); const store = mockStore(initialState); -fetchMock.get('glob:*/api/v1/database/*/schemas/?*', { result: [] }); -describe('SqlEditorLeftBar', () => { - let wrapper; - - beforeEach(() => { - wrapper = shallow(<SqlEditorLeftBar {...mockedProps} />, { - context: { store }, - }); - }); - afterEach(() => { - wrapper.unmount(); +beforeEach(() => { + fetchMock.get('glob:*/api/v1/database/?*', { result: [] }); + fetchMock.get('glob:*/api/v1/database/*/schemas/?*', { + count: 2, + result: ['main', 'new_schema'], }); - - it('is valid', () => { - expect(React.isValidElement(<SqlEditorLeftBar {...mockedProps} />)).toBe( - true, - ); + fetchMock.get('glob:*/api/v1/database/*/tables/*', { + count: 1, + result: [ + { + label: 'ab_user', + value: 'ab_user', + }, + ], }); +}); - it('renders a TableElement', () => { - expect(wrapper.find(TableElement)).toExist(); - }); +afterEach(() => { + fetchMock.restore(); }); -describe('Left Panel Expansion', () => { - it('table should be visible when expanded is true', () => { - const { container } = render( - <ThemeProvider theme={supersetTheme}> - <Provider store={store}> - <SqlEditorLeftBar {...mockedProps} /> - </Provider> - </ThemeProvider>, - ); - const dbSelect = screen.getByRole('combobox', { - name: 'Select database or type database name', - }); - const schemaSelect = screen.getByRole('combobox', { - name: 'Select schema or type schema name', - }); - const dropdown = screen.getByText(/Select table or type table name/i); - const abUser = screen.getByText(/ab_user/i); +const renderAndWait = (props, store) => + waitFor(() => + render(<SqlEditorLeftBar {...props} />, { + useRedux: true, + ...(store && { store }), + }), + ); + +test('is valid', () => { + expect( + React.isValidElement( + <Provider store={store}> + <SqlEditorLeftBar {...mockedProps} /> + </Provider>, + ), + ).toBe(true); +}); + +test('renders a TableElement', async () => { + await renderAndWait(mockedProps, store); + expect(await screen.findByText(/Database/i)).toBeInTheDocument(); + const tableElement = screen.getAllByTestId('table-element'); + expect(tableElement.length).toBeGreaterThanOrEqual(1); +}); + +test('table should be visible when expanded is true', async () => { + const { container } = await renderAndWait(mockedProps, store); + + const dbSelect = screen.getByRole('combobox', { + name: 'Select database or type database name', + }); + const schemaSelect = screen.getByRole('combobox', { + name: 'Select schema or type schema name', + }); + const dropdown = screen.getByText(/Table/i); + const abUser = screen.queryAllByText(/ab_user/i); + + await waitFor(() => { + expect(screen.getByText(/Database/i)).toBeInTheDocument(); expect(dbSelect).toBeInTheDocument(); expect(schemaSelect).toBeInTheDocument(); expect(dropdown).toBeInTheDocument(); - expect(abUser).toBeInTheDocument(); + expect(abUser).toHaveLength(2); expect( container.querySelector('.ant-collapse-content-active'), ).toBeInTheDocument(); }); +}); - it('should toggle the table when the header is clicked', async () => { - const collapseMock = jest.fn(); - render( - <ThemeProvider theme={supersetTheme}> - <Provider store={store}> - <SqlEditorLeftBar - actions={{ ...mockedActions, collapseTable: collapseMock }} - tables={[table]} - queryEditor={defaultQueryEditor} - database={databases} - height={0} - /> - </Provider> - </ThemeProvider>, +test('should toggle the table when the header is clicked', async () => { + const store = mockStore(initialState); + await renderAndWait(mockedProps, store); + + const header = (await screen.findAllByText(/ab_user/))[1]; + expect(header).toBeInTheDocument(); + userEvent.click(header); + + await waitFor(() => { + expect(store.getActions()[store.getActions().length - 1].type).toEqual( + 'COLLAPSE_TABLE', ); - const header = screen.getByText(/ab_user/); - userEvent.click(header); - expect(collapseMock).toHaveBeenCalled(); }); }); + +test('When changing database the table list must be updated', async () => { + const { rerender } = await renderAndWait(mockedProps, store); + + expect(screen.getAllByText(/main/i)[0]).toBeInTheDocument(); + expect(screen.getAllByText(/ab_user/i)[0]).toBeInTheDocument(); + + rerender( + <SqlEditorLeftBar + {...mockedProps} + database={{ + id: 2, + database_name: 'new_db', + backend: 'postgresql', + }} + queryEditorId={defaultQueryEditor.id} + tables={[{ ...mockedProps.tables[0], dbId: 2, name: 'new_table' }]} + />, + { + useRedux: true, + store: mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + schema: 'new_schema', + }, + }, + }), + }, + ); + expect(await screen.findByText(/new_db/i)).toBeInTheDocument(); + expect(await screen.findByText(/new_table/i)).toBeInTheDocument(); +}); + +test('ignore schema api when current schema is deprecated', async () => { + const invalidSchemaName = 'None'; + const { rerender } = await renderAndWait( + mockedProps, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + schema: invalidSchemaName, + }, + }, + }), + ); + + expect(await screen.findByText(/Database/i)).toBeInTheDocument(); + expect(screen.queryByText(/None/i)).toBeInTheDocument(); + expect(fetchMock.calls()).not.toContainEqual( + expect.arrayContaining([ + expect.stringContaining( + `/tables/${mockedProps.database.id}/${invalidSchemaName}/`, + ), + ]), + ); + rerender(); + // Deselect the deprecated schema selection + await waitFor(() => + expect(screen.queryByText(/None/i)).not.toBeInTheDocument(), + ); +}); diff --git a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx index f74249465456a..e241e3c2e2c92 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx +++ b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx @@ -18,53 +18,55 @@ */ import React, { useEffect, - useRef, useCallback, useMemo, useState, Dispatch, SetStateAction, } from 'react'; +import { useDispatch } from 'react-redux'; +import querystring from 'query-string'; + +import { + queryEditorSetDb, + queryEditorSetFunctionNames, + addTable, + removeTables, + collapseTable, + expandTable, + queryEditorSetSchema, + queryEditorSetTableOptions, + queryEditorSetSchemaOptions, + setDatabases, + addDangerToast, + resetState, +} from 'src/SqlLab/actions/sqlLab'; import Button from 'src/components/Button'; import { t, styled, css, SupersetTheme } from '@superset-ui/core'; import Collapse from 'src/components/Collapse'; import Icons from 'src/components/Icons'; import { TableSelectorMultiple } from 'src/components/TableSelector'; import { IconTooltip } from 'src/components/IconTooltip'; -import { QueryEditor } from 'src/SqlLab/types'; +import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; import { DatabaseObject } from 'src/components/DatabaseSelector'; -import { EmptyStateSmall } from 'src/components/EmptyState'; -import TableElement, { Table, TableElementProps } from '../TableElement'; +import { emptyStateComponent } from 'src/components/EmptyState'; +import { + getItem, + LocalStorageKeys, + setItem, +} from 'src/utils/localStorageHelpers'; +import TableElement, { Table } from '../TableElement'; interface ExtendedTable extends Table { expanded: boolean; } -interface actionsTypes { - queryEditorSetDb: (queryEditor: QueryEditor, dbId: number) => void; - queryEditorSetFunctionNames: (queryEditor: QueryEditor, dbId: number) => void; - collapseTable: (table: Table) => void; - expandTable: (table: Table) => void; - addTable: (queryEditor: any, database: any, value: any, schema: any) => void; - setDatabases: (arg0: any) => {}; - addDangerToast: (msg: string) => void; - queryEditorSetSchema: (queryEditor: QueryEditor, schema?: string) => void; - queryEditorSetSchemaOptions: () => void; - queryEditorSetTableOptions: ( - queryEditor: QueryEditor, - options: Array<any>, - ) => void; - resetState: () => void; -} - interface SqlEditorLeftBarProps { - queryEditor: QueryEditor; + queryEditorId: string; height?: number; tables?: ExtendedTable[]; - actions: actionsTypes & TableElementProps['actions']; database: DatabaseObject; setEmptyState: Dispatch<SetStateAction<boolean>>; - showDisabled: boolean; } const StyledScrollbarContainer = styled.div` @@ -87,28 +89,53 @@ const collapseStyles = (theme: SupersetTheme) => css` .ant-collapse-arrow { top: ${theme.gridUnit * 2}px !important; color: ${theme.colors.primary.dark1} !important; - &: hover { + &:hover { color: ${theme.colors.primary.dark2} !important; } } `; -export default function SqlEditorLeftBar({ - actions, +const LeftBarStyles = styled.div` + ${({ theme }) => css` + height: 100%; + display: flex; + flex-direction: column; + + .divider { + border-bottom: 1px solid ${theme.colors.grayscale.light4}; + margin: ${theme.gridUnit * 4}px 0; + } + `} +`; + +const SqlEditorLeftBar = ({ database, - queryEditor, + queryEditorId, tables = [], height = 500, setEmptyState, -}: SqlEditorLeftBarProps) { - // Ref needed to avoid infinite rerenders on handlers - // that require and modify the queryEditor - const queryEditorRef = useRef<QueryEditor>(queryEditor); +}: SqlEditorLeftBarProps) => { + const dispatch = useDispatch(); + const queryEditor = useQueryEditor(queryEditorId, ['dbId', 'schema']); + const [emptyResultsWithSearch, setEmptyResultsWithSearch] = useState(false); + const [userSelectedDb, setUserSelected] = useState<DatabaseObject | null>( + null, + ); + const { schema } = queryEditor; useEffect(() => { - queryEditorRef.current = queryEditor; - }, [queryEditor]); + const bool = querystring.parse(window.location.search).db; + const userSelected = getItem( + LocalStorageKeys.db, + null, + ) as DatabaseObject | null; + + if (bool && userSelected) { + setUserSelected(userSelected); + setItem(LocalStorageKeys.db, null); + } else setUserSelected(database); + }, [database]); const onEmptyResults = (searchText?: string) => { setEmptyResultsWithSearch(!!searchText); @@ -116,8 +143,8 @@ export default function SqlEditorLeftBar({ const onDbChange = ({ id: dbId }: { id: number }) => { setEmptyState(false); - actions.queryEditorSetDb(queryEditor, dbId); - actions.queryEditorSetFunctionNames(queryEditor, dbId); + dispatch(queryEditorSetDb(queryEditor, dbId)); + dispatch(queryEditorSetFunctionNames(queryEditor, dbId)); }; const selectedTableNames = useMemo( @@ -142,21 +169,21 @@ export default function SqlEditorLeftBar({ }); tablesToAdd.forEach(tableName => - actions.addTable(queryEditor, database, tableName, schemaName), + dispatch(addTable(queryEditor, database, tableName, schemaName)), ); - currentTables.forEach(table => actions.removeTable(table)); + dispatch(removeTables(currentTables)); }; const onToggleTable = (updatedTables: string[]) => { tables.forEach((table: ExtendedTable) => { if (!updatedTables.includes(table.id.toString()) && table.expanded) { - actions.collapseTable(table); + dispatch(collapseTable(table)); } else if ( updatedTables.includes(table.id.toString()) && !table.expanded ) { - actions.expandTable(table); + dispatch(expandTable(table)); } }); }; @@ -183,54 +210,65 @@ export default function SqlEditorLeftBar({ const shouldShowReset = window.location.search === '?reset=1'; const tableMetaDataHeight = height - 130; // 130 is the height of the selects above - const emptyStateComponent = ( - <EmptyStateSmall - image="empty.svg" - title={ - emptyResultsWithSearch - ? t('No databases match your search') - : t('There are no databases available') - } - description={ - <p> - {t('Manage your databases')}{' '} - <a href="/databaseview/list">{t('here')}</a> - </p> - } - /> - ); const handleSchemaChange = useCallback( (schema: string) => { - if (queryEditorRef.current) { - actions.queryEditorSetSchema(queryEditorRef.current, schema); + if (queryEditor) { + dispatch(queryEditorSetSchema(queryEditor, schema)); } }, - [actions], + [dispatch, queryEditor], ); - const handleTablesLoad = React.useCallback( + const handleTablesLoad = useCallback( (options: Array<any>) => { - if (queryEditorRef.current) { - actions.queryEditorSetTableOptions(queryEditorRef.current, options); + if (queryEditor) { + dispatch(queryEditorSetTableOptions(queryEditor, options)); } }, - [actions], + [dispatch, queryEditor], ); + const handleSchemasLoad = useCallback( + (options: Array<any>) => { + if (queryEditor) { + dispatch(queryEditorSetSchemaOptions(queryEditor, options)); + } + }, + [dispatch, queryEditor], + ); + + const handleDbList = useCallback( + (result: DatabaseObject) => { + dispatch(setDatabases(result)); + }, + [dispatch], + ); + + const handleError = useCallback( + (message: string) => { + dispatch(addDangerToast(message)); + }, + [dispatch], + ); + + const handleResetState = useCallback(() => { + dispatch(resetState()); + }, [dispatch]); + return ( - <div className="SqlEditorLeftBar"> + <LeftBarStyles data-test="sql-editor-left-bar"> <TableSelectorMultiple onEmptyResults={onEmptyResults} - emptyState={emptyStateComponent} - database={database} - getDbList={actions.setDatabases} - handleError={actions.addDangerToast} + emptyState={emptyStateComponent(emptyResultsWithSearch)} + database={userSelectedDb} + getDbList={handleDbList} + handleError={handleError} onDbChange={onDbChange} onSchemaChange={handleSchemaChange} - onSchemasLoad={actions.queryEditorSetSchemaOptions} + onSchemasLoad={handleSchemasLoad} onTableSelectChange={onTablesChange} onTablesLoad={handleTablesLoad} - schema={queryEditor.schema} + schema={schema} tableValue={selectedTableNames} sqlLabMode /> @@ -252,7 +290,7 @@ export default function SqlEditorLeftBar({ expandIcon={renderExpandIconWithTooltip} > {tables.map(table => ( - <TableElement table={table} key={table.id} actions={actions} /> + <TableElement table={table} key={table.id} /> ))} </Collapse> </div> @@ -261,11 +299,13 @@ export default function SqlEditorLeftBar({ <Button buttonSize="small" buttonStyle="danger" - onClick={actions.resetState} + onClick={handleResetState} > <i className="fa fa-bomb" /> {t('Reset state')} </Button> )} - </div> + </LeftBarStyles> ); -} +}; + +export default SqlEditorLeftBar; diff --git a/superset-frontend/src/SqlLab/components/SqlEditorTabHeader/SqlEditorTabHeader.test.tsx b/superset-frontend/src/SqlLab/components/SqlEditorTabHeader/SqlEditorTabHeader.test.tsx new file mode 100644 index 0000000000000..6c231401c7053 --- /dev/null +++ b/superset-frontend/src/SqlLab/components/SqlEditorTabHeader/SqlEditorTabHeader.test.tsx @@ -0,0 +1,220 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { + fireEvent, + screen, + render, + waitFor, +} from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { QueryEditor } from 'src/SqlLab/types'; +import { + initialState, + defaultQueryEditor, + extraQueryEditor1, + extraQueryEditor2, +} from 'src/SqlLab/fixtures'; +import { Store } from 'redux'; +import { + REMOVE_QUERY_EDITOR, + QUERY_EDITOR_SET_TITLE, + ADD_QUERY_EDITOR, + QUERY_EDITOR_TOGGLE_LEFT_BAR, +} from 'src/SqlLab/actions/sqlLab'; +import SqlEditorTabHeader from 'src/SqlLab/components/SqlEditorTabHeader'; + +jest.mock('src/components/DeprecatedSelect', () => () => ( + <div data-test="mock-deprecated-select" /> +)); +jest.mock('src/components/Select/Select', () => () => ( + <div data-test="mock-deprecated-select-select" /> +)); +jest.mock('src/components/Select/AsyncSelect', () => () => ( + <div data-test="mock-async-select" /> +)); + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); +const setup = (queryEditor: QueryEditor, store?: Store) => + render(<SqlEditorTabHeader queryEditor={queryEditor} />, { + useRedux: true, + ...(store && { store }), + }); + +describe('SqlEditorTabHeader', () => { + it('renders name', () => { + const { queryByText } = setup(defaultQueryEditor, mockStore(initialState)); + expect(queryByText(defaultQueryEditor.name)).toBeTruthy(); + expect(queryByText(extraQueryEditor1.name)).toBeFalsy(); + expect(queryByText(extraQueryEditor2.name)).toBeFalsy(); + }); + + it('renders name from unsaved changes', () => { + const expectedTitle = 'updated title'; + const { queryByText } = setup( + defaultQueryEditor, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + name: expectedTitle, + }, + }, + }), + ); + expect(queryByText(expectedTitle)).toBeTruthy(); + expect(queryByText(defaultQueryEditor.name)).toBeFalsy(); + expect(queryByText(extraQueryEditor1.name)).toBeFalsy(); + expect(queryByText(extraQueryEditor2.name)).toBeFalsy(); + }); + + it('renders current name for unrelated unsaved changes', () => { + const unrelatedTitle = 'updated title'; + const { queryByText } = setup( + defaultQueryEditor, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: `${defaultQueryEditor.id}-other`, + name: unrelatedTitle, + }, + }, + }), + ); + expect(queryByText(defaultQueryEditor.name)).toBeTruthy(); + expect(queryByText(unrelatedTitle)).toBeFalsy(); + expect(queryByText(extraQueryEditor1.name)).toBeFalsy(); + expect(queryByText(extraQueryEditor2.name)).toBeFalsy(); + }); + + describe('with dropdown menus', () => { + let store = mockStore(); + beforeEach(async () => { + store = mockStore(initialState); + const { getByTestId } = setup(defaultQueryEditor, store); + const dropdown = getByTestId('dropdown-trigger'); + + userEvent.click(dropdown); + }); + + it('should dispatch removeQueryEditor action', async () => { + await waitFor(() => + expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(), + ); + + fireEvent.click(screen.getByTestId('close-tab-menu-option')); + + const actions = store.getActions(); + await waitFor(() => + expect(actions[0]).toEqual({ + type: REMOVE_QUERY_EDITOR, + queryEditor: defaultQueryEditor, + }), + ); + }); + + it('should dispatch queryEditorSetTitle action', async () => { + await waitFor(() => + expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(), + ); + const expectedTitle = 'typed text'; + const mockPrompt = jest + .spyOn(window, 'prompt') + .mockImplementation(() => expectedTitle); + fireEvent.click(screen.getByTestId('rename-tab-menu-option')); + + const actions = store.getActions(); + await waitFor(() => + expect(actions[0]).toEqual({ + type: QUERY_EDITOR_SET_TITLE, + name: expectedTitle, + queryEditor: expect.objectContaining({ + id: defaultQueryEditor.id, + }), + }), + ); + mockPrompt.mockClear(); + }); + + it('should dispatch toggleLeftBar action', async () => { + await waitFor(() => + expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(), + ); + fireEvent.click(screen.getByTestId('toggle-menu-option')); + + const actions = store.getActions(); + await waitFor(() => + expect(actions[0]).toEqual({ + type: QUERY_EDITOR_TOGGLE_LEFT_BAR, + hideLeftBar: !defaultQueryEditor.hideLeftBar, + queryEditor: expect.objectContaining({ + id: defaultQueryEditor.id, + }), + }), + ); + }); + + it('should dispatch removeAllOtherQueryEditors action', async () => { + await waitFor(() => + expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(), + ); + fireEvent.click(screen.getByTestId('close-all-other-menu-option')); + + const actions = store.getActions(); + await waitFor(() => + expect(actions).toEqual([ + { + type: REMOVE_QUERY_EDITOR, + queryEditor: initialState.sqlLab.queryEditors[1], + }, + { + type: REMOVE_QUERY_EDITOR, + queryEditor: initialState.sqlLab.queryEditors[2], + }, + ]), + ); + }); + + it('should dispatch cloneQueryToNewTab action', async () => { + await waitFor(() => + expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(), + ); + fireEvent.click(screen.getByTestId('clone-tab-menu-option')); + + const actions = store.getActions(); + await waitFor(() => + expect(actions[0]).toEqual({ + type: ADD_QUERY_EDITOR, + queryEditor: expect.objectContaining({ + name: `Copy of ${defaultQueryEditor.name}`, + sql: defaultQueryEditor.sql, + autorun: false, + }), + }), + ); + }); + }); +}); diff --git a/superset-frontend/src/SqlLab/components/SqlEditorTabHeader/index.tsx b/superset-frontend/src/SqlLab/components/SqlEditorTabHeader/index.tsx new file mode 100644 index 0000000000000..1e1b22a81d245 --- /dev/null +++ b/superset-frontend/src/SqlLab/components/SqlEditorTabHeader/index.tsx @@ -0,0 +1,153 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useMemo } from 'react'; +import { bindActionCreators } from 'redux'; +import { useSelector, useDispatch, shallowEqual } from 'react-redux'; +import { Dropdown } from 'src/components/Dropdown'; +import { Menu } from 'src/components/Menu'; +import { styled, t, QueryState } from '@superset-ui/core'; +import { + removeQueryEditor, + removeAllOtherQueryEditors, + queryEditorSetTitle, + cloneQueryToNewTab, + toggleLeftBar, +} from 'src/SqlLab/actions/sqlLab'; +import { QueryEditor, SqlLabRootState } from 'src/SqlLab/types'; +import TabStatusIcon from '../TabStatusIcon'; + +const TabTitleWrapper = styled.div` + display: flex; + align-items: center; +`; +const TabTitle = styled.span` + margin-right: ${({ theme }) => theme.gridUnit * 2}px; + text-transform: none; +`; + +const IconContainer = styled.div` + display: inline-block; + width: ${({ theme }) => theme.gridUnit * 8}px; + text-align: center; +`; + +interface Props { + queryEditor: QueryEditor; +} + +const SqlEditorTabHeader: React.FC<Props> = ({ queryEditor }) => { + const qe = useSelector<SqlLabRootState, QueryEditor>( + ({ sqlLab: { unsavedQueryEditor } }) => ({ + ...queryEditor, + ...(queryEditor.id === unsavedQueryEditor.id && unsavedQueryEditor), + }), + shallowEqual, + ); + const queryState = useSelector<SqlLabRootState, QueryState>( + ({ sqlLab }) => sqlLab.queries[qe.latestQueryId || '']?.state || '', + ); + const dispatch = useDispatch(); + const actions = useMemo( + () => + bindActionCreators( + { + removeQueryEditor, + removeAllOtherQueryEditors, + queryEditorSetTitle, + cloneQueryToNewTab, + toggleLeftBar, + }, + dispatch, + ), + [dispatch], + ); + + function renameTab() { + const newTitle = prompt(t('Enter a new title for the tab')); + if (newTitle) { + actions.queryEditorSetTitle(qe, newTitle, qe.id); + } + } + + return ( + <TabTitleWrapper> + <Dropdown + trigger={['click']} + overlay={ + <Menu style={{ width: 176 }}> + <Menu.Item + className="close-btn" + key="1" + onClick={() => actions.removeQueryEditor(qe)} + data-test="close-tab-menu-option" + > + <IconContainer> + <i className="fa fa-close" /> + </IconContainer> + {t('Close tab')} + </Menu.Item> + <Menu.Item + key="2" + onClick={renameTab} + data-test="rename-tab-menu-option" + > + <IconContainer> + <i className="fa fa-i-cursor" /> + </IconContainer> + {t('Rename tab')} + </Menu.Item> + <Menu.Item + key="3" + onClick={() => actions.toggleLeftBar(qe)} + data-test="toggle-menu-option" + > + <IconContainer> + <i className="fa fa-cogs" /> + </IconContainer> + {qe.hideLeftBar ? t('Expand tool bar') : t('Hide tool bar')} + </Menu.Item> + <Menu.Item + key="4" + onClick={() => actions.removeAllOtherQueryEditors(qe)} + data-test="close-all-other-menu-option" + > + <IconContainer> + <i className="fa fa-times-circle-o" /> + </IconContainer> + {t('Close all other tabs')} + </Menu.Item> + <Menu.Item + key="5" + onClick={() => actions.cloneQueryToNewTab(qe, false)} + data-test="clone-tab-menu-option" + > + <IconContainer> + <i className="fa fa-files-o" /> + </IconContainer> + {t('Duplicate tab')} + </Menu.Item> + </Menu> + } + /> + <TabTitle>{qe.name}</TabTitle> <TabStatusIcon tabState={queryState} />{' '} + </TabTitleWrapper> + ); +}; + +export default SqlEditorTabHeader; diff --git a/superset-frontend/src/SqlLab/components/TabStatusIcon/TabStatusIcon.test.jsx b/superset-frontend/src/SqlLab/components/TabStatusIcon/TabStatusIcon.test.tsx similarity index 72% rename from superset-frontend/src/SqlLab/components/TabStatusIcon/TabStatusIcon.test.jsx rename to superset-frontend/src/SqlLab/components/TabStatusIcon/TabStatusIcon.test.tsx index 08923c5d9e9e8..fb8ee55992301 100644 --- a/superset-frontend/src/SqlLab/components/TabStatusIcon/TabStatusIcon.test.jsx +++ b/superset-frontend/src/SqlLab/components/TabStatusIcon/TabStatusIcon.test.tsx @@ -16,24 +16,22 @@ * specific language governing permissions and limitations * under the License. */ +import { QueryState } from '@superset-ui/core'; import React from 'react'; -import sinon from 'sinon'; -import { shallow } from 'enzyme'; +import { render } from 'spec/helpers/testing-library'; import TabStatusIcon from 'src/SqlLab/components/TabStatusIcon'; function setup() { - const onClose = sinon.spy(); - const wrapper = shallow( - <TabStatusIcon onClose={onClose} tabState="running" />, - ); - return { wrapper, onClose }; + return render(<TabStatusIcon tabState={'running' as QueryState} />); } describe('TabStatusIcon', () => { it('renders a circle without an x when hovered', () => { - const { wrapper } = setup(); - expect(wrapper.find('div.circle')).toExist(); - expect(wrapper.text()).toBe(''); + const { container } = setup(); + expect(container.getElementsByClassName('circle')[0]).toBeInTheDocument(); + expect( + container.getElementsByClassName('circle')[0]?.textContent ?? 'undefined', + ).toBe(''); }); }); diff --git a/superset-frontend/src/SqlLab/components/TabStatusIcon/index.tsx b/superset-frontend/src/SqlLab/components/TabStatusIcon/index.tsx index 799124fb9c099..f40e946866586 100644 --- a/superset-frontend/src/SqlLab/components/TabStatusIcon/index.tsx +++ b/superset-frontend/src/SqlLab/components/TabStatusIcon/index.tsx @@ -17,12 +17,62 @@ * under the License. */ import React from 'react'; -import { QueryState } from '@superset-ui/core'; +import { css, QueryState, styled } from '@superset-ui/core'; +import Icons, { IconType } from 'src/components/Icons'; + +const IconContainer = styled.span` + position: absolute; + top: -6px; + left: 1px; +`; + +const Circle = styled.div` + ${({ theme }) => css` + border-radius: 50%; + width: ${theme.gridUnit * 3}px; + height: ${theme.gridUnit * 3}px; + + display: inline-block; + background-color: ${theme.colors.grayscale.light2}; + text-align: center; + vertical-align: middle; + font-size: ${theme.typography.sizes.m}px; + font-weight: ${theme.typography.weights.bold}; + color: ${theme.colors.grayscale.light5}; + position: relative; + + &.running { + background-color: ${theme.colors.info.base}; + } + + &.success { + background-color: ${theme.colors.success.base}; + } + + &.failed { + background-color: ${theme.colors.error.base}; + } + `} +`; interface TabStatusIconProps { tabState: QueryState; } +const STATE_ICONS: Record<string, React.FC<IconType>> = { + success: Icons.Check, + failed: Icons.CancelX, +}; + export default function TabStatusIcon({ tabState }: TabStatusIconProps) { - return <div className={`circle ${tabState}`} />; + const StatusIcon = STATE_ICONS[tabState]; + return ( + <Circle className={`circle ${tabState}`}> + {StatusIcon && ( + <IconContainer> + <StatusIcon iconSize="xs" /> + </IconContainer> + )} + </Circle> + ); } diff --git a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/TabbedSqlEditors.test.jsx b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/TabbedSqlEditors.test.jsx index 9f8e5bcf1ae25..105751a4d0ebd 100644 --- a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/TabbedSqlEditors.test.jsx +++ b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/TabbedSqlEditors.test.jsx @@ -22,6 +22,7 @@ import thunk from 'redux-thunk'; import URI from 'urijs'; import { Provider } from 'react-redux'; import { shallow, mount } from 'enzyme'; +import { fireEvent, render, waitFor } from 'spec/helpers/testing-library'; import sinon from 'sinon'; import { act } from 'react-dom/test-utils'; import fetchMock from 'fetch-mock'; @@ -29,7 +30,9 @@ import { supersetTheme, ThemeProvider } from '@superset-ui/core'; import { EditableTabs } from 'src/components/Tabs'; import TabbedSqlEditors from 'src/SqlLab/components/TabbedSqlEditors'; import SqlEditor from 'src/SqlLab/components/SqlEditor'; -import { table, initialState } from 'src/SqlLab/fixtures'; +import { initialState } from 'src/SqlLab/fixtures'; +import { newQueryTabName } from 'src/SqlLab/utils/newQueryTabName'; +import QueryProvider from 'src/views/QueryProvider'; fetchMock.get('glob:*/api/v1/database/*', {}); fetchMock.get('glob:*/savedqueryviewapi/api/get/*', {}); @@ -40,12 +43,6 @@ describe('TabbedSqlEditors', () => { const mockStore = configureStore(middlewares); const store = mockStore(initialState); - const tabHistory = ['dfsadfs', 'newEditorId']; - - const tables = [ - { ...table, dataPreviewQueryId: 'B1-VQU1zW', queryEditorId: 'newEditorId' }, - ]; - const queryEditors = [ { autorun: false, @@ -55,17 +52,9 @@ describe('TabbedSqlEditors', () => { schema: null, selectedText: null, sql: 'SELECT ds...', - title: 'Untitled Query', + name: 'Untitled Query', }, ]; - const queries = { - 'B1-VQU1zW': { - id: 'B1-VQU1zW', - sqlEditorId: 'newEditorId', - tableName: 'ab_user', - state: 'success', - }, - }; const mockedProps = { actions: {}, databases: {}, @@ -88,15 +77,22 @@ describe('TabbedSqlEditors', () => { const mountWithAct = async () => act(async () => { mount( - <Provider store={store}> - <TabbedSqlEditors {...mockedProps} /> - </Provider>, + <QueryProvider> + <Provider store={store}> + <TabbedSqlEditors {...mockedProps} /> + </Provider> + </QueryProvider>, { wrappingComponent: ThemeProvider, wrappingComponentProps: { theme: supersetTheme }, }, ); }); + const setup = (props = {}, overridesStore) => + render(<TabbedSqlEditors {...props} />, { + useRedux: true, + store: overridesStore || store, + }); let wrapper; it('is valid', () => { @@ -136,32 +132,6 @@ describe('TabbedSqlEditors', () => { ); }); }); - describe('UNSAFE_componentWillReceiveProps', () => { - beforeEach(() => { - wrapper = getWrapper(); - wrapper.setProps({ queryEditors, queries, tabHistory, tables }); - }); - it('should update queriesArray and dataPreviewQueries', () => { - expect(wrapper.state().queriesArray.slice(-1)[0]).toBe( - queries['B1-VQU1zW'], - ); - expect(wrapper.state().dataPreviewQueries.slice(-1)[0]).toEqual( - queries['B1-VQU1zW'], - ); - }); - }); - it('should rename Tab', () => { - global.prompt = () => 'new title'; - wrapper = getWrapper(); - sinon.stub(wrapper.instance().props.actions, 'queryEditorSetTitle'); - - wrapper.instance().renameTab(queryEditors[0]); - expect( - wrapper.instance().props.actions.queryEditorSetTitle.getCall(0).args[1], - ).toBe('new title'); - - delete global.prompt; - }); it('should removeQueryEditor', () => { wrapper = getWrapper(); sinon.stub(wrapper.instance().props.actions, 'removeQueryEditor'); @@ -171,23 +141,32 @@ describe('TabbedSqlEditors', () => { wrapper.instance().props.actions.removeQueryEditor.getCall(0).args[0], ).toBe(queryEditors[0]); }); - it('should add new query editor', () => { - wrapper = getWrapper(); - sinon.stub(wrapper.instance().props.actions, 'addQueryEditor'); - - wrapper.instance().newQueryEditor(); - expect( - wrapper.instance().props.actions.addQueryEditor.getCall(0).args[0].title, - ).toContain('Untitled Query'); + it('should add new query editor', async () => { + const { getAllByLabelText } = setup(mockedProps); + fireEvent.click(getAllByLabelText('Add tab')[0]); + const actions = store.getActions(); + await waitFor(() => + expect(actions).toContainEqual({ + type: 'ADD_QUERY_EDITOR', + queryEditor: expect.objectContaining({ + name: expect.stringMatching(/Untitled Query (\d+)+/), + }), + }), + ); }); - it('should properly increment query tab name', () => { - wrapper = getWrapper(); - sinon.stub(wrapper.instance().props.actions, 'addQueryEditor'); - - wrapper.instance().newQueryEditor(); - expect( - wrapper.instance().props.actions.addQueryEditor.getCall(0).args[0].title, - ).toContain('Untitled Query 2'); + it('should properly increment query tab name', async () => { + const { getAllByLabelText } = setup(mockedProps); + const newTitle = newQueryTabName(store.getState().sqlLab.queryEditors); + fireEvent.click(getAllByLabelText('Add tab')[0]); + const actions = store.getActions(); + await waitFor(() => + expect(actions).toContainEqual({ + type: 'ADD_QUERY_EDITOR', + queryEditor: expect.objectContaining({ + name: newTitle, + }), + }), + ); }); it('should duplicate query editor', () => { wrapper = getWrapper(); @@ -233,9 +212,9 @@ describe('TabbedSqlEditors', () => { }); it('should disable new tab when offline', () => { wrapper = getWrapper(); - expect(wrapper.find(EditableTabs).props().hideAdd).toBe(false); + expect(wrapper.find('#a11y-query-editor-tabs').props().hideAdd).toBe(false); wrapper.setProps({ offline: true }); - expect(wrapper.find(EditableTabs).props().hideAdd).toBe(true); + expect(wrapper.find('#a11y-query-editor-tabs').props().hideAdd).toBe(true); }); it('should have an empty state when query editors is empty', () => { wrapper = getWrapper(); diff --git a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx index 494ef9cba0ef7..1b3e3a999d778 100644 --- a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx +++ b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx @@ -18,22 +18,19 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import { Dropdown } from 'src/components/Dropdown'; import { EditableTabs } from 'src/components/Tabs'; -import { Menu } from 'src/components/Menu'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import URI from 'urijs'; import { styled, t } from '@superset-ui/core'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; -import { areArraysShallowEqual } from 'src/reduxUtils'; import { Tooltip } from 'src/components/Tooltip'; import { detectOS } from 'src/utils/common'; import * as Actions from 'src/SqlLab/actions/sqlLab'; import { EmptyStateBig } from 'src/components/EmptyState'; -import { newQueryTabName } from '../../utils/newQueryTabName'; +import getBootstrapData from 'src/utils/getBootstrapData'; import SqlEditor from '../SqlEditor'; -import TabStatusIcon from '../TabStatusIcon'; +import SqlEditorTabHeader from '../SqlEditorTabHeader'; const propTypes = { actions: PropTypes.object.isRequired, @@ -44,7 +41,6 @@ const propTypes = { databases: PropTypes.object.isRequired, queries: PropTypes.object.isRequired, queryEditors: PropTypes.array, - requestedQuery: PropTypes.object, tabHistory: PropTypes.array.isRequired, tables: PropTypes.array.isRequired, offline: PropTypes.bool, @@ -54,14 +50,14 @@ const propTypes = { const defaultProps = { queryEditors: [], offline: false, - requestedQuery: null, saveQueryWarning: null, scheduleQueryWarning: null, }; -const TabTitleWrapper = styled.div` +const StyledEditableTabs = styled(EditableTabs)` + height: 100%; display: flex; - align-items: center; + flex-direction: column; `; const StyledTab = styled.span` @@ -82,14 +78,8 @@ class TabbedSqlEditors extends React.PureComponent { const sqlLabUrl = '/superset/sqllab'; this.state = { sqlLabUrl, - queriesArray: [], - dataPreviewQueries: [], }; this.removeQueryEditor = this.removeQueryEditor.bind(this); - this.renameTab = this.renameTab.bind(this); - this.toggleLeftBar = this.toggleLeftBar.bind(this); - this.removeAllOtherQueryEditors = - this.removeAllOtherQueryEditors.bind(this); this.duplicateQueryEditor = this.duplicateQueryEditor.bind(this); this.handleSelect = this.handleSelect.bind(this); this.handleEdit = this.handleEdit.bind(this); @@ -123,13 +113,10 @@ class TabbedSqlEditors extends React.PureComponent { } // merge post form data with GET search params - // Hack: this data should be comming from getInitialState + // Hack: this data should be coming from getInitialState // but for some reason this data isn't being passed properly through // the reducer. - const appContainer = document.getElementById('app'); - const bootstrapData = JSON.parse( - appContainer?.getAttribute('data-bootstrap') || '{}', - ); + const bootstrapData = getBootstrapData(); const query = { ...bootstrapData.requested_query, ...URI(window.location).search(true), @@ -167,7 +154,7 @@ class TabbedSqlEditors extends React.PureComponent { } } const newQueryEditor = { - title: query.title, + name: query.name, dbId, schema: query.schema, autorun: query.autorun, @@ -200,50 +187,11 @@ class TabbedSqlEditors extends React.PureComponent { } } - UNSAFE_componentWillReceiveProps(nextProps) { - const nextActiveQeId = - nextProps.tabHistory[nextProps.tabHistory.length - 1]; - const queriesArray = Object.values(nextProps.queries).filter( - query => query.sqlEditorId === nextActiveQeId, - ); - if (!areArraysShallowEqual(queriesArray, this.state.queriesArray)) { - this.setState({ queriesArray }); - } - - const dataPreviewQueries = []; - nextProps.tables.forEach(table => { - const queryId = table.dataPreviewQueryId; - if ( - queryId && - nextProps.queries[queryId] && - table.queryEditorId === nextActiveQeId - ) { - dataPreviewQueries.push({ - ...nextProps.queries[queryId], - tableName: table.name, - }); - } - }); - if ( - !areArraysShallowEqual(dataPreviewQueries, this.state.dataPreviewQueries) - ) { - this.setState({ dataPreviewQueries }); - } - } - popNewTab() { // Clean the url in browser history window.history.replaceState({}, document.title, this.state.sqlLabUrl); } - renameTab(qe) { - /* eslint no-alert: 0 */ - const newTitle = prompt(t('Enter a new title for the tab')); - if (newTitle) { - this.props.actions.queryEditorSetTitle(qe, newTitle); - } - } - activeQueryEditor() { if (this.props.tabHistory.length === 0) { return this.props.queryEditors[0]; @@ -253,36 +201,16 @@ class TabbedSqlEditors extends React.PureComponent { } newQueryEditor() { - const activeQueryEditor = this.activeQueryEditor(); - const firstDbId = Math.min( - ...Object.values(this.props.databases).map(database => database.id), - ); - const warning = isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE) - ? '' - : t( - '-- Note: Unless you save your query, these tabs will NOT persist if you clear your cookies or change browsers.\n\n', - ); - - const newTitle = newQueryTabName(this.props.queryEditors || []); - - const qe = { - title: newTitle, - dbId: - activeQueryEditor && activeQueryEditor.dbId - ? activeQueryEditor.dbId - : this.props.defaultDbId || firstDbId, - schema: activeQueryEditor ? activeQueryEditor.schema : null, - autorun: false, - sql: `${warning}SELECT ...`, - queryLimit: this.props.defaultQueryLimit, - }; - this.props.actions.addQueryEditor(qe); + this.props.actions.addNewQueryEditor(); } handleSelect(key) { const qeid = this.props.tabHistory[this.props.tabHistory.length - 1]; if (key !== qeid) { const queryEditor = this.props.queryEditors.find(qe => qe.id === key); + if (!queryEditor) { + return; + } this.props.actions.switchQueryEditor( queryEditor, this.props.displayLimit, @@ -304,106 +232,30 @@ class TabbedSqlEditors extends React.PureComponent { this.props.actions.removeQueryEditor(qe); } - removeAllOtherQueryEditors(cqe) { - this.props.queryEditors.forEach( - qe => qe !== cqe && this.removeQueryEditor(qe), - ); - } - duplicateQueryEditor(qe) { this.props.actions.cloneQueryToNewTab(qe, false); } - toggleLeftBar(qe) { - this.props.actions.toggleLeftBar(qe); - } - render() { const noQueryEditors = this.props.queryEditors?.length === 0; - const editors = this.props.queryEditors.map(qe => { - let latestQuery; - if (qe.latestQueryId) { - latestQuery = this.props.queries[qe.latestQueryId]; - } - let database; - if (qe.dbId) { - database = this.props.databases[qe.dbId]; - } - const state = latestQuery ? latestQuery.state : ''; - - const menu = ( - <Menu style={{ width: 176 }}> - <Menu.Item - className="close-btn" - key="1" - onClick={() => this.removeQueryEditor(qe)} - data-test="close-tab-menu-option" - > - <div className="icon-container"> - <i className="fa fa-close" /> - </div> - {t('Close tab')} - </Menu.Item> - <Menu.Item key="2" onClick={() => this.renameTab(qe)}> - <div className="icon-container"> - <i className="fa fa-i-cursor" /> - </div> - {t('Rename tab')} - </Menu.Item> - <Menu.Item key="3" onClick={() => this.toggleLeftBar(qe)}> - <div className="icon-container"> - <i className="fa fa-cogs" /> - </div> - {qe.hideLeftBar ? t('Expand tool bar') : t('Hide tool bar')} - </Menu.Item> - <Menu.Item - key="4" - onClick={() => this.removeAllOtherQueryEditors(qe)} - > - <div className="icon-container"> - <i className="fa fa-times-circle-o" /> - </div> - {t('Close all other tabs')} - </Menu.Item> - <Menu.Item key="5" onClick={() => this.duplicateQueryEditor(qe)}> - <div className="icon-container"> - <i className="fa fa-files-o" /> - </div> - {t('Duplicate tab')} - </Menu.Item> - </Menu> - ); - const tabHeader = ( - <TabTitleWrapper> - <Dropdown overlay={menu} trigger={['click']} /> - <TabTitle>{qe.title}</TabTitle> <TabStatusIcon tabState={state} />{' '} - </TabTitleWrapper> - ); - return ( - <EditableTabs.TabPane - key={qe.id} - tab={tabHeader} - // for tests - key prop isn't handled by enzyme well bcs it's a react keyword - data-key={qe.id} - > - <SqlEditor - tables={this.props.tables.filter(xt => xt.queryEditorId === qe.id)} - queryEditorId={qe.id} - editorQueries={this.state.queriesArray} - dataPreviewQueries={this.state.dataPreviewQueries} - latestQuery={latestQuery} - database={database} - actions={this.props.actions} - hideLeftBar={qe.hideLeftBar} - defaultQueryLimit={this.props.defaultQueryLimit} - maxRow={this.props.maxRow} - displayLimit={this.props.displayLimit} - saveQueryWarning={this.props.saveQueryWarning} - scheduleQueryWarning={this.props.scheduleQueryWarning} - /> - </EditableTabs.TabPane> - ); - }); + const editors = this.props.queryEditors?.map(qe => ( + <EditableTabs.TabPane + key={qe.id} + tab={<SqlEditorTabHeader queryEditor={qe} />} + // for tests - key prop isn't handled by enzyme well bcs it's a react keyword + data-key={qe.id} + > + <SqlEditor + tables={this.props.tables.filter(xt => xt.queryEditorId === qe.id)} + queryEditor={qe} + defaultQueryLimit={this.props.defaultQueryLimit} + maxRow={this.props.maxRow} + displayLimit={this.props.displayLimit} + saveQueryWarning={this.props.saveQueryWarning} + scheduleQueryWarning={this.props.scheduleQueryWarning} + /> + </EditableTabs.TabPane> + )); const emptyTab = ( <StyledTab> @@ -437,7 +289,7 @@ class TabbedSqlEditors extends React.PureComponent { ); return ( - <EditableTabs + <StyledEditableTabs destroyInactiveTabPane activeKey={this.props.tabHistory[this.props.tabHistory.length - 1]} id="a11y-query-editor-tabs" @@ -465,14 +317,14 @@ class TabbedSqlEditors extends React.PureComponent { > {editors} {noQueryEditors && emptyTabState} - </EditableTabs> + </StyledEditableTabs> ); } } TabbedSqlEditors.propTypes = propTypes; TabbedSqlEditors.defaultProps = defaultProps; -function mapStateToProps({ sqlLab, common, requestedQuery }) { +function mapStateToProps({ sqlLab, common }) { return { databases: sqlLab.databases, queryEditors: sqlLab.queryEditors, @@ -486,7 +338,6 @@ function mapStateToProps({ sqlLab, common, requestedQuery }) { maxRow: common.conf.SQL_MAX_ROW, saveQueryWarning: common.conf.SQLLAB_SAVE_WARNING_MESSAGE, scheduleQueryWarning: common.conf.SQLLAB_SCHEDULE_WARNING_MESSAGE, - requestedQuery, }; } function mapDispatchToProps(dispatch) { diff --git a/superset-frontend/src/SqlLab/components/TableElement/TableElement.test.jsx b/superset-frontend/src/SqlLab/components/TableElement/TableElement.test.jsx index 91bddc57fb2b3..60efa3a59677f 100644 --- a/superset-frontend/src/SqlLab/components/TableElement/TableElement.test.jsx +++ b/superset-frontend/src/SqlLab/components/TableElement/TableElement.test.jsx @@ -17,22 +17,24 @@ * under the License. */ import React from 'react'; -import { mount, shallow } from 'enzyme'; +import { mount } from 'enzyme'; import { Provider } from 'react-redux'; import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; import Collapse from 'src/components/Collapse'; import { IconTooltip } from 'src/components/IconTooltip'; import TableElement from 'src/SqlLab/components/TableElement'; import ColumnElement from 'src/SqlLab/components/ColumnElement'; import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; -import { mockedActions, table } from 'src/SqlLab/fixtures'; +import { initialState, table } from 'src/SqlLab/fixtures'; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); describe('TableElement', () => { - const mockStore = configureStore([]); - const store = mockStore({}); + const store = mockStore(initialState); const mockedProps = { - actions: mockedActions, table, timeout: 0, }; @@ -57,7 +59,17 @@ describe('TableElement', () => { expect(wrapper.find(IconTooltip)).toHaveLength(4); }); it('has 14 columns', () => { - const wrapper = shallow(<TableElement {...mockedProps} />); + const wrapper = mount( + <Provider store={store}> + <TableElement {...mockedProps} /> + </Provider>, + { + wrappingComponent: ThemeProvider, + wrappingComponentProps: { + theme: supersetTheme, + }, + }, + ); expect(wrapper.find(ColumnElement)).toHaveLength(14); }); it('mounts', () => { @@ -143,6 +155,7 @@ describe('TableElement', () => { }, ); wrapper.find('.table-remove').hostNodes().simulate('click'); - expect(mockedActions.removeDataPreview.called).toBe(true); + expect(store.getActions()).toHaveLength(1); + expect(store.getActions()[0].type).toEqual('REMOVE_DATA_PREVIEW'); }); }); diff --git a/superset-frontend/src/SqlLab/components/TableElement/index.tsx b/superset-frontend/src/SqlLab/components/TableElement/index.tsx index 6e5b18d28c4d7..0f1140f9e87cd 100644 --- a/superset-frontend/src/SqlLab/components/TableElement/index.tsx +++ b/superset-frontend/src/SqlLab/components/TableElement/index.tsx @@ -17,12 +17,14 @@ * under the License. */ import React, { useState, useRef } from 'react'; +import { useDispatch } from 'react-redux'; import Collapse from 'src/components/Collapse'; import Card from 'src/components/Card'; import ButtonGroup from 'src/components/ButtonGroup'; -import { t, styled } from '@superset-ui/core'; +import { css, t, styled } from '@superset-ui/core'; import { debounce } from 'lodash'; +import { removeDataPreview, removeTables } from 'src/SqlLab/actions/sqlLab'; import { Tooltip } from 'src/components/Tooltip'; import CopyToClipboard from 'src/components/CopyToClipboard'; import { IconTooltip } from 'src/components/IconTooltip'; @@ -55,15 +57,11 @@ export interface Table { export interface TableElementProps { table: Table; - actions: { - removeDataPreview: (table: Table) => void; - removeTable: (table: Table) => void; - }; } const StyledSpan = styled.span` color: ${({ theme }) => theme.colors.primary.dark1}; - &: hover { + &:hover { color: ${({ theme }) => theme.colors.primary.dark2}; } cursor: pointer; @@ -74,7 +72,42 @@ const Fade = styled.div` opacity: ${(props: { hovered: boolean }) => (props.hovered ? 1 : 0)}; `; -const TableElement = ({ table, actions, ...props }: TableElementProps) => { +const StyledCollapsePanel = styled(Collapse.Panel)` + ${({ theme }) => css` + & { + .ws-el-controls { + margin-right: ${-theme.gridUnit}px; + display: flex; + } + + .header-container { + display: flex; + flex: 1; + align-items: center; + width: 100%; + + .table-name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: ${theme.typography.sizes.l}px; + flex: 1; + } + + .header-right-side { + margin-left: auto; + display: flex; + align-items: center; + margin-right: ${theme.gridUnit * 8}px; + } + } + } + `} +`; + +const TableElement = ({ table, ...props }: TableElementProps) => { + const dispatch = useDispatch(); + const [sortColumns, setSortColumns] = useState(false); const [hovered, setHovered] = useState(false); const tableNameRef = useRef<HTMLInputElement>(null); @@ -84,8 +117,8 @@ const TableElement = ({ table, actions, ...props }: TableElementProps) => { }; const removeTable = () => { - actions.removeDataPreview(table); - actions.removeTable(table); + dispatch(removeDataPreview(table)); + dispatch(removeTables([table])); }; const toggleSortColumns = () => { @@ -149,14 +182,11 @@ const TableElement = ({ table, actions, ...props }: TableElementProps) => { const renderControls = () => { let keyLink; + const KEYS_FOR_TABLE_TEXT = t('Keys for table'); if (table?.indexes?.length) { keyLink = ( <ModalTrigger - modalTitle={ - <div> - {t('Keys for table')} <strong>{table.name}</strong> - </div> - } + modalTitle={`${KEYS_FOR_TABLE_TEXT} ${table.name}`} modalBody={table.indexes.map((ix, i) => ( <pre key={i}>{JSON.stringify(ix, null, ' ')}</pre> ))} @@ -274,6 +304,7 @@ const TableElement = ({ table, actions, ...props }: TableElementProps) => { const metadata = ( <div + data-test="table-element" onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)} css={{ paddingTop: 6 }} @@ -290,7 +321,7 @@ const TableElement = ({ table, actions, ...props }: TableElementProps) => { }; return ( - <Collapse.Panel + <StyledCollapsePanel {...props} key={table.id} header={renderHeader()} @@ -298,7 +329,7 @@ const TableElement = ({ table, actions, ...props }: TableElementProps) => { forceRender > {renderBody()} - </Collapse.Panel> + </StyledCollapsePanel> ); }; diff --git a/superset-frontend/src/SqlLab/components/TemplateParamsEditor/TemplateParamsEditor.test.tsx b/superset-frontend/src/SqlLab/components/TemplateParamsEditor/TemplateParamsEditor.test.tsx index bc04030d28c8e..fdf8fd3b53f57 100644 --- a/superset-frontend/src/SqlLab/components/TemplateParamsEditor/TemplateParamsEditor.test.tsx +++ b/superset-frontend/src/SqlLab/components/TemplateParamsEditor/TemplateParamsEditor.test.tsx @@ -17,38 +17,103 @@ * under the License. */ -import React, { ReactNode } from 'react'; +import React from 'react'; +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { Store } from 'redux'; import { render, fireEvent, getByText, waitFor, } from 'spec/helpers/testing-library'; -import { ThemeProvider, supersetTheme } from '@superset-ui/core'; +import { initialState, defaultQueryEditor } from 'src/SqlLab/fixtures'; -import TemplateParamsEditor from 'src/SqlLab/components/TemplateParamsEditor'; +import TemplateParamsEditor, { + TemplateParamsEditorProps, +} from 'src/SqlLab/components/TemplateParamsEditor'; -const ThemeWrapper = ({ children }: { children: ReactNode }) => ( - <ThemeProvider theme={supersetTheme}>{children}</ThemeProvider> -); +jest.mock('src/components/DeprecatedSelect', () => () => ( + <div data-test="mock-deprecated-select" /> +)); +jest.mock('src/components/Select/Select', () => () => ( + <div data-test="mock-deprecated-select-select" /> +)); +jest.mock('src/components/Select/AsyncSelect', () => () => ( + <div data-test="mock-async-select" /> +)); +jest.mock('src/components/AsyncAceEditor', () => ({ + ConfigEditor: ({ value }: { value: string }) => ( + <div data-test="mock-async-ace-editor">{value}</div> + ), +})); + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); +const setup = ( + otherProps: Partial<TemplateParamsEditorProps> = {}, + store?: Store, +) => + render( + <TemplateParamsEditor + language="json" + onChange={() => {}} + queryEditorId={defaultQueryEditor.id} + {...otherProps} + />, + { + useRedux: true, + store: mockStore(initialState), + ...(store && { store }), + }, + ); describe('TemplateParamsEditor', () => { it('should render with a title', () => { - const { container } = render( - <TemplateParamsEditor code="FOO" language="json" onChange={() => {}} />, - { wrapper: ThemeWrapper }, - ); + const { container } = setup(); expect(container.querySelector('div[role="button"]')).toBeInTheDocument(); }); it('should open a modal with the ace editor', async () => { - const { container, baseElement } = render( - <TemplateParamsEditor code="FOO" language="json" onChange={() => {}} />, - { wrapper: ThemeWrapper }, + const { container, getByTestId } = setup(); + fireEvent.click(getByText(container, 'Parameters')); + await waitFor(() => { + expect(getByTestId('mock-async-ace-editor')).toBeInTheDocument(); + }); + }); + + it('renders templateParams', async () => { + const { container, getByTestId } = setup(); + fireEvent.click(getByText(container, 'Parameters')); + await waitFor(() => { + expect(getByTestId('mock-async-ace-editor')).toBeInTheDocument(); + }); + expect(getByTestId('mock-async-ace-editor')).toHaveTextContent( + defaultQueryEditor.templateParams, + ); + }); + + it('renders code from unsaved changes', async () => { + const expectedCode = 'custom code value'; + const { container, getByTestId } = setup( + {}, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + templateParams: expectedCode, + }, + }, + }), ); fireEvent.click(getByText(container, 'Parameters')); await waitFor(() => { - expect(baseElement.querySelector('#ace-editor')).toBeInTheDocument(); + expect(getByTestId('mock-async-ace-editor')).toBeInTheDocument(); }); + expect(getByTestId('mock-async-ace-editor')).toHaveTextContent( + expectedCode, + ); }); }); diff --git a/superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx b/superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx index 62d0a7209de1c..a862fd326aaca 100644 --- a/superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx +++ b/superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx @@ -17,15 +17,16 @@ * under the License. */ import React, { useState, useEffect } from 'react'; -import Badge from 'src/components/Badge'; import { t, styled } from '@superset-ui/core'; import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; import { debounce } from 'lodash'; +import Badge from 'src/components/Badge'; import ModalTrigger from 'src/components/ModalTrigger'; import { ConfigEditor } from 'src/components/AsyncAceEditor'; import { FAST_DEBOUNCE } from 'src/constants'; import { Tooltip } from 'src/components/Tooltip'; +import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; const StyledConfigEditor = styled(ConfigEditor)` &.ace_editor { @@ -33,18 +34,23 @@ const StyledConfigEditor = styled(ConfigEditor)` } `; -function TemplateParamsEditor({ - code = '{}', - language, - onChange = () => {}, -}: { - code: string; +export type TemplateParamsEditorProps = { + queryEditorId: string; language: 'yaml' | 'json'; onChange: () => void; -}) { +}; + +const TemplateParamsEditor = ({ + queryEditorId, + language, + onChange = () => {}, +}: TemplateParamsEditorProps) => { const [parsedJSON, setParsedJSON] = useState({}); const [isValid, setIsValid] = useState(true); + const { templateParams } = useQueryEditor(queryEditorId, ['templateParams']); + const code = templateParams ?? '{}'; + useEffect(() => { try { setParsedJSON(JSON.parse(code)); @@ -58,20 +64,20 @@ function TemplateParamsEditor({ const modalBody = ( <div> <p> - Assign a set of parameters as + {t('Assign a set of parameters as')} <code>JSON</code> - below (example: + {t('below (example:')} <code>{'{"my_table": "foo"}'}</code> - ), and they become available in your SQL (example: - <code>SELECT * FROM {'{{ my_table }}'} </code>) by using  + {t('), and they become available in your SQL (example:')} + <code>SELECT * FROM {'{{ my_table }}'} </code>) {t('by using')}  <a href="https://superset.apache.org/sqllab.html#templating-with-jinja" target="_blank" rel="noopener noreferrer" > - Jinja templating + {t('Jinja templating')} </a>{' '} - syntax. + {t('syntax.')} </p> <StyledConfigEditor mode={language} @@ -115,6 +121,6 @@ function TemplateParamsEditor({ modalBody={modalBody} /> ); -} +}; export default TemplateParamsEditor; diff --git a/superset-frontend/src/SqlLab/constants.ts b/superset-frontend/src/SqlLab/constants.ts index 7d0ea09c18264..108ce895618a0 100644 --- a/superset-frontend/src/SqlLab/constants.ts +++ b/superset-frontend/src/SqlLab/constants.ts @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ +import { t } from '@superset-ui/core'; + export const STATE_TYPE_MAP = { offline: 'danger', failed: 'danger', @@ -26,6 +28,16 @@ export const STATE_TYPE_MAP = { success: 'success', }; +export const STATE_TYPE_MAP_LOCALIZED = { + offline: t('offline'), + failed: t('failed'), + pending: t('pending'), + fetching: t('fetching'), + running: t('running'), + stopped: t('stopped'), + success: t('success'), +}; + export const STATUS_OPTIONS = { success: 'success', failed: 'failed', @@ -34,6 +46,14 @@ export const STATUS_OPTIONS = { pending: 'pending', }; +export const STATUS_OPTIONS_LOCALIZED = { + success: t('success'), + failed: t('failed'), + running: t('running'), + offline: t('offline'), + pending: t('pending'), +}; + export const TIME_OPTIONS = [ 'now', '1 hour ago', @@ -48,6 +68,13 @@ export const TIME_OPTIONS = [ export const SQL_EDITOR_GUTTER_HEIGHT = 5; export const SQL_EDITOR_GUTTER_MARGIN = 3; export const SQL_TOOLBAR_HEIGHT = 51; +export const SQL_EDITOR_LEFTBAR_WIDTH = 400; +export const SQL_EDITOR_PADDING = 10; +export const INITIAL_NORTH_PERCENT = 30; +export const INITIAL_SOUTH_PERCENT = 70; +export const SET_QUERY_EDITOR_SQL_DEBOUNCE_MS = 2000; +export const VALIDATION_DEBOUNCE_MS = 600; +export const WINDOW_RESIZE_THROTTLE_MS = 100; // kilobyte storage export const KB_STORAGE = 1024; diff --git a/superset-frontend/src/SqlLab/fixtures.ts b/superset-frontend/src/SqlLab/fixtures.ts index 5b12ee29213ee..456a83a3faf1e 100644 --- a/superset-frontend/src/SqlLab/fixtures.ts +++ b/superset-frontend/src/SqlLab/fixtures.ts @@ -19,6 +19,8 @@ import sinon from 'sinon'; import * as actions from 'src/SqlLab/actions/sqlLab'; import { ColumnKeyTypeType } from 'src/SqlLab/components/ColumnElement'; +import { DatasourceType, QueryResponse, QueryState } from '@superset-ui/core'; +import { ISaveableDatasource } from 'src/SqlLab/components/SaveDatasetModal'; export const mockedActions = sinon.stub({ ...actions }); @@ -176,11 +178,16 @@ export const table = { export const defaultQueryEditor = { id: 'dfsadfs', autorun: false, - dbId: null, + dbId: undefined, latestQueryId: null, - selectedText: null, + selectedText: undefined, sql: 'SELECT *\nFROM\nWHERE', - title: 'Untitled Query 1', + name: 'Untitled Query 1', + schema: 'main', + remoteId: null, + tableOptions: [], + functionNames: [], + hideLeftBar: false, schemaOptions: [ { value: 'main', @@ -188,7 +195,24 @@ export const defaultQueryEditor = { title: 'main', }, ], + templateParams: '{}', +}; + +export const extraQueryEditor1 = { + ...defaultQueryEditor, + id: 'diekd23', + sql: 'SELECT *\nFROM\nWHERE\nLIMIT', + name: 'Untitled Query 2', + selectedText: 'SELECT', }; + +export const extraQueryEditor2 = { + ...defaultQueryEditor, + id: 'owkdi998', + sql: 'SELECT *\nFROM\nWHERE\nGROUP BY', + name: 'Untitled Query 3', +}; + export const queries = [ { dbId: 1, @@ -201,7 +225,7 @@ export const queries = [ id: 'BkA1CLrJg', progress: 100, startDttm: 1476910566092.96, - state: 'success', + state: QueryState.SUCCESS, changedOn: 1476910566000, tempTable: null, userId: 1, @@ -260,7 +284,7 @@ export const queries = [ id: 'S1zeAISkx', progress: 100, startDttm: 1476910570802.2, - state: 'success', + state: QueryState.SUCCESS, changedOn: 1476910572000, tempTable: null, userId: 1, @@ -294,7 +318,7 @@ export const queryWithNoQueryLimit = { id: 'BkA1CLrJg', progress: 100, startDttm: 1476910566092.96, - state: 'success', + state: QueryState.SUCCESS, changedOn: 1476910566000, tempTable: null, userId: 1, @@ -344,6 +368,7 @@ export const queryWithNoQueryLimit = { }, }, }; + export const queryWithBadColumns = { ...queries[0], results: { @@ -407,6 +432,7 @@ export const queryWithBadColumns = { ], }, }; + export const databases = { result: [ { @@ -429,6 +455,7 @@ export const databases = { }, ], }; + export const tables = { options: [ { @@ -464,7 +491,7 @@ export const stoppedQuery = { sql: 'SELECT ...', sqlEditorId: 'rJaf5u9WZ', startDttm: 1497400851936, - state: 'stopped', + state: QueryState.STOPPED, tab: 'Untitled Query 2', tempTable: '', }; @@ -482,7 +509,7 @@ export const failedQueryWithErrorMessage = { sql: 'SELECT ...', sqlEditorId: 'rJaf5u9WZ', startDttm: 1497400851936, - state: 'failed', + state: QueryState.FAILED, tab: 'Untitled Query 2', tempTable: '', }; @@ -507,20 +534,113 @@ export const failedQueryWithErrors = { sql: 'SELECT ...', sqlEditorId: 'rJaf5u9WZ', startDttm: 1497400851936, - state: 'failed', + state: QueryState.FAILED, tab: 'Untitled Query 2', tempTable: '', }; -export const runningQuery = { +const baseQuery: QueryResponse = { + queryId: 567, + dbId: 1, + sql: 'SELECT * FROM superset.slices', + sqlEditorId: 'SJ8YO72R', + tab: 'Demo', + ctas: false, + cached: false, + id: 'BkA1CLrJg', + progress: 100, + startDttm: 1476910566092.96, + state: QueryState.SUCCESS, + tempSchema: null, + tempTable: 'temp', + userId: 1, + executedSql: 'SELECT * FROM superset.slices', + rows: 42, + started: 'started', + queryLimit: 100, + endDttm: 1476910566798, + schema: 'test_schema', + errorMessage: null, + db: { key: 'main' }, + user: { key: 'admin' }, + isDataPreview: false, + resultsKey: null, + trackingUrl: null, + templateParams: null, + limitingFactor: 'capacity', + duration: '2334645675467', + time: { key: 'value' }, + querylink: { key: 'value' }, + output: { key: 'value' }, + actions: { key: 'value' }, + extra: { + progress: null, + }, + columns: [], + type: DatasourceType.Query, + results: { + displayLimitReached: false, + query: { limit: 6 }, + columns: [ + { + is_dttm: true, + name: 'ds', + type: 'STRING', + }, + { + is_dttm: false, + name: 'gender', + type: 'STRING', + }, + ], + selected_columns: [ + { + is_dttm: true, + name: 'ds', + type: 'STRING', + }, + { + is_dttm: false, + name: 'gender', + type: 'STRING', + }, + ], + expanded_columns: [ + { + is_dttm: true, + name: 'ds', + type: 'STRING', + }, + ], + data: [ + { col1: '0', col2: '1' }, + { col1: '2', col2: '3' }, + ], + }, +}; + +export const runningQuery: QueryResponse = { + ...baseQuery, dbId: 1, cached: false, ctas: false, id: 'ryhMUZCGb', progress: 90, - state: 'running', + state: QueryState.RUNNING, startDttm: Date.now() - 500, }; + +export const successfulQuery: QueryResponse = { + ...baseQuery, + dbId: 1, + cached: false, + ctas: false, + id: 'ryhMUZCGb', + progress: 100, + state: QueryState.SUCCESS, + startDttm: Date.now() - 500, +}; + export const cachedQuery = { ...queries[0], cached: true }; export const user = { @@ -541,13 +661,14 @@ export const initialState = { alerts: [], queries: {}, databases: {}, - queryEditors: [defaultQueryEditor], + queryEditors: [defaultQueryEditor, extraQueryEditor1, extraQueryEditor2], tabHistory: [defaultQueryEditor.id], tables: [], workspaceQueries: [], queriesLastUpdate: 0, activeSouthPaneTab: 'Results', user: { user }, + unsavedQueryEditor: {}, }, messageToasts: [], common: { @@ -562,13 +683,49 @@ export const initialState = { }; export const query = { - id: 'clientId2353', + name: 'test query', dbId: 1, sql: 'SELECT * FROM something', - sqlEditorId: defaultQueryEditor.id, - tab: 'unimportant', - tempTable: null, - runAsync: false, - ctas: false, - cached: false, + description: 'test description', + schema: 'test schema', + resultsKey: 'test', }; + +export const queryId = 'clientId2353'; + +export const testQuery: ISaveableDatasource = { + name: 'unimportant', + dbId: 1, + sql: 'SELECT *', + columns: [ + { + name: 'Column 1', + type: DatasourceType.Query, + is_dttm: false, + }, + { + name: 'Column 3', + type: DatasourceType.Query, + is_dttm: false, + }, + { + name: 'Column 2', + type: DatasourceType.Query, + is_dttm: true, + }, + ], +}; + +export const mockdatasets = [...new Array(3)].map((_, i) => ({ + changed_by_name: 'user', + kind: i === 0 ? 'virtual' : 'physical', // ensure there is 1 virtual + changed_by_url: 'changed_by_url', + changed_by: 'user', + changed_on: new Date().toISOString(), + database_name: `db ${i}`, + explore_url: `/explore/?datasource_type=table&datasource_id=${i}`, + id: i, + schema: `schema ${i}`, + table_name: `coolest table ${i}`, + owners: [{ username: 'admin', userId: 1 }], +})); diff --git a/superset-frontend/src/SqlLab/hooks/useQueryEditor/index.ts b/superset-frontend/src/SqlLab/hooks/useQueryEditor/index.ts new file mode 100644 index 0000000000000..7044e77798fd2 --- /dev/null +++ b/superset-frontend/src/SqlLab/hooks/useQueryEditor/index.ts @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import pick from 'lodash/pick'; +import { shallowEqual, useSelector } from 'react-redux'; +import { SqlLabRootState, QueryEditor } from 'src/SqlLab/types'; + +export default function useQueryEditor<T extends keyof QueryEditor>( + sqlEditorId: string, + attributes: ReadonlyArray<T>, +) { + return useSelector<SqlLabRootState, Pick<QueryEditor, T | 'id'>>( + ({ sqlLab: { unsavedQueryEditor, queryEditors } }) => + pick( + { + ...queryEditors.find(({ id }) => id === sqlEditorId), + ...(sqlEditorId === unsavedQueryEditor.id && unsavedQueryEditor), + }, + ['id'].concat(attributes), + ) as Pick<QueryEditor, T | 'id'>, + shallowEqual, + ); +} diff --git a/superset-frontend/src/SqlLab/hooks/useQueryEditor/useQueryEditor.test.ts b/superset-frontend/src/SqlLab/hooks/useQueryEditor/useQueryEditor.test.ts new file mode 100644 index 0000000000000..23de4d68226cf --- /dev/null +++ b/superset-frontend/src/SqlLab/hooks/useQueryEditor/useQueryEditor.test.ts @@ -0,0 +1,92 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { initialState, defaultQueryEditor } from 'src/SqlLab/fixtures'; +import { renderHook } from '@testing-library/react-hooks'; +import { createWrapper } from 'spec/helpers/testing-library'; + +import useQueryEditor from '.'; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); + +test('returns selected queryEditor values', () => { + const { result } = renderHook( + () => + useQueryEditor(defaultQueryEditor.id, [ + 'id', + 'name', + 'dbId', + 'schemaOptions', + ]), + { + wrapper: createWrapper({ + useRedux: true, + store: mockStore(initialState), + }), + }, + ); + expect(result.current).toEqual({ + id: defaultQueryEditor.id, + name: defaultQueryEditor.name, + dbId: defaultQueryEditor.dbId, + schemaOptions: defaultQueryEditor.schemaOptions, + }); +}); + +test('includes id implicitly', () => { + const { result } = renderHook( + () => useQueryEditor(defaultQueryEditor.id, ['name']), + { + wrapper: createWrapper({ + useRedux: true, + store: mockStore(initialState), + }), + }, + ); + expect(result.current).toEqual({ + id: defaultQueryEditor.id, + name: defaultQueryEditor.name, + }); +}); + +test('returns updated values from unsaved change', () => { + const expectedSql = 'SELECT updated_column\nFROM updated_table\nWHERE'; + const { result } = renderHook( + () => useQueryEditor(defaultQueryEditor.id, ['id', 'sql']), + { + wrapper: createWrapper({ + useRedux: true, + store: mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + sql: expectedSql, + }, + }, + }), + }), + }, + ); + expect(result.current.id).toEqual(defaultQueryEditor.id); + expect(result.current.sql).toEqual(expectedSql); +}); diff --git a/superset-frontend/src/SqlLab/main.less b/superset-frontend/src/SqlLab/main.less deleted file mode 100644 index 652c7a60b2187..0000000000000 --- a/superset-frontend/src/SqlLab/main.less +++ /dev/null @@ -1,493 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -@import '../assets/stylesheets/less/variables.less'; - -body { - min-height: ~'max(100vh, 500px)'; // Set a min height so the gutter is always visible when resizing - overflow: hidden; -} - -.inlineBlock { - display: inline-block; -} - -.valignTop { - vertical-align: top; -} - -.inline { - display: inline; -} - -.nopadding { - padding: 0px; -} - -.pane-cell { - padding: 10px; - overflow: auto; - width: 100%; - height: 100%; -} - -.ant-tabs-content-holder { - /* This is needed for Safari */ - height: 100%; -} - -.ant-tabs-content { - height: 100%; - position: relative; - background-color: @lightest; - overflow-x: auto; - overflow-y: auto; - - > .ant-tabs-tabpane { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - } -} - -.Workspace .btn-sm { - box-shadow: 1px 1px 2px fade(@darkest, @opacity-light); - margin-top: 2px; - padding: 4px; -} - -.Workspace hr { - margin-top: 10px; - margin-bottom: 10px; -} - -div.Workspace { - height: 100%; - margin: 0px; -} - -.padded { - padding: 10px; -} - -.p-t-10 { - padding-top: 10px; -} - -.p-t-5 { - padding-top: 5px; -} - -.m-r-5 { - margin-right: 5px; -} - -.m-r-3 { - margin-right: 3px; -} - -.m-l-1 { - margin-left: 1px; -} - -.m-l-2 { - margin-left: 2px; -} - -.m-r-10 { - margin-right: 10px; -} - -.m-l-10 { - margin-left: 10px; -} - -.m-l-5 { - margin-left: 5px; -} - -.m-b-10 { - margin-bottom: 10px; -} - -.m-t-5 { - margin-top: 5px; -} - -.m-t-10 { - margin-top: 10px; -} - -.p-t-10 { - padding-top: 10px; -} - -.no-shadow { - box-shadow: none; - background-color: transparent; -} - -.pane-west { - height: 100%; - overflow: auto; -} - -.circle { - @circle-diameter: 10px; - border-radius: (@circle-diameter / 2); - width: @circle-diameter; - height: @circle-diameter; - - display: inline-block; - background-color: @gray-light; - text-align: center; - vertical-align: middle; - font-size: @font-size-m; - font-weight: @font-weight-bold; -} - -.running { - background-color: fade(@success, @opacity-heavy); - color: @darkest; -} - -.success { - background-color: @success; -} - -.failed { - background-color: @danger; -} - -.handle { - cursor: move; -} - -#a11y-query-editor-tabs { - height: 100%; - display: flex; - flex-direction: column; -} - -.SqlLab { - position: absolute; - top: 0px; - right: 0px; - bottom: 0px; - left: 0px; - padding: 0 10px; - - pre { - padding: 0px !important; - margin: 0px; - border: none; - font-size: @font-size-s; - background-color: transparent !important; - } - - .north-pane { - display: flex; - flex-direction: column; - } - - #ace-editor { - height: calc(100% - 51px); - flex-grow: 1; - } - - .ace_content { - height: 100%; - } -} - -.SqlEditorTabs li { - a:focus { - outline: 0; - } - - .ddbtn-tab { - font-size: inherit; - color: black; - - &:active { - background: none; - } - - svg { - vertical-align: middle; - } - } - - .dropdown.btn-group.btn-group-sm { - width: 3px; - height: 3px; - border-radius: 1.5px; - background: #bababa; - margin-right: 8px; - font-weight: @font-weight-normal; - display: inline-flex; - - &:hover { - background-color: @primary-color; - - &:before, - &:after { - background-color: @primary-color; - } - } - - &:before, - &:after { - position: absolute; - content: ' '; - width: 3px; - height: 3px; - border-radius: 1.5px; - background-color: #bababa; - } - &:before { - transform: translateY(-5px); - } - &:after { - transform: translateY(5px); - } - } - - ul.dropdown-menu { - margin-top: 10px; - } - - .dropdown-toggle { - padding-top: 2px; - } -} - -.SqlEditor { - display: flex; - flex-direction: row; - height: 100%; - padding: 10px; - - .schemaPane { - flex: 0 0 400px; - max-width: 400px; - transition: transform @timing-normal ease-in-out; - } - - .queryPane { - flex: 1 1 auto; - padding-left: 10px; - overflow-y: none; - overflow-x: scroll; - } - - .schemaPane-enter-done, - .schemaPane-exit { - transform: translateX(0); - z-index: 7; - } - - .schemaPane-exit-active { - transform: translateX(-120%); - } - - .schemaPane-enter-active { - transform: translateX(0); - max-width: 300px; - } - - .schemaPane-enter, - .schemaPane-exit-done { - max-width: 0; - transform: translateX(-120%); - overflow: hidden; - } - - .schemaPane-exit-done + .queryPane { - margin-left: 0; - } - - .gutter { - border-top: 1px solid @gray-light; - border-bottom: 1px solid @gray-light; - width: 3%; - margin: 3px 47%; - } - - .gutter.gutter-vertical { - cursor: row-resize; - } -} - -.SqlEditorLeftBar { - height: 100%; - display: flex; - flex-direction: column; - - .divider { - border-bottom: 1px solid @gray-bg; - margin: 15px 0; - } -} - -.popover { - max-width: 400px; -} - -.table-label { - margin-top: 5px; - margin-right: 10px; - float: left; -} - -div.tablePopover { - opacity: 0.7 !important; - - &:hover { - opacity: 1 !important; - } -} - -.ace_editor.ace_editor { - //double class is better than !important - border: 1px solid @gray-light; - font-feature-settings: @font-feature-settings; - // Fira Code causes problem with Ace under Firefox - font-family: 'Menlo', 'Consolas', 'Courier New', 'Ubuntu Mono', - 'source-code-pro', 'Lucida Console', monospace; - - &.ace_autocomplete { - // Use !important because Ace Editor applies extra CSS at the last second - // when opening the autocomplete. - width: 520px !important; - } -} - -.Select__menu-outer { - min-width: 100%; - width: inherit; - z-index: @z-index-dropdown; -} - -.Select__clear-indicator { - margin-top: -2px; -} - -.Select__arrow { - margin-top: 5px; -} - -.ace_scroller { - background-color: @gray-bg; -} - -.TableElement { - .well { - margin-top: 5px; - margin-bottom: 5px; - padding: 5px 10px; - } - - .ws-el-controls { - margin-right: -0.3em; - display: flex; - } - - .header-container { - display: flex; - flex: 1; - align-items: center; - width: 100%; - - .table-name { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - font-size: 16px; - flex: 1; - } - - .header-right-side { - margin-left: auto; - display: flex; - align-items: center; - margin-right: 33px; - } - } -} - -.QueryTable .label { - display: inline-block; -} - -.QueryTable .ant-btn { - position: static; -} - -.ResultsModal .ant-modal-body { - min-height: 560px; -} - -.ant-modal-body { - overflow: auto; -} - -a.Link { - cursor: pointer; -} - -.QueryTable .well { - padding: 3px 5px; - margin: 3px 5px; -} - -.nav-tabs .ddbtn-tab { - padding: 0; - border: none; - background: none; - position: relative; - top: 2px; - - &:focus { - outline: 0; - } - - &:active { - box-shadow: none; - } -} - -.icon-container { - display: inline-block; - width: 30px; - text-align: center; -} - -.search-date-filter-container { - display: flex; - - .Select { - margin-right: 3px; - } -} - -.cost-estimate { - font-size: @font-size-s; -} diff --git a/superset-frontend/src/SqlLab/reducers/getInitialState.js b/superset-frontend/src/SqlLab/reducers/getInitialState.js index d5f02029d0ccf..2d00d3e0d68bd 100644 --- a/superset-frontend/src/SqlLab/reducers/getInitialState.js +++ b/superset-frontend/src/SqlLab/reducers/getInitialState.js @@ -37,11 +37,11 @@ export default function getInitialState({ * To allow for a transparent migration, the initial state is a combination * of the backend state (if any) with the browser state (if any). */ - const queryEditors = []; + let queryEditors = {}; const defaultQueryEditor = { id: null, loaded: true, - title: t('Untitled query'), + name: t('Untitled query'), sql: 'SELECT *\nFROM\nWHERE', selectedText: null, latestQueryId: null, @@ -55,13 +55,9 @@ export default function getInitialState({ errors: [], completed: false, }, - queryCostEstimate: { - cost: null, - completed: false, - error: null, - }, hideLeftBar: false, }; + let unsavedQueryEditor = {}; /** * Load state from the backend. This will be empty if the feature flag @@ -73,7 +69,7 @@ export default function getInitialState({ queryEditor = { id: id.toString(), loaded: true, - title: activeTab.label, + name: activeTab.label, sql: activeTab.sql || undefined, selectedText: undefined, latestQueryId: activeTab.latest_query @@ -99,10 +95,13 @@ export default function getInitialState({ ...defaultQueryEditor, id: id.toString(), loaded: false, - title: label, + name: label, }; } - queryEditors.push(queryEditor); + queryEditors = { + ...queryEditors, + [queryEditor.id]: queryEditor, + }; }); const tabHistory = activeTab ? [activeTab.id.toString()] : []; @@ -160,15 +159,22 @@ export default function getInitialState({ // migration was successful localStorage.removeItem('redux'); } else { + unsavedQueryEditor = sqlLab.unsavedQueryEditor || {}; // add query editors and tables to state with a special flag so they can // be migrated if the `SQLLAB_BACKEND_PERSISTENCE` feature flag is on - sqlLab.queryEditors.forEach(qe => - queryEditors.push({ - ...qe, - inLocalStorage: true, - loaded: true, - }), - ); + sqlLab.queryEditors.forEach(qe => { + queryEditors = { + ...queryEditors, + [qe.id]: { + ...queryEditors[qe.id], + ...qe, + name: qe.title || qe.name, + ...(unsavedQueryEditor.id === qe.id && unsavedQueryEditor), + inLocalStorage: true, + loaded: true, + }, + }; + }); sqlLab.tables.forEach(table => tables.push({ ...table, inLocalStorage: true }), ); @@ -186,11 +192,13 @@ export default function getInitialState({ databases, offline: false, queries, - queryEditors, + queryEditors: Object.values(queryEditors), tabHistory, tables, queriesLastUpdate: Date.now(), user, + unsavedQueryEditor, + queryCostEstimates: {}, }, requestedQuery, messageToasts: getToastsFromPyFlashMessages( diff --git a/superset-frontend/src/SqlLab/reducers/sqlLab.js b/superset-frontend/src/SqlLab/reducers/sqlLab.js index d20d34420575a..e3bb196fbcef0 100644 --- a/superset-frontend/src/SqlLab/reducers/sqlLab.js +++ b/superset-frontend/src/SqlLab/reducers/sqlLab.js @@ -16,8 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { t } from '@superset-ui/core'; - +import { QueryState, t } from '@superset-ui/core'; import getInitialState from './getInitialState'; import * as actions from '../actions/sqlLab'; import { now } from '../../utils/dates'; @@ -31,24 +30,53 @@ import { extendArr, } from '../../reduxUtils'; +function alterUnsavedQueryEditorState(state, updatedState, id) { + if (state.tabHistory[state.tabHistory.length - 1] !== id) { + const { queryEditors } = alterInArr( + state, + 'queryEditors', + { id }, + updatedState, + ); + return { + queryEditors, + }; + } + return { + unsavedQueryEditor: { + ...(state.unsavedQueryEditor.id === id && state.unsavedQueryEditor), + ...(id ? { id, ...updatedState } : state.unsavedQueryEditor), + }, + }; +} + export default function sqlLabReducer(state = {}, action) { const actionHandlers = { [actions.ADD_QUERY_EDITOR]() { - const tabHistory = state.tabHistory.slice(); - tabHistory.push(action.queryEditor.id); - const newState = { ...state, tabHistory }; + const mergeUnsavedState = alterInArr( + state, + 'queryEditors', + state.unsavedQueryEditor, + { + ...state.unsavedQueryEditor, + }, + ); + const newState = { + ...mergeUnsavedState, + tabHistory: [...state.tabHistory, action.queryEditor.id], + }; return addToArr(newState, 'queryEditors', action.queryEditor); }, [actions.QUERY_EDITOR_SAVED]() { - const { query, result } = action; - const existing = state.queryEditors.find(qe => qe.id === query.id); + const { query, result, clientId } = action; + const existing = state.queryEditors.find(qe => qe.id === clientId); return alterInArr( state, 'queryEditors', existing, { remoteId: result.remoteId, - title: query.title, + name: query.name, }, 'id', ); @@ -66,12 +94,17 @@ export default function sqlLabReducer(state = {}, action) { ); }, [actions.CLONE_QUERY_TO_NEW_TAB]() { - const progenitor = state.queryEditors.find( + const queryEditor = state.queryEditors.find( qe => qe.id === state.tabHistory[state.tabHistory.length - 1], ); + const progenitor = { + ...queryEditor, + ...(state.unsavedQueryEditor.id === queryEditor.id && + state.unsavedQueryEditor), + }; const qe = { remoteId: progenitor.remoteId, - title: t('Copy of %s', progenitor.title), + name: t('Copy of %s', progenitor.name), dbId: action.query.dbId ? action.query.dbId : null, schema: action.query.schema ? action.query.schema : null, autorun: true, @@ -79,10 +112,22 @@ export default function sqlLabReducer(state = {}, action) { queryLimit: action.query.queryLimit, maxRow: action.query.maxRow, }; - return sqlLabReducer(state, actions.addQueryEditor(qe)); + const stateWithoutUnsavedState = { + ...state, + unsavedQueryEditor: {}, + }; + return sqlLabReducer( + stateWithoutUnsavedState, + actions.addQueryEditor(qe), + ); }, [actions.REMOVE_QUERY_EDITOR]() { - let newState = removeFromArr(state, 'queryEditors', action.queryEditor); + const queryEditor = { + ...action.queryEditor, + ...(action.queryEditor.id === state.unsavedQueryEditor.id && + state.unsavedQueryEditor), + }; + let newState = removeFromArr(state, 'queryEditors', queryEditor); // List of remaining queryEditor ids const qeIds = newState.queryEditors.map(qe => qe.id); @@ -99,10 +144,19 @@ export default function sqlLabReducer(state = {}, action) { // Remove associated table schemas const tables = state.tables.filter( - table => table.queryEditorId !== action.queryEditor.id, + table => table.queryEditorId !== queryEditor.id, ); - newState = { ...newState, tabHistory, tables, queries }; + newState = { + ...newState, + tabHistory, + tables, + queries, + unsavedQueryEditor: { + ...(action.queryEditor.id !== state.unsavedQueryEditor.id && + state.unsavedQueryEditor), + }, + }; return newState; }, [actions.REMOVE_QUERY]() { @@ -175,20 +229,28 @@ export default function sqlLabReducer(state = {}, action) { [actions.COLLAPSE_TABLE]() { return alterInArr(state, 'tables', action.table, { expanded: false }); }, - [actions.REMOVE_TABLE]() { - return removeFromArr(state, 'tables', action.table); + [actions.REMOVE_TABLES]() { + const tableIds = action.tables.map(table => table.id); + return { + ...state, + tables: state.tables.filter(table => !tableIds.includes(table.id)), + }; }, [actions.START_QUERY_VALIDATION]() { - let newState = { ...state }; - const sqlEditor = { id: action.query.sqlEditorId }; - newState = alterInArr(newState, 'queryEditors', sqlEditor, { - validationResult: { - id: action.query.id, - errors: [], - completed: false, - }, - }); - return newState; + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + validationResult: { + id: action.query.id, + errors: [], + completed: false, + }, + }, + action.query.sqlEditorId, + ), + }; }, [actions.QUERY_VALIDATION_RETURNED]() { // If the server is very slow about answering us, we might get validation @@ -198,21 +260,29 @@ export default function sqlLabReducer(state = {}, action) { // We don't care about any but the most recent because validations are // only valid for the SQL text they correspond to -- once the SQL has // changed, the old validation doesn't tell us anything useful anymore. - const qe = getFromArr(state.queryEditors, action.query.sqlEditorId); + const qe = { + ...getFromArr(state.queryEditors, action.query.sqlEditorId), + ...(state.unsavedQueryEditor.id === action.query.sqlEditorId && + state.unsavedQueryEditor), + }; if (qe.validationResult.id !== action.query.id) { return state; } // Otherwise, persist the results on the queryEditor state - let newState = { ...state }; - const sqlEditor = { id: action.query.sqlEditorId }; - newState = alterInArr(newState, 'queryEditors', sqlEditor, { - validationResult: { - id: action.query.id, - errors: action.results, - completed: true, - }, - }); - return newState; + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + validationResult: { + id: action.query.id, + errors: action.results, + completed: true, + }, + }, + action.query.sqlEditorId, + ), + }; }, [actions.QUERY_VALIDATION_FAILED]() { // If the server is very slow about answering us, we might get validation @@ -246,45 +316,52 @@ export default function sqlLabReducer(state = {}, action) { return newState; }, [actions.COST_ESTIMATE_STARTED]() { - let newState = { ...state }; - const sqlEditor = { id: action.query.sqlEditorId }; - newState = alterInArr(newState, 'queryEditors', sqlEditor, { - queryCostEstimate: { - completed: false, - cost: null, - error: null, + return { + ...state, + queryCostEstimates: { + ...state.queryCostEstimates, + [action.query.id]: { + completed: false, + cost: null, + error: null, + }, }, - }); - return newState; + }; }, [actions.COST_ESTIMATE_RETURNED]() { - let newState = { ...state }; - const sqlEditor = { id: action.query.sqlEditorId }; - newState = alterInArr(newState, 'queryEditors', sqlEditor, { - queryCostEstimate: { - completed: true, - cost: action.json, - error: null, + return { + ...state, + queryCostEstimates: { + ...state.queryCostEstimates, + [action.query.id]: { + completed: true, + cost: action.json, + error: null, + }, }, - }); - return newState; + }; }, [actions.COST_ESTIMATE_FAILED]() { - let newState = { ...state }; - const sqlEditor = { id: action.query.sqlEditorId }; - newState = alterInArr(newState, 'queryEditors', sqlEditor, { - queryCostEstimate: { - completed: false, - cost: null, - error: action.error, + return { + ...state, + queryCostEstimates: { + ...state.queryCostEstimates, + [action.query.id]: { + completed: false, + cost: null, + error: action.error, + }, }, - }); - return newState; + }; }, [actions.START_QUERY]() { let newState = { ...state }; if (action.query.sqlEditorId) { - const qe = getFromArr(state.queryEditors, action.query.sqlEditorId); + const qe = { + ...getFromArr(state.queryEditors, action.query.sqlEditorId), + ...(action.query.sqlEditorId === state.unsavedQueryEditor.id && + state.unsavedQueryEditor), + }; if (qe.latestQueryId && state.queries[qe.latestQueryId]) { const newResults = { ...state.queries[qe.latestQueryId].results, @@ -299,14 +376,21 @@ export default function sqlLabReducer(state = {}, action) { newState.activeSouthPaneTab = action.query.id; } newState = addToObject(newState, 'queries', action.query); - const sqlEditor = { id: action.query.sqlEditorId }; - return alterInArr(newState, 'queryEditors', sqlEditor, { - latestQueryId: action.query.id, - }); + + return { + ...newState, + ...alterUnsavedQueryEditorState( + state, + { + latestQueryId: action.query.id, + }, + action.query.sqlEditorId, + ), + }; }, [actions.STOP_QUERY]() { return alterInObject(state, 'queries', action.query, { - state: 'stopped', + state: QueryState.STOPPED, results: [], }); }, @@ -320,12 +404,16 @@ export default function sqlLabReducer(state = {}, action) { }, [actions.REQUEST_QUERY_RESULTS]() { return alterInObject(state, 'queries', action.query, { - state: 'fetching', + state: QueryState.FETCHING, }); }, [actions.QUERY_SUCCESS]() { - // prevent race condition were query succeeds shortly after being canceled - if (action.query.state === 'stopped') { + // prevent race condition where query succeeds shortly after being canceled + // or the final result was unsuccessful + if ( + action.query.state === QueryState.STOPPED || + action.results.status !== QueryState.SUCCESS + ) { return state; } const alts = { @@ -333,7 +421,7 @@ export default function sqlLabReducer(state = {}, action) { progress: 100, results: action.results, rows: action?.results?.query?.rows || 0, - state: 'success', + state: QueryState.SUCCESS, limitingFactor: action?.results?.query?.limitingFactor, tempSchema: action?.results?.query?.tempSchema, tempTable: action?.results?.query?.tempTable, @@ -349,11 +437,11 @@ export default function sqlLabReducer(state = {}, action) { return alterInObject(state, 'queries', action.query, alts); }, [actions.QUERY_FAILED]() { - if (action.query.state === 'stopped') { + if (action.query.state === QueryState.STOPPED) { return state; } const alts = { - state: 'failed', + state: QueryState.FAILED, errors: action.errors, errorMessage: action.msg, endDttm: now(), @@ -367,14 +455,41 @@ export default function sqlLabReducer(state = {}, action) { qeIds.indexOf(action.queryEditor?.id) > -1 && state.tabHistory[state.tabHistory.length - 1] !== action.queryEditor.id ) { - const tabHistory = state.tabHistory.slice(); - tabHistory.push(action.queryEditor.id); - return { ...state, tabHistory }; + const mergeUnsavedState = alterInArr( + state, + 'queryEditors', + state.unsavedQueryEditor, + { + ...state.unsavedQueryEditor, + }, + ); + return { + ...(action.queryEditor.id === state.unsavedQueryEditor.id + ? alterInArr( + mergeUnsavedState, + 'queryEditors', + action.queryEditor, + { + ...action.queryEditor, + ...state.unsavedQueryEditor, + }, + ) + : mergeUnsavedState), + tabHistory: [...state.tabHistory, action.queryEditor.id], + }; } return state; }, [actions.LOAD_QUERY_EDITOR]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { + const mergeUnsavedState = alterInArr( + state, + 'queryEditors', + state.unsavedQueryEditor, + { + ...state.unsavedQueryEditor, + }, + ); + return alterInArr(mergeUnsavedState, 'queryEditors', action.queryEditor, { ...action.queryEditor, }); }, @@ -437,70 +552,161 @@ export default function sqlLabReducer(state = {}, action) { return { ...state, queries }; }, [actions.QUERY_EDITOR_SETDB]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - dbId: action.dbId, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + dbId: action.dbId, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_SET_FUNCTION_NAMES]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - functionNames: action.functionNames, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + functionNames: action.functionNames, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_SET_SCHEMA]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - schema: action.schema, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + schema: action.schema, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_SET_SCHEMA_OPTIONS]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - schemaOptions: action.options, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + schemaOptions: action.options, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_SET_TABLE_OPTIONS]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - tableOptions: action.options, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + tableOptions: action.options, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_SET_TITLE]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - title: action.title, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + name: action.name, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_SET_SQL]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - sql: action.sql, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + sql: action.sql, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_SET_QUERY_LIMIT]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - queryLimit: action.queryLimit, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + queryLimit: action.queryLimit, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_SET_TEMPLATE_PARAMS]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - templateParams: action.templateParams, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + templateParams: action.templateParams, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_SET_SELECTED_TEXT]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - selectedText: action.sql, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + selectedText: action.sql, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_SET_AUTORUN]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - autorun: action.autorun, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + autorun: action.autorun, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_PERSIST_HEIGHT]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - northPercent: action.northPercent, - southPercent: action.southPercent, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + northPercent: action.northPercent, + southPercent: action.southPercent, + }, + action.queryEditor.id, + ), + }; }, [actions.QUERY_EDITOR_TOGGLE_LEFT_BAR]() { - return alterInArr(state, 'queryEditors', action.queryEditor, { - hideLeftBar: action.hideLeftBar, - }); + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + hideLeftBar: action.hideLeftBar, + }, + action.queryEditor.id, + ), + }; }, [actions.SET_DATABASES]() { const databases = {}; @@ -520,8 +726,8 @@ export default function sqlLabReducer(state = {}, action) { Object.entries(action.alteredQueries).forEach(([id, changedQuery]) => { if ( !state.queries.hasOwnProperty(id) || - (state.queries[id].state !== 'stopped' && - state.queries[id].state !== 'failed') + (state.queries[id].state !== QueryState.STOPPED && + state.queries[id].state !== QueryState.FAILED) ) { if (changedQuery.changedOn > queriesLastUpdate) { queriesLastUpdate = changedQuery.changedOn; @@ -535,8 +741,8 @@ export default function sqlLabReducer(state = {}, action) { // because of async behavior, sql lab may still poll a couple of seconds // when it started fetching or finished rendering results state: - currentState === 'success' && - ['fetching', 'success'].includes(prevState) + currentState === QueryState.SUCCESS && + [QueryState.FETCHING, QueryState.SUCCESS].includes(prevState) ? prevState : currentState, }; diff --git a/superset-frontend/src/SqlLab/reducers/sqlLab.test.js b/superset-frontend/src/SqlLab/reducers/sqlLab.test.js index 067cba3070ac9..dd4c0be4b4ce7 100644 --- a/superset-frontend/src/SqlLab/reducers/sqlLab.test.js +++ b/superset-frontend/src/SqlLab/reducers/sqlLab.test.js @@ -39,23 +39,77 @@ describe('sqlLabReducer', () => { qe = newState.queryEditors.find(e => e.id === 'abcd'); }); it('should add a query editor', () => { - expect(newState.queryEditors).toHaveLength(2); + expect(newState.queryEditors).toHaveLength( + initialState.queryEditors.length + 1, + ); + }); + it('should merge the current unsaved changes when adding a query editor', () => { + const expectedTitle = 'new updated title'; + const updateAction = { + type: actions.QUERY_EDITOR_SET_TITLE, + queryEditor: initialState.queryEditors[0], + name: expectedTitle, + }; + newState = sqlLabReducer(newState, updateAction); + const addAction = { + type: actions.ADD_QUERY_EDITOR, + queryEditor: { ...initialState.queryEditors[0], id: 'efgh' }, + }; + newState = sqlLabReducer(newState, addAction); + + expect(newState.queryEditors[0].name).toEqual(expectedTitle); + expect( + newState.queryEditors[newState.queryEditors.length - 1].id, + ).toEqual('efgh'); }); it('should remove a query editor', () => { - expect(newState.queryEditors).toHaveLength(2); + expect(newState.queryEditors).toHaveLength( + initialState.queryEditors.length + 1, + ); const action = { type: actions.REMOVE_QUERY_EDITOR, queryEditor: qe, }; newState = sqlLabReducer(newState, action); - expect(newState.queryEditors).toHaveLength(1); + expect(newState.queryEditors).toHaveLength( + initialState.queryEditors.length, + ); + }); + it('should remove a query editor including unsaved changes', () => { + expect(newState.queryEditors).toHaveLength( + initialState.queryEditors.length + 1, + ); + let action = { + type: actions.QUERY_EDITOR_SETDB, + queryEditor: qe, + dbId: 123, + }; + newState = sqlLabReducer(newState, action); + expect(newState.unsavedQueryEditor.dbId).toEqual(action.dbId); + action = { + type: actions.REMOVE_QUERY_EDITOR, + queryEditor: qe, + }; + newState = sqlLabReducer(newState, action); + expect(newState.queryEditors).toHaveLength( + initialState.queryEditors.length, + ); + expect(newState.unsavedQueryEditor.dbId).toBeUndefined(); + expect(newState.unsavedQueryEditor.id).toBeUndefined(); }); it('should set q query editor active', () => { + const expectedTitle = 'new updated title'; const addQueryEditorAction = { type: actions.ADD_QUERY_EDITOR, queryEditor: { ...initialState.queryEditors[0], id: 'abcd' }, }; newState = sqlLabReducer(newState, addQueryEditorAction); + const updateAction = { + type: actions.QUERY_EDITOR_SET_TITLE, + queryEditor: initialState.queryEditors[1], + name: expectedTitle, + }; + newState = sqlLabReducer(newState, updateAction); const setActiveQueryEditorAction = { type: actions.SET_ACTIVE_QUERY_EDITOR, queryEditor: defaultQueryEditor, @@ -64,6 +118,7 @@ describe('sqlLabReducer', () => { expect(newState.tabHistory[newState.tabHistory.length - 1]).toBe( defaultQueryEditor.id, ); + expect(newState.queryEditors[1].name).toEqual(expectedTitle); }); it('should not fail while setting DB', () => { const dbId = 9; @@ -73,7 +128,8 @@ describe('sqlLabReducer', () => { dbId, }; newState = sqlLabReducer(newState, action); - expect(newState.queryEditors[1].dbId).toBe(dbId); + expect(newState.unsavedQueryEditor.dbId).toBe(dbId); + expect(newState.unsavedQueryEditor.id).toBe(qe.id); }); it('should not fail while setting schema', () => { const schema = 'foo'; @@ -83,7 +139,8 @@ describe('sqlLabReducer', () => { schema, }; newState = sqlLabReducer(newState, action); - expect(newState.queryEditors[1].schema).toBe(schema); + expect(newState.unsavedQueryEditor.schema).toBe(schema); + expect(newState.unsavedQueryEditor.id).toBe(qe.id); }); it('should not fail while setting autorun', () => { const action = { @@ -91,19 +148,22 @@ describe('sqlLabReducer', () => { queryEditor: qe, }; newState = sqlLabReducer(newState, { ...action, autorun: false }); - expect(newState.queryEditors[1].autorun).toBe(false); + expect(newState.unsavedQueryEditor.autorun).toBe(false); + expect(newState.unsavedQueryEditor.id).toBe(qe.id); newState = sqlLabReducer(newState, { ...action, autorun: true }); - expect(newState.queryEditors[1].autorun).toBe(true); + expect(newState.unsavedQueryEditor.autorun).toBe(true); + expect(newState.unsavedQueryEditor.id).toBe(qe.id); }); it('should not fail while setting title', () => { - const title = 'a new title'; + const title = 'Untitled Query 1'; const action = { type: actions.QUERY_EDITOR_SET_TITLE, queryEditor: qe, - title, + name: title, }; newState = sqlLabReducer(newState, action); - expect(newState.queryEditors[1].title).toBe(title); + expect(newState.unsavedQueryEditor.name).toBe(title); + expect(newState.unsavedQueryEditor.id).toBe(qe.id); }); it('should not fail while setting Sql', () => { const sql = 'SELECT nothing from dev_null'; @@ -113,7 +173,8 @@ describe('sqlLabReducer', () => { sql, }; newState = sqlLabReducer(newState, action); - expect(newState.queryEditors[1].sql).toBe(sql); + expect(newState.unsavedQueryEditor.sql).toBe(sql); + expect(newState.unsavedQueryEditor.id).toBe(qe.id); }); it('should not fail while setting queryLimit', () => { const queryLimit = 101; @@ -123,18 +184,40 @@ describe('sqlLabReducer', () => { queryLimit, }; newState = sqlLabReducer(newState, action); - expect(newState.queryEditors[1].queryLimit).toEqual(queryLimit); + expect(newState.unsavedQueryEditor.queryLimit).toBe(queryLimit); + expect(newState.unsavedQueryEditor.id).toBe(qe.id); }); it('should set selectedText', () => { const selectedText = 'TEST'; const action = { type: actions.QUERY_EDITOR_SET_SELECTED_TEXT, - queryEditor: newState.queryEditors[0], + queryEditor: qe, sql: selectedText, }; - expect(newState.queryEditors[0].selectedText).toBeNull(); + expect(qe.selectedText).toBeFalsy(); newState = sqlLabReducer(newState, action); - expect(newState.queryEditors[0].selectedText).toBe(selectedText); + expect(newState.unsavedQueryEditor.selectedText).toBe(selectedText); + expect(newState.unsavedQueryEditor.id).toBe(qe.id); + }); + it('should not wiped out unsaved changes while delayed async call intercepted', () => { + const expectedSql = 'Updated SQL WORKING IN PROGRESS--'; + const action = { + type: actions.QUERY_EDITOR_SET_SQL, + queryEditor: qe, + sql: expectedSql, + }; + newState = sqlLabReducer(newState, action); + expect(newState.unsavedQueryEditor.sql).toBe(expectedSql); + const interceptedAction = { + type: actions.QUERY_EDITOR_SET_FUNCTION_NAMES, + queryEditor: newState.queryEditors[0], + functionNames: ['func1', 'func2'], + }; + newState = sqlLabReducer(newState, interceptedAction); + expect(newState.unsavedQueryEditor.sql).toBe(expectedSql); + expect(newState.queryEditors[0].functionNames).toBe( + interceptedAction.functionNames, + ); }); }); describe('Tables', () => { @@ -181,8 +264,8 @@ describe('sqlLabReducer', () => { }); it('should remove a table', () => { const action = { - type: actions.REMOVE_TABLE, - table: newTable, + type: actions.REMOVE_TABLES, + tables: [newTable], }; newState = sqlLabReducer(newState, action); expect(newState.tables).toHaveLength(0); diff --git a/superset-frontend/src/SqlLab/types.ts b/superset-frontend/src/SqlLab/types.ts index fb3993fe84f6b..7317ef0789d5a 100644 --- a/superset-frontend/src/SqlLab/types.ts +++ b/superset-frontend/src/SqlLab/types.ts @@ -16,26 +16,42 @@ * specific language governing permissions and limitations * under the License. */ +import { JsonObject, QueryResponse } from '@superset-ui/core'; import { SupersetError } from 'src/components/ErrorMessage/types'; import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; import { ToastType } from 'src/components/MessageToasts/types'; -import { Dataset } from '@superset-ui/chart-controls'; -import { Query, QueryResponse } from '@superset-ui/core'; -import { ExploreRootState } from 'src/explore/types'; +import { RootState } from 'src/dashboard/types'; +import { DropdownButtonProps } from 'src/components/DropdownButton'; +import { ButtonProps } from 'src/components/Button'; -export type ExploreDatasource = Dataset | QueryResponse; +export type QueryButtonProps = DropdownButtonProps | ButtonProps; + +// Object as Dictionary (associative array) with Query id as the key and type Query as the value +export type QueryDictionary = { + [id: string]: QueryResponse; +}; export interface QueryEditor { + id: string; dbId?: number; - title: string; + name: string; schema: string; autorun: boolean; sql: string; remoteId: number | null; + tableOptions: any[]; + schemaOptions?: SchemaOption[]; + functionNames: string[]; validationResult?: { completed: boolean; errors: SupersetError[]; }; + hideLeftBar?: boolean; + latestQueryId?: string | null; + templateParams?: string; + selectedText?: string; + queryLimit?: number; + description?: string; } export type toastState = { @@ -53,20 +69,25 @@ export type SqlLabRootState = { databases: Record<string, any>; dbConnect: boolean; offline: boolean; - queries: Query[]; + queries: Record<string, QueryResponse>; queryEditors: QueryEditor[]; tabHistory: string[]; // default is activeTab ? [activeTab.id.toString()] : [] tables: Record<string, any>[]; queriesLastUpdate: number; user: UserWithPermissionsAndRoles; errorMessage: string | null; + unsavedQueryEditor: Partial<QueryEditor>; + queryCostEstimates?: Record<string, QueryCostEstimate>; }; localStorageUsageInKilobytes: number; messageToasts: toastState[]; - common: {}; + common: { + flash_messages: string[]; + conf: JsonObject; + }; }; -export type SqlLabExploreRootState = SqlLabRootState | ExploreRootState; +export type SqlLabExploreRootState = SqlLabRootState | RootState; export const getInitialState = (state: SqlLabExploreRootState) => { if (state.hasOwnProperty('sqlLab')) { @@ -76,10 +97,8 @@ export const getInitialState = (state: SqlLabExploreRootState) => { return user; } - const { - explore: { user }, - } = state as ExploreRootState; - return user; + const { user } = state as RootState; + return user as UserWithPermissionsAndRoles; }; export enum DatasetRadioState { @@ -91,7 +110,7 @@ export const EXPLORE_CHART_DEFAULT = { metrics: [], groupby: [], time_range: 'No filter', - viz_type: 'table', + row_limit: 1000, }; export interface DatasetOwner { @@ -106,3 +125,15 @@ export interface DatasetOptionAutocomplete { datasetId: number; owners: [DatasetOwner]; } + +export interface SchemaOption { + value: string; + label: string; + title: string; +} + +export interface QueryCostEstimate { + completed: string; + cost: Record<string, any>[]; + error: string; +} diff --git a/superset-frontend/src/SqlLab/utils/newQueryTabName.test.ts b/superset-frontend/src/SqlLab/utils/newQueryTabName.test.ts index d0d98c3cd5e29..33eec73781613 100644 --- a/superset-frontend/src/SqlLab/utils/newQueryTabName.test.ts +++ b/superset-frontend/src/SqlLab/utils/newQueryTabName.test.ts @@ -17,9 +17,11 @@ * under the License. */ +import { defaultQueryEditor } from 'src/SqlLab/fixtures'; import { newQueryTabName } from './newQueryTabName'; const emptyEditor = { + ...defaultQueryEditor, title: '', schema: '', autorun: false, @@ -36,8 +38,8 @@ describe('newQueryTabName', () => { it('should return next available number if there are unsaved editors', () => { const untitledQueryText = 'Untitled Query'; const unsavedEditors = [ - { ...emptyEditor, title: `${untitledQueryText} 1` }, - { ...emptyEditor, title: `${untitledQueryText} 2` }, + { ...emptyEditor, name: `${untitledQueryText} 1` }, + { ...emptyEditor, name: `${untitledQueryText} 2` }, ]; const nextTitle = newQueryTabName(unsavedEditors); diff --git a/superset-frontend/src/SqlLab/utils/newQueryTabName.ts b/superset-frontend/src/SqlLab/utils/newQueryTabName.ts index 3815226cd4ba5..ac0728339c934 100644 --- a/superset-frontend/src/SqlLab/utils/newQueryTabName.ts +++ b/superset-frontend/src/SqlLab/utils/newQueryTabName.ts @@ -31,10 +31,10 @@ export const newQueryTabName = ( if (queryEditors.length > 0) { const mappedUntitled = queryEditors.filter(qe => - qe.title.match(untitledQueryRegex), + qe.name?.match(untitledQueryRegex), ); const untitledQueryNumbers = mappedUntitled.map( - qe => +qe.title.replace(untitledQuery, ''), + qe => +qe.name.replace(untitledQuery, ''), ); if (untitledQueryNumbers.length > 0) { // When there are query tabs open, and at least one is called "Untitled Query #" diff --git a/superset-frontend/src/SqlLab/utils/reduxStateToLocalStorageHelper.js b/superset-frontend/src/SqlLab/utils/reduxStateToLocalStorageHelper.js index 3a4288180dbf0..66e33b07c5f4c 100644 --- a/superset-frontend/src/SqlLab/utils/reduxStateToLocalStorageHelper.js +++ b/superset-frontend/src/SqlLab/utils/reduxStateToLocalStorageHelper.js @@ -32,7 +32,7 @@ const PERSISTENT_QUERY_EDITOR_KEYS = new Set([ 'southPercent', 'sql', 'templateParams', - 'title', + 'name', 'hideLeftBar', ]); diff --git a/superset-frontend/src/SqlLab/utils/useInterval.ts b/superset-frontend/src/SqlLab/utils/useInterval.ts new file mode 100644 index 0000000000000..731e6c85cf74c --- /dev/null +++ b/superset-frontend/src/SqlLab/utils/useInterval.ts @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useEffect, useRef } from 'react'; + +/* + * Functional components and setTimeout with useState do not play well + * and the setTimeout callback typically has stale state from a closure + * The useInterval function solves this issue. + * more info: https://overreacted.io/making-setinterval-declarative-with-react-hooks/ + */ +function useInterval(callback: Function, delay: number | null): void { + const savedCallback = useRef<Function>(callback); + // Remember the latest function. + useEffect(() => { + savedCallback.current = callback; + }, [callback]); + + // Set up the interval. + useEffect(() => { + function tick() { + savedCallback?.current?.(); + } + if (delay !== null) { + const id = setInterval(tick, delay); + return () => clearInterval(id); + } + return () => {}; + }, [delay]); +} + +export default useInterval; diff --git a/superset-frontend/src/addSlice/AddSliceContainer.test.tsx b/superset-frontend/src/addSlice/AddSliceContainer.test.tsx deleted file mode 100644 index 00e7276a5864c..0000000000000 --- a/superset-frontend/src/addSlice/AddSliceContainer.test.tsx +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import { ReactWrapper } from 'enzyme'; -import Button from 'src/components/Button'; -import { Select } from 'src/components'; -import AddSliceContainer, { - AddSliceContainerProps, - AddSliceContainerState, -} from 'src/addSlice/AddSliceContainer'; -import VizTypeGallery from 'src/explore/components/controls/VizTypeControl/VizTypeGallery'; -import { styledMount as mount } from 'spec/helpers/theming'; -import { act } from 'spec/helpers/testing-library'; - -const datasource = { - value: '1', - label: 'table', -}; - -describe('AddSliceContainer', () => { - let wrapper: ReactWrapper< - AddSliceContainerProps, - AddSliceContainerState, - AddSliceContainer - >; - - beforeEach(async () => { - wrapper = mount(<AddSliceContainer />) as ReactWrapper< - AddSliceContainerProps, - AddSliceContainerState, - AddSliceContainer - >; - // suppress a warning caused by some unusual async behavior in Icon - await act(() => new Promise(resolve => setTimeout(resolve, 0))); - }); - - it('renders a select and a VizTypeControl', () => { - expect(wrapper.find(Select)).toExist(); - expect(wrapper.find(VizTypeGallery)).toExist(); - }); - - it('renders a button', () => { - expect(wrapper.find(Button)).toExist(); - }); - - it('renders a disabled button if no datasource is selected', () => { - expect( - wrapper.find(Button).find({ disabled: true }).hostNodes(), - ).toHaveLength(1); - }); - - it('renders an enabled button if datasource and viz type is selected', () => { - wrapper.setState({ - datasource, - visType: 'table', - }); - expect( - wrapper.find(Button).find({ disabled: true }).hostNodes(), - ).toHaveLength(0); - }); - - it('formats explore url', () => { - wrapper.setState({ - datasource, - visType: 'table', - }); - const formattedUrl = - '/superset/explore/?form_data=%7B%22viz_type%22%3A%22table%22%2C%22datasource%22%3A%221%22%7D'; - expect(wrapper.instance().exploreUrl()).toBe(formattedUrl); - }); -}); diff --git a/superset-frontend/src/addSlice/App.tsx b/superset-frontend/src/addSlice/App.tsx deleted file mode 100644 index dac830308364f..0000000000000 --- a/superset-frontend/src/addSlice/App.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import { hot } from 'react-hot-loader/root'; -import { ThemeProvider } from '@superset-ui/core'; -import { GlobalStyles } from 'src/GlobalStyles'; -import setupApp from '../setup/setupApp'; -import setupPlugins from '../setup/setupPlugins'; -import { DynamicPluginProvider } from '../components/DynamicPlugins'; -import AddSliceContainer from './AddSliceContainer'; -import { initFeatureFlags } from '../featureFlags'; -import { theme } from '../preamble'; - -setupApp(); -setupPlugins(); - -const addSliceContainer = document.getElementById('app'); -const bootstrapData = JSON.parse( - addSliceContainer?.getAttribute('data-bootstrap') || '{}', -); - -initFeatureFlags(bootstrapData.common.feature_flags); - -const App = () => ( - <ThemeProvider theme={theme}> - <GlobalStyles /> - <DynamicPluginProvider> - <AddSliceContainer /> - </DynamicPluginProvider> - </ThemeProvider> -); - -export default hot(App); diff --git a/superset-frontend/src/assets/images/apache-kylin.png b/superset-frontend/src/assets/images/apache-kylin.png index 4b0fdab01d91d..d69914cf56d15 100644 Binary files a/superset-frontend/src/assets/images/apache-kylin.png and b/superset-frontend/src/assets/images/apache-kylin.png differ diff --git a/superset-frontend/src/assets/images/clickhouse.png b/superset-frontend/src/assets/images/clickhouse.png index fae469d52bde0..0e75d77ed6851 100644 Binary files a/superset-frontend/src/assets/images/clickhouse.png and b/superset-frontend/src/assets/images/clickhouse.png differ diff --git a/superset-frontend/src/assets/images/databricks.png b/superset-frontend/src/assets/images/databricks.png new file mode 100644 index 0000000000000..be4935236c732 Binary files /dev/null and b/superset-frontend/src/assets/images/databricks.png differ diff --git a/superset-frontend/src/assets/images/db2.png b/superset-frontend/src/assets/images/db2.png index 7deb9368289e8..d3d001b521245 100644 Binary files a/superset-frontend/src/assets/images/db2.png and b/superset-frontend/src/assets/images/db2.png differ diff --git a/superset-frontend/src/assets/images/druid.png b/superset-frontend/src/assets/images/druid.png index 6860d78bbfba6..7bc0ea5195c45 100644 Binary files a/superset-frontend/src/assets/images/druid.png and b/superset-frontend/src/assets/images/druid.png differ diff --git a/superset-frontend/src/assets/images/empty-dataset.svg b/superset-frontend/src/assets/images/empty-dataset.svg new file mode 100644 index 0000000000000..5ce1752545b29 --- /dev/null +++ b/superset-frontend/src/assets/images/empty-dataset.svg @@ -0,0 +1,38 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<svg width="152" height="152" viewBox="0 0 152 152" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M44.5 1C45.0523 1 45.5 1.44772 45.5 2V45C45.5 45.5523 45.0523 46 44.5 46H1.5C0.947716 46 0.5 45.5523 0.5 45V2C0.5 1.44772 0.947716 1 1.5 1L44.5 1Z" fill="white"/> +<path d="M97.5 1C98.0523 1 98.5 1.44772 98.5 2V45C98.5 45.5523 98.0523 46 97.5 46H54.5C53.9477 46 53.5 45.5523 53.5 45V2C53.5 1.44772 53.9477 1 54.5 1L97.5 1Z" fill="white"/> +<path d="M150.5 1C151.052 1 151.5 1.44772 151.5 2V45C151.5 45.5523 151.052 46 150.5 46H107.5C106.948 46 106.5 45.5523 106.5 45V2C106.5 1.44772 106.948 1 107.5 1L150.5 1Z" fill="white"/> +<path d="M44.5 54C45.0523 54 45.5 54.4477 45.5 55V98C45.5 98.5523 45.0523 99 44.5 99H1.5C0.947716 99 0.5 98.5523 0.5 98V55C0.5 54.4477 0.947716 54 1.5 54H44.5Z" fill="white"/> +<path d="M97.5 54C98.0523 54 98.5 54.4477 98.5 55V98C98.5 98.5523 98.0523 99 97.5 99H54.5C53.9477 99 53.5 98.5523 53.5 98V55C53.5 54.4477 53.9477 54 54.5 54H97.5Z" fill="white"/> +<path d="M150.5 54C151.052 54 151.5 54.4477 151.5 55V98C151.5 98.5523 151.052 99 150.5 99H107.5C106.948 99 106.5 98.5523 106.5 98V55C106.5 54.4477 106.948 54 107.5 54H150.5Z" fill="white"/> +<path d="M44.5 106C45.0523 106 45.5 106.448 45.5 107V150C45.5 150.552 45.0523 151 44.5 151H1.5C0.947716 151 0.5 150.552 0.5 150V107C0.5 106.448 0.947716 106 1.5 106H44.5Z" fill="white"/> +<path d="M97.5 106C98.0523 106 98.5 106.448 98.5 107V150C98.5 150.552 98.0523 151 97.5 151H54.5C53.9477 151 53.5 150.552 53.5 150V107C53.5 106.448 53.9477 106 54.5 106H97.5Z" fill="white"/> +<path d="M150.5 106C151.052 106 151.5 106.448 151.5 107V150C151.5 150.552 151.052 151 150.5 151H107.5C106.948 151 106.5 150.552 106.5 150V107C106.5 106.448 106.948 106 107.5 106H150.5Z" fill="white"/> +<path d="M44.5 1C45.0523 1 45.5 1.44772 45.5 2V45C45.5 45.5523 45.0523 46 44.5 46H1.5C0.947716 46 0.5 45.5523 0.5 45V2C0.5 1.44772 0.947716 1 1.5 1L44.5 1Z" stroke="#E0E0E0"/> +<path d="M97.5 1C98.0523 1 98.5 1.44772 98.5 2V45C98.5 45.5523 98.0523 46 97.5 46H54.5C53.9477 46 53.5 45.5523 53.5 45V2C53.5 1.44772 53.9477 1 54.5 1L97.5 1Z" stroke="#E0E0E0"/> +<path d="M150.5 1C151.052 1 151.5 1.44772 151.5 2V45C151.5 45.5523 151.052 46 150.5 46H107.5C106.948 46 106.5 45.5523 106.5 45V2C106.5 1.44772 106.948 1 107.5 1L150.5 1Z" stroke="#E0E0E0"/> +<path d="M44.5 54C45.0523 54 45.5 54.4477 45.5 55V98C45.5 98.5523 45.0523 99 44.5 99H1.5C0.947716 99 0.5 98.5523 0.5 98V55C0.5 54.4477 0.947716 54 1.5 54H44.5Z" stroke="#E0E0E0"/> +<path d="M97.5 54C98.0523 54 98.5 54.4477 98.5 55V98C98.5 98.5523 98.0523 99 97.5 99H54.5C53.9477 99 53.5 98.5523 53.5 98V55C53.5 54.4477 53.9477 54 54.5 54H97.5Z" stroke="#E0E0E0"/> +<path d="M150.5 54C151.052 54 151.5 54.4477 151.5 55V98C151.5 98.5523 151.052 99 150.5 99H107.5C106.948 99 106.5 98.5523 106.5 98V55C106.5 54.4477 106.948 54 107.5 54H150.5Z" stroke="#E0E0E0"/> +<path d="M44.5 106C45.0523 106 45.5 106.448 45.5 107V150C45.5 150.552 45.0523 151 44.5 151H1.5C0.947716 151 0.5 150.552 0.5 150V107C0.5 106.448 0.947716 106 1.5 106H44.5Z" stroke="#E0E0E0"/> +<path d="M97.5 106C98.0523 106 98.5 106.448 98.5 107V150C98.5 150.552 98.0523 151 97.5 151H54.5C53.9477 151 53.5 150.552 53.5 150V107C53.5 106.448 53.9477 106 54.5 106H97.5Z" stroke="#E0E0E0"/> +<path d="M150.5 106C151.052 106 151.5 106.448 151.5 107V150C151.5 150.552 151.052 151 150.5 151H107.5C106.948 151 106.5 150.552 106.5 150V107C106.5 106.448 106.948 106 107.5 106H150.5Z" stroke="#E0E0E0"/> +</svg> diff --git a/superset-frontend/src/assets/images/empty-table.svg b/superset-frontend/src/assets/images/empty-table.svg new file mode 100644 index 0000000000000..c1062502f39dc --- /dev/null +++ b/superset-frontend/src/assets/images/empty-table.svg @@ -0,0 +1,22 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<svg width="81" height="82" viewBox="0 0 81 82" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M76.5 1H4.5C2.29086 1 0.5 2.79086 0.5 5V77C0.5 79.2091 2.29086 81 4.5 81H76.5C78.7091 81 80.5 79.2091 80.5 77V5C80.5 2.79086 78.7091 1 76.5 1ZM36.5 73H8.5V57H36.5V73ZM36.5 49H8.5V33H36.5V49ZM72.5 73H44.5V57H72.5V73ZM72.5 49H44.5V33H72.5V49ZM72.5 25H8.5V9H72.5V25Z" fill="#F7F7F7"/> +<path d="M36.5 73V73.5H37V73H36.5ZM8.5 73H8V73.5H8.5V73ZM8.5 57V56.5H8V57H8.5ZM36.5 57H37V56.5H36.5V57ZM36.5 49V49.5H37V49H36.5ZM8.5 49H8V49.5H8.5V49ZM8.5 33V32.5H8V33H8.5ZM36.5 33H37V32.5H36.5V33ZM72.5 73V73.5H73V73H72.5ZM44.5 73H44V73.5H44.5V73ZM44.5 57V56.5H44V57H44.5ZM72.5 57H73V56.5H72.5V57ZM72.5 49V49.5H73V49H72.5ZM44.5 49H44V49.5H44.5V49ZM44.5 33V32.5H44V33H44.5ZM72.5 33H73V32.5H72.5V33ZM72.5 25V25.5H73V25H72.5ZM8.5 25H8V25.5H8.5V25ZM8.5 9V8.5H8V9H8.5ZM72.5 9H73V8.5H72.5V9ZM76.5 0.5H4.5V1.5H76.5V0.5ZM4.5 0.5C2.01472 0.5 0 2.51472 0 5H1C1 3.067 2.567 1.5 4.5 1.5V0.5ZM0 5V77H1V5H0ZM0 77C0 79.4853 2.01472 81.5 4.5 81.5V80.5C2.567 80.5 1 78.933 1 77H0ZM4.5 81.5H76.5V80.5H4.5V81.5ZM76.5 81.5C78.9853 81.5 81 79.4853 81 77H80C80 78.933 78.433 80.5 76.5 80.5V81.5ZM81 77V5H80V77H81ZM81 5C81 2.51472 78.9853 0.5 76.5 0.5V1.5C78.433 1.5 80 3.067 80 5H81ZM36.5 72.5H8.5V73.5H36.5V72.5ZM9 73V57H8V73H9ZM8.5 57.5H36.5V56.5H8.5V57.5ZM36 57V73H37V57H36ZM36.5 48.5H8.5V49.5H36.5V48.5ZM9 49V33H8V49H9ZM8.5 33.5H36.5V32.5H8.5V33.5ZM36 33V49H37V33H36ZM72.5 72.5H44.5V73.5H72.5V72.5ZM45 73V57H44V73H45ZM44.5 57.5H72.5V56.5H44.5V57.5ZM72 57V73H73V57H72ZM72.5 48.5H44.5V49.5H72.5V48.5ZM45 49V33H44V49H45ZM44.5 33.5H72.5V32.5H44.5V33.5ZM72 33V49H73V33H72ZM72.5 24.5H8.5V25.5H72.5V24.5ZM9 25V9H8V25H9ZM8.5 9.5H72.5V8.5H8.5V9.5ZM72 9V25H73V9H72Z" fill="#E0E0E0"/> +</svg> diff --git a/superset-frontend/src/assets/images/exasol.png b/superset-frontend/src/assets/images/exasol.png index 46260f8d4fceb..fff47b00a003c 100644 Binary files a/superset-frontend/src/assets/images/exasol.png and b/superset-frontend/src/assets/images/exasol.png differ diff --git a/superset-frontend/src/assets/images/firebird.png b/superset-frontend/src/assets/images/firebird.png index 19e862c03be25..386562354d293 100644 Binary files a/superset-frontend/src/assets/images/firebird.png and b/superset-frontend/src/assets/images/firebird.png differ diff --git a/superset-frontend/src/assets/images/firebolt.png b/superset-frontend/src/assets/images/firebolt.png index f9ffc947e2201..3e36f92c80816 100644 Binary files a/superset-frontend/src/assets/images/firebolt.png and b/superset-frontend/src/assets/images/firebolt.png differ diff --git a/superset-frontend/src/assets/images/google-biquery.png b/superset-frontend/src/assets/images/google-biquery.png index da6960ac9b32f..fbc8523866595 100644 Binary files a/superset-frontend/src/assets/images/google-biquery.png and b/superset-frontend/src/assets/images/google-biquery.png differ diff --git a/superset-frontend/src/assets/images/greenplum.png b/superset-frontend/src/assets/images/greenplum.png index 70f82ea18ce61..16e89f47f6ea2 100644 Binary files a/superset-frontend/src/assets/images/greenplum.png and b/superset-frontend/src/assets/images/greenplum.png differ diff --git a/superset-frontend/src/assets/images/hologres.png b/superset-frontend/src/assets/images/hologres.png index 612b41d04ee5f..60400df3c901f 100644 Binary files a/superset-frontend/src/assets/images/hologres.png and b/superset-frontend/src/assets/images/hologres.png differ diff --git a/superset-frontend/src/assets/images/mariadb.png b/superset-frontend/src/assets/images/mariadb.png index bd1687931fba8..fbc301a1309c8 100644 Binary files a/superset-frontend/src/assets/images/mariadb.png and b/superset-frontend/src/assets/images/mariadb.png differ diff --git a/superset-frontend/src/assets/images/monet-db.png b/superset-frontend/src/assets/images/monet-db.png index 3b0dcc2b0e8ba..0500ed155b82c 100644 Binary files a/superset-frontend/src/assets/images/monet-db.png and b/superset-frontend/src/assets/images/monet-db.png differ diff --git a/superset-frontend/src/assets/images/mssql-server.png b/superset-frontend/src/assets/images/mssql-server.png index f4f0d6f9950c5..bf8bffe34bfbb 100644 Binary files a/superset-frontend/src/assets/images/mssql-server.png and b/superset-frontend/src/assets/images/mssql-server.png differ diff --git a/superset-frontend/src/assets/images/mysql.png b/superset-frontend/src/assets/images/mysql.png index b68620c289f13..02526578256e8 100644 Binary files a/superset-frontend/src/assets/images/mysql.png and b/superset-frontend/src/assets/images/mysql.png differ diff --git a/superset-frontend/src/assets/images/netezza.png b/superset-frontend/src/assets/images/netezza.png index 2658d8629bf1e..c8a47a6fa13c7 100644 Binary files a/superset-frontend/src/assets/images/netezza.png and b/superset-frontend/src/assets/images/netezza.png differ diff --git a/superset-frontend/src/assets/images/no-columns.svg b/superset-frontend/src/assets/images/no-columns.svg new file mode 100644 index 0000000000000..2fc8fe0661bfe --- /dev/null +++ b/superset-frontend/src/assets/images/no-columns.svg @@ -0,0 +1,22 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<svg width="152" height="152" viewBox="0 0 152 152" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M143.5 1H8.5C4.35786 1 1 4.35786 1 8.5V143.5C1 147.642 4.35786 151 8.5 151H143.5C147.642 151 151 147.642 151 143.5V8.5C151 4.35786 147.642 1 143.5 1ZM68.5 136H16V106H68.5V136ZM68.5 91H16V61H68.5V91ZM136 136H83.5V106H136V136ZM136 91H83.5V61H136V91ZM136 46H16V16H136V46Z" fill="#F7F7F7"/> +<path d="M68.5 136V136.5H69V136H68.5ZM16 136H15.5V136.5H16V136ZM16 106V105.5H15.5V106H16ZM68.5 106H69V105.5H68.5V106ZM68.5 91V91.5H69V91H68.5ZM16 91H15.5V91.5H16V91ZM16 61V60.5H15.5V61H16ZM68.5 61H69V60.5H68.5V61ZM136 136V136.5H136.5V136H136ZM83.5 136H83V136.5H83.5V136ZM83.5 106V105.5H83V106H83.5ZM136 106H136.5V105.5H136V106ZM136 91V91.5H136.5V91H136ZM83.5 91H83V91.5H83.5V91ZM83.5 61V60.5H83V61H83.5ZM136 61H136.5V60.5H136V61ZM136 46V46.5H136.5V46H136ZM16 46H15.5V46.5H16V46ZM16 16V15.5H15.5V16H16ZM136 16H136.5V15.5H136V16ZM143.5 0.5H8.5V1.5H143.5V0.5ZM8.5 0.5C4.08172 0.5 0.5 4.08172 0.5 8.5H1.5C1.5 4.63401 4.63401 1.5 8.5 1.5V0.5ZM0.5 8.5V143.5H1.5V8.5H0.5ZM0.5 143.5C0.5 147.918 4.08172 151.5 8.5 151.5V150.5C4.63401 150.5 1.5 147.366 1.5 143.5H0.5ZM8.5 151.5H143.5V150.5H8.5V151.5ZM143.5 151.5C147.918 151.5 151.5 147.918 151.5 143.5H150.5C150.5 147.366 147.366 150.5 143.5 150.5V151.5ZM151.5 143.5V8.5H150.5V143.5H151.5ZM151.5 8.5C151.5 4.08172 147.918 0.5 143.5 0.5V1.5C147.366 1.5 150.5 4.63401 150.5 8.5H151.5ZM68.5 135.5H16V136.5H68.5V135.5ZM16.5 136V106H15.5V136H16.5ZM16 106.5H68.5V105.5H16V106.5ZM68 106V136H69V106H68ZM68.5 90.5H16V91.5H68.5V90.5ZM16.5 91V61H15.5V91H16.5ZM16 61.5H68.5V60.5H16V61.5ZM68 61V91H69V61H68ZM136 135.5H83.5V136.5H136V135.5ZM84 136V106H83V136H84ZM83.5 106.5H136V105.5H83.5V106.5ZM135.5 106V136H136.5V106H135.5ZM136 90.5H83.5V91.5H136V90.5ZM84 91V61H83V91H84ZM83.5 61.5H136V60.5H83.5V61.5ZM135.5 61V91H136.5V61H135.5ZM136 45.5H16V46.5H136V45.5ZM16.5 46V16H15.5V46H16.5ZM16 16.5H136V15.5H16V16.5ZM135.5 16V46H136.5V16H135.5Z" fill="#E0E0E0"/> +</svg> diff --git a/superset-frontend/src/assets/images/oracle.png b/superset-frontend/src/assets/images/oracle.png index e923094c7ec42..40507d220a629 100644 Binary files a/superset-frontend/src/assets/images/oracle.png and b/superset-frontend/src/assets/images/oracle.png differ diff --git a/superset-frontend/src/assets/images/pinot.png b/superset-frontend/src/assets/images/pinot.png index 61f8cb6f57c39..0e92bb46625d0 100644 Binary files a/superset-frontend/src/assets/images/pinot.png and b/superset-frontend/src/assets/images/pinot.png differ diff --git a/superset-frontend/src/assets/images/postgresql.png b/superset-frontend/src/assets/images/postgresql.png index 7befee8eff0b1..8d3530a24e776 100644 Binary files a/superset-frontend/src/assets/images/postgresql.png and b/superset-frontend/src/assets/images/postgresql.png differ diff --git a/superset-frontend/src/assets/images/presto.png b/superset-frontend/src/assets/images/presto.png index a2e187f27d748..5d4bbb6d4f4e9 100644 Binary files a/superset-frontend/src/assets/images/presto.png and b/superset-frontend/src/assets/images/presto.png differ diff --git a/superset-frontend/src/assets/images/redshift.png b/superset-frontend/src/assets/images/redshift.png index 73d79b8bf4a88..f3fcd10dbabc1 100644 Binary files a/superset-frontend/src/assets/images/redshift.png and b/superset-frontend/src/assets/images/redshift.png differ diff --git a/superset-frontend/src/assets/images/rockset.png b/superset-frontend/src/assets/images/rockset.png index d7e301c617073..b94b9e040fd7a 100644 Binary files a/superset-frontend/src/assets/images/rockset.png and b/superset-frontend/src/assets/images/rockset.png differ diff --git a/superset-frontend/src/assets/images/snowflake.png b/superset-frontend/src/assets/images/snowflake.png index adc3443fdda77..e096a5dad19b2 100644 Binary files a/superset-frontend/src/assets/images/snowflake.png and b/superset-frontend/src/assets/images/snowflake.png differ diff --git a/superset-frontend/src/assets/images/sqlite.png b/superset-frontend/src/assets/images/sqlite.png index f7112cf7094d8..d0098a79363c9 100644 Binary files a/superset-frontend/src/assets/images/sqlite.png and b/superset-frontend/src/assets/images/sqlite.png differ diff --git a/superset-frontend/src/assets/images/sybase.png b/superset-frontend/src/assets/images/sybase.png index c5c8bca7e9b64..1437756a0b2a9 100644 Binary files a/superset-frontend/src/assets/images/sybase.png and b/superset-frontend/src/assets/images/sybase.png differ diff --git a/superset-frontend/src/assets/images/teradata.png b/superset-frontend/src/assets/images/teradata.png index 9b6e006117540..133747767756b 100644 Binary files a/superset-frontend/src/assets/images/teradata.png and b/superset-frontend/src/assets/images/teradata.png differ diff --git a/superset-frontend/src/assets/images/timescale.png b/superset-frontend/src/assets/images/timescale.png index 86706ec445db4..b68fc324bac30 100644 Binary files a/superset-frontend/src/assets/images/timescale.png and b/superset-frontend/src/assets/images/timescale.png differ diff --git a/superset-frontend/src/assets/images/trino.png b/superset-frontend/src/assets/images/trino.png index 904db40bb56c5..4fda6f84dbb0e 100644 Binary files a/superset-frontend/src/assets/images/trino.png and b/superset-frontend/src/assets/images/trino.png differ diff --git a/superset-frontend/src/assets/images/vertica.png b/superset-frontend/src/assets/images/vertica.png index 0bd39498c6e66..cf8f0a60b114c 100644 Binary files a/superset-frontend/src/assets/images/vertica.png and b/superset-frontend/src/assets/images/vertica.png differ diff --git a/superset-frontend/src/assets/images/yugabyte.png b/superset-frontend/src/assets/images/yugabyte.png index 576dd3848d299..89acadb9a9266 100644 Binary files a/superset-frontend/src/assets/images/yugabyte.png and b/superset-frontend/src/assets/images/yugabyte.png differ diff --git a/superset-frontend/src/assets/stylesheets/superset.less b/superset-frontend/src/assets/stylesheets/superset.less index 5808d0144bc73..7bf8c27fff60e 100644 --- a/superset-frontend/src/assets/stylesheets/superset.less +++ b/superset-frontend/src/assets/stylesheets/superset.less @@ -42,10 +42,6 @@ input.form-control { background-color: @lightest; } -.chart-header a.danger { - color: @danger; -} - .disabledButton { pointer-events: none; } @@ -165,16 +161,6 @@ img.viz-thumb-option { max-height: 700px; } -.chart-header .header-text { - font-size: @font-size-xl; - line-height: 22px; - padding-bottom: 8px; - border-bottom: 1px solid @gray; - margin-top: 10px; - margin-left: 10px; - margin-right: 10px; -} - #is_cached { display: none; } @@ -327,6 +313,10 @@ table.table-no-hover tr:hover { margin-bottom: 10px; } +.m-l-2 { + margin-left: 2px; +} + .m-l-4 { margin-left: 4px; } @@ -355,22 +345,6 @@ table.table-no-hover tr:hover { padding-right: 2; } -/** not found record **/ -.panel b { - display: inline-block; - width: 98%; - padding: 2rem; - margin: 0 1% 20px 1%; - background: @gray-bg; -} - -/** table on both sides of the gap **/ -@media screen and (max-width: 767px) { - .panel .table-responsive { - width: 98%; - } -} - .list-container { position: relative; } diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/Buttons.css b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/Buttons.css new file mode 100644 index 0000000000000..3d4c353a0cd33 --- /dev/null +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/Buttons.css @@ -0,0 +1,31 @@ +.Button { + background-color: transparent; + border: solid rgb(137, 137, 137); + border-width: 0 2px 2px 0; + display: inline-block; + padding-right: 3px; + padding-left: 3px; + padding-top: 3px; + padding-bottom: 3px; + vertical-align: middle; + margin-right: 10px; + margin-left: 5px; +} + +.Expand { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); +} + +.Collapse { + transform: rotate(45deg); + -webkit-transform: rotate(45deg); +} + +.Row-Expand { + background-color: transparent; + text-decoration: underline; + vertical-align: middle; + border: none; + color: rgb(31, 167, 201); +} diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/CccsGrid.tsx b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/CccsGrid.tsx index 67167ad1860fc..29ebf2ef14996 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/CccsGrid.tsx +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/CccsGrid.tsx @@ -42,6 +42,7 @@ import Ipv4ValueRenderer from './Ipv4ValueRenderer'; import Ipv6ValueRenderer from './Ipv6ValueRenderer'; import DomainValueRenderer from './DomainValueRenderer'; import JsonValueRenderer from './JsonValueRenderer'; +import ExpandAllValueRenderer from './ExpandAllValueRenderer'; import CustomTooltip from './CustomTooltip'; /// / jcc @@ -90,9 +91,11 @@ export default function CccsGrid({ const crossFilterValue = useSelector<RootState, any>( state => state.dataMask[formData.slice_id]?.filterState?.value, ); - - const [selectedDataByColumnName, setSelectedDataColumnName] = useState<{[key: string]: string[] }>(initialFilters); - const [selectedDataByAdvancedType, setselectedDataByAdvancedType] = useState<{[key: string]: string[]}>(initialFilters); + + const [selectedDataByColumnName, setSelectedDataColumnName] = + useState<{ [key: string]: string[] }>(initialFilters); + const [selectedDataByAdvancedType, setselectedDataByAdvancedType] = + useState<{ [key: string]: string[] }>(initialFilters); const [principalColumnFilters, setPrincipalColumnFilters] = useState({}); const [searchValue, setSearchValue] = useState(''); @@ -134,120 +137,125 @@ export default function CccsGrid({ [emitFilter, setDataMask, selectedDataByColumnName, principalColumnFilters], ); // only take relevant page size options - const generateNativeFilterUrlString = (nativefilterID: string, urlSelectedData: any[], column: string = "" ) =>{ - const stringSelectedData = urlSelectedData.map( e => { - return `${e.toString()}` - }) + const generateNativeFilterUrlString = ( + nativefilterID: string, + urlSelectedData: any[], + column: string = '', + ) => { + const stringSelectedData = urlSelectedData.map(e => { + return `${e.toString()}`; + }); const navtiveFilter = { extraFormData: { - filters: [ - {col: column, - op: "IN", - val: stringSelectedData} - ] + filters: [{ col: column, op: 'IN', val: stringSelectedData }], }, filterState: { label: stringSelectedData, validateStatus: false, - value: stringSelectedData + value: stringSelectedData, }, id: nativefilterID, - ownState: {} - } - return navtiveFilter - } - const getJumpToDashboardContextMenuItems = (selectedData: {[key: string]: string[] }, disableOveride: boolean): (string | MenuItemDef)[] => { - - let sub_menu: any = [] + ownState: {}, + }; + return navtiveFilter; + }; + const getJumpToDashboardContextMenuItems = ( + selectedData: { [key: string]: string[] }, + disableOveride: boolean, + ): (string | MenuItemDef)[] => { + let sub_menu: any = []; for (let key in jumpActionConfigs) { - let advancedDataTypeNativeFilters = jumpActionConfigs[key]; let nativeFilterUrls: any = {}; - let jumpActionName: string = "" + let jumpActionName: string = ''; advancedDataTypeNativeFilters.forEach((element: any) => { - jumpActionName = element.name + jumpActionName = element.name; let advancedDataType = element['advancedDataType']; - let nativefilters: any[] = element["nativefilters"]; + let nativefilters: any[] = element['nativefilters']; let selectedDataForUrl = selectedData[advancedDataType]; - + if (selectedDataForUrl && nativefilters) { - nativefilters.forEach( filter => { - nativeFilterUrls[filter["value"]] = generateNativeFilterUrlString(filter["value"], selectedDataForUrl, filter["column"]) + nativefilters.forEach(filter => { + nativeFilterUrls[filter['value']] = generateNativeFilterUrlString( + filter['value'], + selectedDataForUrl, + filter['column'], + ); }); } - }); - - if (Object.keys(nativeFilterUrls).length !== 0){ - + + if (Object.keys(nativeFilterUrls).length !== 0) { let action = () => { - let baseUrl = location.protocol + '//' + location.host; - let url = `${baseUrl}/superset/dashboard/${key}/?native_filters=${rison.encode(nativeFilterUrls)}` + let baseUrl = location.protocol + '//' + location.host; + let url = `${baseUrl}/superset/dashboard/${key}/?native_filters=${rison.encode( + nativeFilterUrls, + )}`; window.open(url, '_blank'); - } - + }; + let DashboardMenuItem = { name: jumpActionName, - action - } - - sub_menu.push(DashboardMenuItem) + action, + }; + + sub_menu.push(DashboardMenuItem); } - } - - const menu = {name: "Jump to dashboard", subMenu: sub_menu, disabled: disableOveride || sub_menu.length < 1, icon: '<span class="ag-icon ag-icon-pivot" unselectable="on" role="presentation"></span>' } - return [ menu ] - } + + const menu = { + name: 'Jump to dashboard', + subMenu: sub_menu, + disabled: disableOveride || sub_menu.length < 1, + icon: '<span class="ag-icon ag-icon-pivot" unselectable="on" role="presentation"></span>', + }; + return [menu]; + }; const getContextMenuItems = useCallback( (params: GetContextMenuItemsParams): (string | MenuItemDef)[] => { - let result: (string | MenuItemDef)[] = []; - result = ['copy', 'copyWithHeaders', 'paste',]; - - if(emitFilter) { - result = result.concat( - [ - 'separator', - { - name: 'Emit Filter(s)', - disabled: params.value === null, - action: () => handleChange(selectedDataByColumnName), - // eslint-disable-next-line theme-colors/no-literal-colors - icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" class=""><path fill-rule="evenodd" clip-rule="evenodd" d="M18.1573 17.864C21.2763 14.745 21.2763 9.66935 18.1573 6.5503C15.0382 3.43125 9.96264 3.43125 6.84359 6.5503L5.42938 5.13609C9.32836 1.2371 15.6725 1.2371 19.5715 5.13609C23.4705 9.03507 23.4705 15.3792 19.5715 19.2782C15.6725 23.1772 9.32836 23.1772 5.42938 19.2782L6.84359 17.864C9.96264 20.9831 15.0375 20.9838 18.1573 17.864ZM2.00035 11.5C2.00035 11.2239 2.2242 11 2.50035 11H5.00035L5.00035 10C5.00035 9.58798 5.47073 9.35279 5.80035 9.60001L9.00035 12C9.17125 12.1032 6.98685 13.637 5.77613 14.4703C5.44613 14.6975 5.00035 14.4601 5.00035 14.0595V13L2.50035 13C2.22421 13 2.00035 12.7761 2.00035 12.5L2.00035 11.5ZM9.67202 9.37873C11.2319 7.81885 13.7697 7.81956 15.3289 9.37873C16.888 10.9379 16.8887 13.4757 15.3289 15.0356C13.769 16.5955 11.2312 16.5948 9.67202 15.0356L8.2578 16.4498C10.5976 18.7896 14.4033 18.7896 16.7431 16.4498C19.0829 14.11 19.0829 10.3043 16.7431 7.96451C14.4033 5.6247 10.5976 5.6247 8.2578 7.96451L9.67202 9.37873Z" fill="#20A7C9"></path></svg>', - }, - { - name: 'Emit Principal Column Filter(s)', - disabled: - ensureIsArray(principalColumns).length === 0 || - Object.keys(principalColumnFilters).some(column => - principalColumnFilters[column].some((val: any) => val === null), - ) || - params.node === null, - action: () => handleChange(principalColumnFilters), - // eslint-disable-next-line theme-colors/no-literal-colors - icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" class=""><path fill-rule="evenodd" clip-rule="evenodd" d="M18.1573 17.864C21.2763 14.745 21.2763 9.66935 18.1573 6.5503C15.0382 3.43125 9.96264 3.43125 6.84359 6.5503L5.42938 5.13609C9.32836 1.2371 15.6725 1.2371 19.5715 5.13609C23.4705 9.03507 23.4705 15.3792 19.5715 19.2782C15.6725 23.1772 9.32836 23.1772 5.42938 19.2782L6.84359 17.864C9.96264 20.9831 15.0375 20.9838 18.1573 17.864ZM2.00035 11.5C2.00035 11.2239 2.2242 11 2.50035 11H5.00035L5.00035 10C5.00035 9.58798 5.47073 9.35279 5.80035 9.60001L9.00035 12C9.17125 12.1032 6.98685 13.637 5.77613 14.4703C5.44613 14.6975 5.00035 14.4601 5.00035 14.0595V13L2.50035 13C2.22421 13 2.00035 12.7761 2.00035 12.5L2.00035 11.5ZM9.67202 9.37873C11.2319 7.81885 13.7697 7.81956 15.3289 9.37873C16.888 10.9379 16.8887 13.4757 15.3289 15.0356C13.769 16.5955 11.2312 16.5948 9.67202 15.0356L8.2578 16.4498C10.5976 18.7896 14.4033 18.7896 16.7431 16.4498C19.0829 14.11 19.0829 10.3043 16.7431 7.96451C14.4033 5.6247 10.5976 5.6247 8.2578 7.96451L9.67202 9.37873Z" fill="#20A7C9"></path></svg>', - }, - { - name: 'Clear Emitted Filter(s)', - disabled: crossFilterValue === undefined, - action: () => dispatch(clearDataMask(formData.slice_id)), - icon: '<span class="ag-icon ag-icon-cross" unselectable="on" role="presentation"></span>', - }, - ] - ) - } - result = result.concat( - getJumpToDashboardContextMenuItems(selectedDataByAdvancedType, (params.value === null)) - ) - result = result.concat( - [ + result = ['copy', 'copyWithHeaders', 'paste']; + + if (emitFilter) { + result = result.concat([ 'separator', - 'export' - ] - ) - + { + name: 'Emit Filter(s)', + disabled: + params.value === null || 'undefined' in selectedDataByColumnName, + action: () => handleChange(selectedDataByColumnName), + // eslint-disable-next-line theme-colors/no-literal-colors + icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" class=""><path fill-rule="evenodd" clip-rule="evenodd" d="M18.1573 17.864C21.2763 14.745 21.2763 9.66935 18.1573 6.5503C15.0382 3.43125 9.96264 3.43125 6.84359 6.5503L5.42938 5.13609C9.32836 1.2371 15.6725 1.2371 19.5715 5.13609C23.4705 9.03507 23.4705 15.3792 19.5715 19.2782C15.6725 23.1772 9.32836 23.1772 5.42938 19.2782L6.84359 17.864C9.96264 20.9831 15.0375 20.9838 18.1573 17.864ZM2.00035 11.5C2.00035 11.2239 2.2242 11 2.50035 11H5.00035L5.00035 10C5.00035 9.58798 5.47073 9.35279 5.80035 9.60001L9.00035 12C9.17125 12.1032 6.98685 13.637 5.77613 14.4703C5.44613 14.6975 5.00035 14.4601 5.00035 14.0595V13L2.50035 13C2.22421 13 2.00035 12.7761 2.00035 12.5L2.00035 11.5ZM9.67202 9.37873C11.2319 7.81885 13.7697 7.81956 15.3289 9.37873C16.888 10.9379 16.8887 13.4757 15.3289 15.0356C13.769 16.5955 11.2312 16.5948 9.67202 15.0356L8.2578 16.4498C10.5976 18.7896 14.4033 18.7896 16.7431 16.4498C19.0829 14.11 19.0829 10.3043 16.7431 7.96451C14.4033 5.6247 10.5976 5.6247 8.2578 7.96451L9.67202 9.37873Z" fill="#20A7C9"></path></svg>', + }, + { + name: 'Emit Principal Column Filter(s)', + disabled: + ensureIsArray(principalColumns).length === 0 || + Object.keys(principalColumnFilters).some(column => + principalColumnFilters[column].some((val: any) => val === null), + ) || + params.node === null, + action: () => handleChange(principalColumnFilters), + // eslint-disable-next-line theme-colors/no-literal-colors + icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" class=""><path fill-rule="evenodd" clip-rule="evenodd" d="M18.1573 17.864C21.2763 14.745 21.2763 9.66935 18.1573 6.5503C15.0382 3.43125 9.96264 3.43125 6.84359 6.5503L5.42938 5.13609C9.32836 1.2371 15.6725 1.2371 19.5715 5.13609C23.4705 9.03507 23.4705 15.3792 19.5715 19.2782C15.6725 23.1772 9.32836 23.1772 5.42938 19.2782L6.84359 17.864C9.96264 20.9831 15.0375 20.9838 18.1573 17.864ZM2.00035 11.5C2.00035 11.2239 2.2242 11 2.50035 11H5.00035L5.00035 10C5.00035 9.58798 5.47073 9.35279 5.80035 9.60001L9.00035 12C9.17125 12.1032 6.98685 13.637 5.77613 14.4703C5.44613 14.6975 5.00035 14.4601 5.00035 14.0595V13L2.50035 13C2.22421 13 2.00035 12.7761 2.00035 12.5L2.00035 11.5ZM9.67202 9.37873C11.2319 7.81885 13.7697 7.81956 15.3289 9.37873C16.888 10.9379 16.8887 13.4757 15.3289 15.0356C13.769 16.5955 11.2312 16.5948 9.67202 15.0356L8.2578 16.4498C10.5976 18.7896 14.4033 18.7896 16.7431 16.4498C19.0829 14.11 19.0829 10.3043 16.7431 7.96451C14.4033 5.6247 10.5976 5.6247 8.2578 7.96451L9.67202 9.37873Z" fill="#20A7C9"></path></svg>', + }, + { + name: 'Clear Emitted Filter(s)', + disabled: crossFilterValue === undefined, + action: () => dispatch(clearDataMask(formData.slice_id)), + icon: '<span class="ag-icon ag-icon-cross" unselectable="on" role="presentation"></span>', + }, + ]); + } + result = result.concat( + getJumpToDashboardContextMenuItems( + selectedDataByAdvancedType, + params.value === null, + ), + ); + result = result.concat(['separator', 'export']); + return result; }, [ @@ -262,12 +270,67 @@ export default function CccsGrid({ ], ); + const getMainMenuItems = useCallback(params => { + // If the column currently selected has either JSON data, or the + // expand all button for the row, add extra options + if ( + params.column.colDef.cellRenderer === 'jsonValueRenderer' || + params.column.colDef.cellRenderer === 'expandAllValueRenderer' + ) { + // Get the default menu items so we can add to them + const jsonMenuItems = params.defaultItems.slice(0); + + // Get all of the cell renderers and the current column ID + const instances = params.api.getCellRendererInstances(); + const columnID = params.column.colId; + + // Only keep cells which belong to the current column + const newInstances = instances.filter( + (instance: any) => instance.params.column.colId === columnID, + ); + + // Add an expand all button which will send an update to each cell renderer + jsonMenuItems.push({ + name: + params.column.colDef.cellRenderer === 'jsonValueRenderer' + ? 'Expand Column' + : 'Expand All', + action: () => { + newInstances.map((instance: any) => + instance.componentInstance.updateState(true), + ); + }, + }); + + // Add a collapse all button which will send an update to each cell renderer + jsonMenuItems.push({ + name: + params.column.colDef.cellRenderer === 'jsonValueRenderer' + ? 'Collapse Column' + : 'Collapse All', + action: () => { + newInstances.map((instance: any) => + instance.componentInstance.updateState(false), + ); + }, + }); + + // Return the default menu with added options (expand/collapse) + return jsonMenuItems; + } + + // If the column currently selected has neither JSON data, nor the + // expand all button for the row, use the regular menu + return params.defaultItems; + }, []); + const frameworkComponents = { countryValueRenderer: CountryValueRenderer, ipv4ValueRenderer: Ipv4ValueRenderer, ipv6ValueRenderer: Ipv6ValueRenderer, domainValueRenderer: DomainValueRenderer, jsonValueRenderer: JsonValueRenderer, + expandAllValueRenderer: ExpandAllValueRenderer, customTooltip: CustomTooltip, }; @@ -284,6 +347,21 @@ export default function CccsGrid({ } }; + const onFirstDataRendered = (params: any) => { + // Get all of the columns in the grid + const instances = params.columnApi.getAllColumns(); + + // Filter on columns that have JSON data + const newInstances = instances.filter( + (instance: any) => instance.colDef?.cellRenderer === 'jsonValueRenderer', + ); + + // Set the columns which have JSON data to be 350 pixels wide + newInstances.map((instance: any) => + params.columnApi.setColumnWidth(instance.colId, 350), + ); + }; + const onSelectionChanged = (params: any) => { const gridApi = params.api; const selectedRows = gridApi.getSelectedRows(); @@ -298,22 +376,24 @@ export default function CccsGrid({ const gridApi = params.api; const cellRanges = gridApi.getCellRanges(); - - const updatedSelectedData: {[key: string]: string[] } = {}; - const newSelectedbyAdvancedType: {[key: string]: string[] } = {}; - const updatedPrincipalColumnFilters = {}; + const updatedSelectedData: { [key: string]: string[] } = {}; + const newSelectedbyAdvancedType: { [key: string]: string[] } = {}; + const updatedPrincipalColumnFilters = {}; cellRanges.forEach((range: any) => { range.columns.forEach((column: any) => { const col = getEmitTarget(column.colDef?.field); - let advancedDataType = datasetColumns.find( (column) => { return column.column_name == col })?.advanced_data_type || "" - + let advancedDataType = + datasetColumns.find(column => { + return column.column_name == col; + })?.advanced_data_type || ''; updatedSelectedData[col] = updatedSelectedData[col] || []; - - newSelectedbyAdvancedType[advancedDataType] = newSelectedbyAdvancedType[advancedDataType] || [] - + + newSelectedbyAdvancedType[advancedDataType] = + newSelectedbyAdvancedType[advancedDataType] || []; + const startRow = Math.min( range.startRow.rowIndex, range.endRow.rowIndex, @@ -321,27 +401,35 @@ export default function CccsGrid({ const endRow = Math.max(range.startRow.rowIndex, range.endRow.rowIndex); for (let rowIndex = startRow; rowIndex <= endRow; rowIndex++) { + const rowNode = gridApi.getModel().getRow(rowIndex); + const value = gridApi.getValue(column, rowNode); + + const valueRendererName = column.colDef.cellRenderer; + let valueRendererObjt = null; + let renderedValue = null; - const rowNode = gridApi.getModel().getRow(rowIndex) - const value = gridApi.getValue( - column, - rowNode, - ); - - const valueRendererName = column.colDef.cellRenderer - let valueRendererObjt = null - let renderedValue = null - if (valueRendererName) { - const valueRenderer = valueRendererName ? frameworkComponents[valueRendererName] : undefined - valueRendererObjt = new valueRenderer({value, valueFormatted: null}) + const valueRenderer = valueRendererName + ? frameworkComponents[valueRendererName] + : undefined; + valueRendererObjt = new valueRenderer({ + value, + valueFormatted: null, + }); } - renderedValue = valueRendererObjt ? valueRendererObjt.render() : value + renderedValue = valueRendererObjt + ? valueRendererObjt.render() + : value; if (!updatedSelectedData[col].includes(value)) { updatedSelectedData[col].push(value); } - if (!newSelectedbyAdvancedType[advancedDataType].includes(renderedValue) && renderedValue) { + if ( + !newSelectedbyAdvancedType[advancedDataType].includes( + renderedValue, + ) && + renderedValue + ) { newSelectedbyAdvancedType[advancedDataType].push(renderedValue); } } @@ -479,7 +567,9 @@ export default function CccsGrid({ gridOptions={gridOptions} onGridColumnsChanged={autoSizeFirst100Columns} getContextMenuItems={getContextMenuItems} + getMainMenuItems={getMainMenuItems} onGridReady={onGridReady} + onFirstDataRendered={onFirstDataRendered} onRangeSelectionChanged={onRangeSelectionChanged} onSelectionChanged={onSelectionChanged} rowData={rowData} diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/ExpandAllValueRenderer.tsx b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/ExpandAllValueRenderer.tsx new file mode 100644 index 0000000000000..faf7265ea24fc --- /dev/null +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/ExpandAllValueRenderer.tsx @@ -0,0 +1,118 @@ +import { GroupCellRenderer } from '@ag-grid-enterprise/all-modules'; +import React, { Component } from 'react'; +import './Buttons.css'; + +// Show a button to collapse all of the JSON blobs in the row +function collapseJSON(this: any, reverseState: any) { + return ( + <button className="Row-Expand" type="button" onClick={reverseState}> + Collapse Row + </button> + ); +} + +// Show a button to expand all of the JSON blobs in the row +function expandJSON(this: any, reverseState: any) { + return ( + <> + <button className="Row-Expand" type="button" onClick={reverseState}> + Expand Row + </button> + </> + ); +} + +export default class ExpandAllValueRenderer extends Component< + {}, + { api: any; expanded: boolean; rowIndex: number } +> { + constructor(props: any) { + super(props); + + this.state = { + api: props.api, + expanded: false, + rowIndex: props.rowIndex, + }; + } + + // Get all of the cells in the AG Grid and only keep the ones that + // are in the same row as the current expand all button, and make + // sure that they have a JSON blob + getJSONCells = () => { + const instances = this.state.api.getCellRendererInstances(); + + // Make sure row grouping is not enabled, but if it is, don't + // try to find all of the JSON blobs in the row + if ( + instances.filter((instance: any) => instance instanceof GroupCellRenderer) + .length === 0 + ) { + const newInstances = instances.filter( + (instance: any) => + instance.params.rowIndex === this.state.rowIndex && + instance.params.column.colDef.cellRenderer === 'jsonValueRenderer', + ); + + return newInstances; + } + return []; + }; + + // Set the current `expanded` field to the opposite of what it currently is + // as well as go through each cell renderer and if it's in the same row & + // it's a cell with a JSON blob, update whether it is expanded or not + reverseState = () => { + this.setState(prevState => ({ + ...prevState, + expanded: !prevState.expanded, + })); + + const newInstances = this.getJSONCells(); + + newInstances.map((instance: any) => + instance.componentInstance.updateState(!this.state.expanded), + ); + }; + + // Set the current `expanded` field to be equal to the boolean being passed in + // as well as go through each cell renderer and if it's in the same row & + // it's a cell with a JSON blob, update whether it is expanded or not + updateState = (newFlag: any) => { + this.setState(prevState => ({ ...prevState, expanded: newFlag })); + + const newInstances = this.getJSONCells(); + + newInstances.map((instance: any) => + instance.componentInstance.updateState(newFlag), + ); + }; + + // Get all of the cells in the AG Grid and only keep the ones + // that are in the same row as the current expand all button and + // make sure that they have a JSON blob (and see whether they are + // expanded or not) + checkState = () => { + const newInstances = this.getJSONCells(); + + const jsonCellExpandedValues = newInstances.map((instance: any) => + instance.componentInstance.getExpandedValue(), + ); + + // If there is at least one cell that can expand, the expand all + // button for the row should show 'Expand' + this.setState(prevState => ({ + ...prevState, + expanded: !jsonCellExpandedValues.includes(false), + })); + }; + + // Show either the expand or collapse button dependent + // on the value of the `expanded` field + render() { + if (this.state.expanded === false) { + return expandJSON(this.reverseState); + } + return collapseJSON(this.reverseState); + } +} diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/JsonValueRenderer.tsx b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/JsonValueRenderer.tsx index 3eb8342010e98..c5f34ad72c7f7 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/JsonValueRenderer.tsx +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/JsonValueRenderer.tsx @@ -1,28 +1,8 @@ +import { GroupCellRenderer } from '@ag-grid-enterprise/all-modules'; import React, { Component } from 'react'; -import ModalTrigger from 'src/components/ModalTrigger'; -import JSONTree from 'react-json-tree'; -import Button from 'src/components/Button'; -import CopyToClipboard from 'src/components/CopyToClipboard'; +import { JSONTree } from 'react-json-tree'; -const JSON_TREE_THEME = { - scheme: 'monokai', - base00: '#272822', - base01: '#383830', - base02: '#49483e', - base03: '#75715e', - base04: '#a59f85', - base05: '#f8f8f2', - base06: '#f5f4f1', - base07: '#f9f8f5', - base08: '#f92672', - base09: '#fd971f', - base0A: '#f4bf75', - base0B: '#a6e22e', - base0C: '#a1efe4', - base0D: '#66d9ef', - base0E: '#ae81ff', - base0F: '#cc6633', -}; +import './Buttons.css'; function safeJsonObjectParse( data: unknown, @@ -48,34 +28,60 @@ function safeJsonObjectParse( } } -function addJsonModal( - node: React.ReactNode, - jsonObject: Record<string, unknown> | unknown[], - jsonString: String, -) { +// JSX which shows the JSON tree inline, and a button to collapse it +function collapseJSON(this: any, reverseState: any, jsonObject: any) { return ( - <ModalTrigger - modalBody={<JSONTree data={jsonObject} theme={JSON_TREE_THEME} />} - modalFooter={ - <Button> - <CopyToClipboard shouldShowText={false} text={jsonString} /> - </Button> - } - modalTitle="Cell content as JSON" - triggerNode={node} - /> + <> + <div style={{ float: 'left' }}> + <button + className="Button Collapse" + type="button" + title="Collapse" + onClick={reverseState} + > + {' '} + </button> + </div> + <div style={{ float: 'left' }}> + <JSONTree + data={jsonObject} + theme="default" + shouldExpandNode={() => true} + /> + </div> + </> + ); +} + +// JSX which shows the JSON data on one line, and a button to open the JSON tree +function expandJSON(this: any, reverseState: any, cellData: any) { + return ( + <> + <button + className="Button Expand" + type="button" + title="Expand" + onClick={reverseState} + > + {' '} + </button> + {cellData} + </> ); } export default class JsonValueRenderer extends Component< {}, - { cellValue: any } + { api: any; cellValue: any; expanded: boolean; rowIndex: number } > { constructor(props: any) { super(props); this.state = { + api: props.api, cellValue: JsonValueRenderer.getValueToDisplay(props), + expanded: false, + rowIndex: props.rowIndex, }; } @@ -86,14 +92,56 @@ export default class JsonValueRenderer extends Component< }; } + // Set the current `expanded` field to the opposite of what it currently is + // and trigger the 'checkState` function in the expand all button for the row + reverseState = () => { + this.setState( + prevState => ({ ...prevState, expanded: !prevState.expanded }), + () => { + const instances = this.state.api.getCellRendererInstances(); + + // Make sure row grouping is not enabled, but if it is, don't + // trigger the 'checkState` function in the expand all button for the row + if ( + instances.filter( + (instance: any) => instance instanceof GroupCellRenderer, + ).length === 0 + ) { + instances + .filter( + (instance: any) => + instance.params.rowIndex === this.state.rowIndex && + instance.params.column.colDef.cellRenderer === + 'expandAllValueRenderer', + ) + .map((instance: any) => instance.componentInstance.checkState()); + } + }, + ); + }; + + // Take the boolean value passed in and set the `expanded` field equal to it + updateState = (newFlag: any) => { + this.setState(prevState => ({ ...prevState, expanded: newFlag })); + }; + + // Return whether 'expanded' is set to true or false + getExpandedValue = () => this.state.expanded; + render() { const cellData = this.state.cellValue; const jsonObject = safeJsonObjectParse(this.state.cellValue); - const cellNode = <div>{cellData}</div>; + + // If there is a JSON object, either show it expanded or collapsed based + // on the value which the `expanded` field is set to if (jsonObject) { - return addJsonModal(cellNode, jsonObject, cellData); + if (this.state.expanded === false) { + return expandJSON(this.reverseState, cellData); + } + return collapseJSON(this.reverseState, jsonObject); } - return cellData ?? null; + // If the cellData is set to 'null' or undefined, return null + return cellData !== 'null' && cellData !== undefined ? cellData : null; } static getValueToDisplay(params: { valueFormatted: any; value: any }) { diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/components/controls/JumpActionConfigControll/JumpActionConfig.tsx b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/components/controls/JumpActionConfigControll/JumpActionConfig.tsx index 30221152c8e26..14c348152cf12 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/components/controls/JumpActionConfigControll/JumpActionConfig.tsx +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/components/controls/JumpActionConfigControll/JumpActionConfig.tsx @@ -1,202 +1,204 @@ -import React, { useState, useCallback, useEffect } from "react"; +import React, { useState, useCallback, useEffect } from 'react'; import SelectControl from 'src/explore/components/controls/SelectControl'; import { bootstrapData } from 'src/preamble'; import Button from 'src/components/Button'; import { - t, - SupersetClient, - validateNonEmpty, - withTheme, - SupersetTheme - } from '@superset-ui/core'; - - - + t, + SupersetClient, + validateNonEmpty, + withTheme, + SupersetTheme, +} from '@superset-ui/core'; interface Props { - dashboardID: number; - filters: any[]; - advancedDataType: string; - error: string; - visiblePopoverIndex: number; - close: () => void; - addDrillActionConfig: (drillactionConfig: any) => boolean; - removeDrillActionConfig: () => boolean + dashboardID: number; + filters: any[]; + advancedDataType: string; + error: string; + visiblePopoverIndex: number; + close: () => void; + addDrillActionConfig: (drillactionConfig: any) => boolean; + removeDrillActionConfig: () => boolean; } const useDashboardState = () => { - - const [dashboardList, setDashboardList] = useState([]); - - const [filterList, setFilterList] = useState([]); - - const fetchDashboardList = useCallback(() => { - const endpoint = `/api/v1/dashboard`; - SupersetClient.get({ endpoint }).then( - ({json}) => { - const dashboards = json.result.filter( (e: any) => { - return JSON.parse((e.json_metadata))?.native_filter_configuration - }) - .map( (e: any) => { - return {value: e.id, label: e.dashboard_title } - }) - setDashboardList(dashboards) - } - ).catch(error => {}); - }, []) - - const fetchFilterList = useCallback((dashboardId: number) => { - const endpoint = `/api/v1/dashboard/${dashboardId}`; - if(dashboardId < 0 ) - return - SupersetClient.get({ endpoint }).then( - ({json}) => { - const metadata = JSON.parse((json.result.json_metadata)) - - setFilterList(metadata?.native_filter_configuration.map( (e: any) => { - return {value: e.id, label: e.name, column: e?.targets[0].column?.name || "" } - })) - - } - ).catch(error => {}); - }, []) - - return { - dashboardList, - filterList, - fetchDashboardList, - fetchFilterList, - } -} - -const DrillActionConfig: React.FC<Props> = (props : Props) => { - const {dashboardID, filters, advancedDataType, visiblePopoverIndex } = props - - const {dashboardList, filterList, fetchDashboardList, fetchFilterList} = useDashboardState() - - const [selectedDashboardID, setSelectedDashboardID] = useState<number>(dashboardID) - - const [selectedFilters, setSelectedFilters] = useState(filters?.map( (filter: any) => filter.value) || []) - - - const [advancedDataTypeName, setAdvancedDataTypeName] = useState<string>(advancedDataType) - - const [state, setState] = useState({ - isNew: !props.dashboardID, - }) - - useEffect (()=> { - setSelectedFilters(filters?.map( (filter: any) => filter.value) || []) - setSelectedDashboardID(dashboardID) - setAdvancedDataTypeName(advancedDataType) - }, [dashboardID, filters, advancedDataType, visiblePopoverIndex] - - ) - useEffect(() => { - fetchDashboardList() - },[fetchDashboardList] ) - - useEffect(() => { - fetchFilterList(selectedDashboardID) - }, [fetchFilterList, selectedDashboardID]) - - - const isValidForm = () => { - const errors = [ - validateNonEmpty(selectedDashboardID), - validateNonEmpty(selectedFilters), - validateNonEmpty(advancedDataTypeName), - ]; - return !errors.filter(x => x).length; - } - const applyDrillActionConfig = () => { - - if (isValidForm()) { - const element: any = (dashboardList || []).find( - (e: any) => e.value === selectedDashboardID - ) - const advancedDataTypeNameLabel = bootstrapData?.common?.advanced_data_types.find( (e: { id: string; }) => e.id === advancedDataTypeName)?.verbose_name || advancedDataTypeName - const selectedFiltersWithColumn = filterList.filter( (filter: any) => selectedFilters.includes(filter.value) ) - const name = `${ element?.label } | ${ advancedDataTypeNameLabel }` - const newDrillActionConfig = { - dashboardID: selectedDashboardID, - filters: selectedFiltersWithColumn, - dashBoardName: element?.label || "", - advancedDataType: advancedDataTypeName, - name - } - props.addDrillActionConfig(newDrillActionConfig) - setState({...state, isNew: false}) - props.close() - } + const [dashboardList, setDashboardList] = useState([]); + + const [filterList, setFilterList] = useState([]); + + const fetchDashboardList = useCallback(() => { + const endpoint = `/api/v1/dashboard`; + SupersetClient.get({ endpoint }) + .then(({ json }) => { + const dashboards = json.result + .filter( + (e: any) => + JSON.parse(e.json_metadata)?.native_filter_configuration, + ) + .map((e: any) => ({ value: e.id, label: e.dashboard_title })); + setDashboardList(dashboards); + }) + .catch(error => {}); + }, []); + + const fetchFilterList = useCallback((dashboardId: number) => { + const endpoint = `/api/v1/dashboard/${dashboardId}`; + if (dashboardId < 0) return; + SupersetClient.get({ endpoint }) + .then(({ json }) => { + const metadata = JSON.parse(json.result.json_metadata); + + setFilterList( + metadata?.native_filter_configuration.map((e: any) => ({ + value: e.id, + label: e.name, + column: e?.targets[0].column?.name || '', + })), + ); + }) + .catch(error => {}); + }, []); + + return { + dashboardList, + filterList, + fetchDashboardList, + fetchFilterList, + }; +}; + +const DrillActionConfig: React.FC<Props> = (props: Props) => { + const { dashboardID, filters, advancedDataType, visiblePopoverIndex } = props; + + const { dashboardList, filterList, fetchDashboardList, fetchFilterList } = + useDashboardState(); + + const [selectedDashboardID, setSelectedDashboardID] = + useState<number>(dashboardID); + + const [selectedFilters, setSelectedFilters] = useState( + filters?.map((filter: any) => filter.value) || [], + ); + + const [advancedDataTypeName, setAdvancedDataTypeName] = + useState<string>(advancedDataType); + + const [state, setState] = useState({ + isNew: !props.dashboardID, + }); + + useEffect(() => { + setSelectedFilters(filters?.map((filter: any) => filter.value) || []); + setSelectedDashboardID(dashboardID); + setAdvancedDataTypeName(advancedDataType); + }, [dashboardID, filters, advancedDataType, visiblePopoverIndex]); + useEffect(() => { + fetchDashboardList(); + }, [fetchDashboardList]); + + useEffect(() => { + fetchFilterList(selectedDashboardID); + }, [fetchFilterList, selectedDashboardID]); + + const isValidForm = () => { + const errors = [ + validateNonEmpty(selectedDashboardID), + validateNonEmpty(selectedFilters), + validateNonEmpty(advancedDataTypeName), + ]; + return !errors.filter(x => x).length; + }; + const applyDrillActionConfig = () => { + if (isValidForm()) { + const element: any = (dashboardList || []).find( + (e: any) => e.value === selectedDashboardID, + ); + const advancedDataTypeNameLabel = + bootstrapData?.common?.advanced_data_types.find( + (e: { id: string }) => e.id === advancedDataTypeName, + )?.verbose_name || advancedDataTypeName; + const selectedFiltersWithColumn = filterList.filter((filter: any) => + selectedFilters.includes(filter.value), + ); + const name = `${element?.label} | ${advancedDataTypeNameLabel}`; + const newDrillActionConfig = { + dashboardID: selectedDashboardID, + filters: selectedFiltersWithColumn, + dashBoardName: element?.label || '', + advancedDataType: advancedDataTypeName, + name, + }; + props.addDrillActionConfig(newDrillActionConfig); + setState({ ...state, isNew: false }); + props.close(); } - - const onDashboardChange = (v: any) => { - setSelectedDashboardID(v) - setSelectedFilters([]) - } - return( - <div style={{ width: 400 }}> - <div style={{ width: '9000', paddingBottom: 25 }}> - <SelectControl - css={(theme: SupersetTheme) => ({ marginBottom: theme.gridUnit * 4 })} - ariaLabel={t('Annotation layer value')} - name="annotation-layer-value" - label={t('DashBoard')} - showHeader - hovered - placeholder="" - options={dashboardList} - value={selectedDashboardID} - onChange={onDashboardChange} - /> - <SelectControl - style = {{length: '100%'}} - ariaLabel={'Advanced Data Type'} - name="advanced-data-type-value" - label={'Advanced Data Type'} - showHeader - hovered - freeForm - placeholder="" - options={ bootstrapData?.common?.advanced_data_types.map( - ( v: { id: any; verbose_name: any; }) => ({ - value: v.id, - label: v.verbose_name, - }))} - value={advancedDataTypeName} - onChange={setAdvancedDataTypeName} - /> - <SelectControl - ariaLabel={t('Annotation layer value')} - name="annotation-layer-value" - label={t('Filters')} - showHeader - hovered - multi - placeholder="" - options={filterList} - value={selectedFilters} - onChange={setSelectedFilters} - /> - </div> - <div style={{ display: 'flex', justifyContent: 'space-between' }}> - <Button buttonSize="small" onClick={() => props.close()}> - {t('Cancel')} - </Button> - <div> - - <Button - buttonSize="small" - buttonStyle="primary" - disabled={!isValidForm()} - onClick={applyDrillActionConfig} - > - {t('OK')} - </Button> - </div> + }; + + const onDashboardChange = (v: any) => { + setSelectedDashboardID(v); + setSelectedFilters([]); + }; + return ( + <div style={{ width: 400 }}> + <div style={{ width: '9000', paddingBottom: 25 }}> + <SelectControl + css={(theme: SupersetTheme) => ({ marginBottom: theme.gridUnit * 4 })} + ariaLabel={t('Annotation layer value')} + name="annotation-layer-value" + label={t('DashBoard')} + showHeader + hovered + placeholder="" + options={dashboardList} + value={selectedDashboardID} + onChange={onDashboardChange} + /> + <SelectControl + style={{ length: '100%' }} + ariaLabel="Advanced Data Type" + name="advanced-data-type-value" + label="Advanced Data Type" + showHeader + hovered + freeForm + placeholder="" + options={bootstrapData?.common?.advanced_data_types.map( + (v: { id: any; verbose_name: any }) => ({ + value: v.id, + label: v.verbose_name, + }), + )} + value={advancedDataTypeName} + onChange={setAdvancedDataTypeName} + /> + <SelectControl + ariaLabel={t('Annotation layer value')} + name="annotation-layer-value" + label={t('Filters')} + showHeader + hovered + multi + placeholder="" + options={filterList} + value={selectedFilters} + onChange={setSelectedFilters} + /> + </div> + <div style={{ display: 'flex', justifyContent: 'space-between' }}> + <Button buttonSize="small" onClick={() => props.close()}> + {t('Cancel')} + </Button> + <div> + <Button + buttonSize="small" + buttonStyle="primary" + disabled={!isValidForm()} + onClick={applyDrillActionConfig} + > + {t('OK')} + </Button> </div> - </div> - ); - -} -export default withTheme(DrillActionConfig); \ No newline at end of file + </div> + </div> + ); +}; +export default withTheme(DrillActionConfig); diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/components/controls/JumpActionConfigControll/index.tsx b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/components/controls/JumpActionConfigControll/index.tsx index 018c354bf46ff..3cd912603080d 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/components/controls/JumpActionConfigControll/index.tsx +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/components/controls/JumpActionConfigControll/index.tsx @@ -22,27 +22,27 @@ import CustomListItem from 'src/explore/components/controls/CustomListItem'; import { t, withTheme } from '@superset-ui/core'; import AsyncEsmComponent from 'src/components/AsyncEsmComponent'; import { List } from 'src/components'; -import ControlPopover from 'src/explore/components/controls/ControlPopover/ControlPopover' +import ControlPopover from 'src/explore/components/controls/ControlPopover/ControlPopover'; import { connect } from 'react-redux'; import { HeaderContainer, LabelsContainer, -} from 'src/explore/components/controls/OptionControls' +} from 'src/explore/components/controls/OptionControls'; import ControlHeader from 'src/explore/components/ControlHeader'; export interface Props { - colorScheme: string; - annotationError: object; - annotationQuery: object; - vizType: string; - theme: any; - validationErrors: string[]; - name: string; - actions: object; - label: string; - value?: object[]; - onChange: (a: any) => void, -}; + colorScheme: string; + annotationError: object; + annotationQuery: object; + vizType: string; + theme: any; + validationErrors: string[]; + name: string; + actions: object; + label: string; + value?: object[]; + onChange: (a: any) => void; +} const DrillActionConfig = AsyncEsmComponent( () => import('./JumpActionConfig'), @@ -50,143 +50,147 @@ const DrillActionConfig = AsyncEsmComponent( () => <div style={{ width: 450, height: 368 }} />, ); - - const DrillActionConfigControl: React.FC<Props> = ( - { - colorScheme, - annotationError, - annotationQuery, - vizType, - theme, - validationErrors, - name, - actions, - onChange, - value = [], - ...props - } - ) => - { - // Need to bind function - // Need to preload - const [state, setState] = useState({ - handleVisibleChange: {}, - addedDrillActionConfigIndex: -1, - }); - - const [visiblePopoverIndex, setVisiblePopoverindex] = useState<string | number>(-1) - - const addDrillActionConfig = (originalDrillActionConfig: any, newDrillActionConfig: any) => - { - let drillActionConfigs = value; - if (drillActionConfigs.includes(originalDrillActionConfig)) { - drillActionConfigs = drillActionConfigs.map(anno => - anno === originalDrillActionConfig ? newDrillActionConfig : anno, - ); - } else { - drillActionConfigs = [...drillActionConfigs, newDrillActionConfig]; - setState({...state, addedDrillActionConfigIndex: drillActionConfigs.length - 1 }); - } - onChange(drillActionConfigs); - } - - - const handleVisibleChange = (visible: any, popoverKey: string | number) => { - setVisiblePopoverindex(visible ? popoverKey: -1) - } - - const removeDrillActionConfig = (drillActionConfig: any) => { - const annotations = value.filter(anno => anno !== drillActionConfig); - onChange(annotations); - } - const renderPopover = (popoverKey: string | number, drillActionConfig: any, error: string = "") => { - const id = drillActionConfig?.name || '_new'; - - return ( - <div id={`annotation-pop-${id}`} data-test="popover-content"> - <DrillActionConfig - {...drillActionConfig} - error={error} - visiblePopoverIndex={visiblePopoverIndex} - addDrillActionConfig={(newAnnotation: any) => - addDrillActionConfig(drillActionConfig, newAnnotation) - } - removeDrillActionConfig={() => removeDrillActionConfig(drillActionConfig)} - close={() => { - handleVisibleChange(false, popoverKey); - setState({...state, addedDrillActionConfigIndex: -1 }); - }} - visi - /> - </div> +const DrillActionConfigControl: React.FC<Props> = ({ + colorScheme, + annotationError, + annotationQuery, + vizType, + theme, + validationErrors, + name, + actions, + onChange, + value = [], + ...props +}) => { + // Need to bind function + // Need to preload + const [state, setState] = useState({ + handleVisibleChange: {}, + addedDrillActionConfigIndex: -1, + }); + + const [visiblePopoverIndex, setVisiblePopoverindex] = useState< + string | number + >(-1); + + const addDrillActionConfig = ( + originalDrillActionConfig: any, + newDrillActionConfig: any, + ) => { + let drillActionConfigs = value; + if (drillActionConfigs.includes(originalDrillActionConfig)) { + drillActionConfigs = drillActionConfigs.map(anno => + anno === originalDrillActionConfig ? newDrillActionConfig : anno, ); + } else { + drillActionConfigs = [...drillActionConfigs, newDrillActionConfig]; + setState({ + ...state, + addedDrillActionConfigIndex: drillActionConfigs.length - 1, + }); } + onChange(drillActionConfigs); + }; - const { addedDrillActionConfigIndex } = state; - const addedDrillActionConfig = value[addedDrillActionConfigIndex]; + const handleVisibleChange = (visible: any, popoverKey: string | number) => { + setVisiblePopoverindex(visible ? popoverKey : -1); + }; - const drillactionConfigs = value.map((anno: any, i) => ( - <ControlPopover - key={i} - trigger="click" - title={t('Edit Jump Action')} - css={theme => ({ - '&:hover': { - cursor: 'pointer', - backgroundColor: theme.colors.grayscale.light4, - }, - })} - content={renderPopover( - i, - anno, - )} - visible={visiblePopoverIndex === i} - onVisibleChange={visible => handleVisibleChange(visible, i)} - > - <CustomListItem selectable style={{fontSize: 12}}> - <i - onClick={() => removeDrillActionConfig(anno)} - data-test="add-annotation-layer-button" - className="fa fa-times" - />{' '} -   {anno.name} - </CustomListItem> - </ControlPopover> - )); + const removeDrillActionConfig = (drillActionConfig: any) => { + const annotations = value.filter(anno => anno !== drillActionConfig); + onChange(annotations); + }; + const renderPopover = ( + popoverKey: string | number, + drillActionConfig: any, + error: string = '', + ) => { + const id = drillActionConfig?.name || '_new'; - const addLayerPopoverKey = 'add'; return ( - <> - <HeaderContainer> - <ControlHeader {...props} /> - </HeaderContainer> - <LabelsContainer> - <List bordered css={theme => ({ borderRadius: theme.gridUnit })}> - {drillactionConfigs} - <ControlPopover - trigger="click" - content={renderPopover(addLayerPopoverKey, addedDrillActionConfig)} - title={t('Add Jump Action')} - visible={visiblePopoverIndex === addLayerPopoverKey} - destroyTooltipOnHide - onVisibleChange={visible => - handleVisibleChange(visible, addLayerPopoverKey) - } - > - <CustomListItem selectable style={{fontSize: 12}}> - <i - data-test="add-annotation-layer-button" - className="fa fa-plus" - />{' '} -   {t('Add Jump Action')} - </CustomListItem> - </ControlPopover> - </List> - </LabelsContainer> - </> + <div id={`annotation-pop-${id}`} data-test="popover-content"> + <DrillActionConfig + {...drillActionConfig} + error={error} + visiblePopoverIndex={visiblePopoverIndex} + addDrillActionConfig={(newAnnotation: any) => + addDrillActionConfig(drillActionConfig, newAnnotation) + } + removeDrillActionConfig={() => + removeDrillActionConfig(drillActionConfig) + } + close={() => { + handleVisibleChange(false, popoverKey); + setState({ ...state, addedDrillActionConfigIndex: -1 }); + }} + visi + /> + </div> ); - } + }; + const { addedDrillActionConfigIndex } = state; + const addedDrillActionConfig = value[addedDrillActionConfigIndex]; + + const drillactionConfigs = value.map((anno: any, i) => ( + <ControlPopover + key={i} + trigger="click" + title={t('Edit Jump Action')} + css={theme => ({ + '&:hover': { + cursor: 'pointer', + backgroundColor: theme.colors.grayscale.light4, + }, + })} + content={renderPopover(i, anno)} + visible={visiblePopoverIndex === i} + onVisibleChange={visible => handleVisibleChange(visible, i)} + > + <CustomListItem selectable style={{ fontSize: 12 }}> + <i + onClick={() => removeDrillActionConfig(anno)} + data-test="add-annotation-layer-button" + className="fa fa-times" + />{' '} +   {anno.name} + </CustomListItem> + </ControlPopover> + )); + + const addLayerPopoverKey = 'add'; + return ( + <> + <HeaderContainer> + <ControlHeader {...props} /> + </HeaderContainer> + <LabelsContainer> + <List bordered css={theme => ({ borderRadius: theme.gridUnit })}> + {drillactionConfigs} + <ControlPopover + trigger="click" + content={renderPopover(addLayerPopoverKey, addedDrillActionConfig)} + title={t('Add Jump Action')} + visible={visiblePopoverIndex === addLayerPopoverKey} + destroyTooltipOnHide + onVisibleChange={visible => + handleVisibleChange(visible, addLayerPopoverKey) + } + > + <CustomListItem selectable style={{ fontSize: 12 }}> + <i + data-test="add-annotation-layer-button" + className="fa fa-plus" + />{' '} +   {t('Add Jump Action')} + </CustomListItem> + </ControlPopover> + </List> + </LabelsContainer> + </> + ); +}; // Tried to hook this up through stores/control.jsx instead of using redux // directly, could not figure out how to get access to the color_scheme @@ -198,10 +202,6 @@ function mapStateToProps({ charts, explore }: any) { }; } - - const themedDrillActionConfigControl = withTheme(DrillActionConfigControl); -export default connect( - mapStateToProps, -)(themedDrillActionConfigControl); +export default connect(mapStateToProps)(themedDrillActionConfigControl); diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/plugin/controlPanel.tsx b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/plugin/controlPanel.tsx index d69a73c510610..991a7ca8f4b56 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/plugin/controlPanel.tsx +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/plugin/controlPanel.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react' +import React from 'react'; import { t, @@ -48,7 +48,6 @@ import { StyledColumnOption } from 'src/explore/components/optionRenderers'; import DrillActionConfig from '../components/controls/JumpActionConfigControll'; - export const PAGE_SIZE_OPTIONS = formatSelectOptions<number>([ [0, t('page_size.all')], 10, @@ -104,7 +103,6 @@ const validateAggControlValues = ( : []; }; - // function isIP(v: unknown) { // if (typeof v === 'string' && v.trim().length > 0) { // //console.log(v.trim()); @@ -229,7 +227,7 @@ const config: ControlPanelConfig = { return newState; }, - rerender: ['metrics', 'percent_metrics', ], + rerender: ['metrics', 'percent_metrics', 'default_group_by'], }, }, ], @@ -329,10 +327,10 @@ const config: ControlPanelConfig = { : []; return newState; }, - rerender: ['principalColumns'], + rerender: ['principalColumns', 'default_group_by'], visibility: isRawMode, canCopy: true, - } + }, }, ], [ @@ -422,9 +420,9 @@ const config: ControlPanelConfig = { controlState: ControlState, ) => { const { controls } = state; - const originalMapStateToProps = isRawMode({ controls }) ? - sharedControls?.columns?.mapStateToProps : - sharedControls?.groupby?.mapStateToProps; + const originalMapStateToProps = isRawMode({ controls }) + ? sharedControls?.columns?.mapStateToProps + : sharedControls?.groupby?.mapStateToProps; const newState = originalMapStateToProps?.(state, controlState) ?? {}; const choices = isRawMode({ controls }) @@ -454,7 +452,6 @@ const config: ControlPanelConfig = { return newState; }, visibility: ({ controls }) => - // TODO properly emsure is Bool Boolean(controls?.emitFilter?.value), canCopy: true, }, @@ -590,8 +587,73 @@ config.controlPanelSections.push({ renderTrigger: true, default: false, description: t( - 'Whether to enable row grouping (this will only take affect after a save)', + 'Whether to enable row grouping (this will only take affect after a save). NOTE: "JSON Row Expand" and "Row Grouping" are mutually exclusive. If "Row Grouping" is selected, "JSON Row Expand" will not be visible.', + ), + visibility: ({ controls }) => + Boolean(!controls?.enable_json_expand?.value), + }, + }, + ], + [ + { + name: 'default_group_by', + config: { + type: 'SelectControl', + label: t('Default columns for row grouping'), + description: t( + 'Preselect a set of columns for row grouping in the grid.', + ), + multi: true, + freeForm: true, + allowAll: true, + default: [], + canSelectAll: true, + renderTrigger: true, + optionRenderer: (c: ColumnMeta) => ( + // eslint-disable-next-line react/react-in-jsx-scope + <StyledColumnOption showType column={c} /> + ), + // eslint-disable-next-line react/react-in-jsx-scope + valueRenderer: (c: ColumnMeta) => ( + // eslint-disable-next-line react/react-in-jsx-scope + <StyledColumnOption column={c} /> ), + valueKey: 'column_name', + mapStateToProps: ( + state: ControlPanelState, + controlState: ControlState, + ) => { + const { controls } = state; + const originalMapStateToProps = isRawMode({ controls }) + ? sharedControls?.columns?.mapStateToProps + : sharedControls?.groupby?.mapStateToProps; + const newState = + originalMapStateToProps?.(state, controlState) ?? {}; + const choices = isRawMode({ controls }) + ? controls?.columns?.value + : controls?.groupby?.value; + newState.options = newState.options.filter( + (o: { column_name: string }) => + ensureIsArray(choices).includes(o.column_name), + ); + const invalidOptions = ensureIsArray(controlState.value).filter( + c => !ensureIsArray(choices).includes(c), + ); + newState.externalValidationErrors = + invalidOptions.length > 0 + ? invalidOptions.length > 1 + ? [ + `'${invalidOptions.join(', ')}'${t( + ' are not valid options', + )}`, + ] + : [`'${invalidOptions}'${t(' is not a valid option')}`] + : []; + return newState; + }, + visibility: ({ controls }) => + Boolean(controls?.enable_grouping?.value), + canCopy: true, }, }, ], @@ -607,6 +669,22 @@ config.controlPanelSections.push({ }, }, ], + [ + { + name: 'enable_json_expand', + config: { + type: 'CheckboxControl', + label: t('JSON Row Expand'), + renderTrigger: true, + default: false, + description: t( + 'Whether to enable row level JSON expand buttons. NOTE: "JSON Row Expand" and "Row Grouping" are mutually exclusive. If "JSON Row Expand" is selected, "Row Grouping" will not be visible.', + ), + visibility: ({ controls }) => + Boolean(!controls?.enable_grouping?.value), + }, + }, + ], [ { name: 'page_length', diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/plugin/transformProps.ts index f6362c356d789..04e3faa2e0e28 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/plugin/transformProps.ts +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/plugin/transformProps.ts @@ -83,7 +83,9 @@ export default function transformProps(chartProps: CccsGridChartProps) { enable_grouping, column_state, enable_row_numbers, + enable_json_expand, jump_action_configs, + default_group_by, }: CccsGridQueryFormData = { ...DEFAULT_FORM_DATA, ...formData }; const data = queriesData[0].data as TimeseriesDataRecord[]; const agGridLicenseKey = queriesData[0].agGridLicenseKey as String; @@ -232,6 +234,12 @@ export default function transformProps(chartProps: CccsGridChartProps) { const isSortable = true; const enableRowGroup = true; const columnDescription = columnDescriptionMap[column]; + const autoHeight = true; + const rowGroupIndex = default_group_by.findIndex((element: any) => { + return element === column; + }); + const rowGroup = rowGroupIndex >= 0; + const hide = rowGroup; return { field: column, headerName: columnHeader, @@ -240,8 +248,12 @@ export default function transformProps(chartProps: CccsGridChartProps) { sort: sortDirection, sortIndex, enableRowGroup, + rowGroup, + hide, + rowGroupIndex, getQuickFilterText: (params: any) => valueFormatter(params), headerTooltip: columnDescription, + autoHeight, }; }); } else { @@ -261,14 +273,26 @@ export default function transformProps(chartProps: CccsGridChartProps) { const isSortable = true; const enableRowGroup = true; const columnDescription = columnDescriptionMap[column]; + const autoHeight = true; + const rowGroupIndex = default_group_by.findIndex( + (element: any) => element === column, + ); + const initialRowGroupIndex = rowGroupIndex; + const rowGroup = rowGroupIndex >= 0; + const hide = rowGroup; return { field: column, headerName: columnHeader, cellRenderer, sortable: isSortable, enableRowGroup, + rowGroup, + rowGroupIndex, + initialRowGroupIndex, + hide, getQuickFilterText: (params: any) => valueFormatter(params), headerTooltip: columnDescription, + autoHeight, }; }); columnDefs = columnDefs.concat(groupByColumnDefs); @@ -314,29 +338,45 @@ export default function transformProps(chartProps: CccsGridChartProps) { headerName: '#', colId: 'rowNum', pinned: 'left', + lockVisible: true, valueGetter: (params: any) => params.node ? params.node.rowIndex + 1 : null, } as any); } - let parsed_jump_action_configs = {} - jump_action_configs?.forEach( (e: any) => - { + const parsed_jump_action_configs = {}; + jump_action_configs?.forEach((e: any) => { if (e.dashboardID in parsed_jump_action_configs) { - parsed_jump_action_configs[e.dashboardID] = parsed_jump_action_configs[e.dashboardID].concat({ + parsed_jump_action_configs[e.dashboardID] = parsed_jump_action_configs[ + e.dashboardID + ].concat({ advancedDataType: e.advancedDataType, nativefilters: e.filters, - name: e.dashBoardName - }) - } - else { - parsed_jump_action_configs[e.dashboardID] = [{ - advancedDataType: e.advancedDataType, - nativefilters: e.filters, - name: e.dashBoardName - }] + name: e.dashBoardName, + }); + } else { + parsed_jump_action_configs[e.dashboardID] = [ + { + advancedDataType: e.advancedDataType, + nativefilters: e.filters, + name: e.dashBoardName, + }, + ]; } }); + // If the flag is set to true, add a column which will contain + // a button to expand all JSON blobs in the row + if (enable_json_expand) { + columnDefs.splice(1, 0, { + colId: 'jsonExpand', + pinned: 'left', + cellRenderer: 'expandAllValueRenderer', + autoHeight: true, + minWidth: 105, + lockVisible: true, + } as any); + } + return { formData, setDataMask, @@ -357,6 +397,6 @@ export default function transformProps(chartProps: CccsGridChartProps) { column_state, agGridLicenseKey, datasetColumns: columns, - jumpActionConfigs: parsed_jump_action_configs + jumpActionConfigs: parsed_jump_action_configs, }; } diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/types.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/types.ts index a4754380c79df..4dc11b0fd7fe7 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/types.ts +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/types.ts @@ -88,7 +88,7 @@ export interface CccsGridTransformedProps extends CccsGridStylesProps { // add typing here for the props you pass in from transformProps.ts! agGridLicenseKey: string; datasetColumns: Column[]; - jumpActionConfigs?: any[] + jumpActionConfigs?: any[]; } export type EventHandlers = Record<string, { (props: any): void }>; diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx index fa1cec2d74420..9fb1f9c05a143 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx @@ -1,17 +1,35 @@ import React from 'react'; import { IFrameVisualizationProps } from './types'; - export default function IFrameVisualization(props: IFrameVisualizationProps) { - const { url, url_parameter_value, parameter_name, parameter_prefix, errorMessage} = props - - const parserdUrlParameterName = parameter_name.includes('=') ? parameter_name : `${parameter_name}=${parameter_prefix}` + const { + url, + url_parameter_value, + parameter_name, + parameter_prefix, + errorMessage, + } = props; + + const parserdUrlParameterName = parameter_name.includes('=') + ? parameter_name + : `${parameter_name}=${parameter_prefix}`; return ( <> - { errorMessage ? - <>{errorMessage}</> : - <iframe src={`${url}?${parserdUrlParameterName}${url_parameter_value}`} style={{ position: 'absolute', left:0, top: '50px', width:'95%', height:'100%' }}></iframe> } + {errorMessage ? ( + <>{errorMessage}</> + ) : ( + <iframe + src={`${url}?${parserdUrlParameterName}${url_parameter_value}`} + style={{ + position: 'absolute', + left: 0, + top: '50px', + width: '95%', + height: '100%', + }} + ></iframe> + )} </> ); } diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts index 22405e6d1202f..245655da2c1c8 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts @@ -16,42 +16,41 @@ * specific language governing permissions and limitations * under the License. */ - import { buildQueryContext, QueryFormData } from '@superset-ui/core'; +import { buildQueryContext, QueryFormData } from '@superset-ui/core'; - /** - * The buildQuery function is used to create an instance of QueryContext that's - * sent to the chart data endpoint. In addition to containing information of which - * datasource to use, it specifies the type (e.g. full payload, samples, query) and - * format (e.g. CSV or JSON) of the result and whether or not to force refresh the data from - * the datasource as opposed to using a cached copy of the data, if available. - * - * More importantly though, QueryContext contains a property `queries`, which is an array of - * QueryObjects specifying individual data requests to be made. A QueryObject specifies which - * columns, metrics and filters, among others, to use during the query. Usually it will be enough - * to specify just one query based on the baseQueryObject, but for some more advanced use cases - * it is possible to define post processing operations in the QueryObject, or multiple queries - * if a viz needs multiple different result sets. - */ - export default function buildQuery(formData: QueryFormData) { - /* +/** + * The buildQuery function is used to create an instance of QueryContext that's + * sent to the chart data endpoint. In addition to containing information of which + * datasource to use, it specifies the type (e.g. full payload, samples, query) and + * format (e.g. CSV or JSON) of the result and whether or not to force refresh the data from + * the datasource as opposed to using a cached copy of the data, if available. + * + * More importantly though, QueryContext contains a property `queries`, which is an array of + * QueryObjects specifying individual data requests to be made. A QueryObject specifies which + * columns, metrics and filters, among others, to use during the query. Usually it will be enough + * to specify just one query based on the baseQueryObject, but for some more advanced use cases + * it is possible to define post processing operations in the QueryObject, or multiple queries + * if a viz needs multiple different result sets. + */ +export default function buildQuery(formData: QueryFormData) { + /* We receive an ip as a filter, our job is to find everthing there is to know about that ip We fire multiple queries to multiple data sets and collect the results here. */ - - const formDataCopy = { - ...formData, - result_type: 'post_processed', - }; - - return buildQueryContext(formDataCopy, baseQueryObject => { - // RAW mode (not aggregated) - // eslint-disable-next-line no-param-reassign - return [ - { - ...baseQueryObject, - row_limit: 10, - }, - ]; - }); - } - \ No newline at end of file + + const formDataCopy = { + ...formData, + result_type: 'post_processed', + }; + + return buildQueryContext(formDataCopy, baseQueryObject => { + // RAW mode (not aggregated) + // eslint-disable-next-line no-param-reassign + return [ + { + ...baseQueryObject, + row_limit: 10, + }, + ]; + }); +} diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts index 5c7a9df66fbce..3b35503b6e303 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts @@ -25,7 +25,6 @@ import { } from '@superset-ui/chart-controls'; const config: ControlPanelConfig = { - /** * The control panel is split into two tabs: "Query" and * "Chart Options". The controls that define the inputs to @@ -99,7 +98,7 @@ const config: ControlPanelConfig = { * - validateInteger: must be an integer value * - validateNumber: must be an intger or decimal value */ - + // For control input types, see: superset-frontend/src/explore/components/controls/index.js controlPanelSections: [ { @@ -121,7 +120,9 @@ const config: ControlPanelConfig = { sharedControls?.groupby?.mapStateToProps; const newState = originalMapStateToProps?.(state, controlState) ?? {}; - newState.externalValidationErrors = controlState.value ? [] : ["Please add a value for URL."] + newState.externalValidationErrors = controlState.value + ? [] + : ['Please add a value for URL.']; return newState; }, renderTrigger: true, @@ -135,7 +136,8 @@ const config: ControlPanelConfig = { name: 'groupby', override: { label: t('Parameter Column Name'), - description: "The name of the column that will populate the url parameter value.", + description: + 'The name of the column that will populate the url parameter value.', multi: false, allowAll: false, default: [], @@ -148,7 +150,10 @@ const config: ControlPanelConfig = { sharedControls?.groupby?.mapStateToProps; const newState = originalMapStateToProps?.(state, controlState) ?? {}; - newState.externalValidationErrors = ensureIsArray(controlState.value).length > 0 ? [] : ["Please add a value for Parameter Column Name."] + newState.externalValidationErrors = + ensureIsArray(controlState.value).length > 0 + ? [] + : ['Please add a value for Parameter Column Name.']; return newState; }, }, @@ -168,7 +173,9 @@ const config: ControlPanelConfig = { sharedControls?.groupby?.mapStateToProps; const newState = originalMapStateToProps?.(state, controlState) ?? {}; - newState.externalValidationErrors = controlState.value ? [] : ["Please add a value for Parameter Name."] + newState.externalValidationErrors = controlState.value + ? [] + : ['Please add a value for Parameter Name.']; return newState; }, default: '', @@ -183,10 +190,12 @@ const config: ControlPanelConfig = { type: 'TextControl', label: t('Parameter Prefix'), default: '', - description: t('A value that will be prefix the parameter value.'), + description: t( + 'A value that will be prefix the parameter value.', + ), }, }, - ] + ], ], }, ], diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts index ee67ef9d2aff7..08a54a5b0f61b 100644 --- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts +++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { ChartProps, TimeseriesDataRecord, } from '@superset-ui/core'; +import { ChartProps, TimeseriesDataRecord } from '@superset-ui/core'; export default function transformProps(chartProps: ChartProps) { /** @@ -51,25 +51,26 @@ export default function transformProps(chartProps: ChartProps) { const formData = chartProps.formData; const queriesData = chartProps.queriesData; - const { url, parameterName, parameterPrefix, groupby } = formData + const { url, parameterName, parameterPrefix, groupby } = formData; const data = queriesData[0]?.data as TimeseriesDataRecord[]; - let value: string | number | true | Date = "" - let errorMessage = ""; + let value: string | number | true | Date = ''; + let errorMessage = ''; - if(Array.isArray(data) && data.length > 1) { - errorMessage = "The query returned too many rows when only one was expected." + if (Array.isArray(data) && data.length > 1) { + errorMessage = + 'The query returned too many rows when only one was expected.'; } - - if(Array.isArray(data) && data.length === 0) { - errorMessage = "The query returned no rows." + + if (Array.isArray(data) && data.length === 0) { + errorMessage = 'The query returned no rows.'; } - if(Array.isArray(data) && data.length === 1) { - value = data[0][groupby] || "" + if (Array.isArray(data) && data.length === 1) { + value = data[0][groupby] || ''; } - + return { url_parameter_value: value, parameter_name: parameterName, diff --git a/superset-frontend/src/components/Alert/Alert.test.tsx b/superset-frontend/src/components/Alert/Alert.test.tsx index 8a59469180d19..9d921d0301479 100644 --- a/superset-frontend/src/components/Alert/Alert.test.tsx +++ b/superset-frontend/src/components/Alert/Alert.test.tsx @@ -64,13 +64,14 @@ test('renders without icon', async () => { }); }); -test('renders message', () => { +test('renders message', async () => { render(<Alert message="Message" />); - expect(screen.getByRole('alert')).toHaveTextContent('Message'); + expect(await screen.findByRole('alert')).toHaveTextContent('Message'); }); -test('renders message and description', () => { +test('renders message and description', async () => { render(<Alert message="Message" description="Description" />); - expect(screen.getByRole('alert')).toHaveTextContent('Message'); - expect(screen.getByRole('alert')).toHaveTextContent('Description'); + const alert = await screen.findByRole('alert'); + expect(alert).toHaveTextContent('Message'); + expect(alert).toHaveTextContent('Description'); }); diff --git a/superset-frontend/src/components/AlteredSliceTag/index.jsx b/superset-frontend/src/components/AlteredSliceTag/index.jsx index dd5dfb3c87868..5c9b04949bb84 100644 --- a/superset-frontend/src/components/AlteredSliceTag/index.jsx +++ b/superset-frontend/src/components/AlteredSliceTag/index.jsx @@ -171,15 +171,15 @@ export default class AlteredSliceTag extends React.Component { const columns = [ { accessor: 'control', - Header: 'Control', + Header: t('Control'), }, { accessor: 'before', - Header: 'Before', + Header: t('Before'), }, { accessor: 'after', - Header: 'After', + Header: t('After'), }, ]; // set the wrap text in the specific columns. diff --git a/superset-frontend/src/components/AsyncSelect/AsyncSelect.test.jsx b/superset-frontend/src/components/AsyncSelect/AsyncSelect.test.jsx index 0f11fe2709b8f..f3bce12713308 100644 --- a/superset-frontend/src/components/AsyncSelect/AsyncSelect.test.jsx +++ b/superset-frontend/src/components/AsyncSelect/AsyncSelect.test.jsx @@ -19,7 +19,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import fetchMock from 'fetch-mock'; -import Select from 'src/components/Select'; +import Select from 'src/components/DeprecatedSelect'; import AsyncSelect from 'src/components/AsyncSelect'; describe('AsyncSelect', () => { diff --git a/superset-frontend/src/components/AsyncSelect/index.jsx b/superset-frontend/src/components/AsyncSelect/index.jsx index 1f2fb66e53b06..69799eadeae46 100644 --- a/superset-frontend/src/components/AsyncSelect/index.jsx +++ b/superset-frontend/src/components/AsyncSelect/index.jsx @@ -19,7 +19,7 @@ import React from 'react'; import PropTypes from 'prop-types'; // TODO: refactor this with `import { AsyncSelect } from src/components/Select` -import { Select } from 'src/components/Select'; +import { Select } from 'src/components/DeprecatedSelect'; import { t, SupersetClient } from '@superset-ui/core'; import { getClientErrorObject } from '../../utils/getClientErrorObject'; diff --git a/superset-frontend/src/components/Badge/index.tsx b/superset-frontend/src/components/Badge/index.tsx index f33d9808e4db4..01c03f3fcf8f2 100644 --- a/superset-frontend/src/components/Badge/index.tsx +++ b/superset-frontend/src/components/Badge/index.tsx @@ -28,8 +28,8 @@ export interface BadgeProps extends AntdBadgeProps { const Badge = styled( ( // eslint-disable-next-line @typescript-eslint/no-unused-vars - { textColor, ...props }: BadgeProps, - ) => <AntdBadge {...props} />, + { textColor, color, text, ...props }: BadgeProps, + ) => <AntdBadge text={text} color={text ? color : undefined} {...props} />, )` & > sup { padding: 0 ${({ theme }) => theme.gridUnit * 2}px; diff --git a/superset-frontend/src/components/Button/index.tsx b/superset-frontend/src/components/Button/index.tsx index b8e428d6ca3a6..05a1a3ad79881 100644 --- a/superset-frontend/src/components/Button/index.tsx +++ b/superset-frontend/src/components/Button/index.tsx @@ -16,13 +16,15 @@ * specific language governing permissions and limitations * under the License. */ -import React, { CSSProperties, Children, ReactElement } from 'react'; +import React, { Children, ReactElement } from 'react'; import { kebabCase } from 'lodash'; import { mix } from 'polished'; import cx from 'classnames'; import { AntdButton } from 'src/components'; import { useTheme } from '@superset-ui/core'; import { Tooltip } from 'src/components/Tooltip'; +import { ButtonProps as AntdButtonProps } from 'antd/lib/button'; +import { TooltipProps } from 'antd/lib/tooltip'; export type OnClickHandler = React.MouseEventHandler<HTMLElement>; @@ -37,45 +39,17 @@ export type ButtonStyle = | 'link' | 'dashed'; -export interface ButtonProps { - id?: string; - className?: string; - tooltip?: string; - ghost?: boolean; - placement?: - | 'bottom' - | 'left' - | 'right' - | 'top' - | 'topLeft' - | 'topRight' - | 'bottomLeft' - | 'bottomRight' - | 'leftTop' - | 'leftBottom' - | 'rightTop' - | 'rightBottom'; - onClick?: OnClickHandler; - onMouseDown?: OnClickHandler; - disabled?: boolean; - buttonStyle?: ButtonStyle; - buttonSize?: 'default' | 'small' | 'xsmall'; - style?: CSSProperties; - children?: React.ReactNode; - href?: string; - htmlType?: 'button' | 'submit' | 'reset'; - cta?: boolean; - loading?: boolean | { delay?: number | undefined } | undefined; - showMarginRight?: boolean; - type?: - | 'default' - | 'text' - | 'link' - | 'primary' - | 'dashed' - | 'ghost' - | undefined; -} +export type ButtonSize = 'default' | 'small' | 'xsmall'; + +export type ButtonProps = Omit<AntdButtonProps, 'css'> & + Pick<TooltipProps, 'placement'> & { + tooltip?: string; + className?: string; + buttonSize?: ButtonSize; + buttonStyle?: ButtonStyle; + cta?: boolean; + showMarginRight?: boolean; + }; export default function Button(props: ButtonProps) { const { @@ -119,8 +93,8 @@ export default function Button(props: ButtonProps) { let borderColorDisabled = 'transparent'; if (buttonStyle === 'primary') { - backgroundColor = primary.dark1; - backgroundColorHover = mix(0.1, grayscale.light5, primary.dark1); + backgroundColor = primary.base; + backgroundColorHover = primary.dark1; backgroundColorActive = mix(0.2, grayscale.dark2, primary.dark1); color = grayscale.light5; colorHover = color; diff --git a/superset-frontend/src/components/CertifiedBadge/CertifiedBadge.test.tsx b/superset-frontend/src/components/CertifiedBadge/CertifiedBadge.test.tsx index eb593be1607bc..03d01e78c92ff 100644 --- a/superset-frontend/src/components/CertifiedBadge/CertifiedBadge.test.tsx +++ b/superset-frontend/src/components/CertifiedBadge/CertifiedBadge.test.tsx @@ -17,24 +17,29 @@ * under the License. */ import React from 'react'; -import { render, screen } from 'spec/helpers/testing-library'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; -import CertifiedBadge from 'src/components/CertifiedBadge'; +import CertifiedBadge, { + CertifiedBadgeProps, +} from 'src/components/CertifiedBadge'; -test('renders with default props', () => { - render(<CertifiedBadge />); +const asyncRender = (props?: CertifiedBadgeProps) => + waitFor(() => render(<CertifiedBadge {...props} />)); + +test('renders with default props', async () => { + await asyncRender(); expect(screen.getByRole('img')).toBeInTheDocument(); }); test('renders a tooltip when hovered', async () => { - render(<CertifiedBadge />); + await asyncRender(); userEvent.hover(screen.getByRole('img')); expect(await screen.findByRole('tooltip')).toBeInTheDocument(); }); test('renders with certified by', async () => { const certifiedBy = 'Trusted Authority'; - render(<CertifiedBadge certifiedBy={certifiedBy} />); + await asyncRender({ certifiedBy }); userEvent.hover(screen.getByRole('img')); expect(await screen.findByRole('tooltip')).toHaveTextContent(certifiedBy); }); @@ -50,7 +55,7 @@ test('renders with multiple certified by values', async () => { test('renders with details', async () => { const details = 'All requirements have been met.'; - render(<CertifiedBadge details={details} />); + await asyncRender({ details }); userEvent.hover(screen.getByRole('img')); expect(await screen.findByRole('tooltip')).toHaveTextContent(details); }); diff --git a/superset-frontend/src/components/Chart/Chart.jsx b/superset-frontend/src/components/Chart/Chart.jsx index d5bdea70ac91d..4e6de07b7fbbc 100644 --- a/superset-frontend/src/components/Chart/Chart.jsx +++ b/superset-frontend/src/components/Chart/Chart.jsx @@ -28,6 +28,8 @@ import ErrorBoundary from 'src/components/ErrorBoundary'; import { Logger, LOG_ACTIONS_RENDER_CHART } from 'src/logger/LogUtils'; import { URL_PARAMS } from 'src/constants'; import { getUrlParam } from 'src/utils/urlUtils'; +import { isCurrentUserBot } from 'src/utils/isBot'; +import { ChartSource } from 'src/types/ChartSource'; import { ResourceStatus } from 'src/hooks/apiResources/apiResources'; import ChartRenderer from './ChartRenderer'; import { ChartErrorMessage } from './ChartErrorMessage'; @@ -74,6 +76,8 @@ const propTypes = { ownState: PropTypes.object, postTransformProps: PropTypes.func, datasetsStatus: PropTypes.oneOf(['loading', 'error', 'complete']), + isInView: PropTypes.bool, + emitCrossFilters: PropTypes.bool, }; const BLANK = {}; @@ -92,6 +96,7 @@ const defaultProps = { chartStackTrace: null, isDeactivatedViz: false, force: false, + isInView: true, }; const Styles = styled.div` @@ -109,6 +114,10 @@ const Styles = styled.div` .pivot_table tbody tr { font-feature-settings: 'tnum' 1; } + + .alert { + margin: ${({ theme }) => theme.gridUnit * 2}px; + } } `; @@ -204,7 +213,6 @@ class Chart extends React.PureComponent { height, datasetsStatus, } = this.props; - const error = queryResponse?.errors?.[0]; const message = chartAlert || queryResponse?.message; @@ -236,7 +244,7 @@ class Chart extends React.PureComponent { subtitle={<MonospaceDiv>{message}</MonospaceDiv>} copyText={message} link={queryResponse ? queryResponse.link : null} - source={dashboardId ? 'dashboard' : 'explore'} + source={dashboardId ? ChartSource.Dashboard : ChartSource.Explore} stackTrace={chartStackTrace} /> ); @@ -309,11 +317,17 @@ class Chart extends React.PureComponent { width={width} > <div className="slice_container" data-test="slice-container"> - <ChartRenderer - {...this.props} - source={this.props.dashboardId ? 'dashboard' : 'explore'} - data-test={this.props.vizType} - /> + {this.props.isInView || + !isFeatureEnabled(FeatureFlag.DASHBOARD_VIRTUALIZATION) || + isCurrentUserBot() ? ( + <ChartRenderer + {...this.props} + source={this.props.dashboardId ? 'dashboard' : 'explore'} + data-test={this.props.vizType} + /> + ) : ( + <Loading /> + )} </div> {isLoading && !isDeactivatedViz && <Loading />} </Styles> diff --git a/superset-frontend/src/components/Chart/ChartContextMenu.tsx b/superset-frontend/src/components/Chart/ChartContextMenu.tsx new file mode 100644 index 0000000000000..c202d9ee9dd61 --- /dev/null +++ b/superset-frontend/src/components/Chart/ChartContextMenu.tsx @@ -0,0 +1,152 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { + forwardRef, + RefObject, + useCallback, + useImperativeHandle, + useState, +} from 'react'; +import ReactDOM from 'react-dom'; +import { useSelector } from 'react-redux'; +import { + BinaryQueryObjectFilterClause, + FeatureFlag, + isFeatureEnabled, + QueryFormData, +} from '@superset-ui/core'; +import { RootState } from 'src/dashboard/types'; +import { findPermission } from 'src/utils/findPermission'; +import { Menu } from 'src/components/Menu'; +import { AntdDropdown as Dropdown } from 'src/components'; +import { DrillDetailMenuItems } from './DrillDetail'; +import { getMenuAdjustedY } from './utils'; + +export interface ChartContextMenuProps { + id: number; + formData: QueryFormData; + onSelection: () => void; + onClose: () => void; +} + +export interface Ref { + open: ( + clientX: number, + clientY: number, + filters?: BinaryQueryObjectFilterClause[], + ) => void; +} + +const ChartContextMenu = ( + { id, formData, onSelection, onClose }: ChartContextMenuProps, + ref: RefObject<Ref>, +) => { + const canExplore = useSelector((state: RootState) => + findPermission('can_explore', 'Superset', state.user?.roles), + ); + + const [{ filters, clientX, clientY }, setState] = useState<{ + clientX: number; + clientY: number; + filters?: BinaryQueryObjectFilterClause[]; + }>({ clientX: 0, clientY: 0 }); + + const menuItems = []; + const showDrillToDetail = + isFeatureEnabled(FeatureFlag.DRILL_TO_DETAIL) && canExplore; + + if (showDrillToDetail) { + menuItems.push( + <DrillDetailMenuItems + chartId={id} + formData={formData} + filters={filters} + isContextMenu + contextMenuY={clientY} + onSelection={onSelection} + />, + ); + } + + const open = useCallback( + ( + clientX: number, + clientY: number, + filters?: BinaryQueryObjectFilterClause[], + ) => { + const itemsCount = + [ + showDrillToDetail ? 2 : 0, // Drill to detail always has 2 top-level menu items + ].reduce((a, b) => a + b, 0) || 1; // "No actions" appears if no actions in menu + + const adjustedY = getMenuAdjustedY(clientY, itemsCount); + setState({ + clientX, + clientY: adjustedY, + filters, + }); + + // Since Ant Design's Dropdown does not offer an imperative API + // and we can't attach event triggers to charts SVG elements, we + // use a hidden span that gets clicked on when receiving click events + // from the charts. + document.getElementById(`hidden-span-${id}`)?.click(); + }, + [id, showDrillToDetail], + ); + + useImperativeHandle( + ref, + () => ({ + open, + }), + [open], + ); + + return ReactDOM.createPortal( + <Dropdown + overlay={ + <Menu> + {menuItems.length ? ( + menuItems + ) : ( + <Menu.Item disabled>No actions</Menu.Item> + )} + </Menu> + } + trigger={['click']} + onVisibleChange={value => !value && onClose()} + > + <span + id={`hidden-span-${id}`} + css={{ + visibility: 'hidden', + position: 'fixed', + top: clientY, + left: clientX, + width: 1, + height: 1, + }} + /> + </Dropdown>, + document.body, + ); +}; + +export default forwardRef(ChartContextMenu); diff --git a/superset-frontend/src/components/Chart/ChartRenderer.jsx b/superset-frontend/src/components/Chart/ChartRenderer.jsx index ed330ab7afc95..588e2b4e4dfbe 100644 --- a/superset-frontend/src/components/Chart/ChartRenderer.jsx +++ b/superset-frontend/src/components/Chart/ChartRenderer.jsx @@ -19,9 +19,19 @@ import { snakeCase, isEqual } from 'lodash'; import PropTypes from 'prop-types'; import React from 'react'; -import { SuperChart, logging, Behavior, t } from '@superset-ui/core'; +import { + SuperChart, + logging, + Behavior, + t, + isFeatureEnabled, + FeatureFlag, + getChartMetadataRegistry, +} from '@superset-ui/core'; import { Logger, LOG_ACTIONS_RENDER_CHART } from 'src/logger/LogUtils'; import { EmptyStateBig, EmptyStateSmall } from 'src/components/EmptyState'; +import { ChartSource } from 'src/types/ChartSource'; +import ChartContextMenu from './ChartContextMenu'; const propTypes = { annotationData: PropTypes.object, @@ -51,7 +61,8 @@ const propTypes = { onFilterMenuClose: PropTypes.func, ownState: PropTypes.object, postTransformProps: PropTypes.func, - source: PropTypes.oneOf(['dashboard', 'explore']), + source: PropTypes.oneOf([ChartSource.Dashboard, ChartSource.Explore]), + emitCrossFilters: PropTypes.bool, }; const BLANK = {}; @@ -73,15 +84,30 @@ const defaultProps = { class ChartRenderer extends React.Component { constructor(props) { super(props); + this.state = { + showContextMenu: + props.source === ChartSource.Dashboard && + isFeatureEnabled(FeatureFlag.DRILL_TO_DETAIL), + inContextMenu: false, + }; this.hasQueryResponseChange = false; + this.contextMenuRef = React.createRef(); + this.handleAddFilter = this.handleAddFilter.bind(this); this.handleRenderSuccess = this.handleRenderSuccess.bind(this); this.handleRenderFailure = this.handleRenderFailure.bind(this); this.handleSetControlValue = this.handleSetControlValue.bind(this); + this.handleOnContextMenu = this.handleOnContextMenu.bind(this); + this.handleContextMenuSelected = this.handleContextMenuSelected.bind(this); + this.handleContextMenuClosed = this.handleContextMenuClosed.bind(this); + this.onContextMenuFallback = this.onContextMenuFallback.bind(this); this.hooks = { onAddFilter: this.handleAddFilter, + onContextMenu: this.state.showContextMenu + ? this.handleOnContextMenu + : undefined, onError: this.handleRenderFailure, setControlValue: this.handleSetControlValue, onFilterMenuOpen: this.props.onFilterMenuOpen, @@ -92,13 +118,16 @@ class ChartRenderer extends React.Component { }; } - shouldComponentUpdate(nextProps) { + shouldComponentUpdate(nextProps, nextState) { const resultsReady = nextProps.queriesResponse && ['success', 'rendered'].indexOf(nextProps.chartStatus) > -1 && !nextProps.queriesResponse?.[0]?.error; if (resultsReady) { + if (!isEqual(this.state, nextState)) { + return true; + } this.hasQueryResponseChange = nextProps.queriesResponse !== this.props.queriesResponse; return ( @@ -114,7 +143,8 @@ class ChartRenderer extends React.Component { nextProps.sharedLabelColors !== this.props.sharedLabelColors || nextProps.formData.color_scheme !== this.props.formData.color_scheme || nextProps.formData.stack !== this.props.formData.stack || - nextProps.cacheBusterProp !== this.props.cacheBusterProp + nextProps.cacheBusterProp !== this.props.cacheBusterProp || + nextProps.emitCrossFilters !== this.props.emitCrossFilters ); } return false; @@ -172,8 +202,30 @@ class ChartRenderer extends React.Component { } } + handleOnContextMenu(offsetX, offsetY, filters) { + this.contextMenuRef.current.open(offsetX, offsetY, filters); + this.setState({ inContextMenu: true }); + } + + handleContextMenuSelected() { + this.setState({ inContextMenu: false }); + } + + handleContextMenuClosed() { + this.setState({ inContextMenu: false }); + } + + // When viz plugins don't handle `contextmenu` event, fallback handler + // calls `handleOnContextMenu` with no `filters` param. + onContextMenuFallback(event) { + if (!this.state.inContextMenu) { + event.preventDefault(); + this.handleOnContextMenu(event.clientX, event.clientY); + } + } + render() { - const { chartAlert, chartStatus, chartId } = this.props; + const { chartAlert, chartStatus, chartId, emitCrossFilters } = this.props; // Skip chart rendering if (chartStatus === 'loading' || !!chartAlert || chartStatus === null) { @@ -226,7 +278,7 @@ class ChartRenderer extends React.Component { let noResultsComponent; const noResultTitle = t('No results were returned for this query'); const noResultDescription = - this.props.source === 'explore' + this.props.source === ChartSource.Explore ? t( 'Make sure that the controls are configured properly and the datasource contains data for the selected time range', ) @@ -246,29 +298,56 @@ class ChartRenderer extends React.Component { ); } + // Check for Behavior.DRILL_TO_DETAIL to tell if chart can receive Drill to + // Detail props or if it'll cause side-effects (e.g. excessive re-renders). + const drillToDetailProps = getChartMetadataRegistry() + .get(formData.viz_type) + ?.behaviors.find(behavior => behavior === Behavior.DRILL_TO_DETAIL) + ? { inContextMenu: this.state.inContextMenu } + : {}; + return ( - <SuperChart - disableErrorBoundary - key={`${chartId}${webpackHash}`} - id={`chart-id-${chartId}`} - className={chartClassName} - chartType={vizType} - width={width} - height={height} - annotationData={annotationData} - datasource={datasource} - initialValues={initialValues} - formData={currentFormData} - ownState={ownState} - filterState={filterState} - hooks={this.hooks} - behaviors={behaviors} - queriesData={queriesResponse} - onRenderSuccess={this.handleRenderSuccess} - onRenderFailure={this.handleRenderFailure} - noResults={noResultsComponent} - postTransformProps={postTransformProps} - /> + <> + {this.state.showContextMenu && ( + <ChartContextMenu + ref={this.contextMenuRef} + id={chartId} + formData={currentFormData} + onSelection={this.handleContextMenuSelected} + onClose={this.handleContextMenuClosed} + /> + )} + <div + onContextMenu={ + this.state.showContextMenu ? this.onContextMenuFallback : undefined + } + > + <SuperChart + disableErrorBoundary + key={`${chartId}${webpackHash}`} + id={`chart-id-${chartId}`} + className={chartClassName} + chartType={vizType} + width={width} + height={height} + annotationData={annotationData} + datasource={datasource} + initialValues={initialValues} + formData={currentFormData} + ownState={ownState} + filterState={filterState} + hooks={this.hooks} + behaviors={behaviors} + queriesData={queriesResponse} + onRenderSuccess={this.handleRenderSuccess} + onRenderFailure={this.handleRenderFailure} + noResults={noResultsComponent} + postTransformProps={postTransformProps} + emitCrossFilters={emitCrossFilters} + {...drillToDetailProps} + /> + </div> + </> ); } } diff --git a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.test.tsx b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.test.tsx new file mode 100644 index 0000000000000..8a0f8dbfc5cd1 --- /dev/null +++ b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.test.tsx @@ -0,0 +1,345 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import userEvent from '@testing-library/user-event'; +import { render, screen, within } from 'spec/helpers/testing-library'; +import { getMockStoreWithNativeFilters } from 'spec/fixtures/mockStore'; +import chartQueries, { sliceId } from 'spec/fixtures/mockChartQueries'; +import { BinaryQueryObjectFilterClause } from '@superset-ui/core'; +import { Menu } from 'src/components/Menu'; +import DrillDetailMenuItems, { + DrillDetailMenuItemsProps, +} from './DrillDetailMenuItems'; + +/* eslint jest/expect-expect: ["warn", { "assertFunctionNames": ["expect*"] }] */ + +jest.mock( + './DrillDetailPane', + () => + ({ initialFilters }: { initialFilters: BinaryQueryObjectFilterClause[] }) => + <pre data-test="modal-filters">{JSON.stringify(initialFilters)}</pre>, +); + +const { id: defaultChartId, form_data: defaultFormData } = + chartQueries[sliceId]; + +const { slice_name: chartName } = defaultFormData; +const unsupportedChartFormData = { + ...defaultFormData, + viz_type: 'dist_bar', +}; + +const noDimensionsFormData = { + ...defaultFormData, + viz_type: 'table', + query_mode: 'raw', +}; + +const filterA: BinaryQueryObjectFilterClause = { + col: 'sample_column', + op: '==', + val: 1234567890, + formattedVal: 'Yesterday', +}; + +const filterB: BinaryQueryObjectFilterClause = { + col: 'sample_column_2', + op: '==', + val: 987654321, + formattedVal: 'Two days ago', +}; + +const renderMenu = ({ + chartId, + formData, + isContextMenu, + filters, +}: Partial<DrillDetailMenuItemsProps>) => { + const store = getMockStoreWithNativeFilters(); + return render( + <Menu> + <DrillDetailMenuItems + chartId={chartId ?? defaultChartId} + formData={formData ?? defaultFormData} + filters={filters} + isContextMenu={isContextMenu} + /> + </Menu>, + { useRouter: true, useRedux: true, store }, + ); +}; + +/** + * Drill to Detail modal should appear with correct initial filters + */ +const expectDrillToDetailModal = async ( + buttonName: string, + filters: BinaryQueryObjectFilterClause[] = [], +) => { + const button = screen.getByRole('menuitem', { name: buttonName }); + userEvent.click(button); + const modal = await screen.findByRole('dialog', { + name: `Drill to detail: ${chartName}`, + }); + + expect(modal).toBeVisible(); + expect(screen.getByTestId('modal-filters')).toHaveTextContent( + JSON.stringify(filters), + ); +}; + +/** + * Menu item should be enabled without explanatory tooltip + */ +const expectMenuItemEnabled = async (menuItem: HTMLElement) => { + expect(menuItem).toBeInTheDocument(); + expect(menuItem).not.toHaveAttribute('aria-disabled'); + const tooltipTrigger = within(menuItem).queryByTestId('tooltip-trigger'); + expect(tooltipTrigger).not.toBeInTheDocument(); +}; + +/** + * Menu item should be disabled, optionally with an explanatory tooltip + */ +const expectMenuItemDisabled = async ( + menuItem: HTMLElement, + tooltipContent?: string, +) => { + expect(menuItem).toBeVisible(); + expect(menuItem).toHaveAttribute('aria-disabled', 'true'); + const tooltipTrigger = within(menuItem).queryByTestId('tooltip-trigger'); + if (tooltipContent) { + userEvent.hover(tooltipTrigger as HTMLElement); + const tooltip = await screen.findByRole('tooltip', { + name: tooltipContent, + }); + + expect(tooltip).toBeInTheDocument(); + } else { + expect(tooltipTrigger).not.toBeInTheDocument(); + } +}; + +/** + * "Drill to detail" item should be enabled and open the correct modal + */ +const expectDrillToDetailEnabled = async () => { + const drillToDetailMenuItem = screen.getByRole('menuitem', { + name: 'Drill to detail', + }); + + await expectMenuItemEnabled(drillToDetailMenuItem); + await expectDrillToDetailModal('Drill to detail'); +}; + +/** + * "Drill to detail" item should be present and disabled + */ +const expectDrillToDetailDisabled = async (tooltipContent?: string) => { + const drillToDetailMenuItem = screen.getByRole('menuitem', { + name: 'Drill to detail', + }); + + await expectMenuItemDisabled(drillToDetailMenuItem, tooltipContent); +}; + +/** + * "Drill to detail by" item should not be present + */ +const expectNoDrillToDetailBy = async () => { + const drillToDetailBy = screen.queryByRole('menuitem', { + name: 'Drill to detail by', + }); + + expect(drillToDetailBy).not.toBeInTheDocument(); +}; + +/** + * "Drill to detail by" submenu should be present and enabled + */ +const expectDrillToDetailByEnabled = async () => { + const drillToDetailBy = screen.getByRole('menuitem', { + name: 'Drill to detail by', + }); + + await expectMenuItemEnabled(drillToDetailBy); + userEvent.hover( + within(drillToDetailBy).getByRole('button', { name: 'Drill to detail by' }), + ); + + expect( + await screen.findByTestId('drill-to-detail-by-submenu'), + ).toBeInTheDocument(); +}; + +/** + * "Drill to detail by" submenu should be present and disabled + */ +const expectDrillToDetailByDisabled = async (tooltipContent?: string) => { + const drillToDetailBySubmenuItem = screen.getByRole('menuitem', { + name: 'Drill to detail by', + }); + + await expectMenuItemDisabled(drillToDetailBySubmenuItem, tooltipContent); +}; + +/** + * "Drill to detail by {dimension}" submenu item should exist and open the correct modal + */ +const expectDrillToDetailByDimension = async ( + filter: BinaryQueryObjectFilterClause, +) => { + userEvent.hover(screen.getByRole('button', { name: 'Drill to detail by' })); + const drillToDetailBySubMenu = await screen.findByTestId( + 'drill-to-detail-by-submenu', + ); + + const menuItemName = `Drill to detail by ${filter.formattedVal}`; + const drillToDetailBySubmenuItem = within(drillToDetailBySubMenu).getByRole( + 'menuitem', + { name: menuItemName }, + ); + + await expectMenuItemEnabled(drillToDetailBySubmenuItem); + await expectDrillToDetailModal(menuItemName, [filter]); +}; + +/** + * "Drill to detail by all" submenu item should exist and open the correct modal + */ +const expectDrillToDetailByAll = async ( + filters: BinaryQueryObjectFilterClause[], +) => { + userEvent.hover(screen.getByRole('button', { name: 'Drill to detail by' })); + const drillToDetailBySubMenu = await screen.findByTestId( + 'drill-to-detail-by-submenu', + ); + + const menuItemName = 'Drill to detail by all'; + const drillToDetailBySubmenuItem = within(drillToDetailBySubMenu).getByRole( + 'menuitem', + { name: menuItemName }, + ); + + await expectMenuItemEnabled(drillToDetailBySubmenuItem); + await expectDrillToDetailModal(menuItemName, filters); +}; + +test('dropdown menu for unsupported chart', async () => { + renderMenu({ formData: unsupportedChartFormData }); + await expectDrillToDetailEnabled(); + await expectNoDrillToDetailBy(); +}); + +test('context menu for unsupported chart', async () => { + renderMenu({ + formData: unsupportedChartFormData, + isContextMenu: true, + }); + + await expectDrillToDetailEnabled(); + await expectDrillToDetailByDisabled( + 'Drill to detail by value is not yet supported for this chart type.', + ); +}); + +test('dropdown menu for supported chart, no dimensions', async () => { + renderMenu({ + formData: noDimensionsFormData, + }); + + await expectDrillToDetailDisabled( + 'Drill to detail is disabled because this chart does not group data by dimension value.', + ); + + await expectNoDrillToDetailBy(); +}); + +test('context menu for supported chart, no dimensions, no filters', async () => { + renderMenu({ + formData: noDimensionsFormData, + isContextMenu: true, + }); + + await expectDrillToDetailDisabled( + 'Drill to detail is disabled because this chart does not group data by dimension value.', + ); + + await expectDrillToDetailByDisabled(); +}); + +test('context menu for supported chart, no dimensions, 1 filter', async () => { + renderMenu({ + formData: noDimensionsFormData, + isContextMenu: true, + filters: [filterA], + }); + + await expectDrillToDetailDisabled( + 'Drill to detail is disabled because this chart does not group data by dimension value.', + ); + + await expectDrillToDetailByDisabled(); +}); + +test('dropdown menu for supported chart, dimensions', async () => { + renderMenu({ formData: defaultFormData }); + await expectDrillToDetailEnabled(); + await expectNoDrillToDetailBy(); +}); + +test('context menu for supported chart, dimensions, no filters', async () => { + renderMenu({ + formData: defaultFormData, + isContextMenu: true, + }); + + await expectDrillToDetailEnabled(); + await expectDrillToDetailByDisabled( + 'Right-click on a dimension value to drill to detail by that value.', + ); +}); + +test('context menu for supported chart, dimensions, 1 filter', async () => { + const filters = [filterA]; + renderMenu({ + formData: defaultFormData, + isContextMenu: true, + filters, + }); + + await expectDrillToDetailEnabled(); + await expectDrillToDetailByEnabled(); + await expectDrillToDetailByDimension(filterA); +}); + +test('context menu for supported chart, dimensions, 2 filters', async () => { + const filters = [filterA, filterB]; + renderMenu({ + formData: defaultFormData, + isContextMenu: true, + filters, + }); + + await expectDrillToDetailEnabled(); + await expectDrillToDetailByEnabled(); + await expectDrillToDetailByDimension(filterA); + await expectDrillToDetailByDimension(filterB); + await expectDrillToDetailByAll(filters); +}); diff --git a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx new file mode 100644 index 0000000000000..6159e212e34f1 --- /dev/null +++ b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx @@ -0,0 +1,255 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { ReactNode, useCallback, useMemo, useState } from 'react'; +import { isEmpty } from 'lodash'; +import { + Behavior, + BinaryQueryObjectFilterClause, + css, + extractQueryFields, + getChartMetadataRegistry, + QueryFormData, + styled, + SupersetTheme, + t, +} from '@superset-ui/core'; +import { Menu } from 'src/components/Menu'; +import Icons from 'src/components/Icons'; +import { Tooltip } from 'src/components/Tooltip'; +import DrillDetailModal from './DrillDetailModal'; +import { getMenuAdjustedY, MENU_ITEM_HEIGHT } from '../utils'; + +const MENU_PADDING = 4; +const DRILL_TO_DETAIL_TEXT = t('Drill to detail by'); + +const DisabledMenuItemTooltip = ({ title }: { title: ReactNode }) => ( + <Tooltip title={title} placement="top"> + <Icons.InfoCircleOutlined + data-test="tooltip-trigger" + css={(theme: SupersetTheme) => css` + color: ${theme.colors.text.label}; + margin-left: ${theme.gridUnit * 2}px; + &.anticon { + font-size: unset; + .anticon { + line-height: unset; + vertical-align: unset; + } + } + `} + /> + </Tooltip> +); + +const DisabledMenuItem = ({ children, ...props }: { children: ReactNode }) => ( + <Menu.Item disabled {...props}> + <div + css={css` + white-space: normal; + max-width: 160px; + `} + > + {children} + </div> + </Menu.Item> +); + +const Filter = styled.span` + ${({ theme }) => ` + font-weight: ${theme.typography.weights.bold}; + color: ${theme.colors.primary.base}; + `} +`; + +export type DrillDetailMenuItemsProps = { + chartId: number; + formData: QueryFormData; + filters?: BinaryQueryObjectFilterClause[]; + isContextMenu?: boolean; + contextMenuY?: number; + onSelection?: () => void; + onClick?: (event: MouseEvent) => void; +}; + +const DrillDetailMenuItems = ({ + chartId, + formData, + filters = [], + isContextMenu = false, + contextMenuY = 0, + onSelection = () => null, + onClick = () => null, + ...props +}: DrillDetailMenuItemsProps) => { + const [modalFilters, setFilters] = useState<BinaryQueryObjectFilterClause[]>( + [], + ); + + const [showModal, setShowModal] = useState(false); + const openModal = useCallback( + (filters, event) => { + onClick(event); + onSelection(); + setFilters(filters); + setShowModal(true); + }, + [onClick, onSelection], + ); + + const closeModal = useCallback(() => { + setShowModal(false); + }, []); + + // Check for Behavior.DRILL_TO_DETAIL to tell if plugin handles the `contextmenu` + // event for dimensions. If it doesn't, tell the user that drill to detail by + // dimension is not supported. If it does, and the `contextmenu` handler didn't + // pass any filters, tell the user that they didn't select a dimension. + const handlesDimensionContextMenu = useMemo( + () => + getChartMetadataRegistry() + .get(formData.viz_type) + ?.behaviors.find(behavior => behavior === Behavior.DRILL_TO_DETAIL), + [formData.viz_type], + ); + + // Check metrics to see if chart's current configuration lacks + // aggregations, in which case Drill to Detail should be disabled. + const noAggregations = useMemo(() => { + const { metrics } = extractQueryFields(formData); + return isEmpty(metrics); + }, [formData]); + + let drillToDetailMenuItem; + if (handlesDimensionContextMenu && noAggregations) { + drillToDetailMenuItem = ( + <DisabledMenuItem {...props} key="drill-detail-no-aggregations"> + {t('Drill to detail')} + <DisabledMenuItemTooltip + title={t( + 'Drill to detail is disabled because this chart does not group data by dimension value.', + )} + /> + </DisabledMenuItem> + ); + } else { + drillToDetailMenuItem = ( + <Menu.Item + {...props} + key="drill-detail-no-filters" + onClick={openModal.bind(null, [])} + > + {t('Drill to detail')} + </Menu.Item> + ); + } + + let drillToDetailByMenuItem; + if (!handlesDimensionContextMenu) { + drillToDetailByMenuItem = ( + <DisabledMenuItem {...props} key="drill-detail-by-chart-not-supported"> + {DRILL_TO_DETAIL_TEXT} + <DisabledMenuItemTooltip + title={t( + 'Drill to detail by value is not yet supported for this chart type.', + )} + /> + </DisabledMenuItem> + ); + } + + if (handlesDimensionContextMenu && noAggregations) { + drillToDetailByMenuItem = ( + <DisabledMenuItem {...props} key="drill-detail-by-no-aggregations"> + {DRILL_TO_DETAIL_TEXT} + </DisabledMenuItem> + ); + } + + // Ensure submenu doesn't appear offscreen + const submenuYOffset = useMemo(() => { + const itemsCount = filters.length > 1 ? filters.length + 1 : filters.length; + const submenuY = + contextMenuY + MENU_PADDING + MENU_ITEM_HEIGHT + MENU_PADDING; + + return getMenuAdjustedY(submenuY, itemsCount) - submenuY; + }, [contextMenuY, filters.length]); + + if (handlesDimensionContextMenu && !noAggregations && filters?.length) { + drillToDetailByMenuItem = ( + <Menu.SubMenu + {...props} + popupOffset={[0, submenuYOffset]} + title={DRILL_TO_DETAIL_TEXT} + > + <div data-test="drill-to-detail-by-submenu"> + {filters.map((filter, i) => ( + <Menu.Item + {...props} + key={`drill-detail-filter-${i}`} + onClick={openModal.bind(null, [filter])} + > + {`${DRILL_TO_DETAIL_TEXT} `} + <Filter>{filter.formattedVal}</Filter> + </Menu.Item> + ))} + {filters.length > 1 && ( + <Menu.Item + {...props} + key="drill-detail-filter-all" + onClick={openModal.bind(null, filters)} + > + {`${DRILL_TO_DETAIL_TEXT} `} + <Filter>{t('all')}</Filter> + </Menu.Item> + )} + </div> + </Menu.SubMenu> + ); + } + + if (handlesDimensionContextMenu && !noAggregations && !filters?.length) { + drillToDetailByMenuItem = ( + <DisabledMenuItem {...props} key="drill-detail-by-select-aggregation"> + {DRILL_TO_DETAIL_TEXT} + <DisabledMenuItemTooltip + title={t( + 'Right-click on a dimension value to drill to detail by that value.', + )} + /> + </DisabledMenuItem> + ); + } + + return ( + <> + {drillToDetailMenuItem} + {isContextMenu && drillToDetailByMenuItem} + <DrillDetailModal + chartId={chartId} + formData={formData} + initialFilters={modalFilters} + showModal={showModal} + onHideModal={closeModal} + /> + </> + ); +}; + +export default DrillDetailMenuItems; diff --git a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailModal.test.tsx b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailModal.test.tsx new file mode 100644 index 0000000000000..038541d390761 --- /dev/null +++ b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailModal.test.tsx @@ -0,0 +1,95 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState } from 'react'; +import userEvent from '@testing-library/user-event'; +import { render, screen } from 'spec/helpers/testing-library'; +import { getMockStoreWithNativeFilters } from 'spec/fixtures/mockStore'; +import chartQueries, { sliceId } from 'spec/fixtures/mockChartQueries'; +import DrillDetailModal from './DrillDetailModal'; + +jest.mock('./DrillDetailPane', () => () => null); +const mockHistoryPush = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useHistory: () => ({ + push: mockHistoryPush, + }), +})); + +const { id: chartId, form_data: formData } = chartQueries[sliceId]; +const { slice_name: chartName } = formData; + +const renderModal = async () => { + const store = getMockStoreWithNativeFilters(); + const DrillDetailModalWrapper = () => { + const [showModal, setShowModal] = useState(false); + return ( + <> + <button type="button" onClick={() => setShowModal(true)}> + Show modal + </button> + <DrillDetailModal + chartId={chartId} + formData={formData} + initialFilters={[]} + showModal={showModal} + onHideModal={() => setShowModal(false)} + /> + </> + ); + }; + + render(<DrillDetailModalWrapper />, { + useRouter: true, + useRedux: true, + store, + }); + + userEvent.click(screen.getByRole('button', { name: 'Show modal' })); + await screen.findByRole('dialog', { name: `Drill to detail: ${chartName}` }); +}; + +test('should render the title', async () => { + await renderModal(); + expect(screen.getByText(`Drill to detail: ${chartName}`)).toBeInTheDocument(); +}); + +test('should render the button', async () => { + await renderModal(); + expect( + screen.getByRole('button', { name: 'Edit chart' }), + ).toBeInTheDocument(); + expect(screen.getAllByRole('button', { name: 'Close' })).toHaveLength(2); +}); + +test('should close the modal', async () => { + await renderModal(); + expect(screen.getByRole('dialog')).toBeInTheDocument(); + userEvent.click(screen.getAllByRole('button', { name: 'Close' })[1]); + expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); +}); + +test('should forward to Explore', async () => { + await renderModal(); + userEvent.click(screen.getByRole('button', { name: 'Edit chart' })); + expect(mockHistoryPush).toHaveBeenCalledWith( + `/explore/?dashboard_page_id=&slice_id=${sliceId}`, + ); +}); diff --git a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailModal.tsx b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailModal.tsx new file mode 100644 index 0000000000000..e1207f8aac5fc --- /dev/null +++ b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailModal.tsx @@ -0,0 +1,118 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useCallback, useContext, useMemo } from 'react'; +import { useHistory } from 'react-router-dom'; +import { + BinaryQueryObjectFilterClause, + css, + QueryFormData, + t, + useTheme, +} from '@superset-ui/core'; +import Modal from 'src/components/Modal'; +import Button from 'src/components/Button'; +import { useSelector } from 'react-redux'; +import { DashboardPageIdContext } from 'src/dashboard/containers/DashboardPage'; +import { Slice } from 'src/types/Chart'; +import DrillDetailPane from './DrillDetailPane'; + +interface ModalFooterProps { + exploreChart: () => void; + closeModal?: () => void; +} + +const ModalFooter = ({ exploreChart, closeModal }: ModalFooterProps) => ( + <> + <Button buttonStyle="secondary" buttonSize="small" onClick={exploreChart}> + {t('Edit chart')} + </Button> + <Button + buttonStyle="primary" + buttonSize="small" + onClick={closeModal} + data-test="close-drilltodetail-modal" + > + {t('Close')} + </Button> + </> +); + +interface DrillDetailModalProps { + chartId: number; + formData: QueryFormData; + initialFilters: BinaryQueryObjectFilterClause[]; + showModal: boolean; + onHideModal: () => void; +} + +export default function DrillDetailModal({ + chartId, + formData, + initialFilters, + showModal, + onHideModal, +}: DrillDetailModalProps) { + const theme = useTheme(); + const history = useHistory(); + const dashboardPageId = useContext(DashboardPageIdContext); + const { slice_name: chartName } = useSelector( + (state: { sliceEntities: { slices: Record<number, Slice> } }) => + state.sliceEntities.slices[chartId], + ); + + const exploreUrl = useMemo( + () => `/explore/?dashboard_page_id=${dashboardPageId}&slice_id=${chartId}`, + [chartId, dashboardPageId], + ); + + const exploreChart = useCallback(() => { + history.push(exploreUrl); + }, [exploreUrl, history]); + + return ( + <Modal + show={showModal} + onHide={onHideModal ?? (() => null)} + css={css` + .ant-modal-body { + display: flex; + flex-direction: column; + } + `} + title={t('Drill to detail: %s', chartName)} + footer={<ModalFooter exploreChart={exploreChart} />} + responsive + resizable + resizableConfig={{ + minHeight: theme.gridUnit * 128, + minWidth: theme.gridUnit * 128, + defaultSize: { + width: 'auto', + height: '75vh', + }, + }} + draggable + destroyOnClose + maskClosable={false} + > + <DrillDetailPane formData={formData} initialFilters={initialFilters} /> + </Modal> + ); +} diff --git a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.test.tsx b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.test.tsx new file mode 100644 index 0000000000000..a6c8fd06b07f0 --- /dev/null +++ b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.test.tsx @@ -0,0 +1,200 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import { getMockStoreWithNativeFilters } from 'spec/fixtures/mockStore'; +import chartQueries, { sliceId } from 'spec/fixtures/mockChartQueries'; +import { QueryFormData, SupersetClient } from '@superset-ui/core'; +import fetchMock from 'fetch-mock'; +import DrillDetailPane from './DrillDetailPane'; + +const chart = chartQueries[sliceId]; +const setup = (overrides: Record<string, any> = {}) => { + const store = getMockStoreWithNativeFilters(); + const props = { + initialFilters: [], + formData: chart.form_data as unknown as QueryFormData, + ...overrides, + }; + return render(<DrillDetailPane {...props} />, { + useRedux: true, + store, + }); +}; + +const waitForRender = (overrides: Record<string, any> = {}) => + waitFor(() => setup(overrides)); + +const SAMPLES_ENDPOINT = + 'end:/datasource/samples?force=false&datasource_type=table&datasource_id=7&per_page=50&page=1'; + +const DATASET_ENDPOINT = 'glob:*/api/v1/dataset/*'; + +const MOCKED_DATASET = { + changed_on_humanized: '2 days ago', + created_on_humanized: 'a week ago', + description: 'Simple description', + table_name: 'test_table', + changed_by: { + first_name: 'John', + last_name: 'Doe', + }, + created_by: { + first_name: 'John', + last_name: 'Doe', + }, + owners: [ + { + first_name: 'John', + last_name: 'Doe', + }, + ], +}; + +const setupDatasetEndpoint = () => { + fetchMock.get(DATASET_ENDPOINT, { + status: 'complete', + result: MOCKED_DATASET, + }); +}; + +const fetchWithNoData = () => { + setupDatasetEndpoint(); + fetchMock.post(SAMPLES_ENDPOINT, { + result: { + total_count: 0, + data: [], + colnames: [], + coltypes: [], + }, + }); +}; + +const fetchWithData = () => { + setupDatasetEndpoint(); + fetchMock.post(SAMPLES_ENDPOINT, { + result: { + total_count: 3, + data: [ + { + year: 1996, + na_sales: 11.27, + eu_sales: 8.89, + }, + { + year: 1989, + na_sales: 23.2, + eu_sales: 2.26, + }, + { + year: 1999, + na_sales: 9, + eu_sales: 6.18, + }, + ], + colnames: ['year', 'na_sales', 'eu_sales'], + coltypes: [0, 0, 0], + }, + }); +}; + +afterEach(fetchMock.restore); + +test('should render', async () => { + fetchWithNoData(); + const { container } = await waitForRender(); + expect(container).toBeInTheDocument(); +}); + +test('should render loading indicator', async () => { + fetchWithData(); + setup(); + await waitFor(() => + expect(screen.getByLabelText('Loading')).toBeInTheDocument(), + ); +}); + +test('should render the table with results', async () => { + fetchWithData(); + await waitForRender(); + expect(screen.getByRole('table')).toBeInTheDocument(); + expect(screen.getByText('1996')).toBeInTheDocument(); + expect(screen.getByText('11.27')).toBeInTheDocument(); + expect(screen.getByText('1989')).toBeInTheDocument(); + expect(screen.getByText('23.2')).toBeInTheDocument(); + expect(screen.getByText('1999')).toBeInTheDocument(); + expect(screen.getByText('9')).toBeInTheDocument(); + expect( + screen.getByRole('columnheader', { name: 'year' }), + ).toBeInTheDocument(); + expect( + screen.getByRole('columnheader', { name: 'na_sales' }), + ).toBeInTheDocument(); + expect( + screen.getByRole('columnheader', { name: 'eu_sales' }), + ).toBeInTheDocument(); +}); + +test('should render the "No results" components', async () => { + fetchWithNoData(); + setup(); + expect( + await screen.findByText('No rows were returned for this dataset'), + ).toBeInTheDocument(); +}); + +test('should render the metadata bar', async () => { + fetchWithNoData(); + setup(); + expect( + await screen.findByText(MOCKED_DATASET.table_name), + ).toBeInTheDocument(); + expect( + await screen.findByText(MOCKED_DATASET.description), + ).toBeInTheDocument(); + expect( + await screen.findByText( + `${MOCKED_DATASET.created_by.first_name} ${MOCKED_DATASET.created_by.last_name}`, + ), + ).toBeInTheDocument(); + expect( + await screen.findByText(MOCKED_DATASET.changed_on_humanized), + ).toBeInTheDocument(); +}); + +test('should render an error message when fails to load the metadata', async () => { + fetchWithNoData(); + fetchMock.get( + DATASET_ENDPOINT, + { status: 'error', error: 'Some error' }, + { overwriteRoutes: true }, + ); + setup(); + expect( + await screen.findByText('There was an error loading the dataset metadata'), + ).toBeInTheDocument(); +}); + +test('should render the error', async () => { + jest + .spyOn(SupersetClient, 'post') + .mockRejectedValue(new Error('Something went wrong')); + await waitForRender(); + expect(screen.getByText('Error: Something went wrong')).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.tsx b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.tsx new file mode 100644 index 0000000000000..cf387b4e7e821 --- /dev/null +++ b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.tsx @@ -0,0 +1,397 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { + useState, + useEffect, + useMemo, + useCallback, + useRef, + ReactElement, +} from 'react'; +import { useSelector } from 'react-redux'; +import { + BinaryQueryObjectFilterClause, + css, + ensureIsArray, + t, + useTheme, + QueryFormData, + JsonObject, + GenericDataType, +} from '@superset-ui/core'; +import { useResizeDetector } from 'react-resize-detector'; +import Loading from 'src/components/Loading'; +import BooleanCell from 'src/components/Table/cell-renderers/BooleanCell'; +import NullCell from 'src/components/Table/cell-renderers/NullCell'; +import TimeCell from 'src/components/Table/cell-renderers/TimeCell'; +import { EmptyStateMedium } from 'src/components/EmptyState'; +import { getDatasourceSamples } from 'src/components/Chart/chartAction'; +import Table, { + ColumnsType, + TablePaginationConfig, + TableSize, +} from 'src/components/Table'; +import MetadataBar, { + ContentType, + MetadataType, +} from 'src/components/MetadataBar'; +import Alert from 'src/components/Alert'; +import { useApiV1Resource } from 'src/hooks/apiResources'; +import HeaderWithRadioGroup from 'src/components/Table/header-renderers/HeaderWithRadioGroup'; +import TableControls from './DrillDetailTableControls'; +import { getDrillPayload } from './utils'; +import { Dataset, ResultsPage } from './types'; + +const PAGE_SIZE = 50; + +interface DataType { + [key: string]: any; +} + +// Must be outside of the main component due to problems in +// react-resize-detector with conditional rendering +// https://github.com/maslianok/react-resize-detector/issues/178 +function Resizable({ children }: { children: ReactElement }) { + const { ref, height } = useResizeDetector(); + return ( + <div ref={ref} css={{ flex: 1 }}> + {React.cloneElement(children, { height })} + </div> + ); +} + +enum TimeFormatting { + Original, + Formatted, +} + +export default function DrillDetailPane({ + formData, + initialFilters, +}: { + formData: QueryFormData; + initialFilters: BinaryQueryObjectFilterClause[]; +}) { + const theme = useTheme(); + const [pageIndex, setPageIndex] = useState(0); + const lastPageIndex = useRef(pageIndex); + const [filters, setFilters] = useState(initialFilters); + const [isLoading, setIsLoading] = useState(false); + const [responseError, setResponseError] = useState(''); + const [resultsPages, setResultsPages] = useState<Map<number, ResultsPage>>( + new Map(), + ); + const [timeFormatting, setTimeFormatting] = useState({}); + + const SAMPLES_ROW_LIMIT = useSelector( + (state: { common: { conf: JsonObject } }) => + state.common.conf.SAMPLES_ROW_LIMIT, + ); + + // Extract datasource ID/type from string ID + const [datasourceId, datasourceType] = useMemo( + () => formData.datasource.split('__'), + [formData.datasource], + ); + + // Get page of results + const resultsPage = useMemo(() => { + const nextResultsPage = resultsPages.get(pageIndex); + if (nextResultsPage) { + lastPageIndex.current = pageIndex; + return nextResultsPage; + } + + return resultsPages.get(lastPageIndex.current); + }, [pageIndex, resultsPages]); + + const mappedColumns: ColumnsType<DataType> = useMemo( + () => + resultsPage?.colNames.map((column, index) => ({ + key: column, + dataIndex: column, + title: + resultsPage?.colTypes[index] === GenericDataType.TEMPORAL ? ( + <HeaderWithRadioGroup + headerTitle={column} + groupTitle={t('Formatting')} + groupOptions={[ + { label: t('Original value'), value: TimeFormatting.Original }, + { + label: t('Formatted value'), + value: TimeFormatting.Formatted, + }, + ]} + value={ + timeFormatting[column] === TimeFormatting.Original + ? TimeFormatting.Original + : TimeFormatting.Formatted + } + onChange={value => + setTimeFormatting(state => ({ ...state, [column]: value })) + } + /> + ) : ( + column + ), + render: value => { + if (value === true || value === false) { + return <BooleanCell value={value} />; + } + if (value === null) { + return <NullCell />; + } + if ( + resultsPage?.colTypes[index] === GenericDataType.TEMPORAL && + timeFormatting[column] !== TimeFormatting.Original && + (typeof value === 'number' || value instanceof Date) + ) { + return <TimeCell value={value} />; + } + return String(value); + }, + width: 150, + })) || [], + [resultsPage?.colNames, resultsPage?.colTypes, timeFormatting], + ); + + const data: DataType[] = useMemo( + () => + resultsPage?.data.map((row, index) => + resultsPage?.colNames.reduce( + (acc, curr) => ({ ...acc, [curr]: row[curr] }), + { + key: index, + }, + ), + ) || [], + [resultsPage?.colNames, resultsPage?.data], + ); + + // Clear cache on reload button click + const handleReload = useCallback(() => { + setResponseError(''); + setResultsPages(new Map()); + setPageIndex(0); + }, []); + + // Clear cache and reset page index if filters change + useEffect(() => { + setResponseError(''); + setResultsPages(new Map()); + setPageIndex(0); + }, [filters]); + + // Update cache order if page in cache + useEffect(() => { + if ( + resultsPages.has(pageIndex) && + [...resultsPages.keys()].at(-1) !== pageIndex + ) { + const nextResultsPages = new Map(resultsPages); + nextResultsPages.delete(pageIndex); + setResultsPages( + nextResultsPages.set( + pageIndex, + resultsPages.get(pageIndex) as ResultsPage, + ), + ); + } + }, [pageIndex, resultsPages]); + + // Download page of results & trim cache if page not in cache + useEffect(() => { + if (!responseError && !isLoading && !resultsPages.has(pageIndex)) { + setIsLoading(true); + const jsonPayload = getDrillPayload(formData, filters) ?? {}; + const cachePageLimit = Math.ceil(SAMPLES_ROW_LIMIT / PAGE_SIZE); + getDatasourceSamples( + datasourceType, + datasourceId, + false, + jsonPayload, + PAGE_SIZE, + pageIndex + 1, + ) + .then(response => { + setResultsPages( + new Map([ + ...[...resultsPages.entries()].slice(-cachePageLimit + 1), + [ + pageIndex, + { + total: response.total_count, + data: response.data, + colNames: ensureIsArray(response.colnames), + colTypes: ensureIsArray(response.coltypes), + }, + ], + ]), + ); + setResponseError(''); + }) + .catch(error => { + setResponseError(`${error.name}: ${error.message}`); + }) + .finally(() => { + setIsLoading(false); + }); + } + }, [ + SAMPLES_ROW_LIMIT, + datasourceId, + datasourceType, + filters, + formData, + isLoading, + pageIndex, + responseError, + resultsPages, + ]); + + // Get datasource metadata + const response = useApiV1Resource<Dataset>(`/api/v1/dataset/${datasourceId}`); + + const bootstrapping = + (!responseError && !resultsPages.size) || response.status === 'loading'; + + let tableContent = null; + if (responseError) { + // Render error if page download failed + tableContent = ( + <pre + css={css` + margin-top: ${theme.gridUnit * 4}px; + `} + > + {responseError} + </pre> + ); + } else if (bootstrapping) { + // Render loading if first page hasn't loaded + tableContent = <Loading />; + } else if (resultsPage?.total === 0) { + // Render empty state if no results are returned for page + const title = t('No rows were returned for this dataset'); + tableContent = <EmptyStateMedium image="document.svg" title={title} />; + } else { + // Render table if at least one page has successfully loaded + tableContent = ( + <Resizable> + <Table + data={data} + columns={mappedColumns} + size={TableSize.SMALL} + defaultPageSize={PAGE_SIZE} + recordCount={resultsPage?.total} + usePagination + loading={isLoading} + onChange={(pagination: TablePaginationConfig) => + setPageIndex(pagination.current ? pagination.current - 1 : 0) + } + resizable + virtualize + /> + </Resizable> + ); + } + + const metadata = useMemo(() => { + const { status, result } = response; + const items: ContentType[] = []; + if (result) { + const { + changed_on_humanized, + created_on_humanized, + description, + table_name, + changed_by, + created_by, + owners, + } = result; + const notAvailable = t('Not available'); + const createdBy = + `${created_by?.first_name ?? ''} ${ + created_by?.last_name ?? '' + }`.trim() || notAvailable; + const modifiedBy = changed_by + ? `${changed_by.first_name} ${changed_by.last_name}` + : notAvailable; + const formattedOwners = + owners.length > 0 + ? owners.map(owner => `${owner.first_name} ${owner.last_name}`) + : [notAvailable]; + items.push({ + type: MetadataType.TABLE, + title: table_name, + }); + items.push({ + type: MetadataType.LAST_MODIFIED, + value: changed_on_humanized, + modifiedBy, + }); + items.push({ + type: MetadataType.OWNER, + createdBy, + owners: formattedOwners, + createdOn: created_on_humanized, + }); + if (description) { + items.push({ + type: MetadataType.DESCRIPTION, + value: description, + }); + } + } + return ( + <div + css={css` + display: flex; + margin-bottom: ${theme.gridUnit * 4}px; + `} + > + {status === 'complete' && ( + <MetadataBar items={items} tooltipPlacement="bottom" /> + )} + {status === 'error' && ( + <Alert + type="error" + message={t('There was an error loading the dataset metadata')} + /> + )} + </div> + ); + }, [response, theme.gridUnit]); + + return ( + <> + {!bootstrapping && metadata} + {!bootstrapping && ( + <TableControls + filters={filters} + setFilters={setFilters} + totalCount={resultsPage?.total} + loading={isLoading} + onReload={handleReload} + /> + )} + {tableContent} + </> + ); +} diff --git a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.test.tsx b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.test.tsx new file mode 100644 index 0000000000000..179fc8ee35760 --- /dev/null +++ b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.test.tsx @@ -0,0 +1,109 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import TableControls from './DrillDetailTableControls'; + +const setFilters = jest.fn(); +const onReload = jest.fn(); +const setup = (overrides: Record<string, any> = {}) => { + const props = { + filters: [], + setFilters, + onReload, + loading: false, + totalCount: 0, + ...overrides, + }; + return render(<TableControls {...props} />); +}; +test('should render', () => { + const { container } = setup(); + expect(container).toBeInTheDocument(); +}); + +test('should show 0 rows', () => { + setup(); + expect(screen.getByText('0 rows')).toBeInTheDocument(); +}); + +test('should show the correct amount of rows', () => { + setup({ + totalCount: 10, + }); + expect(screen.getByText('10 rows')).toBeInTheDocument(); +}); + +test('should render the reload button', () => { + setup(); + expect(screen.getByRole('button', { name: 'Reload' })).toBeInTheDocument(); +}); + +test('should show the loading indicator', () => { + setup({ + loading: true, + }); + expect(screen.getByText('Loading...')).toBeInTheDocument(); +}); + +test('should call onreload', () => { + setup(); + userEvent.click(screen.getByRole('button', { name: 'Reload' })); + expect(onReload).toHaveBeenCalledTimes(1); +}); + +test('should render with filters', () => { + setup({ + filters: [ + { + col: 'platform', + op: '==', + val: 'GB', + }, + { + col: 'lang', + op: '==', + val: 'IT', + }, + ], + }); + expect(screen.getByText('platform')).toBeInTheDocument(); + expect(screen.getByText('GB')).toBeInTheDocument(); + expect(screen.getByText('lang')).toBeInTheDocument(); + expect(screen.getByText('IT')).toBeInTheDocument(); +}); + +test('should remove the filters on close', () => { + setup({ + filters: [ + { + col: 'platform', + op: '==', + val: 'GB', + }, + ], + }); + expect(screen.getByText('platform')).toBeInTheDocument(); + expect(screen.getByText('GB')).toBeInTheDocument(); + + userEvent.click(screen.getByRole('img', { name: 'close' })); + + expect(setFilters).toHaveBeenCalledWith([]); +}); diff --git a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.tsx b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.tsx new file mode 100644 index 0000000000000..523cbaff3e45a --- /dev/null +++ b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.tsx @@ -0,0 +1,140 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useCallback, useMemo } from 'react'; +import { Tag } from 'antd'; +import { + BinaryQueryObjectFilterClause, + css, + isAdhocColumn, + t, + useTheme, +} from '@superset-ui/core'; +import RowCountLabel from 'src/explore/components/RowCountLabel'; +import Icons from 'src/components/Icons'; + +export default function TableControls({ + filters, + setFilters, + totalCount, + loading, + onReload, +}: { + filters: BinaryQueryObjectFilterClause[]; + setFilters: (filters: BinaryQueryObjectFilterClause[]) => void; + totalCount?: number; + loading: boolean; + onReload: () => void; +}) { + const theme = useTheme(); + const filterMap: Record<string, BinaryQueryObjectFilterClause> = useMemo( + () => + Object.assign( + {}, + ...filters.map(filter => ({ + [isAdhocColumn(filter.col) + ? (filter.col.label as string) + : filter.col]: filter, + })), + ), + [filters], + ); + + const removeFilter = useCallback( + colName => { + const updatedFilterMap = { ...filterMap }; + delete updatedFilterMap[colName]; + setFilters([...Object.values(updatedFilterMap)]); + }, + [filterMap, setFilters], + ); + + const filterTags = useMemo( + () => + Object.entries(filterMap) + .map(([colName, { val, formattedVal }]) => ({ + colName, + val: formattedVal ?? val, + })) + .sort((a, b) => a.colName.localeCompare(b.colName)), + [filterMap], + ); + + return ( + <div + css={css` + display: flex; + justify-content: space-between; + padding: ${theme.gridUnit / 2}px 0; + margin-bottom: ${theme.gridUnit * 2}px; + `} + > + <div + css={css` + display: flex; + flex-wrap: wrap; + margin-bottom: -${theme.gridUnit * 4}px; + `} + > + {filterTags.map(({ colName, val }) => ( + <Tag + closable + onClose={removeFilter.bind(null, colName)} + key={colName} + css={css` + height: ${theme.gridUnit * 6}px; + display: flex; + align-items: center; + padding: ${theme.gridUnit / 2}px ${theme.gridUnit * 2}px; + margin-right: ${theme.gridUnit * 4}px; + margin-bottom: ${theme.gridUnit * 4}px; + line-height: 1.2; + `} + data-test="filter-col" + > + <span + css={css` + margin-right: ${theme.gridUnit}px; + `} + > + {colName} + </span> + <strong data-test="filter-val">{val}</strong> + </Tag> + ))} + </div> + <div + css={css` + display: flex; + align-items: center; + height: min-content; + `} + > + <RowCountLabel loading={loading && !totalCount} rowcount={totalCount} /> + <Icons.ReloadOutlined + iconColor={theme.colors.grayscale.light1} + iconSize="l" + aria-label={t('Reload')} + role="button" + onClick={onReload} + /> + </div> + </div> + ); +} diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboard_list.helper.ts b/superset-frontend/src/components/Chart/DrillDetail/index.ts similarity index 91% rename from superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboard_list.helper.ts rename to superset-frontend/src/components/Chart/DrillDetail/index.ts index 5ccb39432cd81..cf154680becb7 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboard_list.helper.ts +++ b/superset-frontend/src/components/Chart/DrillDetail/index.ts @@ -16,4 +16,5 @@ * specific language governing permissions and limitations * under the License. */ -export const DASHBOARD_LIST = '/dashboard/list/'; + +export { default as DrillDetailMenuItems } from './DrillDetailMenuItems'; diff --git a/superset-frontend/src/views/CRUD/chart/types.ts b/superset-frontend/src/components/Chart/DrillDetail/types.ts similarity index 60% rename from superset-frontend/src/views/CRUD/chart/types.ts rename to superset-frontend/src/components/Chart/DrillDetail/types.ts index e16b42a23f185..ea49c22ce3f10 100644 --- a/superset-frontend/src/views/CRUD/chart/types.ts +++ b/superset-frontend/src/components/Chart/DrillDetail/types.ts @@ -16,13 +16,30 @@ * specific language governing permissions and limitations * under the License. */ -export type ChartObject = { - slice_name?: string; - description?: string; - viz_type?: string; - params?: string; - cache_timeout?: number; - datasource_id?: number; - datasource_type?: number; - is_managed_externally: boolean; +import { GenericDataType } from '@superset-ui/core'; + +export type ResultsPage = { + total: number; + data: Record<string, any>[]; + colNames: string[]; + colTypes: GenericDataType[]; +}; + +export type Dataset = { + changed_by?: { + first_name: string; + last_name: string; + }; + created_by?: { + first_name: string; + last_name: string; + }; + changed_on_humanized: string; + created_on_humanized: string; + description: string; + table_name: string; + owners: { + first_name: string; + last_name: string; + }[]; }; diff --git a/superset-frontend/src/components/Chart/DrillDetail/utils.ts b/superset-frontend/src/components/Chart/DrillDetail/utils.ts new file mode 100644 index 0000000000000..03494024a9855 --- /dev/null +++ b/superset-frontend/src/components/Chart/DrillDetail/utils.ts @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { omit } from 'lodash'; +import { + ensureIsArray, + QueryFormData, + BinaryQueryObjectFilterClause, + buildQueryObject, +} from '@superset-ui/core'; + +export function getDrillPayload( + queryFormData?: QueryFormData, + drillFilters?: BinaryQueryObjectFilterClause[], +) { + if (!queryFormData) { + return undefined; + } + const queryObject = buildQueryObject(queryFormData); + const extras = omit(queryObject.extras, 'having'); + const filters = [ + ...ensureIsArray(queryObject.filters), + ...ensureIsArray(drillFilters).map(f => omit(f, 'formattedVal')), + ]; + return { + granularity: queryObject.granularity, + time_range: queryObject.time_range, + filters, + extras, + }; +} diff --git a/superset-frontend/src/components/Chart/chartAction.js b/superset-frontend/src/components/Chart/chartAction.js index b9aeffec4a4b8..7418a8f8b72c9 100644 --- a/superset-frontend/src/components/Chart/chartAction.js +++ b/superset-frontend/src/components/Chart/chartAction.js @@ -19,7 +19,7 @@ /* eslint no-undef: 'error' */ /* eslint no-param-reassign: ["error", { "props": false }] */ import moment from 'moment'; -import { t, SupersetClient } from '@superset-ui/core'; +import { t, SupersetClient, isDefined } from '@superset-ui/core'; import { getControlsState } from 'src/explore/store'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import { @@ -30,10 +30,7 @@ import { shouldUseLegacyApi, getChartDataUri, } from 'src/explore/exploreUtils'; -import { - requiresQuery, - ANNOTATION_SOURCE_TYPES, -} from 'src/modules/AnnotationTypes'; +import { requiresQuery } from 'src/modules/AnnotationTypes'; import { addDangerToast } from 'src/components/MessageToasts/actions'; import { logEvent } from 'src/logger/actions'; @@ -139,6 +136,7 @@ const legacyChartDataRequest = async ( ...requestParams, url, postPayload: { form_data: formData }, + parseMethod: 'json-bigint', }; const clientMethod = @@ -196,6 +194,7 @@ const v1ChartDataRequest = async ( url, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), + parseMethod: 'json-bigint', }; return SupersetClient.post(querySettings); @@ -288,26 +287,35 @@ export function runAnnotationQuery({ : undefined; } - const isNative = annotation.sourceType === ANNOTATION_SOURCE_TYPES.NATIVE; - const url = getAnnotationJsonUrl( - annotation.value, - sliceFormData, - isNative, - force, - ); + const url = getAnnotationJsonUrl(annotation.value, force); const controller = new AbortController(); const { signal } = controller; dispatch(annotationQueryStarted(annotation, controller, sliceKey)); - return SupersetClient.get({ + const annotationIndex = fd?.annotation_layers?.findIndex( + it => it.name === annotation.name, + ); + if (annotationIndex >= 0) { + fd.annotation_layers[annotationIndex].overrides = sliceFormData; + } + + return SupersetClient.post({ url, signal, timeout: timeout * 1000, + headers: { 'Content-Type': 'application/json' }, + jsonPayload: buildV1ChartDataPayload({ + formData: fd, + force, + resultFormat: 'json', + resultType: 'full', + }), }) - .then(({ json }) => - dispatch(annotationQuerySuccess(annotation, json, sliceKey)), - ) + .then(({ json }) => { + const data = json?.result?.[0]?.annotation_data?.[annotation.name]; + return dispatch(annotationQuerySuccess(annotation, { data }, sliceKey)); + }) .catch(response => getClientErrorObject(response).then(err => { if (err.statusText === 'timeout') { @@ -598,10 +606,32 @@ export function refreshChart(chartKey, force, dashboardId) { }; } -export const getDatasetSamples = async (datasetId, force) => { - const endpoint = `/api/v1/dataset/${datasetId}/samples?force=${force}`; +export const getDatasourceSamples = async ( + datasourceType, + datasourceId, + force, + jsonPayload, + perPage, + page, +) => { try { - const response = await SupersetClient.get({ endpoint }); + const searchParams = { + force, + datasource_type: datasourceType, + datasource_id: datasourceId, + }; + + if (isDefined(perPage) && isDefined(page)) { + searchParams.per_page = perPage; + searchParams.page = page; + } + + const response = await SupersetClient.post({ + endpoint: '/datasource/samples', + jsonPayload, + searchParams, + }); + return response.json.result; } catch (err) { const clientError = await getClientErrorObject(err); diff --git a/superset-frontend/src/components/Chart/chartActions.test.js b/superset-frontend/src/components/Chart/chartActions.test.js index 7c7af00a4b2e4..65b008de62f52 100644 --- a/superset-frontend/src/components/Chart/chartActions.test.js +++ b/superset-frontend/src/components/Chart/chartActions.test.js @@ -94,6 +94,25 @@ describe('chart actions', () => { ); expect(dispatch.args[0][0].type).toBe(actions.CHART_UPDATE_STARTED); }); + + it('should handle the bigint without regression', async () => { + getChartDataUriStub.restore(); + const mockBigIntUrl = '/mock/chart/data/bigint'; + const expectedBigNumber = '9223372036854775807'; + fetchMock.post(mockBigIntUrl, `{ "value": ${expectedBigNumber} }`, { + overwriteRoutes: true, + }); + getChartDataUriStub = sinon + .stub(exploreUtils, 'getChartDataUri') + .callsFake(() => URI(mockBigIntUrl)); + + const { json } = await actions.getChartDataRequest({ + formData: fakeMetadata, + }); + + expect(fetchMock.calls(mockBigIntUrl)).toHaveLength(1); + expect(json.value.toString()).toEqual(expectedBigNumber); + }); }); describe('legacy API', () => { @@ -194,5 +213,24 @@ describe('chart actions', () => { setupDefaultFetchMock(); }); }); + + it('should handle the bigint without regression', async () => { + getExploreUrlStub.restore(); + const mockBigIntUrl = '/mock/chart/data/bigint'; + const expectedBigNumber = '9223372036854775807'; + fetchMock.post(mockBigIntUrl, `{ "value": ${expectedBigNumber} }`, { + overwriteRoutes: true, + }); + getExploreUrlStub = sinon + .stub(exploreUtils, 'getExploreUrl') + .callsFake(() => mockBigIntUrl); + + const { json } = await actions.getChartDataRequest({ + formData: fakeMetadata, + }); + + expect(fetchMock.calls(mockBigIntUrl)).toHaveLength(1); + expect(json.result[0].value.toString()).toEqual(expectedBigNumber); + }); }); }); diff --git a/superset-frontend/src/components/Chart/chartReducer.ts b/superset-frontend/src/components/Chart/chartReducer.ts index 010140584c2b1..1d1ae60ea614e 100644 --- a/superset-frontend/src/components/Chart/chartReducer.ts +++ b/superset-frontend/src/components/Chart/chartReducer.ts @@ -22,6 +22,7 @@ import { HYDRATE_DASHBOARD } from 'src/dashboard/actions/hydrate'; import { DatasourcesAction } from 'src/dashboard/actions/datasources'; import { ChartState } from 'src/explore/types'; import { getFormDataFromControls } from 'src/explore/controlUtils'; +import { HYDRATE_EXPLORE } from 'src/explore/actions/hydrateExplore'; import { now } from 'src/utils/dates'; import * as actions from './chartAction'; @@ -129,10 +130,7 @@ export default function chartReducer( return { ...state, latestQueryFormData: action.value }; }, [actions.ANNOTATION_QUERY_STARTED](state) { - if ( - state.annotationQuery && - state.annotationQuery[action.annotation.name] - ) { + if (state.annotationQuery?.[action.annotation.name]) { state.annotationQuery[action.annotation.name].abort(); } const annotationQuery = { @@ -194,7 +192,7 @@ export default function chartReducer( delete charts[key]; return charts; } - if (action.type === HYDRATE_DASHBOARD) { + if (action.type === HYDRATE_DASHBOARD || action.type === HYDRATE_EXPLORE) { return { ...action.data.charts }; } if (action.type === DatasourcesAction.SET_DATASOURCES) { diff --git a/superset-frontend/src/components/Chart/utils.test.ts b/superset-frontend/src/components/Chart/utils.test.ts new file mode 100644 index 0000000000000..b8de155a2afce --- /dev/null +++ b/superset-frontend/src/components/Chart/utils.test.ts @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { getMenuAdjustedY } from './utils'; + +const originalInnerHeight = window.innerHeight; + +beforeEach(() => { + window.innerHeight = 500; +}); + +afterEach(() => { + window.innerHeight = originalInnerHeight; +}); + +test('correctly positions at upper edge of screen', () => { + expect(getMenuAdjustedY(75, 1)).toEqual(75); // No adjustment + expect(getMenuAdjustedY(75, 2)).toEqual(75); // No adjustment + expect(getMenuAdjustedY(75, 3)).toEqual(75); // No adjustment +}); + +test('correctly positions at lower edge of screen', () => { + expect(getMenuAdjustedY(425, 1)).toEqual(425); // No adjustment + expect(getMenuAdjustedY(425, 2)).toEqual(404); // Adjustment + expect(getMenuAdjustedY(425, 3)).toEqual(372); // Adjustment +}); diff --git a/superset-frontend/src/components/Chart/utils.ts b/superset-frontend/src/components/Chart/utils.ts new file mode 100644 index 0000000000000..54fc5e892699e --- /dev/null +++ b/superset-frontend/src/components/Chart/utils.ts @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const MENU_ITEM_HEIGHT = 32; +const MENU_VERTICAL_SPACING = 32; + +/** + * Calculates an adjusted Y-offset for a menu or submenu to prevent that + * menu from appearing offscreen + * + * @param clientY The original Y-offset + * @param itemsCount The number of menu items + */ +export function getMenuAdjustedY(clientY: number, itemsCount: number) { + // Viewport height + const vh = Math.max( + document.documentElement.clientHeight || 0, + window.innerHeight || 0, + ); + + const menuHeight = MENU_ITEM_HEIGHT * itemsCount + MENU_VERTICAL_SPACING; + // Always show the context menu inside the viewport + return vh - clientY < menuHeight ? vh - menuHeight : clientY; +} diff --git a/superset-frontend/src/components/Checkbox/Checkbox.tsx b/superset-frontend/src/components/Checkbox/Checkbox.tsx index 7162929a967f0..249fca01841e1 100644 --- a/superset-frontend/src/components/Checkbox/Checkbox.tsx +++ b/superset-frontend/src/components/Checkbox/Checkbox.tsx @@ -24,6 +24,7 @@ export interface CheckboxProps { checked: boolean; onChange: (val?: boolean) => void; style?: React.CSSProperties; + className?: string; } const Styles = styled.span` @@ -33,7 +34,12 @@ const Styles = styled.span` } `; -export default function Checkbox({ checked, onChange, style }: CheckboxProps) { +export default function Checkbox({ + checked, + onChange, + style, + className, +}: CheckboxProps) { return ( <Styles style={style} @@ -44,6 +50,7 @@ export default function Checkbox({ checked, onChange, style }: CheckboxProps) { tabIndex={0} aria-checked={checked} aria-label="Checkbox" + className={className || ''} > {checked ? <CheckboxChecked /> : <CheckboxUnchecked />} </Styles> diff --git a/superset-frontend/src/components/ConfirmStatusChange/index.tsx b/superset-frontend/src/components/ConfirmStatusChange/index.tsx index a11bc0eeab47b..09c374bdb5c07 100644 --- a/superset-frontend/src/components/ConfirmStatusChange/index.tsx +++ b/superset-frontend/src/components/ConfirmStatusChange/index.tsx @@ -69,7 +69,7 @@ export default function ConfirmStatusChange({ return ( <> - {children && children(showConfirm)} + {children?.(showConfirm)} <DeleteModal description={description} onConfirm={confirm} diff --git a/superset-frontend/src/components/CopyToClipboard/index.jsx b/superset-frontend/src/components/CopyToClipboard/index.jsx index 95b6cdfdc0f70..d4f74904dbca4 100644 --- a/superset-frontend/src/components/CopyToClipboard/index.jsx +++ b/superset-frontend/src/components/CopyToClipboard/index.jsx @@ -37,7 +37,7 @@ const propTypes = { }; const defaultProps = { - copyNode: <span>Copy</span>, + copyNode: <span>{t('Copy')}</span>, onCopyEnd: () => {}, shouldShowText: true, wrapped: true, diff --git a/superset-frontend/src/components/CronPicker/CronPicker.tsx b/superset-frontend/src/components/CronPicker/CronPicker.tsx index 631f7f24b4302..385062e0cec85 100644 --- a/superset-frontend/src/components/CronPicker/CronPicker.tsx +++ b/superset-frontend/src/components/CronPicker/CronPicker.tsx @@ -110,6 +110,9 @@ export const CronPicker = styled((props: CronProps) => ( <ReactCronPicker locale={LOCALE} {...props} /> </ConfigProvider> ))` + .react-js-cron-field { + margin-bottom: 0px; + } .react-js-cron-select:not(.react-js-cron-custom-select) > div:first-of-type, .react-js-cron-custom-select { border-radius: ${({ theme }) => theme.gridUnit}px; @@ -119,4 +122,10 @@ export const CronPicker = styled((props: CronProps) => ( .react-js-cron-custom-select > div:first-of-type { border-radius: ${({ theme }) => theme.gridUnit}px; } + .react-js-cron-custom-select .ant-select-selection-placeholder { + flex: auto; + } + .react-js-cron-custom-select .ant-select-selection-overflow-item { + align-self: center; + } `; diff --git a/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx b/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx index 272249b549600..57b6a539ae188 100644 --- a/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx +++ b/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx @@ -18,25 +18,23 @@ */ import React from 'react'; +import fetchMock from 'fetch-mock'; import { render, screen, waitFor } from 'spec/helpers/testing-library'; -import { SupersetClient } from '@superset-ui/core'; +import { queryClient } from 'src/views/QueryProvider'; import userEvent from '@testing-library/user-event'; import DatabaseSelector, { DatabaseSelectorProps } from '.'; import { EmptyStateSmall } from '../EmptyState'; -const SupersetClientGet = jest.spyOn(SupersetClient, 'get'); - const createProps = (): DatabaseSelectorProps => ({ db: { id: 1, database_name: 'test', backend: 'test-postgresql', - allow_multi_schema_metadata_fetch: false, }, formMode: false, isDatabaseSelectEnabled: true, readOnly: false, - schema: undefined, + schema: 'public', sqlLabMode: true, getDbList: jest.fn(), handleError: jest.fn(), @@ -45,129 +43,133 @@ const createProps = (): DatabaseSelectorProps => ({ onSchemasLoad: jest.fn(), }); -beforeEach(() => { - jest.resetAllMocks(); - SupersetClientGet.mockImplementation( - async ({ endpoint }: { endpoint: string }) => { - if (endpoint.includes('schemas')) { - return { - json: { result: ['information_schema', 'public'] }, - } as any; - } - if (endpoint.includes('/function_names')) { - return { - json: { function_names: [] }, - } as any; - } - return { - json: { - count: 2, - description_columns: {}, - ids: [1, 2], - label_columns: { - allow_file_upload: 'Allow Csv Upload', - allow_ctas: 'Allow Ctas', - allow_cvas: 'Allow Cvas', - allow_dml: 'Allow Dml', - allow_multi_schema_metadata_fetch: - 'Allow Multi Schema Metadata Fetch', - allow_run_async: 'Allow Run Async', - allows_cost_estimate: 'Allows Cost Estimate', - allows_subquery: 'Allows Subquery', - allows_virtual_table_explore: 'Allows Virtual Table Explore', - disable_data_preview: 'Disables SQL Lab Data Preview', - backend: 'Backend', - changed_on: 'Changed On', - changed_on_delta_humanized: 'Changed On Delta Humanized', - 'created_by.first_name': 'Created By First Name', - 'created_by.last_name': 'Created By Last Name', - database_name: 'Database Name', - explore_database_id: 'Explore Database Id', - expose_in_sqllab: 'Expose In Sqllab', - force_ctas_schema: 'Force Ctas Schema', - id: 'Id', - }, - list_columns: [ - 'allow_file_upload', - 'allow_ctas', - 'allow_cvas', - 'allow_dml', - 'allow_multi_schema_metadata_fetch', - 'allow_run_async', - 'allows_cost_estimate', - 'allows_subquery', - 'allows_virtual_table_explore', - 'disable_data_preview', - 'backend', - 'changed_on', - 'changed_on_delta_humanized', - 'created_by.first_name', - 'created_by.last_name', - 'database_name', - 'explore_database_id', - 'expose_in_sqllab', - 'force_ctas_schema', - 'id', - ], - list_title: 'List Database', - order_columns: [ - 'allow_file_upload', - 'allow_dml', - 'allow_run_async', - 'changed_on', - 'changed_on_delta_humanized', - 'created_by.first_name', - 'database_name', - 'expose_in_sqllab', - ], - result: [ - { - allow_file_upload: false, - allow_ctas: false, - allow_cvas: false, - allow_dml: false, - allow_multi_schema_metadata_fetch: false, - allow_run_async: false, - allows_cost_estimate: null, - allows_subquery: true, - allows_virtual_table_explore: true, - disable_data_preview: false, - backend: 'postgresql', - changed_on: '2021-03-09T19:02:07.141095', - changed_on_delta_humanized: 'a day ago', - created_by: null, - database_name: 'test-postgres', - explore_database_id: 1, - expose_in_sqllab: true, - force_ctas_schema: null, - id: 1, - }, - { - allow_csv_upload: false, - allow_ctas: false, - allow_cvas: false, - allow_dml: false, - allow_multi_schema_metadata_fetch: false, - allow_run_async: false, - allows_cost_estimate: null, - allows_subquery: true, - allows_virtual_table_explore: true, - disable_data_preview: false, - backend: 'mysql', - changed_on: '2021-03-09T19:02:07.141095', - changed_on_delta_humanized: 'a day ago', - created_by: null, - database_name: 'test-mysql', - explore_database_id: 1, - expose_in_sqllab: true, - force_ctas_schema: null, - id: 2, - }, - ], - }, - } as any; +const fakeDatabaseApiResult = { + count: 2, + description_columns: {}, + ids: [1, 2], + label_columns: { + allow_file_upload: 'Allow Csv Upload', + allow_ctas: 'Allow Ctas', + allow_cvas: 'Allow Cvas', + allow_dml: 'Allow Dml', + allow_run_async: 'Allow Run Async', + allows_cost_estimate: 'Allows Cost Estimate', + allows_subquery: 'Allows Subquery', + allows_virtual_table_explore: 'Allows Virtual Table Explore', + disable_data_preview: 'Disables SQL Lab Data Preview', + backend: 'Backend', + changed_on: 'Changed On', + changed_on_delta_humanized: 'Changed On Delta Humanized', + 'created_by.first_name': 'Created By First Name', + 'created_by.last_name': 'Created By Last Name', + database_name: 'Database Name', + explore_database_id: 'Explore Database Id', + expose_in_sqllab: 'Expose In Sqllab', + force_ctas_schema: 'Force Ctas Schema', + id: 'Id', + }, + list_columns: [ + 'allow_file_upload', + 'allow_ctas', + 'allow_cvas', + 'allow_dml', + 'allow_run_async', + 'allows_cost_estimate', + 'allows_subquery', + 'allows_virtual_table_explore', + 'disable_data_preview', + 'backend', + 'changed_on', + 'changed_on_delta_humanized', + 'created_by.first_name', + 'created_by.last_name', + 'database_name', + 'explore_database_id', + 'expose_in_sqllab', + 'force_ctas_schema', + 'id', + ], + list_title: 'List Database', + order_columns: [ + 'allow_file_upload', + 'allow_dml', + 'allow_run_async', + 'changed_on', + 'changed_on_delta_humanized', + 'created_by.first_name', + 'database_name', + 'expose_in_sqllab', + ], + result: [ + { + allow_file_upload: false, + allow_ctas: false, + allow_cvas: false, + allow_dml: false, + allow_run_async: false, + allows_cost_estimate: null, + allows_subquery: true, + allows_virtual_table_explore: true, + disable_data_preview: false, + backend: 'postgresql', + changed_on: '2021-03-09T19:02:07.141095', + changed_on_delta_humanized: 'a day ago', + created_by: null, + database_name: 'test-postgres', + explore_database_id: 1, + expose_in_sqllab: true, + force_ctas_schema: null, + id: 1, }, - ); + { + allow_csv_upload: false, + allow_ctas: false, + allow_cvas: false, + allow_dml: false, + allow_run_async: false, + allows_cost_estimate: null, + allows_subquery: true, + allows_virtual_table_explore: true, + disable_data_preview: false, + backend: 'mysql', + changed_on: '2021-03-09T19:02:07.141095', + changed_on_delta_humanized: 'a day ago', + created_by: null, + database_name: 'test-mysql', + explore_database_id: 1, + expose_in_sqllab: true, + force_ctas_schema: null, + id: 2, + }, + ], +}; + +const fakeSchemaApiResult = { + count: 2, + result: ['information_schema', 'public'], +}; + +const fakeFunctionNamesApiResult = { + function_names: [], +}; + +const databaseApiRoute = 'glob:*/api/v1/database/?*'; +const schemaApiRoute = 'glob:*/api/v1/database/*/schemas/?*'; +const tablesApiRoute = 'glob:*/api/v1/database/*/tables/*'; + +function setupFetchMock() { + fetchMock.get(databaseApiRoute, fakeDatabaseApiResult); + fetchMock.get(schemaApiRoute, fakeSchemaApiResult); + fetchMock.get(tablesApiRoute, fakeFunctionNamesApiResult); +} + +beforeEach(() => { + queryClient.clear(); + setupFetchMock(); +}); + +afterEach(() => { + fetchMock.reset(); }); test('Should render', async () => { @@ -181,6 +183,8 @@ test('Refresh should work', async () => { render(<DatabaseSelector {...props} />, { useRedux: true }); + expect(fetchMock.calls(schemaApiRoute).length).toBe(0); + const select = screen.getByRole('combobox', { name: 'Select schema or type schema name', }); @@ -188,23 +192,22 @@ test('Refresh should work', async () => { userEvent.click(select); await waitFor(() => { - expect(SupersetClientGet).toBeCalledTimes(2); - expect(props.getDbList).toBeCalledTimes(0); + expect(fetchMock.calls(databaseApiRoute).length).toBe(1); + expect(fetchMock.calls(schemaApiRoute).length).toBe(1); expect(props.handleError).toBeCalledTimes(0); expect(props.onDbChange).toBeCalledTimes(0); expect(props.onSchemaChange).toBeCalledTimes(0); - expect(props.onSchemasLoad).toBeCalledTimes(0); }); + // click schema reload userEvent.click(screen.getByRole('button', { name: 'refresh' })); await waitFor(() => { - expect(SupersetClientGet).toBeCalledTimes(3); - expect(props.getDbList).toBeCalledTimes(1); + expect(fetchMock.calls(databaseApiRoute).length).toBe(1); + expect(fetchMock.calls(schemaApiRoute).length).toBe(2); expect(props.handleError).toBeCalledTimes(0); expect(props.onDbChange).toBeCalledTimes(0); expect(props.onSchemaChange).toBeCalledTimes(0); - expect(props.onSchemasLoad).toBeCalledTimes(2); }); }); @@ -220,9 +223,10 @@ test('Should database select display options', async () => { }); test('should show empty state if there are no options', async () => { - SupersetClientGet.mockImplementation( - async () => ({ json: { result: [] } } as any), - ); + fetchMock.reset(); + fetchMock.get(databaseApiRoute, { result: [] }); + fetchMock.get(schemaApiRoute, { result: [] }); + fetchMock.get(tablesApiRoute, { result: [] }); const props = createProps(); render( <DatabaseSelector @@ -272,7 +276,6 @@ test('Sends the correct db when changing the database', async () => { id: 2, database_name: 'test-mysql', backend: 'mysql', - allow_multi_schema_metadata_fetch: false, }), ), ); diff --git a/superset-frontend/src/components/DatabaseSelector/index.tsx b/superset-frontend/src/components/DatabaseSelector/index.tsx index 718177a13956f..d78a94bde60fc 100644 --- a/superset-frontend/src/components/DatabaseSelector/index.tsx +++ b/superset-frontend/src/components/DatabaseSelector/index.tsx @@ -19,11 +19,12 @@ import React, { ReactNode, useState, useMemo, useEffect } from 'react'; import { styled, SupersetClient, t } from '@superset-ui/core'; import rison from 'rison'; -import { Select } from 'src/components'; +import { AsyncSelect, Select } from 'src/components'; import Label from 'src/components/Label'; import { FormLabel } from 'src/components/Form'; import RefreshLabel from 'src/components/RefreshLabel'; import { useToasts } from 'src/components/MessageToasts/withToasts'; +import { useSchemas, SchemaOption } from 'src/hooks/apiResources'; const DatabaseSelectorWrapper = styled.div` ${({ theme }) => ` @@ -74,23 +75,19 @@ type DatabaseValue = { id: number; database_name: string; backend: string; - allow_multi_schema_metadata_fetch: boolean; }; export type DatabaseObject = { id: number; database_name: string; backend: string; - allow_multi_schema_metadata_fetch: boolean; }; -type SchemaValue = { label: string; value: string }; - export interface DatabaseSelectorProps { - db?: DatabaseObject; + db?: DatabaseObject | null; emptyState?: ReactNode; formMode?: boolean; - getDbList?: (arg0: any) => {}; + getDbList?: (arg0: any) => void; handleError: (msg: string) => void; isDatabaseSelectEnabled?: boolean; onDbChange?: (db: DatabaseObject) => void; @@ -117,6 +114,8 @@ const SelectLabel = ({ </LabelStyle> ); +const EMPTY_SCHEMA_OPTIONS: SchemaOption[] = []; + export default function DatabaseSelector({ db, formMode = false, @@ -132,23 +131,10 @@ export default function DatabaseSelector({ schema, sqlLabMode = false, }: DatabaseSelectorProps) { - const [loadingSchemas, setLoadingSchemas] = useState(false); - const [schemaOptions, setSchemaOptions] = useState<SchemaValue[]>([]); - const [currentDb, setCurrentDb] = useState<DatabaseValue | undefined>( - db - ? { - label: ( - <SelectLabel backend={db.backend} databaseName={db.database_name} /> - ), - value: db.id, - ...db, - } - : undefined, - ); - const [currentSchema, setCurrentSchema] = useState<SchemaValue | undefined>( - schema ? { label: schema, value: schema } : undefined, + const [currentDb, setCurrentDb] = useState<DatabaseValue | undefined>(); + const [currentSchema, setCurrentSchema] = useState<SchemaOption | undefined>( + schema ? { label: schema, value: schema, title: schema } : undefined, ); - const [refresh, setRefresh] = useState(0); const { addSuccessToast } = useToasts(); const loadDatabases = useMemo( @@ -199,8 +185,6 @@ export default function DatabaseSelector({ id: row.id, database_name: row.database_name, backend: row.backend, - allow_multi_schema_metadata_fetch: - row.allow_multi_schema_metadata_fetch, })); return { @@ -213,32 +197,55 @@ export default function DatabaseSelector({ ); useEffect(() => { - if (currentDb) { - setLoadingSchemas(true); - const queryParams = rison.encode({ force: refresh > 0 }); - const endpoint = `/api/v1/database/${currentDb.value}/schemas/?q=${queryParams}`; + setCurrentDb(current => + current?.id !== db?.id + ? db + ? { + label: ( + <SelectLabel + backend={db.backend} + databaseName={db.database_name} + /> + ), + value: db.id, + ...db, + } + : undefined + : current, + ); + }, [db]); - // TODO: Would be nice to add pagination in a follow-up. Needs endpoint changes. - SupersetClient.get({ endpoint }) - .then(({ json }) => { - const options = json.result.map((s: string) => ({ - value: s, - label: s, - title: s, - })); - if (onSchemasLoad) { - onSchemasLoad(options); - } - setSchemaOptions(options); - setLoadingSchemas(false); - if (refresh > 0) addSuccessToast('List refreshed'); - }) - .catch(() => { - setLoadingSchemas(false); - handleError(t('There was an error loading the schemas')); - }); + function changeSchema(schema: SchemaOption | undefined) { + setCurrentSchema(schema); + if (onSchemaChange) { + onSchemaChange(schema?.value); } - }, [currentDb, onSchemasLoad, refresh]); + } + + const { + data, + isFetching: loadingSchemas, + isFetched, + refetch, + } = useSchemas({ + dbId: currentDb?.value, + onSuccess: data => { + onSchemasLoad?.(data); + + if (data.length === 1) { + changeSchema(data[0]); + } else if (!data.find(schemaOption => schema === schemaOption.value)) { + changeSchema(undefined); + } + + if (isFetched) { + addSuccessToast('List refreshed'); + } + }, + onError: () => handleError(t('There was an error loading the schemas')), + }); + + const schemaOptions = data || EMPTY_SCHEMA_OPTIONS; function changeDataBase( value: { label: string; value: number }, @@ -254,13 +261,6 @@ export default function DatabaseSelector({ } } - function changeSchema(schema: SchemaValue) { - setCurrentSchema(schema); - if (onSchemaChange) { - onSchemaChange(schema.value); - } - } - function renderSelectRow(select: ReactNode, refreshBtn: ReactNode) { return ( <div className="section"> @@ -272,7 +272,7 @@ export default function DatabaseSelector({ function renderDatabaseSelect() { return renderSelectRow( - <Select + <AsyncSelect ariaLabel={t('Select database or type database name')} optionFilterProps={['database_name', 'value']} data-test="select-database" @@ -290,9 +290,9 @@ export default function DatabaseSelector({ } function renderSchemaSelect() { - const refreshIcon = !formMode && !readOnly && ( + const refreshIcon = !readOnly && ( <RefreshLabel - onClick={() => setRefresh(refresh + 1)} + onClick={() => refetch()} tooltipContent={t('Force refresh schema list')} /> ); @@ -302,11 +302,11 @@ export default function DatabaseSelector({ disabled={!currentDb || readOnly} header={<FormLabel>{t('Schema')}</FormLabel>} labelInValue - lazyLoading={false} loading={loadingSchemas} name="select-schema" + notFoundContent={t('No compatible schema found')} placeholder={t('Select schema or type schema name')} - onChange={item => changeSchema(item as SchemaValue)} + onChange={item => changeSchema(item as SchemaOption)} options={schemaOptions} showSearch value={currentSchema} diff --git a/superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx index a7c29c51d91f1..5ec5926808da8 100644 --- a/superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx @@ -190,7 +190,7 @@ const ChangeDatasourceModal: FunctionComponent<ChangeDatasourceModalProps> = ({ ); }); onHide(); - addSuccessToast('Successfully changed dataset!'); + addSuccessToast(t('Successfully changed dataset!')); }; const handlerCancelConfirm = () => { @@ -251,7 +251,7 @@ const ChangeDatasourceModal: FunctionComponent<ChangeDatasourceModalProps> = ({ show={show} onHide={onHide} responsive - title={t('Change dataset')} + title={t('Swap dataset')} width={confirmChange ? '432px' : ''} height={confirmChange ? 'auto' : '540px'} hideFooter={!confirmChange} @@ -260,13 +260,13 @@ const ChangeDatasourceModal: FunctionComponent<ChangeDatasourceModalProps> = ({ {confirmChange && ( <ConfirmModalStyled> <div className="btn-container"> - <Button onClick={handlerCancelConfirm}>Cancel</Button> + <Button onClick={handlerCancelConfirm}>{t('Cancel')}</Button> <Button className="proceed-btn" buttonStyle="primary" onClick={handleChangeConfirm} > - Proceed + {t('Proceed')} </Button> </div> </ConfirmModalStyled> diff --git a/superset-frontend/src/components/Datasource/CollectionTable.tsx b/superset-frontend/src/components/Datasource/CollectionTable.tsx index 194d3765792c9..baa53264c719f 100644 --- a/superset-frontend/src/components/Datasource/CollectionTable.tsx +++ b/superset-frontend/src/components/Datasource/CollectionTable.tsx @@ -33,6 +33,14 @@ interface CRUDCollectionProps { expandFieldset?: ReactNode; extraButtons?: ReactNode; itemGenerator?: () => any; + itemCellProps?: (( + val: unknown, + label: string, + record: any, + ) => React.DetailedHTMLProps< + React.TdHTMLAttributes<HTMLTableCellElement>, + HTMLTableCellElement + >)[]; itemRenderers?: (( val: unknown, onChange: () => void, @@ -206,7 +214,7 @@ export default class CRUDCollection extends React.PureComponent< getLabel(col: any) { const { columnLabels } = this.props; - let label = columnLabels && columnLabels[col] ? columnLabels[col] : col; + let label = columnLabels?.[col] ? columnLabels[col] : col; if (label.startsWith('__')) { // special label-free columns (ie: caret for expand, delete cross) label = ''; @@ -335,8 +343,14 @@ export default class CRUDCollection extends React.PureComponent< ); } + getCellProps(record: any, col: any) { + const cellPropsFn = this.props.itemCellProps?.[col]; + const val = record[col]; + return cellPropsFn ? cellPropsFn(val, this.getLabel(col), record) : {}; + } + renderCell(record: any, col: any) { - const renderer = this.props.itemRenderers && this.props.itemRenderers[col]; + const renderer = this.props.itemRenderers?.[col]; const val = record[col]; const onChange = this.onCellChange.bind(this, record.id, col); return renderer ? renderer(val, onChange, this.getLabel(col), record) : val; @@ -366,7 +380,9 @@ export default class CRUDCollection extends React.PureComponent< } tds = tds.concat( tableColumns.map(col => ( - <td key={col}>{this.renderCell(record, col)}</td> + <td {...this.getCellProps(record, col)} key={col}> + {this.renderCell(record, col)} + </td> )), ); if (allowAddItem) { diff --git a/superset-frontend/src/components/Datasource/DatasourceEditor.jsx b/superset-frontend/src/components/Datasource/DatasourceEditor.jsx index cfc826da6aa71..9e453dba3d854 100644 --- a/superset-frontend/src/components/Datasource/DatasourceEditor.jsx +++ b/superset-frontend/src/components/Datasource/DatasourceEditor.jsx @@ -25,7 +25,7 @@ import Alert from 'src/components/Alert'; import Badge from 'src/components/Badge'; import shortid from 'shortid'; import { styled, SupersetClient, t, withTheme } from '@superset-ui/core'; -import { Select, Row, Col } from 'src/components'; +import { Select, AsyncSelect, Row, Col } from 'src/components'; import { FormLabel } from 'src/components/Form'; import Button from 'src/components/Button'; import Tabs from 'src/components/Tabs'; @@ -135,10 +135,10 @@ const checkboxGenerator = (d, onChange) => ( <CheckboxControl value={d} onChange={onChange} /> ); const DATA_TYPES = [ - { value: 'STRING', label: 'STRING' }, - { value: 'NUMERIC', label: 'NUMERIC' }, - { value: 'DATETIME', label: 'DATETIME' }, - { value: 'BOOLEAN', label: 'BOOLEAN' }, + { value: 'STRING', label: t('STRING') }, + { value: 'NUMERIC', label: t('NUMERIC') }, + { value: 'DATETIME', label: t('DATETIME') }, + { value: 'BOOLEAN', label: t('BOOLEAN') }, ]; const DATASOURCE_TYPES_ARR = [ @@ -236,6 +236,7 @@ function ColumnCollectionTable({ <TextAreaControl language="markdown" offerEditInModal={false} + resize="vertical" /> } /> @@ -499,7 +500,7 @@ ColumnCollectionTable.defaultProps = { allowAddItem: false, allowEditDataType: false, itemGenerator: () => ({ - column_name: '<new column>', + column_name: t('<new column>'), filterable: true, groupby: true, }), @@ -548,16 +549,18 @@ function OwnersSelector({ datasource, onChange }) { return SupersetClient.get({ endpoint: `/api/v1/dataset/related/owners?q=${query}`, }).then(response => ({ - data: response.json.result.map(item => ({ - value: item.value, - label: item.text, - })), + data: response.json.result + .filter(item => item.extra.active) + .map(item => ({ + value: item.value, + label: item.text, + })), totalCount: response.json.count, })); }, []); return ( - <Select + <AsyncSelect ariaLabel={t('Select owners')} mode="multiple" name="owners" @@ -598,9 +601,6 @@ class DatasourceEditor extends React.PureComponent { }), }, errors: [], - isDruid: - props.datasource.type === 'druid' || - props.datasource.datasource_type === 'druid', isSqla: props.datasource.datasource_type === 'table' || props.datasource.type === 'table', @@ -752,7 +752,9 @@ class DatasourceEditor extends React.PureComponent { database_name: datasource.database.database_name || datasource.database.name, schema_name: datasource.schema, - table_name: datasource.table_name, + table_name: datasource.table_name + ? encodeURIComponent(datasource.table_name) + : datasource.table_name, }; Object.entries(params).forEach(([key, value]) => { // rison can't encode the undefined value @@ -860,7 +862,11 @@ class DatasourceEditor extends React.PureComponent { fieldKey="description" label={t('Description')} control={ - <TextAreaControl language="markdown" offerEditInModal={false} /> + <TextAreaControl + language="markdown" + offerEditInModal={false} + resize="vertical" + /> } /> <Field @@ -894,6 +900,7 @@ class DatasourceEditor extends React.PureComponent { language="sql" controlId="fetch_values_predicate" minLines={5} + resize="vertical" /> } /> @@ -913,6 +920,7 @@ class DatasourceEditor extends React.PureComponent { controlId="extra" language="json" offerEditInModal={false} + resize="vertical" /> } /> @@ -977,8 +985,8 @@ class DatasourceEditor extends React.PureComponent { tableColumns={['name', 'config']} onChange={this.onDatasourcePropChange.bind(this, 'spatials')} itemGenerator={() => ({ - name: '<new spatial>', - type: '<no type>', + name: t('<new spatial>'), + type: t('<no type>'), config: null, })} collection={spatials} @@ -1093,25 +1101,12 @@ class DatasourceEditor extends React.PureComponent { minLines={20} maxLines={20} readOnly={!this.state.isEditMode} + resize="both" /> } /> </> )} - {this.state.isDruid && ( - <Field - fieldKey="json" - label={t('JSON')} - description={ - <div> - {t('The JSON metric or post aggregation definition.')} - </div> - } - control={ - <TextAreaControl language="json" offerEditInModal={false} /> - } - /> - )} </div> )} {this.state.datasourceType === DATASOURCE_TYPES.physical.key && ( @@ -1259,6 +1254,7 @@ class DatasourceEditor extends React.PureComponent { controlId="warning_markdown" language="markdown" offerEditInModal={false} + resize="vertical" /> } /> @@ -1269,10 +1265,15 @@ class DatasourceEditor extends React.PureComponent { allowAddItem onChange={this.onDatasourcePropChange.bind(this, 'metrics')} itemGenerator={() => ({ - metric_name: '<new metric>', + metric_name: t('<new metric>'), verbose_name: '', expression: '', })} + itemCellProps={{ + expression: () => ({ + width: '240px', + }), + }} itemRenderers={{ metric_name: (v, onChange, _, record) => ( <FlexRowContainer> @@ -1302,6 +1303,8 @@ class DatasourceEditor extends React.PureComponent { language="sql" offerEditInModal={false} minLines={5} + textAreaStyles={{ minWidth: '200px', maxWidth: '450px' }} + resize="both" /> ), description: (v, onChange, label) => ( @@ -1424,10 +1427,10 @@ class DatasourceEditor extends React.PureComponent { allowAddItem allowEditDataType itemGenerator={() => ({ - column_name: '<new column>', + column_name: t('<new column>'), filterable: true, groupby: true, - expression: '<enter SQL expression here>', + expression: t('<enter SQL expression here>'), __expanded: true, })} /> diff --git a/superset-frontend/src/components/Datasource/DatasourceEditor.test.jsx b/superset-frontend/src/components/Datasource/DatasourceEditor.test.jsx index 7ad7b9f9a8420..1046c69f846e6 100644 --- a/superset-frontend/src/components/Datasource/DatasourceEditor.test.jsx +++ b/superset-frontend/src/components/Datasource/DatasourceEditor.test.jsx @@ -19,7 +19,7 @@ import React from 'react'; import fetchMock from 'fetch-mock'; import userEvent from '@testing-library/user-event'; -import { render, screen } from 'spec/helpers/testing-library'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; import DatasourceEditor from 'src/components/Datasource/DatasourceEditor'; import mockDatasource from 'spec/fixtures/mockDatasource'; import * as featureFlags from 'src/featureFlags'; @@ -32,26 +32,26 @@ const props = { }; const DATASOURCE_ENDPOINT = 'glob:*/datasource/external_metadata_by_name/*'; +const asyncRender = props => + waitFor(() => render(<DatasourceEditor {...props} />, { useRedux: true })); + describe('DatasourceEditor', () => { fetchMock.get(DATASOURCE_ENDPOINT, []); - let el; let isFeatureEnabledMock; - beforeEach(() => { - el = <DatasourceEditor {...props} />; - render(el, { useRedux: true }); - }); - - it('is valid', () => { - expect(React.isValidElement(el)).toBe(true); + beforeEach(async () => { + await asyncRender({ + ...props, + datasource: { ...props.datasource, table_name: 'Vehicle Sales +' }, + }); }); it('renders Tabs', () => { expect(screen.getByTestId('edit-dataset-tabs')).toBeInTheDocument(); }); - it('makes an async request', () => + it('can sync columns from source', () => new Promise(done => { const columnsTab = screen.getByTestId('collection-tab-Columns'); @@ -63,6 +63,9 @@ describe('DatasourceEditor', () => { setTimeout(() => { expect(fetchMock.calls(DATASOURCE_ENDPOINT)).toHaveLength(1); + expect(fetchMock.calls(DATASOURCE_ENDPOINT)[0][0]).toContain( + 'Vehicle%20Sales%20%2B%27', + ); fetchMock.reset(); done(); }, 0); @@ -185,11 +188,8 @@ describe('DatasourceEditor', () => { .mockImplementation(() => true); }); - beforeEach(() => { - render(el, { useRedux: true }); - }); - - it('disable edit Source tab', () => { + it('disable edit Source tab', async () => { + await asyncRender(props); expect( screen.queryByRole('img', { name: /lock-locked/i }), ).not.toBeInTheDocument(); @@ -200,7 +200,7 @@ describe('DatasourceEditor', () => { describe('DatasourceEditor RTL', () => { it('properly renders the metric information', async () => { - render(<DatasourceEditor {...props} />, { useRedux: true }); + await asyncRender(props); const metricButton = screen.getByTestId('collection-tab-Metrics'); userEvent.click(metricButton); const expandToggle = await screen.findAllByLabelText(/toggle expand/i); @@ -213,9 +213,7 @@ describe('DatasourceEditor RTL', () => { expect(warningMarkdown.value).toEqual('someone'); }); it('properly updates the metric information', async () => { - render(<DatasourceEditor {...props} />, { - useRedux: true, - }); + await asyncRender(props); const metricButton = screen.getByTestId('collection-tab-Metrics'); userEvent.click(metricButton); const expandToggle = await screen.findAllByLabelText(/toggle expand/i); @@ -230,26 +228,22 @@ describe('DatasourceEditor RTL', () => { expect(certificationDetails.value).toEqual('I am typing something new'); }); it('shows the default datetime column', async () => { - render(<DatasourceEditor {...props} />, { useRedux: true }); + await asyncRender(props); const metricButton = screen.getByTestId('collection-tab-Columns'); userEvent.click(metricButton); - const dsDefaultDatetimeRadio = screen.getByTestId('radio-default-dttm-ds'); expect(dsDefaultDatetimeRadio).toBeChecked(); - const genderDefaultDatetimeRadio = screen.getByTestId( 'radio-default-dttm-gender', ); expect(genderDefaultDatetimeRadio).not.toBeChecked(); }); it('allows choosing only temporal columns as the default datetime', async () => { - render(<DatasourceEditor {...props} />, { useRedux: true }); + await asyncRender(props); const metricButton = screen.getByTestId('collection-tab-Columns'); userEvent.click(metricButton); - const dsDefaultDatetimeRadio = screen.getByTestId('radio-default-dttm-ds'); expect(dsDefaultDatetimeRadio).toBeEnabled(); - const genderDefaultDatetimeRadio = screen.getByTestId( 'radio-default-dttm-gender', ); diff --git a/superset-frontend/src/components/Datasource/DatasourceModal.test.jsx b/superset-frontend/src/components/Datasource/DatasourceModal.test.jsx index 9743e3a325f36..12be350521515 100644 --- a/superset-frontend/src/components/Datasource/DatasourceModal.test.jsx +++ b/superset-frontend/src/components/Datasource/DatasourceModal.test.jsx @@ -32,6 +32,7 @@ import { DatasourceModal } from 'src/components/Datasource'; import DatasourceEditor from 'src/components/Datasource/DatasourceEditor'; import * as featureFlags from 'src/featureFlags'; import mockDatasource from 'spec/fixtures/mockDatasource'; +import QueryProvider from 'src/views/QueryProvider'; const mockStore = configureStore([thunk]); const store = mockStore({}); @@ -53,9 +54,11 @@ const mockedProps = { async function mountAndWait(props = mockedProps) { const mounted = mount( - <Provider store={store}> - <DatasourceModal {...props} /> - </Provider>, + <QueryProvider> + <Provider store={store}> + <DatasourceModal {...props} /> + </Provider> + </QueryProvider>, { wrappingComponent: ThemeProvider, wrappingComponentProps: { theme: supersetTheme }, diff --git a/superset-frontend/src/components/Datasource/DatasourceModal.tsx b/superset-frontend/src/components/Datasource/DatasourceModal.tsx index 98f2e561db83f..b0a0bb9c42f5f 100644 --- a/superset-frontend/src/components/Datasource/DatasourceModal.tsx +++ b/superset-frontend/src/components/Datasource/DatasourceModal.tsx @@ -133,7 +133,7 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({ setIsSaving(false); getClientErrorObject(response).then(({ error }) => { modal.error({ - title: 'Error', + title: t('Error'), content: error || t('An error has occurred'), okButtonProps: { danger: true, className: 'btn-danger' }, }); @@ -177,6 +177,8 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({ content: renderSaveDialog(), onOk: onConfirmSave, icon: null, + okText: t('OK'), + cancelText: t('Cancel'), }); }; diff --git a/superset-frontend/src/components/Select/DeprecatedSelect.stories.tsx b/superset-frontend/src/components/DeprecatedSelect/DeprecatedSelect.stories.tsx similarity index 100% rename from superset-frontend/src/components/Select/DeprecatedSelect.stories.tsx rename to superset-frontend/src/components/DeprecatedSelect/DeprecatedSelect.stories.tsx diff --git a/superset-frontend/src/components/Select/DeprecatedSelect.tsx b/superset-frontend/src/components/DeprecatedSelect/DeprecatedSelect.tsx similarity index 99% rename from superset-frontend/src/components/Select/DeprecatedSelect.tsx rename to superset-frontend/src/components/DeprecatedSelect/DeprecatedSelect.tsx index 690f6379aaeed..2e2c1e9546f49 100644 --- a/superset-frontend/src/components/Select/DeprecatedSelect.tsx +++ b/superset-frontend/src/components/DeprecatedSelect/DeprecatedSelect.tsx @@ -40,6 +40,7 @@ import { } from 'react-sortable-hoc'; import arrayMove from 'array-move'; import { useTheme } from '@superset-ui/core'; +import { findValue } from './utils'; import { WindowedSelectComponentType, WindowedSelectProps, @@ -59,7 +60,6 @@ import { InputProps, defaultTheme, } from './styles'; -import { findValue } from './utils'; type AnyReactSelect<OptionType extends OptionTypeBase> = | BasicSelect<OptionType> @@ -90,7 +90,7 @@ export type SupersetStyledSelectProps< // callback for paste event onPaste?: (e: SyntheticEvent) => void; forceOverflow?: boolean; - // for simplier theme overrides + // for simpler theme overrides themeConfig?: PartialThemeConfig; stylesConfig?: PartialStylesConfig; }; @@ -185,7 +185,7 @@ function styled< // `value` may be rendered values (strings), we want option objects const value: OptionType[] = findValue(value_, options || [], valueKey); - // Add backward compability to v1 API + // Add backward compatibility to v1 API const isMulti = isMulti_ === undefined ? multi : isMulti_; const isClearable = isClearable_ === undefined ? clearable : isClearable_; diff --git a/superset-frontend/src/components/Select/NativeSelect.tsx b/superset-frontend/src/components/DeprecatedSelect/NativeSelect.tsx similarity index 100% rename from superset-frontend/src/components/Select/NativeSelect.tsx rename to superset-frontend/src/components/DeprecatedSelect/NativeSelect.tsx diff --git a/superset-frontend/src/components/Select/OnPasteSelect.jsx b/superset-frontend/src/components/DeprecatedSelect/OnPasteSelect.jsx similarity index 98% rename from superset-frontend/src/components/Select/OnPasteSelect.jsx rename to superset-frontend/src/components/DeprecatedSelect/OnPasteSelect.jsx index e178a0a4c0672..bffa5428a60df 100644 --- a/superset-frontend/src/components/Select/OnPasteSelect.jsx +++ b/superset-frontend/src/components/DeprecatedSelect/OnPasteSelect.jsx @@ -18,7 +18,7 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import { Select } from 'src/components/Select'; +import { Select } from 'src/components/DeprecatedSelect'; export default class OnPasteSelect extends React.Component { constructor(props) { diff --git a/superset-frontend/src/components/Select/OnPasteSelect.test.jsx b/superset-frontend/src/components/DeprecatedSelect/OnPasteSelect.test.jsx similarity index 97% rename from superset-frontend/src/components/Select/OnPasteSelect.test.jsx rename to superset-frontend/src/components/DeprecatedSelect/OnPasteSelect.test.jsx index 9c6af28d7a109..95d01cc28b9a6 100644 --- a/superset-frontend/src/components/Select/OnPasteSelect.test.jsx +++ b/superset-frontend/src/components/DeprecatedSelect/OnPasteSelect.test.jsx @@ -20,7 +20,11 @@ import React from 'react'; import sinon from 'sinon'; import { shallow } from 'enzyme'; -import { Select, OnPasteSelect, CreatableSelect } from 'src/components/Select'; +import { + Select, + OnPasteSelect, + CreatableSelect, +} from 'src/components/DeprecatedSelect'; const defaultProps = { onChange: sinon.spy(), @@ -41,7 +45,7 @@ const defaultProps = { const defaultEvt = { preventDefault: sinon.spy(), clipboardData: { - getData: sinon.spy(() => ' United States, China , India, Canada, '), + getData: sinon.spy(() => ' United States, China, India, Canada, '), }, }; diff --git a/superset-frontend/src/components/Select/WindowedSelect/WindowedMenuList.tsx b/superset-frontend/src/components/DeprecatedSelect/WindowedSelect/WindowedMenuList.tsx similarity index 98% rename from superset-frontend/src/components/Select/WindowedSelect/WindowedMenuList.tsx rename to superset-frontend/src/components/DeprecatedSelect/WindowedSelect/WindowedMenuList.tsx index 8eb94b55d3927..f29466b33988c 100644 --- a/superset-frontend/src/components/Select/WindowedSelect/WindowedMenuList.tsx +++ b/superset-frontend/src/components/DeprecatedSelect/WindowedSelect/WindowedMenuList.tsx @@ -55,7 +55,7 @@ export type WindowedMenuListProps = { * grouped options just yet. */ -type MenuListPropsChildren<OptionType> = +type MenuListPropsChildren<OptionType extends OptionTypeBase> = | Component<OptionProps<OptionType>>[] | ReactElement[]; diff --git a/superset-frontend/src/components/Select/WindowedSelect/index.tsx b/superset-frontend/src/components/DeprecatedSelect/WindowedSelect/index.tsx similarity index 100% rename from superset-frontend/src/components/Select/WindowedSelect/index.tsx rename to superset-frontend/src/components/DeprecatedSelect/WindowedSelect/index.tsx diff --git a/superset-frontend/src/components/Select/WindowedSelect/windowed.tsx b/superset-frontend/src/components/DeprecatedSelect/WindowedSelect/windowed.tsx similarity index 85% rename from superset-frontend/src/components/Select/WindowedSelect/windowed.tsx rename to superset-frontend/src/components/DeprecatedSelect/WindowedSelect/windowed.tsx index 4c2f64aa13d7a..a611cf36c96db 100644 --- a/superset-frontend/src/components/Select/WindowedSelect/windowed.tsx +++ b/superset-frontend/src/components/DeprecatedSelect/WindowedSelect/windowed.tsx @@ -68,13 +68,17 @@ export function MenuList<OptionType extends OptionTypeBase>({ export default function windowed<OptionType extends OptionTypeBase>( SelectComponent: ComponentType<SelectProps<OptionType>>, ): WindowedSelectComponentType<OptionType> { - function WindowedSelect( - props: WindowedSelectProps<OptionType>, - ref: React.RefObject<Select<OptionType>>, - ) { - const { components: components_ = {}, ...restProps } = props; - const components = { ...components_, MenuList }; - return <SelectComponent components={components} ref={ref} {...restProps} />; - } - return forwardRef(WindowedSelect); + const WindowedSelect = forwardRef( + ( + props: WindowedSelectProps<OptionType>, + ref: React.RefObject<Select<OptionType>>, + ) => { + const { components: components_ = {}, ...restProps } = props; + const components = { ...components_, MenuList }; + return ( + <SelectComponent components={components} ref={ref} {...restProps} /> + ); + }, + ); + return WindowedSelect; } diff --git a/superset-frontend/src/components/Select/index.ts b/superset-frontend/src/components/DeprecatedSelect/index.ts similarity index 100% rename from superset-frontend/src/components/Select/index.ts rename to superset-frontend/src/components/DeprecatedSelect/index.ts diff --git a/superset-frontend/src/components/DeprecatedSelect/styles.tsx b/superset-frontend/src/components/DeprecatedSelect/styles.tsx new file mode 100644 index 0000000000000..f04cfbdba9eda --- /dev/null +++ b/superset-frontend/src/components/DeprecatedSelect/styles.tsx @@ -0,0 +1,406 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Deprecated component +/* eslint-disable theme-colors/no-literal-colors */ + +import React, { CSSProperties, ComponentType, ReactNode } from 'react'; +import { SerializedStyles } from '@emotion/react'; +import { SupersetTheme, css } from '@superset-ui/core'; +import { + Styles, + Theme, + SelectComponentsConfig, + components as defaultComponents, + InputProps as ReactSelectInputProps, + Props as SelectProps, +} from 'react-select'; +import type { colors as reactSelectColors } from 'react-select/src/theme'; +import type { DeepNonNullable } from 'react-select/src/components'; +import { OptionType } from 'antd/lib/select'; +import { SupersetStyledSelectProps } from './DeprecatedSelect'; + +export const DEFAULT_CLASS_NAME = 'Select'; +export const DEFAULT_CLASS_NAME_PREFIX = 'Select'; + +type RecursivePartial<T> = { + [P in keyof T]?: RecursivePartial<T[P]>; +}; + +const colors = (theme: SupersetTheme) => ({ + primary: theme.colors.success.base, + danger: theme.colors.error.base, + warning: theme.colors.warning.base, + indicator: theme.colors.info.base, + almostBlack: theme.colors.grayscale.dark1, + grayDark: theme.colors.grayscale.dark1, + grayLight: theme.colors.grayscale.light2, + gray: theme.colors.grayscale.light1, + grayBg: theme.colors.grayscale.light4, + grayBgDarker: theme.colors.grayscale.light3, + grayBgDarkest: theme.colors.grayscale.light2, + grayHeading: theme.colors.grayscale.light1, + menuHover: theme.colors.grayscale.light3, + lightest: theme.colors.grayscale.light5, + darkest: theme.colors.grayscale.dark2, + grayBorder: theme.colors.grayscale.light2, + grayBorderLight: theme.colors.grayscale.light3, + grayBorderDark: theme.colors.grayscale.light1, + textDefault: theme.colors.grayscale.dark1, + textDarkest: theme.colors.grayscale.dark2, + dangerLight: theme.colors.error.light1, +}); + +export type ThemeConfig = { + borderRadius: number; + // z-index for menu dropdown + // (the same as `@z-index-above-dashboard-charts + 1` in variables.less) + zIndex: number; + colors: { + // add known colors + [key in keyof typeof reactSelectColors]: string; + } & { + [key in keyof ReturnType<typeof colors>]: string; + } & { + [key: string]: string; // any other colors + }; + spacing: Theme['spacing'] & { + // line height and font size must be pixels for easier computation + // of option item height in WindowedMenuList + lineHeight: number; + fontSize: number; + // other relative size must be string + minWidth: string; + }; +}; + +export type PartialThemeConfig = RecursivePartial<ThemeConfig>; + +export const defaultTheme: (theme: SupersetTheme) => PartialThemeConfig = + theme => ({ + borderRadius: theme.borderRadius, + zIndex: 11, + colors: colors(theme), + spacing: { + baseUnit: 3, + menuGutter: 0, + controlHeight: 34, + lineHeight: 19, + fontSize: 14, + minWidth: '6.5em', + }, + weights: theme.typography.weights, + }); + +// let styles accept serialized CSS, too +type CSSStyles = CSSProperties | SerializedStyles; +type styleFnWithSerializedStyles = ( + base: CSSProperties, + state: any, +) => CSSStyles | CSSStyles[]; + +export type StylesConfig = { + [key in keyof Styles]: styleFnWithSerializedStyles; +}; +export type PartialStylesConfig = Partial<StylesConfig>; + +export const DEFAULT_STYLES: PartialStylesConfig = { + container: ( + provider, + { + theme: { + spacing: { minWidth }, + }, + }, + ) => [ + provider, + css` + min-width: ${minWidth}; + `, + ], + placeholder: provider => [ + provider, + css` + white-space: nowrap; + `, + ], + indicatorSeparator: () => css` + display: none; + `, + indicatorsContainer: provider => [ + provider, + css` + i { + width: 1em; + display: inline-block; + } + `, + ], + clearIndicator: provider => [ + provider, + css` + padding: 4px 0 4px 6px; + `, + ], + control: ( + provider, + { isFocused, menuIsOpen, theme: { borderRadius, colors } }, + ) => { + const isPseudoFocused = isFocused && !menuIsOpen; + let borderColor = colors.grayBorder; + if (isPseudoFocused || menuIsOpen) { + borderColor = colors.grayBorderDark; + } + return [ + provider, + css` + border-color: ${borderColor}; + box-shadow: ${isPseudoFocused + ? 'inset 0 1px 1px rgba(0,0,0,.075), 0 0 0 3px rgba(0,0,0,.1)' + : 'none'}; + border-radius: ${menuIsOpen + ? `${borderRadius}px ${borderRadius}px 0 0` + : `${borderRadius}px`}; + &:hover { + border-color: ${borderColor}; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06); + } + flex-wrap: nowrap; + padding-left: 1px; + `, + ]; + }, + menu: (provider, { theme: { zIndex } }) => [ + provider, + css` + padding-bottom: 2em; + z-index: ${zIndex}; /* override at least multi-page pagination */ + width: auto; + min-width: 100%; + max-width: 80vw; + background: none; + box-shadow: none; + border: 0; + `, + ], + menuList: (provider, { theme: { borderRadius, colors } }) => [ + provider, + css` + background: ${colors.lightest}; + border-radius: 0 0 ${borderRadius}px ${borderRadius}px; + border: 1px solid ${colors.grayBorderDark}; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06); + margin-top: -1px; + border-top-color: ${colors.grayBorderLight}; + min-width: 100%; + width: auto; + border-radius: 0 0 ${borderRadius}px ${borderRadius}px; + padding-top: 0; + padding-bottom: 0; + `, + ], + option: ( + provider, + { + isDisabled, + isFocused, + isSelected, + theme: { + colors, + spacing: { lineHeight, fontSize }, + weights, + }, + }, + ) => { + let color = colors.textDefault; + let backgroundColor = colors.lightest; + if (isFocused) { + backgroundColor = colors.grayBgDarker; + } else if (isDisabled) { + color = '#ccc'; + } + return [ + provider, + css` + cursor: pointer; + line-height: ${lineHeight}px; + font-size: ${fontSize}px; + background-color: ${backgroundColor}; + color: ${color}; + font-weight: ${isSelected ? weights.bold : weights.normal}; + white-space: nowrap; + &:hover:active { + background-color: ${colors.grayBg}; + } + `, + ]; + }, + valueContainer: ( + provider, + { + isMulti, + hasValue, + theme: { + spacing: { baseUnit }, + }, + }, + ) => [ + provider, + css` + padding-left: ${isMulti && hasValue ? 1 : baseUnit * 3}px; + `, + ], + multiValueLabel: ( + provider, + { + theme: { + spacing: { baseUnit }, + }, + }, + ) => ({ + ...provider, + paddingLeft: baseUnit * 1.2, + paddingRight: baseUnit * 1.2, + }), + input: (provider, { selectProps }) => [ + provider, + css` + margin-left: 0; + vertical-align: middle; + ${selectProps?.isMulti && selectProps?.value?.length + ? 'padding: 0 6px; width: 100%' + : 'padding: 0; flex: 1 1 auto;'}; + `, + ], + menuPortal: base => ({ + ...base, + zIndex: 1030, // must be same or higher of antd popover + }), +}; + +const INPUT_TAG_BASE_STYLES = { + background: 'none', + border: 'none', + outline: 'none', + padding: 0, +}; + +export type SelectComponentsType = Omit< + SelectComponentsConfig<any>, + 'Input' +> & { + Input: ComponentType<InputProps>; +}; + +// react-select is missing selectProps from their props type +// so overwriting it here to avoid errors +export type InputProps = ReactSelectInputProps & { + placeholder?: ReactNode; + selectProps: SelectProps; + autoComplete?: string; + onPaste?: SupersetStyledSelectProps<OptionType>['onPaste']; + inputStyle?: object; +}; + +const { ClearIndicator, DropdownIndicator, Option, Input, SelectContainer } = + defaultComponents as Required<DeepNonNullable<SelectComponentsType>>; + +export const DEFAULT_COMPONENTS: SelectComponentsType = { + SelectContainer: ({ children, ...props }) => { + const { + selectProps: { assistiveText }, + } = props; + return ( + <div> + <SelectContainer {...props}>{children}</SelectContainer> + {assistiveText && ( + <span + css={(theme: SupersetTheme) => ({ + marginLeft: 3, + fontSize: theme.typography.sizes.s, + color: theme.colors.grayscale.light1, + })} + > + {assistiveText} + </span> + )} + </div> + ); + }, + Option: ({ children, innerProps, data, ...props }) => ( + <Option + {...props} + data={data} + css={data?.style ? data.style : null} + innerProps={innerProps} + > + {children} + </Option> + ), + ClearIndicator: props => ( + <ClearIndicator {...props}> + <i className="fa">×</i> + </ClearIndicator> + ), + DropdownIndicator: props => ( + <DropdownIndicator {...props}> + <i + className={`fa fa-caret-${ + props.selectProps.menuIsOpen ? 'up' : 'down' + }`} + /> + </DropdownIndicator> + ), + Input: (props: InputProps) => { + const { getStyles } = props; + return ( + <Input + {...props} + css={getStyles('input', props)} + autoComplete="chrome-off" + inputStyle={INPUT_TAG_BASE_STYLES} + /> + ); + }, +}; + +export const VALUE_LABELED_STYLES: PartialStylesConfig = { + valueContainer: ( + provider, + { + getValue, + theme: { + spacing: { baseUnit }, + }, + isMulti, + }, + ) => ({ + ...provider, + paddingLeft: getValue().length > 0 ? 1 : baseUnit * 3, + overflow: isMulti && getValue().length > 0 ? 'visible' : 'hidden', + }), + // render single value as is they are multi-value + singleValue: (provider, props) => { + const { getStyles } = props; + return { + ...getStyles('multiValue', props), + '.metric-option': getStyles('multiValueLabel', props), + }; + }, +}; diff --git a/superset-frontend/src/components/Select/utils.ts b/superset-frontend/src/components/DeprecatedSelect/utils.ts similarity index 66% rename from superset-frontend/src/components/Select/utils.ts rename to superset-frontend/src/components/DeprecatedSelect/utils.ts index 9836b9ddd2eaa..497791b62d75a 100644 --- a/superset-frontend/src/components/Select/utils.ts +++ b/superset-frontend/src/components/DeprecatedSelect/utils.ts @@ -16,23 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import { ReactNode } from 'react'; -import { ensureIsArray } from '@superset-ui/core'; import { OptionTypeBase, ValueType, OptionsType, GroupedOptionsType, } from 'react-select'; -import { LabeledValue as AntdLabeledValue } from 'antd/lib/select'; - -export function isObject(value: unknown): value is Record<string, unknown> { - return ( - value !== null && - typeof value === 'object' && - Array.isArray(value) === false - ); -} /** * Find Option value that matches a possibly string value. @@ -68,32 +57,3 @@ export function findValue<OptionType extends OptionTypeBase>( // empty: https://github.com/JedWatson/react-select/blob/32ad5c040bdd96cd1ca71010c2558842d684629c/packages/react-select/src/utils.js#L64 return (Array.isArray(value) ? value : [value]).map(find); } - -export function isLabeledValue(value: unknown): value is AntdLabeledValue { - return isObject(value) && 'value' in value && 'label' in value; -} - -export function getValue( - option: string | number | AntdLabeledValue | null | undefined, -) { - return isLabeledValue(option) ? option.value : option; -} - -type LabeledValue<V> = { label?: ReactNode; value?: V }; - -export function hasOption<V>( - value: V, - options?: V | LabeledValue<V> | (V | LabeledValue<V>)[], - checkLabel = false, -): boolean { - const optionsArray = ensureIsArray(options); - return ( - optionsArray.find( - x => - x === value || - (isObject(x) && - (('value' in x && x.value === value) || - (checkLabel && 'label' in x && x.label === value))), - ) !== undefined - ); -} diff --git a/superset-frontend/src/components/DesignSystem.stories.mdx b/superset-frontend/src/components/DesignSystem.stories.mdx new file mode 100644 index 0000000000000..e00612c5be40a --- /dev/null +++ b/superset-frontend/src/components/DesignSystem.stories.mdx @@ -0,0 +1,25 @@ +import { Meta, Source } from '@storybook/addon-docs'; +import AtomicDesign from './atomic-design.png'; + +<Meta title="Design System/Introduction" /> + +# Superset Design System + +A design system is a complete set of standards intended to manage design at scale using reusable components and patterns. + +You can get an overview of Atomic Design concepts and a link to the full book on the topic here: + +<a href="https://bradfrost.com/blog/post/atomic-web-design/" target="_blank"> + Intro to Atomic Design +</a> + +While the Superset Design System will use Atomic Design principles, we choose a different language to describe the elements. + +| Atomic Design | Atoms | Molecules | Organisms | Templates | Pages / Screens | +| :-------------- | :---------: | :--------: | :-------: | :-------: | :-------------: | +| Superset Design | Foundations | Components | Patterns | Templates | Features | + +<img + src={AtomicDesign} + alt="Atoms = Foundations, Molecules = Components, Organisms = Patterns, Templates = Templates, Pages / Screens = Features" +/> diff --git a/superset-frontend/src/components/Dropdown/index.tsx b/superset-frontend/src/components/Dropdown/index.tsx index e5d5f9f8526c5..c40f479579d2e 100644 --- a/superset-frontend/src/components/Dropdown/index.tsx +++ b/superset-frontend/src/components/Dropdown/index.tsx @@ -20,6 +20,7 @@ import React, { RefObject } from 'react'; import { AntdDropdown } from 'src/components'; import { DropDownProps } from 'antd/lib/dropdown'; import { styled } from '@superset-ui/core'; +import Icons from 'src/components/Icons'; const MenuDots = styled.div` width: ${({ theme }) => theme.gridUnit * 0.75}px; @@ -66,14 +67,35 @@ const MenuDotsWrapper = styled.div` padding-left: ${({ theme }) => theme.gridUnit}px; `; -export interface DropdownProps { +export enum IconOrientation { + VERTICAL = 'vertical', + HORIZONTAL = 'horizontal', +} +export interface DropdownProps extends DropDownProps { overlay: React.ReactElement; + iconOrientation?: IconOrientation; } -export const Dropdown = ({ overlay, ...rest }: DropdownProps) => ( +const RenderIcon = ( + iconOrientation: IconOrientation = IconOrientation.VERTICAL, +) => { + const component = + iconOrientation === IconOrientation.HORIZONTAL ? ( + <Icons.MoreHoriz iconSize="xl" /> + ) : ( + <MenuDots /> + ); + return component; +}; + +export const Dropdown = ({ + overlay, + iconOrientation = IconOrientation.VERTICAL, + ...rest +}: DropdownProps) => ( <AntdDropdown overlay={overlay} {...rest}> <MenuDotsWrapper data-test="dropdown-trigger"> - <MenuDots /> + {RenderIcon(iconOrientation)} </MenuDotsWrapper> </AntdDropdown> ); diff --git a/superset-frontend/src/components/DropdownButton/index.tsx b/superset-frontend/src/components/DropdownButton/index.tsx index f2a223a49fd8d..c6293f66a3fbd 100644 --- a/superset-frontend/src/components/DropdownButton/index.tsx +++ b/superset-frontend/src/components/DropdownButton/index.tsx @@ -52,10 +52,9 @@ const StyledDropdownButton = styled.div` border-left: 1px solid ${({ theme }) => theme.colors.grayscale.light5}; content: ''; display: block; - height: 23px; + height: ${({ theme }) => theme.gridUnit * 8}px; margin: 0; position: absolute; - top: ${({ theme }) => theme.gridUnit * 0.75}px; width: ${({ theme }) => theme.gridUnit * 0.25}px; } diff --git a/superset-frontend/src/components/DropdownContainer/DropdownContainer.stories.tsx b/superset-frontend/src/components/DropdownContainer/DropdownContainer.stories.tsx new file mode 100644 index 0000000000000..4aeaa03a16f36 --- /dev/null +++ b/superset-frontend/src/components/DropdownContainer/DropdownContainer.stories.tsx @@ -0,0 +1,109 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useCallback, useState } from 'react'; +import { isEqual } from 'lodash'; +import { css } from '@superset-ui/core'; +import Select from '../Select/Select'; +import Button from '../Button'; +import DropdownContainer, { DropdownContainerProps, Ref } from '.'; + +export default { + title: 'Design System/Components/DropdownContainer', + component: DropdownContainer, +}; + +const ITEMS_COUNT = 6; +const ITEM_OPTIONS = 10; +const MIN_WIDTH = 700; +const MAX_WIDTH = 1300; +const HEIGHT = 400; + +const itemsOptions = Array.from({ length: ITEM_OPTIONS }).map((_, i) => ({ + label: `Option ${i}`, + value: `option-${i}`, +})); + +type ItemsType = Pick<DropdownContainerProps, 'items'>['items']; + +type OverflowingState = { notOverflowed: string[]; overflowed: string[] }; + +const generateItems = (overflowingState?: OverflowingState) => + Array.from({ length: ITEMS_COUNT }).map((_, i) => ({ + id: `el-${i}`, + element: ( + <div style={{ minWidth: 150 }}> + <Select + options={itemsOptions} + header={`Label ${i}`} + headerPosition={ + overflowingState?.overflowed.includes(`el-${i}`) ? 'top' : 'left' + } + /> + </div> + ), + })); + +export const Component = (props: DropdownContainerProps) => { + const [items, setItems] = useState<ItemsType>([]); + const [overflowingState, setOverflowingState] = useState<OverflowingState>(); + const containerRef = React.useRef<Ref>(null); + const onOverflowingStateChange = useCallback( + value => { + if (!isEqual(overflowingState, value)) { + setItems(generateItems(value)); + setOverflowingState(value); + } + }, + [overflowingState], + ); + + return ( + <div> + <div + css={css` + overflow: auto; + min-width: ${MIN_WIDTH}px; + width: ${MIN_WIDTH}px; + max-width: ${MAX_WIDTH}px; + height: ${HEIGHT}px; + border: 1px solid lightgray; + resize: horizontal; + padding: 24px; + margin-bottom: 12px; + `} + > + <DropdownContainer + {...props} + items={items} + onOverflowingStateChange={onOverflowingStateChange} + ref={containerRef} + /> + </div> + <Button onClick={() => containerRef.current?.open()}>Open</Button> + <span + css={css` + margin-left: ${MIN_WIDTH - 340}px; + color: gray; + `} + > + Use the drag icon to resize the container + </span> + </div> + ); +}; diff --git a/superset-frontend/src/components/DropdownContainer/DropdownContainer.test.tsx b/superset-frontend/src/components/DropdownContainer/DropdownContainer.test.tsx new file mode 100644 index 0000000000000..4a0fd9906226e --- /dev/null +++ b/superset-frontend/src/components/DropdownContainer/DropdownContainer.test.tsx @@ -0,0 +1,156 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import userEvent from '@testing-library/user-event'; +import { screen, render } from 'spec/helpers/testing-library'; +import Button from '../Button'; +import Icons from '../Icons'; +import DropdownContainer from '.'; + +const generateItems = (n: number) => + Array.from({ length: n }).map((_, i) => ({ + id: `el-${i + 1}`, + element: <Button>{`Element ${i + 1}`}</Button>, + })); + +const ITEMS = generateItems(10); + +const mockOverflowingIndex = async ( + overflowingIndex: number, + func: Function, +) => { + const spy = jest.spyOn(React, 'useState'); + spy.mockImplementation(() => [overflowingIndex, jest.fn()]); + await func(); + spy.mockRestore(); +}; + +test('renders children', () => { + render(<DropdownContainer items={generateItems(3)} />); + expect(screen.getByText('Element 1')).toBeInTheDocument(); + expect(screen.getByText('Element 2')).toBeInTheDocument(); + expect(screen.getByText('Element 3')).toBeInTheDocument(); +}); + +test('renders children with custom horizontal spacing', () => { + render(<DropdownContainer items={ITEMS} style={{ gap: 20 }} />); + expect(screen.getByTestId('container')).toHaveStyle('gap: 20px'); +}); + +test('renders a dropdown trigger when overflowing', async () => { + await mockOverflowingIndex(3, () => { + render(<DropdownContainer items={ITEMS} />); + expect(screen.getByText('More')).toBeInTheDocument(); + }); +}); + +test('renders a dropdown trigger with custom icon', async () => { + await mockOverflowingIndex(3, async () => { + render( + <DropdownContainer items={ITEMS} dropdownTriggerIcon={<Icons.Link />} />, + ); + expect( + await screen.findByRole('img', { name: 'link' }), + ).toBeInTheDocument(); + }); +}); + +test('renders a dropdown trigger with custom text', async () => { + await mockOverflowingIndex(3, () => { + const customText = 'Custom text'; + render( + <DropdownContainer items={ITEMS} dropdownTriggerText={customText} />, + ); + expect(screen.getByText(customText)).toBeInTheDocument(); + }); +}); + +test('renders a dropdown trigger with custom count', async () => { + await mockOverflowingIndex(3, () => { + const customCount = 99; + render( + <DropdownContainer items={ITEMS} dropdownTriggerCount={customCount} />, + ); + expect(screen.getByTitle(customCount)).toBeInTheDocument(); + }); +}); + +test('does not render a dropdown button when not overflowing', () => { + render(<DropdownContainer items={generateItems(3)} />); + expect(screen.queryByText('More')).not.toBeInTheDocument(); +}); + +test('renders a dropdown when overflowing', async () => { + await mockOverflowingIndex(3, () => { + render(<DropdownContainer items={ITEMS} />); + userEvent.click(screen.getByText('More')); + expect(screen.getByTestId('dropdown-content')).toBeInTheDocument(); + }); +}); + +test('renders children with custom vertical spacing', async () => { + await mockOverflowingIndex(3, () => { + render(<DropdownContainer items={ITEMS} dropdownStyle={{ gap: 20 }} />); + userEvent.click(screen.getByText('More')); + expect(screen.getByTestId('dropdown-content')).toHaveStyle('gap: 20px'); + }); +}); + +test('fires event when overflowing state changes', async () => { + await mockOverflowingIndex(3, () => { + const onOverflowingStateChange = jest.fn(); + render( + <DropdownContainer + items={generateItems(5)} + onOverflowingStateChange={onOverflowingStateChange} + />, + ); + expect(onOverflowingStateChange).toHaveBeenCalledWith({ + notOverflowed: ['el-1', 'el-2', 'el-3'], + overflowed: ['el-4', 'el-5'], + }); + }); +}); + +test('renders a dropdown with custom content', async () => { + await mockOverflowingIndex(3, () => { + const customDropdownContent = <div>Custom content</div>; + render( + <DropdownContainer + items={ITEMS} + dropdownContent={() => customDropdownContent} + />, + ); + userEvent.click(screen.getByText('More')); + expect(screen.getByText('Custom content')).toBeInTheDocument(); + }); +}); + +test('Shows tooltip on dropdown trigger hover', async () => { + await mockOverflowingIndex(3, async () => { + render( + <DropdownContainer + items={generateItems(5)} + dropdownTriggerTooltip="Test tooltip" + />, + ); + userEvent.hover(screen.getByText('More')); + expect(await screen.findByText('Test tooltip')).toBeInTheDocument(); + }); +}); diff --git a/superset-frontend/src/components/DropdownContainer/Overview.stories.mdx b/superset-frontend/src/components/DropdownContainer/Overview.stories.mdx new file mode 100644 index 0000000000000..691dfeac7318f --- /dev/null +++ b/superset-frontend/src/components/DropdownContainer/Overview.stories.mdx @@ -0,0 +1,17 @@ +import { Meta, Source } from '@storybook/addon-docs'; + +<Meta title="Design System/Components/DropdownContainer/Overview" /> + +# Usage + +The dropdown container is used to display elements horizontally in a responsive way. If the elements don't fit in +the available width, they are displayed vertically in a dropdown. Some of the common applications in Superset are: + +- Display chart filters in the CRUD views +- Horizontally display native filters in a dashboard + +# Variations + +The component accepts any React element which ensures a high level of variability in Superset. + +To check the component in detail and its interactions, check the [DropdownContainer](/story/design-system-components-dropdowncontainer--component) page. diff --git a/superset-frontend/src/components/DropdownContainer/index.tsx b/superset-frontend/src/components/DropdownContainer/index.tsx new file mode 100644 index 0000000000000..c90372973efbc --- /dev/null +++ b/superset-frontend/src/components/DropdownContainer/index.tsx @@ -0,0 +1,408 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { + CSSProperties, + forwardRef, + ReactElement, + RefObject, + useEffect, + useImperativeHandle, + useLayoutEffect, + useMemo, + useState, + useRef, + ReactNode, +} from 'react'; +import { Global } from '@emotion/react'; +import { css, t, useTheme } from '@superset-ui/core'; +import { useResizeDetector } from 'react-resize-detector'; +import { usePrevious } from 'src/hooks/usePrevious'; +import Badge from '../Badge'; +import Icons from '../Icons'; +import Button from '../Button'; +import Popover from '../Popover'; +import { Tooltip } from '../Tooltip'; + +const MAX_HEIGHT = 500; + +/** + * Container item. + */ +export interface Item { + /** + * String that uniquely identifies the item. + */ + id: string; + /** + * The element to be rendered. + */ + element: ReactElement; +} + +/** + * Horizontal container that displays overflowed items in a dropdown. + * It shows an indicator of how many items are currently overflowing. + */ +export interface DropdownContainerProps { + /** + * Array of items. The id property is used to uniquely identify + * the elements when rendering or dealing with event handlers. + */ + items: Item[]; + /** + * Event handler called every time an element moves between + * main container and dropdown. + */ + onOverflowingStateChange?: (overflowingState: { + notOverflowed: string[]; + overflowed: string[]; + }) => void; + /** + * Option to customize the content of the dropdown. + */ + dropdownContent?: (overflowedItems: Item[]) => ReactElement; + /** + * Dropdown ref. + */ + dropdownRef?: RefObject<HTMLDivElement>; + /** + * Dropdown additional style properties. + */ + dropdownStyle?: CSSProperties; + /** + * Displayed count in the dropdown trigger. + */ + dropdownTriggerCount?: number; + /** + * Icon of the dropdown trigger. + */ + dropdownTriggerIcon?: ReactElement; + /** + * Text of the dropdown trigger. + */ + dropdownTriggerText?: string; + /** + * Text of the dropdown trigger tooltip + */ + dropdownTriggerTooltip?: ReactNode | null; + /** + * Main container additional style properties. + */ + style?: CSSProperties; +} + +export type Ref = HTMLDivElement & { open: () => void }; + +const DropdownContainer = forwardRef( + ( + { + items, + onOverflowingStateChange, + dropdownContent, + dropdownRef, + dropdownStyle = {}, + dropdownTriggerCount, + dropdownTriggerIcon, + dropdownTriggerText = t('More'), + dropdownTriggerTooltip = null, + style, + }: DropdownContainerProps, + outerRef: RefObject<Ref>, + ) => { + const theme = useTheme(); + const { ref, width = 0 } = useResizeDetector<HTMLDivElement>(); + const previousWidth = usePrevious(width) || 0; + const { current } = ref; + const [itemsWidth, setItemsWidth] = useState<number[]>([]); + const [popoverVisible, setPopoverVisible] = useState(false); + + // We use React.useState to be able to mock the state in Jest + const [overflowingIndex, setOverflowingIndex] = React.useState<number>(-1); + + let targetRef = useRef<HTMLDivElement>(null); + if (dropdownRef) { + targetRef = dropdownRef; + } + + const [showOverflow, setShowOverflow] = useState(false); + + const reduceItems = (items: Item[]): [Item[], string[]] => + items.reduce( + ([items, ids], item) => { + items.push({ + id: item.id, + element: React.cloneElement(item.element, { key: item.id }), + }); + ids.push(item.id); + return [items, ids]; + }, + [[], []] as [Item[], string[]], + ); + + const [notOverflowedItems, notOverflowedIds] = useMemo( + () => + reduceItems( + items.slice( + 0, + overflowingIndex !== -1 ? overflowingIndex : items.length, + ), + ), + [items, overflowingIndex], + ); + + const [overflowedItems, overflowedIds] = useMemo( + () => + overflowingIndex !== -1 + ? reduceItems(items.slice(overflowingIndex)) + : [[], []], + [items, overflowingIndex], + ); + + useLayoutEffect(() => { + const container = current?.children.item(0); + if (container) { + const { children } = container; + const childrenArray = Array.from(children); + + // If items length change, add all items to the container + // and recalculate the widths + if (itemsWidth.length !== items.length) { + if (childrenArray.length === items.length) { + setItemsWidth( + childrenArray.map(child => child.getBoundingClientRect().width), + ); + } else { + setOverflowingIndex(-1); + return; + } + } + + // Calculates the index of the first overflowed element + // +1 is to give at least one pixel of difference and avoid flakiness + const index = childrenArray.findIndex( + child => + child.getBoundingClientRect().right > + container.getBoundingClientRect().right + 1, + ); + + // If elements fit (-1) and there's overflowed items + // then preserve the overflow index. We can't use overflowIndex + // directly because the items may have been modified + let newOverflowingIndex = + index === -1 && overflowedItems.length > 0 + ? items.length - overflowedItems.length + : index; + + if (width > previousWidth) { + // Calculates remaining space in the container + const button = current?.children.item(1); + const buttonRight = button?.getBoundingClientRect().right || 0; + const containerRight = current?.getBoundingClientRect().right || 0; + const remainingSpace = containerRight - buttonRight; + + // Checks if some elements in the dropdown fits in the remaining space + let sum = 0; + for (let i = childrenArray.length; i < items.length; i += 1) { + sum += itemsWidth[i]; + if (sum <= remainingSpace) { + newOverflowingIndex = i + 1; + } else { + break; + } + } + } + + setOverflowingIndex(newOverflowingIndex); + } + }, [ + current, + items.length, + itemsWidth, + overflowedItems.length, + previousWidth, + width, + ]); + + useEffect(() => { + if (onOverflowingStateChange) { + onOverflowingStateChange({ + notOverflowed: notOverflowedIds, + overflowed: overflowedIds, + }); + } + }, [notOverflowedIds, onOverflowingStateChange, overflowedIds]); + + const overflowingCount = + overflowingIndex !== -1 ? items.length - overflowingIndex : 0; + + const popoverContent = useMemo( + () => + dropdownContent || overflowingCount ? ( + <div + css={css` + display: flex; + flex-direction: column; + gap: ${theme.gridUnit * 4}px; + `} + data-test="dropdown-content" + style={dropdownStyle} + ref={targetRef} + > + {dropdownContent + ? dropdownContent(overflowedItems) + : overflowedItems.map(item => item.element)} + </div> + ) : null, + [ + dropdownContent, + overflowingCount, + theme.gridUnit, + dropdownStyle, + overflowedItems, + ], + ); + + useLayoutEffect(() => { + if (popoverVisible) { + // Measures scroll height after rendering the elements + setTimeout(() => { + if (targetRef.current) { + // We only set overflow when there's enough space to display + // Select's popovers because they are restrained by the overflow property. + setShowOverflow(targetRef.current.scrollHeight > MAX_HEIGHT); + } + }, 100); + } + }, [popoverVisible]); + + useImperativeHandle( + outerRef, + () => ({ + ...(ref.current as HTMLDivElement), + open: () => setPopoverVisible(true), + }), + [ref], + ); + + // Closes the popover when scrolling on the document + useEffect(() => { + document.onscroll = popoverVisible + ? () => setPopoverVisible(false) + : null; + return () => { + document.onscroll = null; + }; + }, [popoverVisible]); + + return ( + <div + ref={ref} + css={css` + display: flex; + align-items: center; + `} + > + <div + css={css` + display: flex; + align-items: center; + gap: ${theme.gridUnit * 4}px; + margin-right: ${theme.gridUnit * 4}px; + min-width: 0px; + `} + data-test="container" + style={style} + > + {notOverflowedItems.map(item => item.element)} + </div> + {popoverContent && ( + <> + <Global + styles={css` + .ant-popover-inner-content { + max-height: ${MAX_HEIGHT}px; + overflow: ${showOverflow ? 'auto' : 'visible'}; + padding: ${theme.gridUnit * 3}px ${theme.gridUnit * 4}px; + + // Some OS versions only show the scroll when hovering. + // These settings will make the scroll always visible. + ::-webkit-scrollbar { + -webkit-appearance: none; + width: 14px; + } + ::-webkit-scrollbar-thumb { + border-radius: 9px; + background-color: ${theme.colors.grayscale.light1}; + border: 3px solid transparent; + background-clip: content-box; + } + ::-webkit-scrollbar-track { + background-color: ${theme.colors.grayscale.light4}; + border-left: 1px solid ${theme.colors.grayscale.light2}; + } + } + `} + /> + <Popover + content={popoverContent} + trigger="click" + visible={popoverVisible} + onVisibleChange={visible => setPopoverVisible(visible)} + placement="bottom" + destroyTooltipOnHide + > + <Tooltip title={dropdownTriggerTooltip}> + <Button + buttonStyle="secondary" + data-test="dropdown-container-btn" + > + {dropdownTriggerIcon} + {dropdownTriggerText} + <Badge + count={dropdownTriggerCount ?? overflowingCount} + color={ + (dropdownTriggerCount ?? overflowingCount) > 0 + ? theme.colors.primary.base + : theme.colors.grayscale.light1 + } + showZero + css={css` + margin-left: ${theme.gridUnit * 2}px; + `} + /> + <Icons.DownOutlined + iconSize="m" + iconColor={theme.colors.grayscale.light1} + css={css` + .anticon { + display: flex; + } + `} + /> + </Button> + </Tooltip> + </Popover> + </> + )} + </div> + ); + }, +); + +export default DropdownContainer; diff --git a/superset-frontend/src/components/DropdownSelectableIcon/DropdownSelectableIcon.stories.tsx b/superset-frontend/src/components/DropdownSelectableIcon/DropdownSelectableIcon.stories.tsx new file mode 100644 index 0000000000000..1b5bfbc520ac6 --- /dev/null +++ b/superset-frontend/src/components/DropdownSelectableIcon/DropdownSelectableIcon.stories.tsx @@ -0,0 +1,65 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import Icons from 'src/components/Icons'; +import DropdownSelectableIcon, { DropDownSelectableProps } from '.'; + +export default { + title: 'DropdownSelectableIcon', + component: DropdownSelectableIcon, +}; + +export const Component = (props: DropDownSelectableProps) => ( + <DropdownSelectableIcon + {...props} + icon={<Icons.Gear name="gear" iconColor="#000000" />} + /> +); + +Component.story = { + parameters: { + knobs: { + disable: true, + }, + }, +}; + +Component.args = { + info: 'Info go here', + selectedKeys: ['vertical'], + menuItems: [ + { + key: 'vertical', + label: 'Vertical', + }, + { + key: 'horizontal', + label: 'Horizontal', + }, + ], +}; + +Component.argTypes = { + onSelect: { + action: 'onSelect', + table: { + disable: true, + }, + }, +}; diff --git a/superset-frontend/src/components/DropdownSelectableIcon/DropdownSelectableIcon.test.tsx b/superset-frontend/src/components/DropdownSelectableIcon/DropdownSelectableIcon.test.tsx new file mode 100644 index 0000000000000..51007d96ff567 --- /dev/null +++ b/superset-frontend/src/components/DropdownSelectableIcon/DropdownSelectableIcon.test.tsx @@ -0,0 +1,99 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import Icons from 'src/components/Icons'; +import userEvent from '@testing-library/user-event'; +import DropdownSelectableIcon, { DropDownSelectableProps } from '.'; + +const mockedProps = { + menuItems: [ + { + key: 'vertical', + label: 'vertical', + }, + { + key: 'horizontal', + label: 'horizontal', + }, + ], + selectedKeys: [], + icon: <Icons.Gear name="gear" />, +}; + +const asyncRender = (props: DropDownSelectableProps) => + waitFor(() => render(<DropdownSelectableIcon {...props} />)); + +const openMenu = () => { + userEvent.click(screen.getByRole('img', { name: 'gear' })); +}; + +test('should render', async () => { + const { container } = await asyncRender(mockedProps); + expect(container).toBeInTheDocument(); +}); + +test('should render the icon', async () => { + await asyncRender(mockedProps); + expect(screen.getByRole('img', { name: 'gear' })).toBeInTheDocument(); +}); + +test('should not render the info', async () => { + await asyncRender(mockedProps); + openMenu(); + expect( + screen.queryByTestId('dropdown-selectable-info'), + ).not.toBeInTheDocument(); +}); + +test('should render the info', async () => { + const infoProps = { + ...mockedProps, + info: 'Test', + }; + await asyncRender(infoProps); + openMenu(); + expect(screen.getByTestId('dropdown-selectable-info')).toBeInTheDocument(); + expect(screen.getByText('Test')).toBeInTheDocument(); +}); + +test('should render the menu items', async () => { + await asyncRender(mockedProps); + openMenu(); + expect(screen.getAllByRole('menuitem')).toHaveLength(2); + expect(screen.getByText('vertical')).toBeInTheDocument(); + expect(screen.getByText('horizontal')).toBeInTheDocument(); +}); + +test('should not render any selected menu item', async () => { + await asyncRender(mockedProps); + openMenu(); + expect(screen.getAllByRole('menuitem')).toHaveLength(2); + expect(screen.queryByRole('img', { name: 'check' })).not.toBeInTheDocument(); +}); + +test('should render the selected menu items', async () => { + const selectedProps = { + ...mockedProps, + selectedKeys: ['vertical'], + }; + await asyncRender(selectedProps); + openMenu(); + expect(screen.getByRole('img', { name: 'check' })).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/components/DropdownSelectableIcon/index.tsx b/superset-frontend/src/components/DropdownSelectableIcon/index.tsx new file mode 100644 index 0000000000000..85c4284439f19 --- /dev/null +++ b/superset-frontend/src/components/DropdownSelectableIcon/index.tsx @@ -0,0 +1,154 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { styled, useTheme } from '@superset-ui/core'; +import React, { RefObject, useMemo } from 'react'; +import Icons from 'src/components/Icons'; +import { DropdownButton } from 'src/components/DropdownButton'; +import { DropdownButtonProps } from 'antd/lib/dropdown'; +import { Menu, MenuProps } from 'src/components/Menu'; + +const { SubMenu } = Menu; + +type SubMenuItemProps = { key: string; label: string | React.ReactNode }; + +export interface DropDownSelectableProps extends Pick<MenuProps, 'onSelect'> { + ref?: RefObject<HTMLDivElement>; + icon: React.ReactNode; + info?: string; + menuItems: { + key: string; + label: string | React.ReactNode; + children?: SubMenuItemProps[]; + divider?: boolean; + }[]; + selectedKeys?: string[]; +} + +const StyledDropdownButton = styled( + DropdownButton as React.FC<DropdownButtonProps>, +)` + button.ant-btn:first-of-type { + display: none; + } + > button.ant-btn:nth-child(2) { + display: inline-flex; + background-color: transparent !important; + height: unset; + padding: 0; + border: none; + width: auto !important; + + .anticon { + line-height: 0; + } + &:after { + box-shadow: none !important; + } + } +`; + +const StyledMenu = styled(Menu)` + ${({ theme }) => ` + .info { + font-size: ${theme.typography.sizes.s}px; + color: ${theme.colors.grayscale.base}; + padding: ${theme.gridUnit}px ${theme.gridUnit * 3}px ${ + theme.gridUnit + }px ${theme.gridUnit * 3}px; + } + .ant-dropdown-menu-item-selected { + color: ${theme.colors.grayscale.dark1}; + background-color: ${theme.colors.primary.light5}; + } + `} +`; + +const StyleMenuItem = styled(Menu.Item)<{ divider?: boolean }>` + display: flex; + justify-content: space-between; + > span { + width: 100%; + } + border-bottom: ${({ divider, theme }) => + divider ? `1px solid ${theme.colors.grayscale.light3};` : 'none;'}; +`; + +const StyleSubmenuItem = styled.div` + display: flex; + justify-content: space-between; + > span { + width: 100%; + } +`; + +export default (props: DropDownSelectableProps) => { + const theme = useTheme(); + const { icon, info, menuItems, selectedKeys, onSelect } = props; + const menuItem = ( + label: string | React.ReactNode, + key: string, + divider?: boolean, + ) => ( + <StyleMenuItem key={key} divider={divider}> + <StyleSubmenuItem> + <span>{label}</span> + {selectedKeys?.includes(key) && ( + <Icons.Check + iconColor={theme.colors.primary.base} + className="tick-menu-item" + iconSize="xl" + /> + )} + </StyleSubmenuItem> + </StyleMenuItem> + ); + const overlayMenu = useMemo( + () => ( + <StyledMenu selectedKeys={selectedKeys} onSelect={onSelect} selectable> + {info && ( + <div className="info" data-test="dropdown-selectable-info"> + {info} + </div> + )} + {menuItems.map(m => + m.children?.length ? ( + <SubMenu + title={m.label} + key={m.key} + data-test="dropdown-selectable-icon-submenu" + > + {m.children.map(s => menuItem(s.label, s.key))} + </SubMenu> + ) : ( + menuItem(m.label, m.key, m.divider) + ), + )} + </StyledMenu> + ), + [info, menuItems], + ); + + return ( + <StyledDropdownButton + overlay={overlayMenu} + trigger={['click']} + icon={icon} + /> + ); +}; diff --git a/superset-frontend/src/components/DynamicEditableTitle/index.tsx b/superset-frontend/src/components/DynamicEditableTitle/index.tsx index d9e7066330130..86205bebc267e 100644 --- a/superset-frontend/src/components/DynamicEditableTitle/index.tsx +++ b/superset-frontend/src/components/DynamicEditableTitle/index.tsx @@ -197,7 +197,7 @@ export const DynamicEditableTitle = ({ ${inputWidth && inputWidth > 0 && css` - width: ${inputWidth}px; + width: ${inputWidth + 1}px; `} `} /> diff --git a/superset-frontend/src/components/EditableTitle/index.tsx b/superset-frontend/src/components/EditableTitle/index.tsx index 131e9731c0dcf..eebb0c714cfa5 100644 --- a/superset-frontend/src/components/EditableTitle/index.tsx +++ b/superset-frontend/src/components/EditableTitle/index.tsx @@ -17,8 +17,9 @@ * under the License. */ import React, { useEffect, useState, useRef } from 'react'; +import { Link } from 'react-router-dom'; import cx from 'classnames'; -import { css, styled, t } from '@superset-ui/core'; +import { css, styled, SupersetTheme, t } from '@superset-ui/core'; import { Tooltip } from 'src/components/Tooltip'; import CertifiedBadge from '../CertifiedBadge'; @@ -37,7 +38,7 @@ export interface EditableTitleProps { placeholder?: string; certifiedBy?: string; certificationDetails?: string; - onClickTitle?: () => void; + url?: string; } const StyledCertifiedBadge = styled(CertifiedBadge)` @@ -58,7 +59,7 @@ export default function EditableTitle({ placeholder = '', certifiedBy, certificationDetails, - onClickTitle, + url, // rest is related to title tooltip ...rest }: EditableTitleProps) { @@ -218,20 +219,20 @@ export default function EditableTitle({ } if (!canEdit) { // don't actually want an input in this case - titleComponent = onClickTitle ? ( - <span - role="button" - onClick={onClickTitle} - tabIndex={0} + titleComponent = url ? ( + <Link + to={url} data-test="editable-title-input" - css={css` + css={(theme: SupersetTheme) => css` + color: ${theme.colors.grayscale.dark1}; + text-decoration: none; :hover { text-decoration: underline; } `} > {value} - </span> + </Link> ) : ( <span data-test="editable-title-input">{value}</span> ); diff --git a/superset-frontend/src/components/EmptyState/index.tsx b/superset-frontend/src/components/EmptyState/index.tsx index 7ee69d7eea5e9..b8230c8fcf246 100644 --- a/superset-frontend/src/components/EmptyState/index.tsx +++ b/superset-frontend/src/components/EmptyState/index.tsx @@ -18,7 +18,7 @@ */ import React, { ReactNode, SyntheticEvent } from 'react'; -import { styled, css, SupersetTheme } from '@superset-ui/core'; +import { styled, css, SupersetTheme, t } from '@superset-ui/core'; import { Empty } from 'src/components'; import Button from 'src/components/Button'; @@ -31,12 +31,13 @@ export enum EmptyStateSize { export interface EmptyStateSmallProps { title: ReactNode; description?: ReactNode; - image: ReactNode; + image?: ReactNode; } export interface EmptyStateProps extends EmptyStateSmallProps { buttonText?: ReactNode; buttonAction?: React.MouseEventHandler<HTMLElement>; + className?: string; } export interface ImageContainerProps { @@ -152,9 +153,10 @@ export const EmptyStateBig = ({ description, buttonAction, buttonText, + className, }: EmptyStateProps) => ( - <EmptyStateContainer> - <ImageContainer image={image} size={EmptyStateSize.Big} /> + <EmptyStateContainer className={className}> + {image && <ImageContainer image={image} size={EmptyStateSize.Big} />} <TextContainer css={(theme: SupersetTheme) => css` @@ -185,7 +187,7 @@ export const EmptyStateMedium = ({ buttonText, }: EmptyStateProps) => ( <EmptyStateContainer> - <ImageContainer image={image} size={EmptyStateSize.Medium} /> + {image && <ImageContainer image={image} size={EmptyStateSize.Medium} />} <TextContainer css={(theme: SupersetTheme) => css` @@ -214,7 +216,7 @@ export const EmptyStateSmall = ({ description, }: EmptyStateSmallProps) => ( <EmptyStateContainer> - <ImageContainer image={image} size={EmptyStateSize.Small} /> + {image && <ImageContainer image={image} size={EmptyStateSize.Small} />} <TextContainer css={(theme: SupersetTheme) => css` @@ -227,3 +229,27 @@ export const EmptyStateSmall = ({ </TextContainer> </EmptyStateContainer> ); + +const TRANSLATIONS = { + NO_DATABASES_MATCH_TITLE: t('No databases match your search'), + NO_DATABASES_AVAILABLE_TITLE: t('There are no databases available'), + MANAGE_YOUR_DATABASES_TEXT: t('Manage your databases'), + HERE_TEXT: t('here'), +}; + +export const emptyStateComponent = (emptyResultsWithSearch: boolean) => ( + <EmptyStateSmall + image="empty.svg" + title={ + emptyResultsWithSearch + ? TRANSLATIONS.NO_DATABASES_MATCH_TITLE + : TRANSLATIONS.NO_DATABASES_AVAILABLE_TITLE + } + description={ + <p> + {TRANSLATIONS.MANAGE_YOUR_DATABASES_TEXT}{' '} + <a href="/databaseview/list">{TRANSLATIONS.HERE_TEXT}</a> + </p> + } + /> +); diff --git a/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.test.tsx b/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.test.tsx index b6be9a1b9f8cf..dd2187c9315e1 100644 --- a/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.test.tsx +++ b/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.test.tsx @@ -23,6 +23,13 @@ import { supersetTheme } from '@superset-ui/core'; import BasicErrorAlert from './BasicErrorAlert'; import { ErrorLevel } from './types'; +jest.mock( + 'src/components/Icons/Icon', + () => + ({ fileName }: { fileName: string }) => + <span role="img" aria-label={fileName.replace('_', '-')} />, +); + const mockedProps = { body: 'Error body', level: 'warning' as ErrorLevel, diff --git a/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.test.tsx b/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.test.tsx index 6959c5351a7ee..c8dbe8ba345f0 100644 --- a/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.test.tsx +++ b/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.test.tsx @@ -23,6 +23,13 @@ import userEvent from '@testing-library/user-event'; import DatabaseErrorMessage from './DatabaseErrorMessage'; import { ErrorLevel, ErrorSource, ErrorTypeEnum } from './types'; +jest.mock( + 'src/components/Icons/Icon', + () => + ({ fileName }: { fileName: string }) => + <span role="img" aria-label={fileName.replace('_', '-')} />, +); + const mockedProps = { error: { error_type: ErrorTypeEnum.DATABASE_SECURITY_ACCESS_ERROR, diff --git a/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx b/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx index 612abcaf75d17..a7a0a4199f5d8 100644 --- a/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx +++ b/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx @@ -75,19 +75,18 @@ function DatabaseErrorMessage({ </> ); - const copyText = - extra && extra.issue_codes - ? t('%(message)s\nThis may be triggered by: \n%(issues)s', { - message, - issues: extra.issue_codes - .map(issueCode => issueCode.message) - .join('\n'), - }) - : message; + const copyText = extra?.issue_codes + ? t('%(message)s\nThis may be triggered by: \n%(issues)s', { + message, + issues: extra.issue_codes + .map(issueCode => issueCode.message) + .join('\n'), + }) + : message; return ( <ErrorAlert - title={t('%s Error', (extra && extra.engine_name) || t('DB engine'))} + title={t('%s Error', extra?.engine_name || t('DB engine'))} subtitle={subtitle} level={level} source={source} diff --git a/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.test.tsx b/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.test.tsx index 087b08fa8f865..e73d2eb93b6a9 100644 --- a/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.test.tsx +++ b/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.test.tsx @@ -22,6 +22,13 @@ import { render, screen } from 'spec/helpers/testing-library'; import DatasetNotFoundErrorMessage from './DatasetNotFoundErrorMessage'; import { ErrorLevel, ErrorSource, ErrorTypeEnum } from './types'; +jest.mock( + 'src/components/Icons/Icon', + () => + ({ fileName }: { fileName: string }) => + <span role="img" aria-label={fileName.replace('_', '-')} />, +); + const mockedProps = { error: { error_type: ErrorTypeEnum.FAILED_FETCHING_DATASOURCE_INFO_ERROR, diff --git a/superset-frontend/src/components/ErrorMessage/ErrorAlert.test.tsx b/superset-frontend/src/components/ErrorMessage/ErrorAlert.test.tsx index 7133f25c9e5e5..38006c2ec409e 100644 --- a/superset-frontend/src/components/ErrorMessage/ErrorAlert.test.tsx +++ b/superset-frontend/src/components/ErrorMessage/ErrorAlert.test.tsx @@ -24,6 +24,13 @@ import { supersetTheme } from '@superset-ui/core'; import ErrorAlert from './ErrorAlert'; import { ErrorLevel, ErrorSource } from './types'; +jest.mock( + 'src/components/Icons/Icon', + () => + ({ fileName }: { fileName: string }) => + <span role="img" aria-label={fileName.replace('_', '-')} />, +); + const mockedProps = { body: 'Error body', level: 'warning' as ErrorLevel, @@ -31,6 +38,7 @@ const mockedProps = { subtitle: 'Error subtitle', title: 'Error title', source: 'dashboard' as ErrorSource, + description: 'we are unable to connect db.', }; test('should render', () => { @@ -63,6 +71,11 @@ test('should render the error title', () => { expect(screen.getByText('Error title')).toBeInTheDocument(); }); +test('should render the error description', () => { + render(<ErrorAlert {...mockedProps} />, { useRedux: true }); + expect(screen.getByText('we are unable to connect db.')).toBeInTheDocument(); +}); + test('should render the error subtitle', () => { render(<ErrorAlert {...mockedProps} />, { useRedux: true }); const button = screen.getByText('See more'); diff --git a/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx b/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx index 3340c8ad6d3e7..cf2522b4e43ce 100644 --- a/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx +++ b/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx @@ -87,6 +87,7 @@ interface ErrorAlertProps { source?: ErrorSource; subtitle: ReactNode; title: ReactNode; + description?: string; } export default function ErrorAlert({ @@ -96,6 +97,7 @@ export default function ErrorAlert({ source = 'dashboard', subtitle, title, + description, }: ErrorAlertProps) { const theme = useTheme(); @@ -116,7 +118,7 @@ export default function ErrorAlert({ )} <strong>{title}</strong> </LeftSideContent> - {!isExpandable && ( + {!isExpandable && !description && ( <span role="button" tabIndex={0} @@ -127,6 +129,21 @@ export default function ErrorAlert({ </span> )} </div> + {description && ( + <div className="error-body"> + <p>{description}</p> + {!isExpandable && ( + <span + role="button" + tabIndex={0} + className="link" + onClick={() => setIsModalOpen(true)} + > + {t('See more')} + </span> + )} + </div> + )} {isExpandable ? ( <div className="error-body"> <p>{subtitle}</p> @@ -196,7 +213,10 @@ export default function ErrorAlert({ > <> <p>{subtitle}</p> - <br /> + {/* This break was in the original design of the modal but + the spacing looks really off if there is only + subtitle or a body */} + {subtitle && body && <br />} {body} </> </ErrorModal> diff --git a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx index 6e343eba7ff20..ae30e5cb991bd 100644 --- a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx +++ b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx @@ -23,6 +23,13 @@ import userEvent from '@testing-library/user-event'; import ErrorMessageWithStackTrace from './ErrorMessageWithStackTrace'; import { ErrorLevel, ErrorSource } from './types'; +jest.mock( + 'src/components/Icons/Icon', + () => + ({ fileName }: { fileName: string }) => + <span role="img" aria-label={fileName.replace('_', '-')} />, +); + const mockedProps = { level: 'warning' as ErrorLevel, link: 'https://sample.com', diff --git a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx index c073cf0461b47..b54277b4ac2db 100644 --- a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx +++ b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx @@ -18,7 +18,6 @@ */ import React from 'react'; import { t } from '@superset-ui/core'; - import getErrorMessageComponentRegistry from './getErrorMessageComponentRegistry'; import { SupersetError, ErrorSource } from './types'; import ErrorAlert from './ErrorAlert'; @@ -33,6 +32,8 @@ type Props = { copyText?: string; stackTrace?: string; source?: ErrorSource; + description?: string; + errorMitigationFunction?: () => void; }; export default function ErrorMessageWithStackTrace({ @@ -43,6 +44,7 @@ export default function ErrorMessageWithStackTrace({ link, stackTrace, source, + description, }: Props) { // Check if a custom error message component was registered for this message if (error) { @@ -66,6 +68,7 @@ export default function ErrorMessageWithStackTrace({ title={title} subtitle={subtitle} copyText={copyText} + description={description} source={source} body={ link || stackTrace ? ( diff --git a/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.test.tsx b/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.test.tsx index 17f38c4d23c57..e8be71b7e3079 100644 --- a/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.test.tsx +++ b/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.test.tsx @@ -23,6 +23,13 @@ import { render, screen } from 'spec/helpers/testing-library'; import ParameterErrorMessage from './ParameterErrorMessage'; import { ErrorLevel, ErrorSource, ErrorTypeEnum } from './types'; +jest.mock( + 'src/components/Icons/Icon', + () => + ({ fileName }: { fileName: string }) => + <span role="img" aria-label={fileName.replace('_', '-')} />, +); + const mockedProps = { error: { error_type: ErrorTypeEnum.MISSING_TEMPLATE_PARAMS_ERROR, diff --git a/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.test.tsx b/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.test.tsx index e41308f5381b5..cc3a8a9a599e4 100644 --- a/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.test.tsx +++ b/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.test.tsx @@ -23,6 +23,13 @@ import { render, screen } from 'spec/helpers/testing-library'; import TimeoutErrorMessage from './TimeoutErrorMessage'; import { ErrorLevel, ErrorSource, ErrorTypeEnum } from './types'; +jest.mock( + 'src/components/Icons/Icon', + () => + ({ fileName }: { fileName: string }) => + <span role="img" aria-label={fileName.replace('_', '-')} />, +); + const mockedProps = { error: { error_type: ErrorTypeEnum.FRONTEND_TIMEOUT_ERROR, diff --git a/superset-frontend/src/components/FacePile/index.tsx b/superset-frontend/src/components/FacePile/index.tsx index 730d162e2d14e..44cc62ce1d624 100644 --- a/superset-frontend/src/components/FacePile/index.tsx +++ b/superset-frontend/src/components/FacePile/index.tsx @@ -67,8 +67,8 @@ export default function FacePile({ users, maxCount = 4 }: FacePileProps) { borderColor: color, }} > - {first_name && first_name[0]?.toLocaleUpperCase()} - {last_name && last_name[0]?.toLocaleUpperCase()} + {first_name?.[0]?.toLocaleUpperCase()} + {last_name?.[0]?.toLocaleUpperCase()} </StyledAvatar> </Tooltip> ); diff --git a/superset-frontend/src/components/FaveStar/FaveStar.test.tsx b/superset-frontend/src/components/FaveStar/FaveStar.test.tsx index 68433db96ea4e..ab2fa9fa0ed1e 100644 --- a/superset-frontend/src/components/FaveStar/FaveStar.test.tsx +++ b/superset-frontend/src/components/FaveStar/FaveStar.test.tsx @@ -26,13 +26,13 @@ jest.mock('src/components/Tooltip', () => ({ Tooltip: (props: any) => <div data-test="tooltip" {...props} />, })); -test('render right content', () => { +test('render right content', async () => { const props = { itemId: 3, saveFaveStar: jest.fn(), }; - const { rerender } = render(<FaveStar {...props} isStarred />); + const { rerender, findByRole } = render(<FaveStar {...props} isStarred />); expect(screen.getByRole('button')).toBeInTheDocument(); expect( screen.getByRole('img', { name: 'favorite-selected' }), @@ -45,7 +45,7 @@ test('render right content', () => { rerender(<FaveStar {...props} />); expect( - screen.getByRole('img', { name: 'favorite-unselected' }), + await findByRole('img', { name: 'favorite-unselected' }), ).toBeInTheDocument(); expect(props.saveFaveStar).toBeCalledTimes(1); @@ -54,7 +54,7 @@ test('render right content', () => { expect(props.saveFaveStar).toBeCalledWith(props.itemId, false); }); -test('render content on tooltip', () => { +test('render content on tooltip', async () => { const props = { itemId: 3, showTooltip: true, @@ -63,7 +63,7 @@ test('render content on tooltip', () => { render(<FaveStar {...props} />); - expect(screen.getByTestId('tooltip')).toBeInTheDocument(); + expect(await screen.findByTestId('tooltip')).toBeInTheDocument(); expect(screen.getByTestId('tooltip')).toHaveAttribute( 'id', 'fave-unfave-tooltip', @@ -75,7 +75,7 @@ test('render content on tooltip', () => { expect(screen.getByRole('button')).toBeInTheDocument(); }); -test('Call fetchFaveStar only on the first render', () => { +test('Call fetchFaveStar only on the first render', async () => { const props = { itemId: 3, fetchFaveStar: jest.fn(), @@ -84,7 +84,10 @@ test('Call fetchFaveStar only on the first render', () => { showTooltip: false, }; - const { rerender } = render(<FaveStar {...props} />); + const { rerender, findByRole } = render(<FaveStar {...props} />); + expect( + await findByRole('img', { name: 'favorite-unselected' }), + ).toBeInTheDocument(); expect(props.fetchFaveStar).toBeCalledTimes(1); expect(props.fetchFaveStar).toBeCalledWith(props.itemId); diff --git a/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx b/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx index 494af6033072d..8cef35078dd06 100644 --- a/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx +++ b/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx @@ -21,6 +21,7 @@ import { ReactWrapper } from 'enzyme'; import { styledMount as mount } from 'spec/helpers/theming'; import FilterableTable, { MAX_COLUMNS_FOR_TABLE, + convertBigIntStrToNumber, } from 'src/components/FilterableTable'; import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; @@ -331,3 +332,19 @@ describe('FilterableTable sorting - RTL', () => { expect(gridCells[6]).toHaveTextContent('2022-01-02'); }); }); + +test('renders bigInt value in a number format', () => { + expect(convertBigIntStrToNumber('123')).toBe('123'); + expect(convertBigIntStrToNumber('some string value')).toBe( + 'some string value', + ); + expect(convertBigIntStrToNumber('{ a: 123 }')).toBe('{ a: 123 }'); + expect(convertBigIntStrToNumber('"Not a Number"')).toBe('"Not a Number"'); + // trim quotes for bigint string format + expect(convertBigIntStrToNumber('"-12345678901234567890"')).toBe( + '-12345678901234567890', + ); + expect(convertBigIntStrToNumber('"12345678901234567890"')).toBe( + '12345678901234567890', + ); +}); diff --git a/superset-frontend/src/components/FilterableTable/index.tsx b/superset-frontend/src/components/FilterableTable/index.tsx index 621565b154c32..e7e8f3ebf4c6b 100644 --- a/superset-frontend/src/components/FilterableTable/index.tsx +++ b/superset-frontend/src/components/FilterableTable/index.tsx @@ -17,8 +17,8 @@ * under the License. */ import JSONbig from 'json-bigint'; -import React, { PureComponent } from 'react'; -import JSONTree from 'react-json-tree'; +import React, { useEffect, useRef, useState } from 'react'; +import { JSONTree } from 'react-json-tree'; import { AutoSizer, Column, @@ -33,8 +33,7 @@ import { getMultipleTextDimensions, t, styled, - SupersetTheme, - withTheme, + useTheme, } from '@superset-ui/core'; import Button from '../Button'; import CopyToClipboard from '../CopyToClipboard'; @@ -54,7 +53,7 @@ function safeJsonObjectParse( // We know `data` is a string starting with '{' or '[', so try to parse it as a valid object try { - const jsonData = JSON.parse(data); + const jsonData = JSONbig({ storeAsString: true }).parse(data); if (jsonData && typeof jsonData === 'object') { return jsonData; } @@ -64,6 +63,17 @@ function safeJsonObjectParse( } } +export function convertBigIntStrToNumber(value: string | number) { + if (typeof value === 'string' && /^"-?\d+"$/.test(value)) { + return value.substring(1, value.length - 1); + } + return value; +} + +function renderBigIntStrToNumber(value: string | number) { + return <>{convertBigIntStrToNumber(value)}</>; +} + const GRID_POSITION_ADJUSTMENT = 4; const SCROLL_BAR_HEIGHT = 15; // This regex handles all possible number formats in javascript, including ints, floats, @@ -188,98 +198,65 @@ export interface FilterableTableProps { orderedColumnKeys: string[]; data: Record<string, unknown>[]; height: number; - filterText: string; - headerHeight: number; - overscanColumnCount: number; - overscanRowCount: number; - rowHeight: number; - striped: boolean; - expandedColumns: string[]; - theme: SupersetTheme; -} - -interface FilterableTableState { - sortBy?: string; - sortDirection?: SortDirectionType; - fitted: boolean; - displayedList: Datum[]; + filterText?: string; + headerHeight?: number; + overscanColumnCount?: number; + overscanRowCount?: number; + rowHeight?: number; + striped?: boolean; + expandedColumns?: string[]; } -class FilterableTable extends PureComponent< - FilterableTableProps, - FilterableTableState -> { - static defaultProps = { - filterText: '', - headerHeight: 32, - overscanColumnCount: 10, - overscanRowCount: 10, - rowHeight: 32, - striped: true, - expandedColumns: [], - }; - - list: Datum[]; - - complexColumns: Record<string, boolean>; - - widthsForColumnsByKey: Record<string, number>; - - totalTableWidth: number; - - totalTableHeight: number; - - container: React.RefObject<HTMLDivElement>; - - jsonTreeTheme: Record<string, string>; - - constructor(props: FilterableTableProps) { - super(props); - this.list = this.formatTableData(props.data); - this.addJsonModal = this.addJsonModal.bind(this); - this.getCellContent = this.getCellContent.bind(this); - this.renderGridCell = this.renderGridCell.bind(this); - this.renderGridCellHeader = this.renderGridCellHeader.bind(this); - this.renderGrid = this.renderGrid.bind(this); - this.renderTableCell = this.renderTableCell.bind(this); - this.renderTableHeader = this.renderTableHeader.bind(this); - this.sortResults = this.sortResults.bind(this); - this.renderTable = this.renderTable.bind(this); - this.rowClassName = this.rowClassName.bind(this); - this.sort = this.sort.bind(this); - this.getJsonTreeTheme = this.getJsonTreeTheme.bind(this); +const FilterableTable = ({ + orderedColumnKeys, + data, + height, + filterText = '', + headerHeight = 32, + overscanColumnCount = 10, + overscanRowCount = 10, + rowHeight = 32, + striped = true, + expandedColumns = [], +}: FilterableTableProps) => { + const formatTableData = (data: Record<string, unknown>[]): Datum[] => + data.map(row => { + const newRow = {}; + Object.entries(row).forEach(([key, val]) => { + if (['string', 'number'].indexOf(typeof val) >= 0) { + newRow[key] = val; + } else { + newRow[key] = val === null ? null : JSONbig.stringify(val); + } + }); + return newRow; + }); - // columns that have complex type and were expanded into sub columns - this.complexColumns = props.orderedColumnKeys.reduce( + const [sortByState, setSortByState] = useState<string | undefined>(undefined); + const [sortDirectionState, setSortDirectionState] = useState< + SortDirectionType | undefined + >(undefined); + const [fitted, setFitted] = useState(false); + const [list] = useState<Datum[]>(() => formatTableData(data)); + const [displayedList, setDisplayedList] = useState<Datum[]>(list); + + // columns that have complex type and were expanded into sub columns + const [complexColumns] = useState<Record<string, boolean>>( + orderedColumnKeys.reduce( (obj, key) => ({ ...obj, - [key]: props.expandedColumns.some(name => name.startsWith(`${key}.`)), + [key]: expandedColumns.some(name => name.startsWith(`${key}.`)), }), {}, - ); - - this.widthsForColumnsByKey = this.getWidthsForColumns(); - this.totalTableWidth = props.orderedColumnKeys - .map(key => this.widthsForColumnsByKey[key]) - .reduce((curr, next) => curr + next); - this.totalTableHeight = props.height; - - this.state = { - fitted: false, - displayedList: [...this.list], - }; + ), + ); - this.container = React.createRef(); - } - - componentDidMount() { - this.fitTableToWidthIfNeeded(); - } + const theme = useTheme(); + const [jsonTreeTheme, setJsonTreeTheme] = useState<Record<string, string>>(); - getJsonTreeTheme() { - if (!this.jsonTreeTheme) { - const { theme } = this.props; - this.jsonTreeTheme = { + const getJsonTreeTheme = () => { + if (!jsonTreeTheme) { + setJsonTreeTheme({ base00: theme.colors.grayscale.dark2, base01: theme.colors.grayscale.dark1, base02: theme.colors.grayscale.base, @@ -296,22 +273,20 @@ class FilterableTable extends PureComponent< base0D: theme.colors.primary.base, base0E: theme.colors.primary.dark1, base0F: theme.colors.error.dark1, - }; + }); } - return this.jsonTreeTheme; - } + return jsonTreeTheme; + }; - getDatum(list: Datum[], index: number) { - return list[index % list.length]; - } + const getDatum = (list: Datum[], index: number) => list[index % list.length]; - getWidthsForColumns() { + const getWidthsForColumns = () => { const PADDING = 50; // accounts for cell padding and width of sorting icon const widthsByColumnKey = {}; const cellContent = ([] as string[]).concat( - ...this.props.orderedColumnKeys.map(key => { - const cellContentList = this.list.map((data: Datum) => - this.getCellContent({ cellData: data[key], columnKey: key }), + ...orderedColumnKeys.map(key => { + const cellContentList = list.map((data: Datum) => + getCellContent({ cellData: data[key], columnKey: key }), ); cellContentList.push(key); return cellContentList; @@ -323,30 +298,26 @@ class FilterableTable extends PureComponent< texts: cellContent, }).map(dimension => dimension.width); - this.props.orderedColumnKeys.forEach((key, index) => { + orderedColumnKeys.forEach((key, index) => { // we can't use Math.max(...colWidths.slice(...)) here since the number // of elements might be bigger than the number of allowed arguments in a - // Javascript function - const value = (widthsByColumnKey[key] = + // JavaScript function + widthsByColumnKey[key] = colWidths - .slice( - index * (this.list.length + 1), - (index + 1) * (this.list.length + 1), - ) - .reduce((a, b) => Math.max(a, b)) + PADDING); - widthsByColumnKey[key] = value; + .slice(index * (list.length + 1), (index + 1) * (list.length + 1)) + .reduce((a, b) => Math.max(a, b)) + PADDING; }); return widthsByColumnKey; - } + }; - getCellContent({ + const getCellContent = ({ cellData, columnKey, }: { cellData: CellDataType; columnKey: string; - }) { + }) => { if (cellData === null) { return 'NULL'; } @@ -360,24 +331,34 @@ class FilterableTable extends PureComponent< } else { truncated = ''; } - return this.complexColumns[columnKey] ? truncated : content; - } + return complexColumns[columnKey] ? truncated : content; + }; - formatTableData(data: Record<string, unknown>[]): Datum[] { - return data.map(row => { - const newRow = {}; - Object.entries(row).forEach(([key, val]) => { - if (['string', 'number'].indexOf(typeof val) >= 0) { - newRow[key] = val; - } else { - newRow[key] = val === null ? null : JSONbig.stringify(val); - } - }); - return newRow; - }); - } + const [widthsForColumnsByKey] = useState<Record<string, number>>(() => + getWidthsForColumns(), + ); + + const totalTableWidth = useRef( + orderedColumnKeys + .map(key => widthsForColumnsByKey[key]) + .reduce((curr, next) => curr + next), + ); + const container = useRef<HTMLDivElement>(null); + + const fitTableToWidthIfNeeded = () => { + const containerWidth = container.current?.clientWidth ?? 0; + if (totalTableWidth.current < containerWidth) { + // fit table width if content doesn't fill the width of the container + totalTableWidth.current = containerWidth; + } + setFitted(true); + }; - hasMatch(text: string, row: Datum) { + useEffect(() => { + fitTableToWidthIfNeeded(); + }, []); + + const hasMatch = (text: string, row: Datum) => { const values: string[] = []; Object.keys(row).forEach(key => { if (row.hasOwnProperty(key)) { @@ -394,82 +375,66 @@ class FilterableTable extends PureComponent< }); const lowerCaseText = text.toLowerCase(); return values.some(v => v.includes(lowerCaseText)); - } + }; - rowClassName({ index }: { index: number }) { + const rowClassName = ({ index }: { index: number }) => { let className = ''; - if (this.props.striped) { + if (striped) { className = index % 2 === 0 ? 'even-row' : 'odd-row'; } return className; - } + }; - sort({ + const sort = ({ sortBy, sortDirection, }: { sortBy: string; sortDirection: SortDirectionType; - }) { - let updatedState: FilterableTableState; - + }) => { const shouldClearSort = - this.state.sortDirection === SortDirection.DESC && - this.state.sortBy === sortBy; + sortDirectionState === SortDirection.DESC && sortByState === sortBy; if (shouldClearSort) { - updatedState = { - ...this.state, - sortBy: undefined, - sortDirection: undefined, - displayedList: [...this.list], - }; + setSortByState(undefined); + setSortDirectionState(undefined); + setDisplayedList([...list]); } else { - updatedState = { - ...this.state, - sortBy, - sortDirection, - displayedList: [...this.list].sort( - this.sortResults(sortBy, sortDirection === SortDirection.DESC), + setSortByState(sortBy); + setSortDirectionState(sortDirection); + setDisplayedList( + [...list].sort( + sortResults(sortBy, sortDirection === SortDirection.DESC), ), - }; - } - - this.setState(updatedState); - } - - fitTableToWidthIfNeeded() { - const containerWidth = this.container.current?.clientWidth ?? 0; - if (this.totalTableWidth < containerWidth) { - // fit table width if content doesn't fill the width of the container - this.totalTableWidth = containerWidth; + ); } - this.setState({ fitted: true }); - } + }; - addJsonModal( + const addJsonModal = ( node: React.ReactNode, jsonObject: Record<string, unknown> | unknown[], jsonString: CellDataType, - ) { - return ( - <ModalTrigger - modalBody={ - <JSONTree data={jsonObject} theme={this.getJsonTreeTheme()} /> - } - modalFooter={ - <Button> - <CopyToClipboard shouldShowText={false} text={jsonString} /> - </Button> - } - modalTitle={t('Cell content')} - triggerNode={node} - /> - ); - } + ) => ( + <ModalTrigger + modalBody={ + <JSONTree + data={jsonObject} + theme={getJsonTreeTheme()} + valueRenderer={renderBigIntStrToNumber} + /> + } + modalFooter={ + <Button> + <CopyToClipboard shouldShowText={false} text={jsonString} /> + </Button> + } + modalTitle={t('Cell content')} + triggerNode={node} + /> + ); // Parse any numbers from strings so they'll sort correctly - parseNumberFromString = (value: string | number | null) => { + const parseNumberFromString = (value: string | number | null) => { if (typeof value === 'string') { if (ONLY_NUMBER_REGEX.test(value)) { return parseFloat(value); @@ -479,10 +444,10 @@ class FilterableTable extends PureComponent< return value; }; - sortResults(sortBy: string, descending: boolean) { - return (a: Datum, b: Datum) => { - const aValue = this.parseNumberFromString(a[sortBy]); - const bValue = this.parseNumberFromString(b[sortBy]); + const sortResults = + (sortBy: string, descending: boolean) => (a: Datum, b: Datum) => { + const aValue = parseNumberFromString(a[sortBy]); + const bValue = parseNumberFromString(b[sortBy]); // equal items sort equally if (aValue === bValue) { @@ -502,20 +467,18 @@ class FilterableTable extends PureComponent< } return aValue < bValue ? -1 : 1; }; - } - sortGrid = (label: string) => { - this.sort({ + const sortGrid = (label: string) => { + sort({ sortBy: label, sortDirection: - this.state.sortDirection === SortDirection.DESC || - this.state.sortBy !== label + sortDirectionState === SortDirection.DESC || sortByState !== label ? SortDirection.ASC : SortDirection.DESC, }); }; - renderTableHeader({ + const renderTableHeader = ({ dataKey, label, sortBy, @@ -525,9 +488,9 @@ class FilterableTable extends PureComponent< label: string; sortBy: string; sortDirection: SortDirectionType; - }) { + }) => { const className = - this.props.expandedColumns.indexOf(label) > -1 + expandedColumns.indexOf(label) > -1 ? 'header-style-disabled' : 'header-style'; @@ -537,9 +500,9 @@ class FilterableTable extends PureComponent< {sortBy === dataKey && <SortIndicator sortDirection={sortDirection} />} </div> ); - } + }; - renderGridCellHeader({ + const renderGridCellHeader = ({ columnIndex, key, style, @@ -547,10 +510,10 @@ class FilterableTable extends PureComponent< columnIndex: number; key: string; style: React.CSSProperties; - }) { - const label = this.props.orderedColumnKeys[columnIndex]; + }) => { + const label = orderedColumnKeys[columnIndex]; const className = - this.props.expandedColumns.indexOf(label) > -1 + expandedColumns.indexOf(label) > -1 ? 'header-style-disabled' : 'header-style'; return ( @@ -566,17 +529,17 @@ class FilterableTable extends PureComponent< className={`${className} grid-cell grid-header-cell`} role="columnheader" tabIndex={columnIndex} - onClick={() => this.sortGrid(label)} + onClick={() => sortGrid(label)} > {label} - {this.state.sortBy === label && ( - <SortIndicator sortDirection={this.state.sortDirection} /> + {sortByState === label && ( + <SortIndicator sortDirection={sortDirectionState} /> )} </div> ); - } + }; - renderGridCell({ + const renderGridCell = ({ columnIndex, key, rowIndex, @@ -586,10 +549,10 @@ class FilterableTable extends PureComponent< key: string; rowIndex: number; style: React.CSSProperties; - }) { - const columnKey = this.props.orderedColumnKeys[columnIndex]; - const cellData = this.state.displayedList[rowIndex][columnKey]; - const cellText = this.getCellContent({ cellData, columnKey }); + }) => { + const columnKey = orderedColumnKeys[columnIndex]; + const cellData = displayedList[rowIndex][columnKey]; + const cellText = getCellContent({ cellData, columnKey }); const content = cellData === null ? <i className="text-muted">{cellText}</i> : cellText; const cellNode = ( @@ -602,7 +565,7 @@ class FilterableTable extends PureComponent< ? style.top - GRID_POSITION_ADJUSTMENT : style.top, }} - className={`grid-cell ${this.rowClassName({ index: rowIndex })}`} + className={`grid-cell ${rowClassName({ index: rowIndex })}`} > <div css={{ width: 'inherit' }}>{content}</div> </div> @@ -610,37 +573,26 @@ class FilterableTable extends PureComponent< const jsonObject = safeJsonObjectParse(cellData); if (jsonObject) { - return this.addJsonModal(cellNode, jsonObject, cellData); + return addJsonModal(cellNode, jsonObject, cellData); } return cellNode; - } + }; - renderGrid() { - const { - orderedColumnKeys, - overscanColumnCount, - overscanRowCount, - rowHeight, - } = this.props; - - let { height } = this.props; - let totalTableHeight = height; - if ( - this.container.current && - this.totalTableWidth > this.container.current.clientWidth - ) { - // exclude the height of the horizontal scroll bar from the height of the table - // and the height of the table container if the content overflows - height -= SCROLL_BAR_HEIGHT; - totalTableHeight -= SCROLL_BAR_HEIGHT; - } + const renderGrid = () => { + // exclude the height of the horizontal scroll bar from the height of the table + // and the height of the table container if the content overflows + const totalTableHeight = + container.current && + totalTableWidth.current > container.current.clientWidth + ? height - SCROLL_BAR_HEIGHT + : height; const getColumnWidth = ({ index }: { index: number }) => - this.widthsForColumnsByKey[orderedColumnKeys[index]]; + widthsForColumnsByKey[orderedColumnKeys[index]]; // fix height of filterable table return ( - <StyledFilterableTable> + <StyledFilterableTable data-test="grid-container"> <ScrollSync> {({ onScroll, scrollLeft }) => ( <> @@ -648,7 +600,7 @@ class FilterableTable extends PureComponent< {({ width }) => ( <div> <Grid - cellRenderer={this.renderGridCellHeader} + cellRenderer={renderGridCellHeader} columnCount={orderedColumnKeys.length} columnWidth={getColumnWidth} height={rowHeight} @@ -659,14 +611,14 @@ class FilterableTable extends PureComponent< style={{ overflow: 'hidden' }} /> <Grid - cellRenderer={this.renderGridCell} + cellRenderer={renderGridCell} columnCount={orderedColumnKeys.length} columnWidth={getColumnWidth} height={totalTableHeight - rowHeight} onScroll={onScroll} overscanColumnCount={overscanColumnCount} overscanRowCount={overscanRowCount} - rowCount={this.list.length} + rowCount={list.length} rowHeight={rowHeight} width={width} /> @@ -678,86 +630,73 @@ class FilterableTable extends PureComponent< </ScrollSync> </StyledFilterableTable> ); - } + }; - renderTableCell({ + const renderTableCell = ({ cellData, columnKey, }: { cellData: CellDataType; columnKey: string; - }) { - const cellNode = this.getCellContent({ cellData, columnKey }); + }) => { + const cellNode = getCellContent({ cellData, columnKey }); const content = cellData === null ? <i className="text-muted">{cellNode}</i> : cellNode; const jsonObject = safeJsonObjectParse(cellData); if (jsonObject) { - return this.addJsonModal(cellNode, jsonObject, cellData); + return addJsonModal(cellNode, jsonObject, cellData); } return content; - } + }; - renderTable() { - const { sortBy, sortDirection } = this.state; - const { - filterText, - headerHeight, - orderedColumnKeys, - overscanRowCount, - rowHeight, - } = this.props; - - let sortedAndFilteredList = this.state.displayedList; + const renderTable = () => { + let sortedAndFilteredList = displayedList; // filter list if (filterText) { sortedAndFilteredList = sortedAndFilteredList.filter((row: Datum) => - this.hasMatch(filterText, row), + hasMatch(filterText, row), ); } - let { height } = this.props; - let totalTableHeight = height; - if ( - this.container.current && - this.totalTableWidth > this.container.current.clientWidth - ) { - // exclude the height of the horizontal scroll bar from the height of the table - // and the height of the table container if the content overflows - height -= SCROLL_BAR_HEIGHT; - totalTableHeight -= SCROLL_BAR_HEIGHT; - } + // exclude the height of the horizontal scroll bar from the height of the table + // and the height of the table container if the content overflows + const totalTableHeight = + container.current && + totalTableWidth.current > container.current.clientWidth + ? height - SCROLL_BAR_HEIGHT + : height; const rowGetter = ({ index }: { index: number }) => - this.getDatum(sortedAndFilteredList, index); + getDatum(sortedAndFilteredList, index); return ( <StyledFilterableTable className="filterable-table-container" - ref={this.container} + data-test="table-container" + ref={container} > - {this.state.fitted && ( + {fitted && ( <Table - ref="Table" headerHeight={headerHeight} height={totalTableHeight} overscanRowCount={overscanRowCount} - rowClassName={this.rowClassName} + rowClassName={rowClassName} rowHeight={rowHeight} rowGetter={rowGetter} rowCount={sortedAndFilteredList.length} - sort={this.sort} - sortBy={sortBy} - sortDirection={sortDirection} - width={this.totalTableWidth} + sort={sort} + sortBy={sortByState} + sortDirection={sortDirectionState} + width={totalTableWidth.current} > {orderedColumnKeys.map(columnKey => ( <Column cellRenderer={({ cellData }) => - this.renderTableCell({ cellData, columnKey }) + renderTableCell({ cellData, columnKey }) } dataKey={columnKey} disableSort={false} - headerRenderer={this.renderTableHeader} - width={this.widthsForColumnsByKey[columnKey]} + headerRenderer={renderTableHeader} + width={widthsForColumnsByKey[columnKey]} label={columnKey} key={columnKey} /> @@ -766,14 +705,12 @@ class FilterableTable extends PureComponent< )} </StyledFilterableTable> ); - } + }; - render() { - if (this.props.orderedColumnKeys.length > MAX_COLUMNS_FOR_TABLE) { - return this.renderGrid(); - } - return this.renderTable(); + if (orderedColumnKeys.length > MAX_COLUMNS_FOR_TABLE) { + return renderGrid(); } -} + return renderTable(); +}; -export default withTheme(FilterableTable); +export default FilterableTable; diff --git a/superset-frontend/src/components/Form/LabeledErrorBoundInput.test.jsx b/superset-frontend/src/components/Form/LabeledErrorBoundInput.test.jsx index a49b2713d07ad..5324f1bef0972 100644 --- a/superset-frontend/src/components/Form/LabeledErrorBoundInput.test.jsx +++ b/superset-frontend/src/components/Form/LabeledErrorBoundInput.test.jsx @@ -75,4 +75,18 @@ describe('LabeledErrorBoundInput', () => { expect(textboxInput).toBeVisible(); expect(await screen.findByText('This is a tooltip')).toBeInTheDocument(); }); + + it('becomes a password input if visibilityToggle prop is passed in', async () => { + defaultProps.visibilityToggle = true; + render(<LabeledErrorBoundInput {...defaultProps} />); + + expect(await screen.findByTestId('icon-eye')).toBeVisible(); + }); + + it('becomes a password input if props.name === password (backwards compatibility)', async () => { + defaultProps.name = 'password'; + render(<LabeledErrorBoundInput {...defaultProps} />); + + expect(await screen.findByTestId('icon-eye')).toBeVisible(); + }); }); diff --git a/superset-frontend/src/components/Form/LabeledErrorBoundInput.tsx b/superset-frontend/src/components/Form/LabeledErrorBoundInput.tsx index ebbb1c023622e..51cf104b271ca 100644 --- a/superset-frontend/src/components/Form/LabeledErrorBoundInput.tsx +++ b/superset-frontend/src/components/Form/LabeledErrorBoundInput.tsx @@ -18,9 +18,9 @@ */ import React from 'react'; import { Input, Tooltip } from 'antd'; -import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons'; -import { styled, css, SupersetTheme } from '@superset-ui/core'; +import { styled, css, SupersetTheme, t } from '@superset-ui/core'; import InfoTooltip from 'src/components/InfoTooltip'; +import Icons from 'src/components/Icons'; import errorIcon from 'src/assets/images/icons/error.svg'; import FormItem from './FormItem'; import FormLabel from './FormLabel'; @@ -37,6 +37,7 @@ export interface LabeledErrorBoundInputProps { tooltipText?: string | null; id?: string; classname?: string; + visibilityToggle?: boolean; [x: string]: any; } @@ -91,6 +92,12 @@ const StyledFormLabel = styled(FormLabel)` margin-bottom: 0; `; +const iconReset = css` + &.anticon > * { + line-height: 0; + } +`; + const LabeledErrorBoundInput = ({ label, validationMethods, @@ -101,6 +108,7 @@ const LabeledErrorBoundInput = ({ tooltipText, id, className, + visibilityToggle, ...props }: LabeledErrorBoundInputProps) => ( <StyledFormGroup className={className}> @@ -119,18 +127,22 @@ const LabeledErrorBoundInput = ({ help={errorMessage || helpText} hasFeedback={!!errorMessage} > - {props.name === 'password' ? ( + {visibilityToggle || props.name === 'password' ? ( <StyledInputPassword {...props} {...validationMethods} iconRender={visible => visible ? ( - <Tooltip title="Hide password."> - <EyeInvisibleOutlined /> + <Tooltip title={t('Hide password.')}> + <Icons.EyeInvisibleOutlined iconSize="m" css={iconReset} /> </Tooltip> ) : ( - <Tooltip title="Show password."> - <EyeOutlined /> + <Tooltip title={t('Show password.')}> + <Icons.EyeOutlined + iconSize="m" + css={iconReset} + data-test="icon-eye" + /> </Tooltip> ) } diff --git a/superset-frontend/src/components/GenericLink/GenericLink.test.tsx b/superset-frontend/src/components/GenericLink/GenericLink.test.tsx new file mode 100644 index 0000000000000..c8f2ba5f5f41e --- /dev/null +++ b/superset-frontend/src/components/GenericLink/GenericLink.test.tsx @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import { GenericLink } from './GenericLink'; + +test('renders', () => { + render(<GenericLink to="/explore">Link to Explore</GenericLink>, { + useRouter: true, + }); + expect(screen.getByText('Link to Explore')).toBeVisible(); +}); + +test('navigates to internal URL', () => { + render(<GenericLink to="/explore">Link to Explore</GenericLink>, { + useRouter: true, + }); + const internalLink = screen.getByTestId('internal-link'); + expect(internalLink).toHaveAttribute('href', '/explore'); +}); + +test('navigates to external URL', () => { + render( + <GenericLink to="https://superset.apache.org/"> + Link to external website + </GenericLink>, + { useRouter: true }, + ); + const externalLink = screen.getByTestId('external-link'); + expect(externalLink).toHaveAttribute('href', 'https://superset.apache.org/'); +}); + +test('navigates to external URL without host', () => { + render( + <GenericLink to="superset.apache.org/"> + Link to external website + </GenericLink>, + { useRouter: true }, + ); + const externalLink = screen.getByTestId('external-link'); + expect(externalLink).toHaveAttribute('href', '//superset.apache.org/'); +}); diff --git a/superset-frontend/src/components/GenericLink/GenericLink.tsx b/superset-frontend/src/components/GenericLink/GenericLink.tsx new file mode 100644 index 0000000000000..2bc111d1b60f4 --- /dev/null +++ b/superset-frontend/src/components/GenericLink/GenericLink.tsx @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { Link, LinkProps } from 'react-router-dom'; +import { isUrlExternal, parseUrl } from 'src/utils/urlUtils'; + +export const GenericLink = <S,>({ + to, + component, + replace, + innerRef, + children, + ...rest +}: React.PropsWithoutRef<LinkProps<S>> & + React.RefAttributes<HTMLAnchorElement>) => { + if (typeof to === 'string' && isUrlExternal(to)) { + return ( + <a data-test="external-link" href={parseUrl(to)} {...rest}> + {children} + </a> + ); + } + return ( + <Link + data-test="internal-link" + to={to} + component={component} + replace={replace} + innerRef={innerRef} + {...rest} + > + {children} + </Link> + ); +}; diff --git a/superset-frontend/src/components/Icons/index.tsx b/superset-frontend/src/components/Icons/index.tsx index 371278d6d8ef0..f9462cc3472ff 100644 --- a/superset-frontend/src/components/Icons/index.tsx +++ b/superset-frontend/src/components/Icons/index.tsx @@ -167,7 +167,7 @@ const IconFileNames = [ 'redo', ]; -const iconOverrides: Record<string, React.FC> = {}; +const iconOverrides: Record<string, React.FC<IconType>> = {}; IconFileNames.forEach(fileName => { const keyName = _.startCase(fileName).replace(/ /g, ''); iconOverrides[keyName] = (props: IconType) => ( diff --git a/superset-frontend/src/components/ImportModal/ErrorAlert.tsx b/superset-frontend/src/components/ImportModal/ErrorAlert.tsx index 52bd54a796188..904dced7bad54 100644 --- a/superset-frontend/src/components/ImportModal/ErrorAlert.tsx +++ b/superset-frontend/src/components/ImportModal/ErrorAlert.tsx @@ -49,7 +49,7 @@ const ErrorAlert: FunctionComponent<IProps> = ({ <> <br /> {t( - 'Database driver for importing maybe not installed. Visit the Superset documentation page for installation instructions:', + 'Database driver for importing maybe not installed. Visit the Superset documentation page for installation instructions: ', )} <a href={DOCUMENTATION_LINK} diff --git a/superset-frontend/src/components/ImportModal/index.tsx b/superset-frontend/src/components/ImportModal/index.tsx index 6a980f7d2013b..4e8ec11396578 100644 --- a/superset-frontend/src/components/ImportModal/index.tsx +++ b/superset-frontend/src/components/ImportModal/index.tsx @@ -216,7 +216,7 @@ const ImportModelsModal: FunctionComponent<ImportModelsModalProps> = ({ return ( <> - <h5>Database passwords</h5> + <h5>{t('Database passwords')}</h5> <HelperMessage>{passwordsNeededMessage}</HelperMessage> {passwordFields.map(fileName => ( <StyledInputContainer key={`password-for-${fileName}`}> @@ -297,7 +297,7 @@ const ImportModelsModal: FunctionComponent<ImportModelsModalProps> = ({ customRequest={() => {}} disabled={importingModel} > - <Button loading={importingModel}>Select file</Button> + <Button loading={importingModel}>{t('Select file')}</Button> </Upload> </StyledInputContainer> {errorMessage && ( diff --git a/superset-frontend/src/components/IndeterminateCheckbox/IndeterminateCheckbox.test.tsx b/superset-frontend/src/components/IndeterminateCheckbox/IndeterminateCheckbox.test.tsx index 7bced98f8eb81..08fdbe2fa4dd2 100644 --- a/superset-frontend/src/components/IndeterminateCheckbox/IndeterminateCheckbox.test.tsx +++ b/superset-frontend/src/components/IndeterminateCheckbox/IndeterminateCheckbox.test.tsx @@ -18,11 +18,11 @@ */ import React from 'react'; -import { render, screen } from 'spec/helpers/testing-library'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; -import IndeterminateCheckbox from '.'; +import IndeterminateCheckbox, { IndeterminateCheckboxProps } from '.'; -const mockedProps = { +const mockedProps: IndeterminateCheckboxProps = { checked: false, id: 'checkbox-id', indeterminate: false, @@ -30,27 +30,30 @@ const mockedProps = { onChange: jest.fn(), }; -test('should render', () => { - const { container } = render(<IndeterminateCheckbox {...mockedProps} />); +const asyncRender = (props = mockedProps) => + waitFor(() => render(<IndeterminateCheckbox {...props} />)); + +test('should render', async () => { + const { container } = await asyncRender(); expect(container).toBeInTheDocument(); }); -test('should render the label', () => { - render(<IndeterminateCheckbox {...mockedProps} />); +test('should render the label', async () => { + await asyncRender(); expect(screen.getByTitle('Checkbox title')).toBeInTheDocument(); }); -test('should render the checkbox', () => { - render(<IndeterminateCheckbox {...mockedProps} />); +test('should render the checkbox', async () => { + await asyncRender(); expect(screen.getByRole('checkbox')).toBeInTheDocument(); }); -test('should render the checkbox-half icon', () => { +test('should render the checkbox-half icon', async () => { const indeterminateProps = { ...mockedProps, indeterminate: true, }; - render(<IndeterminateCheckbox {...indeterminateProps} />); + await asyncRender(indeterminateProps); expect(screen.getByRole('img')).toBeInTheDocument(); expect(screen.getByRole('img')).toHaveAttribute( 'aria-label', @@ -58,24 +61,24 @@ test('should render the checkbox-half icon', () => { ); }); -test('should render the checkbox-off icon', () => { - render(<IndeterminateCheckbox {...mockedProps} />); +test('should render the checkbox-off icon', async () => { + await asyncRender(); expect(screen.getByRole('img')).toBeInTheDocument(); expect(screen.getByRole('img')).toHaveAttribute('aria-label', 'checkbox-off'); }); -test('should render the checkbox-on icon', () => { +test('should render the checkbox-on icon', async () => { const checkboxOnProps = { ...mockedProps, checked: true, }; - render(<IndeterminateCheckbox {...checkboxOnProps} />); + await asyncRender(checkboxOnProps); expect(screen.getByRole('img')).toBeInTheDocument(); expect(screen.getByRole('img')).toHaveAttribute('aria-label', 'checkbox-on'); }); -test('should call the onChange', () => { - render(<IndeterminateCheckbox {...mockedProps} />); +test('should call the onChange', async () => { + await asyncRender(); const label = screen.getByTitle('Checkbox title'); userEvent.click(label); expect(mockedProps.onChange).toHaveBeenCalledTimes(1); diff --git a/superset-frontend/src/components/LastUpdated/LastUpdated.test.tsx b/superset-frontend/src/components/LastUpdated/LastUpdated.test.tsx index 8306959180571..1df3f60ee4766 100644 --- a/superset-frontend/src/components/LastUpdated/LastUpdated.test.tsx +++ b/superset-frontend/src/components/LastUpdated/LastUpdated.test.tsx @@ -20,6 +20,7 @@ import React from 'react'; import { ReactWrapper } from 'enzyme'; import { styledMount as mount } from 'spec/helpers/theming'; +import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; import LastUpdated from '.'; describe('LastUpdated', () => { @@ -31,9 +32,10 @@ describe('LastUpdated', () => { expect(/^Last Updated .+$/.test(wrapper.text())).toBe(true); }); - it('renders a refresh action', () => { + it('renders a refresh action', async () => { const mockAction = jest.fn(); wrapper = mount(<LastUpdated updatedAt={updatedAt} update={mockAction} />); + await waitForComponentToPaint(wrapper); const props = wrapper.find('[aria-label="refresh"]').first().props(); if (props.onClick) { props.onClick({} as React.MouseEvent); diff --git a/superset-frontend/src/components/ListView/CrossLinks.test.tsx b/superset-frontend/src/components/ListView/CrossLinks.test.tsx new file mode 100644 index 0000000000000..ad7eb4e0dd281 --- /dev/null +++ b/superset-frontend/src/components/ListView/CrossLinks.test.tsx @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import CrossLinks, { CrossLinksProps } from './CrossLinks'; + +const mockedProps = { + crossLinks: [ + { + id: 1, + title: 'Test dashboard', + }, + { + id: 2, + title: 'Test dashboard 2', + }, + { + id: 3, + title: 'Test dashboard 3', + }, + { + id: 4, + title: 'Test dashboard 4', + }, + ], +}; + +function setup(overrideProps: CrossLinksProps | {} = {}) { + return render(<CrossLinks {...mockedProps} {...overrideProps} />, { + useRouter: true, + }); +} + +test('should render', () => { + const { container } = setup(); + expect(container).toBeInTheDocument(); +}); + +test('should not render links', () => { + setup({ + crossLinks: [], + }); + expect(screen.queryByRole('link')).not.toBeInTheDocument(); +}); + +test('should render the link with just one item', () => { + setup({ + crossLinks: [ + { + id: 1, + title: 'Test dashboard', + }, + ], + }); + expect(screen.getByText('Test dashboard')).toBeInTheDocument(); + expect(screen.getByRole('link')).toHaveAttribute( + 'href', + `/superset/dashboard/1`, + ); +}); + +test('should render a custom prefix link', () => { + setup({ + crossLinks: [ + { + id: 1, + title: 'Test dashboard', + }, + ], + linkPrefix: '/custom/dashboard/', + }); + expect(screen.getByRole('link')).toHaveAttribute( + 'href', + `/custom/dashboard/1`, + ); +}); + +test('should render multiple links', () => { + setup(); + expect(screen.getAllByRole('link')).toHaveLength(4); +}); diff --git a/superset-frontend/src/components/ListView/CrossLinks.tsx b/superset-frontend/src/components/ListView/CrossLinks.tsx new file mode 100644 index 0000000000000..653e97b06eab9 --- /dev/null +++ b/superset-frontend/src/components/ListView/CrossLinks.tsx @@ -0,0 +1,122 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useMemo, useRef } from 'react'; +import { styled } from '@superset-ui/core'; +import { Link } from 'react-router-dom'; +import { useTruncation } from 'src/hooks/useTruncation'; +import CrossLinksTooltip from './CrossLinksTooltip'; + +export type CrossLinkProps = { + title: string; + id: number; +}; + +export type CrossLinksProps = { + crossLinks: Array<CrossLinkProps>; + maxLinks?: number; + linkPrefix?: string; +}; + +const StyledCrossLinks = styled.div` + ${({ theme }) => ` + & > span { + width: 100%; + display: flex; + + .ant-tooltip-open { + display: inline; + } + + .truncated { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: inline-block; + width: 100%; + vertical-align: bottom; + } + + .count { + cursor: pointer; + color: ${theme.colors.grayscale.base}; + font-weight: ${theme.typography.weights.bold}; + } + } + `} +`; + +export default function CrossLinks({ + crossLinks, + maxLinks = 20, + linkPrefix = '/superset/dashboard/', +}: CrossLinksProps) { + const crossLinksRef = useRef<HTMLDivElement>(null); + const plusRef = useRef<HTMLDivElement>(null); + const [elementsTruncated, hasHiddenElements] = useTruncation( + crossLinksRef, + plusRef, + ); + const hasMoreItems = useMemo( + () => + crossLinks.length > maxLinks ? crossLinks.length - maxLinks : undefined, + [crossLinks, maxLinks], + ); + const links = useMemo( + () => ( + <span className="truncated" ref={crossLinksRef} data-test="crosslinks"> + {crossLinks.map((link, index) => ( + <Link + key={link.id} + to={linkPrefix + link.id} + target="_blank" + rel="noreferer noopener" + > + {index === 0 ? link.title : `, ${link.title}`} + </Link> + ))} + </span> + ), + [crossLinks], + ); + const tooltipLinks = useMemo( + () => + crossLinks.slice(0, maxLinks).map(l => ({ + title: l.title, + to: linkPrefix + l.id, + })), + [crossLinks, maxLinks], + ); + + return ( + <StyledCrossLinks> + <CrossLinksTooltip + moreItems={hasMoreItems} + crossLinks={tooltipLinks} + show={!!elementsTruncated} + > + {links} + {hasHiddenElements && ( + <span ref={plusRef} className="count" data-test="count-crosslinks"> + +{elementsTruncated} + </span> + )} + </CrossLinksTooltip> + </StyledCrossLinks> + ); +} diff --git a/superset-frontend/src/components/ListView/CrossLinksTooltip.test.tsx b/superset-frontend/src/components/ListView/CrossLinksTooltip.test.tsx new file mode 100644 index 0000000000000..96723e7bf698d --- /dev/null +++ b/superset-frontend/src/components/ListView/CrossLinksTooltip.test.tsx @@ -0,0 +1,89 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import CrossLinksTooltip, { CrossLinksTooltipProps } from './CrossLinksTooltip'; + +const mockedProps = { + crossLinks: [ + { + to: 'somewhere/1', + title: 'Test dashboard', + }, + { + to: 'somewhere/2', + title: 'Test dashboard 2', + }, + { + to: 'somewhere/3', + title: 'Test dashboard 3', + }, + { + to: 'somewhere/4', + title: 'Test dashboard 4', + }, + ], + moreItems: 0, + show: true, +}; + +function setup(overrideProps: CrossLinksTooltipProps | {} = {}) { + return render( + <CrossLinksTooltip {...mockedProps} {...overrideProps}> + Hover me + </CrossLinksTooltip>, + { + useRouter: true, + }, + ); +} + +test('should render', () => { + const { container } = setup(); + expect(container).toBeInTheDocument(); +}); + +test('should render multiple links', async () => { + setup(); + userEvent.hover(screen.getByText('Hover me')); + + await waitFor(() => { + expect(screen.getByText('Test dashboard')).toBeInTheDocument(); + expect(screen.getByText('Test dashboard 2')).toBeInTheDocument(); + expect(screen.getByText('Test dashboard 3')).toBeInTheDocument(); + expect(screen.getByText('Test dashboard 4')).toBeInTheDocument(); + expect(screen.getAllByRole('link')).toHaveLength(4); + }); +}); + +test('should not render the "+ {x} more"', () => { + setup(); + userEvent.hover(screen.getByText('Hover me')); + expect(screen.queryByTestId('plus-more')).not.toBeInTheDocument(); +}); + +test('should render the "+ {x} more"', async () => { + setup({ + moreItems: 3, + }); + userEvent.hover(screen.getByText('Hover me')); + expect(await screen.findByTestId('plus-more')).toBeInTheDocument(); + expect(await screen.findByText('+ 3 more')).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/components/ListView/CrossLinksTooltip.tsx b/superset-frontend/src/components/ListView/CrossLinksTooltip.tsx new file mode 100644 index 0000000000000..cc552cd8b4cf9 --- /dev/null +++ b/superset-frontend/src/components/ListView/CrossLinksTooltip.tsx @@ -0,0 +1,73 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { styled, t } from '@superset-ui/core'; +import { Tooltip } from 'src/components/Tooltip'; +import { Link } from 'react-router-dom'; + +export type CrossLinksTooltipProps = { + children: React.ReactNode; + crossLinks: { to: string; title: string }[]; + moreItems?: number; + show: boolean; +}; + +const StyledLinkedTooltip = styled.div` + .link { + color: ${({ theme }) => theme.colors.grayscale.light5}; + display: block; + text-decoration: underline; + } +`; + +export default function CrossLinksTooltip({ + children, + crossLinks = [], + moreItems = undefined, + show = false, +}: CrossLinksTooltipProps) { + return ( + <Tooltip + placement="top" + data-test="crosslinks-tooltip" + title={ + show && ( + <StyledLinkedTooltip> + {crossLinks.map(link => ( + <Link + className="link" + key={link.to} + to={link.to} + target="_blank" + rel="noreferer noopener" + > + {link.title} + </Link> + ))} + {moreItems && ( + <span data-test="plus-more">{t('+ %s more', moreItems)}</span> + )} + </StyledLinkedTooltip> + ) + } + > + {children} + </Tooltip> + ); +} diff --git a/superset-frontend/src/components/ListView/Filters/DateRange.tsx b/superset-frontend/src/components/ListView/Filters/DateRange.tsx index 4dfaf11f79fdf..121131248f2d9 100644 --- a/superset-frontend/src/components/ListView/Filters/DateRange.tsx +++ b/superset-frontend/src/components/ListView/Filters/DateRange.tsx @@ -23,7 +23,7 @@ import React, { useImperativeHandle, } from 'react'; import moment, { Moment } from 'moment'; -import { styled } from '@superset-ui/core'; +import { styled, t } from '@superset-ui/core'; import { RangePicker } from 'src/components/DatePicker'; import { FormLabel } from 'src/components/Form'; import { BaseFilter, FilterHandler } from './Base'; @@ -64,6 +64,7 @@ function DateRangeFilter( <RangeFilterContainer> <FormLabel>{Header}</FormLabel> <RangePicker + placeholder={[t('Start date'), t('End date')]} showTime value={momentValue} onChange={momentRange => { diff --git a/superset-frontend/src/components/ListView/Filters/Select.tsx b/superset-frontend/src/components/ListView/Filters/Select.tsx index 525061fd27411..b6c1e27642384 100644 --- a/superset-frontend/src/components/ListView/Filters/Select.tsx +++ b/superset-frontend/src/components/ListView/Filters/Select.tsx @@ -26,12 +26,13 @@ import { t } from '@superset-ui/core'; import { Select } from 'src/components'; import { Filter, SelectOption } from 'src/components/ListView/types'; import { FormLabel } from 'src/components/Form'; +import AsyncSelect from 'src/components/Select/AsyncSelect'; import { FilterContainer, BaseFilter, FilterHandler } from './Base'; interface SelectFilterProps extends BaseFilter { fetchSelects?: Filter['fetchSelects']; name?: string; - onSelect: (selected: SelectOption | undefined) => void; + onSelect: (selected: SelectOption | undefined, isClear?: boolean) => void; paginate?: boolean; selects: Filter['selects']; } @@ -57,7 +58,7 @@ function SelectFilter( }; const onClear = () => { - onSelect(undefined); + onSelect(undefined, true); setSelectedOption(undefined); }; @@ -86,19 +87,34 @@ function SelectFilter( return ( <FilterContainer> - <Select - allowClear - ariaLabel={typeof Header === 'string' ? Header : name || t('Filter')} - labelInValue - data-test="filters-select" - header={<FormLabel>{Header}</FormLabel>} - onChange={onChange} - onClear={onClear} - options={fetchSelects ? fetchAndFormatSelects : selects} - placeholder={t('Select or type a value')} - showSearch - value={selectedOption} - /> + {fetchSelects ? ( + <AsyncSelect + allowClear + ariaLabel={typeof Header === 'string' ? Header : name || t('Filter')} + data-test="filters-select" + header={<FormLabel>{Header}</FormLabel>} + onChange={onChange} + onClear={onClear} + options={fetchAndFormatSelects} + placeholder={t('Select or type a value')} + showSearch + value={selectedOption} + /> + ) : ( + <Select + allowClear + ariaLabel={typeof Header === 'string' ? Header : name || t('Filter')} + data-test="filters-select" + header={<FormLabel>{Header}</FormLabel>} + labelInValue + onChange={onChange} + onClear={onClear} + options={selects} + placeholder={t('Select or type a value')} + showSearch + value={selectedOption} + /> + )} </FilterContainer> ); } diff --git a/superset-frontend/src/components/ListView/Filters/index.tsx b/superset-frontend/src/components/ListView/Filters/index.tsx index 348ed3850dd26..dbbc761cb8a2a 100644 --- a/superset-frontend/src/components/ListView/Filters/index.tsx +++ b/superset-frontend/src/components/ListView/Filters/index.tsx @@ -62,9 +62,20 @@ function UIFilters( return ( <> {filters.map( - ({ Header, fetchSelects, id, input, paginate, selects }, index) => { - const initialValue = - internalFilters[index] && internalFilters[index].value; + ( + { + Header, + fetchSelects, + key, + id, + input, + paginate, + selects, + onFilterUpdate, + }, + index, + ) => { + const initialValue = internalFilters?.[index]?.value; if (input === 'select') { return ( <SelectFilter @@ -72,11 +83,21 @@ function UIFilters( Header={Header} fetchSelects={fetchSelects} initialValue={initialValue} - key={id} + key={key} name={id} - onSelect={(option: SelectOption | undefined) => - updateFilterValue(index, option) - } + onSelect={( + option: SelectOption | undefined, + isClear?: boolean, + ) => { + if (onFilterUpdate) { + // Filter change triggers both onChange AND onClear, only want to track onChange + if (!isClear) { + onFilterUpdate(option); + } + } + + updateFilterValue(index, option); + }} paginate={paginate} selects={selects} /> @@ -88,9 +109,15 @@ function UIFilters( ref={filterRefs[index]} Header={Header} initialValue={initialValue} - key={id} + key={key} name={id} - onSubmit={(value: string) => updateFilterValue(index, value)} + onSubmit={(value: string) => { + if (onFilterUpdate) { + onFilterUpdate(value); + } + + updateFilterValue(index, value); + }} /> ); } @@ -100,7 +127,7 @@ function UIFilters( ref={filterRefs[index]} Header={Header} initialValue={initialValue} - key={id} + key={key} name={id} onSubmit={value => updateFilterValue(index, value)} /> diff --git a/superset-frontend/src/components/ListView/types.ts b/superset-frontend/src/components/ListView/types.ts index f8bff90f0ee95..641cb05801515 100644 --- a/superset-frontend/src/components/ListView/types.ts +++ b/superset-frontend/src/components/ListView/types.ts @@ -39,6 +39,7 @@ export interface CardSortSelectOption { export interface Filter { Header: ReactNode; + key: string; id: string; urlDisplay?: string; operator?: FilterOperator; @@ -52,6 +53,7 @@ export interface Filter { unfilteredLabel?: string; selects?: SelectOption[]; onFilterOpen?: () => void; + onFilterUpdate?: (value?: any) => void; fetchSelects?: ( filterValue: string, page: number, @@ -114,4 +116,6 @@ export enum FilterOperator { chartIsCertified = 'chart_is_certified', dashboardIsCertified = 'dashboard_is_certified', datasetIsCertified = 'dataset_is_certified', + dashboardHasCreatedBy = 'dashboard_has_created_by', + chartHasCreatedBy = 'chart_has_created_by', } diff --git a/superset-frontend/src/components/ListView/utils.ts b/superset-frontend/src/components/ListView/utils.ts index 78873f51f14a0..8a8c57cb6234e 100644 --- a/superset-frontend/src/components/ListView/utils.ts +++ b/superset-frontend/src/components/ListView/utils.ts @@ -35,7 +35,7 @@ import { import rison from 'rison'; import { isEqual } from 'lodash'; -import { PartialStylesConfig } from 'src/components/Select'; +import { PartialStylesConfig } from 'src/components/DeprecatedSelect'; import { FetchDataConfig, Filter, @@ -344,7 +344,7 @@ export function useListViewState({ const applyFilterValue = (index: number, value: any) => { setInternalFilters(currentInternalFilters => { - // skip redunundant updates + // skip redundant updates if (currentInternalFilters[index].value === value) { return currentInternalFilters; } diff --git a/superset-frontend/src/components/ListViewCard/ListViewCard.stories.tsx b/superset-frontend/src/components/ListViewCard/ListViewCard.stories.tsx index 9f91193ee9327..ca53d81084642 100644 --- a/superset-frontend/src/components/ListViewCard/ListViewCard.stories.tsx +++ b/superset-frontend/src/components/ListViewCard/ListViewCard.stories.tsx @@ -18,9 +18,7 @@ */ import React from 'react'; import { action } from '@storybook/addon-actions'; -import { withKnobs, boolean, select, text } from '@storybook/addon-knobs'; -import DashboardImg from 'src/assets/images/dashboard-card-fallback.svg'; -import ChartImg from 'src/assets/images/chart-card-fallback.svg'; +import { boolean, text } from '@storybook/addon-knobs'; import { AntdDropdown } from 'src/components'; import { Menu } from 'src/components/Menu'; import Icons from 'src/components/Icons'; @@ -30,16 +28,6 @@ import ListViewCard from '.'; export default { title: 'ListViewCard', component: ListViewCard, - decorators: [withKnobs], -}; - -const imgFallbackKnob = { - label: 'Fallback/Loading Image', - options: { - Dashboard: DashboardImg, - Chart: ChartImg, - }, - defaultValue: DashboardImg, }; export const SupersetListViewCard = () => ( @@ -47,11 +35,13 @@ export const SupersetListViewCard = () => ( title="Superset Card Title" loading={boolean('loading', false)} url="/superset/dashboard/births/" - imgURL={text('imgURL', 'https://picsum.photos/800/600')} - imgFallbackURL={select( - imgFallbackKnob.label, - imgFallbackKnob.options, - imgFallbackKnob.defaultValue, + imgURL={text( + 'imgURL', + 'https://images.unsplash.com/photo-1658163724548-29ef00812a54?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2670&q=80', + )} + imgFallbackURL={text( + 'imgURL', + 'https://images.unsplash.com/photo-1658208193219-e859d9771912?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2670&q=80', )} description="Lorem ipsum dolor sit amet, consectetur adipiscing elit..." coverLeft="Left Section" diff --git a/superset-frontend/src/components/ListViewCard/index.tsx b/superset-frontend/src/components/ListViewCard/index.tsx index 3078db8ea4ba4..f182fd70b8f58 100644 --- a/superset-frontend/src/components/ListViewCard/index.tsx +++ b/superset-frontend/src/components/ListViewCard/index.tsx @@ -71,7 +71,7 @@ const Cover = styled.div` const TitleContainer = styled.div` display: flex; justify-content: flex-start; - flex-direction: row; + flex-direction: column; .card-actions { margin-left: auto; @@ -82,6 +82,12 @@ const TitleContainer = styled.div` align-items: center; } } + + .titleRow { + display: flex; + justify-content: flex-start; + flex-direction: row; + } `; const TitleLink = styled.span` @@ -141,6 +147,7 @@ const AnchorLink: React.FC<LinkProps> = ({ to, children }) => ( interface CardProps { title?: React.ReactNode; + subtitle?: React.ReactNode; url?: string; linkComponent?: React.ComponentType<LinkProps>; imgURL?: string; @@ -161,6 +168,7 @@ interface CardProps { function ListViewCard({ title, + subtitle, url, linkComponent, titleRight, @@ -245,9 +253,10 @@ function ListViewCard({ <AntdCard.Meta title={ <TitleContainer> - <Tooltip title={title}> - <TitleLink> - <Link to={url!}> + {subtitle || null} + <div className="titleRow"> + <Tooltip title={title}> + <TitleLink> {certifiedBy && ( <> <CertifiedBadge @@ -257,12 +266,12 @@ function ListViewCard({ </> )} {title} - </Link> - </TitleLink> - </Tooltip> - {titleRight && <TitleRight>{titleRight}</TitleRight>} - <div className="card-actions" data-test="card-actions"> - {actions} + </TitleLink> + </Tooltip> + {titleRight && <TitleRight>{titleRight}</TitleRight>} + <div className="card-actions" data-test="card-actions"> + {actions} + </div> </div> </TitleContainer> } diff --git a/superset-frontend/src/components/Loading/Loading.stories.tsx b/superset-frontend/src/components/Loading/Loading.stories.tsx index 9f079848b8a2e..0c80c6f0ff618 100644 --- a/superset-frontend/src/components/Loading/Loading.stories.tsx +++ b/superset-frontend/src/components/Loading/Loading.stories.tsx @@ -40,7 +40,7 @@ export const LoadingGallery = () => ( }} > <h4>{position}</h4> - <Loading position={position} image="/src/assets/images/loading.gif" /> + <Loading position={position} /> </div> ))} </> @@ -71,7 +71,7 @@ InteractiveLoading.story = { }; InteractiveLoading.args = { - image: '/src/assets/images/loading.gif', + image: '', className: '', }; diff --git a/superset-frontend/src/components/Loading/Loading.test.tsx b/superset-frontend/src/components/Loading/Loading.test.tsx index d6ea8581c5105..7325c9304b587 100644 --- a/superset-frontend/src/components/Loading/Loading.test.tsx +++ b/superset-frontend/src/components/Loading/Loading.test.tsx @@ -26,11 +26,9 @@ test('Rerendering correctly with default props', () => { render(<Loading />); const loading = screen.getByRole('status'); const classNames = loading.getAttribute('class')?.split(' '); - const imagePath = loading.getAttribute('src'); const ariaLive = loading.getAttribute('aria-live'); const ariaLabel = loading.getAttribute('aria-label'); expect(loading).toBeInTheDocument(); - expect(imagePath).toBe('/static/assets/images/loading.gif'); expect(classNames).toContain('floating'); expect(classNames).toContain('loading'); expect(ariaLive).toContain('polite'); @@ -56,7 +54,7 @@ test('support for extra classes', () => { expect(classNames).toContain('extra-class'); }); -test('Diferent image path', () => { +test('Different image path', () => { render(<Loading image="/src/assets/images/loading.gif" />); const loading = screen.getByRole('status'); const imagePath = loading.getAttribute('src'); diff --git a/superset-frontend/src/components/Loading/index.tsx b/superset-frontend/src/components/Loading/index.tsx index 6ba6fb45c5443..b8d91ce6a2ead 100644 --- a/superset-frontend/src/components/Loading/index.tsx +++ b/superset-frontend/src/components/Loading/index.tsx @@ -20,6 +20,7 @@ import React from 'react'; import { styled } from '@superset-ui/core'; import cls from 'classnames'; +import Loader from 'src/assets/images/loading.gif'; export type PositionOption = | 'floating' @@ -35,6 +36,7 @@ export interface Props { const LoaderImg = styled.img` z-index: 99; width: 50px; + height: unset; position: relative; margin: 10px; &.inline { @@ -57,17 +59,18 @@ const LoaderImg = styled.img` `; export default function Loading({ position = 'floating', - image = '/static/assets/images/loading.gif', + image, className, }: Props) { return ( <LoaderImg className={cls('loading', position, className)} alt="Loading..." - src={image} + src={image || Loader} role="status" aria-live="polite" aria-label="Loading" + data-test="loading-indicator" /> ); } diff --git a/superset-frontend/src/components/Menu/index.tsx b/superset-frontend/src/components/Menu/index.tsx index 73858bc92e911..a7061b47e12c4 100644 --- a/superset-frontend/src/components/Menu/index.tsx +++ b/superset-frontend/src/components/Menu/index.tsx @@ -18,6 +18,9 @@ */ import { styled } from '@superset-ui/core'; import { Menu as AntdMenu } from 'antd'; +import { MenuProps as AntdMenuProps } from 'antd/lib/menu'; + +export type MenuProps = AntdMenuProps; const MenuItem = styled(AntdMenu.Item)` > a { diff --git a/superset-frontend/src/components/MessageToasts/Toast.tsx b/superset-frontend/src/components/MessageToasts/Toast.tsx index 0a1a93d92a499..c248a2427b374 100644 --- a/superset-frontend/src/components/MessageToasts/Toast.tsx +++ b/superset-frontend/src/components/MessageToasts/Toast.tsx @@ -18,7 +18,7 @@ */ import { styled, css, SupersetTheme } from '@superset-ui/core'; import cx from 'classnames'; -import Interweave from 'interweave'; +import { Interweave } from 'interweave'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import Icons from 'src/components/Icons'; import { ToastType, ToastMeta } from './types'; diff --git a/superset-frontend/src/components/MetadataBar/ContentConfig.tsx b/superset-frontend/src/components/MetadataBar/ContentConfig.tsx new file mode 100644 index 0000000000000..8e9958da1c8f0 --- /dev/null +++ b/superset-frontend/src/components/MetadataBar/ContentConfig.tsx @@ -0,0 +1,136 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { ensureIsArray, styled, t } from '@superset-ui/core'; +import Icons from 'src/components/Icons'; +import { ContentType, MetadataType } from '.'; + +const Header = styled.div` + font-weight: ${({ theme }) => theme.typography.weights.bold}; +`; + +const Info = ({ + text, + header, +}: { + text?: string | string[]; + header?: string; +}) => { + const values = ensureIsArray(text); + return ( + <> + {header && <Header>{header}</Header>} + {values.map(value => ( + <div key={value}>{value}</div> + ))} + </> + ); +}; + +const config = (contentType: ContentType) => { + const { type } = contentType; + + /** + * Tooltips are very similar. It's pretty much blocks + * of header/text pairs. That's why they are implemented here. + * If more complex tooltips emerge, then we should extract the different + * types of tooltips to their own components and reference them here. + */ + + switch (type) { + case MetadataType.DASHBOARDS: + return { + icon: Icons.FundProjectionScreenOutlined, + title: contentType.title, + tooltip: contentType.description ? ( + <div> + <Info header={contentType.title} text={contentType.description} /> + </div> + ) : undefined, + }; + + case MetadataType.DESCRIPTION: + return { + icon: Icons.BookOutlined, + title: contentType.value, + }; + + case MetadataType.LAST_MODIFIED: + return { + icon: Icons.EditOutlined, + title: contentType.value, + tooltip: ( + <div> + <Info header={t('Last modified')} text={contentType.value} /> + <Info header={t('Modified by')} text={contentType.modifiedBy} /> + </div> + ), + }; + + case MetadataType.OWNER: + return { + icon: Icons.UserOutlined, + title: contentType.createdBy, + tooltip: ( + <div> + <Info header={t('Created by')} text={contentType.createdBy} /> + <Info header={t('Owners')} text={contentType.owners} /> + <Info header={t('Created on')} text={contentType.createdOn} /> + </div> + ), + }; + + case MetadataType.ROWS: + return { + icon: Icons.InsertRowBelowOutlined, + title: contentType.title, + tooltip: contentType.title, + }; + + case MetadataType.SQL: + return { + icon: Icons.ConsoleSqlOutlined, + title: contentType.title, + tooltip: contentType.title, + }; + + case MetadataType.TABLE: + return { + icon: Icons.Table, + title: contentType.title, + tooltip: contentType.title, + }; + + case MetadataType.TAGS: + return { + icon: Icons.TagsOutlined, + title: contentType.values.join(', '), + tooltip: ( + <div> + <Info header={t('Tags')} text={contentType.values} /> + </div> + ), + }; + + default: + throw Error(`Invalid type provided: ${type}`); + } +}; + +export { config }; diff --git a/superset-frontend/src/components/MetadataBar/ContentType.ts b/superset-frontend/src/components/MetadataBar/ContentType.ts new file mode 100644 index 0000000000000..13c0707391085 --- /dev/null +++ b/superset-frontend/src/components/MetadataBar/ContentType.ts @@ -0,0 +1,91 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export enum MetadataType { + DASHBOARDS = 'dashboards', + DESCRIPTION = 'description', + LAST_MODIFIED = 'lastModified', + OWNER = 'owner', + ROWS = 'rows', + SQL = 'sql', + TABLE = 'table', + TAGS = 'tags', +} + +export type Dashboards = { + type: MetadataType.DASHBOARDS; + title: string; + description?: string; + onClick?: (type: string) => void; +}; + +export type Description = { + type: MetadataType.DESCRIPTION; + value: string; + onClick?: (type: string) => void; +}; + +export type LastModified = { + type: MetadataType.LAST_MODIFIED; + value: string; + modifiedBy: string; + onClick?: (type: string) => void; +}; + +export type Owner = { + type: MetadataType.OWNER; + createdBy: string; + owners: string[]; + createdOn: string; + onClick?: (type: string) => void; +}; + +export type Rows = { + type: MetadataType.ROWS; + title: string; + onClick?: (type: string) => void; +}; + +export type Sql = { + type: MetadataType.SQL; + title: string; + onClick?: (type: string) => void; +}; + +export type Table = { + type: MetadataType.TABLE; + title: string; + onClick?: (type: string) => void; +}; + +export type Tags = { + type: MetadataType.TAGS; + values: string[]; + onClick?: (type: string) => void; +}; + +export type ContentType = + | Dashboards + | Description + | LastModified + | Owner + | Rows + | Sql + | Table + | Tags; diff --git a/superset-frontend/src/components/MetadataBar/MetadataBar.stories.mdx b/superset-frontend/src/components/MetadataBar/MetadataBar.stories.mdx new file mode 100644 index 0000000000000..d85c2c622684b --- /dev/null +++ b/superset-frontend/src/components/MetadataBar/MetadataBar.stories.mdx @@ -0,0 +1,145 @@ +import { Meta, Source, Story } from '@storybook/addon-docs'; + +<Meta title="Design System/Components/MetadataBar/Overview" /> + +# Metadata bar + +The metadata bar component is used to display additional information about an entity. + +## Usage + +Some of the common applications in Superset are: + +- Display the chart's metadata in Explore to help the user understand what dashboards this chart is added to and get + to know the details of the chart +- Display the database's metadata in a drill to detail modal to help the user understand what data they are looking + at while accessing the feature in the dashboard + +## Basic example + +<Story id="design-system-components-metadatabar-examples--basic" /> + +## Variations + +The metadata bar is by default a static component (besides the links in text). +The variations in this component are related to content and entity type as all of the details are predefined +in the code and should be specific for each metadata object. + +Content types are predefined and consistent across the whole app. This means that +they will be displayed and behave in a consistent manner, keeping the same ordering, +information formatting, and interactions. For example, the Owner content type will always +have the same icon and when hovered it will present who created the entity, its current owners, and when the entity was created. + +To extend the list of content types, a developer needs to request the inclusion of the new type in the design system. +This process is important to make sure the new type is reviewed by the design team, improving Superset consistency. + +To check each content type in detail and its interactions, check the [MetadataBar](/story/design-system-components-metadatabar-examples--basic) page. +Below you can find the configurations for each content type: + +<Source + language="jsx" + format={true} + code={` + export enum MetadataType { + DASHBOARDS = 'dashboards', + DESCRIPTION = 'description', + LAST_MODIFIED = 'lastModified', + OWNER = 'owner', + ROWS = 'rows', + SQL = 'sql', + TABLE = 'table', + TAGS = 'tags', + }`} +/> + +<Source + language="jsx" + format={true} + code={` + export type Dashboards = { + type: MetadataType.DASHBOARDS; + title: string; + description?: string; + onClick?: (type: string) => void; + };`} +/> + +<Source + language="jsx" + format={true} + code={` + export type Description = { + type: MetadataType.DESCRIPTION; + value: string; + onClick?: (type: string) => void; + };`} +/> + +<Source + language="jsx" + format={true} + code={` + export type LastModified = { + type: MetadataType.LAST_MODIFIED; + value: Date; + modifiedBy: string; + onClick?: (type: string) => void; + };`} +/> + +<Source + language="jsx" + format={true} + code={` + export type Owner = { + type: MetadataType.OWNER; + createdBy: string; + owners: string[]; + createdOn: Date; + onClick?: (type: string) => void; + };`} +/> + +<Source + language="jsx" + format={true} + code={` + export type Rows = { + type: MetadataType.ROWS; + title: string; + onClick?: (type: string) => void; + };`} +/> + +<Source + language="jsx" + format={true} + code={` + export type Sql = { + type: MetadataType.SQL; + title: string; + onClick?: (type: string) => void; + };`} +/> + +<Source + language="jsx" + format={true} + code={` + export type Table = { + type: MetadataType.TABLE; + title: string; + onClick?: (type: string) => void; + };`} +/> + +<Source + language="jsx" + format={true} + code={` + export type Tags = { + type: MetadataType.TAGS; + values: string[]; + onClick?: (type: string) => void; + };`} +/> diff --git a/superset-frontend/src/components/MetadataBar/MetadataBar.stories.tsx b/superset-frontend/src/components/MetadataBar/MetadataBar.stories.tsx new file mode 100644 index 0000000000000..1b5fb33d9612c --- /dev/null +++ b/superset-frontend/src/components/MetadataBar/MetadataBar.stories.tsx @@ -0,0 +1,109 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { css } from '@superset-ui/core'; +import { useResizeDetector } from 'react-resize-detector'; +import MetadataBar, { MetadataBarProps, MetadataType } from '.'; + +export default { + title: 'Design System/Components/MetadataBar/Examples', + component: MetadataBar, +}; + +const A_WEEK_AGO = 'a week ago'; + +export const Basic = ({ + items, + onClick, +}: MetadataBarProps & { + onClick: (type: string) => void; +}) => { + const { width, height, ref } = useResizeDetector(); + // eslint-disable-next-line no-param-reassign + items[0].onClick = onClick; + return ( + <div + ref={ref} + css={css` + margin-top: 70px; + margin-left: 80px; + overflow: auto; + min-width: ${168}px; + max-width: ${740}px; + resize: horizontal; + `} + > + <MetadataBar items={items} /> + <span + css={css` + position: absolute; + top: 150px; + left: 115px; + `} + >{`${width}x${height}`}</span> + </div> + ); +}; + +Basic.story = { + parameters: { + knobs: { + disable: true, + }, + }, +}; + +Basic.args = { + items: [ + { + type: MetadataType.SQL, + title: 'Click to view query', + }, + { + type: MetadataType.OWNER, + createdBy: 'Jane Smith', + owners: ['John Doe', 'Mary Wilson'], + createdOn: A_WEEK_AGO, + }, + { + type: MetadataType.LAST_MODIFIED, + value: A_WEEK_AGO, + modifiedBy: 'Jane Smith', + }, + { + type: MetadataType.TAGS, + values: ['management', 'research', 'poc'], + }, + { + type: MetadataType.DASHBOARDS, + title: 'Added to 452 dashboards', + description: + 'To preview the list of dashboards go to "More" settings on the right.', + }, + ], +}; + +Basic.argTypes = { + onClick: { + action: 'onClick', + table: { + disable: true, + }, + }, +}; diff --git a/superset-frontend/src/components/MetadataBar/MetadataBar.test.tsx b/superset-frontend/src/components/MetadataBar/MetadataBar.test.tsx new file mode 100644 index 0000000000000..549b917ec1386 --- /dev/null +++ b/superset-frontend/src/components/MetadataBar/MetadataBar.test.tsx @@ -0,0 +1,268 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen, within } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import * as resizeDetector from 'react-resize-detector'; +import { supersetTheme } from '@superset-ui/core'; +import { hexToRgb } from 'src/utils/colorUtils'; +import MetadataBar, { + MIN_NUMBER_ITEMS, + MAX_NUMBER_ITEMS, + ContentType, + MetadataType, +} from '.'; + +const DASHBOARD_TITLE = 'Added to 452 dashboards'; +const DASHBOARD_DESCRIPTION = + 'To preview the list of dashboards go to "More" settings on the right.'; +const DESCRIPTION_VALUE = 'This is the description'; +const ROWS_TITLE = '500 rows'; +const SQL_TITLE = 'Click to view query'; +const TABLE_TITLE = 'database.schema.table'; +const CREATED_BY = 'Jane Smith'; +const MODIFIED_BY = 'Jane Smith'; +const OWNERS = ['John Doe', 'Mary Wilson']; +const TAGS = ['management', 'research', 'poc']; +const A_WEEK_AGO = 'a week ago'; +const TWO_DAYS_AGO = '2 days ago'; + +const runWithBarCollapsed = async (func: Function) => { + const spy = jest.spyOn(resizeDetector, 'useResizeDetector'); + let width: number; + spy.mockImplementation(props => { + if (props?.onResize && !width) { + width = 80; + props.onResize(width); + } + return { ref: { current: undefined } }; + }); + await func(); + spy.mockRestore(); +}; + +const ITEMS: ContentType[] = [ + { + type: MetadataType.DASHBOARDS, + title: DASHBOARD_TITLE, + description: DASHBOARD_DESCRIPTION, + }, + { + type: MetadataType.DESCRIPTION, + value: DESCRIPTION_VALUE, + }, + { + type: MetadataType.LAST_MODIFIED, + value: TWO_DAYS_AGO, + modifiedBy: MODIFIED_BY, + }, + { + type: MetadataType.OWNER, + createdBy: CREATED_BY, + owners: OWNERS, + createdOn: A_WEEK_AGO, + }, + { + type: MetadataType.ROWS, + title: ROWS_TITLE, + }, + { + type: MetadataType.SQL, + title: SQL_TITLE, + }, + { + type: MetadataType.TABLE, + title: TABLE_TITLE, + }, + { + type: MetadataType.TAGS, + values: TAGS, + }, +]; + +test('renders an array of items', () => { + render(<MetadataBar items={ITEMS.slice(0, 2)} />); + expect(screen.getByText(DASHBOARD_TITLE)).toBeInTheDocument(); + expect(screen.getByText(DESCRIPTION_VALUE)).toBeInTheDocument(); +}); + +test('throws errors when out of min/max restrictions', () => { + const spy = jest.spyOn(console, 'error'); + spy.mockImplementation(() => {}); + expect(() => + render(<MetadataBar items={ITEMS.slice(0, MIN_NUMBER_ITEMS - 1)} />), + ).toThrow( + `The minimum number of items for the metadata bar is ${MIN_NUMBER_ITEMS}.`, + ); + expect(() => + render(<MetadataBar items={ITEMS.slice(0, MAX_NUMBER_ITEMS + 1)} />), + ).toThrow( + `The maximum number of items for the metadata bar is ${MAX_NUMBER_ITEMS}.`, + ); + spy.mockRestore(); +}); + +test('removes duplicated items when rendering', () => { + render(<MetadataBar items={[...ITEMS.slice(0, 2), ...ITEMS.slice(0, 2)]} />); + expect(screen.getAllByRole('img').length).toBe(2); +}); + +test('collapses the bar when min width is reached', async () => { + await runWithBarCollapsed(() => { + render(<MetadataBar items={ITEMS.slice(0, 2)} />); + expect(screen.queryByText(DASHBOARD_TITLE)).not.toBeInTheDocument(); + expect(screen.queryByText(DESCRIPTION_VALUE)).not.toBeInTheDocument(); + expect(screen.getAllByRole('img').length).toBe(2); + }); +}); + +test('always renders a tooltip when the bar is collapsed', async () => { + await runWithBarCollapsed(async () => { + render(<MetadataBar items={ITEMS.slice(0, 2)} />); + userEvent.hover(screen.getAllByRole('img')[0]); + expect(await screen.findByText(DASHBOARD_DESCRIPTION)).toBeInTheDocument(); + userEvent.hover(screen.getAllByRole('img')[1]); + expect(await screen.findByText(DESCRIPTION_VALUE)).toBeInTheDocument(); + }); +}); + +test('renders a tooltip when one is provided even if not collapsed', async () => { + render(<MetadataBar items={ITEMS.slice(0, 2)} />); + expect(screen.getByText(DASHBOARD_TITLE)).toBeInTheDocument(); + userEvent.hover(screen.getAllByRole('img')[0]); + expect(await screen.findByText(DASHBOARD_DESCRIPTION)).toBeInTheDocument(); +}); + +test('renders underlined text and emits event when clickable', () => { + const onClick = jest.fn(); + const items = [{ ...ITEMS[0], onClick }, ITEMS[1]]; + render(<MetadataBar items={items} />); + const element = screen.getByText(DASHBOARD_TITLE); + userEvent.click(element); + expect(onClick).toHaveBeenCalled(); + const style = window.getComputedStyle(element); + expect(style.textDecoration).toBe('underline'); +}); + +test('renders clicable items with blue icons when the bar is collapsed', async () => { + await runWithBarCollapsed(async () => { + const onClick = jest.fn(); + const items = [{ ...ITEMS[0], onClick }, ITEMS[1]]; + render(<MetadataBar items={items} />); + const images = screen.getAllByRole('img'); + const clickableColor = window.getComputedStyle(images[0]).color; + const nonClickableColor = window.getComputedStyle(images[1]).color; + expect(clickableColor).toBe(hexToRgb(supersetTheme.colors.primary.base)); + expect(nonClickableColor).toBe( + hexToRgb(supersetTheme.colors.grayscale.base), + ); + }); +}); + +test('renders the items sorted', () => { + const { container } = render(<MetadataBar items={ITEMS.slice(0, 6)} />); + const nodes = container.firstChild?.childNodes as NodeListOf<HTMLElement>; + expect(within(nodes[0]).getByText(DASHBOARD_TITLE)).toBeInTheDocument(); + expect(within(nodes[1]).getByText(SQL_TITLE)).toBeInTheDocument(); + expect(within(nodes[2]).getByText(ROWS_TITLE)).toBeInTheDocument(); + expect(within(nodes[3]).getByText(DESCRIPTION_VALUE)).toBeInTheDocument(); + expect(within(nodes[4]).getByText(CREATED_BY)).toBeInTheDocument(); +}); + +test('correctly renders the dashboards tooltip', async () => { + render(<MetadataBar items={ITEMS.slice(0, 2)} />); + userEvent.hover(screen.getByText(DASHBOARD_TITLE)); + const tooltip = await screen.findByRole('tooltip'); + expect(tooltip).toBeInTheDocument(); + expect(within(tooltip).getByText(DASHBOARD_TITLE)).toBeInTheDocument(); + expect(within(tooltip).getByText(DASHBOARD_DESCRIPTION)).toBeInTheDocument(); +}); + +test('correctly renders the description tooltip', async () => { + await runWithBarCollapsed(async () => { + render(<MetadataBar items={ITEMS.slice(0, 2)} />); + userEvent.hover(screen.getAllByRole('img')[1]); + const tooltip = await screen.findByRole('tooltip'); + expect(tooltip).toBeInTheDocument(); + expect(within(tooltip).getByText(DESCRIPTION_VALUE)).toBeInTheDocument(); + }); +}); + +test('correctly renders the last modified tooltip', async () => { + render(<MetadataBar items={ITEMS.slice(0, 3)} />); + userEvent.hover(screen.getByText(TWO_DAYS_AGO)); + const tooltip = await screen.findByRole('tooltip'); + expect(tooltip).toBeInTheDocument(); + expect(within(tooltip).getByText(TWO_DAYS_AGO)).toBeInTheDocument(); + expect(within(tooltip).getByText(MODIFIED_BY)).toBeInTheDocument(); +}); + +test('correctly renders the owner tooltip', async () => { + render(<MetadataBar items={ITEMS.slice(0, 4)} />); + userEvent.hover(screen.getByText(CREATED_BY)); + const tooltip = await screen.findByRole('tooltip'); + expect(tooltip).toBeInTheDocument(); + expect(within(tooltip).getByText(CREATED_BY)).toBeInTheDocument(); + expect(within(tooltip).getByText(A_WEEK_AGO)).toBeInTheDocument(); + OWNERS.forEach(owner => + expect(within(tooltip).getByText(owner)).toBeInTheDocument(), + ); +}); + +test('correctly renders the rows tooltip', async () => { + await runWithBarCollapsed(async () => { + render(<MetadataBar items={ITEMS.slice(4, 8)} />); + userEvent.hover(screen.getAllByRole('img')[2]); + const tooltip = await screen.findByRole('tooltip'); + expect(tooltip).toBeInTheDocument(); + expect(within(tooltip).getByText(ROWS_TITLE)).toBeInTheDocument(); + }); +}); + +test('correctly renders the sql tooltip', async () => { + await runWithBarCollapsed(async () => { + render(<MetadataBar items={ITEMS.slice(4, 8)} />); + userEvent.hover(screen.getAllByRole('img')[1]); + const tooltip = await screen.findByRole('tooltip'); + expect(tooltip).toBeInTheDocument(); + expect(within(tooltip).getByText(SQL_TITLE)).toBeInTheDocument(); + }); +}); + +test('correctly renders the table tooltip', async () => { + await runWithBarCollapsed(async () => { + render(<MetadataBar items={ITEMS.slice(4, 8)} />); + userEvent.hover(screen.getAllByRole('img')[0]); + const tooltip = await screen.findByRole('tooltip'); + expect(tooltip).toBeInTheDocument(); + expect(within(tooltip).getByText(TABLE_TITLE)).toBeInTheDocument(); + }); +}); + +test('correctly renders the tags tooltip', async () => { + await runWithBarCollapsed(async () => { + render(<MetadataBar items={ITEMS.slice(4, 8)} />); + userEvent.hover(screen.getAllByRole('img')[3]); + const tooltip = await screen.findByRole('tooltip'); + expect(tooltip).toBeInTheDocument(); + TAGS.forEach(tag => + expect(within(tooltip).getByText(tag)).toBeInTheDocument(), + ); + }); +}); diff --git a/superset-frontend/src/components/MetadataBar/MetadataBar.tsx b/superset-frontend/src/components/MetadataBar/MetadataBar.tsx new file mode 100644 index 0000000000000..b2809ae53c2c7 --- /dev/null +++ b/superset-frontend/src/components/MetadataBar/MetadataBar.tsx @@ -0,0 +1,237 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useResizeDetector } from 'react-resize-detector'; +import { uniqWith } from 'lodash'; +import { styled } from '@superset-ui/core'; +import { Tooltip, TooltipPlacement } from 'src/components/Tooltip'; +import { ContentType } from './ContentType'; +import { config } from './ContentConfig'; + +export const MIN_NUMBER_ITEMS = 2; +export const MAX_NUMBER_ITEMS = 6; + +const HORIZONTAL_PADDING = 12; +const VERTICAL_PADDING = 8; +const ICON_PADDING = 8; +const SPACE_BETWEEN_ITEMS = 16; +const ICON_WIDTH = 16; +const TEXT_MIN_WIDTH = 70; +const TEXT_MAX_WIDTH = 150; +const ORDER = { + dashboards: 0, + table: 1, + sql: 2, + rows: 3, + tags: 4, + description: 5, + owner: 6, + lastModified: 7, +}; + +const Bar = styled.div<{ count: number }>` + ${({ theme, count }) => ` + display: flex; + align-items: center; + padding: ${VERTICAL_PADDING}px ${HORIZONTAL_PADDING}px; + background-color: ${theme.colors.grayscale.light4}; + color: ${theme.colors.grayscale.base}; + font-size: ${theme.typography.sizes.s}px; + min-width: ${ + HORIZONTAL_PADDING * 2 + + (ICON_WIDTH + SPACE_BETWEEN_ITEMS) * count - + SPACE_BETWEEN_ITEMS + }px; + border-radius: ${theme.borderRadius}px; + line-height: 1; + `} +`; + +const StyledItem = styled.div<{ + collapsed: boolean; + last: boolean; + onClick?: () => void; +}>` + ${({ theme, collapsed, last, onClick }) => ` + display: flex; + align-items: center; + max-width: ${ + ICON_WIDTH + + ICON_PADDING + + TEXT_MAX_WIDTH + + (last ? 0 : SPACE_BETWEEN_ITEMS) + }px; + min-width: ${ + collapsed + ? ICON_WIDTH + (last ? 0 : SPACE_BETWEEN_ITEMS) + : ICON_WIDTH + + ICON_PADDING + + TEXT_MIN_WIDTH + + (last ? 0 : SPACE_BETWEEN_ITEMS) + }px; + padding-right: ${last ? 0 : SPACE_BETWEEN_ITEMS}px; + cursor: ${onClick ? 'pointer' : 'default'}; + & .metadata-icon { + color: ${ + onClick && collapsed + ? theme.colors.primary.base + : theme.colors.grayscale.base + }; + padding-right: ${collapsed ? 0 : ICON_PADDING}px; + & .anticon { + line-height: 0; + } + } + & .metadata-text { + min-width: ${TEXT_MIN_WIDTH}px; + overflow: hidden; + text-overflow: ${collapsed ? 'unset' : 'ellipsis'}; + white-space: nowrap; + text-decoration: ${onClick ? 'underline' : 'none'}; + } + `} +`; + +// Make sure big tootips are truncated +const TootipContent = styled.div` + display: -webkit-box; + -webkit-line-clamp: 20; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; +`; + +const Item = ({ + barWidth, + contentType, + collapsed, + last = false, + tooltipPlacement, +}: { + barWidth: number | undefined; + contentType: ContentType; + collapsed: boolean; + last?: boolean; + tooltipPlacement: TooltipPlacement; +}) => { + const { icon, title, tooltip = title } = config(contentType); + const [isTruncated, setIsTruncated] = useState(false); + const ref = useRef<HTMLDivElement>(null); + const Icon = icon; + const { type, onClick } = contentType; + + useEffect(() => { + setIsTruncated( + ref.current ? ref.current.scrollWidth > ref.current.clientWidth : false, + ); + }, [barWidth, setIsTruncated, contentType]); + + const content = ( + <StyledItem + collapsed={collapsed} + last={last} + onClick={onClick ? () => onClick(type) : undefined} + > + <Icon iconSize="l" className="metadata-icon" /> + {!collapsed && ( + <span ref={ref} className="metadata-text"> + {title} + </span> + )} + </StyledItem> + ); + return isTruncated || collapsed || (tooltip && tooltip !== title) ? ( + <Tooltip + placement={tooltipPlacement} + title={<TootipContent>{tooltip}</TootipContent>} + > + {content} + </Tooltip> + ) : ( + content + ); +}; + +export interface MetadataBarProps { + /** + * Array of content type configurations. To see the available properties + * for each content type, check {@link ContentType} + */ + items: ContentType[]; + /** + * Antd tooltip placement. To see available values, check {@link TooltipPlacement}. + * Defaults to "top". + */ + tooltipPlacement?: TooltipPlacement; +} + +/** + * The metadata bar component is used to display additional information about an entity. + * Content types are predefined and consistent across the whole app. This means that + * they will be displayed and behave in a consistent manner, keeping the same ordering, + * information formatting, and interactions. + * To extend the list of content types, a developer needs to request the inclusion of the new type in the design system. + * This process is important to make sure the new type is reviewed by the design team, improving Superset consistency. + */ +const MetadataBar = ({ items, tooltipPlacement = 'top' }: MetadataBarProps) => { + const [width, setWidth] = useState<number>(); + const [collapsed, setCollapsed] = useState(false); + const uniqueItems = uniqWith(items, (a, b) => a.type === b.type); + const sortedItems = uniqueItems.sort((a, b) => ORDER[a.type] - ORDER[b.type]); + const count = sortedItems.length; + if (count < MIN_NUMBER_ITEMS) { + throw Error('The minimum number of items for the metadata bar is 2.'); + } + if (count > MAX_NUMBER_ITEMS) { + throw Error('The maximum number of items for the metadata bar is 6.'); + } + + const onResize = useCallback( + width => { + // Calculates the breakpoint width to collapse the bar. + // The last item does not have a space, so we subtract SPACE_BETWEEN_ITEMS from the total. + const breakpoint = + (ICON_WIDTH + ICON_PADDING + TEXT_MIN_WIDTH + SPACE_BETWEEN_ITEMS) * + count - + SPACE_BETWEEN_ITEMS; + setWidth(width); + setCollapsed(Boolean(width && width < breakpoint)); + }, + [count], + ); + + const { ref } = useResizeDetector({ onResize }); + + return ( + <Bar ref={ref} count={count} data-test="metadata-bar"> + {sortedItems.map((item, index) => ( + <Item + barWidth={width} + key={index} + contentType={item} + collapsed={collapsed} + last={index === count - 1} + tooltipPlacement={tooltipPlacement} + /> + ))} + </Bar> + ); +}; + +export default MetadataBar; diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/shared-controls/emitFilterControl.test.tsx b/superset-frontend/src/components/MetadataBar/index.tsx similarity index 77% rename from superset-frontend/packages/superset-ui-chart-controls/test/shared-controls/emitFilterControl.test.tsx rename to superset-frontend/src/components/MetadataBar/index.tsx index 6070ccccfdeed..e4398a3063b26 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/shared-controls/emitFilterControl.test.tsx +++ b/superset-frontend/src/components/MetadataBar/index.tsx @@ -16,11 +16,14 @@ * specific language governing permissions and limitations * under the License. */ +import MetadataBar, { + MetadataBarProps, + MIN_NUMBER_ITEMS, + MAX_NUMBER_ITEMS, +} from './MetadataBar'; -import { emitFilterControl } from '@superset-ui/chart-controls'; +export default MetadataBar; -describe('isFeatureFlagEnabled', () => { - it('returns empty array for unset feature flag', () => { - expect(emitFilterControl).toHaveLength(0); - }); -}); +export { MetadataBarProps, MIN_NUMBER_ITEMS, MAX_NUMBER_ITEMS }; + +export * from './ContentType'; diff --git a/superset-frontend/src/components/Modal/Modal.stories.tsx b/superset-frontend/src/components/Modal/Modal.stories.tsx index b3557c5a8b990..67b8837b0d27d 100644 --- a/superset-frontend/src/components/Modal/Modal.stories.tsx +++ b/superset-frontend/src/components/Modal/Modal.stories.tsx @@ -16,8 +16,10 @@ * specific language governing permissions and limitations * under the License. */ +import { ModalFuncProps } from 'antd/lib/modal'; import React from 'react'; import Modal, { ModalProps } from '.'; +import Button from '../Button'; export default { title: 'Modal', @@ -50,3 +52,16 @@ InteractiveModal.story = { }, }, }; + +export const ModalFunctions = (props: ModalFuncProps) => ( + <div> + <Button onClick={() => Modal.error(props)}>Error</Button> + <Button onClick={() => Modal.warning(props)}>Warning</Button> + <Button onClick={() => Modal.confirm(props)}>Confirm</Button> + </div> +); + +ModalFunctions.args = { + title: 'Modal title', + content: 'Modal content', +}; diff --git a/superset-frontend/src/components/Modal/Modal.tsx b/superset-frontend/src/components/Modal/Modal.tsx index 3bd21fef8075f..d1e1affcfbe98 100644 --- a/superset-frontend/src/components/Modal/Modal.tsx +++ b/superset-frontend/src/components/Modal/Modal.tsx @@ -16,8 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useRef, useState } from 'react'; +import React, { useMemo, useRef, useState } from 'react'; import { isNil } from 'lodash'; +import { ModalFuncProps } from 'antd/lib/modal'; import { styled, t } from '@superset-ui/core'; import { css } from '@emotion/react'; import { AntdModal, AntdModalProps } from 'src/components'; @@ -57,6 +58,7 @@ export interface ModalProps { draggableConfig?: DraggableProps; destroyOnClose?: boolean; maskClosable?: boolean; + zIndex?: number; } interface StyledModalProps { @@ -201,6 +203,24 @@ export const StyledModal = styled(BaseModal)<StyledModalProps>` } `} `; +const defaultResizableConfig = (hideFooter: boolean | undefined) => ({ + maxHeight: RESIZABLE_MAX_HEIGHT, + maxWidth: RESIZABLE_MAX_WIDTH, + minHeight: hideFooter + ? RESIZABLE_MIN_HEIGHT + : RESIZABLE_MIN_HEIGHT + MODAL_FOOTER_HEIGHT, + minWidth: RESIZABLE_MIN_WIDTH, + enable: { + bottom: true, + bottomLeft: false, + bottomRight: true, + left: false, + top: false, + topLeft: false, + topRight: false, + right: true, + }, +}); const CustomModal = ({ children, @@ -222,24 +242,7 @@ const CustomModal = ({ wrapProps, draggable = false, resizable = false, - resizableConfig = { - maxHeight: RESIZABLE_MAX_HEIGHT, - maxWidth: RESIZABLE_MAX_WIDTH, - minHeight: hideFooter - ? RESIZABLE_MIN_HEIGHT - : RESIZABLE_MIN_HEIGHT + MODAL_FOOTER_HEIGHT, - minWidth: RESIZABLE_MIN_WIDTH, - enable: { - bottom: true, - bottomLeft: false, - bottomRight: true, - left: false, - top: false, - topLeft: false, - topRight: false, - right: true, - }, - }, + resizableConfig = defaultResizableConfig(hideFooter), draggableConfig, destroyOnClose, ...rest @@ -247,7 +250,13 @@ const CustomModal = ({ const draggableRef = useRef<HTMLDivElement>(null); const [bounds, setBounds] = useState<DraggableBounds>(); const [dragDisabled, setDragDisabled] = useState<boolean>(true); - const modalFooter = isNil(footer) + let FooterComponent; + if (React.isValidElement(footer)) { + // If a footer component is provided inject a closeModal function + // so the footer can provide a "close" button if desired + FooterComponent = React.cloneElement(footer, { closeModal: onHide }); + } + const modalFooter = isNil(FooterComponent) ? [ <Button key="back" onClick={onHide} cta data-test="modal-cancel-button"> {t('Cancel')} @@ -264,7 +273,7 @@ const CustomModal = ({ {primaryButtonName} </Button>, ] - : footer; + : FooterComponent; const modalWidth = width || (responsive ? '100vw' : '600px'); const shouldShowMask = !(resizable || draggable); @@ -283,6 +292,13 @@ const CustomModal = ({ } }; + const getResizableConfig = useMemo(() => { + if (Object.keys(resizableConfig).length === 0) { + return defaultResizableConfig(hideFooter); + } + return resizableConfig; + }, [hideFooter, resizableConfig]); + const ModalTitle = () => draggable ? ( <div @@ -323,7 +339,7 @@ const CustomModal = ({ {...draggableConfig} > {resizable ? ( - <Resizable className="resizable" {...resizableConfig}> + <Resizable className="resizable" {...getResizableConfig}> <div className="resizable-wrapper" ref={draggableRef}> {modal} </div> @@ -348,13 +364,26 @@ const CustomModal = ({ }; CustomModal.displayName = 'Modal'; +// Ant Design 4 does not allow overriding Modal's buttons when +// using one of the pre-defined functions. Ant Design 5 Modal introduced +// the footer property that will allow that. Meanwhile, we're replicating +// Button style using global CSS in src/GlobalStyles.tsx. +// TODO: Replace this logic when on Ant Design 5. +const buttonProps = { + okButtonProps: { className: 'modal-functions-ok-button' }, + cancelButtonProps: { className: 'modal-functions-cancel-button' }, +}; + // TODO: in another PR, rename this to CompatabilityModal // and demote it as the default export. // We should start using AntD component interfaces going forward. const Modal = Object.assign(CustomModal, { - error: AntdModal.error, - warning: AntdModal.warning, - confirm: AntdModal.confirm, + error: (config: ModalFuncProps) => + AntdModal.error({ ...config, ...buttonProps }), + warning: (config: ModalFuncProps) => + AntdModal.warning({ ...config, ...buttonProps }), + confirm: (config: ModalFuncProps) => + AntdModal.confirm({ ...config, ...buttonProps }), useModal: AntdModal.useModal, }); diff --git a/superset-frontend/src/components/ModalTrigger/ModalTrigger.stories.tsx b/superset-frontend/src/components/ModalTrigger/ModalTrigger.stories.tsx index 9c0817c2dbc60..7ab85dd1c49ef 100644 --- a/superset-frontend/src/components/ModalTrigger/ModalTrigger.stories.tsx +++ b/superset-frontend/src/components/ModalTrigger/ModalTrigger.stories.tsx @@ -20,11 +20,11 @@ import React from 'react'; import ModalTrigger from '.'; interface IModalTriggerProps { - triggerNode: React.ReactNode; + triggerNode: JSX.Element; dialogClassName?: string; - modalTitle?: React.ReactNode; - modalBody?: React.ReactNode; - modalFooter?: React.ReactNode; + modalTitle?: string; + modalBody?: JSX.Element; + modalFooter?: JSX.Element; beforeOpen?: () => void; onExit?: () => void; isButton?: boolean; diff --git a/superset-frontend/src/components/ModalTrigger/index.jsx b/superset-frontend/src/components/ModalTrigger/index.jsx deleted file mode 100644 index b15000d851fb3..0000000000000 --- a/superset-frontend/src/components/ModalTrigger/index.jsx +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import PropTypes from 'prop-types'; -import Modal from 'src/components/Modal'; -import Button from 'src/components/Button'; - -const propTypes = { - dialogClassName: PropTypes.string, - triggerNode: PropTypes.node.isRequired, - modalTitle: PropTypes.node, - modalBody: PropTypes.node, // not required because it can be generated by beforeOpen - modalFooter: PropTypes.node, - beforeOpen: PropTypes.func, - onExit: PropTypes.func, - isButton: PropTypes.bool, - className: PropTypes.string, - tooltip: PropTypes.string, - width: PropTypes.string, - maxWidth: PropTypes.string, - responsive: PropTypes.bool, - resizable: PropTypes.bool, - resizableConfig: PropTypes.object, - draggable: PropTypes.bool, - draggableConfig: PropTypes.object, - destroyOnClose: PropTypes.bool, -}; - -const defaultProps = { - beforeOpen: () => {}, - onExit: () => {}, - isButton: false, - className: '', - modalTitle: '', - resizable: false, - draggable: false, -}; - -export default class ModalTrigger extends React.Component { - constructor(props) { - super(props); - this.state = { - showModal: false, - }; - this.open = this.open.bind(this); - this.close = this.close.bind(this); - } - - close() { - this.setState(() => ({ showModal: false })); - } - - open(e) { - e.preventDefault(); - this.props.beforeOpen(); - this.setState(() => ({ showModal: true })); - } - - renderModal() { - return ( - <Modal - wrapClassName={this.props.dialogClassName} - className={this.props.className} - show={this.state.showModal} - onHide={this.close} - afterClose={this.props.onExit} - title={this.props.modalTitle} - footer={this.props.modalFooter} - hideFooter={!this.props.modalFooter} - width={this.props.width} - maxWidth={this.props.maxWidth} - responsive={this.props.responsive} - resizable={this.props.resizable} - resizableConfig={this.props.resizableConfig} - draggable={this.props.draggable} - draggableConfig={this.props.draggableConfig} - destroyOnClose={this.props.destroyOnClose} - > - {this.props.modalBody} - </Modal> - ); - } - - render() { - if (this.props.isButton) { - return ( - <> - <Button - className="modal-trigger" - data-test="btn-modal-trigger" - tooltip={this.props.tooltip} - onClick={this.open} - > - {this.props.triggerNode} - </Button> - {this.renderModal()} - </> - ); - } - /* eslint-disable jsx-a11y/interactive-supports-focus */ - return ( - <> - <span data-test="span-modal-trigger" onClick={this.open} role="button"> - {this.props.triggerNode} - </span> - {this.renderModal()} - </> - ); - } -} - -ModalTrigger.propTypes = propTypes; -ModalTrigger.defaultProps = defaultProps; diff --git a/superset-frontend/src/components/ModalTrigger/index.tsx b/superset-frontend/src/components/ModalTrigger/index.tsx new file mode 100644 index 0000000000000..8b689d640b7cc --- /dev/null +++ b/superset-frontend/src/components/ModalTrigger/index.tsx @@ -0,0 +1,130 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useState } from 'react'; +import Modal from 'src/components/Modal'; +import Button from 'src/components/Button'; + +interface ModalTriggerProps { + dialogClassName?: string; + triggerNode: React.ReactNode; + modalTitle?: string; + modalBody?: React.ReactNode; // not required because it can be generated by beforeOpen + modalFooter?: React.ReactNode; + beforeOpen?: Function; + onExit?: Function; + isButton?: boolean; + className?: string; + tooltip?: string; + width?: string; + maxWidth?: string; + responsive?: boolean; + resizable?: boolean; + resizableConfig?: any; + draggable?: boolean; + draggableConfig?: any; + destroyOnClose?: boolean; +} + +export interface ModalTriggerRef { + current: { + close: Function; + open: Function; + }; +} + +const ModalTrigger = React.forwardRef( + (props: ModalTriggerProps, ref: ModalTriggerRef | null) => { + const [showModal, setShowModal] = useState(false); + const { + beforeOpen = () => {}, + onExit = () => {}, + isButton = false, + resizable = false, + draggable = false, + className = '', + tooltip, + modalFooter, + triggerNode, + destroyOnClose = true, + modalBody, + draggableConfig = {}, + resizableConfig = {}, + modalTitle, + responsive, + width, + maxWidth, + } = props; + + const close = () => { + setShowModal(false); + onExit?.(); + }; + + const open = (e: React.MouseEvent) => { + e.preventDefault(); + beforeOpen?.(); + setShowModal(true); + }; + + if (ref) { + ref.current = { close, open }; // eslint-disable-line + } + + /* eslint-disable jsx-a11y/interactive-supports-focus */ + return ( + <> + {isButton && ( + <Button + className="modal-trigger" + data-test="btn-modal-trigger" + tooltip={tooltip} + onClick={open} + > + {triggerNode} + </Button> + )} + {!isButton && ( + <span data-test="span-modal-trigger" onClick={open} role="button"> + {triggerNode} + </span> + )} + <Modal + className={className} + show={showModal} + onHide={close} + title={modalTitle} + footer={modalFooter} + hideFooter={!modalFooter} + width={width} + maxWidth={maxWidth} + responsive={responsive} + resizable={resizable} + resizableConfig={resizableConfig} + draggable={draggable} + draggableConfig={draggableConfig} + destroyOnClose={destroyOnClose} + > + {modalBody} + </Modal> + </> + ); + }, +); + +export default ModalTrigger; diff --git a/superset-frontend/src/components/PageHeaderWithActions/index.tsx b/superset-frontend/src/components/PageHeaderWithActions/index.tsx index 4449d1c6b3472..9209ab818d44f 100644 --- a/superset-frontend/src/components/PageHeaderWithActions/index.tsx +++ b/superset-frontend/src/components/PageHeaderWithActions/index.tsx @@ -19,6 +19,7 @@ import React, { ReactNode, ReactElement } from 'react'; import { css, SupersetTheme, t, useTheme } from '@superset-ui/core'; import { AntdDropdown, AntdDropdownProps } from 'src/components'; +import { TooltipPlacement } from 'src/components/Tooltip'; import { DynamicEditableTitle, DynamicEditableTitleProps, @@ -92,7 +93,7 @@ const buttonsStyles = (theme: SupersetTheme) => css` & .fave-unfave-icon { padding: 0 ${theme.gridUnit}px; - &:first-child { + &:first-of-type { padding-left: 0; } } @@ -112,6 +113,10 @@ export type PageHeaderWithActionsProps = { rightPanelAdditionalItems: ReactNode; additionalActionsMenu: ReactElement; menuDropdownProps: Omit<AntdDropdownProps, 'overlay'>; + tooltipProps?: { + text?: string; + placement?: TooltipPlacement; + }; }; export const PageHeaderWithActions = ({ @@ -124,6 +129,7 @@ export const PageHeaderWithActions = ({ rightPanelAdditionalItems, additionalActionsMenu, menuDropdownProps, + tooltipProps, }: PageHeaderWithActionsProps) => { const theme = useTheme(); return ( @@ -152,6 +158,9 @@ export const PageHeaderWithActions = ({ css={menuTriggerStyles} buttonStyle="tertiary" aria-label={t('Menu actions trigger')} + tooltip={tooltipProps?.text} + placement={tooltipProps?.placement} + data-test="actions-trigger" > <Icons.MoreHoriz iconColor={theme.colors.primary.dark2} diff --git a/superset-frontend/src/components/PopoverDropdown/PopoverDropdown.test.tsx b/superset-frontend/src/components/PopoverDropdown/PopoverDropdown.test.tsx index 2704e11e0cd43..2c02eec91ab2f 100644 --- a/superset-frontend/src/components/PopoverDropdown/PopoverDropdown.test.tsx +++ b/superset-frontend/src/components/PopoverDropdown/PopoverDropdown.test.tsx @@ -36,19 +36,19 @@ const defaultProps: PopoverDropdownProps = { onChange: jest.fn(), }; -test('renders with default props', () => { +test('renders with default props', async () => { render(<PopoverDropdown {...defaultProps} />); - expect(screen.getByRole('button')).toBeInTheDocument(); + expect(await screen.findByRole('button')).toBeInTheDocument(); expect(screen.getByRole('button')).toHaveTextContent('Option 1'); }); -test('renders the menu on click', () => { +test('renders the menu on click', async () => { render(<PopoverDropdown {...defaultProps} />); userEvent.click(screen.getByRole('button')); - expect(screen.getByRole('menu')).toBeInTheDocument(); + expect(await screen.findByRole('menu')).toBeInTheDocument(); }); -test('renders with custom button', () => { +test('renders with custom button', async () => { render( <PopoverDropdown {...defaultProps} @@ -59,10 +59,10 @@ test('renders with custom button', () => { )} />, ); - expect(screen.getByText('Custom Option 1')).toBeInTheDocument(); + expect(await screen.findByText('Custom Option 1')).toBeInTheDocument(); }); -test('renders with custom option', () => { +test('renders with custom option', async () => { render( <PopoverDropdown {...defaultProps} @@ -74,13 +74,13 @@ test('renders with custom option', () => { />, ); userEvent.click(screen.getByRole('button')); - expect(screen.getByText('Custom Option 1')).toBeInTheDocument(); + expect(await screen.findByText('Custom Option 1')).toBeInTheDocument(); }); -test('triggers onChange', () => { +test('triggers onChange', async () => { render(<PopoverDropdown {...defaultProps} />); userEvent.click(screen.getByRole('button')); - expect(screen.getByText('Option 2')).toBeInTheDocument(); + expect(await screen.findByText('Option 2')).toBeInTheDocument(); userEvent.click(screen.getByText('Option 2')); expect(defaultProps.onChange).toHaveBeenCalled(); }); diff --git a/superset-frontend/src/components/PopoverSection/PopoverSection.test.tsx b/superset-frontend/src/components/PopoverSection/PopoverSection.test.tsx index 2135f6ba46ef3..16952834c16ce 100644 --- a/superset-frontend/src/components/PopoverSection/PopoverSection.test.tsx +++ b/superset-frontend/src/components/PopoverSection/PopoverSection.test.tsx @@ -21,23 +21,23 @@ import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import PopoverSection from 'src/components/PopoverSection'; -test('renders with default props', () => { +test('renders with default props', async () => { render( <PopoverSection title="Title"> <div role="form" /> </PopoverSection>, ); - expect(screen.getByRole('form')).toBeInTheDocument(); - expect(screen.getAllByRole('img').length).toBe(1); + expect(await screen.findByRole('form')).toBeInTheDocument(); + expect((await screen.findAllByRole('img')).length).toBe(1); }); -test('renders tooltip icon', () => { +test('renders tooltip icon', async () => { render( <PopoverSection title="Title" info="Tooltip"> <div role="form" /> </PopoverSection>, ); - expect(screen.getAllByRole('img').length).toBe(2); + expect((await screen.findAllByRole('img')).length).toBe(2); }); test('renders a tooltip when hovered', async () => { @@ -50,13 +50,13 @@ test('renders a tooltip when hovered', async () => { expect(await screen.findByRole('tooltip')).toBeInTheDocument(); }); -test('calls onSelect when clicked', () => { +test('calls onSelect when clicked', async () => { const onSelect = jest.fn(); render( <PopoverSection title="Title" onSelect={onSelect}> <div role="form" /> </PopoverSection>, ); - userEvent.click(screen.getByRole('img')); + userEvent.click(await screen.findByRole('img')); expect(onSelect).toHaveBeenCalled(); }); diff --git a/superset-frontend/src/components/ProgressBar/index.tsx b/superset-frontend/src/components/ProgressBar/index.tsx index 93b4315e523d7..ba69fc90c6cab 100644 --- a/superset-frontend/src/components/ProgressBar/index.tsx +++ b/superset-frontend/src/components/ProgressBar/index.tsx @@ -27,7 +27,7 @@ export interface ProgressBarProps extends ProgressProps { // eslint-disable-next-line @typescript-eslint/no-unused-vars const ProgressBar = styled(({ striped, ...props }: ProgressBarProps) => ( - <AntdProgress {...props} /> + <AntdProgress data-test="progress-bar" {...props} /> ))` line-height: 0; position: static; diff --git a/superset-frontend/src/components/Radio/index.tsx b/superset-frontend/src/components/Radio/index.tsx index 9ab656e4aa80b..f06392d27879e 100644 --- a/superset-frontend/src/components/Radio/index.tsx +++ b/superset-frontend/src/components/Radio/index.tsx @@ -57,4 +57,5 @@ const StyledGroup = styled(AntdRadio.Group)` export const Radio = Object.assign(StyledRadio, { Group: StyledGroup, + Button: AntdRadio.Button, }); diff --git a/superset-frontend/src/components/RefreshLabel/RefreshLabel.test.tsx b/superset-frontend/src/components/RefreshLabel/RefreshLabel.test.tsx index 55750fba828e2..a8d5d7e3c2e17 100644 --- a/superset-frontend/src/components/RefreshLabel/RefreshLabel.test.tsx +++ b/superset-frontend/src/components/RefreshLabel/RefreshLabel.test.tsx @@ -21,9 +21,9 @@ import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import RefreshLabel from 'src/components/RefreshLabel'; -test('renders with default props', () => { +test('renders with default props', async () => { render(<RefreshLabel tooltipContent="Tooltip" onClick={jest.fn()} />); - const refresh = screen.getByRole('button'); + const refresh = await screen.findByRole('button'); expect(refresh).toBeInTheDocument(); userEvent.hover(refresh); }); @@ -38,10 +38,10 @@ test('renders tooltip on hover', async () => { expect(tooltip).toHaveTextContent(tooltipText); }); -test('triggers on click event', () => { +test('triggers on click event', async () => { const onClick = jest.fn(); render(<RefreshLabel tooltipContent="Tooltip" onClick={onClick} />); - const refresh = screen.getByRole('button'); + const refresh = await screen.findByRole('button'); userEvent.click(refresh); expect(onClick).toHaveBeenCalled(); }); diff --git a/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.test.tsx b/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.test.tsx index a527fd67ccfde..ea1d823d2498c 100644 --- a/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.test.tsx +++ b/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.test.tsx @@ -33,72 +33,64 @@ const createProps = () => ({ }); const stateWithOnlyUser = { - explore: { - user: { - email: 'admin@test.com', - firstName: 'admin', - isActive: true, - lastName: 'admin', - permissions: {}, - createdOn: '2022-01-12T10:17:37.801361', - roles: { Admin: [['menu_access', 'Manage']] }, - userId: 1, - username: 'admin', - }, + user: { + email: 'admin@test.com', + firstName: 'admin', + isActive: true, + lastName: 'admin', + permissions: {}, + createdOn: '2022-01-12T10:17:37.801361', + roles: { Admin: [['menu_access', 'Manage']] }, + userId: 1, + username: 'admin', }, reports: {}, }; const stateWithNonAdminUser = { - explore: { - user: { - email: 'nonadmin@test.com', - firstName: 'nonadmin', - isActive: true, - lastName: 'nonadmin', - permissions: {}, - createdOn: '2022-01-12T10:17:37.801361', - roles: { - Gamme: [['no_menu_access', 'Manage']], - OtherRole: [['menu_access', 'Manage']], - }, - userId: 1, - username: 'nonadmin', + user: { + email: 'nonadmin@test.com', + firstName: 'nonadmin', + isActive: true, + lastName: 'nonadmin', + permissions: {}, + createdOn: '2022-01-12T10:17:37.801361', + roles: { + Gamme: [['no_menu_access', 'Manage']], + OtherRole: [['menu_access', 'Manage']], }, + userId: 1, + username: 'nonadmin', }, reports: {}, }; const stateWithNonMenuAccessOnManage = { - explore: { - user: { - email: 'nonaccess@test.com', - firstName: 'nonaccess', - isActive: true, - lastName: 'nonaccess', - permissions: {}, - createdOn: '2022-01-12T10:17:37.801361', - roles: { Gamma: [['no_menu_access', 'Manage']] }, - userId: 1, - username: 'nonaccess', - }, + user: { + email: 'nonaccess@test.com', + firstName: 'nonaccess', + isActive: true, + lastName: 'nonaccess', + permissions: {}, + createdOn: '2022-01-12T10:17:37.801361', + roles: { Gamma: [['no_menu_access', 'Manage']] }, + userId: 1, + username: 'nonaccess', }, reports: {}, }; const stateWithUserAndReport = { - explore: { - user: { - email: 'admin@test.com', - firstName: 'admin', - isActive: true, - lastName: 'admin', - permissions: {}, - createdOn: '2022-01-12T10:17:37.801361', - roles: { Admin: [['menu_access', 'Manage']] }, - userId: 1, - username: 'admin', - }, + user: { + email: 'admin@test.com', + firstName: 'admin', + isActive: true, + lastName: 'admin', + permissions: {}, + createdOn: '2022-01-12T10:17:37.801361', + roles: { Admin: [['menu_access', 'Manage']] }, + userId: 1, + username: 'admin', }, reports: { dashboards: { diff --git a/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx b/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx index a83ab239ff17d..504ba41d09a3f 100644 --- a/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx +++ b/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx @@ -23,9 +23,11 @@ import { t, SupersetTheme, css, + styled, useTheme, FeatureFlag, isFeatureEnabled, + getExtensionsRegistry, } from '@superset-ui/core'; import Icons from 'src/components/Icons'; import { Switch } from 'src/components/Switch'; @@ -46,6 +48,8 @@ import { import { reportSelector } from 'src/views/CRUD/hooks'; import { MenuItemWithCheckboxContainer } from 'src/explore/components/useExploreAdditionalActionsMenu/index'; +const extensionsRegistry = getExtensionsRegistry(); + const deleteColor = (theme: SupersetTheme) => css` color: ${theme.colors.error.base}; `; @@ -70,6 +74,21 @@ const onMenuItemHover = (theme: SupersetTheme) => css` background-color: ${theme.colors.secondary.light5}; } `; + +const StyledDropdownItemWithIcon = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + > *:first-child { + margin-right: ${({ theme }) => theme.gridUnit}px; + } +`; + +const DropdownItemExtension = extensionsRegistry.get( + 'report-modal.dropdown.item.icon', +); + export enum CreationMethod { CHARTS = 'charts', DASHBOARDS = 'dashboards', @@ -103,7 +122,7 @@ export default function HeaderReportDropDown({ const user: UserWithPermissionsAndRoles = useSelector< any, UserWithPermissionsAndRoles - >(state => state.user || state.explore?.user); + >(state => state.user); const canAddReports = () => { if (!isFeatureEnabled(FeatureFlag.ALERT_REPORTS)) { return false; @@ -201,7 +220,14 @@ export default function HeaderReportDropDown({ ) : ( <Menu selectable={false} css={onMenuHover}> <Menu.Item onClick={handleShowMenu}> - {t('Set up an email report')} + {DropdownItemExtension ? ( + <StyledDropdownItemWithIcon> + <div>{t('Set up an email report')}</div> + <DropdownItemExtension /> + </StyledDropdownItemWithIcon> + ) : ( + t('Set up an email report') + )} </Menu.Item> <Menu.Divider /> </Menu> diff --git a/superset-frontend/src/components/ReportModal/ReportModal.test.tsx b/superset-frontend/src/components/ReportModal/ReportModal.test.tsx index 1db3aa0fd6c5e..2755d832d79f5 100644 --- a/superset-frontend/src/components/ReportModal/ReportModal.test.tsx +++ b/superset-frontend/src/components/ReportModal/ReportModal.test.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import userEvent from '@testing-library/user-event'; import sinon from 'sinon'; import fetchMock from 'fetch-mock'; -import { render, screen } from 'spec/helpers/testing-library'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; import * as featureFlags from 'src/featureFlags'; import * as actions from 'src/reports/actions/reports'; import { FeatureFlag } from '@superset-ui/core'; @@ -156,7 +156,7 @@ describe('Email Report Modal', () => { // Click "Add" button to create a new email report const addButton = screen.getByRole('button', { name: /add/i }); - userEvent.click(addButton); + await waitFor(() => userEvent.click(addButton)); // Mock addReport from Redux const makeRequest = () => { @@ -164,16 +164,15 @@ describe('Email Report Modal', () => { return request(dispatch); }; - return makeRequest().then(() => { - // 🐞 ----- There are 2 POST calls at this point ----- 🐞 + await makeRequest(); - // addReport's mocked POST return should match the mocked values - expect(fetchMock.lastOptions()?.body).toEqual(stringyReportValues); - // Dispatch should be called once for addReport - expect(dispatch.callCount).toBe(2); - const reportCalls = fetchMock.calls(REPORT_ENDPOINT); - expect(reportCalls).toHaveLength(2); - }); + // 🐞 ----- There are 2 POST calls at this point ----- 🐞 + + // addReport's mocked POST return should match the mocked values + expect(fetchMock.lastOptions()?.body).toEqual(stringyReportValues); + expect(dispatch.callCount).toBe(2); + const reportCalls = fetchMock.calls(REPORT_ENDPOINT); + expect(reportCalls).toHaveLength(2); }); }); }); diff --git a/superset-frontend/src/components/ReportModal/index.tsx b/superset-frontend/src/components/ReportModal/index.tsx index 632f9f91ec42e..9f9596e2ffcf3 100644 --- a/superset-frontend/src/components/ReportModal/index.tsx +++ b/superset-frontend/src/components/ReportModal/index.tsx @@ -273,7 +273,7 @@ function ReportModal({ onChange: ({ target }: { target: HTMLInputElement }) => setCurrentReport({ name: target.value }), }} - label="Report Name" + label={t('Report Name')} data-test="report-name-test" /> <LabeledErrorBoundInput diff --git a/superset-frontend/src/components/ResizableSidebar/index.tsx b/superset-frontend/src/components/ResizableSidebar/index.tsx new file mode 100644 index 0000000000000..4abe56e526fd3 --- /dev/null +++ b/superset-frontend/src/components/ResizableSidebar/index.tsx @@ -0,0 +1,82 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { Resizable } from 're-resizable'; +import { styled } from '@superset-ui/core'; +import useStoredSidebarWidth from './useStoredSidebarWidth'; + +const ResizableWrapper = styled.div` + position: absolute; + height: 100%; + + :hover .sidebar-resizer::after { + background-color: ${({ theme }) => theme.colors.primary.base}; + } + + .sidebar-resizer { + // @z-index-above-sticky-header (100) + 1 = 101 + z-index: 101; + } + + .sidebar-resizer::after { + display: block; + content: ''; + width: 1px; + height: 100%; + margin: 0 auto; + } +`; + +type Props = { + id: string; + initialWidth: number; + enable: boolean; + minWidth?: number; + maxWidth?: number; + children: (width: number) => React.ReactNode; +}; + +const ResizableSidebar: React.FC<Props> = ({ + id, + initialWidth, + minWidth, + maxWidth, + enable, + children, +}) => { + const [width, setWidth] = useStoredSidebarWidth(id, initialWidth); + + return ( + <> + <ResizableWrapper> + <Resizable + enable={{ right: enable }} + handleClasses={{ right: 'sidebar-resizer' }} + size={{ width, height: '100%' }} + minWidth={minWidth} + maxWidth={maxWidth} + onResizeStop={(e, direction, ref, d) => setWidth(width + d.width)} + /> + </ResizableWrapper> + {children(width)} + </> + ); +}; + +export default ResizableSidebar; diff --git a/superset-frontend/src/components/ResizableSidebar/useStoredSidebarWidth.test.ts b/superset-frontend/src/components/ResizableSidebar/useStoredSidebarWidth.test.ts new file mode 100644 index 0000000000000..347cfd8b9ae30 --- /dev/null +++ b/superset-frontend/src/components/ResizableSidebar/useStoredSidebarWidth.test.ts @@ -0,0 +1,92 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { renderHook, act } from '@testing-library/react-hooks'; +import { + LocalStorageKeys, + setItem, + getItem, +} from 'src/utils/localStorageHelpers'; +import useStoredSidebarWidth from './useStoredSidebarWidth'; + +const INITIAL_WIDTH = 300; + +describe('useStoredSidebarWidth', () => { + beforeEach(() => { + localStorage.clear(); + }); + + afterAll(() => { + localStorage.clear(); + }); + + it('returns a default filterBar width by initialWidth', () => { + const id = '123'; + const { result } = renderHook(() => + useStoredSidebarWidth(id, INITIAL_WIDTH), + ); + const [actualWidth] = result.current; + + expect(actualWidth).toEqual(INITIAL_WIDTH); + }); + + it('returns a stored filterBar width from localStorage', () => { + const id = '123'; + const expectedWidth = 378; + setItem(LocalStorageKeys.common__resizable_sidebar_widths, { + [id]: expectedWidth, + '456': 250, + }); + const { result } = renderHook(() => + useStoredSidebarWidth(id, INITIAL_WIDTH), + ); + const [actualWidth] = result.current; + + expect(actualWidth).toEqual(expectedWidth); + expect(actualWidth).not.toEqual(250); + }); + + it('returns a setter for filterBar width that stores the state in localStorage together', () => { + const id = '123'; + const expectedWidth = 378; + const otherDashboardId = '456'; + const otherDashboardWidth = 253; + setItem(LocalStorageKeys.common__resizable_sidebar_widths, { + [id]: 300, + [otherDashboardId]: otherDashboardWidth, + }); + const { result } = renderHook(() => + useStoredSidebarWidth(id, INITIAL_WIDTH), + ); + const [prevWidth, setter] = result.current; + + expect(prevWidth).toEqual(300); + + act(() => setter(expectedWidth)); + + const updatedWidth = result.current[0]; + const widthsMap = getItem( + LocalStorageKeys.common__resizable_sidebar_widths, + {}, + ); + expect(widthsMap[id]).toEqual(expectedWidth); + expect(widthsMap[otherDashboardId]).toEqual(otherDashboardWidth); + expect(updatedWidth).toEqual(expectedWidth); + expect(updatedWidth).not.toEqual(250); + }); +}); diff --git a/superset-frontend/src/components/ResizableSidebar/useStoredSidebarWidth.ts b/superset-frontend/src/components/ResizableSidebar/useStoredSidebarWidth.ts new file mode 100644 index 0000000000000..4448d2ec52a3f --- /dev/null +++ b/superset-frontend/src/components/ResizableSidebar/useStoredSidebarWidth.ts @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useEffect, useRef, useState } from 'react'; +import { + LocalStorageKeys, + setItem, + getItem, +} from 'src/utils/localStorageHelpers'; + +export default function useStoredSidebarWidth( + id: string, + initialWidth: number, +) { + const widthsMapRef = useRef<Record<string, number>>(); + const [sidebarWidth, setSidebarWidth] = useState<number>(initialWidth); + + useEffect(() => { + widthsMapRef.current = + widthsMapRef.current ?? + getItem(LocalStorageKeys.common__resizable_sidebar_widths, {}); + if (widthsMapRef.current[id]) { + setSidebarWidth(widthsMapRef.current[id]); + } + }, [id]); + + function setStoredSidebarWidth(updatedWidth: number) { + setSidebarWidth(updatedWidth); + setItem(LocalStorageKeys.common__resizable_sidebar_widths, { + ...widthsMapRef.current, + [id]: updatedWidth, + }); + } + + return [sidebarWidth, setStoredSidebarWidth] as const; +} diff --git a/superset-frontend/src/components/Select/AsyncSelect.stories.tsx b/superset-frontend/src/components/Select/AsyncSelect.stories.tsx new file mode 100644 index 0000000000000..0bdaf43f2c06f --- /dev/null +++ b/superset-frontend/src/components/Select/AsyncSelect.stories.tsx @@ -0,0 +1,368 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { + ReactNode, + useState, + useCallback, + useRef, + useMemo, +} from 'react'; +import Button from 'src/components/Button'; +import AsyncSelect from './AsyncSelect'; +import { + SelectOptionsType, + AsyncSelectProps, + AsyncSelectRef, + SelectOptionsTypePage, +} from './types'; + +export default { + title: 'AsyncSelect', + component: AsyncSelect, +}; + +const DEFAULT_WIDTH = 200; + +const options: SelectOptionsType = [ + { + label: 'Such an incredibly awesome long long label', + value: 'Such an incredibly awesome long long label', + custom: 'Secret custom prop', + }, + { + label: 'Another incredibly awesome long long label', + value: 'Another incredibly awesome long long label', + }, + { + label: 'JSX Label', + customLabel: <div style={{ color: 'red' }}>JSX Label</div>, + value: 'JSX Label', + }, + { label: 'A', value: 'A' }, + { label: 'B', value: 'B' }, + { label: 'C', value: 'C' }, + { label: 'D', value: 'D' }, + { label: 'E', value: 'E' }, + { label: 'F', value: 'F' }, + { label: 'G', value: 'G' }, + { label: 'H', value: 'H' }, + { label: 'I', value: 'I' }, +]; + +const ARG_TYPES = { + options: { + defaultValue: options, + description: `It defines the options of the Select. + The options can be static, an array of options. + The options can also be async, a promise that returns an array of options. + `, + }, + ariaLabel: { + description: `It adds the aria-label tag for accessibility standards. + Must be plain English and localized. + `, + }, + labelInValue: { + defaultValue: true, + table: { + disable: true, + }, + }, + name: { + table: { + disable: true, + }, + }, + notFoundContent: { + table: { + disable: true, + }, + }, + mode: { + description: `It defines whether the Select should allow for + the selection of multiple options or single. Single by default. + `, + defaultValue: 'single', + control: { + type: 'inline-radio', + options: ['single', 'multiple'], + }, + }, + allowNewOptions: { + description: `It enables the user to create new options. + Can be used with standard or async select types. + Can be used with any mode, single or multiple. False by default. + `, + }, + invertSelection: { + description: `It shows a stop-outlined icon at the far right of a selected + option instead of the default checkmark. + Useful to better indicate to the user that by clicking on a selected + option it will be de-selected. False by default. + `, + }, + optionFilterProps: { + description: `It allows to define which properties of the option object + should be looked for when searching. + By default label and value. + `, + }, + oneLine: { + defaultValue: false, + description: `Sets maxTagCount to 1. The overflow tag is always displayed in + the same line, line wrapping is disabled. + When the dropdown is open, sets maxTagCount to 0, + displays only the overflow tag. + Requires '"mode=multiple"'. + `, + }, +}; + +const USERS = [ + 'John', + 'Liam', + 'Olivia', + 'Emma', + 'Noah', + 'Ava', + 'Oliver', + 'Elijah', + 'Charlotte', + 'Diego', + 'Evan', + 'Michael', + 'Giovanni', + 'Luca', + 'Paolo', + 'Francesca', + 'Chiara', + 'Sara', + 'Valentina', + 'Jessica', + 'Angelica', + 'Mario', + 'Marco', + 'Andrea', + 'Luigi', + 'Quarto', + 'Quinto', + 'Sesto', + 'Franco', + 'Sandro', + 'Alehandro', + 'Johnny', + 'Nikole', + 'Igor', + 'Sipatha', + 'Thami', + 'Munei', + 'Guilherme', + 'Umair', + 'Ashfaq', + 'Amna', + 'Irfan', + 'George', + 'Naseer', + 'Mohammad', + 'Rick', + 'Saliya', + 'Claire', + 'Benedetta', + 'Ilenia', +].sort(); + +export const AsynchronousSelect = ({ + fetchOnlyOnSearch, + withError, + withInitialValue, + responseTime, + ...rest +}: AsyncSelectProps & { + withError: boolean; + withInitialValue: boolean; + responseTime: number; +}) => { + const [requests, setRequests] = useState<ReactNode[]>([]); + const ref = useRef<AsyncSelectRef>(null); + + const getResults = (username?: string) => { + let results: { label: string; value: string }[] = []; + + if (!username) { + results = USERS.map(u => ({ + label: u, + value: u, + })); + } else { + const foundUsers = USERS.filter(u => u.toLowerCase().includes(username)); + if (foundUsers) { + results = foundUsers.map(u => ({ label: u, value: u })); + } else { + results = []; + } + } + return results; + }; + + const setRequestLog = (results: number, total: number, username?: string) => { + const request = ( + <> + Emulating network request with search <b>{username || 'empty'}</b> ...{' '} + <b> + {results}/{total} + </b>{' '} + results + </> + ); + + setRequests(requests => [request, ...requests]); + }; + + const fetchUserListPage = useCallback( + ( + search: string, + page: number, + pageSize: number, + ): Promise<SelectOptionsTypePage> => { + const username = search.trim().toLowerCase(); + return new Promise(resolve => { + let results = getResults(username); + const totalCount = results.length; + const start = page * pageSize; + const deleteCount = + start + pageSize < totalCount ? pageSize : totalCount - start; + results = results.splice(start, deleteCount); + setRequestLog(start + results.length, totalCount, username); + setTimeout(() => { + resolve({ data: results, totalCount }); + }, responseTime * 1000); + }); + }, + [responseTime], + ); + + const fetchUserListError = async (): Promise<SelectOptionsTypePage> => + new Promise((_, reject) => { + reject(new Error('Error while fetching the names from the server')); + }); + + const initialValue = useMemo( + () => ({ label: 'Valentina', value: 'Valentina' }), + [], + ); + + return ( + <> + <div + style={{ + width: DEFAULT_WIDTH, + }} + > + <AsyncSelect + {...rest} + ref={ref} + fetchOnlyOnSearch={fetchOnlyOnSearch} + options={withError ? fetchUserListError : fetchUserListPage} + placeholder={fetchOnlyOnSearch ? 'Type anything' : 'AsyncSelect...'} + value={withInitialValue ? initialValue : undefined} + /> + </div> + <div + style={{ + position: 'absolute', + top: 32, + left: DEFAULT_WIDTH + 100, + height: 400, + width: 600, + overflowY: 'auto', + border: '1px solid #d9d9d9', + padding: 20, + }} + > + {requests.map((request, index) => ( + <p key={`request-${index}`}>{request}</p> + ))} + </div> + <Button + style={{ + position: 'absolute', + top: 452, + left: DEFAULT_WIDTH + 580, + }} + onClick={() => { + ref.current?.clearCache(); + setRequests([]); + }} + > + Clear cache + </Button> + </> + ); +}; + +AsynchronousSelect.args = { + allowClear: false, + allowNewOptions: false, + fetchOnlyOnSearch: false, + pageSize: 10, + withError: false, + withInitialValue: false, + tokenSeparators: ['\n', '\t', ';'], +}; + +AsynchronousSelect.argTypes = { + ...ARG_TYPES, + header: { + table: { + disable: true, + }, + }, + invertSelection: { + table: { + disable: true, + }, + }, + pageSize: { + defaultValue: 10, + control: { + type: 'range', + min: 10, + max: 50, + step: 10, + }, + }, + responseTime: { + defaultValue: 0.5, + name: 'responseTime (seconds)', + control: { + type: 'range', + min: 0.5, + max: 5, + step: 0.5, + }, + }, +}; + +AsynchronousSelect.story = { + parameters: { + knobs: { + disable: true, + }, + }, +}; diff --git a/superset-frontend/src/components/Select/AsyncSelect.test.tsx b/superset-frontend/src/components/Select/AsyncSelect.test.tsx new file mode 100644 index 0000000000000..ac9c78767c4ae --- /dev/null +++ b/superset-frontend/src/components/Select/AsyncSelect.test.tsx @@ -0,0 +1,813 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen, waitFor, within } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { AsyncSelect } from 'src/components'; + +const ARIA_LABEL = 'Test'; +const NEW_OPTION = 'Kyle'; +const NO_DATA = 'No Data'; +const LOADING = 'Loading...'; +const OPTIONS = [ + { label: 'John', value: 1, gender: 'Male' }, + { label: 'Liam', value: 2, gender: 'Male' }, + { label: 'Olivia', value: 3, gender: 'Female' }, + { label: 'Emma', value: 4, gender: 'Female' }, + { label: 'Noah', value: 5, gender: 'Male' }, + { label: 'Ava', value: 6, gender: 'Female' }, + { label: 'Oliver', value: 7, gender: 'Male' }, + { label: 'ElijahH', value: 8, gender: 'Male' }, + { label: 'Charlotte', value: 9, gender: 'Female' }, + { label: 'Giovanni', value: 10, gender: 'Male' }, + { label: 'Franco', value: 11, gender: 'Male' }, + { label: 'Sandro', value: 12, gender: 'Male' }, + { label: 'Alehandro', value: 13, gender: 'Male' }, + { label: 'Johnny', value: 14, gender: 'Male' }, + { label: 'Nikole', value: 15, gender: 'Female' }, + { label: 'Igor', value: 16, gender: 'Male' }, + { label: 'Guilherme', value: 17, gender: 'Male' }, + { label: 'Irfan', value: 18, gender: 'Male' }, + { label: 'George', value: 19, gender: 'Male' }, + { label: 'Ashfaq', value: 20, gender: 'Male' }, + { label: 'Herme', value: 21, gender: 'Male' }, + { label: 'Cher', value: 22, gender: 'Female' }, + { label: 'Her', value: 23, gender: 'Male' }, +].sort((option1, option2) => option1.label.localeCompare(option2.label)); +const NULL_OPTION = { label: '<NULL>', value: null } as unknown as { + label: string; + value: number; +}; + +const loadOptions = async (search: string, page: number, pageSize: number) => { + const totalCount = OPTIONS.length; + const start = page * pageSize; + const deleteCount = + start + pageSize < totalCount ? pageSize : totalCount - start; + const searchValue = search.trim().toLowerCase(); + const optionFilterProps = ['label', 'value', 'gender']; + const data = OPTIONS.filter(option => + optionFilterProps.some(prop => { + const optionProp = option?.[prop] + ? String(option[prop]).trim().toLowerCase() + : ''; + return optionProp.includes(searchValue); + }), + ).splice(start, deleteCount); + return { + data, + totalCount: OPTIONS.length, + }; +}; + +const defaultProps = { + allowClear: true, + ariaLabel: ARIA_LABEL, + labelInValue: true, + options: loadOptions, + pageSize: 10, + showSearch: true, +}; + +const getElementByClassName = (className: string) => + document.querySelector(className)! as HTMLElement; + +const getElementsByClassName = (className: string) => + document.querySelectorAll(className)! as NodeListOf<HTMLElement>; + +const getSelect = () => screen.getByRole('combobox', { name: ARIA_LABEL }); + +const findSelectOption = (text: string) => + waitFor(() => + within(getElementByClassName('.rc-virtual-list')).getByText(text), + ); + +const querySelectOption = (text: string) => + waitFor(() => + within(getElementByClassName('.rc-virtual-list')).queryByText(text), + ); + +const findAllSelectOptions = () => + waitFor(() => getElementsByClassName('.ant-select-item-option-content')); + +const findSelectValue = () => + waitFor(() => getElementByClassName('.ant-select-selection-item')); + +const findAllSelectValues = () => + waitFor(() => getElementsByClassName('.ant-select-selection-item')); + +const clearAll = () => userEvent.click(screen.getByLabelText('close-circle')); + +const matchOrder = async (expectedLabels: string[]) => { + const actualLabels: string[] = []; + (await findAllSelectOptions()).forEach(option => { + actualLabels.push(option.textContent || ''); + }); + // menu is a virtual list, which means it may not render all options + expect(actualLabels.slice(0, expectedLabels.length)).toEqual( + expectedLabels.slice(0, actualLabels.length), + ); + return true; +}; + +const type = (text: string) => { + const select = getSelect(); + userEvent.clear(select); + return userEvent.type(select, text, { delay: 10 }); +}; + +const open = () => waitFor(() => userEvent.click(getSelect())); + +test('displays a header', async () => { + const headerText = 'Header'; + render(<AsyncSelect {...defaultProps} header={headerText} />); + expect(screen.getByText(headerText)).toBeInTheDocument(); +}); + +test('adds a new option if the value is not in the options, when options are empty', async () => { + const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 })); + render( + <AsyncSelect {...defaultProps} options={loadOptions} value={OPTIONS[0]} />, + ); + await open(); + expect(await findSelectOption(OPTIONS[0].label)).toBeInTheDocument(); + const options = await findAllSelectOptions(); + expect(options).toHaveLength(1); + options.forEach((option, i) => + expect(option).toHaveTextContent(OPTIONS[i].label), + ); +}); + +test('adds a new option if the value is not in the options, when options have values', async () => { + const loadOptions = jest.fn(async () => ({ + data: [OPTIONS[1]], + totalCount: 1, + })); + render( + <AsyncSelect {...defaultProps} options={loadOptions} value={OPTIONS[0]} />, + ); + await open(); + expect(await findSelectOption(OPTIONS[0].label)).toBeInTheDocument(); + expect(await findSelectOption(OPTIONS[1].label)).toBeInTheDocument(); + const options = await findAllSelectOptions(); + expect(options).toHaveLength(2); + options.forEach((option, i) => + expect(option).toHaveTextContent(OPTIONS[i].label), + ); +}); + +test('does not add a new option if the value is already in the options', async () => { + const loadOptions = jest.fn(async () => ({ + data: [OPTIONS[0]], + totalCount: 1, + })); + render( + <AsyncSelect {...defaultProps} options={loadOptions} value={OPTIONS[0]} />, + ); + await open(); + expect(await findSelectOption(OPTIONS[0].label)).toBeInTheDocument(); + const options = await findAllSelectOptions(); + expect(options).toHaveLength(1); +}); + +test('inverts the selection', async () => { + render(<AsyncSelect {...defaultProps} invertSelection />); + await open(); + userEvent.click(await findSelectOption(OPTIONS[0].label)); + expect(await screen.findByLabelText('stop')).toBeInTheDocument(); +}); + +test('sort the options by label if no sort comparator is provided', async () => { + const loadUnsortedOptions = jest.fn(async () => ({ + data: [...OPTIONS].sort(() => Math.random()), + totalCount: 2, + })); + render(<AsyncSelect {...defaultProps} options={loadUnsortedOptions} />); + await open(); + const options = await findAllSelectOptions(); + options.forEach((option, key) => + expect(option).toHaveTextContent(OPTIONS[key].label), + ); +}); + +test('sort the options using a custom sort comparator', async () => { + const sortComparator = ( + option1: typeof OPTIONS[0], + option2: typeof OPTIONS[0], + ) => option1.gender.localeCompare(option2.gender); + render(<AsyncSelect {...defaultProps} sortComparator={sortComparator} />); + await open(); + const options = await findAllSelectOptions(); + const optionsPage = OPTIONS.slice(0, defaultProps.pageSize); + const sortedOptions = optionsPage.sort(sortComparator); + options.forEach((option, key) => { + expect(option).toHaveTextContent(sortedOptions[key].label); + }); +}); + +test('should sort selected to top when in single mode', async () => { + render(<AsyncSelect {...defaultProps} mode="single" />); + const originalLabels = OPTIONS.map(option => option.label); + await open(); + userEvent.click(await findSelectOption(originalLabels[1])); + // after selection, keep the original order + expect(await matchOrder(originalLabels)).toBe(true); + + // order selected to top when reopen + await type('{esc}'); + await open(); + let labels = originalLabels.slice(); + labels = labels.splice(1, 1).concat(labels); + expect(await matchOrder(labels)).toBe(true); + + // keep clicking other items, the updated order should still based on + // original order + userEvent.click(await findSelectOption(originalLabels[5])); + await matchOrder(labels); + await type('{esc}'); + await open(); + labels = originalLabels.slice(); + labels = labels.splice(5, 1).concat(labels); + expect(await matchOrder(labels)).toBe(true); + + // should revert to original order + clearAll(); + await type('{esc}'); + await open(); + expect(await matchOrder(originalLabels)).toBe(true); +}); + +test('should sort selected to the top when in multi mode', async () => { + render(<AsyncSelect {...defaultProps} mode="multiple" />); + const originalLabels = OPTIONS.map(option => option.label); + let labels = originalLabels.slice(); + + await open(); + userEvent.click(await findSelectOption(labels[1])); + expect(await matchOrder(labels)).toBe(true); + + await type('{esc}'); + await open(); + labels = labels.splice(1, 1).concat(labels); + expect(await matchOrder(labels)).toBe(true); + + await open(); + userEvent.click(await findSelectOption(labels[5])); + await type('{esc}'); + await open(); + labels = [labels.splice(0, 1)[0], labels.splice(4, 1)[0]].concat(labels); + expect(await matchOrder(labels)).toBe(true); + + // should revert to original order + clearAll(); + await type('{esc}'); + await open(); + expect(await matchOrder(originalLabels)).toBe(true); +}); + +test('searches for label or value', async () => { + const option = OPTIONS[11]; + render(<AsyncSelect {...defaultProps} />); + const search = option.value; + await type(search.toString()); + expect(await findSelectOption(option.label)).toBeInTheDocument(); + const options = await findAllSelectOptions(); + expect(options.length).toBe(1); + expect(options[0]).toHaveTextContent(option.label); +}); + +test('search order exact and startWith match first', async () => { + render(<AsyncSelect {...defaultProps} />); + await open(); + await type('Her'); + expect(await findSelectOption('Guilherme')).toBeInTheDocument(); + const options = await findAllSelectOptions(); + expect(options.length).toBe(4); + expect(options[0]).toHaveTextContent('Her'); + expect(options[1]).toHaveTextContent('Herme'); + expect(options[2]).toHaveTextContent('Cher'); + expect(options[3]).toHaveTextContent('Guilherme'); +}); + +test('ignores case when searching', async () => { + render(<AsyncSelect {...defaultProps} />); + await type('george'); + expect(await findSelectOption('George')).toBeInTheDocument(); +}); + +test('same case should be ranked to the top', async () => { + const loadOptions = jest.fn(async () => ({ + data: [ + { value: 'Cac' }, + { value: 'abac' }, + { value: 'acbc' }, + { value: 'CAc' }, + ], + totalCount: 4, + })); + render(<AsyncSelect {...defaultProps} options={loadOptions} />); + await type('Ac'); + const options = await findAllSelectOptions(); + expect(options.length).toBe(4); + expect(options[0]?.textContent).toEqual('acbc'); + expect(options[1]?.textContent).toEqual('CAc'); + expect(options[2]?.textContent).toEqual('abac'); + expect(options[3]?.textContent).toEqual('Cac'); +}); + +test('ignores special keys when searching', async () => { + render(<AsyncSelect {...defaultProps} />); + await type('{shift}'); + expect(screen.queryByText(LOADING)).not.toBeInTheDocument(); +}); + +test('searches for custom fields', async () => { + render( + <AsyncSelect {...defaultProps} optionFilterProps={['label', 'gender']} />, + ); + await open(); + await type('Liam'); + // Liam is on the second page. need to wait to fetch options + expect(await findSelectOption('Liam')).toBeInTheDocument(); + let options = await findAllSelectOptions(); + expect(options.length).toBe(1); + expect(options[0]).toHaveTextContent('Liam'); + await type('Female'); + // Olivia is on the second page. need to wait to fetch options + expect(await findSelectOption('Olivia')).toBeInTheDocument(); + options = await findAllSelectOptions(); + expect(options.length).toBe(6); + expect(options[0]).toHaveTextContent('Ava'); + expect(options[1]).toHaveTextContent('Charlotte'); + expect(options[2]).toHaveTextContent('Cher'); + expect(options[3]).toHaveTextContent('Emma'); + expect(options[4]).toHaveTextContent('Nikole'); + expect(options[5]).toHaveTextContent('Olivia'); + await type('1'); + expect(await screen.findByText(NO_DATA)).toBeInTheDocument(); +}); + +test('removes duplicated values', async () => { + render(<AsyncSelect {...defaultProps} mode="multiple" allowNewOptions />); + await type('a,b,b,b,c,d,d'); + const values = await findAllSelectValues(); + expect(values.length).toBe(4); + expect(values[0]).toHaveTextContent('a'); + expect(values[1]).toHaveTextContent('b'); + expect(values[2]).toHaveTextContent('c'); + expect(values[3]).toHaveTextContent('d'); +}); + +test('renders a custom label', async () => { + const loadOptions = jest.fn(async () => ({ + data: [ + { label: 'John', value: 1, customLabel: <h1>John</h1> }, + { label: 'Liam', value: 2, customLabel: <h1>Liam</h1> }, + { label: 'Olivia', value: 3, customLabel: <h1>Olivia</h1> }, + ], + totalCount: 3, + })); + render(<AsyncSelect {...defaultProps} options={loadOptions} />); + await open(); + expect(screen.getByRole('heading', { name: 'John' })).toBeInTheDocument(); + expect(screen.getByRole('heading', { name: 'Liam' })).toBeInTheDocument(); + expect(screen.getByRole('heading', { name: 'Olivia' })).toBeInTheDocument(); +}); + +test('searches for a word with a custom label', async () => { + const loadOptions = jest.fn(async () => ({ + data: [ + { label: 'John', value: 1, customLabel: <h1>John</h1> }, + { label: 'Liam', value: 2, customLabel: <h1>Liam</h1> }, + { label: 'Olivia', value: 3, customLabel: <h1>Olivia</h1> }, + ], + totalCount: 3, + })); + render(<AsyncSelect {...defaultProps} options={loadOptions} />); + await type('Liam'); + const selectOptions = await findAllSelectOptions(); + expect(selectOptions.length).toBe(1); + expect(selectOptions[0]).toHaveTextContent('Liam'); +}); + +test('removes a new option if the user does not select it', async () => { + render(<AsyncSelect {...defaultProps} allowNewOptions />); + await type(NEW_OPTION); + expect(await findSelectOption(NEW_OPTION)).toBeInTheDocument(); + await type('k'); + await waitFor(() => + expect(screen.queryByText(NEW_OPTION)).not.toBeInTheDocument(), + ); +}); + +test('clear all the values', async () => { + const onClear = jest.fn(); + render( + <AsyncSelect + {...defaultProps} + mode="multiple" + value={[OPTIONS[0], OPTIONS[1]]} + onClear={onClear} + />, + ); + clearAll(); + expect(onClear).toHaveBeenCalled(); + const values = await findAllSelectValues(); + expect(values.length).toBe(0); +}); + +test('does not add a new option if allowNewOptions is false', async () => { + render(<AsyncSelect {...defaultProps} />); + await open(); + await type(NEW_OPTION); + expect(await screen.findByText(NO_DATA)).toBeInTheDocument(); +}); + +test('adds the null option when selected in single mode', async () => { + const loadOptions = jest.fn(async () => ({ + data: [OPTIONS[0], NULL_OPTION], + totalCount: 2, + })); + render(<AsyncSelect {...defaultProps} options={loadOptions} />); + await open(); + userEvent.click(await findSelectOption(NULL_OPTION.label)); + const values = await findAllSelectValues(); + expect(values[0]).toHaveTextContent(NULL_OPTION.label); +}); + +test('adds the null option when selected in multiple mode', async () => { + const loadOptions = jest.fn(async () => ({ + data: [OPTIONS[0], NULL_OPTION], + totalCount: 2, + })); + render( + <AsyncSelect {...defaultProps} options={loadOptions} mode="multiple" />, + ); + await open(); + userEvent.click(await findSelectOption(OPTIONS[0].label)); + userEvent.click(await findSelectOption(NULL_OPTION.label)); + const values = await findAllSelectValues(); + expect(values[0]).toHaveTextContent(OPTIONS[0].label); + expect(values[1]).toHaveTextContent(NULL_OPTION.label); +}); + +test('renders the select with default props', () => { + render(<AsyncSelect {...defaultProps} />); + expect(getSelect()).toBeInTheDocument(); +}); + +test('opens the select without any data', async () => { + render( + <AsyncSelect + {...defaultProps} + options={async () => ({ data: [], totalCount: 0 })} + />, + ); + await open(); + expect(await screen.findByText(/no data/i)).toBeInTheDocument(); +}); + +test('displays the loading indicator when opening', async () => { + render(<AsyncSelect {...defaultProps} />); + await waitFor(() => { + userEvent.click(getSelect()); + expect(screen.getByText(LOADING)).toBeInTheDocument(); + }); + expect(screen.queryByText(LOADING)).not.toBeInTheDocument(); +}); + +test('makes a selection in single mode', async () => { + render(<AsyncSelect {...defaultProps} />); + const optionText = 'Emma'; + await open(); + userEvent.click(await findSelectOption(optionText)); + expect(await findSelectValue()).toHaveTextContent(optionText); +}); + +test('multiple selections in multiple mode', async () => { + render(<AsyncSelect {...defaultProps} mode="multiple" />); + await open(); + const [firstOption, secondOption] = OPTIONS; + userEvent.click(await findSelectOption(firstOption.label)); + userEvent.click(await findSelectOption(secondOption.label)); + const values = await findAllSelectValues(); + expect(values[0]).toHaveTextContent(firstOption.label); + expect(values[1]).toHaveTextContent(secondOption.label); +}); + +test('changes the selected item in single mode', async () => { + const onChange = jest.fn(); + render(<AsyncSelect {...defaultProps} onChange={onChange} />); + await open(); + const [firstOption, secondOption] = OPTIONS; + userEvent.click(await findSelectOption(firstOption.label)); + expect(onChange).toHaveBeenCalledWith( + expect.objectContaining({ + label: firstOption.label, + value: firstOption.value, + }), + firstOption, + ); + expect(await findSelectValue()).toHaveTextContent(firstOption.label); + userEvent.click(await findSelectOption(secondOption.label)); + expect(onChange).toHaveBeenCalledWith( + expect.objectContaining({ + label: secondOption.label, + value: secondOption.value, + }), + secondOption, + ); + expect(await findSelectValue()).toHaveTextContent(secondOption.label); +}); + +test('deselects an item in multiple mode', async () => { + render(<AsyncSelect {...defaultProps} mode="multiple" />); + await open(); + const option3 = OPTIONS[2]; + const option8 = OPTIONS[7]; + userEvent.click(await findSelectOption(option8.label)); + userEvent.click(await findSelectOption(option3.label)); + + let options = await findAllSelectOptions(); + expect(options).toHaveLength(Math.min(defaultProps.pageSize, OPTIONS.length)); + expect(options[0]).toHaveTextContent(OPTIONS[0].label); + expect(options[1]).toHaveTextContent(OPTIONS[1].label); + + await type('{esc}'); + await open(); + + // should rank selected options to the top after menu closes + options = await findAllSelectOptions(); + expect(options).toHaveLength(Math.min(defaultProps.pageSize, OPTIONS.length)); + expect(options[0]).toHaveTextContent(option3.label); + expect(options[1]).toHaveTextContent(option8.label); + + let values = await findAllSelectValues(); + expect(values).toHaveLength(2); + // should keep the order by which the options were selected + expect(values[0]).toHaveTextContent(option8.label); + expect(values[1]).toHaveTextContent(option3.label); + + userEvent.click(await findSelectOption(option3.label)); + values = await findAllSelectValues(); + expect(values.length).toBe(1); + expect(values[0]).toHaveTextContent(option8.label); +}); + +test('adds a new option if none is available and allowNewOptions is true', async () => { + render(<AsyncSelect {...defaultProps} allowNewOptions />); + await open(); + await type(NEW_OPTION); + expect(await findSelectOption(NEW_OPTION)).toBeInTheDocument(); +}); + +test('does not add a new option if the option already exists', async () => { + render(<AsyncSelect {...defaultProps} allowNewOptions />); + const option = OPTIONS[0].label; + await open(); + await type(option); + await waitFor(() => { + const array = within( + getElementByClassName('.rc-virtual-list'), + ).getAllByText(option); + expect(array.length).toBe(1); + }); +}); + +test('shows "No data" when allowNewOptions is false and a new option is entered', async () => { + render(<AsyncSelect {...defaultProps} allowNewOptions={false} showSearch />); + await open(); + await type(NEW_OPTION); + expect(await screen.findByText(NO_DATA)).toBeInTheDocument(); +}); + +test('does not show "No data" when allowNewOptions is true and a new option is entered', async () => { + render(<AsyncSelect {...defaultProps} allowNewOptions />); + await open(); + await type(NEW_OPTION); + expect(screen.queryByText(NO_DATA)).not.toBeInTheDocument(); +}); + +test('sets a initial value in single mode', async () => { + render(<AsyncSelect {...defaultProps} value={OPTIONS[0]} />); + expect(await findSelectValue()).toHaveTextContent(OPTIONS[0].label); +}); + +test('sets a initial value in multiple mode', async () => { + render( + <AsyncSelect + {...defaultProps} + mode="multiple" + value={[OPTIONS[0], OPTIONS[1]]} + />, + ); + const values = await findAllSelectValues(); + expect(values[0]).toHaveTextContent(OPTIONS[0].label); + expect(values[1]).toHaveTextContent(OPTIONS[1].label); +}); + +test('searches for matches in both loaded and unloaded pages', async () => { + render(<AsyncSelect {...defaultProps} />); + await open(); + await type('and'); + + let options = await findAllSelectOptions(); + expect(options.length).toBe(1); + expect(options[0]).toHaveTextContent('Alehandro'); + + await screen.findByText('Sandro'); + options = await findAllSelectOptions(); + expect(options.length).toBe(2); + expect(options[0]).toHaveTextContent('Alehandro'); + expect(options[1]).toHaveTextContent('Sandro'); +}); + +test('searches for an item in a page not loaded', async () => { + const mock = jest.fn(loadOptions); + render(<AsyncSelect {...defaultProps} options={mock} />); + const search = 'Sandro'; + await open(); + await type(search); + await waitFor(() => expect(mock).toHaveBeenCalledTimes(2)); + const options = await findAllSelectOptions(); + expect(options.length).toBe(1); + expect(options[0]).toHaveTextContent(search); +}); + +test('does not fetches data when rendering', async () => { + const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 })); + render(<AsyncSelect {...defaultProps} options={loadOptions} />); + expect(loadOptions).not.toHaveBeenCalled(); +}); + +test('fetches data when opening', async () => { + const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 })); + render(<AsyncSelect {...defaultProps} options={loadOptions} />); + await open(); + expect(loadOptions).toHaveBeenCalled(); +}); + +test('fetches data only after a search input is entered if fetchOnlyOnSearch is true', async () => { + const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 })); + render( + <AsyncSelect {...defaultProps} options={loadOptions} fetchOnlyOnSearch />, + ); + await open(); + await waitFor(() => expect(loadOptions).not.toHaveBeenCalled()); + await type('search'); + await waitFor(() => expect(loadOptions).toHaveBeenCalled()); +}); + +test('displays an error message when an exception is thrown while fetching', async () => { + const error = 'Fetch error'; + const loadOptions = async () => { + throw new Error(error); + }; + render(<AsyncSelect {...defaultProps} options={loadOptions} />); + await open(); + expect(screen.getByText(error)).toBeInTheDocument(); +}); + +test('does not fire a new request for the same search input', async () => { + const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 })); + render( + <AsyncSelect {...defaultProps} options={loadOptions} fetchOnlyOnSearch />, + ); + await type('search'); + expect(await screen.findByText(NO_DATA)).toBeInTheDocument(); + expect(loadOptions).toHaveBeenCalledTimes(1); + clearAll(); + await type('search'); + expect(await screen.findByText(LOADING)).toBeInTheDocument(); + expect(loadOptions).toHaveBeenCalledTimes(1); +}); + +test('does not fire a new request if all values have been fetched', async () => { + const mock = jest.fn(loadOptions); + const search = 'George'; + const pageSize = OPTIONS.length; + render(<AsyncSelect {...defaultProps} options={mock} pageSize={pageSize} />); + await open(); + expect(mock).toHaveBeenCalledTimes(1); + await type(search); + expect(await findSelectOption(search)).toBeInTheDocument(); + expect(mock).toHaveBeenCalledTimes(1); +}); + +test('fires a new request if all values have not been fetched', async () => { + const mock = jest.fn(loadOptions); + const pageSize = OPTIONS.length / 2; + render(<AsyncSelect {...defaultProps} options={mock} pageSize={pageSize} />); + await open(); + expect(mock).toHaveBeenCalledTimes(1); + await type('or'); + + // `George` is on the first page so when it appears the API has not been called again + expect(await findSelectOption('George')).toBeInTheDocument(); + expect(mock).toHaveBeenCalledTimes(1); + + // `Igor` is on the second paged API request + expect(await findSelectOption('Igor')).toBeInTheDocument(); + expect(mock).toHaveBeenCalledTimes(2); +}); + +test('does not render a helper text by default', async () => { + render(<AsyncSelect {...defaultProps} />); + await open(); + expect(screen.queryByRole('note')).not.toBeInTheDocument(); +}); + +test('renders a helper text when one is provided', async () => { + const helperText = 'Helper text'; + render(<AsyncSelect {...defaultProps} helperText={helperText} />); + await open(); + expect(screen.getByRole('note')).toBeInTheDocument(); + expect(screen.queryByText(helperText)).toBeInTheDocument(); +}); + +test('finds an element with a numeric value and does not duplicate the options', async () => { + const options = jest.fn(async () => ({ + data: [ + { label: 'a', value: 11 }, + { label: 'b', value: 12 }, + ], + totalCount: 2, + })); + render(<AsyncSelect {...defaultProps} options={options} allowNewOptions />); + await open(); + await type('11'); + expect(await findSelectOption('a')).toBeInTheDocument(); + expect(await querySelectOption('11')).not.toBeInTheDocument(); +}); + +test('Renders only 1 tag and an overflow tag in oneLine mode', () => { + render( + <AsyncSelect + {...defaultProps} + value={[OPTIONS[0], OPTIONS[1], OPTIONS[2]]} + mode="multiple" + oneLine + />, + ); + expect(screen.getByText(OPTIONS[0].label)).toBeVisible(); + expect(screen.queryByText(OPTIONS[1].label)).not.toBeInTheDocument(); + expect(screen.queryByText(OPTIONS[2].label)).not.toBeInTheDocument(); + expect(screen.getByText('+ 2 ...')).toBeVisible(); +}); + +test('Renders only an overflow tag if dropdown is open in oneLine mode', async () => { + render( + <AsyncSelect + {...defaultProps} + value={[OPTIONS[0], OPTIONS[1], OPTIONS[2]]} + mode="multiple" + oneLine + />, + ); + await open(); + + const withinSelector = within(getElementByClassName('.ant-select-selector')); + await waitFor(() => { + expect( + withinSelector.queryByText(OPTIONS[0].label), + ).not.toBeInTheDocument(); + expect( + withinSelector.queryByText(OPTIONS[1].label), + ).not.toBeInTheDocument(); + expect( + withinSelector.queryByText(OPTIONS[2].label), + ).not.toBeInTheDocument(); + expect(withinSelector.getByText('+ 3 ...')).toBeVisible(); + }); + + await type('{esc}'); + + expect(await withinSelector.findByText(OPTIONS[0].label)).toBeVisible(); + expect(withinSelector.queryByText(OPTIONS[1].label)).not.toBeInTheDocument(); + expect(withinSelector.queryByText(OPTIONS[2].label)).not.toBeInTheDocument(); + expect(withinSelector.getByText('+ 2 ...')).toBeVisible(); +}); + +/* + TODO: Add tests that require scroll interaction. Needs further investigation. + - Fetches more data when scrolling and more data is available + - Doesn't fetch more data when no more data is available + - Requests the correct page and page size + - Sets the page to zero when a new search is made + */ diff --git a/superset-frontend/src/components/Select/AsyncSelect.tsx b/superset-frontend/src/components/Select/AsyncSelect.tsx new file mode 100644 index 0000000000000..00c1443c56e21 --- /dev/null +++ b/superset-frontend/src/components/Select/AsyncSelect.tsx @@ -0,0 +1,532 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { + forwardRef, + ReactElement, + RefObject, + UIEvent, + useEffect, + useMemo, + useState, + useRef, + useCallback, + useImperativeHandle, +} from 'react'; +import { ensureIsArray, t } from '@superset-ui/core'; +import { LabeledValue as AntdLabeledValue } from 'antd/lib/select'; +import debounce from 'lodash/debounce'; +import { isEqual } from 'lodash'; +import Icons from 'src/components/Icons'; +import { getClientErrorObject } from 'src/utils/getClientErrorObject'; +import { SLOW_DEBOUNCE } from 'src/constants'; +import { + getValue, + hasOption, + isLabeledValue, + renderSelectOptions, + hasCustomLabels, + sortSelectedFirstHelper, + sortComparatorWithSearchHelper, + sortComparatorForNoSearchHelper, + getSuffixIcon, + dropDownRenderHelper, + handleFilterOptionHelper, +} from './utils'; +import { + AsyncSelectProps, + AsyncSelectRef, + SelectOptionsPagePromise, + SelectOptionsType, + SelectOptionsTypePage, +} from './types'; +import { + StyledCheckOutlined, + StyledContainer, + StyledError, + StyledErrorMessage, + StyledHeader, + StyledSelect, + StyledStopOutlined, +} from './styles'; +import { + DEFAULT_PAGE_SIZE, + EMPTY_OPTIONS, + MAX_TAG_COUNT, + TOKEN_SEPARATORS, + DEFAULT_SORT_COMPARATOR, +} from './constants'; +import { customTagRender } from './CustomTag'; + +const Error = ({ error }: { error: string }) => ( + <StyledError> + <Icons.ErrorSolid /> <StyledErrorMessage>{error}</StyledErrorMessage> + </StyledError> +); + +const getQueryCacheKey = (value: string, page: number, pageSize: number) => + `${value};${page};${pageSize}`; + +/** + * This component is a customized version of the Antdesign 4.X Select component + * https://ant.design/components/select/. + * The aim of the component was to combine all the instances of select components throughout the + * project under one and to remove the react-select component entirely. + * This Select component provides an API that is tested against all the different use cases of Superset. + * It limits and overrides the existing Antdesign API in order to keep their usage to the minimum + * and to enforce simplification and standardization. + * It is divided into two macro categories, Static and Async. + * The Static type accepts a static array of options. + * The Async type accepts a promise that will return the options. + * Each of the categories come with different abilities. For a comprehensive guide please refer to + * the storybook in src/components/Select/Select.stories.tsx. + */ +const AsyncSelect = forwardRef( + ( + { + allowClear, + allowNewOptions = false, + ariaLabel, + fetchOnlyOnSearch, + filterOption = true, + header = null, + headerPosition = 'top', + helperText, + invertSelection = false, + lazyLoading = true, + loading, + mode = 'single', + name, + notFoundContent, + onError, + onChange, + onClear, + onDropdownVisibleChange, + optionFilterProps = ['label', 'value'], + options, + pageSize = DEFAULT_PAGE_SIZE, + placeholder = t('Select ...'), + showSearch = true, + sortComparator = DEFAULT_SORT_COMPARATOR, + tokenSeparators, + value, + getPopupContainer, + oneLine, + maxTagCount: propsMaxTagCount, + ...props + }: AsyncSelectProps, + ref: RefObject<AsyncSelectRef>, + ) => { + const isSingleMode = mode === 'single'; + const [selectValue, setSelectValue] = useState(value); + const [inputValue, setInputValue] = useState(''); + const [isLoading, setIsLoading] = useState(loading); + const [error, setError] = useState(''); + const [isDropdownVisible, setIsDropdownVisible] = useState(false); + const [page, setPage] = useState(0); + const [totalCount, setTotalCount] = useState(0); + const [loadingEnabled, setLoadingEnabled] = useState(!lazyLoading); + const [allValuesLoaded, setAllValuesLoaded] = useState(false); + const selectValueRef = useRef(selectValue); + const fetchedQueries = useRef(new Map<string, number>()); + const mappedMode = isSingleMode + ? undefined + : allowNewOptions + ? 'tags' + : 'multiple'; + const allowFetch = !fetchOnlyOnSearch || inputValue; + + const [maxTagCount, setMaxTagCount] = useState( + propsMaxTagCount ?? MAX_TAG_COUNT, + ); + + useEffect(() => { + if (oneLine) { + setMaxTagCount(isDropdownVisible ? 0 : 1); + } + }, [isDropdownVisible, oneLine]); + + useEffect(() => { + selectValueRef.current = selectValue; + }, [selectValue]); + + const sortSelectedFirst = useCallback( + (a: AntdLabeledValue, b: AntdLabeledValue) => + sortSelectedFirstHelper(a, b, selectValueRef.current), + [], + ); + + const sortComparatorWithSearch = useCallback( + (a: AntdLabeledValue, b: AntdLabeledValue) => + sortComparatorWithSearchHelper( + a, + b, + inputValue, + sortSelectedFirst, + sortComparator, + ), + [inputValue, sortComparator, sortSelectedFirst], + ); + + const sortComparatorForNoSearch = useCallback( + (a: AntdLabeledValue, b: AntdLabeledValue) => + sortComparatorForNoSearchHelper( + a, + b, + sortSelectedFirst, + sortComparator, + ), + [sortComparator, sortSelectedFirst], + ); + + const [selectOptions, setSelectOptions] = + useState<SelectOptionsType>(EMPTY_OPTIONS); + + // add selected values to options list if they are not in it + const fullSelectOptions = useMemo(() => { + const missingValues: SelectOptionsType = ensureIsArray(selectValue) + .filter(opt => !hasOption(getValue(opt), selectOptions)) + .map(opt => + isLabeledValue(opt) ? opt : { value: opt, label: String(opt) }, + ); + return missingValues.length > 0 + ? missingValues.concat(selectOptions) + : selectOptions; + }, [selectOptions, selectValue]); + + const handleOnSelect = ( + selectedItem: string | number | AntdLabeledValue | undefined, + ) => { + if (isSingleMode) { + setSelectValue(selectedItem); + } else { + setSelectValue(previousState => { + const array = ensureIsArray(previousState); + const value = getValue(selectedItem); + // Tokenized values can contain duplicated values + if (!hasOption(value, array)) { + const result = [...array, selectedItem]; + return isLabeledValue(selectedItem) + ? (result as AntdLabeledValue[]) + : (result as (string | number)[]); + } + return previousState; + }); + } + setInputValue(''); + }; + + const handleOnDeselect = ( + value: string | number | AntdLabeledValue | undefined, + ) => { + if (Array.isArray(selectValue)) { + if (isLabeledValue(value)) { + const array = selectValue as AntdLabeledValue[]; + setSelectValue( + array.filter(element => element.value !== value.value), + ); + } else { + const array = selectValue as (string | number)[]; + setSelectValue(array.filter(element => element !== value)); + } + } + setInputValue(''); + }; + + const internalOnError = useCallback( + (response: Response) => + getClientErrorObject(response).then(e => { + const { error } = e; + setError(error); + + if (onError) { + onError(error); + } + }), + [onError], + ); + + const mergeData = useCallback( + (data: SelectOptionsType) => { + let mergedData: SelectOptionsType = []; + if (data && Array.isArray(data) && data.length) { + // unique option values should always be case sensitive so don't lowercase + const dataValues = new Set(data.map(opt => opt.value)); + // merges with existing and creates unique options + setSelectOptions(prevOptions => { + mergedData = prevOptions + .filter(previousOption => !dataValues.has(previousOption.value)) + .concat(data) + .sort(sortComparatorForNoSearch); + return mergedData; + }); + } + return mergedData; + }, + [sortComparatorForNoSearch], + ); + + const fetchPage = useMemo( + () => (search: string, page: number) => { + setPage(page); + if (allValuesLoaded) { + setIsLoading(false); + return; + } + const key = getQueryCacheKey(search, page, pageSize); + const cachedCount = fetchedQueries.current.get(key); + if (cachedCount !== undefined) { + setTotalCount(cachedCount); + setIsLoading(false); + return; + } + setIsLoading(true); + + const fetchOptions = options as SelectOptionsPagePromise; + fetchOptions(search, page, pageSize) + .then(({ data, totalCount }: SelectOptionsTypePage) => { + const mergedData = mergeData(data); + fetchedQueries.current.set(key, totalCount); + setTotalCount(totalCount); + if ( + !fetchOnlyOnSearch && + search === '' && + mergedData.length >= totalCount + ) { + setAllValuesLoaded(true); + } + }) + .catch(internalOnError) + .finally(() => { + setIsLoading(false); + }); + }, + [ + allValuesLoaded, + fetchOnlyOnSearch, + mergeData, + internalOnError, + options, + pageSize, + ], + ); + + const debouncedFetchPage = useMemo( + () => debounce(fetchPage, SLOW_DEBOUNCE), + [fetchPage], + ); + + const handleOnSearch = (search: string) => { + const searchValue = search.trim(); + if (allowNewOptions && isSingleMode) { + const newOption = searchValue && + !hasOption(searchValue, fullSelectOptions, true) && { + label: searchValue, + value: searchValue, + isNewOption: true, + }; + const cleanSelectOptions = fullSelectOptions.filter( + opt => !opt.isNewOption || hasOption(opt.value, selectValue), + ); + const newOptions = newOption + ? [newOption, ...cleanSelectOptions] + : cleanSelectOptions; + setSelectOptions(newOptions); + } + if ( + !allValuesLoaded && + loadingEnabled && + !fetchedQueries.current.has(getQueryCacheKey(searchValue, 0, pageSize)) + ) { + // if fetch only on search but search value is empty, then should not be + // in loading state + setIsLoading(!(fetchOnlyOnSearch && !searchValue)); + } + setInputValue(search); + }; + + const handlePagination = (e: UIEvent<HTMLElement>) => { + const vScroll = e.currentTarget; + const thresholdReached = + vScroll.scrollTop > (vScroll.scrollHeight - vScroll.offsetHeight) * 0.7; + const hasMoreData = page * pageSize + pageSize < totalCount; + + if (!isLoading && hasMoreData && thresholdReached) { + const newPage = page + 1; + fetchPage(inputValue, newPage); + } + }; + + const handleFilterOption = (search: string, option: AntdLabeledValue) => + handleFilterOptionHelper(search, option, optionFilterProps, filterOption); + + const handleOnDropdownVisibleChange = (isDropdownVisible: boolean) => { + setIsDropdownVisible(isDropdownVisible); + + // loading is enabled when dropdown is open, + // disabled when dropdown is closed + if (loadingEnabled !== isDropdownVisible) { + setLoadingEnabled(isDropdownVisible); + } + // when closing dropdown, always reset loading state + if (!isDropdownVisible && isLoading) { + // delay is for the animation of closing the dropdown + // so the dropdown doesn't flash between "Loading..." and "No data" + // before closing. + setTimeout(() => { + setIsLoading(false); + }, 250); + } + // if no search input value, force sort options because it won't be sorted by + // `filterSort`. + if (isDropdownVisible && !inputValue && selectOptions.length > 1) { + const sortedOptions = selectOptions + .slice() + .sort(sortComparatorForNoSearch); + if (!isEqual(sortedOptions, selectOptions)) { + setSelectOptions(sortedOptions); + } + } + + if (onDropdownVisibleChange) { + onDropdownVisibleChange(isDropdownVisible); + } + }; + + const dropdownRender = ( + originNode: ReactElement & { ref?: RefObject<HTMLElement> }, + ) => + dropDownRenderHelper( + originNode, + isDropdownVisible, + isLoading, + fullSelectOptions.length, + helperText, + error ? <Error error={error} /> : undefined, + ); + + const handleClear = () => { + setSelectValue(undefined); + if (onClear) { + onClear(); + } + }; + + useEffect(() => { + // when `options` list is updated from component prop, reset states + fetchedQueries.current.clear(); + setAllValuesLoaded(false); + setSelectOptions(EMPTY_OPTIONS); + }, [options]); + + useEffect(() => { + setSelectValue(value); + }, [value]); + + // Stop the invocation of the debounced function after unmounting + useEffect( + () => () => { + debouncedFetchPage.cancel(); + }, + [debouncedFetchPage], + ); + + useEffect(() => { + if (loadingEnabled && allowFetch) { + // trigger fetch every time inputValue changes + if (inputValue) { + debouncedFetchPage(inputValue, 0); + } else { + fetchPage('', 0); + } + } + }, [loadingEnabled, fetchPage, allowFetch, inputValue, debouncedFetchPage]); + + useEffect(() => { + if (loading !== undefined && loading !== isLoading) { + setIsLoading(loading); + } + }, [isLoading, loading]); + + const clearCache = () => fetchedQueries.current.clear(); + + useImperativeHandle( + ref, + () => ({ + ...(ref.current as HTMLInputElement), + clearCache, + }), + [ref], + ); + + return ( + <StyledContainer headerPosition={headerPosition}> + {header && ( + <StyledHeader headerPosition={headerPosition}>{header}</StyledHeader> + )} + <StyledSelect + allowClear={!isLoading && allowClear} + aria-label={ariaLabel || name} + dropdownRender={dropdownRender} + filterOption={handleFilterOption} + filterSort={sortComparatorWithSearch} + getPopupContainer={ + getPopupContainer || (triggerNode => triggerNode.parentNode) + } + headerPosition={headerPosition} + labelInValue + maxTagCount={maxTagCount} + mode={mappedMode} + notFoundContent={isLoading ? t('Loading...') : notFoundContent} + onDeselect={handleOnDeselect} + onDropdownVisibleChange={handleOnDropdownVisibleChange} + onPopupScroll={handlePagination} + onSearch={showSearch ? handleOnSearch : undefined} + onSelect={handleOnSelect} + onClear={handleClear} + onChange={onChange} + options={ + hasCustomLabels(fullSelectOptions) ? undefined : fullSelectOptions + } + placeholder={placeholder} + showSearch={showSearch} + showArrow + tokenSeparators={tokenSeparators || TOKEN_SEPARATORS} + value={selectValue} + suffixIcon={getSuffixIcon(isLoading, showSearch, isDropdownVisible)} + menuItemSelectedIcon={ + invertSelection ? ( + <StyledStopOutlined iconSize="m" aria-label="stop" /> + ) : ( + <StyledCheckOutlined iconSize="m" aria-label="check" /> + ) + } + oneLine={oneLine} + tagRender={customTagRender} + {...props} + ref={ref} + > + {hasCustomLabels(fullSelectOptions) && + renderSelectOptions(fullSelectOptions)} + </StyledSelect> + </StyledContainer> + ); + }, +); + +export default AsyncSelect; diff --git a/superset-frontend/src/components/Select/CustomTag.tsx b/superset-frontend/src/components/Select/CustomTag.tsx new file mode 100644 index 0000000000000..a7ffe10f6d54f --- /dev/null +++ b/superset-frontend/src/components/Select/CustomTag.tsx @@ -0,0 +1,82 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { Tag as AntdTag } from 'antd'; +import { styled } from '@superset-ui/core'; +import { useCSSTextTruncation } from 'src/hooks/useTruncation'; +import { Tooltip } from '../Tooltip'; +import { CustomTagProps } from './types'; +import { SELECT_ALL_VALUE } from './utils'; +import { NoElement } from './styles'; + +const StyledTag = styled(AntdTag)` + & .ant-tag-close-icon { + display: inline-flex; + align-items: center; + margin-left: ${({ theme }) => theme.gridUnit}px; + } + + & .tag-content { + overflow: hidden; + text-overflow: ellipsis; + } +`; + +// TODO: use antd Tag props instead of any. Currently it's causing a typescript error +const Tag = (props: any) => { + const [tagRef, tagIsTruncated] = useCSSTextTruncation<HTMLSpanElement>(); + return ( + <Tooltip title={tagIsTruncated ? props.children : null}> + <StyledTag {...props} className="ant-select-selection-item"> + <span className="tag-content" ref={tagRef}> + {props.children} + </span> + </StyledTag> + </Tooltip> + ); +}; + +/** + * Custom tag renderer + */ +export const customTagRender = (props: CustomTagProps) => { + const { label, value } = props; + + const onPreventMouseDown = (event: React.MouseEvent<HTMLElement>) => { + // if close icon is clicked, stop propagation to avoid opening the dropdown + const target = event.target as HTMLElement; + if ( + target.tagName === 'svg' || + target.tagName === 'path' || + (target.tagName === 'span' && + target.className.includes('ant-tag-close-icon')) + ) { + event.stopPropagation(); + } + }; + + if (value !== SELECT_ALL_VALUE) { + return ( + <Tag onMouseDown={onPreventMouseDown} {...(props as object)}> + {label} + </Tag> + ); + } + return <NoElement />; +}; diff --git a/superset-frontend/src/components/Select/Select.stories.tsx b/superset-frontend/src/components/Select/Select.stories.tsx index 5526c2fc2ac01..cb7224fdca3b4 100644 --- a/superset-frontend/src/components/Select/Select.stories.tsx +++ b/superset-frontend/src/components/Select/Select.stories.tsx @@ -16,9 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import React, { ReactNode, useState, useCallback } from 'react'; +import React from 'react'; import ControlHeader from 'src/explore/components/ControlHeader'; -import Select, { SelectProps, OptionsTypePage, OptionsType } from './Select'; +import { SelectOptionsType, SelectProps } from './types'; + +import Select from './Select'; export default { title: 'Select', @@ -27,7 +29,7 @@ export default { const DEFAULT_WIDTH = 200; -const options: OptionsType = [ +const options: SelectOptionsType = [ { label: 'Such an incredibly awesome long long label', value: 'Such an incredibly awesome long long label', @@ -130,6 +132,22 @@ const ARG_TYPES = { By default label and value. `, }, + oneLine: { + defaultValue: false, + description: `Sets maxTagCount to 1. The overflow tag is always displayed in + the same line, line wrapping is disabled. + When the dropdown is open, sets maxTagCount to 0, + displays only the overflow tag. + Requires '"mode=multiple"'. + `, + }, + maxTagCount: { + defaultValue: 4, + description: `Sets maxTagCount attribute. The overflow tag is displayed in + place of the remaining items. + Requires '"mode=multiple"'. + `, + }, }; const mountHeader = (type: String) => { @@ -140,14 +158,14 @@ const mountHeader = (type: String) => { header = ( <ControlHeader label="Control header" - warning="Example of warning messsage" + warning="Example of warning message" /> ); } return header; }; -const generateOptions = (opts: OptionsType, count: number) => { +const generateOptions = (opts: SelectOptionsType, count: number) => { let generated = opts.slice(); let iteration = 0; while (generated.length < count) { @@ -195,6 +213,8 @@ InteractiveSelect.args = { invertSelection: false, placeholder: 'Select ...', optionFilterProps: ['value', 'label', 'custom'], + oneLine: false, + maxTagCount: 4, }; InteractiveSelect.argTypes = { @@ -321,220 +341,3 @@ PageScroll.story = { }, }, }; - -const USERS = [ - 'John', - 'Liam', - 'Olivia', - 'Emma', - 'Noah', - 'Ava', - 'Oliver', - 'Elijah', - 'Charlotte', - 'Diego', - 'Evan', - 'Michael', - 'Giovanni', - 'Luca', - 'Paolo', - 'Francesca', - 'Chiara', - 'Sara', - 'Valentina', - 'Jessica', - 'Angelica', - 'Mario', - 'Marco', - 'Andrea', - 'Luigi', - 'Quarto', - 'Quinto', - 'Sesto', - 'Franco', - 'Sandro', - 'Alehandro', - 'Johnny', - 'Nikole', - 'Igor', - 'Sipatha', - 'Thami', - 'Munei', - 'Guilherme', - 'Umair', - 'Ashfaq', - 'Amna', - 'Irfan', - 'George', - 'Naseer', - 'Mohammad', - 'Rick', - 'Saliya', - 'Claire', - 'Benedetta', - 'Ilenia', -].sort(); - -export const AsyncSelect = ({ - fetchOnlyOnSearch, - withError, - withInitialValue, - responseTime, - ...rest -}: SelectProps & { - withError: boolean; - withInitialValue: boolean; - responseTime: number; -}) => { - const [requests, setRequests] = useState<ReactNode[]>([]); - - const getResults = (username?: string) => { - let results: { label: string; value: string }[] = []; - - if (!username) { - results = USERS.map(u => ({ - label: u, - value: u, - })); - } else { - const foundUsers = USERS.filter(u => u.toLowerCase().includes(username)); - if (foundUsers) { - results = foundUsers.map(u => ({ label: u, value: u })); - } else { - results = []; - } - } - return results; - }; - - const setRequestLog = (results: number, total: number, username?: string) => { - const request = ( - <> - Emulating network request with search <b>{username || 'empty'}</b> ...{' '} - <b> - {results}/{total} - </b>{' '} - results - </> - ); - - setRequests(requests => [request, ...requests]); - }; - - const fetchUserListPage = useCallback( - ( - search: string, - page: number, - pageSize: number, - ): Promise<OptionsTypePage> => { - const username = search.trim().toLowerCase(); - return new Promise(resolve => { - let results = getResults(username); - const totalCount = results.length; - const start = page * pageSize; - const deleteCount = - start + pageSize < totalCount ? pageSize : totalCount - start; - results = results.splice(start, deleteCount); - setRequestLog(start + results.length, totalCount, username); - setTimeout(() => { - resolve({ data: results, totalCount }); - }, responseTime * 1000); - }); - }, - [responseTime], - ); - - const fetchUserListError = async (): Promise<OptionsTypePage> => - new Promise((_, reject) => { - reject(new Error('Error while fetching the names from the server')); - }); - - return ( - <> - <div - style={{ - width: DEFAULT_WIDTH, - }} - > - <Select - {...rest} - fetchOnlyOnSearch={fetchOnlyOnSearch} - options={withError ? fetchUserListError : fetchUserListPage} - placeholder={fetchOnlyOnSearch ? 'Type anything' : 'Select...'} - value={ - withInitialValue - ? { label: 'Valentina', value: 'Valentina' } - : undefined - } - /> - </div> - <div - style={{ - position: 'absolute', - top: 32, - left: DEFAULT_WIDTH + 100, - height: 400, - width: 600, - overflowY: 'auto', - border: '1px solid #d9d9d9', - padding: 20, - }} - > - {requests.map((request, index) => ( - <p key={`request-${index}`}>{request}</p> - ))} - </div> - </> - ); -}; - -AsyncSelect.args = { - allowClear: false, - allowNewOptions: false, - fetchOnlyOnSearch: false, - pageSize: 10, - withError: false, - withInitialValue: false, - tokenSeparators: ['\n', '\t', ';'], -}; - -AsyncSelect.argTypes = { - ...ARG_TYPES, - header: { - table: { - disable: true, - }, - }, - invertSelection: { - table: { - disable: true, - }, - }, - pageSize: { - defaultValue: 10, - control: { - type: 'range', - min: 10, - max: 50, - step: 10, - }, - }, - responseTime: { - defaultValue: 0.5, - name: 'responseTime (seconds)', - control: { - type: 'range', - min: 0.5, - max: 5, - step: 0.5, - }, - }, -}; - -AsyncSelect.story = { - parameters: { - knobs: { - disable: true, - }, - }, -}; diff --git a/superset-frontend/src/components/Select/Select.test.tsx b/superset-frontend/src/components/Select/Select.test.tsx index 37a39204369f6..f55299e3fc7bd 100644 --- a/superset-frontend/src/components/Select/Select.test.tsx +++ b/superset-frontend/src/components/Select/Select.test.tsx @@ -19,13 +19,21 @@ import React from 'react'; import { render, screen, waitFor, within } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; -import { Select } from 'src/components'; +import Select from 'src/components/Select/Select'; +import { SELECT_ALL_VALUE } from './utils'; + +type Option = { + label: string; + value: number; + gender: string; + disabled?: boolean; +}; const ARIA_LABEL = 'Test'; const NEW_OPTION = 'Kyle'; const NO_DATA = 'No Data'; const LOADING = 'Loading...'; -const OPTIONS = [ +const OPTIONS: Option[] = [ { label: 'John', value: 1, gender: 'Male' }, { label: 'Liam', value: 2, gender: 'Male' }, { label: 'Olivia', value: 3, gender: 'Female' }, @@ -55,21 +63,6 @@ const NULL_OPTION = { label: '<NULL>', value: null } as unknown as { value: number; }; -const loadOptions = async (search: string, page: number, pageSize: number) => { - const totalCount = OPTIONS.length; - const start = page * pageSize; - const deleteCount = - start + pageSize < totalCount ? pageSize : totalCount - start; - const data = OPTIONS.filter(option => option.label.match(search)).splice( - start, - deleteCount, - ); - return { - data, - totalCount: OPTIONS.length, - }; -}; - const defaultProps = { allowClear: true, ariaLabel: ARIA_LABEL, @@ -79,6 +72,9 @@ const defaultProps = { showSearch: true, }; +const selectAllOptionLabel = (numOptions: number) => + `${String(SELECT_ALL_VALUE)} (${numOptions})`; + const getElementByClassName = (className: string) => document.querySelector(className)! as HTMLElement; @@ -92,6 +88,11 @@ const findSelectOption = (text: string) => within(getElementByClassName('.rc-virtual-list')).getByText(text), ); +const querySelectOption = (text: string) => + waitFor(() => + within(getElementByClassName('.rc-virtual-list')).queryByText(text), + ); + const findAllSelectOptions = () => waitFor(() => getElementsByClassName('.ant-select-item-option-content')); @@ -99,7 +100,12 @@ const findSelectValue = () => waitFor(() => getElementByClassName('.ant-select-selection-item')); const findAllSelectValues = () => - waitFor(() => getElementsByClassName('.ant-select-selection-item')); + waitFor(() => [...getElementsByClassName('.ant-select-selection-item')]); + +const findAllCheckedValues = () => + waitFor(() => [ + ...getElementsByClassName('.ant-select-item-option-selected'), + ]); const clearAll = () => userEvent.click(screen.getByLabelText('close-circle')); @@ -129,17 +135,24 @@ test('displays a header', async () => { expect(screen.getByText(headerText)).toBeInTheDocument(); }); -test('adds a new option if the value is not in the options', async () => { - const { rerender } = render( - <Select {...defaultProps} options={[]} value={OPTIONS[0]} />, - ); +test('adds a new option if the value is not in the options, when options are empty', async () => { + render(<Select {...defaultProps} options={[]} value={OPTIONS[0]} />); await open(); expect(await findSelectOption(OPTIONS[0].label)).toBeInTheDocument(); + const options = await findAllSelectOptions(); + expect(options).toHaveLength(1); + options.forEach((option, i) => + expect(option).toHaveTextContent(OPTIONS[i].label), + ); +}); - rerender( +test('adds a new option if the value is not in the options, when options have values', async () => { + render( <Select {...defaultProps} options={[OPTIONS[1]]} value={OPTIONS[0]} />, ); await open(); + expect(await findSelectOption(OPTIONS[0].label)).toBeInTheDocument(); + expect(await findSelectOption(OPTIONS[1].label)).toBeInTheDocument(); const options = await findAllSelectOptions(); expect(options).toHaveLength(2); options.forEach((option, i) => @@ -147,6 +160,16 @@ test('adds a new option if the value is not in the options', async () => { ); }); +test('does not add a new option if the value is already in the options', async () => { + render( + <Select {...defaultProps} options={[OPTIONS[0]]} value={OPTIONS[0]} />, + ); + await open(); + expect(await findSelectOption(OPTIONS[0].label)).toBeInTheDocument(); + const options = await findAllSelectOptions(); + expect(options).toHaveLength(1); +}); + test('inverts the selection', async () => { render(<Select {...defaultProps} invertSelection />); await open(); @@ -164,27 +187,6 @@ test('sort the options by label if no sort comparator is provided', async () => ); }); -test('sort the options using a custom sort comparator', async () => { - const sortComparator = ( - option1: typeof OPTIONS[0], - option2: typeof OPTIONS[0], - ) => option1.gender.localeCompare(option2.gender); - render( - <Select - {...defaultProps} - options={loadOptions} - sortComparator={sortComparator} - />, - ); - await open(); - const options = await findAllSelectOptions(); - const optionsPage = OPTIONS.slice(0, defaultProps.pageSize); - const sortedOptions = optionsPage.sort(sortComparator); - options.forEach((option, key) => { - expect(option).toHaveTextContent(sortedOptions[key].label); - }); -}); - test('should sort selected to top when in single mode', async () => { render(<Select {...defaultProps} mode="single" />); const originalLabels = OPTIONS.map(option => option.label); @@ -223,26 +225,37 @@ test('should sort selected to the top when in multi mode', async () => { let labels = originalLabels.slice(); await open(); - userEvent.click(await findSelectOption(labels[1])); - expect(await matchOrder(labels)).toBe(true); + userEvent.click(await findSelectOption(labels[2])); + expect( + await matchOrder([selectAllOptionLabel(originalLabels.length), ...labels]), + ).toBe(true); await type('{esc}'); await open(); - labels = labels.splice(1, 1).concat(labels); - expect(await matchOrder(labels)).toBe(true); + labels = labels.splice(2, 1).concat(labels); + expect( + await matchOrder([selectAllOptionLabel(originalLabels.length), ...labels]), + ).toBe(true); await open(); userEvent.click(await findSelectOption(labels[5])); await type('{esc}'); await open(); labels = [labels.splice(0, 1)[0], labels.splice(4, 1)[0]].concat(labels); - expect(await matchOrder(labels)).toBe(true); + expect( + await matchOrder([selectAllOptionLabel(originalLabels.length), ...labels]), + ).toBe(true); // should revert to original order clearAll(); await type('{esc}'); await open(); - expect(await matchOrder(originalLabels)).toBe(true); + expect( + await matchOrder([ + selectAllOptionLabel(originalLabels.length), + ...originalLabels, + ]), + ).toBe(true); }); test('searches for label or value', async () => { @@ -382,7 +395,7 @@ test('clear all the values', async () => { }); test('does not add a new option if allowNewOptions is false', async () => { - render(<Select {...defaultProps} options={loadOptions} />); + render(<Select {...defaultProps} options={OPTIONS} />); await open(); await type(NEW_OPTION); expect(await screen.findByText(NO_DATA)).toBeInTheDocument(); @@ -412,18 +425,18 @@ test('adds the null option when selected in multiple mode', async () => { expect(values[1]).toHaveTextContent(NULL_OPTION.label); }); -test('static - renders the select with default props', () => { +test('renders the select with default props', () => { render(<Select {...defaultProps} />); expect(getSelect()).toBeInTheDocument(); }); -test('static - opens the select without any data', async () => { +test('opens the select without any data', async () => { render(<Select {...defaultProps} options={[]} />); await open(); expect(screen.getByText(NO_DATA)).toBeInTheDocument(); }); -test('static - makes a selection in single mode', async () => { +test('makes a selection in single mode', async () => { render(<Select {...defaultProps} />); const optionText = 'Emma'; await open(); @@ -431,7 +444,7 @@ test('static - makes a selection in single mode', async () => { expect(await findSelectValue()).toHaveTextContent(optionText); }); -test('static - multiple selections in multiple mode', async () => { +test('multiple selections in multiple mode', async () => { render(<Select {...defaultProps} mode="multiple" />); await open(); const [firstOption, secondOption] = OPTIONS; @@ -442,7 +455,7 @@ test('static - multiple selections in multiple mode', async () => { expect(values[1]).toHaveTextContent(secondOption.label); }); -test('static - changes the selected item in single mode', async () => { +test('changes the selected item in single mode', async () => { const onChange = jest.fn(); render(<Select {...defaultProps} onChange={onChange} />); await open(); @@ -454,7 +467,7 @@ test('static - changes the selected item in single mode', async () => { label: firstOption.label, value: firstOption.value, }), - firstOption, + expect.objectContaining(firstOption), ); userEvent.click(await findSelectOption(secondOption.label)); expect(onChange).toHaveBeenCalledWith( @@ -462,12 +475,12 @@ test('static - changes the selected item in single mode', async () => { label: secondOption.label, value: secondOption.value, }), - secondOption, + expect.objectContaining(secondOption), ); expect(await findSelectValue()).toHaveTextContent(secondOption.label); }); -test('static - deselects an item in multiple mode', async () => { +test('deselects an item in multiple mode', async () => { render(<Select {...defaultProps} mode="multiple" />); await open(); const [firstOption, secondOption] = OPTIONS; @@ -483,35 +496,35 @@ test('static - deselects an item in multiple mode', async () => { expect(values[0]).toHaveTextContent(secondOption.label); }); -test('static - adds a new option if none is available and allowNewOptions is true', async () => { +test('adds a new option if none is available and allowNewOptions is true', async () => { render(<Select {...defaultProps} allowNewOptions />); await open(); await type(NEW_OPTION); expect(await findSelectOption(NEW_OPTION)).toBeInTheDocument(); }); -test('static - shows "No data" when allowNewOptions is false and a new option is entered', async () => { +test('shows "No data" when allowNewOptions is false and a new option is entered', async () => { render(<Select {...defaultProps} allowNewOptions={false} />); await open(); await type(NEW_OPTION); expect(await screen.findByText(NO_DATA)).toBeInTheDocument(); }); -test('static - does not show "No data" when allowNewOptions is true and a new option is entered', async () => { +test('does not show "No data" when allowNewOptions is true and a new option is entered', async () => { render(<Select {...defaultProps} allowNewOptions />); await open(); await type(NEW_OPTION); expect(screen.queryByText(NO_DATA)).not.toBeInTheDocument(); }); -test('static - does not show "Loading..." when allowNewOptions is false and a new option is entered', async () => { +test('does not show "Loading..." when allowNewOptions is false and a new option is entered', async () => { render(<Select {...defaultProps} allowNewOptions={false} />); await open(); await type(NEW_OPTION); expect(screen.queryByText(LOADING)).not.toBeInTheDocument(); }); -test('static - does not add a new option if the option already exists', async () => { +test('does not add a new option if the option already exists', async () => { render(<Select {...defaultProps} allowNewOptions />); const option = OPTIONS[0].label; await open(); @@ -519,12 +532,12 @@ test('static - does not add a new option if the option already exists', async () expect(await findSelectOption(option)).toBeInTheDocument(); }); -test('static - sets a initial value in single mode', async () => { +test('sets a initial value in single mode', async () => { render(<Select {...defaultProps} value={OPTIONS[0]} />); expect(await findSelectValue()).toHaveTextContent(OPTIONS[0].label); }); -test('static - sets a initial value in multiple mode', async () => { +test('sets a initial value in multiple mode', async () => { render( <Select {...defaultProps} @@ -537,7 +550,7 @@ test('static - sets a initial value in multiple mode', async () => { expect(values[1]).toHaveTextContent(OPTIONS[1].label); }); -test('static - searches for an item', async () => { +test('searches for an item', async () => { render(<Select {...defaultProps} />); const search = 'Oli'; await type(search); @@ -547,270 +560,327 @@ test('static - searches for an item', async () => { expect(options[1]).toHaveTextContent('Olivia'); }); -test('async - renders the select with default props', () => { - render(<Select {...defaultProps} options={loadOptions} />); - expect(getSelect()).toBeInTheDocument(); -}); - -test('async - opens the select without any data', async () => { - render( - <Select - {...defaultProps} - options={async () => ({ data: [], totalCount: 0 })} - />, - ); +test('triggers getPopupContainer if passed', async () => { + const getPopupContainer = jest.fn(); + render(<Select {...defaultProps} getPopupContainer={getPopupContainer} />); await open(); - expect(await screen.findByText(/no data/i)).toBeInTheDocument(); + expect(getPopupContainer).toHaveBeenCalled(); }); -test('async - displays the loading indicator when opening', async () => { - render(<Select {...defaultProps} options={loadOptions} />); - await waitFor(() => { - userEvent.click(getSelect()); - expect(screen.getByText(LOADING)).toBeInTheDocument(); - }); - expect(screen.queryByText(LOADING)).not.toBeInTheDocument(); +test('does not render a helper text by default', async () => { + render(<Select {...defaultProps} />); + await open(); + expect(screen.queryByRole('note')).not.toBeInTheDocument(); }); -test('async - makes a selection in single mode', async () => { - render(<Select {...defaultProps} options={loadOptions} />); - const optionText = 'Emma'; +test('renders a helper text when one is provided', async () => { + const helperText = 'Helper text'; + render(<Select {...defaultProps} helperText={helperText} />); await open(); - userEvent.click(await findSelectOption(optionText)); - expect(await findSelectValue()).toHaveTextContent(optionText); + expect(screen.getByRole('note')).toBeInTheDocument(); + expect(screen.queryByText(helperText)).toBeInTheDocument(); }); -test('async - multiple selections in multiple mode', async () => { - render(<Select {...defaultProps} options={loadOptions} mode="multiple" />); +test('finds an element with a numeric value and does not duplicate the options', async () => { + const options = [ + { label: 'a', value: 11 }, + { label: 'b', value: 12 }, + ]; + render(<Select {...defaultProps} options={options} allowNewOptions />); await open(); - const [firstOption, secondOption] = OPTIONS; - userEvent.click(await findSelectOption(firstOption.label)); - userEvent.click(await findSelectOption(secondOption.label)); - const values = await findAllSelectValues(); - expect(values[0]).toHaveTextContent(firstOption.label); - expect(values[1]).toHaveTextContent(secondOption.label); + await type('11'); + expect(await findSelectOption('a')).toBeInTheDocument(); + expect(await querySelectOption('11')).not.toBeInTheDocument(); }); -test('async - changes the selected item in single mode', async () => { - const onChange = jest.fn(); - render( - <Select {...defaultProps} options={loadOptions} onChange={onChange} />, - ); +test('render "Select all" for multi select', async () => { + render(<Select {...defaultProps} mode="multiple" options={OPTIONS} />); await open(); - const [firstOption, secondOption] = OPTIONS; - userEvent.click(await findSelectOption(firstOption.label)); - expect(onChange).toHaveBeenCalledWith( - expect.objectContaining({ - label: firstOption.label, - value: firstOption.value, - }), - firstOption, - ); - expect(await findSelectValue()).toHaveTextContent(firstOption.label); - userEvent.click(await findSelectOption(secondOption.label)); - expect(onChange).toHaveBeenCalledWith( - expect.objectContaining({ - label: secondOption.label, - value: secondOption.value, - }), - secondOption, - ); - expect(await findSelectValue()).toHaveTextContent(secondOption.label); + const options = await findAllSelectOptions(); + expect(options[0]).toHaveTextContent(selectAllOptionLabel(OPTIONS.length)); }); -test('async - deselects an item in multiple mode', async () => { - render(<Select {...defaultProps} options={loadOptions} mode="multiple" />); +test('does not render "Select all" for single select', async () => { + render(<Select {...defaultProps} options={OPTIONS} mode="single" />); await open(); - const option3 = OPTIONS[2]; - const option8 = OPTIONS[7]; - userEvent.click(await findSelectOption(option8.label)); - userEvent.click(await findSelectOption(option3.label)); - - let options = await findAllSelectOptions(); - expect(options).toHaveLength(Math.min(defaultProps.pageSize, OPTIONS.length)); - expect(options[0]).toHaveTextContent(OPTIONS[0].label); - expect(options[1]).toHaveTextContent(OPTIONS[1].label); + expect( + screen.queryByText(selectAllOptionLabel(OPTIONS.length)), + ).not.toBeInTheDocument(); +}); - await type('{esc}'); +test('does not render "Select all" for an empty multiple select', async () => { + render(<Select {...defaultProps} options={[]} mode="multiple" />); await open(); - - // should rank selected options to the top after menu closes - options = await findAllSelectOptions(); - expect(options).toHaveLength(Math.min(defaultProps.pageSize, OPTIONS.length)); - expect(options[0]).toHaveTextContent(option3.label); - expect(options[1]).toHaveTextContent(option8.label); - - let values = await findAllSelectValues(); - expect(values).toHaveLength(2); - // should keep the order by which the options were selected - expect(values[0]).toHaveTextContent(option8.label); - expect(values[1]).toHaveTextContent(option3.label); - - userEvent.click(await findSelectOption(option3.label)); - values = await findAllSelectValues(); - expect(values.length).toBe(1); - expect(values[0]).toHaveTextContent(option8.label); + expect( + screen.queryByText(selectAllOptionLabel(OPTIONS.length)), + ).not.toBeInTheDocument(); }); -test('async - adds a new option if none is available and allowNewOptions is true', async () => { - render(<Select {...defaultProps} options={loadOptions} allowNewOptions />); +test('does not render "Select all" when searching', async () => { + render(<Select {...defaultProps} options={OPTIONS} mode="multiple" />); await open(); - await type(NEW_OPTION); - expect(await findSelectOption(NEW_OPTION)).toBeInTheDocument(); + await type('Select'); + expect( + screen.queryByText(selectAllOptionLabel(OPTIONS.length)), + ).not.toBeInTheDocument(); }); -test('async - does not add a new option if the option already exists', async () => { - render(<Select {...defaultProps} options={loadOptions} allowNewOptions />); - const option = OPTIONS[0].label; +test('does not render "Select all" as one of the tags after selection', async () => { + render(<Select {...defaultProps} options={OPTIONS} mode="multiple" />); await open(); - await type(option); - await waitFor(() => { - const array = within( - getElementByClassName('.rc-virtual-list'), - ).getAllByText(option); - expect(array.length).toBe(1); - }); + userEvent.click(await findSelectOption(selectAllOptionLabel(OPTIONS.length))); + const values = await findAllSelectValues(); + expect(values[0]).not.toHaveTextContent(selectAllOptionLabel(OPTIONS.length)); }); -test('async - shows "No data" when allowNewOptions is false and a new option is entered', async () => { +test('keeps "Select all" at the top after a selection', async () => { + const selected = OPTIONS[2]; render( <Select {...defaultProps} - options={loadOptions} - allowNewOptions={false} - showSearch + options={OPTIONS.slice(0, 10)} + mode="multiple" + value={[selected]} />, ); await open(); - await type(NEW_OPTION); - expect(await screen.findByText(NO_DATA)).toBeInTheDocument(); + const options = await findAllSelectOptions(); + expect(options[0]).toHaveTextContent(selectAllOptionLabel(10)); + expect(options[1]).toHaveTextContent(selected.label); }); -test('async - does not show "No data" when allowNewOptions is true and a new option is entered', async () => { - render(<Select {...defaultProps} options={loadOptions} allowNewOptions />); +test('selects all values', async () => { + render( + <Select + {...defaultProps} + options={OPTIONS} + mode="multiple" + maxTagCount={0} + />, + ); await open(); - await type(NEW_OPTION); - expect(screen.queryByText(NO_DATA)).not.toBeInTheDocument(); -}); - -test('async - sets a initial value in single mode', async () => { - render(<Select {...defaultProps} options={loadOptions} value={OPTIONS[0]} />); - expect(await findSelectValue()).toHaveTextContent(OPTIONS[0].label); + userEvent.click(await findSelectOption(selectAllOptionLabel(OPTIONS.length))); + const values = await findAllSelectValues(); + expect(values.length).toBe(1); + expect(values[0]).toHaveTextContent(`+ ${OPTIONS.length} ...`); }); -test('async - sets a initial value in multiple mode', async () => { +test('unselects all values', async () => { render( <Select {...defaultProps} + options={OPTIONS} mode="multiple" - options={loadOptions} - value={[OPTIONS[0], OPTIONS[1]]} + maxTagCount={0} />, ); - const values = await findAllSelectValues(); - expect(values[0]).toHaveTextContent(OPTIONS[0].label); - expect(values[1]).toHaveTextContent(OPTIONS[1].label); + await open(); + userEvent.click(await findSelectOption(selectAllOptionLabel(OPTIONS.length))); + let values = await findAllSelectValues(); + expect(values.length).toBe(1); + expect(values[0]).toHaveTextContent(`+ ${OPTIONS.length} ...`); + userEvent.click(await findSelectOption(selectAllOptionLabel(OPTIONS.length))); + values = await findAllSelectValues(); + expect(values.length).toBe(0); }); -test('async - searches for matches in both loaded and unloaded pages', async () => { - render(<Select {...defaultProps} options={loadOptions} />); +test('deselecting a value also deselects "Select all"', async () => { + render( + <Select + {...defaultProps} + options={OPTIONS.slice(0, 10)} + mode="multiple" + maxTagCount={0} + />, + ); await open(); - await type('and'); - - let options = await findAllSelectOptions(); - expect(options.length).toBe(1); - expect(options[0]).toHaveTextContent('Alehandro'); - - await screen.findByText('Sandro'); - options = await findAllSelectOptions(); - expect(options.length).toBe(2); - expect(options[0]).toHaveTextContent('Alehandro'); - expect(options[1]).toHaveTextContent('Sandro'); + userEvent.click(await findSelectOption(selectAllOptionLabel(10))); + let values = await findAllCheckedValues(); + expect(values[0]).toHaveTextContent(selectAllOptionLabel(10)); + userEvent.click(await findSelectOption(OPTIONS[0].label)); + values = await findAllCheckedValues(); + expect(values[0]).not.toHaveTextContent(selectAllOptionLabel(10)); }); -test('async - searches for an item in a page not loaded', async () => { - const mock = jest.fn(loadOptions); - render(<Select {...defaultProps} options={mock} />); - const search = 'Sandro'; +test('selecting all values also selects "Select all"', async () => { + render( + <Select + {...defaultProps} + options={OPTIONS.slice(0, 10)} + mode="multiple" + maxTagCount={0} + />, + ); await open(); - await type(search); - await waitFor(() => expect(mock).toHaveBeenCalledTimes(2)); const options = await findAllSelectOptions(); - expect(options.length).toBe(1); - expect(options[0]).toHaveTextContent(search); + options.forEach((option, index) => { + // skip select all + if (index > 0) { + userEvent.click(option); + } + }); + const values = await findAllSelectValues(); + expect(values[0]).toHaveTextContent(`+ 10 ...`); }); -test('async - does not fetches data when rendering', async () => { - const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 })); - render(<Select {...defaultProps} options={loadOptions} />); - expect(loadOptions).not.toHaveBeenCalled(); +test('Renders only 1 tag and an overflow tag in oneLine mode', () => { + render( + <Select + {...defaultProps} + value={[OPTIONS[0], OPTIONS[1], OPTIONS[2]]} + mode="multiple" + oneLine + />, + ); + expect(screen.getByText(OPTIONS[0].label)).toBeVisible(); + expect(screen.queryByText(OPTIONS[1].label)).not.toBeInTheDocument(); + expect(screen.queryByText(OPTIONS[2].label)).not.toBeInTheDocument(); + expect(screen.getByText('+ 2 ...')).toBeVisible(); }); -test('async - fetches data when opening', async () => { - const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 })); - render(<Select {...defaultProps} options={loadOptions} />); +test('Renders only an overflow tag if dropdown is open in oneLine mode', async () => { + render( + <Select + {...defaultProps} + value={[OPTIONS[0], OPTIONS[1], OPTIONS[2]]} + mode="multiple" + oneLine + />, + ); await open(); - expect(loadOptions).toHaveBeenCalled(); -}); -test('async - fetches data only after a search input is entered if fetchOnlyOnSearch is true', async () => { - const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 })); - render(<Select {...defaultProps} options={loadOptions} fetchOnlyOnSearch />); - await open(); - await waitFor(() => expect(loadOptions).not.toHaveBeenCalled()); - await type('search'); - await waitFor(() => expect(loadOptions).toHaveBeenCalled()); + const withinSelector = within(getElementByClassName('.ant-select-selector')); + await waitFor(() => { + expect( + withinSelector.queryByText(OPTIONS[0].label), + ).not.toBeInTheDocument(); + expect( + withinSelector.queryByText(OPTIONS[1].label), + ).not.toBeInTheDocument(); + expect( + withinSelector.queryByText(OPTIONS[2].label), + ).not.toBeInTheDocument(); + expect(withinSelector.getByText('+ 3 ...')).toBeVisible(); + }); + + await type('{esc}'); + + expect(await withinSelector.findByText(OPTIONS[0].label)).toBeVisible(); + expect(withinSelector.queryByText(OPTIONS[1].label)).not.toBeInTheDocument(); + expect(withinSelector.queryByText(OPTIONS[2].label)).not.toBeInTheDocument(); + expect(withinSelector.getByText('+ 2 ...')).toBeVisible(); }); -test('async - displays an error message when an exception is thrown while fetching', async () => { - const error = 'Fetch error'; - const loadOptions = async () => { - throw new Error(error); - }; - render(<Select {...defaultProps} options={loadOptions} />); +test('+N tag does not count the "Select All" option', async () => { + render( + <Select + {...defaultProps} + options={OPTIONS.slice(0, 10)} + mode="multiple" + maxTagCount={0} + />, + ); await open(); - expect(screen.getByText(error)).toBeInTheDocument(); + userEvent.click(await findSelectOption(selectAllOptionLabel(10))); + const values = await findAllSelectValues(); + // maxTagCount is 0 so the +N tag should be + 10 ... + expect(values[0]).toHaveTextContent('+ 10 ...'); }); -test('async - does not fire a new request for the same search input', async () => { - const loadOptions = jest.fn(async () => ({ data: [], totalCount: 0 })); - render(<Select {...defaultProps} options={loadOptions} fetchOnlyOnSearch />); - await type('search'); - expect(await screen.findByText(NO_DATA)).toBeInTheDocument(); - expect(loadOptions).toHaveBeenCalledTimes(1); - clearAll(); - await type('search'); - expect(await screen.findByText(LOADING)).toBeInTheDocument(); - expect(loadOptions).toHaveBeenCalledTimes(1); +test('"Select All" is checked when unchecking a newly added option and all the other options are still selected', async () => { + render( + <Select + {...defaultProps} + options={OPTIONS.slice(0, 10)} + mode="multiple" + allowNewOptions + />, + ); + await open(); + userEvent.click(await findSelectOption(selectAllOptionLabel(10))); + expect(await findSelectOption(selectAllOptionLabel(10))).toBeInTheDocument(); + // add a new option + await type(`${NEW_OPTION}{enter}`); + expect(await findSelectOption(selectAllOptionLabel(11))).toBeInTheDocument(); + expect(await findSelectOption(NEW_OPTION)).toBeInTheDocument(); + // select all should be selected + let values = await findAllCheckedValues(); + expect(values[0]).toHaveTextContent(selectAllOptionLabel(11)); + // remove new option + userEvent.click(await findSelectOption(NEW_OPTION)); + // select all should still be selected + values = await findAllCheckedValues(); + expect(values[0]).toHaveTextContent(selectAllOptionLabel(10)); + expect(await findSelectOption(selectAllOptionLabel(10))).toBeInTheDocument(); +}); + +test('does not render "Select All" when there are 0 or 1 options', async () => { + const { rerender } = render( + <Select {...defaultProps} options={[]} mode="multiple" allowNewOptions />, + ); + await open(); + expect(screen.queryByText(selectAllOptionLabel(0))).not.toBeInTheDocument(); + rerender( + <Select + {...defaultProps} + options={OPTIONS.slice(0, 1)} + mode="multiple" + allowNewOptions + />, + ); + expect(screen.queryByText(selectAllOptionLabel(1))).not.toBeInTheDocument(); + await type(`${NEW_OPTION}{enter}`); + expect(screen.queryByText(selectAllOptionLabel(2))).toBeInTheDocument(); }); -test('async - does not fire a new request if all values have been fetched', async () => { - const mock = jest.fn(loadOptions); - const search = 'George'; - const pageSize = OPTIONS.length; - render(<Select {...defaultProps} options={mock} pageSize={pageSize} />); +test('do not count unselected disabled options in "Select All"', async () => { + const options = [...OPTIONS]; + options[0].disabled = true; + options[1].disabled = true; + render( + <Select + {...defaultProps} + options={options} + mode="multiple" + value={options[0]} + />, + ); await open(); - expect(mock).toHaveBeenCalledTimes(1); - await type(search); - expect(await findSelectOption(search)).toBeInTheDocument(); - expect(mock).toHaveBeenCalledTimes(1); + // We have 2 options disabled but one is selected initially + // Select All should count one and ignore the other + expect( + screen.getByText(selectAllOptionLabel(OPTIONS.length - 1)), + ).toBeInTheDocument(); }); -test('async - fires a new request if all values have not been fetched', async () => { - const mock = jest.fn(loadOptions); - const pageSize = OPTIONS.length / 2; - render(<Select {...defaultProps} options={mock} pageSize={pageSize} />); +test('"Select All" does not affect disabled options', async () => { + const options = [...OPTIONS]; + options[0].disabled = true; + options[1].disabled = true; + render( + <Select + {...defaultProps} + options={options} + mode="multiple" + value={options[0]} + />, + ); await open(); - expect(mock).toHaveBeenCalledTimes(1); - await type('or'); - // `George` is on the first page so when it appears the API has not been called again - expect(await findSelectOption('George')).toBeInTheDocument(); - expect(mock).toHaveBeenCalledTimes(1); + // We have 2 options disabled but one is selected initially + expect(await findSelectValue()).toHaveTextContent(options[0].label); + expect(await findSelectValue()).not.toHaveTextContent(options[1].label); + + // Checking Select All shouldn't affect the disabled options + const selectAll = selectAllOptionLabel(OPTIONS.length - 1); + userEvent.click(await findSelectOption(selectAll)); + expect(await findSelectValue()).toHaveTextContent(options[0].label); + expect(await findSelectValue()).not.toHaveTextContent(options[1].label); - // `Igor` is on the second paged API request - expect(await findSelectOption('Igor')).toBeInTheDocument(); - expect(mock).toHaveBeenCalledTimes(2); + // Unchecking Select All shouldn't affect the disabled options + userEvent.click(await findSelectOption(selectAll)); + expect(await findSelectValue()).toHaveTextContent(options[0].label); + expect(await findSelectValue()).not.toHaveTextContent(options[1].label); }); /* diff --git a/superset-frontend/src/components/Select/Select.tsx b/superset-frontend/src/components/Select/Select.tsx index b018b53a8b937..11f66d8dba529 100644 --- a/superset-frontend/src/components/Select/Select.tsx +++ b/superset-frontend/src/components/Select/Select.tsx @@ -19,260 +19,50 @@ import React, { forwardRef, ReactElement, - ReactNode, RefObject, - UIEvent, useEffect, useMemo, useState, - useRef, useCallback, } from 'react'; -import { ensureIsArray, styled, t } from '@superset-ui/core'; -import AntdSelect, { - SelectProps as AntdSelectProps, - SelectValue as AntdSelectValue, - LabeledValue as AntdLabeledValue, -} from 'antd/lib/select'; -import { DownOutlined, SearchOutlined } from '@ant-design/icons'; -import { Spin } from 'antd'; -import debounce from 'lodash/debounce'; +import { + ensureIsArray, + formatNumber, + NumberFormats, + t, +} from '@superset-ui/core'; +import AntdSelect, { LabeledValue as AntdLabeledValue } from 'antd/lib/select'; import { isEqual } from 'lodash'; -import Icons from 'src/components/Icons'; -import { getClientErrorObject } from 'src/utils/getClientErrorObject'; -import { SLOW_DEBOUNCE } from 'src/constants'; -import { rankedSearchCompare } from 'src/utils/rankedSearchCompare'; -import { getValue, hasOption, isLabeledValue } from './utils'; - -const { Option } = AntdSelect; - -export const SELECT_ALL_STRING = 'Select all'; - -type AntdSelectAllProps = AntdSelectProps<AntdSelectValue>; - -type PickedSelectProps = Pick< - AntdSelectAllProps, - | 'allowClear' - | 'autoFocus' - | 'disabled' - | 'filterOption' - | 'labelInValue' - | 'loading' - | 'notFoundContent' - | 'onChange' - | 'onClear' - | 'onFocus' - | 'onBlur' - | 'onDropdownVisibleChange' - | 'placeholder' - | 'showSearch' - | 'tokenSeparators' - | 'value' ->; - -export type OptionsType = Exclude<AntdSelectAllProps['options'], undefined>; - -export type OptionsTypePage = { - data: OptionsType; - totalCount: number; -}; - -export type OptionsPagePromise = ( - search: string, - page: number, - pageSize: number, -) => Promise<OptionsTypePage>; - -export interface SelectProps extends PickedSelectProps { - /** - * It enables the user to create new options. - * Can be used with standard or async select types. - * Can be used with any mode, single or multiple. - * False by default. - * */ - allowNewOptions?: boolean; - /** - * It adds the aria-label tag for accessibility standards. - * Must be plain English and localized. - */ - ariaLabel: string; - /** - * It adds a header on top of the Select. - * Can be any ReactNode. - */ - header?: ReactNode; - /** - * It fires a request against the server after - * the first interaction and not on render. - * Works in async mode only (See the options property). - * True by default. - */ - lazyLoading?: boolean; - /** - * It defines whether the Select should allow for the - * selection of multiple options or single. - * Single by default. - */ - mode?: 'single' | 'multiple'; - /** - * Deprecated. - * Prefer ariaLabel instead. - */ - name?: string; // discourage usage - /** - * It allows to define which properties of the option object - * should be looked for when searching. - * By default label and value. - */ - optionFilterProps?: string[]; - /** - * It defines the options of the Select. - * The options can be static, an array of options. - * The options can also be async, a promise that returns - * an array of options. - */ - options: OptionsType | OptionsPagePromise; - /** - * It defines how many results should be included - * in the query response. - * Works in async mode only (See the options property). - */ - pageSize?: number; - /** - * It shows a stop-outlined icon at the far right of a selected - * option instead of the default checkmark. - * Useful to better indicate to the user that by clicking on a selected - * option it will be de-selected. - * False by default. - */ - invertSelection?: boolean; - /** - * It fires a request against the server only after - * searching. - * Works in async mode only (See the options property). - * Undefined by default. - */ - fetchOnlyOnSearch?: boolean; - /** - * It provides a callback function when an error - * is generated after a request is fired. - * Works in async mode only (See the options property). - */ - onError?: (error: string) => void; - /** - * Customize how filtered options are sorted while users search. - * Will not apply to predefined `options` array when users are not searching. - */ - sortComparator?: typeof DEFAULT_SORT_COMPARATOR; -} - -const StyledContainer = styled.div` - display: flex; - flex-direction: column; - width: 100%; -`; - -const StyledSelect = styled(AntdSelect)` - ${({ theme }) => ` - && .ant-select-selector { - border-radius: ${theme.gridUnit}px; - } - // Open the dropdown when clicking on the suffix - // This is fixed in version 4.16 - .ant-select-arrow .anticon:not(.ant-select-suffix) { - pointer-events: none; - } - `} -`; - -const StyledStopOutlined = styled(Icons.StopOutlined)` - vertical-align: 0; -`; - -const StyledCheckOutlined = styled(Icons.CheckOutlined)` - vertical-align: 0; -`; - -const StyledError = styled.div` - ${({ theme }) => ` - display: flex; - justify-content: center; - align-items: flex-start; - width: 100%; - padding: ${theme.gridUnit * 2}px; - color: ${theme.colors.error.base}; - & svg { - margin-right: ${theme.gridUnit * 2}px; - } - `} -`; - -const StyledErrorMessage = styled.div` - overflow: hidden; - text-overflow: ellipsis; -`; - -const StyledSpin = styled(Spin)` - margin-top: ${({ theme }) => -theme.gridUnit}px; -`; - -const StyledLoadingText = styled.div` - ${({ theme }) => ` - margin-left: ${theme.gridUnit * 3}px; - line-height: ${theme.gridUnit * 8}px; - color: ${theme.colors.grayscale.light1}; - `} -`; - -const MAX_TAG_COUNT = 4; -const TOKEN_SEPARATORS = [',', '\n', '\t', ';']; -const DEFAULT_PAGE_SIZE = 100; -const EMPTY_OPTIONS: OptionsType = []; - -const Error = ({ error }: { error: string }) => ( - <StyledError> - <Icons.ErrorSolid /> <StyledErrorMessage>{error}</StyledErrorMessage> - </StyledError> -); - -export const DEFAULT_SORT_COMPARATOR = ( - a: AntdLabeledValue, - b: AntdLabeledValue, - search?: string, -) => { - let aText: string | undefined; - let bText: string | undefined; - if (typeof a.label === 'string' && typeof b.label === 'string') { - aText = a.label; - bText = b.label; - } else if (typeof a.value === 'string' && typeof b.value === 'string') { - aText = a.value; - bText = b.value; - } - // sort selected options first - if (typeof aText === 'string' && typeof bText === 'string') { - if (search) { - return rankedSearchCompare(aText, bText, search); - } - return aText.localeCompare(bText); - } - return (a.value as number) - (b.value as number); -}; - -/** - * It creates a comparator to check for a specific property. - * Can be used with string and number property values. - * */ -export const propertyComparator = - (property: string) => (a: AntdLabeledValue, b: AntdLabeledValue) => { - if (typeof a[property] === 'string' && typeof b[property] === 'string') { - return a[property].localeCompare(b[property]); - } - return (a[property] as number) - (b[property] as number); - }; - -const getQueryCacheKey = (value: string, page: number, pageSize: number) => - `${value};${page};${pageSize}`; +import { + getValue, + hasOption, + isLabeledValue, + renderSelectOptions, + sortSelectedFirstHelper, + sortComparatorWithSearchHelper, + handleFilterOptionHelper, + dropDownRenderHelper, + getSuffixIcon, + SELECT_ALL_VALUE, + selectAllOption, + mapValues, + mapOptions, +} from './utils'; +import { SelectOptionsType, SelectProps } from './types'; +import { + StyledCheckOutlined, + StyledContainer, + StyledHeader, + StyledSelect, + StyledStopOutlined, +} from './styles'; +import { + EMPTY_OPTIONS, + MAX_TAG_COUNT, + TOKEN_SEPARATORS, + DEFAULT_SORT_COMPARATOR, +} from './constants'; +import { customTagRender } from './CustomTag'; /** * This component is a customized version of the Antdesign 4.X Select component @@ -288,451 +78,439 @@ const getQueryCacheKey = (value: string, page: number, pageSize: number) => * Each of the categories come with different abilities. For a comprehensive guide please refer to * the storybook in src/components/Select/Select.stories.tsx. */ -const Select = ( - { - allowClear, - allowNewOptions = false, - ariaLabel, - fetchOnlyOnSearch, - filterOption = true, - header = null, - invertSelection = false, - labelInValue = false, - lazyLoading = true, - loading, - mode = 'single', - name, - notFoundContent, - onError, - onChange, - onClear, - onDropdownVisibleChange, - optionFilterProps = ['label', 'value'], - options, - pageSize = DEFAULT_PAGE_SIZE, - placeholder = t('Select ...'), - showSearch = true, - sortComparator = DEFAULT_SORT_COMPARATOR, - tokenSeparators, - value, - ...props - }: SelectProps, - ref: RefObject<HTMLInputElement>, -) => { - const isAsync = typeof options === 'function'; - const isSingleMode = mode === 'single'; - const shouldShowSearch = isAsync || allowNewOptions ? true : showSearch; - const [selectValue, setSelectValue] = useState(value); - const [inputValue, setInputValue] = useState(''); - const [isLoading, setIsLoading] = useState(loading); - const [error, setError] = useState(''); - const [isDropdownVisible, setIsDropdownVisible] = useState(false); - const [page, setPage] = useState(0); - const [totalCount, setTotalCount] = useState(0); - const [loadingEnabled, setLoadingEnabled] = useState(!lazyLoading); - const [allValuesLoaded, setAllValuesLoaded] = useState(false); - const fetchedQueries = useRef(new Map<string, number>()); - const mappedMode = isSingleMode - ? undefined - : allowNewOptions - ? 'tags' - : 'multiple'; - const allowFetch = !fetchOnlyOnSearch || inputValue; - - const sortSelectedFirst = useCallback( - (a: AntdLabeledValue, b: AntdLabeledValue) => - selectValue && a.value !== undefined && b.value !== undefined - ? Number(hasOption(b.value, selectValue)) - - Number(hasOption(a.value, selectValue)) - : 0, - [selectValue], - ); - const sortComparatorWithSearch = useCallback( - (a: AntdLabeledValue, b: AntdLabeledValue) => - sortSelectedFirst(a, b) || sortComparator(a, b, inputValue), - [inputValue, sortComparator, sortSelectedFirst], - ); - const sortComparatorForNoSearch = useCallback( - (a: AntdLabeledValue, b: AntdLabeledValue) => - sortSelectedFirst(a, b) || - // Only apply the custom sorter in async mode because we should - // preserve the options order as much as possible. - (isAsync ? sortComparator(a, b, '') : 0), - [isAsync, sortComparator, sortSelectedFirst], - ); - - const initialOptions = useMemo( - () => (options && Array.isArray(options) ? options.slice() : EMPTY_OPTIONS), - [options], - ); - const initialOptionsSorted = useMemo( - () => initialOptions.slice().sort(sortComparatorForNoSearch), - [initialOptions, sortComparatorForNoSearch], - ); - - const [selectOptions, setSelectOptions] = - useState<OptionsType>(initialOptionsSorted); - - // add selected values to options list if they are not in it - const fullSelectOptions = useMemo(() => { - const missingValues: OptionsType = ensureIsArray(selectValue) - .filter(opt => !hasOption(getValue(opt), selectOptions)) - .map(opt => - isLabeledValue(opt) ? opt : { value: opt, label: String(opt) }, - ); - return missingValues.length > 0 - ? missingValues.concat(selectOptions) - : selectOptions; - }, [selectOptions, selectValue]); - - const hasCustomLabels = fullSelectOptions.some(opt => !!opt?.customLabel); - - const handleOnSelect = ( - selectedItem: string | number | AntdLabeledValue | undefined, - ) => { - if (isSingleMode) { - setSelectValue(selectedItem); - } else { - setSelectValue(previousState => { - const array = ensureIsArray(previousState); - const value = getValue(selectedItem); - // Tokenized values can contain duplicated values - if (!hasOption(value, array)) { - const result = [...array, selectedItem]; - return isLabeledValue(selectedItem) - ? (result as AntdLabeledValue[]) - : (result as (string | number)[]); - } - return previousState; - }); - } - setInputValue(''); - }; - - const handleOnDeselect = ( - value: string | number | AntdLabeledValue | undefined, +const Select = forwardRef( + ( + { + allowClear, + allowNewOptions = false, + ariaLabel, + filterOption = true, + header = null, + headerPosition = 'top', + helperText, + invertSelection = false, + labelInValue = false, + loading, + mode = 'single', + name, + notFoundContent, + onChange, + onClear, + onDropdownVisibleChange, + optionFilterProps = ['label', 'value'], + options, + placeholder = t('Select ...'), + showSearch = true, + sortComparator = DEFAULT_SORT_COMPARATOR, + tokenSeparators, + value, + getPopupContainer, + oneLine, + maxTagCount: propsMaxTagCount, + ...props + }: SelectProps, + ref: RefObject<HTMLInputElement>, ) => { - if (Array.isArray(selectValue)) { - if (isLabeledValue(value)) { - const array = selectValue as AntdLabeledValue[]; - setSelectValue(array.filter(element => element.value !== value.value)); - } else { - const array = selectValue as (string | number)[]; - setSelectValue(array.filter(element => element !== value)); + const isSingleMode = mode === 'single'; + const shouldShowSearch = allowNewOptions ? true : showSearch; + const [selectValue, setSelectValue] = useState(value); + const [inputValue, setInputValue] = useState(''); + const [isLoading, setIsLoading] = useState(loading); + const [isDropdownVisible, setIsDropdownVisible] = useState(false); + const [maxTagCount, setMaxTagCount] = useState( + propsMaxTagCount ?? MAX_TAG_COUNT, + ); + + useEffect(() => { + if (oneLine) { + setMaxTagCount(isDropdownVisible ? 0 : 1); } - } - setInputValue(''); - }; - - const internalOnError = useCallback( - (response: Response) => - getClientErrorObject(response).then(e => { - const { error } = e; - setError(error); - - if (onError) { - onError(error); - } - }), - [onError], - ); - - const mergeData = useCallback( - (data: OptionsType) => { - let mergedData: OptionsType = []; - if (data && Array.isArray(data) && data.length) { - // unique option values should always be case sensitive so don't lowercase - const dataValues = new Set(data.map(opt => opt.value)); - // merges with existing and creates unique options - setSelectOptions(prevOptions => { - mergedData = prevOptions - .filter(previousOption => !dataValues.has(previousOption.value)) - .concat(data) - .sort(sortComparatorForNoSearch); - return mergedData; + }, [isDropdownVisible, oneLine]); + + const mappedMode = isSingleMode + ? undefined + : allowNewOptions + ? 'tags' + : 'multiple'; + + const { Option } = AntdSelect; + + const sortSelectedFirst = useCallback( + (a: AntdLabeledValue, b: AntdLabeledValue) => + sortSelectedFirstHelper(a, b, selectValue), + [selectValue], + ); + const sortComparatorWithSearch = useCallback( + (a: AntdLabeledValue, b: AntdLabeledValue) => + sortComparatorWithSearchHelper( + a, + b, + inputValue, + sortSelectedFirst, + sortComparator, + ), + [inputValue, sortComparator, sortSelectedFirst], + ); + + const initialOptions = useMemo( + () => + options && Array.isArray(options) ? options.slice() : EMPTY_OPTIONS, + [options], + ); + const initialOptionsSorted = useMemo( + () => initialOptions.slice().sort(sortSelectedFirst), + [initialOptions, sortSelectedFirst], + ); + + const [selectOptions, setSelectOptions] = + useState<SelectOptionsType>(initialOptionsSorted); + + // add selected values to options list if they are not in it + const fullSelectOptions = useMemo(() => { + const missingValues: SelectOptionsType = ensureIsArray(selectValue) + .filter(opt => !hasOption(getValue(opt), selectOptions)) + .map(opt => + isLabeledValue(opt) ? opt : { value: opt, label: String(opt) }, + ); + const result = + missingValues.length > 0 + ? missingValues.concat(selectOptions) + : selectOptions; + return result.filter(opt => opt.value !== SELECT_ALL_VALUE); + }, [selectOptions, selectValue]); + + const enabledOptions = useMemo( + () => fullSelectOptions.filter(option => !option.disabled), + [fullSelectOptions], + ); + + const selectAllEligible = useMemo( + () => + fullSelectOptions.filter( + option => hasOption(option.value, selectValue) || !option.disabled, + ), + [fullSelectOptions, selectValue], + ); + + const selectAllEnabled = useMemo( + () => + !isSingleMode && + selectOptions.length > 0 && + enabledOptions.length > 1 && + !inputValue, + [isSingleMode, selectOptions.length, enabledOptions.length, inputValue], + ); + + const selectAllMode = useMemo( + () => ensureIsArray(selectValue).length === selectAllEligible.length + 1, + [selectValue, selectAllEligible], + ); + + const handleOnSelect = ( + selectedItem: string | number | AntdLabeledValue | undefined, + ) => { + if (isSingleMode) { + setSelectValue(selectedItem); + } else { + setSelectValue(previousState => { + const array = ensureIsArray(previousState); + const value = getValue(selectedItem); + // Tokenized values can contain duplicated values + if (value === getValue(SELECT_ALL_VALUE)) { + if (isLabeledValue(selectedItem)) { + return [ + ...selectAllEligible, + selectAllOption, + ] as AntdLabeledValue[]; + } + return [ + SELECT_ALL_VALUE, + ...selectAllEligible.map(opt => opt.value), + ] as AntdLabeledValue[]; + } + if (!hasOption(value, array)) { + const result = [...array, selectedItem]; + if ( + result.length === selectAllEligible.length && + selectAllEnabled + ) { + return isLabeledValue(selectedItem) + ? ([...result, selectAllOption] as AntdLabeledValue[]) + : ([...result, SELECT_ALL_VALUE] as (string | number)[]); + } + return result as AntdLabeledValue[]; + } + return previousState; }); } - return mergedData; - }, - [sortComparatorForNoSearch], - ); - - const fetchPage = useMemo( - () => (search: string, page: number) => { - setPage(page); - if (allValuesLoaded) { - setIsLoading(false); - return; - } - const key = getQueryCacheKey(search, page, pageSize); - const cachedCount = fetchedQueries.current.get(key); - if (cachedCount !== undefined) { - setTotalCount(cachedCount); - setIsLoading(false); - return; - } - setIsLoading(true); - const fetchOptions = options as OptionsPagePromise; - fetchOptions(search, page, pageSize) - .then(({ data, totalCount }: OptionsTypePage) => { - const mergedData = mergeData(data); - fetchedQueries.current.set(key, totalCount); - setTotalCount(totalCount); + setInputValue(''); + }; + + const clear = () => { + setSelectValue( + fullSelectOptions + .filter( + option => option.disabled && hasOption(option.value, selectValue), + ) + .map(option => + labelInValue + ? { label: option.label, value: option.value } + : option.value, + ), + ); + }; + + const handleOnDeselect = ( + value: string | number | AntdLabeledValue | undefined, + ) => { + if (Array.isArray(selectValue)) { + if (getValue(value) === getValue(SELECT_ALL_VALUE)) { + clear(); + } else { + let array = selectValue as AntdLabeledValue[]; + array = array.filter( + element => getValue(element) !== getValue(value), + ); + // if this was not a new item, deselect select all option if ( - !fetchOnlyOnSearch && - value === '' && - mergedData.length >= totalCount + selectAllMode && + selectOptions.some(opt => opt.value === getValue(value)) ) { - setAllValuesLoaded(true); + array = array.filter( + element => getValue(element) !== SELECT_ALL_VALUE, + ); } - }) - .catch(internalOnError) - .finally(() => { - setIsLoading(false); - }); - }, - [ - allValuesLoaded, - fetchOnlyOnSearch, - mergeData, - internalOnError, - options, - pageSize, - value, - ], - ); - - const debouncedFetchPage = useMemo( - () => debounce(fetchPage, SLOW_DEBOUNCE), - [fetchPage], - ); - - const handleOnSearch = (search: string) => { - const searchValue = search.trim(); - if (allowNewOptions && isSingleMode) { - const newOption = searchValue && - !hasOption(searchValue, fullSelectOptions, true) && { - label: searchValue, - value: searchValue, - isNewOption: true, - }; - const cleanSelectOptions = fullSelectOptions.filter( - opt => !opt.isNewOption || hasOption(opt.value, selectValue), - ); - const newOptions = newOption - ? [newOption, ...cleanSelectOptions] - : cleanSelectOptions; - setSelectOptions(newOptions); - } - if ( - isAsync && - !allValuesLoaded && - loadingEnabled && - !fetchedQueries.current.has(getQueryCacheKey(searchValue, 0, pageSize)) - ) { - // if fetch only on search but search value is empty, then should not be - // in loading state - setIsLoading(!(fetchOnlyOnSearch && !searchValue)); - } - setInputValue(search); - }; - - const handlePagination = (e: UIEvent<HTMLElement>) => { - const vScroll = e.currentTarget; - const thresholdReached = - vScroll.scrollTop > (vScroll.scrollHeight - vScroll.offsetHeight) * 0.7; - const hasMoreData = page * pageSize + pageSize < totalCount; - - if (!isLoading && isAsync && hasMoreData && thresholdReached) { - const newPage = page + 1; - fetchPage(inputValue, newPage); - } - }; - - const handleFilterOption = (search: string, option: AntdLabeledValue) => { - if (typeof filterOption === 'function') { - return filterOption(search, option); - } - - if (filterOption) { - const searchValue = search.trim().toLowerCase(); - if (optionFilterProps && optionFilterProps.length) { - return optionFilterProps.some(prop => { - const optionProp = option?.[prop] - ? String(option[prop]).trim().toLowerCase() - : ''; - return optionProp.includes(searchValue); - }); + setSelectValue(array); + } + } + setInputValue(''); + }; + + const handleOnSearch = (search: string) => { + const searchValue = search.trim(); + if (allowNewOptions && isSingleMode) { + const newOption = searchValue && + !hasOption(searchValue, fullSelectOptions, true) && { + label: searchValue, + value: searchValue, + isNewOption: true, + }; + const cleanSelectOptions = ensureIsArray(fullSelectOptions).filter( + opt => !opt.isNewOption || hasOption(opt.value, selectValue), + ); + const newOptions = newOption + ? [newOption, ...cleanSelectOptions] + : cleanSelectOptions; + setSelectOptions(newOptions); } - } + setInputValue(search); + }; - return false; - }; + const handleFilterOption = (search: string, option: AntdLabeledValue) => + handleFilterOptionHelper(search, option, optionFilterProps, filterOption); - const handleOnDropdownVisibleChange = (isDropdownVisible: boolean) => { - setIsDropdownVisible(isDropdownVisible); + const handleOnDropdownVisibleChange = (isDropdownVisible: boolean) => { + setIsDropdownVisible(isDropdownVisible); - if (isAsync) { - // loading is enabled when dropdown is open, - // disabled when dropdown is closed - if (loadingEnabled !== isDropdownVisible) { - setLoadingEnabled(isDropdownVisible); - } - // when closing dropdown, always reset loading state - if (!isDropdownVisible && isLoading) { - // delay is for the animation of closing the dropdown - // so the dropdown doesn't flash between "Loading..." and "No data" - // before closing. - setTimeout(() => { - setIsLoading(false); - }, 250); + // if no search input value, force sort options because it won't be sorted by + // `filterSort`. + if (isDropdownVisible && !inputValue && selectOptions.length > 1) { + if (!isEqual(initialOptionsSorted, selectOptions)) { + setSelectOptions(initialOptionsSorted); + } } - } - // if no search input value, force sort options because it won't be sorted by - // `filterSort`. - if (isDropdownVisible && !inputValue && selectOptions.length > 1) { - const sortedOptions = isAsync - ? selectOptions.slice().sort(sortComparatorForNoSearch) - : // if not in async mode, revert to the original select options - // (with selected options still sorted to the top) - initialOptionsSorted; - if (!isEqual(sortedOptions, selectOptions)) { - setSelectOptions(sortedOptions); + if (onDropdownVisibleChange) { + onDropdownVisibleChange(isDropdownVisible); } - } - - if (onDropdownVisibleChange) { - onDropdownVisibleChange(isDropdownVisible); - } - }; - - const dropdownRender = ( - originNode: ReactElement & { ref?: RefObject<HTMLElement> }, - ) => { - if (!isDropdownVisible) { - originNode.ref?.current?.scrollTo({ top: 0 }); - } - if (isLoading && fullSelectOptions.length === 0) { - return <StyledLoadingText>{t('Loading...')}</StyledLoadingText>; - } - return error ? <Error error={error} /> : originNode; - }; - - // use a function instead of component since every rerender of the - // Select component will create a new component - const getSuffixIcon = () => { - if (isLoading) { - return <StyledSpin size="small" />; - } - if (shouldShowSearch && isDropdownVisible) { - return <SearchOutlined />; - } - return <DownOutlined />; - }; - - const handleClear = () => { - setSelectValue(undefined); - if (onClear) { - onClear(); - } - }; - - useEffect(() => { - // when `options` list is updated from component prop, reset states - fetchedQueries.current.clear(); - setAllValuesLoaded(false); - setSelectOptions(initialOptions); - }, [initialOptions]); - - useEffect(() => { - setSelectValue(value); - }, [value]); - - // Stop the invocation of the debounced function after unmounting - useEffect( - () => () => { - debouncedFetchPage.cancel(); - }, - [debouncedFetchPage], - ); + }; + + const dropdownRender = ( + originNode: ReactElement & { ref?: RefObject<HTMLElement> }, + ) => + dropDownRenderHelper( + originNode, + isDropdownVisible, + isLoading, + fullSelectOptions.length, + helperText, + ); - useEffect(() => { - if (isAsync && loadingEnabled && allowFetch) { - // trigger fetch every time inputValue changes - if (inputValue) { - debouncedFetchPage(inputValue, 0); - } else { - fetchPage('', 0); + const handleClear = () => { + clear(); + if (onClear) { + onClear(); } - } - }, [ - isAsync, - loadingEnabled, - fetchPage, - allowFetch, - inputValue, - debouncedFetchPage, - ]); + }; - useEffect(() => { - if (loading !== undefined && loading !== isLoading) { - setIsLoading(loading); - } - }, [isLoading, loading]); + useEffect(() => { + // when `options` list is updated from component prop, reset states + setSelectOptions(initialOptions); + }, [initialOptions]); - return ( - <StyledContainer> - {header} - <StyledSelect - allowClear={!isLoading && allowClear} - aria-label={ariaLabel || name} - dropdownRender={dropdownRender} - filterOption={handleFilterOption} - filterSort={sortComparatorWithSearch} - getPopupContainer={triggerNode => triggerNode.parentNode} - labelInValue={isAsync || labelInValue} - maxTagCount={MAX_TAG_COUNT} - mode={mappedMode} - notFoundContent={isLoading ? t('Loading...') : notFoundContent} - onDeselect={handleOnDeselect} - onDropdownVisibleChange={handleOnDropdownVisibleChange} - onPopupScroll={isAsync ? handlePagination : undefined} - onSearch={shouldShowSearch ? handleOnSearch : undefined} - onSelect={handleOnSelect} - onClear={handleClear} - onChange={onChange} - options={hasCustomLabels ? undefined : fullSelectOptions} - placeholder={placeholder} - showSearch={shouldShowSearch} - showArrow - tokenSeparators={tokenSeparators || TOKEN_SEPARATORS} - value={selectValue} - suffixIcon={getSuffixIcon()} - menuItemSelectedIcon={ - invertSelection ? ( - <StyledStopOutlined iconSize="m" /> - ) : ( - <StyledCheckOutlined iconSize="m" /> + useEffect(() => { + if (loading !== undefined && loading !== isLoading) { + setIsLoading(loading); + } + }, [isLoading, loading]); + + useEffect(() => { + setSelectValue(value); + }, [value]); + + useEffect(() => { + // if all values are selected, add select all to value + if ( + !isSingleMode && + ensureIsArray(value).length === selectAllEligible.length && + selectOptions.length > 0 + ) { + setSelectValue( + labelInValue + ? ([...ensureIsArray(value), selectAllOption] as AntdLabeledValue[]) + : ([ + ...ensureIsArray(value), + SELECT_ALL_VALUE, + ] as AntdLabeledValue[]), + ); + } + }, [ + value, + isSingleMode, + labelInValue, + selectAllEligible.length, + selectOptions.length, + ]); + + useEffect(() => { + const checkSelectAll = ensureIsArray(selectValue).some( + v => getValue(v) === SELECT_ALL_VALUE, + ); + if (checkSelectAll && !selectAllMode) { + const optionsToSelect = selectAllEligible.map(option => + labelInValue ? option : option.value, + ); + optionsToSelect.push(labelInValue ? selectAllOption : SELECT_ALL_VALUE); + setSelectValue(optionsToSelect); + } + }, [selectValue, selectAllMode, labelInValue, selectAllEligible]); + + const selectAllLabel = useMemo( + () => () => + // TODO: localize + `${SELECT_ALL_VALUE} (${formatNumber( + NumberFormats.INTEGER, + selectAllEligible.length, + )})`, + [selectAllEligible], + ); + + const handleOnChange = (values: any, options: any) => { + // intercept onChange call to handle the select all case + // if the "select all" option is selected, we want to send all options to the onChange, + // otherwise we want to remove + let newValues = values; + let newOptions = options; + if (!isSingleMode) { + if ( + ensureIsArray(newValues).some( + val => getValue(val) === SELECT_ALL_VALUE, ) - } - ref={ref} - {...props} - > - {hasCustomLabels && - fullSelectOptions.map(opt => { - const isOptObject = typeof opt === 'object'; - const label = isOptObject ? opt?.label || opt.value : opt; - const value = isOptObject ? opt.value : opt; - const { customLabel, ...optProps } = opt; - return ( - <Option {...optProps} key={value} label={label} value={value}> - {isOptObject && customLabel ? customLabel : label} - </Option> + ) { + // send all options to onchange if all are not currently there + if (!selectAllMode) { + newValues = mapValues(selectAllEligible, labelInValue); + newOptions = mapOptions(selectAllEligible); + } else { + newValues = ensureIsArray(values).filter( + (val: any) => getValue(val) !== SELECT_ALL_VALUE, ); - })} - </StyledSelect> - </StyledContainer> - ); -}; + } + } else if ( + ensureIsArray(values).length === selectAllEligible.length && + selectAllMode + ) { + const array = selectAllEligible.filter( + option => hasOption(option.value, selectValue) && option.disabled, + ); + newValues = mapValues(array, labelInValue); + newOptions = mapOptions(array); + } + } + onChange?.(newValues, newOptions); + }; + + const customMaxTagPlaceholder = () => { + const num_selected = ensureIsArray(selectValue).length; + const num_shown = maxTagCount as number; + return selectAllMode + ? `+ ${num_selected - num_shown - 1} ...` + : `+ ${num_selected - num_shown} ...`; + }; + + return ( + <StyledContainer headerPosition={headerPosition}> + {header && ( + <StyledHeader headerPosition={headerPosition}>{header}</StyledHeader> + )} + <StyledSelect + allowClear={!isLoading && allowClear} + aria-label={ariaLabel || name} + dropdownRender={dropdownRender} + filterOption={handleFilterOption} + filterSort={sortComparatorWithSearch} + getPopupContainer={ + getPopupContainer || (triggerNode => triggerNode.parentNode) + } + headerPosition={headerPosition} + labelInValue={labelInValue} + maxTagCount={maxTagCount} + maxTagPlaceholder={customMaxTagPlaceholder} + mode={mappedMode} + notFoundContent={isLoading ? t('Loading...') : notFoundContent} + onDeselect={handleOnDeselect} + onDropdownVisibleChange={handleOnDropdownVisibleChange} + onPopupScroll={undefined} + onSearch={shouldShowSearch ? handleOnSearch : undefined} + onSelect={handleOnSelect} + onClear={handleClear} + onChange={handleOnChange} + placeholder={placeholder} + showSearch={shouldShowSearch} + showArrow + tokenSeparators={tokenSeparators || TOKEN_SEPARATORS} + value={selectValue} + suffixIcon={getSuffixIcon( + isLoading, + shouldShowSearch, + isDropdownVisible, + )} + menuItemSelectedIcon={ + invertSelection ? ( + <StyledStopOutlined iconSize="m" aria-label="stop" /> + ) : ( + <StyledCheckOutlined iconSize="m" aria-label="check" /> + ) + } + oneLine={oneLine} + tagRender={customTagRender} + {...props} + ref={ref} + > + {selectAllEnabled && ( + <Option + id="select-all" + className="select-all" + key={SELECT_ALL_VALUE} + value={SELECT_ALL_VALUE} + > + {selectAllLabel()} + </Option> + )} + {renderSelectOptions(fullSelectOptions)} + </StyledSelect> + </StyledContainer> + ); + }, +); -export default forwardRef(Select); +export default Select; diff --git a/superset-frontend/src/components/Select/constants.ts b/superset-frontend/src/components/Select/constants.ts new file mode 100644 index 0000000000000..63218d9b712ed --- /dev/null +++ b/superset-frontend/src/components/Select/constants.ts @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { LabeledValue as AntdLabeledValue } from 'antd/lib/select'; +import { rankedSearchCompare } from 'src/utils/rankedSearchCompare'; + +export const MAX_TAG_COUNT = 4; + +export const TOKEN_SEPARATORS = [',', '\r\n', '\n', '\t', ';']; + +export const EMPTY_OPTIONS = []; + +export const DEFAULT_PAGE_SIZE = 100; + +export const DEFAULT_SORT_COMPARATOR = ( + a: AntdLabeledValue, + b: AntdLabeledValue, + search?: string, +) => { + let aText: string | undefined; + let bText: string | undefined; + if (typeof a.label === 'string' && typeof b.label === 'string') { + aText = a.label; + bText = b.label; + } else if (typeof a.value === 'string' && typeof b.value === 'string') { + aText = a.value; + bText = b.value; + } + // sort selected options first + if (typeof aText === 'string' && typeof bText === 'string') { + if (search) { + return rankedSearchCompare(aText, bText, search); + } + return aText.localeCompare(bText); + } + return (a.value as number) - (b.value as number); +}; diff --git a/superset-frontend/src/components/Select/styles.tsx b/superset-frontend/src/components/Select/styles.tsx index f04cfbdba9eda..cf9613d1c8e8c 100644 --- a/superset-frontend/src/components/Select/styles.tsx +++ b/superset-frontend/src/components/Select/styles.tsx @@ -16,391 +16,123 @@ * specific language governing permissions and limitations * under the License. */ - -// Deprecated component -/* eslint-disable theme-colors/no-literal-colors */ - -import React, { CSSProperties, ComponentType, ReactNode } from 'react'; -import { SerializedStyles } from '@emotion/react'; -import { SupersetTheme, css } from '@superset-ui/core'; -import { - Styles, - Theme, - SelectComponentsConfig, - components as defaultComponents, - InputProps as ReactSelectInputProps, - Props as SelectProps, -} from 'react-select'; -import type { colors as reactSelectColors } from 'react-select/src/theme'; -import type { DeepNonNullable } from 'react-select/src/components'; -import { OptionType } from 'antd/lib/select'; -import { SupersetStyledSelectProps } from './DeprecatedSelect'; - -export const DEFAULT_CLASS_NAME = 'Select'; -export const DEFAULT_CLASS_NAME_PREFIX = 'Select'; - -type RecursivePartial<T> = { - [P in keyof T]?: RecursivePartial<T[P]>; -}; - -const colors = (theme: SupersetTheme) => ({ - primary: theme.colors.success.base, - danger: theme.colors.error.base, - warning: theme.colors.warning.base, - indicator: theme.colors.info.base, - almostBlack: theme.colors.grayscale.dark1, - grayDark: theme.colors.grayscale.dark1, - grayLight: theme.colors.grayscale.light2, - gray: theme.colors.grayscale.light1, - grayBg: theme.colors.grayscale.light4, - grayBgDarker: theme.colors.grayscale.light3, - grayBgDarkest: theme.colors.grayscale.light2, - grayHeading: theme.colors.grayscale.light1, - menuHover: theme.colors.grayscale.light3, - lightest: theme.colors.grayscale.light5, - darkest: theme.colors.grayscale.dark2, - grayBorder: theme.colors.grayscale.light2, - grayBorderLight: theme.colors.grayscale.light3, - grayBorderDark: theme.colors.grayscale.light1, - textDefault: theme.colors.grayscale.dark1, - textDarkest: theme.colors.grayscale.dark2, - dangerLight: theme.colors.error.light1, -}); - -export type ThemeConfig = { - borderRadius: number; - // z-index for menu dropdown - // (the same as `@z-index-above-dashboard-charts + 1` in variables.less) - zIndex: number; - colors: { - // add known colors - [key in keyof typeof reactSelectColors]: string; - } & { - [key in keyof ReturnType<typeof colors>]: string; - } & { - [key: string]: string; // any other colors - }; - spacing: Theme['spacing'] & { - // line height and font size must be pixels for easier computation - // of option item height in WindowedMenuList - lineHeight: number; - fontSize: number; - // other relative size must be string - minWidth: string; - }; -}; - -export type PartialThemeConfig = RecursivePartial<ThemeConfig>; - -export const defaultTheme: (theme: SupersetTheme) => PartialThemeConfig = - theme => ({ - borderRadius: theme.borderRadius, - zIndex: 11, - colors: colors(theme), - spacing: { - baseUnit: 3, - menuGutter: 0, - controlHeight: 34, - lineHeight: 19, - fontSize: 14, - minWidth: '6.5em', - }, - weights: theme.typography.weights, - }); - -// let styles accept serialized CSS, too -type CSSStyles = CSSProperties | SerializedStyles; -type styleFnWithSerializedStyles = ( - base: CSSProperties, - state: any, -) => CSSStyles | CSSStyles[]; - -export type StylesConfig = { - [key in keyof Styles]: styleFnWithSerializedStyles; -}; -export type PartialStylesConfig = Partial<StylesConfig>; - -export const DEFAULT_STYLES: PartialStylesConfig = { - container: ( - provider, - { - theme: { - spacing: { minWidth }, - }, - }, - ) => [ - provider, - css` - min-width: ${minWidth}; - `, - ], - placeholder: provider => [ - provider, - css` - white-space: nowrap; - `, - ], - indicatorSeparator: () => css` - display: none; - `, - indicatorsContainer: provider => [ - provider, - css` - i { - width: 1em; - display: inline-block; - } - `, - ], - clearIndicator: provider => [ - provider, - css` - padding: 4px 0 4px 6px; - `, - ], - control: ( - provider, - { isFocused, menuIsOpen, theme: { borderRadius, colors } }, - ) => { - const isPseudoFocused = isFocused && !menuIsOpen; - let borderColor = colors.grayBorder; - if (isPseudoFocused || menuIsOpen) { - borderColor = colors.grayBorderDark; +import { styled } from '@superset-ui/core'; +import Icons from 'src/components/Icons'; +import { Spin, Tag } from 'antd'; +import AntdSelect from 'antd/lib/select'; + +export const StyledHeader = styled.span<{ headerPosition: string }>` + ${({ theme, headerPosition }) => ` + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin-right: ${headerPosition === 'left' ? theme.gridUnit * 2 : 0}px; + `} +`; + +export const StyledContainer = styled.div<{ headerPosition: string }>` + ${({ headerPosition }) => ` + display: flex; + flex-direction: ${headerPosition === 'top' ? 'column' : 'row'}; + align-items: ${headerPosition === 'left' ? 'center' : undefined}; + width: 100%; + `} +`; + +export const StyledSelect = styled(AntdSelect, { + shouldForwardProp: prop => prop !== 'headerPosition' && prop !== 'oneLine', +})<{ headerPosition: string; oneLine?: boolean }>` + ${({ theme, headerPosition, oneLine }) => ` + flex: ${headerPosition === 'left' ? 1 : 0}; + && .ant-select-selector { + border-radius: ${theme.gridUnit}px; } - return [ - provider, - css` - border-color: ${borderColor}; - box-shadow: ${isPseudoFocused - ? 'inset 0 1px 1px rgba(0,0,0,.075), 0 0 0 3px rgba(0,0,0,.1)' - : 'none'}; - border-radius: ${menuIsOpen - ? `${borderRadius}px ${borderRadius}px 0 0` - : `${borderRadius}px`}; - &:hover { - border-color: ${borderColor}; - box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06); - } - flex-wrap: nowrap; - padding-left: 1px; - `, - ]; - }, - menu: (provider, { theme: { zIndex } }) => [ - provider, - css` - padding-bottom: 2em; - z-index: ${zIndex}; /* override at least multi-page pagination */ - width: auto; - min-width: 100%; - max-width: 80vw; - background: none; - box-shadow: none; - border: 0; - `, - ], - menuList: (provider, { theme: { borderRadius, colors } }) => [ - provider, - css` - background: ${colors.lightest}; - border-radius: 0 0 ${borderRadius}px ${borderRadius}px; - border: 1px solid ${colors.grayBorderDark}; - box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06); - margin-top: -1px; - border-top-color: ${colors.grayBorderLight}; - min-width: 100%; - width: auto; - border-radius: 0 0 ${borderRadius}px ${borderRadius}px; - padding-top: 0; - padding-bottom: 0; - `, - ], - option: ( - provider, - { - isDisabled, - isFocused, - isSelected, - theme: { - colors, - spacing: { lineHeight, fontSize }, - weights, - }, - }, - ) => { - let color = colors.textDefault; - let backgroundColor = colors.lightest; - if (isFocused) { - backgroundColor = colors.grayBgDarker; - } else if (isDisabled) { - color = '#ccc'; + // Open the dropdown when clicking on the suffix + // This is fixed in version 4.16 + .ant-select-arrow .anticon:not(.ant-select-suffix) { + pointer-events: none; + } + .select-all { + border-bottom: 1px solid ${theme.colors.grayscale.light3}; } - return [ - provider, - css` - cursor: pointer; - line-height: ${lineHeight}px; - font-size: ${fontSize}px; - background-color: ${backgroundColor}; - color: ${color}; - font-weight: ${isSelected ? weights.bold : weights.normal}; - white-space: nowrap; - &:hover:active { - background-color: ${colors.grayBg}; + ${ + oneLine && + ` + .ant-select-selection-overflow { + flex-wrap: nowrap; } - `, - ]; - }, - valueContainer: ( - provider, - { - isMulti, - hasValue, - theme: { - spacing: { baseUnit }, - }, - }, - ) => [ - provider, - css` - padding-left: ${isMulti && hasValue ? 1 : baseUnit * 3}px; - `, - ], - multiValueLabel: ( - provider, - { - theme: { - spacing: { baseUnit }, - }, - }, - ) => ({ - ...provider, - paddingLeft: baseUnit * 1.2, - paddingRight: baseUnit * 1.2, - }), - input: (provider, { selectProps }) => [ - provider, - css` - margin-left: 0; - vertical-align: middle; - ${selectProps?.isMulti && selectProps?.value?.length - ? 'padding: 0 6px; width: 100%' - : 'padding: 0; flex: 1 1 auto;'}; - `, - ], - menuPortal: base => ({ - ...base, - zIndex: 1030, // must be same or higher of antd popover - }), -}; - -const INPUT_TAG_BASE_STYLES = { - background: 'none', - border: 'none', - outline: 'none', - padding: 0, -}; - -export type SelectComponentsType = Omit< - SelectComponentsConfig<any>, - 'Input' -> & { - Input: ComponentType<InputProps>; -}; - -// react-select is missing selectProps from their props type -// so overwriting it here to avoid errors -export type InputProps = ReactSelectInputProps & { - placeholder?: ReactNode; - selectProps: SelectProps; - autoComplete?: string; - onPaste?: SupersetStyledSelectProps<OptionType>['onPaste']; - inputStyle?: object; -}; -const { ClearIndicator, DropdownIndicator, Option, Input, SelectContainer } = - defaultComponents as Required<DeepNonNullable<SelectComponentsType>>; - -export const DEFAULT_COMPONENTS: SelectComponentsType = { - SelectContainer: ({ children, ...props }) => { - const { - selectProps: { assistiveText }, - } = props; - return ( - <div> - <SelectContainer {...props}>{children}</SelectContainer> - {assistiveText && ( - <span - css={(theme: SupersetTheme) => ({ - marginLeft: 3, - fontSize: theme.typography.sizes.s, - color: theme.colors.grayscale.light1, - })} - > - {assistiveText} - </span> - )} - </div> - ); - }, - Option: ({ children, innerProps, data, ...props }) => ( - <Option - {...props} - data={data} - css={data?.style ? data.style : null} - innerProps={innerProps} - > - {children} - </Option> - ), - ClearIndicator: props => ( - <ClearIndicator {...props}> - <i className="fa">×</i> - </ClearIndicator> - ), - DropdownIndicator: props => ( - <DropdownIndicator {...props}> - <i - className={`fa fa-caret-${ - props.selectProps.menuIsOpen ? 'up' : 'down' - }`} - /> - </DropdownIndicator> - ), - Input: (props: InputProps) => { - const { getStyles } = props; - return ( - <Input - {...props} - css={getStyles('input', props)} - autoComplete="chrome-off" - inputStyle={INPUT_TAG_BASE_STYLES} - /> - ); - }, -}; + .ant-select-selection-overflow-item:not(.ant-select-selection-overflow-item-rest):not(.ant-select-selection-overflow-item-suffix) { + flex-shrink: 1; + min-width: ${theme.gridUnit * 13}px; + } -export const VALUE_LABELED_STYLES: PartialStylesConfig = { - valueContainer: ( - provider, - { - getValue, - theme: { - spacing: { baseUnit }, - }, - isMulti, - }, - ) => ({ - ...provider, - paddingLeft: getValue().length > 0 ? 1 : baseUnit * 3, - overflow: isMulti && getValue().length > 0 ? 'visible' : 'hidden', - }), - // render single value as is they are multi-value - singleValue: (provider, props) => { - const { getStyles } = props; - return { - ...getStyles('multiValue', props), - '.metric-option': getStyles('multiValueLabel', props), + .ant-select-selection-overflow-item-suffix { + flex: unset; + min-width: 0px; + } + ` }; - }, -}; + `} +`; + +export const NoElement = styled.span` + display: none; +`; + +export const StyledTag = styled(Tag)` + ${({ theme }) => ` + background: ${theme.colors.grayscale.light3}; + font-size: ${theme.typography.sizes.m}px; + border: none; + `} +`; + +export const StyledStopOutlined = styled(Icons.StopOutlined)` + vertical-align: 0; +`; + +export const StyledCheckOutlined = styled(Icons.CheckOutlined)` + vertical-align: 0; +`; + +export const StyledSpin = styled(Spin)` + margin-top: ${({ theme }) => -theme.gridUnit}px; +`; + +export const StyledLoadingText = styled.div` + ${({ theme }) => ` + margin-left: ${theme.gridUnit * 3}px; + line-height: ${theme.gridUnit * 8}px; + color: ${theme.colors.grayscale.light1}; + `} +`; + +export const StyledHelperText = styled.div` + ${({ theme }) => ` + padding: ${theme.gridUnit * 2}px ${theme.gridUnit * 3}px; + color: ${theme.colors.grayscale.base}; + font-size: ${theme.typography.sizes.s}px; + cursor: default; + border-bottom: 1px solid ${theme.colors.grayscale.light2}; + `} +`; + +export const StyledError = styled.div` + ${({ theme }) => ` + display: flex; + justify-content: center; + align-items: flex-start; + width: 100%; + padding: ${theme.gridUnit * 2}px; + color: ${theme.colors.error.base}; + & svg { + margin-right: ${theme.gridUnit * 2}px; + } + `} +`; + +export const StyledErrorMessage = styled.div` + overflow: hidden; + text-overflow: ellipsis; +`; diff --git a/superset-frontend/src/components/Select/types.ts b/superset-frontend/src/components/Select/types.ts new file mode 100644 index 0000000000000..6e4c7f072db80 --- /dev/null +++ b/superset-frontend/src/components/Select/types.ts @@ -0,0 +1,217 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + JSXElementConstructor, + ReactElement, + ReactNode, + RefObject, +} from 'react'; +import { + SelectProps as AntdSelectProps, + SelectValue as AntdSelectValue, + LabeledValue as AntdLabeledValue, +} from 'antd/lib/select'; +import { TagProps } from 'antd/lib/tag'; + +export type RawValue = string | number; + +export type V = string | number | null | undefined; + +export type LabeledValue = { label?: ReactNode; value?: V }; + +export type AntdProps = AntdSelectProps<AntdSelectValue>; + +export type AntdExposedProps = Pick< + AntdProps, + | 'allowClear' + | 'autoFocus' + | 'disabled' + | 'filterOption' + | 'filterSort' + | 'loading' + | 'labelInValue' + | 'maxTagCount' + | 'notFoundContent' + | 'onChange' + | 'onClear' + | 'onDeselect' + | 'onSelect' + | 'onFocus' + | 'onBlur' + | 'onPopupScroll' + | 'onSearch' + | 'onDropdownVisibleChange' + | 'placeholder' + | 'showArrow' + | 'showSearch' + | 'tokenSeparators' + | 'value' + | 'getPopupContainer' + | 'menuItemSelectedIcon' +>; + +export type SelectOptionsType = Exclude<AntdProps['options'], undefined>; + +export interface BaseSelectProps extends AntdExposedProps { + /** + * It enables the user to create new options. + * Can be used with standard or async select types. + * Can be used with any mode, single or multiple. + * False by default. + * */ + allowNewOptions?: boolean; + /** + * It adds the aria-label tag for accessibility standards. + * Must be plain English and localized. + */ + ariaLabel?: string; + /** + * Renders the dropdown + */ + dropdownRender?: ( + menu: ReactElement<any, string | JSXElementConstructor<any>>, + ) => ReactElement<any, string | JSXElementConstructor<any>>; + /** + * It adds a header on top of the Select. + * Can be any ReactNode. + */ + header?: ReactNode; + /** + * It changes the position of the header. + */ + headerPosition?: 'top' | 'left'; + /** + * It adds a helper text on top of the Select options + * with additional context to help with the interaction. + */ + helperText?: string; + /** + * It allows to define which properties of the option object + * should be looked for when searching. + * By default label and value. + */ + mappedMode?: 'multiple' | 'tags'; + /** + * It defines whether the Select should allow for the + * selection of multiple options or single. + * Single by default. + */ + mode?: 'single' | 'multiple'; + /** + * Deprecated. + * Prefer ariaLabel instead. + */ + name?: string; // discourage usage + /** + * It allows to define which properties of the option object + * should be looked for when searching. + * By default label and value. + */ + optionFilterProps?: string[]; + /** + * It shows a stop-outlined icon at the far right of a selected + * option instead of the default checkmark. + * Useful to better indicate to the user that by clicking on a selected + * option it will be de-selected. + * False by default. + */ + invertSelection?: boolean; + /** + * Customize how filtered options are sorted while users search. + * Will not apply to predefined `options` array when users are not searching. + */ + sortComparator?: ( + a: AntdLabeledValue, + b: AntdLabeledValue, + search?: string, + ) => number; + /** + * Sets maxTagCount to 1. The overflow tag is always displayed in + * the same line, line wrapping is disabled. + * When the dropdown is open, sets maxTagCount to 0, + * displays only the overflow tag. + */ + oneLine?: boolean; + + suffixIcon?: ReactNode; + + ref: RefObject<HTMLInputElement>; +} + +export interface SelectProps extends BaseSelectProps { + /** + * It defines the options of the Select. + * The options can be static, an array of options. + */ + options: SelectOptionsType; +} + +export type AsyncSelectRef = HTMLInputElement & { clearCache: () => void }; + +export type SelectOptionsTypePage = { + data: SelectOptionsType; + totalCount: number; +}; + +export type SelectOptionsPagePromise = ( + search: string, + page: number, + pageSize: number, +) => Promise<SelectOptionsTypePage>; + +export interface AsyncSelectProps extends BaseSelectProps { + /** + * It fires a request against the server after + * the first interaction and not on render. + * Works in async mode only (See the options property). + * True by default. + */ + lazyLoading?: boolean; + /** + * It defines the options of the Select. + * The options are async, a promise that returns + * an array of options. + */ + options: SelectOptionsPagePromise; + /** + * It defines how many results should be included + * in the query response. + * Works in async mode only (See the options property). + */ + pageSize?: number; + /** + * It fires a request against the server only after + * searching. + * Works in async mode only (See the options property). + * Undefined by default. + */ + fetchOnlyOnSearch?: boolean; + /** + * It provides a callback function when an error + * is generated after a request is fired. + * Works in async mode only (See the options property). + */ + onError?: (error: string) => void; +} + +export type CustomTagProps = HTMLSpanElement & + TagProps & { + label: ReactNode; + value: string; + }; diff --git a/superset-frontend/src/components/Select/utils.tsx b/superset-frontend/src/components/Select/utils.tsx new file mode 100644 index 0000000000000..d6d352132fcc8 --- /dev/null +++ b/superset-frontend/src/components/Select/utils.tsx @@ -0,0 +1,224 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { ensureIsArray, t } from '@superset-ui/core'; +import AntdSelect, { LabeledValue as AntdLabeledValue } from 'antd/lib/select'; +import React, { ReactElement, RefObject } from 'react'; +import Icons from 'src/components/Icons'; +import { StyledHelperText, StyledLoadingText, StyledSpin } from './styles'; +import { LabeledValue, RawValue, SelectOptionsType, V } from './types'; + +const { Option } = AntdSelect; + +export const SELECT_ALL_VALUE: RawValue = 'Select All'; +export const selectAllOption = { + value: SELECT_ALL_VALUE, + label: String(SELECT_ALL_VALUE), +}; + +export function isObject(value: unknown): value is Record<string, unknown> { + return ( + value !== null && + typeof value === 'object' && + Array.isArray(value) === false + ); +} + +export function isLabeledValue(value: unknown): value is AntdLabeledValue { + return isObject(value) && 'value' in value && 'label' in value; +} + +export function getValue( + option: string | number | AntdLabeledValue | null | undefined, +) { + return isLabeledValue(option) ? option.value : option; +} + +export function hasOption( + value: V, + options?: V | LabeledValue | (V | LabeledValue)[], + checkLabel = false, +): boolean { + const optionsArray = ensureIsArray(options); + // When comparing the values we use the equality + // operator to automatically convert different types + return ( + optionsArray.find( + x => + // eslint-disable-next-line eqeqeq + x == value || + (isObject(x) && + // eslint-disable-next-line eqeqeq + (('value' in x && x.value == value) || + (checkLabel && 'label' in x && x.label === value))), + ) !== undefined + ); +} + +/** + * It creates a comparator to check for a specific property. + * Can be used with string and number property values. + * */ +export const propertyComparator = + (property: string) => (a: AntdLabeledValue, b: AntdLabeledValue) => { + if (typeof a[property] === 'string' && typeof b[property] === 'string') { + return a[property].localeCompare(b[property]); + } + return (a[property] as number) - (b[property] as number); + }; + +export const sortSelectedFirstHelper = ( + a: AntdLabeledValue, + b: AntdLabeledValue, + selectValue: + | string + | number + | RawValue[] + | AntdLabeledValue + | AntdLabeledValue[] + | undefined, +) => + selectValue && a.value !== undefined && b.value !== undefined + ? Number(hasOption(b.value, selectValue)) - + Number(hasOption(a.value, selectValue)) + : 0; + +export const sortComparatorWithSearchHelper = ( + a: AntdLabeledValue, + b: AntdLabeledValue, + inputValue: string, + sortCallback: (a: AntdLabeledValue, b: AntdLabeledValue) => number, + sortComparator: ( + a: AntdLabeledValue, + b: AntdLabeledValue, + search?: string | undefined, + ) => number, +) => sortCallback(a, b) || sortComparator(a, b, inputValue); + +export const sortComparatorForNoSearchHelper = ( + a: AntdLabeledValue, + b: AntdLabeledValue, + sortCallback: (a: AntdLabeledValue, b: AntdLabeledValue) => number, + sortComparator: ( + a: AntdLabeledValue, + b: AntdLabeledValue, + search?: string | undefined, + ) => number, +) => sortCallback(a, b) || sortComparator(a, b, ''); + +// use a function instead of component since every rerender of the +// Select component will create a new component +export const getSuffixIcon = ( + isLoading: boolean | undefined, + showSearch: boolean, + isDropdownVisible: boolean, +) => { + if (isLoading) { + return <StyledSpin size="small" />; + } + if (showSearch && isDropdownVisible) { + return <Icons.SearchOutlined iconSize="s" />; + } + return <Icons.DownOutlined iconSize="s" />; +}; + +export const dropDownRenderHelper = ( + originNode: ReactElement & { ref?: RefObject<HTMLElement> }, + isDropdownVisible: boolean, + isLoading: boolean | undefined, + optionsLength: number, + helperText: string | undefined, + errorComponent?: JSX.Element, +) => { + if (!isDropdownVisible) { + originNode.ref?.current?.scrollTo({ top: 0 }); + } + if (isLoading && optionsLength === 0) { + return <StyledLoadingText>{t('Loading...')}</StyledLoadingText>; + } + if (errorComponent) { + return errorComponent; + } + return ( + <> + {helperText && ( + <StyledHelperText role="note">{helperText}</StyledHelperText> + )} + {originNode} + </> + ); +}; + +export const handleFilterOptionHelper = ( + search: string, + option: AntdLabeledValue, + optionFilterProps: string[], + filterOption: boolean | Function, +) => { + if (typeof filterOption === 'function') { + return filterOption(search, option); + } + + if (filterOption) { + const searchValue = search.trim().toLowerCase(); + if (optionFilterProps?.length) { + return optionFilterProps.some(prop => { + const optionProp = option?.[prop] + ? String(option[prop]).trim().toLowerCase() + : ''; + return optionProp.includes(searchValue); + }); + } + } + + return false; +}; + +export const hasCustomLabels = (options: SelectOptionsType) => + options?.some(opt => !!opt?.customLabel); + +export const renderSelectOptions = (options: SelectOptionsType) => + options.map(opt => { + const isOptObject = typeof opt === 'object'; + const label = isOptObject ? opt?.label || opt.value : opt; + const value = isOptObject ? opt.value : opt; + const { customLabel, ...optProps } = opt; + return ( + <Option {...optProps} key={value} label={label} value={value}> + {isOptObject && customLabel ? customLabel : label} + </Option> + ); + }); + +export const mapValues = (values: SelectOptionsType, labelInValue: boolean) => + labelInValue + ? values.map(opt => ({ + key: opt.value, + value: opt.value, + label: opt.label, + })) + : values.map(opt => opt.value); + +export const mapOptions = (values: SelectOptionsType) => + values.map(opt => ({ + children: opt.label, + key: opt.value, + value: opt.value, + label: opt.label, + disabled: opt.disabled, + })); diff --git a/superset-frontend/src/components/Table/Table.overview.mdx b/superset-frontend/src/components/Table/Table.overview.mdx new file mode 100644 index 0000000000000..2fa1455cd0eda --- /dev/null +++ b/superset-frontend/src/components/Table/Table.overview.mdx @@ -0,0 +1,339 @@ +import { Meta, Source, Story, ArgsTable } from '@storybook/addon-docs'; + +<Meta title="Design System/Components/Table/Overview" /> + +# Table + +A table is UI that allows the user to explore data in a tabular format. + +## Usage + +Common table applications in Superset: + +- Display lists of user-generated entities (e.g. dashboard, charts, queries) for further exploration and use +- Display data that can help the user make a decision (e.g. query results) + +This component provides a general use Table. + +--- + +### [Basic example](./?path=/docs/design-system-components-table-examples--basic) + +<Story id="design-system-components-table-examples--basic" /> + +### Data and Columns + +To set the visible columns and data for the table you use the `columns` and `data` props. + +<details> + +The basic table example for the `columns` prop is: + +``` +const basicColumns: = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name', + width: 150, + sorter: (a: BasicData, b: BasicData) => + alphabeticalSort('name', a, b), + }, + { + title: 'Category', + dataIndex: 'category', + key: 'category', + sorter: (a: BasicData, b: BasicData) => + alphabeticalSort('category', a, b), + }, + { + title: 'Price', + dataIndex: 'price', + key: 'price', + sorter: (a: BasicData, b: BasicData) => + numericalSort('price', a, b), + }, + { + title: 'Description', + dataIndex: 'description', + key: 'description', + }, +]; +``` + +The data prop is: + +``` +const basicData: = [ + { + key: 1, + name: 'Floppy Disk 10 pack', + category: 'Disk Storage', + price: '9.99' + description: 'A real blast from the past', + }, + { + key: 2, + name: 'DVD 100 pack', + category: 'Optical Storage', + price: '27.99' + description: 'Still pretty ancient', + }, + { + key: 3, + name: '128 GB SSD', + category: 'Hardrive', + price: '49.99' + description: 'Reliable and fast data storage', + }, +]; +``` + +</details> + +### Column Sort Functions + +To ensure consistency for column sorting and to avoid redundant definitions for common column sorters, reusable sort functions are provided. +When defining the object for the `columns` prop you can provide an optional attribute `sorter`. +The function provided in the `sorter` prop is given the entire record representing a row as props `a` and `b`. +When using a provided sorter function the pattern is to wrap the call to the sorter with an inline function, then specify the specific attribute value from `dataIndex`, representing a column +of the data object for that row, as the first argument of the sorter function. + +#### alphabeticalSort + +The alphabeticalSort is for columns that display a string of text. + +<details> + +``` +import { alphabeticalSort } from 'src/components/Table/sorters'; + +const basicColumns = [ + { + title: 'Column Name', + dataIndex: 'columnName', + key: 'columnName', + sorter: (a, b) => + alphabeticalSort('columnName', a, b), + } +] +``` + +</details> + +#### numericSort + +The numericalSort is for columns that display a numeric value. + +<details> + +``` +import { numericalSort } from './sorters'; + +const basicColumns = [ + { + title: 'Height', + dataIndex: 'height', + key: 'height', + sorter: (a, b) => + numericalSort('height', a, b), + } +] +``` + +</details> + +If a different sort option is needed, consider adding it as a reusable sort function following the pattern provided above. + +--- + +### Cell Content Renderers + +By default, each column will render the value as simple text. Often you will want to show formatted values, such as a numeric column showing as currency, or a more complex component such as a button or action menu as a cell value. +Cell Renderers are React components provided to the optional `render` attribute on a column definition that enables injecting a specific React component to enable this. + +<Story id="design-system-components-table-examples--cell-renderers" /> + +For convenience and consistency, the Table component provides pre-built Cell Renderers for: +The following data types can be displayed in table cells. + +- Text (default) +- [Button Cell](./?path=/docs/design-system-components-table-cell-renderers-buttoncell--basic) +- [Numeric Cell](./docs/design-system-components-table-cell-renderers-numericcell--basic) + - Support Locale and currency formatting + - w/ icons - Coming Soon +- [Action Menu Cell](./?path=/docs/design-system-components-table-cell-renderers-actioncell-overview--page) +- Provide a list of menu options with callback functions that retain a reference to the row the menu is defined for +- Custom + - You can provide your own React component as a cell renderer in cases not supported + +--- + +### Loading + +The table can be set to a loading state simply by setting the loading prop to true | false + +<Story id="design-system-components-table-examples--loading" /> + +--- + +### Pagination + +The table displays a set number of rows at a time, the user navigates the table via pagination. Use in scenarios where the user is searching for a specific piece of content. +The default page size and page size options for the menu are configurable via the `pageSizeOptions` and `defaultPageSize` props. +NOTE: Pagination controls will only display when the data for the table has more records than the default page size. + +<Story id="design-system-components-table-examples--pagination" /> + +``` +<Table pageSizeOptions={[5, 10, 15, 20, 25] defaultPageSize={10} /> +``` + +--- + +### Server Pagination + +The table can be configured for async data fetching to get partial data sets while showing pagination controls that let the user navigate through data. +To override the default paging, which uses `data.length` to determine the record count, populate the `recordCount` prop with the total number of records +contained in the dataset on the server being paged through. When the user navigates through the paged data it will invoke the `onChange` callback +function enabling data fetching to occur when the user changes the page. + +<Story id="design-system-components-table-examples--server-pagination" /> + +``` +interface BasicData { + name: string; + category: string; + price: number; + description?: string; + key: number; +} + +const generateData = (startIndex: number, pageSize: number): BasicData[] => { + const data: BasicData[] = []; + for (let i = 0; i < pageSize; i += 1) { + const recordIndex = startIndex + i; + data.push({ + key: recordIndex, + name: `Dynamic Record ${recordIndex}`, + category: 'Disk Storage', + price: recordIndex * 2.59, + description: 'A random description', + }); + } + return data; +}; + +const ServerPaginationTable = () => { + const [data, setData] = useState(generateData(0, 5)); + const [loading, setLoading] = useState(false); + // This should really be calculated server side for the data set being paged through + const recordCount = 5000; + + const handleChange = (pagination: TablePaginationConfig) => { + const pageSize = pagination?.pageSize ?? 5; + const current = pagination?.current ?? 0; + setLoading(true); + // simulate a fetch + setTimeout(() => { + setData(generateData(current * pageSize, pageSize)); + setLoading(false); + }, 1000); + }; + + return ( + <Table + columns: paginationColumns, + size: TableSize.SMALL, + pageSizeOptions: ['10', '20', '50'], + defaultPageSize: 10, + data={data} + recordCount={5000} + onChange={handleChange} + loading={loading} + /> + ); +}; +``` + +--- + +### Virtualization for Performance + +Table virtualization can enable viewing data with many columns and/or rows. +Virtualization can be enabled via the `virtualize` prop. + +NOTE: Row event handlers will be ignored when table is running with `virtualize={true}`. +Support for row event handlers may be added in future versions of the Table. + +<Story id="design-system-components-table-examples--virtualized-performance" /> + +--- + +## Integration Checklist + +The following specifications are required every time a table is used. These choices should be intentional based on the specific user needs for the table instance. + +<details> + +- [ ] Size + - Large + - Small +- Columns + - [ ] Number of + - [ ] Contents + - [ ] Order + - [ ] Widths +- Column headers + - [ ] Labels + - [ ] Has tooltip + - [ ] Tooltip text +- [ ] Default sort +- Functionality + - [ ] Can sort columns + - [ ] Can filter columns +- [ ] Loading + - Pagination + - [ ] Number of rows per page + - Infinite scroll +- [ ] Has toolbar + - [ ] Has table title + - [ ] Label + - [ ] Has buttons + - [ ] Labels + - [ ] Actions + - [ ] Has search + +</details> + +--- + +## Experimental features + +The Table component has features that are still experimental and can be used at your own risk. +These features are intended to be made fully stable in future releases. + +### Resizable Columns + +The prop `resizable` enables table columns to be resized by the user dragging from the right edge of each +column to increase or decrease the columns' width + +<Story id="design-system-components-table-examples--resizable-columns" /> + +### Drag & Drop Columns + +The prop `reorderable` can enable column drag and drop reordering as well as dragging a column to another component. If you want to accept the drop event of a Table Column +you can register `onDragOver` and `onDragDrop` event handlers on the destination component. In the `onDragDrop` handler you can check for `SUPERSET_TABLE_COLUMN` +as the getData key as shown below. + +``` +import { SUPERSET_TABLE_COLUMN } from 'src/components/table'; + +const handleDrop = (ev:Event) => { + const json = ev.dataTransfer?.getData?.(SUPERSET_TABLE_COLUMN); + const data = JSON.parse(json); + // ... do something with the data here +} +``` + +<Story id="design-system-components-table-examples--reorderable-columns" /> diff --git a/superset-frontend/src/components/Table/Table.stories.tsx b/superset-frontend/src/components/Table/Table.stories.tsx new file mode 100644 index 0000000000000..7ae3525562d18 --- /dev/null +++ b/superset-frontend/src/components/Table/Table.stories.tsx @@ -0,0 +1,682 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useState } from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import { + Table, + TableSize, + SUPERSET_TABLE_COLUMN, + ColumnsType, + OnChangeFunction, + ETableAction, +} from './index'; +import { numericalSort, alphabeticalSort } from './sorters'; +import ButtonCell from './cell-renderers/ButtonCell'; +import ActionCell from './cell-renderers/ActionCell'; +import { exampleMenuOptions } from './cell-renderers/ActionCell/fixtures'; +import NumericCell, { + CurrencyCode, + LocaleCode, + Style, +} from './cell-renderers/NumericCell'; +import HeaderWithRadioGroup from './header-renderers/HeaderWithRadioGroup'; +import TimeCell from './cell-renderers/TimeCell'; + +export default { + title: 'Design System/Components/Table/Examples', + component: Table, + argTypes: { onClick: { action: 'clicked' } }, +} as ComponentMeta<typeof Table>; + +export interface BasicData { + name: string; + category: string; + price: number; + description?: string; + key: number; +} + +export interface RendererData { + key: number; + buttonCell: string; + textCell: string; + euroCell: number; + dollarCell: number; +} + +export interface ExampleData { + title: string; + name: string; + age: number; + address: string; + tags?: string[]; + key: number; +} + +function generateValues(amount: number, row = 0): object { + const cells = {}; + for (let i = 0; i < amount; i += 1) { + cells[`col-${i}`] = i * row * 0.75; + } + return cells; +} + +function generateColumns(amount: number): ColumnsType<ExampleData>[] { + const newCols: any[] = []; + for (let i = 0; i < amount; i += 1) { + newCols.push({ + title: `C${i}`, + dataIndex: `col-${i}`, + key: `col-${i}`, + width: 90, + render: (value: number) => ( + <NumericCell + options={{ style: Style.CURRENCY, currency: CurrencyCode.EUR }} + value={value} + locale={LocaleCode.en_US} + /> + ), + sorter: (a: BasicData, b: BasicData) => numericalSort(`col-${i}`, a, b), + }); + } + return newCols as ColumnsType<ExampleData>[]; +} +const recordCount = 500; +const columnCount = 500; +const randomCols: ColumnsType<ExampleData>[] = generateColumns(columnCount); + +const basicData: BasicData[] = [ + { + key: 1, + name: 'Floppy Disk 10 pack', + category: 'Disk Storage', + price: 9.99, + description: 'A real blast from the past', + }, + { + key: 2, + name: 'DVD 100 pack', + category: 'Optical Storage', + price: 27.99, + description: 'Still pretty ancient', + }, + { + key: 3, + name: '128 GB SSD', + category: 'Hardrive', + price: 49.99, + description: 'Reliable and fast data storage', + }, + { + key: 4, + name: '128 GB SSD', + category: 'Hardrive', + price: 49.99, + description: 'Reliable and fast data storage', + }, + { + key: 5, + name: '4GB 144mhz', + category: 'Memory', + price: 19.99, + description: 'Laptop memory', + }, + { + key: 6, + name: '1GB USB Flash Drive', + category: 'Portable Storage', + price: 9.99, + description: 'USB Flash Drive portal data storage', + }, + { + key: 7, + name: '256 GB SSD', + category: 'Hardrive', + price: 175, + description: 'Reliable and fast data storage', + }, + { + key: 8, + name: '1 TB SSD', + category: 'Hardrive', + price: 349.99, + description: 'Reliable and fast data storage', + }, +]; + +const basicColumns: ColumnsType<BasicData> = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name', + width: 100, + sorter: (a: BasicData, b: BasicData) => alphabeticalSort('name', a, b), + }, + { + title: 'Category', + dataIndex: 'category', + key: 'category', + sorter: (a: BasicData, b: BasicData) => alphabeticalSort('category', a, b), + }, + { + title: 'Price', + dataIndex: 'price', + key: 'price', + sorter: (a: BasicData, b: BasicData) => numericalSort('price', a, b), + width: 100, + }, + { + title: 'Description', + dataIndex: 'description', + key: 'description', + }, +]; + +const bigColumns: ColumnsType<ExampleData> = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name', + width: 150, + }, + { + title: 'Age', + dataIndex: 'age', + key: 'age', + sorter: (a: ExampleData, b: ExampleData) => numericalSort('age', a, b), + width: 75, + }, + { + title: 'Address', + dataIndex: 'address', + key: 'address', + width: 100, + }, + ...(randomCols as ColumnsType<ExampleData>), +]; + +const rendererColumns: ColumnsType<RendererData> = [ + { + title: 'Button Cell', + dataIndex: 'buttonCell', + key: 'buttonCell', + width: 150, + render: (text: string, data: object, index: number) => ( + <ButtonCell + label={text} + row={data} + index={index} + onClick={action('button-cell-click')} + /> + ), + }, + { + title: 'Text Cell', + dataIndex: 'textCell', + key: 'textCell', + }, + { + title: 'Euro Cell', + dataIndex: 'euroCell', + key: 'euroCell', + render: (value: number) => ( + <NumericCell + options={{ style: Style.CURRENCY, currency: CurrencyCode.EUR }} + value={value} + locale={LocaleCode.en_US} + /> + ), + }, + { + title: 'Dollar Cell', + dataIndex: 'dollarCell', + key: 'dollarCell', + render: (value: number) => ( + <NumericCell + options={{ style: Style.CURRENCY, currency: CurrencyCode.USD }} + value={value} + locale={LocaleCode.en_US} + /> + ), + }, + { + dataIndex: 'actions', + key: 'actions', + render: (text: string, row: object) => ( + <ActionCell row={row} menuOptions={exampleMenuOptions} /> + ), + width: 32, + fixed: 'right', + }, +]; + +const baseData: any[] = [ + { + key: 1, + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park', + tags: ['nice', 'developer'], + ...generateValues(columnCount), + }, + { + key: 2, + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park', + tags: ['loser'], + ...generateValues(columnCount), + }, + { + key: 3, + name: 'Joe Black', + age: 32, + address: 'Sidney No. 1 Lake Park', + tags: ['cool', 'teacher'], + ...generateValues(columnCount), + }, +]; + +const bigdata: any[] = []; +for (let i = 0; i < recordCount; i += 1) { + bigdata.push({ + key: i + baseData.length, + name: `Dynamic record ${i}`, + age: 32 + i, + address: `DynamoCity, Dynamic Lane no. ${i}`, + ...generateValues(columnCount, i), + }); +} + +export const Basic: ComponentStory<typeof Table> = args => <Table {...args} />; + +function handlers(record: object, rowIndex: number) { + return { + onClick: action( + `row onClick, row: ${rowIndex}, record: ${JSON.stringify(record)}`, + ), // click row + onDoubleClick: action( + `row onDoubleClick, row: ${rowIndex}, record: ${JSON.stringify(record)}`, + ), // double click row + onContextMenu: action( + `row onContextMenu, row: ${rowIndex}, record: ${JSON.stringify(record)}`, + ), // right button click row + onMouseEnter: action(`Mouse Enter, row: ${rowIndex}`), // mouse enter row + onMouseLeave: action(`Mouse Leave, row: ${rowIndex}`), // mouse leave row + }; +} + +Basic.args = { + data: basicData, + columns: basicColumns, + size: TableSize.SMALL, + onRow: handlers, + usePagination: false, +}; + +export const Pagination: ComponentStory<typeof Table> = args => ( + <Table {...args} /> +); + +Pagination.args = { + data: basicData, + columns: basicColumns, + size: TableSize.SMALL, + pageSizeOptions: ['5', '10', '15', '20', '25'], + defaultPageSize: 5, +}; + +const generateData = (startIndex: number, pageSize: number): BasicData[] => { + const data: BasicData[] = []; + for (let i = 0; i < pageSize; i += 1) { + const recordIndex = startIndex + i; + data.push({ + key: recordIndex, + name: `Dynamic Record ${recordIndex}`, + category: 'Disk Storage', + price: recordIndex * 2.59, + description: 'A random description', + }); + } + return data; +}; + +const paginationColumns: ColumnsType<BasicData> = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name', + width: 100, + }, + { + title: 'Category', + dataIndex: 'category', + key: 'category', + }, + { + title: 'Price', + dataIndex: 'price', + key: 'price', + width: 100, + render: (value: number) => ( + <NumericCell + options={{ style: Style.CURRENCY, currency: CurrencyCode.EUR }} + value={value} + locale={LocaleCode.en_US} + /> + ), + sorter: (a: BasicData, b: BasicData) => numericalSort('price', a, b), + }, + { + title: 'Description', + dataIndex: 'description', + key: 'description', + }, + { + dataIndex: 'actions', + key: 'actions', + render: (text: string, row: object) => ( + <ActionCell row={row} menuOptions={exampleMenuOptions} /> + ), + width: 32, + fixed: 'right', + }, +]; + +export const ServerPagination: ComponentStory<typeof Table> = args => { + const [data, setData] = useState(generateData(0, 5)); + const [loading, setLoading] = useState(false); + + const handleChange: OnChangeFunction = ( + pagination, + filters, + sorter, + extra, + ) => { + const pageSize = pagination?.pageSize ?? 5; + const current = pagination?.current ?? 0; + switch (extra?.action) { + case ETableAction.PAGINATE: { + setLoading(true); + // simulate a fetch + setTimeout(() => { + setData(generateData(current * pageSize, pageSize)); + setLoading(false); + }, 1000); + break; + } + case ETableAction.SORT: { + action(`table-sort-change: ${JSON.stringify(sorter)}`); + break; + } + case ETableAction.FILTER: { + action(`table-sort-change: ${JSON.stringify(filters)}`); + break; + } + default: { + action('table action unknown'); + break; + } + } + }; + + return ( + <Table + {...args} + data={data} + recordCount={5000} + onChange={handleChange} + loading={loading} + /> + ); +}; + +ServerPagination.args = { + columns: paginationColumns, + size: TableSize.SMALL, + pageSizeOptions: ['5', '20', '50'], + defaultPageSize: 5, +}; + +export const VirtualizedPerformance: ComponentStory<typeof Table> = args => ( + <Table {...args} /> +); + +VirtualizedPerformance.args = { + data: bigdata, + columns: bigColumns, + size: TableSize.SMALL, + resizable: true, + reorderable: true, + height: 350, + virtualize: true, + usePagination: false, +}; + +export const Loading: ComponentStory<typeof Table> = args => ( + <Table {...args} /> +); + +Loading.args = { + data: basicData, + columns: basicColumns, + size: TableSize.SMALL, + loading: true, +}; + +export const ResizableColumns: ComponentStory<typeof Table> = args => ( + <Table {...args} /> +); + +ResizableColumns.args = { + data: basicData, + columns: basicColumns, + size: TableSize.SMALL, + resizable: true, +}; + +export const ReorderableColumns: ComponentStory<typeof Table> = args => { + const [droppedItem, setDroppedItem] = useState<string | undefined>(); + const dragOver = (ev: React.DragEvent<HTMLDivElement>) => { + ev.preventDefault(); + const element: HTMLElement | null = ev?.currentTarget as HTMLElement; + if (element?.style) { + element.style.border = '1px dashed green'; + } + }; + + const dragOut = (ev: React.DragEvent<HTMLDivElement>) => { + ev.preventDefault(); + const element: HTMLElement | null = ev?.currentTarget as HTMLElement; + if (element?.style) { + element.style.border = '1px solid grey'; + } + }; + + const dragDrop = (ev: React.DragEvent<HTMLDivElement>) => { + const data = ev.dataTransfer?.getData?.(SUPERSET_TABLE_COLUMN); + const element: HTMLElement | null = ev?.currentTarget as HTMLElement; + if (element?.style) { + element.style.border = '1px solid grey'; + } + setDroppedItem(data); + }; + return ( + <div> + <div + onDragOver={(ev: React.DragEvent<HTMLDivElement>) => dragOver(ev)} + onDragLeave={(ev: React.DragEvent<HTMLDivElement>) => dragOut(ev)} + onDrop={(ev: React.DragEvent<HTMLDivElement>) => dragDrop(ev)} + style={{ + width: '100%', + height: '40px', + border: '1px solid grey', + marginBottom: '8px', + padding: '8px', + borderRadius: '4px', + }} + > + {droppedItem ?? 'Drop column here...'} + </div> + <Table {...args} /> + </div> + ); +}; + +ReorderableColumns.args = { + data: basicData, + columns: basicColumns, + size: TableSize.SMALL, + reorderable: true, +}; + +const rendererData: RendererData[] = [ + { + key: 1, + buttonCell: 'Click Me', + textCell: 'Some text', + euroCell: 45.5, + dollarCell: 45.5, + }, + { + key: 2, + buttonCell: 'I am a button', + textCell: 'More text', + euroCell: 1700, + dollarCell: 1700, + }, + { + key: 3, + buttonCell: 'Button 3', + textCell: 'The third string of text', + euroCell: 500.567, + dollarCell: 500.567, + }, +]; + +export const CellRenderers: ComponentStory<typeof Table> = args => ( + <Table {...args} /> +); + +CellRenderers.args = { + data: rendererData, + columns: rendererColumns, + size: TableSize.SMALL, + reorderable: true, +}; + +export interface ShoppingData { + key: number; + item: string; + orderDate: number; + price: number; +} + +const shoppingData: ShoppingData[] = [ + { + key: 1, + item: 'Floppy Disk 10 pack', + orderDate: Date.now(), + price: 9.99, + }, + { + key: 2, + item: 'DVD 100 pack', + orderDate: Date.now(), + price: 7.99, + }, + { + key: 3, + item: '128 GB SSD', + orderDate: Date.now(), + price: 3.99, + }, +]; + +export const HeaderRenderers: ComponentStory<typeof Table> = args => { + const [orderDateFormatting, setOrderDateFormatting] = useState('formatted'); + const [priceLocale, setPriceLocale] = useState(LocaleCode.en_US); + const shoppingColumns: ColumnsType<ShoppingData> = [ + { + title: 'Item', + dataIndex: 'item', + key: 'item', + width: 200, + }, + { + title: () => ( + <HeaderWithRadioGroup + headerTitle="Order date" + groupTitle="Formatting" + groupOptions={[ + { label: 'Original value', value: 'original' }, + { label: 'Formatted value', value: 'formatted' }, + ]} + value={orderDateFormatting} + onChange={value => setOrderDateFormatting(value)} + /> + ), + dataIndex: 'orderDate', + key: 'orderDate', + width: 200, + render: value => + orderDateFormatting === 'original' ? value : <TimeCell value={value} />, + }, + { + title: () => ( + <HeaderWithRadioGroup + headerTitle="Price" + groupTitle="Currency" + groupOptions={[ + { label: 'US Dollar', value: LocaleCode.en_US }, + { label: 'Brazilian Real', value: LocaleCode.pt_BR }, + ]} + value={priceLocale} + onChange={value => setPriceLocale(value as LocaleCode)} + /> + ), + dataIndex: 'price', + key: 'price', + width: 200, + render: value => ( + <NumericCell + value={value} + options={{ + style: Style.CURRENCY, + currency: + priceLocale === LocaleCode.en_US + ? CurrencyCode.USD + : CurrencyCode.BRL, + }} + locale={priceLocale} + /> + ), + }, + ]; + + return ( + <Table + data={shoppingData} + columns={shoppingColumns} + size={TableSize.SMALL} + resizable + /> + ); +}; diff --git a/superset-frontend/src/components/Table/Table.test.tsx b/superset-frontend/src/components/Table/Table.test.tsx new file mode 100644 index 0000000000000..eded7efeb96f3 --- /dev/null +++ b/superset-frontend/src/components/Table/Table.test.tsx @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import type { ColumnsType } from 'antd/es/table'; +import { Table, TableSize } from './index'; + +interface BasicData { + columnName: string; + columnType: string; + dataType: string; +} + +const testData: BasicData[] = [ + { + columnName: 'Number', + columnType: 'Numerical', + dataType: 'number', + }, + { + columnName: 'String', + columnType: 'Physical', + dataType: 'string', + }, + { + columnName: 'Date', + columnType: 'Virtual', + dataType: 'date', + }, +]; + +const testColumns: ColumnsType<BasicData> = [ + { + title: 'Column Name', + dataIndex: 'columnName', + key: 'columnName', + }, + { + title: 'Column Type', + dataIndex: 'columnType', + key: 'columnType', + }, + { + title: 'Data Type', + dataIndex: 'dataType', + key: 'dataType', + }, +]; + +test('renders with default props', async () => { + render( + <Table size={TableSize.MIDDLE} columns={testColumns} data={testData} />, + ); + await waitFor(() => + testColumns.forEach(column => + expect(screen.getByText(column.title as string)).toBeInTheDocument(), + ), + ); + testData.forEach(row => { + expect(screen.getByText(row.columnName)).toBeInTheDocument(); + expect(screen.getByText(row.columnType)).toBeInTheDocument(); + expect(screen.getByText(row.dataType)).toBeInTheDocument(); + }); +}); diff --git a/superset-frontend/src/components/Table/VirtualTable.tsx b/superset-frontend/src/components/Table/VirtualTable.tsx new file mode 100644 index 0000000000000..fc7b7ee27d355 --- /dev/null +++ b/superset-frontend/src/components/Table/VirtualTable.tsx @@ -0,0 +1,247 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { Table as AntTable } from 'antd'; +import classNames from 'classnames'; +import { useResizeDetector } from 'react-resize-detector'; +import React, { useEffect, useRef, useState, useCallback } from 'react'; +import { VariableSizeGrid as Grid } from 'react-window'; +import { StyledComponent } from '@emotion/styled'; +import { useTheme, styled } from '@superset-ui/core'; +import { TablePaginationConfig } from 'antd/lib/table'; +import { TableProps, TableSize, ETableAction } from './index'; + +const StyledCell: StyledComponent<any> = styled('div')<any>( + ({ theme, height }) => ` + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding-left: ${theme.gridUnit * 2}px; + padding-right: ${theme.gridUnit}px; + border-bottom: 1px solid ${theme.colors.grayscale.light3}; + transition: background 0.3s; + line-height: ${height}px; + box-sizing: border-box; +`, +); + +const StyledTable: StyledComponent<any> = styled(AntTable)<any>( + ({ theme }) => ` + th.ant-table-cell { + font-weight: ${theme.typography.weights.bold}; + color: ${theme.colors.grayscale.dark1}; + user-select: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .ant-pagination-item-active { + border-color: ${theme.colors.primary.base}; + } + } +`, +); + +const SMALL = 39; +const MIDDLE = 47; + +const VirtualTable = (props: TableProps) => { + const { columns, pagination, onChange, height, scroll, size } = props; + const [tableWidth, setTableWidth] = useState<number>(0); + const onResize = useCallback((width: number) => { + setTableWidth(width); + }, []); + const { ref } = useResizeDetector({ onResize }); + const theme = useTheme(); + + // If a column definition has no width, react-window will use this as the default column width + const DEFAULT_COL_WIDTH = theme?.gridUnit * 37 || 150; + const widthColumnCount = columns!.filter(({ width }) => !width).length; + let staticColWidthTotal = 0; + columns?.forEach(column => { + if (column.width) { + staticColWidthTotal += column.width as number; + } + }); + + let totalWidth = 0; + const defaultWidth = Math.max( + Math.floor((tableWidth - staticColWidthTotal) / widthColumnCount), + 50, + ); + + const mergedColumns = + columns?.map?.(column => { + const modifiedColumn = { ...column }; + if (!column.width) { + modifiedColumn.width = defaultWidth; + } + totalWidth += modifiedColumn.width as number; + return modifiedColumn; + }) ?? []; + + /* + * There are cases where a user could set the width of each column and the total width is less than width of + * the table. In this case we will stretch the last column to use the extra space + */ + if (totalWidth < tableWidth) { + const lastColumn = mergedColumns[mergedColumns.length - 1]; + lastColumn.width = + (lastColumn.width as number) + Math.floor(tableWidth - totalWidth); + } + + const gridRef = useRef<any>(); + const [connectObject] = useState<any>(() => { + const obj = {}; + Object.defineProperty(obj, 'scrollLeft', { + get: () => { + if (gridRef.current) { + return gridRef.current?.state?.scrollLeft; + } + return null; + }, + set: (scrollLeft: number) => { + if (gridRef.current) { + gridRef.current.scrollTo({ scrollLeft }); + } + }, + }); + + return obj; + }); + + const resetVirtualGrid = () => { + gridRef.current?.resetAfterIndices({ + columnIndex: 0, + shouldForceUpdate: true, + }); + }; + + useEffect(() => resetVirtualGrid, [tableWidth, columns, size]); + + /* + * antd Table has a runtime error when it tries to fire the onChange event triggered from a pageChange + * when the table body is overridden with the virtualized table. This function capture the page change event + * from within the pagination controls and proxies the onChange event payload + */ + const onPageChange = (page: number, size: number) => { + /** + * This resets vertical scroll position to 0 (top) when page changes + * We intentionally leave horizontal scroll where it was so user can focus on + * specific range of columns as they page through data + */ + gridRef.current?.scrollTo?.({ scrollTop: 0 }); + + onChange?.( + { + ...pagination, + current: page, + pageSize: size, + } as TablePaginationConfig, + {}, + {}, + { + action: ETableAction.PAGINATE, + currentDataSource: [], + }, + ); + }; + + const renderVirtualList = (rawData: object[], { ref, onScroll }: any) => { + // eslint-disable-next-line no-param-reassign + ref.current = connectObject; + const cellSize = size === TableSize.MIDDLE ? MIDDLE : SMALL; + return ( + <Grid + ref={gridRef} + className="virtual-grid" + columnCount={mergedColumns.length} + columnWidth={(index: number) => { + const { width = DEFAULT_COL_WIDTH } = mergedColumns[index]; + return width as number; + }} + height={height || (scroll!.y as number)} + rowCount={rawData.length} + rowHeight={() => cellSize} + width={tableWidth} + onScroll={({ scrollLeft }: { scrollLeft: number }) => { + onScroll({ scrollLeft }); + }} + > + {({ + columnIndex, + rowIndex, + style, + }: { + columnIndex: number; + rowIndex: number; + style: React.CSSProperties; + }) => { + const data: any = rawData?.[rowIndex]; + // Set default content + let content = + data?.[(mergedColumns as any)?.[columnIndex]?.dataIndex]; + // Check if the column has a render function + const render = mergedColumns[columnIndex]?.render; + if (typeof render === 'function') { + // Use render function to generate formatted content using column's render function + content = render(content, data, rowIndex); + } + + return ( + <StyledCell + className={classNames('virtual-table-cell', { + 'virtual-table-cell-last': + columnIndex === mergedColumns.length - 1, + })} + style={style} + title={typeof content === 'string' ? content : undefined} + theme={theme} + height={cellSize} + > + {content} + </StyledCell> + ); + }} + </Grid> + ); + }; + + const modifiedPagination = { + ...pagination, + onChange: onPageChange, + }; + + return ( + <div ref={ref}> + <StyledTable + {...props} + sticky={false} + className="virtual-table" + columns={mergedColumns} + components={{ + body: renderVirtualList, + }} + pagination={modifiedPagination} + /> + </div> + ); +}; + +export default VirtualTable; diff --git a/superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.overview.mdx b/superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.overview.mdx new file mode 100644 index 0000000000000..09e1b5ed6b17b --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.overview.mdx @@ -0,0 +1,69 @@ +import { Meta, Source, Story, ArgsTable } from '@storybook/addon-docs'; + +<Meta title="Design System/Components/Table/Cell Renderers/ActionCell/Overview" /> + +# ActionCell + +An ActionCell is used to display an overflow icon that opens a menu allowing the user to take actions +specific to the data in the table row that the cell is a member of. + +### [Basic example](./?path=/docs/design-system-components-table-cell-renderers-actioncell--basic) + +<Story id="design-system-components-table-cell-renderers-actioncell--basic" /> + +--- + +## Usage + +The action cell accepts an array of objects that define the label, tooltip, onClick callback functions, +and an optional data payload to be provided back to the onClick handler function. + +### [Basic example](./?path=/docs/design-system-components-table-cell-renderers-actioncell--basic) + +<Story id="design-system-components-table-cell-renderers-actioncell--basic" /> + +``` +import { ActionMenuItem } from 'src/components/Table/cell-renderers/index'; + +export const exampleMenuOptions: ActionMenuItem[] = [ + { + label: 'Action 1', + tooltip: "This is a tip, don't spend it all in one place", + onClick: (item: ActionMenuItem) => { + // eslint-disable-next-line no-alert + alert(JSON.stringify(item)); + }, + payload: { + taco: 'spicy chicken', + }, + }, + { + label: 'Action 2', + tooltip: 'This is another tip', + onClick: (item: ActionMenuItem) => { + // eslint-disable-next-line no-alert + alert(JSON.stringify(item)); + }, + payload: { + taco: 'saucy tofu', + }, + }, +]; + +``` + +Within the context of adding an action cell to cell definitions provided to the table using the ActionCell component +for the return value from the render function on the cell definition. See the [Basic example](./?path=/docs/design-system-components-table-examples--basic) + +``` +import ActionCell from './index'; + +const cellExample = [ + { + title: 'Actions', + dataIndex: 'actions', + key: 'actions', + render: () => <ActionCell menuOptions={exampleMenuOptions} />, + } +] +``` diff --git a/superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.stories.tsx b/superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.stories.tsx new file mode 100644 index 0000000000000..d51dbcc559fdd --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.stories.tsx @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * License); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import ActionCell from './index'; +import { exampleMenuOptions, exampleRow } from './fixtures'; + +export default { + title: 'Design System/Components/Table/Cell Renderers/ActionCell', + component: ActionCell, +} as ComponentMeta<typeof ActionCell>; + +export const Basic: ComponentStory<typeof ActionCell> = args => ( + <ActionCell {...args} /> +); + +Basic.args = { + menuOptions: exampleMenuOptions, + row: exampleRow, +}; diff --git a/superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.test.tsx b/superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.test.tsx new file mode 100644 index 0000000000000..5da7453aa9d7f --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.test.tsx @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import ActionCell, { appendDataToMenu } from './index'; +import { exampleMenuOptions, exampleRow } from './fixtures'; + +test('renders with default props', async () => { + const clickHandler = jest.fn(); + exampleMenuOptions[0].onClick = clickHandler; + render(<ActionCell menuOptions={exampleMenuOptions} row={exampleRow} />); + // Open the menu + userEvent.click(await screen.findByTestId('dropdown-trigger')); + // verify all of the menu items are being displayed + exampleMenuOptions.forEach((item, index) => { + expect(screen.getByText(item.label)).toBeInTheDocument(); + if (index === 0) { + // verify the menu items' onClick gets invoked + userEvent.click(screen.getByText(item.label)); + } + }); + expect(clickHandler).toHaveBeenCalled(); +}); + +/** + * Validate that the appendDataToMenu utility function used within the + * Action cell menu rendering works as expected + */ +test('appendDataToMenu utility', () => { + exampleMenuOptions.forEach(item => expect(item?.row).toBeUndefined()); + const modifiedMenuOptions = appendDataToMenu(exampleMenuOptions, exampleRow); + modifiedMenuOptions.forEach(item => expect(item?.row).toBeDefined()); +}); diff --git a/superset-frontend/src/components/Table/cell-renderers/ActionCell/fixtures.ts b/superset-frontend/src/components/Table/cell-renderers/ActionCell/fixtures.ts new file mode 100644 index 0000000000000..a0569b69906bc --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/ActionCell/fixtures.ts @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * License); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { action } from '@storybook/addon-actions'; +import { ActionMenuItem } from './index'; + +export const exampleMenuOptions: ActionMenuItem[] = [ + { + label: 'Action 1', + tooltip: "This is a tip, don't spend it all in one place", + onClick: action('menu item onClick'), + payload: { + taco: 'spicy chicken', + }, + }, + { + label: 'Action 2', + tooltip: 'This is another tip', + onClick: action('menu item onClick'), + payload: { + taco: 'saucy tofu', + }, + }, +]; + +export const exampleRow = { + key: 1, + buttonCell: 'Click Me', + textCell: 'Some text', + euroCell: 45.5, + dollarCell: 45.5, +}; diff --git a/superset-frontend/src/components/Table/cell-renderers/ActionCell/index.tsx b/superset-frontend/src/components/Table/cell-renderers/ActionCell/index.tsx new file mode 100644 index 0000000000000..b6ba57420c6b4 --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/ActionCell/index.tsx @@ -0,0 +1,145 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useState, useEffect } from 'react'; +import { styled } from '@superset-ui/core'; +import { Dropdown, IconOrientation } from 'src/components/Dropdown'; +import { Menu } from 'src/components/Menu'; +import { MenuProps } from 'antd/lib/menu'; + +/** + * Props interface for Action Cell Renderer + */ +export interface ActionCellProps { + /** + * The Menu option presented to user when menu displays + */ + menuOptions: ActionMenuItem[]; + /** + * Object representing the data rendering the Table row with attribute for each column + */ + row: object; +} + +export interface ActionMenuItem { + /** + * Click handler specific to the menu item + * @param menuItem The definition of the menu item that was clicked + * @returns ActionMenuItem + */ + onClick: (menuItem: ActionMenuItem) => void; + /** + * Label user will see displayed in the list of menu options + */ + label: string; + /** + * Optional tooltip user will see if they hover over the menu option to get more context + */ + tooltip?: string; + /** + * Optional variable that can contain data relevant to the menu item that you + * want easy access to in the callback function for the menu + */ + payload?: any; + /** + * Object representing the data rendering the Table row with attribute for each column + */ + row?: object; +} + +/** + * Props interface for ActionMenu + */ +export interface ActionMenuProps { + menuOptions: ActionMenuItem[]; + setVisible: (visible: boolean) => void; +} + +const SHADOW = + 'box-shadow: 0px 3px 6px -4px rgba(0, 0, 0, 0.12), 0px 9px 28px 8px rgba(0, 0, 0, 0.05)'; +const FILTER = 'drop-shadow(0px 6px 16px rgba(0, 0, 0, 0.08))'; + +const StyledMenu = styled(Menu)` + box-shadow: ${SHADOW} !important; + filter: ${FILTER} !important; + border-radius: 2px !important; + -webkit-box-shadow: ${SHADOW} !important; +`; + +export const appendDataToMenu = ( + options: ActionMenuItem[], + row: object, +): ActionMenuItem[] => { + const newOptions = options?.map?.(option => ({ + ...option, + row, + })); + return newOptions; +}; + +function ActionMenu(props: ActionMenuProps) { + const { menuOptions, setVisible } = props; + const handleClick: MenuProps['onClick'] = ({ key }) => { + setVisible?.(false); + const menuItem = menuOptions[key]; + if (menuItem) { + menuItem?.onClick?.(menuItem); + } + }; + + return ( + <StyledMenu onClick={handleClick}> + {menuOptions?.map?.((option: ActionMenuItem, index: number) => ( + <Menu.Item key={index}>{option?.label}</Menu.Item> + ))} + </StyledMenu> + ); +} + +export function ActionCell(props: ActionCellProps) { + const { menuOptions, row } = props; + const [visible, setVisible] = useState(false); + const [appendedMenuOptions, setAppendedMenuOptions] = useState( + appendDataToMenu(menuOptions, row), + ); + + useEffect(() => { + const newOptions = appendDataToMenu(menuOptions, row); + setAppendedMenuOptions(newOptions); + }, [menuOptions, row]); + + const handleVisibleChange = (flag: boolean) => { + setVisible(flag); + }; + return ( + <Dropdown + iconOrientation={IconOrientation.HORIZONTAL} + onVisibleChange={handleVisibleChange} + trigger={['click']} + overlay={ + <ActionMenu menuOptions={appendedMenuOptions} setVisible={setVisible} /> + } + disabled={ + !(appendedMenuOptions?.length && appendedMenuOptions.length > 0) + } + visible={visible} + /> + ); +} + +export default ActionCell; diff --git a/superset-frontend/src/components/Table/cell-renderers/BooleanCell/BooleanCell.stories.tsx b/superset-frontend/src/components/Table/cell-renderers/BooleanCell/BooleanCell.stories.tsx new file mode 100644 index 0000000000000..8a98f18299c7b --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/BooleanCell/BooleanCell.stories.tsx @@ -0,0 +1,34 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import BooleanCell from '.'; + +export default { + title: 'Design System/Components/Table/Cell Renderers/BooleanCell', + component: BooleanCell, +} as ComponentMeta<typeof BooleanCell>; + +export const Basic: ComponentStory<typeof BooleanCell> = args => ( + <BooleanCell {...args} /> +); + +Basic.args = { + value: true, +}; diff --git a/superset-frontend/src/components/Table/cell-renderers/BooleanCell/BooleanCell.test.tsx b/superset-frontend/src/components/Table/cell-renderers/BooleanCell/BooleanCell.test.tsx new file mode 100644 index 0000000000000..fa83db6271d97 --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/BooleanCell/BooleanCell.test.tsx @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import { BOOL_FALSE_DISPLAY, BOOL_TRUE_DISPLAY } from 'src/constants'; +import BooleanCell from '.'; + +test('renders true value', async () => { + render(<BooleanCell value />); + expect(screen.getByText(BOOL_TRUE_DISPLAY)).toBeInTheDocument(); +}); + +test('renders false value', async () => { + render(<BooleanCell value={false} />); + expect(screen.getByText(BOOL_FALSE_DISPLAY)).toBeInTheDocument(); +}); + +test('renders falsy value', async () => { + render(<BooleanCell />); + expect(screen.getByText(BOOL_FALSE_DISPLAY)).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/components/Table/cell-renderers/BooleanCell/index.tsx b/superset-frontend/src/components/Table/cell-renderers/BooleanCell/index.tsx new file mode 100644 index 0000000000000..2707d522417d0 --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/BooleanCell/index.tsx @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { BOOL_FALSE_DISPLAY, BOOL_TRUE_DISPLAY } from 'src/constants'; + +export interface BooleanCellProps { + value?: boolean; +} + +function BooleanCell({ value }: BooleanCellProps) { + return <span>{value ? BOOL_TRUE_DISPLAY : BOOL_FALSE_DISPLAY}</span>; +} + +export default BooleanCell; diff --git a/superset-frontend/src/components/Table/cell-renderers/ButtonCell/ButtonCell.stories.tsx b/superset-frontend/src/components/Table/cell-renderers/ButtonCell/ButtonCell.stories.tsx new file mode 100644 index 0000000000000..707e758eedb81 --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/ButtonCell/ButtonCell.stories.tsx @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import { ButtonCell } from './index'; + +export default { + title: 'Design System/Components/Table/Cell Renderers/ButtonCell', + component: ButtonCell, +} as ComponentMeta<typeof ButtonCell>; + +const clickHandler = action('button cell onClick'); + +export const Basic: ComponentStory<typeof ButtonCell> = args => ( + <ButtonCell {...args} /> +); + +Basic.args = { + onClick: clickHandler, + label: 'Primary', + row: { + key: 1, + buttonCell: 'Click Me', + textCell: 'Some text', + euroCell: 45.5, + dollarCell: 45.5, + }, +}; + +export const Secondary: ComponentStory<typeof ButtonCell> = args => ( + <ButtonCell {...args} /> +); + +Secondary.args = { + onClick: clickHandler, + label: 'Secondary', + buttonStyle: 'secondary', + row: { + key: 1, + buttonCell: 'Click Me', + textCell: 'Some text', + euroCell: 45.5, + dollarCell: 45.5, + }, +}; diff --git a/superset-frontend/src/components/Table/cell-renderers/ButtonCell/ButtonCell.test.tsx b/superset-frontend/src/components/Table/cell-renderers/ButtonCell/ButtonCell.test.tsx new file mode 100644 index 0000000000000..dbdb8fd4f2f2e --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/ButtonCell/ButtonCell.test.tsx @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import ButtonCell from './index'; +import { exampleRow } from '../fixtures'; + +test('renders with default props', async () => { + const clickHandler = jest.fn(); + const BUTTON_LABEL = 'Button Label'; + + render( + <ButtonCell + label={BUTTON_LABEL} + key={5} + index={0} + row={exampleRow} + onClick={clickHandler} + />, + ); + await userEvent.click(screen.getByText(BUTTON_LABEL)); + expect(clickHandler).toHaveBeenCalled(); +}); diff --git a/superset-frontend/src/dashboard/stylesheets/builder.less b/superset-frontend/src/components/Table/cell-renderers/ButtonCell/index.tsx similarity index 51% rename from superset-frontend/src/dashboard/stylesheets/builder.less rename to superset-frontend/src/components/Table/cell-renderers/ButtonCell/index.tsx index 422d455622a40..c5739a386ced8 100644 --- a/superset-frontend/src/dashboard/stylesheets/builder.less +++ b/superset-frontend/src/components/Table/cell-renderers/ButtonCell/index.tsx @@ -16,34 +16,43 @@ * specific language governing permissions and limitations * under the License. */ -.dashboard { - position: relative; - color: @almost-black; - flex-grow: 1; - display: flex; - flex-direction: column; - height: 100%; -} +import React from 'react'; +import Button, { ButtonStyle, ButtonSize } from 'src/components/Button'; -/* only top-level tabs have popover, give it more padding to match header + tabs */ -.dashboard > .with-popover-menu > .popover-menu { - left: 24px; -} +type onClickFunction = (row: object, index: number) => void; -/* drop shadow for top-level tabs only */ -.dashboard .dashboard-component-tabs { - box-shadow: 0 4px 4px 0 fade(@darkest, @opacity-light); - padding-left: 8px; /* note this is added to tab-level padding, to match header */ +export interface ButtonCellProps { + label: string; + onClick: onClickFunction; + row: object; + index: number; + tooltip?: string; + buttonStyle?: ButtonStyle; + buttonSize?: ButtonSize; } -.dropdown-toggle.btn.btn-primary .caret { - color: @lightest; -} +export function ButtonCell(props: ButtonCellProps) { + const { + label, + onClick, + row, + index, + tooltip, + buttonStyle = 'primary', + buttonSize = 'small', + } = props; -.background--transparent { - background-color: transparent; + return ( + <Button + buttonStyle={buttonStyle} + buttonSize={buttonSize} + onClick={() => onClick?.(row, index)} + key={`${buttonStyle}_${buttonSize}`} + tooltip={tooltip} + > + {label} + </Button> + ); } -.background--white { - background-color: @lightest; -} +export default ButtonCell; diff --git a/superset-frontend/src/dashboard/stylesheets/index.less b/superset-frontend/src/components/Table/cell-renderers/NullCell/NullCell.stories.tsx similarity index 70% rename from superset-frontend/src/dashboard/stylesheets/index.less rename to superset-frontend/src/components/Table/cell-renderers/NullCell/NullCell.stories.tsx index ba46688dfe64d..ff39cd25528b0 100644 --- a/superset-frontend/src/dashboard/stylesheets/index.less +++ b/superset-frontend/src/components/Table/cell-renderers/NullCell/NullCell.stories.tsx @@ -16,14 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -@import '../../assets/stylesheets/less/variables.less'; +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import NullCell from '.'; -@import './builder.less'; -@import './builder-sidepane.less'; -@import './dashboard.less'; -@import './dnd.less'; -@import './filter-scope-selector.less'; -@import './grid.less'; -@import './popover-menu.less'; -@import './resizable.less'; -@import './components/index.less'; +export default { + title: 'Design System/Components/Table/Cell Renderers/NullCell', + component: NullCell, +} as ComponentMeta<typeof NullCell>; + +export const Basic: ComponentStory<typeof NullCell> = () => <NullCell />; diff --git a/superset-frontend/src/explore/reducers/index.js b/superset-frontend/src/components/Table/cell-renderers/NullCell/NullCell.test.tsx similarity index 60% rename from superset-frontend/src/explore/reducers/index.js rename to superset-frontend/src/components/Table/cell-renderers/NullCell/NullCell.test.tsx index a504fbf6e644c..3a3fd9d416caf 100644 --- a/superset-frontend/src/explore/reducers/index.js +++ b/superset-frontend/src/components/Table/cell-renderers/NullCell/NullCell.test.tsx @@ -16,23 +16,20 @@ * specific language governing permissions and limitations * under the License. */ -import { combineReducers } from 'redux'; +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import { supersetTheme } from '@superset-ui/core'; +import { NULL_DISPLAY } from 'src/constants'; +import NullCell from '.'; -import reports from 'src/reports/reducers/reports'; -import charts from 'src/components/Chart/chartReducer'; -import dataMask from 'src/dataMask/reducer'; -import messageToasts from 'src/components/MessageToasts/reducers'; -import saveModal from './saveModalReducer'; -import explore from './exploreReducer'; - -const impressionId = (state = '') => state; +test('renders null value', async () => { + render(<NullCell />); + expect(screen.getByText(NULL_DISPLAY)).toBeInTheDocument(); +}); -export default combineReducers({ - charts, - saveModal, - dataMask, - explore, - impressionId, - messageToasts, - reports, +test('renders with gray font', async () => { + render(<NullCell />); + expect(screen.getByText(NULL_DISPLAY)).toHaveStyle( + `color: ${supersetTheme.colors.grayscale.light1}`, + ); }); diff --git a/superset-frontend/src/components/Table/cell-renderers/NullCell/index.tsx b/superset-frontend/src/components/Table/cell-renderers/NullCell/index.tsx new file mode 100644 index 0000000000000..f1c9139fd9f0d --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/NullCell/index.tsx @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { css, SupersetTheme } from '@superset-ui/core'; +import { NULL_DISPLAY } from 'src/constants'; + +function NullCell() { + return ( + <span + css={(theme: SupersetTheme) => + css` + color: ${theme.colors.grayscale.light1}; + ` + } + > + {NULL_DISPLAY} + </span> + ); +} + +export default NullCell; diff --git a/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorScheme.test.jsx b/superset-frontend/src/components/Table/cell-renderers/NumericCell/NumericCell.stories.tsx similarity index 55% rename from superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorScheme.test.jsx rename to superset-frontend/src/components/Table/cell-renderers/NumericCell/NumericCell.stories.tsx index 565c4f9f28b54..bb0b52fe625f4 100644 --- a/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorScheme.test.jsx +++ b/superset-frontend/src/components/Table/cell-renderers/NumericCell/NumericCell.stories.tsx @@ -16,28 +16,32 @@ * specific language governing permissions and limitations * under the License. */ -/* eslint-disable no-unused-expressions */ import React from 'react'; -import { Select } from 'src/components'; -import { getCategoricalSchemeRegistry } from '@superset-ui/core'; -import { styledMount as mount } from 'spec/helpers/theming'; -import ColorSchemeControl from 'src/explore/components/controls/ColorSchemeControl'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { CurrencyCode, LocaleCode, NumericCell, Style } from './index'; -const defaultProps = { - name: 'color_scheme', - label: 'Color Scheme', - options: getCategoricalSchemeRegistry() - .keys() - .map(s => [s, s]), +export default { + title: 'Design System/Components/Table/Cell Renderers/NumericCell', + component: NumericCell, +} as ComponentMeta<typeof NumericCell>; + +export const Basic: ComponentStory<typeof NumericCell> = args => ( + <NumericCell {...args} /> +); + +Basic.args = { + value: 5678943, }; -describe('ColorSchemeControl', () => { - let wrapper; - beforeEach(() => { - wrapper = mount(<ColorSchemeControl {...defaultProps} />); - }); +export const FrenchLocale: ComponentStory<typeof NumericCell> = args => ( + <NumericCell {...args} /> +); - it('renders a Select', () => { - expect(wrapper.find(Select)).toExist(); - }); -}); +FrenchLocale.args = { + value: 5678943, + locale: LocaleCode.fr, + options: { + style: Style.CURRENCY, + currency: CurrencyCode.EUR, + }, +}; diff --git a/superset-frontend/src/explore/exploreUtils/getAnnotationJsonUrl.test.ts b/superset-frontend/src/components/Table/cell-renderers/NumericCell/NumericCell.test.tsx similarity index 51% rename from superset-frontend/src/explore/exploreUtils/getAnnotationJsonUrl.test.ts rename to superset-frontend/src/components/Table/cell-renderers/NumericCell/NumericCell.test.tsx index 388c3b9a03093..b76a5bef65f87 100644 --- a/superset-frontend/src/explore/exploreUtils/getAnnotationJsonUrl.test.ts +++ b/superset-frontend/src/components/Table/cell-renderers/NumericCell/NumericCell.test.tsx @@ -16,36 +16,34 @@ * specific language governing permissions and limitations * under the License. */ -import { getAnnotationJsonUrl } from '.'; +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import NumericCell, { CurrencyCode, LocaleCode, Style } from './index'; -let windowLocation: any; - -beforeAll(() => { - windowLocation = window.location; - // @ts-expect-error - delete window.location; -}); - -beforeEach(() => { - window.location = { - search: '?testA=0&testB=1', - } as any; -}); - -afterAll(() => { - window.location = windowLocation; -}); - -test('get correct annotation when isNative:true', () => { - const response = getAnnotationJsonUrl('slice_id', 'form_data', true); - expect(response).toBe( - '/superset/annotation_json/slice_id?form_data=%22form_data%22', +test('renders with French locale and Euro currency format', () => { + render( + <NumericCell + value={5678943} + locale={LocaleCode.fr} + options={{ + style: Style.CURRENCY, + currency: CurrencyCode.EUR, + }} + />, ); + expect(screen.getByText('5 678 943,00 €')).toBeInTheDocument(); }); -test('get correct annotation when isNative:false', () => { - const response = getAnnotationJsonUrl('slice_id', { json: 'my-data' }, false); - expect(response).toBe( - '/superset/slice_json/slice_id?form_data=%7B%22json%22%3A%22my-data%22%7D', +test('renders with English US locale and USD currency format', () => { + render( + <NumericCell + value={5678943} + locale={LocaleCode.en_US} + options={{ + style: Style.CURRENCY, + currency: CurrencyCode.USD, + }} + />, ); + expect(screen.getByText('$5,678,943.00')).toBeInTheDocument(); }); diff --git a/superset-frontend/src/components/Table/cell-renderers/NumericCell/index.tsx b/superset-frontend/src/components/Table/cell-renderers/NumericCell/index.tsx new file mode 100644 index 0000000000000..5e6d61aa47829 --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/NumericCell/index.tsx @@ -0,0 +1,418 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { logging } from '@superset-ui/core'; + +export interface NumericCellProps { + /** + * The number to display (before optional formatting applied) + */ + value: number; + /** + * ISO 639-1 language code with optional region or script modifier (e.g. en_US). + */ + locale?: LocaleCode; + /** + * Options for number formatting + */ + options?: NumberOptions; +} + +interface NumberOptions { + /** + * Style of number to display + */ + style?: Style; + + /** + * ISO 4217 currency code + */ + currency?: CurrencyCode; + + /** + * Languages in the form of a ISO 639-1 language code with optional region or script modifier (e.g. de_AT). + */ + maximumFractionDigits?: number; + + /** + * A number from 1 to 21 (default is 21) + */ + maximumSignificantDigits?: number; + + /** + * A number from 0 to 20 (default is 3) + */ + minimumFractionDigits?: number; + + /** + * A number from 1 to 21 (default is 1) + */ + minimumIntegerDigits?: number; + + /** + * A number from 1 to 21 (default is 21) + */ + minimumSignificantDigits?: number; +} + +export enum Style { + CURRENCY = 'currency', + DECIMAL = 'decimal', + PERCENT = 'percent', +} + +export enum CurrencyDisplay { + SYMBOL = 'symbol', + CODE = 'code', + NAME = 'name', +} + +export enum LocaleCode { + af = 'af', + ak = 'ak', + sq = 'sq', + am = 'am', + ar = 'ar', + hy = 'hy', + as = 'as', + az = 'az', + bm = 'bm', + bn = 'bn', + eu = 'eu', + be = 'be', + bs = 'bs', + br = 'br', + bg = 'bg', + my = 'my', + ca = 'ca', + ce = 'ce', + zh = 'zh', + zh_Hans = 'zh-Hans', + zh_Hant = 'zh-Hant', + cu = 'cu', + kw = 'kw', + co = 'co', + hr = 'hr', + cs = 'cs', + da = 'da', + nl = 'nl', + nl_BE = 'nl-BE', + dz = 'dz', + en = 'en', + en_AU = 'en-AU', + en_CA = 'en-CA', + en_GB = 'en-GB', + en_US = 'en-US', + eo = 'eo', + et = 'et', + ee = 'ee', + fo = 'fo', + fi = 'fi', + fr = 'fr', + fr_CA = 'fr-CA', + fr_CH = 'fr-CH', + ff = 'ff', + gl = 'gl', + lg = 'lg', + ka = 'ka', + de = 'de', + de_AT = 'de-AT', + de_CH = 'de-CH', + el = 'el', + gu = 'gu', + ht = 'ht', + ha = 'ha', + he = 'he', + hi = 'hi', + hu = 'hu', + is = 'is', + ig = 'ig', + id = 'id', + ia = 'ia', + ga = 'ga', + it = 'it', + ja = 'ja', + jv = 'jv', + kl = 'kl', + kn = 'kn', + ks = 'ks', + kk = 'kk', + km = 'km', + ki = 'ki', + rw = 'rw', + ko = 'ko', + ku = 'ku', + ky = 'ky', + lo = 'lo', + la = 'la', + lv = 'lv', + ln = 'ln', + lt = 'lt', + lu = 'lu', + lb = 'lb', + mk = 'mk', + mg = 'mg', + ms = 'ms', + ml = 'ml', + mt = 'mt', + gv = 'gv', + mi = 'mi', + mr = 'mr', + mn = 'mn', + ne = 'ne', + nd = 'nd', + se = 'se', + nb = 'nb', + nn = 'nn', + ny = 'ny', + or = 'or', + om = 'om', + os = 'os', + ps = 'ps', + fa = 'fa', + fa_AF = 'fa-AF', + pl = 'pl', + pt = 'pt', + pt_BR = 'pt-BR', + pt_PT = 'pt-PT', + pa = 'pa', + qu = 'qu', + ro = 'ro', + ro_MD = 'ro-MD', + rm = 'rm', + rn = 'rn', + ru = 'ru', + sm = 'sm', + sg = 'sg', + sa = 'sa', + gd = 'gd', + sr = 'sr', + sn = 'sn', + ii = 'ii', + sd = 'sd', + si = 'si', + sk = 'sk', + sl = 'sl', + so = 'so', + st = 'st', + es = 'es', + es_ES = 'es-ES', + es_MX = 'es-MX', + su = 'su', + sw = 'sw', + sw_CD = 'sw-CD', + sv = 'sv', + tg = 'tg', + ta = 'ta', + tt = 'tt', + te = 'te', + th = 'th', + bo = 'bo', + ti = 'ti', + to = 'to', + tr = 'tr', + tk = 'tk', + uk = 'uk', + ur = 'ur', + ug = 'ug', + uz = 'uz', + vi = 'vi', + vo = 'vo', + cy = 'cy', + fy = 'fy', + wo = 'wo', + xh = 'xh', + yi = 'yi', + yo = 'yo', + zu = 'zu', +} + +export enum CurrencyCode { + AED = 'AED', + AFN = 'AFN', + ALL = 'ALL', + AMD = 'AMD', + ANG = 'ANG', + AOA = 'AOA', + ARS = 'ARS', + AUD = 'AUD', + AWG = 'AWG', + AZN = 'AZN', + BAM = 'BAM', + BBD = 'BBD', + BDT = 'BDT', + BGN = 'BGN', + BHD = 'BHD', + BIF = 'BIF', + BMD = 'BMD', + BND = 'BND', + BOB = 'BOB', + BRL = 'BRL', + BSD = 'BSD', + BTN = 'BTN', + BWP = 'BWP', + BYN = 'BYN', + BZD = 'BZD', + CAD = 'CAD', + CDF = 'CDF', + CHF = 'CHF', + CLP = 'CLP', + CNY = 'CNY', + COP = 'COP', + CRC = 'CRC', + CUC = 'CUC', + CUP = 'CUP', + CVE = 'CVE', + CZK = 'CZK', + DJF = 'DJF', + DKK = 'DKK', + DOP = 'DOP', + DZD = 'DZD', + EGP = 'EGP', + ERN = 'ERN', + ETB = 'ETB', + EUR = 'EUR', + FJD = 'FJD', + FKP = 'FKP', + GBP = 'GBP', + GEL = 'GEL', + GHS = 'GHS', + GIP = 'GIP', + GMD = 'GMD', + GNF = 'GNF', + GTQ = 'GTQ', + GYD = 'GYD', + HKD = 'HKD', + HNL = 'HNL', + HRK = 'HRK', + HTG = 'HTG', + HUF = 'HUF', + IDR = 'IDR', + ILS = 'ILS', + INR = 'INR', + IQD = 'IQD', + IRR = 'IRR', + ISK = 'ISK', + JMD = 'JMD', + JOD = 'JOD', + JPY = 'JPY', + KES = 'KES', + KGS = 'KGS', + KHR = 'KHR', + KMF = 'KMF', + KPW = 'KPW', + KRW = 'KRW', + KWD = 'KWD', + KYD = 'KYD', + KZT = 'KZT', + LAK = 'LAK', + LBP = 'LBP', + LKR = 'LKR', + LRD = 'LRD', + LSL = 'LSL', + LYD = 'LYD', + MAD = 'MAD', + MDL = 'MDL', + MGA = 'MGA', + MKD = 'MKD', + MMK = 'MMK', + MNT = 'MNT', + MOP = 'MOP', + MRU = 'MRU', + MUR = 'MUR', + MVR = 'MVR', + MWK = 'MWK', + MXN = 'MXN', + MYR = 'MYR', + MZN = 'MZN', + NAD = 'NAD', + NGN = 'NGN', + NIO = 'NIO', + NOK = 'NOK', + NPR = 'NPR', + NZD = 'NZD', + OMR = 'OMR', + PAB = 'PAB', + PEN = 'PEN', + PGK = 'PGK', + PHP = 'PHP', + PKR = 'PKR', + PLN = 'PLN', + PYG = 'PYG', + QAR = 'QAR', + RON = 'RON', + RSD = 'RSD', + RUB = 'RUB', + RWF = 'RWF', + SAR = 'SAR', + SBD = 'SBD', + SCR = 'SCR', + SDG = 'SDG', + SEK = 'SEK', + SGD = 'SGD', + SHP = 'SHP', + SLL = 'SLL', + SOS = 'SOS', + SRD = 'SRD', + SSP = 'SSP', + STN = 'STN', + SVC = 'SVC', + SYP = 'SYP', + SZL = 'SZL', + THB = 'THB', + TJS = 'TJS', + TMT = 'TMT', + TND = 'TND', + TOP = 'TOP', + TRY = 'TRY', + TTD = 'TTD', + TWD = 'TWD', + TZS = 'TZS', + UAH = 'UAH', + UGX = 'UGX', + USD = 'USD', + UYU = 'UYU', + UZS = 'UZS', + VES = 'VES', + VND = 'VND', + VUV = 'VUV', + WST = 'WST', + XAF = 'XAF', + XCD = 'XCD', + XOF = 'XOF', + XPF = 'XPF', + YER = 'YER', + ZAR = 'ZAR', + ZMW = 'ZMW', + ZWL = 'ZWL', +} + +export function NumericCell(props: NumericCellProps) { + const { value, locale = LocaleCode.en_US, options } = props; + let displayValue = value?.toString() ?? value; + try { + displayValue = value?.toLocaleString?.(locale, options); + } catch (e) { + logging.error(e); + } + + return <span>{displayValue}</span>; +} + +export default NumericCell; diff --git a/superset-frontend/src/dashboard/stylesheets/components/markdown.less b/superset-frontend/src/components/Table/cell-renderers/TimeCell/TimeCell.stories.tsx similarity index 57% rename from superset-frontend/src/dashboard/stylesheets/components/markdown.less rename to superset-frontend/src/components/Table/cell-renderers/TimeCell/TimeCell.stories.tsx index d8b3676eb8e96..f37c5b8c6af3b 100644 --- a/superset-frontend/src/dashboard/stylesheets/components/markdown.less +++ b/superset-frontend/src/components/Table/cell-renderers/TimeCell/TimeCell.stories.tsx @@ -16,42 +16,28 @@ * specific language governing permissions and limitations * under the License. */ -.dashboard-markdown { - overflow: hidden; +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { TimeFormats } from '@superset-ui/core'; +import TimeCell from '.'; - h4, - h5, - h6 { - font-weight: @font-weight-normal; - } +export default { + title: 'Design System/Components/Table/Cell Renderers/TimeCell', + component: TimeCell, +} as ComponentMeta<typeof TimeCell>; - h5 { - color: @gray-heading; - } +export const Basic: ComponentStory<typeof TimeCell> = args => ( + <TimeCell {...args} /> +); - h6 { - font-size: @font-size-s; - } +Basic.args = { + value: Date.now(), +}; - .dashboard-component-chart-holder { - overflow-y: auto; - overflow-x: hidden; - } - - .dashboard--editing & { - cursor: move; - } - - #ace-editor { - border: none; - } -} - -/* maximize editing space */ -.dashboard-markdown--editing { - .dashboard-component-chart-holder { - .with-popover-menu--focused & { - padding: 1px; - } - } -} +Basic.argTypes = { + format: { + defaultValue: TimeFormats.DATABASE_DATETIME, + control: 'select', + options: Object.values(TimeFormats), + }, +}; diff --git a/superset-frontend/src/components/Table/cell-renderers/TimeCell/TimeCell.test.tsx b/superset-frontend/src/components/Table/cell-renderers/TimeCell/TimeCell.test.tsx new file mode 100644 index 0000000000000..81ccbed38acdd --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/TimeCell/TimeCell.test.tsx @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { TimeFormats } from '@superset-ui/core'; +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import TimeCell from '.'; + +const DATE = Date.parse('2022-01-01'); + +test('renders with default format', async () => { + render(<TimeCell value={DATE} />); + expect(screen.getByText('2022-01-01 00:00:00')).toBeInTheDocument(); +}); + +test('renders with custom format', async () => { + render(<TimeCell value={DATE} format={TimeFormats.DATABASE_DATE} />); + expect(screen.getByText('2022-01-01')).toBeInTheDocument(); +}); + +test('renders with number', async () => { + render(<TimeCell value={DATE.valueOf()} />); + expect(screen.getByText('2022-01-01 00:00:00')).toBeInTheDocument(); +}); + +test('renders with no value', async () => { + render(<TimeCell />); + expect(screen.getByText('N/A')).toBeInTheDocument(); +}); + +test('renders with invalid date format', async () => { + render(<TimeCell format="aaa-bbb-ccc" value={DATE} />); + expect(screen.getByText('aaa-bbb-ccc')).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/components/Table/cell-renderers/TimeCell/index.tsx b/superset-frontend/src/components/Table/cell-renderers/TimeCell/index.tsx new file mode 100644 index 0000000000000..31a9dac247295 --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/TimeCell/index.tsx @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { getTimeFormatter, TimeFormats } from '@superset-ui/core'; +import NullCell from '../NullCell'; + +export interface TimeCellProps { + format?: string; + value?: number | Date; +} + +function TimeCell({ + format = TimeFormats.DATABASE_DATETIME, + value, +}: TimeCellProps) { + if (value) { + return <span>{getTimeFormatter(format).format(value)}</span>; + } + return <NullCell />; +} + +export default TimeCell; diff --git a/superset-frontend/src/components/Table/cell-renderers/fixtures.ts b/superset-frontend/src/components/Table/cell-renderers/fixtures.ts new file mode 100644 index 0000000000000..9b2070b0359bb --- /dev/null +++ b/superset-frontend/src/components/Table/cell-renderers/fixtures.ts @@ -0,0 +1,25 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * License); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +export const exampleRow = { + key: 1, + buttonCell: 'Click Me', + textCell: 'Some text', + euroCell: 45.5, + dollarCell: 45.5, +}; diff --git a/superset-frontend/src/components/Table/header-renderers/HeaderWithRadioGroup.tsx b/superset-frontend/src/components/Table/header-renderers/HeaderWithRadioGroup.tsx new file mode 100644 index 0000000000000..65fd435119ffb --- /dev/null +++ b/superset-frontend/src/components/Table/header-renderers/HeaderWithRadioGroup.tsx @@ -0,0 +1,94 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useState } from 'react'; +import { css, useTheme } from '@superset-ui/core'; +import { Radio } from 'src/components/Radio'; +import { Space } from 'src/components'; +import Icons from 'src/components/Icons'; +import Popover from 'src/components/Popover'; + +export interface HeaderWithRadioGroupProps { + headerTitle: string; + groupTitle: string; + groupOptions: { label: string; value: string | number }[]; + value?: string | number; + onChange: (value: string) => void; +} + +function HeaderWithRadioGroup(props: HeaderWithRadioGroupProps) { + const { headerTitle, groupTitle, groupOptions, value, onChange } = props; + const theme = useTheme(); + const [popoverVisible, setPopoverVisible] = useState(false); + + return ( + <div + css={css` + display: flex; + align-items: center; + `} + > + <Popover + trigger="click" + visible={popoverVisible} + content={ + <div> + <div + css={css` + font-weight: ${theme.typography.weights.bold}; + margin-bottom: ${theme.gridUnit}px; + `} + > + {groupTitle} + </div> + <Radio.Group + value={value} + onChange={e => { + onChange(e.target.value); + setPopoverVisible(false); + }} + > + <Space direction="vertical"> + {groupOptions.map(option => ( + <Radio key={option.value} value={option.value}> + {option.label} + </Radio> + ))} + </Space> + </Radio.Group> + </div> + } + placement="bottomLeft" + arrowPointAtCenter + > + <Icons.SettingOutlined + iconSize="m" + iconColor={theme.colors.grayscale.light1} + css={css` + margin-top: 3px; // we need exactly 3px to align the icon + margin-right: ${theme.gridUnit}px; + `} + onClick={() => setPopoverVisible(true)} + /> + </Popover> + {headerTitle} + </div> + ); +} + +export default HeaderWithRadioGroup; diff --git a/superset-frontend/src/components/Table/index.tsx b/superset-frontend/src/components/Table/index.tsx new file mode 100644 index 0000000000000..55b004570ad1b --- /dev/null +++ b/superset-frontend/src/components/Table/index.tsx @@ -0,0 +1,454 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * License); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useState, useEffect, useRef, ReactElement } from 'react'; +import { Table as AntTable, ConfigProvider } from 'antd'; +import { + ColumnType, + ColumnGroupType, + TableProps as AntTableProps, +} from 'antd/es/table'; +import { PaginationProps } from 'antd/es/pagination'; +import { Key } from 'antd/lib/table/interface'; +import { t, useTheme, logging } from '@superset-ui/core'; +import Loading from 'src/components/Loading'; +import styled, { StyledComponent } from '@emotion/styled'; +import InteractiveTableUtils from './utils/InteractiveTableUtils'; +import VirtualTable from './VirtualTable'; + +export const SUPERSET_TABLE_COLUMN = 'superset/table-column'; +export interface TableDataType { + key: React.Key; +} + +export interface TablePaginationConfig extends PaginationProps { + extra?: object; +} + +export type ColumnsType<RecordType = unknown> = ( + | ColumnGroupType<RecordType> + | ColumnType<RecordType> +)[]; + +export enum SelectionType { + 'DISABLED' = 'disabled', + 'SINGLE' = 'single', + 'MULTI' = 'multi', +} + +export interface Locale { + /** + * Text contained within the Table UI. + */ + filterTitle: string; + filterConfirm: string; + filterReset: string; + filterEmptyText: string; + filterCheckall: string; + filterSearchPlaceholder: string; + emptyText: string; + selectAll: string; + selectInvert: string; + selectNone: string; + selectionAll: string; + sortTitle: string; + expand: string; + collapse: string; + triggerDesc: string; + triggerAsc: string; + cancelSort: string; +} + +export type SortOrder = 'descend' | 'ascend' | null; +export interface SorterResult<RecordType> { + column?: ColumnType<RecordType>; + order?: SortOrder; + field?: Key | Key[]; + columnKey?: Key; +} + +export enum ETableAction { + PAGINATE = 'paginate', + SORT = 'sort', + FILTER = 'filter', +} + +export interface TableCurrentDataSource<RecordType> { + currentDataSource: RecordType[]; + action: ETableAction; +} + +export type OnChangeFunction = ( + pagination: TablePaginationConfig, + filters: Record<string, (Key | boolean)[] | null>, + sorter: SorterResult<any> | SorterResult<any>[], + extra: TableCurrentDataSource<any>, +) => void; + +export interface TableProps extends AntTableProps<TableProps> { + /** + * Data that will populate the each row and map to the column key. + */ + data: object[]; + /** + * Table column definitions. + */ + columns: ColumnsType<any>; + /** + * Array of row keys to represent list of selected rows. + */ + selectedRows?: React.Key[]; + /** + * Callback function invoked when a row is selected by user. + */ + handleRowSelection?: Function; + /** + * Controls the size of the table. + */ + size: TableSize; + /** + * Adjusts the padding around elements for different amounts of spacing between elements. + */ + selectionType?: SelectionType; + /* + * Places table in visual loading state. Use while waiting to retrieve data or perform an async operation that will update the table. + */ + loading?: boolean; + /** + * Uses a sticky header which always displays when vertically scrolling the table. Default: true + */ + sticky?: boolean; + /** + * Controls if columns are resizable by user. + */ + resizable?: boolean; + /** + * EXPERIMENTAL: Controls if columns are re-orderable by user drag drop. + */ + reorderable?: boolean; + /** + * Controls if pagination is active or disabled. + */ + usePagination?: boolean; + /** + * Default number of rows table will display per page of data. + */ + defaultPageSize?: number; + /** + * Array of numeric options for the number of rows table will display per page of data. + * The user can select from these options in the page size drop down menu. + */ + pageSizeOptions?: string[]; + /** + * Set table to display no data even if data has been provided + */ + hideData?: boolean; + /** + * emptyComponent + */ + emptyComponent?: ReactElement; + /** + * Enables setting the text displayed in various components and tooltips within the Table UI. + */ + locale?: Locale; + /** + * Restricts the visible height of the table and allows for internal scrolling within the table + * when the number of rows exceeds the visible space. + */ + height?: number; + /** + * Sets the table to use react-window for scroll virtualization in cases where + * there are unknown amount of columns, or many, many rows + */ + virtualize?: boolean; + /** + * Used to override page controls total record count when using server-side paging. + */ + recordCount?: number; + /** + * Invoked when the tables sorting, paging, or filtering is changed. + */ + onChange?: OnChangeFunction; +} + +interface IPaginationOptions { + hideOnSinglePage: boolean; + pageSize: number; + pageSizeOptions: string[]; + onShowSizeChange: Function; + total?: number; +} + +export enum TableSize { + SMALL = 'small', + MIDDLE = 'middle', +} + +const defaultRowSelection: React.Key[] = []; + +const PAGINATION_HEIGHT = 40; +const HEADER_HEIGHT = 68; + +const StyledTable: StyledComponent<any> = styled(AntTable)<any>( + ({ theme, height }) => ` + .ant-table-body { + overflow: auto; + height: ${height ? `${height}px` : undefined}; + } + + th.ant-table-cell { + font-weight: ${theme.typography.weights.bold}; + color: ${theme.colors.grayscale.dark1}; + user-select: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .ant-table-tbody > tr > td { + user-select: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + border-bottom: 1px solid ${theme.colors.grayscale.light3}; + } + + .ant-pagination-item-active { + border-color: ${theme.colors.primary.base}; + } + } +`, +); + +const StyledVirtualTable: StyledComponent<any> = styled(VirtualTable)<any>( + ({ theme }) => ` + .virtual-table .ant-table-container:before, + .virtual-table .ant-table-container:after { + display: none; + } + .virtual-table-cell { + box-sizing: border-box; + padding: ${theme.gridUnit * 4}px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +`, +); + +const defaultLocale = { + filterTitle: t('Filter menu'), + filterConfirm: t('OK'), + filterReset: t('Reset'), + filterEmptyText: t('No filters'), + filterCheckall: t('Select all items'), + filterSearchPlaceholder: t('Search in filters'), + emptyText: t('No data'), + selectAll: t('Select current page'), + selectInvert: t('Invert current page'), + selectNone: t('Clear all data'), + selectionAll: t('Select all data'), + sortTitle: t('Sort'), + expand: t('Expand row'), + collapse: t('Collapse row'), + triggerDesc: t('Click to sort descending'), + triggerAsc: t('Click to sort ascending'), + cancelSort: t('Click to cancel sorting'), +}; + +const selectionMap = {}; +const noop = () => {}; +selectionMap[SelectionType.MULTI] = 'checkbox'; +selectionMap[SelectionType.SINGLE] = 'radio'; +selectionMap[SelectionType.DISABLED] = null; + +export function Table(props: TableProps) { + const { + data, + columns, + selectedRows = defaultRowSelection, + handleRowSelection, + size = TableSize.SMALL, + selectionType = SelectionType.DISABLED, + sticky = true, + loading = false, + resizable = false, + reorderable = false, + usePagination = true, + defaultPageSize = 15, + pageSizeOptions = ['5', '15', '25', '50', '100'], + hideData = false, + emptyComponent, + locale, + height, + virtualize = false, + onChange = noop, + recordCount, + } = props; + + const wrapperRef = useRef<HTMLDivElement | null>(null); + const [derivedColumns, setDerivedColumns] = useState(columns); + const [pageSize, setPageSize] = useState(defaultPageSize); + const [mergedLocale, setMergedLocale] = useState({ ...defaultLocale }); + const [selectedRowKeys, setSelectedRowKeys] = + useState<React.Key[]>(selectedRows); + const interactiveTableUtils = useRef<InteractiveTableUtils | null>(null); + + const onSelectChange = (newSelectedRowKeys: React.Key[]) => { + setSelectedRowKeys(newSelectedRowKeys); + handleRowSelection?.(newSelectedRowKeys); + }; + + const selectionTypeValue = selectionMap[selectionType]; + const rowSelection = { + type: selectionTypeValue, + selectedRowKeys, + onChange: onSelectChange, + }; + + const renderEmpty = () => + emptyComponent ?? <div>{mergedLocale.emptyText}</div>; + + // Log use of experimental features + useEffect(() => { + if (reorderable === true) { + logging.warn( + 'EXPERIMENTAL FEATURE ENABLED: The "reorderable" prop of Table is experimental and NOT recommended for use in production deployments.', + ); + } + if (resizable === true) { + logging.warn( + 'EXPERIMENTAL FEATURE ENABLED: The "resizable" prop of Table is experimental and NOT recommended for use in production deployments.', + ); + } + }, [reorderable, resizable]); + + useEffect(() => { + let updatedLocale; + if (locale) { + // This spread allows for locale to only contain a subset of locale overrides on props + updatedLocale = { ...defaultLocale, ...locale }; + } else { + updatedLocale = { ...defaultLocale }; + } + setMergedLocale(updatedLocale); + }, [locale]); + + useEffect(() => setDerivedColumns(columns), [columns]); + + useEffect(() => { + if (interactiveTableUtils.current) { + interactiveTableUtils.current?.clearListeners(); + } + const table = wrapperRef.current?.getElementsByTagName('table')[0]; + if (table) { + interactiveTableUtils.current = new InteractiveTableUtils( + table, + derivedColumns, + setDerivedColumns, + ); + if (reorderable) { + interactiveTableUtils?.current?.initializeDragDropColumns( + reorderable, + table, + ); + } + if (resizable) { + interactiveTableUtils?.current?.initializeResizableColumns( + resizable, + table, + ); + } + } + return () => { + interactiveTableUtils?.current?.clearListeners?.(); + }; + /** + * We DO NOT want this effect to trigger when derivedColumns changes as it will break functionality + * The exclusion from the effect dependencies is intentional and should not be modified + */ + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [wrapperRef, reorderable, resizable, virtualize, interactiveTableUtils]); + + const theme = useTheme(); + + const paginationSettings: IPaginationOptions | false = usePagination + ? { + hideOnSinglePage: true, + pageSize, + pageSizeOptions, + onShowSizeChange: (page: number, size: number) => setPageSize(size), + } + : false; + + /** + * When recordCount is provided it lets the user of Table control total number of pages + * independent from data.length. This allows the parent component do things like server side paging + * where the user can be shown the total mount of data they can page through, but the component can provide + * data one page at a time, and respond to the onPageChange event to fetch and set new data + */ + if (paginationSettings && recordCount) { + paginationSettings.total = recordCount; + } + + let bodyHeight = height; + if (bodyHeight) { + bodyHeight -= HEADER_HEIGHT; + const hasPagination = + usePagination && recordCount && recordCount > pageSize; + if (hasPagination) { + bodyHeight -= PAGINATION_HEIGHT; + } + } + + const sharedProps = { + loading: { spinning: loading ?? false, indicator: <Loading /> }, + hasData: hideData ? false : data, + columns: derivedColumns, + dataSource: hideData ? [undefined] : data, + size, + pagination: paginationSettings, + locale: mergedLocale, + showSorterTooltip: false, + onChange, + theme, + height: bodyHeight, + }; + + return ( + <ConfigProvider renderEmpty={renderEmpty}> + <div ref={wrapperRef}> + {!virtualize && ( + <StyledTable + {...sharedProps} + rowSelection={selectionTypeValue ? rowSelection : undefined} + sticky={sticky} + /> + )} + {virtualize && ( + <StyledVirtualTable + {...sharedProps} + scroll={{ y: 300, x: '100vw' }} + /> + )} + </div> + </ConfigProvider> + ); +} + +export default Table; diff --git a/superset-frontend/src/components/Table/sorters.test.ts b/superset-frontend/src/components/Table/sorters.test.ts new file mode 100644 index 0000000000000..80bc0a20c42c5 --- /dev/null +++ b/superset-frontend/src/components/Table/sorters.test.ts @@ -0,0 +1,100 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { alphabeticalSort, numericalSort } from './sorters'; + +const rows = [ + { + name: 'Deathstar Lamp', + category: 'Lamp', + cost: 75.99, + }, + { + name: 'Desk Lamp', + category: 'Lamp', + cost: 15.99, + }, + { + name: 'Bedside Lamp', + category: 'Lamp', + cost: 15.99, + }, + { name: 'Drafting Desk', category: 'Desk', cost: 125 }, + { name: 'Sit / Stand Desk', category: 'Desk', cost: 275.99 }, +]; + +/** + * NOTE: Sorters for antd table use < 0, 0, > 0 for sorting + * -1 or less means the first item comes after the second item + * 0 means the items sort values is equivalent + * 1 or greater means the first item comes before the second item + */ +test('alphabeticalSort sorts correctly', () => { + expect(alphabeticalSort('name', rows[0], rows[1])).toBe(-1); + expect(alphabeticalSort('name', rows[1], rows[0])).toBe(1); + expect(alphabeticalSort('category', rows[1], rows[0])).toBe(0); +}); + +test('numericalSort sorts correctly', () => { + expect(numericalSort('cost', rows[1], rows[2])).toBe(0); + expect(numericalSort('cost', rows[1], rows[0])).toBeLessThan(0); + expect(numericalSort('cost', rows[4], rows[1])).toBeGreaterThan(0); +}); + +/** + * We want to make sure our sorters do not throw runtime errors given bad inputs. + * Runtime Errors in a sorter will cause a catastrophic React lifecycle error and produce white screen of death + * In the case the sorter cannot perform the comparison it should return undefined and the next sort step will proceed without error + */ +test('alphabeticalSort bad inputs no errors', () => { + // @ts-ignore + expect(alphabeticalSort('name', null, null)).toBe(undefined); + // incorrect non-object values + // @ts-ignore + expect(alphabeticalSort('name', 3, [])).toBe(undefined); + // incorrect object values without specificed key + expect(alphabeticalSort('name', {}, {})).toBe(undefined); + // Object as value for name when it should be a string + expect( + alphabeticalSort( + 'name', + { name: { title: 'the name attribute should not be an object' } }, + { name: 'Doug' }, + ), + ).toBe(undefined); +}); + +test('numericalSort bad inputs no errors', () => { + // @ts-ignore + expect(numericalSort('name', undefined, undefined)).toBe(NaN); + // @ts-ignore + expect(numericalSort('name', null, null)).toBe(NaN); + // incorrect non-object values + // @ts-ignore + expect(numericalSort('name', 3, [])).toBe(NaN); + // incorrect object values without specified key + expect(numericalSort('name', {}, {})).toBe(NaN); + // Object as value for name when it should be a string + expect( + numericalSort( + 'name', + { name: { title: 'the name attribute should not be an object' } }, + { name: 'Doug' }, + ), + ).toBe(NaN); +}); diff --git a/superset-frontend/src/SqlLab/components/SouthPane/state.ts b/superset-frontend/src/components/Table/sorters.ts similarity index 56% rename from superset-frontend/src/SqlLab/components/SouthPane/state.ts rename to superset-frontend/src/components/Table/sorters.ts index 9963739fa6d48..3f06071aacc69 100644 --- a/superset-frontend/src/SqlLab/components/SouthPane/state.ts +++ b/superset-frontend/src/components/Table/sorters.ts @@ -16,24 +16,21 @@ * specific language governing permissions and limitations * under the License. */ -import { connect } from 'react-redux'; -import { bindActionCreators, Dispatch } from 'redux'; -import * as Actions from 'src/SqlLab/actions/sqlLab'; -import SouthPane from '.'; -function mapStateToProps({ sqlLab }: Record<string, any>) { - return { - activeSouthPaneTab: sqlLab.activeSouthPaneTab, - databases: sqlLab.databases, - offline: sqlLab.offline, - user: sqlLab.user, - }; -} - -function mapDispatchToProps(dispatch: Dispatch) { - return { - actions: bindActionCreators<any, any>(Actions, dispatch), - }; -} +/** + * @param key The name of the row's attribute used to compare values for alphabetical sorting + * @param a First row object to compare + * @param b Second row object to compare + * @returns number + */ +export const alphabeticalSort = (key: string, a: object, b: object): number => + a?.[key]?.localeCompare?.(b?.[key]); -export default connect<any>(mapStateToProps, mapDispatchToProps)(SouthPane); +/** + * @param key The name of the row's attribute used to compare values for numerical sorting + * @param a First row object to compare + * @param b Second row object to compare + * @returns number + */ +export const numericalSort = (key: string, a: object, b: object): number => + a?.[key] - b?.[key]; diff --git a/superset-frontend/src/components/Table/utils/InteractiveTableUtils.ts b/superset-frontend/src/components/Table/utils/InteractiveTableUtils.ts new file mode 100644 index 0000000000000..94977413e2cdc --- /dev/null +++ b/superset-frontend/src/components/Table/utils/InteractiveTableUtils.ts @@ -0,0 +1,233 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import type { ColumnsType } from 'antd/es/table'; +import { SUPERSET_TABLE_COLUMN } from 'src/components/Table'; +import { withinRange } from './utils'; + +interface IInteractiveColumn extends HTMLElement { + mouseDown: boolean; + oldX: number; + oldWidth: number; + draggable: boolean; +} +export default class InteractiveTableUtils { + tableRef: HTMLTableElement | null; + + columnRef: IInteractiveColumn | null; + + setDerivedColumns: Function; + + isDragging: boolean; + + resizable: boolean; + + reorderable: boolean; + + derivedColumns: ColumnsType<any>; + + RESIZE_INDICATOR_THRESHOLD: number; + + constructor( + tableRef: HTMLTableElement, + derivedColumns: ColumnsType<any>, + setDerivedColumns: Function, + ) { + this.setDerivedColumns = setDerivedColumns; + this.tableRef = tableRef; + this.isDragging = false; + this.RESIZE_INDICATOR_THRESHOLD = 8; + this.resizable = false; + this.reorderable = false; + this.derivedColumns = [...derivedColumns]; + document.addEventListener('mouseup', this.handleMouseup); + } + + clearListeners = () => { + document.removeEventListener('mouseup', this.handleMouseup); + this.initializeResizableColumns(false, this.tableRef); + this.initializeDragDropColumns(false, this.tableRef); + }; + + setTableRef = (table: HTMLTableElement) => { + this.tableRef = table; + }; + + getColumnIndex = (): number => { + let index = -1; + const parent = this.columnRef?.parentNode; + if (parent) { + index = Array.prototype.indexOf.call(parent.children, this.columnRef); + } + return index; + }; + + handleColumnDragStart = (ev: DragEvent): void => { + const target = ev?.currentTarget as IInteractiveColumn; + if (target) { + this.columnRef = target; + } + this.isDragging = true; + const index = this.getColumnIndex(); + const columnData = this.derivedColumns[index]; + const dragData = { index, columnData }; + ev?.dataTransfer?.setData(SUPERSET_TABLE_COLUMN, JSON.stringify(dragData)); + }; + + handleDragDrop = (ev: DragEvent): void => { + const data = ev.dataTransfer?.getData?.(SUPERSET_TABLE_COLUMN); + if (data) { + ev.preventDefault(); + const parent = (ev.currentTarget as HTMLElement) + ?.parentNode as HTMLElement; + const dropIndex = Array.prototype.indexOf.call( + parent.children, + ev.currentTarget, + ); + const dragIndex = this.getColumnIndex(); + const columnsCopy = [...this.derivedColumns]; + const removedItem = columnsCopy.slice(dragIndex, dragIndex + 1); + columnsCopy.splice(dragIndex, 1); + columnsCopy.splice(dropIndex, 0, removedItem[0]); + this.derivedColumns = [...columnsCopy]; + this.setDerivedColumns(columnsCopy); + } + }; + + allowDrop = (ev: DragEvent): void => { + ev.preventDefault(); + }; + + handleMouseDown = (event: MouseEvent) => { + const target = event?.currentTarget as IInteractiveColumn; + if (target) { + this.columnRef = target; + if ( + event && + withinRange( + event.offsetX, + target.offsetWidth, + this.RESIZE_INDICATOR_THRESHOLD, + ) + ) { + target.mouseDown = true; + target.oldX = event.x; + target.oldWidth = target.offsetWidth; + target.draggable = false; + } else if (this.reorderable) { + target.draggable = true; + } + } + }; + + handleMouseMove = (event: MouseEvent) => { + if (this.resizable === true && !this.isDragging) { + const target = event.currentTarget as IInteractiveColumn; + if ( + event && + withinRange( + event.offsetX, + target.offsetWidth, + this.RESIZE_INDICATOR_THRESHOLD, + ) + ) { + target.style.cursor = 'col-resize'; + } else { + target.style.cursor = 'default'; + } + + const column = this.columnRef; + if (column?.mouseDown) { + let width = column.oldWidth; + const diff = event.x - column.oldX; + if (column.oldWidth + (event.x - column.oldX) > 0) { + width = column.oldWidth + diff; + } + const colIndex = this.getColumnIndex(); + if (!Number.isNaN(colIndex)) { + const columnDef = { ...this.derivedColumns[colIndex] }; + columnDef.width = width; + this.derivedColumns[colIndex] = columnDef; + this.setDerivedColumns([...this.derivedColumns]); + } + } + } + }; + + handleMouseup = () => { + if (this.columnRef) { + this.columnRef.mouseDown = false; + this.columnRef.style.cursor = 'default'; + this.columnRef.draggable = false; + } + this.isDragging = false; + }; + + initializeResizableColumns = ( + resizable = false, + table: HTMLTableElement | null, + ) => { + this.tableRef = table; + const header: HTMLTableRowElement | undefined = this.tableRef?.rows?.[0]; + if (header) { + const { cells } = header; + const len = cells.length; + for (let i = 0; i < len; i += 1) { + const cell = cells[i]; + if (resizable === true) { + this.resizable = true; + cell.addEventListener('mousedown', this.handleMouseDown); + cell.addEventListener('mousemove', this.handleMouseMove, true); + } else { + this.resizable = false; + cell.removeEventListener('mousedown', this.handleMouseDown); + cell.removeEventListener('mousemove', this.handleMouseMove, true); + } + } + } + }; + + initializeDragDropColumns = ( + reorderable = false, + table: HTMLTableElement | null, + ) => { + this.tableRef = table; + const header: HTMLTableRowElement | undefined = this.tableRef?.rows?.[0]; + if (header) { + const { cells } = header; + const len = cells.length; + for (let i = 0; i < len; i += 1) { + const cell = cells[i]; + if (reorderable === true) { + this.reorderable = true; + cell.addEventListener('mousedown', this.handleMouseDown); + cell.addEventListener('dragover', this.allowDrop); + cell.addEventListener('dragstart', this.handleColumnDragStart); + cell.addEventListener('drop', this.handleDragDrop); + } else { + this.reorderable = false; + cell.draggable = false; + cell.removeEventListener('mousedown', this.handleMouseDown); + cell.removeEventListener('dragover', this.allowDrop); + cell.removeEventListener('dragstart', this.handleColumnDragStart); + cell.removeEventListener('drop', this.handleDragDrop); + } + } + } + }; +} diff --git a/superset-frontend/src/components/Table/utils/utils.test.ts b/superset-frontend/src/components/Table/utils/utils.test.ts new file mode 100644 index 0000000000000..eff50f1580fc0 --- /dev/null +++ b/superset-frontend/src/components/Table/utils/utils.test.ts @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { withinRange } from './utils'; + +test('withinRange supported positive numbers', () => { + // Valid inputs within range + expect(withinRange(50, 60, 16)).toBeTruthy(); + + // Valid inputs outside of range + expect(withinRange(40, 60, 16)).toBeFalsy(); +}); + +test('withinRange unsupported negative numbers', () => { + // Negative numbers not supported + expect(withinRange(65, 60, -16)).toBeFalsy(); + expect(withinRange(-60, -65, 16)).toBeFalsy(); + expect(withinRange(-60, -65, 16)).toBeFalsy(); + expect(withinRange(-60, 65, 16)).toBeFalsy(); +}); + +test('withinRange invalid inputs', () => { + // Invalid inputs should return falsy and not throw an error + // We need ts-ignore here to be able to pass invalid values and pass linting + // @ts-ignore + expect(withinRange(null, 60, undefined)).toBeFalsy(); + // @ts-ignore + expect(withinRange([], 'hello', {})).toBeFalsy(); + // @ts-ignore + expect(withinRange([], undefined, {})).toBeFalsy(); + // @ts-ignore + expect(withinRange([], 'hello', {})).toBeFalsy(); +}); diff --git a/superset-frontend/src/components/Table/utils/utils.ts b/superset-frontend/src/components/Table/utils/utils.ts new file mode 100644 index 0000000000000..5b4e4d13baa85 --- /dev/null +++ b/superset-frontend/src/components/Table/utils/utils.ts @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Method to check if a number is within inclusive range between a maximum value minus a threshold + * Invalid non numeric inputs will not error, but will return false + * + * @param value number coordinate to determine if it is within bounds of the targetCoordinate - threshold. Must be positive and less than maximum. + * @param maximum number max value for the test range. Must be positive and greater than value + * @param threshold number values to determine a range from maximum - threshold. Must be positive and greater than zero. + * @returns boolean + */ +export const withinRange = ( + value: number, + maximum: number, + threshold: number, +): boolean => { + let within = false; + const diff = maximum - value; + if (diff > 0 && diff <= threshold) { + within = true; + } + return within; +}; diff --git a/superset-frontend/src/components/TableCollection/index.tsx b/superset-frontend/src/components/TableCollection/index.tsx index ad83f3b9027f2..88296edf638ee 100644 --- a/superset-frontend/src/components/TableCollection/index.tsx +++ b/superset-frontend/src/components/TableCollection/index.tsx @@ -292,9 +292,9 @@ export default React.memo( {row.cells.map(cell => { if (cell.column.hidden) return null; const columnCellProps = cell.column.cellProps || {}; - const isWrapText = - columnsForWrapText && - columnsForWrapText.includes(cell.column.Header as string); + const isWrapText = columnsForWrapText?.includes( + cell.column.Header as string, + ); return ( <td diff --git a/superset-frontend/src/components/TableSelector/TableSelector.test.tsx b/superset-frontend/src/components/TableSelector/TableSelector.test.tsx index 32d84c008605c..b4b67deb92dca 100644 --- a/superset-frontend/src/components/TableSelector/TableSelector.test.tsx +++ b/superset-frontend/src/components/TableSelector/TableSelector.test.tsx @@ -19,55 +19,60 @@ import React from 'react'; import { render, screen, waitFor, within } from 'spec/helpers/testing-library'; -import { SupersetClient } from '@superset-ui/core'; +import { queryClient } from 'src/views/QueryProvider'; +import fetchMock from 'fetch-mock'; import { act } from 'react-dom/test-utils'; import userEvent from '@testing-library/user-event'; import TableSelector, { TableSelectorMultiple } from '.'; -const SupersetClientGet = jest.spyOn(SupersetClient, 'get'); - const createProps = (props = {}) => ({ database: { id: 1, database_name: 'main', backend: 'sqlite', - allow_multi_schema_metadata_fetch: false, }, schema: 'test_schema', handleError: jest.fn(), ...props, }); -afterEach(() => { - jest.clearAllMocks(); -}); - -const getSchemaMockFunction = async () => +const getSchemaMockFunction = () => ({ - json: { - result: ['schema_a', 'schema_b'], - }, + result: ['schema_a', 'schema_b'], } as any); -const getTableMockFunction = async () => +const getTableMockFunction = () => ({ - json: { - options: [ - { label: 'table_a', value: 'table_a' }, - { label: 'table_b', value: 'table_b' }, - { label: 'table_c', value: 'table_c' }, - { label: 'table_d', value: 'table_d' }, - ], - }, + count: 4, + result: [ + { label: 'table_a', value: 'table_a' }, + { label: 'table_b', value: 'table_b' }, + { label: 'table_c', value: 'table_c' }, + { label: 'table_d', value: 'table_d' }, + ], } as any); +const databaseApiRoute = 'glob:*/api/v1/database/?*'; +const schemaApiRoute = 'glob:*/api/v1/database/*/schemas/?*'; +const tablesApiRoute = 'glob:*/api/v1/database/*/tables/*'; + const getSelectItemContainer = (select: HTMLElement) => select.parentElement?.parentElement?.getElementsByClassName( 'ant-select-selection-item', ); +beforeEach(() => { + queryClient.clear(); + fetchMock.get(databaseApiRoute, { result: [] }); +}); + +afterEach(() => { + fetchMock.reset(); +}); + test('renders with default props', async () => { - SupersetClientGet.mockImplementation(getTableMockFunction); + fetchMock.get(schemaApiRoute, { result: [] }); + fetchMock.get(tablesApiRoute, getTableMockFunction()); const props = createProps(); render(<TableSelector {...props} />, { useRedux: true }); @@ -88,7 +93,8 @@ test('renders with default props', async () => { }); test('renders table options', async () => { - SupersetClientGet.mockImplementation(getTableMockFunction); + fetchMock.get(schemaApiRoute, { result: ['test_schema'] }); + fetchMock.get(tablesApiRoute, getTableMockFunction()); const props = createProps(); render(<TableSelector {...props} />, { useRedux: true }); @@ -105,7 +111,8 @@ test('renders table options', async () => { }); test('renders disabled without schema', async () => { - SupersetClientGet.mockImplementation(getTableMockFunction); + fetchMock.get(schemaApiRoute, { result: [] }); + fetchMock.get(tablesApiRoute, getTableMockFunction()); const props = createProps(); render(<TableSelector {...props} schema={undefined} />, { useRedux: true }); @@ -118,7 +125,7 @@ test('renders disabled without schema', async () => { }); test('table options are notified after schema selection', async () => { - SupersetClientGet.mockImplementation(getSchemaMockFunction); + fetchMock.get(schemaApiRoute, getSchemaMockFunction()); const callback = jest.fn(); const props = createProps({ @@ -142,7 +149,7 @@ test('table options are notified after schema selection', async () => { await screen.findByRole('option', { name: 'schema_b' }), ).toBeInTheDocument(); - SupersetClientGet.mockImplementation(getTableMockFunction); + fetchMock.get(tablesApiRoute, getTableMockFunction()); act(() => { userEvent.click(screen.getAllByText('schema_a')[1]); @@ -159,7 +166,8 @@ test('table options are notified after schema selection', async () => { }); test('table select retain value if not in SQL Lab mode', async () => { - SupersetClientGet.mockImplementation(getTableMockFunction); + fetchMock.get(schemaApiRoute, { result: ['test_schema'] }); + fetchMock.get(tablesApiRoute, getTableMockFunction()); const callback = jest.fn(); const props = createProps({ @@ -182,7 +190,7 @@ test('table select retain value if not in SQL Lab mode', async () => { await screen.findByRole('option', { name: 'table_a' }), ).toBeInTheDocument(); - act(() => { + await waitFor(() => { userEvent.click(screen.getAllByText('table_a')[1]); }); @@ -199,7 +207,8 @@ test('table select retain value if not in SQL Lab mode', async () => { }); test('table multi select retain all the values selected', async () => { - SupersetClientGet.mockImplementation(getTableMockFunction); + fetchMock.get(schemaApiRoute, { result: ['test_schema'] }); + fetchMock.get(tablesApiRoute, getTableMockFunction()); const callback = jest.fn(); const props = createProps({ @@ -217,31 +226,19 @@ test('table multi select retain all the values selected', async () => { userEvent.click(tableSelect); - expect( - await screen.findByRole('option', { name: 'table_a' }), - ).toBeInTheDocument(); - - act(() => { - const item = screen.getAllByText('table_a'); + await waitFor(async () => { + const item = await screen.findAllByText('table_b'); userEvent.click(item[item.length - 1]); }); - act(() => { - const item = screen.getAllByText('table_c'); + await waitFor(async () => { + const item = await screen.findAllByText('table_c'); userEvent.click(item[item.length - 1]); }); - const selectedValueContainer = getSelectItemContainer(tableSelect); + const selection1 = await screen.findByRole('option', { name: 'table_b' }); + expect(selection1).toHaveAttribute('aria-selected', 'true'); - expect(selectedValueContainer).toHaveLength(2); - expect( - await within(selectedValueContainer?.[0] as HTMLElement).findByText( - 'table_a', - ), - ).toBeInTheDocument(); - expect( - await within(selectedValueContainer?.[1] as HTMLElement).findByText( - 'table_c', - ), - ).toBeInTheDocument(); + const selection2 = await screen.findByRole('option', { name: 'table_c' }); + expect(selection2).toHaveAttribute('aria-selected', 'true'); }); diff --git a/superset-frontend/src/components/TableSelector/index.tsx b/superset-frontend/src/components/TableSelector/index.tsx index fcc5dbe10d214..ffb45cc8fed9f 100644 --- a/superset-frontend/src/components/TableSelector/index.tsx +++ b/superset-frontend/src/components/TableSelector/index.tsx @@ -25,7 +25,7 @@ import React, { } from 'react'; import { SelectValue } from 'antd/lib/select'; -import { styled, SupersetClient, t } from '@superset-ui/core'; +import { styled, t } from '@superset-ui/core'; import { Select } from 'src/components'; import { FormLabel } from 'src/components/Form'; import Icons from 'src/components/Icons'; @@ -36,13 +36,21 @@ import RefreshLabel from 'src/components/RefreshLabel'; import CertifiedBadge from 'src/components/CertifiedBadge'; import WarningIconWithTooltip from 'src/components/WarningIconWithTooltip'; import { useToasts } from 'src/components/MessageToasts/withToasts'; +import { SchemaOption } from 'src/SqlLab/types'; +import { useTables, Table } from 'src/hooks/apiResources'; +import { + getClientErrorMessage, + getClientErrorObject, +} from 'src/utils/getClientErrorObject'; + +const REFRESH_WIDTH = 30; const TableSelectorWrapper = styled.div` ${({ theme }) => ` .refresh { display: flex; align-items: center; - width: 30px; + width: ${REFRESH_WIDTH}px; margin-left: ${theme.gridUnit}px; margin-top: ${theme.gridUnit * 5}px; } @@ -64,6 +72,7 @@ const TableSelectorWrapper = styled.div` .select { flex: 1; + max-width: calc(100% - ${theme.gridUnit + REFRESH_WIDTH}px) } `} `; @@ -81,15 +90,15 @@ const TableLabel = styled.span` interface TableSelectorProps { clearable?: boolean; - database?: DatabaseObject; + database?: DatabaseObject | null; emptyState?: ReactNode; formMode?: boolean; - getDbList?: (arg0: any) => {}; + getDbList?: (arg0: any) => void; handleError: (msg: string) => void; isDatabaseSelectEnabled?: boolean; onDbChange?: (db: DatabaseObject) => void; onSchemaChange?: (schema?: string) => void; - onSchemasLoad?: () => void; + onSchemasLoad?: (schemaOptions: SchemaOption[]) => void; onTablesLoad?: (options: Array<any>) => void; readOnly?: boolean; schema?: string; @@ -100,29 +109,16 @@ interface TableSelectorProps { tableSelectMode?: 'single' | 'multiple'; } -interface Table { - label: string; - value: string; - type: string; - extra?: { - certification?: { - certified_by: string; - details: string; - }; - warning_markdown?: string; - }; -} - -interface TableOption { +export interface TableOption { label: JSX.Element; text: string; value: string; } -const TableOption = ({ table }: { table: Table }) => { - const { label, type, extra } = table; +export const TableOption = ({ table }: { table: Table }) => { + const { value, type, extra } = table; return ( - <TableLabel title={label}> + <TableLabel title={value}> {type === 'view' ? ( <Icons.Eye iconSize="m" /> ) : ( @@ -141,11 +137,20 @@ const TableOption = ({ table }: { table: Table }) => { size="l" /> )} - {label} + {value} </TableLabel> ); }; +function renderSelectRow(select: ReactNode, refreshBtn: ReactNode) { + return ( + <div className="section"> + <span className="select">{select}</span> + <span className="refresh">{refreshBtn}</span> + </div> + ); +} + const TableSelector: FunctionComponent<TableSelectorProps> = ({ database, emptyState, @@ -165,26 +170,61 @@ const TableSelector: FunctionComponent<TableSelectorProps> = ({ tableValue = undefined, onTableSelectChange, }) => { - const [currentDatabase, setCurrentDatabase] = useState< - DatabaseObject | undefined - >(database); + const { addSuccessToast } = useToasts(); const [currentSchema, setCurrentSchema] = useState<string | undefined>( schema, ); - - const [tableOptions, setTableOptions] = useState<TableOption[]>([]); const [tableSelectValue, setTableSelectValue] = useState< SelectValue | undefined >(undefined); - const [refresh, setRefresh] = useState(0); - const [previousRefresh, setPreviousRefresh] = useState(0); - const [loadingTables, setLoadingTables] = useState(false); - const { addSuccessToast } = useToasts(); + const { + data, + isFetching: loadingTables, + isFetched, + refetch, + } = useTables({ + dbId: database?.id, + schema: currentSchema, + onSuccess: () => { + if (isFetched) { + addSuccessToast(t('List updated')); + } + }, + onError: (err: Response) => { + getClientErrorObject(err).then(clientError => { + handleError( + getClientErrorMessage( + t('There was an error loading the tables'), + clientError, + ), + ); + }); + }, + }); + + useEffect(() => { + // Set the tableOptions in the queryEditor so autocomplete + // works on new tabs + if (data && isFetched) { + onTablesLoad?.(data.options); + } + }, [data, isFetched, onTablesLoad]); + + const tableOptions = useMemo<TableOption[]>( + () => + data + ? data.options.map(table => ({ + value: table.value, + label: <TableOption table={table} />, + text: table.value, + })) + : [], + [data], + ); useEffect(() => { // reset selections if (database === undefined) { - setCurrentDatabase(undefined); setCurrentSchema(undefined); setTableSelectValue(undefined); } @@ -204,56 +244,6 @@ const TableSelector: FunctionComponent<TableSelectorProps> = ({ } }, [tableOptions, tableValue, tableSelectMode]); - useEffect(() => { - if (currentDatabase && currentSchema) { - setLoadingTables(true); - const encodedSchema = encodeURIComponent(currentSchema); - const forceRefresh = refresh !== previousRefresh; - // TODO: Would be nice to add pagination in a follow-up. Needs endpoint changes. - const endpoint = encodeURI( - `/superset/tables/${currentDatabase.id}/${encodedSchema}/undefined/${forceRefresh}/`, - ); - - if (previousRefresh !== refresh) { - setPreviousRefresh(refresh); - } - - SupersetClient.get({ endpoint }) - .then(({ json }) => { - const options: TableOption[] = json.options.map((table: Table) => { - const option: TableOption = { - value: table.value, - label: <TableOption table={table} />, - text: table.label, - }; - - return option; - }); - - onTablesLoad?.(json.options); - setTableOptions(options); - setLoadingTables(false); - if (forceRefresh) addSuccessToast('List updated'); - }) - .catch(() => { - setLoadingTables(false); - handleError(t('There was an error loading the tables')); - }); - } - // We are using the refresh state to re-trigger the query - // previousRefresh should be out of dependencies array - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [currentDatabase, currentSchema, onTablesLoad, setTableOptions, refresh]); - - function renderSelectRow(select: ReactNode, refreshBtn: ReactNode) { - return ( - <div className="section"> - <span className="select">{select}</span> - <span className="refresh">{refreshBtn}</span> - </div> - ); - } - const internalTableChange = ( selectedOptions: TableOption | TableOption[] | undefined, ) => { @@ -270,7 +260,6 @@ const TableSelector: FunctionComponent<TableSelectorProps> = ({ }; const internalDbChange = (db: DatabaseObject) => { - setCurrentDatabase(db); if (onDbChange) { onDbChange(db); } @@ -282,30 +271,10 @@ const TableSelector: FunctionComponent<TableSelectorProps> = ({ onSchemaChange(schema); } - internalTableChange(undefined); + const value = tableSelectMode === 'single' ? undefined : []; + internalTableChange(value); }; - function renderDatabaseSelector() { - return ( - <DatabaseSelector - key={currentDatabase?.id} - db={currentDatabase} - emptyState={emptyState} - formMode={formMode} - getDbList={getDbList} - handleError={handleError} - onDbChange={readOnly ? undefined : internalDbChange} - onEmptyResults={onEmptyResults} - onSchemaChange={readOnly ? undefined : internalSchemaChange} - onSchemasLoad={onSchemasLoad} - schema={currentSchema} - sqlLabMode={sqlLabMode} - isDatabaseSelectEnabled={isDatabaseSelectEnabled && !readOnly} - readOnly={readOnly} - /> - ); - } - const handleFilterOption = useMemo( () => (search: string, option: TableOption) => { const searchValue = search.trim().toLowerCase(); @@ -316,9 +285,7 @@ const TableSelector: FunctionComponent<TableSelectorProps> = ({ ); function renderTableSelect() { - const disabled = - (currentSchema && !formMode && readOnly) || - (!currentSchema && !database?.allow_multi_schema_metadata_fetch); + const disabled = (currentSchema && !formMode && readOnly) || !currentSchema; const header = sqlLabMode ? ( <FormLabel>{t('See table schema')}</FormLabel> @@ -333,7 +300,6 @@ const TableSelector: FunctionComponent<TableSelectorProps> = ({ filterOption={handleFilterOption} header={header} labelInValue - lazyLoading={false} loading={loadingTables} name="select-table" onChange={(options: TableOption | TableOption[]) => @@ -348,9 +314,9 @@ const TableSelector: FunctionComponent<TableSelectorProps> = ({ /> ); - const refreshLabel = !formMode && !readOnly && ( + const refreshLabel = !readOnly && ( <RefreshLabel - onClick={() => setRefresh(refresh + 1)} + onClick={() => refetch()} tooltipContent={t('Force refresh table list')} /> ); @@ -360,7 +326,21 @@ const TableSelector: FunctionComponent<TableSelectorProps> = ({ return ( <TableSelectorWrapper> - {renderDatabaseSelector()} + <DatabaseSelector + db={database} + emptyState={emptyState} + formMode={formMode} + getDbList={getDbList} + handleError={handleError} + onDbChange={readOnly ? undefined : internalDbChange} + onEmptyResults={onEmptyResults} + onSchemaChange={readOnly ? undefined : internalSchemaChange} + onSchemasLoad={onSchemasLoad} + schema={currentSchema} + sqlLabMode={sqlLabMode} + isDatabaseSelectEnabled={isDatabaseSelectEnabled && !readOnly} + readOnly={readOnly} + /> {sqlLabMode && !formMode && <div className="divider" />} {renderTableSelect()} </TableSelectorWrapper> diff --git a/superset-frontend/src/components/TableView/TableView.stories.tsx b/superset-frontend/src/components/TableView/TableView.stories.tsx index 9d28ca38b44d2..ff2079431a393 100644 --- a/superset-frontend/src/components/TableView/TableView.stories.tsx +++ b/superset-frontend/src/components/TableView/TableView.stories.tsx @@ -77,6 +77,7 @@ InteractiveTableView.args = { showRowCount: true, withPagination: true, columnsForWrapText: ['Summary'], + scrollTopOnPagination: false, }; InteractiveTableView.argTypes = { diff --git a/superset-frontend/src/components/TableView/TableView.tsx b/superset-frontend/src/components/TableView/TableView.tsx index 25a403ff9e60f..5bf393363669b 100644 --- a/superset-frontend/src/components/TableView/TableView.tsx +++ b/superset-frontend/src/components/TableView/TableView.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useEffect } from 'react'; +import React, { useEffect, useRef } from 'react'; import isEqual from 'lodash/isEqual'; import { styled, t } from '@superset-ui/core'; import { useFilters, usePagination, useSortBy, useTable } from 'react-table'; @@ -49,6 +49,7 @@ export interface TableViewProps { isPaginationSticky?: boolean; showRowCount?: boolean; scrollTable?: boolean; + scrollTopOnPagination?: boolean; small?: boolean; columnsForWrapText?: string[]; } @@ -130,6 +131,7 @@ const TableView = ({ serverPagination = false, columnsForWrapText, onServerPagination = () => {}, + scrollTopOnPagination = false, ...props }: TableViewProps) => { const initialState = { @@ -161,22 +163,6 @@ const TableView = ({ useSortBy, usePagination, ); - useEffect(() => { - if (serverPagination && pageIndex !== initialState.pageIndex) { - onServerPagination({ - pageIndex, - }); - } - }, [pageIndex]); - - useEffect(() => { - if (serverPagination && !isEqual(sortBy, initialState.sortBy)) { - onServerPagination({ - pageIndex: 0, - sortBy, - }); - } - }, [sortBy]); const content = withPagination ? page : rows; @@ -194,10 +180,34 @@ const TableView = ({ const isEmpty = !loading && content.length === 0; const hasPagination = pageCount > 1 && withPagination; + const tableRef = useRef<HTMLTableElement>(null); + const handleGotoPage = (p: number) => { + if (scrollTopOnPagination) { + tableRef?.current?.scroll(0, 0); + } + gotoPage(p); + }; + + useEffect(() => { + if (serverPagination && pageIndex !== initialState.pageIndex) { + onServerPagination({ + pageIndex, + }); + } + }, [pageIndex]); + + useEffect(() => { + if (serverPagination && !isEqual(sortBy, initialState.sortBy)) { + onServerPagination({ + pageIndex: 0, + sortBy, + }); + } + }, [sortBy]); return ( <> - <TableViewStyles {...props}> + <TableViewStyles {...props} ref={tableRef}> <TableCollection getTableProps={getTableProps} getTableBodyProps={getTableBodyProps} @@ -229,7 +239,7 @@ const TableView = ({ <Pagination totalPages={pageCount || 0} currentPage={pageCount ? pageIndex + 1 : 0} - onChange={(p: number) => gotoPage(p - 1)} + onChange={(p: number) => handleGotoPage(p - 1)} hideFirstAndLastPageLinks /> {showRowCount && ( diff --git a/superset-frontend/src/components/Timer/index.tsx b/superset-frontend/src/components/Timer/index.tsx index cfffc285717ba..ce9bac55e983b 100644 --- a/superset-frontend/src/components/Timer/index.tsx +++ b/superset-frontend/src/components/Timer/index.tsx @@ -31,6 +31,7 @@ export interface TimerProps { const TimerLabel = styled(Label)` text-align: left; + font-family: ${({ theme }) => theme.typography.families.monospace}; `; export default function Timer({ diff --git a/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.test.tsx b/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.test.tsx index 19c713adf4f13..6e79954b3b819 100644 --- a/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.test.tsx +++ b/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.test.tsx @@ -39,7 +39,7 @@ const loadComponent = (mockCurrentTime?: string) => { const getSelectOptions = () => waitFor(() => document.querySelectorAll('.ant-select-item-option-content')); -const openSelectMenu = async () => { +const openSelectMenu = () => { const searchInput = screen.getByRole('combobox'); userEvent.click(searchInput); }; @@ -86,7 +86,7 @@ test('render timezones in correct oder for standard time', async () => { timezone="America/Nassau" />, ); - await openSelectMenu(); + openSelectMenu(); const options = await getSelectOptions(); expect(options[0]).toHaveTextContent('GMT -05:00 (Eastern Standard Time)'); expect(options[1]).toHaveTextContent('GMT -11:00 (Pacific/Pago_Pago)'); @@ -103,7 +103,7 @@ test('render timezones in correct order for daylight saving time', async () => { timezone="America/Nassau" />, ); - await openSelectMenu(); + openSelectMenu(); const options = await getSelectOptions(); // first option is always current timezone expect(options[0]).toHaveTextContent('GMT -04:00 (Eastern Daylight Time)'); @@ -122,7 +122,7 @@ test('can select a timezone values and returns canonical timezone name', async ( />, ); - await openSelectMenu(); + openSelectMenu(); const searchInput = screen.getByRole('combobox'); // search for mountain time diff --git a/superset-frontend/src/components/Tooltip/index.tsx b/superset-frontend/src/components/Tooltip/index.tsx index 9267502682809..06469abd13670 100644 --- a/superset-frontend/src/components/Tooltip/index.tsx +++ b/superset-frontend/src/components/Tooltip/index.tsx @@ -19,9 +19,14 @@ import React from 'react'; import { useTheme, css } from '@superset-ui/core'; import { Tooltip as AntdTooltip } from 'antd'; -import { TooltipProps } from 'antd/lib/tooltip'; +import { + TooltipProps, + TooltipPlacement as AntdTooltipPlacement, +} from 'antd/lib/tooltip'; import { Global } from '@emotion/react'; +export type TooltipPlacement = AntdTooltipPlacement; + export const Tooltip = (props: TooltipProps) => { const theme = useTheme(); return ( diff --git a/superset-frontend/src/components/TruncatedList/index.tsx b/superset-frontend/src/components/TruncatedList/index.tsx new file mode 100644 index 0000000000000..37d4fe0436564 --- /dev/null +++ b/superset-frontend/src/components/TruncatedList/index.tsx @@ -0,0 +1,160 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { ReactNode, useMemo, useRef } from 'react'; +import { styled, t } from '@superset-ui/core'; +import { useTruncation } from 'src/hooks/useTruncation'; +import { Tooltip } from '../Tooltip'; + +export type TruncatedListProps<ListItemType> = { + /** + * Array of input items of type `ListItemType`. + */ + items: ListItemType[]; + + /** + * Renderer for items not overflowed into the tooltip. + * Required if `ListItemType` is not renderable by React. + */ + renderVisibleItem?: (item: ListItemType) => ReactNode; + + /** + * Renderer for items that are overflowed into the tooltip. + * Required if `ListItemType` is not renderable by React. + */ + renderTooltipItem?: (item: ListItemType) => ReactNode; + + /** + * Returns the React key for an item. + */ + getKey?: (item: ListItemType) => React.Key; + + /** + * The max number of links that should appear in the tooltip. + */ + maxLinks?: number; +}; + +const StyledTruncatedList = styled.div` + & > span { + width: 100%; + display: flex; + + .ant-tooltip-open { + display: inline; + } + } +`; + +const StyledVisibleItems = styled.span` + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: inline-block; + width: 100%; + vertical-align: bottom; +`; + +const StyledVisibleItem = styled.span` + &:not(:last-child)::after { + content: ', '; + } +`; + +const StyledTooltipItem = styled.div` + .link { + color: ${({ theme }) => theme.colors.grayscale.light5}; + display: block; + text-decoration: underline; + } +`; + +const StyledPlus = styled.span` + ${({ theme }) => ` + cursor: pointer; + color: ${theme.colors.primary.dark1}; + font-weight: ${theme.typography.weights.normal}; + `} +`; + +export default function TruncatedList<ListItemType>({ + items, + renderVisibleItem = item => item, + renderTooltipItem = item => item, + getKey = item => item as unknown as React.Key, + maxLinks = 20, +}: TruncatedListProps<ListItemType>) { + const itemsNotInTooltipRef = useRef<HTMLDivElement>(null); + const plusRef = useRef<HTMLDivElement>(null); + const [elementsTruncated, hasHiddenElements] = useTruncation( + itemsNotInTooltipRef, + plusRef, + ) as [number, boolean]; + + const nMoreItems = useMemo( + () => (items.length > maxLinks ? items.length - maxLinks : undefined), + [items, maxLinks], + ); + + const itemsNotInTooltip = useMemo( + () => ( + <StyledVisibleItems ref={itemsNotInTooltipRef} data-test="crosslinks"> + {items.map(item => ( + <StyledVisibleItem key={getKey(item)}> + {renderVisibleItem(item)} + </StyledVisibleItem> + ))} + </StyledVisibleItems> + ), + [getKey, items, renderVisibleItem], + ); + + const itemsInTooltip = useMemo( + () => + items + .slice(0, maxLinks) + .map(item => ( + <StyledTooltipItem key={getKey(item)}> + {renderTooltipItem(item)} + </StyledTooltipItem> + )), + [getKey, items, maxLinks, renderTooltipItem], + ); + + return ( + <StyledTruncatedList> + <Tooltip + placement="top" + title={ + elementsTruncated ? ( + <> + {itemsInTooltip} + {nMoreItems && <span>{t('+ %s more', nMoreItems)}</span>} + </> + ) : null + } + > + {itemsNotInTooltip} + {hasHiddenElements && ( + <StyledPlus ref={plusRef}>+{elementsTruncated}</StyledPlus> + )} + </Tooltip> + </StyledTruncatedList> + ); +} diff --git a/superset-frontend/src/components/atomic-design.png b/superset-frontend/src/components/atomic-design.png new file mode 100644 index 0000000000000..e44c5f34a54eb Binary files /dev/null and b/superset-frontend/src/components/atomic-design.png differ diff --git a/superset-frontend/src/components/index.ts b/superset-frontend/src/components/index.ts index a370836fcfb8b..bfa341a9ddd18 100644 --- a/superset-frontend/src/components/index.ts +++ b/superset-frontend/src/components/index.ts @@ -23,6 +23,7 @@ * E.g. import { Select } from 'src/components' */ export { default as Select } from './Select/Select'; +export { default as AsyncSelect } from './Select/AsyncSelect'; /* * Components that don't conflict with the ones in src/components. diff --git a/superset-frontend/src/constants.ts b/superset-frontend/src/constants.ts index 60668ddcb865d..974edeeb6eee2 100644 --- a/superset-frontend/src/constants.ts +++ b/superset-frontend/src/constants.ts @@ -16,6 +16,10 @@ * specific language governing permissions and limitations * under the License. */ +import { t } from '@superset-ui/core'; + +import { BootstrapData, CommonBootstrapData } from './types/bootstrapTypes'; + export const DATETIME_WITH_TIME_ZONE = 'YYYY-MM-DD HH:mm:ssZ'; export const TIME_WITH_MS = 'HH:mm:ss.SSS'; @@ -65,7 +69,7 @@ export const URL_PARAMS = { }, sliceId: { name: 'slice_id', - type: 'string', + type: 'number', }, datasourceId: { name: 'datasource_id', @@ -91,6 +95,26 @@ export const URL_PARAMS = { name: 'permalink_key', type: 'string', }, + vizType: { + name: 'viz_type', + type: 'string', + }, + showDatabaseModal: { + name: 'show_database_modal', + type: 'boolean', + }, + saveAction: { + name: 'save_action', + type: 'string', + }, + dashboardPageId: { + name: 'dashboard_page_id', + type: 'string', + }, + dashboardFocusedChart: { + name: 'focused_chart', + type: 'number', + }, } as const; export const RESERVED_CHART_URL_PARAMS: string[] = [ @@ -120,4 +144,58 @@ export const SLOW_DEBOUNCE = 500; /** * Display null as `N/A` */ -export const NULL_DISPLAY = 'N/A'; +export const NULL_DISPLAY = t('N/A'); + +export const DEFAULT_COMMON_BOOTSTRAP_DATA: CommonBootstrapData = { + flash_messages: [], + conf: {}, + locale: 'en', + feature_flags: {}, + language_pack: { + domain: '', + locale_data: { + superset: { + '': { + domain: 'superset', + lang: 'en', + plural_forms: '', + }, + }, + }, + }, + extra_categorical_color_schemes: [], + extra_sequential_color_schemes: [], + theme_overrides: {}, + menu_data: { + menu: [], + brand: { + path: '', + icon: '', + alt: '', + tooltip: '', + text: '', + }, + navbar_right: { + show_watermark: true, + languages: {}, + show_language_picker: true, + user_is_anonymous: false, + user_info_url: '', + user_login_url: '', + user_logout_url: '', + user_profile_url: '', + locale: '', + }, + settings: [], + environment_tag: { + text: '', + color: '', + }, + }, + datahub_url: '', + advanced_data_types: [], +}; + +export const DEFAULT_BOOTSTRAP_DATA: BootstrapData = { + common: DEFAULT_COMMON_BOOTSTRAP_DATA, +}; diff --git a/superset-frontend/src/dashboard/actions/dashboardInfo.ts b/superset-frontend/src/dashboard/actions/dashboardInfo.ts index 9a769101cfdca..bbc06d37b0ad4 100644 --- a/superset-frontend/src/dashboard/actions/dashboardInfo.ts +++ b/superset-frontend/src/dashboard/actions/dashboardInfo.ts @@ -19,7 +19,15 @@ import { Dispatch } from 'redux'; import { makeApi, CategoricalColorNamespace } from '@superset-ui/core'; import { isString } from 'lodash'; -import { ChartConfiguration, DashboardInfo } from '../reducers/types'; +import { getErrorText } from 'src/utils/getClientErrorObject'; +import { addDangerToast } from 'src/components/MessageToasts/actions'; +import { + DashboardInfo, + FilterBarOrientation, + RootState, +} from 'src/dashboard/types'; +import { ChartConfiguration } from 'src/dashboard/reducers/types'; +import { onSave } from './dashboardState'; export const DASHBOARD_INFO_UPDATED = 'DASHBOARD_INFO_UPDATED'; @@ -111,3 +119,93 @@ export const setChartConfiguration = dispatch({ type: SET_CHART_CONFIG_FAIL, chartConfiguration }); } }; + +export const SET_FILTER_BAR_ORIENTATION = 'SET_FILTER_BAR_ORIENTATION'; +export interface SetFilterBarOrientation { + type: typeof SET_FILTER_BAR_ORIENTATION; + filterBarOrientation: FilterBarOrientation; +} +export function setFilterBarOrientation( + filterBarOrientation: FilterBarOrientation, +) { + return { type: SET_FILTER_BAR_ORIENTATION, filterBarOrientation }; +} + +export const SET_CROSS_FILTERS_ENABLED = 'SET_CROSS_FILTERS_ENABLED'; +export interface SetCrossFiltersEnabled { + type: typeof SET_CROSS_FILTERS_ENABLED; + crossFiltersEnabled: boolean; +} +export function setCrossFiltersEnabled(crossFiltersEnabled: boolean) { + return { type: SET_CROSS_FILTERS_ENABLED, crossFiltersEnabled }; +} + +export function saveFilterBarOrientation(orientation: FilterBarOrientation) { + return async (dispatch: Dispatch, getState: () => RootState) => { + const { id, metadata } = getState().dashboardInfo; + const updateDashboard = makeApi< + Partial<DashboardInfo>, + { result: Partial<DashboardInfo>; last_modified_time: number } + >({ + method: 'PUT', + endpoint: `/api/v1/dashboard/${id}`, + }); + try { + const response = await updateDashboard({ + json_metadata: JSON.stringify({ + ...metadata, + filter_bar_orientation: orientation, + }), + }); + const updatedDashboard = response.result; + const lastModifiedTime = response.last_modified_time; + if (updatedDashboard.json_metadata) { + const metadata = JSON.parse(updatedDashboard.json_metadata); + if (metadata.filter_bar_orientation) { + dispatch(setFilterBarOrientation(metadata.filter_bar_orientation)); + } + } + if (lastModifiedTime) { + dispatch(onSave(lastModifiedTime)); + } + } catch (errorObject) { + const errorText = await getErrorText(errorObject, 'dashboard'); + dispatch(addDangerToast(errorText)); + throw errorObject; + } + }; +} + +export function saveCrossFiltersSetting(crossFiltersEnabled: boolean) { + return async (dispatch: Dispatch, getState: () => RootState) => { + const { id, metadata } = getState().dashboardInfo; + const updateDashboard = makeApi< + Partial<DashboardInfo>, + { result: Partial<DashboardInfo>; last_modified_time: number } + >({ + method: 'PUT', + endpoint: `/api/v1/dashboard/${id}`, + }); + try { + const response = await updateDashboard({ + json_metadata: JSON.stringify({ + ...metadata, + cross_filters_enabled: crossFiltersEnabled, + }), + }); + const updatedDashboard = response.result; + const lastModifiedTime = response.last_modified_time; + if (updatedDashboard.json_metadata) { + const metadata = JSON.parse(updatedDashboard.json_metadata); + dispatch(setCrossFiltersEnabled(metadata.cross_filters_enabled)); + } + if (lastModifiedTime) { + dispatch(onSave(lastModifiedTime)); + } + } catch (errorObject) { + const errorText = await getErrorText(errorObject, 'dashboard'); + dispatch(addDangerToast(errorText)); + throw errorObject; + } + }; +} diff --git a/superset-frontend/src/dashboard/actions/dashboardState.js b/superset-frontend/src/dashboard/actions/dashboardState.js index f96b3ebadf28b..8db1a500eee32 100644 --- a/superset-frontend/src/dashboard/actions/dashboardState.js +++ b/superset-frontend/src/dashboard/actions/dashboardState.js @@ -32,7 +32,11 @@ import { import { chart as initChart } from 'src/components/Chart/chartReducer'; import { applyDefaultFormData } from 'src/explore/store'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; -import { SAVE_TYPE_OVERWRITE } from 'src/dashboard/util/constants'; +import { + SAVE_TYPE_OVERWRITE, + SAVE_TYPE_OVERWRITE_CONFIRMED, +} from 'src/dashboard/util/constants'; +import { isCrossFiltersEnabled } from 'src/dashboard/util/crossFilters'; import { addSuccessToast, addWarningToast, @@ -43,6 +47,8 @@ import serializeFilterScopes from 'src/dashboard/util/serializeFilterScopes'; import { getActiveFilters } from 'src/dashboard/util/activeDashboardFilters'; import { safeStringify } from 'src/utils/safeStringify'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; +import { logEvent } from 'src/logger/actions'; +import { LOG_ACTIONS_CONFIRM_OVERWRITE_DASHBOARD_METADATA } from 'src/logger/LogUtils'; import { UPDATE_COMPONENTS_PARENTS_LIST } from './dashboardLayout'; import { setChartConfiguration, @@ -56,6 +62,7 @@ import { updateDirectPathToFilter, } from './dashboardFilters'; import { SET_FILTER_CONFIG_COMPLETE } from './nativeFilters'; +import getOverwriteItems from '../util/getOverwriteItems'; export const SET_UNSAVED_CHANGES = 'SET_UNSAVED_CHANGES'; export function setUnsavedChanges(hasUnsavedChanges) { @@ -72,11 +79,6 @@ export function removeSlice(sliceId) { return { type: REMOVE_SLICE, sliceId }; } -export const RESET_SLICE = 'RESET_SLICE'; -export function resetSlice() { - return { type: RESET_SLICE }; -} - const FAVESTAR_BASE_URL = '/superset/favstar/Dashboard'; export const TOGGLE_FAVE_STAR = 'TOGGLE_FAVE_STAR'; export function toggleFaveStar(isStarred) { @@ -194,9 +196,28 @@ export function saveDashboardRequestSuccess(lastModifiedTime) { }; } +export const SET_OVERRIDE_CONFIRM = 'SET_OVERRIDE_CONFIRM'; +export function setOverrideConfirm(overwriteConfirmMetadata) { + return { + type: SET_OVERRIDE_CONFIRM, + overwriteConfirmMetadata, + }; +} + +export const SAVE_DASHBOARD_STARTED = 'SAVE_DASHBOARD_STARTED'; +export function saveDashboardStarted() { + return { type: SAVE_DASHBOARD_STARTED }; +} + +export const SAVE_DASHBOARD_FINISHED = 'SAVE_DASHBOARD_FINISHED'; +export function saveDashboardFinished() { + return { type: SAVE_DASHBOARD_FINISHED }; +} + export function saveDashboardRequest(data, id, saveType) { return (dispatch, getState) => { dispatch({ type: UPDATE_COMPONENTS_PARENTS_LIST }); + dispatch(saveDashboardStarted()); const { dashboardFilters, dashboardLayout } = getState(); const layout = dashboardLayout.present; @@ -222,7 +243,7 @@ export function saveDashboardRequest(data, id, saveType) { } = data; const hasId = item => item.id !== undefined; - + const metadataCrossFiltersEnabled = data.metadata?.cross_filters_enabled; // making sure the data is what the backend expects const cleanedData = { ...data, @@ -240,12 +261,17 @@ export function saveDashboardRequest(data, id, saveType) { ...data.metadata, color_namespace: data.metadata?.color_namespace || undefined, color_scheme: data.metadata?.color_scheme || '', + color_scheme_domain: data.metadata?.color_scheme_domain || [], expanded_slices: data.metadata?.expanded_slices || {}, label_colors: data.metadata?.label_colors || {}, shared_label_colors: data.metadata?.shared_label_colors || {}, refresh_frequency: data.metadata?.refresh_frequency || 0, timed_refresh_immune_slices: data.metadata?.timed_refresh_immune_slices || [], + // cross-filters should be enabled by default + cross_filters_enabled: isCrossFiltersEnabled( + metadataCrossFiltersEnabled, + ), }, }; @@ -281,6 +307,7 @@ export function saveDashboardRequest(data, id, saveType) { const chartConfiguration = handleChartConfiguration(); dispatch(setChartConfiguration(chartConfiguration)); } + dispatch(saveDashboardFinished()); dispatch(addSuccessToast(t('This dashboard was saved successfully.'))); return response; }; @@ -288,7 +315,7 @@ export function saveDashboardRequest(data, id, saveType) { const onUpdateSuccess = response => { const updatedDashboard = response.json.result; const lastModifiedTime = response.json.last_modified_time; - // synching with the backend transformations of the metadata + // syncing with the backend transformations of the metadata if (updatedDashboard.json_metadata) { const metadata = JSON.parse(updatedDashboard.json_metadata); dispatch( @@ -312,6 +339,7 @@ export function saveDashboardRequest(data, id, saveType) { if (lastModifiedTime) { dispatch(saveDashboardRequestSuccess(lastModifiedTime)); } + dispatch(saveDashboardFinished()); // redirect to the new slug or id window.history.pushState( { event: 'dashboard_properties_changed' }, @@ -320,6 +348,7 @@ export function saveDashboardRequest(data, id, saveType) { ); dispatch(addSuccessToast(t('This dashboard was saved successfully.'))); + dispatch(setOverrideConfirm(undefined)); return response; }; @@ -336,37 +365,89 @@ export function saveDashboardRequest(data, id, saveType) { if (typeof message === 'string' && message === 'Forbidden') { errorText = t('You do not have permission to edit this dashboard'); } + dispatch(saveDashboardFinished()); dispatch(addDangerToast(errorText)); }; - if (saveType === SAVE_TYPE_OVERWRITE) { + if ( + [SAVE_TYPE_OVERWRITE, SAVE_TYPE_OVERWRITE_CONFIRMED].includes(saveType) + ) { let chartConfiguration = {}; if (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)) { chartConfiguration = handleChartConfiguration(); } - const updatedDashboard = { - certified_by: cleanedData.certified_by, - certification_details: cleanedData.certification_details, - css: cleanedData.css, - dashboard_title: cleanedData.dashboard_title, - slug: cleanedData.slug, - owners: cleanedData.owners, - roles: cleanedData.roles, - json_metadata: safeStringify({ - ...(cleanedData?.metadata || {}), - default_filters: safeStringify(serializedFilters), - filter_scopes: serializedFilterScopes, - chart_configuration: chartConfiguration, - }), - }; - - return SupersetClient.put({ - endpoint: `/api/v1/dashboard/${id}`, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(updatedDashboard), + const updatedDashboard = + saveType === SAVE_TYPE_OVERWRITE_CONFIRMED + ? data + : { + certified_by: cleanedData.certified_by, + certification_details: cleanedData.certification_details, + css: cleanedData.css, + dashboard_title: cleanedData.dashboard_title, + slug: cleanedData.slug, + owners: cleanedData.owners, + roles: cleanedData.roles, + json_metadata: safeStringify({ + ...(cleanedData?.metadata || {}), + default_filters: safeStringify(serializedFilters), + filter_scopes: serializedFilterScopes, + chart_configuration: chartConfiguration, + }), + }; + + const updateDashboard = () => + SupersetClient.put({ + endpoint: `/api/v1/dashboard/${id}`, + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(updatedDashboard), + }) + .then(response => onUpdateSuccess(response)) + .catch(response => onError(response)); + return new Promise((resolve, reject) => { + if ( + !isFeatureEnabled(FeatureFlag.CONFIRM_DASHBOARD_DIFF) || + saveType === SAVE_TYPE_OVERWRITE_CONFIRMED + ) { + // skip overwrite precheck + resolve(); + return; + } + + // precheck for overwrite items + SupersetClient.get({ + endpoint: `/api/v1/dashboard/${id}`, + }).then(response => { + const dashboard = response.json.result; + const overwriteConfirmItems = getOverwriteItems( + dashboard, + updatedDashboard, + ); + if (overwriteConfirmItems.length > 0) { + dispatch( + setOverrideConfirm({ + updatedAt: dashboard.changed_on, + updatedBy: dashboard.changed_by_name, + overwriteConfirmItems, + dashboardId: id, + data: updatedDashboard, + }), + ); + return reject(overwriteConfirmItems); + } + return resolve(); + }); }) - .then(response => onUpdateSuccess(response)) - .catch(response => onError(response)); + .then(updateDashboard) + .catch(overwriteConfirmItems => { + const errorText = t('Please confirm the overwrite values.'); + dispatch( + logEvent(LOG_ACTIONS_CONFIRM_OVERWRITE_DASHBOARD_METADATA, { + dashboard_id: id, + items: overwriteConfirmItems, + }), + ); + dispatch(addDangerToast(errorText)); + }); } // changing the data as the endpoint requires const copyData = { ...cleanedData }; @@ -489,8 +570,7 @@ export function addSliceToDashboard(id, component) { const newChart = { ...initChart, id, - form_data, - formData: applyDefaultFormData(form_data), + form_data: applyDefaultFormData(form_data), }; return Promise.all([ @@ -506,28 +586,6 @@ export function addSliceToDashboard(id, component) { }; } -export function postAddSliceFromDashboard() { - return (dispatch, getState) => { - const { - dashboardInfo: { metadata }, - dashboardState, - } = getState(); - - if (dashboardState?.updateSlice && dashboardState?.editMode) { - metadata.shared_label_colors = getSharedLabelColor().getColorMap( - metadata?.color_namespace, - metadata?.color_scheme, - ); - dispatch( - dashboardInfoChanged({ - metadata, - }), - ); - dispatch(resetSlice()); - } - }; -} - export function removeSliceFromDashboard(id) { return (dispatch, getState) => { const sliceEntity = getState().sliceEntities.slices[id]; @@ -537,20 +595,7 @@ export function removeSliceFromDashboard(id) { dispatch(removeSlice(id)); dispatch(removeChart(id)); - - const { - dashboardInfo: { metadata }, - } = getState(); getSharedLabelColor().removeSlice(id); - metadata.shared_label_colors = getSharedLabelColor().getColorMap( - metadata?.color_namespace, - metadata?.color_scheme, - ); - dispatch( - dashboardInfoChanged({ - metadata, - }), - ); }; } @@ -607,7 +652,10 @@ export function maxUndoHistoryToast() { return dispatch( addWarningToast( - `You have used all ${historyLength} undo slots and will not be able to fully undo subsequent actions. You may save your current state to reset the history.`, + t( + 'You have used all %(historyLength)s undo slots and will not be able to fully undo subsequent actions. You may save your current state to reset the history.', + { historyLength }, + ), ), ); }; diff --git a/superset-frontend/src/dashboard/actions/dashboardState.test.js b/superset-frontend/src/dashboard/actions/dashboardState.test.js index f5fa60c08d56d..00b358bc43972 100644 --- a/superset-frontend/src/dashboard/actions/dashboardState.test.js +++ b/superset-frontend/src/dashboard/actions/dashboardState.test.js @@ -18,14 +18,22 @@ */ import sinon from 'sinon'; import { SupersetClient } from '@superset-ui/core'; +import { waitFor } from '@testing-library/react'; import { removeSliceFromDashboard, + SAVE_DASHBOARD_STARTED, saveDashboardRequest, + SET_OVERRIDE_CONFIRM, } from 'src/dashboard/actions/dashboardState'; import { REMOVE_FILTER } from 'src/dashboard/actions/dashboardFilters'; +import * as featureFlags from 'src/featureFlags'; import { UPDATE_COMPONENTS_PARENTS_LIST } from 'src/dashboard/actions/dashboardLayout'; -import { DASHBOARD_GRID_ID } from 'src/dashboard/util/constants'; +import { + DASHBOARD_GRID_ID, + SAVE_TYPE_OVERWRITE, + SAVE_TYPE_OVERWRITE_CONFIRMED, +} from 'src/dashboard/util/constants'; import { filterId, sliceEntitiesForDashboard as sliceEntities, @@ -55,13 +63,32 @@ describe('dashboardState actions', () => { const newDashboardData = mockDashboardData; let postStub; + let getStub; + let putStub; + const updatedCss = '.updated_css_value {\n color: black;\n}'; + beforeEach(() => { postStub = sinon .stub(SupersetClient, 'post') .resolves('the value you want to return'); + getStub = sinon.stub(SupersetClient, 'get').resolves({ + json: { + result: { + ...mockDashboardData, + css: updatedCss, + }, + }, + }); + putStub = sinon.stub(SupersetClient, 'put').resolves({ + json: { + result: mockDashboardData, + }, + }); }); afterEach(() => { postStub.restore(); + getStub.restore(); + putStub.restore(); }); function setup(stateOverrides) { @@ -78,10 +105,11 @@ describe('dashboardState actions', () => { }); const thunk = saveDashboardRequest(newDashboardData, 1, 'save_dash'); thunk(dispatch, getState); - expect(dispatch.callCount).toBe(1); + expect(dispatch.callCount).toBe(2); expect(dispatch.getCall(0).args[0].type).toBe( UPDATE_COMPONENTS_PARENTS_LIST, ); + expect(dispatch.getCall(1).args[0].type).toBe(SAVE_DASHBOARD_STARTED); }); it('should post dashboard data with updated redux state', () => { @@ -111,6 +139,58 @@ describe('dashboardState actions', () => { mockParentsList, ); }); + + describe('FeatureFlag.CONFIRM_DASHBOARD_DIFF', () => { + let isFeatureEnabledMock; + beforeEach(() => { + isFeatureEnabledMock = jest + .spyOn(featureFlags, 'isFeatureEnabled') + .mockImplementation(feature => feature === 'CONFIRM_DASHBOARD_DIFF'); + }); + + afterEach(() => { + isFeatureEnabledMock.mockRestore(); + }); + + it('dispatches SET_OVERRIDE_CONFIRM when an inspect value has diff', async () => { + const id = 192; + const { getState, dispatch } = setup(); + const thunk = saveDashboardRequest( + newDashboardData, + id, + SAVE_TYPE_OVERWRITE, + ); + thunk(dispatch, getState); + expect(getStub.callCount).toBe(1); + expect(postStub.callCount).toBe(0); + await waitFor(() => + expect(dispatch.getCall(2).args[0].type).toBe(SET_OVERRIDE_CONFIRM), + ); + expect( + dispatch.getCall(2).args[0].overwriteConfirmMetadata.dashboardId, + ).toBe(id); + }); + + it('should post dashboard data with after confirm the overwrite values', async () => { + const id = 192; + const { getState, dispatch } = setup(); + const confirmedDashboardData = { + ...newDashboardData, + css: updatedCss, + }; + const thunk = saveDashboardRequest( + confirmedDashboardData, + id, + SAVE_TYPE_OVERWRITE_CONFIRMED, + ); + thunk(dispatch, getState); + expect(getStub.callCount).toBe(0); + expect(postStub.callCount).toBe(0); + await waitFor(() => expect(putStub.callCount).toBe(1)); + const { body } = putStub.getCall(0).args[0]; + expect(body).toBe(JSON.stringify(confirmedDashboardData)); + }); + }); }); it('should dispatch removeFilter if a removed slice is a filter_box', () => { @@ -120,6 +200,6 @@ describe('dashboardState actions', () => { const removeFilter = dispatch.getCall(0).args[0]; removeFilter(dispatch, getState); - expect(dispatch.getCall(4).args[0].type).toBe(REMOVE_FILTER); + expect(dispatch.getCall(3).args[0].type).toBe(REMOVE_FILTER); }); }); diff --git a/superset-frontend/src/dashboard/actions/hydrate.js b/superset-frontend/src/dashboard/actions/hydrate.js index ccc8288e6158e..efae72151ef94 100644 --- a/superset-frontend/src/dashboard/actions/hydrate.js +++ b/superset-frontend/src/dashboard/actions/hydrate.js @@ -24,9 +24,9 @@ import { initSliceEntities } from 'src/dashboard/reducers/sliceEntities'; import { getInitialState as getInitialNativeFilterState } from 'src/dashboard/reducers/nativeFilters'; import { applyDefaultFormData } from 'src/explore/store'; import { buildActiveFilters } from 'src/dashboard/util/activeDashboardFilters'; -import findPermission, { - canUserEditDashboard, -} from 'src/dashboard/util/findPermission'; +import { findPermission } from 'src/utils/findPermission'; +import { canUserEditDashboard } from 'src/dashboard/util/permissionUtils'; +import { isCrossFiltersEnabled } from 'src/dashboard/util/crossFilters'; import { DASHBOARD_FILTER_SCOPE_GLOBAL, dashboardFilter, @@ -56,27 +56,31 @@ import { FeatureFlag, isFeatureEnabled } from '../../featureFlags'; import extractUrlParams from '../util/extractUrlParams'; import getNativeFilterConfig from '../util/filterboxMigrationHelper'; import { updateColorSchema } from './dashboardInfo'; +import { getChartIdsInFilterScope } from '../util/getChartIdsInFilterScope'; +import updateComponentParentsList from '../util/updateComponentParentsList'; +import { FilterBarOrientation } from '../types'; export const HYDRATE_DASHBOARD = 'HYDRATE_DASHBOARD'; export const hydrateDashboard = - ( - dashboardData, - chartData, + ({ + history, + dashboard, + charts, filterboxMigrationState = FILTER_BOX_MIGRATION_STATES.NOOP, - dataMaskApplied, - ) => + dataMask, + activeTabs, + }) => (dispatch, getState) => { const { user, common, dashboardState } = getState(); - - const { metadata } = dashboardData; + const { metadata, position_data: positionData } = dashboard; const regularUrlParams = extractUrlParams('regular'); const reservedUrlParams = extractUrlParams('reserved'); const editMode = reservedUrlParams.edit === 'true'; let preselectFilters = {}; - chartData.forEach(chart => { + charts.forEach(chart => { // eslint-disable-next-line no-param-reassign chart.slice_id = chart.form_data.slice_id; }); @@ -99,12 +103,10 @@ export const hydrateDashboard = updateColorSchema(metadata, metadata?.label_colors); } - // dashboard layout - const { position_data } = dashboardData; // new dash: position_json could be {} or null const layout = - position_data && Object.keys(position_data).length > 0 - ? position_data + positionData && Object.keys(positionData).length > 0 + ? positionData : getEmptyLayout(); // create a lookup to sync layout names with slice names @@ -129,7 +131,7 @@ export const hydrateDashboard = const sliceIds = new Set(); const slicesFromExploreCount = new Map(); - chartData.forEach(slice => { + charts.forEach(slice => { const key = slice.slice_id; const form_data = { ...slice.form_data, @@ -141,8 +143,7 @@ export const hydrateDashboard = chartQueries[key] = { ...chart, id: key, - form_data, - formData: applyDefaultFormData(form_data), + form_data: applyDefaultFormData(form_data), }; slices[key] = { @@ -260,6 +261,19 @@ export const hydrateDashboard = layout[layoutId].meta.sliceName = slice.slice_name; } }); + + // make sure that parents tree is built + if ( + Object.values(layout).some( + element => element.id !== DASHBOARD_ROOT_ID && !element.parents, + ) + ) { + updateComponentParentsList({ + currentComponent: layout[DASHBOARD_ROOT_ID], + layout, + }); + } + buildActiveFilters({ dashboardFilters, components: layout, @@ -270,7 +284,7 @@ export const hydrateDashboard = id: DASHBOARD_HEADER_ID, type: DASHBOARD_HEADER_TYPE, meta: { - text: dashboardData.dashboard_title, + text: dashboard.dashboard_title, }, }; @@ -280,9 +294,26 @@ export const hydrateDashboard = future: [], }; + // Searches for a focused_chart parameter in the URL to automatically focus a chart + const focusedChartId = getUrlParam(URL_PARAMS.dashboardFocusedChart); + let focusedChartLayoutId; + if (focusedChartId) { + // Converts focused_chart to dashboard layout id + const found = Object.values(dashboardLayout.present).find( + element => element.meta?.chartId === focusedChartId, + ); + focusedChartLayoutId = found?.id; + // Removes the focused_chart parameter from the URL + const params = new URLSearchParams(window.location.search); + params.delete(URL_PARAMS.dashboardFocusedChart.name); + history.replace({ + search: params.toString(), + }); + } + // find direct link component and path from root - const directLinkComponentId = getLocationHash(); - let directPathToChild = []; + const directLinkComponentId = focusedChartLayoutId || getLocationHash(); + let directPathToChild = dashboardState.directPathToChild || []; if (layout[directLinkComponentId]) { directPathToChild = (layout[directLinkComponentId].parents || []).slice(); directPathToChild.push(directLinkComponentId); @@ -292,7 +323,7 @@ export const hydrateDashboard = let filterConfig = metadata?.native_filter_configuration || []; if (filterboxMigrationState === FILTER_BOX_MIGRATION_STATES.REVIEWING) { filterConfig = getNativeFilterConfig( - chartData, + charts, filterScopes, preselectFilters, ); @@ -303,7 +334,7 @@ export const hydrateDashboard = filterConfig, }); metadata.show_native_filters = - dashboardData?.metadata?.show_native_filters ?? + dashboard?.metadata?.show_native_filters ?? (isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS) && [ FILTER_BOX_MIGRATION_STATES.CONVERTED, @@ -319,13 +350,32 @@ export const hydrateDashboard = const behaviors = ( getChartMetadataRegistry().get( - chartQueries[chartId]?.formData?.viz_type, + chartQueries[chartId]?.form_data?.viz_type, ) ?? {} )?.behaviors ?? []; if (!metadata.chart_configuration) { metadata.chart_configuration = {}; } + if (behaviors.includes(Behavior.INTERACTIVE_CHART)) { + if (!metadata.chart_configuration[chartId]) { + metadata.chart_configuration[chartId] = { + id: chartId, + crossFilters: { + scope: { + rootPath: [DASHBOARD_ROOT_ID], + excluded: [chartId], // By default it doesn't affects itself + }, + }, + }; + } + metadata.chart_configuration[chartId].crossFilters.chartsInScope = + getChartIdsInFilterScope( + metadata.chart_configuration[chartId].crossFilters.scope, + chartQueries, + dashboardLayout.present, + ); + } if ( behaviors.includes(Behavior.INTERACTIVE_CHART) && !metadata.chart_configuration[chartId] @@ -344,7 +394,10 @@ export const hydrateDashboard = } const { roles } = user; - const canEdit = canUserEditDashboard(dashboardData, user); + const canEdit = canUserEditDashboard(dashboard, user); + const crossFiltersEnabled = isCrossFiltersEnabled( + metadata.cross_filters_enabled, + ); return dispatch({ type: HYDRATE_DASHBOARD, @@ -353,7 +406,7 @@ export const hydrateDashboard = charts: chartQueries, // read-only data dashboardInfo: { - ...dashboardData, + ...dashboard, metadata, userId: user.userId ? String(user.userId) : null, // legacy, please use state.user instead dash_edit_perm: canEdit, @@ -380,8 +433,13 @@ export const hydrateDashboard = flash_messages: common?.flash_messages, conf: common?.conf, }, + filterBarOrientation: + (isFeatureEnabled(FeatureFlag.HORIZONTAL_FILTER_BAR) && + metadata.filter_bar_orientation) || + FilterBarOrientation.VERTICAL, + crossFiltersEnabled, }, - dataMask: dataMaskApplied, + dataMask, dashboardFilters, nativeFilters, dashboardState: { @@ -395,17 +453,18 @@ export const hydrateDashboard = // dashboard viewers can set refresh frequency for the current visit, // only persistent refreshFrequency will be saved to backend shouldPersistRefreshFrequency: false, - css: dashboardData.css || '', + css: dashboard.css || '', colorNamespace: metadata?.color_namespace || null, colorScheme: metadata?.color_scheme || null, editMode: canEdit && editMode, - isPublished: dashboardData.published, + isPublished: dashboard.published, hasUnsavedChanges: false, + dashboardIsSaving: false, maxUndoHistoryExceeded: false, - lastModifiedTime: dashboardData.changed_on, + lastModifiedTime: dashboard.changed_on, isRefreshing: false, isFiltersRefreshing: false, - activeTabs: dashboardState?.activeTabs || [], + activeTabs: activeTabs || dashboardState?.activeTabs || [], filterboxMigrationState, datasetsStatus: ResourceStatus.LOADING, }, diff --git a/superset-frontend/src/dashboard/actions/nativeFilters.ts b/superset-frontend/src/dashboard/actions/nativeFilters.ts index 71cc01d99681f..76ac6cc1fbede 100644 --- a/superset-frontend/src/dashboard/actions/nativeFilters.ts +++ b/superset-frontend/src/dashboard/actions/nativeFilters.ts @@ -372,6 +372,28 @@ export function unsetFocusedNativeFilter(): UnsetFocusedNativeFilter { }; } +export const SET_HOVERED_NATIVE_FILTER = 'SET_HOVERED_NATIVE_FILTER'; +export interface SetHoveredNativeFilter { + type: typeof SET_HOVERED_NATIVE_FILTER; + id: string; +} +export const UNSET_HOVERED_NATIVE_FILTER = 'UNSET_HOVERED_NATIVE_FILTER'; +export interface UnsetHoveredNativeFilter { + type: typeof UNSET_HOVERED_NATIVE_FILTER; +} + +export function setHoveredNativeFilter(id: string): SetHoveredNativeFilter { + return { + type: SET_HOVERED_NATIVE_FILTER, + id, + }; +} +export function unsetHoveredNativeFilter(): UnsetHoveredNativeFilter { + return { + type: UNSET_HOVERED_NATIVE_FILTER, + }; +} + export type AnyFilterAction = | SetFilterConfigBegin | SetFilterConfigComplete @@ -383,6 +405,8 @@ export type AnyFilterAction = | SetBootstrapData | SetFocusedNativeFilter | UnsetFocusedNativeFilter + | SetHoveredNativeFilter + | UnsetHoveredNativeFilter | CreateFilterSetBegin | CreateFilterSetComplete | CreateFilterSetFail diff --git a/superset-frontend/src/dashboard/actions/sliceEntities.js b/superset-frontend/src/dashboard/actions/sliceEntities.js index be111605202cd..74fd8fd7f2520 100644 --- a/superset-frontend/src/dashboard/actions/sliceEntities.js +++ b/superset-frontend/src/dashboard/actions/sliceEntities.js @@ -24,6 +24,12 @@ import { addDangerToast } from 'src/components/MessageToasts/actions'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; export const SET_ALL_SLICES = 'SET_ALL_SLICES'; +const FETCH_SLICES_PAGE_SIZE = 200; + +export function getDatasourceParameter(datasourceId, datasourceType) { + return `${datasourceId}__${datasourceType}`; +} + export function setAllSlices(slices) { return { type: SET_ALL_SLICES, payload: { slices } }; } @@ -38,96 +44,141 @@ export function fetchAllSlicesFailed(error) { return { type: FETCH_ALL_SLICES_FAILED, payload: { error } }; } -export function getDatasourceParameter(datasourceId, datasourceType) { - return `${datasourceId}__${datasourceType}`; +export function fetchSlices( + userId, + excludeFilterBox, + dispatch, + filter_value, + sortColumn = 'changed_on', + slices = {}, +) { + const additional_filters = filter_value + ? [{ col: 'slice_name', opr: 'chart_all_text', value: filter_value }] + : []; + + const cloneSlices = { ...slices }; + + return SupersetClient.get({ + endpoint: `/api/v1/chart/?q=${rison.encode({ + columns: [ + 'changed_on_delta_humanized', + 'changed_on_utc', + 'datasource_id', + 'datasource_type', + 'datasource_url', + 'datasource_name_text', + 'description_markeddown', + 'description', + 'id', + 'params', + 'slice_name', + 'thumbnail_url', + 'url', + 'viz_type', + ], + filters: [...additional_filters], + page_size: FETCH_SLICES_PAGE_SIZE, + order_column: + sortColumn === 'changed_on' ? 'changed_on_delta_humanized' : sortColumn, + order_direction: sortColumn === 'changed_on' ? 'desc' : 'asc', + })}`, + }) + .then(({ json }) => { + let { result } = json; + // disable add filter_box viz to dashboard + if (excludeFilterBox) { + result = result.filter(slice => slice.viz_type !== 'filter_box'); + } + result.forEach(slice => { + let form_data = JSON.parse(slice.params); + form_data = { + ...form_data, + // force using datasource stored in relational table prop + datasource: + getDatasourceParameter( + slice.datasource_id, + slice.datasource_type, + ) || form_data.datasource, + }; + cloneSlices[slice.id] = { + slice_id: slice.id, + slice_url: slice.url, + slice_name: slice.slice_name, + form_data, + datasource_name: slice.datasource_name_text, + datasource_url: slice.datasource_url, + datasource_id: slice.datasource_id, + datasource_type: slice.datasource_type, + changed_on: new Date(slice.changed_on_utc).getTime(), + description: slice.description, + description_markdown: slice.description_markeddown, + viz_type: slice.viz_type, + modified: slice.changed_on_delta_humanized, + changed_on_humanized: slice.changed_on_delta_humanized, + thumbnail_url: slice.thumbnail_url, + }; + }); + + return dispatch(setAllSlices(cloneSlices)); + }) + .catch(errorResponse => + getClientErrorObject(errorResponse).then(({ error }) => { + dispatch( + fetchAllSlicesFailed(error || t('Could not fetch all saved charts')), + ); + dispatch( + addDangerToast( + t('Sorry there was an error fetching saved charts: ') + error, + ), + ); + }), + ); } -const FETCH_SLICES_PAGE_SIZE = 200; export function fetchAllSlices(userId, excludeFilterBox = false) { return (dispatch, getState) => { const { sliceEntities } = getState(); if (sliceEntities.lastUpdated === 0) { dispatch(fetchAllSlicesStarted()); - - return SupersetClient.get({ - endpoint: `/api/v1/chart/?q=${rison.encode({ - columns: [ - 'changed_on_delta_humanized', - 'changed_on_utc', - 'datasource_id', - 'datasource_type', - 'datasource_url', - 'datasource_name_text', - 'description_markeddown', - 'description', - 'id', - 'params', - 'slice_name', - 'url', - 'viz_type', - ], - filters: [{ col: 'owners', opr: 'rel_m_m', value: userId }], - page_size: FETCH_SLICES_PAGE_SIZE, - order_column: 'changed_on_delta_humanized', - order_direction: 'desc', - })}`, - }) - .then(({ json }) => { - const slices = {}; - let { result } = json; - // disable add filter_box viz to dashboard - if (excludeFilterBox) { - result = result.filter(slice => slice.viz_type !== 'filter_box'); - } - result.forEach(slice => { - let form_data = JSON.parse(slice.params); - form_data = { - ...form_data, - // force using datasource stored in relational table prop - datasource: - getDatasourceParameter( - slice.datasource_id, - slice.datasource_type, - ) || form_data.datasource, - }; - slices[slice.id] = { - slice_id: slice.id, - slice_url: slice.url, - slice_name: slice.slice_name, - form_data, - datasource_name: slice.datasource_name_text, - datasource_url: slice.datasource_url, - datasource_id: slice.datasource_id, - datasource_type: slice.datasource_type, - changed_on: new Date(slice.changed_on_utc).getTime(), - description: slice.description, - description_markdown: slice.description_markeddown, - viz_type: slice.viz_type, - modified: slice.changed_on_delta_humanized, - changed_on_humanized: slice.changed_on_delta_humanized, - }; - }); - - return dispatch(setAllSlices(slices)); - }) - .catch( - errorResponse => - console.log(errorResponse) || - getClientErrorObject(errorResponse).then(({ error }) => { - dispatch( - fetchAllSlicesFailed( - error || t('Could not fetch all saved charts'), - ), - ); - dispatch( - addDangerToast( - t('Sorry there was an error fetching saved charts: ') + error, - ), - ); - }), - ); + return fetchSlices(userId, excludeFilterBox, dispatch, undefined); } return dispatch(setAllSlices(sliceEntities.slices)); }; } + +export function fetchSortedSlices( + userId, + excludeFilterBox = false, + order_column, +) { + return dispatch => { + dispatch(fetchAllSlicesStarted()); + return fetchSlices( + userId, + excludeFilterBox, + dispatch, + undefined, + order_column, + ); + }; +} + +export function fetchFilteredSlices( + userId, + excludeFilterBox = false, + filter_value, +) { + return (dispatch, getState) => { + dispatch(fetchAllSlicesStarted()); + const { sliceEntities } = getState(); + return fetchSlices( + userId, + excludeFilterBox, + dispatch, + filter_value, + undefined, + sliceEntities.slices, + ); + }; +} diff --git a/superset-frontend/src/dashboard/actions/sliceEntities.test.js b/superset-frontend/src/dashboard/actions/sliceEntities.test.js new file mode 100644 index 0000000000000..0fe9365fc9d1c --- /dev/null +++ b/superset-frontend/src/dashboard/actions/sliceEntities.test.js @@ -0,0 +1,102 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import sinon from 'sinon'; +import { SupersetClient } from '@superset-ui/core'; + +import { + FETCH_ALL_SLICES_STARTED, + fetchSortedSlices, + fetchFilteredSlices, + fetchAllSlices, +} from './sliceEntities'; + +describe('slice entity actions', () => { + const mockState = { + sliceEntities: { slices: {} }, + isLoading: true, + errorMessage: null, + lastUpdated: 0, + }; + + function setup(stateOverrides) { + const state = { ...mockState, ...stateOverrides }; + const getState = sinon.spy(() => state); + const dispatch = sinon.spy(); + + return { getState, dispatch, state }; + } + + let spy; + + beforeEach(() => { + spy = sinon.spy(SupersetClient); + }); + + afterEach(() => { + sinon.restore(); + }); + + describe('fetchSortedSlices', () => { + it('should dispatch an fetchAllSlicesStarted action', async () => { + const { dispatch } = setup(); + const thunk1 = fetchSortedSlices('userId', false, 'orderColumn'); + await thunk1(dispatch); + expect(dispatch.getCall(0).args[0]).toEqual({ + type: FETCH_ALL_SLICES_STARTED, + }); + expect(spy.get.callCount).toBe(1); + }); + }); + + describe('fetchFilteredSlices', () => { + it('should dispatch an fetchAllSlicesStarted action', async () => { + const { dispatch, getState } = setup(); + const thunk1 = fetchFilteredSlices('userId', false, 'filter_value'); + await thunk1(dispatch, getState); + expect(dispatch.getCall(0).args[0]).toEqual({ + type: FETCH_ALL_SLICES_STARTED, + }); + expect(spy.get.callCount).toBe(1); + }); + }); + + describe('fetchAllSlices', () => { + it('should not trigger fetchSlices when sliceEntities lastUpdate is not 0', async () => { + const { dispatch, getState } = setup({ + sliceEntities: { slices: {}, lastUpdated: 1 }, + }); + + const thunk1 = fetchAllSlices('userId', false, 'filter_value'); + await thunk1(dispatch, getState); + + expect(spy.get.callCount).toBe(0); + }); + + it('should trigger fetchSlices when sliceEntities lastUpdate is 0', async () => { + const { dispatch, getState } = setup({ + sliceEntities: { slices: {}, lastUpdated: 0 }, + }); + + const thunk1 = fetchAllSlices('userId', false, 'filter_value'); + await thunk1(dispatch, getState); + + expect(spy.get.callCount).toBe(1); + }); + }); +}); diff --git a/superset-frontend/src/dashboard/components/AddSliceCard.jsx b/superset-frontend/src/dashboard/components/AddSliceCard.jsx deleted file mode 100644 index 7a8f7f3b78280..0000000000000 --- a/superset-frontend/src/dashboard/components/AddSliceCard.jsx +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import cx from 'classnames'; -import React from 'react'; -import PropTypes from 'prop-types'; -import { t, styled } from '@superset-ui/core'; - -const propTypes = { - datasourceUrl: PropTypes.string, - datasourceName: PropTypes.string, - innerRef: PropTypes.func, - isSelected: PropTypes.bool, - lastModified: PropTypes.string, - sliceName: PropTypes.string.isRequired, - style: PropTypes.object, - visType: PropTypes.string.isRequired, -}; - -const defaultProps = { - datasourceUrl: null, - datasourceName: '-', - innerRef: null, - isSelected: false, - style: null, - lastModified: null, -}; - -const Styled = styled.div` - ${({ theme }) => ` - .chart-card { - border: 1px solid ${theme.colors.grayscale.light2}; - border-radius: ${theme.gridUnit}px; - background: ${theme.colors.grayscale.light5}; - padding: ${theme.gridUnit * 2}px; - margin: 0 ${theme.gridUnit * 3}px - ${theme.gridUnit * 3}px - ${theme.gridUnit * 3}px; - position: relative; - cursor: move; - white-space: nowrap; - overflow: hidden; - - &:hover { - background: ${theme.colors.grayscale.light4}; - } - } - - .chart-card.is-selected { - cursor: not-allowed; - opacity: 0.4; - } - - .card-title { - margin-right: 60px; - margin-bottom: ${theme.gridUnit * 2}px; - font-weight: ${theme.typography.weights.bold}; - } - - .card-body { - display: flex; - flex-direction: column; - - .item { - span { - word-break: break-all; - - &:first-child { - font-weight: ${theme.typography.weights.normal}; - } - } - } - } - - .is-added-label { - background: ${theme.colors.grayscale.base}; - border-radius: ${theme.gridUnit}px; - color: ${theme.colors.grayscale.light5}; - font-size: ${theme.typography.sizes.s}px; - text-transform: uppercase; - position: absolute; - padding: ${theme.gridUnit}px - ${theme.gridUnit * 2}px; - top: ${theme.gridUnit * 8}px; - right: ${theme.gridUnit * 8}px; - pointer-events: none; - } - `} -`; - -function AddSliceCard({ - datasourceUrl, - datasourceName, - innerRef, - isSelected, - lastModified, - sliceName, - style, - visType, -}) { - return ( - <Styled ref={innerRef} style={style}> - <div - className={cx('chart-card', isSelected && 'is-selected')} - data-test="chart-card" - > - <div className="card-title" data-test="card-title"> - {sliceName} - </div> - <div className="card-body"> - <div className="item"> - <span>{t('Modified')} </span> - <span>{lastModified}</span> - </div> - <div className="item"> - <span>{t('Visualization')} </span> - <span>{visType}</span> - </div> - <div className="item"> - <span>{t('Data source')} </span> - <a href={datasourceUrl}>{datasourceName}</a> - </div> - </div> - </div> - {isSelected && <div className="is-added-label">{t('Added')}</div>} - </Styled> - ); -} - -AddSliceCard.propTypes = propTypes; -AddSliceCard.defaultProps = defaultProps; - -export default AddSliceCard; diff --git a/superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.test.tsx b/superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.test.tsx new file mode 100644 index 0000000000000..26cd7b945d0e9 --- /dev/null +++ b/superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.test.tsx @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { FeatureFlag } from '@superset-ui/core'; +import { act, render, screen } from 'spec/helpers/testing-library'; +import AddSliceCard from '.'; + +jest.mock('src/components/DynamicPlugins', () => ({ + usePluginContext: () => ({ + mountedPluginMetadata: { table: { name: 'Table' } }, + }), +})); + +const mockedProps = { + visType: 'table', + sliceName: '-', +}; + +declare const global: { + featureFlags: Record<string, boolean>; +}; + +test('do not render thumbnail if feature flag is not set', async () => { + global.featureFlags = { + [FeatureFlag.THUMBNAILS]: false, + }; + + await act(async () => { + render(<AddSliceCard {...mockedProps} />); + }); + + expect(screen.queryByTestId('thumbnail')).not.toBeInTheDocument(); +}); + +test('render thumbnail if feature flag is set', async () => { + global.featureFlags = { + [FeatureFlag.THUMBNAILS]: true, + }; + + await act(async () => { + render(<AddSliceCard {...mockedProps} />); + }); + + expect(screen.queryByTestId('thumbnail')).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.tsx b/superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.tsx new file mode 100644 index 0000000000000..caf71c0b90190 --- /dev/null +++ b/superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.tsx @@ -0,0 +1,288 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { + CSSProperties, + ReactNode, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import { t, isFeatureEnabled, FeatureFlag, css } from '@superset-ui/core'; +import ImageLoader from 'src/components/ListViewCard/ImageLoader'; +import { usePluginContext } from 'src/components/DynamicPlugins'; +import { Tooltip } from 'src/components/Tooltip'; +import { GenericLink } from 'src/components/GenericLink/GenericLink'; +import { Theme } from '@emotion/react'; + +const FALLBACK_THUMBNAIL_URL = '/static/assets/images/chart-card-fallback.svg'; + +const TruncatedTextWithTooltip: React.FC = ({ children, ...props }) => { + const [isTruncated, setIsTruncated] = useState(false); + const ref = useRef<HTMLDivElement>(null); + useEffect(() => { + setIsTruncated( + ref.current ? ref.current.scrollWidth > ref.current.clientWidth : false, + ); + }, [children]); + + const div = ( + <div + {...props} + ref={ref} + css={css` + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + `} + > + {children} + </div> + ); + + return isTruncated ? <Tooltip title={children}>{div}</Tooltip> : div; +}; + +const MetadataItem: React.FC<{ + label: ReactNode; + value: ReactNode; +}> = ({ label, value }) => ( + <div + css={(theme: Theme) => css` + font-size: ${theme.typography.sizes.s}px; + display: flex; + justify-content: space-between; + + &:not(:last-child) { + margin-bottom: ${theme.gridUnit}px; + } + `} + > + <span + css={(theme: Theme) => css` + margin-right: ${theme.gridUnit * 4}px; + color: ${theme.colors.grayscale.base}; + `} + > + {label} + </span> + <span + css={css` + min-width: 0; + `} + > + <TruncatedTextWithTooltip>{value}</TruncatedTextWithTooltip> + </span> + </div> +); + +const SliceAddedBadgePlaceholder: React.FC<{ + showThumbnails?: boolean; + placeholderRef: (element: HTMLDivElement) => void; +}> = ({ showThumbnails, placeholderRef }) => ( + <div + ref={placeholderRef} + css={(theme: Theme) => css` + /* Display styles */ + border: 1px solid ${theme.colors.primary.dark1}; + border-radius: ${theme.gridUnit}px; + color: ${theme.colors.primary.dark1}; + font-size: ${theme.typography.sizes.xs}px; + text-transform: uppercase; + letter-spacing: 0.02em; + padding: ${theme.gridUnit / 2}px ${theme.gridUnit * 2}px; + margin-left: ${theme.gridUnit * 4}px; + pointer-events: none; + + /* Position styles */ + visibility: hidden; + position: ${showThumbnails ? 'absolute' : 'unset'}; + top: ${showThumbnails ? '72px' : 'unset'}; + left: ${showThumbnails ? '84px' : 'unset'}; + `} + > + {t('Added')} + </div> +); + +const SliceAddedBadge: React.FC<{ placeholder?: HTMLDivElement }> = ({ + placeholder, +}) => ( + <div + css={(theme: Theme) => css` + /* Display styles */ + border: 1px solid ${theme.colors.primary.dark1}; + border-radius: ${theme.gridUnit}px; + color: ${theme.colors.primary.dark1}; + font-size: ${theme.typography.sizes.xs}px; + text-transform: uppercase; + letter-spacing: 0.02em; + padding: ${theme.gridUnit / 2}px ${theme.gridUnit * 2}px; + margin-left: ${theme.gridUnit * 4}px; + pointer-events: none; + + /* Position styles */ + display: ${placeholder ? 'unset' : 'none'}; + position: absolute; + top: ${placeholder ? `${placeholder.offsetTop}px` : 'unset'}; + left: ${placeholder ? `${placeholder.offsetLeft - 2}px` : 'unset'}; + `} + > + {t('Added')} + </div> +); + +const AddSliceCard: React.FC<{ + datasourceUrl?: string; + datasourceName?: string; + innerRef?: React.RefObject<HTMLDivElement>; + isSelected?: boolean; + lastModified?: string; + sliceName: string; + style?: CSSProperties; + thumbnailUrl?: string; + visType: string; +}> = ({ + datasourceUrl, + datasourceName = '-', + innerRef, + isSelected = false, + lastModified, + sliceName, + style = {}, + thumbnailUrl, + visType, +}) => { + const showThumbnails = isFeatureEnabled(FeatureFlag.THUMBNAILS); + const [sliceAddedBadge, setSliceAddedBadge] = useState<HTMLDivElement>(); + const { mountedPluginMetadata } = usePluginContext(); + const vizName = useMemo( + () => mountedPluginMetadata[visType].name, + [mountedPluginMetadata, visType], + ); + + return ( + <div ref={innerRef} style={style}> + <div + data-test="chart-card" + css={(theme: Theme) => css` + border: 1px solid ${theme.colors.grayscale.light2}; + border-radius: ${theme.gridUnit}px; + background: ${theme.colors.grayscale.light5}; + padding: ${theme.gridUnit * 4}px; + margin: 0 ${theme.gridUnit * 3}px + ${theme.gridUnit * 3}px + ${theme.gridUnit * 3}px; + position: relative; + cursor: ${isSelected ? 'not-allowed' : 'move'}; + white-space: nowrap; + overflow: hidden; + line-height: 1.3; + color: ${theme.colors.grayscale.dark1} + + &:hover { + background: ${theme.colors.grayscale.light4}; + } + + opacity: ${isSelected ? 0.4 : 'unset'}; + `} + > + <div + css={css` + display: flex; + `} + > + {showThumbnails ? ( + <div + data-test="thumbnail" + css={css` + width: 146px; + height: 82px; + flex-shrink: 0; + margin-right: 16px; + `} + > + <ImageLoader + src={thumbnailUrl || ''} + fallback={FALLBACK_THUMBNAIL_URL} + position="top" + /> + {isSelected && showThumbnails ? ( + <SliceAddedBadgePlaceholder + placeholderRef={setSliceAddedBadge} + showThumbnails={showThumbnails} + /> + ) : null} + </div> + ) : null} + <div + css={css` + flex-grow: 1; + min-width: 0; + `} + > + <div + data-test="card-title" + css={(theme: Theme) => css` + margin-bottom: ${theme.gridUnit * 2}px; + font-weight: ${theme.typography.weights.bold}; + display: flex; + justify-content: space-between; + align-items: center; + `} + > + <TruncatedTextWithTooltip>{sliceName}</TruncatedTextWithTooltip> + {isSelected && !showThumbnails ? ( + <SliceAddedBadgePlaceholder + placeholderRef={setSliceAddedBadge} + /> + ) : null} + </div> + <div + css={css` + display: flex; + flex-direction: column; + `} + > + <MetadataItem label={t('Viz type')} value={vizName} /> + <MetadataItem + label={t('Dataset')} + value={ + datasourceUrl ? ( + <GenericLink to={datasourceUrl}> + {datasourceName} + </GenericLink> + ) : ( + datasourceName + ) + } + /> + <MetadataItem label={t('Modified')} value={lastModified} /> + </div> + </div> + </div> + </div> + <SliceAddedBadge placeholder={sliceAddedBadge} /> + </div> + ); +}; + +export default AddSliceCard; diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/chart_list.helper.ts b/superset-frontend/src/dashboard/components/AddSliceCard/index.ts similarity index 91% rename from superset-frontend/cypress-base/cypress/integration/chart_list/chart_list.helper.ts rename to superset-frontend/src/dashboard/components/AddSliceCard/index.ts index 0d66010cf4eb7..c3736da122cdf 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/chart_list.helper.ts +++ b/superset-frontend/src/dashboard/components/AddSliceCard/index.ts @@ -16,4 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -export const CHART_LIST = '/chart/list/'; + +import AddSliceCard from './AddSliceCard'; + +export default AddSliceCard; diff --git a/superset-frontend/src/dashboard/components/AnchorLink/index.tsx b/superset-frontend/src/dashboard/components/AnchorLink/index.tsx index cfabaf51b7daf..a2541ce2a242c 100644 --- a/superset-frontend/src/dashboard/components/AnchorLink/index.tsx +++ b/superset-frontend/src/dashboard/components/AnchorLink/index.tsx @@ -26,9 +26,10 @@ import getLocationHash from 'src/dashboard/util/getLocationHash'; export type AnchorLinkProps = { id: string; + dashboardId?: number; scrollIntoView?: boolean; showShortLinkButton?: boolean; -} & Pick<URLShortLinkButtonProps, 'dashboardId' | 'placement'>; +} & Pick<URLShortLinkButtonProps, 'placement'>; export default function AnchorLink({ id, diff --git a/superset-frontend/src/dashboard/components/BuilderComponentPane/BuilderComponentPane.test.tsx b/superset-frontend/src/dashboard/components/BuilderComponentPane/BuilderComponentPane.test.tsx index a5ff5b1314f3d..be2b429f59db4 100644 --- a/superset-frontend/src/dashboard/components/BuilderComponentPane/BuilderComponentPane.test.tsx +++ b/superset-frontend/src/dashboard/components/BuilderComponentPane/BuilderComponentPane.test.tsx @@ -24,7 +24,7 @@ import BuilderComponentPane from '.'; jest.mock('src/dashboard/containers/SliceAdder'); test('BuilderComponentPane has correct tabs in correct order', () => { - render(<BuilderComponentPane isStandalone={false} topOffset={115} />); + render(<BuilderComponentPane topOffset={115} />); const tabs = screen.getAllByRole('tab'); expect(tabs).toHaveLength(2); expect(tabs[0]).toHaveTextContent('Charts'); diff --git a/superset-frontend/src/dashboard/components/BuilderComponentPane/index.tsx b/superset-frontend/src/dashboard/components/BuilderComponentPane/index.tsx index 7a1019a0e2b22..d9b34cfed2c5c 100644 --- a/superset-frontend/src/dashboard/components/BuilderComponentPane/index.tsx +++ b/superset-frontend/src/dashboard/components/BuilderComponentPane/index.tsx @@ -18,12 +18,9 @@ */ /* eslint-env browser */ import React from 'react'; +import { rgba } from 'emotion-rgba'; import Tabs from 'src/components/Tabs'; -import { StickyContainer, Sticky } from 'react-sticky'; -import { ParentSize } from '@vx/responsive'; - -import { t, styled } from '@superset-ui/core'; - +import { t, css, SupersetTheme } from '@superset-ui/core'; import SliceAdder from 'src/dashboard/containers/SliceAdder'; import dashboardComponents from 'src/visualizations/presets/dashboardComponents'; import NewColumn from '../gridComponents/new/NewColumn'; @@ -34,98 +31,72 @@ import NewTabs from '../gridComponents/new/NewTabs'; import NewMarkdown from '../gridComponents/new/NewMarkdown'; import NewDynamicComponent from '../gridComponents/new/NewDynamicComponent'; -export interface BCPProps { - isStandalone: boolean; - topOffset: number; -} - -const SUPERSET_HEADER_HEIGHT = 59; -const SIDEPANE_ADJUST_OFFSET = 4; -const TOP_PANEL_OFFSET = 210; - -const BuilderComponentPaneTabs = styled(Tabs)` - line-height: inherit; - margin-top: ${({ theme }) => theme.gridUnit * 2}px; -`; - -const DashboardBuilderSidepane = styled.div<{ - topOffset: number; -}>` - height: calc(100% - ${TOP_PANEL_OFFSET}px); - position: fixed; - right: 0; - top: 0; -`; +const BUILDER_PANE_WIDTH = 374; -const BuilderComponentPane: React.FC<BCPProps> = ({ - isStandalone, - topOffset = 0, -}) => ( - <DashboardBuilderSidepane - topOffset={topOffset} - className="dashboard-builder-sidepane" +const BuilderComponentPane = ({ topOffset = 0 }) => ( + <div + data-test="dashboard-builder-sidepane" + css={css` + position: sticky; + right: 0; + top: ${topOffset}px; + height: calc(100vh - ${topOffset}px); + width: ${BUILDER_PANE_WIDTH}px; + `} > - <ParentSize> - {({ height }) => ( - <StickyContainer> - <Sticky topOffset={-topOffset} bottomOffset={Infinity}> - {({ style, isSticky }: { style: any; isSticky: boolean }) => { - const { pageYOffset } = window; - const hasHeader = - pageYOffset < SUPERSET_HEADER_HEIGHT && !isStandalone; - const withHeaderTopOffset = - topOffset + - (SUPERSET_HEADER_HEIGHT - pageYOffset - SIDEPANE_ADJUST_OFFSET); + <div + css={(theme: SupersetTheme) => css` + position: absolute; + height: 100%; + width: ${BUILDER_PANE_WIDTH}px; + box-shadow: -4px 0 4px 0 ${rgba(theme.colors.grayscale.dark2, 0.1)}; + background-color: ${theme.colors.grayscale.light5}; + `} + > + <Tabs + data-test="dashboard-builder-component-pane-tabs-navigation" + id="tabs" + css={(theme: SupersetTheme) => css` + line-height: inherit; + margin-top: ${theme.gridUnit * 2}px; + height: 100%; - return ( - <div - className="viewport" - style={{ - ...style, - top: hasHeader ? withHeaderTopOffset : topOffset, - }} - > - <BuilderComponentPaneTabs - id="tabs" - className="tabs-components" - data-test="dashboard-builder-component-pane-tabs-navigation" - > - <Tabs.TabPane - key={1} - tab={t('Charts')} - className="tab-charts" - > - <SliceAdder - height={ - height + (isSticky ? SUPERSET_HEADER_HEIGHT : 0) - } - /> - </Tabs.TabPane> - <Tabs.TabPane key={2} tab={t('Layout elements')}> - <NewTabs /> - <NewRow /> - <NewColumn /> - <NewHeader /> - <NewMarkdown /> - <NewDivider /> - {dashboardComponents - .getAll() - .map(({ key: componentKey, metadata }) => ( - <NewDynamicComponent - metadata={metadata} - componentKey={componentKey} - /> - ))} - </Tabs.TabPane> - </BuilderComponentPaneTabs> - </div> - ); - }} - </Sticky> - </StickyContainer> - )} - </ParentSize> - </DashboardBuilderSidepane> + & .ant-tabs-content-holder { + height: 100%; + & .ant-tabs-content { + height: 100%; + } + } + `} + > + <Tabs.TabPane + key={1} + tab={t('Charts')} + css={css` + height: 100%; + `} + > + <SliceAdder /> + </Tabs.TabPane> + <Tabs.TabPane key={2} tab={t('Layout elements')}> + <NewTabs /> + <NewRow /> + <NewColumn /> + <NewHeader /> + <NewMarkdown /> + <NewDivider /> + {dashboardComponents + .getAll() + .map(({ key: componentKey, metadata }) => ( + <NewDynamicComponent + metadata={metadata} + componentKey={componentKey} + /> + ))} + </Tabs.TabPane> + </Tabs> + </div> + </div> ); export default BuilderComponentPane; diff --git a/superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx b/superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx index f860f65b3550b..cdd9364b4b82d 100644 --- a/superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx +++ b/superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx @@ -24,6 +24,8 @@ import Button from 'src/components/Button'; import { AntdForm } from 'src/components'; import { setChartConfiguration } from 'src/dashboard/actions/dashboardInfo'; import { ChartConfiguration } from 'src/dashboard/reducers/types'; +import { ChartsState, Layout, RootState } from 'src/dashboard/types'; +import { getChartIdsInFilterScope } from 'src/dashboard/util/getChartIdsInFilterScope'; import CrossFilterScopingForm from './CrossFilterScopingForm'; import { CrossFilterScopingFormType } from './types'; import { StyledForm } from '../nativeFilters/FiltersConfigModal/FiltersConfigModal'; @@ -44,14 +46,24 @@ const CrossFilterScopingModal: FC<CrossFilterScopingModalProps> = ({ const chartConfig = useSelector<any, ChartConfiguration>( ({ dashboardInfo }) => dashboardInfo?.metadata?.chart_configuration, ); + const charts = useSelector<RootState, ChartsState>(state => state.charts); + const layout = useSelector<RootState, Layout>( + state => state.dashboardLayout.present, + ); const scope = chartConfig?.[chartId]?.crossFilters?.scope; const handleSave = () => { + const chartsInScope = getChartIdsInFilterScope( + form.getFieldValue('scope'), + charts, + layout, + ); + dispatch( setChartConfiguration({ ...chartConfig, [chartId]: { id: chartId, - crossFilters: { scope: form.getFieldValue('scope') }, + crossFilters: { scope: form.getFieldValue('scope'), chartsInScope }, }, }), ); diff --git a/superset-frontend/src/dashboard/components/Dashboard.jsx b/superset-frontend/src/dashboard/components/Dashboard.jsx index f04eb696aade8..827f0f455d3d6 100644 --- a/superset-frontend/src/dashboard/components/Dashboard.jsx +++ b/superset-frontend/src/dashboard/components/Dashboard.jsx @@ -22,6 +22,7 @@ import { isFeatureEnabled, t, FeatureFlag } from '@superset-ui/core'; import { PluginContext } from 'src/components/DynamicPlugins'; import Loading from 'src/components/Loading'; +import getBootstrapData from 'src/utils/getBootstrapData'; import getChartIdsFromLayout from '../util/getChartIdsFromLayout'; import getLayoutComponentFromChartId from '../util/getLayoutComponentFromChartId'; import DashboardBuilder from './DashboardBuilder/DashboardBuilder'; @@ -38,7 +39,6 @@ import { } from '../../logger/LogUtils'; import { areObjectsEqual } from '../../reduxUtils'; -import '../stylesheets/index.less'; import getLocationHash from '../util/getLocationHash'; import isDashboardEmpty from '../util/isDashboardEmpty'; import { getAffectedOwnDataCharts } from '../util/charts/getOwnDataCharts'; @@ -56,7 +56,7 @@ const propTypes = { charts: PropTypes.objectOf(chartPropShape).isRequired, slices: PropTypes.objectOf(slicePropShape).isRequired, activeFilters: PropTypes.object.isRequired, - chartConfiguration: PropTypes.object.isRequired, + chartConfiguration: PropTypes.object, datasources: PropTypes.object.isRequired, ownDataCharts: PropTypes.object.isRequired, layout: PropTypes.object.isRequired, @@ -97,8 +97,7 @@ class Dashboard extends React.PureComponent { } componentDidMount() { - const appContainer = document.getElementById('app'); - const bootstrapData = appContainer?.getAttribute('data-bootstrap') || '{}'; + const bootstrapData = getBootstrapData(); const { dashboardState, layout } = this.props; const eventData = { is_soft_navigation: Logger.timeOriginOffset > 0, diff --git a/superset-frontend/src/dashboard/components/Dashboard.test.jsx b/superset-frontend/src/dashboard/components/Dashboard.test.jsx index a881d0cdadf93..56a696f913140 100644 --- a/superset-frontend/src/dashboard/components/Dashboard.test.jsx +++ b/superset-frontend/src/dashboard/components/Dashboard.test.jsx @@ -31,7 +31,6 @@ import datasources from 'spec/fixtures/mockDatasource'; import { extraFormData, NATIVE_FILTER_ID, - layoutForSingleNativeFilter, singleNativeFiltersState, dataMaskWith1Filter, } from 'spec/fixtures/mockNativeFilters'; @@ -157,7 +156,7 @@ describe('Dashboard', () => { ...getAllActiveFilters({ dataMask: dataMaskWith1Filter, nativeFilters: singleNativeFiltersState.filters, - layout: layoutForSingleNativeFilter, + allSliceIds: [227, 229, 230], }), }, }); diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.test.jsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.test.jsx deleted file mode 100644 index 937012a9f8bea..0000000000000 --- a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.test.jsx +++ /dev/null @@ -1,196 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { Provider } from 'react-redux'; -import React from 'react'; -import { mount } from 'enzyme'; -import sinon from 'sinon'; -import fetchMock from 'fetch-mock'; -import { ParentSize } from '@vx/responsive'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; -import Tabs from 'src/components/Tabs'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; -import BuilderComponentPane from 'src/dashboard/components/BuilderComponentPane'; -import DashboardBuilder from 'src/dashboard/components/DashboardBuilder/DashboardBuilder'; -import DashboardComponent from 'src/dashboard/containers/DashboardComponent'; -import DashboardHeader from 'src/dashboard/containers/DashboardHeader'; -import DashboardGrid from 'src/dashboard/containers/DashboardGrid'; -import * as dashboardStateActions from 'src/dashboard/actions/dashboardState'; -import { - dashboardLayout as undoableDashboardLayout, - dashboardLayoutWithTabs as undoableDashboardLayoutWithTabs, -} from 'spec/fixtures/mockDashboardLayout'; -import { mockStoreWithTabs, storeWithState } from 'spec/fixtures/mockStore'; -import mockState from 'spec/fixtures/mockState'; -import { - DASHBOARD_ROOT_ID, - DASHBOARD_GRID_ID, -} from 'src/dashboard/util/constants'; - -fetchMock.get('glob:*/csstemplateasyncmodelview/api/read', {}); - -jest.mock('src/dashboard/actions/dashboardState'); - -describe('DashboardBuilder', () => { - let favStarStub; - let activeTabsStub; - - beforeAll(() => { - // this is invoked on mount, so we stub it instead of making a request - favStarStub = sinon - .stub(dashboardStateActions, 'fetchFaveStar') - .returns({ type: 'mock-action' }); - activeTabsStub = sinon - .stub(dashboardStateActions, 'setActiveTabs') - .returns({ type: 'mock-action' }); - }); - - afterAll(() => { - favStarStub.restore(); - activeTabsStub.restore(); - }); - - function setup(overrideState = {}, overrideStore) { - const store = - overrideStore ?? - storeWithState({ - ...mockState, - dashboardLayout: undoableDashboardLayout, - ...overrideState, - }); - return mount( - <Provider store={store}> - <DndProvider backend={HTML5Backend}> - <DashboardBuilder /> - </DndProvider> - </Provider>, - { - wrappingComponent: ThemeProvider, - wrappingComponentProps: { theme: supersetTheme }, - }, - ); - } - - it('should render a StickyContainer with class "dashboard"', () => { - const wrapper = setup(); - const stickyContainer = wrapper.find('[data-test="dashboard-content"]'); - expect(stickyContainer).toHaveLength(1); - expect(stickyContainer.prop('className')).toBe('dashboard'); - }); - - it('should add the "dashboard--editing" class if editMode=true', () => { - const wrapper = setup({ dashboardState: { editMode: true } }); - const stickyContainer = wrapper.find('[data-test="dashboard-content"]'); - expect(stickyContainer.prop('className')).toBe( - 'dashboard dashboard--editing', - ); - }); - - it('should render a DragDroppable DashboardHeader', () => { - const wrapper = setup(); - expect(wrapper.find(DashboardHeader)).toExist(); - }); - - it('should render a Sticky top-level Tabs if the dashboard has tabs', () => { - const wrapper = setup( - { dashboardLayout: undoableDashboardLayoutWithTabs }, - mockStoreWithTabs, - ); - - const sticky = wrapper.find('[data-test="top-level-tabs"]'); - const dashboardComponent = sticky.find(DashboardComponent); - - const tabChildren = - undoableDashboardLayoutWithTabs.present.TABS_ID.children; - expect(dashboardComponent).toHaveLength(1 + tabChildren.length); // tab + tabs - expect(dashboardComponent.at(0).prop('id')).toBe('TABS_ID'); - tabChildren.forEach((tabId, i) => { - expect(dashboardComponent.at(i + 1).prop('id')).toBe(tabId); - }); - }); - - it('should render one Tabs and two TabPane', () => { - const wrapper = setup({ dashboardLayout: undoableDashboardLayoutWithTabs }); - const parentSize = wrapper.find(ParentSize); - expect(parentSize.find(Tabs)).toHaveLength(1); - expect(parentSize.find(Tabs.TabPane)).toHaveLength(2); - }); - - it('should render a TabPane and DashboardGrid for first Tab', () => { - const wrapper = setup({ dashboardLayout: undoableDashboardLayoutWithTabs }); - const parentSize = wrapper.find(ParentSize); - const expectedCount = - undoableDashboardLayoutWithTabs.present.TABS_ID.children.length; - expect(parentSize.find(Tabs.TabPane)).toHaveLength(expectedCount); - expect( - parentSize.find(Tabs.TabPane).first().find(DashboardGrid), - ).toHaveLength(1); - }); - - it('should render a TabPane and DashboardGrid for second Tab', () => { - const wrapper = setup({ - dashboardLayout: undoableDashboardLayoutWithTabs, - dashboardState: { - ...mockState, - directPathToChild: [DASHBOARD_ROOT_ID, 'TABS_ID', 'TAB_ID2'], - }, - }); - const parentSize = wrapper.find(ParentSize); - const expectedCount = - undoableDashboardLayoutWithTabs.present.TABS_ID.children.length; - expect(parentSize.find(Tabs.TabPane)).toHaveLength(expectedCount); - expect( - parentSize.find(Tabs.TabPane).at(1).find(DashboardGrid), - ).toHaveLength(1); - }); - - it('should render a BuilderComponentPane if editMode=false and user selects "Insert Components" pane', () => { - const wrapper = setup(); - expect(wrapper.find(BuilderComponentPane)).not.toExist(); - }); - - it('should render a BuilderComponentPane if editMode=true and user selects "Insert Components" pane', () => { - const wrapper = setup({ dashboardState: { editMode: true } }); - expect(wrapper.find(BuilderComponentPane)).toExist(); - }); - - it('should change redux state if a top-level Tab is clicked', () => { - dashboardStateActions.setDirectPathToChild = jest.fn(arg0 => ({ - type: 'type', - arg0, - })); - const wrapper = setup({ - ...mockStoreWithTabs, - dashboardLayout: undoableDashboardLayoutWithTabs, - }); - - expect(wrapper.find(Tabs).at(1).prop('activeKey')).toBe(DASHBOARD_GRID_ID); - - wrapper - .find('.dashboard-component-tabs .ant-tabs .ant-tabs-tab') - .at(1) - .simulate('click'); - - expect(dashboardStateActions.setDirectPathToChild).toHaveBeenCalledWith([ - 'ROOT_ID', - 'TABS_ID', - 'TAB_ID2', - ]); - }); -}); diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.test.tsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.test.tsx new file mode 100644 index 0000000000000..fc651e52b706c --- /dev/null +++ b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.test.tsx @@ -0,0 +1,291 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { Store } from 'redux'; +import React from 'react'; +import fetchMock from 'fetch-mock'; +import { render } from 'spec/helpers/testing-library'; +import { fireEvent, within } from '@testing-library/react'; +import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; +import DashboardBuilder from 'src/dashboard/components/DashboardBuilder/DashboardBuilder'; +import useStoredSidebarWidth from 'src/components/ResizableSidebar/useStoredSidebarWidth'; +import { + fetchFaveStar, + setActiveTabs, + setDirectPathToChild, +} from 'src/dashboard/actions/dashboardState'; +import { + dashboardLayout as undoableDashboardLayout, + dashboardLayoutWithTabs as undoableDashboardLayoutWithTabs, +} from 'spec/fixtures/mockDashboardLayout'; +import { mockStoreWithTabs, storeWithState } from 'spec/fixtures/mockStore'; +import mockState from 'spec/fixtures/mockState'; +import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants'; + +fetchMock.get('glob:*/csstemplateasyncmodelview/api/read', {}); + +jest.mock('src/dashboard/actions/dashboardState', () => ({ + ...jest.requireActual('src/dashboard/actions/dashboardState'), + fetchFaveStar: jest.fn(), + setActiveTabs: jest.fn(), + setDirectPathToChild: jest.fn(), +})); +jest.mock('src/featureFlags'); +jest.mock('src/components/ResizableSidebar/useStoredSidebarWidth'); + +// mock following dependant components to fix the prop warnings +jest.mock('src/components/DeprecatedSelect/WindowedSelect', () => () => ( + <div data-test="mock-windowed-select" /> +)); +jest.mock('src/components/DeprecatedSelect', () => () => ( + <div data-test="mock-deprecated-select" /> +)); +jest.mock('src/components/Select/Select', () => () => ( + <div data-test="mock-select" /> +)); +jest.mock('src/components/Select/AsyncSelect', () => () => ( + <div data-test="mock-async-select" /> +)); +jest.mock('src/dashboard/components/Header/HeaderActionsDropdown', () => () => ( + <div data-test="mock-header-actions-dropdown" /> +)); +jest.mock('src/components/PageHeaderWithActions', () => ({ + PageHeaderWithActions: () => ( + <div data-test="mock-page-header-with-actions" /> + ), +})); +jest.mock( + 'src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal', + () => () => <div data-test="mock-filters-config-modal" />, +); +jest.mock('src/dashboard/components/BuilderComponentPane', () => () => ( + <div data-test="mock-builder-component-pane" /> +)); +jest.mock('src/dashboard/components/nativeFilters/FilterBar', () => () => ( + <div data-test="mock-filter-bar" /> +)); +jest.mock('src/dashboard/containers/DashboardGrid', () => () => ( + <div data-test="mock-dashboard-grid" /> +)); + +describe('DashboardBuilder', () => { + let favStarStub: jest.Mock; + let activeTabsStub: jest.Mock; + + beforeAll(() => { + // this is invoked on mount, so we stub it instead of making a request + favStarStub = (fetchFaveStar as jest.Mock).mockReturnValue({ + type: 'mock-action', + }); + activeTabsStub = (setActiveTabs as jest.Mock).mockReturnValue({ + type: 'mock-action', + }); + (useStoredSidebarWidth as jest.Mock).mockImplementation(() => [ + 100, + jest.fn(), + ]); + (isFeatureEnabled as jest.Mock).mockImplementation(() => false); + }); + + afterAll(() => { + favStarStub.mockReset(); + activeTabsStub.mockReset(); + (useStoredSidebarWidth as jest.Mock).mockReset(); + }); + + function setup(overrideState = {}, overrideStore?: Store) { + return render(<DashboardBuilder />, { + useRedux: true, + store: storeWithState({ + ...mockState, + dashboardLayout: undoableDashboardLayout, + ...overrideState, + }), + useDnd: true, + }); + } + + it('should render a StickyContainer with class "dashboard"', () => { + const { getByTestId } = setup(); + const stickyContainer = getByTestId('dashboard-content-wrapper'); + expect(stickyContainer).toHaveClass('dashboard'); + }); + + it('should add the "dashboard--editing" class if editMode=true', () => { + const { getByTestId } = setup({ + dashboardState: { ...mockState.dashboardState, editMode: true }, + }); + const stickyContainer = getByTestId('dashboard-content-wrapper'); + expect(stickyContainer).toHaveClass('dashboard dashboard--editing'); + }); + + it('should render a DragDroppable DashboardHeader', () => { + const { queryByTestId } = setup(); + const header = queryByTestId('dashboard-header-container'); + expect(header).toBeTruthy(); + }); + + it('should render a Sticky top-level Tabs if the dashboard has tabs', async () => { + const { findAllByTestId } = setup( + { dashboardLayout: undoableDashboardLayoutWithTabs }, + mockStoreWithTabs, + ); + const sticky = await findAllByTestId('nav-list'); + + expect(sticky.length).toBe(1); + expect(sticky[0]).toHaveAttribute('id', 'TABS_ID'); + + const dashboardTabComponents = within(sticky[0]).getAllByRole('tab'); + const tabChildren = + undoableDashboardLayoutWithTabs.present.TABS_ID.children; + expect(dashboardTabComponents.length).toBe(tabChildren.length); + tabChildren.forEach((tabId, i) => { + const idMatcher = new RegExp(`${tabId}$`); + expect(dashboardTabComponents[i]).toHaveAttribute( + 'id', + expect.stringMatching(idMatcher), + ); + }); + }); + + it('should render one Tabs and two TabPane', async () => { + const { findAllByRole } = setup({ + dashboardLayout: undoableDashboardLayoutWithTabs, + }); + const tabs = await findAllByRole('tablist'); + expect(tabs.length).toBe(1); + const tabPanels = await findAllByRole('tabpanel'); + expect(tabPanels.length).toBe(2); + }); + + it('should render a TabPane and DashboardGrid for first Tab', async () => { + const { findByTestId } = setup({ + dashboardLayout: undoableDashboardLayoutWithTabs, + }); + const parentSize = await findByTestId('grid-container'); + const expectedCount = + undoableDashboardLayoutWithTabs.present.TABS_ID.children.length; + const tabPanels = within(parentSize).getAllByRole('tabpanel', { + // to include invisiable tab panels + hidden: true, + }); + expect(tabPanels.length).toBe(expectedCount); + expect( + within(tabPanels[0]).getAllByTestId('mock-dashboard-grid').length, + ).toBe(1); + }); + + it('should render a TabPane and DashboardGrid for second Tab', async () => { + const { findByTestId } = setup({ + dashboardLayout: undoableDashboardLayoutWithTabs, + dashboardState: { + ...mockState.dashboardState, + directPathToChild: [DASHBOARD_ROOT_ID, 'TABS_ID', 'TAB_ID2'], + }, + }); + const parentSize = await findByTestId('grid-container'); + const expectedCount = + undoableDashboardLayoutWithTabs.present.TABS_ID.children.length; + const tabPanels = within(parentSize).getAllByRole('tabpanel', { + // to include invisiable tab panels + hidden: true, + }); + expect(tabPanels.length).toBe(expectedCount); + expect( + within(tabPanels[1]).getAllByTestId('mock-dashboard-grid').length, + ).toBe(1); + }); + + it('should render a BuilderComponentPane if editMode=false and user selects "Insert Components" pane', () => { + const { queryAllByTestId } = setup(); + const builderComponents = queryAllByTestId('mock-builder-component-pane'); + expect(builderComponents.length).toBe(0); + }); + + it('should render a BuilderComponentPane if editMode=true and user selects "Insert Components" pane', () => { + const { queryAllByTestId } = setup({ dashboardState: { editMode: true } }); + const builderComponents = queryAllByTestId('mock-builder-component-pane'); + expect(builderComponents.length).toBeGreaterThanOrEqual(1); + }); + + it('should change redux state if a top-level Tab is clicked', async () => { + (setDirectPathToChild as jest.Mock).mockImplementation(arg0 => ({ + type: 'type', + arg0, + })); + const { findByRole } = setup( + { + dashboardLayout: undoableDashboardLayoutWithTabs, + }, + mockStoreWithTabs, + ); + const tabList = await findByRole('tablist'); + const tabs = within(tabList).getAllByRole('tab'); + expect(setDirectPathToChild).toHaveBeenCalledTimes(0); + fireEvent.click(tabs[1]); + expect(setDirectPathToChild).toHaveBeenCalledWith([ + 'ROOT_ID', + 'TABS_ID', + 'TAB_ID2', + ]); + (setDirectPathToChild as jest.Mock).mockReset(); + }); + + it('should not display a loading spinner when saving is not in progress', () => { + const { queryByAltText } = setup(); + + expect(queryByAltText('Loading...')).not.toBeInTheDocument(); + }); + + it('should display a loading spinner when saving is in progress', async () => { + const { findByAltText } = setup({ + dashboardState: { dashboardIsSaving: true }, + }); + + expect(await findByAltText('Loading...')).toBeVisible(); + }); + + describe('when nativeFiltersEnabled', () => { + beforeEach(() => { + (isFeatureEnabled as jest.Mock).mockImplementation( + flag => flag === FeatureFlag.DASHBOARD_NATIVE_FILTERS, + ); + }); + afterEach(() => { + (isFeatureEnabled as jest.Mock).mockReset(); + }); + + it('should set FilterBar width by useStoredSidebarWidth', () => { + const expectedValue = 200; + const setter = jest.fn(); + (useStoredSidebarWidth as jest.Mock).mockImplementation(() => [ + expectedValue, + setter, + ]); + const { getByTestId } = setup({ + dashboardInfo: { + ...mockState.dashboardInfo, + dash_edit_perm: true, + metadata: { show_native_filters: true }, + }, + }); + const filterbar = getByTestId('dashboard-filters-panel'); + expect(filterbar).toHaveStyleRule('width', `${expectedValue}px`); + }); + }); +}); diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx index 8352482ed8ab8..f07fdb9c066c4 100644 --- a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx +++ b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx @@ -22,11 +22,18 @@ import React, { FC, useCallback, useEffect, - useState, useMemo, useRef, + useState, } from 'react'; -import { JsonObject, styled, css, t } from '@superset-ui/core'; +import { + addAlpha, + css, + JsonObject, + styled, + t, + useTheme, +} from '@superset-ui/core'; import { Global } from '@emotion/react'; import { useDispatch, useSelector } from 'react-redux'; import ErrorBoundary from 'src/components/ErrorBoundary'; @@ -40,7 +47,11 @@ import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu'; import getDirectPathToTabIndex from 'src/dashboard/util/getDirectPathToTabIndex'; import { URL_PARAMS } from 'src/constants'; import { getUrlParam } from 'src/utils/urlUtils'; -import { DashboardLayout, RootState } from 'src/dashboard/types'; +import { + DashboardLayout, + FilterBarOrientation, + RootState, +} from 'src/dashboard/types'; import { setDirectPathToChild, setEditMode, @@ -53,82 +64,99 @@ import { } from 'src/dashboard/actions/dashboardLayout'; import { DASHBOARD_GRID_ID, - DASHBOARD_ROOT_ID, DASHBOARD_ROOT_DEPTH, + DASHBOARD_ROOT_ID, DashboardStandaloneMode, } from 'src/dashboard/util/constants'; import FilterBar from 'src/dashboard/components/nativeFilters/FilterBar'; import Loading from 'src/components/Loading'; import { EmptyStateBig } from 'src/components/EmptyState'; import { useUiConfig } from 'src/components/UiConfigContext'; +import ResizableSidebar from 'src/components/ResizableSidebar'; import { BUILDER_SIDEPANEL_WIDTH, CLOSED_FILTER_BAR_WIDTH, FILTER_BAR_HEADER_HEIGHT, FILTER_BAR_TABS_HEIGHT, MAIN_HEADER_HEIGHT, + OPEN_FILTER_BAR_MAX_WIDTH, OPEN_FILTER_BAR_WIDTH, } from 'src/dashboard/constants'; -import { shouldFocusTabs, getRootLevelTabsComponent } from './utils'; +import { getRootLevelTabsComponent, shouldFocusTabs } from './utils'; import DashboardContainer from './DashboardContainer'; import { useNativeFilters } from './state'; type DashboardBuilderProps = {}; const StyledDiv = styled.div` - display: grid; - grid-template-columns: auto 1fr; - grid-template-rows: auto 1fr; - flex: 1; - /* Special cases */ - - /* A row within a column has inset hover menu */ - .dragdroppable-column .dragdroppable-row .hover-menu--left { - left: -12px; - background: ${({ theme }) => theme.colors.grayscale.light5}; - border: 1px solid ${({ theme }) => theme.colors.grayscale.light2}; - } - - .dashboard-component-tabs { - position: relative; - } - - /* A column within a column or tabs has inset hover menu */ - .dragdroppable-column .dragdroppable-column .hover-menu--top, - .dashboard-component-tabs .dragdroppable-column .hover-menu--top { - top: -12px; - background: ${({ theme }) => theme.colors.grayscale.light5}; - border: 1px solid ${({ theme }) => theme.colors.grayscale.light2}; - } - - /* move Tabs hover menu to top near actual Tabs */ - .dashboard-component-tabs > .hover-menu-container > .hover-menu--left { - top: 0; - transform: unset; - background: transparent; - } - - /* push Chart actions to upper right */ - .dragdroppable-column .dashboard-component-chart-holder .hover-menu--top, - .dragdroppable .dashboard-component-header .hover-menu--top { - right: 8px; - top: 8px; - background: transparent; - border: none; - transform: unset; - left: unset; - } - div:hover > .hover-menu-container .hover-menu, - .hover-menu-container .hover-menu:hover { - opacity: 1; - } + ${({ theme }) => css` + display: grid; + grid-template-columns: auto 1fr; + grid-template-rows: auto 1fr; + flex: 1; + /* Special cases */ + + /* A row within a column has inset hover menu */ + .dragdroppable-column .dragdroppable-row .hover-menu--left { + left: ${theme.gridUnit * -3}px; + background: ${theme.colors.grayscale.light5}; + border: 1px solid ${theme.colors.grayscale.light2}; + } + + .dashboard-component-tabs { + position: relative; + } + + /* A column within a column or tabs has inset hover menu */ + .dragdroppable-column .dragdroppable-column .hover-menu--top, + .dashboard-component-tabs .dragdroppable-column .hover-menu--top { + top: ${theme.gridUnit * -3}px; + background: ${theme.colors.grayscale.light5}; + border: 1px solid ${theme.colors.grayscale.light2}; + } + + /* move Tabs hover menu to top near actual Tabs */ + .dashboard-component-tabs > .hover-menu-container > .hover-menu--left { + top: 0; + transform: unset; + background: transparent; + } + + /* push Chart actions to upper right */ + .dragdroppable-column .dashboard-component-chart-holder .hover-menu--top, + .dragdroppable .dashboard-component-header .hover-menu--top { + right: ${theme.gridUnit * 2}px; + top: ${theme.gridUnit * 2}px; + background: transparent; + border: none; + transform: unset; + left: unset; + } + div:hover > .hover-menu-container .hover-menu, + .hover-menu-container .hover-menu:hover { + opacity: 1; + } + + p { + margin: 0 0 ${theme.gridUnit * 2}px 0; + } + + i.danger { + color: ${theme.colors.error.base}; + } + + i.warning { + color: ${theme.colors.alert.base}; + } + `} `; // @z-index-above-dashboard-charts + 1 = 11 -const FiltersPanel = styled.div` +const FiltersPanel = styled.div<{ width: number }>` grid-column: 1; grid-row: 1 / span 2; z-index: 11; + width: ${({ width }) => width}px; `; const StickyPanel = styled.div<{ width: number }>` @@ -145,6 +173,7 @@ const StyledHeader = styled.div` position: sticky; top: 0; z-index: 100; + max-width: 100vw; `; const StyledContent = styled.div<{ @@ -156,69 +185,251 @@ const StyledContent = styled.div<{ ${({ fullSizeChartId }) => fullSizeChartId && `z-index: 101;`} `; +const DashboardContentWrapper = styled.div` + ${({ theme }) => css` + &.dashboard { + position: relative; + flex-grow: 1; + display: flex; + flex-direction: column; + height: 100%; + + /* drop shadow for top-level tabs only */ + & .dashboard-component-tabs { + box-shadow: 0 ${theme.gridUnit}px ${theme.gridUnit}px 0 + ${addAlpha( + theme.colors.grayscale.dark2, + parseFloat(theme.opacity.light) / 100, + )}; + padding-left: ${theme.gridUnit * + 2}px; /* note this is added to tab-level padding, to match header */ + } + + .dropdown-toggle.btn.btn-primary .caret { + color: ${theme.colors.grayscale.light5}; + } + + .background--transparent { + background-color: transparent; + } + + .background--white { + background-color: ${theme.colors.grayscale.light5}; + } + } + &.dashboard--editing { + .grid-row:after, + .dashboard-component-tabs > .hover-menu:hover + div:after { + border: 1px dashed transparent; + content: ''; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 1; + pointer-events: none; + } + + .resizable-container { + & .dashboard-component-chart-holder { + .dashboard-chart { + .chart-container { + cursor: move; + opacity: 0.2; + } + + .slice_container { + /* disable chart interactions in edit mode */ + pointer-events: none; + } + } + + &:hover .dashboard-chart .chart-container { + opacity: 0.7; + } + } + + &:hover, + &.resizable-container--resizing:hover { + & > .dashboard-component-chart-holder:after { + border: 1px dashed ${theme.colors.primary.base}; + } + } + } + + .resizable-container--resizing:hover > .grid-row:after, + .hover-menu:hover + .grid-row:after, + .dashboard-component-tabs > .hover-menu:hover + div:after { + border: 1px dashed ${theme.colors.primary.base}; + z-index: 2; + } + + .grid-row:after, + .dashboard-component-tabs > .hover-menu + div:after { + border: 1px dashed ${theme.colors.grayscale.light2}; + } + + /* provide hit area in case row contents is edge to edge */ + .dashboard-component-tabs-content { + .dragdroppable-row { + padding-top: ${theme.gridUnit * 4}px; + } + + & > div:not(:last-child):not(.empty-droptarget) { + margin-bottom: ${theme.gridUnit * 4}px; + } + } + + .dashboard-component-chart-holder { + &:after { + content: ''; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 1; + pointer-events: none; + border: 1px solid transparent; + } + + &:hover:after { + border: 1px dashed ${theme.colors.primary.base}; + z-index: 2; + } + } + + .contract-trigger:before { + display: none; + } + } + + & .dashboard-component-tabs-content { + & > div:not(:last-child):not(.empty-droptarget) { + margin-bottom: ${theme.gridUnit * 4}px; + } + + & > .empty-droptarget { + position: absolute; + width: 100%; + } + + & > .empty-droptarget:first-child { + height: ${theme.gridUnit * 4}px; + top: -2px; + z-index: 10; + } + + & > .empty-droptarget:last-child { + height: ${theme.gridUnit * 3}px; + bottom: 0; + } + } + + .empty-droptarget:first-child .drop-indicator--bottom { + top: ${theme.gridUnit * 6}px; + } + `} +`; + const StyledDashboardContent = styled.div<{ - dashboardFiltersOpen: boolean; editMode: boolean; - nativeFiltersEnabled: boolean; + marginLeft: number; }>` - display: flex; - flex-direction: row; - flex-wrap: nowrap; - height: auto; - flex: 1; - - .grid-container .dashboard-component-tabs { - box-shadow: none; - padding-left: 0; - } - - .grid-container { - /* without this, the grid will not get smaller upon toggling the builder panel on */ - width: 0; + ${({ theme, editMode, marginLeft }) => css` + display: flex; + flex-direction: row; + flex-wrap: nowrap; + height: auto; flex: 1; - position: relative; - margin-top: ${({ theme }) => theme.gridUnit * 6}px; - margin-right: ${({ theme }) => theme.gridUnit * 8}px; - margin-bottom: ${({ theme }) => theme.gridUnit * 6}px; - margin-left: ${({ - theme, - dashboardFiltersOpen, - editMode, - nativeFiltersEnabled, - }) => { - if (!dashboardFiltersOpen && !editMode && nativeFiltersEnabled) { - return 0; - } - return theme.gridUnit * 8; - }}px; - ${({ editMode, theme }) => - editMode && + .grid-container .dashboard-component-tabs { + box-shadow: none; + padding-left: 0; + } + + .grid-container { + /* without this, the grid will not get smaller upon toggling the builder panel on */ + width: 0; + flex: 1; + position: relative; + margin-top: ${theme.gridUnit * 6}px; + margin-right: ${theme.gridUnit * 8}px; + margin-bottom: ${theme.gridUnit * 6}px; + margin-left: ${marginLeft}px; + + ${editMode && ` max-width: calc(100% - ${ BUILDER_SIDEPANEL_WIDTH + theme.gridUnit * 16 }px); `} - } - - .dashboard-builder-sidepane { - width: ${BUILDER_SIDEPANEL_WIDTH}px; - z-index: 1; - } - - .dashboard-component-chart-holder { - // transitionable traits to show filter relevance - transition: opacity ${({ theme }) => theme.transitionTiming}s, - border-color ${({ theme }) => theme.transitionTiming}s, - box-shadow ${({ theme }) => theme.transitionTiming}s; - border: 0 solid transparent; - } + + /* this is the ParentSize wrapper */ + & > div:first-child { + height: inherit !important; + } + } + + .dashboard-builder-sidepane { + width: ${BUILDER_SIDEPANEL_WIDTH}px; + z-index: 1; + } + + .dashboard-component-chart-holder { + width: 100%; + height: 100%; + background-color: ${theme.colors.grayscale.light5}; + position: relative; + padding: ${theme.gridUnit * 4}px; + overflow-y: visible; + + // transitionable traits to show filter relevance + transition: opacity ${theme.transitionTiming}s ease-in-out, + border-color ${theme.transitionTiming}s ease-in-out, + box-shadow ${theme.transitionTiming}s ease-in-out; + + &.fade-in { + border-radius: ${theme.borderRadius}px; + box-shadow: inset 0 0 0 2px ${theme.colors.primary.base}, + 0 0 0 3px + ${addAlpha( + theme.colors.primary.base, + parseFloat(theme.opacity.light) / 100, + )}; + } + + &.fade-out { + border-radius: ${theme.borderRadius}px; + box-shadow: none; + } + + & .missing-chart-container { + display: flex; + flex-direction: column; + align-items: center; + overflow-y: auto; + justify-content: center; + + .missing-chart-body { + font-size: ${theme.typography.sizes.s}px; + position: relative; + display: flex; + } + } + } + `} `; const DashboardBuilder: FC<DashboardBuilderProps> = () => { const dispatch = useDispatch(); const uiConfig = useUiConfig(); + const theme = useTheme(); + const dashboardId = useSelector<RootState, string>( + ({ dashboardInfo }) => `${dashboardInfo.id}`, + ); const dashboardLayout = useSelector<RootState, DashboardLayout>( state => state.dashboardLayout.present, ); @@ -228,12 +439,20 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => { const canEdit = useSelector<RootState, boolean>( ({ dashboardInfo }) => dashboardInfo.dash_edit_perm, ); - const directPathToChild = useSelector<RootState, string[]>( - state => state.dashboardState.directPathToChild, + const dashboardIsSaving = useSelector<RootState, boolean>( + ({ dashboardState }) => dashboardState.dashboardIsSaving, ); + const nativeFilters = useSelector((state: RootState) => state.nativeFilters); + const focusedFilterId = nativeFilters?.focusedFilterId; const fullSizeChartId = useSelector<RootState, number | null>( state => state.dashboardState.fullSizeChartId, ); + const filterBarOrientation = useSelector<RootState, FilterBarOrientation>( + ({ dashboardInfo }) => + isFeatureEnabled(FeatureFlag.HORIZONTAL_FILTER_BAR) + ? dashboardInfo.filterBarOrientation + : FilterBarOrientation.VERTICAL, + ); const handleChangeTab = useCallback( ({ pathToTabIndex }: { pathToTabIndex: string[] }) => { @@ -270,13 +489,14 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => { uiConfig.hideTitle || standaloneMode === DashboardStandaloneMode.HIDE_NAV_AND_TITLE || isReport; + const [barTopOffset, setBarTopOffset] = useState(0); useEffect(() => { setBarTopOffset(headerRef.current?.getBoundingClientRect()?.height || 0); let observer: ResizeObserver; - if (typeof global.ResizeObserver !== 'undefined' && headerRef.current) { + if (global.hasOwnProperty('ResizeObserver') && headerRef.current) { observer = new ResizeObserver(entries => { setBarTopOffset( current => entries?.[0]?.contentRect?.height || current, @@ -298,10 +518,6 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => { nativeFiltersEnabled, } = useNativeFilters(); - const filterBarWidth = dashboardFiltersOpen - ? OPEN_FILTER_BAR_WIDTH - : CLOSED_FILTER_BAR_WIDTH; - const [containerRef, isSticky] = useElementOnScreen<HTMLDivElement>({ threshold: [1], }); @@ -309,6 +525,7 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => { const filterSetEnabled = isFeatureEnabled( FeatureFlag.DASHBOARD_NATIVE_FILTERS_SET, ); + const showFilterBar = nativeFiltersEnabled && !editMode; const offset = FILTER_BAR_HEADER_HEIGHT + @@ -321,9 +538,19 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => { const draggableStyle = useMemo( () => ({ marginLeft: - dashboardFiltersOpen || editMode || !nativeFiltersEnabled ? 0 : -32, + dashboardFiltersOpen || + editMode || + !nativeFiltersEnabled || + filterBarOrientation === FilterBarOrientation.HORIZONTAL + ? 0 + : -32, }), - [dashboardFiltersOpen, editMode, nativeFiltersEnabled], + [ + dashboardFiltersOpen, + editMode, + filterBarOrientation, + nativeFiltersEnabled, + ], ); // If a new tab was added, update the directPathToChild to reflect it @@ -351,6 +578,13 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => { ({ dropIndicatorProps }: { dropIndicatorProps: JsonObject }) => ( <div> {!hideDashboardHeader && <DashboardHeader />} + {showFilterBar && + filterBarOrientation === FilterBarOrientation.HORIZONTAL && ( + <FilterBar + focusedFilterId={focusedFilterId} + orientation={FilterBarOrientation.HORIZONTAL} + /> + )} {dropIndicatorProps && <div {...dropIndicatorProps} />} {!isReport && topLevelTabs && !uiConfig.hideNav && ( <WithPopoverMenu @@ -358,7 +592,7 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => { menuItems={[ <IconButton icon={<Icons.FallOutlined iconSize="xl" />} - label="Collapse tab content" + label={t('Collapse tab content')} onClick={handleDeleteTopLevelTabs} />, ]} @@ -379,6 +613,9 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => { </div> ), [ + focusedFilterId, + nativeFiltersEnabled, + filterBarOrientation, editMode, handleChangeTab, handleDeleteTopLevelTabs, @@ -389,23 +626,56 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => { ], ); + const dashboardContentMarginLeft = + !dashboardFiltersOpen && + !editMode && + nativeFiltersEnabled && + filterBarOrientation !== FilterBarOrientation.HORIZONTAL + ? 0 + : theme.gridUnit * 8; + return ( <StyledDiv> - {nativeFiltersEnabled && !editMode && ( - <FiltersPanel> - <StickyPanel ref={containerRef} width={filterBarWidth}> - <ErrorBoundary> - <FilterBar - filtersOpen={dashboardFiltersOpen} - toggleFiltersBar={toggleDashboardFiltersOpen} - directPathToChild={directPathToChild} - width={filterBarWidth} - height={filterBarHeight} - offset={filterBarOffset} - /> - </ErrorBoundary> - </StickyPanel> - </FiltersPanel> + {showFilterBar && filterBarOrientation === FilterBarOrientation.VERTICAL && ( + <> + <ResizableSidebar + id={`dashboard:${dashboardId}`} + enable={dashboardFiltersOpen} + minWidth={OPEN_FILTER_BAR_WIDTH} + maxWidth={OPEN_FILTER_BAR_MAX_WIDTH} + initialWidth={OPEN_FILTER_BAR_WIDTH} + > + {adjustedWidth => { + const filterBarWidth = dashboardFiltersOpen + ? adjustedWidth + : CLOSED_FILTER_BAR_WIDTH; + return ( + <FiltersPanel + width={filterBarWidth} + data-test="dashboard-filters-panel" + > + <StickyPanel ref={containerRef} width={filterBarWidth}> + <ErrorBoundary> + {!isReport && ( + <FilterBar + focusedFilterId={focusedFilterId} + orientation={FilterBarOrientation.VERTICAL} + verticalConfig={{ + filtersOpen: dashboardFiltersOpen, + toggleFiltersBar: toggleDashboardFiltersOpen, + width: filterBarWidth, + height: filterBarHeight, + offset: filterBarOffset, + }} + /> + )} + </ErrorBoundary> + </StickyPanel> + </FiltersPanel> + ); + }} + </ResizableSidebar> + </> )} <StyledHeader ref={headerRef}> {/* @ts-ignore */} @@ -449,30 +719,33 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => { image="dashboard.svg" /> )} - <div - data-test="dashboard-content" + <DashboardContentWrapper + data-test="dashboard-content-wrapper" className={cx('dashboard', editMode && 'dashboard--editing')} > <StyledDashboardContent className="dashboard-content" - dashboardFiltersOpen={dashboardFiltersOpen} editMode={editMode} - nativeFiltersEnabled={nativeFiltersEnabled} + marginLeft={dashboardContentMarginLeft} > {showDashboard ? ( <DashboardContainer topLevelTabs={topLevelTabs} /> ) : ( <Loading /> )} - {editMode && ( - <BuilderComponentPane - isStandalone={!!standaloneMode} - topOffset={barTopOffset} - /> - )} + {editMode && <BuilderComponentPane topOffset={barTopOffset} />} </StyledDashboardContent> - </div> + </DashboardContentWrapper> </StyledContent> + {dashboardIsSaving && ( + <Loading + css={css` + && { + position: fixed; + } + `} + /> + )} </StyledDiv> ); }; diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardContainer.tsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardContainer.tsx index c763f07267f55..386d96266a099 100644 --- a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardContainer.tsx +++ b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardContainer.tsx @@ -18,20 +18,23 @@ */ // ParentSize uses resize observer so the dashboard will update size // when its container size changes, due to e.g., builder side panel opening -import React, { FC, useEffect, useMemo } from 'react'; +import React, { FC, useCallback, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { FeatureFlag, Filter, Filters, + getCategoricalSchemeRegistry, isFeatureEnabled, + SupersetClient, } from '@superset-ui/core'; -import { ParentSize } from '@vx/responsive'; +import { ParentSize } from '@visx/responsive'; import pick from 'lodash/pick'; import Tabs from 'src/components/Tabs'; import DashboardGrid from 'src/dashboard/containers/DashboardGrid'; import { ChartsState, + DashboardInfo, DashboardLayout, LayoutItem, RootState, @@ -43,9 +46,13 @@ import { import { getChartIdsInFilterScope } from 'src/dashboard/util/getChartIdsInFilterScope'; import findTabIndexByComponentId from 'src/dashboard/util/findTabIndexByComponentId'; import { setInScopeStatusOfFilters } from 'src/dashboard/actions/nativeFilters'; -import { getRootLevelTabIndex, getRootLevelTabsComponent } from './utils'; -import { findTabsWithChartsInScope } from '../nativeFilters/utils'; +import { dashboardInfoChanged } from 'src/dashboard/actions/dashboardInfo'; +import { setColorScheme } from 'src/dashboard/actions/dashboardState'; +import { useComponentDidUpdate } from 'src/hooks/useComponentDidUpdate/useComponentDidUpdate'; +import jsonStringify from 'json-stringify-pretty-compact'; import { NATIVE_FILTER_DIVIDER_PREFIX } from '../nativeFilters/FiltersConfigModal/utils'; +import { findTabsWithChartsInScope } from '../nativeFilters/utils'; +import { getRootLevelTabIndex, getRootLevelTabsComponent } from './utils'; type DashboardContainerProps = { topLevelTabs?: LayoutItem; @@ -73,6 +80,9 @@ const DashboardContainer: FC<DashboardContainerProps> = ({ topLevelTabs }) => { const dashboardLayout = useSelector<RootState, DashboardLayout>( state => state.dashboardLayout.present, ); + const dashboardInfo = useSelector<RootState, DashboardInfo>( + state => state.dashboardInfo, + ); const directPathToChild = useSelector<RootState, string[]>( state => state.dashboardState.directPathToChild, ); @@ -122,10 +132,88 @@ const DashboardContainer: FC<DashboardContainerProps> = ({ topLevelTabs }) => { dispatch(setInScopeStatusOfFilters(scopes)); }, [nativeFilterScopes, dashboardLayout, dispatch]); + const verifyUpdateColorScheme = useCallback(() => { + const currentMetadata = dashboardInfo.metadata; + if (currentMetadata?.color_scheme) { + const metadata = { ...currentMetadata }; + const colorScheme = metadata?.color_scheme; + const colorSchemeDomain = metadata?.color_scheme_domain || []; + const categoricalSchemes = getCategoricalSchemeRegistry(); + const registryColorScheme = + categoricalSchemes.get(colorScheme, true) || undefined; + const registryColorSchemeDomain = registryColorScheme?.colors || []; + const defaultColorScheme = categoricalSchemes.defaultKey; + const colorSchemeExists = !!registryColorScheme; + + const updateDashboardData = () => { + SupersetClient.put({ + endpoint: `/api/v1/dashboard/${dashboardInfo.id}`, + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + json_metadata: jsonStringify(metadata), + }), + }).catch(e => console.log(e)); + }; + const updateColorScheme = (scheme: string) => { + dispatch(setColorScheme(scheme)); + }; + const updateDashboard = () => { + dispatch( + dashboardInfoChanged({ + metadata, + }), + ); + updateDashboardData(); + }; + // selected color scheme does not exist anymore + // must fallback to the available default one + if (!colorSchemeExists) { + const updatedScheme = + defaultColorScheme?.toString() || 'supersetColors'; + metadata.color_scheme = updatedScheme; + metadata.color_scheme_domain = + categoricalSchemes.get(defaultColorScheme)?.colors || []; + + // reset shared_label_colors + // TODO: Requires regenerating the shared_label_colors after + // fixing a bug which affects their generation on dashboards with tabs + metadata.shared_label_colors = {}; + + updateColorScheme(updatedScheme); + updateDashboard(); + } else { + // if this dashboard does not have a color_scheme_domain saved + // must create one and store it for the first time + if (colorSchemeExists && !colorSchemeDomain.length) { + metadata.color_scheme_domain = registryColorSchemeDomain; + updateDashboard(); + } + // if the color_scheme_domain is not the same as the registry domain + // must update the existing color_scheme_domain + if ( + colorSchemeExists && + colorSchemeDomain.length && + registryColorSchemeDomain.toString() !== colorSchemeDomain.toString() + ) { + metadata.color_scheme_domain = registryColorSchemeDomain; + + // reset shared_label_colors + // TODO: Requires regenerating the shared_label_colors after + // fixing a bug which affects their generation on dashboards with tabs + metadata.shared_label_colors = {}; + + updateColorScheme(colorScheme); + updateDashboard(); + } + } + } + }, [charts]); + + useComponentDidUpdate(verifyUpdateColorScheme); + const childIds: string[] = topLevelTabs ? topLevelTabs.children : [DASHBOARD_GRID_ID]; - const min = Math.min(tabIndex, childIds.length - 1); const activeKey = min === 0 ? DASHBOARD_GRID_ID : min.toString(); diff --git a/superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx b/superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx index a2c44f490243f..8d7702edd4d3d 100644 --- a/superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx +++ b/superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx @@ -22,7 +22,7 @@ import { styled, SupersetApiError, t, - getUiOverrideRegistry, + getExtensionsRegistry, } from '@superset-ui/core'; import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; import Modal from 'src/components/Modal'; @@ -33,7 +33,7 @@ import { useToasts } from 'src/components/MessageToasts/withToasts'; import { FormItem } from 'src/components/Form'; import { EmbeddedDashboard } from '../types'; -const uiOverrideRegistry = getUiOverrideRegistry(); +const extensionsRegistry = getExtensionsRegistry(); type Props = { dashboardId: string; @@ -148,30 +148,37 @@ export const DashboardEmbedControls = ({ dashboardId, onHide }: Props) => { return <Loading />; } - const docsDescription = uiOverrideRegistry.get( + const DocsConfigDetails = extensionsRegistry.get( + 'embedded.documentation.configuration_details', + ); + const docsDescription = extensionsRegistry.get( 'embedded.documentation.description', ); const docsUrl = - uiOverrideRegistry.get('embedded.documentation.url') ?? + extensionsRegistry.get('embedded.documentation.url') ?? 'https://www.npmjs.com/package/@superset-ui/embedded-sdk'; return ( <> - <p> - {embedded ? ( - <> + {embedded ? ( + DocsConfigDetails ? ( + <DocsConfigDetails embeddedId={embedded.uuid} /> + ) : ( + <p> {t( 'This dashboard is ready to embed. In your application, pass the following id to the SDK:', )} <br /> <code>{embedded.uuid}</code> - </> - ) : ( - t( + </p> + ) + ) : ( + <p> + {t( 'Configure this dashboard to embed it into an external web application.', - ) - )} - </p> + )} + </p> + )} <p> {t('For further instructions, consult the')}{' '} <a href={docsUrl} target="_blank" rel="noreferrer"> @@ -180,7 +187,7 @@ export const DashboardEmbedControls = ({ dashboardId, onHide }: Props) => { : t('Superset Embedded SDK documentation.')} </a> </p> - <h3>Settings</h3> + <h3>{t('Settings')}</h3> <FormItem> <label htmlFor="allowed-domains"> {t('Allowed Domains (comma separated)')}{' '} diff --git a/superset-frontend/src/dashboard/components/DashboardGrid.jsx b/superset-frontend/src/dashboard/components/DashboardGrid.jsx index 72f86fff3210c..601dbac4a4cdc 100644 --- a/superset-frontend/src/dashboard/components/DashboardGrid.jsx +++ b/superset-frontend/src/dashboard/components/DashboardGrid.jsx @@ -18,7 +18,7 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import { styled, t } from '@superset-ui/core'; +import { addAlpha, css, styled, t } from '@superset-ui/core'; import { EmptyStateBig } from 'src/components/EmptyState'; import { componentShape } from '../util/propShapes'; import DashboardComponent from '../containers/DashboardComponent'; @@ -28,8 +28,8 @@ import { TAB_TYPE } from '../util/componentTypes'; const propTypes = { depth: PropTypes.number.isRequired, - editMode: PropTypes.bool.isRequired, - gridComponent: componentShape.isRequired, + editMode: PropTypes.bool, + gridComponent: componentShape, handleComponentDrop: PropTypes.func.isRequired, isComponentVisible: PropTypes.bool.isRequired, resizeComponent: PropTypes.func.isRequired, @@ -58,16 +58,62 @@ const DashboardEmptyStateContainer = styled.div` right: 0; `; +const GridContent = styled.div` + ${({ theme }) => css` + display: flex; + flex-direction: column; + + /* gutters between rows */ + & > div:not(:last-child):not(.empty-droptarget) { + margin-bottom: ${theme.gridUnit * 4}px; + } + + & > .empty-droptarget { + width: 100%; + height: 100%; + } + + & > .empty-droptarget:first-child { + height: ${theme.gridUnit * 12}px; + margin-top: ${theme.gridUnit * -6}px; + margin-bottom: ${theme.gridUnit * -6}px; + } + + & > .empty-droptarget:only-child { + height: 80vh; + } + `} +`; + +const GridColumnGuide = styled.div` + ${({ theme }) => css` + // /* Editing guides */ + &.grid-column-guide { + position: absolute; + top: 0; + min-height: 100%; + background-color: ${addAlpha( + theme.colors.primary.base, + parseFloat(theme.opacity.light) / 100, + )}; + pointer-events: none; + box-shadow: inset 0 0 0 1px + ${addAlpha( + theme.colors.primary.base, + parseFloat(theme.opacity.mediumHeavy) / 100, + )}; + } + `}; +`; + class DashboardGrid extends React.PureComponent { constructor(props) { super(props); this.state = { isResizing: false, - rowGuideTop: null, }; this.handleResizeStart = this.handleResizeStart.bind(this); - this.handleResize = this.handleResize.bind(this); this.handleResizeStop = this.handleResizeStop.bind(this); this.handleTopDropTargetDrop = this.handleTopDropTargetDrop.bind(this); this.getRowGuidePosition = this.getRowGuidePosition.bind(this); @@ -90,30 +136,17 @@ class DashboardGrid extends React.PureComponent { this.grid = ref; } - handleResizeStart({ ref, direction }) { - let rowGuideTop = null; - if (direction === 'bottom' || direction === 'bottomRight') { - rowGuideTop = this.getRowGuidePosition(ref); - } - + handleResizeStart() { this.setState(() => ({ isResizing: true, - rowGuideTop, })); } - handleResize({ ref, direction }) { - if (direction === 'bottom' || direction === 'bottomRight') { - this.setState(() => ({ rowGuideTop: this.getRowGuidePosition(ref) })); - } - } - handleResizeStop({ id, widthMultiple: width, heightMultiple: height }) { this.props.resizeComponent({ id, width, height }); this.setState(() => ({ isResizing: false, - rowGuideTop: null, })); } @@ -150,7 +183,7 @@ class DashboardGrid extends React.PureComponent { (width + GRID_GUTTER_SIZE) / GRID_COLUMN_COUNT; const columnWidth = columnPlusGutterWidth - GRID_GUTTER_SIZE; - const { isResizing, rowGuideTop } = this.state; + const { isResizing } = this.state; const shouldDisplayEmptyState = gridComponent?.children?.length === 0; const shouldDisplayTopLevelTabEmptyState = @@ -227,7 +260,7 @@ class DashboardGrid extends React.PureComponent { </DashboardEmptyStateContainer> )} <div className="dashboard-grid" ref={this.setGridRef}> - <div className="grid-content" data-test="grid-content"> + <GridContent className="grid-content" data-test="grid-content"> {/* make the area above components droppable */} {editMode && ( <DragDroppable @@ -278,7 +311,7 @@ class DashboardGrid extends React.PureComponent { Array(GRID_COLUMN_COUNT) .fill(null) .map((_, i) => ( - <div + <GridColumnGuide key={`grid-column-${i}`} className="grid-column-guide" style={{ @@ -287,16 +320,7 @@ class DashboardGrid extends React.PureComponent { }} /> ))} - {isResizing && rowGuideTop && ( - <div - className="grid-row-guide" - style={{ - top: rowGuideTop, - width, - }} - /> - )} - </div> + </GridContent> </div> </> ); diff --git a/superset-frontend/src/dashboard/components/DashboardGrid.test.jsx b/superset-frontend/src/dashboard/components/DashboardGrid.test.jsx index 4fd1704b230ec..c954ecff7be6e 100644 --- a/superset-frontend/src/dashboard/components/DashboardGrid.test.jsx +++ b/superset-frontend/src/dashboard/components/DashboardGrid.test.jsx @@ -76,13 +76,6 @@ describe('DashboardGrid', () => { expect(wrapper.find('.grid-column-guide')).toHaveLength(GRID_COLUMN_COUNT); }); - it('should render a grid row guide when resizing', () => { - const wrapper = setup(); - expect(wrapper.find('.grid-row-guide')).not.toExist(); - wrapper.setState({ isResizing: true, rowGuideTop: 10 }); - expect(wrapper.find('.grid-row-guide')).toExist(); - }); - it('should call resizeComponent when a child DashboardComponent calls resizeStop', () => { const resizeComponent = sinon.spy(); const args = { id: 'id', widthMultiple: 1, heightMultiple: 3 }; diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/DetailsPanel.test.tsx b/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/DetailsPanel.test.tsx index 12efe2c3e5d67..8d2b121ff6b0d 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/DetailsPanel.test.tsx +++ b/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/DetailsPanel.test.tsx @@ -102,13 +102,11 @@ test('Should render "appliedCrossFilterIndicators"', () => { userEvent.click(screen.getByTestId('details-panel-content')); expect(screen.getByText('Applied Cross Filters (1)')).toBeInTheDocument(); expect( - screen.getByRole('button', { name: 'search Clinical Stage' }), + screen.getByRole('button', { name: 'Clinical Stage' }), ).toBeInTheDocument(); expect(props.onHighlightFilterSource).toBeCalledTimes(0); - userEvent.click( - screen.getByRole('button', { name: 'search Clinical Stage' }), - ); + userEvent.click(screen.getByRole('button', { name: 'Clinical Stage' })); expect(props.onHighlightFilterSource).toBeCalledTimes(1); expect(props.onHighlightFilterSource).toBeCalledWith([ 'ROOT_ID', @@ -135,12 +133,10 @@ test('Should render "appliedIndicators"', () => { userEvent.click(screen.getByTestId('details-panel-content')); expect(screen.getByText('Applied Filters (1)')).toBeInTheDocument(); - expect( - screen.getByRole('button', { name: 'search Country' }), - ).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Country' })).toBeInTheDocument(); expect(props.onHighlightFilterSource).toBeCalledTimes(0); - userEvent.click(screen.getByRole('button', { name: 'search Country' })); + userEvent.click(screen.getByRole('button', { name: 'Country' })); expect(props.onHighlightFilterSource).toBeCalledTimes(1); expect(props.onHighlightFilterSource).toBeCalledWith([ 'ROOT_ID', @@ -168,12 +164,12 @@ test('Should render "incompatibleIndicators"', () => { userEvent.click(screen.getByTestId('details-panel-content')); expect(screen.getByText('Incompatible Filters (1)')).toBeInTheDocument(); expect( - screen.getByRole('button', { name: 'search Vaccine Approach Copy' }), + screen.getByRole('button', { name: 'Vaccine Approach Copy' }), ).toBeInTheDocument(); expect(props.onHighlightFilterSource).toBeCalledTimes(0); userEvent.click( - screen.getByRole('button', { name: 'search Vaccine Approach Copy' }), + screen.getByRole('button', { name: 'Vaccine Approach Copy' }), ); expect(props.onHighlightFilterSource).toBeCalledTimes(1); expect(props.onHighlightFilterSource).toBeCalledWith([ @@ -202,13 +198,11 @@ test('Should render "unsetIndicators"', () => { userEvent.click(screen.getByTestId('details-panel-content')); expect(screen.getByText('Unset Filters (1)')).toBeInTheDocument(); expect( - screen.getByRole('button', { name: 'search Vaccine Approach' }), + screen.getByRole('button', { name: 'Vaccine Approach' }), ).toBeInTheDocument(); expect(props.onHighlightFilterSource).toBeCalledTimes(0); - userEvent.click( - screen.getByRole('button', { name: 'search Vaccine Approach' }), - ); + userEvent.click(screen.getByRole('button', { name: 'Vaccine Approach' })); expect(props.onHighlightFilterSource).toBeCalledTimes(1); expect(props.onHighlightFilterSource).toBeCalledWith([ 'ROOT_ID', diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx b/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx index b5dfb0150d59e..3531ab1be9b25 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx +++ b/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx @@ -20,11 +20,6 @@ import React, { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { Global, css } from '@emotion/react'; import { t, useTheme } from '@superset-ui/core'; -import { - MinusCircleFilled, - CheckCircleFilled, - ExclamationCircleFilled, -} from '@ant-design/icons'; import Popover from 'src/components/Popover'; import Collapse from 'src/components/Collapse'; import Icons from 'src/components/Icons'; @@ -38,6 +33,12 @@ import { Indicator } from 'src/dashboard/components/FiltersBadge/selectors'; import FilterIndicator from 'src/dashboard/components/FiltersBadge/FilterIndicator'; import { RootState } from 'src/dashboard/types'; +const iconReset = css` + span { + line-height: 0; + } +`; + export interface DetailsPanelProps { appliedCrossFilterIndicators: Indicator[]; appliedIndicators: Indicator[]; @@ -206,7 +207,7 @@ const DetailsPanelPopover = ({ key="applied" header={ <Title bold color={theme.colors.success.base}> - <CheckCircleFilled />{' '} + <Icons.CheckCircleFilled css={iconReset} iconSize="m" />{' '} {t('Applied Filters (%d)', appliedIndicators.length)} } @@ -227,7 +228,7 @@ const DetailsPanelPopover = ({ key="incompatible" header={ - <ExclamationCircleFilled />{' '} + <Icons.ExclamationCircleFilled css={iconReset} iconSize="m" />{' '} {t( 'Incompatible Filters (%d)', incompatibleIndicators.length, @@ -251,7 +252,7 @@ const DetailsPanelPopover = ({ key="unset" header={ <Title bold color={theme.colors.grayscale.light1}> - <MinusCircleFilled />{' '} + <Icons.MinusCircleFilled css={iconReset} iconSize="m" />{' '} {t('Unset Filters (%d)', unsetIndicators.length)} } diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/FilterIndicator.test.tsx b/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/FilterIndicator.test.tsx index c93abaa903620..fdded804b8ba0 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/FilterIndicator.test.tsx +++ b/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/FilterIndicator.test.tsx @@ -43,9 +43,9 @@ test('Should render', () => { render(); expect( - screen.getByRole('button', { name: 'search Vaccine Approach' }), + screen.getByRole('button', { name: 'Vaccine Approach' }), ).toBeInTheDocument(); - expect(screen.getByRole('img', { name: 'search' })).toBeInTheDocument(); + expect(screen.getByRole('img')).toBeInTheDocument(); }); test('Should call "onClick"', () => { @@ -53,9 +53,7 @@ test('Should call "onClick"', () => { render(); expect(props.onClick).toBeCalledTimes(0); - userEvent.click( - screen.getByRole('button', { name: 'search Vaccine Approach' }), - ); + userEvent.click(screen.getByRole('button', { name: 'Vaccine Approach' })); expect(props.onClick).toBeCalledTimes(1); }); @@ -66,7 +64,7 @@ test('Should render "value"', () => { expect( screen.getByRole('button', { - name: 'search Vaccine Approach: any, string', + name: 'Vaccine Approach: any, string', }), ).toBeInTheDocument(); }); @@ -77,9 +75,7 @@ test('Should render with default props', () => { render(); expect( - screen.getByRole('button', { name: 'search Vaccine Approach' }), + screen.getByRole('button', { name: 'Vaccine Approach' }), ).toBeInTheDocument(); - userEvent.click( - screen.getByRole('button', { name: 'search Vaccine Approach' }), - ); + userEvent.click(screen.getByRole('button', { name: 'Vaccine Approach' })); }); diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/index.tsx b/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/index.tsx index e94bca37751db..e7675a3ef0e3d 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/index.tsx +++ b/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/index.tsx @@ -17,8 +17,9 @@ * under the License. */ -import { SearchOutlined } from '@ant-design/icons'; import React, { FC } from 'react'; +import { css } from '@superset-ui/core'; +import Icons from 'src/components/Icons'; import { getFilterValueForDisplay } from 'src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils'; import { FilterIndicatorText, @@ -46,7 +47,14 @@ const FilterIndicator: FC = ({ onClick([...path, `LABEL-${column}`])}> <ItemIcon> - <SearchOutlined /> + <Icons.SearchOutlined + iconSize="m" + css={css` + span { + vertical-align: 0; + } + `} + /> </ItemIcon> {name} {resultValue ? ': ' : ''} diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/index.tsx b/superset-frontend/src/dashboard/components/FiltersBadge/index.tsx index 316534823772d..fd21d07fc2b9b 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/index.tsx +++ b/superset-frontend/src/dashboard/components/FiltersBadge/index.tsx @@ -23,6 +23,7 @@ import cx from 'classnames'; import { DataMaskStateWithId, Filters } from '@superset-ui/core'; import Icons from 'src/components/Icons'; import { usePrevious } from 'src/hooks/usePrevious'; +import { setFocusedNativeFilter } from 'src/dashboard/actions/nativeFilters'; import DetailsPanelPopover from './DetailsPanel'; import { Pill } from './Styles'; import { @@ -31,7 +32,6 @@ import { selectIndicatorsForChart, selectNativeIndicatorsForChart, } from './selectors'; -import { setDirectPathToChild } from '../../actions/dashboardState'; import { ChartsState, DashboardInfo, @@ -87,7 +87,7 @@ export const FiltersBadge = ({ chartId }: FiltersBadgeProps) => { const onHighlightFilterSource = useCallback( (path: string[]) => { - dispatch(setDirectPathToChild(path)); + dispatch(setFocusedNativeFilter(path[0])); }, [dispatch], ); diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts b/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts index 6d9ab6fe9c9d6..c0916b99607b0 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts +++ b/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts @@ -25,10 +25,10 @@ import { FilterState, isFeatureEnabled, NativeFilterType, + NO_TIME_RANGE, } from '@superset-ui/core'; -import { NO_TIME_RANGE, TIME_FILTER_MAP } from 'src/explore/constants'; +import { TIME_FILTER_MAP } from 'src/explore/constants'; import { getChartIdsInFilterBoxScope } from 'src/dashboard/util/activeDashboardFilters'; -import { CHART_TYPE } from 'src/dashboard/util/componentTypes'; import { ChartConfiguration } from 'src/dashboard/reducers/types'; import { Layout } from 'src/dashboard/types'; import { areObjectsEqual } from 'src/reduxUtils'; @@ -293,18 +293,9 @@ export const selectNativeIndicatorsForChart = ( let crossFilterIndicators: any = []; if (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)) { const dashboardLayoutValues = Object.values(dashboardLayout); - const chartLayoutItem = dashboardLayoutValues.find( - layoutItem => layoutItem?.meta?.chartId === chartId, - ); crossFilterIndicators = Object.values(chartConfiguration) - .filter( - chartConfig => - !chartConfig.crossFilters.scope.excluded.includes(chartId) && - chartConfig.crossFilters.scope.rootPath.some( - elementId => - chartLayoutItem?.type === CHART_TYPE && - chartLayoutItem?.parents?.includes(elementId), - ), + .filter(chartConfig => + chartConfig.crossFilters?.chartsInScope?.includes(chartId), ) .map(chartConfig => { const filterState = dataMask[chartConfig.id]?.filterState; diff --git a/superset-frontend/src/dashboard/components/Header/Header.test.tsx b/superset-frontend/src/dashboard/components/Header/Header.test.tsx index 214a0d0a5322a..79ae0a48652b6 100644 --- a/superset-frontend/src/dashboard/components/Header/Header.test.tsx +++ b/superset-frontend/src/dashboard/components/Header/Header.test.tsx @@ -20,6 +20,8 @@ import React from 'react'; import { render, screen, fireEvent } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import fetchMock from 'fetch-mock'; +import { getExtensionsRegistry } from '@superset-ui/core'; +import setupExtensions from 'src/setup/setupExtensions'; import { HeaderProps } from './types'; import Header from '.'; @@ -35,7 +37,12 @@ const createProps = () => ({ userId: '1', metadata: {}, common: { - conf: {}, + conf: { + DASHBOARD_AUTO_REFRESH_INTERVALS: [ + [0, "Don't refresh"], + [10, '10 seconds'], + ], + }, }, }, user: { @@ -75,7 +82,8 @@ const createProps = () => ({ setEditMode: jest.fn(), showBuilderPane: jest.fn(), updateCss: jest.fn(), - setColorSchemeAndUnsavedChanges: jest.fn(), + setColorScheme: jest.fn(), + setUnsavedChanges: jest.fn(), logEvent: jest.fn(), setRefreshFrequency: jest.fn(), hasUnsavedChanges: false, @@ -328,6 +336,20 @@ test('should refresh the charts', async () => { expect(mockedProps.onRefresh).toHaveBeenCalledTimes(1); }); +test('should render an extension component if one is supplied', () => { + const extensionsRegistry = getExtensionsRegistry(); + extensionsRegistry.set('dashboard.nav.right', () => ( + <>dashboard.nav.right extension component</> + )); + setupExtensions(); + + const mockedProps = createProps(); + setup(mockedProps); + expect( + screen.getByText('dashboard.nav.right extension component'), + ).toBeInTheDocument(); +}); + test('should show datahub link', async () => { const mockedProps = createProps(); setup(mockedProps); diff --git a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/HeaderActionsDropdown.test.tsx b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/HeaderActionsDropdown.test.tsx index eb3c6aeb4e973..37ff40c6b79b5 100644 --- a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/HeaderActionsDropdown.test.tsx +++ b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/HeaderActionsDropdown.test.tsx @@ -38,7 +38,12 @@ const createProps = () => ({ userId: '1', metadata: {}, common: { - conf: {}, + conf: { + DASHBOARD_AUTO_REFRESH_INTERVALS: [ + [0, "Don't refresh"], + [10, '10 seconds'], + ], + }, }, }, dashboardTitle: 'Title', @@ -63,6 +68,7 @@ const createProps = () => ({ lastModifiedTime: 0, isDropdownVisible: true, dataMask: {}, + logEvent: jest.fn(), }); const editModeOnProps = { ...createProps(), diff --git a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx index 3d25b049fba5b..d4c9a8aadb6bc 100644 --- a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx +++ b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx @@ -36,39 +36,45 @@ import getDashboardUrl from 'src/dashboard/util/getDashboardUrl'; import { getActiveFilters } from 'src/dashboard/util/activeDashboardFilters'; import { getUrlParam } from 'src/utils/urlUtils'; import { FILTER_BOX_MIGRATION_STATES } from 'src/explore/constants'; +import { LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_IMAGE } from 'src/logger/LogUtils'; const propTypes = { addSuccessToast: PropTypes.func.isRequired, addDangerToast: PropTypes.func.isRequired, dashboardInfo: PropTypes.object.isRequired, - dashboardId: PropTypes.number.isRequired, - dashboardTitle: PropTypes.string.isRequired, + dashboardId: PropTypes.number, + dashboardTitle: PropTypes.string, dataMask: PropTypes.object.isRequired, - customCss: PropTypes.string.isRequired, + customCss: PropTypes.string, colorNamespace: PropTypes.string, colorScheme: PropTypes.string, onChange: PropTypes.func.isRequired, updateCss: PropTypes.func.isRequired, forceRefreshAllCharts: PropTypes.func.isRequired, - refreshFrequency: PropTypes.number.isRequired, + refreshFrequency: PropTypes.number, shouldPersistRefreshFrequency: PropTypes.bool.isRequired, setRefreshFrequency: PropTypes.func.isRequired, startPeriodicRender: PropTypes.func.isRequired, editMode: PropTypes.bool.isRequired, - userCanEdit: PropTypes.bool.isRequired, - userCanShare: PropTypes.bool.isRequired, - userCanSave: PropTypes.bool.isRequired, + userCanEdit: PropTypes.bool, + userCanShare: PropTypes.bool, + userCanSave: PropTypes.bool, userCanCurate: PropTypes.bool.isRequired, isLoading: PropTypes.bool.isRequired, layout: PropTypes.object.isRequired, - expandedSlices: PropTypes.object.isRequired, + expandedSlices: PropTypes.object, onSave: PropTypes.func.isRequired, showPropertiesModal: PropTypes.func.isRequired, manageEmbedded: PropTypes.func.isRequired, + logEvent: PropTypes.func, refreshLimit: PropTypes.number, refreshWarning: PropTypes.string, lastModifiedTime: PropTypes.number.isRequired, - filterboxMigrationState: FILTER_BOX_MIGRATION_STATES, + filterboxMigrationState: PropTypes.oneOf( + Object.keys(FILTER_BOX_MIGRATION_STATES).map( + key => FILTER_BOX_MIGRATION_STATES[key], + ), + ), }; const defaultProps = { @@ -178,6 +184,7 @@ class HeaderActionsDropdown extends React.PureComponent { )(domEvent).then(() => { menu.style.visibility = 'visible'; }); + this.props.logEvent?.(LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_IMAGE); break; } case MENU_KEYS.TOGGLE_FULLSCREEN: { @@ -239,6 +246,9 @@ class HeaderActionsDropdown extends React.PureComponent { hash: window.location.hash, }); + const refreshIntervalOptions = + dashboardInfo.common?.conf?.DASHBOARD_AUTO_REFRESH_INTERVALS; + return ( <Menu selectable={false} data-test="header-actions-menu" {...rest}> {!editMode && ( @@ -386,6 +396,7 @@ class HeaderActionsDropdown extends React.PureComponent { refreshWarning={refreshWarning} onChange={this.changeRefreshInterval} editMode={editMode} + refreshIntervalOptions={refreshIntervalOptions} triggerNode={<span>{t('Set auto-refresh interval')}</span>} /> </Menu.Item> diff --git a/superset-frontend/src/dashboard/components/Header/index.jsx b/superset-frontend/src/dashboard/components/Header/index.jsx index e55d83e4e5460..6c7565cea9401 100644 --- a/superset-frontend/src/dashboard/components/Header/index.jsx +++ b/superset-frontend/src/dashboard/components/Header/index.jsx @@ -20,7 +20,13 @@ import moment from 'moment'; import React from 'react'; import PropTypes from 'prop-types'; -import { styled, css, t, getSharedLabelColor } from '@superset-ui/core'; +import { + styled, + css, + t, + getSharedLabelColor, + getUiOverrideRegistry, +} from '@superset-ui/core'; import { Global } from '@emotion/react'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import { @@ -31,6 +37,7 @@ import { import Icons from 'src/components/Icons'; import Button from 'src/components/Button'; import { AntdButton } from 'src/components/'; +import { findPermission } from 'src/utils/findPermission'; import { Tooltip } from 'src/components/Tooltip'; import { safeStringify } from 'src/utils/safeStringify'; import HeaderActionsDropdown from 'src/dashboard/components/Header/HeaderActionsDropdown'; @@ -38,7 +45,6 @@ import PublishedStatus from 'src/dashboard/components/PublishedStatus'; import UndoRedoKeyListeners from 'src/dashboard/components/UndoRedoKeyListeners'; import PropertiesModal from 'src/dashboard/components/PropertiesModal'; import { chartPropShape } from 'src/dashboard/util/propShapes'; -import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; import { UNDO_LIMIT, SAVE_TYPE_OVERWRITE, @@ -47,28 +53,30 @@ import { import setPeriodicRunner, { stopPeriodicRender, } from 'src/dashboard/util/setPeriodicRunner'; -import { options as PeriodicRefreshOptions } from 'src/dashboard/components/RefreshIntervalModal'; -import findPermission from 'src/dashboard/util/findPermission'; import { FILTER_BOX_MIGRATION_STATES } from 'src/explore/constants'; import { PageHeaderWithActions } from 'src/components/PageHeaderWithActions'; import { datahubUrl } from 'src/preamble'; import { DashboardEmbedModal } from '../DashboardEmbedControls'; +import OverwriteConfirm from '../OverwriteConfirm'; + +const uiOverrideRegistry = getUiOverrideRegistry(); const propTypes = { addSuccessToast: PropTypes.func.isRequired, addDangerToast: PropTypes.func.isRequired, addWarningToast: PropTypes.func.isRequired, - user: UserWithPermissionsAndRoles, + user: PropTypes.object, // UserWithPermissionsAndRoles, dashboardInfo: PropTypes.object.isRequired, - dashboardTitle: PropTypes.string.isRequired, + dashboardTitle: PropTypes.string, dataMask: PropTypes.object.isRequired, charts: PropTypes.objectOf(chartPropShape).isRequired, layout: PropTypes.object.isRequired, - expandedSlices: PropTypes.object.isRequired, - customCss: PropTypes.string.isRequired, + expandedSlices: PropTypes.object, + customCss: PropTypes.string, colorNamespace: PropTypes.string, colorScheme: PropTypes.string, - setColorSchemeAndUnsavedChanges: PropTypes.func.isRequired, + setColorScheme: PropTypes.func.isRequired, + setUnsavedChanges: PropTypes.func.isRequired, isStarred: PropTypes.bool.isRequired, isPublished: PropTypes.bool.isRequired, isLoading: PropTypes.bool.isRequired, @@ -96,7 +104,7 @@ const propTypes = { redoLength: PropTypes.number.isRequired, setMaxUndoHistoryExceeded: PropTypes.func.isRequired, maxUndoHistoryToast: PropTypes.func.isRequired, - refreshFrequency: PropTypes.number.isRequired, + refreshFrequency: PropTypes.number, shouldPersistRefreshFrequency: PropTypes.bool.isRequired, setRefreshFrequency: PropTypes.func.isRequired, dashboardInfoChanged: PropTypes.func.isRequired, @@ -125,6 +133,7 @@ const actionButtonsStyle = theme => css` } .undoRedo { + display: flex; margin-right: ${theme.gridUnit * 2}px; } `; @@ -280,12 +289,17 @@ class Header extends React.PureComponent { startPeriodicRender(interval) { let intervalMessage; + if (interval) { - const predefinedValue = PeriodicRefreshOptions.find( - option => option.value === interval / 1000, + const { dashboardInfo } = this.props; + const periodicRefreshOptions = + dashboardInfo.common?.conf?.DASHBOARD_AUTO_REFRESH_INTERVALS; + const predefinedValue = periodicRefreshOptions.find( + option => Number(option[0]) === interval / 1000, ); + if (predefinedValue) { - intervalMessage = predefinedValue.label; + intervalMessage = t(predefinedValue[1]); } else { intervalMessage = moment.duration(interval, 'millisecond').humanize(); } @@ -363,9 +377,8 @@ class Header extends React.PureComponent { dashboardInfo?.metadata?.color_scheme || colorScheme; const currentColorNamespace = dashboardInfo?.metadata?.color_namespace || colorNamespace; - const currentSharedLabelColors = getSharedLabelColor().getColorMap( - currentColorNamespace, - currentColorScheme, + const currentSharedLabelColors = Object.fromEntries( + getSharedLabelColor().getColorMap(), ); const data = { @@ -431,7 +444,8 @@ class Header extends React.PureComponent { customCss, colorNamespace, dataMask, - setColorSchemeAndUnsavedChanges, + setColorScheme, + setUnsavedChanges, colorScheme, onUndo, onRedo, @@ -451,6 +465,7 @@ class Header extends React.PureComponent { setRefreshFrequency, lastModifiedTime, filterboxMigrationState, + logEvent, } = this.props; const userCanEdit = @@ -472,6 +487,8 @@ class Header extends React.PureComponent { const handleOnPropertiesChange = updates => { const { dashboardInfoChanged, dashboardTitleChanged } = this.props; + + setColorScheme(updates.colorScheme); dashboardInfoChanged({ slug: updates.slug, metadata: JSON.parse(updates.jsonMetadata || '{}'), @@ -480,13 +497,16 @@ class Header extends React.PureComponent { owners: updates.owners, roles: updates.roles, }); - setColorSchemeAndUnsavedChanges(updates.colorScheme); + setUnsavedChanges(true); dashboardTitleChanged(updates.title); }; + const NavExtension = uiOverrideRegistry.get('dashboard.nav.right'); + return ( <div css={headerContainerStyle} + data-test="dashboard-header-container" data-test-id={dashboardInfo.id} className="dashboard-header-container" > @@ -611,11 +631,12 @@ class Header extends React.PureComponent { /> ) : ( <div css={actionButtonsStyle}> + {NavExtension && <NavExtension />} {userCanEdit && ( <Button buttonStyle="secondary" onClick={this.toggleEditMode} - data-test="query-save-button" + data-test="edit-dashboard-button" className="action-button" css={editButtonStyle} aria-label={t('Edit dashboard')} @@ -669,6 +690,7 @@ class Header extends React.PureComponent { filterboxMigrationState={filterboxMigrationState} isDropdownVisible={this.state.isDropdownVisible} setIsDropdownVisible={this.setIsDropdownVisible} + logEvent={logEvent} /> } showFaveStar={user?.userId && dashboardInfo?.id} @@ -687,6 +709,8 @@ class Header extends React.PureComponent { /> )} + <OverwriteConfirm /> + {userCanCurate && ( <DashboardEmbedModal show={this.state.showingEmbedModal} diff --git a/superset-frontend/src/dashboard/components/Header/types.ts b/superset-frontend/src/dashboard/components/Header/types.ts index f03e01874005f..89ea7569888d1 100644 --- a/superset-frontend/src/dashboard/components/Header/types.ts +++ b/superset-frontend/src/dashboard/components/Header/types.ts @@ -68,7 +68,8 @@ export interface HeaderProps { user: Object | undefined; dashboardInfo: DashboardInfo; dashboardTitle: string; - setColorSchemeAndUnsavedChanges: () => void; + setColorScheme: () => void; + setUnsavedChanges: () => void; isStarred: boolean; isPublished: boolean; onChange: () => void; diff --git a/superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirm.test.tsx b/superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirm.test.tsx new file mode 100644 index 0000000000000..498fbbc6ea8f7 --- /dev/null +++ b/superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirm.test.tsx @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import { render, waitFor } from 'spec/helpers/testing-library'; +import { overwriteConfirmMetadata } from 'spec/fixtures/mockDashboardState'; + +import OverwriteConfirm from '.'; + +import './OverwriteConfirmModal'; + +const mockStore = configureStore(); + +test('renders nothing without overwriteConfirmMetadata', () => { + const { queryByText } = render(<OverwriteConfirm />, { + useRedux: true, + store: mockStore({ dashboardState: {} }), + }); + expect(queryByText('Confirm overwrite')).not.toBeInTheDocument(); +}); + +test('renders confirm modal on overwriteConfirmMetadata is provided', async () => { + const { queryByText } = render(<OverwriteConfirm />, { + useRedux: true, + store: mockStore({ + dashboardState: { + overwriteConfirmMetadata, + }, + }), + }); + await waitFor(() => + expect(queryByText('Confirm overwrite')).toBeInTheDocument(), + ); +}); diff --git a/superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.test.tsx b/superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.test.tsx new file mode 100644 index 0000000000000..c49977ce7a52d --- /dev/null +++ b/superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.test.tsx @@ -0,0 +1,90 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import thunk from 'redux-thunk'; +import configureStore from 'redux-mock-store'; +import fetchMock from 'fetch-mock'; +import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils'; + +import { fireEvent, render, waitFor } from 'spec/helpers/testing-library'; +import { overwriteConfirmMetadata } from 'spec/fixtures/mockDashboardState'; +import OverwriteConfirmModal from './OverwriteConfirmModal'; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); + +jest.mock('react-diff-viewer-continued', () => () => ( + <div data-test="mock-diff-viewer" /> +)); + +test('renders diff viewer when it contains overwriteConfirmMetadata', async () => { + const { queryByText, findAllByTestId } = render( + <OverwriteConfirmModal + overwriteConfirmMetadata={overwriteConfirmMetadata} + />, + { + useRedux: true, + store: mockStore(), + }, + ); + expect(queryByText('Confirm overwrite')).toBeInTheDocument(); + const diffViewers = await findAllByTestId('mock-diff-viewer'); + expect(diffViewers).toHaveLength( + overwriteConfirmMetadata.overwriteConfirmItems.length, + ); +}); + +test('requests update dashboard api when save button is clicked', async () => { + const updateDashboardEndpoint = `glob:*/api/v1/dashboard/${overwriteConfirmMetadata.dashboardId}`; + fetchMock.put(updateDashboardEndpoint, { + id: overwriteConfirmMetadata.dashboardId, + last_modified_time: +new Date(), + result: overwriteConfirmMetadata.data, + }); + const store = mockStore({ + dashboardLayout: {}, + dashboardFilters: {}, + }); + const { findByTestId } = render( + <OverwriteConfirmModal + overwriteConfirmMetadata={overwriteConfirmMetadata} + />, + { + useRedux: true, + store, + }, + ); + const saveButton = await findByTestId('overwrite-confirm-save-button'); + expect(fetchMock.calls(updateDashboardEndpoint)).toHaveLength(0); + fireEvent.click(saveButton); + expect(fetchMock.calls(updateDashboardEndpoint)).toHaveLength(0); + mockAllIsIntersecting(true); + fireEvent.click(saveButton); + await waitFor(() => + expect(fetchMock.calls(updateDashboardEndpoint)?.[0]?.[1]?.body).toEqual( + JSON.stringify(overwriteConfirmMetadata.data), + ), + ); + await waitFor(() => + expect(store.getActions()).toContainEqual({ + type: 'SET_OVERRIDE_CONFIRM', + overwriteConfirmMetadata: undefined, + }), + ); +}); diff --git a/superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.tsx b/superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.tsx new file mode 100644 index 0000000000000..134681731c078 --- /dev/null +++ b/superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.tsx @@ -0,0 +1,209 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useMemo, useCallback, RefObject, createRef } from 'react'; +import moment from 'moment'; +import { useDispatch } from 'react-redux'; +import ReactDiffViewer from 'react-diff-viewer-continued'; +import { useInView } from 'react-intersection-observer'; +import Modal from 'src/components/Modal'; +import Button from 'src/components/Button'; +import { DashboardState } from 'src/dashboard/types'; +import { + saveDashboardRequest, + setOverrideConfirm, +} from 'src/dashboard/actions/dashboardState'; +import { t, styled } from '@superset-ui/core'; +import { SAVE_TYPE_OVERWRITE_CONFIRMED } from 'src/dashboard/util/constants'; + +const STICKY_HEADER_TOP = 16; +const STICKY_HEADER_HEIGHT = 32; + +const StyledTitle = styled.h2` + ${({ theme }) => ` + color: ${theme.colors.grayscale.dark1} + `} +`; + +const StyledEditor = styled.div` + ${({ theme }) => ` + table { + border: 1px ${theme.colors.grayscale.light2} solid; + } + pre { + font-size: 11px; + padding: 0px; + background-color: transparent; + border: 0px; + line-height: 110%; + } + `} +`; + +const StackableHeader = styled(Button)<{ top: number }>` + ${({ theme, top }) => ` + position: sticky; + top: ${top}px; + background-color: ${theme.colors.grayscale.light5}; + margin: 0px; + padding: 8px 4px; + z-index: 1; + border: 0px; + border-radius: 0px; + width: 100%; + justify-content: flex-start; + border-bottom: 1px ${theme.colors.grayscale.light1} solid; + &::before { + display: inline-block; + position: relative; + opacity: 1; + content: "\\00BB"; + } + `} +`; + +const StyledBottom = styled.div<{ inView: boolean }>` + ${({ inView }) => ` + margin: 8px auto; + text-align: center; + opacity: ${inView ? 0 : 1}; + `} +`; + +type Props = { + overwriteConfirmMetadata: DashboardState['overwriteConfirmMetadata']; +}; + +const OverrideConfirmModal = ({ overwriteConfirmMetadata }: Props) => { + const [bottomRef, hasReviewed] = useInView({ triggerOnce: true }); + const dispatch = useDispatch(); + const onHide = useCallback( + () => dispatch(setOverrideConfirm(undefined)), + [dispatch], + ); + const anchors = useMemo<RefObject<HTMLDivElement>[]>( + () => + overwriteConfirmMetadata + ? overwriteConfirmMetadata.overwriteConfirmItems.map(() => + createRef<HTMLDivElement>(), + ) + : [], + [overwriteConfirmMetadata], + ); + const onAnchorClicked = useCallback( + (index: number) => { + anchors[index]?.current?.scrollIntoView({ behavior: 'smooth' }); + }, + [anchors], + ); + const onConfirmOverwrite = useCallback(() => { + if (overwriteConfirmMetadata) { + dispatch( + saveDashboardRequest( + overwriteConfirmMetadata.data, + overwriteConfirmMetadata.dashboardId, + SAVE_TYPE_OVERWRITE_CONFIRMED, + ), + ); + } + }, [dispatch, overwriteConfirmMetadata]); + + return ( + <Modal + responsive + maxWidth="1024px" + height="50vh" + show={Boolean(overwriteConfirmMetadata)} + title={t('Confirm overwrite')} + footer={ + <> + {t('Scroll down to the bottom to enable overwriting changes. ')} + <Button + htmlType="button" + buttonSize="small" + onClick={onHide} + data-test="override-confirm-modal-cancel-button" + cta + > + {t('No')} + </Button> + <Button + data-test="overwrite-confirm-save-button" + htmlType="button" + buttonSize="small" + cta + buttonStyle="primary" + onClick={onConfirmOverwrite} + disabled={!hasReviewed} + > + {t('Yes, overwrite changes')} + </Button> + </> + } + onHide={onHide} + > + {overwriteConfirmMetadata && ( + <> + <StyledTitle> + {t('Are you sure you intend to overwrite the following values?')} + </StyledTitle> + <StyledEditor> + {overwriteConfirmMetadata.overwriteConfirmItems.map( + ({ keyPath, oldValue, newValue }, index) => ( + <React.Fragment key={keyPath}> + <div ref={anchors[index]} /> + <StackableHeader + top={index * STICKY_HEADER_HEIGHT - STICKY_HEADER_TOP} + buttonStyle="tertiary" + onClick={() => onAnchorClicked(index)} + > + {keyPath} + </StackableHeader> + <ReactDiffViewer + oldValue={oldValue} + newValue={newValue} + leftTitle={t( + 'Last Updated %s by %s', + moment.utc(overwriteConfirmMetadata.updatedAt).calendar(), + overwriteConfirmMetadata.updatedBy, + )} + rightTitle="new value" + /> + </React.Fragment> + ), + )} + <StyledBottom ref={bottomRef} inView={hasReviewed}> + {/* Add submit button at the bottom in case of intersection-observer fallback */} + <Button + htmlType="button" + buttonSize="small" + cta + buttonStyle="primary" + onClick={onConfirmOverwrite} + > + {t('Yes, overwrite changes')} + </Button> + </StyledBottom> + </StyledEditor> + </> + )} + </Modal> + ); +}; + +export default OverrideConfirmModal; diff --git a/superset-frontend/src/dashboard/stylesheets/components/new-component.less b/superset-frontend/src/dashboard/components/OverwriteConfirm/index.tsx similarity index 54% rename from superset-frontend/src/dashboard/stylesheets/components/new-component.less rename to superset-frontend/src/dashboard/components/OverwriteConfirm/index.tsx index 2202a59ff70b6..46e4f3ab50146 100644 --- a/superset-frontend/src/dashboard/stylesheets/components/new-component.less +++ b/superset-frontend/src/dashboard/components/OverwriteConfirm/index.tsx @@ -16,40 +16,26 @@ * specific language governing permissions and limitations * under the License. */ -@import '../../../assets/stylesheets/less/variables.less'; +import React from 'react'; +import { useSelector } from 'react-redux'; +import AsyncEsmComponent from 'src/components/AsyncEsmComponent'; +import { DashboardState, RootState } from 'src/dashboard/types'; -.new-component { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - align-items: center; - padding: 16px; - background: @lightest; - cursor: move; +const Modal = AsyncEsmComponent(() => import('./OverwriteConfirmModal')); - &:not(.static):hover { - background: @gray-bg; - } -} +const OverrideConfirm = () => { + const overwriteConfirmMetadata = useSelector< + RootState, + DashboardState['overwriteConfirmMetadata'] + >(({ dashboardState }) => dashboardState.overwriteConfirmMetadata); -.new-component-placeholder { - position: relative; - background: @gray-bg; - width: 40px; - height: 40px; - margin-right: 16px; - border: 1px solid @lightest; - display: flex; - align-items: center; - justify-content: center; - color: @gray; - font-size: @font-size-xxl; + return ( + <> + {overwriteConfirmMetadata && ( + <Modal overwriteConfirmMetadata={overwriteConfirmMetadata} /> + )} + </> + ); +}; - &.fa-window-restore { - font-size: @font-size-l; - } - - &.fa-area-chart { - font-size: @font-size-xl; - } -} +export default OverrideConfirm; diff --git a/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx b/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx index 07d48eb98a3cd..8469ef60057bc 100644 --- a/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx +++ b/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx @@ -38,7 +38,7 @@ spyColorSchemeControlWrapper.mockImplementation( ); fetchMock.get( - 'http://localhost/api/v1/dashboard/related/roles?q=(filter:%27%27)', + 'http://localhost/api/v1/dashboard/related/roles?q=(filter:%27%27,page:0,page_size:100)', { body: { count: 6, @@ -46,26 +46,32 @@ fetchMock.get( { text: 'Admin', value: 1, + extra: {}, }, { text: 'Alpha', value: 3, + extra: {}, }, { text: 'Gamma', value: 4, + extra: {}, }, { text: 'granter', value: 5, + extra: {}, }, { text: 'Public', value: 2, + extra: {}, }, { text: 'sql_lab', value: 6, + extra: {}, }, ], }, @@ -73,7 +79,7 @@ fetchMock.get( ); fetchMock.get( - 'http://localhost/api/v1/dashboard/related/owners?q=(filter:%27%27)', + 'http://localhost/api/v1/dashboard/related/owners?q=(filter:%27%27,page:0,page_size:100)', { body: { count: 1, @@ -81,45 +87,53 @@ fetchMock.get( { text: 'Superset Admin', value: 1, + extra: { active: true }, + }, + { + text: 'Inactive Admin', + value: 2, + extra: { active: false }, }, ], }, }, ); +const dashboardInfo = { + certified_by: 'John Doe', + certification_details: 'Sample certification', + changed_by: null, + changed_by_name: '', + changed_by_url: '', + changed_on: '2021-03-30T19:30:14.020942', + charts: [ + 'Vaccine Candidates per Country & Stage', + 'Vaccine Candidates per Country', + 'Vaccine Candidates per Country', + 'Vaccine Candidates per Approach & Stage', + 'Vaccine Candidates per Phase', + 'Vaccine Candidates per Phase', + 'Vaccine Candidates per Country & Stage', + 'Filtering Vaccines', + ], + css: '', + dashboard_title: 'COVID Vaccine Dashboard', + id: 26, + metadata: mockedJsonMetadata, + owners: [], + position_json: + '{"CHART-63bEuxjDMJ": {"children": [], "id": "CHART-63bEuxjDMJ", "meta": {"chartId": 369, "height": 76, "sliceName": "Vaccine Candidates per Country", "sliceNameOverride": "Map of Vaccine Candidates", "uuid": "ddc91df6-fb40-4826-bdca-16b85af1c024", "width": 7}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-zvw7luvEL"], "type": "CHART"}, "CHART-F-fkth0Dnv": {"children": [], "id": "CHART-F-fkth0Dnv", "meta": {"chartId": 314, "height": 76, "sliceName": "Vaccine Candidates per Country", "sliceNameOverride": "Treemap of Vaccine Candidates per Country", "uuid": "e2f5a8a7-feb0-4f79-bc6b-01fe55b98b3c", "width": 5}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-zvw7luvEL"], "type": "CHART"}, "CHART-RjD_ygqtwH": {"children": [], "id": "CHART-RjD_ygqtwH", "meta": {"chartId": 351, "height": 59, "sliceName": "Vaccine Candidates per Phase", "sliceNameOverride": "Vaccine Candidates per Phase", "uuid": "30b73c65-85e7-455f-bb24-801bb0cdc670", "width": 2}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-xSeNAspgw"], "type": "CHART"}, "CHART-aGfmWtliqA": {"children": [], "id": "CHART-aGfmWtliqA", "meta": {"chartId": 312, "height": 59, "sliceName": "Vaccine Candidates per Phase", "uuid": "392f293e-0892-4316-bd41-c927b65606a4", "width": 4}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-xSeNAspgw"], "type": "CHART"}, "CHART-dCUpAcPsji": {"children": [], "id": "CHART-dCUpAcPsji", "meta": {"chartId": 325, "height": 82, "sliceName": "Vaccine Candidates per Country & Stage", "sliceNameOverride": "Heatmap of Countries & Clinical Stages", "uuid": "cd111331-d286-4258-9020-c7949a109ed2", "width": 4}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-zhOlQLQnB"], "type": "CHART"}, "CHART-eirDduqb1A": {"children": [], "id": "CHART-eirDduqb1A", "meta": {"chartId": 358, "height": 59, "sliceName": "Filtering Vaccines", "sliceNameOverride": "Filter Box of Vaccines", "uuid": "c29381ce-0e99-4cf3-bf0f-5f55d6b94176", "width": 3}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-xSeNAspgw"], "type": "CHART"}, "CHART-fYo7IyvKZQ": {"children": [], "id": "CHART-fYo7IyvKZQ", "meta": {"chartId": 371, "height": 82, "sliceName": "Vaccine Candidates per Country & Stage", "sliceNameOverride": "Sunburst of Country & Clinical Stages", "uuid": "f69c556f-15fe-4a82-a8bb-69d5b6954123", "width": 5}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-zhOlQLQnB"], "type": "CHART"}, "CHART-j4hUvP5dDD": {"children": [], "id": "CHART-j4hUvP5dDD", "meta": {"chartId": 364, "height": 82, "sliceName": "Vaccine Candidates per Approach & Stage", "sliceNameOverride": "Heatmap of Approaches & Clinical Stages", "uuid": "0c953c84-0c9a-418d-be9f-2894d2a2cee0", "width": 3}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-zhOlQLQnB"], "type": "CHART"}, "DASHBOARD_VERSION_KEY": "v2", "GRID_ID": {"children": [], "id": "GRID_ID", "parents": ["ROOT_ID"], "type": "GRID"}, "HEADER_ID": {"id": "HEADER_ID", "meta": {"text": "COVID Vaccine Dashboard"}, "type": "HEADER"}, "MARKDOWN-VjQQ5SFj5v": {"children": [], "id": "MARKDOWN-VjQQ5SFj5v", "meta": {"code": "# COVID-19 Vaccine Dashboard\\n\\nEverywhere you look, you see negative news about COVID-19. This is to be expected; it\'s been a brutal year and this disease is no joke. This dashboard hopes to use visualization to inject some optimism about the coming return to normalcy we enjoyed before 2020! There\'s lots to be optimistic about:\\n\\n- the sheer volume of attempts to fund the R&D needed to produce and bring an effective vaccine to market\\n- the large number of countries involved in at least one vaccine candidate (and the diversity of economic status of these countries)\\n- the diversity of vaccine approaches taken\\n- the fact that 2 vaccines have already been approved (and a hundreds of thousands of patients have already been vaccinated)\\n\\n### The Dataset\\n\\nThis dashboard is powered by data maintained by the Millken Institute ([link to dataset](https://airtable.com/shrSAi6t5WFwqo3GM/tblEzPQS5fnc0FHYR/viwDBH7b6FjmIBX5x?blocks=bipZFzhJ7wHPv7x9z)). We researched each vaccine candidate and added our own best guesses for the country responsible for each vaccine effort.\\n\\n_Note that this dataset was last updated on 12/23/2020_.\\n\\n", "height": 59, "width": 3}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-xSeNAspgw"], "type": "MARKDOWN"}, "ROOT_ID": {"children": ["TABS-wUKya7eQ0Z"], "id": "ROOT_ID", "type": "ROOT"}, "ROW-xSeNAspgw": {"children": ["MARKDOWN-VjQQ5SFj5v", "CHART-aGfmWtliqA", "CHART-RjD_ygqtwH", "CHART-eirDduqb1A"], "id": "ROW-xSeNAspgw", "meta": {"0": "ROOT_ID", "background": "BACKGROUND_TRANSPARENT"}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ"], "type": "ROW"}, "ROW-zhOlQLQnB": {"children": ["CHART-j4hUvP5dDD", "CHART-dCUpAcPsji", "CHART-fYo7IyvKZQ"], "id": "ROW-zhOlQLQnB", "meta": {"0": "ROOT_ID", "background": "BACKGROUND_TRANSPARENT"}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ"], "type": "ROW"}, "ROW-zvw7luvEL": {"children": ["CHART-63bEuxjDMJ", "CHART-F-fkth0Dnv"], "id": "ROW-zvw7luvEL", "meta": {"0": "ROOT_ID", "background": "BACKGROUND_TRANSPARENT"}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ"], "type": "ROW"}, "TAB-BCIJF4NvgQ": {"children": ["ROW-xSeNAspgw", "ROW-zvw7luvEL", "ROW-zhOlQLQnB"], "id": "TAB-BCIJF4NvgQ", "meta": {"text": "Overview"}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z"], "type": "TAB"}, "TABS-wUKya7eQ0Z": {"children": ["TAB-BCIJF4NvgQ"], "id": "TABS-wUKya7eQ0Z", "meta": {}, "parents": ["ROOT_ID"], "type": "TABS"}}', + published: false, + roles: [], + slug: null, + thumbnail_url: + '/api/v1/dashboard/26/thumbnail/b24805e98d90116da8c0974d24f5c533/', + url: '/superset/dashboard/26/', +}; + fetchMock.get('glob:*/api/v1/dashboard/26', { body: { - result: { - certified_by: 'John Doe', - certification_details: 'Sample certification', - changed_by: null, - changed_by_name: '', - changed_by_url: '', - changed_on: '2021-03-30T19:30:14.020942', - charts: [ - 'Vaccine Candidates per Country & Stage', - 'Vaccine Candidates per Country', - 'Vaccine Candidates per Country', - 'Vaccine Candidates per Approach & Stage', - 'Vaccine Candidates per Phase', - 'Vaccine Candidates per Phase', - 'Vaccine Candidates per Country & Stage', - 'Filtering Vaccines', - ], - css: '', - dashboard_title: 'COVID Vaccine Dashboard', - id: 26, - json_metadata: mockedJsonMetadata, - owners: [], - position_json: - '{"CHART-63bEuxjDMJ": {"children": [], "id": "CHART-63bEuxjDMJ", "meta": {"chartId": 369, "height": 76, "sliceName": "Vaccine Candidates per Country", "sliceNameOverride": "Map of Vaccine Candidates", "uuid": "ddc91df6-fb40-4826-bdca-16b85af1c024", "width": 7}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-zvw7luvEL"], "type": "CHART"}, "CHART-F-fkth0Dnv": {"children": [], "id": "CHART-F-fkth0Dnv", "meta": {"chartId": 314, "height": 76, "sliceName": "Vaccine Candidates per Country", "sliceNameOverride": "Treemap of Vaccine Candidates per Country", "uuid": "e2f5a8a7-feb0-4f79-bc6b-01fe55b98b3c", "width": 5}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-zvw7luvEL"], "type": "CHART"}, "CHART-RjD_ygqtwH": {"children": [], "id": "CHART-RjD_ygqtwH", "meta": {"chartId": 351, "height": 59, "sliceName": "Vaccine Candidates per Phase", "sliceNameOverride": "Vaccine Candidates per Phase", "uuid": "30b73c65-85e7-455f-bb24-801bb0cdc670", "width": 2}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-xSeNAspgw"], "type": "CHART"}, "CHART-aGfmWtliqA": {"children": [], "id": "CHART-aGfmWtliqA", "meta": {"chartId": 312, "height": 59, "sliceName": "Vaccine Candidates per Phase", "uuid": "392f293e-0892-4316-bd41-c927b65606a4", "width": 4}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-xSeNAspgw"], "type": "CHART"}, "CHART-dCUpAcPsji": {"children": [], "id": "CHART-dCUpAcPsji", "meta": {"chartId": 325, "height": 82, "sliceName": "Vaccine Candidates per Country & Stage", "sliceNameOverride": "Heatmap of Countries & Clinical Stages", "uuid": "cd111331-d286-4258-9020-c7949a109ed2", "width": 4}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-zhOlQLQnB"], "type": "CHART"}, "CHART-eirDduqb1A": {"children": [], "id": "CHART-eirDduqb1A", "meta": {"chartId": 358, "height": 59, "sliceName": "Filtering Vaccines", "sliceNameOverride": "Filter Box of Vaccines", "uuid": "c29381ce-0e99-4cf3-bf0f-5f55d6b94176", "width": 3}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-xSeNAspgw"], "type": "CHART"}, "CHART-fYo7IyvKZQ": {"children": [], "id": "CHART-fYo7IyvKZQ", "meta": {"chartId": 371, "height": 82, "sliceName": "Vaccine Candidates per Country & Stage", "sliceNameOverride": "Sunburst of Country & Clinical Stages", "uuid": "f69c556f-15fe-4a82-a8bb-69d5b6954123", "width": 5}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-zhOlQLQnB"], "type": "CHART"}, "CHART-j4hUvP5dDD": {"children": [], "id": "CHART-j4hUvP5dDD", "meta": {"chartId": 364, "height": 82, "sliceName": "Vaccine Candidates per Approach & Stage", "sliceNameOverride": "Heatmap of Aproaches & Clinical Stages", "uuid": "0c953c84-0c9a-418d-be9f-2894d2a2cee0", "width": 3}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-zhOlQLQnB"], "type": "CHART"}, "DASHBOARD_VERSION_KEY": "v2", "GRID_ID": {"children": [], "id": "GRID_ID", "parents": ["ROOT_ID"], "type": "GRID"}, "HEADER_ID": {"id": "HEADER_ID", "meta": {"text": "COVID Vaccine Dashboard"}, "type": "HEADER"}, "MARKDOWN-VjQQ5SFj5v": {"children": [], "id": "MARKDOWN-VjQQ5SFj5v", "meta": {"code": "# COVID-19 Vaccine Dashboard\\n\\nEverywhere you look, you see negative news about COVID-19. This is to be expected; it\'s been a brutal year and this disease is no joke. This dashboard hopes to use visualization to inject some optimism about the coming return to normalcy we enjoyed before 2020! There\'s lots to be optimistic about:\\n\\n- the sheer volume of attempts to fund the R&D needed to produce and bring an effective vaccine to market\\n- the large number of countries involved in at least one vaccine candidate (and the diversity of economic status of these countries)\\n- the diversity of vaccine approaches taken\\n- the fact that 2 vaccines have already been approved (and a hundreds of thousands of patients have already been vaccinated)\\n\\n### The Dataset\\n\\nThis dashboard is powered by data maintained by the Millken Institute ([link to dataset](https://airtable.com/shrSAi6t5WFwqo3GM/tblEzPQS5fnc0FHYR/viwDBH7b6FjmIBX5x?blocks=bipZFzhJ7wHPv7x9z)). We researched each vaccine candidate and added our own best guesses for the country responsible for each vaccine effort.\\n\\n_Note that this dataset was last updated on 12/23/2020_.\\n\\n", "height": 59, "width": 3}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ", "ROW-xSeNAspgw"], "type": "MARKDOWN"}, "ROOT_ID": {"children": ["TABS-wUKya7eQ0Z"], "id": "ROOT_ID", "type": "ROOT"}, "ROW-xSeNAspgw": {"children": ["MARKDOWN-VjQQ5SFj5v", "CHART-aGfmWtliqA", "CHART-RjD_ygqtwH", "CHART-eirDduqb1A"], "id": "ROW-xSeNAspgw", "meta": {"0": "ROOT_ID", "background": "BACKGROUND_TRANSPARENT"}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ"], "type": "ROW"}, "ROW-zhOlQLQnB": {"children": ["CHART-j4hUvP5dDD", "CHART-dCUpAcPsji", "CHART-fYo7IyvKZQ"], "id": "ROW-zhOlQLQnB", "meta": {"0": "ROOT_ID", "background": "BACKGROUND_TRANSPARENT"}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ"], "type": "ROW"}, "ROW-zvw7luvEL": {"children": ["CHART-63bEuxjDMJ", "CHART-F-fkth0Dnv"], "id": "ROW-zvw7luvEL", "meta": {"0": "ROOT_ID", "background": "BACKGROUND_TRANSPARENT"}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z", "TAB-BCIJF4NvgQ"], "type": "ROW"}, "TAB-BCIJF4NvgQ": {"children": ["ROW-xSeNAspgw", "ROW-zvw7luvEL", "ROW-zhOlQLQnB"], "id": "TAB-BCIJF4NvgQ", "meta": {"text": "Overview"}, "parents": ["ROOT_ID", "TABS-wUKya7eQ0Z"], "type": "TAB"}, "TABS-wUKya7eQ0Z": {"children": ["TAB-BCIJF4NvgQ"], "id": "TABS-wUKya7eQ0Z", "meta": {}, "parents": ["ROOT_ID"], "type": "TABS"}}', - published: false, - roles: [], - slug: null, - thumbnail_url: - '/api/v1/dashboard/26/thumbnail/b24805e98d90116da8c0974d24f5c533/', - url: '/superset/dashboard/26/', - }, + result: { ...dashboardInfo, json_metadata: mockedJsonMetadata }, }, }); @@ -262,6 +276,7 @@ test('submitting with onlyApply:false', async () => { ); spyGetCategoricalSchemeRegistry.mockReturnValue({ keys: () => ['supersetColors'], + get: () => ['#FFFFFF', '#000000'], } as any); put.mockResolvedValue({ json: { @@ -289,13 +304,12 @@ test('submitting with onlyApply:false', async () => { userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => { - expect(props.onHide).toBeCalledTimes(1); expect(props.onSubmit).toBeCalledTimes(1); expect(props.onSubmit).toBeCalledWith({ certificationDetails: 'Sample certification', certifiedBy: 'John Doe', colorScheme: 'supersetColors', - colorNamespace: '', + colorNamespace: undefined, id: 26, jsonMetadata: expect.anything(), owners: [], @@ -312,6 +326,7 @@ test('submitting with onlyApply:true', async () => { ); spyGetCategoricalSchemeRegistry.mockReturnValue({ keys: () => ['supersetColors'], + get: () => ['#FFFFFF', '#000000'], } as any); spyIsFeatureEnabled.mockReturnValue(false); const props = createProps(); @@ -328,7 +343,6 @@ test('submitting with onlyApply:true', async () => { userEvent.click(screen.getByRole('button', { name: 'Apply' })); await waitFor(() => { - expect(props.onHide).toBeCalledTimes(1); expect(props.onSubmit).toBeCalledTimes(1); }); }); @@ -347,3 +361,102 @@ test('Empty "Certified by" should clear "Certification details"', async () => { screen.getByRole('textbox', { name: 'Certification details' }), ).toHaveValue(''); }); + +test('should show all roles', async () => { + spyIsFeatureEnabled.mockReturnValue(true); + + const props = createProps(); + const propsWithDashboardIndo = { ...props, dashboardInfo }; + + const open = () => waitFor(() => userEvent.click(getSelect())); + const getSelect = () => + screen.getByRole('combobox', { name: SupersetCore.t('Roles') }); + + const getElementsByClassName = (className: string) => + document.querySelectorAll(className)! as NodeListOf<HTMLElement>; + + const findAllSelectOptions = () => + waitFor(() => getElementsByClassName('.ant-select-item-option-content')); + + render(<PropertiesModal {...propsWithDashboardIndo} />, { + useRedux: true, + }); + + expect(screen.getAllByRole('combobox')).toHaveLength(2); + expect( + screen.getByRole('combobox', { name: SupersetCore.t('Roles') }), + ).toBeInTheDocument(); + + await open(); + + const options = await findAllSelectOptions(); + + expect(options).toHaveLength(6); + expect(options[0]).toHaveTextContent('Admin'); +}); + +test('should show active owners with dashboard rbac', async () => { + spyIsFeatureEnabled.mockReturnValue(true); + + const props = createProps(); + const propsWithDashboardIndo = { ...props, dashboardInfo }; + + const open = () => waitFor(() => userEvent.click(getSelect())); + const getSelect = () => + screen.getByRole('combobox', { name: SupersetCore.t('Owners') }); + + const getElementsByClassName = (className: string) => + document.querySelectorAll(className)! as NodeListOf<HTMLElement>; + + const findAllSelectOptions = () => + waitFor(() => getElementsByClassName('.ant-select-item-option-content')); + + render(<PropertiesModal {...propsWithDashboardIndo} />, { + useRedux: true, + }); + + expect(screen.getAllByRole('combobox')).toHaveLength(2); + expect( + screen.getByRole('combobox', { name: SupersetCore.t('Owners') }), + ).toBeInTheDocument(); + + await open(); + + const options = await findAllSelectOptions(); + + expect(options).toHaveLength(1); + expect(options[0]).toHaveTextContent('Superset Admin'); +}); + +test('should show active owners without dashboard rbac', async () => { + spyIsFeatureEnabled.mockReturnValue(false); + + const props = createProps(); + const propsWithDashboardIndo = { ...props, dashboardInfo }; + + const open = () => waitFor(() => userEvent.click(getSelect())); + const getSelect = () => + screen.getByRole('combobox', { name: SupersetCore.t('Owners') }); + + const getElementsByClassName = (className: string) => + document.querySelectorAll(className)! as NodeListOf<HTMLElement>; + + const findAllSelectOptions = () => + waitFor(() => getElementsByClassName('.ant-select-item-option-content')); + + render(<PropertiesModal {...propsWithDashboardIndo} />, { + useRedux: true, + }); + + expect(screen.getByRole('combobox')).toBeInTheDocument(); + expect( + screen.getByRole('combobox', { name: SupersetCore.t('Owners') }), + ).toBeInTheDocument(); + + await open(); + + const options = await findAllSelectOptions(); + + expect(options).toHaveLength(1); + expect(options[0]).toHaveTextContent('Superset Admin'); +}); diff --git a/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx b/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx index effd18b3d07c4..59eca184085d8 100644 --- a/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx +++ b/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx @@ -21,21 +21,23 @@ import { Input } from 'src/components/Input'; import { FormItem } from 'src/components/Form'; import jsonStringify from 'json-stringify-pretty-compact'; import Button from 'src/components/Button'; -import { Select, Row, Col, AntdForm } from 'src/components'; +import { AntdForm, AsyncSelect, Col, Row } from 'src/components'; import rison from 'rison'; import { - styled, - t, - SupersetClient, - getCategoricalSchemeRegistry, + CategoricalColorNamespace, ensureIsArray, + getCategoricalSchemeRegistry, getSharedLabelColor, + styled, + SupersetClient, + t, } from '@superset-ui/core'; import Modal from 'src/components/Modal'; import { JsonEditor } from 'src/components/AsyncAceEditor'; import ColorSchemeControlWrapper from 'src/dashboard/components/ColorSchemeControlWrapper'; +import FilterScopeModal from 'src/dashboard/components/filterscope/FilterScopeModal'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; import withToasts from 'src/components/MessageToasts/withToasts'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; @@ -56,9 +58,9 @@ type PropertiesModalProps = { show?: boolean; onHide?: () => void; colorScheme?: string; - setColorSchemeAndUnsavedChanges?: () => void; onSubmit?: (params: Record<string, any>) => void; addSuccessToast: (message: string) => void; + addDangerToast: (message: string) => void; onlyApply?: boolean; }; @@ -80,6 +82,7 @@ type DashboardInfo = { const PropertiesModal = ({ addSuccessToast, + addDangerToast, colorScheme: currentColorScheme, dashboardId, dashboardInfo: currentDashboardInfo, @@ -98,6 +101,7 @@ const PropertiesModal = ({ const [owners, setOwners] = useState<Owners>([]); const [roles, setRoles] = useState<Roles>([]); const saveLabel = onlyApply ? t('Apply') : t('Save'); + const categoricalSchemeRegistry = getCategoricalSchemeRegistry(); const handleErrorResponse = async (response: Response) => { const { error, statusText, message } = await getClientErrorObject(response); @@ -113,7 +117,7 @@ const PropertiesModal = ({ } Modal.error({ - title: 'Error', + title: t('Error'), content: errorText, okButtonProps: { danger: true, className: 'btn-danger' }, }); @@ -129,12 +133,14 @@ const PropertiesModal = ({ return SupersetClient.get({ endpoint: `/api/v1/dashboard/related/${accessType}?q=${query}`, }).then(response => ({ - data: response.json.result.map( - (item: { value: number; text: string }) => ({ + data: response.json.result + .filter((item: { extra: { active: boolean } }) => + item.extra.active !== undefined ? item.extra.active : true, + ) + .map((item: { value: number; text: string }) => ({ value: item.value, label: item.text, - }), - ), + })), totalCount: response.json.count, })); }, @@ -174,9 +180,11 @@ const PropertiesModal = ({ delete metadata.positions; } const metaDataCopy = { ...metadata }; - if (metaDataCopy?.shared_label_colors) { - delete metaDataCopy.shared_label_colors; - } + + delete metaDataCopy.shared_label_colors; + + delete metaDataCopy.color_scheme_domain; + setJsonMetadata(metaDataCopy ? jsonStringify(metaDataCopy) : ''); }, [form], @@ -258,17 +266,17 @@ const PropertiesModal = ({ }; const onColorSchemeChange = ( - colorScheme?: string, + colorScheme = '', { updateMetadata = true } = {}, ) => { // check that color_scheme is valid - const colorChoices = getCategoricalSchemeRegistry().keys(); + const colorChoices = categoricalSchemeRegistry.keys(); const jsonMetadataObj = getJsonMetadata(); // only fire if the color_scheme is present and invalid if (colorScheme && !colorChoices.includes(colorScheme)) { Modal.error({ - title: 'Error', + title: t('Error'), content: t('A valid color scheme is required'), okButtonProps: { danger: true, className: 'btn-danger' }, }); @@ -292,25 +300,52 @@ const PropertiesModal = ({ let colorNamespace = ''; let currentJsonMetadata = jsonMetadata; - // color scheme in json metadata has precedence over selection - if (currentJsonMetadata?.length) { - const metadata = JSON.parse(currentJsonMetadata); - currentColorScheme = metadata?.color_scheme || colorScheme; - colorNamespace = metadata?.color_namespace || ''; - - // filter shared_label_color from user input - if (metadata?.shared_label_colors) { - delete metadata.shared_label_colors; + // validate currentJsonMetadata + let metadata; + try { + if ( + !currentJsonMetadata.startsWith('{') || + !currentJsonMetadata.endsWith('}') + ) { + throw new Error(); } - const colorMap = getSharedLabelColor().getColorMap( - colorNamespace, - currentColorScheme, - true, + metadata = JSON.parse(currentJsonMetadata); + } catch (error) { + addDangerToast(t('JSON metadata is invalid!')); + return; + } + + // color scheme in json metadata has precedence over selection + currentColorScheme = metadata?.color_scheme || colorScheme; + colorNamespace = metadata?.color_namespace; + + // filter shared_label_color from user input + if (metadata?.shared_label_colors) { + delete metadata.shared_label_colors; + } + if (metadata?.color_scheme_domain) { + delete metadata.color_scheme_domain; + } + + const sharedLabelColor = getSharedLabelColor(); + const categoricalNamespace = + CategoricalColorNamespace.getNamespace(colorNamespace); + categoricalNamespace.resetColors(); + if (currentColorScheme) { + sharedLabelColor.updateColorMap(colorNamespace, currentColorScheme); + metadata.shared_label_colors = Object.fromEntries( + sharedLabelColor.getColorMap(), ); - metadata.shared_label_colors = colorMap; - currentJsonMetadata = jsonStringify(metadata); + metadata.color_scheme_domain = + categoricalSchemeRegistry.get(colorScheme)?.colors || []; + } else { + sharedLabelColor.reset(); + metadata.shared_label_colors = {}; + metadata.color_scheme_domain = []; } + currentJsonMetadata = jsonStringify(metadata); + onColorSchemeChange(currentColorScheme, { updateMetadata: false, }); @@ -334,9 +369,9 @@ const PropertiesModal = ({ ...moreOnSubmitProps, }; if (onlyApply) { - addSuccessToast(t('Dashboard properties updated')); onSubmit(onSubmitProps); onHide(); + addSuccessToast(t('Dashboard properties updated')); } else { SupersetClient.put({ endpoint: `/api/v1/dashboard/${dashboardId}`, @@ -352,9 +387,9 @@ const PropertiesModal = ({ ...morePutProps, }), }).then(() => { - addSuccessToast(t('The dashboard has been saved')); onSubmit(onSubmitProps); onHide(); + addSuccessToast(t('The dashboard has been saved')); }, handleErrorResponse); } }; @@ -370,7 +405,7 @@ const PropertiesModal = ({ <Col xs={24} md={12}> <h3 style={{ marginTop: '1em' }}>{t('Access')}</h3> <StyledFormItem label={t('Owners')}> - <Select + <AsyncSelect allowClear ariaLabel={t('Owners')} disabled={isLoading} @@ -417,7 +452,7 @@ const PropertiesModal = ({ <Row gutter={16}> <Col xs={24} md={12}> <StyledFormItem label={t('Owners')}> - <Select + <AsyncSelect allowClear ariaLabel={t('Owners')} disabled={isLoading} @@ -437,7 +472,7 @@ const PropertiesModal = ({ </Col> <Col xs={24} md={12}> <StyledFormItem label={t('Roles')}> - <Select + <AsyncSelect allowClear ariaLabel={t('Roles')} disabled={isLoading} @@ -513,6 +548,7 @@ const PropertiesModal = ({ {t('Cancel')} </Button> <Button + data-test="properties-modal-apply-button" onClick={form.submit} buttonSize="small" buttonStyle="primary" @@ -625,6 +661,23 @@ const PropertiesModal = ({ {t( 'This JSON object is generated dynamically when clicking the save or overwrite button in the dashboard view. It is exposed here for reference and for power users who may want to alter specific parameters.', )} + {onlyApply && ( + <> + {' '} + {t( + 'Please DO NOT overwrite the "filter_scopes" key.', + )}{' '} + <FilterScopeModal + triggerNode={ + <span className="alert-link"> + {t('Use "%(menuName)s" menu instead.', { + menuName: t('Set filter mapping'), + })} + </span> + } + /> + </> + )} </p> </> )} diff --git a/superset-frontend/src/dashboard/components/PublishedStatus/index.jsx b/superset-frontend/src/dashboard/components/PublishedStatus/index.jsx index 915ea0aecc968..490112e9c88db 100644 --- a/superset-frontend/src/dashboard/components/PublishedStatus/index.jsx +++ b/superset-frontend/src/dashboard/components/PublishedStatus/index.jsx @@ -23,11 +23,11 @@ import { Tooltip } from 'src/components/Tooltip'; import Label from 'src/components/Label'; const propTypes = { - dashboardId: PropTypes.number.isRequired, + dashboardId: PropTypes.number, isPublished: PropTypes.bool.isRequired, savePublished: PropTypes.func.isRequired, - canEdit: PropTypes.bool.isRequired, - canSave: PropTypes.bool.isRequired, + canEdit: PropTypes.bool, + canSave: PropTypes.bool, }; const draftButtonTooltip = t( diff --git a/superset-frontend/src/dashboard/components/RefreshIntervalModal.test.tsx b/superset-frontend/src/dashboard/components/RefreshIntervalModal.test.tsx index 9151275e800de..aad254d9ceb4c 100644 --- a/superset-frontend/src/dashboard/components/RefreshIntervalModal.test.tsx +++ b/superset-frontend/src/dashboard/components/RefreshIntervalModal.test.tsx @@ -41,6 +41,7 @@ describe('RefreshIntervalModal - Enzyme', () => { refreshFrequency: 10, onChange: jest.fn(), editMode: true, + refreshIntervalOptions: [], }; it('should show warning message', () => { const props = { @@ -78,7 +79,20 @@ const createProps = () => ({ userId: '1', metadata: {}, common: { - conf: {}, + conf: { + DASHBOARD_AUTO_REFRESH_INTERVALS: [ + [0, "Don't refresh"], + [10, '10 seconds'], + [30, '30 seconds'], + [60, '1 minute'], + [300, '5 minutes'], + [1800, '30 minutes'], + [3600, '1 hour'], + [21600, '6 hours'], + [43200, '12 hours'], + [86400, '24 hours'], + ], + }, }, }, dashboardTitle: 'Title', @@ -133,6 +147,7 @@ const defaultRefreshIntervalModalProps = { onChange: jest.fn(), editMode: true, addSuccessToast: jest.fn(), + refreshIntervalOptions: [], }; describe('RefreshIntervalModal - RTL', () => { diff --git a/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx b/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx index 896792ceebf68..6299b09c539a6 100644 --- a/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx +++ b/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx @@ -16,27 +16,15 @@ * specific language governing permissions and limitations * under the License. */ -import React, { RefObject } from 'react'; -import Select, { propertyComparator } from 'src/components/Select/Select'; +import React from 'react'; +import Select from 'src/components/Select/Select'; import { t, styled } from '@superset-ui/core'; import Alert from 'src/components/Alert'; import Button from 'src/components/Button'; -import ModalTrigger from 'src/components/ModalTrigger'; +import ModalTrigger, { ModalTriggerRef } from 'src/components/ModalTrigger'; import { FormLabel } from 'src/components/Form'; - -export const options = [ - [0, t("Don't refresh")], - [10, t('10 seconds')], - [30, t('30 seconds')], - [60, t('1 minute')], - [300, t('5 minutes')], - [1800, t('30 minutes')], - [3600, t('1 hour')], - [21600, t('6 hours')], - [43200, t('12 hours')], - [86400, t('24 hours')], -].map(o => ({ value: o[0] as number, label: o[1] })); +import { propertyComparator } from 'src/components/Select/utils'; const StyledModalTrigger = styled(ModalTrigger)` .ant-modal-body { @@ -56,6 +44,7 @@ type RefreshIntervalModalProps = { editMode: boolean; refreshLimit?: number; refreshWarning: string | null; + refreshIntervalOptions: [number, string][]; }; type RefreshIntervalModalState = { @@ -71,11 +60,11 @@ class RefreshIntervalModal extends React.PureComponent< refreshWarning: null, }; - modalRef: RefObject<ModalTrigger>; + modalRef: ModalTriggerRef | null; constructor(props: RefreshIntervalModalProps) { super(props); - this.modalRef = React.createRef(); + this.modalRef = React.createRef() as ModalTriggerRef; this.state = { refreshFrequency: props.refreshFrequency, }; @@ -86,7 +75,7 @@ class RefreshIntervalModal extends React.PureComponent< onSave() { this.props.onChange(this.state.refreshFrequency, this.props.editMode); - this.modalRef.current?.close(); + this.modalRef?.current?.close(); this.props.addSuccessToast(t('Refresh interval saved')); } @@ -94,17 +83,23 @@ class RefreshIntervalModal extends React.PureComponent< this.setState({ refreshFrequency: this.props.refreshFrequency, }); - this.modalRef.current?.close(); + this.modalRef?.current?.close(); } handleFrequencyChange(value: number) { + const { refreshIntervalOptions } = this.props; this.setState({ - refreshFrequency: value || options[0].value, + refreshFrequency: value || refreshIntervalOptions[0][0], }); } render() { - const { refreshLimit = 0, refreshWarning, editMode } = this.props; + const { + refreshLimit = 0, + refreshWarning, + editMode, + refreshIntervalOptions, + } = this.props; const { refreshFrequency = 0 } = this.state; const showRefreshWarning = !!refreshFrequency && !!refreshWarning && refreshFrequency < refreshLimit; @@ -119,7 +114,10 @@ class RefreshIntervalModal extends React.PureComponent< <FormLabel>{t('Refresh frequency')}</FormLabel> <Select ariaLabel={t('Refresh interval')} - options={options} + options={refreshIntervalOptions.map(option => ({ + value: option[0], + label: t(option[1]), + }))} value={refreshFrequency} onChange={this.handleFrequencyChange} sortComparator={propertyComparator('value')} diff --git a/superset-frontend/src/dashboard/components/SaveModal.tsx b/superset-frontend/src/dashboard/components/SaveModal.tsx index 913125a16800a..dbdcb7b55200e 100644 --- a/superset-frontend/src/dashboard/components/SaveModal.tsx +++ b/superset-frontend/src/dashboard/components/SaveModal.tsx @@ -24,7 +24,7 @@ import { Input } from 'src/components/Input'; import Button from 'src/components/Button'; import { t, JsonResponse } from '@superset-ui/core'; -import ModalTrigger from 'src/components/ModalTrigger'; +import ModalTrigger, { ModalTriggerRef } from 'src/components/ModalTrigger'; import Checkbox from 'src/components/Checkbox'; import { SAVE_TYPE_OVERWRITE, @@ -69,7 +69,7 @@ const defaultProps = { class SaveModal extends React.PureComponent<SaveModalProps, SaveModalState> { static defaultProps = defaultProps; - modal: ModalTrigger | null; + modal: ModalTriggerRef | null; onSave: ( data: Record<string, any>, @@ -81,20 +81,16 @@ class SaveModal extends React.PureComponent<SaveModalProps, SaveModalState> { super(props); this.state = { saveType: props.saveType, - newDashName: `${props.dashboardTitle} [copy]`, + newDashName: props.dashboardTitle + t('[copy]'), duplicateSlices: false, }; - this.modal = null; + this.handleSaveTypeChange = this.handleSaveTypeChange.bind(this); this.handleNameChange = this.handleNameChange.bind(this); this.saveDashboard = this.saveDashboard.bind(this); - this.setModalRef = this.setModalRef.bind(this); this.toggleDuplicateSlices = this.toggleDuplicateSlices.bind(this); this.onSave = this.props.onSave.bind(this); - } - - setModalRef(ref: ModalTrigger | null) { - this.modal = ref; + this.modal = React.createRef() as ModalTriggerRef; } toggleDuplicateSlices(): void { @@ -166,14 +162,14 @@ class SaveModal extends React.PureComponent<SaveModalProps, SaveModalState> { window.location.href = `/superset/dashboard/${resp.json.id}/`; } }); - this.modal?.close(); + this.modal?.current?.close?.(); } } render() { return ( <ModalTrigger - ref={this.setModalRef} + ref={this.modal} triggerNode={this.props.triggerNode} modalTitle={t('Save dashboard')} modalBody={ diff --git a/superset-frontend/src/dashboard/components/SliceAdder.jsx b/superset-frontend/src/dashboard/components/SliceAdder.jsx index 22f8038ee494c..55db08cd86ac5 100644 --- a/superset-frontend/src/dashboard/components/SliceAdder.jsx +++ b/superset-frontend/src/dashboard/components/SliceAdder.jsx @@ -19,7 +19,8 @@ /* eslint-env browser */ import React from 'react'; import PropTypes from 'prop-types'; -import { List } from 'react-virtualized'; +import AutoSizer from 'react-virtualized-auto-sizer'; +import { FixedSizeList as List } from 'react-window'; import { createFilter } from 'react-search-input'; import { t, @@ -43,6 +44,7 @@ import { } from 'src/dashboard/util/constants'; import { slicePropShape } from 'src/dashboard/util/propShapes'; import { FILTER_BOX_MIGRATION_STATES } from 'src/explore/constants'; +import _ from 'lodash'; import AddSliceCard from './AddSliceCard'; import AddSliceDragPreview from './dnd/AddSliceDragPreview'; import DragDroppable from './dnd/DragDroppable'; @@ -56,7 +58,6 @@ const propTypes = { userId: PropTypes.string.isRequired, selectedSliceIds: PropTypes.arrayOf(PropTypes.number), editMode: PropTypes.bool, - height: PropTypes.number, filterboxMigrationState: FILTER_BOX_MIGRATION_STATES, dashboardId: PropTypes.number, }; @@ -65,24 +66,20 @@ const defaultProps = { selectedSliceIds: [], editMode: false, errorMessage: '', - height: window.innerHeight, filterboxMigrationState: FILTER_BOX_MIGRATION_STATES.NOOP, }; const KEYS_TO_FILTERS = ['slice_name', 'viz_type', 'datasource_name']; const KEYS_TO_SORT = { - slice_name: 'name', - viz_type: 'viz type', - datasource_name: 'dataset', - changed_on: 'recent', + slice_name: t('name'), + viz_type: t('viz type'), + datasource_name: t('dataset'), + changed_on: t('recent'), }; const DEFAULT_SORT_KEY = 'changed_on'; -const MARGIN_BOTTOM = 16; -const SIDEPANE_HEADER_HEIGHT = 30; -const SLICE_ADDER_CONTROL_HEIGHT = 64; -const DEFAULT_CELL_HEIGHT = 112; +const DEFAULT_CELL_HEIGHT = 128; const Controls = styled.div` display: flex; @@ -118,6 +115,11 @@ const NewChartButton = styled(Button)` `} `; +export const ChartList = styled.div` + flex-grow: 1; + min-height: 0; +`; + class SliceAdder extends React.Component { static sortByComparator(attr) { const desc = attr === 'changed_on' ? -1 : 1; @@ -144,7 +146,6 @@ class SliceAdder extends React.Component { this.rowRenderer = this.rowRenderer.bind(this); this.searchUpdated = this.searchUpdated.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); - this.handleChange = this.handleChange.bind(this); this.handleSelect = this.handleSelect.bind(this); } @@ -194,9 +195,17 @@ class SliceAdder extends React.Component { } } - handleChange(ev) { - this.searchUpdated(ev.target.value); - } + handleChange = _.debounce(value => { + this.searchUpdated(value); + + const { userId, filterboxMigrationState } = this.props; + this.slicesRequest = this.props.fetchFilteredSlices( + userId, + isFeatureEnabled(FeatureFlag.ENABLE_FILTER_BOX_MIGRATION) && + filterboxMigrationState !== FILTER_BOX_MIGRATION_STATES.SNOOZED, + value, + ); + }, 300); searchUpdated(searchTerm) { this.setState(prevState => ({ @@ -216,6 +225,14 @@ class SliceAdder extends React.Component { sortBy, ), })); + + const { userId, filterboxMigrationState } = this.props; + this.slicesRequest = this.props.fetchSortedSlices( + userId, + isFeatureEnabled(FeatureFlag.ENABLE_FILTER_BOX_MIGRATION) && + filterboxMigrationState !== FILTER_BOX_MIGRATION_STATES.SNOOZED, + sortBy, + ); } rowRenderer({ key, index, style }) { @@ -257,6 +274,7 @@ class SliceAdder extends React.Component { visType={cellData.viz_type} datasourceUrl={cellData.datasource_url} datasourceName={cellData.datasource_name} + thumbnailUrl={cellData.thumbnail_url} isSelected={isSelected} /> )} @@ -265,13 +283,14 @@ class SliceAdder extends React.Component { } render() { - const slicesListHeight = - this.props.height - - SIDEPANE_HEADER_HEIGHT - - SLICE_ADDER_CONTROL_HEIGHT - - MARGIN_BOTTOM; return ( - <div className="slice-adder-container"> + <div + css={css` + height: 100%; + display: flex; + flex-direction: column; + `} + > <NewChartButtonContainer> <NewChartButton buttonStyle="link" @@ -292,7 +311,7 @@ class SliceAdder extends React.Component { <Input placeholder={t('Filter your charts')} className="search-input" - onChange={this.handleChange} + onChange={ev => this.handleChange(ev.target.value)} onKeyPress={this.handleKeyPress} data-test="dashboard-charts-filter-search-input" /> @@ -309,19 +328,32 @@ class SliceAdder extends React.Component { </Controls> {this.props.isLoading && <Loading />} {!this.props.isLoading && this.state.filteredSlices.length > 0 && ( - <List - width={376} - height={slicesListHeight} - rowCount={this.state.filteredSlices.length} - rowHeight={DEFAULT_CELL_HEIGHT} - rowRenderer={this.rowRenderer} - searchTerm={this.state.searchTerm} - sortBy={this.state.sortBy} - selectedSliceIds={this.props.selectedSliceIds} - /> + <ChartList> + <AutoSizer> + {({ height, width }) => ( + <List + width={width} + height={height} + itemCount={this.state.filteredSlices.length} + itemSize={DEFAULT_CELL_HEIGHT} + searchTerm={this.state.searchTerm} + sortBy={this.state.sortBy} + selectedSliceIds={this.props.selectedSliceIds} + > + {this.rowRenderer} + </List> + )} + </AutoSizer> + </ChartList> )} {this.props.errorMessage && ( - <div className="error-message">{this.props.errorMessage}</div> + <div + css={css` + padding: 16px; + `} + > + {this.props.errorMessage} + </div> )} {/* Drag preview is just a single fixed-position element */} <AddSliceDragPreview slices={this.state.filteredSlices} /> diff --git a/superset-frontend/src/dashboard/components/SliceAdder.test.jsx b/superset-frontend/src/dashboard/components/SliceAdder.test.jsx index 16703d0505ce5..72327d63c7ab7 100644 --- a/superset-frontend/src/dashboard/components/SliceAdder.test.jsx +++ b/superset-frontend/src/dashboard/components/SliceAdder.test.jsx @@ -20,10 +20,9 @@ import React from 'react'; import { shallow } from 'enzyme'; import sinon from 'sinon'; -import { List } from 'react-virtualized'; - -import SliceAdder from 'src/dashboard/components/SliceAdder'; +import SliceAdder, { ChartList } from 'src/dashboard/components/SliceAdder'; import { sliceEntitiesForDashboard as mockSliceEntities } from 'spec/fixtures/mockSliceEntities'; +import { styledShallow } from 'spec/helpers/theming'; describe('SliceAdder', () => { const mockEvent = { @@ -36,9 +35,9 @@ describe('SliceAdder', () => { const props = { ...mockSliceEntities, fetchAllSlices: () => {}, + fetchSortedSlices: () => {}, selectedSliceIds: [127, 128], userId: '1', - height: 100, }; const errorProps = { ...props, @@ -71,10 +70,10 @@ describe('SliceAdder', () => { }); }); - it('render List', () => { - const wrapper = shallow(<SliceAdder {...props} />); + it('render chart list', () => { + const wrapper = styledShallow(<SliceAdder {...props} />); wrapper.setState({ filteredSlices: Object.values(props.slices) }); - expect(wrapper.find(List)).toExist(); + expect(wrapper.find(ChartList)).toExist(); }); it('render error', () => { diff --git a/superset-frontend/src/dashboard/components/SliceHeader/SliceHeader.test.tsx b/superset-frontend/src/dashboard/components/SliceHeader/SliceHeader.test.tsx index ffee7f6ee465a..f1aacd79e087a 100644 --- a/superset-frontend/src/dashboard/components/SliceHeader/SliceHeader.test.tsx +++ b/superset-frontend/src/dashboard/components/SliceHeader/SliceHeader.test.tsx @@ -17,6 +17,8 @@ * under the License. */ import React from 'react'; +import { Router } from 'react-router-dom'; +import { createMemoryHistory } from 'history'; import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import SliceHeader from '.'; @@ -115,7 +117,7 @@ const createProps = (overrides: any = {}) => ({ sliceCanEdit: false, slice: { slice_id: 312, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20312%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20312%7D', slice_name: 'Vaccine Candidates per Phase', form_data: { adhoc_filters: [], @@ -154,8 +156,8 @@ const createProps = (overrides: any = {}) => ({ toggleExpandSlice: jest.fn(), forceRefresh: jest.fn(), logExploreChart: jest.fn(), + logEvent: jest.fn(), exportCSV: jest.fn(), - onExploreChart: jest.fn(), formData: { slice_id: 1, datasource: '58__table' }, width: 100, height: 100, @@ -164,7 +166,7 @@ const createProps = (overrides: any = {}) => ({ test('Should render', () => { const props = createProps(); - render(<SliceHeader {...props} />, { useRedux: true }); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); expect(screen.getByTestId('slice-header')).toBeInTheDocument(); }); @@ -206,7 +208,7 @@ test('Should render - default props', () => { // @ts-ignore delete props.sliceCanEdit; - render(<SliceHeader {...props} />, { useRedux: true }); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); expect(screen.getByTestId('slice-header')).toBeInTheDocument(); }); @@ -248,7 +250,7 @@ test('Should render default props and "call" actions', () => { // @ts-ignore delete props.sliceCanEdit; - render(<SliceHeader {...props} />, { useRedux: true }); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); userEvent.click(screen.getByTestId('toggleExpandSlice')); userEvent.click(screen.getByTestId('forceRefresh')); userEvent.click(screen.getByTestId('exploreChart')); @@ -261,27 +263,69 @@ test('Should render default props and "call" actions', () => { test('Should render title', () => { const props = createProps(); - render(<SliceHeader {...props} />, { useRedux: true }); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); expect(screen.getByText('Vaccine Candidates per Phase')).toBeInTheDocument(); }); test('Should render click to edit prompt and run onExploreChart on click', async () => { const props = createProps(); - render(<SliceHeader {...props} />, { useRedux: true }); + const history = createMemoryHistory({ + initialEntries: ['/superset/dashboard/1/'], + }); + render( + <Router history={history}> + <SliceHeader {...props} /> + </Router>, + { useRedux: true }, + ); + userEvent.hover(screen.getByText('Vaccine Candidates per Phase')); + expect( + await screen.findByText('Click to edit Vaccine Candidates per Phase.'), + ).toBeInTheDocument(); + expect( + await screen.findByText('Use ctrl + click to open in a new tab.'), + ).toBeInTheDocument(); + + userEvent.click(screen.getByText('Vaccine Candidates per Phase')); + expect(history.location.pathname).toMatch('/explore'); +}); + +test('Display cmd button in tooltip if running on MacOS', async () => { + jest.spyOn(window.navigator, 'appVersion', 'get').mockReturnValue('Mac'); + const props = createProps(); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); + userEvent.hover(screen.getByText('Vaccine Candidates per Phase')); + expect( + await screen.findByText('Click to edit Vaccine Candidates per Phase.'), + ).toBeInTheDocument(); + expect( + await screen.findByText('Use ⌘ + click to open in a new tab.'), + ).toBeInTheDocument(); +}); + +test('Display correct tooltip when DASHBOARD_EDIT_CHART_IN_NEW_TAB is enabled', async () => { + window.featureFlags.DASHBOARD_EDIT_CHART_IN_NEW_TAB = true; + const props = createProps(); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); userEvent.hover(screen.getByText('Vaccine Candidates per Phase')); expect( await screen.findByText( 'Click to edit Vaccine Candidates per Phase in a new tab', ), ).toBeInTheDocument(); - - userEvent.click(screen.getByText('Vaccine Candidates per Phase')); - expect(props.onExploreChart).toHaveBeenCalled(); }); test('Should not render click to edit prompt and run onExploreChart on click if supersetCanExplore=false', () => { const props = createProps({ supersetCanExplore: false }); - render(<SliceHeader {...props} />, { useRedux: true }); + const history = createMemoryHistory({ + initialEntries: ['/superset/dashboard/1/'], + }); + render( + <Router history={history}> + <SliceHeader {...props} /> + </Router>, + { useRedux: true }, + ); userEvent.hover(screen.getByText('Vaccine Candidates per Phase')); expect( screen.queryByText( @@ -290,12 +334,20 @@ test('Should not render click to edit prompt and run onExploreChart on click if ).not.toBeInTheDocument(); userEvent.click(screen.getByText('Vaccine Candidates per Phase')); - expect(props.onExploreChart).not.toHaveBeenCalled(); + expect(history.location.pathname).toMatch('/superset/dashboard'); }); test('Should not render click to edit prompt and run onExploreChart on click if in edit mode', () => { const props = createProps({ editMode: true }); - render(<SliceHeader {...props} />, { useRedux: true }); + const history = createMemoryHistory({ + initialEntries: ['/superset/dashboard/1/'], + }); + render( + <Router history={history}> + <SliceHeader {...props} /> + </Router>, + { useRedux: true }, + ); userEvent.hover(screen.getByText('Vaccine Candidates per Phase')); expect( screen.queryByText( @@ -304,12 +356,12 @@ test('Should not render click to edit prompt and run onExploreChart on click if ).not.toBeInTheDocument(); userEvent.click(screen.getByText('Vaccine Candidates per Phase')); - expect(props.onExploreChart).not.toHaveBeenCalled(); + expect(history.location.pathname).toMatch('/superset/dashboard'); }); test('Should render "annotationsLoading"', () => { const props = createProps(); - render(<SliceHeader {...props} />, { useRedux: true }); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); expect( screen.getByRole('img', { name: 'Annotation layers are still loading.', @@ -319,7 +371,7 @@ test('Should render "annotationsLoading"', () => { test('Should render "annotationsError"', () => { const props = createProps(); - render(<SliceHeader {...props} />, { useRedux: true }); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); expect( screen.getByRole('img', { name: 'One ore more annotation layers failed loading.', @@ -331,7 +383,7 @@ test('Should not render "annotationsError" and "annotationsLoading"', () => { const props = createProps(); props.annotationQuery = {}; props.annotationError = {}; - render(<SliceHeader {...props} />, { useRedux: true }); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); expect( screen.queryByRole('img', { name: 'One ore more annotation layers failed loading.', @@ -346,7 +398,7 @@ test('Should not render "annotationsError" and "annotationsLoading"', () => { test('Correct props to "FiltersBadge"', () => { const props = createProps(); - render(<SliceHeader {...props} />, { useRedux: true }); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); expect(screen.getByTestId('FiltersBadge')).toHaveAttribute( 'data-chart-id', '312', @@ -355,7 +407,7 @@ test('Correct props to "FiltersBadge"', () => { test('Correct props to "SliceHeaderControls"', () => { const props = createProps(); - render(<SliceHeader {...props} />, { useRedux: true }); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); expect(screen.getByTestId('SliceHeaderControls')).toHaveAttribute( 'data-cached-dttm', '', @@ -412,7 +464,7 @@ test('Correct props to "SliceHeaderControls"', () => { test('Correct actions to "SliceHeaderControls"', () => { const props = createProps(); - render(<SliceHeader {...props} />, { useRedux: true }); + render(<SliceHeader {...props} />, { useRedux: true, useRouter: true }); expect(props.toggleExpandSlice).toBeCalledTimes(0); userEvent.click(screen.getByTestId('toggleExpandSlice')); diff --git a/superset-frontend/src/dashboard/components/SliceHeader/index.tsx b/superset-frontend/src/dashboard/components/SliceHeader/index.tsx index af9d509e2f8af..a928933b54a27 100644 --- a/superset-frontend/src/dashboard/components/SliceHeader/index.tsx +++ b/superset-frontend/src/dashboard/components/SliceHeader/index.tsx @@ -16,8 +16,16 @@ * specific language governing permissions and limitations * under the License. */ -import React, { FC, useEffect, useMemo, useRef, useState } from 'react'; -import { styled, t } from '@superset-ui/core'; +import React, { + FC, + ReactNode, + useContext, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import { css, styled, t } from '@superset-ui/core'; import { useUiConfig } from 'src/components/UiConfigContext'; import { Tooltip } from 'src/components/Tooltip'; import { useDispatch, useSelector } from 'react-redux'; @@ -29,6 +37,8 @@ import FiltersBadge from 'src/dashboard/components/FiltersBadge'; import Icons from 'src/components/Icons'; import { RootState } from 'src/dashboard/types'; import FilterIndicator from 'src/dashboard/components/FiltersBadge/FilterIndicator'; +import { getSliceHeaderTooltip } from 'src/dashboard/util/getSliceHeaderTooltip'; +import { DashboardPageIdContext } from 'src/dashboard/containers/DashboardPage'; import { clearDataMask } from 'src/dataMask/actions'; type SliceHeaderProps = SliceHeaderControlsProps & { @@ -54,13 +64,76 @@ const CrossFilterIcon = styled(Icons.CursorTarget)` width: 22px; `; +const ChartHeaderStyles = styled.div` + ${({ theme }) => css` + font-size: ${theme.typography.sizes.l}px; + font-weight: ${theme.typography.weights.bold}; + margin-bottom: ${theme.gridUnit}px; + display: flex; + max-width: 100%; + align-items: flex-start; + min-height: 0; + + & > .header-title { + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + flex-grow: 1; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + + & > span.ant-tooltip-open { + display: inline; + } + } + + & > .header-controls { + display: flex; + + & > * { + margin-left: ${theme.gridUnit * 2}px; + } + } + + .dropdown.btn-group { + pointer-events: none; + vertical-align: top; + & > * { + pointer-events: auto; + } + } + + .dropdown-toggle.btn.btn-default { + background: none; + border: none; + box-shadow: none; + } + + .dropdown-menu.dropdown-menu-right { + top: ${theme.gridUnit * 5}px; + } + + .divider { + margin: ${theme.gridUnit}px 0; + } + + .refresh-tooltip { + display: block; + height: ${theme.gridUnit * 4}px; + margin: ${theme.gridUnit}px 0; + color: ${theme.colors.text.label}; + } + `} +`; + const SliceHeader: FC<SliceHeaderProps> = ({ innerRef = null, forceRefresh = () => ({}), updateSliceName = () => ({}), toggleExpandSlice = () => ({}), logExploreChart = () => ({}), - onExploreChart, + logEvent, exportCSV = () => ({}), editMode = false, annotationQuery = {}, @@ -89,12 +162,16 @@ const SliceHeader: FC<SliceHeaderProps> = ({ }) => { const dispatch = useDispatch(); const uiConfig = useUiConfig(); - const [headerTooltip, setHeaderTooltip] = useState<string | null>(null); + const dashboardPageId = useContext(DashboardPageIdContext); + const [headerTooltip, setHeaderTooltip] = useState<ReactNode | null>(null); const headerRef = useRef<HTMLDivElement>(null); // TODO: change to indicator field after it will be implemented const crossFilterValue = useSelector<RootState, any>( state => state.dataMask[slice?.slice_id]?.filterState?.value, ); + const isCrossFiltersEnabled = useSelector<RootState, boolean>( + ({ dashboardInfo }) => dashboardInfo.crossFiltersEnabled, + ); const indicator = useMemo( () => ({ @@ -104,17 +181,12 @@ const SliceHeader: FC<SliceHeaderProps> = ({ [crossFilterValue], ); - const handleClickTitle = - !editMode && supersetCanExplore ? onExploreChart : undefined; + const canExplore = !editMode && supersetCanExplore; useEffect(() => { const headerElement = headerRef.current; - if (handleClickTitle) { - setHeaderTooltip( - sliceName - ? t('Click to edit %s in a new tab', sliceName) - : t('Click to edit chart in a new tab'), - ); + if (canExplore) { + setHeaderTooltip(getSliceHeaderTooltip(sliceName)); } else if ( headerElement && (headerElement.scrollWidth > headerElement.offsetWidth || @@ -124,10 +196,12 @@ const SliceHeader: FC<SliceHeaderProps> = ({ } else { setHeaderTooltip(null); } - }, [sliceName, width, height, handleClickTitle]); + }, [sliceName, width, height, canExplore]); + + const exploreUrl = `/explore/?dashboard_page_id=${dashboardPageId}&slice_id=${slice.slice_id}`; return ( - <div className="chart-header" data-test="slice-header" ref={innerRef}> + <ChartHeaderStyles data-test="slice-header" ref={innerRef}> <div className="header-title" ref={headerRef}> <Tooltip title={headerTooltip}> <EditableTitle @@ -138,10 +212,9 @@ const SliceHeader: FC<SliceHeaderProps> = ({ : '') } canEdit={editMode} - emptyText="" onSaveTitle={updateSliceName} showTooltip={false} - onClickTitle={handleClickTitle} + url={canExplore ? exploreUrl : undefined} /> </Tooltip> {!!Object.values(annotationQuery).length && ( @@ -159,7 +232,7 @@ const SliceHeader: FC<SliceHeaderProps> = ({ )} {!!Object.values(annotationError).length && ( <Tooltip - id="annoation-errors-tooltip" + id="annotation-errors-tooltip" placement="top" title={annotationsError} > @@ -202,7 +275,7 @@ const SliceHeader: FC<SliceHeaderProps> = ({ toggleExpandSlice={toggleExpandSlice} forceRefresh={forceRefresh} logExploreChart={logExploreChart} - onExploreChart={onExploreChart} + logEvent={logEvent} exportCSV={exportCSV} exportFullCSV={exportFullCSV} supersetCanExplore={supersetCanExplore} @@ -218,12 +291,14 @@ const SliceHeader: FC<SliceHeaderProps> = ({ isDescriptionExpanded={isExpanded} chartStatus={chartStatus} formData={formData} + exploreUrl={exploreUrl} + crossFiltersEnabled={isCrossFiltersEnabled} /> )} </> )} </div> - </div> + </ChartHeaderStyles> ); }; diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx b/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx index 9e212018ad422..3a1e30564022e 100644 --- a/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx +++ b/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx @@ -19,9 +19,10 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; +import { getMockStore } from 'spec/fixtures/mockStore'; import { render, screen } from 'spec/helpers/testing-library'; import { FeatureFlag } from 'src/featureFlags'; -import SliceHeaderControls from '.'; +import SliceHeaderControls, { SliceHeaderControlsProps } from '.'; jest.mock('src/components/Dropdown', () => { const original = jest.requireActual('src/components/Dropdown'); @@ -36,66 +37,77 @@ jest.mock('src/components/Dropdown', () => { }; }); -const createProps = (viz_type = 'sunburst') => ({ - addDangerToast: jest.fn(), - addSuccessToast: jest.fn(), - exploreChart: jest.fn(), - exportCSV: jest.fn(), - exportFullCSV: jest.fn(), - forceRefresh: jest.fn(), - handleToggleFullSize: jest.fn(), - toggleExpandSlice: jest.fn(), - onExploreChart: jest.fn(), - slice: { - slice_id: 371, - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20371%7D', - slice_name: 'Vaccine Candidates per Country & Stage', - slice_description: 'Table of vaccine candidates for 100 countries', - form_data: { - adhoc_filters: [], - color_scheme: 'supersetColors', - datasource: '58__table', - groupby: ['product_category', 'clinical_stage'], - linear_color_scheme: 'schemeYlOrBr', - metric: 'count', - queryFields: { - groupby: 'groupby', - metric: 'metrics', - secondary_metric: 'metrics', - }, - row_limit: 10000, +const createProps = (viz_type = 'sunburst') => + ({ + addDangerToast: jest.fn(), + addSuccessToast: jest.fn(), + exploreChart: jest.fn(), + exportCSV: jest.fn(), + exportFullCSV: jest.fn(), + forceRefresh: jest.fn(), + handleToggleFullSize: jest.fn(), + toggleExpandSlice: jest.fn(), + logEvent: jest.fn(), + slice: { slice_id: 371, - time_range: 'No filter', - url_params: {}, + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20371%7D', + slice_name: 'Vaccine Candidates per Country & Stage', + slice_description: 'Table of vaccine candidates for 100 countries', + form_data: { + adhoc_filters: [], + color_scheme: 'supersetColors', + datasource: '58__table', + groupby: ['product_category', 'clinical_stage'], + linear_color_scheme: 'schemeYlOrBr', + metric: 'count', + queryFields: { + groupby: 'groupby', + metric: 'metrics', + secondary_metric: 'metrics', + }, + row_limit: 10000, + slice_id: 371, + time_range: 'No filter', + url_params: {}, + viz_type, + }, viz_type, + datasource: '58__table', + description: 'test-description', + description_markeddown: '', + owners: [], + modified: '<span class="no-wrap">22 hours ago</span>', + changed_on: 1617143411523, }, - viz_type, - datasource: '58__table', - description: 'test-description', - description_markeddown: '', - owners: [], - modified: '<span class="no-wrap">22 hours ago</span>', - changed_on: 1617143411523, - }, - isCached: [false], - isExpanded: false, - cachedDttm: [''], - updatedDttm: 1617213803803, - supersetCanExplore: true, - supersetCanCSV: true, - sliceCanEdit: false, - componentId: 'CHART-fYo7IyvKZQ', - dashboardId: 26, - isFullSize: false, - chartStatus: 'rendered', - showControls: true, - supersetCanShare: true, - formData: { slice_id: 1, datasource: '58__table', viz_type: 'sunburst' }, -}); + isCached: [false], + isExpanded: false, + cachedDttm: [''], + updatedDttm: 1617213803803, + supersetCanExplore: true, + supersetCanCSV: true, + sliceCanEdit: false, + componentId: 'CHART-fYo7IyvKZQ', + dashboardId: 26, + isFullSize: false, + chartStatus: 'rendered', + showControls: true, + supersetCanShare: true, + formData: { slice_id: 1, datasource: '58__table', viz_type: 'sunburst' }, + exploreUrl: '/explore', + } as SliceHeaderControlsProps); + +const renderWrapper = (overrideProps?: SliceHeaderControlsProps) => { + const props = overrideProps || createProps(); + const store = getMockStore(); + return render(<SliceHeaderControls {...props} />, { + useRedux: true, + useRouter: true, + store, + }); +}; test('Should render', () => { - const props = createProps(); - render(<SliceHeaderControls {...props} />, { useRedux: true }); + renderWrapper(); expect( screen.getByRole('button', { name: 'More Options' }), ).toBeInTheDocument(); @@ -124,7 +136,7 @@ test('Should render default props', () => { // @ts-ignore delete props.sliceCanEdit; - render(<SliceHeaderControls {...props} />, { useRedux: true }); + renderWrapper(props); expect( screen.getByRole('menuitem', { name: 'Enter fullscreen' }), ).toBeInTheDocument(); @@ -150,8 +162,7 @@ test('Should render default props', () => { test('Should "export to CSV"', async () => { const props = createProps(); - render(<SliceHeaderControls {...props} />, { useRedux: true }); - + renderWrapper(props); expect(props.exportCSV).toBeCalledTimes(0); userEvent.hover(screen.getByText('Download')); userEvent.click(await screen.findByText('Export to .CSV')); @@ -161,7 +172,7 @@ test('Should "export to CSV"', async () => { test('Should not show "Download" if slice is filter box', () => { const props = createProps('filter_box'); - render(<SliceHeaderControls {...props} />, { useRedux: true }); + renderWrapper(props); expect(screen.queryByText('Download')).not.toBeInTheDocument(); }); @@ -171,7 +182,7 @@ test('Export full CSV is under featureflag', async () => { [FeatureFlag.ALLOW_FULL_CSV_EXPORT]: false, }; const props = createProps('table'); - render(<SliceHeaderControls {...props} />, { useRedux: true }); + renderWrapper(props); userEvent.hover(screen.getByText('Download')); expect(await screen.findByText('Export to .CSV')).toBeInTheDocument(); expect(screen.queryByText('Export to full .CSV')).not.toBeInTheDocument(); @@ -183,7 +194,7 @@ test('Should "export full CSV"', async () => { [FeatureFlag.ALLOW_FULL_CSV_EXPORT]: true, }; const props = createProps('table'); - render(<SliceHeaderControls {...props} />, { useRedux: true }); + renderWrapper(props); expect(props.exportFullCSV).toBeCalledTimes(0); userEvent.hover(screen.getByText('Download')); userEvent.click(await screen.findByText('Export to full .CSV')); @@ -196,8 +207,7 @@ test('Should not show export full CSV if report is not table', async () => { global.featureFlags = { [FeatureFlag.ALLOW_FULL_CSV_EXPORT]: true, }; - const props = createProps(); - render(<SliceHeaderControls {...props} />, { useRedux: true }); + renderWrapper(); userEvent.hover(screen.getByText('Download')); expect(await screen.findByText('Export to .CSV')).toBeInTheDocument(); expect(screen.queryByText('Export to full .CSV')).not.toBeInTheDocument(); @@ -205,8 +215,7 @@ test('Should not show export full CSV if report is not table', async () => { test('Should "Show chart description"', () => { const props = createProps(); - render(<SliceHeaderControls {...props} />, { useRedux: true }); - + renderWrapper(props); expect(props.toggleExpandSlice).toBeCalledTimes(0); userEvent.click(screen.getByText('Show chart description')); expect(props.toggleExpandSlice).toBeCalledTimes(1); @@ -215,8 +224,7 @@ test('Should "Show chart description"', () => { test('Should "Force refresh"', () => { const props = createProps(); - render(<SliceHeaderControls {...props} />, { useRedux: true }); - + renderWrapper(props); expect(props.forceRefresh).toBeCalledTimes(0); userEvent.click(screen.getByText('Force refresh')); expect(props.forceRefresh).toBeCalledTimes(1); @@ -226,9 +234,30 @@ test('Should "Force refresh"', () => { test('Should "Enter fullscreen"', () => { const props = createProps(); - render(<SliceHeaderControls {...props} />, { useRedux: true }); + renderWrapper(props); expect(props.handleToggleFullSize).toBeCalledTimes(0); userEvent.click(screen.getByText('Enter fullscreen')); expect(props.handleToggleFullSize).toBeCalledTimes(1); }); + +test('Drill to detail modal is under featureflag', () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.DRILL_TO_DETAIL]: false, + }; + const props = createProps(); + renderWrapper(props); + expect(screen.queryByText('Drill to detail')).not.toBeInTheDocument(); +}); + +test('Should show the "Drill to detail"', () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.DRILL_TO_DETAIL]: true, + }; + const props = createProps(); + props.slice.slice_id = 18; + renderWrapper(props); + expect(screen.getByText('Drill to detail')).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx index e7415f517c820..4037234f74fd0 100644 --- a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx +++ b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx @@ -16,7 +16,19 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; +import React, { + MouseEvent, + Key, + ReactChild, + useState, + useCallback, +} from 'react'; +import { + Link, + RouteComponentProps, + useHistory, + withRouter, +} from 'react-router-dom'; import moment from 'moment'; import { Behavior, @@ -25,6 +37,7 @@ import { QueryFormData, styled, t, + useTheme, } from '@superset-ui/core'; import { Menu } from 'src/components/Menu'; import { NoAnimationDropdown } from 'src/components/Dropdown'; @@ -32,11 +45,16 @@ import ShareMenuItems from 'src/dashboard/components/menu/ShareMenuItems'; import downloadAsImage from 'src/utils/downloadAsImage'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import CrossFilterScopingModal from 'src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal'; +import { getSliceHeaderTooltip } from 'src/dashboard/util/getSliceHeaderTooltip'; +import { Tooltip } from 'src/components/Tooltip'; import Icons from 'src/components/Icons'; import ModalTrigger from 'src/components/ModalTrigger'; import Button from 'src/components/Button'; import ViewQueryModal from 'src/explore/components/controls/ViewQueryModal'; import { ResultsPaneOnDashboard } from 'src/explore/components/DataTablesPane'; +import Modal from 'src/components/Modal'; +import { DrillDetailMenuItems } from 'src/components/Chart/DrillDetail'; +import { LOG_ACTIONS_CHART_DOWNLOAD_AS_IMAGE } from 'src/logger/LogUtils'; const MENU_KEYS = { CROSS_FILTER_SCOPING: 'cross_filter_scoping', @@ -49,14 +67,23 @@ const MENU_KEYS = { TOGGLE_CHART_DESCRIPTION: 'toggle_chart_description', VIEW_QUERY: 'view_query', VIEW_RESULTS: 'view_results', + DRILL_TO_DETAIL: 'drill_to_detail', }; +// TODO: replace 3 dots with an icon const VerticalDotsContainer = styled.div` padding: ${({ theme }) => theme.gridUnit / 4}px ${({ theme }) => theme.gridUnit * 1.5}px; .dot { display: block; + + height: ${({ theme }) => theme.gridUnit}px; + width: ${({ theme }) => theme.gridUnit}px; + border-radius: 50%; + margin: ${({ theme }) => theme.gridUnit / 2}px 0; + + background-color: ${({ theme }) => theme.colors.text.label}; } &:hover { @@ -93,7 +120,7 @@ export interface SliceHeaderControlsProps { slice_name: string; slice_id: number; slice_description: string; - form_data?: { emit_filter?: boolean }; + datasource: string; }; componentId: string; @@ -106,10 +133,11 @@ export interface SliceHeaderControlsProps { isFullSize?: boolean; isDescriptionExpanded?: boolean; formData: QueryFormData; - onExploreChart: () => void; + exploreUrl: string; forceRefresh: (sliceId: number, dashboardId: number) => void; logExploreChart?: (sliceId: number) => void; + logEvent?: (eventName: string, eventData?: object) => void; toggleExpandSlice?: (sliceId: number) => void; exportCSV?: (sliceId: number) => void; exportFullCSV?: (sliceId: number) => void; @@ -122,7 +150,11 @@ export interface SliceHeaderControlsProps { supersetCanShare?: boolean; supersetCanCSV?: boolean; sliceCanEdit?: boolean; + + crossFiltersEnabled?: boolean; } +type SliceHeaderControlsPropsWithRouter = SliceHeaderControlsProps & + RouteComponentProps; interface State { showControls: boolean; showCrossFilterScopingModal: boolean; @@ -135,11 +167,88 @@ const dropdownIconsStyles = css` } `; +const ViewResultsModalTrigger = ({ + exploreUrl, + triggerNode, + modalTitle, + modalBody, +}: { + exploreUrl: string; + triggerNode: ReactChild; + modalTitle: ReactChild; + modalBody: ReactChild; +}) => { + const [showModal, setShowModal] = useState(false); + const openModal = useCallback(() => setShowModal(true), []); + const closeModal = useCallback(() => setShowModal(false), []); + const history = useHistory(); + const exploreChart = () => history.push(exploreUrl); + const theme = useTheme(); + + return ( + <> + <span + data-test="span-modal-trigger" + onClick={openModal} + role="button" + tabIndex={0} + > + {triggerNode} + </span> + {(() => ( + <Modal + css={css` + .ant-modal-body { + display: flex; + flex-direction: column; + } + `} + show={showModal} + onHide={closeModal} + title={modalTitle} + footer={ + <> + <Button + buttonStyle="secondary" + buttonSize="small" + onClick={exploreChart} + > + {t('Edit chart')} + </Button> + <Button + buttonStyle="primary" + buttonSize="small" + onClick={closeModal} + > + {t('Close')} + </Button> + </> + } + responsive + resizable + resizableConfig={{ + minHeight: theme.gridUnit * 128, + minWidth: theme.gridUnit * 128, + defaultSize: { + width: 'auto', + height: '75vh', + }, + }} + draggable + destroyOnClose + > + {modalBody} + </Modal> + ))()} + </> + ); +}; + class SliceHeaderControls extends React.PureComponent< - SliceHeaderControlsProps, + SliceHeaderControlsPropsWithRouter, State > { - constructor(props: SliceHeaderControlsProps) { + constructor(props: SliceHeaderControlsPropsWithRouter) { super(props); this.toggleControls = this.toggleControls.bind(this); this.refreshChart = this.refreshChart.bind(this); @@ -170,8 +279,8 @@ class SliceHeaderControls extends React.PureComponent< key, domEvent, }: { - key: React.Key; - domEvent: React.MouseEvent<HTMLElement>; + key: Key; + domEvent: MouseEvent<HTMLElement>; }) { switch (key) { case MENU_KEYS.FORCE_REFRESH: @@ -183,25 +292,22 @@ class SliceHeaderControls extends React.PureComponent< break; case MENU_KEYS.TOGGLE_CHART_DESCRIPTION: // eslint-disable-next-line no-unused-expressions - this.props.toggleExpandSlice && - this.props.toggleExpandSlice(this.props.slice.slice_id); + this.props.toggleExpandSlice?.(this.props.slice.slice_id); break; case MENU_KEYS.EXPLORE_CHART: // eslint-disable-next-line no-unused-expressions - this.props.logExploreChart && - this.props.logExploreChart(this.props.slice.slice_id); + this.props.logExploreChart?.(this.props.slice.slice_id); break; case MENU_KEYS.EXPORT_CSV: // eslint-disable-next-line no-unused-expressions - this.props.exportCSV && this.props.exportCSV(this.props.slice.slice_id); + this.props.exportCSV?.(this.props.slice.slice_id); break; case MENU_KEYS.FULLSCREEN: this.props.handleToggleFullSize(); break; case MENU_KEYS.EXPORT_FULL_CSV: // eslint-disable-next-line no-unused-expressions - this.props.exportFullCSV && - this.props.exportFullCSV(this.props.slice.slice_id); + this.props.exportFullCSV?.(this.props.slice.slice_id); break; case MENU_KEYS.DOWNLOAD_AS_IMAGE: { // menu closes with a delay, we need to hide it manually, @@ -218,6 +324,9 @@ class SliceHeaderControls extends React.PureComponent< )(domEvent).then(() => { menu.style.visibility = 'visible'; }); + this.props.logEvent?.(LOG_ACTIONS_CHART_DOWNLOAD_AS_IMAGE, { + chartId: this.props.slice.slice_id, + }); break; } default: @@ -237,6 +346,7 @@ class SliceHeaderControls extends React.PureComponent< addDangerToast = () => {}, supersetCanShare = false, isCached = [], + crossFiltersEnabled, } = this.props; const crossFilterItems = getChartMetadataRegistry().items; const isTable = slice.viz_type === 'table'; @@ -246,7 +356,6 @@ class SliceHeaderControls extends React.PureComponent< value.behaviors?.includes(Behavior.INTERACTIVE_CHART), ) .find(([key]) => key === slice.viz_type); - const canEmitCrossFilter = slice.form_data?.emit_filter; const cachedWhen = (cachedDttm || []).map(itemCachedDttm => moment.utc(itemCachedDttm).fromNow(), @@ -273,6 +382,7 @@ class SliceHeaderControls extends React.PureComponent< const fullscreenLabel = isFullSize ? t('Exit fullscreen') : t('Enter fullscreen'); + const menu = ( <Menu onClick={this.handleMenuClick} @@ -304,11 +414,14 @@ class SliceHeaderControls extends React.PureComponent< )} {this.props.supersetCanExplore && ( - <Menu.Item - key={MENU_KEYS.EXPLORE_CHART} - onClick={this.props.onExploreChart} - > - {t('Edit chart')} + <Menu.Item key={MENU_KEYS.EXPLORE_CHART}> + <Link to={this.props.exploreUrl}> + <Tooltip + title={getSliceHeaderTooltip(this.props.slice.slice_name)} + > + {t('Edit chart')} + </Tooltip> + </Link> </Menu.Item> )} @@ -331,7 +444,8 @@ class SliceHeaderControls extends React.PureComponent< {this.props.supersetCanExplore && ( <Menu.Item key={MENU_KEYS.VIEW_RESULTS}> - <ModalTrigger + <ViewResultsModalTrigger + exploreUrl={this.props.exploreUrl} triggerNode={ <span data-test="view-query-menu-item"> {t('View as table')} @@ -347,29 +461,25 @@ class SliceHeaderControls extends React.PureComponent< isVisible /> } - modalFooter={ - <Button - buttonStyle="secondary" - buttonSize="small" - onClick={this.props.onExploreChart} - > - {t('Edit chart')} - </Button> - } - draggable - resizable - responsive /> </Menu.Item> )} + {isFeatureEnabled(FeatureFlag.DRILL_TO_DETAIL) && + this.props.supersetCanExplore && ( + <DrillDetailMenuItems + chartId={slice.slice_id} + formData={this.props.formData} + /> + )} + {(slice.description || this.props.supersetCanExplore) && ( <Menu.Divider /> )} {isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) && isCrossFilter && - canEmitCrossFilter && ( + crossFiltersEnabled && ( <> <Menu.Item key={MENU_KEYS.CROSS_FILTER_SCOPING}> {t('Cross-filter scoping')} @@ -459,4 +569,4 @@ class SliceHeaderControls extends React.PureComponent< } } -export default SliceHeaderControls; +export default withRouter(SliceHeaderControls); diff --git a/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx b/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx index f2af7af1dcbca..2d13cedcd63e2 100644 --- a/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx +++ b/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx @@ -20,10 +20,11 @@ import React, { useState } from 'react'; import { t } from '@superset-ui/core'; import Popover, { PopoverProps } from 'src/components/Popover'; import CopyToClipboard from 'src/components/CopyToClipboard'; -import { getDashboardPermalink, getUrlParam } from 'src/utils/urlUtils'; +import { getDashboardPermalink } from 'src/utils/urlUtils'; import { useToasts } from 'src/components/MessageToasts/withToasts'; -import { URL_PARAMS } from 'src/constants'; -import { getFilterValue } from 'src/dashboard/components/nativeFilters/FilterBar/keyValue'; +import { useSelector } from 'react-redux'; +import { RootState } from 'src/dashboard/types'; +import { getClientErrorObject } from 'src/utils/getClientErrorObject'; export type URLShortLinkButtonProps = { dashboardId: number; @@ -42,19 +43,27 @@ export default function URLShortLinkButton({ }: URLShortLinkButtonProps) { const [shortUrl, setShortUrl] = useState(''); const { addDangerToast } = useToasts(); + const { dataMask, activeTabs } = useSelector((state: RootState) => ({ + dataMask: state.dataMask, + activeTabs: state.dashboardState.activeTabs, + })); const getCopyUrl = async () => { - const nativeFiltersKey = getUrlParam(URL_PARAMS.nativeFiltersKey); try { - const filterState = await getFilterValue(dashboardId, nativeFiltersKey); const url = await getDashboardPermalink({ dashboardId, - filterState, - hash: anchorLinkId, + dataMask, + activeTabs, + anchor: anchorLinkId, }); setShortUrl(url); } catch (error) { - addDangerToast(error); + if (error) { + addDangerToast( + (await getClientErrorObject(error)).error || + t('Something went wrong.'), + ); + } } }; @@ -66,7 +75,14 @@ export default function URLShortLinkButton({ trigger="click" placement={placement} content={ - <div id="shorturl-popover" data-test="shorturl-popover"> + // eslint-disable-next-line jsx-a11y/no-static-element-interactions + <div + id="shorturl-popover" + data-test="shorturl-popover" + onClick={e => { + e.stopPropagation(); + }} + > <CopyToClipboard text={shortUrl} copyNode={ diff --git a/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx b/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx index a29d0475e53b4..3bc9f4d299a00 100644 --- a/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx +++ b/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx @@ -21,6 +21,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { DragSource, DropTarget } from 'react-dnd'; import cx from 'classnames'; +import { css, styled } from '@superset-ui/core'; import { componentShape } from '../../util/propShapes'; import { dragConfig, dropConfig } from './dragDroppableConfig'; @@ -34,7 +35,7 @@ import { const propTypes = { children: PropTypes.func, className: PropTypes.string, - component: componentShape.isRequired, + component: componentShape, parentComponent: componentShape, depth: PropTypes.number.isRequired, disableDragDrop: PropTypes.bool, @@ -42,16 +43,17 @@ const propTypes = { index: PropTypes.number.isRequired, style: PropTypes.object, onDrop: PropTypes.func, - editMode: PropTypes.bool.isRequired, + onHover: PropTypes.func, + editMode: PropTypes.bool, useEmptyDragPreview: PropTypes.bool, // from react-dnd - isDragging: PropTypes.bool.isRequired, - isDraggingOver: PropTypes.bool.isRequired, - isDraggingOverShallow: PropTypes.bool.isRequired, - droppableRef: PropTypes.func.isRequired, - dragSourceRef: PropTypes.func.isRequired, - dragPreviewRef: PropTypes.func.isRequired, + isDragging: PropTypes.bool, + isDraggingOver: PropTypes.bool, + isDraggingOverShallow: PropTypes.bool, + droppableRef: PropTypes.func, + dragSourceRef: PropTypes.func, + dragPreviewRef: PropTypes.func, }; const defaultProps = { @@ -61,10 +63,75 @@ const defaultProps = { disableDragDrop: false, children() {}, onDrop() {}, + onHover() {}, orientation: 'row', useEmptyDragPreview: false, + isDragging: false, + isDraggingOver: false, + isDraggingOverShallow: false, + droppableRef() {}, + dragSourceRef() {}, + dragPreviewRef() {}, }; +const DragDroppableStyles = styled.div` + ${({ theme }) => css` + position: relative; + + &.dragdroppable--dragging { + opacity: 0.2; + } + + &.dragdroppable-row { + width: 100%; + } + + &.dragdroppable-column .resizable-container span div { + z-index: 10; + } + + & { + .drop-indicator { + display: block; + background-color: ${theme.colors.primary.base}; + position: absolute; + z-index: 10; + } + + .drop-indicator--top { + top: 0; + left: 0; + height: ${theme.gridUnit}px; + width: 100%; + min-width: ${theme.gridUnit * 4}px; + } + + .drop-indicator--bottom { + top: 100%; + left: 0; + height: ${theme.gridUnit}px; + width: 100%; + min-width: ${theme.gridUnit * 4}px; + } + + .drop-indicator--right { + top: 0; + left: 100%; + height: 100%; + width: ${theme.gridUnit}px; + min-height: ${theme.gridUnit * 4}px; + } + + .drop-indicator--left { + top: 0; + left: 0; + height: 100%; + width: ${theme.gridUnit}px; + min-height: ${theme.gridUnit * 4}px; + } + } + `}; +`; // export unwrapped component for testing export class UnwrappedDragDroppable extends React.PureComponent { constructor(props) { @@ -95,7 +162,7 @@ export class UnwrappedDragDroppable extends React.PureComponent { } else { this.props.dragPreviewRef(ref); } - this.props.droppableRef(ref); + this.props.droppableRef?.(ref); } render() { @@ -133,7 +200,7 @@ export class UnwrappedDragDroppable extends React.PureComponent { : {}; return ( - <div + <DragDroppableStyles style={style} ref={this.setRef} data-test="dragdroppable-object" @@ -146,7 +213,7 @@ export class UnwrappedDragDroppable extends React.PureComponent { )} > {children(childProps)} - </div> + </DragDroppableStyles> ); } } diff --git a/superset-frontend/src/dashboard/components/dnd/DragDroppable.test.jsx b/superset-frontend/src/dashboard/components/dnd/DragDroppable.test.jsx index 65d77e773c566..e8366815a6dd3 100644 --- a/superset-frontend/src/dashboard/components/dnd/DragDroppable.test.jsx +++ b/superset-frontend/src/dashboard/components/dnd/DragDroppable.test.jsx @@ -17,7 +17,10 @@ * under the License. */ import React from 'react'; -import { shallow, mount } from 'enzyme'; +import { + styledMount as mount, + styledShallow as shallow, +} from 'spec/helpers/theming'; import sinon from 'sinon'; import newComponentFactory from 'src/dashboard/util/newComponentFactory'; diff --git a/superset-frontend/src/dashboard/components/dnd/dragDroppableConfig.js b/superset-frontend/src/dashboard/components/dnd/dragDroppableConfig.js index 02466d3c5e155..4d7185148e85f 100644 --- a/superset-frontend/src/dashboard/components/dnd/dragDroppableConfig.js +++ b/superset-frontend/src/dashboard/components/dnd/dragDroppableConfig.js @@ -19,7 +19,7 @@ import handleHover from './handleHover'; import handleDrop from './handleDrop'; -// note: the 'type' hook is not useful for us as dropping is contigent on other properties +// note: the 'type' hook is not useful for us as dropping is contingent on other properties const TYPE = 'DRAG_DROPPABLE'; export const dragConfig = [ diff --git a/superset-frontend/src/dashboard/components/dnd/handleHover.js b/superset-frontend/src/dashboard/components/dnd/handleHover.js index 71862a66c5b56..e709b6e3e54d1 100644 --- a/superset-frontend/src/dashboard/components/dnd/handleHover.js +++ b/superset-frontend/src/dashboard/components/dnd/handleHover.js @@ -40,6 +40,8 @@ function handleHover(props, monitor, Component) { return; } + Component?.props?.onHover(); + Component.setState(() => ({ dropIndicator: dropPosition, })); diff --git a/superset-frontend/src/dashboard/components/filterscope/FilterScopeModal.tsx b/superset-frontend/src/dashboard/components/filterscope/FilterScopeModal.tsx index 53bd0e170f6d9..6fe994e11bedf 100644 --- a/superset-frontend/src/dashboard/components/filterscope/FilterScopeModal.tsx +++ b/superset-frontend/src/dashboard/components/filterscope/FilterScopeModal.tsx @@ -16,9 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -import React, { RefObject } from 'react'; +import React from 'react'; import { styled } from '@superset-ui/core'; -import ModalTrigger from 'src/components/ModalTrigger'; +import ModalTrigger, { ModalTriggerRef } from 'src/components/ModalTrigger'; import FilterScope from 'src/dashboard/containers/FilterScope'; type FilterScopeModalProps = { @@ -34,19 +34,17 @@ export default class FilterScopeModal extends React.PureComponent< FilterScopeModalProps, {} > { - modal: RefObject<ModalTrigger>; + modal: ModalTriggerRef; constructor(props: FilterScopeModalProps) { super(props); - this.modal = React.createRef(); + this.modal = React.createRef() as ModalTriggerRef; this.handleCloseModal = this.handleCloseModal.bind(this); } handleCloseModal(): void { - if (this.modal.current) { - this.modal.current.close(); - } + this?.modal?.current?.close?.(); } render() { diff --git a/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx b/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx index 995cac01ca1f5..1b146148682bc 100644 --- a/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx +++ b/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx @@ -20,7 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; import Button from 'src/components/Button'; -import { t, styled } from '@superset-ui/core'; +import { css, t, styled } from '@superset-ui/core'; import buildFilterScopeTreeEntry from 'src/dashboard/util/buildFilterScopeTreeEntry'; import getFilterScopeNodesTree from 'src/dashboard/util/getFilterScopeNodesTree'; @@ -49,6 +49,268 @@ const propTypes = { onCloseModal: PropTypes.func.isRequired, }; +const ScopeContainer = styled.div` + ${({ theme }) => css` + display: flex; + flex-direction: column; + height: 80%; + margin-right: ${theme.gridUnit * -6}px; + font-size: ${theme.typography.sizes.m}px; + + & .nav.nav-tabs { + border: none; + } + + & .filter-scope-body { + flex: 1; + max-height: calc(100% - ${theme.gridUnit * 32}px); + + .filter-field-pane, + .filter-scope-pane { + overflow-y: auto; + } + } + + & .warning-message { + padding: ${theme.gridUnit * 6}px; + } + `} +`; + +const ScopeBody = styled.div` + ${({ theme }) => css` + &.filter-scope-body { + flex: 1; + max-height: calc(100% - ${theme.gridUnit * 32}px); + + .filter-field-pane, + .filter-scope-pane { + overflow-y: auto; + } + } + `} +`; + +const ScopeHeader = styled.div` + ${({ theme }) => css` + height: ${theme.gridUnit * 16}px; + border-bottom: 1px solid ${theme.colors.grayscale.light2}; + padding-left: ${theme.gridUnit * 6}px; + margin-left: ${theme.gridUnit * -6}px; + + h4 { + margin-top: 0; + } + + .selected-fields { + margin: ${theme.gridUnit * 3}px 0 ${theme.gridUnit * 4}px; + visibility: hidden; + + &.multi-edit-mode { + visibility: visible; + } + + .selected-scopes { + padding-left: ${theme.gridUnit}px; + } + } + `} +`; + +const ScopeSelector = styled.div` + ${({ theme }) => css` + &.filters-scope-selector { + display: flex; + flex-direction: row; + position: relative; + height: 100%; + + a, + a:active, + a:hover { + color: inherit; + text-decoration: none; + } + + .react-checkbox-tree .rct-icon.rct-icon-expand-all, + .react-checkbox-tree .rct-icon.rct-icon-collapse-all { + font-family: ${theme.typography.families.sansSerif}; + font-size: ${theme.typography.sizes.m}px; + color: ${theme.colors.primary.base}; + + &::before { + content: ''; + } + + &:hover { + text-decoration: underline; + } + + &:focus { + outline: none; + } + } + + .filter-field-pane { + position: relative; + width: 40%; + padding: ${theme.gridUnit * 4}px; + padding-left: 0; + border-right: 1px solid ${theme.colors.grayscale.light2}; + + .filter-container label { + font-weight: ${theme.typography.weights.normal}; + margin: 0 0 0 ${theme.gridUnit * 4}px; + word-break: break-all; + } + + .filter-field-item { + height: ${theme.gridUnit * 9}px; + display: flex; + align-items: center; + justify-content: center; + padding: 0 ${theme.gridUnit * 6}px; + margin-left: ${theme.gridUnit * -6}px; + + &.is-selected { + border: 1px solid ${theme.colors.text.label}; + border-radius: ${theme.borderRadius}px; + background-color: ${theme.colors.grayscale.light4}; + margin-left: ${theme.gridUnit * -6}px; + } + } + + .react-checkbox-tree { + .rct-title .root { + font-weight: ${theme.typography.weights.bold}; + } + + .rct-text { + height: ${theme.gridUnit * 10}px; + } + } + } + + .filter-scope-pane { + position: relative; + flex: 1; + padding: ${theme.gridUnit * 4}px; + padding-right: ${theme.gridUnit * 6}px; + } + + .react-checkbox-tree { + flex-direction: column; + color: ${theme.colors.grayscale.dark1}; + font-size: ${theme.typography.sizes.m}px; + + .filter-scope-type { + padding: ${theme.gridUnit * 2}px 0; + display: flex; + align-items: center; + + &.chart { + font-weight: ${theme.typography.weights.normal}; + } + + &.selected-filter { + padding-left: ${theme.gridUnit * 7}px; + position: relative; + color: ${theme.colors.text.label}; + + &::before { + content: ' '; + position: absolute; + left: 0; + top: 50%; + width: ${theme.gridUnit * 4}px; + height: ${theme.gridUnit * 4}px; + border-radius: ${theme.borderRadius}px; + margin-top: ${theme.gridUnit * -2}px; + box-shadow: inset 0 0 0 2px ${theme.colors.grayscale.light2}; + background: ${theme.colors.grayscale.light3}; + } + } + + &.root { + font-weight: ${theme.typography.weights.bold}; + } + } + + .rct-checkbox { + svg { + position: relative; + top: 3px; + width: ${theme.gridUnit * 4.5}px; + } + } + + .rct-node-leaf { + .rct-bare-label { + &::before { + padding-left: ${theme.gridUnit}px; + } + } + } + + .rct-options { + text-align: left; + margin-left: 0; + margin-bottom: ${theme.gridUnit * 2}px; + } + + .rct-text { + margin: 0; + display: flex; + } + + .rct-title { + display: block; + } + + // disable style from react-checkbox-trees.css + .rct-node-clickable:hover, + .rct-node-clickable:focus, + label:hover, + label:active { + background: none !important; + } + } + + .multi-edit-mode { + &.filter-scope-pane { + .rct-node.rct-node-leaf .filter-scope-type.filter_box { + display: none; + } + } + + .filter-field-item { + padding: 0 ${theme.gridUnit * 4}px 0 ${theme.gridUnit * 12}px; + margin-left: ${theme.gridUnit * -12}px; + + &.is-selected { + margin-left: ${theme.gridUnit * -13}px; + } + } + } + + .scope-search { + position: absolute; + right: ${theme.gridUnit * 4}px; + top: ${theme.gridUnit * 4}px; + border-radius: ${theme.borderRadius}px; + border: 1px solid ${theme.colors.grayscale.light2}; + padding: ${theme.gridUnit}px ${theme.gridUnit * 2}px; + font-size: ${theme.typography.sizes.m}px; + outline: none; + + &:focus { + border: 1px solid ${theme.colors.primary.base}; + } + } + } + `} +`; + const ActionsContainer = styled.div` ${({ theme }) => ` height: ${theme.gridUnit * 16}px; @@ -496,28 +758,28 @@ export default class FilterScopeSelector extends React.PureComponent { const { showSelector } = this.state; return ( - <div className="filter-scope-container"> - <div className="filter-scope-header"> + <ScopeContainer> + <ScopeHeader> <h4>{t('Configure filter scopes')}</h4> {showSelector && this.renderEditingFiltersName()} - </div> + </ScopeHeader> - <div className="filter-scope-body"> + <ScopeBody className="filter-scope-body"> {!showSelector ? ( <div className="warning-message"> {t('There are no filters in this dashboard.')} </div> ) : ( - <div className="filters-scope-selector"> + <ScopeSelector className="filters-scope-selector"> <div className={cx('filter-field-pane multi-edit-mode')}> {this.renderFilterFieldList()} </div> <div className="filter-scope-pane multi-edit-mode"> {this.renderFilterScopeTree()} </div> - </div> + </ScopeSelector> )} - </div> + </ScopeBody> <ActionsContainer> <Button buttonSize="small" onClick={this.onClose}> @@ -533,7 +795,7 @@ export default class FilterScopeSelector extends React.PureComponent { </Button> )} </ActionsContainer> - </div> + </ScopeContainer> ); } } diff --git a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx index fc3f6d39b34a0..89d4fb94ce7cf 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx @@ -19,8 +19,15 @@ import cx from 'classnames'; import React from 'react'; import PropTypes from 'prop-types'; -import { styled, t, logging } from '@superset-ui/core'; +import { + styled, + t, + logging, + isFeatureEnabled, + FeatureFlag, +} from '@superset-ui/core'; import { isEqual } from 'lodash'; +import { withRouter } from 'react-router-dom'; import { exportChart, mountExploreUrl } from 'src/explore/exploreUtils'; import ChartContainer from 'src/components/Chart/ChartContainer'; @@ -63,7 +70,11 @@ const propTypes = { sliceName: PropTypes.string.isRequired, timeout: PropTypes.number.isRequired, maxRows: PropTypes.number.isRequired, - filterboxMigrationState: FILTER_BOX_MIGRATION_STATES, + filterboxMigrationState: PropTypes.oneOf( + Object.keys(FILTER_BOX_MIGRATION_STATES).map( + key => FILTER_BOX_MIGRATION_STATES[key], + ), + ), // all active filter fields in dashboard filters: PropTypes.object.isRequired, refreshChart: PropTypes.func.isRequired, @@ -85,6 +96,8 @@ const propTypes = { filterState: PropTypes.object, postTransformProps: PropTypes.func, datasetsStatus: PropTypes.oneOf(['loading', 'error', 'complete']), + isInView: PropTypes.bool, + emitCrossFilters: PropTypes.bool, }; const defaultProps = { @@ -102,6 +115,15 @@ const SHOULD_UPDATE_ON_PROP_CHANGES = Object.keys(propTypes).filter( const OVERFLOWABLE_VIZ_TYPES = new Set(['filter_box']); const DEFAULT_HEADER_HEIGHT = 22; +const ChartWrapper = styled.div` + overflow: hidden; + position: relative; + + &.dashboard-chart--overflowable { + overflow: visible; + } +`; + const ChartOverlay = styled.div` position: absolute; top: 0; @@ -120,7 +142,7 @@ const SliceContainer = styled.div` max-height: 100%; `; -export default class Chart extends React.Component { +class Chart extends React.Component { constructor(props) { super(props); this.state = { @@ -155,6 +177,14 @@ export default class Chart extends React.Component { return true; } + // allow chart to update if the status changed and the previous status was loading. + if ( + this.props?.chart?.chartStatus !== nextProps?.chart?.chartStatus && + this.props?.chart?.chartStatus === 'loading' + ) { + return true; + } + // allow chart update/re-render only if visible: // under selected tab or no tab layout if (nextProps.isComponentVisible) { @@ -170,7 +200,9 @@ export default class Chart extends React.Component { if ( nextProps.width !== this.props.width || - nextProps.height !== this.props.height + nextProps.height !== this.props.height || + nextProps.width !== this.state.width || + nextProps.height !== this.state.height ) { clearTimeout(this.resizeTimeout); this.resizeTimeout = setTimeout(this.resize, RESIZE_TIMEOUT); @@ -179,11 +211,20 @@ export default class Chart extends React.Component { for (let i = 0; i < SHOULD_UPDATE_ON_PROP_CHANGES.length; i += 1) { const prop = SHOULD_UPDATE_ON_PROP_CHANGES[i]; // use deep objects equality comparison to prevent - // unneccessary updates when objects references change + // unnecessary updates when objects references change if (!areObjectsEqual(nextProps[prop], this.props[prop])) { return true; } } + } else if ( + // chart should re-render if color scheme or label color was changed + nextProps.formData?.color_scheme !== this.props.formData?.color_scheme || + !areObjectsEqual( + nextProps.formData?.label_colors, + this.props.formData?.label_colors, + ) + ) { + return true; } // `cacheBusterProp` is jected by react-hot-loader @@ -270,7 +311,9 @@ export default class Chart extends React.Component { }); }; - onExploreChart = async () => { + onExploreChart = async clickEvent => { + const isOpenInNewTab = + clickEvent.shiftKey || clickEvent.ctrlKey || clickEvent.metaKey; try { const lastTabId = window.localStorage.getItem('last_tab_id'); const nextTabId = lastTabId @@ -287,7 +330,14 @@ export default class Chart extends React.Component { [URL_PARAMS.formDataKey.name]: key, [URL_PARAMS.sliceId.name]: this.props.slice.slice_id, }); - window.open(url, '_blank', 'noreferrer'); + if ( + isFeatureEnabled(FeatureFlag.DASHBOARD_EDIT_CHART_IN_NEW_TAB) || + isOpenInNewTab + ) { + window.open(url, '_blank', 'noreferrer'); + } else { + this.props.history.push(url); + } } catch (error) { logging.error(error); this.props.addDangerToast(t('An error occurred while opening Explore')); @@ -358,6 +408,9 @@ export default class Chart extends React.Component { filterboxMigrationState, postTransformProps, datasetsStatus, + isInView, + emitCrossFilters, + logEvent, } = this.props; const { width } = this.state; @@ -387,6 +440,7 @@ export default class Chart extends React.Component { filterId: id, }) : {}; + return ( <SliceContainer className="chart-slice" @@ -407,6 +461,7 @@ export default class Chart extends React.Component { editMode={editMode} annotationQuery={chart.annotationQuery} logExploreChart={this.logExploreChart} + logEvent={logEvent} onExploreChart={this.onExploreChart} exportCSV={this.exportCSV} exportFullCSV={this.exportFullCSV} @@ -445,7 +500,7 @@ export default class Chart extends React.Component { /> )} - <div + <ChartWrapper className={cx( 'dashboard-chart', isOverflowable && 'dashboard-chart--overflowable', @@ -487,8 +542,10 @@ export default class Chart extends React.Component { filterboxMigrationState={filterboxMigrationState} postTransformProps={postTransformProps} datasetsStatus={datasetsStatus} + isInView={isInView} + emitCrossFilters={emitCrossFilters} /> - </div> + </ChartWrapper> </SliceContainer> ); } @@ -496,3 +553,5 @@ export default class Chart extends React.Component { Chart.propTypes = propTypes; Chart.defaultProps = defaultProps; + +export default withRouter(Chart); diff --git a/superset-frontend/src/dashboard/components/gridComponents/Chart.test.jsx b/superset-frontend/src/dashboard/components/gridComponents/Chart.test.jsx index 59cbce2090354..a3851a73b3e94 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Chart.test.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Chart.test.jsx @@ -40,7 +40,7 @@ describe('Chart', () => { // from redux maxRows: 666, chart: chartQueries[queryId], - formData: chartQueries[queryId].formData, + formData: chartQueries[queryId].form_data, datasource: mockDatasource[sliceEntities.slices[queryId].datasource], slice: { ...sliceEntities.slices[queryId], @@ -72,7 +72,9 @@ describe('Chart', () => { }; function setup(overrideProps) { - const wrapper = shallow(<Chart {...props} {...overrideProps} />); + const wrapper = shallow( + <Chart.WrappedComponent {...props} {...overrideProps} />, + ); return wrapper; } @@ -94,7 +96,10 @@ describe('Chart', () => { }); it('should calculate the description height if it has one and isExpanded=true', () => { - const spy = jest.spyOn(Chart.prototype, 'getDescriptionHeight'); + const spy = jest.spyOn( + Chart.WrappedComponent.prototype, + 'getDescriptionHeight', + ); const wrapper = setup({ isExpanded: true }); expect(wrapper.find('.slice_description')).toExist(); diff --git a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.jsx b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.jsx deleted file mode 100644 index 2363b1610e4fa..0000000000000 --- a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.jsx +++ /dev/null @@ -1,420 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import PropTypes from 'prop-types'; -import cx from 'classnames'; -import { useTheme } from '@superset-ui/core'; -import { useSelector, connect } from 'react-redux'; - -import { getChartIdsInFilterBoxScope } from 'src/dashboard/util/activeDashboardFilters'; -import Chart from 'src/dashboard/containers/Chart'; -import AnchorLink from 'src/dashboard/components/AnchorLink'; -import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton'; -import DragDroppable from 'src/dashboard/components/dnd/DragDroppable'; -import HoverMenu from 'src/dashboard/components/menu/HoverMenu'; -import ResizableContainer from 'src/dashboard/components/resizable/ResizableContainer'; -import getChartAndLabelComponentIdFromPath from 'src/dashboard/util/getChartAndLabelComponentIdFromPath'; -import { componentShape } from 'src/dashboard/util/propShapes'; -import { COLUMN_TYPE, ROW_TYPE } from 'src/dashboard/util/componentTypes'; -import { - GRID_BASE_UNIT, - GRID_GUTTER_SIZE, - GRID_MIN_COLUMN_COUNT, - GRID_MIN_ROW_UNITS, -} from 'src/dashboard/util/constants'; - -const CHART_MARGIN = 32; - -const propTypes = { - id: PropTypes.string.isRequired, - parentId: PropTypes.string.isRequired, - dashboardId: PropTypes.number.isRequired, - component: componentShape.isRequired, - parentComponent: componentShape.isRequired, - getComponentById: PropTypes.func.isRequired, - index: PropTypes.number.isRequired, - depth: PropTypes.number.isRequired, - editMode: PropTypes.bool.isRequired, - directPathToChild: PropTypes.arrayOf(PropTypes.string), - directPathLastUpdated: PropTypes.number, - focusedFilterScope: PropTypes.object, - fullSizeChartId: PropTypes.oneOf([PropTypes.number, null]), - - // grid related - availableColumnCount: PropTypes.number.isRequired, - columnWidth: PropTypes.number.isRequired, - onResizeStart: PropTypes.func.isRequired, - onResize: PropTypes.func.isRequired, - onResizeStop: PropTypes.func.isRequired, - - // dnd - deleteComponent: PropTypes.func.isRequired, - updateComponents: PropTypes.func.isRequired, - handleComponentDrop: PropTypes.func.isRequired, - setFullSizeChartId: PropTypes.func.isRequired, - postAddSliceFromDashboard: PropTypes.func, -}; - -const defaultProps = { - directPathToChild: [], - directPathLastUpdated: 0, -}; - -/** - * Selects the chart scope of the filter input that has focus. - * - * @returns {{chartId: number, scope: { scope: string[], immune: string[] }} | null } - * the scope of the currently focused filter, if any - */ -function selectFocusedFilterScope(dashboardState, dashboardFilters) { - if (!dashboardState.focusedFilterField) return null; - const { chartId, column } = dashboardState.focusedFilterField; - return { - chartId, - scope: dashboardFilters[chartId].scopes[column], - }; -} - -/** - * Renders any styles necessary to highlight the chart's relationship to the focused filter. - * - * If there is no focused filter scope (i.e. most of the time), this will be just a pass-through. - * - * If the chart is outside the scope of the focused filter, dims the chart. - * - * If the chart is in the scope of the focused filter, - * renders a highlight around the chart. - * - * If ChartHolder were a function component, this could be implemented as a hook instead. - */ -const FilterFocusHighlight = React.forwardRef( - ({ chartId, ...otherProps }, ref) => { - const theme = useTheme(); - - const nativeFilters = useSelector(state => state.nativeFilters); - const dashboardState = useSelector(state => state.dashboardState); - const dashboardFilters = useSelector(state => state.dashboardFilters); - const focusedFilterScope = selectFocusedFilterScope( - dashboardState, - dashboardFilters, - ); - const focusedNativeFilterId = nativeFilters.focusedFilterId; - if (!(focusedFilterScope || focusedNativeFilterId)) { - return <div ref={ref} {...otherProps} />; - } - - // we use local styles here instead of a conditionally-applied class, - // because adding any conditional class to this container - // causes performance issues in Chrome. - - // default to the "de-emphasized" state - const unfocusedChartStyles = { opacity: 0.3, pointerEvents: 'none' }; - const focusedChartStyles = { - borderColor: theme.colors.primary.light2, - opacity: 1, - boxShadow: `0px 0px ${theme.gridUnit * 2}px ${theme.colors.primary.base}`, - pointerEvents: 'auto', - }; - - if (focusedNativeFilterId) { - if ( - nativeFilters.filters[focusedNativeFilterId]?.chartsInScope?.includes( - chartId, - ) - ) { - return <div ref={ref} style={focusedChartStyles} {...otherProps} />; - } - } else if ( - chartId === focusedFilterScope.chartId || - getChartIdsInFilterBoxScope({ - filterScope: focusedFilterScope.scope, - }).includes(chartId) - ) { - return <div ref={ref} style={focusedChartStyles} {...otherProps} />; - } - - // inline styles are used here due to a performance issue when adding/changing a class, which causes a reflow - return <div ref={ref} style={unfocusedChartStyles} {...otherProps} />; - }, -); - -class ChartHolder extends React.Component { - static renderInFocusCSS(columnName) { - return ( - <style> - {`label[for=${columnName}] + .Select .Select__control { - border-color: #00736a; - transition: border-color 1s ease-in-out; - }`} - </style> - ); - } - - static getDerivedStateFromProps(props, state) { - const { component, directPathToChild, directPathLastUpdated } = props; - const { label: columnName, chart: chartComponentId } = - getChartAndLabelComponentIdFromPath(directPathToChild); - - if ( - directPathLastUpdated !== state.directPathLastUpdated && - component.id === chartComponentId - ) { - return { - outlinedComponentId: component.id, - outlinedColumnName: columnName, - directPathLastUpdated, - }; - } - return null; - } - - constructor(props) { - super(props); - this.state = { - isFocused: false, - outlinedComponentId: null, - outlinedColumnName: null, - directPathLastUpdated: 0, - extraControls: {}, - }; - - this.handleChangeFocus = this.handleChangeFocus.bind(this); - this.handleDeleteComponent = this.handleDeleteComponent.bind(this); - this.handleUpdateSliceName = this.handleUpdateSliceName.bind(this); - this.handleToggleFullSize = this.handleToggleFullSize.bind(this); - this.handleExtraControl = this.handleExtraControl.bind(this); - this.handlePostTransformProps = this.handlePostTransformProps.bind(this); - } - - componentDidMount() { - this.hideOutline({}, this.state); - } - - componentDidUpdate(prevProps, prevState) { - this.hideOutline(prevState, this.state); - } - - hideOutline(prevState, state) { - const { outlinedComponentId: timerKey } = state; - const { outlinedComponentId: prevTimerKey } = prevState; - - // because of timeout, there might be multiple charts showing outline - if (!!timerKey && !prevTimerKey) { - setTimeout(() => { - this.setState(() => ({ - outlinedComponentId: null, - outlinedColumnName: null, - })); - }, 2000); - } - } - - handleChangeFocus(nextFocus) { - this.setState(() => ({ isFocused: nextFocus })); - } - - handleDeleteComponent() { - const { deleteComponent, id, parentId } = this.props; - deleteComponent(id, parentId); - } - - handleUpdateSliceName(nextName) { - const { component, updateComponents } = this.props; - updateComponents({ - [component.id]: { - ...component, - meta: { - ...component.meta, - sliceNameOverride: nextName, - }, - }, - }); - } - - handleToggleFullSize() { - const { component, fullSizeChartId, setFullSizeChartId } = this.props; - const { chartId } = component.meta; - const isFullSize = fullSizeChartId === chartId; - setFullSizeChartId(isFullSize ? null : chartId); - } - - handleExtraControl(name, value) { - this.setState(prevState => ({ - extraControls: { - ...prevState.extraControls, - [name]: value, - }, - })); - } - - handlePostTransformProps(props) { - this.props.postAddSliceFromDashboard(); - return props; - } - - render() { - const { isFocused, extraControls } = this.state; - const { - component, - parentComponent, - index, - depth, - availableColumnCount, - columnWidth, - onResizeStart, - onResize, - onResizeStop, - handleComponentDrop, - editMode, - isComponentVisible, - dashboardId, - fullSizeChartId, - getComponentById = () => undefined, - } = this.props; - - const { chartId } = component.meta; - const isFullSize = fullSizeChartId === chartId; - - // inherit the size of parent columns - const columnParentWidth = getComponentById( - parentComponent.parents?.find(parent => parent.startsWith(COLUMN_TYPE)), - )?.meta?.width; - let widthMultiple = component.meta.width || GRID_MIN_COLUMN_COUNT; - if (parentComponent.type === COLUMN_TYPE) { - widthMultiple = parentComponent.meta.width || GRID_MIN_COLUMN_COUNT; - } else if (columnParentWidth && widthMultiple > columnParentWidth) { - widthMultiple = columnParentWidth; - } - - let chartWidth = 0; - let chartHeight = 0; - - if (isFullSize) { - chartWidth = window.innerWidth - CHART_MARGIN; - chartHeight = window.innerHeight - CHART_MARGIN; - } else { - chartWidth = Math.floor( - widthMultiple * columnWidth + - (widthMultiple - 1) * GRID_GUTTER_SIZE - - CHART_MARGIN, - ); - chartHeight = Math.floor( - component.meta.height * GRID_BASE_UNIT - CHART_MARGIN, - ); - } - - return ( - <DragDroppable - component={component} - parentComponent={parentComponent} - orientation={parentComponent.type === ROW_TYPE ? 'column' : 'row'} - index={index} - depth={depth} - onDrop={handleComponentDrop} - disableDragDrop={isFocused} - editMode={editMode} - > - {({ dropIndicatorProps, dragSourceRef }) => ( - <ResizableContainer - id={component.id} - adjustableWidth={parentComponent.type === ROW_TYPE} - adjustableHeight - widthStep={columnWidth} - widthMultiple={widthMultiple} - heightStep={GRID_BASE_UNIT} - heightMultiple={component.meta.height} - minWidthMultiple={GRID_MIN_COLUMN_COUNT} - minHeightMultiple={GRID_MIN_ROW_UNITS} - maxWidthMultiple={availableColumnCount + widthMultiple} - onResizeStart={onResizeStart} - onResize={onResize} - onResizeStop={onResizeStop} - editMode={editMode} - > - <FilterFocusHighlight - chartId={chartId} - ref={dragSourceRef} - data-test="dashboard-component-chart-holder" - className={cx( - 'dashboard-component', - 'dashboard-component-chart-holder', - // The following class is added to support custom dashboard styling via the CSS editor - `dashboard-chart-id-${chartId}`, - this.state.outlinedComponentId ? 'fade-in' : 'fade-out', - isFullSize && 'full-size', - )} - > - {!editMode && ( - <AnchorLink - id={component.id} - scrollIntoView={ - this.state.outlinedComponentId === component.id - } - /> - )} - {!!this.state.outlinedComponentId && - ChartHolder.renderInFocusCSS(this.state.outlinedColumnName)} - <Chart - componentId={component.id} - id={component.meta.chartId} - dashboardId={dashboardId} - width={chartWidth} - height={chartHeight} - sliceName={ - component.meta.sliceNameOverride || - component.meta.sliceName || - '' - } - updateSliceName={this.handleUpdateSliceName} - isComponentVisible={isComponentVisible} - handleToggleFullSize={this.handleToggleFullSize} - isFullSize={isFullSize} - setControlValue={this.handleExtraControl} - extraControls={extraControls} - postTransformProps={this.handlePostTransformProps} - /> - {editMode && ( - <HoverMenu position="top"> - <div data-test="dashboard-delete-component-button"> - <DeleteComponentButton - onDelete={this.handleDeleteComponent} - /> - </div> - </HoverMenu> - )} - </FilterFocusHighlight> - - {dropIndicatorProps && <div {...dropIndicatorProps} />} - </ResizableContainer> - )} - </DragDroppable> - ); - } -} - -ChartHolder.propTypes = propTypes; -ChartHolder.defaultProps = defaultProps; - -function mapStateToProps(state) { - return { - directPathToChild: state.dashboardState.directPathToChild, - directPathLastUpdated: state.dashboardState.directPathLastUpdated, - }; -} -export default connect(mapStateToProps)(ChartHolder); diff --git a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.jsx b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.jsx deleted file mode 100644 index 0c46b16de471b..0000000000000 --- a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.jsx +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { Provider } from 'react-redux'; -import React from 'react'; -import { styledMount as mount } from 'spec/helpers/theming'; -import sinon from 'sinon'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; - -import Chart from 'src/dashboard/containers/Chart'; -import ChartHolderConnected from 'src/dashboard/components/gridComponents/ChartHolder'; -import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton'; -import DragDroppable from 'src/dashboard/components/dnd/DragDroppable'; -import HoverMenu from 'src/dashboard/components/menu/HoverMenu'; -import ResizableContainer from 'src/dashboard/components/resizable/ResizableContainer'; - -import { getMockStore } from 'spec/fixtures/mockStore'; -import { sliceId } from 'spec/fixtures/mockChartQueries'; -import dashboardInfo from 'spec/fixtures/mockDashboardInfo'; -import { nativeFilters } from 'spec/fixtures/mockNativeFilters'; -import { dashboardLayout as mockLayout } from 'spec/fixtures/mockDashboardLayout'; -import { sliceEntitiesForChart } from 'spec/fixtures/mockSliceEntities'; -import { initialState } from 'src/SqlLab/fixtures'; - -describe('ChartHolder', () => { - const props = { - id: String(sliceId), - dashboardId: dashboardInfo.id, - parentId: 'ROW_ID', - component: mockLayout.present.CHART_ID, - depth: 2, - parentComponent: mockLayout.present.ROW_ID, - index: 0, - editMode: false, - availableColumnCount: 12, - columnWidth: 50, - onResizeStart() {}, - onResize() {}, - onResizeStop() {}, - handleComponentDrop() {}, - updateComponents() {}, - deleteComponent() {}, - nativeFilters: nativeFilters.filters, - }; - - function setup(overrideProps) { - const mockStore = getMockStore({ - ...initialState, - sliceEntities: sliceEntitiesForChart, - }); - - // We have to wrap provide DragDropContext for the underlying DragDroppable - // otherwise we cannot assert on DragDroppable children - const wrapper = mount( - <Provider store={mockStore}> - <DndProvider backend={HTML5Backend}> - <ChartHolderConnected {...props} {...overrideProps} /> - </DndProvider> - </Provider>, - ); - return wrapper; - } - - it('should render a DragDroppable', () => { - const wrapper = setup(); - expect(wrapper.find(DragDroppable)).toExist(); - }); - - it('should render a ResizableContainer', () => { - const wrapper = setup(); - expect(wrapper.find(ResizableContainer)).toExist(); - }); - - it('should only have an adjustableWidth if its parent is a Row', () => { - let wrapper = setup(); - expect(wrapper.find(ResizableContainer).prop('adjustableWidth')).toBe(true); - - wrapper = setup({ ...props, parentComponent: mockLayout.present.CHART_ID }); - expect(wrapper.find(ResizableContainer).prop('adjustableWidth')).toBe( - false, - ); - }); - - it('should pass correct props to ResizableContainer', () => { - const wrapper = setup(); - const resizableProps = wrapper.find(ResizableContainer).props(); - expect(resizableProps.widthStep).toBe(props.columnWidth); - expect(resizableProps.widthMultiple).toBe(props.component.meta.width); - expect(resizableProps.heightMultiple).toBe(props.component.meta.height); - expect(resizableProps.maxWidthMultiple).toBe( - props.component.meta.width + props.availableColumnCount, - ); - }); - - it('should render a div with class "dashboard-component-chart-holder"', () => { - const wrapper = setup(); - expect(wrapper.find('.dashboard-component-chart-holder')).toExist(); - }); - - it('should render a Chart', () => { - const wrapper = setup(); - expect(wrapper.find(Chart)).toExist(); - }); - - it('should render a HoverMenu with DeleteComponentButton in editMode', () => { - let wrapper = setup(); - expect(wrapper.find(HoverMenu)).not.toExist(); - expect(wrapper.find(DeleteComponentButton)).not.toExist(); - - // we cannot set props on the Divider because of the WithDragDropContext wrapper - wrapper = setup({ editMode: true }); - expect(wrapper.find(HoverMenu)).toExist(); - expect(wrapper.find(DeleteComponentButton)).toExist(); - }); - - it('should call deleteComponent when deleted', () => { - const deleteComponent = sinon.spy(); - const wrapper = setup({ editMode: true, deleteComponent }); - wrapper.find(DeleteComponentButton).simulate('click'); - expect(deleteComponent.callCount).toBe(1); - }); -}); diff --git a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx index 09cd34738e5ee..4470d616fc591 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx +++ b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx @@ -18,25 +18,40 @@ */ import React from 'react'; +import { combineReducers, createStore, applyMiddleware, compose } from 'redux'; +import { Provider } from 'react-redux'; +import thunk from 'redux-thunk'; +import sinon from 'sinon'; +import userEvent from '@testing-library/user-event'; +import mockState from 'spec/fixtures/mockState'; +import reducerIndex from 'spec/helpers/reducerIndex'; import { sliceId as chartId } from 'spec/fixtures/mockChartQueries'; +import { + screen, + render, + waitFor, + fireEvent, +} from 'spec/helpers/testing-library'; import { nativeFiltersInfo } from 'src/dashboard/fixtures/mockNativeFilters'; import newComponentFactory from 'src/dashboard/util/newComponentFactory'; -import { getMockStore } from 'spec/fixtures/mockStore'; import { initialState } from 'src/SqlLab/fixtures'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; -import { Provider } from 'react-redux'; -import { screen, render } from 'spec/helpers/testing-library'; -import { CHART_TYPE, ROW_TYPE } from '../../util/componentTypes'; -import { ChartHolder } from './index'; +import { SET_DIRECT_PATH } from 'src/dashboard/actions/dashboardState'; +import { CHART_TYPE, COLUMN_TYPE, ROW_TYPE } from '../../util/componentTypes'; +import ChartHolder, { CHART_MARGIN } from './ChartHolder'; +import { GRID_BASE_UNIT, GRID_GUTTER_SIZE } from '../../util/constants'; + +const DEFAULT_HEADER_HEIGHT = 22; describe('ChartHolder', () => { + let scrollViewBase: any; + const defaultProps = { component: { ...newComponentFactory(CHART_TYPE), - id: 'CHART_ID', + id: 'CHART-ID', parents: ['ROOT_ID', 'TABS_ID', 'TAB_ID', 'ROW_ID'], meta: { + uuid: `CHART-${chartId}`, chartId, width: 3, height: 10, @@ -50,7 +65,7 @@ describe('ChartHolder', () => { }, index: 0, depth: 0, - id: 'CHART_ID', + id: 'CHART-ID', parentId: 'ROW_ID', availableColumnCount: 12, columnWidth: 300, @@ -67,18 +82,31 @@ describe('ChartHolder', () => { fullSizeChartId: chartId, setFullSizeChartId: () => {}, }; - const mockStore = getMockStore({ - ...initialState, + + beforeAll(() => { + scrollViewBase = window.HTMLElement.prototype.scrollIntoView; + window.HTMLElement.prototype.scrollIntoView = () => {}; }); - const renderWrapper = () => - render( - <Provider store={mockStore}> - <DndProvider backend={HTML5Backend}> - <ChartHolder {...defaultProps} />{' '} - </DndProvider> - </Provider>, + + afterAll(() => { + window.HTMLElement.prototype.scrollIntoView = scrollViewBase; + }); + + const createMockStore = (customState: any = {}) => + createStore( + combineReducers(reducerIndex), + { ...mockState, ...(initialState as any), ...customState }, + compose(applyMiddleware(thunk)), ); + const renderWrapper = (store = createMockStore(), props: any = {}) => + render(<ChartHolder {...defaultProps} {...props} />, { + useRouter: true, + useDnd: true, + useRedux: true, + store, + }); + it('should render empty state', async () => { renderWrapper(); @@ -92,4 +120,315 @@ describe('ChartHolder', () => { ).not.toBeInTheDocument(); // description should display only in Explore view expect(screen.getByAltText('empty')).toBeVisible(); }); + + it('should render anchor link when not editing', async () => { + const store = createMockStore(); + const { rerender } = renderWrapper(store, { editMode: false }); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toBeVisible(); + + expect( + screen + .getByTestId('dashboard-component-chart-holder') + .getElementsByClassName('anchor-link-container').length, + ).toEqual(1); + + rerender( + <Provider store={store}> + <ChartHolder {...defaultProps} editMode isInView /> + </Provider>, + ); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toBeVisible(); + + expect( + screen + .getByTestId('dashboard-component-chart-holder') + .getElementsByClassName('anchor-link-container').length, + ).toEqual(0); + }); + + it('should highlight when path matches', async () => { + const store = createMockStore({ + dashboardState: { + ...mockState.dashboardState, + directPathToChild: ['CHART-ID'], + }, + }); + renderWrapper(store); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toBeVisible(); + + expect(screen.getByTestId('dashboard-component-chart-holder')).toHaveClass( + 'fade-out', + ); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).not.toHaveClass('fade-in'); + + store.dispatch({ type: SET_DIRECT_PATH, path: ['CHART-ID'] }); + + await waitFor(() => { + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).not.toHaveClass('fade-out'); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toHaveClass('fade-in'); + }); + + await waitFor( + () => { + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toHaveClass('fade-out'); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).not.toHaveClass('fade-in'); + }, + { timeout: 5000 }, + ); + }); + + it('should calculate the default widthMultiple', async () => { + const widthMultiple = 5; + renderWrapper(createMockStore(), { + editMode: true, + component: { + ...defaultProps.component, + meta: { + ...defaultProps.component.meta, + width: widthMultiple, + }, + }, + }); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toBeVisible(); + + const resizeContainer = screen + .getByTestId('dragdroppable-object') + .getElementsByClassName('resizable-container')[0]; + + const { width: computedWidth } = getComputedStyle(resizeContainer); + const expectedWidth = + (defaultProps.columnWidth + GRID_GUTTER_SIZE) * widthMultiple - + GRID_GUTTER_SIZE; + + expect(computedWidth).toEqual(`${expectedWidth}px`); + }); + + it('should set the resizable width to auto when parent component type is column', async () => { + renderWrapper(createMockStore(), { + editMode: true, + parentComponent: { + ...newComponentFactory(COLUMN_TYPE), + id: 'ROW_ID', + children: ['COLUMN_ID'], + }, + }); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toBeVisible(); + + const resizeContainer = screen + .getByTestId('dragdroppable-object') + .getElementsByClassName('resizable-container')[0]; + + const { width: computedWidth } = getComputedStyle(resizeContainer); + + // the width is only adjustable if the parent component is row type + expect(computedWidth).toEqual('auto'); + }); + + it("should override the widthMultiple if there's a column in the parent chain whose width is less than the chart", async () => { + const widthMultiple = 10; + const parentColumnWidth = 6; + renderWrapper(createMockStore(), { + editMode: true, + component: { + ...defaultProps.component, + meta: { + ...defaultProps.component.meta, + width: widthMultiple, + }, + }, + // Return the first column in the chain + getComponentById: () => + newComponentFactory(COLUMN_TYPE, { width: parentColumnWidth }), + }); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toBeVisible(); + + const resizeContainer = screen + .getByTestId('dragdroppable-object') + .getElementsByClassName('resizable-container')[0]; + + const { width: computedWidth } = getComputedStyle(resizeContainer); + const expectedWidth = + (defaultProps.columnWidth + GRID_GUTTER_SIZE) * parentColumnWidth - + GRID_GUTTER_SIZE; + + expect(computedWidth).toEqual(`${expectedWidth}px`); + }); + + it('should calculate the chartWidth', async () => { + const widthMultiple = 7; + const columnWidth = 250; + renderWrapper(createMockStore(), { + fullSizeChartId: null, + component: { + ...defaultProps.component, + meta: { + ...defaultProps.component.meta, + width: widthMultiple, + }, + }, + columnWidth, + }); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toBeVisible(); + + const container = screen.getByTestId('chart-container'); + + const computedWidth = parseInt(container.getAttribute('width') || '0', 10); + const expectedWidth = Math.floor( + widthMultiple * columnWidth + + (widthMultiple - 1) * GRID_GUTTER_SIZE - + CHART_MARGIN, + ); + + expect(computedWidth).toEqual(expectedWidth); + }); + + it('should calculate the chartWidth on full screen mode', async () => { + const widthMultiple = 7; + const columnWidth = 250; + renderWrapper(createMockStore(), { + component: { + ...defaultProps.component, + meta: { + ...defaultProps.component.meta, + width: widthMultiple, + }, + }, + columnWidth, + }); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toBeVisible(); + + const container = screen.getByTestId('chart-container'); + + const computedWidth = parseInt(container.getAttribute('width') || '0', 10); + const expectedWidth = window.innerWidth - CHART_MARGIN; + + expect(computedWidth).toEqual(expectedWidth); + }); + + it('should calculate the chartHeight', async () => { + const heightMultiple = 12; + renderWrapper(createMockStore(), { + fullSizeChartId: null, + component: { + ...defaultProps.component, + meta: { + ...defaultProps.component.meta, + height: heightMultiple, + }, + }, + }); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toBeVisible(); + + const container = screen.getByTestId('chart-container'); + + const computedWidth = parseInt(container.getAttribute('height') || '0', 10); + const expectedWidth = Math.floor( + heightMultiple * GRID_BASE_UNIT - CHART_MARGIN - DEFAULT_HEADER_HEIGHT, + ); + + expect(computedWidth).toEqual(expectedWidth); + }); + + it('should calculate the chartHeight on full screen mode', async () => { + const heightMultiple = 12; + renderWrapper(createMockStore(), { + component: { + ...defaultProps.component, + meta: { + ...defaultProps.component.meta, + height: heightMultiple, + }, + }, + }); + + expect( + screen.getByTestId('dashboard-component-chart-holder'), + ).toBeVisible(); + + const container = screen.getByTestId('chart-container'); + + const computedWidth = parseInt(container.getAttribute('height') || '0', 10); + const expectedWidth = + window.innerHeight - CHART_MARGIN - DEFAULT_HEADER_HEIGHT; + + expect(computedWidth).toEqual(expectedWidth); + }); + + it('should call deleteComponent when deleted', async () => { + const deleteComponent = sinon.spy(); + const store = createMockStore(); + const { rerender } = renderWrapper(store, { + editMode: false, + fullSizeChartId: null, + deleteComponent, + }); + + expect( + screen.queryByTestId('dashboard-delete-component-button'), + ).not.toBeInTheDocument(); + + rerender( + <Provider store={store}> + <ChartHolder + {...defaultProps} + deleteComponent={deleteComponent} + fullSizeChartId={null} + editMode + isInView + /> + </Provider>, + ); + + expect( + screen.getByTestId('dashboard-delete-component-button'), + ).toBeInTheDocument(); + + userEvent.hover(screen.getByTestId('dashboard-component-chart-holder')); + + fireEvent.click( + screen.getByTestId('dashboard-delete-component-button') + .firstElementChild!, + ); + expect(deleteComponent.callCount).toBe(1); + }); }); diff --git a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.tsx b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.tsx new file mode 100644 index 0000000000000..a93f3b0b8db63 --- /dev/null +++ b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.tsx @@ -0,0 +1,334 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useState, useMemo, useCallback, useEffect } from 'react'; +import { ResizeCallback, ResizeStartCallback } from 're-resizable'; +import cx from 'classnames'; +import { useSelector } from 'react-redux'; +import { css } from '@superset-ui/core'; +import { LayoutItem, RootState } from 'src/dashboard/types'; +import AnchorLink from 'src/dashboard/components/AnchorLink'; +import Chart from 'src/dashboard/containers/Chart'; +import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton'; +import DragDroppable from 'src/dashboard/components/dnd/DragDroppable'; +import HoverMenu from 'src/dashboard/components/menu/HoverMenu'; +import ResizableContainer from 'src/dashboard/components/resizable/ResizableContainer'; +import getChartAndLabelComponentIdFromPath from 'src/dashboard/util/getChartAndLabelComponentIdFromPath'; +import useFilterFocusHighlightStyles from 'src/dashboard/util/useFilterFocusHighlightStyles'; +import { COLUMN_TYPE, ROW_TYPE } from 'src/dashboard/util/componentTypes'; +import { + GRID_BASE_UNIT, + GRID_GUTTER_SIZE, + GRID_MIN_COLUMN_COUNT, + GRID_MIN_ROW_UNITS, +} from 'src/dashboard/util/constants'; + +export const CHART_MARGIN = 32; + +interface ChartHolderProps { + id: string; + parentId: string; + dashboardId: number; + component: LayoutItem; + parentComponent: LayoutItem; + getComponentById?: (id?: string) => LayoutItem | undefined; + index: number; + depth: number; + editMode: boolean; + directPathLastUpdated?: number; + fullSizeChartId: number | null; + isComponentVisible: boolean; + + // grid related + availableColumnCount: number; + columnWidth: number; + onResizeStart: ResizeStartCallback; + onResize: ResizeCallback; + onResizeStop: ResizeCallback; + + // dnd + deleteComponent: (id: string, parentId: string) => void; + updateComponents: Function; + handleComponentDrop: (...args: unknown[]) => unknown; + setFullSizeChartId: (chartId: number | null) => void; + isInView: boolean; +} + +const fullSizeStyle = css` + && { + position: fixed; + z-index: 3000; + left: 0; + top: 0; + } +`; + +const ChartHolder: React.FC<ChartHolderProps> = ({ + id, + parentId, + component, + parentComponent, + index, + depth, + availableColumnCount, + columnWidth, + onResizeStart, + onResize, + onResizeStop, + editMode, + isComponentVisible, + dashboardId, + fullSizeChartId, + getComponentById = () => undefined, + deleteComponent, + updateComponents, + handleComponentDrop, + setFullSizeChartId, + isInView, +}) => { + const { chartId } = component.meta; + const isFullSize = fullSizeChartId === chartId; + + const focusHighlightStyles = useFilterFocusHighlightStyles(chartId); + const dashboardState = useSelector( + (state: RootState) => state.dashboardState, + ); + const [extraControls, setExtraControls] = useState<Record<string, unknown>>( + {}, + ); + const [outlinedComponentId, setOutlinedComponentId] = useState<string>(); + const [outlinedColumnName, setOutlinedColumnName] = useState<string>(); + const [currentDirectPathLastUpdated, setCurrentDirectPathLastUpdated] = + useState(0); + + const directPathToChild = useMemo( + () => dashboardState?.directPathToChild ?? [], + [dashboardState], + ); + + const directPathLastUpdated = useMemo( + () => dashboardState?.directPathLastUpdated ?? 0, + [dashboardState], + ); + + const infoFromPath = useMemo( + () => getChartAndLabelComponentIdFromPath(directPathToChild) as any, + [directPathToChild], + ); + + // Calculate if the chart should be outlined + useEffect(() => { + const { label: columnName, chart: chartComponentId } = infoFromPath; + + if ( + directPathLastUpdated !== currentDirectPathLastUpdated && + component.id === chartComponentId + ) { + setCurrentDirectPathLastUpdated(directPathLastUpdated); + setOutlinedComponentId(component.id); + setOutlinedColumnName(columnName); + } + }, [ + component, + currentDirectPathLastUpdated, + directPathLastUpdated, + infoFromPath, + ]); + + // Remove the chart outline after a defined time + useEffect(() => { + let timerId: NodeJS.Timeout | undefined; + if (outlinedComponentId) { + timerId = setTimeout(() => { + setOutlinedComponentId(undefined); + setOutlinedColumnName(undefined); + }, 2000); + } + + return () => { + if (timerId) { + clearTimeout(timerId); + } + }; + }, [outlinedComponentId]); + + const widthMultiple = useMemo(() => { + const columnParentWidth = getComponentById( + parentComponent.parents?.find(parent => parent.startsWith(COLUMN_TYPE)), + )?.meta?.width; + + let widthMultiple = component.meta.width || GRID_MIN_COLUMN_COUNT; + if (parentComponent.type === COLUMN_TYPE) { + widthMultiple = parentComponent.meta.width || GRID_MIN_COLUMN_COUNT; + } else if (columnParentWidth && widthMultiple > columnParentWidth) { + widthMultiple = columnParentWidth; + } + + return widthMultiple; + }, [ + component, + getComponentById, + parentComponent.meta.width, + parentComponent.parents, + parentComponent.type, + ]); + + const { chartWidth, chartHeight } = useMemo(() => { + let chartWidth = 0; + let chartHeight = 0; + + if (isFullSize) { + chartWidth = window.innerWidth - CHART_MARGIN; + chartHeight = window.innerHeight - CHART_MARGIN; + } else { + chartWidth = Math.floor( + widthMultiple * columnWidth + + (widthMultiple - 1) * GRID_GUTTER_SIZE - + CHART_MARGIN, + ); + chartHeight = Math.floor( + component.meta.height * GRID_BASE_UNIT - CHART_MARGIN, + ); + } + + return { + chartWidth, + chartHeight, + }; + }, [columnWidth, component, isFullSize, widthMultiple]); + + const handleDeleteComponent = useCallback(() => { + deleteComponent(id, parentId); + }, [deleteComponent, id, parentId]); + + const handleUpdateSliceName = useCallback( + (nextName: string) => { + updateComponents({ + [component.id]: { + ...component, + meta: { + ...component.meta, + sliceNameOverride: nextName, + }, + }, + }); + }, + [component, updateComponents], + ); + + const handleToggleFullSize = useCallback(() => { + setFullSizeChartId(isFullSize ? null : chartId); + }, [chartId, isFullSize, setFullSizeChartId]); + + const handleExtraControl = useCallback((name: string, value: unknown) => { + setExtraControls(current => ({ + ...current, + [name]: value, + })); + }, []); + + return ( + <DragDroppable + component={component} + parentComponent={parentComponent} + orientation={parentComponent.type === ROW_TYPE ? 'column' : 'row'} + index={index} + depth={depth} + onDrop={handleComponentDrop} + disableDragDrop={false} + editMode={editMode} + > + {({ dropIndicatorProps, dragSourceRef }) => ( + <ResizableContainer + id={component.id} + adjustableWidth={parentComponent.type === ROW_TYPE} + adjustableHeight + widthStep={columnWidth} + widthMultiple={widthMultiple} + heightStep={GRID_BASE_UNIT} + heightMultiple={component.meta.height} + minWidthMultiple={GRID_MIN_COLUMN_COUNT} + minHeightMultiple={GRID_MIN_ROW_UNITS} + maxWidthMultiple={availableColumnCount + widthMultiple} + onResizeStart={onResizeStart} + onResize={onResize} + onResizeStop={onResizeStop} + editMode={editMode} + > + <div + ref={dragSourceRef} + data-test="dashboard-component-chart-holder" + style={focusHighlightStyles} + css={isFullSize ? fullSizeStyle : undefined} + className={cx( + 'dashboard-component', + 'dashboard-component-chart-holder', + // The following class is added to support custom dashboard styling via the CSS editor + `dashboard-chart-id-${chartId}`, + outlinedComponentId ? 'fade-in' : 'fade-out', + )} + > + {!editMode && ( + <AnchorLink + id={component.id} + scrollIntoView={outlinedComponentId === component.id} + /> + )} + {!!outlinedComponentId && ( + <style> + {`label[for=${outlinedColumnName}] + .Select .Select__control { + border-color: #00736a; + transition: border-color 1s ease-in-out; + }`} + </style> + )} + <Chart + componentId={component.id} + id={component.meta.chartId} + dashboardId={dashboardId} + width={chartWidth} + height={chartHeight} + sliceName={ + component.meta.sliceNameOverride || + component.meta.sliceName || + '' + } + updateSliceName={handleUpdateSliceName} + isComponentVisible={isComponentVisible} + handleToggleFullSize={handleToggleFullSize} + isFullSize={isFullSize} + setControlValue={handleExtraControl} + extraControls={extraControls} + isInView={isInView} + /> + {editMode && ( + <HoverMenu position="top"> + <div data-test="dashboard-delete-component-button"> + <DeleteComponentButton onDelete={handleDeleteComponent} /> + </div> + </HoverMenu> + )} + </div> + {dropIndicatorProps && <div {...dropIndicatorProps} />} + </ResizableContainer> + )} + </DragDroppable> + ); +}; + +export default ChartHolder; diff --git a/superset-frontend/src/dashboard/components/gridComponents/Column.jsx b/superset-frontend/src/dashboard/components/gridComponents/Column.jsx index 90666d6d98836..1883531404f77 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Column.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Column.jsx @@ -19,6 +19,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; +import { css, styled, t } from '@superset-ui/core'; import Icons from 'src/components/Icons'; import DashboardComponent from 'src/dashboard/containers/DashboardComponent'; import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton'; @@ -58,6 +59,46 @@ const propTypes = { const defaultProps = {}; +const ColumnStyles = styled.div` + ${({ theme }) => css` + &.grid-column { + width: 100%; + position: relative; + + & > :not(.hover-menu):not(:last-child) { + margin-bottom: ${theme.gridUnit * 4}px; + } + } + + .dashboard--editing &:after { + content: ''; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 1; + pointer-events: none; + border: 1px dashed ${theme.colors.grayscale.light2}; + } + .dashboard--editing .resizable-container--resizing:hover > &:after, + .dashboard--editing .hover-menu:hover + &:after { + border: 1px dashed ${theme.colors.primary.base}; + z-index: 2; + } + `} +`; + +const emptyColumnContentStyles = theme => css` + min-height: ${theme.gridUnit * 25}px; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + color: ${theme.colors.text.label}; +`; + class Column extends React.PureComponent { constructor(props) { super(props); @@ -172,32 +213,32 @@ class Column extends React.PureComponent { /> </HoverMenu> )} - <div - className={cx( - 'grid-column', - columnItems.length === 0 && 'grid-column--empty', - backgroundStyle.className, - )} + <ColumnStyles + className={cx('grid-column', backgroundStyle.className)} > - {columnItems.map((componentId, itemIndex) => ( - <DashboardComponent - key={componentId} - id={componentId} - parentId={columnComponent.id} - depth={depth + 1} - index={itemIndex} - availableColumnCount={columnComponent.meta.width} - columnWidth={columnWidth} - onResizeStart={onResizeStart} - onResize={onResize} - onResizeStop={onResizeStop} - isComponentVisible={isComponentVisible} - onChangeTab={onChangeTab} - /> - ))} + {columnItems.length === 0 ? ( + <div css={emptyColumnContentStyles}>{t('Empty column')}</div> + ) : ( + columnItems.map((componentId, itemIndex) => ( + <DashboardComponent + key={componentId} + id={componentId} + parentId={columnComponent.id} + depth={depth + 1} + index={itemIndex} + availableColumnCount={columnComponent.meta.width} + columnWidth={columnWidth} + onResizeStart={onResizeStart} + onResize={onResize} + onResizeStop={onResizeStop} + isComponentVisible={isComponentVisible} + onChangeTab={onChangeTab} + /> + )) + )} {dropIndicatorProps && <div {...dropIndicatorProps} />} - </div> + </ColumnStyles> </WithPopoverMenu> </ResizableContainer> )} diff --git a/superset-frontend/src/dashboard/components/gridComponents/Column.test.jsx b/superset-frontend/src/dashboard/components/gridComponents/Column.test.jsx index a117d9082097c..72e89075b58c7 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Column.test.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Column.test.jsx @@ -20,6 +20,7 @@ import { Provider } from 'react-redux'; import React from 'react'; import { mount } from 'enzyme'; import sinon from 'sinon'; +import { MemoryRouter } from 'react-router-dom'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; @@ -71,9 +72,11 @@ describe('Column', () => { }); const wrapper = mount( <Provider store={mockStore}> - <DndProvider backend={HTML5Backend}> - <Column {...props} {...overrideProps} /> - </DndProvider> + <MemoryRouter> + <DndProvider backend={HTML5Backend}> + <Column {...props} {...overrideProps} /> + </DndProvider> + </MemoryRouter> </Provider>, { wrappingComponent: ThemeProvider, diff --git a/superset-frontend/src/dashboard/components/gridComponents/Divider.jsx b/superset-frontend/src/dashboard/components/gridComponents/Divider.jsx index 8be4fe8924851..078405be3e4a3 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Divider.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Divider.jsx @@ -18,6 +18,7 @@ */ import React from 'react'; import PropTypes from 'prop-types'; +import { css, styled } from '@superset-ui/core'; import DragDroppable from '../dnd/DragDroppable'; import HoverMenu from '../menu/HoverMenu'; @@ -36,6 +37,31 @@ const propTypes = { deleteComponent: PropTypes.func.isRequired, }; +const DividerLine = styled.div` + ${({ theme }) => css` + width: 100%; + padding: ${theme.gridUnit * 2}px 0; /* this is padding not margin to enable a larger mouse target */ + background-color: transparent; + + &:after { + content: ''; + height: 1px; + width: 100%; + background-color: ${theme.colors.grayscale.light2}; + display: block; + } + + div[draggable='true'] & { + cursor: move; + } + + .dashboard-component-tabs & { + padding-left: ${theme.gridUnit * 4}px; + padding-right: ${theme.gridUnit * 4}px; + } + `} +`; + class Divider extends React.PureComponent { constructor(props) { super(props); @@ -75,7 +101,7 @@ class Divider extends React.PureComponent { </HoverMenu> )} - <div className="dashboard-component dashboard-component-divider" /> + <DividerLine className="dashboard-component dashboard-component-divider" /> {dropIndicatorProps && <div {...dropIndicatorProps} />} </div> diff --git a/superset-frontend/src/dashboard/components/gridComponents/Header.jsx b/superset-frontend/src/dashboard/components/gridComponents/Header.jsx index 938a48bf099d9..253f377fc2f7d 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Header.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Header.jsx @@ -19,6 +19,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; +import { css, styled } from '@superset-ui/core'; import PopoverDropdown from 'src/components/PopoverDropdown'; import EditableTitle from 'src/components/EditableTitle'; @@ -55,6 +56,64 @@ const propTypes = { const defaultProps = {}; +const HeaderStyles = styled.div` + ${({ theme }) => css` + font-weight: ${theme.typography.weights.bold}; + width: 100%; + padding: ${theme.gridUnit * 4}px 0; + + &.header-small { + font-size: ${theme.typography.sizes.l}px; + } + + &.header-medium { + font-size: ${theme.typography.sizes.xl}px; + } + + &.header-large { + font-size: ${theme.typography.sizes.xxl}px; + } + + .dashboard--editing .dashboard-grid & { + &:after { + border: 1px dashed transparent; + content: ''; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 1; + pointer-events: none; + } + + &:hover:after { + border: 1px dashed ${theme.colors.primary.base}; + z-index: 2; + } + } + + .dashboard--editing .dragdroppable-row & { + cursor: move; + } + + /** + * grids add margin between items, so don't double pad within columns + * we'll not worry about double padding on top as it can serve as a visual separator + */ + .grid-column > :not(:last-child) & { + margin-bottom: ${theme.gridUnit * -4}px; + } + + .background--white &, + &.background--white, + .dashboard-component-tabs & { + padding-left: ${theme.gridUnit * 4}px; + padding-right: ${theme.gridUnit * 4}px; + } + `} +`; + class Header extends React.PureComponent { constructor(props) { super(props); @@ -154,7 +213,7 @@ class Header extends React.PureComponent { ]} editMode={editMode} > - <div + <HeaderStyles className={cx( 'dashboard-component', 'dashboard-component-header', @@ -178,7 +237,7 @@ class Header extends React.PureComponent { {!editMode && ( <AnchorLink id={component.id} dashboardId={dashboardId} /> )} - </div> + </HeaderStyles> </WithPopoverMenu> {dropIndicatorProps && <div {...dropIndicatorProps} />} diff --git a/superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx b/superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx index a6dfe4e2b84b5..9febfacf909dc 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx @@ -21,7 +21,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import cx from 'classnames'; -import { t, SafeMarkdown } from '@superset-ui/core'; +import { css, styled, t, SafeMarkdown } from '@superset-ui/core'; import { Logger, LOG_ACTIONS_RENDER_CHART } from 'src/logger/LogUtils'; import { MarkdownEditor } from 'src/components/AsyncAceEditor'; @@ -73,16 +73,48 @@ const propTypes = { const defaultProps = {}; -const MARKDOWN_PLACE_HOLDER = `# ✨Markdown -## ✨Markdown -### ✨Markdown +// TODO: localize +const MARKDOWN_PLACE_HOLDER = `# ✨Header 1 +## ✨Header 2 +### ✨Header 3 <br /> -Click here to edit [markdown](https://bit.ly/1dQOfRK)`; +Click here to learn more about [markdown formatting](https://bit.ly/1dQOfRK)`; const MARKDOWN_ERROR_MESSAGE = t('This markdown component has an error.'); +const MarkdownStyles = styled.div` + ${({ theme }) => css` + &.dashboard-markdown { + overflow: hidden; + + h4, + h5, + h6 { + font-weight: ${theme.typography.weights.normal}; + } + + h5 { + color: ${theme.colors.grayscale.base}; + } + + h6 { + font-size: ${theme.typography.sizes.s}px; + } + + .dashboard-component-chart-holder { + overflow-y: auto; + overflow-x: hidden; + } + + .dashboard--editing & { + cursor: move; + } + } + `} +`; + class Markdown extends React.PureComponent { constructor(props) { super(props); @@ -322,7 +354,7 @@ class Markdown extends React.PureComponent { ]} editMode={editMode} > - <div + <MarkdownStyles data-test="dashboard-markdown-editor" className={cx( 'dashboard-markdown', @@ -363,7 +395,7 @@ class Markdown extends React.PureComponent { : this.renderPreviewMode()} </div> </ResizableContainer> - </div> + </MarkdownStyles> {dropIndicatorProps && <div {...dropIndicatorProps} />} </WithPopoverMenu> )} diff --git a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx index b0037bf12322a..ae3db36d1dbf5 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx @@ -19,6 +19,13 @@ import React from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; +import { + css, + FeatureFlag, + isFeatureEnabled, + styled, + t, +} from '@superset-ui/core'; import DragDroppable from 'src/dashboard/components/dnd/DragDroppable'; import DragHandle from 'src/dashboard/components/dnd/DragHandle'; @@ -32,6 +39,7 @@ import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu'; import { componentShape } from 'src/dashboard/util/propShapes'; import backgroundStyleOptions from 'src/dashboard/util/backgroundStyleOptions'; import { BACKGROUND_TRANSPARENT } from 'src/dashboard/util/constants'; +import { isCurrentUserBot } from 'src/utils/isBot'; const propTypes = { id: PropTypes.string.isRequired, @@ -56,11 +64,42 @@ const propTypes = { updateComponents: PropTypes.func.isRequired, }; +const GridRow = styled.div` + ${({ theme }) => css` + position: relative; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: flex-start; + width: 100%; + height: fit-content; + + & > :not(:last-child):not(.hover-menu) { + margin-right: ${theme.gridUnit * 4}px; + } + + &.grid-row--empty { + min-height: ${theme.gridUnit * 25}px; + } + `} +`; + +const emptyRowContentStyles = theme => css` + position: absolute; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + color: ${theme.colors.text.label}; +`; + class Row extends React.PureComponent { constructor(props) { super(props); this.state = { isFocused: false, + isInView: false, }; this.handleDeleteComponent = this.handleDeleteComponent.bind(this); this.handleUpdateMeta = this.handleUpdateMeta.bind(this); @@ -69,6 +108,50 @@ class Row extends React.PureComponent { 'background', ); this.handleChangeFocus = this.handleChangeFocus.bind(this); + + this.containerRef = React.createRef(); + this.observerEnabler = null; + this.observerDisabler = null; + } + + // if chart not rendered - render it if it's less than 1 view height away from current viewport + // if chart rendered - remove it if it's more than 4 view heights away from current viewport + componentDidMount() { + if ( + isFeatureEnabled(FeatureFlag.DASHBOARD_VIRTUALIZATION) && + !isCurrentUserBot() + ) { + this.observerEnabler = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting && !this.state.isInView) { + this.setState({ isInView: true }); + } + }, + { + rootMargin: '100% 0px', + }, + ); + this.observerDisabler = new IntersectionObserver( + ([entry]) => { + if (!entry.isIntersecting && this.state.isInView) { + this.setState({ isInView: false }); + } + }, + { + rootMargin: '400% 0px', + }, + ); + const element = this.containerRef.current; + if (element) { + this.observerEnabler.observe(element); + this.observerDisabler.observe(element); + } + } + } + + componentWillUnmount() { + this.observerEnabler?.disconnect(); + this.observerDisabler?.disconnect(); } handleChangeFocus(nextFocus) { @@ -154,35 +237,41 @@ class Row extends React.PureComponent { /> </HoverMenu> )} - <div + <GridRow className={cx( 'grid-row', rowItems.length === 0 && 'grid-row--empty', backgroundStyle.className, )} data-test={`grid-row-${backgroundStyle.className}`} + ref={this.containerRef} > - {rowItems.map((componentId, itemIndex) => ( - <DashboardComponent - key={componentId} - id={componentId} - parentId={rowComponent.id} - depth={depth + 1} - index={itemIndex} - availableColumnCount={ - availableColumnCount - occupiedColumnCount - } - columnWidth={columnWidth} - onResizeStart={onResizeStart} - onResize={onResize} - onResizeStop={onResizeStop} - isComponentVisible={isComponentVisible} - onChangeTab={onChangeTab} - /> - ))} + {rowItems.length === 0 ? ( + <div css={emptyRowContentStyles}>{t('Empty row')}</div> + ) : ( + rowItems.map((componentId, itemIndex) => ( + <DashboardComponent + key={componentId} + id={componentId} + parentId={rowComponent.id} + depth={depth + 1} + index={itemIndex} + availableColumnCount={ + availableColumnCount - occupiedColumnCount + } + columnWidth={columnWidth} + onResizeStart={onResizeStart} + onResize={onResize} + onResizeStop={onResizeStop} + isComponentVisible={isComponentVisible} + onChangeTab={onChangeTab} + isInView={this.state.isInView} + /> + )) + )} {dropIndicatorProps && <div {...dropIndicatorProps} />} - </div> + </GridRow> </WithPopoverMenu> )} </DragDroppable> diff --git a/superset-frontend/src/dashboard/components/gridComponents/Row.test.jsx b/superset-frontend/src/dashboard/components/gridComponents/Row.test.jsx index 86cf613b6f27e..84591e5a882c6 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Row.test.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Row.test.jsx @@ -22,6 +22,7 @@ import { mount } from 'enzyme'; import sinon from 'sinon'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; +import { MemoryRouter } from 'react-router-dom'; import BackgroundStyleDropdown from 'src/dashboard/components/menu/BackgroundStyleDropdown'; import DashboardComponent from 'src/dashboard/containers/DashboardComponent'; @@ -67,9 +68,11 @@ describe('Row', () => { }); const wrapper = mount( <Provider store={mockStore}> - <DndProvider backend={HTML5Backend}> - <Row {...props} {...overrideProps} /> - </DndProvider> + <MemoryRouter> + <DndProvider backend={HTML5Backend}> + <Row {...props} {...overrideProps} /> + </DndProvider> + </MemoryRouter> </Provider>, { wrappingComponent: ThemeProvider, diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx b/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx index d8312cd60a9d0..32ac77936c6ad 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx @@ -43,6 +43,7 @@ const propTypes = { depth: PropTypes.number.isRequired, renderType: PropTypes.oneOf([RENDER_TAB, RENDER_TAB_CONTENT]).isRequired, onDropOnTab: PropTypes.func, + onHoverTab: PropTypes.func, editMode: PropTypes.bool.isRequired, canEdit: PropTypes.bool.isRequired, @@ -64,6 +65,7 @@ const defaultProps = { availableColumnCount: 0, columnWidth: 0, onDropOnTab() {}, + onHoverTab() {}, onResizeStart() {}, onResize() {}, onResizeStop() {}, @@ -95,6 +97,7 @@ class Tab extends React.PureComponent { super(props); this.handleChangeText = this.handleChangeText.bind(this); this.handleDrop = this.handleDrop.bind(this); + this.handleOnHover = this.handleOnHover.bind(this); this.handleTopDropTargetDrop = this.handleTopDropTargetDrop.bind(this); this.handleChangeTab = this.handleChangeTab.bind(this); } @@ -123,6 +126,10 @@ class Tab extends React.PureComponent { this.props.onDropOnTab(dropResult); } + handleOnHover() { + this.props.onHoverTab(); + } + handleTopDropTargetDrop(dropResult) { if (dropResult) { this.props.handleComponentDrop({ @@ -216,6 +223,7 @@ class Tab extends React.PureComponent { depth={depth} // see isValidChild.js for why tabs don't increment child depth index={componentIndex} onDrop={this.handleDrop} + onHover={this.handleOnHover} availableColumnCount={availableColumnCount} columnWidth={columnWidth} onResizeStart={onResizeStart} @@ -234,6 +242,7 @@ class Tab extends React.PureComponent { index={tabComponent.children.length} depth={depth} onDrop={this.handleDrop} + onHover={this.handleOnHover} editMode className="empty-droptarget" > @@ -263,6 +272,7 @@ class Tab extends React.PureComponent { index={index} depth={depth} onDrop={this.handleDrop} + onHover={this.handleOnHover} editMode={editMode} > {({ dropIndicatorProps, dragSourceRef }) => ( diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx b/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx index c579abb911b15..43ed8906906e5 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx @@ -48,7 +48,12 @@ const propTypes = { editMode: PropTypes.bool.isRequired, renderHoverMenu: PropTypes.bool, directPathToChild: PropTypes.arrayOf(PropTypes.string), - filterboxMigrationState: FILTER_BOX_MIGRATION_STATES, + activeTabs: PropTypes.arrayOf(PropTypes.string), + filterboxMigrationState: PropTypes.oneOf( + Object.keys(FILTER_BOX_MIGRATION_STATES).map( + key => FILTER_BOX_MIGRATION_STATES[key], + ), + ), // actions (from DashboardComponent.jsx) logEvent: PropTypes.func.isRequired, @@ -74,6 +79,7 @@ const defaultProps = { renderHoverMenu: true, availableColumnCount: 0, columnWidth: 0, + activeTabs: [], directPathToChild: [], filterboxMigrationState: FILTER_BOX_MIGRATION_STATES.NOOP, setActiveTabs() {}, @@ -112,15 +118,7 @@ const StyledTabsContainer = styled.div` export class Tabs extends React.PureComponent { constructor(props) { super(props); - const tabIndex = Math.max( - 0, - findTabIndexByComponentId({ - currentComponent: props.component, - directPathToChild: props.directPathToChild, - }), - ); - const { children: tabIds } = props.component; - const activeKey = tabIds[tabIndex]; + const { tabIndex, activeKey } = this.getTabInfo(props); this.state = { tabIndex, @@ -155,6 +153,15 @@ export class Tabs extends React.PureComponent { this.setState(() => ({ tabIndex: maxIndex })); } + // reset tab index if dashboard was changed + if (nextProps.dashboardId !== this.props.dashboardId) { + const { tabIndex, activeKey } = this.getTabInfo(nextProps); + this.setState(() => ({ + tabIndex, + activeKey, + })); + } + if (nextProps.isComponentVisible) { const nextFocusComponent = getLeafComponentIdFromPath( nextProps.directPathToChild, @@ -187,15 +194,42 @@ export class Tabs extends React.PureComponent { } } + getTabInfo = props => { + let tabIndex = Math.max( + 0, + findTabIndexByComponentId({ + currentComponent: props.component, + directPathToChild: props.directPathToChild, + }), + ); + if (tabIndex === 0 && props.activeTabs?.length) { + props.component.children.forEach((tabId, index) => { + if (tabIndex === 0 && props.activeTabs.includes(tabId)) { + tabIndex = index; + } + }); + } + const { children: tabIds } = props.component; + const activeKey = tabIds[tabIndex]; + + return { + tabIndex, + activeKey, + }; + }; + showDeleteConfirmModal = key => { const { component, deleteComponent } = this.props; AntdModal.confirm({ title: t('Delete dashboard tab?'), content: ( <span> - Deleting a tab will remove all content within it. You may still - reverse this action with the <b>undo</b> button (cmd + z) until you - save your changes. + {t( + 'Deleting a tab will remove all content within it. You may still ' + + 'reverse this action with the', + )}{' '} + <b>{t('undo')}</b>{' '} + {t('button (cmd + z) until you save your changes.')} </span> ), onOk: () => { @@ -204,8 +238,8 @@ export class Tabs extends React.PureComponent { this.handleDeleteTab(tabIndex); }, okType: 'danger', - okText: 'DELETE', - cancelText: 'CANCEL', + okText: t('DELETE'), + cancelText: t('CANCEL'), icon: null, }); }; @@ -309,9 +343,10 @@ export class Tabs extends React.PureComponent { const { tabIndex: selectedTabIndex, activeKey } = this.state; let tabsToHighlight; - if (nativeFilters?.focusedFilterId) { - tabsToHighlight = - nativeFilters.filters[nativeFilters.focusedFilterId].tabsInScope; + const highlightedFilterId = + nativeFilters?.focusedFilterId || nativeFilters?.hoveredFilterId; + if (highlightedFilterId) { + tabsToHighlight = nativeFilters.filters[highlightedFilterId]?.tabsInScope; } return ( <DragDroppable @@ -361,6 +396,7 @@ export class Tabs extends React.PureComponent { availableColumnCount={availableColumnCount} columnWidth={columnWidth} onDropOnTab={this.handleDropOnTab} + onHoverTab={() => this.handleClickTab(tabIndex)} isFocused={activeKey === tabId} isHighlighted={ activeKey !== tabId && tabsToHighlight?.includes(tabId) @@ -408,6 +444,7 @@ Tabs.defaultProps = defaultProps; function mapStateToProps(state) { return { nativeFilters: state.nativeFilters, + activeTabs: state.dashboardState.activeTabs, directPathToChild: state.dashboardState.directPathToChild, filterboxMigrationState: state.dashboardState.filterboxMigrationState, }; diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tabs.test.jsx b/superset-frontend/src/dashboard/components/gridComponents/Tabs.test.jsx index 0ceb2f47bac81..8a4f5117187c0 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Tabs.test.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Tabs.test.jsx @@ -40,7 +40,7 @@ import { nativeFilters } from 'spec/fixtures/mockNativeFilters'; import { initialState } from 'src/SqlLab/fixtures'; describe('Tabs', () => { - fetchMock.post('glob:*/r/shortner/', {}); + fetchMock.post('glob:*/r/shortener/', {}); const props = { id: 'TABS_ID', @@ -53,6 +53,7 @@ describe('Tabs', () => { editMode: false, availableColumnCount: 12, columnWidth: 50, + dashboardId: 1, onResizeStart() {}, onResize() {}, onResizeStop() {}, @@ -202,4 +203,15 @@ describe('Tabs', () => { expect(modalMock.mock.calls).toHaveLength(1); expect(deleteComponent.callCount).toBe(0); }); + + it('should set new tab key if dashboardId was changed', () => { + const wrapper = shallow(<Tabs {...props} />); + expect(wrapper.state('activeKey')).toBe('TAB_ID'); + wrapper.setProps({ + ...props, + dashboardId: 2, + component: dashboardLayoutWithTabs.present.TAB_ID, + }); + expect(wrapper.state('activeKey')).toBe('ROW_ID'); + }); }); diff --git a/superset-frontend/src/dashboard/components/gridComponents/new/DraggableNewComponent.jsx b/superset-frontend/src/dashboard/components/gridComponents/new/DraggableNewComponent.jsx index f4f33c9333dfb..c261fd2da25e1 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/new/DraggableNewComponent.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/new/DraggableNewComponent.jsx @@ -19,10 +19,11 @@ import React from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; +import { css, styled } from '@superset-ui/core'; -import DragDroppable from '../../dnd/DragDroppable'; -import { NEW_COMPONENTS_SOURCE_ID } from '../../../util/constants'; -import { NEW_COMPONENT_SOURCE_TYPE } from '../../../util/componentTypes'; +import DragDroppable from 'src/dashboard/components/dnd/DragDroppable'; +import { NEW_COMPONENTS_SOURCE_ID } from 'src/dashboard/util/constants'; +import { NEW_COMPONENT_SOURCE_TYPE } from 'src/dashboard/util/componentTypes'; const propTypes = { id: PropTypes.string.isRequired, @@ -35,6 +36,53 @@ const defaultProps = { className: null, }; +const NewComponent = styled.div` + ${({ theme }) => css` + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + padding: ${theme.gridUnit * 4}px; + background: ${theme.colors.grayscale.light5}; + cursor: move; + + &:not(.static):hover { + background: ${theme.colors.grayscale.light4}; + } + `} +`; + +const NewComponentPlaceholder = styled.div` + ${({ theme }) => css` + position: relative; + background: ${theme.colors.grayscale.light4}; + width: ${theme.gridUnit * 10}px; + height: ${theme.gridUnit * 10}px; + margin-right: ${theme.gridUnit * 4}px; + border: 1px solid ${theme.colors.grayscale.light5}; + display: flex; + align-items: center; + justify-content: center; + color: ${theme.colors.text.label}; + font-size: ${theme.typography.sizes.xxl}px; + + &.fa-window-restore { + font-size: ${theme.typography.sizes.l}px; + } + + &.fa-area-chart { + font-size: ${theme.typography.sizes.xl}px; + } + + &.divider-placeholder:after { + content: ''; + height: 2px; + width: 100%; + background-color: ${theme.colors.grayscale.light2}; + } + `} +`; + export default class DraggableNewComponent extends React.PureComponent { render() { const { label, id, type, className, meta } = this.props; @@ -50,14 +98,12 @@ export default class DraggableNewComponent extends React.PureComponent { editMode > {({ dragSourceRef }) => ( - <div - ref={dragSourceRef} - className="new-component" - data-test="new-component" - > - <div className={cx('new-component-placeholder', className)} /> + <NewComponent ref={dragSourceRef} data-test="new-component"> + <NewComponentPlaceholder + className={cx('new-component-placeholder', className)} + /> {label} - </div> + </NewComponent> )} </DragDroppable> ); diff --git a/superset-frontend/src/dashboard/components/gridComponents/new/DraggableNewComponent.test.jsx b/superset-frontend/src/dashboard/components/gridComponents/new/DraggableNewComponent.test.jsx index 2b56f02f5d91b..a105fa43964f3 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/new/DraggableNewComponent.test.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/new/DraggableNewComponent.test.jsx @@ -17,7 +17,7 @@ * under the License. */ import React from 'react'; -import { mount } from 'enzyme'; +import { styledMount as mount } from 'spec/helpers/theming'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; @@ -73,7 +73,9 @@ describe('DraggableNewComponent', () => { it('should render the passed label', () => { const wrapper = setup(); - expect(wrapper.find('.new-component').text()).toBe(props.label); + expect( + wrapper.find('[data-test="new-component"]').at(0).childAt(0).text(), + ).toBe(props.label); }); it('should add the passed className', () => { diff --git a/superset-frontend/src/dashboard/components/gridComponents/new/NewMarkdown.jsx b/superset-frontend/src/dashboard/components/gridComponents/new/NewMarkdown.jsx index f16b4b55f42d3..3cc3138667b88 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/new/NewMarkdown.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/new/NewMarkdown.jsx @@ -17,6 +17,7 @@ * under the License. */ import React from 'react'; +import { t } from '@superset-ui/core'; import { MARKDOWN_TYPE } from '../../../util/componentTypes'; import { NEW_MARKDOWN_ID } from '../../../util/constants'; @@ -27,8 +28,8 @@ export default function DraggableNewDivider() { <DraggableNewComponent id={NEW_MARKDOWN_ID} type={MARKDOWN_TYPE} - label="Markdown" - className="fa fa-code" + label={t('Text')} + className="fa fa-font" /> ); } diff --git a/superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.tsx b/superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.tsx index 82c8994102533..5498b72169da4 100644 --- a/superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.tsx +++ b/superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.tsx @@ -18,6 +18,7 @@ */ import React from 'react'; import cx from 'classnames'; +import { css, styled, t } from '@superset-ui/core'; import backgroundStyleOptions from 'src/dashboard/util/backgroundStyleOptions'; import PopoverDropdown, { @@ -31,19 +32,64 @@ interface BackgroundStyleDropdownProps { onChange: OnChangeHandler; } +const BackgroundStyleOption = styled.div` + ${({ theme }) => css` + display: inline-block; + + &:before { + content: ''; + width: 1em; + height: 1em; + margin-right: ${theme.gridUnit * 2}px; + display: inline-block; + vertical-align: middle; + } + + &.background--white { + padding-left: 0; + background: transparent; + + &:before { + background: ${theme.colors.grayscale.light5}; + border: 1px solid ${theme.colors.grayscale.light2}; + } + } + + /* Create the transparent rect icon */ + &.background--transparent:before { + background-image: linear-gradient( + 45deg, + ${theme.colors.text.label} 25%, + transparent 25% + ), + linear-gradient(-45deg, ${theme.colors.text.label} 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, ${theme.colors.text.label} 75%), + linear-gradient(-45deg, transparent 75%, ${theme.colors.text.label} 75%); + background-size: ${theme.gridUnit * 2}px ${theme.gridUnit * 2}px; + background-position: 0 0, 0 ${theme.gridUnit}px, + ${theme.gridUnit}px ${-theme.gridUnit}px, ${-theme.gridUnit}px 0px; + } + `} +`; + function renderButton(option: OptionProps) { + const BACKGROUND_TEXT = t('background'); return ( - <div className={cx('background-style-option', option.className)}> - {`${option.label} background`} - </div> + <BackgroundStyleOption + className={cx('background-style-option', option.className)} + > + {`${option.label} ${BACKGROUND_TEXT}`} + </BackgroundStyleOption> ); } function renderOption(option: OptionProps) { return ( - <div className={cx('background-style-option', option.className)}> + <BackgroundStyleOption + className={cx('background-style-option', option.className)} + > {option.label} - </div> + </BackgroundStyleOption> ); } diff --git a/superset-frontend/src/dashboard/components/menu/ShareMenuItems/ShareMenuItems.test.tsx b/superset-frontend/src/dashboard/components/menu/ShareMenuItems/ShareMenuItems.test.tsx index 498009224a5e7..bf247bc249251 100644 --- a/superset-frontend/src/dashboard/components/menu/ShareMenuItems/ShareMenuItems.test.tsx +++ b/superset-frontend/src/dashboard/components/menu/ShareMenuItems/ShareMenuItems.test.tsx @@ -70,6 +70,7 @@ test('Should render menu items', () => { <Menu onClick={jest.fn()} selectable={false} data-test="main-menu"> <ShareMenuItems {...props} /> </Menu>, + { useRedux: true }, ); expect( screen.getByRole('menuitem', { name: 'Copy dashboard URL' }), @@ -92,6 +93,7 @@ test('Click on "Copy dashboard URL" and succeed', async () => { <Menu onClick={jest.fn()} selectable={false} data-test="main-menu"> <ShareMenuItems {...props} /> </Menu>, + { useRedux: true }, ); await waitFor(() => { @@ -119,6 +121,7 @@ test('Click on "Copy dashboard URL" and fail', async () => { <Menu onClick={jest.fn()} selectable={false} data-test="main-menu"> <ShareMenuItems {...props} /> </Menu>, + { useRedux: true }, ); await waitFor(() => { @@ -147,6 +150,7 @@ test('Click on "Share dashboard by email" and succeed', async () => { <Menu onClick={jest.fn()} selectable={false} data-test="main-menu"> <ShareMenuItems {...props} /> </Menu>, + { useRedux: true }, ); await waitFor(() => { @@ -177,6 +181,7 @@ test('Click on "Share dashboard by email" and fail', async () => { <Menu onClick={jest.fn()} selectable={false} data-test="main-menu"> <ShareMenuItems {...props} /> </Menu>, + { useRedux: true }, ); await waitFor(() => { diff --git a/superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx b/superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx index f9016e5263c02..d0d8844cdd2b7 100644 --- a/superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx +++ b/superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx @@ -20,9 +20,9 @@ import React from 'react'; import copyTextToClipboard from 'src/utils/copy'; import { t, logging } from '@superset-ui/core'; import { Menu } from 'src/components/Menu'; -import { getDashboardPermalink, getUrlParam } from 'src/utils/urlUtils'; -import { URL_PARAMS } from 'src/constants'; -import { getFilterValue } from 'src/dashboard/components/nativeFilters/FilterBar/keyValue'; +import { getDashboardPermalink } from 'src/utils/urlUtils'; +import { RootState } from 'src/dashboard/types'; +import { useSelector } from 'react-redux'; interface ShareMenuItemProps { url?: string; @@ -48,17 +48,17 @@ const ShareMenuItems = (props: ShareMenuItemProps) => { dashboardComponentId, ...rest } = props; + const { dataMask, activeTabs } = useSelector((state: RootState) => ({ + dataMask: state.dataMask, + activeTabs: state.dashboardState.activeTabs, + })); async function generateUrl() { - const nativeFiltersKey = getUrlParam(URL_PARAMS.nativeFiltersKey); - let filterState = {}; - if (nativeFiltersKey && dashboardId) { - filterState = await getFilterValue(dashboardId, nativeFiltersKey); - } return getDashboardPermalink({ dashboardId, - filterState, - hash: dashboardComponentId, + dataMask, + activeTabs, + anchor: dashboardComponentId, }); } diff --git a/superset-frontend/src/dashboard/components/menu/WithPopoverMenu.tsx b/superset-frontend/src/dashboard/components/menu/WithPopoverMenu.tsx index df44b4e1c1f24..3aa0aa81d3d2f 100644 --- a/superset-frontend/src/dashboard/components/menu/WithPopoverMenu.tsx +++ b/superset-frontend/src/dashboard/components/menu/WithPopoverMenu.tsx @@ -18,6 +18,7 @@ */ import React from 'react'; import cx from 'classnames'; +import { addAlpha, css, styled } from '@superset-ui/core'; type ShouldFocusContainer = HTMLDivElement & { contains: (event_target: EventTarget & HTMLElement) => Boolean; @@ -41,6 +42,67 @@ interface WithPopoverMenuState { isFocused: Boolean; } +const WithPopoverMenuStyles = styled.div` + ${({ theme }) => css` + position: relative; + outline: none; + + &.with-popover-menu--focused:after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 2px solid ${theme.colors.primary.base}; + pointer-events: none; + } + + .dashboard-component-tabs li &.with-popover-menu--focused:after { + top: ${theme.gridUnit * -3}px; + left: ${theme.gridUnit * -2}px; + width: calc(100% + ${theme.gridUnit * 4}px); + height: calc(100% + ${theme.gridUnit * 7}px); + } + `} +`; + +const PopoverMenuStyles = styled.div` + ${({ theme }) => css` + position: absolute; + flex-wrap: nowrap; + left: 1px; + top: -42px; + height: ${theme.gridUnit * 10}px; + padding: 0 ${theme.gridUnit * 4}px; + background: ${theme.colors.grayscale.light5}; + box-shadow: 0 1px 2px 1px + ${addAlpha( + theme.colors.grayscale.dark2, + parseFloat(theme.opacity.mediumLight) / 100, + )}; + font-size: ${theme.typography.sizes.m}px; + cursor: default; + z-index: 3000; + + &, + .menu-item { + display: flex; + flex-direction: row; + align-items: center; + } + + /* vertical spacer after each menu item */ + .menu-item:not(:last-child):after { + content: ''; + width: 1px; + height: 100%; + background: ${theme.colors.grayscale.light2}; + margin: 0 ${theme.gridUnit * 4}px; + } + `} +`; + export default class WithPopoverMenu extends React.PureComponent< WithPopoverMenuProps, WithPopoverMenuState @@ -126,7 +188,7 @@ export default class WithPopoverMenu extends React.PureComponent< const { isFocused } = this.state; return ( - <div + <WithPopoverMenuStyles ref={this.setRef} onClick={this.handleClick} role="none" @@ -138,15 +200,15 @@ export default class WithPopoverMenu extends React.PureComponent< > {children} {editMode && isFocused && (menuItems?.length ?? 0) > 0 && ( - <div className="popover-menu"> + <PopoverMenuStyles> {menuItems.map((node: React.ReactNode, i: Number) => ( <div className="menu-item" key={`menu-item-${i}`}> {node} </div> ))} - </div> + </PopoverMenuStyles> )} - </div> + </WithPopoverMenuStyles> ); } } diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/ActionButtons.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/ActionButtons.test.tsx index 77aede5be3534..525f519632463 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/ActionButtons.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/ActionButtons.test.tsx @@ -17,9 +17,10 @@ * under the License. */ import React from 'react'; +import { OPEN_FILTER_BAR_WIDTH } from 'src/dashboard/constants'; import userEvent from '@testing-library/user-event'; import { render, screen } from 'spec/helpers/testing-library'; -import { ActionButtons } from './index'; +import ActionButtons from './index'; const createProps = () => ({ onApply: jest.fn(), @@ -77,3 +78,28 @@ test('should apply', () => { userEvent.click(applyBtn); expect(mockedProps.onApply).toHaveBeenCalled(); }); + +describe('custom width', () => { + it('sets its default width with OPEN_FILTER_BAR_WIDTH', () => { + const mockedProps = createProps(); + render(<ActionButtons {...mockedProps} />, { useRedux: true }); + const container = screen.getByTestId('filterbar-action-buttons'); + expect(container).toHaveStyleRule( + 'width', + `${OPEN_FILTER_BAR_WIDTH - 1}px`, + ); + }); + + it('sets custom width', () => { + const mockedProps = createProps(); + const expectedWidth = 423; + const { getByTestId } = render( + <ActionButtons {...mockedProps} width={expectedWidth} />, + { + useRedux: true, + }, + ); + const container = getByTestId('filterbar-action-buttons'); + expect(container).toHaveStyleRule('width', `${expectedWidth - 1}px`); + }); +}); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx index d94885b1c970e..cb6f17d96dbf9 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx @@ -21,89 +21,116 @@ import { css, DataMaskState, DataMaskStateWithId, - styled, t, + isDefined, + SupersetTheme, } from '@superset-ui/core'; import Button from 'src/components/Button'; -import { isNullish } from 'src/utils/common'; import { OPEN_FILTER_BAR_WIDTH } from 'src/dashboard/constants'; import { rgba } from 'emotion-rgba'; -import { getFilterBarTestId } from '../index'; +import { FilterBarOrientation } from 'src/dashboard/types'; +import { getFilterBarTestId } from '../utils'; interface ActionButtonsProps { + width?: number; onApply: () => void; onClearAll: () => void; dataMaskSelected: DataMaskState; dataMaskApplied: DataMaskStateWithId; isApplyDisabled: boolean; + filterBarOrientation?: FilterBarOrientation; } -const ActionButtonsContainer = styled.div` - ${({ theme }) => css` - display: flex; - flex-direction: column; - align-items: center; +const containerStyle = (theme: SupersetTheme) => css` + display: flex; - position: fixed; - z-index: 100; + && > .filter-clear-all-button { + color: ${theme.colors.grayscale.base}; + margin-left: 0; + &:hover { + color: ${theme.colors.primary.dark1}; + } - // filter bar width minus 1px for border - width: ${OPEN_FILTER_BAR_WIDTH - 1}px; - bottom: 0; + &[disabled], + &[disabled]:hover { + color: ${theme.colors.grayscale.light1}; + } + } +`; - padding: ${theme.gridUnit * 4}px; - padding-top: ${theme.gridUnit * 6}px; +const verticalStyle = (theme: SupersetTheme, width: number) => css` + flex-direction: column; + align-items: center; + pointer-events: none; + position: fixed; + z-index: 100; - background: linear-gradient( - ${rgba(theme.colors.grayscale.light5, 0)}, - ${theme.colors.grayscale.light5} ${theme.opacity.mediumLight} - ); + // filter bar width minus 1px for border + width: ${width - 1}px; + bottom: 0; - pointer-events: none; + padding: ${theme.gridUnit * 4}px; + padding-top: ${theme.gridUnit * 6}px; - & > button { - pointer-events: auto; - } + background: linear-gradient( + ${rgba(theme.colors.grayscale.light5, 0)}, + ${theme.colors.grayscale.light5} ${theme.opacity.mediumLight} + ); - & > .filter-apply-button { - margin-bottom: ${theme.gridUnit * 3}px; - } + & > button { + pointer-events: auto; + } - && > .filter-clear-all-button { - color: ${theme.colors.grayscale.base}; - margin-left: 0; - &:hover { - color: ${theme.colors.primary.dark1}; - } + & > .filter-apply-button { + margin-bottom: ${theme.gridUnit * 3}px; + } +`; - &[disabled], - &[disabled]:hover { - color: ${theme.colors.grayscale.light1}; - } +const horizontalStyle = (theme: SupersetTheme) => css` + align-items: center; + margin-left: auto; + && > .filter-clear-all-button { + text-transform: capitalize; + font-weight: ${theme.typography.weights.normal}; + } + & > .filter-apply-button { + &[disabled], + &[disabled]:hover { + color: ${theme.colors.grayscale.light1}; + background: ${theme.colors.grayscale.light3}; } - `}; + } `; -export const ActionButtons = ({ +const ActionButtons = ({ + width = OPEN_FILTER_BAR_WIDTH, onApply, onClearAll, dataMaskApplied, dataMaskSelected, isApplyDisabled, + filterBarOrientation = FilterBarOrientation.VERTICAL, }: ActionButtonsProps) => { const isClearAllEnabled = useMemo( () => Object.values(dataMaskApplied).some( filter => - !isNullish(dataMaskSelected[filter.id]?.filterState?.value) || + isDefined(dataMaskSelected[filter.id]?.filterState?.value) || (!dataMaskSelected[filter.id] && - !isNullish(filter.filterState?.value)), + isDefined(filter.filterState?.value)), ), [dataMaskApplied, dataMaskSelected], ); + const isVertical = filterBarOrientation === FilterBarOrientation.VERTICAL; return ( - <ActionButtonsContainer> + <div + css={(theme: SupersetTheme) => [ + containerStyle(theme), + isVertical ? verticalStyle(theme, width) : horizontalStyle(theme), + ]} + data-test="filterbar-action-buttons" + > <Button disabled={isApplyDisabled} buttonStyle="primary" @@ -112,7 +139,7 @@ export const ActionButtons = ({ onClick={onApply} {...getFilterBarTestId('apply-button')} > - {t('Apply filters')} + {isVertical ? t('Apply filters') : t('Apply')} </Button> <Button disabled={!isClearAllEnabled} @@ -124,6 +151,8 @@ export const ActionButtons = ({ > {t('Clear all')} </Button> - </ActionButtonsContainer> + </div> ); }; + +export default ActionButtons; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.test.tsx index de7d6af99ca09..7a8106ecbe971 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.test.tsx @@ -26,10 +26,12 @@ import { testWithId } from 'src/utils/testUtils'; import { FeatureFlag } from 'src/featureFlags'; import { Preset } from '@superset-ui/core'; import { TimeFilterPlugin, SelectFilterPlugin } from 'src/filters/components'; -import { DATE_FILTER_CONTROL_TEST_ID } from 'src/explore/components/controls/DateFilterControl/DateFilterLabel'; +import { DATE_FILTER_TEST_KEY } from 'src/explore/components/controls/DateFilterControl'; import fetchMock from 'fetch-mock'; import { waitFor } from '@testing-library/react'; -import FilterBar, { FILTER_BAR_TEST_ID } from '.'; +import { FilterBarOrientation } from 'src/dashboard/types'; +import { FILTER_BAR_TEST_ID } from './utils'; +import FilterBar from '.'; import { FILTERS_CONFIG_MODAL_TEST_ID } from '../FiltersConfigModal/FiltersConfigModal'; jest.useFakeTimers(); @@ -71,10 +73,6 @@ fetchMock.get('glob:*/api/v1/dataset/7', { const getTestId = testWithId<string>(FILTER_BAR_TEST_ID, true); const getModalTestId = testWithId<string>(FILTERS_CONFIG_MODAL_TEST_ID, true); -const getDateControlTestId = testWithId<string>( - DATE_FILTER_CONTROL_TEST_ID, - true, -); const FILTER_NAME = 'Time filter 1'; const FILTER_SET_NAME = 'New filter set'; @@ -121,7 +119,7 @@ const changeFilterValue = async () => { userEvent.click(screen.getAllByText('No filter')[0]); userEvent.click(screen.getByDisplayValue('Last day')); expect(await screen.findByText(/2021-04-13/)).toBeInTheDocument(); - userEvent.click(screen.getByTestId(getDateControlTestId('apply-button'))); + userEvent.click(screen.getByTestId(DATE_FILTER_TEST_KEY.applyButton)); }; describe('FilterBar', () => { @@ -220,12 +218,23 @@ describe('FilterBar', () => { }); const renderWrapper = (props = closedBarProps, state?: object) => - render(<FilterBar {...props} width={280} height={400} offset={0} />, { - initialState: state, - useDnd: true, - useRedux: true, - useRouter: true, - }); + render( + <FilterBar + orientation={FilterBarOrientation.VERTICAL} + verticalConfig={{ + width: 280, + height: 400, + offset: 0, + ...props, + }} + />, + { + initialState: state, + useDnd: true, + useRedux: true, + useRouter: true, + }, + ); it('should render', () => { const { container } = renderWrapper(); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/FilterBarSettings.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/FilterBarSettings.test.tsx new file mode 100644 index 0000000000000..344e891365a50 --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/FilterBarSettings.test.tsx @@ -0,0 +1,299 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import fetchMock from 'fetch-mock'; +import { waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { render, screen, within } from 'spec/helpers/testing-library'; +import { DashboardInfo, FilterBarOrientation } from 'src/dashboard/types'; +import * as mockedMessageActions from 'src/components/MessageToasts/actions'; +import { FeatureFlag } from '@superset-ui/core'; +import FilterBarSettings from '.'; + +const initialState: { dashboardInfo: DashboardInfo } = { + dashboardInfo: { + id: 1, + userId: '1', + metadata: { + native_filter_configuration: {}, + show_native_filters: true, + chart_configuration: {}, + color_scheme: '', + color_namespace: '', + color_scheme_domain: [], + label_colors: {}, + shared_label_colors: {}, + cross_filters_enabled: false, + }, + json_metadata: '', + dash_edit_perm: true, + filterBarOrientation: FilterBarOrientation.VERTICAL, + common: { + conf: {}, + flash_messages: [], + }, + crossFiltersEnabled: true, + }, +}; + +const setup = (dashboardInfoOverride: Partial<DashboardInfo> = {}) => + waitFor(() => + render(<FilterBarSettings />, { + useRedux: true, + initialState: { + ...initialState, + dashboardInfo: { + ...initialState.dashboardInfo, + ...dashboardInfoOverride, + }, + }, + }), + ); + +test('Dropdown trigger renders with FF HORIZONTAL_FILTER_BAR on', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.HORIZONTAL_FILTER_BAR]: true, + }; + await setup(); + expect(screen.getByLabelText('gear')).toBeVisible(); +}); + +test('Dropdown trigger does not render with FF HORIZONTAL_FILTER_BAR off', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.HORIZONTAL_FILTER_BAR]: false, + }; + await setup(); + expect(screen.queryByLabelText('gear')).not.toBeInTheDocument(); +}); + +test('Dropdown trigger renders with dashboard edit permissions', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.HORIZONTAL_FILTER_BAR]: true, + }; + await setup({ + dash_edit_perm: true, + }); + expect(screen.getByRole('img', { name: 'gear' })).toBeInTheDocument(); +}); + +test('Dropdown trigger does not render without dashboard edit permissions', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.HORIZONTAL_FILTER_BAR]: true, + }; + await setup({ + dash_edit_perm: false, + }); + + expect(screen.queryByRole('img', { name: 'gear' })).not.toBeInTheDocument(); +}); + +test('Dropdown trigger renders with FF DASHBOARD_CROSS_FILTERS on', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.DASHBOARD_CROSS_FILTERS]: true, + }; + await setup(); + + expect(screen.getByRole('img', { name: 'gear' })).toBeInTheDocument(); +}); + +test('Dropdown trigger does not render with FF DASHBOARD_CROSS_FILTERS off', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.DASHBOARD_CROSS_FILTERS]: false, + }; + await setup(); + + expect(screen.queryByRole('img', { name: 'gear' })).not.toBeInTheDocument(); +}); + +test('Popover shows cross-filtering option on by default', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.DASHBOARD_CROSS_FILTERS]: true, + }; + await setup(); + userEvent.click(screen.getByLabelText('gear')); + expect(screen.getByText('Enable cross-filtering')).toBeInTheDocument(); + expect(screen.getByRole('checkbox')).toBeChecked(); +}); + +test('Can enable/disable cross-filtering', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.DASHBOARD_CROSS_FILTERS]: true, + }; + fetchMock.reset(); + fetchMock.put('glob:*/api/v1/dashboard/1', { + result: {}, + }); + await setup(); + userEvent.click(screen.getByLabelText('gear')); + const checkbox = screen.getByRole('checkbox'); + expect(checkbox).toBeChecked(); + + userEvent.click(checkbox); + + userEvent.click(screen.getByLabelText('gear')); + expect(checkbox).not.toBeChecked(); +}); + +test('Popover opens with "Vertical" selected', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.HORIZONTAL_FILTER_BAR]: true, + }; + await setup(); + userEvent.click(screen.getByLabelText('gear')); + userEvent.hover(screen.getByText('Orientation of filter bar')); + expect(await screen.findByText('Vertical (Left)')).toBeInTheDocument(); + expect(screen.getByText('Horizontal (Top)')).toBeInTheDocument(); + expect( + within(screen.getAllByRole('menuitem')[1]).getByLabelText('check'), + ).toBeInTheDocument(); +}); + +test('Popover opens with "Horizontal" selected', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.HORIZONTAL_FILTER_BAR]: true, + }; + await setup({ filterBarOrientation: FilterBarOrientation.HORIZONTAL }); + userEvent.click(screen.getByLabelText('gear')); + userEvent.hover(screen.getByText('Orientation of filter bar')); + expect(await screen.findByText('Vertical (Left)')).toBeInTheDocument(); + expect(screen.getByText('Horizontal (Top)')).toBeInTheDocument(); + expect( + within(screen.getAllByRole('menuitem')[2]).getByLabelText('check'), + ).toBeInTheDocument(); +}); + +test('On selection change, send request and update checked value', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.HORIZONTAL_FILTER_BAR]: true, + }; + fetchMock.reset(); + fetchMock.put('glob:*/api/v1/dashboard/1', { + result: { + json_metadata: JSON.stringify({ + ...initialState.dashboardInfo.metadata, + filter_bar_orientation: 'HORIZONTAL', + }), + }, + }); + + await setup(); + userEvent.click(screen.getByLabelText('gear')); + userEvent.hover(screen.getByText('Orientation of filter bar')); + + expect(await screen.findByText('Vertical (Left)')).toBeInTheDocument(); + expect(screen.getByText('Horizontal (Top)')).toBeInTheDocument(); + expect( + within(screen.getAllByRole('menuitem')[1]).getByLabelText('check'), + ).toBeInTheDocument(); + expect( + within(screen.getAllByRole('menuitem')[2]).queryByLabelText('check'), + ).not.toBeInTheDocument(); + + userEvent.click(await screen.findByText('Horizontal (Top)')); + + // 1st check - checkmark appears immediately after click + expect( + await within(screen.getAllByRole('menuitem')[2]).findByLabelText('check'), + ).toBeInTheDocument(); + expect( + within(screen.getAllByRole('menuitem')[1]).queryByLabelText('check'), + ).not.toBeInTheDocument(); + + // successful query + await waitFor(() => + expect(fetchMock.lastCall()?.[1]?.body).toEqual( + JSON.stringify({ + json_metadata: JSON.stringify({ + ...initialState.dashboardInfo.metadata, + filter_bar_orientation: 'HORIZONTAL', + }), + }), + ), + ); + + // 2nd check - checkmark stays after successful query + expect( + await within(screen.getAllByRole('menuitem')[2]).findByLabelText('check'), + ).toBeInTheDocument(); + expect( + within(screen.getAllByRole('menuitem')[1]).queryByLabelText('check'), + ).not.toBeInTheDocument(); + + fetchMock.reset(); +}); + +test('On failed request, restore previous selection', async () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.HORIZONTAL_FILTER_BAR]: true, + }; + fetchMock.reset(); + fetchMock.put('glob:*/api/v1/dashboard/1', 400); + + const dangerToastSpy = jest.spyOn(mockedMessageActions, 'addDangerToast'); + + await setup(); + userEvent.click(screen.getByLabelText('gear')); + userEvent.hover(screen.getByText('Orientation of filter bar')); + + expect(await screen.findByText('Vertical (Left)')).toBeInTheDocument(); + expect(screen.getByText('Horizontal (Top)')).toBeInTheDocument(); + + expect( + within(screen.getAllByRole('menuitem')[1]).getByLabelText('check'), + ).toBeInTheDocument(); + expect( + within(screen.getAllByRole('menuitem')[2]).queryByLabelText('check'), + ).not.toBeInTheDocument(); + + userEvent.click(await screen.findByText('Horizontal (Top)')); + + await waitFor(() => { + expect(dangerToastSpy).toHaveBeenCalledWith( + 'Sorry, there was an error saving this dashboard: Unknown Error', + ); + }); + + userEvent.click(screen.getByLabelText('gear')); + userEvent.hover(screen.getByText('Orientation of filter bar')); + + expect(await screen.findByText('Vertical (Left)')).toBeInTheDocument(); + + // checkmark gets rolled back to the original selection after successful query + expect( + await within(screen.getAllByRole('menuitem')[1]).findByLabelText('check'), + ).toBeInTheDocument(); + expect( + within(screen.getAllByRole('menuitem')[2]).queryByLabelText('check'), + ).not.toBeInTheDocument(); + + fetchMock.reset(); +}); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx new file mode 100644 index 0000000000000..dda3b7e47ba08 --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx @@ -0,0 +1,192 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useCallback, useMemo, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { + FeatureFlag, + isFeatureEnabled, + styled, + t, + useTheme, +} from '@superset-ui/core'; +import { MenuProps } from 'src/components/Menu'; +import { FilterBarOrientation, RootState } from 'src/dashboard/types'; +import { + saveFilterBarOrientation, + saveCrossFiltersSetting, +} from 'src/dashboard/actions/dashboardInfo'; +import Icons from 'src/components/Icons'; +import DropdownSelectableIcon, { + DropDownSelectableProps, +} from 'src/components/DropdownSelectableIcon'; +import Checkbox from 'src/components/Checkbox'; +import { clearDataMaskState } from 'src/dataMask/actions'; + +type SelectedKey = FilterBarOrientation | string | number; + +const StyledMenuLabel = styled.span` + display: flex; + align-items: center; + justify-content: space-between; + + .enable-cross-filters-text { + padding-left: ${({ theme }) => `${theme.gridUnit * 2}px`}; + } +`; + +const StyledCheckbox = styled(Checkbox)` + ${({ theme }) => ` + &, + svg { + display: inline-block; + width: ${theme.gridUnit * 4}px; + height: ${theme.gridUnit * 4}px; + } +`} +`; + +const FilterBarSettings = () => { + const dispatch = useDispatch(); + const theme = useTheme(); + const isCrossFiltersEnabled = useSelector<RootState, boolean>( + ({ dashboardInfo }) => dashboardInfo.crossFiltersEnabled, + ); + const filterBarOrientation = useSelector<RootState, FilterBarOrientation>( + ({ dashboardInfo }) => dashboardInfo.filterBarOrientation, + ); + const [selectedFilterBarOrientation, setSelectedFilterBarOrientation] = + useState(filterBarOrientation); + const isCrossFiltersFeatureEnabled = isFeatureEnabled( + FeatureFlag.DASHBOARD_CROSS_FILTERS, + ); + const shouldEnableCrossFilters = + !!isCrossFiltersEnabled && isCrossFiltersFeatureEnabled; + const [crossFiltersEnabled, setCrossFiltersEnabled] = useState<boolean>( + shouldEnableCrossFilters, + ); + const canEdit = useSelector<RootState, boolean>( + ({ dashboardInfo }) => dashboardInfo.dash_edit_perm, + ); + const canSetHorizontalFilterBar = + canEdit && isFeatureEnabled(FeatureFlag.HORIZONTAL_FILTER_BAR); + const crossFiltersMenuKey = 'cross-filters-menu-key'; + const isOrientation = (o: SelectedKey): o is FilterBarOrientation => + o === FilterBarOrientation.VERTICAL || + o === FilterBarOrientation.HORIZONTAL; + const updateCrossFiltersSetting = useCallback( + async isEnabled => { + if (!isEnabled) { + dispatch(clearDataMaskState()); + } + await dispatch(saveCrossFiltersSetting(isEnabled)); + }, + [dispatch, crossFiltersEnabled], + ); + const changeFilterBarSettings = useCallback( + async ( + selection: Parameters< + Required<Pick<MenuProps, 'onSelect'>>['onSelect'] + >[0], + ) => { + const selectedKey: SelectedKey = selection.key; + if (selectedKey === crossFiltersMenuKey) { + setCrossFiltersEnabled(!crossFiltersEnabled); + updateCrossFiltersSetting(!crossFiltersEnabled); + return; + } + if (isOrientation(selectedKey) && selectedKey !== filterBarOrientation) { + // set displayed selection in local state for immediate visual response after clicking + setSelectedFilterBarOrientation(selectedKey as FilterBarOrientation); + try { + // save selection in Redux and backend + await dispatch( + saveFilterBarOrientation(selection.key as FilterBarOrientation), + ); + } catch { + // revert local state in case of error when saving + setSelectedFilterBarOrientation(filterBarOrientation); + } + } + }, + [dispatch, crossFiltersEnabled, filterBarOrientation], + ); + const crossFiltersMenuItem = useMemo( + () => ( + <StyledMenuLabel> + <StyledCheckbox + className="enable-cross-filters" + checked={crossFiltersEnabled} + onChange={checked => setCrossFiltersEnabled(checked || false)} + />{' '} + <span className="enable-cross-filters-text"> + {t('Enable cross-filtering')} + </span> + </StyledMenuLabel> + ), + [crossFiltersEnabled], + ); + const menuItems: DropDownSelectableProps['menuItems'] = []; + + if (isCrossFiltersFeatureEnabled) { + menuItems.unshift({ + key: crossFiltersMenuKey, + label: crossFiltersMenuItem, + divider: canSetHorizontalFilterBar, + }); + } + + if (canSetHorizontalFilterBar) { + menuItems.push({ + key: 'placement', + label: t('Orientation of filter bar'), + children: [ + { + key: FilterBarOrientation.VERTICAL, + label: t('Vertical (Left)'), + }, + { + key: FilterBarOrientation.HORIZONTAL, + label: t('Horizontal (Top)'), + }, + ], + }); + } + + if (!menuItems.length) { + return null; + } + + return ( + <DropdownSelectableIcon + onSelect={changeFilterBarSettings} + icon={ + <Icons.Gear + name="gear" + iconColor={theme.colors.grayscale.base} + data-test="filterbar-orientation-icon" + /> + } + menuItems={menuItems} + selectedKeys={[selectedFilterBarOrientation]} + /> + ); +}; + +export default FilterBarSettings; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx index bb3c1517104e5..c9e4b834d9408 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx @@ -16,17 +16,20 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useState } from 'react'; +import React, { useCallback, useState } from 'react'; import { useDispatch } from 'react-redux'; import { setFilterConfiguration } from 'src/dashboard/actions/nativeFilters'; import Button from 'src/components/Button'; import { FilterConfiguration, styled } from '@superset-ui/core'; -import { FiltersConfigModal } from 'src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal'; -import { getFilterBarTestId } from '..'; +import FiltersConfigModal from 'src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal'; +import { getFilterBarTestId } from '../utils'; export interface FCBProps { createNewOnOpen?: boolean; dashboardId?: number; + initialFilterId?: string; + onClick?: () => void; + children?: React.ReactNode; } const HeaderButton = styled(Button)` @@ -36,19 +39,31 @@ const HeaderButton = styled(Button)` export const FilterConfigurationLink: React.FC<FCBProps> = ({ createNewOnOpen, dashboardId, + initialFilterId, + onClick, children, }) => { const dispatch = useDispatch(); const [isOpen, setOpen] = useState(false); - function close() { + const close = useCallback(() => { setOpen(false); - } + }, [setOpen]); - async function submit(filterConfig: FilterConfiguration) { - dispatch(await setFilterConfiguration(filterConfig)); - close(); - } + const submit = useCallback( + async (filterConfig: FilterConfiguration) => { + dispatch(await setFilterConfiguration(filterConfig)); + close(); + }, + [dispatch, close], + ); + + const handleClick = useCallback(() => { + setOpen(true); + if (onClick) { + onClick(); + } + }, [setOpen, onClick]); return ( <> @@ -57,7 +72,7 @@ export const FilterConfigurationLink: React.FC<FCBProps> = ({ {...getFilterBarTestId('create-filter')} buttonStyle="link" buttonSize="xsmall" - onClick={() => setOpen(true)} + onClick={handleClick} > {children} </HeaderButton> @@ -65,6 +80,7 @@ export const FilterConfigurationLink: React.FC<FCBProps> = ({ isOpen={isOpen} onSave={submit} onCancel={close} + initialFilterId={initialFilterId} createNewOnOpen={createNewOnOpen} key={`filters-for-${dashboardId}`} /> @@ -72,4 +88,4 @@ export const FilterConfigurationLink: React.FC<FCBProps> = ({ ); }; -export default FilterConfigurationLink; +export default React.memo(FilterConfigurationLink); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx index ff5b08781e4e4..fa54036dbbcaf 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx @@ -17,28 +17,49 @@ * under the License. */ import React, { useContext, useMemo, useState } from 'react'; +import { + createHtmlPortalNode, + InPortal, + OutPortal, +} from 'react-reverse-portal'; import { styled, SupersetTheme } from '@superset-ui/core'; import { FormItem as StyledFormItem, Form } from 'src/components/Form'; import { Tooltip } from 'src/components/Tooltip'; +import { FilterBarOrientation } from 'src/dashboard/types'; +import { truncationCSS } from 'src/hooks/useTruncation'; import { checkIsMissingRequiredValue } from '../utils'; import FilterValue from './FilterValue'; -import { FilterProps } from './types'; import { FilterCard } from '../../FilterCard'; -import { FilterBarScrollContext } from '../index'; +import { FilterBarScrollContext } from '../Vertical'; +import { FilterControlProps } from './types'; +import { FilterCardPlacement } from '../../FilterCard/types'; const StyledIcon = styled.div` position: absolute; right: 0; `; -const StyledFilterControlTitle = styled.h4` +const VerticalFilterControlTitle = styled.h4` font-size: ${({ theme }) => theme.typography.sizes.s}px; color: ${({ theme }) => theme.colors.grayscale.dark1}; margin: 0; overflow-wrap: break-word; `; -const StyledFilterControlTitleBox = styled.div` +const HorizontalFilterControlTitle = styled(VerticalFilterControlTitle)` + font-weight: ${({ theme }) => theme.typography.weights.normal}; + color: ${({ theme }) => theme.colors.grayscale.base}; + max-width: ${({ theme }) => theme.gridUnit * 15}px; + ${truncationCSS}; +`; + +const HorizontalOverflowFilterControlTitle = styled( + HorizontalFilterControlTitle, +)` + max-width: none; +`; + +const VerticalFilterControlTitleBox = styled.div` display: flex; flex-direction: row; align-items: center; @@ -46,7 +67,17 @@ const StyledFilterControlTitleBox = styled.div` margin-bottom: ${({ theme }) => theme.gridUnit}px; `; -const StyledFilterControlContainer = styled(Form)` +const HorizontalFilterControlTitleBox = styled(VerticalFilterControlTitleBox)` + margin-bottom: unset; +`; + +const HorizontalOverflowFilterControlTitleBox = styled( + VerticalFilterControlTitleBox, +)` + width: 100%; +`; + +const VerticalFilterControlContainer = styled(Form)` width: 100%; && .ant-form-item-label > label { text-transform: none; @@ -58,7 +89,28 @@ const StyledFilterControlContainer = styled(Form)` } `; -const FormItem = styled(StyledFormItem)` +const HorizontalFilterControlContainer = styled(Form)` + && .ant-form-item-label > label { + margin-bottom: 0; + text-transform: none; + } + .ant-form-item-tooltip { + margin-bottom: ${({ theme }) => theme.gridUnit}px; + } +`; + +const HorizontalOverflowFilterControlContainer = styled( + VerticalFilterControlContainer, +)` + && .ant-form-item-label { + line-height: 1; + & > label { + padding-right: unset; + } + } +`; + +const VerticalFormItem = styled(StyledFormItem)` .ant-form-item-label { label.ant-form-item-required:not(.ant-form-item-required-mark-optional) { &::after { @@ -68,6 +120,62 @@ const FormItem = styled(StyledFormItem)` } `; +const HorizontalFormItem = styled(StyledFormItem)` + && { + margin-bottom: 0; + align-items: center; + } + + .ant-form-item-label { + padding-bottom: 0; + margin-right: ${({ theme }) => theme.gridUnit * 2}px; + label.ant-form-item-required:not(.ant-form-item-required-mark-optional) { + &::after { + display: none; + } + } + + & > label::after { + display: none; + } + } + + .ant-form-item-control { + width: ${({ theme }) => theme.gridUnit * 41}px; + } +`; + +const HorizontalOverflowFormItem = VerticalFormItem; + +const useFilterControlDisplay = ( + orientation: FilterBarOrientation, + overflow: boolean, +) => + useMemo(() => { + if (orientation === FilterBarOrientation.HORIZONTAL) { + if (overflow) { + return { + FilterControlContainer: HorizontalOverflowFilterControlContainer, + FormItem: HorizontalOverflowFormItem, + FilterControlTitleBox: HorizontalOverflowFilterControlTitleBox, + FilterControlTitle: HorizontalOverflowFilterControlTitle, + }; + } + return { + FilterControlContainer: HorizontalFilterControlContainer, + FormItem: HorizontalFormItem, + FilterControlTitleBox: HorizontalFilterControlTitleBox, + FilterControlTitle: HorizontalFilterControlTitle, + }; + } + return { + FilterControlContainer: VerticalFilterControlContainer, + FormItem: VerticalFormItem, + FilterControlTitleBox: VerticalFilterControlTitleBox, + FilterControlTitle: VerticalFilterControlTitle, + }; + }, [orientation, overflow]); + const ToolTipContainer = styled.div` font-size: ${({ theme }) => theme.typography.sizes.m}px; display: flex; @@ -109,16 +217,19 @@ const DescriptionToolTip = ({ description }: { description: string }) => ( </ToolTipContainer> ); -const FilterControl: React.FC<FilterProps> = ({ +const FilterControl = ({ dataMaskSelected, filter, icon, onFilterSelectionChange, - directPathToChild, + focusedFilterId, inView, showOverflow, parentRef, -}) => { + orientation = FilterBarOrientation.VERTICAL, + overflow = false, +}: FilterControlProps) => { + const portalNode = useMemo(() => createHtmlPortalNode(), []); const [isFilterActive, setIsFilterActive] = useState(false); const { name = '<undefined>' } = filter; @@ -129,47 +240,87 @@ const FilterControl: React.FC<FilterProps> = ({ ); const isRequired = !!filter.controlValues?.enableEmptyFilter; + const { + FilterControlContainer, + FormItem, + FilterControlTitleBox, + FilterControlTitle, + } = useFilterControlDisplay(orientation, overflow); + const label = useMemo( () => ( - <StyledFilterControlTitleBox> - <StyledFilterControlTitle data-test="filter-control-name"> + <FilterControlTitleBox> + <FilterControlTitle data-test="filter-control-name"> {name} - </StyledFilterControlTitle> + </FilterControlTitle> {isRequired && <RequiredFieldIndicator />} - {filter.description && filter.description.trim() && ( + {filter.description?.trim() && ( <DescriptionToolTip description={filter.description} /> )} <StyledIcon data-test="filter-icon">{icon}</StyledIcon> - </StyledFilterControlTitleBox> + </FilterControlTitleBox> ), - [name, isRequired, filter.description, icon], + [ + FilterControlTitleBox, + FilterControlTitle, + name, + isRequired, + filter.description, + icon, + ], ); const isScrolling = useContext(FilterBarScrollContext); + const filterCardPlacement = useMemo(() => { + if (orientation === FilterBarOrientation.HORIZONTAL) { + if (overflow) { + return FilterCardPlacement.Left; + } + return FilterCardPlacement.Bottom; + } + return FilterCardPlacement.Right; + }, [orientation, overflow]); return ( - <StyledFilterControlContainer layout="vertical"> - <FilterCard filter={filter} isVisible={!isFilterActive && !isScrolling}> - <div> - <FormItem - label={label} - required={filter?.controlValues?.enableEmptyFilter} - validateStatus={isMissingRequiredValue ? 'error' : undefined} - > - <FilterValue - dataMaskSelected={dataMaskSelected} - filter={filter} - showOverflow={showOverflow} - directPathToChild={directPathToChild} - onFilterSelectionChange={onFilterSelectionChange} - inView={inView} - parentRef={parentRef} - setFilterActive={setIsFilterActive} - /> - </FormItem> - </div> - </FilterCard> - </StyledFilterControlContainer> + <> + <InPortal node={portalNode}> + <FilterValue + dataMaskSelected={dataMaskSelected} + filter={filter} + showOverflow={showOverflow} + focusedFilterId={focusedFilterId} + onFilterSelectionChange={onFilterSelectionChange} + inView={inView} + parentRef={parentRef} + setFilterActive={setIsFilterActive} + orientation={orientation} + overflow={overflow} + /> + </InPortal> + <FilterControlContainer + layout={ + orientation === FilterBarOrientation.HORIZONTAL && !overflow + ? 'horizontal' + : 'vertical' + } + > + <FilterCard + filter={filter} + isVisible={!isFilterActive && !isScrolling} + placement={filterCardPlacement} + > + <div> + <FormItem + label={label} + required={filter?.controlValues?.enableEmptyFilter} + validateStatus={isMissingRequiredValue ? 'error' : undefined} + > + <OutPortal node={portalNode} /> + </FormItem> + </div> + </FilterCard> + </FilterControlContainer> + </> ); }; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx index 79085daee3f48..a621052d51438 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx @@ -16,152 +16,247 @@ * specific language governing permissions and limitations * under the License. */ -import React, { FC, useCallback, useMemo } from 'react'; -import { css } from '@emotion/react'; +import React, { + FC, + useEffect, + useCallback, + useMemo, + useRef, + useState, +} from 'react'; import { DataMask, DataMaskStateWithId, Filter, - isFilterDivider, - styled, + Divider, + css, + SupersetTheme, t, + isFeatureEnabled, + FeatureFlag, + isNativeFilterWithDataMask, } from '@superset-ui/core'; import { createHtmlPortalNode, InPortal, OutPortal, } from 'react-reverse-portal'; -import { AntdCollapse } from 'src/components'; +import { useSelector } from 'react-redux'; import { useDashboardHasTabs, useSelectFiltersInScope, } from 'src/dashboard/components/nativeFilters/state'; -import { useFilters } from '../state'; -import FilterControl from './FilterControl'; - -const Wrapper = styled.div` - padding: ${({ theme }) => theme.gridUnit * 4}px; - // 108px padding to make room for buttons with position: absolute - padding-bottom: ${({ theme }) => theme.gridUnit * 27}px; -`; +import { FilterBarOrientation, RootState } from 'src/dashboard/types'; +import DropdownContainer, { + Ref as DropdownContainerRef, +} from 'src/components/DropdownContainer'; +import Icons from 'src/components/Icons'; +import { FiltersOutOfScopeCollapsible } from '../FiltersOutOfScopeCollapsible'; +import { useFilterControlFactory } from '../useFilterControlFactory'; +import { FiltersDropdownContent } from '../FiltersDropdownContent'; type FilterControlsProps = { - directPathToChild?: string[]; + focusedFilterId?: string; dataMaskSelected: DataMaskStateWithId; onFilterSelectionChange: (filter: Filter, dataMask: DataMask) => void; }; const FilterControls: FC<FilterControlsProps> = ({ - directPathToChild, + focusedFilterId, dataMaskSelected, onFilterSelectionChange, }) => { - const filters = useFilters(); - const filterValues = useMemo(() => Object.values(filters), [filters]); + const filterBarOrientation = useSelector<RootState, FilterBarOrientation>( + ({ dashboardInfo }) => + isFeatureEnabled(FeatureFlag.HORIZONTAL_FILTER_BAR) + ? dashboardInfo.filterBarOrientation + : FilterBarOrientation.VERTICAL, + ); + + const [overflowedIds, setOverflowedIds] = useState<string[]>([]); + const popoverRef = useRef<DropdownContainerRef>(null); + + const { filterControlFactory, filtersWithValues } = useFilterControlFactory( + dataMaskSelected, + focusedFilterId, + onFilterSelectionChange, + ); const portalNodes = useMemo(() => { - const nodes = new Array(filterValues.length); - for (let i = 0; i < filterValues.length; i += 1) { + const nodes = new Array(filtersWithValues.length); + for (let i = 0; i < filtersWithValues.length; i += 1) { nodes[i] = createHtmlPortalNode(); } return nodes; - }, [filterValues.length]); + }, [filtersWithValues.length]); - const filtersWithValues = useMemo( - () => - filterValues.map(filter => ({ - ...filter, - dataMask: dataMaskSelected[filter.id], - })), - [filterValues, dataMaskSelected], - ); const filterIds = new Set(filtersWithValues.map(item => item.id)); const [filtersInScope, filtersOutOfScope] = useSelectFiltersInScope(filtersWithValues); + const dashboardHasTabs = useDashboardHasTabs(); const showCollapsePanel = dashboardHasTabs && filtersWithValues.length > 0; - const filterControlFactory = useCallback( - index => { - const filter = filtersWithValues[index]; - if (isFilterDivider(filter)) { - return ( - <div> - <h3>{filter.title}</h3> - <p>{filter.description}</p> - </div> - ); - } + const renderer = useCallback( + ({ id }: Filter | Divider, index: number | undefined) => { + const filterIndex = filtersWithValues.findIndex(f => f.id === id); + const key = index ?? id; return ( - <FilterControl - dataMaskSelected={dataMaskSelected} - filter={filter} - directPathToChild={directPathToChild} - onFilterSelectionChange={onFilterSelectionChange} - inView={false} - /> + // Empty text node is to ensure there's always an element preceding + // the OutPortal, otherwise react-reverse-portal crashes + <React.Fragment key={key}> + {'' /* eslint-disable-line react/jsx-curly-brace-presence */} + <OutPortal node={portalNodes[filterIndex]} inView /> + </React.Fragment> ); }, - [ - filtersWithValues, - JSON.stringify(dataMaskSelected), - directPathToChild, - onFilterSelectionChange, - ], + [filtersWithValues, portalNodes], + ); + + const renderVerticalContent = () => ( + <> + {filtersInScope.map(renderer)} + {showCollapsePanel && ( + <FiltersOutOfScopeCollapsible + filtersOutOfScope={filtersOutOfScope} + hasTopMargin={filtersInScope.length > 0} + renderer={renderer} + /> + )} + </> ); + + const items = useMemo( + () => + filtersInScope.map((filter, index) => ({ + id: filter.id, + element: ( + <div + className="filter-item-wrapper" + css={css` + flex-shrink: 0; + `} + > + {renderer(filter, index)} + </div> + ), + })), + [filtersInScope, renderer], + ); + + const overflowedFiltersInScope = useMemo( + () => filtersInScope.filter(({ id }) => overflowedIds?.includes(id)), + [filtersInScope, overflowedIds], + ); + + const activeOverflowedFiltersInScope = useMemo( + () => + overflowedFiltersInScope.filter(filter => + isNativeFilterWithDataMask(filter), + ), + [overflowedFiltersInScope], + ); + + const renderHorizontalContent = () => ( + <div + css={(theme: SupersetTheme) => + css` + padding: 0 ${theme.gridUnit * 4}px; + min-width: 0; + flex: 1; + ` + } + > + <DropdownContainer + items={items} + dropdownTriggerIcon={ + <Icons.FilterSmall + css={css` + && { + margin-right: -4px; + display: flex; + } + `} + /> + } + dropdownTriggerText={t('More filters')} + dropdownTriggerCount={activeOverflowedFiltersInScope.length} + dropdownTriggerTooltip={ + activeOverflowedFiltersInScope.length === 0 + ? t('No applied filters') + : t( + 'Applied filters: %s', + activeOverflowedFiltersInScope + .map(filter => filter.name) + .join(', '), + ) + } + dropdownContent={ + overflowedFiltersInScope.length || + (filtersOutOfScope.length && showCollapsePanel) + ? () => ( + <FiltersDropdownContent + filtersInScope={overflowedFiltersInScope} + filtersOutOfScope={filtersOutOfScope} + renderer={renderer} + showCollapsePanel={showCollapsePanel} + /> + ) + : undefined + } + ref={popoverRef} + onOverflowingStateChange={({ overflowed: nextOverflowedIds }) => { + if ( + nextOverflowedIds.length !== overflowedIds.length || + overflowedIds.reduce( + (a, b, i) => a || b !== nextOverflowedIds[i], + false, + ) + ) { + setOverflowedIds(nextOverflowedIds); + } + }} + /> + </div> + ); + + const overflowedByIndex = useMemo(() => { + const filtersOutOfScopeIds = new Set(filtersOutOfScope.map(({ id }) => id)); + const overflowedFiltersInScopeIds = new Set( + overflowedFiltersInScope.map(({ id }) => id), + ); + + return filtersWithValues.map( + filter => + filtersOutOfScopeIds.has(filter.id) || + overflowedFiltersInScopeIds.has(filter.id), + ); + }, [filtersOutOfScope, filtersWithValues, overflowedFiltersInScope]); + + useEffect(() => { + if (focusedFilterId && overflowedIds.includes(focusedFilterId)) { + popoverRef?.current?.open(); + } + }, [focusedFilterId, popoverRef, overflowedIds]); + return ( - <Wrapper> + <> {portalNodes - .filter((node, index) => filterIds.has(filterValues[index].id)) + .filter((node, index) => filterIds.has(filtersWithValues[index].id)) .map((node, index) => ( - <InPortal node={node}>{filterControlFactory(index)}</InPortal> + <InPortal node={node} key={filtersWithValues[index].id}> + {filterControlFactory( + index, + filterBarOrientation, + overflowedByIndex[index], + )} + </InPortal> ))} - {filtersInScope.map(filter => { - const index = filterValues.findIndex(f => f.id === filter.id); - return <OutPortal node={portalNodes[index]} inView />; - })} - {showCollapsePanel && ( - <AntdCollapse - ghost - bordered - expandIconPosition="right" - collapsible={filtersOutOfScope.length === 0 ? 'disabled' : undefined} - css={theme => css` - &.ant-collapse { - margin-top: ${filtersInScope.length > 0 - ? theme.gridUnit * 6 - : 0}px; - & > .ant-collapse-item { - & > .ant-collapse-header { - padding-left: 0; - padding-bottom: ${theme.gridUnit * 2}px; - - & > .ant-collapse-arrow { - right: ${theme.gridUnit}px; - } - } - - & .ant-collapse-content-box { - padding: ${theme.gridUnit * 4}px 0 0; - } - } - } - `} - > - <AntdCollapse.Panel - header={t('Filters out of scope (%d)', filtersOutOfScope.length)} - key="1" - > - {filtersOutOfScope.map(filter => { - const index = filtersWithValues.findIndex( - f => f.id === filter.id, - ); - return <OutPortal node={portalNodes[index]} inView />; - })} - </AntdCollapse.Panel> - </AntdCollapse> - )} - </Wrapper> + {filterBarOrientation === FilterBarOrientation.VERTICAL && + renderVerticalContent()} + {filterBarOrientation === FilterBarOrientation.HORIZONTAL && + renderHorizontalContent()} + </> ); }; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.stories.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.stories.tsx new file mode 100644 index 0000000000000..46e7c03fadb5d --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.stories.tsx @@ -0,0 +1,121 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { css } from '@emotion/react'; +import { FilterBarOrientation } from 'src/dashboard/types'; +import FilterDivider from './FilterDivider'; +import { FilterDividerProps } from './types'; + +export default { + title: 'FilterDivider', + component: FilterDivider, +}; + +export const VerticalFilterDivider = (props: FilterDividerProps) => ( + <div + css={css` + background-color: #ddd; + padding: 50px; + `} + > + <div + css={css` + display: flex; + flex-direction: column; + width: 259px; + padding: 16px; + background-color: white; + `} + > + <FilterDivider {...props} /> + </div> + </div> +); + +export const HorizontalFilterDivider = (props: FilterDividerProps) => ( + <div + css={css` + background-color: #ddd; + padding: 50px; + `} + > + <div + css={css` + height: 48px; + padding: 0 16px; + display: flex; + align-items: center; + background-color: white; + `} + > + <FilterDivider orientation={FilterBarOrientation.HORIZONTAL} {...props} /> + </div> + </div> +); + +export const HorizontalOverflowFilterDivider = (props: FilterDividerProps) => ( + <div + css={css` + background-color: #ddd; + padding: 50px; + `} + > + <div + css={css` + width: 224px; + padding: 16px; + background-color: white; + `} + > + <FilterDivider {...props} /> + </div> + </div> +); + +const args = { + title: 'Sample title', + description: 'Sample description', +}; + +const story = { parameters: { knobs: { disable: true } } }; + +VerticalFilterDivider.args = { + ...args, + horizontal: false, + overflow: false, +}; + +VerticalFilterDivider.story = story; + +HorizontalFilterDivider.args = { + ...args, + horizontal: true, + overflow: false, +}; + +HorizontalFilterDivider.story = story; + +HorizontalOverflowFilterDivider.args = { + ...args, + horizontal: true, + overflow: true, +}; + +HorizontalOverflowFilterDivider.story = story; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.test.tsx new file mode 100644 index 0000000000000..8491c93d8fa14 --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.test.tsx @@ -0,0 +1,135 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import { FilterBarOrientation } from 'src/dashboard/types'; +import FilterDivider from './FilterDivider'; + +const SAMPLE_TITLE = 'Sample title'; +const SAMPLE_DESCRIPTION = + 'Sample description that is even longer, it goes on and on and on and on and on and on and on and on and on and on.'; + +test('vertical mode, title', () => { + render(<FilterDivider title={SAMPLE_TITLE} description="" />); + const title = screen.getByRole('heading', { name: SAMPLE_TITLE }); + expect(title).toBeVisible(); + expect(title).toHaveTextContent(SAMPLE_TITLE); + const description = screen.queryByTestId('divider-description'); + expect(description).not.toBeInTheDocument(); + const descriptionIcon = screen.queryByTestId('divider-description-icon'); + expect(descriptionIcon).not.toBeInTheDocument(); +}); + +test('vertical mode, title and description', () => { + render( + <FilterDivider title={SAMPLE_TITLE} description={SAMPLE_DESCRIPTION} />, + ); + + const title = screen.getByRole('heading', { name: SAMPLE_TITLE }); + expect(title).toBeVisible(); + expect(title).toHaveTextContent(SAMPLE_TITLE); + const description = screen.getByTestId('divider-description'); + expect(description).toBeVisible(); + expect(description).toHaveTextContent(SAMPLE_DESCRIPTION); + const descriptionIcon = screen.queryByTestId('divider-description-icon'); + expect(descriptionIcon).not.toBeInTheDocument(); +}); + +test('horizontal mode, title', () => { + render( + <FilterDivider + orientation={FilterBarOrientation.HORIZONTAL} + title={SAMPLE_TITLE} + description="" + overflow + />, + ); + + const title = screen.getByRole('heading', { name: SAMPLE_TITLE }); + expect(title).toBeVisible(); + expect(title).toHaveTextContent(SAMPLE_TITLE); + const description = screen.queryByTestId('divider-description'); + expect(description).not.toBeInTheDocument(); + const descriptionIcon = screen.queryByTestId('divider-description-icon'); + expect(descriptionIcon).not.toBeInTheDocument(); +}); + +test('horizontal mode, title and description', async () => { + render( + <FilterDivider + orientation={FilterBarOrientation.HORIZONTAL} + title={SAMPLE_TITLE} + description={SAMPLE_DESCRIPTION} + />, + ); + + const title = screen.getByRole('heading', { name: SAMPLE_TITLE }); + expect(title).toBeVisible(); + expect(title).toHaveTextContent(SAMPLE_TITLE); + const description = screen.queryByTestId('divider-description'); + expect(description).not.toBeInTheDocument(); + const descriptionIcon = screen.getByTestId('divider-description-icon'); + expect(descriptionIcon).toBeVisible(); + userEvent.hover(descriptionIcon); + const tooltip = await screen.findByRole('tooltip'); + + expect(tooltip).toBeInTheDocument(); + expect(tooltip).toHaveTextContent(SAMPLE_DESCRIPTION); +}); + +test('horizontal overflow mode, title', () => { + render( + <FilterDivider + orientation={FilterBarOrientation.HORIZONTAL} + overflow + title={SAMPLE_TITLE} + description="" + />, + ); + + const title = screen.getByRole('heading', { name: SAMPLE_TITLE }); + expect(title).toBeVisible(); + expect(title).toHaveTextContent(SAMPLE_TITLE); + const description = screen.queryByTestId('divider-description'); + expect(description).not.toBeInTheDocument(); + const descriptionIcon = screen.queryByTestId('divider-description-icon'); + expect(descriptionIcon).not.toBeInTheDocument(); +}); + +test('horizontal overflow mode, title and description', () => { + render( + <FilterDivider + orientation={FilterBarOrientation.HORIZONTAL} + overflow + title={SAMPLE_TITLE} + description={SAMPLE_DESCRIPTION} + />, + ); + + const title = screen.getByRole('heading', { name: SAMPLE_TITLE }); + expect(title).toBeVisible(); + expect(title).toHaveTextContent(SAMPLE_TITLE); + const description = screen.queryByTestId('divider-description'); + expect(description).toBeVisible(); + expect(description).toHaveTextContent(SAMPLE_DESCRIPTION); + const descriptionIcon = screen.queryByTestId('divider-description-icon'); + expect(descriptionIcon).not.toBeInTheDocument(); +}); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.tsx new file mode 100644 index 0000000000000..e06a56ac7bc66 --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.tsx @@ -0,0 +1,162 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { css, useTheme } from '@superset-ui/core'; +import React from 'react'; +import Icons from 'src/components/Icons'; +import { Tooltip } from 'src/components/Tooltip'; +import { FilterBarOrientation } from 'src/dashboard/types'; +import { useCSSTextTruncation, truncationCSS } from 'src/hooks/useTruncation'; +import { FilterDividerProps } from './types'; + +const VerticalDivider = ({ title, description }: FilterDividerProps) => ( + <div> + <h3>{title}</h3> + {description ? <p data-test="divider-description">{description}</p> : null} + </div> +); + +const HorizontalDivider = ({ title, description }: FilterDividerProps) => { + const theme = useTheme(); + const [titleRef, titleIsTruncated] = + useCSSTextTruncation<HTMLHeadingElement>(); + + return ( + <div + css={css` + display: flex; + align-items: center; + height: ${6 * theme.gridUnit}px; + border-left: 1px solid ${theme.colors.grayscale.light2}; + padding-left: ${4 * theme.gridUnit}px; + + .filter-item-wrapper:first-child & { + border-left: none; + padding-left: 0; + } + `} + > + <Tooltip overlay={titleIsTruncated ? title : null}> + <h3 + ref={titleRef} + css={css` + ${truncationCSS}; + max-width: ${theme.gridUnit * 32.5}px; + font-size: ${theme.typography.sizes.m}px; + font-weight: ${theme.typography.weights.normal}; + margin: 0; + color: ${theme.colors.grayscale.dark1}; + `} + > + {title} + </h3> + </Tooltip> + {description ? ( + <Tooltip overlay={description}> + <Icons.BookOutlined + data-test="divider-description-icon" + iconSize="l" + iconColor={theme.colors.grayscale.base} + css={css` + margin: 0 ${theme.gridUnit * 1.5}px; + vertical-align: unset; + line-height: unset; + `} + /> + </Tooltip> + ) : null} + </div> + ); +}; + +const HorizontalOverflowDivider = ({ + title, + description, +}: FilterDividerProps) => { + const theme = useTheme(); + const [titleRef, titleIsTruncated] = + useCSSTextTruncation<HTMLHeadingElement>(); + + const [descriptionRef, descriptionIsTruncated] = + useCSSTextTruncation<HTMLHeadingElement>(); + + return ( + <div + css={css` + border-top: 1px solid ${theme.colors.grayscale.light2}; + padding-top: ${theme.gridUnit * 4}px; + margin-bottom: ${theme.gridUnit * 4}px; + `} + > + <Tooltip overlay={titleIsTruncated ? <strong>{title}</strong> : null}> + <h3 + ref={titleRef} + css={css` + ${truncationCSS}; + display: block; + color: ${theme.colors.grayscale.dark1}; + font-weight: ${theme.typography.weights.normal}; + font-size: ${theme.typography.sizes.m}px; + margin: 0 0 ${theme.gridUnit}px 0; + `} + > + {title} + </h3> + </Tooltip> + {description ? ( + <Tooltip overlay={descriptionIsTruncated ? description : null}> + <p + ref={descriptionRef} + data-test="divider-description" + css={css` + ${truncationCSS}; + display: block; + font-size: ${theme.typography.sizes.s}px; + color: ${theme.colors.grayscale.base}; + margin: ${theme.gridUnit}px 0 0 0; + `} + > + {description} + </p> + </Tooltip> + ) : null} + </div> + ); +}; + +const FilterDivider = ({ + title, + description, + orientation = FilterBarOrientation.VERTICAL, + overflow = false, +}: FilterDividerProps) => { + if (orientation === FilterBarOrientation.HORIZONTAL) { + if (overflow) { + return ( + <HorizontalOverflowDivider title={title} description={description} /> + ); + } + + return <HorizontalDivider title={title} description={description} />; + } + + return <VerticalDivider title={title} description={description} />; +}; + +export default FilterDivider; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx index 4337d59ed86fc..308361622e16a 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx @@ -42,10 +42,11 @@ import BasicErrorAlert from 'src/components/ErrorMessage/BasicErrorAlert'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import { waitForAsyncData } from 'src/middleware/asyncEvent'; import { ClientErrorObject } from 'src/utils/getClientErrorObject'; -import { RootState } from 'src/dashboard/types'; +import { FilterBarOrientation, RootState } from 'src/dashboard/types'; import { onFiltersRefreshSuccess } from 'src/dashboard/actions/dashboardState'; -import { dispatchFocusAction } from './utils'; -import { FilterProps } from './types'; +import { FAST_DEBOUNCE } from 'src/constants'; +import { dispatchHoverAction, dispatchFocusAction } from './utils'; +import { FilterControlProps } from './types'; import { getFormData } from '../../utils'; import { useFilterDependencies } from './state'; import { checkIsMissingRequiredValue } from '../utils'; @@ -75,15 +76,17 @@ const useShouldFilterRefresh = () => { return !isDashboardRefreshing && isFilterRefreshing; }; -const FilterValue: React.FC<FilterProps> = ({ +const FilterValue: React.FC<FilterControlProps> = ({ dataMaskSelected, filter, - directPathToChild, + focusedFilterId, onFilterSelectionChange, inView = true, showOverflow, parentRef, setFilterActive, + orientation = FilterBarOrientation.VERTICAL, + overflow = false, }) => { const { id, targets, filterType, adhoc_filters, time_range } = filter; const metadata = getChartMetadataRegistry().get(filterType); @@ -209,10 +212,12 @@ const FilterValue: React.FC<FilterProps> = ({ ]); useEffect(() => { - if (directPathToChild?.[0] === filter.id) { - inputRef?.current?.focus(); + if (focusedFilterId && focusedFilterId === filter.id) { + setTimeout(() => { + inputRef?.current?.focus(); + }, FAST_DEBOUNCE); } - }, [inputRef, directPathToChild, filter.id]); + }, [inputRef, focusedFilterId, filter.id]); const setDataMask = useCallback( (dataMask: DataMask) => onFilterSelectionChange(filter, dataMask), @@ -228,14 +233,32 @@ const FilterValue: React.FC<FilterProps> = ({ [dispatch], ); + const setHoveredFilter = useCallback( + () => dispatchHoverAction(dispatch, id), + [dispatch, id], + ); + const unsetHoveredFilter = useCallback( + () => dispatchHoverAction(dispatch), + [dispatch], + ); + const hooks = useMemo( () => ({ setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, }), - [setDataMask, setFilterActive, setFocusedFilter, unsetFocusedFilter], + [ + setDataMask, + setFilterActive, + setHoveredFilter, + unsetHoveredFilter, + setFocusedFilter, + unsetFocusedFilter, + ], ); const isMissingRequiredValue = checkIsMissingRequiredValue( @@ -251,6 +274,14 @@ const FilterValue: React.FC<FilterProps> = ({ [filter.dataMask?.filterState, isMissingRequiredValue], ); + const displaySettings = useMemo( + () => ({ + filterBarOrientation: orientation, + isOverflowingFilterBar: overflow, + }), + [orientation, overflow], + ); + if (error) { return ( <BasicErrorAlert @@ -271,6 +302,7 @@ const FilterValue: React.FC<FilterProps> = ({ width="100%" showOverflow={showOverflow} formData={formData} + displaySettings={displaySettings} parentRef={parentRef} inputRef={inputRef} // For charts that don't have datasource we need workaround for empty placeholder @@ -287,4 +319,4 @@ const FilterValue: React.FC<FilterProps> = ({ </StyledDiv> ); }; -export default FilterValue; +export default React.memo(FilterValue); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/types.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/types.ts index e5b553712634e..ac9cca8c01799 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/types.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/types.ts @@ -18,14 +18,25 @@ */ import React, { RefObject } from 'react'; import { DataMask, DataMaskStateWithId, Filter } from '@superset-ui/core'; +import { FilterBarOrientation } from 'src/dashboard/types'; -export interface FilterProps { +export interface BaseFilterProps { + orientation?: FilterBarOrientation; + overflow?: boolean; +} + +export interface FilterDividerProps extends BaseFilterProps { + title: string; + description: string; +} + +export interface FilterControlProps extends BaseFilterProps { dataMaskSelected?: DataMaskStateWithId; filter: Filter & { dataMask?: DataMask; }; icon?: React.ReactElement; - directPathToChild?: string[]; + focusedFilterId?: string; onFilterSelectionChange: (filter: Filter, dataMask: DataMask) => void; inView?: boolean; showOverflow?: boolean; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/utils.ts index 3077c42768e84..5e0e159d1189d 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/utils.ts @@ -21,7 +21,21 @@ import { Dispatch } from 'react'; import { setFocusedNativeFilter, unsetFocusedNativeFilter, + setHoveredNativeFilter, + unsetHoveredNativeFilter, } from 'src/dashboard/actions/nativeFilters'; +import { FAST_DEBOUNCE } from 'src/constants'; + +export const dispatchHoverAction = debounce( + (dispatch: Dispatch<any>, id?: string) => { + if (id) { + dispatch(setHoveredNativeFilter(id)); + } else { + dispatch(unsetHoveredNativeFilter()); + } + }, + FAST_DEBOUNCE, +); export const dispatchFocusAction = debounce( (dispatch: Dispatch<any>, id?: string) => { @@ -31,5 +45,5 @@ export const dispatchFocusAction = debounce( dispatch(unsetFocusedNativeFilter()); } }, - 300, + FAST_DEBOUNCE, ); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx index 689eaa826627d..4b753a6a3e6a3 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx @@ -22,12 +22,12 @@ import { Typography, AntdTooltip } from 'src/components'; import { useDispatch } from 'react-redux'; import Button from 'src/components/Button'; import { updateFilterSet } from 'src/dashboard/actions/nativeFilters'; -import { WarningOutlined } from '@ant-design/icons'; +import Icons from 'src/components/Icons'; import { ActionButtons } from './Footer'; import { useNativeFiltersDataMask, useFilters, useFilterSets } from '../state'; import { APPLY_FILTERS_HINT, findExistingFilterSet } from './utils'; import { useFilterSetNameDuplicated } from './state'; -import { getFilterBarTestId } from '../index'; +import { getFilterBarTestId } from '../utils'; const Wrapper = styled.div` display: grid; @@ -160,7 +160,7 @@ const EditSection: FC<EditSectionProps> = ({ </ActionButtons> {isDuplicateFilterSet && ( <Warning mark> - <WarningOutlined /> + <Icons.WarningOutlined iconSize="m" /> {t('This filter set is identical to: "%s"', foundFilterSet?.name)} </Warning> )} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.test.tsx index a5e34432cd7f1..50fe910c53ae1 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.test.tsx @@ -32,7 +32,7 @@ const createProps = () => ({ }); function openDropdown() { - const dropdownIcon = screen.getByRole('img', { name: 'ellipsis' }); + const dropdownIcon = screen.getAllByRole('img', { name: '' })[0]; userEvent.click(dropdownIcon); } diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx index 53ea1c94c5289..74cf3aa6625e4 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx @@ -27,11 +27,11 @@ import { useTheme, t, } from '@superset-ui/core'; -import { CheckOutlined, EllipsisOutlined } from '@ant-design/icons'; +import Icons from 'src/components/Icons'; import Button from 'src/components/Button'; import { Tooltip } from 'src/components/Tooltip'; import FiltersHeader from './FiltersHeader'; -import { getFilterBarTestId } from '..'; +import { getFilterBarTestId } from '../utils'; const HeaderButton = styled(Button)` padding: 0; @@ -107,7 +107,10 @@ const FilterSetUnit: FC<FilterSetUnitProps> = ({ </Typography.Text> <IconsBlock> {isApplied && ( - <CheckOutlined style={{ color: theme.colors.success.base }} /> + <Icons.CheckOutlined + iconSize="m" + iconColor={theme.colors.success.base} + /> )} {onDelete && ( <AntdDropdown @@ -124,7 +127,7 @@ const FilterSetUnit: FC<FilterSetUnitProps> = ({ buttonStyle="link" buttonSize="xsmall" > - <EllipsisOutlined /> + <Icons.EllipsisOutlined iconSize="m" /> </HeaderButton> </AntdDropdown> )} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSets.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSets.test.tsx index 78ad4599933d3..2fe855147ab60 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSets.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSets.test.tsx @@ -21,7 +21,7 @@ import { render, screen } from 'spec/helpers/testing-library'; import { mockStore } from 'spec/fixtures/mockStore'; import { Provider } from 'react-redux'; import FilterSets, { FilterSetsProps } from '.'; -import { TabIds } from '../utils'; +import { TabIds } from '../types'; const createProps = () => ({ disabled: false, diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx index 5a7bff6527f37..5982bf515a6eb 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx @@ -30,7 +30,7 @@ import Icons from 'src/components/Icons'; import { areObjectsEqual } from 'src/reduxUtils'; import { getFilterValueForDisplay } from './utils'; import { useFilters } from '../state'; -import { getFilterBarTestId } from '../index'; +import { getFilterBarTestId } from '../utils'; const FilterHeader = styled.div` display: flex; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx index df6c6ee44ebf0..7847927ff5b86 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx @@ -22,7 +22,7 @@ import Button from 'src/components/Button'; import { Tooltip } from 'src/components/Tooltip'; import { APPLY_FILTERS_HINT } from './utils'; import { useFilterSetNameDuplicated } from './state'; -import { getFilterBarTestId } from '..'; +import { getFilterBarTestId } from '../utils'; export type FooterProps = { filterSetName: string; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx index 5fdfd481719ea..2e12425de75b8 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx @@ -40,8 +40,8 @@ import { findExistingFilterSet } from './utils'; import { useFilters, useNativeFiltersDataMask, useFilterSets } from '../state'; import Footer from './Footer'; import FilterSetUnit from './FilterSetUnit'; -import { getFilterBarTestId } from '..'; -import { TabIds } from '../utils'; +import { getFilterBarTestId } from '../utils'; +import { TabIds } from '../types'; const FilterSetsWrapper = styled.div` display: grid; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersDropdownContent/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersDropdownContent/index.tsx new file mode 100644 index 0000000000000..84710c94b5f09 --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersDropdownContent/index.tsx @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { ReactNode } from 'react'; +import { css, Divider, Filter, SupersetTheme } from '@superset-ui/core'; +import { FiltersOutOfScopeCollapsible } from '../FiltersOutOfScopeCollapsible'; + +export interface FiltersDropdownContentProps { + filtersInScope: (Filter | Divider)[]; + filtersOutOfScope: (Filter | Divider)[]; + renderer: (filter: Filter | Divider, index: number) => ReactNode; + showCollapsePanel?: boolean; +} + +export const FiltersDropdownContent = ({ + filtersInScope, + filtersOutOfScope, + renderer, + showCollapsePanel, +}: FiltersDropdownContentProps) => ( + <div + css={(theme: SupersetTheme) => + css` + width: ${theme.gridUnit * 56}px; + padding: ${theme.gridUnit}px 0; + ` + } + > + {filtersInScope.map(renderer)} + {showCollapsePanel && ( + <FiltersOutOfScopeCollapsible + filtersOutOfScope={filtersOutOfScope} + renderer={renderer} + horizontalOverflow + /> + )} + </div> +); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersOutOfScopeCollapsible/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersOutOfScopeCollapsible/index.tsx new file mode 100644 index 0000000000000..a85f1907322c1 --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersOutOfScopeCollapsible/index.tsx @@ -0,0 +1,89 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { ReactNode } from 'react'; +import { css } from '@emotion/react'; +import { Divider, Filter, SupersetTheme, t } from '@superset-ui/core'; +import { AntdCollapse } from 'src/components'; + +export interface FiltersOutOfScopeCollapsibleProps { + filtersOutOfScope: (Filter | Divider)[]; + renderer: (filter: Filter | Divider, index: number) => ReactNode; + hasTopMargin?: boolean; + horizontalOverflow?: boolean; +} + +export const FiltersOutOfScopeCollapsible = ({ + filtersOutOfScope, + renderer, + hasTopMargin, + horizontalOverflow, +}: FiltersOutOfScopeCollapsibleProps) => ( + <AntdCollapse + ghost + bordered + expandIconPosition="right" + collapsible={filtersOutOfScope.length === 0 ? 'disabled' : undefined} + css={(theme: SupersetTheme) => + horizontalOverflow + ? css` + &.ant-collapse > .ant-collapse-item { + & > .ant-collapse-header { + padding: 0; + + & > .ant-collapse-arrow { + right: 0; + padding: 0; + } + } + + & .ant-collapse-content-box { + padding: ${theme.gridUnit * 4}px 0 0; + margin-bottom: ${theme.gridUnit * -4}px; + } + } + ` + : css` + &.ant-collapse { + margin-top: ${hasTopMargin ? theme.gridUnit * 6 : 0}px; + & > .ant-collapse-item { + & > .ant-collapse-header { + padding-left: 0; + padding-bottom: ${theme.gridUnit * 2}px; + + & > .ant-collapse-arrow { + right: ${theme.gridUnit}px; + } + } + + & .ant-collapse-content-box { + padding: ${theme.gridUnit * 4}px 0 0; + } + } + } + ` + } + > + <AntdCollapse.Panel + header={t('Filters out of scope (%d)', filtersOutOfScope.length)} + key="1" + > + {filtersOutOfScope.map(renderer)} + </AntdCollapse.Panel> + </AntdCollapse> +); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx index 45019f58cdfc7..7cd4877d11e2c 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx @@ -18,25 +18,39 @@ */ /* eslint-disable no-param-reassign */ import { css, styled, t, useTheme } from '@superset-ui/core'; -import React, { FC } from 'react'; +import React, { FC, useMemo } from 'react'; import Icons from 'src/components/Icons'; import Button from 'src/components/Button'; import { useSelector } from 'react-redux'; import FilterConfigurationLink from 'src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink'; import { useFilters } from 'src/dashboard/components/nativeFilters/FilterBar/state'; import { RootState } from 'src/dashboard/types'; -import { getFilterBarTestId } from '..'; +import { getFilterBarTestId } from '../utils'; +import FilterBarSettings from '../FilterBarSettings'; -const TitleArea = styled.h4` - display: flex; - flex-direction: row; - justify-content: space-between; - margin: 0; - padding: ${({ theme }) => theme.gridUnit * 2}px; +const TitleArea = styled.div` + ${({ theme }) => css` + display: flex; + align-items: center; + flex-direction: row; + justify-content: space-between; + margin: 0; + padding: 0 ${theme.gridUnit * 2}px ${theme.gridUnit * 2}px; + + & > span { + font-size: ${theme.typography.sizes.l}px; + flex-grow: 1; + font-weight: ${theme.typography.weights.bold}; + } + + & > div:first-of-type { + line-height: 0; + } - & > span { - flex-grow: 1; - } + & > button > span.anticon { + line-height: 0; + } + `} `; const HeaderButton = styled(Button)` @@ -44,8 +58,15 @@ const HeaderButton = styled(Button)` `; const Wrapper = styled.div` - padding: ${({ theme }) => theme.gridUnit}px - ${({ theme }) => theme.gridUnit * 2}px; + ${({ theme }) => ` + padding: ${theme.gridUnit * 3}px ${theme.gridUnit * 2}px ${ + theme.gridUnit + }px; + + .ant-dropdown-trigger span { + padding-right: ${theme.gridUnit * 2}px; + } + `} `; type HeaderProps = { @@ -74,7 +95,7 @@ const AddFiltersButtonContainer = styled.div` const Header: FC<HeaderProps> = ({ toggleFiltersBar }) => { const theme = useTheme(); const filters = useFilters(); - const filterValues = Object.values(filters); + const filterValues = useMemo(() => Object.values(filters), [filters]); const canEdit = useSelector<RootState, boolean>( ({ dashboardInfo }) => dashboardInfo.dash_edit_perm, ); @@ -86,6 +107,7 @@ const Header: FC<HeaderProps> = ({ toggleFiltersBar }) => { <Wrapper> <TitleArea> <span>{t('Filters')}</span> + <FilterBarSettings /> <HeaderButton {...getFilterBarTestId('collapse-button')} buttonStyle="link" @@ -109,4 +131,4 @@ const Header: FC<HeaderProps> = ({ toggleFiltersBar }) => { ); }; -export default Header; +export default React.memo(Header); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx new file mode 100644 index 0000000000000..7e786985e890f --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx @@ -0,0 +1,138 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { styled, t } from '@superset-ui/core'; +import Icons from 'src/components/Icons'; +import Loading from 'src/components/Loading'; +import FilterControls from './FilterControls/FilterControls'; +import { getFilterBarTestId } from './utils'; +import { HorizontalBarProps } from './types'; +import FilterBarSettings from './FilterBarSettings'; +import FilterConfigurationLink from './FilterConfigurationLink'; + +const HorizontalBar = styled.div` + ${({ theme }) => ` + padding: ${theme.gridUnit * 3}px ${theme.gridUnit * 2}px ${ + theme.gridUnit * 3 + }px ${theme.gridUnit * 4}px; + background: ${theme.colors.grayscale.light5}; + box-shadow: inset 0px -2px 2px -1px ${theme.colors.grayscale.light2}; + `} +`; + +const HorizontalBarContent = styled.div` + ${({ theme }) => ` + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + justify-content: flex-start; + line-height: 0; + + .loading { + margin: ${theme.gridUnit * 2}px auto ${theme.gridUnit * 2}px; + padding: 0; + } + `} +`; + +const FilterBarEmptyStateContainer = styled.div` + ${({ theme }) => ` + font-weight: ${theme.typography.weights.bold}; + color: ${theme.colors.grayscale.base}; + font-size: ${theme.typography.sizes.s}px; + `} +`; + +const FiltersLinkContainer = styled.div<{ hasFilters: boolean }>` + ${({ theme, hasFilters }) => ` + height: 24px; + display: flex; + align-items: center; + padding: 0 ${theme.gridUnit * 4}px 0 ${theme.gridUnit * 4}px; + border-right: ${ + hasFilters ? `1px solid ${theme.colors.grayscale.light2}` : 0 + }; + + button { + display: flex; + align-items: center; + > .anticon { + height: 24px; + padding-right: ${theme.gridUnit}px; + } + > .anticon + span, > .anticon { + margin-right: 0; + margin-left: 0; + } + } + `} +`; + +const HorizontalFilterBar: React.FC<HorizontalBarProps> = ({ + actions, + canEdit, + dashboardId, + dataMaskSelected, + filterValues, + isInitialized, + focusedFilterId, + onSelectionChange, +}) => { + const hasFilters = filterValues.length > 0; + + return ( + <HorizontalBar {...getFilterBarTestId()}> + <HorizontalBarContent> + {!isInitialized ? ( + <Loading position="inline-centered" /> + ) : ( + <> + <FilterBarSettings /> + {canEdit && ( + <FiltersLinkContainer hasFilters={hasFilters}> + <FilterConfigurationLink + dashboardId={dashboardId} + createNewOnOpen={filterValues.length === 0} + > + <Icons.PlusSmall /> {t('Add/Edit Filters')} + </FilterConfigurationLink> + </FiltersLinkContainer> + )} + {!hasFilters && ( + <FilterBarEmptyStateContainer data-test="horizontal-filterbar-empty"> + {t('No filters are currently added to this dashboard.')} + </FilterBarEmptyStateContainer> + )} + {hasFilters && ( + <FilterControls + dataMaskSelected={dataMaskSelected} + focusedFilterId={focusedFilterId} + onFilterSelectionChange={onSelectionChange} + /> + )} + {actions} + </> + )} + </HorizontalBarContent> + </HorizontalBar> + ); +}; +export default React.memo(HorizontalFilterBar); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/HorizontalFilterBar.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/HorizontalFilterBar.test.tsx new file mode 100644 index 0000000000000..c0b2b7c199403 --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/HorizontalFilterBar.test.tsx @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { NativeFilterType } from '@superset-ui/core'; +import React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import HorizontalBar from './Horizontal'; + +const defaultProps = { + actions: null, + canEdit: true, + dashboardId: 1, + dataMaskSelected: {}, + filterValues: [], + isInitialized: true, + onSelectionChange: jest.fn(), +}; + +const renderWrapper = (overrideProps?: Record<string, any>) => + waitFor(() => + render(<HorizontalBar {...defaultProps} {...overrideProps} />, { + useRedux: true, + initialState: { + dashboardInfo: { + dash_edit_perm: true, + }, + }, + }), + ); + +test('should render', async () => { + const { container } = await renderWrapper(); + expect(container).toBeInTheDocument(); +}); + +test('should not render the empty message', async () => { + await renderWrapper({ + filterValues: [ + { + id: 'test', + type: NativeFilterType.NATIVE_FILTER, + }, + ], + }); + expect( + screen.queryByText('No filters are currently added to this dashboard.'), + ).not.toBeInTheDocument(); +}); + +test('should render the empty message', async () => { + await renderWrapper(); + expect( + screen.getByText('No filters are currently added to this dashboard.'), + ).toBeInTheDocument(); +}); + +test('should not render the loading icon', async () => { + await renderWrapper(); + expect( + screen.queryByRole('status', { name: 'Loading' }), + ).not.toBeInTheDocument(); +}); + +test('should render the loading icon', async () => { + await renderWrapper({ + isInitialized: false, + }); + expect(screen.getByRole('status', { name: 'Loading' })).toBeInTheDocument(); +}); + +test('should render Add/Edit Filters', async () => { + await renderWrapper(); + expect(screen.getByText('Add/Edit Filters')).toBeInTheDocument(); +}); + +test('should not render Add/Edit Filters', async () => { + await renderWrapper({ + canEdit: false, + }); + expect(screen.queryByText('Add/Edit Filters')).not.toBeInTheDocument(); +}); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx new file mode 100644 index 0000000000000..2a6b7178362d1 --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx @@ -0,0 +1,316 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* eslint-disable no-param-reassign */ +import throttle from 'lodash/throttle'; +import React, { + useEffect, + useState, + useCallback, + useMemo, + useRef, + createContext, +} from 'react'; +import cx from 'classnames'; +import { HandlerFunction, styled, t, isNativeFilter } from '@superset-ui/core'; +import Icons from 'src/components/Icons'; +import { AntdTabs } from 'src/components'; +import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; +import Loading from 'src/components/Loading'; +import { EmptyStateSmall } from 'src/components/EmptyState'; +import { getFilterBarTestId } from './utils'; +import { TabIds, VerticalBarProps } from './types'; +import FilterSets from './FilterSets'; +import { useFilterSets } from './state'; +import EditSection from './FilterSets/EditSection'; +import Header from './Header'; +import FilterControls from './FilterControls/FilterControls'; + +const BarWrapper = styled.div<{ width: number }>` + width: ${({ theme }) => theme.gridUnit * 8}px; + + & .ant-tabs-top > .ant-tabs-nav { + margin: 0; + } + &.open { + width: ${({ width }) => width}px; // arbitrary... + } +`; + +const Bar = styled.div<{ width: number }>` + ${({ theme, width }) => ` + & .ant-typography-edit-content { + left: 0; + margin-top: 0; + width: 100%; + } + position: absolute; + top: 0; + left: 0; + flex-direction: column; + flex-grow: 1; + width: ${width}px; + background: ${theme.colors.grayscale.light5}; + border-right: 1px solid ${theme.colors.grayscale.light2}; + border-bottom: 1px solid ${theme.colors.grayscale.light2}; + min-height: 100%; + display: none; + &.open { + display: flex; + } + `} +`; + +const CollapsedBar = styled.div<{ offset: number }>` + ${({ theme, offset }) => ` + position: absolute; + top: ${offset}px; + left: 0; + height: 100%; + width: ${theme.gridUnit * 8}px; + padding-top: ${theme.gridUnit * 2}px; + display: none; + text-align: center; + &.open { + display: flex; + flex-direction: column; + align-items: center; + padding: ${theme.gridUnit * 2}px; + } + svg { + cursor: pointer; + } + `} +`; + +const StyledCollapseIcon = styled(Icons.Collapse)` + ${({ theme }) => ` + color: ${theme.colors.primary.base}; + margin-bottom: ${theme.gridUnit * 3}px; + `} +`; + +const StyledFilterIcon = styled(Icons.Filter)` + color: ${({ theme }) => theme.colors.grayscale.base}; +`; + +const StyledTabs = styled(AntdTabs)` + & .ant-tabs-nav-list { + width: 100%; + } + & .ant-tabs-tab { + display: flex; + justify-content: center; + margin: 0; + flex: 1; + } + + & > .ant-tabs-nav .ant-tabs-nav-operations { + display: none; + } +`; + +const FilterBarEmptyStateContainer = styled.div` + margin-top: ${({ theme }) => theme.gridUnit * 8}px; +`; + +const FilterControlsWrapper = styled.div` + padding: ${({ theme }) => theme.gridUnit * 4}px; + // 108px padding to make room for buttons with position: absolute + padding-bottom: ${({ theme }) => theme.gridUnit * 27}px; +`; + +export const FilterBarScrollContext = createContext(false); +const VerticalFilterBar: React.FC<VerticalBarProps> = ({ + actions, + canEdit, + dataMaskSelected, + focusedFilterId, + filtersOpen, + filterValues, + height, + isDisabled, + isInitialized, + offset, + onSelectionChange, + toggleFiltersBar, + width, +}) => { + const [editFilterSetId, setEditFilterSetId] = useState<number | null>(null); + const filterSets = useFilterSets(); + const filterSetFilterValues = Object.values(filterSets); + const [tab, setTab] = useState(TabIds.AllFilters); + const nativeFilterValues = filterValues.filter(isNativeFilter); + const [isScrolling, setIsScrolling] = useState(false); + const timeout = useRef<any>(); + + const openFiltersBar = useCallback( + () => toggleFiltersBar(true), + [toggleFiltersBar], + ); + + const onScroll = useMemo( + () => + throttle(() => { + clearTimeout(timeout.current); + setIsScrolling(true); + timeout.current = setTimeout(() => { + setIsScrolling(false); + }, 300); + }, 200), + [], + ); + + useEffect(() => { + document.onscroll = onScroll; + return () => { + document.onscroll = null; + }; + }, [onScroll]); + + const tabPaneStyle = useMemo( + () => ({ overflow: 'auto', height, overscrollBehavior: 'contain' }), + [height], + ); + + const numberOfFilters = nativeFilterValues.length; + + return ( + <FilterBarScrollContext.Provider value={isScrolling}> + <BarWrapper + {...getFilterBarTestId()} + className={cx({ open: filtersOpen })} + width={width} + > + <CollapsedBar + {...getFilterBarTestId('collapsable')} + className={cx({ open: !filtersOpen })} + onClick={openFiltersBar} + offset={offset} + > + <StyledCollapseIcon + {...getFilterBarTestId('expand-button')} + iconSize="l" + /> + <StyledFilterIcon + {...getFilterBarTestId('filter-icon')} + iconSize="l" + /> + </CollapsedBar> + <Bar className={cx({ open: filtersOpen })} width={width}> + <Header toggleFiltersBar={toggleFiltersBar} /> + {!isInitialized ? ( + <div css={{ height }}> + <Loading /> + </div> + ) : isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS_SET) ? ( + <StyledTabs + centered + onChange={setTab as HandlerFunction} + defaultActiveKey={TabIds.AllFilters} + activeKey={editFilterSetId ? TabIds.AllFilters : undefined} + > + <AntdTabs.TabPane + tab={t('All filters (%(filterCount)d)', { + filterCount: numberOfFilters, + })} + key={TabIds.AllFilters} + css={tabPaneStyle} + > + {editFilterSetId && ( + <EditSection + dataMaskSelected={dataMaskSelected} + disabled={!isDisabled} + onCancel={() => setEditFilterSetId(null)} + filterSetId={editFilterSetId} + /> + )} + {filterValues.length === 0 ? ( + <FilterBarEmptyStateContainer> + <EmptyStateSmall + title={t('No filters are currently added')} + image="filter.svg" + description={ + canEdit && + t( + 'Click the button above to add a filter to the dashboard', + ) + } + /> + </FilterBarEmptyStateContainer> + ) : ( + <FilterControlsWrapper> + <FilterControls + dataMaskSelected={dataMaskSelected} + focusedFilterId={focusedFilterId} + onFilterSelectionChange={onSelectionChange} + /> + </FilterControlsWrapper> + )} + </AntdTabs.TabPane> + <AntdTabs.TabPane + disabled={!!editFilterSetId} + tab={t('Filter sets (%(filterSetCount)d)', { + filterSetCount: filterSetFilterValues.length, + })} + key={TabIds.FilterSets} + css={tabPaneStyle} + > + <FilterSets + onEditFilterSet={setEditFilterSetId} + disabled={!isDisabled} + dataMaskSelected={dataMaskSelected} + tab={tab} + onFilterSelectionChange={onSelectionChange} + /> + </AntdTabs.TabPane> + </StyledTabs> + ) : ( + <div css={tabPaneStyle} onScroll={onScroll}> + {filterValues.length === 0 ? ( + <FilterBarEmptyStateContainer> + <EmptyStateSmall + title={t('No filters are currently added')} + image="filter.svg" + description={ + canEdit && + t( + 'Click the button above to add a filter to the dashboard', + ) + } + /> + </FilterBarEmptyStateContainer> + ) : ( + <FilterControlsWrapper> + <FilterControls + dataMaskSelected={dataMaskSelected} + focusedFilterId={focusedFilterId} + onFilterSelectionChange={onSelectionChange} + /> + </FilterControlsWrapper> + )} + </div> + )} + {actions} + </Bar> + </BarWrapper> + </FilterBarScrollContext.Provider> + ); +}; +export default React.memo(VerticalFilterBar); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx index 309d75dac9a80..6eeee2ae708f9 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx @@ -18,152 +18,38 @@ */ /* eslint-disable no-param-reassign */ -import throttle from 'lodash/throttle'; -import React, { - useEffect, - useState, - useCallback, - useMemo, - useRef, - createContext, -} from 'react'; +import React, { useEffect, useState, useCallback, createContext } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import cx from 'classnames'; import { DataMaskStateWithId, DataMaskWithId, Filter, DataMask, - HandlerFunction, - styled, - t, SLOW_DEBOUNCE, isNativeFilter, } from '@superset-ui/core'; -import Icons from 'src/components/Icons'; -import { AntdTabs } from 'src/components'; import { useHistory } from 'react-router-dom'; import { usePrevious } from 'src/hooks/usePrevious'; -import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import { updateDataMask, clearDataMask } from 'src/dataMask/actions'; import { useImmer } from 'use-immer'; import { isEmpty, isEqual, debounce } from 'lodash'; -import { testWithId } from 'src/utils/testUtils'; -import Loading from 'src/components/Loading'; import { getInitialDataMask } from 'src/dataMask/reducer'; import { URL_PARAMS } from 'src/constants'; import { getUrlParam } from 'src/utils/urlUtils'; -import { EmptyStateSmall } from 'src/components/EmptyState'; import { useTabId } from 'src/hooks/useTabId'; -import { RootState } from 'src/dashboard/types'; -import { checkIsApplyDisabled, TabIds } from './utils'; -import FilterSets from './FilterSets'; +import { FilterBarOrientation, RootState } from 'src/dashboard/types'; +import { checkIsApplyDisabled } from './utils'; +import { FiltersBarProps } from './types'; import { useNativeFiltersDataMask, useFilters, - useFilterSets, useFilterUpdates, useInitialization, } from './state'; import { createFilterKey, updateFilterKey } from './keyValue'; -import EditSection from './FilterSets/EditSection'; -import Header from './Header'; -import FilterControls from './FilterControls/FilterControls'; -import { ActionButtons } from './ActionButtons'; - -export const FILTER_BAR_TEST_ID = 'filter-bar'; -export const getFilterBarTestId = testWithId(FILTER_BAR_TEST_ID); - -const BarWrapper = styled.div<{ width: number }>` - width: ${({ theme }) => theme.gridUnit * 8}px; - - & .ant-tabs-top > .ant-tabs-nav { - margin: 0; - } - &.open { - width: ${({ width }) => width}px; // arbitrary... - } -`; - -const Bar = styled.div<{ width: number }>` - & .ant-typography-edit-content { - left: 0; - margin-top: 0; - width: 100%; - } - position: absolute; - top: 0; - left: 0; - flex-direction: column; - flex-grow: 1; - width: ${({ width }) => width}px; - background: ${({ theme }) => theme.colors.grayscale.light5}; - border-right: 1px solid ${({ theme }) => theme.colors.grayscale.light2}; - border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2}; - min-height: 100%; - display: none; - &.open { - display: flex; - } -`; - -const CollapsedBar = styled.div<{ offset: number }>` - position: absolute; - top: ${({ offset }) => offset}px; - left: 0; - height: 100%; - width: ${({ theme }) => theme.gridUnit * 8}px; - padding-top: ${({ theme }) => theme.gridUnit * 2}px; - display: none; - text-align: center; - &.open { - display: flex; - flex-direction: column; - align-items: center; - padding: ${({ theme }) => theme.gridUnit * 2}px; - } - svg { - cursor: pointer; - } -`; - -const StyledCollapseIcon = styled(Icons.Collapse)` - color: ${({ theme }) => theme.colors.primary.base}; - margin-bottom: ${({ theme }) => theme.gridUnit * 3}px; -`; - -const StyledFilterIcon = styled(Icons.Filter)` - color: ${({ theme }) => theme.colors.grayscale.base}; -`; - -const StyledTabs = styled(AntdTabs)` - & .ant-tabs-nav-list { - width: 100%; - } - & .ant-tabs-tab { - display: flex; - justify-content: center; - margin: 0; - flex: 1; - } - - & > .ant-tabs-nav .ant-tabs-nav-operations { - display: none; - } -`; - -const FilterBarEmptyStateContainer = styled.div` - margin-top: ${({ theme }) => theme.gridUnit * 8}px; -`; - -export interface FiltersBarProps { - filtersOpen: boolean; - toggleFiltersBar: any; - directPathToChild?: string[]; - width: number; - height: number | string; - offset: number; -} +import ActionButtons from './ActionButtons'; +import Horizontal from './Horizontal'; +import Vertical from './Vertical'; const EXCLUDED_URL_PARAMS: string[] = [ URL_PARAMS.nativeFilters.name, @@ -211,48 +97,43 @@ const publishDataMask = debounce( // pathname could be updated somewhere else through window.history // keep react router history in sync with window history - history.location.pathname = window.location.pathname; - history.replace({ - search: newParams.toString(), - }); + // replace params only when current page is /superset/dashboard + // this prevents a race condition between updating filters and navigating to Explore + if (window.location.pathname.includes('/superset/dashboard')) { + history.location.pathname = window.location.pathname; + history.replace({ + search: newParams.toString(), + }); + } }, SLOW_DEBOUNCE, ); export const FilterBarScrollContext = createContext(false); const FilterBar: React.FC<FiltersBarProps> = ({ - filtersOpen, - toggleFiltersBar, - directPathToChild, - width, - height, - offset, + focusedFilterId, + orientation = FilterBarOrientation.VERTICAL, + verticalConfig, }) => { const history = useHistory(); const dataMaskApplied: DataMaskStateWithId = useNativeFiltersDataMask(); - const [editFilterSetId, setEditFilterSetId] = useState<number | null>(null); const [dataMaskSelected, setDataMaskSelected] = useImmer<DataMaskStateWithId>(dataMaskApplied); const dispatch = useDispatch(); const [updateKey, setUpdateKey] = useState(0); const tabId = useTabId(); - const filterSets = useFilterSets(); - const filterSetFilterValues = Object.values(filterSets); - const [tab, setTab] = useState(TabIds.AllFilters); const filters = useFilters(); const previousFilters = usePrevious(filters); const filterValues = Object.values(filters); const nativeFilterValues = filterValues.filter(isNativeFilter); - const dashboardId = useSelector<any, string>( + const dashboardId = useSelector<any, number>( ({ dashboardInfo }) => dashboardInfo?.id, ); + const previousDashboardId = usePrevious(dashboardId); const canEdit = useSelector<RootState, boolean>( ({ dashboardInfo }) => dashboardInfo.dash_edit_perm, ); - const [isScrolling, setIsScrolling] = useState(false); - const timeout = useRef<any>(); - const handleFilterSelectionChange = useCallback( ( filter: Pick<Filter, 'id'> & Partial<Filter>, @@ -279,7 +160,7 @@ const FilterBar: React.FC<FiltersBarProps> = ({ ); useEffect(() => { - if (previousFilters) { + if (previousFilters && dashboardId === previousDashboardId) { const updates = {}; Object.values(filters).forEach(currentFilter => { const previousFilter = previousFilters?.[currentFilter.id]; @@ -306,7 +187,11 @@ const FilterBar: React.FC<FiltersBarProps> = ({ Object.keys(updates).forEach(key => dispatch(clearDataMask(key))); } } - }, [JSON.stringify(filters), JSON.stringify(previousFilters)]); + }, [ + JSON.stringify(filters), + JSON.stringify(previousFilters), + previousDashboardId, + ]); const dataMaskAppliedText = JSON.stringify(dataMaskApplied); @@ -343,29 +228,6 @@ const FilterBar: React.FC<FiltersBarProps> = ({ }); }, [dataMaskSelected, dispatch, setDataMaskSelected]); - const openFiltersBar = useCallback( - () => toggleFiltersBar(true), - [toggleFiltersBar], - ); - - const onScroll = useCallback( - throttle(() => { - clearTimeout(timeout.current); - setIsScrolling(true); - timeout.current = setTimeout(() => { - setIsScrolling(false); - }, 300); - }, 200), - [], - ); - - useEffect(() => { - document.onscroll = onScroll; - return () => { - document.onscroll = null; - }; - }, [onScroll]); - useFilterUpdates(dataMaskSelected, setDataMaskSelected); const isApplyDisabled = checkIsApplyDisabled( dataMaskSelected, @@ -373,135 +235,46 @@ const FilterBar: React.FC<FiltersBarProps> = ({ nativeFilterValues, ); const isInitialized = useInitialization(); - const tabPaneStyle = useMemo( - () => ({ overflow: 'auto', height, overscrollBehavior: 'contain' }), - [height], - ); - - const numberOfFilters = nativeFilterValues.length; - return ( - <FilterBarScrollContext.Provider value={isScrolling}> - <BarWrapper - {...getFilterBarTestId()} - className={cx({ open: filtersOpen })} - width={width} - > - <CollapsedBar - {...getFilterBarTestId('collapsable')} - className={cx({ open: !filtersOpen })} - onClick={openFiltersBar} - offset={offset} - > - <StyledCollapseIcon - {...getFilterBarTestId('expand-button')} - iconSize="l" - /> - <StyledFilterIcon - {...getFilterBarTestId('filter-icon')} - iconSize="l" - /> - </CollapsedBar> - <Bar className={cx({ open: filtersOpen })} width={width}> - <Header toggleFiltersBar={toggleFiltersBar} /> - {!isInitialized ? ( - <div css={{ height }}> - <Loading /> - </div> - ) : isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS_SET) ? ( - <StyledTabs - centered - onChange={setTab as HandlerFunction} - defaultActiveKey={TabIds.AllFilters} - activeKey={editFilterSetId ? TabIds.AllFilters : undefined} - > - <AntdTabs.TabPane - tab={t('All filters (%(filterCount)d)', { - filterCount: numberOfFilters, - })} - key={TabIds.AllFilters} - css={tabPaneStyle} - > - {editFilterSetId && ( - <EditSection - dataMaskSelected={dataMaskSelected} - disabled={!isApplyDisabled} - onCancel={() => setEditFilterSetId(null)} - filterSetId={editFilterSetId} - /> - )} - {filterValues.length === 0 ? ( - <FilterBarEmptyStateContainer> - <EmptyStateSmall - title={t('No filters are currently added')} - image="filter.svg" - description={ - canEdit && - t( - 'Click the button above to add a filter to the dashboard', - ) - } - /> - </FilterBarEmptyStateContainer> - ) : ( - <FilterControls - dataMaskSelected={dataMaskSelected} - directPathToChild={directPathToChild} - onFilterSelectionChange={handleFilterSelectionChange} - /> - )} - </AntdTabs.TabPane> - <AntdTabs.TabPane - disabled={!!editFilterSetId} - tab={t('Filter sets (%(filterSetCount)d)', { - filterSetCount: filterSetFilterValues.length, - })} - key={TabIds.FilterSets} - css={tabPaneStyle} - > - <FilterSets - onEditFilterSet={setEditFilterSetId} - disabled={!isApplyDisabled} - dataMaskSelected={dataMaskSelected} - tab={tab} - onFilterSelectionChange={handleFilterSelectionChange} - /> - </AntdTabs.TabPane> - </StyledTabs> - ) : ( - <div css={tabPaneStyle} onScroll={onScroll}> - {filterValues.length === 0 ? ( - <FilterBarEmptyStateContainer> - <EmptyStateSmall - title={t('No filters are currently added')} - image="filter.svg" - description={ - canEdit && - t( - 'Click the button above to add a filter to the dashboard', - ) - } - /> - </FilterBarEmptyStateContainer> - ) : ( - <FilterControls - dataMaskSelected={dataMaskSelected} - directPathToChild={directPathToChild} - onFilterSelectionChange={handleFilterSelectionChange} - /> - )} - </div> - )} - <ActionButtons - onApply={handleApply} - onClearAll={handleClearAll} - dataMaskSelected={dataMaskSelected} - dataMaskApplied={dataMaskApplied} - isApplyDisabled={isApplyDisabled} - /> - </Bar> - </BarWrapper> - </FilterBarScrollContext.Provider> + const actions = ( + <ActionButtons + filterBarOrientation={orientation} + width={verticalConfig?.width} + onApply={handleApply} + onClearAll={handleClearAll} + dataMaskSelected={dataMaskSelected} + dataMaskApplied={dataMaskApplied} + isApplyDisabled={isApplyDisabled} + /> ); + + return orientation === FilterBarOrientation.HORIZONTAL ? ( + <Horizontal + actions={actions} + canEdit={canEdit} + dashboardId={dashboardId} + dataMaskSelected={dataMaskSelected} + focusedFilterId={focusedFilterId} + filterValues={filterValues} + isInitialized={isInitialized} + onSelectionChange={handleFilterSelectionChange} + /> + ) : verticalConfig ? ( + <Vertical + actions={actions} + canEdit={canEdit} + dataMaskSelected={dataMaskSelected} + focusedFilterId={focusedFilterId} + filtersOpen={verticalConfig.filtersOpen} + filterValues={filterValues} + isInitialized={isInitialized} + isDisabled={isApplyDisabled} + height={verticalConfig.height} + offset={verticalConfig.offset} + onSelectionChange={handleFilterSelectionChange} + toggleFiltersBar={verticalConfig.toggleFiltersBar} + width={verticalConfig.width} + /> + ) : null; }; export default React.memo(FilterBar); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/state.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/state.ts index 4e1b2eda1271e..425029bb86872 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/state.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/state.ts @@ -111,7 +111,7 @@ export const useInitialization = () => { // do not load filter_box in reviewing if (filterboxMigrationState === FILTER_BOX_MIGRATION_STATES.REVIEWING) { charts = keyBy( - filter(charts, chart => chart.formData?.viz_type !== 'filter_box'), + filter(charts, chart => chart.form_data?.viz_type !== 'filter_box'), 'id', ); const numberOfFilterbox = document.querySelectorAll( diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/types.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/types.ts new file mode 100644 index 0000000000000..034a639f589e0 --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/types.ts @@ -0,0 +1,67 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + DataMask, + DataMaskStateWithId, + Divider, + Filter, +} from '@superset-ui/core'; +import { FilterBarOrientation } from 'src/dashboard/types'; + +interface CommonFiltersBarProps { + actions: React.ReactNode; + canEdit: boolean; + dataMaskSelected: DataMaskStateWithId; + focusedFilterId?: string; + filterValues: (Filter | Divider)[]; + isInitialized: boolean; + onSelectionChange: ( + filter: Pick<Filter, 'id'> & Partial<Filter>, + dataMask: Partial<DataMask>, + ) => void; +} + +interface VerticalBarConfig { + filtersOpen: boolean; + height: number | string; + offset: number; + toggleFiltersBar: any; + width: number; +} + +export interface FiltersBarProps + extends Pick<CommonFiltersBarProps, 'focusedFilterId'> { + orientation: FilterBarOrientation; + verticalConfig?: VerticalBarConfig; +} + +export type HorizontalBarProps = CommonFiltersBarProps & { + dashboardId: number; +}; + +export type VerticalBarProps = Omit<FiltersBarProps, 'orientation'> & + CommonFiltersBarProps & + VerticalBarConfig & { + isDisabled: boolean; + }; + +export enum TabIds { + AllFilters = 'allFilters', + FilterSets = 'filterSets', +} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/useFilterControlFactory.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/useFilterControlFactory.tsx new file mode 100644 index 0000000000000..29e539630d15e --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/useFilterControlFactory.tsx @@ -0,0 +1,87 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useCallback, useMemo } from 'react'; +import { + DataMask, + DataMaskStateWithId, + Divider, + Filter, + isFilterDivider, +} from '@superset-ui/core'; +import { FilterBarOrientation } from 'src/dashboard/types'; +import FilterControl from './FilterControls/FilterControl'; +import { useFilters } from './state'; +import FilterDivider from './FilterControls/FilterDivider'; + +export const useFilterControlFactory = ( + dataMaskSelected: DataMaskStateWithId, + focusedFilterId: string | undefined, + onFilterSelectionChange: (filter: Filter, dataMask: DataMask) => void, +) => { + const filters = useFilters(); + const filterValues = useMemo(() => Object.values(filters), [filters]); + const filtersWithValues: (Filter | Divider)[] = useMemo( + () => + filterValues.map(filter => ({ + ...filter, + dataMask: dataMaskSelected[filter.id], + })), + [filterValues, dataMaskSelected], + ); + + const filterControlFactory = useCallback( + ( + index: number, + filterBarOrientation: FilterBarOrientation, + overflow: boolean, + ) => { + const filter = filtersWithValues[index]; + if (isFilterDivider(filter)) { + return ( + <FilterDivider + title={filter.title} + description={filter.description} + orientation={filterBarOrientation} + overflow={overflow} + /> + ); + } + return ( + <FilterControl + dataMaskSelected={dataMaskSelected} + filter={filter} + focusedFilterId={focusedFilterId} + onFilterSelectionChange={onFilterSelectionChange} + inView={false} + orientation={filterBarOrientation} + overflow={overflow} + /> + ); + }, + [ + filtersWithValues, + dataMaskSelected, + focusedFilterId, + onFilterSelectionChange, + ], + ); + + return { filterControlFactory, filtersWithValues }; +}; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/utils.ts index 842bb440542c3..9aaa02fc54eac 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/utils.ts @@ -19,11 +19,7 @@ import { areObjectsEqual } from 'src/reduxUtils'; import { DataMaskStateWithId, Filter, FilterState } from '@superset-ui/core'; - -export enum TabIds { - AllFilters = 'allFilters', - FilterSets = 'filterSets', -} +import { testWithId } from 'src/utils/testUtils'; export const getOnlyExtraFormData = (data: DataMaskStateWithId) => Object.values(data).reduce( @@ -65,3 +61,6 @@ export const checkIsApplyDisabled = ( ) ); }; + +export const FILTER_BAR_TEST_ID = 'filter-bar'; +export const getFilterBarTestId = testWithId(FILTER_BAR_TEST_ID); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/DependenciesRow.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/DependenciesRow.tsx index 18a1c257b4ba3..6a846c012f6d8 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/DependenciesRow.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/DependenciesRow.tsx @@ -19,8 +19,9 @@ import React, { useCallback, useMemo, useRef } from 'react'; import { useDispatch } from 'react-redux'; import { css, t, useTheme } from '@superset-ui/core'; -import { setDirectPathToChild } from 'src/dashboard/actions/dashboardState'; import Icons from 'src/components/Icons'; +import { useTruncation } from 'src/hooks/useTruncation'; +import { setFocusedNativeFilter } from 'src/dashboard/actions/nativeFilters'; import { DependencyItem, Row, @@ -30,7 +31,6 @@ import { TooltipList, } from './Styles'; import { useFilterDependencies } from './useFilterDependencies'; -import { useTruncation } from './useTruncation'; import { DependencyValueProps, FilterCardRowProps } from './types'; import { TooltipWithTruncation } from './TooltipWithTruncation'; @@ -40,7 +40,7 @@ const DependencyValue = ({ }: DependencyValueProps) => { const dispatch = useDispatch(); const handleClick = useCallback(() => { - dispatch(setDirectPathToChild([dependency.id])); + dispatch(setFocusedNativeFilter(dependency.id)); }, [dependency.id, dispatch]); return ( <span> @@ -55,7 +55,11 @@ const DependencyValue = ({ export const DependenciesRow = React.memo(({ filter }: FilterCardRowProps) => { const dependencies = useFilterDependencies(filter); const dependenciesRef = useRef<HTMLDivElement>(null); - const [elementsTruncated, hasHiddenElements] = useTruncation(dependenciesRef); + const plusRef = useRef<HTMLDivElement>(null); + const [elementsTruncated, hasHiddenElements] = useTruncation( + dependenciesRef, + plusRef, + ); const theme = useTheme(); const tooltipText = useMemo( @@ -102,13 +106,16 @@ export const DependenciesRow = React.memo(({ filter }: FilterCardRowProps) => { <RowValue ref={dependenciesRef}> {dependencies.map((dependency, index) => ( <DependencyValue + key={dependency.id} dependency={dependency} hasSeparator={index !== 0} /> ))} </RowValue> {hasHiddenElements && ( - <RowTruncationCount>+{elementsTruncated}</RowTruncationCount> + <RowTruncationCount ref={plusRef}> + +{elementsTruncated} + </RowTruncationCount> )} </TooltipWithTruncation> </Row> diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/FilterCard.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/FilterCard.test.tsx index 93f1ccfca438d..560fa1faf0080 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/FilterCard.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/FilterCard.test.tsx @@ -23,10 +23,11 @@ import { Filter, NativeFilterType } from '@superset-ui/core'; import userEvent from '@testing-library/user-event'; import { render, screen } from 'spec/helpers/testing-library'; import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants'; -import { SET_DIRECT_PATH } from 'src/dashboard/actions/dashboardState'; +import { SET_FOCUSED_NATIVE_FILTER } from 'src/dashboard/actions/nativeFilters'; import { FilterCardContent } from './FilterCardContent'; const baseInitialState = { + dashboardInfo: {}, nativeFilters: { filters: { 'NATIVE_FILTER-1': { @@ -204,6 +205,13 @@ jest.mock('@superset-ui/core', () => ({ }), })); +jest.mock( + 'src/components/Icons/Icon', + () => + ({ fileName }: { fileName: string }) => + <span role="img" aria-label={fileName.replace('_', '-')} />, +); + // extract text from embedded html tags // source: https://polvara.me/posts/five-things-you-didnt-know-about-testing-library const getTextInHTMLTags = @@ -217,90 +225,115 @@ const getTextInHTMLTags = return nodeHasText && childrenDontHaveText; }; +const hidePopover = jest.fn(); + const renderContent = (filter = baseFilter, initialState = baseInitialState) => - render(<FilterCardContent filter={filter} />, { + render(<FilterCardContent filter={filter} hidePopover={hidePopover} />, { useRedux: true, initialState, }); -describe('Filter Card', () => { - it('Basic', () => { - renderContent(); - expect(screen.getByText('Native filter 1')).toBeVisible(); - expect(screen.getByLabelText('filter-small')).toBeVisible(); +test('filter card title, type, scope, dependencies', () => { + renderContent(); + expect(screen.getByText('Native filter 1')).toBeVisible(); + expect(screen.getByLabelText('filter-small')).toBeVisible(); - expect(screen.getByText('Filter type')).toBeVisible(); - expect(screen.getByText('Select filter')).toBeVisible(); + expect(screen.getByText('Filter type')).toBeVisible(); + expect(screen.getByText('Select filter')).toBeVisible(); - expect(screen.getByText('Scope')).toBeVisible(); - expect(screen.getByText('All charts')).toBeVisible(); + expect(screen.getByText('Scope')).toBeVisible(); + expect(screen.getByText('All charts')).toBeVisible(); - expect(screen.queryByText('Dependencies')).not.toBeInTheDocument(); - }); + expect(screen.queryByText('Dependencies')).not.toBeInTheDocument(); +}); + +test('filter card scope with excluded', () => { + const filter = { + ...baseFilter, + scope: { rootPath: [DASHBOARD_ROOT_ID], excluded: [1, 4] }, + }; + renderContent(filter); + expect(screen.getByText('Scope')).toBeVisible(); + expect( + screen.getByText(getTextInHTMLTags('Test chart 2, Test chart 3')), + ).toBeVisible(); +}); + +test('filter card scope with top level tab as root', () => { + const filter = { + ...baseFilter, + scope: { rootPath: ['TAB-1', 'TAB-2'], excluded: [1, 2] }, + }; + renderContent(filter); + expect(screen.getByText('Scope')).toBeVisible(); + expect( + screen.getByText(getTextInHTMLTags('Tab 2, Test chart 3')), + ).toBeVisible(); +}); + +test('filter card empty scope', () => { + const filter = { + ...baseFilter, + scope: { rootPath: [], excluded: [1, 2, 3, 4] }, + }; + renderContent(filter); + expect(screen.getByText('Scope')).toBeVisible(); + expect(screen.getByText('None')).toBeVisible(); +}); + +test('filter card with dependency', () => { + const filter = { + ...baseFilter, + cascadeParentIds: ['NATIVE_FILTER-2'], + }; + renderContent(filter); + expect(screen.getByText('Dependent on')).toBeVisible(); + expect(screen.getByText('Native filter 2')).toBeVisible(); +}); - describe('Scope', () => { - it('Scope with excluded', () => { - const filter = { - ...baseFilter, - scope: { rootPath: [DASHBOARD_ROOT_ID], excluded: [1, 4] }, - }; - renderContent(filter); - expect(screen.getByText('Scope')).toBeVisible(); - expect( - screen.getByText(getTextInHTMLTags('Test chart 2, Test chart 3')), - ).toBeVisible(); - }); +test('focus filter on filter card dependency click', () => { + const useDispatchMock = jest.spyOn(reactRedux, 'useDispatch'); + const dummyDispatch = jest.fn(); + useDispatchMock.mockReturnValue(dummyDispatch); - it('Scope with top level tab as root', () => { - const filter = { - ...baseFilter, - scope: { rootPath: ['TAB-1', 'TAB-2'], excluded: [1, 2] }, - }; - renderContent(filter); - expect(screen.getByText('Scope')).toBeVisible(); - expect( - screen.getByText(getTextInHTMLTags('Tab 2, Test chart 3')), - ).toBeVisible(); - }); + const filter = { + ...baseFilter, + cascadeParentIds: ['NATIVE_FILTER-2'], + }; + renderContent(filter); - it('Empty scope', () => { - const filter = { - ...baseFilter, - scope: { rootPath: [], excluded: [1, 2, 3, 4] }, - }; - renderContent(filter); - expect(screen.getByText('Scope')).toBeVisible(); - expect(screen.getByText('None')).toBeVisible(); - }); + userEvent.click(screen.getByText('Native filter 2')); + expect(dummyDispatch).toHaveBeenCalledWith({ + type: SET_FOCUSED_NATIVE_FILTER, + id: 'NATIVE_FILTER-2', }); +}); - describe('Dependencies', () => { - it('Has dependency', () => { - const filter = { - ...baseFilter, - cascadeParentIds: ['NATIVE_FILTER-2'], - }; - renderContent(filter); - expect(screen.getByText('Dependent on')).toBeVisible(); - expect(screen.getByText('Native filter 2')).toBeVisible(); - }); +test('edit filter button for dashboard viewer', () => { + renderContent(); + expect( + screen.queryByRole('button', { name: /edit/i }), + ).not.toBeInTheDocument(); +}); - it('Focus filter on dependency click', () => { - const useDispatchMock = jest.spyOn(reactRedux, 'useDispatch'); - const dummyDispatch = jest.fn(); - useDispatchMock.mockReturnValue(dummyDispatch); +test('edit filter button for dashboard editor', () => { + renderContent(baseFilter, { + ...baseInitialState, + dashboardInfo: { dash_edit_perm: true }, + }); - const filter = { - ...baseFilter, - cascadeParentIds: ['NATIVE_FILTER-2'], - }; - renderContent(filter); + expect(screen.getByRole('button', { name: /edit/i })).toBeVisible(); +}); - userEvent.click(screen.getByText('Native filter 2')); - expect(dummyDispatch).toHaveBeenCalledWith({ - type: SET_DIRECT_PATH, - path: ['NATIVE_FILTER-2'], - }); - }); +test('open modal on edit filter button click', async () => { + renderContent(baseFilter, { + ...baseInitialState, + dashboardInfo: { dash_edit_perm: true }, }); + + const editButton = screen.getByRole('button', { name: /edit/i }); + userEvent.click(editButton); + expect( + await screen.findByRole('dialog', { name: /add and edit filters/i }), + ).toBeVisible(); }); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/FilterCardContent.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/FilterCardContent.tsx index 41696ed98f881..02b0d875a9dc9 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/FilterCardContent.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/FilterCardContent.tsx @@ -24,9 +24,17 @@ import { DependenciesRow } from './DependenciesRow'; import { NameRow } from './NameRow'; import { TypeRow } from './TypeRow'; -export const FilterCardContent = ({ filter }: { filter: Filter }) => ( +interface FilterCardContentProps { + filter: Filter; + hidePopover: () => void; +} + +export const FilterCardContent = ({ + filter, + hidePopover, +}: FilterCardContentProps) => ( <div> - <NameRow filter={filter} /> + <NameRow filter={filter} hidePopover={hidePopover} /> <TypeRow filter={filter} /> <ScopeRow filter={filter} /> <DependenciesRow filter={filter} /> diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/NameRow.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/NameRow.tsx index 05cb8119487cd..6c7e82b15ddb4 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/NameRow.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/NameRow.tsx @@ -17,34 +17,61 @@ * under the License. */ import React, { useRef } from 'react'; -import { css, SupersetTheme } from '@superset-ui/core'; +import { useSelector } from 'react-redux'; +import { css, SupersetTheme, useTheme } from '@superset-ui/core'; import Icons from 'src/components/Icons'; -import { Row, FilterName } from './Styles'; +import { useTruncation } from 'src/hooks/useTruncation'; +import { RootState } from 'src/dashboard/types'; +import { Row, FilterName, InternalRow } from './Styles'; import { FilterCardRowProps } from './types'; -import { useTruncation } from './useTruncation'; +import { FilterConfigurationLink } from '../FilterBar/FilterConfigurationLink'; import { TooltipWithTruncation } from './TooltipWithTruncation'; -export const NameRow = ({ filter }: FilterCardRowProps) => { +export const NameRow = ({ + filter, + hidePopover, +}: FilterCardRowProps & { hidePopover: () => void }) => { + const theme = useTheme(); const filterNameRef = useRef<HTMLElement>(null); const [elementsTruncated] = useTruncation(filterNameRef); + const dashboardId = useSelector<RootState, number>( + ({ dashboardInfo }) => dashboardInfo.id, + ); + + const canEdit = useSelector<RootState, boolean>( + ({ dashboardInfo }) => dashboardInfo.dash_edit_perm, + ); + return ( <Row css={(theme: SupersetTheme) => css` margin-bottom: ${theme.gridUnit * 3}px; + justify-content: space-between; ` } > - <Icons.FilterSmall - css={(theme: SupersetTheme) => - css` - margin-right: ${theme.gridUnit}px; - ` - } - /> - <TooltipWithTruncation title={elementsTruncated ? filter.name : null}> - <FilterName ref={filterNameRef}>{filter.name}</FilterName> - </TooltipWithTruncation> + <InternalRow> + <Icons.FilterSmall + css={(theme: SupersetTheme) => + css` + margin-right: ${theme.gridUnit}px; + ` + } + /> + <TooltipWithTruncation title={elementsTruncated ? filter.name : null}> + <FilterName ref={filterNameRef}>{filter.name}</FilterName> + </TooltipWithTruncation> + </InternalRow> + {canEdit && ( + <FilterConfigurationLink + dashboardId={dashboardId} + onClick={hidePopover} + initialFilterId={filter.id} + > + <Icons.Edit iconSize="l" iconColor={theme.colors.grayscale.light1} /> + </FilterConfigurationLink> + )} </Row> ); }; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx index 66656f0ba514d..0c0704089119f 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx @@ -18,6 +18,7 @@ */ import React, { useMemo, useRef } from 'react'; import { t } from '@superset-ui/core'; +import { useTruncation } from 'src/hooks/useTruncation'; import { useFilterScope } from './useFilterScope'; import { Row, @@ -27,7 +28,6 @@ import { TooltipList, TooltipSectionLabel, } from './Styles'; -import { useTruncation } from './useTruncation'; import { FilterCardRowProps } from './types'; import { TooltipWithTruncation } from './TooltipWithTruncation'; @@ -46,8 +46,12 @@ const getTooltipSection = (items: string[] | undefined, label: string) => export const ScopeRow = React.memo(({ filter }: FilterCardRowProps) => { const scope = useFilterScope(filter); const scopeRef = useRef<HTMLDivElement>(null); + const plusRef = useRef<HTMLDivElement>(null); - const [elementsTruncated, hasHiddenElements] = useTruncation(scopeRef); + const [elementsTruncated, hasHiddenElements] = useTruncation( + scopeRef, + plusRef, + ); const tooltipText = useMemo(() => { if (elementsTruncated === 0 || !scope) { return null; @@ -72,12 +76,16 @@ export const ScopeRow = React.memo(({ filter }: FilterCardRowProps) => { ? Object.values(scope) .flat() .map((element, index) => ( - <span>{index === 0 ? element : `, ${element}`}</span> + <span key={element}> + {index === 0 ? element : `, ${element}`} + </span> )) : t('None')} </RowValue> {hasHiddenElements > 0 && ( - <RowTruncationCount>+{elementsTruncated}</RowTruncationCount> + <RowTruncationCount ref={plusRef}> + +{elementsTruncated} + </RowTruncationCount> )} </TooltipWithTruncation> </Row> diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/Styles.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/Styles.ts index bda865063d751..8090201f1c3c5 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/Styles.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/Styles.ts @@ -92,3 +92,8 @@ export const TooltipTrigger = styled.div` display: inline-flex; white-space: nowrap; `; + +export const InternalRow = styled.div` + display: flex; + align-items: center; +`; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/index.tsx index bc1f7b2ea3712..bdbfcff8aebf3 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/index.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/index.tsx @@ -27,9 +27,14 @@ export const FilterCard = ({ filter, getPopupContainer, isVisible: externalIsVisible = true, + placement, }: FilterCardProps) => { const [internalIsVisible, setInternalIsVisible] = useState(false); + const hidePopover = () => { + setInternalIsVisible(false); + }; + useEffect(() => { if (!externalIsVisible) { setInternalIsVisible(false); @@ -37,7 +42,7 @@ export const FilterCard = ({ }, [externalIsVisible]); return ( <Popover - placement="right" + placement={placement} overlayClassName="filter-card-popover" mouseEnterDelay={0.2} mouseLeaveDelay={0.2} @@ -45,9 +50,8 @@ export const FilterCard = ({ setInternalIsVisible(externalIsVisible && visible); }} visible={externalIsVisible && internalIsVisible} - content={<FilterCardContent filter={filter} />} + content={<FilterCardContent filter={filter} hidePopover={hidePopover} />} getPopupContainer={getPopupContainer ?? (() => document.body)} - destroyTooltipOnHide > {children} </Popover> diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/types.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/types.ts index 6e65a4eecc634..10af257b26618 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/types.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/types.ts @@ -19,11 +19,18 @@ import { ReactNode } from 'react'; import { Filter } from '@superset-ui/core'; +export enum FilterCardPlacement { + Right = 'right', + Bottom = 'bottom', + Left = 'left', +} + export interface FilterCardProps { children: ReactNode; filter: Filter; getPopupContainer?: (node: HTMLElement) => HTMLElement; isVisible?: boolean; + placement: FilterCardPlacement; } export interface FilterCardRowProps { diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useFilterScope.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useFilterScope.ts index 12a578c35a140..35c84a8591d14 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useFilterScope.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useFilterScope.ts @@ -62,10 +62,9 @@ export const useFilterScope = (filter: Filter) => { if ( filter.scope.excluded.length === 0 && (filter.scope.rootPath[0] === DASHBOARD_ROOT_ID || - (topLevelTabs && - topLevelTabs.every(topLevelTab => - filter.scope.rootPath.includes(topLevelTab), - ))) + topLevelTabs?.every(topLevelTab => + filter.scope.rootPath.includes(topLevelTab), + )) ) { return { all: [t('All charts')] }; } diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterConfigPane.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterConfigPane.test.tsx index 3742d536326fb..223d5a35d00d1 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterConfigPane.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterConfigPane.test.tsx @@ -26,7 +26,6 @@ const scrollMock = jest.fn(); Element.prototype.scroll = scrollMock; const defaultProps = { - children: jest.fn(), getFilterTitle: (id: string) => id, onChange: jest.fn(), onAdd: jest.fn(), @@ -63,13 +62,6 @@ beforeEach(() => { scrollMock.mockClear(); }); -test('renders form', async () => { - await act(async () => { - defaultRender(); - }); - expect(defaultProps.children).toHaveBeenCalledTimes(3); -}); - test('drag and drop', async () => { defaultRender(); // Drag the state and country filter above the product filter diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterConfigurePane.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterConfigurePane.tsx index dba7e6bb30250..b582b240977d4 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterConfigurePane.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterConfigurePane.tsx @@ -22,7 +22,7 @@ import FilterTitlePane from './FilterTitlePane'; import { FilterRemoval } from './types'; interface Props { - children: (filterId: string) => React.ReactNode; + children?: React.ReactNode; getFilterTitle: (filterId: string) => string; onChange: (activeKey: string) => void; onAdd: (type: NativeFilterType) => void; @@ -46,7 +46,7 @@ const ContentHolder = styled.div` `; const TitlesContainer = styled.div` - width: 270px; + min-width: 270px; border-right: 1px solid ${({ theme }) => theme.colors.grayscale.light2}; `; @@ -62,40 +62,24 @@ const FilterConfigurePane: React.FC<Props> = ({ currentFilterId, filters, removedFilters, -}) => { - const active = filters.filter(id => id === currentFilterId)[0]; - return ( - <Container> - <TitlesContainer> - <FilterTitlePane - currentFilterId={currentFilterId} - filters={filters} - removedFilters={removedFilters} - erroredFilters={erroredFilters} - getFilterTitle={getFilterTitle} - onChange={onChange} - onAdd={(type: NativeFilterType) => onAdd(type)} - onRearrange={onRearrange} - onRemove={(id: string) => onRemove(id)} - restoreFilter={restoreFilter} - /> - </TitlesContainer> - <ContentHolder> - {filters.map(id => ( - <div - key={id} - style={{ - height: '100%', - overflowY: 'auto', - display: id === active ? '' : 'none', - }} - > - {children(id)} - </div> - ))} - </ContentHolder> - </Container> - ); -}; +}) => ( + <Container> + <TitlesContainer> + <FilterTitlePane + currentFilterId={currentFilterId} + filters={filters} + removedFilters={removedFilters} + erroredFilters={erroredFilters} + getFilterTitle={getFilterTitle} + onChange={onChange} + onAdd={(type: NativeFilterType) => onAdd(type)} + onRearrange={onRearrange} + onRemove={(id: string) => onRemove(id)} + restoreFilter={restoreFilter} + /> + </TitlesContainer> + <ContentHolder>{children}</ContentHolder> + </Container> +); export default FilterConfigurePane; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitlePane.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitlePane.tsx index 79dc4148349aa..a080d35645131 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitlePane.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitlePane.tsx @@ -53,8 +53,8 @@ const TabsContainer = styled.div` `; const options = [ - { label: 'Filter', type: NativeFilterType.NATIVE_FILTER }, - { label: 'Divider', type: NativeFilterType.DIVIDER }, + { label: t('Filter'), type: NativeFilterType.NATIVE_FILTER }, + { label: t('Divider'), type: NativeFilterType.DIVIDER }, ]; const FilterTitlePane: React.FC<Props> = ({ diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx index 8ecb75777f3b6..fa0b4fbea09b2 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx @@ -19,7 +19,7 @@ import React, { useCallback, useMemo } from 'react'; import rison from 'rison'; import { t, SupersetClient } from '@superset-ui/core'; -import { Select } from 'src/components'; +import { AsyncSelect } from 'src/components'; import { cacheWrapper } from 'src/utils/cacheWrapper'; import { ClientErrorObject, @@ -85,11 +85,12 @@ const DatasetSelect = ({ onChange, value }: DatasetSelectProps) => { }; return ( - <Select + <AsyncSelect ariaLabel={t('Dataset')} value={value} options={loadDatasetOptions} onChange={onChange} + notFoundContent={t('No compatible datasets found')} /> ); }; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx index 07f785484d52d..e4ae521764fc9 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx @@ -51,7 +51,7 @@ const DefaultValue: FC<DefaultValueProps> = ({ const formFilter = (form.getFieldValue('filters') || {})[filterId]; const queriesData = formFilter?.defaultValueQueriesData; const loading = hasDataset && queriesData === null; - const value = formFilter.defaultDataMask?.filterState?.value; + const value = formFilter?.defaultDataMask?.filterState?.value; const isMissingRequiredValue = hasDefaultValue && (value === null || value === undefined); return loading ? ( @@ -71,7 +71,7 @@ const DefaultValue: FC<DefaultValueProps> = ({ hooks={{ setDataMask }} enableNoResults={enableNoResults} filterState={{ - ...formFilter.defaultDataMask?.filterState, + ...formFilter?.defaultDataMask?.filterState, validateMessage: isMissingRequiredValue && t('Value is required'), validateStatus: isMissingRequiredValue && 'error', }} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.test.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.test.ts new file mode 100644 index 0000000000000..9172b1dba58bf --- /dev/null +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.test.ts @@ -0,0 +1,18204 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { Layout } from 'src/dashboard/types'; +import { buildTree } from './utils'; + +// The types defined for Layout and sub elements is not compatible with the data we get back fro a real dashboard layout +// This test file is using data from a real example dashboard to test real world data sets. ts-ignore is set for this entire file +// until we can reconcile adjusting types to match the actual data structures used + +describe('Ensure buildTree does not throw runtime errors when encountering an invalid node', () => { + const node = { + children: ['TABS-97PVJa11D_'], + id: 'ROOT_ID', + type: 'ROOT', + parents: [], + }; + + const treeItem = { + children: [], + key: 'ROOT_ID', + type: 'ROOT', + title: 'All panels', + }; + + const layout: Layout = { + 'CHART-1L7NIcXvVN': { + children: [], + id: 'CHART-1L7NIcXvVN', + meta: { + chartId: 95, + height: 79, + sliceName: 'Games per Genre over time', + uuid: '0f8976aa-7bb4-40c7-860b-64445a51aaaf', + width: 6, + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-2_QXp8aNq', 'ROW-fjg6YQBkH'], + type: 'CHART', + }, + 'CHART-7mKdnU7OUJ': { + children: [], + id: 'CHART-7mKdnU7OUJ', + meta: { + chartId: 131, + height: 80, + sliceName: 'Games per Genre', + uuid: '0499bdec-0837-44f3-ae8a-8c670de81afd', + width: 3, + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-2_QXp8aNq', 'ROW-yP9SB89PZ'], + type: 'CHART', + }, + 'CHART-8OG3UJX-Tn': { + children: [], + id: 'CHART-8OG3UJX-Tn', + meta: { + chartId: 125, + height: 54, + sliceName: '# of Games That Hit 100k in Sales By Release Year', + sliceNameOverride: 'Top 10 Consoles, by # of Hit Games', + uuid: '2b69887b-23e3-b46d-d38c-8ea11856c555', + width: 6, + }, + parents: [ + 'ROOT_ID', + 'TABS-97PVJa11D_', + 'TAB-lg-5ymUDgm', + 'ROW-7kAf1blYU', + ], + type: 'CHART', + }, + 'CHART-W02beJK7ms': { + children: [], + id: 'CHART-W02beJK7ms', + meta: { + chartId: 78, + height: 54, + sliceName: 'Publishers With Most Titles', + sliceNameOverride: 'Top 10 Games (by Global Sales)', + uuid: 'd20b7324-3b80-24d4-37e2-3bd583b66713', + width: 3, + }, + parents: [ + 'ROOT_ID', + 'TABS-97PVJa11D_', + 'TAB-lg-5ymUDgm', + 'ROW-7kAf1blYU', + ], + type: 'CHART', + }, + 'CHART-XFag0yZdLk': { + children: [], + id: 'CHART-XFag0yZdLk', + meta: { + chartId: 123, + height: 54, + sliceName: 'Most Dominant Platforms', + sliceNameOverride: 'Publishers of Top 25 Games', + uuid: '1810975a-f6d4-07c3-495c-c3b535d01f21', + width: 3, + }, + parents: [ + 'ROOT_ID', + 'TABS-97PVJa11D_', + 'TAB-lg-5ymUDgm', + 'ROW-7kAf1blYU', + ], + type: 'CHART', + }, + 'CHART-XRvRfsMsaQ': { + children: [], + id: 'CHART-XRvRfsMsaQ', + meta: { + chartId: 113, + height: 62, + sliceName: 'Top 10 Games: Proportion of Sales in Markets', + uuid: 'a40879d5-653a-42fe-9314-bbe88ad26e92', + width: 6, + }, + parents: [ + 'ROOT_ID', + 'TABS-97PVJa11D_', + 'TAB-lg-5ymUDgm', + 'ROW-NuR8GFQTO', + ], + type: 'CHART', + }, + 'CHART-XVIYTeubZh': { + children: [], + id: 'CHART-XVIYTeubZh', + meta: { + chartId: 132, + height: 80, + sliceName: 'Games', + uuid: '2a5e562b-ab37-1b9b-1de3-1be4335c8e83', + width: 5, + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-2_QXp8aNq', 'ROW-yP9SB89PZ'], + type: 'CHART', + }, + 'CHART-_sx22yawJO': { + children: [], + id: 'CHART-_sx22yawJO', + meta: { + chartId: 93, + height: 62, + sliceName: 'Popular Genres Across Platforms', + uuid: '326fc7e5-b7f1-448e-8a6f-80d0e7ce0b64', + width: 6, + }, + parents: [ + 'ROOT_ID', + 'TABS-97PVJa11D_', + 'TAB-lg-5ymUDgm', + 'ROW-NuR8GFQTO', + ], + type: 'CHART', + }, + 'CHART-nYns6xr4Ft': { + children: [], + id: 'CHART-nYns6xr4Ft', + meta: { + chartId: 120, + height: 79, + sliceName: 'Total Sales per Market (Grouped by Genre)', + uuid: 'd8bf948e-46fd-4380-9f9c-a950c34bcc92', + width: 6, + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-2_QXp8aNq', 'ROW-fjg6YQBkH'], + type: 'CHART', + }, + 'CHART-uP9GF0z0rT': { + children: [], + id: 'CHART-uP9GF0z0rT', + meta: { + chartId: 127, + height: 45, + sliceName: 'Video Game Sales filter', + uuid: 'fd9ce7ec-ae08-4f71-93e0-7c26b132b2e6', + width: 4, + }, + parents: [ + 'ROOT_ID', + 'TABS-97PVJa11D_', + 'TAB-2_QXp8aNq', + 'ROW-yP9SB89PZ', + 'COLUMN-F53B1OSMcz', + ], + type: 'CHART', + }, + 'CHART-wt6ZO8jRXZ': { + children: [], + id: 'CHART-wt6ZO8jRXZ', + meta: { + chartId: 103, + height: 72, + sliceName: 'Rise & Fall of Video Game Consoles', + sliceNameOverride: 'Global Sales per Console', + uuid: '83b0e2d0-d38b-d980-ed8e-e1c9846361b6', + width: 12, + }, + parents: [ + 'ROOT_ID', + 'TABS-97PVJa11D_', + 'TAB-lg-5ymUDgm', + 'ROW-XT1DsNA_V', + ], + type: 'CHART', + }, + 'COLUMN-F53B1OSMcz': { + children: ['MARKDOWN-7K5cBNy7qu', 'CHART-uP9GF0z0rT'], + id: 'COLUMN-F53B1OSMcz', + meta: { + // @ts-expect-error + background: 'BACKGROUND_TRANSPARENT', + width: 4, + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-2_QXp8aNq', 'ROW-yP9SB89PZ'], + type: 'COLUMN', + }, + // @ts-expect-error + DASHBOARD_VERSION_KEY: 'v2', + // @ts-expect-error + GRID_ID: { + children: [], + id: 'GRID_ID', + parents: ['ROOT_ID'], + type: 'GRID', + }, + HEADER_ID: { + id: 'HEADER_ID', + type: 'HEADER', + // @ts-expect-error + meta: { + text: 'Video Game Sales', + }, + }, + 'MARKDOWN-7K5cBNy7qu': { + children: [], + id: 'MARKDOWN-7K5cBNy7qu', + meta: { + // @ts-expect-error + code: '# 🤿 Explore Trends\n\nDive into data on popular video games using the following dimensions:\n\n- Year\n- Platform\n- Publisher\n- Genre\n\nTo use the **Filter Games** box below, select values for each dimension you want to zoom in on and then click **Apply**. \n\nThe filter criteria you set in this Filter-box will apply to *all* charts in this tab.', + height: 33, + width: 4, + }, + parents: [ + 'ROOT_ID', + 'TABS-97PVJa11D_', + 'TAB-2_QXp8aNq', + 'ROW-yP9SB89PZ', + 'COLUMN-F53B1OSMcz', + ], + type: 'MARKDOWN', + }, + 'MARKDOWN-JOZKOjVc3a': { + children: [], + id: 'MARKDOWN-JOZKOjVc3a', + meta: { + // @ts-expect-error + code: '## 🎮Video Game Sales\n\nThis dashboard visualizes sales & platform data on video games that sold more than 100k copies. The data was last updated in early 2017.\n\n[Original dataset](https://www.kaggle.com/gregorut/videogamesales)', + height: 18, + width: 12, + }, + parents: [ + 'ROOT_ID', + 'TABS-97PVJa11D_', + 'TAB-lg-5ymUDgm', + 'ROW-0F99WDC-sz', + ], + type: 'MARKDOWN', + }, + // @ts-expect-error + ROOT_ID: { + children: ['TABS-97PVJa11D_'], + id: 'ROOT_ID', + type: 'ROOT', + }, + 'ROW-0F99WDC-sz': { + children: ['MARKDOWN-JOZKOjVc3a'], + id: 'ROW-0F99WDC-sz', + meta: { + // @ts-expect-error + background: 'BACKGROUND_TRANSPARENT', + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-lg-5ymUDgm'], + type: 'ROW', + }, + 'ROW-7kAf1blYU': { + children: ['CHART-W02beJK7ms', 'CHART-XFag0yZdLk', 'CHART-8OG3UJX-Tn'], + id: 'ROW-7kAf1blYU', + meta: { + // @ts-expect-error + '0': 'ROOT_ID', + background: 'BACKGROUND_TRANSPARENT', + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-lg-5ymUDgm'], + type: 'ROW', + }, + 'ROW-NuR8GFQTO': { + children: ['CHART-_sx22yawJO', 'CHART-XRvRfsMsaQ'], + id: 'ROW-NuR8GFQTO', + meta: { + // @ts-expect-error + '0': 'ROOT_ID', + '1': 'TABS-97PVJa11D_', + background: 'BACKGROUND_TRANSPARENT', + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-lg-5ymUDgm'], + type: 'ROW', + }, + 'ROW-XT1DsNA_V': { + children: ['CHART-wt6ZO8jRXZ'], + id: 'ROW-XT1DsNA_V', + meta: { + // @ts-expect-error + background: 'BACKGROUND_TRANSPARENT', + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-lg-5ymUDgm'], + type: 'ROW', + }, + 'ROW-fjg6YQBkH': { + children: ['CHART-1L7NIcXvVN', 'CHART-nYns6xr4Ft'], + id: 'ROW-fjg6YQBkH', + meta: { + // @ts-expect-error + background: 'BACKGROUND_TRANSPARENT', + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-2_QXp8aNq'], + type: 'ROW', + }, + 'ROW-yP9SB89PZ': { + children: ['COLUMN-F53B1OSMcz', 'CHART-XVIYTeubZh', 'CHART-7mKdnU7OUJ'], + id: 'ROW-yP9SB89PZ', + meta: { + // @ts-expect-error + background: 'BACKGROUND_TRANSPARENT', + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_', 'TAB-2_QXp8aNq'], + type: 'ROW', + }, + 'TAB-2_QXp8aNq': { + children: ['ROW-yP9SB89PZ', 'ROW-fjg6YQBkH'], + id: 'TAB-2_QXp8aNq', + // @ts-expect-error + meta: { + text: '🤿 Explore Trends', + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_'], + type: 'TAB', + }, + 'TAB-lg-5ymUDgm': { + children: [ + 'ROW-0F99WDC-sz', + 'ROW-XT1DsNA_V', + 'ROW-7kAf1blYU', + 'ROW-NuR8GFQTO', + ], + id: 'TAB-lg-5ymUDgm', + // @ts-expect-error + meta: { + text: 'Overview', + }, + parents: ['ROOT_ID', 'TABS-97PVJa11D_'], + type: 'TAB', + }, + 'TABS-97PVJa11D_': { + children: ['TAB-lg-5ymUDgm', 'TAB-2_QXp8aNq'], + id: 'TABS-97PVJa11D_', + // @ts-expect-error + meta: {}, + parents: ['ROOT_ID'], + type: 'TABS', + }, + }; + + const charts = { + '78': { + id: 78, + chartAlert: null, + chartStatus: 'rendered', + chartStackTrace: null, + chartUpdateEndTime: 1673046999783, + chartUpdateStartTime: 1673046994590, + latestQueryFormData: { + datasource: '20__table', + viz_type: 'table', + slice_id: 78, + url_params: {}, + granularity_sqla: 'year', + time_grain_sqla: 'P1D', + time_range: 'No filter', + query_mode: 'raw', + groupby: [], + metrics: ['count'], + all_columns: [ + 'rank', + 'name', + 'global_sales', + 'platform', + 'genre', + 'publisher', + 'year', + ], + percent_metrics: [], + adhoc_filters: [], + order_by_cols: [], + row_limit: 10, + server_page_length: 10, + order_desc: true, + table_timestamp_format: 'smart_date', + page_length: null, + show_cell_bars: false, + color_pn: false, + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + label_colors: { + '0': '#1FA8C9', + '1': '#454E7C', + '2600': '#666666', + Europe: '#5AC189', + Japan: '#FF7F44', + 'North America': '#666666', + Other: '#E04355', + PS2: '#FCC700', + X360: '#A868B7', + PS3: '#3CCCCB', + Wii: '#A38F79', + DS: '#8FD3E4', + PS: '#A1A6BD', + GBA: '#ACE1C4', + PSP: '#FEC0A1', + PS4: '#B2B2B2', + PC: '#EFA1AA', + GB: '#FDE380', + XB: '#D3B3DA', + NES: '#9EE5E5', + '3DS': '#D1C6BC', + N64: '#1FA8C9', + SNES: '#454E7C', + GC: '#5AC189', + XOne: '#FF7F44', + WiiU: '#E04355', + PSV: '#FCC700', + SAT: '#A868B7', + GEN: '#3CCCCB', + DC: '#A38F79', + SCD: '#8FD3E4', + NG: '#A1A6BD', + WS: '#ACE1C4', + TG16: '#FEC0A1', + '3DO': '#B2B2B2', + GG: '#EFA1AA', + PCFX: '#FDE380', + Nintendo: '#D3B3DA', + 'Take-Two Interactive': '#9EE5E5', + 'Microsoft Game Studios': '#D1C6BC', + Action: '#1FA8C9', + Adventure: '#454E7C', + Fighting: '#5AC189', + Misc: '#FF7F44', + Platform: '#666666', + Puzzle: '#E04355', + Racing: '#FCC700', + 'Role-Playing': '#A868B7', + Shooter: '#3CCCCB', + Simulation: '#A38F79', + Sports: '#8FD3E4', + Strategy: '#A1A6BD', + }, + shared_label_colors: {}, + color_scheme: 'supersetColors', + extra_filters: [ + { + col: '__time_range', + op: '==', + val: 'No filter', + }, + ], + extra_form_data: {}, + dashboardId: 9, + }, + sliceFormData: null, + queryController: {}, + queriesResponse: [ + { + cache_key: '83862e7cb770044d4b5a4b2d8e665022', + cached_dttm: null, + cache_timeout: 86400, + applied_template_filters: [], + annotation_data: {}, + error: null, + is_cached: null, + query: + 'SELECT rank AS rank,\n name AS name,\n global_sales AS global_sales,\n platform AS platform,\n genre AS genre,\n publisher AS publisher,\n year AS year\nFROM main.video_game_sales\nLIMIT 10\nOFFSET 0;\n\n', + status: 'success', + stacktrace: null, + rowcount: 10, + from_dttm: null, + to_dttm: null, + label_map: { + rank: ['rank'], + name: ['name'], + global_sales: ['global_sales'], + platform: ['platform'], + genre: ['genre'], + publisher: ['publisher'], + year: ['year'], + }, + colnames: [ + 'rank', + 'name', + 'global_sales', + 'platform', + 'genre', + 'publisher', + 'year', + ], + indexnames: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + coltypes: [0, 1, 0, 1, 1, 1, 2], + data: [ + { + rank: 1, + name: 'Wii Sports', + global_sales: 82.74, + platform: 'Wii', + genre: 'Sports', + publisher: 'Nintendo', + year: 1136073600000, + }, + { + rank: 2, + name: 'Super Mario Bros.', + global_sales: 40.24, + platform: 'NES', + genre: 'Platform', + publisher: 'Nintendo', + year: 473385600000, + }, + { + rank: 3, + name: 'Mario Kart Wii', + global_sales: 35.82, + platform: 'Wii', + genre: 'Racing', + publisher: 'Nintendo', + year: 1199145600000, + }, + { + rank: 4, + name: 'Wii Sports Resort', + global_sales: 33, + platform: 'Wii', + genre: 'Sports', + publisher: 'Nintendo', + year: 1230768000000, + }, + { + rank: 5, + name: 'Pokemon Red/Pokemon Blue', + global_sales: 31.37, + platform: 'GB', + genre: 'Role-Playing', + publisher: 'Nintendo', + year: 820454400000, + }, + { + rank: 6, + name: 'Tetris', + global_sales: 30.26, + platform: 'GB', + genre: 'Puzzle', + publisher: 'Nintendo', + year: 599616000000, + }, + { + rank: 7, + name: 'New Super Mario Bros.', + global_sales: 30.01, + platform: 'DS', + genre: 'Platform', + publisher: 'Nintendo', + year: 1136073600000, + }, + { + rank: 8, + name: 'Wii Play', + global_sales: 29.02, + platform: 'Wii', + genre: 'Misc', + publisher: 'Nintendo', + year: 1136073600000, + }, + { + rank: 9, + name: 'New Super Mario Bros. Wii', + global_sales: 28.62, + platform: 'Wii', + genre: 'Platform', + publisher: 'Nintendo', + year: 1230768000000, + }, + { + rank: 10, + name: 'Duck Hunt', + global_sales: 28.31, + platform: 'NES', + genre: 'Shooter', + publisher: 'Nintendo', + year: 441763200000, + }, + ], + result_format: 'json', + applied_filters: [ + { + column: '__time_range', + }, + ], + rejected_filters: [], + }, + ], + triggerQuery: false, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'table', + slice_id: 78, + url_params: {}, + granularity_sqla: 'year', + time_grain_sqla: 'P1D', + time_range: 'No filter', + query_mode: 'raw', + groupby: [], + metrics: ['count'], + all_columns: [ + 'rank', + 'name', + 'global_sales', + 'platform', + 'genre', + 'publisher', + 'year', + ], + percent_metrics: [], + adhoc_filters: [], + order_by_cols: [], + row_limit: 10, + server_page_length: 10, + order_desc: true, + table_timestamp_format: 'smart_date', + page_length: null, + show_cell_bars: false, + color_pn: false, + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + }, + }, + '93': { + id: 93, + chartAlert: null, + chartStatus: 'rendered', + chartStackTrace: null, + chartUpdateEndTime: 1673046999051, + chartUpdateStartTime: 1673046994633, + latestQueryFormData: { + datasource: '20__table', + viz_type: 'heatmap', + slice_id: 93, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + all_columns_x: 'platform', + all_columns_y: 'genre', + metric: 'count', + adhoc_filters: [], + row_limit: 10000, + linear_color_scheme: 'blue_white_yellow', + xscale_interval: null, + yscale_interval: null, + canvas_image_rendering: 'pixelated', + normalize_across: 'heatmap', + left_margin: 'auto', + bottom_margin: 'auto', + y_axis_bounds: [null, null], + y_axis_format: 'SMART_NUMBER', + sort_x_axis: 'alpha_asc', + sort_y_axis: 'alpha_asc', + show_legend: true, + show_perc: true, + show_values: true, + queryFields: { + metric: 'metrics', + }, + shared_label_colors: {}, + color_scheme: 'supersetColors', + extra_filters: [ + { + col: '__time_range', + op: '==', + val: 'No filter', + }, + ], + extra_form_data: {}, + dashboardId: 9, + }, + sliceFormData: null, + queryController: {}, + queriesResponse: [ + { + cache_key: '74366173c918f7430ab23aaa5567af49', + cached_dttm: null, + cache_timeout: 86400, + errors: [], + form_data: { + datasource: '20__table', + viz_type: 'heatmap', + slice_id: 93, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + all_columns_x: 'platform', + all_columns_y: 'genre', + metric: 'count', + adhoc_filters: [], + row_limit: 10000, + linear_color_scheme: 'blue_white_yellow', + xscale_interval: null, + yscale_interval: null, + canvas_image_rendering: 'pixelated', + normalize_across: 'heatmap', + left_margin: 'auto', + bottom_margin: 'auto', + y_axis_bounds: [null, null], + y_axis_format: 'SMART_NUMBER', + sort_x_axis: 'alpha_asc', + sort_y_axis: 'alpha_asc', + show_legend: true, + show_perc: true, + show_values: true, + queryFields: { + metric: 'metrics', + }, + shared_label_colors: {}, + color_scheme: 'supersetColors', + dashboardId: 9, + applied_time_extras: {}, + where: '', + having: '', + having_filters: [], + filters: [], + }, + is_cached: false, + query: + 'SELECT platform AS platform,\n genre AS genre,\n COUNT(*) AS count\nFROM main.video_game_sales\nGROUP BY platform,\n genre\nLIMIT 10000\nOFFSET 0', + from_dttm: null, + to_dttm: null, + status: 'success', + stacktrace: null, + rowcount: 293, + colnames: ['platform', 'genre', 'count'], + coltypes: [1, 1, 0], + data: { + records: [ + { + x: '2600', + y: 'Action', + v: 61, + perc: 0.15037593984962405, + rank: 0.6962457337883959, + }, + { + x: '2600', + y: 'Adventure', + v: 2, + perc: 0.002506265664160401, + rank: 0.09044368600682594, + }, + { + x: '2600', + y: 'Fighting', + v: 2, + perc: 0.002506265664160401, + rank: 0.09044368600682594, + }, + { + x: '2600', + y: 'Misc', + v: 5, + perc: 0.010025062656641603, + rank: 0.1962457337883959, + }, + { + x: '2600', + y: 'Platform', + v: 9, + perc: 0.020050125313283207, + rank: 0.2832764505119454, + }, + { + x: '2600', + y: 'Puzzle', + v: 11, + perc: 0.02506265664160401, + rank: 0.3242320819112628, + }, + { + x: '2600', + y: 'Racing', + v: 6, + perc: 0.012531328320802004, + rank: 0.22184300341296928, + }, + { + x: '2600', + y: 'Shooter', + v: 24, + perc: 0.05764411027568922, + rank: 0.49829351535836175, + }, + { + x: '2600', + y: 'Simulation', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: '2600', + y: 'Sports', + v: 12, + perc: 0.02756892230576441, + rank: 0.34982935153583616, + }, + { + x: '3DO', + y: 'Adventure', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: '3DO', + y: 'Puzzle', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: '3DO', + y: 'Simulation', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: '3DS', + y: 'Action', + v: 182, + perc: 0.45363408521303256, + rank: 0.9146757679180887, + }, + { + x: '3DS', + y: 'Adventure', + v: 37, + perc: 0.09022556390977443, + rank: 0.6006825938566553, + }, + { + x: '3DS', + y: 'Fighting', + v: 14, + perc: 0.03258145363408521, + rank: 0.378839590443686, + }, + { + x: '3DS', + y: 'Misc', + v: 53, + perc: 0.13032581453634084, + rank: 0.6723549488054608, + }, + { + x: '3DS', + y: 'Platform', + v: 28, + perc: 0.06766917293233082, + rank: 0.5426621160409556, + }, + { + x: '3DS', + y: 'Puzzle', + v: 20, + perc: 0.047619047619047616, + rank: 0.4590443686006826, + }, + { + x: '3DS', + y: 'Racing', + v: 11, + perc: 0.02506265664160401, + rank: 0.3242320819112628, + }, + { + x: '3DS', + y: 'Role-Playing', + v: 86, + perc: 0.21303258145363407, + rank: 0.7832764505119454, + }, + { + x: '3DS', + y: 'Shooter', + v: 7, + perc: 0.015037593984962405, + rank: 0.24573378839590443, + }, + { + x: '3DS', + y: 'Simulation', + v: 30, + perc: 0.07268170426065163, + rank: 0.5580204778156996, + }, + { + x: '3DS', + y: 'Sports', + v: 26, + perc: 0.06265664160401002, + rank: 0.5273037542662116, + }, + { + x: '3DS', + y: 'Strategy', + v: 15, + perc: 0.03508771929824561, + rank: 0.39419795221843, + }, + { + x: 'DC', + y: 'Action', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'DC', + y: 'Adventure', + v: 11, + perc: 0.02506265664160401, + rank: 0.3242320819112628, + }, + { + x: 'DC', + y: 'Fighting', + v: 12, + perc: 0.02756892230576441, + rank: 0.34982935153583616, + }, + { + x: 'DC', + y: 'Platform', + v: 2, + perc: 0.002506265664160401, + rank: 0.09044368600682594, + }, + { + x: 'DC', + y: 'Racing', + v: 6, + perc: 0.012531328320802004, + rank: 0.22184300341296928, + }, + { + x: 'DC', + y: 'Role-Playing', + v: 4, + perc: 0.007518796992481203, + rank: 0.16552901023890784, + }, + { + x: 'DC', + y: 'Shooter', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'DC', + y: 'Simulation', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'DC', + y: 'Sports', + v: 10, + perc: 0.022556390977443608, + rank: 0.3003412969283277, + }, + { + x: 'DS', + y: 'Action', + v: 343, + perc: 0.8571428571428571, + rank: 0.9863481228668942, + }, + { + x: 'DS', + y: 'Adventure', + v: 240, + perc: 0.5989974937343359, + rank: 0.9692832764505119, + }, + { + x: 'DS', + y: 'Fighting', + v: 36, + perc: 0.08771929824561403, + rank: 0.5887372013651877, + }, + { + x: 'DS', + y: 'Misc', + v: 393, + perc: 0.9824561403508771, + rank: 0.9965870307167235, + }, + { + x: 'DS', + y: 'Platform', + v: 92, + perc: 0.22807017543859648, + rank: 0.8003412969283277, + }, + { + x: 'DS', + y: 'Puzzle', + v: 238, + perc: 0.5939849624060151, + rank: 0.9641638225255973, + }, + { + x: 'DS', + y: 'Racing', + v: 67, + perc: 0.16541353383458646, + rank: 0.726962457337884, + }, + { + x: 'DS', + y: 'Role-Playing', + v: 200, + perc: 0.49874686716791977, + rank: 0.931740614334471, + }, + { + x: 'DS', + y: 'Shooter', + v: 42, + perc: 0.10275689223057644, + rank: 0.6279863481228669, + }, + { + x: 'DS', + y: 'Simulation', + v: 284, + perc: 0.7092731829573935, + rank: 0.9795221843003413, + }, + { + x: 'DS', + y: 'Sports', + v: 148, + perc: 0.3684210526315789, + rank: 0.8822525597269625, + }, + { + x: 'DS', + y: 'Strategy', + v: 79, + perc: 0.19548872180451127, + rank: 0.7679180887372014, + }, + { + x: 'GB', + y: 'Action', + v: 6, + perc: 0.012531328320802004, + rank: 0.22184300341296928, + }, + { + x: 'GB', + y: 'Adventure', + v: 5, + perc: 0.010025062656641603, + rank: 0.1962457337883959, + }, + { + x: 'GB', + y: 'Misc', + v: 8, + perc: 0.017543859649122806, + rank: 0.26791808873720135, + }, + { + x: 'GB', + y: 'Platform', + v: 19, + perc: 0.045112781954887216, + rank: 0.45051194539249145, + }, + { + x: 'GB', + y: 'Puzzle', + v: 15, + perc: 0.03508771929824561, + rank: 0.39419795221843, + }, + { + x: 'GB', + y: 'Racing', + v: 2, + perc: 0.002506265664160401, + rank: 0.09044368600682594, + }, + { + x: 'GB', + y: 'Role-Playing', + v: 21, + perc: 0.05012531328320802, + rank: 0.46757679180887374, + }, + { + x: 'GB', + y: 'Shooter', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'GB', + y: 'Simulation', + v: 5, + perc: 0.010025062656641603, + rank: 0.1962457337883959, + }, + { + x: 'GB', + y: 'Sports', + v: 9, + perc: 0.020050125313283207, + rank: 0.2832764505119454, + }, + { + x: 'GB', + y: 'Strategy', + v: 7, + perc: 0.015037593984962405, + rank: 0.24573378839590443, + }, + { + x: 'GBA', + y: 'Action', + v: 167, + perc: 0.41604010025062654, + rank: 0.9078498293515358, + }, + { + x: 'GBA', + y: 'Adventure', + v: 38, + perc: 0.09273182957393483, + rank: 0.6092150170648464, + }, + { + x: 'GBA', + y: 'Fighting', + v: 23, + perc: 0.05513784461152882, + rank: 0.4812286689419795, + }, + { + x: 'GBA', + y: 'Misc', + v: 110, + perc: 0.2731829573934837, + rank: 0.8378839590443686, + }, + { + x: 'GBA', + y: 'Platform', + v: 142, + perc: 0.3533834586466165, + rank: 0.8737201365187713, + }, + { + x: 'GBA', + y: 'Puzzle', + v: 41, + perc: 0.10025062656641603, + rank: 0.621160409556314, + }, + { + x: 'GBA', + y: 'Racing', + v: 64, + perc: 0.15789473684210525, + rank: 0.7081911262798635, + }, + { + x: 'GBA', + y: 'Role-Playing', + v: 73, + perc: 0.18045112781954886, + rank: 0.7457337883959044, + }, + { + x: 'GBA', + y: 'Shooter', + v: 40, + perc: 0.09774436090225563, + rank: 0.6160409556313993, + }, + { + x: 'GBA', + y: 'Simulation', + v: 18, + perc: 0.042606516290726815, + rank: 0.43686006825938567, + }, + { + x: 'GBA', + y: 'Sports', + v: 88, + perc: 0.21804511278195488, + rank: 0.7918088737201365, + }, + { + x: 'GBA', + y: 'Strategy', + v: 18, + perc: 0.042606516290726815, + rank: 0.43686006825938567, + }, + { + x: 'GC', + y: 'Action', + v: 101, + perc: 0.2506265664160401, + rank: 0.8156996587030717, + }, + { + x: 'GC', + y: 'Adventure', + v: 20, + perc: 0.047619047619047616, + rank: 0.4590443686006826, + }, + { + x: 'GC', + y: 'Fighting', + v: 42, + perc: 0.10275689223057644, + rank: 0.6279863481228669, + }, + { + x: 'GC', + y: 'Misc', + v: 36, + perc: 0.08771929824561403, + rank: 0.5887372013651877, + }, + { + x: 'GC', + y: 'Platform', + v: 73, + perc: 0.18045112781954886, + rank: 0.7457337883959044, + }, + { + x: 'GC', + y: 'Puzzle', + v: 13, + perc: 0.03007518796992481, + rank: 0.36689419795221845, + }, + { + x: 'GC', + y: 'Racing', + v: 63, + perc: 0.15538847117794485, + rank: 0.7013651877133106, + }, + { + x: 'GC', + y: 'Role-Playing', + v: 27, + perc: 0.06516290726817042, + rank: 0.5358361774744027, + }, + { + x: 'GC', + y: 'Shooter', + v: 48, + perc: 0.11779448621553884, + rank: 0.6535836177474402, + }, + { + x: 'GC', + y: 'Simulation', + v: 12, + perc: 0.02756892230576441, + rank: 0.34982935153583616, + }, + { + x: 'GC', + y: 'Sports', + v: 110, + perc: 0.2731829573934837, + rank: 0.8378839590443686, + }, + { + x: 'GC', + y: 'Strategy', + v: 11, + perc: 0.02506265664160401, + rank: 0.3242320819112628, + }, + { + x: 'GEN', + y: 'Action', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'GEN', + y: 'Adventure', + v: 2, + perc: 0.002506265664160401, + rank: 0.09044368600682594, + }, + { + x: 'GEN', + y: 'Fighting', + v: 5, + perc: 0.010025062656641603, + rank: 0.1962457337883959, + }, + { + x: 'GEN', + y: 'Misc', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'GEN', + y: 'Platform', + v: 7, + perc: 0.015037593984962405, + rank: 0.24573378839590443, + }, + { + x: 'GEN', + y: 'Racing', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'GEN', + y: 'Role-Playing', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'GEN', + y: 'Shooter', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'GEN', + y: 'Sports', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'GEN', + y: 'Strategy', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'GG', + y: 'Platform', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'N64', + y: 'Action', + v: 38, + perc: 0.09273182957393483, + rank: 0.6092150170648464, + }, + { + x: 'N64', + y: 'Adventure', + v: 4, + perc: 0.007518796992481203, + rank: 0.16552901023890784, + }, + { + x: 'N64', + y: 'Fighting', + v: 29, + perc: 0.07017543859649122, + rank: 0.5511945392491467, + }, + { + x: 'N64', + y: 'Misc', + v: 18, + perc: 0.042606516290726815, + rank: 0.43686006825938567, + }, + { + x: 'N64', + y: 'Platform', + v: 30, + perc: 0.07268170426065163, + rank: 0.5580204778156996, + }, + { + x: 'N64', + y: 'Puzzle', + v: 12, + perc: 0.02756892230576441, + rank: 0.34982935153583616, + }, + { + x: 'N64', + y: 'Racing', + v: 57, + perc: 0.14035087719298245, + rank: 0.6791808873720137, + }, + { + x: 'N64', + y: 'Role-Playing', + v: 8, + perc: 0.017543859649122806, + rank: 0.26791808873720135, + }, + { + x: 'N64', + y: 'Shooter', + v: 24, + perc: 0.05764411027568922, + rank: 0.49829351535836175, + }, + { + x: 'N64', + y: 'Simulation', + v: 10, + perc: 0.022556390977443608, + rank: 0.3003412969283277, + }, + { + x: 'N64', + y: 'Sports', + v: 80, + perc: 0.19799498746867167, + rank: 0.7713310580204779, + }, + { + x: 'N64', + y: 'Strategy', + v: 9, + perc: 0.020050125313283207, + rank: 0.2832764505119454, + }, + { + x: 'NES', + y: 'Action', + v: 13, + perc: 0.03007518796992481, + rank: 0.36689419795221845, + }, + { + x: 'NES', + y: 'Adventure', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'NES', + y: 'Fighting', + v: 4, + perc: 0.007518796992481203, + rank: 0.16552901023890784, + }, + { + x: 'NES', + y: 'Misc', + v: 2, + perc: 0.002506265664160401, + rank: 0.09044368600682594, + }, + { + x: 'NES', + y: 'Platform', + v: 28, + perc: 0.06766917293233082, + rank: 0.5426621160409556, + }, + { + x: 'NES', + y: 'Puzzle', + v: 14, + perc: 0.03258145363408521, + rank: 0.378839590443686, + }, + { + x: 'NES', + y: 'Racing', + v: 4, + perc: 0.007518796992481203, + rank: 0.16552901023890784, + }, + { + x: 'NES', + y: 'Role-Playing', + v: 11, + perc: 0.02506265664160401, + rank: 0.3242320819112628, + }, + { + x: 'NES', + y: 'Shooter', + v: 7, + perc: 0.015037593984962405, + rank: 0.24573378839590443, + }, + { + x: 'NES', + y: 'Sports', + v: 14, + perc: 0.03258145363408521, + rank: 0.378839590443686, + }, + { + x: 'NG', + y: 'Fighting', + v: 11, + perc: 0.02506265664160401, + rank: 0.3242320819112628, + }, + { + x: 'NG', + y: 'Sports', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'PC', + y: 'Action', + v: 165, + perc: 0.41102756892230574, + rank: 0.9044368600682594, + }, + { + x: 'PC', + y: 'Adventure', + v: 65, + perc: 0.16040100250626566, + rank: 0.7167235494880546, + }, + { + x: 'PC', + y: 'Fighting', + v: 6, + perc: 0.012531328320802004, + rank: 0.22184300341296928, + }, + { + x: 'PC', + y: 'Misc', + v: 24, + perc: 0.05764411027568922, + rank: 0.49829351535836175, + }, + { + x: 'PC', + y: 'Platform', + v: 11, + perc: 0.02506265664160401, + rank: 0.3242320819112628, + }, + { + x: 'PC', + y: 'Puzzle', + v: 25, + perc: 0.06015037593984962, + rank: 0.515358361774744, + }, + { + x: 'PC', + y: 'Racing', + v: 60, + perc: 0.14786967418546365, + rank: 0.689419795221843, + }, + { + x: 'PC', + y: 'Role-Playing', + v: 104, + perc: 0.2581453634085213, + rank: 0.8225255972696246, + }, + { + x: 'PC', + y: 'Shooter', + v: 148, + perc: 0.3684210526315789, + rank: 0.8822525597269625, + }, + { + x: 'PC', + y: 'Simulation', + v: 115, + perc: 0.2857142857142857, + rank: 0.8430034129692833, + }, + { + x: 'PC', + y: 'Sports', + v: 49, + perc: 0.12030075187969924, + rank: 0.6621160409556314, + }, + { + x: 'PC', + y: 'Strategy', + v: 188, + perc: 0.46867167919799496, + rank: 0.9215017064846417, + }, + { + x: 'PCFX', + y: 'Role-Playing', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'PS', + y: 'Action', + v: 157, + perc: 0.39097744360902253, + rank: 0.8976109215017065, + }, + { + x: 'PS', + y: 'Adventure', + v: 69, + perc: 0.17042606516290726, + rank: 0.7337883959044369, + }, + { + x: 'PS', + y: 'Fighting', + v: 108, + perc: 0.2681704260651629, + rank: 0.8327645051194539, + }, + { + x: 'PS', + y: 'Misc', + v: 76, + perc: 0.18796992481203006, + rank: 0.7610921501706485, + }, + { + x: 'PS', + y: 'Platform', + v: 64, + perc: 0.15789473684210525, + rank: 0.7081911262798635, + }, + { + x: 'PS', + y: 'Puzzle', + v: 32, + perc: 0.07769423558897243, + rank: 0.5699658703071673, + }, + { + x: 'PS', + y: 'Racing', + v: 145, + perc: 0.3609022556390977, + rank: 0.8771331058020477, + }, + { + x: 'PS', + y: 'Role-Playing', + v: 97, + perc: 0.24060150375939848, + rank: 0.8122866894197952, + }, + { + x: 'PS', + y: 'Shooter', + v: 96, + perc: 0.23809523809523808, + rank: 0.8088737201365188, + }, + { + x: 'PS', + y: 'Simulation', + v: 60, + perc: 0.14786967418546365, + rank: 0.689419795221843, + }, + { + x: 'PS', + y: 'Sports', + v: 222, + perc: 0.5538847117794486, + rank: 0.9556313993174061, + }, + { + x: 'PS', + y: 'Strategy', + v: 70, + perc: 0.17293233082706766, + rank: 0.7372013651877133, + }, + { + x: 'PS2', + y: 'Action', + v: 348, + perc: 0.8696741854636592, + rank: 0.9897610921501706, + }, + { + x: 'PS2', + y: 'Adventure', + v: 196, + perc: 0.48872180451127817, + rank: 0.9283276450511946, + }, + { + x: 'PS2', + y: 'Fighting', + v: 150, + perc: 0.37343358395989973, + rank: 0.8873720136518771, + }, + { + x: 'PS2', + y: 'Misc', + v: 222, + perc: 0.5538847117794486, + rank: 0.9556313993174061, + }, + { + x: 'PS2', + y: 'Platform', + v: 103, + perc: 0.2556390977443609, + rank: 0.8191126279863481, + }, + { + x: 'PS2', + y: 'Puzzle', + v: 18, + perc: 0.042606516290726815, + rank: 0.43686006825938567, + }, + { + x: 'PS2', + y: 'Racing', + v: 216, + perc: 0.5388471177944862, + rank: 0.9453924914675768, + }, + { + x: 'PS2', + y: 'Role-Playing', + v: 187, + perc: 0.46616541353383456, + rank: 0.9180887372013652, + }, + { + x: 'PS2', + y: 'Shooter', + v: 160, + perc: 0.39849624060150374, + rank: 0.9010238907849829, + }, + { + x: 'PS2', + y: 'Simulation', + v: 90, + perc: 0.22305764411027568, + rank: 0.7952218430034129, + }, + { + x: 'PS2', + y: 'Sports', + v: 400, + perc: 1, + rank: 1, + }, + { + x: 'PS2', + y: 'Strategy', + v: 71, + perc: 0.17543859649122806, + rank: 0.7406143344709898, + }, + { + x: 'PS3', + y: 'Action', + v: 380, + perc: 0.949874686716792, + rank: 0.9931740614334471, + }, + { + x: 'PS3', + y: 'Adventure', + v: 74, + perc: 0.18295739348370926, + rank: 0.7525597269624573, + }, + { + x: 'PS3', + y: 'Fighting', + v: 76, + perc: 0.18796992481203006, + rank: 0.7610921501706485, + }, + { + x: 'PS3', + y: 'Misc', + v: 124, + perc: 0.3082706766917293, + rank: 0.856655290102389, + }, + { + x: 'PS3', + y: 'Platform', + v: 37, + perc: 0.09022556390977443, + rank: 0.6006825938566553, + }, + { + x: 'PS3', + y: 'Puzzle', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'PS3', + y: 'Racing', + v: 92, + perc: 0.22807017543859648, + rank: 0.8003412969283277, + }, + { + x: 'PS3', + y: 'Role-Playing', + v: 119, + perc: 0.2957393483709273, + rank: 0.8464163822525598, + }, + { + x: 'PS3', + y: 'Shooter', + v: 156, + perc: 0.38847117794486213, + rank: 0.89419795221843, + }, + { + x: 'PS3', + y: 'Simulation', + v: 31, + perc: 0.07518796992481203, + rank: 0.5648464163822525, + }, + { + x: 'PS3', + y: 'Sports', + v: 213, + perc: 0.531328320802005, + rank: 0.9402730375426621, + }, + { + x: 'PS3', + y: 'Strategy', + v: 24, + perc: 0.05764411027568922, + rank: 0.49829351535836175, + }, + { + x: 'PS4', + y: 'Action', + v: 122, + perc: 0.3032581453634085, + rank: 0.8498293515358362, + }, + { + x: 'PS4', + y: 'Adventure', + v: 19, + perc: 0.045112781954887216, + rank: 0.45051194539249145, + }, + { + x: 'PS4', + y: 'Fighting', + v: 17, + perc: 0.040100250626566414, + rank: 0.42150170648464164, + }, + { + x: 'PS4', + y: 'Misc', + v: 15, + perc: 0.03508771929824561, + rank: 0.39419795221843, + }, + { + x: 'PS4', + y: 'Platform', + v: 11, + perc: 0.02506265664160401, + rank: 0.3242320819112628, + }, + { + x: 'PS4', + y: 'Puzzle', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'PS4', + y: 'Racing', + v: 17, + perc: 0.040100250626566414, + rank: 0.42150170648464164, + }, + { + x: 'PS4', + y: 'Role-Playing', + v: 47, + perc: 0.11528822055137844, + rank: 0.6467576791808873, + }, + { + x: 'PS4', + y: 'Shooter', + v: 34, + perc: 0.08270676691729323, + rank: 0.5767918088737202, + }, + { + x: 'PS4', + y: 'Simulation', + v: 5, + perc: 0.010025062656641603, + rank: 0.1962457337883959, + }, + { + x: 'PS4', + y: 'Sports', + v: 43, + perc: 0.10526315789473684, + rank: 0.6348122866894198, + }, + { + x: 'PS4', + y: 'Strategy', + v: 5, + perc: 0.010025062656641603, + rank: 0.1962457337883959, + }, + { + x: 'PSP', + y: 'Action', + v: 222, + perc: 0.5538847117794486, + rank: 0.9556313993174061, + }, + { + x: 'PSP', + y: 'Adventure', + v: 213, + perc: 0.531328320802005, + rank: 0.9402730375426621, + }, + { + x: 'PSP', + y: 'Fighting', + v: 74, + perc: 0.18295739348370926, + rank: 0.7525597269624573, + }, + { + x: 'PSP', + y: 'Misc', + v: 106, + perc: 0.2631578947368421, + rank: 0.8293515358361775, + }, + { + x: 'PSP', + y: 'Platform', + v: 36, + perc: 0.08771929824561403, + rank: 0.5887372013651877, + }, + { + x: 'PSP', + y: 'Puzzle', + v: 44, + perc: 0.10776942355889724, + rank: 0.6382252559726962, + }, + { + x: 'PSP', + y: 'Racing', + v: 65, + perc: 0.16040100250626566, + rank: 0.7167235494880546, + }, + { + x: 'PSP', + y: 'Role-Playing', + v: 192, + perc: 0.47869674185463656, + rank: 0.9249146757679181, + }, + { + x: 'PSP', + y: 'Shooter', + v: 37, + perc: 0.09022556390977443, + rank: 0.6006825938566553, + }, + { + x: 'PSP', + y: 'Simulation', + v: 29, + perc: 0.07017543859649122, + rank: 0.5511945392491467, + }, + { + x: 'PSP', + y: 'Sports', + v: 135, + perc: 0.3358395989974937, + rank: 0.8668941979522184, + }, + { + x: 'PSP', + y: 'Strategy', + v: 60, + perc: 0.14786967418546365, + rank: 0.689419795221843, + }, + { + x: 'PSV', + y: 'Action', + v: 141, + perc: 0.3508771929824561, + rank: 0.8703071672354948, + }, + { + x: 'PSV', + y: 'Adventure', + v: 86, + perc: 0.21303258145363407, + rank: 0.7832764505119454, + }, + { + x: 'PSV', + y: 'Fighting', + v: 16, + perc: 0.03759398496240601, + rank: 0.40955631399317405, + }, + { + x: 'PSV', + y: 'Misc', + v: 24, + perc: 0.05764411027568922, + rank: 0.49829351535836175, + }, + { + x: 'PSV', + y: 'Platform', + v: 10, + perc: 0.022556390977443608, + rank: 0.3003412969283277, + }, + { + x: 'PSV', + y: 'Puzzle', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'PSV', + y: 'Racing', + v: 11, + perc: 0.02506265664160401, + rank: 0.3242320819112628, + }, + { + x: 'PSV', + y: 'Role-Playing', + v: 82, + perc: 0.20300751879699247, + rank: 0.7747440273037542, + }, + { + x: 'PSV', + y: 'Shooter', + v: 5, + perc: 0.010025062656641603, + rank: 0.1962457337883959, + }, + { + x: 'PSV', + y: 'Simulation', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'PSV', + y: 'Sports', + v: 23, + perc: 0.05513784461152882, + rank: 0.4812286689419795, + }, + { + x: 'PSV', + y: 'Strategy', + v: 7, + perc: 0.015037593984962405, + rank: 0.24573378839590443, + }, + { + x: 'SAT', + y: 'Action', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'SAT', + y: 'Adventure', + v: 26, + perc: 0.06265664160401002, + rank: 0.5273037542662116, + }, + { + x: 'SAT', + y: 'Fighting', + v: 31, + perc: 0.07518796992481203, + rank: 0.5648464163822525, + }, + { + x: 'SAT', + y: 'Misc', + v: 15, + perc: 0.03508771929824561, + rank: 0.39419795221843, + }, + { + x: 'SAT', + y: 'Platform', + v: 5, + perc: 0.010025062656641603, + rank: 0.1962457337883959, + }, + { + x: 'SAT', + y: 'Puzzle', + v: 5, + perc: 0.010025062656641603, + rank: 0.1962457337883959, + }, + { + x: 'SAT', + y: 'Racing', + v: 8, + perc: 0.017543859649122806, + rank: 0.26791808873720135, + }, + { + x: 'SAT', + y: 'Role-Playing', + v: 17, + perc: 0.040100250626566414, + rank: 0.42150170648464164, + }, + { + x: 'SAT', + y: 'Shooter', + v: 22, + perc: 0.05263157894736842, + rank: 0.47440273037542663, + }, + { + x: 'SAT', + y: 'Simulation', + v: 7, + perc: 0.015037593984962405, + rank: 0.24573378839590443, + }, + { + x: 'SAT', + y: 'Sports', + v: 16, + perc: 0.03759398496240601, + rank: 0.40955631399317405, + }, + { + x: 'SAT', + y: 'Strategy', + v: 18, + perc: 0.042606516290726815, + rank: 0.43686006825938567, + }, + { + x: 'SCD', + y: 'Misc', + v: 2, + perc: 0.002506265664160401, + rank: 0.09044368600682594, + }, + { + x: 'SCD', + y: 'Platform', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'SCD', + y: 'Racing', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'SCD', + y: 'Role-Playing', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'SCD', + y: 'Strategy', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'SNES', + y: 'Action', + v: 12, + perc: 0.02756892230576441, + rank: 0.34982935153583616, + }, + { + x: 'SNES', + y: 'Adventure', + v: 4, + perc: 0.007518796992481203, + rank: 0.16552901023890784, + }, + { + x: 'SNES', + y: 'Fighting', + v: 25, + perc: 0.06015037593984962, + rank: 0.515358361774744, + }, + { + x: 'SNES', + y: 'Misc', + v: 17, + perc: 0.040100250626566414, + rank: 0.42150170648464164, + }, + { + x: 'SNES', + y: 'Platform', + v: 26, + perc: 0.06265664160401002, + rank: 0.5273037542662116, + }, + { + x: 'SNES', + y: 'Puzzle', + v: 13, + perc: 0.03007518796992481, + rank: 0.36689419795221845, + }, + { + x: 'SNES', + y: 'Racing', + v: 9, + perc: 0.020050125313283207, + rank: 0.2832764505119454, + }, + { + x: 'SNES', + y: 'Role-Playing', + v: 50, + perc: 0.12280701754385964, + rank: 0.6689419795221843, + }, + { + x: 'SNES', + y: 'Shooter', + v: 10, + perc: 0.022556390977443608, + rank: 0.3003412969283277, + }, + { + x: 'SNES', + y: 'Simulation', + v: 9, + perc: 0.020050125313283207, + rank: 0.2832764505119454, + }, + { + x: 'SNES', + y: 'Sports', + v: 49, + perc: 0.12030075187969924, + rank: 0.6621160409556314, + }, + { + x: 'SNES', + y: 'Strategy', + v: 15, + perc: 0.03508771929824561, + rank: 0.39419795221843, + }, + { + x: 'TG16', + y: 'Adventure', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'TG16', + y: 'Shooter', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'WS', + y: 'Role-Playing', + v: 4, + perc: 0.007518796992481203, + rank: 0.16552901023890784, + }, + { + x: 'WS', + y: 'Strategy', + v: 2, + perc: 0.002506265664160401, + rank: 0.09044368600682594, + }, + { + x: 'Wii', + y: 'Action', + v: 238, + perc: 0.5939849624060151, + rank: 0.9641638225255973, + }, + { + x: 'Wii', + y: 'Adventure', + v: 84, + perc: 0.20802005012531327, + rank: 0.7781569965870307, + }, + { + x: 'Wii', + y: 'Fighting', + v: 42, + perc: 0.10275689223057644, + rank: 0.6279863481228669, + }, + { + x: 'Wii', + y: 'Misc', + v: 280, + perc: 0.6992481203007519, + rank: 0.9761092150170648, + }, + { + x: 'Wii', + y: 'Platform', + v: 58, + perc: 0.14285714285714285, + rank: 0.6825938566552902, + }, + { + x: 'Wii', + y: 'Puzzle', + v: 55, + perc: 0.13533834586466165, + rank: 0.6757679180887372, + }, + { + x: 'Wii', + y: 'Racing', + v: 94, + perc: 0.23308270676691728, + rank: 0.8054607508532423, + }, + { + x: 'Wii', + y: 'Role-Playing', + v: 35, + perc: 0.08521303258145363, + rank: 0.5802047781569966, + }, + { + x: 'Wii', + y: 'Shooter', + v: 66, + perc: 0.16290726817042606, + rank: 0.7235494880546075, + }, + { + x: 'Wii', + y: 'Simulation', + v: 87, + perc: 0.21553884711779447, + rank: 0.78839590443686, + }, + { + x: 'Wii', + y: 'Sports', + v: 261, + perc: 0.6516290726817042, + rank: 0.9726962457337884, + }, + { + x: 'Wii', + y: 'Strategy', + v: 25, + perc: 0.06015037593984962, + rank: 0.515358361774744, + }, + { + x: 'WiiU', + y: 'Action', + v: 63, + perc: 0.15538847117794485, + rank: 0.7013651877133106, + }, + { + x: 'WiiU', + y: 'Adventure', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'WiiU', + y: 'Fighting', + v: 5, + perc: 0.010025062656641603, + rank: 0.1962457337883959, + }, + { + x: 'WiiU', + y: 'Misc', + v: 21, + perc: 0.05012531328320802, + rank: 0.46757679180887374, + }, + { + x: 'WiiU', + y: 'Platform', + v: 16, + perc: 0.03759398496240601, + rank: 0.40955631399317405, + }, + { + x: 'WiiU', + y: 'Puzzle', + v: 4, + perc: 0.007518796992481203, + rank: 0.16552901023890784, + }, + { + x: 'WiiU', + y: 'Racing', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'WiiU', + y: 'Role-Playing', + v: 6, + perc: 0.012531328320802004, + rank: 0.22184300341296928, + }, + { + x: 'WiiU', + y: 'Shooter', + v: 10, + perc: 0.022556390977443608, + rank: 0.3003412969283277, + }, + { + x: 'WiiU', + y: 'Simulation', + v: 1, + perc: 0, + rank: 0.03924914675767918, + }, + { + x: 'WiiU', + y: 'Sports', + v: 8, + perc: 0.017543859649122806, + rank: 0.26791808873720135, + }, + { + x: 'WiiU', + y: 'Strategy', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'X360', + y: 'Action', + v: 324, + perc: 0.8095238095238095, + rank: 0.9829351535836177, + }, + { + x: 'X360', + y: 'Adventure', + v: 47, + perc: 0.11528822055137844, + rank: 0.6467576791808873, + }, + { + x: 'X360', + y: 'Fighting', + v: 65, + perc: 0.16040100250626566, + rank: 0.7167235494880546, + }, + { + x: 'X360', + y: 'Misc', + v: 126, + perc: 0.3132832080200501, + rank: 0.8600682593856656, + }, + { + x: 'X360', + y: 'Platform', + v: 24, + perc: 0.05764411027568922, + rank: 0.49829351535836175, + }, + { + x: 'X360', + y: 'Puzzle', + v: 7, + perc: 0.015037593984962405, + rank: 0.24573378839590443, + }, + { + x: 'X360', + y: 'Racing', + v: 105, + perc: 0.2606516290726817, + rank: 0.825938566552901, + }, + { + x: 'X360', + y: 'Role-Playing', + v: 76, + perc: 0.18796992481203006, + rank: 0.7610921501706485, + }, + { + x: 'X360', + y: 'Shooter', + v: 203, + perc: 0.506265664160401, + rank: 0.9351535836177475, + }, + { + x: 'X360', + y: 'Simulation', + v: 40, + perc: 0.09774436090225563, + rank: 0.6160409556313993, + }, + { + x: 'X360', + y: 'Sports', + v: 220, + perc: 0.5488721804511278, + rank: 0.9488054607508533, + }, + { + x: 'X360', + y: 'Strategy', + v: 28, + perc: 0.06766917293233082, + rank: 0.5426621160409556, + }, + { + x: 'XB', + y: 'Action', + v: 155, + perc: 0.38596491228070173, + rank: 0.8907849829351536, + }, + { + x: 'XB', + y: 'Adventure', + v: 26, + perc: 0.06265664160401002, + rank: 0.5273037542662116, + }, + { + x: 'XB', + y: 'Fighting', + v: 48, + perc: 0.11779448621553884, + rank: 0.6535836177474402, + }, + { + x: 'XB', + y: 'Misc', + v: 46, + perc: 0.11278195488721804, + rank: 0.6416382252559727, + }, + { + x: 'XB', + y: 'Platform', + v: 49, + perc: 0.12030075187969924, + rank: 0.6621160409556314, + }, + { + x: 'XB', + y: 'Puzzle', + v: 7, + perc: 0.015037593984962405, + rank: 0.24573378839590443, + }, + { + x: 'XB', + y: 'Racing', + v: 123, + perc: 0.3057644110275689, + rank: 0.8532423208191127, + }, + { + x: 'XB', + y: 'Role-Playing', + v: 23, + perc: 0.05513784461152882, + rank: 0.4812286689419795, + }, + { + x: 'XB', + y: 'Shooter', + v: 132, + perc: 0.3283208020050125, + rank: 0.863481228668942, + }, + { + x: 'XB', + y: 'Simulation', + v: 24, + perc: 0.05764411027568922, + rank: 0.49829351535836175, + }, + { + x: 'XB', + y: 'Sports', + v: 170, + perc: 0.42355889724310775, + rank: 0.9112627986348123, + }, + { + x: 'XB', + y: 'Strategy', + v: 21, + perc: 0.05012531328320802, + rank: 0.46757679180887374, + }, + { + x: 'XOne', + y: 'Action', + v: 68, + perc: 0.16791979949874686, + rank: 0.7303754266211604, + }, + { + x: 'XOne', + y: 'Adventure', + v: 12, + perc: 0.02756892230576441, + rank: 0.34982935153583616, + }, + { + x: 'XOne', + y: 'Fighting', + v: 7, + perc: 0.015037593984962405, + rank: 0.24573378839590443, + }, + { + x: 'XOne', + y: 'Misc', + v: 15, + perc: 0.03508771929824561, + rank: 0.39419795221843, + }, + { + x: 'XOne', + y: 'Platform', + v: 4, + perc: 0.007518796992481203, + rank: 0.16552901023890784, + }, + { + x: 'XOne', + y: 'Racing', + v: 19, + perc: 0.045112781954887216, + rank: 0.45051194539249145, + }, + { + x: 'XOne', + y: 'Role-Playing', + v: 13, + perc: 0.03007518796992481, + rank: 0.36689419795221845, + }, + { + x: 'XOne', + y: 'Shooter', + v: 33, + perc: 0.08020050125313283, + rank: 0.5733788395904437, + }, + { + x: 'XOne', + y: 'Simulation', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + { + x: 'XOne', + y: 'Sports', + v: 36, + perc: 0.08771929824561403, + rank: 0.5887372013651877, + }, + { + x: 'XOne', + y: 'Strategy', + v: 3, + perc: 0.005012531328320802, + rank: 0.12798634812286688, + }, + ], + extents: [1, 400], + }, + applied_filters: [], + rejected_filters: [], + }, + ], + triggerQuery: false, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'heatmap', + slice_id: 93, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + all_columns_x: 'platform', + all_columns_y: 'genre', + metric: 'count', + adhoc_filters: [], + row_limit: 10000, + linear_color_scheme: 'blue_white_yellow', + xscale_interval: null, + yscale_interval: null, + canvas_image_rendering: 'pixelated', + normalize_across: 'heatmap', + left_margin: 'auto', + bottom_margin: 'auto', + y_axis_bounds: [null, null], + y_axis_format: 'SMART_NUMBER', + sort_x_axis: 'alpha_asc', + sort_y_axis: 'alpha_asc', + show_legend: true, + show_perc: true, + show_values: true, + queryFields: { + metric: 'metrics', + }, + }, + }, + '95': { + id: 95, + chartAlert: null, + chartStatus: 'loading', + chartStackTrace: null, + chartUpdateEndTime: null, + chartUpdateStartTime: 0, + latestQueryFormData: {}, + sliceFormData: null, + queryController: null, + queriesResponse: null, + triggerQuery: true, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'line', + slice_id: 95, + url_params: { + preselect_filters: + '{"1389": {"platform": ["PS", "PS2", "PS3", "PS4"], "genre": null, "__time_range": "No filter"}}', + }, + granularity_sqla: 'year', + time_grain_sqla: null, + time_range: 'No filter', + metrics: ['count'], + adhoc_filters: [], + groupby: ['genre'], + order_desc: true, + contribution: false, + row_limit: null, + color_scheme: 'supersetColors', + show_brush: 'auto', + show_legend: true, + rich_tooltip: true, + show_markers: false, + line_interpolation: 'linear', + x_axis_label: 'Year Published', + bottom_margin: 'auto', + x_ticks_layout: 'auto', + x_axis_format: 'smart_date', + x_axis_showminmax: true, + y_axis_label: '# of Games Published', + left_margin: 'auto', + y_axis_showminmax: true, + y_axis_format: 'SMART_NUMBER', + y_axis_bounds: [null, null], + rolling_type: 'None', + comparison_type: 'values', + annotation_layers: [], + label_colors: { + '0': '#1FA8C9', + '1': '#454E7C', + '2600': '#666666', + '3DO': '#B2B2B2', + '3DS': '#D1C6BC', + Action: '#1FA8C9', + Adventure: '#454E7C', + DC: '#A38F79', + DS: '#8FD3E4', + Europe: '#5AC189', + Fighting: '#5AC189', + GB: '#FDE380', + GBA: '#ACE1C4', + GC: '#5AC189', + GEN: '#3CCCCB', + GG: '#EFA1AA', + Japan: '#FF7F44', + 'Microsoft Game Studios': '#D1C6BC', + Misc: '#FF7F44', + N64: '#1FA8C9', + NES: '#9EE5E5', + NG: '#A1A6BD', + Nintendo: '#D3B3DA', + 'North America': '#666666', + Other: '#E04355', + PC: '#EFA1AA', + PCFX: '#FDE380', + PS: '#A1A6BD', + PS2: '#FCC700', + PS3: '#3CCCCB', + PS4: '#B2B2B2', + PSP: '#FEC0A1', + PSV: '#FCC700', + Platform: '#666666', + Puzzle: '#E04355', + Racing: '#FCC700', + 'Role-Playing': '#A868B7', + SAT: '#A868B7', + SCD: '#8FD3E4', + SNES: '#454E7C', + Shooter: '#3CCCCB', + Simulation: '#A38F79', + Sports: '#8FD3E4', + Strategy: '#A1A6BD', + TG16: '#FEC0A1', + 'Take-Two Interactive': '#9EE5E5', + WS: '#ACE1C4', + Wii: '#A38F79', + WiiU: '#E04355', + X360: '#A868B7', + XB: '#D3B3DA', + XOne: '#FF7F44', + }, + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + }, + }, + '103': { + id: 103, + chartAlert: null, + chartStatus: 'rendered', + chartStackTrace: null, + chartUpdateEndTime: 1673047001527, + chartUpdateStartTime: 1673046994566, + latestQueryFormData: { + datasource: '20__table', + viz_type: 'area', + slice_id: 103, + url_params: { + preselect_filters: + '{"1389": {"platform": ["PS", "PS2", "PS3", "PS4"], "genre": null, "__time_range": "No filter"}}', + }, + granularity_sqla: 'year', + time_grain_sqla: null, + time_range: 'No filter', + metrics: [ + { + aggregate: 'SUM', + column: { + column_name: 'global_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 887, + is_dttm: false, + optionName: '_col_Global_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: false, + isNew: false, + label: 'SUM(Global_Sales)', + optionName: 'metric_ufl75addr8c_oqqhdumirpn', + sqlExpression: null, + }, + ], + adhoc_filters: [], + groupby: ['platform'], + order_desc: true, + contribution: false, + row_limit: null, + show_brush: 'auto', + show_legend: false, + line_interpolation: 'linear', + stacked_style: 'stream', + color_scheme: 'supersetColors', + rich_tooltip: true, + x_axis_label: 'Year Published', + bottom_margin: 'auto', + x_ticks_layout: 'auto', + x_axis_format: 'smart_date', + x_axis_showminmax: true, + y_axis_format: 'SMART_NUMBER', + y_axis_bounds: [null, null], + rolling_type: 'None', + comparison_type: 'values', + annotation_layers: [], + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + shared_label_colors: {}, + extra_filters: [ + { + col: '__time_range', + op: '==', + val: 'No filter', + }, + ], + extra_form_data: {}, + dashboardId: 9, + }, + sliceFormData: null, + queryController: {}, + queriesResponse: [ + { + cache_key: '20775ba73440f8cab2208ae3f422402f', + cached_dttm: null, + cache_timeout: 86400, + errors: [], + form_data: { + datasource: '20__table', + viz_type: 'area', + slice_id: 103, + url_params: { + preselect_filters: + '{"1389": {"platform": ["PS", "PS2", "PS3", "PS4"], "genre": null, "__time_range": "No filter"}}', + }, + granularity_sqla: 'year', + time_grain_sqla: null, + time_range: 'No filter', + metrics: [ + { + aggregate: 'SUM', + column: { + column_name: 'global_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 887, + is_dttm: false, + optionName: '_col_Global_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: false, + isNew: false, + label: 'SUM(Global_Sales)', + optionName: 'metric_ufl75addr8c_oqqhdumirpn', + sqlExpression: null, + }, + ], + adhoc_filters: [], + groupby: ['platform'], + order_desc: true, + contribution: false, + row_limit: null, + show_brush: 'auto', + show_legend: false, + line_interpolation: 'linear', + stacked_style: 'stream', + color_scheme: 'supersetColors', + rich_tooltip: true, + x_axis_label: 'Year Published', + bottom_margin: 'auto', + x_ticks_layout: 'auto', + x_axis_format: 'smart_date', + x_axis_showminmax: true, + y_axis_format: 'SMART_NUMBER', + y_axis_bounds: [null, null], + rolling_type: 'None', + comparison_type: 'values', + annotation_layers: [], + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + shared_label_colors: {}, + dashboardId: 9, + applied_time_extras: {}, + where: '', + having: '', + having_filters: [], + filters: [], + }, + is_cached: false, + query: + 'SELECT year AS __timestamp,\n platform AS platform,\n sum(global_sales) AS "SUM(Global_Sales)"\nFROM main.video_game_sales\nGROUP BY platform,\n year\nORDER BY "SUM(Global_Sales)" DESC\nLIMIT 50000\nOFFSET 0', + from_dttm: null, + to_dttm: null, + status: 'success', + stacktrace: null, + rowcount: 255, + colnames: ['__timestamp', 'platform', 'SUM(Global_Sales)'], + coltypes: [2, 1, 0], + data: [ + { + key: ['PS2'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 0, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 0, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 0, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 0, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 0, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 0, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 0, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 0, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 0, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 0, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 0, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 0, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 0, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 0, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 0, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 0, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 0, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 0, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 0, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 0, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 0, + display: { + y: 0, + y0: 365.16480818468705, + }, + series: 0, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 0, + display: { + y: 0, + y0: 355.9463874586553, + }, + series: 0, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 0, + display: { + y: 0, + y0: 375.71003766873946, + }, + series: 0, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 0, + display: { + y: 0, + y0: 377.41055311023564, + }, + series: 0, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 0, + display: { + y: 0, + y0: 383.37655475227183, + }, + series: 0, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 0, + display: { + y: 0, + y0: 381.6416336309462, + }, + series: 0, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 0, + display: { + y: 0, + y0: 436.22008078133535, + }, + series: 0, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 0, + display: { + y: 0, + y0: 421.48302062609594, + }, + series: 0, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 0, + display: { + y: 0, + y0: 457.6032684133616, + }, + series: 0, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 0, + display: { + y: 0, + y0: 464.9110839106354, + }, + series: 0, + }, + { + x: 946684800000, + y: 39.11000000000001, + index: 20, + seriesIndex: 0, + display: { + y: 39.11000000000001, + y0: 422.2363863019829, + }, + series: 0, + }, + { + x: 978307200000, + y: 166.43000000000006, + index: 21, + seriesIndex: 0, + display: { + y: 166.43000000000006, + y0: 375.71659853838435, + }, + series: 0, + }, + { + x: 1009843200000, + y: 205.40000000000006, + index: 22, + seriesIndex: 0, + display: { + y: 205.40000000000006, + y0: 366.939571207276, + }, + series: 0, + }, + { + x: 1041379200000, + y: 184.28999999999996, + index: 23, + seriesIndex: 0, + display: { + y: 184.28999999999996, + y0: 366.3006269568918, + }, + series: 0, + }, + { + x: 1072915200000, + y: 211.77999999999992, + index: 24, + seriesIndex: 0, + display: { + y: 211.77999999999992, + y0: 358.5965490670251, + }, + series: 0, + }, + { + x: 1104537600000, + y: 160.65000000000012, + index: 25, + seriesIndex: 0, + display: { + y: 160.65000000000012, + y0: 367.8171603424089, + }, + series: 0, + }, + { + x: 1136073600000, + y: 103.41999999999999, + index: 26, + seriesIndex: 0, + display: { + y: 103.41999999999999, + y0: 332.2283968117778, + }, + series: 0, + }, + { + x: 1167609600000, + y: 76, + index: 27, + seriesIndex: 0, + display: { + y: 76, + y0: 334.2380715127416, + }, + series: 0, + }, + { + x: 1199145600000, + y: 53.830000000000034, + index: 28, + seriesIndex: 0, + display: { + y: 53.830000000000034, + y0: 331.2200000000006, + }, + series: 0, + }, + { + x: 1230768000000, + y: 26.45, + index: 29, + seriesIndex: 0, + display: { + y: 26.45, + y0: 323.57657904990293, + }, + series: 0, + }, + { + x: 1262304000000, + y: 5.629999999999995, + index: 30, + seriesIndex: 0, + display: { + y: 5.629999999999995, + y0: 353.63872327506743, + }, + series: 0, + }, + { + x: 1293840000000, + y: 0.47, + index: 31, + seriesIndex: 0, + display: { + y: 0.47, + y0: 346.7617397094945, + }, + series: 0, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 0, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 0, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 0, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 0, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 0, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 0, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 0, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 0, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 0, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 0, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 0, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 0, + }, + ], + }, + { + key: ['X360'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 1, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 1, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 1, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 1, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 1, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 1, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 1, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 1, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 1, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 1, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 1, + display: { + y: 0, + y0: 303.54220029343605, + }, + series: 1, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 1, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 1, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 1, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 1, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 1, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 1, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 1, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 1, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 1, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 1, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 1, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 1, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 1, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 1, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 1, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 1, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 1, + display: { + y: 0, + y0: 317.05655475227184, + }, + series: 1, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 1, + display: { + y: 0, + y0: 297.7616336309462, + }, + series: 1, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 1, + display: { + y: 0, + y0: 247.66008078133538, + }, + series: 1, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 1, + display: { + y: 0, + y0: 231.76302062609608, + }, + series: 1, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 1, + display: { + y: 0, + y0: 204.41326841336158, + }, + series: 1, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 1, + display: { + y: 0, + y0: 218.39108391063536, + }, + series: 1, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 1, + display: { + y: 0, + y0: 264.466386301983, + }, + series: 1, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 1, + display: { + y: 0, + y0: 216.18659853838435, + }, + series: 1, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 1, + display: { + y: 0, + y0: 185.4195712072759, + }, + series: 1, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 1, + display: { + y: 0, + y0: 201.70062695689174, + }, + series: 1, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 1, + display: { + y: 0, + y0: 161.52654906702506, + }, + series: 1, + }, + { + x: 1104537600000, + y: 8.319999999999999, + index: 25, + seriesIndex: 1, + display: { + y: 8.319999999999999, + y0: 72.99716034240856, + }, + series: 1, + }, + { + x: 1136073600000, + y: 51.879999999999995, + index: 26, + seriesIndex: 1, + display: { + y: 51.879999999999995, + y0: 76.55839681177778, + }, + series: 1, + }, + { + x: 1167609600000, + y: 95.83999999999993, + index: 27, + seriesIndex: 1, + display: { + y: 95.83999999999993, + y0: 37.28807151274146, + }, + series: 1, + }, + { + x: 1199145600000, + y: 135.76000000000002, + index: 28, + seriesIndex: 1, + display: { + y: 135.76000000000002, + y0: 12.669999999999975, + }, + series: 1, + }, + { + x: 1230768000000, + y: 120.85000000000001, + index: 29, + seriesIndex: 1, + display: { + y: 120.85000000000001, + y0: 42.666579049902865, + }, + series: 1, + }, + { + x: 1262304000000, + y: 171.05000000000004, + index: 30, + seriesIndex: 1, + display: { + y: 171.05000000000004, + y0: 59.49872327506736, + }, + series: 1, + }, + { + x: 1293840000000, + y: 145.1200000000002, + index: 31, + seriesIndex: 1, + display: { + y: 145.1200000000002, + y0: 155.9517397094943, + }, + series: 1, + }, + { + x: 1325376000000, + y: 100.87999999999992, + index: 32, + seriesIndex: 1, + display: { + y: 100.87999999999992, + y0: 234.96331147601265, + }, + series: 1, + }, + { + x: 1356998400000, + y: 89.61000000000001, + index: 33, + seriesIndex: 1, + display: { + y: 89.61000000000001, + y0: 252.25434975261473, + }, + series: 1, + }, + { + x: 1388534400000, + y: 36.41999999999998, + index: 34, + seriesIndex: 1, + display: { + y: 36.41999999999998, + y0: 319.4614727314013, + }, + series: 1, + }, + { + x: 1420070400000, + y: 13.049999999999999, + index: 35, + seriesIndex: 1, + display: { + y: 13.049999999999999, + y0: 339.81176221105636, + }, + series: 1, + }, + { + x: 1451606400000, + y: 0.8300000000000001, + index: 36, + seriesIndex: 1, + display: { + y: 0.8300000000000001, + y0: 322.48515851727376, + }, + series: 1, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 1, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 1, + }, + ], + }, + { + key: ['PS3'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 2, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 2, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 2, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 2, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 2, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 2, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 2, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 2, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 2, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 2, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 2, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 2, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 2, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 2, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 2, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 2, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 2, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 2, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 2, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 2, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 2, + display: { + y: 0, + y0: 365.16480818468705, + }, + series: 2, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 2, + display: { + y: 0, + y0: 355.9463874586553, + }, + series: 2, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 2, + display: { + y: 0, + y0: 375.71003766873946, + }, + series: 2, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 2, + display: { + y: 0, + y0: 377.41055311023564, + }, + series: 2, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 2, + display: { + y: 0, + y0: 383.37655475227183, + }, + series: 2, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 2, + display: { + y: 0, + y0: 381.6416336309462, + }, + series: 2, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 2, + display: { + y: 0, + y0: 436.22008078133535, + }, + series: 2, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 2, + display: { + y: 0, + y0: 421.48302062609594, + }, + series: 2, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 2, + display: { + y: 0, + y0: 457.6032684133616, + }, + series: 2, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 2, + display: { + y: 0, + y0: 464.9110839106354, + }, + series: 2, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 2, + display: { + y: 0, + y0: 461.34638630198293, + }, + series: 2, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 2, + display: { + y: 0, + y0: 542.1465985383844, + }, + series: 2, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 2, + display: { + y: 0, + y0: 572.3395712072761, + }, + series: 2, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 2, + display: { + y: 0, + y0: 550.5906269568918, + }, + series: 2, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 2, + display: { + y: 0, + y0: 570.376549067025, + }, + series: 2, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 2, + display: { + y: 0, + y0: 528.467160342409, + }, + series: 2, + }, + { + x: 1136073600000, + y: 21.070000000000004, + index: 26, + seriesIndex: 2, + display: { + y: 21.070000000000004, + y0: 573.5583968117778, + }, + series: 2, + }, + { + x: 1167609600000, + y: 73.81000000000006, + index: 27, + seriesIndex: 2, + display: { + y: 73.81000000000006, + y0: 565.2080715127415, + }, + series: 2, + }, + { + x: 1199145600000, + y: 119.69000000000001, + index: 28, + seriesIndex: 2, + display: { + y: 119.69000000000001, + y0: 559.2100000000006, + }, + series: 2, + }, + { + x: 1230768000000, + y: 132.33999999999997, + index: 29, + seriesIndex: 2, + display: { + y: 132.33999999999997, + y0: 560.4665790499031, + }, + series: 2, + }, + { + x: 1262304000000, + y: 144.42000000000007, + index: 30, + seriesIndex: 2, + display: { + y: 144.42000000000007, + y0: 491.06872327506755, + }, + series: 2, + }, + { + x: 1293840000000, + y: 159.3700000000001, + index: 31, + seriesIndex: 2, + display: { + y: 159.3700000000001, + y0: 409.6417397094946, + }, + series: 2, + }, + { + x: 1325376000000, + y: 109.49000000000002, + index: 32, + seriesIndex: 2, + display: { + y: 109.49000000000002, + y0: 377.9733114760125, + }, + series: 2, + }, + { + x: 1356998400000, + y: 117.38999999999994, + index: 33, + seriesIndex: 2, + display: { + y: 117.38999999999994, + y0: 356.37434975261476, + }, + series: 2, + }, + { + x: 1388534400000, + y: 50.96000000000002, + index: 34, + seriesIndex: 2, + display: { + y: 50.96000000000002, + y0: 360.5814727314012, + }, + series: 2, + }, + { + x: 1420070400000, + y: 18.220000000000002, + index: 35, + seriesIndex: 2, + display: { + y: 18.220000000000002, + y0: 354.5317622110564, + }, + series: 2, + }, + { + x: 1451606400000, + y: 2.59, + index: 36, + seriesIndex: 2, + display: { + y: 2.59, + y0: 323.31515851727374, + }, + series: 2, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 2, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 2, + }, + ], + }, + { + key: ['Wii'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 3, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 3, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 3, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 3, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 3, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 3, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 3, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 3, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 3, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 3, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 3, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 3, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 3, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 3, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 3, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 3, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 3, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 3, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 3, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 3, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 3, + display: { + y: 0, + y0: 365.16480818468705, + }, + series: 3, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 3, + display: { + y: 0, + y0: 355.9463874586553, + }, + series: 3, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 3, + display: { + y: 0, + y0: 375.71003766873946, + }, + series: 3, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 3, + display: { + y: 0, + y0: 377.41055311023564, + }, + series: 3, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 3, + display: { + y: 0, + y0: 383.37655475227183, + }, + series: 3, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 3, + display: { + y: 0, + y0: 381.6416336309462, + }, + series: 3, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 3, + display: { + y: 0, + y0: 436.22008078133535, + }, + series: 3, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 3, + display: { + y: 0, + y0: 421.48302062609594, + }, + series: 3, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 3, + display: { + y: 0, + y0: 457.6032684133616, + }, + series: 3, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 3, + display: { + y: 0, + y0: 464.9110839106354, + }, + series: 3, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 3, + display: { + y: 0, + y0: 461.34638630198293, + }, + series: 3, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 3, + display: { + y: 0, + y0: 542.1465985383844, + }, + series: 3, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 3, + display: { + y: 0, + y0: 572.3395712072761, + }, + series: 3, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 3, + display: { + y: 0, + y0: 550.5906269568918, + }, + series: 3, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 3, + display: { + y: 0, + y0: 570.376549067025, + }, + series: 3, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 3, + display: { + y: 0, + y0: 528.467160342409, + }, + series: 3, + }, + { + x: 1136073600000, + y: 137.91000000000003, + index: 26, + seriesIndex: 3, + display: { + y: 137.91000000000003, + y0: 435.64839681177784, + }, + series: 3, + }, + { + x: 1167609600000, + y: 154.96999999999997, + index: 27, + seriesIndex: 3, + display: { + y: 154.96999999999997, + y0: 410.2380715127416, + }, + series: 3, + }, + { + x: 1199145600000, + y: 174.16, + index: 28, + seriesIndex: 3, + display: { + y: 174.16, + y0: 385.05000000000064, + }, + series: 3, + }, + { + x: 1230768000000, + y: 210.4400000000002, + index: 29, + seriesIndex: 3, + display: { + y: 210.4400000000002, + y0: 350.0265790499029, + }, + series: 3, + }, + { + x: 1262304000000, + y: 131.8000000000001, + index: 30, + seriesIndex: 3, + display: { + y: 131.8000000000001, + y0: 359.26872327506743, + }, + series: 3, + }, + { + x: 1293840000000, + y: 62.41000000000001, + index: 31, + seriesIndex: 3, + display: { + y: 62.41000000000001, + y0: 347.23173970949455, + }, + series: 3, + }, + { + x: 1325376000000, + y: 22.770000000000003, + index: 32, + seriesIndex: 3, + display: { + y: 22.770000000000003, + y0: 355.2033114760125, + }, + series: 3, + }, + { + x: 1356998400000, + y: 9.359999999999998, + index: 33, + seriesIndex: 3, + display: { + y: 9.359999999999998, + y0: 347.01434975261475, + }, + series: 3, + }, + { + x: 1388534400000, + y: 4.439999999999999, + index: 34, + seriesIndex: 3, + display: { + y: 4.439999999999999, + y0: 356.1414727314012, + }, + series: 3, + }, + { + x: 1420070400000, + y: 1.55, + index: 35, + seriesIndex: 3, + display: { + y: 1.55, + y0: 352.9817622110564, + }, + series: 3, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 3, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 3, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 3, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 3, + }, + ], + }, + { + key: ['DS'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 4, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 4, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 4, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 4, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 4, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 4, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 4, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 4, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 4, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 4, + }, + { + x: 473385600000, + y: 0.02, + index: 5, + seriesIndex: 4, + display: { + y: 0.02, + y0: 303.54220029343605, + }, + series: 4, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 4, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 4, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 4, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 4, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 4, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 4, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 4, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 4, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 4, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 4, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 4, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 4, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 4, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 4, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 4, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 4, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 4, + display: { + y: 0, + y0: 317.05655475227184, + }, + series: 4, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 4, + display: { + y: 0, + y0: 297.7616336309462, + }, + series: 4, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 4, + display: { + y: 0, + y0: 247.66008078133538, + }, + series: 4, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 4, + display: { + y: 0, + y0: 231.76302062609608, + }, + series: 4, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 4, + display: { + y: 0, + y0: 204.41326841336158, + }, + series: 4, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 4, + display: { + y: 0, + y0: 218.39108391063536, + }, + series: 4, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 4, + display: { + y: 0, + y0: 264.466386301983, + }, + series: 4, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 4, + display: { + y: 0, + y0: 216.18659853838435, + }, + series: 4, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 4, + display: { + y: 0, + y0: 185.4195712072759, + }, + series: 4, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 4, + display: { + y: 0, + y0: 201.70062695689174, + }, + series: 4, + }, + { + x: 1072915200000, + y: 17.459999999999994, + index: 24, + seriesIndex: 4, + display: { + y: 17.459999999999994, + y0: 161.52654906702506, + }, + series: 4, + }, + { + x: 1104537600000, + y: 131.4000000000002, + index: 25, + seriesIndex: 4, + display: { + y: 131.4000000000002, + y0: 81.31716034240856, + }, + series: 4, + }, + { + x: 1136073600000, + y: 121.14999999999998, + index: 26, + seriesIndex: 4, + display: { + y: 121.14999999999998, + y0: 128.43839681177778, + }, + series: 4, + }, + { + x: 1167609600000, + y: 149.3600000000002, + index: 27, + seriesIndex: 4, + display: { + y: 149.3600000000002, + y0: 133.1280715127414, + }, + series: 4, + }, + { + x: 1199145600000, + y: 147.89000000000047, + index: 28, + seriesIndex: 4, + display: { + y: 147.89000000000047, + y0: 148.43, + }, + series: 4, + }, + { + x: 1230768000000, + y: 121.99000000000001, + index: 29, + seriesIndex: 4, + display: { + y: 121.99000000000001, + y0: 163.51657904990287, + }, + series: 4, + }, + { + x: 1262304000000, + y: 87.97999999999995, + index: 30, + seriesIndex: 4, + display: { + y: 87.97999999999995, + y0: 230.5487232750674, + }, + series: 4, + }, + { + x: 1293840000000, + y: 27.799999999999994, + index: 31, + seriesIndex: 4, + display: { + y: 27.799999999999994, + y0: 301.0717397094945, + }, + series: 4, + }, + { + x: 1325376000000, + y: 11.639999999999993, + index: 32, + seriesIndex: 4, + display: { + y: 11.639999999999993, + y0: 335.84331147601256, + }, + series: 4, + }, + { + x: 1356998400000, + y: 1.96, + index: 33, + seriesIndex: 4, + display: { + y: 1.96, + y0: 341.86434975261477, + }, + series: 4, + }, + { + x: 1388534400000, + y: 0.02, + index: 34, + seriesIndex: 4, + display: { + y: 0.02, + y0: 355.88147273140123, + }, + series: 4, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 4, + display: { + y: 0, + y0: 352.8617622110564, + }, + series: 4, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 4, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 4, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 4, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 4, + }, + ], + }, + { + key: ['PS'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 5, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 5, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 5, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 5, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 5, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 5, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 5, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 5, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 5, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 5, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 5, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 5, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 5, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 5, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 5, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 5, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 5, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 5, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 5, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 5, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 5, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 5, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 5, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 5, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 5, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 5, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 5, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 5, + }, + { + x: 757382400000, + y: 6.020000000000001, + index: 14, + seriesIndex: 5, + display: { + y: 6.020000000000001, + y0: 317.05655475227184, + }, + series: 5, + }, + { + x: 788918400000, + y: 35.92000000000002, + index: 15, + seriesIndex: 5, + display: { + y: 35.92000000000002, + y0: 297.7616336309462, + }, + series: 5, + }, + { + x: 820454400000, + y: 94.67999999999999, + index: 16, + seriesIndex: 5, + display: { + y: 94.67999999999999, + y0: 247.66008078133538, + }, + series: 5, + }, + { + x: 852076800000, + y: 136.0799999999999, + index: 17, + seriesIndex: 5, + display: { + y: 136.0799999999999, + y0: 231.76302062609608, + }, + series: 5, + }, + { + x: 883612800000, + y: 169.58, + index: 18, + seriesIndex: 5, + display: { + y: 169.58, + y0: 204.41326841336158, + }, + series: 5, + }, + { + x: 915148800000, + y: 144.5700000000001, + index: 19, + seriesIndex: 5, + display: { + y: 144.5700000000001, + y0: 218.39108391063536, + }, + series: 5, + }, + { + x: 946684800000, + y: 96.27999999999993, + index: 20, + seriesIndex: 5, + display: { + y: 96.27999999999993, + y0: 265.516386301983, + }, + series: 5, + }, + { + x: 978307200000, + y: 35.520000000000024, + index: 21, + seriesIndex: 5, + display: { + y: 35.520000000000024, + y0: 300.04659853838433, + }, + series: 5, + }, + { + x: 1009843200000, + y: 6.689999999999998, + index: 22, + seriesIndex: 5, + display: { + y: 6.689999999999998, + y0: 307.949571207276, + }, + series: 5, + }, + { + x: 1041379200000, + y: 2.05, + index: 23, + seriesIndex: 5, + display: { + y: 2.05, + y0: 313.59062695689175, + }, + series: 5, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 5, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 5, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 5, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 5, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 5, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 5, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 5, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 5, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 5, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 5, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 5, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 5, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 5, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 5, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 5, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 5, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 5, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 5, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 5, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 5, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 5, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 5, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 5, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 5, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 5, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 5, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 5, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 5, + }, + ], + }, + { + key: ['GBA'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 6, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 6, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 6, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 6, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 6, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 6, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 6, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 6, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 6, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 6, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 6, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 6, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 6, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 6, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 6, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 6, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 6, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 6, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 6, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 6, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 6, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 6, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 6, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 6, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 6, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 6, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 6, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 6, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 6, + display: { + y: 0, + y0: 317.05655475227184, + }, + series: 6, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 6, + display: { + y: 0, + y0: 297.7616336309462, + }, + series: 6, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 6, + display: { + y: 0, + y0: 247.66008078133538, + }, + series: 6, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 6, + display: { + y: 0, + y0: 231.76302062609608, + }, + series: 6, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 6, + display: { + y: 0, + y0: 204.41326841336158, + }, + series: 6, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 6, + display: { + y: 0, + y0: 218.39108391063536, + }, + series: 6, + }, + { + x: 946684800000, + y: 0.06, + index: 20, + seriesIndex: 6, + display: { + y: 0.06, + y0: 265.456386301983, + }, + series: 6, + }, + { + x: 978307200000, + y: 61.62000000000001, + index: 21, + seriesIndex: 6, + display: { + y: 61.62000000000001, + y0: 238.42659853838433, + }, + series: 6, + }, + { + x: 1009843200000, + y: 74.38, + index: 22, + seriesIndex: 6, + display: { + y: 74.38, + y0: 233.56957120727597, + }, + series: 6, + }, + { + x: 1041379200000, + y: 56.72999999999996, + index: 23, + seriesIndex: 6, + display: { + y: 56.72999999999996, + y0: 256.8606269568918, + }, + series: 6, + }, + { + x: 1072915200000, + y: 78.09, + index: 24, + seriesIndex: 6, + display: { + y: 78.09, + y0: 251.61654906702506, + }, + series: 6, + }, + { + x: 1104537600000, + y: 33.90000000000001, + index: 25, + seriesIndex: 6, + display: { + y: 33.90000000000001, + y0: 306.1171603424089, + }, + series: 6, + }, + { + x: 1136073600000, + y: 5.35, + index: 26, + seriesIndex: 6, + display: { + y: 5.35, + y0: 315.5883968117778, + }, + series: 6, + }, + { + x: 1167609600000, + y: 3.4299999999999997, + index: 27, + seriesIndex: 6, + display: { + y: 3.4299999999999997, + y0: 330.51807151274164, + }, + series: 6, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 6, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 6, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 6, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 6, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 6, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 6, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 6, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 6, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 6, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 6, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 6, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 6, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 6, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 6, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 6, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 6, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 6, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 6, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 6, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 6, + }, + ], + }, + { + key: ['PSP'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 7, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 7, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 7, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 7, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 7, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 7, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 7, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 7, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 7, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 7, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 7, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 7, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 7, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 7, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 7, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 7, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 7, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 7, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 7, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 7, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 7, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 7, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 7, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 7, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 7, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 7, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 7, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 7, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 7, + display: { + y: 0, + y0: 317.05655475227184, + }, + series: 7, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 7, + display: { + y: 0, + y0: 297.7616336309462, + }, + series: 7, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 7, + display: { + y: 0, + y0: 247.66008078133538, + }, + series: 7, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 7, + display: { + y: 0, + y0: 231.76302062609608, + }, + series: 7, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 7, + display: { + y: 0, + y0: 204.41326841336158, + }, + series: 7, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 7, + display: { + y: 0, + y0: 218.39108391063536, + }, + series: 7, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 7, + display: { + y: 0, + y0: 264.466386301983, + }, + series: 7, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 7, + display: { + y: 0, + y0: 216.18659853838435, + }, + series: 7, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 7, + display: { + y: 0, + y0: 185.4195712072759, + }, + series: 7, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 7, + display: { + y: 0, + y0: 201.70062695689174, + }, + series: 7, + }, + { + x: 1072915200000, + y: 7.13, + index: 24, + seriesIndex: 7, + display: { + y: 7.13, + y0: 178.98654906702507, + }, + series: 7, + }, + { + x: 1104537600000, + y: 44.23000000000001, + index: 25, + seriesIndex: 7, + display: { + y: 44.23000000000001, + y0: 212.71716034240876, + }, + series: 7, + }, + { + x: 1136073600000, + y: 55.850000000000044, + index: 26, + seriesIndex: 7, + display: { + y: 55.850000000000044, + y0: 249.58839681177776, + }, + series: 7, + }, + { + x: 1167609600000, + y: 47.48000000000004, + index: 27, + seriesIndex: 7, + display: { + y: 47.48000000000004, + y0: 282.4880715127416, + }, + series: 7, + }, + { + x: 1199145600000, + y: 34.680000000000035, + index: 28, + seriesIndex: 7, + display: { + y: 34.680000000000035, + y0: 296.3200000000005, + }, + series: 7, + }, + { + x: 1230768000000, + y: 38.070000000000036, + index: 29, + seriesIndex: 7, + display: { + y: 38.070000000000036, + y0: 285.5065790499029, + }, + series: 7, + }, + { + x: 1262304000000, + y: 35.11000000000007, + index: 30, + seriesIndex: 7, + display: { + y: 35.11000000000007, + y0: 318.52872327506736, + }, + series: 7, + }, + { + x: 1293840000000, + y: 17.89000000000001, + index: 31, + seriesIndex: 7, + display: { + y: 17.89000000000001, + y0: 328.87173970949453, + }, + series: 7, + }, + { + x: 1325376000000, + y: 7.71999999999999, + index: 32, + seriesIndex: 7, + display: { + y: 7.71999999999999, + y0: 347.48331147601255, + }, + series: 7, + }, + { + x: 1356998400000, + y: 3.189999999999996, + index: 33, + seriesIndex: 7, + display: { + y: 3.189999999999996, + y0: 343.82434975261475, + }, + series: 7, + }, + { + x: 1388534400000, + y: 0.24000000000000005, + index: 34, + seriesIndex: 7, + display: { + y: 0.24000000000000005, + y0: 355.9014727314012, + }, + series: 7, + }, + { + x: 1420070400000, + y: 0.12000000000000001, + index: 35, + seriesIndex: 7, + display: { + y: 0.12000000000000001, + y0: 352.8617622110564, + }, + series: 7, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 7, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 7, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 7, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 7, + }, + ], + }, + { + key: ['PS4'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 8, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 8, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 8, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 8, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 8, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 8, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 8, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 8, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 8, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 8, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 8, + display: { + y: 0, + y0: 303.5122002934361, + }, + series: 8, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 8, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 8, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 8, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 8, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 8, + display: { + y: 0, + y0: 305.7350172280039, + }, + series: 8, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 8, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 8, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 8, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 8, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 8, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 8, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 8, + display: { + y: 0, + y0: 299.5500376687394, + }, + series: 8, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 8, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 8, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 8, + display: { + y: 0, + y0: 304.2065547522718, + }, + series: 8, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 8, + display: { + y: 0, + y0: 293.5316336309462, + }, + series: 8, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 8, + display: { + y: 0, + y0: 237.07008078133538, + }, + series: 8, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 8, + display: { + y: 0, + y0: 220.5030206260961, + }, + series: 8, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 8, + display: { + y: 0, + y0: 201.13326841336158, + }, + series: 8, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 8, + display: { + y: 0, + y0: 213.64108391063536, + }, + series: 8, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 8, + display: { + y: 0, + y0: 259.786386301983, + }, + series: 8, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 8, + display: { + y: 0, + y0: 210.67659853838435, + }, + series: 8, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 8, + display: { + y: 0, + y0: 176.8195712072759, + }, + series: 8, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 8, + display: { + y: 0, + y0: 192.74062695689176, + }, + series: 8, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 8, + display: { + y: 0, + y0: 151.06654906702508, + }, + series: 8, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 8, + display: { + y: 0, + y0: 68.52716034240856, + }, + series: 8, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 8, + display: { + y: 0, + y0: 73.58839681177778, + }, + series: 8, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 8, + display: { + y: 0, + y0: 27.888071512741476, + }, + series: 8, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 8, + display: { + y: 0, + y0: 0, + }, + series: 8, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 8, + display: { + y: 0, + y0: 25.506579049902825, + }, + series: 8, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 8, + display: { + y: 0, + y0: 35.038723275067355, + }, + series: 8, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 8, + display: { + y: 0, + y0: 115.55173970949426, + }, + series: 8, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 8, + display: { + y: 0, + y0: 175.06331147601264, + }, + series: 8, + }, + { + x: 1356998400000, + y: 24.760000000000005, + index: 33, + seriesIndex: 8, + display: { + y: 24.760000000000005, + y0: 180.13434975261472, + }, + series: 8, + }, + { + x: 1388534400000, + y: 98.76000000000003, + index: 34, + seriesIndex: 8, + display: { + y: 98.76000000000003, + y0: 170.06147273140124, + }, + series: 8, + }, + { + x: 1420070400000, + y: 115.29999999999997, + index: 35, + seriesIndex: 8, + display: { + y: 115.29999999999997, + y0: 192.96176221105642, + }, + series: 8, + }, + { + x: 1451606400000, + y: 39.25000000000002, + index: 36, + seriesIndex: 8, + display: { + y: 39.25000000000002, + y0: 273.94515851727374, + }, + series: 8, + }, + { + x: 1483228800000, + y: 0.03, + index: 37, + seriesIndex: 8, + display: { + y: 0.03, + y0: 293.55515851727375, + }, + series: 8, + }, + ], + }, + { + key: ['PC'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 9, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 9, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 9, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 9, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 9, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 9, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 9, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 9, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 9, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 9, + }, + { + x: 473385600000, + y: 0.03, + index: 5, + seriesIndex: 9, + display: { + y: 0.03, + y0: 303.5122002934361, + }, + series: 9, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 9, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 9, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 9, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 9, + }, + { + x: 567993600000, + y: 0.03, + index: 8, + seriesIndex: 9, + display: { + y: 0.03, + y0: 305.7350172280039, + }, + series: 9, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 9, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 9, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 9, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 9, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 9, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 9, + }, + { + x: 694224000000, + y: 3.0199999999999996, + index: 12, + seriesIndex: 9, + display: { + y: 3.0199999999999996, + y0: 299.5500376687394, + }, + series: 9, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 9, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 9, + }, + { + x: 757382400000, + y: 12.85, + index: 14, + seriesIndex: 9, + display: { + y: 12.85, + y0: 304.2065547522718, + }, + series: 9, + }, + { + x: 788918400000, + y: 4.2299999999999995, + index: 15, + seriesIndex: 9, + display: { + y: 4.2299999999999995, + y0: 293.5316336309462, + }, + series: 9, + }, + { + x: 820454400000, + y: 10.59, + index: 16, + seriesIndex: 9, + display: { + y: 10.59, + y0: 237.07008078133538, + }, + series: 9, + }, + { + x: 852076800000, + y: 11.260000000000002, + index: 17, + seriesIndex: 9, + display: { + y: 11.260000000000002, + y0: 220.5030206260961, + }, + series: 9, + }, + { + x: 883612800000, + y: 3.2800000000000002, + index: 18, + seriesIndex: 9, + display: { + y: 3.2800000000000002, + y0: 201.13326841336158, + }, + series: 9, + }, + { + x: 915148800000, + y: 4.749999999999999, + index: 19, + seriesIndex: 9, + display: { + y: 4.749999999999999, + y0: 213.64108391063536, + }, + series: 9, + }, + { + x: 946684800000, + y: 4.679999999999999, + index: 20, + seriesIndex: 9, + display: { + y: 4.679999999999999, + y0: 259.786386301983, + }, + series: 9, + }, + { + x: 978307200000, + y: 5.51, + index: 21, + seriesIndex: 9, + display: { + y: 5.51, + y0: 210.67659853838435, + }, + series: 9, + }, + { + x: 1009843200000, + y: 8.599999999999996, + index: 22, + seriesIndex: 9, + display: { + y: 8.599999999999996, + y0: 176.8195712072759, + }, + series: 9, + }, + { + x: 1041379200000, + y: 8.959999999999988, + index: 23, + seriesIndex: 9, + display: { + y: 8.959999999999988, + y0: 192.74062695689176, + }, + series: 9, + }, + { + x: 1072915200000, + y: 10.459999999999992, + index: 24, + seriesIndex: 9, + display: { + y: 10.459999999999992, + y0: 151.06654906702508, + }, + series: 9, + }, + { + x: 1104537600000, + y: 4.469999999999995, + index: 25, + seriesIndex: 9, + display: { + y: 4.469999999999995, + y0: 68.52716034240856, + }, + series: 9, + }, + { + x: 1136073600000, + y: 2.969999999999998, + index: 26, + seriesIndex: 9, + display: { + y: 2.969999999999998, + y0: 73.58839681177778, + }, + series: 9, + }, + { + x: 1167609600000, + y: 9.399999999999984, + index: 27, + seriesIndex: 9, + display: { + y: 9.399999999999984, + y0: 27.888071512741476, + }, + series: 9, + }, + { + x: 1199145600000, + y: 12.669999999999975, + index: 28, + seriesIndex: 9, + display: { + y: 12.669999999999975, + y0: 0, + }, + series: 9, + }, + { + x: 1230768000000, + y: 17.160000000000043, + index: 29, + seriesIndex: 9, + display: { + y: 17.160000000000043, + y0: 25.506579049902825, + }, + series: 9, + }, + { + x: 1262304000000, + y: 24.460000000000004, + index: 30, + seriesIndex: 9, + display: { + y: 24.460000000000004, + y0: 35.038723275067355, + }, + series: 9, + }, + { + x: 1293840000000, + y: 35.250000000000036, + index: 31, + seriesIndex: 9, + display: { + y: 35.250000000000036, + y0: 120.70173970949426, + }, + series: 9, + }, + { + x: 1325376000000, + y: 23.53, + index: 32, + seriesIndex: 9, + display: { + y: 23.53, + y0: 211.43331147601265, + }, + series: 9, + }, + { + x: 1356998400000, + y: 12.829999999999995, + index: 33, + seriesIndex: 9, + display: { + y: 12.829999999999995, + y0: 239.42434975261475, + }, + series: 9, + }, + { + x: 1388534400000, + y: 13.389999999999993, + index: 34, + seriesIndex: 9, + display: { + y: 13.389999999999993, + y0: 306.0714727314013, + }, + series: 9, + }, + { + x: 1420070400000, + y: 8.069999999999997, + index: 35, + seriesIndex: 9, + display: { + y: 8.069999999999997, + y0: 331.74176221105637, + }, + series: 9, + }, + { + x: 1451606400000, + y: 2.5999999999999974, + index: 36, + seriesIndex: 9, + display: { + y: 2.5999999999999974, + y0: 319.88515851727374, + }, + series: 9, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 9, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 9, + }, + ], + }, + { + key: ['GB'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 10, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 10, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 10, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 10, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 10, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 10, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 10, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 10, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 10, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 10, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 10, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 10, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 10, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 10, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 10, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 10, + }, + { + x: 567993600000, + y: 1.43, + index: 8, + seriesIndex: 10, + display: { + y: 1.43, + y0: 305.7650172280039, + }, + series: 10, + }, + { + x: 599616000000, + y: 64.98, + index: 9, + seriesIndex: 10, + display: { + y: 64.98, + y0: 272.3260219931503, + }, + series: 10, + }, + { + x: 631152000000, + y: 4.890000000000001, + index: 10, + seriesIndex: 10, + display: { + y: 4.890000000000001, + y0: 315.774808184687, + }, + series: 10, + }, + { + x: 662688000000, + y: 5.57, + index: 11, + seriesIndex: 10, + display: { + y: 5.57, + y0: 323.71638745865533, + }, + series: 10, + }, + { + x: 694224000000, + y: 25.48, + index: 12, + seriesIndex: 10, + display: { + y: 25.48, + y0: 302.57003766873936, + }, + series: 10, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 10, + display: { + y: 0, + y0: 333.14055311023566, + }, + series: 10, + }, + { + x: 757382400000, + y: 12.170000000000002, + index: 14, + seriesIndex: 10, + display: { + y: 12.170000000000002, + y0: 327.9065547522718, + }, + series: 10, + }, + { + x: 788918400000, + y: 3.5999999999999996, + index: 15, + seriesIndex: 10, + display: { + y: 3.5999999999999996, + y0: 345.8316336309462, + }, + series: 10, + }, + { + x: 820454400000, + y: 36.02, + index: 16, + seriesIndex: 10, + display: { + y: 36.02, + y0: 350.16008078133535, + }, + series: 10, + }, + { + x: 852076800000, + y: 6.37, + index: 17, + seriesIndex: 10, + display: { + y: 6.37, + y0: 374.61302062609593, + }, + series: 10, + }, + { + x: 883612800000, + y: 26.9, + index: 18, + seriesIndex: 10, + display: { + y: 26.9, + y0: 377.8132684133616, + }, + series: 10, + }, + { + x: 915148800000, + y: 38.010000000000005, + index: 19, + seriesIndex: 10, + display: { + y: 38.010000000000005, + y0: 363.05108391063544, + }, + series: 10, + }, + { + x: 946684800000, + y: 19.759999999999998, + index: 20, + seriesIndex: 10, + display: { + y: 19.759999999999998, + y0: 361.7963863019829, + }, + series: 10, + }, + { + x: 978307200000, + y: 9.24, + index: 21, + seriesIndex: 10, + display: { + y: 9.24, + y0: 335.56659853838437, + }, + series: 10, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 10, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 10, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 10, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 10, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 10, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 10, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 10, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 10, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 10, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 10, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 10, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 10, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 10, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 10, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 10, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 10, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 10, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 10, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 10, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 10, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 10, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 10, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 10, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 10, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 10, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 10, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 10, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 10, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 10, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 10, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 10, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 10, + }, + ], + }, + { + key: ['XB'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 11, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 11, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 11, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 11, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 11, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 11, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 11, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 11, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 11, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 11, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 11, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 11, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 11, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 11, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 11, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 11, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 11, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 11, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 11, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 11, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 11, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 11, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 11, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 11, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 11, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 11, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 11, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 11, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 11, + display: { + y: 0, + y0: 317.05655475227184, + }, + series: 11, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 11, + display: { + y: 0, + y0: 297.7616336309462, + }, + series: 11, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 11, + display: { + y: 0, + y0: 247.66008078133538, + }, + series: 11, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 11, + display: { + y: 0, + y0: 231.76302062609608, + }, + series: 11, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 11, + display: { + y: 0, + y0: 204.41326841336158, + }, + series: 11, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 11, + display: { + y: 0, + y0: 218.39108391063536, + }, + series: 11, + }, + { + x: 946684800000, + y: 0.99, + index: 20, + seriesIndex: 11, + display: { + y: 0.99, + y0: 264.466386301983, + }, + series: 11, + }, + { + x: 978307200000, + y: 22.23999999999999, + index: 21, + seriesIndex: 11, + display: { + y: 22.23999999999999, + y0: 216.18659853838435, + }, + series: 11, + }, + { + x: 1009843200000, + y: 48.15000000000006, + index: 22, + seriesIndex: 11, + display: { + y: 48.15000000000006, + y0: 185.4195712072759, + }, + series: 11, + }, + { + x: 1041379200000, + y: 55.16000000000003, + index: 23, + seriesIndex: 11, + display: { + y: 55.16000000000003, + y0: 201.70062695689174, + }, + series: 11, + }, + { + x: 1072915200000, + y: 65.50000000000001, + index: 24, + seriesIndex: 11, + display: { + y: 65.50000000000001, + y0: 186.11654906702506, + }, + series: 11, + }, + { + x: 1104537600000, + y: 49.17000000000011, + index: 25, + seriesIndex: 11, + display: { + y: 49.17000000000011, + y0: 256.9471603424088, + }, + series: 11, + }, + { + x: 1136073600000, + y: 10.149999999999991, + index: 26, + seriesIndex: 11, + display: { + y: 10.149999999999991, + y0: 305.4383968117778, + }, + series: 11, + }, + { + x: 1167609600000, + y: 0.5499999999999999, + index: 27, + seriesIndex: 11, + display: { + y: 0.5499999999999999, + y0: 329.96807151274163, + }, + series: 11, + }, + { + x: 1199145600000, + y: 0.18, + index: 28, + seriesIndex: 11, + display: { + y: 0.18, + y0: 331.00000000000057, + }, + series: 11, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 11, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 11, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 11, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 11, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 11, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 11, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 11, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 11, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 11, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 11, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 11, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 11, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 11, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 11, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 11, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 11, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 11, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 11, + }, + ], + }, + { + key: ['NES'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 12, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 12, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 12, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 12, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 12, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 12, + }, + { + x: 410227200000, + y: 10.959999999999999, + index: 3, + seriesIndex: 12, + display: { + y: 10.959999999999999, + y0: 325.1457418579461, + }, + series: 12, + }, + { + x: 441763200000, + y: 50.09000000000001, + index: 4, + seriesIndex: 12, + display: { + y: 50.09000000000001, + y0: 305.6707329222829, + }, + series: 12, + }, + { + x: 473385600000, + y: 53.44, + index: 5, + seriesIndex: 12, + display: { + y: 53.44, + y0: 304.012200293436, + }, + series: 12, + }, + { + x: 504921600000, + y: 36.410000000000004, + index: 6, + seriesIndex: 12, + display: { + y: 36.410000000000004, + y0: 312.37746735575064, + }, + series: 12, + }, + { + x: 536457600000, + y: 19.759999999999998, + index: 7, + seriesIndex: 12, + display: { + y: 19.759999999999998, + y0: 320.00436707976166, + }, + series: 12, + }, + { + x: 567993600000, + y: 45.01, + index: 8, + seriesIndex: 12, + display: { + y: 45.01, + y0: 307.9450172280039, + }, + series: 12, + }, + { + x: 599616000000, + y: 7.849999999999999, + index: 9, + seriesIndex: 12, + display: { + y: 7.849999999999999, + y0: 337.9260219931503, + }, + series: 12, + }, + { + x: 631152000000, + y: 15.74, + index: 10, + seriesIndex: 12, + display: { + y: 15.74, + y0: 320.664808184687, + }, + series: 12, + }, + { + x: 662688000000, + y: 6.11, + index: 11, + seriesIndex: 12, + display: { + y: 6.11, + y0: 329.2863874586553, + }, + series: 12, + }, + { + x: 694224000000, + y: 1.9800000000000002, + index: 12, + seriesIndex: 12, + display: { + y: 1.9800000000000002, + y0: 328.0500376687394, + }, + series: 12, + }, + { + x: 725846400000, + y: 3.61, + index: 13, + seriesIndex: 12, + display: { + y: 3.61, + y0: 333.14055311023566, + }, + series: 12, + }, + { + x: 757382400000, + y: 0.11, + index: 14, + seriesIndex: 12, + display: { + y: 0.11, + y0: 340.0765547522718, + }, + series: 12, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 12, + display: { + y: 0, + y0: 349.43163363094624, + }, + series: 12, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 12, + display: { + y: 0, + y0: 386.18008078133533, + }, + series: 12, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 12, + display: { + y: 0, + y0: 380.98302062609594, + }, + series: 12, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 12, + display: { + y: 0, + y0: 404.71326841336156, + }, + series: 12, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 12, + display: { + y: 0, + y0: 401.06108391063543, + }, + series: 12, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 12, + display: { + y: 0, + y0: 381.5563863019829, + }, + series: 12, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 12, + display: { + y: 0, + y0: 344.8065985383844, + }, + series: 12, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 12, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 12, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 12, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 12, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 12, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 12, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 12, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 12, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 12, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 12, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 12, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 12, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 12, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 12, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 12, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 12, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 12, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 12, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 12, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 12, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 12, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 12, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 12, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 12, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 12, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 12, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 12, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 12, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 12, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 12, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 12, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 12, + }, + ], + }, + { + key: ['3DS'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 13, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 13, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 13, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 13, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 13, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 13, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 13, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 13, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 13, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 13, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 13, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 13, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 13, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 13, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 13, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 13, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 13, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 13, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 13, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 13, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 13, + display: { + y: 0, + y0: 365.16480818468705, + }, + series: 13, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 13, + display: { + y: 0, + y0: 355.9463874586553, + }, + series: 13, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 13, + display: { + y: 0, + y0: 375.71003766873946, + }, + series: 13, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 13, + display: { + y: 0, + y0: 377.41055311023564, + }, + series: 13, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 13, + display: { + y: 0, + y0: 383.37655475227183, + }, + series: 13, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 13, + display: { + y: 0, + y0: 381.6416336309462, + }, + series: 13, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 13, + display: { + y: 0, + y0: 436.22008078133535, + }, + series: 13, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 13, + display: { + y: 0, + y0: 421.48302062609594, + }, + series: 13, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 13, + display: { + y: 0, + y0: 457.6032684133616, + }, + series: 13, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 13, + display: { + y: 0, + y0: 464.9110839106354, + }, + series: 13, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 13, + display: { + y: 0, + y0: 461.34638630198293, + }, + series: 13, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 13, + display: { + y: 0, + y0: 542.1465985383844, + }, + series: 13, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 13, + display: { + y: 0, + y0: 572.3395712072761, + }, + series: 13, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 13, + display: { + y: 0, + y0: 550.5906269568918, + }, + series: 13, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 13, + display: { + y: 0, + y0: 570.376549067025, + }, + series: 13, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 13, + display: { + y: 0, + y0: 528.467160342409, + }, + series: 13, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 13, + display: { + y: 0, + y0: 594.6283968117779, + }, + series: 13, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 13, + display: { + y: 0, + y0: 639.0180715127416, + }, + series: 13, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 13, + display: { + y: 0, + y0: 678.9000000000007, + }, + series: 13, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 13, + display: { + y: 0, + y0: 692.8065790499031, + }, + series: 13, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 13, + display: { + y: 0, + y0: 635.4887232750676, + }, + series: 13, + }, + { + x: 1293840000000, + y: 62.53, + index: 31, + seriesIndex: 13, + display: { + y: 62.53, + y0: 569.0117397094947, + }, + series: 13, + }, + { + x: 1325376000000, + y: 51.14000000000004, + index: 32, + seriesIndex: 13, + display: { + y: 51.14000000000004, + y0: 487.4633114760125, + }, + series: 13, + }, + { + x: 1356998400000, + y: 55.88000000000002, + index: 33, + seriesIndex: 13, + display: { + y: 55.88000000000002, + y0: 473.7643497526147, + }, + series: 13, + }, + { + x: 1388534400000, + y: 43.140000000000036, + index: 34, + seriesIndex: 13, + display: { + y: 43.140000000000036, + y0: 411.54147273140126, + }, + series: 13, + }, + { + x: 1420070400000, + y: 26.99, + index: 35, + seriesIndex: 13, + display: { + y: 26.99, + y0: 372.7517622110564, + }, + series: 13, + }, + { + x: 1451606400000, + y: 6.599999999999999, + index: 36, + seriesIndex: 13, + display: { + y: 6.599999999999999, + y0: 325.9051585172737, + }, + series: 13, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 13, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 13, + }, + ], + }, + { + key: ['N64'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 14, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 14, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 14, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 14, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 14, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 14, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 14, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 14, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 14, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 14, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 14, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 14, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 14, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 14, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 14, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 14, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 14, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 14, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 14, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 14, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 14, + display: { + y: 0, + y0: 365.16480818468705, + }, + series: 14, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 14, + display: { + y: 0, + y0: 355.9463874586553, + }, + series: 14, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 14, + display: { + y: 0, + y0: 375.71003766873946, + }, + series: 14, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 14, + display: { + y: 0, + y0: 377.41055311023564, + }, + series: 14, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 14, + display: { + y: 0, + y0: 383.37655475227183, + }, + series: 14, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 14, + display: { + y: 0, + y0: 381.6416336309462, + }, + series: 14, + }, + { + x: 820454400000, + y: 34.10999999999999, + index: 16, + seriesIndex: 14, + display: { + y: 34.10999999999999, + y0: 402.11008078133534, + }, + series: 14, + }, + { + x: 852076800000, + y: 39.509999999999984, + index: 17, + seriesIndex: 14, + display: { + y: 39.509999999999984, + y0: 381.97302062609594, + }, + series: 14, + }, + { + x: 883612800000, + y: 49.28000000000002, + index: 18, + seriesIndex: 14, + display: { + y: 49.28000000000002, + y0: 404.9332684133616, + }, + series: 14, + }, + { + x: 915148800000, + y: 57.95999999999997, + index: 19, + seriesIndex: 14, + display: { + y: 57.95999999999997, + y0: 401.3210839106354, + }, + series: 14, + }, + { + x: 946684800000, + y: 34.00999999999999, + index: 20, + seriesIndex: 14, + display: { + y: 34.00999999999999, + y0: 381.5563863019829, + }, + series: 14, + }, + { + x: 978307200000, + y: 3.2600000000000002, + index: 21, + seriesIndex: 14, + display: { + y: 3.2600000000000002, + y0: 344.8065985383844, + }, + series: 14, + }, + { + x: 1009843200000, + y: 0.08, + index: 22, + seriesIndex: 14, + display: { + y: 0.08, + y0: 314.639571207276, + }, + series: 14, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 14, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 14, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 14, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 14, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 14, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 14, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 14, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 14, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 14, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 14, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 14, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 14, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 14, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 14, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 14, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 14, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 14, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 14, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 14, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 14, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 14, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 14, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 14, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 14, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 14, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 14, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 14, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 14, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 14, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 14, + }, + ], + }, + { + key: ['SNES'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 15, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 15, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 15, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 15, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 15, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 15, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 15, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 15, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 15, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 15, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 15, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 15, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 15, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 15, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 15, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 15, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 15, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 15, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 15, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 15, + }, + { + x: 631152000000, + y: 26.16, + index: 10, + seriesIndex: 15, + display: { + y: 26.16, + y0: 339.004808184687, + }, + series: 15, + }, + { + x: 662688000000, + y: 16.21, + index: 11, + seriesIndex: 15, + display: { + y: 16.21, + y0: 339.7363874586553, + }, + series: 15, + }, + { + x: 694224000000, + y: 32.97999999999999, + index: 12, + seriesIndex: 15, + display: { + y: 32.97999999999999, + y0: 342.73003766873944, + }, + series: 15, + }, + { + x: 725846400000, + y: 40.010000000000005, + index: 13, + seriesIndex: 15, + display: { + y: 40.010000000000005, + y0: 337.40055311023565, + }, + series: 15, + }, + { + x: 757382400000, + y: 35.08, + index: 14, + seriesIndex: 15, + display: { + y: 35.08, + y0: 348.29655475227185, + }, + series: 15, + }, + { + x: 788918400000, + y: 32.21000000000001, + index: 15, + seriesIndex: 15, + display: { + y: 32.21000000000001, + y0: 349.43163363094624, + }, + series: 15, + }, + { + x: 820454400000, + y: 15.929999999999996, + index: 16, + seriesIndex: 15, + display: { + y: 15.929999999999996, + y0: 386.18008078133533, + }, + series: 15, + }, + { + x: 852076800000, + y: 0.99, + index: 17, + seriesIndex: 15, + display: { + y: 0.99, + y0: 380.98302062609594, + }, + series: 15, + }, + { + x: 883612800000, + y: 0.22000000000000003, + index: 18, + seriesIndex: 15, + display: { + y: 0.22000000000000003, + y0: 404.71326841336156, + }, + series: 15, + }, + { + x: 915148800000, + y: 0.26, + index: 19, + seriesIndex: 15, + display: { + y: 0.26, + y0: 401.06108391063543, + }, + series: 15, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 15, + display: { + y: 0, + y0: 381.5563863019829, + }, + series: 15, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 15, + display: { + y: 0, + y0: 344.8065985383844, + }, + series: 15, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 15, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 15, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 15, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 15, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 15, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 15, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 15, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 15, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 15, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 15, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 15, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 15, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 15, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 15, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 15, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 15, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 15, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 15, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 15, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 15, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 15, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 15, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 15, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 15, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 15, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 15, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 15, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 15, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 15, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 15, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 15, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 15, + }, + ], + }, + { + key: ['GC'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 16, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 16, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 16, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 16, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 16, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 16, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 16, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 16, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 16, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 16, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 16, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 16, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 16, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 16, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 16, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 16, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 16, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 16, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 16, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 16, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 16, + display: { + y: 0, + y0: 365.16480818468705, + }, + series: 16, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 16, + display: { + y: 0, + y0: 355.9463874586553, + }, + series: 16, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 16, + display: { + y: 0, + y0: 375.71003766873946, + }, + series: 16, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 16, + display: { + y: 0, + y0: 377.41055311023564, + }, + series: 16, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 16, + display: { + y: 0, + y0: 383.37655475227183, + }, + series: 16, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 16, + display: { + y: 0, + y0: 381.6416336309462, + }, + series: 16, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 16, + display: { + y: 0, + y0: 436.22008078133535, + }, + series: 16, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 16, + display: { + y: 0, + y0: 421.48302062609594, + }, + series: 16, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 16, + display: { + y: 0, + y0: 457.6032684133616, + }, + series: 16, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 16, + display: { + y: 0, + y0: 464.9110839106354, + }, + series: 16, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 16, + display: { + y: 0, + y0: 422.2363863019829, + }, + series: 16, + }, + { + x: 978307200000, + y: 26.299999999999997, + index: 21, + seriesIndex: 16, + display: { + y: 26.299999999999997, + y0: 349.41659853838433, + }, + series: 16, + }, + { + x: 1009843200000, + y: 51.93, + index: 22, + seriesIndex: 16, + display: { + y: 51.93, + y0: 315.009571207276, + }, + series: 16, + }, + { + x: 1041379200000, + y: 50.660000000000004, + index: 23, + seriesIndex: 16, + display: { + y: 50.660000000000004, + y0: 315.64062695689177, + }, + series: 16, + }, + { + x: 1072915200000, + y: 28.889999999999983, + index: 24, + seriesIndex: 16, + display: { + y: 28.889999999999983, + y0: 329.7065490670251, + }, + series: 16, + }, + { + x: 1104537600000, + y: 27.799999999999976, + index: 25, + seriesIndex: 16, + display: { + y: 27.799999999999976, + y0: 340.01716034240894, + }, + series: 16, + }, + { + x: 1136073600000, + y: 11.29, + index: 26, + seriesIndex: 16, + display: { + y: 11.29, + y0: 320.9383968117778, + }, + series: 16, + }, + { + x: 1167609600000, + y: 0.27, + index: 27, + seriesIndex: 16, + display: { + y: 0.27, + y0: 333.96807151274163, + }, + series: 16, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 16, + display: { + y: 0, + y0: 331.2200000000006, + }, + series: 16, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 16, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 16, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 16, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 16, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 16, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 16, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 16, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 16, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 16, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 16, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 16, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 16, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 16, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 16, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 16, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 16, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 16, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 16, + }, + ], + }, + { + key: ['XOne'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 17, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 17, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 17, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 17, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 17, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 17, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 17, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 17, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 17, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 17, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 17, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 17, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 17, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 17, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 17, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 17, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 17, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 17, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 17, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 17, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 17, + display: { + y: 0, + y0: 365.16480818468705, + }, + series: 17, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 17, + display: { + y: 0, + y0: 355.9463874586553, + }, + series: 17, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 17, + display: { + y: 0, + y0: 375.71003766873946, + }, + series: 17, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 17, + display: { + y: 0, + y0: 377.41055311023564, + }, + series: 17, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 17, + display: { + y: 0, + y0: 383.37655475227183, + }, + series: 17, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 17, + display: { + y: 0, + y0: 381.6416336309462, + }, + series: 17, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 17, + display: { + y: 0, + y0: 436.22008078133535, + }, + series: 17, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 17, + display: { + y: 0, + y0: 421.48302062609594, + }, + series: 17, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 17, + display: { + y: 0, + y0: 457.6032684133616, + }, + series: 17, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 17, + display: { + y: 0, + y0: 464.9110839106354, + }, + series: 17, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 17, + display: { + y: 0, + y0: 461.34638630198293, + }, + series: 17, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 17, + display: { + y: 0, + y0: 542.1465985383844, + }, + series: 17, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 17, + display: { + y: 0, + y0: 572.3395712072761, + }, + series: 17, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 17, + display: { + y: 0, + y0: 550.5906269568918, + }, + series: 17, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 17, + display: { + y: 0, + y0: 570.376549067025, + }, + series: 17, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 17, + display: { + y: 0, + y0: 528.467160342409, + }, + series: 17, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 17, + display: { + y: 0, + y0: 594.6283968117779, + }, + series: 17, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 17, + display: { + y: 0, + y0: 639.0180715127416, + }, + series: 17, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 17, + display: { + y: 0, + y0: 678.9000000000007, + }, + series: 17, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 17, + display: { + y: 0, + y0: 692.8065790499031, + }, + series: 17, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 17, + display: { + y: 0, + y0: 635.4887232750676, + }, + series: 17, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 17, + display: { + y: 0, + y0: 631.5417397094947, + }, + series: 17, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 17, + display: { + y: 0, + y0: 538.6033114760125, + }, + series: 17, + }, + { + x: 1356998400000, + y: 18.599999999999998, + index: 33, + seriesIndex: 17, + display: { + y: 18.599999999999998, + y0: 529.6443497526147, + }, + series: 17, + }, + { + x: 1388534400000, + y: 52.43, + index: 34, + seriesIndex: 17, + display: { + y: 52.43, + y0: 454.6814727314013, + }, + series: 17, + }, + { + x: 1420070400000, + y: 57.660000000000025, + index: 35, + seriesIndex: 17, + display: { + y: 57.660000000000025, + y0: 399.7417622110564, + }, + series: 17, + }, + { + x: 1451606400000, + y: 12.369999999999987, + index: 36, + seriesIndex: 17, + display: { + y: 12.369999999999987, + y0: 332.50515851727374, + }, + series: 17, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 17, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 17, + }, + ], + }, + { + key: ['2600'], + values: [ + { + x: 315532800000, + y: 11.379999999999999, + index: 0, + seriesIndex: 18, + display: { + y: 11.379999999999999, + y0: 312.60127789129933, + }, + series: 18, + }, + { + x: 347155200000, + y: 35.77000000000001, + index: 1, + seriesIndex: 18, + display: { + y: 35.77000000000001, + y0: 300.40627789129934, + }, + series: 18, + }, + { + x: 378691200000, + y: 28.859999999999996, + index: 2, + seriesIndex: 18, + display: { + y: 28.859999999999996, + y0: 303.8612778912993, + }, + series: 18, + }, + { + x: 410227200000, + y: 5.83, + index: 3, + seriesIndex: 18, + display: { + y: 5.83, + y0: 319.31574185794614, + }, + series: 18, + }, + { + x: 441763200000, + y: 0.27, + index: 4, + seriesIndex: 18, + display: { + y: 0.27, + y0: 305.40073292228294, + }, + series: 18, + }, + { + x: 473385600000, + y: 0.45, + index: 5, + seriesIndex: 18, + display: { + y: 0.45, + y0: 303.56220029343604, + }, + series: 18, + }, + { + x: 504921600000, + y: 0.6599999999999999, + index: 6, + seriesIndex: 18, + display: { + y: 0.6599999999999999, + y0: 311.7174673557506, + }, + series: 18, + }, + { + x: 536457600000, + y: 1.9800000000000002, + index: 7, + seriesIndex: 18, + display: { + y: 1.9800000000000002, + y0: 318.02436707976165, + }, + series: 18, + }, + { + x: 567993600000, + y: 0.75, + index: 8, + seriesIndex: 18, + display: { + y: 0.75, + y0: 307.1950172280039, + }, + series: 18, + }, + { + x: 599616000000, + y: 0.62, + index: 9, + seriesIndex: 18, + display: { + y: 0.62, + y0: 337.3060219931503, + }, + series: 18, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 18, + display: { + y: 0, + y0: 320.664808184687, + }, + series: 18, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 18, + display: { + y: 0, + y0: 329.2863874586553, + }, + series: 18, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 18, + display: { + y: 0, + y0: 328.0500376687394, + }, + series: 18, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 18, + display: { + y: 0, + y0: 333.14055311023566, + }, + series: 18, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 18, + display: { + y: 0, + y0: 340.0765547522718, + }, + series: 18, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 18, + display: { + y: 0, + y0: 349.43163363094624, + }, + series: 18, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 18, + display: { + y: 0, + y0: 386.18008078133533, + }, + series: 18, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 18, + display: { + y: 0, + y0: 380.98302062609594, + }, + series: 18, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 18, + display: { + y: 0, + y0: 404.71326841336156, + }, + series: 18, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 18, + display: { + y: 0, + y0: 401.06108391063543, + }, + series: 18, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 18, + display: { + y: 0, + y0: 381.5563863019829, + }, + series: 18, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 18, + display: { + y: 0, + y0: 344.8065985383844, + }, + series: 18, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 18, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 18, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 18, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 18, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 18, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 18, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 18, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 18, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 18, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 18, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 18, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 18, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 18, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 18, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 18, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 18, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 18, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 18, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 18, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 18, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 18, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 18, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 18, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 18, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 18, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 18, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 18, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 18, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 18, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 18, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 18, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 18, + }, + ], + }, + { + key: ['WiiU'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 19, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 19, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 19, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 19, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 19, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 19, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 19, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 19, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 19, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 19, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 19, + display: { + y: 0, + y0: 303.5122002934361, + }, + series: 19, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 19, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 19, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 19, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 19, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 19, + display: { + y: 0, + y0: 305.7350172280039, + }, + series: 19, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 19, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 19, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 19, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 19, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 19, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 19, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 19, + display: { + y: 0, + y0: 299.5500376687394, + }, + series: 19, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 19, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 19, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 19, + display: { + y: 0, + y0: 304.2065547522718, + }, + series: 19, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 19, + display: { + y: 0, + y0: 293.5316336309462, + }, + series: 19, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 19, + display: { + y: 0, + y0: 237.07008078133538, + }, + series: 19, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 19, + display: { + y: 0, + y0: 220.5030206260961, + }, + series: 19, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 19, + display: { + y: 0, + y0: 201.13326841336158, + }, + series: 19, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 19, + display: { + y: 0, + y0: 213.64108391063536, + }, + series: 19, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 19, + display: { + y: 0, + y0: 259.786386301983, + }, + series: 19, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 19, + display: { + y: 0, + y0: 210.67659853838435, + }, + series: 19, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 19, + display: { + y: 0, + y0: 176.8195712072759, + }, + series: 19, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 19, + display: { + y: 0, + y0: 192.74062695689176, + }, + series: 19, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 19, + display: { + y: 0, + y0: 151.06654906702508, + }, + series: 19, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 19, + display: { + y: 0, + y0: 68.52716034240856, + }, + series: 19, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 19, + display: { + y: 0, + y0: 73.58839681177778, + }, + series: 19, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 19, + display: { + y: 0, + y0: 27.888071512741476, + }, + series: 19, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 19, + display: { + y: 0, + y0: 0, + }, + series: 19, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 19, + display: { + y: 0, + y0: 25.506579049902825, + }, + series: 19, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 19, + display: { + y: 0, + y0: 35.038723275067355, + }, + series: 19, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 19, + display: { + y: 0, + y0: 115.55173970949426, + }, + series: 19, + }, + { + x: 1325376000000, + y: 17.840000000000003, + index: 32, + seriesIndex: 19, + display: { + y: 17.840000000000003, + y0: 175.06331147601264, + }, + series: 19, + }, + { + x: 1356998400000, + y: 21.84, + index: 33, + seriesIndex: 19, + display: { + y: 21.84, + y0: 204.89434975261474, + }, + series: 19, + }, + { + x: 1388534400000, + y: 22.509999999999994, + index: 34, + seriesIndex: 19, + display: { + y: 22.509999999999994, + y0: 268.8214727314013, + }, + series: 19, + }, + { + x: 1420070400000, + y: 16.380000000000003, + index: 35, + seriesIndex: 19, + display: { + y: 16.380000000000003, + y0: 308.2617622110564, + }, + series: 19, + }, + { + x: 1451606400000, + y: 3.2899999999999996, + index: 36, + seriesIndex: 19, + display: { + y: 3.2899999999999996, + y0: 313.19515851727374, + }, + series: 19, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 19, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 19, + }, + ], + }, + { + key: ['PSV'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 20, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 20, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 20, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 20, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 20, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 20, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 20, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 20, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 20, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 20, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 20, + display: { + y: 0, + y0: 303.5122002934361, + }, + series: 20, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 20, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 20, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 20, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 20, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 20, + display: { + y: 0, + y0: 305.7350172280039, + }, + series: 20, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 20, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 20, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 20, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 20, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 20, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 20, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 20, + display: { + y: 0, + y0: 299.5500376687394, + }, + series: 20, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 20, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 20, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 20, + display: { + y: 0, + y0: 304.2065547522718, + }, + series: 20, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 20, + display: { + y: 0, + y0: 293.5316336309462, + }, + series: 20, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 20, + display: { + y: 0, + y0: 237.07008078133538, + }, + series: 20, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 20, + display: { + y: 0, + y0: 220.5030206260961, + }, + series: 20, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 20, + display: { + y: 0, + y0: 201.13326841336158, + }, + series: 20, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 20, + display: { + y: 0, + y0: 213.64108391063536, + }, + series: 20, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 20, + display: { + y: 0, + y0: 259.786386301983, + }, + series: 20, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 20, + display: { + y: 0, + y0: 210.67659853838435, + }, + series: 20, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 20, + display: { + y: 0, + y0: 176.8195712072759, + }, + series: 20, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 20, + display: { + y: 0, + y0: 192.74062695689176, + }, + series: 20, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 20, + display: { + y: 0, + y0: 151.06654906702508, + }, + series: 20, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 20, + display: { + y: 0, + y0: 68.52716034240856, + }, + series: 20, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 20, + display: { + y: 0, + y0: 73.58839681177778, + }, + series: 20, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 20, + display: { + y: 0, + y0: 27.888071512741476, + }, + series: 20, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 20, + display: { + y: 0, + y0: 0, + }, + series: 20, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 20, + display: { + y: 0, + y0: 25.506579049902825, + }, + series: 20, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 20, + display: { + y: 0, + y0: 35.038723275067355, + }, + series: 20, + }, + { + x: 1293840000000, + y: 5.1499999999999995, + index: 31, + seriesIndex: 20, + display: { + y: 5.1499999999999995, + y0: 115.55173970949426, + }, + series: 20, + }, + { + x: 1325376000000, + y: 18.530000000000005, + index: 32, + seriesIndex: 20, + display: { + y: 18.530000000000005, + y0: 192.90331147601265, + }, + series: 20, + }, + { + x: 1356998400000, + y: 12.690000000000001, + index: 33, + seriesIndex: 20, + display: { + y: 12.690000000000001, + y0: 226.73434975261475, + }, + series: 20, + }, + { + x: 1388534400000, + y: 14.73999999999999, + index: 34, + seriesIndex: 20, + display: { + y: 14.73999999999999, + y0: 291.3314727314013, + }, + series: 20, + }, + { + x: 1420070400000, + y: 7.09999999999999, + index: 35, + seriesIndex: 20, + display: { + y: 7.09999999999999, + y0: 324.6417622110564, + }, + series: 20, + }, + { + x: 1451606400000, + y: 3.399999999999996, + index: 36, + seriesIndex: 20, + display: { + y: 3.399999999999996, + y0: 316.48515851727376, + }, + series: 20, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 20, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 20, + }, + ], + }, + { + key: ['SAT'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 21, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 21, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 21, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 21, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 21, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 21, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 21, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 21, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 21, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 21, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 21, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 21, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 21, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 21, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 21, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 21, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 21, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 21, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 21, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 21, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 21, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 21, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 21, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 21, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 21, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 21, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 21, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 21, + }, + { + x: 757382400000, + y: 3.6400000000000006, + index: 14, + seriesIndex: 21, + display: { + y: 3.6400000000000006, + y0: 323.0965547522718, + }, + series: 21, + }, + { + x: 788918400000, + y: 11.579999999999998, + index: 15, + seriesIndex: 21, + display: { + y: 11.579999999999998, + y0: 333.92163363094625, + }, + series: 21, + }, + { + x: 820454400000, + y: 7.69, + index: 16, + seriesIndex: 21, + display: { + y: 7.69, + y0: 342.37008078133533, + }, + series: 21, + }, + { + x: 852076800000, + y: 6.7700000000000005, + index: 17, + seriesIndex: 21, + display: { + y: 6.7700000000000005, + y0: 367.84302062609595, + }, + series: 21, + }, + { + x: 883612800000, + y: 3.819999999999999, + index: 18, + seriesIndex: 21, + display: { + y: 3.819999999999999, + y0: 373.9932684133616, + }, + series: 21, + }, + { + x: 915148800000, + y: 0.09, + index: 19, + seriesIndex: 21, + display: { + y: 0.09, + y0: 362.96108391063547, + }, + series: 21, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 21, + display: { + y: 0, + y0: 361.7963863019829, + }, + series: 21, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 21, + display: { + y: 0, + y0: 335.56659853838437, + }, + series: 21, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 21, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 21, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 21, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 21, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 21, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 21, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 21, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 21, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 21, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 21, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 21, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 21, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 21, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 21, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 21, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 21, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 21, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 21, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 21, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 21, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 21, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 21, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 21, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 21, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 21, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 21, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 21, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 21, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 21, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 21, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 21, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 21, + }, + ], + }, + { + key: ['GEN'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 22, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 22, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 22, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 22, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 22, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 22, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 22, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 22, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 22, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 22, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 22, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 22, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 22, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 22, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 22, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 22, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 22, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 22, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 22, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 22, + }, + { + x: 631152000000, + y: 2.6, + index: 10, + seriesIndex: 22, + display: { + y: 2.6, + y0: 336.404808184687, + }, + series: 22, + }, + { + x: 662688000000, + y: 4.34, + index: 11, + seriesIndex: 22, + display: { + y: 4.34, + y0: 335.39638745865534, + }, + series: 22, + }, + { + x: 694224000000, + y: 12.66, + index: 12, + seriesIndex: 22, + display: { + y: 12.66, + y0: 330.0300376687394, + }, + series: 22, + }, + { + x: 725846400000, + y: 0.6500000000000001, + index: 13, + seriesIndex: 22, + display: { + y: 0.6500000000000001, + y0: 336.75055311023567, + }, + series: 22, + }, + { + x: 757382400000, + y: 8.109999999999998, + index: 14, + seriesIndex: 22, + display: { + y: 8.109999999999998, + y0: 340.18655475227183, + }, + series: 22, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 22, + display: { + y: 0, + y0: 349.43163363094624, + }, + series: 22, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 22, + display: { + y: 0, + y0: 386.18008078133533, + }, + series: 22, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 22, + display: { + y: 0, + y0: 380.98302062609594, + }, + series: 22, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 22, + display: { + y: 0, + y0: 404.71326841336156, + }, + series: 22, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 22, + display: { + y: 0, + y0: 401.06108391063543, + }, + series: 22, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 22, + display: { + y: 0, + y0: 381.5563863019829, + }, + series: 22, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 22, + display: { + y: 0, + y0: 344.8065985383844, + }, + series: 22, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 22, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 22, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 22, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 22, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 22, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 22, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 22, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 22, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 22, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 22, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 22, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 22, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 22, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 22, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 22, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 22, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 22, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 22, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 22, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 22, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 22, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 22, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 22, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 22, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 22, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 22, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 22, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 22, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 22, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 22, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 22, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 22, + }, + ], + }, + { + key: ['DC'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 23, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 23, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 23, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 23, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 23, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 23, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 23, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 23, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 23, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 23, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 23, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 23, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 23, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 23, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 23, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 23, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 23, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 23, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 23, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 23, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 23, + display: { + y: 0, + y0: 365.16480818468705, + }, + series: 23, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 23, + display: { + y: 0, + y0: 355.9463874586553, + }, + series: 23, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 23, + display: { + y: 0, + y0: 375.71003766873946, + }, + series: 23, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 23, + display: { + y: 0, + y0: 377.41055311023564, + }, + series: 23, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 23, + display: { + y: 0, + y0: 383.37655475227183, + }, + series: 23, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 23, + display: { + y: 0, + y0: 381.6416336309462, + }, + series: 23, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 23, + display: { + y: 0, + y0: 436.22008078133535, + }, + series: 23, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 23, + display: { + y: 0, + y0: 421.48302062609594, + }, + series: 23, + }, + { + x: 883612800000, + y: 3.39, + index: 18, + seriesIndex: 23, + display: { + y: 3.39, + y0: 454.2132684133616, + }, + series: 23, + }, + { + x: 915148800000, + y: 5.169999999999999, + index: 19, + seriesIndex: 23, + display: { + y: 5.169999999999999, + y0: 459.2810839106354, + }, + series: 23, + }, + { + x: 946684800000, + y: 5.989999999999998, + index: 20, + seriesIndex: 23, + display: { + y: 5.989999999999998, + y0: 415.5663863019829, + }, + series: 23, + }, + { + x: 978307200000, + y: 1.07, + index: 21, + seriesIndex: 23, + display: { + y: 1.07, + y0: 348.06659853838437, + }, + series: 23, + }, + { + x: 1009843200000, + y: 0.29, + index: 22, + seriesIndex: 23, + display: { + y: 0.29, + y0: 314.719571207276, + }, + series: 23, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 23, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 23, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 23, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 23, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 23, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 23, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 23, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 23, + }, + { + x: 1167609600000, + y: 0.02, + index: 27, + seriesIndex: 23, + display: { + y: 0.02, + y0: 333.94807151274165, + }, + series: 23, + }, + { + x: 1199145600000, + y: 0.04, + index: 28, + seriesIndex: 23, + display: { + y: 0.04, + y0: 331.1800000000006, + }, + series: 23, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 23, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 23, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 23, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 23, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 23, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 23, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 23, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 23, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 23, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 23, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 23, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 23, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 23, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 23, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 23, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 23, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 23, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 23, + }, + ], + }, + { + key: ['SCD'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 24, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 24, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 24, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 24, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 24, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 24, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 24, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 24, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 24, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 24, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 24, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 24, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 24, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 24, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 24, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 24, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 24, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 24, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 24, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 24, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 24, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 24, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 24, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 24, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 24, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 24, + }, + { + x: 725846400000, + y: 1.5, + index: 13, + seriesIndex: 24, + display: { + y: 1.5, + y0: 331.64055311023566, + }, + series: 24, + }, + { + x: 757382400000, + y: 0.37, + index: 14, + seriesIndex: 24, + display: { + y: 0.37, + y0: 327.5365547522718, + }, + series: 24, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 24, + display: { + y: 0, + y0: 345.8316336309462, + }, + series: 24, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 24, + display: { + y: 0, + y0: 350.16008078133535, + }, + series: 24, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 24, + display: { + y: 0, + y0: 374.61302062609593, + }, + series: 24, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 24, + display: { + y: 0, + y0: 377.8132684133616, + }, + series: 24, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 24, + display: { + y: 0, + y0: 363.05108391063544, + }, + series: 24, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 24, + display: { + y: 0, + y0: 361.7963863019829, + }, + series: 24, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 24, + display: { + y: 0, + y0: 335.56659853838437, + }, + series: 24, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 24, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 24, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 24, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 24, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 24, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 24, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 24, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 24, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 24, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 24, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 24, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 24, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 24, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 24, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 24, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 24, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 24, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 24, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 24, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 24, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 24, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 24, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 24, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 24, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 24, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 24, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 24, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 24, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 24, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 24, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 24, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 24, + }, + ], + }, + { + key: ['NG'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 25, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 25, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 25, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 25, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 25, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 25, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 25, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 25, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 25, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 25, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 25, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 25, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 25, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 25, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 25, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 25, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 25, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 25, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 25, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 25, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 25, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 25, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 25, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 25, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 25, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 25, + }, + { + x: 725846400000, + y: 0.21000000000000002, + index: 13, + seriesIndex: 25, + display: { + y: 0.21000000000000002, + y0: 331.4305531102357, + }, + series: 25, + }, + { + x: 757382400000, + y: 0.7999999999999999, + index: 14, + seriesIndex: 25, + display: { + y: 0.7999999999999999, + y0: 326.7365547522718, + }, + series: 25, + }, + { + x: 788918400000, + y: 0.33000000000000007, + index: 15, + seriesIndex: 25, + display: { + y: 0.33000000000000007, + y0: 345.50163363094623, + }, + series: 25, + }, + { + x: 820454400000, + y: 0.1, + index: 16, + seriesIndex: 25, + display: { + y: 0.1, + y0: 350.06008078133533, + }, + series: 25, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 25, + display: { + y: 0, + y0: 374.61302062609593, + }, + series: 25, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 25, + display: { + y: 0, + y0: 377.8132684133616, + }, + series: 25, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 25, + display: { + y: 0, + y0: 363.05108391063544, + }, + series: 25, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 25, + display: { + y: 0, + y0: 361.7963863019829, + }, + series: 25, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 25, + display: { + y: 0, + y0: 335.56659853838437, + }, + series: 25, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 25, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 25, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 25, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 25, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 25, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 25, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 25, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 25, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 25, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 25, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 25, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 25, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 25, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 25, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 25, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 25, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 25, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 25, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 25, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 25, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 25, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 25, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 25, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 25, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 25, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 25, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 25, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 25, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 25, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 25, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 25, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 25, + }, + ], + }, + { + key: ['WS'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 26, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 26, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 26, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 26, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 26, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 26, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 26, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 26, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 26, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 26, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 26, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 26, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 26, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 26, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 26, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 26, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 26, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 26, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 26, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 26, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 26, + display: { + y: 0, + y0: 365.16480818468705, + }, + series: 26, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 26, + display: { + y: 0, + y0: 355.9463874586553, + }, + series: 26, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 26, + display: { + y: 0, + y0: 375.71003766873946, + }, + series: 26, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 26, + display: { + y: 0, + y0: 377.41055311023564, + }, + series: 26, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 26, + display: { + y: 0, + y0: 383.37655475227183, + }, + series: 26, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 26, + display: { + y: 0, + y0: 381.6416336309462, + }, + series: 26, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 26, + display: { + y: 0, + y0: 436.22008078133535, + }, + series: 26, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 26, + display: { + y: 0, + y0: 421.48302062609594, + }, + series: 26, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 26, + display: { + y: 0, + y0: 457.6032684133616, + }, + series: 26, + }, + { + x: 915148800000, + y: 0.46, + index: 19, + seriesIndex: 26, + display: { + y: 0.46, + y0: 464.4510839106354, + }, + series: 26, + }, + { + x: 946684800000, + y: 0.68, + index: 20, + seriesIndex: 26, + display: { + y: 0.68, + y0: 421.5563863019829, + }, + series: 26, + }, + { + x: 978307200000, + y: 0.28, + index: 21, + seriesIndex: 26, + display: { + y: 0.28, + y0: 349.13659853838436, + }, + series: 26, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 26, + display: { + y: 0, + y0: 315.009571207276, + }, + series: 26, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 26, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 26, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 26, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 26, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 26, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 26, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 26, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 26, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 26, + display: { + y: 0, + y0: 333.96807151274163, + }, + series: 26, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 26, + display: { + y: 0, + y0: 331.2200000000006, + }, + series: 26, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 26, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 26, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 26, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 26, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 26, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 26, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 26, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 26, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 26, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 26, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 26, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 26, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 26, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 26, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 26, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 26, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 26, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 26, + }, + ], + }, + { + key: ['TG16'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 27, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 27, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 27, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 27, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 27, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 27, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 27, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 27, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 27, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 27, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 27, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 27, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 27, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 27, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 27, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 27, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 27, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 27, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 27, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 27, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 27, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 27, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 27, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 27, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 27, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 27, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 27, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 27, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 27, + display: { + y: 0, + y0: 323.0965547522718, + }, + series: 27, + }, + { + x: 788918400000, + y: 0.16, + index: 15, + seriesIndex: 27, + display: { + y: 0.16, + y0: 333.7616336309462, + }, + series: 27, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 27, + display: { + y: 0, + y0: 342.37008078133533, + }, + series: 27, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 27, + display: { + y: 0, + y0: 367.84302062609595, + }, + series: 27, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 27, + display: { + y: 0, + y0: 373.9932684133616, + }, + series: 27, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 27, + display: { + y: 0, + y0: 362.96108391063547, + }, + series: 27, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 27, + display: { + y: 0, + y0: 361.7963863019829, + }, + series: 27, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 27, + display: { + y: 0, + y0: 335.56659853838437, + }, + series: 27, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 27, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 27, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 27, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 27, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 27, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 27, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 27, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 27, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 27, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 27, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 27, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 27, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 27, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 27, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 27, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 27, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 27, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 27, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 27, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 27, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 27, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 27, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 27, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 27, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 27, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 27, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 27, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 27, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 27, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 27, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 27, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 27, + }, + ], + }, + { + key: ['3DO'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 28, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 28, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 28, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 28, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 28, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 28, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 28, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 28, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 28, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 28, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 28, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 28, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 28, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 28, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 28, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 28, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 28, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 28, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 28, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 28, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 28, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 28, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 28, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 28, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 28, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 28, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 28, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 28, + }, + { + x: 757382400000, + y: 0.02, + index: 14, + seriesIndex: 28, + display: { + y: 0.02, + y0: 323.0765547522718, + }, + series: 28, + }, + { + x: 788918400000, + y: 0.08, + index: 15, + seriesIndex: 28, + display: { + y: 0.08, + y0: 333.68163363094624, + }, + series: 28, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 28, + display: { + y: 0, + y0: 342.37008078133533, + }, + series: 28, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 28, + display: { + y: 0, + y0: 367.84302062609595, + }, + series: 28, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 28, + display: { + y: 0, + y0: 373.9932684133616, + }, + series: 28, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 28, + display: { + y: 0, + y0: 362.96108391063547, + }, + series: 28, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 28, + display: { + y: 0, + y0: 361.7963863019829, + }, + series: 28, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 28, + display: { + y: 0, + y0: 335.56659853838437, + }, + series: 28, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 28, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 28, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 28, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 28, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 28, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 28, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 28, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 28, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 28, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 28, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 28, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 28, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 28, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 28, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 28, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 28, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 28, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 28, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 28, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 28, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 28, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 28, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 28, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 28, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 28, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 28, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 28, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 28, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 28, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 28, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 28, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 28, + }, + ], + }, + { + key: ['GG'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 29, + display: { + y: 0, + y0: 323.9812778912993, + }, + series: 29, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 29, + display: { + y: 0, + y0: 336.1762778912994, + }, + series: 29, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 29, + display: { + y: 0, + y0: 332.72127789129934, + }, + series: 29, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 29, + display: { + y: 0, + y0: 336.1057418579461, + }, + series: 29, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 29, + display: { + y: 0, + y0: 355.76073292228295, + }, + series: 29, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 29, + display: { + y: 0, + y0: 357.452200293436, + }, + series: 29, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 29, + display: { + y: 0, + y0: 348.78746735575066, + }, + series: 29, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 29, + display: { + y: 0, + y0: 339.76436707976166, + }, + series: 29, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 29, + display: { + y: 0, + y0: 352.9550172280039, + }, + series: 29, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 29, + display: { + y: 0, + y0: 345.7760219931503, + }, + series: 29, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 29, + display: { + y: 0, + y0: 339.004808184687, + }, + series: 29, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 29, + display: { + y: 0, + y0: 339.7363874586553, + }, + series: 29, + }, + { + x: 694224000000, + y: 0.04, + index: 12, + seriesIndex: 29, + display: { + y: 0.04, + y0: 342.6900376687394, + }, + series: 29, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 29, + display: { + y: 0, + y0: 337.40055311023565, + }, + series: 29, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 29, + display: { + y: 0, + y0: 348.29655475227185, + }, + series: 29, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 29, + display: { + y: 0, + y0: 349.43163363094624, + }, + series: 29, + }, + { + x: 820454400000, + y: 0, + index: 16, + seriesIndex: 29, + display: { + y: 0, + y0: 386.18008078133533, + }, + series: 29, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 29, + display: { + y: 0, + y0: 380.98302062609594, + }, + series: 29, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 29, + display: { + y: 0, + y0: 404.71326841336156, + }, + series: 29, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 29, + display: { + y: 0, + y0: 401.06108391063543, + }, + series: 29, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 29, + display: { + y: 0, + y0: 381.5563863019829, + }, + series: 29, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 29, + display: { + y: 0, + y0: 344.8065985383844, + }, + series: 29, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 29, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 29, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 29, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 29, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 29, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 29, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 29, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 29, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 29, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 29, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 29, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 29, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 29, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 29, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 29, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 29, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 29, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 29, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 29, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 29, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 29, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 29, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 29, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 29, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 29, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 29, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 29, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 29, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 29, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 29, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 29, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 29, + }, + ], + }, + { + key: ['PCFX'], + values: [ + { + x: 315532800000, + y: 0, + index: 0, + seriesIndex: 30, + display: { + y: 0, + y0: 312.60127789129933, + }, + series: 30, + }, + { + x: 347155200000, + y: 0, + index: 1, + seriesIndex: 30, + display: { + y: 0, + y0: 300.40627789129934, + }, + series: 30, + }, + { + x: 378691200000, + y: 0, + index: 2, + seriesIndex: 30, + display: { + y: 0, + y0: 303.8612778912993, + }, + series: 30, + }, + { + x: 410227200000, + y: 0, + index: 3, + seriesIndex: 30, + display: { + y: 0, + y0: 319.31574185794614, + }, + series: 30, + }, + { + x: 441763200000, + y: 0, + index: 4, + seriesIndex: 30, + display: { + y: 0, + y0: 305.40073292228294, + }, + series: 30, + }, + { + x: 473385600000, + y: 0, + index: 5, + seriesIndex: 30, + display: { + y: 0, + y0: 303.56220029343604, + }, + series: 30, + }, + { + x: 504921600000, + y: 0, + index: 6, + seriesIndex: 30, + display: { + y: 0, + y0: 311.7174673557506, + }, + series: 30, + }, + { + x: 536457600000, + y: 0, + index: 7, + seriesIndex: 30, + display: { + y: 0, + y0: 318.02436707976165, + }, + series: 30, + }, + { + x: 567993600000, + y: 0, + index: 8, + seriesIndex: 30, + display: { + y: 0, + y0: 305.7650172280039, + }, + series: 30, + }, + { + x: 599616000000, + y: 0, + index: 9, + seriesIndex: 30, + display: { + y: 0, + y0: 272.3260219931503, + }, + series: 30, + }, + { + x: 631152000000, + y: 0, + index: 10, + seriesIndex: 30, + display: { + y: 0, + y0: 315.774808184687, + }, + series: 30, + }, + { + x: 662688000000, + y: 0, + index: 11, + seriesIndex: 30, + display: { + y: 0, + y0: 323.71638745865533, + }, + series: 30, + }, + { + x: 694224000000, + y: 0, + index: 12, + seriesIndex: 30, + display: { + y: 0, + y0: 302.57003766873936, + }, + series: 30, + }, + { + x: 725846400000, + y: 0, + index: 13, + seriesIndex: 30, + display: { + y: 0, + y0: 331.4305531102357, + }, + series: 30, + }, + { + x: 757382400000, + y: 0, + index: 14, + seriesIndex: 30, + display: { + y: 0, + y0: 323.0765547522718, + }, + series: 30, + }, + { + x: 788918400000, + y: 0, + index: 15, + seriesIndex: 30, + display: { + y: 0, + y0: 333.68163363094624, + }, + series: 30, + }, + { + x: 820454400000, + y: 0.03, + index: 16, + seriesIndex: 30, + display: { + y: 0.03, + y0: 342.34008078133536, + }, + series: 30, + }, + { + x: 852076800000, + y: 0, + index: 17, + seriesIndex: 30, + display: { + y: 0, + y0: 367.84302062609595, + }, + series: 30, + }, + { + x: 883612800000, + y: 0, + index: 18, + seriesIndex: 30, + display: { + y: 0, + y0: 373.9932684133616, + }, + series: 30, + }, + { + x: 915148800000, + y: 0, + index: 19, + seriesIndex: 30, + display: { + y: 0, + y0: 362.96108391063547, + }, + series: 30, + }, + { + x: 946684800000, + y: 0, + index: 20, + seriesIndex: 30, + display: { + y: 0, + y0: 361.7963863019829, + }, + series: 30, + }, + { + x: 978307200000, + y: 0, + index: 21, + seriesIndex: 30, + display: { + y: 0, + y0: 335.56659853838437, + }, + series: 30, + }, + { + x: 1009843200000, + y: 0, + index: 22, + seriesIndex: 30, + display: { + y: 0, + y0: 314.639571207276, + }, + series: 30, + }, + { + x: 1041379200000, + y: 0, + index: 23, + seriesIndex: 30, + display: { + y: 0, + y0: 315.64062695689177, + }, + series: 30, + }, + { + x: 1072915200000, + y: 0, + index: 24, + seriesIndex: 30, + display: { + y: 0, + y0: 329.7065490670251, + }, + series: 30, + }, + { + x: 1104537600000, + y: 0, + index: 25, + seriesIndex: 30, + display: { + y: 0, + y0: 340.01716034240894, + }, + series: 30, + }, + { + x: 1136073600000, + y: 0, + index: 26, + seriesIndex: 30, + display: { + y: 0, + y0: 320.9383968117778, + }, + series: 30, + }, + { + x: 1167609600000, + y: 0, + index: 27, + seriesIndex: 30, + display: { + y: 0, + y0: 333.94807151274165, + }, + series: 30, + }, + { + x: 1199145600000, + y: 0, + index: 28, + seriesIndex: 30, + display: { + y: 0, + y0: 331.1800000000006, + }, + series: 30, + }, + { + x: 1230768000000, + y: 0, + index: 29, + seriesIndex: 30, + display: { + y: 0, + y0: 323.57657904990293, + }, + series: 30, + }, + { + x: 1262304000000, + y: 0, + index: 30, + seriesIndex: 30, + display: { + y: 0, + y0: 353.63872327506743, + }, + series: 30, + }, + { + x: 1293840000000, + y: 0, + index: 31, + seriesIndex: 30, + display: { + y: 0, + y0: 346.7617397094945, + }, + series: 30, + }, + { + x: 1325376000000, + y: 0, + index: 32, + seriesIndex: 30, + display: { + y: 0, + y0: 355.2033114760125, + }, + series: 30, + }, + { + x: 1356998400000, + y: 0, + index: 33, + seriesIndex: 30, + display: { + y: 0, + y0: 347.01434975261475, + }, + series: 30, + }, + { + x: 1388534400000, + y: 0, + index: 34, + seriesIndex: 30, + display: { + y: 0, + y0: 356.1414727314012, + }, + series: 30, + }, + { + x: 1420070400000, + y: 0, + index: 35, + seriesIndex: 30, + display: { + y: 0, + y0: 352.9817622110564, + }, + series: 30, + }, + { + x: 1451606400000, + y: 0, + index: 36, + seriesIndex: 30, + display: { + y: 0, + y0: 323.31515851727374, + }, + series: 30, + }, + { + x: 1483228800000, + y: 0, + index: 37, + seriesIndex: 30, + display: { + y: 0, + y0: 293.5851585172737, + }, + series: 30, + }, + ], + }, + ], + applied_filters: [], + rejected_filters: [], + }, + ], + triggerQuery: false, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'area', + slice_id: 103, + url_params: { + preselect_filters: + '{"1389": {"platform": ["PS", "PS2", "PS3", "PS4"], "genre": null, "__time_range": "No filter"}}', + }, + granularity_sqla: 'year', + time_grain_sqla: null, + time_range: 'No filter', + metrics: [ + { + aggregate: 'SUM', + column: { + column_name: 'global_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 887, + is_dttm: false, + optionName: '_col_Global_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: false, + isNew: false, + label: 'SUM(Global_Sales)', + optionName: 'metric_ufl75addr8c_oqqhdumirpn', + sqlExpression: null, + }, + ], + adhoc_filters: [], + groupby: ['platform'], + order_desc: true, + contribution: false, + row_limit: null, + show_brush: 'auto', + show_legend: false, + line_interpolation: 'linear', + stacked_style: 'stream', + color_scheme: 'supersetColors', + rich_tooltip: true, + x_axis_label: 'Year Published', + bottom_margin: 'auto', + x_ticks_layout: 'auto', + x_axis_format: 'smart_date', + x_axis_showminmax: true, + y_axis_format: 'SMART_NUMBER', + y_axis_bounds: [null, null], + rolling_type: 'None', + comparison_type: 'values', + annotation_layers: [], + label_colors: { + '0': '#1FA8C9', + '1': '#454E7C', + '2600': '#666666', + '3DO': '#B2B2B2', + '3DS': '#D1C6BC', + Action: '#1FA8C9', + Adventure: '#454E7C', + DC: '#A38F79', + DS: '#8FD3E4', + Europe: '#5AC189', + Fighting: '#5AC189', + GB: '#FDE380', + GBA: '#ACE1C4', + GC: '#5AC189', + GEN: '#3CCCCB', + GG: '#EFA1AA', + Japan: '#FF7F44', + 'Microsoft Game Studios': '#D1C6BC', + Misc: '#FF7F44', + N64: '#1FA8C9', + NES: '#9EE5E5', + NG: '#A1A6BD', + Nintendo: '#D3B3DA', + 'North America': '#666666', + Other: '#E04355', + PC: '#EFA1AA', + PCFX: '#FDE380', + PS: '#A1A6BD', + PS2: '#FCC700', + PS3: '#3CCCCB', + PS4: '#B2B2B2', + PSP: '#FEC0A1', + PSV: '#FCC700', + Platform: '#666666', + Puzzle: '#E04355', + Racing: '#FCC700', + 'Role-Playing': '#A868B7', + SAT: '#A868B7', + SCD: '#8FD3E4', + SNES: '#454E7C', + Shooter: '#3CCCCB', + Simulation: '#A38F79', + Sports: '#8FD3E4', + Strategy: '#A1A6BD', + TG16: '#FEC0A1', + 'Take-Two Interactive': '#9EE5E5', + WS: '#ACE1C4', + Wii: '#A38F79', + WiiU: '#E04355', + X360: '#A868B7', + XB: '#D3B3DA', + XOne: '#FF7F44', + }, + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + }, + }, + '113': { + id: 113, + chartAlert: null, + chartStatus: 'rendered', + chartStackTrace: null, + chartUpdateEndTime: 1673047001005, + chartUpdateStartTime: 1673046994648, + latestQueryFormData: { + datasource: '20__table', + viz_type: 'dist_bar', + slice_id: 113, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + metrics: [ + { + aggregate: 'SUM', + column: { + column_name: 'na_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 883, + is_dttm: false, + optionName: '_col_NA_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'North America', + optionName: 'metric_a943v7wg5g_0mm03hrsmpf', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'eu_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 884, + is_dttm: false, + optionName: '_col_EU_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Europe', + optionName: 'metric_bibau54x0rb_dwrjtqkbyso', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'jp_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 885, + is_dttm: false, + optionName: '_col_JP_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Japan', + optionName: 'metric_06whpr2oyhw_4l88xxu6zvd', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'other_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 886, + is_dttm: false, + optionName: '_col_Other_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Other', + optionName: 'metric_pcx05ioxums_ibr16zvi74', + sqlExpression: null, + }, + ], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: '10', + expressionType: 'SIMPLE', + filterOptionName: 'filter_juemdnqji5_d6fm8tuf4rc', + isExtra: false, + isNew: false, + operator: '<=', + sqlExpression: null, + subject: 'rank', + }, + ], + groupby: ['name'], + columns: [], + row_limit: null, + order_desc: true, + contribution: true, + color_scheme: 'supersetColors', + show_legend: true, + rich_tooltip: true, + bar_stacked: true, + y_axis_format: 'SMART_NUMBER', + y_axis_bounds: [null, null], + bottom_margin: 'auto', + x_ticks_layout: 'staggered', + queryFields: { + columns: 'groupby', + groupby: 'groupby', + metrics: 'metrics', + }, + shared_label_colors: {}, + extra_filters: [ + { + col: '__time_range', + op: '==', + val: 'No filter', + }, + ], + extra_form_data: {}, + dashboardId: 9, + }, + sliceFormData: null, + queryController: {}, + queriesResponse: [ + { + cache_key: '420a73a7c686ce86838126ba14e5c69a', + cached_dttm: null, + cache_timeout: 86400, + errors: [], + form_data: { + datasource: '20__table', + viz_type: 'dist_bar', + slice_id: 113, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + metrics: [ + { + aggregate: 'SUM', + column: { + column_name: 'na_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 883, + is_dttm: false, + optionName: '_col_NA_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'North America', + optionName: 'metric_a943v7wg5g_0mm03hrsmpf', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'eu_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 884, + is_dttm: false, + optionName: '_col_EU_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Europe', + optionName: 'metric_bibau54x0rb_dwrjtqkbyso', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'jp_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 885, + is_dttm: false, + optionName: '_col_JP_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Japan', + optionName: 'metric_06whpr2oyhw_4l88xxu6zvd', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'other_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 886, + is_dttm: false, + optionName: '_col_Other_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Other', + optionName: 'metric_pcx05ioxums_ibr16zvi74', + sqlExpression: null, + }, + ], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: '10', + expressionType: 'SIMPLE', + filterOptionName: 'filter_juemdnqji5_d6fm8tuf4rc', + isExtra: false, + isNew: false, + operator: '<=', + sqlExpression: null, + subject: 'rank', + }, + ], + groupby: ['name'], + columns: [], + row_limit: null, + order_desc: true, + contribution: true, + color_scheme: 'supersetColors', + show_legend: true, + rich_tooltip: true, + bar_stacked: true, + y_axis_format: 'SMART_NUMBER', + y_axis_bounds: [null, null], + bottom_margin: 'auto', + x_ticks_layout: 'staggered', + queryFields: { + columns: 'groupby', + groupby: 'groupby', + metrics: 'metrics', + }, + shared_label_colors: {}, + dashboardId: 9, + applied_time_extras: {}, + where: '', + having: '', + having_filters: [], + filters: [ + { + col: 'rank', + op: '<=', + val: '10', + }, + ], + }, + is_cached: false, + query: + 'SELECT name AS name,\n sum(na_sales) AS "North America",\n sum(eu_sales) AS "Europe",\n sum(jp_sales) AS "Japan",\n sum(other_sales) AS "Other"\nFROM main.video_game_sales\nWHERE rank <= 10\nGROUP BY name\nORDER BY "North America" DESC\nLIMIT 50000\nOFFSET 0', + from_dttm: null, + to_dttm: null, + status: 'success', + stacktrace: null, + rowcount: 10, + colnames: ['name', 'North America', 'Europe', 'Japan', 'Other'], + coltypes: [1, 0, 0, 0, 0], + data: [ + { + key: 'North America', + values: [ + { + x: 'Wii Sports', + y: 0.5014503263234228, + y0: 0, + series: 0, + key: 'North America', + size: 0.5014503263234228, + y1: 0.5014503263234228, + }, + { + x: 'Super Mario Bros.', + y: 0.7226640159045725, + y0: 0, + series: 0, + key: 'North America', + size: 0.7226640159045725, + y1: 0.7226640159045725, + }, + { + x: 'Duck Hunt', + y: 0.9512539738608266, + y0: 0, + series: 0, + key: 'North America', + size: 0.9512539738608266, + y1: 0.9512539738608266, + }, + { + x: 'Tetris', + y: 0.7666886979510906, + y0: 0, + series: 0, + key: 'North America', + size: 0.7666886979510906, + y1: 0.7666886979510906, + }, + { + x: 'Mario Kart Wii', + y: 0.44236673178900354, + y0: 0, + series: 0, + key: 'North America', + size: 0.44236673178900354, + y1: 0.44236673178900354, + }, + { + x: 'Wii Sports Resort', + y: 0.4772727272727273, + y0: 0, + series: 0, + key: 'North America', + size: 0.4772727272727273, + y1: 0.4772727272727273, + }, + { + x: 'New Super Mario Bros. Wii', + y: 0.5099615519049283, + y0: 0, + series: 0, + key: 'North America', + size: 0.5099615519049283, + y1: 0.5099615519049283, + }, + { + x: 'Wii Play', + y: 0.4836263357462944, + y0: 0, + series: 0, + key: 'North America', + size: 0.4836263357462944, + y1: 0.4836263357462944, + }, + { + x: 'New Super Mario Bros.', + y: 0.3792069310229924, + y0: 0, + series: 0, + key: 'North America', + size: 0.3792069310229924, + y1: 0.3792069310229924, + }, + { + x: 'Pokemon Red/Pokemon Blue', + y: 0.3591459528362014, + y0: 0, + series: 0, + key: 'North America', + size: 0.3591459528362014, + y1: 0.3591459528362014, + }, + ], + }, + { + key: 'Europe', + values: [ + { + x: 'Wii Sports', + y: 0.3507372492144065, + y0: 0.5014503263234228, + series: 1, + key: 'Europe', + size: 0.3507372492144065, + y1: 0.8521875755378293, + }, + { + x: 'Super Mario Bros.', + y: 0.0889662027833002, + y0: 0.7226640159045725, + series: 1, + key: 'Europe', + size: 0.0889662027833002, + y1: 0.8116302186878728, + }, + { + x: 'Duck Hunt', + y: 0.022253620628753093, + y0: 0.9512539738608266, + series: 1, + key: 'Europe', + size: 0.022253620628753093, + y1: 0.9735075944895797, + }, + { + x: 'Tetris', + y: 0.07468605419695969, + y0: 0.7666886979510906, + series: 1, + key: 'Europe', + size: 0.07468605419695969, + y1: 0.8413747521480504, + }, + { + x: 'Mario Kart Wii', + y: 0.35947530002790956, + y0: 0.44236673178900354, + series: 1, + key: 'Europe', + size: 0.35947530002790956, + y1: 0.801842031816913, + }, + { + x: 'Wii Sports Resort', + y: 0.3336363636363636, + y0: 0.4772727272727273, + series: 1, + key: 'Europe', + size: 0.3336363636363636, + y1: 0.8109090909090909, + }, + { + x: 'New Super Mario Bros. Wii', + y: 0.24676686473261097, + y0: 0.5099615519049283, + series: 1, + key: 'Europe', + size: 0.24676686473261097, + y1: 0.7567284166375393, + }, + { + x: 'Wii Play', + y: 0.31713202344019303, + y0: 0.4836263357462944, + series: 1, + key: 'Europe', + size: 0.31713202344019303, + y1: 0.8007583591864874, + }, + { + x: 'New Super Mario Bros.', + y: 0.30756414528490506, + y0: 0.3792069310229924, + series: 1, + key: 'Europe', + size: 0.30756414528490506, + y1: 0.6867710763078975, + }, + { + x: 'Pokemon Red/Pokemon Blue', + y: 0.28330146590184835, + y0: 0.3591459528362014, + series: 1, + key: 'Europe', + size: 0.28330146590184835, + y1: 0.6424474187380498, + }, + ], + }, + { + key: 'Japan', + values: [ + { + x: 'Wii Sports', + y: 0.04556441866086536, + y0: 0.8521875755378293, + series: 2, + key: 'Japan', + size: 0.04556441866086536, + y1: 0.8977519941986947, + }, + { + x: 'Super Mario Bros.', + y: 0.169234592445328, + y0: 0.8116302186878728, + series: 2, + key: 'Japan', + size: 0.169234592445328, + y1: 0.9808648111332008, + }, + { + x: 'Duck Hunt', + y: 0.009890498057223597, + y0: 0.9735075944895797, + series: 2, + key: 'Japan', + size: 0.009890498057223597, + y1: 0.9833980925468033, + }, + { + x: 'Tetris', + y: 0.1394580304031725, + y0: 0.8413747521480504, + series: 2, + key: 'Japan', + size: 0.1394580304031725, + y1: 0.9808327825512229, + }, + { + x: 'Mario Kart Wii', + y: 0.1057772816075914, + y0: 0.801842031816913, + series: 2, + key: 'Japan', + size: 0.1057772816075914, + y1: 0.9076193134245044, + }, + { + x: 'Wii Sports Resort', + y: 0.09939393939393938, + y0: 0.8109090909090909, + series: 2, + key: 'Japan', + size: 0.09939393939393938, + y1: 0.9103030303030303, + }, + { + x: 'New Super Mario Bros. Wii', + y: 0.16427822439706397, + y0: 0.7567284166375393, + series: 2, + key: 'Japan', + size: 0.16427822439706397, + y1: 0.9210066410346033, + }, + { + x: 'Wii Play', + y: 0.10099965529127888, + y0: 0.8007583591864874, + series: 2, + key: 'Japan', + size: 0.10099965529127888, + y1: 0.9017580144777663, + }, + { + x: 'New Super Mario Bros.', + y: 0.21659446851049652, + y0: 0.6867710763078975, + series: 2, + key: 'Japan', + size: 0.21659446851049652, + y1: 0.9033655448183939, + }, + { + x: 'Pokemon Red/Pokemon Blue', + y: 0.32568514977692803, + y0: 0.6424474187380498, + series: 2, + key: 'Japan', + size: 0.32568514977692803, + y1: 0.9681325685149778, + }, + ], + }, + { + key: 'Other', + values: [ + { + x: 'Wii Sports', + y: 0.10224800580130529, + y0: 0.8977519941986947, + series: 3, + key: 'Other', + size: 0.10224800580130529, + y1: 1, + }, + { + x: 'Super Mario Bros.', + y: 0.019135188866799203, + y0: 0.9808648111332008, + series: 3, + key: 'Other', + size: 0.019135188866799203, + y1: 1, + }, + { + x: 'Duck Hunt', + y: 0.01660190745319675, + y0: 0.9833980925468033, + series: 3, + key: 'Other', + size: 0.01660190745319675, + y1: 1, + }, + { + x: 'Tetris', + y: 0.019167217448777262, + y0: 0.9808327825512229, + series: 3, + key: 'Other', + size: 0.019167217448777262, + y1: 1.0000000000000002, + }, + { + x: 'Mario Kart Wii', + y: 0.09238068657549538, + y0: 0.9076193134245044, + series: 3, + key: 'Other', + size: 0.09238068657549538, + y1: 0.9999999999999998, + }, + { + x: 'Wii Sports Resort', + y: 0.08969696969696969, + y0: 0.9103030303030303, + series: 3, + key: 'Other', + size: 0.08969696969696969, + y1: 1, + }, + { + x: 'New Super Mario Bros. Wii', + y: 0.0789933589653967, + y0: 0.9210066410346033, + series: 3, + key: 'Other', + size: 0.0789933589653967, + y1: 1, + }, + { + x: 'Wii Play', + y: 0.09824198552223372, + y0: 0.9017580144777663, + series: 3, + key: 'Other', + size: 0.09824198552223372, + y1: 1, + }, + { + x: 'New Super Mario Bros.', + y: 0.09663445518160614, + y0: 0.9033655448183939, + series: 3, + key: 'Other', + size: 0.09663445518160614, + y1: 1, + }, + { + x: 'Pokemon Red/Pokemon Blue', + y: 0.03186743148502231, + y0: 0.9681325685149778, + series: 3, + key: 'Other', + size: 0.03186743148502231, + y1: 1, + }, + ], + }, + ], + applied_filters: [ + { + column: 'rank', + }, + ], + rejected_filters: [], + }, + ], + triggerQuery: false, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'dist_bar', + slice_id: 113, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + metrics: [ + { + aggregate: 'SUM', + column: { + column_name: 'na_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 883, + is_dttm: false, + optionName: '_col_NA_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'North America', + optionName: 'metric_a943v7wg5g_0mm03hrsmpf', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'eu_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 884, + is_dttm: false, + optionName: '_col_EU_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Europe', + optionName: 'metric_bibau54x0rb_dwrjtqkbyso', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'jp_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 885, + is_dttm: false, + optionName: '_col_JP_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Japan', + optionName: 'metric_06whpr2oyhw_4l88xxu6zvd', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'other_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 886, + is_dttm: false, + optionName: '_col_Other_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Other', + optionName: 'metric_pcx05ioxums_ibr16zvi74', + sqlExpression: null, + }, + ], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: '10', + expressionType: 'SIMPLE', + filterOptionName: 'filter_juemdnqji5_d6fm8tuf4rc', + isExtra: false, + isNew: false, + operator: '<=', + sqlExpression: null, + subject: 'rank', + }, + ], + groupby: ['name'], + columns: [], + row_limit: null, + order_desc: true, + contribution: true, + color_scheme: 'supersetColors', + show_legend: true, + rich_tooltip: true, + bar_stacked: true, + y_axis_format: 'SMART_NUMBER', + y_axis_bounds: [null, null], + bottom_margin: 'auto', + x_ticks_layout: 'staggered', + label_colors: {}, + queryFields: { + columns: 'groupby', + groupby: 'groupby', + metrics: 'metrics', + }, + }, + }, + '120': { + id: 120, + chartAlert: null, + chartStatus: 'loading', + chartStackTrace: null, + chartUpdateEndTime: null, + chartUpdateStartTime: 0, + latestQueryFormData: {}, + sliceFormData: null, + queryController: null, + queriesResponse: null, + triggerQuery: true, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'dist_bar', + slice_id: 120, + url_params: { + preselect_filters: + '{"1389": {"platform": ["PS", "PS2", "PS3", "PS4"], "genre": null, "__time_range": "No filter"}}', + }, + granularity_sqla: 'year', + time_range: 'No filter', + metrics: [ + { + aggregate: 'SUM', + column: { + column_name: 'na_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 883, + is_dttm: false, + optionName: '_col_NA_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'North America', + optionName: 'metric_3pl6jwmyd72_p9o4j2xxgyp', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'eu_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 884, + is_dttm: false, + optionName: '_col_EU_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Europe', + optionName: 'metric_e8rdyfxxjdu_6dgyhf7xcne', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'jp_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 885, + is_dttm: false, + optionName: '_col_JP_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Japan', + optionName: 'metric_6gesefugzy6_517l3wowdwu', + sqlExpression: null, + }, + { + aggregate: 'SUM', + column: { + column_name: 'other_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 886, + is_dttm: false, + optionName: '_col_Other_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: true, + isNew: false, + label: 'Other', + optionName: 'metric_cf6kbre28f_2sg5b5pfq5a', + sqlExpression: null, + }, + ], + adhoc_filters: [], + groupby: ['genre'], + columns: [], + row_limit: null, + order_desc: true, + contribution: false, + color_scheme: 'supersetColors', + show_legend: true, + show_bar_value: false, + rich_tooltip: true, + bar_stacked: true, + order_bars: false, + y_axis_format: 'SMART_NUMBER', + show_controls: true, + y_axis_bounds: [null, null], + x_axis_label: 'Genre', + bottom_margin: 'auto', + x_ticks_layout: 'flat', + label_colors: { + '0': '#1FA8C9', + '1': '#454E7C', + '2600': '#666666', + '3DO': '#B2B2B2', + '3DS': '#D1C6BC', + Action: '#1FA8C9', + Adventure: '#454E7C', + DC: '#A38F79', + DS: '#8FD3E4', + Europe: '#5AC189', + Fighting: '#5AC189', + GB: '#FDE380', + GBA: '#ACE1C4', + GC: '#5AC189', + GEN: '#3CCCCB', + GG: '#EFA1AA', + Japan: '#FF7F44', + 'Microsoft Game Studios': '#D1C6BC', + Misc: '#FF7F44', + N64: '#1FA8C9', + NES: '#9EE5E5', + NG: '#A1A6BD', + Nintendo: '#D3B3DA', + 'North America': '#666666', + Other: '#E04355', + PC: '#EFA1AA', + PCFX: '#FDE380', + PS: '#A1A6BD', + PS2: '#FCC700', + PS3: '#3CCCCB', + PS4: '#B2B2B2', + PSP: '#FEC0A1', + PSV: '#FCC700', + Platform: '#666666', + Puzzle: '#E04355', + Racing: '#FCC700', + 'Role-Playing': '#A868B7', + SAT: '#A868B7', + SCD: '#8FD3E4', + SNES: '#454E7C', + Shooter: '#3CCCCB', + Simulation: '#A38F79', + Sports: '#8FD3E4', + Strategy: '#A1A6BD', + TG16: '#FEC0A1', + 'Take-Two Interactive': '#9EE5E5', + WS: '#ACE1C4', + Wii: '#A38F79', + WiiU: '#E04355', + X360: '#A868B7', + XB: '#D3B3DA', + XOne: '#FF7F44', + }, + queryFields: { + columns: 'groupby', + groupby: 'groupby', + metrics: 'metrics', + }, + }, + }, + '123': { + id: 123, + chartAlert: null, + chartStatus: 'rendered', + chartStackTrace: null, + chartUpdateEndTime: 1673046998143, + chartUpdateStartTime: 1673046994604, + latestQueryFormData: { + datasource: '20__table', + viz_type: 'pie', + slice_id: 123, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + groupby: ['publisher'], + metric: { + aggregate: 'SUM', + column: { + column_name: 'global_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 887, + is_dttm: false, + optionName: '_col_Global_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: false, + isNew: false, + label: 'SUM(Global_Sales)', + optionName: 'metric_k2rqz0zqhkf_49hu4kq9h3u', + sqlExpression: null, + }, + adhoc_filters: [ + { + clause: 'WHERE', + comparator: '25', + expressionType: 'SIMPLE', + filterOptionName: 'filter_znxs4o61aod_n5blgxo29r', + isExtra: false, + isNew: false, + operator: '<=', + sqlExpression: null, + subject: 'rank', + }, + ], + row_limit: null, + sort_by_metric: true, + color_scheme: 'supersetColors', + show_labels_threshold: 5, + show_legend: false, + legendType: 'scroll', + legendOrientation: 'top', + label_type: 'key', + number_format: 'SMART_NUMBER', + date_format: 'smart_date', + show_labels: true, + labels_outside: true, + label_line: true, + outerRadius: 67, + donut: true, + innerRadius: 45, + queryFields: { + groupby: 'groupby', + metric: 'metrics', + }, + label_colors: { + '0': '#1FA8C9', + '1': '#454E7C', + '2600': '#666666', + Europe: '#5AC189', + Japan: '#FF7F44', + 'North America': '#666666', + Other: '#E04355', + PS2: '#FCC700', + X360: '#A868B7', + PS3: '#3CCCCB', + Wii: '#A38F79', + DS: '#8FD3E4', + PS: '#A1A6BD', + GBA: '#ACE1C4', + PSP: '#FEC0A1', + PS4: '#B2B2B2', + PC: '#EFA1AA', + GB: '#FDE380', + XB: '#D3B3DA', + NES: '#9EE5E5', + '3DS': '#D1C6BC', + N64: '#1FA8C9', + SNES: '#454E7C', + GC: '#5AC189', + XOne: '#FF7F44', + WiiU: '#E04355', + PSV: '#FCC700', + SAT: '#A868B7', + GEN: '#3CCCCB', + DC: '#A38F79', + SCD: '#8FD3E4', + NG: '#A1A6BD', + WS: '#ACE1C4', + TG16: '#FEC0A1', + '3DO': '#B2B2B2', + GG: '#EFA1AA', + PCFX: '#FDE380', + Nintendo: '#D3B3DA', + 'Take-Two Interactive': '#9EE5E5', + 'Microsoft Game Studios': '#D1C6BC', + Action: '#1FA8C9', + Adventure: '#454E7C', + Fighting: '#5AC189', + Misc: '#FF7F44', + Platform: '#666666', + Puzzle: '#E04355', + Racing: '#FCC700', + 'Role-Playing': '#A868B7', + Shooter: '#3CCCCB', + Simulation: '#A38F79', + Sports: '#8FD3E4', + Strategy: '#A1A6BD', + }, + shared_label_colors: {}, + extra_filters: [ + { + col: '__time_range', + op: '==', + val: 'No filter', + }, + ], + extra_form_data: {}, + dashboardId: 9, + }, + sliceFormData: null, + queryController: {}, + queriesResponse: [ + { + cache_key: '18929e0056e248f9ae6e413e91a3e0ef', + cached_dttm: null, + cache_timeout: 86400, + applied_template_filters: [], + annotation_data: {}, + error: null, + is_cached: null, + query: + 'SELECT publisher AS publisher,\n sum(global_sales) AS "SUM(Global_Sales)"\nFROM main.video_game_sales\nWHERE rank <= 25\nGROUP BY publisher\nORDER BY "SUM(Global_Sales)" DESC\nLIMIT 50000\nOFFSET 0;\n\n', + status: 'success', + stacktrace: null, + rowcount: 3, + from_dttm: null, + to_dttm: null, + label_map: { + publisher: ['publisher'], + 'SUM(Global_Sales)': ['SUM(Global_Sales)'], + }, + colnames: ['publisher', 'SUM(Global_Sales)'], + indexnames: [0, 1, 2], + coltypes: [1, 0], + data: [ + { + publisher: 'Nintendo', + 'SUM(Global_Sales)': 580, + }, + { + publisher: 'Take-Two Interactive', + 'SUM(Global_Sales)': 74.73999999999998, + }, + { + publisher: 'Microsoft Game Studios', + 'SUM(Global_Sales)': 21.82, + }, + ], + result_format: 'json', + applied_filters: [ + { + column: 'rank', + }, + { + column: '__time_range', + }, + ], + rejected_filters: [], + }, + ], + triggerQuery: false, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'pie', + slice_id: 123, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + groupby: ['publisher'], + metric: { + aggregate: 'SUM', + column: { + column_name: 'global_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 887, + is_dttm: false, + optionName: '_col_Global_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: false, + isNew: false, + label: 'SUM(Global_Sales)', + optionName: 'metric_k2rqz0zqhkf_49hu4kq9h3u', + sqlExpression: null, + }, + adhoc_filters: [ + { + clause: 'WHERE', + comparator: '25', + expressionType: 'SIMPLE', + filterOptionName: 'filter_znxs4o61aod_n5blgxo29r', + isExtra: false, + isNew: false, + operator: '<=', + sqlExpression: null, + subject: 'rank', + }, + ], + row_limit: null, + sort_by_metric: true, + color_scheme: 'supersetColors', + show_labels_threshold: 5, + show_legend: false, + legendType: 'scroll', + legendOrientation: 'top', + label_type: 'key', + number_format: 'SMART_NUMBER', + date_format: 'smart_date', + show_labels: true, + labels_outside: true, + label_line: true, + outerRadius: 67, + donut: true, + innerRadius: 45, + queryFields: { + groupby: 'groupby', + metric: 'metrics', + }, + }, + }, + '125': { + id: 125, + chartAlert: null, + chartStatus: 'rendered', + chartStackTrace: null, + chartUpdateEndTime: 1673046997626, + chartUpdateStartTime: 1673046994618, + latestQueryFormData: { + datasource: '20__table', + viz_type: 'treemap', + slice_id: 125, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + metrics: ['count'], + adhoc_filters: [], + groupby: ['platform'], + row_limit: 10, + order_desc: true, + color_scheme: 'supersetColors', + treemap_ratio: 1.618033988749895, + number_format: 'SMART_NUMBER', + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + shared_label_colors: {}, + extra_filters: [ + { + col: '__time_range', + op: '==', + val: 'No filter', + }, + ], + dashboardId: 9, + }, + sliceFormData: null, + queryController: {}, + queriesResponse: [ + { + cache_key: '9a7e15121b29cddbb238559d031557df', + cached_dttm: null, + cache_timeout: 86400, + errors: [], + form_data: { + datasource: '20__table', + viz_type: 'treemap', + slice_id: 125, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + metrics: ['count'], + adhoc_filters: [], + groupby: ['platform'], + row_limit: 10, + order_desc: true, + color_scheme: 'supersetColors', + treemap_ratio: 1.618033988749895, + number_format: 'SMART_NUMBER', + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + shared_label_colors: {}, + dashboardId: 9, + applied_time_extras: {}, + where: '', + having: '', + having_filters: [], + filters: [], + }, + is_cached: false, + query: + 'SELECT platform AS platform,\n COUNT(*) AS count\nFROM main.video_game_sales\nGROUP BY platform\nLIMIT 10\nOFFSET 0', + from_dttm: null, + to_dttm: null, + status: 'success', + stacktrace: null, + rowcount: 10, + colnames: ['platform', 'count'], + coltypes: [1, 0], + data: [ + { + name: 'count', + children: [ + { + name: '2600', + value: 133, + }, + { + name: '3DO', + value: 3, + }, + { + name: '3DS', + value: 509, + }, + { + name: 'DC', + value: 52, + }, + { + name: 'DS', + value: 2162, + }, + { + name: 'GB', + value: 98, + }, + { + name: 'GBA', + value: 822, + }, + { + name: 'GC', + value: 556, + }, + { + name: 'GEN', + value: 27, + }, + { + name: 'GG', + value: 1, + }, + ], + }, + ], + applied_filters: [], + rejected_filters: [], + }, + ], + triggerQuery: false, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'treemap', + slice_id: 125, + url_params: {}, + granularity_sqla: 'year', + time_range: 'No filter', + metrics: ['count'], + adhoc_filters: [], + groupby: ['platform'], + row_limit: 10, + order_desc: true, + color_scheme: 'supersetColors', + treemap_ratio: 1.618033988749895, + number_format: 'SMART_NUMBER', + label_colors: { + '2600': '#D1C6BC', + '3DO': '#A38F79', + '3DS': '#B2B2B2', + Action: '#ACE1C4', + Adventure: '#5AC189', + 'COUNT(*)': '#1FA8C9', + DC: '#666666', + DS: '#E04355', + Fighting: '#D1C6BC', + GB: '#A1A6BD', + GBA: '#A868B7', + GC: '#D3B3DA', + GEN: '#FF7F44', + GG: '#8FD3E4', + 'Microsoft Game Studios': '#FCC700', + Misc: '#D3B3DA', + N64: '#EFA1AA', + NES: '#FEC0A1', + NG: '#FCC700', + Nintendo: '#666666', + PC: '#8FD3E4', + PCFX: '#A1A6BD', + PS: '#FCC700', + PS2: '#454E7C', + PS3: '#FF7F44', + PS4: '#A38F79', + PSP: '#3CCCCB', + PSV: '#454E7C', + Platform: '#FDE380', + Puzzle: '#454E7C', + Racing: '#9EE5E5', + 'Role-Playing': '#EFA1AA', + SAT: '#5AC189', + SCD: '#E04355', + SNES: '#FDE380', + Shooter: '#B2B2B2', + Simulation: '#1FA8C9', + Sports: '#FEC0A1', + Strategy: '#FF7F44', + TG16: '#3CCCCB', + 'Take-Two Interactive': '#E04355', + WS: '#A868B7', + Wii: '#666666', + WiiU: '#1FA8C9', + X360: '#5AC189', + XB: '#ACE1C4', + XOne: '#9EE5E5', + }, + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + }, + }, + '127': { + id: 127, + chartAlert: null, + chartStatus: 'loading', + chartStackTrace: null, + chartUpdateEndTime: null, + chartUpdateStartTime: 0, + latestQueryFormData: {}, + sliceFormData: null, + queryController: null, + queriesResponse: null, + triggerQuery: true, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'filter_box', + slice_id: 127, + url_params: { + preselect_filters: + '{"1389": {"platform": ["PS", "PS2", "PS3", "PS4"], "genre": null, "__time_range": "No filter"}}', + }, + granularity_sqla: 'Year', + time_range: 'No filter', + filter_configs: [ + { + asc: true, + clearable: true, + column: 'platform', + key: 's3ItH9vhG', + label: 'Platform', + multiple: true, + searchAllOptions: false, + }, + { + asc: true, + clearable: true, + column: 'genre', + key: '202hDeMsG', + label: 'Genre', + multiple: true, + searchAllOptions: false, + }, + { + asc: true, + clearable: true, + column: 'publisher', + key: '5Os6jsJFK', + label: 'Publisher', + multiple: true, + searchAllOptions: false, + }, + ], + date_filter: true, + adhoc_filters: [], + queryFields: {}, + }, + }, + '131': { + id: 131, + chartAlert: null, + chartStatus: 'loading', + chartStackTrace: null, + chartUpdateEndTime: null, + chartUpdateStartTime: 0, + latestQueryFormData: {}, + sliceFormData: null, + queryController: null, + queriesResponse: null, + triggerQuery: true, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'treemap', + slice_id: 131, + url_params: { + preselect_filters: + '{"1389": {"platform": ["PS", "PS2", "PS3", "PS4"], "genre": null, "__time_range": "No filter"}}', + }, + granularity_sqla: 'year', + time_range: 'No filter', + metrics: ['count'], + adhoc_filters: [], + groupby: ['genre'], + row_limit: null, + order_desc: true, + color_scheme: 'supersetColors', + treemap_ratio: 1.618033988749895, + number_format: 'SMART_NUMBER', + label_colors: { + '0': '#1FA8C9', + '1': '#454E7C', + '2600': '#666666', + '3DO': '#B2B2B2', + '3DS': '#D1C6BC', + Action: '#1FA8C9', + Adventure: '#454E7C', + DC: '#A38F79', + DS: '#8FD3E4', + Europe: '#5AC189', + Fighting: '#5AC189', + GB: '#FDE380', + GBA: '#ACE1C4', + GC: '#5AC189', + GEN: '#3CCCCB', + GG: '#EFA1AA', + Japan: '#FF7F44', + 'Microsoft Game Studios': '#D1C6BC', + Misc: '#FF7F44', + N64: '#1FA8C9', + NES: '#9EE5E5', + NG: '#A1A6BD', + Nintendo: '#D3B3DA', + 'North America': '#666666', + Other: '#E04355', + PC: '#EFA1AA', + PCFX: '#FDE380', + PS: '#A1A6BD', + PS2: '#FCC700', + PS3: '#3CCCCB', + PS4: '#B2B2B2', + PSP: '#FEC0A1', + PSV: '#FCC700', + Platform: '#666666', + Puzzle: '#E04355', + Racing: '#FCC700', + 'Role-Playing': '#A868B7', + SAT: '#A868B7', + SCD: '#8FD3E4', + SNES: '#454E7C', + Shooter: '#3CCCCB', + Simulation: '#A38F79', + Sports: '#8FD3E4', + Strategy: '#A1A6BD', + TG16: '#FEC0A1', + 'Take-Two Interactive': '#9EE5E5', + WS: '#ACE1C4', + Wii: '#A38F79', + WiiU: '#E04355', + X360: '#A868B7', + XB: '#D3B3DA', + XOne: '#FF7F44', + }, + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + }, + }, + '132': { + id: 132, + chartAlert: null, + chartStatus: 'loading', + chartStackTrace: null, + chartUpdateEndTime: null, + chartUpdateStartTime: 0, + latestQueryFormData: {}, + sliceFormData: null, + queryController: null, + queriesResponse: null, + triggerQuery: true, + lastRendered: 0, + form_data: { + datasource: '20__table', + viz_type: 'table', + slice_id: 132, + url_params: {}, + granularity_sqla: 'year', + time_grain_sqla: 'P1D', + time_range: 'No filter', + query_mode: 'raw', + groupby: ['name'], + metrics: [ + { + aggregate: 'SUM', + column: { + column_name: 'global_sales', + description: null, + expression: null, + filterable: true, + groupby: true, + id: 887, + is_dttm: false, + optionName: '_col_Global_Sales', + python_date_format: null, + type: 'DOUBLE PRECISION', + verbose_name: null, + }, + expressionType: 'SIMPLE', + hasCustomLabel: false, + isNew: false, + label: 'SUM(Global_Sales)', + optionName: 'metric_pkpvgdsf70d_pnqv77v0x2p', + sqlExpression: null, + }, + ], + all_columns: [ + 'name', + 'global_sales', + 'platform', + 'genre', + 'publisher', + 'year', + ], + percent_metrics: [], + adhoc_filters: [], + order_by_cols: ['["global_sales", false]'], + row_limit: null, + server_page_length: 10, + order_desc: true, + table_timestamp_format: 'smart_date', + page_length: '15', + include_search: true, + show_cell_bars: false, + color_pn: false, + queryFields: { + groupby: 'groupby', + metrics: 'metrics', + }, + table_filter: false, + }, + }, + }; + + const validNodes = [ + 'ROOT_ID', + 'TABS-97PVJa11D_', + 'TAB-2_QXp8aNq', + 'ROW-fjg6YQBkH', + 'CHART-1L7NIcXvVN', + 'ROW-yP9SB89PZ', + 'CHART-7mKdnU7OUJ', + 'TAB-lg-5ymUDgm', + 'ROW-7kAf1blYU', + 'CHART-8OG3UJX-Tn', + 'CHART-W02beJK7ms', + 'CHART-XFag0yZdLk', + 'ROW-NuR8GFQTO', + 'CHART-XRvRfsMsaQ', + 'CHART-XVIYTeubZh', + 'CHART-_sx22yawJO', + 'CHART-nYns6xr4Ft', + 'COLUMN-F53B1OSMcz', + 'CHART-uP9GF0z0rT', + 'ROW-XT1DsNA_V', + 'CHART-wt6ZO8jRXZ', + ]; + + const initiallyExcludedCharts: number[] = []; + it('Succeeds with valid', () => { + expect(() => { + buildTree( + // @ts-ignore + node, + treeItem, + layout, + charts, + validNodes, + initiallyExcludedCharts, + () => 'Fake title', + ); + }).not.toThrowError(); + }); + + it('Avoids runtime error with invalid inputs', () => { + expect(() => { + buildTree( + // @ts-expect-error + undefined, + treeItem, + layout, + charts, + validNodes, + initiallyExcludedCharts, + () => 'Fake title', + ); + }).not.toThrowError(); + + expect(() => { + buildTree( + // @ts-expect-error + node, + null, + layout, + charts, + validNodes, + initiallyExcludedCharts, + () => 'Fake title', + ); + }).not.toThrowError(); + + expect(() => { + buildTree( + // @ts-expect-error + node, + treeItem, + null, + charts, + validNodes, + initiallyExcludedCharts, + () => 'Fake title', + ); + }).not.toThrowError(); + + expect(() => { + buildTree( + // @ts-expect-error + node, + treeItem, + layout, + null, + validNodes, + initiallyExcludedCharts, + () => 'Fake title', + ); + }).not.toThrowError(); + + expect(() => { + buildTree( + // @ts-expect-error + node, + treeItem, + layout, + charts, + null, + initiallyExcludedCharts, + () => 'Fake title', + ); + }).not.toThrowError(); + + expect(() => { + buildTree( + // @ts-expect-error + node, + treeItem, + layout, + charts, + validNodes, + null, + () => 'Fake title', + ); + }).not.toThrowError(); + }); +}); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.ts index 4bf04c7e957bf..347da2d2ca687 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.ts @@ -23,12 +23,20 @@ import { TAB_TYPE, } from 'src/dashboard/util/componentTypes'; import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants'; -import { NativeFilterScope, t } from '@superset-ui/core'; +import { logging, NativeFilterScope, t } from '@superset-ui/core'; import { BuildTreeLeafTitle, TreeItem } from './types'; export const isShowTypeInTree = ({ type, meta }: LayoutItem, charts?: Charts) => (type === TAB_TYPE || type === CHART_TYPE || type === DASHBOARD_ROOT_TYPE) && - (!charts || charts[meta?.chartId]?.formData?.viz_type !== 'filter_box'); + (!charts || charts[meta?.chartId]?.form_data?.viz_type !== 'filter_box'); + +export const getNodeTitle = (node: LayoutItem) => + node?.meta?.sliceNameOverride ?? + node?.meta?.sliceName ?? + node?.meta?.text ?? + node?.meta?.defaultText ?? + node?.id?.toString?.() ?? + ''; export const buildTree = ( node: LayoutItem, @@ -41,17 +49,15 @@ export const buildTree = ( ) => { let itemToPass: TreeItem = treeItem; if ( + node && + treeItem && isShowTypeInTree(node, charts) && node.type !== DASHBOARD_ROOT_TYPE && - validNodes.includes(node.id) + validNodes?.includes?.(node.id) ) { const title = buildTreeLeafTitle( - node.meta.sliceNameOverride || - node.meta.sliceName || - node.meta.text || - node.meta.defaultText || - node.id.toString(), - initiallyExcludedCharts.includes(node.meta?.chartId), + getNodeTitle(node), + initiallyExcludedCharts?.includes?.(node.meta?.chartId), t( "This chart might be incompatible with the filter (datasets don't match)", ), @@ -65,17 +71,24 @@ export const buildTree = ( treeItem.children.push(currentTreeItem); itemToPass = currentTreeItem; } - node.children.forEach(child => - buildTree( - layout[child], - itemToPass, - layout, - charts, - validNodes, - initiallyExcludedCharts, - buildTreeLeafTitle, - ), - ); + node?.children?.forEach?.(child => { + const node = layout?.[child]; + if (node) { + buildTree( + node, + itemToPass, + layout, + charts, + validNodes, + initiallyExcludedCharts, + buildTreeLeafTitle, + ); + } else { + logging.warn( + `Unable to find item with id: ${child} in the dashboard layout. This may indicate you have invalid references in your dashboard and the references to id: ${child} should be removed.`, + ); + } + }); }; const addInvisibleParents = (layout: Layout, item: string) => [ diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx index fc7092b0176ed..0f61aeb04b141 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx @@ -191,10 +191,6 @@ export const StyledLabel = styled.span` text-transform: uppercase; `; -export const StyledCheckboxFormItem = styled(FormItem)` - margin-bottom: 0; -`; - const CleanFormItem = styled(FormItem)` margin-bottom: 0; `; @@ -262,6 +258,19 @@ const StyledAsterisk = styled.span` } `; +const FilterTypeInfo = styled.div` + ${({ theme }) => ` + width: 49%; + font-size: ${theme.typography.sizes.s}px; + color: ${theme.colors.grayscale.light1}; + margin: + ${-theme.gridUnit * 2}px + 0px + ${theme.gridUnit * 4}px + ${theme.gridUnit * 4}px; + `} +`; + const FilterTabs = { configuration: { key: 'configuration', @@ -337,6 +346,7 @@ const FiltersConfigForm = ( setErroredFilters, validateDependencies, getDependencySuggestion, + isActive, }: FiltersConfigFormProps, ref: React.RefObject<any>, ) => { @@ -351,7 +361,7 @@ const FiltersConfigForm = ( string, any > | null>(null); - const forceUpdate = useForceUpdate(); + const forceUpdate = useForceUpdate(isActive); const [datasetDetails, setDatasetDetails] = useState<Record<string, any>>(); const defaultFormFilter = useMemo(() => ({}), []); const filters = form.getFieldValue('filters'); @@ -693,7 +703,7 @@ const FiltersConfigForm = ( } Object.values(charts).forEach((chart: Chart) => { - const chartDatasetUid = chart.formData?.datasource; + const chartDatasetUid = chart.form_data?.datasource; if (chartDatasetUid === undefined) { return; } @@ -799,6 +809,13 @@ const FiltersConfigForm = ( /> </StyledFormItem> </StyledContainer> + {formFilter?.filterType === 'filter_time' && ( + <FilterTypeInfo> + {t(`Dashboard time range filters apply to temporal columns defined in + the filter section of each chart. Add temporal columns to the chart + filters to have this dashboard filter impact those charts.`)} + </FilterTypeInfo> + )} {hasDataset && ( <StyledRowContainer> {showDataset ? ( @@ -844,7 +861,7 @@ const FiltersConfigForm = ( </StyledRowContainer> )} <StyledCollapse - activeKey={activeFilterPanelKeys} + defaultActiveKey={activeFilterPanelKeys} onChange={key => { handleActiveFilterPanelChange(key); }} @@ -1248,6 +1265,8 @@ const FiltersConfigForm = ( ); }; -export default forwardRef<typeof FiltersConfigForm, FiltersConfigFormProps>( - FiltersConfigForm, +export default React.memo( + forwardRef<typeof FiltersConfigForm, FiltersConfigFormProps>( + FiltersConfigForm, + ), ); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx index 22078c26a926b..ec43e4aa59294 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx @@ -129,7 +129,7 @@ export default function getControlItemsMap({ doesColumnMatchFilterType(formFilter?.filterType || '', column) } onChange={() => { - // We need reset default value when when column changed + // We need reset default value when column changed setNativeFilterFieldValues(form, filterId, { defaultDataMask: null, }); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts index 538f5ce88bfb3..66ab7f8e8ba40 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts @@ -44,9 +44,13 @@ export const FILTER_SUPPORTED_TYPES = { filter_range: [GenericDataType.NUMERIC], }; -export const useForceUpdate = () => { +export const useForceUpdate = (isActive = true) => { const [, updateState] = React.useState({}); - return React.useCallback(() => updateState({}), []); + return React.useCallback(() => { + if (isActive) { + updateState({}); + } + }, [isActive]); }; export const setNativeFilterFieldValues = ( @@ -117,7 +121,7 @@ export const mostUsedDataset = ( let maxCount = 0; Object.values(charts).forEach(chart => { - const { formData } = chart; + const { form_data: formData } = chart; if (formData) { const { datasource } = formData; const count = (map.get(datasource) || 0) + 1; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx index 80126fe6a9256..58ebcea548bc4 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx @@ -32,8 +32,7 @@ import { TimeFilterPlugin, TimeGrainFilterPlugin, } from 'src/filters/components'; -import { - FiltersConfigModal, +import FiltersConfigModal, { FiltersConfigModalProps, } from './FiltersConfigModal'; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx index d258b34fa7489..fa7ef238e8f7e 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx @@ -23,7 +23,7 @@ import React, { useState, useRef, } from 'react'; -import { uniq, isEqual, sortBy, debounce } from 'lodash'; +import { uniq, isEqual, sortBy, debounce, isEmpty } from 'lodash'; import { Filter, FilterConfiguration, @@ -91,6 +91,12 @@ export interface FiltersConfigModalProps { } export const ALLOW_DEPENDENCIES = ['filter_select']; +const DEFAULT_EMPTY_FILTERS: string[] = []; +const DEFAULT_REMOVED_FILTERS: Record<string, FilterRemoval> = {}; +const DEFAULT_FORM_VALUES: NativeFiltersForm = { + filters: {}, +}; + /** * This is the modal to configure all the dashboard-native filters. * Manages modal-level state, such as what filters are in the list, @@ -99,7 +105,7 @@ export const ALLOW_DEPENDENCIES = ['filter_select']; * Calls the `save` callback with the new FilterConfiguration object * when the user saves the filters. */ -export function FiltersConfigModal({ +function FiltersConfigModal({ isOpen, initialFilterId, createNewOnOpen, @@ -116,14 +122,16 @@ export function FiltersConfigModal({ // new filter ids belong to filters have been added during // this configuration session, and only exist in the form state until we submit. - const [newFilterIds, setNewFilterIds] = useState<string[]>([]); + const [newFilterIds, setNewFilterIds] = useState<string[]>( + DEFAULT_EMPTY_FILTERS, + ); // store ids of filters that have been removed with the time they were removed // so that we can disappear them after a few secs. // filters are still kept in state until form is submitted. const [removedFilters, setRemovedFilters] = useState< Record<string, FilterRemoval> - >({}); + >(DEFAULT_REMOVED_FILTERS); const [saveAlertVisible, setSaveAlertVisible] = useState<boolean>(false); @@ -143,28 +151,39 @@ export function FiltersConfigModal({ const [currentFilterId, setCurrentFilterId] = useState( initialCurrentFilterId, ); - const [erroredFilters, setErroredFilters] = useState<string[]>([]); + const [erroredFilters, setErroredFilters] = useState<string[]>( + DEFAULT_EMPTY_FILTERS, + ); // the form values are managed by the antd form, but we copy them to here // so that we can display them (e.g. filter titles in the tab headers) - const [formValues, setFormValues] = useState<NativeFiltersForm>({ - filters: {}, - }); + const [formValues, setFormValues] = + useState<NativeFiltersForm>(DEFAULT_FORM_VALUES); const unsavedFiltersIds = newFilterIds.filter(id => !removedFilters[id]); // brings back a filter that was previously removed ("Undo") - const restoreFilter = (id: string) => { - const removal = removedFilters[id]; - // gotta clear the removal timeout to prevent the filter from getting deleted - if (removal?.isPending) clearTimeout(removal.timerId); - setRemovedFilters(current => ({ ...current, [id]: null })); - }; - const getInitialFilterOrder = () => Object.keys(filterConfigMap); + const restoreFilter = useCallback( + (id: string) => { + const removal = removedFilters[id]; + // gotta clear the removal timeout to prevent the filter from getting deleted + if (removal?.isPending) clearTimeout(removal.timerId); + setRemovedFilters(current => ({ ...current, [id]: null })); + }, + [removedFilters], + ); + const initialFilterOrder = useMemo( + () => Object.keys(filterConfigMap), + [filterConfigMap], + ); // State for tracking the re-ordering of filters - const [orderedFilters, setOrderedFilters] = useState<string[]>( - getInitialFilterOrder(), - ); + const [orderedFilters, setOrderedFilters] = + useState<string[]>(initialFilterOrder); + + // State for rendered filter to improve performance + const [renderedFilters, setRenderedFilters] = useState<string[]>([ + initialCurrentFilterId, + ]); const getActiveFilterPanelKey = (filterId: string) => [ `${filterId}-${FilterPanels.configuration.key}`, @@ -175,7 +194,7 @@ export function FiltersConfigModal({ string | string[] >(getActiveFilterPanelKey(initialCurrentFilterId)); - const onTabChange = (filterId: string) => { + const handleTabChange = (filterId: string) => { setCurrentFilterId(filterId); setActiveFilterPanelKey(getActiveFilterPanelKey(filterId)); }; @@ -217,18 +236,19 @@ export function FiltersConfigModal({ // After this, it should be as if the modal was just opened fresh. // Called when the modal is closed. const resetForm = (isSaving = false) => { - setNewFilterIds([]); + setNewFilterIds(DEFAULT_EMPTY_FILTERS); setCurrentFilterId(initialCurrentFilterId); - setRemovedFilters({}); + setRemovedFilters(DEFAULT_REMOVED_FILTERS); setSaveAlertVisible(false); - setFormValues({ filters: {} }); - setErroredFilters([]); + setFormValues(DEFAULT_FORM_VALUES); + setErroredFilters(DEFAULT_EMPTY_FILTERS); if (filterIds.length > 0) { setActiveFilterPanelKey(getActiveFilterPanelKey(filterIds[0])); } if (!isSaving) { - setOrderedFilters(getInitialFilterOrder()); + setOrderedFilters(initialFilterOrder); } + setRenderedFilters([initialCurrentFilterId]); form.resetFields(['filters']); form.setFieldsValue({ changed: false }); }; @@ -321,7 +341,7 @@ export function FiltersConfigModal({ // no form validation issues found, resets errored filters if (!erroredFiltersIds.length && erroredFilters.length > 0) { - setErroredFilters([]); + setErroredFilters(DEFAULT_EMPTY_FILTERS); return; } // form validation issues found, sets errored filters @@ -364,10 +384,9 @@ export function FiltersConfigModal({ const handleCancel = () => { const changed = form.getFieldValue('changed'); - const initialOrder = getInitialFilterOrder(); const didChangeOrder = - orderedFilters.length !== initialOrder.length || - orderedFilters.some((val, index) => val !== initialOrder[index]); + orderedFilters.length !== initialFilterOrder.length || + orderedFilters.some((val, index) => val !== initialFilterOrder[index]); if ( unsavedFiltersIds.length > 0 || form.isFieldsTouched() || @@ -379,7 +398,7 @@ export function FiltersConfigModal({ handleConfirmCancel(); } }; - const onRearrange = (dragIndex: number, targetIndex: number) => { + const handleRearrange = (dragIndex: number, targetIndex: number) => { const newOrderedFilter = [...orderedFilters]; const removed = newOrderedFilter.splice(dragIndex, 1)[0]; newOrderedFilter.splice(targetIndex, 0, removed); @@ -396,7 +415,7 @@ export function FiltersConfigModal({ let array: string[] = []; if (formItem && 'dependencies' in formItem) { array = [...formItem.dependencies]; - } else if (configItem && configItem.cascadeParentIds) { + } else if (configItem?.cascadeParentIds) { array = [...configItem.cascadeParentIds]; } dependencyMap.set(key, array); @@ -405,7 +424,7 @@ export function FiltersConfigModal({ return dependencyMap; }, [filterConfigMap, form]); - const validateDependencies = () => { + const validateDependencies = useCallback(() => { const dependencyMap = buildDependencyMap(); filterIds .filter(id => !removedFilters[id]) @@ -418,26 +437,35 @@ export function FiltersConfigModal({ form.setFields([field]); }); handleErroredFilters(); - }; + }, [ + buildDependencyMap, + filterIds, + form, + handleErroredFilters, + removedFilters, + ]); - const getDependencySuggestion = (filterId: string) => { - const dependencyMap = buildDependencyMap(); - const possibleDependencies = orderedFilters.filter( - key => key !== filterId && canBeUsedAsDependency(key), - ); - const found = possibleDependencies.find(filter => { - const dependencies = dependencyMap.get(filterId) || []; - dependencies.push(filter); - if (hasCircularDependency(dependencyMap, filterId)) { - dependencies.pop(); - return false; - } - return true; - }); - return found || possibleDependencies[0]; - }; + const getDependencySuggestion = useCallback( + (filterId: string) => { + const dependencyMap = buildDependencyMap(); + const possibleDependencies = orderedFilters.filter( + key => key !== filterId && canBeUsedAsDependency(key), + ); + const found = possibleDependencies.find(filter => { + const dependencies = dependencyMap.get(filterId) || []; + dependencies.push(filter); + if (hasCircularDependency(dependencyMap, filterId)) { + dependencies.pop(); + return false; + } + return true; + }); + return found || possibleDependencies[0]; + }, + [buildDependencyMap, canBeUsedAsDependency, orderedFilters], + ); - const onValuesChange = useMemo( + const handleValuesChange = useMemo( () => debounce((changes: any, values: NativeFiltersForm) => { const didChangeFilterName = @@ -461,37 +489,80 @@ export function FiltersConfigModal({ ); useEffect(() => { - setErroredFilters(prevErroredFilters => - prevErroredFilters.filter(f => !removedFilters[f]), - ); + if (!isEmpty(removedFilters)) { + setErroredFilters(prevErroredFilters => + prevErroredFilters.filter(f => !removedFilters[f]), + ); + } }, [removedFilters]); - const getForm = (id: string) => { - const isDivider = id.startsWith(NATIVE_FILTER_DIVIDER_PREFIX); - return isDivider ? ( - <DividerConfigForm - componentId={id} - divider={filterConfigMap[id] as Divider} - /> - ) : ( - <FiltersConfigForm - ref={configFormRef} - form={form} - filterId={id} - filterToEdit={filterConfigMap[id] as Filter} - removedFilters={removedFilters} - restoreFilter={restoreFilter} - getAvailableFilters={getAvailableFilters} - key={id} - activeFilterPanelKeys={activeFilterPanelKey} - handleActiveFilterPanelChange={key => setActiveFilterPanelKey(key)} - isActive={currentFilterId === id} - setErroredFilters={setErroredFilters} - validateDependencies={validateDependencies} - getDependencySuggestion={getDependencySuggestion} - /> - ); - }; + useEffect(() => { + if (!renderedFilters.includes(currentFilterId)) { + setRenderedFilters([...renderedFilters, currentFilterId]); + } + }, [currentFilterId]); + + const handleActiveFilterPanelChange = useCallback( + key => setActiveFilterPanelKey(key), + [setActiveFilterPanelKey], + ); + + const formList = useMemo( + () => + orderedFilters.map(id => { + if (!renderedFilters.includes(id)) return null; + const isDivider = id.startsWith(NATIVE_FILTER_DIVIDER_PREFIX); + const isActive = currentFilterId === id; + return ( + <div + key={id} + style={{ + height: '100%', + overflowY: 'auto', + display: isActive ? '' : 'none', + }} + > + {isDivider ? ( + <DividerConfigForm + componentId={id} + divider={filterConfigMap[id] as Divider} + /> + ) : ( + <FiltersConfigForm + ref={configFormRef} + form={form} + filterId={id} + filterToEdit={filterConfigMap[id] as Filter} + removedFilters={removedFilters} + restoreFilter={restoreFilter} + getAvailableFilters={getAvailableFilters} + key={id} + activeFilterPanelKeys={activeFilterPanelKey} + handleActiveFilterPanelChange={handleActiveFilterPanelChange} + isActive={isActive} + setErroredFilters={setErroredFilters} + validateDependencies={validateDependencies} + getDependencySuggestion={getDependencySuggestion} + /> + )} + </div> + ); + }), + [ + renderedFilters, + orderedFilters, + currentFilterId, + filterConfigMap, + form, + removedFilters, + restoreFilter, + getAvailableFilters, + activeFilterPanelKey, + validateDependencies, + getDependencySuggestion, + handleActiveFilterPanelChange, + ], + ); return ( <StyledModalWrapper @@ -519,22 +590,22 @@ export function FiltersConfigModal({ <StyledModalBody> <StyledForm form={form} - onValuesChange={onValuesChange} + onValuesChange={handleValuesChange} layout="vertical" > <FilterConfigurePane erroredFilters={erroredFilters} onRemove={handleRemoveItem} onAdd={addFilter} - onChange={onTabChange} + onChange={handleTabChange} getFilterTitle={getFilterTitle} currentFilterId={currentFilterId} removedFilters={removedFilters} restoreFilter={restoreFilter} - onRearrange={onRearrange} + onRearrange={handleRearrange} filters={orderedFilters} > - {(id: string) => getForm(id)} + {formList} </FilterConfigurePane> </StyledForm> </StyledModalBody> @@ -542,3 +613,5 @@ export function FiltersConfigModal({ </StyledModalWrapper> ); } + +export default React.memo(FiltersConfigModal); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/NativeFiltersModal.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/NativeFiltersModal.test.tsx index 7717d1915b114..06a566937d0b4 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/NativeFiltersModal.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/NativeFiltersModal.test.tsx @@ -28,7 +28,7 @@ import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; import { AntdDropdown } from 'src/components'; import { Menu } from 'src/components/Menu'; import Alert from 'src/components/Alert'; -import { FiltersConfigModal } from 'src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal'; +import FiltersConfigModal from 'src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal'; Object.defineProperty(window, 'matchMedia', { writable: true, diff --git a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts index 868205714f670..32a060057b7c3 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts @@ -28,7 +28,7 @@ import { getChartMetadataRegistry, QueryFormData, } from '@superset-ui/core'; -import { Charts, DashboardLayout } from 'src/dashboard/types'; +import { DashboardLayout } from 'src/dashboard/types'; import extractUrlParams from 'src/dashboard/util/extractUrlParams'; import { isFeatureEnabled } from 'src/featureFlags'; import { CHART_TYPE, TAB_TYPE } from '../../util/componentTypes'; @@ -122,7 +122,6 @@ export function isCrossFilter(vizType: string) { export function getExtraFormData( dataMask: DataMaskStateWithId, - charts: Charts, filterIdsAppliedOnChart: string[], ): ExtraFormData { let extraFormData: ExtraFormData = {}; @@ -147,7 +146,7 @@ export function nativeFilterGate(behaviors: Behavior[]): boolean { const isComponentATab = ( dashboardLayout: DashboardLayout, componentId: string, -) => dashboardLayout[componentId].type === TAB_TYPE; +) => dashboardLayout?.[componentId]?.type === TAB_TYPE; const findTabsWithChartsInScopeHelper = ( dashboardLayout: DashboardLayout, @@ -157,19 +156,19 @@ const findTabsWithChartsInScopeHelper = ( tabsToHighlight: Set<string>, ) => { if ( - dashboardLayout[componentId].type === CHART_TYPE && - chartsInScope.includes(dashboardLayout[componentId].meta.chartId) + dashboardLayout?.[componentId]?.type === CHART_TYPE && + chartsInScope.includes(dashboardLayout[componentId]?.meta?.chartId) ) { tabIds.forEach(tabsToHighlight.add, tabsToHighlight); } if ( - dashboardLayout[componentId].children.length === 0 || + dashboardLayout?.[componentId]?.children?.length === 0 || (isComponentATab(dashboardLayout, componentId) && tabsToHighlight.has(componentId)) ) { return; } - dashboardLayout[componentId].children.forEach(childId => + dashboardLayout[componentId]?.children.forEach(childId => findTabsWithChartsInScopeHelper( dashboardLayout, chartsInScope, @@ -189,7 +188,7 @@ export const findTabsWithChartsInScope = ( const hasTopLevelTabs = rootChildId !== DASHBOARD_GRID_ID; const tabsInScope = new Set<string>(); if (hasTopLevelTabs) { - dashboardLayout[rootChildId].children?.forEach(tabId => + dashboardLayout[rootChildId]?.children?.forEach(tabId => findTabsWithChartsInScopeHelper( dashboardLayout, chartsInScope, @@ -200,7 +199,7 @@ export const findTabsWithChartsInScope = ( ); } else { Object.values(dashboardLayout) - .filter(element => element.type === TAB_TYPE) + .filter(element => element?.type === TAB_TYPE) .forEach(element => findTabsWithChartsInScopeHelper( dashboardLayout, diff --git a/superset-frontend/src/dashboard/components/resizable/ResizableContainer.jsx b/superset-frontend/src/dashboard/components/resizable/ResizableContainer.jsx index ff576101f4916..a14731574e582 100644 --- a/superset-frontend/src/dashboard/components/resizable/ResizableContainer.jsx +++ b/superset-frontend/src/dashboard/components/resizable/ResizableContainer.jsx @@ -20,6 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Resizable } from 're-resizable'; import cx from 'classnames'; +import { css, styled } from '@superset-ui/core'; import ResizableHandle from './ResizableHandle'; import resizableConfig from '../../util/resizableConfig'; @@ -80,6 +81,93 @@ const HANDLE_CLASSES = { right: 'resizable-container-handle--right', bottom: 'resizable-container-handle--bottom', }; + +const StyledResizable = styled(Resizable)` + ${({ theme }) => css` + &.resizable-container { + background-color: transparent; + position: relative; + + /* re-resizable sets an empty div to 100% width and height, which doesn't + play well with many 100% height containers we need */ + + & ~ div { + width: auto !important; + height: auto !important; + } + } + + &.resizable-container--resizing { + /* after ensures border visibility on top of any children */ + + &:after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + box-shadow: inset 0 0 0 2px ${theme.colors.primary.base}; + } + + & > span .resize-handle { + border-color: ${theme.colors.primary.base}; + } + } + + .resize-handle { + opacity: 0; + z-index: 10; + + &--bottom-right { + position: absolute; + border-right: 1px solid ${theme.colors.text.label}; + border-bottom: 1px solid ${theme.colors.text.label}; + right: ${theme.gridUnit * 4}px; + bottom: ${theme.gridUnit * 4}px; + width: ${theme.gridUnit * 2}px; + height: ${theme.gridUnit * 2}px; + } + + &--right { + width: ${theme.gridUnit / 2}px; + height: ${theme.gridUnit * 5}px; + right: ${theme.gridUnit}px; + top: 50%; + transform: translate(0, -50%); + position: absolute; + border-left: 1px solid ${theme.colors.text.label}; + border-right: 1px solid ${theme.colors.text.label}; + } + + &--bottom { + height: ${theme.gridUnit / 2}px; + width: ${theme.gridUnit * 5}px; + bottom: ${theme.gridUnit}px; + left: 50%; + transform: translate(-50%); + position: absolute; + border-top: 1px solid ${theme.colors.text.label}; + border-bottom: 1px solid ${theme.colors.text.label}; + } + } + `} + + &.resizable-container:hover .resize-handle, + &.resizable-container--resizing .resize-handle { + opacity: 1; + } + + .dragdroppable-column & .resizable-container-handle--right { + /* override the default because the inner column's handle's mouse target is very small */ + right: 0 !important; + } + + & .resizable-container-handle--bottom { + bottom: 0 !important; + } +`; + class ResizableContainer extends React.PureComponent { constructor(props) { super(props); @@ -186,7 +274,7 @@ class ResizableContainer extends React.PureComponent { const { isResizing } = this.state; return ( - <Resizable + <StyledResizable enable={enableConfig} grid={SNAP_TO_GRID} minWidth={ @@ -228,7 +316,7 @@ class ResizableContainer extends React.PureComponent { handleClasses={HANDLE_CLASSES} > {children} - </Resizable> + </StyledResizable> ); } } diff --git a/superset-frontend/src/dashboard/constants.ts b/superset-frontend/src/dashboard/constants.ts index 296bc0a9b3bb3..97753abe45c54 100644 --- a/superset-frontend/src/dashboard/constants.ts +++ b/superset-frontend/src/dashboard/constants.ts @@ -37,6 +37,8 @@ export const PLACEHOLDER_DATASOURCE: Datasource = { export const MAIN_HEADER_HEIGHT = 53; export const CLOSED_FILTER_BAR_WIDTH = 32; export const OPEN_FILTER_BAR_WIDTH = 260; +export const OPEN_FILTER_BAR_MAX_WIDTH = 550; export const FILTER_BAR_HEADER_HEIGHT = 80; export const FILTER_BAR_TABS_HEIGHT = 46; export const BUILDER_SIDEPANEL_WIDTH = 374; +export const OVERWRITE_INSPECT_FIELDS = ['css', 'json_metadata.filter_scopes']; diff --git a/superset-frontend/src/dashboard/containers/Chart.jsx b/superset-frontend/src/dashboard/containers/Chart.jsx index 81d06b8566239..167ec0a043878 100644 --- a/superset-frontend/src/dashboard/containers/Chart.jsx +++ b/superset-frontend/src/dashboard/containers/Chart.jsx @@ -46,7 +46,6 @@ function mapStateToProps( charts: chartQueries, dashboardInfo, dashboardState, - dashboardLayout, dataMask, datasources, sliceEntities, @@ -65,16 +64,15 @@ function mapStateToProps( const sharedLabelColors = dashboardInfo?.metadata?.shared_label_colors || {}; // note: this method caches filters if possible to prevent render cascades const formData = getFormDataWithExtraFilters({ - layout: dashboardLayout.present, chart, - // eslint-disable-next-line camelcase chartConfiguration: dashboardInfo.metadata?.chart_configuration, charts: chartQueries, filters: getAppliedFilterValues(id), colorScheme, colorNamespace, sliceId: id, - nativeFilters, + nativeFilters: nativeFilters?.filters, + allSliceIds: dashboardState.sliceIds, dataMask, extraControls, labelColors, @@ -104,6 +102,7 @@ function mapStateToProps( setControlValue, filterboxMigrationState: dashboardState.filterboxMigrationState, datasetsStatus, + emitCrossFilters: !!dashboardInfo.crossFiltersEnabled, }; } diff --git a/superset-frontend/src/dashboard/containers/Dashboard.ts b/superset-frontend/src/dashboard/containers/Dashboard.ts index 647d774f48357..50e42fef24dce 100644 --- a/superset-frontend/src/dashboard/containers/Dashboard.ts +++ b/superset-frontend/src/dashboard/containers/Dashboard.ts @@ -68,7 +68,7 @@ function mapStateToProps(state: RootState) { chartConfiguration: dashboardInfo.metadata?.chart_configuration, nativeFilters: nativeFilters.filters, dataMask, - layout: dashboardLayout.present, + allSliceIds: dashboardState.sliceIds, }), }, chartConfiguration: dashboardInfo.metadata?.chart_configuration, diff --git a/superset-frontend/src/dashboard/containers/DashboardComponent.jsx b/superset-frontend/src/dashboard/containers/DashboardComponent.jsx index 23298d8bf96a4..08b7ed9f82d90 100644 --- a/superset-frontend/src/dashboard/containers/DashboardComponent.jsx +++ b/superset-frontend/src/dashboard/containers/DashboardComponent.jsx @@ -37,7 +37,6 @@ import { setDirectPathToChild, setActiveTabs, setFullSizeChartId, - postAddSliceFromDashboard, } from 'src/dashboard/actions/dashboardState'; const propTypes = { @@ -112,7 +111,6 @@ function mapDispatchToProps(dispatch) { setFullSizeChartId, setActiveTabs, logEvent, - postAddSliceFromDashboard, }, dispatch, ); diff --git a/superset-frontend/src/dashboard/containers/DashboardHeader.jsx b/superset-frontend/src/dashboard/containers/DashboardHeader.jsx index 121215fe8bfea..178568f064eaa 100644 --- a/superset-frontend/src/dashboard/containers/DashboardHeader.jsx +++ b/superset-frontend/src/dashboard/containers/DashboardHeader.jsx @@ -31,7 +31,8 @@ import { fetchFaveStar, saveFaveStar, savePublished, - setColorSchemeAndUnsavedChanges, + setColorScheme, + setUnsavedChanges, fetchCharts, updateCss, onChange, @@ -112,7 +113,8 @@ function mapDispatchToProps(dispatch) { onRedo: redoLayoutAction, setEditMode, showBuilderPane, - setColorSchemeAndUnsavedChanges, + setColorScheme, + setUnsavedChanges, fetchFaveStar, saveFaveStar, savePublished, diff --git a/superset-frontend/src/dashboard/containers/DashboardPage.tsx b/superset-frontend/src/dashboard/containers/DashboardPage.tsx index 49bf783ba3444..0066354f589b5 100644 --- a/superset-frontend/src/dashboard/containers/DashboardPage.tsx +++ b/superset-frontend/src/dashboard/containers/DashboardPage.tsx @@ -16,15 +16,18 @@ * specific language governing permissions and limitations * under the License. */ -import React, { FC, useRef, useEffect, useState } from 'react'; +import React, { FC, useEffect, useMemo, useRef, useState } from 'react'; +import { useHistory } from 'react-router-dom'; import { CategoricalColorNamespace, FeatureFlag, getSharedLabelColor, isFeatureEnabled, + SharedLabelColorSource, t, useTheme, } from '@superset-ui/core'; +import pick from 'lodash/pick'; import { useDispatch, useSelector } from 'react-redux'; import { Global } from '@emotion/react'; import { useToasts } from 'src/components/MessageToasts/withToasts'; @@ -44,8 +47,8 @@ import { addWarningToast } from 'src/components/MessageToasts/actions'; import { getItem, - setItem, LocalStorageKeys, + setItem, } from 'src/utils/localStorageHelpers'; import { FILTER_BOX_MIGRATION_STATES, @@ -53,19 +56,25 @@ import { } from 'src/explore/constants'; import { URL_PARAMS } from 'src/constants'; import { getUrlParam } from 'src/utils/urlUtils'; -import { canUserEditDashboard } from 'src/dashboard/util/findPermission'; -import { getFilterSets } from '../actions/nativeFilters'; -import { setDatasetsStatus } from '../actions/dashboardState'; +import { canUserEditDashboard } from 'src/dashboard/util/permissionUtils'; +import { getFilterSets } from 'src/dashboard/actions/nativeFilters'; +import { setDatasetsStatus } from 'src/dashboard/actions/dashboardState'; import { getFilterValue, getPermalinkValue, -} from '../components/nativeFilters/FilterBar/keyValue'; -import { filterCardPopoverStyle } from '../styles'; +} from 'src/dashboard/components/nativeFilters/FilterBar/keyValue'; +import { filterCardPopoverStyle, headerStyles } from 'src/dashboard/styles'; +import { DashboardContextForExplore } from 'src/types/DashboardContextForExplore'; +import shortid from 'shortid'; +import { RootState } from '../types'; +import { getActiveFilters } from '../util/activeDashboardFilters'; export const MigrationContext = React.createContext( FILTER_BOX_MIGRATION_STATES.NOOP, ); +export const DashboardPageIdContext = React.createContext(''); + setupPlugins(); const DashboardContainer = React.lazy( () => @@ -82,12 +91,77 @@ type PageProps = { idOrSlug: string; }; +const getDashboardContextLocalStorage = () => { + const dashboardsContexts = getItem( + LocalStorageKeys.dashboard__explore_context, + {}, + ); + // A new dashboard tab id is generated on each dashboard page opening. + // We mark ids as redundant when user leaves the dashboard, because they won't be reused. + // Then we remove redundant dashboard contexts from local storage in order not to clutter it + return Object.fromEntries( + Object.entries(dashboardsContexts).filter( + ([, value]) => !value.isRedundant, + ), + ); +}; + +const updateDashboardTabLocalStorage = ( + dashboardPageId: string, + dashboardContext: DashboardContextForExplore, +) => { + const dashboardsContexts = getDashboardContextLocalStorage(); + setItem(LocalStorageKeys.dashboard__explore_context, { + ...dashboardsContexts, + [dashboardPageId]: dashboardContext, + }); +}; + +const useSyncDashboardStateWithLocalStorage = () => { + const dashboardPageId = useMemo(() => shortid.generate(), []); + const dashboardContextForExplore = useSelector< + RootState, + DashboardContextForExplore + >(({ dashboardInfo, dashboardState, nativeFilters, dataMask }) => ({ + labelColors: dashboardInfo.metadata?.label_colors || {}, + sharedLabelColors: dashboardInfo.metadata?.shared_label_colors || {}, + colorScheme: dashboardState?.colorScheme, + chartConfiguration: dashboardInfo.metadata?.chart_configuration || {}, + nativeFilters: Object.entries(nativeFilters.filters).reduce( + (acc, [key, filterValue]) => ({ + ...acc, + [key]: pick(filterValue, ['chartsInScope']), + }), + {}, + ), + dataMask, + dashboardId: dashboardInfo.id, + filterBoxFilters: getActiveFilters(), + dashboardPageId, + })); + + useEffect(() => { + updateDashboardTabLocalStorage(dashboardPageId, dashboardContextForExplore); + return () => { + // mark tab id as redundant when dashboard unmounts - case when user opens + // Explore in the same tab + updateDashboardTabLocalStorage(dashboardPageId, { + ...dashboardContextForExplore, + isRedundant: true, + }); + }; + }, [dashboardContextForExplore, dashboardPageId]); + return dashboardPageId; +}; + export const DashboardPage: FC<PageProps> = ({ idOrSlug }: PageProps) => { const dispatch = useDispatch(); const theme = useTheme(); + const history = useHistory(); const user = useSelector<any, UserWithPermissionsAndRoles>( state => state.user, ); + const dashboardPageId = useSyncDashboardStateWithLocalStorage(); const { addDangerToast } = useToasts(); const { result: dashboard, error: dashboardApiError } = useDashboard(idOrSlug); @@ -113,15 +187,34 @@ export const DashboardPage: FC<PageProps> = ({ idOrSlug }: PageProps) => { migrationStateParam || FILTER_BOX_MIGRATION_STATES.NOOP, ); + useEffect(() => { + // mark tab id as redundant when user closes browser tab - a new id will be + // generated next time user opens a dashboard and the old one won't be reused + const handleTabClose = () => { + const dashboardsContexts = getDashboardContextLocalStorage(); + setItem(LocalStorageKeys.dashboard__explore_context, { + ...dashboardsContexts, + [dashboardPageId]: { + ...dashboardsContexts[dashboardPageId], + isRedundant: true, + }, + }); + }; + window.addEventListener('beforeunload', handleTabClose); + return () => { + window.removeEventListener('beforeunload', handleTabClose); + }; + }, [dashboardPageId]); + useEffect(() => { dispatch(setDatasetsStatus(status)); }, [dispatch, status]); useEffect(() => { // should convert filter_box to filter component? - const hasFilterBox = - charts && - charts.some(chart => chart.form_data?.viz_type === 'filter_box'); + const hasFilterBox = charts?.some( + chart => chart.form_data?.viz_type === 'filter_box', + ); const canEdit = dashboard && canUserEditDashboard(dashboard, user); if (canEdit) { @@ -183,19 +276,22 @@ export const DashboardPage: FC<PageProps> = ({ idOrSlug }: PageProps) => { async function getDataMaskApplied() { const permalinkKey = getUrlParam(URL_PARAMS.permalinkKey); const nativeFilterKeyValue = getUrlParam(URL_PARAMS.nativeFiltersKey); - let dataMaskFromUrl = nativeFilterKeyValue || {}; - const isOldRison = getUrlParam(URL_PARAMS.nativeFilters); + + let dataMask = nativeFilterKeyValue || {}; + // activeTabs is initialized with undefined so that it doesn't override + // the currently stored value when hydrating + let activeTabs: string[] | undefined; if (permalinkKey) { const permalinkValue = await getPermalinkValue(permalinkKey); if (permalinkValue) { - dataMaskFromUrl = permalinkValue.state.filterState; + ({ dataMask, activeTabs } = permalinkValue.state); } } else if (nativeFilterKeyValue) { - dataMaskFromUrl = await getFilterValue(id, nativeFilterKeyValue); + dataMask = await getFilterValue(id, nativeFilterKeyValue); } if (isOldRison) { - dataMaskFromUrl = isOldRison; + dataMask = isOldRison; } if (readyToRender) { @@ -207,12 +303,14 @@ export const DashboardPage: FC<PageProps> = ({ idOrSlug }: PageProps) => { } } dispatch( - hydrateDashboard( + hydrateDashboard({ + history, dashboard, charts, + activeTabs, filterboxMigrationState, - dataMaskFromUrl, - ), + dataMask, + }), ); } return null; @@ -239,17 +337,18 @@ export const DashboardPage: FC<PageProps> = ({ idOrSlug }: PageProps) => { return () => {}; }, [css]); - useEffect( - () => () => { + useEffect(() => { + const sharedLabelColor = getSharedLabelColor(); + sharedLabelColor.source = SharedLabelColorSource.dashboard; + return () => { // clean up label color const categoricalNamespace = CategoricalColorNamespace.getNamespace( metadata?.color_namespace, ); categoricalNamespace.resetColors(); - getSharedLabelColor().clear(); - }, - [metadata?.color_namespace], - ); + sharedLabelColor.clear(); + }; + }, [metadata?.color_namespace]); useEffect(() => { if (datasetsApiError) { @@ -266,7 +365,7 @@ export const DashboardPage: FC<PageProps> = ({ idOrSlug }: PageProps) => { return ( <> - <Global styles={filterCardPopoverStyle(theme)} /> + <Global styles={[filterCardPopoverStyle(theme), headerStyles(theme)]} /> <FilterBoxMigrationModal show={filterboxMigrationState === FILTER_BOX_MIGRATION_STATES.UNDECIDED} hideFooter={!isMigrationEnabled} @@ -291,7 +390,9 @@ export const DashboardPage: FC<PageProps> = ({ idOrSlug }: PageProps) => { /> <MigrationContext.Provider value={filterboxMigrationState}> - <DashboardContainer /> + <DashboardPageIdContext.Provider value={dashboardPageId}> + <DashboardContainer /> + </DashboardPageIdContext.Provider> </MigrationContext.Provider> </> ); diff --git a/superset-frontend/src/dashboard/containers/SliceAdder.jsx b/superset-frontend/src/dashboard/containers/SliceAdder.jsx index 078ded23d8ac8..580dedc2f8300 100644 --- a/superset-frontend/src/dashboard/containers/SliceAdder.jsx +++ b/superset-frontend/src/dashboard/containers/SliceAdder.jsx @@ -19,7 +19,11 @@ import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { fetchAllSlices } from '../actions/sliceEntities'; +import { + fetchAllSlices, + fetchSortedSlices, + fetchFilteredSlices, +} from '../actions/sliceEntities'; import SliceAdder from '../components/SliceAdder'; function mapStateToProps( @@ -44,6 +48,8 @@ function mapDispatchToProps(dispatch) { return bindActionCreators( { fetchAllSlices, + fetchSortedSlices, + fetchFilteredSlices, }, dispatch, ); diff --git a/superset-frontend/src/dashboard/reducers/dashboardInfo.js b/superset-frontend/src/dashboard/reducers/dashboardInfo.js index fdd39fae12324..3503c441b65c2 100644 --- a/superset-frontend/src/dashboard/reducers/dashboardInfo.js +++ b/superset-frontend/src/dashboard/reducers/dashboardInfo.js @@ -17,7 +17,11 @@ * under the License. */ -import { DASHBOARD_INFO_UPDATED } from '../actions/dashboardInfo'; +import { + DASHBOARD_INFO_UPDATED, + SET_FILTER_BAR_ORIENTATION, + SET_CROSS_FILTERS_ENABLED, +} from '../actions/dashboardInfo'; import { HYDRATE_DASHBOARD } from '../actions/hydrate'; export default function dashboardStateReducer(state = {}, action) { @@ -35,6 +39,16 @@ export default function dashboardStateReducer(state = {}, action) { ...action.data.dashboardInfo, // set async api call data }; + case SET_FILTER_BAR_ORIENTATION: + return { + ...state, + filterBarOrientation: action.filterBarOrientation, + }; + case SET_CROSS_FILTERS_ENABLED: + return { + ...state, + crossFiltersEnabled: action.crossFiltersEnabled, + }; default: return state; } diff --git a/superset-frontend/src/dashboard/reducers/dashboardLayout.js b/superset-frontend/src/dashboard/reducers/dashboardLayout.js index 30ad33c62b6c1..6ba297be9147e 100644 --- a/superset-frontend/src/dashboard/reducers/dashboardLayout.js +++ b/superset-frontend/src/dashboard/reducers/dashboardLayout.js @@ -45,6 +45,39 @@ import { import { HYDRATE_DASHBOARD } from '../actions/hydrate'; +export function recursivelyDeleteChildren( + componentId, + componentParentId, + nextComponents, +) { + // delete child and it's children + const component = nextComponents?.[componentId]; + if (component) { + // eslint-disable-next-line no-param-reassign + delete nextComponents[componentId]; + + const { children = [] } = component; + children?.forEach?.(childId => { + recursivelyDeleteChildren(childId, componentId, nextComponents); + }); + + const parent = nextComponents?.[componentParentId]; + if (Array.isArray(parent?.children)) { + // may have been deleted in another recursion + const componentIndex = parent.children.indexOf(componentId); + if (componentIndex > -1) { + const nextChildren = [...parent.children]; + nextChildren.splice(componentIndex, 1); + // eslint-disable-next-line no-param-reassign + nextComponents[componentParentId] = { + ...parent, + children: nextChildren, + }; + } + } + } +} + const actionHandlers = { [HYDRATE_DASHBOARD](state, action) { return { @@ -71,39 +104,14 @@ const actionHandlers = { const nextComponents = { ...state }; - function recursivelyDeleteChildren(componentId, componentParentId) { - // delete child and it's children - const component = nextComponents[componentId]; - delete nextComponents[componentId]; - - const { children = [] } = component; - children.forEach(childId => { - recursivelyDeleteChildren(childId, componentId); - }); - - const parent = nextComponents[componentParentId]; - if (parent) { - // may have been deleted in another recursion - const componentIndex = (parent.children || []).indexOf(componentId); - if (componentIndex > -1) { - const nextChildren = [...parent.children]; - nextChildren.splice(componentIndex, 1); - nextComponents[componentParentId] = { - ...parent, - children: nextChildren, - }; - } - } - } - - recursivelyDeleteChildren(id, parentId); + recursivelyDeleteChildren(id, parentId, nextComponents); const nextParent = nextComponents[parentId]; - if (nextParent.type === ROW_TYPE && nextParent.children.length === 0) { + if (nextParent?.type === ROW_TYPE && nextParent?.children?.length === 0) { const grandparentId = findParentId({ childId: parentId, layout: nextComponents, }); - recursivelyDeleteChildren(parentId, grandparentId); + recursivelyDeleteChildren(parentId, grandparentId, nextComponents); } return nextComponents; diff --git a/superset-frontend/src/dashboard/reducers/dashboardLayout.test.js b/superset-frontend/src/dashboard/reducers/dashboardLayout.test.js index f9b504acf75a9..f0f4d8b1bcafd 100644 --- a/superset-frontend/src/dashboard/reducers/dashboardLayout.test.js +++ b/superset-frontend/src/dashboard/reducers/dashboardLayout.test.js @@ -16,7 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -import layoutReducer from 'src/dashboard/reducers/dashboardLayout'; +import layoutReducer, { + recursivelyDeleteChildren, +} from 'src/dashboard/reducers/dashboardLayout'; import { UPDATE_COMPONENTS, @@ -455,4 +457,23 @@ describe('dashboardLayout reducer', () => { expect(result[DASHBOARD_GRID_ID].children).toHaveLength(2); expect(result[newId].type).toBe(ROW_TYPE); }); + + it('recursivelyDeleteChildren should be error proof with bad inputs', () => { + /* + ** The recursivelyDeleteChildren function was missing runtime safety checks before operating + ** on sub properties of object causing runtime errors when a componentId lookup returned and unexpected value + ** These test are to ensure this function is fault tolerant if provided any bad values while recursively looping + ** through the data structure of + */ + const componentId = '123'; + const componentParentId = '456'; + const nextComponents = []; + expect(() => { + recursivelyDeleteChildren(componentId, componentParentId, nextComponents); + }).not.toThrow(); + + expect(() => { + recursivelyDeleteChildren(null, null, null); + }).not.toThrow(); + }); }); diff --git a/superset-frontend/src/dashboard/reducers/dashboardState.js b/superset-frontend/src/dashboard/reducers/dashboardState.js index 277865030cb79..5d81cd8ac11f0 100644 --- a/superset-frontend/src/dashboard/reducers/dashboardState.js +++ b/superset-frontend/src/dashboard/reducers/dashboardState.js @@ -39,10 +39,12 @@ import { UNSET_FOCUSED_FILTER_FIELD, SET_ACTIVE_TABS, SET_FULL_SIZE_CHART_ID, - RESET_SLICE, ON_FILTERS_REFRESH, ON_FILTERS_REFRESH_SUCCESS, SET_DATASETS_STATUS, + SET_OVERRIDE_CONFIRM, + SAVE_DASHBOARD_STARTED, + SAVE_DASHBOARD_FINISHED, } from '../actions/dashboardState'; import { HYDRATE_DASHBOARD } from '../actions/hydrate'; @@ -60,7 +62,6 @@ export default function dashboardStateReducer(state = {}, action) { return { ...state, sliceIds: Array.from(updatedSliceIds), - updateSlice: true, }; }, [REMOVE_SLICE]() { @@ -73,12 +74,6 @@ export default function dashboardStateReducer(state = {}, action) { sliceIds: Array.from(updatedSliceIds), }; }, - [RESET_SLICE]() { - return { - ...state, - updateSlice: false, - }; - }, [TOGGLE_FAVE_STAR]() { return { ...state, isStarred: action.isStarred }; }, @@ -118,6 +113,18 @@ export default function dashboardStateReducer(state = {}, action) { [ON_CHANGE]() { return { ...state, hasUnsavedChanges: true }; }, + [SAVE_DASHBOARD_STARTED]() { + return { + ...state, + dashboardIsSaving: true, + }; + }, + [SAVE_DASHBOARD_FINISHED]() { + return { + ...state, + dashboardIsSaving: false, + }; + }, [ON_SAVE]() { return { ...state, @@ -125,7 +132,6 @@ export default function dashboardStateReducer(state = {}, action) { maxUndoHistoryExceeded: false, editMode: false, updatedColorScheme: false, - updateSlice: false, // server-side returns last_modified_time for latest change lastModifiedTime: action.lastModifiedTime, }; @@ -182,6 +188,12 @@ export default function dashboardStateReducer(state = {}, action) { activeTabs: Array.from(newActiveTabs), }; }, + [SET_OVERRIDE_CONFIRM]() { + return { + ...state, + overwriteConfirmMetadata: action.overwriteConfirmMetadata, + }; + }, [SET_FOCUSED_FILTER_FIELD]() { return { ...state, diff --git a/superset-frontend/src/dashboard/reducers/dashboardState.test.js b/superset-frontend/src/dashboard/reducers/dashboardState.test.js index de3ecf72ff3ec..39798ecf139e5 100644 --- a/superset-frontend/src/dashboard/reducers/dashboardState.test.js +++ b/superset-frontend/src/dashboard/reducers/dashboardState.test.js @@ -28,7 +28,6 @@ import { TOGGLE_EXPAND_SLICE, TOGGLE_FAVE_STAR, UNSET_FOCUSED_FILTER_FIELD, - RESET_SLICE, } from 'src/dashboard/actions/dashboardState'; import dashboardStateReducer from 'src/dashboard/reducers/dashboardState'; @@ -44,7 +43,7 @@ describe('dashboardState reducer', () => { { sliceIds: [1] }, { type: ADD_SLICE, slice: { slice_id: 2 } }, ), - ).toEqual({ sliceIds: [1, 2], updateSlice: true }); + ).toEqual({ sliceIds: [1, 2] }); }); it('should remove a slice', () => { @@ -56,12 +55,6 @@ describe('dashboardState reducer', () => { ).toEqual({ sliceIds: [1], filters: {} }); }); - it('should reset updateSlice', () => { - expect( - dashboardStateReducer({ updateSlice: true }, { type: RESET_SLICE }), - ).toEqual({ updateSlice: false }); - }); - it('should toggle fav star', () => { expect( dashboardStateReducer( diff --git a/superset-frontend/src/dashboard/reducers/nativeFilters.ts b/superset-frontend/src/dashboard/reducers/nativeFilters.ts index b3900af31cf52..81a1a4bd2d208 100644 --- a/superset-frontend/src/dashboard/reducers/nativeFilters.ts +++ b/superset-frontend/src/dashboard/reducers/nativeFilters.ts @@ -23,6 +23,8 @@ import { SET_FILTER_SETS_COMPLETE, SET_FOCUSED_NATIVE_FILTER, UNSET_FOCUSED_NATIVE_FILTER, + SET_HOVERED_NATIVE_FILTER, + UNSET_HOVERED_NATIVE_FILTER, } from 'src/dashboard/actions/nativeFilters'; import { FilterSet, @@ -102,6 +104,18 @@ export default function nativeFilterReducer( ...state, focusedFilterId: undefined, }; + + case SET_HOVERED_NATIVE_FILTER: + return { + ...state, + hoveredFilterId: action.id, + }; + + case UNSET_HOVERED_NATIVE_FILTER: + return { + ...state, + hoveredFilterId: undefined, + }; // TODO handle SET_FILTER_CONFIG_FAIL action default: return state; diff --git a/superset-frontend/src/dashboard/reducers/types.ts b/superset-frontend/src/dashboard/reducers/types.ts index 7b3aec25241ee..9e9b4e8ca5fa0 100644 --- a/superset-frontend/src/dashboard/reducers/types.ts +++ b/superset-frontend/src/dashboard/reducers/types.ts @@ -30,6 +30,7 @@ export type ChartConfiguration = { id: number; crossFilters: { scope: NativeFilterScope; + chartsInScope: number[]; }; }; }; diff --git a/superset-frontend/src/dashboard/styles.ts b/superset-frontend/src/dashboard/styles.ts index 5947fd6f26145..a5f49acb85f4f 100644 --- a/superset-frontend/src/dashboard/styles.ts +++ b/superset-frontend/src/dashboard/styles.ts @@ -18,15 +18,57 @@ */ import { css, SupersetTheme } from '@superset-ui/core'; +export const headerStyles = (theme: SupersetTheme) => css` + body { + h1 { + font-weight: ${theme.typography.weights.bold}; + line-height: 1.4; + font-size: ${theme.typography.sizes.xxl}px; + letter-spacing: -0.2px; + margin-top: ${theme.gridUnit * 3}px; + margin-bottom: ${theme.gridUnit * 3}px; + } + + h2 { + font-weight: ${theme.typography.weights.bold}; + line-height: 1.4; + font-size: ${theme.typography.sizes.xl}px; + margin-top: ${theme.gridUnit * 3}px; + margin-bottom: ${theme.gridUnit * 2}px; + } + + h3, + h4, + h5, + h6 { + font-weight: ${theme.typography.weights.bold}; + line-height: 1.4; + font-size: ${theme.typography.sizes.l}px; + letter-spacing: 0.2px; + margin-top: ${theme.gridUnit * 2}px; + margin-bottom: ${theme.gridUnit}px; + } + } +`; + export const filterCardPopoverStyle = (theme: SupersetTheme) => css` .filter-card-popover { width: 240px; padding: 0; border-radius: 4px; + &.ant-popover-placement-bottom { + padding-top: ${theme.gridUnit}px; + } + + &.ant-popover-placement-left { + padding-right: ${theme.gridUnit * 3}px; + } + .ant-popover-inner { box-shadow: 0 0 8px rgb(0 0 0 / 10%); } + .ant-popover-inner-content { padding: ${theme.gridUnit * 4}px; } diff --git a/superset-frontend/src/dashboard/stylesheets/builder-sidepane.less b/superset-frontend/src/dashboard/stylesheets/builder-sidepane.less deleted file mode 100644 index ad26877771a23..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/builder-sidepane.less +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -@import '../../assets/stylesheets/less/variables.less'; - -.dashboard-builder-sidepane { - .dashboard-builder-sidepane-header { - font-size: @font-size-l; - font-weight: @font-weight-bold; - border-top: 1px solid @gray-light; - border-bottom: 1px solid @gray-light; - padding: 16px; - display: flex; - align-items: center; - } - - .trigger { - font-size: @font-size-l; - color: @almost-black; - opacity: 1; - margin-left: auto; - cursor: pointer; - } - - .slices-layer .trigger { - margin-left: 0; - margin-right: 20px; - } - - .viewport { - position: absolute; - transform: none !important; - overflow: hidden; - width: @builder-pane-width; - height: 100%; - box-shadow: -4px 0 4px 0 fade(@darkest, @opacity-light); - background-color: @lightest; - } - - .slider-container { - position: absolute; - background: @lightest; - width: @builder-pane-width * 2; - height: 100vh; - display: flex; - transition: all @timing-normal ease; - - &.slide-in { - left: -@builder-pane-width; - } - - &.slide-out { - left: 0; - } - - .slide-content { - width: @builder-pane-width; - } - } - - .component-layer .new-component.static, - .slices-layer .dashboard-builder-sidepane-header { - cursor: pointer; - } - - .component-layer { - .new-component.static { - cursor: pointer; - } - } - - .new-component-label { - flex-grow: 1; - } - - .slice-adder-container { - position: relative; - background-color: white; - min-height: 200px; /* for loader positioning */ - - .error-message { - padding: 16px; - } - - .controls { - display: flex; - padding: 16px; - - /* the input is wrapped in a div */ - .search-input { - flex-grow: 1; - margin-right: 16px; - } - - .dropdown.btn-group button, - input { - font-size: @font-size-m; - padding: 7px 12px; - height: 32px; - border: 1px solid @gray-light; - } - - input { - width: 100%; - - &:focus { - outline: none; - border-color: @gray; - } - } - } - - .ReactVirtualized__Grid.ReactVirtualized__List:focus { - outline: none; - } - } -} diff --git a/superset-frontend/src/dashboard/stylesheets/components/chart.less b/superset-frontend/src/dashboard/stylesheets/components/chart.less deleted file mode 100644 index 01bf3db1e7f83..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/components/chart.less +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -.dashboard-component-chart-holder { - width: 100%; - height: 100%; - color: @gray-dark; - background-color: @lightest; - position: relative; - padding: 16px; - overflow-y: visible; - - // transitionable traits for when a filter is being actively focused - transition: opacity 0.2s, border-color 0.2s, box-shadow 0.2s; - border: 2px solid transparent; - - .missing-chart-container { - display: flex; - flex-direction: column; - align-items: center; - overflow-y: auto; - justify-content: center; - - .missing-chart-body { - font-size: @font-size-s; - position: relative; - display: flex; - } - } - - &.fade-in { - border-radius: @border-radius-large; - box-shadow: inset 0 0 0 2px @shadow-highlight, - 0 0 0 3px fade(@shadow-highlight, @opacity-light); - transition: box-shadow 0.2s ease-in-out, opacity 0.2s ease-in-out, - border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out; - } - - &.fade-out { - border-radius: @border-radius-large; - box-shadow: none; - transition: box-shadow 0.2s ease-in-out, opacity 0.2s ease-in-out, - border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out; - } -} - -.dashboard-chart { - overflow: hidden; - position: relative; - flex-shrink: 0; -} - -.dashboard-chart.dashboard-chart--overflowable { - overflow: visible; -} - -.dashboard--editing { - .dashboard-component-chart-holder { - &:after { - content: ''; - position: absolute; - width: 100%; - height: 100%; - top: 0px; - left: 0px; - z-index: @z-index-chart; - pointer-events: none; - border: 1px solid transparent; - } - - &:hover:after { - border: 1px dashed @indicator-color; - z-index: @z-index-chart--dragging; - } - } - - .resizable-container { - &:hover, - &.resizable-container--resizing:hover { - & > .dashboard-component-chart-holder:after { - border: 1px dashed @indicator-color; - } - } - } - - .resizable-container .dashboard-component-chart-holder { - .dashboard-chart { - .chart-container { - cursor: move; - opacity: 0.2; - } - - .slice_container { - /* disable chart interactions in edit mode */ - pointer-events: none; - } - } - - &:hover .dashboard-chart .chart-container { - opacity: 0.7; - } - } -} - -.dot { - @dot-diameter: 4px; - - height: @dot-diameter; - width: @dot-diameter; - border-radius: @dot-diameter / 2; - margin: @dot-diameter / 2 0; - - background-color: @gray; - display: inline-block; - - a[role='menuitem'] & { - width: 8px; - height: 8px; - margin-right: 8px; - } -} - -.time-filter-tabs > .nav-tabs { - margin-bottom: 8px; -} - -.time-filter-tabs > .nav-tabs > li > a { - padding: 4px; -} - -.full-size { - position: fixed; - z-index: @z-index-max; - left: 0; - top: 0; -} diff --git a/superset-frontend/src/dashboard/stylesheets/components/column.less b/superset-frontend/src/dashboard/stylesheets/components/column.less deleted file mode 100644 index 7d7b7baba3646..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/components/column.less +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -.grid-column { - width: 100%; - position: relative; -} - -/* gutters between elements in a column */ -.grid-column > :not(:only-child):not(.hover-menu):not(:last-child) { - margin-bottom: 16px; -} - -.dashboard--editing { - .grid-column:after { - content: ''; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - z-index: @z-index-chart; - pointer-events: none; - border: 1px dashed @gray-light; - } - - .resizable-container.resizable-container--resizing:hover > .grid-column:after, - .hover-menu:hover + .grid-column:after { - border: 1px dashed @indicator-color; - z-index: @z-index-chart--dragging; - } -} - -.grid-column--empty { - min-height: 100px; - - &:before { - content: 'Empty column'; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - color: @gray-light; - } -} diff --git a/superset-frontend/src/dashboard/stylesheets/components/header.less b/superset-frontend/src/dashboard/stylesheets/components/header.less deleted file mode 100644 index 355385d373fd6..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/components/header.less +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -.dashboard-component-header { - width: 100%; - font-weight: @font-weight-bold; - padding: 16px 0; - color: @almost-black; -} - -.dashboard--editing { - .dashboard-grid { - .dashboard-component-header { - &:after { - border: 1px dashed transparent; - content: ''; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - z-index: @z-index-chart; - pointer-events: none; - } - - &:hover:after { - border: 1px dashed @indicator-color; - z-index: @z-index-chart--dragging; - } - } - } - - .dragdroppable-row .dashboard-component-header { - cursor: move; - } -} - -.header-style-option { - font-weight: @font-weight-bold; - color: @almost-black; -} - -.dashboard--editing - -/* note: sizes should be a multiple of the 8px grid unit so that rows in the grid align */ -.header-small { - font-size: @font-size-l; -} - -.header-medium { - font-size: @font-size-xl; -} - -.header-large { - font-size: @font-size-xxl; -} - -.background--white .dashboard-component-header, -.dashboard-component-header.background--white, -.dashboard-component-tabs .dashboard-component-header, -.dashboard-component-tabs .dashboard-component-divider { - padding-left: 16px; - padding-right: 16px; -} - -/* - * grids add margin between items, so don't double pad within columns - * we'll not worry about double padding on top as it can serve as a visual separator - */ -.grid-column > :not(:only-child):not(:last-child) .dashboard-component-header { - margin-bottom: -16px; -} diff --git a/superset-frontend/src/dashboard/stylesheets/components/index.less b/superset-frontend/src/dashboard/stylesheets/components/index.less deleted file mode 100644 index d99e11df2a45a..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/components/index.less +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -@import './chart.less'; -@import './column.less'; -@import './divider.less'; -@import './header.less'; -@import './new-component.less'; -@import './row.less'; -@import './markdown.less'; diff --git a/superset-frontend/src/dashboard/stylesheets/components/row.less b/superset-frontend/src/dashboard/stylesheets/components/row.less deleted file mode 100644 index 87b376f51dbfd..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/components/row.less +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -.grid-row { - position: relative; - display: flex; - flex-direction: row; - flex-wrap: nowrap; - align-items: flex-start; - width: 100%; - height: fit-content; -} - -/* gutters between elements in a row */ -.grid-row > :not(:only-child):not(:last-child):not(.hover-menu) { - margin-right: 16px; -} - -/* hover indicator */ -.dashboard--editing { - .grid-row:after, - .dashboard-component-tabs > .hover-menu:hover + div:after { - border: 1px dashed transparent; - content: ''; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - z-index: @z-index-chart; - pointer-events: none; - } - - .resizable-container.resizable-container--resizing:hover > .grid-row:after, - .hover-menu:hover + .grid-row:after, - .dashboard-component-tabs > .hover-menu:hover + div:after { - border: 1px dashed @indicator-color; - z-index: @z-index-chart--dragging; - } - - .grid-row:after, - .dashboard-component-tabs > .hover-menu + div:after { - border: 1px dashed @gray-light; - } - - /* provide hit area in case row contents is edge to edge */ - .dashboard-component-tabs-content { - .dragdroppable-row { - padding-top: 16px; - } - } -} - -.grid-row.grid-row--empty { - /* this centers the empty note content */ - align-items: center; - height: 100px; - - &:before { - position: absolute; - top: 0; - left: 0; - content: 'Empty row'; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - color: @gray; - } -} diff --git a/superset-frontend/src/dashboard/stylesheets/dashboard.less b/superset-frontend/src/dashboard/stylesheets/dashboard.less deleted file mode 100644 index b69303ce16072..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/dashboard.less +++ /dev/null @@ -1,165 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -/* header has mysterious extra margin */ -header.top { - margin-bottom: 2px; - z-index: 10; -} - -body { - h1 { - font-weight: @font-weight-bold; - line-height: @line-height-base; - font-size: @font-size-xxl; - letter-spacing: -0.2px; - margin-top: 12px; - margin-bottom: 12px; - } - - h2 { - font-weight: @font-weight-bold; - line-height: @line-height-base; - font-size: @font-size-xl; - margin-top: 12px; - margin-bottom: 8px; - } - - h3, - h4, - h5, - h6 { - font-weight: @font-weight-bold; - line-height: @line-height-base; - font-size: @font-size-l; - letter-spacing: 0.2px; - margin-top: 8px; - margin-bottom: 4px; - } - - p { - margin: 0 0 8px 0; - } -} - -.dashboard .chart-header { - font-size: @font-size-l; - font-weight: @font-weight-bold; - margin-bottom: 4px; - display: flex; - max-width: 100%; - align-items: flex-start; - min-height: 0; - flex-shrink: 0; - - & > .header-title { - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; - flex-grow: 1; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - - & > span.ant-tooltip-open { - display: inline; - } - } - - & > .header-controls { - display: flex; - - & > * { - margin-left: 8px; - } - } - - .dropdown.btn-group { - pointer-events: none; - vertical-align: top; - & > * { - pointer-events: auto; - } - } - - .dropdown-toggle.btn.btn-default { - background: none; - border: none; - box-shadow: none; - } - - .dropdown-menu.dropdown-menu-right { - top: 20px; - } - - .divider { - margin: 5px 0; - } - - .refresh-tooltip { - display: block; - height: 16px; - margin: 3px 0; - color: @gray; - } -} - -.dashboard .chart-header, -.dashboard .dashboard-header { - .dropdown-menu { - padding: 9px 0; - } - - .dropdown-menu li { - font-weight: @font-weight-normal; - } -} - -.react-bs-container-body { - max-height: 400px; - overflow-y: auto; -} - -.hidden, -#pageDropDown { - display: none; -} - -.separator .chart-container { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; -} - -.dashboard .title { - margin: 0 20px; -} - -.slice_container .alert { - margin: 10px; -} - -i.danger { - color: @danger; -} - -i.warning { - color: @warning; -} diff --git a/superset-frontend/src/dashboard/stylesheets/dnd.less b/superset-frontend/src/dashboard/stylesheets/dnd.less deleted file mode 100644 index 2465c6fac0661..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/dnd.less +++ /dev/null @@ -1,130 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -.dragdroppable { - position: relative; -} - -// Fixes ISSUE-12181 - before in chart's contract-trigger breaks drag and drop mode -.dashboard--editing { - .contract-trigger:before { - display: none; - } -} - -.dragdroppable--dragging { - opacity: 0.2; -} - -.dragdroppable-row { - width: 100%; -} - -.dragdroppable-column { - .resizable-container { - span { - div { - z-index: @z-index-above-dashboard-charts; - } - } - } -} - -/* drop indicators */ -.drop-indicator { - display: block; - background-color: @indicator-color; - position: absolute; - z-index: @z-index-above-dashboard-charts; -} - -.drop-indicator--top { - top: 0; - left: 0; - height: 4px; - width: 100%; - min-width: 16px; -} - -.drop-indicator--bottom { - top: 100%; - left: 0; - height: 4px; - width: 100%; - min-width: 16px; -} - -.empty-droptarget:first-child { - .drop-indicator--bottom { - top: 24px; - } -} - -.drop-indicator--right { - top: 0; - left: 100%; - height: 100%; - width: 4px; - min-height: 16px; -} - -.drop-indicator--left { - top: 0; - left: 0; - height: 100%; - width: 4px; - min-height: 16px; -} - -/* empty drop targets */ -.dashboard-component-tabs-content { - & > .empty-droptarget { - position: absolute; - width: 100%; - } - - & > .empty-droptarget:first-child { - height: 14px; - top: -2px; - z-index: @z-index-above-dashboard-charts; - } - - & > .empty-droptarget:last-child { - height: 12px; - bottom: 0px; - } -} - -.grid-content { - /* note we don't do a :last-child selection because - assuming bottom empty-droptarget is last child is fragile */ - & > .empty-droptarget { - width: 100%; - height: 100%; - } - - & > .empty-droptarget:first-child { - height: 48px; - margin-top: -24px; - margin-bottom: -24px; - } - - & > .empty-droptarget:only-child { - height: 80vh; - } -} diff --git a/superset-frontend/src/dashboard/stylesheets/filter-scope-selector.less b/superset-frontend/src/dashboard/stylesheets/filter-scope-selector.less deleted file mode 100644 index e12054e09da7c..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/filter-scope-selector.less +++ /dev/null @@ -1,259 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -@import '../../assets/stylesheets/less/variables.less'; - -.filter-scope-container { - display: flex; - flex-direction: column; - height: 80%; - margin-right: -24px; - font-size: @font-size-m; - - .nav.nav-tabs { - border: none; - } - - .filter-scope-body { - flex: 1; - max-height: calc(100% - 128px); - - .filter-field-pane, - .filter-scope-pane { - overflow-y: scroll; - } - } - - .warning-message { - padding: 24px; - } -} - -.filter-scope-header { - height: 64px; - border-bottom: 1px solid @gray-light; - padding-left: 24px; - margin-left: -24px; - - h4 { - margin-top: 0; - } - - .selected-fields { - margin: 12px 0 16px; - visibility: hidden; - - &.multi-edit-mode { - visibility: visible; - } - - .selected-scopes { - padding-left: 5px; - } - } -} - -.filters-scope-selector { - display: flex; - flex-direction: row; - position: relative; - height: 100%; - - a, - a:active, - a:hover { - color: @almost-black; - text-decoration: none; - } - - .react-checkbox-tree .rct-icon.rct-icon-expand-all, - .react-checkbox-tree .rct-icon.rct-icon-collapse-all { - font-size: @font-size-m; - font-family: @font-family-sans-serif; - color: @brand-primary; - - &::before { - content: ''; - } - - &:hover { - text-decoration: underline; - } - - &:focus { - outline: none; - } - } - - .filter-field-pane { - position: relative; - width: 40%; - padding: 16px 16px 16px 0; - border-right: 1px solid @gray-light; - - .filter-container { - label { - font-weight: @font-weight-normal; - margin: 0 0 0 16px; - word-break: break-all; - } - } - - .filter-field-item { - height: 35px; - display: flex; - align-items: center; - justify-content: center; - padding: 0 24px; - margin-left: -24px; - - &.is-selected { - border: 1px solid @gray-heading; - border-radius: @border-radius-large; - background-color: @gray-bg; - margin-left: -25px; - } - } - - .react-checkbox-tree { - .rct-title .root { - font-weight: @font-weight-bold; - } - - .rct-text { - height: 40px; - } - } - } - - .filter-scope-pane { - position: relative; - flex: 1; - padding: 16px 24px 16px 16px; - } - - .react-checkbox-tree { - flex-direction: column; - color: @almost-black; - font-size: @font-size-m; - - .filter-scope-type { - padding: 8px 0; - display: flex; - align-items: center; - - &.chart { - font-weight: @font-weight-normal; - } - - &.selected-filter { - padding-left: 28px; - position: relative; - color: @gray-heading; - - &::before { - content: ' '; - position: absolute; - left: 0; - top: 50%; - width: 18px; - height: 18px; - border-radius: @border-radius-normal; - margin-top: -9px; - box-shadow: inset 0 0 0 2px @gray-light; - background: #f2f2f2; - } - } - - &.root { - font-weight: @font-weight-bold; - } - } - - .rct-checkbox { - svg { - position: relative; - top: 3px; - width: 18px; - } - } - - .rct-node-leaf { - .rct-bare-label { - &::before { - padding-left: 5px; - } - } - } - - .rct-options { - text-align: left; - margin-left: 0; - margin-bottom: 8px; - } - - .rct-text { - margin: 0; - display: flex; - } - - .rct-title { - display: block; - } - - // disable style from react-checkbox-trees.css - .rct-node-clickable:hover, - .rct-node-clickable:focus, - label:hover, - label:active { - background: none !important; - } - } - - .multi-edit-mode { - &.filter-scope-pane { - .rct-node.rct-node-leaf .filter-scope-type.filter_box { - display: none; - } - } - - .filter-field-item { - padding: 0 16px 0 50px; - margin-left: -50px; - - &.is-selected { - margin-left: -51px; - } - } - } - - .scope-search { - position: absolute; - right: 16px; - top: 16px; - border-radius: @border-radius-large; - border: 1px solid @gray-light; - padding: 4px 8px 4px 8px; - font-size: @font-size-m; - outline: none; - - &:focus { - border: 1px solid @brand-primary; - } - } -} diff --git a/superset-frontend/src/dashboard/stylesheets/popover-menu.less b/superset-frontend/src/dashboard/stylesheets/popover-menu.less deleted file mode 100644 index 4abc494993609..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/popover-menu.less +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -.with-popover-menu { - position: relative; - outline: none; -} - -.grid-row.grid-row--empty .with-popover-menu { - /* drop indicator doesn't show up without this */ - width: 100%; - height: 100%; -} - -.with-popover-menu--focused:after { - content: ''; - position: absolute; - top: 0px; - left: 0px; - width: 100%; - height: 100%; - border: 2px solid @indicator-color; - pointer-events: none; -} - -.popover-menu { - position: absolute; - flex-wrap: nowrap; - left: 1px; - top: -42px; - height: 40px; - padding: 0 16px; - background: @lightest; - box-shadow: 0 1px 2px 1px fade(@darkest, @opacity-medium-light); - font-size: @font-size-m; - cursor: default; - z-index: @z-index-max; - - &, - .menu-item { - display: flex; - flex-direction: row; - align-items: center; - } - - /* vertical spacer after each menu item */ - .menu-item:not(:only-child):not(:last-child):after { - content: ''; - width: 1; - height: 100%; - background: @gray-light; - margin: 0 16px; - } -} - -/* the focus menu doesn't account for parent padding */ -.dashboard-component-tabs li .with-popover-menu--focused:after { - top: -12px; - left: -8px; - width: ~'calc(100% + 16px)'; /* escape for .less */ - height: ~'calc(100% + 28px)'; -} - -.dashboard-component-tabs li .popover-menu { - top: -56px; - left: -7px; -} - -.hover-dropdown .btn { - &:hover, - &:active, - &:focus { - background: initial; - box-shadow: none; - } -} - -.hover-dropdown, -.popover-menu { - li.dropdown-item { - &:hover a { - background: @menu-hover; - } - - &.active a { - background: @gray-light; - font-weight: @font-weight-bold; - color: @almost-black; - } - } -} - -/* background style menu */ -.background-style-option { - display: inline-block; - - &:before { - content: ''; - width: 1em; - height: 1em; - margin-right: 8px; - display: inline-block; - vertical-align: middle; - } - - &.background--white { - padding-left: 0; - background: transparent; - - &:before { - background: @lightest; - border: 1px solid @gray-light; - } - } - - /* Create the transparent rect icon */ - &.background--transparent:before { - background-image: linear-gradient(45deg, @gray 25%, transparent 25%), - linear-gradient(-45deg, @gray 25%, transparent 25%), - linear-gradient(45deg, transparent 75%, @gray 75%), - linear-gradient(-45deg, transparent 75%, @gray 75%); - background-size: 8px 8px; - background-position: 0 0, 0 4px, 4px -4px, -4px 0px; - } -} diff --git a/superset-frontend/src/dashboard/stylesheets/resizable.less b/superset-frontend/src/dashboard/stylesheets/resizable.less deleted file mode 100644 index be7182716d044..0000000000000 --- a/superset-frontend/src/dashboard/stylesheets/resizable.less +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -.resizable-container { - background-color: transparent; - position: relative; - - /* re-resizable sets an empty div to 100% width and height, which doesn't - play well with many 100% height containers we need - */ - & ~ div { - width: auto !important; - height: auto !important; - } -} - -.resizable-container--resizing { - /* after ensures border visibility on top of any children */ - &:after { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - box-shadow: inset 0 0 0 2px @indicator-color; - } - - & > span .resize-handle { - border-color: @indicator-color; - } -} - -.resize-handle { - opacity: 0; - z-index: @z-index-above-dashboard-charts; - - &--bottom-right { - position: absolute; - border: solid; - border-width: 0 1.5px 1.5px 0; - border-right-color: @gray; - border-bottom-color: @gray; - right: 16px; - bottom: 16px; - width: 8px; - height: 8px; - } - - &--right { - width: 2px; - height: 20px; - right: 4px; - top: 50%; - transform: translate(0, -50%); - position: absolute; - border-left: 1px solid @gray; - border-right: 1px solid @gray; - } - - &--bottom { - height: 2px; - width: 20px; - bottom: 4px; - left: 50%; - transform: translate(-50%); - position: absolute; - border-top: 1px solid @gray; - border-bottom: 1px solid @gray; - } -} - -.resizable-container:hover .resize-handle, -.resizable-container--resizing .resize-handle { - opacity: 1; -} - -.dragdroppable-column .resizable-container-handle--right { - /* override the default because the inner column's handle's mouse target is very small */ - right: 0 !important; -} - -.dragdroppable-column .dragdroppable-column .resizable-container-handle--right { - /* override the default because the inner column's handle's mouse target is very small */ - right: 0 !important; -} - -.resizable-container-handle--bottom { - bottom: 0 !important; -} diff --git a/superset-frontend/src/dashboard/types.ts b/superset-frontend/src/dashboard/types.ts index e4b8227689ce4..87dee0b05ab68 100644 --- a/superset-frontend/src/dashboard/types.ts +++ b/superset-frontend/src/dashboard/types.ts @@ -27,8 +27,9 @@ import { import { Dataset } from '@superset-ui/chart-controls'; import { chart } from 'src/components/Chart/chartReducer'; import componentTypes from 'src/dashboard/util/componentTypes'; +import { UrlParamEntries } from 'src/utils/urlUtils'; -import { User } from 'src/types/bootstrapTypes'; +import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; import { ChartState } from '../explore/types'; export { Dashboard } from 'src/types/Dashboard'; @@ -39,19 +40,23 @@ export type ChartReducerInitialState = typeof chart; // Ref: https://github.com/apache/superset/blob/dcac860f3e5528ecbc39e58f045c7388adb5c3d0/superset-frontend/src/dashboard/reducers/getInitialState.js#L120 export interface ChartQueryPayload extends Partial<ChartReducerInitialState> { id: number; - formData: ChartProps['formData']; form_data?: ChartProps['rawFormData']; [key: string]: unknown; } /** Chart state of redux */ export type Chart = ChartState & { - formData: { + form_data: { viz_type: string; datasource: string; }; }; +export enum FilterBarOrientation { + VERTICAL = 'VERTICAL', + HORIZONTAL = 'HORIZONTAL', +} + export type ActiveTabs = string[]; export type DashboardLayout = { [key: string]: LayoutItem }; export type DashboardLayoutState = { present: DashboardLayout }; @@ -65,6 +70,25 @@ export type DashboardState = { isRefreshing: boolean; isFiltersRefreshing: boolean; hasUnsavedChanges: boolean; + dashboardIsSaving: boolean; + colorScheme: string; + sliceIds: number[]; + directPathLastUpdated: number; + focusedFilterField?: { + chartId: number; + column: string; + }; + overwriteConfirmMetadata?: { + updatedAt: string; + updatedBy: string; + overwriteConfirmItems: { + keyPath: string; + oldValue: string; + newValue: string; + }[]; + dashboardId: number; + data: JsonObject; + }; }; export type DashboardInfo = { id: number; @@ -79,7 +103,15 @@ export type DashboardInfo = { native_filter_configuration: JsonObject; show_native_filters: boolean; chart_configuration: JsonObject; + color_scheme: string; + color_namespace: string; + color_scheme_domain: string[]; + label_colors: JsonObject; + shared_label_colors: JsonObject; + cross_filters_enabled: boolean; }; + crossFiltersEnabled: boolean; + filterBarOrientation: FilterBarOrientation; }; export type ChartsState = { [key: string]: Chart }; @@ -105,7 +137,7 @@ export type RootState = { dataMask: DataMaskStateWithId; impressionId: string; nativeFilters: NativeFiltersState; - user: User; + user: UserWithPermissionsAndRoles; }; /** State of dashboardLayout in redux */ @@ -145,13 +177,17 @@ export type ActiveFilters = { [key: string]: ActiveFilter; }; -export type DashboardPermalinkValue = { +export interface DashboardPermalinkState { + dataMask: DataMaskStateWithId; + activeTabs: string[]; + anchor: string; + urlParams?: UrlParamEntries; +} + +export interface DashboardPermalinkValue { dashboardId: string; - state: { - filterState: DataMaskStateWithId; - hash: string; - }; -}; + state: DashboardPermalinkState; +} export type EmbeddedDashboard = { uuid: string; diff --git a/superset-frontend/src/dashboard/util/activeAllDashboardFilters.ts b/superset-frontend/src/dashboard/util/activeAllDashboardFilters.ts index f0a9b709ee5db..14ae2d4ea083a 100644 --- a/superset-frontend/src/dashboard/util/activeAllDashboardFilters.ts +++ b/superset-frontend/src/dashboard/util/activeAllDashboardFilters.ts @@ -18,61 +18,11 @@ */ import { DataMaskStateWithId, - Filters, + PartialFilters, JsonObject, - NativeFilterScope, } from '@superset-ui/core'; -import { CHART_TYPE } from './componentTypes'; -import { ActiveFilters, Layout, LayoutItem } from '../types'; +import { ActiveFilters } from '../types'; import { ChartConfiguration } from '../reducers/types'; -import { DASHBOARD_ROOT_ID } from './constants'; - -// Looking for affected chart scopes and values -export const findAffectedCharts = ({ - child, - layout, - scope, - activeFilters, - filterId, - extraFormData, -}: { - child: string; - layout: { [key: string]: LayoutItem }; - scope: NativeFilterScope; - activeFilters: ActiveFilters; - filterId: string; - extraFormData: any; -}) => { - const chartId = layout[child]?.meta?.chartId; - if (layout[child].type === CHART_TYPE) { - // Ignore excluded charts - if (scope.excluded.includes(chartId)) { - return; - } - if (!activeFilters[filterId]) { - // Small mutation but simplify logic - // eslint-disable-next-line no-param-reassign - activeFilters[filterId] = { - scope: [], - values: extraFormData, - }; - } - // Add not excluded chart scopes(to know what charts refresh) and values(refresh only if its value changed) - activeFilters[filterId].scope.push(chartId); - return; - } - // If child is not chart, recursive iterate over its children - layout[child].children.forEach((child: string) => - findAffectedCharts({ - child, - layout, - scope, - activeFilters, - filterId, - extraFormData, - }), - ); -}; export const getRelevantDataMask = ( dataMask: DataMaskStateWithId, @@ -89,36 +39,27 @@ export const getAllActiveFilters = ({ chartConfiguration, nativeFilters, dataMask, - layout, + allSliceIds, }: { chartConfiguration: ChartConfiguration; dataMask: DataMaskStateWithId; - nativeFilters: Filters; - layout: Layout; + nativeFilters: PartialFilters; + allSliceIds: number[]; }): ActiveFilters => { const activeFilters = {}; // Combine native filters with cross filters, because they have similar logic Object.values(dataMask).forEach(({ id: filterId, extraFormData }) => { - const scope = nativeFilters?.[filterId]?.scope ?? - chartConfiguration?.[filterId]?.crossFilters?.scope ?? { - rootPath: [DASHBOARD_ROOT_ID], - excluded: [filterId], - }; + const scope = + nativeFilters?.[filterId]?.chartsInScope ?? + chartConfiguration?.[filterId]?.crossFilters?.chartsInScope ?? + allSliceIds ?? + []; // Iterate over all roots to find all affected charts - scope.rootPath.forEach((layoutItemId: string | number) => { - layout[layoutItemId]?.children?.forEach((child: string) => { - // Need exclude from affected charts, charts that located in scope `excluded` - findAffectedCharts({ - child, - layout, - scope, - activeFilters, - filterId, - extraFormData, - }); - }); - }); + activeFilters[filterId] = { + scope, + values: extraFormData, + }; }); return activeFilters; }; diff --git a/superset-frontend/src/dashboard/util/activeDashboardFilters.js b/superset-frontend/src/dashboard/util/activeDashboardFilters.js index 41871f7c0b084..3369dc1c5be62 100644 --- a/superset-frontend/src/dashboard/util/activeDashboardFilters.js +++ b/superset-frontend/src/dashboard/util/activeDashboardFilters.js @@ -45,10 +45,10 @@ export function isFilterBox(chartId) { // this function is to find all filter values applied to a chart, // it goes through all active filters and their scopes. // return: { [column]: array of selected values } -export function getAppliedFilterValues(chartId) { +export function getAppliedFilterValues(chartId, filters) { // use cached data if possible if (!(chartId in appliedFilterValuesByChart)) { - const applicableFilters = Object.entries(activeFilters).filter( + const applicableFilters = Object.entries(filters || activeFilters).filter( ([, { scope: chartIds }]) => chartIds.includes(chartId), ); appliedFilterValuesByChart[chartId] = flow( diff --git a/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts b/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts index 0bbabfcde52d1..cbed55755a89e 100644 --- a/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts +++ b/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts @@ -20,9 +20,9 @@ import { DataMaskStateWithId, DataRecordFilters, JsonObject, - NativeFiltersState, + PartialFilters, } from '@superset-ui/core'; -import { ChartQueryPayload, Charts, LayoutItem } from 'src/dashboard/types'; +import { ChartQueryPayload } from 'src/dashboard/types'; import { getExtraFormData } from 'src/dashboard/components/nativeFilters/utils'; import { areObjectsEqual } from 'src/reduxUtils'; import getEffectiveExtraFilters from './getEffectiveExtraFilters'; @@ -37,17 +37,16 @@ const cachedFormdataByChart = {}; export interface GetFormDataWithExtraFiltersArguments { chartConfiguration: ChartConfiguration; chart: ChartQueryPayload; - charts: Charts; filters: DataRecordFilters; - layout: { [key: string]: LayoutItem }; colorScheme?: string; colorNamespace?: string; sliceId: number; dataMask: DataMaskStateWithId; - nativeFilters: NativeFiltersState; + nativeFilters: PartialFilters; extraControls: Record<string, string | boolean | null>; labelColors?: Record<string, string>; sharedLabelColors?: Record<string, string>; + allSliceIds: number[]; } // this function merge chart's formData with dashboard filters value, @@ -55,18 +54,17 @@ export interface GetFormDataWithExtraFiltersArguments { // filters param only contains those applicable to this chart. export default function getFormDataWithExtraFilters({ chart, - charts, filters, nativeFilters, chartConfiguration, colorScheme, colorNamespace, sliceId, - layout, dataMask, extraControls, labelColors, sharedLabelColors, + allSliceIds, }: GetFormDataWithExtraFiltersArguments) { // if dashboard metadata + filters have not changed, use cache if possible const cachedFormData = cachedFormdataByChart[sliceId]; @@ -99,24 +97,20 @@ export default function getFormDataWithExtraFilters({ const activeFilters = getAllActiveFilters({ chartConfiguration, dataMask, - layout, - nativeFilters: nativeFilters.filters, + nativeFilters, + allSliceIds, }); const filterIdsAppliedOnChart = Object.entries(activeFilters) .filter(([, { scope }]) => scope.includes(chart.id)) .map(([filterId]) => filterId); if (filterIdsAppliedOnChart.length) { extraData = { - extra_form_data: getExtraFormData( - dataMask, - charts, - filterIdsAppliedOnChart, - ), + extra_form_data: getExtraFormData(dataMask, filterIdsAppliedOnChart), }; } const formData = { - ...chart.formData, + ...chart.form_data, label_colors: labelColors, shared_label_colors: sharedLabelColors, ...(colorScheme && { color_scheme: colorScheme }), diff --git a/superset-frontend/src/dashboard/util/constants.ts b/superset-frontend/src/dashboard/util/constants.ts index 640028eb4e947..0743d7a5a42d3 100644 --- a/superset-frontend/src/dashboard/util/constants.ts +++ b/superset-frontend/src/dashboard/util/constants.ts @@ -58,6 +58,7 @@ export const UNDO_LIMIT = 50; // save dash options export const SAVE_TYPE_OVERWRITE = 'overwrite'; +export const SAVE_TYPE_OVERWRITE_CONFIRMED = 'overwriteConfirmed'; export const SAVE_TYPE_NEWDASHBOARD = 'newDashboard'; // default dashboard layout data size limit diff --git a/superset-frontend/src/dashboard/util/crossFilters.ts b/superset-frontend/src/dashboard/util/crossFilters.ts new file mode 100644 index 0000000000000..061ed82634ac9 --- /dev/null +++ b/superset-frontend/src/dashboard/util/crossFilters.ts @@ -0,0 +1,26 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { FeatureFlag, isFeatureEnabled } from '@superset-ui/core'; + +export const isCrossFiltersEnabled = ( + metadataCrossFiltersEnabled: boolean | undefined, +): boolean => + isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) && + (metadataCrossFiltersEnabled === undefined || metadataCrossFiltersEnabled); diff --git a/superset-frontend/src/dashboard/util/filterboxMigrationHelper.test.ts b/superset-frontend/src/dashboard/util/filterboxMigrationHelper.test.ts index 82ed0dd8ac401..f59f36541e35f 100644 --- a/superset-frontend/src/dashboard/util/filterboxMigrationHelper.test.ts +++ b/superset-frontend/src/dashboard/util/filterboxMigrationHelper.test.ts @@ -61,7 +61,7 @@ const regionFilter = { }, modified: '<bound method AuditMixinNullable.modified of Region Filter>', slice_name: 'Region Filter', - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%2032%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%2032%7D', slice_id: 32, }; const chart1 = { @@ -88,7 +88,7 @@ const chart1 = { }, modified: "<bound method AuditMixinNullable.modified of World's Population>", slice_name: "World's Population", - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%2033%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%2033%7D', slice_id: 33, }; const chartData = [regionFilter, chart1]; diff --git a/superset-frontend/src/dashboard/util/filterboxMigrationHelper.ts b/superset-frontend/src/dashboard/util/filterboxMigrationHelper.ts index 44356637682f7..61ceec8310141 100644 --- a/superset-frontend/src/dashboard/util/filterboxMigrationHelper.ts +++ b/superset-frontend/src/dashboard/util/filterboxMigrationHelper.ts @@ -51,9 +51,6 @@ interface SliceData { granularity_sqla?: string; time_grain_sqla?: string; time_range?: string; - druid_time_origin?: string; - show_druid_time_granularity?: boolean; - show_druid_time_origin?: boolean; show_sqla_time_column?: boolean; show_sqla_time_granularity?: boolean; viz_type: string; @@ -75,7 +72,7 @@ interface PreselectedFilterColumn { [key: string]: boolean | string | number | string[] | number[]; } -interface PreselectedFiltersMeatadata { +interface PreselectedFiltersMetadata { [key: string]: PreselectedFilterColumn; } @@ -101,12 +98,9 @@ enum FILTER_COMPONENT_FILTER_TYPES { } const getPreselectedValuesFromDashboard = - (preselectedFilters: PreselectedFiltersMeatadata) => + (preselectedFilters: PreselectedFiltersMetadata) => (filterKey: string, column: string) => { - if ( - preselectedFilters[filterKey] && - preselectedFilters[filterKey][column] - ) { + if (preselectedFilters[filterKey]?.[column]) { // overwrite default values by dashboard default_filters return preselectedFilters[filterKey][column]; } @@ -161,7 +155,7 @@ const getFilterboxDependencies = (filterScopes: FilterScopesMetadata) => { export default function getNativeFilterConfig( chartData: SliceData[] = [], filterScopes: FilterScopesMetadata = {}, - preselectFilters: PreselectedFiltersMeatadata = {}, + preselectFilters: PreselectedFiltersMetadata = {}, ): Filter[] { const filterConfig: Filter[] = []; const filterBoxToFilterComponentMap: FilterBoxToFilterComponentMap = {}; @@ -206,12 +200,8 @@ export default function getNativeFilterConfig( adhoc_filters = [], datasource = '', date_filter = false, - druid_time_origin, filter_configs = [], - granularity, granularity_sqla, - show_druid_time_granularity = false, - show_druid_time_origin = false, show_sqla_time_column = false, show_sqla_time_granularity = false, time_grain_sqla, @@ -344,96 +334,6 @@ export default function getNativeFilterConfig( } filterConfig.push(timeColumnFilter); } - - if (show_druid_time_granularity) { - const { scope, immune }: FilterScopeType = - scopesByChartId[TIME_FILTER_MAP.granularity] || - DASHBOARD_FILTER_SCOPE_GLOBAL; - const druidGranularityFilter: Filter = { - id: `NATIVE_FILTER-${shortid.generate()}`, - description: 'time grain filter', - controlValues: {}, - name: TIME_FILTER_LABELS.granularity, - filterType: FILTER_COMPONENT_FILTER_TYPES.FILTER_TIMEGRAIN, - targets: [ - { - datasetId: parseInt(datasource.split('__')[0], 10), - }, - ], - cascadeParentIds: [], - defaultDataMask: {}, - type: NativeFilterType.NATIVE_FILTER, - scope: { - rootPath: scope, - excluded: immune, - }, - }; - filterBoxToFilterComponentMap[key][TIME_FILTER_MAP.granularity] = - druidGranularityFilter.id; - const dashboardDefaultValues = getDashboardDefaultValues( - key, - TIME_FILTER_MAP.granularity, - ); - if (!isEmpty(dashboardDefaultValues)) { - druidGranularityFilter.defaultDataMask = { - extraFormData: { - granularity_sqla: (dashboardDefaultValues || - granularity) as string, - }, - filterState: { - value: setValuesInArray(dashboardDefaultValues, granularity), - }, - }; - } - filterConfig.push(druidGranularityFilter); - } - - if (show_druid_time_origin) { - const { scope, immune }: FilterScopeType = - scopesByChartId[TIME_FILTER_MAP.druid_time_origin] || - DASHBOARD_FILTER_SCOPE_GLOBAL; - const druidOriginFilter: Filter = { - id: `NATIVE_FILTER-${shortid.generate()}`, - description: 'time column filter', - controlValues: {}, - name: TIME_FILTER_LABELS.druid_time_origin, - filterType: FILTER_COMPONENT_FILTER_TYPES.FILTER_TIMECOLUMN, - targets: [ - { - datasetId: parseInt(datasource.split('__')[0], 10), - }, - ], - cascadeParentIds: [], - defaultDataMask: {}, - type: NativeFilterType.NATIVE_FILTER, - scope: { - rootPath: scope, - excluded: immune, - }, - }; - filterBoxToFilterComponentMap[key][ - TIME_FILTER_MAP.druid_time_origin - ] = druidOriginFilter.id; - const dashboardDefaultValues = getDashboardDefaultValues( - key, - TIME_FILTER_MAP.druid_time_origin, - ); - if (!isEmpty(dashboardDefaultValues)) { - druidOriginFilter.defaultDataMask = { - extraFormData: { - granularity_sqla: (dashboardDefaultValues || - druid_time_origin) as string, - }, - filterState: { - value: setValuesInArray( - dashboardDefaultValues, - druid_time_origin, - ), - }, - }; - } - filterConfig.push(druidOriginFilter); - } } filter_configs.forEach(config => { diff --git a/superset-frontend/src/dashboard/util/findParentId.test.js b/superset-frontend/src/dashboard/util/findParentId.test.ts similarity index 79% rename from superset-frontend/src/dashboard/util/findParentId.test.js rename to superset-frontend/src/dashboard/util/findParentId.test.ts index d63be401076a7..b5fe36c59de7a 100644 --- a/superset-frontend/src/dashboard/util/findParentId.test.js +++ b/superset-frontend/src/dashboard/util/findParentId.test.ts @@ -41,4 +41,15 @@ describe('findParentId', () => { it('should return null if the parent cannot be found', () => { expect(findParentId({ childId: 'a', layout })).toBeNull(); }); + + it('should not throw error and return null with bad / missing inputs', () => { + // @ts-ignore + expect(findParentId(null)).toBeNull(); + // @ts-ignore + expect(findParentId({ layout })).toBeNull(); + // @ts-ignore + expect(findParentId({ childId: 'a' })).toBeNull(); + // @ts-ignore + expect(findParentId({ childId: 'a', layout: null })).toBeNull(); + }); }); diff --git a/superset-frontend/src/dashboard/util/findParentId.ts b/superset-frontend/src/dashboard/util/findParentId.ts new file mode 100644 index 0000000000000..d8dbb4dbf2514 --- /dev/null +++ b/superset-frontend/src/dashboard/util/findParentId.ts @@ -0,0 +1,68 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +interface ILayoutItem { + [key: string]: { + id: string; + children: string[]; + }; +} + +interface IStructure { + childId: string; + layout: ILayoutItem; +} + +function findParentId(structure: IStructure): string | null { + let parentId = null; + if (structure) { + const { childId, layout = {} } = structure; + // default assignment to layout only works if value is undefined, not null + if (layout) { + const ids = Object.keys(layout); + for (let i = 0; i <= ids.length - 1; i += 1) { + const id = ids[i]; + const component = layout[id] || {}; + if (id !== childId && component?.children?.includes?.(childId)) { + parentId = id; + break; + } + } + } + } + return parentId; +} + +const cache = {}; +export default function findParentIdWithCache( + structure: IStructure, +): string | null { + let parentId = null; + if (structure) { + const { childId, layout = {} } = structure; + if (cache[childId]) { + const lastParent = layout?.[cache[childId]] || {}; + if (lastParent?.children && lastParent?.children?.includes?.(childId)) { + return lastParent.id; + } + } + parentId = findParentId({ childId, layout }); + cache[childId] = parentId; + } + return parentId; +} diff --git a/superset-frontend/src/dashboard/util/findTabIndexByComponentId.test.js b/superset-frontend/src/dashboard/util/findTabIndexByComponentId.test.js index 3a3672c030b82..c41ea486335f6 100644 --- a/superset-frontend/src/dashboard/util/findTabIndexByComponentId.test.js +++ b/superset-frontend/src/dashboard/util/findTabIndexByComponentId.test.js @@ -4,7 +4,7 @@ * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the - * 'License'); you may not use this file except in compliance + * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 diff --git a/superset-frontend/src/dashboard/util/getFilterConfigsFromFormdata.js b/superset-frontend/src/dashboard/util/getFilterConfigsFromFormdata.js index 807076cfabcda..46f4512a0a9db 100644 --- a/superset-frontend/src/dashboard/util/getFilterConfigsFromFormdata.js +++ b/superset-frontend/src/dashboard/util/getFilterConfigsFromFormdata.js @@ -28,7 +28,6 @@ export default function getFilterConfigsFromFormdata(form_data = {}) { date_filter, filter_configs = [], show_druid_time_granularity, - show_druid_time_origin, show_sqla_time_column, show_sqla_time_granularity, } = form_data; @@ -101,13 +100,6 @@ export default function getFilterConfigsFromFormdata(form_data = {}) { }; } - if (show_druid_time_origin) { - updatedColumns = { - ...updatedColumns, - [TIME_FILTER_MAP.druid_time_origin]: form_data.druid_time_origin, - }; - } - configs = { ...configs, columns: updatedColumns, diff --git a/superset-frontend/src/dashboard/util/getFormDataWithExtraFilters.test.ts b/superset-frontend/src/dashboard/util/getFormDataWithExtraFilters.test.ts index 021a488e37794..34cbe4b1bd97a 100644 --- a/superset-frontend/src/dashboard/util/getFormDataWithExtraFilters.test.ts +++ b/superset-frontend/src/dashboard/util/getFormDataWithExtraFilters.test.ts @@ -35,7 +35,7 @@ describe('getFormDataWithExtraFilters', () => { queryController: null, queriesResponse: null, triggerQuery: false, - formData: { + form_data: { viz_type: 'filter_select', filters: [ { @@ -45,23 +45,18 @@ describe('getFormDataWithExtraFilters', () => { }, ], datasource: '123', + url_params: {}, }, }; const mockArgs: GetFormDataWithExtraFiltersArguments = { chartConfiguration: {}, - charts: { - [chartId as number]: mockChart, - }, chart: mockChart, filters: { region: ['Spain'], color: ['pink', 'purple'], }, sliceId: chartId, - nativeFilters: { - filters: {}, - filterSets: {}, - }, + nativeFilters: {}, dataMask: { [filterId]: { id: filterId, @@ -70,10 +65,10 @@ describe('getFormDataWithExtraFilters', () => { ownState: {}, }, }, - layout: {}, extraControls: { stack: 'Stacked', }, + allSliceIds: [chartId], }; it('should include filters from the passed filters', () => { diff --git a/superset-frontend/src/dashboard/util/getOverwriteItems.test.ts b/superset-frontend/src/dashboard/util/getOverwriteItems.test.ts new file mode 100644 index 0000000000000..e4328fb08897d --- /dev/null +++ b/superset-frontend/src/dashboard/util/getOverwriteItems.test.ts @@ -0,0 +1,57 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import getOverwriteItems from './getOverwriteItems'; + +test('returns diff items', () => { + const prevFilterScopes = { + filter1: { + scope: ['abc'], + immune: [], + }, + }; + const nextFilterScopes = { + scope: ['ROOT_ID'], + immune: ['efg'], + }; + + const prevValue = { + css: '', + json_metadata: JSON.stringify({ + filter_scopes: prevFilterScopes, + default_filters: {}, + }), + }; + + const nextValue = { + css: '.updated_css {color: white;}', + json_metadata: JSON.stringify({ + filter_scopes: nextFilterScopes, + default_filters: {}, + }), + }; + expect(getOverwriteItems(prevValue, nextValue)).toEqual([ + { keyPath: 'css', newValue: nextValue.css, oldValue: prevValue.css }, + { + keyPath: 'json_metadata.filter_scopes', + newValue: JSON.stringify(nextFilterScopes, null, 2), + oldValue: JSON.stringify(prevFilterScopes, null, 2), + }, + ]); +}); diff --git a/superset-frontend/src/dashboard/util/getOverwriteItems.ts b/superset-frontend/src/dashboard/util/getOverwriteItems.ts new file mode 100644 index 0000000000000..7492b8aeacf71 --- /dev/null +++ b/superset-frontend/src/dashboard/util/getOverwriteItems.ts @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { JsonObject } from '@superset-ui/core'; +import { OVERWRITE_INSPECT_FIELDS } from 'src/dashboard/constants'; + +const JSON_KEYS = new Set(['json_metadata', 'position_json']); + +function extractValue(object: JsonObject, keyPath: string) { + return keyPath.split('.').reduce((obj: JsonObject, key: string) => { + const value = obj?.[key]; + return JSON_KEYS.has(key) && value ? JSON.parse(value) : value; + }, object); +} + +export default function getOverwriteItems(prev: JsonObject, next: JsonObject) { + return OVERWRITE_INSPECT_FIELDS.map(keyPath => ({ + keyPath, + ...(keyPath.split('.').find(key => JSON_KEYS.has(key)) + ? { + oldValue: + JSON.stringify(extractValue(prev, keyPath), null, 2) || '{}', + newValue: + JSON.stringify(extractValue(next, keyPath), null, 2) || '{}', + } + : { + oldValue: extractValue(prev, keyPath) || '', + newValue: extractValue(next, keyPath) || '', + }), + })).filter(({ oldValue, newValue }) => oldValue !== newValue); +} diff --git a/superset-frontend/src/dashboard/util/getSliceHeaderTooltip.tsx b/superset-frontend/src/dashboard/util/getSliceHeaderTooltip.tsx new file mode 100644 index 0000000000000..57def408b6c66 --- /dev/null +++ b/superset-frontend/src/dashboard/util/getSliceHeaderTooltip.tsx @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; +import { detectOS } from 'src/utils/common'; + +export const getSliceHeaderTooltip = (sliceName: string | undefined) => { + if (isFeatureEnabled(FeatureFlag.DASHBOARD_EDIT_CHART_IN_NEW_TAB)) { + return sliceName + ? t('Click to edit %s in a new tab', sliceName) + : t('Click to edit chart.'); + } + const isMac = detectOS() === 'MacOS'; + const firstLine = sliceName + ? t('Click to edit %s.', sliceName) + : t('Click to edit chart.'); + const secondLine = t( + 'Use %s to open in a new tab.', + isMac ? t('⌘ + click') : t('ctrl + click'), + ); + return ( + <> + <div>{firstLine}</div> + <div>{secondLine}</div> + </> + ); +}; diff --git a/superset-frontend/src/dashboard/util/logging/childChartsDidLoad.js b/superset-frontend/src/dashboard/util/logging/childChartsDidLoad.js index fc6fa68fbd5d1..7cef9ae6dc521 100644 --- a/superset-frontend/src/dashboard/util/logging/childChartsDidLoad.js +++ b/superset-frontend/src/dashboard/util/logging/childChartsDidLoad.js @@ -26,7 +26,7 @@ export default function childChartsDidLoad({ chartQueries, layout, id }) { const query = chartQueries[chartId] || {}; // filterbox's don't re-render, don't use stale update time - if (query.formData && query.formData.viz_type !== 'filter_box') { + if (query.form_data && query.form_data.viz_type !== 'filter_box') { minQueryStartTime = Math.min( query.chartUpdateStartTime, minQueryStartTime, diff --git a/superset-frontend/src/dashboard/util/newComponentFactory.js b/superset-frontend/src/dashboard/util/newComponentFactory.js index 8fddfda83c385..bec990b4e6600 100644 --- a/superset-frontend/src/dashboard/util/newComponentFactory.js +++ b/superset-frontend/src/dashboard/util/newComponentFactory.js @@ -46,7 +46,7 @@ const typeToDefaultMetaData = { }, [DIVIDER_TYPE]: null, [HEADER_TYPE]: { - text: 'New header', + text: t('New header'), headerSize: MEDIUM_HEADER, background: BACKGROUND_TRANSPARENT, }, diff --git a/superset-frontend/src/dashboard/util/findPermission.test.ts b/superset-frontend/src/dashboard/util/permissionUtils.test.ts similarity index 74% rename from superset-frontend/src/dashboard/util/findPermission.test.ts rename to superset-frontend/src/dashboard/util/permissionUtils.test.ts index 0752bad404443..d19b048769ecb 100644 --- a/superset-frontend/src/dashboard/util/findPermission.test.ts +++ b/superset-frontend/src/dashboard/util/permissionUtils.test.ts @@ -20,12 +20,13 @@ import { UndefinedUser, UserWithPermissionsAndRoles, } from 'src/types/bootstrapTypes'; -import Dashboard from 'src/types/Dashboard'; +import { Dashboard } from 'src/types/Dashboard'; import Owner from 'src/types/Owner'; -import findPermission, { +import { + canUserAccessSqlLab, canUserEditDashboard, isUserAdmin, -} from './findPermission'; +} from './permissionUtils'; const ownerUser: UserWithPermissionsAndRoles = { createdOn: '2021-05-12T16:56:22.116839', @@ -63,55 +64,15 @@ const owner: Owner = { username: ownerUser.username, }; -const undefinedUser: UndefinedUser = {}; - -describe('findPermission', () => { - it('findPermission for single role', () => { - expect(findPermission('abc', 'def', { role: [['abc', 'def']] })).toEqual( - true, - ); - - expect(findPermission('abc', 'def', { role: [['abc', 'de']] })).toEqual( - false, - ); - - expect(findPermission('abc', 'def', { role: [] })).toEqual(false); - }); - - it('findPermission for multiple roles', () => { - expect( - findPermission('abc', 'def', { - role1: [ - ['ccc', 'aaa'], - ['abc', 'def'], - ], - role2: [['abc', 'def']], - }), - ).toEqual(true); - - expect( - findPermission('abc', 'def', { - role1: [['abc', 'def']], - role2: [['abc', 'dd']], - }), - ).toEqual(true); - - expect( - findPermission('abc', 'def', { - role1: [['ccc', 'aaa']], - role2: [['aaa', 'ddd']], - }), - ).toEqual(false); - - expect(findPermission('abc', 'def', { role1: [], role2: [] })).toEqual( - false, - ); - }); +const sqlLabUser: UserWithPermissionsAndRoles = { + ...ownerUser, + roles: { + ...ownerUser.roles, + sql_lab: [], + }, +}; - it('handles nonexistent roles', () => { - expect(findPermission('abc', 'def', null)).toEqual(false); - }); -}); +const undefinedUser: UndefinedUser = {}; describe('canUserEditDashboard', () => { const dashboard: Dashboard = { @@ -160,6 +121,10 @@ test('isUserAdmin returns true for admin user', () => { expect(isUserAdmin(adminUser)).toEqual(true); }); +test('isUserAdmin returns false for undefined', () => { + expect(isUserAdmin(undefined)).toEqual(false); +}); + test('isUserAdmin returns false for undefined user', () => { expect(isUserAdmin(undefinedUser)).toEqual(false); }); @@ -167,3 +132,23 @@ test('isUserAdmin returns false for undefined user', () => { test('isUserAdmin returns false for non-admin user', () => { expect(isUserAdmin(ownerUser)).toEqual(false); }); + +test('canUserAccessSqlLab returns true for admin user', () => { + expect(canUserAccessSqlLab(adminUser)).toEqual(true); +}); + +test('canUserAccessSqlLab returns false for undefined', () => { + expect(canUserAccessSqlLab(undefined)).toEqual(false); +}); + +test('canUserAccessSqlLab returns false for undefined user', () => { + expect(canUserAccessSqlLab(undefinedUser)).toEqual(false); +}); + +test('canUserAccessSqlLab returns false for non-sqllab role', () => { + expect(canUserAccessSqlLab(ownerUser)).toEqual(false); +}); + +test('canUserAccessSqlLab returns true for sqllab role', () => { + expect(canUserAccessSqlLab(sqlLabUser)).toEqual(true); +}); diff --git a/superset-frontend/src/dashboard/util/findPermission.ts b/superset-frontend/src/dashboard/util/permissionUtils.ts similarity index 78% rename from superset-frontend/src/dashboard/util/findPermission.ts rename to superset-frontend/src/dashboard/util/permissionUtils.ts index 6edefbc997ad9..3ea63976bfdaa 100644 --- a/superset-frontend/src/dashboard/util/findPermission.ts +++ b/superset-frontend/src/dashboard/util/permissionUtils.ts @@ -16,31 +16,21 @@ * specific language governing permissions and limitations * under the License. */ -import memoizeOne from 'memoize-one'; import { - UserRoles, isUserWithPermissionsAndRoles, UndefinedUser, UserWithPermissionsAndRoles, } from 'src/types/bootstrapTypes'; -import Dashboard from 'src/types/Dashboard'; - -const findPermission = memoizeOne( - (perm: string, view: string, roles?: UserRoles | null) => - !!roles && - Object.values(roles).some(permissions => - permissions.some(([perm_, view_]) => perm_ === perm && view_ === view), - ), -); - -export default findPermission; +import { Dashboard } from 'src/types/Dashboard'; +import { findPermission } from 'src/utils/findPermission'; // this should really be a config value, // but is hardcoded in backend logic already, so... const ADMIN_ROLE_NAME = 'admin'; +const SQL_LAB_ROLE = 'sql_lab'; export const isUserAdmin = ( - user: UserWithPermissionsAndRoles | UndefinedUser, + user?: UserWithPermissionsAndRoles | UndefinedUser, ) => isUserWithPermissionsAndRoles(user) && Object.keys(user.roles || {}).some( @@ -61,3 +51,15 @@ export const canUserEditDashboard = ( isUserWithPermissionsAndRoles(user) && (isUserAdmin(user) || isUserDashboardOwner(dashboard, user)) && findPermission('can_write', 'Dashboard', user.roles); + +export function canUserAccessSqlLab( + user?: UserWithPermissionsAndRoles | UndefinedUser, +) { + return ( + isUserAdmin(user) || + (isUserWithPermissionsAndRoles(user) && + Object.keys(user.roles || {}).some( + role => role.toLowerCase() === SQL_LAB_ROLE, + )) + ); +} diff --git a/superset-frontend/src/dashboard/util/propShapes.jsx b/superset-frontend/src/dashboard/util/propShapes.jsx index 37aaac2e2180e..09380951bac04 100644 --- a/superset-frontend/src/dashboard/util/propShapes.jsx +++ b/superset-frontend/src/dashboard/util/propShapes.jsx @@ -63,7 +63,7 @@ export const slicePropShape = PropTypes.shape({ datasource_name: PropTypes.string, datasource_link: PropTypes.string, changed_on: PropTypes.number.isRequired, - modified: PropTypes.string.isRequired, + modified: PropTypes.string, viz_type: PropTypes.string.isRequired, description: PropTypes.string, description_markeddown: PropTypes.string, @@ -84,10 +84,10 @@ export const dashboardFilterPropShape = PropTypes.shape({ }); export const dashboardStatePropShape = PropTypes.shape({ - sliceIds: PropTypes.arrayOf(PropTypes.number).isRequired, + sliceIds: PropTypes.arrayOf(PropTypes.number), expandedSlices: PropTypes.object, editMode: PropTypes.bool, - isPublished: PropTypes.bool.isRequired, + isPublished: PropTypes.bool, colorNamespace: PropTypes.string, colorScheme: PropTypes.string, updatedColorScheme: PropTypes.bool, @@ -95,13 +95,13 @@ export const dashboardStatePropShape = PropTypes.shape({ }); export const dashboardInfoPropShape = PropTypes.shape({ - id: PropTypes.number.isRequired, + id: PropTypes.number, metadata: PropTypes.object, slug: PropTypes.string, - dash_edit_perm: PropTypes.bool.isRequired, - dash_save_perm: PropTypes.bool.isRequired, + dash_edit_perm: PropTypes.bool, + dash_save_perm: PropTypes.bool, common: PropTypes.object, - userId: PropTypes.string.isRequired, + userId: PropTypes.string, }); /* eslint-disable-next-line no-undef */ diff --git a/superset-frontend/src/dashboard/util/updateComponentParentsList.js b/superset-frontend/src/dashboard/util/updateComponentParentsList.js index 48f01e20a61d5..44e6c24a19adb 100644 --- a/superset-frontend/src/dashboard/util/updateComponentParentsList.js +++ b/superset-frontend/src/dashboard/util/updateComponentParentsList.js @@ -1,3 +1,5 @@ +import { logging } from '@superset-ui/core'; + /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -20,16 +22,34 @@ export default function updateComponentParentsList({ currentComponent, layout = {}, }) { - if (currentComponent && layout[currentComponent.id]) { - const parentsList = (currentComponent.parents || []).slice(); - parentsList.push(currentComponent.id); + if (currentComponent && layout) { + if (layout[currentComponent.id]) { + const parentsList = Array.isArray(currentComponent.parents) + ? currentComponent.parents.slice() + : []; + + parentsList.push(currentComponent.id); - currentComponent.children.forEach(childId => { - layout[childId].parents = parentsList; // eslint-disable-line no-param-reassign - updateComponentParentsList({ - currentComponent: layout[childId], - layout, - }); - }); + if (Array.isArray(currentComponent.children)) { + currentComponent.children.forEach(childId => { + const child = layout[childId]; + if (child) { + child.parents = parentsList; // eslint-disable-line no-param-reassign + updateComponentParentsList({ + currentComponent: child, + layout, + }); + } else { + logging.warn( + `The current layout does not contain a component with the id: ${childId}. Skipping this component`, + ); + } + }); + } + } else { + logging.warn( + `The current layout does not contain a component with the id: ${currentComponent?.id}. Skipping this component`, + ); + } } } diff --git a/superset-frontend/src/dashboard/util/updateComponentParentsList.test.js b/superset-frontend/src/dashboard/util/updateComponentParentsList.test.js index c8f66b1934069..c5a15d72901b6 100644 --- a/superset-frontend/src/dashboard/util/updateComponentParentsList.test.js +++ b/superset-frontend/src/dashboard/util/updateComponentParentsList.test.js @@ -4,7 +4,7 @@ * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the - * 'License'); you may not use this file except in compliance + * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 @@ -95,3 +95,68 @@ describe('updateComponentParentsList', () => { ]); }); }); + +describe('updateComponentParentsList with bad inputs', () => { + it('should handle invalid parameters and not throw error', () => { + updateComponentParentsList({ + currentComponent: undefined, + layout: undefined, + }); + + expect(() => + updateComponentParentsList({ + currentComponent: undefined, + layout: undefined, + }), + ).not.toThrow(); + + expect(() => + updateComponentParentsList({ + currentComponent: {}, + layout: undefined, + }), + ).not.toThrow(); + + /** + * the assignment of layout = {} only works for undefined, not null + * This was a missed case in the function previously. + * This test ensure the null check is not removed + */ + expect(() => + updateComponentParentsList({ + currentComponent: {}, + layout: null, + }), + ).not.toThrow(); + + /** + * This test catches an edge case that caused runtime error in production system where + * a simple logic flaw performed a dot notation lookup on an undefined object + */ + expect(() => + updateComponentParentsList({ + currentComponent: { id: 'id3', children: ['id1', 'id2'] }, + layout: { id3: {} }, + }), + ).not.toThrow(); + + /** + * This test catches an edge case that causes runtime error where + * a simple logic flaw performed currentComponent.children.forEach without + * verifying currentComponent.children is an Array with a .forEach function defined + */ + expect(() => + updateComponentParentsList({ + currentComponent: { id: 'id3' }, + layout: { id3: {} }, + }), + ).not.toThrow(); + + expect(() => + updateComponentParentsList({ + currentComponent: { id: 'id3' }, + layout: {}, + }), + ).not.toThrow(); + }); +}); diff --git a/superset-frontend/src/dashboard/util/useFilterFocusHighlightStyles.test.tsx b/superset-frontend/src/dashboard/util/useFilterFocusHighlightStyles.test.tsx new file mode 100644 index 0000000000000..fdc31f78af52e --- /dev/null +++ b/superset-frontend/src/dashboard/util/useFilterFocusHighlightStyles.test.tsx @@ -0,0 +1,248 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { combineReducers, createStore, applyMiddleware, compose } from 'redux'; +import thunk from 'redux-thunk'; +import mockState from 'spec/fixtures/mockState'; +import reducerIndex from 'spec/helpers/reducerIndex'; +import { screen, render } from 'spec/helpers/testing-library'; +import { initialState } from 'src/SqlLab/fixtures'; +import { dashboardFilters } from 'spec/fixtures/mockDashboardFilters'; +import { dashboardWithFilter } from 'spec/fixtures/mockDashboardLayout'; +import { buildActiveFilters } from './activeDashboardFilters'; +import useFilterFocusHighlightStyles from './useFilterFocusHighlightStyles'; + +const TestComponent = ({ chartId }: { chartId: number }) => { + const styles = useFilterFocusHighlightStyles(chartId); + + return <div data-test="test-component" style={styles} />; +}; + +describe('useFilterFocusHighlightStyles', () => { + const createMockStore = (customState: any = {}) => + createStore( + combineReducers(reducerIndex), + { ...mockState, ...(initialState as any), ...customState }, + compose(applyMiddleware(thunk)), + ); + + const renderWrapper = (chartId: number, store = createMockStore()) => + render(<TestComponent chartId={chartId} />, { + useRouter: true, + useDnd: true, + useRedux: true, + store, + }); + + it('should return no style if filter not in scope', async () => { + renderWrapper(10); + + const container = screen.getByTestId('test-component'); + + const styles = getComputedStyle(container); + expect(styles.opacity).toBeFalsy(); + }); + + it('should return unfocused styles if chart is not in scope of focused native filter', async () => { + const store = createMockStore({ + nativeFilters: { + focusedFilterId: 'test-filter', + filters: { + otherId: { + chartsInScope: [], + }, + }, + }, + }); + renderWrapper(10, store); + + const container = screen.getByTestId('test-component'); + + const styles = getComputedStyle(container); + expect(parseFloat(styles.opacity)).toBe(0.3); + }); + + it('should return unfocused styles if chart is not in scope of hovered native filter', async () => { + const store = createMockStore({ + nativeFilters: { + hoveredFilterId: 'test-filter', + filters: { + otherId: { + chartsInScope: [], + }, + }, + }, + }); + renderWrapper(10, store); + + const container = screen.getByTestId('test-component'); + + const styles = getComputedStyle(container); + expect(parseFloat(styles.opacity)).toBe(0.3); + }); + + it('should return focused styles if chart is in scope of focused native filter', async () => { + const chartId = 18; + const store = createMockStore({ + nativeFilters: { + focusedFilterId: 'testFilter', + filters: { + testFilter: { + chartsInScope: [chartId], + }, + }, + }, + }); + renderWrapper(chartId, store); + + const container = screen.getByTestId('test-component'); + + const styles = getComputedStyle(container); + expect(parseFloat(styles.opacity)).toBe(1); + }); + + it('should return focused styles if chart is in scope of hovered native filter', async () => { + const chartId = 18; + const store = createMockStore({ + nativeFilters: { + hoveredFilterId: 'testFilter', + filters: { + testFilter: { + chartsInScope: [chartId], + }, + }, + }, + }); + renderWrapper(chartId, store); + + const container = screen.getByTestId('test-component'); + + const styles = getComputedStyle(container); + expect(parseFloat(styles.opacity)).toBe(1); + }); + + it('should return unfocused styles if focusedFilterField is targeting a different chart', async () => { + const chartId = 18; + const store = createMockStore({ + dashboardState: { + focusedFilterField: { + chartId: 10, + column: 'test', + }, + }, + dashboardFilters: { + 10: { + scopes: {}, + }, + }, + }); + renderWrapper(chartId, store); + + const container = screen.getByTestId('test-component'); + + const styles = getComputedStyle(container); + expect(parseFloat(styles.opacity)).toBe(0.3); + }); + + it('should return focused styles if focusedFilterField chart equals our own', async () => { + const chartId = 18; + const store = createMockStore({ + dashboardState: { + focusedFilterField: { + chartId, + column: 'test', + }, + }, + dashboardFilters: { + [chartId]: { + scopes: { + otherColumn: {}, + }, + }, + }, + }); + renderWrapper(chartId, store); + + const container = screen.getByTestId('test-component'); + + const styles = getComputedStyle(container); + expect(parseFloat(styles.opacity)).toBe(1); + }); + + it('should return unfocused styles if chart is not inside filter box scope', async () => { + buildActiveFilters({ + dashboardFilters, + components: dashboardWithFilter, + }); + + const chartId = 18; + const store = createMockStore({ + dashboardState: { + focusedFilterField: { + chartId, + column: 'test', + }, + }, + dashboardFilters: { + [chartId]: { + scopes: { + column: {}, + }, + }, + }, + }); + renderWrapper(20, store); + + const container = screen.getByTestId('test-component'); + + const styles = getComputedStyle(container); + expect(parseFloat(styles.opacity)).toBe(0.3); + }); + + it('should return focused styles if chart is inside filter box scope', async () => { + buildActiveFilters({ + dashboardFilters, + components: dashboardWithFilter, + }); + + const chartId = 18; + const store = createMockStore({ + dashboardState: { + focusedFilterField: { + chartId, + column: 'test', + }, + }, + dashboardFilters: { + [chartId]: { + scopes: { + column: {}, + }, + }, + }, + }); + renderWrapper(chartId, store); + + const container = screen.getByTestId('test-component'); + + const styles = getComputedStyle(container); + expect(parseFloat(styles.opacity)).toBe(1); + }); +}); diff --git a/superset-frontend/src/dashboard/util/useFilterFocusHighlightStyles.ts b/superset-frontend/src/dashboard/util/useFilterFocusHighlightStyles.ts new file mode 100644 index 0000000000000..8be43490ad3aa --- /dev/null +++ b/superset-frontend/src/dashboard/util/useFilterFocusHighlightStyles.ts @@ -0,0 +1,92 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useTheme } from '@superset-ui/core'; +import { useSelector } from 'react-redux'; + +import { getChartIdsInFilterBoxScope } from 'src/dashboard/util/activeDashboardFilters'; +import { DashboardState, RootState } from 'src/dashboard/types'; + +const selectFocusedFilterScope = ( + dashboardState: DashboardState, + dashboardFilters: any, +) => { + if (!dashboardState.focusedFilterField) return null; + const { chartId, column } = dashboardState.focusedFilterField; + return { + chartId, + scope: dashboardFilters[chartId].scopes[column], + }; +}; + +const useFilterFocusHighlightStyles = (chartId: number) => { + const theme = useTheme(); + + const nativeFilters = useSelector((state: RootState) => state.nativeFilters); + const dashboardState = useSelector( + (state: RootState) => state.dashboardState, + ); + const dashboardFilters = useSelector( + (state: RootState) => state.dashboardFilters, + ); + const focusedFilterScope = selectFocusedFilterScope( + dashboardState, + dashboardFilters, + ); + + const highlightedFilterId = + nativeFilters?.focusedFilterId || nativeFilters?.hoveredFilterId; + if (!(focusedFilterScope || highlightedFilterId)) { + return {}; + } + + // we use local styles here instead of a conditionally-applied class, + // because adding any conditional class to this container + // causes performance issues in Chrome. + + // default to the "de-emphasized" state + const unfocusedChartStyles = { opacity: 0.3, pointerEvents: 'none' }; + const focusedChartStyles = { + borderColor: theme.colors.primary.light2, + opacity: 1, + boxShadow: `0px 0px ${theme.gridUnit * 2}px ${theme.colors.primary.base}`, + pointerEvents: 'auto', + }; + + if (highlightedFilterId) { + if ( + nativeFilters.filters[highlightedFilterId]?.chartsInScope?.includes( + chartId, + ) + ) { + return focusedChartStyles; + } + } else if ( + chartId === focusedFilterScope?.chartId || + getChartIdsInFilterBoxScope({ + filterScope: focusedFilterScope?.scope, + }).includes(chartId) + ) { + return focusedChartStyles; + } + + // inline styles are used here due to a performance issue when adding/changing a class, which causes a reflow + return unfocusedChartStyles; +}; + +export default useFilterFocusHighlightStyles; diff --git a/superset-frontend/src/embedded/api.tsx b/superset-frontend/src/embedded/api.tsx new file mode 100644 index 0000000000000..9d37daf2e01bc --- /dev/null +++ b/superset-frontend/src/embedded/api.tsx @@ -0,0 +1,68 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import getBootstrapData from 'src/utils/getBootstrapData'; +import { store } from '../views/store'; +import { getDashboardPermalink as getDashboardPermalinkUtil } from '../utils/urlUtils'; + +const bootstrapData = getBootstrapData(); + +type Size = { + width: number; + height: number; +}; + +type EmbeddedSupersetApi = { + getScrollSize: () => Size; + getDashboardPermalink: ({ anchor }: { anchor: string }) => Promise<string>; + getActiveTabs: () => string[]; +}; + +const getScrollSize = (): Size => ({ + width: document.body.scrollWidth, + height: document.body.scrollHeight, +}); + +const getDashboardPermalink = async ({ + anchor, +}: { + anchor: string; +}): Promise<string> => { + const state = store?.getState(); + const { dashboardId, dataMask, activeTabs } = { + dashboardId: + state?.dashboardInfo?.id || bootstrapData?.embedded!.dashboard_id, + dataMask: state?.dataMask, + activeTabs: state.dashboardState?.activeTabs, + }; + + return getDashboardPermalinkUtil({ + dashboardId, + dataMask, + activeTabs, + anchor, + }); +}; + +const getActiveTabs = () => store?.getState()?.dashboardState?.activeTabs || []; + +export const embeddedApi: EmbeddedSupersetApi = { + getScrollSize, + getDashboardPermalink, + getActiveTabs, +}; diff --git a/superset-frontend/src/embedded/index.tsx b/superset-frontend/src/embedded/index.tsx index c28d416a18aef..50c026fba8f93 100644 --- a/superset-frontend/src/embedded/index.tsx +++ b/superset-frontend/src/embedded/index.tsx @@ -20,8 +20,8 @@ import React, { lazy, Suspense } from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter as Router, Route } from 'react-router-dom'; import { makeApi, t, logging } from '@superset-ui/core'; -import { Switchboard } from '@superset-ui/switchboard'; -import { bootstrapData } from 'src/preamble'; +import Switchboard from '@superset-ui/switchboard'; +import getBootstrapData from 'src/utils/getBootstrapData'; import setupClient from 'src/setup/setupClient'; import { RootContextProviders } from 'src/views/RootContextProviders'; import { store, USER_LOADED } from 'src/views/store'; @@ -30,8 +30,10 @@ import Loading from 'src/components/Loading'; import { addDangerToast } from 'src/components/MessageToasts/actions'; import ToastContainer from 'src/components/MessageToasts/ToastContainer'; import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; +import { embeddedApi } from './api'; const debugMode = process.env.WEBPACK_MODE === 'development'; +const bootstrapData = getBootstrapData(); function log(...info: unknown[]) { if (debugMode) { @@ -175,7 +177,7 @@ window.addEventListener('message', function embeddedPageInitializer(event) { if (event.data.handshake === 'port transfer' && port) { log('message port received', event); - const switchboard = new Switchboard({ + Switchboard.init({ port, name: 'superset', debug: debugMode, @@ -183,20 +185,24 @@ window.addEventListener('message', function embeddedPageInitializer(event) { let started = false; - switchboard.defineMethod('guestToken', ({ guestToken }) => { - setupGuestClient(guestToken); - if (!started) { - start(); - started = true; - } - }); - - switchboard.defineMethod('getScrollSize', () => ({ - width: document.body.scrollWidth, - height: document.body.scrollHeight, - })); - - switchboard.start(); + Switchboard.defineMethod( + 'guestToken', + ({ guestToken }: { guestToken: string }) => { + setupGuestClient(guestToken); + if (!started) { + start(); + started = true; + } + }, + ); + + Switchboard.defineMethod('getScrollSize', embeddedApi.getScrollSize); + Switchboard.defineMethod( + 'getDashboardPermalink', + embeddedApi.getDashboardPermalink, + ); + Switchboard.defineMethod('getActiveTabs', embeddedApi.getActiveTabs); + Switchboard.start(); } }); diff --git a/superset-frontend/src/explore/App.jsx b/superset-frontend/src/explore/App.jsx deleted file mode 100644 index c440b784e7def..0000000000000 --- a/superset-frontend/src/explore/App.jsx +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import { hot } from 'react-hot-loader/root'; -import { Provider } from 'react-redux'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; -import { ThemeProvider } from '@superset-ui/core'; -import { GlobalStyles } from 'src/GlobalStyles'; -import { DynamicPluginProvider } from 'src/components/DynamicPlugins'; -import ToastContainer from 'src/components/MessageToasts/ToastContainer'; -import setupApp from 'src/setup/setupApp'; -import setupPlugins from 'src/setup/setupPlugins'; -import './main.less'; -import '../assets/stylesheets/reactable-pagination.less'; -import { theme } from 'src/preamble'; -import ExploreViewContainer from './components/ExploreViewContainer'; - -setupApp(); -setupPlugins(); - -const App = ({ store }) => ( - <Provider store={store}> - <DndProvider backend={HTML5Backend}> - <ThemeProvider theme={theme}> - <GlobalStyles /> - <DynamicPluginProvider> - <ExploreViewContainer /> - <ToastContainer /> - </DynamicPluginProvider> - </ThemeProvider> - </DndProvider> - </Provider> -); - -export default hot(App); diff --git a/superset-frontend/src/explore/ExplorePage.tsx b/superset-frontend/src/explore/ExplorePage.tsx new file mode 100644 index 0000000000000..cea43560afb69 --- /dev/null +++ b/superset-frontend/src/explore/ExplorePage.tsx @@ -0,0 +1,162 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useEffect, useRef, useState } from 'react'; +import { useDispatch } from 'react-redux'; +import { useLocation } from 'react-router-dom'; +import { + getSharedLabelColor, + isDefined, + JsonObject, + makeApi, + SharedLabelColorSource, + t, +} from '@superset-ui/core'; +import Loading from 'src/components/Loading'; +import { addDangerToast } from 'src/components/MessageToasts/actions'; +import { getUrlParam } from 'src/utils/urlUtils'; +import { URL_PARAMS } from 'src/constants'; +import { getClientErrorObject } from 'src/utils/getClientErrorObject'; +import getFormDataWithExtraFilters from 'src/dashboard/util/charts/getFormDataWithExtraFilters'; +import { getAppliedFilterValues } from 'src/dashboard/util/activeDashboardFilters'; +import { getParsedExploreURLParams } from './exploreUtils/getParsedExploreURLParams'; +import { hydrateExplore } from './actions/hydrateExplore'; +import ExploreViewContainer from './components/ExploreViewContainer'; +import { ExploreResponsePayload, SaveActionType } from './types'; +import { fallbackExploreInitialData } from './fixtures'; +import { getItem, LocalStorageKeys } from '../utils/localStorageHelpers'; +import { getFormDataWithDashboardContext } from './controlUtils/getFormDataWithDashboardContext'; + +const isValidResult = (rv: JsonObject): boolean => + rv?.result?.form_data && isDefined(rv?.result?.dataset?.id); + +const fetchExploreData = async (exploreUrlParams: URLSearchParams) => { + try { + const rv = await makeApi<{}, ExploreResponsePayload>({ + method: 'GET', + endpoint: 'api/v1/explore/', + })(exploreUrlParams); + if (isValidResult(rv)) { + return rv; + } + let message = t('Failed to load chart data'); + const responseError = rv?.result?.message; + if (responseError) { + message = `${message}:\n${responseError}`; + } + throw new Error(message); + } catch (err) { + // todo: encapsulate the error handler + const clientError = await getClientErrorObject(err); + throw new Error( + clientError.message || + clientError.error || + t('Failed to load chart data.'), + ); + } +}; + +const getDashboardPageContext = (pageId?: string | null) => { + if (!pageId) { + return null; + } + return ( + getItem(LocalStorageKeys.dashboard__explore_context, {})[pageId] || null + ); +}; + +const getDashboardContextFormData = () => { + const dashboardPageId = getUrlParam(URL_PARAMS.dashboardPageId); + const dashboardContext = getDashboardPageContext(dashboardPageId); + if (dashboardContext) { + const sliceId = getUrlParam(URL_PARAMS.sliceId) || 0; + const { + labelColors, + sharedLabelColors, + colorScheme, + chartConfiguration, + nativeFilters, + filterBoxFilters, + dataMask, + dashboardId, + } = dashboardContext; + const dashboardContextWithFilters = getFormDataWithExtraFilters({ + chart: { id: sliceId }, + filters: getAppliedFilterValues(sliceId, filterBoxFilters), + nativeFilters, + chartConfiguration, + colorScheme, + dataMask, + labelColors, + sharedLabelColors, + sliceId, + allSliceIds: [sliceId], + extraControls: {}, + }); + Object.assign(dashboardContextWithFilters, { dashboardId }); + return dashboardContextWithFilters; + } + return null; +}; + +export default function ExplorePage() { + const [isLoaded, setIsLoaded] = useState(false); + const isExploreInitialized = useRef(false); + const dispatch = useDispatch(); + const location = useLocation(); + + useEffect(() => { + const exploreUrlParams = getParsedExploreURLParams(location); + const saveAction = getUrlParam( + URL_PARAMS.saveAction, + ) as SaveActionType | null; + const dashboardContextFormData = getDashboardContextFormData(); + if (!isExploreInitialized.current || !!saveAction) { + fetchExploreData(exploreUrlParams) + .then(({ result }) => { + const formData = dashboardContextFormData + ? getFormDataWithDashboardContext( + result.form_data, + dashboardContextFormData, + ) + : result.form_data; + dispatch( + hydrateExplore({ + ...result, + form_data: formData, + saveAction, + }), + ); + }) + .catch(err => { + dispatch(hydrateExplore(fallbackExploreInitialData)); + dispatch(addDangerToast(err.message)); + }) + .finally(() => { + setIsLoaded(true); + isExploreInitialized.current = true; + }); + } + getSharedLabelColor().source = SharedLabelColorSource.explore; + }, [dispatch, location]); + + if (!isLoaded) { + return <Loading />; + } + return <ExploreViewContainer />; +} diff --git a/superset-frontend/src/explore/actions/datasourcesActions.test.ts b/superset-frontend/src/explore/actions/datasourcesActions.test.ts new file mode 100644 index 0000000000000..6317f1f4a6d15 --- /dev/null +++ b/superset-frontend/src/explore/actions/datasourcesActions.test.ts @@ -0,0 +1,139 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { DatasourceType } from '@superset-ui/core'; +import fetchMock from 'fetch-mock'; +import { + setDatasource, + changeDatasource, + saveDataset, +} from 'src/explore/actions/datasourcesActions'; +import sinon from 'sinon'; +import * as ClientError from 'src/utils/getClientErrorObject'; +import datasourcesReducer from '../reducers/datasourcesReducer'; +import { updateFormDataByDatasource } from './exploreActions'; + +const CURRENT_DATASOURCE = { + id: 1, + uid: '1__table', + type: DatasourceType.Table, + columns: [], + metrics: [], + column_format: {}, + verbose_map: {}, + main_dttm_col: '__timestamp', + // eg. ['["ds", true]', 'ds [asc]'] + datasource_name: 'test datasource', + description: null, +}; + +const NEW_DATASOURCE = { + id: 2, + type: DatasourceType.Table, + columns: [], + metrics: [], + column_format: {}, + verbose_map: {}, + main_dttm_col: '__timestamp', + // eg. ['["ds", true]', 'ds [asc]'] + datasource_name: 'test datasource', + description: null, +}; + +const SAVE_DATASET_POST_ARGS = { + schema: 'foo', + sql: 'select * from bar', + database: { id: 1 }, + templateParams: undefined, + datasourceName: 'new dataset', + columns: [], +}; + +const defaultDatasourcesReducerState = { + [CURRENT_DATASOURCE.uid]: CURRENT_DATASOURCE, +}; + +const saveDatasetEndpoint = `glob:*/superset/sqllab_viz/`; + +test('sets new datasource', () => { + const newState = datasourcesReducer( + defaultDatasourcesReducerState, + setDatasource(NEW_DATASOURCE), + ); + expect(newState).toEqual({ + ...defaultDatasourcesReducerState, + '2__table': NEW_DATASOURCE, + }); +}); + +test('change datasource action', () => { + const dispatch = jest.fn(); + const getState = jest.fn(() => ({ + explore: { + datasource: CURRENT_DATASOURCE, + }, + })); + // ignore getState type check - we dont need explore.datasource field for this test + // @ts-ignore + changeDatasource(NEW_DATASOURCE)(dispatch, getState); + expect(dispatch).toHaveBeenCalledTimes(2); + expect(dispatch).toHaveBeenNthCalledWith(1, setDatasource(NEW_DATASOURCE)); + expect(dispatch).toHaveBeenNthCalledWith( + 2, + updateFormDataByDatasource(CURRENT_DATASOURCE, NEW_DATASOURCE), + ); +}); + +test('saveDataset handles success', async () => { + const datasource = { id: 1 }; + const saveDatasetResponse = { + data: datasource, + }; + fetchMock.reset(); + fetchMock.post(saveDatasetEndpoint, saveDatasetResponse); + const dispatch = sinon.spy(); + const getState = sinon.spy(() => ({ explore: { datasource } })); + const dataset = await saveDataset(SAVE_DATASET_POST_ARGS)(dispatch); + + expect(fetchMock.calls(saveDatasetEndpoint)).toHaveLength(1); + expect(dispatch.callCount).toBe(1); + const thunk = dispatch.getCall(0).args[0]; + thunk(dispatch, getState); + expect(dispatch.getCall(1).args[0].type).toEqual('SET_DATASOURCE'); + + expect(dataset).toEqual(datasource); +}); + +test('updateSlice with add to existing dashboard handles failure', async () => { + fetchMock.reset(); + const sampleError = new Error('sampleError'); + fetchMock.post(saveDatasetEndpoint, { throws: sampleError }); + const dispatch = sinon.spy(); + const errorSpy = jest.spyOn(ClientError, 'getClientErrorObject'); + + let caughtError; + try { + await saveDataset(SAVE_DATASET_POST_ARGS)(dispatch); + } catch (error) { + caughtError = error; + } + + expect(caughtError).toEqual(sampleError); + expect(fetchMock.calls(saveDatasetEndpoint)).toHaveLength(4); + expect(errorSpy).toHaveBeenCalledWith(sampleError); +}); diff --git a/superset-frontend/src/explore/actions/datasourcesActions.ts b/superset-frontend/src/explore/actions/datasourcesActions.ts new file mode 100644 index 0000000000000..9306c180e288b --- /dev/null +++ b/superset-frontend/src/explore/actions/datasourcesActions.ts @@ -0,0 +1,93 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Dispatch, AnyAction } from 'redux'; +import { ThunkDispatch } from 'redux-thunk'; +import { Dataset } from '@superset-ui/chart-controls'; +import { SupersetClient } from '@superset-ui/core'; +import { addDangerToast } from 'src/components/MessageToasts/actions'; +import { getClientErrorObject } from 'src/utils/getClientErrorObject'; +import { updateFormDataByDatasource } from './exploreActions'; +import { ExplorePageState } from '../types'; + +export const SET_DATASOURCE = 'SET_DATASOURCE'; +export interface SetDatasource { + type: string; + datasource: Dataset; +} +export function setDatasource(datasource: Dataset) { + return { type: SET_DATASOURCE, datasource }; +} + +export function saveDataset({ + schema, + sql, + database, + templateParams, + datasourceName, + columns, +}: Omit<SqlLabPostRequest['data'], 'dbId'> & { database: { id: number } }) { + return async function (dispatch: ThunkDispatch<any, undefined, AnyAction>) { + // Create a dataset object + try { + const { + json: { data }, + } = await SupersetClient.post({ + endpoint: '/superset/sqllab_viz/', + postPayload: { + data: { + schema, + sql, + dbId: database?.id, + templateParams, + datasourceName, + metrics: [], + columns, + }, + }, + }); + // Update form_data to point to new dataset + dispatch(changeDatasource(data)); + return data; + } catch (error) { + getClientErrorObject(error).then(e => { + dispatch(addDangerToast(e.error)); + }); + throw error; + } + }; +} + +export function changeDatasource(newDatasource: Dataset) { + return function (dispatch: Dispatch, getState: () => ExplorePageState) { + const { + explore: { datasource: prevDatasource }, + } = getState(); + dispatch(setDatasource(newDatasource)); + dispatch(updateFormDataByDatasource(prevDatasource, newDatasource)); + }; +} + +export const datasourcesActions = { + setDatasource, + changeDatasource, + saveDataset, +}; + +export type AnyDatasourcesAction = SetDatasource; diff --git a/superset-frontend/src/explore/actions/exploreActions.ts b/superset-frontend/src/explore/actions/exploreActions.ts index 2b6c0f549059d..0e13499b14c43 100644 --- a/superset-frontend/src/explore/actions/exploreActions.ts +++ b/superset-frontend/src/explore/actions/exploreActions.ts @@ -18,34 +18,27 @@ */ /* eslint camelcase: 0 */ import { Dataset } from '@superset-ui/chart-controls'; -import { - t, - SupersetClient, - DatasourceType, - QueryFormData, -} from '@superset-ui/core'; +import { t, SupersetClient, QueryFormData } from '@superset-ui/core'; import { Dispatch } from 'redux'; import { addDangerToast, toastActions, } from 'src/components/MessageToasts/actions'; import { Slice } from 'src/types/Chart'; +import { SaveActionType } from 'src/explore/types'; const FAVESTAR_BASE_URL = '/superset/favstar/slice'; -export const SET_DATASOURCE_TYPE = 'SET_DATASOURCE_TYPE'; -export function setDatasourceType(datasourceType: DatasourceType) { - return { type: SET_DATASOURCE_TYPE, datasourceType }; -} - -export const SET_DATASOURCE = 'SET_DATASOURCE'; -export function setDatasource(datasource: Dataset) { - return { type: SET_DATASOURCE, datasource }; -} - -export const SET_DATASOURCES = 'SET_DATASOURCES'; -export function setDatasources(datasources: Dataset[]) { - return { type: SET_DATASOURCES, datasources }; +export const UPDATE_FORM_DATA_BY_DATASOURCE = 'UPDATE_FORM_DATA_BY_DATASOURCE'; +export function updateFormDataByDatasource( + prevDatasource: Dataset, + newDatasource: Dataset, +) { + return { + type: UPDATE_FORM_DATA_BY_DATASOURCE, + prevDatasource, + newDatasource, + }; } export const POST_DATASOURCE_STARTED = 'POST_DATASOURCE_STARTED'; @@ -112,11 +105,21 @@ export function setExploreControls(formData: QueryFormData) { return { type: SET_EXPLORE_CONTROLS, formData }; } +export const SET_FORM_DATA = 'UPDATE_FORM_DATA'; +export function setFormData(formData: QueryFormData) { + return { type: SET_FORM_DATA, formData }; +} + export const UPDATE_CHART_TITLE = 'UPDATE_CHART_TITLE'; export function updateChartTitle(sliceName: string) { return { type: UPDATE_CHART_TITLE, sliceName }; } +export const SET_SAVE_ACTION = 'SET_SAVE_ACTION'; +export function setSaveAction(saveAction: SaveActionType | null) { + return { type: SET_SAVE_ACTION, saveAction }; +} + export const CREATE_NEW_SLICE = 'CREATE_NEW_SLICE'; export function createNewSlice( can_add: boolean, @@ -150,9 +153,6 @@ export function setForceQuery(force: boolean) { export const exploreActions = { ...toastActions, - setDatasourceType, - setDatasource, - setDatasources, fetchDatasourcesStarted, fetchDatasourcesSucceeded, toggleFaveStar, diff --git a/superset-frontend/src/explore/actions/hydrateExplore.test.ts b/superset-frontend/src/explore/actions/hydrateExplore.test.ts new file mode 100644 index 0000000000000..7f363adef6fd6 --- /dev/null +++ b/superset-frontend/src/explore/actions/hydrateExplore.test.ts @@ -0,0 +1,214 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { hydrateExplore, HYDRATE_EXPLORE } from './hydrateExplore'; +import { exploreInitialData } from '../fixtures'; + +test('creates hydrate action from initial data', () => { + const dispatch = jest.fn(); + const getState = jest.fn(() => ({ + user: {}, + charts: {}, + datasources: {}, + common: {}, + explore: {}, + })); + // ignore type check - we dont need exact explore state for this test + // @ts-ignore + hydrateExplore(exploreInitialData)(dispatch, getState); + expect(dispatch).toHaveBeenCalledWith( + expect.objectContaining({ + type: HYDRATE_EXPLORE, + data: { + charts: { + 371: { + id: 371, + chartAlert: null, + chartStatus: null, + chartStackTrace: null, + chartUpdateEndTime: null, + chartUpdateStartTime: 0, + latestQueryFormData: { + cache_timeout: undefined, + datasource: '8__table', + slice_id: 371, + url_params: undefined, + viz_type: 'table', + }, + sliceFormData: { + cache_timeout: undefined, + datasource: '8__table', + slice_id: 371, + url_params: undefined, + viz_type: 'table', + }, + queryController: null, + queriesResponse: null, + triggerQuery: false, + lastRendered: 0, + }, + }, + datasources: { + '8__table': exploreInitialData.dataset, + }, + saveModal: { + dashboards: [], + saveModalAlert: null, + isVisible: false, + }, + explore: { + can_add: false, + can_download: false, + can_overwrite: false, + isDatasourceMetaLoading: false, + isStarred: false, + triggerRender: false, + datasource: exploreInitialData.dataset, + controls: expect.any(Object), + form_data: exploreInitialData.form_data, + slice: exploreInitialData.slice, + standalone: null, + force: null, + saveAction: null, + common: {}, + }, + }, + }), + ); +}); + +test('creates hydrate action with existing state', () => { + const dispatch = jest.fn(); + const getState = jest.fn(() => ({ + user: {}, + charts: {}, + datasources: {}, + common: {}, + explore: { controlsTransferred: ['all_columns'] }, + })); + // ignore type check - we dont need exact explore state for this test + // @ts-ignore + hydrateExplore(exploreInitialData)(dispatch, getState); + expect(dispatch).toHaveBeenCalledWith( + expect.objectContaining({ + type: HYDRATE_EXPLORE, + data: { + charts: { + 371: { + id: 371, + chartAlert: null, + chartStatus: null, + chartStackTrace: null, + chartUpdateEndTime: null, + chartUpdateStartTime: 0, + latestQueryFormData: { + cache_timeout: undefined, + datasource: '8__table', + slice_id: 371, + url_params: undefined, + viz_type: 'table', + }, + sliceFormData: { + cache_timeout: undefined, + datasource: '8__table', + slice_id: 371, + url_params: undefined, + viz_type: 'table', + }, + queryController: null, + queriesResponse: null, + triggerQuery: false, + lastRendered: 0, + }, + }, + datasources: { + '8__table': exploreInitialData.dataset, + }, + saveModal: { + dashboards: [], + saveModalAlert: null, + isVisible: false, + }, + explore: { + can_add: false, + can_download: false, + can_overwrite: false, + isDatasourceMetaLoading: false, + isStarred: false, + triggerRender: false, + datasource: exploreInitialData.dataset, + controls: expect.any(Object), + controlsTransferred: ['all_columns'], + form_data: exploreInitialData.form_data, + slice: exploreInitialData.slice, + standalone: null, + force: null, + saveAction: null, + common: {}, + }, + }, + }), + ); +}); + +test('uses configured default time range if not set', () => { + const dispatch = jest.fn(); + const getState = jest.fn(() => ({ + user: {}, + charts: {}, + datasources: {}, + common: { + conf: { + DEFAULT_TIME_FILTER: 'Last year', + }, + }, + explore: {}, + })); + // @ts-ignore + hydrateExplore({ form_data: {}, slice: {}, dataset: {} })(dispatch, getState); + expect(dispatch).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + explore: expect.objectContaining({ + form_data: expect.objectContaining({ + time_range: 'Last year', + }), + }), + }), + }), + ); + const withTimeRangeSet = { + form_data: { time_range: 'Last day' }, + slice: {}, + dataset: {}, + }; + // @ts-ignore + hydrateExplore(withTimeRangeSet)(dispatch, getState); + expect(dispatch).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + explore: expect.objectContaining({ + form_data: expect.objectContaining({ + time_range: 'Last day', + }), + }), + }), + }), + ); +}); diff --git a/superset-frontend/src/explore/actions/hydrateExplore.ts b/superset-frontend/src/explore/actions/hydrateExplore.ts new file mode 100644 index 0000000000000..f9adc2fe056f7 --- /dev/null +++ b/superset-frontend/src/explore/actions/hydrateExplore.ts @@ -0,0 +1,195 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { ControlStateMapping } from '@superset-ui/chart-controls'; + +import { + ChartState, + ExplorePageInitialData, + ExplorePageState, +} from 'src/explore/types'; +import { getChartKey } from 'src/explore/exploreUtils'; +import { getControlsState } from 'src/explore/store'; +import { Dispatch } from 'redux'; +import { + ensureIsArray, + getCategoricalSchemeRegistry, + getSequentialSchemeRegistry, + NO_TIME_RANGE, +} from '@superset-ui/core'; +import { + getFormDataFromControls, + applyMapStateToPropsToControl, +} from 'src/explore/controlUtils'; +import { getDatasourceUid } from 'src/utils/getDatasourceUid'; +import { getUrlParam } from 'src/utils/urlUtils'; +import { URL_PARAMS } from 'src/constants'; +import { findPermission } from 'src/utils/findPermission'; + +enum ColorSchemeType { + CATEGORICAL = 'CATEGORICAL', + SEQUENTIAL = 'SEQUENTIAL', +} + +export const HYDRATE_EXPLORE = 'HYDRATE_EXPLORE'; +export const hydrateExplore = + ({ + form_data, + slice, + dataset, + metadata, + saveAction = null, + }: ExplorePageInitialData) => + (dispatch: Dispatch, getState: () => ExplorePageState) => { + const { user, datasources, charts, sliceEntities, common, explore } = + getState(); + + const sliceId = getUrlParam(URL_PARAMS.sliceId); + const dashboardId = getUrlParam(URL_PARAMS.dashboardId); + const fallbackSlice = sliceId ? sliceEntities?.slices?.[sliceId] : null; + const initialSlice = slice ?? fallbackSlice; + const initialFormData = form_data ?? initialSlice?.form_data; + if (!initialFormData.viz_type) { + const defaultVizType = common?.conf.DEFAULT_VIZ_TYPE || 'table'; + initialFormData.viz_type = + getUrlParam(URL_PARAMS.vizType) || defaultVizType; + } + if (!initialFormData.time_range) { + initialFormData.time_range = + common?.conf?.DEFAULT_TIME_FILTER || NO_TIME_RANGE; + } + if (dashboardId) { + initialFormData.dashboardId = dashboardId; + } + const initialDatasource = dataset; + + const initialExploreState = { + form_data: initialFormData, + slice: initialSlice, + datasource: initialDatasource, + }; + const initialControls = getControlsState( + initialExploreState, + initialFormData, + ) as ControlStateMapping; + const colorSchemeKey = initialControls.color_scheme && 'color_scheme'; + const linearColorSchemeKey = + initialControls.linear_color_scheme && 'linear_color_scheme'; + // if the selected color scheme does not exist anymore + // fallbacks and selects the available default one + const verifyColorScheme = (type: ColorSchemeType) => { + const schemes = + type === 'CATEGORICAL' + ? getCategoricalSchemeRegistry() + : getSequentialSchemeRegistry(); + const key = + type === 'CATEGORICAL' ? colorSchemeKey : linearColorSchemeKey; + const registryDefaultScheme = schemes.defaultKey; + const defaultScheme = + type === 'CATEGORICAL' ? 'supersetColors' : 'superset_seq_1'; + const currentScheme = initialFormData[key]; + const colorSchemeExists = !!schemes.get(currentScheme, true); + + if (currentScheme && !colorSchemeExists) { + initialControls[key].value = registryDefaultScheme || defaultScheme; + } + }; + + if (colorSchemeKey) verifyColorScheme(ColorSchemeType.CATEGORICAL); + if (linearColorSchemeKey) verifyColorScheme(ColorSchemeType.SEQUENTIAL); + + const exploreState = { + // note this will add `form_data` to state, + // which will be manipulable by future reducers. + can_add: findPermission('can_write', 'Chart', user?.roles), + can_download: findPermission('can_csv', 'Superset', user?.roles), + can_overwrite: ensureIsArray(slice?.owners).includes( + user?.userId as number, + ), + isDatasourceMetaLoading: false, + isStarred: false, + triggerRender: false, + // duplicate datasource in exploreState - it's needed by getControlsState + datasource: initialDatasource, + // Initial control state will skip `control.mapStateToProps` + // because `bootstrapData.controls` is undefined. + controls: initialControls, + form_data: initialFormData, + slice: initialSlice, + controlsTransferred: explore.controlsTransferred, + standalone: getUrlParam(URL_PARAMS.standalone), + force: getUrlParam(URL_PARAMS.force), + metadata, + saveAction, + common, + }; + + // apply initial mapStateToProps for all controls, must execute AFTER + // bootstrapState has initialized `controls`. Order of execution is not + // guaranteed, so controls shouldn't rely on each other's mapped state. + Object.entries(exploreState.controls).forEach(([key, controlState]) => { + exploreState.controls[key] = applyMapStateToPropsToControl( + controlState, + exploreState, + ); + }); + const sliceFormData = initialSlice + ? getFormDataFromControls(initialControls) + : null; + + const chartKey: number = getChartKey(initialExploreState); + const chart: ChartState = { + id: chartKey, + chartAlert: null, + chartStatus: null, + chartStackTrace: null, + chartUpdateEndTime: null, + chartUpdateStartTime: 0, + latestQueryFormData: getFormDataFromControls(exploreState.controls), + sliceFormData, + queryController: null, + queriesResponse: null, + triggerQuery: false, + lastRendered: 0, + }; + + return dispatch({ + type: HYDRATE_EXPLORE, + data: { + charts: { + ...charts, + [chartKey]: chart, + }, + datasources: { + ...datasources, + [getDatasourceUid(initialDatasource)]: initialDatasource, + }, + saveModal: { + dashboards: [], + saveModalAlert: null, + isVisible: false, + }, + explore: exploreState, + }, + }); + }; + +export type HydrateExplore = { + type: typeof HYDRATE_EXPLORE; + data: ExplorePageState; +}; diff --git a/superset-frontend/src/explore/actions/saveModalActions.js b/superset-frontend/src/explore/actions/saveModalActions.js index 6e87fe52b5f17..14bbe09995458 100644 --- a/superset-frontend/src/explore/actions/saveModalActions.js +++ b/superset-frontend/src/explore/actions/saveModalActions.js @@ -16,8 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import { SupersetClient } from '@superset-ui/core'; -import { buildV1ChartDataPayload, getExploreUrl } from '../exploreUtils'; +import rison from 'rison'; +import { SupersetClient, t } from '@superset-ui/core'; +import { addSuccessToast } from 'src/components/MessageToasts/actions'; +import { buildV1ChartDataPayload } from '../exploreUtils'; + +const ADHOC_FILTER_REGEX = /^adhoc_filters/; export const FETCH_DASHBOARDS_SUCCEEDED = 'FETCH_DASHBOARDS_SUCCEEDED'; export function fetchDashboardsSucceeded(choices) { @@ -29,6 +33,12 @@ export function fetchDashboardsFailed(userId) { return { type: FETCH_DASHBOARDS_FAILED, userId }; } +export const SET_SAVE_CHART_MODAL_VISIBILITY = + 'SET_SAVE_CHART_MODAL_VISIBILITY'; +export function setSaveChartModalVisibility(isVisible) { + return { type: SET_SAVE_CHART_MODAL_VISIBILITY, isVisible }; +} + export function fetchDashboards(userId) { return function fetchDashboardsThunk(dispatch) { return SupersetClient.get({ @@ -39,6 +49,12 @@ export function fetchDashboards(userId) { value: id, label: (json.result[index] || {}).dashboard_title, })); + choices.sort((a, b) => + a.label.localeCompare(b.label, { + sensitivity: 'base', + numeric: true, + }), + ); return dispatch(fetchDashboardsSucceeded(choices)); }) @@ -60,33 +76,173 @@ export function removeSaveModalAlert() { return { type: REMOVE_SAVE_MODAL_ALERT }; } -export function saveSlice(formData, requestParams) { - return dispatch => { - const url = getExploreUrl({ - formData, - endpointType: 'base', - force: false, - curUrl: null, - requestParams, +export const getSlicePayload = ( + sliceName, + formDataWithNativeFilters, + dashboards, + owners, +) => { + const adhocFilters = Object.entries(formDataWithNativeFilters).reduce( + (acc, [key, value]) => + ADHOC_FILTER_REGEX.test(key) + ? { ...acc, [key]: value?.filter(f => !f.isExtra) } + : acc, + {}, + ); + const formData = { + ...formDataWithNativeFilters, + ...adhocFilters, + dashboards, + }; + + const [datasourceId, datasourceType] = formData.datasource.split('__'); + const payload = { + params: JSON.stringify(formData), + slice_name: sliceName, + viz_type: formData.viz_type, + datasource_id: parseInt(datasourceId, 10), + datasource_type: datasourceType, + dashboards, + owners, + query_context: JSON.stringify( + buildV1ChartDataPayload({ + formData, + force: false, + resultFormat: 'json', + resultType: 'full', + setDataMask: null, + ownState: null, + }), + ), + }; + return payload; +}; + +const addToasts = (isNewSlice, sliceName, addedToDashboard) => { + const toasts = []; + if (isNewSlice) { + toasts.push(addSuccessToast(t('Chart [%s] has been saved', sliceName))); + } else { + toasts.push( + addSuccessToast(t('Chart [%s] has been overwritten', sliceName)), + ); + } + + if (addedToDashboard) { + if (addedToDashboard.new) { + toasts.push( + addSuccessToast( + t( + 'Dashboard [%s] just got created and chart [%s] was added to it', + addedToDashboard.title, + sliceName, + ), + ), + ); + } else { + toasts.push( + addSuccessToast( + t( + 'Chart [%s] was added to dashboard [%s]', + sliceName, + addedToDashboard.title, + ), + ), + ); + } + } + + return toasts; +}; + +// Update existing slice +export const updateSlice = + ({ slice_id: sliceId, owners }, sliceName, dashboards, addedToDashboard) => + async (dispatch, getState) => { + const { + explore: { + form_data: { url_params: _, ...formData }, + }, + } = getState(); + try { + const response = await SupersetClient.put({ + endpoint: `/api/v1/chart/${sliceId}`, + jsonPayload: getSlicePayload(sliceName, formData, dashboards, owners), + }); + + dispatch(saveSliceSuccess()); + addToasts(false, sliceName, addedToDashboard).map(dispatch); + return response.json; + } catch (error) { + dispatch(saveSliceFailed()); + throw error; + } + }; + +// Create new slice +export const createSlice = + (sliceName, dashboards, addedToDashboard) => async (dispatch, getState) => { + const { + explore: { + form_data: { url_params: _, ...formData }, + }, + } = getState(); + try { + const response = await SupersetClient.post({ + endpoint: `/api/v1/chart/`, + jsonPayload: getSlicePayload(sliceName, formData, dashboards), + }); + + dispatch(saveSliceSuccess()); + addToasts(true, sliceName, addedToDashboard).map(dispatch); + return response.json; + } catch (error) { + dispatch(saveSliceFailed()); + throw error; + } + }; + +// Create new dashboard +export const createDashboard = dashboardName => async dispatch => { + try { + const response = await SupersetClient.post({ + endpoint: `/api/v1/dashboard/`, + jsonPayload: { dashboard_title: dashboardName }, }); - // Save the query context so we can re-generate the data from Python - // for alerts and reports - const queryContext = buildV1ChartDataPayload({ - formData, - force: false, - resultFormat: 'json', - resultType: 'full', + return response.json; + } catch (error) { + dispatch(saveSliceFailed()); + throw error; + } +}; + +// Get existing dashboard from ID +export const getDashboard = dashboardId => async dispatch => { + try { + const response = await SupersetClient.get({ + endpoint: `/api/v1/dashboard/${dashboardId}`, }); - return SupersetClient.post({ - url, - postPayload: { form_data: formData, query_context: queryContext }, - }) - .then(response => { - dispatch(saveSliceSuccess(response.json)); - return response.json; - }) - .catch(() => dispatch(saveSliceFailed())); - }; -} + return response.json; + } catch (error) { + dispatch(saveSliceFailed()); + throw error; + } +}; + +// Get dashboards the slice is added to +export const getSliceDashboards = slice => async dispatch => { + try { + const response = await SupersetClient.get({ + endpoint: `/api/v1/chart/${slice.slice_id}?q=${rison.encode({ + columns: ['dashboards.id'], + })}`, + }); + + return response.json.result.dashboards.map(({ id }) => id); + } catch (error) { + dispatch(saveSliceFailed()); + throw error; + } +}; diff --git a/superset-frontend/src/explore/actions/saveModalActions.test.js b/superset-frontend/src/explore/actions/saveModalActions.test.js new file mode 100644 index 0000000000000..8e4a4e5abd32f --- /dev/null +++ b/superset-frontend/src/explore/actions/saveModalActions.test.js @@ -0,0 +1,341 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import sinon from 'sinon'; +import fetchMock from 'fetch-mock'; +import { ADD_TOAST } from 'src/components/MessageToasts/actions'; +import { + createDashboard, + createSlice, + fetchDashboards, + FETCH_DASHBOARDS_FAILED, + FETCH_DASHBOARDS_SUCCEEDED, + getDashboard, + getSliceDashboards, + SAVE_SLICE_FAILED, + SAVE_SLICE_SUCCESS, + updateSlice, +} from './saveModalActions'; + +/** + * Tests fetchDashboards action + */ + +const userId = 1; +const fetchDashboardsEndpoint = `glob:*/dashboardasync/api/read?_flt_0_owners=${1}`; +const mockDashboardData = { + pks: ['id'], + result: [{ id: 'id', dashboard_title: 'dashboard title' }], +}; + +test('fetchDashboards handles success', async () => { + fetchMock.reset(); + fetchMock.get(fetchDashboardsEndpoint, mockDashboardData); + const dispatch = sinon.spy(); + await fetchDashboards(userId)(dispatch); + expect(fetchMock.calls(fetchDashboardsEndpoint)).toHaveLength(1); + expect(dispatch.callCount).toBe(1); + expect(dispatch.getCall(0).args[0].type).toBe(FETCH_DASHBOARDS_SUCCEEDED); +}); + +test('fetchDashboards handles failure', async () => { + fetchMock.reset(); + fetchMock.get(fetchDashboardsEndpoint, { throws: 'error' }); + const dispatch = sinon.spy(); + await fetchDashboards(userId)(dispatch); + expect(fetchMock.calls(fetchDashboardsEndpoint)).toHaveLength(4); // 3 retries + expect(dispatch.callCount).toBe(1); + expect(dispatch.getCall(0).args[0].type).toBe(FETCH_DASHBOARDS_FAILED); +}); + +const sliceId = 10; +const sliceName = 'New chart'; +const vizType = 'sample_viz_type'; +const datasourceId = 11; +const datasourceType = 'sample_datasource_type'; +const dashboards = [12, 13]; +const queryContext = { sampleKey: 'sampleValue' }; +const formData = { + viz_type: vizType, + datasource: `${datasourceId}__${datasourceType}`, + dashboards, +}; +const mockExploreState = { explore: { form_data: formData } }; + +const sliceResponsePayload = { + id: 10, +}; + +const sampleError = new Error('sampleError'); + +jest.mock('../exploreUtils', () => ({ + buildV1ChartDataPayload: jest.fn(() => queryContext), +})); + +/** + * Tests updateSlice action + */ + +const updateSliceEndpoint = `glob:*/api/v1/chart/${sliceId}`; +test('updateSlice handles success', async () => { + fetchMock.reset(); + fetchMock.put(updateSliceEndpoint, sliceResponsePayload); + const dispatch = sinon.spy(); + const getState = sinon.spy(() => mockExploreState); + const slice = await updateSlice( + { slice_id: sliceId }, + sliceName, + [], + )(dispatch, getState); + + expect(fetchMock.calls(updateSliceEndpoint)).toHaveLength(1); + expect(dispatch.callCount).toBe(2); + expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_SUCCESS); + expect(dispatch.getCall(1).args[0].type).toBe(ADD_TOAST); + expect(dispatch.getCall(1).args[0].payload.toastType).toBe('SUCCESS_TOAST'); + expect(dispatch.getCall(1).args[0].payload.text).toBe( + 'Chart [New chart] has been overwritten', + ); + + expect(slice).toEqual(sliceResponsePayload); +}); + +test('updateSlice handles failure', async () => { + fetchMock.reset(); + fetchMock.put(updateSliceEndpoint, { throws: sampleError }); + const dispatch = sinon.spy(); + const getState = sinon.spy(() => mockExploreState); + let caughtError; + try { + await updateSlice({ slice_id: sliceId }, sliceName, [])(dispatch, getState); + } catch (error) { + caughtError = error; + } + + expect(caughtError).toEqual(sampleError); + expect(fetchMock.calls(updateSliceEndpoint)).toHaveLength(4); + expect(dispatch.callCount).toBe(1); + expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED); +}); + +/** + * Tests createSlice action + */ + +const createSliceEndpoint = `glob:*/api/v1/chart/`; +test('createSlice handles success', async () => { + fetchMock.reset(); + fetchMock.post(createSliceEndpoint, sliceResponsePayload); + const dispatch = sinon.spy(); + const getState = sinon.spy(() => mockExploreState); + const slice = await createSlice(sliceName, [])(dispatch, getState); + expect(fetchMock.calls(createSliceEndpoint)).toHaveLength(1); + expect(dispatch.callCount).toBe(2); + expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_SUCCESS); + expect(dispatch.getCall(1).args[0].type).toBe(ADD_TOAST); + expect(dispatch.getCall(1).args[0].payload.toastType).toBe('SUCCESS_TOAST'); + expect(dispatch.getCall(1).args[0].payload.text).toBe( + 'Chart [New chart] has been saved', + ); + + expect(slice).toEqual(sliceResponsePayload); +}); + +test('createSlice handles failure', async () => { + fetchMock.reset(); + fetchMock.post(createSliceEndpoint, { throws: sampleError }); + const dispatch = sinon.spy(); + const getState = sinon.spy(() => mockExploreState); + let caughtError; + try { + await createSlice(sliceName, [])(dispatch, getState); + } catch (error) { + caughtError = error; + } + + expect(caughtError).toEqual(sampleError); + expect(fetchMock.calls(createSliceEndpoint)).toHaveLength(4); + expect(dispatch.callCount).toBe(1); + expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED); +}); + +const dashboardId = 14; +const dashboardName = 'New dashboard'; +const dashboardResponsePayload = { + id: 14, +}; + +/** + * Tests createDashboard action + */ + +const createDashboardEndpoint = `glob:*/api/v1/dashboard/`; +test('createDashboard handles success', async () => { + fetchMock.reset(); + fetchMock.post(createDashboardEndpoint, dashboardResponsePayload); + const dispatch = sinon.spy(); + const dashboard = await createDashboard(dashboardName)(dispatch); + expect(fetchMock.calls(createDashboardEndpoint)).toHaveLength(1); + expect(dispatch.callCount).toBe(0); + expect(dashboard).toEqual(dashboardResponsePayload); +}); + +test('createDashboard handles failure', async () => { + fetchMock.reset(); + fetchMock.post(createDashboardEndpoint, { throws: sampleError }); + const dispatch = sinon.spy(); + let caughtError; + try { + await createDashboard(dashboardName)(dispatch); + } catch (error) { + caughtError = error; + } + + expect(caughtError).toEqual(sampleError); + expect(fetchMock.calls(createDashboardEndpoint)).toHaveLength(4); + expect(dispatch.callCount).toBe(1); + expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED); +}); + +/** + * Tests getDashboard action + */ + +const getDashboardEndpoint = `glob:*/api/v1/dashboard/${dashboardId}`; +test('getDashboard handles success', async () => { + fetchMock.reset(); + fetchMock.get(getDashboardEndpoint, dashboardResponsePayload); + const dispatch = sinon.spy(); + const dashboard = await getDashboard(dashboardId)(dispatch); + expect(fetchMock.calls(getDashboardEndpoint)).toHaveLength(1); + expect(dispatch.callCount).toBe(0); + expect(dashboard).toEqual(dashboardResponsePayload); +}); + +test('getDashboard handles failure', async () => { + fetchMock.reset(); + fetchMock.get(getDashboardEndpoint, { throws: sampleError }); + const dispatch = sinon.spy(); + let caughtError; + try { + await getDashboard(dashboardId)(dispatch); + } catch (error) { + caughtError = error; + } + + expect(caughtError).toEqual(sampleError); + expect(fetchMock.calls(getDashboardEndpoint)).toHaveLength(4); + expect(dispatch.callCount).toBe(1); + expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED); +}); + +test('updateSlice with add to new dashboard handles success', async () => { + fetchMock.reset(); + fetchMock.put(updateSliceEndpoint, sliceResponsePayload); + const dispatch = sinon.spy(); + const getState = sinon.spy(() => mockExploreState); + const slice = await updateSlice({ slice_id: sliceId }, sliceName, [], { + new: true, + title: dashboardName, + })(dispatch, getState); + + expect(fetchMock.calls(updateSliceEndpoint)).toHaveLength(1); + expect(dispatch.callCount).toBe(3); + expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_SUCCESS); + expect(dispatch.getCall(1).args[0].type).toBe(ADD_TOAST); + expect(dispatch.getCall(1).args[0].payload.toastType).toBe('SUCCESS_TOAST'); + expect(dispatch.getCall(1).args[0].payload.text).toBe( + 'Chart [New chart] has been overwritten', + ); + expect(dispatch.getCall(2).args[0].type).toBe(ADD_TOAST); + expect(dispatch.getCall(2).args[0].payload.toastType).toBe('SUCCESS_TOAST'); + expect(dispatch.getCall(2).args[0].payload.text).toBe( + 'Dashboard [New dashboard] just got created and chart [New chart] was added to it', + ); + + expect(slice).toEqual(sliceResponsePayload); +}); + +test('updateSlice with add to existing dashboard handles success', async () => { + fetchMock.reset(); + fetchMock.put(updateSliceEndpoint, sliceResponsePayload); + const dispatch = sinon.spy(); + const getState = sinon.spy(() => mockExploreState); + const slice = await updateSlice({ slice_id: sliceId }, sliceName, [], { + new: false, + title: dashboardName, + })(dispatch, getState); + + expect(fetchMock.calls(updateSliceEndpoint)).toHaveLength(1); + expect(dispatch.callCount).toBe(3); + expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_SUCCESS); + expect(dispatch.getCall(1).args[0].type).toBe(ADD_TOAST); + expect(dispatch.getCall(1).args[0].payload.toastType).toBe('SUCCESS_TOAST'); + expect(dispatch.getCall(1).args[0].payload.text).toBe( + 'Chart [New chart] has been overwritten', + ); + expect(dispatch.getCall(2).args[0].type).toBe(ADD_TOAST); + expect(dispatch.getCall(2).args[0].payload.toastType).toBe('SUCCESS_TOAST'); + expect(dispatch.getCall(2).args[0].payload.text).toBe( + 'Chart [New chart] was added to dashboard [New dashboard]', + ); + + expect(slice).toEqual(sliceResponsePayload); +}); + +const slice = { slice_id: 10 }; +const dashboardSlicesResponsePayload = { + result: { + dashboards: [{ id: 21 }, { id: 22 }, { id: 23 }], + }, +}; + +const getDashboardSlicesReturnValue = [21, 22, 23]; + +/** + * Tests getSliceDashboards action + */ + +const getSliceDashboardsEndpoint = `glob:*/api/v1/chart/${sliceId}?q=(columns:!(dashboards.id))`; +test('getSliceDashboards with slice handles success', async () => { + fetchMock.reset(); + fetchMock.get(getSliceDashboardsEndpoint, dashboardSlicesResponsePayload); + const dispatch = sinon.spy(); + const sliceDashboards = await getSliceDashboards(slice)(dispatch); + expect(fetchMock.calls(getSliceDashboardsEndpoint)).toHaveLength(1); + expect(dispatch.callCount).toBe(0); + expect(sliceDashboards).toEqual(getDashboardSlicesReturnValue); +}); + +test('getSliceDashboards with slice handles failure', async () => { + fetchMock.reset(); + fetchMock.get(getSliceDashboardsEndpoint, { throws: sampleError }); + const dispatch = sinon.spy(); + let caughtError; + try { + await getSliceDashboards(slice)(dispatch); + } catch (error) { + caughtError = error; + } + + expect(caughtError).toEqual(sampleError); + expect(fetchMock.calls(getSliceDashboardsEndpoint)).toHaveLength(4); + expect(dispatch.callCount).toBe(1); + expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED); +}); diff --git a/superset-frontend/src/explore/components/Control.test.tsx b/superset-frontend/src/explore/components/Control.test.tsx index 3921d43746636..9b8b549858d45 100644 --- a/superset-frontend/src/explore/components/Control.test.tsx +++ b/superset-frontend/src/explore/components/Control.test.tsx @@ -61,7 +61,7 @@ describe('Control', () => { it('render null if type is not valid', () => { render( setup({ - type: 'UnkownControl', + type: 'UnknownControl', }), ); expect(screen.queryByRole('checkbox')).not.toBeInTheDocument(); diff --git a/superset-frontend/src/explore/components/ControlHeader.tsx b/superset-frontend/src/explore/components/ControlHeader.tsx index 69d34e13c857c..2f374d7653ac0 100644 --- a/superset-frontend/src/explore/components/ControlHeader.tsx +++ b/superset-frontend/src/explore/components/ControlHeader.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { FC, ReactNode } from 'react'; +import React, { FC, ReactNode, useMemo, useRef } from 'react'; import { t, css, useTheme, SupersetTheme } from '@superset-ui/core'; import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; import { Tooltip } from 'src/components/Tooltip'; @@ -44,6 +44,16 @@ export type ControlHeaderProps = { selectAllOnClick?: () => void; }; +const iconStyles = css` + &.anticon { + font-size: unset; + .anticon { + line-height: unset; + vertical-align: unset; + } + } +`; + const ControlHeader: FC<ControlHeaderProps> = ({ name, label, @@ -63,6 +73,22 @@ const ControlHeader: FC<ControlHeaderProps> = ({ selectAllOnClick, }) => { const { gridUnit, colors } = useTheme(); + const hasHadNoErrors = useRef(false); + const labelColor = useMemo(() => { + if (!validationErrors.length) { + hasHadNoErrors.current = true; + } + + if (hasHadNoErrors.current) { + if (validationErrors.length) { + return colors.error.base; + } + + return 'unset'; + } + + return colors.alert.base; + }, [colors.error.base, colors.alert.base, validationErrors.length]); if (!label) { return null; @@ -86,12 +112,16 @@ const ControlHeader: FC<ControlHeaderProps> = ({ > {description && ( <span> - <InfoTooltipWithTrigger - label={t('description')} - tooltip={description} + <Tooltip + id="description-tooltip" + title={description} placement="top" - onClick={tooltipOnClick} - />{' '} + > + <Icons.InfoCircleOutlined + css={iconStyles} + onClick={tooltipOnClick} + /> + </Tooltip>{' '} </span> )} {renderTrigger && ( @@ -138,8 +168,6 @@ const ControlHeader: FC<ControlHeaderProps> = ({ </span> ); - const labelClass = validationErrors?.length > 0 ? 'text-danger' : ''; - return ( <div className="ControlHeader" @@ -162,7 +190,6 @@ const ControlHeader: FC<ControlHeaderProps> = ({ role="button" tabIndex={0} onClick={onClick} - className={labelClass} style={{ cursor: onClick ? 'pointer' : '' }} > {label} @@ -182,13 +209,18 @@ const ControlHeader: FC<ControlHeaderProps> = ({ </span> )} {validationErrors?.length > 0 && ( - <span> + <span data-test="error-tooltip"> <Tooltip id="error-tooltip" placement="top" title={validationErrors?.join(' ')} > - <Icons.ErrorSolid iconColor={colors.error.base} iconSize="s" /> + <Icons.ExclamationCircleOutlined + css={css` + ${iconStyles} + color: ${labelColor}; + `} + /> </Tooltip>{' '} </span> )} diff --git a/superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx b/superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx index 6af860470cce4..2be8745fa1936 100644 --- a/superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx +++ b/superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx @@ -97,10 +97,12 @@ describe('ControlPanelsContainer', () => { } as ControlPanelsContainerProps; } - it('renders ControlPanelSections', () => { - render(<ControlPanelsContainer {...getDefaultProps()} />); + test('renders ControlPanelSections', async () => { + render(<ControlPanelsContainer {...getDefaultProps()} />, { + useRedux: true, + }); expect( - screen.getAllByTestId('collapsible-control-panel-header'), + await screen.findAllByTestId('collapsible-control-panel-header'), ).toHaveLength(4); }); }); diff --git a/superset-frontend/src/explore/components/ControlPanelsContainer.tsx b/superset-frontend/src/explore/components/ControlPanelsContainer.tsx index bb2be2b182b61..60aac1948bf4e 100644 --- a/superset-frontend/src/explore/components/ControlPanelsContainer.tsx +++ b/superset-frontend/src/explore/components/ControlPanelsContainer.tsx @@ -35,6 +35,10 @@ import { DatasourceType, css, SupersetTheme, + useTheme, + isDefined, + JsonValue, + NO_TIME_RANGE, } from '@superset-ui/core'; import { ControlPanelSectionConfig, @@ -42,27 +46,32 @@ import { CustomControlItem, Dataset, ExpandedControlItem, - InfoTooltipWithTrigger, + isTemporalColumn, sections, } from '@superset-ui/chart-controls'; +import { useSelector } from 'react-redux'; +import { rgba } from 'emotion-rgba'; +import { kebabCase } from 'lodash'; import Collapse from 'src/components/Collapse'; import Tabs from 'src/components/Tabs'; import { PluginContext } from 'src/components/DynamicPlugins'; import Loading from 'src/components/Loading'; +import Modal from 'src/components/Modal'; import { usePrevious } from 'src/hooks/usePrevious'; import { getSectionsToRender } from 'src/explore/controlUtils'; import { ExploreActions } from 'src/explore/actions/exploreActions'; -import { ExplorePageState } from 'src/explore/reducers/getInitialState'; -import { ChartState } from 'src/explore/types'; +import { ChartState, ExplorePageState } from 'src/explore/types'; import { Tooltip } from 'src/components/Tooltip'; - -import { rgba } from 'emotion-rgba'; +import Icons from 'src/components/Icons'; import ControlRow from './ControlRow'; import Control from './Control'; import { ExploreAlert } from './ExploreAlert'; import { RunQueryButton } from './RunQueryButton'; +import { Operators } from '../constants'; + +const { confirm } = Modal; export type ControlPanelsContainerProps = { exploreState: ExplorePageState['explore']; @@ -86,6 +95,16 @@ export type ExpandedControlPanelSectionConfig = Omit< controlSetRows: ExpandedControlItem[][]; }; +const iconStyles = css` + &.anticon { + font-size: unset; + .anticon { + line-height: unset; + vertical-align: unset; + } + } +`; + const actionButtonsContainerStyles = (theme: SupersetTheme) => css` display: flex; position: sticky; @@ -175,9 +194,7 @@ const isTimeSection = (section: ControlPanelSectionConfig): boolean => sections.legacyTimeseriesTime.label === section.label); const hasTimeColumn = (datasource: Dataset): boolean => - datasource?.columns?.some(c => c.is_dttm) || - datasource.type === DatasourceType.Druid; - + datasource?.columns?.some(c => c.is_dttm); const sectionsToExpand = ( sections: ControlPanelSectionConfig[], datasource: Dataset, @@ -185,7 +202,8 @@ const sectionsToExpand = ( // avoid expanding time section if datasource doesn't include time column sections.reduce( (acc, section) => - section.expanded && (!isTimeSection(section) || hasTimeColumn(datasource)) + (section.expanded || !section.label) && + (!isTimeSection(section) || hasTimeColumn(datasource)) ? [...acc, String(section.label)] : acc, [] as string[], @@ -237,19 +255,137 @@ function getState( }; } +function useResetOnChangeRef(initialValue: () => any, resetOnChangeValue: any) { + const value = useRef(initialValue()); + const prevResetOnChangeValue = useRef(resetOnChangeValue); + if (prevResetOnChangeValue.current !== resetOnChangeValue) { + value.current = initialValue(); + prevResetOnChangeValue.current = resetOnChangeValue; + } + + return value; +} + export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { + const { colors } = useTheme(); const pluginContext = useContext(PluginContext); const prevState = usePrevious(props.exploreState); const prevDatasource = usePrevious(props.exploreState.datasource); + const prevChartStatus = usePrevious(props.chart.chartStatus); const [showDatasourceAlert, setShowDatasourceAlert] = useState(false); const containerRef = useRef<HTMLDivElement>(null); + const controlsTransferred = useSelector< + ExplorePageState, + string[] | undefined + >(state => state.explore.controlsTransferred); + + const defaultTimeFilter = useSelector<ExplorePageState>( + state => state.common?.conf?.DEFAULT_TIME_FILTER, + ); + + const { form_data, actions } = props; + const { setControlValue } = actions; + const { x_axis, adhoc_filters } = form_data; + + const previousXAxis = usePrevious(x_axis); + + useEffect(() => { + if ( + x_axis && + x_axis !== previousXAxis && + isTemporalColumn(x_axis, props.exploreState.datasource) + ) { + const noFilter = + !adhoc_filters || + !adhoc_filters.find( + filter => + filter.expressionType === 'SIMPLE' && + filter.operator === Operators.TEMPORAL_RANGE && + filter.subject === x_axis, + ); + if (noFilter) { + confirm({ + title: t('The X-axis is not on the filters list'), + content: + t(`The X-axis is not on the filters list which will prevent it from being used in + time range filters in dashboards. Would you like to add it to the filters list?`), + onOk: () => { + setControlValue('adhoc_filters', [ + ...(adhoc_filters || []), + { + clause: 'WHERE', + subject: x_axis, + operator: Operators.TEMPORAL_RANGE, + comparator: defaultTimeFilter || NO_TIME_RANGE, + expressionType: 'SIMPLE', + }, + ]); + }, + }); + } + } + }, [ + x_axis, + adhoc_filters, + setControlValue, + defaultTimeFilter, + previousXAxis, + props.exploreState.datasource, + ]); + + useEffect(() => { + let shouldUpdateControls = false; + const removeDatasourceWarningFromControl = ( + value: JsonValue | undefined, + ) => { + if ( + typeof value === 'object' && + isDefined(value) && + 'datasourceWarning' in value && + value.datasourceWarning === true + ) { + shouldUpdateControls = true; + return { ...value, datasourceWarning: false }; + } + return value; + }; + if ( + props.chart.chartStatus === 'success' && + prevChartStatus !== 'success' + ) { + controlsTransferred?.forEach(controlName => { + shouldUpdateControls = false; + if (!isDefined(props.controls[controlName])) { + return; + } + const alteredControls = Array.isArray(props.controls[controlName].value) + ? ensureIsArray(props.controls[controlName].value)?.map( + removeDatasourceWarningFromControl, + ) + : removeDatasourceWarningFromControl( + props.controls[controlName].value, + ); + if (shouldUpdateControls) { + props.actions.setControlValue(controlName, alteredControls); + } + }); + } + }, [ + controlsTransferred, + prevChartStatus, + props.actions, + props.chart.chartStatus, + props.controls, + ]); + useEffect(() => { if ( prevDatasource && + prevDatasource.type !== DatasourceType.Query && (props.exploreState.datasource?.id !== prevDatasource.id || props.exploreState.datasource?.type !== prevDatasource.type) ) { @@ -270,15 +406,11 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { } = useMemo( () => getState( - props.form_data.viz_type, + form_data.viz_type, props.exploreState.datasource, props.datasource_type, ), - [ - props.exploreState.datasource, - props.form_data.viz_type, - props.datasource_type, - ], + [props.exploreState.datasource, form_data.viz_type, props.datasource_type], ); const resetTransferredControls = useCallback(() => { @@ -332,7 +464,12 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { undefined), name, }; - const { validationErrors, ...restProps } = controlData as ControlState & { + const { + validationErrors, + label: baseLabel, + description: baseDescription, + ...restProps + } = controlData as ControlState & { validationErrors?: any[]; }; @@ -340,10 +477,41 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { ? visibility.call(config, props, controlData) : undefined; + const label = + typeof baseLabel === 'function' + ? baseLabel(exploreState, controls[name], chart) + : baseLabel; + + const description = + typeof baseDescription === 'function' + ? baseDescription(exploreState, controls[name], chart) + : baseDescription; + + if (name === 'adhoc_filters') { + restProps.canDelete = ( + valueToBeDeleted: Record<string, any>, + values: Record<string, any>[], + ) => { + const isTemporalRange = (filter: Record<string, any>) => + filter.operator === Operators.TEMPORAL_RANGE; + if (isTemporalRange(valueToBeDeleted)) { + const count = values.filter(isTemporalRange).length; + if (count === 1) { + return t( + `You cannot delete the last temporal filter as it's used for time range filters in dashboards.`, + ); + } + } + return true; + }; + } + return ( <Control key={`control-${name}`} name={name} + label={label} + description={description} validationErrors={validationErrors} actions={props.actions} isVisible={isVisible} @@ -352,6 +520,11 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { ); }; + const sectionHasHadNoErrors = useResetOnChangeRef( + () => ({}), + form_data.viz_type, + ); + const renderControlPanelSection = ( section: ExpandedControlPanelSectionConfig, ) => { @@ -379,19 +552,42 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { ); }), ); + + if (!hasErrors) { + sectionHasHadNoErrors.current[sectionId] = true; + } + + const errorColor = sectionHasHadNoErrors.current[sectionId] + ? colors.error.base + : colors.alert.base; + const PanelHeader = () => ( <span data-test="collapsible-control-panel-header"> - <span>{label}</span>{' '} + <span + css={(theme: SupersetTheme) => css` + font-size: ${theme.typography.sizes.m}px; + line-height: 1.3; + `} + > + {label} + </span>{' '} {description && ( - // label is only used in tooltip id (should probably call this prop `id`) - <InfoTooltipWithTrigger label={sectionId} tooltip={description} /> + <Tooltip id={sectionId} title={description}> + <Icons.InfoCircleOutlined css={iconStyles} /> + </Tooltip> )} {hasErrors && ( - <InfoTooltipWithTrigger - label="validation-errors" - bsStyle="danger" - tooltip="This section contains validation errors" - /> + <Tooltip + id={`${kebabCase('validation-errors')}-tooltip`} + title={t('This section contains validation errors')} + > + <Icons.InfoCircleOutlined + css={css` + ${iconStyles}; + color: ${errorColor}; + `} + /> + </Tooltip> )} </span> ); @@ -415,6 +611,12 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { span.label { display: inline-block; } + ${!section.label && + ` + .ant-collapse-header { + display: none; + } + `} `} header={<PanelHeader />} key={sectionId} @@ -486,14 +688,26 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { [handleClearFormClick, handleContinueClick, hasControlsTransferred], ); - const dataTabTitle = useMemo( - () => ( + const dataTabHasHadNoErrors = useResetOnChangeRef( + () => false, + form_data.viz_type, + ); + + const dataTabTitle = useMemo(() => { + if (!props.errorMessage) { + dataTabHasHadNoErrors.current = true; + } + + const errorColor = dataTabHasHadNoErrors.current + ? colors.error.base + : colors.alert.base; + + return ( <> <span>{t('Data')}</span> {props.errorMessage && ( <span css={(theme: SupersetTheme) => css` - font-size: ${theme.typography.sizes.xs}px; margin-left: ${theme.gridUnit * 2}px; `} > @@ -503,20 +717,26 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { placement="right" title={props.errorMessage} > - <i className="fa fa-exclamation-circle text-danger fa-lg" /> + <Icons.ExclamationCircleOutlined + css={css` + ${iconStyles}; + color: ${errorColor}; + `} + /> </Tooltip> </span> )} </> - ), - [props.errorMessage], - ); + ); + }, [ + colors.error.base, + colors.alert.base, + dataTabHasHadNoErrors, + props.errorMessage, + ]); const controlPanelRegistry = getChartControlPanelRegistry(); - if ( - !controlPanelRegistry.has(props.form_data.viz_type) && - pluginContext.loading - ) { + if (!controlPanelRegistry.has(form_data.viz_type) && pluginContext.loading) { return <Loading />; } diff --git a/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx b/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx index fb77c21d7a779..e05964285573b 100644 --- a/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx +++ b/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx @@ -29,6 +29,7 @@ jest.mock('lodash/debounce', () => ({ test('Render a FilterInput', async () => { const onChangeHandler = jest.fn(); render(<FilterInput onChangeHandler={onChangeHandler} />); + expect(await screen.findByRole('textbox')).toBeInTheDocument(); expect(onChangeHandler).toBeCalledTimes(0); userEvent.type(screen.getByRole('textbox'), 'test'); diff --git a/superset-frontend/src/explore/components/DataTableControl/index.tsx b/superset-frontend/src/explore/components/DataTableControl/index.tsx index fdc74d7bb4cde..7cca07a408008 100644 --- a/superset-frontend/src/explore/components/DataTableControl/index.tsx +++ b/superset-frontend/src/explore/components/DataTableControl/index.tsx @@ -314,9 +314,9 @@ export const useTableColumns = ( const isOriginalTimeColumn = originalFormattedTimeColumns.includes(key); return { - id: key, + // react-table requires a non-empty id, therefore we introduce a fallback value in case the key is empty + id: key || index, accessor: row => row[key], - // When the key is empty, have to give a string of length greater than 0 Header: colType === GenericDataType.TEMPORAL && typeof firstValue !== 'string' ? ( diff --git a/superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx b/superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx index bfba9cf980011..4101911da702b 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx @@ -26,6 +26,7 @@ import React, { import { styled, t, useTheme } from '@superset-ui/core'; import Icons from 'src/components/Icons'; import Tabs from 'src/components/Tabs'; +import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import { getItem, setItem, @@ -96,11 +97,14 @@ export const DataTablesPane = ({ samples: false, }); const [panelOpen, setPanelOpen] = useState( - getItem(LocalStorageKeys.is_datapanel_open, false), + isFeatureEnabled(FeatureFlag.DATAPANEL_CLOSED_BY_DEFAULT) + ? false + : getItem(LocalStorageKeys.is_datapanel_open, false), ); useEffect(() => { - setItem(LocalStorageKeys.is_datapanel_open, panelOpen); + if (!isFeatureEnabled(FeatureFlag.DATAPANEL_CLOSED_BY_DEFAULT)) + setItem(LocalStorageKeys.is_datapanel_open, panelOpen); }, [panelOpen]); useEffect(() => { diff --git a/superset-frontend/src/explore/components/DataTablesPane/components/ResultsPaneOnDashboard.tsx b/superset-frontend/src/explore/components/DataTablesPane/components/ResultsPaneOnDashboard.tsx index 3f27929f5cd8b..ade2c1519dfc4 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/components/ResultsPaneOnDashboard.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/components/ResultsPaneOnDashboard.tsx @@ -17,11 +17,34 @@ * under the License. */ import React from 'react'; -import { t } from '@superset-ui/core'; +import { t, styled } from '@superset-ui/core'; import Tabs from 'src/components/Tabs'; import { ResultTypes, ResultsPaneProps } from '../types'; import { useResultsPane } from './useResultsPane'; +const Wrapper = styled.div` + display: flex; + flex-direction: column; + height: 100%; + + .ant-tabs { + height: 100%; + } + + .ant-tabs-content { + height: 100%; + } + + .ant-tabs-tabpane { + display: flex; + flex-direction: column; + } + + .table-condensed { + overflow: auto; + } +`; + export const ResultsPaneOnDashboard = ({ isRequest, queryFormData, @@ -42,8 +65,9 @@ export const ResultsPaneOnDashboard = ({ dataSize, isVisible, }); + if (resultsPanes.length === 1) { - return resultsPanes[0]; + return <Wrapper>{resultsPanes[0]}</Wrapper>; } const panes = resultsPanes.map((pane, idx) => { @@ -65,5 +89,9 @@ export const ResultsPaneOnDashboard = ({ ); }); - return <Tabs fullWidth={false}> {panes} </Tabs>; + return ( + <Wrapper> + <Tabs fullWidth={false}>{panes}</Tabs> + </Wrapper> + ); }; diff --git a/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx b/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx index 8b1137334b9de..5c66075750dc5 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx @@ -25,7 +25,7 @@ import { useFilteredTableData, useTableColumns, } from 'src/explore/components/DataTableControl'; -import { getDatasetSamples } from 'src/components/Chart/chartAction'; +import { getDatasourceSamples } from 'src/components/Chart/chartAction'; import { TableControls } from './DataTableControls'; import { SamplesPaneProps } from '../types'; @@ -61,7 +61,7 @@ export const SamplesPane = ({ if (isRequest && !cache.has(datasource)) { setIsLoading(true); - getDatasetSamples(datasource.id, queryForce) + getDatasourceSamples(datasource.type, datasource.id, queryForce, {}) .then(response => { setData(ensureIsArray(response.data)); setColnames(ensureIsArray(response.colnames)); diff --git a/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx b/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx index 20e53df849cd1..9b6b597c7900f 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx @@ -17,13 +17,17 @@ * under the License. */ import React, { useState, useEffect } from 'react'; -import { ensureIsArray, styled, t } from '@superset-ui/core'; +import { + ensureIsArray, + styled, + t, + getChartMetadataRegistry, +} from '@superset-ui/core'; import Loading from 'src/components/Loading'; import { EmptyStateMedium } from 'src/components/EmptyState'; import { getChartDataRequest } from 'src/components/Chart/chartAction'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; import { ResultsPaneProps, QueryResultInterface } from '../types'; -import { getQueryCount } from '../utils'; import { SingleQueryResultPane } from './SingleQueryResultPane'; import { TableControls } from './DataTableControls'; @@ -31,7 +35,7 @@ const Error = styled.pre` margin-top: ${({ theme }) => `${theme.gridUnit * 4}px`}; `; -const cache = new WeakSet(); +const cache = new WeakMap(); export const useResultsPane = ({ isRequest, @@ -43,16 +47,26 @@ export const useResultsPane = ({ isVisible, dataSize = 50, }: ResultsPaneProps): React.ReactElement[] => { + const metadata = getChartMetadataRegistry().get( + queryFormData?.viz_type || queryFormData?.vizType, + ); + const [resultResp, setResultResp] = useState<QueryResultInterface[]>([]); const [isLoading, setIsLoading] = useState<boolean>(true); const [responseError, setResponseError] = useState<string>(''); - const queryCount = getQueryCount( - queryFormData?.viz_type || queryFormData?.vizType, - ); + const queryCount = metadata?.queryObjectCount ?? 1; useEffect(() => { // it's an invalid formData when gets a errorMessage if (errorMessage) return; + if (isRequest && cache.has(queryFormData)) { + setResultResp(ensureIsArray(cache.get(queryFormData))); + setResponseError(''); + if (queryForce && actions) { + actions.setForceQuery(false); + } + setIsLoading(false); + } if (isRequest && !cache.has(queryFormData)) { setIsLoading(true); getChartDataRequest({ @@ -65,7 +79,7 @@ export const useResultsPane = ({ .then(({ json }) => { setResultResp(ensureIsArray(json.result)); setResponseError(''); - cache.add(queryFormData); + cache.set(queryFormData, json.result); if (queryForce && actions) { actions.setForceQuery(false); } @@ -122,15 +136,17 @@ export const useResultsPane = ({ ); } - return resultResp.map((result, idx) => ( - <SingleQueryResultPane - data={result.data} - colnames={result.colnames} - coltypes={result.coltypes} - dataSize={dataSize} - datasourceId={queryFormData.datasource} - key={idx} - isVisible={isVisible} - /> - )); + return resultResp + .slice(0, queryCount) + .map((result, idx) => ( + <SingleQueryResultPane + data={result.data} + colnames={result.colnames} + coltypes={result.coltypes} + dataSize={dataSize} + datasourceId={queryFormData.datasource} + key={idx} + isVisible={isVisible} + /> + )); }; diff --git a/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx b/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx index c5d9d0c7bb2d3..a27385f51e9b8 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx @@ -19,12 +19,14 @@ import React from 'react'; import userEvent from '@testing-library/user-event'; import fetchMock from 'fetch-mock'; +import { FeatureFlag } from 'src/featureFlags'; import * as copyUtils from 'src/utils/copy'; import { render, screen, waitForElementToBeRemoved, } from 'spec/helpers/testing-library'; +import { setItem, LocalStorageKeys } from 'src/utils/localStorageHelpers'; import { DataTablesPane } from '..'; import { createDataTablesPaneProps } from './fixture'; @@ -39,10 +41,10 @@ describe('DataTablesPane', () => { localStorage.clear(); }); - test('Rendering DataTablesPane correctly', () => { + test('Rendering DataTablesPane correctly', async () => { const props = createDataTablesPaneProps(0); render(<DataTablesPane {...props} />, { useRedux: true }); - expect(screen.getByText('Results')).toBeVisible(); + expect(await screen.findByText('Results')).toBeVisible(); expect(screen.getByText('Samples')).toBeVisible(); expect(screen.getByLabelText('Expand data panel')).toBeVisible(); }); @@ -143,4 +145,19 @@ describe('DataTablesPane', () => { expect(screen.queryByText('Action')).not.toBeInTheDocument(); fetchMock.restore(); }); + + test('Displaying the data pane is under featureflag', () => { + // @ts-ignore + global.featureFlags = { + [FeatureFlag.DATAPANEL_CLOSED_BY_DEFAULT]: true, + }; + const props = createDataTablesPaneProps(0); + setItem(LocalStorageKeys.is_datapanel_open, true); + render(<DataTablesPane {...props} />, { + useRedux: true, + }); + expect( + screen.queryByLabelText('Collapse data panel'), + ).not.toBeInTheDocument(); + }); }); diff --git a/superset-frontend/src/explore/components/DataTablesPane/test/ResultsPaneOnDashboard.test.tsx b/superset-frontend/src/explore/components/DataTablesPane/test/ResultsPaneOnDashboard.test.tsx index 19980ff711479..839126bb62530 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/test/ResultsPaneOnDashboard.test.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/test/ResultsPaneOnDashboard.test.tsx @@ -22,9 +22,10 @@ import userEvent from '@testing-library/user-event'; import { render, waitForElementToBeRemoved, + waitFor, } from 'spec/helpers/testing-library'; import { exploreActions } from 'src/explore/actions/exploreActions'; -import { promiseTimeout } from '@superset-ui/core'; +import { ChartMetadata, ChartPlugin } from '@superset-ui/core'; import { ResultsPaneOnDashboard } from '../components'; import { createResultsPaneOnDashboardProps } from './fixture'; @@ -133,9 +134,9 @@ describe('ResultsPaneOnDashboard', () => { }, ); - await promiseTimeout(() => { + await waitFor(() => { expect(setForceQuery).toHaveBeenCalledTimes(1); - }, 10); + }); expect(queryByText('2 rows')).toBeVisible(); expect(queryByText('Action')).toBeVisible(); expect(queryByText('Horror')).toBeVisible(); @@ -147,6 +148,19 @@ describe('ResultsPaneOnDashboard', () => { }); test('multiple results pane', async () => { + const FakeChart = () => <span>test</span>; + const metadata = new ChartMetadata({ + name: 'test-chart', + thumbnail: '', + queryObjectCount: 2, + }); + + const plugin = new ChartPlugin({ + metadata, + Chart: FakeChart, + }); + plugin.configure({ key: 'mixed_timeseries' }).register(); + const props = createResultsPaneOnDashboardProps({ sliceId: 196, vizType: 'mixed_timeseries', diff --git a/superset-frontend/src/explore/components/DataTablesPane/test/SamplesPane.test.tsx b/superset-frontend/src/explore/components/DataTablesPane/test/SamplesPane.test.tsx index 54c04c6003ba2..eed6e84808b73 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/test/SamplesPane.test.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/test/SamplesPane.test.tsx @@ -22,33 +22,42 @@ import userEvent from '@testing-library/user-event'; import { render, waitForElementToBeRemoved, + waitFor, } from 'spec/helpers/testing-library'; import { exploreActions } from 'src/explore/actions/exploreActions'; -import { promiseTimeout } from '@superset-ui/core'; import { SamplesPane } from '../components'; import { createSamplesPaneProps } from './fixture'; describe('SamplesPane', () => { - fetchMock.get('end:/api/v1/dataset/34/samples?force=false', { - result: { - data: [], - colnames: [], - coltypes: [], + fetchMock.post( + 'end:/datasource/samples?force=false&datasource_type=table&datasource_id=34', + { + result: { + data: [], + colnames: [], + coltypes: [], + }, }, - }); + ); - fetchMock.get('end:/api/v1/dataset/35/samples?force=true', { - result: { - data: [ - { __timestamp: 1230768000000, genre: 'Action' }, - { __timestamp: 1230768000010, genre: 'Horror' }, - ], - colnames: ['__timestamp', 'genre'], - coltypes: [2, 1], + fetchMock.post( + 'end:/datasource/samples?force=true&datasource_type=table&datasource_id=35', + { + result: { + data: [ + { __timestamp: 1230768000000, genre: 'Action' }, + { __timestamp: 1230768000010, genre: 'Horror' }, + ], + colnames: ['__timestamp', 'genre'], + coltypes: [2, 1], + }, }, - }); + ); - fetchMock.get('end:/api/v1/dataset/36/samples?force=false', 400); + fetchMock.post( + 'end:/datasource/samples?force=false&datasource_type=table&datasource_id=36', + 400, + ); const setForceQuery = jest.spyOn(exploreActions, 'setForceQuery'); @@ -63,9 +72,9 @@ describe('SamplesPane', () => { expect( await findByText('No samples were returned for this dataset'), ).toBeVisible(); - await promiseTimeout(() => { + await waitFor(() => { expect(setForceQuery).toHaveBeenCalledTimes(0); - }, 10); + }); }); test('error response', async () => { @@ -91,9 +100,9 @@ describe('SamplesPane', () => { }, ); - await promiseTimeout(() => { + await waitFor(() => { expect(setForceQuery).toHaveBeenCalledTimes(1); - }, 10); + }); expect(queryByText('2 rows')).toBeVisible(); expect(queryByText('Action')).toBeVisible(); expect(queryByText('Horror')).toBeVisible(); diff --git a/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx b/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx index 4b19c5b2f3818..95258f443ec45 100644 --- a/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx +++ b/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanel.test.tsx @@ -17,11 +17,10 @@ * under the License. */ import React from 'react'; -import { HTML5Backend } from 'react-dnd-html5-backend'; -import { DndProvider } from 'react-dnd'; import { render, screen, waitFor } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import DatasourcePanel, { + IDatasource, Props as DatasourcePanelProps, } from 'src/explore/components/DatasourcePanel'; import { @@ -31,23 +30,15 @@ import { import { DatasourceType } from '@superset-ui/core'; import DatasourceControl from 'src/explore/components/controls/DatasourceControl'; -const datasource = { +const datasource: IDatasource = { id: 1, type: DatasourceType.Table, - name: 'birth_names', columns, metrics, - uid: '1__table', database: { - backend: 'mysql', - name: 'main', + id: 1, }, - column_format: { ratio: '.2%' }, - verbose_map: { __timestamp: 'Time' }, - main_dttm_col: 'None', datasource_name: 'table1', - description: 'desc', - owners: [{ username: 'admin', userId: 1 }], }; const mockUser = { @@ -80,53 +71,50 @@ const props: DatasourcePanelProps = { }, }; -const setup = (props: DatasourcePanelProps) => ( - <DndProvider backend={HTML5Backend}> - <DatasourcePanel {...props} /> - </DndProvider> -); - -function search(value: string, input: HTMLElement) { +const search = (value: string, input: HTMLElement) => { userEvent.clear(input); userEvent.type(input, value); -} +}; -test('should render', () => { - const { container } = render(setup(props), { useRedux: true }); +test('should render', async () => { + const { container } = render(<DatasourcePanel {...props} />, { + useRedux: true, + useDnd: true, + }); + expect(await screen.findByText(/metrics/i)).toBeInTheDocument(); expect(container).toBeVisible(); }); -test('should display items in controls', () => { - render(setup(props), { useRedux: true }); - expect(screen.getByText('birth_names')).toBeInTheDocument(); - expect(screen.getByText('Metrics')).toBeInTheDocument(); +test('should display items in controls', async () => { + render(<DatasourcePanel {...props} />, { useRedux: true, useDnd: true }); + expect(await screen.findByText('Metrics')).toBeInTheDocument(); expect(screen.getByText('Columns')).toBeInTheDocument(); }); -test('should render the metrics', () => { - render(setup(props), { useRedux: true }); +test('should render the metrics', async () => { + render(<DatasourcePanel {...props} />, { useRedux: true, useDnd: true }); const metricsNum = metrics.length; metrics.forEach(metric => expect(screen.getByText(metric.metric_name)).toBeInTheDocument(), ); expect( - screen.getByText(`Showing ${metricsNum} of ${metricsNum}`), + await screen.findByText(`Showing ${metricsNum} of ${metricsNum}`), ).toBeInTheDocument(); }); -test('should render the columns', () => { - render(setup(props), { useRedux: true }); +test('should render the columns', async () => { + render(<DatasourcePanel {...props} />, { useRedux: true, useDnd: true }); const columnsNum = columns.length; columns.forEach(col => expect(screen.getByText(col.column_name)).toBeInTheDocument(), ); expect( - screen.getByText(`Showing ${columnsNum} of ${columnsNum}`), + await screen.findByText(`Showing ${columnsNum} of ${columnsNum}`), ).toBeInTheDocument(); }); test('should render 0 search results', async () => { - render(setup(props), { useRedux: true }); + render(<DatasourcePanel {...props} />, { useRedux: true, useDnd: true }); const searchInput = screen.getByPlaceholderText('Search Metrics & Columns'); search('nothing', searchInput); @@ -134,7 +122,7 @@ test('should render 0 search results', async () => { }); test('should search and render matching columns', async () => { - render(setup(props), { useRedux: true }); + render(<DatasourcePanel {...props} />, { useRedux: true, useDnd: true }); const searchInput = screen.getByPlaceholderText('Search Metrics & Columns'); search(columns[0].column_name, searchInput); @@ -146,7 +134,7 @@ test('should search and render matching columns', async () => { }); test('should search and render matching metrics', async () => { - render(setup(props), { useRedux: true }); + render(<DatasourcePanel {...props} />, { useRedux: true, useDnd: true }); const searchInput = screen.getByPlaceholderText('Search Metrics & Columns'); search(metrics[0].metric_name, searchInput); @@ -162,38 +150,34 @@ test('should render a warning', async () => { ...datasource, extra: JSON.stringify({ warning_markdown: 'This is a warning.' }), }; - render( - setup({ - ...props, - datasource: deprecatedDatasource, - controls: { - datasource: { - ...props.controls.datasource, - datasource: deprecatedDatasource, - user: mockUser, - }, + const newProps = { + ...props, + datasource: deprecatedDatasource, + controls: { + datasource: { + ...props.controls.datasource, + datasource: deprecatedDatasource, + user: mockUser, }, - }), - { useRedux: true }, - ); + }, + }; + render(<DatasourcePanel {...newProps} />, { useRedux: true, useDnd: true }); expect( await screen.findByRole('img', { name: 'alert-solid' }), ).toBeInTheDocument(); }); -test('should render a create dataset infobox', () => { - render( - setup({ - ...props, - datasource: { - ...datasource, - type: DatasourceType.Query, - }, - }), - { useRedux: true }, - ); +test('should render a create dataset infobox', async () => { + const newProps = { + ...props, + datasource: { + ...datasource, + type: DatasourceType.Query, + }, + }; + render(<DatasourcePanel {...newProps} />, { useRedux: true, useDnd: true }); - const createButton = screen.getByRole('button', { + const createButton = await screen.findByRole('button', { name: /create a dataset/i, }); const infoboxText = screen.getByText(/to edit or add columns and metrics./i); @@ -202,40 +186,16 @@ test('should render a create dataset infobox', () => { expect(infoboxText).toBeVisible(); }); -test('should render a save dataset modal when "Create a dataset" is clicked', () => { - render( - setup({ - ...props, - datasource: { - ...datasource, - type: DatasourceType.Query, - }, - }), - { useRedux: true }, - ); - - const createButton = screen.getByRole('button', { - name: /create a dataset/i, - }); - - userEvent.click(createButton); - - const saveDatasetModalTitle = screen.getByText(/save or overwrite dataset/i); - - expect(saveDatasetModalTitle).toBeVisible(); -}); - -test('should not render a save dataset modal when datasource is not query or dataset', () => { - render( - setup({ - ...props, - datasource: { - ...datasource, - type: DatasourceType.Table, - }, - }), - { useRedux: true }, - ); +test('should not render a save dataset modal when datasource is not query or dataset', async () => { + const newProps = { + ...props, + datasource: { + ...datasource, + type: DatasourceType.Table, + }, + }; + render(<DatasourcePanel {...newProps} />, { useRedux: true, useDnd: true }); + expect(await screen.findByText(/metrics/i)).toBeInTheDocument(); expect(screen.queryByText(/create a dataset/i)).toBe(null); }); diff --git a/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanelDragOption/DatasourcePanelDragOption.test.tsx b/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanelDragOption/DatasourcePanelDragOption.test.tsx index be8f91eade6aa..8de766da88c97 100644 --- a/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanelDragOption/DatasourcePanelDragOption.test.tsx +++ b/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanelDragOption/DatasourcePanelDragOption.test.tsx @@ -17,38 +17,35 @@ * under the License. */ import React from 'react'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; import { render, screen } from 'spec/helpers/testing-library'; import { DndItemType } from 'src/explore/components/DndItemType'; import DatasourcePanelDragOption from '.'; -test('should render', () => { +test('should render', async () => { render( - <DndProvider backend={HTML5Backend}> - <DatasourcePanelDragOption - value={{ metric_name: 'test' }} - type={DndItemType.Metric} - /> - </DndProvider>, + <DatasourcePanelDragOption + value={{ metric_name: 'test' }} + type={DndItemType.Metric} + />, + { useDnd: true }, ); - expect(screen.getByTestId('DatasourcePanelDragOption')).toBeInTheDocument(); + expect( + await screen.findByTestId('DatasourcePanelDragOption'), + ).toBeInTheDocument(); expect(screen.getByText('test')).toBeInTheDocument(); }); -test('should have attribute draggable:true', () => { +test('should have attribute draggable:true', async () => { render( - <DndProvider backend={HTML5Backend}> - <DatasourcePanelDragOption - value={{ metric_name: 'test' }} - type={DndItemType.Metric} - /> - </DndProvider>, + <DatasourcePanelDragOption + value={{ metric_name: 'test' }} + type={DndItemType.Metric} + />, + { useDnd: true }, ); - expect(screen.getByTestId('DatasourcePanelDragOption')).toHaveAttribute( - 'draggable', - 'true', - ); + expect( + await screen.findByTestId('DatasourcePanelDragOption'), + ).toHaveAttribute('draggable', 'true'); }); diff --git a/superset-frontend/src/explore/components/DatasourcePanel/fixtures.tsx b/superset-frontend/src/explore/components/DatasourcePanel/fixtures.tsx index a4a893fae08fe..05909b1e64fc2 100644 --- a/superset-frontend/src/explore/components/DatasourcePanel/fixtures.tsx +++ b/superset-frontend/src/explore/components/DatasourcePanel/fixtures.tsx @@ -16,10 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -import { ColumnMeta } from '@superset-ui/chart-controls'; import { GenericDataType } from '@superset-ui/core'; -export const columns: ColumnMeta[] = [ +export const columns = [ { column_name: 'bootcamp_attend', description: null, diff --git a/superset-frontend/src/explore/components/DatasourcePanel/index.tsx b/superset-frontend/src/explore/components/DatasourcePanel/index.tsx index b0042e138f4a1..dedffc104455e 100644 --- a/superset-frontend/src/explore/components/DatasourcePanel/index.tsx +++ b/superset-frontend/src/explore/components/DatasourcePanel/index.tsx @@ -17,39 +17,69 @@ * under the License. */ import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { css, styled, t, DatasourceType } from '@superset-ui/core'; import { - ControlConfig, - Dataset, - ColumnMeta, -} from '@superset-ui/chart-controls'; -import { debounce } from 'lodash'; + css, + styled, + t, + DatasourceType, + Metric, + QueryFormData, +} from '@superset-ui/core'; + +import { ControlConfig, ColumnMeta } from '@superset-ui/chart-controls'; + +import { debounce, isArray } from 'lodash'; import { matchSorter, rankings } from 'match-sorter'; import Collapse from 'src/components/Collapse'; import Alert from 'src/components/Alert'; import { SaveDatasetModal } from 'src/SqlLab/components/SaveDatasetModal'; +import { getDatasourceAsSaveableDataset } from 'src/utils/datasourceUtils'; import { Input } from 'src/components/Input'; import { FAST_DEBOUNCE } from 'src/constants'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import { ExploreActions } from 'src/explore/actions/exploreActions'; import Control from 'src/explore/components/Control'; -import { ExploreDatasource } from 'src/SqlLab/types'; import DatasourcePanelDragOption from './DatasourcePanelDragOption'; import { DndItemType } from '../DndItemType'; import { StyledColumnOption, StyledMetricOption } from '../optionRenderers'; +import { DndItemValue } from './types'; interface DatasourceControl extends ControlConfig { - datasource?: ExploreDatasource; + datasource?: IDatasource; +} + +export interface DataSourcePanelColumn { + is_dttm?: boolean | null; + description?: string | null; + expression?: string | null; + is_certified?: number | null; + column_name?: string | null; + name?: string | null; + type?: string; +} +export interface IDatasource { + metrics: Metric[]; + columns: DataSourcePanelColumn[]; + id: number; + type: DatasourceType; + database: { + id: number; + }; + sql?: string | null; + datasource_name?: string | null; + name?: string | null; + schema?: string | null; } export interface Props { - datasource: Dataset; + datasource: IDatasource; controls: { datasource: DatasourceControl; }; actions: Partial<ExploreActions> & Pick<ExploreActions, 'setControlValue'>; // we use this props control force update when this panel resize shouldForceUpdate?: number; + formData?: QueryFormData; } const enableExploreDnd = isFeatureEnabled( @@ -150,8 +180,9 @@ const LabelWrapper = styled.div` `; const SectionHeader = styled.span` - ${({ theme }) => css` - font-size: ${theme.typography.sizes.s}px; + ${({ theme }) => ` + font-size: ${theme.typography.sizes.m}px; + line-height: 1.3; `} `; @@ -182,20 +213,20 @@ const LabelContainer = (props: { export default function DataSourcePanel({ datasource, + formData, controls: { datasource: datasourceControl }, actions, shouldForceUpdate, }: Props) { const { columns: _columns, metrics } = datasource; - // display temporal column first const columns = useMemo( () => - [..._columns].sort((col1, col2) => { - if (col1.is_dttm && !col2.is_dttm) { + [...(isArray(_columns) ? _columns : [])].sort((col1, col2) => { + if (col1?.is_dttm && !col2?.is_dttm) { return -1; } - if (col2.is_dttm && !col1.is_dttm) { + if (col2?.is_dttm && !col1?.is_dttm) { return 1; } return 0; @@ -235,7 +266,7 @@ export default function DataSourcePanel({ }, { key: item => - [item.description, item.expression].map( + [item?.description ?? '', item?.expression ?? ''].map( x => x?.replace(/[_\n\s]+/g, ' ') || '', ), threshold: rankings.CONTAINS, @@ -256,7 +287,7 @@ export default function DataSourcePanel({ }, { key: item => - [item.description, item.expression].map( + [item?.description ?? '', item?.expression ?? ''].map( x => x?.replace(/[_\n\s]+/g, ' ') || '', ), threshold: rankings.CONTAINS, @@ -265,8 +296,9 @@ export default function DataSourcePanel({ ], keepDiacritics: true, baseSort: (a, b) => - Number(b.item.is_certified) - Number(a.item.is_certified) || - String(a.rankedValue).localeCompare(b.rankedValue), + Number(b?.item?.is_certified ?? 0) - + Number(a?.item?.is_certified ?? 0) || + String(a?.rankedValue ?? '').localeCompare(b?.rankedValue ?? ''), }), }); }, FAST_DEBOUNCE), @@ -281,23 +313,23 @@ export default function DataSourcePanel({ setInputValue(''); }, [columns, datasource, metrics]); - const sortCertifiedFirst = (slice: ColumnMeta[]) => - slice.sort((a, b) => b.is_certified - a.is_certified); + const sortCertifiedFirst = (slice: DataSourcePanelColumn[]) => + slice.sort((a, b) => (b?.is_certified ?? 0) - (a?.is_certified ?? 0)); const metricSlice = useMemo( () => showAllMetrics - ? lists.metrics - : lists.metrics.slice(0, DEFAULT_MAX_METRICS_LENGTH), - [lists.metrics, showAllMetrics], + ? lists?.metrics + : lists?.metrics?.slice?.(0, DEFAULT_MAX_METRICS_LENGTH), + [lists?.metrics, showAllMetrics], ); const columnSlice = useMemo( () => showAllColumns - ? sortCertifiedFirst(lists.columns) + ? sortCertifiedFirst(lists?.columns) : sortCertifiedFirst( - lists.columns.slice(0, DEFAULT_MAX_COLUMNS_LENGTH), + lists?.columns?.slice?.(0, DEFAULT_MAX_COLUMNS_LENGTH), ), [lists.columns, showAllColumns], ); @@ -307,6 +339,14 @@ export default function DataSourcePanel({ return true; }; + const saveableDatasets = { + query: DatasourceType.Query, + saved_query: DatasourceType.SavedQuery, + }; + + const datasourceIsSaveable = + datasource.type && saveableDatasets[datasource.type]; + const mainBody = useMemo( () => ( <> @@ -321,7 +361,7 @@ export default function DataSourcePanel({ placeholder={t('Search Metrics & Columns')} /> <div className="field-selections"> - {datasource.type === DatasourceType.Query && showInfoboxCheck() && ( + {datasourceIsSaveable && showInfoboxCheck() && ( <StyledInfoboxWrapper> <Alert closable @@ -349,42 +389,44 @@ export default function DataSourcePanel({ expandIconPosition="right" ghost > - <Collapse.Panel - header={<SectionHeader>{t('Metrics')}</SectionHeader>} - key="metrics" - > - <div className="field-length"> - {t( - `Showing %s of %s`, - metricSlice.length, - lists.metrics.length, - )} - </div> - {metricSlice.map(m => ( - <LabelContainer - key={m.metric_name + String(shouldForceUpdate)} - className="column" - > - {enableExploreDnd ? ( - <DatasourcePanelDragOption - value={m} - type={DndItemType.Metric} - /> - ) : ( - <StyledMetricOption metric={m} showType /> + {metrics?.length && ( + <Collapse.Panel + header={<SectionHeader>{t('Metrics')}</SectionHeader>} + key="metrics" + > + <div className="field-length"> + {t( + `Showing %s of %s`, + metricSlice?.length, + lists?.metrics.length, )} - </LabelContainer> - ))} - {lists.metrics.length > DEFAULT_MAX_METRICS_LENGTH ? ( - <ButtonContainer> - <Button onClick={() => setShowAllMetrics(!showAllMetrics)}> - {showAllMetrics ? t('Show less...') : t('Show all...')} - </Button> - </ButtonContainer> - ) : ( - <></> - )} - </Collapse.Panel> + </div> + {metricSlice?.map?.((m: Metric) => ( + <LabelContainer + key={m.metric_name + String(shouldForceUpdate)} + className="column" + > + {enableExploreDnd ? ( + <DatasourcePanelDragOption + value={m} + type={DndItemType.Metric} + /> + ) : ( + <StyledMetricOption metric={m} showType /> + )} + </LabelContainer> + ))} + {lists?.metrics?.length > DEFAULT_MAX_METRICS_LENGTH ? ( + <ButtonContainer> + <Button onClick={() => setShowAllMetrics(!showAllMetrics)}> + {showAllMetrics ? t('Show less...') : t('Show all...')} + </Button> + </ButtonContainer> + ) : ( + <></> + )} + </Collapse.Panel> + )} <Collapse.Panel header={<SectionHeader>{t('Columns')}</SectionHeader>} key="column" @@ -403,11 +445,11 @@ export default function DataSourcePanel({ > {enableExploreDnd ? ( <DatasourcePanelDragOption - value={col} + value={col as DndItemValue} type={DndItemType.Column} /> ) : ( - <StyledColumnOption column={col} showType /> + <StyledColumnOption column={col as ColumnMeta} showType /> )} </LabelContainer> ))} @@ -425,28 +467,34 @@ export default function DataSourcePanel({ </div> </> ), + // eslint-disable-next-line react-hooks/exhaustive-deps [ columnSlice, inputValue, lists.columns.length, - lists.metrics.length, + lists?.metrics?.length, metricSlice, search, showAllColumns, showAllMetrics, + datasourceIsSaveable, shouldForceUpdate, ], ); return ( <DatasourceContainer> - <SaveDatasetModal - visible={showSaveDatasetModal} - onHide={() => setShowSaveDatasetModal(false)} - buttonTextOnSave={t('Save')} - buttonTextOnOverwrite={t('Overwrite')} - datasource={datasource} - /> + {datasourceIsSaveable && showSaveDatasetModal && ( + <SaveDatasetModal + visible={showSaveDatasetModal} + onHide={() => setShowSaveDatasetModal(false)} + buttonTextOnSave={t('Save')} + buttonTextOnOverwrite={t('Overwrite')} + datasource={getDatasourceAsSaveableDataset(datasource)} + openWindow={false} + formData={formData} + /> + )} <Control {...datasourceControl} name="datasource" actions={actions} /> {datasource.id != null && mainBody} </DatasourceContainer> diff --git a/superset-frontend/src/explore/components/ExploreAlert.tsx b/superset-frontend/src/explore/components/ExploreAlert.tsx index 34c4cf070e30a..0602fc9035018 100644 --- a/superset-frontend/src/explore/components/ExploreAlert.tsx +++ b/superset-frontend/src/explore/components/ExploreAlert.tsx @@ -28,7 +28,7 @@ interface ControlPanelAlertProps { secondaryButtonAction?: (e: React.MouseEvent) => void; primaryButtonText?: string; secondaryButtonText?: string; - type: 'info' | 'warning'; + type: 'info' | 'warning' | 'error'; className?: string; } @@ -85,6 +85,11 @@ const Title = styled.p` font-weight: ${({ theme }) => theme.typography.weights.bold}; `; +const typeChart = { + warning: 'warning', + danger: 'danger', +}; + export const ExploreAlert = forwardRef( ( { @@ -114,7 +119,7 @@ export const ExploreAlert = forwardRef( </Button> )} <Button - buttonStyle={type === 'warning' ? 'warning' : 'primary'} + buttonStyle={type in typeChart ? typeChart[type] : 'primary'} buttonSize="small" onClick={primaryButtonAction} > diff --git a/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx b/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx index 540a444ab0473..3d9f6b995cc4e 100644 --- a/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx +++ b/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx @@ -23,15 +23,21 @@ import { render, screen, waitFor } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import fetchMock from 'fetch-mock'; import * as chartAction from 'src/components/Chart/chartAction'; +import * as saveModalActions from 'src/explore/actions/saveModalActions'; import * as downloadAsImage from 'src/utils/downloadAsImage'; import * as exploreUtils from 'src/explore/exploreUtils'; +import { FeatureFlag } from '@superset-ui/core'; import ExploreHeader from '.'; const chartEndpoint = 'glob:*api/v1/chart/*'; fetchMock.get(chartEndpoint, { json: 'foo' }); -const createProps = () => ({ +window.featureFlags = { + [FeatureFlag.EMBEDDABLE_CHARTS]: true, +}; + +const createProps = (additionalProps = {}) => ({ chart: { id: 1, latestQueryFormData: { @@ -58,7 +64,7 @@ const createProps = () => ({ changed_on: '2021-03-19T16:30:56.750230', changed_on_humanized: '7 days ago', datasource: 'FCC 2018 Survey', - description: null, + description: 'Simple description', description_markeddown: '', edit_url: '/chart/edit/318', form_data: { @@ -88,7 +94,7 @@ const createProps = () => ({ ], slice_id: 318, slice_name: 'Age distribution of respondents', - slice_url: '/superset/explore/?form_data=%7B%22slice_id%22%3A%20318%7D', + slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20318%7D', }, slice_name: 'Age distribution of respondents', actions: { @@ -101,10 +107,18 @@ const createProps = () => ({ user: { userId: 1, }, - onSaveChart: jest.fn(), + metadata: { + created_on_humanized: 'a week ago', + changed_on_humanized: '2 days ago', + owners: ['John Doe'], + created_by: 'John Doe', + changed_by: 'John Doe', + dashboards: [{ id: 1, dashboard_title: 'Test' }], + }, canOverwrite: false, canDownload: false, isStarred: false, + ...additionalProps, }); fetchMock.post( @@ -115,16 +129,19 @@ fetchMock.post( }, ); -test('Cancelling changes to the properties should reset previous properties', () => { +test('Cancelling changes to the properties should reset previous properties', async () => { const props = createProps(); render(<ExploreHeader {...props} />, { useRedux: true }); const newChartName = 'New chart name'; const prevChartName = props.slice_name; + expect( + await screen.findByText(/add the name of the chart/i), + ).toBeInTheDocument(); userEvent.click(screen.getByLabelText('Menu actions trigger')); userEvent.click(screen.getByText('Edit chart properties')); - const nameInput = screen.getByRole('textbox', { name: 'Name' }); + const nameInput = await screen.findByRole('textbox', { name: 'Name' }); userEvent.clear(nameInput); userEvent.type(nameInput, newChartName); @@ -136,31 +153,80 @@ test('Cancelling changes to the properties should reset previous properties', () userEvent.click(screen.getByLabelText('Menu actions trigger')); userEvent.click(screen.getByText('Edit chart properties')); - expect(screen.getByDisplayValue(prevChartName)).toBeInTheDocument(); + expect(await screen.findByDisplayValue(prevChartName)).toBeInTheDocument(); +}); + +test('renders the metadata bar when saved', async () => { + const props = createProps({ showTitlePanelItems: true }); + render(<ExploreHeader {...props} />, { useRedux: true }); + expect(await screen.findByText('Added to 1 dashboard')).toBeInTheDocument(); + expect(await screen.findByText('Simple description')).toBeInTheDocument(); + expect(await screen.findByText('John Doe')).toBeInTheDocument(); + expect(await screen.findByText('2 days ago')).toBeInTheDocument(); +}); + +test('Changes "Added to X dashboards" to plural when more than 1 dashboard', async () => { + const props = createProps({ showTitlePanelItems: true }); + render( + <ExploreHeader + {...props} + metadata={{ + ...props.metadata, + dashboards: [ + { id: 1, dashboard_title: 'Test' }, + { id: 2, dashboard_title: 'Test2' }, + ], + }} + />, + { useRedux: true }, + ); + expect(await screen.findByText('Added to 2 dashboards')).toBeInTheDocument(); }); -test('Save chart', () => { +test('does not render the metadata bar when not saved', async () => { + const props = createProps({ showTitlePanelItems: true, slice: null }); + render(<ExploreHeader {...props} />, { useRedux: true }); + await waitFor(() => + expect(screen.queryByText('Added to 1 dashboard')).not.toBeInTheDocument(), + ); +}); + +test('Save chart', async () => { + const setSaveChartModalVisibility = jest.spyOn( + saveModalActions, + 'setSaveChartModalVisibility', + ); const props = createProps(); render(<ExploreHeader {...props} />, { useRedux: true }); + expect(await screen.findByText('Save')).toBeInTheDocument(); userEvent.click(screen.getByText('Save')); - expect(props.onSaveChart).toHaveBeenCalled(); + expect(setSaveChartModalVisibility).toHaveBeenCalledWith(true); + setSaveChartModalVisibility.mockClear(); }); -test('Save disabled', () => { +test('Save disabled', async () => { + const setSaveChartModalVisibility = jest.spyOn( + saveModalActions, + 'setSaveChartModalVisibility', + ); const props = createProps(); render(<ExploreHeader {...props} saveDisabled />, { useRedux: true }); + expect(await screen.findByText('Save')).toBeInTheDocument(); userEvent.click(screen.getByText('Save')); - expect(props.onSaveChart).not.toHaveBeenCalled(); + expect(setSaveChartModalVisibility).not.toHaveBeenCalled(); + setSaveChartModalVisibility.mockClear(); }); describe('Additional actions tests', () => { - test('Should render a button', () => { + test('Should render a button', async () => { const props = createProps(); render(<ExploreHeader {...props} />, { useRedux: true }); - expect(screen.getByLabelText('Menu actions trigger')).toBeInTheDocument(); + expect( + await screen.findByLabelText('Menu actions trigger'), + ).toBeInTheDocument(); }); - test('Should open a menu', () => { + test('Should open a menu', async () => { const props = createProps(); render(<ExploreHeader {...props} />, { useRedux: true, @@ -168,7 +234,9 @@ describe('Additional actions tests', () => { userEvent.click(screen.getByLabelText('Menu actions trigger')); - expect(screen.getByText('Edit chart properties')).toBeInTheDocument(); + expect( + await screen.findByText('Edit chart properties'), + ).toBeInTheDocument(); expect(screen.getByText('Download')).toBeInTheDocument(); expect(screen.getByText('Share')).toBeInTheDocument(); expect(screen.getByText('View query')).toBeInTheDocument(); @@ -252,11 +320,12 @@ describe('Additional actions tests', () => { await waitFor(() => expect(getChartDataRequest).toBeCalledTimes(1)); }); - test('Should call onOpenInEditor when click on "Run in SQL Lab"', () => { + test('Should call onOpenInEditor when click on "Run in SQL Lab"', async () => { const props = createProps(); render(<ExploreHeader {...props} />, { useRedux: true, }); + expect(await screen.findByText('Save')).toBeInTheDocument(); expect(props.actions.redirectSQLLab).toBeCalledTimes(0); userEvent.click(screen.getByLabelText('Menu actions trigger')); @@ -278,6 +347,7 @@ describe('Additional actions tests', () => { spyDownloadAsImage.restore(); spyExportChart.restore(); }); + test('Should call downloadAsImage when click on "Download as image"', async () => { const props = createProps(); const spy = jest.spyOn(downloadAsImage, 'default'); diff --git a/superset-frontend/src/explore/components/ExploreChartHeader/index.jsx b/superset-frontend/src/explore/components/ExploreChartHeader/index.jsx index fb85882f02337..958aa16a31994 100644 --- a/superset-frontend/src/explore/components/ExploreChartHeader/index.jsx +++ b/superset-frontend/src/explore/components/ExploreChartHeader/index.jsx @@ -16,18 +16,18 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useEffect, useState } from 'react'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; import { Tooltip } from 'src/components/Tooltip'; import { CategoricalColorNamespace, css, + logging, SupersetClient, t, + tn, } from '@superset-ui/core'; -import { toggleActive, deleteActiveReport } from 'src/reports/actions/reports'; import { chartPropShape } from 'src/dashboard/util/propShapes'; import AlteredSliceTag from 'src/components/AlteredSliceTag'; import Button from 'src/components/Button'; @@ -35,6 +35,8 @@ import Icons from 'src/components/Icons'; import PropertiesModal from 'src/explore/components/PropertiesModal'; import { sliceUpdated } from 'src/explore/actions/exploreActions'; import { PageHeaderWithActions } from 'src/components/PageHeaderWithActions'; +import MetadataBar, { MetadataType } from 'src/components/MetadataBar'; +import { setSaveChartModalVisibility } from 'src/explore/actions/saveModalActions'; import { useExploreAdditionalActionsMenu } from '../useExploreAdditionalActionsMenu'; const propTypes = { @@ -60,6 +62,15 @@ const saveButtonStyles = theme => css` } `; +const additionalItemsStyles = theme => css` + display: flex; + align-items: center; + margin-left: ${theme.gridUnit}px; + & > span { + margin-right: ${theme.gridUnit * 3}px; + } +`; + export const ExploreChartHeader = ({ dashboardId, slice, @@ -71,57 +82,54 @@ export const ExploreChartHeader = ({ canOverwrite, canDownload, isStarred, - sliceUpdated, sliceName, - onSaveChart, saveDisabled, + metadata, }) => { + const dispatch = useDispatch(); const { latestQueryFormData, sliceFormData } = chart; const [isPropertiesModalOpen, setIsPropertiesModalOpen] = useState(false); - const fetchChartDashboardData = async () => { - await SupersetClient.get({ - endpoint: `/api/v1/chart/${slice.slice_id}`, - }) - .then(res => { - const response = res?.json?.result; - if (response && response.dashboards && response.dashboards.length) { - const { dashboards } = response; - const dashboard = - dashboardId && - dashboards.length && - dashboards.find(d => d.id === dashboardId); - - if (dashboard && dashboard.json_metadata) { - // setting the chart to use the dashboard custom label colors if any - const metadata = JSON.parse(dashboard.json_metadata); - const sharedLabelColors = metadata.shared_label_colors || {}; - const customLabelColors = metadata.label_colors || {}; - const mergedLabelColors = { - ...sharedLabelColors, - ...customLabelColors, - }; - - const categoricalNamespace = - CategoricalColorNamespace.getNamespace(); - - Object.keys(mergedLabelColors).forEach(label => { - categoricalNamespace.setColor( - label, - mergedLabelColors[label], - metadata.color_scheme, - ); - }); - } - } - }) - .catch(() => {}); + const updateCategoricalNamespace = async () => { + const { dashboards } = metadata || {}; + const dashboard = + dashboardId && dashboards && dashboards.find(d => d.id === dashboardId); + + if (dashboard) { + try { + // Dashboards from metadata don't contain the json_metadata field + // to avoid unnecessary payload. Here we query for the dashboard json_metadata. + const response = await SupersetClient.get({ + endpoint: `/api/v1/dashboard/${dashboard.id}`, + }); + const result = response?.json?.result; + + // setting the chart to use the dashboard custom label colors if any + const metadata = JSON.parse(result.json_metadata); + const sharedLabelColors = metadata.shared_label_colors || {}; + const customLabelColors = metadata.label_colors || {}; + const mergedLabelColors = { + ...sharedLabelColors, + ...customLabelColors, + }; + + const categoricalNamespace = CategoricalColorNamespace.getNamespace(); + + Object.keys(mergedLabelColors).forEach(label => { + categoricalNamespace.setColor( + label, + mergedLabelColors[label], + metadata.color_scheme, + ); + }); + } catch (error) { + logging.info(t('Unable to retrieve dashboard colors')); + } + } }; useEffect(() => { - if (dashboardId) { - fetchChartDashboardData(); - } + if (dashboardId) updateCategoricalNamespace(); }, []); const openPropertiesModal = () => { @@ -132,6 +140,17 @@ export const ExploreChartHeader = ({ setIsPropertiesModalOpen(false); }; + const showModal = useCallback(() => { + dispatch(setSaveChartModalVisibility(true)); + }, [dispatch]); + + const updateSlice = useCallback( + slice => { + dispatch(sliceUpdated(slice)); + }, + [dispatch], + ); + const [menu, isDropdownVisible, setIsDropdownVisible] = useExploreAdditionalActionsMenu( latestQueryFormData, @@ -140,8 +159,52 @@ export const ExploreChartHeader = ({ actions.redirectSQLLab, openPropertiesModal, ownState, + metadata?.dashboards, ); + const metadataBar = useMemo(() => { + if (!metadata) { + return null; + } + const items = []; + items.push({ + type: MetadataType.DASHBOARDS, + title: + metadata.dashboards.length > 0 + ? tn( + 'Added to 1 dashboard', + 'Added to %s dashboards', + metadata.dashboards.length, + metadata.dashboards.length, + ) + : t('Not added to any dashboard'), + description: + metadata.dashboards.length > 0 + ? t( + 'You can preview the list of dashboards in the chart settings dropdown.', + ) + : undefined, + }); + items.push({ + type: MetadataType.LAST_MODIFIED, + value: metadata.changed_on_humanized, + modifiedBy: metadata.changed_by || t('Not available'), + }); + items.push({ + type: MetadataType.OWNER, + createdBy: metadata.created_by || t('Not available'), + owners: metadata.owners.length > 0 ? metadata.owners : t('None'), + createdOn: metadata.created_on_humanized, + }); + if (slice?.description) { + items.push({ + type: MetadataType.DESCRIPTION, + value: slice?.description, + }); + } + return <MetadataBar items={items} tooltipPlacement="bottom" />; + }, [metadata, slice?.description]); + const oldSliceName = slice?.slice_name; return ( <> @@ -170,16 +233,19 @@ export const ExploreChartHeader = ({ showTooltip: true, }} titlePanelAdditionalItems={ - sliceFormData ? ( - <AlteredSliceTag - className="altered" - origFormData={{ - ...sliceFormData, - chartTitle: oldSliceName, - }} - currentFormData={{ ...formData, chartTitle: sliceName }} - /> - ) : null + <div css={additionalItemsStyles}> + {sliceFormData ? ( + <AlteredSliceTag + className="altered" + origFormData={{ + ...sliceFormData, + chartTitle: oldSliceName, + }} + currentFormData={{ ...formData, chartTitle: sliceName }} + /> + ) : null} + {metadataBar} + </div> } rightPanelAdditionalItems={ <Tooltip @@ -193,7 +259,7 @@ export const ExploreChartHeader = ({ <div> <Button buttonStyle="secondary" - onClick={onSaveChart} + onClick={showModal} disabled={saveDisabled} data-test="query-save-button" css={saveButtonStyles} @@ -214,7 +280,7 @@ export const ExploreChartHeader = ({ <PropertiesModal show={isPropertiesModalOpen} onHide={closePropertiesModal} - onSave={sliceUpdated} + onSave={updateSlice} slice={slice} /> )} @@ -224,11 +290,4 @@ export const ExploreChartHeader = ({ ExploreChartHeader.propTypes = propTypes; -function mapDispatchToProps(dispatch) { - return bindActionCreators( - { sliceUpdated, toggleActive, deleteActiveReport }, - dispatch, - ); -} - -export default connect(null, mapDispatchToProps)(ExploreChartHeader); +export default ExploreChartHeader; diff --git a/superset-frontend/src/explore/components/ExploreChartPanel.jsx b/superset-frontend/src/explore/components/ExploreChartPanel.jsx index cfb60f64878c4..fe23251b8d1b1 100644 --- a/superset-frontend/src/explore/components/ExploreChartPanel.jsx +++ b/superset-frontend/src/explore/components/ExploreChartPanel.jsx @@ -26,15 +26,21 @@ import { SupersetClient, t, useTheme, + getChartMetadataRegistry, + DatasourceType, } from '@superset-ui/core'; import { useResizeDetector } from 'react-resize-detector'; import { chartPropShape } from 'src/dashboard/util/propShapes'; import ChartContainer from 'src/components/Chart/ChartContainer'; +import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import { getItem, setItem, LocalStorageKeys, } from 'src/utils/localStorageHelpers'; +import Alert from 'src/components/Alert'; +import { SaveDatasetModal } from 'src/SqlLab/components/SaveDatasetModal'; +import { getDatasourceAsSaveableDataset } from 'src/utils/datasourceUtils'; import { DataTablesPane } from './DataTablesPane'; import { buildV1ChartDataPayload } from '../exploreUtils'; import { ChartPills } from './ChartPills'; @@ -57,7 +63,7 @@ const propTypes = { vizType: PropTypes.string.isRequired, form_data: PropTypes.object, ownState: PropTypes.object, - standalone: PropTypes.number, + standalone: PropTypes.bool, force: PropTypes.bool, timeout: PropTypes.number, chartIsStale: PropTypes.bool, @@ -93,6 +99,7 @@ const Styles = styled.div` } .gutter.gutter-vertical { + display: ${({ showSplite }) => (showSplite ? 'block' : 'none')}; cursor: row-resize; } @@ -142,12 +149,27 @@ const ExploreChartPanel = ({ refreshRate: 300, }); const [splitSizes, setSplitSizes] = useState( - getItem(LocalStorageKeys.chart_split_sizes, INITIAL_SIZES), + isFeatureEnabled(FeatureFlag.DATAPANEL_CLOSED_BY_DEFAULT) + ? INITIAL_SIZES + : getItem(LocalStorageKeys.chart_split_sizes, INITIAL_SIZES), ); + const [showSplite, setShowSplit] = useState( + isFeatureEnabled(FeatureFlag.DATAPANEL_CLOSED_BY_DEFAULT) + ? false + : getItem(LocalStorageKeys.is_datapanel_open, false), + ); + + const [showDatasetModal, setShowDatasetModal] = useState(false); + const metaDataRegistry = getChartMetadataRegistry(); + const { useLegacyApi } = metaDataRegistry.get(vizType) ?? {}; + const vizTypeNeedsDataset = + useLegacyApi && datasource.type !== DatasourceType.Table; + // added boolean column to below show boolean so that the errors aren't overlapping const showAlertBanner = !chartAlert && chartIsStale && + !vizTypeNeedsDataset && chart.chartStatus !== 'failed' && ensureIsArray(chart.queriesResponse).length > 0; @@ -212,6 +234,7 @@ const ExploreChartPanel = ({ ]; } setSplitSizes(splitSizes); + setShowSplit(isOpen); }, []); const renderChart = useCallback( @@ -286,6 +309,31 @@ const ExploreChartPanel = ({ flex-direction: column; `} > + {vizTypeNeedsDataset && ( + <Alert + message={t('Chart type requires a dataset')} + type="error" + css={theme => css` + margin: 0 0 ${theme.gridUnit * 4}px 0; + `} + description={ + <> + {t( + 'This chart type is not supported when using an unsaved query as a chart source. ', + )} + <span + role="button" + tabIndex={0} + onClick={() => setShowDatasetModal(true)} + css={{ textDecoration: 'underline' }} + > + {t('Create a dataset')} + </span> + {t(' to visualize your data.')} + </> + } + /> + )} {showAlertBanner && ( <ExploreAlert title={ @@ -363,7 +411,7 @@ const ExploreChartPanel = ({ ); if (standalone) { - // dom manipulation hack to get rid of the boostrap theme's body background + // dom manipulation hack to get rid of the bootstrap theme's body background const standaloneClass = 'background-transparent'; const bodyClasses = document.body.className.split(' '); if (!bodyClasses.includes(standaloneClass)) { @@ -373,7 +421,10 @@ const ExploreChartPanel = ({ } return ( - <Styles className="panel panel-default chart-container"> + <Styles + className="panel panel-default chart-container" + showSplite={showSplite} + > {vizType === 'filter_box' ? ( panelBody ) : ( @@ -399,6 +450,17 @@ const ExploreChartPanel = ({ /> </Split> )} + {showDatasetModal && ( + <SaveDatasetModal + visible={showDatasetModal} + onHide={() => setShowDatasetModal(false)} + buttonTextOnSave={t('Save')} + buttonTextOnOverwrite={t('Overwrite')} + datasource={getDatasourceAsSaveableDataset(datasource)} + openWindow={false} + formData={formData} + /> + )} </Styles> ); }; diff --git a/superset-frontend/src/explore/components/ExploreChartPanel.test.jsx b/superset-frontend/src/explore/components/ExploreChartPanel.test.jsx index 557b2149e01e1..63e139e755d84 100644 --- a/superset-frontend/src/explore/components/ExploreChartPanel.test.jsx +++ b/superset-frontend/src/explore/components/ExploreChartPanel.test.jsx @@ -18,8 +18,10 @@ */ import React from 'react'; import userEvent from '@testing-library/user-event'; -import { render, screen } from 'spec/helpers/testing-library'; +import { render, screen, within } from 'spec/helpers/testing-library'; +import { getChartMetadataRegistry, ChartMetadata } from '@superset-ui/core'; import ChartContainer from 'src/explore/components/ExploreChartPanel'; +import { setItem, LocalStorageKeys } from 'src/utils/localStorageHelpers'; const createProps = (overrides = {}) => ({ sliceName: 'Trend Line', @@ -57,42 +59,54 @@ const createProps = (overrides = {}) => ({ }); describe('ChartContainer', () => { - it('renders when vizType is line', () => { + test('renders when vizType is line', () => { const props = createProps(); expect(React.isValidElement(<ChartContainer {...props} />)).toBe(true); }); - it('renders with alert banner', () => { + test('renders with alert banner', async () => { const props = createProps({ chartIsStale: true, chart: { chartStatus: 'rendered', queriesResponse: [{}] }, }); + getChartMetadataRegistry().registerValue( + 'histogram', + new ChartMetadata({ + name: 'fake table', + thumbnail: '.png', + useLegacyApi: false, + }), + ); render(<ChartContainer {...props} />, { useRedux: true }); - expect(screen.getByText('Your chart is not up to date')).toBeVisible(); + expect( + await screen.findByText('Your chart is not up to date'), + ).toBeVisible(); }); - it('doesnt render alert banner when no changes in control panel were made (chart is not stale)', () => { + test('doesnt render alert banner when no changes in control panel were made (chart is not stale)', async () => { const props = createProps({ chartIsStale: false, }); render(<ChartContainer {...props} />, { useRedux: true }); + expect(await screen.findByText(/cached/i)).toBeInTheDocument(); expect( screen.queryByText('Your chart is not up to date'), ).not.toBeInTheDocument(); }); - it('doesnt render alert banner when chart not created yet (no queries response)', () => { + test('doesnt render alert banner when chart not created yet (no queries response)', async () => { const props = createProps({ chartIsStale: true, chart: { queriesResponse: [] }, }); render(<ChartContainer {...props} />, { useRedux: true }); + expect(await screen.findByRole('timer')).toBeInTheDocument(); expect( screen.queryByText('Your chart is not up to date'), ).not.toBeInTheDocument(); }); - it('renders prompt to fill required controls when required control removed', () => { + test('renders prompt to fill required controls when required control removed', async () => { const props = createProps({ chartIsStale: true, chart: { chartStatus: 'rendered', queriesResponse: [{}] }, @@ -100,11 +114,11 @@ describe('ChartContainer', () => { }); render(<ChartContainer {...props} />, { useRedux: true }); expect( - screen.getByText('Required control values have been removed'), + await screen.findByText('Required control values have been removed'), ).toBeVisible(); }); - it('should render cached button and call expected actions', () => { + test('should render cached button and call expected actions', async () => { const setForceQuery = jest.fn(); const postChartFormData = jest.fn(); const updateQueryFormData = jest.fn(); @@ -117,7 +131,7 @@ describe('ChartContainer', () => { }); render(<ChartContainer {...props} />, { useRedux: true }); - const cached = screen.queryByText('Cached'); + const cached = await screen.findByText('Cached'); expect(cached).toBeInTheDocument(); userEvent.click(cached); @@ -126,7 +140,7 @@ describe('ChartContainer', () => { expect(updateQueryFormData).toHaveBeenCalledTimes(1); }); - it('should hide cached button', () => { + test('should hide cached button', async () => { const props = createProps({ chart: { chartStatus: 'rendered', @@ -134,6 +148,24 @@ describe('ChartContainer', () => { }, }); render(<ChartContainer {...props} />, { useRedux: true }); - expect(screen.queryByText('Cached')).not.toBeInTheDocument(); + expect(await screen.findByRole('timer')).toBeInTheDocument(); + expect(screen.queryByText(/cached/i)).not.toBeInTheDocument(); + }); + + it('hides gutter when collapsing data panel', async () => { + const props = createProps(); + setItem(LocalStorageKeys.is_datapanel_open, true); + const { container } = render(<ChartContainer {...props} />, { + useRedux: true, + }); + const tabpanel = screen.getByRole('tabpanel', { name: /results/i }); + expect(await within(tabpanel).findByText(/0 rows/i)).toBeInTheDocument(); + + const gutter = container.querySelector('.gutter'); + expect(gutter).toBeVisible(); + + userEvent.click(screen.getByLabelText('Collapse data panel')); + expect(await screen.findByRole('timer')).toBeInTheDocument(); + expect(gutter).not.toBeVisible(); }); }); diff --git a/superset-frontend/src/explore/components/ExploreViewContainer/ExploreViewContainer.test.tsx b/superset-frontend/src/explore/components/ExploreViewContainer/ExploreViewContainer.test.tsx index 2260346968dd3..a4ad594387433 100644 --- a/superset-frontend/src/explore/components/ExploreViewContainer/ExploreViewContainer.test.tsx +++ b/superset-frontend/src/explore/components/ExploreViewContainer/ExploreViewContainer.test.tsx @@ -18,7 +18,11 @@ */ import React from 'react'; import fetchMock from 'fetch-mock'; -import { getChartControlPanelRegistry } from '@superset-ui/core'; +import { + getChartControlPanelRegistry, + getChartMetadataRegistry, + ChartMetadata, +} from '@superset-ui/core'; import { MemoryRouter, Route } from 'react-router-dom'; import { render, screen, waitFor } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; @@ -26,7 +30,6 @@ import ExploreViewContainer from '.'; const reduxState = { explore: { - common: { conf: { SUPERSET_WEBSERVER_TIMEOUT: 60 } }, controls: { datasource: { value: '1__table' }, viz_type: { value: 'table' }, @@ -37,10 +40,18 @@ const reduxState = { columns: [{ is_dttm: false }], metrics: [{ id: 1, metric_name: 'count' }], }, - user: { - userId: 1, - }, isStarred: false, + slice: { + slice_id: 1, + }, + metadata: { + created_on_humanized: 'a week ago', + changed_on_humanized: '2 days ago', + owners: ['John Doe'], + created_by: 'John Doe', + changed_by: 'John Doe', + dashboards: [{ id: 1, dashboard_title: 'Test' }], + }, }, charts: { 1: { @@ -50,9 +61,22 @@ const reduxState = { }, }, }, + user: { + userId: 1, + }, + common: { conf: { SUPERSET_WEBSERVER_TIMEOUT: 60 } }, + datasources: { + '1__table': { + id: 1, + type: 'table', + columns: [{ is_dttm: false }], + metrics: [{ id: 1, metric_name: 'count' }], + }, + }, }; -const key = 'aWrs7w29sd'; +const KEY = 'aWrs7w29sd'; +const SEARCH = `?form_data_key=${KEY}&dataset_id=1`; jest.mock('react-resize-detector', () => ({ __esModule: true, @@ -64,13 +88,25 @@ jest.mock('lodash/debounce', () => ({ default: (fuc: Function) => fuc, })); -fetchMock.post('glob:*/api/v1/explore/form_data*', { key }); -fetchMock.put('glob:*/api/v1/explore/form_data*', { key }); +fetchMock.post('glob:*/api/v1/explore/form_data*', { key: KEY }); +fetchMock.put('glob:*/api/v1/explore/form_data*', { key: KEY }); fetchMock.get('glob:*/api/v1/explore/form_data*', {}); +fetchMock.get('glob:*/favstar/slice*', { count: 0 }); -const renderWithRouter = (withKey?: boolean) => { - const path = '/superset/explore/'; - const search = withKey ? `?form_data_key=${key}&dataset_id=1` : ''; +const defaultPath = '/explore/'; +const renderWithRouter = ({ + search = '', + overridePathname, +}: { + search?: string; + overridePathname?: string; +} = {}) => { + const path = overridePathname ?? defaultPath; + Object.defineProperty(window, 'location', { + get() { + return { pathname: path, search }; + }, + }); return render( <MemoryRouter initialEntries={[`${path}${search}`]}> <Route path={path}> @@ -82,6 +118,14 @@ const renderWithRouter = (withKey?: boolean) => { }; test('generates a new form_data param when none is available', async () => { + getChartMetadataRegistry().registerValue( + 'table', + new ChartMetadata({ + name: 'fake table', + thumbnail: '.png', + useLegacyApi: false, + }), + ); const replaceState = jest.spyOn(window.history, 'replaceState'); await waitFor(() => renderWithRouter()); expect(replaceState).toHaveBeenCalledWith( @@ -99,12 +143,12 @@ test('generates a new form_data param when none is available', async () => { test('generates a different form_data param when one is provided and is mounting', async () => { const replaceState = jest.spyOn(window.history, 'replaceState'); - await waitFor(() => renderWithRouter(true)); + await waitFor(() => renderWithRouter({ search: SEARCH })); expect(replaceState).not.toHaveBeenLastCalledWith( 0, expect.anything(), undefined, - expect.stringMatching(key), + expect.stringMatching(KEY), ); expect(replaceState).toHaveBeenCalledWith( expect.anything(), @@ -120,7 +164,7 @@ test('reuses the same form_data param when updating', async () => { }); const replaceState = jest.spyOn(window.history, 'replaceState'); const pushState = jest.spyOn(window.history, 'pushState'); - await waitFor(() => renderWithRouter()); + await waitFor(() => renderWithRouter({ search: SEARCH })); expect(replaceState.mock.calls.length).toBe(1); userEvent.click(screen.getByText('Update chart')); await waitFor(() => expect(pushState.mock.calls.length).toBe(1)); @@ -129,3 +173,32 @@ test('reuses the same form_data param when updating', async () => { pushState.mockRestore(); getChartControlPanelRegistry().remove('table'); }); + +test('doesnt call replaceState when pathname is not /explore', async () => { + getChartMetadataRegistry().registerValue( + 'table', + new ChartMetadata({ + name: 'fake table', + thumbnail: '.png', + useLegacyApi: false, + }), + ); + const replaceState = jest.spyOn(window.history, 'replaceState'); + await waitFor(() => renderWithRouter({ overridePathname: '/dashboard' })); + expect(replaceState).not.toHaveBeenCalled(); + replaceState.mockRestore(); +}); + +test('preserves unknown parameters', async () => { + const replaceState = jest.spyOn(window.history, 'replaceState'); + const unknownParam = 'test=123'; + await waitFor(() => + renderWithRouter({ search: `${SEARCH}&${unknownParam}` }), + ); + expect(replaceState).toHaveBeenCalledWith( + expect.anything(), + undefined, + expect.stringMatching(unknownParam), + ); + replaceState.mockRestore(); +}); diff --git a/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx b/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx index 9f33e9df824d1..66eed14a6ca57 100644 --- a/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx +++ b/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx @@ -37,6 +37,12 @@ import { LocalStorageKeys, } from 'src/utils/localStorageHelpers'; import { RESERVED_CHART_URL_PARAMS, URL_PARAMS } from 'src/constants'; +import { areObjectsEqual } from 'src/reduxUtils'; +import * as logActions from 'src/logger/actions'; +import { + LOG_ACTIONS_MOUNT_EXPLORER, + LOG_ACTIONS_CHANGE_EXPLORE_CONTROLS, +} from 'src/logger/LogUtils'; import { getUrlParam } from 'src/utils/urlUtils'; import cx from 'classnames'; import * as chartActions from 'src/components/Chart/chartAction'; @@ -44,21 +50,17 @@ import { fetchDatasourceMetadata } from 'src/dashboard/actions/datasources'; import { chartPropShape } from 'src/dashboard/util/propShapes'; import { mergeExtraFormData } from 'src/dashboard/components/nativeFilters/utils'; import { postFormData, putFormData } from 'src/explore/exploreUtils/formData'; +import { datasourcesActions } from 'src/explore/actions/datasourcesActions'; +import { mountExploreUrl } from 'src/explore/exploreUtils'; +import { getFormDataFromControls } from 'src/explore/controlUtils'; +import * as exploreActions from 'src/explore/actions/exploreActions'; +import * as saveModalActions from 'src/explore/actions/saveModalActions'; import { useTabId } from 'src/hooks/useTabId'; +import withToasts from 'src/components/MessageToasts/withToasts'; import ExploreChartPanel from '../ExploreChartPanel'; import ConnectedControlPanelsContainer from '../ControlPanelsContainer'; import SaveModal from '../SaveModal'; import DataSourcePanel from '../DatasourcePanel'; -import { mountExploreUrl } from '../../exploreUtils'; -import { areObjectsEqual } from '../../../reduxUtils'; -import { getFormDataFromControls } from '../../controlUtils'; -import * as exploreActions from '../../actions/exploreActions'; -import * as saveModalActions from '../../actions/saveModalActions'; -import * as logActions from '../../../logger/actions'; -import { - LOG_ACTIONS_MOUNT_EXPLORER, - LOG_ACTIONS_CHANGE_EXPLORE_CONTROLS, -} from '../../../logger/LogUtils'; import ConnectedExploreChartHeader from '../ExploreChartHeader'; const propTypes = { @@ -73,17 +75,20 @@ const propTypes = { controls: PropTypes.object.isRequired, forcedHeight: PropTypes.string, form_data: PropTypes.object.isRequired, - standalone: PropTypes.number.isRequired, + standalone: PropTypes.bool.isRequired, force: PropTypes.bool, timeout: PropTypes.number, impressionId: PropTypes.string, vizType: PropTypes.string, + saveAction: PropTypes.string, + isSaveModalVisible: PropTypes.bool, }; const ExploreContainer = styled.div` display: flex; flex-direction: column; height: 100%; + min-height: 0; `; const ExplorePanelContainer = styled.div` @@ -126,10 +131,10 @@ const ExplorePanelContainer = styled.div` position: relative; display: flex; flex-direction: row; - padding: 0 ${theme.gridUnit * 4}px; + padding: 0 ${theme.gridUnit * 2}px 0 ${theme.gridUnit * 4}px; justify-content: space-between; .horizontal-text { - font-size: ${theme.typography.sizes.s}px; + font-size: ${theme.typography.sizes.m}px; } } .no-show { @@ -145,7 +150,7 @@ const ExplorePanelContainer = styled.div` padding: ${theme.gridUnit * 2}px; width: ${theme.gridUnit * 8}px; } - .callpase-icon > svg { + .collapse-icon > svg { color: ${theme.colors.primary.base}; } `}; @@ -164,7 +169,9 @@ const updateHistory = debounce( ) => { const payload = { ...formData }; const chartId = formData.slice_id; - const additionalParam = {}; + const params = new URLSearchParams(window.location.search); + const additionalParam = Object.fromEntries(params); + if (chartId) { additionalParam[URL_PARAMS.sliceId.name] = chartId; } else { @@ -203,15 +210,18 @@ const updateHistory = debounce( ); stateModifier = 'pushState'; } - const url = mountExploreUrl( - standalone ? URL_PARAMS.standalone.name : null, - { - [URL_PARAMS.formDataKey.name]: key, - ...additionalParam, - }, - force, - ); - window.history[stateModifier](payload, title, url); + // avoid race condition in case user changes route before explore updates the url + if (window.location.pathname.startsWith('/explore')) { + const url = mountExploreUrl( + standalone ? URL_PARAMS.standalone.name : null, + { + [URL_PARAMS.formDataKey.name]: key, + ...additionalParam, + }, + force, + ); + window.history[stateModifier](payload, title, url); + } } catch (e) { logging.warn('Failed at altering browser history', e); } @@ -232,7 +242,6 @@ function ExploreViewContainer(props) { props.controls, ); - const [showingModal, setShowingModal] = useState(false); const [isCollapsed, setIsCollapsed] = useState(false); const [shouldForceUpdate, setShouldForceUpdate] = useState(-1); const tabId = useTabId(); @@ -330,10 +339,6 @@ function ExploreViewContainer(props) { } } - function toggleModal() { - setShowingModal(!showingModal); - } - function toggleCollapse() { setIsCollapsed(!isCollapsed); } @@ -450,6 +455,7 @@ function ExploreViewContainer(props) { !areObjectsEqual( props.controls[key].value, lastQueriedControls[key].value, + { ignoreFields: ['datasourceWarning'] }, ), ); @@ -462,6 +468,14 @@ function ExploreViewContainer(props) { return false; }, [lastQueriedControls, props.controls]); + useChangeEffect(props.saveAction, () => { + if (['saveas', 'overwrite'].includes(props.saveAction)) { + onQuery(); + addHistory({ isReplace: true }); + props.actions.setSaveAction(null); + } + }); + useEffect(() => { if (props.ownState !== undefined) { onQuery(); @@ -549,8 +563,8 @@ function ExploreViewContainer(props) { ownState={props.ownState} user={props.user} reports={props.reports} - onSaveChart={toggleModal} saveDisabled={errorMessage || props.chart.chartStatus === 'loading'} + metadata={props.metadata} /> <ExplorePanelContainer id="explore-container"> <Global @@ -577,15 +591,6 @@ function ExploreViewContainer(props) { } `} /> - {showingModal && ( - <SaveModal - onHide={toggleModal} - actions={props.actions} - form_data={props.form_data} - sliceName={props.sliceName} - dashboardId={props.dashboardId} - /> - )} <Resizable onResizeStop={(evt, direction, ref, d) => { setShouldForceUpdate(d?.width); @@ -603,7 +608,7 @@ function ExploreViewContainer(props) { } > <div className="title-container"> - <span className="horizontal-text">{t('Dataset')}</span> + <span className="horizontal-text">{t('Chart Source')}</span> <span role="button" tabIndex={0} @@ -618,6 +623,7 @@ function ExploreViewContainer(props) { </span> </div> <DataSourcePanel + formData={props.form_data} datasource={props.datasource} controls={props.controls} actions={props.actions} @@ -642,11 +648,6 @@ function ExploreViewContainer(props) { /> </Tooltip> </span> - <Icons.DatasetPhysical - css={{ marginTop: theme.gridUnit * 2 }} - iconSize="l" - iconColor={theme.colors.grayscale.base} - /> </div> ) : null} <Resizable @@ -686,6 +687,15 @@ function ExploreViewContainer(props) { {renderChartContainer()} </div> </ExplorePanelContainer> + {props.isSaveModalVisible && ( + <SaveModal + addDangerToast={props.addDangerToast} + actions={props.actions} + form_data={props.form_data} + sliceName={props.sliceName} + dashboardId={props.dashboardId} + /> + )} </ExploreContainer> ); } @@ -693,16 +703,26 @@ function ExploreViewContainer(props) { ExploreViewContainer.propTypes = propTypes; function mapStateToProps(state) { - const { explore, charts, impressionId, dataMask, reports } = state; - const form_data = getFormDataFromControls(explore.controls); + const { + explore, + charts, + common, + impressionId, + dataMask, + reports, + user, + saveModal, + } = state; + const { controls, slice, datasource, metadata } = explore; + const form_data = getFormDataFromControls(controls); + const slice_id = form_data.slice_id ?? slice?.slice_id ?? 0; // 0 - unsaved chart form_data.extra_form_data = mergeExtraFormData( { ...form_data.extra_form_data }, { - ...dataMask[form_data.slice_id ?? 0]?.ownState, // 0 - unsaved chart + ...dataMask[slice_id]?.ownState, }, ); - const chartKey = Object.keys(charts)[0]; - const chart = charts[chartKey]; + const chart = charts[slice_id]; let dashboardId = Number(explore.form_data?.dashboardId); if (Number.isNaN(dashboardId)) { @@ -711,43 +731,44 @@ function mapStateToProps(state) { return { isDatasourceMetaLoading: explore.isDatasourceMetaLoading, - datasource: explore.datasource, - datasource_type: explore.datasource.type, - datasourceId: explore.datasource_id, + datasource, + datasource_type: datasource.type, + datasourceId: datasource.datasource_id, dashboardId, controls: explore.controls, - can_overwrite: !!explore.can_overwrite, can_add: !!explore.can_add, can_download: !!explore.can_download, - column_formats: explore.datasource - ? explore.datasource.column_formats - : null, - containerId: explore.slice - ? `slice-container-${explore.slice.slice_id}` + can_overwrite: !!explore.can_overwrite, + column_formats: datasource?.column_formats ?? null, + containerId: slice + ? `slice-container-${slice.slice_id}` : 'slice-container', isStarred: explore.isStarred, - slice: explore.slice, - sliceName: explore.sliceName, + slice, + sliceName: explore.sliceName ?? slice?.slice_name ?? null, triggerRender: explore.triggerRender, form_data, - table_name: form_data.datasource_name, + table_name: datasource.table_name, vizType: form_data.viz_type, - standalone: explore.standalone, - force: explore.force, - forcedHeight: explore.forced_height, + standalone: !!explore.standalone, + force: !!explore.force, chart, - timeout: explore.common.conf.SUPERSET_WEBSERVER_TIMEOUT, - ownState: dataMask[form_data.slice_id ?? 0]?.ownState, // 0 - unsaved chart + timeout: common.conf.SUPERSET_WEBSERVER_TIMEOUT, + ownState: dataMask[slice_id]?.ownState, impressionId, - user: explore.user, + user, exploreState: explore, reports, + metadata, + saveAction: explore.saveAction, + isSaveModalVisible: saveModal.isVisible, }; } function mapDispatchToProps(dispatch) { const actions = { ...exploreActions, + ...datasourcesActions, ...saveModalActions, ...chartActions, ...logActions, @@ -760,4 +781,4 @@ function mapDispatchToProps(dispatch) { export default connect( mapStateToProps, mapDispatchToProps, -)(ExploreViewContainer); +)(withToasts(React.memo(ExploreViewContainer))); diff --git a/superset-frontend/src/explore/components/ExportToCSVDropdown/ExportToCSVDropdown.test.tsx b/superset-frontend/src/explore/components/ExportToCSVDropdown/ExportToCSVDropdown.test.tsx index 5207b5f5ffbb4..144f03aa6f165 100644 --- a/superset-frontend/src/explore/components/ExportToCSVDropdown/ExportToCSVDropdown.test.tsx +++ b/superset-frontend/src/explore/components/ExportToCSVDropdown/ExportToCSVDropdown.test.tsx @@ -18,21 +18,27 @@ */ import React from 'react'; import userEvent from '@testing-library/user-event'; -import { render, screen } from 'spec/helpers/testing-library'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; import { ExportToCSVDropdown } from './index'; const exportCSVOriginal = jest.fn(); const exportCSVPivoted = jest.fn(); -test('Dropdown button with menu renders', () => { - render( - <ExportToCSVDropdown - exportCSVOriginal={exportCSVOriginal} - exportCSVPivoted={exportCSVPivoted} - > - <div>.CSV</div> - </ExportToCSVDropdown>, +const waitForRender = () => { + waitFor(() => + render( + <ExportToCSVDropdown + exportCSVOriginal={exportCSVOriginal} + exportCSVPivoted={exportCSVPivoted} + > + <div>.CSV</div> + </ExportToCSVDropdown>, + ), ); +}; + +test('Dropdown button with menu renders', () => { + waitForRender(); expect(screen.getByText('.CSV')).toBeVisible(); @@ -43,14 +49,7 @@ test('Dropdown button with menu renders', () => { }); test('Call export csv original on click', () => { - render( - <ExportToCSVDropdown - exportCSVOriginal={exportCSVOriginal} - exportCSVPivoted={exportCSVPivoted} - > - <div>.CSV</div> - </ExportToCSVDropdown>, - ); + waitForRender(); userEvent.click(screen.getByText('.CSV')); userEvent.click(screen.getByText('Original')); @@ -59,14 +58,7 @@ test('Call export csv original on click', () => { }); test('Call export csv pivoted on click', () => { - render( - <ExportToCSVDropdown - exportCSVOriginal={exportCSVOriginal} - exportCSVPivoted={exportCSVPivoted} - > - <div>.CSV</div> - </ExportToCSVDropdown>, - ); + waitForRender(); userEvent.click(screen.getByText('.CSV')); userEvent.click(screen.getByText('Pivoted')); diff --git a/superset-frontend/src/explore/components/PropertiesModal/PropertiesModal.test.tsx b/superset-frontend/src/explore/components/PropertiesModal/PropertiesModal.test.tsx index 4ea1327603311..9b8d4ec2edf53 100644 --- a/superset-frontend/src/explore/components/PropertiesModal/PropertiesModal.test.tsx +++ b/superset-frontend/src/explore/components/PropertiesModal/PropertiesModal.test.tsx @@ -269,6 +269,9 @@ test('Empty "Certified by" should clear "Certification details"', async () => { }; renderModal(noCertifiedByProps); + expect( + await screen.findByRole('textbox', { name: 'Certification details' }), + ).toBeInTheDocument(); expect( screen.getByRole('textbox', { name: 'Certification details' }), ).toHaveValue(''); diff --git a/superset-frontend/src/explore/components/PropertiesModal/index.tsx b/superset-frontend/src/explore/components/PropertiesModal/index.tsx index de1639894b77a..53bcfe77c3d10 100644 --- a/superset-frontend/src/explore/components/PropertiesModal/index.tsx +++ b/superset-frontend/src/explore/components/PropertiesModal/index.tsx @@ -20,7 +20,7 @@ import React, { useMemo, useState, useCallback, useEffect } from 'react'; import Modal from 'src/components/Modal'; import { Input, TextArea } from 'src/components/Input'; import Button from 'src/components/Button'; -import { Select, Row, Col, AntdForm } from 'src/components'; +import { AsyncSelect, Row, Col, AntdForm } from 'src/components'; import { SelectValue } from 'antd/lib/select'; import rison from 'rison'; import { t, SupersetClient, styled } from '@superset-ui/core'; @@ -69,7 +69,7 @@ function PropertiesModal({ errorText = t('You do not have permission to edit this chart'); } Modal.error({ - title: 'Error', + title: t('Error'), content: errorText, okButtonProps: { danger: true, className: 'btn-danger' }, }); @@ -107,12 +107,12 @@ function PropertiesModal({ return SupersetClient.get({ endpoint: `/api/v1/chart/related/owners?q=${query}`, }).then(response => ({ - data: response.json.result.map( - (item: { value: number; text: string }) => ({ + data: response.json.result + .filter((item: { extra: { active: boolean } }) => item.extra.active) + .map((item: { value: number; text: string }) => ({ value: item.value, label: item.text, - }), - ), + })), totalCount: response.json.count, })); }, @@ -159,6 +159,7 @@ function PropertiesModal({ ...payload, ...res.json.result, id: slice.slice_id, + owners: selectedOwners, }; onSave(updatedChart); addSuccessToast(t('Chart properties updated')); @@ -186,7 +187,7 @@ function PropertiesModal({ <Modal show={show} onHide={onHide} - title="Edit Chart Properties" + title={t('Edit Chart Properties')} footer={ <> <Button @@ -298,7 +299,7 @@ function PropertiesModal({ </FormItem> <h3 style={{ marginTop: '1em' }}>{t('Access')}</h3> <FormItem label={ownersLabel}> - <Select + <AsyncSelect ariaLabel={ownersLabel} mode="multiple" name="owners" diff --git a/superset-frontend/src/explore/components/RowCountLabel/index.tsx b/superset-frontend/src/explore/components/RowCountLabel/index.tsx index 3597e49724752..be41be0ba67de 100644 --- a/superset-frontend/src/explore/components/RowCountLabel/index.tsx +++ b/superset-frontend/src/explore/components/RowCountLabel/index.tsx @@ -35,10 +35,14 @@ export default function RowCountLabel(props: RowCountLabelProps) { limitReached || (rowcount === 0 && !loading) ? 'danger' : 'default'; const formattedRowCount = getNumberFormatter()(rowcount); const label = ( - <Label type={type} data-test="row-count-label"> - {loading - ? t('Loading...') - : tn('%s row', '%s rows', rowcount, formattedRowCount)} + <Label type={type}> + {loading ? ( + t('Loading...') + ) : ( + <span data-test="row-count-label"> + {tn('%s row', '%s rows', rowcount, formattedRowCount)} + </span> + )} </Label> ); return limitReached ? ( diff --git a/superset-frontend/src/explore/components/SaveModal.test.jsx b/superset-frontend/src/explore/components/SaveModal.test.jsx index b3a7ac3d58b17..15bfc64e7588b 100644 --- a/superset-frontend/src/explore/components/SaveModal.test.jsx +++ b/superset-frontend/src/explore/components/SaveModal.test.jsx @@ -29,322 +29,199 @@ import Button from 'src/components/Button'; import sinon from 'sinon'; import fetchMock from 'fetch-mock'; -import * as exploreUtils from 'src/explore/exploreUtils'; import * as saveModalActions from 'src/explore/actions/saveModalActions'; import SaveModal, { StyledModal } from 'src/explore/components/SaveModal'; - -describe('SaveModal', () => { - const middlewares = [thunk]; - const mockStore = configureStore(middlewares); - const initialState = { - chart: {}, - saveModal: { - dashboards: [], - }, - explore: { - datasource: {}, - slice: { - slice_id: 1, - slice_name: 'title', - owners: [1], - }, - alert: null, - user: { - userId: 1, - }, - }, - }; - const store = mockStore(initialState); - - const defaultProps = { - onHide: () => ({}), - actions: bindActionCreators(saveModalActions, arg => { - if (typeof arg === 'function') { - return arg(jest.fn); - } - return arg; - }), - form_data: { datasource: '107__table', url_params: { foo: 'bar' } }, - }; - const mockEvent = { - target: { - value: 'mock event target', +import { BrowserRouter } from 'react-router-dom'; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); +const initialState = { + chart: {}, + saveModal: { + dashboards: [], + }, + explore: { + datasource: {}, + slice: { + slice_id: 1, + slice_name: 'title', + owners: [1], }, - value: 10, - }; - - const mockDashboardData = { - pks: ['id'], - result: [{ id: 'id', dashboard_title: 'dashboard title' }], - }; - - const saveEndpoint = `glob:*/dashboardasync/api/read?_flt_0_owners=${1}`; - - beforeAll(() => fetchMock.get(saveEndpoint, mockDashboardData)); - - afterAll(() => fetchMock.restore()); - - const getWrapper = () => - shallow(<SaveModal {...defaultProps} store={store} />) - .dive() - .dive(); - - it('renders a Modal with the right set of components', () => { - const wrapper = getWrapper(); - expect(wrapper.find(StyledModal)).toExist(); - expect(wrapper.find(Radio)).toHaveLength(2); - - const footerWrapper = shallow(wrapper.find(StyledModal).props().footer); - - expect(footerWrapper.find(Button)).toHaveLength(3); - }); - - it('renders the right footer buttons when an existing dashboard', () => { - const wrapper = getWrapper(); - const footerWrapper = shallow(wrapper.find(StyledModal).props().footer); - const saveAndGoDash = footerWrapper - .find('#btn_modal_save_goto_dash') - .getElement(); - const save = footerWrapper.find('#btn_modal_save').getElement(); - expect(save.props.children).toBe('Save'); - expect(saveAndGoDash.props.children).toBe('Save & go to dashboard'); - }); - - it('renders the right footer buttons when a new dashboard', () => { - const wrapper = getWrapper(); - wrapper.setState({ - saveToDashboardId: null, - newDashboardName: 'Test new dashboard', - }); - const footerWrapper = shallow(wrapper.find(StyledModal).props().footer); - const saveAndGoDash = footerWrapper - .find('#btn_modal_save_goto_dash') - .getElement(); - const save = footerWrapper.find('#btn_modal_save').getElement(); - expect(save.props.children).toBe('Save to new dashboard'); - expect(saveAndGoDash.props.children).toBe('Save & go to new dashboard'); - }); - - it('overwrite radio button is disabled for new slice', () => { - const wrapper = getWrapper(); - wrapper.setProps({ slice: null }); - expect(wrapper.find('#overwrite-radio').prop('disabled')).toBe(true); - }); - - it('disable overwrite option for non-owner', () => { - const wrapperForNonOwner = getWrapper(); - wrapperForNonOwner.setProps({ userId: 2 }); - const overwriteRadio = wrapperForNonOwner.find('#overwrite-radio'); - expect(overwriteRadio).toHaveLength(1); - expect(overwriteRadio.prop('disabled')).toBe(true); - }); - - it('saves a new slice', () => { - const wrapperForNewSlice = getWrapper(); - wrapperForNewSlice.setProps({ can_overwrite: false }); - wrapperForNewSlice.instance().changeAction('saveas'); - const saveasRadio = wrapperForNewSlice.find('#saveas-radio'); - saveasRadio.simulate('click'); - expect(wrapperForNewSlice.state().action).toBe('saveas'); - }); - - it('overwrite a slice', () => { - const wrapperForOverwrite = getWrapper(); - const overwriteRadio = wrapperForOverwrite.find('#overwrite-radio'); - overwriteRadio.simulate('click'); - expect(wrapperForOverwrite.state().action).toBe('overwrite'); - }); - - it('componentDidMount', () => { - sinon.spy(defaultProps.actions, 'fetchDashboards'); - mount( - <Provider store={store}> - <SaveModal {...defaultProps} /> - </Provider>, - ); - expect(defaultProps.actions.fetchDashboards.calledOnce).toBe(true); - - defaultProps.actions.fetchDashboards.restore(); - }); - - it('onChange', () => { - const wrapper = getWrapper(); - const dashboardId = mockEvent.value; - - wrapper.instance().onSliceNameChange(mockEvent); - expect(wrapper.state().newSliceName).toBe(mockEvent.target.value); - - wrapper.instance().onDashboardSelectChange(dashboardId); - expect(wrapper.state().saveToDashboardId).toBe(dashboardId); - }); - - describe('saveOrOverwrite', () => { - beforeEach(() => { - sinon.stub(exploreUtils, 'getExploreUrl').callsFake(() => 'mockURL'); - - sinon.stub(defaultProps.actions, 'saveSlice').callsFake(() => - Promise.resolve({ - dashboard_url: 'http://localhost/mock_dashboard/', - slice: { slice_url: '/mock_slice/' }, - }), - ); - }); - - afterEach(() => { - exploreUtils.getExploreUrl.restore(); - defaultProps.actions.saveSlice.restore(); - }); - - it('should save slice without url_params in form_data', () => { - const wrapper = getWrapper(); - wrapper.instance().saveOrOverwrite(true); - const { args } = defaultProps.actions.saveSlice.getCall(0); - expect(args[0]).toEqual({ datasource: '107__table' }); - }); - - it('existing dashboard', () => { - const wrapper = getWrapper(); - const saveToDashboardId = 100; + alert: null, + }, + user: { + userId: 1, + }, +}; + +const initialStore = mockStore(initialState); + +const defaultProps = { + onHide: () => ({}), + actions: bindActionCreators(saveModalActions, arg => { + if (typeof arg === 'function') { + return arg(jest.fn); + } + return arg; + }), + form_data: { datasource: '107__table', url_params: { foo: 'bar' } }, +}; + +const mockEvent = { + target: { + value: 'mock event target', + }, + value: 10, +}; + +const mockDashboardData = { + pks: ['id'], + result: [{ id: 'id', dashboard_title: 'dashboard title' }], +}; + +const queryStore = mockStore({ + chart: {}, + saveModal: { + dashboards: [], + }, + explore: { + datasource: { name: 'test', type: 'query' }, + slice: null, + alert: null, + }, + user: { + userId: 1, + }, +}); - wrapper.setState({ saveToDashboardId }); - wrapper.instance().saveOrOverwrite(true); - const { args } = defaultProps.actions.saveSlice.getCall(0); - expect(args[1].save_to_dashboard_id).toBe(saveToDashboardId); - }); +const queryDefaultProps = { + ...defaultProps, + form_data: { datasource: '107__query', url_params: { foo: 'bar' } }, +}; - it('new dashboard', () => { - const wrapper = getWrapper(); - const newDashboardName = 'new dashboard name'; +const fetchDashboardsEndpoint = `glob:*/dashboardasync/api/read?_flt_0_owners=${1}`; - wrapper.setState({ newDashboardName }); - wrapper.instance().saveOrOverwrite(true); - const { args } = defaultProps.actions.saveSlice.getCall(0); - expect(args[1].new_dashboard_name).toBe(newDashboardName); - }); +beforeAll(() => fetchMock.get(fetchDashboardsEndpoint, mockDashboardData)); - describe('should always reload or redirect', () => { - const originalLocation = window.location; - delete window.location; - window.location = { assign: jest.fn() }; - const stub = sinon.stub(window.location, 'assign'); +afterAll(() => fetchMock.restore()); - afterAll(() => { - delete window.location; - window.location = originalLocation; - }); +const getWrapper = (props = defaultProps, store = initialStore) => + shallow( + <BrowserRouter> + <SaveModal {...props} store={store} /> + </BrowserRouter>, + ) + .dive() + .dive() + .dive() + .dive() + .dive() + .dive() + .dive() + .dive(); - let wrapper; +test('renders a Modal with the right set of components', () => { + const wrapper = getWrapper(); + expect(wrapper.find(StyledModal)).toExist(); + expect(wrapper.find(Radio)).toHaveLength(2); - beforeEach(() => { - stub.resetHistory(); - wrapper = getWrapper(); - }); + const footerWrapper = shallow(wrapper.find(StyledModal).props().footer); - it('Save & go to dashboard', () => - new Promise(done => { - wrapper.instance().saveOrOverwrite(true); - defaultProps.actions.saveSlice().then(() => { - expect(window.location.assign.callCount).toEqual(1); - expect(window.location.assign.getCall(0).args[0]).toEqual( - 'http://localhost/mock_dashboard/?foo=bar', - ); - done(); - }); - })); + expect(footerWrapper.find(Button)).toHaveLength(3); +}); - it('saveas new slice', () => - new Promise(done => { - wrapper.setState({ - action: 'saveas', - newSliceName: 'new slice name', - }); - wrapper.instance().saveOrOverwrite(false); - defaultProps.actions.saveSlice().then(() => { - expect(window.location.assign.callCount).toEqual(1); - expect(window.location.assign.getCall(0).args[0]).toEqual( - '/mock_slice/?foo=bar', - ); - done(); - }); - })); +test('renders the right footer buttons when existing dashboard selected', () => { + const wrapper = getWrapper(); + const footerWrapper = shallow(wrapper.find(StyledModal).props().footer); + const saveAndGoDash = footerWrapper + .find('#btn_modal_save_goto_dash') + .getElement(); + const save = footerWrapper.find('#btn_modal_save').getElement(); + expect(save.props.children).toBe('Save'); + expect(saveAndGoDash.props.children).toBe('Save & go to dashboard'); +}); - it('overwrite original slice', () => - new Promise(done => { - wrapper.setState({ action: 'overwrite' }); - wrapper.instance().saveOrOverwrite(false); - defaultProps.actions.saveSlice().then(() => { - expect(window.location.assign.callCount).toEqual(1); - expect(window.location.assign.getCall(0).args[0]).toEqual( - '/mock_slice/?foo=bar', - ); - done(); - }); - })); - }); +test('renders the right footer buttons when new dashboard selected', () => { + const wrapper = getWrapper(); + wrapper.setState({ + saveToDashboardId: null, + newDashboardName: 'Test new dashboard', }); + const footerWrapper = shallow(wrapper.find(StyledModal).props().footer); + const saveAndGoDash = footerWrapper + .find('#btn_modal_save_goto_dash') + .getElement(); + const save = footerWrapper.find('#btn_modal_save').getElement(); + expect(save.props.children).toBe('Save to new dashboard'); + expect(saveAndGoDash.props.children).toBe('Save & go to new dashboard'); +}); - describe('fetchDashboards', () => { - let dispatch; - let actionThunk; - const userID = 1; - - beforeEach(() => { - fetchMock.resetHistory(); - dispatch = sinon.spy(); - }); +test('disables overwrite option for new slice', () => { + const wrapper = getWrapper(); + wrapper.setProps({ slice: null }); + expect(wrapper.find('#overwrite-radio').prop('disabled')).toBe(true); +}); - const makeRequest = () => { - actionThunk = saveModalActions.fetchDashboards(userID); - return actionThunk(dispatch); - }; +test('disables overwrite option for non-owner', () => { + const wrapperForNonOwner = getWrapper(); + wrapperForNonOwner.setProps({ userId: 2 }); + const overwriteRadio = wrapperForNonOwner.find('#overwrite-radio'); + expect(overwriteRadio).toHaveLength(1); + expect(overwriteRadio.prop('disabled')).toBe(true); +}); - it('makes the fetch request', () => - makeRequest().then(() => { - expect(fetchMock.calls(saveEndpoint)).toHaveLength(1); +test('sets action when saving as new slice', () => { + const wrapperForNewSlice = getWrapper(); + wrapperForNewSlice.setProps({ can_overwrite: false }); + wrapperForNewSlice.instance().changeAction('saveas'); + const saveasRadio = wrapperForNewSlice.find('#saveas-radio'); + saveasRadio.simulate('click'); + expect(wrapperForNewSlice.state().action).toBe('saveas'); +}); - return Promise.resolve(); - })); +test('sets action when overwriting slice', () => { + const wrapperForOverwrite = getWrapper(); + const overwriteRadio = wrapperForOverwrite.find('#overwrite-radio'); + overwriteRadio.simulate('click'); + expect(wrapperForOverwrite.state().action).toBe('overwrite'); +}); - it('calls correct actions on success', () => - makeRequest().then(() => { - expect(dispatch.callCount).toBe(1); - expect(dispatch.getCall(0).args[0].type).toBe( - saveModalActions.FETCH_DASHBOARDS_SUCCEEDED, - ); +test('fetches dashboards on component mount', () => { + sinon.spy(defaultProps.actions, 'fetchDashboards'); + mount( + <Provider store={initialStore}> + <SaveModal {...defaultProps} /> + </Provider>, + ); + expect(defaultProps.actions.fetchDashboards.calledOnce).toBe(true); - return Promise.resolve(); - })); + defaultProps.actions.fetchDashboards.restore(); +}); - it('calls correct actions on error', () => { - fetchMock.get( - saveEndpoint, - { throws: 'error' }, - { overwriteRoutes: true }, - ); +test('updates slice name and selected dashboard', () => { + const wrapper = getWrapper(); + const dashboardId = mockEvent.value; - return makeRequest().then(() => { - expect(dispatch.callCount).toBe(1); - expect(dispatch.getCall(0).args[0].type).toBe( - saveModalActions.FETCH_DASHBOARDS_FAILED, - ); + wrapper.instance().onSliceNameChange(mockEvent); + expect(wrapper.state().newSliceName).toBe(mockEvent.target.value); - fetchMock.get(saveEndpoint, mockDashboardData, { - overwriteRoutes: true, - }); + wrapper.instance().onDashboardSelectChange(dashboardId); + expect(wrapper.state().saveToDashboardId).toBe(dashboardId); +}); - return Promise.resolve(); - }); - }); - }); +test('removes alert', () => { + sinon.spy(defaultProps.actions, 'removeSaveModalAlert'); + const wrapper = getWrapper(); + wrapper.setProps({ alert: 'old alert' }); - it('removeAlert', () => { - sinon.spy(defaultProps.actions, 'removeSaveModalAlert'); - const wrapper = getWrapper(); - wrapper.setProps({ alert: 'old alert' }); + wrapper.instance().removeAlert(); + expect(defaultProps.actions.removeSaveModalAlert.callCount).toBe(1); + expect(wrapper.state().alert).toBeNull(); + defaultProps.actions.removeSaveModalAlert.restore(); +}); - wrapper.instance().removeAlert(); - expect(defaultProps.actions.removeSaveModalAlert.callCount).toBe(1); - expect(wrapper.state().alert).toBeNull(); - defaultProps.actions.removeSaveModalAlert.restore(); - }); +test('set dataset name when chart source is query', () => { + const wrapper = getWrapper(queryDefaultProps, queryStore); + expect(wrapper.find('[data-test="new-dataset-name"]')).toExist(); + expect(wrapper.state().datasetName).toBe('test'); }); diff --git a/superset-frontend/src/explore/components/SaveModal.tsx b/superset-frontend/src/explore/components/SaveModal.tsx index 5a9cd37fbb59f..d62cb4d898c6c 100644 --- a/superset-frontend/src/explore/components/SaveModal.tsx +++ b/superset-frontend/src/explore/components/SaveModal.tsx @@ -18,22 +18,35 @@ */ /* eslint camelcase: 0 */ import React from 'react'; +import { Dispatch } from 'redux'; +import { SelectValue } from 'antd/lib/select'; +import { connect } from 'react-redux'; +import { withRouter, RouteComponentProps } from 'react-router-dom'; +import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; +import { + css, + t, + styled, + DatasourceType, + isDefined, + ensureIsArray, +} from '@superset-ui/core'; import { Input } from 'src/components/Input'; import { Form, FormItem } from 'src/components/Form'; import Alert from 'src/components/Alert'; -import { JsonObject, t, styled } from '@superset-ui/core'; import Modal from 'src/components/Modal'; import { Radio } from 'src/components/Radio'; import Button from 'src/components/Button'; import { Select } from 'src/components'; -import { SelectValue } from 'antd/lib/select'; -import { connect } from 'react-redux'; +import Loading from 'src/components/Loading'; +import { setSaveChartModalVisibility } from 'src/explore/actions/saveModalActions'; +import { SaveActionType } from 'src/explore/types'; // Session storage key for recent dashboard const SK_DASHBOARD_ID = 'save_chart_recent_dashboard'; -type SaveModalProps = { - onHide: () => void; +interface SaveModalProps extends RouteComponentProps { + addDangerToast: (msg: string) => void; actions: Record<string, any>; form_data?: Record<string, any>; userId: number; @@ -43,22 +56,30 @@ type SaveModalProps = { slice?: Record<string, any>; datasource?: Record<string, any>; dashboardId: '' | number | null; -}; - -type ActionType = 'overwrite' | 'saveas'; + isVisible: boolean; + dispatch: Dispatch; +} type SaveModalState = { saveToDashboardId: number | string | null; newSliceName?: string; newDashboardName?: string; + datasetName: string; alert: string | null; - action: ActionType; + action: SaveActionType; + isLoading: boolean; + saveStatus?: string | null; }; export const StyledModal = styled(Modal)` .ant-modal-body { overflow: visible; } + i { + position: absolute; + top: -${({ theme }) => theme.gridUnit * 5.25}px; + left: ${({ theme }) => theme.gridUnit * 26.75}px; + } `; class SaveModal extends React.Component<SaveModalProps, SaveModalState> { @@ -67,14 +88,18 @@ class SaveModal extends React.Component<SaveModalProps, SaveModalState> { this.state = { saveToDashboardId: null, newSliceName: props.sliceName, + datasetName: props.datasource?.name, alert: null, action: this.canOverwriteSlice() ? 'overwrite' : 'saveas', + isLoading: false, }; this.onDashboardSelectChange = this.onDashboardSelectChange.bind(this); this.onSliceNameChange = this.onSliceNameChange.bind(this); this.changeAction = this.changeAction.bind(this); this.saveOrOverwrite = this.saveOrOverwrite.bind(this); this.isNewDashboard = this.isNewDashboard.bind(this); + this.removeAlert = this.removeAlert.bind(this); + this.onHide = this.onHide.bind(this); } isNewDashboard(): boolean { @@ -90,7 +115,10 @@ class SaveModal extends React.Component<SaveModalProps, SaveModalState> { componentDidMount() { this.props.actions.fetchDashboards(this.props.userId).then(() => { - const dashboardIds = this.props.dashboards.map( + if (ensureIsArray(this.props.dashboards).length === 0) { + return; + } + const dashboardIds = this.props.dashboards?.map( dashboard => dashboard.value, ); const lastDashboard = sessionStorage.getItem(SK_DASHBOARD_ID); @@ -111,6 +139,11 @@ class SaveModal extends React.Component<SaveModalProps, SaveModalState> { }); } + handleDatasetNameChange = (e: React.FormEvent<HTMLInputElement>) => { + // @ts-expect-error + this.setState({ datasetName: e.target.value }); + }; + onSliceNameChange(event: React.ChangeEvent<HTMLInputElement>) { this.setState({ newSliceName: event.target.value }); } @@ -122,48 +155,256 @@ class SaveModal extends React.Component<SaveModalProps, SaveModalState> { this.setState({ saveToDashboardId, newDashboardName }); } - changeAction(action: ActionType) { + changeAction(action: SaveActionType) { this.setState({ action }); } - saveOrOverwrite(gotodash: boolean) { - this.setState({ alert: null }); + onHide() { + this.props.dispatch(setSaveChartModalVisibility(false)); + } + + async saveOrOverwrite(gotodash: boolean) { + this.setState({ alert: null, isLoading: true }); this.props.actions.removeSaveModalAlert(); - const sliceParams: Record<string, any> = {}; - if (this.props.slice && this.props.slice.slice_id) { - sliceParams.slice_id = this.props.slice.slice_id; - } - if (sliceParams.action === 'saveas') { - if (this.state.newSliceName === '') { - this.setState({ alert: t('Please enter a chart name') }); + // Create or retrieve dashboard + type DashboardGetResponse = { + id: number; + url: string; + dashboard_title: string; + }; + + try { + if (this.props.datasource?.type === DatasourceType.Query) { + const { schema, sql, database } = this.props.datasource; + const { templateParams } = this.props.datasource; + const columns = this.props.datasource?.columns || []; + + await this.props.actions.saveDataset({ + schema, + sql, + database, + templateParams, + datasourceName: this.state.datasetName, + columns, + }); + } + + // Get chart dashboards + let sliceDashboards: number[] = []; + if (this.props.slice && this.state.action === 'overwrite') { + sliceDashboards = await this.props.actions.getSliceDashboards( + this.props.slice, + ); + } + + const formData = this.props.form_data || {}; + delete formData.url_params; + + let dashboard: DashboardGetResponse | null = null; + if (this.state.newDashboardName || this.state.saveToDashboardId) { + let saveToDashboardId = this.state.saveToDashboardId || null; + if (!this.state.saveToDashboardId) { + const response = await this.props.actions.createDashboard( + this.state.newDashboardName, + ); + saveToDashboardId = response.id; + } + + const response = await this.props.actions.getDashboard( + saveToDashboardId, + ); + dashboard = response.result; + if (isDefined(dashboard) && isDefined(dashboard?.id)) { + sliceDashboards = sliceDashboards.includes(dashboard.id) + ? sliceDashboards + : [...sliceDashboards, dashboard.id]; + formData.dashboards = sliceDashboards; + } + } + + // Sets the form data + this.props.actions.setFormData({ ...formData }); + + // Update or create slice + let value: { id: number }; + if (this.state.action === 'overwrite') { + value = await this.props.actions.updateSlice( + this.props.slice, + this.state.newSliceName, + sliceDashboards, + dashboard + ? { + title: dashboard.dashboard_title, + new: !this.state.saveToDashboardId, + } + : null, + ); + } else { + value = await this.props.actions.createSlice( + this.state.newSliceName, + sliceDashboards, + dashboard + ? { + title: dashboard.dashboard_title, + new: !this.state.saveToDashboardId, + } + : null, + ); + } + + if (dashboard) { + sessionStorage.setItem(SK_DASHBOARD_ID, `${dashboard.id}`); + } else { + sessionStorage.removeItem(SK_DASHBOARD_ID); + } + + // Go to new dashboard url + if (gotodash && dashboard) { + this.props.history.push(dashboard.url); return; } + + const searchParams = new URLSearchParams(window.location.search); + searchParams.set('save_action', this.state.action); + searchParams.delete('form_data_key'); + if (this.state.action === 'saveas') { + searchParams.set('slice_id', value.id.toString()); + } + this.props.history.replace(`/explore/?${searchParams.toString()}`); + + this.setState({ isLoading: false }); + this.onHide(); + } finally { + this.setState({ isLoading: false }); } - sliceParams.action = this.state.action; - sliceParams.slice_name = this.state.newSliceName; - sliceParams.save_to_dashboard_id = this.state.saveToDashboardId; - sliceParams.new_dashboard_name = this.state.newDashboardName; - const { url_params, ...formData } = this.props.form_data || {}; - - this.props.actions - .saveSlice(formData, sliceParams) - .then((data: JsonObject) => { - if (data.dashboard_id === null) { - sessionStorage.removeItem(SK_DASHBOARD_ID); - } else { - sessionStorage.setItem(SK_DASHBOARD_ID, data.dashboard_id); + } + + renderSaveChartModal = () => { + const dashboardSelectValue = + this.state.saveToDashboardId || this.state.newDashboardName; + + return ( + <Form data-test="save-modal-body" layout="vertical"> + {(this.state.alert || this.props.alert) && ( + <Alert + type="warning" + message={this.state.alert || this.props.alert} + onClose={this.removeAlert} + /> + )} + <FormItem data-test="radio-group"> + <Radio + id="overwrite-radio" + disabled={!this.canOverwriteSlice()} + checked={this.state.action === 'overwrite'} + onChange={() => this.changeAction('overwrite')} + data-test="save-overwrite-radio" + > + {t('Save (Overwrite)')} + </Radio> + <Radio + id="saveas-radio" + data-test="saveas-radio" + checked={this.state.action === 'saveas'} + onChange={() => this.changeAction('saveas')} + > + {t('Save as...')} + </Radio> + </FormItem> + <hr /> + <FormItem label={t('Chart name')} required> + <Input + name="new_slice_name" + type="text" + placeholder="Name" + value={this.state.newSliceName} + onChange={this.onSliceNameChange} + data-test="new-chart-name" + /> + </FormItem> + {this.props.datasource?.type === 'query' && ( + <FormItem label={t('Dataset Name')} required> + <InfoTooltipWithTrigger + tooltip={t('A reusable dataset will be saved with your chart.')} + placement="right" + /> + <Input + name="dataset_name" + type="text" + placeholder="Dataset Name" + value={this.state.datasetName} + onChange={this.handleDatasetNameChange} + data-test="new-dataset-name" + /> + </FormItem> + )} + <FormItem + label={t('Add to dashboard')} + data-test="save-chart-modal-select-dashboard-form" + > + <Select + allowClear + allowNewOptions + ariaLabel={t('Select a dashboard')} + options={this.props.dashboards} + onChange={this.onDashboardSelectChange} + value={dashboardSelectValue || undefined} + placeholder={ + <div> + <b>{t('Select')}</b> + {t(' a dashboard OR ')} + <b>{t('create')}</b> + {t(' a new one')} + </div> + } + /> + </FormItem> + </Form> + ); + }; + + renderFooter = () => ( + <div data-test="save-modal-footer"> + <Button id="btn_cancel" buttonSize="small" onClick={this.onHide}> + {t('Cancel')} + </Button> + <Button + id="btn_modal_save_goto_dash" + buttonSize="small" + disabled={ + !this.state.newSliceName || + (!this.state.saveToDashboardId && !this.state.newDashboardName) || + (this.props.datasource?.type !== DatasourceType.Table && + !this.state.datasetName) } - // Go to new slice url or dashboard url - let url = gotodash ? data.dashboard_url : data.slice.slice_url; - if (url_params) { - const prefix = url.includes('?') ? '&' : '?'; - url = `${url}${prefix}${new URLSearchParams(url_params).toString()}`; + onClick={() => this.saveOrOverwrite(true)} + > + {this.isNewDashboard() + ? t('Save & go to new dashboard') + : t('Save & go to dashboard')} + </Button> + <Button + id="btn_modal_save" + buttonSize="small" + buttonStyle="primary" + onClick={() => this.saveOrOverwrite(false)} + disabled={ + this.state.isLoading || + !this.state.newSliceName || + (this.props.datasource?.type !== DatasourceType.Table && + !this.state.datasetName) } - window.location.assign(url); - }); - this.props.onHide(); - } + data-test="btn-modal-save" + > + {!this.canOverwriteSlice() && this.props.slice + ? t('Save as new chart') + : this.isNewDashboard() + ? t('Save to new dashboard') + : t('Save')} + </Button> + </div> + ); removeAlert() { if (this.props.alert) { @@ -173,139 +414,52 @@ class SaveModal extends React.Component<SaveModalProps, SaveModalState> { } render() { - const dashboardSelectValue = - this.state.saveToDashboardId || this.state.newDashboardName; return ( <StyledModal - show - onHide={this.props.onHide} + show={this.props.isVisible} + onHide={this.onHide} title={t('Save chart')} - footer={ - <div data-test="save-modal-footer"> - <Button - id="btn_cancel" - buttonSize="small" - onClick={this.props.onHide} - > - {t('Cancel')} - </Button> - <Button - id="btn_modal_save_goto_dash" - buttonSize="small" - disabled={ - !this.state.newSliceName || - (!this.state.saveToDashboardId && !this.state.newDashboardName) - } - onClick={() => this.saveOrOverwrite(true)} - > - {this.isNewDashboard() - ? t('Save & go to new dashboard') - : t('Save & go to dashboard')} - </Button> - <Button - id="btn_modal_save" - buttonSize="small" - buttonStyle="primary" - onClick={() => this.saveOrOverwrite(false)} - disabled={!this.state.newSliceName} - data-test="btn-modal-save" - > - {!this.canOverwriteSlice() && this.props.slice - ? t('Save as new chart') - : this.isNewDashboard() - ? t('Save to new dashboard') - : t('Save')} - </Button> - </div> - } + footer={this.renderFooter()} > - <Form data-test="save-modal-body" layout="vertical"> - {(this.state.alert || this.props.alert) && ( - <Alert - type="warning" - message={ - <> - {this.state.alert ? this.state.alert : this.props.alert} - <i - role="button" - aria-label="Remove alert" - tabIndex={0} - className="fa fa-close pull-right" - onClick={this.removeAlert.bind(this)} - style={{ cursor: 'pointer' }} - /> - </> - } - /> - )} - <FormItem data-test="radio-group"> - <Radio - id="overwrite-radio" - disabled={!this.canOverwriteSlice()} - checked={this.state.action === 'overwrite'} - onChange={() => this.changeAction('overwrite')} - data-test="save-overwrite-radio" - > - {t('Save (Overwrite)')} - </Radio> - <Radio - id="saveas-radio" - data-test="saveas-radio" - checked={this.state.action === 'saveas'} - onChange={() => this.changeAction('saveas')} - > - {t('Save as...')} - </Radio> - </FormItem> - <hr /> - <FormItem label={t('Chart name')} required> - <Input - name="new_slice_name" - type="text" - placeholder="Name" - value={this.state.newSliceName} - onChange={this.onSliceNameChange} - data-test="new-chart-name" - /> - </FormItem> - <FormItem - label={t('Add to dashboard')} - data-test="save-chart-modal-select-dashboard-form" + {this.state.isLoading ? ( + <div + css={css` + display: flex; + justify-content: center; + `} > - <Select - allowClear - allowNewOptions - ariaLabel={t('Select a dashboard')} - options={this.props.dashboards} - onChange={this.onDashboardSelectChange} - value={dashboardSelectValue || undefined} - placeholder={ - <div> - <b>{t('Select')}</b> - {t(' a dashboard OR ')} - <b>{t('create')}</b> - {t(' a new one')} - </div> - } - /> - </FormItem> - </Form> + <Loading position="normal" /> + </div> + ) : ( + this.renderSaveChartModal() + )} </StyledModal> ); } } +interface StateProps { + datasource: any; + slice: any; + userId: any; + dashboards: any; + alert: any; + isVisible: boolean; +} + function mapStateToProps({ explore, saveModal, -}: Record<string, any>): Partial<SaveModalProps> { + user, +}: Record<string, any>): StateProps { return { datasource: explore.datasource, slice: explore.slice, - userId: explore.user?.userId, + userId: user?.userId, dashboards: saveModal.dashboards, alert: saveModal.saveModalAlert, + isVisible: saveModal.isVisible, }; } -export default connect(mapStateToProps, () => ({}))(SaveModal); +export default withRouter(connect(mapStateToProps)(SaveModal)); diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx index 8df36c1291ac8..c444e027d9b2b 100644 --- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx +++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx @@ -28,6 +28,7 @@ import { validateNonEmpty, isValidExpression, styled, + getColumnLabel, withTheme, } from '@superset-ui/core'; @@ -115,7 +116,7 @@ const NotFoundContent = () => ( <span> {t('Add an annotation layer')}{' '} <a - href="/annotationlayermodelview/list" + href="/annotationlayer/list" target="_blank" rel="noopener noreferrer" > @@ -300,7 +301,7 @@ class AnnotationLayer extends React.PureComponent { if (isLoadingOptions) { if (sourceType === ANNOTATION_SOURCE_TYPES.NATIVE) { SupersetClient.get({ - endpoint: '/annotationlayermodelview/api/read?', + endpoint: '/api/v1/annotation_layer/', }).then(({ json }) => { const layers = json ? json.result.map(layer => ({ @@ -326,7 +327,19 @@ class AnnotationLayer extends React.PureComponent { metadata && metadata.canBeAnnotationType(annotationType) ); }) - .map(x => ({ value: x.id, label: x.title, slice: x })), + .map(x => ({ + value: x.id, + label: x.title, + slice: { + ...x, + data: { + ...x.data, + groupby: x.data.groupby?.map(column => + getColumnLabel(column), + ), + }, + }, + })), }); }, ); @@ -413,8 +426,8 @@ class AnnotationLayer extends React.PureComponent { let description = ''; if (requiresQuery(sourceType)) { if (sourceType === ANNOTATION_SOURCE_TYPES.NATIVE) { - label = 'Annotation layer'; - description = 'Select the Annotation Layer you would like to use.'; + label = t('Annotation layer'); + description = t('Select the Annotation Layer you would like to use.'); } else { label = t('Chart'); description = t( @@ -426,10 +439,10 @@ class AnnotationLayer extends React.PureComponent { ); } } else if (annotationType === ANNOTATION_TYPES.FORMULA) { - label = 'Formula'; - description = `Expects a formula with depending time parameter 'x' + label = t('Formula'); + description = t(`Expects a formula with depending time parameter 'x' in milliseconds since epoch. mathjs is used to evaluate the formulas. - Example: '2x+5'`; + Example: '2x+5'`); } if (requiresQuery(sourceType)) { return ( @@ -464,7 +477,7 @@ class AnnotationLayer extends React.PureComponent { onChange={this.handleValue} validationErrors={ !this.isValidFormulaAnnotation(value, annotationType) - ? ['Bad formula.'] + ? [t('Bad formula.')] : [] } /> @@ -499,7 +512,7 @@ class AnnotationLayer extends React.PureComponent { isSelected title={t('Annotation Slice Configuration')} info={t(`This section allows you to configure how to use the slice - to generate annotations.`)} + to generate annotations.`)} > {(annotationType === ANNOTATION_TYPES.EVENT || annotationType === ANNOTATION_TYPES.INTERVAL) && ( @@ -543,7 +556,7 @@ class AnnotationLayer extends React.PureComponent { name="annotation-layer-title" label={t('Title Column')} description={t('Pick a title for you annotation.')} - options={[{ value: '', label: 'None' }].concat(columns)} + options={[{ value: '', label: t('None') }].concat(columns)} value={titleColumn} onChange={value => this.setState({ titleColumn: value })} /> @@ -566,9 +579,9 @@ class AnnotationLayer extends React.PureComponent { <CheckboxControl hovered name="annotation-override-time_range" - label="Override time range" - description={`This controls whether the "time_range" field from the current - view should be passed down to the chart containing the annotation data.`} + label={t('Override time range')} + description={t(`This controls whether the "time_range" field from the current + view should be passed down to the chart containing the annotation data.`)} value={'time_range' in overrides} onChange={v => { delete overrides.time_range; @@ -584,9 +597,9 @@ class AnnotationLayer extends React.PureComponent { <CheckboxControl hovered name="annotation-override-timegrain" - label="Override time grain" - description={`This controls whether the time grain field from the current - view should be passed down to the chart containing the annotation data.`} + label={t('Override time grain')} + description={t(`This controls whether the time grain field from the current + view should be passed down to the chart containing the annotation data.`)} value={'time_grain_sqla' in overrides} onChange={v => { delete overrides.time_grain_sqla; @@ -607,9 +620,9 @@ class AnnotationLayer extends React.PureComponent { <TextControl hovered name="annotation-layer-timeshift" - label="Time Shift" - description={`Time delta in natural language - (example: 24 hours, 7 days, 56 weeks, 365 days)`} + label={t('Time Shift')} + description={t(`Time delta in natural language + (example: 24 hours, 7 days, 56 weeks, 365 days)`)} placeholder="" value={overrides.time_shift} onChange={v => @@ -656,10 +669,10 @@ class AnnotationLayer extends React.PureComponent { label={t('Style')} // see '../../../visualizations/nvd3_vis.css' options={[ - { value: 'solid', label: 'Solid' }, - { value: 'dashed', label: 'Dashed' }, - { value: 'longDashed', label: 'Long dashed' }, - { value: 'dotted', label: 'Dotted' }, + { value: 'solid', label: t('Solid') }, + { value: 'dashed', label: t('Dashed') }, + { value: 'longDashed', label: t('Long dashed') }, + { value: 'dotted', label: t('Dotted') }, ]} value={style} clearable={false} @@ -671,7 +684,7 @@ class AnnotationLayer extends React.PureComponent { label={t('Opacity')} // see '../../../visualizations/nvd3_vis.css' options={[ - { value: '', label: 'Solid' }, + { value: '', label: t('Solid') }, { value: 'opacityLow', label: '0.2' }, { value: 'opacityMedium', label: '0.5' }, { value: 'opacityHigh', label: '0.8' }, @@ -693,7 +706,7 @@ class AnnotationLayer extends React.PureComponent { buttonSize="xsmall" onClick={() => this.setState({ color: AUTOMATIC_COLOR })} > - Automatic Color + {t('Automatic Color')} </Button> </div> </div> @@ -708,8 +721,8 @@ class AnnotationLayer extends React.PureComponent { <CheckboxControl hovered name="annotation-layer-show-markers" - label="Show Markers" - description="Shows or hides markers for the time series" + label={t('Show Markers')} + description={t('Shows or hides markers for the time series')} value={showMarkers} onChange={v => this.setState({ showMarkers: v })} /> @@ -718,8 +731,8 @@ class AnnotationLayer extends React.PureComponent { <CheckboxControl hovered name="annotation-layer-hide-line" - label="Hide Line" - description="Hides the Line for the time series" + label={t('Hide Line')} + description={t('Hides the Line for the time series')} value={hideLine} onChange={v => this.setState({ hideLine: v })} /> diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx index ed8ae44339b2e..c5fed0b865f61 100644 --- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx +++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx @@ -36,7 +36,7 @@ beforeAll(() => { value => value.value, ); - fetchMock.get('glob:*/annotationlayermodelview/api/read?*', { + fetchMock.get('glob:*/api/v1/annotation_layer/*', { result: [{ label: 'Chart A', value: 'a' }], }); @@ -78,7 +78,7 @@ test('renders extra checkboxes when type is time series', async () => { userEvent.click(screen.getAllByText('Formula')[0]); userEvent.click(screen.getByText('Time series')); expect( - screen.getByRole('button', { name: 'Show Markers' }), + await screen.findByRole('button', { name: 'Show Markers' }), ).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Hide Line' })).toBeInTheDocument(); }); @@ -86,7 +86,7 @@ test('renders extra checkboxes when type is time series', async () => { test('enables apply and ok buttons', async () => { const { container } = render(<AnnotationLayer {...defaultProps} />); - waitFor(() => { + await waitFor(() => { expect(container).toBeInTheDocument(); }); @@ -99,7 +99,7 @@ test('enables apply and ok buttons', async () => { userEvent.type(nameInput, 'Name'); userEvent.type(formulaInput, '2x'); - waitFor(() => { + await waitFor(() => { expect(screen.getByRole('button', { name: 'Apply' })).toBeEnabled(); expect(screen.getByRole('button', { name: 'OK' })).toBeEnabled(); }); @@ -150,13 +150,13 @@ test('renders chart options', async () => { screen.getByRole('combobox', { name: 'Annotation source type' }), ); userEvent.click(screen.getByText('Superset annotation')); - expect(screen.getByText('Annotation layer')).toBeInTheDocument(); + expect(await screen.findByText('Annotation layer')).toBeInTheDocument(); userEvent.click( screen.getByRole('combobox', { name: 'Annotation source type' }), ); userEvent.click(screen.getByText('Table')); - expect(screen.getByText('Chart')).toBeInTheDocument(); + expect(await screen.findByText('Chart')).toBeInTheDocument(); }); test('keeps apply disabled when missing required fields', async () => { @@ -167,25 +167,26 @@ test('keeps apply disabled when missing required fields', async () => { userEvent.click( screen.getByRole('combobox', { name: 'Annotation layer value' }), ); - userEvent.click(await screen.findByText('Chart A')); - expect( - screen.getByText('Annotation Slice Configuration'), - ).toBeInTheDocument(); + expect(await screen.findByText('Chart A')).toBeInTheDocument(); + userEvent.click(screen.getByText('Chart A')); userEvent.click(screen.getByRole('button', { name: 'Automatic Color' })); userEvent.click( screen.getByRole('combobox', { name: 'Annotation layer title column' }), ); + expect(await screen.findByText(/none/i)).toBeInTheDocument(); userEvent.click(screen.getByText('None')); userEvent.click(screen.getByText('Style')); userEvent.click( screen.getByRole('combobox', { name: 'Annotation layer stroke' }), ); + expect(await screen.findByText('Dashed')).toBeInTheDocument(); userEvent.click(screen.getByText('Dashed')); userEvent.click(screen.getByText('Opacity')); userEvent.click( screen.getByRole('combobox', { name: 'Annotation layer opacity' }), ); + expect(await screen.findByText(/0.5/i)).toBeInTheDocument(); userEvent.click(screen.getByText('0.5')); const checkboxes = screen.getAllByRole('checkbox'); diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx index f1381abee1aa4..f70557170c0d8 100644 --- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx +++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx @@ -26,7 +26,9 @@ import AsyncEsmComponent from 'src/components/AsyncEsmComponent'; import { getChartKey } from 'src/explore/exploreUtils'; import { runAnnotationQuery } from 'src/components/Chart/chartAction'; import CustomListItem from 'src/explore/components/controls/CustomListItem'; -import ControlPopover from '../ControlPopover/ControlPopover'; +import ControlPopover, { + getSectionContainerElement, +} from '../ControlPopover/ControlPopover'; const AnnotationLayer = AsyncEsmComponent( () => import('./AnnotationLayer'), @@ -69,7 +71,7 @@ class AnnotationLayerControl extends React.PureComponent { } componentDidMount() { - // preload the AnotationLayer component and dependent libraries i.e. mathjs + // preload the AnnotationLayer component and dependent libraries i.e. mathjs AnnotationLayer.preload(); } @@ -114,6 +116,11 @@ class AnnotationLayerControl extends React.PureComponent { removeAnnotationLayer(annotation) { const annotations = this.props.value.filter(anno => anno !== annotation); + // So scrollbar doesnt get stuck on hidden + const element = getSectionContainerElement(); + if (element) { + element.style.setProperty('overflow-y', 'auto', 'important'); + } this.props.onChange(annotations); } diff --git a/superset-frontend/src/explore/components/controls/CollectionControl/CollectionControl.test.tsx b/superset-frontend/src/explore/components/controls/CollectionControl/CollectionControl.test.tsx index 53d57030c9466..00ece2306901a 100644 --- a/superset-frontend/src/explore/components/controls/CollectionControl/CollectionControl.test.tsx +++ b/superset-frontend/src/explore/components/controls/CollectionControl/CollectionControl.test.tsx @@ -85,49 +85,58 @@ const createProps = () => ({ value: [{ key: 'hrYAZ5iBH' }], }); -test('Should render', () => { +test('Should render', async () => { const props = createProps(); render(<CollectionControl {...props} />); - expect(screen.getByTestId('CollectionControl')).toBeInTheDocument(); + expect(await screen.findByTestId('CollectionControl')).toBeInTheDocument(); }); -test('Should show the button with the label', () => { +test('Should show the button with the label', async () => { const props = createProps(); render(<CollectionControl {...props} />); - expect(screen.getByRole('button', { name: props.label })).toBeInTheDocument(); + expect( + await screen.findByRole('button', { name: props.label }), + ).toBeInTheDocument(); expect(screen.getByRole('button', { name: props.label })).toHaveTextContent( props.label, ); }); -test('Should have add button', () => { +test('Should have add button', async () => { const props = createProps(); render(<CollectionControl {...props} />); + expect( + await screen.findByRole('button', { name: 'plus-large' }), + ).toBeInTheDocument(); expect(props.onChange).toBeCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'plus-large' })); expect(props.onChange).toBeCalledWith([{ key: 'hrYAZ5iBH' }, undefined]); }); -test('Should have remove button', () => { +test('Should have remove button', async () => { const props = createProps(); render(<CollectionControl {...props} />); + expect( + await screen.findByRole('button', { name: 'remove-item' }), + ).toBeInTheDocument(); expect(props.onChange).toBeCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'remove-item' })); expect(props.onChange).toBeCalledWith([]); }); -test('Should have SortableDragger icon', () => { +test('Should have SortableDragger icon', async () => { const props = createProps(); render(<CollectionControl {...props} />); - expect(screen.getByLabelText('drag')).toBeVisible(); + expect(await screen.findByLabelText('drag')).toBeVisible(); }); -test('Should call Control component', () => { +test('Should call Control component', async () => { const props = createProps(); render(<CollectionControl {...props} />); + expect(await screen.findByTestId('TestControl')).toBeInTheDocument(); expect(props.onChange).toBeCalledTimes(0); userEvent.click(screen.getByTestId('TestControl')); expect(props.onChange).toBeCalledWith([{ key: 'hrYAZ5iBH' }]); diff --git a/superset-frontend/src/explore/components/controls/ColorPickerControl.jsx b/superset-frontend/src/explore/components/controls/ColorPickerControl.jsx index d0337dcc3eabb..3b887357924b3 100644 --- a/superset-frontend/src/explore/components/controls/ColorPickerControl.jsx +++ b/superset-frontend/src/explore/components/controls/ColorPickerControl.jsx @@ -59,7 +59,7 @@ const styles = { ...swatchCommon, borderRadius: '2px', }, - checkboard: { + checkerboard: { ...swatchCommon, background: 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==") left center', @@ -105,7 +105,7 @@ export default class ColorPickerControl extends React.Component { content={this.renderPopover()} > <StyledSwatch> - <div style={styles.checkboard} /> + <div style={styles.checkerboard} /> <div style={colStyle} /> </StyledSwatch> </Popover> diff --git a/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeControl.test.tsx b/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeControl.test.tsx index 1f19d8a2c3a89..9e760aab13166 100644 --- a/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeControl.test.tsx +++ b/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeControl.test.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; import { render, screen, waitFor } from 'spec/helpers/testing-library'; -import ColorSchemeControl from '.'; +import ColorSchemeControl, { ColorSchemes } from '.'; const defaultProps = { hasCustomLabelColors: false, @@ -28,7 +28,7 @@ const defaultProps = { value: 'supersetDefault', clearable: true, choices: [], - schemes: () => null, + schemes: () => ({} as ColorSchemes), isLinear: false, }; diff --git a/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.test.tsx b/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.test.tsx new file mode 100644 index 0000000000000..e3117d2f77cee --- /dev/null +++ b/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.test.tsx @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import ColorSchemeLabel from './ColorSchemeLabel'; + +const defaultProps = { + colors: [ + '#000000', + '#FFFFFF', + '#CCCCCC', + '#000000', + '#FFFFFF', + '#CCCCCC', + '#000000', + '#FFFFFF', + '#CCCCCC', + '#000000', + '#FFFFFF', + '#CCCCCC', + ], + label: 'Superset Colors', + id: 'colorScheme', +}; + +const setup = (overrides?: Record<string, any>) => + render(<ColorSchemeLabel {...defaultProps} {...overrides} />); + +test('should render', async () => { + const { container } = setup(); + await waitFor(() => expect(container).toBeVisible()); +}); + +test('should render the label', () => { + setup(); + expect(screen.getByText('Superset Colors')).toBeInTheDocument(); +}); + +test('should render the colors', () => { + setup(); + const allColors = screen.getAllByTestId('color'); + expect(allColors).toHaveLength(12); +}); diff --git a/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.tsx b/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.tsx new file mode 100644 index 0000000000000..cd046eb1fd90e --- /dev/null +++ b/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.tsx @@ -0,0 +1,126 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { css, SupersetTheme } from '@superset-ui/core'; +import React, { useRef, useState } from 'react'; +import { Tooltip } from 'src/components/Tooltip'; + +type ColorSchemeLabelProps = { + colors: string[]; + id: string; + label: string; +}; + +export default function ColorSchemeLabel(props: ColorSchemeLabelProps) { + const { id, label, colors } = props; + const [showTooltip, setShowTooltip] = useState<boolean>(false); + const labelNameRef = useRef<HTMLElement>(null); + const labelColorsRef = useRef<HTMLElement>(null); + const handleShowTooltip = () => { + const labelNameElement = labelNameRef.current; + const labelColorsElement = labelColorsRef.current; + if ( + labelNameElement && + labelColorsElement && + (labelNameElement.scrollWidth > labelNameElement.offsetWidth || + labelNameElement.scrollHeight > labelNameElement.offsetHeight || + labelColorsElement.scrollWidth > labelColorsElement.offsetWidth || + labelColorsElement.scrollHeight > labelColorsElement.offsetHeight) + ) { + setShowTooltip(true); + } + }; + const handleHideTooltip = () => { + setShowTooltip(false); + }; + + const colorsList = () => + colors.map((color: string, i: number) => ( + <span + data-test="color" + key={`${id}-${i}`} + css={(theme: { gridUnit: number }) => css` + padding-left: ${theme.gridUnit / 2}px; + :before { + content: ''; + display: inline-block; + background-color: ${color}; + border: 1px solid ${color === 'white' ? 'black' : color}; + width: 9px; + height: 10px; + } + `} + /> + )); + + const tooltipContent = () => ( + <> + <span>{label}</span> + <div>{colorsList()}</div> + </> + ); + + return ( + <Tooltip + data-testid="tooltip" + overlayClassName="color-scheme-tooltip" + title={tooltipContent} + key={id} + visible={showTooltip} + > + <span + className="color-scheme-option" + onMouseEnter={handleShowTooltip} + onMouseLeave={handleHideTooltip} + css={css` + display: flex; + align-items: center; + justify-content: flex-start; + `} + data-test={id} + > + <span + className="color-scheme-label" + ref={labelNameRef} + css={(theme: SupersetTheme) => css` + min-width: 125px; + padding-right: ${theme.gridUnit * 2}px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + `} + > + {label} + </span> + <span + ref={labelColorsRef} + css={(theme: SupersetTheme) => css` + flex: 100%; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + padding-right: ${theme.gridUnit}px; + `} + > + {colorsList()} + </span> + </span> + </Tooltip> + ); +} diff --git a/superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx b/superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx deleted file mode 100644 index f0ccc1239814f..0000000000000 --- a/superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import PropTypes from 'prop-types'; -import { isFunction } from 'lodash'; -import { Select } from 'src/components'; -import { Tooltip } from 'src/components/Tooltip'; -import { styled, t } from '@superset-ui/core'; -import Icons from 'src/components/Icons'; -import ControlHeader from 'src/explore/components/ControlHeader'; - -const propTypes = { - hasCustomLabelColors: PropTypes.bool, - dashboardId: PropTypes.number, - description: PropTypes.string, - label: PropTypes.string, - labelMargin: PropTypes.number, - name: PropTypes.string.isRequired, - onChange: PropTypes.func, - value: PropTypes.string, - clearable: PropTypes.bool, - default: PropTypes.string, - choices: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.array), - PropTypes.func, - ]), - schemes: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), - isLinear: PropTypes.bool, -}; - -const defaultProps = { - choices: [], - hasCustomLabelColors: false, - label: t('Color scheme'), - schemes: {}, - clearable: false, - onChange: () => {}, -}; - -const StyledAlert = styled(Icons.AlertSolid)` - color: ${({ theme }) => theme.colors.alert.base}; -`; - -export default class ColorSchemeControl extends React.PureComponent { - constructor(props) { - super(props); - this.onChange = this.onChange.bind(this); - this.renderOption = this.renderOption.bind(this); - this.renderLabel = this.renderLabel.bind(this); - this.dashboardColorSchemeAlert = t( - `The color scheme is determined by the related dashboard. - Edit the color scheme in the dashboard properties.`, - ); - } - - onChange(value) { - this.props.onChange(value); - } - - renderOption(value) { - const { isLinear } = this.props; - const currentScheme = this.schemes[value]; - - // For categorical scheme, display all the colors - // For sequential scheme, show 10 or interpolate to 10. - // Sequential schemes usually have at most 10 colors. - let colors = []; - if (currentScheme) { - colors = isLinear ? currentScheme.getColors(10) : currentScheme.colors; - } - - return ( - <span key={currentScheme.id} title={currentScheme.label}> - <ul - css={{ - listStyle: 'none', - margin: 0, - padding: 0, - display: 'flex', - alignItems: 'center', - - '& li': { - flexBasis: 9, - height: 10, - margin: '9px 1px', - }, - }} - data-test={currentScheme.id} - > - {colors.map((color, i) => ( - <li - key={`${currentScheme.id}-${i}`} - css={{ - backgroundColor: color, - border: `1px solid ${color === 'white' ? 'black' : color}`, - }} - > -   - </li> - ))} - </ul> - </span> - ); - } - - renderLabel() { - const { dashboardId, hasCustomLabelColors, label } = this.props; - - if (hasCustomLabelColors || dashboardId) { - const alertTitle = hasCustomLabelColors - ? t( - `This color scheme is being overriden by custom label colors. - Check the JSON metadata in the Advanced settings`, - ) - : this.dashboardColorSchemeAlert; - return ( - <> - {label}{' '} - <Tooltip title={alertTitle}> - <StyledAlert iconSize="s" /> - </Tooltip> - </> - ); - } - return label; - } - - render() { - const { choices, dashboardId, schemes } = this.props; - let options = dashboardId - ? [ - { - value: 'dashboard', - label: 'dashboard', - customLabel: ( - <Tooltip title={this.dashboardColorSchemeAlert}> - {t('Dashboard scheme')} - </Tooltip> - ), - }, - ] - : []; - let currentScheme = dashboardId ? 'dashboard' : undefined; - - // if related to a dashboard the scheme is dictated by the dashboard - if (!dashboardId) { - this.schemes = isFunction(schemes) ? schemes() : schemes; - const controlChoices = isFunction(choices) ? choices() : choices; - const allColorOptions = []; - const filteredColorOptions = controlChoices.filter(o => { - const option = o[0]; - const isValidColorOption = - option !== 'SUPERSET_DEFAULT' && !allColorOptions.includes(option); - allColorOptions.push(option); - return isValidColorOption; - }); - - options = filteredColorOptions.map(([value]) => ({ - customLabel: this.renderOption(value), - label: this.schemes?.[value]?.label || value, - value, - })); - - currentScheme = this.props.value || this.props.default; - - if (currentScheme === 'SUPERSET_DEFAULT') { - currentScheme = this.schemes?.SUPERSET_DEFAULT?.id; - } - } - - const selectProps = { - ariaLabel: t('Select color scheme'), - allowClear: this.props.clearable, - disabled: !!dashboardId, - name: `select-${this.props.name}`, - onChange: this.onChange, - options, - placeholder: t('Select scheme'), - value: currentScheme, - }; - - return ( - <Select - header={<ControlHeader {...this.props} label={this.renderLabel()} />} - {...selectProps} - /> - ); - } -} - -ColorSchemeControl.propTypes = propTypes; -ColorSchemeControl.defaultProps = defaultProps; diff --git a/superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx b/superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx new file mode 100644 index 0000000000000..2faa08d8eea2a --- /dev/null +++ b/superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx @@ -0,0 +1,189 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useMemo } from 'react'; +import { ColorScheme, SequentialScheme, styled, t } from '@superset-ui/core'; +import { isFunction } from 'lodash'; +import { Select } from 'src/components'; +import ControlHeader from 'src/explore/components/ControlHeader'; +import { Tooltip } from 'src/components/Tooltip'; +import Icons from 'src/components/Icons'; +import ColorSchemeLabel from './ColorSchemeLabel'; + +export interface ColorSchemes { + [key: string]: ColorScheme; +} + +export interface ColorSchemeControlProps { + hasCustomLabelColors: boolean; + dashboardId?: number; + label: string; + name: string; + onChange?: (value: string) => void; + value: string; + clearable: boolean; + defaultScheme?: string; + choices: string[][] | (() => string[][]); + schemes: ColorSchemes | (() => ColorSchemes); + isLinear: boolean; +} + +const StyledAlert = styled(Icons.AlertSolid)` + color: ${({ theme }) => theme.colors.alert.base}; +`; + +const CUSTOM_LABEL_ALERT = t( + `This color scheme is being overridden by custom label colors. + Check the JSON metadata in the Advanced settings`, +); + +const DASHBOARD_ALERT = t( + `The color scheme is determined by the related dashboard. + Edit the color scheme in the dashboard properties.`, +); + +const Label = ({ + label, + hasCustomLabelColors, + dashboardId, +}: Pick< + ColorSchemeControlProps, + 'label' | 'hasCustomLabelColors' | 'dashboardId' +>) => { + if (hasCustomLabelColors || dashboardId) { + const alertTitle = hasCustomLabelColors + ? CUSTOM_LABEL_ALERT + : DASHBOARD_ALERT; + return ( + <> + {label}{' '} + <Tooltip title={alertTitle}> + <StyledAlert iconSize="s" /> + </Tooltip> + </> + ); + } + return <>{label}</>; +}; + +const ColorSchemeControl = ({ + hasCustomLabelColors = false, + dashboardId, + label = t('Color scheme'), + name, + onChange = () => {}, + value, + clearable = false, + defaultScheme, + choices = [], + schemes = {}, + isLinear, + ...rest +}: ColorSchemeControlProps) => { + const currentScheme = useMemo(() => { + if (dashboardId) { + return 'dashboard'; + } + let result = value || defaultScheme; + if (result === 'SUPERSET_DEFAULT') { + const schemesObject = isFunction(schemes) ? schemes() : schemes; + result = schemesObject?.SUPERSET_DEFAULT?.id; + } + return result; + }, [dashboardId, defaultScheme, schemes, value]); + + const options = useMemo(() => { + if (dashboardId) { + return [ + { + value: 'dashboard', + label: t('dashboard'), + customLabel: ( + <Tooltip title={DASHBOARD_ALERT}>{t('Dashboard scheme')}</Tooltip> + ), + }, + ]; + } + const schemesObject = isFunction(schemes) ? schemes() : schemes; + const controlChoices = isFunction(choices) ? choices() : choices; + const allColorOptions: string[] = []; + const filteredColorOptions = controlChoices.filter(o => { + const option = o[0]; + const isValidColorOption = + option !== 'SUPERSET_DEFAULT' && !allColorOptions.includes(option); + allColorOptions.push(option); + return isValidColorOption; + }); + + return filteredColorOptions.map(([value]) => { + const currentScheme = schemesObject[value]; + + // For categorical scheme, display all the colors + // For sequential scheme, show 10 or interpolate to 10. + // Sequential schemes usually have at most 10 colors. + let colors: string[] = []; + if (currentScheme) { + colors = isLinear + ? (currentScheme as SequentialScheme).getColors(10) + : currentScheme.colors; + } + return { + customLabel: ( + <ColorSchemeLabel + id={currentScheme.id} + label={currentScheme.label} + colors={colors} + /> + ), + label: schemesObject?.[value]?.label || value, + value, + }; + }); + }, [choices, dashboardId, isLinear, schemes]); + + // We can't pass on change directly because it receives a second + // parameter and it would be interpreted as the error parameter + const handleOnChange = (value: string) => onChange(value); + + return ( + <Select + header={ + <ControlHeader + {...rest} + label={ + <Label + label={label} + hasCustomLabelColors={hasCustomLabelColors} + dashboardId={dashboardId} + /> + } + /> + } + ariaLabel={t('Select color scheme')} + allowClear={clearable} + disabled={!!dashboardId} + name={`select-${name}`} + onChange={handleOnChange} + options={options} + placeholder={t('Select scheme')} + value={currentScheme} + /> + ); +}; + +export default ColorSchemeControl; diff --git a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx index b32ca5f216399..d50e71608ba10 100644 --- a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx +++ b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx @@ -45,7 +45,7 @@ const colorSchemeOptions = (theme: SupersetTheme) => [ ]; const operatorOptions = [ - { value: COMPARATOR.NONE, label: 'None' }, + { value: COMPARATOR.NONE, label: t('None') }, { value: COMPARATOR.GREATER_THAN, label: '>' }, { value: COMPARATOR.LESS_THAN, label: '<' }, { value: COMPARATOR.GREATER_OR_EQUAL, label: '≥' }, diff --git a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx index f84194c43caaa..55391c04c9a57 100644 --- a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx +++ b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx @@ -24,12 +24,12 @@ import Popover, { } from 'src/components/Popover'; const sectionContainerId = 'controlSections'; -const getSectionContainerElement = () => +export const getSectionContainerElement = () => document.getElementById(sectionContainerId)?.lastElementChild as HTMLElement; const getElementYVisibilityRatioOnContainer = (node: HTMLElement) => { const containerHeight = window?.innerHeight; - const nodePositionInViewport = node.getBoundingClientRect()?.top; + const nodePositionInViewport = node?.getBoundingClientRect()?.top; if (!containerHeight || !nodePositionInViewport) { return 0; } @@ -45,6 +45,7 @@ const ControlPopover: React.FC<PopoverProps> = ({ getPopupContainer, getVisibilityRatio = getElementYVisibilityRatioOnContainer, visible: visibleProp, + destroyTooltipOnHide = false, ...props }) => { const triggerElementRef = useRef<HTMLElement>(); @@ -56,10 +57,9 @@ const ControlPopover: React.FC<PopoverProps> = ({ const calculatePlacement = useCallback(() => { const visibilityRatio = getVisibilityRatio(triggerElementRef.current!); - - if (visibilityRatio < 0.35) { + if (visibilityRatio < 0.35 && placement !== 'rightTop') { setPlacement('rightTop'); - } else if (visibilityRatio > 0.65) { + } else if (visibilityRatio > 0.65 && placement !== 'rightBottom') { setPlacement('rightBottom'); } else { setPlacement('right'); @@ -68,10 +68,6 @@ const ControlPopover: React.FC<PopoverProps> = ({ const changeContainerScrollStatus = useCallback( visible => { - if (triggerElementRef.current && visible) { - calculatePlacement(); - } - const element = getSectionContainerElement(); if (element) { element.style.setProperty( @@ -87,9 +83,6 @@ const ControlPopover: React.FC<PopoverProps> = ({ const handleGetPopupContainer = useCallback( (triggerNode: HTMLElement) => { triggerElementRef.current = triggerNode; - setTimeout(() => { - calculatePlacement(); - }, 0); return getPopupContainer?.(triggerNode) || document.body; }, @@ -140,6 +133,12 @@ const ControlPopover: React.FC<PopoverProps> = ({ }; }, [handleDocumentKeyDownListener, visible]); + useEffect(() => { + if (visible) { + calculatePlacement(); + } + }, [visible, calculatePlacement]); + return ( <Popover {...props} @@ -148,6 +147,7 @@ const ControlPopover: React.FC<PopoverProps> = ({ placement={placement} onVisibleChange={handleOnVisibleChange} getPopupContainer={handleGetPopupContainer} + destroyTooltipOnHide={destroyTooltipOnHide} /> ); }; diff --git a/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.jsx b/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.jsx index 41a40c0bc4422..a4e9c100ee0f9 100644 --- a/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.jsx +++ b/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.jsx @@ -20,13 +20,19 @@ import React from 'react'; import sinon from 'sinon'; import configureStore from 'redux-mock-store'; import { mount, shallow } from 'enzyme'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { + supersetTheme, + ThemeProvider, + DatasourceType, +} from '@superset-ui/core'; import { Menu } from 'src/components/Menu'; import { DatasourceModal, ChangeDatasourceModal, } from 'src/components/Datasource'; -import DatasourceControl from 'src/explore/components/controls/DatasourceControl'; +import DatasourceControl, { + getDatasourceTitle, +} from 'src/explore/components/controls/DatasourceControl'; import Icons from 'src/components/Icons'; import { Tooltip } from 'src/components/Tooltip'; @@ -110,29 +116,6 @@ describe('DatasourceControl', () => { </div>, ); expect(menuWrapper.find(Menu.Item)).toHaveLength(2); - - wrapper = setup({ - datasource: { - name: 'birth_names', - type: 'druid', - uid: '1__druid', - id: 1, - columns: [], - metrics: [], - owners: [{ username: 'admin', userId: 1 }], - database: { - backend: 'druid', - name: 'main', - }, - }, - }); - expect(wrapper.find('[data-test="datasource-menu"]')).toExist(); - menuWrapper = shallow( - <div> - {wrapper.find('[data-test="datasource-menu"]').first().prop('overlay')} - </div>, - ); - expect(menuWrapper.find(Menu.Item)).toHaveLength(2); }); it('should render health check message', () => { @@ -143,4 +126,30 @@ describe('DatasourceControl', () => { defaultProps.datasource.health_check_message, ); }); + + it('Gets Datasource Title', () => { + const sql = 'This is the sql'; + const name = 'this is a name'; + const emptyResult = ''; + const queryDatasource1 = { type: DatasourceType.Query, sql }; + let displayText = getDatasourceTitle(queryDatasource1); + expect(displayText).toBe(sql); + const queryDatasource2 = { type: DatasourceType.Query, sql: null }; + displayText = getDatasourceTitle(queryDatasource2); + expect(displayText).toBe(null); + const queryDatasource3 = { type: 'random type', name }; + displayText = getDatasourceTitle(queryDatasource3); + expect(displayText).toBe(name); + const queryDatasource4 = { type: 'random type' }; + displayText = getDatasourceTitle(queryDatasource4); + expect(displayText).toBe(emptyResult); + displayText = getDatasourceTitle(); + expect(displayText).toBe(emptyResult); + displayText = getDatasourceTitle(null); + expect(displayText).toBe(emptyResult); + displayText = getDatasourceTitle('I should not be a string'); + expect(displayText).toBe(emptyResult); + displayText = getDatasourceTitle([]); + expect(displayText).toBe(emptyResult); + }); }); diff --git a/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.tsx b/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.tsx index 8a65a1139df9c..2c094e72afba0 100644 --- a/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.tsx +++ b/superset-frontend/src/explore/components/controls/DatasourceControl/DatasourceControl.test.tsx @@ -18,14 +18,16 @@ */ import React from 'react'; -import { render, screen, act } from 'spec/helpers/testing-library'; +import fetchMock from 'fetch-mock'; import userEvent from '@testing-library/user-event'; -import { SupersetClient, DatasourceType } from '@superset-ui/core'; +import { DatasourceType, JsonObject, SupersetClient } from '@superset-ui/core'; +import { render, screen, act, waitFor } from 'spec/helpers/testing-library'; +import { fallbackExploreInitialData } from 'src/explore/fixtures'; import DatasourceControl from '.'; const SupersetClientGet = jest.spyOn(SupersetClient, 'get'); -const createProps = () => ({ +const createProps = (overrides: JsonObject = {}) => ({ hovered: false, type: 'DatasourceControl', label: 'Datasource', @@ -45,7 +47,10 @@ const createProps = () => ({ }, validationErrors: [], name: 'datasource', - actions: {}, + actions: { + changeDatasource: jest.fn(), + setControlValue: jest.fn(), + }, isEditable: true, user: { createdOn: '2021-04-27T18:12:38.952304', @@ -60,37 +65,94 @@ const createProps = () => ({ }, onChange: jest.fn(), onDatasourceSave: jest.fn(), + ...overrides, }); -test('Should render', () => { +async function openAndSaveChanges(datasource: any) { + fetchMock.post('glob:*/datasource/save/', datasource, { + overwriteRoutes: true, + }); + userEvent.click(screen.getByTestId('datasource-menu-trigger')); + userEvent.click(await screen.findByTestId('edit-dataset')); + userEvent.click(await screen.findByTestId('datasource-modal-save')); + userEvent.click(await screen.findByText('OK')); +} + +test('Should render', async () => { const props = createProps(); render(<DatasourceControl {...props} />); - expect(screen.getByTestId('datasource-control')).toBeVisible(); + expect(await screen.findByTestId('datasource-control')).toBeVisible(); }); -test('Should have elements', () => { +test('Should have elements', async () => { const props = createProps(); render(<DatasourceControl {...props} />); - expect(screen.getByText('channels')).toBeVisible(); + expect(await screen.findByText('channels')).toBeVisible(); expect(screen.getByTestId('datasource-menu-trigger')).toBeVisible(); }); -test('Should open a menu', () => { +test('Should open a menu', async () => { const props = createProps(); render(<DatasourceControl {...props} />); expect(screen.queryByText('Edit dataset')).not.toBeInTheDocument(); - expect(screen.queryByText('Change dataset')).not.toBeInTheDocument(); + expect(screen.queryByText('Swap dataset')).not.toBeInTheDocument(); + expect(screen.queryByText('View in SQL Lab')).not.toBeInTheDocument(); + + userEvent.click(screen.getByTestId('datasource-menu-trigger')); + + expect(await screen.findByText('Edit dataset')).toBeInTheDocument(); + expect(screen.getByText('Swap dataset')).toBeInTheDocument(); + expect(screen.getByText('View in SQL Lab')).toBeInTheDocument(); +}); + +test('Should not show SQL Lab for non sql_lab role', async () => { + const props = createProps({ + user: { + createdOn: '2021-04-27T18:12:38.952304', + email: 'gamma', + firstName: 'gamma', + isActive: true, + lastName: 'gamma', + permissions: {}, + roles: { Gamma: [] }, + userId: 2, + username: 'gamma', + }, + }); + render(<DatasourceControl {...props} />); + + userEvent.click(screen.getByTestId('datasource-menu-trigger')); + + expect(await screen.findByText('Edit dataset')).toBeInTheDocument(); + expect(screen.getByText('Swap dataset')).toBeInTheDocument(); expect(screen.queryByText('View in SQL Lab')).not.toBeInTheDocument(); +}); + +test('Should show SQL Lab for sql_lab role', async () => { + const props = createProps({ + user: { + createdOn: '2021-04-27T18:12:38.952304', + email: 'sql', + firstName: 'sql', + isActive: true, + lastName: 'sql', + permissions: {}, + roles: { Gamma: [], sql_lab: [] }, + userId: 2, + username: 'sql', + }, + }); + render(<DatasourceControl {...props} />); userEvent.click(screen.getByTestId('datasource-menu-trigger')); - expect(screen.getByText('Edit dataset')).toBeInTheDocument(); - expect(screen.getByText('Change dataset')).toBeInTheDocument(); + expect(await screen.findByText('Edit dataset')).toBeInTheDocument(); + expect(screen.getByText('Swap dataset')).toBeInTheDocument(); expect(screen.getByText('View in SQL Lab')).toBeInTheDocument(); }); -test('Click on Change dataset option', async () => { +test('Click on Swap dataset option', async () => { const props = createProps(); SupersetClientGet.mockImplementation( async ({ endpoint }: { endpoint: string }) => { @@ -109,7 +171,7 @@ test('Click on Change dataset option', async () => { userEvent.click(screen.getByTestId('datasource-menu-trigger')); await act(async () => { - userEvent.click(screen.getByText('Change dataset')); + userEvent.click(screen.getByText('Swap dataset')); }); expect( screen.getByText( @@ -139,6 +201,27 @@ test('Click on Edit dataset', async () => { ).toBeInTheDocument(); }); +test('Edit dataset should be disabled when user is not admin', async () => { + const props = createProps(); + // @ts-expect-error + props.user.roles = {}; + props.datasource.owners = []; + SupersetClientGet.mockImplementation( + async () => ({ json: { result: [] } } as any), + ); + + render(<DatasourceControl {...props} />, { + useRedux: true, + }); + + userEvent.click(screen.getByTestId('datasource-menu-trigger')); + + expect(await screen.findByTestId('edit-dataset')).toHaveAttribute( + 'aria-disabled', + 'true', + ); +}); + test('Click on View in SQL Lab', async () => { const props = createProps(); const postFormSpy = jest.spyOn(SupersetClient, 'postForm'); @@ -158,7 +241,7 @@ test('Click on View in SQL Lab', async () => { expect(postFormSpy).toBeCalledTimes(1); }); -test('Should open a different menu when datasource=query', () => { +test('Should open a different menu when datasource=query', async () => { const props = createProps(); const queryProps = { ...props, @@ -175,12 +258,12 @@ test('Should open a different menu when datasource=query', () => { userEvent.click(screen.getByTestId('datasource-menu-trigger')); - expect(screen.getByText('Query preview')).toBeInTheDocument(); + expect(await screen.findByText('Query preview')).toBeInTheDocument(); expect(screen.getByText('View in SQL Lab')).toBeInTheDocument(); expect(screen.getByText('Save as dataset')).toBeInTheDocument(); }); -test('Click on Save as dataset', () => { +test('Click on Save as dataset', async () => { const props = createProps(); const queryProps = { ...props, @@ -195,14 +278,148 @@ test('Click on Save as dataset', () => { userEvent.click(screen.getByText('Save as dataset')); // Renders a save dataset modal - const saveRadioBtn = screen.getByRole('radio', { - name: /save as new undefined/i, + const saveRadioBtn = await screen.findByRole('radio', { + name: /save as new/i, }); const overwriteRadioBtn = screen.getByRole('radio', { - name: /overwrite existing select or type dataset name/i, + name: /overwrite existing/i, }); + const dropdownField = screen.getByText(/select or type dataset name/i); expect(saveRadioBtn).toBeVisible(); expect(overwriteRadioBtn).toBeVisible(); expect(screen.getByRole('button', { name: /save/i })).toBeVisible(); expect(screen.getByRole('button', { name: /close/i })).toBeVisible(); + expect(dropdownField).toBeVisible(); +}); + +test('should set the default temporal column', async () => { + const props = createProps(); + const overrideProps = { + ...props, + form_data: { + granularity_sqla: 'test-col', + }, + datasource: { + ...props.datasource, + main_dttm_col: 'test-default', + columns: [ + { + column_name: 'test-col', + is_dttm: false, + }, + { + column_name: 'test-default', + is_dttm: true, + }, + ], + }, + }; + render(<DatasourceControl {...props} {...overrideProps} />, { + useRedux: true, + }); + + await openAndSaveChanges(overrideProps.datasource); + await waitFor(() => { + expect(props.actions.setControlValue).toHaveBeenCalledWith( + 'granularity_sqla', + 'test-default', + ); + }); +}); + +test('should set the first available temporal column', async () => { + const props = createProps(); + const overrideProps = { + ...props, + form_data: { + granularity_sqla: 'test-col', + }, + datasource: { + ...props.datasource, + main_dttm_col: null, + columns: [ + { + column_name: 'test-col', + is_dttm: false, + }, + { + column_name: 'test-first', + is_dttm: true, + }, + ], + }, + }; + render(<DatasourceControl {...props} {...overrideProps} />, { + useRedux: true, + }); + + await openAndSaveChanges(overrideProps.datasource); + await waitFor(() => { + expect(props.actions.setControlValue).toHaveBeenCalledWith( + 'granularity_sqla', + 'test-first', + ); + }); +}); + +test('should not set the temporal column', async () => { + const props = createProps(); + const overrideProps = { + ...props, + form_data: { + granularity_sqla: null, + }, + datasource: { + ...props.datasource, + main_dttm_col: null, + columns: [ + { + column_name: 'test-col', + is_dttm: false, + }, + { + column_name: 'test-col-2', + is_dttm: false, + }, + ], + }, + }; + render(<DatasourceControl {...props} {...overrideProps} />, { + useRedux: true, + }); + + await openAndSaveChanges(overrideProps.datasource); + await waitFor(() => { + expect(props.actions.setControlValue).toHaveBeenCalledWith( + 'granularity_sqla', + null, + ); + }); +}); + +test('should show missing params state', () => { + const props = createProps({ datasource: fallbackExploreInitialData.dataset }); + render(<DatasourceControl {...props} />, { useRedux: true }); + expect(screen.getByText(/missing dataset/i)).toBeVisible(); + expect(screen.getByText(/missing url parameters/i)).toBeVisible(); + expect( + screen.getByText( + /the url is missing the dataset_id or slice_id parameters\./i, + ), + ).toBeVisible(); +}); + +test('should show missing dataset state', () => { + // @ts-ignore + delete window.location; + // @ts-ignore + window.location = { search: '?slice_id=152' }; + const props = createProps({ datasource: fallbackExploreInitialData.dataset }); + render(<DatasourceControl {...props} />, { useRedux: true }); + expect(screen.getAllByText(/missing dataset/i)).toHaveLength(2); + expect( + screen.getByText( + /the dataset linked to this chart may have been deleted\./i, + ), + ).toBeVisible(); }); diff --git a/superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx b/superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx index 615c61c2bd20a..c99193dd427d6 100644 --- a/superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx +++ b/superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx @@ -17,6 +17,7 @@ * specific language governing permissions and limitations * under the License. */ + import React from 'react'; import PropTypes from 'prop-types'; import { @@ -26,8 +27,8 @@ import { t, withTheme, } from '@superset-ui/core'; +import { getTemporalColumns } from '@superset-ui/chart-controls'; import { getUrlParam } from 'src/utils/urlUtils'; - import { AntdDropdown } from 'src/components'; import { Menu } from 'src/components/Menu'; import { Tooltip } from 'src/components/Tooltip'; @@ -40,9 +41,17 @@ import Button from 'src/components/Button'; import ErrorAlert from 'src/components/ErrorMessage/ErrorAlert'; import WarningIconWithTooltip from 'src/components/WarningIconWithTooltip'; import { URL_PARAMS } from 'src/constants'; -import { isUserAdmin } from 'src/dashboard/util/findPermission'; +import { getDatasourceAsSaveableDataset } from 'src/utils/datasourceUtils'; +import { + canUserAccessSqlLab, + isUserAdmin, +} from 'src/dashboard/util/permissionUtils'; +import ModalTrigger from 'src/components/ModalTrigger'; +import ViewQueryModalFooter from 'src/explore/components/controls/ViewQueryModalFooter'; +import ViewQuery from 'src/explore/components/controls/ViewQuery'; import { SaveDatasetModal } from 'src/SqlLab/components/SaveDatasetModal'; import { safeStringify } from 'src/utils/safeStringify'; +import { isString } from 'lodash'; const propTypes = { actions: PropTypes.object.isRequired, @@ -104,7 +113,7 @@ const Styles = styled.div` white-space: nowrap; overflow: hidden; } - .dataset-svg { + .datasource-svg { margin-right: ${({ theme }) => 2 * theme.gridUnit}px; flex: none; } @@ -122,67 +131,104 @@ const EDIT_DATASET = 'edit_dataset'; const QUERY_PREVIEW = 'query_preview'; const SAVE_AS_DATASET = 'save_as_dataset'; +// If the string is longer than this value's number characters we add +// a tooltip for user can see the full name by hovering over the visually truncated string in UI +const VISIBLE_TITLE_LENGTH = 25; + +// Assign icon for each DatasourceType. If no icon assingment is found in the lookup, no icon will render +export const datasourceIconLookup = { + [DatasourceType.Query]: ( + <Icons.ConsoleSqlOutlined className="datasource-svg" /> + ), + [DatasourceType.Table]: <Icons.DatasetPhysical className="datasource-svg" />, +}; + +// Render title for datasource with tooltip only if text is longer than VISIBLE_TITLE_LENGTH +export const renderDatasourceTitle = (displayString, tooltip) => + displayString?.length > VISIBLE_TITLE_LENGTH ? ( + // Add a tooltip only for long names that will be visually truncated + <Tooltip title={tooltip}> + <span className="title-select">{displayString}</span> + </Tooltip> + ) : ( + <span title={tooltip} className="title-select"> + {displayString} + </span> + ); + +// Different data source types use different attributes for the display title +export const getDatasourceTitle = datasource => { + if (datasource?.type === 'query') return datasource?.sql; + return datasource?.name || ''; +}; + class DatasourceControl extends React.PureComponent { constructor(props) { super(props); this.state = { showEditDatasourceModal: false, showChangeDatasourceModal: false, + showSaveDatasetModal: false, }; - this.onDatasourceSave = this.onDatasourceSave.bind(this); - this.toggleChangeDatasourceModal = - this.toggleChangeDatasourceModal.bind(this); - this.toggleEditDatasourceModal = this.toggleEditDatasourceModal.bind(this); - this.toggleShowDatasource = this.toggleShowDatasource.bind(this); - this.handleMenuItemClick = this.handleMenuItemClick.bind(this); - this.toggleSaveDatasetModal = this.toggleSaveDatasetModal.bind(this); } - onDatasourceSave(datasource) { - this.props.actions.setDatasource(datasource); + onDatasourceSave = datasource => { + this.props.actions.changeDatasource(datasource); + const { temporalColumns, defaultTemporalColumn } = + getTemporalColumns(datasource); + const { columns } = datasource; + // the current granularity_sqla might not be a temporal column anymore const timeCol = this.props.form_data?.granularity_sqla; - const { columns } = this.props.datasource; - const firstDttmCol = columns.find(column => column.is_dttm); - if ( - datasource.type === 'table' && - !columns.find(({ column_name }) => column_name === timeCol)?.is_dttm - ) { - // set `granularity_sqla` to first datatime column name or null + const isGranularitySqalTemporal = columns.find( + ({ column_name }) => column_name === timeCol, + )?.is_dttm; + // the current main_dttm_col might not be a temporal column anymore + const isDefaultTemporal = columns.find( + ({ column_name }) => column_name === defaultTemporalColumn, + )?.is_dttm; + + // if the current granularity_sqla is empty or it is not a temporal column anymore + // let's update the control value + if (datasource.type === 'table' && !isGranularitySqalTemporal) { + const temporalColumn = isDefaultTemporal + ? defaultTemporalColumn + : temporalColumns?.[0]; this.props.actions.setControlValue( 'granularity_sqla', - firstDttmCol ? firstDttmCol.column_name : null, + temporalColumn || null, ); } + if (this.props.onDatasourceSave) { this.props.onDatasourceSave(datasource); } - } + }; - toggleShowDatasource() { + toggleShowDatasource = () => { this.setState(({ showDatasource }) => ({ showDatasource: !showDatasource, })); - } + }; - toggleChangeDatasourceModal() { + toggleChangeDatasourceModal = () => { this.setState(({ showChangeDatasourceModal }) => ({ showChangeDatasourceModal: !showChangeDatasourceModal, })); - } + }; - toggleEditDatasourceModal() { + toggleEditDatasourceModal = () => { this.setState(({ showEditDatasourceModal }) => ({ showEditDatasourceModal: !showEditDatasourceModal, })); - } + }; - toggleSaveDatasetModal() { + toggleSaveDatasetModal = () => { this.setState(({ showSaveDatasetModal }) => ({ showSaveDatasetModal: !showSaveDatasetModal, })); - } + }; - handleMenuItemClick({ key }) { + handleMenuItemClick = ({ key }) => { switch (key) { case CHANGE_DATASET: this.toggleChangeDatasourceModal(); @@ -205,9 +251,6 @@ class DatasourceControl extends React.PureComponent { } break; - case QUERY_PREVIEW: - break; - case SAVE_AS_DATASET: this.toggleSaveDatasetModal(); break; @@ -215,7 +258,7 @@ class DatasourceControl extends React.PureComponent { default: break; } - } + }; render() { const { @@ -224,28 +267,29 @@ class DatasourceControl extends React.PureComponent { showSaveDatasetModal, } = this.state; const { datasource, onChange, theme } = this.props; - const isMissingDatasource = datasource.id == null; + const isMissingDatasource = !datasource?.id; let isMissingParams = false; if (isMissingDatasource) { const datasourceId = getUrlParam(URL_PARAMS.datasourceId); const sliceId = getUrlParam(URL_PARAMS.sliceId); + if (!datasourceId && !sliceId) { isMissingParams = true; } } - const isSqlSupported = datasource.type === 'table'; const { user } = this.props; - const allowEdit = datasource.owners - .map(o => o.id || o.value) - .includes(user.userId); - isUserAdmin(user); + const allowEdit = + datasource.owners?.map(o => o.id || o.value).includes(user.userId) || + isUserAdmin(user); + + const canAccessSqlLab = canUserAccessSqlLab(user); const editText = t('Edit dataset'); const defaultDatasourceMenu = ( <Menu onClick={this.handleMenuItemClick}> - {this.props.isEditable && ( + {this.props.isEditable && !isMissingDatasource && ( <Menu.Item key={EDIT_DATASET} data-test="edit-dataset" @@ -264,8 +308,8 @@ class DatasourceControl extends React.PureComponent { )} </Menu.Item> )} - <Menu.Item key={CHANGE_DATASET}>{t('Change dataset')}</Menu.Item> - {isSqlSupported && ( + <Menu.Item key={CHANGE_DATASET}>{t('Swap dataset')}</Menu.Item> + {!isMissingDatasource && canAccessSqlLab && ( <Menu.Item key={VIEW_IN_SQL_LAB}>{t('View in SQL Lab')}</Menu.Item> )} </Menu> @@ -273,35 +317,59 @@ class DatasourceControl extends React.PureComponent { const queryDatasourceMenu = ( <Menu onClick={this.handleMenuItemClick}> - <Menu.Item key={QUERY_PREVIEW}>{t('Query preview')}</Menu.Item> - <Menu.Item key={VIEW_IN_SQL_LAB}>{t('View in SQL Lab')}</Menu.Item> + <Menu.Item key={QUERY_PREVIEW}> + <ModalTrigger + triggerNode={ + <span data-test="view-query-menu-item">{t('Query preview')}</span> + } + modalTitle={t('Query preview')} + modalBody={ + <ViewQuery + sql={datasource?.sql || datasource?.select_star || ''} + /> + } + modalFooter={ + <ViewQueryModalFooter + changeDatasource={this.toggleSaveDatasetModal} + datasource={datasource} + /> + } + draggable={false} + resizable={false} + responsive + /> + </Menu.Item> + {canAccessSqlLab && ( + <Menu.Item key={VIEW_IN_SQL_LAB}>{t('View in SQL Lab')}</Menu.Item> + )} <Menu.Item key={SAVE_AS_DATASET}>{t('Save as dataset')}</Menu.Item> </Menu> ); const { health_check_message: healthCheckMessage } = datasource; - let extra = {}; + let extra; if (datasource?.extra) { - try { - extra = JSON.parse(datasource?.extra); - } catch {} // eslint-disable-line no-empty + if (isString(datasource.extra)) { + try { + extra = JSON.parse(datasource.extra); + } catch {} // eslint-disable-line no-empty + } else { + extra = datasource.extra; // eslint-disable-line prefer-destructuring + } } + const titleText = isMissingDatasource + ? t('Missing dataset') + : getDatasourceTitle(datasource); + + const tooltip = titleText; + return ( <Styles data-test="datasource-control" className="DatasourceControl"> <div className="data-container"> - <Icons.DatasetPhysical className="dataset-svg" /> - {/* Add a tooltip only for long dataset names */} - {!isMissingDatasource && datasource.name.length > 25 ? ( - <Tooltip title={datasource.name}> - <span className="title-select">{datasource.name}</span> - </Tooltip> - ) : ( - <span title={datasource.name} className="title-select"> - {datasource.name} - </span> - )} + {datasourceIconLookup[datasource?.type]} + {renderDatasourceTitle(titleText, tooltip)} {healthCheckMessage && ( <Tooltip title={healthCheckMessage}> <Icons.AlertSolid iconColor={theme.colors.warning.base} /> @@ -319,12 +387,10 @@ class DatasourceControl extends React.PureComponent { trigger={['click']} data-test="datasource-menu" > - <Tooltip title={t('More dataset related options')}> - <Icons.MoreVert - className="datasource-modal-trigger" - data-test="datasource-menu-trigger" - /> - </Tooltip> + <Icons.MoreVert + className="datasource-modal-trigger" + data-test="datasource-menu-trigger" + /> </AntdDropdown> </div> {/* missing dataset */} @@ -366,7 +432,7 @@ class DatasourceControl extends React.PureComponent { this.handleMenuItemClick({ key: CHANGE_DATASET }) } > - {t('Change dataset')} + {t('Swap dataset')} </Button> </p> </> @@ -394,12 +460,14 @@ class DatasourceControl extends React.PureComponent { <SaveDatasetModal visible={showSaveDatasetModal} onHide={this.toggleSaveDatasetModal} - buttonTextOnSave={t('Save & Explore')} - buttonTextOnOverwrite={t('Overwrite & Explore')} + buttonTextOnSave={t('Save')} + buttonTextOnOverwrite={t('Overwrite')} modalDescription={t( 'Save this query as a virtual dataset to continue exploring', )} - datasource={datasource} + datasource={getDatasourceAsSaveableDataset(datasource)} + openWindow={false} + formData={this.props.form_data} /> )} </Styles> diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx index cf63995c5a5f1..031c8d9ad55f1 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx @@ -16,83 +16,44 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useState, useEffect, useMemo } from 'react'; -import rison from 'rison'; -import { css, SupersetClient, styled, t, useTheme } from '@superset-ui/core'; +import React, { ReactNode, useState, useEffect, useMemo } from 'react'; import { - buildTimeRangeString, - formatTimeRange, - COMMON_RANGE_VALUES_SET, - CALENDAR_RANGE_VALUES_SET, - FRAME_OPTIONS, - customTimeRangeDecode, -} from 'src/explore/components/controls/DateFilterControl/utils'; -import { getClientErrorObject } from 'src/utils/getClientErrorObject'; + css, + styled, + t, + useTheme, + NO_TIME_RANGE, + SupersetTheme, +} from '@superset-ui/core'; import Button from 'src/components/Button'; import ControlHeader from 'src/explore/components/ControlHeader'; -import Label, { Type } from 'src/components/Label'; +import Modal from 'src/components/Modal'; import { Divider } from 'src/components'; import Icons from 'src/components/Icons'; import Select from 'src/components/Select/Select'; import { Tooltip } from 'src/components/Tooltip'; -import { DEFAULT_TIME_RANGE } from 'src/explore/constants'; import { useDebouncedEffect } from 'src/explore/exploreUtils'; import { SLOW_DEBOUNCE } from 'src/constants'; -import { testWithId } from 'src/utils/testUtils'; import { noOp } from 'src/utils/common'; -import { FrameType } from './types'; +import { useCSSTextTruncation } from 'src/hooks/useTruncation'; import ControlPopover from '../ControlPopover/ControlPopover'; +import { DateFilterControlProps, FrameType } from './types'; +import { + DATE_FILTER_TEST_KEY, + fetchTimeRange, + FRAME_OPTIONS, + guessFrame, + useDefaultTimeFilter, +} from './utils'; import { CommonFrame, CalendarFrame, CustomFrame, AdvancedFrame, + DateLabel, } from './components'; -const guessFrame = (timeRange: string): FrameType => { - if (COMMON_RANGE_VALUES_SET.has(timeRange)) { - return 'Common'; - } - if (timeRange === 'today : tomorrow') { - return 'Today'; - } - if (timeRange === 'yesterday : today') { - return 'Yesterday'; - } - if (CALENDAR_RANGE_VALUES_SET.has(timeRange)) { - return 'Calendar'; - } - if (timeRange === 'No filter') { - return 'No filter'; - } - if (customTimeRangeDecode(timeRange).matchedFlag) { - return 'Custom'; - } - return 'Advanced'; -}; - -const fetchTimeRange = async (timeRange: string) => { - const query = rison.encode_uri(timeRange); - const endpoint = `/api/v1/time_range/?q=${query}`; - try { - const response = await SupersetClient.get({ endpoint }); - const timeRangeString = buildTimeRangeString( - response?.json?.result?.since || '', - response?.json?.result?.until || '', - ); - return { - value: formatTimeRange(timeRangeString), - }; - } catch (response) { - const clientError = await getClientErrorObject(response); - return { - error: clientError.message || clientError.error, - }; - } -}; - -const StyledPopover = styled(ControlPopover)``; const StyledRangeType = styled(Select)` width: 272px; `; @@ -167,27 +128,39 @@ const IconWrapper = styled.span` } `; -interface DateFilterControlProps { - name: string; - onChange: (timeRange: string) => void; - value?: string; - type?: Type; - onOpenPopover?: () => void; - onClosePopover?: () => void; -} - -export const DATE_FILTER_CONTROL_TEST_ID = 'date-filter-control'; -export const getDateFilterControlTestId = testWithId( - DATE_FILTER_CONTROL_TEST_ID, -); +const getTooltipTitle = ( + isLabelTruncated: boolean, + label: string | undefined, + range: string | undefined, +) => + isLabelTruncated ? ( + <div> + {label && <strong>{label}</strong>} + {range && ( + <div + css={(theme: SupersetTheme) => css` + margin-top: ${theme.gridUnit}px; + `} + > + {range} + </div> + )} + </div> + ) : ( + range || null + ); export default function DateFilterLabel(props: DateFilterControlProps) { const { - value = DEFAULT_TIME_RANGE, onChange, onOpenPopover = noOp, onClosePopover = noOp, + overlayStyle = 'Popover', + isOverflowingFilterBar = false, } = props; + const defaultTimeFilter = useDefaultTimeFilter(); + + const value = props.value ?? defaultTimeFilter; const [actualTimeRange, setActualTimeRange] = useState<string>(value); const [show, setShow] = useState<boolean>(false); @@ -197,14 +170,22 @@ export default function DateFilterLabel(props: DateFilterControlProps) { const [timeRangeValue, setTimeRangeValue] = useState(value); const [validTimeRange, setValidTimeRange] = useState<boolean>(false); const [evalResponse, setEvalResponse] = useState<string>(value); - const [tooltipTitle, setTooltipTitle] = useState<string>(value); + const [tooltipTitle, setTooltipTitle] = useState<ReactNode | null>(value); + const theme = useTheme(); + const [labelRef, labelIsTruncated] = useCSSTextTruncation<HTMLSpanElement>(); useEffect(() => { + if (value === NO_TIME_RANGE) { + setActualTimeRange(NO_TIME_RANGE); + setTooltipTitle(null); + setValidTimeRange(true); + return; + } fetchTimeRange(value).then(({ value: actualRange, error }) => { if (error) { setEvalResponse(error || ''); setValidTimeRange(false); - setTooltipTitle(value || ''); + setTooltipTitle(value || null); } else { /* HRT == human readable text @@ -223,22 +204,30 @@ export default function DateFilterLabel(props: DateFilterControlProps) { guessedFrame === 'No filter' ) { setActualTimeRange(value); - setTooltipTitle(actualRange || ''); - } else if (guessedFrame === 'Today' || guessedFrame === 'Yesterday') { - setActualTimeRange(guessedFrame); - setTooltipTitle(actualRange || ''); + setTooltipTitle( + getTooltipTitle(labelIsTruncated, value, actualRange), + ); } else { setActualTimeRange(actualRange || ''); - setTooltipTitle(value || ''); + setTooltipTitle( + getTooltipTitle(labelIsTruncated, actualRange, value), + ); } setValidTimeRange(true); } setLastFetchedTimeRange(value); + setEvalResponse(actualRange || value); }); - }, [value]); + }, [guessedFrame, labelIsTruncated, labelRef, value]); useDebouncedEffect( () => { + if (timeRangeValue === NO_TIME_RANGE) { + setEvalResponse(NO_TIME_RANGE); + setLastFetchedTimeRange(NO_TIME_RANGE); + setValidTimeRange(true); + return; + } if (lastFetchedTimeRange !== timeRangeValue) { fetchTimeRange(timeRangeValue).then(({ value: actualRange, error }) => { if (error) { @@ -259,45 +248,38 @@ export default function DateFilterLabel(props: DateFilterControlProps) { function onSave() { onChange(timeRangeValue); setShow(false); + onClosePopover(); } function onOpen() { setTimeRangeValue(value); setFrame(guessedFrame); setShow(true); + onOpenPopover(); } function onHide() { setTimeRangeValue(value); setFrame(guessedFrame); setShow(false); + onClosePopover(); } - const togglePopover = () => { + const toggleOverlay = () => { if (show) { onHide(); - onClosePopover(); } else { onOpen(); - onOpenPopover(); } }; - function onChangeFrame(value: string) { - if (value === 'No filter') { - setTimeRangeValue('No filter'); - } - if (value === 'Today') { - setTimeRangeValue('today : tomorrow'); - } - if (value === 'Yesterday') { - setTimeRangeValue('yesterday : today'); + function onChangeFrame(value: FrameType) { + if (value === NO_TIME_RANGE) { + setTimeRangeValue(NO_TIME_RANGE); } - setFrame(value as FrameType); + setFrame(value); } - const theme = useTheme(); - const overlayContent = ( <ContentStyleWrapper> <div className="control-label">{t('RANGE TYPE')}</div> @@ -322,7 +304,9 @@ export default function DateFilterLabel(props: DateFilterControlProps) { {frame === 'Custom' && ( <CustomFrame value={timeRangeValue} onChange={setTimeRangeValue} /> )} - {frame === 'No filter' && <div data-test="no-filter" />} + {frame === 'No filter' && ( + <div data-test={DATE_FILTER_TEST_KEY.noFilter} /> + )} <Divider /> <div> <div className="section-title">{t('Actual time range')}</div> @@ -341,7 +325,7 @@ export default function DateFilterLabel(props: DateFilterControlProps) { cta key="cancel" onClick={onHide} - data-test="cancel-button" + data-test={DATE_FILTER_TEST_KEY.cancelButton} > {t('CANCEL')} </Button> @@ -351,7 +335,7 @@ export default function DateFilterLabel(props: DateFilterControlProps) { disabled={!validTimeRange} key="apply" onClick={onSave} - {...getDateFilterControlTestId('apply-button')} + data-test={DATE_FILTER_TEST_KEY.applyButton} > {t('APPLY')} </Button> @@ -366,29 +350,65 @@ export default function DateFilterLabel(props: DateFilterControlProps) { </IconWrapper> ); - const overlayStyle = { - width: '600px', - }; + const popoverContent = ( + <ControlPopover + placement="right" + trigger="click" + content={overlayContent} + title={title} + defaultVisible={show} + visible={show} + onVisibleChange={toggleOverlay} + overlayStyle={{ width: '600px' }} + getPopupContainer={triggerNode => + isOverflowingFilterBar + ? (triggerNode.parentNode as HTMLElement) + : document.body + } + destroyTooltipOnHide + > + <Tooltip placement="top" title={tooltipTitle}> + <DateLabel + label={actualTimeRange} + isActive={show} + isPlaceholder={actualTimeRange === NO_TIME_RANGE} + data-test={DATE_FILTER_TEST_KEY.popoverOverlay} + ref={labelRef} + /> + </Tooltip> + </ControlPopover> + ); - return ( + const modalContent = ( <> - <ControlHeader {...props} /> - <StyledPopover - placement="right" - trigger="click" - content={overlayContent} + <Tooltip placement="top" title={tooltipTitle}> + <DateLabel + onClick={toggleOverlay} + label={actualTimeRange} + isActive={show} + isPlaceholder={actualTimeRange === NO_TIME_RANGE} + data-test={DATE_FILTER_TEST_KEY.modalOverlay} + ref={labelRef} + /> + </Tooltip> + {/* the zIndex value is from trying so that the Modal doesn't overlay the AdhocFilter when GENERIC_CHART_AXES is enabled */} + <Modal title={title} - defaultVisible={show} - visible={show} - onVisibleChange={togglePopover} - overlayStyle={overlayStyle} + show={show} + onHide={toggleOverlay} + width="600px" + hideFooter + zIndex={1030} > - <Tooltip placement="top" title={tooltipTitle}> - <Label className="pointer" data-test="time-range-trigger"> - {actualTimeRange} - </Label> - </Tooltip> - </StyledPopover> + {overlayContent} + </Modal> + </> + ); + + return ( + <> + <ControlHeader {...props} /> + {overlayStyle === 'Modal' ? modalContent : popoverContent} </> ); } diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx index f865b703a78ab..77f42598ac9a2 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx @@ -24,20 +24,20 @@ import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; import { FrameComponentProps } from 'src/explore/components/controls/DateFilterControl/types'; import DateFunctionTooltip from './DateFunctionTooltip'; -export function AdvancedFrame(props: FrameComponentProps) { - function getAdvancedRange(value: string): string { - if (value.includes(SEPARATOR)) { - return value; - } - if (value.startsWith('Last')) { - return [value, ''].join(SEPARATOR); - } - if (value.startsWith('Next')) { - return ['', value].join(SEPARATOR); - } - return SEPARATOR; +function getAdvancedRange(value: string): string { + if (value.includes(SEPARATOR)) { + return value; } + if (value.startsWith('Last')) { + return [value, ''].join(SEPARATOR); + } + if (value.startsWith('Next')) { + return ['', value].join(SEPARATOR); + } + return SEPARATOR; +} +export function AdvancedFrame(props: FrameComponentProps) { const advancedRange = getAdvancedRange(props.value || ''); const [since, until] = advancedRange.split(SEPARATOR); if (advancedRange !== props.value) { diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx index 4b76ab648a157..d3de2b9991b19 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx @@ -22,6 +22,7 @@ import { Radio } from 'src/components/Radio'; import { COMMON_RANGE_OPTIONS, COMMON_RANGE_SET, + DATE_FILTER_TEST_KEY, } from 'src/explore/components/controls/DateFilterControl/utils'; import { CommonRangeType, @@ -38,7 +39,12 @@ export function CommonFrame(props: FrameComponentProps) { return ( <> - <div className="section-title">{t('Configure Time Range: Last...')}</div> + <div + className="section-title" + data-test={DATE_FILTER_TEST_KEY.commonFrame} + > + {t('Configure Time Range: Last...')} + </div> <Radio.Group value={commonRange} onChange={(e: any) => props.onChange(e.target.value)} diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/DateLabel.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/DateLabel.tsx new file mode 100644 index 0000000000000..2c31f8030f567 --- /dev/null +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/DateLabel.tsx @@ -0,0 +1,100 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { forwardRef, ReactNode, RefObject } from 'react'; +import { css, styled, useTheme } from '@superset-ui/core'; +import Icons from 'src/components/Icons'; + +export type DateLabelProps = { + label: ReactNode; + isActive?: boolean; + isPlaceholder?: boolean; + onClick?: (event: React.MouseEvent) => void; +}; + +// This is the color that antd components (such as Select or Input) use on hover +// TODO: use theme.colors.primary.base here and in antd components +const ACTIVE_BORDER_COLOR = '#45BED6'; + +const LabelContainer = styled.div<{ + isActive?: boolean; + isPlaceholder?: boolean; +}>` + ${({ theme, isActive, isPlaceholder }) => css` + width: 100%; + height: ${theme.gridUnit * 8}px; + + display: flex; + align-items: center; + flex-wrap: nowrap; + + padding: 0 ${theme.gridUnit * 3}px; + + background-color: ${theme.colors.grayscale.light5}; + + border: 1px solid + ${isActive ? ACTIVE_BORDER_COLOR : theme.colors.grayscale.light2}; + border-radius: ${theme.borderRadius}px; + + cursor: pointer; + + transition: border-color 0.3s cubic-bezier(0.65, 0.05, 0.36, 1); + :hover, + :focus { + border-color: ${ACTIVE_BORDER_COLOR}; + } + + .date-label-content { + color: ${isPlaceholder + ? theme.colors.grayscale.light1 + : theme.colors.grayscale.dark1}; + overflow: hidden; + text-overflow: ellipsis; + min-width: 0; + flex-shrink: 1; + white-space: nowrap; + } + + span[role='img'] { + margin-left: auto; + padding-left: ${theme.gridUnit}px; + + & > span[role='img'] { + line-height: 0; + } + } + `} +`; + +export const DateLabel = forwardRef( + (props: DateLabelProps, ref: RefObject<HTMLSpanElement>) => { + const theme = useTheme(); + return ( + <LabelContainer {...props} tabIndex={0}> + <span className="date-label-content" ref={ref}> + {props.label} + </span> + <Icons.CalendarOutlined + iconSize="s" + iconColor={theme.colors.grayscale.base} + /> + </LabelContainer> + ); + }, +); diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts index 0bec821065627..0d46ee7a97d19 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts @@ -20,3 +20,4 @@ export { CommonFrame } from './CommonFrame'; export { CalendarFrame } from './CalendarFrame'; export { CustomFrame } from './CustomFrame'; export { AdvancedFrame } from './AdvancedFrame'; +export { DateLabel } from './DateLabel'; diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/index.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/index.ts index da29085f8b52c..d339827629fbb 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/index.ts +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/index.ts @@ -17,3 +17,4 @@ * under the License. */ export { default } from './DateFilterLabel'; +export * from './utils'; diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.test.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/AdvancedFrame.test.tsx similarity index 97% rename from superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.test.tsx rename to superset-frontend/src/explore/components/controls/DateFilterControl/tests/AdvancedFrame.test.tsx index f7f13add422a1..327f020b7c563 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.test.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/AdvancedFrame.test.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; -import { AdvancedFrame } from '.'; +import { AdvancedFrame } from '../components'; test('renders with default props', () => { render(<AdvancedFrame onChange={jest.fn()} value="Last week" />); diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.test.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/CustomFrame.test.tsx similarity index 95% rename from superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.test.tsx rename to superset-frontend/src/explore/components/controls/DateFilterControl/tests/CustomFrame.test.tsx index 5a26d728a725a..83cad48bdb439 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.test.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/CustomFrame.test.tsx @@ -22,7 +22,9 @@ import { Provider } from 'react-redux'; import configureStore from 'redux-mock-store'; import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; -import { CustomFrame } from '.'; +import { CustomFrame } from '../components'; + +jest.useFakeTimers(); const emptyValue = ''; const nowValue = 'now : now'; @@ -191,7 +193,7 @@ test('triggers onChange when the value changes', () => { expect(onChange).toHaveBeenCalled(); }); -test('triggers onChange when the mode changes', () => { +test('triggers onChange when the mode changes', async () => { const onChange = jest.fn(); render( <Provider store={store}> @@ -199,8 +201,12 @@ test('triggers onChange when the mode changes', () => { </Provider>, ); userEvent.click(screen.getByTitle('Midnight')); + expect(await screen.findByTitle('Relative Date/Time')).toBeInTheDocument(); userEvent.click(screen.getByTitle('Relative Date/Time')); userEvent.click(screen.getAllByTitle('Now')[1]); + expect( + await screen.findByText('Configure custom time range'), + ).toBeInTheDocument(); userEvent.click(screen.getAllByTitle('Specific Date/Time')[1]); expect(onChange).toHaveBeenCalledTimes(2); }); @@ -213,8 +219,10 @@ test('triggers onChange when the grain changes', async () => { </Provider>, ); userEvent.click(screen.getByText('Days Before')); + expect(await screen.findByText('Weeks Before')).toBeInTheDocument(); userEvent.click(screen.getByText('Weeks Before')); userEvent.click(screen.getByText('Days After')); + expect(await screen.findByText('Weeks After')).toBeInTheDocument(); userEvent.click(screen.getByText('Weeks After')); expect(onChange).toHaveBeenCalledTimes(2); }); diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/tests/DateFilterLabel.test.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/DateFilterLabel.test.tsx new file mode 100644 index 0000000000000..dc7559beece76 --- /dev/null +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/DateFilterLabel.test.tsx @@ -0,0 +1,108 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import thunk from 'redux-thunk'; +import { Provider } from 'react-redux'; +import configureStore from 'redux-mock-store'; + +import { render, screen } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; + +import { NO_TIME_RANGE } from '@superset-ui/core'; +import DateFilterLabel from '..'; +import { DateFilterControlProps } from '../types'; +import { DATE_FILTER_TEST_KEY } from '../utils'; + +const mockStore = configureStore([thunk]); + +const defaultProps = { + onChange: jest.fn(), + onClosePopover: jest.fn(), + onOpenPopover: jest.fn(), +}; + +function setup( + props: Omit<DateFilterControlProps, 'name'> = defaultProps, + store: any = mockStore({}), +) { + return ( + <Provider store={store}> + <DateFilterLabel name="time_range" {...props} /> + </Provider> + ); +} + +test('DateFilter with default props', () => { + render(setup()); + // label + expect(screen.getByText(NO_TIME_RANGE)).toBeInTheDocument(); + + // should be popover by default + userEvent.click(screen.getByText(NO_TIME_RANGE)); + expect( + screen.getByTestId(DATE_FILTER_TEST_KEY.popoverOverlay), + ).toBeInTheDocument(); +}); + +test('DateFilter should be applied the overlayStyle props', () => { + render(setup({ onChange: () => {}, overlayStyle: 'Modal' })); + // should be Modal as overlay + userEvent.click(screen.getByText(NO_TIME_RANGE)); + expect( + screen.getByTestId(DATE_FILTER_TEST_KEY.modalOverlay), + ).toBeInTheDocument(); +}); + +test('DateFilter should be applied the global config time_filter from the store', () => { + render( + setup( + defaultProps, + mockStore({ + common: { conf: { DEFAULT_TIME_FILTER: 'Last week' } }, + }), + ), + ); + // the label should be 'Last week' + expect(screen.getByText('Last week')).toBeInTheDocument(); + + userEvent.click(screen.getByText('Last week')); + expect( + screen.getByTestId(DATE_FILTER_TEST_KEY.commonFrame), + ).toBeInTheDocument(); +}); + +test('Open and close popover', () => { + render(setup()); + + // click "Cancel" + userEvent.click(screen.getByText(NO_TIME_RANGE)); + expect(defaultProps.onOpenPopover).toHaveBeenCalled(); + expect(screen.getByText('Edit time range')).toBeInTheDocument(); + userEvent.click(screen.getByText('CANCEL')); + expect(defaultProps.onClosePopover).toHaveBeenCalled(); + expect(screen.queryByText('Edit time range')).not.toBeInTheDocument(); + + // click "Apply" + userEvent.click(screen.getByText(NO_TIME_RANGE)); + expect(defaultProps.onOpenPopover).toHaveBeenCalled(); + expect(screen.getByText('Edit time range')).toBeInTheDocument(); + userEvent.click(screen.getByText('APPLY')); + expect(defaultProps.onClosePopover).toHaveBeenCalled(); + expect(screen.queryByText('Edit time range')).not.toBeInTheDocument(); +}); diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/utils.test.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/utils.test.ts similarity index 100% rename from superset-frontend/src/explore/components/controls/DateFilterControl/utils/utils.test.ts rename to superset-frontend/src/explore/components/controls/DateFilterControl/tests/utils.test.ts diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts index e4d9b977e3fd9..1835b254619d5 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts @@ -96,3 +96,13 @@ export type FrameComponentProps = { onChange: (timeRange: string) => void; value: string; }; + +export interface DateFilterControlProps { + name: string; + onChange: (timeRange: string) => void; + value?: string; + onOpenPopover?: () => void; + onClosePopover?: () => void; + overlayStyle?: 'Modal' | 'Popover'; + isOverflowingFilterBar?: boolean; +} diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts index 7cda21f840191..f92f7704bac47 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts @@ -118,11 +118,7 @@ export const SEVEN_DAYS_AGO = moment() .startOf('day') .subtract(7, 'days') .format(MOMENT_FORMAT); -export const MIDNIGHT = moment() - .utc() - .add(DEFAULT_RELATIVE_END_TIME === 'tomorrow' ? 1 : 0, 'days') - .startOf('day') - .format(MOMENT_FORMAT); +export const MIDNIGHT = moment().utc().startOf('day').format(MOMENT_FORMAT); export const LOCALE_MAPPING = { en: 'en_US', @@ -140,3 +136,12 @@ export const LOCALE_MAPPING = { sl: 'sl_SI', nl: 'nl_NL', }; + +export enum DATE_FILTER_TEST_KEY { + commonFrame = 'common-frame', + modalOverlay = 'modal-overlay', + popoverOverlay = 'time-range-trigger', + noFilter = 'no-filter', + cancelButton = 'cancel-button', + applyButton = 'date-filter-control__apply-button', +} diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts index fc14dd9855bfd..08162cedf02d0 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts @@ -16,6 +16,17 @@ * specific language governing permissions and limitations * under the License. */ +import rison from 'rison'; +import { SupersetClient, NO_TIME_RANGE, JsonObject } from '@superset-ui/core'; +import { getClientErrorObject } from 'src/utils/getClientErrorObject'; +import { useSelector } from 'react-redux'; +import { + COMMON_RANGE_VALUES_SET, + CALENDAR_RANGE_VALUES_SET, + customTimeRangeDecode, +} from '.'; +import { FrameType } from '../types'; + export const SEPARATOR = ' : '; export const buildTimeRangeString = (since: string, until: string): string => @@ -24,11 +35,61 @@ export const buildTimeRangeString = (since: string, until: string): string => const formatDateEndpoint = (dttm: string, isStart?: boolean): string => dttm.replace('T00:00:00', '') || (isStart ? '-∞' : '∞'); -export const formatTimeRange = (timeRange: string) => { +export const formatTimeRange = ( + timeRange: string, + columnPlaceholder = 'col', +) => { const splitDateRange = timeRange.split(SEPARATOR); if (splitDateRange.length === 1) return timeRange; return `${formatDateEndpoint( splitDateRange[0], true, - )} ≤ col < ${formatDateEndpoint(splitDateRange[1])}`; + )} ≤ ${columnPlaceholder} < ${formatDateEndpoint(splitDateRange[1])}`; +}; + +export const guessFrame = (timeRange: string): FrameType => { + if (COMMON_RANGE_VALUES_SET.has(timeRange)) { + return 'Common'; + } + if (CALENDAR_RANGE_VALUES_SET.has(timeRange)) { + return 'Calendar'; + } + if (timeRange === NO_TIME_RANGE) { + return 'No filter'; + } + if (customTimeRangeDecode(timeRange).matchedFlag) { + return 'Custom'; + } + return 'Advanced'; }; + +export const fetchTimeRange = async ( + timeRange: string, + columnPlaceholder = 'col', +) => { + const query = rison.encode_uri(timeRange); + const endpoint = `/api/v1/time_range/?q=${query}`; + try { + const response = await SupersetClient.get({ endpoint }); + const timeRangeString = buildTimeRangeString( + response?.json?.result?.since || '', + response?.json?.result?.until || '', + ); + return { + value: formatTimeRange(timeRangeString, columnPlaceholder), + }; + } catch (response) { + const clientError = await getClientErrorObject(response); + return { + error: clientError.message || clientError.error || response.statusText, + }; + } +}; + +export function useDefaultTimeFilter() { + return ( + useSelector( + (state: JsonObject) => state?.common?.conf?.DEFAULT_TIME_FILTER, + ) ?? NO_TIME_RANGE + ); +} diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx index 9c4011f9d54bb..dbbc8fe948432 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx @@ -18,18 +18,24 @@ */ /* eslint-disable camelcase */ import React, { + Dispatch, + SetStateAction, useCallback, useEffect, useMemo, useRef, useState, } from 'react'; -import { AdhocColumn, t, styled, css } from '@superset-ui/core'; +import { useSelector } from 'react-redux'; import { - ColumnMeta, + AdhocColumn, isAdhocColumn, - isSavedExpression, -} from '@superset-ui/chart-controls'; + t, + styled, + css, + DatasourceType, +} from '@superset-ui/core'; +import { ColumnMeta, isSavedExpression } from '@superset-ui/chart-controls'; import Tabs from 'src/components/Tabs'; import Button from 'src/components/Button'; import { Select } from 'src/components'; @@ -42,6 +48,7 @@ import { POPOVER_INITIAL_HEIGHT, UNRESIZABLE_POPOVER_WIDTH, } from 'src/explore/constants'; +import { ExplorePageState } from 'src/explore/types'; const StyledSelect = styled(Select)` .metric-option { @@ -64,6 +71,7 @@ interface ColumnSelectPopoverProps { getCurrentTab: (tab: string) => void; label: string; isTemporal?: boolean; + setDatasetModal?: Dispatch<SetStateAction<boolean>>; } const getInitialColumnValues = ( @@ -86,11 +94,15 @@ const ColumnSelectPopover = ({ editedColumn, onChange, onClose, + setDatasetModal, setLabel, getCurrentTab, label, isTemporal, }: ColumnSelectPopoverProps) => { + const datasourceType = useSelector<ExplorePageState, string | undefined>( + state => state.explore.datasource.type, + ); const [initialLabel] = useState(label); const [initialAdhocColumn, initialCalculatedColumn, initialSimpleColumn] = getInitialColumnValues(editedColumn); @@ -125,7 +137,7 @@ const ColumnSelectPopover = ({ const onSqlExpressionChange = useCallback( sqlExpression => { - setAdhocColumn({ label, sqlExpression } as AdhocColumn); + setAdhocColumn({ label, sqlExpression, expressionType: 'SQL' }); setSelectedSimpleColumn(undefined); setSelectedCalculatedColumn(undefined); }, @@ -218,6 +230,13 @@ const ColumnSelectPopover = ({ sqlEditorRef.current?.editor.resize(); }, []); + const setDatasetAndClose = () => { + if (setDatasetModal) { + setDatasetModal(true); + } + onClose(); + }; + const stateIsValid = adhocColumn || selectedCalculatedColumn || selectedSimpleColumn; const hasUnsavedChanges = @@ -265,7 +284,7 @@ const ColumnSelectPopover = ({ }))} /> </FormItem> - ) : ( + ) : datasourceType === DatasourceType.Table ? ( <EmptyStateSmall image="empty.svg" title={ @@ -283,6 +302,40 @@ const ColumnSelectPopover = ({ ) } /> + ) : ( + <EmptyStateSmall + image="empty.svg" + title={ + isTemporal + ? t('No temporal columns found') + : t('No saved expressions found') + } + description={ + isTemporal ? ( + <> + <span + role="button" + tabIndex={0} + onClick={setDatasetAndClose} + > + {t('Create a dataset')} + </span>{' '} + {t(' to mark a column as a time column')} + </> + ) : ( + <> + <span + role="button" + tabIndex={0} + onClick={setDatasetAndClose} + > + {t('Create a dataset')} + </span>{' '} + {t(' to add calculated columns')} + </> + ) + } + /> )} </Tabs.TabPane> <Tabs.TabPane key="simple" tab={t('Simple')}> @@ -290,9 +343,22 @@ const ColumnSelectPopover = ({ <EmptyStateSmall image="empty.svg" title={t('No temporal columns found')} - description={t( - 'Mark a column as temporal in "Edit datasource" modal', - )} + description={ + datasourceType === DatasourceType.Table ? ( + t('Mark a column as temporal in "Edit datasource" modal') + ) : ( + <> + <span + role="button" + tabIndex={0} + onClick={setDatasetAndClose} + > + {t('Create a dataset')} + </span>{' '} + {t(' to mark a column as a time column')} + </> + ) + } /> ) : ( <FormItem label={simpleColumnsLabel}> @@ -342,10 +408,8 @@ const ColumnSelectPopover = ({ {t('Close')} </Button> <Button - disabled={!stateIsValid} - buttonStyle={ - hasUnsavedChanges && stateIsValid ? 'primary' : 'default' - } + disabled={!stateIsValid || !hasUnsavedChanges} + buttonStyle="primary" buttonSize="small" onClick={onSave} data-test="ColumnEdit#save" diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx index 62107753e8289..4340317f04d11 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx @@ -17,13 +17,11 @@ * under the License. */ import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { AdhocColumn, t } from '@superset-ui/core'; -import { - ColumnMeta, - isAdhocColumn, - isColumnMeta, -} from '@superset-ui/chart-controls'; +import { useSelector } from 'react-redux'; +import { AdhocColumn, t, isAdhocColumn } from '@superset-ui/core'; +import { ColumnMeta, isColumnMeta } from '@superset-ui/chart-controls'; import { ExplorePopoverContent } from 'src/explore/components/ExploreContentPopover'; +import { SaveDatasetModal } from 'src/SqlLab/components/SaveDatasetModal'; import ColumnSelectPopover from './ColumnSelectPopover'; import { DndColumnSelectPopoverTitle } from './DndColumnSelectPopoverTitle'; import ControlPopover from '../ControlPopover/ControlPopover'; @@ -52,10 +50,13 @@ const ColumnSelectPopoverTrigger = ({ isTemporal, ...props }: ColumnSelectPopoverTriggerProps) => { + // @ts-ignore + const datasource = useSelector(state => state.explore.datasource); const [popoverLabel, setPopoverLabel] = useState(defaultPopoverLabel); const [popoverVisible, setPopoverVisible] = useState(false); const [isTitleEditDisabled, setIsTitleEditDisabled] = useState(true); const [hasCustomLabel, setHasCustomLabel] = useState(false); + const [showDatasetModal, setDatasetModal] = useState(false); let initialPopoverLabel = defaultPopoverLabel; if (editedColumn && isColumnMeta(editedColumn)) { @@ -99,6 +100,7 @@ const ColumnSelectPopoverTrigger = ({ <ColumnSelectPopover editedColumn={editedColumn} columns={columns} + setDatasetModal={setDatasetModal} onClose={handleClosePopover} onChange={onColumnEdit} label={popoverLabel} @@ -137,17 +139,31 @@ const ColumnSelectPopoverTrigger = ({ ); return ( - <ControlPopover - trigger="click" - content={overlayContent} - defaultVisible={visible} - visible={visible} - onVisibleChange={handleTogglePopover} - title={popoverTitle} - destroyTooltipOnHide - > - {children} - </ControlPopover> + <> + {showDatasetModal && ( + <SaveDatasetModal + visible={showDatasetModal} + onHide={() => setDatasetModal(false)} + buttonTextOnSave={t('Save')} + buttonTextOnOverwrite={t('Overwrite')} + modalDescription={t( + 'Save this query as a virtual dataset to continue exploring', + )} + datasource={datasource} + /> + )} + <ControlPopover + trigger="click" + content={overlayContent} + defaultVisible={visible} + visible={visible} + onVisibleChange={handleTogglePopover} + title={popoverTitle} + destroyTooltipOnHide + > + {children} + </ControlPopover> + </> ); }; diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndAdhocFilterOption.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndAdhocFilterOption.tsx new file mode 100644 index 0000000000000..2b9b72b459a1e --- /dev/null +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndAdhocFilterOption.tsx @@ -0,0 +1,78 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { t } from '@superset-ui/core'; +import { DndItemType } from 'src/explore/components/DndItemType'; +import AdhocFilterPopoverTrigger from 'src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import { OptionSortType } from 'src/explore/types'; +import { useGetTimeRangeLabel } from 'src/explore/components/controls/FilterControl/utils'; +import OptionWrapper from './OptionWrapper'; + +export interface DndAdhocFilterOptionProps { + adhocFilter: AdhocFilter; + onFilterEdit: (changedFilter: AdhocFilter) => void; + onClickClose: (index: number) => void; + onShiftOptions: (dragIndex: number, hoverIndex: number) => void; + options: OptionSortType[]; + datasource: Record<string, any>; + partitionColumn?: string; + index: number; +} + +export default function DndAdhocFilterOption({ + adhocFilter, + options, + datasource, + onFilterEdit, + onShiftOptions, + onClickClose, + partitionColumn, + index, +}: DndAdhocFilterOptionProps) { + const { actualTimeRange, title } = useGetTimeRangeLabel(adhocFilter); + + return ( + <AdhocFilterPopoverTrigger + key={index} + adhocFilter={adhocFilter} + options={options} + datasource={datasource} + onFilterEdit={onFilterEdit} + partitionColumn={partitionColumn} + > + <OptionWrapper + key={index} + index={index} + label={actualTimeRange ?? adhocFilter.getDefaultLabel()} + tooltipTitle={title ?? adhocFilter.getTooltipTitle()} + clickClose={onClickClose} + onShiftOptions={onShiftOptions} + type={DndItemType.FilterOption} + withCaret + isExtra={adhocFilter.isExtra} + datasourceWarningMessage={ + adhocFilter.datasourceWarning + ? t('This filter might be incompatible with current dataset') + : undefined + } + /> + </AdhocFilterPopoverTrigger> + ); +} diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.test.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.test.tsx index 37240d57caada..5cf5c59fd99fe 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.test.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.test.tsx @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import { FeatureFlag } from '@superset-ui/core'; import React from 'react'; import { render, screen } from 'spec/helpers/testing-library'; import { @@ -27,18 +28,46 @@ const defaultProps: DndColumnSelectProps = { type: 'DndColumnSelect', name: 'Filter', onChange: jest.fn(), - options: { string: { column_name: 'Column A' } }, + options: [{ column_name: 'Column A' }], actions: { setControlValue: jest.fn() }, }; -test('renders with default props', () => { - render(<DndColumnSelect {...defaultProps} />, { useDnd: true }); - expect(screen.getByText('Drop columns here')).toBeInTheDocument(); +beforeAll(() => { + window.featureFlags = { [FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP]: true }; }); -test('renders with value', () => { - render(<DndColumnSelect {...defaultProps} value="string" />, { +afterAll(() => { + window.featureFlags = {}; +}); + +test('renders with default props', async () => { + render(<DndColumnSelect {...defaultProps} />, { + useDnd: true, + useRedux: true, + }); + expect(await screen.findByText('Drop columns here')).toBeInTheDocument(); +}); + +test('renders with value', async () => { + render(<DndColumnSelect {...defaultProps} value="Column A" />, { useDnd: true, + useRedux: true, }); - expect(screen.getByText('Column A')).toBeInTheDocument(); + expect(await screen.findByText('Column A')).toBeInTheDocument(); +}); + +test('renders adhoc column', async () => { + render( + <DndColumnSelect + {...defaultProps} + value={{ + sqlExpression: 'Count *', + label: 'adhoc column', + expressionType: 'SQL', + }} + />, + { useDnd: true, useRedux: true }, + ); + expect(await screen.findByText('adhoc column')).toBeVisible(); + expect(screen.getByLabelText('calculator')).toBeVisible(); }); diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx index e7b25908cf11c..071fdbd42443c 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx @@ -23,24 +23,30 @@ import { isFeatureEnabled, tn, QueryFormColumn, + t, + isAdhocColumn, } from '@superset-ui/core'; -import { ColumnMeta, isColumnMeta } from '@superset-ui/chart-controls'; +import { + ColumnMeta, + isColumnMeta, + withDndFallback, +} from '@superset-ui/chart-controls'; import { isEmpty } from 'lodash'; import DndSelectLabel from 'src/explore/components/controls/DndColumnSelectControl/DndSelectLabel'; import OptionWrapper from 'src/explore/components/controls/DndColumnSelectControl/OptionWrapper'; import { OptionSelector } from 'src/explore/components/controls/DndColumnSelectControl/utils'; import { DatasourcePanelDndItem } from 'src/explore/components/DatasourcePanel/types'; import { DndItemType } from 'src/explore/components/DndItemType'; -import { useComponentDidUpdate } from 'src/hooks/useComponentDidUpdate'; import ColumnSelectPopoverTrigger from './ColumnSelectPopoverTrigger'; import { DndControlProps } from './types'; +import SelectControl from '../SelectControl'; export type DndColumnSelectProps = DndControlProps<QueryFormColumn> & { - options: Record<string, ColumnMeta>; + options: ColumnMeta[]; isTemporal?: boolean; }; -export function DndColumnSelect(props: DndColumnSelectProps) { +function DndColumnSelect(props: DndColumnSelectProps) { const { value, options, @@ -48,44 +54,20 @@ export function DndColumnSelect(props: DndColumnSelectProps) { onChange, canDelete = true, ghostButtonText, + clickEnabledGhostButtonText, name, label, isTemporal, } = props; const [newColumnPopoverVisible, setNewColumnPopoverVisible] = useState(false); - const optionSelector = useMemo( - () => new OptionSelector(options, multi, value), - [multi, options, value], - ); + const optionSelector = useMemo(() => { + const optionsMap = Object.fromEntries( + options.map(option => [option.column_name, option]), + ); - // synchronize values in case of dataset changes - const handleOptionsChange = useCallback(() => { - const optionSelectorValues = optionSelector.getValues(); - if (typeof value !== typeof optionSelectorValues) { - onChange(optionSelectorValues); - } - if ( - typeof value === 'string' && - typeof optionSelectorValues === 'string' && - value !== optionSelectorValues - ) { - onChange(optionSelectorValues); - } - if ( - Array.isArray(optionSelectorValues) && - Array.isArray(value) && - (optionSelectorValues.length !== value.length || - optionSelectorValues.every((val, index) => val === value[index])) - ) { - onChange(optionSelectorValues); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [JSON.stringify(value), JSON.stringify(optionSelector.getValues())]); - - // useComponentDidUpdate to avoid running this for the first render, to avoid - // calling onChange when the initial value is not valid for the dataset - useComponentDidUpdate(handleOptionsChange); + return new OptionSelector(optionsMap, multi, value); + }, [multi, options, value]); const onDrop = useCallback( (item: DatasourcePanelDndItem) => { @@ -126,15 +108,22 @@ export function DndColumnSelect(props: DndColumnSelectProps) { [onChange, optionSelector], ); - const popoverOptions = useMemo(() => Object.values(options), [options]); + const clickEnabled = useMemo( + () => isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX), + [], + ); const valuesRenderer = useCallback( () => - optionSelector.values.map((column, idx) => - isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX) ? ( + optionSelector.values.map((column, idx) => { + const datasourceWarningMessage = + isAdhocColumn(column) && column.datasourceWarning + ? t('This column might be incompatible with current dataset') + : undefined; + return clickEnabled ? ( <ColumnSelectPopoverTrigger key={idx} - columns={popoverOptions} + columns={options} onColumnEdit={newColumn => { if (isColumnMeta(newColumn)) { optionSelector.replace(idx, newColumn.column_name); @@ -154,6 +143,7 @@ export function DndColumnSelect(props: DndColumnSelectProps) { type={`${DndItemType.ColumnOption}_${name}_${label}`} canDelete={canDelete} column={column} + datasourceWarningMessage={datasourceWarningMessage} withCaret /> </ColumnSelectPopoverTrigger> @@ -166,18 +156,21 @@ export function DndColumnSelect(props: DndColumnSelectProps) { type={`${DndItemType.ColumnOption}_${name}_${label}`} canDelete={canDelete} column={column} + datasourceWarningMessage={datasourceWarningMessage} /> - ), - ), + ); + }), [ canDelete, + clickEnabled, + isTemporal, label, name, onChange, onClickClose, onShiftOptions, optionSelector, - popoverOptions, + options, ], ); @@ -205,15 +198,24 @@ export function DndColumnSelect(props: DndColumnSelectProps) { togglePopover(true); }, [togglePopover]); - const defaultGhostButtonText = isFeatureEnabled( - FeatureFlag.ENABLE_DND_WITH_CLICK_UX, - ) - ? tn( - 'Drop a column here or click', - 'Drop columns here or click', - multi ? 2 : 1, - ) - : tn('Drop column here', 'Drop columns here', multi ? 2 : 1); + const labelGhostButtonText = useMemo(() => { + if (clickEnabled) { + return ( + clickEnabledGhostButtonText ?? + ghostButtonText ?? + tn( + 'Drop a column here or click', + 'Drop columns here or click', + multi ? 2 : 1, + ) + ); + } + + return ( + ghostButtonText ?? + tn('Drop column here', 'Drop columns here', multi ? 2 : 1) + ); + }, [clickEnabled, clickEnabledGhostButtonText, ghostButtonText, multi]); return ( <div> @@ -223,16 +225,12 @@ export function DndColumnSelect(props: DndColumnSelectProps) { valuesRenderer={valuesRenderer} accept={DndItemType.Column} displayGhostButton={multi || optionSelector.values.length === 0} - ghostButtonText={ghostButtonText || defaultGhostButtonText} - onClickGhostButton={ - isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX) - ? openPopover - : undefined - } + ghostButtonText={labelGhostButtonText} + onClickGhostButton={clickEnabled ? openPopover : undefined} {...props} /> <ColumnSelectPopoverTrigger - columns={popoverOptions} + columns={options} onColumnEdit={addNewColumnWithPopover} isControlledComponent togglePopover={togglePopover} @@ -245,3 +243,10 @@ export function DndColumnSelect(props: DndColumnSelectProps) { </div> ); } + +const DndColumnSelectWithFallback = withDndFallback( + DndColumnSelect, + SelectControl, +); + +export { DndColumnSelectWithFallback as DndColumnSelect }; diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.test.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.test.tsx index 7371d7bb488a1..b6f6c6fb9c2f5 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.test.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.test.tsx @@ -17,7 +17,19 @@ * under the License. */ import React from 'react'; -import { GenericDataType } from '@superset-ui/core'; +import thunk from 'redux-thunk'; +import { Provider } from 'react-redux'; +import configureStore from 'redux-mock-store'; + +import { + ensureIsArray, + FeatureFlag, + GenericDataType, + QueryFormData, +} from '@superset-ui/core'; +import { ColumnMeta } from '@superset-ui/chart-controls'; +import { TimeseriesDefaultFormData } from '@superset-ui/plugin-chart-echarts'; + import { render, screen } from 'spec/helpers/testing-library'; import AdhocMetric from 'src/explore/components/controls/MetricControl/AdhocMetric'; import AdhocFilter, { @@ -28,7 +40,6 @@ import { DndFilterSelectProps, } from 'src/explore/components/controls/DndColumnSelectControl/DndFilterSelect'; import { PLACEHOLDER_DATASOURCE } from 'src/dashboard/constants'; -import { TimeseriesDefaultFormData } from '@superset-ui/plugin-chart-echarts'; const defaultProps: DndFilterSelectProps = { type: 'DndFilterSelect', @@ -48,76 +59,113 @@ const baseFormData = { datasource: 'table__1', }; -test('renders with default props', () => { - render(<DndFilterSelect {...defaultProps} />, { useDnd: true }); - expect(screen.getByText('Drop columns or metrics here')).toBeInTheDocument(); +beforeAll(() => { + window.featureFlags = { [FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP]: true }; +}); + +afterAll(() => { + window.featureFlags = {}; +}); + +const mockStore = configureStore([thunk]); +const store = mockStore({}); + +function setup({ + value = undefined, + formData = baseFormData, + columns = [], +}: { + value?: AdhocFilter; + formData?: QueryFormData; + columns?: ColumnMeta[]; +} = {}) { + return ( + <Provider store={store}> + <DndFilterSelect + {...defaultProps} + value={ensureIsArray(value)} + formData={formData} + columns={columns} + /> + </Provider> + ); +} + +test('renders with default props', async () => { + render(setup(), { useDnd: true }); + expect( + await screen.findByText('Drop columns or metrics here'), + ).toBeInTheDocument(); }); -test('renders with value', () => { +test('renders with value', async () => { const value = new AdhocFilter({ sqlExpression: 'COUNT(*)', expressionType: EXPRESSION_TYPES.SQL, }); - render(<DndFilterSelect {...defaultProps} value={[value]} />, { + render(setup({ value }), { useDnd: true, }); - expect(screen.getByText('COUNT(*)')).toBeInTheDocument(); + expect(await screen.findByText('COUNT(*)')).toBeInTheDocument(); }); -test('renders options with saved metric', () => { +test('renders options with saved metric', async () => { render( - <DndFilterSelect - {...defaultProps} - formData={{ + setup({ + formData: { ...baseFormData, ...TimeseriesDefaultFormData, metrics: ['saved_metric'], - }} - />, + }, + }), { useDnd: true, }, ); - expect(screen.getByText('Drop columns or metrics here')).toBeInTheDocument(); + expect( + await screen.findByText('Drop columns or metrics here'), + ).toBeInTheDocument(); }); -test('renders options with column', () => { +test('renders options with column', async () => { render( - <DndFilterSelect - {...defaultProps} - columns={[ + setup({ + columns: [ { id: 1, type: 'VARCHAR', type_generic: GenericDataType.STRING, column_name: 'Column', }, - ]} - />, + ], + }), { useDnd: true, }, ); - expect(screen.getByText('Drop columns or metrics here')).toBeInTheDocument(); + expect( + await screen.findByText('Drop columns or metrics here'), + ).toBeInTheDocument(); }); -test('renders options with adhoc metric', () => { +test('renders options with adhoc metric', async () => { const adhocMetric = new AdhocMetric({ expression: 'AVG(birth_names.num)', metric_name: 'avg__num', }); render( - <DndFilterSelect - {...defaultProps} - formData={{ + setup({ + formData: { ...baseFormData, ...TimeseriesDefaultFormData, metrics: [adhocMetric], - }} - />, + }, + }), { useDnd: true, }, ); - expect(screen.getByText('Drop columns or metrics here')).toBeInTheDocument(); + expect( + await screen.findByText('Drop columns or metrics here'), + ).toBeInTheDocument(); }); diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx index 4a08c214de8e8..134678aa6fad9 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx @@ -19,6 +19,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { FeatureFlag, + hasGenericChartAxes, isFeatureEnabled, logging, Metric, @@ -27,7 +28,13 @@ import { SupersetClient, t, } from '@superset-ui/core'; -import { ColumnMeta } from '@superset-ui/chart-controls'; +import { + ColumnMeta, + isColumnMeta, + isTemporalColumn, + withDndFallback, +} from '@superset-ui/chart-controls'; +import Modal from 'src/components/Modal'; import { OPERATOR_ENUM_TO_OPERATOR_TYPE, Operators, @@ -35,7 +42,6 @@ import { import { Datasource, OptionSortType } from 'src/explore/types'; import { OptionValueType } from 'src/explore/components/controls/DndColumnSelectControl/types'; import AdhocFilterPopoverTrigger from 'src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger'; -import OptionWrapper from 'src/explore/components/controls/DndColumnSelectControl/OptionWrapper'; import DndSelectLabel from 'src/explore/components/controls/DndColumnSelectControl/DndSelectLabel'; import AdhocFilter, { CLAUSES, @@ -49,6 +55,11 @@ import { } from 'src/explore/components/DatasourcePanel/types'; import { DndItemType } from 'src/explore/components/DndItemType'; import { ControlComponentProps } from 'src/explore/components/Control'; +import AdhocFilterControl from '../FilterControl/AdhocFilterControl'; +import DndAdhocFilterOption from './DndAdhocFilterOption'; +import { useDefaultTimeFilter } from '../DateFilterControl/utils'; + +const { warning } = Modal; const EMPTY_OBJECT = {}; const DND_ACCEPTED_TYPES = [ @@ -67,10 +78,19 @@ export interface DndFilterSelectProps savedMetrics: Metric[]; selectedMetrics: QueryFormMetric[]; datasource: Datasource; + canDelete?: ( + valueToBeDeleted: OptionValueType, + values: OptionValueType[], + ) => true | string; } -export const DndFilterSelect = (props: DndFilterSelectProps) => { - const { datasource, onChange = () => {}, name: controlName } = props; +const DndFilterSelect = (props: DndFilterSelectProps) => { + const { + datasource, + onChange = () => {}, + name: controlName, + canDelete, + } = props; const propsValues = Array.from(props.value ?? []); const [values, setValues] = useState( @@ -150,13 +170,12 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => { endpoint: `/api/v1/database/${dbId}/table_extra/${name}/${schema}/`, }) .then(({ json }: { json: Record<string, any> }) => { - if (json && json.partitions) { + if (json?.partitions) { const { partitions } = json; // for now only show latest_partition option // when table datasource has only 1 partition key. if ( - partitions && - partitions.cols && + partitions?.cols && Object.keys(partitions.cols).length === 1 ) { setPartitionColumn(partitions.cols[0]); @@ -182,7 +201,7 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => { ); }, [props.value]); - const onClickClose = useCallback( + const removeValue = useCallback( (index: number) => { const valuesCopy = [...values]; valuesCopy.splice(index, 1); @@ -192,6 +211,18 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => { [onChange, values], ); + const onClickClose = useCallback( + (index: number) => { + const result = canDelete?.(values[index], values); + if (typeof result === 'string') { + warning({ title: t('Warning'), content: result }); + return; + } + removeValue(index); + }, + [canDelete, removeValue, values], + ); + const onShiftOptions = useCallback( (dragIndex: number, hoverIndex: number) => { const newValues = [...values]; @@ -222,14 +253,8 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => { // via datasource saved metric if (filterOptions.saved_metric_name) { return new AdhocFilter({ - expressionType: - datasource.type === 'druid' - ? EXPRESSION_TYPES.SIMPLE - : EXPRESSION_TYPES.SQL, - subject: - datasource.type === 'druid' - ? filterOptions.saved_metric_name - : getMetricExpression(filterOptions.saved_metric_name), + expressionType: EXPRESSION_TYPES.SQL, + subject: getMetricExpression(filterOptions.saved_metric_name), operator: OPERATOR_ENUM_TO_OPERATOR_TYPE[Operators.GREATER_THAN].operation, operatorId: Operators.GREATER_THAN, @@ -240,14 +265,8 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => { // has a custom label, meaning it's custom column if (filterOptions.label) { return new AdhocFilter({ - expressionType: - datasource.type === 'druid' - ? EXPRESSION_TYPES.SIMPLE - : EXPRESSION_TYPES.SQL, - subject: - datasource.type === 'druid' - ? filterOptions.label - : new AdhocMetric(option).translateToSql(), + expressionType: EXPRESSION_TYPES.SQL, + subject: new AdhocMetric(option).translateToSql(), operator: OPERATOR_ENUM_TO_OPERATOR_TYPE[Operators.GREATER_THAN].operation, operatorId: Operators.GREATER_THAN, @@ -308,32 +327,18 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => { const valuesRenderer = useCallback( () => - values.map((adhocFilter: AdhocFilter, index: number) => { - const label = adhocFilter.getDefaultLabel(); - const tooltipTitle = adhocFilter.getTooltipTitle(); - return ( - <AdhocFilterPopoverTrigger - key={index} - adhocFilter={adhocFilter} - options={options} - datasource={datasource} - onFilterEdit={onFilterEdit} - partitionColumn={partitionColumn} - > - <OptionWrapper - key={index} - index={index} - label={label} - tooltipTitle={tooltipTitle} - clickClose={onClickClose} - onShiftOptions={onShiftOptions} - type={DndItemType.FilterOption} - withCaret - isExtra={adhocFilter.isExtra} - /> - </AdhocFilterPopoverTrigger> - ); - }), + values.map((adhocFilter: AdhocFilter, index: number) => ( + <DndAdhocFilterOption + index={index} + adhocFilter={adhocFilter} + options={options} + datasource={datasource} + onFilterEdit={onFilterEdit} + partitionColumn={partitionColumn} + onClickClose={onClickClose} + onShiftOptions={onShiftOptions} + /> + )), [ onClickClose, onFilterEdit, @@ -350,6 +355,7 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => { togglePopover(true); }, [togglePopover]); + const defaultTimeFilter = useDefaultTimeFilter(); const adhocFilter = useMemo(() => { if (isSavedMetric(droppedItem)) { return new AdhocFilter({ @@ -372,6 +378,15 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => { config.operator = OPERATOR_ENUM_TO_OPERATOR_TYPE[Operators.IN].operation; config.operatorId = Operators.IN; } + if ( + hasGenericChartAxes && + isColumnMeta(droppedItem) && + isTemporalColumn(droppedItem?.column_name, props.datasource) + ) { + config.operator = Operators.TEMPORAL_RANGE; + config.operatorId = Operators.TEMPORAL_RANGE; + config.comparator = defaultTimeFilter; + } return new AdhocFilter(config); }, [droppedItem]); @@ -413,9 +428,15 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => { visible={newFilterPopoverVisible} togglePopover={togglePopover} closePopover={closePopover} - > - <div /> - </AdhocFilterPopoverTrigger> + requireSave={!!droppedItem} + /> </> ); }; + +const DndFilterSelectWithFallback = withDndFallback( + DndFilterSelect, + AdhocFilterControl, +); + +export { DndFilterSelectWithFallback as DndFilterSelect }; diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.test.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.test.tsx index e16c1d0d2557c..80337344a2a1d 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.test.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.test.tsx @@ -18,6 +18,7 @@ */ import React from 'react'; import userEvent from '@testing-library/user-event'; +import { FeatureFlag } from '@superset-ui/core'; import { render, screen, @@ -67,6 +68,14 @@ const adhocMetricB = { optionName: 'def', }; +beforeAll(() => { + window.featureFlags = { [FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP]: true }; +}); + +afterAll(() => { + window.featureFlags = {}; +}); + test('renders with default props', () => { render(<DndMetricSelect {...defaultProps} />, { useDnd: true }); expect(screen.getByText('Drop column or metric here')).toBeInTheDocument(); @@ -124,6 +133,7 @@ test('remove selected custom metric when metric gets removed from dataset', () = ); expect(screen.getByText('metric_a')).toBeVisible(); expect(screen.queryByText('Metric B')).not.toBeInTheDocument(); + expect(screen.queryByText('metric_b')).not.toBeInTheDocument(); expect(screen.getByText('SUM(column_a)')).toBeVisible(); expect(screen.getByText('SUM(Column B)')).toBeVisible(); }); @@ -162,15 +172,6 @@ test('remove selected custom metric when metric gets removed from dataset for si ], }; - // rerender twice - first to update columns, second to update value - rerender( - <DndMetricSelect - {...newPropsWithRemovedMetric} - value={metricValue} - onChange={onChange} - multi={false} - />, - ); rerender( <DndMetricSelect {...newPropsWithRemovedMetric} @@ -211,15 +212,6 @@ test('remove selected adhoc metric when column gets removed from dataset', async ], }; - // rerender twice - first to update columns, second to update value - rerender( - <DndMetricSelect - {...newPropsWithRemovedColumn} - value={metricValues} - onChange={onChange} - multi - />, - ); rerender( <DndMetricSelect {...newPropsWithRemovedColumn} diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx index 0d9591a0c5ae7..32a9c3756bb18 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx @@ -22,14 +22,15 @@ import { ensureIsArray, FeatureFlag, GenericDataType, + isAdhocMetricSimple, isFeatureEnabled, + isSavedMetric, Metric, QueryFormMetric, + t, tn, } from '@superset-ui/core'; -import { ColumnMeta } from '@superset-ui/chart-controls'; -import { isEqual } from 'lodash'; -import { usePrevious } from 'src/hooks/usePrevious'; +import { ColumnMeta, withDndFallback } from '@superset-ui/chart-controls'; import AdhocMetric from 'src/explore/components/controls/MetricControl/AdhocMetric'; import AdhocMetricPopoverTrigger from 'src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger'; import MetricDefinitionValue from 'src/explore/components/controls/MetricControl/MetricDefinitionValue'; @@ -41,28 +42,54 @@ import { DndItemType } from 'src/explore/components/DndItemType'; import DndSelectLabel from 'src/explore/components/controls/DndColumnSelectControl/DndSelectLabel'; import { savedMetricType } from 'src/explore/components/controls/MetricControl/types'; import { AGGREGATES } from 'src/explore/constants'; +import MetricsControl from '../MetricControl/MetricsControl'; const EMPTY_OBJECT = {}; const DND_ACCEPTED_TYPES = [DndItemType.Column, DndItemType.Metric]; -const isDictionaryForAdhocMetric = (value: any) => - value && !(value instanceof AdhocMetric) && value.expressionType; +const isDictionaryForAdhocMetric = (value: QueryFormMetric) => + value && + !(value instanceof AdhocMetric) && + typeof value !== 'string' && + value.expressionType; -const coerceAdhocMetrics = (value: any) => { - if (!value) { +const coerceMetrics = ( + addedMetrics: QueryFormMetric | QueryFormMetric[] | undefined | null, + savedMetrics: Metric[], + columns: ColumnMeta[], +) => { + if (!addedMetrics) { return []; } - if (!Array.isArray(value)) { - if (isDictionaryForAdhocMetric(value)) { - return [new AdhocMetric(value)]; + const metricsCompatibleWithDataset = ensureIsArray(addedMetrics).filter( + metric => { + if (isSavedMetric(metric)) { + return savedMetrics.some( + savedMetric => savedMetric.metric_name === metric, + ); + } + if (isAdhocMetricSimple(metric)) { + return columns.some( + column => column.column_name === metric.column.column_name, + ); + } + return true; + }, + ); + + return metricsCompatibleWithDataset.map(metric => { + if (!isDictionaryForAdhocMetric(metric)) { + return metric; } - return [value]; - } - return value.map(val => { - if (isDictionaryForAdhocMetric(val)) { - return new AdhocMetric(val); + if (isAdhocMetricSimple(metric)) { + const column = columns.find( + col => col.column_name === metric.column.column_name, + ); + if (column) { + return new AdhocMetric({ ...metric, column }); + } } - return val; + return new AdhocMetric(metric); }); }; @@ -80,53 +107,8 @@ const getOptionsForSavedMetrics = ( type ValueType = Metric | AdhocMetric | QueryFormMetric; -// TODO: use typeguards to distinguish saved metrics from adhoc metrics -const getMetricsMatchingCurrentDataset = ( - values: ValueType[], - columns: ColumnMeta[], - savedMetrics: (savedMetricType | Metric)[], - prevColumns: ColumnMeta[], - prevSavedMetrics: (savedMetricType | Metric)[], -): ValueType[] => { - const areSavedMetricsEqual = - !prevSavedMetrics || isEqual(prevSavedMetrics, savedMetrics); - const areColsEqual = !prevColumns || isEqual(prevColumns, columns); - - if (areColsEqual && areSavedMetricsEqual) { - return values; - } - return values.reduce((acc: ValueType[], metric) => { - if (typeof metric === 'string' || (metric as Metric).metric_name) { - if ( - areSavedMetricsEqual || - savedMetrics?.some( - savedMetric => - savedMetric.metric_name === metric || - savedMetric.metric_name === (metric as Metric).metric_name, - ) - ) { - acc.push(metric); - } - return acc; - } - - if (!areColsEqual) { - const newCol = columns?.find( - column => - (metric as AdhocMetric).column?.column_name === column.column_name, - ); - if (newCol) { - acc.push({ ...(metric as AdhocMetric), column: newCol }); - } - } else { - acc.push(metric); - } - return acc; - }, []); -}; - -export const DndMetricSelect = (props: any) => { - const { onChange, multi, columns, savedMetrics } = props; +const DndMetricSelect = (props: any) => { + const { onChange, multi } = props; const handleChange = useCallback( opts => { @@ -152,39 +134,20 @@ export const DndMetricSelect = (props: any) => { ); const [value, setValue] = useState<ValueType[]>( - coerceAdhocMetrics(props.value), + coerceMetrics(props.value, props.savedMetrics, props.columns), ); const [droppedItem, setDroppedItem] = useState< DatasourcePanelDndItem | typeof EMPTY_OBJECT >({}); const [newMetricPopoverVisible, setNewMetricPopoverVisible] = useState(false); - const prevColumns = usePrevious(columns); - const prevSavedMetrics = usePrevious(savedMetrics); useEffect(() => { - setValue(coerceAdhocMetrics(props.value)); - }, [JSON.stringify(props.value)]); - - useEffect(() => { - // Remove selected custom metrics that do not exist in the dataset anymore - // Remove selected adhoc metrics that use columns which do not exist in the dataset anymore - // Sync adhoc metrics with dataset columns when they are modified by the user - if (!props.value) { - return; - } - const propsValues = ensureIsArray(props.value); - const matchingMetrics = getMetricsMatchingCurrentDataset( - propsValues, - columns, - savedMetrics, - prevColumns, - prevSavedMetrics, - ); - - if (!isEqual(propsValues, matchingMetrics)) { - handleChange(matchingMetrics); - } - }, [columns, savedMetrics, handleChange]); + setValue(coerceMetrics(props.value, props.savedMetrics, props.columns)); + }, [ + JSON.stringify(props.value), + JSON.stringify(props.savedMetrics), + JSON.stringify(props.columns), + ]); const canDrop = useCallback( (item: DatasourcePanelDndItem) => { @@ -290,6 +253,11 @@ export const DndMetricSelect = (props: any) => { onDropLabel={handleDropLabel} type={`${DndItemType.AdhocMetricOption}_${props.name}_${props.label}`} multi={multi} + datasourceWarningMessage={ + option instanceof AdhocMetric && option.datasourceWarning + ? t('This metric might be incompatible with current dataset') + : undefined + } /> ), [ @@ -360,7 +328,7 @@ export const DndMetricSelect = (props: any) => { } return new AdhocMetric(config); } - return new AdhocMetric({ isNew: true }); + return new AdhocMetric({}); }, [droppedItem]); const ghostButtonText = isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX) @@ -402,9 +370,17 @@ export const DndMetricSelect = (props: any) => { visible={newMetricPopoverVisible} togglePopover={togglePopover} closePopover={closePopover} + isNew > <div /> </AdhocMetricPopoverTrigger> </div> ); }; + +const DndMetricSelectWithFallback = withDndFallback( + DndMetricSelect, + MetricsControl, +); + +export { DndMetricSelectWithFallback as DndMetricSelect }; diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.test.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.test.tsx index 744fe03a0955c..042cd73a763b1 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.test.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.test.tsx @@ -21,47 +21,53 @@ import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import Option from 'src/explore/components/controls/DndColumnSelectControl/Option'; -test('renders with default props', () => { +test('renders with default props', async () => { const { container } = render( <Option index={1} clickClose={jest.fn()}> Option </Option>, ); expect(container).toBeInTheDocument(); - expect(screen.getByRole('img', { name: 'x-small' })).toBeInTheDocument(); + expect( + await screen.findByRole('img', { name: 'x-small' }), + ).toBeInTheDocument(); expect( screen.queryByRole('img', { name: 'caret-right' }), ).not.toBeInTheDocument(); }); -test('renders with caret', () => { +test('renders with caret', async () => { render( <Option index={1} clickClose={jest.fn()} withCaret> Option </Option>, ); - expect(screen.getByRole('img', { name: 'x-small' })).toBeInTheDocument(); - expect(screen.getByRole('img', { name: 'caret-right' })).toBeInTheDocument(); + expect( + await screen.findByRole('img', { name: 'x-small' }), + ).toBeInTheDocument(); + expect( + await screen.findByRole('img', { name: 'caret-right' }), + ).toBeInTheDocument(); }); -test('renders with extra triangle', () => { +test('renders with extra triangle', async () => { render( <Option index={1} clickClose={jest.fn()} isExtra> Option </Option>, ); expect( - screen.getByRole('button', { name: 'Show info tooltip' }), + await screen.findByRole('button', { name: 'Show info tooltip' }), ).toBeInTheDocument(); }); -test('triggers onClose', () => { +test('triggers onClose', async () => { const clickClose = jest.fn(); render( <Option index={1} clickClose={clickClose}> Option </Option>, ); - userEvent.click(screen.getByRole('img', { name: 'x-small' })); + userEvent.click(await screen.findByRole('img', { name: 'x-small' })); expect(clickClose).toHaveBeenCalled(); }); diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx index 3c7ee3c7c14bc..3de910c1375f7 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx @@ -38,6 +38,7 @@ export default function Option({ clickClose, withCaret, isExtra, + datasourceWarningMessage, canDelete = true, }: OptionProps) { const theme = useTheme(); @@ -60,15 +61,18 @@ export default function Option({ </CloseContainer> )} <Label data-test="control-label">{children}</Label> - {isExtra && ( + {(!!datasourceWarningMessage || isExtra) && ( <StyledInfoTooltipWithTrigger icon="exclamation-triangle" placement="top" bsStyle="warning" - tooltip={t(` + tooltip={ + datasourceWarningMessage || + t(` This filter was inherited from the dashboard's context. It won't be saved when saving the chart. - `)} + `) + } /> )} {withCaret && ( diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.test.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.test.tsx index e237cea989a5c..d7d362996fe1e 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.test.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.test.tsx @@ -21,7 +21,7 @@ import { render, screen, fireEvent } from 'spec/helpers/testing-library'; import { DndItemType } from 'src/explore/components/DndItemType'; import OptionWrapper from 'src/explore/components/controls/DndColumnSelectControl/OptionWrapper'; -test('renders with default props', () => { +test('renders with default props', async () => { const { container } = render( <OptionWrapper index={1} @@ -33,10 +33,12 @@ test('renders with default props', () => { { useDnd: true }, ); expect(container).toBeInTheDocument(); - expect(screen.getByRole('img', { name: 'x-small' })).toBeInTheDocument(); + expect( + await screen.findByRole('img', { name: 'x-small' }), + ).toBeInTheDocument(); }); -test('triggers onShiftOptions on drop', () => { +test('triggers onShiftOptions on drop', async () => { const onShiftOptions = jest.fn(); render( <> @@ -58,7 +60,7 @@ test('triggers onShiftOptions on drop', () => { { useDnd: true }, ); - fireEvent.dragStart(screen.getByText('Option 1')); - fireEvent.drop(screen.getByText('Option 2')); + fireEvent.dragStart(await screen.findByText('Option 1')); + fireEvent.drop(await screen.findByText('Option 2')); expect(onShiftOptions).toHaveBeenCalled(); }); diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.tsx index 18cd57645eca5..e2272288326a9 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.tsx @@ -30,8 +30,8 @@ import { } from 'src/explore/components/controls/DndColumnSelectControl/types'; import { Tooltip } from 'src/components/Tooltip'; import { StyledColumnOption } from 'src/explore/components/optionRenderers'; -import { styled } from '@superset-ui/core'; -import { ColumnMeta, isAdhocColumn } from '@superset-ui/chart-controls'; +import { styled, isAdhocColumn } from '@superset-ui/core'; +import { ColumnMeta } from '@superset-ui/chart-controls'; import Option from './Option'; export const OptionLabel = styled.div` @@ -57,6 +57,7 @@ export default function OptionWrapper( clickClose, withCaret, isExtra, + datasourceWarningMessage, canDelete = true, ...rest } = props; @@ -176,6 +177,7 @@ export default function OptionWrapper( clickClose={clickClose} withCaret={withCaret} isExtra={isExtra} + datasourceWarningMessage={datasourceWarningMessage} canDelete={canDelete} > <Label /> diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts index b2c9bd953b981..f1658b5ae3e0a 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts @@ -30,6 +30,7 @@ export interface OptionProps { clickClose: (index: number) => void; withCaret?: boolean; isExtra?: boolean; + datasourceWarningMessage?: string; canDelete?: boolean; } @@ -46,6 +47,7 @@ export type DndControlProps<ValueType extends JsonValue> = multi?: boolean; canDelete?: boolean; ghostButtonText?: string; + clickEnabledGhostButtonText?: string; onChange: (value: ValueType | ValueType[] | null | undefined) => void; }; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/AdhocFilter.test.js b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/AdhocFilter.test.js index 2aa5fd1604189..f3e08d7a28ae3 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/AdhocFilter.test.js +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/AdhocFilter.test.js @@ -36,6 +36,7 @@ describe('AdhocFilter', () => { expressionType: EXPRESSION_TYPES.SIMPLE, subject: 'value', operator: '>', + datasourceWarning: false, comparator: '10', clause: CLAUSES.WHERE, filterOptionName: adhocFilter.filterOptionName, diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/index.js b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/index.js index 5b6278bde2679..3b54a7dc1a7aa 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/index.js +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/index.js @@ -62,7 +62,9 @@ function translateToSql(adhocMetric, { useSimple } = {}) { const { subject, comparator } = adhocMetric; const operator = adhocMetric.operator && - CUSTOM_OPERATIONS.indexOf(adhocMetric.operator) >= 0 + // 'LATEST PARTITION' supported callback only + adhocMetric.operator === + OPERATOR_ENUM_TO_OPERATOR_TYPE[Operators.LATEST_PARTITION].operation ? OPERATORS_TO_SQL[adhocMetric.operator](adhocMetric) : OPERATORS_TO_SQL[adhocMetric.operator]; return getSimpleSQLExpression(subject, operator, comparator); @@ -118,6 +120,7 @@ export default class AdhocFilter { } this.isExtra = !!adhocFilter.isExtra; this.isNew = !!adhocFilter.isNew; + this.datasourceWarning = !!adhocFilter.datasourceWarning; this.filterOptionName = adhocFilter.filterOptionName || diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx index 876eca1e75b4d..c0750c7805d00 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx @@ -42,6 +42,7 @@ import { LabelsContainer, } from 'src/explore/components/controls/OptionControls'; import Icons from 'src/components/Icons'; +import Modal from 'src/components/Modal'; import AdhocFilterPopoverTrigger from 'src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger'; import AdhocFilterOption from 'src/explore/components/controls/FilterControl/AdhocFilterOption'; import AdhocFilter, { @@ -51,6 +52,8 @@ import AdhocFilter, { import adhocFilterType from 'src/explore/components/controls/FilterControl/adhocFilterType'; import columnType from 'src/explore/components/controls/FilterControl/columnType'; +const { warning } = Modal; + const selectedMetricType = PropTypes.oneOfType([ PropTypes.string, adhocMetricType, @@ -71,6 +74,7 @@ const propTypes = { PropTypes.arrayOf(selectedMetricType), ]), isLoading: PropTypes.bool, + canDelete: PropTypes.func, }; const defaultProps = { @@ -96,6 +100,7 @@ class AdhocFilterControl extends React.Component { this.onChange = this.onChange.bind(this); this.mapOption = this.mapOption.bind(this); this.getMetricExpression = this.getMetricExpression.bind(this); + this.removeFilter = this.removeFilter.bind(this); const filters = (this.props.value || []).map(filter => isDictionaryForAdhocFilter(filter) ? new AdhocFilter(filter) : filter, @@ -112,7 +117,10 @@ class AdhocFilterControl extends React.Component { sections={this.props.sections} operators={this.props.operators} datasource={this.props.datasource} - onRemoveFilter={() => this.onRemoveFilter(index)} + onRemoveFilter={e => { + e.stopPropagation(); + this.onRemoveFilter(index); + }} onMoveLabel={this.moveLabel} onDropLabel={() => this.props.onChange(this.state.values)} partitionColumn={this.state.partitionColumn} @@ -173,7 +181,7 @@ class AdhocFilterControl extends React.Component { } } - onRemoveFilter(index) { + removeFilter(index) { const valuesCopy = [...this.state.values]; valuesCopy.splice(index, 1); this.setState(prevState => ({ @@ -183,6 +191,17 @@ class AdhocFilterControl extends React.Component { this.props.onChange(valuesCopy); } + onRemoveFilter(index) { + const { canDelete } = this.props; + const { values } = this.state; + const result = canDelete?.(values[index], values); + if (typeof result === 'string') { + warning({ title: t('Warning'), content: result }); + return; + } + this.removeFilter(index); + } + onNewFilter(newFilter) { const mappedOption = this.mapOption(newFilter); if (mappedOption) { @@ -241,14 +260,8 @@ class AdhocFilterControl extends React.Component { // via datasource saved metric if (option.saved_metric_name) { return new AdhocFilter({ - expressionType: - this.props.datasource.type === 'druid' - ? EXPRESSION_TYPES.SIMPLE - : EXPRESSION_TYPES.SQL, - subject: - this.props.datasource.type === 'druid' - ? option.saved_metric_name - : this.getMetricExpression(option.saved_metric_name), + expressionType: EXPRESSION_TYPES.SQL, + subject: this.getMetricExpression(option.saved_metric_name), operator: OPERATOR_ENUM_TO_OPERATOR_TYPE[Operators.GREATER_THAN].operation, comparator: 0, @@ -258,14 +271,8 @@ class AdhocFilterControl extends React.Component { // has a custom label, meaning it's custom column if (option.label) { return new AdhocFilter({ - expressionType: - this.props.datasource.type === 'druid' - ? EXPRESSION_TYPES.SIMPLE - : EXPRESSION_TYPES.SQL, - subject: - this.props.datasource.type === 'druid' - ? option.label - : new AdhocMetric(option).translateToSql(), + expressionType: EXPRESSION_TYPES.SQL, + subject: new AdhocMetric(option).translateToSql(), operator: OPERATOR_ENUM_TO_OPERATOR_TYPE[Operators.GREATER_THAN].operation, comparator: 0, diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/AdhocFilterEditPopover.test.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/AdhocFilterEditPopover.test.jsx index 907d78ff64386..3fec073f94660 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/AdhocFilterEditPopover.test.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/AdhocFilterEditPopover.test.jsx @@ -122,7 +122,7 @@ describe('AdhocFilterEditPopover', () => { it('prevents saving if the filter is invalid', () => { const { wrapper } = setup(); - expect(wrapper.find(Button).find({ disabled: true })).not.toExist(); + expect(wrapper.find(Button).find({ disabled: true })).toExist(); wrapper .instance() .onAdhocFilterChange(simpleAdhocFilter.duplicateWith({ operator: null })); @@ -133,7 +133,6 @@ describe('AdhocFilterEditPopover', () => { it('highlights save if changes are present', () => { const { wrapper } = setup(); - expect(wrapper.find(Button).find({ buttonStyle: 'primary' })).not.toExist(); wrapper.instance().onAdhocFilterChange(sqlAdhocFilter); expect(wrapper.find(Button).find({ buttonStyle: 'primary' })).toExist(); }); diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx index 8ae706fc54de5..98c6da8f1c004 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx @@ -19,7 +19,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import Button from 'src/components/Button'; -import { Tooltip } from 'src/components/Tooltip'; import { styled, t } from '@superset-ui/core'; import ErrorBoundary from 'src/components/ErrorBoundary'; @@ -53,6 +52,7 @@ const propTypes = { theme: PropTypes.object, sections: PropTypes.arrayOf(PropTypes.string), operators: PropTypes.arrayOf(PropTypes.string), + requireSave: PropTypes.bool, }; const ResizeIcon = styled.i` @@ -182,12 +182,14 @@ export default class AdhocFilterEditPopover extends React.Component { partitionColumn, theme, operators, + requireSave, ...popoverProps } = this.props; const { adhocFilter } = this.state; const stateIsValid = adhocFilter.isValid(); - const hasUnsavedChanges = !adhocFilter.equals(propsAdhocFilter); + const hasUnsavedChanges = + requireSave || !adhocFilter.equals(propsAdhocFilter); return ( <FilterPopoverContentContainer @@ -227,20 +229,7 @@ export default class AdhocFilterEditPopover extends React.Component { <Tabs.TabPane className="adhoc-filter-edit-tab" key={EXPRESSION_TYPES.SQL} - tab={ - datasource?.type === 'druid' ? ( - <Tooltip - title={t( - 'Custom SQL ad-hoc filters are not available for the native Druid connector', - )} - > - {t('Custom SQL')} - </Tooltip> - ) : ( - t('Custom SQL') - ) - } - disabled={datasource?.type === 'druid'} + tab={t('Custom SQL')} > <ErrorBoundary> <AdhocFilterEditPopoverSqlTabContent @@ -259,10 +248,12 @@ export default class AdhocFilterEditPopover extends React.Component { </Button> <Button data-test="adhoc-filter-edit-popover-save-button" - disabled={!stateIsValid || !this.state.isSimpleTabValid} - buttonStyle={ - hasUnsavedChanges && stateIsValid ? 'primary' : 'default' + disabled={ + !stateIsValid || + !this.state.isSimpleTabValid || + !hasUnsavedChanges } + buttonStyle="primary" buttonSize="small" className="m-r-5" onClick={this.onSave} diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/AdhocFilterEditPopoverSimpleTabContent.test.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/AdhocFilterEditPopoverSimpleTabContent.test.tsx index a34a77c44217f..9d1b68bc6f75d 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/AdhocFilterEditPopoverSimpleTabContent.test.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/AdhocFilterEditPopoverSimpleTabContent.test.tsx @@ -18,8 +18,12 @@ */ /* eslint-disable no-unused-expressions */ import React from 'react'; +import * as redux from 'react-redux'; import sinon from 'sinon'; import { shallow } from 'enzyme'; +import thunk from 'redux-thunk'; +import { Provider } from 'react-redux'; +import configureStore from 'redux-mock-store'; import AdhocFilter, { EXPRESSION_TYPES, @@ -37,6 +41,7 @@ import * as featureFlags from 'src/featureFlags'; import userEvent from '@testing-library/user-event'; import fetchMock from 'fetch-mock'; +import { TestDataset } from '@superset-ui/chart-controls'; import AdhocFilterEditPopoverSimpleTabContent, { useSimpleTabFilterProps, Props, @@ -99,10 +104,11 @@ const getAdvancedDataTypeTestProps = (overrides?: Record<string, any>) => { onChange, options: [{ type: 'DOUBLE', column_name: 'advancedDataType', id: 5 }], datasource: { - id: 'test-id', - columns: [], - type: 'postgres', - filter_select: false, + ...TestDataset, + ...{ + columns: [], + filter_select: false, + }, }, partitionColumn: 'test', ...overrides, @@ -114,15 +120,18 @@ const getAdvancedDataTypeTestProps = (overrides?: Record<string, any>) => { function setup(overrides?: Record<string, any>) { const onChange = sinon.spy(); const validHandler = sinon.spy(); + const spy = jest.spyOn(redux, 'useSelector'); + spy.mockReturnValue({}); const props = { adhocFilter: simpleAdhocFilter, onChange, options, datasource: { - id: 'test-id', - columns: [], - type: 'postgres', - filter_select: false, + ...TestDataset, + ...{ + columns: [], + filter_select: false, + }, }, partitionColumn: 'test', ...overrides, @@ -235,17 +244,9 @@ describe('AdhocFilterEditPopoverSimpleTabContent', () => { it('will filter operators for table datasources', () => { const { props } = setup({ datasource: { type: 'table' } }); const { isOperatorRelevant } = useSimpleTabFilterProps(props); - expect(isOperatorRelevant(Operators.REGEX, 'value')).toBe(false); expect(isOperatorRelevant(Operators.LIKE, 'value')).toBe(true); }); - it('will filter operators for druid datasources', () => { - const { props } = setup({ datasource: { type: 'druid' } }); - const { isOperatorRelevant } = useSimpleTabFilterProps(props); - expect(isOperatorRelevant(Operators.REGEX, 'value')).toBe(true); - expect(isOperatorRelevant(Operators.LIKE, 'value')).toBe(false); - }); - it('will show LATEST PARTITION operator', () => { const { props } = setup({ datasource: { @@ -380,14 +381,19 @@ fetchMock.get(ADVANCED_DATA_TYPE_ENDPOINT_INVALID, { values: [], }, }); +const mockStore = configureStore([thunk]); +const store = mockStore({}); describe('AdhocFilterEditPopoverSimpleTabContent Advanced data Type Test', () => { const setupFilter = async (props: Props) => { await act(async () => { render( - <ThemeProvider theme={supersetTheme}> - <AdhocFilterEditPopoverSimpleTabContent {...props} /> - </ThemeProvider>, + <Provider store={store}> + <ThemeProvider theme={supersetTheme}> + <AdhocFilterEditPopoverSimpleTabContent {...props} /> + </ThemeProvider> + , + </Provider>, ); }); }; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx index cb432318bbc12..e65e25b9b3756 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx @@ -19,12 +19,17 @@ import React, { useEffect, useState } from 'react'; import FormItem from 'src/components/Form/FormItem'; import { Select } from 'src/components'; -import { t, SupersetClient, SupersetTheme, styled } from '@superset-ui/core'; +import { + t, + SupersetClient, + SupersetTheme, + styled, + hasGenericChartAxes, + isDefined, +} from '@superset-ui/core'; import { Operators, OPERATORS_OPTIONS, - TABLE_ONLY_OPERATORS, - DRUID_ONLY_OPERATORS, HAVING_OPERATORS, MULTI_OPERATORS, CUSTOM_OPERATORS, @@ -41,7 +46,14 @@ import { Tooltip } from 'src/components/Tooltip'; import { Input } from 'src/components/Input'; import { optionLabel } from 'src/utils/common'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; +import { + ColumnMeta, + Dataset, + isTemporalColumn, +} from '@superset-ui/chart-controls'; import useAdvancedDataTypes from './useAdvancedDataTypes'; +import { useDatePickerInAdhocFilter } from '../utils'; +import { useDefaultTimeFilter } from '../../DateFilterControl/utils'; const StyledInput = styled(Input)` margin-bottom: ${({ theme }) => theme.gridUnit * 4}px; @@ -63,20 +75,9 @@ const SelectWithLabel = styled(Select)<{ labelText: string }>` } `; -export interface SimpleColumnType { - id: number; - column_name: string; - expression?: string; - type: string; - optionName?: string; - filterBy?: string; - value?: string; - advanced_data_type?: string; -} - export interface SimpleExpressionType { expressionType: keyof typeof EXPRESSION_TYPES; - column: SimpleColumnType; + column: ColumnMeta; aggregate: keyof typeof AGGREGATES; label: string; } @@ -91,7 +92,7 @@ export interface MetricColumnType { } export type ColumnType = - | SimpleColumnType + | ColumnMeta | SimpleExpressionType | SQLExpressionType | MetricColumnType; @@ -100,12 +101,7 @@ export interface Props { adhocFilter: AdhocFilter; onChange: (filter: AdhocFilter) => void; options: ColumnType[]; - datasource: { - id: string; - columns: SimpleColumnType[]; - type: string; - filter_select: boolean; - }; + datasource: Dataset; partitionColumn: string; operators?: Operators[]; validHandler: (isValid: boolean) => void; @@ -119,6 +115,8 @@ export interface AdvancedDataTypesState { } export const useSimpleTabFilterProps = (props: Props) => { + const defaultTimeFilter = useDefaultTimeFilter(); + const isOperatorRelevant = (operator: Operators, subject: string) => { const column = props.datasource.columns?.find( col => col.column_name === subject, @@ -129,10 +127,14 @@ export const useSimpleTabFilterProps = (props: Props) => { !!column && (column.type === 'INT' || column.type === 'INTEGER'); const isColumnFunction = !!column && !!column.expression; - if (operator && CUSTOM_OPERATORS.has(operator)) { + if (operator && operator === Operators.LATEST_PARTITION) { const { partitionColumn } = props; return partitionColumn && subject && subject === partitionColumn; } + if (operator && operator === Operators.TEMPORAL_RANGE) { + // hide the TEMPORAL_RANGE operator + return false; + } if (operator === Operators.IS_TRUE || operator === Operators.IS_FALSE) { return isColumnBoolean || isColumnNumber || isColumnFunction; } @@ -141,13 +143,9 @@ export const useSimpleTabFilterProps = (props: Props) => { operator === Operators.IS_NULL || operator === Operators.IS_NOT_NULL ); } - return !( - (props.datasource.type === 'druid' && - TABLE_ONLY_OPERATORS.indexOf(operator) >= 0) || - (props.datasource.type === 'table' && - DRUID_ONLY_OPERATORS.indexOf(operator) >= 0) || - (props.adhocFilter.clause === CLAUSES.HAVING && - HAVING_OPERATORS.indexOf(operator) === -1) + return ( + props.adhocFilter.clause !== CLAUSES.HAVING || + HAVING_OPERATORS.indexOf(operator) !== -1 ); }; const onSubjectChange = (id: string) => { @@ -165,21 +163,37 @@ export const useSimpleTabFilterProps = (props: Props) => { } else if (option && 'saved_metric_name' in option) { subject = option.saved_metric_name; clause = CLAUSES.HAVING; - } else if (option && option.label) { + } else if (option?.label) { subject = option.label; clause = CLAUSES.HAVING; } - const { operator, operatorId } = props.adhocFilter; + let { operator, operatorId, comparator } = props.adhocFilter; + operator = + operator && operatorId && isOperatorRelevant(operatorId, subject) + ? OPERATOR_ENUM_TO_OPERATOR_TYPE[operatorId].operation + : null; + if (!isDefined(operator)) { + // if operator is `null`, use the `IN` and reset the comparator. + operator = Operators.IN; + operatorId = Operators.IN; + comparator = undefined; + } + + if (hasGenericChartAxes && isTemporalColumn(id, props.datasource)) { + subject = id; + operator = Operators.TEMPORAL_RANGE; + operatorId = Operators.TEMPORAL_RANGE; + comparator = defaultTimeFilter; + } + props.onChange( props.adhocFilter.duplicateWith({ subject, clause, - operator: - operator && operatorId && isOperatorRelevant(operatorId, subject) - ? OPERATOR_ENUM_TO_OPERATOR_TYPE[operatorId].operation - : null, + operator, expressionType: EXPRESSION_TYPES.SIMPLE, operatorId, + comparator, }), ); }; @@ -238,12 +252,23 @@ export const useSimpleTabFilterProps = (props: Props) => { }), ); }; + const onDatePickerChange = (columnName: string, timeRange: string) => { + props.onChange( + props.adhocFilter.duplicateWith({ + subject: columnName, + operator: Operators.TEMPORAL_RANGE, + comparator: timeRange, + expressionType: EXPRESSION_TYPES.SIMPLE, + }), + ); + }; return { onSubjectChange, onOperatorChange, onComparatorChange, isOperatorRelevant, clearOperator, + onDatePickerChange, }; }; @@ -253,6 +278,7 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => { onOperatorChange, isOperatorRelevant, onComparatorChange, + onDatePickerChange, } = useSimpleTabFilterProps(props); const [suggestions, setSuggestions] = useState< Record<'label' | 'value', any>[] @@ -317,23 +343,13 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => { placeholder: '', }; - if (props.datasource.type === 'druid') { - subjectSelectProps.placeholder = t( - '%s column(s) and metric(s)', - columns.length, - ); - } else { - // we cannot support simple ad-hoc filters for metrics because we don't know what type - // the value should be cast to (without knowing the output type of the aggregate, which - // becomes a rather complicated problem) - subjectSelectProps.placeholder = - props.adhocFilter.clause === CLAUSES.WHERE - ? t('%s column(s)', columns.length) - : t('To filter on a metric, use Custom SQL tab.'); - columns = props.options.filter( - option => 'column_name' in option && option.column_name, - ); - } + subjectSelectProps.placeholder = + props.adhocFilter.clause === CLAUSES.WHERE + ? t('%s column(s)', columns.length) + : t('To filter on a metric, use Custom SQL tab.'); + columns = props.options.filter( + option => 'column_name' in option && option.column_name, + ); const operatorSelectProps = { placeholder: t( @@ -370,6 +386,16 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => { const labelText = comparator && comparator.length > 0 && createSuggestionsPlaceholder(); + const datePicker = useDatePickerInAdhocFilter({ + columnName: props.adhocFilter.subject, + timeRange: + props.adhocFilter.operator === Operators.TEMPORAL_RANGE + ? props.adhocFilter.comparator + : undefined, + datasource: props.datasource, + onChange: onDatePickerChange, + }); + useEffect(() => { const refreshComparatorSuggestions = () => { const { datasource } = props; @@ -385,14 +411,16 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => { setLoadingComparatorSuggestions(true); SupersetClient.get({ signal, - endpoint: `/superset/filter/${datasource.type}/${datasource.id}/${col}/`, + endpoint: `/api/v1/datasource/${datasource.type}/${datasource.id}/column/${col}/values/`, }) .then(({ json }) => { setSuggestions( - json.map((suggestion: null | number | boolean | string) => ({ - value: suggestion, - label: optionLabel(suggestion), - })), + json.result.map( + (suggestion: null | number | boolean | string) => ({ + value: suggestion, + label: optionLabel(suggestion), + }), + ), ); setLoadingComparatorSuggestions(false); }) @@ -402,7 +430,9 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => { }); } }; - refreshComparatorSuggestions(); + if (!datePicker) { + refreshComparatorSuggestions(); + } }, [props.adhocFilter.subject]); useEffect(() => { @@ -427,31 +457,35 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => { } }, [props.adhocFilter.comparator]); - return ( + // another name for columns, just for following previous naming. + const subjectComponent = ( + <Select + css={(theme: SupersetTheme) => ({ + marginTop: theme.gridUnit * 4, + marginBottom: theme.gridUnit * 4, + })} + data-test="select-element" + options={columns.map(column => ({ + value: + ('column_name' in column && column.column_name) || + ('optionName' in column && column.optionName) || + '', + label: + ('saved_metric_name' in column && column.saved_metric_name) || + ('column_name' in column && column.column_name) || + ('label' in column && column.label), + key: + ('id' in column && column.id) || + ('optionName' in column && column.optionName) || + undefined, + customLabel: renderSubjectOptionLabel(column), + }))} + {...subjectSelectProps} + /> + ); + + const operatorsAndOperandComponent = ( <> - <Select - css={(theme: SupersetTheme) => ({ - marginTop: theme.gridUnit * 4, - marginBottom: theme.gridUnit * 4, - })} - data-test="select-element" - options={columns.map(column => ({ - value: - ('column_name' in column && column.column_name) || - ('optionName' in column && column.optionName) || - '', - label: - ('saved_metric_name' in column && column.saved_metric_name) || - ('column_name' in column && column.column_name) || - ('label' in column && column.label), - key: - ('id' in column && column.id) || - ('optionName' in column && column.optionName) || - undefined, - customLabel: renderSubjectOptionLabel(column), - }))} - {...subjectSelectProps} - /> <Select css={(theme: SupersetTheme) => ({ marginBottom: theme.gridUnit * 4 })} options={(props.operators ?? OPERATORS_OPTIONS) @@ -501,6 +535,12 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => { )} </> ); + return ( + <> + {subjectComponent} + {datePicker ?? operatorsAndOperandComponent} + </> + ); }; export default AdhocFilterEditPopoverSimpleTabContent; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/AdhocFilterOption.test.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/AdhocFilterOption.test.tsx index 34ec66d087dda..8513f452e58d8 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/AdhocFilterOption.test.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/AdhocFilterOption.test.tsx @@ -19,13 +19,11 @@ import React from 'react'; import { render, screen, waitFor } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; -import { HTML5Backend } from 'react-dnd-html5-backend'; -import { DndProvider } from 'react-dnd'; import AdhocFilter, { EXPRESSION_TYPES, CLAUSES, } from 'src/explore/components/controls/FilterControl/AdhocFilter'; -import AdhocFilterOption from '.'; +import AdhocFilterOption, { AdhocFilterOptionProps } from '.'; const simpleAdhocFilter = new AdhocFilter({ expressionType: EXPRESSION_TYPES.SIMPLE, @@ -44,48 +42,49 @@ const options = [ const mockedProps = { adhocFilter: simpleAdhocFilter, onFilterEdit: jest.fn(), + onRemoveFilter: jest.fn(), options, + sections: [], + operators: [], + datasource: {}, + partitionColumn: '', + onMoveLabel: jest.fn(), + onDropLabel: jest.fn(), + index: 1, }; -const setup = (props: { - adhocFilter: typeof simpleAdhocFilter; - onFilterEdit: () => void; - options: { - type: string; - column_name: string; - id: number; - }[]; -}) => ( - <DndProvider backend={HTML5Backend}> - <AdhocFilterOption {...props} /> - </DndProvider> +const setup = (props: AdhocFilterOptionProps) => ( + <AdhocFilterOption {...props} /> ); test('should render', async () => { - const { container } = render(setup(mockedProps)); + const { container } = render(setup(mockedProps), { + useDnd: true, + useRedux: true, + }); await waitFor(() => expect(container).toBeInTheDocument()); }); test('should render the control label', async () => { - render(setup(mockedProps)); + render(setup(mockedProps), { useDnd: true, useRedux: true }); expect(await screen.findByText('value > 10')).toBeInTheDocument(); }); test('should render the remove button', async () => { - render(setup(mockedProps)); + render(setup(mockedProps), { useDnd: true, useRedux: true }); const removeBtn = await screen.findByRole('button'); expect(removeBtn).toBeInTheDocument(); }); test('should render the right caret', async () => { - render(setup(mockedProps)); + render(setup(mockedProps), { useDnd: true, useRedux: true }); expect( await screen.findByRole('img', { name: 'caret-right' }), ).toBeInTheDocument(); }); test('should render the Popover on clicking the right caret', async () => { - render(setup(mockedProps)); + render(setup(mockedProps), { useDnd: true, useRedux: true }); const rightCaret = await screen.findByRole('img', { name: 'caret-right' }); userEvent.click(rightCaret); expect(screen.getByRole('tooltip')).toBeInTheDocument(); diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/index.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/index.jsx deleted file mode 100644 index c9f90b7b29a48..0000000000000 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/index.jsx +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import PropTypes from 'prop-types'; -import adhocMetricType from 'src/explore/components/controls/MetricControl/adhocMetricType'; -import { OptionControlLabel } from 'src/explore/components/controls/OptionControls'; -import { DndItemType } from 'src/explore/components/DndItemType'; -import columnType from 'src/explore/components/controls/FilterControl/columnType'; -import AdhocFilterPopoverTrigger from 'src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger'; -import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; - -const propTypes = { - adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired, - onFilterEdit: PropTypes.func.isRequired, - onRemoveFilter: PropTypes.func, - options: PropTypes.arrayOf( - PropTypes.oneOfType([ - columnType, - PropTypes.shape({ saved_metric_name: PropTypes.string.isRequired }), - adhocMetricType, - ]), - ).isRequired, - sections: PropTypes.arrayOf(PropTypes.string), - operators: PropTypes.arrayOf(PropTypes.string), - datasource: PropTypes.object, - partitionColumn: PropTypes.string, - onMoveLabel: PropTypes.func, - onDropLabel: PropTypes.func, - index: PropTypes.number, -}; - -const AdhocFilterOption = ({ - adhocFilter, - options, - datasource, - onFilterEdit, - onRemoveFilter, - partitionColumn, - onMoveLabel, - onDropLabel, - index, - sections, - operators, -}) => ( - <AdhocFilterPopoverTrigger - sections={sections} - operators={operators} - adhocFilter={adhocFilter} - options={options} - datasource={datasource} - onFilterEdit={onFilterEdit} - partitionColumn={partitionColumn} - > - <OptionControlLabel - label={adhocFilter.getDefaultLabel()} - tooltipTitle={adhocFilter.getTooltipTitle()} - onRemove={onRemoveFilter} - onMoveLabel={onMoveLabel} - onDropLabel={onDropLabel} - index={index} - type={DndItemType.FilterOption} - withCaret - isExtra={adhocFilter.isExtra} - /> - </AdhocFilterPopoverTrigger> -); - -export default AdhocFilterOption; - -AdhocFilterOption.propTypes = propTypes; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/index.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/index.tsx new file mode 100644 index 0000000000000..a8bffe9dd5cf6 --- /dev/null +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/index.tsx @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { OptionControlLabel } from 'src/explore/components/controls/OptionControls'; +import { DndItemType } from 'src/explore/components/DndItemType'; +import AdhocFilterPopoverTrigger from 'src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import { OptionSortType } from 'src/explore/types'; +import { Operators } from 'src/explore/constants'; +import { useGetTimeRangeLabel } from '../utils'; + +export interface AdhocFilterOptionProps { + adhocFilter: AdhocFilter; + onFilterEdit: () => void; + onRemoveFilter: () => void; + options: OptionSortType[]; + sections: string[]; + operators: Operators[]; + datasource: Record<string, any>; + partitionColumn: string; + onMoveLabel: () => void; + onDropLabel: () => void; + index: number; +} + +export default function AdhocFilterOption({ + adhocFilter, + options, + datasource, + onFilterEdit, + onRemoveFilter, + partitionColumn, + onMoveLabel, + onDropLabel, + index, + sections, + operators, +}: AdhocFilterOptionProps) { + const { actualTimeRange, title } = useGetTimeRangeLabel(adhocFilter); + + return ( + <AdhocFilterPopoverTrigger + sections={sections} + operators={operators} + adhocFilter={adhocFilter} + options={options} + datasource={datasource} + onFilterEdit={onFilterEdit} + partitionColumn={partitionColumn} + > + <OptionControlLabel + label={actualTimeRange ?? adhocFilter.getDefaultLabel()} + tooltipTitle={title ?? adhocFilter.getTooltipTitle()} + onRemove={onRemoveFilter} + onMoveLabel={onMoveLabel} + onDropLabel={onDropLabel} + index={index} + type={DndItemType.FilterOption} + withCaret + isExtra={adhocFilter.isExtra} + /> + </AdhocFilterPopoverTrigger> + ); +} diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/index.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/index.tsx index 5dd6993c12018..931a69657dfba 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/index.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/index.tsx @@ -36,6 +36,7 @@ interface AdhocFilterPopoverTriggerProps { visible?: boolean; togglePopover?: (visible: boolean) => void; closePopover?: () => void; + requireSave?: boolean; } interface AdhocFilterPopoverTriggerState { @@ -96,6 +97,7 @@ class AdhocFilterPopoverTrigger extends React.PureComponent< sections={this.props.sections} operators={this.props.operators} onChange={this.props.onFilterEdit} + requireSave={this.props.requireSave} /> </ExplorePopoverContent> ); diff --git a/superset-frontend/src/explore/components/controls/FilterControl/utils/index.ts b/superset-frontend/src/explore/components/controls/FilterControl/utils/index.ts new file mode 100644 index 0000000000000..f2d580c9785da --- /dev/null +++ b/superset-frontend/src/explore/components/controls/FilterControl/utils/index.ts @@ -0,0 +1,20 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +export { useGetTimeRangeLabel } from './useGetTimeRangeLabel'; +export { useDatePickerInAdhocFilter } from './useDatePickerInAdhocFilter'; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/utils/useDatePickerInAdhocFilter.tsx b/superset-frontend/src/explore/components/controls/FilterControl/utils/useDatePickerInAdhocFilter.tsx new file mode 100644 index 0000000000000..14e6544810b39 --- /dev/null +++ b/superset-frontend/src/explore/components/controls/FilterControl/utils/useDatePickerInAdhocFilter.tsx @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; + +import { hasGenericChartAxes, t } from '@superset-ui/core'; +import { Dataset, isTemporalColumn } from '@superset-ui/chart-controls'; +import DateFilterControl from 'src/explore/components/controls/DateFilterControl/DateFilterLabel'; +import ControlHeader from 'src/explore/components/ControlHeader'; + +interface DatePickerInFilterProps { + columnName: string; + timeRange?: string; + datasource: Dataset; + onChange: (columnName: string, timeRange: string) => void; +} + +export const useDatePickerInAdhocFilter = ({ + columnName, + timeRange, + datasource, + onChange, +}: DatePickerInFilterProps): React.ReactElement | undefined => { + const onTimeRangeChange = (val: string) => onChange(columnName, val); + + return hasGenericChartAxes && isTemporalColumn(columnName, datasource) ? ( + <> + <ControlHeader label={t('Time Range')} /> + <DateFilterControl + value={timeRange} + name="time_range" + onChange={onTimeRangeChange} + overlayStyle="Modal" + /> + </> + ) : undefined; +}; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/utils/useDatePickerInAdhocfilter.test.ts b/superset-frontend/src/explore/components/controls/FilterControl/utils/useDatePickerInAdhocfilter.test.ts new file mode 100644 index 0000000000000..fdafba2d989c5 --- /dev/null +++ b/superset-frontend/src/explore/components/controls/FilterControl/utils/useDatePickerInAdhocfilter.test.ts @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { renderHook } from '@testing-library/react-hooks'; +import { TestDataset } from '@superset-ui/chart-controls'; +import * as supersetCoreModule from '@superset-ui/core'; +import { useDatePickerInAdhocFilter } from './useDatePickerInAdhocFilter'; + +test('should return undefined if Generic Axis is disabled', () => { + Object.defineProperty(supersetCoreModule, 'hasGenericChartAxes', { + value: false, + }); + const { result } = renderHook(() => + useDatePickerInAdhocFilter({ + columnName: 'ds', + datasource: TestDataset, + onChange: jest.fn(), + }), + ); + expect(result.current).toBeUndefined(); +}); + +test('should return undefined if column is not temporal', () => { + Object.defineProperty(supersetCoreModule, 'hasGenericChartAxes', { + value: true, + }); + const { result } = renderHook(() => + useDatePickerInAdhocFilter({ + columnName: 'gender', + datasource: TestDataset, + onChange: jest.fn(), + }), + ); + expect(result.current).toBeUndefined(); +}); + +test('should return JSX', () => { + Object.defineProperty(supersetCoreModule, 'hasGenericChartAxes', { + value: true, + }); + const { result } = renderHook(() => + useDatePickerInAdhocFilter({ + columnName: 'ds', + datasource: TestDataset, + onChange: jest.fn(), + }), + ); + expect(result.current).not.toBeUndefined(); +}); diff --git a/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts new file mode 100644 index 0000000000000..0d39ef8a27041 --- /dev/null +++ b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts @@ -0,0 +1,103 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { renderHook } from '@testing-library/react-hooks'; +import { NO_TIME_RANGE } from '@superset-ui/core'; +import { Operators } from 'src/explore/constants'; +import * as FetchTimeRangeModule from 'src/explore/components/controls/DateFilterControl'; +import { useGetTimeRangeLabel } from './useGetTimeRangeLabel'; +import AdhocFilter, { CLAUSES, EXPRESSION_TYPES } from '../AdhocFilter'; + +test('should return empty object if operator is not TEMPORAL_RANGE', () => { + const adhocFilter = new AdhocFilter({ + expressionType: EXPRESSION_TYPES.SIMPLE, + subject: 'value', + operator: '>', + comparator: '10', + clause: CLAUSES.WHERE, + }); + const { result } = renderHook(() => useGetTimeRangeLabel(adhocFilter)); + expect(result.current).toEqual({}); +}); + +test('should return empty object if expressionType is SQL', () => { + const adhocFilter = new AdhocFilter({ + expressionType: EXPRESSION_TYPES.SQL, + subject: 'temporal column', + operator: Operators.TEMPORAL_RANGE, + comparator: 'Last week', + clause: CLAUSES.WHERE, + }); + const { result } = renderHook(() => useGetTimeRangeLabel(adhocFilter)); + expect(result.current).toEqual({}); +}); + +test('should get "No filter" label', () => { + const adhocFilter = new AdhocFilter({ + expressionType: EXPRESSION_TYPES.SIMPLE, + subject: 'temporal column', + operator: Operators.TEMPORAL_RANGE, + comparator: NO_TIME_RANGE, + clause: CLAUSES.WHERE, + }); + const { result } = renderHook(() => useGetTimeRangeLabel(adhocFilter)); + expect(result.current).toEqual({ + actualTimeRange: 'temporal column (No filter)', + title: 'No filter', + }); +}); + +test('should get actualTimeRange and title', async () => { + jest + .spyOn(FetchTimeRangeModule, 'fetchTimeRange') + .mockResolvedValue({ value: 'MOCK TIME' }); + + const adhocFilter = new AdhocFilter({ + expressionType: EXPRESSION_TYPES.SIMPLE, + subject: 'temporal column', + operator: Operators.TEMPORAL_RANGE, + comparator: 'Last week', + clause: CLAUSES.WHERE, + }); + + const { result } = await renderHook(() => useGetTimeRangeLabel(adhocFilter)); + expect(result.current).toEqual({ + actualTimeRange: 'MOCK TIME', + title: 'Last week', + }); +}); + +test('should get actualTimeRange and title when gets an error', async () => { + jest + .spyOn(FetchTimeRangeModule, 'fetchTimeRange') + .mockResolvedValue({ error: 'MOCK ERROR' }); + + const adhocFilter = new AdhocFilter({ + expressionType: EXPRESSION_TYPES.SIMPLE, + subject: 'temporal column', + operator: Operators.TEMPORAL_RANGE, + comparator: 'Last week', + clause: CLAUSES.WHERE, + }); + + const { result } = await renderHook(() => useGetTimeRangeLabel(adhocFilter)); + expect(result.current).toEqual({ + actualTimeRange: 'temporal column (Last week)', + title: 'MOCK ERROR', + }); +}); diff --git a/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx new file mode 100644 index 0000000000000..abc2ad5b27c91 --- /dev/null +++ b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useEffect, useState } from 'react'; +import { NO_TIME_RANGE } from '@superset-ui/core'; +import { fetchTimeRange } from 'src/explore/components/controls/DateFilterControl'; +import { Operators } from 'src/explore/constants'; +import AdhocFilter, { EXPRESSION_TYPES } from '../AdhocFilter'; + +interface Results { + actualTimeRange?: string; + title?: string; +} + +export const useGetTimeRangeLabel = (adhocFilter: AdhocFilter): Results => { + const [actualTimeRange, setActualTimeRange] = useState<Results>({}); + + useEffect(() => { + if ( + adhocFilter.operator !== Operators.TEMPORAL_RANGE || + adhocFilter.expressionType !== EXPRESSION_TYPES.SIMPLE + ) { + setActualTimeRange({}); + } + if ( + adhocFilter.operator === Operators.TEMPORAL_RANGE && + adhocFilter.comparator === NO_TIME_RANGE + ) { + setActualTimeRange({ + actualTimeRange: `${adhocFilter.subject} (${NO_TIME_RANGE})`, + title: NO_TIME_RANGE, + }); + } + + if ( + adhocFilter.operator === Operators.TEMPORAL_RANGE && + adhocFilter.expressionType === EXPRESSION_TYPES.SIMPLE && + adhocFilter.comparator !== NO_TIME_RANGE && + actualTimeRange.title !== adhocFilter.comparator + ) { + fetchTimeRange(adhocFilter.comparator, adhocFilter.subject).then( + ({ value, error }) => { + if (error) { + setActualTimeRange({ + actualTimeRange: `${adhocFilter.subject} (${adhocFilter.comparator})`, + title: error, + }); + } else { + setActualTimeRange({ + actualTimeRange: value ?? '', + title: adhocFilter.comparator, + }); + } + }, + ); + } + }, [adhocFilter]); + + return actualTimeRange; +}; diff --git a/superset-frontend/src/explore/components/controls/FixedOrMetricControl/FixedOrMetricControl.test.tsx b/superset-frontend/src/explore/components/controls/FixedOrMetricControl/FixedOrMetricControl.test.tsx index 6a2efd59ab4d3..f44b5a932f2a6 100644 --- a/superset-frontend/src/explore/components/controls/FixedOrMetricControl/FixedOrMetricControl.test.tsx +++ b/superset-frontend/src/explore/components/controls/FixedOrMetricControl/FixedOrMetricControl.test.tsx @@ -21,6 +21,13 @@ import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import FixedOrMetricControl from '.'; +jest.mock( + 'src/components/Icons/Icon', + () => + ({ fileName }: { fileName: string }) => + <span role="img" aria-label={fileName.replace('_', '-')} />, +); + const createProps = () => ({ datasource: { columns: [{ column_name: 'Column A' }], diff --git a/superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx b/superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx index 545065319b77a..2652c30f9e13a 100644 --- a/superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx +++ b/superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx @@ -133,7 +133,7 @@ export default class FixedOrMetricControl extends React.Component { )} {this.state.type === controlTypes.metric && ( <span> - <span>metric: </span> + <span>{t('metric')}: </span> <strong> {this.state.metricValue ? this.state.metricValue.label diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.js b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.js index 5b29d7418c2fe..752fc457b948c 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.js +++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.js @@ -75,7 +75,7 @@ export default class AdhocMetric { this.column = null; this.aggregate = null; } - this.isNew = !!adhocMetric.isNew; + this.datasourceWarning = !!adhocMetric.datasourceWarning; this.hasCustomLabel = !!(adhocMetric.hasCustomLabel && adhocMetric.label); this.label = this.hasCustomLabel ? adhocMetric.label @@ -124,9 +124,6 @@ export default class AdhocMetric { duplicateWith(nextFields) { return new AdhocMetric({ ...this, - // all duplicate metrics are not considered new by default - isNew: false, - // but still overriddable by nextFields ...nextFields, }); } diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.test.js b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.test.js index 336b194e00240..4edc21572f8ee 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.test.js +++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.test.js @@ -34,11 +34,11 @@ describe('AdhocMetric', () => { expressionType: EXPRESSION_TYPES.SIMPLE, column: valueColumn, aggregate: AGGREGATES.SUM, + datasourceWarning: false, label: 'SUM(value)', hasCustomLabel: false, optionName: adhocMetric.optionName, sqlExpression: null, - isNew: false, }); }); @@ -46,7 +46,6 @@ describe('AdhocMetric', () => { const adhocMetric1 = new AdhocMetric({ column: valueColumn, aggregate: AGGREGATES.SUM, - isNew: true, }); const adhocMetric2 = adhocMetric1.duplicateWith({ aggregate: AGGREGATES.AVG, @@ -57,10 +56,6 @@ describe('AdhocMetric', () => { expect(adhocMetric1.aggregate).toBe(AGGREGATES.SUM); expect(adhocMetric2.aggregate).toBe(AGGREGATES.AVG); - - // duplicated clone should not be new - expect(adhocMetric1.isNew).toBe(true); - expect(adhocMetric2.isNew).toStrictEqual(false); }); it('can verify equality', () => { diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.jsx b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.jsx index 1025131e43613..5fdd80e9d3f6c 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.jsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.jsx @@ -98,7 +98,7 @@ describe('AdhocMetricEditPopover', () => { it('prevents saving if no column or aggregate is chosen', () => { const { wrapper } = setup(); - expect(wrapper.find(Button).find({ disabled: true })).not.toExist(); + expect(wrapper.find(Button).find({ disabled: false })).not.toExist(); wrapper.instance().onColumnChange(null); expect(wrapper.find(Button).find({ disabled: true })).toExist(); wrapper.instance().onColumnChange(columns[0].column_name); @@ -109,9 +109,9 @@ describe('AdhocMetricEditPopover', () => { it('highlights save if changes are present', () => { const { wrapper } = setup(); - expect(wrapper.find(Button).find({ buttonStyle: 'primary' })).not.toExist(); + expect(wrapper.find(Button).find({ disabled: true })).toExist(); wrapper.instance().onColumnChange(columns[1].column_name); - expect(wrapper.find(Button).find({ buttonStyle: 'primary' })).toExist(); + expect(wrapper.find(Button).find({ disabled: true })).not.toExist(); }); it('will initiate a drag when clicked', () => { diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx index d665befcca6ad..78add7781469f 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx @@ -18,7 +18,7 @@ */ import userEvent from '@testing-library/user-event'; import React from 'react'; -import { render, screen } from 'spec/helpers/testing-library'; +import { render, screen, waitFor, within } from 'spec/helpers/testing-library'; import AdhocMetric from 'src/explore/components/controls/MetricControl/AdhocMetric'; import AdhocMetricEditPopover from '.'; @@ -35,12 +35,17 @@ const createProps = () => ({ }, savedMetricsOptions: [ { - id: 65, + id: 64, metric_name: 'count', expression: 'COUNT(*)', }, + { + id: 65, + metric_name: 'sum', + expression: 'sum(num)', + }, ], - adhocMetric: new AdhocMetric({ isNew: true }), + adhocMetric: new AdhocMetric({}), datasource: { extra: '{}', type: 'table', @@ -80,18 +85,6 @@ test('Should render correct elements for SQL', () => { expect(screen.getByRole('tabpanel', { name: 'Saved' })).toBeVisible(); }); -test('Should render correct elements for native Druid', () => { - const props = { ...createProps(), datasource: { type: 'druid' } }; - render(<AdhocMetricEditPopover {...props} />); - expect(screen.getByRole('tab', { name: 'Custom SQL' })).toHaveAttribute( - 'aria-disabled', - 'true', - ); - expect(screen.getByRole('tab', { name: 'Simple' })).toBeEnabled(); - expect(screen.getByRole('tab', { name: 'Saved' })).toBeEnabled(); - expect(screen.getByRole('tabpanel', { name: 'Saved' })).toBeVisible(); -}); - test('Should render correct elements for allow ad-hoc metrics', () => { const props = { ...createProps(), @@ -130,25 +123,52 @@ test('Clicking on "Close" should call onClose', () => { expect(props.onClose).toBeCalledTimes(1); }); -test('Clicking on "Save" should call onChange and onClose', () => { +test('Clicking on "Save" should call onChange and onClose', async () => { const props = createProps(); render(<AdhocMetricEditPopover {...props} />); expect(props.onChange).toBeCalledTimes(0); expect(props.onClose).toBeCalledTimes(0); + userEvent.click( + screen.getByRole('combobox', { + name: 'Select saved metrics', + }), + ); + const sumOption = await waitFor(() => + within(document.querySelector('.rc-virtual-list')!).getByText('sum'), + ); + userEvent.click(sumOption); + userEvent.click(screen.getByRole('button', { name: 'Save' })); + expect(props.onChange).toBeCalledTimes(1); + expect(props.onClose).toBeCalledTimes(1); +}); + +test('Clicking on "Save" should not call onChange and onClose', () => { + const props = createProps(); + render(<AdhocMetricEditPopover {...props} />); + expect(props.onChange).toBeCalledTimes(0); + expect(props.onClose).toBeCalledTimes(0); + userEvent.click(screen.getByRole('button', { name: 'Save' })); + expect(props.onChange).toBeCalledTimes(0); + expect(props.onClose).toBeCalledTimes(0); +}); + +test('Clicking on "Save" should call onChange and onClose for new metric', () => { + const props = createProps(); + render(<AdhocMetricEditPopover {...props} isNewMetric />); + expect(props.onChange).toBeCalledTimes(0); + expect(props.onClose).toBeCalledTimes(0); + userEvent.click(screen.getByRole('button', { name: 'Save' })); + expect(props.onChange).toBeCalledTimes(1); + expect(props.onClose).toBeCalledTimes(1); +}); + +test('Clicking on "Save" should call onChange and onClose for new title', () => { + const props = createProps(); + render(<AdhocMetricEditPopover {...props} isLabelModified />); + expect(props.onChange).toBeCalledTimes(0); + expect(props.onClose).toBeCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'Save' })); expect(props.onChange).toBeCalledTimes(1); - expect(props.onChange).toBeCalledWith( - { - id: 64, - metric_name: 'count', - expression: 'COUNT(*)', - }, - { - id: 64, - metric_name: 'count', - expression: 'COUNT(*)', - }, - ); expect(props.onClose).toBeCalledTimes(1); }); diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx index decad4c12d5da..9ed817f283955 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx @@ -19,7 +19,13 @@ /* eslint-disable camelcase */ import React from 'react'; import PropTypes from 'prop-types'; -import { t, styled, ensureIsArray } from '@superset-ui/core'; +import { + isDefined, + t, + styled, + ensureIsArray, + DatasourceType, +} from '@superset-ui/core'; import Tabs from 'src/components/Tabs'; import Button from 'src/components/Button'; import { Select } from 'src/components'; @@ -55,11 +61,14 @@ const propTypes = { savedMetricsOptions: PropTypes.arrayOf(savedMetricType), savedMetric: savedMetricType, datasource: PropTypes.object, + isNewMetric: PropTypes.bool, + isLabelModified: PropTypes.bool, }; const defaultProps = { columns: [], getCurrentTab: noOp, + isNewMetric: false, }; const StyledSelect = styled(Select)` @@ -78,12 +87,7 @@ export const SAVED_TAB_KEY = 'SAVED'; export default class AdhocMetricEditPopover extends React.PureComponent { // "Saved" is a default tab unless there are no saved metrics for dataset - defaultActiveTabKey = - (this.props.savedMetric.metric_name || this.props.adhocMetric.isNew) && - Array.isArray(this.props.savedMetricsOptions) && - this.props.savedMetricsOptions.length > 0 - ? SAVED_TAB_KEY - : this.props.adhocMetric.expressionType; + defaultActiveTabKey = this.getDefaultTab(); constructor(props) { super(props); @@ -99,6 +103,7 @@ export default class AdhocMetricEditPopover extends React.PureComponent { this.onTabChange = this.onTabChange.bind(this); this.handleAceEditorRef = this.handleAceEditorRef.bind(this); this.refreshAceEditor = this.refreshAceEditor.bind(this); + this.getDefaultTab = this.getDefaultTab.bind(this); this.state = { adhocMetric: this.props.adhocMetric, @@ -106,7 +111,6 @@ export default class AdhocMetricEditPopover extends React.PureComponent { width: POPOVER_INITIAL_WIDTH, height: POPOVER_INITIAL_HEIGHT, }; - document.addEventListener('mouseup', this.onMouseUp); } @@ -137,6 +141,22 @@ export default class AdhocMetricEditPopover extends React.PureComponent { document.removeEventListener('mousemove', this.onMouseMove); } + getDefaultTab() { + const { adhocMetric, savedMetric, savedMetricsOptions, isNewMetric } = + this.props; + if (isDefined(adhocMetric.column) || isDefined(adhocMetric.sqlExpression)) { + return adhocMetric.expressionType; + } + if ( + (isNewMetric || savedMetric.metric_name) && + Array.isArray(savedMetricsOptions) && + savedMetricsOptions.length > 0 + ) { + return SAVED_TAB_KEY; + } + return adhocMetric.expressionType; + } + onSave() { const { adhocMetric, savedMetric } = this.state; @@ -279,6 +299,8 @@ export default class AdhocMetricEditPopover extends React.PureComponent { onClose, onResize, datasource, + isNewMetric, + isLabelModified, ...popoverProps } = this.props; const { adhocMetric, savedMetric } = this.state; @@ -323,17 +345,10 @@ export default class AdhocMetricEditPopover extends React.PureComponent { autoFocus: true, }; - if ( - this.props.datasource?.type === 'druid' && - aggregateSelectProps.options - ) { - aggregateSelectProps.options = aggregateSelectProps.options.filter( - aggregate => aggregate !== 'AVG', - ); - } - const stateIsValid = adhocMetric.isValid() || savedMetric?.metric_name; const hasUnsavedChanges = + isLabelModified || + isNewMetric || !adhocMetric.equals(propsAdhocMetric) || (!( typeof savedMetric?.metric_name === 'undefined' && @@ -379,7 +394,7 @@ export default class AdhocMetricEditPopover extends React.PureComponent { {...savedSelectProps} /> </FormItem> - ) : ( + ) : datasource.type === DatasourceType.Table ? ( <EmptyStateSmall image="empty.svg" title={t('No saved metrics found')} @@ -387,6 +402,26 @@ export default class AdhocMetricEditPopover extends React.PureComponent { 'Add metrics to dataset in "Edit datasource" modal', )} /> + ) : ( + <EmptyStateSmall + image="empty.svg" + title={t('No saved metrics found')} + description={ + <> + <span + tabIndex={0} + role="button" + onClick={() => { + this.props.handleDatasetModal(true); + this.props.onClose(); + }} + > + {t('Create a dataset')} + </span> + {t(' to add metrics')} + </> + } + /> )} </Tabs.TabPane> <Tabs.TabPane @@ -431,18 +466,11 @@ export default class AdhocMetricEditPopover extends React.PureComponent { <Tabs.TabPane key={EXPRESSION_TYPES.SQL} tab={ - extra.disallow_adhoc_metrics || - this.props.datasource?.type === 'druid' ? ( + extra.disallow_adhoc_metrics ? ( <Tooltip - title={ - this.props.datasource?.type === 'druid' - ? t( - 'Custom SQL ad-hoc metrics are not available for the native Druid connector', - ) - : t( - 'Custom SQL ad-hoc metrics are not enabled for this dataset', - ) - } + title={t( + 'Custom SQL ad-hoc metrics are not enabled for this dataset', + )} > {t('Custom SQL')} </Tooltip> @@ -451,10 +479,7 @@ export default class AdhocMetricEditPopover extends React.PureComponent { ) } data-test="adhoc-metric-edit-tab#custom" - disabled={ - extra.disallow_adhoc_metrics || - this.props.datasource?.type === 'druid' - } + disabled={extra.disallow_adhoc_metrics} > <SQLEditor data-test="sql-editor" @@ -486,10 +511,8 @@ export default class AdhocMetricEditPopover extends React.PureComponent { {t('Close')} </Button> <Button - disabled={!stateIsValid} - buttonStyle={ - hasUnsavedChanges && stateIsValid ? 'primary' : 'default' - } + disabled={!stateIsValid || !hasUnsavedChanges} + buttonStyle="primary" buttonSize="small" data-test="AdhocMetricEdit#save" onClick={this.onSave} diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx index da6a2739c3871..5bc8e530fb2e7 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx @@ -102,7 +102,7 @@ const AdhocMetricEditPopoverTitle: React.FC<AdhocMetricEditPopoverTitleProps> = } return ( - <Tooltip placement="top" title="Click to edit label"> + <Tooltip placement="top" title={t('Click to edit label')}> <span className="AdhocMetricEditPopoverTitle inline-editable" data-test="AdhocMetricEditTitle#trigger" diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricOption.jsx b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricOption.jsx index 352480f222205..80cf879f7f256 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricOption.jsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricOption.jsx @@ -38,6 +38,7 @@ const propTypes = { index: PropTypes.number, type: PropTypes.string, multi: PropTypes.bool, + datasourceWarningMessage: PropTypes.string, }; class AdhocMetricOption extends React.PureComponent { @@ -64,6 +65,7 @@ class AdhocMetricOption extends React.PureComponent { index, type, multi, + datasourceWarningMessage, } = this.props; return ( @@ -87,6 +89,7 @@ class AdhocMetricOption extends React.PureComponent { withCaret isFunction multi={multi} + datasourceWarningMessage={datasourceWarningMessage} /> </AdhocMetricPopoverTrigger> ); diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx index 273c83e7d2658..f423c2651a3e4 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx @@ -17,9 +17,14 @@ * under the License. */ import React, { ReactNode } from 'react'; -import { Datasource, Metric } from '@superset-ui/core'; +import { Metric, t } from '@superset-ui/core'; import AdhocMetricEditPopoverTitle from 'src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle'; import { ExplorePopoverContent } from 'src/explore/components/ExploreContentPopover'; +import { + ISaveableDatasource, + SaveDatasetModal, +} from 'src/SqlLab/components/SaveDatasetModal'; +import { Datasource } from 'src/explore/types'; import AdhocMetricEditPopover, { SAVED_TAB_KEY, } from './AdhocMetricEditPopover'; @@ -33,12 +38,13 @@ export type AdhocMetricPopoverTriggerProps = { columns: { column_name: string; type: string }[]; savedMetricsOptions: savedMetricType[]; savedMetric: savedMetricType; - datasource?: Datasource; + datasource: Datasource & ISaveableDatasource; children: ReactNode; isControlledComponent?: boolean; visible?: boolean; togglePopover?: (visible: boolean) => void; closePopover?: () => void; + isNew?: boolean; }; export type AdhocMetricPopoverTriggerState = { @@ -48,6 +54,7 @@ export type AdhocMetricPopoverTriggerState = { currentLabel: string; labelModified: boolean; isTitleEditDisabled: boolean; + showSaveDatasetModal: boolean; }; class AdhocMetricPopoverTrigger extends React.PureComponent< @@ -63,6 +70,7 @@ class AdhocMetricPopoverTrigger extends React.PureComponent< this.getCurrentTab = this.getCurrentTab.bind(this); this.getCurrentLabel = this.getCurrentLabel.bind(this); this.onChange = this.onChange.bind(this); + this.handleDatasetModal = this.handleDatasetModal.bind(this); this.state = { adhocMetric: props.adhocMetric, @@ -74,6 +82,7 @@ class AdhocMetricPopoverTrigger extends React.PureComponent< currentLabel: '', labelModified: false, isTitleEditDisabled: false, + showSaveDatasetModal: false, }; } @@ -119,6 +128,10 @@ class AdhocMetricPopoverTrigger extends React.PureComponent< this.forceUpdate(); } + handleDatasetModal(showModal: boolean) { + this.setState({ showSaveDatasetModal: showModal }); + } + closePopover() { this.togglePopover(false); this.setState({ @@ -205,11 +218,17 @@ class AdhocMetricPopoverTrigger extends React.PureComponent< savedMetricsOptions={savedMetricsOptions} savedMetric={savedMetric} datasource={datasource} + handleDatasetModal={this.handleDatasetModal} onResize={this.onPopoverResize} onClose={closePopover} onChange={this.onChange} getCurrentTab={this.getCurrentTab} getCurrentLabel={this.getCurrentLabel} + isNewMetric={this.props.isNew} + isLabelModified={ + this.state.labelModified && + adhocMetricLabel !== this.state.title.label + } /> </ExplorePopoverContent> ); @@ -223,18 +242,32 @@ class AdhocMetricPopoverTrigger extends React.PureComponent< ); return ( - <ControlPopover - placement="right" - trigger="click" - content={overlayContent} - defaultVisible={visible} - visible={visible} - onVisibleChange={togglePopover} - title={popoverTitle} - destroyTooltipOnHide - > - {this.props.children} - </ControlPopover> + <> + {this.state.showSaveDatasetModal && ( + <SaveDatasetModal + visible={this.state.showSaveDatasetModal} + onHide={() => this.handleDatasetModal(false)} + buttonTextOnSave={t('Save')} + buttonTextOnOverwrite={t('Overwrite')} + modalDescription={t( + 'Save this query as a virtual dataset to continue exploring', + )} + datasource={datasource} + /> + )} + <ControlPopover + placement="right" + trigger="click" + content={overlayContent} + defaultVisible={visible} + visible={visible} + onVisibleChange={togglePopover} + title={popoverTitle} + destroyTooltipOnHide + > + {this.props.children} + </ControlPopover> + </> ); } } diff --git a/superset-frontend/src/explore/components/controls/MetricControl/MetricDefinitionValue.jsx b/superset-frontend/src/explore/components/controls/MetricControl/MetricDefinitionValue.jsx index 0b5f5de0acca1..67d9d6e4d231a 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/MetricDefinitionValue.jsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/MetricDefinitionValue.jsx @@ -35,6 +35,7 @@ const propTypes = { savedMetricsOptions: PropTypes.arrayOf(savedMetricType), multi: PropTypes.bool, datasource: PropTypes.object, + datasourceWarningMessage: PropTypes.string, }; export default function MetricDefinitionValue({ @@ -50,6 +51,7 @@ export default function MetricDefinitionValue({ index, type, multi, + datasourceWarningMessage, }) { const getSavedMetricByName = metricName => savedMetrics.find(metric => metric.metric_name === metricName); @@ -63,7 +65,7 @@ export default function MetricDefinitionValue({ if (option instanceof AdhocMetric || savedMetric) { const adhocMetric = - option instanceof AdhocMetric ? option : new AdhocMetric({ isNew: true }); + option instanceof AdhocMetric ? option : new AdhocMetric({}); const metricOptionProps = { onMetricEdit, @@ -78,6 +80,7 @@ export default function MetricDefinitionValue({ savedMetric: savedMetric ?? {}, type, multi, + datasourceWarningMessage, }; return <AdhocMetricOption {...metricOptionProps} />; diff --git a/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.jsx b/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.jsx index 853ca90294b18..617be7112bdf3 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.jsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.jsx @@ -217,10 +217,7 @@ const MetricsControl = ({ [propsValue, savedMetrics], ); - const newAdhocMetric = useMemo( - () => new AdhocMetric({ isNew: true }), - [value], - ); + const newAdhocMetric = useMemo(() => new AdhocMetric({}), [value]); const addNewMetricPopoverTrigger = useCallback( trigger => { if (isAddNewMetricDisabled()) { @@ -234,6 +231,7 @@ const MetricsControl = ({ savedMetricsOptions={savedMetricOptions} savedMetric={emptySavedMetric} datasource={datasource} + isNew > {trigger} </AdhocMetricPopoverTrigger> diff --git a/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.test.jsx b/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.test.jsx index c255e6a62b53a..12a19c5cdf796 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.test.jsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.test.jsx @@ -100,7 +100,6 @@ describe.skip('MetricsControl', () => { hasCustomLabel: false, optionName: 'blahblahblah', sqlExpression: null, - isNew: false, }, ]); }); diff --git a/superset-frontend/src/explore/components/controls/MetricControl/savedMetricType.js b/superset-frontend/src/explore/components/controls/MetricControl/savedMetricType.js index c57831aa9332c..3c9a987bd1995 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/savedMetricType.js +++ b/superset-frontend/src/explore/components/controls/MetricControl/savedMetricType.js @@ -19,7 +19,7 @@ import PropTypes from 'prop-types'; export default PropTypes.shape({ - metric_name: PropTypes.string.isRequired, + metric_name: PropTypes.string, verbose_name: PropTypes.string, - expression: PropTypes.string.isRequired, + expression: PropTypes.string, }); diff --git a/superset-frontend/src/explore/components/controls/OptionControls/index.tsx b/superset-frontend/src/explore/components/controls/OptionControls/index.tsx index 74ec85dc143b8..90ae73c6370aa 100644 --- a/superset-frontend/src/explore/components/controls/OptionControls/index.tsx +++ b/superset-frontend/src/explore/components/controls/OptionControls/index.tsx @@ -179,6 +179,7 @@ export const OptionControlLabel = ({ type, index, isExtra, + datasourceWarningMessage, tooltipTitle, multi = true, ...props @@ -195,7 +196,8 @@ export const OptionControlLabel = ({ type: string; index: number; isExtra?: boolean; - tooltipTitle: string; + datasourceWarningMessage?: string; + tooltipTitle?: string; multi?: boolean; }) => { const theme = useTheme(); @@ -314,15 +316,18 @@ export const OptionControlLabel = ({ {isFunction && <Icons.FieldDerived />} {getLabelContent()} </Label> - {isExtra && ( + {(!!datasourceWarningMessage || isExtra) && ( <StyledInfoTooltipWithTrigger icon="exclamation-triangle" placement="top" bsStyle="warning" - tooltip={t(` + tooltip={ + datasourceWarningMessage || + t(` This filter was inherited from the dashboard's context. It won't be saved when saving the chart. - `)} + `) + } /> )} {withCaret && ( diff --git a/superset-frontend/src/explore/components/controls/SelectAsyncControl/SelectAsyncControl.test.tsx b/superset-frontend/src/explore/components/controls/SelectAsyncControl/SelectAsyncControl.test.tsx index bc78434850818..80bdc78babffa 100644 --- a/superset-frontend/src/explore/components/controls/SelectAsyncControl/SelectAsyncControl.test.tsx +++ b/superset-frontend/src/explore/components/controls/SelectAsyncControl/SelectAsyncControl.test.tsx @@ -65,17 +65,17 @@ beforeEach(() => { jest.resetAllMocks(); }); -test('Should render', () => { +test('Should render', async () => { const props = createProps(); render(<SelectAsyncControl {...props} />, { useRedux: true }); - expect(screen.getByTestId('select-test')).toBeInTheDocument(); + expect(await screen.findByTestId('select-test')).toBeInTheDocument(); }); -test('Should send correct props to Select component - value props', () => { +test('Should send correct props to Select component - value props', async () => { const props = createProps(); render(<SelectAsyncControl {...props} />, { useRedux: true }); - expect(screen.getByTestId('select-test')).toHaveAttribute( + expect(await screen.findByTestId('select-test')).toHaveAttribute( 'data-value', JSON.stringify(props.value), ); @@ -89,20 +89,20 @@ test('Should send correct props to Select component - value props', () => { ); }); -test('Should send correct props to Select component - function onChange multi:true', () => { +test('Should send correct props to Select component - function onChange multi:true', async () => { const props = createProps(); render(<SelectAsyncControl {...props} />, { useRedux: true }); expect(props.onChange).toBeCalledTimes(0); - userEvent.click(screen.getByText('onChange')); + userEvent.click(await screen.findByText('onChange')); expect(props.onChange).toBeCalledTimes(1); }); -test('Should send correct props to Select component - function onChange multi:false', () => { +test('Should send correct props to Select component - function onChange multi:false', async () => { const props = createProps(); render(<SelectAsyncControl {...{ ...props, multi: false }} />, { useRedux: true, }); expect(props.onChange).toBeCalledTimes(0); - userEvent.click(screen.getByText('onChange')); + userEvent.click(await screen.findByText('onChange')); expect(props.onChange).toBeCalledTimes(1); }); diff --git a/superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx b/superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx index 66d9fb154eb88..ddc242a76495c 100644 --- a/superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx +++ b/superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx @@ -20,7 +20,7 @@ import React, { useEffect, useState } from 'react'; import { t, SupersetClient } from '@superset-ui/core'; import ControlHeader from 'src/explore/components/ControlHeader'; import { Select } from 'src/components'; -import { SelectProps, OptionsType } from 'src/components/Select/Select'; +import { SelectOptionsType, SelectProps } from 'src/components/Select/types'; import { SelectValue, LabeledValue } from 'antd/lib/select'; import withToasts from 'src/components/MessageToasts/withToasts'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; @@ -32,7 +32,7 @@ interface SelectAsyncControlProps extends SelectAsyncProps { ariaLabel?: string; dataEndpoint: string; default?: SelectValue; - mutator?: (response: Record<string, any>) => OptionsType; + mutator?: (response: Record<string, any>) => SelectOptionsType; multi?: boolean; onChange: (val: SelectValue) => void; // ControlHeader related props @@ -57,7 +57,7 @@ const SelectAsyncControl = ({ value, ...props }: SelectAsyncControlProps) => { - const [options, setOptions] = useState<OptionsType>([]); + const [options, setOptions] = useState<SelectOptionsType>([]); const handleOnChange = (val: SelectValue) => { let onChangeVal = val; diff --git a/superset-frontend/src/explore/components/controls/SelectControl.jsx b/superset-frontend/src/explore/components/controls/SelectControl.jsx index c641377f202b7..b686e3d9e6375 100644 --- a/superset-frontend/src/explore/components/controls/SelectControl.jsx +++ b/superset-frontend/src/explore/components/controls/SelectControl.jsx @@ -27,7 +27,7 @@ const propTypes = { autoFocus: PropTypes.bool, choices: PropTypes.array, clearable: PropTypes.bool, - description: PropTypes.string, + description: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), disabled: PropTypes.bool, freeForm: PropTypes.bool, isLoading: PropTypes.bool, @@ -225,7 +225,6 @@ export default class SelectControl extends React.PureComponent { name, placeholder, onFocus, - optionRenderer, showHeader, value, tokenSeparators, @@ -300,7 +299,6 @@ export default class SelectControl extends React.PureComponent { name: `select-${name}`, onChange: this.onChange, onFocus, - optionRenderer, options: this.state.options, placeholder, sortComparator: this.props.sortComparator, diff --git a/superset-frontend/src/explore/components/controls/SelectControl.test.jsx b/superset-frontend/src/explore/components/controls/SelectControl.test.jsx index 7307a4d515d93..1a004ee71a37e 100644 --- a/superset-frontend/src/explore/components/controls/SelectControl.test.jsx +++ b/superset-frontend/src/explore/components/controls/SelectControl.test.jsx @@ -21,9 +21,7 @@ import React from 'react'; import sinon from 'sinon'; import { shallow } from 'enzyme'; import { Select as SelectComponent } from 'src/components'; -import { Select as DeprecatedSelect } from 'src/components/Select/DeprecatedSelect'; import SelectControl from 'src/explore/components/controls/SelectControl'; -import ControlHeader from 'src/explore/components/ControlHeader'; import { styledMount as mount } from 'spec/helpers/theming'; const defaultProps = { @@ -62,20 +60,6 @@ describe('SelectControl', () => { expect(wrapper.find(SelectComponent)).toExist(); }); - it('renders with DeprecatedSelect & ControlHeader when deprecatedSelectFlag=true', () => { - wrapper.setProps({ deprecatedSelectFlag: true }); - expect(wrapper.find(SelectComponent)).not.toExist(); - expect(wrapper.find(DeprecatedSelect)).toExist(); - expect(wrapper.find(ControlHeader)).toExist(); - }); - - it('renders with Select when deprecatedSelectFlag=false', () => { - wrapper.setProps({ deprecatedSelectFlag: false }); - expect(wrapper.find(SelectComponent)).toExist(); - expect(wrapper.find(DeprecatedSelect)).not.toExist(); - expect(wrapper.find(ControlHeader)).not.toExist(); - }); - it('renders as mode multiple', () => { wrapper.setProps({ multi: true }); expect(wrapper.find(SelectComponent)).toExist(); diff --git a/superset-frontend/src/explore/components/controls/SpatialControl.jsx b/superset-frontend/src/explore/components/controls/SpatialControl.jsx index 77c8279de084e..9528e665363d2 100644 --- a/superset-frontend/src/explore/components/controls/SpatialControl.jsx +++ b/superset-frontend/src/explore/components/controls/SpatialControl.jsx @@ -171,11 +171,11 @@ export default class SpatialControl extends React.Component { > <Row gutter={16}> <Col xs={24} md={12}> - Longitude + {t('Longitude')} {this.renderSelect('lonCol', spatialTypes.latlong)} </Col> <Col xs={24} md={12}> - Latitude + {t('Latitude')} {this.renderSelect('latCol', spatialTypes.latlong)} </Col> </Row> @@ -206,7 +206,7 @@ export default class SpatialControl extends React.Component { > <Row gutter={16}> <Col xs={24} md={12}> - Column + {t('Column')} {this.renderSelect('geohashCol', spatialTypes.geohash)} </Col> <Col xs={24} md={12}> diff --git a/superset-frontend/src/explore/components/controls/TextAreaControl.jsx b/superset-frontend/src/explore/components/controls/TextAreaControl.jsx index e371061fbe556..48582c4bc757c 100644 --- a/superset-frontend/src/explore/components/controls/TextAreaControl.jsx +++ b/superset-frontend/src/explore/components/controls/TextAreaControl.jsx @@ -45,6 +45,16 @@ const propTypes = { ]), aboveEditorSection: PropTypes.node, readOnly: PropTypes.bool, + resize: PropTypes.oneOf([ + null, + 'block', + 'both', + 'horizontal', + 'inline', + 'none', + 'vertical', + ]), + textAreaStyles: PropTypes.object, }; const defaultProps = { @@ -55,6 +65,8 @@ const defaultProps = { maxLines: 10, offerEditInModal: true, readOnly: false, + resize: null, + textAreaStyles: {}, }; class TextAreaControl extends React.Component { @@ -72,18 +84,23 @@ class TextAreaControl extends React.Component { if (this.props.language) { const style = { border: `1px solid ${this.props.theme.colors.grayscale.light1}`, + minHeight: `${minLines}em`, + width: 'auto', + ...this.props.textAreaStyles, }; + if (this.props.resize) { + style.resize = this.props.resize; + } if (this.props.readOnly) { style.backgroundColor = '#f2f2f2'; } + return ( <TextAreaEditor mode={this.props.language} style={style} minLines={minLines} maxLines={inModal ? 1000 : this.props.maxLines} - width="100%" - height={`${minLines}em`} editorProps={{ $blockScrolling: true }} defaultValue={this.props.initialValue} readOnly={this.props.readOnly} @@ -106,10 +123,10 @@ class TextAreaControl extends React.Component { renderModalBody() { return ( - <div> + <> <div>{this.props.aboveEditorSection}</div> {this.renderEditor(true)} - </div> + </> ); } diff --git a/superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx b/superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx index 5070c9a5956d2..29ac223cf3e03 100644 --- a/superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx +++ b/superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx @@ -61,17 +61,17 @@ const defaultProps = { }; const comparisonTypeOptions = [ - { value: 'value', label: 'Actual value', key: 'value' }, - { value: 'diff', label: 'Difference', key: 'diff' }, - { value: 'perc', label: 'Percentage', key: 'perc' }, - { value: 'perc_change', label: 'Percentage change', key: 'perc_change' }, + { value: 'value', label: t('Actual value'), key: 'value' }, + { value: 'diff', label: t('Difference'), key: 'diff' }, + { value: 'perc', label: t('Percentage'), key: 'perc' }, + { value: 'perc_change', label: t('Percentage change'), key: 'perc_change' }, ]; const colTypeOptions = [ - { value: 'time', label: 'Time comparison', key: 'time' }, - { value: 'contrib', label: 'Contribution', key: 'contrib' }, - { value: 'spark', label: 'Sparkline', key: 'spark' }, - { value: 'avg', label: 'Period average', key: 'avg' }, + { value: 'time', label: t('Time comparison'), key: 'time' }, + { value: 'contrib', label: t('Contribution'), key: 'contrib' }, + { value: 'spark', label: t('Sparkline'), key: 'spark' }, + { value: 'avg', label: t('Period average'), key: 'avg' }, ]; const StyledRow = styled(Row)` @@ -192,28 +192,28 @@ export default class TimeSeriesColumnControl extends React.Component { return ( <div id="ts-col-popo" style={{ width: 320 }}> {this.formRow( - 'Label', - 'The column header label', + t('Label'), + t('The column header label'), 'time-lag', <Input value={this.state.label} onChange={this.onTextInputChange.bind(this, 'label')} - placeholder="Label" + placeholder={t('Label')} />, )} {this.formRow( - 'Tooltip', - 'Column header tooltip', + t('Tooltip'), + t('Column header tooltip'), 'col-tooltip', <Input value={this.state.tooltip} onChange={this.onTextInputChange.bind(this, 'tooltip')} - placeholder="Tooltip" + placeholder={t('Tooltip')} />, )} {this.formRow( - 'Type', - 'Type of comparison, value difference or percentage', + t('Type'), + t('Type of comparison, value difference or percentage'), 'col-type', <Select ariaLabel={t('Type')} @@ -225,52 +225,52 @@ export default class TimeSeriesColumnControl extends React.Component { <hr /> {this.state.colType === 'spark' && this.formRow( - 'Width', - 'Width of the sparkline', + t('Width'), + t('Width of the sparkline'), 'spark-width', <Input value={this.state.width} onChange={this.onTextInputChange.bind(this, 'width')} - placeholder="Width" + placeholder={t('Width')} />, )} {this.state.colType === 'spark' && this.formRow( - 'Height', - 'Height of the sparkline', + t('Height'), + t('Height of the sparkline'), 'spark-width', <Input value={this.state.height} onChange={this.onTextInputChange.bind(this, 'height')} - placeholder="Height" + placeholder={t('Height')} />, )} {['time', 'avg'].indexOf(this.state.colType) >= 0 && this.formRow( - 'Time lag', - 'Number of periods to compare against', + t('Time lag'), + t('Number of periods to compare against'), 'time-lag', <Input value={this.state.timeLag} onChange={this.onTextInputChange.bind(this, 'timeLag')} - placeholder="Time Lag" + placeholder={t('Time Lag')} />, )} {['spark'].indexOf(this.state.colType) >= 0 && this.formRow( - 'Time ratio', - 'Number of periods to ratio against', + t('Time ratio'), + t('Number of periods to ratio against'), 'time-ratio', <Input value={this.state.timeRatio} onChange={this.onTextInputChange.bind(this, 'timeRatio')} - placeholder="Time Ratio" + placeholder={t('Time Ratio')} />, )} {this.state.colType === 'time' && this.formRow( - 'Type', - 'Type of comparison, value difference or percentage', + t('Type'), + t('Type of comparison, value difference or percentage'), 'comp-type', <Select ariaLabel={t('Type')} @@ -281,8 +281,10 @@ export default class TimeSeriesColumnControl extends React.Component { )} {this.state.colType === 'spark' && this.formRow( - 'Show Y-axis', - 'Show Y-axis on the sparkline. Will display the manually set min/max if set or min/max values in the data otherwise.', + t('Show Y-axis'), + t( + 'Show Y-axis on the sparkline. Will display the manually set min/max if set or min/max values in the data otherwise.', + ), 'show-y-axis-bounds', <CheckboxControl value={this.state.showYAxis} @@ -291,8 +293,8 @@ export default class TimeSeriesColumnControl extends React.Component { )} {this.state.colType === 'spark' && this.formRow( - 'Y-axis bounds', - 'Manually set min/max values for the y-axis.', + t('Y-axis bounds'), + t('Manually set min/max values for the y-axis.'), 'y-axis-bounds', <BoundsControl value={this.state.yAxisBounds} @@ -301,10 +303,10 @@ export default class TimeSeriesColumnControl extends React.Component { )} {this.state.colType !== 'spark' && this.formRow( - 'Color bounds', - `Number bounds used for color encoding from red to blue. - Reverse the numbers for blue to red. To get pure red or blue, - you can enter either only min or max.`, + t('Color bounds'), + t(`Number bounds used for color encoding from red to blue. + Reverse the numbers for blue to red. To get pure red or blue, + you can enter either only min or max.`), 'bounds', <BoundsControl value={this.state.bounds} @@ -312,24 +314,24 @@ export default class TimeSeriesColumnControl extends React.Component { />, )} {this.formRow( - 'Number format', - 'Optional d3 number format string', + t('Number format'), + t('Optional d3 number format string'), 'd3-format', <Input value={this.state.d3format} onChange={this.onTextInputChange.bind(this, 'd3format')} - placeholder="Number format string" + placeholder={t('Number format string')} />, )} {this.state.colType === 'spark' && this.formRow( - 'Date format', - 'Optional d3 date format string', + t('Date format'), + t('Optional d3 date format string'), 'date-format', <Input value={this.state.dateFormat} onChange={this.onTextInputChange.bind(this, 'dateFormat')} - placeholder="Date format string" + placeholder={t('Date format string')} />, )} <ButtonBar> @@ -356,7 +358,7 @@ export default class TimeSeriesColumnControl extends React.Component { <ControlPopover trigger="click" content={this.renderPopover()} - title="Column Configuration" + title={t('Column Configuration')} visible={this.state.popoverVisible} onVisibleChange={this.onPopoverVisibleChange} > diff --git a/superset-frontend/src/explore/components/controls/ViewQuery.tsx b/superset-frontend/src/explore/components/controls/ViewQuery.tsx new file mode 100644 index 0000000000000..a8ebd975d3344 --- /dev/null +++ b/superset-frontend/src/explore/components/controls/ViewQuery.tsx @@ -0,0 +1,76 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { styled } from '@superset-ui/core'; +import SyntaxHighlighter from 'react-syntax-highlighter/dist/cjs/light'; +import github from 'react-syntax-highlighter/dist/cjs/styles/hljs/github'; +import CopyToClipboard from 'src/components/CopyToClipboard'; +import { CopyButton } from 'src/explore/components/DataTableControl'; +import markdownSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/markdown'; +import htmlSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/htmlbars'; +import sqlSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql'; +import jsonSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/json'; + +const CopyButtonViewQuery = styled(CopyButton)` + && { + margin: 0 0 ${({ theme }) => theme.gridUnit}px; + } +`; + +SyntaxHighlighter.registerLanguage('markdown', markdownSyntax); +SyntaxHighlighter.registerLanguage('html', htmlSyntax); +SyntaxHighlighter.registerLanguage('sql', sqlSyntax); +SyntaxHighlighter.registerLanguage('json', jsonSyntax); + +interface ViewQueryProps { + sql: string; + language?: string; +} + +const StyledSyntaxContainer = styled.div` + height: 100%; + display: flex; + flex-direction: column; +`; + +const StyledSyntaxHighlighter = styled(SyntaxHighlighter)` + flex: 1; +`; + +const ViewQuery: React.FC<ViewQueryProps> = props => { + const { sql, language = 'sql' } = props; + return ( + <StyledSyntaxContainer key={sql}> + <CopyToClipboard + text={sql} + shouldShowText={false} + copyNode={ + <CopyButtonViewQuery buttonSize="xsmall"> + <i className="fa fa-clipboard" /> + </CopyButtonViewQuery> + } + /> + <StyledSyntaxHighlighter language={language} style={github}> + {sql} + </StyledSyntaxHighlighter> + </StyledSyntaxContainer> + ); +}; + +export default ViewQuery; diff --git a/superset-frontend/src/explore/components/controls/ViewQueryModal.tsx b/superset-frontend/src/explore/components/controls/ViewQueryModal.tsx index 238982c3d85f5..023c1e3551307 100644 --- a/superset-frontend/src/explore/components/controls/ViewQueryModal.tsx +++ b/superset-frontend/src/explore/components/controls/ViewQueryModal.tsx @@ -17,29 +17,11 @@ * under the License. */ import React, { useEffect, useState } from 'react'; -import { ensureIsArray, styled, t } from '@superset-ui/core'; -import SyntaxHighlighter from 'react-syntax-highlighter/dist/cjs/light'; -import github from 'react-syntax-highlighter/dist/cjs/styles/hljs/github'; -import CopyToClipboard from 'src/components/CopyToClipboard'; +import { styled, ensureIsArray, t } from '@superset-ui/core'; import Loading from 'src/components/Loading'; -import { CopyButton } from 'src/explore/components/DataTableControl'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; import { getChartDataRequest } from 'src/components/Chart/chartAction'; -import markdownSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/markdown'; -import htmlSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/htmlbars'; -import sqlSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql'; -import jsonSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/json'; - -const CopyButtonViewQuery = styled(CopyButton)` - && { - margin: 0 0 ${({ theme }) => theme.gridUnit}px; - } -`; - -SyntaxHighlighter.registerLanguage('markdown', markdownSyntax); -SyntaxHighlighter.registerLanguage('html', htmlSyntax); -SyntaxHighlighter.registerLanguage('sql', sqlSyntax); -SyntaxHighlighter.registerLanguage('json', jsonSyntax); +import ViewQuery from 'src/explore/components/controls/ViewQuery'; interface Props { latestQueryFormData: object; @@ -50,12 +32,10 @@ type Result = { language: string; }; -const StyledSyntaxContainer = styled.div` +const ViewQueryModalContainer = styled.div` height: 100%; -`; - -const StyledSyntaxHighlighter = styled(SyntaxHighlighter)` - height: calc(100% - 26px); // 100% - clipboard height + display: flex; + flex-direction: column; `; const ViewQueryModal: React.FC<Props> = props => { @@ -97,30 +77,15 @@ const ViewQueryModal: React.FC<Props> = props => { if (error) { return <pre>{error}</pre>; } + return ( - <> + <ViewQueryModalContainer> {result.map(item => item.query ? ( - <StyledSyntaxContainer key={item.query}> - <CopyToClipboard - text={item.query} - shouldShowText={false} - copyNode={ - <CopyButtonViewQuery buttonSize="xsmall"> - <i className="fa fa-clipboard" /> - </CopyButtonViewQuery> - } - /> - <StyledSyntaxHighlighter - language={item.language || undefined} - style={github} - > - {item.query} - </StyledSyntaxHighlighter> - </StyledSyntaxContainer> + <ViewQuery sql={item.query} language={item.language || undefined} /> ) : null, )} - </> + </ViewQueryModalContainer> ); }; diff --git a/superset-frontend/src/explore/components/controls/ViewQueryModalFooter.tsx b/superset-frontend/src/explore/components/controls/ViewQueryModalFooter.tsx new file mode 100644 index 0000000000000..4f4af039b1a23 --- /dev/null +++ b/superset-frontend/src/explore/components/controls/ViewQueryModalFooter.tsx @@ -0,0 +1,83 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { isObject } from 'lodash'; +import { t, SupersetClient } from '@superset-ui/core'; +import Button from 'src/components/Button'; + +interface SimpleDataSource { + id: string; + sql: string; + type: string; +} + +interface ViewQueryModalFooterProps { + closeModal?: Function; + changeDatasource?: Function; + datasource?: SimpleDataSource; +} + +const CLOSE = t('Close'); +const SAVE_AS_DATASET = t('Save as Dataset'); +const OPEN_IN_SQL_LAB = t('Open in SQL Lab'); + +const ViewQueryModalFooter: React.FC<ViewQueryModalFooterProps> = (props: { + closeModal: () => void; + changeDatasource: () => void; + datasource: SimpleDataSource; +}) => { + const viewInSQLLab = (id: string, type: string, sql: string) => { + const payload = { + datasourceKey: `${id}__${type}`, + sql, + }; + SupersetClient.postForm('/superset/sqllab/', payload); + }; + + const openSQL = () => { + const { datasource } = props; + if (isObject(datasource)) { + const { id, type, sql } = datasource; + viewInSQLLab(id, type, sql); + } + }; + return ( + <div> + <Button + onClick={() => { + props?.closeModal?.(); + props?.changeDatasource?.(); + }} + > + {SAVE_AS_DATASET} + </Button> + <Button onClick={() => openSQL()}>{OPEN_IN_SQL_LAB}</Button> + <Button + buttonStyle="primary" + onClick={() => { + props?.closeModal?.(); + }} + > + {CLOSE} + </Button> + </div> + ); +}; + +export default ViewQueryModalFooter; diff --git a/superset-frontend/src/explore/components/controls/ViewportControl.jsx b/superset-frontend/src/explore/components/controls/ViewportControl.jsx index 631a8c5508789..ff9ebef2042ed 100644 --- a/superset-frontend/src/explore/components/controls/ViewportControl.jsx +++ b/superset-frontend/src/explore/components/controls/ViewportControl.jsx @@ -17,6 +17,7 @@ * under the License. */ import React from 'react'; +import { t } from '@superset-ui/core'; import PropTypes from 'prop-types'; import Popover from 'src/components/Popover'; import { decimal2sexagesimal } from 'geolib'; @@ -107,7 +108,7 @@ export default class ViewportControl extends React.Component { trigger="click" placement="right" content={this.renderPopover()} - title="Viewport" + title={t('Viewport')} > <Label className="pointer">{this.renderLabel()}</Label> </Popover> diff --git a/superset-frontend/src/explore/components/controls/VizTypeControl/FastVizSwitcher.tsx b/superset-frontend/src/explore/components/controls/VizTypeControl/FastVizSwitcher.tsx index 5b9df8021fa16..a7186e2aa19b5 100644 --- a/superset-frontend/src/explore/components/controls/VizTypeControl/FastVizSwitcher.tsx +++ b/superset-frontend/src/explore/components/controls/VizTypeControl/FastVizSwitcher.tsx @@ -29,7 +29,8 @@ import { css, SupersetTheme, t, useTheme } from '@superset-ui/core'; import { usePluginContext } from 'src/components/DynamicPlugins'; import { Tooltip } from 'src/components/Tooltip'; import Icons from 'src/components/Icons'; -import { ExplorePageState } from 'src/explore/reducers/getInitialState'; +import { getChartKey } from 'src/explore/exploreUtils'; +import { ExplorePageState } from 'src/explore/types'; export interface VizMeta { icon: ReactElement; @@ -52,19 +53,29 @@ const FEATURED_CHARTS: VizMeta[] = [ name: 'echarts_timeseries_line', icon: <Icons.LineChartTile />, }, + { + name: 'echarts_timeseries_bar', + icon: <Icons.BarChartTile />, + }, + { name: 'echarts_area', icon: <Icons.AreaChartTile /> }, { name: 'table', icon: <Icons.TableChartTile /> }, { name: 'big_number_total', icon: <Icons.BigNumberChartTile />, }, { name: 'pie', icon: <Icons.PieChartTile /> }, - { - name: 'echarts_timeseries_bar', - icon: <Icons.BarChartTile />, - }, - { name: 'echarts_area', icon: <Icons.AreaChartTile /> }, ]; +const antdIconProps = { + iconSize: 'l' as const, + css: (theme: SupersetTheme) => css` + padding: ${theme.gridUnit}px; + & > * { + line-height: 0; + } + `, +}; + const VizTile = ({ isActive, isRendered, @@ -188,8 +199,8 @@ export const FastVizSwitcher = React.memo( ({ currentSelection, onChange }: FastVizSwitcherProps) => { const currentViz = useSelector<ExplorePageState, string | undefined>( state => - state.charts && - Object.values(state.charts)[0]?.latestQueryFormData?.viz_type, + state.charts?.[getChartKey(state.explore)]?.latestQueryFormData + ?.viz_type, ); const vizTiles = useMemo(() => { const vizTiles = [...FEATURED_CHARTS]; @@ -203,15 +214,7 @@ export const FastVizSwitcher = React.memo( vizTiles.unshift({ name: currentSelection, icon: ( - <Icons.MonitorOutlined - iconSize="l" - css={(theme: SupersetTheme) => css` - padding: ${theme.gridUnit}px; - & > * { - line-height: 0; - } - `} - /> + <Icons.MonitorOutlined {...antdIconProps} aria-label="monitor" /> ), }); } @@ -223,7 +226,12 @@ export const FastVizSwitcher = React.memo( ) { vizTiles.unshift({ name: currentViz, - icon: <Icons.CurrentRenderedTile />, + icon: ( + <Icons.CheckSquareOutlined + {...antdIconProps} + aria-label="check-square" + /> + ), }); } return vizTiles; diff --git a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx index 98a7b9099e728..034b339cda94a 100644 --- a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx +++ b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx @@ -17,7 +17,13 @@ * under the License. */ import { Preset } from '@superset-ui/core'; -import { render, cleanup, screen, within } from 'spec/helpers/testing-library'; +import { + render, + cleanup, + screen, + within, + waitFor, +} from 'spec/helpers/testing-library'; import { stateWithoutNativeFilters } from 'spec/fixtures/mockStore'; import React from 'react'; import userEvent from '@testing-library/user-event'; @@ -34,7 +40,7 @@ import { } from '@superset-ui/plugin-chart-echarts'; import TableChartPlugin from '@superset-ui/plugin-chart-table'; import { LineChartPlugin } from '@superset-ui/preset-chart-xy'; -import TimeTableChartPlugin from '../../../../visualizations/TimeTable'; +import TimeTableChartPlugin from 'src/visualizations/TimeTable'; import VizTypeControl, { VIZ_TYPE_CONTROL_TEST_ID } from './index'; jest.useFakeTimers(); @@ -90,30 +96,31 @@ describe('VizTypeControl', () => { isModalOpenInit: true, }; - const renderWrapper = ( + const waitForRenderWrapper = ( props: typeof defaultProps = defaultProps, state: object = stateWithoutNativeFilters, - ) => { - render( - <DynamicPluginProvider> - <VizTypeControl {...props} /> - </DynamicPluginProvider>, - { useRedux: true, initialState: state }, - ); - }; + ) => + waitFor(() => { + render( + <DynamicPluginProvider> + <VizTypeControl {...props} /> + </DynamicPluginProvider>, + { useRedux: true, initialState: state }, + ); + }); afterEach(() => { cleanup(); jest.clearAllMocks(); }); - it('Fast viz switcher tiles render', () => { + it('Fast viz switcher tiles render', async () => { const props = { ...defaultProps, value: 'echarts_timeseries_line', isModalOpenInit: false, }; - renderWrapper(props); + await waitForRenderWrapper(props); expect(screen.getByLabelText('line-chart-tile')).toBeVisible(); expect(screen.getByLabelText('table-chart-tile')).toBeVisible(); expect(screen.getByLabelText('big-number-chart-tile')).toBeVisible(); @@ -121,9 +128,7 @@ describe('VizTypeControl', () => { expect(screen.getByLabelText('bar-chart-tile')).toBeVisible(); expect(screen.getByLabelText('area-chart-tile')).toBeVisible(); expect(screen.queryByLabelText('monitor')).not.toBeInTheDocument(); - expect( - screen.queryByLabelText('current-rendered-tile'), - ).not.toBeInTheDocument(); + expect(screen.queryByLabelText('check-square')).not.toBeInTheDocument(); expect( within(screen.getByTestId('fast-viz-switcher')).getByText( @@ -141,7 +146,7 @@ describe('VizTypeControl', () => { ).toBeInTheDocument(); expect( within(screen.getByTestId('fast-viz-switcher')).getByText( - 'Time-series Bar Chart v2', + 'Time-series Bar Chart', ), ).toBeInTheDocument(); expect( @@ -154,13 +159,13 @@ describe('VizTypeControl', () => { ).not.toBeInTheDocument(); }); - it('Render viz tiles when non-featured chart is selected', () => { + it('Render viz tiles when non-featured chart is selected', async () => { const props = { ...defaultProps, value: 'line', isModalOpenInit: false, }; - renderWrapper(props); + await waitForRenderWrapper(props); expect(screen.getByLabelText('monitor')).toBeVisible(); expect( @@ -168,7 +173,7 @@ describe('VizTypeControl', () => { ).toBeVisible(); }); - it('Render viz tiles when non-featured is rendered', () => { + it('Render viz tiles when non-featured is rendered', async () => { const props = { ...defaultProps, value: 'line', @@ -182,21 +187,26 @@ describe('VizTypeControl', () => { }, }, }, + explore: { + slice: { + slice_id: 1, + }, + }, }; - renderWrapper(props, state); - expect(screen.getByLabelText('current-rendered-tile')).toBeVisible(); + await waitForRenderWrapper(props, state); + expect(screen.getByLabelText('check-square')).toBeVisible(); expect( within(screen.getByTestId('fast-viz-switcher')).getByText('Line Chart'), ).toBeVisible(); }); - it('Change viz type on click', () => { + it('Change viz type on click', async () => { const props = { ...defaultProps, value: 'echarts_timeseries_line', isModalOpenInit: false, }; - renderWrapper(props); + await waitForRenderWrapper(props); userEvent.click( within(screen.getByTestId('fast-viz-switcher')).getByText( 'Time-series Line Chart', @@ -210,7 +220,7 @@ describe('VizTypeControl', () => { }); it('Open viz gallery modal on "View all charts" click', async () => { - renderWrapper({ ...defaultProps, isModalOpenInit: false }); + await waitForRenderWrapper({ ...defaultProps, isModalOpenInit: false }); expect( screen.queryByText('Select a visualization type'), ).not.toBeInTheDocument(); @@ -221,7 +231,7 @@ describe('VizTypeControl', () => { }); it('Search visualization type', async () => { - renderWrapper(); + await waitForRenderWrapper(); const visualizations = screen.getByTestId(getTestId('viz-row')); @@ -248,7 +258,7 @@ describe('VizTypeControl', () => { within(visualizations).getByText('Time-series Line Chart'), ).toBeVisible(); expect( - within(visualizations).getByText('Time-series Bar Chart v2'), + within(visualizations).getByText('Time-series Bar Chart'), ).toBeVisible(); expect( within(visualizations).queryByText('Line Chart'), @@ -261,4 +271,20 @@ describe('VizTypeControl', () => { within(visualizations).queryByText('Pie Chart'), ).not.toBeInTheDocument(); }); + + it('Submit on viz type double-click', async () => { + await waitForRenderWrapper(); + userEvent.click(screen.getByRole('button', { name: 'ballot All charts' })); + const visualizations = screen.getByTestId(getTestId('viz-row')); + userEvent.click(within(visualizations).getByText('Time-series Bar Chart')); + + expect(defaultProps.onChange).not.toBeCalled(); + userEvent.dblClick( + within(visualizations).getByText('Time-series Line Chart'), + ); + + expect(defaultProps.onChange).toHaveBeenCalledWith( + 'echarts_timeseries_line', + ); + }); }); diff --git a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx index 1679fff699808..6b14660075127 100644 --- a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx +++ b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx @@ -47,8 +47,10 @@ import scrollIntoView from 'scroll-into-view-if-needed'; interface VizTypeGalleryProps { onChange: (vizType: string | null) => void; + onDoubleClick: () => void; selectedViz: string | null; className?: string; + denyList: string[]; } type VizEntry = { @@ -224,7 +226,7 @@ const SelectorLabel = styled.button` } &.selected { - background-color: ${theme.colors.primary.dark1}; + background-color: ${theme.colors.primary.base}; color: ${theme.colors.primary.light5}; svg { @@ -380,12 +382,14 @@ interface ThumbnailProps { entry: VizEntry; selectedViz: string | null; setSelectedViz: (viz: string) => void; + onDoubleClick: () => void; } const Thumbnail: React.FC<ThumbnailProps> = ({ entry, selectedViz, setSelectedViz, + onDoubleClick, }) => { const theme = useTheme(); const { key, value: type } = entry; @@ -400,6 +404,7 @@ const Thumbnail: React.FC<ThumbnailProps> = ({ tabIndex={0} className={isSelected ? 'selected' : ''} onClick={() => setSelectedViz(key)} + onDoubleClick={onDoubleClick} data-test="viztype-selector-container" > <img @@ -429,6 +434,7 @@ interface ThumbnailGalleryProps { vizEntries: VizEntry[]; selectedViz: string | null; setSelectedViz: (viz: string) => void; + onDoubleClick: () => void; } /** A list of viz thumbnails, used within the viz picker modal */ @@ -487,7 +493,7 @@ const doesVizMatchSelector = (viz: ChartMetadata, selector: string) => (viz.tags || []).indexOf(selector) > -1; export default function VizTypeGallery(props: VizTypeGalleryProps) { - const { selectedViz, onChange, className } = props; + const { selectedViz, onChange, onDoubleClick, className } = props; const { mountedPluginMetadata } = usePluginContext(); const searchInputRef = useRef<HTMLInputElement>(); const [searchInputValue, setSearchInputValue] = useState(''); @@ -501,6 +507,7 @@ export default function VizTypeGallery(props: VizTypeGalleryProps) { const chartMetadata: VizEntry[] = useMemo(() => { const result = Object.entries(mountedPluginMetadata) .map(([key, value]) => ({ key, value })) + .filter(({ key }) => !props.denyList.includes(key)) .filter( ({ value }) => nativeFilterGate(value.behaviors || []) && !value.deprecated, @@ -793,6 +800,7 @@ export default function VizTypeGallery(props: VizTypeGalleryProps) { vizEntries={getVizEntriesToDisplay()} selectedViz={selectedViz} setSelectedViz={onChange} + onDoubleClick={onDoubleClick} /> </RightPane> diff --git a/superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx b/superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx index 0f8de76926c0a..802c04f8a995d 100644 --- a/superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx +++ b/superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx @@ -27,6 +27,7 @@ import { import { usePluginContext } from 'src/components/DynamicPlugins'; import Modal from 'src/components/Modal'; import { noOp } from 'src/utils/common'; +import getBootstrapData from 'src/utils/getBootstrapData'; import VizTypeGallery, { MAX_ADVISABLE_VIZ_GALLERY_WIDTH, } from './VizTypeGallery'; @@ -41,6 +42,8 @@ interface VizTypeControlProps { isModalOpenInit?: boolean; } +const bootstrapData = getBootstrapData(); +const denyList: string[] = bootstrapData.common.conf.VIZ_TYPE_DENYLIST || []; const metadataRegistry = getChartMetadataRegistry(); export const VIZ_TYPE_CONTROL_TEST_ID = 'viz-type-control'; @@ -140,6 +143,8 @@ const VizTypeControl = ({ key={modalKey} selectedViz={selectedViz} onChange={setSelectedViz} + onDoubleClick={onSubmit} + denyList={denyList} /> </UnpaddedModal> </> diff --git a/superset-frontend/src/dashboard/stylesheets/components/divider.less b/superset-frontend/src/explore/components/controls/XAxisSortControl.tsx similarity index 61% rename from superset-frontend/src/dashboard/stylesheets/components/divider.less rename to superset-frontend/src/explore/components/controls/XAxisSortControl.tsx index 7ee4956ddfc09..05d27dc0d4361 100644 --- a/superset-frontend/src/dashboard/stylesheets/components/divider.less +++ b/superset-frontend/src/explore/components/controls/XAxisSortControl.tsx @@ -16,27 +16,21 @@ * specific language governing permissions and limitations * under the License. */ -.dashboard-component-divider { - width: 100%; - padding: 8px 0; /* this is padding not margin to enable a larger mouse target */ - background-color: transparent; -} - -.dashboard-component-divider:after { - content: ''; - height: 1px; - width: 100%; - background-color: @gray-light; - display: block; -} +import React, { useEffect, useState } from 'react'; +import SelectControl from './SelectControl'; -.new-component-placeholder.divider-placeholder:after { - content: ''; - height: 2px; - width: 100%; - background-color: @gray-light; -} +export default function XAxisSortControl(props: { + onChange: (val: string | undefined) => void; + value: string | null; + shouldReset: boolean; +}) { + const [value, setValue] = useState(props.value); + useEffect(() => { + if (props.shouldReset) { + props.onChange(undefined); + setValue(null); + } + }, [props.shouldReset, props.value]); -.dragdroppable .dashboard-component-divider { - cursor: move; + return <SelectControl {...props} value={value} />; } diff --git a/superset-frontend/src/explore/components/controls/index.js b/superset-frontend/src/explore/components/controls/index.js index 23cd3a73d85b5..21e3bd4cf285d 100644 --- a/superset-frontend/src/explore/components/controls/index.js +++ b/superset-frontend/src/explore/components/controls/index.js @@ -45,6 +45,7 @@ import DndColumnSelectControl, { DndFilterSelect, DndMetricSelect, } from './DndColumnSelectControl'; +import XAxisSortControl from './XAxisSortControl'; const controlMap = { AnnotationLayerControl, @@ -74,6 +75,7 @@ const controlMap = { AdhocFilterControl, FilterBoxItemControl, ConditionalFormattingControl, + XAxisSortControl, ...sharedControlComponents, }; export default controlMap; diff --git a/superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/DashboardsSubMenu.test.tsx b/superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/DashboardsSubMenu.test.tsx new file mode 100644 index 0000000000000..aea0b4a8e598e --- /dev/null +++ b/superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/DashboardsSubMenu.test.tsx @@ -0,0 +1,78 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { Menu } from 'src/components/Menu'; +import DashboardItems from './DashboardsSubMenu'; + +const asyncRender = (numberOfItems: number) => + waitFor(() => { + const dashboards = []; + for (let i = 1; i <= numberOfItems; i += 1) { + dashboards.push({ id: i, dashboard_title: `Dashboard ${i}` }); + } + render( + <Menu openKeys={['menu']}> + <Menu.SubMenu title="Dashboards added to" key="menu"> + <DashboardItems key="menu" dashboards={dashboards} /> + </Menu.SubMenu> + </Menu>, + { + useRouter: true, + }, + ); + }); + +test('renders a submenu', async () => { + await asyncRender(3); + expect(screen.getByText('Dashboard 1')).toBeInTheDocument(); + expect(screen.getByText('Dashboard 2')).toBeInTheDocument(); + expect(screen.getByText('Dashboard 3')).toBeInTheDocument(); +}); + +test('renders a submenu with search', async () => { + await asyncRender(20); + expect(screen.getByPlaceholderText('Search')).toBeInTheDocument(); +}); + +test('displays a searched value', async () => { + await asyncRender(20); + userEvent.type(screen.getByPlaceholderText('Search'), '2'); + expect(screen.getByText('Dashboard 2')).toBeInTheDocument(); + expect(screen.getByText('Dashboard 20')).toBeInTheDocument(); +}); + +test('renders a "No results found" message when searching', async () => { + await asyncRender(20); + userEvent.type(screen.getByPlaceholderText('Search'), 'unknown'); + expect(screen.getByText('No results found')).toBeInTheDocument(); +}); + +test('renders a submenu with no dashboards', async () => { + await asyncRender(0); + expect(screen.getByText('None')).toBeInTheDocument(); +}); + +test('shows link icon when hovering', async () => { + await asyncRender(3); + expect(screen.queryByRole('img', { name: 'full' })).not.toBeInTheDocument(); + userEvent.hover(screen.getByText('Dashboard 1')); + expect(screen.getByRole('img', { name: 'full' })).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/DashboardsSubMenu.tsx b/superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/DashboardsSubMenu.tsx new file mode 100644 index 0000000000000..625f4b8949d85 --- /dev/null +++ b/superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/DashboardsSubMenu.tsx @@ -0,0 +1,146 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useState } from 'react'; +import { css, t, useTheme } from '@superset-ui/core'; +import { Input } from 'src/components/Input'; +import Icons from 'src/components/Icons'; +import { Menu } from 'src/components/Menu'; +import { Link } from 'react-router-dom'; + +export interface DashboardsSubMenuProps { + chartId?: number; + dashboards?: { id: number; dashboard_title: string }[]; +} + +const WIDTH = 220; +const HEIGHT = 300; +const SEARCH_THRESHOLD = 10; + +const DashboardsSubMenu = ({ + chartId, + dashboards = [], + ...menuProps +}: DashboardsSubMenuProps) => { + const theme = useTheme(); + const [dashboardSearch, setDashboardSearch] = useState<string>(); + const [hoveredItem, setHoveredItem] = useState<number | null>(); + const showSearch = dashboards.length > SEARCH_THRESHOLD; + const filteredDashboards = dashboards.filter( + dashboard => + !dashboardSearch || + dashboard.dashboard_title + .toLowerCase() + .includes(dashboardSearch.toLowerCase()), + ); + const noResults = dashboards.length === 0; + const noResultsFound = dashboardSearch && filteredDashboards.length === 0; + const urlQueryString = chartId ? `?focused_chart=${chartId}` : ''; + return ( + <> + {showSearch && ( + <Input + allowClear + placeholder={t('Search')} + prefix={<Icons.Search iconSize="l" />} + css={css` + width: ${WIDTH}px; + margin: ${theme.gridUnit * 2}px ${theme.gridUnit * 3}px; + `} + value={dashboardSearch} + onChange={e => setDashboardSearch(e.currentTarget.value)} + /> + )} + <div + css={css` + max-height: ${HEIGHT}px; + overflow: auto; + `} + > + {filteredDashboards.map(dashboard => ( + <Menu.Item + key={String(dashboard.id)} + onMouseEnter={() => setHoveredItem(dashboard.id)} + onMouseLeave={() => { + if (hoveredItem === dashboard.id) { + setHoveredItem(null); + } + }} + {...menuProps} + > + <Link + target="_blank" + rel="noreferer noopener" + to={`/superset/dashboard/${dashboard.id}${urlQueryString}`} + > + <div + css={css` + display: flex; + flex-direction: row; + align-items: center; + max-width: ${WIDTH}px; + `} + > + <div + css={css` + white-space: normal; + `} + > + {dashboard.dashboard_title} + </div> + <Icons.Full + iconSize="l" + iconColor={theme.colors.grayscale.base} + css={css` + margin-left: ${theme.gridUnit * 2}px; + visibility: ${hoveredItem === dashboard.id + ? 'visible' + : 'hidden'}; + `} + /> + </div> + </Link> + </Menu.Item> + ))} + {noResultsFound && ( + <div + css={css` + margin-left: ${theme.gridUnit * 3}px; + margin-bottom: ${theme.gridUnit}px; + `} + > + {t('No results found')} + </div> + )} + {noResults && ( + <Menu.Item + disabled + css={css` + min-width: ${WIDTH}px; + `} + {...menuProps} + > + {t('None')} + </Menu.Item> + )} + </div> + </> + ); +}; + +export default DashboardsSubMenu; diff --git a/superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx b/superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx index fb317985a17ca..445db6dc44145 100644 --- a/superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx +++ b/superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx @@ -18,26 +18,30 @@ */ import React, { useCallback, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; -import { FileOutlined, FileImageOutlined } from '@ant-design/icons'; import { css, styled, t, useTheme } from '@superset-ui/core'; +import Icons from 'src/components/Icons'; import { Menu } from 'src/components/Menu'; import ModalTrigger from 'src/components/ModalTrigger'; import Button from 'src/components/Button'; import { useToasts } from 'src/components/MessageToasts/withToasts'; -import { exportChart } from 'src/explore/exploreUtils'; +import { exportChart, getChartKey } from 'src/explore/exploreUtils'; import downloadAsImage from 'src/utils/downloadAsImage'; import { getChartPermalink } from 'src/utils/urlUtils'; import copyTextToClipboard from 'src/utils/copy'; import HeaderReportDropDown from 'src/components/ReportModal/HeaderReportDropdown'; +import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import ViewQueryModal from '../controls/ViewQueryModal'; import EmbedCodeContent from '../EmbedCodeContent'; +import DashboardsSubMenu from './DashboardsSubMenu'; const MENU_KEYS = { EDIT_PROPERTIES: 'edit_properties', + DASHBOARDS_ADDED_TO: 'dashboards_added_to', DOWNLOAD_SUBMENU: 'download_submenu', EXPORT_TO_CSV: 'export_to_csv', EXPORT_TO_CSV_PIVOTED: 'export_to_csv_pivoted', EXPORT_TO_JSON: 'export_to_json', + EXPORT_TO_XLSX: 'export_to_xlsx', DOWNLOAD_AS_IMAGE: 'download_as_image', SHARE_SUBMENU: 'share_submenu', COPY_PERMALINK: 'copy_permalink', @@ -89,6 +93,13 @@ export const MenuTrigger = styled(Button)` `} `; +const iconReset = css` + .ant-dropdown-menu-item > & > .anticon:first-child { + margin-right: 0; + vertical-align: 0; + } +`; + export const useExploreAdditionalActionsMenu = ( latestQueryFormData, canDownloadCSV, @@ -96,26 +107,18 @@ export const useExploreAdditionalActionsMenu = ( onOpenInEditor, onOpenPropertiesModal, ownState, + dashboards, ) => { const theme = useTheme(); const { addDangerToast, addSuccessToast } = useToasts(); const [showReportSubMenu, setShowReportSubMenu] = useState(null); const [isDropdownVisible, setIsDropdownVisible] = useState(false); const [openSubmenus, setOpenSubmenus] = useState([]); - const charts = useSelector(state => state.charts); - const chart = useMemo(() => { - if (!charts) { - return undefined; - } - const chartsValues = Object.values(charts); - if (chartsValues.length > 0) { - return chartsValues[0]; - } - return undefined; - }, [charts]); + const chart = useSelector( + state => state.charts?.[getChartKey(state.explore)], + ); const { datasource } = latestQueryFormData; - const sqlSupported = datasource && datasource.split('__')[1] === 'table'; const shareByEmail = useCallback(async () => { try { @@ -163,6 +166,16 @@ export const useExploreAdditionalActionsMenu = ( [latestQueryFormData], ); + const exportExcel = useCallback( + () => + exportChart({ + formData: latestQueryFormData, + resultType: 'results', + resultFormat: 'xlsx', + }), + [latestQueryFormData], + ); + const copyLink = useCallback(async () => { try { if (!latestQueryFormData) { @@ -197,6 +210,11 @@ export const useExploreAdditionalActionsMenu = ( setIsDropdownVisible(false); setOpenSubmenus([]); + break; + case MENU_KEYS.EXPORT_TO_XLSX: + exportExcel(); + setIsDropdownVisible(false); + setOpenSubmenus([]); break; case MENU_KEYS.DOWNLOAD_AS_IMAGE: downloadAsImage( @@ -254,27 +272,36 @@ export const useExploreAdditionalActionsMenu = ( openKeys={openSubmenus} onOpenChange={setOpenSubmenus} > - {slice && ( - <> + <> + {slice && ( <Menu.Item key={MENU_KEYS.EDIT_PROPERTIES}> {t('Edit chart properties')} </Menu.Item> - <Menu.Divider /> - </> - )} + )} + <Menu.SubMenu + title={t('Dashboards added to')} + key={MENU_KEYS.DASHBOARDS_ADDED_TO} + > + <DashboardsSubMenu + chartId={slice?.slice_id} + dashboards={dashboards} + /> + </Menu.SubMenu> + <Menu.Divider /> + </> <Menu.SubMenu title={t('Download')} key={MENU_KEYS.DOWNLOAD_SUBMENU}> {VIZ_TYPES_PIVOTABLE.includes(latestQueryFormData.viz_type) ? ( <> <Menu.Item key={MENU_KEYS.EXPORT_TO_CSV} - icon={<FileOutlined />} + icon={<Icons.FileOutlined css={iconReset} />} disabled={!canDownloadCSV} > {t('Export to original .CSV')} </Menu.Item> <Menu.Item key={MENU_KEYS.EXPORT_TO_CSV_PIVOTED} - icon={<FileOutlined />} + icon={<Icons.FileOutlined css={iconReset} />} disabled={!canDownloadCSV} > {t('Export to pivoted .CSV')} @@ -283,21 +310,30 @@ export const useExploreAdditionalActionsMenu = ( ) : ( <Menu.Item key={MENU_KEYS.EXPORT_TO_CSV} - icon={<FileOutlined />} + icon={<Icons.FileOutlined css={iconReset} />} disabled={!canDownloadCSV} > {t('Export to .CSV')} </Menu.Item> )} - <Menu.Item key={MENU_KEYS.EXPORT_TO_JSON} icon={<FileOutlined />}> + <Menu.Item + key={MENU_KEYS.EXPORT_TO_JSON} + icon={<Icons.FileOutlined css={iconReset} />} + > {t('Export to .JSON')} </Menu.Item> <Menu.Item key={MENU_KEYS.DOWNLOAD_AS_IMAGE} - icon={<FileImageOutlined />} + icon={<Icons.FileImageOutlined css={iconReset} />} > {t('Download as image')} </Menu.Item> + <Menu.Item + key={MENU_KEYS.EXPORT_TO_XLSX} + icon={<Icons.FileOutlined css={iconReset} />} + > + {t('Export to Excel')} + </Menu.Item> </Menu.SubMenu> <Menu.SubMenu title={t('Share')} key={MENU_KEYS.SHARE_SUBMENU}> <Menu.Item key={MENU_KEYS.COPY_PERMALINK}> @@ -306,23 +342,25 @@ export const useExploreAdditionalActionsMenu = ( <Menu.Item key={MENU_KEYS.SHARE_BY_EMAIL}> {t('Share chart by email')} </Menu.Item> - <Menu.Item key={MENU_KEYS.EMBED_CODE}> - <ModalTrigger - triggerNode={ - <span data-test="embed-code-button">{t('Embed code')}</span> - } - modalTitle={t('Embed code')} - modalBody={ - <EmbedCodeContent - formData={latestQueryFormData} - addDangerToast={addDangerToast} - /> - } - maxWidth={`${theme.gridUnit * 100}px`} - destroyOnClose - responsive - /> - </Menu.Item> + {isFeatureEnabled(FeatureFlag.EMBEDDABLE_CHARTS) ? ( + <Menu.Item key={MENU_KEYS.EMBED_CODE}> + <ModalTrigger + triggerNode={ + <span data-test="embed-code-button">{t('Embed code')}</span> + } + modalTitle={t('Embed code')} + modalBody={ + <EmbedCodeContent + formData={latestQueryFormData} + addDangerToast={addDangerToast} + /> + } + maxWidth={`${theme.gridUnit * 100}px`} + destroyOnClose + responsive + /> + </Menu.Item> + ) : null} </Menu.SubMenu> <Menu.Divider /> {showReportSubMenu ? ( @@ -364,7 +402,7 @@ export const useExploreAdditionalActionsMenu = ( responsive /> </Menu.Item> - {sqlSupported && ( + {datasource && ( <Menu.Item key={MENU_KEYS.RUN_IN_SQL_LAB}> {t('Run in SQL Lab')} </Menu.Item> @@ -375,13 +413,13 @@ export const useExploreAdditionalActionsMenu = ( addDangerToast, canDownloadCSV, chart, + dashboards, handleMenuClick, isDropdownVisible, latestQueryFormData, openSubmenus, showReportSubMenu, slice, - sqlSupported, theme.gridUnit, ], ); diff --git a/superset-frontend/src/explore/constants.ts b/superset-frontend/src/explore/constants.ts index f1353c7734bf7..cd038dac20ca3 100644 --- a/superset-frontend/src/explore/constants.ts +++ b/superset-frontend/src/explore/constants.ts @@ -45,6 +45,7 @@ export enum Operators { LATEST_PARTITION = 'LATEST_PARTITION', IS_TRUE = 'IS_TRUE', IS_FALSE = 'IS_FALSE', + TEMPORAL_RANGE = 'TEMPORAL_RANGE', } export interface OperatorType { @@ -55,37 +56,46 @@ export interface OperatorType { export const OPERATOR_ENUM_TO_OPERATOR_TYPE: { [key in Operators]: OperatorType; } = { - [Operators.EQUALS]: { display: 'Equal to (=)', operation: '==' }, - [Operators.NOT_EQUALS]: { display: 'Not equal to (≠)', operation: '!=' }, - [Operators.LESS_THAN]: { display: 'Less than (<)', operation: '<' }, + [Operators.EQUALS]: { display: t('Equal to (=)'), operation: '==' }, + [Operators.NOT_EQUALS]: { display: t('Not equal to (≠)'), operation: '!=' }, + [Operators.LESS_THAN]: { display: t('Less than (<)'), operation: '<' }, [Operators.LESS_THAN_OR_EQUAL]: { - display: 'Less or equal (<=)', + display: t('Less or equal (<=)'), operation: '<=', }, - [Operators.GREATER_THAN]: { display: 'Greater than (>)', operation: '>' }, + [Operators.GREATER_THAN]: { display: t('Greater than (>)'), operation: '>' }, [Operators.GREATER_THAN_OR_EQUAL]: { - display: 'Greater or equal (>=)', + display: t('Greater or equal (>=)'), operation: '>=', }, - [Operators.IN]: { display: 'In', operation: 'IN' }, - [Operators.NOT_IN]: { display: 'Not in', operation: 'NOT IN' }, - [Operators.LIKE]: { display: 'Like', operation: 'LIKE' }, - [Operators.ILIKE]: { display: 'Like (case insensitive)', operation: 'ILIKE' }, - [Operators.REGEX]: { display: 'Regex', operation: 'REGEX' }, - [Operators.IS_NOT_NULL]: { display: 'Is not null', operation: 'IS NOT NULL' }, - [Operators.IS_NULL]: { display: 'Is null', operation: 'IS NULL' }, + [Operators.IN]: { display: t('In'), operation: 'IN' }, + [Operators.NOT_IN]: { display: t('Not in'), operation: 'NOT IN' }, + [Operators.LIKE]: { display: t('Like'), operation: 'LIKE' }, + [Operators.ILIKE]: { + display: t('Like (case insensitive)'), + operation: 'ILIKE', + }, + [Operators.REGEX]: { display: t('Regex'), operation: 'REGEX' }, + [Operators.IS_NOT_NULL]: { + display: t('Is not null'), + operation: 'IS NOT NULL', + }, + [Operators.IS_NULL]: { display: t('Is null'), operation: 'IS NULL' }, [Operators.LATEST_PARTITION]: { - display: 'use latest_partition template', + display: t('use latest_partition template'), operation: 'LATEST PARTITION', }, - [Operators.IS_TRUE]: { display: 'Is true', operation: '==' }, - [Operators.IS_FALSE]: { display: 'Is false', operation: '==' }, + [Operators.IS_TRUE]: { display: t('Is true'), operation: '==' }, + [Operators.IS_FALSE]: { display: t('Is false'), operation: '==' }, + [Operators.TEMPORAL_RANGE]: { + display: t('TEMPORAL_RANGE'), + operation: 'TEMPORAL_RANGE', + }, }; export const OPERATORS_OPTIONS = Object.values(Operators) as Operators[]; export const TABLE_ONLY_OPERATORS = [Operators.LIKE, Operators.ILIKE]; -export const DRUID_ONLY_OPERATORS = [Operators.REGEX]; export const HAVING_OPERATORS = [ Operators.EQUALS, Operators.NOT_EQUALS, @@ -97,7 +107,10 @@ export const HAVING_OPERATORS = [ export const MULTI_OPERATORS = new Set([Operators.IN, Operators.NOT_IN]); // CUSTOM_OPERATORS will show operator in simple mode, // but will generate customized sqlExpression -export const CUSTOM_OPERATORS = new Set([Operators.LATEST_PARTITION]); +export const CUSTOM_OPERATORS = new Set([ + Operators.LATEST_PARTITION, + Operators.TEMPORAL_RANGE, +]); // DISABLE_INPUT_OPERATORS will disable filter value input // in adhocFilter control export const DISABLE_INPUT_OPERATORS = [ @@ -119,7 +132,6 @@ export const TIME_FILTER_LABELS = { time_range: t('Time range'), granularity_sqla: t('Time column'), time_grain_sqla: t('Time grain'), - druid_time_origin: t('Origin'), granularity: t('Time granularity'), }; @@ -141,14 +153,9 @@ export const TIME_FILTER_MAP = { time_range: '__time_range', granularity_sqla: '__time_col', time_grain_sqla: '__time_grain', - druid_time_origin: '__time_origin', granularity: '__granularity', }; -// TODO: make this configurable per Superset installation -export const DEFAULT_TIME_RANGE = 'No filter'; -export const NO_TIME_RANGE = 'No filter'; - export enum FILTER_BOX_MIGRATION_STATES { CONVERTED = 'CONVERTED', NOOP = 'NOOP', @@ -162,3 +169,5 @@ export const FILTER_BOX_TRANSITION_SNOOZE_DURATION = 24 * 60 * 60 * 1000; // 24 export const POPOVER_INITIAL_HEIGHT = 240; export const POPOVER_INITIAL_WIDTH = 320; export const UNRESIZABLE_POPOVER_WIDTH = 296; + +export const UNSAVED_CHART_ID = 0; diff --git a/superset-frontend/src/explore/controlPanels/sections.tsx b/superset-frontend/src/explore/controlPanels/sections.tsx index 78815215df228..51b6b9c2f2aa8 100644 --- a/superset-frontend/src/explore/controlPanels/sections.tsx +++ b/superset-frontend/src/explore/controlPanels/sections.tsx @@ -19,18 +19,8 @@ import React from 'react'; import { t } from '@superset-ui/core'; import { ControlPanelSectionConfig } from '@superset-ui/chart-controls'; -import { formatSelectOptions } from 'src/explore/exploreUtils'; - -export const druidTimeSeries: ControlPanelSectionConfig = { - label: t('Time'), - expanded: true, - description: t('Time related form attributes'), - controlSetRows: [['time_range']], -}; export const datasourceAndVizType: ControlPanelSectionConfig = { - label: t('Visualization type'), - expanded: true, controlSetRows: [ ['datasource'], ['viz_type'], @@ -90,7 +80,7 @@ export const annotations: ControlPanelSectionConfig = { type: 'AnnotationLayerControl', label: '', default: [], - description: 'Annotation layers', + description: t('Annotation layers'), renderTrigger: true, tabOverride: 'data', }, @@ -140,13 +130,13 @@ export const NVD3TimeSeries: ControlPanelSectionConfig[] = [ type: 'SelectControl', label: t('Rolling function'), default: 'None', - choices: formatSelectOptions([ - 'None', - 'mean', - 'sum', - 'std', - 'cumsum', - ]), + choices: [ + ['None', t('None')], + ['mean', t('mean')], + ['sum', t('sum')], + ['std', t('std')], + ['cumsum', t('cumsum')], + ], description: t( 'Defines a rolling window function to apply, works along ' + 'with the [Periods] text box', @@ -190,22 +180,22 @@ export const NVD3TimeSeries: ControlPanelSectionConfig[] = [ multi: true, freeForm: true, label: t('Time shift'), - choices: formatSelectOptions([ - '1 day', - '1 week', - '28 days', - '30 days', - '52 weeks', - '1 year', - '104 weeks', - '2 years', - '156 weeks', - '3 years', - ]), + choices: [ + ['1 day', t('1 day')], + ['1 week', t('1 week')], + ['28 days', t('28 days')], + ['30 days', t('30 days')], + ['52 weeks', t('52 weeks')], + ['1 year', t('1 year')], + ['104 weeks', t('104 weeks')], + ['2 years', t('2 years')], + ['156 weeks', t('156 weeks')], + ['3 years', t('3 years')], + ], description: t( 'Overlay one or more timeseries from a ' + 'relative time period. Expects relative time deltas ' + - 'in natural language (example: 24 hours, 7 days, ' + + 'in natural language (example: 24 hours, 7 days, ' + '52 weeks, 365 days). Free text is supported.', ), }, @@ -217,10 +207,10 @@ export const NVD3TimeSeries: ControlPanelSectionConfig[] = [ label: t('Calculation type'), default: 'values', choices: [ - ['values', 'Actual values'], - ['absolute', 'Difference'], - ['percentage', 'Percentage change'], - ['ratio', 'Ratio'], + ['values', t('Actual values')], + ['absolute', t('Difference')], + ['percentage', t('Percentage change')], + ['ratio', t('Ratio')], ], description: t( 'How to display time shifts: as individual lines; as the ' + @@ -239,7 +229,14 @@ export const NVD3TimeSeries: ControlPanelSectionConfig[] = [ freeForm: true, label: t('Rule'), default: null, - choices: formatSelectOptions(['1T', '1H', '1D', '7D', '1M', '1AS']), + choices: [ + ['1T', t('1T')], + ['1H', t('1H')], + ['1D', t('1D')], + ['7D', t('7D')], + ['1M', t('1M')], + ['1AS', t('1AS')], + ], description: t('Pandas resample rule'), }, }, @@ -250,14 +247,14 @@ export const NVD3TimeSeries: ControlPanelSectionConfig[] = [ freeForm: true, label: t('Method'), default: null, - choices: formatSelectOptions([ - 'asfreq', - 'bfill', - 'ffill', - 'median', - 'mean', - 'sum', - ]), + choices: [ + ['asfreq', t('asfreq')], + ['bfill', t('bfill')], + ['ffill', t('ffill')], + ['median', t('median')], + ['mean', t('mean')], + ['sum', t('sum')], + ], description: t('Pandas resample method'), }, }, diff --git a/superset-frontend/src/explore/controlUtils/controlUtils.test.tsx b/superset-frontend/src/explore/controlUtils/controlUtils.test.tsx index 1b9cf1ea55c73..5feefc3481aa1 100644 --- a/superset-frontend/src/explore/controlUtils/controlUtils.test.tsx +++ b/superset-frontend/src/explore/controlUtils/controlUtils.test.tsx @@ -59,6 +59,7 @@ describe('controlUtils', () => { }, controls: {}, form_data: { datasource: '1__table', viz_type: 'table' }, + common: {}, }; beforeAll(() => { diff --git a/superset-frontend/src/explore/controlUtils/getControlState.ts b/superset-frontend/src/explore/controlUtils/getControlState.ts index 5014cd3c1a40c..794c2b7b7a9d8 100644 --- a/superset-frontend/src/explore/controlUtils/getControlState.ts +++ b/superset-frontend/src/explore/controlUtils/getControlState.ts @@ -98,6 +98,21 @@ export function applyMapStateToPropsToControl<T = ControlType>( // `mapStateToProps` may also provide a value value = value || state.value; } + + // InitialValue is used for setting value for the control, + // this value is not recalculated. The default value will override it. + if (typeof state.initialValue === 'function') { + state.initialValue = state.initialValue(state, controlPanelState); + // if default is still a function, discard + if (typeof state.initialValue === 'function') { + delete state.initialValue; + } + } + if (state.initialValue) { + value = state.initialValue; + delete state.initialValue; + } + // If default is a function, evaluate it if (typeof state.default === 'function') { state.default = state.default(state, controlPanelState); @@ -159,7 +174,7 @@ export function getAllControlsState( getSectionsToRender(vizType, datasourceType).forEach(section => section.controlSetRows.forEach(fieldsetRow => fieldsetRow.forEach((field: CustomControlItem) => { - if (field && field.config && field.name) { + if (field?.config && field.name) { const { config, name } = field; controlsState[name] = getControlStateFromControlConfig( config, diff --git a/superset-frontend/src/explore/controlUtils/getControlValuesCompatibleWithDatasource.test.ts b/superset-frontend/src/explore/controlUtils/getControlValuesCompatibleWithDatasource.test.ts new file mode 100644 index 0000000000000..ad7ccc480121a --- /dev/null +++ b/superset-frontend/src/explore/controlUtils/getControlValuesCompatibleWithDatasource.test.ts @@ -0,0 +1,287 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + ControlState, + Dataset, + sharedControls, +} from '@superset-ui/chart-controls'; +import { DatasourceType, JsonValue } from '@superset-ui/core'; +import { getControlValuesCompatibleWithDatasource } from './getControlValuesCompatibleWithDatasource'; + +const sampleDatasource: Dataset = { + id: 1, + type: DatasourceType.Table, + columns: [ + { column_name: 'sample_column_1' }, + { column_name: 'sample_column_3' }, + { column_name: 'sample_column_4' }, + ], + metrics: [{ metric_name: 'saved_metric_2' }], + column_format: {}, + verbose_map: {}, + main_dttm_col: '', + datasource_name: 'Sample Dataset', + description: 'A sample dataset', +}; + +const getValues = (controlState: ControlState) => { + const { value } = controlState; + return getControlValuesCompatibleWithDatasource( + sampleDatasource, + controlState, + value as JsonValue, + ); +}; + +test('empty values', () => { + const controlState = sharedControls.groupby; + expect( + getValues({ + ...controlState, + value: undefined, + }), + ).toEqual(undefined); + + expect( + getValues({ + ...controlState, + value: null, + }), + ).toEqual(undefined); + + expect( + getValues({ + ...controlState, + value: [], + }), + ).toEqual(controlState.default); +}); + +test('column values', () => { + const controlState = { + ...sharedControls.columns, + options: [ + { column_name: 'sample_column_1' }, + { column_name: 'sample_column_2' }, + { column_name: 'sample_column_3' }, + ], + }; + + expect( + getValues({ + ...controlState, + value: 'sample_column_1', + }), + ).toEqual('sample_column_1'); + + expect( + getValues({ + ...controlState, + value: 'sample_column_2', + }), + ).toEqual(controlState.default); + + expect( + getValues({ + ...controlState, + value: 'sample_column_3', + }), + ).toEqual('sample_column_3'); + + expect( + getValues({ + ...controlState, + value: ['sample_column_1', 'sample_column_2', 'sample_column_3'], + }), + ).toEqual(['sample_column_1', 'sample_column_3']); +}); + +test('saved metric values', () => { + const controlState = { + ...sharedControls.metrics, + savedMetrics: [ + { metric_name: 'saved_metric_1' }, + { metric_name: 'saved_metric_2' }, + ], + }; + + expect( + getValues({ + ...controlState, + value: 'saved_metric_1', + }), + ).toEqual(controlState.default); + + expect( + getValues({ + ...controlState, + value: 'saved_metric_2', + }), + ).toEqual('saved_metric_2'); + + expect( + getValues({ + ...controlState, + value: ['saved_metric_1', 'saved_metric_2'], + }), + ).toEqual(['saved_metric_2']); +}); + +test('simple ad-hoc metric values', () => { + const controlState = { + ...sharedControls.metrics, + columns: [ + { column_name: 'sample_column_1' }, + { column_name: 'sample_column_2' }, + { column_name: 'sample_column_3' }, + ], + }; + + expect( + getValues({ + ...controlState, + value: { + expressionType: 'SIMPLE', + column: { column_name: 'sample_column_1' }, + }, + }), + ).toEqual({ + expressionType: 'SIMPLE', + column: { column_name: 'sample_column_1' }, + }); + + expect( + getValues({ + ...controlState, + value: { + expressionType: 'SIMPLE', + column: { column_name: 'sample_column_2' }, + }, + }), + ).toEqual(controlState.default); + + expect( + getValues({ + ...controlState, + value: [ + { + expressionType: 'SIMPLE', + column: { column_name: 'sample_column_1' }, + }, + { + expressionType: 'SIMPLE', + column: { column_name: 'sample_column_2' }, + }, + ], + }), + ).toEqual([ + { expressionType: 'SIMPLE', column: { column_name: 'sample_column_1' } }, + ]); +}); + +test('SQL ad-hoc metric values', () => { + const controlState = { + ...sharedControls.metrics, + }; + + expect( + getValues({ + ...controlState, + value: { + expressionType: 'SQL', + sqlExpression: 'select * from sample_column_1;', + }, + }), + ).toEqual({ + datasourceWarning: true, + expressionType: 'SQL', + sqlExpression: 'select * from sample_column_1;', + }); +}); + +test('simple ad-hoc filter values', () => { + const controlState = { + ...sharedControls.adhoc_filters, + columns: [ + { column_name: 'sample_column_1' }, + { column_name: 'sample_column_2' }, + { column_name: 'sample_column_3' }, + ], + }; + + expect( + getValues({ + ...controlState, + value: { + expressionType: 'SIMPLE', + subject: 'sample_column_1', + }, + }), + ).toEqual({ + expressionType: 'SIMPLE', + subject: 'sample_column_1', + }); + + expect( + getValues({ + ...controlState, + value: { + expressionType: 'SIMPLE', + subject: 'sample_column_2', + }, + }), + ).toEqual(controlState.default); + + expect( + getValues({ + ...controlState, + value: [ + { + expressionType: 'SIMPLE', + subject: 'sample_column_1', + }, + { + expressionType: 'SIMPLE', + subject: 'sample_column_2', + }, + ], + }), + ).toEqual([{ expressionType: 'SIMPLE', subject: 'sample_column_1' }]); +}); + +test('SQL ad-hoc filter values', () => { + const controlState = { + ...sharedControls.adhoc_filters, + }; + + expect( + getValues({ + ...controlState, + value: { + expressionType: 'SQL', + sqlExpression: 'select * from sample_column_1;', + }, + }), + ).toEqual({ + datasourceWarning: true, + expressionType: 'SQL', + sqlExpression: 'select * from sample_column_1;', + }); +}); diff --git a/superset-frontend/src/explore/controlUtils/getControlValuesCompatibleWithDatasource.ts b/superset-frontend/src/explore/controlUtils/getControlValuesCompatibleWithDatasource.ts index e070e82464d52..7013b59764cb0 100644 --- a/superset-frontend/src/explore/controlUtils/getControlValuesCompatibleWithDatasource.ts +++ b/superset-frontend/src/explore/controlUtils/getControlValuesCompatibleWithDatasource.ts @@ -21,6 +21,7 @@ import { ControlState, Dataset, Metric } from '@superset-ui/chart-controls'; import { Column, isAdhocMetricSimple, + isAdhocMetricSQL, isSavedMetric, isSimpleAdhocFilter, JsonValue, @@ -35,11 +36,12 @@ const isControlValueCompatibleWithDatasource = ( ) => { if (controlState.options && typeof value === 'string') { if ( - (Array.isArray(controlState.options) && - controlState.options.some( - (option: [string | number, string]) => option[0] === value, - )) || - value in controlState.options + controlState.options.some( + (option: [string | number, string] | { column_name: string }) => + Array.isArray(option) + ? option[0] === value + : option.column_name === value, + ) ) { return datasource.columns.some(column => column.column_name === value); } @@ -70,6 +72,10 @@ const isControlValueCompatibleWithDatasource = ( column.column_name === (value as SimpleAdhocFilter).subject, ); } + if (isAdhocMetricSQL(value)) { + Object.assign(value, { datasourceWarning: true }); + return true; + } return false; }; diff --git a/superset-frontend/src/explore/controlUtils/getFormDataFromDashboardContext.test.ts b/superset-frontend/src/explore/controlUtils/getFormDataFromDashboardContext.test.ts new file mode 100644 index 0000000000000..f3584e1c70924 --- /dev/null +++ b/superset-frontend/src/explore/controlUtils/getFormDataFromDashboardContext.test.ts @@ -0,0 +1,305 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { JsonObject } from '@superset-ui/core'; +import { getFormDataWithDashboardContext } from './getFormDataWithDashboardContext'; + +const getExploreFormData = (overrides: JsonObject = {}) => ({ + adhoc_filters: [ + { + clause: 'WHERE' as const, + expressionType: 'SIMPLE' as const, + operator: 'IN' as const, + subject: 'gender', + comparator: ['boys'], + filterOptionName: '123', + }, + { + clause: 'WHERE' as const, + expressionType: 'SQL' as const, + operator: null, + subject: null, + comparator: null, + sqlExpression: "name = 'John'", + filterOptionName: '456', + }, + { + clause: 'WHERE' as const, + expressionType: 'SQL' as const, + operator: null, + subject: null, + comparator: null, + sqlExpression: "city = 'Warsaw'", + filterOptionName: '567', + }, + { + clause: 'WHERE' as const, + expressionType: 'SIMPLE' as const, + operator: 'TEMPORAL_RANGE' as const, + subject: 'ds', + comparator: 'No filter', + filterOptionName: '678', + }, + ], + adhoc_filters_b: [ + { + clause: 'WHERE' as const, + expressionType: 'SQL' as const, + operator: null, + subject: null, + comparator: null, + sqlExpression: "country = 'Poland'", + filterOptionName: '789', + }, + ], + applied_time_extras: {}, + color_scheme: 'supersetColors', + datasource: '2__table', + granularity_sqla: 'ds', + groupby: ['gender'], + metric: { + aggregate: 'SUM', + column: { + column_name: 'num', + type: 'BIGINT', + }, + expressionType: 'SIMPLE', + label: 'Births', + }, + slice_id: 46, + time_range: '100 years ago : now', + viz_type: 'pie', + ...overrides, +}); + +const getDashboardFormData = (overrides: JsonObject = {}) => ({ + label_colors: { + Girls: '#FF69B4', + Boys: '#ADD8E6', + girl: '#FF69B4', + boy: '#ADD8E6', + }, + shared_label_colors: { + boy: '#ADD8E6', + girl: '#FF69B4', + }, + color_scheme: 'd3Category20b', + extra_filters: [ + { + col: '__time_range', + op: '==', + val: 'No filter', + }, + { + col: '__time_grain', + op: '==', + val: 'P1D', + }, + { + col: '__time_col', + op: '==', + val: 'ds', + }, + ], + extra_form_data: { + filters: [ + { + col: 'name', + op: 'IN', + val: ['Aaron'], + }, + { + col: 'num_boys', + op: '<=', + val: 10000, + }, + ], + granularity_sqla: 'ds', + time_range: 'Last month', + time_grain_sqla: 'PT1S', + }, + dashboardId: 2, + ...overrides, +}); + +const getExpectedResultFormData = (overrides: JsonObject = {}) => ({ + adhoc_filters: [ + { + clause: 'WHERE', + expressionType: 'SIMPLE', + operator: 'IN', + subject: 'gender', + comparator: ['boys'], + filterOptionName: '123', + }, + { + clause: 'WHERE' as const, + expressionType: 'SQL' as const, + operator: null, + subject: null, + comparator: null, + sqlExpression: "name = 'John'", + filterOptionName: '456', + }, + { + clause: 'WHERE' as const, + expressionType: 'SQL' as const, + operator: null, + subject: null, + comparator: null, + sqlExpression: "city = 'Warsaw'", + filterOptionName: '567', + }, + { + clause: 'WHERE', + expressionType: 'SIMPLE', + operator: 'TEMPORAL_RANGE', + subject: 'ds', + comparator: 'Last month', + filterOptionName: expect.any(String), + isExtra: true, + }, + { + clause: 'WHERE', + expressionType: 'SIMPLE', + operator: 'IN', + subject: 'name', + comparator: ['Aaron'], + isExtra: true, + filterOptionName: expect.any(String), + }, + { + clause: 'WHERE', + expressionType: 'SIMPLE', + operator: '<=', + subject: 'num_boys', + comparator: 10000, + isExtra: true, + filterOptionName: expect.any(String), + }, + ], + adhoc_filters_b: [ + { + clause: 'WHERE' as const, + expressionType: 'SQL' as const, + operator: null, + subject: null, + comparator: null, + sqlExpression: "country = 'Poland'", + filterOptionName: expect.any(String), + }, + { + clause: 'WHERE', + expressionType: 'SIMPLE', + operator: 'IN', + subject: 'name', + comparator: ['Aaron'], + isExtra: true, + filterOptionName: expect.any(String), + }, + { + clause: 'WHERE', + expressionType: 'SIMPLE', + operator: '<=', + subject: 'num_boys', + comparator: 10000, + isExtra: true, + filterOptionName: expect.any(String), + }, + ], + applied_time_extras: { + __time_grain: 'P1D', + __time_col: 'ds', + }, + color_scheme: 'd3Category20b', + datasource: '2__table', + granularity_sqla: 'ds', + groupby: ['gender'], + metric: { + aggregate: 'SUM', + column: { + column_name: 'num', + type: 'BIGINT', + }, + expressionType: 'SIMPLE', + label: 'Births', + }, + slice_id: 46, + time_range: 'Last month', + viz_type: 'pie', + label_colors: { + Girls: '#FF69B4', + Boys: '#ADD8E6', + girl: '#FF69B4', + boy: '#ADD8E6', + }, + shared_label_colors: { + boy: '#ADD8E6', + girl: '#FF69B4', + }, + extra_filters: [ + { + col: '__time_range', + op: '==', + val: 'No filter', + }, + { + col: '__time_grain', + op: '==', + val: 'P1D', + }, + { + col: '__time_col', + op: '==', + val: 'ds', + }, + ], + extra_form_data: { + filters: [ + { + col: 'name', + op: 'IN', + val: ['Aaron'], + }, + { + col: 'num_boys', + op: '<=', + val: 10000, + }, + ], + granularity_sqla: 'ds', + time_range: 'Last month', + time_grain_sqla: 'PT1S', + }, + dashboardId: 2, + time_grain_sqla: 'PT1S', + granularity: 'ds', + extras: { + time_grain_sqla: 'PT1S', + }, + ...overrides, +}); + +test('merges dashboard context form data with explore form data', () => { + const fullFormData = getFormDataWithDashboardContext( + getExploreFormData(), + getDashboardFormData(), + ); + expect(fullFormData).toEqual(getExpectedResultFormData()); +}); diff --git a/superset-frontend/src/explore/controlUtils/getFormDataWithDashboardContext.ts b/superset-frontend/src/explore/controlUtils/getFormDataWithDashboardContext.ts new file mode 100644 index 0000000000000..9565b48ddf461 --- /dev/null +++ b/superset-frontend/src/explore/controlUtils/getFormDataWithDashboardContext.ts @@ -0,0 +1,236 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import isEqual from 'lodash/isEqual'; +import { + EXTRA_FORM_DATA_OVERRIDE_REGULAR_MAPPINGS, + EXTRA_FORM_DATA_OVERRIDE_EXTRA_KEYS, + isDefined, + JsonObject, + ensureIsArray, + QueryObjectFilterClause, + SimpleAdhocFilter, + QueryFormData, + AdhocFilter, + isFreeFormAdhocFilter, + isSimpleAdhocFilter, + NO_TIME_RANGE, +} from '@superset-ui/core'; + +const simpleFilterToAdhoc = ( + filterClause: QueryObjectFilterClause, + clause = 'where', +) => { + const result = { + clause: clause.toUpperCase(), + expressionType: 'SIMPLE', + operator: filterClause.op, + subject: filterClause.col, + comparator: 'val' in filterClause ? filterClause.val : undefined, + } as SimpleAdhocFilter; + if (filterClause.isExtra) { + Object.assign(result, { + isExtra: true, + filterOptionName: `filter_${Math.random() + .toString(36) + .substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`, + }); + } + return result; +}; + +const removeAdhocFilterDuplicates = (filters: AdhocFilter[]) => { + const isDuplicate = ( + adhocFilter: AdhocFilter, + existingFilters: AdhocFilter[], + ) => + existingFilters.some( + (existingFilter: AdhocFilter) => + (isFreeFormAdhocFilter(existingFilter) && + isFreeFormAdhocFilter(adhocFilter) && + existingFilter.clause === adhocFilter.clause && + existingFilter.sqlExpression === adhocFilter.sqlExpression) || + (isSimpleAdhocFilter(existingFilter) && + isSimpleAdhocFilter(adhocFilter) && + existingFilter.operator === adhocFilter.operator && + existingFilter.subject === adhocFilter.subject && + ((!('comparator' in existingFilter) && + !('comparator' in adhocFilter)) || + ('comparator' in existingFilter && + 'comparator' in adhocFilter && + isEqual(existingFilter.comparator, adhocFilter.comparator)))), + ); + + return filters.reduce((acc, filter) => { + if (!isDuplicate(filter, acc)) { + acc.push(filter); + } + return acc; + }, [] as AdhocFilter[]); +}; + +const mergeFilterBoxToFormData = ( + exploreFormData: QueryFormData, + dashboardFormData: JsonObject, +) => { + const dateColumns = { + __time_range: 'time_range', + __time_col: 'granularity_sqla', + __time_grain: 'time_grain_sqla', + __granularity: 'granularity', + }; + const appliedTimeExtras = {}; + + const filterBoxData: JsonObject = {}; + ensureIsArray(dashboardFormData.extra_filters).forEach(filter => { + if (dateColumns[filter.col]) { + if (filter.val !== NO_TIME_RANGE) { + filterBoxData[dateColumns[filter.col]] = filter.val; + appliedTimeExtras[filter.col] = filter.val; + } + } else { + const adhocFilter = simpleFilterToAdhoc({ + ...(filter as QueryObjectFilterClause), + isExtra: true, + }); + filterBoxData.adhoc_filters = [ + ...ensureIsArray(filterBoxData.adhoc_filters), + adhocFilter, + ]; + } + }); + filterBoxData.applied_time_extras = appliedTimeExtras; + return filterBoxData; +}; + +const mergeNativeFiltersToFormData = ( + exploreFormData: QueryFormData, + dashboardFormData: JsonObject, +) => { + const nativeFiltersData: JsonObject = {}; + const extraFormData = dashboardFormData.extra_form_data || {}; + + Object.entries(EXTRA_FORM_DATA_OVERRIDE_REGULAR_MAPPINGS).forEach( + ([srcKey, targetKey]) => { + const val = extraFormData[srcKey]; + if (isDefined(val)) { + nativeFiltersData[targetKey] = val; + } + }, + ); + + if ('time_grain_sqla' in extraFormData) { + nativeFiltersData.time_grain_sqla = extraFormData.time_grain_sqla; + } + if ('granularity_sqla' in extraFormData) { + nativeFiltersData.granularity_sqla = extraFormData.granularity_sqla; + } + + const extras = dashboardFormData.extras || {}; + EXTRA_FORM_DATA_OVERRIDE_EXTRA_KEYS.forEach(key => { + const val = extraFormData[key]; + if (isDefined(val)) { + extras[key] = val; + } + }); + if (Object.keys(extras).length) { + nativeFiltersData.extras = extras; + } + + nativeFiltersData.adhoc_filters = ensureIsArray( + extraFormData.adhoc_filters, + ).map(filter => ({ + ...filter, + isExtra: true, + })); + + const appendFilters = ensureIsArray(extraFormData.filters).map(extraFilter => + simpleFilterToAdhoc({ ...extraFilter, isExtra: true }), + ); + Object.keys(exploreFormData).forEach(key => { + if (key.match(/adhoc_filter.*/)) { + nativeFiltersData[key] = [ + ...ensureIsArray(nativeFiltersData[key]), + ...appendFilters, + ]; + } + }); + return nativeFiltersData; +}; + +const applyTimeRangeFilters = ( + dashboardFormData: JsonObject, + adhocFilters: AdhocFilter[], +) => { + const extraFormData = dashboardFormData.extra_form_data || {}; + if ('time_range' in extraFormData) { + return adhocFilters.map((filter: SimpleAdhocFilter) => { + if (filter.operator === 'TEMPORAL_RANGE') { + return { + ...filter, + comparator: extraFormData.time_range, + isExtra: true, + }; + } + return filter; + }); + } + return adhocFilters; +}; + +export const getFormDataWithDashboardContext = ( + exploreFormData: QueryFormData, + dashboardContextFormData: JsonObject, +) => { + const filterBoxData = mergeFilterBoxToFormData( + exploreFormData, + dashboardContextFormData, + ); + const nativeFiltersData = mergeNativeFiltersToFormData( + exploreFormData, + dashboardContextFormData, + ); + const adhocFilters = [ + ...Object.keys(exploreFormData), + ...Object.keys(filterBoxData), + ...Object.keys(nativeFiltersData), + ] + .filter(key => key.match(/adhoc_filter.*/)) + .reduce( + (acc, key) => ({ + ...acc, + [key]: applyTimeRangeFilters( + dashboardContextFormData, + removeAdhocFilterDuplicates([ + ...ensureIsArray(exploreFormData[key]), + ...ensureIsArray(filterBoxData[key]), + ...ensureIsArray(nativeFiltersData[key]), + ]), + ), + }), + {}, + ); + + return { + ...exploreFormData, + ...dashboardContextFormData, + ...filterBoxData, + ...nativeFiltersData, + ...adhocFilters, + }; +}; diff --git a/superset-frontend/src/explore/controlUtils/getSectionsToRender.ts b/superset-frontend/src/explore/controlUtils/getSectionsToRender.ts index c82833f4705b1..5bfefb8ec6545 100644 --- a/superset-frontend/src/explore/controlUtils/getSectionsToRender.ts +++ b/superset-frontend/src/explore/controlUtils/getSectionsToRender.ts @@ -54,11 +54,11 @@ const getMemoizedSectionsToRender = memoizeOne( const { datasourceAndVizType } = sections; - // list of datasource-specific controls that should be removed - const invalidControls = - datasourceType === 'table' - ? ['granularity', 'druid_time_origin'] - : ['granularity_sqla', 'time_grain_sqla']; + // list of datasource-specific controls that should be removed if the datasource is a specific type + const filterControlsForTypes = [DatasourceType.Query, DatasourceType.Table]; + const invalidControls = filterControlsForTypes.includes(datasourceType) + ? ['granularity'] + : ['granularity_sqla', 'time_grain_sqla']; return [datasourceAndVizType] .concat(controlPanelSections.filter(isControlPanelSectionConfig)) diff --git a/superset-frontend/src/explore/controlUtils/standardizedFormData.test.ts b/superset-frontend/src/explore/controlUtils/standardizedFormData.test.ts index e7d1c758c44d9..4f8de967a895b 100644 --- a/superset-frontend/src/explore/controlUtils/standardizedFormData.test.ts +++ b/superset-frontend/src/explore/controlUtils/standardizedFormData.test.ts @@ -16,33 +16,180 @@ * specific language governing permissions and limitations * under the License. */ -import { getChartControlPanelRegistry, QueryFormData } from '@superset-ui/core'; +import { + AdhocColumn, + AdhocMetricSimple, + AdhocMetricSQL, + getChartControlPanelRegistry, + QueryFormData, + TimeGranularity, +} from '@superset-ui/core'; import TableChartPlugin from '@superset-ui/plugin-chart-table'; import { BigNumberTotalChartPlugin } from '@superset-ui/plugin-chart-echarts'; import { sections } from '@superset-ui/chart-controls'; import { StandardizedFormData, - sharedControls, + sharedMetricsKey, + sharedColumnsKey, publicControls, } from './standardizedFormData'; -import { xAxisControl } from '../../../plugins/plugin-chart-echarts/src/controls'; + +const adhocColumn: AdhocColumn = { + expressionType: 'SQL', + label: 'country', + optionName: 'country', + sqlExpression: 'country', +}; +const adhocMetricSQL: AdhocMetricSQL = { + expressionType: 'SQL', + label: 'count', + optionName: 'count', + sqlExpression: 'count(*)', +}; +const adhocMetricSimple: AdhocMetricSimple = { + expressionType: 'SIMPLE', + column: { + id: 1, + column_name: 'sales', + columnName: 'sales', + verbose_name: 'sales', + }, + aggregate: 'SUM', + label: 'count', + optionName: 'count', +}; + +const tableVizFormData = { + datasource: '30__table', + viz_type: 'table', + granularity_sqla: 'ds', + time_grain_sqla: TimeGranularity.DAY, + time_range: 'No filter', + query_mode: 'aggregate', + groupby: ['name', 'gender', adhocColumn], + metrics: ['count', 'avg(sales)', adhocMetricSimple, adhocMetricSQL], + all_columns: [], + percent_metrics: [], + adhoc_filters: [], + order_by_cols: [], + row_limit: 10000, + server_page_length: 10, + order_desc: true, + table_timestamp_format: 'smart_date', + show_cell_bars: true, + color_pn: true, + url_params: { + form_data_key: + 'p3No_sqDW7k-kMTzlBPAPd9vwp1IXTf6stbyzjlrPPa0ninvdYUUiMC6F1iKit3Y', + dataset_id: '30', + }, +}; +const tableVizStore = { + form_data: tableVizFormData, + controls: { + datasource: { + value: '30__table', + }, + viz_type: { + value: 'table', + }, + slice_id: {}, + cache_timeout: {}, + url_params: { + value: { + form_data_key: + 'p3No_sqDW7k-kMTzlBPAPd9vwp1IXTf6stbyzjlrPPa0ninvdYUUiMC6F1iKit3Y', + dataset_id: '30', + }, + }, + granularity_sqla: { + value: 'ds', + }, + time_grain_sqla: { + value: 'P1D', + }, + time_range: { + value: 'No filter', + }, + query_mode: { + value: 'aggregate', + }, + groupby: { + value: ['name', 'gender', adhocColumn], + }, + metrics: { + value: ['count', 'avg(sales)', adhocMetricSimple, adhocMetricSQL], + }, + all_columns: { + value: [], + }, + percent_metrics: { + value: [], + }, + adhoc_filters: { + value: [], + }, + timeseries_limit_metric: {}, + order_by_cols: { + value: [], + }, + server_pagination: {}, + row_limit: { + value: 10000, + }, + server_page_length: { + value: 10, + }, + include_time: {}, + order_desc: { + value: true, + }, + show_totals: {}, + table_timestamp_format: { + value: 'smart_date', + }, + page_length: {}, + include_search: {}, + show_cell_bars: { + value: true, + }, + align_pn: {}, + color_pn: { + value: true, + }, + column_config: {}, + conditional_formatting: {}, + }, + datasource: { + type: 'table', + columns: [], + }, +}; describe('should collect control values and create SFD', () => { + const sharedKey = [...sharedMetricsKey, ...sharedColumnsKey]; const sharedControlsFormData = { // metrics metric: 'm1', metrics: ['m2'], metric_2: 'm3', + size: 'm4', + x: 'm5', + y: 'm6', + secondary_metric: 'm7', // columns groupby: ['c1'], columns: ['c2'], groupbyColumns: ['c3'], groupbyRows: ['c4'], + series: 'c5', + entity: 'c6', + series_columns: ['c7'], }; const publicControlsFormData = { // time section granularity_sqla: 'time_column', - time_grain_sqla: 'P1D', + time_grain_sqla: TimeGranularity.DAY, time_range: '2000 : today', // filters adhoc_filters: [], @@ -74,6 +221,7 @@ describe('should collect control values and create SFD', () => { datasource: '100__table', viz_type: 'source_viz', }; + const sourceMockStore = { form_data: sourceMockFormData, controls: Object.fromEntries( @@ -87,6 +235,7 @@ describe('should collect control values and create SFD', () => { columns: [], }, }; + beforeAll(() => { getChartControlPanelRegistry().registerValue('source_viz', { controlPanelSections: [ @@ -97,7 +246,7 @@ describe('should collect control values and create SFD', () => { }, { label: 'axis column', - controlSetRows: [[xAxisControl]], + controlSetRows: [['x_axis']], }, ], }); @@ -110,19 +259,19 @@ describe('should collect control values and create SFD', () => { }, { label: 'axis column', - controlSetRows: [[xAxisControl]], + controlSetRows: [['x_axis']], }, ], - denormalizeFormData: (formData: QueryFormData) => ({ + formDataOverrides: (formData: QueryFormData) => ({ ...formData, - columns: formData.standardizedFormData.standardizedState.columns, - metrics: formData.standardizedFormData.standardizedState.metrics, + columns: formData.standardizedFormData.controls.columns, + metrics: formData.standardizedFormData.controls.metrics, }), }); }); test('should avoid to overlap', () => { - const sharedControlsSet = new Set(Object.keys(sharedControls)); + const sharedControlsSet = new Set(Object.keys(sharedKey)); const publicControlsSet = new Set(publicControls); expect( [...sharedControlsSet].filter((x: string) => publicControlsSet.has(x)), @@ -131,19 +280,26 @@ describe('should collect control values and create SFD', () => { test('should collect all sharedControls', () => { expect(Object.entries(sharedControlsFormData).length).toBe( - Object.entries(sharedControls).length, + Object.entries(sharedKey).length, ); const sfd = new StandardizedFormData(sourceMockFormData); - expect(sfd.serialize().standardizedState.metrics).toEqual([ + expect(sfd.serialize().controls.metrics).toEqual([ 'm1', 'm2', 'm3', + 'm4', + 'm5', + 'm6', + 'm7', ]); - expect(sfd.serialize().standardizedState.columns).toEqual([ + expect(sfd.serialize().controls.columns).toEqual([ 'c1', 'c2', 'c3', 'c4', + 'c5', + 'c6', + 'c7', ]); }); @@ -158,8 +314,24 @@ describe('should collect control values and create SFD', () => { expect(formData).toHaveProperty(key); expect(value).toEqual(publicControlsFormData[key]); }); - expect(formData.columns).toEqual(['c1', 'c2', 'c3', 'c4']); - expect(formData.metrics).toEqual(['m1', 'm2', 'm3']); + expect(formData.columns).toEqual([ + 'c1', + 'c2', + 'c3', + 'c4', + 'c5', + 'c6', + 'c7', + ]); + expect(formData.metrics).toEqual([ + 'm1', + 'm2', + 'm3', + 'm4', + 'm5', + 'm6', + 'm7', + ]); }); test('should inherit standardizedFormData and memorizedFormData is LIFO', () => { @@ -204,114 +376,6 @@ describe('should collect control values and create SFD', () => { }); describe('should transform form_data between table and bigNumberTotal', () => { - const tableVizFormData = { - datasource: '30__table', - viz_type: 'table', - granularity_sqla: 'ds', - time_grain_sqla: 'P1D', - time_range: 'No filter', - query_mode: 'aggregate', - groupby: ['name'], - metrics: ['count'], - all_columns: [], - percent_metrics: [], - adhoc_filters: [], - order_by_cols: [], - row_limit: 10000, - server_page_length: 10, - order_desc: true, - table_timestamp_format: 'smart_date', - show_cell_bars: true, - color_pn: true, - url_params: { - form_data_key: - 'p3No_sqDW7k-kMTzlBPAPd9vwp1IXTf6stbyzjlrPPa0ninvdYUUiMC6F1iKit3Y', - dataset_id: '30', - }, - }; - const tableVizStore = { - form_data: tableVizFormData, - controls: { - datasource: { - value: '30__table', - }, - viz_type: { - value: 'table', - }, - slice_id: {}, - cache_timeout: {}, - url_params: { - value: { - form_data_key: - 'p3No_sqDW7k-kMTzlBPAPd9vwp1IXTf6stbyzjlrPPa0ninvdYUUiMC6F1iKit3Y', - dataset_id: '30', - }, - }, - granularity_sqla: { - value: 'ds', - }, - time_grain_sqla: { - value: 'P1D', - }, - time_range: { - value: 'No filter', - }, - query_mode: { - value: 'aggregate', - }, - groupby: { - value: ['name'], - }, - metrics: { - value: ['count'], - }, - all_columns: { - value: [], - }, - percent_metrics: { - value: [], - }, - adhoc_filters: { - value: [], - }, - timeseries_limit_metric: {}, - order_by_cols: { - value: [], - }, - server_pagination: {}, - row_limit: { - value: 10000, - }, - server_page_length: { - value: 10, - }, - include_time: {}, - order_desc: { - value: true, - }, - show_totals: {}, - emit_filter: {}, - table_timestamp_format: { - value: 'smart_date', - }, - page_length: {}, - include_search: {}, - show_cell_bars: { - value: true, - }, - align_pn: {}, - color_pn: { - value: true, - }, - column_config: {}, - conditional_formatting: {}, - }, - datasource: { - type: 'table', - columns: [], - }, - }; - beforeAll(() => { getChartControlPanelRegistry().registerValue( 'big_number_total', @@ -350,7 +414,7 @@ describe('should transform form_data between table and bigNumberTotal', () => { expect(bntFormData.viz_type).toBe('big_number_total'); expect(bntFormData.metric).toBe('count'); - // change control values + // change control values on bigNumber bntFormData.metric = 'sum(sales)'; bntFormData.time_range = '2021 : 2022'; bntControlsState.metric.value = 'sum(sales)'; @@ -368,8 +432,56 @@ describe('should transform form_data between table and bigNumberTotal', () => { [...Object.keys(tblControlsState), 'standardizedFormData'].sort(), ); expect(tblFormData.viz_type).toBe('table'); - expect(tblFormData.metrics).toEqual(['sum(sales)']); - expect(tblFormData.groupby).toEqual(['name']); + expect(tblFormData.metrics).toEqual([ + 'sum(sales)', + 'avg(sales)', + adhocMetricSimple, + adhocMetricSQL, + ]); + expect(tblFormData.groupby).toEqual(['name', 'gender', adhocColumn]); expect(tblFormData.time_range).toBe('2021 : 2022'); }); }); + +describe('initial SFD between different datasource', () => { + beforeAll(() => { + getChartControlPanelRegistry().registerValue( + 'big_number_total', + new BigNumberTotalChartPlugin().controlPanel, + ); + getChartControlPanelRegistry().registerValue( + 'table', + new TableChartPlugin().controlPanel, + ); + }); + + test('initial SFD between different datasource', () => { + const sfd = new StandardizedFormData(tableVizFormData); + // table -> big number + const { formData: bntFormData, controlsState: bntControlsState } = + sfd.transform('big_number_total', tableVizStore); + const sfd2 = new StandardizedFormData(bntFormData); + // big number -> table + const { formData: tblFormData } = sfd2.transform('table', { + ...tableVizStore, + form_data: bntFormData, + controls: bntControlsState, + }); + + expect( + tblFormData.standardizedFormData.memorizedFormData.map( + (mfd: [string, QueryFormData][]) => mfd[0], + ), + ).toEqual(['table', 'big_number_total']); + const newDatasourceFormData = { ...tblFormData, datasource: '20__table' }; + const newDatasourceSFD = new StandardizedFormData(newDatasourceFormData); + expect( + newDatasourceSFD + .serialize() + .memorizedFormData.map(([vizType]) => vizType), + ).toEqual(['table']); + expect(newDatasourceSFD.get('table')).not.toHaveProperty( + 'standardizedFormData', + ); + }); +}); diff --git a/superset-frontend/src/explore/controlUtils/standardizedFormData.ts b/superset-frontend/src/explore/controlUtils/standardizedFormData.ts index 99b0220da3342..082ff6c91daa2 100644 --- a/superset-frontend/src/explore/controlUtils/standardizedFormData.ts +++ b/superset-frontend/src/explore/controlUtils/standardizedFormData.ts @@ -16,38 +16,43 @@ * specific language governing permissions and limitations * under the License. */ -import { isEmpty, intersection } from 'lodash'; +import { omit } from 'lodash'; import { ensureIsArray, getChartControlPanelRegistry, + QueryFormColumn, QueryFormData, + QueryFormMetric, } from '@superset-ui/core'; import { ControlStateMapping, - StandardizedState, + getStandardizedControls, + isStandardizedFormData, + StandardizedControls, StandardizedFormDataInterface, } from '@superset-ui/chart-controls'; import { getControlsState } from 'src/explore/store'; import { getFormDataFromControls } from './getFormDataFromControls'; -export const sharedControls: Record<string, keyof StandardizedState> = { - // metrics - metric: 'metrics', // via sharedControls, scalar - metrics: 'metrics', // via sharedControls, array - metric_2: 'metrics', // via sharedControls, scalar - // columns - groupby: 'columns', // via sharedControls, array - columns: 'columns', // via sharedControls, array - groupbyColumns: 'columns', // via pivot table v2, array - groupbyRows: 'columns', // via pivot table v2, array -}; -const sharedControlsMap: Record<keyof StandardizedState, string[]> = { - metrics: [], - columns: [], -}; -Object.entries(sharedControls).forEach(([key, value]) => - sharedControlsMap[value].push(key), -); +export const sharedMetricsKey = [ + 'metric', // via sharedControls, scalar + 'metrics', // via sharedControls, array + 'metric_2', // via sharedControls, scalar + 'size', // via sharedControls, scalar + 'x', // via sharedControls, scalar + 'y', // via sharedControls, scalar + 'secondary_metric', // via sharedControls, scalar +]; +export const sharedColumnsKey = [ + 'groupby', // via sharedControls, array + 'columns', // via sharedControls, array + 'groupbyColumns', // via pivot table v2, array + 'groupbyRows', // via pivot table v2, array + 'entity', // via sharedControls, scalar + 'series', // via sharedControls, scalar + 'series_columns', // via sharedControls, array +]; + export const publicControls = [ // time section 'granularity_sqla', // via sharedControls @@ -87,90 +92,78 @@ export class StandardizedFormData { * */ const formData = Object.freeze(sourceFormData); - // generates an ordered map, the key is viz_type and the value is form_data. the last item is current viz - const memorizedFormData: Map<string, QueryFormData> = Array.isArray( - formData?.standardizedFormData?.memorizedFormData, - ) - ? new Map(formData.standardizedFormData.memorizedFormData) - : new Map(); + // generates an ordered map, the key is viz_type and the value is form_data. the last item is current viz. + const mfd = formData?.standardizedFormData?.memorizedFormData; const vizType = formData.viz_type; - if (memorizedFormData.has(vizType)) { - memorizedFormData.delete(vizType); + let memorizedFormData = new Map<string, QueryFormData>(); + let controls: StandardizedControls; + if ( + Array.isArray(mfd) && + mfd.length > 0 && + formData.datasource === mfd.slice(-1)[0][1]?.datasource + ) { + memorizedFormData = new Map( + formData.standardizedFormData.memorizedFormData, + ); + if (memorizedFormData.has(vizType)) { + memorizedFormData.delete(vizType); + } + memorizedFormData.set(vizType, formData); + controls = StandardizedFormData.getStandardizedControls(formData); + } else { + // reset the `memorizedFormData` if a request between different datasource. + const restFormData = omit( + formData, + 'standardizedFormData', + ) as QueryFormData; + memorizedFormData.set(vizType, restFormData); + controls = StandardizedFormData.getStandardizedControls(restFormData); } - memorizedFormData.set(vizType, formData); - - // calculate sharedControls - const standardizedState = - StandardizedFormData.getStandardizedState(formData); this.sfd = { - standardizedState, + controls, memorizedFormData, }; } - static getStandardizedState(formData: QueryFormData): StandardizedState { - // 1. collect current sharedControls - let currState: StandardizedState = { + static getStandardizedControls( + formData: QueryFormData, + ): StandardizedControls { + // 1. initial StandardizedControls + const controls: StandardizedControls = { metrics: [], columns: [], }; + + // 2. collect current sharedControls Object.entries(formData).forEach(([key, value]) => { - if (key in sharedControls) { - currState[sharedControls[key]].push(...ensureIsArray(value)); + if (sharedMetricsKey.includes(key)) { + controls.metrics.push(...ensureIsArray<QueryFormMetric>(value)); } - }); - - // 2. get previous StandardizedState - let prevState: StandardizedState = { - metrics: [], - columns: [], - }; - if ( - formData?.standardizedFormData?.standardizedState && - Array.isArray(formData.standardizedFormData.standardizedState.metrics) && - Array.isArray(formData.standardizedFormData.standardizedState.columns) - ) { - prevState = formData.standardizedFormData.standardizedState; - } - // the initial prevState should equal to currentState - if (isEmpty(prevState.metrics) && isEmpty(prevState.columns)) { - prevState = currState; - } - - // 3. inherit SS from previous state if current viz hasn't columns-like controls or metrics-like controls - Object.keys(sharedControlsMap).forEach(key => { - if ( - isEmpty(intersection(Object.keys(formData), sharedControlsMap[key])) - ) { - currState[key] = prevState[key]; + if (sharedColumnsKey.includes(key)) { + controls.columns.push(...ensureIsArray<QueryFormColumn>(value)); } }); - // 4. update hook - const controlPanel = getChartControlPanelRegistry().get(formData.viz_type); - if (controlPanel?.updateStandardizedState) { - currState = controlPanel.updateStandardizedState(prevState, currState); + // 3. append inherit sharedControls + if (isStandardizedFormData(formData)) { + const { metrics, columns } = formData.standardizedFormData.controls; + controls.metrics.push(...metrics); + controls.columns.push(...columns); } - // 5. clear up - Object.entries(currState).forEach(([key, value]) => { - currState[key] = value.filter(Boolean); - }); - - return currState; + return controls; } private getLatestFormData(vizType: string): QueryFormData { if (this.has(vizType)) { return this.get(vizType); } - return this.memorizedFormData.slice(-1)[0][1]; } - private get standardizedState() { - return this.sfd.standardizedState; + private get standardizedControls() { + return this.sfd.controls; } private get memorizedFormData() { @@ -179,7 +172,7 @@ export class StandardizedFormData { serialize() { return { - standardizedState: this.standardizedState, + controls: this.standardizedControls, memorizedFormData: this.memorizedFormData, }; } @@ -205,8 +198,9 @@ export class StandardizedFormData { * 2. collect public control values * 3. generate initial targetControlsState * 4. attach `standardizedFormData` to the initial form_data - * 5. call denormalizeFormData to transform initial form_data if the plugin was defined + * 5. call formDataOverrides to transform initial form_data if the plugin was defined * 6. use final form_data to generate controlsState + * 7. to refresh validator message * */ const latestFormData = this.getLatestFormData(targetVizType); const publicFormData = {}; @@ -225,18 +219,33 @@ export class StandardizedFormData { standardizedFormData: this.serialize(), }; + let rv = { + formData: targetFormData, + controlsState: targetControlsState, + }; + const controlPanel = getChartControlPanelRegistry().get(targetVizType); - if (controlPanel?.denormalizeFormData) { - const transformed = controlPanel.denormalizeFormData(targetFormData); - return { + if (controlPanel?.formDataOverrides) { + getStandardizedControls().setStandardizedControls(targetFormData); + const transformed = { + ...controlPanel.formDataOverrides(targetFormData), + standardizedFormData: { + controls: { ...getStandardizedControls().controls }, + memorizedFormData: this.memorizedFormData, + }, + }; + getStandardizedControls().clear(); + rv = { formData: transformed, controlsState: getControlsState(exploreState, transformed), }; } - return { - formData: targetFormData, - controlsState: targetControlsState, - }; + // refresh validator message + rv.controlsState = getControlsState( + { ...exploreState, controls: rv.controlsState }, + rv.formData, + ); + return rv; } } diff --git a/superset-frontend/src/explore/controls.jsx b/superset-frontend/src/explore/controls.jsx index e3fb05614de38..d4e371c93958d 100644 --- a/superset-frontend/src/explore/controls.jsx +++ b/superset-frontend/src/explore/controls.jsx @@ -75,8 +75,8 @@ export const PRIMARY_COLOR = { r: 0, g: 122, b: 135, a: 1 }; // input choices & options export const D3_FORMAT_OPTIONS = [ - ['SMART_NUMBER', 'Adaptive formatting'], - ['~g', 'Original value'], + ['SMART_NUMBER', t('Adaptive formatting')], + ['~g', t('Original value')], [',d', ',d (12345.432 => 12,345)'], ['.1s', '.1s (12345.432 => 10k)'], ['.3s', '.3s (12345.432 => 12.3k)'], @@ -86,8 +86,8 @@ export const D3_FORMAT_OPTIONS = [ [',.3f', ',.3f (12345.432 => 12,345.432)'], ['+,', '+, (12345.432 => +12,345.432)'], ['$,.2f', '$,.2f (12345.432 => $12,345.43)'], - ['DURATION', 'Duration in ms (66000 => 1m 6s)'], - ['DURATION_SUB', 'Duration in ms (100.40008 => 100ms 400µs 80ns)'], + ['DURATION', t('Duration in ms (66000 => 1m 6s)')], + ['DURATION_SUB', t('Duration in ms (100.40008 => 100ms 400µs 80ns)')], ]; const ROW_LIMIT_OPTIONS = [10, 50, 100, 250, 500, 1000, 5000, 10000, 50000]; @@ -98,7 +98,7 @@ export const D3_FORMAT_DOCS = 'D3 format syntax: https://github.com/d3/d3-format'; export const D3_TIME_FORMAT_OPTIONS = [ - ['smart_date', 'Adaptive formatting'], + ['smart_date', t('Adaptive formatting')], ['%d/%m/%Y', '%d/%m/%Y | 14/01/2019'], ['%m/%d/%Y', '%m/%d/%Y | 01/14/2019'], ['%Y-%m-%d', '%Y-%m-%d | 2019-01-14'], @@ -200,7 +200,6 @@ export const controls = { viz_type: { type: 'VizTypeControl', - label: t('Visualization type'), default: 'table', description: t('The type of visualization to display'), }, @@ -249,47 +248,32 @@ export const controls = { description: t('One or many controls to pivot as columns'), }, - druid_time_origin: { - type: 'SelectControl', - freeForm: true, - label: TIME_FILTER_LABELS.druid_time_origin, - choices: [ - ['', 'default'], - ['now', 'now'], - ], - default: null, - description: t( - 'Defines the origin where time buckets start, ' + - 'accepts natural dates as in `now`, `sunday` or `1970-01-01`', - ), - }, - granularity: { type: 'SelectControl', freeForm: true, label: TIME_FILTER_LABELS.granularity, default: 'P1D', choices: [ - [null, 'all'], - ['PT5S', '5 seconds'], - ['PT30S', '30 seconds'], - ['PT1M', '1 minute'], - ['PT5M', '5 minutes'], - ['PT30M', '30 minutes'], - ['PT1H', '1 hour'], - ['PT6H', '6 hour'], - ['P1D', '1 day'], - ['P7D', '7 days'], - ['P1W', 'week'], - ['week_starting_sunday', 'week starting Sunday'], - ['week_ending_saturday', 'week ending Saturday'], - ['P1M', 'month'], - ['P3M', 'quarter'], - ['P1Y', 'year'], + [null, t('all')], + ['PT5S', t('5 seconds')], + ['PT30S', t('30 seconds')], + ['PT1M', t('1 minute')], + ['PT5M', t('5 minutes')], + ['PT30M', t('30 minutes')], + ['PT1H', t('1 hour')], + ['PT6H', t('6 hour')], + ['P1D', t('1 day')], + ['P7D', t('7 days')], + ['P1W', t('week')], + ['week_starting_sunday', t('week starting Sunday')], + ['week_ending_saturday', t('week ending Saturday')], + ['P1M', t('month')], + ['P3M', t('quarter')], + ['P1Y', t('year')], ], description: t( 'The time granularity for the visualization. Note that you ' + - 'can type and use simple natural language as in `10 seconds`, ' + + 'can type and use simple natural language as in `10 seconds`,' + '`1 day` or `56 weeks`', ), }, diff --git a/superset-frontend/src/explore/exploreUtils/exploreUtils.test.jsx b/superset-frontend/src/explore/exploreUtils/exploreUtils.test.jsx index b385099699cb4..52c20dcd84bd2 100644 --- a/superset-frontend/src/explore/exploreUtils/exploreUtils.test.jsx +++ b/superset-frontend/src/explore/exploreUtils/exploreUtils.test.jsx @@ -51,7 +51,7 @@ describe('exploreUtils', () => { force: false, curUrl: 'http://superset.com', }); - compareURI(URI(url), URI('/superset/explore/')); + compareURI(URI(url), URI('/explore/')); }); it('generates proper json url', () => { const url = getExploreUrl({ @@ -95,7 +95,7 @@ describe('exploreUtils', () => { }); compareURI( URI(url), - URI('/superset/explore/').search({ + URI('/explore/').search({ standalone: DashboardStandaloneMode.HIDE_NAV, }), ); diff --git a/superset-frontend/src/explore/exploreUtils/getExploreUrl.test.ts b/superset-frontend/src/explore/exploreUtils/getExploreUrl.test.ts index 7457b462b0314..c0f2721a49b98 100644 --- a/superset-frontend/src/explore/exploreUtils/getExploreUrl.test.ts +++ b/superset-frontend/src/explore/exploreUtils/getExploreUrl.test.ts @@ -33,7 +33,7 @@ const createParams = () => ({ test('Get ExploreUrl with default params', () => { const params = createParams(); - expect(getExploreUrl(params)).toBe('http://localhost/superset/explore/'); + expect(getExploreUrl(params)).toBe('http://localhost/explore/'); }); test('Get ExploreUrl with endpointType:full', () => { diff --git a/superset-frontend/src/explore/exploreUtils/getHostName.test.ts b/superset-frontend/src/explore/exploreUtils/getHostName.test.ts index 6b90cc0f53bbf..6711eca4a2fd0 100644 --- a/superset-frontend/src/explore/exploreUtils/getHostName.test.ts +++ b/superset-frontend/src/explore/exploreUtils/getHostName.test.ts @@ -30,7 +30,7 @@ jest.mock('src/utils/hostNamesConfig', () => ({ ], })); -test('Should get next diferent domain on a loop, never the first on the list', () => { +test('Should get next different domain on a loop, never the first on the list', () => { for (let loop = 3; loop > 0; loop -= 1) { expect(getHostName(true)).toBe('domain-b'); expect(getHostName(true)).toBe('domain-c'); diff --git a/superset-frontend/src/explore/exploreUtils/getParsedExploreURLParams.test.ts b/superset-frontend/src/explore/exploreUtils/getParsedExploreURLParams.test.ts new file mode 100644 index 0000000000000..f6f2344f62289 --- /dev/null +++ b/superset-frontend/src/explore/exploreUtils/getParsedExploreURLParams.test.ts @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { getParsedExploreURLParams } from './getParsedExploreURLParams'; + +const EXPLORE_BASE_URL = 'http://localhost:9000/explore/'; +const setupLocation = (newUrl: string) => { + delete (window as any).location; + // @ts-ignore + window.location = new URL(newUrl); +}; + +test('get form_data_key and slice_id from search params - url when moving from dashboard to explore', () => { + setupLocation( + `${EXPLORE_BASE_URL}?form_data_key=yrLXmyE9fmhQ11lM1KgaD1PoPSBpuLZIJfqdyIdw9GoBwhPFRZHeIgeFiNZljbpd&slice_id=56`, + ); + expect(getParsedExploreURLParams().toString()).toEqual( + 'form_data_key=yrLXmyE9fmhQ11lM1KgaD1PoPSBpuLZIJfqdyIdw9GoBwhPFRZHeIgeFiNZljbpd&slice_id=56', + ); +}); + +test('get slice_id from form_data search param - url on Chart List', () => { + setupLocation(`${EXPLORE_BASE_URL}?form_data=%7B%22slice_id%22%3A%2056%7D`); + expect(getParsedExploreURLParams().toString()).toEqual('slice_id=56'); +}); + +test('get datasource and viz type from form_data search param - url when creating new chart', () => { + setupLocation( + `${EXPLORE_BASE_URL}?form_data=%7B%22viz_type%22%3A%22big_number%22%2C%22datasource%22%3A%222__table%22%7D`, + ); + expect(getParsedExploreURLParams().toString()).toEqual( + 'viz_type=big_number&datasource_id=2&datasource_type=table', + ); +}); + +test('get permalink key from path params', () => { + setupLocation(`${EXPLORE_BASE_URL}p/kpOqweaMY9R/`); + expect(getParsedExploreURLParams().toString()).toEqual( + 'permalink_key=kpOqweaMY9R', + ); +}); + +test('get dataset id from path params', () => { + setupLocation(`${EXPLORE_BASE_URL}table/42/`); + expect(getParsedExploreURLParams().toString()).toEqual('datasource_id=42'); +}); diff --git a/superset-frontend/src/explore/exploreUtils/getParsedExploreURLParams.ts b/superset-frontend/src/explore/exploreUtils/getParsedExploreURLParams.ts new file mode 100644 index 0000000000000..b5a544031d7dc --- /dev/null +++ b/superset-frontend/src/explore/exploreUtils/getParsedExploreURLParams.ts @@ -0,0 +1,125 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export interface Location { + search: string; + pathname: string; +} + +// mapping { url_param: v1_explore_request_param } +const EXPLORE_URL_SEARCH_PARAMS = { + form_data: { + name: 'form_data', + parser: (formData: string) => { + const formDataObject = JSON.parse(formData); + if (formDataObject.datasource) { + const [datasource_id, datasource_type] = + formDataObject.datasource.split('__'); + formDataObject.datasource_id = datasource_id; + formDataObject.datasource_type = datasource_type; + delete formDataObject.datasource; + } + return formDataObject; + }, + }, + slice_id: { + name: 'slice_id', + }, + datasource_id: { + name: 'datasource_id', + }, + datasource_type: { + name: 'datasource_type', + }, + datasource: { + name: 'datasource', + parser: (datasource: string) => { + const [datasource_id, datasource_type] = datasource.split('__'); + return { datasource_id, datasource_type }; + }, + }, + form_data_key: { + name: 'form_data_key', + }, + permalink_key: { + name: 'permalink_key', + }, + viz_type: { + name: 'viz_type', + }, + dashboard_id: { + name: 'dashboard_id', + }, +}; + +const EXPLORE_URL_PATH_PARAMS = { + p: 'permalink_key', // permalink + table: 'datasource_id', +}; + +// search params can be placed in form_data object +// we need to "flatten" the search params to use them with /v1/explore endpoint +const getParsedExploreURLSearchParams = (search: string) => { + const urlSearchParams = new URLSearchParams(search); + return Array.from(urlSearchParams.keys()).reduce((acc, currentParam) => { + const paramValue = urlSearchParams.get(currentParam); + if (paramValue === null) { + return acc; + } + let parsedParamValue; + try { + parsedParamValue = + EXPLORE_URL_SEARCH_PARAMS[currentParam].parser?.(paramValue) ?? + paramValue; + } catch { + parsedParamValue = paramValue; + } + if (typeof parsedParamValue === 'object') { + return { ...acc, ...parsedParamValue }; + } + const key = EXPLORE_URL_SEARCH_PARAMS[currentParam]?.name || currentParam; + return { + ...acc, + [key]: parsedParamValue, + }; + }, {}); +}; + +// path params need to be transformed to search params to use them with /v1/explore endpoint +const getParsedExploreURLPathParams = (pathname: string) => + Object.keys(EXPLORE_URL_PATH_PARAMS).reduce((acc, currentParam) => { + const re = new RegExp(`/(${currentParam})/(\\w+)`); + const pathGroups = pathname.match(re); + if (pathGroups?.[2]) { + return { ...acc, [EXPLORE_URL_PATH_PARAMS[currentParam]]: pathGroups[2] }; + } + return acc; + }, {}); + +export const getParsedExploreURLParams = ( + location: Location = window.location, +) => + new URLSearchParams( + Object.entries({ + ...getParsedExploreURLSearchParams(location.search), + ...getParsedExploreURLPathParams(location.pathname), + }) + .map(entry => entry.join('=')) + .join('&'), + ); diff --git a/superset-frontend/src/explore/exploreUtils/getURIDirectory.test.ts b/superset-frontend/src/explore/exploreUtils/getURIDirectory.test.ts index c8d43f413f699..1d6ad40045ae7 100644 --- a/superset-frontend/src/explore/exploreUtils/getURIDirectory.test.ts +++ b/superset-frontend/src/explore/exploreUtils/getURIDirectory.test.ts @@ -25,6 +25,6 @@ test('Cases in which the "explore_json" will be returned', () => { }); test('Cases in which the "explore" will be returned', () => { - expect(getURIDirectory('any-string')).toBe('/superset/explore/'); - expect(getURIDirectory()).toBe('/superset/explore/'); + expect(getURIDirectory('any-string')).toBe('/explore/'); + expect(getURIDirectory()).toBe('/explore/'); }); diff --git a/superset-frontend/src/explore/exploreUtils/index.js b/superset-frontend/src/explore/exploreUtils/index.js index 94bcfc7750477..754e84c5305ab 100644 --- a/superset-frontend/src/explore/exploreUtils/index.js +++ b/superset-frontend/src/explore/exploreUtils/index.js @@ -30,17 +30,18 @@ import { import { omit } from 'lodash'; import { availableDomains } from 'src/utils/hostNamesConfig'; import { safeStringify } from 'src/utils/safeStringify'; +import { optionLabel } from 'src/utils/common'; import { URL_PARAMS } from 'src/constants'; import { MULTI_OPERATORS, OPERATOR_ENUM_TO_OPERATOR_TYPE, + UNSAVED_CHART_ID, } from 'src/explore/constants'; import { DashboardStandaloneMode } from 'src/dashboard/util/constants'; -import { optionLabel } from '../../utils/common'; export function getChartKey(explore) { - const { slice } = explore; - return slice ? slice.slice_id : 0; + const { slice, form_data } = explore; + return slice?.slice_id ?? form_data?.slice_id ?? UNSAVED_CHART_ID; } let requestCounter = 0; @@ -61,18 +62,16 @@ export function getHostName(allowDomainSharding = false) { return availableDomains[currentIndex]; } -export function getAnnotationJsonUrl(slice_id, form_data, isNative, force) { +export function getAnnotationJsonUrl(slice_id, force) { if (slice_id === null || slice_id === undefined) { return null; } + const uri = URI(window.location.search); - const endpoint = isNative ? 'annotation_json' : 'slice_json'; return uri - .pathname(`/superset/${endpoint}/${slice_id}`) + .pathname('/api/v1/chart/data') .search({ - form_data: safeStringify(form_data, (key, value) => - value === null ? undefined : value, - ), + form_data: safeStringify({ slice_id }), force, }) .toString(); @@ -87,7 +86,7 @@ export function getURIDirectory(endpointType = 'base') { ) { return '/superset/explore_json/'; } - return '/superset/explore/'; + return '/explore/'; } export function mountExploreUrl(endpointType, extraSearch = {}, force = false) { @@ -274,11 +273,12 @@ export const exportChart = ({ SupersetClient.postForm(url, { form_data: safeStringify(payload) }); }; -export const exploreChart = formData => { +export const exploreChart = (formData, requestParams) => { const url = getExploreUrl({ formData, endpointType: 'base', allowDomainSharding: false, + requestParams, }); SupersetClient.postForm(url, { form_data: safeStringify(formData) }); }; diff --git a/superset-frontend/src/explore/fixtures.tsx b/superset-frontend/src/explore/fixtures.tsx index 78579b82e49c3..351e6f26b126b 100644 --- a/superset-frontend/src/explore/fixtures.tsx +++ b/superset-frontend/src/explore/fixtures.tsx @@ -18,13 +18,14 @@ */ import React from 'react'; -import { t } from '@superset-ui/core'; +import { DatasourceType, t } from '@superset-ui/core'; import { ColumnMeta, ColumnOption, ControlConfig, ControlPanelSectionConfig, } from '@superset-ui/chart-controls'; +import { ExplorePageInitialData } from './types'; export const controlPanelSectionsChartOptions: (ControlPanelSectionConfig | null)[] = [ @@ -57,9 +58,9 @@ export const controlPanelSectionsChartOptions: (ControlPanelSectionConfig | null label: t('Stacked Style'), renderTrigger: true, choices: [ - ['stack', 'stack'], - ['stream', 'stream'], - ['expand', 'expand'], + ['stack', t('stack')], + ['stream', t('stream')], + ['expand', t('expand')], ], default: 'stack', description: '', @@ -108,3 +109,57 @@ export const controlPanelSectionsChartOptionsTable: ControlPanelSectionConfig[] ], }, ]; + +export const exploreInitialData: ExplorePageInitialData = { + form_data: { + datasource: '8__table', + metric: 'count', + slice_id: 371, + viz_type: 'table', + }, + slice: { + cache_timeout: null, + description: null, + slice_id: 371, + slice_name: 'Age distribution of respondents', + is_managed_externally: false, + form_data: { + datasource: '8__table', + metric: 'count', + slice_id: 371, + viz_type: 'table', + }, + }, + dataset: { + id: 8, + type: DatasourceType.Table, + columns: [{ column_name: 'a' }], + metrics: [{ metric_name: 'first' }, { metric_name: 'second' }], + column_format: {}, + verbose_map: {}, + main_dttm_col: '', + datasource_name: '8__table', + description: null, + }, +}; + +export const fallbackExploreInitialData: ExplorePageInitialData = { + form_data: { + datasource: '0__table', + viz_type: 'table', + }, + dataset: { + id: 0, + type: DatasourceType.Table, + columns: [], + metrics: [], + column_format: {}, + verbose_map: {}, + main_dttm_col: '', + owners: [], + datasource_name: 'missing_datasource', + name: 'missing_datasource', + description: null, + }, + slice: null, +}; diff --git a/superset-frontend/src/explore/index.jsx b/superset-frontend/src/explore/index.jsx deleted file mode 100644 index cc99666e02f5b..0000000000000 --- a/superset-frontend/src/explore/index.jsx +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { createStore, applyMiddleware, compose } from 'redux'; -import thunk from 'redux-thunk'; -import logger from '../middleware/loggerMiddleware'; -import { initFeatureFlags } from '../featureFlags'; -import { initEnhancer } from '../reduxUtils'; -import getInitialState from './reducers/getInitialState'; -import rootReducer from './reducers/index'; -import App from './App'; - -const exploreViewContainer = document.getElementById('app'); -const bootstrapData = JSON.parse( - exploreViewContainer.getAttribute('data-bootstrap'), -); -initFeatureFlags(bootstrapData.common.feature_flags); -const initState = getInitialState(bootstrapData); -const store = createStore( - rootReducer, - initState, - compose(applyMiddleware(thunk, logger), initEnhancer(false)), -); - -ReactDOM.render(<App store={store} />, document.getElementById('app')); diff --git a/superset-frontend/src/explore/main.less b/superset-frontend/src/explore/main.less deleted file mode 100644 index 015a8a1a3bed3..0000000000000 --- a/superset-frontend/src/explore/main.less +++ /dev/null @@ -1,137 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -@import '../assets/stylesheets/less/variables.less'; - -.scrollbar-container { - position: relative; - overflow: hidden; - width: 100%; - height: 100%; -} - -.scrollbar-content { - position: absolute; - top: 0px; - left: 0px; - right: 0px; - bottom: 0px; - overflow-y: auto; - margin-right: 0px; - margin-bottom: 40px; -} - -.edit-desc-icon { - padding: 0 0 0 0.5em; - font-size: @font-size-m; -} - -.checkbox { - float: left; - margin-top: 0px; - margin-right: 3px; -} - -.background-transparent { - background-color: transparent !important; -} - -.fa.expander { - width: 15px; -} - -.list-group { - margin-bottom: 10px; -} - -.color-popover.popover { - border: none; - background-color: transparent; -} - -.color-popover .popover-content { - padding: 0; - background-color: transparent; -} - -.column-option { - margin-left: 3px; -} - -.datasource-container { - overflow: auto; -} - -.adhoc-metric-edit-tabs > .nav-tabs { - margin-bottom: 6px; - - & > li > a { - padding: 4px 4px 4px 4px; - } -} - -#metrics-edit-popover { - max-width: none; - - .inline-editable { - line-height: 30px; // hand-tweaked to match the height of the input - } -} - -.adhoc-option { - cursor: pointer; -} - -.label-dropdown ul.dropdown-menu { - position: fixed; - top: auto; - left: auto; - margin: 20px 0 0; -} - -.label-btn:hover, -.label-btn-label:hover { - background-color: @gray-dark; -} - -.label-btn-label { - cursor: pointer; -} - -.adhoc-label-arrow { - font-size: @font-size-s; - margin-left: 3px; - position: static; -} - -.time-filter-tabs > .nav-tabs { - margin-bottom: 8px; - - & > li > a { - padding: 4px; - } -} - -div.section-header { - font-size: @font-size-s; - font-weight: @font-weight-bold; - color: @gray-light5; - margin-bottom: 0; - margin-top: 0; - padding-bottom: 16px; -} diff --git a/superset-frontend/src/dashboard/util/findParentId.js b/superset-frontend/src/explore/reducers/datasourcesReducer.ts similarity index 51% rename from superset-frontend/src/dashboard/util/findParentId.js rename to superset-frontend/src/explore/reducers/datasourcesReducer.ts index 4d24bb761d857..50393dbd24507 100644 --- a/superset-frontend/src/dashboard/util/findParentId.js +++ b/superset-frontend/src/explore/reducers/datasourcesReducer.ts @@ -16,34 +16,27 @@ * specific language governing permissions and limitations * under the License. */ -function findParentId({ childId, layout = {} }) { - let parentId = null; +import { Dataset } from '@superset-ui/chart-controls'; +import { getDatasourceUid } from 'src/utils/getDatasourceUid'; +import { + AnyDatasourcesAction, + SET_DATASOURCE, +} from '../actions/datasourcesActions'; +import { HYDRATE_EXPLORE, HydrateExplore } from '../actions/hydrateExplore'; - const ids = Object.keys(layout); - for (let i = 0; i <= ids.length - 1; i += 1) { - const id = ids[i]; - const component = layout[id] || {}; - if ( - id !== childId && - component.children && - component.children.includes(childId) - ) { - parentId = id; - break; - } +export default function datasourcesReducer( + // TODO: change type to include other datasource types + datasources: { [key: string]: Dataset }, + action: AnyDatasourcesAction | HydrateExplore, +) { + if (action.type === SET_DATASOURCE) { + return { + ...datasources, + [getDatasourceUid(action.datasource)]: action.datasource, + }; } - - return parentId; -} - -const cache = {}; -export default function findParentIdWithCache({ childId, layout = {} }) { - if (cache[childId]) { - const lastParent = layout[cache[childId]] || {}; - if (lastParent.children && lastParent.children.includes(childId)) { - return lastParent.id; - } + if (action.type === HYDRATE_EXPLORE) { + return { ...(action as HydrateExplore).data.datasources }; } - cache[childId] = findParentId({ childId, layout }); - return cache[childId]; + return datasources || {}; } diff --git a/superset-frontend/src/explore/reducers/exploreReducer.js b/superset-frontend/src/explore/reducers/exploreReducer.js index 87c3aa9b0a6ee..ac451ade3da16 100644 --- a/superset-frontend/src/explore/reducers/exploreReducer.js +++ b/superset-frontend/src/explore/reducers/exploreReducer.js @@ -19,7 +19,6 @@ /* eslint camelcase: 0 */ import { ensureIsArray } from '@superset-ui/core'; import { DYNAMIC_PLUGIN_CONTROLS_READY } from 'src/components/Chart/chartAction'; -import { DEFAULT_TIME_RANGE } from 'src/explore/constants'; import { getControlsState } from 'src/explore/store'; import { getControlConfig, @@ -28,6 +27,7 @@ import { StandardizedFormData, } from 'src/explore/controlUtils'; import * as actions from 'src/explore/actions/exploreActions'; +import { HYDRATE_EXPLORE } from '../actions/hydrateExplore'; export default function exploreReducer(state = {}, action) { const actionHandlers = { @@ -49,65 +49,46 @@ export default function exploreReducer(state = {}, action) { isDatasourceMetaLoading: true, }; }, - [actions.SET_DATASOURCE]() { + [actions.UPDATE_FORM_DATA_BY_DATASOURCE]() { const newFormData = { ...state.form_data }; - if (action.datasource.type !== state.datasource.type) { - if (action.datasource.type === 'table') { - newFormData.granularity_sqla = action.datasource.granularity_sqla; - newFormData.time_grain_sqla = action.datasource.time_grain_sqla; - delete newFormData.druid_time_origin; - delete newFormData.granularity; - } else { - newFormData.druid_time_origin = action.datasource.druid_time_origin; - newFormData.granularity = action.datasource.granularity; - delete newFormData.granularity_sqla; - delete newFormData.time_grain_sqla; - } - } - + const { prevDatasource, newDatasource } = action; const controls = { ...state.controls }; const controlsTransferred = []; + if ( - action.datasource.id !== state.datasource.id || - action.datasource.type !== state.datasource.type + prevDatasource.id !== newDatasource.id || + prevDatasource.type !== newDatasource.type ) { - // reset time range filter to default - newFormData.time_range = DEFAULT_TIME_RANGE; - - // reset control values for column/metric related controls - Object.entries(controls).forEach(([controlName, controlState]) => { + newFormData.datasource = newDatasource.uid; + } + // reset control values for column/metric related controls + Object.entries(controls).forEach(([controlName, controlState]) => { + if ( + // for direct column select controls + controlState.valueKey === 'column_name' || + // for all other controls + 'savedMetrics' in controlState || + 'columns' in controlState || + ('options' in controlState && !Array.isArray(controlState.options)) + ) { + newFormData[controlName] = getControlValuesCompatibleWithDatasource( + newDatasource, + controlState, + controlState.value, + ); if ( - // for direct column select controls - controlState.valueKey === 'column_name' || - // for all other controls - 'savedMetrics' in controlState || - 'columns' in controlState || - ('options' in controlState && !Array.isArray(controlState.options)) + ensureIsArray(newFormData[controlName]).length > 0 && + newFormData[controlName] !== controls[controlName].default ) { - controls[controlName] = { - ...controlState, - }; - newFormData[controlName] = getControlValuesCompatibleWithDatasource( - action.datasource, - controlState, - controlState.value, - ); - if ( - ensureIsArray(newFormData[controlName]).length > 0 && - newFormData[controlName] !== controls[controlName].default - ) { - controlsTransferred.push(controlName); - } + controlsTransferred.push(controlName); } - }); - } + } + }); const newState = { ...state, controls, - datasource: action.datasource, - datasource_id: action.datasource.id, - datasource_type: action.datasource.type, + datasource: action.newDatasource, }; return { ...newState, @@ -122,12 +103,6 @@ export default function exploreReducer(state = {}, action) { isDatasourcesLoading: true, }; }, - [actions.SET_DATASOURCES]() { - return { - ...state, - datasources: action.datasources, - }; - }, [actions.SET_FIELD_VALUE]() { const { controlName, value, validationErrors } = action; let new_form_data = { ...state.form_data, [controlName]: value }; @@ -235,12 +210,24 @@ export default function exploreReducer(state = {}, action) { controls: getControlsState(state, action.formData), }; }, + [actions.SET_FORM_DATA]() { + return { + ...state, + form_data: action.formData, + }; + }, [actions.UPDATE_CHART_TITLE]() { return { ...state, sliceName: action.sliceName, }; }, + [actions.SET_SAVE_ACTION]() { + return { + ...state, + saveAction: action.saveAction, + }; + }, [actions.CREATE_NEW_SLICE]() { return { ...state, @@ -257,9 +244,17 @@ export default function exploreReducer(state = {}, action) { slice: { ...state.slice, ...action.slice, - owners: action.slice.owners ?? null, + owners: action.slice.owners + ? action.slice.owners.map(owner => owner.value) + : null, }, sliceName: action.slice.slice_name ?? state.sliceName, + metadata: { + ...state.metadata, + owners: action.slice.owners + ? action.slice.owners.map(owner => owner.label) + : null, + }, }; }, [actions.SET_FORCE_QUERY]() { @@ -268,8 +263,12 @@ export default function exploreReducer(state = {}, action) { force: action.force, }; }, + [HYDRATE_EXPLORE]() { + return { + ...action.data.explore, + }; + }, }; - if (action.type in actionHandlers) { return actionHandlers[action.type](); } diff --git a/superset-frontend/src/explore/reducers/getInitialState.ts b/superset-frontend/src/explore/reducers/getInitialState.ts deleted file mode 100644 index 4d598fb722de8..0000000000000 --- a/superset-frontend/src/explore/reducers/getInitialState.ts +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import shortid from 'shortid'; -import { DatasourceType, JsonObject, QueryFormData } from '@superset-ui/core'; -import { ControlStateMapping, Dataset } from '@superset-ui/chart-controls'; -import { - CommonBootstrapData, - UserWithPermissionsAndRoles, -} from 'src/types/bootstrapTypes'; -import getToastsFromPyFlashMessages from 'src/components/MessageToasts/getToastsFromPyFlashMessages'; - -import { ChartState, Slice } from 'src/explore/types'; -import { getChartKey } from 'src/explore/exploreUtils'; -import { getControlsState } from 'src/explore/store'; -import { - getFormDataFromControls, - applyMapStateToPropsToControl, -} from 'src/explore/controlUtils'; - -export interface ExplorePageBootstrapData extends JsonObject { - can_add: boolean; - can_download: boolean; - can_overwrite: boolean; - common: CommonBootstrapData; - datasource: Dataset; - datasource_id: number; - datasource_type: DatasourceType; - forced_height: string | null; - form_data: QueryFormData; - slice: Slice | null; - standalone: boolean; - force: boolean; - user: UserWithPermissionsAndRoles; -} - -export default function getInitialState( - bootstrapData: ExplorePageBootstrapData, -) { - const { form_data: initialFormData } = bootstrapData; - const { slice } = bootstrapData; - const sliceName = slice ? slice.slice_name : null; - - const exploreState = { - // note this will add `form_data` to state, - // which will be manipulatable by future reducers. - ...bootstrapData, - sliceName, - common: { - flash_messages: bootstrapData.common.flash_messages, - conf: bootstrapData.common.conf, - }, - isDatasourceMetaLoading: false, - isStarred: false, - // Initial control state will skip `control.mapStateToProps` - // because `bootstrapData.controls` is undefined. - controls: getControlsState( - bootstrapData, - initialFormData, - ) as ControlStateMapping, - controlsTransferred: [], - }; - - // apply initial mapStateToProps for all controls, must execute AFTER - // bootstrapState has initialized `controls`. Order of execution is not - // guaranteed, so controls shouldn't rely on the each other's mapped state. - Object.entries(exploreState.controls).forEach(([key, controlState]) => { - exploreState.controls[key] = applyMapStateToPropsToControl( - controlState, - exploreState, - ); - }); - - const sliceFormData = slice - ? getFormDataFromControls(getControlsState(bootstrapData, slice.form_data)) - : null; - - const chartKey: number = getChartKey(bootstrapData); - const chart: ChartState = { - id: chartKey, - chartAlert: null, - chartStatus: null, - chartStackTrace: null, - chartUpdateEndTime: null, - chartUpdateStartTime: 0, - latestQueryFormData: getFormDataFromControls(exploreState.controls), - sliceFormData, - queryController: null, - queriesResponse: null, - triggerQuery: false, - lastRendered: 0, - }; - - return { - charts: { - [chartKey]: chart, - }, - saveModal: { - dashboards: [], - saveModalAlert: null, - }, - explore: exploreState, - impressionId: shortid.generate(), - messageToasts: getToastsFromPyFlashMessages( - (bootstrapData.common || {}).flash_messages || [], - ), - }; -} - -export type ExplorePageState = ReturnType<typeof getInitialState>; diff --git a/superset-frontend/src/explore/reducers/saveModalReducer.js b/superset-frontend/src/explore/reducers/saveModalReducer.js index eee4197991189..85983e1ef1ca4 100644 --- a/superset-frontend/src/explore/reducers/saveModalReducer.js +++ b/superset-frontend/src/explore/reducers/saveModalReducer.js @@ -18,9 +18,13 @@ */ /* eslint camelcase: 0 */ import * as actions from '../actions/saveModalActions'; +import { HYDRATE_EXPLORE } from '../actions/hydrateExplore'; export default function saveModalReducer(state = {}, action) { const actionHandlers = { + [actions.SET_SAVE_CHART_MODAL_VISIBILITY]() { + return { ...state, isVisible: action.isVisible }; + }, [actions.FETCH_DASHBOARDS_SUCCEEDED]() { return { ...state, dashboards: action.choices }; }, @@ -39,6 +43,9 @@ export default function saveModalReducer(state = {}, action) { [actions.REMOVE_SAVE_MODAL_ALERT]() { return { ...state, saveModalAlert: null }; }, + [HYDRATE_EXPLORE]() { + return { ...action.data.saveModal }; + }, }; if (action.type in actionHandlers) { diff --git a/superset-frontend/src/explore/store.js b/superset-frontend/src/explore/store.js index 80ad75e3e5bdf..239884bcdedbb 100644 --- a/superset-frontend/src/explore/store.js +++ b/superset-frontend/src/explore/store.js @@ -22,7 +22,7 @@ import { getAllControlsState, getFormDataFromControls } from './controlUtils'; import { controls } from './controls'; function handleDeprecatedControls(formData) { - // Reacffectation / handling of deprecated controls + // Reaffectation / handling of deprecated controls /* eslint-disable no-param-reassign */ // y_axis_zero was a boolean forcing 0 to be part of the Y Axis @@ -42,10 +42,9 @@ export function getControlsState(state, inputFormData) { // Getting a list of active control names for the current viz const formData = { ...inputFormData }; const vizType = - formData.viz_type || state.common.conf.DEFAULT_VIZ_TYPE || 'table'; + formData.viz_type || state.common?.conf.DEFAULT_VIZ_TYPE || 'table'; handleDeprecatedControls(formData); - const controlsState = getAllControlsState( vizType, state.datasource.type, diff --git a/superset-frontend/src/explore/types.ts b/superset-frontend/src/explore/types.ts index fbbb90ee33c7d..85240c919d3b9 100644 --- a/superset-frontend/src/explore/types.ts +++ b/superset-frontend/src/explore/types.ts @@ -25,15 +25,14 @@ import { } from '@superset-ui/core'; import { ColumnMeta, - Dataset, ControlStateMapping, + Dataset, } from '@superset-ui/chart-controls'; import { DatabaseObject } from 'src/views/CRUD/types'; import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; -import { toastState } from 'src/SqlLab/types'; import { Slice } from 'src/types/Chart'; -export { Slice, Chart } from 'src/types/Chart'; +export type SaveActionType = 'overwrite' | 'saveas'; export type ChartStatus = | 'loading' @@ -71,36 +70,18 @@ export type Datasource = Dataset & { is_sqllab_view?: boolean; }; -export type ExploreRootState = { - explore: { - can_add: boolean; - can_download: boolean; - common: object; - controls: object; - controlsTransferred: object; - datasource: object; - datasource_id: number; - datasource_type: string; - force: boolean; - forced_height: object; - form_data: object; - isDatasourceMetaLoading: boolean; - isStarred: boolean; - slice: object; - sliceName: string; - standalone: boolean; - timeFormattedColumns: object; - user: UserWithPermissionsAndRoles; - }; - localStorageUsageInKilobytes: number; - messageToasts: toastState[]; - common: {}; -}; - export interface ExplorePageInitialData { dataset: Dataset; form_data: QueryFormData; slice: Slice | null; + metadata?: { + created_on_humanized: string; + changed_on_humanized: string; + owners: string[]; + created_by?: string; + changed_by?: string; + }; + saveAction?: SaveActionType | null; } export interface ExploreResponsePayload { @@ -131,6 +112,7 @@ export interface ExplorePageState { controlsTransferred: string[]; standalone: boolean; force: boolean; + common: JsonObject; }; sliceEntities?: JsonObject; // propagated from Dashboard view } diff --git a/superset-frontend/src/featureFlags.ts b/superset-frontend/src/featureFlags.ts index 4d457fd527f9b..e71ec8207410b 100644 --- a/superset-frontend/src/featureFlags.ts +++ b/superset-frontend/src/featureFlags.ts @@ -21,12 +21,20 @@ import { FeatureFlagMap, FeatureFlag } from '@superset-ui/core'; export { FeatureFlag } from '@superset-ui/core'; export type { FeatureFlagMap } from '@superset-ui/core'; -export function initFeatureFlags(featureFlags: FeatureFlagMap) { +export function initFeatureFlags(featureFlags?: FeatureFlagMap) { if (!window.featureFlags) { window.featureFlags = featureFlags || {}; } } export function isFeatureEnabled(feature: FeatureFlag) { - return window && window.featureFlags && !!window.featureFlags[feature]; + try { + return !!window.featureFlags[feature]; + } catch (error) { + // eslint-disable-next-line no-console + console.error(`Failed to query feature flag ${feature} (see error below)`); + // eslint-disable-next-line no-console + console.error(error); + return false; + } } diff --git a/superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx b/superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx index 091232a5ec3e6..dfc314024ec9f 100644 --- a/superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx @@ -36,6 +36,8 @@ export default function PluginFilterGroupBy(props: PluginFilterGroupByProps) { height, width, setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, @@ -116,6 +118,8 @@ export default function PluginFilterGroupBy(props: PluginFilterGroupByProps) { onChange={handleChange} onBlur={unsetFocusedFilter} onFocus={setFocusedFilter} + onMouseEnter={setHoveredFilter} + onMouseLeave={unsetHoveredFilter} ref={inputRef} options={options} onDropdownVisibleChange={setFilterActive} diff --git a/superset-frontend/src/filters/components/GroupBy/controlPanel.ts b/superset-frontend/src/filters/components/GroupBy/controlPanel.ts index fbc61bf6e4a36..5b26f9cdcfaab 100644 --- a/superset-frontend/src/filters/components/GroupBy/controlPanel.ts +++ b/superset-frontend/src/filters/components/GroupBy/controlPanel.ts @@ -39,7 +39,7 @@ const config: ControlPanelConfig = { name: 'groupby', config: { ...sharedControls.groupby, - label: 'Columns to show', + label: t('Columns to show'), multiple: true, required: false, }, diff --git a/superset-frontend/src/filters/components/GroupBy/transformProps.ts b/superset-frontend/src/filters/components/GroupBy/transformProps.ts index 9ca0ec047bfa8..1f502602734eb 100644 --- a/superset-frontend/src/filters/components/GroupBy/transformProps.ts +++ b/superset-frontend/src/filters/components/GroupBy/transformProps.ts @@ -33,6 +33,8 @@ export default function transformProps(chartProps: ChartProps) { } = chartProps; const { setDataMask = noOp, + setHoveredFilter = noOp, + unsetHoveredFilter = noOp, setFocusedFilter = noOp, unsetFocusedFilter = noOp, setFilterActive = noOp, @@ -48,6 +50,8 @@ export default function transformProps(chartProps: ChartProps) { data, formData: { ...DEFAULT_FORM_DATA, ...formData }, setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, diff --git a/superset-frontend/src/filters/components/Range/RangeFilterPlugin.test.tsx b/superset-frontend/src/filters/components/Range/RangeFilterPlugin.test.tsx index 7dac323d6b137..0a2aac41ba813 100644 --- a/superset-frontend/src/filters/components/Range/RangeFilterPlugin.test.tsx +++ b/superset-frontend/src/filters/components/Range/RangeFilterPlugin.test.tsx @@ -18,7 +18,7 @@ */ import { AppSection, GenericDataType } from '@superset-ui/core'; import React from 'react'; -import { render } from 'spec/helpers/testing-library'; +import { render, screen } from 'spec/helpers/testing-library'; import RangeFilterPlugin from './RangeFilterPlugin'; import { SingleValueType } from './SingleValueType'; import transformProps from './transformProps'; @@ -121,41 +121,49 @@ describe('RangeFilterPlugin', () => { }); it('should call setDataMask with correct greater than filter', () => { - getWrapper({ enableSingleValue: SingleValueType.Minimum }); + getWrapper({ + enableSingleValue: SingleValueType.Minimum, + defaultValue: [20, 60], + }); expect(setDataMask).toHaveBeenCalledWith({ extraFormData: { filters: [ { col: 'SP_POP_TOTL', op: '>=', - val: 70, + val: 20, }, ], }, filterState: { - label: 'x ≥ 70', - value: [70, 100], + label: 'x ≥ 20', + value: [20, 100], }, }); + expect(screen.getByRole('slider')).toHaveAttribute('aria-valuenow', '20'); }); it('should call setDataMask with correct less than filter', () => { - getWrapper({ enableSingleValue: SingleValueType.Maximum }); + getWrapper({ + enableSingleValue: SingleValueType.Maximum, + defaultValue: [20, 60], + }); expect(setDataMask).toHaveBeenCalledWith({ extraFormData: { filters: [ { col: 'SP_POP_TOTL', op: '<=', - val: 70, + val: 60, }, ], }, filterState: { - label: 'x ≤ 70', - value: [10, 70], + label: 'x ≤ 60', + value: [10, 60], }, }); + expect(screen.getByRole('slider')).toHaveAttribute('aria-valuenow', '60'); }); it('should call setDataMask with correct exact filter', () => { diff --git a/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx b/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx index d2cc9a4171323..5c8533dd1e5ad 100644 --- a/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx @@ -25,8 +25,9 @@ import { t, } from '@superset-ui/core'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { AntdSlider } from 'src/components'; import { rgba } from 'emotion-rgba'; +import { AntdSlider } from 'src/components'; +import { FilterBarOrientation } from 'src/dashboard/types'; import { PluginFilterRangeProps } from './types'; import { StatusMessage, StyledFormItem, FilterPluginStyle } from '../common'; import { getRangeExtraFormData } from '../../utils'; @@ -65,8 +66,12 @@ const StyledMinSlider = styled(AntdSlider)<{ `} `; -const Wrapper = styled.div<{ validateStatus?: 'error' | 'warning' | 'info' }>` - ${({ theme, validateStatus }) => ` +const Wrapper = styled.div<{ + validateStatus?: 'error' | 'warning' | 'info'; + orientation?: FilterBarOrientation; + isOverflowing?: boolean; +}>` + ${({ theme, validateStatus, orientation, isOverflowing }) => ` border: 1px solid transparent; &:focus { border: 1px solid @@ -76,8 +81,18 @@ const Wrapper = styled.div<{ validateStatus?: 'error' | 'warning' | 'info' }>` ${rgba(theme.colors[validateStatus || 'primary']?.base, 0.2)}; } & .ant-slider { - margin-top: ${theme.gridUnit}px; - margin-bottom: ${theme.gridUnit * 5}px; + margin-top: ${ + orientation === FilterBarOrientation.HORIZONTAL ? 0 : theme.gridUnit + }px; + margin-bottom: ${ + orientation === FilterBarOrientation.HORIZONTAL ? 0 : theme.gridUnit * 5 + }px; + + ${ + orientation === FilterBarOrientation.HORIZONTAL && + !isOverflowing && + `line-height: 1.2;` + } & .ant-slider-track { background-color: ${ @@ -93,6 +108,10 @@ const Wrapper = styled.div<{ validateStatus?: 'error' | 'warning' | 'info' }>` ${rgba(theme.colors[validateStatus || 'primary']?.base, 0.2)}; } } + & .ant-slider-mark { + font-size: ${theme.typography.sizes.s}px; + } + &:hover { & .ant-slider-track { background-color: ${ @@ -152,9 +171,13 @@ export default function RangeFilterPlugin(props: PluginFilterRangeProps) { setDataMask, setFocusedFilter, unsetFocusedFilter, + setHoveredFilter, + unsetHoveredFilter, setFilterActive, filterState, inputRef, + filterBarOrientation, + isOverflowingFilterBar, } = props; const [row] = data; // @ts-ignore @@ -261,13 +284,13 @@ export default function RangeFilterPlugin(props: PluginFilterRangeProps) { useEffect(() => { if (enableSingleMaxValue) { - handleAfterChange([min, minMax[minIndex]]); + handleAfterChange([min, minMax[maxIndex]]); } }, [enableSingleMaxValue]); useEffect(() => { if (enableSingleMinValue) { - handleAfterChange([minMax[maxIndex], max]); + handleAfterChange([minMax[minIndex], max]); } }, [enableSingleMinValue]); @@ -287,10 +310,12 @@ export default function RangeFilterPlugin(props: PluginFilterRangeProps) { tabIndex={-1} ref={inputRef} validateStatus={filterState.validateStatus} + orientation={filterBarOrientation} + isOverflowing={isOverflowingFilterBar} onFocus={setFocusedFilter} onBlur={unsetFocusedFilter} - onMouseEnter={setFocusedFilter} - onMouseLeave={unsetFocusedFilter} + onMouseEnter={setHoveredFilter} + onMouseLeave={unsetHoveredFilter} onMouseDown={() => setFilterActive(true)} onMouseUp={() => setFilterActive(false)} > diff --git a/superset-frontend/src/filters/components/Range/buildQuery.ts b/superset-frontend/src/filters/components/Range/buildQuery.ts index f29228c7f714c..72e2fa549247c 100644 --- a/superset-frontend/src/filters/components/Range/buildQuery.ts +++ b/superset-frontend/src/filters/components/Range/buildQuery.ts @@ -20,6 +20,7 @@ import { buildQueryContext, GenericDataType, QueryFormData, + t, } from '@superset-ui/core'; /** @@ -44,7 +45,6 @@ export default function buildQuery(formData: QueryFormData) { { ...baseQueryObject, columns: [], - groupby: [], metrics: [ { aggregate: 'MIN', @@ -55,7 +55,7 @@ export default function buildQuery(formData: QueryFormData) { }, expressionType: 'SIMPLE', hasCustomLabel: true, - label: 'min', + label: t('min'), }, { aggregate: 'MAX', @@ -66,7 +66,7 @@ export default function buildQuery(formData: QueryFormData) { }, expressionType: 'SIMPLE', hasCustomLabel: true, - label: 'max', + label: t('max'), }, ], }, diff --git a/superset-frontend/src/filters/components/Range/controlPanel.ts b/superset-frontend/src/filters/components/Range/controlPanel.ts index 076d5a44aa0dc..2a38f5733cb1a 100644 --- a/superset-frontend/src/filters/components/Range/controlPanel.ts +++ b/superset-frontend/src/filters/components/Range/controlPanel.ts @@ -36,7 +36,7 @@ const config: ControlPanelConfig = { name: 'groupby', config: { ...sharedControls.groupby, - label: 'Column', + label: t('Column'), required: true, }, }, diff --git a/superset-frontend/src/filters/components/Range/transformProps.ts b/superset-frontend/src/filters/components/Range/transformProps.ts index f4c47cec267b1..cbca7a982a3c0 100644 --- a/superset-frontend/src/filters/components/Range/transformProps.ts +++ b/superset-frontend/src/filters/components/Range/transformProps.ts @@ -29,11 +29,14 @@ export default function transformProps(chartProps: ChartProps) { behaviors, filterState, inputRef, + displaySettings, } = chartProps; const { setDataMask = noOp, setFocusedFilter = noOp, unsetFocusedFilter = noOp, + setHoveredFilter = noOp, + unsetHoveredFilter = noOp, setFilterActive = noOp, } = hooks; const { data } = queriesData[0]; @@ -46,9 +49,13 @@ export default function transformProps(chartProps: ChartProps) { setDataMask, filterState, width, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, inputRef, + isOverflowingFilterBar: displaySettings?.isOverflowingFilterBar, + filterBarOrientation: displaySettings?.filterBarOrientation, }; } diff --git a/superset-frontend/src/filters/components/Range/types.ts b/superset-frontend/src/filters/components/Range/types.ts index 69ad4d53da80b..25a18bb3e86b0 100644 --- a/superset-frontend/src/filters/components/Range/types.ts +++ b/superset-frontend/src/filters/components/Range/types.ts @@ -24,6 +24,7 @@ import { } from '@superset-ui/core'; import { RefObject } from 'react'; import { PluginFilterHooks, PluginFilterStylesProps } from '../types'; +import { FilterBarOrientation } from '../../../dashboard/types'; interface PluginFilterSelectCustomizeProps { max?: number; @@ -40,4 +41,6 @@ export type PluginFilterRangeProps = PluginFilterStylesProps & { filterState: FilterState; behaviors: Behavior[]; inputRef: RefObject<any>; + filterBarOrientation?: FilterBarOrientation; + isOverflowingFilterBar?: boolean; } & PluginFilterHooks; diff --git a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx index 8c025c97119bd..f0aa4453b1b19 100644 --- a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx +++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx @@ -24,6 +24,8 @@ import { NULL_STRING } from 'src/utils/common'; import SelectFilterPlugin from './SelectFilterPlugin'; import transformProps from './transformProps'; +jest.useFakeTimers(); + const selectMultipleProps = { formData: { sortAscending: true, @@ -86,7 +88,7 @@ describe('SelectFilterPlugin', () => { jest.clearAllMocks(); }); - it('Add multiple values with first render', () => { + test('Add multiple values with first render', async () => { getWrapper(); expect(setDataMask).toHaveBeenCalledWith({ extraFormData: {}, @@ -114,6 +116,7 @@ describe('SelectFilterPlugin', () => { }); userEvent.click(screen.getByRole('combobox')); userEvent.click(screen.getByTitle('girl')); + expect(await screen.findByTitle(/girl/i)).toBeInTheDocument(); expect(setDataMask).toHaveBeenCalledWith({ __cache: { value: ['boy'], @@ -134,9 +137,14 @@ describe('SelectFilterPlugin', () => { }); }); - it('Remove multiple values when required', () => { + test('Remove multiple values when required', () => { getWrapper(); - userEvent.click(document.querySelector('[data-icon="close"]')!); + userEvent.click( + screen.getByRole('img', { + name: /close-circle/i, + hidden: true, + }), + ); expect(setDataMask).toHaveBeenCalledWith({ __cache: { value: ['boy'], @@ -157,9 +165,14 @@ describe('SelectFilterPlugin', () => { }); }); - it('Remove multiple values when not required', () => { + test('Remove multiple values when not required', () => { getWrapper({ enableEmptyFilter: false }); - userEvent.click(document.querySelector('[data-icon="close"]')!); + userEvent.click( + screen.getByRole('img', { + name: /close-circle/i, + hidden: true, + }), + ); expect(setDataMask).toHaveBeenCalledWith({ __cache: { value: ['boy'], @@ -172,9 +185,10 @@ describe('SelectFilterPlugin', () => { }); }); - it('Select single values with inverse', () => { + test('Select single values with inverse', async () => { getWrapper({ multiSelect: false, inverseSelection: true }); userEvent.click(screen.getByRole('combobox')); + expect(await screen.findByTitle('girl')).toBeInTheDocument(); userEvent.click(screen.getByTitle('girl')); expect(setDataMask).toHaveBeenCalledWith({ __cache: { @@ -196,9 +210,10 @@ describe('SelectFilterPlugin', () => { }); }); - it('Select single null (empty) value', () => { + test('Select single null (empty) value', async () => { getWrapper(); userEvent.click(screen.getByRole('combobox')); + expect(await screen.findByRole('combobox')).toBeInTheDocument(); userEvent.click(screen.getByTitle(NULL_STRING)); expect(setDataMask).toHaveBeenLastCalledWith({ __cache: { @@ -220,9 +235,10 @@ describe('SelectFilterPlugin', () => { }); }); - it('Add ownState with column types when search all options', () => { + test('Add ownState with column types when search all options', async () => { getWrapper({ searchAllOptions: true, multiSelect: false }); userEvent.click(screen.getByRole('combobox')); + expect(await screen.findByRole('combobox')).toBeInTheDocument(); userEvent.click(screen.getByTitle('girl')); expect(setDataMask).toHaveBeenCalledWith({ __cache: { diff --git a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx index 9803e4a7e6fac..fb8e20093c921 100644 --- a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx @@ -17,6 +17,7 @@ * under the License. */ /* eslint-disable no-param-reassign */ +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { AppSection, DataMask, @@ -31,14 +32,14 @@ import { tn, } from '@superset-ui/core'; import { LabeledValue as AntdLabeledValue } from 'antd/lib/select'; -import React, { useCallback, useEffect, useState, useMemo } from 'react'; -import { Select } from 'src/components'; import debounce from 'lodash/debounce'; -import { SLOW_DEBOUNCE } from 'src/constants'; import { useImmerReducer } from 'use-immer'; -import { propertyComparator } from 'src/components/Select/Select'; +import { Select } from 'src/components'; +import { SLOW_DEBOUNCE } from 'src/constants'; +import { propertyComparator } from 'src/components/Select/utils'; +import { FilterBarOrientation } from 'src/dashboard/types'; import { PluginFilterSelectProps, SelectValue } from './types'; -import { StyledFormItem, FilterPluginStyle, StatusMessage } from '../common'; +import { FilterPluginStyle, StatusMessage, StyledFormItem } from '../common'; import { getDataRecordFormatter, getSelectExtraFormData } from '../../utils'; type DataMaskAction = @@ -82,6 +83,8 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { isRefreshing, width, setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, @@ -89,6 +92,7 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { showOverflow, parentRef, inputRef, + filterBarOrientation, } = props; const { enableEmptyFilter, @@ -228,7 +232,7 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { : null; // firstItem[0] !== undefined for a case when groupby changed but new data still not fetched // TODO: still need repopulate default value in config modal when column changed - if (firstItem && firstItem[0] !== undefined) { + if (firstItem?.[0] !== undefined) { updateDataMask(firstItem); } } else if (isDisabled) { @@ -307,8 +311,9 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { disabled={isDisabled} getPopupContainer={ showOverflow - ? () => parentRef?.current - : (trigger: HTMLElement) => trigger?.parentNode + ? () => (parentRef?.current as HTMLElement) || document.body + : (trigger: HTMLElement) => + (trigger?.parentNode as HTMLElement) || document.body } showSearch={showSearch} mode={multiSelect ? 'multiple' : 'single'} @@ -316,13 +321,14 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { onSearch={searchWrapper} onSelect={clearSuggestionSearch} onBlur={handleBlur} - onMouseEnter={setFocusedFilter} - onMouseLeave={unsetFocusedFilter} + onFocus={setFocusedFilter} + onMouseEnter={setHoveredFilter} + onMouseLeave={unsetHoveredFilter} // @ts-ignore onChange={handleChange} ref={inputRef} loading={isRefreshing} - maxTagCount={5} + oneLine={filterBarOrientation === FilterBarOrientation.HORIZONTAL} invertSelection={inverseSelection} // @ts-ignore options={options} diff --git a/superset-frontend/src/filters/components/Select/buildQuery.test.ts b/superset-frontend/src/filters/components/Select/buildQuery.test.ts index 08b7037f9cef6..c89719dc836d7 100644 --- a/superset-frontend/src/filters/components/Select/buildQuery.test.ts +++ b/superset-frontend/src/filters/components/Select/buildQuery.test.ts @@ -41,7 +41,7 @@ describe('Select buildQuery', () => { const queryContext = buildQuery(formData); expect(queryContext.queries.length).toEqual(1); const [query] = queryContext.queries; - expect(query.groupby).toEqual(['my_col']); + expect(query.columns).toEqual(['my_col']); expect(query.filters).toEqual([]); expect(query.metrics).toEqual([]); expect(query.orderby).toEqual([]); @@ -55,7 +55,7 @@ describe('Select buildQuery', () => { }); expect(queryContext.queries.length).toEqual(1); const [query] = queryContext.queries; - expect(query.groupby).toEqual(['my_col']); + expect(query.columns).toEqual(['my_col']); expect(query.metrics).toEqual(['my_metric']); expect(query.orderby).toEqual([['my_metric', false]]); }); @@ -68,7 +68,7 @@ describe('Select buildQuery', () => { }); expect(queryContext.queries.length).toEqual(1); const [query] = queryContext.queries; - expect(query.groupby).toEqual(['my_col']); + expect(query.columns).toEqual(['my_col']); expect(query.metrics).toEqual(['my_metric']); expect(query.orderby).toEqual([['my_metric', true]]); }); @@ -80,7 +80,7 @@ describe('Select buildQuery', () => { }); expect(queryContext.queries.length).toEqual(1); const [query] = queryContext.queries; - expect(query.groupby).toEqual(['my_col']); + expect(query.columns).toEqual(['my_col']); expect(query.metrics).toEqual([]); expect(query.orderby).toEqual([['my_col', true]]); }); @@ -92,7 +92,7 @@ describe('Select buildQuery', () => { }); expect(queryContext.queries.length).toEqual(1); const [query] = queryContext.queries; - expect(query.groupby).toEqual(['my_col']); + expect(query.columns).toEqual(['my_col']); expect(query.metrics).toEqual([]); expect(query.orderby).toEqual([['my_col', false]]); }); diff --git a/superset-frontend/src/filters/components/Select/buildQuery.ts b/superset-frontend/src/filters/components/Select/buildQuery.ts index abcd84f9d238d..d9a5b3c229ab4 100644 --- a/superset-frontend/src/filters/components/Select/buildQuery.ts +++ b/superset-frontend/src/filters/components/Select/buildQuery.ts @@ -63,7 +63,7 @@ const buildQuery: BuildQuery<PluginFilterSelectQueryFormData> = ( const query: QueryObject[] = [ { ...baseQueryObject, - groupby: columns, + columns, metrics: sortMetric ? [sortMetric] : [], filters: filters.concat(extraFilters), orderby: diff --git a/superset-frontend/src/filters/components/Select/controlPanel.ts b/superset-frontend/src/filters/components/Select/controlPanel.ts index 6b1549d5359cc..12bc36a7ade49 100644 --- a/superset-frontend/src/filters/components/Select/controlPanel.ts +++ b/superset-frontend/src/filters/components/Select/controlPanel.ts @@ -46,7 +46,7 @@ const config: ControlPanelConfig = { name: 'groupby', config: { ...sharedControls.groupby, - label: 'Column', + label: t('Column'), required: true, }, }, diff --git a/superset-frontend/src/filters/components/Select/transformProps.ts b/superset-frontend/src/filters/components/Select/transformProps.ts index 59d9adc57e930..2ed3d74ff0924 100644 --- a/superset-frontend/src/filters/components/Select/transformProps.ts +++ b/superset-frontend/src/filters/components/Select/transformProps.ts @@ -29,6 +29,7 @@ export default function transformProps( hooks, queriesData, width, + displaySettings, behaviors, appSection, filterState, @@ -38,6 +39,8 @@ export default function transformProps( const newFormData = { ...DEFAULT_FORM_DATA, ...formData }; const { setDataMask = noOp, + setHoveredFilter = noOp, + unsetHoveredFilter = noOp, setFocusedFilter = noOp, unsetFocusedFilter = noOp, setFilterActive = noOp, @@ -60,9 +63,13 @@ export default function transformProps( formData: newFormData, isRefreshing, setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, inputRef, + filterBarOrientation: displaySettings?.filterBarOrientation, + isOverflowingFilterBar: displaySettings?.isOverflowingFilterBar, }; } diff --git a/superset-frontend/src/filters/components/Select/types.ts b/superset-frontend/src/filters/components/Select/types.ts index 0497b58e55581..e608f59640fc3 100644 --- a/superset-frontend/src/filters/components/Select/types.ts +++ b/superset-frontend/src/filters/components/Select/types.ts @@ -27,6 +27,7 @@ import { ChartDataResponseResult, } from '@superset-ui/core'; import { RefObject } from 'react'; +import { FilterBarOrientation } from 'src/dashboard/types'; import { PluginFilterHooks, PluginFilterStylesProps } from '../types'; export type SelectValue = (number | string | null)[] | null | undefined; @@ -61,6 +62,8 @@ export type PluginFilterSelectProps = PluginFilterStylesProps & { showOverflow: boolean; parentRef?: RefObject<any>; inputRef?: RefObject<any>; + filterBarOrientation?: FilterBarOrientation; + isOverflowingFilterBar?: boolean; } & PluginFilterHooks; export const DEFAULT_FORM_DATA: PluginFilterSelectCustomizeProps = { diff --git a/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx b/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx index 9a35cdb359429..d22ee55594005 100644 --- a/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx @@ -16,20 +16,41 @@ * specific language governing permissions and limitations * under the License. */ -import { styled } from '@superset-ui/core'; +import { styled, NO_TIME_RANGE } from '@superset-ui/core'; import React, { useCallback, useEffect } from 'react'; import DateFilterControl from 'src/explore/components/controls/DateFilterControl'; -import { NO_TIME_RANGE } from 'src/explore/constants'; import { PluginFilterTimeProps } from './types'; -import { ControlContainer, FilterPluginStyle } from '../common'; +import { FilterPluginStyle } from '../common'; const TimeFilterStyles = styled(FilterPluginStyle)` + display: flex; + align-items: center; overflow-x: auto; + + & .ant-tag { + margin-right: 0; + } +`; + +const ControlContainer = styled.div<{ + validateStatus?: 'error' | 'warning' | 'info'; +}>` + display: flex; + height: 100%; + max-width: 100%; + width: 100%; + & > div, + & > div:hover { + ${({ validateStatus, theme }) => + validateStatus && `border-color: ${theme.colors[validateStatus]?.base}`} + } `; export default function TimeFilterPlugin(props: PluginFilterTimeProps) { const { setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, @@ -37,6 +58,7 @@ export default function TimeFilterPlugin(props: PluginFilterTimeProps) { height, filterState, inputRef, + isOverflowingFilterBar = false, } = props; const handleTimeRangeChange = useCallback( @@ -61,24 +83,26 @@ export default function TimeFilterPlugin(props: PluginFilterTimeProps) { }, [filterState.value]); return props.formData?.inView ? ( - // @ts-ignore <TimeFilterStyles width={width} height={height}> <ControlContainer - tabIndex={-1} ref={inputRef} validateStatus={filterState.validateStatus} onFocus={setFocusedFilter} onBlur={unsetFocusedFilter} - onMouseEnter={setFocusedFilter} - onMouseLeave={unsetFocusedFilter} + onMouseEnter={setHoveredFilter} + onMouseLeave={unsetHoveredFilter} > <DateFilterControl value={filterState.value || NO_TIME_RANGE} name="time_range" onChange={handleTimeRangeChange} - type={filterState.validateStatus} onOpenPopover={() => setFilterActive(true)} - onClosePopover={() => setFilterActive(false)} + onClosePopover={() => { + setFilterActive(false); + unsetHoveredFilter(); + unsetFocusedFilter(); + }} + isOverflowingFilterBar={isOverflowingFilterBar} /> </ControlContainer> </TimeFilterStyles> diff --git a/superset-frontend/src/filters/components/Time/controlPanel.ts b/superset-frontend/src/filters/components/Time/controlPanel.ts index b54909f70b96b..2dbded3651603 100644 --- a/superset-frontend/src/filters/components/Time/controlPanel.ts +++ b/superset-frontend/src/filters/components/Time/controlPanel.ts @@ -34,7 +34,7 @@ const config: ControlPanelConfig = { name: 'groupby', config: { ...sharedControls.groupby, - label: 'Column', + label: t('Column'), required: true, }, }, diff --git a/superset-frontend/src/filters/components/Time/transformProps.ts b/superset-frontend/src/filters/components/Time/transformProps.ts index 883b6002d8920..b86a3622486aa 100644 --- a/superset-frontend/src/filters/components/Time/transformProps.ts +++ b/superset-frontend/src/filters/components/Time/transformProps.ts @@ -30,9 +30,12 @@ export default function transformProps(chartProps: ChartProps) { behaviors, filterState, inputRef, + displaySettings, } = chartProps; const { setDataMask = noOp, + setHoveredFilter = noOp, + unsetHoveredFilter = noOp, setFocusedFilter = noOp, unsetFocusedFilter = noOp, setFilterActive = noOp, @@ -49,10 +52,14 @@ export default function transformProps(chartProps: ChartProps) { height, behaviors, setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, width, inputRef, + filterBarOrientation: displaySettings?.filterBarOrientation, + isOverflowingFilterBar: displaySettings?.isOverflowingFilterBar, }; } diff --git a/superset-frontend/src/filters/components/Time/types.ts b/superset-frontend/src/filters/components/Time/types.ts index 4219c7cbb351e..39ee425bb0f23 100644 --- a/superset-frontend/src/filters/components/Time/types.ts +++ b/superset-frontend/src/filters/components/Time/types.ts @@ -39,6 +39,7 @@ export type PluginFilterTimeProps = PluginFilterStylesProps & { formData: PluginFilterSelectQueryFormData; filterState: FilterState; inputRef: RefObject<HTMLInputElement>; + isOverflowingFilterBar?: boolean; } & PluginFilterHooks; export const DEFAULT_FORM_DATA: PluginFilterTimeCustomizeProps = { diff --git a/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx b/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx index fd5f21caad914..4c25b4bec0fc2 100644 --- a/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx @@ -38,6 +38,8 @@ export default function PluginFilterTimeColumn( height, width, setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, @@ -114,8 +116,10 @@ export default function PluginFilterTimeColumn( placeholder={placeholderText} // @ts-ignore onChange={handleChange} - onMouseEnter={setFocusedFilter} - onMouseLeave={unsetFocusedFilter} + onBlur={unsetFocusedFilter} + onFocus={setFocusedFilter} + onMouseEnter={setHoveredFilter} + onMouseLeave={unsetHoveredFilter} ref={inputRef} options={options} onDropdownVisibleChange={setFilterActive} diff --git a/superset-frontend/src/filters/components/TimeColumn/transformProps.ts b/superset-frontend/src/filters/components/TimeColumn/transformProps.ts index 9ca0ec047bfa8..1f502602734eb 100644 --- a/superset-frontend/src/filters/components/TimeColumn/transformProps.ts +++ b/superset-frontend/src/filters/components/TimeColumn/transformProps.ts @@ -33,6 +33,8 @@ export default function transformProps(chartProps: ChartProps) { } = chartProps; const { setDataMask = noOp, + setHoveredFilter = noOp, + unsetHoveredFilter = noOp, setFocusedFilter = noOp, unsetFocusedFilter = noOp, setFilterActive = noOp, @@ -48,6 +50,8 @@ export default function transformProps(chartProps: ChartProps) { data, formData: { ...DEFAULT_FORM_DATA, ...formData }, setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, diff --git a/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx b/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx index 383272c7bbd52..55dca4b28054a 100644 --- a/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx @@ -38,6 +38,8 @@ export default function PluginFilterTimegrain( height, width, setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, @@ -124,8 +126,10 @@ export default function PluginFilterTimegrain( placeholder={placeholderText} // @ts-ignore onChange={handleChange} - onMouseEnter={setFocusedFilter} - onMouseLeave={unsetFocusedFilter} + onBlur={unsetFocusedFilter} + onFocus={setFocusedFilter} + onMouseEnter={setHoveredFilter} + onMouseLeave={unsetHoveredFilter} ref={inputRef} options={options} onDropdownVisibleChange={setFilterActive} diff --git a/superset-frontend/src/filters/components/TimeGrain/transformProps.ts b/superset-frontend/src/filters/components/TimeGrain/transformProps.ts index 797a2d1d80e50..b86d04c0c4996 100644 --- a/superset-frontend/src/filters/components/TimeGrain/transformProps.ts +++ b/superset-frontend/src/filters/components/TimeGrain/transformProps.ts @@ -25,6 +25,8 @@ export default function transformProps(chartProps: ChartProps) { chartProps; const { setDataMask = noOp, + setHoveredFilter = noOp, + unsetHoveredFilter = noOp, setFocusedFilter = noOp, unsetFocusedFilter = noOp, setFilterActive = noOp, @@ -39,6 +41,8 @@ export default function transformProps(chartProps: ChartProps) { data, formData: { ...DEFAULT_FORM_DATA, ...formData }, setDataMask, + setHoveredFilter, + unsetHoveredFilter, setFocusedFilter, unsetFocusedFilter, setFilterActive, diff --git a/superset-frontend/src/filters/components/types.ts b/superset-frontend/src/filters/components/types.ts index 2a403fe61bb73..fd6229826bb39 100644 --- a/superset-frontend/src/filters/components/types.ts +++ b/superset-frontend/src/filters/components/types.ts @@ -1,4 +1,5 @@ import { SetDataMaskHook } from '@superset-ui/core'; +import { FilterBarOrientation } from 'src/dashboard/types'; /** * Licensed to the Apache Software Foundation (ASF) under one @@ -21,11 +22,15 @@ import { SetDataMaskHook } from '@superset-ui/core'; export interface PluginFilterStylesProps { height: number; width: number; + orientation?: FilterBarOrientation; + overflow?: boolean; } export interface PluginFilterHooks { setDataMask: SetDataMaskHook; setFocusedFilter: () => void; unsetFocusedFilter: () => void; + setHoveredFilter: () => void; + unsetHoveredFilter: () => void; setFilterActive: (isActive: boolean) => void; } diff --git a/superset-frontend/src/hooks/apiResources/dashboards.ts b/superset-frontend/src/hooks/apiResources/dashboards.ts index 9f512d5b15b2f..b21cc668c06a1 100644 --- a/superset-frontend/src/hooks/apiResources/dashboards.ts +++ b/superset-frontend/src/hooks/apiResources/dashboards.ts @@ -26,6 +26,7 @@ export const useDashboard = (idOrSlug: string | number) => useApiV1Resource<Dashboard>(`/api/v1/dashboard/${idOrSlug}`), dashboard => ({ ...dashboard, + // TODO: load these at the API level metadata: (dashboard.json_metadata && JSON.parse(dashboard.json_metadata)) || {}, position_data: diff --git a/superset-frontend/src/hooks/apiResources/index.ts b/superset-frontend/src/hooks/apiResources/index.ts index 5e63920731144..81d77b5d11a50 100644 --- a/superset-frontend/src/hooks/apiResources/index.ts +++ b/superset-frontend/src/hooks/apiResources/index.ts @@ -28,3 +28,5 @@ export { // different files for different resource types. export * from './charts'; export * from './dashboards'; +export * from './tables'; +export * from './schemas'; diff --git a/superset-frontend/src/hooks/apiResources/schemas.test.ts b/superset-frontend/src/hooks/apiResources/schemas.test.ts new file mode 100644 index 0000000000000..59d00a5dc71bc --- /dev/null +++ b/superset-frontend/src/hooks/apiResources/schemas.test.ts @@ -0,0 +1,138 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import rison from 'rison'; +import fetchMock from 'fetch-mock'; +import { act, renderHook } from '@testing-library/react-hooks'; +import QueryProvider, { queryClient } from 'src/views/QueryProvider'; +import { useSchemas } from './schemas'; + +const fakeApiResult = { + result: ['test schema 1', 'test schema b'], +}; + +const expectedResult = fakeApiResult.result.map((value: string) => ({ + value, + label: value, + title: value, +})); + +describe('useSchemas hook', () => { + beforeEach(() => { + queryClient.clear(); + jest.useFakeTimers(); + }); + + afterEach(() => { + fetchMock.reset(); + jest.useRealTimers(); + }); + + test('returns api response mapping json result', async () => { + const expectDbId = 'db1'; + const forceRefresh = false; + const schemaApiRoute = `glob:*/api/v1/database/${expectDbId}/schemas/*`; + fetchMock.get(schemaApiRoute, fakeApiResult); + const { result } = renderHook( + () => + useSchemas({ + dbId: expectDbId, + }), + { + wrapper: QueryProvider, + }, + ); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(schemaApiRoute).length).toBe(1); + expect( + fetchMock.calls( + `end:/api/v1/database/${expectDbId}/schemas/?q=${rison.encode({ + force: forceRefresh, + })}`, + ).length, + ).toBe(1); + expect(result.current.data).toEqual(expectedResult); + await act(async () => { + result.current.refetch(); + }); + expect(fetchMock.calls(schemaApiRoute).length).toBe(2); + expect( + fetchMock.calls( + `end:/api/v1/database/${expectDbId}/schemas/?q=${rison.encode({ + force: true, + })}`, + ).length, + ).toBe(1); + expect(result.current.data).toEqual(expectedResult); + }); + + test('returns cached data without api request', async () => { + const expectDbId = 'db1'; + const schemaApiRoute = `glob:*/api/v1/database/${expectDbId}/schemas/*`; + fetchMock.get(schemaApiRoute, fakeApiResult); + const { result, rerender } = renderHook( + () => + useSchemas({ + dbId: expectDbId, + }), + { + wrapper: QueryProvider, + }, + ); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(schemaApiRoute).length).toBe(1); + rerender(); + expect(fetchMock.calls(schemaApiRoute).length).toBe(1); + expect(result.current.data).toEqual(expectedResult); + }); + + it('returns refreshed data after expires', async () => { + const expectDbId = 'db1'; + const schemaApiRoute = `glob:*/api/v1/database/${expectDbId}/schemas/*`; + fetchMock.get(schemaApiRoute, fakeApiResult); + const { result, rerender } = renderHook( + () => + useSchemas({ + dbId: expectDbId, + }), + { + wrapper: QueryProvider, + }, + ); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(schemaApiRoute).length).toBe(1); + rerender(); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(schemaApiRoute).length).toBe(1); + queryClient.clear(); + rerender(); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(schemaApiRoute).length).toBe(2); + expect(result.current.data).toEqual(expectedResult); + }); +}); diff --git a/superset-frontend/src/hooks/apiResources/schemas.ts b/superset-frontend/src/hooks/apiResources/schemas.ts new file mode 100644 index 0000000000000..34a50ca4e9896 --- /dev/null +++ b/superset-frontend/src/hooks/apiResources/schemas.ts @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useRef } from 'react'; +import { useQuery, UseQueryOptions } from 'react-query'; +import rison from 'rison'; +import { SupersetClient } from '@superset-ui/core'; + +export type FetchSchemasQueryParams = { + dbId?: string | number; + forceRefresh?: boolean; +}; + +type QueryData = { + json: { result: string[] }; + response: Response; +}; + +export type SchemaOption = { + value: string; + label: string; + title: string; +}; + +export function fetchSchemas({ dbId, forceRefresh }: FetchSchemasQueryParams) { + const queryParams = rison.encode({ force: forceRefresh }); + // TODO: Would be nice to add pagination in a follow-up. Needs endpoint changes. + const endpoint = `/api/v1/database/${dbId}/schemas/?q=${queryParams}`; + return SupersetClient.get({ endpoint }) as Promise<QueryData>; +} + +type Params = FetchSchemasQueryParams & + Pick<UseQueryOptions<SchemaOption[]>, 'onSuccess' | 'onError'>; + +export function useSchemas(options: Params) { + const { dbId, onSuccess, onError } = options || {}; + const forceRefreshRef = useRef(false); + const params = { dbId }; + const result = useQuery<QueryData, Error, SchemaOption[]>( + ['schemas', { dbId }], + () => fetchSchemas({ ...params, forceRefresh: forceRefreshRef.current }), + { + select: ({ json }) => + json.result.map((value: string) => ({ + value, + label: value, + title: value, + })), + enabled: Boolean(dbId), + onSuccess, + onError, + onSettled: () => { + forceRefreshRef.current = false; + }, + }, + ); + + return { + ...result, + refetch: () => { + forceRefreshRef.current = true; + return result.refetch(); + }, + }; +} diff --git a/superset-frontend/src/hooks/apiResources/tables.test.ts b/superset-frontend/src/hooks/apiResources/tables.test.ts new file mode 100644 index 0000000000000..8cc0791d50694 --- /dev/null +++ b/superset-frontend/src/hooks/apiResources/tables.test.ts @@ -0,0 +1,248 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import rison from 'rison'; +import fetchMock from 'fetch-mock'; +import { act, renderHook } from '@testing-library/react-hooks'; +import QueryProvider, { queryClient } from 'src/views/QueryProvider'; +import { useTables } from './tables'; + +const fakeApiResult = { + count: 2, + result: [ + { + id: 1, + name: 'fake api result1', + label: 'fake api label1', + }, + { + id: 2, + name: 'fake api result2', + label: 'fake api label2', + }, + ], +}; + +const fakeHasMoreApiResult = { + count: 4, + result: [ + { + id: 1, + name: 'fake api result1', + label: 'fake api label1', + }, + { + id: 2, + name: 'fake api result2', + label: 'fake api label2', + }, + ], +}; + +const fakeSchemaApiResult = ['schema1', 'schema2']; + +const expectedData = { + options: fakeApiResult.result, + hasMore: false, +}; + +const expectedHasMoreData = { + options: fakeHasMoreApiResult.result, + hasMore: true, +}; + +describe('useTables hook', () => { + beforeEach(() => { + queryClient.clear(); + jest.useFakeTimers(); + }); + + afterEach(() => { + fetchMock.reset(); + jest.useRealTimers(); + }); + + test('returns api response mapping json options', async () => { + const expectDbId = 'db1'; + const expectedSchema = 'schema1'; + const schemaApiRoute = `glob:*/api/v1/database/${expectDbId}/schemas/*`; + const tableApiRoute = `glob:*/api/v1/database/${expectDbId}/tables/?q=*`; + fetchMock.get(tableApiRoute, fakeApiResult); + fetchMock.get(schemaApiRoute, { + result: fakeSchemaApiResult, + }); + const { result } = renderHook( + () => + useTables({ + dbId: expectDbId, + schema: expectedSchema, + }), + { + wrapper: QueryProvider, + }, + ); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(schemaApiRoute).length).toBe(1); + expect( + fetchMock.calls( + `end:api/v1/database/${expectDbId}/tables/?q=${rison.encode({ + force: false, + schema_name: expectedSchema, + })}`, + ).length, + ).toBe(1); + expect(result.current.data).toEqual(expectedData); + await act(async () => { + result.current.refetch(); + }); + expect(fetchMock.calls(schemaApiRoute).length).toBe(1); + expect( + fetchMock.calls( + `end:api/v1/database/${expectDbId}/tables/?q=${rison.encode({ + force: true, + schema_name: expectedSchema, + })}`, + ).length, + ).toBe(1); + expect(result.current.data).toEqual(expectedData); + }); + + test('skips the deprecated schema option', async () => { + const expectDbId = 'db1'; + const unexpectedSchema = 'invalid schema'; + const schemaApiRoute = `glob:*/api/v1/database/${expectDbId}/schemas/*`; + const tableApiRoute = `glob:*/api/v1/database/${expectDbId}/tables/?q=*`; + fetchMock.get(tableApiRoute, fakeApiResult); + fetchMock.get(schemaApiRoute, { + result: fakeSchemaApiResult, + }); + const { result } = renderHook( + () => + useTables({ + dbId: expectDbId, + schema: unexpectedSchema, + }), + { + wrapper: QueryProvider, + }, + ); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(schemaApiRoute).length).toBe(1); + expect(result.current.data).toEqual(undefined); + expect( + fetchMock.calls( + `end:api/v1/database/${expectDbId}/tables/?q=${rison.encode({ + force: false, + schema_name: unexpectedSchema, + })}`, + ).length, + ).toBe(0); + }); + + test('returns hasMore when total is larger than result size', async () => { + const expectDbId = 'db1'; + const expectedSchema = 'schema2'; + const tableApiRoute = `glob:*/api/v1/database/${expectDbId}/tables/?q=*`; + fetchMock.get(tableApiRoute, fakeHasMoreApiResult); + fetchMock.get(`glob:*/api/v1/database/${expectDbId}/schemas/*`, { + result: fakeSchemaApiResult, + }); + const { result } = renderHook( + () => + useTables({ + dbId: expectDbId, + schema: expectedSchema, + }), + { + wrapper: QueryProvider, + }, + ); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(tableApiRoute).length).toBe(1); + expect(result.current.data).toEqual(expectedHasMoreData); + }); + + test('returns cached data without api request', async () => { + const expectDbId = 'db1'; + const expectedSchema = 'schema1'; + const tableApiRoute = `glob:*/api/v1/database/${expectDbId}/tables/?q=*`; + fetchMock.get(tableApiRoute, fakeApiResult); + fetchMock.get(`glob:*/api/v1/database/${expectDbId}/schemas/*`, { + result: fakeSchemaApiResult, + }); + const { result, rerender } = renderHook( + () => + useTables({ + dbId: expectDbId, + schema: expectedSchema, + }), + { + wrapper: QueryProvider, + }, + ); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(tableApiRoute).length).toBe(1); + rerender(); + expect(fetchMock.calls(tableApiRoute).length).toBe(1); + expect(result.current.data).toEqual(expectedData); + }); + + test('returns refreshed data after expires', async () => { + const expectDbId = 'db1'; + const expectedSchema = 'schema1'; + const tableApiRoute = `glob:*/api/v1/database/${expectDbId}/tables/?q=*`; + fetchMock.get(tableApiRoute, fakeApiResult); + fetchMock.get(`glob:*/api/v1/database/${expectDbId}/schemas/*`, { + result: fakeSchemaApiResult, + }); + const { result, rerender } = renderHook( + () => + useTables({ + dbId: expectDbId, + schema: expectedSchema, + }), + { + wrapper: QueryProvider, + }, + ); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(tableApiRoute).length).toBe(1); + rerender(); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(tableApiRoute).length).toBe(1); + queryClient.clear(); + rerender(); + await act(async () => { + jest.runAllTimers(); + }); + expect(fetchMock.calls(tableApiRoute).length).toBe(2); + expect(result.current.data).toEqual(expectedData); + }); +}); diff --git a/superset-frontend/src/hooks/apiResources/tables.ts b/superset-frontend/src/hooks/apiResources/tables.ts new file mode 100644 index 0000000000000..34d286c9456a2 --- /dev/null +++ b/superset-frontend/src/hooks/apiResources/tables.ts @@ -0,0 +1,115 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useRef, useMemo } from 'react'; +import { useQuery, UseQueryOptions } from 'react-query'; +import rison from 'rison'; +import { SupersetClient } from '@superset-ui/core'; + +import { useSchemas } from './schemas'; + +export type FetchTablesQueryParams = { + dbId?: string | number; + schema?: string; + forceRefresh?: boolean; +}; +export interface Table { + label: string; + value: string; + type: string; + extra?: { + certification?: { + certified_by: string; + details: string; + }; + warning_markdown?: string; + }; +} + +type QueryData = { + json: { + count: number; + result: Table[]; + }; + response: Response; +}; + +export type Data = { + options: Table[]; + hasMore: boolean; +}; + +export function fetchTables({ + dbId, + schema, + forceRefresh, +}: FetchTablesQueryParams) { + const encodedSchema = schema ? encodeURIComponent(schema) : ''; + const params = rison.encode({ + force: forceRefresh, + schema_name: encodedSchema, + }); + + // TODO: Would be nice to add pagination in a follow-up. Needs endpoint changes. + const endpoint = `/api/v1/database/${ + dbId ?? 'undefined' + }/tables/?q=${params}`; + return SupersetClient.get({ endpoint }) as Promise<QueryData>; +} + +type Params = FetchTablesQueryParams & + Pick<UseQueryOptions<Data>, 'onSuccess' | 'onError'>; + +export function useTables(options: Params) { + const { data: schemaOptions, isFetching } = useSchemas({ + dbId: options.dbId, + }); + const schemaOptionsMap = useMemo( + () => new Set(schemaOptions?.map(({ value }) => value)), + [schemaOptions], + ); + const { dbId, schema, onSuccess, onError } = options || {}; + const forceRefreshRef = useRef(false); + const params = { dbId, schema }; + const result = useQuery<QueryData, Error, Data>( + ['tables', { dbId, schema }], + () => fetchTables({ ...params, forceRefresh: forceRefreshRef.current }), + { + select: ({ json }) => ({ + options: json.result, + hasMore: json.count > json.result.length, + }), + enabled: Boolean( + dbId && schema && !isFetching && schemaOptionsMap.has(schema), + ), + onSuccess, + onError, + onSettled: () => { + forceRefreshRef.current = false; + }, + }, + ); + + return { + ...result, + refetch: () => { + forceRefreshRef.current = true; + return result.refetch(); + }, + }; +} diff --git a/superset-frontend/src/hooks/useTabId.ts b/superset-frontend/src/hooks/useTabId.ts index 1bd0df3a36aa7..4f60763c88875 100644 --- a/superset-frontend/src/hooks/useTabId.ts +++ b/superset-frontend/src/hooks/useTabId.ts @@ -17,6 +17,7 @@ * under the License. */ import { useEffect, useState } from 'react'; +import shortid from 'shortid'; import { BroadcastChannel } from 'broadcast-channel'; interface TabIdChannelMessage { @@ -32,7 +33,21 @@ const channel = new BroadcastChannel<TabIdChannelMessage>('tab_id_channel'); export function useTabId() { const [tabId, setTabId] = useState<string>(); + function isStorageAvailable() { + try { + return window.localStorage && window.sessionStorage; + } catch (error) { + return false; + } + } useEffect(() => { + if (!isStorageAvailable()) { + if (!tabId) { + setTabId(shortid.generate()); + } + return; + } + const updateTabId = () => { const lastTabId = window.localStorage.getItem('last_tab_id'); const newTabId = String( diff --git a/superset-frontend/src/explore/components/DataTablesPane/utils.ts b/superset-frontend/src/hooks/useTruncation/index.ts similarity index 80% rename from superset-frontend/src/explore/components/DataTablesPane/utils.ts rename to superset-frontend/src/hooks/useTruncation/index.ts index c6394fb9b67f5..5dc5550188a3d 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/utils.ts +++ b/superset-frontend/src/hooks/useTruncation/index.ts @@ -16,9 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -const queryObjectCount = { - mixed_timeseries: 2, -}; -export const getQueryCount = (vizType: string): number => - queryObjectCount?.[vizType] || 1; +import useTruncation from './useChildElementTruncation'; +import useCSSTextTruncation, { truncationCSS } from './useCSSTextTruncation'; + +export { useTruncation, useCSSTextTruncation, truncationCSS }; diff --git a/superset-frontend/src/hooks/useTruncation/useCSSTextTruncation.ts b/superset-frontend/src/hooks/useTruncation/useCSSTextTruncation.ts new file mode 100644 index 0000000000000..a591766fbb2c7 --- /dev/null +++ b/superset-frontend/src/hooks/useTruncation/useCSSTextTruncation.ts @@ -0,0 +1,61 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { css } from '@emotion/react'; +import React, { useEffect, useRef, useState } from 'react'; + +/** + * Importable CSS that enables text truncation on fixed-width block + * elements. + */ +export const truncationCSS = css` + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +`; + +/** + * This hook encapsulates logic supporting truncation of text via + * the CSS "text-overflow: ellipsis;" feature. Given the text content + * to be displayed, this hook returns a ref to attach to the text + * element and a boolean for whether that element is currently truncated. + */ +const useCSSTextTruncation = <T extends HTMLElement>(): [ + React.RefObject<T>, + boolean, +] => { + const [isTruncated, setIsTruncated] = useState(true); + const ref = useRef<T>(null); + const [offsetWidth, setOffsetWidth] = useState(0); + const [scrollWidth, setScrollWidth] = useState(0); + + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(() => { + setOffsetWidth(ref.current?.offsetWidth ?? 0); + setScrollWidth(ref.current?.scrollWidth ?? 0); + }); + + useEffect(() => { + setIsTruncated(offsetWidth < scrollWidth); + }, [offsetWidth, scrollWidth]); + + return [ref, isTruncated]; +}; + +export default useCSSTextTruncation; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useTruncation.ts b/superset-frontend/src/hooks/useTruncation/useChildElementTruncation.ts similarity index 62% rename from superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useTruncation.ts rename to superset-frontend/src/hooks/useTruncation/useChildElementTruncation.ts index a4a893463f616..4f6b628642ab4 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useTruncation.ts +++ b/superset-frontend/src/hooks/useTruncation/useChildElementTruncation.ts @@ -18,17 +18,32 @@ */ import { RefObject, useLayoutEffect, useState, useRef } from 'react'; -export const useTruncation = (elementRef: RefObject<HTMLElement>) => { +/** + * This hook encapsulates logic to support truncation of child HTML + * elements contained in a fixed-width parent HTML element. Given + * a ref to the parent element and optionally a ref to the "+x" + * component that shows the number of truncated items, this hook + * will return the number of elements that are not fully visible + * (including those completely hidden) and whether any elements + * are completely hidden. + */ +const useChildElementTruncation = ( + elementRef: RefObject<HTMLElement>, + plusRef?: RefObject<HTMLElement>, +) => { const [elementsTruncated, setElementsTruncated] = useState(0); const [hasHiddenElements, setHasHiddenElements] = useState(false); const previousEffectInfoRef = useRef({ scrollWidth: 0, parentElementWidth: 0, + plusRefWidth: 0, }); useLayoutEffect(() => { const currentElement = elementRef.current; + const plusRefElement = plusRef?.current; + if (!currentElement) { return; } @@ -45,36 +60,50 @@ export const useTruncation = (elementRef: RefObject<HTMLElement>) => { // the child nodes changes. const previousEffectInfo = previousEffectInfoRef.current; const parentElementWidth = currentElement.parentElement?.clientWidth || 0; + const plusRefWidth = plusRefElement?.offsetWidth || 0; previousEffectInfoRef.current = { scrollWidth, parentElementWidth, + plusRefWidth, }; if ( previousEffectInfo.parentElementWidth === parentElementWidth && - previousEffectInfo.scrollWidth === scrollWidth + previousEffectInfo.scrollWidth === scrollWidth && + previousEffectInfo.plusRefWidth === plusRefWidth ) { return; } if (scrollWidth > clientWidth) { // "..." is around 6px wide - const maxWidth = clientWidth - 6; + const truncationWidth = 6; + const plusSize = plusRefElement?.offsetWidth || 0; + const maxWidth = clientWidth - truncationWidth; const elementsCount = childNodes.length; + let width = 0; - let i = 0; - while (width < maxWidth) { - width += (childNodes[i] as HTMLElement).offsetWidth; - i += 1; + let hiddenElements = 0; + for (let i = 0; i < elementsCount; i += 1) { + const itemWidth = (childNodes[i] as HTMLElement).offsetWidth; + const remainingWidth = maxWidth - truncationWidth - width - plusSize; + + // assures it shows +{number} only when the item is not visible + if (remainingWidth <= 0) { + hiddenElements += 1; + } + width += itemWidth; } - if (i === elementsCount) { - setElementsTruncated(1); - setHasHiddenElements(false); - } else { - setElementsTruncated(elementsCount - i); + + if (elementsCount > 1 && hiddenElements) { setHasHiddenElements(true); + setElementsTruncated(hiddenElements); + } else { + setHasHiddenElements(false); + setElementsTruncated(1); } } else { + setHasHiddenElements(false); setElementsTruncated(0); } }, [ @@ -85,3 +114,5 @@ export const useTruncation = (elementRef: RefObject<HTMLElement>) => { return [elementsTruncated, hasHiddenElements]; }; + +export default useChildElementTruncation; diff --git a/superset-frontend/src/logger/LogUtils.ts b/superset-frontend/src/logger/LogUtils.ts index b3e834bc935df..5c4c05e4f09bc 100644 --- a/superset-frontend/src/logger/LogUtils.ts +++ b/superset-frontend/src/logger/LogUtils.ts @@ -35,6 +35,23 @@ export const LOG_ACTIONS_EXPLORE_DASHBOARD_CHART = 'explore_dashboard_chart'; export const LOG_ACTIONS_EXPORT_CSV_DASHBOARD_CHART = 'export_csv_dashboard_chart'; export const LOG_ACTIONS_CHANGE_DASHBOARD_FILTER = 'change_dashboard_filter'; +export const LOG_ACTIONS_DATASET_CREATION_EMPTY_CANCELLATION = + 'dataset_creation_empty_cancellation'; +export const LOG_ACTIONS_DATASET_CREATION_DATABASE_CANCELLATION = + 'dataset_creation_database_cancellation'; +export const LOG_ACTIONS_DATASET_CREATION_SCHEMA_CANCELLATION = + 'dataset_creation_schema_cancellation'; +export const LOG_ACTIONS_DATASET_CREATION_TABLE_CANCELLATION = + 'dataset_creation_table_cancellation'; +export const LOG_ACTIONS_DATASET_CREATION_SUCCESS = 'dataset_creation_success'; +export const LOG_ACTIONS_SPA_NAVIGATION = 'spa_navigation'; +export const LOG_ACTIONS_CONFIRM_OVERWRITE_DASHBOARD_METADATA = + 'confirm_overwrite_dashboard_metadata'; +export const LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_IMAGE = + 'dashboard_download_as_image'; +export const LOG_ACTIONS_CHART_DOWNLOAD_AS_IMAGE = 'chart_download_as_image'; +export const LOG_ACTIONS_SQLLAB_WARN_LOCAL_STORAGE_USAGE = + 'sqllab_warn_local_storage_usage'; // Log event types -------------------------------------------------------------- export const LOG_EVENT_TYPE_TIMING = new Set([ @@ -54,8 +71,19 @@ export const LOG_EVENT_TYPE_USER = new Set([ LOG_ACTIONS_FORCE_REFRESH_DASHBOARD, LOG_ACTIONS_PERIODIC_RENDER_DASHBOARD, LOG_ACTIONS_MOUNT_EXPLORER, + LOG_ACTIONS_CONFIRM_OVERWRITE_DASHBOARD_METADATA, + LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_IMAGE, + LOG_ACTIONS_CHART_DOWNLOAD_AS_IMAGE, ]); +export const LOG_EVENT_DATASET_TYPE_DATASET_CREATION = [ + LOG_ACTIONS_DATASET_CREATION_EMPTY_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_DATABASE_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_SCHEMA_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_TABLE_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_SUCCESS, +]; + export const Logger = { timeOriginOffset: 0, diff --git a/superset-frontend/src/middleware/asyncEvent.ts b/superset-frontend/src/middleware/asyncEvent.ts index 9ae4f90e479f4..6966ad6d3f710 100644 --- a/superset-frontend/src/middleware/asyncEvent.ts +++ b/superset-frontend/src/middleware/asyncEvent.ts @@ -23,6 +23,7 @@ import { logging, } from '@superset-ui/core'; import { SupersetError } from 'src/components/ErrorMessage/types'; +import getBootstrapData from 'src/utils/getBootstrapData'; import { FeatureFlag, isFeatureEnabled } from '../featureFlags'; import { getClientErrorObject, @@ -171,7 +172,7 @@ const loadEventsFromApi = async () => { if (Object.keys(listenersByJobId).length) { try { const { result: events } = await fetchEvents(eventArgs); - if (events && events.length) await processEvents(events); + if (events?.length) await processEvents(events); } catch (err) { logging.warn(err); } @@ -235,21 +236,7 @@ export const init = (appConfig?: AppConfig) => { retriesByJobId = {}; lastReceivedEventId = null; - if (appConfig) { - config = appConfig; - } else { - // load bootstrap data from DOM - const appContainer = document.getElementById('app'); - if (appContainer) { - const bootstrapData = JSON.parse( - appContainer?.getAttribute('data-bootstrap') || '{}', - ); - config = bootstrapData?.common?.conf; - } else { - config = {}; - logging.warn('asyncEvent: app config data not found'); - } - } + config = appConfig || getBootstrapData().common.conf; transport = config.GLOBAL_ASYNC_QUERIES_TRANSPORT || TRANSPORT_POLLING; pollingDelayMs = config.GLOBAL_ASYNC_QUERIES_POLLING_DELAY || 500; diff --git a/superset-frontend/src/middleware/logger.test.js b/superset-frontend/src/middleware/logger.test.js index fd584c2b36ac7..d67c681caaf1c 100644 --- a/superset-frontend/src/middleware/logger.test.js +++ b/superset-frontend/src/middleware/logger.test.js @@ -109,4 +109,39 @@ describe('logger middleware', () => { SupersetClient.post.getCall(0).args[0].postPayload.events, ).toHaveLength(3); }); + + it('should use navigator.sendBeacon if it exists', () => { + const clock = sinon.useFakeTimers(); + const beaconMock = jest.fn(); + Object.defineProperty(navigator, 'sendBeacon', { + writable: true, + value: beaconMock, + }); + + logger(mockStore)(next)(action); + expect(beaconMock.mock.calls.length).toBe(0); + clock.tick(2000); + + expect(beaconMock.mock.calls.length).toBe(1); + const endpoint = beaconMock.mock.calls[0][0]; + expect(endpoint).toMatch('/superset/log/'); + }); + + it('should pass a guest token to sendBeacon if present', () => { + const clock = sinon.useFakeTimers(); + const beaconMock = jest.fn(); + Object.defineProperty(navigator, 'sendBeacon', { + writable: true, + value: beaconMock, + }); + SupersetClient.configure({ guestToken: 'token' }); + + logger(mockStore)(next)(action); + expect(beaconMock.mock.calls.length).toBe(0); + clock.tick(2000); + expect(beaconMock.mock.calls.length).toBe(1); + + const formData = beaconMock.mock.calls[0][1]; + expect(formData.getAll('guest_token')[0]).toMatch('token'); + }); }); diff --git a/superset-frontend/src/middleware/loggerMiddleware.js b/superset-frontend/src/middleware/loggerMiddleware.js index b88d555428514..475c1784cce55 100644 --- a/superset-frontend/src/middleware/loggerMiddleware.js +++ b/superset-frontend/src/middleware/loggerMiddleware.js @@ -44,6 +44,10 @@ const sendBeacon = events => { if (navigator.sendBeacon) { const formData = new FormData(); formData.append('events', safeStringify(events)); + if (SupersetClient.getGuestToken()) { + // if we have a guest token, we need to send it for auth via the form + formData.append('guest_token', SupersetClient.getGuestToken()); + } navigator.sendBeacon(endpoint, formData); } else { SupersetClient.post({ @@ -68,24 +72,34 @@ const loggerMiddleware = store => next => action => { return next(action); } - const { dashboardInfo, explore, impressionId, dashboardLayout } = + const { dashboardInfo, explore, impressionId, dashboardLayout, sqlLab } = store.getState(); let logMetadata = { impression_id: impressionId, version: 'v2', }; - if (dashboardInfo) { + if (dashboardInfo?.id) { logMetadata = { source: 'dashboard', source_id: dashboardInfo.id, ...logMetadata, }; - } else if (explore) { + } else if (explore?.slice) { logMetadata = { source: 'explore', source_id: explore.slice ? explore.slice.slice_id : 0, ...logMetadata, }; + } else if (sqlLab) { + const editor = sqlLab.queryEditors.find( + ({ id }) => id === sqlLab.tabHistory.slice(-1)[0], + ); + logMetadata = { + source: 'sqlLab', + source_id: editor?.id, + db_id: editor?.dbId, + schema: editor?.schema, + }; } const { eventName } = action.payload; diff --git a/superset-frontend/src/modules/AnnotationTypes.js b/superset-frontend/src/modules/AnnotationTypes.js index 1f8556114d122..cdf7a161f768f 100644 --- a/superset-frontend/src/modules/AnnotationTypes.js +++ b/superset-frontend/src/modules/AnnotationTypes.js @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ +import { t } from '@superset-ui/core'; + function extractTypes(metadata) { return Object.keys(metadata).reduce((prev, key) => { const result = prev; @@ -27,21 +29,21 @@ function extractTypes(metadata) { export const ANNOTATION_TYPES_METADATA = { FORMULA: { value: 'FORMULA', - label: 'Formula', + label: t('Formula'), }, EVENT: { value: 'EVENT', - label: 'Event', + label: t('Event'), supportNativeSource: true, }, INTERVAL: { value: 'INTERVAL', - label: 'Interval', + label: t('Interval'), supportNativeSource: true, }, TIME_SERIES: { value: 'TIME_SERIES', - label: 'Time series', + label: t('Time series'), }, }; diff --git a/superset-frontend/src/pages/ChartCreation/ChartCreation.test.tsx b/superset-frontend/src/pages/ChartCreation/ChartCreation.test.tsx new file mode 100644 index 0000000000000..2c3c7b5d639e7 --- /dev/null +++ b/superset-frontend/src/pages/ChartCreation/ChartCreation.test.tsx @@ -0,0 +1,153 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { ReactWrapper } from 'enzyme'; +import { styledMount as mount } from 'spec/helpers/theming'; +import Button from 'src/components/Button'; +import { AsyncSelect } from 'src/components'; +import { + ChartCreation, + ChartCreationProps, + ChartCreationState, +} from 'src/pages/ChartCreation'; +import VizTypeGallery from 'src/explore/components/controls/VizTypeControl/VizTypeGallery'; +import { act } from 'spec/helpers/testing-library'; +import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; + +const datasource = { + value: '1', + label: 'table', +}; + +const mockUser: UserWithPermissionsAndRoles = { + createdOn: '2021-04-27T18:12:38.952304', + email: 'admin', + firstName: 'admin', + isActive: true, + lastName: 'admin', + permissions: {}, + roles: { Admin: Array(173) }, + userId: 1, + username: 'admin', + isAnonymous: false, +}; + +const mockUserWithDatasetWrite: UserWithPermissionsAndRoles = { + createdOn: '2021-04-27T18:12:38.952304', + email: 'admin', + firstName: 'admin', + isActive: true, + lastName: 'admin', + permissions: {}, + roles: { Admin: [['can_write', 'Dataset']] }, + userId: 1, + username: 'admin', + isAnonymous: false, +}; + +// We don't need the actual implementation for the tests +const routeProps = { + history: {} as any, + location: {} as any, + match: {} as any, +}; + +async function getWrapper(user = mockUser) { + const wrapper = mount( + <ChartCreation user={user} addSuccessToast={() => null} {...routeProps} />, + ) as unknown as ReactWrapper< + ChartCreationProps, + ChartCreationState, + ChartCreation + >; + await act(() => new Promise(resolve => setTimeout(resolve, 0))); + return wrapper; +} + +test('renders a select and a VizTypeGallery', async () => { + const wrapper = await getWrapper(); + expect(wrapper.find(AsyncSelect)).toExist(); + expect(wrapper.find(VizTypeGallery)).toExist(); +}); + +test('renders dataset help text when user lacks dataset write permissions', async () => { + const wrapper = await getWrapper(); + expect(wrapper.find('[data-test="dataset-write"]')).not.toExist(); + expect(wrapper.find('[data-test="no-dataset-write"]')).toExist(); +}); + +test('renders dataset help text when user has dataset write permissions', async () => { + const wrapper = await getWrapper(mockUserWithDatasetWrite); + expect(wrapper.find('[data-test="dataset-write"]')).toExist(); + expect(wrapper.find('[data-test="no-dataset-write"]')).not.toExist(); +}); + +test('renders a button', async () => { + const wrapper = await getWrapper(); + expect(wrapper.find(Button)).toExist(); +}); + +test('renders a disabled button if no datasource is selected', async () => { + const wrapper = await getWrapper(); + expect( + wrapper.find(Button).find({ disabled: true }).hostNodes(), + ).toHaveLength(1); +}); + +test('renders an enabled button if datasource and viz type are selected', async () => { + const wrapper = await getWrapper(); + wrapper.setState({ + datasource, + vizType: 'table', + }); + expect( + wrapper.find(Button).find({ disabled: true }).hostNodes(), + ).toHaveLength(0); +}); + +test('double-click viz type does nothing if no datasource is selected', async () => { + const wrapper = await getWrapper(); + wrapper.instance().gotoSlice = jest.fn(); + wrapper.update(); + wrapper.instance().onVizTypeDoubleClick(); + expect(wrapper.instance().gotoSlice).not.toBeCalled(); +}); + +test('double-click viz type submits if datasource is selected', async () => { + const wrapper = await getWrapper(); + wrapper.instance().gotoSlice = jest.fn(); + wrapper.update(); + wrapper.setState({ + datasource, + vizType: 'table', + }); + + wrapper.instance().onVizTypeDoubleClick(); + expect(wrapper.instance().gotoSlice).toBeCalled(); +}); + +test('formats Explore url', async () => { + const wrapper = await getWrapper(); + wrapper.setState({ + datasource, + vizType: 'table', + }); + const formattedUrl = '/explore/?viz_type=table&datasource=1'; + expect(wrapper.instance().exploreUrl()).toBe(formattedUrl); +}); diff --git a/superset-frontend/src/addSlice/AddSliceContainer.tsx b/superset-frontend/src/pages/ChartCreation/index.tsx similarity index 62% rename from superset-frontend/src/addSlice/AddSliceContainer.tsx rename to superset-frontend/src/pages/ChartCreation/index.tsx index fd22377314ac8..2a01a9123af12 100644 --- a/superset-frontend/src/addSlice/AddSliceContainer.tsx +++ b/superset-frontend/src/pages/ChartCreation/index.tsx @@ -18,18 +18,28 @@ */ import React, { ReactNode } from 'react'; import rison from 'rison'; -import { styled, t, SupersetClient, JsonResponse } from '@superset-ui/core'; +import querystring from 'query-string'; +import { + styled, + t, + SupersetClient, + JsonResponse, + isDefined, +} from '@superset-ui/core'; import { getUrlParam } from 'src/utils/urlUtils'; import { URL_PARAMS } from 'src/constants'; -import { isNullish } from 'src/utils/common'; +import { Link, withRouter, RouteComponentProps } from 'react-router-dom'; import Button from 'src/components/Button'; -import { Select, Steps } from 'src/components'; -import { FormLabel } from 'src/components/Form'; +import { AsyncSelect, Steps } from 'src/components'; import { Tooltip } from 'src/components/Tooltip'; +import withToasts from 'src/components/MessageToasts/withToasts'; import VizTypeGallery, { MAX_ADVISABLE_VIZ_GALLERY_WIDTH, } from 'src/explore/components/controls/VizTypeControl/VizTypeGallery'; +import { findPermission } from 'src/utils/findPermission'; +import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; +import getBootstrapData from 'src/utils/getBootstrapData'; type Dataset = { id: number; @@ -38,16 +48,24 @@ type Dataset = { datasource_type: string; }; -export type AddSliceContainerProps = {}; +export interface ChartCreationProps extends RouteComponentProps { + user: UserWithPermissionsAndRoles; + addSuccessToast: (arg: string) => void; +} -export type AddSliceContainerState = { +export type ChartCreationState = { datasource?: { label: string; value: string }; - visType: string | null; + datasetName?: string | string[] | null; + vizType: string | null; + canCreateDataset: boolean; }; const ESTIMATED_NAV_HEIGHT = 56; const ELEMENTS_EXCEPT_VIZ_GALLERY = ESTIMATED_NAV_HEIGHT + 250; +const bootstrapData = getBootstrapData(); +const denyList: string[] = bootstrapData.common.conf.VIZ_TYPE_DENYLIST || []; + const StyledContainer = styled.div` ${({ theme }) => ` flex: 1 1 auto; @@ -73,7 +91,6 @@ const StyledContainer = styled.div` display: flex; flex-direction: row; align-items: center; - margin-bottom: ${theme.gridUnit * 2}px; & > div { min-width: 200px; @@ -180,49 +197,91 @@ const StyledLabel = styled.span` `} `; -export default class AddSliceContainer extends React.PureComponent< - AddSliceContainerProps, - AddSliceContainerState +const StyledStepTitle = styled.span` + ${({ + theme: { + typography: { sizes, weights }, + }, + }) => ` + font-size: ${sizes.m}px; + font-weight: ${weights.bold}; + `} +`; + +const StyledStepDescription = styled.div` + ${({ theme: { gridUnit } }) => ` + margin-top: ${gridUnit * 4}px; + margin-bottom: ${gridUnit * 3}px; + `} +`; + +export class ChartCreation extends React.PureComponent< + ChartCreationProps, + ChartCreationState > { - constructor(props: AddSliceContainerProps) { + constructor(props: ChartCreationProps) { super(props); this.state = { - visType: null, + vizType: null, + canCreateDataset: findPermission( + 'can_write', + 'Dataset', + props.user.roles, + ), }; this.changeDatasource = this.changeDatasource.bind(this); - this.changeVisType = this.changeVisType.bind(this); + this.changeVizType = this.changeVizType.bind(this); this.gotoSlice = this.gotoSlice.bind(this); this.newLabel = this.newLabel.bind(this); this.loadDatasources = this.loadDatasources.bind(this); + this.onVizTypeDoubleClick = this.onVizTypeDoubleClick.bind(this); + } + + componentDidMount() { + const params = querystring.parse(window.location.search)?.dataset as string; + if (params) { + this.loadDatasources(params, 0, 1).then(r => { + const datasource = r.data[0]; + // override here to force styling of option label + // which expects a reactnode instead of string + // @ts-expect-error + datasource.label = datasource.customLabel; + this.setState({ datasource }); + }); + this.props.addSuccessToast(t('The dataset has been saved')); + } } exploreUrl() { const dashboardId = getUrlParam(URL_PARAMS.dashboardId); - const formData = encodeURIComponent( - JSON.stringify({ - viz_type: this.state.visType, - datasource: this.state.datasource?.value, - ...(!isNullish(dashboardId) && { dashboardId }), - }), - ); - return `/superset/explore/?form_data=${formData}`; + let url = `/explore/?viz_type=${this.state.vizType}&datasource=${this.state.datasource?.value}`; + if (isDefined(dashboardId)) { + url += `&dashboard_id=${dashboardId}`; + } + return url; } gotoSlice() { - window.location.href = this.exploreUrl(); + this.props.history.push(this.exploreUrl()); } changeDatasource(datasource: { label: string; value: string }) { this.setState({ datasource }); } - changeVisType(visType: string | null) { - this.setState({ visType }); + changeVizType(vizType: string | null) { + this.setState({ vizType }); } isBtnDisabled() { - return !(this.state.datasource?.value && this.state.visType); + return !(this.state.datasource?.value && this.state.vizType); + } + + onVizTypeDoubleClick() { + if (!this.isBtnDisabled()) { + this.gotoSlice(); + } } newLabel(item: Dataset) { @@ -276,16 +335,48 @@ export default class AddSliceContainer extends React.PureComponent< render() { const isButtonDisabled = this.isBtnDisabled(); + const VIEW_INSTRUCTIONS_TEXT = t('view instructions'); + const datasetHelpText = this.state.canCreateDataset ? ( + <span data-test="dataset-write"> + <Link to="/dataset/add/" data-test="add-chart-new-dataset"> + {t('Add a dataset')}{' '} + </Link> + {t('or')}{' '} + <a + href="https://superset.apache.org/docs/creating-charts-dashboards/creating-your-first-dashboard/#registering-a-new-table" + rel="noopener noreferrer" + target="_blank" + data-test="add-chart-new-dataset-instructions" + > + {`${VIEW_INSTRUCTIONS_TEXT} `} + <i className="fa fa-external-link" /> + </a> + . + </span> + ) : ( + <span data-test="no-dataset-write"> + <a + href="https://superset.apache.org/docs/creating-charts-dashboards/creating-your-first-dashboard/#registering-a-new-table" + rel="noopener noreferrer" + target="_blank" + > + {`${VIEW_INSTRUCTIONS_TEXT} `} + <i className="fa fa-external-link" /> + </a> + . + </span> + ); + return ( <StyledContainer> <h3>{t('Create a new chart')}</h3> <Steps direction="vertical" size="small"> <Steps.Step - title={<FormLabel>{t('Choose a dataset')}</FormLabel>} + title={<StyledStepTitle>{t('Choose a dataset')}</StyledStepTitle>} status={this.state.datasource?.value ? 'finish' : 'process'} description={ - <div className="dataset"> - <Select + <StyledStepDescription className="dataset"> + <AsyncSelect autoFocus ariaLabel={t('Dataset')} name="select-datasource" @@ -296,30 +387,23 @@ export default class AddSliceContainer extends React.PureComponent< showSearch value={this.state.datasource} /> - <span> - {t( - 'Instructions to add a dataset are available in the Superset tutorial.', - )}{' '} - <a - href="https://superset.apache.org/docs/creating-charts-dashboards/creating-your-first-dashboard/#registering-a-new-table" - rel="noopener noreferrer" - target="_blank" - > - <i className="fa fa-external-link" /> - </a> - </span> - </div> + {datasetHelpText} + </StyledStepDescription> } /> <Steps.Step - title={<FormLabel>{t('Choose chart type')}</FormLabel>} - status={this.state.visType ? 'finish' : 'process'} + title={<StyledStepTitle>{t('Choose chart type')}</StyledStepTitle>} + status={this.state.vizType ? 'finish' : 'process'} description={ - <VizTypeGallery - className="viz-gallery" - onChange={this.changeVisType} - selectedViz={this.state.visType} - /> + <StyledStepDescription> + <VizTypeGallery + denyList={denyList} + className="viz-gallery" + onChange={this.changeVizType} + onDoubleClick={this.onVizTypeDoubleClick} + selectedViz={this.state.vizType} + /> + </StyledStepDescription> } /> </Steps> @@ -341,3 +425,5 @@ export default class AddSliceContainer extends React.PureComponent< ); } } + +export default withRouter(withToasts(ChartCreation)); diff --git a/superset-frontend/src/views/CRUD/chart/ChartCard.tsx b/superset-frontend/src/pages/ChartList/ChartCard.tsx similarity index 96% rename from superset-frontend/src/views/CRUD/chart/ChartCard.tsx rename to superset-frontend/src/pages/ChartList/ChartCard.tsx index 69812bd641559..df9b148567dd0 100644 --- a/superset-frontend/src/views/CRUD/chart/ChartCard.tsx +++ b/superset-frontend/src/pages/ChartList/ChartCard.tsx @@ -18,6 +18,7 @@ */ import React from 'react'; import { t, useTheme } from '@superset-ui/core'; +import { Link, useHistory } from 'react-router-dom'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import ConfirmStatusChange from 'src/components/ConfirmStatusChange'; import Icons from 'src/components/Icons'; @@ -29,7 +30,7 @@ import { AntdDropdown } from 'src/components'; import { Menu } from 'src/components/Menu'; import FaveStar from 'src/components/FaveStar'; import FacePile from 'src/components/FacePile'; -import { handleChartDelete, CardStyles } from '../utils'; +import { handleChartDelete, CardStyles } from 'src/views/CRUD/utils'; interface ChartCardProps { chart: Chart; @@ -64,6 +65,7 @@ export default function ChartCard({ userId, handleBulkChartExport, }: ChartCardProps) { + const history = useHistory(); const canEdit = hasPerm('can_write'); const canDelete = hasPerm('can_write'); const canExport = @@ -136,7 +138,7 @@ export default function ChartCard({ <CardStyles onClick={() => { if (!bulkSelectEnabled && chart.url) { - window.location.href = chart.url; + history.push(chart.url); } }} > @@ -158,6 +160,7 @@ export default function ChartCard({ coverRight={ <Label type="secondary">{chart.datasource_name_text}</Label> } + linkComponent={Link} actions={ <ListViewCard.Actions onClick={e => { diff --git a/superset-frontend/src/views/CRUD/chart/ChartList.test.jsx b/superset-frontend/src/pages/ChartList/ChartList.test.jsx similarity index 98% rename from superset-frontend/src/views/CRUD/chart/ChartList.test.jsx rename to superset-frontend/src/pages/ChartList/ChartList.test.jsx index fd9aee16ab06c..fc216e617dd95 100644 --- a/superset-frontend/src/views/CRUD/chart/ChartList.test.jsx +++ b/superset-frontend/src/pages/ChartList/ChartList.test.jsx @@ -30,7 +30,7 @@ import userEvent from '@testing-library/user-event'; import { QueryParamProvider } from 'use-query-params'; import { act } from 'react-dom/test-utils'; -import ChartList from 'src/views/CRUD/chart/ChartList'; +import ChartList from 'src/pages/ChartList'; import ConfirmStatusChange from 'src/components/ConfirmStatusChange'; import ListView from 'src/components/ListView'; import PropertiesModal from 'src/explore/components/PropertiesModal'; @@ -189,7 +189,7 @@ describe('RTL', () => { <QueryParamProvider> <ChartList {...mockedProps} user={mockUser} /> </QueryParamProvider>, - { useRedux: true }, + { useRedux: true, useRouter: true }, ); }); diff --git a/superset-frontend/src/views/CRUD/chart/ChartList.tsx b/superset-frontend/src/pages/ChartList/index.tsx similarity index 87% rename from superset-frontend/src/views/CRUD/chart/ChartList.tsx rename to superset-frontend/src/pages/ChartList/index.tsx index 1e2298538673d..38271e470db40 100644 --- a/superset-frontend/src/views/CRUD/chart/ChartList.tsx +++ b/superset-frontend/src/pages/ChartList/index.tsx @@ -17,7 +17,9 @@ * under the License. */ import { + ensureIsArray, getChartMetadataRegistry, + JsonResponse, styled, SupersetClient, t, @@ -41,6 +43,7 @@ import handleResourceExport from 'src/utils/export'; import ConfirmStatusChange from 'src/components/ConfirmStatusChange'; import SubMenu, { SubMenuProps } from 'src/views/components/SubMenu'; import FaveStar from 'src/components/FaveStar'; +import { Link, useHistory } from 'react-router-dom'; import ListView, { Filter, FilterOperator, @@ -48,19 +51,21 @@ import ListView, { ListViewProps, SelectOption, } from 'src/components/ListView'; +import CrossLinks from 'src/components/ListView/CrossLinks'; import Loading from 'src/components/Loading'; import { dangerouslyGetItemDoNotUse } from 'src/utils/localStorageHelpers'; import withToasts from 'src/components/MessageToasts/withToasts'; import PropertiesModal from 'src/explore/components/PropertiesModal'; import ImportModelsModal from 'src/components/ImportModal/index'; -import Chart from 'src/types/Chart'; +import Chart, { ChartLinkedDashboard } from 'src/types/Chart'; import { Tooltip } from 'src/components/Tooltip'; import Icons from 'src/components/Icons'; import { nativeFilterGate } from 'src/dashboard/components/nativeFilters/utils'; import setupPlugins from 'src/setup/setupPlugins'; import InfoTooltip from 'src/components/InfoTooltip'; import CertifiedBadge from 'src/components/CertifiedBadge'; -import { bootstrapData } from 'src/preamble'; +import { GenericLink } from 'src/components/GenericLink/GenericLink'; +import getBootstrapData from 'src/utils/getBootstrapData'; import Owner from 'src/types/Owner'; import ChartCard from './ChartCard'; @@ -147,6 +152,8 @@ const Actions = styled.div` color: ${({ theme }) => theme.colors.grayscale.base}; `; +const bootstrapData = getBootstrapData(); + function ChartList(props: ChartListProps) { const { addDangerToast, @@ -154,6 +161,8 @@ function ChartList(props: ChartListProps) { user: { userId }, } = props; + const history = useHistory(); + const { state: { loading, @@ -212,7 +221,7 @@ function ChartList(props: ChartListProps) { hasPerm('can_export') && isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT); const initialSort = [{ id: 'changed_on_delta_humanized', desc: true }]; const enableBroadUserAccess = - bootstrapData?.common?.conf?.ENABLE_BROAD_ACTIVITY_ACCESS; + bootstrapData.common.conf.ENABLE_BROAD_ACTIVITY_ACCESS; const handleBulkChartExport = (chartsToExport: Chart[]) => { const ids = chartsToExport.map(({ id }) => id); handleResourceExport('chart', ids, () => { @@ -242,6 +251,56 @@ function ChartList(props: ChartListProps) { ), ); } + const fetchDashboards = async ( + filterValue = '', + page: number, + pageSize: number, + ) => { + // add filters if filterValue + const filters = filterValue + ? { + filters: [ + { + col: 'dashboards', + opr: FilterOperator.relationManyMany, + value: filterValue, + }, + ], + } + : {}; + const queryParams = rison.encode({ + columns: ['dashboard_title', 'id'], + keys: ['none'], + order_column: 'dashboard_title', + order_direction: 'asc', + page, + page_size: pageSize, + ...filters, + }); + const response: void | JsonResponse = await SupersetClient.get({ + endpoint: !filterValue + ? `/api/v1/dashboard/?q=${queryParams}` + : `/api/v1/chart/?q=${queryParams}`, + }).catch(() => + addDangerToast(t('An error occurred while fetching dashboards')), + ); + const dashboards = response?.json?.result?.map( + ({ + dashboard_title: dashboardTitle, + id, + }: { + dashboard_title: string; + id: number; + }) => ({ + label: dashboardTitle, + value: id, + }), + ); + return { + data: uniqBy<SelectOption>(dashboards, 'value'), + totalCount: response?.json?.count, + }; + }; const columns = useMemo( () => [ @@ -277,7 +336,7 @@ function ChartList(props: ChartListProps) { }, }: any) => ( <FlexRowContainer> - <a href={url} data-test={`${sliceName}-list-chart-title`}> + <Link to={url} data-test={`${sliceName}-list-chart-title`}> {certifiedBy && ( <> <CertifiedBadge @@ -287,7 +346,7 @@ function ChartList(props: ChartListProps) { </> )} {sliceName} - </a> + </Link> {description && ( <InfoTooltip tooltip={description} viewBox="0 -1 24 24" /> )} @@ -314,12 +373,33 @@ function ChartList(props: ChartListProps) { datasource_url: dsUrl, }, }, - }: any) => <a href={dsUrl}>{dsNameTxt}</a>, + }: any) => <GenericLink to={dsUrl}>{dsNameTxt}</GenericLink>, Header: t('Dataset'), accessor: 'datasource_id', disableSortBy: true, size: 'xl', }, + { + Cell: ({ + row: { + original: { dashboards }, + }, + }: any) => ( + <CrossLinks + crossLinks={ensureIsArray(dashboards).map( + (d: ChartLinkedDashboard) => ({ + title: d.dashboard_title, + id: d.id, + }), + )} + /> + ), + Header: t('Dashboards added to'), + accessor: 'dashboards', + disableSortBy: true, + size: 'xxl', + hidden: true, + }, { Cell: ({ row: { @@ -473,6 +553,7 @@ function ChartList(props: ChartListProps) { const favoritesFilter: Filter = useMemo( () => ({ Header: t('Favorite'), + key: 'favorite', id: 'id', urlDisplay: 'favorite', input: 'select', @@ -490,6 +571,7 @@ function ChartList(props: ChartListProps) { () => [ { Header: t('Owner'), + key: 'owner', id: 'owners', input: 'select', operator: FilterOperator.relationManyMany, @@ -511,6 +593,7 @@ function ChartList(props: ChartListProps) { }, { Header: t('Created by'), + key: 'created_by', id: 'created_by', input: 'select', operator: FilterOperator.relationOneMany, @@ -532,6 +615,7 @@ function ChartList(props: ChartListProps) { }, { Header: t('Chart type'), + key: 'viz_type', id: 'viz_type', input: 'select', operator: FilterOperator.equals, @@ -557,6 +641,7 @@ function ChartList(props: ChartListProps) { }, { Header: t('Dataset'), + key: 'dataset', id: 'datasource_id', input: 'select', operator: FilterOperator.equals, @@ -564,9 +649,20 @@ function ChartList(props: ChartListProps) { fetchSelects: createFetchDatasets, paginate: true, }, + { + Header: t('Dashboards'), + key: 'dashboards', + id: 'dashboards', + input: 'select', + operator: FilterOperator.relationManyMany, + unfilteredLabel: t('All'), + fetchSelects: fetchDashboards, + paginate: true, + }, ...(userId ? [favoritesFilter] : []), { Header: t('Certified'), + key: 'certified', id: 'id', urlDisplay: 'certified', input: 'select', @@ -579,6 +675,7 @@ function ChartList(props: ChartListProps) { }, { Header: t('Search'), + key: 'search', id: 'slice_name', input: 'search', operator: FilterOperator.chartAllText, @@ -658,7 +755,7 @@ function ChartList(props: ChartListProps) { ), buttonStyle: 'primary', onClick: () => { - window.location.assign('/chart/add'); + history.push('/chart/add'); }, }); @@ -678,6 +775,7 @@ function ChartList(props: ChartListProps) { }); } } + return ( <> <SubMenu name={t('Charts')} buttons={subMenuButtons} /> diff --git a/superset-frontend/src/preamble.ts b/superset-frontend/src/preamble.ts index c088b10737aae..4d8e8ed0e7365 100644 --- a/superset-frontend/src/preamble.ts +++ b/superset-frontend/src/preamble.ts @@ -25,45 +25,35 @@ import { merge } from 'lodash'; import setupClient from './setup/setupClient'; import setupColors from './setup/setupColors'; import setupFormatters from './setup/setupFormatters'; -import setupDashboardComponents from './setup/setupDasboardComponents'; -import { BootstrapUser, User } from './types/bootstrapTypes'; +import setupDashboardComponents from './setup/setupDashboardComponents'; +import { User } from './types/bootstrapTypes'; +import { initFeatureFlags } from './featureFlags'; +import getBootstrapData from './utils/getBootstrapData'; if (process.env.WEBPACK_MODE === 'development') { setHotLoaderConfig({ logLevel: 'debug', trackTailUpdates: false }); } // eslint-disable-next-line import/no-mutable-exports -export let bootstrapData: { - user?: BootstrapUser; - common?: any; - config?: any; - embedded?: { - dashboard_id: string; - }; -} = {}; +export const bootstrapData = getBootstrapData(); + // Configure translation if (typeof window !== 'undefined') { - const root = document.getElementById('app'); - bootstrapData = root - ? JSON.parse(root.getAttribute('data-bootstrap') || '{}') - : {}; - if (bootstrapData.common && bootstrapData.common.language_pack) { - const languagePack = bootstrapData.common.language_pack; - configure({ languagePack }); - moment.locale(bootstrapData.common.locale); - } else { - configure(); - } + configure({ languagePack: bootstrapData.common.language_pack }); + moment.locale(bootstrapData.common.locale); } else { configure(); } +// Configure feature flags +initFeatureFlags(bootstrapData.common.feature_flags); + // Setup SupersetClient setupClient(); setupColors( - bootstrapData?.common?.extra_categorical_color_schemes, - bootstrapData?.common?.extra_sequential_color_schemes, + bootstrapData.common.extra_categorical_color_schemes, + bootstrapData.common.extra_sequential_color_schemes, ); // Setup number formatters @@ -73,7 +63,7 @@ setupDashboardComponents(); export const theme = merge( supersetTheme, - bootstrapData?.common?.theme_overrides ?? {}, + bootstrapData.common.theme_overrides ?? {}, ); const getMe = makeApi<void, User>({ diff --git a/superset-frontend/src/profile/App.tsx b/superset-frontend/src/profile/App.tsx index 1f2cd144afcc1..ed331ce73725c 100644 --- a/superset-frontend/src/profile/App.tsx +++ b/superset-frontend/src/profile/App.tsx @@ -27,15 +27,15 @@ import App from 'src/profile/components/App'; import messageToastReducer from 'src/components/MessageToasts/reducers'; import { initEnhancer } from 'src/reduxUtils'; import setupApp from 'src/setup/setupApp'; +import setupExtensions from 'src/setup/setupExtensions'; import { theme } from 'src/preamble'; import ToastContainer from 'src/components/MessageToasts/ToastContainer'; +import getBootstrapData from 'src/utils/getBootstrapData'; setupApp(); +setupExtensions(); -const profileViewContainer = document.getElementById('app'); -const bootstrap = JSON.parse( - profileViewContainer?.getAttribute('data-bootstrap') ?? '{}', -); +const bootstrapData = getBootstrapData(); const store = createStore( combineReducers({ @@ -49,7 +49,7 @@ const Application = () => ( <Provider store={store}> <ThemeProvider theme={theme}> <GlobalStyles /> - <App user={bootstrap.user} /> + <App user={bootstrapData.user} /> <ToastContainer /> </ThemeProvider> </Provider> diff --git a/superset-frontend/src/profile/components/App.tsx b/superset-frontend/src/profile/components/App.tsx index e2c910abd2f5c..08130176fe61a 100644 --- a/superset-frontend/src/profile/components/App.tsx +++ b/superset-frontend/src/profile/components/App.tsx @@ -20,7 +20,7 @@ import React from 'react'; import { t, styled } from '@superset-ui/core'; import { Row, Col } from 'src/components'; import Tabs from 'src/components/Tabs'; -import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; +import { BootstrapUser } from 'src/types/bootstrapTypes'; import Favorites from './Favorites'; import UserInfo from './UserInfo'; import Security from './Security'; @@ -28,7 +28,7 @@ import RecentActivity from './RecentActivity'; import CreatedContent from './CreatedContent'; interface AppProps { - user: UserWithPermissionsAndRoles; + user: BootstrapUser; } const StyledTabPane = styled(Tabs.TabPane)` diff --git a/superset-frontend/src/profile/components/CreatedContent.tsx b/superset-frontend/src/profile/components/CreatedContent.tsx index 61dfb418f09c3..a972ea5db90f5 100644 --- a/superset-frontend/src/profile/components/CreatedContent.tsx +++ b/superset-frontend/src/profile/components/CreatedContent.tsx @@ -18,30 +18,45 @@ */ import rison from 'rison'; import React from 'react'; -import moment from 'moment'; import { t } from '@superset-ui/core'; -import TableLoader from '../../components/TableLoader'; -import { Slice } from '../types'; -import { User, DashboardResponse } from '../../types/bootstrapTypes'; +import TableLoader from 'src/components/TableLoader'; +import { + BootstrapUser, + ChartResponse, + DashboardResponse, +} from 'src/types/bootstrapTypes'; interface CreatedContentProps { - user: User; + user: BootstrapUser; } class CreatedContent extends React.PureComponent<CreatedContentProps> { renderSliceTable() { - const mutator = (data: Slice[]) => - data.map(slice => ({ - slice: <a href={slice.url}>{slice.title}</a>, - created: moment.utc(slice.dttm).fromNow(), - _created: slice.dttm, + const search = [ + { col: 'created_by', opr: 'chart_created_by_me', value: 'me' }, + ]; + const query = rison.encode({ + keys: ['none'], + columns: ['created_on_delta_humanized', 'slice_name', 'url'], + filters: search, + order_column: 'changed_on_delta_humanized', + order_direction: 'desc', + page: 0, + page_size: 100, + }); + + const mutator = (data: ChartResponse) => + data.result.map(chart => ({ + chart: <a href={chart.url}>{chart.slice_name}</a>, + created: chart.created_on_delta_humanized, + _created: chart.created_on_delta_humanized, })); return ( <TableLoader - dataEndpoint={`/superset/created_slices/${this.props.user.userId}/`} + dataEndpoint={`/api/v1/chart/?q=${query}`} className="table-condensed" - columns={['slice', 'created']} + columns={['chart', 'created']} mutator={mutator} noDataText={t('No charts')} sortable @@ -50,7 +65,9 @@ class CreatedContent extends React.PureComponent<CreatedContentProps> { } renderDashboardTable() { - const search = [{ col: 'created_by', opr: 'created_by_me', value: 'me' }]; + const search = [ + { col: 'created_by', opr: 'dashboard_created_by_me', value: 'me' }, + ]; const query = rison.encode({ keys: ['none'], columns: ['created_on_delta_humanized', 'dashboard_title', 'url'], diff --git a/superset-frontend/src/profile/components/Favorites.tsx b/superset-frontend/src/profile/components/Favorites.tsx index 1a7daa750f063..1e28cd989aaba 100644 --- a/superset-frontend/src/profile/components/Favorites.tsx +++ b/superset-frontend/src/profile/components/Favorites.tsx @@ -20,13 +20,12 @@ import React from 'react'; import rison from 'rison'; import moment from 'moment'; import { t } from '@superset-ui/core'; - +import { DashboardResponse, BootstrapUser } from 'src/types/bootstrapTypes'; import TableLoader from '../../components/TableLoader'; import { Slice } from '../types'; -import { User, DashboardResponse } from '../../types/bootstrapTypes'; interface FavoritesProps { - user: User; + user: BootstrapUser; } export default class Favorites extends React.PureComponent<FavoritesProps> { @@ -40,7 +39,7 @@ export default class Favorites extends React.PureComponent<FavoritesProps> { })); return ( <TableLoader - dataEndpoint={`/superset/fave_slices/${this.props.user.userId}/`} + dataEndpoint={`/superset/fave_slices/${this.props.user?.userId}/`} className="table-condensed" columns={['slice', 'creator', 'favorited']} mutator={mutator} diff --git a/superset-frontend/src/profile/components/RecentActivity.tsx b/superset-frontend/src/profile/components/RecentActivity.tsx index d1bb83866b5c3..975d8cb3ddf3d 100644 --- a/superset-frontend/src/profile/components/RecentActivity.tsx +++ b/superset-frontend/src/profile/components/RecentActivity.tsx @@ -18,19 +18,21 @@ */ import React from 'react'; import moment from 'moment'; +import { t } from '@superset-ui/core'; +import rison from 'rison'; import TableLoader from '../../components/TableLoader'; -import { Activity } from '../types'; -import { User } from '../../types/bootstrapTypes'; +import { ActivityResult } from '../types'; +import { BootstrapUser } from '../../types/bootstrapTypes'; interface RecentActivityProps { - user: User; + user: BootstrapUser; } export default function RecentActivity({ user }: RecentActivityProps) { const rowLimit = 50; - const mutator = function (data: Activity[]) { - return data + const mutator = function (data: ActivityResult) { + return data.result .filter(row => row.action === 'dashboard' || row.action === 'explore') .map(row => ({ name: <a href={row.item_url}>{row.item_title}</a>, @@ -39,13 +41,15 @@ export default function RecentActivity({ user }: RecentActivityProps) { _time: row.time, })); }; + const params = rison.encode({ page_size: rowLimit }); return ( <div> <TableLoader className="table-condensed" mutator={mutator} sortable - dataEndpoint={`/superset/recent_activity/${user.userId}/?limit=${rowLimit}`} + dataEndpoint={`/api/v1/log/recent_activity/${user?.userId}/?q=${params}`} + noDataText={t('No Data')} /> </div> ); diff --git a/superset-frontend/src/profile/components/Security.tsx b/superset-frontend/src/profile/components/Security.tsx index 078fc42e4c74b..a102e55992878 100644 --- a/superset-frontend/src/profile/components/Security.tsx +++ b/superset-frontend/src/profile/components/Security.tsx @@ -21,10 +21,10 @@ import Badge from 'src/components/Badge'; import { t } from '@superset-ui/core'; import Label from 'src/components/Label'; -import { UserWithPermissionsAndRoles } from '../../types/bootstrapTypes'; +import { BootstrapUser } from 'src/types/bootstrapTypes'; interface SecurityProps { - user: UserWithPermissionsAndRoles; + user: BootstrapUser; } export default function Security({ user }: SecurityProps) { @@ -32,15 +32,16 @@ export default function Security({ user }: SecurityProps) { <div> <div className="roles"> <h4> - {t('Roles')} <Badge count={Object.keys(user.roles).length} showZero /> + {t('Roles')}{' '} + <Badge count={Object.keys(user?.roles || {}).length} showZero /> </h4> - {Object.keys(user.roles).map(role => ( + {Object.keys(user?.roles || {}).map(role => ( <Label key={role}>{role}</Label> ))} <hr /> </div> <div className="databases"> - {user.permissions.database_access && ( + {user?.permissions.database_access && ( <div> <h4> {t('Databases')}{' '} @@ -54,7 +55,7 @@ export default function Security({ user }: SecurityProps) { )} </div> <div className="datasources"> - {user.permissions.datasource_access && ( + {user?.permissions.datasource_access && ( <div> <h4> {t('Datasets')}{' '} diff --git a/superset-frontend/src/profile/components/UserInfo.tsx b/superset-frontend/src/profile/components/UserInfo.tsx index 887b4ec50c136..b79f1fb97cb68 100644 --- a/superset-frontend/src/profile/components/UserInfo.tsx +++ b/superset-frontend/src/profile/components/UserInfo.tsx @@ -20,10 +20,10 @@ import React from 'react'; import Gravatar from 'react-gravatar'; import moment from 'moment'; import { t, styled } from '@superset-ui/core'; -import { UserWithPermissionsAndRoles } from '../../types/bootstrapTypes'; +import { BootstrapUser } from 'src/types/bootstrapTypes'; interface UserInfoProps { - user: UserWithPermissionsAndRoles; + user: BootstrapUser; } const StyledContainer = styled.div` @@ -37,7 +37,7 @@ export default function UserInfo({ user }: UserInfoProps) { <StyledContainer> <a href="https://en.gravatar.com/"> <Gravatar - email={user.email} + email={user?.email} width="100%" height="" size={220} @@ -51,29 +51,30 @@ export default function UserInfo({ user }: UserInfoProps) { <div className="header"> <h3> <strong> - {user.firstName} {user.lastName} + {user?.firstName} {user?.lastName} </strong> </h3> <h4 className="username"> - <i className="fa fa-user-o" /> {user.username} + <i className="fa fa-user-o" /> {user?.username} </h4> </div> <hr /> <p> <i className="fa fa-clock-o" data-test="clock-icon-test" />{' '} - {t('joined')} {moment(user.createdOn, 'YYYYMMDD').fromNow()} + {t('joined')} {moment(user?.createdOn, 'YYYYMMDD').fromNow()} </p> <p className="email"> - <i className="fa fa-envelope-o" /> {user.email} + <i className="fa fa-envelope-o" /> {user?.email} </p> <p className="roles"> - <i className="fa fa-lock" /> {Object.keys(user.roles).join(', ')} + <i className="fa fa-lock" />{' '} + {Object.keys(user?.roles || {}).join(', ')} </p> <p> <i className="fa fa-key" />   - <span className="text-muted">{t('id:')}</span>  - <span className="user-id">{user.userId}</span> + <span className="text-muted">{t('id')}:</span>  + <span className="user-id">{user?.userId}</span> </p> </div> </StyledContainer> diff --git a/superset-frontend/src/profile/types.ts b/superset-frontend/src/profile/types.ts index a2433e0827eb9..29ca01605fb2b 100644 --- a/superset-frontend/src/profile/types.ts +++ b/superset-frontend/src/profile/types.ts @@ -32,3 +32,7 @@ export type Activity = { item_url: string; time: number; }; + +export type ActivityResult = { + result: Activity[]; +}; diff --git a/superset-frontend/src/reduxUtils.ts b/superset-frontend/src/reduxUtils.ts index 245abc23e540f..8e744b48dc140 100644 --- a/superset-frontend/src/reduxUtils.ts +++ b/superset-frontend/src/reduxUtils.ts @@ -19,7 +19,15 @@ import shortid from 'shortid'; import { compose } from 'redux'; import persistState, { StorageAdapter } from 'redux-localstorage'; -import { isEqual, omitBy, isUndefined, isNull } from 'lodash'; +import { + isEqual, + omitBy, + omit, + isUndefined, + isNull, + isEqualWith, +} from 'lodash'; +import { ensureIsArray } from '@superset-ui/core'; export function addToObject( state: Record<string, any>, @@ -136,10 +144,11 @@ export function extendArr( export function initEnhancer( persist = true, persistConfig: { paths?: StorageAdapter<unknown>; config?: string } = {}, + disableDebugger = false, ) { const { paths, config } = persistConfig; const composeEnhancers = - process.env.WEBPACK_MODE === 'development' + process.env.WEBPACK_MODE === 'development' && disableDebugger !== true ? /* eslint-disable-next-line no-underscore-dangle, dot-notation */ window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] ? /* eslint-disable-next-line no-underscore-dangle, dot-notation */ @@ -180,7 +189,8 @@ export function areObjectsEqual( opts: { ignoreUndefined?: boolean; ignoreNull?: boolean; - } = { ignoreUndefined: false, ignoreNull: false }, + ignoreFields?: string[]; + } = { ignoreUndefined: false, ignoreNull: false, ignoreFields: [] }, ) { let comp1 = obj1; let comp2 = obj2; @@ -192,5 +202,14 @@ export function areObjectsEqual( comp1 = omitBy(comp1, isNull); comp2 = omitBy(comp2, isNull); } + if (opts.ignoreFields?.length) { + const ignoreFields = ensureIsArray(opts.ignoreFields); + return isEqualWith(comp1, comp2, (val1, val2) => + isEqual( + ensureIsArray(val1).map(value => omit(value, ignoreFields)), + ensureIsArray(val2).map(value => omit(value, ignoreFields)), + ), + ); + } return isEqual(comp1, comp2); } diff --git a/superset-frontend/src/reports/actions/reports.js b/superset-frontend/src/reports/actions/reports.js index 6fbd8ca4ec0f2..96a435ec5da3a 100644 --- a/superset-frontend/src/reports/actions/reports.js +++ b/superset-frontend/src/reports/actions/reports.js @@ -23,6 +23,7 @@ import { addDangerToast, addSuccessToast, } from 'src/components/MessageToasts/actions'; +import { isEmpty } from 'lodash'; export const SET_REPORT = 'SET_REPORT'; export function setReport(report, resourceId, creationMethod, filterField) { @@ -76,7 +77,7 @@ export function fetchUISpecificReport({ const structureFetchAction = (dispatch, getState) => { const state = getState(); const { user, dashboardInfo, charts, explore } = state; - if (dashboardInfo) { + if (!isEmpty(dashboardInfo)) { dispatch( fetchUISpecificReport({ userId: user.userId, @@ -89,7 +90,7 @@ const structureFetchAction = (dispatch, getState) => { const [chartArr] = Object.keys(charts); dispatch( fetchUISpecificReport({ - userId: explore.user.userId, + userId: explore.user?.userId || user?.userId, filterField: 'chart_id', creationMethod: 'charts', resourceId: charts[chartArr].id, diff --git a/superset-frontend/src/setup/setupApp.ts b/superset-frontend/src/setup/setupApp.ts index ba3b9ac96143c..227aad3a68632 100644 --- a/superset-frontend/src/setup/setupApp.ts +++ b/superset-frontend/src/setup/setupApp.ts @@ -52,7 +52,7 @@ function toggleCheckbox(apiUrlPrefix: string, selector: string) { .then(() => undefined) .catch(response => getClientErrorObject(response).then(parsedResp => { - if (parsedResp && parsedResp.message) { + if (parsedResp?.message) { showApiMessage(parsedResp); } }), diff --git a/superset-frontend/src/setup/setupClient.ts b/superset-frontend/src/setup/setupClient.ts index 8802ae47227d1..80ce6b54bb8c0 100644 --- a/superset-frontend/src/setup/setupClient.ts +++ b/superset-frontend/src/setup/setupClient.ts @@ -30,7 +30,7 @@ function getDefaultConfiguration(): ClientConfig { protocol: ['http:', 'https:'].includes(window?.location?.protocol) ? (window?.location?.protocol as 'http:' | 'https:') : undefined, - host: (window.location && window.location.host) || '', + host: window.location?.host || '', csrfToken: csrfToken || cookieCSRFToken, }; } diff --git a/superset-frontend/src/setup/setupDasboardComponents.ts b/superset-frontend/src/setup/setupDashboardComponents.ts similarity index 100% rename from superset-frontend/src/setup/setupDasboardComponents.ts rename to superset-frontend/src/setup/setupDashboardComponents.ts diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alert_report.helper.ts b/superset-frontend/src/setup/setupExtensions.ts similarity index 88% rename from superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alert_report.helper.ts rename to superset-frontend/src/setup/setupExtensions.ts index dcf8b2b4a2931..88a9cf1059296 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alert_report.helper.ts +++ b/superset-frontend/src/setup/setupExtensions.ts @@ -16,5 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -export const ALERT_LIST = '/alert/list/'; -export const REPORT_LIST = '/report/list/'; + +// For individual deployments to add custom overrides +export default function setupExtensions() {} diff --git a/superset-frontend/src/showSavedQuery/index.jsx b/superset-frontend/src/showSavedQuery/index.jsx index 6b8adcd60d7a9..10c09703f7206 100644 --- a/superset-frontend/src/showSavedQuery/index.jsx +++ b/superset-frontend/src/showSavedQuery/index.jsx @@ -21,11 +21,10 @@ import ReactDom from 'react-dom'; import Form from 'react-jsonschema-form'; import { interpolate } from 'src/showSavedQuery/utils'; import { styled } from '@superset-ui/core'; +import getBootstrapData from 'src/utils/getBootstrapData'; const scheduleInfoContainer = document.getElementById('schedule-info'); -const bootstrapData = JSON.parse( - scheduleInfoContainer.getAttribute('data-bootstrap'), -); +const bootstrapData = getBootstrapData(); const config = bootstrapData.common.conf.SCHEDULED_QUERIES; const { query } = bootstrapData.common; const scheduleInfo = query.extra_json.schedule_info; diff --git a/superset-frontend/src/types/Chart.ts b/superset-frontend/src/types/Chart.ts index cf4a64b6baa66..76ec04f60b7a9 100644 --- a/superset-frontend/src/types/Chart.ts +++ b/superset-frontend/src/types/Chart.ts @@ -24,6 +24,11 @@ import { QueryFormData } from '@superset-ui/core'; import Owner from './Owner'; +export type ChartLinkedDashboard = { + id: number; + dashboard_title: string; +}; + export interface Chart { id: number; url: string; @@ -39,11 +44,20 @@ export interface Chart { cache_timeout: number | null; thumbnail_url?: string; owners?: Owner[]; + last_saved_at?: string; + last_saved_by?: { + id: number; + first_name: string; + last_name: string; + }; datasource_name_text?: string; form_data: { viz_type: string; }; is_managed_externally: boolean; + + // TODO: Update API spec to describe `dashboards` key + dashboards: ChartLinkedDashboard[]; } export type Slice = { @@ -57,6 +71,7 @@ export type Slice = { form_data?: QueryFormData; query_context?: object; is_managed_externally: boolean; + owners?: number[]; }; export default Chart; diff --git a/superset-frontend/cypress-base/cypress/integration/database/helper.ts b/superset-frontend/src/types/ChartSource.ts similarity index 91% rename from superset-frontend/cypress-base/cypress/integration/database/helper.ts rename to superset-frontend/src/types/ChartSource.ts index a339865e1fe6c..6abc7d754c644 100644 --- a/superset-frontend/cypress-base/cypress/integration/database/helper.ts +++ b/superset-frontend/src/types/ChartSource.ts @@ -16,4 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -export const DATABASE_LIST = '/databaseview/list'; + +export enum ChartSource { + Explore = 'explore', + Dashboard = 'dashboard', +} diff --git a/superset-frontend/src/types/Dashboard.ts b/superset-frontend/src/types/Dashboard.ts index 96a92d567f124..faecc0bc4acf7 100644 --- a/superset-frontend/src/types/Dashboard.ts +++ b/superset-frontend/src/types/Dashboard.ts @@ -36,5 +36,3 @@ export interface Dashboard { owners: Owner[]; roles: Role[]; } - -export default Dashboard; diff --git a/superset-frontend/src/types/DashboardContextForExplore.ts b/superset-frontend/src/types/DashboardContextForExplore.ts new file mode 100644 index 0000000000000..b69ec3ca7f0ea --- /dev/null +++ b/superset-frontend/src/types/DashboardContextForExplore.ts @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + DataMaskStateWithId, + DataRecordValue, + PartialFilters, +} from '@superset-ui/core'; +import { ChartConfiguration } from 'src/dashboard/reducers/types'; + +export interface DashboardContextForExplore { + labelColors: Record<string, string>; + sharedLabelColors: Record<string, string>; + colorScheme: string; + chartConfiguration: ChartConfiguration; + nativeFilters: PartialFilters; + dataMask: DataMaskStateWithId; + dashboardId: number; + filterBoxFilters: + | { + [key: string]: { + scope: number[]; + values: DataRecordValue[]; + }; + } + | {}; + isRedundant?: boolean; +} diff --git a/superset-frontend/src/types/Database.ts b/superset-frontend/src/types/Database.ts index 02c9347215d4d..c4491dbb9943d 100644 --- a/superset-frontend/src/types/Database.ts +++ b/superset-frontend/src/types/Database.ts @@ -21,9 +21,10 @@ export default interface Database { id: number; allow_run_async: boolean; database_name: string; - encrypted_extra: string; + masked_encrypted_extra: string; extra: string; impersonate_user: boolean; server_cert: string; sqlalchemy_uri: string; + catalog: object; } diff --git a/superset-frontend/src/types/bootstrapTypes.ts b/superset-frontend/src/types/bootstrapTypes.ts index a6c1a32440b10..f51ec32610871 100644 --- a/superset-frontend/src/types/bootstrapTypes.ts +++ b/superset-frontend/src/types/bootstrapTypes.ts @@ -1,5 +1,14 @@ -import { JsonObject, Locale } from '@superset-ui/core'; +import { + ColorSchemeConfig, + FeatureFlagMap, + JsonObject, + LanguagePack, + Locale, + SequentialSchemeConfig, +} from '@superset-ui/core'; import { isPlainObject } from 'lodash'; +import { FlashMessage } from '../components/FlashProvider'; +import { Languages } from '../views/components/LanguagePicker'; /** * Licensed to the Apache Software Foundation (ASF) under one @@ -64,11 +73,93 @@ export type DashboardResponse = { result: DashboardData[]; }; +export type ChartData = { + slice_name: string; + created_on_delta_humanized?: string; + url: string; +}; + +export type ChartResponse = { + result: ChartData[]; +}; + +export interface BrandProps { + path: string; + icon: string; + alt: string; + tooltip: string; + text: string; +} + +export interface NavBarProps { + show_watermark: boolean; + bug_report_url?: string; + bug_report_text?: string; + bug_report_icon?: string; + version_string?: string; + version_sha?: string; + build_number?: string; + documentation_url?: string; + documentation_text?: string; + documentation_icon?: string; + languages: Languages; + show_language_picker: boolean; + user_is_anonymous: boolean; + user_info_url: string; + user_login_url: string; + user_logout_url: string; + user_profile_url: string | null; + locale: string; +} + +export interface MenuObjectChildProps { + label: string; + name?: string; + icon?: string; + index?: number; + url?: string; + isFrontendRoute?: boolean; + perm?: string | boolean; + view?: string; + disable?: boolean; +} + +export interface MenuObjectProps extends MenuObjectChildProps { + childs?: (MenuObjectChildProps | string)[]; + isHeader?: boolean; +} + +export interface MenuData { + menu: MenuObjectProps[]; + brand: BrandProps; + navbar_right: NavBarProps; + settings: MenuObjectProps[]; + environment_tag: { + text: string; + color: string; + }; +} export interface CommonBootstrapData { - flash_messages: string[][]; + flash_messages: FlashMessage[]; conf: JsonObject; locale: Locale; - feature_flags: Record<string, boolean>; + feature_flags: FeatureFlagMap; + language_pack: LanguagePack; + extra_categorical_color_schemes: ColorSchemeConfig[]; + extra_sequential_color_schemes: SequentialSchemeConfig[]; + theme_overrides: JsonObject; + menu_data: MenuData; + datahub_url: String; + advanced_data_types: Record<string, any>[]; +} + +export interface BootstrapData { + user?: BootstrapUser; + common: CommonBootstrapData; + config?: any; + embedded?: { + dashboard_id: string; + }; } export function isUser(user: any): user is User { diff --git a/superset-frontend/src/types/files.d.ts b/superset-frontend/src/types/files.d.ts index c694d13cfbf22..c4f304b57f636 100644 --- a/superset-frontend/src/types/files.d.ts +++ b/superset-frontend/src/types/files.d.ts @@ -18,3 +18,4 @@ */ declare module '*.svg'; +declare module '*.gif'; diff --git a/superset-frontend/src/utils/DebouncedMessageQueue.js b/superset-frontend/src/utils/DebouncedMessageQueue.js index 031963dda01ea..6fd6c5b778049 100644 --- a/superset-frontend/src/utils/DebouncedMessageQueue.js +++ b/superset-frontend/src/utils/DebouncedMessageQueue.js @@ -26,9 +26,9 @@ class DebouncedMessageQueue { }) { this.queue = []; this.sizeThreshold = sizeThreshold; - this.delayThrehold = delayThreshold; + this.delayThreshold = delayThreshold; - this.trigger = debounce(this.trigger.bind(this), this.delayThrehold); + this.trigger = debounce(this.trigger.bind(this), this.delayThreshold); this.callback = callback; } diff --git a/superset-frontend/src/utils/common.js b/superset-frontend/src/utils/common.js index 400a7d05e0109..4bc702d447584 100644 --- a/superset-frontend/src/utils/common.js +++ b/superset-frontend/src/utils/common.js @@ -36,17 +36,6 @@ export const SHORT_TIME = 'h:m a'; const DATETIME_FORMATTER = getTimeFormatter(TimeFormats.DATABASE_DATETIME); -export function getParamFromQuery(query, param) { - const vars = query.split('&'); - for (let i = 0; i < vars.length; i += 1) { - const pair = vars[i].split('='); - if (decodeURIComponent(pair[0]) === param) { - return decodeURIComponent(pair[1]); - } - } - return null; -} - export function storeQuery(query) { return SupersetClient.post({ endpoint: '/kv/store/', @@ -66,10 +55,10 @@ export function optionLabel(opt) { return EMPTY_STRING; } if (opt === true) { - return '<true>'; + return TRUE_STRING; } if (opt === false) { - return '<false>'; + return FALSE_STRING; } if (typeof opt !== 'string' && opt.toString) { return opt.toString(); @@ -150,5 +139,3 @@ export const isSafari = () => { return userAgent && /^((?!chrome|android).)*safari/i.test(userAgent); }; - -export const isNullish = value => value === null || value === undefined; diff --git a/superset-frontend/src/utils/common.test.jsx b/superset-frontend/src/utils/common.test.jsx index 571e493addbff..59cba6e7b2d0c 100644 --- a/superset-frontend/src/utils/common.test.jsx +++ b/superset-frontend/src/utils/common.test.jsx @@ -21,6 +21,8 @@ import { optionFromValue, prepareCopyToClipboardTabularData, NULL_STRING, + TRUE_STRING, + FALSE_STRING, } from 'src/utils/common'; describe('utils/common', () => { @@ -28,9 +30,12 @@ describe('utils/common', () => { it('converts values as expected', () => { expect(optionFromValue(false)).toEqual({ value: false, - label: '<false>', + label: FALSE_STRING, + }); + expect(optionFromValue(true)).toEqual({ + value: true, + label: TRUE_STRING, }); - expect(optionFromValue(true)).toEqual({ value: true, label: '<true>' }); expect(optionFromValue(null)).toEqual({ value: NULL_STRING, label: NULL_STRING, diff --git a/superset-frontend/src/utils/datasourceUtils.js b/superset-frontend/src/utils/datasourceUtils.js new file mode 100644 index 0000000000000..1a5924b3e6c49 --- /dev/null +++ b/superset-frontend/src/utils/datasourceUtils.js @@ -0,0 +1,25 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +export const getDatasourceAsSaveableDataset = source => ({ + columns: source.columns, + name: source?.datasource_name || source?.name || 'Untitled', + dbId: source?.database?.id || source?.dbId, + sql: source?.sql || '', + schema: source?.schema, +}); diff --git a/superset-frontend/src/utils/downloadAsImage.ts b/superset-frontend/src/utils/downloadAsImage.ts index 145fb86508acf..de7454364637b 100644 --- a/superset-frontend/src/utils/downloadAsImage.ts +++ b/superset-frontend/src/utils/downloadAsImage.ts @@ -19,15 +19,9 @@ import { SyntheticEvent } from 'react'; import domToImage from 'dom-to-image-more'; import kebabCase from 'lodash/kebabCase'; -import { t } from '@superset-ui/core'; +import { t, supersetTheme } from '@superset-ui/core'; import { addWarningToast } from 'src/components/MessageToasts/actions'; -/** - * @remark - * same as https://github.com/apache/superset/blob/c53bc4ddf9808a8bb6916bbe3cb31935d33a2420/superset-frontend/src/assets/stylesheets/less/variables.less#L34 - */ -const GRAY_BACKGROUND_COLOR = '#F5F5F5'; - /** * generate a consistent file stem from a description and date * @@ -77,7 +71,7 @@ export default function downloadAsImage( return domToImage .toJpeg(elementToPrint, { quality: 0.95, - bgcolor: GRAY_BACKGROUND_COLOR, + bgcolor: supersetTheme.colors.grayscale.light4, filter, }) .then(dataUrl => { diff --git a/superset-frontend/src/utils/findPermission.test.ts b/superset-frontend/src/utils/findPermission.test.ts new file mode 100644 index 0000000000000..4dadb3a4ed28f --- /dev/null +++ b/superset-frontend/src/utils/findPermission.test.ts @@ -0,0 +1,63 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { findPermission } from './findPermission'; + +test('findPermission for single role', () => { + expect(findPermission('abc', 'def', { role: [['abc', 'def']] })).toEqual( + true, + ); + + expect(findPermission('abc', 'def', { role: [['abc', 'de']] })).toEqual( + false, + ); + + expect(findPermission('abc', 'def', { role: [] })).toEqual(false); +}); + +test('findPermission for multiple roles', () => { + expect( + findPermission('abc', 'def', { + role1: [ + ['ccc', 'aaa'], + ['abc', 'def'], + ], + role2: [['abc', 'def']], + }), + ).toEqual(true); + + expect( + findPermission('abc', 'def', { + role1: [['abc', 'def']], + role2: [['abc', 'dd']], + }), + ).toEqual(true); + + expect( + findPermission('abc', 'def', { + role1: [['ccc', 'aaa']], + role2: [['aaa', 'ddd']], + }), + ).toEqual(false); + + expect(findPermission('abc', 'def', { role1: [], role2: [] })).toEqual(false); +}); + +test('handles nonexistent roles', () => { + expect(findPermission('abc', 'def', null)).toEqual(false); +}); diff --git a/superset-frontend/src/utils/findPermission.ts b/superset-frontend/src/utils/findPermission.ts new file mode 100644 index 0000000000000..69c45be5a0754 --- /dev/null +++ b/superset-frontend/src/utils/findPermission.ts @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import memoizeOne from 'memoize-one'; +import { UserRoles } from 'src/types/bootstrapTypes'; + +export const findPermission = memoizeOne( + (perm: string, view: string, roles?: UserRoles | null) => + !!roles && + Object.values(roles).some(permissions => + permissions.some(([perm_, view_]) => perm_ === perm && view_ === view), + ), +); diff --git a/superset-frontend/src/utils/getBootstrapData.ts b/superset-frontend/src/utils/getBootstrapData.ts new file mode 100644 index 0000000000000..e426498e5738f --- /dev/null +++ b/superset-frontend/src/utils/getBootstrapData.ts @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { BootstrapData } from 'src/types/bootstrapTypes'; +import { DEFAULT_BOOTSTRAP_DATA } from 'src/constants'; + +export default function getBootstrapData(): BootstrapData { + const appContainer = document.getElementById('app'); + const dataBootstrap = appContainer?.getAttribute('data-bootstrap'); + return dataBootstrap ? JSON.parse(dataBootstrap) : DEFAULT_BOOTSTRAP_DATA; +} diff --git a/superset-frontend/src/utils/getChartRequiredFieldsMissingMessage.ts b/superset-frontend/src/utils/getChartRequiredFieldsMissingMessage.ts index ac11e8503dc2f..865452ade8251 100644 --- a/superset-frontend/src/utils/getChartRequiredFieldsMissingMessage.ts +++ b/superset-frontend/src/utils/getChartRequiredFieldsMissingMessage.ts @@ -19,8 +19,11 @@ import { t } from '@superset-ui/core'; +const CREATE_CHART_TEXT = t('Create chart'); +const UPDATE_CHART_TEXT = t('Update chart'); + export const getChartRequiredFieldsMissingMessage = (isCreating: boolean) => t( 'Select values in highlighted field(s) in the control panel. Then run the query by clicking on the %s button.', - isCreating ? '"Create chart"' : '"Update chart"', + `"${isCreating ? CREATE_CHART_TEXT : UPDATE_CHART_TEXT}"`, ); diff --git a/superset-frontend/src/utils/getClientErrorObject.ts b/superset-frontend/src/utils/getClientErrorObject.ts index 3451528f025ca..a5f2871872b3e 100644 --- a/superset-frontend/src/utils/getClientErrorObject.ts +++ b/superset-frontend/src/utils/getClientErrorObject.ts @@ -41,6 +41,14 @@ interface TimeoutError { timeout: number; } +type ErrorType = + | SupersetClientResponse + | TimeoutError + | { response: Response } + | string; + +type ErrorTextSource = 'dashboard' | 'chart' | 'query' | 'dataset' | 'database'; + export function parseErrorJson(responseObject: JsonObject): ClientErrorObject { let error = { ...responseObject }; // Backwards compatibility for old error renderers with the new error object @@ -48,12 +56,17 @@ export function parseErrorJson(responseObject: JsonObject): ClientErrorObject { error.error = error.description = error.errors[0].message; error.link = error.errors[0]?.extra?.link; } - // Marshmallow field validation returns the error mssage in the format + // Marshmallow field validation returns the error message in the format // of { message: { field1: [msg1, msg2], field2: [msg], } } - if (error.message && typeof error.message === 'object' && !error.error) { - error.error = - Object.values(error.message as Record<string, string[]>)[0]?.[0] || - t('Invalid input'); + if (!error.error && error.message) { + if (typeof error.message === 'object') { + error.error = + Object.values(error.message as Record<string, string[]>)[0]?.[0] || + t('Invalid input'); + } + if (typeof error.message === 'string') { + error.error = error.message; + } } if (error.stack) { error = { @@ -73,6 +86,29 @@ export function parseErrorJson(responseObject: JsonObject): ClientErrorObject { return { ...error, error: error.error }; // explicit ClientErrorObject } +/* + * Utility to get standardized error text for generic update failures + */ +export async function getErrorText( + errorObject: ErrorType, + source: ErrorTextSource, +) { + const { error, message } = await getClientErrorObject(errorObject); + let errorText = t('Sorry, an unknown error occurred.'); + + if (error) { + errorText = t( + 'Sorry, there was an error saving this %s: %s', + source, + error, + ); + } + if (typeof message === 'string' && message === 'Forbidden') { + errorText = t('You do not have permission to edit this %s', source); + } + return errorText; +} + export function getClientErrorObject( response: | SupersetClientResponse @@ -166,3 +202,15 @@ export function getClientErrorObject( }); }); } + +export function getClientErrorMessage( + message: string, + clientError?: ClientErrorObject, +) { + let finalMessage = message; + const errorMessage = clientError?.message || clientError?.error; + if (errorMessage) { + finalMessage = `${finalMessage}:\n${errorMessage}`; + } + return finalMessage; +} diff --git a/superset-frontend/src/utils/getDatasourceUid.test.ts b/superset-frontend/src/utils/getDatasourceUid.test.ts new file mode 100644 index 0000000000000..2d14fde26230c --- /dev/null +++ b/superset-frontend/src/utils/getDatasourceUid.test.ts @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { DatasourceType } from '@superset-ui/core'; +import { getDatasourceUid } from './getDatasourceUid'; + +const TEST_DATASOURCE = { + id: 2, + type: DatasourceType.Table, + columns: [], + metrics: [], + column_format: {}, + verbose_map: {}, + main_dttm_col: '__timestamp', + // eg. ['["ds", true]', 'ds [asc]'] + datasource_name: 'test datasource', + description: null, +}; + +const TEST_DATASOURCE_WITH_UID = { + ...TEST_DATASOURCE, + uid: 'dataset_uid', +}; + +test('creates uid from id and type when dataset does not have uid field', () => { + expect(getDatasourceUid(TEST_DATASOURCE)).toEqual('2__table'); +}); + +test('returns uid when dataset has uid field', () => { + expect(getDatasourceUid(TEST_DATASOURCE_WITH_UID)).toEqual( + TEST_DATASOURCE_WITH_UID.uid, + ); +}); diff --git a/superset-frontend/src/addSlice/index.tsx b/superset-frontend/src/utils/getDatasourceUid.ts similarity index 81% rename from superset-frontend/src/addSlice/index.tsx rename to superset-frontend/src/utils/getDatasourceUid.ts index c257009e64fd5..b438d18ba7dc0 100644 --- a/superset-frontend/src/addSlice/index.tsx +++ b/superset-frontend/src/utils/getDatasourceUid.ts @@ -16,8 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; +import { Dataset } from '@superset-ui/chart-controls'; -ReactDOM.render(<App />, document.getElementById('app')); +export const getDatasourceUid = (datasource: Dataset) => + datasource.uid ?? `${datasource.id ?? 'None'}__${datasource.type}`; diff --git a/superset-frontend/src/utils/hostNamesConfig.js b/superset-frontend/src/utils/hostNamesConfig.js index f2a1638cc7756..2fda95c46ab65 100644 --- a/superset-frontend/src/utils/hostNamesConfig.js +++ b/superset-frontend/src/utils/hostNamesConfig.js @@ -21,6 +21,7 @@ import { isFeatureEnabled, FeatureFlag, } from 'src/featureFlags'; +import getBootstrapData from './getBootstrapData'; function getDomainsConfig() { const appContainer = document.getElementById('app'); @@ -38,11 +39,11 @@ function getDomainsConfig() { return Array.from(availableDomains); } - const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap')); + const bootstrapData = getBootstrapData(); // this module is a little special, it may be loaded before index.jsx, // where window.featureFlags get initialized // eslint-disable-next-line camelcase - initFeatureFlags(bootstrapData?.common?.feature_flags); + initFeatureFlags(bootstrapData.common.feature_flags); if ( isFeatureEnabled(FeatureFlag.ALLOW_DASHBOARD_DOMAIN_SHARDING) && diff --git a/superset-frontend/src/utils/isBot.ts b/superset-frontend/src/utils/isBot.ts new file mode 100644 index 0000000000000..8509a43c85c9e --- /dev/null +++ b/superset-frontend/src/utils/isBot.ts @@ -0,0 +1,21 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// navigator.webdriver is true when browser is controlled by a bot +export const isCurrentUserBot = () => window?.navigator?.webdriver; diff --git a/superset-frontend/src/utils/isDashboardVirtualizationEnabled.ts b/superset-frontend/src/utils/isDashboardVirtualizationEnabled.ts new file mode 100644 index 0000000000000..f27b8c849f3c5 --- /dev/null +++ b/superset-frontend/src/utils/isDashboardVirtualizationEnabled.ts @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export enum DASHBOARD_VIRTUALIZATION_MODE { + NONE = 'NONE', + VIEWPORT = 'VIEWPORT', + PAGINATED = 'PAGINATED', +} + +export const isDashboardVirtualizationEnabled = ( + virtualizationMode: DASHBOARD_VIRTUALIZATION_MODE, +) => + virtualizationMode === DASHBOARD_VIRTUALIZATION_MODE.VIEWPORT || + virtualizationMode === DASHBOARD_VIRTUALIZATION_MODE.PAGINATED; diff --git a/superset-frontend/src/utils/localStorageHelpers.ts b/superset-frontend/src/utils/localStorageHelpers.ts index 482f413372b69..3dceaba86ece6 100644 --- a/superset-frontend/src/utils/localStorageHelpers.ts +++ b/superset-frontend/src/utils/localStorageHelpers.ts @@ -17,8 +17,8 @@ * under the License. */ -import { TableTabTypes } from 'src/views/CRUD/types'; -import { SetTabType } from 'src/views/CRUD/welcome/ActivityTable'; +import { TableTab } from 'src/views/CRUD/types'; +import { DashboardContextForExplore } from 'src/types/DashboardContextForExplore'; export enum LocalStorageKeys { /** @@ -31,6 +31,7 @@ export enum LocalStorageKeys { * and therefore should be done in a major release. */ filter_box_transition_snoozed_at = 'filter_box_transition_snoozed_at', + db = 'db', chart_split_sizes = 'chart_split_sizes', controls_width = 'controls_width', datasource_width = 'datasource_width', @@ -39,6 +40,7 @@ export enum LocalStorageKeys { homepage_dashboard_filter = 'homepage_dashboard_filter', homepage_collapse_state = 'homepage_collapse_state', homepage_activity_filter = 'homepage_activity_filter', + datasetname_set_successful = 'datasetname_set_successful', /** END LEGACY LOCAL STORAGE KEYS */ /** @@ -50,20 +52,28 @@ export enum LocalStorageKeys { */ sqllab__is_autocomplete_enabled = 'sqllab__is_autocomplete_enabled', explore__data_table_original_formatted_time_columns = 'explore__data_table_original_formatted_time_columns', + dashboard__custom_filter_bar_widths = 'dashboard__custom_filter_bar_widths', + dashboard__explore_context = 'dashboard__explore_context', + common__resizable_sidebar_widths = 'common__resizable_sidebar_widths', } export type LocalStorageValues = { filter_box_transition_snoozed_at: Record<number, number>; + db: object | null; chart_split_sizes: [number, number]; controls_width: number; datasource_width: number; is_datapanel_open: boolean; - homepage_chart_filter: TableTabTypes; - homepage_dashboard_filter: TableTabTypes; + homepage_chart_filter: TableTab; + homepage_dashboard_filter: TableTab; homepage_collapse_state: string[]; - homepage_activity_filter: SetTabType | null; + datasetname_set_successful: boolean; + homepage_activity_filter: TableTab | null; sqllab__is_autocomplete_enabled: boolean; explore__data_table_original_formatted_time_columns: Record<string, string[]>; + dashboard__custom_filter_bar_widths: Record<string, number>; + dashboard__explore_context: Record<string, DashboardContextForExplore>; + common__resizable_sidebar_widths: Record<string, number>; }; /* diff --git a/superset-frontend/src/utils/urlUtils.test.ts b/superset-frontend/src/utils/urlUtils.test.ts new file mode 100644 index 0000000000000..19e2a470d1821 --- /dev/null +++ b/superset-frontend/src/utils/urlUtils.test.ts @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { isUrlExternal, parseUrl } from './urlUtils'; + +test('isUrlExternal', () => { + expect(isUrlExternal('http://google.com')).toBeTruthy(); + expect(isUrlExternal('https://google.com')).toBeTruthy(); + expect(isUrlExternal('//google.com')).toBeTruthy(); + expect(isUrlExternal('google.com')).toBeTruthy(); + expect(isUrlExternal('www.google.com')).toBeTruthy(); + expect(isUrlExternal('mailto:mail@example.com')).toBeTruthy(); + + // treat all urls starting with protocol or hostname as external + // such urls are not handled well by react-router Link component + expect(isUrlExternal('http://localhost:8888/port')).toBeTruthy(); + expect(isUrlExternal('https://localhost/secure')).toBeTruthy(); + expect(isUrlExternal('http://localhost/about')).toBeTruthy(); + expect(isUrlExternal('HTTP://localhost/about')).toBeTruthy(); + expect(isUrlExternal('//localhost/about')).toBeTruthy(); + expect(isUrlExternal('localhost/about')).toBeTruthy(); + + expect(isUrlExternal('/about')).toBeFalsy(); + expect(isUrlExternal('#anchor')).toBeFalsy(); +}); + +test('parseUrl', () => { + expect(parseUrl('http://google.com')).toEqual('http://google.com'); + expect(parseUrl('//google.com')).toEqual('//google.com'); + expect(parseUrl('mailto:mail@example.com')).toEqual( + 'mailto:mail@example.com', + ); + expect(parseUrl('google.com')).toEqual('//google.com'); + expect(parseUrl('www.google.com')).toEqual('//www.google.com'); + + expect(parseUrl('/about')).toEqual('/about'); + expect(parseUrl('#anchor')).toEqual('#anchor'); +}); diff --git a/superset-frontend/src/utils/urlUtils.ts b/superset-frontend/src/utils/urlUtils.ts index bd570291f2cba..07c8ad550074d 100644 --- a/superset-frontend/src/utils/urlUtils.ts +++ b/superset-frontend/src/utils/urlUtils.ts @@ -4,22 +4,26 @@ * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the - * 'License'); you may not use this file except in compliance + * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an - * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ -import { JsonObject, QueryFormData, SupersetClient } from '@superset-ui/core'; +import { + isDefined, + JsonObject, + QueryFormData, + SupersetClient, +} from '@superset-ui/core'; import rison from 'rison'; import { isEmpty } from 'lodash'; -import { getClientErrorObject } from './getClientErrorObject'; import { RESERVED_CHART_URL_PARAMS, RESERVED_DASHBOARD_URL_PARAMS, @@ -53,10 +57,10 @@ export function getUrlParam({ name, type }: UrlParam): unknown { if (!urlParam) { return null; } - if (urlParam === 'true') { + if (urlParam.toLowerCase() === 'true') { return 1; } - if (urlParam === 'false') { + if (urlParam.toLowerCase() === 'false') { return 0; } if (!Number.isNaN(Number(urlParam))) { @@ -72,7 +76,7 @@ export function getUrlParam({ name, type }: UrlParam): unknown { if (!urlParam) { return null; } - return urlParam !== 'false' && urlParam !== '0'; + return urlParam.toLowerCase() !== 'false' && urlParam !== '0'; case 'rison': if (!urlParam) { return null; @@ -96,7 +100,7 @@ function getUrlParams(excludedParams: string[]): URLSearchParams { return urlParams; } -type UrlParamEntries = [string, string][]; +export type UrlParamEntries = [string, string][]; function getUrlParamEntries(urlParams: URLSearchParams): UrlParamEntries { const urlEntries: [string, string][] = []; @@ -134,14 +138,7 @@ function getPermalink(endpoint: string, jsonPayload: JsonObject) { return SupersetClient.post({ endpoint, jsonPayload, - }) - .then(result => result.json.url as string) - .catch(response => - // @ts-ignore - getClientErrorObject(response).then(({ error, statusText }) => - Promise.reject(error || statusText), - ), - ); + }).then(result => result.json.url as string); } export function getChartPermalink( @@ -156,17 +153,56 @@ export function getChartPermalink( export function getDashboardPermalink({ dashboardId, - filterState, - hash, // the anchor part of the link which corresponds to the tab/chart id + dataMask, + activeTabs, + anchor, // the anchor part of the link which corresponds to the tab/chart id }: { dashboardId: string | number; - filterState: JsonObject; - hash?: string; + /** + * Current applied data masks (for native filters). + */ + dataMask: JsonObject; + /** + * Current active tabs in the dashboard. + */ + activeTabs: string[]; + /** + * The "anchor" component for the permalink. It will be scrolled into view + * and highlighted upon page load. + */ + anchor?: string; }) { // only encode filter box state if non-empty return getPermalink(`/api/v1/dashboard/${dashboardId}/permalink`, { - filterState, urlParams: getDashboardUrlParams(), - hash, + dataMask, + activeTabs, + anchor, }); } + +const externalUrlRegex = + /^([^:/?#]+:)?(?:(\/\/)?([^/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/; + +// group 1 matches protocol +// group 2 matches '//' +// group 3 matches hostname +export function isUrlExternal(url: string) { + const match = url.match(externalUrlRegex) || []; + return ( + (typeof match[1] === 'string' && match[1].length > 0) || + match[2] === '//' || + (typeof match[3] === 'string' && match[3].length > 0) + ); +} + +export function parseUrl(url: string) { + const match = url.match(externalUrlRegex) || []; + // if url is external but start with protocol or '//', + // it can't be used correctly with <a> element + // in such case, add '//' prefix + if (isUrlExternal(url) && !isDefined(match[1]) && !url.startsWith('//')) { + return `//${url}`; + } + return url; +} diff --git a/superset-frontend/src/views/App.tsx b/superset-frontend/src/views/App.tsx index ecdbddbd56796..cacfaa1455287 100644 --- a/superset-frontend/src/views/App.tsx +++ b/superset-frontend/src/views/App.tsx @@ -24,31 +24,41 @@ import { Route, useLocation, } from 'react-router-dom'; +import { bindActionCreators } from 'redux'; import { GlobalStyles } from 'src/GlobalStyles'; -import { initFeatureFlags } from 'src/featureFlags'; import ErrorBoundary from 'src/components/ErrorBoundary'; import Loading from 'src/components/Loading'; import Menu from 'src/views/components/Menu'; -import { bootstrapData } from 'src/preamble'; +import getBootstrapData from 'src/utils/getBootstrapData'; import ToastContainer from 'src/components/MessageToasts/ToastContainer'; import setupApp from 'src/setup/setupApp'; +import setupPlugins from 'src/setup/setupPlugins'; import { routes, isFrontendRoute } from 'src/views/routes'; -import { Logger } from 'src/logger/LogUtils'; +import { Logger, LOG_ACTIONS_SPA_NAVIGATION } from 'src/logger/LogUtils'; +import setupExtensions from 'src/setup/setupExtensions'; +import { logEvent } from 'src/logger/actions'; +import { store } from 'src/views/store'; import { RootContextProviders } from './RootContextProviders'; import { ScrollToTop } from './ScrollToTop'; +import QueryProvider from './QueryProvider'; setupApp(); +setupPlugins(); +setupExtensions(); + +const bootstrapData = getBootstrapData(); -const user = { ...bootstrapData.user }; -const menu = { - ...bootstrapData.common.menu_data, -}; let lastLocationPathname: string; -initFeatureFlags(bootstrapData.common.feature_flags); + +const boundActions = bindActionCreators({ logEvent }, store.dispatch); const LocationPathnameLogger = () => { const location = useLocation(); useEffect(() => { + // This will log client side route changes for single page app user navigation + boundActions.logEvent(LOG_ACTIONS_SPA_NAVIGATION, { + path: location.pathname, + }); // reset performance logger timer start point to avoid soft navigation // cause dashboard perf measurement problem if (lastLocationPathname && lastLocationPathname !== location.pathname) { @@ -60,26 +70,31 @@ const LocationPathnameLogger = () => { }; const App = () => ( - <Router> - <ScrollToTop /> - <LocationPathnameLogger /> - <RootContextProviders> - <GlobalStyles /> - <Menu data={menu} isFrontendRoute={isFrontendRoute} /> - <Switch> - {routes.map(({ path, Component, props = {}, Fallback = Loading }) => ( - <Route path={path} key={path}> - <Suspense fallback={<Fallback />}> - <ErrorBoundary> - <Component user={user} {...props} /> - </ErrorBoundary> - </Suspense> - </Route> - ))} - </Switch> - <ToastContainer /> - </RootContextProviders> - </Router> + <QueryProvider> + <Router> + <ScrollToTop /> + <LocationPathnameLogger /> + <RootContextProviders> + <GlobalStyles /> + <Menu + data={bootstrapData.common.menu_data} + isFrontendRoute={isFrontendRoute} + /> + <Switch> + {routes.map(({ path, Component, props = {}, Fallback = Loading }) => ( + <Route path={path} key={path}> + <Suspense fallback={<Fallback />}> + <ErrorBoundary> + <Component user={bootstrapData.user} {...props} /> + </ErrorBoundary> + </Suspense> + </Route> + ))} + </Switch> + <ToastContainer /> + </RootContextProviders> + </Router> + </QueryProvider> ); export default hot(App); diff --git a/superset-frontend/src/views/CRUD/alert/AlertList.test.jsx b/superset-frontend/src/views/CRUD/alert/AlertList.test.jsx index 5cf9483a526e0..d5b4d241502c0 100644 --- a/superset-frontend/src/views/CRUD/alert/AlertList.test.jsx +++ b/superset-frontend/src/views/CRUD/alert/AlertList.test.jsx @@ -55,7 +55,7 @@ const mockalerts = [...new Array(3)].map((_, i) => ({ last_eval_dttm: Date.now(), last_state: 'ok', name: `alert ${i} `, - owners: [], + owners: [{ id: 1 }], recipients: [ { id: `${i}`, @@ -67,6 +67,8 @@ const mockalerts = [...new Array(3)].map((_, i) => ({ const mockUser = { userId: 1, + firstName: 'user 1', + lastName: 'lastname', }; fetchMock.get(alertsEndpoint, { diff --git a/superset-frontend/src/views/CRUD/alert/AlertList.tsx b/superset-frontend/src/views/CRUD/alert/AlertList.tsx index a2fdb9110e7d4..1c34167652460 100644 --- a/superset-frontend/src/views/CRUD/alert/AlertList.tsx +++ b/superset-frontend/src/views/CRUD/alert/AlertList.tsx @@ -19,7 +19,13 @@ import React, { useState, useMemo, useEffect, useCallback } from 'react'; import { useHistory } from 'react-router-dom'; -import { t, SupersetClient, makeApi, styled } from '@superset-ui/core'; +import { + t, + SupersetClient, + makeApi, + styled, + getExtensionsRegistry, +} from '@superset-ui/core'; import moment from 'moment'; import ActionsBar, { ActionProps } from 'src/components/ListView/ActionsBar'; import FacePile from 'src/components/FacePile'; @@ -44,9 +50,13 @@ import { useSingleViewResource, } from 'src/views/CRUD/hooks'; import { createErrorHandler, createFetchRelated } from 'src/views/CRUD/utils'; +import { isUserAdmin } from 'src/dashboard/util/permissionUtils'; +import Owner from 'src/types/Owner'; import AlertReportModal from './AlertReportModal'; import { AlertObject, AlertState } from './types'; +const extensionsRegistry = getExtensionsRegistry(); + const PAGE_SIZE = 25; const AlertStateLabel: Record<AlertState, string> = { @@ -80,6 +90,18 @@ const RefreshContainer = styled.div` background-color: ${({ theme }) => theme.colors.grayscale.light5}; `; +const StyledHeaderWithIcon = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + > *:first-child { + margin-right: ${({ theme }) => theme.gridUnit}px; + } +`; + +const HeaderExtension = extensionsRegistry.get('alertsreports.header.icon'); + function AlertList({ addDangerToast, isReportEnabled = false, @@ -191,7 +213,7 @@ function AlertList({ const toggleActive = useCallback( (data: AlertObject, checked: boolean) => { - if (data && data.id) { + if (data?.id) { const update_id = data.id; const original = [...alerts]; @@ -316,14 +338,21 @@ function AlertList({ size: 'xl', }, { - Cell: ({ row: { original } }: any) => ( - <Switch - data-test="toggle-active" - checked={original.active} - onClick={(checked: boolean) => toggleActive(original, checked)} - size="small" - /> - ), + Cell: ({ row: { original } }: any) => { + const allowEdit = + original.owners.map((o: Owner) => o.id).includes(user.userId) || + isUserAdmin(user); + + return ( + <Switch + disabled={!allowEdit} + data-test="toggle-active" + checked={original.active} + onClick={(checked: boolean) => toggleActive(original, checked)} + size="small" + /> + ); + }, Header: t('Active'), accessor: 'active', id: 'active', @@ -337,6 +366,10 @@ function AlertList({ const handleGotoExecutionLog = () => history.push(`/${original.type.toLowerCase()}/${original.id}/log`); + const allowEdit = + original.owners.map((o: Owner) => o.id).includes(user.userId) || + isUserAdmin(user); + const actions = [ canEdit ? { @@ -349,14 +382,14 @@ function AlertList({ : null, canEdit ? { - label: 'edit-action', - tooltip: t('Edit'), + label: allowEdit ? 'edit-action' : 'preview-action', + tooltip: allowEdit ? t('Edit') : t('View'), placement: 'bottom', - icon: 'Edit', + icon: allowEdit ? 'Edit' : 'Binoculars', onClick: handleEdit, } : null, - canDelete + allowEdit && canDelete ? { label: 'delete-action', tooltip: t('Delete'), @@ -418,10 +451,11 @@ function AlertList({ () => [ { Header: t('Owner'), + key: 'owner', id: 'owners', input: 'select', operator: FilterOperator.relationManyMany, - unfilteredLabel: 'All', + unfilteredLabel: t('All'), fetchSelects: createFetchRelated( 'report', 'owners', @@ -434,6 +468,7 @@ function AlertList({ }, { Header: t('Created by'), + key: 'created_by', id: 'created_by', input: 'select', operator: FilterOperator.relationOneMany, @@ -450,6 +485,7 @@ function AlertList({ }, { Header: t('Status'), + key: 'status', id: 'last_state', input: 'select', operator: FilterOperator.equals, @@ -470,6 +506,7 @@ function AlertList({ }, { Header: t('Search'), + key: 'search', id: 'name', input: 'search', operator: FilterOperator.contains, @@ -478,11 +515,20 @@ function AlertList({ [], ); + const header = HeaderExtension ? ( + <StyledHeaderWithIcon> + <div>{t('Alerts & reports')}</div> + <HeaderExtension /> + </StyledHeaderWithIcon> + ) : ( + t('Alerts & reports') + ); + return ( <> <SubMenu activeChild={pathName} - name={t('Alerts & reports')} + name={header} tabs={[ { name: 'Alerts', diff --git a/superset-frontend/src/views/CRUD/alert/AlertReportModal.test.jsx b/superset-frontend/src/views/CRUD/alert/AlertReportModal.test.jsx index 1598e5a926f32..a383c8be20cf0 100644 --- a/superset-frontend/src/views/CRUD/alert/AlertReportModal.test.jsx +++ b/superset-frontend/src/views/CRUD/alert/AlertReportModal.test.jsx @@ -24,7 +24,7 @@ import fetchMock from 'fetch-mock'; import { act } from 'react-dom/test-utils'; import AlertReportModal from 'src/views/CRUD/alert/AlertReportModal'; import Modal from 'src/components/Modal'; -import { Select } from 'src/components'; +import { Select, AsyncSelect } from 'src/components'; import { Switch } from 'src/components/Switch'; import { Radio } from 'src/components/Radio'; import TextAreaControl from 'src/explore/components/controls/TextAreaControl'; @@ -180,9 +180,11 @@ describe('AlertReportModal', () => { expect(wrapper.find('input[name="name"]')).toExist(); }); - it('renders five select elements when in report mode', () => { + it('renders four select elements when in report mode', () => { expect(wrapper.find(Select)).toExist(); - expect(wrapper.find(Select)).toHaveLength(5); + expect(wrapper.find(AsyncSelect)).toExist(); + expect(wrapper.find(Select)).toHaveLength(2); + expect(wrapper.find(AsyncSelect)).toHaveLength(2); }); it('renders Switch element', () => { @@ -218,12 +220,14 @@ describe('AlertReportModal', () => { expect(input.props().initialValue).toEqual('SELECT NaN'); }); - it('renders five select element when in report mode', () => { + it('renders four select element when in report mode', () => { expect(wrapper.find(Select)).toExist(); - expect(wrapper.find(Select)).toHaveLength(5); + expect(wrapper.find(AsyncSelect)).toExist(); + expect(wrapper.find(Select)).toHaveLength(2); + expect(wrapper.find(AsyncSelect)).toHaveLength(2); }); - it('renders seven select elements when in alert mode', async () => { + it('renders six select elements when in alert mode', async () => { const props = { ...mockedProps, isReport: false, @@ -232,7 +236,9 @@ describe('AlertReportModal', () => { const addWrapper = await mountAndWait(props); expect(addWrapper.find(Select)).toExist(); - expect(addWrapper.find(Select)).toHaveLength(7); + expect(addWrapper.find(AsyncSelect)).toExist(); + expect(addWrapper.find(Select)).toHaveLength(3); + expect(addWrapper.find(AsyncSelect)).toHaveLength(3); }); it('renders value input element when in alert mode', async () => { diff --git a/superset-frontend/src/views/CRUD/alert/AlertReportModal.test.tsx b/superset-frontend/src/views/CRUD/alert/AlertReportModal.test.tsx index 8eeea3d45bcd8..928b2e9567062 100644 --- a/superset-frontend/src/views/CRUD/alert/AlertReportModal.test.tsx +++ b/superset-frontend/src/views/CRUD/alert/AlertReportModal.test.tsx @@ -40,3 +40,37 @@ test('allows change to None in log retention', async () => { // check if None is selected expect(selectedItem).toHaveTextContent('None'); }); + +test('renders the appropriate dropdown in Message Content section', async () => { + render(<AlertReportModal show />, { useRedux: true }); + + const chartRadio = screen.getByRole('radio', { name: /chart/i }); + + // Dashboard is initially checked by default + expect( + await screen.findByRole('radio', { + name: /dashboard/i, + }), + ).toBeChecked(); + expect(chartRadio).not.toBeChecked(); + // Only the dashboard dropdown should show + expect(screen.getByRole('combobox', { name: /dashboard/i })).toBeVisible(); + expect( + screen.queryByRole('combobox', { name: /chart/i }), + ).not.toBeInTheDocument(); + + // Click the chart radio option + userEvent.click(chartRadio); + + expect(await screen.findByRole('radio', { name: /chart/i })).toBeChecked(); + expect( + screen.getByRole('radio', { + name: /dashboard/i, + }), + ).not.toBeChecked(); + // Now that chart is checked, only the chart dropdown should show + expect(screen.getByRole('combobox', { name: /chart/i })).toBeVisible(); + expect( + screen.queryByRole('combobox', { name: /dashboard/i }), + ).not.toBeInTheDocument(); +}); diff --git a/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx b/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx index 04398a3582fc9..d7f7a4c7364c3 100644 --- a/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx +++ b/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx @@ -38,11 +38,11 @@ import { Switch } from 'src/components/Switch'; import Modal from 'src/components/Modal'; import TimezoneSelector from 'src/components/TimezoneSelector'; import { Radio } from 'src/components/Radio'; -import Select, { propertyComparator } from 'src/components/Select/Select'; +import { propertyComparator } from 'src/components/Select/utils'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import withToasts from 'src/components/MessageToasts/withToasts'; import Owner from 'src/types/Owner'; -import { AntdCheckbox } from 'src/components'; +import { AntdCheckbox, AsyncSelect, Select } from 'src/components'; import TextAreaControl from 'src/explore/components/controls/TextAreaControl'; import { useCommonConf } from 'src/views/CRUD/data/database/state'; import { @@ -171,6 +171,10 @@ const StyledSectionContainer = styled.div` display: flex; flex-direction: column; + .control-label { + margin-top: ${({ theme }) => theme.gridUnit}px; + } + .header-section { display: flex; flex: 0 0 auto; @@ -257,7 +261,6 @@ const StyledSwitchContainer = styled.div` export const StyledInputContainer = styled.div` flex: 1; - margin: ${({ theme }) => theme.gridUnit * 2}px; margin-top: 0; .helper { @@ -340,6 +343,7 @@ const StyledRadioGroup = styled(Radio.Group)` const StyledCheckbox = styled(AntdCheckbox)` margin-left: ${({ theme }) => theme.gridUnit * 5.5}px; + margin-top: ${({ theme }) => theme.gridUnit}px; `; // Notification Method components @@ -357,10 +361,21 @@ const StyledNotificationAddButton = styled.div` } `; +const StyledNotificationMethodWrapper = styled.div` + .inline-container .input-container { + margin-left: 0; + } +`; + const timezoneHeaderStyle = (theme: SupersetTheme) => css` margin: ${theme.gridUnit * 3}px 0; `; +const inputSpacer = (theme: SupersetTheme) => + css` + margin-right: ${theme.gridUnit * 3}px; + `; + type NotificationAddStatus = 'active' | 'disabled' | 'hidden'; interface NotificationMethodAddProps { @@ -368,6 +383,46 @@ interface NotificationMethodAddProps { onClick: () => void; } +const TRANSLATIONS = { + ADD_NOTIFICATION_METHOD_TEXT: t('Add notification method'), + ADD_DELIVERY_METHOD_TEXT: t('Add delivery method'), + SAVE_TEXT: t('Save'), + ADD_TEXT: t('Add'), + EDIT_REPORT_TEXT: t('Edit Report'), + EDIT_ALERT_TEXT: t('Edit Alert'), + ADD_REPORT_TEXT: t('Add Report'), + ADD_ALERT_TEXT: t('Add Alert'), + REPORT_NAME_TEXT: t('Report name'), + ALERT_NAME_TEXT: t('Alert name'), + OWNERS_TEXT: t('Owners'), + DESCRIPTION_TEXT: t('Description'), + ACTIVE_TEXT: t('Active'), + ALERT_CONDITION_TEXT: t('Alert condition'), + DATABASE_TEXT: t('Database'), + SQL_QUERY_TEXT: t('SQL Query'), + TRIGGER_ALERT_IF_TEXT: t('Trigger Alert If...'), + CONDITION_TEXT: t('Condition'), + VALUE_TEXT: t('Value'), + VALUE_TOOLTIP: t('Threshold value should be double precision number'), + REPORT_SCHEDULE_TEXT: t('Report schedule'), + ALERT_CONDITION_SCHEDULE_TEXT: t('Alert condition schedule'), + TIMEZONE_TEXT: t('Timezone'), + SCHEDULE_SETTINGS_TEXT: t('Schedule settings'), + LOG_RETENTION_TEXT: t('Log retention'), + WORKING_TIMEOUT_TEXT: t('Working timeout'), + TIME_IN_SECONDS_TEXT: t('Time in seconds'), + SECONDS_TEXT: t('seconds'), + GRACE_PERIOD_TEXT: t('Grace period'), + MESSAGE_CONTENT_TEXT: t('Message content'), + DASHBOARD_TEXT: t('Dashboard'), + CHART_TEXT: t('Chart'), + SEND_AS_PNG_TEXT: t('Send as PNG'), + SEND_AS_CSV_TEXT: t('Send as CSV'), + SEND_AS_TEXT: t('Send as text'), + IGNORE_CACHE_TEXT: t('Ignore cache when generating screenshot'), + NOTIFICATION_METHOD_TEXT: t('Notification method'), +}; + const NotificationMethodAdd: FunctionComponent<NotificationMethodAddProps> = ({ status = 'active', onClick, @@ -386,8 +441,8 @@ const NotificationMethodAdd: FunctionComponent<NotificationMethodAddProps> = ({ <StyledNotificationAddButton className={status} onClick={checkStatus}> <i className="fa fa-plus" />{' '} {status === 'active' - ? t('Add notification method') - : t('Add delivery method')} + ? TRANSLATIONS.ADD_NOTIFICATION_METHOD_TEXT + : TRANSLATIONS.ADD_DELIVERY_METHOD_TEXT} </StyledNotificationAddButton> ); }; @@ -516,7 +571,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ const shouldEnableForceScreenshot = contentType === 'chart' && !isReport; const data: any = { ...currentAlert, - type: isReport ? 'Report' : 'Alert', + type: isReport ? t('Report') : t('Alert'), force_screenshot: shouldEnableForceScreenshot || forceScreenshot, validator_type: conditionNotNull ? 'not null' : 'operator', validator_config_json: conditionNotNull @@ -544,7 +599,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ if (isEditMode) { // Edit - if (currentAlert && currentAlert.id) { + if (currentAlert?.id) { const update_id = currentAlert.id; delete data.id; @@ -664,8 +719,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ [], ); - const databaseLabel = - currentAlert && currentAlert.database && !currentAlert.database.label; + const databaseLabel = currentAlert?.database && !currentAlert.database.label; useEffect(() => { // Find source if current alert has one set if (databaseLabel) { @@ -738,8 +792,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ [chartOptions, currentAlert?.chart], ); - const noChartLabel = - currentAlert && currentAlert.chart && !currentAlert.chart.label; + const noChartLabel = currentAlert?.chart && !currentAlert?.chart.label; useEffect(() => { // Find source if current alert has one set if (noChartLabel) { @@ -899,13 +952,12 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ const validate = () => { if ( - currentAlert && - currentAlert.name?.length && - currentAlert.owners?.length && - currentAlert.crontab?.length && - currentAlert.working_timeout !== undefined && - ((contentType === 'dashboard' && !!currentAlert.dashboard) || - (contentType === 'chart' && !!currentAlert.chart)) && + currentAlert?.name?.length && + currentAlert?.owners?.length && + currentAlert?.crontab?.length && + currentAlert?.working_timeout !== undefined && + ((contentType === 'dashboard' && !!currentAlert?.dashboard) || + (contentType === 'chart' && !!currentAlert?.chart)) && checkNotificationSettings() ) { if (isReport) { @@ -932,7 +984,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ isEditMode && (!currentAlert?.id || alert?.id !== currentAlert.id || (isHidden && show)) ) { - if (alert && alert.id !== null && !loading && !fetchError) { + if (alert?.id !== null && !loading && !fetchError) { const id = alert.id || 0; fetchResource(id); } @@ -1054,7 +1106,9 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ disablePrimaryButton={disableSave} onHandledPrimaryAction={onSave} onHide={hide} - primaryButtonName={isEditMode ? t('Save') : t('Add')} + primaryButtonName={ + isEditMode ? TRANSLATIONS.SAVE_TEXT : TRANSLATIONS.ADD_TEXT + } show={show} width="100%" maxWidth="1450px" @@ -1066,12 +1120,12 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ <Icons.PlusLarge css={StyledIcon} /> )} {isEditMode && isReport - ? t('Edit Report') + ? TRANSLATIONS.EDIT_REPORT_TEXT : isEditMode - ? t('Edit Alert') + ? TRANSLATIONS.EDIT_ALERT_TEXT : isReport - ? t('Add Report') - : t('Add Alert')} + ? TRANSLATIONS.ADD_REPORT_TEXT + : TRANSLATIONS.ADD_ALERT_TEXT} </h4> } > @@ -1079,7 +1133,9 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ <div className="header-section"> <StyledInputContainer> <div className="control-label"> - {isReport ? t('Report name') : t('Alert name')} + {isReport + ? TRANSLATIONS.REPORT_NAME_TEXT + : TRANSLATIONS.ALERT_NAME_TEXT} <span className="required">*</span> </div> <div className="input-container"> @@ -1087,19 +1143,24 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ type="text" name="name" value={currentAlert ? currentAlert.name : ''} - placeholder={isReport ? t('Report name') : t('Alert name')} + placeholder={ + isReport + ? TRANSLATIONS.REPORT_NAME_TEXT + : TRANSLATIONS.ALERT_NAME_TEXT + } onChange={onTextChange} + css={inputSpacer} /> </div> </StyledInputContainer> <StyledInputContainer> <div className="control-label"> - {t('Owners')} + {TRANSLATIONS.OWNERS_TEXT} <span className="required">*</span> </div> <div data-test="owners-select" className="input-container"> - <Select - ariaLabel={t('Owners')} + <AsyncSelect + ariaLabel={TRANSLATIONS.OWNERS_TEXT} allowClear name="owners" mode="multiple" @@ -1111,18 +1172,20 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ } options={loadOwnerOptions} onChange={onOwnersChange} + css={inputSpacer} /> </div> </StyledInputContainer> <StyledInputContainer> - <div className="control-label">{t('Description')}</div> + <div className="control-label">{TRANSLATIONS.DESCRIPTION_TEXT}</div> <div className="input-container"> <input type="text" name="description" value={currentAlert ? currentAlert.description || '' : ''} - placeholder={t('Description')} + placeholder={TRANSLATIONS.DESCRIPTION_TEXT} onChange={onTextChange} + css={inputSpacer} /> </div> </StyledInputContainer> @@ -1131,23 +1194,23 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ onChange={onActiveSwitch} checked={currentAlert ? currentAlert.active : true} /> - <div className="switch-label">Active</div> + <div className="switch-label">{TRANSLATIONS.ACTIVE_TEXT}</div> </StyledSwitchContainer> </div> <div className="column-section"> {!isReport && ( <div className="column condition"> <StyledSectionTitle> - <h4>{t('Alert condition')}</h4> + <h4>{TRANSLATIONS.ALERT_CONDITION_TEXT}</h4> </StyledSectionTitle> <StyledInputContainer> <div className="control-label"> - {t('Database')} + {TRANSLATIONS.DATABASE_TEXT} <span className="required">*</span> </div> <div className="input-container"> - <Select - ariaLabel={t('Database')} + <AsyncSelect + ariaLabel={TRANSLATIONS.DATABASE_TEXT} name="source" value={ currentAlert?.database?.label && @@ -1165,7 +1228,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ </StyledInputContainer> <StyledInputContainer> <div className="control-label"> - {t('SQL Query')} + {TRANSLATIONS.SQL_QUERY_TEXT} <span className="required">*</span> </div> <TextAreaControl @@ -1182,29 +1245,28 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ </StyledInputContainer> <div className="inline-container wrap"> <StyledInputContainer> - <div className="control-label"> - {t('Trigger Alert If...')} + <div className="control-label" css={inputSpacer}> + {TRANSLATIONS.TRIGGER_ALERT_IF_TEXT} <span className="required">*</span> </div> <div className="input-container"> <Select - ariaLabel={t('Condition')} + ariaLabel={TRANSLATIONS.CONDITION_TEXT} onChange={onConditionChange} placeholder="Condition" value={ currentAlert?.validator_config_json?.op || undefined } options={CONDITIONS} + css={inputSpacer} /> </div> </StyledInputContainer> <StyledInputContainer> <div className="control-label"> - {t('Value')}{' '} + {TRANSLATIONS.VALUE_TEXT}{' '} <InfoTooltipWithTrigger - tooltip={t( - 'Threshold value should be double precision number', - )} + tooltip={TRANSLATIONS.VALUE_TOOLTIP} /> <span className="required">*</span> </div> @@ -1214,14 +1276,12 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ name="threshold" disabled={conditionNotNull} value={ - currentAlert && - currentAlert.validator_config_json && - currentAlert.validator_config_json.threshold !== - undefined + currentAlert?.validator_config_json?.threshold !== + undefined ? currentAlert.validator_config_json.threshold : '' } - placeholder={t('Value')} + placeholder={TRANSLATIONS.VALUE_TEXT} onChange={onThresholdChange} /> </div> @@ -1233,8 +1293,8 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ <StyledSectionTitle> <h4> {isReport - ? t('Report schedule') - : t('Alert condition schedule')} + ? TRANSLATIONS.REPORT_SCHEDULE_TEXT + : TRANSLATIONS.ALERT_CONDITION_SCHEDULE_TEXT} </h4> <span className="required">*</span> </StyledSectionTitle> @@ -1242,7 +1302,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ value={currentAlert?.crontab || DEFAULT_CRON_VALUE} onChange={newVal => updateAlertState('crontab', newVal)} /> - <div className="control-label">{t('Timezone')}</div> + <div className="control-label">{TRANSLATIONS.TIMEZONE_TEXT}</div> <div className="input-container" css={(theme: SupersetTheme) => timezoneHeaderStyle(theme)} @@ -1254,17 +1314,17 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ /> </div> <StyledSectionTitle> - <h4>{t('Schedule settings')}</h4> + <h4>{TRANSLATIONS.SCHEDULE_SETTINGS_TEXT}</h4> </StyledSectionTitle> <StyledInputContainer> <div className="control-label"> - {t('Log retention')} + {TRANSLATIONS.LOG_RETENTION_TEXT} <span className="required">*</span> </div> <div className="input-container"> <Select - ariaLabel={t('Log retention')} - placeholder={t('Log retention')} + ariaLabel={TRANSLATIONS.LOG_RETENTION_TEXT} + placeholder={TRANSLATIONS.LOG_RETENTION_TEXT} onChange={onLogRetentionChange} value={ typeof currentAlert?.log_retention === 'number' @@ -1278,7 +1338,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ </StyledInputContainer> <StyledInputContainer> <div className="control-label"> - {t('Working timeout')} + {TRANSLATIONS.WORKING_TIMEOUT_TEXT} <span className="required">*</span> </div> <div className="input-container"> @@ -1287,72 +1347,76 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ min="1" name="working_timeout" value={currentAlert?.working_timeout || ''} - placeholder={t('Time in seconds')} + placeholder={TRANSLATIONS.TIME_IN_SECONDS_TEXT} onChange={onTimeoutVerifyChange} /> - <span className="input-label">seconds</span> + <span className="input-label">{TRANSLATIONS.SECONDS_TEXT}</span> </div> </StyledInputContainer> {!isReport && ( <StyledInputContainer> - <div className="control-label">{t('Grace period')}</div> + <div className="control-label"> + {TRANSLATIONS.GRACE_PERIOD_TEXT} + </div> <div className="input-container"> <input type="number" min="1" name="grace_period" value={currentAlert?.grace_period || ''} - placeholder={t('Time in seconds')} + placeholder={TRANSLATIONS.TIME_IN_SECONDS_TEXT} onChange={onTimeoutVerifyChange} /> - <span className="input-label">seconds</span> + <span className="input-label"> + {TRANSLATIONS.SECONDS_TEXT} + </span> </div> </StyledInputContainer> )} </div> <div className="column message"> <StyledSectionTitle> - <h4>{t('Message content')}</h4> + <h4>{TRANSLATIONS.MESSAGE_CONTENT_TEXT}</h4> <span className="required">*</span> </StyledSectionTitle> <Radio.Group onChange={onContentTypeChange} value={contentType}> - <StyledRadio value="dashboard">{t('Dashboard')}</StyledRadio> - <StyledRadio value="chart">{t('Chart')}</StyledRadio> + <StyledRadio value="dashboard"> + {TRANSLATIONS.DASHBOARD_TEXT} + </StyledRadio> + <StyledRadio value="chart">{TRANSLATIONS.CHART_TEXT}</StyledRadio> </Radio.Group> - <Select - ariaLabel={t('Chart')} - css={{ - display: contentType === 'chart' ? 'inline' : 'none', - }} - name="chart" - value={ - currentAlert?.chart?.label && currentAlert?.chart?.value - ? { - value: currentAlert.chart.value, - label: currentAlert.chart.label, - } - : undefined - } - options={loadChartOptions} - onChange={onChartChange} - /> - <Select - ariaLabel={t('Dashboard')} - css={{ - display: contentType === 'dashboard' ? 'inline' : 'none', - }} - name="dashboard" - value={ - currentAlert?.dashboard?.label && currentAlert?.dashboard?.value - ? { - value: currentAlert.dashboard.value, - label: currentAlert.dashboard.label, - } - : undefined - } - options={loadDashboardOptions} - onChange={onDashboardChange} - /> + {contentType === 'chart' ? ( + <AsyncSelect + ariaLabel={TRANSLATIONS.CHART_TEXT} + name="chart" + value={ + currentAlert?.chart?.label && currentAlert?.chart?.value + ? { + value: currentAlert.chart.value, + label: currentAlert.chart.label, + } + : undefined + } + options={loadChartOptions} + onChange={onChartChange} + /> + ) : ( + <AsyncSelect + ariaLabel={TRANSLATIONS.DASHBOARD_TEXT} + name="dashboard" + value={ + currentAlert?.dashboard?.label && + currentAlert?.dashboard?.value + ? { + value: currentAlert.dashboard.value, + label: currentAlert.dashboard.label, + } + : undefined + } + options={loadDashboardOptions} + onChange={onDashboardChange} + /> + )} {formatOptionEnabled && ( <> <div className="inline-container"> @@ -1360,11 +1424,15 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ onChange={onFormatChange} value={reportFormat} > - <StyledRadio value="PNG">{t('Send as PNG')}</StyledRadio> - <StyledRadio value="CSV">{t('Send as CSV')}</StyledRadio> + <StyledRadio value="PNG"> + {TRANSLATIONS.SEND_AS_PNG_TEXT} + </StyledRadio> + <StyledRadio value="CSV"> + {TRANSLATIONS.SEND_AS_CSV_TEXT} + </StyledRadio> {TEXT_BASED_VISUALIZATION_TYPES.includes(chartVizType) && ( <StyledRadio value="TEXT"> - {t('Send as text')} + {TRANSLATIONS.SEND_AS_TEXT} </StyledRadio> )} </StyledRadioGroup> @@ -1379,22 +1447,24 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({ checked={forceScreenshot} onChange={onForceScreenshotChange} > - Ignore cache when generating screenshot + {TRANSLATIONS.IGNORE_CACHE_TEXT} </StyledCheckbox> </div> )} <StyledSectionTitle> - <h4>{t('Notification method')}</h4> + <h4>{TRANSLATIONS.NOTIFICATION_METHOD_TEXT}</h4> <span className="required">*</span> </StyledSectionTitle> {notificationSettings.map((notificationSetting, i) => ( - <NotificationMethod - setting={notificationSetting} - index={i} - key={`NotificationMethod-${i}`} - onUpdate={updateNotificationSetting} - onRemove={removeNotificationSetting} - /> + <StyledNotificationMethodWrapper> + <NotificationMethod + setting={notificationSetting} + index={i} + key={`NotificationMethod-${i}`} + onUpdate={updateNotificationSetting} + onRemove={removeNotificationSetting} + /> + </StyledNotificationMethodWrapper> ))} <NotificationMethodAdd data-test="notification-add" diff --git a/superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx b/superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx index 37f3e7c2add6d..61b801c1c091a 100644 --- a/superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx +++ b/superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx @@ -159,16 +159,26 @@ function ExecutionLog({ addDangerToast, isReportEnabled }: ExecutionLogProps) { [isReportEnabled], ); const path = `/${isReportEnabled ? 'report' : 'alert'}/list/`; + const ALERT_TEXT = t('Alert'); + const REPORT_TEXT = t('Report'); + return ( <> <SubMenu name={ <StyledHeader> <span> - {alertResource?.type} {alertResource?.name} + {alertResource + ? alertResource.type === 'Alert' + ? `${ALERT_TEXT}:` + : alertResource.type === 'Report' + ? `${REPORT_TEXT}:` + : null + : null}{' '} + {alertResource?.name} </span> <span> - <Link to={path}>Back to all</Link> + <Link to={path}>{t('Back to all')}</Link> </span> </StyledHeader> } diff --git a/superset-frontend/src/views/CRUD/alert/components/AlertReportCronScheduler.tsx b/superset-frontend/src/views/CRUD/alert/components/AlertReportCronScheduler.tsx index 5418842aeaaa5..9a7fa6214b8e7 100644 --- a/superset-frontend/src/views/CRUD/alert/components/AlertReportCronScheduler.tsx +++ b/superset-frontend/src/views/CRUD/alert/components/AlertReportCronScheduler.tsx @@ -80,7 +80,7 @@ export const AlertReportCronScheduler: React.FC<AlertReportCronSchedulerProps> = </div> <div className="inline-container add-margin"> <Radio data-test="input" value="input" /> - <span className="input-label">CRON Schedule</span> + <span className="input-label">{t('CRON Schedule')}</span> <StyledInputContainer data-test="input-content" className="styled-input" diff --git a/superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx b/superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx index 6dedb5e0ead69..f92bedd15d58f 100644 --- a/superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx +++ b/superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx @@ -259,9 +259,9 @@ function AnnotationList({ <span>{t('Annotation Layer %s', annotationLayerName)}</span> <span> {hasHistory ? ( - <Link to="/annotationlayermodelview/list/">Back to all</Link> + <Link to="/annotationlayer/list/">{t('Back to all')}</Link> ) : ( - <a href="/annotationlayermodelview/list/">Back to all</a> + <a href="/annotationlayer/list/">{t('Back to all')}</a> )} </span> </StyledHeader> @@ -274,7 +274,7 @@ function AnnotationList({ annotation={currentAnnotation} show={annotationModalOpen} onAnnotationAdd={() => refreshData()} - annnotationLayerId={annotationLayerId} + annotationLayerId={annotationLayerId} onHide={() => setAnnotationModalOpen(false)} /> {annotationCurrentlyDeleting && ( diff --git a/superset-frontend/src/views/CRUD/annotation/AnnotationModal.test.jsx b/superset-frontend/src/views/CRUD/annotation/AnnotationModal.test.jsx index 0b2f4cb9a697e..4ba95fe3bd20f 100644 --- a/superset-frontend/src/views/CRUD/annotation/AnnotationModal.test.jsx +++ b/superset-frontend/src/views/CRUD/annotation/AnnotationModal.test.jsx @@ -80,12 +80,12 @@ describe('AnnotationModal', () => { it('renders add header when no annotation prop is included', async () => { const addWrapper = await mountAndWait({}); expect( - addWrapper.find('[data-test="annotaion-modal-title"]').text(), + addWrapper.find('[data-test="annotation-modal-title"]').text(), ).toEqual('Add annotation'); }); it('renders edit header when annotation prop is included', () => { - expect(wrapper.find('[data-test="annotaion-modal-title"]').text()).toEqual( + expect(wrapper.find('[data-test="annotation-modal-title"]').text()).toEqual( 'Edit annotation', ); }); diff --git a/superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx b/superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx index 22af06241f77b..7aedad199f86a 100644 --- a/superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx +++ b/superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx @@ -32,7 +32,7 @@ import { AnnotationObject } from './types'; interface AnnotationModalProps { addDangerToast: (msg: string) => void; addSuccessToast: (msg: string) => void; - annnotationLayerId: number; + annotationLayerId: number; annotation?: AnnotationObject | null; onAnnotationAdd?: (annotation?: AnnotationObject) => void; onHide: () => void; @@ -84,7 +84,7 @@ const AnnotationContainer = styled.div` const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({ addDangerToast, addSuccessToast, - annnotationLayerId, + annotationLayerId, annotation = null, onAnnotationAdd, onHide, @@ -102,7 +102,7 @@ const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({ createResource, updateResource, } = useSingleViewResource<AnnotationObject>( - `annotation_layer/${annnotationLayerId}/annotation`, + `annotation_layer/${annotationLayerId}/annotation`, t('annotation'), addDangerToast, ); @@ -130,7 +130,7 @@ const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({ const onSave = () => { if (isEditMode) { // Edit - if (currentAnnotation && currentAnnotation.id) { + if (currentAnnotation?.id) { const update_id = currentAnnotation.id; delete currentAnnotation.id; delete currentAnnotation.created_by; @@ -217,10 +217,9 @@ const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({ const validate = () => { if ( - currentAnnotation && - currentAnnotation.short_descr?.length && - currentAnnotation.start_dttm?.length && - currentAnnotation.end_dttm?.length + currentAnnotation?.short_descr?.length && + currentAnnotation?.start_dttm?.length && + currentAnnotation?.end_dttm?.length ) { setDisableSave(false); } else { @@ -237,7 +236,7 @@ const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({ (annotation && annotation.id !== currentAnnotation.id) || show) ) { - if (annotation && annotation.id !== null && !loading) { + if (annotation?.id !== null && !loading) { const id = annotation.id || 0; fetchResource(id); @@ -274,7 +273,7 @@ const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({ show={show} width="55%" title={ - <h4 data-test="annotaion-modal-title"> + <h4 data-test="annotation-modal-title"> {isEditMode ? ( <Icons.EditAlt css={StyledIcon} /> ) : ( @@ -305,6 +304,7 @@ const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({ <span className="required">*</span> </div> <RangePicker + placeholder={[t('Start date'), t('End date')]} format="YYYY-MM-DD HH:mm" onChange={onDateChange} showTime={{ format: 'hh:mm a' }} @@ -337,7 +337,7 @@ const AnnotationModal: FunctionComponent<AnnotationModalProps> = ({ <StyledJsonEditor onChange={onJsonChange} value={ - currentAnnotation && currentAnnotation.json_metadata + currentAnnotation?.json_metadata ? currentAnnotation.json_metadata : '' } diff --git a/superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx b/superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx index a7b78de39a32c..7510ef51c9ba8 100644 --- a/superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx +++ b/superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx @@ -126,7 +126,7 @@ const AnnotationLayerModal: FunctionComponent<AnnotationLayerModalProps> = ({ const onSave = () => { if (isEditMode) { // Edit - if (currentLayer && currentLayer.id) { + if (currentLayer?.id) { const update_id = currentLayer.id; delete currentLayer.id; delete currentLayer.created_by; @@ -173,7 +173,7 @@ const AnnotationLayerModal: FunctionComponent<AnnotationLayerModalProps> = ({ }; const validate = () => { - if (currentLayer && currentLayer.name?.length) { + if (currentLayer?.name?.length) { setDisableSave(false); } else { setDisableSave(true); diff --git a/superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx b/superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx index 0265682dc7e6c..3f4e1cd66c0e5 100644 --- a/superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx +++ b/superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx @@ -143,12 +143,10 @@ function AnnotationLayersList({ } if (hasHistory) { - return ( - <Link to={`/annotationmodelview/${id}/annotation`}>{name}</Link> - ); + return <Link to={`/annotationlayer/${id}/annotation`}>{name}</Link>; } - return <a href={`/annotationmodelview/${id}/annotation`}>{name}</a>; + return <a href={`/annotationlayer/${id}/annotation`}>{name}</a>; }, }, { @@ -283,10 +281,11 @@ function AnnotationLayersList({ () => [ { Header: t('Created by'), + key: 'created_by', id: 'created_by', input: 'select', operator: FilterOperator.relationOneMany, - unfilteredLabel: 'All', + unfilteredLabel: t('All'), fetchSelects: createFetchRelated( 'annotation_layer', 'created_by', @@ -302,6 +301,7 @@ function AnnotationLayersList({ }, { Header: t('Search'), + key: 'search', id: 'name', input: 'search', operator: FilterOperator.contains, @@ -322,7 +322,7 @@ function AnnotationLayersList({ }; const onLayerAdd = (id?: number) => { - window.location.href = `/annotationmodelview/${id}/annotation`; + window.location.href = `/annotationlayer/${id}/annotation`; }; const onModalHide = () => { diff --git a/superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx b/superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx index 3248babb63cfb..63486973592cd 100644 --- a/superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx +++ b/superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx @@ -101,7 +101,7 @@ const CssTemplateModal: FunctionComponent<CssTemplateModalProps> = ({ const onSave = () => { if (isEditMode) { // Edit - if (currentCssTemplate && currentCssTemplate.id) { + if (currentCssTemplate?.id) { const update_id = currentCssTemplate.id; delete currentCssTemplate.id; delete currentCssTemplate.created_by; @@ -157,10 +157,8 @@ const CssTemplateModal: FunctionComponent<CssTemplateModalProps> = ({ const validate = () => { if ( - currentCssTemplate && - currentCssTemplate.template_name.length && - currentCssTemplate.css && - currentCssTemplate.css.length + currentCssTemplate?.template_name.length && + currentCssTemplate?.css?.length ) { setDisableSave(false); } else { @@ -174,10 +172,10 @@ const CssTemplateModal: FunctionComponent<CssTemplateModalProps> = ({ isEditMode && (!currentCssTemplate || !currentCssTemplate.id || - (cssTemplate && cssTemplate.id !== currentCssTemplate.id) || + (cssTemplate && cssTemplate?.id !== currentCssTemplate.id) || (isHidden && show)) ) { - if (cssTemplate && cssTemplate.id !== null && !loading) { + if (cssTemplate?.id !== null && !loading) { const id = cssTemplate.id || 0; fetchResource(id); diff --git a/superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx b/superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx index 4263d2214b535..253a4f4cdf1be 100644 --- a/superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx +++ b/superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx @@ -271,10 +271,11 @@ function CssTemplatesList({ () => [ { Header: t('Created by'), + key: 'created_by', id: 'created_by', input: 'select', operator: FilterOperator.relationOneMany, - unfilteredLabel: 'All', + unfilteredLabel: t('All'), fetchSelects: createFetchRelated( 'css_template', 'created_by', @@ -290,6 +291,7 @@ function CssTemplatesList({ }, { Header: t('Search'), + key: 'search', id: 'template_name', input: 'search', operator: FilterOperator.contains, diff --git a/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx b/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx index 2da9f45515336..0a46749a017ac 100644 --- a/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx +++ b/superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx @@ -19,11 +19,10 @@ import React from 'react'; import { Link, useHistory } from 'react-router-dom'; import { t, useTheme } from '@superset-ui/core'; -import { handleDashboardDelete, CardStyles } from 'src/views/CRUD/utils'; +import { CardStyles } from 'src/views/CRUD/utils'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import { AntdDropdown } from 'src/components'; import { Menu } from 'src/components/Menu'; -import ConfirmStatusChange from 'src/components/ConfirmStatusChange'; import ListViewCard from 'src/components/ListViewCard'; import Icons from 'src/components/Icons'; import Label from 'src/components/Label'; @@ -36,33 +35,27 @@ interface DashboardCardProps { dashboard: Dashboard; hasPerm: (name: string) => boolean; bulkSelectEnabled: boolean; - refreshData: () => void; loading: boolean; - addDangerToast: (msg: string) => void; - addSuccessToast: (msg: string) => void; openDashboardEditModal?: (d: Dashboard) => void; saveFavoriteStatus: (id: number, isStarred: boolean) => void; favoriteStatus: boolean; - dashboardFilter?: string; userId?: string | number; showThumbnails?: boolean; handleBulkDashboardExport: (dashboardsToExport: Dashboard[]) => void; + onDelete: (dashboard: Dashboard) => void; } function DashboardCard({ dashboard, hasPerm, bulkSelectEnabled, - dashboardFilter, - refreshData, userId, - addDangerToast, - addSuccessToast, openDashboardEditModal, favoriteStatus, saveFavoriteStatus, showThumbnails, handleBulkDashboardExport, + onDelete, }: DashboardCardProps) { const history = useHistory(); const canEdit = hasPerm('can_write'); @@ -78,9 +71,7 @@ function DashboardCard({ role="button" tabIndex={0} className="action-button" - onClick={() => - openDashboardEditModal && openDashboardEditModal(dashboard) - } + onClick={() => openDashboardEditModal?.(dashboard)} data-test="dashboard-card-option-edit-button" > <Icons.EditAlt iconSize="l" data-test="edit-alt" /> {t('Edit')} @@ -102,37 +93,15 @@ function DashboardCard({ )} {canDelete && ( <Menu.Item> - <ConfirmStatusChange - title={t('Please confirm')} - description={ - <> - {t('Are you sure you want to delete')}{' '} - <b>{dashboard.dashboard_title}</b>? - </> - } - onConfirm={() => - handleDashboardDelete( - dashboard, - refreshData, - addSuccessToast, - addDangerToast, - dashboardFilter, - userId, - ) - } + <div + role="button" + tabIndex={0} + className="action-button" + onClick={() => onDelete(dashboard)} + data-test="dashboard-card-option-delete-button" > - {confirmDelete => ( - <div - role="button" - tabIndex={0} - className="action-button" - onClick={confirmDelete} - data-test="dashboard-card-option-delete-button" - > - <Icons.Trash iconSize="l" /> {t('Delete')} - </div> - )} - </ConfirmStatusChange> + <Icons.Trash iconSize="l" /> {t('Delete')} + </div> </Menu.Item> )} </Menu> diff --git a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx index 8569f840d3688..d892b24fa1b9c 100644 --- a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx +++ b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx @@ -42,14 +42,16 @@ import Owner from 'src/types/Owner'; import withToasts from 'src/components/MessageToasts/withToasts'; import FacePile from 'src/components/FacePile'; import Icons from 'src/components/Icons'; +import DeleteModal from 'src/components/DeleteModal'; import FaveStar from 'src/components/FaveStar'; import PropertiesModal from 'src/dashboard/components/PropertiesModal'; import { Tooltip } from 'src/components/Tooltip'; import ImportModelsModal from 'src/components/ImportModal/index'; import Dashboard from 'src/dashboard/containers/Dashboard'; +import { Dashboard as CRUDDashboard } from 'src/views/CRUD/types'; import CertifiedBadge from 'src/components/CertifiedBadge'; -import { bootstrapData } from 'src/preamble'; +import getBootstrapData from 'src/utils/getBootstrapData'; import DashboardCard from './DashboardCard'; import { DashboardStatus } from './types'; @@ -95,6 +97,8 @@ const Actions = styled.div` color: ${({ theme }) => theme.colors.grayscale.base}; `; +const bootstrapData = getBootstrapData(); + function DashboardList(props: DashboardListProps) { const { addDangerToast, @@ -129,6 +133,8 @@ function DashboardList(props: DashboardListProps) { const [dashboardToEdit, setDashboardToEdit] = useState<Dashboard | null>( null, ); + const [dashboardToDelete, setDashboardToDelete] = + useState<CRUDDashboard | null>(null); const [importingDashboard, showImportModal] = useState<boolean>(false); const [passwordFields, setPasswordFields] = useState<string[]>([]); @@ -184,6 +190,7 @@ function DashboardList(props: DashboardListProps) { url = '', certified_by = '', certification_details = '', + owners, } = json.result; return { ...dashboard, @@ -197,6 +204,7 @@ function DashboardList(props: DashboardListProps) { url, certified_by, certification_details, + owners, }; } return dashboard; @@ -447,6 +455,7 @@ function DashboardList(props: DashboardListProps) { const favoritesFilter: Filter = useMemo( () => ({ Header: t('Favorite'), + key: 'favorite', id: 'id', urlDisplay: 'favorite', input: 'select', @@ -462,8 +471,16 @@ function DashboardList(props: DashboardListProps) { const filters: Filters = useMemo( () => [ + { + Header: t('Search'), + key: 'search', + id: 'dashboard_title', + input: 'search', + operator: FilterOperator.titleOrSlug, + }, { Header: t('Owner'), + key: 'owner', id: 'owners', input: 'select', operator: FilterOperator.relationManyMany, @@ -485,6 +502,7 @@ function DashboardList(props: DashboardListProps) { }, { Header: t('Created by'), + key: 'created_by', id: 'created_by', input: 'select', operator: FilterOperator.relationOneMany, @@ -506,6 +524,7 @@ function DashboardList(props: DashboardListProps) { }, { Header: t('Status'), + key: 'published', id: 'published', input: 'select', operator: FilterOperator.equals, @@ -518,6 +537,7 @@ function DashboardList(props: DashboardListProps) { ...(userId ? [favoritesFilter] : []), { Header: t('Certified'), + key: 'certified', id: 'id', urlDisplay: 'certified', input: 'select', @@ -528,12 +548,6 @@ function DashboardList(props: DashboardListProps) { { label: t('No'), value: false }, ], }, - { - Header: t('Search'), - id: 'dashboard_title', - input: 'search', - operator: FilterOperator.titleOrSlug, - }, ], [addDangerToast, favoritesFilter, props.user], ); @@ -565,7 +579,6 @@ function DashboardList(props: DashboardListProps) { dashboard={dashboard} hasPerm={hasPerm} bulkSelectEnabled={bulkSelectEnabled} - refreshData={refreshData} showThumbnails={ userKey ? userKey.thumbnails @@ -573,23 +586,19 @@ function DashboardList(props: DashboardListProps) { } userId={userId} loading={loading} - addDangerToast={addDangerToast} - addSuccessToast={addSuccessToast} openDashboardEditModal={openDashboardEditModal} saveFavoriteStatus={saveFavoriteStatus} favoriteStatus={favoriteStatus[dashboard.id]} handleBulkDashboardExport={handleBulkDashboardExport} + onDelete={dashboard => setDashboardToDelete(dashboard)} /> ), [ - addDangerToast, - addSuccessToast, bulkSelectEnabled, favoriteStatus, hasPerm, loading, userId, - refreshData, saveFavoriteStatus, userKey, ], @@ -671,6 +680,30 @@ function DashboardList(props: DashboardListProps) { onSubmit={handleDashboardEdit} /> )} + {dashboardToDelete && ( + <DeleteModal + description={ + <> + {t('Are you sure you want to delete')}{' '} + <b>{dashboardToDelete.dashboard_title}</b>? + </> + } + onConfirm={() => { + handleDashboardDelete( + dashboardToDelete, + refreshData, + addSuccessToast, + addDangerToast, + undefined, + userId, + ); + setDashboardToDelete(null); + }} + onHide={() => setDashboardToDelete(null)} + open={!!dashboardToDelete} + title={t('Please confirm')} + /> + )} <ListView<Dashboard> bulkActions={bulkActions} bulkSelectEnabled={bulkSelectEnabled} diff --git a/superset-frontend/src/views/CRUD/data/common.ts b/superset-frontend/src/views/CRUD/data/common.ts index c6708c4511775..634176145b76d 100644 --- a/superset-frontend/src/views/CRUD/data/common.ts +++ b/superset-frontend/src/views/CRUD/data/common.ts @@ -19,20 +19,8 @@ import { t } from '@superset-ui/core'; export const commonMenuData = { - name: t('Data'), + name: t('SQL'), tabs: [ - { - name: 'Databases', - label: t('Databases'), - url: '/databaseview/list/', - usesRouter: true, - }, - { - name: 'Datasets', - label: t('Datasets'), - url: '/tablemodelview/list/', - usesRouter: true, - }, { name: 'Saved queries', label: t('Saved queries'), diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx b/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx index 1cc66ef9e3c97..f6fc0481f6521 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseList.test.jsx @@ -131,23 +131,27 @@ describe('Admin DatabaseList', () => { await waitForComponentToPaint(wrapper); }); - it('renders', () => { + test('renders', () => { expect(wrapper.find(DatabaseList)).toExist(); }); - it('renders a SubMenu', () => { + test('renders a SubMenu', () => { expect(wrapper.find(SubMenu)).toExist(); }); - it('renders a DatabaseModal', () => { + test('renders a SubMenu with no tabs', () => { + expect(wrapper.find(SubMenu).props().tabs).toBeUndefined(); + }); + + test('renders a DatabaseModal', () => { expect(wrapper.find(DatabaseModal)).toExist(); }); - it('renders a ListView', () => { + test('renders a ListView', () => { expect(wrapper.find(ListView)).toExist(); }); - it('fetches Databases', () => { + test('fetches Databases', () => { const callsD = fetchMock.calls(/database\/\?q/); expect(callsD).toHaveLength(2); expect(callsD[0][0]).toMatchInlineSnapshot( @@ -155,7 +159,7 @@ describe('Admin DatabaseList', () => { ); }); - it('deletes', async () => { + test('deletes', async () => { act(() => { wrapper.find('[data-test="database-delete"]').first().props().onClick(); }); @@ -185,7 +189,7 @@ describe('Admin DatabaseList', () => { expect(fetchMock.calls(/database\/0/, 'DELETE')).toHaveLength(1); }); - it('filters', async () => { + test('filters', async () => { const filtersWrapper = wrapper.find(Filters); act(() => { filtersWrapper @@ -213,7 +217,7 @@ describe('Admin DatabaseList', () => { ); }); - it('should not render dropdown menu button if user is not admin', () => { + test('should not render dropdown menu button if user is not admin', async () => { userSelectorMock.mockReturnValue({ createdOn: '2021-05-27T18:12:38.952304', email: 'alpha@gmail.com', @@ -236,6 +240,8 @@ describe('Admin DatabaseList', () => { <DatabaseList /> </Provider>, ); + await waitForComponentToPaint(newWrapper); + expect(newWrapper.find('.dropdown-menu-links')).not.toExist(); }); }); diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx index dc9dc1a279145..00f207ba7a84c 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx @@ -21,6 +21,7 @@ import React, { useState, useMemo, useEffect } from 'react'; import rison from 'rison'; import { useSelector } from 'react-redux'; import { useQueryParams, BooleanParam } from 'use-query-params'; +import { LocalStorageKeys, setItem } from 'src/utils/localStorageHelpers'; import Loading from 'src/components/Loading'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; @@ -29,15 +30,16 @@ import { createErrorHandler, uploadUserPerms } from 'src/views/CRUD/utils'; import withToasts from 'src/components/MessageToasts/withToasts'; import SubMenu, { SubMenuProps } from 'src/views/components/SubMenu'; import DeleteModal from 'src/components/DeleteModal'; +import { getUrlParam } from 'src/utils/urlUtils'; +import { URL_PARAMS } from 'src/constants'; import { Tooltip } from 'src/components/Tooltip'; import Icons from 'src/components/Icons'; -import { isUserAdmin } from 'src/dashboard/util/findPermission'; +import { isUserAdmin } from 'src/dashboard/util/permissionUtils'; import ListView, { FilterOperator, Filters } from 'src/components/ListView'; -import { commonMenuData } from 'src/views/CRUD/data/common'; import handleResourceExport from 'src/utils/export'; -import { ExtentionConfigs } from 'src/views/components/types'; +import { ExtensionConfigs } from 'src/views/components/types'; import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; -import type { MenuObjectProps } from 'src/views/components/Menu'; +import type { MenuObjectProps } from 'src/types/bootstrapTypes'; import DatabaseModal from './DatabaseModal'; import { DatabaseObject } from './types'; @@ -93,12 +95,15 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) { const user = useSelector<any, UserWithPermissionsAndRoles>( state => state.user, ); + const showDatabaseModal = getUrlParam(URL_PARAMS.showDatabaseModal); const [query, setQuery] = useQueryParams({ databaseAdded: BooleanParam, }); - const [databaseModalOpen, setDatabaseModalOpen] = useState<boolean>(false); + const [databaseModalOpen, setDatabaseModalOpen] = useState<boolean>( + showDatabaseModal || false, + ); const [databaseCurrentlyDeleting, setDatabaseCurrentlyDeleting] = useState<DatabaseDeleteObject | null>(null); const [currentDatabase, setCurrentDatabase] = useState<DatabaseObject | null>( @@ -115,7 +120,7 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) { COLUMNAR_EXTENSIONS, EXCEL_EXTENSIONS, ALLOWED_EXTENSIONS, - } = useSelector<any, ExtentionConfigs>(state => state.common.conf); + } = useSelector<any, ExtensionConfigs>(state => state.common.conf); useEffect(() => { if (query?.databaseAdded) { @@ -153,6 +158,9 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) { refreshData(); addSuccessToast(t('Deleted: %s', dbName)); + // Delete user-selected db from local storage + setItem(LocalStorageKeys.db, null); + // Close delete modal setDatabaseCurrentlyDeleting(null); }, @@ -225,7 +233,13 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) { SupersetClient.get({ endpoint: `/api/v1/database/?q=${rison.encode(payload)}`, }).then(({ json }: Record<string, any>) => { - setAllowUploads(json.count >= 1); + // There might be some existings Gsheets and Clickhouse DBs + // with allow_file_upload set as True which is not possible from now on + const allowedDatabasesWithFileUpload = + json?.result?.filter( + (database: any) => database?.engine_information?.supports_file_upload, + ) || []; + setAllowUploads(allowedDatabasesWithFileUpload?.length >= 1); }); }; @@ -242,7 +256,7 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) { const menuData: SubMenuProps = { activeChild: 'Databases', dropDownLinks: filteredDropDown, - ...commonMenuData, + name: t('Databases'), }; if (canCreate) { @@ -445,13 +459,14 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) { () => [ { Header: t('Expose in SQL Lab'), + key: 'expose_in_sql_lab', id: 'expose_in_sqllab', input: 'select', operator: FilterOperator.equals, - unfilteredLabel: 'All', + unfilteredLabel: t('All'), selects: [ - { label: 'Yes', value: true }, - { label: 'No', value: false }, + { label: t('Yes'), value: true }, + { label: t('No'), value: false }, ], }, { @@ -464,17 +479,19 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) { <span>{t('AQE')}</span> </Tooltip> ), + key: 'allow_run_async', id: 'allow_run_async', input: 'select', operator: FilterOperator.equals, - unfilteredLabel: 'All', + unfilteredLabel: t('All'), selects: [ - { label: 'Yes', value: true }, - { label: 'No', value: false }, + { label: t('Yes'), value: true }, + { label: t('No'), value: false }, ], }, { Header: t('Search'), + key: 'search', id: 'database_name', input: 'search', operator: FilterOperator.contains, diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx index 34c21466bec8d..99a414012b779 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx @@ -66,16 +66,40 @@ export const portField = ({ errorMessage={validationErrors?.port} placeholder={t('e.g. 5432')} className="form-group-w-50" - label="Port" + label={t('Port')} onChange={changeMethods.onParametersChange} /> </> ); +export const httpPath = ({ + required, + changeMethods, + getValidation, + validationErrors, + db, +}: FieldPropTypes) => { + const extraJson = JSON.parse(db?.extra || '{}'); + return ( + <ValidatedInput + id="http_path" + name="http_path" + required={required} + value={extraJson.engine_params?.connect_args?.http_path} + validationMethods={{ onBlur: getValidation }} + errorMessage={validationErrors?.http_path} + placeholder={t('e.g. sql/protocolv1/o/12345')} + label="HTTP Path" + onChange={changeMethods.onExtraInputChange} + helpText={t('Copy the name of the HTTP Path of your cluster.')} + /> + ); +}; export const databaseField = ({ required, changeMethods, getValidation, validationErrors, + placeholder, db, }: FieldPropTypes) => ( <ValidatedInput @@ -85,10 +109,10 @@ export const databaseField = ({ value={db?.parameters?.database} validationMethods={{ onBlur: getValidation }} errorMessage={validationErrors?.database} - placeholder={t('e.g. world_population')} + placeholder={placeholder ?? t('e.g. world_population')} label={t('Database name')} onChange={changeMethods.onParametersChange} - helpText={t('Copy the name of the database you are trying to connect to.')} + helpText={t('Copy the name of the database you are trying to connect to.')} /> ); export const usernameField = ({ @@ -131,6 +155,27 @@ export const passwordField = ({ onChange={changeMethods.onParametersChange} /> ); +export const accessTokenField = ({ + required, + changeMethods, + getValidation, + validationErrors, + db, + isEditMode, +}: FieldPropTypes) => ( + <ValidatedInput + id="access_token" + name="access_token" + required={required} + visibilityToggle={!isEditMode} + value={db?.parameters?.access_token} + validationMethods={{ onBlur: getValidation }} + errorMessage={validationErrors?.access_token} + placeholder={t('e.g. ********')} + label={t('Access token')} + onChange={changeMethods.onParametersChange} + /> +); export const displayField = ({ changeMethods, getValidation, @@ -149,7 +194,7 @@ export const displayField = ({ label={t('Display Name')} onChange={changeMethods.onChange} helpText={t( - 'Pick a nickname for this database to display as in Superset.', + 'Pick a nickname for how the database will display in Superset.', )} /> </> diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx index d4817d68b4415..0125fd36d5128 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx @@ -21,9 +21,9 @@ import { SupersetTheme, t } from '@superset-ui/core'; import { AntdButton, AntdSelect } from 'src/components'; import InfoTooltip from 'src/components/InfoTooltip'; import FormLabel from 'src/components/Form/FormLabel'; -import { DeleteFilled } from '@ant-design/icons'; +import Icons from 'src/components/Icons'; import { FieldPropTypes } from '.'; -import { infoTooltip, labelMarginBotton, CredentialInfoForm } from '../styles'; +import { infoTooltip, labelMarginBottom, CredentialInfoForm } from '../styles'; enum CredentialInfoOptions { jsonUpload, @@ -55,8 +55,7 @@ export const EncryptedField = ({ const [isPublic, setIsPublic] = useState<boolean>(true); const showCredentialsInfo = db?.engine === 'gsheets' ? !isEditMode && !isPublic : !isEditMode; - // a database that has an optional encrypted field has an encrypted_extra that is an empty object, this checks for that. - const isEncrypted = isEditMode && db?.encrypted_extra !== '{}'; + const isEncrypted = isEditMode && db?.masked_encrypted_extra !== '{}'; const encryptedField = db?.engine && encryptedCredentialsMap[db.engine]; const encryptedValue = typeof db?.parameters?.[encryptedField] === 'object' @@ -67,7 +66,7 @@ export const EncryptedField = ({ {db?.engine === 'gsheets' && ( <div className="catalog-type-select"> <FormLabel - css={(theme: SupersetTheme) => labelMarginBotton(theme)} + css={(theme: SupersetTheme) => labelMarginBottom(theme)} required > {t('Type of Google Sheets allowed')} @@ -118,7 +117,9 @@ export const EncryptedField = ({ name={encryptedField} value={encryptedValue} onChange={changeMethods.onParametersChange} - placeholder="Paste content of service credentials JSON file here" + placeholder={t( + 'Paste content of service credentials JSON file here', + )} /> <span className="label-paste"> {t('Copy and paste the entire service account .json file here')} @@ -153,7 +154,8 @@ export const EncryptedField = ({ {fileToUpload && ( <div className="input-upload-current"> {fileToUpload} - <DeleteFilled + <Icons.DeleteFilled + iconSize="m" onClick={() => { setFileToUpload(null); changeMethods.onParametersChange({ @@ -169,6 +171,7 @@ export const EncryptedField = ({ <input id="selectedFile" + accept=".json" className="input-upload" type="file" onChange={async event => { diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx index fb70b9c3652a1..ed5cc94903f2b 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx @@ -17,10 +17,10 @@ * under the License. */ import React from 'react'; -import { t } from '@superset-ui/core'; +import { css, SupersetTheme, t } from '@superset-ui/core'; import ValidatedInput from 'src/components/Form/LabeledErrorBoundInput'; import FormLabel from 'src/components/Form/FormLabel'; -import { CloseOutlined } from '@ant-design/icons'; +import Icons from 'src/components/Icons'; import { FieldPropTypes } from '.'; import { StyledFooterButton, StyledCatalogTable } from '../styles'; import { CatalogObject } from '../../types'; @@ -64,8 +64,17 @@ export const TableCatalog = ({ value={sheet.name} /> {tableCatalog?.length > 1 && ( - <CloseOutlined - className="catalog-delete" + <Icons.CloseOutlined + css={(theme: SupersetTheme) => css` + align-self: center; + background: ${theme.colors.grayscale.light4}; + margin: 5px 5px 8px 5px; + + &.anticon > * { + line-height: 0; + } + `} + iconSize="m" onClick={() => changeMethods.onRemoveTableCatalog(idx)} /> )} diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx index 93ba1f2d1ffe9..a00b3ba9354e9 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx @@ -26,14 +26,14 @@ const FIELD_TEXT_MAP = { helpText: t( 'Copy the account name of that database you are trying to connect to.', ), - placeholder: 'e.g. world_population', + placeholder: t('e.g. world_population'), }, warehouse: { - placeholder: 'e.g. compute_wh', + placeholder: t('e.g. compute_wh'), className: 'form-group-w-50', }, role: { - placeholder: 'e.g. AccountAdmin', + placeholder: t('e.g. AccountAdmin'), className: 'form-group-w-50', }, }; diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/index.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/index.tsx index 84108e40dcc65..f6284ae67d9a7 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/index.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/index.tsx @@ -21,14 +21,16 @@ import { SupersetTheme, JsonObject } from '@superset-ui/core'; import { InputProps } from 'antd/lib/input'; import { Form } from 'src/components/Form'; import { - hostField, - portField, + accessTokenField, databaseField, - usernameField, - passwordField, displayField, - queryField, forceSSLField, + hostField, + httpPath, + passwordField, + portField, + queryField, + usernameField, } from './CommonParameters'; import { validatedInputField } from './ValidatedInputField'; import { EncryptedField } from './EncryptedField'; @@ -42,6 +44,8 @@ export const FormFieldOrder = [ 'database', 'username', 'password', + 'access_token', + 'http_path', 'database_name', 'credentials_info', 'service_account_info', @@ -57,6 +61,7 @@ export interface FieldPropTypes { required: boolean; hasTooltip?: boolean; tooltipText?: (value: any) => string; + placeholder?: string; onParametersChange: (value: any) => string; onParametersUploadFileChange: (value: any) => string; changeMethods: { onParametersChange: (value: any) => string } & { @@ -66,6 +71,9 @@ export interface FieldPropTypes { } & { onParametersUploadFileChange: (value: any) => string } & { onAddTableCatalog: () => void; onRemoveTableCatalog: (idx: number) => void; + } & { + onExtraInputChange: (value: any) => void; + onSSHTunnelParametersChange: (value: any) => string; }; validationErrors: JsonObject | null; getValidation: () => void; @@ -79,10 +87,12 @@ export interface FieldPropTypes { const FORM_FIELD_MAP = { host: hostField, + http_path: httpPath, port: portField, database: databaseField, username: usernameField, password: passwordField, + access_token: accessTokenField, database_name: displayField, query: queryField, encryption: forceSSLField, @@ -94,21 +104,7 @@ const FORM_FIELD_MAP = { account: validatedInputField, }; -const DatabaseConnectionForm = ({ - dbModel: { parameters }, - onParametersChange, - onChange, - onQueryChange, - onParametersUploadFileChange, - onAddTableCatalog, - onRemoveTableCatalog, - validationErrors, - getValidation, - db, - isEditMode = false, - sslForced, - editNewDb, -}: { +interface DatabaseConnectionFormProps { isEditMode?: boolean; sslForced: boolean; editNewDb?: boolean; @@ -126,11 +122,33 @@ const DatabaseConnectionForm = ({ onParametersUploadFileChange?: ( event: FormEvent<InputProps> | { target: HTMLInputElement }, ) => void; + onExtraInputChange: ( + event: FormEvent<InputProps> | { target: HTMLInputElement }, + ) => void; onAddTableCatalog: () => void; onRemoveTableCatalog: (idx: number) => void; validationErrors: JsonObject | null; getValidation: () => void; -}) => ( + getPlaceholder?: (field: string) => string | undefined; +} + +const DatabaseConnectionForm = ({ + dbModel: { parameters }, + db, + editNewDb, + getPlaceholder, + getValidation, + isEditMode = false, + onAddTableCatalog, + onChange, + onExtraInputChange, + onParametersChange, + onParametersUploadFileChange, + onQueryChange, + onRemoveTableCatalog, + sslForced, + validationErrors, +}: DatabaseConnectionFormProps) => ( <Form> <div // @ts-ignore @@ -154,6 +172,7 @@ const DatabaseConnectionForm = ({ onParametersUploadFileChange, onAddTableCatalog, onRemoveTableCatalog, + onExtraInputChange, }, validationErrors, getValidation, @@ -163,6 +182,7 @@ const DatabaseConnectionForm = ({ isEditMode, sslForced, editNewDb, + placeholder: getPlaceholder ? getPlaceholder(field) : undefined, }), )} </div> diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx index 12a712fa35b52..f50d7597f2fce 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx @@ -29,7 +29,7 @@ import { antdCollapseStyles, no_margin_bottom, } from './styles'; -import { DatabaseObject } from '../types'; +import { DatabaseObject, ExtraJson } from '../types'; const ExtraOptions = ({ db, @@ -48,6 +48,18 @@ const ExtraOptions = ({ }) => { const expandableModalIsOpen = !!db?.expose_in_sqllab; const createAsOpen = !!(db?.allow_ctas || db?.allow_cvas); + const isFileUploadSupportedByEngine = + db?.engine_information?.supports_file_upload; + + // JSON.parse will deep parse engine_params + // if it's an object, and we want to keep it a string + const extraJson: ExtraJson = JSON.parse(db?.extra || '{}', (key, value) => { + if (key === 'engine_params' && typeof value === 'object') { + // keep this as a string + return JSON.stringify(value); + } + return value; + }); return ( <Collapse @@ -58,9 +70,9 @@ const ExtraOptions = ({ <Collapse.Panel header={ <div> - <h4>SQL Lab</h4> + <h4>{t('SQL Lab')}</h4> <p className="helper"> - Adjust how this database will interact with SQL Lab. + {t('Adjust how this database will interact with SQL Lab.')} </p> </div> } @@ -120,9 +132,9 @@ const ExtraOptions = ({ <input type="text" name="force_ctas_schema" - value={db?.force_ctas_schema || ''} placeholder={t('Create or select schema...')} onChange={onInputChange} + value={db?.force_ctas_schema || ''} /> </div> <div className="helper"> @@ -148,36 +160,18 @@ const ExtraOptions = ({ /> </div> </StyledInputContainer> - <StyledInputContainer css={no_margin_bottom}> - <div className="input-container"> - <IndeterminateCheckbox - id="allow_multi_schema_metadata_fetch" - indeterminate={false} - checked={!!db?.allow_multi_schema_metadata_fetch} - onChange={onInputChange} - labelText={t('Allow Multi Schema Metadata Fetch')} - /> - <InfoTooltip - tooltip={t( - 'Allow SQL Lab to fetch a list of all tables and all views across all database ' + - 'schemas. For large data warehouse with thousands of tables, this can be ' + - 'expensive and put strain on the system.', - )} - /> - </div> - </StyledInputContainer> <StyledInputContainer css={no_margin_bottom}> <div className="input-container"> <IndeterminateCheckbox id="cost_estimate_enabled" indeterminate={false} - checked={!!db?.extra_json?.cost_estimate_enabled} + checked={!!extraJson?.cost_estimate_enabled} onChange={onExtraInputChange} labelText={t('Enable query cost estimation')} /> <InfoTooltip tooltip={t( - 'For Presto and Postgres, shows a button to compute cost before running a query.', + 'For Bigquery, Presto and Postgres, shows a button to compute cost before running a query.', )} /> </div> @@ -187,7 +181,7 @@ const ExtraOptions = ({ <IndeterminateCheckbox id="allows_virtual_table_explore" indeterminate={false} - checked={!!db?.extra_json?.allows_virtual_table_explore} + checked={!!extraJson?.allows_virtual_table_explore} onChange={onExtraInputChange} labelText={t('Allow this database to be explored')} /> @@ -203,7 +197,7 @@ const ExtraOptions = ({ <IndeterminateCheckbox id="disable_data_preview" indeterminate={false} - checked={!!db?.extra_json?.disable_data_preview} + checked={!!extraJson?.disable_data_preview} onChange={onExtraInputChange} labelText={t('Disable SQL Lab data preview queries')} /> @@ -222,9 +216,9 @@ const ExtraOptions = ({ <Collapse.Panel header={ <div> - <h4>Performance</h4> + <h4>{t('Performance')}</h4> <p className="helper"> - Adjust performance settings of this database. + {t('Adjust performance settings of this database.')} </p> </div> } @@ -256,8 +250,7 @@ const ExtraOptions = ({ type="number" name="schema_cache_timeout" value={ - db?.extra_json?.metadata_cache_timeout?.schema_cache_timeout || - '' + extraJson?.metadata_cache_timeout?.schema_cache_timeout || '' } placeholder={t('Enter duration in seconds')} onChange={onExtraInputChange} @@ -278,8 +271,7 @@ const ExtraOptions = ({ type="number" name="table_cache_timeout" value={ - db?.extra_json?.metadata_cache_timeout?.table_cache_timeout || - '' + extraJson?.metadata_cache_timeout?.table_cache_timeout || '' } placeholder={t('Enter duration in seconds')} onChange={onExtraInputChange} @@ -317,7 +309,7 @@ const ExtraOptions = ({ <IndeterminateCheckbox id="cancel_query_on_windows_unload" indeterminate={false} - checked={!!db?.extra_json?.cancel_query_on_windows_unload} + checked={!!extraJson?.cancel_query_on_windows_unload} onChange={onExtraInputChange} labelText={t('Cancel query on window unload event')} /> @@ -334,8 +326,8 @@ const ExtraOptions = ({ <Collapse.Panel header={ <div> - <h4>Security</h4> - <p className="helper">Add extra connection information.</p> + <h4>{t('Security')}</h4> + <p className="helper">{t('Add extra connection information.')}</p> </div> } key="3" @@ -344,11 +336,11 @@ const ExtraOptions = ({ <div className="control-label">{t('Secure extra')}</div> <div className="input-container"> <StyledJsonEditor - name="encrypted_extra" - value={db?.encrypted_extra || ''} + name="masked_encrypted_extra" + value={db?.masked_encrypted_extra || ''} placeholder={t('Secure extra')} onChange={(json: string) => - onEditorChange({ json, name: 'encrypted_extra' }) + onEditorChange({ json, name: 'masked_encrypted_extra' }) } width="100%" height="160px" @@ -382,28 +374,9 @@ const ExtraOptions = ({ )} </div> </StyledInputContainer> - <StyledInputContainer> - <div className="control-label"> - {t('Schemas allowed for CSV upload')} - </div> - <div className="input-container"> - <input - type="text" - name="schemas_allowed_for_file_upload" - value={( - db?.extra_json?.schemas_allowed_for_file_upload || [] - ).join(',')} - placeholder="schema1,schema2" - onChange={onExtraInputChange} - /> - </div> - <div className="helper"> - {t( - 'A comma-separated list of schemas that CSVs are allowed to upload to.', - )} - </div> - </StyledInputContainer> - <StyledInputContainer css={{ no_margin_bottom }}> + <StyledInputContainer + css={!isFileUploadSupportedByEngine ? no_margin_bottom : {}} + > <div className="input-container"> <IndeterminateCheckbox id="impersonate_user" @@ -425,28 +398,50 @@ const ExtraOptions = ({ /> </div> </StyledInputContainer> - <StyledInputContainer css={{ ...no_margin_bottom }}> - <div className="input-container"> - <IndeterminateCheckbox - id="allow_file_upload" - indeterminate={false} - checked={!!db?.allow_file_upload} - onChange={onInputChange} - labelText={t('Allow data upload')} - /> - <InfoTooltip - tooltip={t( - 'If selected, please set the schemas allowed for data upload in Extra.', + {isFileUploadSupportedByEngine && ( + <StyledInputContainer + css={!db?.allow_file_upload ? no_margin_bottom : {}} + > + <div className="input-container"> + <IndeterminateCheckbox + id="allow_file_upload" + indeterminate={false} + checked={!!db?.allow_file_upload} + onChange={onInputChange} + labelText={t('Allow file uploads to database')} + /> + </div> + </StyledInputContainer> + )} + {isFileUploadSupportedByEngine && !!db?.allow_file_upload && ( + <StyledInputContainer css={no_margin_bottom}> + <div className="control-label"> + {t('Schemas allowed for File upload')} + </div> + <div className="input-container"> + <input + type="text" + name="schemas_allowed_for_file_upload" + value={(extraJson?.schemas_allowed_for_file_upload || []).join( + ',', + )} + placeholder="schema1,schema2" + onChange={onExtraInputChange} + /> + </div> + <div className="helper"> + {t( + 'A comma-separated list of schemas that files are allowed to upload to.', )} - /> - </div> - </StyledInputContainer> + </div> + </StyledInputContainer> + )} </Collapse.Panel> <Collapse.Panel header={ <div> - <h4>Other</h4> - <p className="helper">Additional settings.</p> + <h4>{t('Other')}</h4> + <p className="helper">{t('Additional settings.')}</p> </div> } key="4" @@ -456,13 +451,17 @@ const ExtraOptions = ({ <div className="input-container"> <StyledJsonEditor name="metadata_params" - value={db?.extra_json?.metadata_params || ''} placeholder={t('Metadata Parameters')} onChange={(json: string) => onExtraEditorChange({ json, name: 'metadata_params' }) } width="100%" height="160px" + defaultValue={ + !Object.keys(extraJson?.metadata_params || {}).length + ? '' + : extraJson?.metadata_params + } /> </div> <div className="helper"> @@ -478,13 +477,17 @@ const ExtraOptions = ({ <div className="input-container"> <StyledJsonEditor name="engine_params" - value={db?.extra_json?.engine_params || ''} placeholder={t('Engine Parameters')} onChange={(json: string) => onExtraEditorChange({ json, name: 'engine_params' }) } width="100%" height="160px" + defaultValue={ + !Object.keys(extraJson?.engine_params || {}).length + ? '' + : extraJson?.engine_params + } /> </div> <div className="helper"> @@ -503,9 +506,9 @@ const ExtraOptions = ({ <input type="number" name="version" - value={db?.extra_json?.version || ''} placeholder={t('Version number')} onChange={onExtraInputChange} + value={extraJson?.version || ''} /> </div> <div className="helper"> diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx index 7cdcbaba281eb..9825489a7b80a 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx @@ -20,6 +20,7 @@ import React from 'react'; import { getDatabaseDocumentationLinks } from 'src/views/CRUD/hooks'; import { UploadFile } from 'antd/lib/upload/interface'; +import { t } from '@superset-ui/core'; import { EditHeaderTitle, EditHeaderSubtitle, @@ -88,16 +89,21 @@ const ModalHeader = ({ const useSqlAlchemyFormHeader = ( <StyledFormHeader> - <p className="helper-top"> STEP 2 OF 2 </p> - <h4>Enter Primary Credentials</h4> + <p className="helper-top"> + {t('STEP %(stepCurr)s OF %(stepLast)s', { + stepCurr: 2, + stepLast: 2, + })} + </p> + <h4>{t('Enter Primary Credentials')}</h4> <p className="helper-bottom"> - Need help? Learn how to connect your database{' '} + {t('Need help? Learn how to connect your database')}{' '} <a href={supersetTextDocs?.default || DOCUMENTATION_LINK} target="_blank" rel="noopener noreferrer" > - here + {t('here')} </a> . </p> @@ -107,20 +113,16 @@ const ModalHeader = ({ const hasConnectedDbHeader = ( <StyledStickyHeader> <StyledFormHeader> - <p className="helper-top"> STEP 3 OF 3 </p> - <h4 className="step-3-text"> - Your database was successfully connected! Here are some optional - settings for your database - </h4> - <p className="helper-bottom"> - Need help? Learn more about{' '} - <a - href={documentationLink(db?.engine)} - target="_blank" - rel="noopener noreferrer" - > - connecting to {dbModel.name}. - </a> + <p className="helper-top"> + {t('STEP %(stepCurr)s OF %(stepLast)s', { + stepCurr: 3, + stepLast: 3, + })} + </p> + <h4 className="step-3-text">{t('Database connected')}</h4> + <p className="subheader-text"> + {t(`Create a dataset to begin visualizing your data as a chart or go to + SQL Lab to query your data.`)} </p> </StyledFormHeader> </StyledStickyHeader> @@ -129,16 +131,26 @@ const ModalHeader = ({ const hasDbHeader = ( <StyledStickyHeader> <StyledFormHeader> - <p className="helper-top"> STEP 2 OF 3 </p> - <h4>Enter the required {dbModel.name} credentials</h4> + <p className="helper-top"> + {t('STEP %(stepCurr)s OF %(stepLast)s', { + stepCurr: 2, + stepLast: 3, + })} + </p> + <h4> + {t('Enter the required %(dbModelName)s credentials', { + dbModelName: dbModel.name, + })} + </h4> <p className="helper-bottom"> - Need help? Learn more about{' '} + {t('Need help? Learn more about')}{' '} <a href={documentationLink(db?.engine)} target="_blank" rel="noopener noreferrer" > - connecting to {dbModel.name}. + {t('connecting to %(dbModelName)s.', { dbModelName: dbModel.name })} + . </a> </p> </StyledFormHeader> @@ -148,8 +160,13 @@ const ModalHeader = ({ const noDbHeader = ( <StyledFormHeader> <div className="select-db"> - <p className="helper-top"> STEP 1 OF 3 </p> - <h4>Select a database to connect</h4> + <p className="helper-top"> + {t('STEP %(stepCurr)s OF %(stepLast)s', { + stepCurr: 1, + stepLast: 3, + })} + </p> + <h4>{t('Select a database to connect')}</h4> </div> </StyledFormHeader> ); @@ -157,8 +174,17 @@ const ModalHeader = ({ const importDbHeader = ( <StyledStickyHeader> <StyledFormHeader> - <p className="helper-top"> STEP 2 OF 2 </p> - <h4>Enter the required {dbModel.name} credentials</h4> + <p className="helper-top"> + {t('STEP %(stepCurr)s OF %(stepLast)s', { + stepCurr: 2, + stepLast: 2, + })} + </p> + <h4> + {t('Enter the required %(dbModelName)s credentials', { + dbModelName: dbModel.name, + })} + </h4> <p className="helper-bottom">{fileCheck ? fileList[0].name : ''}</p> </StyledFormHeader> </StyledStickyHeader> diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx new file mode 100644 index 0000000000000..6cc0312b52a4a --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx @@ -0,0 +1,228 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { EventHandler, ChangeEvent, useState } from 'react'; +import { t, styled } from '@superset-ui/core'; +import { AntdForm, Col, Row } from 'src/components'; +import { Form, FormLabel } from 'src/components/Form'; +import { Radio } from 'src/components/Radio'; +import { Input, TextArea } from 'src/components/Input'; +import { Input as AntdInput, Tooltip } from 'antd'; +import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons'; + +import { DatabaseObject } from '../types'; +import { AuthType } from '.'; + +const StyledDiv = styled.div` + padding-top: ${({ theme }) => theme.gridUnit * 2}px; + label { + color: ${({ theme }) => theme.colors.grayscale.base}; + text-transform: uppercase; + margin-bottom: ${({ theme }) => theme.gridUnit * 2}px; + } +`; + +const StyledRow = styled(Row)` + padding-bottom: ${({ theme }) => theme.gridUnit * 2}px; +`; + +const StyledFormItem = styled(AntdForm.Item)` + margin-bottom: 0 !important; +`; + +const StyledInputPassword = styled(AntdInput.Password)` + margin: ${({ theme }) => `${theme.gridUnit}px 0 ${theme.gridUnit * 2}px`}; +`; + +const SSHTunnelForm = ({ + db, + onSSHTunnelParametersChange, + setSSHTunnelLoginMethod, +}: { + db: DatabaseObject | null; + onSSHTunnelParametersChange: EventHandler< + ChangeEvent<HTMLInputElement | HTMLTextAreaElement> + >; + setSSHTunnelLoginMethod: (method: AuthType) => void; +}) => { + const [usePassword, setUsePassword] = useState<AuthType>(AuthType.password); + + return ( + <Form> + <StyledRow gutter={16}> + <Col xs={24} md={12}> + <StyledDiv> + <FormLabel htmlFor="server_address" required> + {t('SSH Host')} + </FormLabel> + <Input + name="server_address" + type="text" + placeholder={t('e.g. 127.0.0.1')} + value={db?.ssh_tunnel?.server_address || ''} + onChange={onSSHTunnelParametersChange} + data-test="ssh-tunnel-server_address-input" + /> + </StyledDiv> + </Col> + <Col xs={24} md={12}> + <StyledDiv> + <FormLabel htmlFor="server_port" required> + {t('SSH Port')} + </FormLabel> + <Input + name="server_port" + type="text" + placeholder={t('22')} + value={db?.ssh_tunnel?.server_port || ''} + onChange={onSSHTunnelParametersChange} + data-test="ssh-tunnel-server_port-input" + /> + </StyledDiv> + </Col> + </StyledRow> + <StyledRow gutter={16}> + <Col xs={24}> + <StyledDiv> + <FormLabel htmlFor="username" required> + {t('Username')} + </FormLabel> + <Input + name="username" + type="text" + placeholder={t('e.g. Analytics')} + value={db?.ssh_tunnel?.username || ''} + onChange={onSSHTunnelParametersChange} + data-test="ssh-tunnel-username-input" + /> + </StyledDiv> + </Col> + </StyledRow> + <StyledRow gutter={16}> + <Col xs={24}> + <StyledDiv> + <FormLabel htmlFor="use_password" required> + {t('Login with')} + </FormLabel> + <StyledFormItem name="use_password" initialValue={usePassword}> + <Radio.Group + onChange={({ target: { value } }) => { + setUsePassword(value); + setSSHTunnelLoginMethod(value); + }} + > + <Radio + value={AuthType.password} + data-test="ssh-tunnel-use_password-radio" + > + {t('Password')} + </Radio> + <Radio + value={AuthType.privateKey} + data-test="ssh-tunnel-use_private_key-radio" + > + {t('Private Key & Password')} + </Radio> + </Radio.Group> + </StyledFormItem> + </StyledDiv> + </Col> + </StyledRow> + {usePassword === AuthType.password && ( + <StyledRow gutter={16}> + <Col xs={24}> + <StyledDiv> + <FormLabel htmlFor="password" required> + {t('SSH Password')} + </FormLabel> + <StyledInputPassword + name="password" + placeholder={t('e.g. ********')} + value={db?.ssh_tunnel?.password || ''} + onChange={onSSHTunnelParametersChange} + data-test="ssh-tunnel-password-input" + iconRender={visible => + visible ? ( + <Tooltip title="Hide password."> + <EyeInvisibleOutlined /> + </Tooltip> + ) : ( + <Tooltip title="Show password."> + <EyeOutlined /> + </Tooltip> + ) + } + role="textbox" + /> + </StyledDiv> + </Col> + </StyledRow> + )} + {usePassword === AuthType.privateKey && ( + <> + <StyledRow gutter={16}> + <Col xs={24}> + <StyledDiv> + <FormLabel htmlFor="private_key" required> + {t('Private Key')} + </FormLabel> + <TextArea + name="private_key" + placeholder={t('Paste Private Key here')} + value={db?.ssh_tunnel?.private_key || ''} + onChange={onSSHTunnelParametersChange} + data-test="ssh-tunnel-private_key-input" + rows={4} + /> + </StyledDiv> + </Col> + </StyledRow> + <StyledRow gutter={16}> + <Col xs={24}> + <StyledDiv> + <FormLabel htmlFor="private_key_password" required> + {t('Private Key Password')} + </FormLabel> + <StyledInputPassword + name="private_key_password" + placeholder={t('e.g. ********')} + value={db?.ssh_tunnel?.private_key_password || ''} + onChange={onSSHTunnelParametersChange} + data-test="ssh-tunnel-private_key_password-input" + iconRender={visible => + visible ? ( + <Tooltip title="Hide password."> + <EyeInvisibleOutlined /> + </Tooltip> + ) : ( + <Tooltip title="Show password."> + <EyeOutlined /> + </Tooltip> + ) + } + role="textbox" + /> + </StyledDiv> + </Col> + </StyledRow> + </> + )} + </Form> + ); +}; +export default SSHTunnelForm; diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelSwitch.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelSwitch.tsx new file mode 100644 index 0000000000000..a3cc38ca37a54 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelSwitch.tsx @@ -0,0 +1,58 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { t, SupersetTheme, SwitchProps } from '@superset-ui/core'; +import { AntdSwitch } from 'src/components'; +import InfoTooltip from 'src/components/InfoTooltip'; +import { isEmpty } from 'lodash'; +import { ActionType } from '.'; +import { infoTooltip, toggleStyle } from './styles'; + +const SSHTunnelSwitch = ({ + isEditMode, + dbFetched, + useSSHTunneling, + setUseSSHTunneling, + setDB, + isSSHTunneling, +}: SwitchProps) => + isSSHTunneling ? ( + <div css={(theme: SupersetTheme) => infoTooltip(theme)}> + <AntdSwitch + disabled={isEditMode && !isEmpty(dbFetched?.ssh_tunnel)} + checked={useSSHTunneling} + onChange={changed => { + setUseSSHTunneling(changed); + if (!changed) { + setDB({ + type: ActionType.removeSSHTunnelConfig, + }); + } + }} + data-test="ssh-tunnel-switch" + /> + <span css={toggleStyle}>{t('SSH Tunnel')}</span> + <InfoTooltip + tooltip={t('SSH Tunnel configuration parameters')} + placement="right" + viewBox="0 -5 24 24" + /> + </div> + ) : null; +export default SSHTunnelSwitch; diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx index 454070b52a91a..003a26c9a1715 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { EventHandler, ChangeEvent, MouseEvent } from 'react'; +import React, { EventHandler, ChangeEvent, MouseEvent, ReactNode } from 'react'; import { t, SupersetTheme } from '@superset-ui/core'; import SupersetText from 'src/utils/textUtils'; import Button from 'src/components/Button'; @@ -30,12 +30,14 @@ const SqlAlchemyTab = ({ testConnection, conf, testInProgress = false, + children, }: { db: DatabaseObject | null; onInputChange: EventHandler<ChangeEvent<HTMLInputElement>>; testConnection: EventHandler<MouseEvent<HTMLElement>>; conf: { SQLALCHEMY_DOCS_URL: string; SQLALCHEMY_DISPLAY_TEXT: string }; testInProgress?: boolean; + children?: ReactNode; }) => { let fallbackDocsUrl; let fallbackDisplayText; @@ -99,9 +101,10 @@ const SqlAlchemyTab = ({ {t('for more information on how to structure your URI.')} </div> </StyledInputContainer> + {children} <Button onClick={testConnection} - disabled={testInProgress} + loading={testInProgress} cta buttonStyle="link" css={(theme: SupersetTheme) => wideButton(theme)} diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.jsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.jsx deleted file mode 100644 index 79a11b0b13438..0000000000000 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.jsx +++ /dev/null @@ -1,1069 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import fetchMock from 'fetch-mock'; -import userEvent from '@testing-library/user-event'; -import { - render, - screen, - within, - cleanup, - act, -} from 'spec/helpers/testing-library'; -/* -- These imports are used for the mock functions that currently don't work -import { - testDatabaseConnection, - useSingleViewResource, -} from 'src/views/CRUD/hooks'; */ -import DatabaseModal from './index'; - -const dbProps = { - show: true, - database_name: 'my database', - sqlalchemy_uri: 'postgres://superset:superset@something:1234/superset', -}; - -const DATABASE_FETCH_ENDPOINT = 'glob:*/api/v1/database/10'; -// const DATABASE_POST_ENDPOINT = 'glob:*/api/v1/database/'; -const AVAILABLE_DB_ENDPOINT = 'glob:*/api/v1/database/available*'; -const VALIDATE_PARAMS_ENDPOINT = 'glob:*/api/v1/database/validate_parameters*'; - -fetchMock.config.overwriteRoutes = true; -fetchMock.get(DATABASE_FETCH_ENDPOINT, { - result: { - id: 10, - database_name: 'my database', - expose_in_sqllab: false, - allow_ctas: false, - allow_cvas: false, - configuration_method: 'sqlalchemy_form', - }, -}); -fetchMock.mock(AVAILABLE_DB_ENDPOINT, { - databases: [ - { - available_drivers: ['psycopg2'], - default_driver: 'psycopg2', - engine: 'postgresql', - name: 'PostgreSQL', - parameters: { - properties: { - database: { - description: 'Database name', - type: 'string', - }, - encryption: { - description: 'Use an encrypted connection to the database', - type: 'boolean', - }, - host: { - description: 'Hostname or IP address', - type: 'string', - }, - password: { - description: 'Password', - nullable: true, - type: 'string', - }, - port: { - description: 'Database port', - format: 'int32', - maximum: 65536, - minimum: 0, - type: 'integer', - }, - query: { - additionalProperties: {}, - description: 'Additional parameters', - type: 'object', - }, - username: { - description: 'Username', - nullable: true, - type: 'string', - }, - }, - required: ['database', 'host', 'port', 'username'], - type: 'object', - }, - preferred: true, - sqlalchemy_uri_placeholder: - 'postgresql://user:password@host:port/dbname[?key=value&key=value...]', - }, - { - available_drivers: ['rest'], - engine: 'presto', - name: 'Presto', - preferred: true, - }, - { - available_drivers: ['mysqldb'], - default_driver: 'mysqldb', - engine: 'mysql', - name: 'MySQL', - parameters: { - properties: { - database: { - description: 'Database name', - type: 'string', - }, - encryption: { - description: 'Use an encrypted connection to the database', - type: 'boolean', - }, - host: { - description: 'Hostname or IP address', - type: 'string', - }, - password: { - description: 'Password', - nullable: true, - type: 'string', - }, - port: { - description: 'Database port', - format: 'int32', - maximum: 65536, - minimum: 0, - type: 'integer', - }, - query: { - additionalProperties: {}, - description: 'Additional parameters', - type: 'object', - }, - username: { - description: 'Username', - nullable: true, - type: 'string', - }, - }, - required: ['database', 'host', 'port', 'username'], - type: 'object', - }, - preferred: true, - sqlalchemy_uri_placeholder: - 'mysql://user:password@host:port/dbname[?key=value&key=value...]', - }, - { - available_drivers: ['pysqlite'], - engine: 'sqlite', - name: 'SQLite', - preferred: true, - }, - { - available_drivers: ['rest'], - engine: 'druid', - name: 'Apache Druid', - preferred: false, - }, - { - available_drivers: ['bigquery'], - default_driver: 'bigquery', - engine: 'bigquery', - name: 'Google BigQuery', - parameters: { - properties: { - credentials_info: { - description: 'Contents of BigQuery JSON credentials.', - type: 'string', - 'x-encrypted-extra': true, - }, - query: { - type: 'object', - }, - }, - type: 'object', - }, - preferred: false, - sqlalchemy_uri_placeholder: 'bigquery://{project_id}', - }, - ], -}); -fetchMock.post(VALIDATE_PARAMS_ENDPOINT, { - message: 'OK', -}); - -describe('DatabaseModal', () => { - const renderAndWait = async () => { - const mounted = act(async () => { - render(<DatabaseModal {...dbProps} />, { - useRedux: true, - }); - }); - - return mounted; - }; - - beforeEach(async () => { - await renderAndWait(); - }); - - afterEach(cleanup); - - describe('Visual: New database connection', () => { - it('renders the initial load of Step 1 correctly', async () => { - // ---------- Components ---------- - // <TabHeader> - AntD header - const closeButton = screen.getByLabelText('Close'); - const step1Header = screen.getByRole('heading', { - name: /connect a database/i, - }); - // <ModalHeader> - Connection header - const step1Helper = screen.getByText(/step 1 of 3/i); - const selectDbHeader = screen.getByRole('heading', { - name: /select a database to connect/i, - }); - // <IconButton> - Preferred database buttons - const preferredDbButtonPostgreSQL = screen.getByRole('button', { - name: /postgresql/i, - }); - const preferredDbTextPostgreSQL = within( - preferredDbButtonPostgreSQL, - ).getByText(/postgresql/i); - const preferredDbButtonPresto = screen.getByRole('button', { - name: /presto/i, - }); - const preferredDbTextPresto = within(preferredDbButtonPresto).getByText( - /presto/i, - ); - const preferredDbButtonMySQL = screen.getByRole('button', { - name: /mysql/i, - }); - const preferredDbTextMySQL = within(preferredDbButtonMySQL).getByText( - /mysql/i, - ); - const preferredDbButtonSQLite = screen.getByRole('button', { - name: /sqlite/i, - }); - const preferredDbTextSQLite = within(preferredDbButtonSQLite).getByText( - /sqlite/i, - ); - // All dbs render with this icon in this testing environment, - // The Icon count should equal the count of databases rendered - const preferredDbIcon = screen.getAllByRole('img', { - name: /default-icon/i, - }); - // renderAvailableSelector() => <Select> - Supported databases selector - const supportedDbsHeader = screen.getByRole('heading', { - name: /or choose from a list of other databases we support:/i, - }); - const selectorLabel = screen.getByText(/supported databases/i); - const selectorPlaceholder = screen.getByText(/choose a database\.\.\./i); - const selectorArrow = screen.getByRole('img', { - name: /down/i, - hidden: true, - }); - - // ---------- TODO (lyndsiWilliams): Selector options, can't seem to get these to render properly. - - // renderAvailableSelector() => <Alert> - Supported databases alert - const alertIcon = screen.getByRole('img', { name: /info icon/i }); - const alertMessage = screen.getByText(/want to add a new database\?/i); - const alertDescription = screen.getByText( - /any databases that allow connections via sql alchemy uris can be added\. learn about how to connect a database driver \./i, - ); - const alertLink = screen.getByRole('link', { name: /here/i }); - - // ---------- Assertions ---------- - const visibleComponents = [ - closeButton, - step1Header, - step1Helper, - selectDbHeader, - supportedDbsHeader, - selectorLabel, - selectorPlaceholder, - selectorArrow, - alertIcon, - alertMessage, - alertDescription, - alertLink, - preferredDbButtonPostgreSQL, - preferredDbButtonPresto, - preferredDbButtonMySQL, - preferredDbButtonSQLite, - preferredDbIcon[0], - preferredDbIcon[1], - preferredDbIcon[2], - preferredDbIcon[3], - preferredDbTextPostgreSQL, - preferredDbTextPresto, - preferredDbTextMySQL, - preferredDbTextSQLite, - ]; - - visibleComponents.forEach(component => { - expect(component).toBeVisible(); - }); - // This is how many preferred databases are rendered - expect(preferredDbIcon).toHaveLength(4); - }); - - it('renders the "Basic" tab of SQL Alchemy form (step 2 of 2) correctly', async () => { - // On step 1, click dbButton to access SQL Alchemy form - userEvent.click( - screen.getByRole('button', { - name: /sqlite/i, - }), - ); - - // ---------- Components ---------- - // <TabHeader> - AntD header - const closeButton = screen.getByRole('button', { name: /close/i }); - const basicHeader = screen.getByRole('heading', { - name: /connect a database/i, - }); - // <ModalHeader> - Connection header - const basicHelper = screen.getByText(/step 2 of 2/i); - const basicHeaderTitle = screen.getByText(/enter primary credentials/i); - const basicHeaderSubtitle = screen.getByText( - /need help\? learn how to connect your database \./i, - ); - const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { - name: /here/i, - }); - // <Tabs> - Basic/Advanced tabs - const basicTab = screen.getByRole('tab', { name: /basic/i }); - const advancedTab = screen.getByRole('tab', { name: /advanced/i }); - // <StyledBasicTab> - Basic tab's content - const displayNameLabel = screen.getByText(/display name*/i); - const displayNameInput = screen.getByTestId('database-name-input'); - const displayNameHelper = screen.getByText( - /pick a name to help you identify this database\./i, - ); - const SQLURILabel = screen.getByText(/sqlalchemy uri*/i); - const SQLURIInput = screen.getByTestId('sqlalchemy-uri-input'); - const SQLURIHelper = screen.getByText( - /refer to the for more information on how to structure your uri\./i, - ); - const testConnectionButton = screen.getByRole('button', { - name: /test connection/i, - }); - // <Alert> - Basic tab's alert - const alertIcon = screen.getByRole('img', { name: /info icon/i }); - const alertMessage = screen.getByText( - /additional fields may be required/i, - ); - const alertDescription = screen.getByText( - /select databases require additional fields to be completed in the advanced tab to successfully connect the database\. learn what requirements your databases has \./i, - ); - const alertLink = within(alertDescription).getByRole('link', { - name: /here/i, - }); - // renderModalFooter() - Basic tab's footer - const backButton = screen.getByRole('button', { name: /back/i }); - const connectButton = screen.getByRole('button', { name: 'Connect' }); - - // ---------- Assertions ---------- - const visibleComponents = [ - closeButton, - basicHeader, - basicHelper, - basicHeaderTitle, - basicHeaderSubtitle, - basicHeaderLink, - basicTab, - advancedTab, - displayNameLabel, - displayNameInput, - displayNameHelper, - SQLURILabel, - SQLURIInput, - SQLURIHelper, - testConnectionButton, - alertIcon, - alertMessage, - alertDescription, - alertLink, - backButton, - connectButton, - ]; - - visibleComponents.forEach(component => { - expect(component).toBeVisible(); - }); - }); - - it('renders the unexpanded "Advanced" tab correctly', async () => { - // On step 1, click dbButton to access step 2 - userEvent.click( - screen.getByRole('button', { - name: /sqlite/i, - }), - ); - // Click the "Advanced" tab - userEvent.click(screen.getByRole('tab', { name: /advanced/i })); - - // ---------- Components ---------- - // <TabHeader> - AntD header - const closeButton = screen.getByRole('button', { name: /close/i }); - const advancedHeader = screen.getByRole('heading', { - name: /connect a database/i, - }); - // <ModalHeader> - Connection header - const basicHelper = screen.getByText(/step 2 of 2/i); - const basicHeaderTitle = screen.getByText(/enter primary credentials/i); - const basicHeaderSubtitle = screen.getByText( - /need help\? learn how to connect your database \./i, - ); - const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { - name: /here/i, - }); - // <Tabs> - Basic/Advanced tabs - const basicTab = screen.getByRole('tab', { name: /basic/i }); - const advancedTab = screen.getByRole('tab', { name: /advanced/i }); - // <ExtraOptions> - Advanced tabs - const sqlLabTab = screen.getByRole('tab', { - name: /right sql lab adjust how this database will interact with sql lab\./i, - }); - const sqlLabTabArrow = within(sqlLabTab).getByRole('img', { - name: /right/i, - }); - const sqlLabTabHeading = screen.getByRole('heading', { - name: /sql lab/i, - }); - const performanceTab = screen.getByRole('tab', { - name: /right performance adjust performance settings of this database\./i, - }); - const performanceTabArrow = within(performanceTab).getByRole('img', { - name: /right/i, - }); - const performanceTabHeading = screen.getByRole('heading', { - name: /performance/i, - }); - const securityTab = screen.getByRole('tab', { - name: /right security add extra connection information\./i, - }); - const securityTabArrow = within(securityTab).getByRole('img', { - name: /right/i, - }); - const securityTabHeading = screen.getByRole('heading', { - name: /security/i, - }); - const otherTab = screen.getByRole('tab', { - name: /right other additional settings\./i, - }); - const otherTabArrow = within(otherTab).getByRole('img', { - name: /right/i, - }); - const otherTabHeading = screen.getByRole('heading', { name: /other/i }); - // renderModalFooter() - Advanced tab's footer - const backButton = screen.getByRole('button', { name: /back/i }); - const connectButton = screen.getByRole('button', { name: 'Connect' }); - - // ---------- Assertions ---------- - const visibleComponents = [ - closeButton, - advancedHeader, - basicHelper, - basicHeaderTitle, - basicHeaderSubtitle, - basicHeaderLink, - basicTab, - advancedTab, - sqlLabTab, - sqlLabTabArrow, - sqlLabTabHeading, - performanceTab, - performanceTabArrow, - performanceTabHeading, - securityTab, - securityTabArrow, - securityTabHeading, - otherTab, - otherTabArrow, - otherTabHeading, - backButton, - connectButton, - ]; - - visibleComponents.forEach(component => { - expect(component).toBeVisible(); - }); - }); - - it('renders the "Advanced" - SQL LAB tab correctly (unexpanded)', async () => { - // ---------- Components ---------- - // On step 1, click dbButton to access step 2 - userEvent.click( - screen.getByRole('button', { - name: /sqlite/i, - }), - ); - // Click the "Advanced" tab - userEvent.click(screen.getByRole('tab', { name: /advanced/i })); - // Click the "SQL Lab" tab - userEvent.click( - screen.getByRole('tab', { - name: /right sql lab adjust how this database will interact with sql lab\./i, - }), - ); - - // ----- BEGIN STEP 2 (ADVANCED - SQL LAB) - // <TabHeader> - AntD header - const closeButton = screen.getByRole('button', { name: /close/i }); - const advancedHeader = screen.getByRole('heading', { - name: /connect a database/i, - }); - // <ModalHeader> - Connection header - const basicHelper = screen.getByText(/step 2 of 2/i); - const basicHeaderTitle = screen.getByText(/enter primary credentials/i); - const basicHeaderSubtitle = screen.getByText( - /need help\? learn how to connect your database \./i, - ); - const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { - name: /here/i, - }); - // <Tabs> - Basic/Advanced tabs - const basicTab = screen.getByRole('tab', { name: /basic/i }); - const advancedTab = screen.getByRole('tab', { name: /advanced/i }); - // <ExtraOptions> - Advanced tabs - const sqlLabTab = screen.getByRole('tab', { - name: /right sql lab adjust how this database will interact with sql lab\./i, - }); - // These are the checkbox SVGs that cover the actual checkboxes - const checkboxOffSVGs = screen.getAllByRole('img', { - name: /checkbox-off/i, - }); - const tooltipIcons = screen.getAllByRole('img', { - name: /info-solid_small/i, - }); - const exposeInSQLLabCheckbox = screen.getByRole('checkbox', { - name: /expose database in sql lab/i, - }); - // This is both the checkbox and it's respective SVG - // const exposeInSQLLabCheckboxSVG = checkboxOffSVGs[0].parentElement; - const exposeInSQLLabText = screen.getByText( - /expose database in sql lab/i, - ); - const allowCTASCheckbox = screen.getByRole('checkbox', { - name: /allow create table as/i, - }); - const allowCTASText = screen.getByText(/allow create table as/i); - const allowCVASCheckbox = screen.getByRole('checkbox', { - name: /allow create table as/i, - }); - const allowCVASText = screen.getByText(/allow create table as/i); - const CTASCVASLabelText = screen.getByText(/ctas & cvas schema/i); - // This grabs the whole input by placeholder text - const CTASCVASInput = screen.getByPlaceholderText( - /create or select schema\.\.\./i, - ); - const CTASCVASHelperText = screen.getByText( - /force all tables and views to be created in this schema when clicking ctas or cvas in sql lab\./i, - ); - const allowDMLCheckbox = screen.getByRole('checkbox', { - name: /allow dml/i, - }); - const allowDMLText = screen.getByText(/allow dml/i); - const allowMultiSchemaMDFetchCheckbox = screen.getByRole('checkbox', { - name: /allow multi schema metadata fetch/i, - }); - const allowMultiSchemaMDFetchText = screen.getByText( - /allow multi schema metadata fetch/i, - ); - const enableQueryCostEstimationCheckbox = screen.getByRole('checkbox', { - name: /enable query cost estimation/i, - }); - const enableQueryCostEstimationText = screen.getByText( - /enable query cost estimation/i, - ); - const allowDbExplorationCheckbox = screen.getByRole('checkbox', { - name: /allow this database to be explored/i, - }); - const allowDbExplorationText = screen.getByText( - /allow this database to be explored/i, - ); - const disableSQLLabDataPreviewQueriesCheckbox = screen.getByRole( - 'checkbox', - { - name: /Disable SQL Lab data preview queries/i, - }, - ); - const disableSQLLabDataPreviewQueriesText = screen.getByText( - /Disable SQL Lab data preview queries/i, - ); - - // ---------- Assertions ---------- - const visibleComponents = [ - closeButton, - advancedHeader, - basicHelper, - basicHeaderTitle, - basicHeaderSubtitle, - basicHeaderLink, - basicTab, - advancedTab, - sqlLabTab, - checkboxOffSVGs[0], - checkboxOffSVGs[1], - checkboxOffSVGs[2], - checkboxOffSVGs[3], - checkboxOffSVGs[4], - checkboxOffSVGs[5], - checkboxOffSVGs[6], - checkboxOffSVGs[7], - tooltipIcons[0], - tooltipIcons[1], - tooltipIcons[2], - tooltipIcons[3], - tooltipIcons[4], - tooltipIcons[5], - tooltipIcons[6], - tooltipIcons[7], - exposeInSQLLabText, - allowCTASText, - allowCVASText, - CTASCVASLabelText, - CTASCVASInput, - CTASCVASHelperText, - allowDMLText, - allowMultiSchemaMDFetchText, - enableQueryCostEstimationText, - allowDbExplorationText, - disableSQLLabDataPreviewQueriesText, - ]; - // These components exist in the DOM but are not visible - const invisibleComponents = [ - exposeInSQLLabCheckbox, - allowCTASCheckbox, - allowCVASCheckbox, - allowDMLCheckbox, - allowMultiSchemaMDFetchCheckbox, - enableQueryCostEstimationCheckbox, - allowDbExplorationCheckbox, - disableSQLLabDataPreviewQueriesCheckbox, - ]; - - visibleComponents.forEach(component => { - expect(component).toBeVisible(); - }); - invisibleComponents.forEach(component => { - expect(component).not.toBeVisible(); - }); - expect(checkboxOffSVGs).toHaveLength(8); - expect(tooltipIcons).toHaveLength(8); - }); - - it('renders the "Advanced" - PERFORMANCE tab correctly', async () => { - // ---------- Components ---------- - // On step 1, click dbButton to access step 2 - userEvent.click( - screen.getByRole('button', { - name: /sqlite/i, - }), - ); - // Click the "Advanced" tab - userEvent.click(screen.getByRole('tab', { name: /advanced/i })); - // Click the "Performance" tab - userEvent.click( - screen.getByRole('tab', { - name: /right performance adjust performance settings of this database\./i, - }), - ); - - // ----- BEGIN STEP 2 (ADVANCED - PERFORMANCE) - // <TabHeader> - AntD header - const closeButton = screen.getByRole('button', { name: /close/i }); - const advancedHeader = screen.getByRole('heading', { - name: /connect a database/i, - }); - // <ModalHeader> - Connection header - const basicHelper = screen.getByText(/step 2 of 2/i); - const basicHeaderTitle = screen.getByText(/enter primary credentials/i); - const basicHeaderSubtitle = screen.getByText( - /need help\? learn how to connect your database \./i, - ); - const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { - name: /here/i, - }); - // <Tabs> - Basic/Advanced tabs - const basicTab = screen.getByRole('tab', { name: /basic/i }); - const advancedTab = screen.getByRole('tab', { name: /advanced/i }); - // <ExtraOptions> - Advanced tabs - const sqlLabTab = screen.getByRole('tab', { - name: /right sql lab adjust how this database will interact with sql lab\./i, - }); - const performanceTab = screen.getByRole('tab', { - name: /right performance adjust performance settings of this database\./i, - }); - - // ---------- Assertions ---------- - const visibleComponents = [ - closeButton, - advancedHeader, - basicHelper, - basicHeaderTitle, - basicHeaderSubtitle, - basicHeaderLink, - basicTab, - advancedTab, - sqlLabTab, - performanceTab, - ]; - - visibleComponents.forEach(component => { - expect(component).toBeVisible(); - }); - }); - - it('renders the "Advanced" - SECURITY tab correctly', async () => { - // ---------- Components ---------- - // On step 1, click dbButton to access step 2 - userEvent.click( - screen.getByRole('button', { - name: /sqlite/i, - }), - ); - // Click the "Advanced" tab - userEvent.click(screen.getByRole('tab', { name: /advanced/i })); - // Click the "Security" tab - userEvent.click( - screen.getByRole('tab', { - name: /right security add extra connection information\./i, - }), - ); - - // ----- BEGIN STEP 2 (ADVANCED - SECURITY) - // <TabHeader> - AntD header - const closeButton = screen.getByRole('button', { name: /close/i }); - const advancedHeader = screen.getByRole('heading', { - name: /connect a database/i, - }); - // <ModalHeader> - Connection header - const basicHelper = screen.getByText(/step 2 of 2/i); - const basicHeaderTitle = screen.getByText(/enter primary credentials/i); - const basicHeaderSubtitle = screen.getByText( - /need help\? learn how to connect your database \./i, - ); - const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { - name: /here/i, - }); - // <Tabs> - Basic/Advanced tabs - const basicTab = screen.getByRole('tab', { name: /basic/i }); - const advancedTab = screen.getByRole('tab', { name: /advanced/i }); - // <ExtraOptions> - Advanced tabs - const sqlLabTab = screen.getByRole('tab', { - name: /right sql lab adjust how this database will interact with sql lab\./i, - }); - const performanceTab = screen.getByRole('tab', { - name: /right performance adjust performance settings of this database\./i, - }); - const securityTab = screen.getByRole('tab', { - name: /right security add extra connection information\./i, - }); - - // ---------- Assertions ---------- - const visibleComponents = [ - closeButton, - advancedHeader, - basicHelper, - basicHeaderTitle, - basicHeaderSubtitle, - basicHeaderLink, - basicTab, - advancedTab, - sqlLabTab, - performanceTab, - securityTab, - ]; - - visibleComponents.forEach(component => { - expect(component).toBeVisible(); - }); - }); - - it('renders the "Advanced" - OTHER tab correctly', async () => { - // ---------- Components ---------- - // On step 1, click dbButton to access step 2 - userEvent.click( - screen.getByRole('button', { - name: /sqlite/i, - }), - ); - // Click the "Advanced" tab - userEvent.click(screen.getByRole('tab', { name: /advanced/i })); - // Click the "Other" tab - userEvent.click( - screen.getByRole('tab', { - name: /right other additional settings\./i, - }), - ); - - // ----- BEGIN STEP 2 (ADVANCED - OTHER) - // <TabHeader> - AntD header - const closeButton = screen.getByRole('button', { name: /close/i }); - const advancedHeader = screen.getByRole('heading', { - name: /connect a database/i, - }); - // <ModalHeader> - Connection header - const basicHelper = screen.getByText(/step 2 of 2/i); - const basicHeaderTitle = screen.getByText(/enter primary credentials/i); - const basicHeaderSubtitle = screen.getByText( - /need help\? learn how to connect your database \./i, - ); - const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { - name: /here/i, - }); - // <Tabs> - Basic/Advanced tabs - const basicTab = screen.getByRole('tab', { name: /basic/i }); - const advancedTab = screen.getByRole('tab', { name: /advanced/i }); - // <ExtraOptions> - Advanced tabs - const sqlLabTab = screen.getByRole('tab', { - name: /right sql lab adjust how this database will interact with sql lab\./i, - }); - const performanceTab = screen.getByRole('tab', { - name: /right performance adjust performance settings of this database\./i, - }); - const securityTab = screen.getByRole('tab', { - name: /right security add extra connection information\./i, - }); - const otherTab = screen.getByRole('tab', { - name: /right other additional settings\./i, - }); - - // ---------- Assertions ---------- - const visibleComponents = [ - closeButton, - advancedHeader, - basicHelper, - basicHeaderTitle, - basicHeaderSubtitle, - basicHeaderLink, - basicTab, - advancedTab, - sqlLabTab, - performanceTab, - securityTab, - otherTab, - ]; - - visibleComponents.forEach(component => { - expect(component).toBeVisible(); - }); - }); - - it('Dynamic form', async () => { - // ---------- Components ---------- - // On step 1, click dbButton to access step 2 - userEvent.click( - screen.getByRole('button', { - name: /postgresql/i, - }), - ); - - expect.anything(); - }); - }); - - describe('Functional: Create new database', () => { - it('directs databases to the appropriate form (dynamic vs. SQL Alchemy)', () => { - // ---------- Dynamic example (3-step form) - // Click the PostgreSQL button to enter the dynamic form - const postgreSQLButton = screen.getByRole('button', { - name: /postgresql/i, - }); - userEvent.click(postgreSQLButton); - - // Dynamic form has 3 steps, seeing this text means the dynamic form is present - const dynamicFormStepText = screen.getByText(/step 2 of 3/i); - - expect(dynamicFormStepText).toBeVisible(); - - // ---------- SQL Alchemy example (2-step form) - // Click the back button to go back to step 1, - // then click the SQLite button to enter the SQL Alchemy form - const backButton = screen.getByRole('button', { name: /back/i }); - userEvent.click(backButton); - - const sqliteButton = screen.getByRole('button', { - name: /sqlite/i, - }); - userEvent.click(sqliteButton); - - // SQL Alchemy form has 2 steps, seeing this text means the SQL Alchemy form is present - const sqlAlchemyFormStepText = screen.getByText(/step 2 of 2/i); - - expect(sqlAlchemyFormStepText).toBeVisible(); - }); - - describe('SQL Alchemy form flow', () => { - beforeEach(() => { - userEvent.click( - screen.getByRole('button', { - name: /sqlite/i, - }), - ); - }); - - it('enters step 2 of 2 when proper database is selected', () => { - const step2text = screen.getByText(/step 2 of 2/i); - expect(step2text).toBeVisible(); - }); - - it('runs fetchResource when "Connect" is clicked', () => { - /* ---------- 🐞 TODO (lyndsiWilliams): function mock is not currently working 🐞 ---------- - - // Mock useSingleViewResource - const mockUseSingleViewResource = jest.fn(); - mockUseSingleViewResource.mockImplementation(useSingleViewResource); - - const { fetchResource } = mockUseSingleViewResource('database'); - - // Invalid hook call? - userEvent.click(screen.getByRole('button', { name: 'Connect' })); - expect(fetchResource).toHaveBeenCalled(); - - The line below makes the linter happy */ - expect.anything(); - }); - - describe('step 2 component interaction', () => { - it('properly interacts with textboxes', () => { - const dbNametextBox = screen.getByTestId('database-name-input'); - expect(dbNametextBox).toHaveValue('SQLite'); - - userEvent.type(dbNametextBox, 'Different text'); - expect(dbNametextBox).toHaveValue('SQLiteDifferent text'); - - const sqlAlchemyURItextBox = screen.getByTestId( - 'sqlalchemy-uri-input', - ); - expect(sqlAlchemyURItextBox).toHaveValue(''); - - userEvent.type(sqlAlchemyURItextBox, 'Different text'); - expect(sqlAlchemyURItextBox).toHaveValue('Different text'); - }); - - it('runs testDatabaseConnection when "TEST CONNECTION" is clicked', () => { - /* ---------- 🐞 TODO (lyndsiWilliams): function mock is not currently working 🐞 ---------- - - // Mock testDatabaseConnection - const mockTestDatabaseConnection = jest.fn(); - mockTestDatabaseConnection.mockImplementation(testDatabaseConnection); - - userEvent.click( - screen.getByRole('button', { - name: /test connection/i, - }), - ); - - expect(mockTestDatabaseConnection).toHaveBeenCalled(); - - The line below makes the linter happy */ - expect.anything(); - }); - }); - }); - - describe('Dynamic form flow', () => { - beforeEach(() => { - userEvent.click( - screen.getByRole('button', { - name: /postgresql/i, - }), - ); - }); - - it('enters step 2 of 3 when proper database is selected', () => { - const step2of3text = screen.getByText(/step 2 of 3/i); - expect(step2of3text).toBeVisible(); - }); - - it('enters form credentials and runs fetchResource when "Connect" is clicked', () => { - const textboxes = screen.getAllByRole('textbox'); - const hostField = textboxes[0]; - const portField = screen.getByRole('spinbutton'); - const databaseNameField = textboxes[1]; - const usernameField = textboxes[2]; - const passwordField = textboxes[3]; - - expect(hostField).toHaveValue(''); - expect(portField).toHaveValue(null); - expect(databaseNameField).toHaveValue(''); - expect(usernameField).toHaveValue(''); - expect(passwordField).toHaveValue(''); - - userEvent.type(hostField, 'localhost'); - userEvent.type(portField, '5432'); - userEvent.type(databaseNameField, 'postgres'); - userEvent.type(usernameField, 'testdb'); - userEvent.type(passwordField, 'demoPassword'); - - expect(hostField).toHaveValue('localhost'); - expect(portField).toHaveValue(5432); - expect(databaseNameField).toHaveValue('postgres'); - expect(usernameField).toHaveValue('testdb'); - expect(passwordField).toHaveValue('demoPassword'); - - /* ---------- 🐞 TODO (lyndsiWilliams): function mock is not currently working 🐞 ---------- - - // Mock useSingleViewResource - const mockUseSingleViewResource = jest.fn(); - mockUseSingleViewResource.mockImplementation(useSingleViewResource); - - const { fetchResource } = mockUseSingleViewResource('database'); - - // Invalid hook call? - userEvent.click(screen.getByRole('button', { name: 'Connect' })); - expect(fetchResource).toHaveBeenCalled(); - - */ - }); - }); - - describe('Import database flow', () => { - it('imports a file', () => { - const importDbButton = screen.getByTestId('import-database-btn'); - expect(importDbButton).toBeVisible(); - - const testFile = new File([new ArrayBuffer(1)], 'model_export.zip'); - - userEvent.click(importDbButton); - userEvent.upload(importDbButton, testFile); - - expect(importDbButton.files[0]).toStrictEqual(testFile); - expect(importDbButton.files.item(0)).toStrictEqual(testFile); - expect(importDbButton.files).toHaveLength(1); - }); - }); - }); - - describe('DatabaseModal w/ Deeplinking Engine', () => { - const renderAndWait = async () => { - const mounted = act(async () => { - render(<DatabaseModal {...dbProps} dbEngine="PostgreSQL" />, { - useRedux: true, - }); - }); - - return mounted; - }; - - beforeEach(async () => { - await renderAndWait(); - }); - - it('enters step 2 of 3 when proper database is selected', () => { - const step2of3text = screen.getByText(/step 2 of 3/i); - expect(step2of3text).toBeVisible(); - }); - }); -}); diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.tsx new file mode 100644 index 0000000000000..32cc16b04f45b --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.tsx @@ -0,0 +1,2101 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import fetchMock from 'fetch-mock'; +import userEvent from '@testing-library/user-event'; +import { + render, + screen, + within, + cleanup, + act, + waitFor, +} from 'spec/helpers/testing-library'; +import { + DatabaseObject, + CONFIGURATION_METHOD, +} from 'src/views/CRUD/data/database/types'; +import { getExtensionsRegistry } from '@superset-ui/core'; +import setupExtensions from 'src/setup/setupExtensions'; +import * as hooks from 'src/views/CRUD/hooks'; +import DatabaseModal, { + dbReducer, + DBReducerActionType, + ActionType, +} from './index'; + +jest.mock('@superset-ui/core', () => ({ + ...jest.requireActual('@superset-ui/core'), + isFeatureEnabled: () => true, +})); + +const mockHistoryPush = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useHistory: () => ({ + push: mockHistoryPush, + }), +})); + +const dbProps = { + show: true, + database_name: 'my database', + sqlalchemy_uri: 'postgres://superset:superset@something:1234/superset', + onHide: () => {}, +}; + +const DATABASE_FETCH_ENDPOINT = 'glob:*/api/v1/database/10'; +const AVAILABLE_DB_ENDPOINT = 'glob:*/api/v1/database/available*'; +const VALIDATE_PARAMS_ENDPOINT = 'glob:*/api/v1/database/validate_parameters*'; +const DATABASE_CONNECT_ENDPOINT = 'glob:*/api/v1/database/'; + +fetchMock.post(DATABASE_CONNECT_ENDPOINT, { + id: 10, + result: { + configuration_method: 'sqlalchemy_form', + database_name: 'Other2', + driver: 'apsw', + expose_in_sqllab: true, + extra: '{"allows_virtual_table_explore":true}', + sqlalchemy_uri: 'gsheets://', + }, + json: 'foo', +}); + +fetchMock.config.overwriteRoutes = true; +fetchMock.get(DATABASE_FETCH_ENDPOINT, { + result: { + id: 10, + database_name: 'my database', + expose_in_sqllab: false, + allow_ctas: false, + allow_cvas: false, + configuration_method: 'sqlalchemy_form', + }, +}); +fetchMock.mock(AVAILABLE_DB_ENDPOINT, { + databases: [ + { + available_drivers: ['psycopg2'], + default_driver: 'psycopg2', + engine: 'postgresql', + name: 'PostgreSQL', + parameters: { + properties: { + database: { + description: 'Database name', + type: 'string', + }, + encryption: { + description: 'Use an encrypted connection to the database', + type: 'boolean', + }, + host: { + description: 'Hostname or IP address', + type: 'string', + }, + password: { + description: 'Password', + nullable: true, + type: 'string', + }, + port: { + description: 'Database port', + format: 'int32', + maximum: 65536, + minimum: 0, + type: 'integer', + }, + query: { + additionalProperties: {}, + description: 'Additional parameters', + type: 'object', + }, + username: { + description: 'Username', + nullable: true, + type: 'string', + }, + }, + required: ['database', 'host', 'port', 'username'], + type: 'object', + }, + preferred: true, + sqlalchemy_uri_placeholder: + 'postgresql://user:password@host:port/dbname[?key=value&key=value...]', + engine_information: { + supports_file_upload: true, + disable_ssh_tunneling: false, + }, + }, + { + available_drivers: ['rest'], + engine: 'presto', + name: 'Presto', + preferred: true, + engine_information: { + supports_file_upload: true, + disable_ssh_tunneling: false, + }, + }, + { + available_drivers: ['mysqldb'], + default_driver: 'mysqldb', + engine: 'mysql', + name: 'MySQL', + parameters: { + properties: { + database: { + description: 'Database name', + type: 'string', + }, + encryption: { + description: 'Use an encrypted connection to the database', + type: 'boolean', + }, + host: { + description: 'Hostname or IP address', + type: 'string', + }, + password: { + description: 'Password', + nullable: true, + type: 'string', + }, + port: { + description: 'Database port', + format: 'int32', + maximum: 65536, + minimum: 0, + type: 'integer', + }, + query: { + additionalProperties: {}, + description: 'Additional parameters', + type: 'object', + }, + username: { + description: 'Username', + nullable: true, + type: 'string', + }, + }, + required: ['database', 'host', 'port', 'username'], + type: 'object', + }, + preferred: true, + sqlalchemy_uri_placeholder: + 'mysql://user:password@host:port/dbname[?key=value&key=value...]', + engine_information: { + supports_file_upload: true, + disable_ssh_tunneling: false, + }, + }, + { + available_drivers: ['pysqlite'], + engine: 'sqlite', + name: 'SQLite', + preferred: true, + engine_information: { + supports_file_upload: true, + disable_ssh_tunneling: false, + }, + }, + { + available_drivers: ['rest'], + engine: 'druid', + name: 'Apache Druid', + preferred: false, + engine_information: { + supports_file_upload: true, + disable_ssh_tunneling: false, + }, + }, + { + available_drivers: ['bigquery'], + default_driver: 'bigquery', + engine: 'bigquery', + name: 'Google BigQuery', + parameters: { + properties: { + credentials_info: { + description: 'Contents of BigQuery JSON credentials.', + type: 'string', + 'x-encrypted-extra': true, + }, + query: { + type: 'object', + }, + }, + type: 'object', + }, + preferred: false, + sqlalchemy_uri_placeholder: 'bigquery://{project_id}', + engine_information: { + supports_file_upload: true, + disable_ssh_tunneling: true, + }, + }, + { + available_drivers: ['rest'], + default_driver: 'apsw', + engine: 'gsheets', + name: 'Google Sheets', + preferred: false, + engine_information: { + supports_file_upload: false, + disable_ssh_tunneling: true, + }, + }, + { + available_drivers: ['connector'], + default_driver: 'connector', + engine: 'databricks', + name: 'Databricks', + parameters: { + properties: { + access_token: { + type: 'string', + }, + database: { + type: 'string', + }, + host: { + type: 'string', + }, + http_path: { + type: 'string', + }, + port: { + format: 'int32', + type: 'integer', + }, + }, + required: ['access_token', 'database', 'host', 'http_path', 'port'], + type: 'object', + }, + preferred: true, + sqlalchemy_uri_placeholder: + 'databricks+connector://token:{access_token}@{host}:{port}/{database_name}', + }, + ], +}); +fetchMock.post(VALIDATE_PARAMS_ENDPOINT, { + message: 'OK', +}); + +const databaseFixture: DatabaseObject = { + backend: 'postgres', + configuration_method: CONFIGURATION_METHOD.DYNAMIC_FORM, + database_name: 'Postgres', + name: 'PostgresDB', + is_managed_externally: false, + driver: 'psycopg2', +}; + +describe('DatabaseModal', () => { + const renderAndWait = async () => { + const mounted = act(async () => { + render(<DatabaseModal {...dbProps} />, { + useRedux: true, + }); + }); + + return mounted; + }; + + beforeEach(async () => { + await renderAndWait(); + }); + + afterEach(cleanup); + + describe('Visual: New database connection', () => { + test('renders the initial load of Step 1 correctly', () => { + // ---------- Components ---------- + // <TabHeader> - AntD header + const closeButton = screen.getByLabelText('Close'); + const step1Header = screen.getByRole('heading', { + name: /connect a database/i, + }); + // <ModalHeader> - Connection header + const step1Helper = screen.getByText(/step 1 of 3/i); + const selectDbHeader = screen.getByRole('heading', { + name: /select a database to connect/i, + }); + // <IconButton> - Preferred database buttons + const preferredDbButtonPostgreSQL = screen.getByRole('button', { + name: /postgresql/i, + }); + const preferredDbTextPostgreSQL = within( + preferredDbButtonPostgreSQL, + ).getByText(/postgresql/i); + const preferredDbButtonPresto = screen.getByRole('button', { + name: /presto/i, + }); + const preferredDbTextPresto = within(preferredDbButtonPresto).getByText( + /presto/i, + ); + const preferredDbButtonMySQL = screen.getByRole('button', { + name: /mysql/i, + }); + const preferredDbTextMySQL = within(preferredDbButtonMySQL).getByText( + /mysql/i, + ); + const preferredDbButtonSQLite = screen.getByRole('button', { + name: /sqlite/i, + }); + const preferredDbTextSQLite = within(preferredDbButtonSQLite).getByText( + /sqlite/i, + ); + // renderAvailableSelector() => <Select> - Supported databases selector + const supportedDbsHeader = screen.getByRole('heading', { + name: /or choose from a list of other databases we support:/i, + }); + const selectorLabel = screen.getByText(/supported databases/i); + const selectorPlaceholder = screen.getByText(/choose a database\.\.\./i); + const selectorArrow = screen.getByRole('img', { + name: /down/i, + hidden: true, + }); + + const footer = document.getElementsByClassName('ant-modal-footer'); + // ---------- TODO (lyndsiWilliams): Selector options, can't seem to get these to render properly. + + // renderAvailableSelector() => <Alert> - Supported databases alert + const alertIcon = screen.getByRole('img', { name: /info icon/i }); + const alertMessage = screen.getByText(/want to add a new database\?/i); + const alertDescription = screen.getByText( + /any databases that allow connections via sql alchemy uris can be added\. learn about how to connect a database driver \./i, + ); + const alertLink = screen.getByRole('link', { name: /here/i }); + + // ---------- Assertions ---------- + const visibleComponents = [ + closeButton, + step1Header, + step1Helper, + selectDbHeader, + supportedDbsHeader, + selectorLabel, + selectorPlaceholder, + selectorArrow, + alertIcon, + alertMessage, + alertDescription, + alertLink, + preferredDbButtonPostgreSQL, + preferredDbButtonPresto, + preferredDbButtonMySQL, + preferredDbButtonSQLite, + preferredDbTextPostgreSQL, + preferredDbTextPresto, + preferredDbTextMySQL, + preferredDbTextSQLite, + ]; + + visibleComponents.forEach(component => { + expect(component).toBeVisible(); + }); + // there should be a footer but it should not have any buttons in it + expect(footer[0]).toBeEmptyDOMElement(); + }); + + test('renders the "Basic" tab of SQL Alchemy form (step 2 of 2) correctly', async () => { + // On step 1, click dbButton to access SQL Alchemy form + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + + // ---------- Components ---------- + // <TabHeader> - AntD header + const closeButton = screen.getByRole('button', { name: /close/i }); + const basicHeader = screen.getByRole('heading', { + name: /connect a database/i, + }); + // <ModalHeader> - Connection header + const basicHelper = screen.getByText(/step 2 of 2/i); + const basicHeaderTitle = screen.getByText(/enter primary credentials/i); + const basicHeaderSubtitle = screen.getByText( + /need help\? learn how to connect your database \./i, + ); + const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { + name: /here/i, + }); + // <Tabs> - Basic/Advanced tabs + const basicTab = screen.getByRole('tab', { name: /basic/i }); + const advancedTab = screen.getByRole('tab', { name: /advanced/i }); + // <StyledBasicTab> - Basic tab's content + const displayNameLabel = screen.getByText(/display name*/i); + const displayNameInput = screen.getByTestId('database-name-input'); + const displayNameHelper = screen.getByText( + /pick a name to help you identify this database\./i, + ); + const SQLURILabel = screen.getByText(/sqlalchemy uri*/i); + const SQLURIInput = screen.getByTestId('sqlalchemy-uri-input'); + const SQLURIHelper = screen.getByText( + /refer to the for more information on how to structure your uri\./i, + ); + // <SSHTunnelForm> - Basic tab's SSH Tunnel Form + const SSHTunnelingToggle = screen.getByTestId('ssh-tunnel-switch'); + userEvent.click(SSHTunnelingToggle); + const SSHTunnelServerAddressInput = screen.getByTestId( + 'ssh-tunnel-server_address-input', + ); + const SSHTunnelServerPortInput = screen.getByTestId( + 'ssh-tunnel-server_port-input', + ); + const SSHTunnelUsernameInput = screen.getByTestId( + 'ssh-tunnel-username-input', + ); + const SSHTunnelPasswordInput = screen.getByTestId( + 'ssh-tunnel-password-input', + ); + const testConnectionButton = screen.getByRole('button', { + name: /test connection/i, + }); + // <Alert> - Basic tab's alert + const alertIcon = screen.getByRole('img', { name: /info icon/i }); + const alertMessage = screen.getByText( + /additional fields may be required/i, + ); + const alertDescription = screen.getByText( + /select databases require additional fields to be completed in the advanced tab to successfully connect the database\. learn what requirements your databases has \./i, + ); + const alertLink = within(alertDescription).getByRole('link', { + name: /here/i, + }); + // renderModalFooter() - Basic tab's footer + const backButton = screen.getByRole('button', { name: /back/i }); + const connectButton = screen.getByRole('button', { name: 'Connect' }); + + // ---------- Assertions ---------- + const visibleComponents = [ + closeButton, + basicHeader, + basicHelper, + basicHeaderTitle, + basicHeaderSubtitle, + basicHeaderLink, + basicTab, + advancedTab, + displayNameLabel, + displayNameInput, + displayNameHelper, + SQLURILabel, + SQLURIInput, + SQLURIHelper, + SSHTunnelingToggle, + SSHTunnelServerAddressInput, + SSHTunnelServerPortInput, + SSHTunnelUsernameInput, + SSHTunnelPasswordInput, + testConnectionButton, + alertIcon, + alertMessage, + alertDescription, + alertLink, + backButton, + connectButton, + ]; + + visibleComponents.forEach(component => { + expect(component).toBeVisible(); + }); + }); + + test('renders the unexpanded "Advanced" tab correctly', async () => { + // On step 1, click dbButton to access step 2 + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + // Click the "Advanced" tab + userEvent.click(screen.getByRole('tab', { name: /advanced/i })); + + // ---------- Components ---------- + // <TabHeader> - AntD header + const closeButton = screen.getByRole('button', { name: /close/i }); + const advancedHeader = screen.getByRole('heading', { + name: /connect a database/i, + }); + // <ModalHeader> - Connection header + const basicHelper = screen.getByText(/step 2 of 2/i); + const basicHeaderTitle = screen.getByText(/enter primary credentials/i); + const basicHeaderSubtitle = screen.getByText( + /need help\? learn how to connect your database \./i, + ); + const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { + name: /here/i, + }); + // <Tabs> - Basic/Advanced tabs + const basicTab = screen.getByRole('tab', { name: /basic/i }); + const advancedTab = screen.getByRole('tab', { name: /advanced/i }); + // <ExtraOptions> - Advanced tabs + const sqlLabTab = screen.getByRole('tab', { + name: /right sql lab adjust how this database will interact with sql lab\./i, + }); + const sqlLabTabArrow = within(sqlLabTab).getByRole('img', { + name: /right/i, + }); + const sqlLabTabHeading = screen.getByRole('heading', { + name: /sql lab/i, + }); + const performanceTab = screen.getByRole('tab', { + name: /right performance adjust performance settings of this database\./i, + }); + const performanceTabArrow = within(performanceTab).getByRole('img', { + name: /right/i, + }); + const performanceTabHeading = screen.getByRole('heading', { + name: /performance/i, + }); + const securityTab = screen.getByRole('tab', { + name: /right security add extra connection information\./i, + }); + const securityTabArrow = within(securityTab).getByRole('img', { + name: /right/i, + }); + const securityTabHeading = screen.getByRole('heading', { + name: /security/i, + }); + const otherTab = screen.getByRole('tab', { + name: /right other additional settings\./i, + }); + const otherTabArrow = within(otherTab).getByRole('img', { + name: /right/i, + }); + const otherTabHeading = screen.getByRole('heading', { name: /other/i }); + // renderModalFooter() - Advanced tab's footer + const backButton = screen.getByRole('button', { name: /back/i }); + const connectButton = screen.getByRole('button', { name: 'Connect' }); + + // ---------- Assertions ---------- + const visibleComponents = [ + closeButton, + advancedHeader, + basicHelper, + basicHeaderTitle, + basicHeaderSubtitle, + basicHeaderLink, + basicTab, + advancedTab, + sqlLabTab, + sqlLabTabArrow, + sqlLabTabHeading, + performanceTab, + performanceTabArrow, + performanceTabHeading, + securityTab, + securityTabArrow, + securityTabHeading, + otherTab, + otherTabArrow, + otherTabHeading, + backButton, + connectButton, + ]; + + visibleComponents.forEach(component => { + expect(component).toBeVisible(); + }); + }); + + test('renders the "Advanced" - SQL LAB tab correctly (unexpanded)', async () => { + // ---------- Components ---------- + // On step 1, click dbButton to access step 2 + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + // Click the "Advanced" tab + userEvent.click(screen.getByRole('tab', { name: /advanced/i })); + // Click the "SQL Lab" tab + userEvent.click( + screen.getByRole('tab', { + name: /right sql lab adjust how this database will interact with sql lab\./i, + }), + ); + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + + // ----- BEGIN STEP 2 (ADVANCED - SQL LAB) + // <TabHeader> - AntD header + const closeButton = screen.getByRole('button', { name: /close/i }); + const advancedHeader = screen.getByRole('heading', { + name: /connect a database/i, + }); + // <ModalHeader> - Connection header + const basicHelper = screen.getByText(/step 2 of 2/i); + const basicHeaderTitle = screen.getByText(/enter primary credentials/i); + const basicHeaderSubtitle = screen.getByText( + /need help\? learn how to connect your database \./i, + ); + const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { + name: /here/i, + }); + // <Tabs> - Basic/Advanced tabs + const basicTab = screen.getByRole('tab', { name: /basic/i }); + const advancedTab = screen.getByRole('tab', { name: /advanced/i }); + // <ExtraOptions> - Advanced tabs + const sqlLabTab = screen.getByRole('tab', { + name: /right sql lab adjust how this database will interact with sql lab\./i, + }); + // These are the checkbox SVGs that cover the actual checkboxes + const checkboxOffSVGs = screen.getAllByRole('img', { + name: /checkbox-off/i, + }); + const tooltipIcons = screen.getAllByRole('img', { + name: /info-solid_small/i, + }); + const exposeInSQLLabCheckbox = screen.getByRole('checkbox', { + name: /expose database in sql lab/i, + }); + // This is both the checkbox and it's respective SVG + // const exposeInSQLLabCheckboxSVG = checkboxOffSVGs[0].parentElement; + const exposeInSQLLabText = screen.getByText( + /expose database in sql lab/i, + ); + const allowCTASCheckbox = screen.getByRole('checkbox', { + name: /allow create table as/i, + }); + const allowCTASText = screen.getByText(/allow create table as/i); + const allowCVASCheckbox = screen.getByRole('checkbox', { + name: /allow create table as/i, + }); + const allowCVASText = screen.getByText(/allow create table as/i); + const CTASCVASLabelText = screen.getByText(/ctas & cvas schema/i); + // This grabs the whole input by placeholder text + const CTASCVASInput = screen.getByPlaceholderText( + /create or select schema\.\.\./i, + ); + const CTASCVASHelperText = screen.getByText( + /force all tables and views to be created in this schema when clicking ctas or cvas in sql lab\./i, + ); + const allowDMLCheckbox = screen.getByRole('checkbox', { + name: /allow dml/i, + }); + const allowDMLText = screen.getByText(/allow dml/i); + const enableQueryCostEstimationCheckbox = screen.getByRole('checkbox', { + name: /enable query cost estimation/i, + }); + const enableQueryCostEstimationText = screen.getByText( + /enable query cost estimation/i, + ); + const allowDbExplorationCheckbox = screen.getByRole('checkbox', { + name: /allow this database to be explored/i, + }); + const allowDbExplorationText = screen.getByText( + /allow this database to be explored/i, + ); + const disableSQLLabDataPreviewQueriesCheckbox = screen.getByRole( + 'checkbox', + { + name: /Disable SQL Lab data preview queries/i, + }, + ); + const disableSQLLabDataPreviewQueriesText = screen.getByText( + /Disable SQL Lab data preview queries/i, + ); + + // ---------- Assertions ---------- + const visibleComponents = [ + closeButton, + advancedHeader, + basicHelper, + basicHeaderTitle, + basicHeaderSubtitle, + basicHeaderLink, + basicTab, + advancedTab, + sqlLabTab, + checkboxOffSVGs[0], + checkboxOffSVGs[1], + checkboxOffSVGs[2], + checkboxOffSVGs[3], + checkboxOffSVGs[4], + tooltipIcons[0], + tooltipIcons[1], + tooltipIcons[2], + tooltipIcons[3], + tooltipIcons[4], + tooltipIcons[5], + tooltipIcons[6], + exposeInSQLLabText, + allowCTASText, + allowCVASText, + CTASCVASLabelText, + CTASCVASInput, + CTASCVASHelperText, + allowDMLText, + enableQueryCostEstimationText, + allowDbExplorationText, + disableSQLLabDataPreviewQueriesText, + ]; + // These components exist in the DOM but are not visible + const invisibleComponents = [ + exposeInSQLLabCheckbox, + allowCTASCheckbox, + allowCVASCheckbox, + allowDMLCheckbox, + enableQueryCostEstimationCheckbox, + allowDbExplorationCheckbox, + disableSQLLabDataPreviewQueriesCheckbox, + ]; + visibleComponents.forEach(component => { + expect(component).toBeVisible(); + }); + invisibleComponents.forEach(component => { + expect(component).not.toBeVisible(); + }); + expect(checkboxOffSVGs).toHaveLength(5); + expect(tooltipIcons).toHaveLength(7); + }); + + test('renders the "Advanced" - PERFORMANCE tab correctly', async () => { + // ---------- Components ---------- + // On step 1, click dbButton to access step 2 + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + // Click the "Advanced" tab + userEvent.click(screen.getByRole('tab', { name: /advanced/i })); + // Click the "Performance" tab + userEvent.click( + screen.getByRole('tab', { + name: /right performance adjust performance settings of this database\./i, + }), + ); + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + + // ----- BEGIN STEP 2 (ADVANCED - PERFORMANCE) + // <TabHeader> - AntD header + const closeButton = screen.getByRole('button', { name: /close/i }); + const advancedHeader = screen.getByRole('heading', { + name: /connect a database/i, + }); + // <ModalHeader> - Connection header + const basicHelper = screen.getByText(/step 2 of 2/i); + const basicHeaderTitle = screen.getByText(/enter primary credentials/i); + const basicHeaderSubtitle = screen.getByText( + /need help\? learn how to connect your database \./i, + ); + const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { + name: /here/i, + }); + // <Tabs> - Basic/Advanced tabs + const basicTab = screen.getByRole('tab', { name: /basic/i }); + const advancedTab = screen.getByRole('tab', { name: /advanced/i }); + // <ExtraOptions> - Advanced tabs + const sqlLabTab = screen.getByRole('tab', { + name: /right sql lab adjust how this database will interact with sql lab\./i, + }); + const performanceTab = screen.getByRole('tab', { + name: /right performance adjust performance settings of this database\./i, + }); + + // ---------- Assertions ---------- + const visibleComponents = [ + closeButton, + advancedHeader, + basicHelper, + basicHeaderTitle, + basicHeaderSubtitle, + basicHeaderLink, + basicTab, + advancedTab, + sqlLabTab, + performanceTab, + ]; + + visibleComponents.forEach(component => { + expect(component).toBeVisible(); + }); + }); + + test('renders the "Advanced" - SECURITY tab correctly', async () => { + // ---------- Components ---------- + // On step 1, click dbButton to access step 2 + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + // Click the "Advanced" tab + userEvent.click(screen.getByRole('tab', { name: /advanced/i })); + // Click the "Security" tab + userEvent.click( + screen.getByRole('tab', { + name: /right security add extra connection information\./i, + }), + ); + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + + // ----- BEGIN STEP 2 (ADVANCED - SECURITY) + // <TabHeader> - AntD header + const closeButton = screen.getByRole('button', { name: /close/i }); + const advancedHeader = screen.getByRole('heading', { + name: /connect a database/i, + }); + // <ModalHeader> - Connection header + const basicHelper = screen.getByText(/step 2 of 2/i); + const basicHeaderTitle = screen.getByText(/enter primary credentials/i); + const basicHeaderSubtitle = screen.getByText( + /need help\? learn how to connect your database \./i, + ); + const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { + name: /here/i, + }); + // <Tabs> - Basic/Advanced tabs + const basicTab = screen.getByRole('tab', { name: /basic/i }); + const advancedTab = screen.getByRole('tab', { name: /advanced/i }); + // <ExtraOptions> - Advanced tabs + const sqlLabTab = screen.getByRole('tab', { + name: /right sql lab adjust how this database will interact with sql lab\./i, + }); + const performanceTab = screen.getByRole('tab', { + name: /right performance adjust performance settings of this database\./i, + }); + const securityTab = screen.getByRole('tab', { + name: /right security add extra connection information\./i, + }); + const allowFileUploadCheckbox = screen.getByRole('checkbox', { + name: /Allow file uploads to database/i, + }); + const allowFileUploadText = screen.getByText( + /Allow file uploads to database/i, + ); + + const schemasForFileUploadText = screen.queryByText( + /Schemas allowed for File upload/i, + ); + + const visibleComponents = [ + closeButton, + advancedHeader, + basicHelper, + basicHeaderTitle, + basicHeaderSubtitle, + basicHeaderLink, + basicTab, + advancedTab, + sqlLabTab, + performanceTab, + securityTab, + allowFileUploadText, + ]; + // These components exist in the DOM but are not visible + const invisibleComponents = [allowFileUploadCheckbox]; + + // ---------- Assertions ---------- + visibleComponents.forEach(component => { + expect(component).toBeVisible(); + }); + invisibleComponents.forEach(component => { + expect(component).not.toBeVisible(); + }); + expect(schemasForFileUploadText).not.toBeInTheDocument(); + }); + + it('renders the "Advanced" - SECURITY tab correctly after selecting Allow file uploads', async () => { + // ---------- Components ---------- + // On step 1, click dbButton to access step 2 + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + // Click the "Advanced" tab + userEvent.click(screen.getByRole('tab', { name: /advanced/i })); + // Click the "Security" tab + userEvent.click( + screen.getByRole('tab', { + name: /right security add extra connection information\./i, + }), + ); + // Click the "Allow file uploads" tab + + const allowFileUploadCheckbox = screen.getByRole('checkbox', { + name: /Allow file uploads to database/i, + }); + userEvent.click(allowFileUploadCheckbox); + + // ----- BEGIN STEP 2 (ADVANCED - SECURITY) + // <TabHeader> - AntD header + const closeButton = screen.getByRole('button', { name: /close/i }); + const advancedHeader = screen.getByRole('heading', { + name: /connect a database/i, + }); + // <ModalHeader> - Connection header + const basicHelper = screen.getByText(/step 2 of 2/i); + const basicHeaderTitle = screen.getByText(/enter primary credentials/i); + const basicHeaderSubtitle = screen.getByText( + /need help\? learn how to connect your database \./i, + ); + const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { + name: /here/i, + }); + // <Tabs> - Basic/Advanced tabs + const basicTab = screen.getByRole('tab', { name: /basic/i }); + const advancedTab = screen.getByRole('tab', { name: /advanced/i }); + // <ExtraOptions> - Advanced tabs + const sqlLabTab = screen.getByRole('tab', { + name: /right sql lab adjust how this database will interact with sql lab\./i, + }); + const performanceTab = screen.getByRole('tab', { + name: /right performance adjust performance settings of this database\./i, + }); + const securityTab = screen.getByRole('tab', { + name: /right security add extra connection information\./i, + }); + const allowFileUploadText = screen.getByText( + /Allow file uploads to database/i, + ); + + const schemasForFileUploadText = screen.queryByText( + /Schemas allowed for File upload/i, + ); + + const visibleComponents = [ + closeButton, + advancedHeader, + basicHelper, + basicHeaderTitle, + basicHeaderSubtitle, + basicHeaderLink, + basicTab, + advancedTab, + sqlLabTab, + performanceTab, + securityTab, + allowFileUploadText, + ]; + // These components exist in the DOM but are not visible + const invisibleComponents = [allowFileUploadCheckbox]; + + // ---------- Assertions ---------- + visibleComponents.forEach(component => { + expect(component).toBeVisible(); + }); + invisibleComponents.forEach(component => { + expect(component).not.toBeVisible(); + }); + expect(schemasForFileUploadText).toBeInTheDocument(); + }); + + test('renders the "Advanced" - OTHER tab correctly', async () => { + // ---------- Components ---------- + // On step 1, click dbButton to access step 2 + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + // Click the "Advanced" tab + userEvent.click(screen.getByRole('tab', { name: /advanced/i })); + // Click the "Other" tab + userEvent.click( + screen.getByRole('tab', { + name: /right other additional settings\./i, + }), + ); + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + + // ----- BEGIN STEP 2 (ADVANCED - OTHER) + // <TabHeader> - AntD header + const closeButton = screen.getByRole('button', { name: /close/i }); + const advancedHeader = screen.getByRole('heading', { + name: /connect a database/i, + }); + // <ModalHeader> - Connection header + const basicHelper = screen.getByText(/step 2 of 2/i); + const basicHeaderTitle = screen.getByText(/enter primary credentials/i); + const basicHeaderSubtitle = screen.getByText( + /need help\? learn how to connect your database \./i, + ); + const basicHeaderLink = within(basicHeaderSubtitle).getByRole('link', { + name: /here/i, + }); + // <Tabs> - Basic/Advanced tabs + const basicTab = screen.getByRole('tab', { name: /basic/i }); + const advancedTab = screen.getByRole('tab', { name: /advanced/i }); + // <ExtraOptions> - Advanced tabs + const sqlLabTab = screen.getByRole('tab', { + name: /right sql lab adjust how this database will interact with sql lab\./i, + }); + const performanceTab = screen.getByRole('tab', { + name: /right performance adjust performance settings of this database\./i, + }); + const securityTab = screen.getByRole('tab', { + name: /right security add extra connection information\./i, + }); + const otherTab = screen.getByRole('tab', { + name: /right other additional settings\./i, + }); + + // ---------- Assertions ---------- + const visibleComponents = [ + closeButton, + advancedHeader, + basicHelper, + basicHeaderTitle, + basicHeaderSubtitle, + basicHeaderLink, + basicTab, + advancedTab, + sqlLabTab, + performanceTab, + securityTab, + otherTab, + ]; + + visibleComponents.forEach(component => { + expect(component).toBeVisible(); + }); + }); + + test('Dynamic form', async () => { + // ---------- Components ---------- + // On step 1, click dbButton to access step 2 + userEvent.click( + screen.getByRole('button', { + name: /postgresql/i, + }), + ); + expect(await screen.findByText(/step 2 of 3/i)).toBeInTheDocument(); + + expect.anything(); + }); + }); + + describe('Functional: Create new database', () => { + test('directs databases to the appropriate form (dynamic vs. SQL Alchemy)', async () => { + // ---------- Dynamic example (3-step form) + // Click the PostgreSQL button to enter the dynamic form + const postgreSQLButton = screen.getByRole('button', { + name: /postgresql/i, + }); + userEvent.click(postgreSQLButton); + + // Dynamic form has 3 steps, seeing this text means the dynamic form is present + const dynamicFormStepText = screen.getByText(/step 2 of 3/i); + + expect(dynamicFormStepText).toBeVisible(); + + // ---------- SQL Alchemy example (2-step form) + // Click the back button to go back to step 1, + // then click the SQLite button to enter the SQL Alchemy form + const backButton = screen.getByRole('button', { name: /back/i }); + userEvent.click(backButton); + + const sqliteButton = screen.getByRole('button', { + name: /sqlite/i, + }); + userEvent.click(sqliteButton); + + // SQL Alchemy form has 2 steps, seeing this text means the SQL Alchemy form is present + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + const sqlAlchemyFormStepText = screen.getByText(/step 2 of 2/i); + + expect(sqlAlchemyFormStepText).toBeVisible(); + }); + + describe('SQL Alchemy form flow', () => { + test('enters step 2 of 2 when proper database is selected', async () => { + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + }); + + test('runs fetchResource when "Connect" is clicked', () => { + /* ---------- 🐞 TODO (lyndsiWilliams): function mock is not currently working 🐞 ---------- + + // Mock useSingleViewResource + const mockUseSingleViewResource = jest.fn(); + mockUseSingleViewResource.mockImplementation(useSingleViewResource); + + const { fetchResource } = mockUseSingleViewResource('database'); + + // Invalid hook call? + userEvent.click(screen.getByRole('button', { name: 'Connect' })); + expect(fetchResource).toHaveBeenCalled(); + + The line below makes the linter happy */ + expect.anything(); + }); + + describe('step 2 component interaction', () => { + test('properly interacts with textboxes', async () => { + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + const dbNametextBox = screen.getByTestId('database-name-input'); + expect(dbNametextBox).toHaveValue('SQLite'); + + userEvent.type(dbNametextBox, 'Different text'); + expect(dbNametextBox).toHaveValue('SQLiteDifferent text'); + + const sqlAlchemyURItextBox = screen.getByTestId( + 'sqlalchemy-uri-input', + ); + expect(sqlAlchemyURItextBox).toHaveValue(''); + + userEvent.type(sqlAlchemyURItextBox, 'Different text'); + expect(sqlAlchemyURItextBox).toHaveValue('Different text'); + }); + + test('runs testDatabaseConnection when "TEST CONNECTION" is clicked', () => { + /* ---------- 🐞 TODO (lyndsiWilliams): function mock is not currently working 🐞 ---------- + + // Mock testDatabaseConnection + const mockTestDatabaseConnection = jest.fn(); + mockTestDatabaseConnection.mockImplementation(testDatabaseConnection); + + userEvent.click( + screen.getByRole('button', { + name: /test connection/i, + }), + ); + + expect(mockTestDatabaseConnection).toHaveBeenCalled(); + + The line below makes the linter happy */ + expect.anything(); + }); + }); + + describe('SSH Tunnel Form interaction', () => { + test('properly interacts with SSH Tunnel form textboxes for dynamic form', async () => { + userEvent.click( + screen.getByRole('button', { + name: /postgresql/i, + }), + ); + expect(await screen.findByText(/step 2 of 3/i)).toBeInTheDocument(); + const SSHTunnelingToggle = screen.getByTestId('ssh-tunnel-switch'); + userEvent.click(SSHTunnelingToggle); + const SSHTunnelServerAddressInput = screen.getByTestId( + 'ssh-tunnel-server_address-input', + ); + expect(SSHTunnelServerAddressInput).toHaveValue(''); + userEvent.type(SSHTunnelServerAddressInput, 'localhost'); + expect(SSHTunnelServerAddressInput).toHaveValue('localhost'); + const SSHTunnelServerPortInput = screen.getByTestId( + 'ssh-tunnel-server_port-input', + ); + expect(SSHTunnelServerPortInput).toHaveValue(''); + userEvent.type(SSHTunnelServerPortInput, '22'); + expect(SSHTunnelServerPortInput).toHaveValue('22'); + const SSHTunnelUsernameInput = screen.getByTestId( + 'ssh-tunnel-username-input', + ); + expect(SSHTunnelUsernameInput).toHaveValue(''); + userEvent.type(SSHTunnelUsernameInput, 'test'); + expect(SSHTunnelUsernameInput).toHaveValue('test'); + const SSHTunnelPasswordInput = screen.getByTestId( + 'ssh-tunnel-password-input', + ); + expect(SSHTunnelPasswordInput).toHaveValue(''); + userEvent.type(SSHTunnelPasswordInput, 'pass'); + expect(SSHTunnelPasswordInput).toHaveValue('pass'); + }); + + test('properly interacts with SSH Tunnel form textboxes', async () => { + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + const SSHTunnelingToggle = screen.getByTestId('ssh-tunnel-switch'); + userEvent.click(SSHTunnelingToggle); + const SSHTunnelServerAddressInput = screen.getByTestId( + 'ssh-tunnel-server_address-input', + ); + expect(SSHTunnelServerAddressInput).toHaveValue(''); + userEvent.type(SSHTunnelServerAddressInput, 'localhost'); + expect(SSHTunnelServerAddressInput).toHaveValue('localhost'); + const SSHTunnelServerPortInput = screen.getByTestId( + 'ssh-tunnel-server_port-input', + ); + expect(SSHTunnelServerPortInput).toHaveValue(''); + userEvent.type(SSHTunnelServerPortInput, '22'); + expect(SSHTunnelServerPortInput).toHaveValue('22'); + const SSHTunnelUsernameInput = screen.getByTestId( + 'ssh-tunnel-username-input', + ); + expect(SSHTunnelUsernameInput).toHaveValue(''); + userEvent.type(SSHTunnelUsernameInput, 'test'); + expect(SSHTunnelUsernameInput).toHaveValue('test'); + const SSHTunnelPasswordInput = screen.getByTestId( + 'ssh-tunnel-password-input', + ); + expect(SSHTunnelPasswordInput).toHaveValue(''); + userEvent.type(SSHTunnelPasswordInput, 'pass'); + expect(SSHTunnelPasswordInput).toHaveValue('pass'); + }); + + test('if the SSH Tunneling toggle is not true, no inputs are displayed', async () => { + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + const SSHTunnelingToggle = screen.getByTestId('ssh-tunnel-switch'); + expect(SSHTunnelingToggle).toBeVisible(); + const SSHTunnelServerAddressInput = screen.queryByTestId( + 'ssh-tunnel-server_address-input', + ); + expect(SSHTunnelServerAddressInput).not.toBeInTheDocument(); + const SSHTunnelServerPortInput = screen.queryByTestId( + 'ssh-tunnel-server_port-input', + ); + expect(SSHTunnelServerPortInput).not.toBeInTheDocument(); + const SSHTunnelUsernameInput = screen.queryByTestId( + 'ssh-tunnel-username-input', + ); + expect(SSHTunnelUsernameInput).not.toBeInTheDocument(); + const SSHTunnelPasswordInput = screen.queryByTestId( + 'ssh-tunnel-password-input', + ); + expect(SSHTunnelPasswordInput).not.toBeInTheDocument(); + }); + + test('If user changes the login method, the inputs change', async () => { + userEvent.click( + screen.getByRole('button', { + name: /sqlite/i, + }), + ); + + expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument(); + const SSHTunnelingToggle = screen.getByTestId('ssh-tunnel-switch'); + userEvent.click(SSHTunnelingToggle); + const SSHTunnelUsePasswordInput = screen.getByTestId( + 'ssh-tunnel-use_password-radio', + ); + expect(SSHTunnelUsePasswordInput).toBeVisible(); + const SSHTunnelUsePrivateKeyInput = screen.getByTestId( + 'ssh-tunnel-use_private_key-radio', + ); + expect(SSHTunnelUsePrivateKeyInput).toBeVisible(); + const SSHTunnelPasswordInput = screen.getByTestId( + 'ssh-tunnel-password-input', + ); + // By default, we use Password as login method + expect(SSHTunnelPasswordInput).toBeVisible(); + // Change the login method to use private key + userEvent.click(SSHTunnelUsePrivateKeyInput); + const SSHTunnelPrivateKeyInput = screen.getByTestId( + 'ssh-tunnel-private_key-input', + ); + expect(SSHTunnelPrivateKeyInput).toBeVisible(); + const SSHTunnelPrivateKeyPasswordInput = screen.getByTestId( + 'ssh-tunnel-private_key_password-input', + ); + expect(SSHTunnelPrivateKeyPasswordInput).toBeVisible(); + }); + }); + }); + + describe('Dynamic form flow', () => { + test('enters step 2 of 3 when proper database is selected', async () => { + expect(await screen.findByText(/step 1 of 3/i)).toBeInTheDocument(); + userEvent.click( + screen.getByRole('button', { + name: /postgresql/i, + }), + ); + expect(await screen.findByText(/step 2 of 3/i)).toBeInTheDocument(); + + const step2of3text = screen.getByText(/step 2 of 3/i); + expect(step2of3text).toBeVisible(); + }); + + test('enters form credentials and runs fetchResource when "Connect" is clicked', async () => { + userEvent.click( + screen.getByRole('button', { + name: /postgresql/i, + }), + ); + + const textboxes = screen.getAllByRole('textbox'); + const hostField = textboxes[0]; + const portField = screen.getByRole('spinbutton'); + const databaseNameField = textboxes[1]; + const usernameField = textboxes[2]; + const passwordField = textboxes[3]; + const connectButton = screen.getByRole('button', { name: 'Connect' }); + + expect(hostField).toHaveValue(''); + expect(portField).toHaveValue(null); + expect(databaseNameField).toHaveValue(''); + expect(usernameField).toHaveValue(''); + expect(passwordField).toHaveValue(''); + + userEvent.type(hostField, 'localhost'); + userEvent.type(portField, '5432'); + userEvent.type(databaseNameField, 'postgres'); + userEvent.type(usernameField, 'testdb'); + userEvent.type(passwordField, 'demoPassword'); + + expect(await screen.findByDisplayValue(/5432/i)).toBeInTheDocument(); + expect(hostField).toHaveValue('localhost'); + expect(portField).toHaveValue(5432); + expect(databaseNameField).toHaveValue('postgres'); + expect(usernameField).toHaveValue('testdb'); + expect(passwordField).toHaveValue('demoPassword'); + + userEvent.click(connectButton); + await waitFor(() => { + expect(fetchMock.calls(VALIDATE_PARAMS_ENDPOINT).length).toEqual(6); + }); + }); + }); + + describe('Import database flow', () => { + test('imports a file', async () => { + const importDbButton = screen.getByTestId( + 'import-database-btn', + ) as HTMLInputElement; + expect(importDbButton).toBeVisible(); + + const testFile = new File([new ArrayBuffer(1)], 'model_export.zip'); + + userEvent.click(importDbButton); + userEvent.upload(importDbButton, testFile); + + expect(importDbButton.files?.[0]).toStrictEqual(testFile); + expect(importDbButton.files?.item(0)).toStrictEqual(testFile); + expect(importDbButton.files).toHaveLength(1); + }); + }); + }); + + describe('DatabaseModal w/ Deeplinking Engine', () => { + const renderAndWait = async () => { + const mounted = act(async () => { + render(<DatabaseModal {...dbProps} dbEngine="PostgreSQL" />, { + useRedux: true, + }); + }); + + return mounted; + }; + + beforeEach(async () => { + await renderAndWait(); + }); + + test('enters step 2 of 3 when proper database is selected', () => { + const step2of3text = screen.getByText(/step 2 of 3/i); + expect(step2of3text).toBeVisible(); + }); + }); + + describe('DatabaseModal w/ GSheet Engine', () => { + const renderAndWait = async () => { + const dbProps = { + show: true, + database_name: 'my database', + sqlalchemy_uri: 'gsheets://', + }; + const mounted = act(async () => { + render(<DatabaseModal {...dbProps} dbEngine="Google Sheets" />, { + useRedux: true, + }); + }); + + return mounted; + }; + + beforeEach(async () => { + await renderAndWait(); + }); + + it('enters step 2 of 2 when proper database is selected', () => { + const step2of2text = screen.getByText(/step 2 of 2/i); + expect(step2of2text).toBeVisible(); + }); + + it('renders the "Advanced" - SECURITY tab without Allow File Upload Checkbox', async () => { + // Click the "Advanced" tab + userEvent.click(screen.getByRole('tab', { name: /advanced/i })); + // Click the "Security" tab + userEvent.click( + screen.getByRole('tab', { + name: /right security add extra connection information\./i, + }), + ); + + // ----- BEGIN STEP 2 (ADVANCED - SECURITY) + // <ExtraOptions> - Advanced tabs + const impersonateLoggerUserCheckbox = screen.getByRole('checkbox', { + name: /impersonate logged in/i, + }); + const impersonateLoggerUserText = screen.getByText( + /impersonate logged in/i, + ); + const allowFileUploadText = screen.queryByText( + /Allow file uploads to database/i, + ); + const schemasForFileUploadText = screen.queryByText( + /Schemas allowed for File upload/i, + ); + + const visibleComponents = [impersonateLoggerUserText]; + // These components exist in the DOM but are not visible + const invisibleComponents = [impersonateLoggerUserCheckbox]; + + // ---------- Assertions ---------- + visibleComponents.forEach(component => { + expect(component).toBeVisible(); + }); + invisibleComponents.forEach(component => { + expect(component).not.toBeVisible(); + }); + expect(allowFileUploadText).not.toBeInTheDocument(); + expect(schemasForFileUploadText).not.toBeInTheDocument(); + }); + + it('if the SSH Tunneling toggle is not displayed, nothing should get displayed', async () => { + const SSHTunnelingToggle = screen.queryByTestId('ssh-tunnel-switch'); + expect(SSHTunnelingToggle).not.toBeInTheDocument(); + const SSHTunnelServerAddressInput = screen.queryByTestId( + 'ssh-tunnel-server_address-input', + ); + expect(SSHTunnelServerAddressInput).not.toBeInTheDocument(); + const SSHTunnelServerPortInput = screen.queryByTestId( + 'ssh-tunnel-server_port-input', + ); + expect(SSHTunnelServerPortInput).not.toBeInTheDocument(); + const SSHTunnelUsernameInput = screen.queryByTestId( + 'ssh-tunnel-username-input', + ); + expect(SSHTunnelUsernameInput).not.toBeInTheDocument(); + const SSHTunnelPasswordInput = screen.queryByTestId( + 'ssh-tunnel-password-input', + ); + expect(SSHTunnelPasswordInput).not.toBeInTheDocument(); + }); + }); + + describe('DatabaseModal w errors as objects', () => { + jest.mock('src/views/CRUD/hooks', () => ({ + ...jest.requireActual('src/views/CRUD/hooks'), + useSingleViewResource: jest.fn(), + })); + + const renderAndWait = async () => { + const mounted = act(async () => { + render(<DatabaseModal {...dbProps} dbEngine="PostgreSQL" />, { + useRedux: true, + }); + }); + + return mounted; + }; + + beforeEach(async () => { + await renderAndWait(); + }); + + test('Error displays when it is an object', async () => { + const step2of3text = screen.getByText(/step 2 of 3/i); + const errorSection = screen.getByText(/Database Creation Error/i); + expect(step2of3text).toBeVisible(); + expect(errorSection).toBeVisible(); + }); + }); + + describe('DatabaseModal w errors as strings', () => { + jest.mock('src/views/CRUD/hooks', () => ({ + ...jest.requireActual('src/views/CRUD/hooks'), + useSingleViewResource: jest.fn(), + })); + const useSingleViewResourceMock = jest.spyOn( + hooks, + 'useSingleViewResource', + ); + + useSingleViewResourceMock.mockReturnValue({ + state: { + loading: false, + resource: null, + error: 'Test Error With String', + }, + fetchResource: jest.fn(), + createResource: jest.fn(), + updateResource: jest.fn(), + clearError: jest.fn(), + setResource: jest.fn(), + }); + + const renderAndWait = async () => { + const mounted = act(async () => { + render(<DatabaseModal {...dbProps} dbEngine="PostgreSQL" />, { + useRedux: true, + }); + }); + + return mounted; + }; + + beforeEach(async () => { + await renderAndWait(); + }); + + test('Error displays when it is a string', async () => { + const step2of3text = screen.getByText(/step 2 of 3/i); + const errorTitleMessage = screen.getByText(/Database Creation Error/i); + const button = screen.getByText('See more'); + userEvent.click(button); + const errorMessage = screen.getByText(/Test Error With String/i); + expect(errorMessage).toBeVisible(); + const closeButton = screen.getByText('Close'); + userEvent.click(closeButton); + expect(step2of3text).toBeVisible(); + expect(errorTitleMessage).toBeVisible(); + }); + }); + + describe('DatabaseModal w Extensions', () => { + const renderAndWait = async () => { + const extensionsRegistry = getExtensionsRegistry(); + + extensionsRegistry.set('ssh_tunnel.form.switch', () => ( + <>ssh_tunnel.form.switch extension component</> + )); + + setupExtensions(); + + const mounted = act(async () => { + render(<DatabaseModal {...dbProps} dbEngine="SQLite" />, { + useRedux: true, + }); + }); + + return mounted; + }; + + beforeEach(async () => { + await renderAndWait(); + }); + + test('should render an extension component if one is supplied', () => { + expect( + screen.getByText('ssh_tunnel.form.switch extension component'), + ).toBeInTheDocument(); + }); + }); +}); + +describe('dbReducer', () => { + test('it will reset state to null', () => { + const action: DBReducerActionType = { type: ActionType.reset }; + const currentState = dbReducer(databaseFixture, action); + expect(currentState).toBeNull(); + }); + + test('it will set state to payload from fetched', () => { + const action: DBReducerActionType = { + type: ActionType.fetched, + payload: databaseFixture, + }; + const currentState = dbReducer({}, action); + expect(currentState).toEqual({ + ...databaseFixture, + engine: 'postgres', + masked_encrypted_extra: '', + parameters: undefined, + query_input: '', + }); + }); + + test('it will set state to payload from extra editor', () => { + const action: DBReducerActionType = { + type: ActionType.extraEditorChange, + payload: { name: 'foo', json: JSON.stringify({ bar: 1 }) }, + }; + const currentState = dbReducer(databaseFixture, action); + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"foo":{"bar":1}}', + }); + }); + + test('it will set state to payload from editor', () => { + const action: DBReducerActionType = { + type: ActionType.editorChange, + payload: { name: 'foo', json: JSON.stringify({ bar: 1 }) }, + }; + const currentState = dbReducer(databaseFixture, action); + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + foo: JSON.stringify({ bar: 1 }), + }); + }); + + test('it will add extra payload to existing extra data', () => { + const action: DBReducerActionType = { + type: ActionType.extraEditorChange, + payload: { name: 'foo', json: JSON.stringify({ bar: 1 }) }, + }; + // extra should be a string + const currentState = dbReducer( + { + ...databaseFixture, + extra: JSON.stringify({ name: 'baz', json: { fiz: 2 } }), + }, + action, + ); + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"name":"baz","json":{"fiz":2},"foo":{"bar":1}}', + }); + }); + + test('it will set state to payload from extra input change', () => { + const action: DBReducerActionType = { + type: ActionType.extraInputChange, + payload: { name: 'foo', value: 'bar' }, + }; + const currentState = dbReducer(databaseFixture, action); + + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"foo":"bar"}', + }); + }); + + test('it will set state to payload from extra input change when checkbox', () => { + const action: DBReducerActionType = { + type: ActionType.extraInputChange, + payload: { name: 'foo', type: 'checkbox', checked: true }, + }; + const currentState = dbReducer(databaseFixture, action); + + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"foo":true}', + }); + }); + + test('it will set state to payload from extra input change when schema_cache_timeout', () => { + const action: DBReducerActionType = { + type: ActionType.extraInputChange, + payload: { name: 'schema_cache_timeout', value: 'bar' }, + }; + const currentState = dbReducer(databaseFixture, action); + + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"metadata_cache_timeout":{"schema_cache_timeout":"bar"}}', + }); + }); + + test('it will set state to payload from extra input change when table_cache_timeout', () => { + const action: DBReducerActionType = { + type: ActionType.extraInputChange, + payload: { name: 'table_cache_timeout', value: 'bar' }, + }; + const currentState = dbReducer(databaseFixture, action); + + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"metadata_cache_timeout":{"table_cache_timeout":"bar"}}', + }); + }); + + test('it will overwrite state to payload from extra input change when table_cache_timeout', () => { + const action: DBReducerActionType = { + type: ActionType.extraInputChange, + payload: { name: 'table_cache_timeout', value: 'bar' }, + }; + const currentState = dbReducer( + { + ...databaseFixture, + extra: '{"metadata_cache_timeout":{"table_cache_timeout":"foo"}}', + }, + action, + ); + + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"metadata_cache_timeout":{"table_cache_timeout":"bar"}}', + }); + }); + + test(`it will set state to payload from extra + input change when schemas_allowed_for_file_upload`, () => { + const action: DBReducerActionType = { + type: ActionType.extraInputChange, + payload: { name: 'schemas_allowed_for_file_upload', value: 'bar' }, + }; + const currentState = dbReducer(databaseFixture, action); + + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"schemas_allowed_for_file_upload":["bar"]}', + }); + }); + + test(`it will overwrite state to payload from extra + input change when schemas_allowed_for_file_upload`, () => { + const action: DBReducerActionType = { + type: ActionType.extraInputChange, + payload: { name: 'schemas_allowed_for_file_upload', value: 'bar' }, + }; + const currentState = dbReducer( + { + ...databaseFixture, + extra: '{"schemas_allowed_for_file_upload":["foo"]}', + }, + action, + ); + + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"schemas_allowed_for_file_upload":["bar"]}', + }); + }); + + test(`it will set state to payload from extra + input change when schemas_allowed_for_file_upload + with blank list`, () => { + const action: DBReducerActionType = { + type: ActionType.extraInputChange, + payload: { name: 'schemas_allowed_for_file_upload', value: 'bar,' }, + }; + const currentState = dbReducer(databaseFixture, action); + + // extra should be serialized + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"schemas_allowed_for_file_upload":["bar"]}', + }); + }); + + test('it will set state to payload from input change', () => { + const action: DBReducerActionType = { + type: ActionType.inputChange, + payload: { name: 'foo', value: 'bar' }, + }; + const currentState = dbReducer(databaseFixture, action); + + expect(currentState).toEqual({ + ...databaseFixture, + foo: 'bar', + }); + }); + + test('it will set state to payload from input change for checkbox', () => { + const action: DBReducerActionType = { + type: ActionType.inputChange, + payload: { name: 'foo', type: 'checkbox', checked: true }, + }; + const currentState = dbReducer(databaseFixture, action); + + expect(currentState).toEqual({ + ...databaseFixture, + foo: true, + }); + }); + + test('it will change state to payload from input change for checkbox', () => { + const action: DBReducerActionType = { + type: ActionType.inputChange, + payload: { name: 'allow_ctas', type: 'checkbox', checked: false }, + }; + const currentState = dbReducer( + { + ...databaseFixture, + allow_ctas: true, + }, + action, + ); + + expect(currentState).toEqual({ + ...databaseFixture, + allow_ctas: false, + }); + }); + + test('it will add a parameter', () => { + const action: DBReducerActionType = { + type: ActionType.parametersChange, + payload: { name: 'host', value: '127.0.0.1' }, + }; + const currentState = dbReducer(databaseFixture, action); + + expect(currentState).toEqual({ + ...databaseFixture, + parameters: { + host: '127.0.0.1', + }, + }); + }); + + test('it will add a parameter with existing parameters', () => { + const action: DBReducerActionType = { + type: ActionType.parametersChange, + payload: { name: 'port', value: '1234' }, + }; + const currentState = dbReducer( + { + ...databaseFixture, + parameters: { + host: '127.0.0.1', + }, + }, + action, + ); + + expect(currentState).toEqual({ + ...databaseFixture, + parameters: { + host: '127.0.0.1', + port: '1234', + }, + }); + }); + + test('it will change a parameter with existing parameters', () => { + const action: DBReducerActionType = { + type: ActionType.parametersChange, + payload: { name: 'host', value: 'localhost' }, + }; + const currentState = dbReducer( + { + ...databaseFixture, + parameters: { + host: '127.0.0.1', + }, + }, + action, + ); + + expect(currentState).toEqual({ + ...databaseFixture, + parameters: { + host: 'localhost', + }, + }); + }); + + test('it will set state to payload from parametersChange with catalog', () => { + const action: DBReducerActionType = { + type: ActionType.parametersChange, + payload: { name: 'name', type: 'catalog-0', value: 'bar' }, + }; + const currentState = dbReducer( + { ...databaseFixture, catalog: [{ name: 'foo', value: 'baz' }] }, + action, + ); + + expect(currentState).toEqual({ + ...databaseFixture, + catalog: [{ name: 'bar', value: 'baz' }], + parameters: { + catalog: { + bar: 'baz', + }, + }, + }); + }); + + test('it will add a new catalog array when empty', () => { + const action: DBReducerActionType = { + type: ActionType.addTableCatalogSheet, + }; + const currentState = dbReducer(databaseFixture, action); + + expect(currentState).toEqual({ + ...databaseFixture, + catalog: [{ name: '', value: '' }], + }); + }); + + test('it will add a new catalog array when one exists', () => { + const action: DBReducerActionType = { + type: ActionType.addTableCatalogSheet, + }; + const currentState = dbReducer( + { ...databaseFixture, catalog: [{ name: 'foo', value: 'baz' }] }, + action, + ); + + expect(currentState).toEqual({ + ...databaseFixture, + catalog: [ + { name: 'foo', value: 'baz' }, + { name: '', value: '' }, + ], + }); + }); + + test('it will remove a catalog when one exists', () => { + const action: DBReducerActionType = { + type: ActionType.removeTableCatalogSheet, + payload: { indexToDelete: 0 }, + }; + const currentState = dbReducer( + { ...databaseFixture, catalog: [{ name: 'foo', value: 'baz' }] }, + action, + ); + + expect(currentState).toEqual({ + ...databaseFixture, + catalog: [], + }); + }); + + test('it will add db information when one is selected', () => { + const { backend, ...db } = databaseFixture; + const action: DBReducerActionType = { + type: ActionType.dbSelected, + payload: { + engine_information: { + supports_file_upload: true, + disable_ssh_tunneling: false, + }, + ...db, + driver: db.driver, + engine: backend, + }, + }; + const currentState = dbReducer({}, action); + + expect(currentState).toEqual({ + database_name: db.database_name, + engine: backend, + configuration_method: db.configuration_method, + engine_information: { + supports_file_upload: true, + disable_ssh_tunneling: false, + }, + driver: db.driver, + expose_in_sqllab: true, + extra: '{"allows_virtual_table_explore":true}', + is_managed_externally: false, + name: 'PostgresDB', + }); + }); + + test('it will add a SSH Tunnel config parameter', () => { + const action: DBReducerActionType = { + type: ActionType.parametersSSHTunnelChange, + payload: { name: 'server_address', value: '127.0.0.1' }, + }; + const currentState = dbReducer(databaseFixture, action); + + expect(currentState).toEqual({ + ...databaseFixture, + ssh_tunnel: { + server_address: '127.0.0.1', + }, + }); + }); + + test('it will add a SSH Tunnel config parameter with existing configs', () => { + const action: DBReducerActionType = { + type: ActionType.parametersSSHTunnelChange, + payload: { name: 'server_port', value: '22' }, + }; + const currentState = dbReducer( + { + ...databaseFixture, + ssh_tunnel: { + server_address: '127.0.0.1', + }, + }, + action, + ); + + expect(currentState).toEqual({ + ...databaseFixture, + ssh_tunnel: { + server_address: '127.0.0.1', + server_port: '22', + }, + }); + }); + + test('it will change a SSH Tunnel config parameter with existing configs', () => { + const action: DBReducerActionType = { + type: ActionType.parametersSSHTunnelChange, + payload: { name: 'server_address', value: 'localhost' }, + }; + const currentState = dbReducer( + { + ...databaseFixture, + ssh_tunnel: { + server_address: '127.0.0.1', + }, + }, + action, + ); + + expect(currentState).toEqual({ + ...databaseFixture, + ssh_tunnel: { + server_address: 'localhost', + }, + }); + }); + + test('it will remove the SSH Tunnel config parameters', () => { + const action: DBReducerActionType = { + type: ActionType.removeSSHTunnelConfig, + }; + const currentState = dbReducer(databaseFixture, action); + expect(currentState).toEqual({ + ...databaseFixture, + ssh_tunnel: undefined, + }); + }); +}); diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx index 7891e6b0e2ed9..35151598e08d3 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx @@ -22,6 +22,7 @@ import { SupersetTheme, FeatureFlag, isFeatureEnabled, + getExtensionsRegistry, } from '@superset-ui/core'; import React, { FunctionComponent, @@ -31,6 +32,7 @@ import React, { useReducer, Reducer, } from 'react'; +import { setItem, LocalStorageKeys } from 'src/utils/localStorageHelpers'; import { UploadChangeParam, UploadFile } from 'antd/lib/upload/interface'; import Tabs from 'src/components/Tabs'; import { AntdSelect, Upload } from 'src/components'; @@ -41,6 +43,8 @@ import IconButton from 'src/components/IconButton'; import InfoTooltip from 'src/components/InfoTooltip'; import withToasts from 'src/components/MessageToasts/withToasts'; import ValidatedInput from 'src/components/Form/LabeledErrorBoundInput'; +import ErrorMessageWithStackTrace from 'src/components/ErrorMessage/ErrorMessageWithStackTrace'; +import ErrorAlert from 'src/components/ImportModal/ErrorAlert'; import { testDatabaseConnection, useSingleViewResource, @@ -56,13 +60,15 @@ import { DatabaseForm, CONFIGURATION_METHOD, CatalogObject, + Engines, + ExtraJson, } from 'src/views/CRUD/data/database/types'; import Loading from 'src/components/Loading'; +import { isEmpty, pick } from 'lodash'; import ExtraOptions from './ExtraOptions'; import SqlAlchemyForm from './SqlAlchemyForm'; import DatabaseConnectionForm from './DatabaseConnectionForm'; import { - antDErrorAlertStyles, antDAlertStyles, antdWarningAlertStyles, StyledAlertMargin, @@ -84,11 +90,12 @@ import { StyledUploadWrapper, } from './styles'; import ModalHeader, { DOCUMENTATION_LINK } from './ModalHeader'; +import SSHTunnelForm from './SSHTunnelForm'; +import SSHTunnelSwitch from './SSHTunnelSwitch'; -enum Engines { - GSheet = 'gsheets', - Snowflake = 'snowflake', -} +const extensionsRegistry = getExtensionsRegistry(); + +const DEFAULT_EXTRA = JSON.stringify({ allows_virtual_table_explore: true }); const engineSpecificAlertMapping = { [Engines.GSheet]: { @@ -114,42 +121,63 @@ const TabsStyled = styled(Tabs)` } `; +const ErrorAlertContainer = styled.div` + ${({ theme }) => ` + margin: ${theme.gridUnit * 8}px ${theme.gridUnit * 4}px; + `}; +`; + +const SSHTunnelContainer = styled.div` + ${({ theme }) => ` + padding: 0px ${theme.gridUnit * 4}px; + `}; +`; + interface DatabaseModalProps { addDangerToast: (msg: string) => void; addSuccessToast: (msg: string) => void; - onDatabaseAdd?: (database?: DatabaseObject) => void; // TODO: should we add a separate function for edit? + onDatabaseAdd?: (database?: DatabaseObject) => void; onHide: () => void; show: boolean; databaseId: number | undefined; // If included, will go into edit mode dbEngine: string | undefined; // if included goto step 2 with engine already set + history?: any; } -enum ActionType { +export enum ActionType { + addTableCatalogSheet, configMethodChange, dbSelected, editorChange, + extraEditorChange, + extraInputChange, fetched, inputChange, parametersChange, + queryChange, + removeTableCatalogSheet, reset, textChange, - extraInputChange, - extraEditorChange, - addTableCatalogSheet, - removeTableCatalogSheet, - queryChange, + parametersSSHTunnelChange, + setSSHTunnelLoginMethod, + removeSSHTunnelConfig, +} + +export enum AuthType { + password, + privateKey, } interface DBReducerPayloadType { target?: string; name: string; - json?: {}; + json?: string; type?: string; checked?: boolean; value?: string; } -type DBReducerActionType = +export type DBReducerActionType = | { type: | ActionType.extraEditorChange @@ -158,7 +186,8 @@ type DBReducerActionType = | ActionType.queryChange | ActionType.inputChange | ActionType.editorChange - | ActionType.parametersChange; + | ActionType.parametersChange + | ActionType.parametersSSHTunnelChange; payload: DBReducerPayloadType; } | { @@ -171,10 +200,15 @@ type DBReducerActionType = database_name?: string; engine?: string; configuration_method: CONFIGURATION_METHOD; + engine_information?: {}; + driver?: string; }; } | { - type: ActionType.reset | ActionType.addTableCatalogSheet; + type: + | ActionType.reset + | ActionType.addTableCatalogSheet + | ActionType.removeSSHTunnelConfig; } | { type: ActionType.removeTableCatalogSheet; @@ -189,9 +223,20 @@ type DBReducerActionType = engine?: string; configuration_method: CONFIGURATION_METHOD; }; + } + | { + type: ActionType.setSSHTunnelLoginMethod; + payload: { + login_method: AuthType; + }; }; -function dbReducer( +const StyledBtns = styled.div` + margin-bottom: ${({ theme }) => theme.gridUnit * 3}px; + margin-left: ${({ theme }) => theme.gridUnit * 3}px; +`; + +export function dbReducer( state: Partial<DatabaseObject> | null, action: DBReducerActionType, ): Partial<DatabaseObject> | null { @@ -200,54 +245,77 @@ function dbReducer( }; let query = {}; let query_input = ''; - let deserializeExtraJSON = { allows_virtual_table_explore: true }; - let extra_json: DatabaseObject['extra_json']; + let parametersCatalog; + let actionPayloadJson; + const extraJson: ExtraJson = JSON.parse(trimmedState.extra || '{}'); switch (action.type) { case ActionType.extraEditorChange: + // "extra" payload in state is a string + try { + // we don't want to stringify encoded strings twice + actionPayloadJson = JSON.parse(action.payload.json || '{}'); + } catch (e) { + actionPayloadJson = action.payload.json; + } return { ...trimmedState, - extra_json: { - ...trimmedState.extra_json, - [action.payload.name]: action.payload.json, - }, + extra: JSON.stringify({ + ...extraJson, + [action.payload.name]: actionPayloadJson, + }), }; case ActionType.extraInputChange: + // "extra" payload in state is a string + if ( action.payload.name === 'schema_cache_timeout' || action.payload.name === 'table_cache_timeout' ) { return { ...trimmedState, - extra_json: { - ...trimmedState.extra_json, + extra: JSON.stringify({ + ...extraJson, metadata_cache_timeout: { - ...trimmedState.extra_json?.metadata_cache_timeout, + ...extraJson?.metadata_cache_timeout, [action.payload.name]: action.payload.value, }, - }, + }), }; } if (action.payload.name === 'schemas_allowed_for_file_upload') { return { ...trimmedState, - extra_json: { - ...trimmedState.extra_json, - schemas_allowed_for_file_upload: (action.payload.value || '').split( - ',', - ), - }, + extra: JSON.stringify({ + ...extraJson, + schemas_allowed_for_file_upload: (action.payload.value || '') + .split(',') + .filter(schema => schema !== ''), + }), + }; + } + if (action.payload.name === 'http_path') { + return { + ...trimmedState, + extra: JSON.stringify({ + ...extraJson, + engine_params: { + connect_args: { + [action.payload.name]: action.payload.value?.trim(), + }, + }, + }), }; } return { ...trimmedState, - extra_json: { - ...trimmedState.extra_json, + extra: JSON.stringify({ + ...extraJson, [action.payload.name]: action.payload.type === 'checkbox' ? action.payload.checked : action.payload.value, - }, + }), }; case ActionType.inputChange: if (action.payload.type === 'checkbox') { @@ -261,26 +329,36 @@ function dbReducer( [action.payload.name]: action.payload.value, }; case ActionType.parametersChange: + // catalog params will always have a catalog state for + // dbs that use a catalog, i.e., gsheets, even if the + // fields are empty strings if ( - trimmedState.catalog !== undefined && - action.payload.type?.startsWith('catalog') + action.payload.type?.startsWith('catalog') && + trimmedState.catalog !== undefined ) { // Formatting wrapping google sheets table catalog + const catalogCopy: CatalogObject[] = [...trimmedState.catalog]; const idx = action.payload.type?.split('-')[1]; - const catalogToUpdate = trimmedState?.catalog[idx] || {}; + const catalogToUpdate: CatalogObject = catalogCopy[idx] || {}; catalogToUpdate[action.payload.name] = action.payload.value; - const paramatersCatalog = {}; + // insert updated catalog to existing state + catalogCopy.splice(parseInt(idx, 10), 1, catalogToUpdate); + + // format catalog for state // eslint-disable-next-line array-callback-return - trimmedState.catalog?.map((item: CatalogObject) => { - paramatersCatalog[item.name] = item.value; - }); + parametersCatalog = catalogCopy.reduce((obj, item: any) => { + const catalog = { ...obj }; + catalog[item.name] = item.value; + return catalog; + }, {}); return { ...trimmedState, + catalog: catalogCopy, parameters: { ...trimmedState.parameters, - catalog: paramatersCatalog, + catalog: parametersCatalog, }, }; } @@ -291,6 +369,55 @@ function dbReducer( [action.payload.name]: action.payload.value, }, }; + + case ActionType.parametersSSHTunnelChange: + return { + ...trimmedState, + ssh_tunnel: { + ...trimmedState.ssh_tunnel, + [action.payload.name]: action.payload.value, + }, + }; + case ActionType.setSSHTunnelLoginMethod: { + let ssh_tunnel = {}; + if (trimmedState?.ssh_tunnel) { + // remove any attributes that are considered sensitive + ssh_tunnel = pick(trimmedState.ssh_tunnel, [ + 'id', + 'server_address', + 'server_port', + 'username', + ]); + } + if (action.payload.login_method === AuthType.privateKey) { + return { + ...trimmedState, + ssh_tunnel: { + private_key: trimmedState?.ssh_tunnel?.private_key, + private_key_password: + trimmedState?.ssh_tunnel?.private_key_password, + ...ssh_tunnel, + }, + }; + } + if (action.payload.login_method === AuthType.password) { + return { + ...trimmedState, + ssh_tunnel: { + password: trimmedState?.ssh_tunnel?.password, + ...ssh_tunnel, + }, + }; + } + return { + ...trimmedState, + }; + } + case ActionType.removeSSHTunnelConfig: + return { + ...trimmedState, + ssh_tunnel: undefined, + }; case ActionType.addTableCatalogSheet: if (trimmedState.catalog !== undefined) { return { @@ -327,22 +454,6 @@ function dbReducer( [action.payload.name]: action.payload.value, }; case ActionType.fetched: - // convert all the keys in this payload into strings - if (action.payload.extra) { - extra_json = { - ...JSON.parse(action.payload.extra || ''), - } as DatabaseObject['extra_json']; - - deserializeExtraJSON = { - ...deserializeExtraJSON, - ...JSON.parse(action.payload.extra || ''), - metadata_params: JSON.stringify(extra_json?.metadata_params), - engine_params: JSON.stringify(extra_json?.engine_params), - schemas_allowed_for_file_upload: - extra_json?.schemas_allowed_for_file_upload, - }; - } - // convert query to a string and store in query_input query = action.payload?.parameters?.query || {}; query_input = Object.entries(query) @@ -350,41 +461,50 @@ function dbReducer( .join('&'); if ( - action.payload.encrypted_extra && + action.payload.masked_encrypted_extra && action.payload.configuration_method === CONFIGURATION_METHOD.DYNAMIC_FORM ) { - const engineParamsCatalog = Object.entries( - extra_json?.engine_params?.catalog || {}, - ).map(([key, value]) => ({ - name: key, - value, - })); + // "extra" payload from the api is a string + const extraJsonPayload: ExtraJson = { + ...JSON.parse((action.payload.extra as string) || '{}'), + }; + + const payloadCatalog = extraJsonPayload.engine_params?.catalog; + + const engineRootCatalog = Object.entries(payloadCatalog || {}).map( + ([name, value]: string[]) => ({ name, value }), + ); + return { ...action.payload, engine: action.payload.backend || trimmedState.engine, configuration_method: action.payload.configuration_method, - extra_json: deserializeExtraJSON, - catalog: engineParamsCatalog, - parameters: action.payload.parameters || trimmedState.parameters, + catalog: engineRootCatalog, + parameters: { + ...(action.payload.parameters || trimmedState.parameters), + catalog: payloadCatalog, + }, query_input, }; } return { ...action.payload, - encrypted_extra: action.payload.encrypted_extra || '', + masked_encrypted_extra: action.payload.masked_encrypted_extra || '', engine: action.payload.backend || trimmedState.engine, configuration_method: action.payload.configuration_method, - extra_json: deserializeExtraJSON, parameters: action.payload.parameters || trimmedState.parameters, + ssh_tunnel: action.payload.ssh_tunnel || trimmedState.ssh_tunnel, query_input, }; case ActionType.dbSelected: + // set initial state for blank form return { ...action.payload, + extra: DEFAULT_EXTRA, + expose_in_sqllab: true, }; - case ActionType.configMethodChange: return { ...action.payload, @@ -398,16 +518,6 @@ function dbReducer( const DEFAULT_TAB_KEY = '1'; -const serializeExtra = (extraJson: DatabaseObject['extra_json']) => - JSON.stringify({ - ...extraJson, - metadata_params: JSON.parse((extraJson?.metadata_params as string) || '{}'), - engine_params: JSON.parse((extraJson?.engine_params as string) || '{}'), - schemas_allowed_for_file_upload: ( - extraJson?.schemas_allowed_for_file_upload || [] - ).filter(schema => schema !== ''), - }); - const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ addDangerToast, addSuccessToast, @@ -416,6 +526,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ show, databaseId, dbEngine, + history, }) => { const [db, setDB] = useReducer< Reducer<Partial<DatabaseObject> | null, DBReducerActionType> @@ -438,6 +549,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ const [validationErrors, getValidation, setValidationErrors] = useDatabaseValidation(); const [hasConnectedDb, setHasConnectedDb] = useState<boolean>(false); + const [showCTAbtns, setShowCTAbtns] = useState(false); const [dbName, setDbName] = useState(''); const [editNewDb, setEditNewDb] = useState<boolean>(false); const [isLoading, setLoading] = useState<boolean>(false); @@ -446,6 +558,13 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ const [confirmedOverwrite, setConfirmedOverwrite] = useState<boolean>(false); const [fileList, setFileList] = useState<UploadFile[]>([]); const [importingModal, setImportingModal] = useState<boolean>(false); + const [importingErrorMessage, setImportingErrorMessage] = useState<string>(); + const [passwordFields, setPasswordFields] = useState<string[]>([]); + + const SSHTunnelSwitchComponent = + extensionsRegistry.get('ssh_tunnel.form.switch') ?? SSHTunnelSwitch; + + const [useSSHTunneling, setUseSSHTunneling] = useState<boolean>(false); const conf = useCommonConf(); const dbImages = getDatabaseImages(); @@ -454,6 +573,15 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ const sslForced = isFeatureEnabled( FeatureFlag.FORCE_DATABASE_CONNECTIONS_SSL, ); + const disableSSHTunnelingForEngine = ( + availableDbs?.databases?.find( + (DB: DatabaseObject) => + DB.backend === db?.engine || DB.engine === db?.engine, + ) as DatabaseObject + )?.engine_information?.disable_ssh_tunneling; + const isSSHTunneling = + isFeatureEnabled(FeatureFlag.SSH_TUNNELING) && + !disableSSHTunnelingForEngine; const hasAlert = connectionAlert || !!(db?.engine && engineSpecificAlertMapping[db.engine]); const useSqlAlchemyForm = @@ -464,8 +592,6 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ (DB: DatabaseObject) => DB.backend === engine || DB.engine === engine, )?.parameters !== undefined; const showDBError = validationErrors || dbErrors; - const isEmpty = (data?: Object | null) => - data && Object.keys(data).length === 0; const dbModel: DatabaseForm = availableDbs?.databases?.find( @@ -485,9 +611,10 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ sqlalchemy_uri: db?.sqlalchemy_uri || '', database_name: db?.database_name?.trim() || undefined, impersonate_user: db?.impersonate_user || undefined, - extra: serializeExtra(db?.extra_json) || undefined, - encrypted_extra: db?.encrypted_extra || '', + extra: db?.extra, + masked_encrypted_extra: db?.masked_encrypted_extra || '', server_cert: db?.server_cert || undefined, + ssh_tunnel: db?.ssh_tunnel || undefined, }; setTestInProgress(true); testDatabaseConnection( @@ -503,6 +630,18 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ ); }; + const getPlaceholder = (field: string) => { + if (field === 'database') { + switch (db?.engine) { + case Engines.Snowflake: + return t('e.g. xy12345.us-east-2.aws'); + default: + return t('e.g. world_population'); + } + } + return undefined; + }; + const removeFile = (removedFile: UploadFile) => { setFileList(fileList.filter(file => file.uid !== removedFile.uid)); return false; @@ -516,11 +655,24 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ setEditNewDb(false); setFileList([]); setImportingModal(false); + setImportingErrorMessage(''); + setPasswordFields([]); setPasswords({}); setConfirmedOverwrite(false); + setUseSSHTunneling(false); onHide(); }; + const redirectURL = (url: string) => { + /* TODO (lyndsiWilliams): This check and passing history + as a prop can be removed once SQL Lab is in the SPA */ + if (!isEmpty(history)) { + history?.push(url); + } else { + window.location.href = url; + } + }; + // Database import logic const { state: { @@ -531,8 +683,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ }, importResource, } = useImportResource('database', t('database'), msg => { - addDangerToast(msg); - onClose(); + setImportingErrorMessage(msg); }); const onChange = (type: any, payload: any) => { @@ -540,40 +691,55 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ }; const onSave = async () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { id, ...update } = db || {}; // Clone DB object - const dbToUpdate = JSON.parse(JSON.stringify(update)); + const dbToUpdate = { ...(db || {}) }; if (dbToUpdate.configuration_method === CONFIGURATION_METHOD.DYNAMIC_FORM) { // Validate DB before saving + if (dbToUpdate?.parameters?.catalog) { + // need to stringify gsheets catalog to allow it to be serialized + dbToUpdate.extra = JSON.stringify({ + ...JSON.parse(dbToUpdate.extra || '{}'), + engine_params: { + catalog: dbToUpdate.parameters.catalog, + }, + }); + } + + // make sure that button spinner animates + setLoading(true); const errors = await getValidation(dbToUpdate, true); if ((validationErrors && !isEmpty(validationErrors)) || errors) { + setLoading(false); return; } + setLoading(false); + // end spinner animation + const parameters_schema = isEditMode - ? dbToUpdate.parameters_schema.properties + ? dbToUpdate.parameters_schema?.properties : dbModel?.parameters.properties; const additionalEncryptedExtra = JSON.parse( - dbToUpdate.encrypted_extra || '{}', + dbToUpdate.masked_encrypted_extra || '{}', ); const paramConfigArray = Object.keys(parameters_schema || {}); paramConfigArray.forEach(paramConfig => { /* - * Parameters that are annotated with the `x-encrypted-extra` properties should be moved to - * `encrypted_extra`, so that they are stored encrypted in the backend when the database is - * created or edited. + * Parameters that are annotated with the `x-encrypted-extra` properties should be + * moved to `masked_encrypted_extra`, so that they are stored encrypted in the + * backend when the database is created or edited. */ if ( parameters_schema[paramConfig]['x-encrypted-extra'] && dbToUpdate.parameters?.[paramConfig] ) { if (typeof dbToUpdate.parameters?.[paramConfig] === 'object') { - // add new encrypted extra to encrypted_extra object + // add new encrypted extra to masked_encrypted_extra object additionalEncryptedExtra[paramConfig] = dbToUpdate.parameters?.[paramConfig]; - // The backend expects `encrypted_extra` as a string for historical reasons. + // The backend expects `masked_encrypted_extra` as a string for historical + // reasons. dbToUpdate.parameters[paramConfig] = JSON.stringify( dbToUpdate.parameters[paramConfig], ); @@ -585,7 +751,9 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ } }); // cast the new encrypted extra object into a string - dbToUpdate.encrypted_extra = JSON.stringify(additionalEncryptedExtra); + dbToUpdate.masked_encrypted_extra = JSON.stringify( + additionalEncryptedExtra, + ); // this needs to be added by default to gsheets if (dbToUpdate.engine === Engines.GSheet) { dbToUpdate.impersonate_user = true; @@ -593,17 +761,13 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ } if (dbToUpdate?.parameters?.catalog) { - // need to stringify gsheets catalog to allow it to be seralized - dbToUpdate.extra_json = { - engine_params: JSON.stringify({ + // need to stringify gsheets catalog to allow it to be serialized + dbToUpdate.extra = JSON.stringify({ + ...JSON.parse(dbToUpdate.extra || '{}'), + engine_params: { catalog: dbToUpdate.parameters.catalog, - }), - }; - } - - if (dbToUpdate?.extra_json) { - // convert extra_json to back to string - dbToUpdate.extra = serializeExtra(dbToUpdate?.extra_json); + }, + }); } setLoading(true); @@ -656,6 +820,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ } } + setShowCTAbtns(true); setEditNewDb(false); setLoading(false); }; @@ -685,13 +850,17 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ database_name, configuration_method: CONFIGURATION_METHOD.SQLALCHEMY_URI, engine: undefined, + engine_information: { + supports_file_upload: true, + }, }, }); } else { const selectedDbModel = availableDbs?.databases.filter( (db: DatabaseObject) => db.name === database_name, )[0]; - const { engine, parameters } = selectedDbModel; + const { engine, parameters, engine_information, default_driver } = + selectedDbModel; const isDynamic = parameters !== undefined; setDB({ type: ActionType.dbSelected, @@ -701,11 +870,16 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ configuration_method: isDynamic ? CONFIGURATION_METHOD.DYNAMIC_FORM : CONFIGURATION_METHOD.SQLALCHEMY_URI, + engine_information, + driver: default_driver, }, }); - } - setDB({ type: ActionType.addTableCatalogSheet }); + if (engine === Engines.GSheet) { + // only create a catalog if the DB is Google Sheets + setDB({ type: ActionType.addTableCatalogSheet }); + } + } }; const renderAvailableSelector = () => ( @@ -788,6 +962,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ onClick={() => setDatabaseModel(database.name)} buttonText={database.name} icon={dbImages?.[database.engine]} + key={`${database.name}`} /> ))} </div> @@ -797,12 +972,19 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ if (dbFetched) { fetchResource(dbFetched.id as number); } + setShowCTAbtns(false); setEditNewDb(true); }; const handleBackButtonOnConnect = () => { if (editNewDb) setHasConnectedDb(false); if (importingModal) setImportingModal(false); + if (importErrored) { + setImportingModal(false); + setImportingErrorMessage(''); + setPasswordFields([]); + setPasswords({}); + } setDB({ type: ActionType.reset }); setFileList([]); }; @@ -819,7 +1001,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ const renderModalFooter = () => { if (db) { - // if db show back + connenct + // if db show back + connect if (!hasConnectedDb || editNewDb) { return ( <> @@ -830,6 +1012,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ key="submit" buttonStyle="primary" onClick={onSave} + loading={isLoading} > {t('Connect')} </StyledFooterButton> @@ -847,6 +1030,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ buttonStyle="primary" onClick={onSave} data-test="modal-confirm-button" + loading={isLoading} > {t('Finish')} </StyledFooterButton> @@ -866,6 +1050,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ buttonStyle="primary" onClick={onSave} disabled={handleDisableOnImport()} + loading={isLoading} > {t('Connect')} </StyledFooterButton> @@ -873,7 +1058,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ ); } - return []; + return <></>; }; const renderEditModalFooter = (db: Partial<DatabaseObject> | null) => ( @@ -886,6 +1071,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ buttonStyle="primary" onClick={onSave} disabled={db?.is_managed_externally} + loading={isLoading} tooltip={ db?.is_managed_externally ? t( @@ -923,8 +1109,8 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ useEffect(() => { if (show) { setTabKey(DEFAULT_TAB_KEY); - getAvailableDbs(); setLoading(true); + getAvailableDbs(); } if (databaseId && show) { fetchDB(); @@ -963,7 +1149,20 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ } }, [importingModal]); + useEffect(() => { + setPasswordFields([...passwordsNeeded]); + }, [passwordsNeeded]); + + useEffect(() => { + if (db && isSSHTunneling) { + setUseSSHTunneling(!isEmpty(db?.ssh_tunnel)); + } + }, [db, isSSHTunneling]); + const onDbImport = async (info: UploadChangeParam) => { + setImportingErrorMessage(''); + setPasswordFields([]); + setPasswords({}); setImportingModal(true); setFileList([ { @@ -973,17 +1172,18 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ ]); if (!(info.file.originFileObj instanceof File)) return; - await importResource( + const dbId = await importResource( info.file.originFileObj, passwords, confirmedOverwrite, ); + if (dbId) onDatabaseAdd?.(); }; const passwordNeededField = () => { - if (!passwordsNeeded.length) return null; + if (!passwordFields.length) return null; - return passwordsNeeded.map(database => ( + return passwordFields.map(database => ( <> <StyledAlertMargin> <Alert @@ -1014,6 +1214,19 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ )); }; + const importingErrorAlert = () => { + if (!importingErrorMessage) return null; + + return ( + <StyledAlertMargin> + <ErrorAlert + errorMessage={importingErrorMessage} + showDbInstallInstructions={passwordFields.length > 0} + /> + </StyledAlertMargin> + ); + }; + const confirmOverwrite = (event: React.ChangeEvent<HTMLInputElement>) => { const targetValue = (event.currentTarget?.value as string) ?? ''; setConfirmedOverwrite(targetValue.toUpperCase() === t('OVERWRITE')); @@ -1042,7 +1255,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ required validationMethods={{ onBlur: () => {} }} errorMessage={validationErrors?.confirm_overwrite} - label={t(`TYPE "OVERWRITE" TO CONFIRM`)} + label={t('Type "%s" to confirm', t('OVERWRITE'))} onChange={confirmOverwrite} css={formScrollableStyles} /> @@ -1085,28 +1298,93 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ // eslint-disable-next-line consistent-return const errorAlert = () => { let alertErrors: string[] = []; - if (isEmpty(dbErrors) === false) { - alertErrors = typeof dbErrors === 'object' ? Object.values(dbErrors) : []; - } else if (db?.engine === Engines.Snowflake) { + if (!isEmpty(dbErrors)) { alertErrors = - validationErrors?.error_type === 'GENERIC_DB_ENGINE_ERROR' - ? [validationErrors?.description] + typeof dbErrors === 'object' + ? Object.values(dbErrors) + : typeof dbErrors === 'string' + ? [dbErrors] : []; + } else if ( + !isEmpty(validationErrors) && + validationErrors?.error_type === 'GENERIC_DB_ENGINE_ERROR' + ) { + alertErrors = [ + validationErrors?.description || validationErrors?.message, + ]; } - if (alertErrors.length) { return ( - <Alert - type="error" - css={(theme: SupersetTheme) => antDErrorAlertStyles(theme)} - message={t('Database Creation Error')} - description={t(alertErrors[0])} - /> + <ErrorAlertContainer> + <ErrorMessageWithStackTrace + title={t('Database Creation Error')} + description={t( + 'We are unable to connect to your database. Click "See more" for database-provided information that may help troubleshoot the issue.', + )} + subtitle={alertErrors?.[0] || validationErrors?.description} + copyText={validationErrors?.description} + /> + </ErrorAlertContainer> ); } return <></>; }; + const fetchAndSetDB = () => { + setLoading(true); + fetchResource(dbFetched?.id as number).then(r => { + setItem(LocalStorageKeys.db, r); + }); + }; + + const renderSSHTunnelForm = () => ( + <SSHTunnelForm + db={db as DatabaseObject} + onSSHTunnelParametersChange={({ + target, + }: { + target: HTMLInputElement | HTMLTextAreaElement; + }) => + onChange(ActionType.parametersSSHTunnelChange, { + type: target.type, + name: target.name, + value: target.value, + }) + } + setSSHTunnelLoginMethod={(method: AuthType) => + setDB({ + type: ActionType.setSSHTunnelLoginMethod, + payload: { login_method: method }, + }) + } + /> + ); + + const renderCTABtns = () => ( + <StyledBtns> + <Button + buttonStyle="secondary" + onClick={() => { + setLoading(true); + fetchAndSetDB(); + redirectURL('/dataset/add/'); + }} + > + {t('CREATE DATASET')} + </Button> + <Button + buttonStyle="secondary" + onClick={() => { + setLoading(true); + fetchAndSetDB(); + redirectURL(`/superset/sqllab/?db=true`); + }} + > + {t('QUERY DATA IN SQL LAB')} + </Button> + </StyledBtns> + ); + const renderFinishState = () => { if (!editNewDb) { return ( @@ -1157,6 +1435,12 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ value: target.value, }) } + onExtraInputChange={({ target }: { target: HTMLInputElement }) => + onChange(ActionType.extraInputChange, { + name: target.name, + value: target.value, + }) + } onChange={({ target }: { target: HTMLInputElement }) => onChange(ActionType.textChange, { name: target.name, @@ -1184,7 +1468,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ ); }; - if (fileList.length > 0 && (alreadyExists.length || passwordsNeeded.length)) { + if (fileList.length > 0 && (alreadyExists.length || passwordFields.length)) { return ( <Modal css={(theme: SupersetTheme) => [ @@ -1215,10 +1499,13 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ /> {passwordNeededField()} {confirmOverwriteField()} + {importingErrorAlert()} </Modal> ); } - + const modalFooter = isEditMode + ? renderEditModalFooter(db) + : renderModalFooter(); return useTabLayout ? ( <Modal css={(theme: SupersetTheme) => [ @@ -1239,7 +1526,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ title={ <h4>{isEditMode ? t('Edit database') : t('Connect a database')}</h4> } - footer={isEditMode ? renderEditModalFooter(db) : renderModalFooter()} + footer={modalFooter} > <StyledStickyHeader> <TabHeader> @@ -1276,7 +1563,18 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ conf={conf} testConnection={testConnection} testInProgress={testInProgress} - /> + > + <SSHTunnelSwitchComponent + isEditMode={isEditMode} + dbFetched={dbFetched} + disableSSHTunnelingForEngine={disableSSHTunnelingForEngine} + useSSHTunneling={useSSHTunneling} + setUseSSHTunneling={setUseSSHTunneling} + setDB={setDB} + isSSHTunneling={isSSHTunneling} + /> + {useSSHTunneling && renderSSHTunnelForm()} + </SqlAlchemyForm> {isDynamic(db?.backend || db?.engine) && !isEditMode && ( <div css={(theme: SupersetTheme) => infoTooltip(theme)}> <Button @@ -1319,6 +1617,12 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ value: target.value, }) } + onExtraInputChange={({ target }: { target: HTMLInputElement }) => + onChange(ActionType.extraInputChange, { + name: target.name, + value: target.value, + }) + } onChange={({ target }: { target: HTMLInputElement }) => onChange(ActionType.textChange, { name: target.name, @@ -1349,7 +1653,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ <Alert closable={false} css={(theme: SupersetTheme) => antDAlertStyles(theme)} - message="Additional fields may be required" + message={t('Additional fields may be required')} showIcon description={ <> @@ -1371,6 +1675,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ /> </StyledAlertMargin> )} + {showDBError && errorAlert()} </Tabs.TabPane> <Tabs.TabPane tab={<span>{t('Advanced')}</span>} key="2"> <ExtraOptions @@ -1404,7 +1709,6 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ onChange(ActionType.extraEditorChange, payload); }} /> - {showDBError && errorAlert()} </Tabs.TabPane> </TabsStyled> </Modal> @@ -1426,7 +1730,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ title={<h4>{t('Connect a database')}</h4>} footer={renderModalFooter()} > - {hasConnectedDb ? ( + {!isLoading && hasConnectedDb ? ( <> <ModalHeader isLoading={isLoading} @@ -1438,6 +1742,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ dbModel={dbModel} editNewDb={editNewDb} /> + {showCTAbtns && renderCTABtns()} {renderFinishState()} </> ) : ( @@ -1477,6 +1782,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ </Button> </Upload> </StyledUploadWrapper> + {importingErrorAlert()} </SelectDatabaseStyles> ) : ( <> @@ -1503,6 +1809,16 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ value: target.value, }) } + onExtraInputChange={({ + target, + }: { + target: HTMLInputElement; + }) => + onChange(ActionType.extraInputChange, { + name: target.name, + value: target.value, + }) + } onRemoveTableCatalog={(idx: number) => { setDB({ type: ActionType.removeTableCatalogSheet, @@ -1529,7 +1845,24 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({ } getValidation={() => getValidation(db)} validationErrors={validationErrors} + getPlaceholder={getPlaceholder} /> + <SSHTunnelContainer> + <SSHTunnelSwitchComponent + isEditMode={isEditMode} + dbFetched={dbFetched} + disableSSHTunnelingForEngine={disableSSHTunnelingForEngine} + useSSHTunneling={useSSHTunneling} + setUseSSHTunneling={setUseSSHTunneling} + setDB={setDB} + isSSHTunneling={isSSHTunneling} + /> + </SSHTunnelContainer> + {useSSHTunneling && ( + <SSHTunnelContainer> + {renderSSHTunnelForm()} + </SSHTunnelContainer> + )} <div css={(theme: SupersetTheme) => infoTooltip(theme)}> {dbModel.engine !== Engines.GSheet && ( <> diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts index d3d0b11dd76a4..ed30e7885b92f 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/styles.ts @@ -21,9 +21,10 @@ import { css, styled, SupersetTheme } from '@superset-ui/core'; import { JsonEditor } from 'src/components/AsyncAceEditor'; import Button from 'src/components/Button'; -const CTAS_CVAS_SCHEMA_FORM_HEIGHT = 102; +const CTAS_CVAS_SCHEMA_FORM_HEIGHT = 108; const EXPOSE_IN_SQLLAB_FORM_HEIGHT = CTAS_CVAS_SCHEMA_FORM_HEIGHT + 153; const EXPOSE_ALL_FORM_HEIGHT = EXPOSE_IN_SQLLAB_FORM_HEIGHT + 102; +const MODAL_BODY_HEIGHT = 180.5; const anticonHeight = 12; @@ -31,7 +32,7 @@ export const no_margin_bottom = css` margin-bottom: 0; `; -export const labelMarginBotton = (theme: SupersetTheme) => css` +export const labelMarginBottom = (theme: SupersetTheme) => css` margin-bottom: ${theme.gridUnit * 2}px; `; @@ -40,8 +41,6 @@ export const marginBottom = (theme: SupersetTheme) => css` `; export const StyledFormHeader = styled.header` - border-bottom: ${({ theme }) => `${theme.gridUnit * 0.25}px solid - ${theme.colors.grayscale.light2};`} padding: ${({ theme }) => theme.gridUnit * 2}px ${({ theme }) => theme.gridUnit * 4}px; line-height: ${({ theme }) => theme.gridUnit * 6}px; @@ -53,6 +52,10 @@ export const StyledFormHeader = styled.header` margin: 0; } + .subheader-text { + line-height: ${({ theme }) => theme.gridUnit * 4.25}px; + } + .helper-bottom { padding-top: 0; color: ${({ theme }) => theme.colors.grayscale.base}; @@ -154,7 +157,7 @@ export const antDModalStyles = (theme: SupersetTheme) => css` } .ant-modal-body { - height: ${theme.gridUnit * 180.5}px; + height: ${theme.gridUnit * MODAL_BODY_HEIGHT}px; } .ant-modal-footer { @@ -275,7 +278,6 @@ export const formStyles = (theme: SupersetTheme) => css` width: ${`calc(50% - ${theme.gridUnit * 4}px)`}; & + .form-group-w-50 { margin-left: ${theme.gridUnit * 8}px; - margin-bottom: ${theme.gridUnit * 10}px; } } } @@ -511,7 +513,7 @@ export const CredentialInfoForm = styled.div` .input-container { .input-upload { - display: none; + display: none !important; } .input-upload-current { display: flex; @@ -603,12 +605,6 @@ export const StyledCatalogTable = styled.div` width: 95%; } - .catalog-delete { - align-self: center; - background: ${({ theme }) => theme.colors.grayscale.light4}; - margin: 5px 5px 8px 5px; - } - .catalog-add-btn { width: 95%; } diff --git a/superset-frontend/src/views/CRUD/data/database/types.ts b/superset-frontend/src/views/CRUD/data/database/types.ts index d48fa956e28b2..c347948f7ed70 100644 --- a/superset-frontend/src/views/CRUD/data/database/types.ts +++ b/superset-frontend/src/views/CRUD/data/database/types.ts @@ -26,17 +26,33 @@ export type CatalogObject = { value: string; }; +export type SSHTunnelObject = { + id?: number; + server_address?: string; + server_port?: number; + username?: string; + password?: string; + private_key?: string; + private_key_password?: string; +}; + export type DatabaseObject = { // Connection + general - id?: number; + backend?: string; + changed_on?: string; + changed_on_delta_humanized?: string; + configuration_method: CONFIGURATION_METHOD; + created_by?: null | DatabaseUser; database_name: string; + driver: string; + engine?: string; + extra?: string; + id?: number; name: string; // synonym to database_name + paramProperties?: Record<string, any>; sqlalchemy_uri?: string; - backend?: string; - created_by?: null | DatabaseUser; - changed_on_delta_humanized?: string; - changed_on?: string; parameters?: { + access_token?: string; database_name?: string; host?: string; port?: number; @@ -47,53 +63,30 @@ export type DatabaseObject = { credentials_info?: string; service_account_info?: string; query?: Record<string, string>; - catalog?: Record<string, string>; + catalog?: Record<string, string | undefined>; properties?: Record<string, any>; warehouse?: string; role?: string; account?: string; }; - configuration_method: CONFIGURATION_METHOD; - engine?: string; - paramProperties?: Record<string, any>; // Performance cache_timeout?: string; allow_run_async?: boolean; // SQL Lab - expose_in_sqllab?: boolean; allow_ctas?: boolean; allow_cvas?: boolean; allow_dml?: boolean; - allow_multi_schema_metadata_fetch?: boolean; + expose_in_sqllab?: boolean; force_ctas_schema?: string; // Security - encrypted_extra?: string; - server_cert?: string; allow_file_upload?: boolean; impersonate_user?: boolean; + masked_encrypted_extra?: string; parameters_schema?: Record<string, any>; - - // Extra - extra_json?: { - engine_params?: { - catalog?: Record<any, any> | string; - }; - metadata_params?: {} | string; - metadata_cache_timeout?: { - schema_cache_timeout?: number; // in Performance - table_cache_timeout?: number; // in Performance - }; // No field, holds schema and table timeout - allows_virtual_table_explore?: boolean; // in SQL Lab - schemas_allowed_for_file_upload?: string[]; // in Security - cancel_query_on_windows_unload?: boolean; // in Performance - - version?: string; - cost_estimate_enabled?: boolean; // in SQL Lab - disable_data_preview?: boolean; // in SQL Lab - }; + server_cert?: string; // External management is_managed_externally: boolean; @@ -101,10 +94,19 @@ export type DatabaseObject = { // Temporary storage catalog?: Array<CatalogObject>; query_input?: string; - extra?: string; + + // DB Engine Spec information + engine_information?: { + supports_file_upload?: boolean; + disable_ssh_tunneling?: boolean; + }; + + // SSH Tunnel information + ssh_tunnel?: SSHTunnelObject; }; export type DatabaseForm = { + default_driver: string; engine: string; name: string; parameters: { @@ -151,6 +153,40 @@ export type DatabaseForm = { required: string[]; type: string; }; + ssh_tunnel: { + properties: { + ssh_address: { + description: string; + type: string; + }; + ssh_port: { + description: string; + format: string; + type: string; + }; + username: { + description: string; + type: string; + }; + password: { + description: string; + nullable: boolean; + type: string; + }; + private_key: { + description: string; + nullable: boolean; + type: string; + }; + private_key_password: { + description: string; + nullable: boolean; + type: string; + }; + }; + required: string[]; + type: string; + }; preferred: boolean; sqlalchemy_uri_placeholder: string; }; @@ -161,3 +197,28 @@ export enum CONFIGURATION_METHOD { SQLALCHEMY_URI = 'sqlalchemy_form', DYNAMIC_FORM = 'dynamic_form', } + +export enum Engines { + GSheet = 'gsheets', + Snowflake = 'snowflake', +} + +export interface ExtraJson { + allows_virtual_table_explore?: boolean; // in SQL Lab + cancel_query_on_windows_unload?: boolean; // in Performance + cost_estimate_enabled?: boolean; // in SQL Lab + disable_data_preview?: boolean; // in SQL Lab + engine_params?: { + catalog?: Record<string, string>; + connect_args?: { + http_path?: string; + }; + }; + metadata_params?: {}; + metadata_cache_timeout?: { + schema_cache_timeout?: number; // in Performance + table_cache_timeout?: number; // in Performance + }; // No field, holds schema and table timeout + schemas_allowed_for_file_upload?: string[]; // in Security + version?: string; +} diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/AddDataset.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/AddDataset.test.tsx new file mode 100644 index 0000000000000..ea595c0f901a0 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/AddDataset.test.tsx @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import AddDataset from 'src/views/CRUD/data/dataset/AddDataset'; + +const mockHistoryPush = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useHistory: () => ({ + push: mockHistoryPush, + }), + useParams: () => ({ datasetId: undefined }), +})); + +describe('AddDataset', () => { + it('renders a blank state AddDataset', async () => { + render(<AddDataset />, { useRedux: true }); + + const blankeStateImgs = screen.getAllByRole('img', { name: /empty/i }); + + // Header + expect(await screen.findByText(/new dataset/i)).toBeVisible(); + // Left panel + expect(blankeStateImgs[0]).toBeVisible(); + // Footer + expect(screen.getByText(/Cancel/i)).toBeVisible(); + + expect(blankeStateImgs.length).toBe(1); + }); +}); diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.stories.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.stories.tsx new file mode 100644 index 0000000000000..8a7fd7d6438fe --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.stories.tsx @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import DatasetPanel from './DatasetPanel'; +import { exampleColumns } from './fixtures'; + +export default { + title: 'Superset App/views/CRUD/data/dataset/DatasetPanel', + component: DatasetPanel, +} as ComponentMeta<typeof DatasetPanel>; + +export const Basic: ComponentStory<typeof DatasetPanel> = args => ( + <ThemeProvider theme={supersetTheme}> + <div style={{ height: '350px' }}> + <DatasetPanel {...args} /> + </div> + </ThemeProvider> +); + +Basic.args = { + tableName: 'example_table', + loading: false, + hasError: false, + columnList: exampleColumns, +}; diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.test.tsx new file mode 100644 index 0000000000000..b5a29638c61bb --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.test.tsx @@ -0,0 +1,160 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import DatasetPanel, { + REFRESHING, + ALT_LOADING, + tableColumnDefinition, + COLUMN_TITLE, +} from 'src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel'; +import { exampleColumns, exampleDataset } from './fixtures'; +import { + SELECT_MESSAGE, + CREATE_MESSAGE, + VIEW_DATASET_MESSAGE, + SELECT_TABLE_TITLE, + NO_COLUMNS_TITLE, + NO_COLUMNS_DESCRIPTION, + ERROR_TITLE, + ERROR_DESCRIPTION, +} from './MessageContent'; + +jest.mock( + 'src/components/Icons/Icon', + () => + ({ fileName }: { fileName: string }) => + <span role="img" aria-label={fileName.replace('_', '-')} />, +); + +describe('DatasetPanel', () => { + test('renders a blank state DatasetPanel', () => { + render(<DatasetPanel hasError={false} columnList={[]} loading={false} />); + + const blankDatasetImg = screen.getByRole('img', { name: /empty/i }); + expect(blankDatasetImg).toBeVisible(); + const blankDatasetTitle = screen.getByText(SELECT_TABLE_TITLE); + expect(blankDatasetTitle).toBeVisible(); + const blankDatasetDescription1 = screen.getByText(SELECT_MESSAGE, { + exact: false, + }); + expect(blankDatasetDescription1).toBeVisible(); + const blankDatasetDescription2 = screen.getByText(VIEW_DATASET_MESSAGE, { + exact: false, + }); + expect(blankDatasetDescription2).toBeVisible(); + const sqlLabLink = screen.getByRole('button', { + name: CREATE_MESSAGE, + }); + expect(sqlLabLink).toBeVisible(); + }); + + test('renders a no columns screen', () => { + render( + <DatasetPanel + tableName="Name" + hasError={false} + columnList={[]} + loading={false} + />, + ); + + const blankDatasetImg = screen.getByRole('img', { name: /empty/i }); + expect(blankDatasetImg).toBeVisible(); + const noColumnsTitle = screen.getByText(NO_COLUMNS_TITLE); + expect(noColumnsTitle).toBeVisible(); + const noColumnsDescription = screen.getByText(NO_COLUMNS_DESCRIPTION); + expect(noColumnsDescription).toBeVisible(); + }); + + test('renders a loading screen', () => { + render( + <DatasetPanel + tableName="Name" + hasError={false} + columnList={[]} + loading + />, + ); + + const blankDatasetImg = screen.getByAltText(ALT_LOADING); + expect(blankDatasetImg).toBeVisible(); + const blankDatasetTitle = screen.getByText(REFRESHING); + expect(blankDatasetTitle).toBeVisible(); + }); + + test('renders an error screen', () => { + render( + <DatasetPanel + tableName="Name" + hasError + columnList={[]} + loading={false} + />, + ); + + const errorTitle = screen.getByText(ERROR_TITLE); + expect(errorTitle).toBeVisible(); + const errorDescription = screen.getByText(ERROR_DESCRIPTION); + expect(errorDescription).toBeVisible(); + }); + + test('renders a table with columns displayed', async () => { + const tableName = 'example_name'; + render( + <DatasetPanel + tableName={tableName} + hasError={false} + columnList={exampleColumns} + loading={false} + />, + ); + expect(await screen.findByText(tableName)).toBeVisible(); + expect(screen.getByText(COLUMN_TITLE)).toBeVisible(); + expect( + screen.getByText(tableColumnDefinition[0].title as string), + ).toBeInTheDocument(); + expect( + screen.getByText(tableColumnDefinition[1].title as string), + ).toBeInTheDocument(); + exampleColumns.forEach(row => { + expect(screen.getByText(row.name)).toBeInTheDocument(); + expect(screen.getByText(row.type)).toBeInTheDocument(); + }); + }); + + test('renders an info banner if table already has a dataset', async () => { + render( + <DatasetPanel + tableName="example_table" + hasError={false} + columnList={exampleColumns} + loading={false} + datasets={exampleDataset} + />, + ); + + // This is text in the info banner + expect( + await screen.findByText( + /this table already has a dataset associated with it. you can only associate one dataset with a table./i, + ), + ).toBeVisible(); + }); +}); diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx new file mode 100644 index 0000000000000..8d579b79b8b92 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx @@ -0,0 +1,353 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { t, styled, useTheme } from '@superset-ui/core'; +import Icons from 'src/components/Icons'; +import Alert from 'src/components/Alert'; +import Table, { ColumnsType, TableSize } from 'src/components/Table'; +import { alphabeticalSort } from 'src/components/Table/sorters'; +// @ts-ignore +import LOADING_GIF from 'src/assets/images/loading.gif'; +import { DatasetObject } from 'src/views/CRUD/data/dataset/AddDataset/types'; +import { ITableColumn } from './types'; +import MessageContent from './MessageContent'; + +/** + * Enum defining CSS position options + */ +enum EPosition { + ABSOLUTE = 'absolute', + RELATIVE = 'relative', +} + +/** + * Interface for StyledHeader + */ +interface StyledHeaderProps { + /** + * Determine the CSS positioning type + * Vertical centering of loader, No columns screen, and select table screen + * gets offset when the header position is relative and needs to be absolute, but table + * needs this positioned relative to render correctly + */ + position: EPosition; +} + +const LOADER_WIDTH = 200; +const SPINNER_WIDTH = 120; +const HALF = 0.5; +const MARGIN_MULTIPLIER = 3; + +const StyledHeader = styled.div<StyledHeaderProps>` + ${({ theme, position }) => ` + position: ${position}; + margin: ${theme.gridUnit * (MARGIN_MULTIPLIER + 1)}px + ${theme.gridUnit * MARGIN_MULTIPLIER}px + ${theme.gridUnit * MARGIN_MULTIPLIER}px + ${theme.gridUnit * (MARGIN_MULTIPLIER + 3)}px; + font-size: ${theme.gridUnit * 6}px; + font-weight: ${theme.typography.weights.medium}; + padding-bottom: ${theme.gridUnit * MARGIN_MULTIPLIER}px; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + .anticon:first-of-type { + margin-right: ${theme.gridUnit * (MARGIN_MULTIPLIER + 1)}px; + } + + .anticon:nth-of-type(2) { + margin-left: ${theme.gridUnit * (MARGIN_MULTIPLIER + 1)}px; + `} +`; + +const StyledTitle = styled.div` + ${({ theme }) => ` + margin-left: ${theme.gridUnit * (MARGIN_MULTIPLIER + 3)}px; + margin-bottom: ${theme.gridUnit * MARGIN_MULTIPLIER}px; + font-weight: ${theme.typography.weights.bold}; + `} +`; + +const LoaderContainer = styled.div` + ${({ theme }) => ` + padding: ${theme.gridUnit * 8}px + ${theme.gridUnit * 6}px; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + height: 100%; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + `} +`; + +const StyledLoader = styled.div` + ${({ theme }) => ` + max-width: 50%; + width: ${LOADER_WIDTH}px; + + img { + width: ${SPINNER_WIDTH}px; + margin-left: ${(LOADER_WIDTH - SPINNER_WIDTH) * HALF}px; + } + + div { + width: 100%; + margin-top: ${theme.gridUnit * MARGIN_MULTIPLIER}px; + text-align: center; + font-weight: ${theme.typography.weights.normal}; + font-size: ${theme.typography.sizes.l}px; + color: ${theme.colors.grayscale.light1}; + } + `} +`; + +const TableContainerWithBanner = styled.div` + ${({ theme }) => ` + position: relative; + margin: ${theme.gridUnit * MARGIN_MULTIPLIER}px; + margin-left: ${theme.gridUnit * (MARGIN_MULTIPLIER + 3)}px; + height: calc(100% - ${theme.gridUnit * 60}px); + overflow: auto; + `} +`; + +const TableContainerWithoutBanner = styled.div` + ${({ theme }) => ` + position: relative; + margin: ${theme.gridUnit * MARGIN_MULTIPLIER}px; + margin-left: ${theme.gridUnit * (MARGIN_MULTIPLIER + 3)}px; + height: calc(100% - ${theme.gridUnit * 30}px); + overflow: auto; + `} +`; + +const TableScrollContainer = styled.div` + position: absolute; + left: 0; + top: 0; + bottom: 0; + right: 0; +`; + +const StyledAlert = styled(Alert)` + ${({ theme }) => ` + border: 1px solid ${theme.colors.info.base}; + padding: ${theme.gridUnit * 4}px; + margin: ${theme.gridUnit * 6}px ${theme.gridUnit * 6}px + ${theme.gridUnit * 8}px; + .view-dataset-button { + position: absolute; + top: ${theme.gridUnit * 4}px; + right: ${theme.gridUnit * 4}px; + font-weight: ${theme.typography.weights.normal}; + + &:hover { + color: ${theme.colors.secondary.dark3}; + text-decoration: underline; + } + } + `} +`; + +export const REFRESHING = t('Refreshing columns'); +export const COLUMN_TITLE = t('Table columns'); +export const ALT_LOADING = t('Loading'); + +const pageSizeOptions = ['5', '10', '15', '25']; +const DEFAULT_PAGE_SIZE = 25; + +// Define the columns for Table instance +export const tableColumnDefinition: ColumnsType<ITableColumn> = [ + { + title: 'Column Name', + dataIndex: 'name', + key: 'name', + sorter: (a: ITableColumn, b: ITableColumn) => + alphabeticalSort('name', a, b), + }, + { + title: 'Datatype', + dataIndex: 'type', + key: 'type', + width: '100px', + sorter: (a: ITableColumn, b: ITableColumn) => + alphabeticalSort('type', a, b), + }, +]; + +/** + * Props interface for DatasetPanel + */ +export interface IDatasetPanelProps { + /** + * Name of the database table + */ + tableName?: string | null; + /** + * Array of ITableColumn instances with name and type attributes + */ + columnList: ITableColumn[]; + /** + * Boolean indicating if there is an error state + */ + hasError: boolean; + /** + * Boolean indicating if the component is in a loading state + */ + loading: boolean; + datasets?: DatasetObject[] | undefined; +} + +const EXISTING_DATASET_DESCRIPTION = t( + 'This table already has a dataset associated with it. You can only associate one dataset with a table.\n', +); +const VIEW_DATASET = t('View Dataset'); + +const renderExistingDatasetAlert = (dataset?: DatasetObject) => ( + <StyledAlert + closable={false} + type="info" + showIcon + message={t('This table already has a dataset')} + description={ + <> + {EXISTING_DATASET_DESCRIPTION} + <span + role="button" + onClick={() => { + window.open( + dataset?.explore_url, + '_blank', + 'noreferrer noopener popup=false', + ); + }} + tabIndex={0} + className="view-dataset-button" + > + {VIEW_DATASET} + </span> + </> + } + /> +); + +const DatasetPanel = ({ + tableName, + columnList, + loading, + hasError, + datasets, +}: IDatasetPanelProps) => { + const theme = useTheme(); + const hasColumns = columnList?.length > 0 ?? false; + const datasetNames = datasets?.map(dataset => dataset.table_name); + const tableWithDataset = datasets?.find( + dataset => dataset.table_name === tableName, + ); + + let component; + let loader; + if (loading) { + loader = ( + <LoaderContainer> + <StyledLoader> + <img alt={ALT_LOADING} src={LOADING_GIF} /> + <div>{REFRESHING}</div> + </StyledLoader> + </LoaderContainer> + ); + } + if (!loading) { + if (!loading && tableName && hasColumns && !hasError) { + component = ( + <> + <StyledTitle>{COLUMN_TITLE}</StyledTitle> + {tableWithDataset ? ( + <TableContainerWithBanner> + <TableScrollContainer> + <Table + loading={loading} + size={TableSize.SMALL} + columns={tableColumnDefinition} + data={columnList} + pageSizeOptions={pageSizeOptions} + defaultPageSize={DEFAULT_PAGE_SIZE} + /> + </TableScrollContainer> + </TableContainerWithBanner> + ) : ( + <TableContainerWithoutBanner> + <TableScrollContainer> + <Table + loading={loading} + size={TableSize.SMALL} + columns={tableColumnDefinition} + data={columnList} + pageSizeOptions={pageSizeOptions} + defaultPageSize={DEFAULT_PAGE_SIZE} + /> + </TableScrollContainer> + </TableContainerWithoutBanner> + )} + </> + ); + } else { + component = ( + <MessageContent + hasColumns={hasColumns} + hasError={hasError} + tableName={tableName} + /> + ); + } + } + + return ( + <> + {tableName && ( + <> + {datasetNames?.includes(tableName) && + renderExistingDatasetAlert(tableWithDataset)} + <StyledHeader + position={ + !loading && hasColumns ? EPosition.RELATIVE : EPosition.ABSOLUTE + } + title={tableName || ''} + > + {tableName && ( + <Icons.Table iconColor={theme.colors.grayscale.base} /> + )} + {tableName} + </StyledHeader> + </> + )} + {component} + {loader} + </> + ); +}; + +export default DatasetPanel; diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx new file mode 100644 index 0000000000000..5d0ef5eda736e --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx @@ -0,0 +1,107 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { t, styled } from '@superset-ui/core'; +import { EmptyStateBig } from 'src/components/EmptyState'; + +const StyledContainer = styled.div` + padding: ${({ theme }) => theme.gridUnit * 8}px + ${({ theme }) => theme.gridUnit * 6}px; + + display: flex; + align-items: center; + justify-content: center; + height: 100%; +`; + +const StyledEmptyStateBig = styled(EmptyStateBig)` + max-width: 50%; + + p { + width: ${({ theme }) => theme.gridUnit * 115}px; + } +`; + +export const SELECT_MESSAGE = t( + 'Datasets can be created from database tables or SQL queries. Select a database table to the left or ', +); +export const CREATE_MESSAGE = t('create dataset from SQL query'); +export const VIEW_DATASET_MESSAGE = t( + ' to open SQL Lab. From there you can save the query as a dataset.', +); + +const renderEmptyDescription = () => ( + <> + {SELECT_MESSAGE} + <span + role="button" + onClick={() => { + window.location.href = `/superset/sqllab`; + }} + tabIndex={0} + > + {CREATE_MESSAGE} + </span> + {VIEW_DATASET_MESSAGE} + </> +); + +export const SELECT_TABLE_TITLE = t('Select dataset source'); +export const NO_COLUMNS_TITLE = t('No table columns'); +export const NO_COLUMNS_DESCRIPTION = t( + 'This database table does not contain any data. Please select a different table.', +); +export const ERROR_TITLE = t('An Error Occurred'); +export const ERROR_DESCRIPTION = t( + 'Unable to load columns for the selected table. Please select a different table.', +); + +interface MessageContentProps { + hasError: boolean; + tableName?: string | null; + hasColumns: boolean; +} + +export const MessageContent = (props: MessageContentProps) => { + const { hasError, tableName, hasColumns } = props; + let currentImage: string | undefined = 'empty-dataset.svg'; + let currentTitle = SELECT_TABLE_TITLE; + let currentDescription = renderEmptyDescription(); + if (hasError) { + currentTitle = ERROR_TITLE; + currentDescription = <>{ERROR_DESCRIPTION}</>; + currentImage = undefined; + } else if (tableName && !hasColumns) { + currentImage = 'no-columns.svg'; + currentTitle = NO_COLUMNS_TITLE; + currentDescription = <>{NO_COLUMNS_DESCRIPTION}</>; + } + return ( + <StyledContainer> + <StyledEmptyStateBig + image={currentImage} + title={currentTitle} + description={currentDescription} + /> + </StyledContainer> + ); +}; + +export default MessageContent; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/fixtures.ts similarity index 57% rename from superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx rename to superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/fixtures.ts index a4c3f4a86d8af..5c09188c61a87 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/fixtures.ts @@ -16,22 +16,34 @@ * specific language governing permissions and limitations * under the License. */ +import { DatasetObject } from 'src/views/CRUD/data/dataset/AddDataset/types'; +import { ITableColumn } from './types'; -import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; +export const exampleColumns: ITableColumn[] = [ + { + name: 'name', + type: 'STRING', + }, + { + name: 'height_in_inches', + type: 'NUMBER', + }, + { + name: 'birth_date', + type: 'DATE', + }, +]; -const enableCrossFilter = isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS); - -export const emitFilterControl = enableCrossFilter - ? [ - { - name: 'emit_filter', - config: { - type: 'CheckboxControl', - label: t('Enable dashboard cross filters'), - default: false, - renderTrigger: true, - description: t('Enable dashboard cross filters'), - }, - }, - ] - : []; +export const exampleDataset: DatasetObject[] = [ + { + db: { + id: 1, + database_name: 'test_database', + owners: [1], + backend: 'test_backend', + }, + schema: 'test_schema', + dataset_name: 'example_dataset', + table_name: 'example_table', + }, +]; diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/index.tsx new file mode 100644 index 0000000000000..73bea70b41f2f --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/index.tsx @@ -0,0 +1,140 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useEffect, useState, useRef } from 'react'; +import { SupersetClient, logging, t } from '@superset-ui/core'; +import { DatasetObject } from 'src/views/CRUD/data/dataset/AddDataset/types'; +import { addDangerToast } from 'src/components/MessageToasts/actions'; +import DatasetPanel from './DatasetPanel'; +import { ITableColumn, IDatabaseTable, isIDatabaseTable } from './types'; + +/** + * Interface for the getTableMetadata API call + */ +interface IColumnProps { + /** + * Unique id of the database + */ + dbId: number; + /** + * Name of the table + */ + tableName: string; + /** + * Name of the schema + */ + schema: string; +} + +export interface IDatasetPanelWrapperProps { + /** + * Name of the database table + */ + tableName?: string | null; + /** + * Database ID + */ + dbId?: number; + /** + * The selected schema for the database + */ + schema?: string | null; + setHasColumns?: Function; + datasets?: DatasetObject[] | undefined; +} + +const DatasetPanelWrapper = ({ + tableName, + dbId, + schema, + setHasColumns, + datasets, +}: IDatasetPanelWrapperProps) => { + const [columnList, setColumnList] = useState<ITableColumn[]>([]); + const [loading, setLoading] = useState(false); + const [hasError, setHasError] = useState(false); + const tableNameRef = useRef(tableName); + + const getTableMetadata = async (props: IColumnProps) => { + const { dbId, tableName, schema } = props; + setLoading(true); + setHasColumns?.(false); + const path = `/api/v1/database/${dbId}/table/${tableName}/${schema}/`; + try { + const response = await SupersetClient.get({ + endpoint: path, + }); + + if (isIDatabaseTable(response?.json)) { + const table: IDatabaseTable = response.json as IDatabaseTable; + /** + * The user is able to click other table columns while the http call for last selected table column is made + * This check ensures we process the response that matches the last selected table name and ignore the others + */ + if (table.name === tableNameRef.current) { + setColumnList(table.columns); + setHasColumns?.(table.columns.length > 0); + setHasError(false); + } + } else { + setColumnList([]); + setHasColumns?.(false); + setHasError(true); + addDangerToast( + t( + 'The API response from %s does not match the IDatabaseTable interface.', + path, + ), + ); + logging.error( + t( + 'The API response from %s does not match the IDatabaseTable interface.', + path, + ), + ); + } + } catch (error) { + setColumnList([]); + setHasColumns?.(false); + setHasError(true); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + tableNameRef.current = tableName; + if (tableName && schema && dbId) { + getTableMetadata({ tableName, dbId, schema }); + } + // getTableMetadata is a const and should not be in dependency array + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [tableName, dbId, schema]); + + return ( + <DatasetPanel + columnList={columnList} + hasError={hasError} + loading={loading} + tableName={tableName} + datasets={datasets} + /> + ); +}; + +export default DatasetPanelWrapper; diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/types.ts b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/types.ts new file mode 100644 index 0000000000000..c2330f3f10a48 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/types.ts @@ -0,0 +1,92 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Interface for table columns dataset + */ +export interface ITableColumn { + /** + * Name of the column + */ + name: string; + /** + * Datatype of the column + */ + type: string; +} + +/** + * Checks if a given item matches the ITableColumn interface + * @param item Object to check if it matches the ITableColumn interface + * @returns boolean true if matches interface + */ +export const isITableColumn = (item: any): boolean => { + let match = true; + const BASE_ERROR = + 'The object provided to isITableColumn does match the interface.'; + if (typeof item?.name !== 'string') { + match = false; + // eslint-disable-next-line no-console + console.error( + `${BASE_ERROR} The property 'name' is required and must be a string`, + ); + } + if (match && typeof item?.type !== 'string') { + match = false; + // eslint-disable-next-line no-console + console.error( + `${BASE_ERROR} The property 'type' is required and must be a string`, + ); + } + return match; +}; + +export interface IDatabaseTable { + name: string; + columns: ITableColumn[]; +} + +/** + * Checks if a given item matches the isIDatabsetTable interface + * @param item Object to check if it matches the isIDatabsetTable interface + * @returns boolean true if matches interface + */ +export const isIDatabaseTable = (item: any): boolean => { + let match = true; + if (typeof item?.name !== 'string') { + match = false; + } + if (match && !Array.isArray(item.columns)) { + match = false; + } + if (match && item.columns.length > 0) { + const invalid = item.columns.some((column: any, index: number) => { + const valid = isITableColumn(column); + if (!valid) { + // eslint-disable-next-line no-console + console.error( + `The provided object does not match the IDatabaseTable interface. columns[${index}] is invalid and does not match the ITableColumn interface`, + ); + } + return !valid; + }); + match = !invalid; + } + return match; +}; diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/EditDataset.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/EditDataset.test.tsx new file mode 100644 index 0000000000000..c24496facc871 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/EditDataset.test.tsx @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import fetchMock from 'fetch-mock'; +import { render, screen } from 'spec/helpers/testing-library'; +import EditDataset from './index'; + +const DATASET_ENDPOINT = 'glob:*api/v1/dataset/1/related_objects'; + +const mockedProps = { + id: '1', +}; + +fetchMock.get(DATASET_ENDPOINT, { charts: { results: [], count: 2 } }); + +test('should render edit dataset view with tabs', async () => { + render(<EditDataset {...mockedProps} />); + + const columnTab = await screen.findByRole('tab', { name: /columns/i }); + const metricsTab = screen.getByRole('tab', { name: /metrics/i }); + const usageTab = screen.getByRole('tab', { name: /usage/i }); + + expect(fetchMock.calls(DATASET_ENDPOINT)).toBeTruthy(); + expect(columnTab).toBeInTheDocument(); + expect(metricsTab).toBeInTheDocument(); + expect(usageTab).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/UsageTab/UsageTab.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/UsageTab/UsageTab.test.tsx new file mode 100644 index 0000000000000..7bbdbbfd52cfa --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/UsageTab/UsageTab.test.tsx @@ -0,0 +1,405 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import fetchMock from 'fetch-mock'; +import userEvent from '@testing-library/user-event'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import { ChartListChart, getMockChart } from 'spec/fixtures/mockCharts'; +import ToastContainer from 'src/components/MessageToasts/ToastContainer'; +import DatasetUsage from '.'; + +const DEFAULT_DATASET_ID = '1'; +const DEFAULT_ORDER_COLUMN = 'last_saved_at'; +const DEFAULT_ORDER_DIRECTION = 'desc'; +const DEFAULT_PAGE = 0; +const DEFAULT_PAGE_SIZE = 25; + +const getChartResponse = (result: ChartListChart[]) => ({ + count: result.length, + result, +}); + +const CHARTS_ENDPOINT = 'glob:*/api/v1/chart/?*'; +const mockChartsFetch = (response: fetchMock.MockResponse) => { + fetchMock.reset(); + fetchMock.get('glob:*/api/v1/chart/_info?*', { + permissions: ['can_export', 'can_read', 'can_write'], + }); + + fetchMock.get(CHARTS_ENDPOINT, response); +}; + +const renderDatasetUsage = () => + render( + <> + <DatasetUsage datasetId={DEFAULT_DATASET_ID} /> + <ToastContainer /> + </>, + { useRedux: true, useRouter: true }, + ); + +const expectLastChartRequest = (params?: { + datasetId?: string; + orderColumn?: string; + orderDirection?: 'desc' | 'asc'; + page?: number; + pageSize?: number; +}) => { + const { datasetId, orderColumn, orderDirection, page, pageSize } = { + datasetId: DEFAULT_DATASET_ID, + orderColumn: DEFAULT_ORDER_COLUMN, + orderDirection: DEFAULT_ORDER_DIRECTION, + page: DEFAULT_PAGE, + pageSize: DEFAULT_PAGE_SIZE, + ...(params || {}), + }; + + const calls = fetchMock.calls(CHARTS_ENDPOINT); + expect(calls.length).toBeGreaterThan(0); + const lastChartRequestUrl = calls[calls.length - 1][0]; + expect(lastChartRequestUrl).toMatch( + new RegExp(`col:datasource_id,opr:eq,value:%27${datasetId}%27`), + ); + + expect(lastChartRequestUrl).toMatch( + new RegExp(`order_column:${orderColumn}`), + ); + + expect(lastChartRequestUrl).toMatch( + new RegExp(`order_direction:${orderDirection}`), + ); + + expect(lastChartRequestUrl).toMatch(new RegExp(`page:${page}`)); + expect(lastChartRequestUrl).toMatch(new RegExp(`page_size:${pageSize}`)); +}; + +test('shows loading state', async () => { + mockChartsFetch( + new Promise(resolve => + setTimeout(() => resolve(getChartResponse([])), 250), + ), + ); + + renderDatasetUsage(); + + const loadingIndicator = await screen.findByRole('status', { + name: /loading/i, + }); + + expect(loadingIndicator).toBeVisible(); +}); + +test('shows error state', async () => { + mockChartsFetch(500); + renderDatasetUsage(); + + const errorMessage = await screen.findByText( + /an error occurred while fetching charts/i, + ); + + expect(errorMessage).toBeInTheDocument(); +}); + +test('shows empty state', async () => { + mockChartsFetch(getChartResponse([])); + renderDatasetUsage(); + + const noChartsTitle = await screen.findByText(/no charts/i); + const noChartsDescription = screen.getByText( + /this dataset is not used to power any charts\./i, + ); + + expect(noChartsTitle).toBeVisible(); + expect(noChartsDescription).toBeVisible(); + expect(fetchMock.calls(CHARTS_ENDPOINT)).toHaveLength(1); + expectLastChartRequest(); +}); + +test('show and sort by chart title', async () => { + mockChartsFetch( + getChartResponse([ + getMockChart({ id: 1, slice_name: 'Sample A' }), + getMockChart({ id: 2, slice_name: 'Sample C' }), + getMockChart({ id: 3, slice_name: 'Sample B' }), + ]), + ); + + renderDatasetUsage(); + + const chartNameColumnHeader = screen.getByText('Chart'); + const chartNameLinks = await screen.findAllByRole('link', { + name: /sample/i, + }); + + // Default sort + expect(chartNameLinks).toHaveLength(3); + expect(chartNameLinks[0]).toHaveTextContent('Sample A'); + expect(chartNameLinks[0]).toHaveAttribute('href', '/explore/?slice_id=1'); + expect(chartNameLinks[1]).toHaveTextContent('Sample C'); + expect(chartNameLinks[1]).toHaveAttribute('href', '/explore/?slice_id=2'); + expect(chartNameLinks[2]).toHaveTextContent('Sample B'); + expect(chartNameLinks[2]).toHaveAttribute('href', '/explore/?slice_id=3'); + expectLastChartRequest(); + + // Sort by name ascending + userEvent.click(chartNameColumnHeader); + waitFor(() => { + expectLastChartRequest({ + orderColumn: 'slice_name', + orderDirection: 'asc', + }); + }); + + // Sort by name descending + userEvent.click(chartNameColumnHeader); + waitFor(() => { + expectLastChartRequest({ + orderColumn: 'slice_name', + orderDirection: 'desc', + }); + }); +}); + +test('show chart owners', async () => { + mockChartsFetch( + getChartResponse([ + getMockChart({ + id: 1, + owners: [ + { id: 1, first_name: 'John', last_name: 'Doe', username: 'j1' }, + { id: 2, first_name: 'Jane', last_name: 'Doe', username: 'j2' }, + ], + }), + getMockChart({ id: 2 }), + getMockChart({ + id: 3, + owners: [ + { id: 3, first_name: 'John', last_name: 'Doe', username: 'j1' }, + ], + }), + ]), + ); + + renderDatasetUsage(); + + const chartOwners = await screen.findAllByText(/doe/i); + + expect(chartOwners).toHaveLength(3); + expect(chartOwners[0]).toHaveTextContent('John Doe'); + expect(chartOwners[1]).toHaveTextContent('Jane Doe'); + expect(chartOwners[0].parentNode).toBe(chartOwners[1].parentNode); + expect(chartOwners[2]).toHaveTextContent('John Doe'); + expect(chartOwners[2].parentNode).not.toBe(chartOwners[0].parentNode); + expect(chartOwners[2].parentNode).not.toBe(chartOwners[1].parentNode); + expectLastChartRequest(); +}); + +const getDate = (msAgo: number) => { + const date = new Date(); + date.setMilliseconds(date.getMilliseconds() - msAgo); + return date; +}; + +test('show and sort by chart last modified', async () => { + mockChartsFetch( + getChartResponse([ + getMockChart({ id: 2, last_saved_at: getDate(10000).toISOString() }), + getMockChart({ id: 1, last_saved_at: getDate(1000000).toISOString() }), + getMockChart({ id: 3, last_saved_at: getDate(100000000).toISOString() }), + ]), + ); + + renderDatasetUsage(); + + const chartLastModifiedColumnHeader = screen.getByText('Chart last modified'); + const chartLastModifiedValues = await screen.findAllByText( + /a few seconds ago|17 minutes ago|a day ago/i, + ); + + // Default sort + expect(chartLastModifiedValues).toHaveLength(3); + expect(chartLastModifiedValues[0]).toHaveTextContent('a few seconds ago'); + expect(chartLastModifiedValues[1]).toHaveTextContent('17 minutes ago'); + expect(chartLastModifiedValues[2]).toHaveTextContent('a day ago'); + expectLastChartRequest(); + + // Sort by last modified ascending + userEvent.click(chartLastModifiedColumnHeader); + waitFor(() => { + expectLastChartRequest({ orderDirection: 'asc' }); + }); + + // Sort by last modified descending + userEvent.click(chartLastModifiedColumnHeader); + waitFor(() => { + expectLastChartRequest({ orderDirection: 'desc' }); + }); +}); + +test('show and sort by chart last modified by', async () => { + mockChartsFetch( + getChartResponse([ + getMockChart({ + id: 2, + last_saved_by: { id: 1, first_name: 'John', last_name: 'Doe' }, + }), + getMockChart({ + id: 1, + last_saved_by: null, + }), + getMockChart({ + id: 3, + last_saved_by: { id: 2, first_name: 'Jane', last_name: 'Doe' }, + }), + ]), + ); + + renderDatasetUsage(); + + const chartLastModifiedByColumnHeader = screen.getByText( + 'Chart last modified by', + ); + + const chartLastModifiedByValues = await screen.findAllByText(/doe/i); + + // Default sort + expect(chartLastModifiedByValues).toHaveLength(2); + expect(chartLastModifiedByValues[0]).toHaveTextContent('John Doe'); + expect(chartLastModifiedByValues[1]).toHaveTextContent('Jane Doe'); + expectLastChartRequest(); + + // Sort by last modified ascending + userEvent.click(chartLastModifiedByColumnHeader); + waitFor(() => { + expectLastChartRequest({ orderDirection: 'asc' }); + }); + + // Sort by last modified descending + userEvent.click(chartLastModifiedByColumnHeader); + waitFor(() => { + expectLastChartRequest({ orderDirection: 'desc' }); + }); +}); + +test('show chart dashboards', async () => { + mockChartsFetch( + getChartResponse([ + getMockChart({ + id: 1, + dashboards: [ + { id: 1, dashboard_title: 'Sample dashboard A' }, + { id: 2, dashboard_title: 'Sample dashboard B' }, + ], + }), + getMockChart({ id: 2 }), + getMockChart({ + id: 3, + dashboards: [{ id: 3, dashboard_title: 'Sample dashboard C' }], + }), + ]), + ); + + renderDatasetUsage(); + + const chartDashboards = await screen.findAllByRole('link', { + name: /sample dashboard/i, + }); + + expect(chartDashboards).toHaveLength(3); + expect(chartDashboards[0]).toHaveTextContent('Sample dashboard A'); + expect(chartDashboards[0]).toHaveAttribute('href', '/superset/dashboard/1'); + expect(chartDashboards[1]).toHaveTextContent('Sample dashboard B'); + expect(chartDashboards[1]).toHaveAttribute('href', '/superset/dashboard/2'); + expect(chartDashboards[0].closest('.ant-table-cell')).toBe( + chartDashboards[1].closest('.ant-table-cell'), + ); + + expect(chartDashboards[2]).toHaveTextContent('Sample dashboard C'); + expect(chartDashboards[2]).toHaveAttribute('href', '/superset/dashboard/3'); + expect(chartDashboards[2].closest('.ant-table-cell')).not.toBe( + chartDashboards[0].closest('.ant-table-cell'), + ); + + expect(chartDashboards[2].closest('.ant-table-cell')).not.toBe( + chartDashboards[1].closest('.ant-table-cell'), + ); + + expectLastChartRequest(); + + expect( + screen.queryByRole('button', { + name: /right/i, + }), + ).not.toBeInTheDocument(); +}); + +test('paginates', async () => { + const charts = []; + for (let i = 0; i < 65; i += 1) { + charts.push( + getMockChart({ + id: i + 1, + slice_name: `Sample chart ${i + 1}`, + }), + ); + } + + mockChartsFetch(getChartResponse(charts)); + renderDatasetUsage(); + + // First page + let chartNameValues = await screen.findAllByRole('cell', { + name: /sample chart/i, + }); + + expect(chartNameValues).toHaveLength(25); + expect(chartNameValues[0]).toHaveTextContent('Sample chart 1'); + expect(chartNameValues[24]).toHaveTextContent('Sample chart 25'); + + // Second page + userEvent.click( + screen.getByRole('button', { + name: /right/i, + }), + ); + + chartNameValues = await screen.findAllByRole('cell', { + name: /sample chart/i, + }); + + expect(chartNameValues).toHaveLength(25); + expect(chartNameValues[0]).toHaveTextContent('Sample chart 26'); + expect(chartNameValues[24]).toHaveTextContent('Sample chart 50'); + + // Third page + userEvent.click( + screen.getByRole('button', { + name: /right/i, + }), + ); + + chartNameValues = await screen.findAllByRole('cell', { + name: /sample chart/i, + }); + + expect(chartNameValues).toHaveLength(15); + expect(chartNameValues[0]).toHaveTextContent('Sample chart 51'); + expect(chartNameValues[14]).toHaveTextContent('Sample chart 65'); +}); diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/UsageTab/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/UsageTab/index.tsx new file mode 100644 index 0000000000000..99663d91e19dc --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/UsageTab/index.tsx @@ -0,0 +1,261 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useCallback, useEffect, useMemo } from 'react'; +import { Link } from 'react-router-dom'; +import { + css, + ensureIsArray, + styled, + SupersetTheme, + t, +} from '@superset-ui/core'; +import Chart, { ChartLinkedDashboard } from 'src/types/Chart'; +import Table, { + ColumnsType, + TableSize, + OnChangeFunction, +} from 'src/components/Table'; +import { EmptyStateBig } from 'src/components/EmptyState'; +import ChartImage from 'src/assets/images/chart.svg'; +import Icons from 'src/components/Icons'; +import { useToasts } from 'src/components/MessageToasts/withToasts'; +import { useListViewResource } from 'src/views/CRUD/hooks'; +import { FilterOperator } from 'src/components/ListView'; +import moment from 'moment'; +import TruncatedList from 'src/components/TruncatedList'; + +interface DatasetUsageProps { + datasetId: string; +} + +const DEFAULT_PAGE_SIZE = 25; + +const getLinkProps = (dashboard: ChartLinkedDashboard) => ({ + key: dashboard.id, + to: `/superset/dashboard/${dashboard.id}`, + target: '_blank', + rel: 'noreferer noopener', + children: dashboard.dashboard_title, +}); + +const tooltipItemCSS = (theme: SupersetTheme) => css` + color: ${theme.colors.grayscale.light5}; + text-decoration: underline; + &:hover { + color: inherit; + } +`; + +const columns: ColumnsType<Chart> = [ + { + key: 'slice_name', + title: t('Chart'), + width: '320px', + sorter: true, + render: (value, record) => <Link to={record.url}>{record.slice_name}</Link>, + }, + { + key: 'owners', + title: t('Chart owners'), + width: '242px', + render: (value, record) => ( + <TruncatedList + items={ + record.owners?.map( + owner => `${owner.first_name} ${owner.last_name}`, + ) ?? [] + } + /> + ), + }, + { + key: 'last_saved_at', + title: t('Chart last modified'), + width: '209px', + sorter: true, + defaultSortOrder: 'descend', + render: (value, record) => + record.last_saved_at ? moment.utc(record.last_saved_at).fromNow() : null, + }, + { + key: 'last_saved_by.first_name', + title: t('Chart last modified by'), + width: '216px', + sorter: true, + render: (value, record) => + record.last_saved_by + ? `${record.last_saved_by.first_name} ${record.last_saved_by.last_name}` + : null, + }, + { + key: 'dashboards', + title: t('Dashboard usage'), + width: '420px', + render: (value, record) => ( + <TruncatedList<ChartLinkedDashboard> + items={record.dashboards} + renderVisibleItem={dashboard => <Link {...getLinkProps(dashboard)} />} + renderTooltipItem={dashboard => ( + <Link {...getLinkProps(dashboard)} css={tooltipItemCSS} /> + )} + getKey={dashboard => dashboard.id} + /> + ), + }, +]; + +const emptyStateTableCSS = (theme: SupersetTheme) => css` + && th.ant-table-cell { + color: ${theme.colors.grayscale.light1}; + } + + .ant-table-placeholder { + display: none; + } +`; + +const emptyStateButtonText = ( + <> + <Icons.PlusOutlined + iconSize="m" + css={css` + & > .anticon { + line-height: 0; + } + `} + /> + {t('Create chart with dataset')} + </> +); + +const StyledEmptyStateBig = styled(EmptyStateBig)` + margin: ${({ theme }) => 13 * theme.gridUnit}px 0; +`; + +/** + * Hook that uses the useListViewResource hook to retrieve records + * based on pagination state. + */ +const useDatasetChartRecords = (datasetId: string) => { + const { addDangerToast } = useToasts(); + + // Always filters charts by dataset + const baseFilters = useMemo( + () => [ + { + id: 'datasource_id', + operator: FilterOperator.equals, + value: datasetId, + }, + ], + [datasetId], + ); + + // Returns request status/results and function for re-fetching + const { + state: { loading, resourceCount, resourceCollection }, + fetchData, + } = useListViewResource<Chart>( + 'chart', + t('chart'), + addDangerToast, + true, + [], + baseFilters, + ); + + // Adds `key` field + const resourceCollectionWithKey = useMemo( + () => resourceCollection.map(o => ({ ...o, key: o.id })), + [resourceCollection], + ); + + // Called by table with updated table state to fetch new data + const onChange: OnChangeFunction = useCallback( + (tablePagination, tableFilters, tableSorter) => { + const pageIndex = (tablePagination.current ?? 1) - 1; + const pageSize = tablePagination.pageSize ?? 0; + const sortBy = ensureIsArray(tableSorter) + .filter(({ columnKey }) => typeof columnKey === 'string') + .map(({ columnKey, order }) => ({ + id: columnKey as string, + desc: order === 'descend', + })); + fetchData({ pageIndex, pageSize, sortBy, filters: [] }); + }, + [fetchData], + ); + + // Initial data request + useEffect(() => { + fetchData({ + pageIndex: 0, + pageSize: DEFAULT_PAGE_SIZE, + sortBy: [{ id: 'last_saved_at', desc: true }], + filters: [], + }); + }, [fetchData]); + + return { + loading, + recordCount: resourceCount, + data: resourceCollectionWithKey, + onChange, + }; +}; + +const DatasetUsage = ({ datasetId }: DatasetUsageProps) => { + const { loading, recordCount, data, onChange } = + useDatasetChartRecords(datasetId); + + const emptyStateButtonAction = useCallback( + () => + window.open( + `/explore/?dataset_type=table&dataset_id=${datasetId}`, + '_blank', + ), + [datasetId], + ); + + return ( + <div css={!data.length ? emptyStateTableCSS : null}> + <Table + columns={columns} + data={data} + size={TableSize.MIDDLE} + defaultPageSize={DEFAULT_PAGE_SIZE} + recordCount={recordCount} + loading={loading} + onChange={onChange} + /> + {!data.length && !loading ? ( + <StyledEmptyStateBig + image={<ChartImage />} + title={t('No charts')} + description={t('This dataset is not used to power any charts.')} + buttonText={emptyStateButtonText} + buttonAction={emptyStateButtonAction} + /> + ) : null} + </div> + ); +}; + +export default DatasetUsage; diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/index.tsx new file mode 100644 index 0000000000000..e8853cf043b19 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/EditDataset/index.tsx @@ -0,0 +1,78 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { styled, t } from '@superset-ui/core'; +import React from 'react'; +import { useGetDatasetRelatedCounts } from 'src/views/CRUD/data/hooks'; +import Badge from 'src/components/Badge'; +import Tabs from 'src/components/Tabs'; +import UsageTab from './UsageTab'; + +const StyledTabs = styled(Tabs)` + ${({ theme }) => ` + margin-top: ${theme.gridUnit * 8.5}px; + padding-left: ${theme.gridUnit * 4}px; + padding-right: ${theme.gridUnit * 4}px; + + .ant-tabs-top > .ant-tabs-nav::before { + width: ${theme.gridUnit * 50}px; + } + `} +`; + +const TabStyles = styled.div` + ${({ theme }) => ` + .ant-badge { + width: ${theme.gridUnit * 8}px; + margin-left: ${theme.gridUnit * 2.5}px; + } + `} +`; + +interface EditPageProps { + id: string; +} + +const TRANSLATIONS = { + USAGE_TEXT: t('Usage'), + COLUMNS_TEXT: t('Columns'), + METRICS_TEXT: t('Metrics'), +}; + +const EditPage = ({ id }: EditPageProps) => { + const { usageCount } = useGetDatasetRelatedCounts(id); + + const usageTab = ( + <TabStyles> + <span>{TRANSLATIONS.USAGE_TEXT}</span> + {usageCount > 0 && <Badge count={usageCount} />} + </TabStyles> + ); + + return ( + <StyledTabs moreIcon={null} fullWidth={false}> + <Tabs.TabPane tab={TRANSLATIONS.COLUMNS_TEXT} key="1" /> + <Tabs.TabPane tab={TRANSLATIONS.METRICS_TEXT} key="2" /> + <Tabs.TabPane tab={usageTab} key="3"> + <UsageTab datasetId={id} /> + </Tabs.TabPane> + </StyledTabs> + ); +}; + +export default EditPage; diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/Footer.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/Footer.test.tsx new file mode 100644 index 0000000000000..a1818cdf2291f --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/Footer.test.tsx @@ -0,0 +1,87 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import Footer from 'src/views/CRUD/data/dataset/AddDataset/Footer'; + +const mockHistoryPush = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useHistory: () => ({ + push: mockHistoryPush, + }), +})); + +const mockedProps = { + url: 'realwebsite.com', +}; + +const mockPropsWithDataset = { + url: 'realwebsite.com', + datasetObject: { + database: { + id: '1', + database_name: 'examples', + }, + owners: [1, 2, 3], + schema: 'public', + dataset_name: 'Untitled', + table_name: 'real_info', + }, + hasColumns: true, +}; + +describe('Footer', () => { + test('renders a Footer with a cancel button and a disabled create button', () => { + render(<Footer {...mockedProps} />, { useRedux: true }); + + const saveButton = screen.getByRole('button', { + name: /Cancel/i, + }); + + const createButton = screen.getByRole('button', { + name: /Create/i, + }); + + expect(saveButton).toBeVisible(); + expect(createButton).toBeDisabled(); + }); + + test('renders a Create Dataset button when a table is selected', () => { + render(<Footer {...mockPropsWithDataset} />, { useRedux: true }); + + const createButton = screen.getByRole('button', { + name: /Create/i, + }); + + expect(createButton).toBeEnabled(); + }); + + test('create button becomes disabled when table already has a dataset', () => { + render(<Footer datasets={['real_info']} {...mockPropsWithDataset} />, { + useRedux: true, + }); + + const createButton = screen.getByRole('button', { + name: /Create/i, + }); + + expect(createButton).toBeDisabled(); + }); +}); diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx new file mode 100644 index 0000000000000..e0853cdc9d587 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx @@ -0,0 +1,130 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { useHistory } from 'react-router-dom'; +import Button from 'src/components/Button'; +import { t } from '@superset-ui/core'; +import { useSingleViewResource } from 'src/views/CRUD/hooks'; +import { logEvent } from 'src/logger/actions'; +import withToasts from 'src/components/MessageToasts/withToasts'; +import { + LOG_ACTIONS_DATASET_CREATION_EMPTY_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_DATABASE_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_SCHEMA_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_TABLE_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_SUCCESS, +} from 'src/logger/LogUtils'; +import { DatasetObject } from '../types'; + +interface FooterProps { + url: string; + addDangerToast: () => void; + datasetObject?: Partial<DatasetObject> | null; + onDatasetAdd?: (dataset: DatasetObject) => void; + hasColumns?: boolean; + datasets?: (string | null | undefined)[] | undefined; +} + +const INPUT_FIELDS = ['db', 'schema', 'table_name']; +const LOG_ACTIONS = [ + LOG_ACTIONS_DATASET_CREATION_EMPTY_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_DATABASE_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_SCHEMA_CANCELLATION, + LOG_ACTIONS_DATASET_CREATION_TABLE_CANCELLATION, +]; + +function Footer({ + datasetObject, + addDangerToast, + hasColumns = false, + datasets, +}: FooterProps) { + const history = useHistory(); + const { createResource } = useSingleViewResource<Partial<DatasetObject>>( + 'dataset', + t('dataset'), + addDangerToast, + ); + + const createLogAction = (dataset: Partial<DatasetObject>) => { + let totalCount = 0; + const value = Object.keys(dataset).reduce((total, key) => { + if (INPUT_FIELDS.includes(key) && dataset[key]) { + totalCount += 1; + } + return totalCount; + }, 0); + + return LOG_ACTIONS[value]; + }; + + const cancelButtonOnClick = () => { + if (!datasetObject) { + logEvent(LOG_ACTIONS_DATASET_CREATION_EMPTY_CANCELLATION, {}); + } else { + const logAction = createLogAction(datasetObject); + logEvent(logAction, datasetObject); + } + history.goBack(); + }; + + const tooltipText = t('Select a database table.'); + + const onSave = () => { + if (datasetObject) { + const data = { + database: datasetObject.db?.id, + schema: datasetObject.schema, + table_name: datasetObject.table_name, + }; + createResource(data).then(response => { + if (!response) { + return; + } + if (typeof response === 'number') { + logEvent(LOG_ACTIONS_DATASET_CREATION_SUCCESS, datasetObject); + // When a dataset is created the response we get is its ID number + history.push(`/chart/add/?dataset=${datasetObject.table_name}`); + } + }); + } + }; + + const CREATE_DATASET_TEXT = t('Create dataset and create chart'); + const disabledCheck = + !datasetObject?.table_name || + !hasColumns || + datasets?.includes(datasetObject?.table_name); + + return ( + <> + <Button onClick={cancelButtonOnClick}>{t('Cancel')}</Button> + <Button + buttonStyle="primary" + disabled={disabledCheck} + tooltip={!datasetObject?.table_name ? tooltipText : undefined} + onClick={onSave} + > + {CREATE_DATASET_TEXT} + </Button> + </> + ); +} + +export default withToasts(Footer); diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/Header.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/Header.test.tsx new file mode 100644 index 0000000000000..539181208694c --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/Header.test.tsx @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import Header, { + DEFAULT_TITLE, +} from 'src/views/CRUD/data/dataset/AddDataset/Header'; + +describe('Header', () => { + const mockSetDataset = jest.fn(); + + const waitForRender = (props?: any) => + waitFor(() => render(<Header setDataset={mockSetDataset} {...props} />)); + + test('renders a blank state Header', async () => { + await waitForRender(); + + const datasetName = screen.getByText(/new dataset/i); + + expect(datasetName).toBeVisible(); + }); + + test('displays "New dataset" when a table is not selected', async () => { + await waitForRender(); + + const datasetName = screen.getByText(/new dataset/i); + expect(datasetName.innerHTML).toBe(DEFAULT_TITLE); + }); + + test('displays table name when a table is selected', async () => { + // The schema and table name are passed in through props once selected + await waitForRender({ schema: 'testSchema', title: 'testTable' }); + + const datasetName = screen.getByText(/testtable/i); + + expect(datasetName.innerHTML).toBe('testTable'); + }); +}); diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/index.tsx new file mode 100644 index 0000000000000..044221c3fe477 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/index.tsx @@ -0,0 +1,109 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { t } from '@superset-ui/core'; +import { PageHeaderWithActions } from 'src/components/PageHeaderWithActions'; +import Button from 'src/components/Button'; +import Icons from 'src/components/Icons'; +import { Menu } from 'src/components/Menu'; +import { TooltipPlacement } from 'src/components/Tooltip'; +import { + HeaderComponentStyles, + disabledSaveBtnStyles, + StyledCreateDatasetTitle, +} from 'src/views/CRUD/data/dataset/styles'; +import { + DatasetActionType, + DSReducerActionType, +} from 'src/views/CRUD/data/dataset/AddDataset/types'; + +export const DEFAULT_TITLE = t('New dataset'); + +const tooltipProps: { text: string; placement: TooltipPlacement } = { + text: t('Select a database table and create dataset'), + placement: 'bottomRight', +}; + +const renderDisabledSaveButton = () => ( + <Button + buttonStyle="primary" + tooltip={tooltipProps?.text} + placement={tooltipProps?.placement} + disabled + css={disabledSaveBtnStyles} + > + <Icons.Save iconSize="m" /> + {t('Save')} + </Button> +); + +const renderOverlay = () => ( + <Menu> + <Menu.Item>{t('Settings')}</Menu.Item> + <Menu.Item>{t('Delete')}</Menu.Item> + </Menu> +); + +export default function Header({ + setDataset, + title = DEFAULT_TITLE, + editing = false, +}: { + setDataset: React.Dispatch<DSReducerActionType>; + title?: string | null | undefined; + schema?: string | null | undefined; + editing?: boolean; +}) { + const editableTitleProps = { + title: title ?? DEFAULT_TITLE, + placeholder: DEFAULT_TITLE, + onSave: (newDatasetName: string) => { + setDataset({ + type: DatasetActionType.changeDataset, + payload: { name: 'dataset_name', value: newDatasetName }, + }); + }, + canEdit: false, + label: t('dataset name'), + }; + + return ( + <HeaderComponentStyles> + {editing ? ( + <PageHeaderWithActions + editableTitleProps={editableTitleProps} + showTitlePanelItems={false} + showFaveStar={false} + faveStarProps={{ itemId: 1, saveFaveStar: () => {} }} + titlePanelAdditionalItems={<></>} + rightPanelAdditionalItems={renderDisabledSaveButton()} + additionalActionsMenu={renderOverlay()} + menuDropdownProps={{ + disabled: true, + }} + tooltipProps={tooltipProps} + /> + ) : ( + <StyledCreateDatasetTitle> + {title || DEFAULT_TITLE} + </StyledCreateDatasetTitle> + )} + </HeaderComponentStyles> + ); +} diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/LeftPanel.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/LeftPanel.test.tsx new file mode 100644 index 0000000000000..3996dc0fec5c6 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/LeftPanel.test.tsx @@ -0,0 +1,283 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import fetchMock from 'fetch-mock'; +import userEvent from '@testing-library/user-event'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import LeftPanel from 'src/views/CRUD/data/dataset/AddDataset/LeftPanel'; +import { exampleDataset } from 'src/views/CRUD/data/dataset/AddDataset/DatasetPanel/fixtures'; + +const databasesEndpoint = 'glob:*/api/v1/database/?q*'; +const schemasEndpoint = 'glob:*/api/v1/database/*/schemas*'; +const tablesEndpoint = 'glob:*/api/v1/database/*/tables/?q*'; + +fetchMock.get(databasesEndpoint, { + count: 2, + description_columns: {}, + ids: [1, 2], + label_columns: { + allow_file_upload: 'Allow Csv Upload', + allow_ctas: 'Allow Ctas', + allow_cvas: 'Allow Cvas', + allow_dml: 'Allow Dml', + allow_multi_schema_metadata_fetch: 'Allow Multi Schema Metadata Fetch', + allow_run_async: 'Allow Run Async', + allows_cost_estimate: 'Allows Cost Estimate', + allows_subquery: 'Allows Subquery', + allows_virtual_table_explore: 'Allows Virtual Table Explore', + disable_data_preview: 'Disables SQL Lab Data Preview', + backend: 'Backend', + changed_on: 'Changed On', + changed_on_delta_humanized: 'Changed On Delta Humanized', + 'created_by.first_name': 'Created By First Name', + 'created_by.last_name': 'Created By Last Name', + database_name: 'Database Name', + explore_database_id: 'Explore Database Id', + expose_in_sqllab: 'Expose In Sqllab', + force_ctas_schema: 'Force Ctas Schema', + id: 'Id', + }, + list_columns: [ + 'allow_file_upload', + 'allow_ctas', + 'allow_cvas', + 'allow_dml', + 'allow_multi_schema_metadata_fetch', + 'allow_run_async', + 'allows_cost_estimate', + 'allows_subquery', + 'allows_virtual_table_explore', + 'disable_data_preview', + 'backend', + 'changed_on', + 'changed_on_delta_humanized', + 'created_by.first_name', + 'created_by.last_name', + 'database_name', + 'explore_database_id', + 'expose_in_sqllab', + 'force_ctas_schema', + 'id', + ], + list_title: 'List Database', + order_columns: [ + 'allow_file_upload', + 'allow_dml', + 'allow_run_async', + 'changed_on', + 'changed_on_delta_humanized', + 'created_by.first_name', + 'database_name', + 'expose_in_sqllab', + ], + result: [ + { + allow_file_upload: false, + allow_ctas: false, + allow_cvas: false, + allow_dml: false, + allow_multi_schema_metadata_fetch: false, + allow_run_async: false, + allows_cost_estimate: null, + allows_subquery: true, + allows_virtual_table_explore: true, + disable_data_preview: false, + backend: 'postgresql', + changed_on: '2021-03-09T19:02:07.141095', + changed_on_delta_humanized: 'a day ago', + created_by: null, + database_name: 'test-postgres', + explore_database_id: 1, + expose_in_sqllab: true, + force_ctas_schema: null, + id: 1, + }, + { + allow_csv_upload: false, + allow_ctas: false, + allow_cvas: false, + allow_dml: false, + allow_multi_schema_metadata_fetch: false, + allow_run_async: false, + allows_cost_estimate: null, + allows_subquery: true, + allows_virtual_table_explore: true, + disable_data_preview: false, + backend: 'mysql', + changed_on: '2021-03-09T19:02:07.141095', + changed_on_delta_humanized: 'a day ago', + created_by: null, + database_name: 'test-mysql', + explore_database_id: 1, + expose_in_sqllab: true, + force_ctas_schema: null, + id: 2, + }, + ], +}); + +fetchMock.get(schemasEndpoint, { + result: ['information_schema', 'public'], +}); + +fetchMock.get(tablesEndpoint, { + count: 3, + result: [ + { value: 'Sheet1', type: 'table', extra: null }, + { value: 'Sheet2', type: 'table', extra: null }, + { value: 'Sheet3', type: 'table', extra: null }, + ], +}); + +const mockFun = jest.fn(); + +test('should render', async () => { + render(<LeftPanel setDataset={mockFun} />, { + useRedux: true, + }); + expect( + await screen.findByText(/select database & schema/i), + ).toBeInTheDocument(); +}); + +test('should render schema selector, database selector container, and selects', async () => { + render(<LeftPanel setDataset={mockFun} />, { useRedux: true }); + + expect(await screen.findByText(/select database & schema/i)).toBeVisible(); + + const databaseSelect = screen.getByRole('combobox', { + name: 'Select database or type database name', + }); + const schemaSelect = screen.getByRole('combobox', { + name: 'Select schema or type schema name', + }); + expect(databaseSelect).toBeInTheDocument(); + expect(schemaSelect).toBeInTheDocument(); +}); + +test('does not render blank state if there is nothing selected', async () => { + render(<LeftPanel setDataset={mockFun} />, { useRedux: true }); + + expect( + await screen.findByText(/select database & schema/i), + ).toBeInTheDocument(); + const emptyState = screen.queryByRole('img', { name: /empty/i }); + expect(emptyState).not.toBeInTheDocument(); +}); + +test('renders list of options when user clicks on schema', async () => { + render(<LeftPanel setDataset={mockFun} dataset={exampleDataset[0]} />, { + useRedux: true, + }); + + // Click 'test-postgres' database to access schemas + const databaseSelect = screen.getByRole('combobox', { + name: 'Select database or type database name', + }); + userEvent.click(databaseSelect); + expect(await screen.findByText('test-postgres')).toBeInTheDocument(); + userEvent.click(screen.getByText('test-postgres')); + + // Schema select will be automatically populated if there is only one schema + const schemaSelect = screen.getByRole('combobox', { + name: /select schema or type schema name/i, + }); + await waitFor(() => { + expect(schemaSelect).toBeEnabled(); + }); +}); + +test('searches for a table name', async () => { + render(<LeftPanel setDataset={mockFun} dataset={exampleDataset[0]} />, { + useRedux: true, + }); + + // Click 'test-postgres' database to access schemas + const databaseSelect = screen.getByRole('combobox', { + name: /select database or type database name/i, + }); + userEvent.click(databaseSelect); + userEvent.click(await screen.findByText('test-postgres')); + + const schemaSelect = screen.getByRole('combobox', { + name: /select schema or type schema name/i, + }); + + await waitFor(() => expect(schemaSelect).toBeEnabled()); + + // Click 'public' schema to access tables + userEvent.click(schemaSelect); + userEvent.click(screen.getAllByText('public')[1]); + + await waitFor(() => { + expect(screen.getByText('Sheet1')).toBeInTheDocument(); + expect(screen.getByText('Sheet2')).toBeInTheDocument(); + expect(screen.getByText('Sheet3')).toBeInTheDocument(); + }); + + userEvent.type(screen.getByRole('textbox'), 'Sheet2'); + + await waitFor(() => { + expect(screen.queryByText('Sheet1')).not.toBeInTheDocument(); + expect(screen.getByText('Sheet2')).toBeInTheDocument(); + expect(screen.queryByText('Sheet3')).not.toBeInTheDocument(); + }); +}); + +test('renders a warning icon when a table name has a pre-existing dataset', async () => { + render( + <LeftPanel + setDataset={mockFun} + dataset={exampleDataset[0]} + datasetNames={['Sheet2']} + />, + { + useRedux: true, + }, + ); + + // Click 'test-postgres' database to access schemas + const databaseSelect = screen.getByRole('combobox', { + name: /select database or type database name/i, + }); + userEvent.click(databaseSelect); + userEvent.click(await screen.findByText('test-postgres')); + + const schemaSelect = screen.getByRole('combobox', { + name: /select schema or type schema name/i, + }); + + await waitFor(() => expect(schemaSelect).toBeEnabled()); + + // Warning icon should not show yet + expect( + screen.queryByRole('img', { name: 'warning' }), + ).not.toBeInTheDocument(); + + // Click 'public' schema to access tables + userEvent.click(schemaSelect); + userEvent.click(screen.getAllByText('public')[1]); + + await waitFor(() => { + expect(screen.getByText('Sheet2')).toBeInTheDocument(); + }); + + // Sheet2 should now show the warning icon + expect(screen.getByRole('img', { name: 'warning' })).toBeVisible(); +}); diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx new file mode 100644 index 0000000000000..1d1d3847a2daf --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx @@ -0,0 +1,378 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { + useEffect, + useState, + SetStateAction, + Dispatch, + useCallback, +} from 'react'; +import rison from 'rison'; +import { + SupersetClient, + t, + styled, + css, + useTheme, + logging, +} from '@superset-ui/core'; +import { Input } from 'src/components/Input'; +import { Form } from 'src/components/Form'; +import Icons from 'src/components/Icons'; +import { TableOption } from 'src/components/TableSelector'; +import RefreshLabel from 'src/components/RefreshLabel'; +import { Table } from 'src/hooks/apiResources'; +import Loading from 'src/components/Loading'; +import DatabaseSelector, { + DatabaseObject, +} from 'src/components/DatabaseSelector'; +import { + EmptyStateMedium, + emptyStateComponent, +} from 'src/components/EmptyState'; +import { useToasts } from 'src/components/MessageToasts/withToasts'; +import { LocalStorageKeys, getItem } from 'src/utils/localStorageHelpers'; +import { + DatasetActionType, + DatasetObject, +} from 'src/views/CRUD/data/dataset/AddDataset/types'; + +interface LeftPanelProps { + setDataset: Dispatch<SetStateAction<object>>; + dataset?: Partial<DatasetObject> | null; + datasetNames?: (string | null | undefined)[] | undefined; +} + +const SearchIcon = styled(Icons.Search)` + color: ${({ theme }) => theme.colors.grayscale.light1}; +`; + +const LeftPanelStyle = styled.div` + ${({ theme }) => ` + max-width: ${theme.gridUnit * 87.5}px; + padding: ${theme.gridUnit * 4}px; + height: 100%; + background-color: ${theme.colors.grayscale.light5}; + position: relative; + .emptystate { + height: auto; + margin-top: ${theme.gridUnit * 17.5}px; + } + .refresh { + position: absolute; + top: ${theme.gridUnit * 38.75}px; + left: ${theme.gridUnit * 16.75}px; + span[role="button"]{ + font-size: ${theme.gridUnit * 4.25}px; + } + } + .section-title { + margin-top: ${theme.gridUnit * 5.5}px; + margin-bottom: ${theme.gridUnit * 11}px; + font-weight: ${theme.typography.weights.bold}; + } + .table-title { + margin-top: ${theme.gridUnit * 11}px; + margin-bottom: ${theme.gridUnit * 6}px; + font-weight: ${theme.typography.weights.bold}; + } + .options-list { + overflow: auto; + position: absolute; + bottom: 0; + top: ${theme.gridUnit * 92.25}px; + left: ${theme.gridUnit * 3.25}px; + right: 0; + + .no-scrollbar { + margin-right: ${theme.gridUnit * 4}px; + } + + .options { + cursor: pointer; + padding: ${theme.gridUnit * 1.75}px; + border-radius: ${theme.borderRadius}px; + :hover { + background-color: ${theme.colors.grayscale.light4} + } + } + + .options-highlighted { + cursor: pointer; + padding: ${theme.gridUnit * 1.75}px; + border-radius: ${theme.borderRadius}px; + background-color: ${theme.colors.primary.dark1}; + color: ${theme.colors.grayscale.light5}; + } + + .options, .options-highlighted { + display: flex; + align-items: center; + justify-content: space-between; + } + } + form > span[aria-label="refresh"] { + position: absolute; + top: ${theme.gridUnit * 69}px; + left: ${theme.gridUnit * 42.75}px; + font-size: ${theme.gridUnit * 4.25}px; + } + .table-form { + margin-bottom: ${theme.gridUnit * 8}px; + } + .loading-container { + position: absolute; + top: ${theme.gridUnit * 89.75}px; + left: 0; + right: 0; + text-align: center; + img { + width: ${theme.gridUnit * 20}px; + margin-bottom: ${theme.gridUnit * 2.5}px; + } + p { + color: ${theme.colors.grayscale.light1}; + } + } +`} +`; + +export default function LeftPanel({ + setDataset, + dataset, + datasetNames, +}: LeftPanelProps) { + const theme = useTheme(); + + const [tableOptions, setTableOptions] = useState<Array<TableOption>>([]); + const [resetTables, setResetTables] = useState(false); + const [loadTables, setLoadTables] = useState(false); + const [searchVal, setSearchVal] = useState(''); + const [refresh, setRefresh] = useState(false); + const [selectedTable, setSelectedTable] = useState<number | null>(null); + + const { addDangerToast } = useToasts(); + + const setDatabase = useCallback( + (db: Partial<DatabaseObject>) => { + setDataset({ type: DatasetActionType.selectDatabase, payload: { db } }); + setSelectedTable(null); + setResetTables(true); + }, + [setDataset], + ); + + const setTable = (tableName: string, index: number) => { + setSelectedTable(index); + setDataset({ + type: DatasetActionType.selectTable, + payload: { name: 'table_name', value: tableName }, + }); + }; + + const getTablesList = useCallback( + (url: string) => { + SupersetClient.get({ url }) + .then(({ json }) => { + const options: TableOption[] = json.result.map((table: Table) => { + const option: TableOption = { + value: table.value, + label: <TableOption table={table} />, + text: table.label, + }; + + return option; + }); + + setTableOptions(options); + setLoadTables(false); + setResetTables(false); + setRefresh(false); + }) + .catch(error => { + addDangerToast(t('There was an error fetching tables')); + logging.error(t('There was an error fetching tables'), error); + }); + }, + [addDangerToast], + ); + + const setSchema = (schema: string) => { + if (schema) { + setDataset({ + type: DatasetActionType.selectSchema, + payload: { name: 'schema', value: schema }, + }); + setLoadTables(true); + } + setSelectedTable(null); + setResetTables(true); + }; + + const encodedSchema = dataset?.schema + ? encodeURIComponent(dataset?.schema) + : undefined; + + useEffect(() => { + const currentUserSelectedDb = getItem( + LocalStorageKeys.db, + null, + ) as DatabaseObject; + if (currentUserSelectedDb) { + setDatabase(currentUserSelectedDb); + } + }, [setDatabase]); + + useEffect(() => { + if (loadTables) { + const params = rison.encode({ + force: refresh, + schema_name: encodedSchema, + }); + + const endpoint = `/api/v1/database/${dataset?.db?.id}/tables/?q=${params}`; + getTablesList(endpoint); + } + }, [loadTables, dataset?.db?.id, encodedSchema, getTablesList, refresh]); + + useEffect(() => { + if (resetTables) { + setTableOptions([]); + setResetTables(false); + } + }, [resetTables]); + + const filteredOptions = tableOptions.filter(option => + option?.value?.toLowerCase().includes(searchVal.toLowerCase()), + ); + + const Loader = (inline: string) => ( + <div className="loading-container"> + <Loading position="inline" /> + <p>{inline}</p> + </div> + ); + + const SELECT_DATABASE_AND_SCHEMA_TEXT = t('Select database & schema'); + const TABLE_LOADING_TEXT = t('Table loading'); + const NO_TABLES_FOUND_TITLE = t('No database tables found'); + const NO_TABLES_FOUND_DESCRIPTION = t('Try selecting a different schema'); + const SELECT_DATABASE_TABLE_TEXT = t('Select database table'); + const REFRESH_TABLE_LIST_TOOLTIP = t('Refresh table list'); + const REFRESH_TABLES_TEXT = t('Refresh tables'); + const SEARCH_TABLES_PLACEHOLDER_TEXT = t('Search tables'); + + const optionsList = document.getElementsByClassName('options-list'); + const scrollableOptionsList = + optionsList[0]?.scrollHeight > optionsList[0]?.clientHeight; + const [emptyResultsWithSearch, setEmptyResultsWithSearch] = useState(false); + + const onEmptyResults = (searchText?: string) => { + setEmptyResultsWithSearch(!!searchText); + }; + + return ( + <LeftPanelStyle> + <p className="section-title db-schema"> + {SELECT_DATABASE_AND_SCHEMA_TEXT} + </p> + <DatabaseSelector + db={dataset?.db} + handleError={addDangerToast} + onDbChange={setDatabase} + onSchemaChange={setSchema} + emptyState={emptyStateComponent(emptyResultsWithSearch)} + onEmptyResults={onEmptyResults} + /> + {loadTables && !refresh && Loader(TABLE_LOADING_TEXT)} + {dataset?.schema && !loadTables && !tableOptions.length && !searchVal && ( + <div className="emptystate"> + <EmptyStateMedium + image="empty-table.svg" + title={NO_TABLES_FOUND_TITLE} + description={NO_TABLES_FOUND_DESCRIPTION} + /> + </div> + )} + + {dataset?.schema && (tableOptions.length > 0 || searchVal.length > 0) && ( + <> + <Form> + <p className="table-title">{SELECT_DATABASE_TABLE_TEXT}</p> + <RefreshLabel + onClick={() => { + setLoadTables(true); + setRefresh(true); + }} + tooltipContent={REFRESH_TABLE_LIST_TOOLTIP} + /> + {refresh && Loader(REFRESH_TABLES_TEXT)} + {!refresh && ( + <Input + value={searchVal} + prefix={<SearchIcon iconSize="l" />} + onChange={evt => { + setSearchVal(evt.target.value); + }} + className="table-form" + placeholder={SEARCH_TABLES_PLACEHOLDER_TEXT} + allowClear + /> + )} + </Form> + <div className="options-list" data-test="options-list"> + {!refresh && + filteredOptions.map((option, i) => ( + <div + className={ + selectedTable === i + ? scrollableOptionsList + ? 'options-highlighted' + : 'options-highlighted no-scrollbar' + : scrollableOptionsList + ? 'options' + : 'options no-scrollbar' + } + key={i} + role="button" + tabIndex={0} + onClick={() => setTable(option.value, i)} + > + {option.label} + {datasetNames?.includes(option.value) && ( + <Icons.Warning + iconColor={ + selectedTable === i + ? theme.colors.grayscale.light5 + : theme.colors.info.base + } + iconSize="m" + css={css` + margin-right: ${theme.gridUnit * 2}px; + `} + /> + )} + </div> + ))} + </div> + </> + )} + </LeftPanelStyle> + ); +} diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/RightPanel/RightPanel.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/RightPanel/RightPanel.test.tsx new file mode 100644 index 0000000000000..987d96abfa9eb --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/RightPanel/RightPanel.test.tsx @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import RightPanel from 'src/views/CRUD/data/dataset/AddDataset/RightPanel'; + +describe('RightPanel', () => { + it('renders a blank state RightPanel', () => { + render(<RightPanel />); + + expect(screen.getByText(/right panel/i)).toBeVisible(); + }); +}); diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/RightPanel/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/RightPanel/index.tsx new file mode 100644 index 0000000000000..60f9589aad2ef --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/RightPanel/index.tsx @@ -0,0 +1,23 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; + +export default function RightPanel() { + return <div>Right Panel</div>; +} diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDataset/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/index.tsx new file mode 100644 index 0000000000000..67b108ab366f1 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/index.tsx @@ -0,0 +1,136 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useReducer, Reducer, useEffect, useState } from 'react'; +import { useParams } from 'react-router-dom'; +import { useDatasetsList } from 'src/views/CRUD/data/hooks'; +import Header from './Header'; +import EditPage from './EditDataset'; +import DatasetPanel from './DatasetPanel'; +import LeftPanel from './LeftPanel'; +import Footer from './Footer'; +import { DatasetActionType, DatasetObject, DSReducerActionType } from './types'; +import DatasetLayout from '../DatasetLayout'; + +type Schema = { + schema: string; +}; + +export function datasetReducer( + state: DatasetObject | null, + action: DSReducerActionType, +): Partial<DatasetObject> | Schema | null { + const trimmedState = { + ...(state || {}), + }; + + switch (action.type) { + case DatasetActionType.selectDatabase: + return { + ...trimmedState, + ...action.payload, + schema: null, + table_name: null, + }; + case DatasetActionType.selectSchema: + return { + ...trimmedState, + [action.payload.name]: action.payload.value, + table_name: null, + }; + case DatasetActionType.selectTable: + return { + ...trimmedState, + [action.payload.name]: action.payload.value, + }; + case DatasetActionType.changeDataset: + return { + ...trimmedState, + [action.payload.name]: action.payload.value, + }; + default: + return null; + } +} + +const prevUrl = + '/tablemodelview/list/?pageIndex=0&sortColumn=changed_on_delta_humanized&sortOrder=desc'; + +export default function AddDataset() { + const [dataset, setDataset] = useReducer< + Reducer<Partial<DatasetObject> | null, DSReducerActionType> + >(datasetReducer, null); + const [hasColumns, setHasColumns] = useState(false); + const [editPageIsVisible, setEditPageIsVisible] = useState(false); + + const { datasets, datasetNames } = useDatasetsList( + dataset?.db, + dataset?.schema, + ); + + const { datasetId: id } = useParams<{ datasetId: string }>(); + useEffect(() => { + if (!Number.isNaN(parseInt(id, 10))) { + setEditPageIsVisible(true); + } + }, [id]); + + const HeaderComponent = () => ( + <Header setDataset={setDataset} title={dataset?.table_name} /> + ); + + const LeftPanelComponent = () => ( + <LeftPanel + setDataset={setDataset} + dataset={dataset} + datasetNames={datasetNames} + /> + ); + + const EditPageComponent = () => <EditPage id={id} />; + + const DatasetPanelComponent = () => ( + <DatasetPanel + tableName={dataset?.table_name} + dbId={dataset?.db?.id} + schema={dataset?.schema} + setHasColumns={setHasColumns} + datasets={datasets} + /> + ); + + const FooterComponent = () => ( + <Footer + url={prevUrl} + datasetObject={dataset} + hasColumns={hasColumns} + datasets={datasetNames} + /> + ); + + return ( + <DatasetLayout + header={HeaderComponent()} + leftPanel={editPageIsVisible ? null : LeftPanelComponent()} + datasetPanel={ + editPageIsVisible ? EditPageComponent() : DatasetPanelComponent() + } + footer={FooterComponent()} + /> + ); +} diff --git a/superset-frontend/src/dashboard/stylesheets/grid.less b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/types.tsx similarity index 50% rename from superset-frontend/src/dashboard/stylesheets/grid.less rename to superset-frontend/src/views/CRUD/data/dataset/AddDataset/types.tsx index 5b793b96bdb6a..89473e5426cbb 100644 --- a/superset-frontend/src/dashboard/stylesheets/grid.less +++ b/superset-frontend/src/views/CRUD/data/dataset/AddDataset/types.tsx @@ -16,38 +16,41 @@ * specific language governing permissions and limitations * under the License. */ +import { DatabaseObject } from 'src/components/DatabaseSelector'; -/* this is the ParentSize wrapper */ -.grid-container > div:first-child { - height: inherit !important; +export enum DatasetActionType { + selectDatabase, + selectSchema, + selectTable, + changeDataset, } -.grid-content { - display: flex; - flex-direction: column; +export interface DatasetObject { + db: DatabaseObject & { owners: [number] }; + schema?: string | null; + dataset_name: string; + table_name?: string | null; + explore_url?: string; } -/* gutters between rows */ -.grid-content > div:not(:only-child):not(:last-child):not(.empty-droptarget) { - margin-bottom: 16px; +export interface DatasetReducerPayloadType { + name: string; + value?: string; } -/* Editing guides */ -.grid-column-guide { - position: absolute; - top: 0; - min-height: 100%; - background-color: fade(@indicator-color, @opacity-light); - pointer-events: none; - box-shadow: inset 0 0 0 1px fade(@indicator-color, @opacity-medium-heavy); -} +export type Schema = { + schema?: string | null | undefined; +}; -.grid-row-guide { - position: absolute; - left: 0; - bottom: 2; - height: 2; - background-color: @indicator-color; - pointer-events: none; - z-index: @z-index-above-dashboard-charts; -} +export type DSReducerActionType = + | { + type: DatasetActionType.selectDatabase; + payload: Partial<DatasetObject>; + } + | { + type: + | DatasetActionType.changeDataset + | DatasetActionType.selectSchema + | DatasetActionType.selectTable; + payload: DatasetReducerPayloadType; + }; diff --git a/superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx b/superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx deleted file mode 100644 index 10a3b7bb77e4a..0000000000000 --- a/superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React, { FunctionComponent, useState, useEffect } from 'react'; -import { styled, t } from '@superset-ui/core'; -import { useSingleViewResource } from 'src/views/CRUD/hooks'; -import Modal from 'src/components/Modal'; -import TableSelector from 'src/components/TableSelector'; -import withToasts from 'src/components/MessageToasts/withToasts'; -import { DatabaseObject } from 'src/components/DatabaseSelector'; - -type DatasetAddObject = { - id: number; - database: number; - schema: string; - table_name: string; -}; -interface DatasetModalProps { - addDangerToast: (msg: string) => void; - addSuccessToast: (msg: string) => void; - onDatasetAdd?: (dataset: DatasetAddObject) => void; - onHide: () => void; - show: boolean; -} - -const TableSelectorContainer = styled.div` - padding-bottom: 340px; - width: 65%; -`; - -const DatasetModal: FunctionComponent<DatasetModalProps> = ({ - addDangerToast, - addSuccessToast, - onDatasetAdd, - onHide, - show, -}) => { - const [currentDatabase, setCurrentDatabase] = useState< - DatabaseObject | undefined - >(); - const [currentSchema, setSchema] = useState<string | undefined>(''); - const [currentTableName, setTableName] = useState(''); - const [disableSave, setDisableSave] = useState(true); - const { - createResource, - state: { loading }, - } = useSingleViewResource<Partial<DatasetAddObject>>( - 'dataset', - t('dataset'), - addDangerToast, - ); - - useEffect(() => { - setDisableSave(currentDatabase === undefined || currentTableName === ''); - }, [currentTableName, currentDatabase]); - - const onDbChange = (db: DatabaseObject) => { - setCurrentDatabase(db); - }; - - const onSchemaChange = (schema?: string) => { - setSchema(schema); - }; - - const onTableChange = (tableName: string) => { - setTableName(tableName); - }; - - const clearModal = () => { - setSchema(''); - setTableName(''); - setCurrentDatabase(undefined); - setDisableSave(true); - }; - - const hide = () => { - clearModal(); - onHide(); - }; - - const onSave = () => { - if (currentDatabase === undefined) { - return; - } - const data = { - database: currentDatabase.id, - ...(currentSchema ? { schema: currentSchema } : {}), - table_name: currentTableName, - }; - createResource(data).then(response => { - if (!response) { - return; - } - if (onDatasetAdd) { - onDatasetAdd({ id: response.id, ...response }); - } - addSuccessToast(t('The dataset has been saved')); - hide(); - }); - }; - - return ( - <Modal - disablePrimaryButton={disableSave} - primaryButtonLoading={loading} - onHandledPrimaryAction={onSave} - onHide={hide} - primaryButtonName={t('Add')} - show={show} - title={t('Add dataset')} - > - <TableSelectorContainer> - <TableSelector - clearable={false} - formMode - database={currentDatabase} - schema={currentSchema} - tableValue={currentTableName} - onDbChange={onDbChange} - onSchemaChange={onSchemaChange} - onTableSelectChange={onTableChange} - handleError={addDangerToast} - /> - </TableSelectorContainer> - </Modal> - ); -}; - -export default withToasts(DatasetModal); diff --git a/superset-frontend/src/views/CRUD/data/dataset/DatasetLayout/DatasetLayout.test.tsx b/superset-frontend/src/views/CRUD/data/dataset/DatasetLayout/DatasetLayout.test.tsx new file mode 100644 index 0000000000000..a1939761aa7c5 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/DatasetLayout/DatasetLayout.test.tsx @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import DatasetLayout from 'src/views/CRUD/data/dataset/DatasetLayout'; +import Header from 'src/views/CRUD/data/dataset/AddDataset/Header'; +import LeftPanel from 'src/views/CRUD/data/dataset/AddDataset/LeftPanel'; +import DatasetPanel from 'src/views/CRUD/data/dataset/AddDataset/DatasetPanel'; +import RightPanel from 'src/views/CRUD/data/dataset/AddDataset/RightPanel'; +import Footer from 'src/views/CRUD/data/dataset/AddDataset/Footer'; + +const mockHistoryPush = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useHistory: () => ({ + push: mockHistoryPush, + }), +})); + +describe('DatasetLayout', () => { + it('renders nothing when no components are passed in', () => { + render(<DatasetLayout />); + const layoutWrapper = screen.getByTestId('dataset-layout-wrapper'); + + expect(layoutWrapper).toHaveTextContent(''); + }); + + const mockSetDataset = jest.fn(); + + const waitForRender = () => + waitFor(() => render(<Header setDataset={mockSetDataset} />)); + + it('renders a Header when passed in', async () => { + await waitForRender(); + + expect(screen.getByText(/new dataset/i)).toBeVisible(); + }); + + it('renders a LeftPanel when passed in', async () => { + render( + <DatasetLayout leftPanel={<LeftPanel setDataset={() => null} />} />, + { useRedux: true }, + ); + + expect( + await screen.findByText(/select database & schema/i), + ).toBeInTheDocument(); + expect(LeftPanel).toBeTruthy(); + }); + + it('renders a DatasetPanel when passed in', () => { + render(<DatasetLayout datasetPanel={<DatasetPanel />} />); + + const blankDatasetImg = screen.getByRole('img', { name: /empty/i }); + const blankDatasetTitle = screen.getByText(/select dataset source/i); + + expect(blankDatasetImg).toBeVisible(); + expect(blankDatasetTitle).toBeVisible(); + }); + + it('renders a RightPanel when passed in', () => { + render(<DatasetLayout rightPanel={RightPanel()} />); + + expect(screen.getByText(/right panel/i)).toBeVisible(); + }); + + it('renders a Footer when passed in', () => { + render(<DatasetLayout footer={<Footer url="" />} />, { useRedux: true }); + + expect(screen.getByText(/Cancel/i)).toBeVisible(); + }); +}); diff --git a/superset-frontend/src/views/CRUD/data/dataset/DatasetLayout/index.tsx b/superset-frontend/src/views/CRUD/data/dataset/DatasetLayout/index.tsx new file mode 100644 index 0000000000000..7702efcb59075 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/DatasetLayout/index.tsx @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { ReactElement, JSXElementConstructor } from 'react'; +import { + StyledLayoutWrapper, + LeftColumn, + RightColumn, + OuterRow, + PanelRow, + FooterRow, + StyledLayoutHeader, + StyledLayoutLeftPanel, + StyledLayoutDatasetPanel, + StyledLayoutRightPanel, + StyledLayoutFooter, +} from 'src/views/CRUD/data/dataset/styles'; + +interface DatasetLayoutProps { + header?: ReactElement<any, string | JSXElementConstructor<any>> | null; + leftPanel?: ReactElement<any, string | JSXElementConstructor<any>> | null; + datasetPanel?: ReactElement<any, string | JSXElementConstructor<any>> | null; + rightPanel?: ReactElement<any, string | JSXElementConstructor<any>> | null; + footer?: ReactElement<any, string | JSXElementConstructor<any>> | null; +} + +export default function DatasetLayout({ + header, + leftPanel, + datasetPanel, + rightPanel, + footer, +}: DatasetLayoutProps) { + return ( + <StyledLayoutWrapper data-test="dataset-layout-wrapper"> + {header && <StyledLayoutHeader>{header}</StyledLayoutHeader>} + <OuterRow> + {leftPanel && ( + <LeftColumn> + <StyledLayoutLeftPanel>{leftPanel}</StyledLayoutLeftPanel> + </LeftColumn> + )} + <RightColumn> + <PanelRow> + {datasetPanel && ( + <StyledLayoutDatasetPanel> + {datasetPanel} + </StyledLayoutDatasetPanel> + )} + {rightPanel && ( + <StyledLayoutRightPanel>{rightPanel}</StyledLayoutRightPanel> + )} + </PanelRow> + + <FooterRow> + {footer && <StyledLayoutFooter>{footer}</StyledLayoutFooter>} + </FooterRow> + </RightColumn> + </OuterRow> + </StyledLayoutWrapper> + ); +} diff --git a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.test.jsx b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.test.tsx similarity index 79% rename from superset-frontend/src/views/CRUD/data/dataset/DatasetList.test.jsx rename to superset-frontend/src/views/CRUD/data/dataset/DatasetList.test.tsx index 92f06881c8578..25f778dff082f 100644 --- a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.test.jsx +++ b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.test.tsx @@ -33,6 +33,7 @@ import Button from 'src/components/Button'; import IndeterminateCheckbox from 'src/components/IndeterminateCheckbox'; import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; import { act } from 'react-dom/test-utils'; +import SubMenu from 'src/views/components/SubMenu'; // store needed for withToasts(DatasetList) const mockStore = configureStore([thunk]); @@ -41,6 +42,7 @@ const store = mockStore({}); const datasetsInfoEndpoint = 'glob:*/api/v1/dataset/_info*'; const datasetsOwnersEndpoint = 'glob:*/api/v1/dataset/related/owners*'; const datasetsSchemaEndpoint = 'glob:*/api/v1/dataset/distinct/schema*'; +const datasetsDuplicateEndpoint = 'glob:*/api/v1/dataset/duplicate*'; const databaseEndpoint = 'glob:*/api/v1/dataset/related/database*'; const datasetsEndpoint = 'glob:*/api/v1/dataset/?*'; @@ -51,7 +53,7 @@ const mockdatasets = [...new Array(3)].map((_, i) => ({ changed_by: 'user', changed_on: new Date().toISOString(), database_name: `db ${i}`, - explore_url: `/explore/table/${i}`, + explore_url: `/explore/?datasource_type=table&datasource_id=${i}`, id: i, schema: `schema ${i}`, table_name: `coolest table ${i}`, @@ -64,7 +66,7 @@ const mockUser = { }; fetchMock.get(datasetsInfoEndpoint, { - permissions: ['can_read', 'can_write'], + permissions: ['can_read', 'can_write', 'can_duplicate'], }); fetchMock.get(datasetsOwnersEndpoint, { result: [], @@ -72,6 +74,9 @@ fetchMock.get(datasetsOwnersEndpoint, { fetchMock.get(datasetsSchemaEndpoint, { result: [], }); +fetchMock.post(datasetsDuplicateEndpoint, { + result: [], +}); fetchMock.get(datasetsEndpoint, { result: mockdatasets, dataset_count: 3, @@ -80,7 +85,7 @@ fetchMock.get(databaseEndpoint, { result: [], }); -async function mountAndWait(props) { +async function mountAndWait(props: {}) { const mounted = mount( <Provider store={store}> <DatasetList {...props} user={mockUser} /> @@ -93,7 +98,7 @@ async function mountAndWait(props) { describe('DatasetList', () => { const mockedProps = {}; - let wrapper; + let wrapper: any; beforeAll(async () => { wrapper = await mountAndWait(mockedProps); @@ -183,12 +188,59 @@ describe('DatasetList', () => { ).toMatchInlineSnapshot(`"3 Selected (2 Physical, 1 Virtual)"`); }); + it('shows duplicate modal when duplicate action is clicked', async () => { + await waitForComponentToPaint(wrapper); + expect( + wrapper.find('[data-test="duplicate-modal-input"]').exists(), + ).toBeFalsy(); + act(() => { + wrapper + .find('#duplicate-action-tooltop') + .at(0) + .find('.action-button') + .props() + .onClick(); + }); + await waitForComponentToPaint(wrapper); + expect( + wrapper.find('[data-test="duplicate-modal-input"]').exists(), + ).toBeTruthy(); + }); + + it('calls the duplicate endpoint', async () => { + await waitForComponentToPaint(wrapper); + await act(async () => { + wrapper + .find('#duplicate-action-tooltop') + .at(0) + .find('.action-button') + .props() + .onClick(); + await waitForComponentToPaint(wrapper); + wrapper + .find('[data-test="duplicate-modal-input"]') + .at(0) + .props() + .onPressEnter(); + }); + expect(fetchMock.calls(/dataset\/duplicate/)).toHaveLength(1); + }); + + it('renders a SubMenu', () => { + expect(wrapper.find(SubMenu)).toExist(); + }); + + it('renders a SubMenu with no tabs', () => { + expect(wrapper.find(SubMenu).props().tabs).toBeUndefined(); + }); + it('renders datahub link when urn is defined', async () => { await waitForComponentToPaint(wrapper); expect( wrapper .find('[data-test="cell-text"]') .filterWhere( + // @ts-ignore e => e.childAt(0).props().cell.column.id === 'datahub_link' && e.childAt(0).props().cell.row.index === 0, @@ -204,6 +256,7 @@ describe('DatasetList', () => { wrapper .find('[data-test="cell-text"]') .filterWhere( + // @ts-ignore e => e.childAt(0).props().cell.column.id === 'datahub_link' && e.childAt(0).props().cell.row.index === 1, @@ -214,6 +267,12 @@ describe('DatasetList', () => { }); }); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({}), + useHistory: () => ({}), +})); + describe('RTL', () => { async function renderAndWait() { const mounted = act(async () => { @@ -222,14 +281,17 @@ describe('RTL', () => { <QueryParamProvider> <DatasetList {...mockedProps} user={mockUser} /> </QueryParamProvider>, - { useRedux: true }, + { useRedux: true, useRouter: true }, ); }); return mounted; } - let isFeatureEnabledMock; + let isFeatureEnabledMock: jest.SpyInstance< + boolean, + [feature: featureFlags.FeatureFlag] + >; beforeEach(async () => { isFeatureEnabledMock = jest .spyOn(featureFlags, 'isFeatureEnabled') diff --git a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx index 0759306cc08b6..958fafb2d9004 100644 --- a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx +++ b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx @@ -23,7 +23,9 @@ import React, { useMemo, useCallback, } from 'react'; +import { useHistory } from 'react-router-dom'; import rison from 'rison'; +import { datahubUrl } from 'src/preamble'; import { createFetchRelated, createFetchDistinct, @@ -45,7 +47,6 @@ import SubMenu, { SubMenuProps, ButtonProps, } from 'src/views/components/SubMenu'; -import { commonMenuData } from 'src/views/CRUD/data/common'; import Owner from 'src/types/Owner'; import withToasts from 'src/components/MessageToasts/withToasts'; import { Tooltip } from 'src/components/Tooltip'; @@ -56,9 +57,8 @@ import InfoTooltip from 'src/components/InfoTooltip'; import ImportModelsModal from 'src/components/ImportModal/index'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import WarningIconWithTooltip from 'src/components/WarningIconWithTooltip'; -import { isUserAdmin } from 'src/dashboard/util/findPermission'; -import { datahubUrl } from 'src/preamble'; -import AddDatasetModal from './AddDatasetModal'; +import { isUserAdmin } from 'src/dashboard/util/permissionUtils'; +import { GenericLink } from 'src/components/GenericLink/GenericLink'; import { PAGE_SIZE, @@ -66,6 +66,7 @@ import { PASSWORDS_NEEDED_MESSAGE, CONFIRM_OVERWRITE_MESSAGE, } from './constants'; +import DuplicateDatasetModal from './DuplicateDatasetModal'; const FlexRowContainer = styled.div` align-items: center; @@ -116,6 +117,11 @@ type Dataset = { table_name: string; }; +interface VirtualDataset extends Dataset { + extra: Record<string, any>; + sql: string; +} + interface DatasetListProps { addDangerToast: (msg: string) => void; addSuccessToast: (msg: string) => void; @@ -131,6 +137,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ addSuccessToast, user, }) => { + const history = useHistory(); const { state: { loading, @@ -144,9 +151,6 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ refreshData, } = useListViewResource<Dataset>('dataset', t('dataset'), addDangerToast); - const [datasetAddModalOpen, setDatasetAddModalOpen] = - useState<boolean>(false); - const [datasetCurrentlyDeleting, setDatasetCurrentlyDeleting] = useState< (Dataset & { chart_count: number; dashboard_count: number }) | null >(null); @@ -154,6 +158,9 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ const [datasetCurrentlyEditing, setDatasetCurrentlyEditing] = useState<Dataset | null>(null); + const [datasetCurrentlyDuplicating, setDatasetCurrentlyDuplicating] = + useState<VirtualDataset | null>(null); + const [importingDataset, showImportModal] = useState<boolean>(false); const [passwordFields, setPasswordFields] = useState<string[]>([]); const [preparingExport, setPreparingExport] = useState<boolean>(false); @@ -175,6 +182,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ const canEdit = hasPerm('can_write'); const canDelete = hasPerm('can_write'); const canCreate = hasPerm('can_write'); + const canDuplicate = hasPerm('can_duplicate'); const canExport = hasPerm('can_export') && isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT); @@ -232,6 +240,10 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ ), ); + const openDatasetDuplicateModal = (dataset: VirtualDataset) => { + setDatasetCurrentlyDuplicating(dataset); + }; + const handleBulkDatasetExport = (datasetsToExport: Dataset[]) => { const ids = datasetsToExport.map(({ id }) => id); handleResourceExport('dataset', ids, () => { @@ -281,7 +293,11 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ }, }, }: any) => { - const titleLink = <a href={exploreURL}>{datasetTitle}</a>; + const titleLink = ( + // exploreUrl can be a link to Explore or an external link + // in the first case use SPA routing, else use HTML anchor + <GenericLink to={exploreURL}>{datasetTitle}</GenericLink> + ); try { const parsedExtra = JSON.parse(extra); return ( @@ -341,7 +357,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ row: { original: { kind }, }, - }: any) => kind[0]?.toUpperCase() + kind.slice(1), + }: any) => (kind === 'physical' ? t('Physical') : t('Virtual')), Header: t('Type'), accessor: 'kind', disableSortBy: true, @@ -408,7 +424,8 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ const handleEdit = () => openDatasetEditModal(original); const handleDelete = () => openDatasetDeleteModal(original); const handleExport = () => handleBulkDatasetExport([original]); - if (!canEdit && !canDelete && !canExport) { + const handleDuplicate = () => openDatasetDuplicateModal(original); + if (!canEdit && !canDelete && !canExport && !canDuplicate) { return null; } return ( @@ -467,22 +484,39 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ </span> </Tooltip> )} + {canDuplicate && original.kind === 'virtual' && ( + <Tooltip + id="duplicate-action-tooltop" + title={t('Duplicate')} + placement="bottom" + > + <span + role="button" + tabIndex={0} + className="action-button" + onClick={handleDuplicate} + > + <Icons.Copy /> + </span> + </Tooltip> + )} </Actions> ); }, Header: t('Actions'), id: 'actions', - hidden: !canEdit && !canDelete, + hidden: !canEdit && !canDelete && !canDuplicate, disableSortBy: true, }, ], - [canEdit, canDelete, canExport, openDatasetEditModal], + [canEdit, canDelete, canExport, openDatasetEditModal, canDuplicate, user], ); const filterTypes: Filters = useMemo( () => [ { Header: t('Owner'), + key: 'owner', id: 'owners', input: 'select', operator: FilterOperator.relationManyMany, @@ -502,6 +536,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ }, { Header: t('Database'), + key: 'database', id: 'database', input: 'select', operator: FilterOperator.relationOneMany, @@ -517,6 +552,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ }, { Header: t('Schema'), + key: 'schema', id: 'schema', input: 'select', operator: FilterOperator.equals, @@ -532,17 +568,19 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ }, { Header: t('Type'), + key: 'sql', id: 'sql', input: 'select', operator: FilterOperator.datasetIsNullOrEmpty, unfilteredLabel: 'All', selects: [ - { label: 'Virtual', value: false }, - { label: 'Physical', value: true }, + { label: t('Virtual'), value: false }, + { label: t('Physical'), value: true }, ], }, { Header: t('Certified'), + key: 'certified', id: 'id', urlDisplay: 'certified', input: 'select', @@ -555,17 +593,18 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ }, { Header: t('Search'), + key: 'search', id: 'table_name', input: 'search', operator: FilterOperator.contains, }, ], - [], + [user], ); const menuData: SubMenuProps = { activeChild: 'Datasets', - ...commonMenuData, + name: t('Datasets'), }; const buttonArr: Array<ButtonProps> = []; @@ -585,7 +624,9 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ <i className="fa fa-plus" /> {t('Dataset')}{' '} </> ), - onClick: () => setDatasetAddModalOpen(true), + onClick: () => { + history.push('/dataset/add/'); + }, buttonStyle: 'primary', }); @@ -616,6 +657,10 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ setDatasetCurrentlyEditing(null); }; + const closeDatasetDuplicateModal = () => { + setDatasetCurrentlyDuplicating(null); + }; + const handleDatasetDelete = ({ id, table_name: tableName }: Dataset) => { SupersetClient.delete({ endpoint: `/api/v1/dataset/${id}`, @@ -651,14 +696,33 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ ); }; + const handleDatasetDuplicate = (newDatasetName: string) => { + if (datasetCurrentlyDuplicating === null) { + addDangerToast(t('There was an issue duplicating the dataset.')); + } + + SupersetClient.post({ + endpoint: `/api/v1/dataset/duplicate`, + jsonPayload: { + base_model_id: datasetCurrentlyDuplicating?.id, + table_name: newDatasetName, + }, + }).then( + () => { + setDatasetCurrentlyDuplicating(null); + refreshData(); + }, + createErrorHandler(errMsg => + addDangerToast( + t('There was an issue duplicating the selected datasets: %s', errMsg), + ), + ), + ); + }; + return ( <> <SubMenu {...menuData} /> - <AddDatasetModal - show={datasetAddModalOpen} - onHide={() => setDatasetAddModalOpen(false)} - onDatasetAdd={refreshData} - /> {datasetCurrentlyDeleting && ( <DeleteModal description={t( @@ -685,6 +749,11 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({ show /> )} + <DuplicateDatasetModal + dataset={datasetCurrentlyDuplicating} + onHide={closeDatasetDuplicateModal} + onDuplicate={handleDatasetDuplicate} + /> <ConfirmStatusChange title={t('Please confirm')} description={t( diff --git a/superset-frontend/src/views/CRUD/data/dataset/DuplicateDatasetModal.tsx b/superset-frontend/src/views/CRUD/data/dataset/DuplicateDatasetModal.tsx index 0885bf03155f0..6766adf74eab5 100644 --- a/superset-frontend/src/views/CRUD/data/dataset/DuplicateDatasetModal.tsx +++ b/superset-frontend/src/views/CRUD/data/dataset/DuplicateDatasetModal.tsx @@ -1,3 +1,21 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ import { t } from '@superset-ui/core'; import React, { FunctionComponent, useEffect, useState } from 'react'; import { FormLabel } from 'src/components/Form'; @@ -43,6 +61,7 @@ const DuplicateDatasetModal: FunctionComponent<DuplicateDatasetModalProps> = ({ title={t('Duplicate dataset')} disablePrimaryButton={disableSave} onHandledPrimaryAction={duplicateDataset} + primaryButtonName={t('Duplicate')} > <FormLabel htmlFor="duplicate">{t('New dataset name')}</FormLabel> <Input diff --git a/superset-frontend/src/views/CRUD/data/dataset/styles.ts b/superset-frontend/src/views/CRUD/data/dataset/styles.ts new file mode 100644 index 0000000000000..268b9e273e486 --- /dev/null +++ b/superset-frontend/src/views/CRUD/data/dataset/styles.ts @@ -0,0 +1,146 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { styled, css, SupersetTheme } from '@superset-ui/core'; + +export const StyledLayoutWrapper = styled.div` + flex-grow: 1; + display: flex; + flex-direction: column; + background-color: ${({ theme }) => theme.colors.grayscale.light5}; +`; + +const Column = styled.div` + width: 100%; + height: 100%; + flex-direction: column; +`; + +export const LeftColumn = styled(Column)` + width: ${({ theme }) => theme.gridUnit * 80}px; + height: auto; +`; + +export const RightColumn = styled(Column)` + height: auto; + display: flex; + flex: 1 0 auto; + width: calc(100% - ${({ theme }) => theme.gridUnit * 80}px); +`; + +const Row = styled.div` + width: 100%; + height: 100%; + display: flex; + flex-direction: row; +`; + +export const OuterRow = styled(Row)` + flex: 1 0 auto; +`; + +export const PanelRow = styled(Row)` + flex: 1 0 auto; + height: auto; +`; + +export const FooterRow = styled(Row)` + flex: 0 0 auto; + height: ${({ theme }) => theme.gridUnit * 16}px; + z-index: 0; +`; + +export const StyledLayoutHeader = styled.div` + ${({ theme }) => ` + flex: 0 0 auto; + height: ${theme.gridUnit * 16}px; + border-bottom: 2px solid ${theme.colors.grayscale.light2}; + + .header-with-actions { + height: ${theme.gridUnit * 15.5}px; + } + `} +`; + +export const StyledCreateDatasetTitle = styled.div` + ${({ theme }) => ` + margin: ${theme.gridUnit * 4}px; + font-size: ${theme.typography.sizes.xl}px; + font-weight: ${theme.typography.weights.bold}; + `} +`; + +export const StyledLayoutLeftPanel = styled.div` + ${({ theme }) => ` + width: ${theme.gridUnit * 80}px; + height: 100%; + border-right: 1px solid ${theme.colors.grayscale.light2}; + `} +`; + +export const StyledLayoutDatasetPanel = styled.div` + width: 100%; + position: relative; +`; + +export const StyledLayoutRightPanel = styled.div` + ${({ theme }) => ` + border-left: 1px solid ${theme.colors.grayscale.light2}; + color: ${theme.colors.success.base}; + `} +`; + +export const StyledLayoutFooter = styled.div` + ${({ theme }) => ` + height: ${theme.gridUnit * 16}px; + width: 100%; + border-top: 1px solid ${theme.colors.grayscale.light2}; + border-bottom: 1px solid ${theme.colors.grayscale.light2}; + color: ${theme.colors.info.base}; + border-top: ${theme.gridUnit / 4}px solid + ${theme.colors.grayscale.light2}; + padding: ${theme.gridUnit * 4}px; + display: flex; + justify-content: flex-end; + background-color: ${theme.colors.grayscale.light5}; + z-index: ${theme.zIndex.max} + `} +`; + +export const HeaderComponentStyles = styled.div` + .ant-btn { + span { + margin-right: 0; + } + + &:disabled { + svg { + color: ${({ theme }) => theme.colors.grayscale.light1}; + } + } + } +`; + +export const disabledSaveBtnStyles = (theme: SupersetTheme) => css` + width: ${theme.gridUnit * 21.5}px; + + &:disabled { + background-color: ${theme.colors.grayscale.light3}; + color: ${theme.colors.grayscale.light1}; + } +`; diff --git a/superset-frontend/src/views/CRUD/data/hooks.ts b/superset-frontend/src/views/CRUD/data/hooks.ts index 41b5145915474..4e7a51de35213 100644 --- a/superset-frontend/src/views/CRUD/data/hooks.ts +++ b/superset-frontend/src/views/CRUD/data/hooks.ts @@ -16,11 +16,17 @@ * specific language governing permissions and limitations * under the License. */ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; +import { SupersetClient, logging, t } from '@superset-ui/core'; +import rison from 'rison'; +import { addDangerToast } from 'src/components/MessageToasts/actions'; +import { DatasetObject } from 'src/views/CRUD/data/dataset/AddDataset/types'; +import { DatabaseObject } from 'src/components/DatabaseSelector'; type BaseQueryObject = { id: number; }; + export function useQueryPreviewState<D extends BaseQueryObject = any>({ queries, fetchData, @@ -73,3 +79,100 @@ export function useQueryPreviewState<D extends BaseQueryObject = any>({ disableNext, }; } + +/** + * Retrieves all pages of dataset results + */ +export const useDatasetsList = ( + db: + | (DatabaseObject & { + owners: [number]; + }) + | undefined, + schema: string | null | undefined, +) => { + const [datasets, setDatasets] = useState<DatasetObject[]>([]); + const encodedSchema = schema ? encodeURIComponent(schema) : undefined; + + const getDatasetsList = useCallback(async (filters: object[]) => { + let results: DatasetObject[] = []; + let page = 0; + let count; + + // If count is undefined or less than results, we need to + // asynchronously retrieve a page of dataset results + while (count === undefined || results.length < count) { + const queryParams = rison.encode_uri({ filters, page }); + try { + // eslint-disable-next-line no-await-in-loop + const response = await SupersetClient.get({ + endpoint: `/api/v1/dataset/?q=${queryParams}`, + }); + + // Reassign local count to response's count + ({ count } = response.json); + + const { + json: { result }, + } = response; + + results = [...results, ...result]; + + page += 1; + } catch (error) { + addDangerToast(t('There was an error fetching dataset')); + logging.error(t('There was an error fetching dataset'), error); + } + } + + setDatasets(results); + }, []); + + useEffect(() => { + const filters = [ + { col: 'database', opr: 'rel_o_m', value: db?.id }, + { col: 'schema', opr: 'eq', value: encodedSchema }, + { col: 'sql', opr: 'dataset_is_null_or_empty', value: true }, + ]; + + if (schema) { + getDatasetsList(filters); + } + }, [db?.id, schema, encodedSchema, getDatasetsList]); + + const datasetNames = datasets?.map(dataset => dataset.table_name); + + return { datasets, datasetNames }; +}; + +export const useGetDatasetRelatedCounts = (id: string) => { + const [usageCount, setUsageCount] = useState(0); + + const getDatasetRelatedObjects = useCallback( + () => + SupersetClient.get({ + endpoint: `/api/v1/dataset/${id}/related_objects`, + }) + .then(({ json }) => { + setUsageCount(json?.charts.count); + }) + .catch(error => { + addDangerToast( + t(`There was an error fetching dataset's related objects`), + ); + logging.error(error); + }), + [id], + ); + + useEffect(() => { + // Todo: this useEffect should be used to call all count methods conncurently + // when we populate data for the new tabs. For right separating out this + // api call for building the usage page. + if (id) { + getDatasetRelatedObjects(); + } + }, [id, getDatasetRelatedObjects]); + + return { usageCount }; +}; diff --git a/superset-frontend/src/views/CRUD/data/query/QueryList.test.tsx b/superset-frontend/src/views/CRUD/data/query/QueryList.test.tsx index 83ecc588b2d1f..be28d7e2dfa85 100644 --- a/superset-frontend/src/views/CRUD/data/query/QueryList.test.tsx +++ b/superset-frontend/src/views/CRUD/data/query/QueryList.test.tsx @@ -32,6 +32,8 @@ import { QueryObject } from 'src/views/CRUD/types'; import ListView from 'src/components/ListView'; import Filters from 'src/components/ListView/Filters'; import SyntaxHighlighter from 'react-syntax-highlighter/dist/cjs/light'; +import SubMenu from 'src/views/components/SubMenu'; +import { QueryState } from '@superset-ui/core'; // store needed for withToasts const mockStore = configureStore([thunk]); @@ -53,7 +55,7 @@ const mockQueries: QueryObject[] = [...new Array(3)].map((_, i) => ({ { schema: 'foo', table: 'table' }, { schema: 'bar', table: 'table_2' }, ], - status: 'success', + status: QueryState.SUCCESS, tab_name: 'Main Tab', user: { first_name: 'cool', @@ -147,4 +149,26 @@ describe('QueryList', () => { `"http://localhost/api/v1/query/?q=(filters:!((col:sql,opr:ct,value:fooo)),order_column:start_time,order_direction:desc,page:0,page_size:25)"`, ); }); + + it('renders a SubMenu', () => { + expect(wrapper.find(SubMenu)).toExist(); + }); + + it('renders a SubMenu with Saved queries and Query History links', () => { + expect(wrapper.find(SubMenu).props().tabs).toEqual( + expect.arrayContaining([ + expect.objectContaining({ label: 'Saved queries' }), + expect.objectContaining({ label: 'Query history' }), + ]), + ); + }); + + it('renders a SubMenu without Databases and Datasets links', () => { + expect(wrapper.find(SubMenu).props().tabs).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ label: 'Databases' }), + expect.objectContaining({ label: 'Datasets' }), + ]), + ); + }); }); diff --git a/superset-frontend/src/views/CRUD/data/query/QueryList.tsx b/superset-frontend/src/views/CRUD/data/query/QueryList.tsx index 6ab71b8d43671..ff7a268f20b97 100644 --- a/superset-frontend/src/views/CRUD/data/query/QueryList.tsx +++ b/superset-frontend/src/views/CRUD/data/query/QueryList.tsx @@ -17,7 +17,13 @@ * under the License. */ import React, { useMemo, useState, useCallback, ReactElement } from 'react'; -import { SupersetClient, t, styled, useTheme } from '@superset-ui/core'; +import { + QueryState, + styled, + SupersetClient, + t, + useTheme, +} from '@superset-ui/core'; import moment from 'moment'; import { createFetchRelated, @@ -127,7 +133,13 @@ function QueryList({ addDangerToast }: QueryListProps) { row: { original: { status }, }, - }: any) => { + }: { + row: { + original: { + status: QueryState; + }; + }; + }) => { const statusConfig: { name: ReactElement | null; label: string; @@ -135,33 +147,39 @@ function QueryList({ addDangerToast }: QueryListProps) { name: null, label: '', }; - if (status === 'success') { + if (status === QueryState.SUCCESS) { statusConfig.name = ( <Icons.Check iconColor={theme.colors.success.base} /> ); statusConfig.label = t('Success'); - } else if (status === 'failed' || status === 'stopped') { + } else if ( + status === QueryState.FAILED || + status === QueryState.STOPPED + ) { statusConfig.name = ( <Icons.XSmall iconColor={ - status === 'failed' + status === QueryState.FAILED ? theme.colors.error.base : theme.colors.grayscale.base } /> ); statusConfig.label = t('Failed'); - } else if (status === 'running') { + } else if (status === QueryState.RUNNING) { statusConfig.name = ( <Icons.Running iconColor={theme.colors.primary.base} /> ); statusConfig.label = t('Running'); - } else if (status === 'timed_out') { + } else if (status === QueryState.TIMED_OUT) { statusConfig.name = ( <Icons.Offline iconColor={theme.colors.grayscale.light1} /> ); statusConfig.label = t('Offline'); - } else if (status === 'scheduled' || status === 'pending') { + } else if ( + status === QueryState.SCHEDULED || + status === QueryState.PENDING + ) { statusConfig.name = ( <Icons.Queued iconColor={theme.colors.grayscale.base} /> ); @@ -329,10 +347,11 @@ function QueryList({ addDangerToast }: QueryListProps) { () => [ { Header: t('Database'), + key: 'database', id: 'database', input: 'select', operator: FilterOperator.relationOneMany, - unfilteredLabel: 'All', + unfilteredLabel: t('All'), fetchSelects: createFetchRelated( 'query', 'database', @@ -346,6 +365,7 @@ function QueryList({ addDangerToast }: QueryListProps) { }, { Header: t('State'), + key: 'state', id: 'status', input: 'select', operator: FilterOperator.equals, @@ -363,6 +383,7 @@ function QueryList({ addDangerToast }: QueryListProps) { }, { Header: t('User'), + key: 'user', id: 'user', input: 'select', operator: FilterOperator.relationOneMany, @@ -380,12 +401,14 @@ function QueryList({ addDangerToast }: QueryListProps) { }, { Header: t('Time range'), + key: 'start_time', id: 'start_time', input: 'datetime_range', operator: FilterOperator.between, }, { Header: t('Search by query text'), + key: 'sql', id: 'sql', input: 'search', operator: FilterOperator.contains, diff --git a/superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.test.tsx b/superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.test.tsx index 7a85e4c292123..96498f6e69a65 100644 --- a/superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.test.tsx +++ b/superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.test.tsx @@ -27,6 +27,7 @@ import QueryPreviewModal from 'src/views/CRUD/data/query/QueryPreviewModal'; import { QueryObject } from 'src/views/CRUD/types'; import SyntaxHighlighter from 'react-syntax-highlighter/dist/cjs/light'; import { act } from 'react-dom/test-utils'; +import { QueryState } from '@superset-ui/core'; // store needed for withToasts const mockStore = configureStore([thunk]); @@ -46,7 +47,7 @@ const mockQueries: QueryObject[] = [...new Array(3)].map((_, i) => ({ { schema: 'foo', table: 'table' }, { schema: 'bar', table: 'table_2' }, ], - status: 'success', + status: QueryState.SUCCESS, tab_name: 'Main Tab', user: { first_name: 'cool', diff --git a/superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx b/superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx index 694b490557001..e8d7b5e201e9d 100644 --- a/superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx +++ b/superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx @@ -115,32 +115,34 @@ function QueryPreviewModal({ onHide={onHide} show={show} title={t('Query preview')} - footer={[ - <Button - data-test="previous-query" - key="previous-query" - disabled={disablePrevious} - onClick={() => handleDataChange(true)} - > - {t('Previous')} - </Button>, - <Button - data-test="next-query" - key="next-query" - disabled={disableNext} - onClick={() => handleDataChange(false)} - > - {t('Next')} - </Button>, - <Button - data-test="open-in-sql-lab" - key="open-in-sql-lab" - buttonStyle="primary" - onClick={() => openInSqlLab(id)} - > - {t('Open in SQL Lab')} - </Button>, - ]} + footer={ + <> + <Button + data-test="previous-query" + key="previous-query" + disabled={disablePrevious} + onClick={() => handleDataChange(true)} + > + {t('Previous')} + </Button> + <Button + data-test="next-query" + key="next-query" + disabled={disableNext} + onClick={() => handleDataChange(false)} + > + {t('Next')} + </Button> + <Button + data-test="open-in-sql-lab" + key="open-in-sql-lab" + buttonStyle="primary" + onClick={() => openInSqlLab(id)} + > + {t('Open in SQL Lab')} + </Button> + </> + } > <QueryTitle>{t('Tab name')}</QueryTitle> <QueryLabel>{query.tab_name}</QueryLabel> diff --git a/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.test.jsx b/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.test.jsx index 456fe2f394f5e..afa0fcd6aeacf 100644 --- a/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.test.jsx +++ b/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.test.jsx @@ -18,6 +18,7 @@ */ import React from 'react'; import thunk from 'redux-thunk'; +import { BrowserRouter } from 'react-router-dom'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-redux'; import fetchMock from 'fetch-mock'; @@ -153,6 +154,24 @@ describe('SavedQueryList', () => { expect(wrapper.find(SubMenu)).toExist(); }); + it('renders a SubMenu with Saved queries and Query History links', () => { + expect(wrapper.find(SubMenu).props().tabs).toEqual( + expect.arrayContaining([ + expect.objectContaining({ label: 'Saved queries' }), + expect.objectContaining({ label: 'Query history' }), + ]), + ); + }); + + it('renders a SubMenu without Databases and Datasets links', () => { + expect(wrapper.find(SubMenu).props().tabs).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ label: 'Databases' }), + expect.objectContaining({ label: 'Datasets' }), + ]), + ); + }); + it('renders a ListView', () => { expect(wrapper.find(ListView)).toExist(); }); @@ -227,9 +246,11 @@ describe('RTL', () => { async function renderAndWait() { const mounted = act(async () => { render( - <QueryParamProvider> - <SavedQueryList /> - </QueryParamProvider>, + <BrowserRouter> + <QueryParamProvider> + <SavedQueryList /> + </QueryParamProvider> + </BrowserRouter>, { useRedux: true }, ); }); diff --git a/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx b/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx index f3d58fe52cce8..291063aa88b1a 100644 --- a/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx +++ b/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx @@ -50,6 +50,7 @@ import copyTextToClipboard from 'src/utils/copy'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import ImportModelsModal from 'src/components/ImportModal/index'; import Icons from 'src/components/Icons'; +import { BootstrapUser } from 'src/types/bootstrapTypes'; import SavedQueryPreviewModal from './SavedQueryPreviewModal'; const PAGE_SIZE = 25; @@ -69,9 +70,7 @@ const CONFIRM_OVERWRITE_MESSAGE = t( interface SavedQueryListProps { addDangerToast: (msg: string) => void; addSuccessToast: (msg: string) => void; - user: { - userId: string | number; - }; + user: BootstrapUser; } const StyledTableLabel = styled.div` @@ -424,10 +423,11 @@ function SavedQueryList({ () => [ { Header: t('Database'), + key: 'database', id: 'database', input: 'select', operator: FilterOperator.relationOneMany, - unfilteredLabel: 'All', + unfilteredLabel: t('All'), fetchSelects: createFetchRelated( 'saved_query', 'database', @@ -445,6 +445,7 @@ function SavedQueryList({ { Header: t('Schema'), id: 'schema', + key: 'schema', input: 'select', operator: FilterOperator.equals, unfilteredLabel: 'All', @@ -462,6 +463,7 @@ function SavedQueryList({ { Header: t('Search'), id: 'label', + key: 'search', input: 'search', operator: FilterOperator.allText, }, diff --git a/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx b/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx index e8250d0fb7f80..29efb634a49e4 100644 --- a/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx +++ b/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx @@ -95,32 +95,34 @@ const SavedQueryPreviewModal: FunctionComponent<SavedQueryPreviewModalProps> = onHide={onHide} show={show} title={t('Query preview')} - footer={[ - <Button - data-test="previous-saved-query" - key="previous-saved-query" - disabled={disablePrevious} - onClick={() => handleDataChange(true)} - > - {t('Previous')} - </Button>, - <Button - data-test="next-saved-query" - key="next-saved-query" - disabled={disableNext} - onClick={() => handleDataChange(false)} - > - {t('Next')} - </Button>, - <Button - data-test="open-in-sql-lab" - key="open-in-sql-lab" - buttonStyle="primary" - onClick={() => openInSqlLab(savedQuery.id)} - > - {t('Open in SQL Lab')} - </Button>, - ]} + footer={ + <> + <Button + data-test="previous-saved-query" + key="previous-saved-query" + disabled={disablePrevious} + onClick={() => handleDataChange(true)} + > + {t('Previous')} + </Button> + <Button + data-test="next-saved-query" + key="next-saved-query" + disabled={disableNext} + onClick={() => handleDataChange(false)} + > + {t('Next')} + </Button> + <Button + data-test="open-in-sql-lab" + key="open-in-sql-lab" + buttonStyle="primary" + onClick={() => openInSqlLab(savedQuery.id)} + > + {t('Open in SQL Lab')} + </Button> + </> + } > <QueryTitle>{t('Query name')}</QueryTitle> <QueryLabel>{savedQuery.label}</QueryLabel> diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index 1bb0a06dc6d9e..80a6c4793bbed 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -420,6 +420,10 @@ export function useImportResource( const formData = new FormData(); formData.append('formData', bundle); + const RE_EXPORT_TEXT = t( + 'Please re-export your file and try importing again', + ); + /* The import bundle never contains database passwords; if required * they should be provided by the user during import. */ @@ -468,8 +472,8 @@ export function useImportResource( resourceLabel, [ ...error.errors.map(payload => payload.message), - t('Please re-export your file and try importing again'), - ].join('\n'), + RE_EXPORT_TEXT, + ].join('.\n'), ), ); } else { @@ -641,7 +645,7 @@ export const testDatabaseConnection = ( addSuccessToast: (arg0: string) => void, ) => { SupersetClient.post({ - endpoint: 'api/v1/database/test_connection', + endpoint: 'api/v1/database/test_connection/', body: JSON.stringify(connection), headers: { 'Content-Type': 'application/json' }, }).then( @@ -668,6 +672,21 @@ export function useAvailableDatabases() { return [availableDbs, getAvailable] as const; } +const transformDB = (db: Partial<DatabaseObject> | null) => { + if (db && Array.isArray(db?.catalog)) { + return { + ...db, + catalog: Object.assign( + {}, + ...db.catalog.map((x: { name: string; value: string }) => ({ + [x.name]: x.value, + })), + ), + }; + } + return db; +}; + export function useDatabaseValidation() { const [validationErrors, setValidationErrors] = useState<JsonObject | null>( null, @@ -675,8 +694,8 @@ export function useDatabaseValidation() { const getValidation = useCallback( (database: Partial<DatabaseObject> | null, onCreate = false) => SupersetClient.post({ - endpoint: '/api/v1/database/validate_parameters', - body: JSON.stringify(database), + endpoint: '/api/v1/database/validate_parameters/', + body: JSON.stringify(transformDB(database)), headers: { 'Content-Type': 'application/json' }, }) .then(() => { diff --git a/superset-frontend/src/views/CRUD/types.ts b/superset-frontend/src/views/CRUD/types.ts index 0090697747ac5..7dd5d74f13391 100644 --- a/superset-frontend/src/views/CRUD/types.ts +++ b/superset-frontend/src/views/CRUD/types.ts @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import { QueryState } from '@superset-ui/core'; import { User } from 'src/types/bootstrapTypes'; import Database from 'src/types/Database'; import Owner from 'src/types/Owner'; @@ -24,13 +25,16 @@ export type FavoriteStatus = { [id: number]: boolean; }; -export enum TableTabTypes { - FAVORITE = 'Favorite', - MINE = 'Mine', - EXAMPLES = 'Examples', +export enum TableTab { + Favorite = 'Favorite', + Mine = 'Mine', + Other = 'Other', + Viewed = 'Viewed', + Created = 'Created', + Edited = 'Edited', } -export type Filters = { +export type Filter = { col: string; opr: string; value: string | number; @@ -39,12 +43,12 @@ export type Filters = { export interface DashboardTableProps { addDangerToast: (message: string) => void; addSuccessToast: (message: string) => void; - search: string; user?: User; mine: Array<Dashboard>; showThumbnails?: boolean; - featureFlag?: boolean; - examples: Array<Dashboard>; + otherTabData: Array<Dashboard>; + otherTabFilters: Filter[]; + otherTabTitle: string; } export interface Dashboard { @@ -91,14 +95,7 @@ export interface QueryObject { sql: string; executed_sql: string | null; sql_tables?: { catalog?: string; schema: string; table: string }[]; - status: - | 'success' - | 'failed' - | 'stopped' - | 'running' - | 'timed_out' - | 'scheduled' - | 'pending'; + status: QueryState; tab_name: string; user: { first_name: string; @@ -120,7 +117,7 @@ export enum QueryObjectColumns { database_name = 'database.database_name', schema = 'schema', sql = 'sql', - executed_sql = 'exceuted_sql', + executed_sql = 'executed_sql', sql_tables = 'sql_tables', status = 'status', tab_name = 'tab_name', diff --git a/superset-frontend/src/views/CRUD/utils.test.tsx b/superset-frontend/src/views/CRUD/utils.test.tsx index e727a0c896bdb..fa41455d8508b 100644 --- a/superset-frontend/src/views/CRUD/utils.test.tsx +++ b/superset-frontend/src/views/CRUD/utils.test.tsx @@ -18,13 +18,17 @@ */ import rison from 'rison'; import { - isNeedsPassword, - isAlreadyExists, - getPasswordsNeeded, + checkUploadExtensions, getAlreadyExists, + getFilterValues, + getPasswordsNeeded, hasTerminalValidation, - checkUploadExtensions, + isAlreadyExists, + isNeedsPassword, } from 'src/views/CRUD/utils'; +import { User } from 'src/types/bootstrapTypes'; +import { Filter, TableTab } from './types'; +import { WelcomeTable } from './welcome/types'; const terminalErrors = { errors: [ @@ -228,3 +232,165 @@ test('checkUploadExtensions should return valid upload extensions', () => { checkUploadExtensions(randomExtensionThree, uploadExtensionTest), ).toBeFalsy(); }); + +test('getFilterValues', () => { + const userId = 1234; + const mockUser: User = { + firstName: 'foo', + lastName: 'bar', + username: 'baz', + userId, + isActive: true, + isAnonymous: false, + }; + const testCases: [ + TableTab, + WelcomeTable, + User | undefined, + Filter[] | undefined, + ReturnType<typeof getFilterValues>, + ][] = [ + [ + TableTab.Mine, + WelcomeTable.SavedQueries, + mockUser, + undefined, + [ + { + id: 'created_by', + operator: 'rel_o_m', + value: `${userId}`, + }, + ], + ], + [ + TableTab.Favorite, + WelcomeTable.SavedQueries, + mockUser, + undefined, + [ + { + id: 'id', + operator: 'saved_query_is_fav', + value: true, + }, + ], + ], + [ + TableTab.Created, + WelcomeTable.Charts, + mockUser, + undefined, + [ + { + id: 'created_by', + operator: 'rel_o_m', + value: `${userId}`, + }, + ], + ], + [ + TableTab.Created, + WelcomeTable.Dashboards, + mockUser, + undefined, + [ + { + id: 'created_by', + operator: 'rel_o_m', + value: `${userId}`, + }, + ], + ], + [ + TableTab.Created, + WelcomeTable.Recents, + mockUser, + undefined, + [ + { + id: 'created_by', + operator: 'rel_o_m', + value: `${userId}`, + }, + ], + ], + [ + TableTab.Mine, + WelcomeTable.Charts, + mockUser, + undefined, + [ + { + id: 'owners', + operator: 'rel_m_m', + value: `${userId}`, + }, + ], + ], + [ + TableTab.Mine, + WelcomeTable.Dashboards, + mockUser, + undefined, + [ + { + id: 'owners', + operator: 'rel_m_m', + value: `${userId}`, + }, + ], + ], + [ + TableTab.Favorite, + WelcomeTable.Dashboards, + mockUser, + undefined, + [ + { + id: 'id', + operator: 'dashboard_is_favorite', + value: true, + }, + ], + ], + [ + TableTab.Favorite, + WelcomeTable.Charts, + mockUser, + undefined, + [ + { + id: 'id', + operator: 'chart_is_favorite', + value: true, + }, + ], + ], + [ + TableTab.Other, + WelcomeTable.Charts, + mockUser, + [ + { + col: 'created_by', + opr: 'rel_o_m', + value: 0, + }, + ], + [ + { + id: 'created_by', + operator: 'rel_o_m', + value: 0, + }, + ], + ], + ]; + testCases.forEach(testCase => { + const [tab, welcomeTable, user, otherTabFilters, expectedValue] = testCase; + expect(getFilterValues(tab, welcomeTable, user, otherTabFilters)).toEqual( + expectedValue, + ); + }); +}); diff --git a/superset-frontend/src/views/CRUD/utils.tsx b/superset-frontend/src/views/CRUD/utils.tsx index a0004a844b7d3..4b839739d47cc 100644 --- a/superset-frontend/src/views/CRUD/utils.tsx +++ b/superset-frontend/src/views/CRUD/utils.tsx @@ -18,22 +18,24 @@ */ import { - t, - SupersetClient, - SupersetClientResponse, + css, logging, styled, + SupersetClient, + SupersetClientResponse, SupersetTheme, - css, + t, } from '@superset-ui/core'; import Chart from 'src/types/Chart'; import { intersection } from 'lodash'; import rison from 'rison'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; -import { FetchDataConfig } from 'src/components/ListView'; +import { FetchDataConfig, FilterValue } from 'src/components/ListView'; import SupersetText from 'src/utils/textUtils'; -import findPermission from 'src/dashboard/util/findPermission'; -import { Dashboard, Filters } from './types'; +import { findPermission } from 'src/utils/findPermission'; +import { User } from 'src/types/bootstrapTypes'; +import { Dashboard, Filter, TableTab } from './types'; +import { WelcomeTable } from './welcome/types'; // Modifies the rison encoding slightly to match the backend's rison encoding/decoding. Applies globally. // Code pulled from rison.js (https://github.com/Nanonid/rison), rison is licensed under the MIT license. @@ -92,8 +94,9 @@ const createFetchResourceMethod = : undefined; const data: { label: string; value: string | number }[] = []; - json?.result?.forEach( - ({ text, value }: { text: string; value: string | number }) => { + json?.result + ?.filter(({ text }: { text: string }) => text.trim().length > 0) + .forEach(({ text, value }: { text: string; value: string | number }) => { if ( loggedUser && value === loggedUser.value && @@ -106,8 +109,7 @@ const createFetchResourceMethod = value, }); } - }, - ); + }); if (loggedUser && (!filterValue || fetchedLoggedUser)) { data.unshift(loggedUser); @@ -120,7 +122,7 @@ const createFetchResourceMethod = }; export const PAGE_SIZE = 5; -const getParams = (filters?: Array<Filters>) => { +const getParams = (filters?: Filter[]) => { const params = { order_column: 'changed_on_delta_humanized', order_direction: 'desc', @@ -164,7 +166,7 @@ export const getEditedObjects = (userId: string | number) => { export const getUserOwnedObjects = ( userId: string | number, resource: string, - filters: Array<Filters> = [ + filters: Filter[] = [ { col: 'owners', opr: 'rel_m_m', @@ -176,20 +178,14 @@ export const getUserOwnedObjects = ( endpoint: `/api/v1/${resource}/?q=${getParams(filters)}`, }).then(res => res.json?.result); -export const getRecentAcitivtyObjs = ( +export const getRecentActivityObjs = ( userId: string | number, recent: string, addDangerToast: (arg1: string, arg2: any) => any, + filters: Filter[], ) => SupersetClient.get({ endpoint: recent }).then(recentsRes => { const res: any = {}; - const filters = [ - { - col: 'created_by', - opr: 'rel_o_m', - value: 0, - }, - ]; const newBatch = [ SupersetClient.get({ endpoint: `/api/v1/chart/?q=${getParams(filters)}`, @@ -200,8 +196,8 @@ export const getRecentAcitivtyObjs = ( ]; return Promise.all(newBatch) .then(([chartRes, dashboardRes]) => { - res.examples = [...chartRes.json.result, ...dashboardRes.json.result]; - res.viewed = recentsRes.json; + res.other = [...chartRes.json.result, ...dashboardRes.json.result]; + res.viewed = recentsRes.json.result; return res; }) .catch(errMsg => @@ -227,10 +223,8 @@ export function createErrorHandler( const errorsArray = parsedError?.errors; const config = await SupersetText; if ( - errorsArray && - errorsArray.length && - config && - config.ERRORS && + errorsArray?.length && + config?.ERRORS && errorsArray[0].error_type in config.ERRORS ) { parsedError.message = config.ERRORS[errorsArray[0].error_type]; @@ -444,3 +438,64 @@ export const uploadUserPerms = ( canUploadData: canUploadCSV || canUploadColumnar || canUploadExcel, }; }; + +export function getFilterValues( + tab: TableTab, + welcomeTable: WelcomeTable, + user?: User, + otherTabFilters?: Filter[], +): FilterValue[] { + if ( + tab === TableTab.Created || + (welcomeTable === WelcomeTable.SavedQueries && tab === TableTab.Mine) + ) { + return [ + { + id: 'created_by', + operator: 'rel_o_m', + value: `${user?.userId}`, + }, + ]; + } + if (welcomeTable === WelcomeTable.SavedQueries && tab === TableTab.Favorite) { + return [ + { + id: 'id', + operator: 'saved_query_is_fav', + value: true, + }, + ]; + } + if (tab === TableTab.Mine && user) { + return [ + { + id: 'owners', + operator: 'rel_m_m', + value: `${user.userId}`, + }, + ]; + } + if ( + tab === TableTab.Favorite && + [WelcomeTable.Dashboards, WelcomeTable.Charts].includes(welcomeTable) + ) { + return [ + { + id: 'id', + operator: + welcomeTable === WelcomeTable.Dashboards + ? 'dashboard_is_favorite' + : 'chart_is_favorite', + value: true, + }, + ]; + } + if (tab === TableTab.Other) { + return (otherTabFilters || []).map(flt => ({ + id: flt.col, + operator: flt.opr, + value: flt.value, + })); + } + return []; +} diff --git a/superset-frontend/src/views/CRUD/welcome/ActivityTable.test.tsx b/superset-frontend/src/views/CRUD/welcome/ActivityTable.test.tsx index 71067b817a3e2..66d521f362b05 100644 --- a/superset-frontend/src/views/CRUD/welcome/ActivityTable.test.tsx +++ b/superset-frontend/src/views/CRUD/welcome/ActivityTable.test.tsx @@ -25,6 +25,7 @@ import fetchMock from 'fetch-mock'; import thunk from 'redux-thunk'; import configureStore from 'redux-mock-store'; import ActivityTable from 'src/views/CRUD/welcome/ActivityTable'; +import { TableTab } from 'src/views/CRUD/types'; const mockStore = configureStore([thunk]); const store = mockStore({}); @@ -33,7 +34,7 @@ const chartsEndpoint = 'glob:*/api/v1/chart/?*'; const dashboardsEndpoint = 'glob:*/api/v1/dashboard/?*'; const mockData = { - Viewed: [ + [TableTab.Viewed]: [ { slice_name: 'ChartyChart', changed_on_utc: '24 Feb 2014 10:13:14', @@ -42,7 +43,7 @@ const mockData = { table: {}, }, ], - Created: [ + [TableTab.Created]: [ { dashboard_title: 'Dashboard_Test', changed_on_utc: '24 Feb 2014 10:13:14', @@ -77,11 +78,11 @@ fetchMock.get(dashboardsEndpoint, { describe('ActivityTable', () => { const activityProps = { - activeChild: 'Created', + activeChild: TableTab.Created, activityData: mockData, setActiveChild: jest.fn(), user: { userId: '1' }, - loadedCount: 3, + isFetchingActivityData: false, }; let wrapper: ReactWrapper; @@ -122,11 +123,11 @@ describe('ActivityTable', () => { }); it('show empty state if there is no data', () => { const activityProps = { - activeChild: 'Created', + activeChild: TableTab.Created, activityData: {}, setActiveChild: jest.fn(), user: { userId: '1' }, - loadedCount: 3, + isFetchingActivityData: false, }; const wrapper = mount( <Provider store={store}> diff --git a/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx b/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx index 540c033419009..11a3e9afdb83c 100644 --- a/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx +++ b/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx @@ -20,9 +20,10 @@ import React, { useEffect, useState } from 'react'; import moment from 'moment'; import { styled, t } from '@superset-ui/core'; import { setItem, LocalStorageKeys } from 'src/utils/localStorageHelpers'; - +import { Link } from 'react-router-dom'; import ListViewCard from 'src/components/ListViewCard'; import SubMenu from 'src/views/components/SubMenu'; +import { Dashboard, SavedQueryObject, TableTab } from 'src/views/CRUD/types'; import { ActivityData, LoadingCards } from 'src/views/CRUD/welcome/Welcome'; import { CardContainer, @@ -30,7 +31,6 @@ import { getEditedObjects, } from 'src/views/CRUD/utils'; import { Chart } from 'src/types/Chart'; -import { Dashboard, SavedQueryObject } from 'src/views/CRUD/types'; import Icons from 'src/components/Icons'; @@ -38,7 +38,7 @@ import EmptyState from './EmptyState'; import { WelcomeTable } from './types'; /** - * Return result from /superset/recent_activity/{user_id} + * Return result from /api/v1/log/recent_activity/{user_id}/ */ interface RecentActivity { action: string; @@ -57,14 +57,8 @@ interface RecentDashboard extends RecentActivity { item_type: 'dashboard'; } -export enum SetTabType { - EDITED = 'Edited', - CREATED = 'Created', - VIEWED = 'Viewed', - EXAMPLE = 'Examples', -} /** - * Recent activity objects fetched by `getRecentAcitivtyObjs`. + * Recent activity objects fetched by `getRecentActivityObjs`. */ type ActivityObject = | RecentSlice @@ -80,7 +74,7 @@ interface ActivityProps { activeChild: string; setActiveChild: (arg0: string) => void; activityData: ActivityData; - loadedCount: number; + isFetchingActivityData: boolean; } const Styles = styled.div` @@ -134,67 +128,64 @@ export default function ActivityTable({ setActiveChild, activityData, user, - loadedCount, + isFetchingActivityData, }: ActivityProps) { - const [editedObjs, setEditedObjs] = useState<Array<ActivityData>>(); - const [loadingState, setLoadingState] = useState(false); + const [editedCards, setEditedCards] = useState<ActivityData[]>(); + const [isFetchingEditedCards, setIsFetchingEditedCards] = useState(false); const getEditedCards = () => { - setLoadingState(true); + setIsFetchingEditedCards(true); getEditedObjects(user.userId).then(r => { - setEditedObjs([...r.editedChart, ...r.editedDash]); - setLoadingState(false); + setEditedCards([...r.editedChart, ...r.editedDash]); + setIsFetchingEditedCards(false); }); }; useEffect(() => { - if (activeChild === 'Edited') { - setLoadingState(true); + if (activeChild === TableTab.Edited) { getEditedCards(); } }, [activeChild]); const tabs = [ { - name: 'Edited', + name: TableTab.Edited, label: t('Edited'), onClick: () => { - setActiveChild('Edited'); - setItem(LocalStorageKeys.homepage_activity_filter, SetTabType.EDITED); + setActiveChild(TableTab.Edited); + setItem(LocalStorageKeys.homepage_activity_filter, TableTab.Edited); }, }, { - name: 'Created', + name: TableTab.Created, label: t('Created'), onClick: () => { - setActiveChild('Created'); - setItem(LocalStorageKeys.homepage_activity_filter, SetTabType.CREATED); + setActiveChild(TableTab.Created); + setItem(LocalStorageKeys.homepage_activity_filter, TableTab.Created); }, }, ]; - if (activityData?.Viewed) { + if (activityData?.[TableTab.Viewed]) { tabs.unshift({ - name: 'Viewed', + name: TableTab.Viewed, label: t('Viewed'), onClick: () => { - setActiveChild('Viewed'); - setItem(LocalStorageKeys.homepage_activity_filter, SetTabType.VIEWED); + setActiveChild(TableTab.Viewed); + setItem(LocalStorageKeys.homepage_activity_filter, TableTab.Viewed); }, }); } const renderActivity = () => - (activeChild !== 'Edited' ? activityData[activeChild] : editedObjs).map( - (entity: ActivityObject) => { - const url = getEntityUrl(entity); - const lastActionOn = getEntityLastActionOn(entity); - return ( - <CardStyles - onClick={() => { - window.location.href = url; - }} - key={url} - > + (activeChild === TableTab.Edited + ? editedCards + : activityData[activeChild] + ).map((entity: ActivityObject) => { + const url = getEntityUrl(entity); + const lastActionOn = getEntityLastActionOn(entity); + return ( + <CardStyles key={url}> + <Link to={url}> <ListViewCard cover={<></>} url={url} @@ -203,21 +194,19 @@ export default function ActivityTable({ avatar={getEntityIcon(entity)} actions={null} /> - </CardStyles> - ); - }, - ); - - const doneFetching = loadedCount < 3; + </Link> + </CardStyles> + ); + }); - if ((loadingState && !editedObjs) || doneFetching) { + if ((isFetchingEditedCards && !editedCards) || isFetchingActivityData) { return <LoadingCards />; } return ( <Styles> <SubMenu activeChild={activeChild} tabs={tabs} /> {activityData[activeChild]?.length > 0 || - (activeChild === 'Edited' && editedObjs && editedObjs.length > 0) ? ( + (activeChild === TableTab.Edited && editedCards?.length) ? ( <CardContainer className="recentCards"> {renderActivity()} </CardContainer> diff --git a/superset-frontend/src/views/CRUD/welcome/ChartTable.test.tsx b/superset-frontend/src/views/CRUD/welcome/ChartTable.test.tsx index cfa9230328c08..45e3483026cc9 100644 --- a/superset-frontend/src/views/CRUD/welcome/ChartTable.test.tsx +++ b/superset-frontend/src/views/CRUD/welcome/ChartTable.test.tsx @@ -62,6 +62,11 @@ describe('ChartTable', () => { user: { userId: '2', }, + mine: [], + otherTabData: [], + otherTabFilters: [], + otherTabTitle: 'Other', + showThumbnails: false, }; let wrapper: ReactWrapper; @@ -89,13 +94,35 @@ describe('ChartTable', () => { expect(wrapper.find('ChartCard')).toExist(); }); + it('renders other tab by default', async () => { + await act(async () => { + wrapper = mount( + <ChartTable + user={{ userId: '2' }} + mine={[]} + otherTabData={mockCharts} + otherTabFilters={[]} + otherTabTitle="Other" + showThumbnails={false} + store={store} + />, + ); + }); + await waitForComponentToPaint(wrapper); + expect(wrapper.find('EmptyState')).not.toExist(); + expect(wrapper.find('ChartCard')).toExist(); + }); + it('display EmptyState if there is no data', async () => { await act(async () => { wrapper = mount( <ChartTable - chartFilter="Mine" user={{ userId: '2' }} mine={[]} + otherTabData={[]} + otherTabFilters={[]} + otherTabTitle="Other" + showThumbnails={false} store={store} />, ); diff --git a/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx b/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx index 41c25033df61c..52548e30b0c03 100644 --- a/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx +++ b/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx @@ -26,17 +26,21 @@ import { } from 'src/views/CRUD/hooks'; import { getItem, - setItem, LocalStorageKeys, + setItem, } from 'src/utils/localStorageHelpers'; import withToasts from 'src/components/MessageToasts/withToasts'; import { useHistory } from 'react-router-dom'; -import { TableTabTypes } from 'src/views/CRUD/types'; +import { Filter, TableTab } from 'src/views/CRUD/types'; import PropertiesModal from 'src/explore/components/PropertiesModal'; import { User } from 'src/types/bootstrapTypes'; -import { CardContainer, PAGE_SIZE } from 'src/views/CRUD/utils'; +import { + CardContainer, + getFilterValues, + PAGE_SIZE, +} from 'src/views/CRUD/utils'; import { LoadingCards } from 'src/views/CRUD/welcome/Welcome'; -import ChartCard from 'src/views/CRUD/chart/ChartCard'; +import ChartCard from 'src/pages/ChartList/ChartCard'; import Chart from 'src/types/Chart'; import handleResourceExport from 'src/utils/export'; import Loading from 'src/components/Loading'; @@ -48,12 +52,12 @@ import { WelcomeTable } from './types'; interface ChartTableProps { addDangerToast: (message: string) => void; addSuccessToast: (message: string) => void; - search: string; - chartFilter?: string; user?: User; mine: Array<any>; showThumbnails: boolean; - examples?: Array<object>; + otherTabData?: Array<object>; + otherTabFilters: Filter[]; + otherTabTitle: string; } function ChartTable({ @@ -62,16 +66,17 @@ function ChartTable({ addSuccessToast, mine, showThumbnails, - examples, + otherTabData, + otherTabFilters, + otherTabTitle, }: ChartTableProps) { const history = useHistory(); - const filterStore = getItem( + const initialTab = getItem( LocalStorageKeys.homepage_chart_filter, - TableTabTypes.EXAMPLES, + TableTab.Other, ); - const initialFilter = filterStore; - const filteredExamples = filter(examples, obj => 'viz_type' in obj); + const filteredOtherTabData = filter(otherTabData, obj => 'viz_type' in obj); const { state: { loading, resourceCollection: charts, bulkSelectEnabled }, @@ -84,7 +89,7 @@ function ChartTable({ t('chart'), addDangerToast, true, - initialFilter === 'Mine' ? mine : filteredExamples, + initialTab === TableTab.Mine ? mine : filteredOtherTabData, [], false, ); @@ -102,36 +107,11 @@ function ChartTable({ closeChartEditModal, } = useChartEditModal(setCharts, charts); - const [chartFilter, setChartFilter] = useState(initialFilter); + const [activeTab, setActiveTab] = useState(initialTab); const [preparingExport, setPreparingExport] = useState<boolean>(false); const [loaded, setLoaded] = useState<boolean>(false); - const getFilters = (filterName: string) => { - const filters = []; - - if (filterName === 'Mine') { - filters.push({ - id: 'owners', - operator: 'rel_m_m', - value: `${user?.userId}`, - }); - } else if (filterName === 'Favorite') { - filters.push({ - id: 'id', - operator: 'chart_is_favorite', - value: true, - }); - } else if (filterName === 'Examples') { - filters.push({ - id: 'created_by', - operator: 'rel_o_m', - value: 0, - }); - } - return filters; - }; - - const getData = (filter: string) => + const getData = (tab: TableTab) => fetchData({ pageIndex: 0, pageSize: PAGE_SIZE, @@ -141,15 +121,15 @@ function ChartTable({ desc: true, }, ], - filters: getFilters(filter), + filters: getFilterValues(tab, WelcomeTable.Charts, user, otherTabFilters), }); useEffect(() => { - if (loaded || chartFilter === 'Favorite') { - getData(chartFilter); + if (loaded || activeTab === TableTab.Favorite) { + getData(activeTab); } setLoaded(true); - }, [chartFilter]); + }, [activeTab]); const handleBulkChartExport = (chartsToExport: Chart[]) => { const ids = chartsToExport.map(({ id }) => id); @@ -161,29 +141,29 @@ function ChartTable({ const menuTabs = [ { - name: 'Favorite', + name: TableTab.Favorite, label: t('Favorite'), onClick: () => { - setChartFilter(TableTabTypes.FAVORITE); - setItem(LocalStorageKeys.homepage_chart_filter, TableTabTypes.FAVORITE); + setActiveTab(TableTab.Favorite); + setItem(LocalStorageKeys.homepage_chart_filter, TableTab.Favorite); }, }, { - name: 'Mine', + name: TableTab.Mine, label: t('Mine'), onClick: () => { - setChartFilter(TableTabTypes.MINE); - setItem(LocalStorageKeys.homepage_chart_filter, TableTabTypes.MINE); + setActiveTab(TableTab.Mine); + setItem(LocalStorageKeys.homepage_chart_filter, TableTab.Mine); }, }, ]; - if (examples) { + if (otherTabData) { menuTabs.push({ - name: 'Examples', - label: t('Examples'), + name: TableTab.Other, + label: otherTabTitle, onClick: () => { - setChartFilter(TableTabTypes.EXAMPLES); - setItem(LocalStorageKeys.homepage_chart_filter, TableTabTypes.EXAMPLES); + setActiveTab(TableTab.Other); + setItem(LocalStorageKeys.homepage_chart_filter, TableTab.Other); }, }); } @@ -201,7 +181,7 @@ function ChartTable({ )} <SubMenu - activeChild={chartFilter} + activeChild={activeTab} tabs={menuTabs} buttons={[ { @@ -221,7 +201,7 @@ function ChartTable({ buttonStyle: 'link', onClick: () => { const target = - chartFilter === 'Favorite' + activeTab === TableTab.Favorite ? `/chart/list/?filters=(favorite:(label:${t( 'Yes', )},value:!t))` @@ -237,7 +217,7 @@ function ChartTable({ <ChartCard key={`${e.id}`} openChartEditModal={openChartEditModal} - chartFilter={chartFilter} + chartFilter={activeTab} chart={e} userId={user?.userId} hasPerm={hasPerm} @@ -253,7 +233,11 @@ function ChartTable({ ))} </CardContainer> ) : ( - <EmptyState tableName={WelcomeTable.Charts} tab={chartFilter} /> + <EmptyState + tableName={WelcomeTable.Charts} + tab={activeTab} + otherTabTitle={otherTabTitle} + /> )} {preparingExport && <Loading />} </ErrorBoundary> diff --git a/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx b/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx index a5078465fc6f8..e4a31bdf4f6de 100644 --- a/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx +++ b/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx @@ -20,54 +20,51 @@ import React, { useEffect, useMemo, useState } from 'react'; import { SupersetClient, t } from '@superset-ui/core'; import { filter } from 'lodash'; import { useFavoriteStatus, useListViewResource } from 'src/views/CRUD/hooks'; -import { - Dashboard, - DashboardTableProps, - TableTabTypes, -} from 'src/views/CRUD/types'; +import { Dashboard, DashboardTableProps, TableTab } from 'src/views/CRUD/types'; import handleResourceExport from 'src/utils/export'; import { useHistory } from 'react-router-dom'; import { getItem, - setItem, LocalStorageKeys, + setItem, } from 'src/utils/localStorageHelpers'; import { LoadingCards } from 'src/views/CRUD/welcome/Welcome'; import { CardContainer, createErrorHandler, + getFilterValues, PAGE_SIZE, + handleDashboardDelete, } from 'src/views/CRUD/utils'; import withToasts from 'src/components/MessageToasts/withToasts'; import Loading from 'src/components/Loading'; +import DeleteModal from 'src/components/DeleteModal'; import PropertiesModal from 'src/dashboard/components/PropertiesModal'; import DashboardCard from 'src/views/CRUD/dashboard/DashboardCard'; import SubMenu from 'src/views/components/SubMenu'; import EmptyState from './EmptyState'; import { WelcomeTable } from './types'; -export interface FilterValue { - col: string; - operator: string; - value: string | boolean | number | null | undefined; -} - function DashboardTable({ user, addDangerToast, addSuccessToast, mine, showThumbnails, - examples, + otherTabData, + otherTabFilters, + otherTabTitle, }: DashboardTableProps) { const history = useHistory(); - const filterStore = getItem( + const defaultTab = getItem( LocalStorageKeys.homepage_dashboard_filter, - TableTabTypes.EXAMPLES, + TableTab.Other, ); - const defaultFilter = filterStore; - const filteredExamples = filter(examples, obj => !('viz_type' in obj)); + const filteredOtherTabData = filter( + otherTabData, + obj => !('viz_type' in obj), + ); const { state: { loading, resourceCollection: dashboards }, @@ -80,7 +77,7 @@ function DashboardTable({ t('dashboard'), addDangerToast, true, - defaultFilter === 'Mine' ? mine : filteredExamples, + defaultTab === TableTab.Mine ? mine : filteredOtherTabData, [], false, ); @@ -92,35 +89,14 @@ function DashboardTable({ ); const [editModal, setEditModal] = useState<Dashboard>(); - const [dashboardFilter, setDashboardFilter] = useState(defaultFilter); + const [activeTab, setActiveTab] = useState(defaultTab); const [preparingExport, setPreparingExport] = useState<boolean>(false); const [loaded, setLoaded] = useState<boolean>(false); + const [dashboardToDelete, setDashboardToDelete] = useState<Dashboard | null>( + null, + ); - const getFilters = (filterName: string) => { - const filters = []; - if (filterName === 'Mine') { - filters.push({ - id: 'owners', - operator: 'rel_m_m', - value: `${user?.userId}`, - }); - } else if (filterName === 'Favorite') { - filters.push({ - id: 'id', - operator: 'dashboard_is_favorite', - value: true, - }); - } else if (filterName === 'Examples') { - filters.push({ - id: 'created_by', - operator: 'rel_o_m', - value: 0, - }); - } - return filters; - }; - - const getData = (filter: string) => + const getData = (tab: TableTab) => fetchData({ pageIndex: 0, pageSize: PAGE_SIZE, @@ -130,15 +106,20 @@ function DashboardTable({ desc: true, }, ], - filters: getFilters(filter), + filters: getFilterValues( + tab, + WelcomeTable.Dashboards, + user, + otherTabFilters, + ), }); useEffect(() => { - if (loaded || dashboardFilter === 'Favorite') { - getData(dashboardFilter); + if (loaded || activeTab === TableTab.Favorite) { + getData(activeTab); } setLoaded(true); - }, [dashboardFilter]); + }, [activeTab]); const handleBulkDashboardExport = (dashboardsToExport: Dashboard[]) => { const ids = dashboardsToExport.map(({ id }) => id); @@ -171,36 +152,30 @@ function DashboardTable({ const menuTabs = [ { - name: 'Favorite', + name: TableTab.Favorite, label: t('Favorite'), onClick: () => { - setDashboardFilter(TableTabTypes.FAVORITE); - setItem( - LocalStorageKeys.homepage_dashboard_filter, - TableTabTypes.FAVORITE, - ); + setActiveTab(TableTab.Favorite); + setItem(LocalStorageKeys.homepage_dashboard_filter, TableTab.Favorite); }, }, { - name: 'Mine', + name: TableTab.Mine, label: t('Mine'), onClick: () => { - setDashboardFilter(TableTabTypes.MINE); - setItem(LocalStorageKeys.homepage_dashboard_filter, TableTabTypes.MINE); + setActiveTab(TableTab.Mine); + setItem(LocalStorageKeys.homepage_dashboard_filter, TableTab.Mine); }, }, ]; - if (examples) { + if (otherTabData) { menuTabs.push({ - name: 'Examples', - label: t('Examples'), + name: TableTab.Other, + label: otherTabTitle, onClick: () => { - setDashboardFilter(TableTabTypes.EXAMPLES); - setItem( - LocalStorageKeys.homepage_dashboard_filter, - TableTabTypes.EXAMPLES, - ); + setActiveTab(TableTab.Other); + setItem(LocalStorageKeys.homepage_dashboard_filter, TableTab.Other); }, }); } @@ -209,7 +184,7 @@ function DashboardTable({ return ( <> <SubMenu - activeChild={dashboardFilter} + activeChild={activeTab} tabs={menuTabs} buttons={[ { @@ -229,7 +204,7 @@ function DashboardTable({ buttonStyle: 'link', onClick: () => { const target = - dashboardFilter === 'Favorite' + activeTab === TableTab.Favorite ? `/dashboard/list/?filters=(favorite:(label:${t( 'Yes', )},value:!t))` @@ -247,6 +222,30 @@ function DashboardTable({ onSubmit={handleDashboardEdit} /> )} + {dashboardToDelete && ( + <DeleteModal + description={ + <> + {t('Are you sure you want to delete')}{' '} + <b>{dashboardToDelete.dashboard_title}</b>? + </> + } + onConfirm={() => { + handleDashboardDelete( + dashboardToDelete, + refreshData, + addSuccessToast, + addDangerToast, + activeTab, + user?.userId, + ); + setDashboardToDelete(null); + }} + onHide={() => setDashboardToDelete(null)} + open={!!dashboardToDelete} + title={t('Please confirm')} + /> + )} {dashboards.length > 0 && ( <CardContainer showThumbnails={showThumbnails}> {dashboards.map(e => ( @@ -256,10 +255,6 @@ function DashboardTable({ hasPerm={hasPerm} bulkSelectEnabled={false} showThumbnails={showThumbnails} - dashboardFilter={dashboardFilter} - refreshData={refreshData} - addDangerToast={addDangerToast} - addSuccessToast={addSuccessToast} userId={user?.userId} loading={loading} openDashboardEditModal={(dashboard: Dashboard) => @@ -268,12 +263,13 @@ function DashboardTable({ saveFavoriteStatus={saveFavoriteStatus} favoriteStatus={favoriteStatus[e.id]} handleBulkDashboardExport={handleBulkDashboardExport} + onDelete={dashboard => setDashboardToDelete(dashboard)} /> ))} </CardContainer> )} {dashboards.length === 0 && ( - <EmptyState tableName={WelcomeTable.Dashboards} tab={dashboardFilter} /> + <EmptyState tableName={WelcomeTable.Dashboards} tab={activeTab} /> )} {preparingExport && <Loading />} </> diff --git a/superset-frontend/src/views/CRUD/welcome/EmptyState.test.tsx b/superset-frontend/src/views/CRUD/welcome/EmptyState.test.tsx index 908ebed6c4f85..fb8ae48ee16b3 100644 --- a/superset-frontend/src/views/CRUD/welcome/EmptyState.test.tsx +++ b/superset-frontend/src/views/CRUD/welcome/EmptyState.test.tsx @@ -18,47 +18,48 @@ */ import React from 'react'; import { styledMount as mount } from 'spec/helpers/theming'; -import EmptyState from 'src/views/CRUD/welcome/EmptyState'; +import { TableTab } from 'src/views/CRUD/types'; +import EmptyState, { EmptyStateProps } from 'src/views/CRUD/welcome/EmptyState'; import { WelcomeTable } from './types'; describe('EmptyState', () => { - const variants = [ + const variants: EmptyStateProps[] = [ { - tab: 'Favorite', + tab: TableTab.Favorite, tableName: WelcomeTable.Dashboards, }, { - tab: 'Mine', + tab: TableTab.Mine, tableName: WelcomeTable.Dashboards, }, { - tab: 'Favorite', + tab: TableTab.Favorite, tableName: WelcomeTable.Charts, }, { - tab: 'Mine', + tab: TableTab.Mine, tableName: WelcomeTable.Charts, }, { - tab: 'Favorite', + tab: TableTab.Favorite, tableName: WelcomeTable.SavedQueries, }, { - tab: 'Mine', + tab: TableTab.Mine, tableName: WelcomeTable.SavedQueries, }, ]; - const recents = [ + const recents: EmptyStateProps[] = [ { - tab: 'Viewed', + tab: TableTab.Viewed, tableName: WelcomeTable.Recents, }, { - tab: 'Edited', + tab: TableTab.Edited, tableName: WelcomeTable.Recents, }, { - tab: 'Created', + tab: TableTab.Created, tableName: WelcomeTable.Recents, }, ]; @@ -68,10 +69,10 @@ describe('EmptyState', () => { expect(wrapper).toExist(); const textContainer = wrapper.find('.ant-empty-description'); expect(textContainer.text()).toEqual( - variant.tab === 'Favorite' + variant.tab === TableTab.Favorite ? "You don't have any favorites yet!" : `No ${ - variant.tableName === 'SAVED_QUERIES' + variant.tableName === WelcomeTable.SavedQueries ? 'saved queries' : variant.tableName.toLowerCase() } yet`, @@ -80,13 +81,13 @@ describe('EmptyState', () => { }); }); recents.forEach(recent => { - it(`it renders an ${recent.tab} ${recent.tableName} empty state`, () => { + it(`it renders a ${recent.tab} ${recent.tableName} empty state`, () => { const wrapper = mount(<EmptyState {...recent} />); expect(wrapper).toExist(); const textContainer = wrapper.find('.ant-empty-description'); expect(wrapper.find('.ant-empty-image').children()).toHaveLength(1); expect(textContainer.text()).toContain( - `Recently ${recent.tab.toLowerCase()} charts, dashboards, and saved queries will appear here`, + `Recently ${recent.tab?.toLowerCase()} charts, dashboards, and saved queries will appear here`, ); }); }); diff --git a/superset-frontend/src/views/CRUD/welcome/EmptyState.tsx b/superset-frontend/src/views/CRUD/welcome/EmptyState.tsx index 525c9ef62e803..47e7817ae374d 100644 --- a/superset-frontend/src/views/CRUD/welcome/EmptyState.tsx +++ b/superset-frontend/src/views/CRUD/welcome/EmptyState.tsx @@ -19,7 +19,8 @@ import React from 'react'; import Button from 'src/components/Button'; import { Empty } from 'src/components'; -import { t, styled } from '@superset-ui/core'; +import { TableTab } from 'src/views/CRUD/types'; +import { styled, t } from '@superset-ui/core'; import { WelcomeTable } from './types'; const welcomeTableLabels: Record<WelcomeTable, string> = { @@ -29,9 +30,29 @@ const welcomeTableLabels: Record<WelcomeTable, string> = { [WelcomeTable.SavedQueries]: t('saved queries'), }; -interface EmptyStateProps { +const welcomeTableEmpty: Record<WelcomeTable, string> = { + [WelcomeTable.Charts]: t('No charts yet'), + [WelcomeTable.Dashboards]: t('No dashboards yet'), + [WelcomeTable.Recents]: t('No recents yet'), + [WelcomeTable.SavedQueries]: t('No saved queries yet'), +}; + +const welcomeTableWillAppear: Record<WelcomeTable, (other: string) => string> = + { + [WelcomeTable.Charts]: (other: string) => + t('%(other)s charts will appear here', { other }), + [WelcomeTable.Dashboards]: (other: string) => + t('%(other)s dashboards will appear here', { other }), + [WelcomeTable.Recents]: (other: string) => + t('%(other)s recents will appear here', { other }), + [WelcomeTable.SavedQueries]: (other: string) => + t('%(other)s saved queries will appear here', { other }), + }; + +export interface EmptyStateProps { tableName: WelcomeTable; tab?: string; + otherTabTitle?: string; } const EmptyContainer = styled.div` min-height: 200px; @@ -52,7 +73,11 @@ type Redirects = Record< string >; -export default function EmptyState({ tableName, tab }: EmptyStateProps) { +export default function EmptyState({ + tableName, + tab, + otherTabTitle, +}: EmptyStateProps) { const mineRedirects: Redirects = { [WelcomeTable.Charts]: '/chart/add', [WelcomeTable.Dashboards]: '/dashboard/new', @@ -69,30 +94,25 @@ export default function EmptyState({ tableName, tab }: EmptyStateProps) { [WelcomeTable.Recents]: 'union.svg', [WelcomeTable.SavedQueries]: 'empty-queries.svg', }; - const mine = ( - <span> - {t('No %(tableName)s yet', { tableName: welcomeTableLabels[tableName] })} - </span> - ); + const mine = <span>{welcomeTableEmpty[tableName]}</span>; const recent = ( <span className="no-recents"> {(() => { - if (tab === 'Viewed') { + if (tab === TableTab.Viewed) { return t( `Recently viewed charts, dashboards, and saved queries will appear here`, ); } - if (tab === 'Created') { + if (tab === TableTab.Created) { return t( 'Recently created charts, dashboards, and saved queries will appear here', ); } - if (tab === 'Examples') { - return t('Example %(tableName)s will appear here', { - tableName: tableName.toLowerCase(), - }); + if (tab === TableTab.Other) { + const other = otherTabTitle || t('Other'); + return welcomeTableWillAppear[tableName](other); } - if (tab === 'Edited') { + if (tab === TableTab.Edited) { return t( `Recently edited charts, dashboards, and saved queries will appear here`, ); @@ -101,17 +121,24 @@ export default function EmptyState({ tableName, tab }: EmptyStateProps) { })()} </span> ); + // Mine and Recent Activity(all tabs) tab empty state - if (tab === 'Mine' || tableName === 'RECENTS' || tab === 'Examples') { + if ( + tab === TableTab.Mine || + tableName === WelcomeTable.Recents || + tab === TableTab.Other + ) { return ( <EmptyContainer> <Empty image={`/static/assets/images/${tableIcon[tableName]}`} description={ - tableName === 'RECENTS' || tab === 'Examples' ? recent : mine + tableName === WelcomeTable.Recents || tab === TableTab.Other + ? recent + : mine } > - {tableName !== 'RECENTS' && ( + {tableName !== WelcomeTable.Recents && ( <ButtonContainer> <Button buttonStyle="primary" @@ -120,7 +147,7 @@ export default function EmptyState({ tableName, tab }: EmptyStateProps) { }} > <i className="fa fa-plus" /> - {tableName === 'SAVED_QUERIES' + {tableName === WelcomeTable.SavedQueries ? t('SQL query') : tableName .split('') @@ -152,7 +179,7 @@ export default function EmptyState({ tableName, tab }: EmptyStateProps) { > {t('See all %(tableName)s', { tableName: - tableName === 'SAVED_QUERIES' + tableName === WelcomeTable.SavedQueries ? t('SQL Lab queries') : welcomeTableLabels[tableName], })} diff --git a/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx b/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx index b267bed8c262d..4e323e633f225 100644 --- a/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx +++ b/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx @@ -22,6 +22,7 @@ import SyntaxHighlighter from 'react-syntax-highlighter/dist/cjs/light'; import sql from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql'; import github from 'react-syntax-highlighter/dist/cjs/styles/hljs/github'; import { LoadingCards } from 'src/views/CRUD/welcome/Welcome'; +import { TableTab } from 'src/views/CRUD/types'; import withToasts from 'src/components/MessageToasts/withToasts'; import { AntdDropdown } from 'src/components'; import { Menu } from 'src/components/Menu'; @@ -30,10 +31,12 @@ import ListViewCard from 'src/components/ListViewCard'; import DeleteModal from 'src/components/DeleteModal'; import Icons from 'src/components/Icons'; import SubMenu from 'src/views/components/SubMenu'; +import { User } from 'src/types/bootstrapTypes'; import EmptyState from './EmptyState'; import { CardContainer, createErrorHandler, + getFilterValues, PAGE_SIZE, shortenSQL, } from '../utils'; @@ -56,9 +59,7 @@ interface Query { } interface SavedQueriesProps { - user: { - userId: string | number; - }; + user: User; queryFilter: string; addDangerToast: (arg0: string) => void; addSuccessToast: (arg0: string) => void; @@ -134,7 +135,7 @@ const SavedQueries = ({ [], false, ); - const [queryFilter, setQueryFilter] = useState('Mine'); + const [activeTab, setActiveTab] = useState(TableTab.Mine); const [queryDeleteModal, setQueryDeleteModal] = useState(false); const [currentlyEdited, setCurrentlyEdited] = useState<Query>({}); const [ifMine, setMine] = useState(true); @@ -149,13 +150,11 @@ const SavedQueries = ({ }).then( () => { const queryParams = { - filters: [ - { - id: 'created_by', - operator: 'rel_o_m', - value: `${user?.userId}`, - }, - ], + filters: getFilterValues( + TableTab.Created, + WelcomeTable.SavedQueries, + user, + ), pageSize: PAGE_SIZE, sortBy: [ { @@ -178,25 +177,7 @@ const SavedQueries = ({ ); }; - const getFilters = (filterName: string) => { - const filters = []; - if (filterName === 'Mine') { - filters.push({ - id: 'created_by', - operator: 'rel_o_m', - value: `${user?.userId}`, - }); - } else { - filters.push({ - id: 'id', - operator: 'saved_query_is_fav', - value: true, - }); - } - return filters; - }; - - const getData = (filter: string) => + const getData = (tab: TableTab) => fetchData({ pageIndex: 0, pageSize: PAGE_SIZE, @@ -206,7 +187,7 @@ const SavedQueries = ({ desc: true, }, ], - filters: getFilters(filter), + filters: getFilterValues(tab, WelcomeTable.SavedQueries, user), }); const renderMenu = (query: Query) => ( @@ -263,21 +244,13 @@ const SavedQueries = ({ /> )} <SubMenu - activeChild={queryFilter} + activeChild={activeTab} tabs={[ - /* @TODO uncomment when fav functionality is implemented - { - name: 'Favorite', - label: t('Favorite'), - onClick: () => { - getData('Favorite').then(() => setQueryFilter('Favorite')); - }, - }, - */ { - name: 'Mine', + name: TableTab.Mine, label: t('Mine'), - onClick: () => getData('Mine').then(() => setQueryFilter('Mine')), + onClick: () => + getData(TableTab.Mine).then(() => setActiveTab(TableTab.Mine)), }, ]} buttons={[ @@ -366,7 +339,7 @@ const SavedQueries = ({ ))} </CardContainer> ) : ( - <EmptyState tableName={WelcomeTable.SavedQueries} tab={queryFilter} /> + <EmptyState tableName={WelcomeTable.SavedQueries} tab={activeTab} /> )} </> ); diff --git a/superset-frontend/src/views/CRUD/welcome/Welcome.test.tsx b/superset-frontend/src/views/CRUD/welcome/Welcome.test.tsx index 85c953017ba19..dffe5acdd0a89 100644 --- a/superset-frontend/src/views/CRUD/welcome/Welcome.test.tsx +++ b/superset-frontend/src/views/CRUD/welcome/Welcome.test.tsx @@ -27,6 +27,9 @@ import * as featureFlags from 'src/featureFlags'; import Welcome from 'src/views/CRUD/welcome/Welcome'; import { ReactWrapper } from 'enzyme'; import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; +import { render, screen } from 'spec/helpers/testing-library'; +import { getExtensionsRegistry } from '@superset-ui/core'; +import setupExtensions from 'src/setup/setupExtensions'; const mockStore = configureStore([thunk]); const store = mockStore({}); @@ -40,7 +43,7 @@ const dashboardFavoriteStatusEndpoint = 'glob:*/api/v1/dashboard/favorite_status?*'; const savedQueryEndpoint = 'glob:*/api/v1/saved_query/?*'; const savedQueryInfoEndpoint = 'glob:*/api/v1/saved_query/_info?*'; -const recentActivityEndpoint = 'glob:*/superset/recent_activity/*'; +const recentActivityEndpoint = 'glob:*/api/v1/log/recent_activity/*'; fetchMock.get(chartsEndpoint, { result: [ @@ -103,10 +106,15 @@ const mockedProps = { userId: 5, email: 'alpha@alpha.com', isActive: true, + isAnonymous: false, + permissions: {}, + roles: { + sql_lab: [], + }, }, }; -describe('Welcome', () => { +describe('Welcome with sql role', () => { let wrapper: ReactWrapper; beforeAll(async () => { @@ -119,6 +127,10 @@ describe('Welcome', () => { }); }); + afterAll(() => { + fetchMock.resetHistory(); + }); + it('renders', () => { expect(wrapper).toExist(); }); @@ -130,7 +142,7 @@ describe('Welcome', () => { it('calls api methods in parallel on page load', () => { const chartCall = fetchMock.calls(/chart\/\?q/); const savedQueryCall = fetchMock.calls(/saved_query\/\?q/); - const recentCall = fetchMock.calls(/superset\/recent_activity\/*/); + const recentCall = fetchMock.calls(/api\/v1\/log\/recent_activity\/*/); const dashboardCall = fetchMock.calls(/dashboard\/\?q/); expect(chartCall).toHaveLength(2); expect(recentCall).toHaveLength(1); @@ -139,6 +151,50 @@ describe('Welcome', () => { }); }); +describe('Welcome without sql role', () => { + let wrapper: ReactWrapper; + + beforeAll(async () => { + await act(async () => { + const props = { + ...mockedProps, + user: { + ...mockedProps.user, + roles: {}, + }, + }; + wrapper = mount( + <Provider store={store}> + <Welcome {...props} /> + </Provider>, + ); + }); + }); + + afterAll(() => { + fetchMock.resetHistory(); + }); + + it('renders', () => { + expect(wrapper).toExist(); + }); + + it('renders all panels on the page on page load', () => { + expect(wrapper.find('CollapsePanel')).toHaveLength(6); + }); + + it('calls api methods in parallel on page load', () => { + const chartCall = fetchMock.calls(/chart\/\?q/); + const savedQueryCall = fetchMock.calls(/saved_query\/\?q/); + const recentCall = fetchMock.calls(/api\/v1\/log\/recent_activity\/*/); + const dashboardCall = fetchMock.calls(/dashboard\/\?q/); + expect(chartCall).toHaveLength(2); + expect(recentCall).toHaveLength(1); + expect(savedQueryCall).toHaveLength(0); + expect(dashboardCall).toHaveLength(2); + }); +}); + async function mountAndWait(props = mockedProps) { const wrapper = mount( <Provider store={store}> @@ -179,3 +235,23 @@ describe('Welcome page with toggle switch', () => { expect(wrapper.find('ImageLoader')).not.toExist(); }); }); + +test('should render an extension component if one is supplied', () => { + const extensionsRegistry = getExtensionsRegistry(); + + extensionsRegistry.set('welcome.banner', () => ( + <>welcome.banner extension component</> + )); + + setupExtensions(); + + render( + <Provider store={store}> + <Welcome {...mockedProps} /> + </Provider>, + ); + + expect( + screen.getByText('welcome.banner extension component'), + ).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/views/CRUD/welcome/Welcome.tsx b/superset-frontend/src/views/CRUD/welcome/Welcome.tsx index 3660b8acc8e09..9da45615fbfc4 100644 --- a/superset-frontend/src/views/CRUD/welcome/Welcome.tsx +++ b/superset-frontend/src/views/CRUD/welcome/Welcome.tsx @@ -16,8 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useEffect, useState } from 'react'; -import { styled, t } from '@superset-ui/core'; +import React, { useEffect, useMemo, useState } from 'react'; +import { + getExtensionsRegistry, + JsonObject, + styled, + t, +} from '@superset-ui/core'; +import rison from 'rison'; import Collapse from 'src/components/Collapse'; import { User } from 'src/types/bootstrapTypes'; import { reject } from 'lodash'; @@ -32,7 +38,7 @@ import ListViewCard from 'src/components/ListViewCard'; import withToasts from 'src/components/MessageToasts/withToasts'; import { createErrorHandler, - getRecentAcitivtyObjs, + getRecentActivityObjs, mq, CardContainer, getUserOwnedObjects, @@ -40,22 +46,27 @@ import { } from 'src/views/CRUD/utils'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import { AntdSwitch } from 'src/components'; - +import getBootstrapData from 'src/utils/getBootstrapData'; +import { TableTab } from 'src/views/CRUD/types'; +import { canUserAccessSqlLab } from 'src/dashboard/util/permissionUtils'; +import { WelcomePageLastTab } from './types'; import ActivityTable from './ActivityTable'; import ChartTable from './ChartTable'; import SavedQueries from './SavedQueries'; import DashboardTable from './DashboardTable'; +const extensionsRegistry = getExtensionsRegistry(); + interface WelcomeProps { user: User; addDangerToast: (arg0: string) => void; } export interface ActivityData { - Created?: Array<object>; - Edited?: Array<object>; - Viewed?: Array<object>; - Examples?: Array<object>; + [TableTab.Created]?: JsonObject[]; + [TableTab.Edited]?: JsonObject[]; + [TableTab.Viewed]?: JsonObject[]; + [TableTab.Other]?: JsonObject[]; } interface LoadingProps { @@ -136,6 +147,8 @@ const WelcomeNav = styled.div` `} `; +const bootstrapData = getBootstrapData(); + export const LoadingCards = ({ cover }: LoadingProps) => ( <CardContainer showThumbnails={cover} className="loading-cards"> {[...new Array(loadingCardCount)].map((_, index) => ( @@ -150,9 +163,11 @@ export const LoadingCards = ({ cover }: LoadingProps) => ( ); function Welcome({ user, addDangerToast }: WelcomeProps) { + const canAccessSqlLab = canUserAccessSqlLab(user); const userid = user.userId; const id = userid!.toString(); // confident that user is not a guest user - const recent = `/superset/recent_activity/${user.userId}/?limit=6`; + const params = rison.encode({ page_size: 6 }); + const recent = `/api/v1/log/recent_activity/${user.userId}/?q=${params}`; const [activeChild, setActiveChild] = useState('Loading'); const userKey = dangerouslyGetItemDoNotUse(id, null); let defaultChecked = false; @@ -167,7 +182,7 @@ function Welcome({ user, addDangerToast }: WelcomeProps) { const [dashboardData, setDashboardData] = useState<Array<object> | null>( null, ); - const [loadedCount, setLoadedCount] = useState(0); + const [isFetchingActivityData, setIsFetchingActivityData] = useState(true); const collapseState = getItem(LocalStorageKeys.homepage_collapse_state, []); const [activeState, setActiveState] = useState<Array<string>>(collapseState); @@ -177,28 +192,64 @@ function Welcome({ user, addDangerToast }: WelcomeProps) { setItem(LocalStorageKeys.homepage_collapse_state, state); }; + const WelcomeMessageExtension = extensionsRegistry.get('welcome.message'); + const WelcomeTopExtension = extensionsRegistry.get('welcome.banner'); + const WelcomeMainExtension = extensionsRegistry.get( + 'welcome.main.replacement', + ); + + const [otherTabTitle, otherTabFilters] = useMemo(() => { + const lastTab = bootstrapData.common?.conf + .WELCOME_PAGE_LAST_TAB as WelcomePageLastTab; + const [customTitle, customFilter] = Array.isArray(lastTab) + ? lastTab + : [undefined, undefined]; + if (customTitle && customFilter) { + return [t(customTitle), customFilter]; + } + if (lastTab === 'all') { + return [t('All'), []]; + } + return [ + t('Examples'), + [ + { + col: 'created_by', + opr: 'rel_o_m', + value: 0, + }, + ], + ]; + }, []); + useEffect(() => { + if (!otherTabFilters) { + return; + } const activeTab = getItem(LocalStorageKeys.homepage_activity_filter, null); setActiveState(collapseState.length > 0 ? collapseState : DEFAULT_TAB_ARR); - getRecentAcitivtyObjs(user.userId!, recent, addDangerToast) + getRecentActivityObjs(user.userId!, recent, addDangerToast, otherTabFilters) .then(res => { const data: ActivityData | null = {}; - data.Examples = res.examples; + data[TableTab.Other] = res.other; if (res.viewed) { const filtered = reject(res.viewed, ['item_url', null]).map(r => r); - data.Viewed = filtered; - if (!activeTab && data.Viewed) { - setActiveChild('Viewed'); - } else if (!activeTab && !data.Viewed) { - setActiveChild('Created'); - } else setActiveChild(activeTab || 'Created'); - } else if (!activeTab) setActiveChild('Created'); + data[TableTab.Viewed] = filtered; + if (!activeTab && data[TableTab.Viewed]) { + setActiveChild(TableTab.Viewed); + } else if (!activeTab && !data[TableTab.Viewed]) { + setActiveChild(TableTab.Created); + } else setActiveChild(activeTab || TableTab.Created); + } else if (!activeTab) setActiveChild(TableTab.Created); else setActiveChild(activeTab); setActivityData(activityData => ({ ...activityData, ...data })); }) .catch( createErrorHandler((errMsg: unknown) => { - setActivityData(activityData => ({ ...activityData, Viewed: [] })); + setActivityData(activityData => ({ + ...activityData, + [TableTab.Viewed]: [], + })); addDangerToast( t('There was an issue fetching your recent activity: %s', errMsg), ); @@ -213,41 +264,47 @@ function Welcome({ user, addDangerToast }: WelcomeProps) { value: `${id}`, }, ]; - getUserOwnedObjects(id, 'dashboard') - .then(r => { - setDashboardData(r); - setLoadedCount(loadedCount => loadedCount + 1); - }) - .catch((err: unknown) => { - setDashboardData([]); - setLoadedCount(loadedCount => loadedCount + 1); - addDangerToast( - t('There was an issue fetching your dashboards: %s', err), - ); - }); - getUserOwnedObjects(id, 'chart') - .then(r => { - setChartData(r); - setLoadedCount(loadedCount => loadedCount + 1); - }) - .catch((err: unknown) => { - setChartData([]); - setLoadedCount(loadedCount => loadedCount + 1); - addDangerToast(t('There was an issue fetching your chart: %s', err)); - }); - getUserOwnedObjects(id, 'saved_query', ownSavedQueryFilters) - .then(r => { - setQueryData(r); - setLoadedCount(loadedCount => loadedCount + 1); - }) - .catch((err: unknown) => { - setQueryData([]); - setLoadedCount(loadedCount => loadedCount + 1); - addDangerToast( - t('There was an issues fetching your saved queries: %s', err), - ); - }); - }, []); + Promise.all([ + getUserOwnedObjects(id, 'dashboard') + .then(r => { + setDashboardData(r); + return Promise.resolve(); + }) + .catch((err: unknown) => { + setDashboardData([]); + addDangerToast( + t('There was an issue fetching your dashboards: %s', err), + ); + return Promise.resolve(); + }), + getUserOwnedObjects(id, 'chart') + .then(r => { + setChartData(r); + return Promise.resolve(); + }) + .catch((err: unknown) => { + setChartData([]); + addDangerToast(t('There was an issue fetching your chart: %s', err)); + return Promise.resolve(); + }), + canAccessSqlLab + ? getUserOwnedObjects(id, 'saved_query', ownSavedQueryFilters) + .then(r => { + setQueryData(r); + return Promise.resolve(); + }) + .catch((err: unknown) => { + setQueryData([]); + addDangerToast( + t('There was an issue fetching your saved queries: %s', err), + ); + return Promise.resolve(); + }) + : Promise.resolve(), + ]).then(() => { + setIsFetchingActivityData(false); + }); + }, [otherTabFilters]); const handleToggle = () => { setChecked(!checked); @@ -269,79 +326,98 @@ function Welcome({ user, addDangerToast }: WelcomeProps) { }, [chartData, queryData, dashboardData]); useEffect(() => { - if (!collapseState && activityData?.Viewed?.length) { + if (!collapseState && activityData?.[TableTab.Viewed]?.length) { setActiveState(activeState => ['1', ...activeState]); } }, [activityData]); const isRecentActivityLoading = - !activityData?.Examples && !activityData?.Viewed; + !activityData?.[TableTab.Other] && !activityData?.[TableTab.Viewed]; + return ( <WelcomeContainer> - <WelcomeNav> - <h1 className="welcome-header">Home</h1> - {isFeatureEnabled(FeatureFlag.THUMBNAILS) ? ( - <div className="switch"> - <AntdSwitch checked={checked} onChange={handleToggle} /> - <span>Thumbnails</span> - </div> - ) : null} - </WelcomeNav> - <Collapse activeKey={activeState} onChange={handleCollapse} ghost bigger> - <Collapse.Panel header={t('Recents')} key="1"> - {activityData && - (activityData.Viewed || - activityData.Examples || - activityData.Created) && - activeChild !== 'Loading' ? ( - <ActivityTable - user={{ userId: user.userId! }} // user is definitely not a guest user on this page - activeChild={activeChild} - setActiveChild={setActiveChild} - activityData={activityData} - loadedCount={loadedCount} - /> - ) : ( - <LoadingCards /> - )} - </Collapse.Panel> - <Collapse.Panel header={t('Dashboards')} key="2"> - {!dashboardData || isRecentActivityLoading ? ( - <LoadingCards cover={checked} /> - ) : ( - <DashboardTable - user={user} - mine={dashboardData} - showThumbnails={checked} - examples={activityData?.Examples} - /> - )} - </Collapse.Panel> - <Collapse.Panel header={t('Charts')} key="3"> - {!chartData || isRecentActivityLoading ? ( - <LoadingCards cover={checked} /> - ) : ( - <ChartTable - showThumbnails={checked} - user={user} - mine={chartData} - examples={activityData?.Examples} - /> - )} - </Collapse.Panel> - <Collapse.Panel header={t('Saved queries')} key="4"> - {!queryData ? ( - <LoadingCards cover={checked} /> - ) : ( - <SavedQueries - showThumbnails={checked} - user={user} - mine={queryData} - featureFlag={isFeatureEnabled(FeatureFlag.THUMBNAILS)} - /> - )} - </Collapse.Panel> - </Collapse> + {WelcomeMessageExtension && <WelcomeMessageExtension />} + {WelcomeTopExtension && <WelcomeTopExtension />} + {WelcomeMainExtension && <WelcomeMainExtension />} + {(!WelcomeTopExtension || !WelcomeMainExtension) && ( + <> + <WelcomeNav> + <h1 className="welcome-header">{t('Home')}</h1> + {isFeatureEnabled(FeatureFlag.THUMBNAILS) ? ( + <div className="switch"> + <AntdSwitch checked={checked} onChange={handleToggle} /> + <span>{t('Thumbnails')}</span> + </div> + ) : null} + </WelcomeNav> + <Collapse + activeKey={activeState} + onChange={handleCollapse} + ghost + bigger + > + <Collapse.Panel header={t('Recents')} key="1"> + {activityData && + (activityData[TableTab.Viewed] || + activityData[TableTab.Other] || + activityData[TableTab.Created]) && + activeChild !== 'Loading' ? ( + <ActivityTable + user={{ userId: user.userId! }} // user is definitely not a guest user on this page + activeChild={activeChild} + setActiveChild={setActiveChild} + activityData={activityData} + isFetchingActivityData={isFetchingActivityData} + /> + ) : ( + <LoadingCards /> + )} + </Collapse.Panel> + <Collapse.Panel header={t('Dashboards')} key="2"> + {!dashboardData || isRecentActivityLoading ? ( + <LoadingCards cover={checked} /> + ) : ( + <DashboardTable + user={user} + mine={dashboardData} + showThumbnails={checked} + otherTabData={activityData?.[TableTab.Other]} + otherTabFilters={otherTabFilters} + otherTabTitle={otherTabTitle} + /> + )} + </Collapse.Panel> + <Collapse.Panel header={t('Charts')} key="3"> + {!chartData || isRecentActivityLoading ? ( + <LoadingCards cover={checked} /> + ) : ( + <ChartTable + showThumbnails={checked} + user={user} + mine={chartData} + otherTabData={activityData?.[TableTab.Other]} + otherTabFilters={otherTabFilters} + otherTabTitle={otherTabTitle} + /> + )} + </Collapse.Panel> + {canAccessSqlLab && ( + <Collapse.Panel header={t('Saved queries')} key="4"> + {!queryData ? ( + <LoadingCards cover={checked} /> + ) : ( + <SavedQueries + showThumbnails={checked} + user={user} + mine={queryData} + featureFlag={isFeatureEnabled(FeatureFlag.THUMBNAILS)} + /> + )} + </Collapse.Panel> + )} + </Collapse> + </> + )} </WelcomeContainer> ); } diff --git a/superset-frontend/src/views/CRUD/welcome/types.ts b/superset-frontend/src/views/CRUD/welcome/types.ts index 8e9d6d4c46ebe..b6e34e8b5708d 100644 --- a/superset-frontend/src/views/CRUD/welcome/types.ts +++ b/superset-frontend/src/views/CRUD/welcome/types.ts @@ -17,9 +17,13 @@ * under the License. */ +import { Filter } from '../types'; + export enum WelcomeTable { Charts = 'CHARTS', Dashboards = 'DASHBOARDS', Recents = 'RECENTS', SavedQueries = 'SAVED_QUERIES', } + +export type WelcomePageLastTab = 'examples' | 'all' | [string, Filter[]]; diff --git a/superset-frontend/src/views/QueryProvider.tsx b/superset-frontend/src/views/QueryProvider.tsx new file mode 100644 index 0000000000000..9fef2022d4c33 --- /dev/null +++ b/superset-frontend/src/views/QueryProvider.tsx @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { QueryClient, QueryClientProvider } from 'react-query'; + +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + retry: false, + retryOnMount: false, + refetchOnMount: false, + refetchOnReconnect: false, + refetchOnWindowFocus: false, + }, + }, +}); + +type Props = { + children: React.ReactNode; +}; + +const Queryprovider: React.FC<Props> = ({ children }) => ( + <QueryClientProvider client={queryClient}>{children}</QueryClientProvider> +); + +export default Queryprovider; diff --git a/superset-frontend/src/views/RootContextProviders.tsx b/superset-frontend/src/views/RootContextProviders.tsx index f40f228bb8c13..795ea7c5ee25c 100644 --- a/superset-frontend/src/views/RootContextProviders.tsx +++ b/superset-frontend/src/views/RootContextProviders.tsx @@ -19,37 +19,51 @@ import React from 'react'; import { Route } from 'react-router-dom'; -import { ThemeProvider } from '@superset-ui/core'; +import { getExtensionsRegistry, ThemeProvider } from '@superset-ui/core'; import { Provider as ReduxProvider } from 'react-redux'; import { QueryParamProvider } from 'use-query-params'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; - +import getBootstrapData from 'src/utils/getBootstrapData'; import { store } from './store'; import FlashProvider from '../components/FlashProvider'; -import { bootstrapData, theme } from '../preamble'; +import { theme } from '../preamble'; import { EmbeddedUiConfigProvider } from '../components/UiConfigContext'; import { DynamicPluginProvider } from '../components/DynamicPlugins'; -const common = { ...bootstrapData.common }; +const { common } = getBootstrapData(); + +const extensionsRegistry = getExtensionsRegistry(); + +export const RootContextProviders: React.FC = ({ children }) => { + const RootContextProviderExtension = extensionsRegistry.get( + 'root.context.provider', + ); -export const RootContextProviders: React.FC = ({ children }) => ( - <ThemeProvider theme={theme}> - <ReduxProvider store={store}> - <DndProvider backend={HTML5Backend}> - <FlashProvider messages={common.flash_messages}> - <EmbeddedUiConfigProvider> - <DynamicPluginProvider> - <QueryParamProvider - ReactRouterRoute={Route} - stringifyOptions={{ encode: false }} - > - {children} - </QueryParamProvider> - </DynamicPluginProvider> - </EmbeddedUiConfigProvider> - </FlashProvider> - </DndProvider> - </ReduxProvider> - </ThemeProvider> -); + return ( + <ThemeProvider theme={theme}> + <ReduxProvider store={store}> + <DndProvider backend={HTML5Backend}> + <FlashProvider messages={common.flash_messages}> + <EmbeddedUiConfigProvider> + <DynamicPluginProvider> + <QueryParamProvider + ReactRouterRoute={Route} + stringifyOptions={{ encode: false }} + > + {RootContextProviderExtension ? ( + <RootContextProviderExtension> + {children} + </RootContextProviderExtension> + ) : ( + children + )} + </QueryParamProvider> + </DynamicPluginProvider> + </EmbeddedUiConfigProvider> + </FlashProvider> + </DndProvider> + </ReduxProvider> + </ThemeProvider> + ); +}; diff --git a/superset-frontend/src/views/components/LanguagePicker.test.tsx b/superset-frontend/src/views/components/LanguagePicker.test.tsx index 230c89d18b48c..a427c4e91ae0c 100644 --- a/superset-frontend/src/views/components/LanguagePicker.test.tsx +++ b/superset-frontend/src/views/components/LanguagePicker.test.tsx @@ -38,22 +38,23 @@ const mockedProps = { }, }; -test('should render', () => { +test('should render', async () => { const { container } = render( <Menu> <LanguagePicker {...mockedProps} /> </Menu>, ); + expect(await screen.findByRole('button')).toBeInTheDocument(); expect(container).toBeInTheDocument(); }); -test('should render the language picker', () => { +test('should render the language picker', async () => { render( <Menu> <LanguagePicker {...mockedProps} /> </Menu>, ); - expect(screen.getByLabelText('Languages')).toBeInTheDocument(); + expect(await screen.findByLabelText('Languages')).toBeInTheDocument(); }); test('should render the items', async () => { diff --git a/superset-frontend/src/views/components/Menu.test.tsx b/superset-frontend/src/views/components/Menu.test.tsx index bcfc01c7704b7..b40a5ab075252 100644 --- a/superset-frontend/src/views/components/Menu.test.tsx +++ b/superset-frontend/src/views/components/Menu.test.tsx @@ -20,7 +20,9 @@ import React from 'react'; import * as reactRedux from 'react-redux'; import fetchMock from 'fetch-mock'; import { render, screen } from 'spec/helpers/testing-library'; +import setupExtensions from 'src/setup/setupExtensions'; import userEvent from '@testing-library/user-event'; +import { getExtensionsRegistry } from '@superset-ui/core'; import { Menu } from './Menu'; const dropdownItems = [ @@ -250,48 +252,64 @@ beforeEach(() => { useSelectorMock.mockClear(); }); -test('should render', () => { +test('should render', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); const { container } = render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true, + useRouter: true, }); + expect(await screen.findByText(/sources/i)).toBeInTheDocument(); expect(container).toBeInTheDocument(); }); -test('should render the navigation', () => { +test('should render the navigation', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); - expect(screen.getByRole('navigation')).toBeInTheDocument(); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + expect(await screen.findByRole('navigation')).toBeInTheDocument(); }); -test('should render the brand', () => { +test('should render the brand', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); const { data: { brand: { alt, icon }, }, } = mockedProps; - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + expect(await screen.findByAltText(alt)).toBeInTheDocument(); const image = screen.getByAltText(alt); expect(image).toHaveAttribute('src', icon); }); -test('should render the environment tag', () => { +test('should render the environment tag', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); const { data: { environment_tag }, } = mockedProps; - render(<Menu {...mockedProps} />, { useRedux: true }); - expect(screen.getByText(environment_tag.text)).toBeInTheDocument(); + render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + expect(await screen.findByText(environment_tag.text)).toBeInTheDocument(); }); -test('should render all the top navbar menu items', () => { +test('should render all the top navbar menu items', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); const { data: { menu }, } = mockedProps; - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + expect(await screen.findByText(menu[0].label)).toBeInTheDocument(); menu.forEach(item => { expect(screen.getByText(item.label)).toBeInTheDocument(); }); @@ -302,7 +320,11 @@ test('should render the top navbar child menu items', async () => { const { data: { menu }, } = mockedProps; - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); const sources = screen.getByText('Sources'); userEvent.hover(sources); const datasets = await screen.findByText('Datasets'); @@ -316,7 +338,11 @@ test('should render the top navbar child menu items', async () => { test('should render the dropdown items', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); - render(<Menu {...notanonProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...notanonProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); const dropdown = screen.getByTestId('new-dropdown-icon'); userEvent.hover(dropdown); // todo (philip): test data submenu @@ -342,14 +368,22 @@ test('should render the dropdown items', async () => { test('should render the Settings', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); const settings = await screen.findByText('Settings'); expect(settings).toBeInTheDocument(); }); test('should render the Settings menu item', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); userEvent.hover(screen.getByText('Settings')); const label = await screen.findByText('Security'); expect(label).toBeInTheDocument(); @@ -360,21 +394,34 @@ test('should render the Settings dropdown child menu items', async () => { const { data: { settings }, } = mockedProps; - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); userEvent.hover(screen.getByText('Settings')); const listUsers = await screen.findByText('List Users'); expect(listUsers).toHaveAttribute('href', settings[0].childs[0].url); }); -test('should render the plus menu (+) when user is not anonymous', () => { +test('should render the plus menu (+) when user is not anonymous', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); - render(<Menu {...notanonProps} />, { useRedux: true, useQueryParams: true }); - expect(screen.getByTestId('new-dropdown')).toBeInTheDocument(); + render(<Menu {...notanonProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + expect(await screen.findByTestId('new-dropdown')).toBeInTheDocument(); }); -test('should NOT render the plus menu (+) when user is anonymous', () => { +test('should NOT render the plus menu (+) when user is anonymous', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + expect(await screen.findByText(/sources/i)).toBeInTheDocument(); expect(screen.queryByTestId('new-dropdown')).not.toBeInTheDocument(); }); @@ -386,7 +433,11 @@ test('should render the user actions when user is not anonymous', async () => { }, } = mockedProps; - render(<Menu {...notanonProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...notanonProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); userEvent.hover(screen.getByText('Settings')); const user = await screen.findByText('User'); expect(user).toBeInTheDocument(); @@ -398,9 +449,14 @@ test('should render the user actions when user is not anonymous', async () => { expect(logout).toHaveAttribute('href', user_logout_url); }); -test('should NOT render the user actions when user is anonymous', () => { +test('should NOT render the user actions when user is anonymous', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + expect(await screen.findByText(/sources/i)).toBeInTheDocument(); expect(screen.queryByText('User')).not.toBeInTheDocument(); }); @@ -412,7 +468,11 @@ test('should render the Profile link when available', async () => { }, } = mockedProps; - render(<Menu {...notanonProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...notanonProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); userEvent.hover(screen.getByText('Settings')); const profile = await screen.findByText('Profile'); @@ -427,7 +487,11 @@ test('should render the About section and version_string, sha or build_number wh }, } = mockedProps; - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); userEvent.hover(screen.getByText('Settings')); const about = await screen.findByText('About'); const version = await screen.findByText(`Version: ${version_string}`); @@ -446,7 +510,11 @@ test('should render the Documentation link when available', async () => { navbar_right: { documentation_url }, }, } = mockedProps; - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); userEvent.hover(screen.getByText('Settings')); const doc = await screen.findByTitle('Documentation'); expect(doc).toHaveAttribute('href', documentation_url); @@ -460,12 +528,16 @@ test('should render the Bug Report link when available', async () => { }, } = mockedProps; - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); const bugReport = await screen.findByTitle('Report a bug'); expect(bugReport).toHaveAttribute('href', bug_report_url); }); -test('should render the Login link when user is anonymous', () => { +test('should render the Login link when user is anonymous', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); const { data: { @@ -473,25 +545,59 @@ test('should render the Login link when user is anonymous', () => { }, } = mockedProps; - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); - const login = screen.getByText('Login'); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + const login = await screen.findByText('Login'); expect(login).toHaveAttribute('href', user_login_url); }); -test('should render the Language Picker', () => { +test('should render the Language Picker', async () => { useSelectorMock.mockReturnValue({ roles: user.roles }); - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); - expect(screen.getByLabelText('Languages')).toBeInTheDocument(); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + expect(await screen.findByLabelText('Languages')).toBeInTheDocument(); }); -test('should hide create button without proper roles', () => { +test('should hide create button without proper roles', async () => { useSelectorMock.mockReturnValue({ roles: [] }); - render(<Menu {...mockedProps} />, { useRedux: true, useQueryParams: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + expect(await screen.findByText(/sources/i)).toBeInTheDocument(); expect(screen.queryByTestId('new-dropdown')).not.toBeInTheDocument(); }); -test('should render without QueryParamProvider', () => { +test('should render without QueryParamProvider', async () => { useSelectorMock.mockReturnValue({ roles: [] }); - render(<Menu {...mockedProps} />, { useRedux: true }); + render(<Menu {...mockedProps} />, { + useRedux: true, + useRouter: true, + useQueryParams: true, + }); + expect(await screen.findByText(/sources/i)).toBeInTheDocument(); expect(screen.queryByTestId('new-dropdown')).not.toBeInTheDocument(); }); + +test('should render an extension component if one is supplied', async () => { + const extensionsRegistry = getExtensionsRegistry(); + + extensionsRegistry.set('navbar.right', () => ( + <>navbar.right extension component</> + )); + + setupExtensions(); + + render(<Menu {...mockedProps} />, { useRouter: true, useQueryParams: true }); + + expect( + await screen.findByText('navbar.right extension component'), + ).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/views/components/Menu.tsx b/superset-frontend/src/views/components/Menu.tsx index 86502c5276e59..652ae63fd91ce 100644 --- a/superset-frontend/src/views/components/Menu.tsx +++ b/superset-frontend/src/views/components/Menu.tsx @@ -25,72 +25,28 @@ import { Row, Col, Grid } from 'src/components'; import { MainNav as DropdownMenu, MenuMode } from 'src/components/Menu'; import { Tooltip } from 'src/components/Tooltip'; import { Link } from 'react-router-dom'; +import { GenericLink } from 'src/components/GenericLink/GenericLink'; import Icons from 'src/components/Icons'; import { useUiConfig } from 'src/components/UiConfigContext'; import { URL_PARAMS } from 'src/constants'; -import RightMenu from './MenuRight'; -import { Languages } from './LanguagePicker'; +import { + MenuObjectChildProps, + MenuObjectProps, + MenuData, +} from 'src/types/bootstrapTypes'; +import RightMenu from './RightMenu'; -interface BrandProps { - path: string; - icon: string; - alt: string; - tooltip: string; - text: string; -} - -export interface NavBarProps { - show_watermark: boolean; - bug_report_url?: string; - version_string?: string; - version_sha?: string; - build_number?: string; - documentation_url?: string; - languages: Languages; - show_language_picker: boolean; - user_is_anonymous: boolean; - user_info_url: string; - user_login_url: string; - user_logout_url: string; - user_profile_url: string | null; - locale: string; -} - -export interface MenuProps { - data: { - menu: MenuObjectProps[]; - brand: BrandProps; - navbar_right: NavBarProps; - settings: MenuObjectProps[]; - environment_tag: { - text: string; - color: string; - }; - }; +interface MenuProps { + data: MenuData; isFrontendRoute?: (path?: string) => boolean; } -export interface MenuObjectChildProps { - label: string; - name?: string; - icon?: string; - index?: number; - url?: string; - isFrontendRoute?: boolean; - perm?: string | boolean; - view?: string; - disable?: boolean; -} - -export interface MenuObjectProps extends MenuObjectChildProps { - childs?: (MenuObjectChildProps | string)[]; - isHeader?: boolean; -} - const StyledHeader = styled.header` ${({ theme }) => ` background-color: ${theme.colors.grayscale.light5}; margin-bottom: 2px; + z-index: 10; + &:nth-last-of-type(2) nav { margin-bottom: 2px; } @@ -106,7 +62,7 @@ const StyledHeader = styled.header` padding: ${theme.gridUnit}px ${theme.gridUnit * 2}px ${ theme.gridUnit }px ${theme.gridUnit * 4}px; - max-width: ${theme.gridUnit * 37}px; + max-width: ${theme.gridUnit * theme.brandIconMaxWidth}px; img { height: 100%; object-fit: contain; @@ -159,7 +115,7 @@ const StyledHeader = styled.header` .ant-menu > .ant-menu-item > a { padding: 0px; } - .main-nav .ant-menu-submenu-title > svg:nth-child(1) { + .main-nav .ant-menu-submenu-title > svg:nth-of-type(1) { display: none; } .ant-menu-item-active > a { @@ -292,9 +248,15 @@ export function Menu({ title={brand.tooltip} arrowPointAtCenter > - <a className="navbar-brand" href={brand.path}> - <img src={brand.icon} alt={brand.alt} /> - </a> + {isFrontendRoute(window.location.pathname) ? ( + <GenericLink className="navbar-brand" to={brand.path}> + <img src={brand.icon} alt={brand.alt} /> + </GenericLink> + ) : ( + <a className="navbar-brand" href={brand.path}> + <img src={brand.icon} alt={brand.alt} /> + </a> + )} </Tooltip> {brand.text && ( <div className="navbar-brand-text"> @@ -348,6 +310,7 @@ export default function MenuWrapper({ data, ...rest }: MenuProps) { }; // Menu items that should go into settings dropdown const settingsMenus = { + Data: true, Security: true, Manage: true, }; diff --git a/superset-frontend/src/views/components/RightMenu.test.tsx b/superset-frontend/src/views/components/RightMenu.test.tsx new file mode 100644 index 0000000000000..907c305ff64c8 --- /dev/null +++ b/superset-frontend/src/views/components/RightMenu.test.tsx @@ -0,0 +1,354 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import * as reactRedux from 'react-redux'; +import fetchMock from 'fetch-mock'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import RightMenu from './RightMenu'; +import { GlobalMenuDataOptions, RightMenuProps } from './types'; + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest.fn(), +})); + +jest.mock('src/views/CRUD/data/database/DatabaseModal', () => () => <span />); + +const dropdownItems = [ + { + label: 'Data', + icon: 'fa-database', + childs: [ + { + label: 'Connect database', + name: GlobalMenuDataOptions.DB_CONNECTION, + perm: true, + }, + { + label: 'Create dataset', + name: GlobalMenuDataOptions.DATASET_CREATION, + perm: true, + }, + { + label: 'Connect Google Sheet', + name: GlobalMenuDataOptions.GOOGLE_SHEETS, + perm: true, + }, + { + label: 'Upload CSV to database', + name: 'Upload a CSV', + url: '/csvtodatabaseview/form', + perm: true, + }, + { + label: 'Upload columnar file to database', + name: 'Upload a Columnar file', + url: '/columnartodatabaseview/form', + perm: true, + }, + { + label: 'Upload Excel file to database', + name: 'Upload Excel', + url: '/exceltodatabaseview/form', + perm: true, + }, + ], + }, + { + label: 'SQL query', + url: '/superset/sqllab?new=true', + icon: 'fa-fw fa-search', + perm: 'can_sqllab', + view: 'Superset', + }, + { + label: 'Chart', + url: '/chart/add', + icon: 'fa-fw fa-bar-chart', + perm: 'can_write', + view: 'Chart', + }, + { + label: 'Dashboard', + url: '/dashboard/new', + icon: 'fa-fw fa-dashboard', + perm: 'can_write', + view: 'Dashboard', + }, +]; + +const createProps = (): RightMenuProps => ({ + align: 'flex-end', + navbarRight: { + show_watermark: false, + bug_report_url: undefined, + documentation_url: undefined, + languages: { + en: { + flag: 'us', + name: 'English', + url: '/lang/en', + }, + it: { + flag: 'it', + name: 'Italian', + url: '/lang/it', + }, + }, + show_language_picker: false, + user_is_anonymous: false, + user_info_url: '/users/userinfo/', + user_logout_url: '/logout/', + user_login_url: '/login/', + user_profile_url: '/profile/', + locale: 'en', + version_string: '1.0.0', + version_sha: 'randomSHA', + build_number: 'randomBuildNumber', + }, + settings: [], + isFrontendRoute: () => true, + environmentTag: { + color: 'error.base', + text: 'Development2', + }, +}); + +const mockNonExamplesDB = [...new Array(2)].map((_, i) => ({ + changed_by: { + first_name: `user`, + last_name: `${i}`, + }, + database_name: `db ${i}`, + backend: 'postgresql', + allow_run_async: true, + allow_dml: false, + allow_file_upload: true, + expose_in_sqllab: false, + changed_on_delta_humanized: `${i} day(s) ago`, + changed_on: new Date().toISOString, + id: i, + engine_information: { + supports_file_upload: true, + }, +})); + +const useSelectorMock = jest.spyOn(reactRedux, 'useSelector'); + +beforeEach(async () => { + useSelectorMock.mockReset(); + fetchMock.get( + 'glob:*api/v1/database/?q=(filters:!((col:allow_file_upload,opr:upload_is_enabled,value:!t)))', + { result: [], count: 0 }, + ); + fetchMock.get( + 'glob:*api/v1/database/?q=(filters:!((col:database_name,opr:neq,value:examples)))', + { result: [], count: 0 }, + ); +}); + +afterEach(fetchMock.restore); + +const resetUseSelectorMock = () => { + useSelectorMock.mockReturnValueOnce({ + createdOn: '2021-04-27T18:12:38.952304', + email: 'admin', + firstName: 'admin', + isActive: true, + lastName: 'admin', + permissions: {}, + roles: { + Admin: [ + ['can_this_form_get', 'CsvToDatabaseView'], // So we can upload CSV + ['can_write', 'Database'], // So we can write DBs + ['can_write', 'Dataset'], // So we can write Datasets + ['can_write', 'Chart'], // So we can write Datasets + ], + }, + userId: 1, + username: 'admin', + }); + + // By default we get file extensions to be uploaded + useSelectorMock.mockReturnValueOnce('1'); + // By default we get file extensions to be uploaded + useSelectorMock.mockReturnValueOnce({ + CSV_EXTENSIONS: ['csv'], + EXCEL_EXTENSIONS: ['xls', 'xlsx'], + COLUMNAR_EXTENSIONS: ['parquet', 'zip'], + ALLOWED_EXTENSIONS: ['parquet', 'zip', 'xls', 'xlsx', 'csv'], + }); +}; + +test('renders', async () => { + const mockedProps = createProps(); + // Initial Load + resetUseSelectorMock(); + const { container } = render(<RightMenu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + }); + // expect(await screen.findByText(/Settings/i)).toBeInTheDocument(); + await waitFor(() => expect(container).toBeInTheDocument()); +}); + +test('If user has permission to upload files AND connect DBs we query existing DBs that has allow_file_upload as True and DBs that are not examples', async () => { + const mockedProps = createProps(); + // Initial Load + resetUseSelectorMock(); + const { container } = render(<RightMenu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + }); + await waitFor(() => expect(container).toBeVisible()); + const callsD = fetchMock.calls(/database\/\?q/); + expect(callsD).toHaveLength(2); + expect(callsD[0][0]).toMatchInlineSnapshot( + `"http://localhost/api/v1/database/?q=(filters:!((col:allow_file_upload,opr:upload_is_enabled,value:!t)))"`, + ); + expect(callsD[1][0]).toMatchInlineSnapshot( + `"http://localhost/api/v1/database/?q=(filters:!((col:database_name,opr:neq,value:examples)))"`, + ); +}); + +test('If only examples DB exist we must show the Connect Database option', async () => { + const mockedProps = createProps(); + fetchMock.get( + 'glob:*api/v1/database/?q=(filters:!((col:allow_file_upload,opr:upload_is_enabled,value:!t)))', + { result: [...mockNonExamplesDB], count: 2 }, + { overwriteRoutes: true }, + ); + fetchMock.get( + 'glob:*api/v1/database/?q=(filters:!((col:database_name,opr:neq,value:examples)))', + { result: [], count: 0 }, + { overwriteRoutes: true }, + ); + // Initial Load + resetUseSelectorMock(); + // setAllowUploads called + resetUseSelectorMock(); + render(<RightMenu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + const dropdown = screen.getByTestId('new-dropdown-icon'); + userEvent.hover(dropdown); + const dataMenu = await screen.findByText(dropdownItems[0].label); + userEvent.hover(dataMenu); + expect(await screen.findByText('Connect database')).toBeInTheDocument(); + expect(screen.queryByText('Create dataset')).not.toBeInTheDocument(); +}); + +test('If more than just examples DB exist we must show the Create dataset option', async () => { + const mockedProps = createProps(); + fetchMock.get( + 'glob:*api/v1/database/?q=(filters:!((col:allow_file_upload,opr:upload_is_enabled,value:!t)))', + { result: [...mockNonExamplesDB], count: 2 }, + { overwriteRoutes: true }, + ); + fetchMock.get( + 'glob:*api/v1/database/?q=(filters:!((col:database_name,opr:neq,value:examples)))', + { result: [...mockNonExamplesDB], count: 2 }, + { overwriteRoutes: true }, + ); + // Initial Load + resetUseSelectorMock(); + // setAllowUploads called + resetUseSelectorMock(); + // setNonExamplesDBConnected called + resetUseSelectorMock(); + render(<RightMenu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + const dropdown = screen.getByTestId('new-dropdown-icon'); + userEvent.hover(dropdown); + const dataMenu = await screen.findByText(dropdownItems[0].label); + userEvent.hover(dataMenu); + expect(await screen.findByText('Create dataset')).toBeInTheDocument(); + expect(screen.queryByText('Connect database')).not.toBeInTheDocument(); +}); + +test('If there is a DB with allow_file_upload set as True the option should be enabled', async () => { + const mockedProps = createProps(); + fetchMock.get( + 'glob:*api/v1/database/?q=(filters:!((col:allow_file_upload,opr:upload_is_enabled,value:!t)))', + { result: [...mockNonExamplesDB], count: 2 }, + { overwriteRoutes: true }, + ); + fetchMock.get( + 'glob:*api/v1/database/?q=(filters:!((col:database_name,opr:neq,value:examples)))', + { result: [...mockNonExamplesDB], count: 2 }, + { overwriteRoutes: true }, + ); + // Initial load + resetUseSelectorMock(); + // setAllowUploads called + resetUseSelectorMock(); + // setNonExamplesDBConnected called + resetUseSelectorMock(); + render(<RightMenu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + const dropdown = screen.getByTestId('new-dropdown-icon'); + userEvent.hover(dropdown); + const dataMenu = await screen.findByText(dropdownItems[0].label); + userEvent.hover(dataMenu); + expect( + (await screen.findByText('Upload CSV to database')).closest('a'), + ).toHaveAttribute('href', '/csvtodatabaseview/form'); +}); + +test('If there is NOT a DB with allow_file_upload set as True the option should be disabled', async () => { + const mockedProps = createProps(); + fetchMock.get( + 'glob:*api/v1/database/?q=(filters:!((col:allow_file_upload,opr:upload_is_enabled,value:!t)))', + { result: [], count: 0 }, + { overwriteRoutes: true }, + ); + fetchMock.get( + 'glob:*api/v1/database/?q=(filters:!((col:database_name,opr:neq,value:examples)))', + { result: [...mockNonExamplesDB], count: 2 }, + { overwriteRoutes: true }, + ); + // Initial load + resetUseSelectorMock(); + // setAllowUploads called + resetUseSelectorMock(); + // setNonExamplesDBConnected called + resetUseSelectorMock(); + render(<RightMenu {...mockedProps} />, { + useRedux: true, + useQueryParams: true, + useRouter: true, + }); + const dropdown = screen.getByTestId('new-dropdown-icon'); + userEvent.hover(dropdown); + const dataMenu = await screen.findByText(dropdownItems[0].label); + userEvent.hover(dataMenu); + expect(await screen.findByText('Upload CSV to database')).toBeInTheDocument(); + expect( + (await screen.findByText('Upload CSV to database')).closest('a'), + ).not.toBeInTheDocument(); +}); diff --git a/superset-frontend/src/views/components/MenuRight.tsx b/superset-frontend/src/views/components/RightMenu.tsx similarity index 65% rename from superset-frontend/src/views/components/MenuRight.tsx rename to superset-frontend/src/views/components/RightMenu.tsx index 179301e926940..e245096f43c22 100644 --- a/superset-frontend/src/views/components/MenuRight.tsx +++ b/superset-frontend/src/views/components/RightMenu.tsx @@ -21,6 +21,7 @@ import rison from 'rison'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import { useQueryParams, BooleanParam } from 'use-query-params'; +import { isEmpty } from 'lodash'; import { t, @@ -28,23 +29,31 @@ import { css, SupersetTheme, SupersetClient, + getExtensionsRegistry, + useTheme, } from '@superset-ui/core'; import { MainNav as Menu } from 'src/components/Menu'; import { Tooltip } from 'src/components/Tooltip'; import Icons from 'src/components/Icons'; -import findPermission, { isUserAdmin } from 'src/dashboard/util/findPermission'; -import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; +import Label from 'src/components/Label'; +import { findPermission } from 'src/utils/findPermission'; +import { isUserAdmin } from 'src/dashboard/util/permissionUtils'; +import { + MenuObjectProps, + UserWithPermissionsAndRoles, + MenuObjectChildProps, +} from 'src/types/bootstrapTypes'; import { RootState } from 'src/dashboard/types'; -import { Tag } from 'antd'; import LanguagePicker from './LanguagePicker'; import DatabaseModal from '../CRUD/data/database/DatabaseModal'; import { uploadUserPerms } from '../CRUD/utils'; import { - ExtentionConfigs, + ExtensionConfigs, GlobalMenuDataOptions, RightMenuProps, } from './types'; -import { MenuObjectProps } from './Menu'; + +const extensionsRegistry = getExtensionsRegistry(); const versionInfoStyles = (theme: SupersetTheme) => css` padding: ${theme.gridUnit * 1.5}px ${theme.gridUnit * 4}px @@ -77,11 +86,29 @@ const StyledDiv = styled.div<{ align: string }>` } `; +const StyledMenuItemWithIcon = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; +`; + const StyledAnchor = styled.a` padding-right: ${({ theme }) => theme.gridUnit}px; padding-left: ${({ theme }) => theme.gridUnit}px; `; +const tagStyles = (theme: SupersetTheme) => css` + color: ${theme.colors.grayscale.light5}; +`; + +const styledChildMenu = (theme: SupersetTheme) => css` + &:hover { + color: ${theme.colors.primary.base} !important; + cursor: pointer !important; + } +`; + const { SubMenu } = Menu; const RightMenu = ({ @@ -92,7 +119,13 @@ const RightMenu = ({ environmentTag, setQuery, }: RightMenuProps & { - setQuery: ({ databaseAdded }: { databaseAdded: boolean }) => void; + setQuery: ({ + databaseAdded, + datasetAdded, + }: { + databaseAdded?: boolean; + datasetAdded?: boolean; + }) => void; }) => { const user = useSelector<any, UserWithPermissionsAndRoles>( state => state.user, @@ -100,21 +133,22 @@ const RightMenu = ({ const dashboardId = useSelector<RootState, number | undefined>( state => state.dashboardInfo?.id, ); - - const { roles } = user; + const userValues = user || {}; + const { roles } = userValues; const { CSV_EXTENSIONS, COLUMNAR_EXTENSIONS, EXCEL_EXTENSIONS, ALLOWED_EXTENSIONS, HAS_GSHEETS_INSTALLED, - } = useSelector<any, ExtentionConfigs>(state => state.common.conf); - const [showModal, setShowModal] = useState<boolean>(false); + } = useSelector<any, ExtensionConfigs>(state => state.common.conf); + const [showDatabaseModal, setShowDatabaseModal] = useState<boolean>(false); const [engine, setEngine] = useState<string>(''); const canSql = findPermission('can_sqllab', 'Superset', roles); const canDashboard = findPermission('can_write', 'Dashboard', roles); const canChart = findPermission('can_write', 'Chart', roles); const canDatabase = findPermission('can_write', 'Database', roles); + const canDataset = findPermission('can_write', 'Dataset', roles); const { canUploadData, canUploadCSV, canUploadColumnar, canUploadExcel } = uploadUserPerms( @@ -127,6 +161,8 @@ const RightMenu = ({ const showActionDropdown = canSql || canChart || canDashboard; const [allowUploads, setAllowUploads] = useState<boolean>(false); + const [nonExamplesDBConnected, setNonExamplesDBConnected] = + useState<boolean>(false); const isAdmin = isUserAdmin(user); const showUploads = allowUploads || isAdmin; const dropdownItems: MenuObjectProps[] = [ @@ -137,7 +173,13 @@ const RightMenu = ({ { label: t('Connect database'), name: GlobalMenuDataOptions.DB_CONNECTION, - perm: canDatabase, + perm: canDatabase && !nonExamplesDBConnected, + }, + { + label: t('Create dataset'), + name: GlobalMenuDataOptions.DATASET_CREATION, + url: '/dataset/add/', + perm: canDataset && nonExamplesDBConnected, }, { label: t('Connect Google Sheet'), @@ -149,18 +191,21 @@ const RightMenu = ({ name: 'Upload a CSV', url: '/csvtodatabaseview/form', perm: canUploadCSV && showUploads, + disable: isAdmin && !allowUploads, }, { label: t('Upload columnar file to database'), name: 'Upload a Columnar file', url: '/columnartodatabaseview/form', perm: canUploadColumnar && showUploads, + disable: isAdmin && !allowUploads, }, { label: t('Upload Excel file to database'), name: 'Upload Excel', url: '/exceltodatabaseview/form', perm: canUploadExcel && showUploads, + disable: isAdmin && !allowUploads, }, ], }, @@ -198,7 +243,24 @@ const RightMenu = ({ SupersetClient.get({ endpoint: `/api/v1/database/?q=${rison.encode(payload)}`, }).then(({ json }: Record<string, any>) => { - setAllowUploads(json.count >= 1); + // There might be some existings Gsheets and Clickhouse DBs + // with allow_file_upload set as True which is not possible from now on + const allowedDatabasesWithFileUpload = + json?.result?.filter( + (database: any) => database?.engine_information?.supports_file_upload, + ) || []; + setAllowUploads(allowedDatabasesWithFileUpload?.length >= 1); + }); + }; + + const existsNonExamplesDatabases = () => { + const payload = { + filters: [{ col: 'database_name', opr: 'neq', value: 'examples' }], + }; + SupersetClient.get({ + endpoint: `/api/v1/database/?q=${rison.encode(payload)}`, + }).then(({ json }: Record<string, any>) => { + setNonExamplesDBConnected(json.count >= 1); }); }; @@ -208,6 +270,12 @@ const RightMenu = ({ } }, [canUploadData]); + useEffect(() => { + if (canDatabase || canDataset) { + existsNonExamplesDatabases(); + } + }, [canDatabase, canDataset]); + const menuIconAndLabel = (menu: MenuObjectProps) => ( <> <i data-test={`menu-item-${menu.label}`} className={`fa ${menu.icon}`} /> @@ -217,62 +285,84 @@ const RightMenu = ({ const handleMenuSelection = (itemChose: any) => { if (itemChose.key === GlobalMenuDataOptions.DB_CONNECTION) { - setShowModal(true); + setShowDatabaseModal(true); } else if (itemChose.key === GlobalMenuDataOptions.GOOGLE_SHEETS) { - setShowModal(true); + setShowDatabaseModal(true); setEngine('Google Sheets'); } }; const handleOnHideModal = () => { setEngine(''); - setShowModal(false); + setShowDatabaseModal(false); }; - const isDisabled = isAdmin && !allowUploads; - const tooltipText = t( - "Enable 'Allow data upload' in any database's settings", + "Enable 'Allow file uploads to database' in any database's settings", ); - const buildMenuItem = (item: Record<string, any>) => { - const disabledText = isDisabled && item.url; - return disabledText ? ( + const buildMenuItem = (item: MenuObjectChildProps) => + item.disable ? ( <Menu.Item key={item.name} css={styledDisabled}> <Tooltip placement="top" title={tooltipText}> {item.label} </Tooltip> </Menu.Item> ) : ( - <Menu.Item key={item.name}> + <Menu.Item key={item.name} css={styledChildMenu}> {item.url ? <a href={item.url}> {item.label} </a> : item.label} </Menu.Item> ); - }; const onMenuOpen = (openKeys: string[]) => { - if (openKeys.length && canUploadData) { - return checkAllowUploads(); + // We should query the API only if opening Data submenus + // because the rest don't need this information. Not using + // "Data" directly since we might change the label later on? + if ( + openKeys.length > 1 && + !isEmpty( + openKeys?.filter((key: string) => + key.includes(`sub2_${dropdownItems?.[0]?.label}`), + ), + ) + ) { + if (canUploadData) checkAllowUploads(); + if (canDatabase || canDataset) existsNonExamplesDatabases(); } return null; }; + const RightMenuExtension = extensionsRegistry.get('navbar.right'); + const RightMenuItemIconExtension = extensionsRegistry.get( + 'navbar.right-menu.item.icon', + ); const handleDatabaseAdd = () => setQuery({ databaseAdded: true }); + const theme = useTheme(); + return ( <StyledDiv align={align}> {canDatabase && ( <DatabaseModal onHide={handleOnHideModal} - show={showModal} + show={showDatabaseModal} dbEngine={engine} onDatabaseAdd={handleDatabaseAdd} /> )} - {environmentTag.text && ( - <Tag css={{ borderRadius: '500px' }} color={environmentTag.color}> - {environmentTag.text} - </Tag> + {environmentTag?.text && ( + <Label + css={{ borderRadius: `${theme.gridUnit * 125}px` }} + color={ + /^#(?:[0-9a-f]{3}){1,2}$/i.test(environmentTag.color) + ? environmentTag.color + : environmentTag.color + .split('.') + .reduce((o, i) => o[i], theme.colors) + } + > + <span css={tagStyles}>{environmentTag.text}</span> + </Label> )} <Menu selectable={false} @@ -280,6 +370,7 @@ const RightMenu = ({ onClick={handleMenuSelection} onOpenChange={onMenuOpen} > + {RightMenuExtension && <RightMenuExtension />} {!navbarRight.user_is_anonymous && showActionDropdown && ( <SubMenu data-test="new-dropdown" @@ -288,7 +379,7 @@ const RightMenu = ({ } icon={<Icons.TriangleDown />} > - {dropdownItems.map(menu => { + {dropdownItems?.map?.(menu => { const canShowChild = menu.childs?.some( item => typeof item === 'object' && !!item.perm, ); @@ -300,10 +391,10 @@ const RightMenu = ({ className="data-menu" title={menuIconAndLabel(menu)} > - {menu.childs.map((item, idx) => + {menu?.childs?.map?.((item, idx) => typeof item !== 'string' && item.name && item.perm ? ( <Fragment key={item.name}> - {idx === 2 && <Menu.Divider />} + {idx === 3 && <Menu.Divider />} {buildMenuItem(item)} </Fragment> ) : null, @@ -322,13 +413,23 @@ const RightMenu = ({ roles, ) && ( <Menu.Item key={menu.label}> - <a href={menu.url}> - <i - data-test={`menu-item-${menu.label}`} - className={`fa ${menu.icon}`} - />{' '} - {menu.label} - </a> + {isFrontendRoute(menu.url) ? ( + <Link to={menu.url || ''}> + <i + data-test={`menu-item-${menu.label}`} + className={`fa ${menu.icon}`} + />{' '} + {menu.label} + </Link> + ) : ( + <a href={menu.url}> + <i + data-test={`menu-item-${menu.label}`} + className={`fa ${menu.icon}`} + />{' '} + {menu.label} + </a> + )} </Menu.Item> ) ); @@ -339,16 +440,24 @@ const RightMenu = ({ title={t('Settings')} icon={<Icons.TriangleDown iconSize="xl" />} > - {settings.map((section, index) => [ + {settings?.map?.((section, index) => [ <Menu.ItemGroup key={`${section.label}`} title={section.label}> - {section.childs?.map(child => { + {section?.childs?.map?.(child => { if (typeof child !== 'string') { + const menuItemDisplay = RightMenuItemIconExtension ? ( + <StyledMenuItemWithIcon> + {child.label} + <RightMenuItemIconExtension menuChild={child} /> + </StyledMenuItemWithIcon> + ) : ( + child.label + ); return ( <Menu.Item key={`${child.label}`}> {isFrontendRoute(child.url) ? ( - <Link to={child.url || ''}>{child.label}</Link> + <Link to={child.url || ''}>{menuItemDisplay}</Link> ) : ( - <a href={child.url}>{child.label}</a> + <a href={child.url}>{menuItemDisplay}</a> )} </Menu.Item> ); @@ -390,17 +499,17 @@ const RightMenu = ({ )} {navbarRight.version_string && ( <div css={versionInfoStyles}> - Version: {navbarRight.version_string} + {t('Version')}: {navbarRight.version_string} </div> )} {navbarRight.version_sha && ( <div css={versionInfoStyles}> - SHA: {navbarRight.version_sha} + {t('SHA')}: {navbarRight.version_sha} </div> )} {navbarRight.build_number && ( <div css={versionInfoStyles}> - Build: {navbarRight.build_number} + {t('Build')}: {navbarRight.build_number} </div> )} </div> @@ -415,25 +524,38 @@ const RightMenu = ({ )} </Menu> {navbarRight.documentation_url && ( - <StyledAnchor - href={navbarRight.documentation_url} - target="_blank" - rel="noreferrer" - title={t('Documentation')} - > - <i className="fa fa-question" /> -   - </StyledAnchor> + <> + <StyledAnchor + href={navbarRight.documentation_url} + target="_blank" + rel="noreferrer" + title={navbarRight.documentation_text || t('Documentation')} + > + {navbarRight.documentation_icon ? ( + <i className={navbarRight.documentation_icon} /> + ) : ( + <i className="fa fa-question" /> + )} + </StyledAnchor> + <span> </span> + </> )} {navbarRight.bug_report_url && ( - <StyledAnchor - href={navbarRight.bug_report_url} - target="_blank" - rel="noreferrer" - title={t('Report a bug')} - > - <i className="fa fa-bug" /> - </StyledAnchor> + <> + <StyledAnchor + href={navbarRight.bug_report_url} + target="_blank" + rel="noreferrer" + title={navbarRight.bug_report_text || t('Report a bug')} + > + {navbarRight.bug_report_icon ? ( + <i className={navbarRight.bug_report_icon} /> + ) : ( + <i className="fa fa-bug" /> + )} + </StyledAnchor> + <span> </span> + </> )} {navbarRight.user_is_anonymous && ( <StyledAnchor href={navbarRight.user_login_url}> @@ -448,6 +570,7 @@ const RightMenu = ({ const RightMenuWithQueryWrapper: React.FC<RightMenuProps> = props => { const [, setQuery] = useQueryParams({ databaseAdded: BooleanParam, + datasetAdded: BooleanParam, }); return <RightMenu setQuery={setQuery} {...props} />; diff --git a/superset-frontend/src/views/components/SubMenu.test.tsx b/superset-frontend/src/views/components/SubMenu.test.tsx index 6359e03cc261f..661787bee9a02 100644 --- a/superset-frontend/src/views/components/SubMenu.test.tsx +++ b/superset-frontend/src/views/components/SubMenu.test.tsx @@ -18,6 +18,7 @@ */ import userEvent from '@testing-library/user-event'; import React from 'react'; +import { BrowserRouter } from 'react-router-dom'; import { render, screen } from 'spec/helpers/testing-library'; import SubMenu, { ButtonProps } from './SubMenu'; @@ -45,7 +46,7 @@ const mockedProps = { ], dropDownLinks: [ { - label: 'test a upload', + label: 'test an upload', childs: [ { label: 'Upload Test', @@ -58,29 +59,43 @@ const mockedProps = { ], }; -test('should render', () => { - const { container } = render(<SubMenu {...mockedProps} />); +const setup = (overrides: Record<string, any> = {}) => { + const props = { + ...mockedProps, + ...overrides, + }; + return render( + <BrowserRouter> + <SubMenu {...props} /> + </BrowserRouter>, + ); +}; + +test('should render', async () => { + const { container } = setup(); + expect(await screen.findByText(/title/i)).toBeInTheDocument(); expect(container).toBeInTheDocument(); }); -test('should render the navigation', () => { - render(<SubMenu {...mockedProps} />); - expect(screen.getByRole('navigation')).toBeInTheDocument(); +test('should render the navigation', async () => { + setup(); + expect(await screen.findByRole('navigation')).toBeInTheDocument(); }); -test('should render the brand', () => { - render(<SubMenu {...mockedProps} />); - expect(screen.getByText('Title')).toBeInTheDocument(); +test('should render the brand', async () => { + setup(); + expect(await screen.findByText('Title')).toBeInTheDocument(); }); -test('should render the right number of tabs', () => { - render(<SubMenu {...mockedProps} />); - expect(screen.getAllByRole('tab')).toHaveLength(3); +test('should render the right number of tabs', async () => { + setup(); + expect(await screen.findAllByRole('tab')).toHaveLength(3); }); -test('should render all the tabs links', () => { +test('should render all the tabs links', async () => { const { tabs } = mockedProps; - render(<SubMenu {...mockedProps} />); + setup(); + expect(await screen.findAllByRole('tab')).toHaveLength(3); tabs.forEach(tab => { const tabItem = screen.getByText(tab.label); expect(tabItem).toHaveAttribute('href', tab.url); @@ -88,13 +103,13 @@ test('should render all the tabs links', () => { }); test('should render dropdownlinks', async () => { - render(<SubMenu {...mockedProps} />); - userEvent.hover(screen.getByText('test a upload')); - const label = await screen.findByText('test a upload'); + setup(); + userEvent.hover(screen.getByText('test an upload')); + const label = await screen.findByText('test an upload'); expect(label).toBeInTheDocument(); }); -test('should render the buttons', () => { +test('should render the buttons', async () => { const mockFunc = jest.fn(); const buttons = [ { @@ -108,13 +123,9 @@ test('should render the buttons', () => { buttonStyle: 'danger' as ButtonProps['buttonStyle'], }, ]; - const buttonsProps = { - ...mockedProps, - buttons, - }; - render(<SubMenu {...buttonsProps} />); + setup({ buttons }); const testButton = screen.getByText(buttons[0].name); - expect(screen.getAllByRole('button')).toHaveLength(3); + expect(await screen.findAllByRole('button')).toHaveLength(3); userEvent.click(testButton); expect(mockFunc).toHaveBeenCalled(); }); diff --git a/superset-frontend/src/views/components/SubMenu.tsx b/superset-frontend/src/views/components/SubMenu.tsx index e51c1e8eca8ce..4d21c0f3a48c4 100644 --- a/superset-frontend/src/views/components/SubMenu.tsx +++ b/superset-frontend/src/views/components/SubMenu.tsx @@ -26,7 +26,7 @@ import { Row } from 'src/components'; import { Menu, MenuMode, MainNav as DropdownMenu } from 'src/components/Menu'; import Button, { OnClickHandler } from 'src/components/Button'; import Icons from 'src/components/Icons'; -import { MenuObjectProps } from './Menu'; +import { MenuObjectProps } from 'src/types/bootstrapTypes'; const StyledHeader = styled.div` margin-bottom: ${({ theme }) => theme.gridUnit * 4}px; @@ -302,7 +302,7 @@ const SubMenuComponent: React.FunctionComponent<SubMenuProps> = props => { <Tooltip placement="top" title={t( - "Enable 'Allow data upload' in any database's settings", + "Enable 'Allow file uploads to database' in any database's settings", )} > {item.label} diff --git a/superset-frontend/src/views/components/types.ts b/superset-frontend/src/views/components/types.ts index 8e0dcdf3d046b..2cdc3ae9240db 100644 --- a/superset-frontend/src/views/components/types.ts +++ b/superset-frontend/src/views/components/types.ts @@ -17,9 +17,9 @@ * under the License. */ -import { NavBarProps, MenuObjectProps } from './Menu'; +import { NavBarProps, MenuObjectProps } from 'src/types/bootstrapTypes'; -export interface ExtentionConfigs { +export interface ExtensionConfigs { ALLOWED_EXTENSIONS: Array<any>; CSV_EXTENSIONS: Array<any>; COLUMNAR_EXTENSIONS: Array<any>; @@ -40,4 +40,5 @@ export interface RightMenuProps { export enum GlobalMenuDataOptions { GOOGLE_SHEETS = 'gsheets', DB_CONNECTION = 'dbconnection', + DATASET_CREATION = 'datasetCreation', } diff --git a/superset-frontend/src/views/menu.tsx b/superset-frontend/src/views/menu.tsx index 166516569198c..287634a29b60e 100644 --- a/superset-frontend/src/views/menu.tsx +++ b/superset-frontend/src/views/menu.tsx @@ -26,14 +26,16 @@ import createCache from '@emotion/cache'; import { ThemeProvider } from '@superset-ui/core'; import Menu from 'src/views/components/Menu'; import { theme } from 'src/preamble'; +import getBootstrapData from 'src/utils/getBootstrapData'; import { Provider } from 'react-redux'; -import { store } from './store'; +import { setupStore } from './store'; -const container = document.getElementById('app'); -const bootstrapJson = container?.getAttribute('data-bootstrap') ?? '{}'; -const bootstrap = JSON.parse(bootstrapJson); -const menu = { ...bootstrap.common.menu_data }; +// Disable connecting to redux debugger so that the React app injected +// Below the menu like SqlLab or Explore can connect its redux store to the debugger +const store = setupStore(true); +const bootstrapData = getBootstrapData(); +const menu = { ...bootstrapData.common.menu_data }; const emotionCache = createCache({ key: 'menu', diff --git a/superset-frontend/src/views/routes.test.tsx b/superset-frontend/src/views/routes.test.tsx index e00c64f4af970..2497dce15a907 100644 --- a/superset-frontend/src/views/routes.test.tsx +++ b/superset-frontend/src/views/routes.test.tsx @@ -16,13 +16,16 @@ * specific language governing permissions and limitations * under the License. */ - +import React from 'react'; import { isFrontendRoute, routes } from './routes'; jest.mock('src/featureFlags', () => ({ ...jest.requireActual<object>('src/featureFlags'), isFeatureEnabled: jest.fn().mockReturnValue(true), })); +jest.mock('src/views/CRUD/welcome/Welcome', () => () => ( + <div data-test="mock-welcome" /> +)); describe('isFrontendRoute', () => { it('returns true if a route matches', () => { diff --git a/superset-frontend/src/views/routes.tsx b/superset-frontend/src/views/routes.tsx index 525860ecef066..cbab3f09fdf39 100644 --- a/superset-frontend/src/views/routes.tsx +++ b/superset-frontend/src/views/routes.tsx @@ -21,6 +21,10 @@ import React, { lazy } from 'react'; // not lazy loaded since this is the home page. import Welcome from 'src/views/CRUD/welcome/Welcome'; +const ChartCreation = lazy( + () => + import(/* webpackChunkName: "ChartCreation" */ 'src/pages/ChartCreation'), +); const AnnotationLayersList = lazy( () => import( @@ -40,10 +44,7 @@ const AnnotationList = lazy( ), ); const ChartList = lazy( - () => - import( - /* webpackChunkName: "ChartList" */ 'src/views/CRUD/chart/ChartList' - ), + () => import(/* webpackChunkName: "ChartList" */ 'src/pages/ChartList'), ); const CssTemplatesList = lazy( () => @@ -75,12 +76,23 @@ const DatasetList = lazy( /* webpackChunkName: "DatasetList" */ 'src/views/CRUD/data/dataset/DatasetList' ), ); + +const AddDataset = lazy( + () => + import( + /* webpackChunkName: "DatasetEditor" */ 'src/views/CRUD/data/dataset/AddDataset/index' + ), +); + const ExecutionLog = lazy( () => import( /* webpackChunkName: "ExecutionLog" */ 'src/views/CRUD/alert/ExecutionLog' ), ); +const ExplorePage = lazy( + () => import(/* webpackChunkName: "ExplorePage" */ 'src/explore/ExplorePage'), +); const QueryList = lazy( () => import( @@ -114,6 +126,10 @@ export const routes: Routes = [ path: '/superset/dashboard/:idOrSlug/', Component: DashboardRoute, }, + { + path: '/chart/add', + Component: ChartCreation, + }, { path: '/chart/list/', Component: ChartList, @@ -135,11 +151,11 @@ export const routes: Routes = [ Component: CssTemplatesList, }, { - path: '/annotationlayermodelview/list/', + path: '/annotationlayer/list/', Component: AnnotationLayersList, }, { - path: '/annotationmodelview/:annotationLayerId/annotation/', + path: '/annotationlayer/:annotationLayerId/annotation/', Component: AnnotationList, }, { @@ -168,6 +184,22 @@ export const routes: Routes = [ isReportEnabled: true, }, }, + { + path: '/explore/', + Component: ExplorePage, + }, + { + path: '/superset/explore/p', + Component: ExplorePage, + }, + { + path: '/dataset/add/', + Component: AddDataset, + }, + { + path: '/dataset/:datasetId', + Component: AddDataset, + }, ]; const frontEndRoutes = routes diff --git a/superset-frontend/src/views/store.ts b/superset-frontend/src/views/store.ts index d363ed2cd99fa..a143deb7379fd 100644 --- a/superset-frontend/src/views/store.ts +++ b/superset-frontend/src/views/store.ts @@ -16,7 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import { applyMiddleware, combineReducers, compose, createStore } from 'redux'; +import { + applyMiddleware, + combineReducers, + compose, + createStore, + Store, +} from 'redux'; import thunk from 'redux-thunk'; import messageToastReducer from 'src/components/MessageToasts/reducers'; import { initEnhancer } from 'src/reduxUtils'; @@ -27,15 +33,28 @@ import dashboardInfo from 'src/dashboard/reducers/dashboardInfo'; import dashboardState from 'src/dashboard/reducers/dashboardState'; import dashboardFilters from 'src/dashboard/reducers/dashboardFilters'; import nativeFilters from 'src/dashboard/reducers/nativeFilters'; -import datasources from 'src/dashboard/reducers/datasources'; +import dashboardDatasources from 'src/dashboard/reducers/datasources'; import sliceEntities from 'src/dashboard/reducers/sliceEntities'; import dashboardLayout from 'src/dashboard/reducers/undoableDashboardLayout'; import logger from 'src/middleware/loggerMiddleware'; +import saveModal from 'src/explore/reducers/saveModalReducer'; +import explore from 'src/explore/reducers/exploreReducer'; +import exploreDatasources from 'src/explore/reducers/datasourcesReducer'; +import { DatasourcesState } from 'src/dashboard/types'; +import { + DatasourcesActionPayload, + DatasourcesAction, +} from 'src/dashboard/actions/datasources'; import shortid from 'shortid'; import { BootstrapUser, + UndefinedUser, UserWithPermissionsAndRoles, } from 'src/types/bootstrapTypes'; +import { AnyDatasourcesAction } from 'src/explore/actions/datasourcesActions'; +import { HydrateExplore } from 'src/explore/actions/hydrateExplore'; +import getBootstrapData from 'src/utils/getBootstrapData'; +import { Dataset } from '@superset-ui/chart-controls'; // Some reducers don't do anything, and redux is just used to reference the initial "state". // This may change later, as the client application takes on more responsibilities. @@ -44,22 +63,7 @@ const noopReducer = (state: STATE = initialState) => state; -const container = document.getElementById('app'); -const bootstrap = JSON.parse(container?.getAttribute('data-bootstrap') ?? '{}'); - -// reducers used only in the dashboard page -const dashboardReducers = { - charts, - datasources, - dashboardInfo, - dashboardFilters, - dataMask, - nativeFilters, - dashboardState, - dashboardLayout, - sliceEntities, - reports, -}; +const bootstrapData = getBootstrapData(); export const USER_LOADED = 'USER_LOADED'; @@ -69,26 +73,75 @@ export type UserLoadedAction = { }; const userReducer = ( - user: BootstrapUser = bootstrap.user || {}, + user = bootstrapData.user || {}, action: UserLoadedAction, -): BootstrapUser => { +): BootstrapUser | UndefinedUser => { if (action.type === USER_LOADED) { return action.user; } return user; }; +// TODO: This reducer is a combination of the Dashboard and Explore reducers. +// The correct way of handling this is to unify the actions and reducers from both +// modules in shared files. This involves a big refactor to unify the parameter types +// and move files around. We should tackle this in a specific PR. +const CombinedDatasourceReducers = ( + datasources: DatasourcesState | undefined | { [key: string]: Dataset }, + action: DatasourcesActionPayload | AnyDatasourcesAction | HydrateExplore, +) => { + if (action.type === DatasourcesAction.SET_DATASOURCES) { + return dashboardDatasources( + datasources as DatasourcesState | undefined, + action as DatasourcesActionPayload, + ); + } + return exploreDatasources( + datasources as { [key: string]: Dataset }, + action as AnyDatasourcesAction | HydrateExplore, + ); +}; + // exported for tests export const rootReducer = combineReducers({ messageToasts: messageToastReducer, - common: noopReducer(bootstrap.common || {}), + common: noopReducer(bootstrapData.common), user: userReducer, impressionId: noopReducer(shortid.generate()), - ...dashboardReducers, + charts, + datasources: CombinedDatasourceReducers, + dashboardInfo, + dashboardFilters, + dataMask, + nativeFilters, + dashboardState, + dashboardLayout, + sliceEntities, + reports, + saveModal, + explore, }); -export const store = createStore( +export const store: Store = createStore( rootReducer, {}, compose(applyMiddleware(thunk, logger), initEnhancer(false)), ); + +/* In some cases the jinja template injects two seperate React apps into basic.html + * One for the top navigation Menu and one for the application below the Menu + * The first app to connect to the Redux debugger wins which is the menu blocking + * the application from being able to connect to the redux debugger. + * setupStore with disableDebugger true enables the menu.tsx component to avoid connecting + * to redux debugger so the application can connect to redux debugger + */ +export function setupStore(disableDegugger = false): Store { + return createStore( + rootReducer, + {}, + compose( + applyMiddleware(thunk, logger), + initEnhancer(false, undefined, disableDegugger), + ), + ); +} diff --git a/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx b/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx index d734cf943dc67..b90d82289e67f 100644 --- a/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx +++ b/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx @@ -20,7 +20,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import { debounce } from 'lodash'; import { max as d3Max } from 'd3-array'; -import { AsyncCreatableSelect, CreatableSelect } from 'src/components/Select'; +import { + AsyncCreatableSelect, + CreatableSelect, +} from 'src/components/DeprecatedSelect'; import Button from 'src/components/Button'; import { css, @@ -43,7 +46,7 @@ import ControlRow from 'src/explore/components/ControlRow'; import Control from 'src/explore/components/Control'; import { controls } from 'src/explore/controls'; import { getExploreUrl } from 'src/explore/exploreUtils'; -import OnPasteSelect from 'src/components/Select/OnPasteSelect'; +import OnPasteSelect from 'src/components/DeprecatedSelect/OnPasteSelect'; import { FILTER_CONFIG_ATTRIBUTES, FILTER_OPTIONS_LIMIT, @@ -81,8 +84,6 @@ const propTypes = { showDateFilter: PropTypes.bool, showSqlaTimeGrain: PropTypes.bool, showSqlaTimeColumn: PropTypes.bool, - showDruidTimeGrain: PropTypes.bool, - showDruidTimeOrigin: PropTypes.bool, }; const defaultProps = { origSelectedValues: {}, @@ -92,8 +93,6 @@ const defaultProps = { showDateFilter: false, showSqlaTimeGrain: false, showSqlaTimeColumn: false, - showDruidTimeGrain: false, - showDruidTimeOrigin: false, instantFiltering: false, }; @@ -319,19 +318,12 @@ class FilterBox extends React.PureComponent { } renderDatasourceFilters() { - const { - showSqlaTimeGrain, - showSqlaTimeColumn, - showDruidTimeGrain, - showDruidTimeOrigin, - } = this.props; + const { showSqlaTimeGrain, showSqlaTimeColumn } = this.props; const datasourceFilters = []; const sqlaFilters = []; const druidFilters = []; if (showSqlaTimeGrain) sqlaFilters.push('time_grain_sqla'); if (showSqlaTimeColumn) sqlaFilters.push('granularity_sqla'); - if (showDruidTimeGrain) druidFilters.push('granularity'); - if (showDruidTimeOrigin) druidFilters.push('druid_time_origin'); if (sqlaFilters.length) { datasourceFilters.push( <ControlRow diff --git a/superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js b/superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js index e1f871fa4cf4f..137a2b191af24 100644 --- a/superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js +++ b/superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js @@ -19,6 +19,8 @@ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example1 from './images/example1.jpg'; +import example2 from './images/example2.jpg'; import controlPanel from './controlPanel'; const metadata = new ChartMetadata({ @@ -28,6 +30,7 @@ const metadata = new ChartMetadata({ t(`Chart component that lets you add a custom filter UI in your dashboard. When added to dashboard, a filter box lets users specify specific values or ranges to filter charts by. The charts that each filter box is applied to can be fine tuned as well in the dashboard view. Note that this plugin is being replaced with the new Filters feature that lives in the dashboard view itself. It's easier to use and has more capabilities!`), + exampleGallery: [{ url: example1 }, { url: example2 }], thumbnail, useLegacyApi: true, }); diff --git a/superset-frontend/src/visualizations/FilterBox/controlPanel.jsx b/superset-frontend/src/visualizations/FilterBox/controlPanel.jsx index 8e76c9d8287ff..60bb9c83af9eb 100644 --- a/superset-frontend/src/visualizations/FilterBox/controlPanel.jsx +++ b/superset-frontend/src/visualizations/FilterBox/controlPanel.jsx @@ -32,7 +32,7 @@ export default { name: 'filter_configs', config: { type: 'CollectionControl', - label: 'Filters', + label: t('Filters'), description: t('Filter configuration for the filter box'), validators: [], controlName: 'FilterBoxItemControl', diff --git a/superset-frontend/src/visualizations/FilterBox/images/example1.jpg b/superset-frontend/src/visualizations/FilterBox/images/example1.jpg new file mode 100644 index 0000000000000..cc109ee5aa387 Binary files /dev/null and b/superset-frontend/src/visualizations/FilterBox/images/example1.jpg differ diff --git a/superset-frontend/src/visualizations/FilterBox/images/example2.jpg b/superset-frontend/src/visualizations/FilterBox/images/example2.jpg new file mode 100644 index 0000000000000..17912d52f72cf Binary files /dev/null and b/superset-frontend/src/visualizations/FilterBox/images/example2.jpg differ diff --git a/superset-frontend/src/visualizations/TimeTable/TimeTable.jsx b/superset-frontend/src/visualizations/TimeTable/TimeTable.jsx index 9dd76ffc1565d..6843387ed20f4 100644 --- a/superset-frontend/src/visualizations/TimeTable/TimeTable.jsx +++ b/superset-frontend/src/visualizations/TimeTable/TimeTable.jsx @@ -21,7 +21,7 @@ import PropTypes from 'prop-types'; import Mustache from 'mustache'; import { scaleLinear } from 'd3-scale'; import TableView from 'src/components/TableView'; -import { formatNumber, formatTime, styled } from '@superset-ui/core'; +import { formatNumber, formatTime, styled, t } from '@superset-ui/core'; import { InfoTooltipWithTrigger, MetricOption, @@ -98,12 +98,13 @@ const defaultProps = { url: '', }; +// @z-index-above-dashboard-charts + 1 = 11 const TimeTableStyles = styled.div` height: ${props => props.height}px; overflow: auto; th { - z-index: 1; // to cover sparkline + z-index: 11 !important; // to cover sparkline } `; @@ -118,7 +119,7 @@ const TimeTable = ({ }) => { const memoizedColumns = useMemo( () => [ - { accessor: 'metric', Header: 'Metric' }, + { accessor: 'metric', Header: t('Metric') }, ...columnConfigs.map((columnConfig, i) => ({ accessor: columnConfig.key, cellProps: columnConfig.colType === 'spark' && { diff --git a/superset-frontend/src/visualizations/TimeTable/controlPanel.js b/superset-frontend/src/visualizations/TimeTable/controlPanel.js index a81576b09c393..65988a5ea70aa 100644 --- a/superset-frontend/src/visualizations/TimeTable/controlPanel.js +++ b/superset-frontend/src/visualizations/TimeTable/controlPanel.js @@ -17,7 +17,7 @@ * under the License. */ import { t, validateNonEmpty } from '@superset-ui/core'; -import { sections } from '@superset-ui/chart-controls'; +import { getStandardizedControls, sections } from '@superset-ui/chart-controls'; export default { controlPanelSections: [ @@ -65,4 +65,9 @@ export default { multiple: false, }, }, + formDataOverrides: formData => ({ + ...formData, + groupby: getStandardizedControls().popAllColumns(), + metrics: getStandardizedControls().popAllMetrics(), + }), }; diff --git a/superset-frontend/src/visualizations/TimeTable/images/example.jpg b/superset-frontend/src/visualizations/TimeTable/images/example.jpg new file mode 100644 index 0000000000000..e20c26506602f Binary files /dev/null and b/superset-frontend/src/visualizations/TimeTable/images/example.jpg differ diff --git a/superset-frontend/src/visualizations/TimeTable/index.ts b/superset-frontend/src/visualizations/TimeTable/index.ts index ae7f406646670..7855a3617aa5a 100644 --- a/superset-frontend/src/visualizations/TimeTable/index.ts +++ b/superset-frontend/src/visualizations/TimeTable/index.ts @@ -19,6 +19,7 @@ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import transformProps from './transformProps'; import thumbnail from './images/thumbnail.png'; +import example from './images/example.jpg'; import controlPanel from './controlPanel'; const metadata = new ChartMetadata({ @@ -27,6 +28,7 @@ const metadata = new ChartMetadata({ description: t( 'Compare multiple time series charts (as sparklines) and related metrics quickly.', ), + exampleGallery: [{ url: example }], tags: [ t('Multi-Variables'), t('Comparison'), diff --git a/superset-frontend/src/visualizations/presets/MainPreset.js b/superset-frontend/src/visualizations/presets/MainPreset.js index db25ff233521b..11c68fd8f23c5 100644 --- a/superset-frontend/src/visualizations/presets/MainPreset.js +++ b/superset-frontend/src/visualizations/presets/MainPreset.js @@ -67,6 +67,7 @@ import { EchartsTreemapChartPlugin, EchartsMixedTimeseriesChartPlugin, EchartsTreeChartPlugin, + EchartsSunburstChartPlugin, } from '@superset-ui/plugin-chart-echarts'; import { AdhocFilterPlugin, @@ -76,7 +77,7 @@ import { TimeColumnFilterPlugin, TimeGrainFilterPlugin, GroupByFilterPlugin, -} from 'src/filters/components/'; +} from 'src/filters/components'; import { PivotTableChartPlugin as PivotTableChartPluginV2 } from '@superset-ui/plugin-chart-pivot-table'; import { HandlebarsChartPlugin } from '@superset-ui/plugin-chart-handlebars'; import { @@ -193,6 +194,7 @@ export default class MainPreset extends Preset { new TimeColumnFilterPlugin().configure({ key: 'filter_timecolumn' }), new TimeGrainFilterPlugin().configure({ key: 'filter_timegrain' }), new EchartsTreeChartPlugin().configure({ key: 'tree_chart' }), + new EchartsSunburstChartPlugin().configure({ key: 'sunburst_v2' }), new HandlebarsChartPlugin().configure({ key: 'handlebars' }), ...experimentalplugins, ], diff --git a/superset-frontend/webpack.config.js b/superset-frontend/webpack.config.js index ac0b9b40f6a21..f8428e4418fbb 100644 --- a/superset-frontend/webpack.config.js +++ b/superset-frontend/webpack.config.js @@ -26,6 +26,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); +const createMdxCompiler = require('@storybook/addon-docs/mdx-compiler-plugin'); const { WebpackManifestPlugin, getCompilerHooks, @@ -107,7 +108,7 @@ const plugins = [ entrypoints: entryFiles, }; }, - // Also write maniafest.json to disk when running `npm run dev`. + // Also write manifest.json to disk when running `npm run dev`. // This is required for Flask to work. writeToFileEmit: isDevMode && !isDevServer, }), @@ -209,8 +210,6 @@ const config = { menu: addPreamble('src/views/menu.tsx'), spa: addPreamble('/src/views/index.tsx'), embedded: addPreamble('/src/embedded/index.tsx'), - addSlice: addPreamble('/src/addSlice/index.tsx'), - explore: addPreamble('/src/explore/index.jsx'), sqllab: addPreamble('/src/SqlLab/index.tsx'), profile: addPreamble('/src/profile/index.tsx'), showSavedQuery: [path.join(APP_DIR, '/src/showSavedQuery/index.jsx')], @@ -290,6 +289,9 @@ const config = { // AntD version conflict has been resolved antd: path.resolve(path.join(APP_DIR, './node_modules/antd')), react: path.resolve(path.join(APP_DIR, './node_modules/react')), + // TODO: remove Handlebars alias once Handlebars NPM package has been updated to + // correctly support webpack import (https://github.com/handlebars-lang/handlebars.js/issues/953) + handlebars: 'handlebars/dist/handlebars.js', }, extensions: ['.ts', '.tsx', '.js', '.jsx', '.yml'], fallback: { @@ -323,7 +325,7 @@ const config = { transpileOnly: true, // must override compiler options here, even though we have set // the same options in `tsconfig.json`, because they may still - // be overriden by `tsconfig.json` in node_modules subdirectories. + // be overridden by `tsconfig.json` in node_modules subdirectories. compilerOptions: { esModuleInterop: false, importHelpers: false, @@ -385,6 +387,9 @@ const config = { sourceMap: true, lessOptions: { javascriptEnabled: true, + modifyVars: { + 'root-entry-name': 'default', + }, }, }, }, @@ -444,6 +449,24 @@ const config = { test: /\.geojson$/, type: 'asset/resource', }, + { + test: /\.mdx$/, + use: [ + { + loader: 'babel-loader', + // may or may not need this line depending on your app's setup + options: { + plugins: ['@babel/plugin-transform-react-jsx'], + }, + }, + { + loader: '@mdx-js/loader', + options: { + compilers: [createMdxCompiler({})], + }, + }, + ], + }, ], }, externals: { diff --git a/superset-websocket/.nvmrc b/superset-websocket/.nvmrc index ab155ce138b84..4be2b935c508d 100644 --- a/superset-websocket/.nvmrc +++ b/superset-websocket/.nvmrc @@ -1 +1 @@ -v14.15.5 +v16.9.1 diff --git a/superset-websocket/Dockerfile b/superset-websocket/Dockerfile index 85ff66520dd29..4cc2117f07a3b 100644 --- a/superset-websocket/Dockerfile +++ b/superset-websocket/Dockerfile @@ -12,13 +12,28 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -FROM node:16 +FROM node:16-alpine as build WORKDIR /home/superset-websocket -COPY . . +COPY . ./ -RUN npm ci -RUN npm run build +RUN npm ci && \ + npm run build -CMD ["npm", "start"] + +FROM node:16-alpine + +ENV NODE_ENV=production +WORKDIR /home/superset-websocket + +COPY --from=build /home/superset-websocket/dist ./dist +COPY package*.json ./ + +# Only install production dependencies +RUN npm ci --omit=dev + +# Don't run as root! +USER node + +CMD [ "npm", "start" ] diff --git a/superset-websocket/README.md b/superset-websocket/README.md index 9a61d70025a0a..a0c7563b1f365 100644 --- a/superset-websocket/README.md +++ b/superset-websocket/README.md @@ -57,7 +57,7 @@ In addition to periodic socket connection cleanup, the internal _channels_ regis Install dependencies: ``` -npm install +npm ci ``` ## WebSocket Server Configuration diff --git a/superset-websocket/package-lock.json b/superset-websocket/package-lock.json index 808666237672a..52fb4e26ea568 100644 --- a/superset-websocket/package-lock.json +++ b/superset-websocket/package-lock.json @@ -9,35 +9,35 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "cookie": "^0.4.1", - "hot-shots": "^9.0.0", + "cookie": "^0.5.0", + "hot-shots": "^10.0.0", "ioredis": "^4.28.0", - "jsonwebtoken": "^8.5.1", - "uuid": "^8.3.2", - "winston": "^3.3.3", - "ws": "^8.2.3" + "jsonwebtoken": "^9.0.0", + "uuid": "^9.0.0", + "winston": "^3.8.2", + "ws": "^8.12.1" }, "devDependencies": { - "@types/cookie": "^0.4.1", + "@types/cookie": "^0.5.1", "@types/ioredis": "^4.27.8", "@types/jest": "^27.0.2", - "@types/jsonwebtoken": "^8.5.5", - "@types/node": "^16.11.6", - "@types/uuid": "^8.3.1", - "@types/ws": "^8.2.0", - "@typescript-eslint/eslint-plugin": "^4.19.0", - "@typescript-eslint/parser": "^4.19.0", - "eslint": "^7.32.0", - "eslint-config-prettier": "^7.1.0", + "@types/jsonwebtoken": "^9.0.1", + "@types/node": "^18.13.0", + "@types/uuid": "^9.0.0", + "@types/ws": "^8.5.4", + "@typescript-eslint/eslint-plugin": "^5.52.0", + "@typescript-eslint/parser": "^5.51.0", + "eslint": "^8.34.0", + "eslint-config-prettier": "^8.6.0", "jest": "^27.3.1", - "prettier": "^2.4.1", + "prettier": "^2.8.4", "ts-jest": "^27.0.7", - "ts-node": "^9.1.1", - "typescript": "^4.2.3" + "ts-node": "^10.9.1", + "typescript": "^4.9.5" }, "engines": { "node": "^16.9.1", - "npm": "^7.5.4" + "npm": "^7.5.4 || ^8.1.2" } }, "node_modules/@babel/code-frame": { @@ -635,6 +635,26 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "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==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@dabh/diagnostics": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", @@ -646,29 +666,38 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -680,20 +709,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -1005,13 +1059,38 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@nodelib/fs.scandir": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", - "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.4", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" }, "engines": { @@ -1019,21 +1098,21 @@ } }, "node_modules/@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", - "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.4", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" }, "engines": { @@ -1067,6 +1146,30 @@ "node": ">= 6" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "node_modules/@types/babel__core": { "version": "7.1.16", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", @@ -1109,9 +1212,9 @@ } }, "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==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.1.tgz", + "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", "dev": true }, "node_modules/@types/graceful-fs": { @@ -1167,24 +1270,24 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "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/jsonwebtoken": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.5.tgz", - "integrity": "sha512-OGqtHQ7N5/Ap/TUwO6IgHDuLiAoTmHhGpNvgkCm/F4N6pKzx/RBSfr2OXZSwC6vkfnsEdb6+7DNZVtiXiwdwFw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", + "integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/node": { - "version": "16.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz", - "integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==", + "version": "18.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", + "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", "dev": true }, "node_modules/@types/prettier": { @@ -1193,6 +1296,12 @@ "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", "dev": true }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -1200,15 +1309,15 @@ "dev": true }, "node_modules/@types/uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", "dev": true }, "node_modules/@types/ws": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz", - "integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, "dependencies": { "@types/node": "*" @@ -1230,137 +1339,405 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.19.0.tgz", - "integrity": "sha512-CRQNQ0mC2Pa7VLwKFbrGVTArfdVDdefS+gTw0oC98vSI98IX5A8EVH4BzJ2FOB0YlCmm8Im36Elad/Jgtvveaw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", + "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "4.19.0", - "@typescript-eslint/scope-manager": "4.19.0", - "debug": "^4.1.1", - "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.15", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/type-utils": "5.52.0", + "@typescript-eslint/utils": "5.52.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", + "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0" }, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "dev": true, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.19.0.tgz", - "integrity": "sha512-9/23F1nnyzbHKuoTqFN1iXwN3bvOm/PRIXSBR3qFAYotK/0LveEOHr5JT1WZSzcD6BESl8kPOG3OoDRKO84bHA==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.19.0", - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/typescript-estree": "4.19.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" + "@typescript-eslint/types": "5.52.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.19.0.tgz", - "integrity": "sha512-/uabZjo2ZZhm66rdAu21HA8nQebl3lAIDcybUoOxoI7VbZBYavLIwtOOmykKCJy+Xq6Vw6ugkiwn8Js7D6wieA==", + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz", + "integrity": "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "4.19.0", - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/typescript-estree": "4.19.0", - "debug": "^4.1.1" + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/typescript-estree": "5.51.0", + "debug": "^4.3.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.19.0.tgz", - "integrity": "sha512-GGy4Ba/hLXwJXygkXqMzduqOMc+Na6LrJTZXJWVhRrSuZeXmu8TAnniQVKgj8uTRKe4igO2ysYzH+Np879G75g==", + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz", + "integrity": "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", + "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/utils": "5.52.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", + "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/visitor-keys": "4.19.0" + "@typescript-eslint/types": "5.52.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.19.0.tgz", - "integrity": "sha512-A4iAlexVvd4IBsSTNxdvdepW0D4uR/fwxDrKUa+iEY9UWvGREu2ZyB8ylTENM1SH8F7bVC9ac9+si3LWNxcBuA==", + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz", + "integrity": "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==", "dev": true, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.19.0.tgz", - "integrity": "sha512-3xqArJ/A62smaQYRv2ZFyTA+XxGGWmlDYrsfZG68zJeNbeqRScnhf81rUVa6QG4UgzHnXw5VnMT5cg75dQGDkA==", + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz", + "integrity": "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/visitor-keys": "4.19.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@typescript-eslint/utils": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", + "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" }, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", + "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", + "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.19.0.tgz", - "integrity": "sha512-aGPS6kz//j7XLSlgpzU2SeTqHPsmRYxFztj2vPuMMFJXZudpRSehE3WCV+BaxwZFvfAqMoSd86TEuM0PQ59E/A==", + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz", + "integrity": "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.19.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "5.51.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/abab": { @@ -1437,15 +1814,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1531,15 +1899,6 @@ "node": ">=8" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/async": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", @@ -1911,14 +2270,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/colorspace": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", @@ -1956,18 +2307,13 @@ } }, "node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "engines": { "node": ">= 0.6" } }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -2027,14 +2373,19 @@ } }, "node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, "engines": { "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decimal.js": { @@ -2190,18 +2541,6 @@ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2252,66 +2591,65 @@ } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", "dev": true, "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-config-prettier": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", - "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -2334,24 +2672,21 @@ } }, "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" } }, "node_modules/eslint-visitor-keys": { @@ -2363,14 +2698,11 @@ "node": ">=10" } }, - "node_modules/eslint/node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", @@ -2384,16 +2716,90 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/eslint/node_modules/globals": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz", - "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/eslint/node_modules/levn": { @@ -2409,6 +2815,21 @@ "node": ">= 0.8.0" } }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint/node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -2426,28 +2847,43 @@ "node": ">= 0.8.0" } }, - "node_modules/eslint/node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { - "node": ">= 0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "p-limit": "^3.0.2" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" } }, "node_modules/eslint/node_modules/type-check": { @@ -2463,26 +2899,41 @@ } }, "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/esprima": { @@ -2626,20 +3077,19 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, "node_modules/fast-json-stable-stringify": { @@ -2654,15 +3104,10 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "node_modules/fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, "node_modules/fastq": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", - "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2678,9 +3123,9 @@ } }, "node_modules/fecha": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz", - "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==" + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" }, "node_modules/file-entry-cache": { "version": "6.0.1", @@ -2789,12 +3234,6 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -2873,29 +3312,23 @@ } }, "node_modules/globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "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.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { "node": ">=10" - } - }, - "node_modules/globby/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/graceful-fs": { @@ -2904,6 +3337,12 @@ "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2926,14 +3365,14 @@ } }, "node_modules/hot-shots": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-9.0.0.tgz", - "integrity": "sha512-fpljto22PvfzDGznnzUpWgFMgccyZRtWo+fY8R4ktwipkv3ywDyeaTLijYaM629DEZvtnEDAN00yV6zxzivnpQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-10.0.0.tgz", + "integrity": "sha512-uy/uGpuJk7yuyiKRfZMBNkF1GAOX5O2ifO9rDCaX9jw8fu6eW9QeWC7WRPDI+O98frW1HQgV3+xwjWsZPECIzQ==", "engines": { - "node": ">=6.0.0" + "node": ">=10.0.0" }, "optionalDependencies": { - "unix-dgram": "2.0.x" + "unix-dgram": "2.x" } }, "node_modules/html-encoding-sniffer": { @@ -3003,9 +3442,9 @@ } }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true, "engines": { "node": ">= 4" @@ -3141,9 +3580,9 @@ } }, "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "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" @@ -3161,6 +3600,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-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", @@ -3184,11 +3632,6 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3794,21 +4237,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-util": { "version": "27.3.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz", @@ -3902,6 +4330,16 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4025,13 +4463,10 @@ "dev": 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==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, "bin": { "json5": "lib/cli.js" }, @@ -4040,24 +4475,18 @@ } }, "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "dependencies": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" }, "engines": { - "node": ">=4", - "npm": ">=1.4.28" + "node": ">=12", + "npm": ">=6" } }, "node_modules/jwa": { @@ -4130,14 +4559,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.defaults": { "version": "4.2.0", @@ -4149,40 +4571,10 @@ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, "node_modules/lodash.isarguments": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" }, "node_modules/lodash.memoize": { "version": "4.1.2", @@ -4196,26 +4588,15 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "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=" - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, "node_modules/logform": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", - "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz", + "integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==", "dependencies": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", + "@colors/colors": "1.5.0", "fecha": "^4.2.0", "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, @@ -4223,7 +4604,6 @@ "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" }, @@ -4329,9 +4709,9 @@ } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -4340,12 +4720,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4363,6 +4737,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -4616,15 +4996,18 @@ } }, "node_modules/prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", "dev": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/pretty-format": { @@ -4654,20 +5037,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -4700,7 +5069,21 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/react-is": { "version": "17.0.1", @@ -4746,12 +5129,15 @@ } }, "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, "node_modules/require-directory": { @@ -4763,15 +5149,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -4842,6 +5219,20 @@ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { "queue-microtask": "^1.2.2" } @@ -4851,6 +5242,14 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4870,11 +5269,17 @@ } }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/shebang-command": { @@ -4932,23 +5337,6 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5135,45 +5523,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "node_modules/table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -5319,42 +5668,68 @@ } } }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ts-node": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", - "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", - "dev": true, - "dependencies": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.17", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "bin": { "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", "ts-node-script": "dist/bin-script.js", "ts-node-transpile-only": "dist/bin-transpile.js", "ts-script": "dist/bin-script-deprecated.js" }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">=10.0.0" + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" } }, "node_modules/tslib": { @@ -5418,9 +5793,9 @@ } }, "node_modules/typescript": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", - "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5468,17 +5843,17 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "bin": { "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, "node_modules/v8-to-istanbul": { @@ -5588,58 +5963,39 @@ } }, "node_modules/winston": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", - "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", "dependencies": { + "@colors/colors": "1.5.0", "@dabh/diagnostics": "^2.0.2", - "async": "^3.1.0", + "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.2.0", + "logform": "^2.4.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", - "winston-transport": "^4.4.0" + "winston-transport": "^4.5.0" }, "engines": { - "node": ">= 6.4.0" + "node": ">= 12.0.0" } }, "node_modules/winston-transport": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", - "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", "dependencies": { - "readable-stream": "^2.3.7", - "triple-beam": "^1.2.0" + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" }, "engines": { "node": ">= 6.4.0" } }, - "node_modules/winston-transport/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/winston-transport/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -5685,15 +6041,15 @@ } }, "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": "8.12.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz", + "integrity": "sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -5728,8 +6084,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/yargs": { "version": "16.2.0", @@ -5766,6 +6121,18 @@ "engines": { "node": ">=6" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } }, "dependencies": { @@ -6221,6 +6588,20 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, "@dabh/diagnostics": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", @@ -6232,44 +6613,65 @@ } }, "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "requires": { "type-fest": "^0.20.2" } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } } } }, "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.0", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" } }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, "@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -6517,29 +6919,51 @@ "chalk": "^4.0.0" } }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@nodelib/fs.scandir": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", - "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.4", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", - "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.4", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, @@ -6567,6 +6991,30 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "@types/babel__core": { "version": "7.1.16", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", @@ -6609,9 +7057,9 @@ } }, "@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==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.1.tgz", + "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", "dev": true }, "@types/graceful-fs": { @@ -6667,24 +7115,24 @@ } }, "@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "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/jsonwebtoken": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.5.tgz", - "integrity": "sha512-OGqtHQ7N5/Ap/TUwO6IgHDuLiAoTmHhGpNvgkCm/F4N6pKzx/RBSfr2OXZSwC6vkfnsEdb6+7DNZVtiXiwdwFw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", + "integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==", "dev": true, "requires": { "@types/node": "*" } }, "@types/node": { - "version": "16.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz", - "integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==", + "version": "18.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", + "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", "dev": true }, "@types/prettier": { @@ -6693,6 +7141,12 @@ "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", "dev": true }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, "@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -6700,15 +7154,15 @@ "dev": true }, "@types/uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", "dev": true }, "@types/ws": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz", - "integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, "requires": { "@types/node": "*" @@ -6730,108 +7184,232 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.19.0.tgz", - "integrity": "sha512-CRQNQ0mC2Pa7VLwKFbrGVTArfdVDdefS+gTw0oC98vSI98IX5A8EVH4BzJ2FOB0YlCmm8Im36Elad/Jgtvveaw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", + "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/type-utils": "5.52.0", + "@typescript-eslint/utils": "5.52.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", + "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0" + } + }, + "@typescript-eslint/types": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "dev": true + }, + "@typescript-eslint/visitor-keys": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.52.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + } + } + }, + "@typescript-eslint/parser": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz", + "integrity": "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.19.0", - "@typescript-eslint/scope-manager": "4.19.0", - "debug": "^4.1.1", - "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.15", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/typescript-estree": "5.51.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz", + "integrity": "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", + "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/utils": "5.52.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" }, "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "@typescript-eslint/types": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", + "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "@typescript-eslint/types": "5.52.0", + "eslint-visitor-keys": "^3.3.0" } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true } } }, - "@typescript-eslint/experimental-utils": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.19.0.tgz", - "integrity": "sha512-9/23F1nnyzbHKuoTqFN1iXwN3bvOm/PRIXSBR3qFAYotK/0LveEOHr5JT1WZSzcD6BESl8kPOG3OoDRKO84bHA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.19.0", - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/typescript-estree": "4.19.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.19.0.tgz", - "integrity": "sha512-/uabZjo2ZZhm66rdAu21HA8nQebl3lAIDcybUoOxoI7VbZBYavLIwtOOmykKCJy+Xq6Vw6ugkiwn8Js7D6wieA==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "4.19.0", - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/typescript-estree": "4.19.0", - "debug": "^4.1.1" - } + "@typescript-eslint/types": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz", + "integrity": "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==", + "dev": true }, - "@typescript-eslint/scope-manager": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.19.0.tgz", - "integrity": "sha512-GGy4Ba/hLXwJXygkXqMzduqOMc+Na6LrJTZXJWVhRrSuZeXmu8TAnniQVKgj8uTRKe4igO2ysYzH+Np879G75g==", + "@typescript-eslint/typescript-estree": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz", + "integrity": "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==", "dev": true, "requires": { - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/visitor-keys": "4.19.0" + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" } }, - "@typescript-eslint/types": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.19.0.tgz", - "integrity": "sha512-A4iAlexVvd4IBsSTNxdvdepW0D4uR/fwxDrKUa+iEY9UWvGREu2ZyB8ylTENM1SH8F7bVC9ac9+si3LWNxcBuA==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.19.0.tgz", - "integrity": "sha512-3xqArJ/A62smaQYRv2ZFyTA+XxGGWmlDYrsfZG68zJeNbeqRScnhf81rUVa6QG4UgzHnXw5VnMT5cg75dQGDkA==", + "@typescript-eslint/utils": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", + "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", "dev": true, "requires": { - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/visitor-keys": "4.19.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" }, "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "@typescript-eslint/scope-manager": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", + "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0" + } + }, + "@typescript-eslint/types": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", + "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "@typescript-eslint/types": "5.52.0", + "eslint-visitor-keys": "^3.3.0" } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true } } }, "@typescript-eslint/visitor-keys": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.19.0.tgz", - "integrity": "sha512-aGPS6kz//j7XLSlgpzU2SeTqHPsmRYxFztj2vPuMMFJXZudpRSehE3WCV+BaxwZFvfAqMoSd86TEuM0PQ59E/A==", + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz", + "integrity": "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==", "dev": true, "requires": { - "@typescript-eslint/types": "4.19.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "5.51.0", + "eslint-visitor-keys": "^3.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + } } }, "abab": { @@ -6890,12 +7468,6 @@ "uri-js": "^4.2.2" } }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -6959,12 +7531,6 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "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==", - "dev": true - }, "async": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", @@ -7271,11 +7837,6 @@ "simple-swizzle": "^0.2.2" } }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" - }, "colorspace": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", @@ -7310,14 +7871,9 @@ } }, "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, "create-require": { "version": "1.1.1", @@ -7371,9 +7927,9 @@ } }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } @@ -7497,15 +8053,6 @@ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -7540,61 +8087,57 @@ } }, "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", "dev": true, "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "escape-string-regexp": { "version": "4.0.0", @@ -7602,15 +8145,65 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, "globals": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz", - "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -7621,6 +8214,15 @@ "type-check": "~0.4.0" } }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -7635,21 +8237,30 @@ "word-wrap": "^1.2.3" } }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "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" - } - }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -7662,9 +8273,9 @@ } }, "eslint-config-prettier": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", - "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "requires": {} }, @@ -7679,20 +8290,12 @@ } }, "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "eslint-visitor-keys": "^2.0.0" } }, "eslint-visitor-keys": { @@ -7702,20 +8305,26 @@ "dev": true }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" }, "dependencies": { + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true } } @@ -7824,17 +8433,16 @@ "dev": true }, "fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" } }, "fast-json-stable-stringify": { @@ -7849,15 +8457,10 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, "fastq": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", - "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -7873,9 +8476,9 @@ } }, "fecha": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz", - "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==" + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" }, "file-entry-cache": { "version": "6.0.1", @@ -7962,12 +8565,6 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -8022,25 +8619,17 @@ "dev": true }, "globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "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.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - } } }, "graceful-fs": { @@ -8049,6 +8638,12 @@ "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -8065,11 +8660,11 @@ "dev": true }, "hot-shots": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-9.0.0.tgz", - "integrity": "sha512-fpljto22PvfzDGznnzUpWgFMgccyZRtWo+fY8R4ktwipkv3ywDyeaTLijYaM629DEZvtnEDAN00yV6zxzivnpQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-10.0.0.tgz", + "integrity": "sha512-uy/uGpuJk7yuyiKRfZMBNkF1GAOX5O2ifO9rDCaX9jw8fu6eW9QeWC7WRPDI+O98frW1HQgV3+xwjWsZPECIzQ==", "requires": { - "unix-dgram": "2.0.x" + "unix-dgram": "2.x" } }, "html-encoding-sniffer": { @@ -8124,9 +8719,9 @@ } }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true }, "import-fresh": { @@ -8224,9 +8819,9 @@ "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "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" @@ -8238,6 +8833,12 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-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", @@ -8255,11 +8856,6 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -8735,17 +9331,6 @@ "natural-compare": "^1.4.0", "pretty-format": "^27.3.1", "semver": "^7.3.2" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } } }, "jest-util": { @@ -8821,6 +9406,12 @@ } } }, + "js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -8906,29 +9497,20 @@ "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==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true }, "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "requires": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" } }, "jwa": { @@ -8989,14 +9571,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.defaults": { "version": "4.2.0", @@ -9008,41 +9583,11 @@ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -9055,26 +9600,15 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "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=" - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, "logform": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", - "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz", + "integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==", "requires": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", + "@colors/colors": "1.5.0", "fecha": "^4.2.0", "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, @@ -9082,7 +9616,6 @@ "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" } @@ -9163,20 +9696,14 @@ "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -9194,6 +9721,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -9384,9 +9917,9 @@ "dev": true }, "prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", "dev": true }, "pretty-format": { @@ -9409,17 +9942,6 @@ } } }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, "prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -9483,9 +10005,9 @@ } }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "require-directory": { @@ -9494,12 +10016,6 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -9560,6 +10076,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -9576,9 +10097,12 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } }, "shebang-command": { "version": "2.0.0", @@ -9628,17 +10152,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9776,40 +10289,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, "terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -9908,31 +10387,41 @@ "make-error": "1.x", "semver": "7.x", "yargs-parser": "20.x" - }, - "dependencies": { - "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } } }, "ts-node": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", - "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", - "dev": true, - "requires": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.17", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" + }, + "dependencies": { + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + } } }, "tslib": { @@ -9981,9 +10470,9 @@ } }, "typescript": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", - "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, "universalify": { @@ -10017,14 +10506,14 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, "v8-to-istanbul": { @@ -10115,52 +10604,31 @@ } }, "winston": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", - "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", "requires": { + "@colors/colors": "1.5.0", "@dabh/diagnostics": "^2.0.2", - "async": "^3.1.0", + "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.2.0", + "logform": "^2.4.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", - "winston-transport": "^4.4.0" + "winston-transport": "^4.5.0" } }, "winston-transport": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", - "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", "requires": { - "readable-stream": "^2.3.7", - "triple-beam": "^1.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==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" } }, "word-wrap": { @@ -10199,9 +10667,9 @@ } }, "ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz", + "integrity": "sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==", "requires": {} }, "xml-name-validator": { @@ -10225,8 +10693,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==" }, "yargs": { "version": "16.2.0", @@ -10254,6 +10721,12 @@ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/superset-websocket/package.json b/superset-websocket/package.json index 4967e36141e80..453a019c08f7d 100644 --- a/superset-websocket/package.json +++ b/superset-websocket/package.json @@ -15,34 +15,34 @@ }, "license": "Apache-2.0", "dependencies": { - "cookie": "^0.4.1", - "hot-shots": "^9.0.0", + "cookie": "^0.5.0", + "hot-shots": "^10.0.0", "ioredis": "^4.28.0", - "jsonwebtoken": "^8.5.1", - "uuid": "^8.3.2", - "winston": "^3.3.3", - "ws": "^8.2.3" + "jsonwebtoken": "^9.0.0", + "uuid": "^9.0.0", + "winston": "^3.8.2", + "ws": "^8.12.1" }, "devDependencies": { - "@types/cookie": "^0.4.1", + "@types/cookie": "^0.5.1", "@types/ioredis": "^4.27.8", "@types/jest": "^27.0.2", - "@types/jsonwebtoken": "^8.5.5", - "@types/node": "^16.11.6", - "@types/uuid": "^8.3.1", - "@types/ws": "^8.2.0", - "@typescript-eslint/eslint-plugin": "^4.19.0", - "@typescript-eslint/parser": "^4.19.0", - "eslint": "^7.32.0", - "eslint-config-prettier": "^7.1.0", + "@types/jsonwebtoken": "^9.0.1", + "@types/node": "^18.13.0", + "@types/uuid": "^9.0.0", + "@types/ws": "^8.5.4", + "@typescript-eslint/eslint-plugin": "^5.52.0", + "@typescript-eslint/parser": "^5.51.0", + "eslint": "^8.34.0", + "eslint-config-prettier": "^8.6.0", "jest": "^27.3.1", - "prettier": "^2.4.1", + "prettier": "^2.8.4", "ts-jest": "^27.0.7", - "ts-node": "^9.1.1", - "typescript": "^4.2.3" + "ts-node": "^10.9.1", + "typescript": "^4.9.5" }, "engines": { "node": "^16.9.1", - "npm": "^7.5.4" + "npm": "^7.5.4 || ^8.1.2" } } diff --git a/superset-websocket/spec/index.test.ts b/superset-websocket/spec/index.test.ts index 320f13b4451e9..ca575e9e8af56 100644 --- a/superset-websocket/spec/index.test.ts +++ b/superset-websocket/spec/index.test.ts @@ -98,7 +98,7 @@ describe('server', () => { expect(endMock).toHaveBeenLastCalledWith('OK'); }); - test('reponds with a 404 when not found', () => { + test('responds with a 404 when not found', () => { const endMock = jest.fn(); const writeHeadMock = jest.fn(); diff --git a/superset-websocket/utils/client-ws-app/package-lock.json b/superset-websocket/utils/client-ws-app/package-lock.json index 3d24b6358e761..e266ae36953b5 100644 --- a/superset-websocket/utils/client-ws-app/package-lock.json +++ b/superset-websocket/utils/client-ws-app/package-lock.json @@ -8,11 +8,11 @@ "name": "client-ws-app", "version": "0.0.0", "dependencies": { - "cookie-parser": "~1.4.5", - "debug": "~4.3.2", - "express": "~4.17.1", - "http-errors": "~1.8.0", - "jsonwebtoken": "^8.5.1", + "cookie-parser": "~1.4.6", + "debug": "~4.3.4", + "express": "~4.18.2", + "http-errors": "~2.0.0", + "jsonwebtoken": "^9.0.0", "morgan": "~1.10.0", "pug": "~3.0.2" } @@ -49,12 +49,12 @@ } }, "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" @@ -109,23 +109,26 @@ } }, "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "dependencies": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/body-parser/node_modules/debug": { @@ -136,40 +139,31 @@ "ms": "2.0.0" } }, - "node_modules/body-parser/node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/body-parser/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/body-parser/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "engines": { "node": ">= 0.8" } @@ -204,16 +198,35 @@ } }, "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dependencies": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" }, "engines": { "node": ">= 0.6" } }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -223,34 +236,42 @@ } }, "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-parser": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", - "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", "dependencies": { - "cookie": "0.4.0", + "cookie": "0.4.1", "cookie-signature": "1.0.6" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -264,17 +285,21 @@ } }, "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, "node_modules/doctypes": { "version": "1.1.0", @@ -297,7 +322,7 @@ "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "engines": { "node": ">= 0.8" } @@ -305,48 +330,49 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "engines": { "node": ">= 0.6" } }, "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -368,17 +394,47 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { @@ -396,7 +452,18 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } }, "node_modules/forwarded": { "version": "0.2.0", @@ -409,7 +476,7 @@ "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "engines": { "node": ">= 0.6" } @@ -469,25 +536,20 @@ } }, "node_modules/http-errors": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz", - "integrity": "sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dependencies": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/http-errors/node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -558,24 +620,18 @@ "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" }, "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "dependencies": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" }, "engines": { - "node": ">=4", - "npm": ">=1.4.28" + "node": ">=12", + "npm": ">=6" } }, "node_modules/jsonwebtoken/node_modules/ms": { @@ -611,45 +667,26 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, - "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=" + "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==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "engines": { "node": ">= 0.6" } @@ -679,19 +716,19 @@ } }, "node_modules/mime-db": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.32", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.49.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -720,14 +757,6 @@ "ms": "2.0.0" } }, - "node_modules/morgan/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/morgan/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -739,9 +768,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { "node": ">= 0.6" } @@ -754,6 +783,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -924,11 +961,17 @@ "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" }, "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/range-parser": { @@ -940,12 +983,12 @@ } }, "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -953,26 +996,6 @@ "node": ">= 0.8" } }, - "node_modules/raw-body/node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, "node_modules/resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -996,31 +1019,37 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "2.0.0", "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", + "ms": "2.1.3", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" @@ -1037,53 +1066,62 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/send/node_modules/http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/to-fast-properties": { @@ -1095,9 +1133,9 @@ } }, "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "engines": { "node": ">=0.6" } @@ -1122,7 +1160,7 @@ "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "engines": { "node": ">= 0.8" } @@ -1164,6 +1202,11 @@ "engines": { "node": ">= 10.0.0" } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } }, "dependencies": { @@ -1187,12 +1230,12 @@ } }, "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, "acorn": { @@ -1232,20 +1275,22 @@ } }, "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "requires": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "dependencies": { "debug": { @@ -1256,27 +1301,18 @@ "ms": "2.0.0" } }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } } } }, @@ -1286,9 +1322,9 @@ "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, "call-bind": { "version": "1.0.2", @@ -1317,11 +1353,18 @@ } }, "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } } }, "content-type": { @@ -1330,17 +1373,24 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, "cookie-parser": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", - "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", "requires": { - "cookie": "0.4.0", + "cookie": "0.4.1", "cookie-signature": "1.0.6" + }, + "dependencies": { + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + } } }, "cookie-signature": { @@ -1349,22 +1399,22 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } }, "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, "doctypes": { "version": "1.1.0", @@ -1387,50 +1437,51 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "requires": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -1448,20 +1499,33 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" } } }, "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "dependencies": { @@ -1476,7 +1540,15 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } } } }, @@ -1488,7 +1560,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "function-bind": { "version": "1.1.1", @@ -1527,22 +1599,15 @@ } }, "http-errors": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz", - "integrity": "sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "requires": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "dependencies": { - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - } + "statuses": "2.0.1", + "toidentifier": "1.0.1" } }, "iconv-lite": { @@ -1600,20 +1665,14 @@ "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" }, "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "requires": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" }, "dependencies": { "ms": { @@ -1651,45 +1710,23 @@ "safe-buffer": "^5.0.1" } }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + "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==", + "requires": { + "yallist": "^4.0.0" + } }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "merge-descriptors": { "version": "1.0.1", @@ -1707,16 +1744,16 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.32", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "requires": { - "mime-db": "1.49.0" + "mime-db": "1.52.0" } }, "morgan": { @@ -1739,11 +1776,6 @@ "ms": "2.0.0" } }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1757,15 +1789,20 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -1924,9 +1961,12 @@ "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } }, "range-parser": { "version": "1.2.1", @@ -1934,33 +1974,14 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" - }, - "dependencies": { - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } } }, "resolve": { @@ -1983,28 +2004,31 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "2.0.0", "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", + "ms": "2.1.3", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "dependencies": { "debug": { @@ -2018,49 +2042,55 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "ee-first": "1.1.1" } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" } } }, "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.18.0" } }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, "to-fast-properties": { "version": "2.0.0", @@ -2068,9 +2098,9 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "token-stream": { "version": "1.0.0", @@ -2089,7 +2119,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, "utils-merge": { "version": "1.0.1", @@ -2116,6 +2146,11 @@ "assert-never": "^1.2.1", "babel-walk": "3.0.0-canary-5" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/superset-websocket/utils/client-ws-app/package.json b/superset-websocket/utils/client-ws-app/package.json index 39b5465d123d5..d2be76c942131 100644 --- a/superset-websocket/utils/client-ws-app/package.json +++ b/superset-websocket/utils/client-ws-app/package.json @@ -6,11 +6,11 @@ "start": "node ./bin/www" }, "dependencies": { - "cookie-parser": "~1.4.5", - "debug": "~4.3.2", - "express": "~4.17.1", - "http-errors": "~1.8.0", - "jsonwebtoken": "^8.5.1", + "cookie-parser": "~1.4.6", + "debug": "~4.3.4", + "express": "~4.18.2", + "http-errors": "~2.0.0", + "jsonwebtoken": "^9.0.0", "morgan": "~1.10.0", "pug": "~3.0.2" } diff --git a/superset-websocket/utils/client-ws-app/views/index.pug b/superset-websocket/utils/client-ws-app/views/index.pug index 3b1efc7fbff98..2322bec5805cc 100644 --- a/superset-websocket/utils/client-ws-app/views/index.pug +++ b/superset-websocket/utils/client-ws-app/views/index.pug @@ -24,7 +24,7 @@ block content div Sockets connected: span#socket-count 0 - div Messages recevied: + div Messages received: span#message-count 0 div Last message received: code#message-debug diff --git a/superset/__init__.py b/superset/__init__.py index 6df897f3ecdb1..5c8ff3ca2dc57 100644 --- a/superset/__init__.py +++ b/superset/__init__.py @@ -19,7 +19,6 @@ from werkzeug.local import LocalProxy from superset.app import create_app -from superset.connectors.connector_registry import ConnectorRegistry from superset.extensions import ( appbuilder, cache_manager, diff --git a/superset/advanced_data_type/api.py b/superset/advanced_data_type/api.py index 87a820e4410c1..b22efa708838e 100644 --- a/superset/advanced_data_type/api.py +++ b/superset/advanced_data_type/api.py @@ -18,7 +18,7 @@ from flask import current_app as app from flask.wrappers import Response -from flask_appbuilder.api import BaseApi, expose, permission_name, protect, rison, safe +from flask_appbuilder.api import expose, permission_name, protect, rison, safe from flask_babel import lazy_gettext as _ from superset.advanced_data_type.schemas import ( @@ -27,12 +27,13 @@ ) from superset.advanced_data_type.types import AdvancedDataTypeResponse from superset.extensions import event_logger +from superset.views.base_api import BaseSupersetApi config = app.config ADVANCED_DATA_TYPES = config["ADVANCED_DATA_TYPES"] -class AdvancedDataTypeRestApi(BaseApi): +class AdvancedDataTypeRestApi(BaseSupersetApi): """ Advanced Data Type Rest API -Will return available AdvancedDataTypes when the /types endpoint is accessed @@ -41,7 +42,6 @@ class AdvancedDataTypeRestApi(BaseApi): """ allow_browser_login = True - include_route_methods = {"get", "get_types"} resource_name = "advanced_data_type" class_permission_name = "AdvancedDataType" diff --git a/superset/annotation_layers/annotations/api.py b/superset/annotation_layers/annotations/api.py index 291c074fa358a..c0af2dce6f002 100644 --- a/superset/annotation_layers/annotations/api.py +++ b/superset/annotation_layers/annotations/api.py @@ -17,7 +17,7 @@ import logging from typing import Any, Dict -from flask import g, request, Response +from flask import request, Response from flask_appbuilder.api import expose, permission_name, protect, rison, safe from flask_appbuilder.api.schemas import get_item_schema, get_list_schema from flask_appbuilder.models.sqla.interface import SQLAInterface @@ -306,7 +306,7 @@ def post(self, pk: int) -> Response: # pylint: disable=arguments-differ except ValidationError as error: return self.response_400(message=error.messages) try: - new_model = CreateAnnotationCommand(g.user, item).run() + new_model = CreateAnnotationCommand(item).run() return self.response(201, id=new_model.id, result=item) except AnnotationLayerNotFoundError as ex: return self.response_400(message=str(ex)) @@ -381,7 +381,7 @@ def put( # pylint: disable=arguments-differ except ValidationError as error: return self.response_400(message=error.messages) try: - new_model = UpdateAnnotationCommand(g.user, annotation_id, item).run() + new_model = UpdateAnnotationCommand(annotation_id, item).run() return self.response(200, id=new_model.id, result=item) except (AnnotationNotFoundError, AnnotationLayerNotFoundError): return self.response_404() @@ -438,7 +438,7 @@ def delete( # pylint: disable=arguments-differ $ref: '#/components/responses/500' """ try: - DeleteAnnotationCommand(g.user, annotation_id).run() + DeleteAnnotationCommand(annotation_id).run() return self.response(200, message="OK") except AnnotationNotFoundError: return self.response_404() @@ -495,7 +495,7 @@ def bulk_delete(self, **kwargs: Any) -> Response: """ item_ids = kwargs["rison"] try: - BulkDeleteAnnotationCommand(g.user, item_ids).run() + BulkDeleteAnnotationCommand(item_ids).run() return self.response( 200, message=ngettext( diff --git a/superset/annotation_layers/annotations/commands/bulk_delete.py b/superset/annotation_layers/annotations/commands/bulk_delete.py index 6a164c877da8b..113725050fd89 100644 --- a/superset/annotation_layers/annotations/commands/bulk_delete.py +++ b/superset/annotation_layers/annotations/commands/bulk_delete.py @@ -17,8 +17,6 @@ import logging from typing import List, Optional -from flask_appbuilder.security.sqla.models import User - from superset.annotation_layers.annotations.commands.exceptions import ( AnnotationBulkDeleteFailedError, AnnotationNotFoundError, @@ -32,8 +30,7 @@ class BulkDeleteAnnotationCommand(BaseCommand): - def __init__(self, user: User, model_ids: List[int]): - self._actor = user + def __init__(self, model_ids: List[int]): self._model_ids = model_ids self._models: Optional[List[Annotation]] = None diff --git a/superset/annotation_layers/annotations/commands/create.py b/superset/annotation_layers/annotations/commands/create.py index d745df121f7c7..26cd968c5a1f4 100644 --- a/superset/annotation_layers/annotations/commands/create.py +++ b/superset/annotation_layers/annotations/commands/create.py @@ -19,7 +19,6 @@ from typing import Any, Dict, List, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError from superset.annotation_layers.annotations.commands.exceptions import ( @@ -38,8 +37,7 @@ class CreateAnnotationCommand(BaseCommand): - def __init__(self, user: User, data: Dict[str, Any]): - self._actor = user + def __init__(self, data: Dict[str, Any]): self._properties = data.copy() def run(self) -> Model: @@ -72,7 +70,7 @@ def validate(self) -> None: # validate date time sanity if start_dttm and end_dttm and end_dttm < start_dttm: - exceptions.append(AnnotationDatesValidationError) + exceptions.append(AnnotationDatesValidationError()) if exceptions: exception = AnnotationInvalidError() diff --git a/superset/annotation_layers/annotations/commands/delete.py b/superset/annotation_layers/annotations/commands/delete.py index 3d874818dc6cb..915f7f80cef64 100644 --- a/superset/annotation_layers/annotations/commands/delete.py +++ b/superset/annotation_layers/annotations/commands/delete.py @@ -18,7 +18,6 @@ from typing import Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from superset.annotation_layers.annotations.commands.exceptions import ( AnnotationDeleteFailedError, @@ -33,8 +32,7 @@ class DeleteAnnotationCommand(BaseCommand): - def __init__(self, user: User, model_id: int): - self._actor = user + def __init__(self, model_id: int): self._model_id = model_id self._model: Optional[Annotation] = None diff --git a/superset/annotation_layers/annotations/commands/update.py b/superset/annotation_layers/annotations/commands/update.py index 9e3012acb69bf..c55a1cdaf768e 100644 --- a/superset/annotation_layers/annotations/commands/update.py +++ b/superset/annotation_layers/annotations/commands/update.py @@ -19,7 +19,6 @@ from typing import Any, Dict, List, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError from superset.annotation_layers.annotations.commands.exceptions import ( @@ -40,8 +39,7 @@ class UpdateAnnotationCommand(BaseCommand): - def __init__(self, user: User, model_id: int, data: Dict[str, Any]): - self._actor = user + def __init__(self, model_id: int, data: Dict[str, Any]): self._model_id = model_id self._properties = data.copy() self._model: Optional[Annotation] = None diff --git a/superset/annotation_layers/annotations/dao.py b/superset/annotation_layers/annotations/dao.py index 3b6e5e72e7099..0c8a9e47c5c06 100644 --- a/superset/annotation_layers/annotations/dao.py +++ b/superset/annotation_layers/annotations/dao.py @@ -40,8 +40,7 @@ def bulk_delete(models: Optional[List[Annotation]], commit: bool = True) -> None if commit: db.session.commit() except SQLAlchemyError as ex: - if commit: - db.session.rollback() + db.session.rollback() raise DAODeleteFailedError() from ex @staticmethod diff --git a/superset/annotation_layers/api.py b/superset/annotation_layers/api.py index db3979f663607..8ef343cae6bc7 100644 --- a/superset/annotation_layers/api.py +++ b/superset/annotation_layers/api.py @@ -17,7 +17,7 @@ import logging from typing import Any -from flask import g, request, Response +from flask import request, Response from flask_appbuilder.api import expose, permission_name, protect, rison, safe from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_babel import ngettext @@ -151,7 +151,7 @@ def delete(self, pk: int) -> Response: $ref: '#/components/responses/500' """ try: - DeleteAnnotationLayerCommand(g.user, pk).run() + DeleteAnnotationLayerCommand(pk).run() return self.response(200, message="OK") except AnnotationLayerNotFoundError: return self.response_404() @@ -216,7 +216,7 @@ def post(self) -> Response: except ValidationError as error: return self.response_400(message=error.messages) try: - new_model = CreateAnnotationLayerCommand(g.user, item).run() + new_model = CreateAnnotationLayerCommand(item).run() return self.response(201, id=new_model.id, result=item) except AnnotationLayerNotFoundError as ex: return self.response_400(message=str(ex)) @@ -288,7 +288,7 @@ def put(self, pk: int) -> Response: except ValidationError as error: return self.response_400(message=error.messages) try: - new_model = UpdateAnnotationLayerCommand(g.user, pk, item).run() + new_model = UpdateAnnotationLayerCommand(pk, item).run() return self.response(200, id=new_model.id, result=item) except AnnotationLayerNotFoundError: return self.response_404() @@ -346,7 +346,7 @@ def bulk_delete(self, **kwargs: Any) -> Response: """ item_ids = kwargs["rison"] try: - BulkDeleteAnnotationLayerCommand(g.user, item_ids).run() + BulkDeleteAnnotationLayerCommand(item_ids).run() return self.response( 200, message=ngettext( diff --git a/superset/annotation_layers/commands/bulk_delete.py b/superset/annotation_layers/commands/bulk_delete.py index a828047fdda03..b9bc17e82f3b5 100644 --- a/superset/annotation_layers/commands/bulk_delete.py +++ b/superset/annotation_layers/commands/bulk_delete.py @@ -17,8 +17,6 @@ import logging from typing import List, Optional -from flask_appbuilder.security.sqla.models import User - from superset.annotation_layers.commands.exceptions import ( AnnotationLayerBulkDeleteFailedError, AnnotationLayerBulkDeleteIntegrityError, @@ -33,8 +31,7 @@ class BulkDeleteAnnotationLayerCommand(BaseCommand): - def __init__(self, user: User, model_ids: List[int]): - self._actor = user + def __init__(self, model_ids: List[int]): self._model_ids = model_ids self._models: Optional[List[AnnotationLayer]] = None diff --git a/superset/annotation_layers/commands/create.py b/superset/annotation_layers/commands/create.py index ee42ce7557404..d5af6c24a292a 100644 --- a/superset/annotation_layers/commands/create.py +++ b/superset/annotation_layers/commands/create.py @@ -18,7 +18,6 @@ from typing import Any, Dict, List from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError from superset.annotation_layers.commands.exceptions import ( @@ -34,8 +33,7 @@ class CreateAnnotationLayerCommand(BaseCommand): - def __init__(self, user: User, data: Dict[str, Any]): - self._actor = user + def __init__(self, data: Dict[str, Any]): self._properties = data.copy() def run(self) -> Model: diff --git a/superset/annotation_layers/commands/delete.py b/superset/annotation_layers/commands/delete.py index c439542b24d96..3dbd7a574f2f8 100644 --- a/superset/annotation_layers/commands/delete.py +++ b/superset/annotation_layers/commands/delete.py @@ -18,7 +18,6 @@ from typing import Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from superset.annotation_layers.commands.exceptions import ( AnnotationLayerDeleteFailedError, @@ -34,8 +33,7 @@ class DeleteAnnotationLayerCommand(BaseCommand): - def __init__(self, user: User, model_id: int): - self._actor = user + def __init__(self, model_id: int): self._model_id = model_id self._model: Optional[AnnotationLayer] = None diff --git a/superset/annotation_layers/commands/update.py b/superset/annotation_layers/commands/update.py index d2f48abb2444e..f4a04cdeb703b 100644 --- a/superset/annotation_layers/commands/update.py +++ b/superset/annotation_layers/commands/update.py @@ -18,7 +18,6 @@ from typing import Any, Dict, List, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError from superset.annotation_layers.commands.exceptions import ( @@ -36,8 +35,7 @@ class UpdateAnnotationLayerCommand(BaseCommand): - def __init__(self, user: User, model_id: int, data: Dict[str, Any]): - self._actor = user + def __init__(self, model_id: int, data: Dict[str, Any]): self._model_id = model_id self._properties = data.copy() self._model: Optional[AnnotationLayer] = None diff --git a/superset/annotation_layers/dao.py b/superset/annotation_layers/dao.py index 0ca19e270091d..d9db4b582d97f 100644 --- a/superset/annotation_layers/dao.py +++ b/superset/annotation_layers/dao.py @@ -42,8 +42,7 @@ def bulk_delete( if commit: db.session.commit() except SQLAlchemyError as ex: - if commit: - db.session.rollback() + db.session.rollback() raise DAODeleteFailedError() from ex @staticmethod diff --git a/superset/async_events/api.py b/superset/async_events/api.py index 61916162eec75..d3f3bee64d64e 100644 --- a/superset/async_events/api.py +++ b/superset/async_events/api.py @@ -18,21 +18,19 @@ from flask import request, Response from flask_appbuilder import expose -from flask_appbuilder.api import BaseApi, safe +from flask_appbuilder.api import safe from flask_appbuilder.security.decorators import permission_name, protect from superset.extensions import async_query_manager, event_logger from superset.utils.async_query_manager import AsyncQueryTokenException +from superset.views.base_api import BaseSupersetApi logger = logging.getLogger(__name__) -class AsyncEventsRestApi(BaseApi): +class AsyncEventsRestApi(BaseSupersetApi): resource_name = "async_event" allow_browser_login = True - include_route_methods = { - "events", - } @expose("/", methods=["GET"]) @event_logger.log_this diff --git a/superset/db_engines/__init__.py b/superset/available_domains/__init__.py similarity index 100% rename from superset/db_engines/__init__.py rename to superset/available_domains/__init__.py diff --git a/superset/available_domains/api.py b/superset/available_domains/api.py new file mode 100644 index 0000000000000..b35f4c0702fd0 --- /dev/null +++ b/superset/available_domains/api.py @@ -0,0 +1,76 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging + +from flask import Response +from flask_appbuilder.api import expose, protect, safe + +from superset import conf +from superset.available_domains.schemas import AvailableDomainsSchema +from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP +from superset.extensions import event_logger +from superset.views.base_api import BaseSupersetApi, statsd_metrics + +logger = logging.getLogger(__name__) + + +class AvailableDomainsRestApi(BaseSupersetApi): + available_domains_schema = AvailableDomainsSchema() + + method_permission_name = MODEL_API_RW_METHOD_PERMISSION_MAP + allow_browser_login = True + class_permission_name = "AvailableDomains" + resource_name = "available_domains" + openapi_spec_tag = "Available Domains" + openapi_spec_component_schemas = (AvailableDomainsSchema,) + + @expose("/", methods=["GET"]) + @protect() + @safe + @statsd_metrics + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.get", + log_to_statsd=True, + ) + def get(self) -> Response: + """ + Returns the list of available Superset Webserver domains (if any) + defined in config. This enables charts embedded in other apps to + leverage domain sharding if appropriately configured. + --- + get: + description: >- + Get all available domains + responses: + 200: + description: a list of available domains + content: + application/json: + schema: + type: object + properties: + result: + $ref: '#/components/schemas/AvailableDomainsSchema' + 401: + $ref: '#/components/responses/401' + 403: + $ref: '#/components/responses/403' + """ + result = self.available_domains_schema.dump( + {"domains": conf.get("SUPERSET_WEBSERVER_DOMAINS")} + ) + return self.response(200, result=result) diff --git a/superset/available_domains/schemas.py b/superset/available_domains/schemas.py new file mode 100644 index 0000000000000..e9aa1b0a0c936 --- /dev/null +++ b/superset/available_domains/schemas.py @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# License ); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from marshmallow import fields, Schema + + +class AvailableDomainsSchema(Schema): + domains = fields.List(fields.String()) diff --git a/superset/cachekeys/api.py b/superset/cachekeys/api.py index 6eb0d54d9eef0..78e680d524c57 100644 --- a/superset/cachekeys/api.py +++ b/superset/cachekeys/api.py @@ -25,8 +25,8 @@ from sqlalchemy.exc import SQLAlchemyError from superset.cachekeys.schemas import CacheInvalidationRequestSchema -from superset.connectors.connector_registry import ConnectorRegistry -from superset.extensions import cache_manager, db, event_logger +from superset.connectors.sqla.models import SqlaTable +from superset.extensions import cache_manager, db, event_logger, stats_logger_manager from superset.models.cache import CacheKey from superset.views.base_api import BaseSupersetModelRestApi, statsd_metrics @@ -83,13 +83,13 @@ def invalidate(self) -> Response: return self.response_400(message=str(error)) datasource_uids = set(datasources.get("datasource_uids", [])) for ds in datasources.get("datasources", []): - ds_obj = ConnectorRegistry.get_datasource_by_name( + ds_obj = SqlaTable.get_datasource_by_name( session=db.session, - datasource_type=ds.get("datasource_type"), datasource_name=ds.get("datasource_name"), schema=ds.get("schema"), database_name=ds.get("database_name"), ) + if ds_obj: datasource_uids.add(ds_obj.uid) @@ -117,7 +117,9 @@ def invalidate(self) -> Response: ) db.session.execute(delete_stmt) db.session.commit() - self.stats_logger.gauge("invalidated_cache", len(cache_keys)) + stats_logger_manager.instance.gauge( + "invalidated_cache", len(cache_keys) + ) logger.info( "Invalidated %s cache records for %s datasources", len(cache_keys), diff --git a/superset/charts/api.py b/superset/charts/api.py index e59c3a41bb733..7dc6d5e1e8d93 100644 --- a/superset/charts/api.py +++ b/superset/charts/api.py @@ -18,10 +18,10 @@ import logging from datetime import datetime from io import BytesIO -from typing import Any, Optional +from typing import Any, cast, Optional from zipfile import is_zipfile, ZipFile -from flask import g, redirect, request, Response, send_file, url_for +from flask import redirect, request, Response, send_file, url_for from flask_appbuilder.api import expose, protect, rison, safe from flask_appbuilder.hooks import before_request from flask_appbuilder.models.sqla.interface import SQLAInterface @@ -50,8 +50,10 @@ from superset.charts.filters import ( ChartAllTextFilter, ChartCertifiedFilter, + ChartCreatedByMeFilter, ChartFavoriteFilter, ChartFilter, + ChartHasCreatedByFilter, ) from superset.charts.schemas import ( CHART_SCHEMAS, @@ -73,6 +75,7 @@ from superset.extensions import event_logger from superset.models.slice import Slice from superset.tasks.thumbnails import cache_chart_thumbnail +from superset.tasks.utils import get_current_user from superset.utils.screenshots import ChartScreenshot from superset.utils.urls import get_url_path from superset.views.base_api import ( @@ -82,7 +85,7 @@ requires_json, statsd_metrics, ) -from superset.views.filters import FilterRelatedOwners +from superset.views.filters import BaseFilterRelatedUsers, FilterRelatedOwners logger = logging.getLogger(__name__) config = app.config @@ -117,16 +120,22 @@ def ensure_thumbnails_enabled(self) -> Optional[Response]: "cache_timeout", "certified_by", "certification_details", + "changed_on_delta_humanized", "dashboards.dashboard_title", "dashboards.id", "dashboards.json_metadata", "description", + "id", "owners.first_name", "owners.id", "owners.last_name", "owners.username", + "dashboards.id", + "dashboards.dashboard_title", "params", "slice_name", + "thumbnail_url", + "url", "viz_type", "query_context", "is_managed_externally", @@ -146,6 +155,7 @@ def ensure_thumbnails_enabled(self) -> Optional[Response]: "created_by.first_name", "created_by.id", "created_by.last_name", + "created_on_delta_humanized", "datasource_id", "datasource_name_text", "datasource_type", @@ -162,6 +172,8 @@ def ensure_thumbnails_enabled(self) -> Optional[Response]: "owners.id", "owners.last_name", "owners.username", + "dashboards.id", + "dashboards.dashboard_title", "params", "slice_name", "table.default_endpoint", @@ -187,15 +199,14 @@ def ensure_thumbnails_enabled(self) -> Optional[Response]: "created_by", "changed_by", "last_saved_at", - "last_saved_by.id", - "last_saved_by.first_name", - "last_saved_by.last_name", + "last_saved_by", "datasource_id", "datasource_name", "datasource_type", "description", "id", "owners", + "dashboards", "slice_name", "viz_type", ] @@ -204,6 +215,7 @@ def ensure_thumbnails_enabled(self) -> Optional[Response]: search_filters = { "id": [ChartFavoriteFilter, ChartCertifiedFilter], "slice_name": [ChartAllTextFilter], + "created_by": [ChartHasCreatedByFilter, ChartCreatedByMeFilter], } # Will just affect _info endpoint @@ -231,7 +243,10 @@ def ensure_thumbnails_enabled(self) -> Optional[Response]: "slices": ("slice_name", "asc"), "owners": ("first_name", "asc"), } - + base_related_field_filters = { + "owners": [["id", BaseFilterRelatedUsers, lambda: []]], + "created_by": [["id", BaseFilterRelatedUsers, lambda: []]], + } related_field_filters = { "owners": RelatedFieldFilter("first_name", FilterRelatedOwners), "created_by": RelatedFieldFilter("first_name", FilterRelatedOwners), @@ -288,7 +303,7 @@ def post(self) -> Response: except ValidationError as error: return self.response_400(message=error.messages) try: - new_model = CreateChartCommand(g.user, item).run() + new_model = CreateChartCommand(item).run() return self.response(201, id=new_model.id, result=item) except ChartInvalidError as ex: return self.response_422(message=ex.normalized_messages()) @@ -359,7 +374,7 @@ def put(self, pk: int) -> Response: except ValidationError as error: return self.response_400(message=error.messages) try: - changed_model = UpdateChartCommand(g.user, pk, item).run() + changed_model = UpdateChartCommand(pk, item).run() response = self.response(200, id=changed_model.id, result=item) except ChartNotFoundError: response = self.response_404() @@ -419,7 +434,7 @@ def delete(self, pk: int) -> Response: $ref: '#/components/responses/500' """ try: - DeleteChartCommand(g.user, pk).run() + DeleteChartCommand(pk).run() return self.response(200, message="OK") except ChartNotFoundError: return self.response_404() @@ -479,7 +494,7 @@ def bulk_delete(self, **kwargs: Any) -> Response: """ item_ids = kwargs["rison"] try: - BulkDeleteChartCommand(g.user, item_ids).run() + BulkDeleteChartCommand(item_ids).run() return self.response( 200, message=ngettext( @@ -541,11 +556,11 @@ def cache_screenshot(self, pk: int, **kwargs: Any) -> WerkzeugResponse: # Don't shrink the image if thumb_size is not specified thumb_size = rison_dict.get("thumb_size") or window_size - chart = self.datamodel.get(pk, self._base_filters) + chart = cast(Slice, self.datamodel.get(pk, self._base_filters)) if not chart: return self.response_404() - chart_url = get_url_path("Superset.slice", slice_id=chart.id, standalone="true") + chart_url = get_url_path("Superset.slice", slice_id=chart.id) screenshot_obj = ChartScreenshot(chart_url, chart.digest) cache_key = screenshot_obj.cache_key(window_size, thumb_size) image_url = get_url_path( @@ -554,14 +569,13 @@ def cache_screenshot(self, pk: int, **kwargs: Any) -> WerkzeugResponse: def trigger_celery() -> WerkzeugResponse: logger.info("Triggering screenshot ASYNC") - kwargs = { - "url": chart_url, - "digest": chart.digest, - "force": True, - "window_size": window_size, - "thumb_size": thumb_size, - } - cache_chart_thumbnail.delay(**kwargs) + cache_chart_thumbnail.delay( + current_user=get_current_user(), + chart_id=chart.id, + force=True, + window_size=window_size, + thumb_size=thumb_size, + ) return self.response( 202, cache_key=cache_key, chart_url=chart_url, image_url=image_url ) @@ -664,16 +678,21 @@ def thumbnail(self, pk: int, digest: str, **kwargs: Any) -> WerkzeugResponse: 500: $ref: '#/components/responses/500' """ - chart = self.datamodel.get(pk, self._base_filters) + chart = cast(Slice, self.datamodel.get(pk, self._base_filters)) if not chart: return self.response_404() - url = get_url_path("Superset.slice", slice_id=chart.id, standalone="true") + current_user = get_current_user() + url = get_url_path("Superset.slice", slice_id=chart.id) if kwargs["rison"].get("force", False): logger.info( "Triggering thumbnail compute (chart id: %s) ASYNC", str(chart.id) ) - cache_chart_thumbnail.delay(url, chart.digest, force=True) + cache_chart_thumbnail.delay( + current_user=current_user, + chart_id=chart.id, + force=True, + ) return self.response(202, message="OK Async") # fetch the chart screenshot using the current user and cache if set screenshot = ChartScreenshot(url, chart.digest).get_from_cache( @@ -685,7 +704,11 @@ def thumbnail(self, pk: int, digest: str, **kwargs: Any) -> WerkzeugResponse: logger.info( "Triggering thumbnail compute (chart id: %s) ASYNC", str(chart.id) ) - cache_chart_thumbnail.delay(url, chart.digest, force=True) + cache_chart_thumbnail.delay( + current_user=current_user, + chart_id=chart.id, + force=True, + ) return self.response(202, message="OK Async") # If digests if chart.digest != digest: @@ -808,7 +831,7 @@ def favorite_status(self, **kwargs: Any) -> Response: charts = ChartDAO.find_by_ids(requested_ids) if not charts: return self.response_404() - favorited_chart_ids = ChartDAO.favorited_ids(charts, g.user.get_id()) + favorited_chart_ids = ChartDAO.favorited_ids(charts) res = [ {"id": request_id, "value": request_id in favorited_chart_ids} for request_id in requested_ids diff --git a/superset/charts/commands/bulk_delete.py b/superset/charts/commands/bulk_delete.py index 26a3fce9e41c4..caf8fe0399228 100644 --- a/superset/charts/commands/bulk_delete.py +++ b/superset/charts/commands/bulk_delete.py @@ -17,9 +17,9 @@ import logging from typing import List, Optional -from flask_appbuilder.security.sqla.models import User from flask_babel import lazy_gettext as _ +from superset import security_manager from superset.charts.commands.exceptions import ( ChartBulkDeleteFailedError, ChartBulkDeleteFailedReportsExistError, @@ -32,14 +32,12 @@ from superset.exceptions import SupersetSecurityException from superset.models.slice import Slice from superset.reports.dao import ReportScheduleDAO -from superset.views.base import check_ownership logger = logging.getLogger(__name__) class BulkDeleteChartCommand(BaseCommand): - def __init__(self, user: User, model_ids: List[int]): - self._actor = user + def __init__(self, model_ids: List[int]): self._model_ids = model_ids self._models: Optional[List[Slice]] = None @@ -66,6 +64,6 @@ def validate(self) -> None: # Check ownership for model in self._models: try: - check_ownership(model) + security_manager.raise_for_ownership(model) except SupersetSecurityException as ex: raise ChartForbiddenError() from ex diff --git a/superset/charts/commands/create.py b/superset/charts/commands/create.py index 34a25aea2d4a6..8238340794478 100644 --- a/superset/charts/commands/create.py +++ b/superset/charts/commands/create.py @@ -18,8 +18,8 @@ from datetime import datetime from typing import Any, Dict, List, Optional +from flask import g from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError from superset.charts.commands.exceptions import ( @@ -37,15 +37,14 @@ class CreateChartCommand(CreateMixin, BaseCommand): - def __init__(self, user: User, data: Dict[str, Any]): - self._actor = user + def __init__(self, data: Dict[str, Any]): self._properties = data.copy() def run(self) -> Model: self.validate() try: self._properties["last_saved_at"] = datetime.now() - self._properties["last_saved_by"] = self._actor + self._properties["last_saved_by"] = g.user chart = ChartDAO.create(self._properties) except DAOCreateFailedError as ex: logger.exception(ex.exception) @@ -73,7 +72,7 @@ def validate(self) -> None: self._properties["dashboards"] = dashboards try: - owners = self.populate_owners(self._actor, owner_ids) + owners = self.populate_owners(owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) diff --git a/superset/charts/commands/delete.py b/superset/charts/commands/delete.py index faf72c5ef7b97..cb6644c711c45 100644 --- a/superset/charts/commands/delete.py +++ b/superset/charts/commands/delete.py @@ -18,9 +18,9 @@ from typing import Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from flask_babel import lazy_gettext as _ +from superset import security_manager from superset.charts.commands.exceptions import ( ChartDeleteFailedError, ChartDeleteFailedReportsExistError, @@ -34,14 +34,12 @@ from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.reports.dao import ReportScheduleDAO -from superset.views.base import check_ownership logger = logging.getLogger(__name__) class DeleteChartCommand(BaseCommand): - def __init__(self, user: User, model_id: int): - self._actor = user + def __init__(self, model_id: int): self._model_id = model_id self._model: Optional[Slice] = None @@ -69,6 +67,6 @@ def validate(self) -> None: ) # Check ownership try: - check_ownership(self._model) + security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise ChartForbiddenError() from ex diff --git a/superset/charts/commands/export.py b/superset/charts/commands/export.py index 9b3a06c473585..39c3c7d46a77b 100644 --- a/superset/charts/commands/export.py +++ b/superset/charts/commands/export.py @@ -21,7 +21,6 @@ from typing import Iterator, Tuple import yaml -from werkzeug.utils import secure_filename from superset.charts.commands.exceptions import ChartNotFoundError from superset.charts.dao import ChartDAO @@ -29,12 +28,13 @@ from superset.commands.export.models import ExportModelsCommand from superset.models.slice import Slice from superset.utils.dict_import_export import EXPORT_VERSION +from superset.utils.file import get_filename logger = logging.getLogger(__name__) # keys present in the standard export that are not needed -REMOVE_KEYS = ["datasource_type", "datasource_name", "query_context", "url_params"] +REMOVE_KEYS = ["datasource_type", "datasource_name", "url_params"] class ExportChartsCommand(ExportModelsCommand): @@ -44,8 +44,8 @@ class ExportChartsCommand(ExportModelsCommand): @staticmethod def _export(model: Slice, export_related: bool = True) -> Iterator[Tuple[str, str]]: - chart_slug = secure_filename(model.slice_name) - file_name = f"charts/{chart_slug}_{model.id}.yaml" + file_name = get_filename(model.slice_name, model.id) + file_path = f"charts/{file_name}.yaml" payload = model.export_to_dict( recursive=False, @@ -70,7 +70,7 @@ def _export(model: Slice, export_related: bool = True) -> Iterator[Tuple[str, st payload["dataset_uuid"] = str(model.table.uuid) file_content = yaml.safe_dump(payload, sort_keys=False) - yield file_name, file_content + yield file_path, file_content if model.table and export_related: yield from ExportDatasetsCommand([model.table.id]).run() diff --git a/superset/charts/commands/update.py b/superset/charts/commands/update.py index 0355e6e5ffe52..042c85a930f93 100644 --- a/superset/charts/commands/update.py +++ b/superset/charts/commands/update.py @@ -18,10 +18,11 @@ from datetime import datetime from typing import Any, Dict, List, Optional +from flask import g from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError +from superset import security_manager from superset.charts.commands.exceptions import ( ChartForbiddenError, ChartInvalidError, @@ -37,7 +38,6 @@ from superset.dashboards.dao import DashboardDAO from superset.exceptions import SupersetSecurityException from superset.models.slice import Slice -from superset.views.base import check_ownership logger = logging.getLogger(__name__) @@ -49,8 +49,7 @@ def is_query_context_update(properties: Dict[str, Any]) -> bool: class UpdateChartCommand(UpdateMixin, BaseCommand): - def __init__(self, user: User, model_id: int, data: Dict[str, Any]): - self._actor = user + def __init__(self, model_id: int, data: Dict[str, Any]): self._model_id = model_id self._properties = data.copy() self._model: Optional[Slice] = None @@ -60,7 +59,7 @@ def run(self) -> Model: try: if self._properties.get("query_context_generation") is None: self._properties["last_saved_at"] = datetime.now() - self._properties["last_saved_by"] = self._actor + self._properties["last_saved_by"] = g.user chart = ChartDAO.update(self._model, self._properties) except DAOUpdateFailedError as ex: logger.exception(ex.exception) @@ -88,8 +87,8 @@ def validate(self) -> None: # ownership so the update can be performed by report workers if not is_query_context_update(self._properties): try: - check_ownership(self._model) - owners = self.populate_owners(self._actor, owner_ids) + security_manager.raise_for_ownership(self._model) + owners = self.populate_owners(owner_ids) self._properties["owners"] = owners except SupersetSecurityException as ex: raise ChartForbiddenError() from ex @@ -106,7 +105,10 @@ def validate(self) -> None: # Validate/Populate dashboards only if it's a list if dashboard_ids is not None: - dashboards = DashboardDAO.find_by_ids(dashboard_ids) + dashboards = DashboardDAO.find_by_ids( + dashboard_ids, + skip_base_filter=True, + ) if len(dashboards) != len(dashboard_ids): exceptions.append(DashboardsNotFoundValidationError()) self._properties["dashboards"] = dashboards diff --git a/superset/charts/dao.py b/superset/charts/dao.py index 8e16f3b445b49..384bd9a1fe6e2 100644 --- a/superset/charts/dao.py +++ b/superset/charts/dao.py @@ -25,6 +25,7 @@ from superset.extensions import db from superset.models.core import FavStar, FavStarClassName from superset.models.slice import Slice +from superset.utils.core import get_user_id if TYPE_CHECKING: from superset.connectors.base.models import BaseDatasource @@ -53,8 +54,7 @@ def bulk_delete(models: Optional[List[Slice]], commit: bool = True) -> None: if commit: db.session.commit() except SQLAlchemyError as ex: - if commit: - db.session.rollback() + db.session.rollback() raise ex @staticmethod @@ -70,7 +70,7 @@ def overwrite(slc: Slice, commit: bool = True) -> None: db.session.commit() @staticmethod - def favorited_ids(charts: List[Slice], current_user_id: int) -> List[FavStar]: + def favorited_ids(charts: List[Slice]) -> List[FavStar]: ids = [chart.id for chart in charts] return [ star.obj_id @@ -78,7 +78,7 @@ def favorited_ids(charts: List[Slice], current_user_id: int) -> List[FavStar]: .filter( FavStar.class_name == FavStarClassName.CHART, FavStar.obj_id.in_(ids), - FavStar.user_id == current_user_id, + FavStar.user_id == get_user_id(), ) .all() ] diff --git a/superset/charts/data/api.py b/superset/charts/data/api.py index 73468d651cbc5..0d0758819ed02 100644 --- a/superset/charts/data/api.py +++ b/superset/charts/data/api.py @@ -21,7 +21,7 @@ from typing import Any, Dict, Optional, TYPE_CHECKING import simplejson -from flask import current_app, g, make_response, request, Response +from flask import current_app, make_response, request, Response from flask_appbuilder.api import expose, protect from flask_babel import gettext as _ from marshmallow import ValidationError @@ -41,11 +41,12 @@ from superset.charts.schemas import ChartDataQueryContextSchema from superset.common.chart_data import ChartDataResultFormat, ChartDataResultType from superset.connectors.base.models import BaseDatasource +from superset.dao.exceptions import DatasourceNotFound from superset.exceptions import QueryObjectValidationError from superset.extensions import event_logger from superset.utils.async_query_manager import AsyncQueryTokenException -from superset.utils.core import create_zip, json_int_dttm_ser -from superset.views.base import CsvResponse, generate_download_headers +from superset.utils.core import create_zip, get_user_id, json_int_dttm_ser +from superset.views.base import CsvResponse, generate_download_headers, XlsxResponse from superset.views.base_api import statsd_metrics if TYPE_CHECKING: @@ -89,6 +90,11 @@ def get_data(self, pk: int) -> Response: description: The type in which the data should be returned schema: type: string + - in: query + name: force + description: Should the queries be forced to load from the source + schema: + type: boolean responses: 200: description: Query result @@ -130,11 +136,14 @@ def get_data(self, pk: int) -> Response: "format", ChartDataResultFormat.JSON ) json_body["result_type"] = request.args.get("type", ChartDataResultType.FULL) + json_body["force"] = request.args.get("force") try: query_context = self._create_query_context_from_form(json_body) command = ChartDataCommand(query_context) command.validate() + except DatasourceNotFound as error: + return self.response_404() except QueryObjectValidationError as error: return self.response_400(message=error.message) except ValidationError as error: @@ -223,6 +232,8 @@ def data(self) -> Response: query_context = self._create_query_context_from_form(json_body) command = ChartDataCommand(query_context) command.validate() + except DatasourceNotFound as error: + return self.response_404() except QueryObjectValidationError as error: return self.response_400(message=error.message) except ValidationError as error: @@ -324,7 +335,7 @@ def _run_async( except AsyncQueryTokenException: return self.response_401() - result = async_command.run(form_data, g.user.get_id()) + result = async_command.run(form_data, get_user_id()) return self.response(202, **result) def _send_chart_response( @@ -342,24 +353,34 @@ def _send_chart_response( if result_type == ChartDataResultType.POST_PROCESSED: result = apply_post_process(result, form_data, datasource) - if result_format == ChartDataResultFormat.CSV: - # Verify user has permission to export CSV file + if result_format in ChartDataResultFormat.table_like(): + # Verify user has permission to export file if not security_manager.can_access("can_csv", "Superset"): return self.response_403() if not result["queries"]: return self.response_400(_("Empty query result")) + is_csv_format = result_format == ChartDataResultFormat.CSV + if len(result["queries"]) == 1: - # return single query results csv format + # return single query results data = result["queries"][0]["data"] - return CsvResponse(data, headers=generate_download_headers("csv")) + if is_csv_format: + return CsvResponse(data, headers=generate_download_headers("csv")) + + return XlsxResponse(data, headers=generate_download_headers("xlsx")) + + # return multi-query results bundled as a zip file + def _process_data(query_data: Any) -> Any: + if result_format == ChartDataResultFormat.CSV: + encoding = current_app.config["CSV_EXPORT"].get("encoding", "utf-8") + return query_data.encode(encoding) + return query_data - # return multi-query csv results bundled as a zip file - encoding = current_app.config["CSV_EXPORT"].get("encoding", "utf-8") files = { - f"query_{idx + 1}.csv": result["data"].encode(encoding) - for idx, result in enumerate(result["queries"]) + f"query_{idx + 1}.{result_format}": _process_data(query["data"]) + for idx, query in enumerate(result["queries"]) } return Response( create_zip(files), diff --git a/superset/charts/data/commands/create_async_job_command.py b/superset/charts/data/commands/create_async_job_command.py index 98a0174e6252f..c4e25f742baa3 100644 --- a/superset/charts/data/commands/create_async_job_command.py +++ b/superset/charts/data/commands/create_async_job_command.py @@ -32,7 +32,7 @@ def validate(self, request: Request) -> None: jwt_data = async_query_manager.parse_jwt_from_request(request) self._async_channel_id = jwt_data["channel"] - def run(self, form_data: Dict[str, Any], user_id: Optional[str]) -> Dict[str, Any]: + def run(self, form_data: Dict[str, Any], user_id: Optional[int]) -> Dict[str, Any]: job_metadata = async_query_manager.init_job(self._async_channel_id, user_id) load_chart_data_into_cache.delay(job_metadata, form_data) return job_metadata diff --git a/superset/charts/data/commands/get_data_command.py b/superset/charts/data/commands/get_data_command.py index 95f7513f253f6..819693607bfb7 100644 --- a/superset/charts/data/commands/get_data_command.py +++ b/superset/charts/data/commands/get_data_command.py @@ -17,6 +17,8 @@ import logging from typing import Any, Dict +from flask_babel import lazy_gettext as _ + from superset.charts.commands.exceptions import ( ChartDataCacheLoadError, ChartDataQueryFailedError, @@ -49,7 +51,9 @@ def run(self, **kwargs: Any) -> Dict[str, Any]: # TODO: QueryContext should support SIP-40 style errors for query in payload["queries"]: if query.get("error"): - raise ChartDataQueryFailedError(f"Error: {query['error']}") + raise ChartDataQueryFailedError( + _("Error: %(error)s", error=query["error"]) + ) return_value = { "query_context": self._query_context, diff --git a/superset/charts/filters.py b/superset/charts/filters.py index c60d285940839..fd3fff7f6e2fa 100644 --- a/superset/charts/filters.py +++ b/superset/charts/filters.py @@ -24,6 +24,7 @@ from superset.connectors.sqla import models from superset.connectors.sqla.models import SqlaTable from superset.models.slice import Slice +from superset.utils.core import get_user_id from superset.views.base import BaseFilter from superset.views.base_api import BaseFavoriteFilter @@ -93,3 +94,34 @@ def apply(self, query: Query, value: Any) -> Query: models.SqlaTable.id.in_(owner_ids_query), ) ) + + +class ChartHasCreatedByFilter(BaseFilter): # pylint: disable=too-few-public-methods + """ + Custom filter for the GET list that filters all charts created by user + """ + + name = _("Has created by") + arg_name = "chart_has_created_by" + + def apply(self, query: Query, value: Any) -> Query: + if value is True: + return query.filter(and_(Slice.created_by_fk.isnot(None))) + if value is False: + return query.filter(and_(Slice.created_by_fk.is_(None))) + return query + + +class ChartCreatedByMeFilter(BaseFilter): # pylint: disable=too-few-public-methods + name = _("Created by me") + arg_name = "chart_created_by_me" + + def apply(self, query: Query, value: Any) -> Query: + return query.filter( + or_( + Slice.created_by_fk # pylint: disable=comparison-with-callable + == get_user_id(), + Slice.changed_by_fk # pylint: disable=comparison-with-callable + == get_user_id(), + ) + ) diff --git a/superset/charts/post_processing.py b/superset/charts/post_processing.py index 44131afe942b0..831775fa039a1 100644 --- a/superset/charts/post_processing.py +++ b/superset/charts/post_processing.py @@ -25,16 +25,15 @@ In order to do that, we reproduce the post-processing in Python for these chart types. """ - import logging from io import StringIO from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING import pandas as pd +from flask_babel import gettext as __ from superset import app from superset.common.chart_data import ChartDataResultFormat -from superset.common.query_context import QueryContext from superset.utils.core import ( DTTM_ALIAS, extract_dataframe_dtypes, @@ -45,8 +44,8 @@ if TYPE_CHECKING: from superset.connectors.base.models import BaseDatasource -config = app.config logger = logging.getLogger(__name__) +config = app.config def get_column_key(label: Tuple[str, ...], metrics: List[str]) -> Tuple[Any, ...]: @@ -74,7 +73,7 @@ def pivot_df( # pylint: disable=too-many-locals, too-many-arguments, too-many-s show_columns_total: bool = False, apply_metrics_on_rows: bool = False, ) -> pd.DataFrame: - metric_name = f"Total ({aggfunc})" + metric_name = __("Total (%(aggfunc)s)", aggfunc=aggfunc) if transpose_pivot: rows, columns = columns, rows @@ -162,7 +161,7 @@ def pivot_df( # pylint: disable=too-many-locals, too-many-arguments, too-many-s slice_ = df.columns.get_loc(subgroup) subtotal = pivot_v2_aggfunc_map[aggfunc](df.iloc[:, slice_], axis=1) depth = df.columns.nlevels - len(subgroup) - 1 - total = metric_name if level == 0 else "Subtotal" + total = metric_name if level == 0 else __("Subtotal") subtotal_name = tuple([*subgroup, total, *([""] * depth)]) # insert column after subgroup df.insert(int(slice_.stop), subtotal_name, subtotal) @@ -179,7 +178,7 @@ def pivot_df( # pylint: disable=too-many-locals, too-many-arguments, too-many-s df.iloc[slice_, :].apply(pd.to_numeric), axis=0 ) depth = df.index.nlevels - len(subgroup) - 1 - total = metric_name if level == 0 else "Subtotal" + total = metric_name if level == 0 else __("Subtotal") subtotal.name = tuple([*subgroup, total, *([""] * depth)]) # insert row after subgroup df = pd.concat( @@ -362,14 +361,7 @@ def apply_post_process( ) -> Dict[Any, Any]: form_data = form_data or {} - viz_type = form_data.get("viz_type", "") - if not viz_type: - viz_type = ( - result.get("query_context", QueryContext).viz_type - if result.get("query_context", QueryContext).viz_type - else "" - ) - + viz_type = form_data.get("viz_type") if viz_type not in post_processors: return result @@ -394,12 +386,21 @@ def apply_post_process( result = post_processor(result, form_data) # type: ignore else: for query in result["queries"]: + if query["result_format"] not in (rf.value for rf in ChartDataResultFormat): + raise Exception(f"Result format {query['result_format']} not supported") + + if not query["data"]: + # do not try to process empty data + continue + if query["result_format"] == ChartDataResultFormat.JSON: df = pd.DataFrame.from_dict(query["data"]) elif query["result_format"] == ChartDataResultFormat.CSV: df = pd.read_csv(StringIO(query["data"])) - else: - raise Exception(f"Result format {query['result_format']} not supported") + + # convert all columns to verbose (label) name + if datasource: + df.rename(columns=datasource.data["verbose_map"], inplace=True) processed_df = post_processor(df, form_data, datasource) # type: ignore diff --git a/superset/charts/schemas.py b/superset/charts/schemas.py index b15f81b091c41..9e62e6322d79f 100644 --- a/superset/charts/schemas.py +++ b/superset/charts/schemas.py @@ -71,6 +71,7 @@ # # Column schema descriptions # +id_description = "The id of the chart." slice_name_description = "The name of the chart." description_description = "A description of the chart propose." viz_type_description = "The type of chart visualization used." @@ -153,7 +154,7 @@ class ChartEntityResponseSchema(Schema): Schema for a chart object """ - slice_id = fields.Integer() + id = fields.Integer(description=id_description) slice_name = fields.String(description=slice_name_description) cache_timeout = fields.Integer(description=cache_timeout_description) changed_on = fields.String(description=changed_on_description) @@ -434,7 +435,7 @@ class ChartDataRollingOptionsSchema(ChartDataPostProcessingOperationOptionsSchem example=7, ) rolling_type_options = fields.Dict( - desctiption="Optional options to pass to rolling method. Needed for " + description="Optional options to pass to rolling method. Needed for " "e.g. quantile operation.", example={}, ) @@ -550,7 +551,7 @@ class ChartDataProphetOptionsSchema(ChartDataPostProcessingOperationOptionsSchem required=True, ) periods = fields.Integer( - descrption="Time periods (in units of `time_grain`) to predict into the future", + description="Time periods (in units of `time_grain`) to predict into the future", min=0, example=7, required=True, @@ -819,7 +820,8 @@ class ChartDataFilterSchema(Schema): ) val = fields.Raw( description="The value or values to compare against. Can be a string, " - "integer, decimal or list, depending on the operator.", + "integer, decimal, None or list, depending on the operator.", + allow_none=True, example=["China", "France", "Japan"], ) grain = fields.String( @@ -853,7 +855,9 @@ class ChartDataExtrasSchema(Schema): ) having_druid = fields.List( fields.Nested(ChartDataFilterSchema), - description="HAVING filters to be added to legacy Druid datasource queries.", + description="HAVING filters to be added to legacy Druid datasource queries. " + "This field is deprecated", + deprecated=True, ) time_grain_sqla = fields.String( description="To what level of granularity should the temporal column be " @@ -869,11 +873,6 @@ class ChartDataExtrasSchema(Schema): example="P1D", allow_none=True, ) - druid_time_origin = fields.String( - description="Starting point for time grain counting on legacy Druid " - "datasources. Used to change e.g. Monday/Sunday first-day-of-week.", - allow_none=True, - ) class AnnotationLayerSchema(Schema): @@ -911,7 +910,7 @@ class AnnotationLayerSchema(Schema): ) overrides = fields.Dict( keys=fields.String( - desciption="Name of property to be overridden", + description="Name of property to be overridden", validate=validate.OneOf( choices=("granularity", "time_grain_sqla", "time_range", "time_shift"), ), @@ -1175,6 +1174,7 @@ class Meta: # pylint: disable=too-few-public-methods "This field is deprecated and should be passed to `extras` " "as `druid_time_origin`.", allow_none=True, + deprecated=True, ) url_params = fields.Dict( description="Optional query parameters passed to a dashboard or Explore view", @@ -1205,6 +1205,7 @@ class ChartDataQueryContextSchema(Schema): force = fields.Boolean( description="Should the queries be forced to load from the source. " "Default: `false`", + allow_none=True, ) result_type = EnumField(ChartDataResultType, by_value=True) @@ -1298,7 +1299,7 @@ class ChartDataResponseResult(Schema): allow_none=False, ) stacktrace = fields.String( - desciption="Stacktrace if there was an error", + description="Stacktrace if there was an error", allow_none=True, ) rowcount = fields.Integer( @@ -1317,10 +1318,10 @@ class ChartDataResponseResult(Schema): fields.Dict(), description="A list with rejected filters" ) from_dttm = fields.Integer( - desciption="Start timestamp of time range", required=False, allow_none=True + description="Start timestamp of time range", required=False, allow_none=True ) to_dttm = fields.Integer( - desciption="End timestamp of time range", required=False, allow_none=True + description="End timestamp of time range", required=False, allow_none=True ) @@ -1368,6 +1369,9 @@ class GetFavStarIdsSchema(Schema): class ImportV1ChartSchema(Schema): slice_name = fields.String(required=True) + description = fields.String(allow_none=True) + certified_by = fields.String(allow_none=True) + certification_details = fields.String(allow_none=True) viz_type = fields.String(required=True) params = fields.Dict() query_context = fields.String(allow_none=True, validate=utils.validate_json) diff --git a/superset/cli/examples.py b/superset/cli/examples.py index cad87da9d3d25..d4ba3af87e531 100755 --- a/superset/cli/examples.py +++ b/superset/cli/examples.py @@ -54,6 +54,9 @@ def load_examples_run( if load_test_data: print("Loading [Tabbed dashboard]") examples.load_tabbed_dashboard(only_metadata) + + print("Loading [Supported Charts Dashboard]") + examples.load_supported_charts_dashboard() else: print("Loading [Random long/lat data]") examples.load_long_lat_data(only_metadata, force) diff --git a/superset/cli/importexport.py b/superset/cli/importexport.py index 1ddaf7cfc8d00..6ca58e9952dfd 100755 --- a/superset/cli/importexport.py +++ b/superset/cli/importexport.py @@ -66,7 +66,7 @@ def import_directory(directory: str, overwrite: bool, force: bool) -> None: @click.option( "--dashboard-file", "-f", - help="Specify the the file to export to", + help="Specify the file to export to", ) def export_dashboards(dashboard_file: Optional[str] = None) -> None: """Export dashboards to ZIP file""" @@ -101,7 +101,7 @@ def export_dashboards(dashboard_file: Optional[str] = None) -> None: @click.option( "--datasource-file", "-f", - help="Specify the the file to export to", + help="Specify the file to export to", ) def export_datasources(datasource_file: Optional[str] = None) -> None: """Export datasources to ZIP file""" @@ -206,7 +206,7 @@ def import_datasources(path: str) -> None: "--dashboard-file", "-f", default=None, - help="Specify the the file to export to", + help="Specify the file to export to", ) @click.option( "--print_stdout", @@ -236,7 +236,7 @@ def export_dashboards( "--datasource-file", "-f", default=None, - help="Specify the the file to export to", + help="Specify the file to export to", ) @click.option( "--print_stdout", diff --git a/superset/cli/thumbnails.py b/superset/cli/thumbnails.py index 5556cff92f620..276d9981c1ec2 100755 --- a/superset/cli/thumbnails.py +++ b/superset/cli/thumbnails.py @@ -22,7 +22,6 @@ from flask.cli import with_appcontext from superset.extensions import db -from superset.utils.urls import get_url_path logger = logging.getLogger(__name__) @@ -94,13 +93,7 @@ def compute_generic_thumbnail( action = "Processing" msg = f'{action} {friendly_type} "{model}" ({i+1}/{count})' click.secho(msg, fg="green") - if friendly_type == "chart": - url = get_url_path( - "Superset.slice", slice_id=model.id, standalone="true" - ) - else: - url = get_url_path("Superset.dashboard", dashboard_id_or_slug=model.id) - func(url, model.digest, force=force) + func(None, model.id, force=force) if not charts_only: compute_generic_thumbnail( diff --git a/superset/cli/update.py b/superset/cli/update.py index ae4ad644c9a8c..bdc54db3a9c99 100755 --- a/superset/cli/update.py +++ b/superset/cli/update.py @@ -30,8 +30,6 @@ from flask_appbuilder.api.manager import resolver import superset.utils.database as database_utils -from superset.extensions import db -from superset.utils.core import override_user from superset.utils.encrypt import SecretsMigrator logger = logging.getLogger(__name__) @@ -53,38 +51,6 @@ def set_database_uri(database_name: str, uri: str, skip_create: bool) -> None: database_utils.get_or_create_db(database_name, uri, not skip_create) -@click.command() -@with_appcontext -@click.option( - "--username", - "-u", - default=None, - help=( - "Specify which user should execute the underlying SQL queries. If undefined " - "defaults to the user registered with the database connection." - ), -) -def update_datasources_cache(username: Optional[str]) -> None: - """Refresh sqllab datasources cache""" - # pylint: disable=import-outside-toplevel - from superset import security_manager - from superset.models.core import Database - - with override_user(security_manager.find_user(username)): - for database in db.session.query(Database).all(): - if database.allow_multi_schema_metadata_fetch: - print("Fetching {} datasources ...".format(database.name)) - try: - database.get_all_table_names_in_database( - force=True, cache=True, cache_timeout=24 * 60 * 60 - ) - database.get_all_view_names_in_database( - force=True, cache=True, cache_timeout=24 * 60 * 60 - ) - except Exception as ex: # pylint: disable=broad-except - print("{}".format(str(ex))) - - @click.command() @with_appcontext def sync_tags() -> None: @@ -95,9 +61,9 @@ def sync_tags() -> None: # pylint: disable=import-outside-toplevel from superset.common.tags import add_favorites, add_owners, add_types - add_types(db.engine, metadata) - add_owners(db.engine, metadata) - add_favorites(db.engine, metadata) + add_types(metadata) + add_owners(metadata) + add_favorites(metadata) @click.command() diff --git a/superset/commands/base.py b/superset/commands/base.py index 552b95feb2e1e..42d5956312cd3 100644 --- a/superset/commands/base.py +++ b/superset/commands/base.py @@ -45,34 +45,28 @@ def validate(self) -> None: class CreateMixin: # pylint: disable=too-few-public-methods @staticmethod - def populate_owners( - user: User, owner_ids: Optional[List[int]] = None - ) -> List[User]: + def populate_owners(owner_ids: Optional[List[int]] = None) -> List[User]: """ Populate list of owners, defaulting to the current user if `owner_ids` is undefined or empty. If current user is missing in `owner_ids`, current user is added unless belonging to the Admin role. - :param user: current user :param owner_ids: list of owners by id's :raises OwnersNotFoundValidationError: if at least one owner can't be resolved :returns: Final list of owners """ - return populate_owners(user, owner_ids, default_to_user=True) + return populate_owners(owner_ids, default_to_user=True) class UpdateMixin: # pylint: disable=too-few-public-methods @staticmethod - def populate_owners( - user: User, owner_ids: Optional[List[int]] = None - ) -> List[User]: + def populate_owners(owner_ids: Optional[List[int]] = None) -> List[User]: """ Populate list of owners. If current user is missing in `owner_ids`, current user is added unless belonging to the Admin role. - :param user: current user :param owner_ids: list of owners by id's :raises OwnersNotFoundValidationError: if at least one owner can't be resolved :returns: Final list of owners """ - return populate_owners(user, owner_ids, default_to_user=False) + return populate_owners(owner_ids, default_to_user=False) diff --git a/superset/commands/importers/v1/__init__.py b/superset/commands/importers/v1/__init__.py index c620ec9f2ac85..fc67d1822e542 100644 --- a/superset/commands/importers/v1/__init__.py +++ b/superset/commands/importers/v1/__init__.py @@ -67,6 +67,9 @@ def run(self) -> None: try: self._import(db.session, self._configs, self.overwrite) db.session.commit() + except CommandException as ex: + db.session.rollback() + raise ex except Exception as ex: db.session.rollback() raise self.import_error() from ex diff --git a/superset/commands/importers/v1/assets.py b/superset/commands/importers/v1/assets.py index 9f945c560af5f..b63de59536c6b 100644 --- a/superset/commands/importers/v1/assets.py +++ b/superset/commands/importers/v1/assets.py @@ -14,12 +14,12 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional from marshmallow import Schema from marshmallow.exceptions import ValidationError from sqlalchemy.orm import Session -from sqlalchemy.sql import select +from sqlalchemy.sql import delete, insert from superset import db from superset.charts.commands.importers.v1.utils import import_chart @@ -70,7 +70,6 @@ def __init__(self, contents: Dict[str, str], *args: Any, **kwargs: Any): self.passwords: Dict[str, str] = kwargs.get("passwords") or {} self._configs: Dict[str, Any] = {} - # pylint: disable=too-many-locals @staticmethod def _import(session: Session, configs: Dict[str, Any]) -> None: # import databases first @@ -106,31 +105,30 @@ def _import(session: Session, configs: Dict[str, Any]) -> None: chart = import_chart(session, config, overwrite=True) chart_ids[str(chart.uuid)] = chart.id - # store the existing relationship between dashboards and charts - existing_relationships = session.execute( - select([dashboard_slices.c.dashboard_id, dashboard_slices.c.slice_id]) - ).fetchall() - # import dashboards - dashboard_chart_ids: List[Tuple[int, int]] = [] for file_name, config in configs.items(): if file_name.startswith("dashboards/"): config = update_id_refs(config, chart_ids, dataset_info) dashboard = import_dashboard(session, config, overwrite=True) + + # set ref in the dashboard_slices table + dashboard_chart_ids: List[Dict[str, int]] = [] for uuid in find_chart_uuids(config["position"]): if uuid not in chart_ids: break chart_id = chart_ids[uuid] - if (dashboard.id, chart_id) not in existing_relationships: - dashboard_chart_ids.append((dashboard.id, chart_id)) - - # set ref in the dashboard_slices table - values = [ - {"dashboard_id": dashboard_id, "slice_id": chart_id} - for (dashboard_id, chart_id) in dashboard_chart_ids - ] - # pylint: disable=no-value-for-parameter # sqlalchemy/issues/4656 - session.execute(dashboard_slices.insert(), values) + dashboard_chart_id = { + "dashboard_id": dashboard.id, + "slice_id": chart_id, + } + dashboard_chart_ids.append(dashboard_chart_id) + + session.execute( + delete(dashboard_slices).where( + dashboard_slices.c.dashboard_id == dashboard.id + ) + ) + session.execute(insert(dashboard_slices).values(dashboard_chart_ids)) def run(self) -> None: self.validate() diff --git a/superset/commands/importers/v1/examples.py b/superset/commands/importers/v1/examples.py index 679b9c441beb4..99aa831faaa4f 100644 --- a/superset/commands/importers/v1/examples.py +++ b/superset/commands/importers/v1/examples.py @@ -181,5 +181,4 @@ def _import( # pylint: disable=arguments-differ, too-many-locals, too-many-bran {"dashboard_id": dashboard_id, "slice_id": chart_id} for (dashboard_id, chart_id) in dashboard_chart_ids ] - # pylint: disable=no-value-for-parameter # sqlalchemy/issues/4656 session.execute(dashboard_slices.insert(), values) diff --git a/superset/commands/importers/v1/utils.py b/superset/commands/importers/v1/utils.py index 3999669356ae9..1e73886682ac0 100644 --- a/superset/commands/importers/v1/utils.py +++ b/superset/commands/importers/v1/utils.py @@ -14,7 +14,7 @@ # under the License. import logging -from pathlib import Path +from pathlib import Path, PurePosixPath from typing import Any, Dict, List, Optional from zipfile import ZipFile @@ -34,8 +34,8 @@ def remove_root(file_path: str) -> str: """Remove the first directory of a path""" - full_path = Path(file_path) - relative_path = Path(*full_path.parts[1:]) + full_path = PurePosixPath(file_path) + relative_path = PurePosixPath(*full_path.parts[1:]) return str(relative_path) diff --git a/superset/commands/utils.py b/superset/commands/utils.py index f7564b3de7689..ad58bb40506f7 100644 --- a/superset/commands/utils.py +++ b/superset/commands/utils.py @@ -18,29 +18,31 @@ from typing import List, Optional, TYPE_CHECKING +from flask import g from flask_appbuilder.security.sqla.models import Role, User +from superset import security_manager from superset.commands.exceptions import ( DatasourceNotFoundValidationError, OwnersNotFoundValidationError, RolesNotFoundValidationError, ) -from superset.connectors.connector_registry import ConnectorRegistry -from superset.datasets.commands.exceptions import DatasetNotFoundError -from superset.extensions import db, security_manager +from superset.dao.exceptions import DatasourceNotFound +from superset.datasource.dao import DatasourceDAO +from superset.extensions import db +from superset.utils.core import DatasourceType, get_user_id if TYPE_CHECKING: from superset.connectors.base.models import BaseDatasource def populate_owners( - user: User, owner_ids: Optional[List[int]], default_to_user: bool, ) -> List[User]: """ Helper function for commands, will fetch all users from owners id's - :param user: current user + :param owner_ids: list of owners by id's :param default_to_user: make user the owner if `owner_ids` is None or empty :raises OwnersNotFoundValidationError: if at least one owner id can't be resolved @@ -49,12 +51,10 @@ def populate_owners( owner_ids = owner_ids or [] owners = [] if not owner_ids and default_to_user: - return [user] - if user.id not in owner_ids and "admin" not in [ - role.name.lower() for role in user.roles - ]: + return [g.user] + if not (security_manager.is_admin() or get_user_id() in owner_ids): # make sure non-admins can't remove themselves as owner by mistake - owners.append(user) + owners.append(g.user) for owner_id in owner_ids: owner = security_manager.get_user_by_id(owner_id) if not owner: @@ -79,8 +79,8 @@ def populate_roles(role_ids: Optional[List[int]] = None) -> List[Role]: def get_datasource_by_id(datasource_id: int, datasource_type: str) -> BaseDatasource: try: - return ConnectorRegistry.get_datasource( - datasource_type, datasource_id, db.session + return DatasourceDAO.get_datasource( + db.session, DatasourceType(datasource_type), datasource_id ) - except DatasetNotFoundError as ex: + except DatasourceNotFound as ex: raise DatasourceNotFoundValidationError() from ex diff --git a/superset/common/chart_data.py b/superset/common/chart_data.py index f3917d6d87177..659a640159378 100644 --- a/superset/common/chart_data.py +++ b/superset/common/chart_data.py @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. from enum import Enum +from typing import Set class ChartDataResultFormat(str, Enum): @@ -24,6 +25,11 @@ class ChartDataResultFormat(str, Enum): CSV = "csv" JSON = "json" + XLSX = "xlsx" + + @classmethod + def table_like(cls) -> Set["ChartDataResultFormat"]: + return {cls.CSV} | {cls.XLSX} class ChartDataResultType(str, Enum): @@ -38,3 +44,4 @@ class ChartDataResultType(str, Enum): SAMPLES = "samples" TIMEGRAINS = "timegrains" POST_PROCESSED = "post_processed" + DRILL_DETAIL = "drill_detail" diff --git a/superset/common/query_actions.py b/superset/common/query_actions.py index 5899757d528d8..bfb3d368789d9 100644 --- a/superset/common/query_actions.py +++ b/superset/common/query_actions.py @@ -150,12 +150,39 @@ def _get_samples( query_obj.orderby = [] query_obj.metrics = None query_obj.post_processing = [] - query_obj.columns = [o.column_name for o in datasource.columns] + qry_obj_cols = [] + for o in datasource.columns: + if isinstance(o, dict): + qry_obj_cols.append(o.get("column_name")) + else: + qry_obj_cols.append(o.column_name) + query_obj.columns = qry_obj_cols query_obj.from_dttm = None query_obj.to_dttm = None return _get_full(query_context, query_obj, force_cached) +def _get_drill_detail( + query_context: QueryContext, query_obj: QueryObject, force_cached: bool = False +) -> Dict[str, Any]: + # todo(yongjie): Remove this function, + # when determining whether samples should be applied to the time filter. + datasource = _get_datasource(query_context, query_obj) + query_obj = copy.copy(query_obj) + query_obj.is_timeseries = False + query_obj.orderby = [] + query_obj.metrics = None + query_obj.post_processing = [] + qry_obj_cols = [] + for o in datasource.columns: + if isinstance(o, dict): + qry_obj_cols.append(o.get("column_name")) + else: + qry_obj_cols.append(o.column_name) + query_obj.columns = qry_obj_cols + return _get_full(query_context, query_obj, force_cached) + + def _get_results( query_context: QueryContext, query_obj: QueryObject, force_cached: bool = False ) -> Dict[str, Any]: @@ -176,6 +203,7 @@ def _get_results( # and post-process it later where we have the chart context, since # post-processing is unique to each visualization type ChartDataResultType.POST_PROCESSED: _get_full, + ChartDataResultType.DRILL_DETAIL: _get_drill_detail, } diff --git a/superset/common/query_context_factory.py b/superset/common/query_context_factory.py index 9a8aaefa9f789..126000a83d274 100644 --- a/superset/common/query_context_factory.py +++ b/superset/common/query_context_factory.py @@ -22,10 +22,11 @@ from superset.charts.dao import ChartDAO from superset.common.chart_data import ChartDataResultFormat, ChartDataResultType from superset.common.query_context import QueryContext +from superset.common.query_object import QueryObject from superset.common.query_object_factory import QueryObjectFactory -from superset.connectors.connector_registry import ConnectorRegistry +from superset.datasource.dao import DatasourceDAO from superset.models.slice import Slice -from superset.utils.core import DatasourceDict +from superset.utils.core import DatasourceDict, DatasourceType if TYPE_CHECKING: from superset.connectors.base.models import BaseDatasource @@ -34,7 +35,7 @@ def create_query_object_factory() -> QueryObjectFactory: - return QueryObjectFactory(config, ConnectorRegistry(), db.session) + return QueryObjectFactory(config, DatasourceDAO(), db.session) class QueryContextFactory: # pylint: disable=too-few-public-methods @@ -66,8 +67,12 @@ def create( result_type = result_type or ChartDataResultType.FULL result_format = result_format or ChartDataResultFormat.JSON queries_ = [ - self._query_object_factory.create( - result_type, datasource=datasource, **query_obj + self._process_query_object( + datasource_model_instance, + form_data, + self._query_object_factory.create( + result_type, datasource=datasource, **query_obj + ), ) for query_obj in queries ] @@ -92,9 +97,97 @@ def create( # pylint: disable=no-self-use def _convert_to_model(self, datasource: DatasourceDict) -> BaseDatasource: - return ConnectorRegistry.get_datasource( - str(datasource["type"]), int(datasource["id"]), db.session + return DatasourceDAO.get_datasource( + session=db.session, + datasource_type=DatasourceType(datasource["type"]), + datasource_id=int(datasource["id"]), ) def _get_slice(self, slice_id: Any) -> Optional[Slice]: return ChartDAO.find_by_id(slice_id) + + def _process_query_object( + self, + datasource: BaseDatasource, + form_data: Optional[Dict[str, Any]], + query_object: QueryObject, + ) -> QueryObject: + self._apply_granularity(query_object, form_data, datasource) + self._apply_filters(query_object) + return query_object + + def _apply_granularity( + self, + query_object: QueryObject, + form_data: Optional[Dict[str, Any]], + datasource: BaseDatasource, + ) -> None: + temporal_columns = { + column["column_name"] if isinstance(column, dict) else column.column_name + for column in datasource.columns + if (column["is_dttm"] if isinstance(column, dict) else column.is_dttm) + } + granularity = query_object.granularity + x_axis = form_data and form_data.get("x_axis") + + if granularity: + filter_to_remove = None + if x_axis and x_axis in temporal_columns: + filter_to_remove = x_axis + x_axis_column = next( + ( + column + for column in query_object.columns + if column == x_axis + or ( + isinstance(column, dict) + and column["sqlExpression"] == x_axis + ) + ), + None, + ) + # Replaces x-axis column values with granularity + if x_axis_column: + if isinstance(x_axis_column, dict): + x_axis_column["sqlExpression"] = granularity + x_axis_column["label"] = granularity + else: + query_object.columns = [ + granularity if column == x_axis_column else column + for column in query_object.columns + ] + for post_processing in query_object.post_processing: + if post_processing.get("operation") == "pivot": + post_processing["options"]["index"] = [granularity] + + # If no temporal x-axis, then get the default temporal filter + if not filter_to_remove: + temporal_filters = [ + filter["col"] + for filter in query_object.filter + if filter["op"] == "TEMPORAL_RANGE" + ] + if len(temporal_filters) > 0: + # Use granularity if it's already in the filters + if granularity in temporal_filters: + filter_to_remove = granularity + else: + # Use the first temporal filter + filter_to_remove = temporal_filters[0] + + # Removes the temporal filter which may be an x-axis or + # another temporal filter. A new filter based on the value of + # the granularity will be added later in the code. + # In practice, this is replacing the previous default temporal filter. + if filter_to_remove: + query_object.filter = [ + filter + for filter in query_object.filter + if filter["col"] != filter_to_remove + ] + + def _apply_filters(self, query_object: QueryObject) -> None: + if query_object.time_range: + for filter_object in query_object.filter: + if filter_object["op"] == "TEMPORAL_RANGE": + filter_object["val"] = query_object.time_range diff --git a/superset/common/query_context_processor.py b/superset/common/query_context_processor.py index 606836b1de88f..77ca69fcf6f02 100644 --- a/superset/common/query_context_processor.py +++ b/superset/common/query_context_processor.py @@ -18,6 +18,7 @@ import copy import logging +import re from typing import Any, ClassVar, Dict, List, Optional, TYPE_CHECKING, Union import numpy as np @@ -32,8 +33,9 @@ from superset.common.chart_data import ChartDataResultFormat from superset.common.db_query_status import QueryStatus from superset.common.query_actions import get_query_results -from superset.common.utils import dataframe_utils as df_utils +from superset.common.utils import dataframe_utils from superset.common.utils.query_cache_manager import QueryCacheManager +from superset.common.utils.time_range_utils import get_since_until_from_query_object from superset.connectors.base.models import BaseDatasource from superset.constants import CacheRegion from superset.exceptions import ( @@ -43,18 +45,24 @@ ) from superset.extensions import cache_manager, security_manager from superset.models.helpers import QueryResult -from superset.utils import csv +from superset.models.sql_lab import Query +from superset.utils import csv, excel from superset.utils.cache import generate_cache_key, set_and_log_cache from superset.utils.core import ( + DatasourceType, + DateColumn, DTTM_ALIAS, error_msg_from_exception, + get_base_axis_labels, get_column_names_from_columns, get_column_names_from_metrics, get_metric_names, + get_xaxis_label, normalize_dttm_col, TIME_COMPARISON, ) from superset.utils.date_parser import get_past_or_future, normalize_time_delta +from superset.utils.pandas_postprocessing.utils import unescape_separator from superset.views.utils import get_viz if TYPE_CHECKING: @@ -116,13 +124,15 @@ def get_df_payload( and col != DTTM_ALIAS ) ] + if invalid_columns: raise QueryObjectValidationError( _( - "Columns missing in datasource: %(invalid_columns)s", + "Columns missing in dataset: %(invalid_columns)s", invalid_columns=invalid_columns, ) ) + query_result = self.get_query_result(query_obj) annotation_data = self.get_annotation_data(query_obj) cache.set_query_result( @@ -138,6 +148,17 @@ def get_df_payload( cache.error_message = str(ex) cache.status = QueryStatus.FAILED + # the N-dimensional DataFrame has converteds into flat DataFrame + # by `flatten operator`, "comma" in the column is escaped by `escape_separator` + # the result DataFrame columns should be unescaped + label_map = { + unescape_separator(col): [ + unescape_separator(col) for col in re.split(r"(?<!\\),\s", col) + ] + for col in cache.df.columns.values + } + cache.df.columns = [unescape_separator(col) for col in cache.df.columns.values] + return { "cache_key": cache_key, "cached_dttm": cache.cache_dttm, @@ -153,6 +174,7 @@ def get_df_payload( "rowcount": len(cache.df.index), "from_dttm": query_obj.from_dttm, "to_dttm": query_obj.to_dttm, + "label_map": label_map, } def query_cache_key(self, query_obj: QueryObject, **kwargs: Any) -> Optional[str]: @@ -182,9 +204,13 @@ def get_query_result(self, query_object: QueryObject) -> QueryResult: # a valid assumption for current setting. In the long term, we may # support multiple queries from different data sources. - # The datasource here can be different backend but the interface is common - result = query_context.datasource.query(query_object.to_dict()) - query = result.query + ";\n\n" + query = "" + if isinstance(query_context.datasource, Query): + # todo(hugh): add logic to manage all sip68 models here + result = query_context.datasource.exc_query(query_object.to_dict()) + else: + result = query_context.datasource.query(query_object.to_dict()) + query = result.query + ";\n\n" df = result.df # Transform the timestamp we received from database to pandas supported @@ -216,28 +242,68 @@ def get_query_result(self, query_object: QueryObject) -> QueryResult: return result def normalize_df(self, df: pd.DataFrame, query_object: QueryObject) -> pd.DataFrame: - datasource = self._qc_datasource - timestamp_format = None - if datasource.type == "table": - dttm_col = datasource.get_column(query_object.granularity) - if dttm_col: - timestamp_format = dttm_col.python_date_format + # todo: should support "python_date_format" and "get_column" in each datasource + def _get_timestamp_format( + source: BaseDatasource, column: Optional[str] + ) -> Optional[str]: + column_obj = source.get_column(column) + if ( + column_obj + # only sqla column was supported + and hasattr(column_obj, "python_date_format") + and (formatter := column_obj.python_date_format) + ): + return str(formatter) + + return None + datasource = self._qc_datasource + labels = tuple( + label + for label in [ + *get_base_axis_labels(query_object.columns), + query_object.granularity, + ] + if datasource + # Query datasource didn't support `get_column` + and hasattr(datasource, "get_column") + and (col := datasource.get_column(label)) + # todo(hugh) standardize column object in Query datasource + and (col.get("is_dttm") if isinstance(col, dict) else col.is_dttm) + ) + dttm_cols = [ + DateColumn( + timestamp_format=_get_timestamp_format(datasource, label), + offset=datasource.offset, + time_shift=query_object.time_shift, + col_label=label, + ) + for label in labels + if label + ] + if DTTM_ALIAS in df: + dttm_cols.append( + DateColumn.get_legacy_time_column( + timestamp_format=_get_timestamp_format( + datasource, query_object.granularity + ), + offset=datasource.offset, + time_shift=query_object.time_shift, + ) + ) normalize_dttm_col( df=df, - timestamp_format=timestamp_format, - offset=datasource.offset, - time_shift=query_object.time_shift, + dttm_cols=tuple(dttm_cols), ) if self.enforce_numerical_metrics: - df_utils.df_metrics_to_num(df, query_object) + dataframe_utils.df_metrics_to_num(df, query_object) df.replace([np.inf, -np.inf], np.nan, inplace=True) return df - def processing_time_offsets( # pylint: disable=too-many-locals + def processing_time_offsets( # pylint: disable=too-many-locals,too-many-statements self, df: pd.DataFrame, query_object: QueryObject, @@ -250,15 +316,36 @@ def processing_time_offsets( # pylint: disable=too-many-locals rv_dfs: List[pd.DataFrame] = [df] time_offsets = query_object.time_offsets - outer_from_dttm = query_object.from_dttm - outer_to_dttm = query_object.to_dttm + outer_from_dttm, outer_to_dttm = get_since_until_from_query_object(query_object) + if not outer_from_dttm or not outer_to_dttm: + raise QueryObjectValidationError( + _( + "An enclosed time range (both start and end) must be specified " + "when using a Time Comparison." + ) + ) for offset in time_offsets: try: + # pylint: disable=line-too-long + # Since the xaxis is also a column name for the time filter, xaxis_label will be set as granularity + # these query object are equivalent: + # 1) { granularity: 'dttm_col', time_range: '2020 : 2021', time_offsets: ['1 year ago']} + # 2) { columns: [ + # {label: 'dttm_col', sqlExpression: 'dttm_col', "columnType": "BASE_AXIS" } + # ], + # time_offsets: ['1 year ago'], + # filters: [{col: 'dttm_col', op: 'TEMPORAL_RANGE', val: '2020 : 2021'}], + # } query_object_clone.from_dttm = get_past_or_future( offset, outer_from_dttm, ) query_object_clone.to_dttm = get_past_or_future(offset, outer_to_dttm) + + xaxis_label = get_xaxis_label(query_object.columns) + query_object_clone.granularity = ( + query_object_clone.granularity or xaxis_label + ) except ValueError as ex: raise QueryObjectValidationError(str(ex)) from ex # make sure subquery use main query where clause @@ -266,14 +353,12 @@ def processing_time_offsets( # pylint: disable=too-many-locals query_object_clone.inner_to_dttm = outer_to_dttm query_object_clone.time_offsets = [] query_object_clone.post_processing = [] + query_object_clone.filter = [ + flt + for flt in query_object_clone.filter + if flt.get("col") != xaxis_label + ] - if not query_object.from_dttm or not query_object.to_dttm: - raise QueryObjectValidationError( - _( - "An enclosed time range (both start and end) must be specified " - "when using a Time Comparison." - ) - ) # `offset` is added to the hash function cache_key = self.query_cache_key(query_object_clone, time_offset=offset) cache = QueryCacheManager.get( @@ -296,7 +381,11 @@ def processing_time_offsets( # pylint: disable=too-many-locals } join_keys = [col for col in df.columns if col not in metrics_mapping.keys()] - result = self._qc_datasource.query(query_object_clone_dct) + if isinstance(self._qc_datasource, Query): + result = self._qc_datasource.exc_query(query_object_clone_dct) + else: + result = self._qc_datasource.query(query_object_clone_dct) + queries.append(result.query) cache_keys.append(None) @@ -318,13 +407,8 @@ def processing_time_offsets( # pylint: disable=too-many-locals offset_metrics_df = offset_metrics_df.rename(columns=metrics_mapping) # 3. set time offset for index - # TODO: add x-axis to QueryObject, potentially as an array for - # multi-dimensional charts - granularity = query_object.granularity - index = granularity if granularity in df.columns else DTTM_ALIAS - if not pd.api.types.is_datetime64_any_dtype( - offset_metrics_df.get(index) - ): + index = (get_base_axis_labels(query_object.columns) or [DTTM_ALIAS])[0] + if not dataframe_utils.is_datetime_series(offset_metrics_df.get(index)): raise QueryObjectValidationError( _( "A time column must be specified " @@ -337,7 +421,7 @@ def processing_time_offsets( # pylint: disable=too-many-locals ) # df left join `offset_metrics_df` - offset_df = df_utils.left_join_df( + offset_df = dataframe_utils.left_join_df( left_df=df, right_df=offset_metrics_df, join_keys=join_keys, @@ -362,15 +446,20 @@ def processing_time_offsets( # pylint: disable=too-many-locals return CachedTimeOffset(df=rv_df, queries=queries, cache_keys=cache_keys) def get_data(self, df: pd.DataFrame) -> Union[str, List[Dict[str, Any]]]: - if self._query_context.result_format == ChartDataResultFormat.CSV: + if self._query_context.result_format in ChartDataResultFormat.table_like(): include_index = not isinstance(df.index, pd.RangeIndex) columns = list(df.columns) verbose_map = self._qc_datasource.data.get("verbose_map", {}) if verbose_map: df.columns = [verbose_map.get(column, column) for column in columns] - result = csv.df_to_escaped_csv( - df, index=include_index, **config["CSV_EXPORT"] - ) + + result = None + if self._query_context.result_format == ChartDataResultFormat.CSV: + result = csv.df_to_escaped_csv( + df, index=include_index, **config["CSV_EXPORT"] + ) + elif self._query_context.result_format == ChartDataResultFormat.XLSX: + result = excel.df_to_excel(df, **config["EXCEL_EXPORT"]) return result or "" return df.to_dict(orient="records") @@ -489,7 +578,10 @@ def get_viz_annotation_data( chart = ChartDAO.find_by_id(annotation_layer["value"]) if not chart: raise QueryObjectValidationError(_("The chart does not exist")) + if not chart.datasource: + raise QueryObjectValidationError(_("The chart datasource does not exist")) form_data = chart.form_data.copy() + form_data.update(annotation_layer.get("overrides", {})) try: viz_obj = get_viz( datasource_type=chart.datasource.type, @@ -510,4 +602,8 @@ def raise_for_access(self) -> None: """ for query in self._query_context.queries: query.validate() - security_manager.raise_for_access(query_context=self._query_context) + + if self._qc_datasource.type == DatasourceType.QUERY: + security_manager.raise_for_access(query=self._qc_datasource) + else: + security_manager.raise_for_access(query_context=self._query_context) diff --git a/superset/common/query_object.py b/superset/common/query_object.py index a8585fd47e055..94cf2a74ccaa9 100644 --- a/superset/common/query_object.py +++ b/superset/common/query_object.py @@ -19,7 +19,7 @@ import json import logging -from datetime import datetime, timedelta +from datetime import datetime from pprint import pformat from typing import Any, Dict, List, NamedTuple, Optional, TYPE_CHECKING @@ -46,7 +46,6 @@ json_int_dttm_ser, QueryObjectFilterClause, ) -from superset.utils.date_parser import parse_human_timedelta from superset.utils.hashing import md5_sha_from_dict if TYPE_CHECKING: @@ -73,8 +72,6 @@ class DeprecatedField(NamedTuple): DEPRECATED_EXTRAS_FIELDS = ( DeprecatedField(old_name="where", new_name="where"), DeprecatedField(old_name="having", new_name="having"), - DeprecatedField(old_name="having_filters", new_name="having_druid"), - DeprecatedField(old_name="druid_time_origin", new_name="druid_time_origin"), ) @@ -108,7 +105,7 @@ class QueryObject: # pylint: disable=too-many-instance-attributes series_limit: int series_limit_metric: Optional[Metric] time_offsets: List[str] - time_shift: Optional[timedelta] + time_shift: Optional[str] time_range: Optional[str] to_dttm: Optional[datetime] @@ -158,7 +155,7 @@ def __init__( # pylint: disable=too-many-locals self.series_limit = series_limit self.series_limit_metric = series_limit_metric self.time_range = time_range - self.time_shift = parse_human_timedelta(time_shift) + self.time_shift = time_shift self.from_dttm = kwargs.get("from_dttm") self.to_dttm = kwargs.get("to_dttm") self.result_type = kwargs.get("result_type") @@ -338,6 +335,7 @@ def to_dict(self) -> Dict[str, Any]: "series_limit": self.series_limit, "series_limit_metric": self.series_limit_metric, "to_dttm": self.to_dttm, + "time_shift": self.time_shift, } return query_object_dict diff --git a/superset/common/query_object_factory.py b/superset/common/query_object_factory.py index 64ae99deebabc..88cc7ca1b461b 100644 --- a/superset/common/query_object_factory.py +++ b/superset/common/query_object_factory.py @@ -16,34 +16,33 @@ # under the License. from __future__ import annotations -from datetime import datetime -from typing import Any, Dict, Optional, Tuple, TYPE_CHECKING +from typing import Any, Dict, Optional, TYPE_CHECKING from superset.common.chart_data import ChartDataResultType from superset.common.query_object import QueryObject -from superset.utils.core import apply_max_row_limit, DatasourceDict -from superset.utils.date_parser import get_since_until +from superset.common.utils.time_range_utils import get_since_until_from_time_range +from superset.utils.core import apply_max_row_limit, DatasourceDict, DatasourceType if TYPE_CHECKING: from sqlalchemy.orm import sessionmaker - from superset import ConnectorRegistry from superset.connectors.base.models import BaseDatasource + from superset.datasource.dao import DatasourceDAO class QueryObjectFactory: # pylint: disable=too-few-public-methods _config: Dict[str, Any] - _connector_registry: ConnectorRegistry + _datasource_dao: DatasourceDAO _session_maker: sessionmaker def __init__( self, app_configurations: Dict[str, Any], - connector_registry: ConnectorRegistry, + _datasource_dao: DatasourceDAO, session_maker: sessionmaker, ): self._config = app_configurations - self._connector_registry = connector_registry + self._datasource_dao = _datasource_dao self._session_maker = session_maker def create( # pylint: disable=too-many-arguments @@ -62,7 +61,9 @@ def create( # pylint: disable=too-many-arguments processed_extras = self._process_extras(extras) result_type = kwargs.setdefault("result_type", parent_result_type) row_limit = self._process_row_limit(row_limit, result_type) - from_dttm, to_dttm = self._get_dttms(time_range, time_shift, processed_extras) + from_dttm, to_dttm = get_since_until_from_time_range( + time_range, time_shift, processed_extras + ) kwargs["from_dttm"] = from_dttm kwargs["to_dttm"] = to_dttm return QueryObject( @@ -75,8 +76,10 @@ def create( # pylint: disable=too-many-arguments ) def _convert_to_model(self, datasource: DatasourceDict) -> BaseDatasource: - return self._connector_registry.get_datasource( - str(datasource["type"]), int(datasource["id"]), self._session_maker() + return self._datasource_dao.get_datasource( + datasource_type=DatasourceType(datasource["type"]), + datasource_id=int(datasource["id"]), + session=self._session_maker(), ) def _process_extras( # pylint: disable=no-self-use @@ -96,23 +99,6 @@ def _process_row_limit( ) return apply_max_row_limit(row_limit or default_row_limit) - def _get_dttms( - self, - time_range: Optional[str], - time_shift: Optional[str], - extras: Dict[str, Any], - ) -> Tuple[Optional[datetime], Optional[datetime]]: - return get_since_until( - relative_start=extras.get( - "relative_start", self._config["DEFAULT_RELATIVE_START_TIME"] - ), - relative_end=extras.get( - "relative_end", self._config["DEFAULT_RELATIVE_END_TIME"] - ), - time_range=time_range, - time_shift=time_shift, - ) - # light version of the view.utils.core # import view.utils require application context # Todo: move it and the view.utils.core to utils package diff --git a/superset/common/tags.py b/superset/common/tags.py index 74c882cf92f69..706192913a1c3 100644 --- a/superset/common/tags.py +++ b/superset/common/tags.py @@ -14,76 +14,20 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from sqlalchemy import Metadata -from sqlalchemy.engine import Engine -from sqlalchemy.exc import IntegrityError -from sqlalchemy.sql import and_, func, functions, join, literal, select - -from superset.models.tags import ObjectTypes, TagTypes +from typing import Any, List +from sqlalchemy import MetaData +from sqlalchemy.exc import IntegrityError +from sqlalchemy.sql import and_, func, join, literal, select -def add_types(engine: Engine, metadata: Metadata) -> None: - """ - Tag every object according to its type: - - INSERT INTO tagged_object (tag_id, object_id, object_type) - SELECT - tag.id AS tag_id, - slices.id AS object_id, - 'chart' AS object_type - FROM slices - JOIN tag - ON tag.name = 'type:chart' - LEFT OUTER JOIN tagged_object - ON tagged_object.tag_id = tag.id - AND tagged_object.object_id = slices.id - AND tagged_object.object_type = 'chart' - WHERE tagged_object.tag_id IS NULL; - - INSERT INTO tagged_object (tag_id, object_id, object_type) - SELECT - tag.id AS tag_id, - dashboards.id AS object_id, - 'dashboard' AS object_type - FROM dashboards - JOIN tag - ON tag.name = 'type:dashboard' - LEFT OUTER JOIN tagged_object - ON tagged_object.tag_id = tag.id - AND tagged_object.object_id = dashboards.id - AND tagged_object.object_type = 'dashboard' - WHERE tagged_object.tag_id IS NULL; - - INSERT INTO tagged_object (tag_id, object_id, object_type) - SELECT - tag.id AS tag_id, - saved_query.id AS object_id, - 'query' AS object_type - FROM saved_query - JOIN tag - ON tag.name = 'type:query'; - LEFT OUTER JOIN tagged_object - ON tagged_object.tag_id = tag.id - AND tagged_object.object_id = saved_query.id - AND tagged_object.object_type = 'query' - WHERE tagged_object.tag_id IS NULL; +from superset.extensions import db +from superset.tags.models import ObjectTypes, TagTypes - """ - tag = metadata.tables["tag"] - tagged_object = metadata.tables["tagged_object"] +def add_types_to_charts( + metadata: MetaData, tag: Any, tagged_object: Any, columns: List[str] +) -> None: slices = metadata.tables["slices"] - dashboards = metadata.tables["dashboards"] - saved_query = metadata.tables["saved_query"] - columns = ["tag_id", "object_id", "object_type"] - - # add a tag for each object type - insert = tag.insert() - for type_ in ObjectTypes.__members__: - try: - engine.execute(insert, name=f"type:{type_}", type=TagTypes.type) - except IntegrityError: - pass # already exists charts = ( select( @@ -109,23 +53,29 @@ def add_types(engine: Engine, metadata: Metadata) -> None: .where(tagged_object.c.tag_id.is_(None)) ) query = tagged_object.insert().from_select(columns, charts) - engine.execute(query) + db.session.execute(query) + + +def add_types_to_dashboards( + metadata: MetaData, tag: Any, tagged_object: Any, columns: List[str] +) -> None: + dashboard_table = metadata.tables["dashboards"] dashboards = ( select( [ tag.c.id.label("tag_id"), - dashboards.c.id.label("object_id"), + dashboard_table.c.id.label("object_id"), literal(ObjectTypes.dashboard.name).label("object_type"), ] ) .select_from( join( - join(dashboards, tag, tag.c.name == "type:dashboard"), + join(dashboard_table, tag, tag.c.name == "type:dashboard"), tagged_object, and_( tagged_object.c.tag_id == tag.c.id, - tagged_object.c.object_id == dashboards.c.id, + tagged_object.c.object_id == dashboard_table.c.id, tagged_object.c.object_type == "dashboard", ), isouter=True, @@ -135,7 +85,13 @@ def add_types(engine: Engine, metadata: Metadata) -> None: .where(tagged_object.c.tag_id.is_(None)) ) query = tagged_object.insert().from_select(columns, dashboards) - engine.execute(query) + db.session.execute(query) + + +def add_types_to_saved_queries( + metadata: MetaData, tag: Any, tagged_object: Any, columns: List[str] +) -> None: + saved_query = metadata.tables["saved_query"] saved_queries = ( select( @@ -161,12 +117,44 @@ def add_types(engine: Engine, metadata: Metadata) -> None: .where(tagged_object.c.tag_id.is_(None)) ) query = tagged_object.insert().from_select(columns, saved_queries) - engine.execute(query) + db.session.execute(query) + + +def add_types_to_datasets( + metadata: MetaData, tag: Any, tagged_object: Any, columns: List[str] +) -> None: + tables = metadata.tables["tables"] + + datasets = ( + select( + [ + tag.c.id.label("tag_id"), + tables.c.id.label("object_id"), + literal(ObjectTypes.dataset.name).label("object_type"), + ] + ) + .select_from( + join( + join(tables, tag, tag.c.name == "type:dataset"), + tagged_object, + and_( + tagged_object.c.tag_id == tag.c.id, + tagged_object.c.object_id == tables.c.id, + tagged_object.c.object_type == "dataset", + ), + isouter=True, + full=False, + ) + ) + .where(tagged_object.c.tag_id.is_(None)) + ) + query = tagged_object.insert().from_select(columns, datasets) + db.session.execute(query) -def add_owners(engine: Engine, metadata: Metadata) -> None: +def add_types(metadata: MetaData) -> None: """ - Tag every object according to its owner: + Tag every object according to its type: INSERT INTO tagged_object (tag_id, object_id, object_type) SELECT @@ -175,58 +163,84 @@ def add_owners(engine: Engine, metadata: Metadata) -> None: 'chart' AS object_type FROM slices JOIN tag - ON tag.name = CONCAT('owner:', slices.created_by_fk) + ON tag.name = 'type:chart' LEFT OUTER JOIN tagged_object ON tagged_object.tag_id = tag.id AND tagged_object.object_id = slices.id AND tagged_object.object_type = 'chart' WHERE tagged_object.tag_id IS NULL; + INSERT INTO tagged_object (tag_id, object_id, object_type) SELECT tag.id AS tag_id, dashboards.id AS object_id, 'dashboard' AS object_type FROM dashboards JOIN tag - ON tag.name = CONCAT('owner:', dashboards.created_by_fk) + ON tag.name = 'type:dashboard' LEFT OUTER JOIN tagged_object ON tagged_object.tag_id = tag.id AND tagged_object.object_id = dashboards.id AND tagged_object.object_type = 'dashboard' WHERE tagged_object.tag_id IS NULL; + INSERT INTO tagged_object (tag_id, object_id, object_type) SELECT tag.id AS tag_id, saved_query.id AS object_id, 'query' AS object_type FROM saved_query JOIN tag - ON tag.name = CONCAT('owner:', saved_query.created_by_fk) + ON tag.name = 'type:query'; LEFT OUTER JOIN tagged_object ON tagged_object.tag_id = tag.id AND tagged_object.object_id = saved_query.id AND tagged_object.object_type = 'query' WHERE tagged_object.tag_id IS NULL; + INSERT INTO tagged_object (tag_id, object_id, object_type) + SELECT + tag.id AS tag_id, + tables.id AS object_id, + 'dataset' AS object_type + FROM tables + JOIN tag + ON tag.name = 'type:dataset' + LEFT OUTER JOIN tagged_object + ON tagged_object.tag_id = tag.id + AND tagged_object.object_id = tables.id + AND tagged_object.object_type = 'dataset' + WHERE tagged_object.tag_id IS NULL; + """ tag = metadata.tables["tag"] tagged_object = metadata.tables["tagged_object"] - users = metadata.tables["ab_user"] - slices = metadata.tables["slices"] - dashboards = metadata.tables["dashboards"] - saved_query = metadata.tables["saved_query"] columns = ["tag_id", "object_id", "object_type"] - # create a custom tag for each user - ids = select([users.c.id]) + # add a tag for each object type insert = tag.insert() - for (id_,) in engine.execute(ids): + for type_ in ObjectTypes.__members__: try: - engine.execute(insert, name=f"owner:{id_}", type=TagTypes.owner) + db.session.execute( + insert, + name=f"type:{type_}", + type=TagTypes.type, + ) except IntegrityError: pass # already exists + add_types_to_charts(metadata, tag, tagged_object, columns) + add_types_to_dashboards(metadata, tag, tagged_object, columns) + add_types_to_saved_queries(metadata, tag, tagged_object, columns) + add_types_to_datasets(metadata, tag, tagged_object, columns) + + +def add_owners_to_charts( + metadata: MetaData, tag: Any, tagged_object: Any, columns: List[str] +) -> None: + slices = metadata.tables["slices"] + charts = ( select( [ @@ -240,7 +254,7 @@ def add_owners(engine: Engine, metadata: Metadata) -> None: join( slices, tag, - tag.c.name == functions.concat("owner:", slices.c.created_by_fk), + tag.c.name == "owner:" + slices.c.created_by_fk, ), tagged_object, and_( @@ -255,28 +269,33 @@ def add_owners(engine: Engine, metadata: Metadata) -> None: .where(tagged_object.c.tag_id.is_(None)) ) query = tagged_object.insert().from_select(columns, charts) - engine.execute(query) + db.session.execute(query) + + +def add_owners_to_dashboards( + metadata: MetaData, tag: Any, tagged_object: Any, columns: List[str] +) -> None: + dashboard_table = metadata.tables["dashboards"] dashboards = ( select( [ tag.c.id.label("tag_id"), - dashboards.c.id.label("object_id"), + dashboard_table.c.id.label("object_id"), literal(ObjectTypes.dashboard.name).label("object_type"), ] ) .select_from( join( join( - dashboards, + dashboard_table, tag, - tag.c.name - == functions.concat("owner:", dashboards.c.created_by_fk), + tag.c.name == "owner:" + dashboard_table.c.created_by_fk, ), tagged_object, and_( tagged_object.c.tag_id == tag.c.id, - tagged_object.c.object_id == dashboards.c.id, + tagged_object.c.object_id == dashboard_table.c.id, tagged_object.c.object_type == "dashboard", ), isouter=True, @@ -286,7 +305,13 @@ def add_owners(engine: Engine, metadata: Metadata) -> None: .where(tagged_object.c.tag_id.is_(None)) ) query = tagged_object.insert().from_select(columns, dashboards) - engine.execute(query) + db.session.execute(query) + + +def add_owners_to_saved_queries( + metadata: MetaData, tag: Any, tagged_object: Any, columns: List[str] +) -> None: + saved_query = metadata.tables["saved_query"] saved_queries = ( select( @@ -301,8 +326,7 @@ def add_owners(engine: Engine, metadata: Metadata) -> None: join( saved_query, tag, - tag.c.name - == functions.concat("owner:", saved_query.c.created_by_fk), + tag.c.name == "owner:" + saved_query.c.created_by_fk, ), tagged_object, and_( @@ -317,10 +341,125 @@ def add_owners(engine: Engine, metadata: Metadata) -> None: .where(tagged_object.c.tag_id.is_(None)) ) query = tagged_object.insert().from_select(columns, saved_queries) - engine.execute(query) + db.session.execute(query) + + +def add_owners_to_datasets( + metadata: MetaData, tag: Any, tagged_object: Any, columns: List[str] +) -> None: + tables = metadata.tables["tables"] + + datasets = ( + select( + [ + tag.c.id.label("tag_id"), + tables.c.id.label("object_id"), + literal(ObjectTypes.dataset.name).label("object_type"), + ] + ) + .select_from( + join( + join( + tables, + tag, + tag.c.name == "owner:" + tables.c.created_by_fk, + ), + tagged_object, + and_( + tagged_object.c.tag_id == tag.c.id, + tagged_object.c.object_id == tables.c.id, + tagged_object.c.object_type == "dataset", + ), + isouter=True, + full=False, + ) + ) + .where(tagged_object.c.tag_id.is_(None)) + ) + query = tagged_object.insert().from_select(columns, datasets) + db.session.execute(query) + + +def add_owners(metadata: MetaData) -> None: + """ + Tag every object according to its owner: + + INSERT INTO tagged_object (tag_id, object_id, object_type) + SELECT + tag.id AS tag_id, + slices.id AS object_id, + 'chart' AS object_type + FROM slices + JOIN tag + ON tag.name = CONCAT('owner:', slices.created_by_fk) + LEFT OUTER JOIN tagged_object + ON tagged_object.tag_id = tag.id + AND tagged_object.object_id = slices.id + AND tagged_object.object_type = 'chart' + WHERE tagged_object.tag_id IS NULL; + + SELECT + tag.id AS tag_id, + dashboards.id AS object_id, + 'dashboard' AS object_type + FROM dashboards + JOIN tag + ON tag.name = CONCAT('owner:', dashboards.created_by_fk) + LEFT OUTER JOIN tagged_object + ON tagged_object.tag_id = tag.id + AND tagged_object.object_id = dashboards.id + AND tagged_object.object_type = 'dashboard' + WHERE tagged_object.tag_id IS NULL; + + SELECT + tag.id AS tag_id, + saved_query.id AS object_id, + 'query' AS object_type + FROM saved_query + JOIN tag + ON tag.name = CONCAT('owner:', saved_query.created_by_fk) + LEFT OUTER JOIN tagged_object + ON tagged_object.tag_id = tag.id + AND tagged_object.object_id = saved_query.id + AND tagged_object.object_type = 'query' + WHERE tagged_object.tag_id IS NULL; + + SELECT + tag.id AS tag_id, + tables.id AS object_id, + 'dataset' AS object_type + FROM tables + JOIN tag + ON tag.name = CONCAT('owner:', tables.created_by_fk) + LEFT OUTER JOIN tagged_object + ON tagged_object.tag_id = tag.id + AND tagged_object.object_id = tables.id + AND tagged_object.object_type = 'dataset' + WHERE tagged_object.tag_id IS NULL; + + """ + + tag = metadata.tables["tag"] + tagged_object = metadata.tables["tagged_object"] + users = metadata.tables["ab_user"] + columns = ["tag_id", "object_id", "object_type"] + # create a custom tag for each user + ids = select([users.c.id]) + insert = tag.insert() + for (id_,) in db.session.execute(ids): + try: + db.session.execute(insert, name=f"owner:{id_}", type=TagTypes.owner) + except IntegrityError: + pass # already exists -def add_favorites(engine: Engine, metadata: Metadata) -> None: + add_owners_to_charts(metadata, tag, tagged_object, columns) + add_owners_to_dashboards(metadata, tag, tagged_object, columns) + add_owners_to_saved_queries(metadata, tag, tagged_object, columns) + add_owners_to_datasets(metadata, tag, tagged_object, columns) + + +def add_favorites(metadata: MetaData) -> None: """ Tag every object that was favorited: @@ -349,9 +488,13 @@ def add_favorites(engine: Engine, metadata: Metadata) -> None: # create a custom tag for each user ids = select([users.c.id]) insert = tag.insert() - for (id_,) in engine.execute(ids): + for (id_,) in db.session.execute(ids): try: - engine.execute(insert, name=f"favorited_by:{id_}", type=TagTypes.type) + db.session.execute( + insert, + name=f"favorited_by:{id_}", + type=TagTypes.type, + ) except IntegrityError: pass # already exists @@ -368,7 +511,7 @@ def add_favorites(engine: Engine, metadata: Metadata) -> None: join( favstar, tag, - tag.c.name == functions.concat("favorited_by:", favstar.c.user_id), + tag.c.name == "favorited_by:" + favstar.c.user_id, ), tagged_object, and_( @@ -383,4 +526,4 @@ def add_favorites(engine: Engine, metadata: Metadata) -> None: .where(tagged_object.c.tag_id.is_(None)) ) query = tagged_object.insert().from_select(columns, favstars) - engine.execute(query) + db.session.execute(query) diff --git a/superset/common/utils/dataframe_utils.py b/superset/common/utils/dataframe_utils.py index a0216ad54e839..4dd62e3b5d886 100644 --- a/superset/common/utils/dataframe_utils.py +++ b/superset/common/utils/dataframe_utils.py @@ -16,7 +16,8 @@ # under the License. from __future__ import annotations -from typing import List, TYPE_CHECKING +import datetime +from typing import Any, List, TYPE_CHECKING import numpy as np import pandas as pd @@ -42,3 +43,15 @@ def df_metrics_to_num(df: pd.DataFrame, query_object: QueryObject) -> None: # soft-convert a metric column to numeric # will stay as strings if conversion fails df[col] = df[col].infer_objects() + + +def is_datetime_series(series: Any) -> bool: + if series is None or not isinstance(series, pd.Series): + return False + + if series.isnull().all(): + return False + + return pd.api.types.is_datetime64_any_dtype(series) or ( + series.apply(lambda x: isinstance(x, datetime.date) or x is None).all() + ) diff --git a/superset/common/utils/time_range_utils.py b/superset/common/utils/time_range_utils.py new file mode 100644 index 0000000000000..fa6a5244b244b --- /dev/null +++ b/superset/common/utils/time_range_utils.py @@ -0,0 +1,77 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +from datetime import datetime +from typing import Any, cast, Dict, Optional, Tuple + +from superset import app +from superset.common.query_object import QueryObject +from superset.utils.core import FilterOperator, get_xaxis_label +from superset.utils.date_parser import get_since_until + + +def get_since_until_from_time_range( + time_range: Optional[str] = None, + time_shift: Optional[str] = None, + extras: Optional[Dict[str, Any]] = None, +) -> Tuple[Optional[datetime], Optional[datetime]]: + return get_since_until( + relative_start=(extras or {}).get( + "relative_start", app.config["DEFAULT_RELATIVE_START_TIME"] + ), + relative_end=(extras or {}).get( + "relative_end", app.config["DEFAULT_RELATIVE_END_TIME"] + ), + time_range=time_range, + time_shift=time_shift, + ) + + +# pylint: disable=invalid-name +def get_since_until_from_query_object( + query_object: QueryObject, +) -> Tuple[Optional[datetime], Optional[datetime]]: + """ + this function will return since and until by tuple if + 1) the time_range is in the query object. + 2) the xaxis column is in the columns field + and its corresponding `temporal_range` filter is in the adhoc filters. + :param query_object: a valid query object + :return: since and until by tuple + """ + if query_object.time_range: + return get_since_until_from_time_range( + time_range=query_object.time_range, + time_shift=query_object.time_shift, + extras=query_object.extras, + ) + + time_range = None + for flt in query_object.filter: + if ( + flt.get("op") == FilterOperator.TEMPORAL_RANGE.value + and flt.get("col") == get_xaxis_label(query_object.columns) + and isinstance(flt.get("val"), str) + ): + time_range = cast(str, flt.get("val")) + + return get_since_until_from_time_range( + time_range=time_range, + time_shift=query_object.time_shift, + extras=query_object.extras, + ) diff --git a/superset/config.py b/superset/config.py index 78f65a3b97fcd..1130920d6fb11 100644 --- a/superset/config.py +++ b/superset/config.py @@ -21,6 +21,8 @@ at the end of this file. """ # pylint: disable=too-many-lines +from __future__ import annotations + import imp # pylint: disable=deprecated-module import importlib.util import json @@ -30,6 +32,7 @@ import sys from collections import OrderedDict from datetime import timedelta +from email.mime.multipart import MIMEMultipart from typing import ( Any, Callable, @@ -37,8 +40,11 @@ List, Literal, Optional, + Set, + Tuple, Type, TYPE_CHECKING, + TypedDict, Union, ) @@ -49,6 +55,7 @@ from flask import Blueprint from flask_appbuilder.security.manager import AUTH_DB from pandas._libs.parsers import STR_NA_VALUES # pylint: disable=no-name-in-module +from sqlalchemy.orm.query import Query from superset.advanced_data_type.plugins.internet_address import internet_address from superset.advanced_data_type.plugins.internet_port import internet_port @@ -57,7 +64,8 @@ from superset.jinja_context import BaseTemplateProcessor from superset.stats_logger import DummyStatsLogger from superset.superset_typing import CacheConfig -from superset.utils.core import is_test, parse_boolean_string +from superset.tasks.types import ExecutorType +from superset.utils.core import is_test, NO_TIME_RANGE, parse_boolean_string from superset.utils.encrypt import SQLAlchemyUtilsAdapter from superset.utils.log import DBEventLogger from superset.utils.logging_configurator import DefaultLoggingConfigurator @@ -69,6 +77,8 @@ from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database + from superset.models.dashboard import Dashboard + from superset.models.slice import Slice # Realtime stats logger, a StatsD implementation exists STATS_LOGGER = DummyStatsLogger() @@ -142,7 +152,7 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: # can be replaced at build time to expose build information. BUILD_NUMBER = None -# default viz used in chart explorer +# default viz used in chart explorer & SQL Lab explore DEFAULT_VIZ_TYPE = "table" # default row limit when requesting chart data @@ -151,6 +161,9 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: SAMPLES_ROW_LIMIT = 1000 # max rows retrieved by filter select auto complete FILTER_SELECT_ROW_LIMIT = 10000 +# default time filter in explore +# values may be "Last day", "Last week", "<ISO date> : now", etc. +DEFAULT_TIME_FILTER = NO_TIME_RANGE SUPERSET_WEBSERVER_PROTOCOL = "http" SUPERSET_WEBSERVER_ADDRESS = "0.0.0.0" @@ -201,8 +214,31 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: # to the DB. # # Note: the default impl leverages SqlAlchemyUtils' EncryptedType, which defaults -# to AES-128 under the covers using the app's SECRET_KEY as key material. +# to AesEngine that uses AES-128 under the covers using the app's SECRET_KEY +# as key material. Do note that AesEngine allows for queryability over the +# encrypted fields. +# +# To change the default engine you need to define your own adapter: # +# e.g.: +# +# class AesGcmEncryptedAdapter( +# AbstractEncryptedFieldAdapter +# ): +# def create( +# self, +# app_config: Optional[Dict[str, Any]], +# *args: List[Any], +# **kwargs: Optional[Dict[str, Any]], +# ) -> TypeDecorator: +# if app_config: +# return EncryptedType( +# *args, app_config["SECRET_KEY"], engine=AesGcmEngine, **kwargs +# ) +# raise Exception("Missing app_config kwarg") +# +# +# SQLALCHEMY_ENCRYPTED_FIELD_TYPE_ADAPTER = AesGcmEncryptedAdapter SQLALCHEMY_ENCRYPTED_FIELD_TYPE_ADAPTER = ( # pylint: disable=invalid-name SQLAlchemyUtilsAdapter ) @@ -237,6 +273,9 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: ENABLE_PROXY_FIX = False PROXY_FIX_CONFIG = {"x_for": 1, "x_proto": 1, "x_host": 1, "x_port": 1, "x_prefix": 1} +# Configuration for scheduling queries from SQL Lab. +SCHEDULED_QUERIES: Dict[str, Any] = {} + # ------------------------------ # GLOBALS FOR APP Builder # ------------------------------ @@ -397,6 +436,7 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: # Feature is under active development and breaking changes are expected "DASHBOARD_NATIVE_FILTERS_SET": False, "DASHBOARD_FILTERS_EXPERIMENTAL": False, + "DASHBOARD_VIRTUALIZATION": False, "GLOBAL_ASYNC_QUERIES": False, "VERSIONED_EXPORT": True, "EMBEDDED_SUPERSET": False, @@ -425,15 +465,48 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: "UX_BETA": False, "GENERIC_CHART_AXES": False, "ALLOW_ADHOC_SUBQUERY": False, - "USE_ANALAGOUS_COLORS": True, + "USE_ANALAGOUS_COLORS": False, + "DASHBOARD_EDIT_CHART_IN_NEW_TAB": False, # Apply RLS rules to SQL Lab queries. This requires parsing and manipulating the # query, and might break queries and/or allow users to bypass RLS. Use with care! "RLS_IN_SQLLAB": False, # Enable caching per impersonation key (e.g username) in a datasource where user # impersonation is enabled "CACHE_IMPERSONATION": False, + # Enable sharing charts with embedding + "EMBEDDABLE_CHARTS": True, + "DRILL_TO_DETAIL": False, + "DATAPANEL_CLOSED_BY_DEFAULT": False, + "HORIZONTAL_FILTER_BAR": False, + # The feature is off by default, and currently only supported in Presto and Postgres, + # and Bigquery. + # It also needs to be enabled on a per-database basis, by adding the key/value pair + # `cost_estimate_enabled: true` to the database `extra` attribute. + "ESTIMATE_QUERY_COST": False, + # Allow users to enable ssh tunneling when creating a DB. + # Users must check whether the DB engine supports SSH Tunnels + # otherwise enabling this flag won't have any effect on the DB. + "SSH_TUNNELING": False, } +# ------------------------------ +# SSH Tunnel +# ------------------------------ +# Allow users to set the host used when connecting to the SSH Tunnel +# as localhost and any other alias (0.0.0.0) +# ---------------------------------------------------------------------- +# | +# -------------+ | +----------+ +# LOCAL | | | REMOTE | :22 SSH +# CLIENT | <== SSH ========> | SERVER | :8080 web service +# -------------+ | +----------+ +# | +# FIREWALL (only port 22 is open) + +# ---------------------------------------------------------------------- +SSH_TUNNEL_MANAGER_CLASS = "superset.extensions.ssh.SSHManager" +SSH_TUNNEL_LOCAL_BIND_ADDRESS = "127.0.0.1" + # Feature flags may also be set via 'SUPERSET_FEATURE_' prefixed environment vars. DEFAULT_FEATURE_FLAGS.update( { @@ -536,9 +609,33 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: # --------------------------------------------------- # Thumbnail config (behind feature flag) -# Also used by Alerts & Reports # --------------------------------------------------- -THUMBNAIL_SELENIUM_USER = "admin" +# When executing Alerts & Reports or Thumbnails as the Selenium user, this defines +# the username of the account used to render the queries and dashboards/charts +THUMBNAIL_SELENIUM_USER: Optional[str] = "admin" + +# To be able to have different thumbnails for different users, use these configs to +# define which user to execute the thumbnails and potentially custom functions for +# calculating thumbnail digests. To have unique thumbnails for all users, use the +# following config: +# THUMBNAIL_EXECUTE_AS = [ExecutorType.CURRENT_USER] +THUMBNAIL_EXECUTE_AS = [ExecutorType.SELENIUM] + +# By default, thumbnail digests are calculated based on various parameters in the +# chart/dashboard metadata, and in the case of user-specific thumbnails, the +# username. To specify a custom digest function, use the following config parameters +# to define callbacks that receive +# 1. the model (dashboard or chart) +# 2. the executor type (e.g. ExecutorType.SELENIUM) +# 3. the executor's username (note, this is the executor as defined by +# `THUMBNAIL_EXECUTE_AS`; the executor is only equal to the currently logged in +# user if the executor type is equal to `ExecutorType.CURRENT_USER`) +# and return the final digest string: +THUMBNAIL_DASHBOARD_DIGEST_FUNC: Optional[ + Callable[[Dashboard, ExecutorType, str], str] +] = None +THUMBNAIL_CHART_DIGEST_FUNC: Optional[Callable[[Slice, ExecutorType, str], str]] = None + THUMBNAIL_CACHE_CONFIG: CacheConfig = { "CACHE_TYPE": "NullCache", "CACHE_NO_NULL_WARNING": True, @@ -556,6 +653,12 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: SCREENSHOT_SELENIUM_HEADSTART = 3 # Wait for the chart animation, in seconds SCREENSHOT_SELENIUM_ANIMATION_WAIT = 5 +# Replace unexpected errors in screenshots with real error messages +SCREENSHOT_REPLACE_UNEXPECTED_ERRORS = False +# Max time to wait for error message modal to show up, in seconds +SCREENSHOT_WAIT_FOR_ERROR_MODAL_VISIBLE = 5 +# Max time to wait for error message modal to close, in seconds +SCREENSHOT_WAIT_FOR_ERROR_MODAL_INVISIBLE = 5 # --------------------------------------------------- # Image and file configuration @@ -645,17 +748,22 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: # note: index option should not be overridden CSV_EXPORT = {"encoding": "utf-8"} +# Excel Options: key/value pairs that will be passed as argument to DataFrame.to_excel +# method. +# note: index option should not be overridden +EXCEL_EXPORT = {"encoding": "utf-8"} + # --------------------------------------------------- # Time grain configurations # --------------------------------------------------- # List of time grains to disable in the application (see list of builtin -# time grains in superset/db_engine_specs.builtin_time_grains). +# time grains in superset/db_engine_specs/base.py). # For example: to disable 1 second time grain: # TIME_GRAIN_DENYLIST = ['PT1S'] TIME_GRAIN_DENYLIST: List[str] = [] # Additional time grains to be supported using similar definitions as in -# superset/db_engine_specs.builtin_time_grains. +# superset/db_engine_specs/base.py. # For example: To add a new 2 second time grain: # TIME_GRAIN_ADDONS = {'PT2S': '2 second'} TIME_GRAIN_ADDONS: Dict[str, str] = {} @@ -748,16 +856,25 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: # the SQL Lab UI DEFAULT_SQLLAB_LIMIT = 1000 -# Maximum number of tables/views displayed in the dropdown window in SQL Lab. -MAX_TABLE_NAMES = 3000 - # Adds a warning message on sqllab save query and schedule query modals. SQLLAB_SAVE_WARNING_MESSAGE = None SQLLAB_SCHEDULE_WARNING_MESSAGE = None # Force refresh while auto-refresh in dashboard DASHBOARD_AUTO_REFRESH_MODE: Literal["fetch", "force"] = "force" - +# Dashboard auto refresh intervals +DASHBOARD_AUTO_REFRESH_INTERVALS = [ + [0, "Don't refresh"], + [10, "10 seconds"], + [30, "30 seconds"], + [60, "1 minute"], + [300, "5 minutes"], + [1800, "30 minutes"], + [3600, "1 hour"], + [21600, "6 hours"], + [43200, "12 hours"], + [86400, "24 hours"], +] # Default celery config is to use SQLA as a broker, in a production setting # you'll want to use a proper broker as specified here: @@ -768,7 +885,6 @@ class CeleryConfig: # pylint: disable=too-few-public-methods broker_url = "sqla+sqlite:///celerydb.sqlite" imports = ("superset.sql_lab",) result_backend = "db+sqlite:///celery_results.sqlite" - worker_log_level = "DEBUG" worker_prefetch_multiplier = 1 task_acks_late = False task_annotations = { @@ -831,16 +947,14 @@ class CeleryConfig: # pylint: disable=too-few-public-methods # query costs before they run. These EXPLAIN queries should have a small # timeout. SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT = int(timedelta(seconds=10).total_seconds()) -# The feature is off by default, and currently only supported in Presto and Postgres. -# It also need to be enabled on a per-database basis, by adding the key/value pair -# `cost_estimate_enabled: true` to the database `extra` attribute. -ESTIMATE_QUERY_COST = False + # The cost returned by the databases is a relative value; in order to map the cost to # a tangible value you need to define a custom formatter that takes into consideration # your specific infrastructure. For example, you could analyze queries a posteriori by # running EXPLAIN on them, and compute a histogram of relative costs to present the -# cost as a percentile: -# +# cost as a percentile, this step is optional as every db engine spec has its own +# query cost formatter, but it you wanna customize it you can define it inside the config: + # def postgres_query_cost_formatter( # result: List[Dict[str, Any]] # ) -> List[Dict[str, str]]: @@ -858,9 +972,7 @@ class CeleryConfig: # pylint: disable=too-few-public-methods # # return out # -# Then on define the formatter on the config: -# -# "QUERY_COST_FORMATTERS_BY_ENGINE": {"postgresql": postgres_query_cost_formatter}, +# QUERY_COST_FORMATTERS_BY_ENGINE: {"postgresql": postgres_query_cost_formatter} QUERY_COST_FORMATTERS_BY_ENGINE: Dict[ str, Callable[[List[Dict[str, Any]]], List[Dict[str, Any]]] ] = {} @@ -888,7 +1000,7 @@ class CeleryConfig: # pylint: disable=too-few-public-methods # return f'tmp_{schema}' # Function accepts database object, user object, schema name and sql that will be run. SQLLAB_CTAS_SCHEMA_NAME_FUNC: Optional[ - Callable[["Database", "models.User", str, str], str] + Callable[[Database, models.User, str, str], str] ] = None # If enabled, it can be used to store the results of long-running queries @@ -913,8 +1025,8 @@ class CeleryConfig: # pylint: disable=too-few-public-methods # Function that creates upload directory dynamically based on the # database used, user and schema provided. def CSV_TO_HIVE_UPLOAD_DIRECTORY_FUNC( # pylint: disable=invalid-name - database: "Database", - user: "models.User", # pylint: disable=unused-argument + database: Database, + user: models.User, # pylint: disable=unused-argument schema: Optional[str], ) -> str: # Note the final empty path enforces a trailing slash. @@ -932,7 +1044,7 @@ def CSV_TO_HIVE_UPLOAD_DIRECTORY_FUNC( # pylint: disable=invalid-name # db configuration and a result of this function. # mypy doesn't catch that if case ensures list content being always str -ALLOWED_USER_CSV_SCHEMA_FUNC: Callable[["Database", "models.User"], List[str]] = ( +ALLOWED_USER_CSV_SCHEMA_FUNC: Callable[[Database, models.User], List[str]] = ( lambda database, user: [UPLOADED_CSV_HIVE_NAMESPACE] if UPLOADED_CSV_HIVE_NAMESPACE else [] @@ -1019,11 +1131,17 @@ def CSV_TO_HIVE_UPLOAD_DIRECTORY_FUNC( # pylint: disable=invalid-name # into a proxied one -TRACKING_URL_TRANSFORMER = lambda x: x +# Transform SQL query tracking url for Hive and Presto engines. You may also +# access information about the query itself by adding a second parameter +# to your transformer function, e.g.: +# TRACKING_URL_TRANSFORMER = ( +# lambda url, query: url if is_fresh(query) else None +# ) +TRACKING_URL_TRANSFORMER = lambda url: url -# Interval between consecutive polls when using Hive Engine -HIVE_POLL_INTERVAL = int(timedelta(seconds=5).total_seconds()) +# customize the polling time of each engine +DB_POLL_INTERVAL_SECONDS: Dict[str, int] = {} # Interval between consecutive polls when using Presto Engine # See here: https://github.com/dropbox/PyHive/blob/8eb0aeab8ca300f3024655419b93dad926c1a351/pyhive/presto.py#L93 # pylint: disable=line-too-long,useless-suppression @@ -1084,6 +1202,36 @@ def SQL_QUERY_MUTATOR( # pylint: disable=invalid-name,unused-argument return sql +# A variable that chooses whether to apply the SQL_QUERY_MUTATOR before or after splitting the input query +# It allows for using the SQL_QUERY_MUTATOR function for more than comments +# Usage: If you want to apply a change to every statement to a given query, set MUTATE_AFTER_SPLIT = True +# An example use case is if data has role based access controls, and you want to apply +# a SET ROLE statement alongside every user query. Changing this variable maintains +# functionality for both the SQL_Lab and Charts. +MUTATE_AFTER_SPLIT = False + +# This allows for a user to add header data to any outgoing emails. For example, +# if you need to include metadata in the header or you want to change the specifications +# of the email title, header, or sender. +def EMAIL_HEADER_MUTATOR( # pylint: disable=invalid-name,unused-argument + msg: MIMEMultipart, **kwargs: Any +) -> MIMEMultipart: + return msg + + +# Define a list of usernames to be excluded from all dropdown lists of users +# Owners, filters for created_by, etc. +# The users can also be excluded by overriding the get_exclude_users_from_lists method +# in security manager +EXCLUDE_USERS_FROM_LISTS: Optional[List[str]] = None + +# For database connections, this dictionary will remove engines from the available +# list/dropdown if you do not want these dbs to show as available. +# The available list is generated by driver installed, and some engines have multiple +# drivers. +# e.g., DBS_AVAILABLE_DENYLIST: Dict[str, Set[str]] = {"databricks": {"pyhive", "pyodbc"}} +DBS_AVAILABLE_DENYLIST: Dict[str, Set[str]] = {} + # This auth provider is used by background (offline) tasks that need to access # protected resources. Can be overridden by end users in order to support # custom auth mechanisms @@ -1096,6 +1244,22 @@ def SQL_QUERY_MUTATOR( # pylint: disable=invalid-name,unused-argument # sliding cron window size, should be synced with the celery beat config minus 1 second ALERT_REPORTS_CRON_WINDOW_SIZE = 59 ALERT_REPORTS_WORKING_TIME_OUT_KILL = True +# Which user to attempt to execute Alerts/Reports as. By default, +# use the user defined in the `THUMBNAIL_SELENIUM_USER` config parameter. +# To first try to execute as the creator in the owners list (if present), then fall +# back to the creator, then the last modifier in the owners list (if present), then the +# last modifier, then an owner (giving priority to the last modifier and then the +# creator if either is contained within the list of owners, otherwise the first owner +# will be used) and finally `THUMBNAIL_SELENIUM_USER`, set as follows: +# ALERT_REPORTS_EXECUTE_AS = [ +# ScheduledTaskExecutor.CREATOR_OWNER, +# ScheduledTaskExecutor.CREATOR, +# ScheduledTaskExecutor.MODIFIER_OWNER, +# ScheduledTaskExecutor.MODIFIER, +# ScheduledTaskExecutor.OWNER, +# ScheduledTaskExecutor.SELENIUM, +# ] +ALERT_REPORTS_EXECUTE_AS: List[ExecutorType] = [ExecutorType.SELENIUM] # if ALERT_REPORTS_WORKING_TIME_OUT_KILL is True, set a celery hard timeout # Equal to working timeout + ALERT_REPORTS_WORKING_TIME_OUT_LAG ALERT_REPORTS_WORKING_TIME_OUT_LAG = int(timedelta(seconds=10).total_seconds()) @@ -1112,6 +1276,9 @@ def SQL_QUERY_MUTATOR( # pylint: disable=invalid-name,unused-argument # A custom prefix to use on all Alerts & Reports emails EMAIL_REPORTS_SUBJECT_PREFIX = "[Report] " +# The text for call-to-action link in Alerts & Reports emails +EMAIL_REPORTS_CTA = "Explore in Superset" + # Slack API token for the superset reports, either string or callable SLACK_API_TOKEN: Optional[Union[Callable[[], str], str]] = None SLACK_PROXY = None @@ -1153,6 +1320,8 @@ def SQL_QUERY_MUTATOR( # pylint: disable=invalid-name,unused-argument # Send user to a link where they can report bugs BUG_REPORT_URL = None +BUG_REPORT_TEXT = "Report a bug" +BUG_REPORT_ICON = None # Recommended size: 16x16 # Send user to a link where they can read more about Superset DOCUMENTATION_URL = None @@ -1223,7 +1392,7 @@ def SQL_QUERY_MUTATOR( # pylint: disable=invalid-name,unused-argument # SESSION_COOKIE_HTTPONLY = True # Prevent cookie from being read by frontend JS? SESSION_COOKIE_SECURE = False # Prevent cookie from being transmitted over non-tls? -SESSION_COOKIE_SAMESITE = "Lax" # One of [None, 'None', 'Lax', 'Strict'] +SESSION_COOKIE_SAMESITE: Optional[Literal["None", "Lax", "Strict"]] = "Lax" # Cache static resources. SEND_FILE_MAX_AGE_DEFAULT = int(timedelta(days=365).total_seconds()) @@ -1243,6 +1412,13 @@ def SQL_QUERY_MUTATOR( # pylint: disable=invalid-name,unused-argument # Prevents unsafe default endpoints to be registered on datasets. PREVENT_UNSAFE_DEFAULT_URLS_ON_DATASET = True +# Define a list of allowed URLs for dataset data imports (v1). +# Simple example to only allow URLs that belong to certain domains: +# ALLOWED_IMPORT_URL_DOMAINS = [ +# r"^https://.+\.domain1\.com\/?.*", r"^https://.+\.domain2\.com\/?.*" +# ] +DATASET_IMPORT_ALLOWED_DATA_URLS = [r".*"] + # Path used to store SSL certificates that are generated when using custom certs. # Defaults to temporary directory. # Example: SSL_CERT_PATH = "/certs" @@ -1271,6 +1447,9 @@ def SQL_QUERY_MUTATOR( # pylint: disable=invalid-name,unused-argument GLOBAL_ASYNC_QUERIES_REDIS_STREAM_LIMIT_FIREHOSE = 1000000 GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME = "async-token" GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = False +GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE: Optional[ + Literal["None", "Lax", "Strict"] +] = None GLOBAL_ASYNC_QUERIES_JWT_COOKIE_DOMAIN = None GLOBAL_ASYNC_QUERIES_JWT_SECRET = "test-secret-change-me" GLOBAL_ASYNC_QUERIES_TRANSPORT = "polling" @@ -1332,24 +1511,59 @@ def SQL_QUERY_MUTATOR( # pylint: disable=invalid-name,unused-argument "port": internet_port, } -DATAHUB_URL = "https://localhost:9002/" - +# By default, the Welcome page features all charts and dashboards the user has access +# to. This can be changed to show only examples, or a custom view +# by providing the title and a FAB filter: +# WELCOME_PAGE_LAST_TAB = ( +# "Xyz", +# [{"col": 'created_by', "opr": 'rel_o_m', "value": 10}], +# ) +WELCOME_PAGE_LAST_TAB: Union[ + Literal["examples", "all"], Tuple[str, List[Dict[str, Any]]] +] = "all" # Configuration for environment tag shown on the navbar. Setting 'text' to '' will hide the tag. +# 'color' can either be a hex color code, or a dot-indexed theme color (e.g. error.base) ENVIRONMENT_TAG_CONFIG = { "variable": "FLASK_ENV", "values": { "development": { - "color": "#c73d2e", + "color": "error.base", "text": "Development", }, "production": { - "color": "#039dfc", - "text": "Production", + "color": "", + "text": "", }, }, } + +# Extra related query filters make it possible to limit which objects are shown +# in the UI. For examples, to only show "admin" or users starting with the letter "b" in +# the "Owners" dropdowns, you could add the following in your config: +# def user_filter(query: Query, *args, *kwargs): +# from superset import security_manager +# +# user_model = security_manager.user_model +# filters = [ +# user_model.username == "admin", +# user_model.username.ilike("b%"), +# ] +# return query.filter(or_(*filters)) +# +# EXTRA_RELATED_QUERY_FILTERS = {"user": user_filter} +# +# Similarly, to restrict the roles in the "Roles" dropdown you can provide a custom +# filter callback for the "role" key. +class ExtraRelatedQueryFilters(TypedDict, total=False): + role: Callable[[Query], Query] + user: Callable[[Query], Query] + + +EXTRA_RELATED_QUERY_FILTERS: ExtraRelatedQueryFilters = {} + + # ------------------------------------------------------------------- # * WARNING: STOP EDITING HERE * # ------------------------------------------------------------------- @@ -1376,7 +1590,7 @@ def SQL_QUERY_MUTATOR( # pylint: disable=invalid-name,unused-argument try: # pylint: disable=import-error,wildcard-import,unused-wildcard-import import superset_config - from superset_config import * # type:ignore + from superset_config import * # type: ignore print(f"Loaded your LOCAL configuration at [{superset_config.__file__}]") except Exception: diff --git a/superset/connectors/base/models.py b/superset/connectors/base/models.py index 7809dab4ae9c5..a5bea92ffa11e 100644 --- a/superset/connectors/base/models.py +++ b/superset/connectors/base/models.py @@ -22,6 +22,7 @@ from typing import Any, Dict, Hashable, List, Optional, Set, Type, TYPE_CHECKING, Union from flask_appbuilder.security.sqla.models import User +from flask_babel import gettext as __ from sqlalchemy import and_, Boolean, Column, Integer, String, Text from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.orm import foreign, Query, relationship, RelationshipProperty, Session @@ -209,7 +210,7 @@ def url(self) -> str: def explore_url(self) -> str: if self.default_endpoint: return self.default_endpoint - return f"/superset/explore/{self.type}/{self.id}/" + return f"/explore/?datasource_type={self.type}&datasource_id={self.id}" @property def column_formats(self) -> Dict[str, Optional[str]]: @@ -248,10 +249,10 @@ def data(self) -> Dict[str, Any]: for column_name in self.column_names: column_name = str(column_name or "") order_by_choices.append( - (json.dumps([column_name, True]), column_name + " [asc]") + (json.dumps([column_name, True]), f"{column_name} " + __("[asc]")) ) order_by_choices.append( - (json.dumps([column_name, False]), column_name + " [desc]") + (json.dumps([column_name, False]), f"{column_name} " + __("[desc]")) ) verbose_map = {"__timestamp": "Time"} @@ -312,9 +313,9 @@ def data_for_slices( # pylint: disable=too-many-locals for metric in utils.get_iterable(form_data.get(metric_param) or []): metric_names.add(utils.get_metric_name(metric)) if utils.is_adhoc_metric(metric): - column_names.add( - (metric.get("column") or {}).get("column_name") - ) + column = metric.get("column") or {} + if column_name := column.get("column_name"): + column_names.add(column_name) # Columns used in query filters column_names.update( @@ -395,6 +396,7 @@ def data_for_slices( # pylint: disable=too-many-locals @staticmethod def filter_values_handler( # pylint: disable=too-many-arguments values: Optional[FilterValues], + operator: str, target_generic_type: GenericDataType, target_native_type: Optional[str] = None, is_list_target: bool = False, @@ -405,6 +407,8 @@ def filter_values_handler( # pylint: disable=too-many-arguments return None def handle_single_value(value: Optional[FilterValue]) -> Optional[FilterValue]: + if operator == utils.FilterOperator.TEMPORAL_RANGE: + return value if ( isinstance(value, (float, int)) and target_generic_type == utils.GenericDataType.TEMPORAL diff --git a/superset/connectors/connector_registry.py b/superset/connectors/connector_registry.py deleted file mode 100644 index 06816fa53049f..0000000000000 --- a/superset/connectors/connector_registry.py +++ /dev/null @@ -1,164 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from typing import Dict, List, Optional, Set, Type, TYPE_CHECKING - -from flask_babel import _ -from sqlalchemy import or_ -from sqlalchemy.orm import Session, subqueryload -from sqlalchemy.orm.exc import NoResultFound - -from superset.datasets.commands.exceptions import DatasetNotFoundError - -if TYPE_CHECKING: - from collections import OrderedDict - - from superset.connectors.base.models import BaseDatasource - from superset.models.core import Database - - -class ConnectorRegistry: - """Central Registry for all available datasource engines""" - - sources: Dict[str, Type["BaseDatasource"]] = {} - - @classmethod - def register_sources(cls, datasource_config: "OrderedDict[str, List[str]]") -> None: - for module_name, class_names in datasource_config.items(): - class_names = [str(s) for s in class_names] - module_obj = __import__(module_name, fromlist=class_names) - for class_name in class_names: - source_class = getattr(module_obj, class_name) - cls.sources[source_class.type] = source_class - - @classmethod - def get_datasource( - cls, datasource_type: str, datasource_id: int, session: Session - ) -> "BaseDatasource": - """Safely get a datasource instance, raises `DatasetNotFoundError` if - `datasource_type` is not registered or `datasource_id` does not - exist.""" - if datasource_type not in cls.sources: - raise DatasetNotFoundError() - - datasource = ( - session.query(cls.sources[datasource_type]) - .filter_by(id=datasource_id) - .one_or_none() - ) - - if not datasource: - raise DatasetNotFoundError() - - return datasource - - @classmethod - def get_all_datasources(cls, session: Session) -> List["BaseDatasource"]: - datasources: List["BaseDatasource"] = [] - for source_class in ConnectorRegistry.sources.values(): - qry = session.query(source_class) - qry = source_class.default_query(qry) - datasources.extend(qry.all()) - return datasources - - @classmethod - def get_datasource_by_id( - cls, session: Session, datasource_id: int - ) -> "BaseDatasource": - """ - Find a datasource instance based on the unique id. - - :param session: Session to use - :param datasource_id: unique id of datasource - :return: Datasource corresponding to the id - :raises NoResultFound: if no datasource is found corresponding to the id - """ - for datasource_class in ConnectorRegistry.sources.values(): - try: - return ( - session.query(datasource_class) - .filter(datasource_class.id == datasource_id) - .one() - ) - except NoResultFound: - # proceed to next datasource type - pass - raise NoResultFound(_("Datasource id not found: %(id)s", id=datasource_id)) - - @classmethod - def get_datasource_by_name( # pylint: disable=too-many-arguments - cls, - session: Session, - datasource_type: str, - datasource_name: str, - schema: str, - database_name: str, - ) -> Optional["BaseDatasource"]: - datasource_class = ConnectorRegistry.sources[datasource_type] - return datasource_class.get_datasource_by_name( - session, datasource_name, schema, database_name - ) - - @classmethod - def query_datasources_by_permissions( # pylint: disable=invalid-name - cls, - session: Session, - database: "Database", - permissions: Set[str], - schema_perms: Set[str], - ) -> List["BaseDatasource"]: - # TODO(bogdan): add unit test - datasource_class = ConnectorRegistry.sources[database.type] - return ( - session.query(datasource_class) - .filter_by(database_id=database.id) - .filter( - or_( - datasource_class.perm.in_(permissions), - datasource_class.schema_perm.in_(schema_perms), - ) - ) - .all() - ) - - @classmethod - def get_eager_datasource( - cls, session: Session, datasource_type: str, datasource_id: int - ) -> "BaseDatasource": - """Returns datasource with columns and metrics.""" - datasource_class = ConnectorRegistry.sources[datasource_type] - return ( - session.query(datasource_class) - .options( - subqueryload(datasource_class.columns), - subqueryload(datasource_class.metrics), - ) - .filter_by(id=datasource_id) - .one() - ) - - @classmethod - def query_datasources_by_name( - cls, - session: Session, - database: "Database", - datasource_name: str, - schema: Optional[str] = None, - ) -> List["BaseDatasource"]: - datasource_class = ConnectorRegistry.sources[database.type] - return datasource_class.query_datasources_by_name( - session, database, datasource_name, schema=schema - ) diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index 4e1c5329309bc..d1f671d106e4d 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -14,7 +14,9 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# pylint: disable=too-many-lines, redefined-outer-name +# pylint: disable=too-many-lines +from __future__ import annotations + import dataclasses import json import logging @@ -31,11 +33,11 @@ List, NamedTuple, Optional, + Set, Tuple, Type, Union, ) -from uuid import uuid4 import dateutil.parser import numpy as np @@ -65,8 +67,15 @@ update, ) from sqlalchemy.engine.base import Connection -from sqlalchemy.orm import backref, Query, relationship, RelationshipProperty, Session -from sqlalchemy.orm.exc import NoResultFound +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy.orm import ( + backref, + Mapped, + Query, + relationship, + RelationshipProperty, + Session, +) from sqlalchemy.orm.mapper import Mapper from sqlalchemy.schema import UniqueConstraint from sqlalchemy.sql import column, ColumnElement, literal_column, table @@ -76,17 +85,18 @@ from superset import app, db, is_feature_enabled, security_manager from superset.advanced_data_type.types import AdvancedDataTypeResponse -from superset.columns.models import Column as NewColumn, UNKOWN_TYPE from superset.common.db_query_status import QueryStatus +from superset.common.utils.time_range_utils import get_since_until_from_time_range from superset.connectors.base.models import BaseColumn, BaseDatasource, BaseMetric from superset.connectors.sqla.utils import ( find_cached_objects_in_session, + get_columns_description, get_physical_table_metadata, get_virtual_table_metadata, validate_adhoc_subquery, ) from superset.datasets.models import Dataset as NewDataset -from superset.db_engine_specs.base import BaseEngineSpec, CTE_ALIAS, TimestampExpression +from superset.db_engine_specs.base import BaseEngineSpec, TimestampExpression from superset.exceptions import ( AdvancedDataTypeResponseError, DatasetInvalidPermissionEvaluationException, @@ -102,18 +112,8 @@ ) from superset.models.annotations import Annotation from superset.models.core import Database -from superset.models.helpers import ( - AuditMixinNullable, - CertificationMixin, - clone_model, - QueryResult, -) -from superset.sql_parse import ( - extract_table_references, - ParsedQuery, - sanitize_clause, - Table as TableName, -) +from superset.models.helpers import AuditMixinNullable, CertificationMixin, QueryResult +from superset.sql_parse import ParsedQuery, sanitize_clause from superset.superset_typing import ( AdhocColumn, AdhocMetric, @@ -122,7 +122,6 @@ OrderBy, QueryObjectDict, ) -from superset.tables.models import Table as NewTable from superset.utils import core as utils from superset.utils.core import ( GenericDataType, @@ -232,10 +231,10 @@ class TableColumn(Model, BaseColumn, CertificationMixin): __tablename__ = "table_columns" __table_args__ = (UniqueConstraint("table_id", "column_name"),) table_id = Column(Integer, ForeignKey("tables.id")) - table: "SqlaTable" = relationship( + table: Mapped["SqlaTable"] = relationship( "SqlaTable", - backref=backref("columns", cascade="all, delete-orphan"), - foreign_keys=[table_id], + back_populates="columns", + lazy="joined", # Eager loading for efficient parent referencing with selectin. ) is_dttm = Column(Boolean, default=False) expression = Column(MediumText()) @@ -311,14 +310,18 @@ def type_generic(self) -> Optional[utils.GenericDataType]: ) return column_spec.generic_type if column_spec else None - def get_sqla_col(self, label: Optional[str] = None) -> Column: + def get_sqla_col( + self, + label: Optional[str] = None, + template_processor: Optional[BaseTemplateProcessor] = None, + ) -> Column: label = label or self.column_name db_engine_spec = self.db_engine_spec column_spec = db_engine_spec.get_column_spec(self.type, db_extra=self.db_extra) type_ = column_spec.sqla_type if column_spec else None - if self.expression: - tp = self.table.get_template_processor() - expression = tp.process_template(self.expression) + if expression := self.expression: + if template_processor: + expression = template_processor.process_template(expression) col = literal_column(expression, type_=type_) else: col = column(self.column_name, type_=type_) @@ -331,10 +334,12 @@ def datasource(self) -> RelationshipProperty: def get_time_filter( self, - start_dttm: DateTime, - end_dttm: DateTime, + start_dttm: Optional[DateTime] = None, + end_dttm: Optional[DateTime] = None, + label: Optional[str] = "__time", + template_processor: Optional[BaseTemplateProcessor] = None, ) -> ColumnElement: - col = self.get_sqla_col(label="__time") + col = self.get_sqla_col(label=label, template_processor=template_processor) l = [] if start_dttm: l.append(col >= self.table.text(self.dttm_sql_literal(start_dttm))) @@ -367,16 +372,13 @@ def get_timestamp_expression( if not self.expression and not time_grain and not is_epoch: sqla_col = column(self.column_name, type_=type_) return self.table.make_sqla_column_compatible(sqla_col, label) - if self.expression: - expression = self.expression + if expression := self.expression: if template_processor: - expression = template_processor.process_template(self.expression) + expression = template_processor.process_template(expression) col = literal_column(expression, type_=type_) else: col = column(self.column_name, type_=type_) - time_expr = self.db_engine_spec.get_timestamp_expr( - col, pdf, time_grain, self.type - ) + time_expr = self.db_engine_spec.get_timestamp_expr(col, pdf, time_grain) return self.table.make_sqla_column_compatible(time_expr, label) def dttm_sql_literal(self, dttm: DateTime) -> str: @@ -436,75 +438,6 @@ def data(self) -> Dict[str, Any]: return attr_dict - def to_sl_column( - self, known_columns: Optional[Dict[str, NewColumn]] = None - ) -> NewColumn: - """Convert a TableColumn to NewColumn""" - session: Session = inspect(self).session - column = known_columns.get(self.uuid) if known_columns else None - if not column: - column = NewColumn() - - extra_json = self.get_extra_dict() - for attr in { - "verbose_name", - "python_date_format", - }: - value = getattr(self, attr) - if value: - extra_json[attr] = value - - if not column.id: - with session.no_autoflush: - saved_column = ( - session.query(NewColumn).filter_by(uuid=self.uuid).one_or_none() - ) - if saved_column: - logger.warning( - "sl_column already exists. Assigning existing id %s", self - ) - - # uuid isn't a primary key, so add the id of the existing column to - # ensure that the column is modified instead of created - # in order to avoid a uuid collision - column.id = saved_column.id - - column.uuid = self.uuid - column.created_on = self.created_on - column.changed_on = self.changed_on - column.created_by = self.created_by - column.changed_by = self.changed_by - column.name = self.column_name - column.type = self.type or UNKOWN_TYPE - column.expression = self.expression or self.table.quote_identifier( - self.column_name - ) - column.description = self.description - column.is_aggregation = False - column.is_dimensional = self.groupby - column.is_filterable = self.filterable - column.is_increase_desired = True - column.is_managed_externally = self.table.is_managed_externally - column.is_partition = False - column.is_physical = not self.expression - column.is_spatial = False - column.is_temporal = self.is_dttm - column.extra_json = json.dumps(extra_json) if extra_json else None - column.external_url = self.table.external_url - - return column - - @staticmethod - def after_delete( # pylint: disable=unused-argument - mapper: Mapper, - connection: Connection, - target: "TableColumn", - ) -> None: - session = inspect(target).session - column = session.query(NewColumn).filter_by(uuid=target.uuid).one_or_none() - if column: - session.delete(column) - class SqlMetric(Model, BaseMetric, CertificationMixin): @@ -513,10 +446,10 @@ class SqlMetric(Model, BaseMetric, CertificationMixin): __tablename__ = "sql_metrics" __table_args__ = (UniqueConstraint("table_id", "metric_name"),) table_id = Column(Integer, ForeignKey("tables.id")) - table = relationship( + table: Mapped["SqlaTable"] = relationship( "SqlaTable", - backref=backref("metrics", cascade="all, delete-orphan"), - foreign_keys=[table_id], + back_populates="metrics", + lazy="joined", # Eager loading for efficient parent referencing with selectin. ) expression = Column(MediumText(), nullable=False) extra = Column(Text) @@ -535,10 +468,20 @@ class SqlMetric(Model, BaseMetric, CertificationMixin): update_from_object_fields = list(s for s in export_fields if s != "table_id") export_parent = "table" - def get_sqla_col(self, label: Optional[str] = None) -> Column: + def __repr__(self) -> str: + return str(self.metric_name) + + def get_sqla_col( + self, + label: Optional[str] = None, + template_processor: Optional[BaseTemplateProcessor] = None, + ) -> Column: label = label or self.metric_name - tp = self.table.get_template_processor() - sqla_col: ColumnClause = literal_column(tp.process_template(self.expression)) + expression = self.expression + if template_processor: + expression = template_processor.process_template(expression) + + sqla_col: ColumnClause = literal_column(expression) return self.table.make_sqla_column_compatible(sqla_col, label) @property @@ -567,73 +510,6 @@ def data(self) -> Dict[str, Any]: attr_dict.update(super().data) return attr_dict - def to_sl_column( - self, known_columns: Optional[Dict[str, NewColumn]] = None - ) -> NewColumn: - """Convert a SqlMetric to NewColumn. Find and update existing or - create a new one.""" - session: Session = inspect(self).session - column = known_columns.get(self.uuid) if known_columns else None - if not column: - column = NewColumn() - - extra_json = self.get_extra_dict() - for attr in {"verbose_name", "metric_type", "d3format"}: - value = getattr(self, attr) - if value is not None: - extra_json[attr] = value - is_additive = ( - self.metric_type and self.metric_type.lower() in ADDITIVE_METRIC_TYPES_LOWER - ) - - if not column.id: - with session.no_autoflush: - saved_column = ( - session.query(NewColumn).filter_by(uuid=self.uuid).one_or_none() - ) - if saved_column: - logger.warning( - "sl_column already exists. Assigning existing id %s", self - ) - # uuid isn't a primary key, so add the id of the existing column to - # ensure that the column is modified instead of created - # in order to avoid a uuid collision - column.id = saved_column.id - - column.uuid = self.uuid - column.name = self.metric_name - column.created_on = self.created_on - column.changed_on = self.changed_on - column.created_by = self.created_by - column.changed_by = self.changed_by - column.type = UNKOWN_TYPE - column.expression = self.expression - column.warning_text = self.warning_text - column.description = self.description - column.is_aggregation = True - column.is_additive = is_additive - column.is_filterable = False - column.is_increase_desired = True - column.is_managed_externally = self.table.is_managed_externally - column.is_partition = False - column.is_physical = False - column.is_spatial = False - column.extra_json = json.dumps(extra_json) if extra_json else None - column.external_url = self.table.external_url - - return column - - @staticmethod - def after_delete( # pylint: disable=unused-argument - mapper: Mapper, - connection: Connection, - target: "SqlMetric", - ) -> None: - session = inspect(target).session - column = session.query(NewColumn).filter_by(uuid=target.uuid).one_or_none() - if column: - session.delete(column) - sqlatable_user = Table( "sqlatable_user", @@ -666,13 +542,23 @@ def _process_sql_expression( class SqlaTable(Model, BaseDatasource): # pylint: disable=too-many-public-methods - """An ORM object for SqlAlchemy table references""" + """An ORM object for SqlAlchemy table references.""" type = "table" query_language = "sql" is_rls_supported = True - columns: List[TableColumn] = [] - metrics: List[SqlMetric] = [] + columns: Mapped[List[TableColumn]] = relationship( + TableColumn, + back_populates="table", + cascade="all, delete-orphan", + lazy="selectin", # Only non-eager loading that works with bidirectional joined. + ) + metrics: Mapped[List[SqlMetric]] = relationship( + SqlMetric, + back_populates="table", + cascade="all, delete-orphan", + lazy="selectin", # Only non-eager loading that works with bidirectional joined. + ) metric_class = SqlMetric column_class = TableColumn owner_class = security_manager.user_model @@ -735,7 +621,7 @@ class SqlaTable(Model, BaseDatasource): # pylint: disable=too-many-public-metho "MAX": sa.func.MAX, } - def __repr__(self) -> str: + def __repr__(self) -> str: # pylint: disable=invalid-repr-returned return self.name @staticmethod @@ -794,7 +680,7 @@ def get_datasource_by_name( datasource_name: str, schema: Optional[str], database_name: str, - ) -> Optional["SqlaTable"]: + ) -> Optional[SqlaTable]: schema = schema or None query = ( session.query(cls) @@ -829,11 +715,9 @@ def get_perm(self) -> str: raise DatasetInvalidPermissionEvaluationException() return f"[{self.database}].[{self.table_name}](id:{self.id})" - @property - def name(self) -> str: - if not self.schema: - return self.table_name - return "{}.{}".format(self.schema, self.table_name) + @hybrid_property + def name(self) -> str: # pylint: disable=invalid-overridden-method + return self.schema + "." + self.table_name if self.schema else self.table_name @property def full_name(self) -> str: @@ -914,6 +798,7 @@ def data(self) -> Dict[str, Any]: data_["is_sqllab_view"] = self.is_sqllab_view data_["health_check_message"] = self.health_check_message data_["extra"] = self.extra + data_["owners"] = self.owners_data return data_ @property @@ -923,10 +808,17 @@ def extra_dict(self) -> Dict[str, Any]: except (TypeError, json.JSONDecodeError): return {} - def get_fetch_values_predicate(self) -> TextClause: - tp = self.get_template_processor() + def get_fetch_values_predicate( + self, + template_processor: Optional[BaseTemplateProcessor] = None, + ) -> TextClause: + fetch_values_predicate = self.fetch_values_predicate + if template_processor: + fetch_values_predicate = template_processor.process_template( + fetch_values_predicate + ) try: - return self.text(tp.process_template(self.fetch_values_predicate)) + return self.text(fetch_values_predicate) except TemplateError as ex: raise QueryObjectValidationError( _( @@ -944,27 +836,32 @@ def values_for_column(self, column_name: str, limit: int = 10000) -> List[Any]: tp = self.get_template_processor() tbl, cte = self.get_from_clause(tp) - qry = select([target_col.get_sqla_col()]).select_from(tbl).distinct() + qry = ( + select([target_col.get_sqla_col(template_processor=tp)]) + .select_from(tbl) + .distinct() + ) if limit: qry = qry.limit(limit) if self.fetch_values_predicate: - qry = qry.where(self.get_fetch_values_predicate()) + qry = qry.where(self.get_fetch_values_predicate(template_processor=tp)) - engine = self.database.get_sqla_engine() - sql = qry.compile(engine, compile_kwargs={"literal_binds": True}) - sql = self._apply_cte(sql, cte) - sql = self.mutate_query_from_config(sql) + with self.database.get_sqla_engine_with_context() as engine: + sql = qry.compile(engine, compile_kwargs={"literal_binds": True}) + sql = self._apply_cte(sql, cte) + sql = self.mutate_query_from_config(sql) - df = pd.read_sql_query(sql=sql, con=engine) - return df[column_name].to_list() + df = pd.read_sql_query(sql=sql, con=engine) + return df[column_name].to_list() def mutate_query_from_config(self, sql: str) -> str: """Apply config's SQL_QUERY_MUTATOR Typically adds comments to the query with context""" sql_query_mutator = config["SQL_QUERY_MUTATOR"] - if sql_query_mutator: + mutate_after_split = config["MUTATE_AFTER_SPLIT"] + if sql_query_mutator and not mutate_after_split: sql = sql_query_mutator( sql, # TODO(john-bodley): Deprecate in 3.0. @@ -1024,7 +921,7 @@ def get_from_clause( cte = self.db_engine_spec.get_cte_query(from_sql) from_clause = ( - table(CTE_ALIAS) + table(self.db_engine_spec.cte_alias) if cte else TextAsFrom(self.text(from_sql), []).alias(VIRTUAL_TABLE_ALIAS) ) @@ -1081,7 +978,9 @@ def adhoc_metric_to_sqla( column_name = cast(str, metric_column.get("column_name")) table_column: Optional[TableColumn] = columns_by_name.get(column_name) if table_column: - sqla_column = table_column.get_sqla_col() + sqla_column = table_column.get_sqla_col( + template_processor=template_processor + ) else: sqla_column = column(column_name) sqla_metric = self.sqla_aggregations[metric["aggregate"]](sqla_column) @@ -1118,7 +1017,31 @@ def adhoc_column_to_sqla( schema=self.schema, template_processor=template_processor, ) - sqla_column = literal_column(expression) + col_in_metadata = self.get_column(expression) + if col_in_metadata: + sqla_column = col_in_metadata.get_sqla_col( + template_processor=template_processor + ) + is_dttm = col_in_metadata.is_temporal + else: + sqla_column = literal_column(expression) + # probe adhoc column type + tbl, _ = self.get_from_clause(template_processor) + qry = sa.select([sqla_column]).limit(1).select_from(tbl) + sql = self.database.compile_sqla_query(qry) + col_desc = get_columns_description(self.database, sql) + is_dttm = col_desc[0]["is_dttm"] + + if ( + is_dttm + and col.get("columnType") == "BASE_AXIS" + and (time_grain := col.get("timeGrain")) + ): + sqla_column = self.db_engine_spec.get_timestamp_expr( + col=sqla_column, + pdf=None, + time_grain=time_grain, + ) return self.make_sqla_column_compatible(sqla_column, label) def make_sqla_column_compatible( @@ -1170,7 +1093,6 @@ def is_alias_used_in_orderby(col: ColumnElement) -> bool: def get_sqla_row_level_filters( self, template_processor: BaseTemplateProcessor, - username: Optional[str] = None, ) -> List[TextClause]: """ Return the appropriate row level security filters for this table and the @@ -1178,14 +1100,12 @@ def get_sqla_row_level_filters( Flask global namespace. :param template_processor: The template processor to apply to the filters. - :param username: Optional username if there's no user in the Flask global - namespace. :returns: A list of SQL clauses to be ANDed together. """ all_filters: List[TextClause] = [] filter_groups: Dict[Union[int, str], List[TextClause]] = defaultdict(list) try: - for filter_ in security_manager.get_rls_filters(self, username): + for filter_ in security_manager.get_rls_filters(self): clause = self.text( f"({template_processor.process_template(filter_.clause)})" ) @@ -1241,6 +1161,7 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma row_offset: Optional[int] = None, timeseries_limit: Optional[int] = None, timeseries_limit_metric: Optional[Metric] = None, + time_shift: Optional[str] = None, ) -> SqlaQuery: """Querying any sqla table from this common interface""" if granularity not in self.dttm_cols and granularity is not None: @@ -1315,7 +1236,11 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma ) ) elif isinstance(metric, str) and metric in metrics_by_name: - metrics_exprs.append(metrics_by_name[metric].get_sqla_col()) + metrics_exprs.append( + metrics_by_name[metric].get_sqla_col( + template_processor=template_processor + ) + ) else: raise QueryObjectValidationError( _("Metric '%(metric)s' does not exist", metric=metric) @@ -1354,12 +1279,16 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma col = metrics_exprs_by_expr.get(str(col), col) need_groupby = True elif col in columns_by_name: - col = columns_by_name[col].get_sqla_col() + col = columns_by_name[col].get_sqla_col( + template_processor=template_processor + ) elif col in metrics_exprs_by_label: col = metrics_exprs_by_label[col] need_groupby = True elif col in metrics_by_name: - col = metrics_by_name[col].get_sqla_col() + col = metrics_by_name[col].get_sqla_col( + template_processor=template_processor + ) need_groupby = True if isinstance(col, ColumnElement): @@ -1393,7 +1322,9 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma ) # if groupby field equals a selected column elif selected in columns_by_name: - outer = columns_by_name[selected].get_sqla_col() + outer = columns_by_name[selected].get_sqla_col( + template_processor=template_processor + ) else: selected = validate_adhoc_subquery( selected, @@ -1427,7 +1358,9 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma self.schema, ) select_exprs.append( - columns_by_name[selected].get_sqla_col() + columns_by_name[selected].get_sqla_col( + template_processor=template_processor + ) if isinstance(selected, str) and selected in columns_by_name else self.make_sqla_column_compatible( literal_column(selected), _column_label @@ -1461,11 +1394,18 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma ): time_filters.append( columns_by_name[self.main_dttm_col].get_time_filter( - from_dttm, - to_dttm, + start_dttm=from_dttm, + end_dttm=to_dttm, + template_processor=template_processor, ) ) - time_filters.append(dttm_col.get_time_filter(from_dttm, to_dttm)) + time_filters.append( + dttm_col.get_time_filter( + start_dttm=from_dttm, + end_dttm=to_dttm, + template_processor=template_processor, + ) + ) # Always remove duplicates by column name, as sometimes `metrics_exprs` # can have the same name as a groupby column (e.g. when users use @@ -1521,7 +1461,9 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma time_grain=filter_grain, template_processor=template_processor ) elif col_obj: - sqla_col = col_obj.get_sqla_col() + sqla_col = col_obj.get_sqla_col( + template_processor=template_processor + ) col_type = col_obj.type if col_obj else None col_spec = db_engine_spec.get_column_spec( native_type=col_type, @@ -1546,6 +1488,7 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma target_generic_type = GenericDataType.STRING eq = self.filter_values_handler( values=val, + operator=op, target_generic_type=target_generic_type, target_native_type=col_type, is_list_target=is_list_target, @@ -1607,7 +1550,14 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma elif op == utils.FilterOperator.IS_FALSE.value: where_clause_and.append(sqla_col.is_(False)) else: - if eq is None: + if ( + op + not in { + utils.FilterOperator.EQUALS.value, + utils.FilterOperator.NOT_EQUALS.value, + } + and eq is None + ): raise QueryObjectValidationError( _( "Must specify a value for filters " @@ -1630,6 +1580,24 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma where_clause_and.append(sqla_col.like(eq)) elif op == utils.FilterOperator.ILIKE.value: where_clause_and.append(sqla_col.ilike(eq)) + elif ( + op == utils.FilterOperator.TEMPORAL_RANGE.value + and isinstance(eq, str) + and col_obj is not None + ): + _since, _until = get_since_until_from_time_range( + time_range=eq, + time_shift=time_shift, + extras=extras, + ) + where_clause_and.append( + col_obj.get_time_filter( + start_dttm=_since, + end_dttm=_until, + label=sqla_col.key, + template_processor=template_processor, + ) + ) else: raise QueryObjectValidationError( _("Invalid filter operation type: %(op)s", op=op) @@ -1672,7 +1640,9 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma having_clause_and += [self.text(having)] if apply_fetch_values_predicate and self.fetch_values_predicate: - qry = qry.where(self.get_fetch_values_predicate()) + qry = qry.where( + self.get_fetch_values_predicate(template_processor=template_processor) + ) if granularity: qry = qry.where(and_(*(time_filters + where_clause_and))) else: @@ -1724,8 +1694,9 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma if dttm_col and not db_engine_spec.time_groupby_inline: inner_time_filter = [ dttm_col.get_time_filter( - inner_from_dttm or from_dttm, - inner_to_dttm or to_dttm, + start_dttm=inner_from_dttm or from_dttm, + end_dttm=inner_to_dttm or to_dttm, + template_processor=template_processor, ) ] subq = subq.where(and_(*(where_clause_and + inner_time_filter))) @@ -1734,7 +1705,10 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma ob = inner_main_metric_expr if series_limit_metric: ob = self._get_series_orderby( - series_limit_metric, metrics_by_name, columns_by_name + series_limit_metric=series_limit_metric, + metrics_by_name=metrics_by_name, + columns_by_name=columns_by_name, + template_processor=template_processor, ) direction = desc if order_desc else asc subq = subq.order_by(direction(ob)) @@ -1754,9 +1728,10 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma orderby = [ ( self._get_series_orderby( - series_limit_metric, - metrics_by_name, - columns_by_name, + series_limit_metric=series_limit_metric, + metrics_by_name=metrics_by_name, + columns_by_name=columns_by_name, + template_processor=template_processor, ), not order_desc, ) @@ -1816,6 +1791,7 @@ def _get_series_orderby( series_limit_metric: Metric, metrics_by_name: Dict[str, SqlMetric], columns_by_name: Dict[str, TableColumn], + template_processor: Optional[BaseTemplateProcessor] = None, ) -> Column: if utils.is_adhoc_metric(series_limit_metric): assert isinstance(series_limit_metric, dict) @@ -1824,7 +1800,9 @@ def _get_series_orderby( isinstance(series_limit_metric, str) and series_limit_metric in metrics_by_name ): - ob = metrics_by_name[series_limit_metric].get_sqla_col() + ob = metrics_by_name[series_limit_metric].get_sqla_col( + template_processor=template_processor + ) else: raise QueryObjectValidationError( _("Metric '%(metric)s' does not exist", metric=series_limit_metric) @@ -1958,7 +1936,10 @@ def fetch_metadata(self, commit: bool = True) -> MetadataResult: :return: Tuple with lists of added, removed and modified column names. """ new_columns = self.external_metadata() - metrics = [] + metrics = [ + SqlMetric(**metric) + for metric in self.database.get_metrics(self.table_name, self.schema) + ] any_date_col = None db_engine_spec = self.db_engine_spec @@ -2015,14 +1996,6 @@ def fetch_metadata(self, commit: bool = True) -> MetadataResult: columns.extend([col for col in old_columns if col.expression]) self.columns = columns - metrics.append( - SqlMetric( - metric_name="count", - verbose_name="COUNT(*)", - metric_type="count", - expression="COUNT(*)", - ) - ) if not self.main_dttm_col: self.main_dttm_col = any_date_col self.add_missing_metrics(metrics) @@ -2042,7 +2015,7 @@ def query_datasources_by_name( database: Database, datasource_name: str, schema: Optional[str] = None, - ) -> List["SqlaTable"]: + ) -> List[SqlaTable]: query = ( session.query(cls) .filter_by(database_id=database.id) @@ -2052,6 +2025,48 @@ def query_datasources_by_name( query = query.filter_by(schema=schema) return query.all() + @classmethod + def query_datasources_by_permissions( # pylint: disable=invalid-name + cls, + session: Session, + database: Database, + permissions: Set[str], + schema_perms: Set[str], + ) -> List[SqlaTable]: + # TODO(hughhhh): add unit test + return ( + session.query(cls) + .filter_by(database_id=database.id) + .filter( + or_( + SqlaTable.perm.in_(permissions), + SqlaTable.schema_perm.in_(schema_perms), + ) + ) + .all() + ) + + @classmethod + def get_eager_sqlatable_datasource( + cls, session: Session, datasource_id: int + ) -> SqlaTable: + """Returns SqlaTable with columns and metrics.""" + return ( + session.query(cls) + .options( + sa.orm.subqueryload(cls.columns), + sa.orm.subqueryload(cls.metrics), + ) + .filter_by(id=datasource_id) + .one() + ) + + @classmethod + def get_all_datasources(cls, session: Session) -> List[SqlaTable]: + qry = session.query(cls) + qry = cls.default_query(qry) + return qry.all() + @staticmethod def default_query(qry: Query) -> Query: return qry.filter_by(is_sqllab_view=False) @@ -2108,7 +2123,7 @@ def quote_identifier(self) -> Callable[[str], str]: def before_update( mapper: Mapper, # pylint: disable=unused-argument connection: Connection, # pylint: disable=unused-argument - target: "SqlaTable", + target: SqlaTable, ) -> None: """ Check before update if the target table already exists. @@ -2145,40 +2160,6 @@ def before_update( ): raise Exception(get_dataset_exist_error_msg(target.full_name)) - def get_sl_columns(self) -> List[NewColumn]: - """ - Convert `SqlaTable.columns` and `SqlaTable.metrics` to the new Column model - """ - session: Session = inspect(self).session - - uuids = set() - for column_or_metric in self.columns + self.metrics: - # pre-assign uuid after new columns or metrics are inserted so - # the related `NewColumn` can have a deterministic uuid, too - if not column_or_metric.uuid: - column_or_metric.uuid = uuid4() - else: - uuids.add(column_or_metric.uuid) - - # load existing columns from cached session states first - existing_columns = set( - find_cached_objects_in_session(session, NewColumn, uuids=uuids) - ) - for column in existing_columns: - uuids.remove(column.uuid) - - if uuids: - with session.no_autoflush: - # load those not found from db - existing_columns |= set( - session.query(NewColumn).filter(NewColumn.uuid.in_(uuids)) - ) - - known_columns = {column.uuid: column for column in existing_columns} - return [ - item.to_sl_column(known_columns) for item in self.columns + self.metrics - ] - @staticmethod def update_column( # pylint: disable=unused-argument mapper: Mapper, connection: Connection, target: Union[SqlMetric, TableColumn] @@ -2195,6 +2176,7 @@ def update_column( # pylint: disable=unused-argument # table is updated. This busts the cache key for all charts that use the table. session.execute(update(SqlaTable).where(SqlaTable.id == target.table.id)) + # TODO: This shadow writing is deprecated # if table itself has changed, shadow-writing will happen in `after_update` anyway if target.table not in session.dirty: dataset: NewDataset = ( @@ -2209,99 +2191,44 @@ def update_column( # pylint: disable=unused-argument target.table.write_shadow_dataset() return - # update changed_on timestamp - session.execute(update(NewDataset).where(NewDataset.id == dataset.id)) - try: - with session.no_autoflush: - column = session.query(NewColumn).filter_by(uuid=target.uuid).one() - # update `Column` model as well - session.merge(target.to_sl_column({target.uuid: column})) - except NoResultFound: - logger.warning("No column was found for %s", target) - # see if the column is in cache - column = next( - find_cached_objects_in_session( - session, NewColumn, uuids=[target.uuid] - ), - None, - ) - if column: - logger.warning("New column was found in cache: %s", column) - - else: - # to be safe, use a different uuid and create a new column - uuid = uuid4() - target.uuid = uuid - - session.add(target.to_sl_column()) - @staticmethod def after_insert( mapper: Mapper, connection: Connection, - sqla_table: "SqlaTable", + sqla_table: SqlaTable, ) -> None: """ - Shadow write the dataset to new models. - - The ``SqlaTable`` model is currently being migrated to two new models, ``Table`` - and ``Dataset``. In the first phase of the migration the new models are populated - whenever ``SqlaTable`` is modified (created, updated, or deleted). - - In the second phase of the migration reads will be done from the new models. - Finally, in the third phase of the migration the old models will be removed. - - For more context: https://github.com/apache/superset/issues/14909 + Update dataset permissions after insert """ - security_manager.set_perm(mapper, connection, sqla_table) + security_manager.dataset_after_insert(mapper, connection, sqla_table) + + # TODO: deprecated sqla_table.write_shadow_dataset() @staticmethod - def after_delete( # pylint: disable=unused-argument + def after_delete( mapper: Mapper, connection: Connection, - sqla_table: "SqlaTable", + sqla_table: SqlaTable, ) -> None: """ - Shadow write the dataset to new models. - - The ``SqlaTable`` model is currently being migrated to two new models, ``Table`` - and ``Dataset``. In the first phase of the migration the new models are populated - whenever ``SqlaTable`` is modified (created, updated, or deleted). - - In the second phase of the migration reads will be done from the new models. - Finally, in the third phase of the migration the old models will be removed. - - For more context: https://github.com/apache/superset/issues/14909 + Update dataset permissions after delete """ - session = inspect(sqla_table).session - dataset = ( - session.query(NewDataset).filter_by(uuid=sqla_table.uuid).one_or_none() - ) - if dataset: - session.delete(dataset) + security_manager.dataset_after_delete(mapper, connection, sqla_table) @staticmethod def after_update( mapper: Mapper, connection: Connection, - sqla_table: "SqlaTable", + sqla_table: SqlaTable, ) -> None: """ - Shadow write the dataset to new models. - - The ``SqlaTable`` model is currently being migrated to two new models, ``Table`` - and ``Dataset``. In the first phase of the migration the new models are populated - whenever ``SqlaTable`` is modified (created, updated, or deleted). - - In the second phase of the migration reads will be done from the new models. - Finally, in the third phase of the migration the old models will be removed. - - For more context: https://github.com/apache/superset/issues/14909 + Update dataset permissions """ # set permissions - security_manager.set_perm(mapper, connection, sqla_table) + security_manager.dataset_after_update(mapper, connection, sqla_table) + # TODO: the shadow writing is deprecated inspector = inspect(sqla_table) session = inspector.session @@ -2327,201 +2254,29 @@ def after_update( sqla_table.write_shadow_dataset() return - # sync column list and delete removed columns - if ( - inspector.attrs.columns.history.has_changes() - or inspector.attrs.metrics.history.has_changes() - ): - # add pending new columns to known columns list, too, so if calling - # `after_update` twice before changes are persisted will not create - # two duplicate columns with the same uuids. - dataset.columns = sqla_table.get_sl_columns() - - # physical dataset - if not sqla_table.sql: - # if the table name changed we should relink the dataset to another table - # (and create one if necessary) - if ( - inspector.attrs.table_name.history.has_changes() - or inspector.attrs.schema.history.has_changes() - or inspector.attrs.database.history.has_changes() - ): - tables = NewTable.bulk_load_or_create( - sqla_table.database, - [TableName(schema=sqla_table.schema, table=sqla_table.table_name)], - sync_columns=False, - default_props=dict( - changed_by=sqla_table.changed_by, - created_by=sqla_table.created_by, - is_managed_externally=sqla_table.is_managed_externally, - external_url=sqla_table.external_url, - ), - ) - if not tables[0].id: - # dataset columns will only be assigned to newly created tables - # existing tables should manage column syncing in another process - physical_columns = [ - clone_model( - column, ignore=["uuid"], keep_relations=["changed_by"] - ) - for column in dataset.columns - if column.is_physical - ] - tables[0].columns = physical_columns - dataset.tables = tables - - # virtual dataset - else: - # mark all columns as virtual (not physical) - for column in dataset.columns: - column.is_physical = False - - # update referenced tables if SQL changed - if sqla_table.sql and inspector.attrs.sql.history.has_changes(): - referenced_tables = extract_table_references( - sqla_table.sql, sqla_table.database.get_dialect().name - ) - dataset.tables = NewTable.bulk_load_or_create( - sqla_table.database, - referenced_tables, - default_schema=sqla_table.schema, - # sync metadata is expensive, we'll do it in another process - # e.g. when users open a Table page - sync_columns=False, - default_props=dict( - changed_by=sqla_table.changed_by, - created_by=sqla_table.created_by, - is_managed_externally=sqla_table.is_managed_externally, - external_url=sqla_table.external_url, - ), - ) - - # update other attributes - dataset.name = sqla_table.table_name - dataset.expression = sqla_table.sql or sqla_table.quote_identifier( - sqla_table.table_name - ) - dataset.is_physical = not sqla_table.sql - def write_shadow_dataset( - self: "SqlaTable", + self: SqlaTable, ) -> None: """ - Shadow write the dataset to new models. - - The ``SqlaTable`` model is currently being migrated to two new models, ``Table`` - and ``Dataset``. In the first phase of the migration the new models are populated - whenever ``SqlaTable`` is modified (created, updated, or deleted). - - In the second phase of the migration reads will be done from the new models. - Finally, in the third phase of the migration the old models will be removed. - - For more context: https://github.com/apache/superset/issues/14909 + This method is deprecated """ session = inspect(self).session - # make sure database points to the right instance, in case only - # `table.database_id` is updated and the changes haven't been - # consolidated by SQLA + # most of the write_shadow_dataset functionality has been removed + # but leaving this portion in + # to remove later because it is adding a Database relationship to the session + # and there is some functionality that depends on this if self.database_id and ( not self.database or self.database.id != self.database_id ): self.database = session.query(Database).filter_by(id=self.database_id).one() - # create columns - columns = [] - for item in self.columns + self.metrics: - item.created_by = self.created_by - item.changed_by = self.changed_by - # on `SqlaTable.after_insert`` event, although the table itself - # already has a `uuid`, the associated columns will not. - # Here we pre-assign a uuid so they can still be matched to the new - # Column after creation. - if not item.uuid: - item.uuid = uuid4() - columns.append(item.to_sl_column()) - - # physical dataset - if not self.sql: - # always create separate column entries for Dataset and Table - # so updating a dataset would not update columns in the related table - physical_columns = [ - clone_model( - column, - ignore=["uuid"], - # `created_by` will always be left empty because it'd always - # be created via some sort of automated system. - # But keep `changed_by` in case someone manually changes - # column attributes such as `is_dttm`. - keep_relations=["changed_by"], - ) - for column in columns - if column.is_physical - ] - tables = NewTable.bulk_load_or_create( - self.database, - [TableName(schema=self.schema, table=self.table_name)], - sync_columns=False, - default_props=dict( - created_by=self.created_by, - changed_by=self.changed_by, - is_managed_externally=self.is_managed_externally, - external_url=self.external_url, - ), - ) - tables[0].columns = physical_columns - - # virtual dataset - else: - # mark all columns as virtual (not physical) - for column in columns: - column.is_physical = False - - # find referenced tables - referenced_tables = extract_table_references( - self.sql, self.database.get_dialect().name - ) - tables = NewTable.bulk_load_or_create( - self.database, - referenced_tables, - default_schema=self.schema, - # syncing table columns can be slow so we are not doing it here - sync_columns=False, - default_props=dict( - created_by=self.created_by, - changed_by=self.changed_by, - is_managed_externally=self.is_managed_externally, - external_url=self.external_url, - ), - ) - - # create the new dataset - new_dataset = NewDataset( - uuid=self.uuid, - database_id=self.database_id, - created_on=self.created_on, - created_by=self.created_by, - changed_by=self.changed_by, - changed_on=self.changed_on, - owners=self.owners, - name=self.table_name, - expression=self.sql or self.quote_identifier(self.table_name), - tables=tables, - columns=columns, - is_physical=not self.sql, - is_managed_externally=self.is_managed_externally, - external_url=self.external_url, - ) - session.add(new_dataset) - sa.event.listen(SqlaTable, "before_update", SqlaTable.before_update) +sa.event.listen(SqlaTable, "after_update", SqlaTable.after_update) sa.event.listen(SqlaTable, "after_insert", SqlaTable.after_insert) sa.event.listen(SqlaTable, "after_delete", SqlaTable.after_delete) -sa.event.listen(SqlaTable, "after_update", SqlaTable.after_update) sa.event.listen(SqlMetric, "after_update", SqlaTable.update_column) -sa.event.listen(SqlMetric, "after_delete", SqlMetric.after_delete) sa.event.listen(TableColumn, "after_update", SqlaTable.update_column) -sa.event.listen(TableColumn, "after_delete", TableColumn.after_delete) RLSFilterRoles = Table( "rls_filter_roles", @@ -2547,6 +2302,8 @@ class RowLevelSecurityFilter(Model, AuditMixinNullable): __tablename__ = "row_level_security_filters" id = Column(Integer, primary_key=True) + name = Column(String(255), unique=True, nullable=False) + description = Column(Text) filter_type = Column( Enum(*[filter_type.value for filter_type in utils.RowLevelSecurityFilterType]) ) @@ -2559,5 +2316,4 @@ class RowLevelSecurityFilter(Model, AuditMixinNullable): tables = relationship( SqlaTable, secondary=RLSFilterTables, backref="row_level_security_filters" ) - clause = Column(Text, nullable=False) diff --git a/superset/connectors/sqla/utils.py b/superset/connectors/sqla/utils.py index db8877aa06e0d..92ee4d97f8340 100644 --- a/superset/connectors/sqla/utils.py +++ b/superset/connectors/sqla/utils.py @@ -14,8 +14,9 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from __future__ import annotations + import logging -from contextlib import closing from typing import ( Any, Callable, @@ -106,7 +107,7 @@ def get_physical_table_metadata( return cols -def get_virtual_table_metadata(dataset: "SqlaTable") -> List[ResultSetColumnType]: +def get_virtual_table_metadata(dataset: SqlaTable) -> List[ResultSetColumnType]: """Use SQLparser to get virtual dataset metadata""" if not dataset.sql: raise SupersetGenericDBErrorException( @@ -114,7 +115,6 @@ def get_virtual_table_metadata(dataset: "SqlaTable") -> List[ResultSetColumnType ) db_engine_spec = dataset.database.db_engine_spec - engine = dataset.database.get_sqla_engine(schema=dataset.schema) sql = dataset.get_template_processor().process_template( dataset.sql, **dataset.template_params_dict ) @@ -139,9 +139,9 @@ def get_virtual_table_metadata(dataset: "SqlaTable") -> List[ResultSetColumnType # TODO(villebro): refactor to use same code that's used by # sql_lab.py:execute_sql_statements try: - with closing(engine.raw_connection()) as conn: + with dataset.database.get_raw_connection(schema=dataset.schema) as conn: cursor = conn.cursor() - query = dataset.database.apply_limit_to_sql(statements[0]) + query = dataset.database.apply_limit_to_sql(statements[0], limit=1) db_engine_spec.execute(cursor, query) result = db_engine_spec.fetch_data(cursor, limit=1) result_set = SupersetResultSet(result, cursor.description, db_engine_spec) @@ -151,6 +151,24 @@ def get_virtual_table_metadata(dataset: "SqlaTable") -> List[ResultSetColumnType return cols +def get_columns_description( + database: Database, + query: str, +) -> List[ResultSetColumnType]: + db_engine_spec = database.db_engine_spec + try: + with database.get_raw_connection() as conn: + cursor = conn.cursor() + query = database.apply_limit_to_sql(query, limit=1) + cursor.execute(query) + db_engine_spec.execute(cursor, query) + result = db_engine_spec.fetch_data(cursor, limit=1) + result_set = SupersetResultSet(result, cursor.description, db_engine_spec) + return result_set.columns + except Exception as ex: + raise SupersetGenericDBErrorException(message=str(ex)) from ex + + def validate_adhoc_subquery( sql: str, database_id: int, @@ -188,12 +206,12 @@ def validate_adhoc_subquery( @memoized def get_dialect_name(drivername: str) -> str: - return SqlaURL(drivername).get_dialect().name + return SqlaURL.create(drivername).get_dialect().name @memoized def get_identifier_quoter(drivername: str) -> Dict[str, Callable[[str], str]]: - return SqlaURL(drivername).get_dialect()().identifier_preparer.quote + return SqlaURL.create(drivername).get_dialect()().identifier_preparer.quote DeclarativeModel = TypeVar("DeclarativeModel", bound=DeclarativeMeta) @@ -217,7 +235,7 @@ def find_cached_objects_in_session( return iter([]) uuids = uuids or [] try: - items = set(session) + items = list(session) except ObjectDeletedError: logger.warning("ObjectDeletedError", exc_info=True) return iter(()) diff --git a/superset/connectors/sqla/views.py b/superset/connectors/sqla/views.py index c7b0271123924..cb46930d9e296 100644 --- a/superset/connectors/sqla/views.py +++ b/superset/connectors/sqla/views.py @@ -35,7 +35,6 @@ from superset.superset_typing import FlaskResponse from superset.utils import core as utils from superset.views.base import ( - create_table_permissions, DatasourceFilter, DeleteMixin, ListWidgetWithCheckboxes, @@ -60,9 +59,10 @@ class SelectDataRequired(DataRequired): # pylint: disable=too-few-public-method field_flags = () -class TableColumnInlineView( - CompactCRUDMixin, SupersetModelView -): # pylint: disable=too-many-ancestors +class TableColumnInlineView( # pylint: disable=too-many-ancestors + CompactCRUDMixin, + SupersetModelView, +): datamodel = SQLAInterface(models.TableColumn) # TODO TODO, review need for this on related_views class_permission_name = "Dataset" @@ -99,6 +99,7 @@ class TableColumnInlineView( "groupby", "filterable", "is_dttm", + "extra", ] page_size = 500 description_columns = { @@ -194,9 +195,10 @@ class TableColumnInlineView( edit_form_extra_fields = add_form_extra_fields -class SqlMetricInlineView( - CompactCRUDMixin, SupersetModelView -): # pylint: disable=too-many-ancestors +class SqlMetricInlineView( # pylint: disable=too-many-ancestors + CompactCRUDMixin, + SupersetModelView, +): datamodel = SQLAInterface(models.SqlMetric) class_permission_name = "Dataset" method_permission_name = MODEL_VIEW_RW_METHOD_PERMISSION_MAP @@ -207,7 +209,7 @@ class SqlMetricInlineView( add_title = _("Add Metric") edit_title = _("Edit Metric") - list_columns = ["metric_name", "verbose_name", "metric_type"] + list_columns = ["metric_name", "verbose_name", "metric_type", "extra"] edit_columns = [ "metric_name", "description", @@ -278,9 +280,9 @@ def __init__(self, **kwargs: Any): super().__init__(**kwargs) -class RowLevelSecurityFiltersModelView( +class RowLevelSecurityFiltersModelView( # pylint: disable=too-many-ancestors SupersetModelView, DeleteMixin -): # pylint: disable=too-many-ancestors +): datamodel = SQLAInterface(models.RowLevelSecurityFilter) list_widget = cast(SupersetListWidget, RowLevelSecurityListWidget) @@ -291,21 +293,39 @@ class RowLevelSecurityFiltersModelView( edit_title = _("Edit Row level security filter") list_columns = [ + "name", "filter_type", "tables", "roles", - "group_key", "clause", "creator", "modified", ] - order_columns = ["filter_type", "group_key", "clause", "modified"] - edit_columns = ["filter_type", "tables", "roles", "group_key", "clause"] + order_columns = ["name", "filter_type", "clause", "modified"] + edit_columns = [ + "name", + "description", + "filter_type", + "tables", + "roles", + "group_key", + "clause", + ] show_columns = edit_columns - search_columns = ("filter_type", "tables", "roles", "group_key", "clause") + search_columns = ( + "name", + "description", + "filter_type", + "tables", + "roles", + "group_key", + "clause", + ) add_columns = edit_columns base_order = ("changed_on", "desc") description_columns = { + "name": _("Choose a unique name"), + "description": _("Optionally add a detailed description"), "filter_type": _( "Regular filters add where clauses to queries if a user belongs to a " "role referenced in the filter. Base filters apply filters to all queries " @@ -338,12 +358,16 @@ class RowLevelSecurityFiltersModelView( ), } label_columns = { + "name": _("Name"), + "description": _("Description"), "tables": _("Tables"), "roles": _("Roles"), "clause": _("Clause"), "creator": _("Creator"), "modified": _("Modified"), } + validators_columns = {"tables": [SelectDataRequired()]} + if app.config["RLS_FORM_QUERY_REL_FIELDS"]: add_form_query_rel_fields = app.config["RLS_FORM_QUERY_REL_FIELDS"] edit_form_query_rel_fields = add_form_query_rel_fields @@ -486,7 +510,6 @@ def post_add( # pylint: disable=arguments-differ ) -> None: if fetch_metadata: item.fetch_metadata() - create_table_permissions(item) if flash_message: flash( _( @@ -511,7 +534,7 @@ def edit(self, pk: str) -> FlaskResponse: resp = super().edit(pk) if isinstance(resp, str): return resp - return redirect("/superset/explore/table/{}/".format(pk)) + return redirect("/explore/?datasource_type=table&datasource_id={}".format(pk)) @expose("/list/") @has_access diff --git a/superset/constants.py b/superset/constants.py index 72fcc3fdb2bce..5c1f0e36fe264 100644 --- a/superset/constants.py +++ b/superset/constants.py @@ -20,6 +20,8 @@ # string to use when None values *need* to be converted to/from strings from enum import Enum +USER_AGENT = "Apache Superset" + NULL_STRING = "<NULL>" EMPTY_STRING = "<empty string>" @@ -28,6 +30,13 @@ # UUID for the examples database EXAMPLES_DB_UUID = "a2dc77af-e654-49bb-b321-40f6b559a1ee" +PASSWORD_MASK = "X" * 10 + +NO_TIME_RANGE = "No filter" + +QUERY_CANCEL_KEY = "cancel_query" +QUERY_EARLY_CANCEL_KEY = "early_cancel_query" + class RouteMethod: # pylint: disable=too-few-public-methods """ @@ -109,6 +118,7 @@ class RouteMethod: # pylint: disable=too-few-public-methods "put": "write", "related": "read", "related_objects": "read", + "tables": "read", "schemas": "read", "select_star": "read", "table_metadata": "read", @@ -130,6 +140,9 @@ class RouteMethod: # pylint: disable=too-few-public-methods "validate_sql": "read", "get_data": "read", "samples": "read", + "delete_ssh_tunnel": "write", + "get_updated_since": "read", + "stop_query": "read", } EXTRA_FORM_DATA_APPEND_KEYS = { @@ -147,7 +160,6 @@ class RouteMethod: # pylint: disable=too-few-public-methods "time_column": "time_column", "time_grain": "time_grain", "time_range": "time_range", - "druid_time_origin": "druid_time_origin", "time_grain_sqla": "time_grain_sqla", } diff --git a/superset/css_templates/api.py b/superset/css_templates/api.py index 5cc36f400198c..ae367985e9c5f 100644 --- a/superset/css_templates/api.py +++ b/superset/css_templates/api.py @@ -17,7 +17,7 @@ import logging from typing import Any -from flask import g, Response +from flask import Response from flask_appbuilder.api import expose, protect, rison, safe from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_babel import ngettext @@ -130,7 +130,7 @@ def bulk_delete(self, **kwargs: Any) -> Response: """ item_ids = kwargs["rison"] try: - BulkDeleteCssTemplateCommand(g.user, item_ids).run() + BulkDeleteCssTemplateCommand(item_ids).run() return self.response( 200, message=ngettext( diff --git a/superset/css_templates/commands/bulk_delete.py b/superset/css_templates/commands/bulk_delete.py index 839dbd26aee5a..93564208c4f15 100644 --- a/superset/css_templates/commands/bulk_delete.py +++ b/superset/css_templates/commands/bulk_delete.py @@ -17,8 +17,6 @@ import logging from typing import List, Optional -from flask_appbuilder.security.sqla.models import User - from superset.commands.base import BaseCommand from superset.css_templates.commands.exceptions import ( CssTemplateBulkDeleteFailedError, @@ -32,8 +30,7 @@ class BulkDeleteCssTemplateCommand(BaseCommand): - def __init__(self, user: User, model_ids: List[int]): - self._actor = user + def __init__(self, model_ids: List[int]): self._model_ids = model_ids self._models: Optional[List[CssTemplate]] = None diff --git a/superset/dao/base.py b/superset/dao/base.py index 0090c4e535e23..126238f661323 100644 --- a/superset/dao/base.py +++ b/superset/dao/base.py @@ -50,14 +50,17 @@ class BaseDAO: @classmethod def find_by_id( - cls, model_id: Union[str, int], session: Session = None + cls, + model_id: Union[str, int], + session: Session = None, + skip_base_filter: bool = False, ) -> Optional[Model]: """ Find a model by id, if defined applies `base_filter` """ session = session or db.session query = session.query(cls.model_cls) - if cls.base_filter: + if cls.base_filter and not skip_base_filter: data_model = SQLAInterface(cls.model_cls, session) query = cls.base_filter( # pylint: disable=not-callable cls.id_column_name, data_model @@ -70,16 +73,22 @@ def find_by_id( return None @classmethod - def find_by_ids(cls, model_ids: Union[List[str], List[int]]) -> List[Model]: + def find_by_ids( + cls, + model_ids: Union[List[str], List[int]], + session: Session = None, + skip_base_filter: bool = False, + ) -> List[Model]: """ Find a List of models by a list of ids, if defined applies `base_filter` """ id_col = getattr(cls.model_cls, cls.id_column_name, None) if id_col is None: return [] - query = db.session.query(cls.model_cls).filter(id_col.in_(model_ids)) - if cls.base_filter: - data_model = SQLAInterface(cls.model_cls, db.session) + session = session or db.session + query = session.query(cls.model_cls).filter(id_col.in_(model_ids)) + if cls.base_filter and not skip_base_filter: + data_model = SQLAInterface(cls.model_cls, session) query = cls.base_filter( # pylint: disable=not-callable cls.id_column_name, data_model ).apply(query, None) diff --git a/superset/dao/datasource/dao.py b/superset/dao/datasource/dao.py deleted file mode 100644 index caa45564aa250..0000000000000 --- a/superset/dao/datasource/dao.py +++ /dev/null @@ -1,147 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -from enum import Enum -from typing import Any, Dict, List, Optional, Set, Type, Union - -from flask_babel import _ -from sqlalchemy import or_ -from sqlalchemy.orm import Session, subqueryload -from sqlalchemy.orm.exc import NoResultFound - -from superset.connectors.sqla.models import SqlaTable -from superset.dao.base import BaseDAO -from superset.dao.exceptions import DatasourceNotFound, DatasourceTypeNotSupportedError -from superset.datasets.commands.exceptions import DatasetNotFoundError -from superset.datasets.models import Dataset -from superset.models.core import Database -from superset.models.sql_lab import Query, SavedQuery -from superset.tables.models import Table -from superset.utils.core import DatasourceType - -Datasource = Union[Dataset, SqlaTable, Table, Query, SavedQuery] - - -class DatasourceDAO(BaseDAO): - - sources: Dict[DatasourceType, Type[Datasource]] = { - DatasourceType.TABLE: SqlaTable, - DatasourceType.QUERY: Query, - DatasourceType.SAVEDQUERY: SavedQuery, - DatasourceType.DATASET: Dataset, - DatasourceType.SLTABLE: Table, - } - - @classmethod - def get_datasource( - cls, session: Session, datasource_type: DatasourceType, datasource_id: int - ) -> Datasource: - if datasource_type not in cls.sources: - raise DatasourceTypeNotSupportedError() - - datasource = ( - session.query(cls.sources[datasource_type]) - .filter_by(id=datasource_id) - .one_or_none() - ) - - if not datasource: - raise DatasourceNotFound() - - return datasource - - @classmethod - def get_all_sqlatables_datasources(cls, session: Session) -> List[Datasource]: - source_class = DatasourceDAO.sources[DatasourceType.TABLE] - qry = session.query(source_class) - qry = source_class.default_query(qry) - return qry.all() - - @classmethod - def get_datasource_by_name( # pylint: disable=too-many-arguments - cls, - session: Session, - datasource_type: DatasourceType, - datasource_name: str, - database_name: str, - schema: str, - ) -> Optional[Datasource]: - datasource_class = DatasourceDAO.sources[datasource_type] - if isinstance(datasource_class, SqlaTable): - return datasource_class.get_datasource_by_name( - session, datasource_name, schema, database_name - ) - return None - - @classmethod - def query_datasources_by_permissions( # pylint: disable=invalid-name - cls, - session: Session, - database: Database, - permissions: Set[str], - schema_perms: Set[str], - ) -> List[Datasource]: - # TODO(hughhhh): add unit test - datasource_class = DatasourceDAO.sources[DatasourceType[database.type]] - if not isinstance(datasource_class, SqlaTable): - return [] - - return ( - session.query(datasource_class) - .filter_by(database_id=database.id) - .filter( - or_( - datasource_class.perm.in_(permissions), - datasource_class.schema_perm.in_(schema_perms), - ) - ) - .all() - ) - - @classmethod - def get_eager_datasource( - cls, session: Session, datasource_type: str, datasource_id: int - ) -> Optional[Datasource]: - """Returns datasource with columns and metrics.""" - datasource_class = DatasourceDAO.sources[DatasourceType[datasource_type]] - if not isinstance(datasource_class, SqlaTable): - return None - return ( - session.query(datasource_class) - .options( - subqueryload(datasource_class.columns), - subqueryload(datasource_class.metrics), - ) - .filter_by(id=datasource_id) - .one() - ) - - @classmethod - def query_datasources_by_name( - cls, - session: Session, - database: Database, - datasource_name: str, - schema: Optional[str] = None, - ) -> List[Datasource]: - datasource_class = DatasourceDAO.sources[DatasourceType[database.type]] - if not isinstance(datasource_class, SqlaTable): - return [] - - return datasource_class.query_datasources_by_name( - session, database, datasource_name, schema=schema - ) diff --git a/superset/dao/exceptions.py b/superset/dao/exceptions.py index 9b5624bd5d31d..a11db63a4c14d 100644 --- a/superset/dao/exceptions.py +++ b/superset/dao/exceptions.py @@ -60,8 +60,10 @@ class DatasourceTypeNotSupportedError(DAOException): DAO datasource query source type is not supported """ + status = 422 message = "DAO datasource query source type is not supported" class DatasourceNotFound(DAOException): + status = 404 message = "Datasource does not exist" diff --git a/superset/dashboards/api.py b/superset/dashboards/api.py index 6e0a15a513e8b..64ea637c663d8 100644 --- a/superset/dashboards/api.py +++ b/superset/dashboards/api.py @@ -20,15 +20,15 @@ import logging from datetime import datetime from io import BytesIO -from typing import Any, Callable, Optional +from typing import Any, Callable, cast, Optional from zipfile import is_zipfile, ZipFile -from flask import g, make_response, redirect, request, Response, send_file, url_for +from flask import make_response, redirect, request, Response, send_file, url_for from flask_appbuilder import permission_name from flask_appbuilder.api import expose, protect, rison, safe from flask_appbuilder.hooks import before_request from flask_appbuilder.models.sqla.interface import SQLAInterface -from flask_babel import ngettext +from flask_babel import gettext, ngettext from marshmallow import ValidationError from werkzeug.wrappers import Response as WerkzeugResponse from werkzeug.wsgi import FileWrapper @@ -60,6 +60,7 @@ DashboardCertifiedFilter, DashboardCreatedByMeFilter, DashboardFavoriteFilter, + DashboardHasCreatedByFilter, DashboardTitleOrSlugFilter, FilterRelatedRoles, ) @@ -82,6 +83,7 @@ from superset.models.dashboard import Dashboard from superset.models.embedded_dashboard import EmbeddedDashboard from superset.tasks.thumbnails import cache_dashboard_thumbnail +from superset.tasks.utils import get_current_user from superset.utils.cache import etag_cache from superset.utils.screenshots import DashboardScreenshot from superset.utils.urls import get_url_path @@ -93,7 +95,11 @@ requires_json, statsd_metrics, ) -from superset.views.filters import FilterRelatedOwners +from superset.views.filters import ( + BaseFilterRelatedRoles, + BaseFilterRelatedUsers, + FilterRelatedOwners, +) logger = logging.getLogger(__name__) @@ -218,7 +224,7 @@ def ensure_thumbnails_enabled(self) -> Optional[Response]: search_filters = { "dashboard_title": [DashboardTitleOrSlugFilter], "id": [DashboardFavoriteFilter, DashboardCertifiedFilter], - "created_by": [DashboardCreatedByMeFilter], + "created_by": [DashboardCreatedByMeFilter, DashboardHasCreatedByFilter], } base_order = ("changed_on", "desc") @@ -239,6 +245,12 @@ def ensure_thumbnails_enabled(self) -> Optional[Response]: "owners": ("first_name", "asc"), "roles": ("name", "asc"), } + base_related_field_filters = { + "owners": [["id", BaseFilterRelatedUsers, lambda: []]], + "created_by": [["id", BaseFilterRelatedUsers, lambda: []]], + "roles": [["id", BaseFilterRelatedRoles, lambda: []]], + } + related_field_filters = { "owners": RelatedFieldFilter("first_name", FilterRelatedOwners), "roles": RelatedFieldFilter("name", FilterRelatedRoles), @@ -285,13 +297,14 @@ def __repr__(self) -> str: ) @safe @statsd_metrics - @event_logger.log_this_with_context( - action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.get", - log_to_statsd=False, - ) @with_dashboard - # pylint: disable=arguments-renamed, arguments-differ - def get(self, dash: Dashboard) -> Response: + @event_logger.log_this_with_extra_payload + # pylint: disable=arguments-differ + def get( + self, + dash: Dashboard, + add_extra_log_payload: Callable[..., None] = lambda **kwargs: None, + ) -> Response: """Gets a dashboard --- get: @@ -323,6 +336,9 @@ def get(self, dash: Dashboard) -> Response: $ref: '#/components/responses/404' """ result = self.dashboard_get_response_schema.dump(dash) + add_extra_log_payload( + dashboard_id=dash.id, action=f"{self.__class__.__name__}.get" + ) return self.response(200, result=result) @expose("/<id_or_slug>/datasets", methods=["GET"]) @@ -383,6 +399,12 @@ def get_datasets(self, id_or_slug: str) -> Response: self.dashboard_dataset_schema.dump(dataset) for dataset in datasets ] return self.response(200, result=result) + except (TypeError, ValueError) as err: + return self.response_400( + message=gettext( + "Dataset schema is invalid, caused by: %(error)s", error=str(err) + ) + ) except DashboardAccessDeniedError: return self.response_403() except DashboardNotFoundError: @@ -504,7 +526,7 @@ def post(self) -> Response: except ValidationError as error: return self.response_400(message=error.messages) try: - new_model = CreateDashboardCommand(g.user, item).run() + new_model = CreateDashboardCommand(item).run() return self.response(201, id=new_model.id, result=item) except DashboardInvalidError as ex: return self.response_422(message=ex.normalized_messages()) @@ -577,7 +599,7 @@ def put(self, pk: int) -> Response: except ValidationError as error: return self.response_400(message=error.messages) try: - changed_model = UpdateDashboardCommand(g.user, pk, item).run() + changed_model = UpdateDashboardCommand(pk, item).run() last_modified_time = changed_model.changed_on.replace( microsecond=0 ).timestamp() @@ -644,7 +666,7 @@ def delete(self, pk: int) -> Response: $ref: '#/components/responses/500' """ try: - DeleteDashboardCommand(g.user, pk).run() + DeleteDashboardCommand(pk).run() return self.response(200, message="OK") except DashboardNotFoundError: return self.response_404() @@ -704,7 +726,7 @@ def bulk_delete(self, **kwargs: Any) -> Response: """ item_ids = kwargs["rison"] try: - BulkDeleteDashboardCommand(g.user, item_ids).run() + BulkDeleteDashboardCommand(item_ids).run() return self.response( 200, message=ngettext( @@ -864,7 +886,7 @@ def thumbnail(self, pk: int, digest: str, **kwargs: Any) -> WerkzeugResponse: 500: $ref: '#/components/responses/500' """ - dashboard = self.datamodel.get(pk, self._base_filters) + dashboard = cast(Dashboard, self.datamodel.get(pk, self._base_filters)) if not dashboard: return self.response_404() @@ -872,8 +894,13 @@ def thumbnail(self, pk: int, digest: str, **kwargs: Any) -> WerkzeugResponse: "Superset.dashboard", dashboard_id_or_slug=dashboard.id ) # If force, request a screenshot from the workers + current_user = get_current_user() if kwargs["rison"].get("force", False): - cache_dashboard_thumbnail.delay(dashboard_url, dashboard.digest, force=True) + cache_dashboard_thumbnail.delay( + current_user=current_user, + dashboard_id=dashboard.id, + force=True, + ) return self.response(202, message="OK Async") # fetch the dashboard screenshot using the current user and cache if set screenshot = DashboardScreenshot( @@ -882,7 +909,11 @@ def thumbnail(self, pk: int, digest: str, **kwargs: Any) -> WerkzeugResponse: # If the screenshot does not exist, request one from the workers if not screenshot: self.incr_stats("async", self.thumbnail.__name__) - cache_dashboard_thumbnail.delay(dashboard_url, dashboard.digest, force=True) + cache_dashboard_thumbnail.delay( + current_user=current_user, + dashboard_id=dashboard.id, + force=True, + ) return self.response(202, message="OK Async") # If digests if dashboard.digest != digest: @@ -942,9 +973,8 @@ def favorite_status(self, **kwargs: Any) -> Response: dashboards = DashboardDAO.find_by_ids(requested_ids) if not dashboards: return self.response_404() - favorited_dashboard_ids = DashboardDAO.favorited_ids( - dashboards, g.user.get_id() - ) + + favorited_dashboard_ids = DashboardDAO.favorited_ids(dashboards) res = [ {"id": request_id, "value": request_id in favorited_dashboard_ids} for request_id in requested_ids diff --git a/superset/dashboards/commands/bulk_delete.py b/superset/dashboards/commands/bulk_delete.py index 958dea27d3915..52f5998438bcb 100644 --- a/superset/dashboards/commands/bulk_delete.py +++ b/superset/dashboards/commands/bulk_delete.py @@ -17,9 +17,9 @@ import logging from typing import List, Optional -from flask_appbuilder.security.sqla.models import User from flask_babel import lazy_gettext as _ +from superset import security_manager from superset.commands.base import BaseCommand from superset.commands.exceptions import DeleteFailedError from superset.dashboards.commands.exceptions import ( @@ -32,14 +32,12 @@ from superset.exceptions import SupersetSecurityException from superset.models.dashboard import Dashboard from superset.reports.dao import ReportScheduleDAO -from superset.views.base import check_ownership logger = logging.getLogger(__name__) class BulkDeleteDashboardCommand(BaseCommand): - def __init__(self, user: User, model_ids: List[int]): - self._actor = user + def __init__(self, model_ids: List[int]): self._model_ids = model_ids self._models: Optional[List[Dashboard]] = None @@ -67,6 +65,6 @@ def validate(self) -> None: # Check ownership for model in self._models: try: - check_ownership(model) + security_manager.raise_for_ownership(model) except SupersetSecurityException as ex: raise DashboardForbiddenError() from ex diff --git a/superset/dashboards/commands/create.py b/superset/dashboards/commands/create.py index 1e796bc318e49..811508c2e78fb 100644 --- a/superset/dashboards/commands/create.py +++ b/superset/dashboards/commands/create.py @@ -18,7 +18,6 @@ from typing import Any, Dict, List, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError from superset.commands.base import BaseCommand, CreateMixin @@ -35,8 +34,7 @@ class CreateDashboardCommand(CreateMixin, BaseCommand): - def __init__(self, user: User, data: Dict[str, Any]): - self._actor = user + def __init__(self, data: Dict[str, Any]): self._properties = data.copy() def run(self) -> Model: @@ -60,7 +58,7 @@ def validate(self) -> None: exceptions.append(DashboardSlugExistsValidationError()) try: - owners = self.populate_owners(self._actor, owner_ids) + owners = self.populate_owners(owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) diff --git a/superset/dashboards/commands/delete.py b/superset/dashboards/commands/delete.py index 67f683a1c1542..7af2fdf4ce03c 100644 --- a/superset/dashboards/commands/delete.py +++ b/superset/dashboards/commands/delete.py @@ -18,9 +18,9 @@ from typing import Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from flask_babel import lazy_gettext as _ +from superset import security_manager from superset.commands.base import BaseCommand from superset.dao.exceptions import DAODeleteFailedError from superset.dashboards.commands.exceptions import ( @@ -33,14 +33,12 @@ from superset.exceptions import SupersetSecurityException from superset.models.dashboard import Dashboard from superset.reports.dao import ReportScheduleDAO -from superset.views.base import check_ownership logger = logging.getLogger(__name__) class DeleteDashboardCommand(BaseCommand): - def __init__(self, user: User, model_id: int): - self._actor = user + def __init__(self, model_id: int): self._model_id = model_id self._model: Optional[Dashboard] = None @@ -67,6 +65,6 @@ def validate(self) -> None: ) # Check ownership try: - check_ownership(self._model) + security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise DashboardForbiddenError() from ex diff --git a/superset/dashboards/commands/export.py b/superset/dashboards/commands/export.py index 2d131d8f84e1c..c175556943874 100644 --- a/superset/dashboards/commands/export.py +++ b/superset/dashboards/commands/export.py @@ -23,7 +23,6 @@ from typing import Any, Dict, Iterator, Optional, Set, Tuple import yaml -from werkzeug.utils import secure_filename from superset.charts.commands.export import ExportChartsCommand from superset.dashboards.commands.exceptions import DashboardNotFoundError @@ -35,6 +34,7 @@ from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.utils.dict_import_export import EXPORT_VERSION +from superset.utils.file import get_filename logger = logging.getLogger(__name__) @@ -111,8 +111,8 @@ class ExportDashboardsCommand(ExportModelsCommand): def _export( model: Dashboard, export_related: bool = True ) -> Iterator[Tuple[str, str]]: - dashboard_slug = secure_filename(model.dashboard_title) - file_name = f"dashboards/{dashboard_slug}_{model.id}.yaml" + file_name = get_filename(model.dashboard_title, model.id) + file_path = f"dashboards/{file_name}.yaml" payload = model.export_to_dict( recursive=False, @@ -163,7 +163,7 @@ def _export( payload["version"] = EXPORT_VERSION file_content = yaml.safe_dump(payload, sort_keys=False) - yield file_name, file_content + yield file_path, file_content if export_related: chart_ids = [chart.id for chart in model.slices] diff --git a/superset/dashboards/commands/importers/v0.py b/superset/dashboards/commands/importers/v0.py index 207920b1d2c2a..e49c931896838 100644 --- a/superset/dashboards/commands/importers/v0.py +++ b/superset/dashboards/commands/importers/v0.py @@ -24,7 +24,7 @@ from flask_babel import lazy_gettext as _ from sqlalchemy.orm import make_transient, Session -from superset import ConnectorRegistry, db +from superset import db from superset.commands.base import BaseCommand from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn from superset.datasets.commands.importers.v0 import import_dataset @@ -63,12 +63,11 @@ def import_chart( slc_to_import = slc_to_import.copy() slc_to_import.reset_ownership() params = slc_to_import.params_dict - datasource = ConnectorRegistry.get_datasource_by_name( - session, - slc_to_import.datasource_type, - params["datasource_name"], - params["schema"], - params["database_name"], + datasource = SqlaTable.get_datasource_by_name( + session=session, + datasource_name=params["datasource_name"], + database_name=params["database_name"], + schema=params["schema"], ) slc_to_import.datasource_id = datasource.id # type: ignore if slc_to_override: diff --git a/superset/dashboards/commands/importers/v1/__init__.py b/superset/dashboards/commands/importers/v1/__init__.py index 1720e01ab8bcc..83d26fc7e7359 100644 --- a/superset/dashboards/commands/importers/v1/__init__.py +++ b/superset/dashboards/commands/importers/v1/__init__.py @@ -139,5 +139,4 @@ def _import( {"dashboard_id": dashboard_id, "slice_id": chart_id} for (dashboard_id, chart_id) in dashboard_chart_ids ] - # pylint: disable=no-value-for-parameter # sqlalchemy/issues/4656 session.execute(dashboard_slices.insert(), values) diff --git a/superset/dashboards/commands/update.py b/superset/dashboards/commands/update.py index 2065437cc3b31..12ac241dccc22 100644 --- a/superset/dashboards/commands/update.py +++ b/superset/dashboards/commands/update.py @@ -19,9 +19,9 @@ from typing import Any, Dict, List, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError +from superset import security_manager from superset.commands.base import BaseCommand, UpdateMixin from superset.commands.utils import populate_roles from superset.dao.exceptions import DAOUpdateFailedError @@ -36,14 +36,12 @@ from superset.exceptions import SupersetSecurityException from superset.extensions import db from superset.models.dashboard import Dashboard -from superset.views.base import check_ownership logger = logging.getLogger(__name__) class UpdateDashboardCommand(UpdateMixin, BaseCommand): - def __init__(self, user: User, model_id: int, data: Dict[str, Any]): - self._actor = user + def __init__(self, model_id: int, data: Dict[str, Any]): self._model_id = model_id self._properties = data.copy() self._model: Optional[Dashboard] = None @@ -52,13 +50,13 @@ def run(self) -> Model: self.validate() try: dashboard = DashboardDAO.update(self._model, self._properties, commit=False) - dashboard = DashboardDAO.update_charts_owners(dashboard, commit=False) if self._properties.get("json_metadata"): dashboard = DashboardDAO.set_dash_metadata( dashboard, data=json.loads(self._properties.get("json_metadata", "{}")), commit=False, ) + dashboard = DashboardDAO.update_charts_owners(dashboard, commit=False) db.session.commit() except DAOUpdateFailedError as ex: logger.exception(ex.exception) @@ -77,7 +75,7 @@ def validate(self) -> None: raise DashboardNotFoundError() # Check ownership try: - check_ownership(self._model) + security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise DashboardForbiddenError() from ex @@ -89,7 +87,7 @@ def validate(self) -> None: if owners_ids is None: owners_ids = [owner.id for owner in self._model.owners] try: - owners = self.populate_owners(self._actor, owners_ids) + owners = self.populate_owners(owners_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) diff --git a/superset/dashboards/dao.py b/superset/dashboards/dao.py index ce6e30f8d4beb..3f0666266f9c8 100644 --- a/superset/dashboards/dao.py +++ b/superset/dashboards/dao.py @@ -19,16 +19,17 @@ from datetime import datetime from typing import Any, Dict, List, Optional, Union +from flask_appbuilder.models.sqla.interface import SQLAInterface from sqlalchemy.exc import SQLAlchemyError -from superset import security_manager from superset.dao.base import BaseDAO from superset.dashboards.commands.exceptions import DashboardNotFoundError from superset.dashboards.filters import DashboardAccessFilter from superset.extensions import db from superset.models.core import FavStar, FavStarClassName -from superset.models.dashboard import Dashboard +from superset.models.dashboard import Dashboard, id_or_slug_filter from superset.models.slice import Slice +from superset.utils.core import get_user_id from superset.utils.dashboard_filter_scopes_converter import copy_filter_scopes logger = logging.getLogger(__name__) @@ -39,11 +40,22 @@ class DashboardDAO(BaseDAO): base_filter = DashboardAccessFilter @staticmethod - def get_by_id_or_slug(id_or_slug: str) -> Dashboard: - dashboard = Dashboard.get(id_or_slug) + def get_by_id_or_slug(id_or_slug: Union[int, str]) -> Dashboard: + query = ( + db.session.query(Dashboard) + .filter(id_or_slug_filter(id_or_slug)) + .outerjoin(Slice, Dashboard.slices) + .outerjoin(Slice.table) + .outerjoin(Dashboard.owners) + .outerjoin(Dashboard.roles) + ) + # Apply dashboard base filters + query = DashboardAccessFilter("id", SQLAInterface(Dashboard, db.session)).apply( + query, None + ) + dashboard = query.one_or_none() if not dashboard: raise DashboardNotFoundError() - security_manager.raise_for_dashboard_access(dashboard) return dashboard @staticmethod @@ -66,7 +78,7 @@ def get_dashboard_changed_on( :returns: The datetime the dashboard was last changed. """ - dashboard = ( + dashboard: Dashboard = ( DashboardDAO.get_by_id_or_slug(id_or_slug_or_dashboard) if isinstance(id_or_slug_or_dashboard, str) else id_or_slug_or_dashboard @@ -159,6 +171,7 @@ def bulk_delete(models: Optional[List[Dashboard]], commit: bool = True) -> None: for model in models: model.slices = [] model.owners = [] + model.embedded = [] db.session.merge(model) # bulk delete itself try: @@ -168,8 +181,7 @@ def bulk_delete(models: Optional[List[Dashboard]], commit: bool = True) -> None: if commit: db.session.commit() except SQLAlchemyError as ex: - if commit: - db.session.rollback() + db.session.rollback() raise ex @staticmethod @@ -266,7 +278,8 @@ def set_dash_metadata( # pylint: disable=too-many-locals md["color_scheme"] = data.get("color_scheme", "") md["label_colors"] = data.get("label_colors", {}) md["shared_label_colors"] = data.get("shared_label_colors", {}) - + md["color_scheme_domain"] = data.get("color_scheme_domain", []) + md["cross_filters_enabled"] = data.get("cross_filters_enabled", True) dashboard.json_metadata = json.dumps(md) if commit: @@ -274,9 +287,7 @@ def set_dash_metadata( # pylint: disable=too-many-locals return dashboard @staticmethod - def favorited_ids( - dashboards: List[Dashboard], current_user_id: int - ) -> List[FavStar]: + def favorited_ids(dashboards: List[Dashboard]) -> List[FavStar]: ids = [dash.id for dash in dashboards] return [ star.obj_id @@ -284,7 +295,7 @@ def favorited_ids( .filter( FavStar.class_name == FavStarClassName.DASHBOARD, FavStar.obj_id.in_(ids), - FavStar.user_id == current_user_id, + FavStar.user_id == get_user_id(), ) .all() ] diff --git a/superset/dashboards/filter_sets/api.py b/superset/dashboards/filter_sets/api.py index 3dc2a28de260c..109ae73f0782b 100644 --- a/superset/dashboards/filter_sets/api.py +++ b/superset/dashboards/filter_sets/api.py @@ -17,7 +17,7 @@ import logging from typing import Any, cast -from flask import g, request, Response +from flask import request, Response from flask_appbuilder.api import ( expose, get_list_schema, @@ -243,7 +243,7 @@ def post(self, dashboard_id: int) -> Response: """ try: item = self.add_model_schema.load(request.json) - new_model = CreateFilterSetCommand(g.user, dashboard_id, item).run() + new_model = CreateFilterSetCommand(dashboard_id, item).run() return self.response( 201, **self.show_model_schema.dump(new_model, many=False) ) @@ -314,7 +314,7 @@ def put(self, dashboard_id: int, pk: int) -> Response: """ try: item = self.edit_model_schema.load(request.json) - changed_model = UpdateFilterSetCommand(g.user, dashboard_id, pk, item).run() + changed_model = UpdateFilterSetCommand(dashboard_id, pk, item).run() return self.response( 200, **self.show_model_schema.dump(changed_model, many=False) ) @@ -374,7 +374,7 @@ def delete(self, dashboard_id: int, pk: int) -> Response: $ref: '#/components/responses/500' """ try: - changed_model = DeleteFilterSetCommand(g.user, dashboard_id, pk).run() + changed_model = DeleteFilterSetCommand(dashboard_id, pk).run() return self.response(200, id=changed_model.id) except ValidationError as error: return self.response_400(message=error.messages) diff --git a/superset/dashboards/filter_sets/commands/base.py b/superset/dashboards/filter_sets/commands/base.py index 0e902e5e687ca..e6a4b03e3faa0 100644 --- a/superset/dashboards/filter_sets/commands/base.py +++ b/superset/dashboards/filter_sets/commands/base.py @@ -18,10 +18,9 @@ from typing import cast, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User +from superset import security_manager from superset.common.not_authrized_object import NotAuthorizedException -from superset.common.request_contexed_based import is_user_admin from superset.dashboards.commands.exceptions import DashboardNotFoundError from superset.dashboards.dao import DashboardDAO from superset.dashboards.filter_sets.commands.exceptions import ( @@ -31,6 +30,7 @@ from superset.dashboards.filter_sets.consts import USER_OWNER_TYPE from superset.models.dashboard import Dashboard from superset.models.filter_set import FilterSet +from superset.utils.core import get_user_id logger = logging.getLogger(__name__) @@ -41,9 +41,7 @@ class BaseFilterSetCommand: _filter_set_id: Optional[int] _filter_set: Optional[FilterSet] - def __init__(self, user: User, dashboard_id: int): - self._actor = user - self._is_actor_admin = is_user_admin() + def __init__(self, dashboard_id: int): self._dashboard_id = dashboard_id def run(self) -> Model: @@ -54,9 +52,6 @@ def _validate_filterset_dashboard_exists(self) -> None: if not self._dashboard: raise DashboardNotFoundError() - def is_user_dashboard_owner(self) -> bool: - return self._is_actor_admin or self._dashboard.is_actor_owner() - def validate_exist_filter_use_cases_set(self) -> None: # pylint: disable=C0103 self._validate_filter_set_exists_and_set_when_exists() self.check_ownership() @@ -70,15 +65,15 @@ def _validate_filter_set_exists_and_set_when_exists(self) -> None: def check_ownership(self) -> None: try: - if not self._is_actor_admin: + if not security_manager.is_admin(): filter_set: FilterSet = cast(FilterSet, self._filter_set) if filter_set.owner_type == USER_OWNER_TYPE: - if self._actor.id != filter_set.owner_id: + if get_user_id() != filter_set.owner_id: raise FilterSetForbiddenError( str(self._filter_set_id), "The user is not the owner of the filter_set", ) - elif not self.is_user_dashboard_owner(): + elif not security_manager.is_owner(self._dashboard): raise FilterSetForbiddenError( str(self._filter_set_id), "The user is not an owner of the filter_set's dashboard", diff --git a/superset/dashboards/filter_sets/commands/create.py b/superset/dashboards/filter_sets/commands/create.py index b74e6d3041628..de1d70daf7879 100644 --- a/superset/dashboards/filter_sets/commands/create.py +++ b/superset/dashboards/filter_sets/commands/create.py @@ -17,9 +17,7 @@ import logging from typing import Any, Dict -from flask import g from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from superset import security_manager from superset.dashboards.filter_sets.commands.base import BaseFilterSetCommand @@ -35,14 +33,15 @@ OWNER_TYPE_FIELD, ) from superset.dashboards.filter_sets.dao import FilterSetDAO +from superset.utils.core import get_user_id logger = logging.getLogger(__name__) class CreateFilterSetCommand(BaseFilterSetCommand): # pylint: disable=C0103 - def __init__(self, user: User, dashboard_id: int, data: Dict[str, Any]): - super().__init__(user, dashboard_id) + def __init__(self, dashboard_id: int, data: Dict[str, Any]): + super().__init__(dashboard_id) self._properties = data.copy() def run(self) -> Model: @@ -61,13 +60,13 @@ def validate(self) -> None: def _validate_owner_id_exists(self) -> None: owner_id = self._properties[OWNER_ID_FIELD] - if not (g.user.id == owner_id or security_manager.get_user_by_id(owner_id)): + if not (get_user_id() == owner_id or security_manager.get_user_by_id(owner_id)): raise FilterSetCreateFailedError( str(self._dashboard_id), "owner_id does not exists" ) def _validate_user_is_the_dashboard_owner(self) -> None: - if not self.is_user_dashboard_owner(): + if not security_manager.is_owner(self._dashboard): raise UserIsNotDashboardOwnerError(str(self._dashboard_id)) def _validate_owner_id_is_dashboard_id(self) -> None: diff --git a/superset/dashboards/filter_sets/commands/delete.py b/superset/dashboards/filter_sets/commands/delete.py index 18d7fed8f2bb8..c416252794e8a 100644 --- a/superset/dashboards/filter_sets/commands/delete.py +++ b/superset/dashboards/filter_sets/commands/delete.py @@ -17,7 +17,6 @@ import logging from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from superset.dao.exceptions import DAODeleteFailedError from superset.dashboards.filter_sets.commands.base import BaseFilterSetCommand @@ -32,8 +31,8 @@ class DeleteFilterSetCommand(BaseFilterSetCommand): - def __init__(self, user: User, dashboard_id: int, filter_set_id: int): - super().__init__(user, dashboard_id) + def __init__(self, dashboard_id: int, filter_set_id: int): + super().__init__(dashboard_id) self._filter_set_id = filter_set_id def run(self) -> Model: diff --git a/superset/dashboards/filter_sets/commands/update.py b/superset/dashboards/filter_sets/commands/update.py index d2c43f085212b..07d59f93aee23 100644 --- a/superset/dashboards/filter_sets/commands/update.py +++ b/superset/dashboards/filter_sets/commands/update.py @@ -18,7 +18,6 @@ from typing import Any, Dict from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from superset.dao.exceptions import DAOUpdateFailedError from superset.dashboards.filter_sets.commands.base import BaseFilterSetCommand @@ -32,10 +31,8 @@ class UpdateFilterSetCommand(BaseFilterSetCommand): - def __init__( - self, user: User, dashboard_id: int, filter_set_id: int, data: Dict[str, Any] - ): - super().__init__(user, dashboard_id) + def __init__(self, dashboard_id: int, filter_set_id: int, data: Dict[str, Any]): + super().__init__(dashboard_id) self._filter_set_id = filter_set_id self._properties = data.copy() diff --git a/superset/dashboards/filter_sets/filters.py b/superset/dashboards/filter_sets/filters.py index 0083f40d1a578..3578e8b0b48af 100644 --- a/superset/dashboards/filter_sets/filters.py +++ b/superset/dashboards/filter_sets/filters.py @@ -18,13 +18,14 @@ from typing import Any, TYPE_CHECKING -from flask import g from sqlalchemy import and_, or_ +from superset import security_manager from superset.dashboards.filter_sets.consts import DASHBOARD_OWNER_TYPE, USER_OWNER_TYPE from superset.models.dashboard import dashboard_user from superset.models.filter_set import FilterSet -from superset.views.base import BaseFilter, is_user_admin +from superset.utils.core import get_user_id +from superset.views.base import BaseFilter if TYPE_CHECKING: from sqlalchemy.orm.query import Query @@ -32,9 +33,8 @@ class FilterSetFilter(BaseFilter): # pylint: disable=too-few-public-methods) def apply(self, query: Query, value: Any) -> Query: - if is_user_admin(): + if security_manager.is_admin(): return query - current_user_id = g.user.id filter_set_ids_by_dashboard_owners = ( # pylint: disable=C0103 query.from_self(FilterSet.id) @@ -42,7 +42,7 @@ def apply(self, query: Query, value: Any) -> Query: .filter( and_( FilterSet.owner_type == DASHBOARD_OWNER_TYPE, - dashboard_user.c.user_id == current_user_id, + dashboard_user.c.user_id == get_user_id(), ) ) ) @@ -51,7 +51,7 @@ def apply(self, query: Query, value: Any) -> Query: or_( and_( FilterSet.owner_type == USER_OWNER_TYPE, - FilterSet.owner_id == current_user_id, + FilterSet.owner_id == get_user_id(), ), FilterSet.id.in_(filter_set_ids_by_dashboard_owners), ) diff --git a/superset/dashboards/filter_state/commands/create.py b/superset/dashboards/filter_state/commands/create.py index 18dff8928fe83..48b5e4f5c2d2e 100644 --- a/superset/dashboards/filter_state/commands/create.py +++ b/superset/dashboards/filter_state/commands/create.py @@ -20,17 +20,17 @@ from superset.dashboards.filter_state.commands.utils import check_access from superset.extensions import cache_manager -from superset.key_value.utils import get_owner, random_key +from superset.key_value.utils import random_key from superset.temporary_cache.commands.create import CreateTemporaryCacheCommand from superset.temporary_cache.commands.entry import Entry from superset.temporary_cache.commands.parameters import CommandParameters from superset.temporary_cache.utils import cache_key +from superset.utils.core import get_user_id class CreateFilterStateCommand(CreateTemporaryCacheCommand): def create(self, cmd_params: CommandParameters) -> str: resource_id = cmd_params.resource_id - actor = cmd_params.actor tab_id = cmd_params.tab_id contextual_key = cache_key(session.get("_id"), tab_id, resource_id) key = cache_manager.filter_state_cache.get(contextual_key) @@ -38,7 +38,7 @@ def create(self, cmd_params: CommandParameters) -> str: key = random_key() value = cast(str, cmd_params.value) # schema ensures that value is not optional check_access(resource_id) - entry: Entry = {"owner": get_owner(actor), "value": value} + entry: Entry = {"owner": get_user_id(), "value": value} cache_manager.filter_state_cache.set(cache_key(resource_id, key), entry) cache_manager.filter_state_cache.set(contextual_key, key) return key diff --git a/superset/dashboards/filter_state/commands/delete.py b/superset/dashboards/filter_state/commands/delete.py index 3ddc08fc51900..6086388a8ce44 100644 --- a/superset/dashboards/filter_state/commands/delete.py +++ b/superset/dashboards/filter_state/commands/delete.py @@ -18,23 +18,22 @@ from superset.dashboards.filter_state.commands.utils import check_access from superset.extensions import cache_manager -from superset.key_value.utils import get_owner from superset.temporary_cache.commands.delete import DeleteTemporaryCacheCommand from superset.temporary_cache.commands.entry import Entry from superset.temporary_cache.commands.exceptions import TemporaryCacheAccessDeniedError from superset.temporary_cache.commands.parameters import CommandParameters from superset.temporary_cache.utils import cache_key +from superset.utils.core import get_user_id class DeleteFilterStateCommand(DeleteTemporaryCacheCommand): def delete(self, cmd_params: CommandParameters) -> bool: resource_id = cmd_params.resource_id - actor = cmd_params.actor key = cache_key(resource_id, cmd_params.key) check_access(resource_id) entry: Entry = cache_manager.filter_state_cache.get(key) if entry: - if entry["owner"] != get_owner(actor): + if entry["owner"] != get_user_id(): raise TemporaryCacheAccessDeniedError() tab_id = cmd_params.tab_id contextual_key = cache_key(session.get("_id"), tab_id, resource_id) diff --git a/superset/dashboards/filter_state/commands/update.py b/superset/dashboards/filter_state/commands/update.py index 7f150aae6bae3..c1dc529ccff58 100644 --- a/superset/dashboards/filter_state/commands/update.py +++ b/superset/dashboards/filter_state/commands/update.py @@ -20,23 +20,23 @@ from superset.dashboards.filter_state.commands.utils import check_access from superset.extensions import cache_manager -from superset.key_value.utils import get_owner, random_key +from superset.key_value.utils import random_key from superset.temporary_cache.commands.entry import Entry from superset.temporary_cache.commands.exceptions import TemporaryCacheAccessDeniedError from superset.temporary_cache.commands.parameters import CommandParameters from superset.temporary_cache.commands.update import UpdateTemporaryCacheCommand from superset.temporary_cache.utils import cache_key +from superset.utils.core import get_user_id class UpdateFilterStateCommand(UpdateTemporaryCacheCommand): def update(self, cmd_params: CommandParameters) -> Optional[str]: resource_id = cmd_params.resource_id - actor = cmd_params.actor key = cmd_params.key value = cast(str, cmd_params.value) # schema ensures that value is not optional check_access(resource_id) entry: Entry = cache_manager.filter_state_cache.get(cache_key(resource_id, key)) - owner = get_owner(actor) + owner = get_user_id() if entry: if entry["owner"] != owner: raise TemporaryCacheAccessDeniedError() diff --git a/superset/dashboards/filters.py b/superset/dashboards/filters.py index 7b02c23679540..e09609ff511e0 100644 --- a/superset/dashboards/filters.py +++ b/superset/dashboards/filters.py @@ -29,7 +29,8 @@ from superset.models.embedded_dashboard import EmbeddedDashboard from superset.models.slice import Slice from superset.security.guest_token import GuestTokenResourceType, GuestUser -from superset.views.base import BaseFilter, is_user_admin +from superset.utils.core import get_user_id +from superset.views.base import BaseFilter from superset.views.base_api import BaseFavoriteFilter @@ -51,15 +52,15 @@ def apply(self, query: Query, value: Any) -> Query: class DashboardCreatedByMeFilter(BaseFilter): # pylint: disable=too-few-public-methods name = _("Created by me") - arg_name = "created_by_me" + arg_name = "dashboard_created_by_me" def apply(self, query: Query, value: Any) -> Query: return query.filter( or_( Dashboard.created_by_fk # pylint: disable=comparison-with-callable - == g.user.get_user_id(), + == get_user_id(), Dashboard.changed_by_fk # pylint: disable=comparison-with-callable - == g.user.get_user_id(), + == get_user_id(), ) ) @@ -97,7 +98,7 @@ class DashboardAccessFilter(BaseFilter): # pylint: disable=too-few-public-metho """ def apply(self, query: Query, value: Any) -> Query: - if is_user_admin(): + if security_manager.is_admin(): return query datasource_perms = security_manager.user_view_menu_names("datasource_access") @@ -110,7 +111,7 @@ def apply(self, query: Query, value: Any) -> Query: datasource_perm_query = ( db.session.query(Dashboard.id) - .join(Dashboard.slices) + .join(Dashboard.slices, isouter=True) .filter( and_( Dashboard.published.is_(True), @@ -126,17 +127,14 @@ def apply(self, query: Query, value: Any) -> Query: users_favorite_dash_query = db.session.query(FavStar.obj_id).filter( and_( - FavStar.user_id == security_manager.user_model.get_user_id(), + FavStar.user_id == get_user_id(), FavStar.class_name == "Dashboard", ) ) owner_ids_query = ( db.session.query(Dashboard.id) .join(Dashboard.owners) - .filter( - security_manager.user_model.id - == security_manager.user_model.get_user_id() - ) + .filter(security_manager.user_model.id == get_user_id()) ) feature_flagged_filters = [] @@ -158,7 +156,6 @@ def apply(self, query: Query, value: Any) -> Query: if is_feature_enabled("EMBEDDED_SUPERSET") and security_manager.is_guest_user( g.user ): - guest_user: GuestUser = g.user embedded_dashboard_ids = [ r["id"] @@ -235,3 +232,19 @@ def apply(self, query: Query, value: Any) -> Query: ) ) return query + + +class DashboardHasCreatedByFilter(BaseFilter): # pylint: disable=too-few-public-methods + """ + Custom filter for the GET list that filters all dashboards created by user + """ + + name = _("Has created by") + arg_name = "dashboard_has_created_by" + + def apply(self, query: Query, value: Any) -> Query: + if value is True: + return query.filter(and_(Dashboard.created_by_fk.isnot(None))) + if value is False: + return query.filter(and_(Dashboard.created_by_fk.is_(None))) + return query diff --git a/superset/dashboards/permalink/api.py b/superset/dashboards/permalink/api.py index ca536af8f7400..a8664f0ddd80b 100644 --- a/superset/dashboards/permalink/api.py +++ b/superset/dashboards/permalink/api.py @@ -16,11 +16,11 @@ # under the License. import logging -from flask import g, request, Response -from flask_appbuilder.api import BaseApi, expose, protect, safe +from flask import request, Response +from flask_appbuilder.api import expose, protect, safe from marshmallow import ValidationError -from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod +from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP from superset.dashboards.commands.exceptions import ( DashboardAccessDeniedError, DashboardNotFoundError, @@ -33,20 +33,14 @@ from superset.dashboards.permalink.schemas import DashboardPermalinkPostSchema from superset.extensions import event_logger from superset.key_value.exceptions import KeyValueAccessDeniedError -from superset.views.base_api import requires_json +from superset.views.base_api import BaseSupersetApi, requires_json logger = logging.getLogger(__name__) -class DashboardPermalinkRestApi(BaseApi): +class DashboardPermalinkRestApi(BaseSupersetApi): add_model_schema = DashboardPermalinkPostSchema() method_permission_name = MODEL_API_RW_METHOD_PERMISSION_MAP - include_route_methods = { - RouteMethod.POST, - RouteMethod.PUT, - RouteMethod.GET, - RouteMethod.DELETE, - } allow_browser_login = True class_permission_name = "DashboardPermalinkRestApi" resource_name = "dashboard" @@ -104,7 +98,6 @@ def post(self, pk: str) -> Response: try: state = self.add_model_schema.load(request.json) key = CreateDashboardPermalinkCommand( - actor=g.user, dashboard_id=pk, state=state, ).run() @@ -162,7 +155,7 @@ def get(self, key: str) -> Response: $ref: '#/components/responses/500' """ try: - value = GetDashboardPermalinkCommand(actor=g.user, key=key).run() + value = GetDashboardPermalinkCommand(key=key).run() if not value: return self.response_404() return self.response(200, **value) diff --git a/superset/dashboards/permalink/commands/create.py b/superset/dashboards/permalink/commands/create.py index 4ffd41104ea08..51dac2d5dee77 100644 --- a/superset/dashboards/permalink/commands/create.py +++ b/superset/dashboards/permalink/commands/create.py @@ -16,27 +16,32 @@ # under the License. import logging -from flask_appbuilder.security.sqla.models import User from sqlalchemy.exc import SQLAlchemyError from superset.dashboards.dao import DashboardDAO from superset.dashboards.permalink.commands.base import BaseDashboardPermalinkCommand from superset.dashboards.permalink.exceptions import DashboardPermalinkCreateFailedError from superset.dashboards.permalink.types import DashboardPermalinkState -from superset.key_value.commands.create import CreateKeyValueCommand -from superset.key_value.utils import encode_permalink_key +from superset.key_value.commands.upsert import UpsertKeyValueCommand +from superset.key_value.utils import encode_permalink_key, get_deterministic_uuid +from superset.utils.core import get_user_id logger = logging.getLogger(__name__) class CreateDashboardPermalinkCommand(BaseDashboardPermalinkCommand): + """ + Get or create a permalink key for the dashboard. + + The same dashboard_id and state for the same user will return the + same permalink. + """ + def __init__( self, - actor: User, dashboard_id: str, state: DashboardPermalinkState, ): - self.actor = actor self.dashboard_id = dashboard_id self.state = state @@ -48,13 +53,13 @@ def run(self) -> str: "dashboardId": self.dashboard_id, "state": self.state, } - key = CreateKeyValueCommand( - actor=self.actor, + user_id = get_user_id() + key = UpsertKeyValueCommand( resource=self.resource, + key=get_deterministic_uuid(self.salt, (user_id, value)), value=value, ).run() - if key.id is None: - raise DashboardPermalinkCreateFailedError("Unexpected missing key id") + assert key.id # for type checks return encode_permalink_key(key=key.id, salt=self.salt) except SQLAlchemyError as ex: logger.exception("Error running create command") diff --git a/superset/dashboards/permalink/commands/get.py b/superset/dashboards/permalink/commands/get.py index 24bf77834a60c..f89f9444e7a4e 100644 --- a/superset/dashboards/permalink/commands/get.py +++ b/superset/dashboards/permalink/commands/get.py @@ -17,7 +17,6 @@ import logging from typing import Optional -from flask_appbuilder.security.sqla.models import User from sqlalchemy.exc import SQLAlchemyError from superset.dashboards.commands.exceptions import DashboardNotFoundError @@ -33,8 +32,7 @@ class GetDashboardPermalinkCommand(BaseDashboardPermalinkCommand): - def __init__(self, actor: User, key: str): - self.actor = actor + def __init__(self, key: str): self.key = key def run(self) -> Optional[DashboardPermalinkValue]: diff --git a/superset/dashboards/permalink/schemas.py b/superset/dashboards/permalink/schemas.py index a0fc1cbc5598f..ce222d7ed62c8 100644 --- a/superset/dashboards/permalink/schemas.py +++ b/superset/dashboards/permalink/schemas.py @@ -18,10 +18,16 @@ class DashboardPermalinkPostSchema(Schema): - filterState = fields.Dict( + dataMask = fields.Dict( required=False, allow_none=True, - description="Native filter state", + description="Data mask used for native filter state", + ) + activeTabs = fields.List( + fields.String(), + required=False, + allow_none=True, + description="Current active dashboard tabs", ) urlParams = fields.List( fields.Tuple( @@ -37,6 +43,8 @@ class DashboardPermalinkPostSchema(Schema): allow_none=True, description="URL Parameters", ) - hash = fields.String( - required=False, allow_none=True, description="Optional anchor link" + anchor = fields.String( + required=False, + allow_none=True, + description="Optional anchor link added to url hash", ) diff --git a/superset/dashboards/permalink/types.py b/superset/dashboards/permalink/types.py index e93076ba23785..91c5a9620cf71 100644 --- a/superset/dashboards/permalink/types.py +++ b/superset/dashboards/permalink/types.py @@ -18,8 +18,9 @@ class DashboardPermalinkState(TypedDict): - filterState: Optional[Dict[str, Any]] - hash: Optional[str] + dataMask: Optional[Dict[str, Any]] + activeTabs: Optional[List[str]] + anchor: Optional[str] urlParams: Optional[List[Tuple[str, str]]] diff --git a/superset/dashboards/schemas.py b/superset/dashboards/schemas.py index d91879f0d88b3..f0d05445aae77 100644 --- a/superset/dashboards/schemas.py +++ b/superset/dashboards/schemas.py @@ -129,9 +129,12 @@ class DashboardJSONMetadataSchema(Schema): positions = fields.Dict(allow_none=True) label_colors = fields.Dict() shared_label_colors = fields.Dict() + color_scheme_domain = fields.List(fields.Str()) + cross_filters_enabled = fields.Boolean(default=True) # used for v0 import/export import_time = fields.Integer() remote_id = fields.Integer() + filter_bar_orientation = fields.Str(allow_none=True) class UserSchema(Schema): @@ -173,7 +176,6 @@ class DatabaseSchema(Schema): id = fields.Int() name = fields.String() backend = fields.String() - allow_multi_schema_metadata_fetch = fields.Bool() # pylint: disable=invalid-name allows_subquery = fields.Bool() allows_cost_estimate = fields.Bool() allows_virtual_table_explore = fields.Bool() @@ -206,7 +208,7 @@ class DashboardDatasetSchema(Schema): health_check_message = fields.Str() fetch_values_predicate = fields.Str() template_params = fields.Str() - owners = fields.List(fields.Int()) + owners = fields.List(fields.Dict()) columns = fields.List(fields.Dict()) column_types = fields.List(fields.Int()) metrics = fields.List(fields.Dict()) diff --git a/superset/databases/api.py b/superset/databases/api.py index b9fe4ca3d7e36..c28519874747f 100644 --- a/superset/databases/api.py +++ b/superset/databases/api.py @@ -19,10 +19,10 @@ import logging from datetime import datetime from io import BytesIO -from typing import Any, Dict, List, Optional +from typing import Any, cast, Dict, List, Optional from zipfile import is_zipfile, ZipFile -from flask import g, request, Response, send_file +from flask import request, Response, send_file from flask_appbuilder.api import expose, protect, rison, safe from flask_appbuilder.models.sqla.interface import SQLAInterface from marshmallow import ValidationError @@ -44,11 +44,13 @@ DatabaseDeleteFailedError, DatabaseInvalidError, DatabaseNotFoundError, + DatabaseTablesUnexpectedError, DatabaseUpdateFailedError, InvalidParametersError, ) from superset.databases.commands.export import ExportDatabasesCommand from superset.databases.commands.importers.dispatcher import ImportDatabasesCommand +from superset.databases.commands.tables import TablesDatabaseCommand from superset.databases.commands.test_connection import TestConnectionDatabaseCommand from superset.databases.commands.update import UpdateDatabaseCommand from superset.databases.commands.validate import ValidateDatabaseParametersCommand @@ -58,10 +60,12 @@ from superset.databases.filters import DatabaseFilter, DatabaseUploadEnabledFilter from superset.databases.schemas import ( database_schemas_query_schema, + database_tables_query_schema, DatabaseFunctionNamesResponse, DatabasePostSchema, DatabasePutSchema, DatabaseRelatedObjectsResponse, + DatabaseTablesResponse, DatabaseTestConnectionSchema, DatabaseValidateParametersSchema, get_export_ids_schema, @@ -72,13 +76,22 @@ ValidateSQLRequest, ValidateSQLResponse, ) +from superset.databases.ssh_tunnel.commands.delete import DeleteSSHTunnelCommand +from superset.databases.ssh_tunnel.commands.exceptions import ( + SSHTunnelDeleteFailedError, + SSHTunnelingNotEnabledError, + SSHTunnelNotFoundError, +) from superset.databases.utils import get_table_metadata from superset.db_engine_specs import get_available_engine_specs from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.exceptions import SupersetErrorsException, SupersetException from superset.extensions import security_manager from superset.models.core import Database from superset.superset_typing import FlaskResponse from superset.utils.core import error_msg_from_exception, parse_js_uri_path_item +from superset.utils.ssh_tunnel import mask_password_info +from superset.views.base import json_errors_response from superset.views.base_api import ( BaseSupersetModelRestApi, requires_form_data, @@ -95,6 +108,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi): include_route_methods = RouteMethod.REST_MODEL_VIEW_CRUD_SET | { RouteMethod.EXPORT, RouteMethod.IMPORT, + "tables", "table_metadata", "table_extra_metadata", "select_star", @@ -105,6 +119,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi): "available", "validate_parameters", "validate_sql", + "delete_ssh_tunnel", } resource_name = "database" class_permission_name = "Database" @@ -113,6 +128,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi): base_filters = [["id", DatabaseFilter, lambda: []]] show_columns = [ "id", + "uuid", "database_name", "cache_timeout", "expose_in_sqllab", @@ -123,23 +139,23 @@ class DatabaseRestApi(BaseSupersetModelRestApi): "allow_cvas", "allow_dml", "backend", + "driver", "force_ctas_schema", - "allow_multi_schema_metadata_fetch", "impersonate_user", - "encrypted_extra", + "masked_encrypted_extra", "extra", "parameters", "parameters_schema", "server_cert", "sqlalchemy_uri", "is_managed_externally", + "engine_information", ] list_columns = [ "allow_file_upload", "allow_ctas", "allow_cvas", "allow_dml", - "allow_multi_schema_metadata_fetch", "allow_run_async", "allows_cost_estimate", "allows_subquery", @@ -155,7 +171,9 @@ class DatabaseRestApi(BaseSupersetModelRestApi): "extra", "force_ctas_schema", "id", + "uuid", "disable_data_preview", + "engine_information", ] add_columns = [ "database_name", @@ -170,7 +188,6 @@ class DatabaseRestApi(BaseSupersetModelRestApi): "configuration_method", "force_ctas_schema", "impersonate_user", - "allow_multi_schema_metadata_fetch", "extra", "encrypted_extra", "server_cert", @@ -198,6 +215,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi): apispec_parameter_schemas = { "database_schemas_query_schema": database_schemas_query_schema, + "database_tables_query_schema": database_tables_query_schema, "get_export_ids_schema": get_export_ids_schema, } @@ -205,6 +223,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi): openapi_spec_component_schemas = ( DatabaseFunctionNamesResponse, DatabaseRelatedObjectsResponse, + DatabaseTablesResponse, DatabaseTestConnectionSchema, DatabaseValidateParametersSchema, TableExtraMetadataResponseSchema, @@ -215,6 +234,47 @@ class DatabaseRestApi(BaseSupersetModelRestApi): ValidateSQLResponse, ) + @expose("/<int:pk>", methods=["GET"]) + @protect() + @safe + def get(self, pk: int, **kwargs: Any) -> Response: + """Get a database + --- + get: + description: >- + Get a database + parameters: + - in: path + schema: + type: integer + description: The database id + name: pk + responses: + 200: + description: Database + content: + application/json: + schema: + type: object + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 422: + $ref: '#/components/responses/422' + 500: + $ref: '#/components/responses/500' + """ + data = self.get_headless(pk, **kwargs) + try: + if ssh_tunnel := DatabaseDAO.get_ssh_tunnel(pk): + payload = data.json + payload["result"]["ssh_tunnel"] = ssh_tunnel.data + return payload + return data + except SupersetException as ex: + return self.response(ex.status, message=ex.message) + @expose("/", methods=["POST"]) @protect() @safe @@ -224,7 +284,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi): log_to_statsd=False, ) @requires_json - def post(self) -> Response: + def post(self) -> FlaskResponse: """Creates a new Database --- post: @@ -264,7 +324,7 @@ def post(self) -> Response: except ValidationError as error: return self.response_400(message=error.messages) try: - new_model = CreateDatabaseCommand(g.user, item).run() + new_model = CreateDatabaseCommand(item).run() # Return censored version for sqlalchemy URI item["sqlalchemy_uri"] = new_model.sqlalchemy_uri item["expose_in_sqllab"] = new_model.expose_in_sqllab @@ -273,11 +333,22 @@ def post(self) -> Response: if new_model.parameters: item["parameters"] = new_model.parameters + if new_model.driver: + item["driver"] = new_model.driver + + # Return SSH Tunnel and hide passwords if any + if item.get("ssh_tunnel"): + item["ssh_tunnel"] = mask_password_info( + new_model.ssh_tunnel # pylint: disable=no-member + ) + return self.response(201, id=new_model.id, result=item) except DatabaseInvalidError as ex: return self.response_422(message=ex.normalized_messages()) except DatabaseConnectionFailedError as ex: return self.response_422(message=str(ex)) + except SupersetErrorsException as ex: + return json_errors_response(errors=ex.errors, status=ex.status) except DatabaseCreateFailedError as ex: logger.error( "Error creating model %s: %s", @@ -286,6 +357,10 @@ def post(self) -> Response: exc_info=True, ) return self.response_422(message=str(ex)) + except SSHTunnelingNotEnabledError as ex: + return self.response_400(message=str(ex)) + except SupersetException as ex: + return self.response(ex.status, message=ex.message) @expose("/<int:pk>", methods=["PUT"]) @protect() @@ -345,11 +420,14 @@ def put(self, pk: int) -> Response: except ValidationError as error: return self.response_400(message=error.messages) try: - changed_model = UpdateDatabaseCommand(g.user, pk, item).run() + changed_model = UpdateDatabaseCommand(pk, item).run() # Return censored version for sqlalchemy URI item["sqlalchemy_uri"] = changed_model.sqlalchemy_uri if changed_model.parameters: item["parameters"] = changed_model.parameters + # Return SSH Tunnel and hide passwords if any + if item.get("ssh_tunnel"): + item["ssh_tunnel"] = mask_password_info(changed_model.ssh_tunnel) return self.response(200, id=changed_model.id, result=item) except DatabaseNotFoundError: return self.response_404() @@ -365,6 +443,8 @@ def put(self, pk: int) -> Response: exc_info=True, ) return self.response_422(message=str(ex)) + except SSHTunnelingNotEnabledError as ex: + return self.response_400(message=str(ex)) @expose("/<int:pk>", methods=["DELETE"]) @protect() @@ -407,7 +487,7 @@ def delete(self, pk: int) -> Response: $ref: '#/components/responses/500' """ try: - DeleteDatabaseCommand(g.user, pk).run() + DeleteDatabaseCommand(pk).run() return self.response(200, message="OK") except DatabaseNotFoundError: return self.response_404() @@ -479,6 +559,75 @@ def schemas(self, pk: int, **kwargs: Any) -> FlaskResponse: return self.response( 500, message="There was an error connecting to the database" ) + except SupersetException as ex: + return self.response(ex.status, message=ex.message) + + @expose("/<int:pk>/tables/") + @protect() + @safe + @rison(database_tables_query_schema) + @statsd_metrics + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" f".tables", + log_to_statsd=False, + ) + def tables(self, pk: int, **kwargs: Any) -> FlaskResponse: + """Get a list of tables for given database + --- + get: + summary: Get a list of tables for given database + parameters: + - in: path + schema: + type: integer + name: pk + description: The database id + - in: query + name: q + content: + application/json: + schema: + $ref: '#/components/schemas/database_tables_query_schema' + responses: + 200: + description: Tables list + content: + application/json: + schema: + type: object + properties: + count: + type: integer + result: + description: >- + A List of tables for given database + type: array + items: + $ref: '#/components/schemas/DatabaseTablesResponse' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 404: + $ref: '#/components/responses/404' + 422: + $ref: '#/components/responses/422' + 500: + $ref: '#/components/responses/500' + """ + force = kwargs["rison"].get("force", False) + schema_name = kwargs["rison"].get("schema_name", "") + + try: + command = TablesDatabaseCommand(pk, schema_name, force) + payload = command.run() + return self.response(200, **payload) + except DatabaseNotFoundError: + return self.response_404() + except SupersetException as ex: + return self.response(ex.status, message=ex.message) + except DatabaseTablesUnexpectedError as ex: + return self.response_422(ex.message) @expose("/<int:pk>/table/<table_name>/<schema_name>/", methods=["GET"]) @protect() @@ -537,6 +686,9 @@ def table_metadata( except SQLAlchemyError as ex: self.incr_stats("error", self.table_metadata.__name__) return self.response_422(error_msg_from_exception(ex)) + except SupersetException as ex: + return self.response(ex.status, message=ex.message) + self.incr_stats("success", self.table_metadata.__name__) return self.response(200, **table_info) @@ -597,7 +749,7 @@ def table_extra_metadata( self.incr_stats("init", self.table_metadata.__name__) parsed_schema = parse_js_uri_path_item(schema_name, eval_undefined=True) - table_name = parse_js_uri_path_item(table_name) # type: ignore + table_name = cast(str, parse_js_uri_path_item(table_name)) payload = database.db_engine_spec.extra_table_metadata( database, table_name, parsed_schema ) @@ -661,11 +813,11 @@ def select_star( ) except NoSuchTableError: self.incr_stats("error", self.select_star.__name__) - return self.response(404, message="Table not found on the database") + return self.response(404, message="Table not found in the database") self.incr_stats("success", self.select_star.__name__) return self.response(200, result=result) - @expose("/test_connection", methods=["POST"]) + @expose("/test_connection/", methods=["POST"]) @protect() @statsd_metrics @event_logger.log_this_with_context( @@ -709,8 +861,11 @@ def test_connection(self) -> FlaskResponse: # This validates custom Schema with custom validations except ValidationError as error: return self.response_400(message=error.messages) - TestConnectionDatabaseCommand(g.user, item).run() - return self.response(200, message="OK") + try: + TestConnectionDatabaseCommand(item).run() + return self.response(200, message="OK") + except SSHTunnelingNotEnabledError as ex: + return self.response_400(message=str(ex)) @expose("/<int:pk>/related_objects/", methods=["GET"]) @protect() @@ -781,7 +936,7 @@ def related_objects(self, pk: int) -> Response: }, ) - @expose("/<int:pk>/validate_sql", methods=["POST"]) + @expose("/<int:pk>/validate_sql/", methods=["POST"]) @protect() @statsd_metrics @event_logger.log_this_with_context( @@ -1070,6 +1225,16 @@ def available(self) -> Response: parameters: description: JSON schema defining the needed parameters type: object + engine_information: + description: Dict with public properties form the DB Engine + type: object + properties: + supports_file_upload: + description: Whether the engine supports file uploads + type: boolean + disable_ssh_tunneling: + description: Whether the engine supports SSH Tunnels + type: boolean 400: $ref: '#/components/responses/400' 500: @@ -1086,10 +1251,11 @@ def available(self) -> Response: "engine": engine_spec.engine, "available_drivers": sorted(drivers), "preferred": engine_spec.engine_name in preferred_databases, + "engine_information": engine_spec.get_public_information(), } - if hasattr(engine_spec, "default_driver"): - payload["default_driver"] = engine_spec.default_driver # type: ignore + if engine_spec.default_driver: + payload["default_driver"] = engine_spec.default_driver # show configuration parameters for DBs that support it if ( @@ -1126,7 +1292,7 @@ def available(self) -> Response: return self.response(200, databases=response) - @expose("/validate_parameters", methods=["POST"]) + @expose("/validate_parameters/", methods=["POST"]) @protect() @statsd_metrics @event_logger.log_this_with_context( @@ -1179,6 +1345,68 @@ def validate_parameters(self) -> FlaskResponse: ] raise InvalidParametersError(errors) from ex - command = ValidateDatabaseParametersCommand(g.user, payload) + command = ValidateDatabaseParametersCommand(payload) command.run() return self.response(200, message="OK") + + @expose("/<int:pk>/ssh_tunnel/", methods=["DELETE"]) + @protect() + @statsd_metrics + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" + f".delete_ssh_tunnel", + log_to_statsd=False, + ) + def delete_ssh_tunnel(self, pk: int) -> Response: + """Deletes a SSH Tunnel + --- + delete: + description: >- + Deletes a SSH Tunnel. + parameters: + - in: path + schema: + type: integer + name: pk + responses: + 200: + description: SSH Tunnel deleted + content: + application/json: + schema: + type: object + properties: + message: + type: string + 401: + $ref: '#/components/responses/401' + 403: + $ref: '#/components/responses/403' + 404: + $ref: '#/components/responses/404' + 422: + $ref: '#/components/responses/422' + 500: + $ref: '#/components/responses/500' + """ + try: + DeleteSSHTunnelCommand(pk).run() + return self.response(200, message="OK") + except SSHTunnelNotFoundError: + return self.response_404() + except SSHTunnelDeleteFailedError as ex: + logger.error( + "Error deleting SSH Tunnel %s: %s", + self.__class__.__name__, + str(ex), + exc_info=True, + ) + return self.response_422(message=str(ex)) + except SSHTunnelingNotEnabledError as ex: + logger.error( + "Error deleting SSH Tunnel %s: %s", + self.__class__.__name__, + str(ex), + exc_info=True, + ) + return self.response_400(message=str(ex)) diff --git a/superset/databases/commands/create.py b/superset/databases/commands/create.py index e91ccec45c591..0ed23549608de 100644 --- a/superset/databases/commands/create.py +++ b/superset/databases/commands/create.py @@ -18,9 +18,9 @@ from typing import Any, Dict, List, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError +from superset import is_feature_enabled from superset.commands.base import BaseCommand from superset.dao.exceptions import DAOCreateFailedError from superset.databases.commands.exceptions import ( @@ -32,14 +32,20 @@ ) from superset.databases.commands.test_connection import TestConnectionDatabaseCommand from superset.databases.dao import DatabaseDAO +from superset.databases.ssh_tunnel.commands.create import CreateSSHTunnelCommand +from superset.databases.ssh_tunnel.commands.exceptions import ( + SSHTunnelCreateFailedError, + SSHTunnelingNotEnabledError, + SSHTunnelInvalidError, +) +from superset.exceptions import SupersetErrorsException from superset.extensions import db, event_logger, security_manager logger = logging.getLogger(__name__) class CreateDatabaseCommand(BaseCommand): - def __init__(self, user: User, data: Dict[str, Any]): - self._actor = user + def __init__(self, data: Dict[str, Any]): self._properties = data.copy() def run(self) -> Model: @@ -47,7 +53,14 @@ def run(self) -> Model: try: # Test connection before starting create transaction - TestConnectionDatabaseCommand(self._actor, self._properties).run() + TestConnectionDatabaseCommand(self._properties).run() + except (SupersetErrorsException, SSHTunnelingNotEnabledError) as ex: + event_logger.log_with_context( + action=f"db_creation_failed.{ex.__class__.__name__}", + engine=self._properties.get("sqlalchemy_uri", "").split(":")[0], + ) + # So we can show the original message + raise ex except Exception as ex: event_logger.log_with_context( action=f"db_creation_failed.{ex.__class__.__name__}", @@ -55,17 +68,48 @@ def run(self) -> Model: ) raise DatabaseConnectionFailedError() from ex + # when creating a new database we don't need to unmask encrypted extra + self._properties["encrypted_extra"] = self._properties.pop( + "masked_encrypted_extra", + "{}", + ) + try: database = DatabaseDAO.create(self._properties, commit=False) database.set_sqlalchemy_uri(database.sqlalchemy_uri) + ssh_tunnel = None + if ssh_tunnel_properties := self._properties.get("ssh_tunnel"): + if not is_feature_enabled("SSH_TUNNELING"): + db.session.rollback() + raise SSHTunnelingNotEnabledError() + try: + # So database.id is not None + db.session.flush() + ssh_tunnel = CreateSSHTunnelCommand( + database.id, ssh_tunnel_properties + ).run() + except (SSHTunnelInvalidError, SSHTunnelCreateFailedError) as ex: + event_logger.log_with_context( + action=f"db_creation_failed.{ex.__class__.__name__}", + engine=self._properties.get("sqlalchemy_uri", "").split(":")[0], + ) + # So we can show the original message + raise ex + except Exception as ex: + event_logger.log_with_context( + action=f"db_creation_failed.{ex.__class__.__name__}", + engine=self._properties.get("sqlalchemy_uri", "").split(":")[0], + ) + raise DatabaseCreateFailedError() from ex + # adding a new database we always want to force refresh schema list - schemas = database.get_all_schema_names(cache=False) + schemas = database.get_all_schema_names(cache=False, ssh_tunnel=ssh_tunnel) for schema in schemas: security_manager.add_permission_view_menu( "schema_access", security_manager.get_schema_perm(database, schema) ) - security_manager.add_permission_view_menu("database_access", database.perm) + db.session.commit() except DAOCreateFailedError as ex: db.session.rollback() diff --git a/superset/databases/commands/delete.py b/superset/databases/commands/delete.py index 61bd7ad0a575d..ebdd543570a11 100644 --- a/superset/databases/commands/delete.py +++ b/superset/databases/commands/delete.py @@ -18,7 +18,6 @@ from typing import Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from flask_babel import lazy_gettext as _ from superset.commands.base import BaseCommand @@ -37,8 +36,7 @@ class DeleteDatabaseCommand(BaseCommand): - def __init__(self, user: User, model_id: int): - self._actor = user + def __init__(self, model_id: int): self._model_id = model_id self._model: Optional[Database] = None diff --git a/superset/databases/commands/exceptions.py b/superset/databases/commands/exceptions.py index a49abd3449d03..8161e1047db68 100644 --- a/superset/databases/commands/exceptions.py +++ b/superset/databases/commands/exceptions.py @@ -137,6 +137,11 @@ class DatabaseTestConnectionUnexpectedError(SupersetErrorsException): message = _("Unexpected error occurred, please check your logs for details") +class DatabaseTablesUnexpectedError(Exception): + status = 422 + message = _("Unexpected error occurred, please check your logs for details") + + class NoValidatorConfigFoundError(SupersetErrorException): status = 422 message = _("no SQL validator is configured") diff --git a/superset/databases/commands/export.py b/superset/databases/commands/export.py index 9e8cb7e374426..4d3bb7f99f251 100644 --- a/superset/databases/commands/export.py +++ b/superset/databases/commands/export.py @@ -21,13 +21,13 @@ from typing import Any, Dict, Iterator, Tuple import yaml -from werkzeug.utils import secure_filename from superset.databases.commands.exceptions import DatabaseNotFoundError from superset.databases.dao import DatabaseDAO from superset.commands.export.models import ExportModelsCommand from superset.models.core import Database from superset.utils.dict_import_export import EXPORT_VERSION +from superset.utils.file import get_filename logger = logging.getLogger(__name__) @@ -58,8 +58,8 @@ class ExportDatabasesCommand(ExportModelsCommand): def _export( model: Database, export_related: bool = True ) -> Iterator[Tuple[str, str]]: - database_slug = secure_filename(model.database_name) - file_name = f"databases/{database_slug}.yaml" + db_file_name = get_filename(model.database_name, model.id, skip_id=True) + file_path = f"databases/{db_file_name}.yaml" payload = model.export_to_dict( recursive=False, @@ -90,12 +90,14 @@ def _export( payload["version"] = EXPORT_VERSION file_content = yaml.safe_dump(payload, sort_keys=False) - yield file_name, file_content + yield file_path, file_content if export_related: for dataset in model.tables: - dataset_slug = secure_filename(dataset.table_name) - file_name = f"datasets/{database_slug}/{dataset_slug}.yaml" + ds_file_name = get_filename( + dataset.table_name, dataset.id, skip_id=True + ) + file_path = f"datasets/{db_file_name}/{ds_file_name}.yaml" payload = dataset.export_to_dict( recursive=True, @@ -107,4 +109,4 @@ def _export( payload["database_uuid"] = str(model.uuid) file_content = yaml.safe_dump(payload, sort_keys=False) - yield file_name, file_content + yield file_path, file_content diff --git a/superset/databases/commands/tables.py b/superset/databases/commands/tables.py new file mode 100644 index 0000000000000..48e9227dea75e --- /dev/null +++ b/superset/databases/commands/tables.py @@ -0,0 +1,113 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging +from typing import Any, cast, Dict + +from superset.commands.base import BaseCommand +from superset.connectors.sqla.models import SqlaTable +from superset.databases.commands.exceptions import ( + DatabaseNotFoundError, + DatabaseTablesUnexpectedError, +) +from superset.databases.dao import DatabaseDAO +from superset.exceptions import SupersetException +from superset.extensions import db, security_manager +from superset.models.core import Database +from superset.utils.core import DatasourceName + +logger = logging.getLogger(__name__) + + +class TablesDatabaseCommand(BaseCommand): + _model: Database + + def __init__(self, db_id: int, schema_name: str, force: bool): + self._db_id = db_id + self._schema_name = schema_name + self._force = force + + def run(self) -> Dict[str, Any]: + self.validate() + try: + tables = security_manager.get_datasources_accessible_by_user( + database=self._model, + schema=self._schema_name, + datasource_names=sorted( + DatasourceName(*datasource_name) + for datasource_name in self._model.get_all_table_names_in_schema( + schema=self._schema_name, + force=self._force, + cache=self._model.table_cache_enabled, + cache_timeout=self._model.table_cache_timeout, + ) + ), + ) + + views = security_manager.get_datasources_accessible_by_user( + database=self._model, + schema=self._schema_name, + datasource_names=sorted( + DatasourceName(*datasource_name) + for datasource_name in self._model.get_all_view_names_in_schema( + schema=self._schema_name, + force=self._force, + cache=self._model.table_cache_enabled, + cache_timeout=self._model.table_cache_timeout, + ) + ), + ) + + extra_dict_by_name = { + table.name: table.extra_dict + for table in ( + db.session.query(SqlaTable).filter( + SqlaTable.database_id == self._model.id, + SqlaTable.schema == self._schema_name, + ) + ).all() + } + + options = sorted( + [ + { + "value": table.table, + "type": "table", + "extra": extra_dict_by_name.get(table.table, None), + } + for table in tables + ] + + [ + { + "value": view.table, + "type": "view", + } + for view in views + ], + key=lambda item: item["value"], + ) + + payload = {"count": len(tables) + len(views), "result": options} + return payload + except SupersetException as ex: + raise ex + except Exception as ex: + raise DatabaseTablesUnexpectedError(ex) from ex + + def validate(self) -> None: + self._model = cast(Database, DatabaseDAO.find_by_id(self._db_id)) + if not self._model: + raise DatabaseNotFoundError() diff --git a/superset/databases/commands/test_connection.py b/superset/databases/commands/test_connection.py index 2e217ab01a807..c5e7dc48f9831 100644 --- a/superset/databases/commands/test_connection.py +++ b/superset/databases/commands/test_connection.py @@ -20,41 +20,61 @@ from typing import Any, Dict, Optional from flask import current_app as app -from flask_appbuilder.security.sqla.models import User from flask_babel import gettext as _ from func_timeout import func_timeout, FunctionTimedOut from sqlalchemy.engine import Engine from sqlalchemy.exc import DBAPIError, NoSuchModuleError +from superset import is_feature_enabled from superset.commands.base import BaseCommand from superset.databases.commands.exceptions import ( DatabaseSecurityUnsafeError, DatabaseTestConnectionDriverError, - DatabaseTestConnectionFailedError, DatabaseTestConnectionUnexpectedError, ) from superset.databases.dao import DatabaseDAO +from superset.databases.ssh_tunnel.commands.exceptions import ( + SSHTunnelingNotEnabledError, +) +from superset.databases.ssh_tunnel.dao import SSHTunnelDAO +from superset.databases.ssh_tunnel.models import SSHTunnel from superset.databases.utils import make_url_safe from superset.errors import ErrorLevel, SupersetErrorType -from superset.exceptions import SupersetSecurityException, SupersetTimeoutException +from superset.exceptions import ( + SupersetErrorsException, + SupersetSecurityException, + SupersetTimeoutException, +) from superset.extensions import event_logger from superset.models.core import Database -from superset.utils.core import override_user +from superset.utils.ssh_tunnel import unmask_password_info logger = logging.getLogger(__name__) +def get_log_connection_action( + action: str, ssh_tunnel: Optional[Any], exc: Optional[Exception] = None +) -> str: + action_modified = action + if exc: + action_modified += f".{exc.__class__.__name__}" + if ssh_tunnel: + action_modified += ".ssh_tunnel" + return action_modified + + class TestConnectionDatabaseCommand(BaseCommand): - def __init__(self, user: User, data: Dict[str, Any]): - self._actor = user + def __init__(self, data: Dict[str, Any]): self._properties = data.copy() self._model: Optional[Database] = None - def run(self) -> None: + def run(self) -> None: # pylint: disable=too-many-statements, too-many-branches self.validate() + ex_str = "" uri = self._properties.get("sqlalchemy_uri", "") if self._model and uri == self._model.safe_sqlalchemy_uri(): uri = self._model.sqlalchemy_uri_decrypted + ssh_tunnel = self._properties.get("ssh_tunnel") # context for error messages url = make_url_safe(uri) @@ -66,39 +86,60 @@ def run(self) -> None: "database": url.database, } + serialized_encrypted_extra = self._properties.get( + "masked_encrypted_extra", + "{}", + ) + if self._model: + serialized_encrypted_extra = ( + self._model.db_engine_spec.unmask_encrypted_extra( + self._model.encrypted_extra, + serialized_encrypted_extra, + ) + ) + try: database = DatabaseDAO.build_db_for_connection_test( server_cert=self._properties.get("server_cert", ""), extra=self._properties.get("extra", "{}"), impersonate_user=self._properties.get("impersonate_user", False), - encrypted_extra=self._properties.get("encrypted_extra", "{}"), + encrypted_extra=serialized_encrypted_extra, ) database.set_sqlalchemy_uri(uri) database.db_engine_spec.mutate_db_for_connection_test(database) - with override_user(self._actor): - engine = database.get_sqla_engine() - event_logger.log_with_context( - action="test_connection_attempt", - engine=database.db_engine_spec.__name__, - ) + # Generate tunnel if present in the properties + if ssh_tunnel: + if not is_feature_enabled("SSH_TUNNELING"): + raise SSHTunnelingNotEnabledError() + # If there's an existing tunnel for that DB we need to use the stored + # password, private_key and private_key_password instead + if ssh_tunnel_id := ssh_tunnel.pop("id", None): + if existing_ssh_tunnel := SSHTunnelDAO.find_by_id(ssh_tunnel_id): + ssh_tunnel = unmask_password_info( + ssh_tunnel, existing_ssh_tunnel + ) + ssh_tunnel = SSHTunnel(**ssh_tunnel) + + event_logger.log_with_context( + action=get_log_connection_action("test_connection_attempt", ssh_tunnel), + engine=database.db_engine_spec.__name__, + ) - def ping(engine: Engine) -> bool: - with closing(engine.raw_connection()) as conn: - return engine.dialect.do_ping(conn) + def ping(engine: Engine) -> bool: + with closing(engine.raw_connection()) as conn: + return engine.dialect.do_ping(conn) + with database.get_sqla_engine_with_context( + override_ssh_tunnel=ssh_tunnel + ) as engine: try: alive = func_timeout( - int( - app.config[ - "TEST_DATABASE_CONNECTION_TIMEOUT" - ].total_seconds() - ), + app.config["TEST_DATABASE_CONNECTION_TIMEOUT"].total_seconds(), ping, args=(engine,), ) - except (sqlite3.ProgrammingError, RuntimeError): # SQLite can't run on a separate thread, so ``func_timeout`` fails # RuntimeError catches the equivalent error from duckdb. @@ -114,20 +155,25 @@ def ping(engine: Engine) -> bool: level=ErrorLevel.ERROR, extra={"sqlalchemy_uri": database.sqlalchemy_uri}, ) from ex - except Exception: # pylint: disable=broad-except + except Exception as ex: # pylint: disable=broad-except alive = False - if not alive: - raise DBAPIError(None, None, None) + # So we stop losing the original message if any + ex_str = str(ex) + + if not alive: + raise DBAPIError(ex_str or None, None, None) # Log succesful connection test with engine event_logger.log_with_context( - action="test_connection_success", + action=get_log_connection_action("test_connection_success", ssh_tunnel), engine=database.db_engine_spec.__name__, ) except (NoSuchModuleError, ModuleNotFoundError) as ex: event_logger.log_with_context( - action=f"test_connection_error.{ex.__class__.__name__}", + action=get_log_connection_action( + "test_connection_error", ssh_tunnel, ex + ), engine=database.db_engine_spec.__name__, ) raise DatabaseTestConnectionDriverError( @@ -137,29 +183,46 @@ def ping(engine: Engine) -> bool: ) from ex except DBAPIError as ex: event_logger.log_with_context( - action=f"test_connection_error.{ex.__class__.__name__}", + action=get_log_connection_action( + "test_connection_error", ssh_tunnel, ex + ), engine=database.db_engine_spec.__name__, ) # check for custom errors (wrong username, wrong password, etc) errors = database.db_engine_spec.extract_errors(ex, context) - raise DatabaseTestConnectionFailedError(errors) from ex + raise SupersetErrorsException(errors) from ex except SupersetSecurityException as ex: event_logger.log_with_context( - action=f"test_connection_error.{ex.__class__.__name__}", + action=get_log_connection_action( + "test_connection_error", ssh_tunnel, ex + ), engine=database.db_engine_spec.__name__, ) raise DatabaseSecurityUnsafeError(message=str(ex)) from ex except SupersetTimeoutException as ex: event_logger.log_with_context( - action=f"test_connection_error.{ex.__class__.__name__}", + action=get_log_connection_action( + "test_connection_error", ssh_tunnel, ex + ), engine=database.db_engine_spec.__name__, ) # bubble up the exception to return a 408 raise ex + except SSHTunnelingNotEnabledError as ex: + event_logger.log_with_context( + action=get_log_connection_action( + "test_connection_error", ssh_tunnel, ex + ), + engine=database.db_engine_spec.__name__, + ) + # bubble up the exception to return a 400 + raise ex except Exception as ex: event_logger.log_with_context( - action=f"test_connection_error.{ex.__class__.__name__}", + action=get_log_connection_action( + "test_connection_error", ssh_tunnel, ex + ), engine=database.db_engine_spec.__name__, ) errors = database.db_engine_spec.extract_errors(ex, context) diff --git a/superset/databases/commands/update.py b/superset/databases/commands/update.py index 69b6c30e71c64..03531803553a5 100644 --- a/superset/databases/commands/update.py +++ b/superset/databases/commands/update.py @@ -18,11 +18,11 @@ from typing import Any, Dict, List, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError +from superset import is_feature_enabled from superset.commands.base import BaseCommand -from superset.dao.exceptions import DAOUpdateFailedError +from superset.dao.exceptions import DAOCreateFailedError, DAOUpdateFailedError from superset.databases.commands.exceptions import ( DatabaseConnectionFailedError, DatabaseExistsValidationError, @@ -31,25 +31,44 @@ DatabaseUpdateFailedError, ) from superset.databases.dao import DatabaseDAO +from superset.databases.ssh_tunnel.commands.create import CreateSSHTunnelCommand +from superset.databases.ssh_tunnel.commands.exceptions import ( + SSHTunnelCreateFailedError, + SSHTunnelingNotEnabledError, + SSHTunnelInvalidError, + SSHTunnelUpdateFailedError, +) +from superset.databases.ssh_tunnel.commands.update import UpdateSSHTunnelCommand from superset.extensions import db, security_manager from superset.models.core import Database +from superset.utils.core import DatasourceType logger = logging.getLogger(__name__) class UpdateDatabaseCommand(BaseCommand): - def __init__(self, user: User, model_id: int, data: Dict[str, Any]): - self._actor = user + def __init__(self, model_id: int, data: Dict[str, Any]): self._properties = data.copy() self._model_id = model_id self._model: Optional[Database] = None def run(self) -> Model: self.validate() + if not self._model: + raise DatabaseNotFoundError() + old_database_name = self._model.database_name + + # unmask ``encrypted_extra`` + self._properties[ + "encrypted_extra" + ] = self._model.db_engine_spec.unmask_encrypted_extra( + self._model.encrypted_extra, + self._properties.pop("masked_encrypted_extra", "{}"), + ) + try: database = DatabaseDAO.update(self._model, self._properties, commit=False) database.set_sqlalchemy_uri(database.sqlalchemy_uri) - security_manager.add_permission_view_menu("database_access", database.perm) # adding a new database we always want to force refresh schema list # TODO Improve this simplistic implementation for catching DB conn fails try: @@ -57,17 +76,93 @@ def run(self) -> Model: except Exception as ex: db.session.rollback() raise DatabaseConnectionFailedError() from ex + + # Update database schema permissions + new_schemas: List[str] = [] + for schema in schemas: + old_view_menu_name = security_manager.get_schema_perm( + old_database_name, schema + ) + new_view_menu_name = security_manager.get_schema_perm( + database.database_name, schema + ) + schema_pvm = security_manager.find_permission_view_menu( + "schema_access", old_view_menu_name + ) + # Update the schema permission if the database name changed + if schema_pvm and old_database_name != database.database_name: + schema_pvm.view_menu.name = new_view_menu_name + + self._propagate_schema_permissions( + old_view_menu_name, new_view_menu_name + ) + else: + new_schemas.append(schema) + for schema in new_schemas: security_manager.add_permission_view_menu( "schema_access", security_manager.get_schema_perm(database, schema) ) + + if ssh_tunnel_properties := self._properties.get("ssh_tunnel"): + if not is_feature_enabled("SSH_TUNNELING"): + db.session.rollback() + raise SSHTunnelingNotEnabledError() + existing_ssh_tunnel_model = DatabaseDAO.get_ssh_tunnel(database.id) + if existing_ssh_tunnel_model is None: + # We couldn't found an existing tunnel so we need to create one + try: + CreateSSHTunnelCommand(database.id, ssh_tunnel_properties).run() + except (SSHTunnelInvalidError, SSHTunnelCreateFailedError) as ex: + # So we can show the original message + raise ex + except Exception as ex: + raise DatabaseUpdateFailedError() from ex + else: + # We found an existing tunnel so we need to update it + try: + UpdateSSHTunnelCommand( + existing_ssh_tunnel_model.id, ssh_tunnel_properties + ).run() + except (SSHTunnelInvalidError, SSHTunnelUpdateFailedError) as ex: + # So we can show the original message + raise ex + except Exception as ex: + raise DatabaseUpdateFailedError() from ex + db.session.commit() - except DAOUpdateFailedError as ex: - logger.exception(ex.exception) + except (DAOUpdateFailedError, DAOCreateFailedError) as ex: raise DatabaseUpdateFailedError() from ex return database + @staticmethod + def _propagate_schema_permissions( + old_view_menu_name: str, new_view_menu_name: str + ) -> None: + from superset.connectors.sqla.models import ( # pylint: disable=import-outside-toplevel + SqlaTable, + ) + from superset.models.slice import ( # pylint: disable=import-outside-toplevel + Slice, + ) + + # Update schema_perm on all datasets + datasets = ( + db.session.query(SqlaTable) + .filter(SqlaTable.schema_perm == old_view_menu_name) + .all() + ) + for dataset in datasets: + dataset.schema_perm = new_view_menu_name + charts = db.session.query(Slice).filter( + Slice.datasource_type == DatasourceType.TABLE, + Slice.datasource_id == dataset.id, + ) + # Update schema_perm on all charts + for chart in charts: + chart.schema_perm = new_view_menu_name + def validate(self) -> None: exceptions: List[ValidationError] = [] # Validate/populate model exists diff --git a/superset/databases/commands/validate.py b/superset/databases/commands/validate.py index 145965fc641fc..8c58ef5de0bfb 100644 --- a/superset/databases/commands/validate.py +++ b/superset/databases/commands/validate.py @@ -18,7 +18,6 @@ from contextlib import closing from typing import Any, Dict, Optional -from flask_appbuilder.security.sqla.models import User from flask_babel import gettext as __ from superset.commands.base import BaseCommand @@ -30,43 +29,30 @@ ) from superset.databases.dao import DatabaseDAO from superset.databases.utils import make_url_safe -from superset.db_engine_specs import get_engine_specs -from superset.db_engine_specs.base import BasicParametersMixin +from superset.db_engine_specs import get_engine_spec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.extensions import event_logger from superset.models.core import Database -from superset.utils.core import override_user BYPASS_VALIDATION_ENGINES = {"bigquery"} class ValidateDatabaseParametersCommand(BaseCommand): - def __init__(self, user: User, parameters: Dict[str, Any]): - self._actor = user - self._properties = parameters.copy() + def __init__(self, properties: Dict[str, Any]): + self._properties = properties.copy() self._model: Optional[Database] = None def run(self) -> None: + self.validate() + engine = self._properties["engine"] - engine_specs = get_engine_specs() + driver = self._properties.get("driver") if engine in BYPASS_VALIDATION_ENGINES: # Skip engines that are only validated onCreate return - if engine not in engine_specs: - raise InvalidEngineError( - SupersetError( - message=__( - 'Engine "%(engine)s" is not a valid engine.', - engine=engine, - ), - error_type=SupersetErrorType.GENERIC_DB_ENGINE_ERROR, - level=ErrorLevel.ERROR, - extra={"allowed": list(engine_specs), "provided": engine}, - ), - ) - engine_spec = engine_specs[engine] + engine_spec = get_engine_spec(engine, driver) if not hasattr(engine_spec, "parameters_schema"): raise InvalidEngineError( SupersetError( @@ -76,26 +62,24 @@ def run(self) -> None: ), error_type=SupersetErrorType.GENERIC_DB_ENGINE_ERROR, level=ErrorLevel.ERROR, - extra={ - "allowed": [ - name - for name, engine_spec in engine_specs.items() - if issubclass(engine_spec, BasicParametersMixin) - ], - "provided": engine, - }, ), ) # perform initial validation - errors = engine_spec.validate_parameters( # type: ignore - self._properties.get("parameters", {}) - ) + errors = engine_spec.validate_parameters(self._properties) # type: ignore if errors: event_logger.log_with_context(action="validation_error", engine=engine) raise InvalidParametersError(errors) - serialized_encrypted_extra = self._properties.get("encrypted_extra", "{}") + serialized_encrypted_extra = self._properties.get( + "masked_encrypted_extra", + "{}", + ) + if self._model: + serialized_encrypted_extra = engine_spec.unmask_encrypted_extra( + self._model.encrypted_extra, + serialized_encrypted_extra, + ) try: encrypted_extra = json.loads(serialized_encrypted_extra) except json.decoder.JSONDecodeError: @@ -117,8 +101,8 @@ def run(self) -> None: database.set_sqlalchemy_uri(sqlalchemy_uri) database.db_engine_spec.mutate_db_for_connection_test(database) - with override_user(self._actor): - engine = database.get_sqla_engine() + alive = False + with database.get_sqla_engine_with_context() as engine: try: with closing(engine.raw_connection()) as conn: alive = engine.dialect.do_ping(conn) @@ -144,6 +128,6 @@ def run(self) -> None: ) def validate(self) -> None: - database_name = self._properties.get("database_name") - if database_name is not None: - self._model = DatabaseDAO.get_database_by_name(database_name) + database_id = self._properties.get("id") + if database_id is not None: + self._model = DatabaseDAO.find_by_id(database_id) diff --git a/superset/databases/dao.py b/superset/databases/dao.py index 892ab86ed21df..c82f0db5745ae 100644 --- a/superset/databases/dao.py +++ b/superset/databases/dao.py @@ -19,6 +19,7 @@ from superset.dao.base import BaseDAO from superset.databases.filters import DatabaseFilter +from superset.databases.ssh_tunnel.models import SSHTunnel from superset.extensions import db from superset.models.core import Database from superset.models.dashboard import Dashboard @@ -33,6 +34,30 @@ class DatabaseDAO(BaseDAO): model_cls = Database base_filter = DatabaseFilter + @classmethod + def update( + cls, + model: Database, + properties: Dict[str, Any], + commit: bool = True, + ) -> Database: + """ + Unmask ``encrypted_extra`` before updating. + + When a database is edited the user sees a masked version of ``encrypted_extra``, + depending on the engine spec. Eg, BigQuery will mask the ``private_key`` attribute + of the credentials. + + The masked values should be unmasked before the database is updated. + """ + if "encrypted_extra" in properties: + properties["encrypted_extra"] = model.db_engine_spec.unmask_encrypted_extra( + model.encrypted_extra, + properties["encrypted_extra"], + ) + + return super().update(model, properties, commit) + @staticmethod def validate_uniqueness(database_name: str) -> bool: database_query = db.session.query(Database).filter( @@ -100,3 +125,13 @@ def get_related_objects(cls, database_id: int) -> Dict[str, Any]: return dict( charts=charts, dashboards=dashboards, sqllab_tab_states=sqllab_tab_states ) + + @classmethod + def get_ssh_tunnel(cls, database_id: int) -> Optional[SSHTunnel]: + ssh_tunnel = ( + db.session.query(SSHTunnel) + .filter(SSHTunnel.database_id == database_id) + .one_or_none() + ) + + return ssh_tunnel diff --git a/superset/databases/decorators.py b/superset/databases/decorators.py index 2cea2f96f8eb7..eb05ccbea781a 100644 --- a/superset/databases/decorators.py +++ b/superset/databases/decorators.py @@ -21,6 +21,7 @@ from flask import g from flask_babel import lazy_gettext as _ +from superset.extensions import stats_logger_manager from superset.models.core import Database from superset.sql_parse import Table from superset.utils.core import parse_js_uri_path_item @@ -46,14 +47,14 @@ def wraps( return self.response_422(message=_("Table name undefined")) database: Database = self.datamodel.get(pk) if not database: - self.stats_logger.incr( + stats_logger_manager.instance.incr( f"database_not_found_{self.__class__.__name__}.select_star" ) return self.response_404() if not self.appbuilder.sm.can_access_table( database, Table(table_name_parsed, schema_name_parsed) ): - self.stats_logger.incr( + stats_logger_manager.instance.incr( f"permisssion_denied_{self.__class__.__name__}.select_star" ) logger.warning( diff --git a/superset/databases/schemas.py b/superset/databases/schemas.py index cdce5578cd7df..e318e41121435 100644 --- a/superset/databases/schemas.py +++ b/superset/databases/schemas.py @@ -14,9 +14,12 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. + +# pylint: disable=no-self-use, unused-argument + import inspect import json -from typing import Any, Dict, Optional, Type +from typing import Any, Dict from flask import current_app from flask_babel import lazy_gettext as _ @@ -26,11 +29,12 @@ from sqlalchemy import MetaData from superset import db +from superset.constants import PASSWORD_MASK from superset.databases.commands.exceptions import DatabaseInvalidError from superset.databases.utils import make_url_safe -from superset.db_engine_specs import BaseEngineSpec, get_engine_specs +from superset.db_engine_specs import get_engine_spec from superset.exceptions import CertificateException, SupersetSecurityException -from superset.models.core import ConfigurationMethod, Database, PASSWORD_MASK +from superset.models.core import ConfigurationMethod, Database from superset.security.analytics_db_safety import check_sqlalchemy_uri from superset.utils.core import markdown, parse_ssl_cert @@ -39,6 +43,15 @@ "properties": {"force": {"type": "boolean"}}, } +database_tables_query_schema = { + "type": "object", + "properties": { + "force": {"type": "boolean"}, + "schema_name": {"type": "string"}, + }, + "required": ["schema_name"], +} + database_name_description = "A database name to identify this connection." port_description = "Port number for the database connection." cache_timeout_description = ( @@ -48,7 +61,7 @@ ) expose_in_sqllab_description = "Expose this database to SQLLab" allow_run_async_description = ( - "Operate the database in asynchronous mode, meaning " + "Operate the database in asynchronous mode, meaning " "that the queries are executed on remote workers as opposed " "to on the web server itself. " "This assumes that you have a Celery worker setup as well " @@ -66,11 +79,6 @@ "(UPDATE, DELETE, CREATE, ...) " "in SQL Lab" ) -allow_multi_schema_metadata_fetch_description = ( - "Allow SQL Lab to fetch a list of all tables and all views across " - "all database schemas. For large data warehouse with thousands of " - "tables, this can be expensive and put strain on the system." -) # pylint: disable=invalid-name configuration_method_description = ( "Configuration_method is used on the frontend to " "inform the backend whether to explode parameters " @@ -150,7 +158,7 @@ def sqlalchemy_uri_validator(value: str) -> str: [ _( "Invalid connection string, a valid string usually follows: " - "driver://user:password@database-host/database-name" + "backend+driver://user:password@database-host/database-name" ) ] ) from ex @@ -231,6 +239,7 @@ class DatabaseParametersSchemaMixin: # pylint: disable=too-few-public-methods """ engine = fields.String(allow_none=True, description="SQLAlchemy engine to use") + driver = fields.String(allow_none=True, description="SQLAlchemy driver to use") parameters = fields.Dict( keys=fields.String(), values=fields.Raw(), @@ -243,7 +252,6 @@ class DatabaseParametersSchemaMixin: # pylint: disable=too-few-public-methods missing=ConfigurationMethod.SQLALCHEMY_FORM, ) - # pylint: disable=no-self-use, unused-argument @pre_load def build_sqlalchemy_uri( self, data: Dict[str, Any], **kwargs: Any @@ -262,10 +270,20 @@ def build_sqlalchemy_uri( or parameters.pop("engine", None) or data.pop("backend", None) ) + driver = data.pop("driver", None) configuration_method = data.get("configuration_method") if configuration_method == ConfigurationMethod.DYNAMIC_FORM: - engine_spec = get_engine_spec(engine) + if not engine: + raise ValidationError( + [ + _( + "An engine must be specified when passing " + "individual parameters to a database." + ) + ] + ) + engine_spec = get_engine_spec(engine, driver) if not hasattr(engine_spec, "build_sqlalchemy_uri") or not hasattr( engine_spec, "parameters_schema" @@ -282,52 +300,55 @@ def build_sqlalchemy_uri( # validate parameters parameters = engine_spec.parameters_schema.load(parameters) # type: ignore - serialized_encrypted_extra = data.get("encrypted_extra") or "{}" + serialized_encrypted_extra = data.get("masked_encrypted_extra") or "{}" try: encrypted_extra = json.loads(serialized_encrypted_extra) except json.decoder.JSONDecodeError: encrypted_extra = {} data["sqlalchemy_uri"] = engine_spec.build_sqlalchemy_uri( # type: ignore - parameters, encrypted_extra + parameters, + encrypted_extra, ) return data -def get_engine_spec(engine: Optional[str]) -> Type[BaseEngineSpec]: - if not engine: - raise ValidationError( - [ - _( - "An engine must be specified when passing " - "individual parameters to a database." - ) - ] - ) - engine_specs = get_engine_specs() - if engine not in engine_specs: - raise ValidationError( - [ - _( - 'Engine "%(engine)s" is not a valid engine.', - engine=engine, - ) - ] - ) - return engine_specs[engine] +def rename_encrypted_extra( + self: Schema, + data: Dict[str, Any], + **kwargs: Any, +) -> Dict[str, Any]: + """ + Rename ``encrypted_extra`` to ``masked_encrypted_extra``. + + PR #21248 changed the database schema for security reasons. This pre-loader keeps + Superset backwards compatible with older clients. + """ + if "encrypted_extra" in data: + data["masked_encrypted_extra"] = data.pop("encrypted_extra") + return data class DatabaseValidateParametersSchema(Schema): class Meta: # pylint: disable=too-few-public-methods unknown = EXCLUDE + rename_encrypted_extra = pre_load(rename_encrypted_extra) + + id = fields.Integer(allow_none=True, description="Database ID (for updates)") engine = fields.String(required=True, description="SQLAlchemy engine to use") + driver = fields.String(allow_none=True, description="SQLAlchemy driver to use") parameters = fields.Dict( keys=fields.String(), values=fields.Raw(allow_none=True), description="DB-specific parameters for configuration", ) + catalog = fields.Dict( + keys=fields.String(), + values=fields.Raw(allow_none=True), + description="Gsheets specific column for managing label to sheet urls", + ) database_name = fields.String( description=database_name_description, allow_none=True, @@ -335,7 +356,7 @@ class Meta: # pylint: disable=too-few-public-methods ) impersonate_user = fields.Boolean(description=impersonate_user_description) extra = fields.String(description=extra_description, validate=extra_validator) - encrypted_extra = fields.String( + masked_encrypted_extra = fields.String( description=encrypted_extra_description, validate=encrypted_extra_validator, allow_none=True, @@ -353,10 +374,26 @@ class Meta: # pylint: disable=too-few-public-methods ) +class DatabaseSSHTunnel(Schema): + id = fields.Integer(allow_none=True, description="SSH Tunnel ID (for updates)") + server_address = fields.String() + server_port = fields.Integer() + username = fields.String() + + # Basic Authentication + password = fields.String(required=False) + + # password protected private key authentication + private_key = fields.String(required=False) + private_key_password = fields.String(required=False) + + class DatabasePostSchema(Schema, DatabaseParametersSchemaMixin): class Meta: # pylint: disable=too-few-public-methods unknown = EXCLUDE + rename_encrypted_extra = pre_load(rename_encrypted_extra) + database_name = fields.String( description=database_name_description, required=True, @@ -376,11 +413,8 @@ class Meta: # pylint: disable=too-few-public-methods allow_none=True, validate=Length(0, 250), ) - allow_multi_schema_metadata_fetch = fields.Boolean( - description=allow_multi_schema_metadata_fetch_description, - ) impersonate_user = fields.Boolean(description=impersonate_user_description) - encrypted_extra = fields.String( + masked_encrypted_extra = fields.String( description=encrypted_extra_description, validate=encrypted_extra_validator, allow_none=True, @@ -397,12 +431,16 @@ class Meta: # pylint: disable=too-few-public-methods ) is_managed_externally = fields.Boolean(allow_none=True, default=False) external_url = fields.String(allow_none=True) + uuid = fields.String(required=False) + ssh_tunnel = fields.Nested(DatabaseSSHTunnel, allow_none=True) class DatabasePutSchema(Schema, DatabaseParametersSchemaMixin): class Meta: # pylint: disable=too-few-public-methods unknown = EXCLUDE + rename_encrypted_extra = pre_load(rename_encrypted_extra) + database_name = fields.String( description=database_name_description, allow_none=True, @@ -422,11 +460,8 @@ class Meta: # pylint: disable=too-few-public-methods allow_none=True, validate=Length(0, 250), ) - allow_multi_schema_metadata_fetch = fields.Boolean( - description=allow_multi_schema_metadata_fetch_description - ) impersonate_user = fields.Boolean(description=impersonate_user_description) - encrypted_extra = fields.String( + masked_encrypted_extra = fields.String( description=encrypted_extra_description, allow_none=True, validate=encrypted_extra_validator, @@ -443,9 +478,13 @@ class Meta: # pylint: disable=too-few-public-methods ) is_managed_externally = fields.Boolean(allow_none=True, default=False) external_url = fields.String(allow_none=True) + ssh_tunnel = fields.Nested(DatabaseSSHTunnel, allow_none=True) class DatabaseTestConnectionSchema(Schema, DatabaseParametersSchemaMixin): + + rename_encrypted_extra = pre_load(rename_encrypted_extra) + database_name = fields.String( description=database_name_description, allow_none=True, @@ -453,7 +492,7 @@ class DatabaseTestConnectionSchema(Schema, DatabaseParametersSchemaMixin): ) impersonate_user = fields.Boolean(description=impersonate_user_description) extra = fields.String(description=extra_description, validate=extra_validator) - encrypted_extra = fields.String( + masked_encrypted_extra = fields.String( description=encrypted_extra_description, validate=encrypted_extra_validator, allow_none=True, @@ -468,6 +507,8 @@ class DatabaseTestConnectionSchema(Schema, DatabaseParametersSchemaMixin): validate=[Length(1, 1024), sqlalchemy_uri_validator], ) + ssh_tunnel = fields.Nested(DatabaseSSHTunnel, allow_none=True) + class TableMetadataOptionsResponseSchema(Schema): deferrable = fields.Bool() @@ -541,6 +582,12 @@ class SchemasResponseSchema(Schema): result = fields.List(fields.String(description="A database schema name")) +class DatabaseTablesResponse(Schema): + extra = fields.Dict(description="Extra data used to specify column metadata") + type = fields.String(description="table or view") + value = fields.String(description="The table or view name") + + class ValidateSQLRequest(Schema): sql = fields.String(required=True, description="SQL statement to validate") schema = fields.String(required=False, allow_none=True) @@ -591,9 +638,8 @@ class DatabaseFunctionNamesResponse(Schema): class ImportV1DatabaseExtraSchema(Schema): - # pylint: disable=no-self-use, unused-argument @pre_load - def fix_schemas_allowed_for_csv_upload( + def fix_schemas_allowed_for_csv_upload( # pylint: disable=invalid-name self, data: Dict[str, Any], **kwargs: Any ) -> Dict[str, Any]: """ @@ -625,10 +671,10 @@ def fix_schemas_allowed_for_csv_upload( cost_estimate_enabled = fields.Boolean() allows_virtual_table_explore = fields.Boolean(required=False) cancel_query_on_windows_unload = fields.Boolean(required=False) + disable_data_preview = fields.Boolean(required=False) class ImportV1DatabaseSchema(Schema): - # pylint: disable=no-self-use, unused-argument @pre_load def fix_allow_csv_upload( self, data: Dict[str, Any], **kwargs: Any @@ -652,6 +698,7 @@ def fix_allow_csv_upload( allow_run_async = fields.Boolean() allow_ctas = fields.Boolean() allow_cvas = fields.Boolean() + allow_dml = fields.Boolean(required=False) allow_csv_upload = fields.Boolean() extra = fields.Nested(ImportV1DatabaseExtraSchema) uuid = fields.UUID(required=True) @@ -659,7 +706,6 @@ def fix_allow_csv_upload( is_managed_externally = fields.Boolean(allow_none=True, default=False) external_url = fields.String(allow_none=True) - # pylint: disable=no-self-use, unused-argument @validates_schema def validate_password(self, data: Dict[str, Any], **kwargs: Any) -> None: """If sqlalchemy_uri has a masked password, password is required""" diff --git a/superset/databases/ssh_tunnel/__init__.py b/superset/databases/ssh_tunnel/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/superset/databases/ssh_tunnel/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/superset/databases/ssh_tunnel/commands/__init__.py b/superset/databases/ssh_tunnel/commands/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/superset/databases/ssh_tunnel/commands/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/superset/databases/ssh_tunnel/commands/create.py b/superset/databases/ssh_tunnel/commands/create.py new file mode 100644 index 0000000000000..9c17149ba3d00 --- /dev/null +++ b/superset/databases/ssh_tunnel/commands/create.py @@ -0,0 +1,92 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging +from typing import Any, Dict, List, Optional + +from flask_appbuilder.models.sqla import Model +from marshmallow import ValidationError + +from superset.commands.base import BaseCommand +from superset.dao.exceptions import DAOCreateFailedError +from superset.databases.ssh_tunnel.commands.exceptions import ( + SSHTunnelCreateFailedError, + SSHTunnelInvalidError, + SSHTunnelRequiredFieldValidationError, +) +from superset.databases.ssh_tunnel.dao import SSHTunnelDAO +from superset.extensions import db, event_logger + +logger = logging.getLogger(__name__) + + +class CreateSSHTunnelCommand(BaseCommand): + def __init__(self, database_id: int, data: Dict[str, Any]): + self._properties = data.copy() + self._properties["database_id"] = database_id + + def run(self) -> Model: + try: + # Start nested transaction since we are always creating the tunnel + # through a DB command (Create or Update). Without this, we cannot + # safely rollback changes to databases if any, i.e, things like + # test_do_not_create_database_if_ssh_tunnel_creation_fails test will fail + db.session.begin_nested() + self.validate() + tunnel = SSHTunnelDAO.create(self._properties, commit=False) + except DAOCreateFailedError as ex: + # Rollback nested transaction + db.session.rollback() + raise SSHTunnelCreateFailedError() from ex + except SSHTunnelInvalidError as ex: + # Rollback nested transaction + db.session.rollback() + raise ex + + return tunnel + + def validate(self) -> None: + # TODO(hughhh): check to make sure the server port is not localhost + # using the config.SSH_TUNNEL_MANAGER + exceptions: List[ValidationError] = [] + database_id: Optional[int] = self._properties.get("database_id") + server_address: Optional[str] = self._properties.get("server_address") + server_port: Optional[int] = self._properties.get("server_port") + username: Optional[str] = self._properties.get("username") + private_key: Optional[str] = self._properties.get("private_key") + private_key_password: Optional[str] = self._properties.get( + "private_key_password" + ) + if not database_id: + exceptions.append(SSHTunnelRequiredFieldValidationError("database_id")) + if not server_address: + exceptions.append(SSHTunnelRequiredFieldValidationError("server_address")) + if not server_port: + exceptions.append(SSHTunnelRequiredFieldValidationError("server_port")) + if not username: + exceptions.append(SSHTunnelRequiredFieldValidationError("username")) + if private_key_password and private_key is None: + exceptions.append(SSHTunnelRequiredFieldValidationError("private_key")) + if exceptions: + exception = SSHTunnelInvalidError() + exception.add_list(exceptions) + event_logger.log_with_context( + action="ssh_tunnel_creation_failed.{}.{}".format( + exception.__class__.__name__, + ".".join(exception.get_list_classnames()), + ) + ) + raise exception diff --git a/superset/databases/ssh_tunnel/commands/delete.py b/superset/databases/ssh_tunnel/commands/delete.py new file mode 100644 index 0000000000000..235ceb697bede --- /dev/null +++ b/superset/databases/ssh_tunnel/commands/delete.py @@ -0,0 +1,55 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging +from typing import Optional + +from flask_appbuilder.models.sqla import Model + +from superset import is_feature_enabled +from superset.commands.base import BaseCommand +from superset.dao.exceptions import DAODeleteFailedError +from superset.databases.ssh_tunnel.commands.exceptions import ( + SSHTunnelDeleteFailedError, + SSHTunnelingNotEnabledError, + SSHTunnelNotFoundError, +) +from superset.databases.ssh_tunnel.dao import SSHTunnelDAO +from superset.databases.ssh_tunnel.models import SSHTunnel + +logger = logging.getLogger(__name__) + + +class DeleteSSHTunnelCommand(BaseCommand): + def __init__(self, model_id: int): + self._model_id = model_id + self._model: Optional[SSHTunnel] = None + + def run(self) -> Model: + if not is_feature_enabled("SSH_TUNNELING"): + raise SSHTunnelingNotEnabledError() + self.validate() + try: + ssh_tunnel = SSHTunnelDAO.delete(self._model) + except DAODeleteFailedError as ex: + raise SSHTunnelDeleteFailedError() from ex + return ssh_tunnel + + def validate(self) -> None: + # Validate/populate model exists + self._model = SSHTunnelDAO.find_by_id(self._model_id) + if not self._model: + raise SSHTunnelNotFoundError() diff --git a/superset/databases/ssh_tunnel/commands/exceptions.py b/superset/databases/ssh_tunnel/commands/exceptions.py new file mode 100644 index 0000000000000..2495961c369a2 --- /dev/null +++ b/superset/databases/ssh_tunnel/commands/exceptions.py @@ -0,0 +1,59 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from flask_babel import lazy_gettext as _ +from marshmallow import ValidationError + +from superset.commands.exceptions import ( + CommandException, + CommandInvalidError, + DeleteFailedError, + UpdateFailedError, +) + + +class SSHTunnelDeleteFailedError(DeleteFailedError): + message = _("SSH Tunnel could not be deleted.") + + +class SSHTunnelNotFoundError(CommandException): + status = 404 + message = _("SSH Tunnel not found.") + + +class SSHTunnelInvalidError(CommandInvalidError): + message = _("SSH Tunnel parameters are invalid.") + + +class SSHTunnelUpdateFailedError(UpdateFailedError): + message = _("SSH Tunnel could not be updated.") + + +class SSHTunnelCreateFailedError(CommandException): + message = _("Creating SSH Tunnel failed for an unknown reason") + + +class SSHTunnelingNotEnabledError(CommandException): + status = 400 + message = _("SSH Tunneling is not enabled") + + +class SSHTunnelRequiredFieldValidationError(ValidationError): + def __init__(self, field_name: str) -> None: + super().__init__( + [_("Field is required")], + field_name=field_name, + ) diff --git a/superset/databases/ssh_tunnel/commands/update.py b/superset/databases/ssh_tunnel/commands/update.py new file mode 100644 index 0000000000000..2ac7856705401 --- /dev/null +++ b/superset/databases/ssh_tunnel/commands/update.py @@ -0,0 +1,63 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging +from typing import Any, Dict, Optional + +from flask_appbuilder.models.sqla import Model + +from superset.commands.base import BaseCommand +from superset.dao.exceptions import DAOUpdateFailedError +from superset.databases.ssh_tunnel.commands.exceptions import ( + SSHTunnelInvalidError, + SSHTunnelNotFoundError, + SSHTunnelRequiredFieldValidationError, + SSHTunnelUpdateFailedError, +) +from superset.databases.ssh_tunnel.dao import SSHTunnelDAO +from superset.databases.ssh_tunnel.models import SSHTunnel + +logger = logging.getLogger(__name__) + + +class UpdateSSHTunnelCommand(BaseCommand): + def __init__(self, model_id: int, data: Dict[str, Any]): + self._properties = data.copy() + self._model_id = model_id + self._model: Optional[SSHTunnel] = None + + def run(self) -> Model: + self.validate() + try: + if self._model is not None: # So we dont get incompatible types error + tunnel = SSHTunnelDAO.update(self._model, self._properties) + except DAOUpdateFailedError as ex: + raise SSHTunnelUpdateFailedError() from ex + return tunnel + + def validate(self) -> None: + # Validate/populate model exists + self._model = SSHTunnelDAO.find_by_id(self._model_id) + if not self._model: + raise SSHTunnelNotFoundError() + private_key: Optional[str] = self._properties.get("private_key") + private_key_password: Optional[str] = self._properties.get( + "private_key_password" + ) + if private_key_password and private_key is None: + exception = SSHTunnelInvalidError() + exception.add(SSHTunnelRequiredFieldValidationError("private_key")) + raise exception diff --git a/superset/databases/ssh_tunnel/dao.py b/superset/databases/ssh_tunnel/dao.py new file mode 100644 index 0000000000000..89562fc05dcc0 --- /dev/null +++ b/superset/databases/ssh_tunnel/dao.py @@ -0,0 +1,49 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging +from typing import Any, Dict + +from superset.dao.base import BaseDAO +from superset.databases.ssh_tunnel.models import SSHTunnel +from superset.utils.ssh_tunnel import unmask_password_info + +logger = logging.getLogger(__name__) + + +class SSHTunnelDAO(BaseDAO): + model_cls = SSHTunnel + + @classmethod + def update( + cls, + model: SSHTunnel, + properties: Dict[str, Any], + commit: bool = True, + ) -> SSHTunnel: + """ + Unmask ``password``, ``private_key`` and ``private_key_password`` before updating. + + When a database is edited the user sees a masked version of + the aforementioned fields. + + The masked values should be unmasked before the ssh tunnel is updated. + """ + # ID cannot be updated so we remove it if present in the payload + properties.pop("id", None) + properties = unmask_password_info(properties, model) + + return super().update(model, properties, commit) diff --git a/superset/databases/ssh_tunnel/models.py b/superset/databases/ssh_tunnel/models.py new file mode 100644 index 0000000000000..727b6ea467c6a --- /dev/null +++ b/superset/databases/ssh_tunnel/models.py @@ -0,0 +1,85 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from typing import Any, Dict + +import sqlalchemy as sa +from flask import current_app +from flask_appbuilder import Model +from sqlalchemy.orm import backref, relationship +from sqlalchemy_utils import EncryptedType + +from superset.constants import PASSWORD_MASK +from superset.models.core import Database +from superset.models.helpers import ( + AuditMixinNullable, + ExtraJSONMixin, + ImportExportMixin, +) + +app_config = current_app.config + + +class SSHTunnel(Model, AuditMixinNullable, ExtraJSONMixin, ImportExportMixin): + """ + A ssh tunnel configuration in a database. + """ + + __tablename__ = "ssh_tunnels" + + id = sa.Column(sa.Integer, primary_key=True) + database_id = sa.Column( + sa.Integer, sa.ForeignKey("dbs.id"), nullable=False, unique=True + ) + database: Database = relationship( + "Database", + backref=backref("ssh_tunnels", uselist=False, cascade="all, delete-orphan"), + foreign_keys=[database_id], + ) + + server_address = sa.Column(sa.Text) + server_port = sa.Column(sa.Integer) + username = sa.Column(EncryptedType(sa.String, app_config["SECRET_KEY"])) + + # basic authentication + password = sa.Column( + EncryptedType(sa.String, app_config["SECRET_KEY"]), nullable=True + ) + + # password protected pkey authentication + private_key = sa.Column( + EncryptedType(sa.String, app_config["SECRET_KEY"]), nullable=True + ) + private_key_password = sa.Column( + EncryptedType(sa.String, app_config["SECRET_KEY"]), nullable=True + ) + + @property + def data(self) -> Dict[str, Any]: + output = { + "id": self.id, + "server_address": self.server_address, + "server_port": self.server_port, + "username": self.username, + } + if self.password is not None: + output["password"] = PASSWORD_MASK + if self.private_key is not None: + output["private_key"] = PASSWORD_MASK + if self.private_key_password is not None: + output["private_key_password"] = PASSWORD_MASK + return output diff --git a/superset/datasets/api.py b/superset/datasets/api.py index c582788ebcfab..b766029872432 100644 --- a/superset/datasets/api.py +++ b/superset/datasets/api.py @@ -21,9 +21,8 @@ from typing import Any from zipfile import is_zipfile, ZipFile -import simplejson import yaml -from flask import g, make_response, request, Response, send_file +from flask import request, Response, send_file from flask_appbuilder.api import expose, protect, rison, safe from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_babel import ngettext @@ -38,6 +37,7 @@ from superset.datasets.commands.bulk_delete import BulkDeleteDatasetCommand from superset.datasets.commands.create import CreateDatasetCommand from superset.datasets.commands.delete import DeleteDatasetCommand +from superset.datasets.commands.duplicate import DuplicateDatasetCommand from superset.datasets.commands.exceptions import ( DatasetBulkDeleteFailedError, DatasetCreateFailedError, @@ -46,24 +46,24 @@ DatasetInvalidError, DatasetNotFoundError, DatasetRefreshFailedError, - DatasetSamplesFailedError, DatasetUpdateFailedError, ) from superset.datasets.commands.export import ExportDatasetsCommand from superset.datasets.commands.importers.dispatcher import ImportDatasetsCommand from superset.datasets.commands.refresh import RefreshDatasetCommand -from superset.datasets.commands.samples import SamplesDatasetCommand from superset.datasets.commands.update import UpdateDatasetCommand from superset.datasets.dao import DatasetDAO from superset.datasets.filters import DatasetCertifiedFilter, DatasetIsNullOrEmptyFilter from superset.datasets.schemas import ( + DatasetDuplicateSchema, DatasetPostSchema, DatasetPutSchema, DatasetRelatedObjectsResponse, get_delete_ids_schema, get_export_ids_schema, + GetOrCreateDatasetSchema, ) -from superset.utils.core import json_int_dttm_ser, parse_boolean_string +from superset.utils.core import parse_boolean_string from superset.views.base import DatasourceFilter, generate_download_headers from superset.views.base_api import ( BaseSupersetModelRestApi, @@ -72,7 +72,7 @@ requires_json, statsd_metrics, ) -from superset.views.filters import FilterRelatedOwners +from superset.views.filters import BaseFilterRelatedUsers, FilterRelatedOwners logger = logging.getLogger(__name__) @@ -93,7 +93,8 @@ class DatasetRestApi(BaseSupersetModelRestApi): "bulk_delete", "refresh", "related_objects", - "samples", + "duplicate", + "get_or_create_dataset", } list_columns = [ "id", @@ -143,10 +144,12 @@ class DatasetRestApi(BaseSupersetModelRestApi): "cache_timeout", "is_sqllab_view", "template_params", + "select_star", "owners.id", "owners.username", "owners.first_name", "owners.last_name", + "columns.advanced_data_type", "columns.changed_on", "columns.column_name", "columns.created_on", @@ -162,11 +165,30 @@ class DatasetRestApi(BaseSupersetModelRestApi): "columns.type", "columns.uuid", "columns.verbose_name", - "metrics", + "metrics", # TODO(john-bodley): Deprecate in 3.0. + "metrics.changed_on", + "metrics.created_on", + "metrics.d3format", + "metrics.description", + "metrics.expression", + "metrics.extra", + "metrics.id", + "metrics.metric_name", + "metrics.metric_type", + "metrics.verbose_name", + "metrics.warning_text", "datasource_type", "url", "extra", "kind", + "created_on", + "created_on_humanized", + "created_by.first_name", + "created_by.last_name", + "changed_on", + "changed_on_humanized", + "changed_by.first_name", + "changed_by.last_name", ] show_columns = show_select_columns + [ "columns.type_generic", @@ -176,7 +198,8 @@ class DatasetRestApi(BaseSupersetModelRestApi): ] add_model_schema = DatasetPostSchema() edit_model_schema = DatasetPutSchema() - add_columns = ["database", "schema", "table_name", "owners"] + duplicate_model_schema = DatasetDuplicateSchema() + add_columns = ["database", "schema", "table_name", "sql", "owners"] edit_columns = [ "table_name", "sql", @@ -196,6 +219,11 @@ class DatasetRestApi(BaseSupersetModelRestApi): "extra", ] openapi_spec_tag = "Datasets" + + base_related_field_filters = { + "owners": [["id", BaseFilterRelatedUsers, lambda: []]], + "database": [["id", DatabaseFilter, lambda: []]], + } related_field_filters = { "owners": RelatedFieldFilter("first_name", FilterRelatedOwners), "database": "database_name", @@ -212,7 +240,14 @@ class DatasetRestApi(BaseSupersetModelRestApi): apispec_parameter_schemas = { "get_export_ids_schema": get_export_ids_schema, } - openapi_spec_component_schemas = (DatasetRelatedObjectsResponse,) + openapi_spec_component_schemas = ( + DatasetRelatedObjectsResponse, + DatasetDuplicateSchema, + GetOrCreateDatasetSchema, + ) + + list_outer_default_load = True + show_outer_default_load = True @expose("/", methods=["POST"]) @protect() @@ -264,7 +299,7 @@ def post(self) -> Response: return self.response_400(message=error.messages) try: - new_model = CreateDatasetCommand(g.user, item).run() + new_model = CreateDatasetCommand(item).run() return self.response(201, id=new_model.id, result=item) except DatasetInvalidError as ex: return self.response_422(message=ex.normalized_messages()) @@ -344,11 +379,9 @@ def put(self, pk: int) -> Response: except ValidationError as error: return self.response_400(message=error.messages) try: - changed_model = UpdateDatasetCommand( - g.user, pk, item, override_columns - ).run() + changed_model = UpdateDatasetCommand(pk, item, override_columns).run() if override_columns: - RefreshDatasetCommand(g.user, pk).run() + RefreshDatasetCommand(pk).run() response = self.response(200, id=changed_model.id, result=item) except DatasetNotFoundError: response = self.response_404() @@ -407,7 +440,7 @@ def delete(self, pk: int) -> Response: $ref: '#/components/responses/500' """ try: - DeleteDatasetCommand(g.user, pk).run() + DeleteDatasetCommand(pk).run() return self.response(200, message="OK") except DatasetNotFoundError: return self.response_404() @@ -506,6 +539,77 @@ def export(self, **kwargs: Any) -> Response: mimetype="application/text", ) + @expose("/duplicate", methods=["POST"]) + @protect() + @safe + @statsd_metrics + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" f".duplicate", + log_to_statsd=False, + ) + @requires_json + def duplicate(self) -> Response: + """Duplicates a Dataset + --- + post: + description: >- + Duplicates a Dataset + requestBody: + description: Dataset schema + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DatasetDuplicateSchema' + responses: + 201: + description: Dataset duplicated + content: + application/json: + schema: + type: object + properties: + id: + type: number + result: + $ref: '#/components/schemas/DatasetDuplicateSchema' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 403: + $ref: '#/components/responses/403' + 404: + $ref: '#/components/responses/404' + 422: + $ref: '#/components/responses/422' + 500: + $ref: '#/components/responses/500' + """ + try: + item = self.duplicate_model_schema.load(request.json) + # This validates custom Schema with custom validations + except ValidationError as error: + return self.response_400(message=error.messages) + + try: + new_model = DuplicateDatasetCommand(item).run() + return self.response(201, id=new_model.id, result=item) + except DatasetInvalidError as ex: + return self.response_422( + message=ex.normalized_messages() + if isinstance(ex, ValidationError) + else str(ex) + ) + except DatasetCreateFailedError as ex: + logger.error( + "Error creating model %s: %s", + self.__class__.__name__, + str(ex), + exc_info=True, + ) + return self.response_422(message=str(ex)) + @expose("/<pk>/refresh", methods=["PUT"]) @protect() @safe @@ -547,7 +651,7 @@ def refresh(self, pk: int) -> Response: $ref: '#/components/responses/500' """ try: - RefreshDatasetCommand(g.user, pk).run() + RefreshDatasetCommand(pk).run() return self.response(200, message="OK") except DatasetNotFoundError: return self.response_404() @@ -671,7 +775,7 @@ def bulk_delete(self, **kwargs: Any) -> Response: """ item_ids = kwargs["rison"] try: - BulkDeleteDatasetCommand(g.user, item_ids).run() + BulkDeleteDatasetCommand(item_ids).run() return self.response( 200, message=ngettext( @@ -778,64 +882,69 @@ def import_(self) -> Response: command.run() return self.response(200, message="OK") - @expose("/<pk>/samples") + @expose("/get_or_create/", methods=["POST"]) @protect() @safe @statsd_metrics @event_logger.log_this_with_context( - action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.samples", + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" + f".get_or_create_dataset", log_to_statsd=False, ) - def samples(self, pk: int) -> Response: - """get samples from a Dataset + def get_or_create_dataset(self) -> Response: + """Retrieve a dataset by name, or create it if it does not exist --- - get: - description: >- - get samples from a Dataset - parameters: - - in: path - schema: - type: integer - name: pk - - in: query - schema: - type: boolean - name: force + post: + summary: Retrieve a table by name, or create it if it does not exist + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GetOrCreateDatasetSchema' responses: 200: - description: Dataset samples + description: The ID of the table content: application/json: schema: type: object properties: result: - $ref: '#/components/schemas/ChartDataResponseResult' + type: object + properties: + table_id: + type: integer + 400: + $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' - 403: - $ref: '#/components/responses/403' - 404: - $ref: '#/components/responses/404' 422: $ref: '#/components/responses/422' 500: $ref: '#/components/responses/500' """ try: - force = parse_boolean_string(request.args.get("force")) - rv = SamplesDatasetCommand(g.user, pk, force).run() - response_data = simplejson.dumps( - {"result": rv}, - default=json_int_dttm_ser, - ignore_nan=True, + body = GetOrCreateDatasetSchema().load(request.json) + except ValidationError as ex: + return self.response(400, message=ex.messages) + table_name = body["table_name"] + database_id = body["database_id"] + table = DatasetDAO.get_table_by_name(database_id, table_name) + if table: + return self.response(200, result={"table_id": table.id}) + + body["database"] = database_id + try: + tbl = CreateDatasetCommand(body).run() + return self.response(200, result={"table_id": tbl.id}) + except DatasetInvalidError as ex: + return self.response_422(message=ex.normalized_messages()) + except DatasetCreateFailedError as ex: + logger.error( + "Error creating model %s: %s", + self.__class__.__name__, + str(ex), + exc_info=True, ) - resp = make_response(response_data, 200) - resp.headers["Content-Type"] = "application/json; charset=utf-8" - return resp - except DatasetNotFoundError: - return self.response_404() - except DatasetForbiddenError: - return self.response_403() - except DatasetSamplesFailedError as ex: - return self.response_400(message=str(ex)) + return self.response_422(message=ex.message) diff --git a/superset/datasets/columns/api.py b/superset/datasets/columns/api.py index d04827d42f7e4..cd260a423bd72 100644 --- a/superset/datasets/columns/api.py +++ b/superset/datasets/columns/api.py @@ -16,7 +16,7 @@ # under the License. import logging -from flask import g, Response +from flask import Response from flask_appbuilder.api import expose, permission_name, protect, safe from flask_appbuilder.models.sqla.interface import SQLAInterface @@ -91,7 +91,7 @@ def delete( # pylint: disable=arguments-differ $ref: '#/components/responses/500' """ try: - DeleteDatasetColumnCommand(g.user, pk, column_id).run() + DeleteDatasetColumnCommand(pk, column_id).run() return self.response(200, message="OK") except DatasetColumnNotFoundError: return self.response_404() diff --git a/superset/datasets/columns/commands/delete.py b/superset/datasets/columns/commands/delete.py index f5914af5277ff..8fb27f9386489 100644 --- a/superset/datasets/columns/commands/delete.py +++ b/superset/datasets/columns/commands/delete.py @@ -18,8 +18,8 @@ from typing import Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User +from superset import security_manager from superset.commands.base import BaseCommand from superset.connectors.sqla.models import TableColumn from superset.dao.exceptions import DAODeleteFailedError @@ -30,14 +30,12 @@ ) from superset.datasets.dao import DatasetDAO from superset.exceptions import SupersetSecurityException -from superset.views.base import check_ownership logger = logging.getLogger(__name__) class DeleteDatasetColumnCommand(BaseCommand): - def __init__(self, user: User, dataset_id: int, model_id: int): - self._actor = user + def __init__(self, dataset_id: int, model_id: int): self._dataset_id = dataset_id self._model_id = model_id self._model: Optional[TableColumn] = None @@ -60,6 +58,6 @@ def validate(self) -> None: raise DatasetColumnNotFoundError() # Check ownership try: - check_ownership(self._model) + security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise DatasetColumnForbiddenError() from ex diff --git a/superset/datasets/commands/bulk_delete.py b/superset/datasets/commands/bulk_delete.py index 13608eda810c9..643ac784ec3b3 100644 --- a/superset/datasets/commands/bulk_delete.py +++ b/superset/datasets/commands/bulk_delete.py @@ -17,8 +17,7 @@ import logging from typing import List, Optional -from flask_appbuilder.security.sqla.models import User - +from superset import security_manager from superset.commands.base import BaseCommand from superset.commands.exceptions import DeleteFailedError from superset.connectors.sqla.models import SqlaTable @@ -29,15 +28,13 @@ ) from superset.datasets.dao import DatasetDAO from superset.exceptions import SupersetSecurityException -from superset.extensions import db, security_manager -from superset.views.base import check_ownership +from superset.extensions import db logger = logging.getLogger(__name__) class BulkDeleteDatasetCommand(BaseCommand): - def __init__(self, user: User, model_ids: List[int]): - self._actor = user + def __init__(self, model_ids: List[int]): self._model_ids = model_ids self._models: Optional[List[SqlaTable]] = None @@ -84,6 +81,6 @@ def validate(self) -> None: # Check ownership for model in self._models: try: - check_ownership(model) + security_manager.raise_for_ownership(model) except SupersetSecurityException as ex: raise DatasetForbiddenError() from ex diff --git a/superset/datasets/commands/create.py b/superset/datasets/commands/create.py index 4a89b1a818394..809eec7a1159a 100644 --- a/superset/datasets/commands/create.py +++ b/superset/datasets/commands/create.py @@ -18,7 +18,6 @@ from typing import Any, Dict, List, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError from sqlalchemy.exc import SQLAlchemyError @@ -32,14 +31,13 @@ TableNotFoundValidationError, ) from superset.datasets.dao import DatasetDAO -from superset.extensions import db, security_manager +from superset.extensions import db logger = logging.getLogger(__name__) class CreateDatasetCommand(CreateMixin, BaseCommand): - def __init__(self, user: User, data: Dict[str, Any]): - self._actor = user + def __init__(self, data: Dict[str, Any]): self._properties = data.copy() def run(self) -> Model: @@ -49,15 +47,6 @@ def run(self) -> Model: dataset = DatasetDAO.create(self._properties, commit=False) # Updates columns and metrics from the dataset dataset.fetch_metadata(commit=False) - # Add datasource access permission - security_manager.add_permission_view_menu( - "datasource_access", dataset.get_perm() - ) - # Add schema access permission if exists - if dataset.schema: - security_manager.add_permission_view_menu( - "schema_access", dataset.schema_perm - ) db.session.commit() except (SQLAlchemyError, DAOCreateFailedError) as ex: logger.warning(ex, exc_info=True) @@ -70,6 +59,7 @@ def validate(self) -> None: database_id = self._properties["database"] table_name = self._properties["table_name"] schema = self._properties.get("schema", None) + sql = self._properties.get("sql", None) owner_ids: Optional[List[int]] = self._properties.get("owners") # Validate uniqueness @@ -82,14 +72,17 @@ def validate(self) -> None: exceptions.append(DatabaseNotFoundValidationError()) self._properties["database"] = database - # Validate table exists on dataset - if database and not DatasetDAO.validate_table_exists( - database, table_name, schema + # Validate table exists on dataset if sql is not provided + # This should be validated when the dataset is physical + if ( + database + and not sql + and not DatasetDAO.validate_table_exists(database, table_name, schema) ): exceptions.append(TableNotFoundValidationError(table_name)) try: - owners = self.populate_owners(self._actor, owner_ids) + owners = self.populate_owners(owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) diff --git a/superset/datasets/commands/delete.py b/superset/datasets/commands/delete.py index a9e5a0ab5aba6..6f91567958135 100644 --- a/superset/datasets/commands/delete.py +++ b/superset/datasets/commands/delete.py @@ -18,9 +18,9 @@ from typing import Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from sqlalchemy.exc import SQLAlchemyError +from superset import security_manager from superset.commands.base import BaseCommand from superset.connectors.sqla.models import SqlaTable from superset.dao.exceptions import DAODeleteFailedError @@ -31,15 +31,13 @@ ) from superset.datasets.dao import DatasetDAO from superset.exceptions import SupersetSecurityException -from superset.extensions import db, security_manager -from superset.views.base import check_ownership +from superset.extensions import db logger = logging.getLogger(__name__) class DeleteDatasetCommand(BaseCommand): - def __init__(self, user: User, model_id: int): - self._actor = user + def __init__(self, model_id: int): self._model_id = model_id self._model: Optional[SqlaTable] = None @@ -47,30 +45,6 @@ def run(self) -> Model: self.validate() try: dataset = DatasetDAO.delete(self._model, commit=False) - - view_menu = ( - security_manager.find_view_menu(self._model.get_perm()) - if self._model - else None - ) - - if view_menu: - permission_views = ( - db.session.query(security_manager.permissionview_model) - .filter_by(view_menu=view_menu) - .all() - ) - - for permission_view in permission_views: - db.session.delete(permission_view) - if view_menu: - db.session.delete(view_menu) - else: - if not view_menu: - logger.error( - "Could not find the data access permission for the dataset", - exc_info=True, - ) db.session.commit() except (SQLAlchemyError, DAODeleteFailedError) as ex: logger.exception(ex) @@ -85,6 +59,6 @@ def validate(self) -> None: raise DatasetNotFoundError() # Check ownership try: - check_ownership(self._model) + security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise DatasetForbiddenError() from ex diff --git a/superset/datasets/commands/duplicate.py b/superset/datasets/commands/duplicate.py new file mode 100644 index 0000000000000..c6b0bbea69257 --- /dev/null +++ b/superset/datasets/commands/duplicate.py @@ -0,0 +1,133 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging +from typing import Any, Dict, List + +from flask_appbuilder.models.sqla import Model +from flask_babel import gettext as __ +from marshmallow import ValidationError +from sqlalchemy.exc import SQLAlchemyError + +from superset.commands.base import BaseCommand, CreateMixin +from superset.commands.exceptions import DatasourceTypeInvalidError +from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn +from superset.dao.exceptions import DAOCreateFailedError +from superset.datasets.commands.exceptions import ( + DatasetDuplicateFailedError, + DatasetExistsValidationError, + DatasetInvalidError, + DatasetNotFoundError, +) +from superset.datasets.dao import DatasetDAO +from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.exceptions import SupersetErrorException +from superset.extensions import db +from superset.models.core import Database +from superset.sql_parse import ParsedQuery + +logger = logging.getLogger(__name__) + + +class DuplicateDatasetCommand(CreateMixin, BaseCommand): + def __init__(self, data: Dict[str, Any]) -> None: + self._base_model: SqlaTable = SqlaTable() + self._properties = data.copy() + + def run(self) -> Model: + self.validate() + try: + database_id = self._base_model.database_id + table_name = self._properties["table_name"] + owners = self._properties["owners"] + database = db.session.query(Database).get(database_id) + if not database: + raise SupersetErrorException( + SupersetError( + message=__("The database was not found."), + error_type=SupersetErrorType.DATABASE_NOT_FOUND_ERROR, + level=ErrorLevel.ERROR, + ), + status=404, + ) + table = SqlaTable(table_name=table_name, owners=owners) + table.database = database + table.schema = self._base_model.schema + table.template_params = self._base_model.template_params + table.is_sqllab_view = True + table.sql = ParsedQuery(self._base_model.sql).stripped() + db.session.add(table) + cols = [] + for config_ in self._base_model.columns: + column_name = config_.column_name + col = TableColumn( + column_name=column_name, + verbose_name=config_.verbose_name, + expression=config_.expression, + filterable=True, + groupby=True, + is_dttm=config_.is_dttm, + type=config_.type, + description=config_.description, + ) + cols.append(col) + table.columns = cols + mets = [] + for config_ in self._base_model.metrics: + metric_name = config_.metric_name + met = SqlMetric( + metric_name=metric_name, + verbose_name=config_.verbose_name, + expression=config_.expression, + metric_type=config_.metric_type, + description=config_.description, + ) + mets.append(met) + table.metrics = mets + db.session.commit() + except (SQLAlchemyError, DAOCreateFailedError) as ex: + logger.warning(ex, exc_info=True) + db.session.rollback() + raise DatasetDuplicateFailedError() from ex + return table + + def validate(self) -> None: + exceptions: List[ValidationError] = [] + base_model_id = self._properties["base_model_id"] + duplicate_name = self._properties["table_name"] + + base_model = DatasetDAO.find_by_id(base_model_id) + if not base_model: + exceptions.append(DatasetNotFoundError()) + else: + self._base_model = base_model + + if self._base_model and self._base_model.kind != "virtual": + exceptions.append(DatasourceTypeInvalidError()) + + if DatasetDAO.find_one_or_none(table_name=duplicate_name): + exceptions.append(DatasetExistsValidationError(table_name=duplicate_name)) + + try: + owners = self.populate_owners() + self._properties["owners"] = owners + except ValidationError as ex: + exceptions.append(ex) + + if exceptions: + exception = DatasetInvalidError() + exception.add_list(exceptions) + raise exception diff --git a/superset/datasets/commands/exceptions.py b/superset/datasets/commands/exceptions.py index b743a4355ea06..91af2fdde4e9c 100644 --- a/superset/datasets/commands/exceptions.py +++ b/superset/datasets/commands/exceptions.py @@ -187,3 +187,11 @@ class DatasetImportError(ImportFailedError): class DatasetAccessDeniedError(ForbiddenError): message = _("You don't have access to this dataset.") + + +class DatasetDuplicateFailedError(CreateFailedError): + message = _("Dataset could not be duplicated.") + + +class DatasetForbiddenDataURI(ImportFailedError): + message = _("Data URI is not allowed.") diff --git a/superset/datasets/commands/export.py b/superset/datasets/commands/export.py index be9210a06c669..b71a95936ab1d 100644 --- a/superset/datasets/commands/export.py +++ b/superset/datasets/commands/export.py @@ -21,13 +21,13 @@ from typing import Iterator, Tuple import yaml -from werkzeug.utils import secure_filename from superset.commands.export.models import ExportModelsCommand from superset.connectors.sqla.models import SqlaTable from superset.datasets.commands.exceptions import DatasetNotFoundError from superset.datasets.dao import DatasetDAO from superset.utils.dict_import_export import EXPORT_VERSION +from superset.utils.file import get_filename logger = logging.getLogger(__name__) @@ -43,9 +43,11 @@ class ExportDatasetsCommand(ExportModelsCommand): def _export( model: SqlaTable, export_related: bool = True ) -> Iterator[Tuple[str, str]]: - database_slug = secure_filename(model.database.database_name) - dataset_slug = secure_filename(model.table_name) - file_name = f"datasets/{database_slug}/{dataset_slug}.yaml" + db_file_name = get_filename( + model.database.database_name, model.database.id, skip_id=True + ) + ds_file_name = get_filename(model.table_name, model.id, skip_id=True) + file_path = f"datasets/{db_file_name}/{ds_file_name}.yaml" payload = model.export_to_dict( recursive=True, @@ -75,11 +77,11 @@ def _export( payload["database_uuid"] = str(model.database.uuid) file_content = yaml.safe_dump(payload, sort_keys=False) - yield file_name, file_content + yield file_path, file_content # include database as well if export_related: - file_name = f"databases/{database_slug}.yaml" + file_path = f"databases/{db_file_name}.yaml" payload = model.database.export_to_dict( recursive=False, @@ -98,4 +100,4 @@ def _export( payload["version"] = EXPORT_VERSION file_content = yaml.safe_dump(payload, sort_keys=False) - yield file_name, file_content + yield file_path, file_content diff --git a/superset/datasets/commands/importers/v0.py b/superset/datasets/commands/importers/v0.py index 74b9ca0a6abb6..f706ecf38bcf7 100644 --- a/superset/datasets/commands/importers/v0.py +++ b/superset/datasets/commands/importers/v0.py @@ -139,7 +139,7 @@ def import_datasource( # pylint: disable=too-many-arguments ) -> int: """Imports the datasource from the object to the database. - Metrics and columns and datasource will be overrided if exists. + Metrics and columns and datasource will be overridden if exists. This function can be used to import/export datasources between multiple superset instances. Audit metadata isn't copies over. """ diff --git a/superset/datasets/commands/importers/v1/utils.py b/superset/datasets/commands/importers/v1/utils.py index ba2b7df26174a..b3fb2a804127b 100644 --- a/superset/datasets/commands/importers/v1/utils.py +++ b/superset/datasets/commands/importers/v1/utils.py @@ -29,6 +29,7 @@ from sqlalchemy.sql.visitors import VisitableType from superset.connectors.sqla.models import SqlaTable +from superset.datasets.commands.exceptions import DatasetForbiddenDataURI from superset.models.core import Database logger = logging.getLogger(__name__) @@ -75,6 +76,28 @@ def get_dtype(df: pd.DataFrame, dataset: SqlaTable) -> Dict[str, VisitableType]: } +def validate_data_uri(data_uri: str) -> None: + """ + Validate that the data URI is configured on DATASET_IMPORT_ALLOWED_URLS + has a valid URL. + + :param data_uri: + :return: + """ + allowed_urls = current_app.config["DATASET_IMPORT_ALLOWED_DATA_URLS"] + for allowed_url in allowed_urls: + try: + match = re.match(allowed_url, data_uri) + except re.error: + logger.exception( + "Invalid regular expression on DATASET_IMPORT_ALLOWED_URLS" + ) + raise + if match: + return + raise DatasetForbiddenDataURI() + + def import_dataset( session: Session, config: Dict[str, Any], @@ -139,7 +162,6 @@ def import_dataset( table_exists = True if data_uri and (not table_exists or force_data): - logger.info("Downloading data from %s", data_uri) load_data(data_uri, dataset, dataset.database, session) if hasattr(g, "user") and g.user: @@ -151,6 +173,14 @@ def import_dataset( def load_data( data_uri: str, dataset: SqlaTable, database: Database, session: Session ) -> None: + """ + Load data from a data URI into a dataset. + + :raises DatasetUnAllowedDataURI: If a dataset is trying + to load data from a URI that is not allowed. + """ + validate_data_uri(data_uri) + logger.info("Downloading data from %s", data_uri) data = request.urlopen(data_uri) # pylint: disable=consider-using-with if data_uri.endswith(".gz"): data = gzip.open(data) @@ -166,17 +196,26 @@ def load_data( if database.sqlalchemy_uri == current_app.config.get("SQLALCHEMY_DATABASE_URI"): logger.info("Loading data inside the import transaction") connection = session.connection() + df.to_sql( + dataset.table_name, + con=connection, + schema=dataset.schema, + if_exists="replace", + chunksize=CHUNKSIZE, + dtype=dtype, + index=False, + method="multi", + ) else: logger.warning("Loading data outside the import transaction") - connection = database.get_sqla_engine() - - df.to_sql( - dataset.table_name, - con=connection, - schema=dataset.schema, - if_exists="replace", - chunksize=CHUNKSIZE, - dtype=dtype, - index=False, - method="multi", - ) + with database.get_sqla_engine_with_context() as engine: + df.to_sql( + dataset.table_name, + con=engine, + schema=dataset.schema, + if_exists="replace", + chunksize=CHUNKSIZE, + dtype=dtype, + index=False, + method="multi", + ) diff --git a/superset/datasets/commands/refresh.py b/superset/datasets/commands/refresh.py index 962ffb4109021..5277c27771c90 100644 --- a/superset/datasets/commands/refresh.py +++ b/superset/datasets/commands/refresh.py @@ -18,8 +18,8 @@ from typing import Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User +from superset import security_manager from superset.commands.base import BaseCommand from superset.connectors.sqla.models import SqlaTable from superset.datasets.commands.exceptions import ( @@ -29,14 +29,12 @@ ) from superset.datasets.dao import DatasetDAO from superset.exceptions import SupersetSecurityException -from superset.views.base import check_ownership logger = logging.getLogger(__name__) class RefreshDatasetCommand(BaseCommand): - def __init__(self, user: User, model_id: int): - self._actor = user + def __init__(self, model_id: int): self._model_id = model_id self._model: Optional[SqlaTable] = None @@ -58,6 +56,6 @@ def validate(self) -> None: raise DatasetNotFoundError() # Check ownership try: - check_ownership(self._model) + security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise DatasetForbiddenError() from ex diff --git a/superset/datasets/commands/samples.py b/superset/datasets/commands/samples.py deleted file mode 100644 index 79ac729be0801..0000000000000 --- a/superset/datasets/commands/samples.py +++ /dev/null @@ -1,83 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -import logging -from typing import Any, Dict, Optional - -from flask_appbuilder.security.sqla.models import User - -from superset.commands.base import BaseCommand -from superset.common.chart_data import ChartDataResultType -from superset.common.query_context_factory import QueryContextFactory -from superset.common.utils.query_cache_manager import QueryCacheManager -from superset.connectors.sqla.models import SqlaTable -from superset.constants import CacheRegion -from superset.datasets.commands.exceptions import ( - DatasetForbiddenError, - DatasetNotFoundError, - DatasetSamplesFailedError, -) -from superset.datasets.dao import DatasetDAO -from superset.exceptions import SupersetSecurityException -from superset.utils.core import QueryStatus -from superset.views.base import check_ownership - -logger = logging.getLogger(__name__) - - -class SamplesDatasetCommand(BaseCommand): - def __init__(self, user: User, model_id: int, force: bool): - self._actor = user - self._model_id = model_id - self._force = force - self._model: Optional[SqlaTable] = None - - def run(self) -> Dict[str, Any]: - self.validate() - if not self._model: - raise DatasetNotFoundError() - - qc_instance = QueryContextFactory().create( - datasource={ - "type": self._model.type, - "id": self._model.id, - }, - queries=[{}], - result_type=ChartDataResultType.SAMPLES, - force=self._force, - ) - results = qc_instance.get_payload() - try: - sample_data = results["queries"][0] - error_msg = sample_data.get("error") - if sample_data.get("status") == QueryStatus.FAILED and error_msg: - cache_key = sample_data.get("cache_key") - QueryCacheManager.delete(cache_key, region=CacheRegion.DATA) - raise DatasetSamplesFailedError(error_msg) - return sample_data - except (IndexError, KeyError) as exc: - raise DatasetSamplesFailedError from exc - - def validate(self) -> None: - # Validate/populate model exists - self._model = DatasetDAO.find_by_id(self._model_id) - if not self._model: - raise DatasetNotFoundError() - # Check ownership - try: - check_ownership(self._model) - except SupersetSecurityException as ex: - raise DatasetForbiddenError() from ex diff --git a/superset/datasets/commands/update.py b/superset/datasets/commands/update.py index 9d448a6c19392..483a98e76c3b8 100644 --- a/superset/datasets/commands/update.py +++ b/superset/datasets/commands/update.py @@ -19,9 +19,9 @@ from typing import Any, Dict, List, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError +from superset import security_manager from superset.commands.base import BaseCommand, UpdateMixin from superset.connectors.sqla.models import SqlaTable from superset.dao.exceptions import DAOUpdateFailedError @@ -41,7 +41,6 @@ ) from superset.datasets.dao import DatasetDAO from superset.exceptions import SupersetSecurityException -from superset.views.base import check_ownership logger = logging.getLogger(__name__) @@ -49,16 +48,15 @@ class UpdateDatasetCommand(UpdateMixin, BaseCommand): def __init__( self, - user: User, model_id: int, data: Dict[str, Any], - override_columns: bool = False, + override_columns: Optional[bool] = False, ): - self._actor = user self._model_id = model_id self._properties = data.copy() self._model: Optional[SqlaTable] = None self.override_columns = override_columns + self._properties["override_columns"] = override_columns def run(self) -> Model: self.validate() @@ -83,7 +81,7 @@ def validate(self) -> None: raise DatasetNotFoundError() # Check ownership try: - check_ownership(self._model) + security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise DatasetForbiddenError() from ex @@ -99,7 +97,7 @@ def validate(self) -> None: exceptions.append(DatabaseChangeValidationError()) # Validate/Populate owner try: - owners = self.populate_owners(self._actor, owner_ids) + owners = self.populate_owners(owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) diff --git a/superset/datasets/dao.py b/superset/datasets/dao.py index 44ab8efa0ce54..b158fce1fefe8 100644 --- a/superset/datasets/dao.py +++ b/superset/datasets/dao.py @@ -17,7 +17,6 @@ import logging from typing import Any, Dict, List, Optional -from flask import current_app from sqlalchemy.exc import SQLAlchemyError from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn @@ -36,14 +35,6 @@ class DatasetDAO(BaseDAO): # pylint: disable=too-many-public-methods model_cls = SqlaTable base_filter = DatasourceFilter - @staticmethod - def get_owner_by_id(owner_id: int) -> Optional[object]: - return ( - db.session.query(current_app.appbuilder.sm.user_model) - .filter_by(id=owner_id) - .one_or_none() - ) - @staticmethod def get_database_by_id(database_id: int) -> Optional[Database]: try: @@ -156,21 +147,25 @@ def validate_metrics_uniqueness(dataset_id: int, metrics_names: List[str]) -> bo @classmethod def update( - cls, model: SqlaTable, properties: Dict[str, Any], commit: bool = True + cls, + model: SqlaTable, + properties: Dict[str, Any], + commit: bool = True, ) -> Optional[SqlaTable]: """ Updates a Dataset model on the metadata DB """ if "columns" in properties: - properties["columns"] = cls.update_columns( - model, properties.get("columns", []), commit=commit + cls.update_columns( + model, + properties.pop("columns"), + commit=commit, + override_columns=bool(properties.get("override_columns")), ) if "metrics" in properties: - properties["metrics"] = cls.update_metrics( - model, properties.get("metrics", []), commit=commit - ) + cls.update_metrics(model, properties.pop("metrics"), commit=commit) return super().update(model, properties, commit=commit) @@ -180,7 +175,8 @@ def update_columns( model: SqlaTable, property_columns: List[Dict[str, Any]], commit: bool = True, - ) -> List[TableColumn]: + override_columns: bool = False, + ) -> None: """ Creates/updates and/or deletes a list of columns, based on a list of Dict. @@ -190,21 +186,54 @@ def update_columns( - If there are extra columns on the metadata db that are not defined on the List then we delete. """ - new_columns = [] - for column in property_columns: - column_id = column.get("id") - - if column_id: - column_obj = db.session.query(TableColumn).get(column_id) - column_obj = DatasetDAO.update_column(column_obj, column, commit=commit) - else: - column_obj = DatasetDAO.create_column(column, commit=commit) - new_columns.append(column_obj) - # Checks if an exiting column is missing from properties and delete it - for existing_column in model.columns: - if existing_column.id not in [column.id for column in new_columns]: - DatasetDAO.delete_column(existing_column) - return new_columns + + if override_columns: + db.session.query(TableColumn).filter( + TableColumn.table_id == model.id + ).delete(synchronize_session="fetch") + + db.session.bulk_insert_mappings( + TableColumn, + [ + {**properties, "table_id": model.id} + for properties in property_columns + ], + ) + else: + columns_by_id = {column.id: column for column in model.columns} + + property_columns_by_id = { + properties["id"]: properties + for properties in property_columns + if "id" in properties + } + + db.session.bulk_insert_mappings( + TableColumn, + [ + {**properties, "table_id": model.id} + for properties in property_columns + if not "id" in properties + ], + ) + + db.session.bulk_update_mappings( + TableColumn, + [ + {**columns_by_id[properties["id"]].__dict__, **properties} + for properties in property_columns_by_id.values() + ], + ) + + db.session.query(TableColumn).filter( + TableColumn.id.in_( + {column.id for column in model.columns} + - property_columns_by_id.keys() + ) + ).delete(synchronize_session="fetch") + + if commit: + db.session.commit() @classmethod def update_metrics( @@ -212,7 +241,7 @@ def update_metrics( model: SqlaTable, property_metrics: List[Dict[str, Any]], commit: bool = True, - ) -> List[SqlMetric]: + ) -> None: """ Creates/updates and/or deletes a list of metrics, based on a list of Dict. @@ -222,21 +251,40 @@ def update_metrics( - If there are extra metrics on the metadata db that are not defined on the List then we delete. """ - new_metrics = [] - for metric in property_metrics: - metric_id = metric.get("id") - if metric.get("id"): - metric_obj = db.session.query(SqlMetric).get(metric_id) - metric_obj = DatasetDAO.update_metric(metric_obj, metric, commit=commit) - else: - metric_obj = DatasetDAO.create_metric(metric, commit=commit) - new_metrics.append(metric_obj) - - # Checks if an exiting column is missing from properties and delete it - for existing_metric in model.metrics: - if existing_metric.id not in [metric.id for metric in new_metrics]: - DatasetDAO.delete_metric(existing_metric) - return new_metrics + + metrics_by_id = {metric.id: metric for metric in model.metrics} + + property_metrics_by_id = { + properties["id"]: properties + for properties in property_metrics + if "id" in properties + } + + db.session.bulk_insert_mappings( + SqlMetric, + [ + {**properties, "table_id": model.id} + for properties in property_metrics + if not "id" in properties + ], + ) + + db.session.bulk_update_mappings( + SqlMetric, + [ + {**metrics_by_id[properties["id"]].__dict__, **properties} + for properties in property_metrics_by_id.values() + ], + ) + + db.session.query(SqlMetric).filter( + SqlMetric.id.in_( + {metric.id for metric in model.metrics} - property_metrics_by_id.keys() + ) + ).delete(synchronize_session="fetch") + + if commit: + db.session.commit() @classmethod def find_dataset_column( @@ -254,23 +302,24 @@ def find_dataset_column( @classmethod def update_column( - cls, model: TableColumn, properties: Dict[str, Any], commit: bool = True - ) -> Optional[TableColumn]: + cls, + model: TableColumn, + properties: Dict[str, Any], + commit: bool = True, + ) -> TableColumn: return DatasetColumnDAO.update(model, properties, commit=commit) @classmethod def create_column( cls, properties: Dict[str, Any], commit: bool = True - ) -> Optional[TableColumn]: + ) -> TableColumn: """ Creates a Dataset model on the metadata DB """ return DatasetColumnDAO.create(properties, commit=commit) @classmethod - def delete_column( - cls, model: TableColumn, commit: bool = True - ) -> Optional[TableColumn]: + def delete_column(cls, model: TableColumn, commit: bool = True) -> TableColumn: """ Deletes a Dataset column """ @@ -287,9 +336,7 @@ def find_dataset_metric( return db.session.query(SqlMetric).get(metric_id) @classmethod - def delete_metric( - cls, model: SqlMetric, commit: bool = True - ) -> Optional[TableColumn]: + def delete_metric(cls, model: SqlMetric, commit: bool = True) -> SqlMetric: """ Deletes a Dataset metric """ @@ -297,14 +344,19 @@ def delete_metric( @classmethod def update_metric( - cls, model: SqlMetric, properties: Dict[str, Any], commit: bool = True - ) -> Optional[SqlMetric]: + cls, + model: SqlMetric, + properties: Dict[str, Any], + commit: bool = True, + ) -> SqlMetric: return DatasetMetricDAO.update(model, properties, commit=commit) @classmethod def create_metric( - cls, properties: Dict[str, Any], commit: bool = True - ) -> Optional[SqlMetric]: + cls, + properties: Dict[str, Any], + commit: bool = True, + ) -> SqlMetric: """ Creates a Dataset model on the metadata DB """ @@ -336,6 +388,14 @@ def bulk_delete(models: Optional[List[SqlaTable]], commit: bool = True) -> None: db.session.rollback() raise ex + @staticmethod + def get_table_by_name(database_id: int, table_name: str) -> Optional[SqlaTable]: + return ( + db.session.query(SqlaTable) + .filter_by(database_id=database_id, table_name=table_name) + .one_or_none() + ) + class DatasetColumnDAO(BaseDAO): model_cls = TableColumn diff --git a/superset/datasets/metrics/api.py b/superset/datasets/metrics/api.py index b55ab9dbb4895..c0831670dba11 100644 --- a/superset/datasets/metrics/api.py +++ b/superset/datasets/metrics/api.py @@ -16,7 +16,7 @@ # under the License. import logging -from flask import g, Response +from flask import Response from flask_appbuilder.api import expose, permission_name, protect, safe from flask_appbuilder.models.sqla.interface import SQLAInterface @@ -91,7 +91,7 @@ def delete( # pylint: disable=arguments-differ $ref: '#/components/responses/500' """ try: - DeleteDatasetMetricCommand(g.user, pk, metric_id).run() + DeleteDatasetMetricCommand(pk, metric_id).run() return self.response(200, message="OK") except DatasetMetricNotFoundError: return self.response_404() diff --git a/superset/datasets/metrics/commands/delete.py b/superset/datasets/metrics/commands/delete.py index cb3f1e0bea1e8..d57e7fa359b49 100644 --- a/superset/datasets/metrics/commands/delete.py +++ b/superset/datasets/metrics/commands/delete.py @@ -18,8 +18,8 @@ from typing import Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User +from superset import security_manager from superset.commands.base import BaseCommand from superset.connectors.sqla.models import SqlMetric from superset.dao.exceptions import DAODeleteFailedError @@ -30,14 +30,12 @@ DatasetMetricNotFoundError, ) from superset.exceptions import SupersetSecurityException -from superset.views.base import check_ownership logger = logging.getLogger(__name__) class DeleteDatasetMetricCommand(BaseCommand): - def __init__(self, user: User, dataset_id: int, model_id: int): - self._actor = user + def __init__(self, dataset_id: int, model_id: int): self._dataset_id = dataset_id self._model_id = model_id self._model: Optional[SqlMetric] = None @@ -60,6 +58,6 @@ def validate(self) -> None: raise DatasetMetricNotFoundError() # Check ownership try: - check_ownership(self._model) + security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise DatasetMetricForbiddenError() from ex diff --git a/superset/datasets/schemas.py b/superset/datasets/schemas.py index 8a44da458f564..103359a2c3f03 100644 --- a/superset/datasets/schemas.py +++ b/superset/datasets/schemas.py @@ -80,6 +80,7 @@ class DatasetPostSchema(Schema): database = fields.Integer(required=True) schema = fields.String(validate=Length(0, 250)) table_name = fields.String(required=True, allow_none=False, validate=Length(1, 250)) + sql = fields.String(allow_none=True) owners = fields.List(fields.Integer()) is_managed_externally = fields.Boolean(allow_none=True, default=False) external_url = fields.String(allow_none=True) @@ -107,6 +108,11 @@ class DatasetPutSchema(Schema): external_url = fields.String(allow_none=True) +class DatasetDuplicateSchema(Schema): + base_model_id = fields.Integer(required=True) + table_name = fields.String(required=True, allow_none=False, validate=Length(1, 250)) + + class DatasetRelatedChart(Schema): id = fields.Integer() slice_name = fields.String() @@ -144,7 +150,7 @@ class ImportV1ColumnSchema(Schema): @pre_load def fix_extra(self, data: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: """ - Fix for extra initially beeing exported as a string. + Fix for extra initially being exported as a string. """ if isinstance(data.get("extra"), str): data["extra"] = json.loads(data["extra"]) @@ -170,7 +176,7 @@ class ImportV1MetricSchema(Schema): @pre_load def fix_extra(self, data: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: """ - Fix for extra initially beeing exported as a string. + Fix for extra initially being exported as a string. """ if isinstance(data.get("extra"), str): data["extra"] = json.loads(data["extra"]) @@ -192,7 +198,7 @@ class ImportV1DatasetSchema(Schema): @pre_load def fix_extra(self, data: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: """ - Fix for extra initially beeing exported as a string. + Fix for extra initially being exported as a string. """ if isinstance(data.get("extra"), str): data["extra"] = json.loads(data["extra"]) @@ -222,6 +228,17 @@ def fix_extra(self, data: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: external_url = fields.String(allow_none=True) +class GetOrCreateDatasetSchema(Schema): + table_name = fields.String(required=True, description="Name of table") + database_id = fields.Integer( + required=True, description="ID of database table belongs to" + ) + schema = fields.String( + description="The schema the table belongs to", allow_none=True + ) + template_params = fields.String(description="Template params for the table") + + class DatasetSchema(SQLAlchemyAutoSchema): """ Schema for the ``Dataset`` model. diff --git a/superset/datasource/__init__.py b/superset/datasource/__init__.py new file mode 100644 index 0000000000000..e0533d99236c2 --- /dev/null +++ b/superset/datasource/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/superset/datasource/api.py b/superset/datasource/api.py new file mode 100644 index 0000000000000..be246c915d535 --- /dev/null +++ b/superset/datasource/api.py @@ -0,0 +1,130 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging + +from flask_appbuilder.api import expose, protect, safe + +from superset import app, db, event_logger +from superset.dao.exceptions import DatasourceNotFound, DatasourceTypeNotSupportedError +from superset.datasource.dao import DatasourceDAO +from superset.exceptions import SupersetSecurityException +from superset.superset_typing import FlaskResponse +from superset.utils.core import apply_max_row_limit, DatasourceType +from superset.views.base_api import BaseSupersetApi, statsd_metrics + +logger = logging.getLogger(__name__) + + +class DatasourceRestApi(BaseSupersetApi): + allow_browser_login = True + class_permission_name = "Datasource" + resource_name = "datasource" + openapi_spec_tag = "Datasources" + + @expose( + "/<datasource_type>/<int:datasource_id>/column/<column_name>/values/", + methods=["GET"], + ) + @protect() + @safe + @statsd_metrics + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" + f".get_column_values", + log_to_statsd=False, + ) + def get_column_values( + self, datasource_type: str, datasource_id: int, column_name: str + ) -> FlaskResponse: + """Get possible values for a datasource column + --- + get: + summary: Get possible values for a datasource column + parameters: + - in: path + schema: + type: string + name: datasource_type + description: The type of datasource + - in: path + schema: + type: integer + name: datasource_id + description: The id of the datasource + - in: path + schema: + type: string + name: column_name + description: The name of the column to get values for + responses: + 200: + description: A List of distinct values for the column + content: + application/json: + schema: + type: object + properties: + result: + type: array + items: + oneOf: + - type: string + - type: integer + - type: number + - type: boolean + - type: object + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 403: + $ref: '#/components/responses/403' + 404: + $ref: '#/components/responses/404' + 500: + $ref: '#/components/responses/500' + """ + try: + datasource = DatasourceDAO.get_datasource( + db.session, DatasourceType(datasource_type), datasource_id + ) + datasource.raise_for_access() + except ValueError: + return self.response( + 400, message=f"Invalid datasource type: {datasource_type}" + ) + except DatasourceTypeNotSupportedError as ex: + return self.response(400, message=ex.message) + except DatasourceNotFound as ex: + return self.response(404, message=ex.message) + except SupersetSecurityException as ex: + return self.response(403, message=ex.message) + + row_limit = apply_max_row_limit(app.config["FILTER_SELECT_ROW_LIMIT"]) + try: + payload = datasource.values_for_column( + column_name=column_name, limit=row_limit + ) + return self.response(200, result=payload) + except NotImplementedError: + return self.response( + 400, + message=( + "Unable to get column values for " + f"datasource type: {datasource_type}" + ), + ) diff --git a/superset/datasource/dao.py b/superset/datasource/dao.py new file mode 100644 index 0000000000000..c8df4c8d8d968 --- /dev/null +++ b/superset/datasource/dao.py @@ -0,0 +1,70 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import logging +from typing import Dict, Type, Union + +from sqlalchemy.orm import Session + +from superset.connectors.sqla.models import SqlaTable +from superset.dao.base import BaseDAO +from superset.dao.exceptions import DatasourceNotFound, DatasourceTypeNotSupportedError +from superset.datasets.models import Dataset +from superset.models.sql_lab import Query, SavedQuery +from superset.tables.models import Table +from superset.utils.core import DatasourceType + +logger = logging.getLogger(__name__) + +Datasource = Union[Dataset, SqlaTable, Table, Query, SavedQuery] + + +class DatasourceDAO(BaseDAO): + + sources: Dict[Union[DatasourceType, str], Type[Datasource]] = { + DatasourceType.TABLE: SqlaTable, + DatasourceType.QUERY: Query, + DatasourceType.SAVEDQUERY: SavedQuery, + DatasourceType.DATASET: Dataset, + DatasourceType.SLTABLE: Table, + } + + @classmethod + def get_datasource( + cls, + session: Session, + datasource_type: Union[DatasourceType, str], + datasource_id: int, + ) -> Datasource: + if datasource_type not in cls.sources: + raise DatasourceTypeNotSupportedError() + + datasource = ( + session.query(cls.sources[datasource_type]) + .filter_by(id=datasource_id) + .one_or_none() + ) + + if not datasource: + logger.warning( + "Datasource not found datasource_type: %s, datasource_id: %s", + datasource_type, + datasource_id, + ) + raise DatasourceNotFound() + + return datasource diff --git a/superset/db_engine_specs/__init__.py b/superset/db_engine_specs/__init__.py index dac700199557c..f19dffd4a3bbe 100644 --- a/superset/db_engine_specs/__init__.py +++ b/superset/db_engine_specs/__init__.py @@ -33,27 +33,35 @@ from collections import defaultdict from importlib import import_module from pathlib import Path -from typing import Any, Dict, List, Set, Type +from typing import Any, Dict, List, Optional, Set, Type import sqlalchemy.databases import sqlalchemy.dialects from pkg_resources import iter_entry_points from sqlalchemy.engine.default import DefaultDialect +from sqlalchemy.engine.url import URL +from superset import app from superset.db_engine_specs.base import BaseEngineSpec logger = logging.getLogger(__name__) -def is_engine_spec(attr: Any) -> bool: +def is_engine_spec(obj: Any) -> bool: + """ + Return true if a given object is a DB engine spec. + """ return ( - inspect.isclass(attr) - and issubclass(attr, BaseEngineSpec) - and attr != BaseEngineSpec + inspect.isclass(obj) + and issubclass(obj, BaseEngineSpec) + and obj != BaseEngineSpec ) def load_engine_specs() -> List[Type[BaseEngineSpec]]: + """ + Load all engine specs, native and 3rd party. + """ engine_specs: List[Type[BaseEngineSpec]] = [] # load standard engines @@ -65,7 +73,6 @@ def load_engine_specs() -> List[Type[BaseEngineSpec]]: for attr in module.__dict__ if is_engine_spec(getattr(module, attr)) ) - # load additional engines from external modules for ep in iter_entry_points("superset.db_engine_specs"): try: @@ -78,20 +85,31 @@ def load_engine_specs() -> List[Type[BaseEngineSpec]]: return engine_specs -def get_engine_specs() -> Dict[str, Type[BaseEngineSpec]]: +def get_engine_spec(backend: str, driver: Optional[str] = None) -> Type[BaseEngineSpec]: + """ + Return the DB engine spec associated with a given SQLAlchemy URL. + + Note that if a driver is not specified the function returns the first DB engine spec + that supports the backend. Also, if a driver is specified but no DB engine explicitly + supporting that driver exists then a backend-only match is done, in order to allow new + drivers to work with Superset even if they are not listed in the DB engine spec + drivers. + """ engine_specs = load_engine_specs() - # build map from name/alias -> spec - engine_specs_map: Dict[str, Type[BaseEngineSpec]] = {} - for engine_spec in engine_specs: - names = [engine_spec.engine] - if engine_spec.engine_aliases: - names.extend(engine_spec.engine_aliases) + if driver is not None: + for engine_spec in engine_specs: + if engine_spec.supports_backend(backend, driver): + return engine_spec - for name in names: - engine_specs_map[name] = engine_spec + # check ignoring the driver, in order to support new drivers; this will return a + # random DB engine spec that supports the engine + for engine_spec in engine_specs: + if engine_spec.supports_backend(backend): + return engine_spec - return engine_specs_map + # default to the generic DB engine spec + return BaseEngineSpec # there's a mismatch between the dialect name reported by the driver in these @@ -152,6 +170,17 @@ def get_available_engine_specs() -> Dict[Type[BaseEngineSpec], Set[str]]: for engine_spec in load_engine_specs(): driver = drivers[engine_spec.engine] + # do not add denied db engine specs to available list + dbs_denylist = app.config["DBS_AVAILABLE_DENYLIST"] + dbs_denylist_engines = dbs_denylist.keys() + + if ( + engine_spec.engine in dbs_denylist_engines + and hasattr(engine_spec, "default_driver") + and engine_spec.default_driver in dbs_denylist[engine_spec.engine] + ): + continue + # lookup driver by engine aliases. if not driver and engine_spec.engine_aliases: for alias in engine_spec.engine_aliases: diff --git a/superset/db_engine_specs/athena.py b/superset/db_engine_specs/athena.py index 9e1d798a7cb03..047952402d2eb 100644 --- a/superset/db_engine_specs/athena.py +++ b/superset/db_engine_specs/athena.py @@ -19,10 +19,10 @@ from typing import Any, Dict, Optional, Pattern, Tuple from flask_babel import gettext as __ +from sqlalchemy import types from superset.db_engine_specs.base import BaseEngineSpec from superset.errors import SupersetErrorType -from superset.utils import core as utils SYNTAX_ERROR_REGEX = re.compile( ": mismatched input '(?P<syntax_error>.*?)'. Expecting: " @@ -33,6 +33,7 @@ class AthenaEngineSpec(BaseEngineSpec): engine = "awsathena" engine_name = "Amazon Athena" allows_escaped_colons = False + disable_ssh_tunneling = True _time_grain_expressions = { None: "{col}", @@ -65,10 +66,11 @@ class AthenaEngineSpec(BaseEngineSpec): def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"DATE '{dttm.date().isoformat()}'" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): datetime_formatted = dttm.isoformat(sep=" ", timespec="milliseconds") return f"""TIMESTAMP '{datetime_formatted}'""" return None diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py index 43ca6967b6587..90386c1e1068b 100644 --- a/superset/db_engine_specs/base.py +++ b/superset/db_engine_specs/base.py @@ -15,14 +15,17 @@ # specific language governing permissions and limitations # under the License. # pylint: disable=too-many-lines + +from __future__ import annotations + import json import logging import re -from contextlib import closing from datetime import datetime from typing import ( Any, Callable, + ContextManager, Dict, List, Match, @@ -61,7 +64,6 @@ from superset import security_manager, sql_parse from superset.databases.utils import make_url_safe from superset.errors import ErrorLevel, SupersetError, SupersetErrorType -from superset.models.sql_lab import Query from superset.sql_parse import ParsedQuery, Table from superset.superset_typing import ResultSetColumnType from superset.utils import core as utils @@ -73,6 +75,7 @@ # prevent circular imports from superset.connectors.sqla.models import TableColumn from superset.models.core import Database + from superset.models.sql_lab import Query ColumnTypeMapping = Tuple[ Pattern[str], @@ -83,9 +86,6 @@ logger = logging.getLogger() -CTE_ALIAS = "__cte" - - class TimeGrain(NamedTuple): name: str # TODO: redundant field, remove label: str @@ -94,7 +94,6 @@ class TimeGrain(NamedTuple): builtin_time_grains: Dict[Optional[str], str] = { - None: __("Original value"), "PT1S": __("Second"), "PT5S": __("5 second"), "PT30S": __("30 second"), @@ -117,7 +116,9 @@ class TimeGrain(NamedTuple): } -class TimestampExpression(ColumnClause): # pylint: disable=abstract-method +class TimestampExpression( + ColumnClause +): # pylint: disable=abstract-method, too-many-ancestors def __init__(self, expr: str, col: ColumnClause, **kwargs: Any) -> None: """Sqlalchemy class that can be can be used to render native column elements respeting engine-specific quoting rules as part of a string-based expression. @@ -152,6 +153,21 @@ class LimitMethod: # pylint: disable=too-few-public-methods FORCE_LIMIT = "force_limit" +class MetricType(TypedDict, total=False): + """ + Type for metrics return by `get_metrics`. + """ + + metric_name: str + expression: str + verbose_name: Optional[str] + metric_type: Optional[str] + description: Optional[str] + d3format: Optional[str] + warning_text: Optional[str] + extra: Optional[str] + + class BaseEngineSpec: # pylint: disable=too-many-public-methods """Abstract class for database engine specific configurations @@ -166,12 +182,19 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods having to add the same aggregation in SELECT. """ + engine_name: Optional[str] = None # for user messages, overridden in child classes + + # These attributes map the DB engine spec to one or more SQLAlchemy dialects/drivers; + # see the ``supports_url`` and ``supports_backend`` methods below. engine = "base" # str as defined in sqlalchemy.engine.engine engine_aliases: Set[str] = set() - engine_name: Optional[str] = None # for user messages, overridden in child classes + drivers: Dict[str, str] = {} + default_driver: Optional[str] = None + disable_ssh_tunneling = False + _date_trunc_functions: Dict[str, str] = {} _time_grain_expressions: Dict[Optional[str], str] = {} - column_type_mappings: Tuple[ColumnTypeMapping, ...] = ( + _default_column_type_mappings: Tuple[ColumnTypeMapping, ...] = ( ( re.compile(r"^string", re.IGNORECASE), types.String(), @@ -288,6 +311,8 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods GenericDataType.BOOLEAN, ), ) + # engine-specific type mappings to check prior to the defaults + column_type_mappings: Tuple[ColumnTypeMapping, ...] = () # Does database support join-free timeslot grouping time_groupby_inline = False @@ -318,6 +343,8 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods # If True, then it will allow in subquery , # if False it will allow as regular CTE allows_cte_in_subquery = True + # Define alias for CTE + cte_alias = "__cte" # Whether allow LIMIT clause in the SQL # If True, then the database engine is allowed for LIMIT clause # If False, then the database engine is allowed for TOP clause @@ -338,6 +365,62 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods Pattern[str], Tuple[str, SupersetErrorType, Dict[str, Any]] ] = {} + # Whether the engine supports file uploads + # if True, database will be listed as option in the upload file form + supports_file_upload = True + + @classmethod + def supports_url(cls, url: URL) -> bool: + """ + Returns true if the DB engine spec supports a given SQLAlchemy URL. + + As an example, if a given DB engine spec has: + + class PostgresDBEngineSpec: + engine = "postgresql" + engine_aliases = "postgres" + drivers = { + "psycopg2": "The default Postgres driver", + "asyncpg": "An asynchronous Postgres driver", + } + + It would be used for all the following SQLAlchemy URIs: + + - postgres://user:password@host/db + - postgresql://user:password@host/db + - postgres+asyncpg://user:password@host/db + - postgres+psycopg2://user:password@host/db + - postgresql+asyncpg://user:password@host/db + - postgresql+psycopg2://user:password@host/db + + Note that SQLAlchemy has a default driver even if one is not specified: + + >>> from sqlalchemy.engine.url import make_url + >>> make_url('postgres://').get_driver_name() + 'psycopg2' + + """ + backend = url.get_backend_name() + driver = url.get_driver_name() + return cls.supports_backend(backend, driver) + + @classmethod + def supports_backend(cls, backend: str, driver: Optional[str] = None) -> bool: + """ + Returns true if the DB engine spec supports a given SQLAlchemy backend/driver. + """ + # check the backend first + if backend != cls.engine and backend not in cls.engine_aliases: + return False + + # originally DB engine specs didn't declare any drivers and the check was made + # only on the engine; if that's the case, ignore the driver for backwards + # compatibility + if not cls.drivers or driver is None: + return True + + return driver in cls.drivers + @classmethod def get_dbapi_exception_mapping(cls) -> Dict[Type[Exception], Type[Exception]]: """ @@ -351,6 +434,15 @@ def get_dbapi_exception_mapping(cls) -> Dict[Type[Exception], Type[Exception]]: """ return {} + @classmethod + def parse_error_exception(cls, exception: Exception) -> Exception: + """ + Each engine can implement and converge its own specific parser method + + :return: An Exception with a parsed string off the original exception + """ + return exception + @classmethod def get_dbapi_mapped_exception(cls, exception: Exception) -> Exception: """ @@ -364,7 +456,7 @@ def get_dbapi_mapped_exception(cls, exception: Exception) -> Exception: """ new_exception = cls.get_dbapi_exception_mapping().get(type(exception)) if not new_exception: - return exception + return cls.parse_error_exception(exception) return new_exception(str(exception)) @classmethod @@ -377,7 +469,7 @@ def get_allow_cost_estimate( # pylint: disable=unused-argument @classmethod def get_text_clause(cls, clause: str) -> TextClause: """ - SQLALchemy wrapper to ensure text clauses are escaped properly + SQLAlchemy wrapper to ensure text clauses are escaped properly :param clause: string clause with potentially unescaped characters :return: text clause with escaped characters @@ -389,11 +481,19 @@ def get_text_clause(cls, clause: str) -> TextClause: @classmethod def get_engine( cls, - database: "Database", + database: Database, schema: Optional[str] = None, - source: Optional[str] = None, - ) -> Engine: - return database.get_sqla_engine(schema=schema, source=source) + source: Optional[utils.QuerySource] = None, + ) -> ContextManager[Engine]: + """ + Return an engine context manager. + + >>> with DBEngineSpec.get_engine(database, schema, source) as engine: + ... connection = engine.connect() + ... connection.execute(sql) + + """ + return database.get_sqla_engine_with_context(schema=schema, source=source) @classmethod def get_timestamp_expr( @@ -401,7 +501,6 @@ def get_timestamp_expr( col: ColumnClause, pdf: Optional[str], time_grain: Optional[str], - type_: Optional[str] = None, ) -> TimestampExpression: """ Construct a TimestampExpression to be used in a SQLAlchemy query. @@ -409,10 +508,10 @@ def get_timestamp_expr( :param col: Target column for the TimestampExpression :param pdf: date format (seconds or milliseconds) :param time_grain: time grain, e.g. P1Y for 1 year - :param type_: the source column type :return: TimestampExpression object """ if time_grain: + type_ = str(getattr(col, "type", "")) time_expr = cls.get_time_grain_expressions().get(time_grain) if not time_expr: raise NotImplementedError( @@ -561,7 +660,7 @@ def fetch_data( return cursor.fetchmany(limit) return cursor.fetchall() except Exception as ex: - raise cls.get_dbapi_mapped_exception(ex) + raise cls.get_dbapi_mapped_exception(ex) from ex @classmethod def expand_data( @@ -637,7 +736,7 @@ def normalize_indexes(cls, indexes: List[Dict[str, Any]]) -> List[Dict[str, Any] @classmethod def extra_table_metadata( # pylint: disable=unused-argument cls, - database: "Database", + database: Database, table_name: str, schema_name: Optional[str], ) -> Dict[str, Any]: @@ -654,7 +753,7 @@ def extra_table_metadata( # pylint: disable=unused-argument @classmethod def apply_limit_to_sql( - cls, sql: str, limit: int, database: "Database", force: bool = False + cls, sql: str, limit: int, database: Database, force: bool = False ) -> str: """ Alters the SQL statement to apply a LIMIT clause @@ -789,14 +888,14 @@ def get_cte_query(cls, sql: str) -> Optional[str]: # extract rest of the SQLs after CTE remainder = "".join(str(token) for token in stmt.tokens[idx:]).strip() - return f"WITH {token.value},\n{CTE_ALIAS} AS (\n{remainder}\n)" + return f"WITH {token.value},\n{cls.cte_alias} AS (\n{remainder}\n)" return None @classmethod def df_to_sql( cls, - database: "Database", + database: Database, table: Table, df: pd.DataFrame, to_sql_kwargs: Dict[str, Any], @@ -816,17 +915,17 @@ def df_to_sql( :param to_sql_kwargs: The kwargs to be passed to pandas.DataFrame.to_sql` method """ - engine = cls.get_engine(database) to_sql_kwargs["name"] = table.table if table.schema: # Only add schema when it is preset and non empty. to_sql_kwargs["schema"] = table.schema - if engine.dialect.supports_multivalues_insert: - to_sql_kwargs["method"] = "multi" + with cls.get_engine(database) as engine: + if engine.dialect.supports_multivalues_insert: + to_sql_kwargs["method"] = "multi" - df.to_sql(con=engine, **to_sql_kwargs) + df.to_sql(con=engine, **to_sql_kwargs) @classmethod def convert_dttm( # pylint: disable=unused-argument @@ -842,48 +941,6 @@ def convert_dttm( # pylint: disable=unused-argument """ return None - @classmethod - def get_all_datasource_names( - cls, database: "Database", datasource_type: str - ) -> List[utils.DatasourceName]: - """Returns a list of all tables or views in database. - - :param database: Database instance - :param datasource_type: Datasource_type can be 'table' or 'view' - :return: List of all datasources in database or schema - """ - # TODO: Fix circular import caused by importing Database - schemas = database.get_all_schema_names( - cache=database.schema_cache_enabled, - cache_timeout=database.schema_cache_timeout, - force=True, - ) - all_datasources: List[utils.DatasourceName] = [] - for schema in schemas: - if datasource_type == "table": - all_datasources.extend( - utils.DatasourceName(*datasource_name) - for datasource_name in database.get_all_table_names_in_schema( - schema=schema, - force=True, - cache=database.table_cache_enabled, - cache_timeout=database.table_cache_timeout, - ) - ) - elif datasource_type == "view": - all_datasources.extend( - utils.DatasourceName(*datasource_name) - for datasource_name in database.get_all_view_names_in_schema( - schema=schema, - force=True, - cache=database.table_cache_enabled, - cache_timeout=database.table_cache_timeout, - ) - ) - else: - raise Exception(f"Unsupported datasource_type: {datasource_type}") - return all_datasources - @classmethod def handle_cursor(cls, cursor: Any, query: Query, session: Session) -> None: """Handle a live cursor between the execute and fetchall calls @@ -933,9 +990,13 @@ def extract_errors( ] @classmethod - def adjust_database_uri(cls, uri: URL, selected_schema: Optional[str]) -> None: + def adjust_database_uri( # pylint: disable=unused-argument + cls, + uri: URL, + selected_schema: Optional[str], + ) -> URL: """ - Mutate the database component of the SQLAlchemy URI. + Return a modified URL with a new database component. The URI here represents the URI as entered when saving the database, ``selected_schema`` is the schema currently active presumably in @@ -949,9 +1010,10 @@ def adjust_database_uri(cls, uri: URL, selected_schema: Optional[str]) -> None: For those it's probably better to not alter the database component of the URI with the schema name, it won't work. - Some database drivers like presto accept '{catalog}/{schema}' in + Some database drivers like Presto accept '{catalog}/{schema}' in the database component of the URL, that can be handled here. """ + return uri @classmethod def patch(cls) -> None: @@ -972,42 +1034,58 @@ def get_schema_names(cls, inspector: Inspector) -> List[str]: @classmethod def get_table_names( # pylint: disable=unused-argument cls, - database: "Database", + database: Database, inspector: Inspector, schema: Optional[str], - ) -> List[str]: + ) -> Set[str]: """ - Get all tables from schema + Get all the real table names within the specified schema. - :param database: The database to get info - :param inspector: SqlAlchemy inspector - :param schema: Schema to inspect. If omitted, uses default schema for database - :return: All tables in schema + Per the SQLAlchemy definition if the schema is omitted the database’s default + schema is used, however some dialects infer the request as schema agnostic. + + :param database: The database to inspect + :param inspector: The SQLAlchemy inspector + :param schema: The schema to inspect + :returns: The physical table names """ - tables = inspector.get_table_names(schema) + + try: + tables = set(inspector.get_table_names(schema)) + except Exception as ex: + raise cls.get_dbapi_mapped_exception(ex) from ex + if schema and cls.try_remove_schema_from_table_name: - tables = [re.sub(f"^{schema}\\.", "", table) for table in tables] - return sorted(tables) + tables = {re.sub(f"^{schema}\\.", "", table) for table in tables} + return tables @classmethod def get_view_names( # pylint: disable=unused-argument cls, - database: "Database", + database: Database, inspector: Inspector, schema: Optional[str], - ) -> List[str]: + ) -> Set[str]: """ - Get all views from schema + Get all the view names within the specified schema. - :param database: The database to get info - :param inspector: SqlAlchemy inspector - :param schema: Schema name. If omitted, uses default schema for database - :return: All views in schema + Per the SQLAlchemy definition if the schema is omitted the database’s default + schema is used, however some dialects infer the request as schema agnostic. + + :param database: The database to inspect + :param inspector: The SQLAlchemy inspector + :param schema: The schema to inspect + :returns: The view names """ - views = inspector.get_view_names(schema) + + try: + views = set(inspector.get_view_names(schema)) + except Exception as ex: + raise cls.get_dbapi_mapped_exception(ex) from ex + if schema and cls.try_remove_schema_from_table_name: - views = [re.sub(f"^{schema}\\.", "", view) for view in views] - return sorted(views) + views = {re.sub(f"^{schema}\\.", "", view) for view in views} + return views @classmethod def get_table_comment( @@ -1047,12 +1125,32 @@ def get_columns( """ return inspector.get_columns(table_name, schema) + @classmethod + def get_metrics( # pylint: disable=unused-argument + cls, + database: Database, + inspector: Inspector, + table_name: str, + schema: Optional[str], + ) -> List[MetricType]: + """ + Get all metrics from a given schema and table. + """ + return [ + { + "metric_name": "count", + "verbose_name": "COUNT(*)", + "metric_type": "count", + "expression": "COUNT(*)", + } + ] + @classmethod def where_latest_partition( # pylint: disable=too-many-arguments,unused-argument cls, table_name: str, schema: Optional[str], - database: "Database", + database: Database, query: Select, columns: Optional[List[Dict[str, str]]] = None, ) -> Optional[Select]: @@ -1077,7 +1175,7 @@ def _get_fields(cls, cols: List[Dict[str, Any]]) -> List[Any]: @classmethod def select_star( # pylint: disable=too-many-arguments,too-many-locals cls, - database: "Database", + database: Database, table_name: str, engine: Engine, schema: Optional[str] = None, @@ -1156,7 +1254,7 @@ def query_cost_formatter( raise Exception("Database does not support cost estimation") @classmethod - def process_statement(cls, statement: str, database: "Database") -> str: + def process_statement(cls, statement: str, database: Database) -> str: """ Process a SQL statement by stripping and mutating it. @@ -1167,7 +1265,8 @@ def process_statement(cls, statement: str, database: "Database") -> str: parsed_query = ParsedQuery(statement) sql = parsed_query.stripped() sql_query_mutator = current_app.config["SQL_QUERY_MUTATOR"] - if sql_query_mutator: + mutate_after_split = current_app.config["MUTATE_AFTER_SPLIT"] + if sql_query_mutator and not mutate_after_split: sql = sql_query_mutator( sql, user_name=get_username(), # TODO(john-bodley): Deprecate in 3.0. @@ -1179,7 +1278,11 @@ def process_statement(cls, statement: str, database: "Database") -> str: @classmethod def estimate_query_cost( - cls, database: "Database", schema: str, sql: str, source: Optional[str] = None + cls, + database: Database, + schema: str, + sql: str, + source: Optional[utils.QuerySource] = None, ) -> List[Dict[str, Any]]: """ Estimate the cost of a multiple statement SQL query. @@ -1196,27 +1299,14 @@ def estimate_query_cost( parsed_query = sql_parse.ParsedQuery(sql) statements = parsed_query.get_statements() - engine = cls.get_engine(database, schema=schema, source=source) costs = [] - with closing(engine.raw_connection()) as conn: + with database.get_raw_connection(schema=schema, source=source) as conn: cursor = conn.cursor() for statement in statements: processed_statement = cls.process_statement(statement, database) costs.append(cls.estimate_statement_cost(processed_statement, cursor)) - return costs - @classmethod - def modify_url_for_impersonation( - cls, url: URL, impersonate_user: bool, username: Optional[str] - ) -> None: - """ - Modify the SQL Alchemy URL object with the user to impersonate if applicable. - :param url: SQLAlchemy URL object - :param impersonate_user: Flag indicating if impersonation is enabled - :param username: Effective username - """ - if impersonate_user and username is not None: - url.username = username + return costs @classmethod def update_impersonation_config( @@ -1258,7 +1348,7 @@ def execute( # pylint: disable=unused-argument try: cursor.execute(query) except Exception as ex: - raise cls.get_dbapi_mapped_exception(ex) + raise cls.get_dbapi_mapped_exception(ex) from ex @classmethod def make_label_compatible(cls, label: str) -> Union[str, quoted_name]: @@ -1284,24 +1374,25 @@ def make_label_compatible(cls, label: str) -> Union[str, quoted_name]: return label_mutated @classmethod - def get_sqla_column_type( + def get_column_types( cls, column_type: Optional[str], - column_type_mappings: Tuple[ColumnTypeMapping, ...] = column_type_mappings, ) -> Optional[Tuple[TypeEngine, GenericDataType]]: """ - Return a sqlalchemy native column type that corresponds to the column type - defined in the data source (return None to use default type inferred by - SQLAlchemy). Override `column_type_mappings` for specific needs + Return a sqlalchemy native column type and generic data type that corresponds + to the column type defined in the data source (return None to use default type + inferred by SQLAlchemy). Override `column_type_mappings` for specific needs (see MSSQL for example of NCHAR/NVARCHAR handling). :param column_type: Column type returned by inspector - :param column_type_mappings: Maps from string to SqlAlchemy TypeEngine - :return: SqlAlchemy column type + :return: SQLAlchemy and generic Superset column types """ if not column_type: return None - for regex, sqla_type, generic_type in column_type_mappings: + + for regex, sqla_type, generic_type in ( + cls.column_type_mappings + cls._default_column_type_mappings + ): match = regex.match(column_type) if not match: continue @@ -1382,7 +1473,7 @@ def column_datatype_to_string( @classmethod def get_function_names( # pylint: disable=unused-argument cls, - database: "Database", + database: Database, ) -> List[str]: """ Get a list of function names that are able to be called on the database. @@ -1407,7 +1498,7 @@ def pyodbc_rows_to_tuples(data: List[Any]) -> List[Tuple[Any, ...]]: @staticmethod def mutate_db_for_connection_test( # pylint: disable=unused-argument - database: "Database", + database: Database, ) -> None: """ Some databases require passing additional parameters for validating database @@ -1419,7 +1510,7 @@ def mutate_db_for_connection_test( # pylint: disable=unused-argument return None @staticmethod - def get_extra_params(database: "Database") -> Dict[str, Any]: + def get_extra_params(database: Database) -> Dict[str, Any]: """ Some databases require adding elements to connection parameters, like passing certificates to `extra`. This can be done here. @@ -1436,26 +1527,6 @@ def get_extra_params(database: "Database") -> Dict[str, Any]: raise ex return extra - @staticmethod - def update_encrypted_extra_params( - database: "Database", params: Dict[str, Any] - ) -> None: - """ - Some databases require some sensitive information which do not conform to - the username:password syntax normally used by SQLAlchemy. - - :param database: database instance from which to extract extras - :param params: params to be updated - """ - if not database.encrypted_extra: - return - try: - encrypted_extra = json.loads(database.encrypted_extra) - params.update(encrypted_extra) - except json.JSONDecodeError as ex: - logger.error(ex, exc_info=True) - raise ex - @staticmethod def update_params_from_encrypted_extra( # pylint: disable=invalid-name database: "Database", params: Dict[str, Any] @@ -1498,19 +1569,16 @@ def get_column_spec( # pylint: disable=unused-argument native_type: Optional[str], db_extra: Optional[Dict[str, Any]] = None, source: utils.ColumnTypeSource = utils.ColumnTypeSource.GET_TABLE, - column_type_mappings: Tuple[ColumnTypeMapping, ...] = column_type_mappings, ) -> Optional[ColumnSpec]: """ - Converts native database type to sqlalchemy column type. + Get generic type related specs regarding a native column type. + :param native_type: Native database type :param db_extra: The database extra object :param source: Type coming from the database table or cursor description - :param column_type_mappings: Maps from string to SqlAlchemy TypeEngine :return: ColumnSpec object """ - col_types = cls.get_sqla_column_type( - native_type, column_type_mappings=column_type_mappings - ) + col_types = cls.get_column_types(native_type) if col_types: column_type, generic_type = col_types is_dttm = generic_type == GenericDataType.TEMPORAL @@ -1519,11 +1587,44 @@ def get_column_spec( # pylint: disable=unused-argument ) return None + @classmethod + def get_sqla_column_type( + cls, + native_type: Optional[str], + db_extra: Optional[Dict[str, Any]] = None, + source: utils.ColumnTypeSource = utils.ColumnTypeSource.GET_TABLE, + ) -> Optional[TypeEngine]: + """ + Converts native database type to sqlalchemy column type. + + :param native_type: Native database type + :param db_extra: The database extra object + :param source: Type coming from the database table or cursor description + :return: ColumnSpec object + """ + column_spec = cls.get_column_spec( + native_type=native_type, + db_extra=db_extra, + source=source, + ) + return column_spec.sqla_type if column_spec else None + + # pylint: disable=unused-argument + @classmethod + def prepare_cancel_query(cls, query: Query, session: Session) -> None: + """ + Some databases may acquire the query cancelation id after the query + cancelation request has been received. For those cases, the db engine spec + can record the cancelation intent so that the query can either be stopped + prior to execution, or canceled once the query id is acquired. + """ + return None + @classmethod def has_implicit_cancel(cls) -> bool: """ Return True if the live cursor handles the implicit cancelation of the query, - False otherise. + False otherwise. :return: Whether the live cursor implicitly cancels the query :see: handle_cursor @@ -1583,6 +1684,45 @@ def get_impersonation_key(cls, user: Optional[User]) -> Any: """ return user.username if user else None + @classmethod + def mask_encrypted_extra(cls, encrypted_extra: Optional[str]) -> Optional[str]: + """ + Mask ``encrypted_extra``. + + This is used to remove any sensitive data in ``encrypted_extra`` when presenting + it to the user. For example, a private key might be replaced with a masked value + "XXXXXXXXXX". If the masked value is changed the corresponding entry is updated, + otherwise the old value is used (see ``unmask_encrypted_extra`` below). + """ + return encrypted_extra + + # pylint: disable=unused-argument + @classmethod + def unmask_encrypted_extra( + cls, old: Optional[str], new: Optional[str] + ) -> Optional[str]: + """ + Remove masks from ``encrypted_extra``. + + This method allows reusing existing values from the current encrypted extra on + updates. It's useful for reusing masked passwords, allowing keys to be updated + without having to provide sensitive data to the client. + """ + return new + + @classmethod + def get_public_information(cls) -> Dict[str, Any]: + """ + Construct a Dict with properties we want to expose. + + :returns: Dict with properties of our class like supports_file_upload + and disable_ssh_tunneling + """ + return { + "supports_file_upload": cls.supports_file_upload, + "disable_ssh_tunneling": cls.disable_ssh_tunneling, + } + # schema for adding a database by providing parameters instead of the # full SQLAlchemy URI @@ -1614,6 +1754,10 @@ class BasicParametersType(TypedDict, total=False): encryption: bool +class BasicPropertiesType(TypedDict): + parameters: BasicParametersType + + class BasicParametersMixin: """ Mixin for configuring DB engine specs via a dictionary. @@ -1645,7 +1789,7 @@ class BasicParametersMixin: def build_sqlalchemy_uri( # pylint: disable=unused-argument cls, parameters: BasicParametersType, - encryted_extra: Optional[Dict[str, str]] = None, + encrypted_extra: Optional[Dict[str, str]] = None, ) -> str: # make a copy so that we don't update the original query = parameters.get("query", {}).copy() @@ -1691,7 +1835,7 @@ def get_parameters_from_uri( # pylint: disable=unused-argument @classmethod def validate_parameters( - cls, parameters: BasicParametersType + cls, properties: BasicPropertiesType ) -> List[SupersetError]: """ Validates any number of parameters, for progressive validation. @@ -1702,6 +1846,7 @@ def validate_parameters( errors: List[SupersetError] = [] required = {"host", "port", "username", "database"} + parameters = properties.get("parameters", {}) present = {key for key in parameters if parameters.get(key, ())} missing = sorted(required - present) diff --git a/superset/db_engine_specs/bigquery.py b/superset/db_engine_specs/bigquery.py index 51fd710ab3352..171dad4732507 100644 --- a/superset/db_engine_specs/bigquery.py +++ b/superset/db_engine_specs/bigquery.py @@ -26,15 +26,17 @@ from flask_babel import gettext as __ from marshmallow import fields, Schema from marshmallow.exceptions import ValidationError -from sqlalchemy import column +from sqlalchemy import column, types from sqlalchemy.engine.base import Engine from sqlalchemy.sql import sqltypes from typing_extensions import TypedDict +from superset import sql_parse +from superset.constants import PASSWORD_MASK from superset.databases.schemas import encrypted_field_properties, EncryptedString from superset.databases.utils import make_url_safe -from superset.db_engine_specs.base import BaseEngineSpec -from superset.db_engine_specs.exceptions import SupersetDBAPIDisconnectionError +from superset.db_engine_specs.base import BaseEngineSpec, BasicPropertiesType +from superset.db_engine_specs.exceptions import SupersetDBAPIConnectionError from superset.errors import SupersetError, SupersetErrorType from superset.sql_parse import Table from superset.utils import core as utils @@ -45,8 +47,8 @@ CONNECTION_DATABASE_PERMISSIONS_REGEX = re.compile( - "Access Denied: Project User does not have bigquery.jobs.create " - + "permission in project (?P<project>.+?)" + "Access Denied: Project (?P<project_name>.+?): User does not have " + + "bigquery.jobs.create permission in project (?P<project>.+?)" ) TABLE_DOES_NOT_EXIST_REGEX = re.compile( @@ -91,6 +93,7 @@ class BigQueryEngineSpec(BaseEngineSpec): engine = "bigquery" engine_name = "Google BigQuery" max_column_name_length = 128 + disable_ssh_tunneling = True parameters_schema = BigQueryParametersSchema() default_driver = "bigquery" @@ -104,13 +107,13 @@ class BigQueryEngineSpec(BaseEngineSpec): """ https://www.python.org/dev/peps/pep-0249/#arraysize - raw_connections bypass the pybigquery query execution context and deal with + raw_connections bypass the sqlalchemy-bigquery query execution context and deal with raw dbapi connection directly. If this value is not set, the default value is set to 1, as described here, https://googlecloudplatform.github.io/google-cloud-python/latest/_modules/google/cloud/bigquery/dbapi/cursor.html#Cursor - The default value of 5000 is derived from the pybigquery. - https://github.com/mxmzdlv/pybigquery/blob/d214bb089ca0807ca9aaa6ce4d5a01172d40264e/pybigquery/sqlalchemy_bigquery.py#L102 + The default value of 5000 is derived from the sqlalchemy-bigquery. + https://github.com/googleapis/python-bigquery-sqlalchemy/blob/4e17259088f89eac155adc19e0985278a29ecf9c/sqlalchemy_bigquery/base.py#L762 """ arraysize = 5000 @@ -153,9 +156,12 @@ class BigQueryEngineSpec(BaseEngineSpec): custom_errors: Dict[Pattern[str], Tuple[str, SupersetErrorType, Dict[str, Any]]] = { CONNECTION_DATABASE_PERMISSIONS_REGEX: ( __( - "We were unable to connect to your database. Please " - "confirm that your service account has the Viewer " - "and Job User roles on the project." + "Unable to connect. Verify that the following roles are set " + 'on the service account: "BigQuery Data Viewer", ' + '"BigQuery Metadata Viewer", "BigQuery Job User" ' + "and the following permissions are set " + '"bigquery.readsessions.create", ' + '"bigquery.readsessions.getData"' ), SupersetErrorType.CONNECTION_DATABASE_PERMISSIONS_ERROR, {}, @@ -195,15 +201,15 @@ class BigQueryEngineSpec(BaseEngineSpec): def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + if isinstance(sqla_type, types.Date): return f"CAST('{dttm.date().isoformat()}' AS DATE)" - if tt == utils.TemporalType.DATETIME: + if isinstance(sqla_type, types.TIMESTAMP): + return f"""CAST('{dttm.isoformat(timespec="microseconds")}' AS TIMESTAMP)""" + if isinstance(sqla_type, types.DateTime): return f"""CAST('{dttm.isoformat(timespec="microseconds")}' AS DATETIME)""" - if tt == utils.TemporalType.TIME: + if isinstance(sqla_type, types.Time): return f"""CAST('{dttm.strftime("%H:%M:%S.%f")}' AS TIME)""" - if tt == utils.TemporalType.TIMESTAMP: - return f"""CAST('{dttm.isoformat(timespec="microseconds")}' AS TIMESTAMP)""" return None @classmethod @@ -336,8 +342,12 @@ def df_to_sql( if not table.schema: raise Exception("The table schema must be defined") - engine = cls.get_engine(database) - to_gbq_kwargs = {"destination_table": str(table), "project_id": engine.url.host} + to_gbq_kwargs = {} + with cls.get_engine(database) as engine: + to_gbq_kwargs = { + "destination_table": str(table), + "project_id": engine.url.host, + } # Add credentials if they are set on the SQLAlchemy dialect. creds = engine.dialect.credentials_info @@ -356,6 +366,97 @@ def df_to_sql( pandas_gbq.to_gbq(df, **to_gbq_kwargs) + @classmethod + def estimate_query_cost( + cls, + database: "Database", + schema: str, + sql: str, + source: Optional[utils.QuerySource] = None, + ) -> List[Dict[str, Any]]: + """ + Estimate the cost of a multiple statement SQL query. + + :param database: Database instance + :param schema: Database schema + :param sql: SQL query with possibly multiple statements + :param source: Source of the query (eg, "sql_lab") + """ + extra = database.get_extra() or {} + if not cls.get_allow_cost_estimate(extra): + raise Exception("Database does not support cost estimation") + + parsed_query = sql_parse.ParsedQuery(sql) + statements = parsed_query.get_statements() + costs = [] + for statement in statements: + processed_statement = cls.process_statement(statement, database) + + costs.append(cls.estimate_statement_cost(processed_statement, database)) + return costs + + @classmethod + def get_allow_cost_estimate(cls, extra: Dict[str, Any]) -> bool: + return True + + @classmethod + def estimate_statement_cost(cls, statement: str, cursor: Any) -> Dict[str, Any]: + try: + # pylint: disable=import-outside-toplevel + # It's the only way to perfom a dry-run estimate cost + from google.cloud import bigquery + from google.oauth2 import service_account + except ImportError as ex: + raise Exception( + "Could not import libraries `pygibquery` or `google.oauth2`, which are " + "required to be installed in your environment in order " + "to upload data to BigQuery" + ) from ex + + with cls.get_engine(cursor) as engine: + creds = engine.dialect.credentials_info + + creds = service_account.Credentials.from_service_account_info(creds) + client = bigquery.Client(credentials=creds) + job_config = bigquery.QueryJobConfig(dry_run=True) + + query_job = client.query( + statement, + job_config=job_config, + ) # Make an API request. + + # Format Bytes. + # TODO: Humanize in case more db engine specs need to be added, + # this should be made a function outside this scope. + byte_division = 1024 + if hasattr(query_job, "total_bytes_processed"): + query_bytes_processed = query_job.total_bytes_processed + if query_bytes_processed // byte_division == 0: + byte_type = "B" + total_bytes_processed = query_bytes_processed + elif query_bytes_processed // (byte_division**2) == 0: + byte_type = "KB" + total_bytes_processed = round(query_bytes_processed / byte_division, 2) + elif query_bytes_processed // (byte_division**3) == 0: + byte_type = "MB" + total_bytes_processed = round( + query_bytes_processed / (byte_division**2), 2 + ) + else: + byte_type = "GB" + total_bytes_processed = round( + query_bytes_processed / (byte_division**3), 2 + ) + + return {f"{byte_type} Processed": total_bytes_processed} + return {} + + @classmethod + def query_cost_formatter( + cls, raw_cost: List[Dict[str, Any]] + ) -> List[Dict[str, str]]: + return [{k: str(v) for k, v in row.items()} for row in raw_cost] + @classmethod def build_sqlalchemy_uri( cls, @@ -380,26 +481,77 @@ def build_sqlalchemy_uri( @classmethod def get_parameters_from_uri( - cls, uri: str, encrypted_extra: Optional[Dict[str, str]] = None + cls, + uri: str, + encrypted_extra: Optional[Dict[str, Any]] = None, ) -> Any: value = make_url_safe(uri) # Building parameters from encrypted_extra and uri if encrypted_extra: - return {**encrypted_extra, "query": value.query} + # ``value.query`` needs to be explicitly converted into a dict (from an + # ``immutabledict``) so that it can be JSON serialized + return {**encrypted_extra, "query": dict(value.query)} raise ValidationError("Invalid service credentials") + @classmethod + def mask_encrypted_extra(cls, encrypted_extra: Optional[str]) -> Optional[str]: + if encrypted_extra is None: + return encrypted_extra + + try: + config = json.loads(encrypted_extra) + except (json.JSONDecodeError, TypeError): + return encrypted_extra + + try: + config["credentials_info"]["private_key"] = PASSWORD_MASK + except KeyError: + pass + + return json.dumps(config) + + @classmethod + def unmask_encrypted_extra( + cls, old: Optional[str], new: Optional[str] + ) -> Optional[str]: + """ + Reuse ``private_key`` if available and unchanged. + """ + if old is None or new is None: + return new + + try: + old_config = json.loads(old) + new_config = json.loads(new) + except (TypeError, json.JSONDecodeError): + return new + + if "credentials_info" not in new_config: + return new + + if "private_key" not in new_config["credentials_info"]: + return new + + if new_config["credentials_info"]["private_key"] == PASSWORD_MASK: + new_config["credentials_info"]["private_key"] = old_config[ + "credentials_info" + ]["private_key"] + + return json.dumps(new_config) + @classmethod def get_dbapi_exception_mapping(cls) -> Dict[Type[Exception], Type[Exception]]: # pylint: disable=import-outside-toplevel from google.auth.exceptions import DefaultCredentialsError - return {DefaultCredentialsError: SupersetDBAPIDisconnectionError} + return {DefaultCredentialsError: SupersetDBAPIConnectionError} @classmethod def validate_parameters( - cls, parameters: BigQueryParametersType # pylint: disable=unused-argument + cls, + properties: BasicPropertiesType, # pylint: disable=unused-argument ) -> List[SupersetError]: return [] @@ -523,3 +675,12 @@ def _get_fields(cls, cols: List[Dict[str, Any]]) -> List[Any]: "author__name" and "author__email", respectively. """ return [column(c["name"]).label(c["name"].replace(".", "__")) for c in cols] + + @classmethod + def parse_error_exception(cls, exception: Exception) -> Exception: + try: + return Exception(str(exception).splitlines()[0].strip()) + except Exception: # pylint: disable=broad-except + # If for some reason we get an exception, for example, no new line + # We will return the original exception + return exception diff --git a/superset/db_engine_specs/clickhouse.py b/superset/db_engine_specs/clickhouse.py index 4f34d2a5543c2..930aeee52839e 100644 --- a/superset/db_engine_specs/clickhouse.py +++ b/superset/db_engine_specs/clickhouse.py @@ -18,12 +18,12 @@ from datetime import datetime from typing import Any, Dict, List, Optional, Type, TYPE_CHECKING +from sqlalchemy import types from urllib3.exceptions import NewConnectionError from superset.db_engine_specs.base import BaseEngineSpec from superset.db_engine_specs.exceptions import SupersetDBAPIDatabaseError from superset.extensions import cache_manager -from superset.utils import core as utils if TYPE_CHECKING: # prevent circular imports @@ -58,6 +58,8 @@ class ClickHouseEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method _show_functions_column = "name" + supports_file_upload = False + @classmethod def get_dbapi_exception_mapping(cls) -> Dict[Type[Exception], Type[Exception]]: return {NewConnectionError: SupersetDBAPIDatabaseError} @@ -75,10 +77,11 @@ def get_dbapi_mapped_exception(cls, exception: Exception) -> Exception: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"toDate('{dttm.date().isoformat()}')" - if tt == utils.TemporalType.DATETIME: + if isinstance(sqla_type, types.DateTime): return f"""toDateTime('{dttm.isoformat(sep=" ", timespec="seconds")}')""" return None diff --git a/superset/db_engine_specs/crate.py b/superset/db_engine_specs/crate.py index 4d934c448c353..7cf7bed15d9c9 100644 --- a/superset/db_engine_specs/crate.py +++ b/superset/db_engine_specs/crate.py @@ -14,11 +14,14 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from __future__ import annotations + from datetime import datetime from typing import Any, Dict, Optional, TYPE_CHECKING +from sqlalchemy import types + from superset.db_engine_specs.base import BaseEngineSpec -from superset.utils import core as utils if TYPE_CHECKING: from superset.connectors.sqla.models import TableColumn @@ -53,12 +56,13 @@ def epoch_ms_to_dttm(cls) -> str: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.TIMESTAMP: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.TIMESTAMP): return f"{dttm.timestamp() * 1000}" return None @classmethod - def alter_new_orm_column(cls, orm_col: "TableColumn") -> None: + def alter_new_orm_column(cls, orm_col: TableColumn) -> None: if orm_col.type == "TIMESTAMP": orm_col.python_date_format = "epoch_ms" diff --git a/superset/db_engine_specs/databricks.py b/superset/db_engine_specs/databricks.py index d010b520d0b00..df82b6d2f93e9 100644 --- a/superset/db_engine_specs/databricks.py +++ b/superset/db_engine_specs/databricks.py @@ -13,13 +13,84 @@ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations -# under the License.o +# under the License. +import json from datetime import datetime -from typing import Any, Dict, Optional +from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING -from superset.db_engine_specs.base import BaseEngineSpec +from apispec import APISpec +from apispec.ext.marshmallow import MarshmallowPlugin +from flask_babel import gettext as __ +from marshmallow import fields, Schema +from marshmallow.validate import Range +from sqlalchemy.engine.reflection import Inspector +from sqlalchemy.engine.url import URL +from typing_extensions import TypedDict + +from superset.constants import USER_AGENT +from superset.databases.utils import make_url_safe +from superset.db_engine_specs.base import BaseEngineSpec, BasicParametersMixin from superset.db_engine_specs.hive import HiveEngineSpec +from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.utils.network import is_hostname_valid, is_port_open + +if TYPE_CHECKING: + from superset.models.core import Database + + +class DatabricksParametersSchema(Schema): + """ + This is the list of fields that are expected + from the client in order to build the sqlalchemy string + """ + + access_token = fields.Str(required=True) + host = fields.Str(required=True) + port = fields.Integer( + required=True, + description=__("Database port"), + validate=Range(min=0, max=2**16, max_inclusive=False), + ) + database = fields.Str(required=True) + encryption = fields.Boolean( + required=False, description=__("Use an encrypted connection to the database") + ) + + +class DatabricksPropertiesSchema(DatabricksParametersSchema): + """ + This is the list of fields expected + for successful database creation execution + """ + + http_path = fields.Str(required=True) + + +class DatabricksParametersType(TypedDict): + """ + The parameters are all the keys that do + not exist on the Database model. + These are used to build the sqlalchemy uri + """ + + access_token: str + host: str + port: int + database: str + encryption: bool + + +class DatabricksPropertiesType(TypedDict): + """ + All properties that need to be available to + this engine in order to create a connection + if the dynamic form is used + """ + + parameters: DatabricksParametersType + extra: str + time_grain_expressions = { None: "{col}", @@ -41,18 +112,23 @@ class DatabricksHiveEngineSpec(HiveEngineSpec): - engine = "databricks" engine_name = "Databricks Interactive Cluster" - driver = "pyhive" + + engine = "databricks" + drivers = {"pyhive": "Hive driver for Interactive Cluster"} + default_driver = "pyhive" + _show_functions_column = "function" _time_grain_expressions = time_grain_expressions class DatabricksODBCEngineSpec(BaseEngineSpec): - engine = "databricks" engine_name = "Databricks SQL Endpoint" - driver = "pyodbc" + + engine = "databricks" + drivers = {"pyodbc": "ODBC driver for SQL endpoint"} + default_driver = "pyodbc" _time_grain_expressions = time_grain_expressions @@ -67,7 +143,225 @@ def epoch_to_dttm(cls) -> str: return HiveEngineSpec.epoch_to_dttm() -class DatabricksNativeEngineSpec(DatabricksODBCEngineSpec): +class DatabricksNativeEngineSpec(DatabricksODBCEngineSpec, BasicParametersMixin): + engine_name = "Databricks" + engine = "databricks" - engine_name = "Databricks Native Connector" - driver = "connector" + drivers = {"connector": "Native all-purpose driver"} + default_driver = "connector" + + parameters_schema = DatabricksParametersSchema() + properties_schema = DatabricksPropertiesSchema() + + sqlalchemy_uri_placeholder = ( + "databricks+connector://token:{access_token}@{host}:{port}/{database_name}" + ) + encryption_parameters = {"ssl": "1"} + + @staticmethod + def get_extra_params(database: "Database") -> Dict[str, Any]: + """ + Add a user agent to be used in the requests. + Trim whitespace from connect_args to avoid databricks driver errors + """ + extra: Dict[str, Any] = BaseEngineSpec.get_extra_params(database) + engine_params: Dict[str, Any] = extra.setdefault("engine_params", {}) + connect_args: Dict[str, Any] = engine_params.setdefault("connect_args", {}) + + connect_args.setdefault("http_headers", [("User-Agent", USER_AGENT)]) + connect_args.setdefault("_user_agent_entry", USER_AGENT) + + # trim whitespace from http_path to avoid databricks errors on connecting + if http_path := connect_args.get("http_path"): + connect_args["http_path"] = http_path.strip() + + return extra + + @classmethod + def get_table_names( + cls, + database: "Database", + inspector: Inspector, + schema: Optional[str], + ) -> Set[str]: + return super().get_table_names( + database, inspector, schema + ) - cls.get_view_names(database, inspector, schema) + + @classmethod + def build_sqlalchemy_uri( # type: ignore + cls, parameters: DatabricksParametersType, *_ + ) -> str: + + query = {} + if parameters.get("encryption"): + if not cls.encryption_parameters: + raise Exception("Unable to build a URL with encryption enabled") + query.update(cls.encryption_parameters) + + return str( + URL( + f"{cls.engine}+{cls.default_driver}".rstrip("+"), + username="token", + password=parameters.get("access_token"), + host=parameters["host"], + port=parameters["port"], + database=parameters["database"], + query=query, + ) + ) + + @classmethod + def extract_errors( + cls, ex: Exception, context: Optional[Dict[str, Any]] = None + ) -> List[SupersetError]: + raw_message = cls._extract_error_message(ex) + + context = context or {} + # access_token isn't currently parseable from the + # databricks error response, but adding it in here + # for reference if their error message changes + context = { + "host": context.get("hostname"), + "access_token": context.get("password"), + "port": context.get("port"), + "username": context.get("username"), + "database": context.get("database"), + } + for regex, (message, error_type, extra) in cls.custom_errors.items(): + match = regex.search(raw_message) + if match: + params = {**context, **match.groupdict()} + extra["engine_name"] = cls.engine_name + return [ + SupersetError( + error_type=error_type, + message=message % params, + level=ErrorLevel.ERROR, + extra=extra, + ) + ] + + return [ + SupersetError( + error_type=SupersetErrorType.GENERIC_DB_ENGINE_ERROR, + message=cls._extract_error_message(ex), + level=ErrorLevel.ERROR, + extra={"engine_name": cls.engine_name}, + ) + ] + + @classmethod + def get_parameters_from_uri( # type: ignore + cls, uri: str, *_, **__ + ) -> DatabricksParametersType: + url = make_url_safe(uri) + encryption = all( + item in url.query.items() for item in cls.encryption_parameters.items() + ) + return { + "access_token": url.password, + "host": url.host, + "port": url.port, + "database": url.database, + "encryption": encryption, + } + + @classmethod + def validate_parameters( # type: ignore + cls, + properties: DatabricksPropertiesType, + ) -> List[SupersetError]: + errors: List[SupersetError] = [] + required = {"access_token", "host", "port", "database", "extra"} + extra = json.loads(properties.get("extra", "{}")) + engine_params = extra.get("engine_params", {}) + connect_args = engine_params.get("connect_args", {}) + parameters = { + **properties, + **properties.get("parameters", {}), + } + if connect_args.get("http_path"): + parameters["http_path"] = connect_args.get("http_path") + + present = {key for key in parameters if parameters.get(key, ())} + missing = sorted(required - present) + + if missing: + errors.append( + SupersetError( + message=f'One or more parameters are missing: {", ".join(missing)}', + error_type=SupersetErrorType.CONNECTION_MISSING_PARAMETERS_ERROR, + level=ErrorLevel.WARNING, + extra={"missing": missing}, + ), + ) + + host = parameters.get("host", None) + if not host: + return errors + + if not is_hostname_valid(host): # type: ignore + errors.append( + SupersetError( + message="The hostname provided can't be resolved.", + error_type=SupersetErrorType.CONNECTION_INVALID_HOSTNAME_ERROR, + level=ErrorLevel.ERROR, + extra={"invalid": ["host"]}, + ), + ) + return errors + + port = parameters.get("port", None) + if not port: + return errors + try: + port = int(port) # type: ignore + except (ValueError, TypeError): + errors.append( + SupersetError( + message="Port must be a valid integer.", + error_type=SupersetErrorType.CONNECTION_INVALID_PORT_ERROR, + level=ErrorLevel.ERROR, + extra={"invalid": ["port"]}, + ), + ) + if not (isinstance(port, int) and 0 <= port < 2**16): + errors.append( + SupersetError( + message=( + "The port must be an integer between 0 and 65535 " + "(inclusive)." + ), + error_type=SupersetErrorType.CONNECTION_INVALID_PORT_ERROR, + level=ErrorLevel.ERROR, + extra={"invalid": ["port"]}, + ), + ) + elif not is_port_open(host, port): # type: ignore + errors.append( + SupersetError( + message="The port is closed.", + error_type=SupersetErrorType.CONNECTION_PORT_CLOSED_ERROR, + level=ErrorLevel.ERROR, + extra={"invalid": ["port"]}, + ), + ) + return errors + + @classmethod + def parameters_json_schema(cls) -> Any: + """ + Return configuration parameters as OpenAPI. + """ + if not cls.properties_schema: + return None + + spec = APISpec( + title="Database Parameters", + version="1.0.0", + openapi_version="3.0.2", + plugins=[MarshmallowPlugin()], + ) + spec.components.schema(cls.__name__, schema=cls.properties_schema) + return spec.to_dict()["components"]["schemas"][cls.__name__] diff --git a/superset/db_engine_specs/dremio.py b/superset/db_engine_specs/dremio.py index fddba00b5fea3..0c773e70938f4 100644 --- a/superset/db_engine_specs/dremio.py +++ b/superset/db_engine_specs/dremio.py @@ -17,8 +17,9 @@ from datetime import datetime from typing import Any, Dict, Optional +from sqlalchemy import types + from superset.db_engine_specs.base import BaseEngineSpec -from superset.utils import core as utils class DremioEngineSpec(BaseEngineSpec): @@ -46,10 +47,11 @@ def epoch_to_dttm(cls) -> str: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"TO_DATE('{dttm.date().isoformat()}', 'YYYY-MM-DD')" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): dttm_formatted = dttm.isoformat(sep=" ", timespec="milliseconds") return f"""TO_TIMESTAMP('{dttm_formatted}', 'YYYY-MM-DD HH24:MI:SS.FFF')""" return None diff --git a/superset/db_engine_specs/drill.py b/superset/db_engine_specs/drill.py index de8c8397f66b3..756f74e82ac6e 100644 --- a/superset/db_engine_specs/drill.py +++ b/superset/db_engine_specs/drill.py @@ -18,11 +18,11 @@ from typing import Any, Dict, Optional from urllib import parse +from sqlalchemy import types from sqlalchemy.engine.url import URL from superset.db_engine_specs.base import BaseEngineSpec from superset.db_engine_specs.exceptions import SupersetDBAPIProgrammingError -from superset.utils import core as utils class DrillEngineSpec(BaseEngineSpec): @@ -59,35 +59,41 @@ def epoch_ms_to_dttm(cls) -> str: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"TO_DATE('{dttm.date().isoformat()}', 'yyyy-MM-dd')" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): datetime_formatted = dttm.isoformat(sep=" ", timespec="seconds") return f"""TO_TIMESTAMP('{datetime_formatted}', 'yyyy-MM-dd HH:mm:ss')""" return None @classmethod - def adjust_database_uri(cls, uri: URL, selected_schema: Optional[str]) -> None: + def adjust_database_uri(cls, uri: URL, selected_schema: Optional[str]) -> URL: if selected_schema: - uri.database = parse.quote(selected_schema, safe="") + uri = uri.set(database=parse.quote(selected_schema, safe="")) + + return uri @classmethod - def modify_url_for_impersonation( + def get_url_for_impersonation( cls, url: URL, impersonate_user: bool, username: Optional[str] - ) -> None: + ) -> URL: """ - Modify the SQL Alchemy URL object with the user to impersonate if applicable. + Return a modified URL with the username set. + :param url: SQLAlchemy URL object :param impersonate_user: Flag indicating if impersonation is enabled :param username: Effective username """ if impersonate_user and username is not None: if url.drivername == "drill+odbc": - url.query["DelegationUID"] = username + url = url.update_query_dict({"DelegationUID": username}) elif url.drivername in ["drill+sadrill", "drill+jdbc"]: - url.query["impersonation_target"] = username + url = url.update_query_dict({"impersonation_target": username}) else: raise SupersetDBAPIProgrammingError( f"impersonation is not supported for {url.drivername}" ) + + return url diff --git a/superset/db_engine_specs/druid.py b/superset/db_engine_specs/druid.py index d193daf5844bb..83829ec22ac32 100644 --- a/superset/db_engine_specs/druid.py +++ b/superset/db_engine_specs/druid.py @@ -14,13 +14,20 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. + +from __future__ import annotations + import json import logging from datetime import datetime -from typing import Any, Dict, Optional, TYPE_CHECKING +from typing import Any, Dict, List, Optional, Type, TYPE_CHECKING + +from sqlalchemy import types +from sqlalchemy.engine.reflection import Inspector from superset import is_feature_enabled from superset.db_engine_specs.base import BaseEngineSpec +from superset.db_engine_specs.exceptions import SupersetDBAPIConnectionError from superset.exceptions import SupersetException from superset.utils import core as utils @@ -67,12 +74,12 @@ class DruidEngineSpec(BaseEngineSpec): } @classmethod - def alter_new_orm_column(cls, orm_col: "TableColumn") -> None: + def alter_new_orm_column(cls, orm_col: TableColumn) -> None: if orm_col.column_name == "__time": orm_col.is_dttm = True @staticmethod - def get_extra_params(database: "Database") -> Dict[str, Any]: + def get_extra_params(database: Database) -> Dict[str, Any]: """ For Druid, the path to a SSL certificate is placed in `connect_args`. @@ -99,10 +106,11 @@ def get_extra_params(database: "Database") -> Dict[str, Any]: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"CAST(TIME_PARSE('{dttm.date().isoformat()}') AS DATE)" - if tt in (utils.TemporalType.DATETIME, utils.TemporalType.TIMESTAMP): + if isinstance(sqla_type, (types.DateTime, types.TIMESTAMP)): return f"""TIME_PARSE('{dttm.isoformat(timespec="seconds")}')""" return None @@ -119,3 +127,21 @@ def epoch_ms_to_dttm(cls) -> str: Convert from number of milliseconds since the epoch to a timestamp. """ return "MILLIS_TO_TIMESTAMP({col})" + + @classmethod + def get_columns( + cls, inspector: Inspector, table_name: str, schema: Optional[str] + ) -> List[Dict[str, Any]]: + """ + Update the Druid type map. + """ + return super().get_columns(inspector, table_name, schema) + + @classmethod + def get_dbapi_exception_mapping(cls) -> Dict[Type[Exception], Type[Exception]]: + # pylint: disable=import-outside-toplevel + from requests import exceptions as requests_exceptions + + return { + requests_exceptions.ConnectionError: SupersetDBAPIConnectionError, + } diff --git a/superset/db_engine_specs/duckdb.py b/superset/db_engine_specs/duckdb.py index 9f2d7422128b1..1248287b8408d 100644 --- a/superset/db_engine_specs/duckdb.py +++ b/superset/db_engine_specs/duckdb.py @@ -18,14 +18,14 @@ import re from datetime import datetime -from typing import Any, Dict, List, Optional, Pattern, Tuple, TYPE_CHECKING +from typing import Any, Dict, Optional, Pattern, Set, Tuple, TYPE_CHECKING from flask_babel import gettext as __ +from sqlalchemy import types from sqlalchemy.engine.reflection import Inspector from superset.db_engine_specs.base import BaseEngineSpec from superset.errors import SupersetErrorType -from superset.utils import core as utils if TYPE_CHECKING: # prevent circular imports @@ -47,7 +47,7 @@ class DuckDBEngineSpec(BaseEngineSpec): "P1D": "DATE_TRUNC('day', {col})", "P1W": "DATE_TRUNC('week', {col})", "P1M": "DATE_TRUNC('month', {col})", - "P0.25Y": "DATE_TRUNC('quarter', {col})", + "P3M": "DATE_TRUNC('quarter', {col})", "P1Y": "DATE_TRUNC('year', {col})", } @@ -67,14 +67,14 @@ def epoch_to_dttm(cls) -> str: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt in (utils.TemporalType.TEXT, utils.TemporalType.DATETIME): + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, (types.String, types.DateTime)): return f"""'{dttm.isoformat(sep=" ", timespec="microseconds")}'""" return None @classmethod def get_table_names( cls, database: Database, inspector: Inspector, schema: Optional[str] - ) -> List[str]: - """Need to disregard the schema for DuckDB""" - return sorted(inspector.get_table_names()) + ) -> Set[str]: + return set(inspector.get_table_names(schema)) diff --git a/superset/db_engine_specs/dynamodb.py b/superset/db_engine_specs/dynamodb.py new file mode 100644 index 0000000000000..c398a9c1dff11 --- /dev/null +++ b/superset/db_engine_specs/dynamodb.py @@ -0,0 +1,65 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from datetime import datetime +from typing import Any, Dict, Optional + +from sqlalchemy import types + +from superset.db_engine_specs.base import BaseEngineSpec + + +class DynamoDBEngineSpec(BaseEngineSpec): + engine = "dynamodb" + engine_name = "Amazon DynamoDB" + + _time_grain_expressions = { + None: "{col}", + "PT1S": "DATETIME(STRFTIME('%Y-%m-%dT%H:%M:%S', {col}))", + "PT1M": "DATETIME(STRFTIME('%Y-%m-%dT%H:%M:00', {col}))", + "PT1H": "DATETIME(STRFTIME('%Y-%m-%dT%H:00:00', {col}))", + "P1D": "DATETIME({col}, 'start of day')", + "P1W": "DATETIME({col}, 'start of day', -strftime('%w', {col}) || ' days')", + "P1M": "DATETIME({col}, 'start of month')", + "P3M": ( + "DATETIME({col}, 'start of month', " + "printf('-%d month', (strftime('%m', {col}) - 1) % 3))" + ), + "P1Y": "DATETIME({col}, 'start of year')", + "P1W/1970-01-03T00:00:00Z": "DATETIME({col}, 'start of day', 'weekday 6')", + "P1W/1970-01-04T00:00:00Z": "DATETIME({col}, 'start of day', 'weekday 0')", + "1969-12-28T00:00:00Z/P1W": ( + "DATETIME({col}, 'start of day', 'weekday 0', '-7 days')" + ), + "1969-12-29T00:00:00Z/P1W": ( + "DATETIME({col}, 'start of day', 'weekday 1', '-7 days')" + ), + } + + @classmethod + def epoch_to_dttm(cls) -> str: + return "datetime({col}, 'unixepoch')" + + @classmethod + def convert_dttm( + cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None + ) -> Optional[str]: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, (types.String, types.DateTime)): + return f"""'{dttm.isoformat(sep=" ", timespec="seconds")}'""" + + return None diff --git a/superset/db_engine_specs/elasticsearch.py b/superset/db_engine_specs/elasticsearch.py index 12a5e21e225d6..b47a61d0ccb70 100644 --- a/superset/db_engine_specs/elasticsearch.py +++ b/superset/db_engine_specs/elasticsearch.py @@ -19,13 +19,14 @@ from distutils.version import StrictVersion from typing import Any, Dict, Optional, Type +from sqlalchemy import types + from superset.db_engine_specs.base import BaseEngineSpec from superset.db_engine_specs.exceptions import ( SupersetDBAPIDatabaseError, SupersetDBAPIOperationalError, SupersetDBAPIProgrammingError, ) -from superset.utils import core as utils logger = logging.getLogger() @@ -68,7 +69,10 @@ def convert_dttm( ) -> Optional[str]: db_extra = db_extra or {} - if target_type.upper() == utils.TemporalType.DATETIME: + + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.DateTime): es_version = db_extra.get("version") # The elasticsearch CAST function does not take effect for the time zone # setting. In elasticsearch7.8 and above, we can use the DATETIME_PARSE @@ -119,7 +123,9 @@ class OpenDistroEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - if target_type.upper() == utils.TemporalType.DATETIME: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.DateTime): return f"""'{dttm.isoformat(timespec="seconds")}'""" return None diff --git a/superset/db_engine_specs/exceptions.py b/superset/db_engine_specs/exceptions.py index 6b4fb5549dd20..56e354d62a574 100644 --- a/superset/db_engine_specs/exceptions.py +++ b/superset/db_engine_specs/exceptions.py @@ -29,7 +29,7 @@ class SupersetDBAPIDatabaseError(SupersetDBAPIError): pass -class SupersetDBAPIDisconnectionError(SupersetDBAPIError): +class SupersetDBAPIConnectionError(SupersetDBAPIError): pass diff --git a/superset/db_engine_specs/firebird.py b/superset/db_engine_specs/firebird.py index 9254a3f2aa314..306a642dc3d11 100644 --- a/superset/db_engine_specs/firebird.py +++ b/superset/db_engine_specs/firebird.py @@ -17,8 +17,9 @@ from datetime import datetime from typing import Any, Dict, Optional +from sqlalchemy import types + from superset.db_engine_specs.base import BaseEngineSpec, LimitMethod -from superset.utils import core as utils class FirebirdEngineSpec(BaseEngineSpec): @@ -73,13 +74,14 @@ def epoch_to_dttm(cls) -> str: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.TIMESTAMP: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): + return f"CAST('{dttm.date().isoformat()}' AS DATE)" + if isinstance(sqla_type, types.DateTime): dttm_formatted = dttm.isoformat(sep=" ") dttm_valid_precision = dttm_formatted[: len("YYYY-MM-DD HH:MM:SS.MMMM")] return f"CAST('{dttm_valid_precision}' AS TIMESTAMP)" - if tt == utils.TemporalType.DATE: - return f"CAST('{dttm.date().isoformat()}' AS DATE)" - if tt == utils.TemporalType.TIME: + if isinstance(sqla_type, types.Time): return f"CAST('{dttm.time().isoformat()}' AS TIME)" return None diff --git a/superset/db_engine_specs/firebolt.py b/superset/db_engine_specs/firebolt.py index 04f48b612a457..65cd7143523c8 100644 --- a/superset/db_engine_specs/firebolt.py +++ b/superset/db_engine_specs/firebolt.py @@ -17,8 +17,9 @@ from datetime import datetime from typing import Any, Dict, Optional +from sqlalchemy import types + from superset.db_engine_specs.base import BaseEngineSpec -from superset.utils import core as utils class FireboltEngineSpec(BaseEngineSpec): @@ -44,13 +45,14 @@ class FireboltEngineSpec(BaseEngineSpec): def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"CAST('{dttm.date().isoformat()}' AS DATE)" - if tt == utils.TemporalType.DATETIME: - return f"""CAST('{dttm.isoformat(timespec="seconds")}' AS DATETIME)""" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): return f"""CAST('{dttm.isoformat(timespec="seconds")}' AS TIMESTAMP)""" + if isinstance(sqla_type, types.DateTime): + return f"""CAST('{dttm.isoformat(timespec="seconds")}' AS DATETIME)""" return None @classmethod diff --git a/superset/db_engine_specs/gsheets.py b/superset/db_engine_specs/gsheets.py index 740c1bc33d367..c181ae62254de 100644 --- a/superset/db_engine_specs/gsheets.py +++ b/superset/db_engine_specs/gsheets.py @@ -16,7 +16,6 @@ # under the License. import json import re -from contextlib import closing from typing import Any, Dict, List, Optional, Pattern, Tuple, TYPE_CHECKING from apispec import APISpec @@ -30,6 +29,7 @@ from typing_extensions import TypedDict from superset import security_manager +from superset.constants import PASSWORD_MASK from superset.databases.schemas import encrypted_field_properties, EncryptedString from superset.db_engine_specs.sqlite import SqliteEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType @@ -54,6 +54,11 @@ class GSheetsParametersSchema(Schema): class GSheetsParametersType(TypedDict): service_account_info: str + catalog: Optional[Dict[str, str]] + + +class GSheetsPropertiesType(TypedDict): + parameters: GSheetsParametersType catalog: Dict[str, str] @@ -64,6 +69,7 @@ class GSheetsEngineSpec(SqliteEngineSpec): engine_name = "Google Sheets" allows_joins = True allows_subqueries = True + disable_ssh_tunneling = True parameters_schema = GSheetsParametersSchema() default_driver = "apsw" @@ -80,17 +86,21 @@ class GSheetsEngineSpec(SqliteEngineSpec): ), } + supports_file_upload = False + @classmethod - def modify_url_for_impersonation( + def get_url_for_impersonation( cls, url: URL, impersonate_user: bool, username: Optional[str], - ) -> None: + ) -> URL: if impersonate_user and username is not None: user = security_manager.find_user(username=username) if user and user.email: - url.query["subject"] = user.email + url = url.update_query_dict({"subject": user.email}) + + return url @classmethod def extra_table_metadata( @@ -99,12 +109,10 @@ def extra_table_metadata( table_name: str, schema_name: Optional[str], ) -> Dict[str, Any]: - engine = cls.get_engine(database, schema=schema_name) - with closing(engine.raw_connection()) as conn: + with database.get_raw_connection(schema=schema_name) as conn: cursor = conn.cursor() cursor.execute(f'SELECT GET_METADATA("{table_name}")') results = cursor.fetchone()[0] - try: metadata = json.loads(results) except Exception: # pylint: disable=broad-except @@ -126,7 +134,7 @@ def build_sqlalchemy_uri( def get_parameters_from_uri( cls, uri: str, # pylint: disable=unused-argument - encrypted_extra: Optional[Dict[str, str]] = None, + encrypted_extra: Optional[Dict[str, Any]] = None, ) -> Any: # Building parameters from encrypted_extra and uri if encrypted_extra: @@ -134,6 +142,52 @@ def get_parameters_from_uri( raise ValidationError("Invalid service credentials") + @classmethod + def mask_encrypted_extra(cls, encrypted_extra: Optional[str]) -> Optional[str]: + if encrypted_extra is None: + return encrypted_extra + + try: + config = json.loads(encrypted_extra) + except (TypeError, json.JSONDecodeError): + return encrypted_extra + + try: + config["service_account_info"]["private_key"] = PASSWORD_MASK + except KeyError: + pass + + return json.dumps(config) + + @classmethod + def unmask_encrypted_extra( + cls, old: Optional[str], new: Optional[str] + ) -> Optional[str]: + """ + Reuse ``private_key`` if available and unchanged. + """ + if old is None or new is None: + return new + + try: + old_config = json.loads(old) + new_config = json.loads(new) + except (TypeError, json.JSONDecodeError): + return new + + if "service_account_info" not in new_config: + return new + + if "private_key" not in new_config["service_account_info"]: + return new + + if new_config["service_account_info"]["private_key"] == PASSWORD_MASK: + new_config["service_account_info"]["private_key"] = old_config[ + "service_account_info" + ]["private_key"] + + return json.dumps(new_config) + @classmethod def parameters_json_schema(cls) -> Any: """ @@ -157,9 +211,18 @@ def parameters_json_schema(cls) -> Any: @classmethod def validate_parameters( cls, - parameters: GSheetsParametersType, + properties: GSheetsPropertiesType, ) -> List[SupersetError]: errors: List[SupersetError] = [] + + # backwards compatible just incase people are send data + # via parameters for validation + parameters = properties.get("parameters", {}) + if parameters and parameters.get("catalog"): + table_catalog = parameters.get("catalog", {}) + else: + table_catalog = properties.get("catalog", {}) + encrypted_credentials = parameters.get("service_account_info") or "{}" # On create the encrypted credentials are a string, @@ -167,8 +230,6 @@ def validate_parameters( if isinstance(encrypted_credentials, str): encrypted_credentials = json.loads(encrypted_credentials) - table_catalog = parameters.get("catalog", {}) - if not table_catalog: # Allowing users to submit empty catalogs errors.append( @@ -194,6 +255,7 @@ def validate_parameters( ) conn = engine.connect() idx = 0 + for name, url in table_catalog.items(): if not name: diff --git a/superset/db_engine_specs/hana.py b/superset/db_engine_specs/hana.py index 0cc55d08d3f6a..e579550b2e2d1 100644 --- a/superset/db_engine_specs/hana.py +++ b/superset/db_engine_specs/hana.py @@ -17,9 +17,10 @@ from datetime import datetime from typing import Any, Dict, Optional +from sqlalchemy import types + from superset.db_engine_specs.base import LimitMethod from superset.db_engine_specs.postgres import PostgresBaseEngineSpec -from superset.utils import core as utils class HanaEngineSpec(PostgresBaseEngineSpec): @@ -46,10 +47,11 @@ class HanaEngineSpec(PostgresBaseEngineSpec): def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"TO_DATE('{dttm.date().isoformat()}', 'YYYY-MM-DD')" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): return f"""TO_TIMESTAMP('{dttm .isoformat(timespec="microseconds")}', 'YYYY-MM-DD"T"HH24:MI:SS.ff6')""" return None diff --git a/superset/db_engine_specs/hive.py b/superset/db_engine_specs/hive.py index 344d1f7ae9334..c049ee652eee4 100644 --- a/superset/db_engine_specs/hive.py +++ b/superset/db_engine_specs/hive.py @@ -14,13 +14,15 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from __future__ import annotations + import logging import os import re import tempfile import time from datetime import datetime -from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING +from typing import Any, Dict, List, Optional, Set, Tuple, TYPE_CHECKING from urllib import parse import numpy as np @@ -28,7 +30,7 @@ import pyarrow as pa import pyarrow.parquet as pq from flask import current_app, g -from sqlalchemy import Column, text +from sqlalchemy import Column, text, types from sqlalchemy.engine.base import Engine from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.url import URL @@ -43,12 +45,13 @@ from superset.extensions import cache_manager from superset.models.sql_lab import Query from superset.sql_parse import ParsedQuery, Table -from superset.utils import core as utils if TYPE_CHECKING: # prevent circular imports - from superset.models.core import Database + from pyhive.hive import Cursor + from TCLIService.ttypes import TFetchOrientation + from superset.models.core import Database logger = logging.getLogger(__name__) @@ -139,18 +142,10 @@ def patch(cls) -> None: ttypes as patched_ttypes, ) - from superset.db_engines import hive as patched_hive - hive.TCLIService = patched_TCLIService hive.constants = patched_constants hive.ttypes = patched_ttypes - hive.Cursor.fetch_logs = patched_hive.fetch_logs - - @classmethod - def get_all_datasource_names( - cls, database: "Database", datasource_type: str - ) -> List[utils.DatasourceName]: - return BaseEngineSpec.get_all_datasource_names(database, datasource_type) + hive.Cursor.fetch_logs = fetch_logs @classmethod def fetch_data( @@ -192,8 +187,6 @@ def df_to_sql( :param to_sql_kwargs: The kwargs to be passed to pandas.DataFrame.to_sql` method """ - engine = cls.get_engine(database) - if to_sql_kwargs["if_exists"] == "append": raise SupersetException("Append operation not currently supported") @@ -212,9 +205,10 @@ def df_to_sql( if table_exists: raise SupersetException("Table already exists") elif to_sql_kwargs["if_exists"] == "replace": - engine.execute(f"DROP TABLE IF EXISTS {str(table)}") + with cls.get_engine(database) as engine: + engine.execute(f"DROP TABLE IF EXISTS {str(table)}") - def _get_hive_type(dtype: np.dtype) -> str: + def _get_hive_type(dtype: np.dtype[Any]) -> str: hive_type_by_dtype = { np.dtype("bool"): "BOOLEAN", np.dtype("float64"): "DOUBLE", @@ -233,45 +227,45 @@ def _get_hive_type(dtype: np.dtype) -> str: ) as file: pq.write_table(pa.Table.from_pandas(df), where=file.name) - engine.execute( - text( - f""" - CREATE TABLE {str(table)} ({schema_definition}) - STORED AS PARQUET - LOCATION :location - """ - ), - location=upload_to_s3( - filename=file.name, - upload_prefix=current_app.config[ - "CSV_TO_HIVE_UPLOAD_DIRECTORY_FUNC" - ](database, g.user, table.schema), - table=table, - ), - ) + with cls.get_engine(database) as engine: + engine.execute( + text( + f""" + CREATE TABLE {str(table)} ({schema_definition}) + STORED AS PARQUET + LOCATION :location + """ + ), + location=upload_to_s3( + filename=file.name, + upload_prefix=current_app.config[ + "CSV_TO_HIVE_UPLOAD_DIRECTORY_FUNC" + ](database, g.user, table.schema), + table=table, + ), + ) @classmethod def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"CAST('{dttm.date().isoformat()}' AS DATE)" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): return f"""CAST('{dttm .isoformat(sep=" ", timespec="microseconds")}' AS TIMESTAMP)""" return None - @classmethod - def epoch_to_dttm(cls) -> str: - return "from_unixtime({col})" - @classmethod def adjust_database_uri( cls, uri: URL, selected_schema: Optional[str] = None - ) -> None: + ) -> URL: if selected_schema: - uri.database = parse.quote(selected_schema, safe="") + uri = uri.set(database=parse.quote(selected_schema, safe="")) + + return uri @classmethod def _extract_error_message(cls, ex: Exception) -> str: @@ -313,7 +307,7 @@ def progress(cls, log_lines: List[str]) -> int: return int(progress) @classmethod - def get_tracking_url(cls, log_lines: List[str]) -> Optional[str]: + def get_tracking_url_from_logs(cls, log_lines: List[str]) -> Optional[str]: lkp = "Tracking URL = " for line in log_lines: if lkp in line: @@ -364,7 +358,7 @@ def handle_cursor( # pylint: disable=too-many-locals query.progress = progress needs_commit = True if not tracking_url: - tracking_url = cls.get_tracking_url(log_lines) + tracking_url = cls.get_tracking_url_from_logs(log_lines) if tracking_url: job_id = tracking_url.split("/")[-2] logger.info( @@ -372,13 +366,6 @@ def handle_cursor( # pylint: disable=too-many-locals str(query_id), tracking_url, ) - transformer = current_app.config["TRACKING_URL_TRANSFORMER"] - tracking_url = transformer(tracking_url) - logger.info( - "Query %s: Transformation applied: %s", - str(query_id), - tracking_url, - ) query.tracking_url = tracking_url logger.info("Query %s: Job id: %s", str(query_id), str(job_id)) needs_commit = True @@ -391,7 +378,15 @@ def handle_cursor( # pylint: disable=too-many-locals last_log_line = len(log_lines) if needs_commit: session.commit() - time.sleep(current_app.config["HIVE_POLL_INTERVAL"]) + if sleep_interval := current_app.config.get("HIVE_POLL_INTERVAL"): + logger.warning( + "HIVE_POLL_INTERVAL is deprecated and will be removed in 3.0. Please use DB_POLL_INTERVAL_SECONDS instead" + ) + else: + sleep_interval = current_app.config["DB_POLL_INTERVAL_SECONDS"].get( + cls.engine, 5 + ) + time.sleep(sleep_interval) polled = cursor.poll() @classmethod @@ -485,17 +480,19 @@ def select_star( # pylint: disable=too-many-arguments ) @classmethod - def modify_url_for_impersonation( + def get_url_for_impersonation( cls, url: URL, impersonate_user: bool, username: Optional[str] - ) -> None: + ) -> URL: """ - Modify the SQL Alchemy URL object with the user to impersonate if applicable. + Return a modified URL with the username set. + :param url: SQLAlchemy URL object :param impersonate_user: Flag indicating if impersonation is enabled :param username: Effective username """ # Do nothing in the URL object since instead this should modify # the configuraiton dictionary. See get_configuration_for_impersonation + return url @classmethod def update_impersonation_config( @@ -573,7 +570,7 @@ def is_readonly_query(cls, parsed_query: ParsedQuery) -> bool: def has_implicit_cancel(cls) -> bool: """ Return True if the live cursor handles the implicit cancelation of the query, - False otherise. + False otherwise. :return: Whether the live cursor implicitly cancels the query :see: handle_cursor @@ -581,7 +578,84 @@ def has_implicit_cancel(cls) -> bool: return True + @classmethod + def get_view_names( + cls, + database: "Database", + inspector: Inspector, + schema: Optional[str], + ) -> Set[str]: + """ + Get all the view names within the specified schema. + + Per the SQLAlchemy definition if the schema is omitted the database’s default + schema is used, however some dialects infer the request as schema agnostic. -class SparkEngineSpec(HiveEngineSpec): + Note that PyHive's Hive SQLAlchemy dialect does not adhere to the specification + where the `get_view_names` method returns both real tables and views. Futhermore + the dialect wrongfully infers the request as schema agnostic when the schema is + omitted. + + :param database: The database to inspect + :param inspector: The SQLAlchemy inspector + :param schema: The schema to inspect + :returns: The view names + """ - engine_name = "Apache Spark SQL" + sql = "SHOW VIEWS" + + if schema: + sql += f" IN `{schema}`" + + with database.get_raw_connection(schema=schema) as conn: + cursor = conn.cursor() + cursor.execute(sql) + results = cursor.fetchall() + return {row[0] for row in results} + + +# TODO: contribute back to pyhive. +def fetch_logs( # pylint: disable=protected-access + self: "Cursor", + _max_rows: int = 1024, + orientation: Optional["TFetchOrientation"] = None, +) -> str: + """Mocked. Retrieve the logs produced by the execution of the query. + Can be called multiple times to fetch the logs produced after + the previous call. + :returns: list<str> + :raises: ``ProgrammingError`` when no query has been started + .. note:: + This is not a part of DB-API. + """ + # pylint: disable=import-outside-toplevel + from pyhive import hive + from TCLIService import ttypes + from thrift import Thrift + + orientation = orientation or ttypes.TFetchOrientation.FETCH_NEXT + try: + req = ttypes.TGetLogReq(operationHandle=self._operationHandle) + logs = self._connection.client.GetLog(req).log + return logs + # raised if Hive is used + except (ttypes.TApplicationException, Thrift.TApplicationException) as ex: + if self._state == self._STATE_NONE: + raise hive.ProgrammingError("No query yet") from ex + logs = [] + while True: + req = ttypes.TFetchResultsReq( + operationHandle=self._operationHandle, + orientation=ttypes.TFetchOrientation.FETCH_NEXT, + maxRows=self.arraysize, + fetchType=1, # 0: results, 1: logs + ) + response = self._connection.client.FetchResults(req) + hive._check_status(response) + assert not response.results.rows, "expected data in columnar format" + assert len(response.results.columns) == 1, response.results.columns + new_logs = hive._unwrap_column(response.results.columns[0]) + logs += new_logs + if not new_logs: + break + return "\n".join(logs) diff --git a/superset/db_engine_specs/impala.py b/superset/db_engine_specs/impala.py index 048588c046fd4..5de1e690c6c9f 100644 --- a/superset/db_engine_specs/impala.py +++ b/superset/db_engine_specs/impala.py @@ -14,13 +14,24 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +import logging +import re +import time from datetime import datetime from typing import Any, Dict, List, Optional +from flask import current_app +from sqlalchemy import types from sqlalchemy.engine.reflection import Inspector +from sqlalchemy.orm import Session +from superset.constants import QUERY_EARLY_CANCEL_KEY from superset.db_engine_specs.base import BaseEngineSpec -from superset.utils import core as utils +from superset.models.sql_lab import Query + +logger = logging.getLogger(__name__) +# Query 5543ffdf692b7d02:f78a944000000000: 3% Complete (17 out of 547) +QUERY_PROGRESS_REGEX = re.compile(r"Query.*: (?P<query_progress>[0-9]+)%") class ImpalaEngineSpec(BaseEngineSpec): @@ -48,10 +59,11 @@ def epoch_to_dttm(cls) -> str: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"CAST('{dttm.date().isoformat()}' AS DATE)" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): return f"""CAST('{dttm.isoformat(timespec="microseconds")}' AS TIMESTAMP)""" return None @@ -63,3 +75,82 @@ def get_schema_names(cls, inspector: Inspector) -> List[str]: if not row[0].startswith("_") ] return schemas + + @classmethod + def has_implicit_cancel(cls) -> bool: + """ + Return True if the live cursor handles the implicit cancelation of the query, + False otherise. + + :return: Whether the live cursor implicitly cancels the query + :see: handle_cursor + """ + + return True + + @classmethod + def execute( + cls, + cursor: Any, + query: str, + **kwargs: Any, + ) -> None: + try: + cursor.execute_async(query) + except Exception as ex: + raise cls.get_dbapi_mapped_exception(ex) + + @classmethod + def handle_cursor(cls, cursor: Any, query: Query, session: Session) -> None: + """Stop query and updates progress information""" + + query_id = query.id + unfinished_states = ( + "INITIALIZED_STATE", + "RUNNING_STATE", + ) + + try: + status = cursor.status() + while status in unfinished_states: + session.refresh(query) + query = session.query(Query).filter_by(id=query_id).one() + # if query cancelation was requested prior to the handle_cursor call, but + # the query was still executed + # modified in stop_query in views / core.py is reflected here. + # stop query + if query.extra.get(QUERY_EARLY_CANCEL_KEY): + cursor.cancel_operation() + cursor.close_operation() + cursor.close() + break + + # updates progress info by log + try: + log = cursor.get_log() or "" + except Exception: # pylint: disable=broad-except + logger.warning("Call to GetLog() failed") + log = "" + + if log: + match = QUERY_PROGRESS_REGEX.match(log) + if match: + progress = int(match.groupdict()["query_progress"]) + logger.debug( + "Query %s: Progress total: %s", str(query_id), str(progress) + ) + needs_commit = False + if progress > query.progress: + query.progress = progress + needs_commit = True + + if needs_commit: + session.commit() + sleep_interval = current_app.config["DB_POLL_INTERVAL_SECONDS"].get( + cls.engine, 5 + ) + time.sleep(sleep_interval) + status = cursor.status() + except Exception: # pylint: disable=broad-except + logger.debug("Call to status() failed ") + return diff --git a/superset/db_engine_specs/kusto.py b/superset/db_engine_specs/kusto.py index d8a52768d9d0a..9fddb23d26185 100644 --- a/superset/db_engine_specs/kusto.py +++ b/superset/db_engine_specs/kusto.py @@ -14,9 +14,13 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +import re from datetime import datetime from typing import Any, Dict, List, Optional, Type +from sqlalchemy import types +from sqlalchemy.dialects.mssql.base import SMALLDATETIME + from superset.db_engine_specs.base import BaseEngineSpec, LimitMethod from superset.db_engine_specs.exceptions import ( SupersetDBAPIDatabaseError, @@ -24,7 +28,7 @@ SupersetDBAPIProgrammingError, ) from superset.sql_parse import ParsedQuery -from superset.utils import core as utils +from superset.utils.core import GenericDataType class KustoSqlEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method @@ -49,7 +53,7 @@ class KustoSqlEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method "P1D": "DATEADD(day, DATEDIFF(day, 0, {col}), 0)", "P1W": "DATEADD(day, -1, DATEADD(week, DATEDIFF(week, 0, {col}), 0))", "P1M": "DATEADD(month, DATEDIFF(month, 0, {col}), 0)", - "P0.25Y": "DATEADD(quarter, DATEDIFF(quarter, 0, {col}), 0)", + "P3M": "DATEADD(quarter, DATEDIFF(quarter, 0, {col}), 0)", "P1Y": "DATEADD(year, DATEDIFF(year, 0, {col}), 0)", "1969-12-28T00:00:00Z/P1W": "DATEADD(day, -1," " DATEADD(week, DATEDIFF(week, 0, {col}), 0))", @@ -59,6 +63,14 @@ class KustoSqlEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method type_code_map: Dict[int, str] = {} # loaded from get_datatype only if needed + column_type_mappings = ( + ( + re.compile(r"^smalldatetime.*", re.IGNORECASE), + SMALLDATETIME(), + GenericDataType.TEMPORAL, + ), + ) + @classmethod def get_dbapi_exception_mapping(cls) -> Dict[Type[Exception], Type[Exception]]: # pylint: disable=import-outside-toplevel,import-error @@ -74,18 +86,19 @@ def get_dbapi_exception_mapping(cls) -> Dict[Type[Exception], Type[Exception]]: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"CONVERT(DATE, '{dttm.date().isoformat()}', 23)" - if tt == utils.TemporalType.DATETIME: - datetime_formatted = dttm.isoformat(timespec="milliseconds") - return f"""CONVERT(DATETIME, '{datetime_formatted}', 126)""" - if tt == utils.TemporalType.SMALLDATETIME: - datetime_formatted = dttm.isoformat(sep=" ", timespec="seconds") - return f"""CONVERT(SMALLDATETIME, '{datetime_formatted}', 20)""" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): datetime_formatted = dttm.isoformat(sep=" ", timespec="seconds") return f"""CONVERT(TIMESTAMP, '{datetime_formatted}', 20)""" + if isinstance(sqla_type, SMALLDATETIME): + datetime_formatted = dttm.isoformat(sep=" ", timespec="seconds") + return f"""CONVERT(SMALLDATETIME, '{datetime_formatted}', 20)""" + if isinstance(sqla_type, types.DateTime): + datetime_formatted = dttm.isoformat(timespec="milliseconds") + return f"""CONVERT(DATETIME, '{datetime_formatted}', 126)""" return None @classmethod @@ -132,13 +145,12 @@ def get_dbapi_exception_mapping(cls) -> Dict[Type[Exception], Type[Exception]]: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - if target_type.upper() in [ - utils.TemporalType.DATETIME, - utils.TemporalType.TIMESTAMP, - ]: - return f"""datetime({dttm.isoformat(timespec="microseconds")})""" - if target_type.upper() == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"""datetime({dttm.date().isoformat()})""" + if isinstance(sqla_type, types.DateTime): + return f"""datetime({dttm.isoformat(timespec="microseconds")})""" return None diff --git a/superset/db_engine_specs/kylin.py b/superset/db_engine_specs/kylin.py index dc3836c7373e4..d76811e86c36c 100644 --- a/superset/db_engine_specs/kylin.py +++ b/superset/db_engine_specs/kylin.py @@ -17,8 +17,9 @@ from datetime import datetime from typing import Any, Dict, Optional +from sqlalchemy import types + from superset.db_engine_specs.base import BaseEngineSpec -from superset.utils import core as utils class KylinEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method @@ -43,10 +44,11 @@ class KylinEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"CAST('{dttm.date().isoformat()}' AS DATE)" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): datetime_fomatted = dttm.isoformat(sep=" ", timespec="seconds") return f"""CAST('{datetime_fomatted}' AS TIMESTAMP)""" return None diff --git a/superset/db_engine_specs/mssql.py b/superset/db_engine_specs/mssql.py index 158e73adeaf99..8b38ec742190f 100644 --- a/superset/db_engine_specs/mssql.py +++ b/superset/db_engine_specs/mssql.py @@ -20,10 +20,12 @@ from typing import Any, Dict, List, Optional, Pattern, Tuple from flask_babel import gettext as __ +from sqlalchemy import types +from sqlalchemy.dialects.mssql.base import SMALLDATETIME from superset.db_engine_specs.base import BaseEngineSpec, LimitMethod from superset.errors import SupersetErrorType -from superset.utils import core as utils +from superset.utils.core import GenericDataType logger = logging.getLogger(__name__) @@ -70,6 +72,13 @@ class MssqlEngineSpec(BaseEngineSpec): "1969-12-29T00:00:00Z/P1W": "DATEADD(WEEK," " DATEDIFF(WEEK, 0, DATEADD(DAY, -1, {col})), 0)", } + column_type_mappings = ( + ( + re.compile(r"^smalldatetime.*", re.IGNORECASE), + SMALLDATETIME(), + GenericDataType.TEMPORAL, + ), + ) custom_errors: Dict[Pattern[str], Tuple[str, SupersetErrorType, Dict[str, Any]]] = { CONNECTION_ACCESS_DENIED_REGEX: ( @@ -108,15 +117,16 @@ def epoch_to_dttm(cls) -> str: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"CONVERT(DATE, '{dttm.date().isoformat()}', 23)" - if tt == utils.TemporalType.DATETIME: - datetime_formatted = dttm.isoformat(timespec="milliseconds") - return f"""CONVERT(DATETIME, '{datetime_formatted}', 126)""" - if tt == utils.TemporalType.SMALLDATETIME: + if isinstance(sqla_type, SMALLDATETIME): datetime_formatted = dttm.isoformat(sep=" ", timespec="seconds") return f"""CONVERT(SMALLDATETIME, '{datetime_formatted}', 20)""" + if isinstance(sqla_type, types.DateTime): + datetime_formatted = dttm.isoformat(timespec="milliseconds") + return f"""CONVERT(DATETIME, '{datetime_formatted}', 126)""" return None @classmethod diff --git a/superset/db_engine_specs/mysql.py b/superset/db_engine_specs/mysql.py index 9aa3c85e0fe62..b873daff75602 100644 --- a/superset/db_engine_specs/mysql.py +++ b/superset/db_engine_specs/mysql.py @@ -20,6 +20,7 @@ from urllib import parse from flask_babel import gettext as __ +from sqlalchemy import types from sqlalchemy.dialects.mysql import ( BIT, DECIMAL, @@ -34,15 +35,10 @@ ) from sqlalchemy.engine.url import URL -from superset.db_engine_specs.base import ( - BaseEngineSpec, - BasicParametersMixin, - ColumnTypeMapping, -) +from superset.db_engine_specs.base import BaseEngineSpec, BasicParametersMixin from superset.errors import SupersetErrorType from superset.models.sql_lab import Query -from superset.utils import core as utils -from superset.utils.core import ColumnSpec, GenericDataType +from superset.utils.core import GenericDataType # Regular expressions to catch custom errors CONNECTION_ACCESS_DENIED_REGEX = re.compile( @@ -182,10 +178,11 @@ class MySQLEngineSpec(BaseEngineSpec, BasicParametersMixin): def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"STR_TO_DATE('{dttm.date().isoformat()}', '%Y-%m-%d')" - if tt == utils.TemporalType.DATETIME: + if isinstance(sqla_type, types.DateTime): datetime_formatted = dttm.isoformat(sep=" ", timespec="microseconds") return f"""STR_TO_DATE('{datetime_formatted}', '%Y-%m-%d %H:%i:%s.%f')""" return None @@ -193,9 +190,11 @@ def convert_dttm( @classmethod def adjust_database_uri( cls, uri: URL, selected_schema: Optional[str] = None - ) -> None: + ) -> URL: if selected_schema: - uri.database = parse.quote(selected_schema, safe="") + uri = uri.set(database=parse.quote(selected_schema, safe="")) + + return uri @classmethod def get_datatype(cls, type_code: Any) -> Optional[str]: @@ -230,23 +229,6 @@ def _extract_error_message(cls, ex: Exception) -> str: pass return message - @classmethod - def get_column_spec( - cls, - native_type: Optional[str], - db_extra: Optional[Dict[str, Any]] = None, - source: utils.ColumnTypeSource = utils.ColumnTypeSource.GET_TABLE, - column_type_mappings: Tuple[ColumnTypeMapping, ...] = column_type_mappings, - ) -> Optional[ColumnSpec]: - - column_spec = super().get_column_spec(native_type) - if column_spec: - return column_spec - - return super().get_column_spec( - native_type, column_type_mappings=column_type_mappings - ) - @classmethod def get_cancel_query_id(cls, cursor: Any, query: Query) -> Optional[str]: """ diff --git a/superset/db_engine_specs/oracle.py b/superset/db_engine_specs/oracle.py index ee04e49ffc64d..4a219919bb537 100644 --- a/superset/db_engine_specs/oracle.py +++ b/superset/db_engine_specs/oracle.py @@ -17,8 +17,9 @@ from datetime import datetime from typing import Any, Dict, List, Optional, Tuple +from sqlalchemy import types + from superset.db_engine_specs.base import BaseEngineSpec, LimitMethod -from superset.utils import core as utils class OracleEngineSpec(BaseEngineSpec): @@ -44,15 +45,16 @@ class OracleEngineSpec(BaseEngineSpec): def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"TO_DATE('{dttm.date().isoformat()}', 'YYYY-MM-DD')" - if tt == utils.TemporalType.DATETIME: - datetime_formatted = dttm.isoformat(timespec="seconds") - return f"""TO_DATE('{datetime_formatted}', 'YYYY-MM-DD"T"HH24:MI:SS')""" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): return f"""TO_TIMESTAMP('{dttm .isoformat(timespec="microseconds")}', 'YYYY-MM-DD"T"HH24:MI:SS.ff6')""" + if isinstance(sqla_type, types.DateTime): + datetime_formatted = dttm.isoformat(timespec="seconds") + return f"""TO_DATE('{datetime_formatted}', 'YYYY-MM-DD"T"HH24:MI:SS')""" return None @classmethod diff --git a/superset/db_engine_specs/pinot.py b/superset/db_engine_specs/pinot.py index 38e30accecbc0..cebdd693a4c7a 100644 --- a/superset/db_engine_specs/pinot.py +++ b/superset/db_engine_specs/pinot.py @@ -75,7 +75,6 @@ def get_timestamp_expr( col: ColumnClause, pdf: Optional[str], time_grain: Optional[str], - type_: Optional[str] = None, ) -> TimestampExpression: if not pdf: raise NotImplementedError(f"Empty date format for '{col}'") diff --git a/superset/db_engine_specs/postgres.py b/superset/db_engine_specs/postgres.py index f9d450a3e9c9e..cbe00ea58dfc6 100644 --- a/superset/db_engine_specs/postgres.py +++ b/superset/db_engine_specs/postgres.py @@ -18,23 +18,19 @@ import logging import re from datetime import datetime -from typing import Any, Dict, List, Optional, Pattern, Tuple, TYPE_CHECKING +from typing import Any, Dict, List, Optional, Pattern, Set, Tuple, TYPE_CHECKING from flask_babel import gettext as __ -from sqlalchemy.dialects.postgresql import ARRAY, DOUBLE_PRECISION, ENUM, JSON +from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION, ENUM, JSON from sqlalchemy.dialects.postgresql.base import PGInspector -from sqlalchemy.types import String +from sqlalchemy.types import Date, DateTime, String -from superset.db_engine_specs.base import ( - BaseEngineSpec, - BasicParametersMixin, - ColumnTypeMapping, -) +from superset.db_engine_specs.base import BaseEngineSpec, BasicParametersMixin from superset.errors import SupersetErrorType from superset.exceptions import SupersetException from superset.models.sql_lab import Query from superset.utils import core as utils -from superset.utils.core import ColumnSpec, GenericDataType +from superset.utils.core import GenericDataType if TYPE_CHECKING: from superset.models.core import Database # pragma: no cover @@ -185,7 +181,7 @@ class PostgresEngineSpec(PostgresBaseEngineSpec, BasicParametersMixin): ), ( re.compile(r"^array.*", re.IGNORECASE), - lambda match: ARRAY(int(match[2])) if match[2] else String(), + String(), GenericDataType.STRING, ), ( @@ -228,20 +224,21 @@ def query_cost_formatter( @classmethod def get_table_names( cls, database: "Database", inspector: PGInspector, schema: Optional[str] - ) -> List[str]: + ) -> Set[str]: """Need to consider foreign tables for PostgreSQL""" - tables = inspector.get_table_names(schema) - tables.extend(inspector.get_foreign_table_names(schema)) - return sorted(tables) + return set(inspector.get_table_names(schema)) | set( + inspector.get_foreign_table_names(schema) + ) @classmethod def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, Date): return f"TO_DATE('{dttm.date().isoformat()}', 'YYYY-MM-DD')" - if "TIMESTAMP" in tt or "DATETIME" in tt: + if isinstance(sqla_type, DateTime): dttm_formatted = dttm.isoformat(sep=" ", timespec="microseconds") return f"""TO_TIMESTAMP('{dttm_formatted}', 'YYYY-MM-DD HH24:MI:SS.US')""" return None @@ -270,23 +267,6 @@ def get_extra_params(database: "Database") -> Dict[str, Any]: extra["engine_params"] = engine_params return extra - @classmethod - def get_column_spec( - cls, - native_type: Optional[str], - db_extra: Optional[Dict[str, Any]] = None, - source: utils.ColumnTypeSource = utils.ColumnTypeSource.GET_TABLE, - column_type_mappings: Tuple[ColumnTypeMapping, ...] = column_type_mappings, - ) -> Optional[ColumnSpec]: - - column_spec = super().get_column_spec(native_type) - if column_spec: - return column_spec - - return super().get_column_spec( - native_type, column_type_mappings=column_type_mappings - ) - @classmethod def get_datatype(cls, type_code: Any) -> Optional[str]: # pylint: disable=import-outside-toplevel diff --git a/superset/db_engine_specs/presto.py b/superset/db_engine_specs/presto.py index cd6fa032b39ed..72931a85b420c 100644 --- a/superset/db_engine_specs/presto.py +++ b/superset/db_engine_specs/presto.py @@ -15,15 +15,28 @@ # specific language governing permissions and limitations # under the License. # pylint: disable=too-many-lines +from __future__ import annotations + import logging import re -import textwrap import time +from abc import ABCMeta from collections import defaultdict, deque -from contextlib import closing from datetime import datetime from distutils.version import StrictVersion -from typing import Any, cast, Dict, List, Optional, Pattern, Tuple, TYPE_CHECKING, Union +from textwrap import dedent +from typing import ( + Any, + cast, + Dict, + List, + Optional, + Pattern, + Set, + Tuple, + TYPE_CHECKING, + Union, +) from urllib import parse import pandas as pd @@ -33,7 +46,7 @@ from sqlalchemy import Column, literal_column, types from sqlalchemy.engine.base import Engine from sqlalchemy.engine.reflection import Inspector -from sqlalchemy.engine.result import RowProxy +from sqlalchemy.engine.result import Row as ResultRow from sqlalchemy.engine.url import URL from sqlalchemy.orm import Session from sqlalchemy.sql.expression import ColumnClause, Select @@ -41,7 +54,7 @@ from superset import cache_manager, is_feature_enabled from superset.common.db_query_status import QueryStatus from superset.databases.utils import make_url_safe -from superset.db_engine_specs.base import BaseEngineSpec, ColumnTypeMapping +from superset.db_engine_specs.base import BaseEngineSpec from superset.errors import SupersetErrorType from superset.exceptions import SupersetTemplateException from superset.models.sql_lab import Query @@ -55,15 +68,20 @@ TinyInteger, ) from superset.result_set import destringify -from superset.sql_parse import ParsedQuery from superset.superset_typing import ResultSetColumnType from superset.utils import core as utils -from superset.utils.core import ColumnSpec, GenericDataType +from superset.utils.core import GenericDataType if TYPE_CHECKING: # prevent circular imports from superset.models.core import Database + # need try/catch because pyhive may not be installed + try: + from pyhive.presto import Cursor # pylint: disable=unused-import + except ImportError: + pass + COLUMN_DOES_NOT_EXIST_REGEX = re.compile( "line (?P<location>.+?): .*Column '(?P<column_name>.+?)' cannot be resolved" ) @@ -139,30 +157,447 @@ def get_children(column: ResultSetColumnType) -> List[ResultSetColumnType]: columns.append(_column) return columns - raise Exception(f"Unknown type {type_}!") + raise Exception(f"Unknown type {type_}!") + + +class PrestoBaseEngineSpec(BaseEngineSpec, metaclass=ABCMeta): + """ + A base class that share common functions between Presto and Trino + """ + + column_type_mappings = ( + ( + re.compile(r"^boolean.*", re.IGNORECASE), + types.BOOLEAN(), + GenericDataType.BOOLEAN, + ), + ( + re.compile(r"^tinyint.*", re.IGNORECASE), + TinyInteger(), + GenericDataType.NUMERIC, + ), + ( + re.compile(r"^smallint.*", re.IGNORECASE), + types.SmallInteger(), + GenericDataType.NUMERIC, + ), + ( + re.compile(r"^integer.*", re.IGNORECASE), + types.INTEGER(), + GenericDataType.NUMERIC, + ), + ( + re.compile(r"^bigint.*", re.IGNORECASE), + types.BigInteger(), + GenericDataType.NUMERIC, + ), + ( + re.compile(r"^real.*", re.IGNORECASE), + types.FLOAT(), + GenericDataType.NUMERIC, + ), + ( + re.compile(r"^double.*", re.IGNORECASE), + types.FLOAT(), + GenericDataType.NUMERIC, + ), + ( + re.compile(r"^decimal.*", re.IGNORECASE), + types.DECIMAL(), + GenericDataType.NUMERIC, + ), + ( + re.compile(r"^varchar(\((\d+)\))*$", re.IGNORECASE), + lambda match: types.VARCHAR(int(match[2])) if match[2] else types.String(), + GenericDataType.STRING, + ), + ( + re.compile(r"^char(\((\d+)\))*$", re.IGNORECASE), + lambda match: types.CHAR(int(match[2])) if match[2] else types.String(), + GenericDataType.STRING, + ), + ( + re.compile(r"^varbinary.*", re.IGNORECASE), + types.VARBINARY(), + GenericDataType.STRING, + ), + ( + re.compile(r"^json.*", re.IGNORECASE), + types.JSON(), + GenericDataType.STRING, + ), + ( + re.compile(r"^date.*", re.IGNORECASE), + types.Date(), + GenericDataType.TEMPORAL, + ), + ( + re.compile(r"^timestamp.*", re.IGNORECASE), + types.TIMESTAMP(), + GenericDataType.TEMPORAL, + ), + ( + re.compile(r"^interval.*", re.IGNORECASE), + Interval(), + GenericDataType.TEMPORAL, + ), + ( + re.compile(r"^time.*", re.IGNORECASE), + types.Time(), + GenericDataType.TEMPORAL, + ), + (re.compile(r"^array.*", re.IGNORECASE), Array(), GenericDataType.STRING), + (re.compile(r"^map.*", re.IGNORECASE), Map(), GenericDataType.STRING), + (re.compile(r"^row.*", re.IGNORECASE), Row(), GenericDataType.STRING), + ) + + # pylint: disable=line-too-long + _time_grain_expressions = { + None: "{col}", + "PT1S": "date_trunc('second', CAST({col} AS TIMESTAMP))", + "PT1M": "date_trunc('minute', CAST({col} AS TIMESTAMP))", + "PT1H": "date_trunc('hour', CAST({col} AS TIMESTAMP))", + "P1D": "date_trunc('day', CAST({col} AS TIMESTAMP))", + "P1W": "date_trunc('week', CAST({col} AS TIMESTAMP))", + "P1M": "date_trunc('month', CAST({col} AS TIMESTAMP))", + "P3M": "date_trunc('quarter', CAST({col} AS TIMESTAMP))", + "P1Y": "date_trunc('year', CAST({col} AS TIMESTAMP))", + # Week starting Sunday + "1969-12-28T00:00:00Z/P1W": "date_trunc('week', CAST({col} AS TIMESTAMP) + interval '1' day) - interval '1' day", # noqa + # Week starting Monday + "1969-12-29T00:00:00Z/P1W": "date_trunc('week', CAST({col} AS TIMESTAMP))", + # Week ending Saturday + "P1W/1970-01-03T00:00:00Z": "date_trunc('week', CAST({col} AS TIMESTAMP) + interval '1' day) + interval '5' day", # noqa + # Week ending Sunday + "P1W/1970-01-04T00:00:00Z": "date_trunc('week', CAST({col} AS TIMESTAMP)) + interval '6' day", # noqa + } + + @classmethod + def convert_dttm( + cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None + ) -> Optional[str]: + """ + Convert a Python `datetime` object to a SQL expression. + :param target_type: The target type of expression + :param dttm: The datetime object + :param db_extra: The database extra object + :return: The SQL expression + Superset only defines time zone naive `datetime` objects, though this method + handles both time zone naive and aware conversions. + """ + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): + return f"DATE '{dttm.date().isoformat()}'" + if isinstance(sqla_type, types.TIMESTAMP): + return f"""TIMESTAMP '{dttm.isoformat(timespec="microseconds", sep=" ")}'""" + + return None + + @classmethod + def epoch_to_dttm(cls) -> str: + return "from_unixtime({col})" + + @classmethod + def adjust_database_uri( + cls, uri: URL, selected_schema: Optional[str] = None + ) -> URL: + database = uri.database + if selected_schema and database: + selected_schema = parse.quote(selected_schema, safe="") + if "/" in database: + database = database.split("/")[0] + "/" + selected_schema + else: + database += "/" + selected_schema + uri = uri.set(database=database) + + return uri + + @classmethod + def estimate_statement_cost(cls, statement: str, cursor: Any) -> Dict[str, Any]: + """ + Run a SQL query that estimates the cost of a given statement. + :param statement: A single SQL statement + :param cursor: Cursor instance + :return: JSON response from Trino + """ + sql = f"EXPLAIN (TYPE IO, FORMAT JSON) {statement}" + cursor.execute(sql) + + # the output from Trino is a single column and a single row containing + # JSON: + # + # { + # ... + # "estimate" : { + # "outputRowCount" : 8.73265878E8, + # "outputSizeInBytes" : 3.41425774958E11, + # "cpuCost" : 3.41425774958E11, + # "maxMemory" : 0.0, + # "networkCost" : 3.41425774958E11 + # } + # } + result = json.loads(cursor.fetchone()[0]) + return result + + @classmethod + def query_cost_formatter( + cls, raw_cost: List[Dict[str, Any]] + ) -> List[Dict[str, str]]: + """ + Format cost estimate. + :param raw_cost: JSON estimate from Trino + :return: Human readable cost estimate + """ + + def humanize(value: Any, suffix: str) -> str: + try: + value = int(value) + except ValueError: + return str(value) + + prefixes = ["K", "M", "G", "T", "P", "E", "Z", "Y"] + prefix = "" + to_next_prefix = 1000 + while value > to_next_prefix and prefixes: + prefix = prefixes.pop(0) + value //= to_next_prefix + + return f"{value} {prefix}{suffix}" + + cost = [] + columns = [ + ("outputRowCount", "Output count", " rows"), + ("outputSizeInBytes", "Output size", "B"), + ("cpuCost", "CPU cost", ""), + ("maxMemory", "Max memory", "B"), + ("networkCost", "Network cost", ""), + ] + for row in raw_cost: + estimate: Dict[str, float] = row.get("estimate", {}) + statement_cost = {} + for key, label, suffix in columns: + if key in estimate: + statement_cost[label] = humanize(estimate[key], suffix).strip() + cost.append(statement_cost) + + return cost + + @classmethod + @cache_manager.data_cache.memoize() + def get_function_names(cls, database: Database) -> List[str]: + """ + Get a list of function names that are able to be called on the database. + Used for SQL Lab autocomplete. + + :param database: The database to get functions for + :return: A list of function names useable in the database + """ + return database.get_df("SHOW FUNCTIONS")["Function"].tolist() + + @classmethod + def _partition_query( # pylint: disable=too-many-arguments,too-many-locals + cls, + table_name: str, + database: Database, + limit: int = 0, + order_by: Optional[List[Tuple[str, bool]]] = None, + filters: Optional[Dict[Any, Any]] = None, + ) -> str: + """Returns a partition query + + :param table_name: the name of the table to get partitions from + :type table_name: str + :param limit: the number of partitions to be returned + :type limit: int + :param order_by: a list of tuples of field name and a boolean + that determines if that field should be sorted in descending + order + :type order_by: list of (str, bool) tuples + :param filters: dict of field name and filter value combinations + """ + limit_clause = "LIMIT {}".format(limit) if limit else "" + order_by_clause = "" + if order_by: + l = [] + for field, desc in order_by: + l.append(field + " DESC" if desc else "") + order_by_clause = "ORDER BY " + ", ".join(l) + + where_clause = "" + if filters: + l = [] + for field, value in filters.items(): + l.append(f"{field} = '{value}'") + where_clause = "WHERE " + " AND ".join(l) + + presto_version = database.get_extra().get("version") + + # Partition select syntax changed in v0.199, so check here. + # Default to the new syntax if version is unset. + partition_select_clause = ( + f'SELECT * FROM "{table_name}$partitions"' + if not presto_version + or StrictVersion(presto_version) >= StrictVersion("0.199") + else f"SHOW PARTITIONS FROM {table_name}" + ) + + sql = dedent( + f"""\ + {partition_select_clause} + {where_clause} + {order_by_clause} + {limit_clause} + """ + ) + return sql + + @classmethod + def where_latest_partition( # pylint: disable=too-many-arguments + cls, + table_name: str, + schema: Optional[str], + database: Database, + query: Select, + columns: Optional[List[Dict[str, str]]] = None, + ) -> Optional[Select]: + try: + col_names, values = cls.latest_partition( + table_name, schema, database, show_first=True + ) + except Exception: # pylint: disable=broad-except + # table is not partitioned + return None + + if values is None: + return None + + column_type_by_name = { + column.get("name"): column.get("type") for column in columns or [] + } + + for col_name, value in zip(col_names, values): + if col_name in column_type_by_name: + if column_type_by_name.get(col_name) == "TIMESTAMP": + query = query.where(Column(col_name, TimeStamp()) == value) + elif column_type_by_name.get(col_name) == "DATE": + query = query.where(Column(col_name, Date()) == value) + else: + query = query.where(Column(col_name) == value) + return query + + @classmethod + def _latest_partition_from_df(cls, df: pd.DataFrame) -> Optional[List[str]]: + if not df.empty: + return df.to_records(index=False)[0].item() + return None + + @classmethod + @cache_manager.data_cache.memoize(timeout=60) + def latest_partition( + cls, + table_name: str, + schema: Optional[str], + database: Database, + show_first: bool = False, + ) -> Tuple[List[str], Optional[List[str]]]: + """Returns col name and the latest (max) partition value for a table + + :param table_name: the name of the table + :param schema: schema / database / namespace + :param database: database query will be run against + :type database: models.Database + :param show_first: displays the value for the first partitioning key + if there are many partitioning keys + :type show_first: bool + + >>> latest_partition('foo_table') + (['ds'], ('2018-01-01',)) + """ + indexes = database.get_indexes(table_name, schema) + if not indexes: + raise SupersetTemplateException( + f"Error getting partition for {schema}.{table_name}. " + "Verify that this table has a partition." + ) + + if len(indexes[0]["column_names"]) < 1: + raise SupersetTemplateException( + "The table should have one partitioned field" + ) + + if not show_first and len(indexes[0]["column_names"]) > 1: + raise SupersetTemplateException( + "The table should have a single partitioned field " + "to use this function. You may want to use " + "`presto.latest_sub_partition`" + ) + + column_names = indexes[0]["column_names"] + part_fields = [(column_name, True) for column_name in column_names] + sql = cls._partition_query(table_name, database, 1, part_fields) + df = database.get_df(sql, schema) + return column_names, cls._latest_partition_from_df(df) + + @classmethod + def latest_sub_partition( + cls, table_name: str, schema: Optional[str], database: Database, **kwargs: Any + ) -> Any: + """Returns the latest (max) partition value for a table + + A filtering criteria should be passed for all fields that are + partitioned except for the field to be returned. For example, + if a table is partitioned by (``ds``, ``event_type`` and + ``event_category``) and you want the latest ``ds``, you'll want + to provide a filter as keyword arguments for both + ``event_type`` and ``event_category`` as in + ``latest_sub_partition('my_table', + event_category='page', event_type='click')`` + + :param table_name: the name of the table, can be just the table + name or a fully qualified table name as ``schema_name.table_name`` + :type table_name: str + :param schema: schema / database / namespace + :type schema: str + :param database: database query will be run against + :type database: models.Database + + :param kwargs: keyword arguments define the filtering criteria + on the partition list. There can be many of these. + :type kwargs: str + >>> latest_sub_partition('sub_partition_table', event_type='click') + '2018-01-01' + """ + indexes = database.get_indexes(table_name, schema) + part_fields = indexes[0]["column_names"] + for k in kwargs.keys(): # pylint: disable=consider-iterating-dictionary + if k not in k in part_fields: # pylint: disable=comparison-with-itself + msg = f"Field [{k}] is not part of the portioning key" + raise SupersetTemplateException(msg) + if len(kwargs.keys()) != len(part_fields) - 1: + msg = ( + "A filter needs to be specified for {} out of the " "{} fields." + ).format(len(part_fields) - 1, len(part_fields)) + raise SupersetTemplateException(msg) + + for field in part_fields: + if field not in kwargs.keys(): + field_to_return = field + + sql = cls._partition_query( + table_name, database, 1, [(field_to_return, True)], kwargs + ) + df = database.get_df(sql, schema) + if df.empty: + return "" + return df.to_dict()[field_to_return][0] -class PrestoEngineSpec(BaseEngineSpec): # pylint: disable=too-many-public-methods +class PrestoEngineSpec(PrestoBaseEngineSpec): engine = "presto" engine_name = "Presto" allows_alias_to_source_column = False - _time_grain_expressions = { - None: "{col}", - "PT1S": "date_trunc('second', CAST({col} AS TIMESTAMP))", - "PT1M": "date_trunc('minute', CAST({col} AS TIMESTAMP))", - "PT1H": "date_trunc('hour', CAST({col} AS TIMESTAMP))", - "P1D": "date_trunc('day', CAST({col} AS TIMESTAMP))", - "P1W": "date_trunc('week', CAST({col} AS TIMESTAMP))", - "P1M": "date_trunc('month', CAST({col} AS TIMESTAMP))", - "P3M": "date_trunc('quarter', CAST({col} AS TIMESTAMP))", - "P1Y": "date_trunc('year', CAST({col} AS TIMESTAMP))", - "P1W/1970-01-03T00:00:00Z": "date_add('day', 5, date_trunc('week', " - "date_add('day', 1, CAST({col} AS TIMESTAMP))))", - "1969-12-28T00:00:00Z/P1W": "date_add('day', -1, date_trunc('week', " - "date_add('day', 1, CAST({col} AS TIMESTAMP))))", - } - custom_errors: Dict[Pattern[str], Tuple[str, SupersetErrorType, Dict[str, Any]]] = { COLUMN_DOES_NOT_EXIST_REGEX: ( __( @@ -249,46 +684,79 @@ def update_impersonation_config( @classmethod def get_table_names( - cls, database: "Database", inspector: Inspector, schema: Optional[str] - ) -> List[str]: - tables = super().get_table_names(database, inspector, schema) - if not is_feature_enabled("PRESTO_SPLIT_VIEWS_FROM_TABLES"): - return tables + cls, + database: Database, + inspector: Inspector, + schema: Optional[str], + ) -> Set[str]: + """ + Get all the real table names within the specified schema. + + Per the SQLAlchemy definition if the schema is omitted the database’s default + schema is used, however some dialects infer the request as schema agnostic. - views = set(cls.get_view_names(database, inspector, schema)) - actual_tables = set(tables) - views - return list(actual_tables) + Note that PyHive's Hive and Presto SQLAlchemy dialects do not adhere to the + specification where the `get_table_names` method returns both real tables and + views. Futhermore the dialects wrongfully infer the request as schema agnostic + when the schema is omitted. + + :param database: The database to inspect + :param inspector: The SQLAlchemy inspector + :param schema: The schema to inspect + :returns: The physical table names + """ + + return super().get_table_names( + database, inspector, schema + ) - cls.get_view_names(database, inspector, schema) @classmethod def get_view_names( - cls, database: "Database", inspector: Inspector, schema: Optional[str] - ) -> List[str]: - """Returns an empty list + cls, + database: Database, + inspector: Inspector, + schema: Optional[str], + ) -> Set[str]: + """ + Get all the view names within the specified schema. + + Per the SQLAlchemy definition if the schema is omitted the database’s default + schema is used, however some dialects infer the request as schema agnostic. + + Note that PyHive's Presto SQLAlchemy dialect does not adhere to the + specification as the `get_view_names` method is not defined. Futhermore the + dialect wrongfully infers the request as schema agnostic when the schema is + omitted. - get_table_names() function returns all table names and view names, - and get_view_names() is not implemented in sqlalchemy_presto.py - https://github.com/dropbox/PyHive/blob/e25fc8440a0686bbb7a5db5de7cb1a77bdb4167a/pyhive/sqlalchemy_presto.py + :param database: The database to inspect + :param inspector: The SQLAlchemy inspector + :param schema: The schema to inspect + :returns: The view names """ - if not is_feature_enabled("PRESTO_SPLIT_VIEWS_FROM_TABLES"): - return [] if schema: - sql = ( - "SELECT table_name FROM information_schema.views " - "WHERE table_schema=%(schema)s" - ) + sql = dedent( + """ + SELECT table_name FROM information_schema.tables + WHERE table_schema = %(schema)s + AND table_type = 'VIEW' + """ + ).strip() params = {"schema": schema} else: - sql = "SELECT table_name FROM information_schema.views" + sql = dedent( + """ + SELECT table_name FROM information_schema.tables + WHERE table_type = 'VIEW' + """ + ).strip() params = {} - engine = cls.get_engine(database, schema=schema) - with closing(engine.raw_connection()) as conn: + with database.get_raw_connection(schema=schema) as conn: cursor = conn.cursor() cursor.execute(sql, params) results = cursor.fetchall() - - return [row[0] for row in results] + return {row[0] for row in results} @classmethod def _create_column_info( @@ -430,7 +898,7 @@ def _parse_structural_column( # pylint: disable=too-many-locals @classmethod def _show_columns( cls, inspector: Inspector, table_name: str, schema: Optional[str] - ) -> List[RowProxy]: + ) -> List[ResultRow]: """ Show presto column names :param inspector: object that performs database schema inspection @@ -442,94 +910,7 @@ def _show_columns( full_table = quote(table_name) if schema: full_table = "{}.{}".format(quote(schema), full_table) - columns = inspector.bind.execute("SHOW COLUMNS FROM {}".format(full_table)) - return columns - - column_type_mappings = ( - ( - re.compile(r"^boolean.*", re.IGNORECASE), - types.BOOLEAN, - GenericDataType.BOOLEAN, - ), - ( - re.compile(r"^tinyint.*", re.IGNORECASE), - TinyInteger(), - GenericDataType.NUMERIC, - ), - ( - re.compile(r"^smallint.*", re.IGNORECASE), - types.SMALLINT(), - GenericDataType.NUMERIC, - ), - ( - re.compile(r"^integer.*", re.IGNORECASE), - types.INTEGER(), - GenericDataType.NUMERIC, - ), - ( - re.compile(r"^bigint.*", re.IGNORECASE), - types.BIGINT(), - GenericDataType.NUMERIC, - ), - ( - re.compile(r"^real.*", re.IGNORECASE), - types.FLOAT(), - GenericDataType.NUMERIC, - ), - ( - re.compile(r"^double.*", re.IGNORECASE), - types.FLOAT(), - GenericDataType.NUMERIC, - ), - ( - re.compile(r"^decimal.*", re.IGNORECASE), - types.DECIMAL(), - GenericDataType.NUMERIC, - ), - ( - re.compile(r"^varchar(\((\d+)\))*$", re.IGNORECASE), - lambda match: types.VARCHAR(int(match[2])) if match[2] else types.String(), - GenericDataType.STRING, - ), - ( - re.compile(r"^char(\((\d+)\))*$", re.IGNORECASE), - lambda match: types.CHAR(int(match[2])) if match[2] else types.CHAR(), - GenericDataType.STRING, - ), - ( - re.compile(r"^varbinary.*", re.IGNORECASE), - types.VARBINARY(), - GenericDataType.STRING, - ), - ( - re.compile(r"^json.*", re.IGNORECASE), - types.JSON(), - GenericDataType.STRING, - ), - ( - re.compile(r"^date.*", re.IGNORECASE), - types.DATE(), - GenericDataType.TEMPORAL, - ), - ( - re.compile(r"^timestamp.*", re.IGNORECASE), - types.TIMESTAMP(), - GenericDataType.TEMPORAL, - ), - ( - re.compile(r"^interval.*", re.IGNORECASE), - Interval(), - GenericDataType.TEMPORAL, - ), - ( - re.compile(r"^time.*", re.IGNORECASE), - types.Time(), - GenericDataType.TEMPORAL, - ), - (re.compile(r"^array.*", re.IGNORECASE), Array(), GenericDataType.STRING), - (re.compile(r"^map.*", re.IGNORECASE), Map(), GenericDataType.STRING), - (re.compile(r"^row.*", re.IGNORECASE), Row(), GenericDataType.STRING), - ) + return inspector.bind.execute(f"SHOW COLUMNS FROM {full_table}").fetchall() @classmethod def get_columns( @@ -615,178 +996,44 @@ def _get_fields(cls, cols: List[Dict[str, Any]]) -> List[ColumnClause]: # create column clause in the format "name"."name" AS "name.name" column_clause = literal_column(quoted_col_name).label(col["name"]) column_clauses.append(column_clause) - return column_clauses - - @classmethod - def select_star( # pylint: disable=too-many-arguments - cls, - database: "Database", - table_name: str, - engine: Engine, - schema: Optional[str] = None, - limit: int = 100, - show_cols: bool = False, - indent: bool = True, - latest_partition: bool = True, - cols: Optional[List[Dict[str, Any]]] = None, - ) -> str: - """ - Include selecting properties of row objects. We cannot easily break arrays into - rows, so render the whole array in its own row and skip columns that correspond - to an array's contents. - """ - cols = cols or [] - presto_cols = cols - if is_feature_enabled("PRESTO_EXPAND_DATA") and show_cols: - dot_regex = r"\.(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)" - presto_cols = [ - col for col in presto_cols if not re.search(dot_regex, col["name"]) - ] - return super().select_star( - database, - table_name, - engine, - schema, - limit, - show_cols, - indent, - latest_partition, - presto_cols, - ) - - @classmethod - def estimate_statement_cost(cls, statement: str, cursor: Any) -> Dict[str, Any]: - """ - Run a SQL query that estimates the cost of a given statement. - - :param statement: A single SQL statement - :param cursor: Cursor instance - :return: JSON response from Presto - """ - sql = f"EXPLAIN (TYPE IO, FORMAT JSON) {statement}" - cursor.execute(sql) - - # the output from Presto is a single column and a single row containing - # JSON: - # - # { - # ... - # "estimate" : { - # "outputRowCount" : 8.73265878E8, - # "outputSizeInBytes" : 3.41425774958E11, - # "cpuCost" : 3.41425774958E11, - # "maxMemory" : 0.0, - # "networkCost" : 3.41425774958E11 - # } - # } - result = json.loads(cursor.fetchone()[0]) - return result - - @classmethod - def query_cost_formatter( - cls, raw_cost: List[Dict[str, Any]] - ) -> List[Dict[str, str]]: - """ - Format cost estimate. - - :param raw_cost: JSON estimate from Presto - :return: Human readable cost estimate - """ - - def humanize(value: Any, suffix: str) -> str: - try: - value = int(value) - except ValueError: - return str(value) - - prefixes = ["K", "M", "G", "T", "P", "E", "Z", "Y"] - prefix = "" - to_next_prefix = 1000 - while value > to_next_prefix and prefixes: - prefix = prefixes.pop(0) - value //= to_next_prefix - - return f"{value} {prefix}{suffix}" - - cost = [] - columns = [ - ("outputRowCount", "Output count", " rows"), - ("outputSizeInBytes", "Output size", "B"), - ("cpuCost", "CPU cost", ""), - ("maxMemory", "Max memory", "B"), - ("networkCost", "Network cost", ""), - ] - for row in raw_cost: - estimate: Dict[str, float] = row.get("estimate", {}) - statement_cost = {} - for key, label, suffix in columns: - if key in estimate: - statement_cost[label] = humanize(estimate[key], suffix).strip() - cost.append(statement_cost) - - return cost - - @classmethod - def adjust_database_uri( - cls, uri: URL, selected_schema: Optional[str] = None - ) -> None: - database = uri.database - if selected_schema and database: - selected_schema = parse.quote(selected_schema, safe="") - if "/" in database: - database = database.split("/")[0] + "/" + selected_schema - else: - database += "/" + selected_schema - uri.database = database - - @classmethod - def convert_dttm( - cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None - ) -> Optional[str]: - """ - Convert a Python `datetime` object to a SQL expression. - - :param target_type: The target type of expression - :param dttm: The datetime object - :param db_extra: The database extra object - :return: The SQL expression - - Superset only defines time zone naive `datetime` objects, though this method - handles both time zone naive and aware conversions. - """ - tt = target_type.upper() - if tt == utils.TemporalType.DATE: - return f"""DATE '{dttm.date().isoformat()}'""" - if tt in ( - utils.TemporalType.TIMESTAMP, - utils.TemporalType.TIMESTAMP_WITH_TIME_ZONE, - ): - return f"""TIMESTAMP '{dttm.isoformat(timespec="milliseconds", sep=" ")}'""" - return None - - @classmethod - def epoch_to_dttm(cls) -> str: - return "from_unixtime({col})" + return column_clauses @classmethod - def get_all_datasource_names( - cls, database: "Database", datasource_type: str - ) -> List[utils.DatasourceName]: - datasource_df = database.get_df( - "SELECT table_schema, table_name FROM INFORMATION_SCHEMA.{}S " - "ORDER BY concat(table_schema, '.', table_name)".format( - datasource_type.upper() - ), - None, + def select_star( # pylint: disable=too-many-arguments + cls, + database: Database, + table_name: str, + engine: Engine, + schema: Optional[str] = None, + limit: int = 100, + show_cols: bool = False, + indent: bool = True, + latest_partition: bool = True, + cols: Optional[List[Dict[str, Any]]] = None, + ) -> str: + """ + Include selecting properties of row objects. We cannot easily break arrays into + rows, so render the whole array in its own row and skip columns that correspond + to an array's contents. + """ + cols = cols or [] + presto_cols = cols + if is_feature_enabled("PRESTO_EXPAND_DATA") and show_cols: + dot_regex = r"\.(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)" + presto_cols = [ + col for col in presto_cols if not re.search(dot_regex, col["name"]) + ] + return super().select_star( + database, + table_name, + engine, + schema, + limit, + show_cols, + indent, + latest_partition, + presto_cols, ) - datasource_names: List[utils.DatasourceName] = [] - for _unused, row in datasource_df.iterrows(): - datasource_names.append( - utils.DatasourceName( - schema=row["table_schema"], table=row["table_name"] - ) - ) - return datasource_names @classmethod def expand_data( # pylint: disable=too-many-locals @@ -899,27 +1146,30 @@ def expand_data( # pylint: disable=too-many-locals @classmethod def extra_table_metadata( - cls, database: "Database", table_name: str, schema_name: Optional[str] + cls, database: Database, table_name: str, schema_name: Optional[str] ) -> Dict[str, Any]: metadata = {} indexes = database.get_indexes(table_name, schema_name) if indexes: - cols = indexes[0].get("column_names", []) - full_table_name = table_name - if schema_name and "." not in table_name: - full_table_name = "{}.{}".format(schema_name, table_name) - pql = cls._partition_query(full_table_name, database) col_names, latest_parts = cls.latest_partition( table_name, schema_name, database, show_first=True ) if not latest_parts: latest_parts = tuple([None] * len(col_names)) + metadata["partitions"] = { - "cols": cols, + "cols": sorted(indexes[0].get("column_names", [])), "latest": dict(zip(col_names, latest_parts)), - "partitionQuery": pql, + "partitionQuery": cls._partition_query( + table_name=( + f"{schema_name}.{table_name}" + if schema_name and "." not in table_name + else table_name + ), + database=database, + ), } # flake8 is not matching `Optional[str]` to `Any` for some reason... @@ -931,7 +1181,7 @@ def extra_table_metadata( @classmethod def get_create_view( - cls, database: "Database", schema: Optional[str], table: str + cls, database: Database, schema: Optional[str], table: str ) -> Optional[str]: """ Return a CREATE VIEW statement, or `None` if not a view. @@ -943,21 +1193,35 @@ def get_create_view( # pylint: disable=import-outside-toplevel from pyhive.exc import DatabaseError - engine = cls.get_engine(database, schema) - with closing(engine.raw_connection()) as conn: + with database.get_raw_connection(schema=schema) as conn: cursor = conn.cursor() sql = f"SHOW CREATE VIEW {schema}.{table}" try: cls.execute(cursor, sql) - except DatabaseError: # not a VIEW return None rows = cls.fetch_data(cursor, 1) - return rows[0][0] + + return rows[0][0] @classmethod - def handle_cursor(cls, cursor: Any, query: Query, session: Session) -> None: + def get_tracking_url(cls, cursor: "Cursor") -> Optional[str]: + try: + if cursor.last_query_id: + # pylint: disable=protected-access, line-too-long + return f"{cursor._protocol}://{cursor._host}:{cursor._port}/ui/query.html?{cursor.last_query_id}" + except AttributeError: + pass + return None + + @classmethod + def handle_cursor(cls, cursor: "Cursor", query: Query, session: Session) -> None: """Updates progress information""" + tracking_url = cls.get_tracking_url(cursor) + if tracking_url: + query.tracking_url = tracking_url + session.commit() + query_id = query.id poll_interval = query.database.connect_args.get( "poll_interval", current_app.config["PRESTO_POLL_INTERVAL"] @@ -1017,243 +1281,11 @@ def _extract_error_message(cls, ex: Exception) -> str: return error_dict.get("message", _("Unknown Presto Error")) return utils.error_msg_from_exception(ex) - @classmethod - def _partition_query( # pylint: disable=too-many-arguments,too-many-locals - cls, - table_name: str, - database: "Database", - limit: int = 0, - order_by: Optional[List[Tuple[str, bool]]] = None, - filters: Optional[Dict[Any, Any]] = None, - ) -> str: - """Returns a partition query - - :param table_name: the name of the table to get partitions from - :type table_name: str - :param limit: the number of partitions to be returned - :type limit: int - :param order_by: a list of tuples of field name and a boolean - that determines if that field should be sorted in descending - order - :type order_by: list of (str, bool) tuples - :param filters: dict of field name and filter value combinations - """ - limit_clause = "LIMIT {}".format(limit) if limit else "" - order_by_clause = "" - if order_by: - l = [] - for field, desc in order_by: - l.append(field + " DESC" if desc else "") - order_by_clause = "ORDER BY " + ", ".join(l) - - where_clause = "" - if filters: - l = [] - for field, value in filters.items(): - l.append(f"{field} = '{value}'") - where_clause = "WHERE " + " AND ".join(l) - - presto_version = database.get_extra().get("version") - - # Partition select syntax changed in v0.199, so check here. - # Default to the new syntax if version is unset. - partition_select_clause = ( - f'SELECT * FROM "{table_name}$partitions"' - if not presto_version - or StrictVersion(presto_version) >= StrictVersion("0.199") - else f"SHOW PARTITIONS FROM {table_name}" - ) - - sql = textwrap.dedent( - f"""\ - {partition_select_clause} - {where_clause} - {order_by_clause} - {limit_clause} - """ - ) - return sql - - @classmethod - def where_latest_partition( # pylint: disable=too-many-arguments - cls, - table_name: str, - schema: Optional[str], - database: "Database", - query: Select, - columns: Optional[List[Dict[str, str]]] = None, - ) -> Optional[Select]: - try: - col_names, values = cls.latest_partition( - table_name, schema, database, show_first=True - ) - except Exception: # pylint: disable=broad-except - # table is not partitioned - return None - - if values is None: - return None - - column_type_by_name = { - column.get("name"): column.get("type") for column in columns or [] - } - - for col_name, value in zip(col_names, values): - if col_name in column_type_by_name: - if column_type_by_name.get(col_name) == "TIMESTAMP": - query = query.where(Column(col_name, TimeStamp()) == value) - elif column_type_by_name.get(col_name) == "DATE": - query = query.where(Column(col_name, Date()) == value) - else: - query = query.where(Column(col_name) == value) - return query - - @classmethod - def _latest_partition_from_df(cls, df: pd.DataFrame) -> Optional[List[str]]: - if not df.empty: - return df.to_records(index=False)[0].item() - return None - - @classmethod - @cache_manager.data_cache.memoize(timeout=60) - def latest_partition( - cls, - table_name: str, - schema: Optional[str], - database: "Database", - show_first: bool = False, - ) -> Tuple[List[str], Optional[List[str]]]: - """Returns col name and the latest (max) partition value for a table - - :param table_name: the name of the table - :param schema: schema / database / namespace - :param database: database query will be run against - :type database: models.Database - :param show_first: displays the value for the first partitioning key - if there are many partitioning keys - :type show_first: bool - - >>> latest_partition('foo_table') - (['ds'], ('2018-01-01',)) - """ - indexes = database.get_indexes(table_name, schema) - if not indexes: - raise SupersetTemplateException( - f"Error getting partition for {schema}.{table_name}. " - "Verify that this table has a partition." - ) - - if len(indexes[0]["column_names"]) < 1: - raise SupersetTemplateException( - "The table should have one partitioned field" - ) - - if not show_first and len(indexes[0]["column_names"]) > 1: - raise SupersetTemplateException( - "The table should have a single partitioned field " - "to use this function. You may want to use " - "`presto.latest_sub_partition`" - ) - - column_names = indexes[0]["column_names"] - part_fields = [(column_name, True) for column_name in column_names] - sql = cls._partition_query(table_name, database, 1, part_fields) - df = database.get_df(sql, schema) - return column_names, cls._latest_partition_from_df(df) - - @classmethod - def latest_sub_partition( - cls, table_name: str, schema: Optional[str], database: "Database", **kwargs: Any - ) -> Any: - """Returns the latest (max) partition value for a table - - A filtering criteria should be passed for all fields that are - partitioned except for the field to be returned. For example, - if a table is partitioned by (``ds``, ``event_type`` and - ``event_category``) and you want the latest ``ds``, you'll want - to provide a filter as keyword arguments for both - ``event_type`` and ``event_category`` as in - ``latest_sub_partition('my_table', - event_category='page', event_type='click')`` - - :param table_name: the name of the table, can be just the table - name or a fully qualified table name as ``schema_name.table_name`` - :type table_name: str - :param schema: schema / database / namespace - :type schema: str - :param database: database query will be run against - :type database: models.Database - - :param kwargs: keyword arguments define the filtering criteria - on the partition list. There can be many of these. - :type kwargs: str - >>> latest_sub_partition('sub_partition_table', event_type='click') - '2018-01-01' - """ - indexes = database.get_indexes(table_name, schema) - part_fields = indexes[0]["column_names"] - for k in kwargs.keys(): # pylint: disable=consider-iterating-dictionary - if k not in k in part_fields: # pylint: disable=comparison-with-itself - msg = f"Field [{k}] is not part of the portioning key" - raise SupersetTemplateException(msg) - if len(kwargs.keys()) != len(part_fields) - 1: - msg = ( - "A filter needs to be specified for {} out of the " "{} fields." - ).format(len(part_fields) - 1, len(part_fields)) - raise SupersetTemplateException(msg) - - for field in part_fields: - if field not in kwargs.keys(): - field_to_return = field - - sql = cls._partition_query( - table_name, database, 1, [(field_to_return, True)], kwargs - ) - df = database.get_df(sql, schema) - if df.empty: - return "" - return df.to_dict()[field_to_return][0] - - @classmethod - @cache_manager.data_cache.memoize() - def get_function_names(cls, database: "Database") -> List[str]: - """ - Get a list of function names that are able to be called on the database. - Used for SQL Lab autocomplete. - - :param database: The database to get functions for - :return: A list of function names useable in the database - """ - return database.get_df("SHOW FUNCTIONS")["Function"].tolist() - - @classmethod - def is_readonly_query(cls, parsed_query: ParsedQuery) -> bool: - """Pessimistic readonly, 100% sure statement won't mutate anything""" - return super().is_readonly_query(parsed_query) or parsed_query.is_show() - - @classmethod - def get_column_spec( - cls, - native_type: Optional[str], - db_extra: Optional[Dict[str, Any]] = None, - source: utils.ColumnTypeSource = utils.ColumnTypeSource.GET_TABLE, - column_type_mappings: Tuple[ColumnTypeMapping, ...] = column_type_mappings, - ) -> Optional[ColumnSpec]: - - column_spec = super().get_column_spec( - native_type, column_type_mappings=column_type_mappings - ) - - if column_spec: - return column_spec - - return super().get_column_spec(native_type) - @classmethod def has_implicit_cancel(cls) -> bool: """ Return True if the live cursor handles the implicit cancelation of the query, - False otherise. + False otherwise. :return: Whether the live cursor implicitly cancels the query :see: handle_cursor diff --git a/superset/common/request_contexed_based.py b/superset/db_engine_specs/risingwave.py similarity index 73% rename from superset/common/request_contexed_based.py rename to superset/db_engine_specs/risingwave.py index 5d8405e36cf05..8f7b1c7de26a6 100644 --- a/superset/common/request_contexed_based.py +++ b/superset/db_engine_specs/risingwave.py @@ -14,12 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from __future__ import annotations +from superset.db_engine_specs.postgres import PostgresEngineSpec -from superset import conf, security_manager - -def is_user_admin() -> bool: - user_roles = [role.name.lower() for role in security_manager.get_user_roles()] - admin_role = conf.get("AUTH_ROLE_ADMIN").lower() - return admin_role in user_roles +class RisingWaveDbEngineSpec(PostgresEngineSpec): + engine = "risingwave" + engine_name = "RisingWave" + default_driver = "" diff --git a/superset/db_engine_specs/rockset.py b/superset/db_engine_specs/rockset.py index 606b860a5e642..3778c527560f6 100644 --- a/superset/db_engine_specs/rockset.py +++ b/superset/db_engine_specs/rockset.py @@ -17,8 +17,9 @@ from datetime import datetime from typing import Any, Dict, Optional, TYPE_CHECKING +from sqlalchemy import types + from superset.db_engine_specs.base import BaseEngineSpec -from superset.utils import core as utils if TYPE_CHECKING: from superset.connectors.sqla.models import TableColumn @@ -53,15 +54,16 @@ def epoch_ms_to_dttm(cls) -> str: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"DATE '{dttm.date().isoformat()}'" - if tt == utils.TemporalType.DATETIME: - dttm_formatted = dttm.isoformat(sep=" ", timespec="microseconds") - return f"""DATETIME '{dttm_formatted}'""" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): dttm_formatted = dttm.isoformat(timespec="microseconds") return f"""TIMESTAMP '{dttm_formatted}'""" + if isinstance(sqla_type, types.DateTime): + dttm_formatted = dttm.isoformat(sep=" ", timespec="microseconds") + return f"""DATETIME '{dttm_formatted}'""" return None @classmethod diff --git a/superset/db_engine_specs/shillelagh.py b/superset/db_engine_specs/shillelagh.py index c6e6f618c7251..37301224484b7 100644 --- a/superset/db_engine_specs/shillelagh.py +++ b/superset/db_engine_specs/shillelagh.py @@ -20,7 +20,11 @@ class ShillelaghEngineSpec(SqliteEngineSpec): """Engine for shillelagh""" - engine = "shillelagh" engine_name = "Shillelagh" + engine = "shillelagh" + drivers = {"apsw": "SQLite driver"} + default_driver = "apsw" + sqlalchemy_uri_placeholder = "shillelagh://" + allows_joins = True allows_subqueries = True diff --git a/superset/db_engine_specs/snowflake.py b/superset/db_engine_specs/snowflake.py index cf645f8b74c24..419e0a0655fe0 100644 --- a/superset/db_engine_specs/snowflake.py +++ b/superset/db_engine_specs/snowflake.py @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. import json +import logging import re from datetime import datetime from typing import Any, Dict, List, Optional, Pattern, Tuple, TYPE_CHECKING @@ -22,16 +23,21 @@ from apispec import APISpec from apispec.ext.marshmallow import MarshmallowPlugin +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from flask import current_app from flask_babel import gettext as __ from marshmallow import fields, Schema +from sqlalchemy import types from sqlalchemy.engine.url import URL from typing_extensions import TypedDict +from superset.constants import USER_AGENT from superset.databases.utils import make_url_safe +from superset.db_engine_specs.base import BaseEngineSpec, BasicPropertiesType from superset.db_engine_specs.postgres import PostgresBaseEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.models.sql_lab import Query -from superset.utils import core as utils if TYPE_CHECKING: from superset.models.core import Database @@ -46,6 +52,8 @@ "unexpected '(?P<syntax_error>.+?)'." ) +logger = logging.getLogger(__name__) + class SnowflakeParametersSchema(Schema): username = fields.Str(required=True) @@ -111,16 +119,31 @@ class SnowflakeEngineSpec(PostgresBaseEngineSpec): ), } + @staticmethod + def get_extra_params(database: "Database") -> Dict[str, Any]: + """ + Add a user agent to be used in the requests. + """ + extra: Dict[str, Any] = BaseEngineSpec.get_extra_params(database) + engine_params: Dict[str, Any] = extra.setdefault("engine_params", {}) + connect_args: Dict[str, Any] = engine_params.setdefault("connect_args", {}) + + connect_args.setdefault("application", USER_AGENT) + + return extra + @classmethod def adjust_database_uri( cls, uri: URL, selected_schema: Optional[str] = None - ) -> None: + ) -> URL: database = uri.database if "/" in uri.database: database = uri.database.split("/")[0] if selected_schema: selected_schema = parse.quote(selected_schema, safe="") - uri.database = database + "/" + selected_schema + uri = uri.set(database=f"{database}/{selected_schema}") + + return uri @classmethod def epoch_to_dttm(cls) -> str: @@ -134,13 +157,14 @@ def epoch_ms_to_dttm(cls) -> str: def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt == utils.TemporalType.DATE: + sqla_type = cls.get_sqla_column_type(target_type) + + if isinstance(sqla_type, types.Date): return f"TO_DATE('{dttm.date().isoformat()}')" - if tt == utils.TemporalType.DATETIME: - return f"""CAST('{dttm.isoformat(timespec="microseconds")}' AS DATETIME)""" - if tt == utils.TemporalType.TIMESTAMP: + if isinstance(sqla_type, types.TIMESTAMP): return f"""TO_TIMESTAMP('{dttm.isoformat(timespec="microseconds")}')""" + if isinstance(sqla_type, types.DateTime): + return f"""CAST('{dttm.isoformat(timespec="microseconds")}' AS DATETIME)""" return None @staticmethod @@ -234,7 +258,7 @@ def get_parameters_from_uri( @classmethod def validate_parameters( - cls, parameters: SnowflakeParametersType + cls, properties: BasicPropertiesType ) -> List[SupersetError]: errors: List[SupersetError] = [] required = { @@ -245,6 +269,7 @@ def validate_parameters( "role", "password", } + parameters = properties.get("parameters", {}) present = {key for key in parameters if parameters.get(key, ())} missing = sorted(required - present) @@ -277,3 +302,52 @@ def parameters_json_schema(cls) -> Any: spec.components.schema(cls.__name__, schema=cls.parameters_schema) return spec.to_dict()["components"]["schemas"][cls.__name__] + + @staticmethod + def update_params_from_encrypted_extra( + database: "Database", + params: Dict[str, Any], + ) -> None: + if not database.encrypted_extra: + return + try: + encrypted_extra = json.loads(database.encrypted_extra) + except json.JSONDecodeError as ex: + logger.error(ex, exc_info=True) + raise ex + auth_method = encrypted_extra.get("auth_method", None) + auth_params = encrypted_extra.get("auth_params", {}) + if not auth_method: + return + connect_args = params.setdefault("connect_args", {}) + if auth_method == "keypair": + privatekey_body = auth_params.get("privatekey_body", None) + key = None + if privatekey_body: + key = privatekey_body.encode() + else: + with open(auth_params["privatekey_path"], "rb") as key_temp: + key = key_temp.read() + p_key = serialization.load_pem_private_key( + key, + password=auth_params["privatekey_pass"].encode(), + backend=default_backend(), + ) + pkb = p_key.private_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.NoEncryption(), + ) + connect_args["private_key"] = pkb + else: + allowed_extra_auths = current_app.config[ + "ALLOWED_EXTRA_AUTHENTICATIONS" + ].get("snowflake", {}) + if auth_method in allowed_extra_auths: + snowflake_auth = allowed_extra_auths.get(auth_method) + else: + raise ValueError( + f"For security reason, custom authentication '{auth_method}' " + f"must be listed in 'ALLOWED_EXTRA_AUTHENTICATIONS' config" + ) + connect_args["auth"] = snowflake_auth(**auth_params) diff --git a/superset/db_engine_specs/spark.py b/superset/db_engine_specs/spark.py new file mode 100644 index 0000000000000..a6eeb2e9db4d0 --- /dev/null +++ b/superset/db_engine_specs/spark.py @@ -0,0 +1,41 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from superset.db_engine_specs.hive import HiveEngineSpec + +time_grain_expressions = { + None: "{col}", + "PT1S": "date_trunc('second', {col})", + "PT1M": "date_trunc('minute', {col})", + "PT1H": "date_trunc('hour', {col})", + "P1D": "date_trunc('day', {col})", + "P1W": "date_trunc('week', {col})", + "P1M": "date_trunc('month', {col})", + "P3M": "date_trunc('quarter', {col})", + "P1Y": "date_trunc('year', {col})", + "P1W/1970-01-03T00:00:00Z": ( + "date_trunc('week', {col} + interval '1 day') + interval '5 days'" + ), + "1969-12-28T00:00:00Z/P1W": ( + "date_trunc('week', {col} + interval '1 day') - interval '1 day'" + ), +} + + +class SparkEngineSpec(HiveEngineSpec): + _time_grain_expressions = time_grain_expressions + engine_name = "Apache Spark SQL" diff --git a/superset/db_engine_specs/sqlite.py b/superset/db_engine_specs/sqlite.py index b82b498c1689d..a414143296338 100644 --- a/superset/db_engine_specs/sqlite.py +++ b/superset/db_engine_specs/sqlite.py @@ -16,14 +16,14 @@ # under the License. import re from datetime import datetime -from typing import Any, Dict, List, Optional, Pattern, Tuple, TYPE_CHECKING +from typing import Any, Dict, Optional, Pattern, Set, Tuple, TYPE_CHECKING from flask_babel import gettext as __ +from sqlalchemy import types from sqlalchemy.engine.reflection import Inspector from superset.db_engine_specs.base import BaseEngineSpec from superset.errors import SupersetErrorType -from superset.utils import core as utils if TYPE_CHECKING: # prevent circular imports @@ -72,50 +72,18 @@ class SqliteEngineSpec(BaseEngineSpec): def epoch_to_dttm(cls) -> str: return "datetime({col}, 'unixepoch')" - @classmethod - def get_all_datasource_names( - cls, database: "Database", datasource_type: str - ) -> List[utils.DatasourceName]: - schemas = database.get_all_schema_names( - cache=database.schema_cache_enabled, - cache_timeout=database.schema_cache_timeout, - force=True, - ) - schema = schemas[0] - if datasource_type == "table": - return [ - utils.DatasourceName(*datasource_name) - for datasource_name in database.get_all_table_names_in_schema( - schema=schema, - force=True, - cache=database.table_cache_enabled, - cache_timeout=database.table_cache_timeout, - ) - ] - if datasource_type == "view": - return [ - utils.DatasourceName(*datasource_name) - for datasource_name in database.get_all_view_names_in_schema( - schema=schema, - force=True, - cache=database.table_cache_enabled, - cache_timeout=database.table_cache_timeout, - ) - ] - raise Exception(f"Unsupported datasource_type: {datasource_type}") - @classmethod def convert_dttm( cls, target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - tt = target_type.upper() - if tt in (utils.TemporalType.TEXT, utils.TemporalType.DATETIME): - return f"""'{dttm.isoformat(sep=" ", timespec="microseconds")}'""" + sqla_type = cls.get_sqla_column_type(target_type) + if isinstance(sqla_type, (types.String, types.DateTime)): + return f"""'{dttm.isoformat(sep=" ", timespec="seconds")}'""" return None @classmethod def get_table_names( cls, database: "Database", inspector: Inspector, schema: Optional[str] - ) -> List[str]: + ) -> Set[str]: """Need to disregard the schema for Sqlite""" - return sorted(inspector.get_table_names()) + return set(inspector.get_table_names()) diff --git a/superset/db_engine_specs/teradata.py b/superset/db_engine_specs/teradata.py index bd2ee5160530a..887add24e909e 100644 --- a/superset/db_engine_specs/teradata.py +++ b/superset/db_engine_specs/teradata.py @@ -36,7 +36,7 @@ class TeradataEngineSpec(BaseEngineSpec): "P1D": "TRUNC(CAST({col} as DATE), 'DDD')", "P1W": "TRUNC(CAST({col} as DATE), 'WW')", "P1M": "TRUNC(CAST({col} as DATE), 'MONTH')", - "P0.25Y": "TRUNC(CAST({col} as DATE), 'Q')", + "P3M": "TRUNC(CAST({col} as DATE), 'Q')", "P1Y": "TRUNC(CAST({col} as DATE), 'YEAR')", } diff --git a/superset/db_engine_specs/trino.py b/superset/db_engine_specs/trino.py index acddb97100266..712574efdd739 100644 --- a/superset/db_engine_specs/trino.py +++ b/superset/db_engine_specs/trino.py @@ -14,8 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from __future__ import annotations + import logging -from typing import Any, Dict, List, Optional, TYPE_CHECKING +from typing import Any, Dict, Optional, Type, TYPE_CHECKING import simplejson as json from flask import current_app @@ -23,23 +25,76 @@ from sqlalchemy.engine.url import URL from sqlalchemy.orm import Session +from superset.constants import QUERY_CANCEL_KEY, QUERY_EARLY_CANCEL_KEY, USER_AGENT from superset.databases.utils import make_url_safe from superset.db_engine_specs.base import BaseEngineSpec -from superset.db_engine_specs.presto import PrestoEngineSpec +from superset.db_engine_specs.exceptions import SupersetDBAPIConnectionError +from superset.db_engine_specs.presto import PrestoBaseEngineSpec from superset.models.sql_lab import Query from superset.utils import core as utils if TYPE_CHECKING: from superset.models.core import Database + try: + from trino.dbapi import Cursor + except ImportError: + pass + logger = logging.getLogger(__name__) -class TrinoEngineSpec(PrestoEngineSpec): +class TrinoEngineSpec(PrestoBaseEngineSpec): engine = "trino" - engine_aliases = {"trinonative"} # Required for backwards compatibility. engine_name = "Trino" + @classmethod + def extra_table_metadata( + cls, + database: Database, + table_name: str, + schema_name: Optional[str], + ) -> Dict[str, Any]: + metadata = {} + + indexes = database.get_indexes(table_name, schema_name) + if indexes: + col_names, latest_parts = cls.latest_partition( + table_name, schema_name, database, show_first=True + ) + + if not latest_parts: + latest_parts = tuple([None] * len(col_names)) + + metadata["partitions"] = { + "cols": sorted( + list( + set( + column_name + for index in indexes + if index.get("name") == "partition" + for column_name in index.get("column_names", []) + ) + ) + ), + "latest": dict(zip(col_names, latest_parts)), + "partitionQuery": cls._partition_query( + table_name=( + f"{schema_name}.{table_name}" + if schema_name and "." not in table_name + else table_name + ), + database=database, + ), + } + + if database.has_view_by_name(table_name, schema_name): + metadata["view"] = database.inspector.get_view_definition( + table_name, schema_name + ) + + return metadata + @classmethod def update_impersonation_config( cls, @@ -65,54 +120,90 @@ def update_impersonation_config( connect_args["user"] = username @classmethod - def modify_url_for_impersonation( + def get_url_for_impersonation( cls, url: URL, impersonate_user: bool, username: Optional[str] - ) -> None: + ) -> URL: """ - Modify the SQL Alchemy URL object with the user to impersonate if applicable. + Return a modified URL with the username set. + :param url: SQLAlchemy URL object :param impersonate_user: Flag indicating if impersonation is enabled :param username: Effective username """ # Do nothing and let update_impersonation_config take care of impersonation + return url @classmethod def get_allow_cost_estimate(cls, extra: Dict[str, Any]) -> bool: return True @classmethod - def get_table_names( - cls, - database: "Database", - inspector: Inspector, - schema: Optional[str], - ) -> List[str]: - return BaseEngineSpec.get_table_names( - database=database, - inspector=inspector, - schema=schema, - ) + def get_tracking_url(cls, cursor: Cursor) -> Optional[str]: + try: + return cursor.info_uri + except AttributeError: + try: + conn = cursor.connection + # pylint: disable=protected-access, line-too-long + return f"{conn.http_scheme}://{conn.host}:{conn.port}/ui/query.html?{cursor._query.query_id}" + except AttributeError: + pass + return None @classmethod - def get_view_names( - cls, - database: "Database", - inspector: Inspector, - schema: Optional[str], - ) -> List[str]: - return BaseEngineSpec.get_view_names( - database=database, - inspector=inspector, - schema=schema, + def handle_cursor(cls, cursor: Cursor, query: Query, session: Session) -> None: + tracking_url = cls.get_tracking_url(cursor) + if tracking_url: + query.tracking_url = tracking_url + + # Adds the executed query id to the extra payload so the query can be cancelled + query.set_extra_json_key( + key=QUERY_CANCEL_KEY, + value=(cancel_query_id := cursor.stats["queryId"]), ) + session.commit() + + # if query cancelation was requested prior to the handle_cursor call, but + # the query was still executed, trigger the actual query cancelation now + if query.extra.get(QUERY_EARLY_CANCEL_KEY): + cls.cancel_query( + cursor=cursor, + query=query, + cancel_query_id=cancel_query_id, + ) + + super().handle_cursor(cursor=cursor, query=query, session=session) + @classmethod - def handle_cursor(cls, cursor: Any, query: Query, session: Session) -> None: - """Updates progress information""" - BaseEngineSpec.handle_cursor(cursor=cursor, query=query, session=session) + def prepare_cancel_query(cls, query: Query, session: Session) -> None: + if QUERY_CANCEL_KEY not in query.extra: + query.set_extra_json_key(QUERY_EARLY_CANCEL_KEY, True) + session.commit() + + @classmethod + def cancel_query(cls, cursor: Any, query: Query, cancel_query_id: str) -> bool: + """ + Cancel query in the underlying database. + + :param cursor: New cursor instance to the db of the query + :param query: Query instance + :param cancel_query_id: Trino `queryId` + :return: True if query cancelled successfully, False otherwise + """ + try: + cursor.execute( + f"CALL system.runtime.kill_query(query_id => '{cancel_query_id}'," + "message => 'Query cancelled by Superset')" + ) + cursor.fetchall() # needed to trigger the call + except Exception: # pylint: disable=broad-except + return False + + return True @staticmethod - def get_extra_params(database: "Database") -> Dict[str, Any]: + def get_extra_params(database: Database) -> Dict[str, Any]: """ Some databases require adding elements to connection parameters, like passing certificates to `extra`. This can be done here. @@ -124,6 +215,8 @@ def get_extra_params(database: "Database") -> Dict[str, Any]: engine_params: Dict[str, Any] = extra.setdefault("engine_params", {}) connect_args: Dict[str, Any] = engine_params.setdefault("connect_args", {}) + connect_args.setdefault("source", USER_AGENT) + if database.server_cert: connect_args["http_scheme"] = "https" connect_args["verify"] = utils.create_ssl_cert_file(database.server_cert) @@ -131,8 +224,9 @@ def get_extra_params(database: "Database") -> Dict[str, Any]: return extra @staticmethod - def update_encrypted_extra_params( - database: "Database", params: Dict[str, Any] + def update_params_from_encrypted_extra( + database: Database, + params: Dict[str, Any], ) -> None: if not database.encrypted_extra: return @@ -150,6 +244,8 @@ def update_encrypted_extra_params( from trino.auth import BasicAuthentication as trino_auth # noqa elif auth_method == "kerberos": from trino.auth import KerberosAuthentication as trino_auth # noqa + elif auth_method == "certificate": + from trino.auth import CertificateAuthentication as trino_auth # noqa elif auth_method == "jwt": from trino.auth import JWTAuthentication as trino_auth # noqa else: @@ -168,3 +264,12 @@ def update_encrypted_extra_params( except json.JSONDecodeError as ex: logger.error(ex, exc_info=True) raise ex + + @classmethod + def get_dbapi_exception_mapping(cls) -> Dict[Type[Exception], Type[Exception]]: + # pylint: disable=import-outside-toplevel + from requests import exceptions as requests_exceptions + + return { + requests_exceptions.ConnectionError: SupersetDBAPIConnectionError, + } diff --git a/superset/db_engines/hive.py b/superset/db_engines/hive.py deleted file mode 100644 index 0c4094fe3ef2c..0000000000000 --- a/superset/db_engines/hive.py +++ /dev/null @@ -1,67 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from typing import Optional, TYPE_CHECKING - -if TYPE_CHECKING: - from pyhive.hive import Cursor - from TCLIService.ttypes import TFetchOrientation - -# TODO: contribute back to pyhive. -def fetch_logs( # pylint: disable=protected-access - self: "Cursor", - _max_rows: int = 1024, - orientation: Optional["TFetchOrientation"] = None, -) -> str: - """Mocked. Retrieve the logs produced by the execution of the query. - Can be called multiple times to fetch the logs produced after - the previous call. - :returns: list<str> - :raises: ``ProgrammingError`` when no query has been started - .. note:: - This is not a part of DB-API. - """ - # pylint: disable=import-outside-toplevel - from pyhive import hive - from TCLIService import ttypes - from thrift import Thrift - - orientation = orientation or ttypes.TFetchOrientation.FETCH_NEXT - try: - req = ttypes.TGetLogReq(operationHandle=self._operationHandle) - logs = self._connection.client.GetLog(req).log - return logs - # raised if Hive is used - except (ttypes.TApplicationException, Thrift.TApplicationException) as ex: - if self._state == self._STATE_NONE: - raise hive.ProgrammingError("No query yet") from ex - logs = [] - while True: - req = ttypes.TFetchResultsReq( - operationHandle=self._operationHandle, - orientation=ttypes.TFetchOrientation.FETCH_NEXT, - maxRows=self.arraysize, - fetchType=1, # 0: results, 1: logs - ) - response = self._connection.client.FetchResults(req) - hive._check_status(response) - assert not response.results.rows, "expected data in columnar format" - assert len(response.results.columns) == 1, response.results.columns - new_logs = hive._unwrap_column(response.results.columns[0]) - logs += new_logs - if not new_logs: - break - return "\n".join(logs) diff --git a/superset/embedded/view.py b/superset/embedded/view.py index 487850b728851..8dd383aadafec 100644 --- a/superset/embedded/view.py +++ b/superset/embedded/view.py @@ -17,11 +17,12 @@ import json from typing import Callable -from flask import abort +from flask import abort, g, request from flask_appbuilder import expose -from flask_login import AnonymousUserMixin, LoginManager +from flask_login import AnonymousUserMixin, login_user +from flask_wtf.csrf import same_origin -from superset import event_logger, is_feature_enabled, security_manager +from superset import event_logger, is_feature_enabled from superset.embedded.dao import EmbeddedDAO from superset.superset_typing import FlaskResponse from superset.utils import core as utils @@ -50,14 +51,24 @@ def embedded( abort(404) embedded = EmbeddedDAO.find_by_id(uuid) + if not embedded: abort(404) + # validate request referrer in allowed domains + is_referrer_allowed = not embedded.allowed_domains + for domain in embedded.allowed_domains: + if same_origin(request.referrer, domain): + is_referrer_allowed = True + break + + if not is_referrer_allowed: + abort(403) + # Log in as an anonymous user, just for this view. # This view needs to be visible to all users, # and building the page fails if g.user and/or ctx.user aren't present. - login_manager: LoginManager = security_manager.lm - login_manager.reload_user(AnonymousUserMixin()) + login_user(AnonymousUserMixin(), force=True) add_extra_log_payload( embedded_dashboard_id=uuid, @@ -65,7 +76,7 @@ def embedded( ) bootstrap_data = { - "common": common_bootstrap_payload(), + "common": common_bootstrap_payload(g.user), "embedded": { "dashboard_id": embedded.dashboard_id, }, diff --git a/superset/errors.py b/superset/errors.py index 9198a82d3fe61..2df0eb82b26e0 100644 --- a/superset/errors.py +++ b/superset/errors.py @@ -18,7 +18,7 @@ from enum import Enum from typing import Any, Dict, Optional -from flask_babel import gettext as _ +from flask_babel import lazy_gettext as _ class SupersetErrorType(str, Enum): @@ -90,6 +90,9 @@ class SupersetErrorType(str, Enum): INVALID_PAYLOAD_FORMAT_ERROR = "INVALID_PAYLOAD_FORMAT_ERROR" INVALID_PAYLOAD_SCHEMA_ERROR = "INVALID_PAYLOAD_SCHEMA_ERROR" + # Report errors + REPORT_NOTIFICATION_ERROR = "REPORT_NOTIFICATION_ERROR" + ISSUE_CODES = { 1000: _("The datasource is too large to query."), diff --git a/superset/examples/bart_lines.py b/superset/examples/bart_lines.py index bcdf3589a821e..5d167b02d0627 100644 --- a/superset/examples/bart_lines.py +++ b/superset/examples/bart_lines.py @@ -23,37 +23,37 @@ from superset import db from ..utils.database import get_example_database -from .helpers import get_example_data, get_table_connector_registry +from .helpers import get_example_url, get_table_connector_registry def load_bart_lines(only_metadata: bool = False, force: bool = False) -> None: tbl_name = "bart_lines" database = get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - table_exists = database.has_table_by_name(tbl_name) + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + table_exists = database.has_table_by_name(tbl_name) - if not only_metadata and (not table_exists or force): - content = get_example_data("bart-lines.json.gz") - df = pd.read_json(content, encoding="latin-1") - df["path_json"] = df.path.map(json.dumps) - df["polyline"] = df.path.map(polyline.encode) - del df["path"] + if not only_metadata and (not table_exists or force): + url = get_example_url("bart-lines.json.gz") + df = pd.read_json(url, encoding="latin-1", compression="gzip") + df["path_json"] = df.path.map(json.dumps) + df["polyline"] = df.path.map(polyline.encode) + del df["path"] - df.to_sql( - tbl_name, - engine, - schema=schema, - if_exists="replace", - chunksize=500, - dtype={ - "color": String(255), - "name": String(255), - "polyline": Text, - "path_json": Text, - }, - index=False, - ) + df.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=500, + dtype={ + "color": String(255), + "name": String(255), + "polyline": Text, + "path_json": Text, + }, + index=False, + ) print("Creating table {} reference".format(tbl_name)) table = get_table_connector_registry() diff --git a/superset/examples/birth_names.py b/superset/examples/birth_names.py index 6b37fe9d08dcf..8da041550e92a 100644 --- a/superset/examples/birth_names.py +++ b/superset/examples/birth_names.py @@ -19,13 +19,11 @@ from typing import Dict, List, Tuple, Union import pandas as pd -from flask_appbuilder.security.sqla.models import User from sqlalchemy import DateTime, inspect, String from sqlalchemy.sql import column -from superset import app, db, security_manager +from superset import app, db from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn -from superset.exceptions import NoDataException from superset.models.core import Database from superset.models.dashboard import Dashboard from superset.models.slice import Slice @@ -33,7 +31,7 @@ from ..utils.database import get_example_database from .helpers import ( - get_example_data, + get_example_url, get_slice_json, get_table_connector_registry, merge_slice, @@ -42,17 +40,6 @@ ) -def get_admin_user() -> User: - admin = security_manager.find_user("admin") - if admin is None: - raise NoDataException( - "Admin user does not exist. " - "Please, check if test users are properly loaded " - "(`superset load_test_users`)." - ) - return admin - - def gen_filter( subject: str, comparator: str, operator: str = "==" ) -> Dict[str, Union[bool, str]]: @@ -66,7 +53,8 @@ def gen_filter( def load_data(tbl_name: str, database: Database, sample: bool = False) -> None: - pdf = pd.read_json(get_example_data("birth_names2.json.gz")) + url = get_example_url("birth_names2.json.gz") + pdf = pd.read_json(url, compression="gzip") # TODO(bkyryliuk): move load examples data into the pytest fixture if database.backend == "presto": pdf.ds = pd.to_datetime(pdf.ds, unit="ms") @@ -75,25 +63,25 @@ def load_data(tbl_name: str, database: Database, sample: bool = False) -> None: pdf.ds = pd.to_datetime(pdf.ds, unit="ms") pdf = pdf.head(100) if sample else pdf - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - - pdf.to_sql( - tbl_name, - database.get_sqla_engine(), - schema=schema, - if_exists="replace", - chunksize=500, - dtype={ - # TODO(bkyryliuk): use TIMESTAMP type for presto - "ds": DateTime if database.backend != "presto" else String(255), - "gender": String(16), - "state": String(10), - "name": String(255), - }, - method="multi", - index=False, - ) + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + + pdf.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=500, + dtype={ + # TODO(bkyryliuk): use TIMESTAMP type for presto + "ds": DateTime if database.backend != "presto" else String(255), + "gender": String(16), + "state": String(10), + "name": String(255), + }, + method="multi", + index=False, + ) print("Done loading table!") print("-" * 80) @@ -103,8 +91,8 @@ def load_birth_names( ) -> None: """Loading birth name dataset from a zip file in the repo""" database = get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name tbl_name = "birth_names" table_exists = database.has_table_by_name(tbl_name, schema=schema) @@ -124,7 +112,7 @@ def load_birth_names( db.session.commit() - slices, _ = create_slices(obj, admin_owner=True) + slices, _ = create_slices(obj) create_dashboard(slices) @@ -156,12 +144,15 @@ def _add_table_metrics(datasource: SqlaTable) -> None: metrics.append(SqlMetric(metric_name="sum__num", expression=f"SUM({col})")) for col in columns: - if col.column_name == "ds": - col.is_dttm = True + if col.column_name == "ds": # type: ignore + col.is_dttm = True # type: ignore break + datasource.columns = columns + datasource.metrics = metrics + -def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[Slice]]: +def create_slices(tbl: SqlaTable) -> Tuple[List[Slice], List[Slice]]: metrics = [ { "expressionType": "SIMPLE", @@ -177,12 +168,10 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ "compare_lag": "10", "compare_suffix": "o10Y", "limit": "25", - "time_range": "No filter", "granularity_sqla": "ds", "groupby": [], "row_limit": app.config["ROW_LIMIT"], - "since": "100 years ago", - "until": "now", + "time_range": "100 years ago : now", "viz_type": "table", "markup_type": "markdown", } @@ -202,26 +191,16 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ], } - admin = get_admin_user() - if admin_owner: - slice_props = dict( - datasource_id=tbl.id, - datasource_type=DatasourceType.TABLE, - owners=[admin], - created_by=admin, - ) - else: - slice_props = dict( - datasource_id=tbl.id, - datasource_type=DatasourceType.TABLE, - owners=[], - created_by=admin, - ) + slice_kwargs = { + "datasource_id": tbl.id, + "datasource_type": DatasourceType.TABLE, + "owners": [], + } print("Creating some slices") slices = [ Slice( - **slice_props, + **slice_kwargs, slice_name="Participants", viz_type="big_number", params=get_slice_json( @@ -234,7 +213,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Genders", viz_type="pie", params=get_slice_json( @@ -242,7 +221,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Trends", viz_type="line", params=get_slice_json( @@ -256,7 +235,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Genders by State", viz_type="dist_bar", params=get_slice_json( @@ -292,7 +271,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Girls", viz_type="table", params=get_slice_json( @@ -305,7 +284,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Girl Name Cloud", viz_type="word_cloud", params=get_slice_json( @@ -321,7 +300,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Boys", viz_type="table", params=get_slice_json( @@ -334,7 +313,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Boy Name Cloud", viz_type="word_cloud", params=get_slice_json( @@ -350,7 +329,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Top 10 Girl Name Share", viz_type="area", params=get_slice_json( @@ -367,7 +346,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Top 10 Boy Name Share", viz_type="area", params=get_slice_json( @@ -384,7 +363,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Pivot Table v2", viz_type="pivot_table_v2", params=get_slice_json( @@ -407,7 +386,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ] misc_slices = [ Slice( - **slice_props, + **slice_kwargs, slice_name="Average and Sum Trends", viz_type="dual_line", params=get_slice_json( @@ -426,26 +405,25 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Num Births Trend", viz_type="line", params=get_slice_json(defaults, viz_type="line", metrics=metrics), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Daily Totals", viz_type="table", params=get_slice_json( defaults, groupby=["ds"], - since="40 years ago", - until="now", + time_range="1983 : 2023", viz_type="table", metrics=metrics, ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Number of California Births", viz_type="big_number_total", params=get_slice_json( @@ -464,7 +442,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Top 10 California Names Timeseries", viz_type="line", params=get_slice_json( @@ -496,7 +474,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Names Sorted by Num in California", viz_type="table", params=get_slice_json( @@ -516,7 +494,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Number of Girls", viz_type="big_number_total", params=get_slice_json( @@ -529,7 +507,7 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ ), ), Slice( - **slice_props, + **slice_kwargs, slice_name="Pivot Table", viz_type="pivot_table", params=get_slice_json( @@ -553,12 +531,10 @@ def create_slices(tbl: SqlaTable, admin_owner: bool) -> Tuple[List[Slice], List[ def create_dashboard(slices: List[Slice]) -> Dashboard: print("Creating a dashboard") - admin = get_admin_user() dash = db.session.query(Dashboard).filter_by(slug="births").first() if not dash: dash = Dashboard() - dash.owners = [admin] - dash.created_by = admin + dash.owners = [] db.session.add(dash) dash.published = True diff --git a/superset/examples/configs/dashboards/COVID_Vaccine_Dashboard.yaml b/superset/examples/configs/dashboards/COVID_Vaccine_Dashboard.yaml index fad874d60030e..a954e63a0272f 100644 --- a/superset/examples/configs/dashboards/COVID_Vaccine_Dashboard.yaml +++ b/superset/examples/configs/dashboards/COVID_Vaccine_Dashboard.yaml @@ -90,7 +90,7 @@ position: chartId: 3962 height: 82 sliceName: Vaccine Candidates per Approach & Stage - sliceNameOverride: Heatmap of Aproaches & Clinical Stages + sliceNameOverride: Heatmap of Approaches & Clinical Stages uuid: 0c953c84-0c9a-418d-be9f-2894d2a2cee0 width: 4 parents: diff --git a/superset/examples/country_map.py b/superset/examples/country_map.py index c959a92085fc0..4331033ca8369 100644 --- a/superset/examples/country_map.py +++ b/superset/examples/country_map.py @@ -27,7 +27,7 @@ from superset.utils.core import DatasourceType from .helpers import ( - get_example_data, + get_example_url, get_slice_json, get_table_connector_registry, merge_slice, @@ -39,40 +39,39 @@ def load_country_map_data(only_metadata: bool = False, force: bool = False) -> N """Loading data for map with country map""" tbl_name = "birth_france_by_region" database = database_utils.get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - table_exists = database.has_table_by_name(tbl_name) - if not only_metadata and (not table_exists or force): - csv_bytes = get_example_data( - "birth_france_data_for_country_map.csv", is_gzip=False, make_bytes=True - ) - data = pd.read_csv(csv_bytes, encoding="utf-8") - data["dttm"] = datetime.datetime.now().date() - data.to_sql( - tbl_name, - engine, - schema=schema, - if_exists="replace", - chunksize=500, - dtype={ - "DEPT_ID": String(10), - "2003": BigInteger, - "2004": BigInteger, - "2005": BigInteger, - "2006": BigInteger, - "2007": BigInteger, - "2008": BigInteger, - "2009": BigInteger, - "2010": BigInteger, - "2011": BigInteger, - "2012": BigInteger, - "2013": BigInteger, - "2014": BigInteger, - "dttm": Date(), - }, - index=False, - ) + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + table_exists = database.has_table_by_name(tbl_name) + + if not only_metadata and (not table_exists or force): + url = get_example_url("birth_france_data_for_country_map.csv") + data = pd.read_csv(url, encoding="utf-8") + data["dttm"] = datetime.datetime.now().date() + data.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=500, + dtype={ + "DEPT_ID": String(10), + "2003": BigInteger, + "2004": BigInteger, + "2005": BigInteger, + "2006": BigInteger, + "2007": BigInteger, + "2008": BigInteger, + "2009": BigInteger, + "2010": BigInteger, + "2011": BigInteger, + "2012": BigInteger, + "2013": BigInteger, + "2014": BigInteger, + "dttm": Date(), + }, + index=False, + ) print("Done loading table!") print("-" * 80) diff --git a/superset/examples/data_loading.py b/superset/examples/data_loading.py index 6eae82a799763..f24ebfc576b6a 100644 --- a/superset/examples/data_loading.py +++ b/superset/examples/data_loading.py @@ -30,6 +30,7 @@ from .paris import load_paris_iris_geojson from .random_time_series import load_random_time_series_data from .sf_population_polygons import load_sf_population_polygons +from .supported_charts_dashboard import load_supported_charts_dashboard from .tabbed_dashboard import load_tabbed_dashboard from .utils import load_examples_from_configs from .world_bank import load_world_bank_health_n_pop diff --git a/superset/examples/energy.py b/superset/examples/energy.py index d88d693651d42..6688e5d08844d 100644 --- a/superset/examples/energy.py +++ b/superset/examples/energy.py @@ -28,7 +28,7 @@ from superset.utils.core import DatasourceType from .helpers import ( - get_example_data, + get_example_url, get_table_connector_registry, merge_slice, misc_dash_slices, @@ -41,24 +41,25 @@ def load_energy( """Loads an energy related dataset to use with sankey and graphs""" tbl_name = "energy_usage" database = database_utils.get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - table_exists = database.has_table_by_name(tbl_name) - if not only_metadata and (not table_exists or force): - data = get_example_data("energy.json.gz") - pdf = pd.read_json(data) - pdf = pdf.head(100) if sample else pdf - pdf.to_sql( - tbl_name, - engine, - schema=schema, - if_exists="replace", - chunksize=500, - dtype={"source": String(255), "target": String(255), "value": Float()}, - index=False, - method="multi", - ) + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + table_exists = database.has_table_by_name(tbl_name) + + if not only_metadata and (not table_exists or force): + url = get_example_url("energy.json.gz") + pdf = pd.read_json(url, compression="gzip") + pdf = pdf.head(100) if sample else pdf + pdf.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=500, + dtype={"source": String(255), "target": String(255), "value": Float()}, + index=False, + method="multi", + ) print("Creating table [wb_health_population] reference") table = get_table_connector_registry() diff --git a/superset/examples/flights.py b/superset/examples/flights.py index 46fdc5c1d07a1..7c8f9802988bd 100644 --- a/superset/examples/flights.py +++ b/superset/examples/flights.py @@ -20,42 +20,44 @@ import superset.utils.database as database_utils from superset import db -from .helpers import get_example_data, get_table_connector_registry +from .helpers import get_example_url, get_table_connector_registry def load_flights(only_metadata: bool = False, force: bool = False) -> None: """Loading random time series data from a zip file in the repo""" tbl_name = "flights" database = database_utils.get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - table_exists = database.has_table_by_name(tbl_name) + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + table_exists = database.has_table_by_name(tbl_name) - if not only_metadata and (not table_exists or force): - data = get_example_data("flight_data.csv.gz", make_bytes=True) - pdf = pd.read_csv(data, encoding="latin-1") + if not only_metadata and (not table_exists or force): + flight_data_url = get_example_url("flight_data.csv.gz") + pdf = pd.read_csv(flight_data_url, encoding="latin-1", compression="gzip") - # Loading airports info to join and get lat/long - airports_bytes = get_example_data("airports.csv.gz", make_bytes=True) - airports = pd.read_csv(airports_bytes, encoding="latin-1") - airports = airports.set_index("IATA_CODE") + # Loading airports info to join and get lat/long + airports_url = get_example_url("airports.csv.gz") + airports = pd.read_csv(airports_url, encoding="latin-1", compression="gzip") + airports = airports.set_index("IATA_CODE") - pdf[ # pylint: disable=unsupported-assignment-operation,useless-suppression - "ds" - ] = (pdf.YEAR.map(str) + "-0" + pdf.MONTH.map(str) + "-0" + pdf.DAY.map(str)) - pdf.ds = pd.to_datetime(pdf.ds) - pdf.drop(columns=["DAY", "MONTH", "YEAR"]) - pdf = pdf.join(airports, on="ORIGIN_AIRPORT", rsuffix="_ORIG") - pdf = pdf.join(airports, on="DESTINATION_AIRPORT", rsuffix="_DEST") - pdf.to_sql( - tbl_name, - engine, - schema=schema, - if_exists="replace", - chunksize=500, - dtype={"ds": DateTime}, - index=False, - ) + pdf[ # pylint: disable=unsupported-assignment-operation,useless-suppression + "ds" + ] = ( + pdf.YEAR.map(str) + "-0" + pdf.MONTH.map(str) + "-0" + pdf.DAY.map(str) + ) + pdf.ds = pd.to_datetime(pdf.ds) + pdf.drop(columns=["DAY", "MONTH", "YEAR"]) + pdf = pdf.join(airports, on="ORIGIN_AIRPORT", rsuffix="_ORIG") + pdf = pdf.join(airports, on="DESTINATION_AIRPORT", rsuffix="_DEST") + pdf.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=500, + dtype={"ds": DateTime}, + index=False, + ) table = get_table_connector_registry() tbl = db.session.query(table).filter_by(table_name=tbl_name).first() diff --git a/superset/examples/helpers.py b/superset/examples/helpers.py index 9d17e73773299..e26e05e49739a 100644 --- a/superset/examples/helpers.py +++ b/superset/examples/helpers.py @@ -17,13 +17,10 @@ """Loads datasets, dashboards and slices in a new superset instance""" import json import os -import zlib -from io import BytesIO from typing import Any, Dict, List, Set -from urllib import request from superset import app, db -from superset.connectors.connector_registry import ConnectorRegistry +from superset.connectors.sqla.models import SqlaTable from superset.models.slice import Slice BASE_URL = "https://github.com/apache-superset/examples-data/blob/master/" @@ -32,7 +29,7 @@ def get_table_connector_registry() -> Any: - return ConnectorRegistry.sources["table"] + return SqlaTable def get_examples_folder() -> str: @@ -73,14 +70,5 @@ def get_slice_json(defaults: Dict[Any, Any], **kwargs: Any) -> str: return json.dumps(defaults_copy, indent=4, sort_keys=True) -def get_example_data( - filepath: str, is_gzip: bool = True, make_bytes: bool = False -) -> BytesIO: - content = request.urlopen( # pylint: disable=consider-using-with - f"{BASE_URL}{filepath}?raw=true" - ).read() - if is_gzip: - content = zlib.decompress(content, zlib.MAX_WBITS | 16) - if make_bytes: - content = BytesIO(content) - return content +def get_example_url(filepath: str) -> str: + return f"{BASE_URL}{filepath}?raw=true" diff --git a/superset/examples/long_lat.py b/superset/examples/long_lat.py index ba9824bb43fea..88b45548f48dc 100644 --- a/superset/examples/long_lat.py +++ b/superset/examples/long_lat.py @@ -27,7 +27,7 @@ from superset.utils.core import DatasourceType from .helpers import ( - get_example_data, + get_example_url, get_slice_json, get_table_connector_registry, merge_slice, @@ -39,49 +39,51 @@ def load_long_lat_data(only_metadata: bool = False, force: bool = False) -> None """Loading lat/long data from a csv file in the repo""" tbl_name = "long_lat" database = database_utils.get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - table_exists = database.has_table_by_name(tbl_name) + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + table_exists = database.has_table_by_name(tbl_name) - if not only_metadata and (not table_exists or force): - data = get_example_data("san_francisco.csv.gz", make_bytes=True) - pdf = pd.read_csv(data, encoding="utf-8") - start = datetime.datetime.now().replace( - hour=0, minute=0, second=0, microsecond=0 - ) - pdf["datetime"] = [ - start + datetime.timedelta(hours=i * 24 / (len(pdf) - 1)) - for i in range(len(pdf)) - ] - pdf["occupancy"] = [random.randint(1, 6) for _ in range(len(pdf))] - pdf["radius_miles"] = [random.uniform(1, 3) for _ in range(len(pdf))] - pdf["geohash"] = pdf[["LAT", "LON"]].apply(lambda x: geohash.encode(*x), axis=1) - pdf["delimited"] = pdf["LAT"].map(str).str.cat(pdf["LON"].map(str), sep=",") - pdf.to_sql( - tbl_name, - engine, - schema=schema, - if_exists="replace", - chunksize=500, - dtype={ - "longitude": Float(), - "latitude": Float(), - "number": Float(), - "street": String(100), - "unit": String(10), - "city": String(50), - "district": String(50), - "region": String(50), - "postcode": Float(), - "id": String(100), - "datetime": DateTime(), - "occupancy": Float(), - "radius_miles": Float(), - "geohash": String(12), - "delimited": String(60), - }, - index=False, - ) + if not only_metadata and (not table_exists or force): + url = get_example_url("san_francisco.csv.gz") + pdf = pd.read_csv(url, encoding="utf-8", compression="gzip") + start = datetime.datetime.now().replace( + hour=0, minute=0, second=0, microsecond=0 + ) + pdf["datetime"] = [ + start + datetime.timedelta(hours=i * 24 / (len(pdf) - 1)) + for i in range(len(pdf)) + ] + pdf["occupancy"] = [random.randint(1, 6) for _ in range(len(pdf))] + pdf["radius_miles"] = [random.uniform(1, 3) for _ in range(len(pdf))] + pdf["geohash"] = pdf[["LAT", "LON"]].apply( + lambda x: geohash.encode(*x), axis=1 + ) + pdf["delimited"] = pdf["LAT"].map(str).str.cat(pdf["LON"].map(str), sep=",") + pdf.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=500, + dtype={ + "longitude": Float(), + "latitude": Float(), + "number": Float(), + "street": String(100), + "unit": String(10), + "city": String(50), + "district": String(50), + "region": String(50), + "postcode": Float(), + "id": String(100), + "datetime": DateTime(), + "occupancy": Float(), + "radius_miles": Float(), + "geohash": String(12), + "delimited": String(60), + }, + index=False, + ) print("Done loading table!") print("-" * 80) diff --git a/superset/examples/multiformat_time_series.py b/superset/examples/multiformat_time_series.py index 9b8bb22c98e89..b030bcdb0f23c 100644 --- a/superset/examples/multiformat_time_series.py +++ b/superset/examples/multiformat_time_series.py @@ -25,7 +25,7 @@ from ..utils.database import get_example_database from .helpers import ( - get_example_data, + get_example_url, get_slice_json, get_table_connector_registry, merge_slice, @@ -39,41 +39,41 @@ def load_multiformat_time_series( # pylint: disable=too-many-locals """Loading time series data from a zip file in the repo""" tbl_name = "multiformat_time_series" database = get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - table_exists = database.has_table_by_name(tbl_name) + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + table_exists = database.has_table_by_name(tbl_name) - if not only_metadata and (not table_exists or force): - data = get_example_data("multiformat_time_series.json.gz") - pdf = pd.read_json(data) - # TODO(bkyryliuk): move load examples data into the pytest fixture - if database.backend == "presto": - pdf.ds = pd.to_datetime(pdf.ds, unit="s") - pdf.ds = pdf.ds.dt.strftime("%Y-%m-%d") - pdf.ds2 = pd.to_datetime(pdf.ds2, unit="s") - pdf.ds2 = pdf.ds2.dt.strftime("%Y-%m-%d %H:%M%:%S") - else: - pdf.ds = pd.to_datetime(pdf.ds, unit="s") - pdf.ds2 = pd.to_datetime(pdf.ds2, unit="s") + if not only_metadata and (not table_exists or force): + url = get_example_url("multiformat_time_series.json.gz") + pdf = pd.read_json(url, compression="gzip") + # TODO(bkyryliuk): move load examples data into the pytest fixture + if database.backend == "presto": + pdf.ds = pd.to_datetime(pdf.ds, unit="s") + pdf.ds = pdf.ds.dt.strftime("%Y-%m-%d") + pdf.ds2 = pd.to_datetime(pdf.ds2, unit="s") + pdf.ds2 = pdf.ds2.dt.strftime("%Y-%m-%d %H:%M%:%S") + else: + pdf.ds = pd.to_datetime(pdf.ds, unit="s") + pdf.ds2 = pd.to_datetime(pdf.ds2, unit="s") - pdf.to_sql( - tbl_name, - engine, - schema=schema, - if_exists="replace", - chunksize=500, - dtype={ - "ds": String(255) if database.backend == "presto" else Date, - "ds2": String(255) if database.backend == "presto" else DateTime, - "epoch_s": BigInteger, - "epoch_ms": BigInteger, - "string0": String(100), - "string1": String(100), - "string2": String(100), - "string3": String(100), - }, - index=False, - ) + pdf.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=500, + dtype={ + "ds": String(255) if database.backend == "presto" else Date, + "ds2": String(255) if database.backend == "presto" else DateTime, + "epoch_s": BigInteger, + "epoch_ms": BigInteger, + "string0": String(100), + "string1": String(100), + "string2": String(100), + "string3": String(100), + }, + index=False, + ) print("Done loading table!") print("-" * 80) diff --git a/superset/examples/paris.py b/superset/examples/paris.py index 264d80feeb695..a54a3706b13c0 100644 --- a/superset/examples/paris.py +++ b/superset/examples/paris.py @@ -22,35 +22,35 @@ import superset.utils.database as database_utils from superset import db -from .helpers import get_example_data, get_table_connector_registry +from .helpers import get_example_url, get_table_connector_registry def load_paris_iris_geojson(only_metadata: bool = False, force: bool = False) -> None: tbl_name = "paris_iris_mapping" database = database_utils.get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - table_exists = database.has_table_by_name(tbl_name) + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + table_exists = database.has_table_by_name(tbl_name) - if not only_metadata and (not table_exists or force): - data = get_example_data("paris_iris.json.gz") - df = pd.read_json(data) - df["features"] = df.features.map(json.dumps) + if not only_metadata and (not table_exists or force): + url = get_example_url("paris_iris.json.gz") + df = pd.read_json(url, compression="gzip") + df["features"] = df.features.map(json.dumps) - df.to_sql( - tbl_name, - engine, - schema=schema, - if_exists="replace", - chunksize=500, - dtype={ - "color": String(255), - "name": String(255), - "features": Text, - "type": Text, - }, - index=False, - ) + df.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=500, + dtype={ + "color": String(255), + "name": String(255), + "features": Text, + "type": Text, + }, + index=False, + ) print("Creating table {} reference".format(tbl_name)) table = get_table_connector_registry() diff --git a/superset/examples/random_time_series.py b/superset/examples/random_time_series.py index 152b63e1cc326..9a296ec2c4713 100644 --- a/superset/examples/random_time_series.py +++ b/superset/examples/random_time_series.py @@ -24,7 +24,7 @@ from superset.utils.core import DatasourceType from .helpers import ( - get_example_data, + get_example_url, get_slice_json, get_table_connector_registry, merge_slice, @@ -37,28 +37,28 @@ def load_random_time_series_data( """Loading random time series data from a zip file in the repo""" tbl_name = "random_time_series" database = database_utils.get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - table_exists = database.has_table_by_name(tbl_name) + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + table_exists = database.has_table_by_name(tbl_name) - if not only_metadata and (not table_exists or force): - data = get_example_data("random_time_series.json.gz") - pdf = pd.read_json(data) - if database.backend == "presto": - pdf.ds = pd.to_datetime(pdf.ds, unit="s") - pdf.ds = pdf.ds.dt.strftime("%Y-%m-%d %H:%M%:%S") - else: - pdf.ds = pd.to_datetime(pdf.ds, unit="s") + if not only_metadata and (not table_exists or force): + url = get_example_url("random_time_series.json.gz") + pdf = pd.read_json(url, compression="gzip") + if database.backend == "presto": + pdf.ds = pd.to_datetime(pdf.ds, unit="s") + pdf.ds = pdf.ds.dt.strftime("%Y-%m-%d %H:%M%:%S") + else: + pdf.ds = pd.to_datetime(pdf.ds, unit="s") - pdf.to_sql( - tbl_name, - engine, - schema=schema, - if_exists="replace", - chunksize=500, - dtype={"ds": DateTime if database.backend != "presto" else String(255)}, - index=False, - ) + pdf.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=500, + dtype={"ds": DateTime if database.backend != "presto" else String(255)}, + index=False, + ) print("Done loading table!") print("-" * 80) diff --git a/superset/examples/sf_population_polygons.py b/superset/examples/sf_population_polygons.py index 6e60d60121b51..6011b82b09651 100644 --- a/superset/examples/sf_population_polygons.py +++ b/superset/examples/sf_population_polygons.py @@ -22,7 +22,7 @@ import superset.utils.database as database_utils from superset import db -from .helpers import get_example_data, get_table_connector_registry +from .helpers import get_example_url, get_table_connector_registry def load_sf_population_polygons( @@ -30,29 +30,29 @@ def load_sf_population_polygons( ) -> None: tbl_name = "sf_population_polygons" database = database_utils.get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - table_exists = database.has_table_by_name(tbl_name) + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + table_exists = database.has_table_by_name(tbl_name) - if not only_metadata and (not table_exists or force): - data = get_example_data("sf_population.json.gz") - df = pd.read_json(data) - df["contour"] = df.contour.map(json.dumps) + if not only_metadata and (not table_exists or force): + url = get_example_url("sf_population.json.gz") + df = pd.read_json(url, compression="gzip") + df["contour"] = df.contour.map(json.dumps) - df.to_sql( - tbl_name, - engine, - schema=schema, - if_exists="replace", - chunksize=500, - dtype={ - "zipcode": BigInteger, - "population": BigInteger, - "contour": Text, - "area": Float, - }, - index=False, - ) + df.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=500, + dtype={ + "zipcode": BigInteger, + "population": BigInteger, + "contour": Text, + "area": Float, + }, + index=False, + ) print("Creating table {} reference".format(tbl_name)) table = get_table_connector_registry() diff --git a/superset/examples/supported_charts_dashboard.py b/superset/examples/supported_charts_dashboard.py new file mode 100644 index 0000000000000..54aa650d502b0 --- /dev/null +++ b/superset/examples/supported_charts_dashboard.py @@ -0,0 +1,1288 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# pylint: disable=too-many-lines + +import json +import textwrap +from typing import List + +from sqlalchemy import inspect + +from superset import db +from superset.connectors.sqla.models import SqlaTable +from superset.models.dashboard import Dashboard +from superset.models.slice import Slice +from superset.utils.core import DatasourceType + +from ..utils.database import get_example_database +from .helpers import ( + get_slice_json, + get_table_connector_registry, + merge_slice, + update_slice_ids, +) + +DASH_SLUG = "supported_charts_dash" + + +def create_slices(tbl: SqlaTable) -> List[Slice]: + slice_kwargs = { + "datasource_id": tbl.id, + "datasource_type": DatasourceType.TABLE, + "owners": [], + } + + defaults = { + "limit": "25", + "time_range": "100 years ago : now", + "granularity_sqla": "ds", + "row_limit": "50000", + "viz_type": "echarts_timeseries_bar", + } + + slices = [ + # --------------------- + # TIER 1 + # --------------------- + Slice( + **slice_kwargs, + slice_name="Big Number", + viz_type="big_number_total", + params=get_slice_json( + defaults, + viz_type="big_number_total", + metric="sum__num", + ), + ), + Slice( + **slice_kwargs, + slice_name="Big Number with Trendline", + viz_type="big_number", + params=get_slice_json( + defaults, + viz_type="big_number", + metric="sum__num", + ), + ), + Slice( + **slice_kwargs, + slice_name="Table", + viz_type="table", + params=get_slice_json( + defaults, + viz_type="table", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Pivot Table", + viz_type="pivot_table_v2", + params=get_slice_json( + defaults, + viz_type="pivot_table_v2", + metrics=["sum__num"], + groupbyColumns=["gender"], + groupbyRows=["state"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Time-Series Line Chart", + viz_type="echarts_timeseries_line", + params=get_slice_json( + defaults, + viz_type="echarts_timeseries_line", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Time-Series Area Chart", + viz_type="echarts_area", + params=get_slice_json( + defaults, + viz_type="echarts_area", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Time-Series Bar Chart V2", + viz_type="echarts_timeseries_bar", + params=get_slice_json( + defaults, + viz_type="echarts_timeseries_bar", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Time-Series Scatter Chart", + viz_type="echarts_timeseries_scatter", + params=get_slice_json( + defaults, + viz_type="echarts_timeseries_scatter", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Pie Chart", + viz_type="pie", + params=get_slice_json( + defaults, + viz_type="pie", + metric="sum__num", + groupby=["gender"], + adhoc_filters=[], + ), + ), + Slice( + **slice_kwargs, + slice_name="Bar Chart", + viz_type="dist_bar", + params=get_slice_json( + defaults, + viz_type="dist_bar", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + # --------------------- + # TIER 2 + # --------------------- + Slice( + **slice_kwargs, + slice_name="Box Plot Chart", + viz_type="box_plot", + params=get_slice_json( + defaults, + viz_type="box_plot", + metrics=["sum__num"], + groupby=["gender"], + columns=["name"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Bubble Chart", + viz_type="bubble", + params=get_slice_json( + defaults, + viz_type="bubble", + size="count", + series="state", + entity="gender", + x={ + "expressionType": "SIMPLE", + "column": { + "column_name": "num_boys", + }, + "aggregate": "SUM", + "label": "SUM(num_boys)", + "optionName": "metric_353e7rjj84m_cirsi2o2s1", + }, + y={ + "expressionType": "SIMPLE", + "column": { + "column_name": "num_girls", + }, + "aggregate": "SUM", + "label": "SUM(num_girls)", + "optionName": "metric_n8rvsr2ysmr_cb3eybtoe5f", + }, + ), + ), + Slice( + **slice_kwargs, + slice_name="Calendar Heatmap", + viz_type="cal_heatmap", + params=get_slice_json( + defaults, + viz_type="cal_heatmap", + metrics=["sum__num"], + time_range="2008-01-01 : 2008-02-01", + ), + ), + Slice( + **slice_kwargs, + slice_name="Chord Chart", + viz_type="chord", + params=get_slice_json( + defaults, + viz_type="chord", + metric="sum__num", + groupby="gender", + columns="state", + ), + ), + Slice( + **slice_kwargs, + slice_name="Time-Series Percent Change Chart", + viz_type="compare", + params=get_slice_json( + defaults, + viz_type="compare", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Time-Series Generic Chart", + viz_type="echarts_timeseries", + params=get_slice_json( + defaults, + viz_type="echarts_timeseries", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Time-Series Smooth Line Chart", + viz_type="echarts_timeseries_smooth", + params=get_slice_json( + defaults, + viz_type="echarts_timeseries_smooth", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Time-Series Step Line Chart", + viz_type="echarts_timeseries_step", + params=get_slice_json( + defaults, + viz_type="echarts_timeseries_step", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Funnel Chart", + viz_type="funnel", + params=get_slice_json( + defaults, + viz_type="funnel", + metric="sum__num", + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Gauge Chart", + viz_type="gauge_chart", + params=get_slice_json( + defaults, + viz_type="gauge_chart", + metric="sum__num", + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Heatmap Chart", + viz_type="heatmap", + params=get_slice_json( + defaults, + viz_type="funnel", + metric="sum__num", + all_columns_x="gender", + all_columns_y="state", + ), + ), + Slice( + **slice_kwargs, + slice_name="Line Chart", + viz_type="line", + params=get_slice_json( + defaults, + viz_type="line", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Mixed Chart", + viz_type="mixed_timeseries", + params=get_slice_json( + defaults, + viz_type="mixed_timeseries", + metrics=["sum__num"], + groupby=["gender"], + metrics_b=["count"], + groupby_b=["state"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Partition Chart", + viz_type="partition", + params=get_slice_json( + defaults, + viz_type="partition", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Radar Chart", + viz_type="radar", + params=get_slice_json( + defaults, + viz_type="radar", + metrics=[ + "sum__num", + "count", + { + "expressionType": "SIMPLE", + "column": { + "column_name": "num_boys", + }, + "aggregate": "SUM", + "label": "SUM(num_boys)", + "optionName": "metric_353e7rjj84m_cirsi2o2s1", + }, + ], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Nightingale Chart", + viz_type="rose", + params=get_slice_json( + defaults, + viz_type="rose", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Sankey Chart", + viz_type="sankey", + params=get_slice_json( + defaults, + viz_type="sankey", + metric="sum__num", + groupby=["gender", "state"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Sunburst Chart", + viz_type="sunburst", + params=get_slice_json( + defaults, + viz_type="sunburst", + metric="sum__num", + groupby=["gender", "state"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Treemap Chart", + viz_type="treemap", + params=get_slice_json( + defaults, + viz_type="treemap", + metrics=["sum__num"], + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Treemap V2 Chart", + viz_type="treemap_v2", + params=get_slice_json( + defaults, + viz_type="treemap_v2", + metric="sum__num", + groupby=["gender"], + ), + ), + Slice( + **slice_kwargs, + slice_name="Word Cloud Chart", + viz_type="word_cloud", + params=get_slice_json( + defaults, + viz_type="word_cloud", + metric="sum__num", + series="state", + ), + ), + ] + + for slc in slices: + merge_slice(slc) + + return slices + + +def load_supported_charts_dashboard() -> None: + """Loading a dashboard featuring supported charts""" + + database = get_example_database() + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name + + tbl_name = "birth_names" + table_exists = database.has_table_by_name(tbl_name, schema=schema) + + if table_exists: + table = get_table_connector_registry() + obj = ( + db.session.query(table) + .filter_by(table_name=tbl_name, schema=schema) + .first() + ) + create_slices(obj) + + print("Creating the dashboard") + + db.session.expunge_all() + dash = db.session.query(Dashboard).filter_by(slug=DASH_SLUG).first() + + if not dash: + dash = Dashboard() + + js = textwrap.dedent( + """ +{ + "CHART-1": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-1" + ], + "id": "CHART-1", + "meta": { + "chartId": 1, + "height": 50, + "sliceName": "Big Number", + "width": 4 + }, + "type": "CHART" + }, + "CHART-2": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-1" + ], + "id": "CHART-2", + "meta": { + "chartId": 2, + "height": 50, + "sliceName": "Big Number with Trendline", + "width": 4 + }, + "type": "CHART" + }, + "CHART-3": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-1" + ], + "id": "CHART-3", + "meta":{ + "chartId": 3, + "height": 50, + "sliceName": "Table", + "width": 4 + }, + "type": "CHART" + }, + "CHART-4": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-2" + ], + "id": "CHART-4", + "meta": { + "chartId": 4, + "height": 50, + "sliceName": "Pivot Table", + "width": 4 + }, + "type": "CHART" + }, + "CHART-5": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-2" + ], + "id": "CHART-5", + "meta": { + "chartId": 5, + "height": 50, + "sliceName": "Time-Series Line Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-6": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-2" + ], + "id": "CHART-6", + "meta": { + "chartId": 6, + "height": 50, + "sliceName": "Time-Series Bar Chart V2", + "width": 4 + }, + "type": "CHART" + }, + "CHART-7": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-3" + ], + "id": "CHART-7", + "meta": { + "chartId": 7, + "height": 50, + "sliceName": "Time-Series Area Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-8": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-3" + ], + "id": "CHART-8", + "meta": { + "chartId": 8, + "height": 50, + "sliceName": "Time-Series Scatter Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-9": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-3" + ], + "id": "CHART-9", + "meta": { + "chartId": 9, + "height": 50, + "sliceName": "Pie Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-10": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-4" + ], + "id": "CHART-10", + "meta": { + "chartId": 10, + "height": 50, + "sliceName": "Bar Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-11": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1", + "ROW-4" + ], + "id": "CHART-11", + "meta": { + "chartId": 11, + "height": 50, + "sliceName": "% Rural", + "width": 4 + }, + "type": "CHART" + }, + "CHART-12": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-5" + ], + "id": "CHART-12", + "meta": { + "chartId": 12, + "height": 50, + "sliceName": "Box Plot Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-13": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-5" + ], + "id": "CHART-13", + "meta": { + "chartId": 13, + "height": 50, + "sliceName": "Bubble Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-14": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-5" + ], + "id": "CHART-14", + "meta": { + "chartId": 14, + "height": 50, + "sliceName": "Calendar Heatmap", + "width": 4 + }, + "type": "CHART" + }, + "CHART-15": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-6" + ], + "id": "CHART-15", + "meta": { + "chartId": 15, + "height": 50, + "sliceName": "Chord Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-16": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-6" + ], + "id": "CHART-16", + "meta": { + "chartId": 16, + "height": 50, + "sliceName": "Time-Series Percent Change Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-17": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-6" + ], + "id": "CHART-17", + "meta": { + "chartId": 17, + "height": 50, + "sliceName": "Time-Series Generic Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-18": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-7" + ], + "id": "CHART-18", + "meta": { + "chartId": 18, + "height": 50, + "sliceName": "Time-Series Smooth Line Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-19": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-7" + ], + "id": "CHART-19", + "meta": { + "chartId": 19, + "height": 50, + "sliceName": "Time-Series Step Line Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-20": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-7" + ], + "id": "CHART-20", + "meta": { + "chartId": 20, + "height": 50, + "sliceName": "Funnel Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-21": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-8" + ], + "id": "CHART-21", + "meta": { + "chartId": 21, + "height": 50, + "sliceName": "Gauge Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-22": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-8" + ], + "id": "CHART-22", + "meta": { + "chartId": 22, + "height": 50, + "sliceName": "Heatmap Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-23": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-8" + ], + "id": "CHART-23", + "meta": { + "chartId": 23, + "height": 50, + "sliceName": "Line Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-24": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-9" + ], + "id": "CHART-24", + "meta": { + "chartId": 24, + "height": 50, + "sliceName": "Mixed Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-25": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-9" + ], + "id": "CHART-25", + "meta": { + "chartId": 25, + "height": 50, + "sliceName": "Partition Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-26": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-9" + ], + "id": "CHART-26", + "meta": { + "chartId": 26, + "height": 50, + "sliceName": "Radar Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-27": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-10" + ], + "id": "CHART-27", + "meta": { + "chartId": 27, + "height": 50, + "sliceName": "Nightingale Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-28": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-10" + ], + "id": "CHART-28", + "meta": { + "chartId": 28, + "height": 50, + "sliceName": "Sankey Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-29": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-10" + ], + "id": "CHART-29", + "meta": { + "chartId": 29, + "height": 50, + "sliceName": "Sunburst Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-30": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-11" + ], + "id": "CHART-30", + "meta": { + "chartId": 30, + "height": 50, + "sliceName": "Treemap Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-31": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-11" + ], + "id": "CHART-31", + "meta": { + "chartId": 31, + "height": 50, + "sliceName": "Treemap V2 Chart", + "width": 4 + }, + "type": "CHART" + }, + "CHART-32": { + "children": [], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2", + "ROW-11" + ], + "id": "CHART-32", + "meta": { + "chartId": 32, + "height": 50, + "sliceName": "Word Cloud Chart", + "width": 4 + }, + "type": "CHART" + }, + "GRID_ID": { + "children": [], + "id": "GRID_ID", + "type": "GRID" + }, + "HEADER_ID": { + "id": "HEADER_ID", + "meta": { + "text": "Supported Charts" + }, + "type": "HEADER" + }, + "TABS-TOP": { + "children": [ + "TAB-TOP-1", + "TAB-TOP-2" + ], + "id": "TABS-TOP", + "type": "TABS" + }, + "TAB-TOP-1": { + "id": "TAB_TOP-1", + "type": "TAB", + "meta": { + "text": "Tier 1", + "defaultText": "Tab title", + "placeholder": "Tab title" + }, + "parents": [ + "ROOT_ID", + "TABS-TOP" + ], + "children": [ + "ROW-1", + "ROW-2", + "ROW-3", + "ROW-4" + ] + }, + "TAB-TOP-2": { + "id": "TAB_TOP-2", + "type": "TAB", + "meta": { + "text": "Tier 2", + "defaultText": "Tab title", + "placeholder": "Tab title" + }, + "parents": [ + "ROOT_ID", + "TABS-TOP" + ], + "children": [ + "ROW-5", + "ROW-6", + "ROW-7", + "ROW-8", + "ROW-9", + "ROW-10", + "ROW-11" + ] + }, + "ROOT_ID": { + "children": [ + "TABS-TOP" + ], + "id": "ROOT_ID", + "type": "ROOT" + }, + "ROW-1": { + "children": [ + "CHART-1", + "CHART-2", + "CHART-3" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1" + ], + "id": "ROW-1", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "ROW-2": { + "children": [ + "CHART-4", + "CHART-5", + "CHART-6" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1" + ], + "id": "ROW-2", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "ROW-3": { + "children": [ + "CHART-7", + "CHART-8", + "CHART-9" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1" + ], + "id": "ROW-3", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "ROW-4": { + "children": [ + "CHART-10", + "CHART-11" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-1" + ], + "id": "ROW-4", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "ROW-5": { + "children": [ + "CHART-12", + "CHART-13", + "CHART-14" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2" + ], + "id": "ROW-5", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "ROW-6": { + "children": [ + "CHART-15", + "CHART-16", + "CHART-17" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2" + ], + "id": "ROW-6", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "ROW-7": { + "children": [ + "CHART-18", + "CHART-19", + "CHART-20" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2" + ], + "id": "ROW-7", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "ROW-8": { + "children": [ + "CHART-21", + "CHART-22", + "CHART-23" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2" + ], + "id": "ROW-8", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "ROW-9": { + "children": [ + "CHART-24", + "CHART-25", + "CHART-26" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2" + ], + "id": "ROW-9", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "ROW-10": { + "children": [ + "CHART-27", + "CHART-28", + "CHART-29" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2" + ], + "id": "ROW-10", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "ROW-11": { + "children": [ + "CHART-30", + "CHART-31", + "CHART-32" + ], + "parents": [ + "ROOT_ID", + "TABS-TOP", + "TAB-TOP-2" + ], + "id": "ROW-11", + "meta": { + "background": "BACKGROUND_TRANSPARENT" + }, + "type": "ROW" + }, + "DASHBOARD_VERSION_KEY": "v2" +} + """ + ) + + pos = json.loads(js) + dash.slices = update_slice_ids(pos) + dash.dashboard_title = "Supported Charts Dashboard" + dash.position_json = json.dumps(pos, indent=2) + dash.slug = DASH_SLUG + db.session.commit() diff --git a/superset/examples/tabbed_dashboard.py b/superset/examples/tabbed_dashboard.py index 7a167bc357d5f..58c0ba3e4c063 100644 --- a/superset/examples/tabbed_dashboard.py +++ b/superset/examples/tabbed_dashboard.py @@ -137,6 +137,25 @@ def load_tabbed_dashboard(_: bool = False) -> None: ], "type": "CHART" }, + "CHART-dxV7Il666H": { + "children": [], + "id": "CHART-dxV7Il666H", + "meta": { + "chartId": 5539, + "height": 50, + "sliceName": "Trends", + "width": 4 + }, + "parents": [ + "ROOT_ID", + "TABS-lV0r00f4H1", + "TAB-gcQJxApOZS", + "TABS-afnrUvdxYF", + "TAB-jNNd4WWar1", + "ROW-7ygtD666Q" + ], + "type": "CHART" + }, "CHART-jJ5Yj1Ptaz": { "children": [], "id": "CHART-jJ5Yj1Ptaz", @@ -238,6 +257,19 @@ def load_tabbed_dashboard(_: bool = False) -> None: ], "type": "ROW" }, + "ROW-7ygtD666Q": { + "children": ["CHART-dxV7Il666H"], + "id": "ROW-7ygtD666Q", + "meta": { "background": "BACKGROUND_TRANSPARENT" }, + "parents": [ + "ROOT_ID", + "TABS-lV0r00f4H1", + "TAB-gcQJxApOZS", + "TABS-afnrUvdxYF", + "TAB-jNNd4WWar1" + ], + "type": "ROW" + }, "ROW-DnYkJgKQE": { "children": ["CHART-06Kg-rUggO", "CHART-E4rQMdzY9-"], "id": "ROW-DnYkJgKQE", @@ -386,7 +418,7 @@ def load_tabbed_dashboard(_: bool = False) -> None: "type": "TAB" }, "TAB-jNNd4WWar1": { - "children": ["ROW-7ygtDczaQ"], + "children": ["ROW-7ygtDczaQ", "ROW-7ygtD666Q"], "id": "TAB-jNNd4WWar1", "meta": { "text": "New Tab" }, "parents": [ diff --git a/superset/examples/world_bank.py b/superset/examples/world_bank.py index 39b982aa52468..b65ad68d1af62 100644 --- a/superset/examples/world_bank.py +++ b/superset/examples/world_bank.py @@ -33,7 +33,7 @@ from ..connectors.base.models import BaseDatasource from .helpers import ( - get_example_data, + get_example_url, get_examples_folder, get_slice_json, get_table_connector_registry, @@ -51,37 +51,38 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals, too-many-s """Loads the world bank health dataset, slices and a dashboard""" tbl_name = "wb_health_population" database = superset.utils.database.get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name - table_exists = database.has_table_by_name(tbl_name) + with database.get_sqla_engine_with_context() as engine: - if not only_metadata and (not table_exists or force): - data = get_example_data("countries.json.gz") - pdf = pd.read_json(data) - pdf.columns = [col.replace(".", "_") for col in pdf.columns] - if database.backend == "presto": - pdf.year = pd.to_datetime(pdf.year) - pdf.year = pdf.year.dt.strftime("%Y-%m-%d %H:%M%:%S") - else: - pdf.year = pd.to_datetime(pdf.year) - pdf = pdf.head(100) if sample else pdf + schema = inspect(engine).default_schema_name + table_exists = database.has_table_by_name(tbl_name) - pdf.to_sql( - tbl_name, - engine, - schema=schema, - if_exists="replace", - chunksize=50, - dtype={ - # TODO(bkyryliuk): use TIMESTAMP type for presto - "year": DateTime if database.backend != "presto" else String(255), - "country_code": String(3), - "country_name": String(255), - "region": String(255), - }, - method="multi", - index=False, - ) + if not only_metadata and (not table_exists or force): + url = get_example_url("countries.json.gz") + pdf = pd.read_json(url, compression="gzip") + pdf.columns = [col.replace(".", "_") for col in pdf.columns] + if database.backend == "presto": + pdf.year = pd.to_datetime(pdf.year) + pdf.year = pdf.year.dt.strftime("%Y-%m-%d %H:%M%:%S") + else: + pdf.year = pd.to_datetime(pdf.year) + pdf = pdf.head(100) if sample else pdf + + pdf.to_sql( + tbl_name, + engine, + schema=schema, + if_exists="replace", + chunksize=50, + dtype={ + # TODO(bkyryliuk): use TIMESTAMP type for presto + "year": DateTime if database.backend != "presto" else String(255), + "country_code": String(3), + "country_name": String(255), + "region": String(255), + }, + method="multi", + index=False, + ) print("Creating table [wb_health_population] reference") table = get_table_connector_registry() diff --git a/superset/exceptions.py b/superset/exceptions.py index 07bedfa2db568..963bf966820d5 100644 --- a/superset/exceptions.py +++ b/superset/exceptions.py @@ -115,6 +115,14 @@ def __init__( self.status = status +class SupersetSyntaxErrorException(SupersetErrorsException): + status = 422 + error_type = SupersetErrorType.SYNTAX_ERROR + + def __init__(self, errors: List[SupersetError]) -> None: + super().__init__(errors) + + class SupersetTimeoutException(SupersetErrorFromParamsException): status = 408 @@ -258,3 +266,7 @@ def __init__(self, error: ValidationError): class SupersetCancelQueryException(SupersetException): status = 422 + + +class QueryNotFoundException(SupersetException): + status = 404 diff --git a/superset/explore/api.py b/superset/explore/api.py new file mode 100644 index 0000000000000..2c1ec4b8e4749 --- /dev/null +++ b/superset/explore/api.py @@ -0,0 +1,138 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging + +from flask import g, request, Response +from flask_appbuilder.api import expose, protect, safe + +from superset.charts.commands.exceptions import ChartNotFoundError +from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP +from superset.explore.commands.get import GetExploreCommand +from superset.explore.commands.parameters import CommandParameters +from superset.explore.exceptions import DatasetAccessDeniedError, WrongEndpointError +from superset.explore.permalink.exceptions import ExplorePermalinkGetFailedError +from superset.explore.schemas import ExploreContextSchema +from superset.extensions import event_logger +from superset.temporary_cache.commands.exceptions import ( + TemporaryCacheAccessDeniedError, + TemporaryCacheResourceNotFoundError, +) +from superset.views.base_api import BaseSupersetApi, statsd_metrics + +logger = logging.getLogger(__name__) + + +class ExploreRestApi(BaseSupersetApi): + method_permission_name = MODEL_API_RW_METHOD_PERMISSION_MAP + allow_browser_login = True + class_permission_name = "Explore" + resource_name = "explore" + openapi_spec_tag = "Explore" + openapi_spec_component_schemas = (ExploreContextSchema,) + + @expose("/", methods=["GET"]) + @protect() + @safe + @statsd_metrics + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.get", + log_to_statsd=True, + ) + def get(self) -> Response: + """Assembles Explore related information (form_data, slice, dataset) + in a single endpoint. + --- + get: + summary: >- + Assembles Explore related information (form_data, slice, dataset) + in a single endpoint. + description: >- + Assembles Explore related information (form_data, slice, dataset) + in a single endpoint.<br/><br/> + The information can be assembled from:<br/> + - The cache using a form_data_key<br/> + - The metadata database using a permalink_key<br/> + - Build from scratch using dataset or slice identifiers. + parameters: + - in: query + schema: + type: string + name: form_data_key + - in: query + schema: + type: string + name: permalink_key + - in: query + schema: + type: integer + name: slice_id + - in: query + schema: + type: integer + name: datasource_id + - in: query + schema: + type: string + name: datasource_type + responses: + 200: + description: Returns the initial context. + content: + application/json: + schema: + $ref: '#/components/schemas/ExploreContextSchema' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 404: + $ref: '#/components/responses/404' + 422: + $ref: '#/components/responses/422' + 500: + $ref: '#/components/responses/500' + """ + try: + params = CommandParameters( + actor=g.user, + permalink_key=request.args.get("permalink_key", type=str), + form_data_key=request.args.get("form_data_key", type=str), + datasource_id=request.args.get("datasource_id", type=int), + datasource_type=request.args.get("datasource_type", type=str), + slice_id=request.args.get("slice_id", type=int), + ) + result = GetExploreCommand(params).run() + if not result: + return self.response_404() + return self.response(200, result=result) + except ValueError as ex: + return self.response(400, message=str(ex)) + except DatasetAccessDeniedError as ex: + return self.response( + 403, + message=ex.message, + datasource_id=ex.datasource_id, + datasource_type=ex.datasource_type, + ) + except (ChartNotFoundError, ExplorePermalinkGetFailedError) as ex: + return self.response(404, message=str(ex)) + except WrongEndpointError as ex: + return self.response(302, redirect=ex.redirect) + except TemporaryCacheAccessDeniedError as ex: + return self.response(403, message=str(ex)) + except TemporaryCacheResourceNotFoundError as ex: + return self.response(404, message=str(ex)) diff --git a/superset/explore/commands/__init__.py b/superset/explore/commands/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/superset/explore/commands/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/superset/explore/commands/get.py b/superset/explore/commands/get.py new file mode 100644 index 0000000000000..fb690a9d75238 --- /dev/null +++ b/superset/explore/commands/get.py @@ -0,0 +1,191 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging +from abc import ABC +from typing import Any, cast, Dict, Optional + +import simplejson as json +from flask import current_app, request +from flask_babel import gettext as __, lazy_gettext as _ +from sqlalchemy.exc import SQLAlchemyError + +from superset import db, security_manager +from superset.commands.base import BaseCommand +from superset.connectors.base.models import BaseDatasource +from superset.connectors.sqla.models import SqlaTable +from superset.dao.exceptions import DatasourceNotFound +from superset.datasource.dao import DatasourceDAO +from superset.exceptions import SupersetException +from superset.explore.commands.parameters import CommandParameters +from superset.explore.exceptions import DatasetAccessDeniedError, WrongEndpointError +from superset.explore.form_data.commands.get import GetFormDataCommand +from superset.explore.form_data.commands.parameters import ( + CommandParameters as FormDataCommandParameters, +) +from superset.explore.permalink.commands.get import GetExplorePermalinkCommand +from superset.explore.permalink.exceptions import ExplorePermalinkGetFailedError +from superset.utils import core as utils +from superset.views.utils import ( + get_datasource_info, + get_form_data, + sanitize_datasource_data, +) + +logger = logging.getLogger(__name__) + + +class GetExploreCommand(BaseCommand, ABC): + def __init__( + self, + params: CommandParameters, + ) -> None: + self._permalink_key = params.permalink_key + self._form_data_key = params.form_data_key + self._datasource_id = params.datasource_id + self._datasource_type = params.datasource_type + self._slice_id = params.slice_id + + # pylint: disable=too-many-locals,too-many-branches,too-many-statements + def run(self) -> Optional[Dict[str, Any]]: + initial_form_data = {} + + if self._permalink_key is not None: + command = GetExplorePermalinkCommand(self._permalink_key) + permalink_value = command.run() + if not permalink_value: + raise ExplorePermalinkGetFailedError() + state = permalink_value["state"] + initial_form_data = state["formData"] + url_params = state.get("urlParams") + if url_params: + initial_form_data["url_params"] = dict(url_params) + elif self._form_data_key: + parameters = FormDataCommandParameters(key=self._form_data_key) + value = GetFormDataCommand(parameters).run() + initial_form_data = json.loads(value) if value else {} + + message = None + + if not initial_form_data: + if self._slice_id: + initial_form_data["slice_id"] = self._slice_id + if self._form_data_key: + message = _( + "Form data not found in cache, reverting to chart metadata." + ) + elif self._datasource_id: + initial_form_data[ + "datasource" + ] = f"{self._datasource_id}__{self._datasource_type}" + if self._form_data_key: + message = _( + "Form data not found in cache, reverting to dataset metadata." + ) + + form_data, slc = get_form_data( + slice_id=self._slice_id, + use_slice_data=True, + initial_form_data=initial_form_data, + ) + try: + self._datasource_id, self._datasource_type = get_datasource_info( + self._datasource_id, self._datasource_type, form_data + ) + except SupersetException: + self._datasource_id = None + # fallback unkonw datasource to table type + self._datasource_type = SqlaTable.type + + datasource: Optional[BaseDatasource] = None + if self._datasource_id is not None: + try: + datasource = DatasourceDAO.get_datasource( + db.session, cast(str, self._datasource_type), self._datasource_id + ) + except DatasourceNotFound: + pass + datasource_name = datasource.name if datasource else _("[Missing Dataset]") + + if datasource: + if current_app.config["ENABLE_ACCESS_REQUEST"] and ( + not security_manager.can_access_datasource(datasource) + ): + message = __( + security_manager.get_datasource_access_error_msg(datasource) + ) + raise DatasetAccessDeniedError( + message=message, + datasource_type=self._datasource_type, + datasource_id=self._datasource_id, + ) + + viz_type = form_data.get("viz_type") + if not viz_type and datasource and datasource.default_endpoint: + raise WrongEndpointError(redirect=datasource.default_endpoint) + + form_data["datasource"] = ( + str(self._datasource_id) + "__" + cast(str, self._datasource_type) + ) + + # On explore, merge legacy/extra filters and URL params into the form data + utils.convert_legacy_filters_into_adhoc(form_data) + utils.merge_extra_filters(form_data) + utils.merge_request_params(form_data, request.args) + + # TODO: this is a dummy placeholder - should be refactored to being just `None` + datasource_data: Dict[str, Any] = { + "type": self._datasource_type, + "name": datasource_name, + "columns": [], + "metrics": [], + "database": {"id": 0, "backend": ""}, + } + try: + if datasource: + datasource_data = datasource.data + except SupersetException as ex: + message = ex.message + except SQLAlchemyError: + message = "SQLAlchemy error" + + metadata = None + + if slc: + metadata = { + "created_on_humanized": slc.created_on_humanized, + "changed_on_humanized": slc.changed_on_humanized, + "owners": [owner.get_full_name() for owner in slc.owners], + "dashboards": [ + {"id": dashboard.id, "dashboard_title": dashboard.dashboard_title} + for dashboard in slc.dashboards + ], + } + if slc.created_by: + metadata["created_by"] = slc.created_by.get_full_name() + if slc.changed_by: + metadata["changed_by"] = slc.changed_by.get_full_name() + + return { + "dataset": sanitize_datasource_data(datasource_data), + "form_data": form_data, + "slice": slc.data if slc else None, + "message": message, + "metadata": metadata, + } + + def validate(self) -> None: + pass diff --git a/superset/explore/commands/parameters.py b/superset/explore/commands/parameters.py new file mode 100644 index 0000000000000..96d72f2670d89 --- /dev/null +++ b/superset/explore/commands/parameters.py @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from dataclasses import dataclass +from typing import Optional + +from flask_appbuilder.security.sqla.models import User + + +@dataclass +class CommandParameters: + actor: User + permalink_key: Optional[str] + form_data_key: Optional[str] + datasource_id: Optional[int] + datasource_type: Optional[str] + slice_id: Optional[int] diff --git a/superset/explore/exceptions.py b/superset/explore/exceptions.py new file mode 100644 index 0000000000000..e3b589c667c50 --- /dev/null +++ b/superset/explore/exceptions.py @@ -0,0 +1,49 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from typing import Optional + +from flask_babel import lazy_gettext as _ + +from superset.commands.exceptions import ( + CommandException, + CommandInvalidError, + ForbiddenError, +) + + +class DatasetAccessDeniedError(ForbiddenError): + def __init__( + self, message: str, datasource_id: Optional[int], datasource_type: Optional[str] + ) -> None: + self.message = message + self.datasource_id = datasource_id + self.datasource_type = datasource_type + super().__init__(self.message) + + +class WrongEndpointError(CommandException): + def __init__(self, redirect: str) -> None: + self.redirect = redirect + super().__init__() + + +class DatasourceSamplesFailedError(CommandInvalidError): + message = _("Samples for datasource could not be retrieved.") + + +class DatasourceForbiddenError(ForbiddenError): + message = _("Changing this datasource is forbidden") diff --git a/superset/explore/form_data/api.py b/superset/explore/form_data/api.py index 00c8730ee411b..cc2fc75bb5e84 100644 --- a/superset/explore/form_data/api.py +++ b/superset/explore/form_data/api.py @@ -15,13 +15,12 @@ # specific language governing permissions and limitations # under the License. import logging -from abc import ABC -from flask import g, request, Response -from flask_appbuilder.api import BaseApi, expose, protect, safe +from flask import request, Response +from flask_appbuilder.api import expose, protect, safe from marshmallow import ValidationError -from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod +from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP from superset.explore.form_data.commands.create import CreateFormDataCommand from superset.explore.form_data.commands.delete import DeleteFormDataCommand from superset.explore.form_data.commands.get import GetFormDataCommand @@ -33,21 +32,15 @@ TemporaryCacheAccessDeniedError, TemporaryCacheResourceNotFoundError, ) -from superset.views.base_api import requires_json +from superset.views.base_api import BaseSupersetApi, requires_json, statsd_metrics logger = logging.getLogger(__name__) -class ExploreFormDataRestApi(BaseApi, ABC): +class ExploreFormDataRestApi(BaseSupersetApi): add_model_schema = FormDataPostSchema() edit_model_schema = FormDataPutSchema() method_permission_name = MODEL_API_RW_METHOD_PERMISSION_MAP - include_route_methods = { - RouteMethod.POST, - RouteMethod.PUT, - RouteMethod.GET, - RouteMethod.DELETE, - } allow_browser_login = True class_permission_name = "ExploreFormDataRestApi" resource_name = "explore" @@ -57,6 +50,7 @@ class ExploreFormDataRestApi(BaseApi, ABC): @expose("/form_data", methods=["POST"]) @protect() @safe + @statsd_metrics @event_logger.log_this_with_context( action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.post", log_to_statsd=False, @@ -103,7 +97,6 @@ def post(self) -> Response: item = self.add_model_schema.load(request.json) tab_id = request.args.get("tab_id") args = CommandParameters( - actor=g.user, datasource_id=item["datasource_id"], datasource_type=item["datasource_type"], chart_id=item.get("chart_id"), @@ -122,6 +115,7 @@ def post(self) -> Response: @expose("/form_data/<string:key>", methods=["PUT"]) @protect() @safe + @statsd_metrics @event_logger.log_this_with_context( action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.put", log_to_statsd=True, @@ -174,7 +168,6 @@ def put(self, key: str) -> Response: item = self.edit_model_schema.load(request.json) tab_id = request.args.get("tab_id") args = CommandParameters( - actor=g.user, datasource_id=item["datasource_id"], datasource_type=item["datasource_type"], chart_id=item.get("chart_id"), @@ -196,6 +189,7 @@ def put(self, key: str) -> Response: @expose("/form_data/<string:key>", methods=["GET"]) @protect() @safe + @statsd_metrics @event_logger.log_this_with_context( action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.get", log_to_statsd=True, @@ -234,7 +228,7 @@ def get(self, key: str) -> Response: $ref: '#/components/responses/500' """ try: - args = CommandParameters(actor=g.user, key=key) + args = CommandParameters(key=key) form_data = GetFormDataCommand(args).run() if not form_data: return self.response_404() @@ -247,6 +241,7 @@ def get(self, key: str) -> Response: @expose("/form_data/<string:key>", methods=["DELETE"]) @protect() @safe + @statsd_metrics @event_logger.log_this_with_context( action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.delete", log_to_statsd=True, @@ -286,7 +281,7 @@ def delete(self, key: str) -> Response: $ref: '#/components/responses/500' """ try: - args = CommandParameters(actor=g.user, key=key) + args = CommandParameters(key=key) result = DeleteFormDataCommand(args).run() if not result: return self.response_404() diff --git a/superset/explore/form_data/commands/create.py b/superset/explore/form_data/commands/create.py index 7946980c82684..df0250f2fffb6 100644 --- a/superset/explore/form_data/commands/create.py +++ b/superset/explore/form_data/commands/create.py @@ -24,9 +24,10 @@ from superset.explore.form_data.commands.state import TemporaryExploreState from superset.explore.form_data.commands.utils import check_access from superset.extensions import cache_manager -from superset.key_value.utils import get_owner, random_key +from superset.key_value.utils import random_key from superset.temporary_cache.commands.exceptions import TemporaryCacheCreateFailedError from superset.temporary_cache.utils import cache_key +from superset.utils.core import DatasourceType, get_user_id from superset.utils.schema import validate_json logger = logging.getLogger(__name__) @@ -43,9 +44,8 @@ def run(self) -> str: datasource_type = self._cmd_params.datasource_type chart_id = self._cmd_params.chart_id tab_id = self._cmd_params.tab_id - actor = self._cmd_params.actor form_data = self._cmd_params.form_data - check_access(datasource_id, chart_id, actor, datasource_type) + check_access(datasource_id, chart_id, datasource_type) contextual_key = cache_key( session.get("_id"), tab_id, datasource_id, chart_id, datasource_type ) @@ -54,9 +54,9 @@ def run(self) -> str: key = random_key() if form_data: state: TemporaryExploreState = { - "owner": get_owner(actor), + "owner": get_user_id(), "datasource_id": datasource_id, - "datasource_type": datasource_type, + "datasource_type": DatasourceType(datasource_type), "chart_id": chart_id, "form_data": form_data, } diff --git a/superset/explore/form_data/commands/delete.py b/superset/explore/form_data/commands/delete.py index 598ece3f080fc..bce13b719a7d4 100644 --- a/superset/explore/form_data/commands/delete.py +++ b/superset/explore/form_data/commands/delete.py @@ -26,13 +26,12 @@ from superset.explore.form_data.commands.state import TemporaryExploreState from superset.explore.form_data.commands.utils import check_access from superset.extensions import cache_manager -from superset.key_value.utils import get_owner from superset.temporary_cache.commands.exceptions import ( TemporaryCacheAccessDeniedError, TemporaryCacheDeleteFailedError, ) from superset.temporary_cache.utils import cache_key -from superset.utils.core import DatasourceType +from superset.utils.core import DatasourceType, get_user_id logger = logging.getLogger(__name__) @@ -43,7 +42,6 @@ def __init__(self, cmd_params: CommandParameters): def run(self) -> bool: try: - actor = self._cmd_params.actor key = self._cmd_params.key state: TemporaryExploreState = cache_manager.explore_form_data_cache.get( key @@ -52,8 +50,8 @@ def run(self) -> bool: datasource_id: int = state["datasource_id"] chart_id: Optional[int] = state["chart_id"] datasource_type = DatasourceType(state["datasource_type"]) - check_access(datasource_id, chart_id, actor, datasource_type) - if state["owner"] != get_owner(actor): + check_access(datasource_id, chart_id, datasource_type) + if state["owner"] != get_user_id(): raise TemporaryCacheAccessDeniedError() tab_id = self._cmd_params.tab_id contextual_key = cache_key( diff --git a/superset/explore/form_data/commands/get.py b/superset/explore/form_data/commands/get.py index 982c8e3b4b7d7..53fd6ea6a9359 100644 --- a/superset/explore/form_data/commands/get.py +++ b/superset/explore/form_data/commands/get.py @@ -40,7 +40,6 @@ def __init__(self, cmd_params: CommandParameters) -> None: def run(self) -> Optional[str]: try: - actor = self._cmd_params.actor key = self._cmd_params.key state: TemporaryExploreState = cache_manager.explore_form_data_cache.get( key @@ -49,7 +48,6 @@ def run(self) -> Optional[str]: check_access( state["datasource_id"], state["chart_id"], - actor, DatasourceType(state["datasource_type"]), ) if self._refresh_timeout: diff --git a/superset/explore/form_data/commands/parameters.py b/superset/explore/form_data/commands/parameters.py index fec06a581fb79..c6c1574c802af 100644 --- a/superset/explore/form_data/commands/parameters.py +++ b/superset/explore/form_data/commands/parameters.py @@ -17,14 +17,11 @@ from dataclasses import dataclass from typing import Optional -from flask_appbuilder.security.sqla.models import User - from superset.utils.core import DatasourceType @dataclass class CommandParameters: - actor: User datasource_type: DatasourceType = DatasourceType.TABLE datasource_id: int = 0 chart_id: int = 0 diff --git a/superset/explore/form_data/commands/state.py b/superset/explore/form_data/commands/state.py index 470f2e22f5989..35e3893478ea0 100644 --- a/superset/explore/form_data/commands/state.py +++ b/superset/explore/form_data/commands/state.py @@ -18,10 +18,12 @@ from typing_extensions import TypedDict +from superset.utils.core import DatasourceType + class TemporaryExploreState(TypedDict): owner: Optional[int] datasource_id: int - datasource_type: str + datasource_type: DatasourceType chart_id: Optional[int] form_data: str diff --git a/superset/explore/form_data/commands/update.py b/superset/explore/form_data/commands/update.py index fdc75093bef85..ace57350c450f 100644 --- a/superset/explore/form_data/commands/update.py +++ b/superset/explore/form_data/commands/update.py @@ -26,12 +26,13 @@ from superset.explore.form_data.commands.state import TemporaryExploreState from superset.explore.form_data.commands.utils import check_access from superset.extensions import cache_manager -from superset.key_value.utils import get_owner, random_key +from superset.key_value.utils import random_key from superset.temporary_cache.commands.exceptions import ( TemporaryCacheAccessDeniedError, TemporaryCacheUpdateFailedError, ) from superset.temporary_cache.utils import cache_key +from superset.utils.core import DatasourceType, get_user_id from superset.utils.schema import validate_json logger = logging.getLogger(__name__) @@ -50,14 +51,13 @@ def run(self) -> Optional[str]: datasource_id = self._cmd_params.datasource_id chart_id = self._cmd_params.chart_id datasource_type = self._cmd_params.datasource_type - actor = self._cmd_params.actor key = self._cmd_params.key form_data = self._cmd_params.form_data - check_access(datasource_id, chart_id, actor, datasource_type) + check_access(datasource_id, chart_id, datasource_type) state: TemporaryExploreState = cache_manager.explore_form_data_cache.get( key ) - owner = get_owner(actor) + owner = get_user_id() if state and form_data: if state["owner"] != owner: raise TemporaryCacheAccessDeniedError() @@ -75,7 +75,7 @@ def run(self) -> Optional[str]: new_state: TemporaryExploreState = { "owner": owner, "datasource_id": datasource_id, - "datasource_type": datasource_type, + "datasource_type": DatasourceType(datasource_type), "chart_id": chart_id, "form_data": form_data, } diff --git a/superset/explore/form_data/commands/utils.py b/superset/explore/form_data/commands/utils.py index 7927457178c9e..e4a843dc6284f 100644 --- a/superset/explore/form_data/commands/utils.py +++ b/superset/explore/form_data/commands/utils.py @@ -16,8 +16,6 @@ # under the License. from typing import Optional -from flask_appbuilder.security.sqla.models import User - from superset.charts.commands.exceptions import ( ChartAccessDeniedError, ChartNotFoundError, @@ -37,11 +35,10 @@ def check_access( datasource_id: int, chart_id: Optional[int], - actor: User, datasource_type: DatasourceType, ) -> None: try: - explore_check_access(datasource_id, chart_id, actor, datasource_type) + explore_check_access(datasource_id, chart_id, datasource_type) except (ChartNotFoundError, DatasetNotFoundError) as ex: raise TemporaryCacheResourceNotFoundError from ex except (ChartAccessDeniedError, DatasetAccessDeniedError) as ex: diff --git a/superset/explore/permalink/api.py b/superset/explore/permalink/api.py index 1d78e4354ae19..88e819aa2b0c2 100644 --- a/superset/explore/permalink/api.py +++ b/superset/explore/permalink/api.py @@ -16,15 +16,15 @@ # under the License. import logging -from flask import g, request, Response -from flask_appbuilder.api import BaseApi, expose, protect, safe +from flask import request, Response +from flask_appbuilder.api import expose, protect, safe from marshmallow import ValidationError from superset.charts.commands.exceptions import ( ChartAccessDeniedError, ChartNotFoundError, ) -from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod +from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP from superset.datasets.commands.exceptions import ( DatasetAccessDeniedError, DatasetNotFoundError, @@ -35,20 +35,14 @@ from superset.explore.permalink.schemas import ExplorePermalinkPostSchema from superset.extensions import event_logger from superset.key_value.exceptions import KeyValueAccessDeniedError -from superset.views.base_api import requires_json +from superset.views.base_api import BaseSupersetApi, requires_json, statsd_metrics logger = logging.getLogger(__name__) -class ExplorePermalinkRestApi(BaseApi): +class ExplorePermalinkRestApi(BaseSupersetApi): add_model_schema = ExplorePermalinkPostSchema() method_permission_name = MODEL_API_RW_METHOD_PERMISSION_MAP - include_route_methods = { - RouteMethod.POST, - RouteMethod.PUT, - RouteMethod.GET, - RouteMethod.DELETE, - } allow_browser_login = True class_permission_name = "ExplorePermalinkRestApi" resource_name = "explore" @@ -58,6 +52,7 @@ class ExplorePermalinkRestApi(BaseApi): @expose("/permalink", methods=["POST"]) @protect() @safe + @statsd_metrics @event_logger.log_this_with_context( action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.post", log_to_statsd=False, @@ -100,7 +95,7 @@ def post(self) -> Response: """ try: state = self.add_model_schema.load(request.json) - key = CreateExplorePermalinkCommand(actor=g.user, state=state).run() + key = CreateExplorePermalinkCommand(state=state).run() http_origin = request.headers.environ.get("HTTP_ORIGIN") url = f"{http_origin}/superset/explore/p/{key}/" return self.response(201, key=key, url=url) @@ -118,6 +113,7 @@ def post(self) -> Response: @expose("/permalink/<string:key>", methods=["GET"]) @protect() @safe + @statsd_metrics @event_logger.log_this_with_context( action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.get", log_to_statsd=False, @@ -156,7 +152,7 @@ def get(self, key: str) -> Response: $ref: '#/components/responses/500' """ try: - value = GetExplorePermalinkCommand(actor=g.user, key=key).run() + value = GetExplorePermalinkCommand(key=key).run() if not value: return self.response_404() return self.response(200, **value) diff --git a/superset/explore/permalink/commands/create.py b/superset/explore/permalink/commands/create.py index 7bd6365d814bd..77ce04c4e47b0 100644 --- a/superset/explore/permalink/commands/create.py +++ b/superset/explore/permalink/commands/create.py @@ -17,7 +17,6 @@ import logging from typing import Any, Dict, Optional -from flask_appbuilder.security.sqla.models import User from sqlalchemy.exc import SQLAlchemyError from superset.explore.permalink.commands.base import BaseExplorePermalinkCommand @@ -31,8 +30,7 @@ class CreateExplorePermalinkCommand(BaseExplorePermalinkCommand): - def __init__(self, actor: User, state: Dict[str, Any]): - self.actor = actor + def __init__(self, state: Dict[str, Any]): self.chart_id: Optional[int] = state["formData"].get("slice_id") self.datasource: str = state["formData"]["datasource"] self.state = state @@ -43,9 +41,7 @@ def run(self) -> str: d_id, d_type = self.datasource.split("__") datasource_id = int(d_id) datasource_type = DatasourceType(d_type) - check_chart_access( - datasource_id, self.chart_id, self.actor, datasource_type - ) + check_chart_access(datasource_id, self.chart_id, datasource_type) value = { "chartId": self.chart_id, "datasourceId": datasource_id, @@ -54,7 +50,6 @@ def run(self) -> str: "state": self.state, } command = CreateKeyValueCommand( - actor=self.actor, resource=self.resource, value=value, ) diff --git a/superset/explore/permalink/commands/get.py b/superset/explore/permalink/commands/get.py index ca4fe8c74fa2f..3376cab080962 100644 --- a/superset/explore/permalink/commands/get.py +++ b/superset/explore/permalink/commands/get.py @@ -17,7 +17,6 @@ import logging from typing import Optional -from flask_appbuilder.security.sqla.models import User from sqlalchemy.exc import SQLAlchemyError from superset.datasets.commands.exceptions import DatasetNotFoundError @@ -34,8 +33,7 @@ class GetExplorePermalinkCommand(BaseExplorePermalinkCommand): - def __init__(self, actor: User, key: str): - self.actor = actor + def __init__(self, key: str): self.key = key def run(self) -> Optional[ExplorePermalinkValue]: @@ -55,7 +53,7 @@ def run(self) -> Optional[ExplorePermalinkValue]: datasource_type = DatasourceType( value.get("datasourceType", DatasourceType.TABLE) ) - check_chart_access(datasource_id, chart_id, self.actor, datasource_type) + check_chart_access(datasource_id, chart_id, datasource_type) return value return None except ( diff --git a/superset/explore/schemas.py b/superset/explore/schemas.py new file mode 100644 index 0000000000000..457c99422a3a6 --- /dev/null +++ b/superset/explore/schemas.py @@ -0,0 +1,114 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# License ); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from marshmallow import fields, Schema + + +class DatasetSchema(Schema): + cache_timeout = fields.Integer( + description="Duration (in seconds) of the caching timeout for this dataset." + ) + column_formats = fields.Dict(description="Column formats.") + columns = fields.List(fields.Dict(), description="Columns metadata.") + database = fields.Dict(description="Database associated with the dataset.") + datasource_name = fields.String(description="Dataset name.") + default_endpoint = fields.String(description="Default endpoint for the dataset.") + description = fields.String(description="Dataset description.") + edit_url = fields.String(description="The URL for editing the dataset.") + extra = fields.Dict( + description="JSON string containing extra configuration elements." + ) + fetch_values_predicate = fields.String( + description="Predicate used when fetching values from the dataset." + ) + filter_select = fields.Bool(description="SELECT filter applied to the dataset.") + filter_select_enabled = fields.Bool(description="If the SELECT filter is enabled.") + granularity_sqla = fields.List( + fields.List(fields.Dict()), + description=( + "Name of temporal column used for time filtering for SQL datasources. " + "This field is deprecated, use `granularity` instead." + ), + ) + health_check_message = fields.String(description="Health check message.") + id = fields.Integer(description="Dataset ID.") + is_sqllab_view = fields.Bool(description="If the dataset is a SQL Lab view.") + main_dttm_col = fields.String(description="The main temporal column.") + metrics = fields.List(fields.Dict(), description="Dataset metrics.") + name = fields.String(description="Dataset name.") + offset = fields.Integer(description="Dataset offset.") + order_by_choices = fields.List( + fields.List(fields.String()), description="List of order by columns." + ) + owners = fields.List(fields.Integer(), description="List of owners identifiers") + params = fields.Dict(description="Extra params for the dataset.") + perm = fields.String(description="Permission expression.") + schema = fields.String(description="Dataset schema.") + select_star = fields.String(description="Select all clause.") + sql = fields.String(description="A SQL statement that defines the dataset.") + table_name = fields.String( + description="The name of the table associated with the dataset." + ) + template_params = fields.Dict(description="Table template params.") + time_grain_sqla = fields.List( + fields.List(fields.String()), + description="List of temporal granularities supported by the dataset.", + ) + type = fields.String(description="Dataset type.") + uid = fields.String(description="Dataset unique identifier.") + verbose_map = fields.Dict(description="Mapping from raw name to verbose name.") + + +class SliceSchema(Schema): + cache_timeout = fields.Integer( + description="Duration (in seconds) of the caching timeout for this chart." + ) + certification_details = fields.String(description="Details of the certification.") + certified_by = fields.String( + description="Person or group that has certified this dashboard." + ) + changed_on = fields.String(description="Timestamp of the last modification.") + changed_on_humanized = fields.String( + description="Timestamp of the last modification in human readable form." + ) + datasource = fields.String(description="Datasource identifier.") + description = fields.String(description="Slice description.") + description_markeddown = fields.String( + description="Sanitized HTML version of the chart description." + ) + edit_url = fields.String(description="The URL for editing the slice.") + form_data = fields.Dict(description="Form data associated with the slice.") + is_managed_externally = fields.Bool( + description="If the chart is managed outside externally." + ) + modified = fields.String(description="Last modification in human readable form.") + owners = fields.List(fields.Integer(), description="Owners identifiers.") + query_context = fields.Dict(description="The context associated with the query.") + slice_id = fields.Integer(description="The slice ID.") + slice_name = fields.String(description="The slice name.") + slice_url = fields.String(description="The slice URL.") + + +class ExploreContextSchema(Schema): + form_data = fields.Dict( + description=( + "Form data from the Explore controls used to form the " + "chart's data query." + ) + ) + dataset = fields.Nested(DatasetSchema) + slice = fields.Nested(SliceSchema) + message = fields.String(description="Any message related to the processed request.") diff --git a/superset/explore/utils.py b/superset/explore/utils.py index f0bfd8f0aa40c..01f63f53f2f44 100644 --- a/superset/explore/utils.py +++ b/superset/explore/utils.py @@ -16,8 +16,6 @@ # under the License. from typing import Optional -from flask_appbuilder.security.sqla.models import User - from superset import security_manager from superset.charts.commands.exceptions import ( ChartAccessDeniedError, @@ -36,13 +34,12 @@ from superset.datasets.dao import DatasetDAO from superset.queries.dao import QueryDAO from superset.utils.core import DatasourceType -from superset.views.base import is_user_admin -from superset.views.utils import is_owner def check_dataset_access(dataset_id: int) -> Optional[bool]: if dataset_id: - dataset = DatasetDAO.find_by_id(dataset_id) + # Access checks below, no need to validate them twice as they can be expensive. + dataset = DatasetDAO.find_by_id(dataset_id, skip_base_filter=True) if dataset: can_access_datasource = security_manager.can_access_datasource(dataset) if can_access_datasource: @@ -53,7 +50,8 @@ def check_dataset_access(dataset_id: int) -> Optional[bool]: def check_query_access(query_id: int) -> Optional[bool]: if query_id: - query = QueryDAO.find_by_id(query_id) + # Access checks below, no need to validate them twice as they can be expensive. + query = QueryDAO.find_by_id(query_id, skip_base_filter=True) if query: security_manager.raise_for_access(query=query) return True @@ -80,19 +78,17 @@ def check_datasource_access( def check_access( datasource_id: int, chart_id: Optional[int], - actor: User, datasource_type: DatasourceType, ) -> Optional[bool]: check_datasource_access(datasource_id, datasource_type) if not chart_id: return True - chart = ChartDAO.find_by_id(chart_id) + # Access checks below, no need to validate them twice as they can be expensive. + chart = ChartDAO.find_by_id(chart_id, skip_base_filter=True) if chart: - can_access_chart = ( - is_user_admin() - or is_owner(chart, actor) - or security_manager.can_access("can_read", "Chart") - ) + can_access_chart = security_manager.is_owner( + chart + ) or security_manager.can_access("can_read", "Chart") if can_access_chart: return True raise ChartAccessDeniedError() diff --git a/superset/extensions/__init__.py b/superset/extensions/__init__.py index 1f5882f7492aa..e2e5592e1edb9 100644 --- a/superset/extensions/__init__.py +++ b/superset/extensions/__init__.py @@ -16,7 +16,6 @@ # under the License. import json import os -from pathlib import Path from typing import Any, Callable, Dict, List, Optional import celery @@ -28,6 +27,8 @@ from flask_wtf.csrf import CSRFProtect from werkzeug.local import LocalProxy +from superset.extensions.ssh import SSHManagerFactory +from superset.extensions.stats_logger import BaseStatsLoggerManager from superset.utils.async_query_manager import AsyncQueryManager from superset.utils.cache_manager import CacheManager from superset.utils.encrypt import EncryptedFieldFactory @@ -126,4 +127,6 @@ def init_app(self, app: Flask) -> None: profiling = ProfilingExtension() results_backend_manager = ResultsBackendManager() security_manager = LocalProxy(lambda: appbuilder.sm) +ssh_manager_factory = SSHManagerFactory() +stats_logger_manager = BaseStatsLoggerManager() talisman = Talisman() diff --git a/superset/extensions/ssh.py b/superset/extensions/ssh.py new file mode 100644 index 0000000000000..ec9c781beed73 --- /dev/null +++ b/superset/extensions/ssh.py @@ -0,0 +1,92 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import importlib +from io import StringIO +from typing import TYPE_CHECKING + +from flask import Flask +from paramiko import RSAKey +from sshtunnel import open_tunnel, SSHTunnelForwarder + +from superset.databases.utils import make_url_safe + +if TYPE_CHECKING: + from superset.databases.ssh_tunnel.models import SSHTunnel + + +class SSHManager: + def __init__(self, app: Flask) -> None: + super().__init__() + self.local_bind_address = app.config["SSH_TUNNEL_LOCAL_BIND_ADDRESS"] + + def build_sqla_url( # pylint: disable=no-self-use + self, sqlalchemy_url: str, server: SSHTunnelForwarder + ) -> str: + # override any ssh tunnel configuration object + url = make_url_safe(sqlalchemy_url) + return url.set( + host=server.local_bind_address[0], + port=server.local_bind_port, + ) + + def create_tunnel( + self, + ssh_tunnel: "SSHTunnel", + sqlalchemy_database_uri: str, + ) -> SSHTunnelForwarder: + url = make_url_safe(sqlalchemy_database_uri) + params = { + "ssh_address_or_host": ssh_tunnel.server_address, + "ssh_port": ssh_tunnel.server_port, + "ssh_username": ssh_tunnel.username, + "remote_bind_address": (url.host, url.port), # bind_port, bind_host + "local_bind_address": (self.local_bind_address,), + } + + if ssh_tunnel.password: + params["ssh_password"] = ssh_tunnel.password + elif ssh_tunnel.private_key: + private_key_file = StringIO(ssh_tunnel.private_key) + private_key = RSAKey.from_private_key(private_key_file) + params["ssh_pkey"] = private_key + params["ssh_private_key_password"] = ssh_tunnel.private_key_password + + return open_tunnel(**params) + + +class SSHManagerFactory: + def __init__(self) -> None: + self._ssh_manager = None + + def init_app(self, app: Flask) -> None: + ssh_manager_fqclass = app.config["SSH_TUNNEL_MANAGER_CLASS"] + ssh_manager_classname = ssh_manager_fqclass[ + ssh_manager_fqclass.rfind(".") + 1 : + ] + ssh_manager_module_name = ssh_manager_fqclass[ + 0 : ssh_manager_fqclass.rfind(".") + ] + ssh_manager_class = getattr( + importlib.import_module(ssh_manager_module_name), ssh_manager_classname + ) + + self._ssh_manager = ssh_manager_class(app) + + @property + def instance(self) -> SSHManager: + return self._ssh_manager # type: ignore diff --git a/tests/integration_tests/db_engine_specs/kylin_tests.py b/superset/extensions/stats_logger.py similarity index 60% rename from tests/integration_tests/db_engine_specs/kylin_tests.py rename to superset/extensions/stats_logger.py index a607565d5b41d..bb6407141a2a1 100644 --- a/tests/integration_tests/db_engine_specs/kylin_tests.py +++ b/superset/extensions/stats_logger.py @@ -14,19 +14,18 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from superset.db_engine_specs.kylin import KylinEngineSpec -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec +from flask import Flask +from superset.stats_logger import BaseStatsLogger -class TestKylinDbEngineSpec(TestDbEngineSpec): - def test_convert_dttm(self): - dttm = self.get_dttm() - self.assertEqual( - KylinEngineSpec.convert_dttm("DATE", dttm), "CAST('2019-01-02' AS DATE)" - ) +class BaseStatsLoggerManager: + def __init__(self) -> None: + self._stats_logger = BaseStatsLogger() - self.assertEqual( - KylinEngineSpec.convert_dttm("TIMESTAMP", dttm), - "CAST('2019-01-02 03:04:05' AS TIMESTAMP)", - ) + def init_app(self, app: Flask) -> None: + self._stats_logger = app.config["STATS_LOGGER"] + + @property + def instance(self) -> BaseStatsLogger: + return self._stats_logger diff --git a/superset/importexport/api.py b/superset/importexport/api.py index e20cc22b80d44..26bc78e5d7a84 100644 --- a/superset/importexport/api.py +++ b/superset/importexport/api.py @@ -20,7 +20,7 @@ from zipfile import is_zipfile, ZipFile from flask import request, Response, send_file -from flask_appbuilder.api import BaseApi, expose, protect +from flask_appbuilder.api import expose, protect from superset.commands.export.assets import ExportAssetsCommand from superset.commands.importers.exceptions import ( @@ -30,10 +30,10 @@ from superset.commands.importers.v1.assets import ImportAssetsCommand from superset.commands.importers.v1.utils import get_contents_from_bundle from superset.extensions import event_logger -from superset.views.base_api import requires_form_data +from superset.views.base_api import BaseSupersetApi, requires_form_data, statsd_metrics -class ImportExportRestApi(BaseApi): +class ImportExportRestApi(BaseSupersetApi): """ API for exporting all assets or importing them. """ @@ -44,6 +44,7 @@ class ImportExportRestApi(BaseApi): @expose("/export/", methods=["GET"]) @protect() + @statsd_metrics @event_logger.log_this_with_context( action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.export", log_to_statsd=False, @@ -92,6 +93,7 @@ def export(self) -> Response: @expose("/import/", methods=["POST"]) @protect() + @statsd_metrics @event_logger.log_this_with_context( action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.import_", log_to_statsd=False, diff --git a/superset/initialization/__init__.py b/superset/initialization/__init__.py index de97b1daa6e5d..b7cea854a2b1a 100644 --- a/superset/initialization/__init__.py +++ b/superset/initialization/__init__.py @@ -28,7 +28,6 @@ from flask_compress import Compress from werkzeug.middleware.proxy_fix import ProxyFix -from superset.connectors.connector_registry import ConnectorRegistry from superset.constants import CHANGE_ME_SECRET_KEY from superset.extensions import ( _event_logger, @@ -46,10 +45,13 @@ migrate, profiling, results_backend_manager, + ssh_manager_factory, + stats_logger_manager, talisman, ) from superset.security import SupersetSecurityManager from superset.superset_typing import FlaskResponse +from superset.tags.core import register_sqla_event_listeners from superset.utils.core import pessimistic_connection_handling from superset.utils.log import DBEventLogger, get_event_logger_from_cfg_value @@ -117,6 +119,7 @@ def init_views(self) -> None: from superset.annotation_layers.annotations.api import AnnotationRestApi from superset.annotation_layers.api import AnnotationLayerRestApi from superset.async_events.api import AsyncEventsRestApi + from superset.available_domains.api import AvailableDomainsRestApi from superset.cachekeys.api import CacheRestApi from superset.charts.api import ChartRestApi from superset.charts.data.api import ChartDataRestApi @@ -135,8 +138,10 @@ def init_views(self) -> None: from superset.datasets.api import DatasetRestApi from superset.datasets.columns.api import DatasetColumnsRestApi from superset.datasets.metrics.api import DatasetMetricRestApi + from superset.datasource.api import DatasourceRestApi from superset.embedded.api import EmbeddedDashboardRestApi from superset.embedded.view import EmbeddedView + from superset.explore.api import ExploreRestApi from superset.explore.form_data.api import ExploreFormDataRestApi from superset.explore.permalink.api import ExplorePermalinkRestApi from superset.importexport.api import ImportExportRestApi @@ -146,12 +151,10 @@ def init_views(self) -> None: from superset.reports.api import ReportScheduleRestApi from superset.reports.logs.api import ReportExecutionLogRestApi from superset.security.api import SecurityRestApi, UsersApi + from superset.sqllab.api import SqlLabRestApi from superset.views.access_requests import AccessRequestsModelView from superset.views.alerts import AlertView, ReportView - from superset.views.annotations import ( - AnnotationLayerModelView, - AnnotationModelView, - ) + from superset.views.annotations import AnnotationLayerView from superset.views.api import Api from superset.views.chart.views import SliceAsync, SliceModelView from superset.views.core import Superset @@ -170,13 +173,14 @@ def init_views(self) -> None: DatabaseView, ExcelToDatabaseView, ) - from superset.views.datasource.views import Datasource + from superset.views.datasource.views import DatasetEditor, Datasource from superset.views.dynamic_plugins import DynamicPluginsView + from superset.views.explore import ExplorePermalinkView, ExploreView from superset.views.key_value import KV from superset.views.log.api import LogRestApi from superset.views.log.views import LogModelView from superset.views.redirects import R - from superset.views.sql_lab import ( + from superset.views.sql_lab.views import ( SavedQueryView, SavedQueryViewApi, SqlLab, @@ -193,6 +197,7 @@ def init_views(self) -> None: appbuilder.add_api(AnnotationLayerRestApi) appbuilder.add_api(AsyncEventsRestApi) appbuilder.add_api(AdvancedDataTypeRestApi) + appbuilder.add_api(AvailableDomainsRestApi) appbuilder.add_api(CacheRestApi) appbuilder.add_api(ChartRestApi) appbuilder.add_api(ChartDataRestApi) @@ -206,7 +211,9 @@ def init_views(self) -> None: appbuilder.add_api(DatasetRestApi) appbuilder.add_api(DatasetColumnsRestApi) appbuilder.add_api(DatasetMetricRestApi) + appbuilder.add_api(DatasourceRestApi) appbuilder.add_api(EmbeddedDashboardRestApi) + appbuilder.add_api(ExploreRestApi) appbuilder.add_api(ExploreFormDataRestApi) appbuilder.add_api(ExplorePermalinkRestApi) appbuilder.add_api(FilterSetRestApi) @@ -215,6 +222,7 @@ def init_views(self) -> None: appbuilder.add_api(ReportScheduleRestApi) appbuilder.add_api(ReportExecutionLogRestApi) appbuilder.add_api(SavedQueryRestApi) + appbuilder.add_api(SqlLabRestApi) appbuilder.add_api(UsersApi) # # Setup regular views @@ -225,14 +233,14 @@ def init_views(self) -> None: href="/superset/welcome/", cond=lambda: bool(appbuilder.app.config["LOGO_TARGET_PATH"]), ) + appbuilder.add_view( - AnnotationLayerModelView, - "Annotation Layers", - label=__("Annotation Layers"), - icon="fa-comment", - category="Manage", - category_label=__("Manage"), - category_icon="", + DatabaseView, + "Databases", + label=__("Database Connections"), + icon="fa-database", + category="Data", + category_label=__("Data"), ) appbuilder.add_view( DashboardModelView, @@ -250,6 +258,16 @@ def init_views(self) -> None: category="", category_icon="", ) + + appbuilder.add_link( + "Datasets", + label=__("Datasets"), + href="/tablemodelview/list/", + icon="fa-table", + category="", + category_icon="", + ) + appbuilder.add_view( DynamicPluginsView, "Plugins", @@ -290,7 +308,10 @@ def init_views(self) -> None: appbuilder.add_view_no_menu(Dashboard) appbuilder.add_view_no_menu(DashboardModelViewAsync) appbuilder.add_view_no_menu(Datasource) + appbuilder.add_view_no_menu(DatasetEditor) appbuilder.add_view_no_menu(EmbeddedView) + appbuilder.add_view_no_menu(ExploreView) + appbuilder.add_view_no_menu(ExplorePermalinkView) appbuilder.add_view_no_menu(KV) appbuilder.add_view_no_menu(R) appbuilder.add_view_no_menu(SavedQueryView) @@ -298,7 +319,6 @@ def init_views(self) -> None: appbuilder.add_view_no_menu(SliceAsync) appbuilder.add_view_no_menu(SqlLab) appbuilder.add_view_no_menu(SqlMetricInlineView) - appbuilder.add_view_no_menu(AnnotationModelView) appbuilder.add_view_no_menu(Superset) appbuilder.add_view_no_menu(TableColumnInlineView) appbuilder.add_view_no_menu(TableModelView) @@ -324,47 +344,30 @@ def init_views(self) -> None: ) appbuilder.add_link( "SQL Editor", - label=_("SQL Editor"), + label=__("SQL Lab"), href="/superset/sqllab/", category_icon="fa-flask", icon="fa-flask", category="SQL Lab", - category_label=__("SQL Lab"), + category_label=__("SQL"), ) appbuilder.add_link( - __("Saved Queries"), + "Saved Queries", + label=__("Saved Queries"), href="/savedqueryview/list/", icon="fa-save", category="SQL Lab", + category_label=__("SQL"), ) appbuilder.add_link( "Query Search", - label=_("Query History"), + label=__("Query History"), href="/superset/sqllab/history/", icon="fa-search", category_icon="fa-flask", category="SQL Lab", - category_label=__("SQL Lab"), - ) - appbuilder.add_view( - DatabaseView, - "Databases", - label=__("Databases"), - icon="fa-database", - category="Data", - category_label=__("Data"), - category_icon="fa-database", - ) - appbuilder.add_link( - "Datasets", - label=__("Datasets"), - href="/tablemodelview/list/", - icon="fa-table", - category="Data", - category_label=__("Data"), - category_icon="fa-table", + category_label=__("SQL"), ) - appbuilder.add_separator("Data") appbuilder.add_api(LogRestApi) appbuilder.add_view( @@ -394,6 +397,17 @@ def init_views(self) -> None: menu_cond=lambda: feature_flag_manager.is_feature_enabled("ALERT_REPORTS"), ) + appbuilder.add_view( + AnnotationLayerView, + "Annotation Layers", + label=__("Annotation Layers"), + href="/annotationlayer/list/", + icon="fa-comment", + category_icon="", + category="Manage", + category_label=__("Manage"), + ) + appbuilder.add_view( AccessRequestsModelView, "Access requests", @@ -413,6 +427,8 @@ def init_app_in_ctx(self) -> None: self.configure_data_sources() self.configure_auth_provider() self.configure_async_queries() + self.configure_ssh_manager() + self.configure_stats_manager() # Hook that provides administrators a handle on the Flask APP # after initialization @@ -420,6 +436,9 @@ def init_app_in_ctx(self) -> None: if flask_app_mutator: flask_app_mutator(self.superset_app) + if feature_flag_manager.is_feature_enabled("TAGGING_SYSTEM"): + register_sqla_event_listeners() + self.init_views() def check_secret_key(self) -> None: @@ -467,6 +486,12 @@ def init_app(self) -> None: def configure_auth_provider(self) -> None: machine_auth_provider_factory.init_app(self.superset_app) + def configure_ssh_manager(self) -> None: + ssh_manager_factory.init_app(self.superset_app) + + def configure_stats_manager(self) -> None: + stats_logger_manager.init_app(self.superset_app) + def setup_event_logger(self) -> None: _event_logger["event_logger"] = get_event_logger_from_cfg_value( self.superset_app.config.get("EVENT_LOGGER", DBEventLogger()) @@ -476,7 +501,11 @@ def configure_data_sources(self) -> None: # Registering sources module_datasource_map = self.config["DEFAULT_MODULE_DS_MAP"] module_datasource_map.update(self.config["ADDITIONAL_MODULE_DS_MAP"]) - ConnectorRegistry.register_sources(module_datasource_map) + + # todo(hughhhh): fully remove the datasource config register + for module_name, class_names in module_datasource_map.items(): + class_names = [str(s) for s in class_names] + __import__(module_name, fromlist=class_names) def configure_cache(self) -> None: cache_manager.init_app(self.superset_app) @@ -561,25 +590,33 @@ def __call__( # Flask-Compress Compress(self.superset_app) + # Talisman + talisman_enabled = self.config["TALISMAN_ENABLED"] + talisman_config = self.config["TALISMAN_CONFIG"] + csp_warning = self.config["CONTENT_SECURITY_POLICY_WARNING"] + + if talisman_enabled: + talisman.init_app(self.superset_app, **talisman_config) + show_csp_warning = False if ( - self.config["CONTENT_SECURITY_POLICY_WARNING"] + csp_warning and not self.superset_app.debug + and ( + not talisman_enabled + or not talisman_config + or not talisman_config.get("content_security_policy") + ) ): - if self.config["TALISMAN_ENABLED"]: - talisman.init_app(self.superset_app, **self.config["TALISMAN_CONFIG"]) - if not self.config["TALISMAN_CONFIG"].get("content_security_policy"): - show_csp_warning = True - else: - show_csp_warning = True + show_csp_warning = True if show_csp_warning: logger.warning( "We haven't found any Content Security Policy (CSP) defined in " "the configurations. Please make sure to configure CSP using the " - "TALISMAN_CONFIG key or any other external software. Failing to " - "configure CSP have serious security implications. Check " - "https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP for more " + "TALISMAN_ENABLED and TALISMAN_CONFIG keys or any other external " + "software. Failing to configure CSP have serious security implications. " + "Check https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP for more " "information. You can disable this warning using the " "CONTENT_SECURITY_POLICY_WARNING key." ) diff --git a/superset/jinja_context.py b/superset/jinja_context.py index 4ee250673f8c6..823c67451bebf 100644 --- a/superset/jinja_context.py +++ b/superset/jinja_context.py @@ -41,7 +41,11 @@ from superset.datasets.commands.exceptions import DatasetNotFoundError from superset.exceptions import SupersetTemplateException from superset.extensions import feature_flag_manager -from superset.utils.core import convert_legacy_filters_into_adhoc, merge_extra_filters +from superset.utils.core import ( + convert_legacy_filters_into_adhoc, + get_user_id, + merge_extra_filters, +) from superset.utils.memoized import memoized if TYPE_CHECKING: @@ -115,9 +119,10 @@ def current_user_id(self, add_to_cache_keys: bool = True) -> Optional[int]: """ if hasattr(g, "user") and g.user: + id_ = get_user_id() if add_to_cache_keys: - self.cache_key_wrapper(g.user.get_id()) - return g.user.get_id() + self.cache_key_wrapper(id_) + return id_ return None def current_username(self, add_to_cache_keys: bool = True) -> Optional[str]: diff --git a/superset/key_value/commands/create.py b/superset/key_value/commands/create.py index 5125ce7b01e28..93e99c223ba59 100644 --- a/superset/key_value/commands/create.py +++ b/superset/key_value/commands/create.py @@ -20,7 +20,6 @@ from typing import Any, Optional, Union from uuid import UUID -from flask_appbuilder.security.sqla.models import User from sqlalchemy.exc import SQLAlchemyError from superset import db @@ -28,23 +27,21 @@ from superset.key_value.exceptions import KeyValueCreateFailedError from superset.key_value.models import KeyValueEntry from superset.key_value.types import Key, KeyValueResource +from superset.utils.core import get_user_id logger = logging.getLogger(__name__) class CreateKeyValueCommand(BaseCommand): - actor: Optional[User] resource: KeyValueResource value: Any key: Optional[Union[int, UUID]] expires_on: Optional[datetime] - # pylint: disable=too-many-arguments def __init__( self, resource: KeyValueResource, value: Any, - actor: Optional[User] = None, key: Optional[Union[int, UUID]] = None, expires_on: Optional[datetime] = None, ): @@ -53,13 +50,11 @@ def __init__( :param resource: the resource (dashboard, chart etc) :param value: the value to persist in the key-value store - :param actor: the user performing the command :param key: id of entry (autogenerated if undefined) :param expires_on: entry expiration time :return: the key associated with the persisted value """ self.resource = resource - self.actor = actor self.value = value self.key = key self.expires_on = expires_on @@ -69,7 +64,6 @@ def run(self) -> Key: return self.create() except SQLAlchemyError as ex: db.session.rollback() - logger.exception("Error running create command") raise KeyValueCreateFailedError() from ex def validate(self) -> None: @@ -80,9 +74,7 @@ def create(self) -> Key: resource=self.resource.value, value=pickle.dumps(self.value), created_on=datetime.now(), - created_by_fk=None - if self.actor is None or self.actor.is_anonymous - else self.actor.id, + created_by_fk=get_user_id(), expires_on=self.expires_on, ) if self.key is not None: diff --git a/superset/key_value/commands/delete.py b/superset/key_value/commands/delete.py index f8ad291714ae1..b3cf84be07515 100644 --- a/superset/key_value/commands/delete.py +++ b/superset/key_value/commands/delete.py @@ -50,7 +50,6 @@ def run(self) -> bool: return self.delete() except SQLAlchemyError as ex: db.session.rollback() - logger.exception("Error running delete command") raise KeyValueDeleteFailedError() from ex def validate(self) -> None: diff --git a/superset/key_value/commands/delete_expired.py b/superset/key_value/commands/delete_expired.py index 4031d13968302..166a9f6f87abe 100644 --- a/superset/key_value/commands/delete_expired.py +++ b/superset/key_value/commands/delete_expired.py @@ -46,7 +46,6 @@ def run(self) -> None: self.delete_expired() except SQLAlchemyError as ex: db.session.rollback() - logger.exception("Error running delete command") raise KeyValueDeleteFailedError() from ex def validate(self) -> None: diff --git a/superset/key_value/commands/get.py b/superset/key_value/commands/get.py index 01560949e37ff..44c02331cccb9 100644 --- a/superset/key_value/commands/get.py +++ b/superset/key_value/commands/get.py @@ -52,7 +52,6 @@ def run(self) -> Any: try: return self.get() except SQLAlchemyError as ex: - logger.exception("Error running get command") raise KeyValueGetFailedError() from ex def validate(self) -> None: diff --git a/superset/key_value/commands/update.py b/superset/key_value/commands/update.py index 48fd8daa8a458..b69ca5e70d76b 100644 --- a/superset/key_value/commands/update.py +++ b/superset/key_value/commands/update.py @@ -21,7 +21,6 @@ from typing import Any, Optional, Union from uuid import UUID -from flask_appbuilder.security.sqla.models import User from sqlalchemy.exc import SQLAlchemyError from superset import db @@ -30,24 +29,22 @@ from superset.key_value.models import KeyValueEntry from superset.key_value.types import Key, KeyValueResource from superset.key_value.utils import get_filter +from superset.utils.core import get_user_id logger = logging.getLogger(__name__) class UpdateKeyValueCommand(BaseCommand): - actor: Optional[User] resource: KeyValueResource value: Any key: Union[int, UUID] expires_on: Optional[datetime] - # pylint: disable=too-many-argumentsåå def __init__( self, resource: KeyValueResource, key: Union[int, UUID], value: Any, - actor: Optional[User] = None, expires_on: Optional[datetime] = None, ): """ @@ -56,11 +53,9 @@ def __init__( :param resource: the resource (dashboard, chart etc) :param key: the key to update :param value: the value to persist in the key-value store - :param actor: the user performing the command :param expires_on: entry expiration time :return: the key associated with the updated value """ - self.actor = actor self.resource = resource self.key = key self.value = value @@ -71,7 +66,6 @@ def run(self) -> Optional[Key]: return self.update() except SQLAlchemyError as ex: db.session.rollback() - logger.exception("Error running update command") raise KeyValueUpdateFailedError() from ex def validate(self) -> None: @@ -89,9 +83,7 @@ def update(self) -> Optional[Key]: entry.value = pickle.dumps(self.value) entry.expires_on = self.expires_on entry.changed_on = datetime.now() - entry.changed_by_fk = ( - None if self.actor is None or self.actor.is_anonymous else self.actor.id - ) + entry.changed_by_fk = get_user_id() db.session.merge(entry) db.session.commit() return Key(id=entry.id, uuid=entry.uuid) diff --git a/superset/key_value/commands/upsert.py b/superset/key_value/commands/upsert.py index 8fd0bd240f2be..06b33c90fcfec 100644 --- a/superset/key_value/commands/upsert.py +++ b/superset/key_value/commands/upsert.py @@ -21,34 +21,34 @@ from typing import Any, Optional, Union from uuid import UUID -from flask_appbuilder.security.sqla.models import User from sqlalchemy.exc import SQLAlchemyError from superset import db from superset.commands.base import BaseCommand from superset.key_value.commands.create import CreateKeyValueCommand -from superset.key_value.exceptions import KeyValueUpdateFailedError +from superset.key_value.exceptions import ( + KeyValueCreateFailedError, + KeyValueUpsertFailedError, +) from superset.key_value.models import KeyValueEntry from superset.key_value.types import Key, KeyValueResource from superset.key_value.utils import get_filter +from superset.utils.core import get_user_id logger = logging.getLogger(__name__) class UpsertKeyValueCommand(BaseCommand): - actor: Optional[User] resource: KeyValueResource value: Any key: Union[int, UUID] expires_on: Optional[datetime] - # pylint: disable=too-many-arguments def __init__( self, resource: KeyValueResource, key: Union[int, UUID], value: Any, - actor: Optional[User] = None, expires_on: Optional[datetime] = None, ): """ @@ -58,28 +58,25 @@ def __init__( :param key: the key to update :param value: the value to persist in the key-value store :param key_type: the type of the key to update - :param actor: the user performing the command :param expires_on: entry expiration time :return: the key associated with the updated value """ - self.actor = actor self.resource = resource self.key = key self.value = value self.expires_on = expires_on - def run(self) -> Optional[Key]: + def run(self) -> Key: try: return self.upsert() - except SQLAlchemyError as ex: + except (KeyValueCreateFailedError, SQLAlchemyError) as ex: db.session.rollback() - logger.exception("Error running update command") - raise KeyValueUpdateFailedError() from ex + raise KeyValueUpsertFailedError() from ex def validate(self) -> None: pass - def upsert(self) -> Optional[Key]: + def upsert(self) -> Key: filter_ = get_filter(self.resource, self.key) entry: KeyValueEntry = ( db.session.query(KeyValueEntry) @@ -91,16 +88,14 @@ def upsert(self) -> Optional[Key]: entry.value = pickle.dumps(self.value) entry.expires_on = self.expires_on entry.changed_on = datetime.now() - entry.changed_by_fk = ( - None if self.actor is None or self.actor.is_anonymous else self.actor.id - ) + entry.changed_by_fk = get_user_id() db.session.merge(entry) db.session.commit() return Key(entry.id, entry.uuid) + return CreateKeyValueCommand( resource=self.resource, value=self.value, - actor=self.actor, key=self.key, expires_on=self.expires_on, ).run() diff --git a/superset/key_value/exceptions.py b/superset/key_value/exceptions.py index fc66d24c2f323..b05daf6b89e02 100644 --- a/superset/key_value/exceptions.py +++ b/superset/key_value/exceptions.py @@ -46,5 +46,9 @@ class KeyValueUpdateFailedError(UpdateFailedError): message = _("An error occurred while updating the value.") +class KeyValueUpsertFailedError(UpdateFailedError): + message = _("An error occurred while upserting the value.") + + class KeyValueAccessDeniedError(ForbiddenError): message = _("You don't have permission to modify the value.") diff --git a/superset/key_value/models.py b/superset/key_value/models.py index f846d9039d4e0..f92457d190178 100644 --- a/superset/key_value/models.py +++ b/superset/key_value/models.py @@ -21,6 +21,8 @@ from superset import security_manager from superset.models.helpers import AuditMixinNullable, ImportExportMixin +VALUE_MAX_SIZE = 2**24 - 1 + class KeyValueEntry(Model, AuditMixinNullable, ImportExportMixin): """Key value store entity""" @@ -28,7 +30,7 @@ class KeyValueEntry(Model, AuditMixinNullable, ImportExportMixin): __tablename__ = "key_value" id = Column(Integer, primary_key=True) resource = Column(String(32), nullable=False) - value = Column(LargeBinary(length=2**24 - 1), nullable=False) + value = Column(LargeBinary(length=VALUE_MAX_SIZE), nullable=False) created_on = Column(DateTime, nullable=True) created_by_fk = Column(Integer, ForeignKey("ab_user.id"), nullable=True) changed_on = Column(DateTime, nullable=True) diff --git a/superset/key_value/utils.py b/superset/key_value/utils.py index db27e505fbd6c..2468618a81b62 100644 --- a/superset/key_value/utils.py +++ b/superset/key_value/utils.py @@ -18,15 +18,15 @@ from hashlib import md5 from secrets import token_urlsafe -from typing import Optional, Union -from uuid import UUID +from typing import Any, Union +from uuid import UUID, uuid3 import hashids -from flask_appbuilder.security.sqla.models import User from flask_babel import gettext as _ from superset.key_value.exceptions import KeyValueParseKeyError from superset.key_value.types import KeyValueFilter, KeyValueResource +from superset.utils.core import json_dumps_w_dates HASHIDS_MIN_LENGTH = 11 @@ -66,5 +66,7 @@ def get_uuid_namespace(seed: str) -> UUID: return UUID(md5_obj.hexdigest()) -def get_owner(user: User) -> Optional[int]: - return user.get_user_id() if not user.is_anonymous else None +def get_deterministic_uuid(namespace: str, payload: Any) -> UUID: + """Get a deterministic UUID (uuid3) from a salt and a JSON-serializable payload.""" + payload_str = json_dumps_w_dates(payload, sort_keys=True) + return uuid3(get_uuid_namespace(namespace), payload_str) diff --git a/superset/migrations/alembic.ini b/superset/migrations/alembic.ini index 28169d2bebf81..1b330a59e206d 100644 --- a/superset/migrations/alembic.ini +++ b/superset/migrations/alembic.ini @@ -28,7 +28,7 @@ file_template = %%(year)d-%%(month).2d-%%(day).2d_%%(hour).2d-%%(minute).2d_%%(r # Logging configuration [loggers] -keys = root,sqlalchemy,alembic +keys = root,sqlalchemy,alembic,flask_migrate [handlers] keys = console @@ -60,3 +60,8 @@ formatter = generic [formatter_generic] format = %(levelname)-5.5s [%(name)s] %(message)s datefmt = %H:%M:%S + +[logger_flask_migrate] +level = DEBUG +handlers = +qualname = flask_migrate diff --git a/superset/migrations/shared/migrate_viz/__init__.py b/superset/migrations/shared/migrate_viz/__init__.py new file mode 100644 index 0000000000000..aaa860e733793 --- /dev/null +++ b/superset/migrations/shared/migrate_viz/__init__.py @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from .processors import * diff --git a/superset/migrations/shared/migrate_viz/base.py b/superset/migrations/shared/migrate_viz/base.py new file mode 100644 index 0000000000000..024a58463e252 --- /dev/null +++ b/superset/migrations/shared/migrate_viz/base.py @@ -0,0 +1,145 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import json +from typing import Dict, Set + +from alembic import op +from sqlalchemy import and_, Column, Integer, String, Text +from sqlalchemy.ext.declarative import declarative_base + +from superset import db +from superset.migrations.shared.utils import paginated_update, try_load_json + +Base = declarative_base() + + +class Slice(Base): # type: ignore + __tablename__ = "slices" + + id = Column(Integer, primary_key=True) + slice_name = Column(String(250)) + viz_type = Column(String(250)) + params = Column(Text) + query_context = Column(Text) + + +FORM_DATA_BAK_FIELD_NAME = "form_data_bak" + + +class MigrateViz: + remove_keys: Set[str] = set() + rename_keys: Dict[str, str] = {} + source_viz_type: str + target_viz_type: str + + def __init__(self, form_data: str) -> None: + self.data = try_load_json(form_data) + + def _pre_action(self) -> None: + """some actions before migrate""" + + def _migrate(self) -> None: + if self.data.get("viz_type") != self.source_viz_type: + return + + if "viz_type" in self.data: + self.data["viz_type"] = self.target_viz_type + + rv_data = {} + for key, value in self.data.items(): + if key in self.rename_keys and self.rename_keys[key] in rv_data: + raise ValueError("Duplicate key in target viz") + + if key in self.rename_keys: + rv_data[self.rename_keys[key]] = value + + if key in self.remove_keys: + continue + + rv_data[key] = value + + self.data = rv_data + + def _post_action(self) -> None: + """some actions after migrate""" + + @classmethod + def upgrade_slice(cls, slc: Slice) -> Slice: + clz = cls(slc.params) + slc.viz_type = cls.target_viz_type + form_data_bak = clz.data.copy() + + clz._pre_action() + clz._migrate() + clz._post_action() + + # only backup params + slc.params = json.dumps({**clz.data, FORM_DATA_BAK_FIELD_NAME: form_data_bak}) + + query_context = try_load_json(slc.query_context) + if "form_data" in query_context: + query_context["form_data"] = clz.data + slc.query_context = json.dumps(query_context) + return slc + + @classmethod + def downgrade_slice(cls, slc: Slice) -> Slice: + form_data = try_load_json(slc.params) + form_data_bak = form_data.get(FORM_DATA_BAK_FIELD_NAME, {}) + if "viz_type" in form_data_bak: + slc.params = json.dumps(form_data_bak) + slc.viz_type = form_data_bak.get("viz_type") + query_context = try_load_json(slc.query_context) + if "form_data" in query_context: + query_context["form_data"] = form_data_bak + slc.query_context = json.dumps(query_context) + return slc + + @classmethod + def upgrade(cls) -> None: + bind = op.get_bind() + session = db.Session(bind=bind) + slices = session.query(Slice).filter(Slice.viz_type == cls.source_viz_type) + for slc in paginated_update( + slices, + lambda current, total: print( + f" Updating {current}/{total} charts", end="\r" + ), + ): + new_viz = cls.upgrade_slice(slc) + session.merge(new_viz) + + @classmethod + def downgrade(cls) -> None: + bind = op.get_bind() + session = db.Session(bind=bind) + slices = session.query(Slice).filter( + and_( + Slice.viz_type == cls.target_viz_type, + Slice.params.like(f"%{FORM_DATA_BAK_FIELD_NAME}%"), + ) + ) + for slc in paginated_update( + slices, + lambda current, total: print( + f" Downgrading {current}/{total} charts", end="\r" + ), + ): + new_viz = cls.downgrade_slice(slc) + session.merge(new_viz) diff --git a/superset/migrations/shared/migrate_viz/processors.py b/superset/migrations/shared/migrate_viz/processors.py new file mode 100644 index 0000000000000..3584856beb72c --- /dev/null +++ b/superset/migrations/shared/migrate_viz/processors.py @@ -0,0 +1,55 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from .base import MigrateViz + + +class MigrateTreeMap(MigrateViz): + source_viz_type = "treemap" + target_viz_type = "treemap_v2" + remove_keys = {"metrics"} + + def _pre_action(self) -> None: + if ( + "metrics" in self.data + and isinstance(self.data["metrics"], list) + and len(self.data["metrics"]) > 0 + ): + self.data["metric"] = self.data["metrics"][0] + + +class MigrateAreaChart(MigrateViz): + source_viz_type = "area" + target_viz_type = "echarts_area" + remove_keys = {"contribution", "stacked_style", "x_axis_label"} + + def _pre_action(self) -> None: + if self.data.get("contribution"): + self.data["contributionMode"] = "row" + + stacked = self.data.get("stacked_style") + if stacked: + stacked_map = { + "expand": "Expand", + "stack": "Stack", + } + self.data["show_extra_controls"] = True + self.data["stack"] = stacked_map.get(stacked) + + x_axis_label = self.data.get("x_axis_label") + if x_axis_label: + self.data["x_axis_title"] = x_axis_label + self.data["x_axis_title_margin"] = 30 diff --git a/superset/migrations/shared/utils.py b/superset/migrations/shared/utils.py index 4b0c4e1440dd5..e05b1d357f2e4 100644 --- a/superset/migrations/shared/utils.py +++ b/superset/migrations/shared/utils.py @@ -14,19 +14,20 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +import json import logging import os import time -from typing import Any +from typing import Any, Callable, Dict, Iterator, Optional, Union from uuid import uuid4 from alembic import op -from sqlalchemy import engine_from_config +from sqlalchemy import engine_from_config, inspect from sqlalchemy.dialects.mysql.base import MySQLDialect from sqlalchemy.dialects.postgresql.base import PGDialect from sqlalchemy.engine import reflection from sqlalchemy.exc import NoSuchTableError -from sqlalchemy.orm import Session +from sqlalchemy.orm import Query, Session logger = logging.getLogger(__name__) @@ -80,16 +81,55 @@ def assign_uuids( print(f"Done. Assigned {count} uuids in {time.time() - start_time:.3f}s.\n") return - # Othwewise Use Python uuid function - start = 0 - while start < count: - end = min(start + batch_size, count) - for obj in session.query(model)[start:end]: - obj.uuid = uuid4() - session.merge(obj) + for obj in paginated_update( + session.query(model), + lambda current, total: print( + f" uuid assigned to {current} out of {total}", end="\r" + ), + batch_size=batch_size, + ): + obj.uuid = uuid4 + print(f"Done. Assigned {count} uuids in {time.time() - start_time:.3f}s.\n") + + +def paginated_update( + query: Query, + print_page_progress: Optional[Union[Callable[[int, int], None], bool]] = None, + batch_size: int = DEFAULT_BATCH_SIZE, +) -> Iterator[Any]: + """ + Update models in small batches so we don't have to load everything in memory. + """ + + total = query.count() + processed = 0 + session: Session = inspect(query).session + result = session.execute(query) + + if print_page_progress is None or print_page_progress is True: + print_page_progress = lambda processed, total: print( + f" {processed}/{total}", end="\r" + ) + + while True: + rows = result.fetchmany(batch_size) + + if not rows: + break + + for row in rows: + yield row[0] + session.commit() - if start + batch_size < count: - print(f" uuid assigned to {end} out of {count}\r", end="") - start += batch_size + processed += len(rows) - print(f"Done. Assigned {count} uuids in {time.time() - start_time:.3f}s.\n") + if print_page_progress: + print_page_progress(processed, total) + + +def try_load_json(data: Optional[str]) -> Dict[str, Any]: + try: + return data and json.loads(data) or {} + except json.decoder.JSONDecodeError: + print(f"Failed to parse: {data}") + return {} diff --git a/superset/migrations/versions/2016-06-27_08-43_27ae655e4247_make_creator_owners.py b/superset/migrations/versions/2016-06-27_08-43_27ae655e4247_make_creator_owners.py index c373c0f7e9090..ee3340d0a3aa3 100644 --- a/superset/migrations/versions/2016-06-27_08-43_27ae655e4247_make_creator_owners.py +++ b/superset/migrations/versions/2016-06-27_08-43_27ae655e4247_make_creator_owners.py @@ -34,6 +34,7 @@ from sqlalchemy.orm import relationship from superset import db +from superset.utils.core import get_user_id Base = declarative_base() @@ -63,17 +64,10 @@ class User(Base): class AuditMixin: - @classmethod - def get_user_id(cls): - try: - return g.user.id - except Exception: - return None - @declared_attr def created_by_fk(cls): return Column( - Integer, ForeignKey("ab_user.id"), default=cls.get_user_id, nullable=False + Integer, ForeignKey("ab_user.id"), default=get_user_id, nullable=False ) @declared_attr diff --git a/superset/migrations/versions/2017-02-08_14-16_a99f2f7c195a_rewriting_url_from_shortner_with_new_.py b/superset/migrations/versions/2017-02-08_14-16_a99f2f7c195a_rewriting_url_from_shortner_with_new_.py index 5e1ae9a258678..04a39a31f5805 100644 --- a/superset/migrations/versions/2017-02-08_14-16_a99f2f7c195a_rewriting_url_from_shortner_with_new_.py +++ b/superset/migrations/versions/2017-02-08_14-16_a99f2f7c195a_rewriting_url_from_shortner_with_new_.py @@ -14,7 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -"""rewriting url from shortner with new format +"""rewriting url from shortener with new format Revision ID: a99f2f7c195a Revises: 53fc3de270ae diff --git a/superset/migrations/versions/2018-07-05_15-19_3dda56f1c4c6_migrate_num_period_compare_and_period_.py b/superset/migrations/versions/2018-07-05_15-19_3dda56f1c4c6_migrate_num_period_compare_and_period_.py index 1d0d81faaf2cf..2e491e9303f4e 100644 --- a/superset/migrations/versions/2018-07-05_15-19_3dda56f1c4c6_migrate_num_period_compare_and_period_.py +++ b/superset/migrations/versions/2018-07-05_15-19_3dda56f1c4c6_migrate_num_period_compare_and_period_.py @@ -56,7 +56,7 @@ class Slice(Base): "second": "PT1S", "minute": "PT1M", "5 minute": "PT5M", - "10 minute": "PT10M", + "10 minute": "PT10M", "half hour": "PT0.5H", "hour": "PT1H", "day": "P1D", diff --git a/superset/migrations/versions/2018-07-26_11-10_c82ee8a39623_add_implicit_tags.py b/superset/migrations/versions/2018-07-26_11-10_c82ee8a39623_add_implicit_tags.py index ad809d3e4564e..0179ba7d0348e 100644 --- a/superset/migrations/versions/2018-07-26_11-10_c82ee8a39623_add_implicit_tags.py +++ b/superset/migrations/versions/2018-07-26_11-10_c82ee8a39623_add_implicit_tags.py @@ -33,7 +33,8 @@ from sqlalchemy import Column, DateTime, Enum, ForeignKey, Integer, String from sqlalchemy.ext.declarative import declarative_base, declared_attr -from superset.models.tags import ObjectTypes, TagTypes +from superset.tags.models import ObjectTypes, TagTypes +from superset.utils.core import get_user_id Base = declarative_base() @@ -54,7 +55,7 @@ def created_by_fk(self) -> Column: return Column( Integer, ForeignKey("ab_user.id"), - default=self.get_user_id, + default=get_user_id, nullable=True, ) @@ -63,8 +64,8 @@ def changed_by_fk(self) -> Column: return Column( Integer, ForeignKey("ab_user.id"), - default=self.get_user_id, - onupdate=self.get_user_id, + default=get_user_id, + onupdate=get_user_id, nullable=True, ) diff --git a/superset/migrations/versions/2020-03-25_10-42_f9a30386bd74_cleanup_time_grainularity.py b/superset/migrations/versions/2020-03-25_10-42_f9a30386bd74_cleanup_time_grainularity.py index 055c51174d20d..b45e7f9ad355a 100644 --- a/superset/migrations/versions/2020-03-25_10-42_f9a30386bd74_cleanup_time_grainularity.py +++ b/superset/migrations/versions/2020-03-25_10-42_f9a30386bd74_cleanup_time_grainularity.py @@ -14,7 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -"""cleanup_time_grainularity +"""cleanup_time_granularity Revision ID: f9a30386bd74 Revises: b5998378c225 @@ -47,7 +47,7 @@ class Slice(Base): def upgrade(): """ - Remove any erroneous time grainularity fields from slices foor those visualization + Remove any erroneous time granularity fields from slices foor those visualization types which do not support time granularity. :see: https://github.com/apache/superset/pull/8674 @@ -59,7 +59,7 @@ def upgrade(): bind = op.get_bind() session = db.Session(bind=bind) - # Visualization types which support time grainularity (hence negate). + # Visualization types which support time granularity (hence negate). viz_types = [ "area", "bar", @@ -73,9 +73,9 @@ def upgrade(): "time_table", ] - # Erroneous time grainularity fields for either Druid NoSQL or SQL slices which do - # not support time grainularity. - erroneous = ["grainularity", "time_grain_sqla"] + # Erroneous time granularity fields for either Druid NoSQL or SQL slices which do + # not support time granularity. + erroneous = ["granularity", "time_grain_sqla"] for slc in session.query(Slice).filter(Slice.viz_type.notin_(viz_types)).all(): try: diff --git a/superset/migrations/versions/2020-09-28_17-57_b56500de1855_add_uuid_column_to_import_mixin.py b/superset/migrations/versions/2020-09-28_17-57_b56500de1855_add_uuid_column_to_import_mixin.py index c392c3e78caff..9ff117b1e2a3c 100644 --- a/superset/migrations/versions/2020-09-28_17-57_b56500de1855_add_uuid_column_to_import_mixin.py +++ b/superset/migrations/versions/2020-09-28_17-57_b56500de1855_add_uuid_column_to_import_mixin.py @@ -101,7 +101,7 @@ def update_position_json(dashboard, session, uuid_map): def update_dashboards(session, uuid_map): message = ( - "Updating dasboard position json with slice uuid.." + "Updating dashboard position json with slice uuid.." if uuid_map else "Cleaning up slice uuid from dashboard position json.." ) diff --git a/superset/migrations/versions/2021-05-27_16-10_6f139c533bea_add_advanced_data_types_to_column_models.py b/superset/migrations/versions/2021-05-27_16-10_6f139c533bea_add_advanced_data_types_to_column_models.py index bbbee47fad239..114716c3dace6 100644 --- a/superset/migrations/versions/2021-05-27_16-10_6f139c533bea_add_advanced_data_types_to_column_models.py +++ b/superset/migrations/versions/2021-05-27_16-10_6f139c533bea_add_advanced_data_types_to_column_models.py @@ -14,10 +14,12 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -"""adding_advanced_data_type.py +"""adding advanced data type to column models + Revision ID: 6f139c533bea Revises: cbe71abde154 Create Date: 2021-05-27 16:10:59.567684 + """ import sqlalchemy as sa diff --git a/superset/migrations/versions/2021-08-31_11-37_021b81fe4fbb_add_type_to_native_filter_configuration.py b/superset/migrations/versions/2021-08-31_11-37_021b81fe4fbb_add_type_to_native_filter_configuration.py index 9c26159ba0a89..ae1b6c82edb08 100644 --- a/superset/migrations/versions/2021-08-31_11-37_021b81fe4fbb_add_type_to_native_filter_configuration.py +++ b/superset/migrations/versions/2021-08-31_11-37_021b81fe4fbb_add_type_to_native_filter_configuration.py @@ -31,7 +31,7 @@ import sqlalchemy as sa from alembic import op -from sqlalchemy.ext.declarative.api import declarative_base +from sqlalchemy.ext.declarative import declarative_base from superset import db @@ -91,7 +91,7 @@ def downgrade(): for dashboard in session.query(Dashboard).all(): logger.info( - "[RemoveTypeToNativeFilter] Updating Dashobard<pk:%s>", + "[RemoveTypeToNativeFilter] Updating Dashboard<pk:%s>", dashboard.id, ) if not dashboard.json_metadata: diff --git a/superset/migrations/versions/2021-09-19_14-42_b92d69a6643c_rename_csv_to_file.py b/superset/migrations/versions/2021-09-19_14-42_b92d69a6643c_rename_csv_to_file.py index b816b24320152..d86c8e9114c05 100644 --- a/superset/migrations/versions/2021-09-19_14-42_b92d69a6643c_rename_csv_to_file.py +++ b/superset/migrations/versions/2021-09-19_14-42_b92d69a6643c_rename_csv_to_file.py @@ -39,7 +39,7 @@ def upgrade(): new_column_name="allow_file_upload", existing_type=sa.Boolean(), ) - except sa.exc.OperationalError: + except (sa.exc.OperationalError, sa.exc.DatabaseError): # In MySQL 8.0 renaming the column rename fails because it has # a constraint check; we can safely remove it in that case, see # https://github.com/sqlalchemy/alembic/issues/699 diff --git a/superset/migrations/versions/2022-01-28_16-03_5afbb1a5849b_add_embedded_dahshoard_table.py b/superset/migrations/versions/2022-01-28_16-03_5afbb1a5849b_add_embedded_dahshoard_table.py index 1f1c62782bbe2..5d415e1596e64 100644 --- a/superset/migrations/versions/2022-01-28_16-03_5afbb1a5849b_add_embedded_dahshoard_table.py +++ b/superset/migrations/versions/2022-01-28_16-03_5afbb1a5849b_add_embedded_dahshoard_table.py @@ -14,7 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -"""add_embedded_dahshoard_table +"""add_embedded_dashboard_table Revision ID: 5afbb1a5849b Revises: 5fd49410a97a diff --git a/superset/migrations/versions/2022-04-01_14-38_a9422eeaae74_new_dataset_models_take_2.py b/superset/migrations/versions/2022-04-01_14-38_a9422eeaae74_new_dataset_models_take_2.py index 87c7e13849abd..2dcd1650f0efa 100644 --- a/superset/migrations/versions/2022-04-01_14-38_a9422eeaae74_new_dataset_models_take_2.py +++ b/superset/migrations/versions/2022-04-01_14-38_a9422eeaae74_new_dataset_models_take_2.py @@ -636,14 +636,31 @@ def postprocess_columns(session: Session) -> None: return def get_joined_tables(offset, limit): + + # Import aliased from sqlalchemy + from sqlalchemy.orm import aliased + + # Create alias of NewColumn + new_column_alias = aliased(NewColumn) + # Get subquery and give it the alias "sl_colums_2" + subquery = ( + session.query(new_column_alias) + .offset(offset) + .limit(limit) + .subquery("sl_columns_2") + ) + return ( sa.join( - session.query(NewColumn) - .offset(offset) - .limit(limit) - .subquery("sl_columns"), + subquery, + NewColumn, + # Use column id from subquery + subquery.c.id == NewColumn.id, + ) + .join( dataset_column_association_table, - dataset_column_association_table.c.column_id == NewColumn.id, + # Use column id from subquery + dataset_column_association_table.c.column_id == subquery.c.id, ) .join( NewDataset, @@ -661,12 +678,14 @@ def get_joined_tables(offset, limit): .join(Database, Database.id == NewDataset.database_id) .join( TableColumn, - TableColumn.uuid == NewColumn.uuid, + # Use column uuid from subquery + TableColumn.uuid == subquery.c.uuid, isouter=True, ) .join( SqlMetric, - SqlMetric.uuid == NewColumn.uuid, + # Use column uuid from subquery + SqlMetric.uuid == subquery.c.uuid, isouter=True, ) ) diff --git a/superset/migrations/versions/2022-05-03_19-39_cbe71abde154_fix_report_schedule_and_log.py b/superset/migrations/versions/2022-05-03_19-39_cbe71abde154_fix_report_schedule_and_log.py index 5c88606511d92..d00b60cd18876 100644 --- a/superset/migrations/versions/2022-05-03_19-39_cbe71abde154_fix_report_schedule_and_log.py +++ b/superset/migrations/versions/2022-05-03_19-39_cbe71abde154_fix_report_schedule_and_log.py @@ -31,7 +31,7 @@ from sqlalchemy.ext.declarative import declarative_base from superset import db -from superset.models.reports import ReportState +from superset.reports.models import ReportState Base = declarative_base() diff --git a/superset/migrations/versions/2022-06-19_16-17_f3afaf1f11f0_add_unique_name_desc_rls.py b/superset/migrations/versions/2022-06-19_16-17_f3afaf1f11f0_add_unique_name_desc_rls.py new file mode 100644 index 0000000000000..474824fcc2bb1 --- /dev/null +++ b/superset/migrations/versions/2022-06-19_16-17_f3afaf1f11f0_add_unique_name_desc_rls.py @@ -0,0 +1,78 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""add_unique_name_desc_rls + +Revision ID: f3afaf1f11f0 +Revises: e09b4ae78457 +Create Date: 2022-06-19 16:17:23.318618 + +""" + +# revision identifiers, used by Alembic. +revision = "f3afaf1f11f0" +down_revision = "e09b4ae78457" + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import Session + +Base = declarative_base() + + +class RowLevelSecurityFilter(Base): + __tablename__ = "row_level_security_filters" + id = sa.Column(sa.Integer, primary_key=True) + name = sa.Column(sa.String(255), unique=True, nullable=False) + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + bind = op.get_bind() + session = Session(bind=bind) + + op.add_column( + "row_level_security_filters", sa.Column("name", sa.String(length=255)) + ) + op.add_column( + "row_level_security_filters", sa.Column("description", sa.Text(), nullable=True) + ) + + # Set initial default names make sure we can have unique non null values + all_rls = session.query(RowLevelSecurityFilter).all() + for rls in all_rls: + rls.name = f"rls-{rls.id}" + session.commit() + + # Now it's safe so set non-null and unique + # add unique constraint + with op.batch_alter_table("row_level_security_filters") as batch_op: + # batch mode is required for sqlite + batch_op.alter_column( + "name", + existing_type=sa.String(255), + nullable=False, + ) + batch_op.create_unique_constraint("uq_rls_name", ["name"]) + # ### end Alembic commands ### + + +def downgrade(): + with op.batch_alter_table("row_level_security_filters") as batch_op: + batch_op.drop_constraint("uq_rls_name", type_="unique") + batch_op.drop_column("description") + batch_op.drop_column("name") diff --git a/superset/migrations/versions/2022-06-27_14-59_7fb8bca906d2_permalink_rename_filterstate.py b/superset/migrations/versions/2022-06-27_14-59_7fb8bca906d2_permalink_rename_filterstate.py new file mode 100644 index 0000000000000..0b76404dc9c7c --- /dev/null +++ b/superset/migrations/versions/2022-06-27_14-59_7fb8bca906d2_permalink_rename_filterstate.py @@ -0,0 +1,88 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""permalink_rename_filterState + +Revision ID: 7fb8bca906d2 +Revises: f3afaf1f11f0 +Create Date: 2022-06-27 14:59:20.740380 + +""" + +# revision identifiers, used by Alembic. +revision = "7fb8bca906d2" +down_revision = "f3afaf1f11f0" + +import pickle + +from alembic import op +from sqlalchemy import Column, Integer, LargeBinary, String +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import Session + +from superset import db +from superset.migrations.shared.utils import paginated_update + +Base = declarative_base() +VALUE_MAX_SIZE = 2**24 - 1 +DASHBOARD_PERMALINK_RESOURCE_TYPE = "dashboard_permalink" + + +class KeyValueEntry(Base): + __tablename__ = "key_value" + id = Column(Integer, primary_key=True) + resource = Column(String(32), nullable=False) + value = Column(LargeBinary(length=VALUE_MAX_SIZE), nullable=False) + + +def upgrade(): + bind = op.get_bind() + session: Session = db.Session(bind=bind) + for entry in paginated_update( + session.query(KeyValueEntry).filter( + KeyValueEntry.resource == DASHBOARD_PERMALINK_RESOURCE_TYPE + ) + ): + value = pickle.loads(entry.value) or {} + state = value.get("state") + if state: + if "filterState" in state: + state["dataMask"] = state["filterState"] + del state["filterState"] + if "hash" in state: + state["anchor"] = state["hash"] + del state["hash"] + entry.value = pickle.dumps(value) + + +def downgrade(): + bind = op.get_bind() + session: Session = db.Session(bind=bind) + for entry in paginated_update( + session.query(KeyValueEntry).filter( + KeyValueEntry.resource == DASHBOARD_PERMALINK_RESOURCE_TYPE + ), + ): + value = pickle.loads(entry.value) or {} + state = value.get("state") + if state: + if "dataMask" in state: + state["filterState"] = state["dataMask"] + del state["dataMask"] + if "anchor" in state: + state["hash"] = state["anchor"] + del state["anchor"] + entry.value = pickle.dumps(value) diff --git a/superset/migrations/versions/2022-07-05_15-48_409c7b420ab0_add_created_by_fk_as_owner.py b/superset/migrations/versions/2022-07-05_15-48_409c7b420ab0_add_created_by_fk_as_owner.py new file mode 100644 index 0000000000000..6cdf9f6891cbd --- /dev/null +++ b/superset/migrations/versions/2022-07-05_15-48_409c7b420ab0_add_created_by_fk_as_owner.py @@ -0,0 +1,135 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""add created_by_fk as owner + +Revision ID: 409c7b420ab0 +Revises: a39867932713 +Create Date: 2022-07-05 15:48:06.029190 + +""" + +from alembic import op +from sqlalchemy import and_, Column, insert, Integer +from sqlalchemy.ext.declarative import declarative_base + +# revision identifiers, used by Alembic. +from superset import db + +revision = "409c7b420ab0" +down_revision = "a39867932713" + + +Base = declarative_base() + + +class Dataset(Base): + __tablename__ = "sl_datasets" + + id = Column(Integer, primary_key=True) + created_by_fk = Column(Integer) + + +class DatasetUser(Base): + __tablename__ = "sl_dataset_users" + + id = Column(Integer, primary_key=True) + user_id = Column(Integer) + dataset_id = Column(Integer) + + +class Slice(Base): + __tablename__ = "slices" + + id = Column(Integer, primary_key=True) + created_by_fk = Column(Integer) + + +class SliceUser(Base): + __tablename__ = "slice_user" + + id = Column(Integer, primary_key=True) + user_id = Column(Integer) + slice_id = Column(Integer) + + +class SqlaTable(Base): + __tablename__ = "tables" + + id = Column(Integer, primary_key=True) + created_by_fk = Column(Integer) + + +class SqlaTableUser(Base): + __tablename__ = "sqlatable_user" + + id = Column(Integer, primary_key=True) + user_id = Column(Integer) + table_id = Column(Integer) + + +def upgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + + op.execute( + insert(DatasetUser).from_select( + ["user_id", "dataset_id"], + session.query(Dataset.created_by_fk, Dataset.id) + .outerjoin( + DatasetUser, + and_( + DatasetUser.dataset_id == Dataset.id, + DatasetUser.user_id == Dataset.created_by_fk, + ), + ) + .filter(DatasetUser.dataset_id == None, Dataset.created_by_fk != None), + ) + ) + + op.execute( + insert(SliceUser).from_select( + ["user_id", "slice_id"], + session.query(Slice.created_by_fk, Slice.id) + .outerjoin( + SliceUser, + and_( + SliceUser.slice_id == Slice.id, + SliceUser.user_id == Slice.created_by_fk, + ), + ) + .filter(SliceUser.slice_id == None), + ) + ) + + op.execute( + insert(SqlaTableUser).from_select( + ["user_id", "table_id"], + session.query(SqlaTable.created_by_fk, SqlaTable.id) + .outerjoin( + SqlaTableUser, + and_( + SqlaTableUser.table_id == SqlaTable.id, + SqlaTableUser.user_id == SqlaTable.created_by_fk, + ), + ) + .filter(SqlaTableUser.table_id == None), + ) + ) + + +def downgrade(): + pass diff --git a/tests/integration_tests/db_engine_specs/drill_tests.py b/superset/migrations/versions/2022-07-07_00-00_cdcf3d64daf4_add_user_id_dttm_idx_to_log_model.py similarity index 58% rename from tests/integration_tests/db_engine_specs/drill_tests.py rename to superset/migrations/versions/2022-07-07_00-00_cdcf3d64daf4_add_user_id_dttm_idx_to_log_model.py index e89462ee5f869..1122571e17a8e 100644 --- a/tests/integration_tests/db_engine_specs/drill_tests.py +++ b/superset/migrations/versions/2022-07-07_00-00_cdcf3d64daf4_add_user_id_dttm_idx_to_log_model.py @@ -14,20 +14,27 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from superset.db_engine_specs.drill import DrillEngineSpec -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec +"""Add user_id and dttm composite index to Log model +Revision ID: cdcf3d64daf4 +Revises: 7fb8bca906d2 +Create Date: 2022-04-05 13:27:06.028908 -class TestDrillDbEngineSpec(TestDbEngineSpec): - def test_convert_dttm(self): - dttm = self.get_dttm() +""" - self.assertEqual( - DrillEngineSpec.convert_dttm("DATE", dttm), - "TO_DATE('2019-01-02', 'yyyy-MM-dd')", - ) +# revision identifiers, used by Alembic. +revision = "cdcf3d64daf4" +down_revision = "7fb8bca906d2" - self.assertEqual( - DrillEngineSpec.convert_dttm("TIMESTAMP", dttm), - "TO_TIMESTAMP('2019-01-02 03:04:05', 'yyyy-MM-dd HH:mm:ss')", - ) + +from alembic import op + + +def upgrade(): + op.create_index( + op.f("ix_logs_user_id_dttm"), "logs", ["user_id", "dttm"], unique=False + ) + + +def downgrade(): + op.drop_index(op.f("ix_logs_user_id_dttm"), table_name="logs") diff --git a/superset/migrations/versions/2022-07-07_13-00_c747c78868b6_migrating_legacy_treemap.py b/superset/migrations/versions/2022-07-07_13-00_c747c78868b6_migrating_legacy_treemap.py new file mode 100644 index 0000000000000..18c9acaf57660 --- /dev/null +++ b/superset/migrations/versions/2022-07-07_13-00_c747c78868b6_migrating_legacy_treemap.py @@ -0,0 +1,47 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""Migrating legacy TreeMap + +Revision ID: c747c78868b6 +Revises: cdcf3d64daf4 +Create Date: 2022-06-30 22:04:17.686635 + +""" +from alembic import op +from sqlalchemy.dialects.mysql.base import MySQLDialect + +from superset.migrations.shared.migrate_viz import MigrateTreeMap + +# revision identifiers, used by Alembic. +revision = "c747c78868b6" +down_revision = "cdcf3d64daf4" + + +def upgrade(): + # Ensure `slice.params` and `slice.query_context`` in MySQL is MEDIUMTEXT + # before migration, as the migration will save a duplicate form_data backup + # which may significantly increase the size of these fields. + if isinstance(op.get_bind().dialect, MySQLDialect): + # If the columns are already MEDIUMTEXT, this is a no-op + op.execute("ALTER TABLE slices MODIFY params MEDIUMTEXT") + op.execute("ALTER TABLE slices MODIFY query_context MEDIUMTEXT") + + MigrateTreeMap.upgrade() + + +def downgrade(): + MigrateTreeMap.downgrade() diff --git a/superset/migrations/versions/2022-07-07_14-00_06e1e70058c7_migrating_legacy_area.py b/superset/migrations/versions/2022-07-07_14-00_06e1e70058c7_migrating_legacy_area.py new file mode 100644 index 0000000000000..de4078099104e --- /dev/null +++ b/superset/migrations/versions/2022-07-07_14-00_06e1e70058c7_migrating_legacy_area.py @@ -0,0 +1,36 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""Migrating legacy Area + +Revision ID: 06e1e70058c7 +Revises: c747c78868b6 +Create Date: 2022-06-13 14:17:51.872706 + +""" +from superset.migrations.shared.migrate_viz import MigrateAreaChart + +# revision identifiers, used by Alembic. +revision = "06e1e70058c7" +down_revision = "c747c78868b6" + + +def upgrade(): + MigrateAreaChart.upgrade() + + +def downgrade(): + MigrateAreaChart.downgrade() diff --git a/superset/migrations/versions/2022-07-11_11-26_ffa79af61a56_rename_report_schedule_extra_to_extra_.py b/superset/migrations/versions/2022-07-11_11-26_ffa79af61a56_rename_report_schedule_extra_to_extra_.py new file mode 100644 index 0000000000000..8de19e1266d50 --- /dev/null +++ b/superset/migrations/versions/2022-07-11_11-26_ffa79af61a56_rename_report_schedule_extra_to_extra_.py @@ -0,0 +1,53 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""rename report_schedule.extra to extra_json + +So we can reuse the ExtraJSONMixin + +Revision ID: ffa79af61a56 +Revises: 409c7b420ab0 +Create Date: 2022-07-11 11:26:00.010714 + +""" + +# revision identifiers, used by Alembic. +revision = "ffa79af61a56" +down_revision = "409c7b420ab0" + +from alembic import op +from sqlalchemy.types import Text + + +def upgrade(): + op.alter_column( + "report_schedule", + "extra", + new_column_name="extra_json", + # existing info is required for MySQL + existing_type=Text, + existing_nullable=True, + ) + + +def downgrade(): + op.alter_column( + "report_schedule", + "extra_json", + new_column_name="extra", + existing_type=Text, + existing_nullable=True, + ) diff --git a/superset/migrations/versions/2022-07-19_15-16_a39867932713_query_context_to_mediumtext.py b/superset/migrations/versions/2022-07-19_15-16_a39867932713_query_context_to_mediumtext.py new file mode 100644 index 0000000000000..027b8c77dd1f3 --- /dev/null +++ b/superset/migrations/versions/2022-07-19_15-16_a39867932713_query_context_to_mediumtext.py @@ -0,0 +1,43 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""query_context_to_mediumtext + +Revision ID: a39867932713 +Revises: 06e1e70058c7 +Create Date: 2022-07-19 15:16:06.091961 + +""" +from alembic import op +from sqlalchemy.dialects.mysql.base import MySQLDialect + +# revision identifiers, used by Alembic. +revision = "a39867932713" +down_revision = "06e1e70058c7" + + +def upgrade(): + if isinstance(op.get_bind().dialect, MySQLDialect): + # If the columns are already MEDIUMTEXT, this is a no-op + op.execute("ALTER TABLE slices MODIFY params MEDIUMTEXT") + op.execute("ALTER TABLE slices MODIFY query_context MEDIUMTEXT") + + +def downgrade(): + # It's Okay to keep these columns as MEDIUMTEXT + # Since some oraganizations may have already manually changed the type + # and downgrade may loose data so we don't do it. + pass diff --git a/superset/migrations/versions/2022-08-16_15-23_6d3c6f9d665d_fix_table_chart_conditional_formatting_.py b/superset/migrations/versions/2022-08-16_15-23_6d3c6f9d665d_fix_table_chart_conditional_formatting_.py new file mode 100644 index 0000000000000..30caf7efa111b --- /dev/null +++ b/superset/migrations/versions/2022-08-16_15-23_6d3c6f9d665d_fix_table_chart_conditional_formatting_.py @@ -0,0 +1,82 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""fix_table_chart_conditional_formatting_colors + +Revision ID: 6d3c6f9d665d +Revises: ffa79af61a56 +Create Date: 2022-08-16 15:23:42.860038 + +""" +import json + +from alembic import op +from sqlalchemy import Column, Integer, String, Text +from sqlalchemy.ext.declarative import declarative_base + +from superset import db + +# revision identifiers, used by Alembic. +revision = "6d3c6f9d665d" +down_revision = "ffa79af61a56" + +Base = declarative_base() + + +class Slice(Base): + __tablename__ = "slices" + id = Column(Integer, primary_key=True) + viz_type = Column(String(250)) + params = Column(Text) + + +def upgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + + for slc in session.query(Slice).filter(Slice.viz_type == "table"): + params = json.loads(slc.params) + conditional_formatting = params.get("conditional_formatting", []) + if conditional_formatting: + new_conditional_formatting = [] + for formatter in conditional_formatting: + color_scheme = formatter.get("colorScheme") + new_color_scheme = None + if color_scheme == "rgb(0,255,0)": + # supersetTheme.colors.success.light1 + new_color_scheme = "#ACE1C4" + elif color_scheme == "rgb(255,255,0)": + # supersetTheme.colors.alert.light1 + new_color_scheme = "#FDE380" + elif color_scheme == "rgb(255,0,0)": + # supersetTheme.colors.error.light1 + new_color_scheme = "#EFA1AA" + if new_color_scheme: + new_conditional_formatting.append( + {**formatter, "colorScheme": new_color_scheme} + ) + else: + new_conditional_formatting.append(formatter) + params["conditional_formatting"] = new_conditional_formatting + slc.params = json.dumps(params) + session.merge(slc) + session.commit() + session.close() + + +# it fixes a bug, downgrading isn't really needed here +def downgrade(): + pass diff --git a/superset/migrations/versions/2022-08-31_19-30_291f024254b5_drop_column_allow_multi_schema_metadata_fetch.py b/superset/migrations/versions/2022-08-31_19-30_291f024254b5_drop_column_allow_multi_schema_metadata_fetch.py new file mode 100644 index 0000000000000..fadcb3dda24e5 --- /dev/null +++ b/superset/migrations/versions/2022-08-31_19-30_291f024254b5_drop_column_allow_multi_schema_metadata_fetch.py @@ -0,0 +1,48 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""drop_column_allow_multi_schema_metadata_fetch + + +Revision ID: 291f024254b5 +Revises: 6d3c6f9d665d +Create Date: 2022-08-31 19:30:33.665025 + +""" + +# revision identifiers, used by Alembic. +revision = "291f024254b5" +down_revision = "6d3c6f9d665d" + +import sqlalchemy as sa +from alembic import op + + +def upgrade(): + with op.batch_alter_table("dbs") as batch_op: + batch_op.drop_column("allow_multi_schema_metadata_fetch") + + +def downgrade(): + op.add_column( + "dbs", + sa.Column( + "allow_multi_schema_metadata_fetch", + sa.Boolean(), + nullable=True, + default=True, + ), + ) diff --git a/superset/migrations/versions/2022-10-03_17-34_deb4c9d4a4ef_parameters_in_saved_queries.py b/superset/migrations/versions/2022-10-03_17-34_deb4c9d4a4ef_parameters_in_saved_queries.py new file mode 100644 index 0000000000000..af3f6157a8658 --- /dev/null +++ b/superset/migrations/versions/2022-10-03_17-34_deb4c9d4a4ef_parameters_in_saved_queries.py @@ -0,0 +1,46 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""parameters in saved queries + +Revision ID: deb4c9d4a4ef +Revises: 291f024254b5 +Create Date: 2022-10-03 17:34:00.721559 + +""" + +# revision identifiers, used by Alembic. +revision = "deb4c9d4a4ef" +down_revision = "291f024254b5" + +import sqlalchemy as sa +from alembic import op + + +def upgrade(): + op.add_column( + "saved_query", + sa.Column( + "template_parameters", + sa.TEXT(), + nullable=True, + ), + ) + + +def downgrade(): + with op.batch_alter_table("saved_query") as batch_op: + batch_op.drop_column("template_parameters") diff --git a/superset/migrations/versions/2022-10-20_10-48_f3c2d8ec8595_create_ssh_tunnel_credentials_tbl.py b/superset/migrations/versions/2022-10-20_10-48_f3c2d8ec8595_create_ssh_tunnel_credentials_tbl.py new file mode 100644 index 0000000000000..b373020cb14c9 --- /dev/null +++ b/superset/migrations/versions/2022-10-20_10-48_f3c2d8ec8595_create_ssh_tunnel_credentials_tbl.py @@ -0,0 +1,89 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""create_ssh_tunnel_credentials_tbl + +Revision ID: f3c2d8ec8595 +Revises: 4ce1d9b25135 +Create Date: 2022-10-20 10:48:08.722861 + +""" + +# revision identifiers, used by Alembic. +revision = "f3c2d8ec8595" +down_revision = "4ce1d9b25135" + +from uuid import uuid4 + +import sqlalchemy as sa +from alembic import op +from sqlalchemy_utils import UUIDType + +from superset import app +from superset.extensions import encrypted_field_factory + +app_config = app.config + + +def upgrade(): + op.create_table( + "ssh_tunnels", + # AuditMixinNullable + sa.Column("created_on", sa.DateTime(), nullable=True), + sa.Column("changed_on", sa.DateTime(), nullable=True), + sa.Column("created_by_fk", sa.Integer(), nullable=True), + sa.Column("changed_by_fk", sa.Integer(), nullable=True), + # ExtraJSONMixin + sa.Column("extra_json", sa.Text(), nullable=True), + # ImportExportMixin + sa.Column( + "uuid", + UUIDType(binary=True), + primary_key=False, + default=uuid4, + unique=True, + index=True, + ), + # SSHTunnelCredentials + sa.Column("id", sa.Integer(), primary_key=True), + sa.Column( + "database_id", + sa.INTEGER(), + sa.ForeignKey("dbs.id"), + unique=True, + index=True, + ), + sa.Column("server_address", sa.String(256)), + sa.Column("server_port", sa.INTEGER()), + sa.Column("username", encrypted_field_factory.create(sa.String(256))), + sa.Column( + "password", encrypted_field_factory.create(sa.String(256)), nullable=True + ), + sa.Column( + "private_key", + encrypted_field_factory.create(sa.String(1024)), + nullable=True, + ), + sa.Column( + "private_key_password", + encrypted_field_factory.create(sa.String(256)), + nullable=True, + ), + ) + + +def downgrade(): + op.drop_table("ssh_tunnels") diff --git a/superset/migrations/versions/2022-11-28_17-51_4ce1d9b25135_remove_filter_bar_orientation.py b/superset/migrations/versions/2022-11-28_17-51_4ce1d9b25135_remove_filter_bar_orientation.py new file mode 100644 index 0000000000000..07ee47b9845c8 --- /dev/null +++ b/superset/migrations/versions/2022-11-28_17-51_4ce1d9b25135_remove_filter_bar_orientation.py @@ -0,0 +1,65 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""remove_filter_bar_orientation + +Revision ID: 4ce1d9b25135 +Revises: deb4c9d4a4ef +Create Date: 2022-11-28 17:51:08.954439 + +""" + +# revision identifiers, used by Alembic. +revision = "4ce1d9b25135" +down_revision = "deb4c9d4a4ef" + +import json + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.ext.declarative import declarative_base + +from superset import db + +Base = declarative_base() + + +class Dashboard(Base): + __tablename__ = "dashboards" + id = sa.Column(sa.Integer, primary_key=True) + json_metadata = sa.Column(sa.Text) + + +def upgrade(): + pass + + +def downgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + + dashboards = ( + session.query(Dashboard) + .filter(Dashboard.json_metadata.like('%"filter_bar_orientation"%')) + .all() + ) + for dashboard in dashboards: + json_meta = json.loads(dashboard.json_metadata) + filter_bar_orientation = json_meta.pop("filter_bar_orientation", None) + if filter_bar_orientation: + dashboard.json_metadata = json.dumps(json_meta) + session.commit() + session.close() diff --git a/superset/models/core.py b/superset/models/core.py index c31f727df9f10..2c5c413479c74 100755 --- a/superset/models/core.py +++ b/superset/models/core.py @@ -21,10 +21,10 @@ import logging import textwrap from ast import literal_eval -from contextlib import closing, contextmanager +from contextlib import closing, contextmanager, nullcontext from copy import deepcopy from datetime import datetime -from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type +from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, TYPE_CHECKING import numpy import pandas as pd @@ -46,19 +46,24 @@ from sqlalchemy.engine import Connection, Dialect, Engine from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.url import URL -from sqlalchemy.exc import ArgumentError +from sqlalchemy.exc import ArgumentError, NoSuchModuleError from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import relationship from sqlalchemy.pool import NullPool from sqlalchemy.schema import UniqueConstraint from sqlalchemy.sql import expression, Select -from superset import app, db_engine_specs, is_feature_enabled +from superset import app, db_engine_specs +from superset.constants import PASSWORD_MASK from superset.databases.utils import make_url_safe -from superset.db_engine_specs.base import TimeGrain -from superset.extensions import cache_manager, encrypted_field_factory, security_manager +from superset.db_engine_specs.base import MetricType, TimeGrain +from superset.extensions import ( + cache_manager, + encrypted_field_factory, + security_manager, + ssh_manager_factory, +) from superset.models.helpers import AuditMixinNullable, ImportExportMixin -from superset.models.tags import FavStarUpdater from superset.result_set import SupersetResultSet from superset.utils import cache as cache_util, core as utils from superset.utils.core import get_username @@ -71,7 +76,9 @@ metadata = Model.metadata # pylint: disable=no-member logger = logging.getLogger(__name__) -PASSWORD_MASK = "X" * 10 +if TYPE_CHECKING: + from superset.databases.ssh_tunnel.models import SSHTunnel + DB_CONNECTION_MUTATOR = config["DB_CONNECTION_MUTATOR"] @@ -134,9 +141,6 @@ class Database( allow_cvas = Column(Boolean, default=False) allow_dml = Column(Boolean, default=False) force_ctas_schema = Column(String(250)) - allow_multi_schema_metadata_fetch = Column( # pylint: disable=invalid-name - Boolean, default=False - ) extra = Column( Text, default=textwrap.dedent( @@ -164,10 +168,16 @@ class Database( "allow_run_async", "allow_ctas", "allow_cvas", + "allow_dml", "allow_file_upload", "extra", ] - extra_import_fields = ["password", "is_managed_externally", "external_url"] + extra_import_fields = [ + "password", + "is_managed_externally", + "external_url", + "encrypted_extra", + ] export_children = ["tables"] def __repr__(self) -> str: @@ -228,7 +238,6 @@ def data(self) -> Dict[str, Any]: "name": self.database_name, "backend": self.backend, "configuration_method": self.configuration_method, - "allow_multi_schema_metadata_fetch": self.allow_multi_schema_metadata_fetch, "allows_subquery": self.allows_subquery, "allows_cost_estimate": self.allows_cost_estimate, "allows_virtual_table_explore": self.allows_virtual_table_explore, @@ -236,6 +245,7 @@ def data(self) -> Dict[str, Any]: "parameters": self.parameters, "disable_data_preview": self.disable_data_preview, "parameters_schema": self.parameters_schema, + "engine_information": self.engine_information, } @property @@ -248,17 +258,36 @@ def url_object(self) -> URL: @property def backend(self) -> str: - sqlalchemy_url = make_url_safe(self.sqlalchemy_uri_decrypted) - return sqlalchemy_url.get_backend_name() + return self.url_object.get_backend_name() + + @property + def driver(self) -> str: + return self.url_object.get_driver_name() + + @property + def masked_encrypted_extra(self) -> Optional[str]: + return self.db_engine_spec.mask_encrypted_extra(self.encrypted_extra) @property def parameters(self) -> Dict[str, Any]: - uri = make_url_safe(self.sqlalchemy_uri_decrypted) - encrypted_extra = self.get_encrypted_extra() + # Database parameters are a dictionary of values that are used to make up + # the sqlalchemy_uri + # When returning the parameters we should use the masked SQLAlchemy URI and the + # masked ``encrypted_extra`` to prevent exposing sensitive credentials. + masked_uri = make_url_safe(self.sqlalchemy_uri) + masked_encrypted_extra = self.masked_encrypted_extra + encrypted_config = {} + if masked_encrypted_extra is not None: + try: + encrypted_config = json.loads(masked_encrypted_extra) + except (TypeError, json.JSONDecodeError): + pass + try: # pylint: disable=useless-suppression parameters = self.db_engine_spec.get_parameters_from_uri( # type: ignore - uri, encrypted_extra=encrypted_extra + masked_uri, + encrypted_extra=encrypted_config, ) except Exception: # pylint: disable=broad-except parameters = {} @@ -301,6 +330,14 @@ def default_schemas(self) -> List[str]: def connect_args(self) -> Dict[str, Any]: return self.get_extra().get("engine_params", {}).get("connect_args", {}) + @property + def engine_information(self) -> Dict[str, Any]: + try: + engine_information = self.db_engine_spec.get_public_information() + except Exception: # pylint: disable=broad-except + engine_information = {} + return engine_information + @classmethod def get_password_masked_url_from_uri( # pylint: disable=invalid-name cls, uri: str @@ -312,7 +349,7 @@ def get_password_masked_url_from_uri( # pylint: disable=invalid-name def get_password_masked_url(cls, masked_url: URL) -> URL: url_copy = deepcopy(masked_url) if url_copy.password is not None: - url_copy.password = PASSWORD_MASK + url_copy = url_copy.set(password=PASSWORD_MASK) return url_copy def set_sqlalchemy_uri(self, uri: str) -> None: @@ -320,7 +357,7 @@ def set_sqlalchemy_uri(self, uri: str) -> None: if conn.password != PASSWORD_MASK and not custom_password_store: # do not over-write the password with the password mask self.password = conn.password - conn.password = PASSWORD_MASK if conn.password else None + conn = conn.set(password=PASSWORD_MASK if conn.password else None) self.sqlalchemy_uri = str(conn) # hides the password def get_effective_user(self, object_url: URL) -> Optional[str]: @@ -345,39 +382,59 @@ def get_sqla_engine_with_context( schema: Optional[str] = None, nullpool: bool = True, source: Optional[utils.QuerySource] = None, + override_ssh_tunnel: Optional["SSHTunnel"] = None, ) -> Engine: - try: - yield self.get_sqla_engine(schema=schema, nullpool=nullpool, source=source) - except Exception as ex: - raise self.db_engine_spec.get_dbapi_mapped_exception(ex) + from superset.databases.dao import ( # pylint: disable=import-outside-toplevel + DatabaseDAO, + ) - @memoized( - watch=( - "impersonate_user", - "sqlalchemy_uri_decrypted", - "extra", - "encrypted_extra", + sqlalchemy_uri = self.sqlalchemy_uri_decrypted + engine_context = nullcontext() + ssh_tunnel = override_ssh_tunnel or DatabaseDAO.get_ssh_tunnel( + database_id=self.id ) - ) - def get_sqla_engine( + + if ssh_tunnel: + # if ssh_tunnel is available build engine with information + engine_context = ssh_manager_factory.instance.create_tunnel( + ssh_tunnel=ssh_tunnel, + sqlalchemy_database_uri=self.sqlalchemy_uri_decrypted, + ) + + with engine_context as server_context: + if ssh_tunnel: + sqlalchemy_uri = ssh_manager_factory.instance.build_sqla_url( + sqlalchemy_uri, server_context + ) + yield self._get_sqla_engine( + schema=schema, + nullpool=nullpool, + source=source, + sqlalchemy_uri=sqlalchemy_uri, + ) + + def _get_sqla_engine( self, schema: Optional[str] = None, nullpool: bool = True, source: Optional[utils.QuerySource] = None, + sqlalchemy_uri: Optional[str] = None, ) -> Engine: extra = self.get_extra() - sqlalchemy_url = make_url_safe(self.sqlalchemy_uri_decrypted) - self.db_engine_spec.adjust_database_uri(sqlalchemy_url, schema) + sqlalchemy_url = make_url_safe( + sqlalchemy_uri if sqlalchemy_uri else self.sqlalchemy_uri_decrypted + ) + sqlalchemy_url = self.db_engine_spec.adjust_database_uri(sqlalchemy_url, schema) effective_username = self.get_effective_user(sqlalchemy_url) # If using MySQL or Presto for example, will set url.username # If using Hive, will not do anything yet since that relies on a # configuration parameter instead. - self.db_engine_spec.modify_url_for_impersonation( + sqlalchemy_url = self.db_engine_spec.get_url_for_impersonation( sqlalchemy_url, self.impersonate_user, effective_username ) masked_url = self.get_password_masked_url(sqlalchemy_url) - logger.debug("Database.get_sqla_engine(). Masked URL: %s", str(masked_url)) + logger.debug("Database._get_sqla_engine(). Masked URL: %s", str(masked_url)) params = extra.get("engine_params", {}) if nullpool: @@ -392,26 +449,38 @@ def get_sqla_engine( if connect_args: params["connect_args"] = connect_args - self.update_encrypted_extra_params(params) + self.update_params_from_encrypted_extra(params) if DB_CONNECTION_MUTATOR: if not source and request and request.referrer: if "/superset/dashboard/" in request.referrer: source = utils.QuerySource.DASHBOARD - elif "/superset/explore/" in request.referrer: + elif "/explore/" in request.referrer: source = utils.QuerySource.CHART - elif "/superset/sqllab/" in request.referrer: + elif "/superset/sqllab" in request.referrer: source = utils.QuerySource.SQL_LAB sqlalchemy_url, params = DB_CONNECTION_MUTATOR( sqlalchemy_url, params, effective_username, security_manager, source ) - try: return create_engine(sqlalchemy_url, **params) except Exception as ex: raise self.db_engine_spec.get_dbapi_mapped_exception(ex) + @contextmanager + def get_raw_connection( + self, + schema: Optional[str] = None, + nullpool: bool = True, + source: Optional[utils.QuerySource] = None, + ) -> Connection: + with self.get_sqla_engine_with_context( + schema=schema, nullpool=nullpool, source=source + ) as engine: + with closing(engine.raw_connection()) as conn: + yield conn + @property def quote_identifier(self) -> Callable[[str], str]: """Add quotes to potential identifiter expressions if needed""" @@ -427,7 +496,10 @@ def get_df( # pylint: disable=too-many-locals mutator: Optional[Callable[[pd.DataFrame], None]] = None, ) -> pd.DataFrame: sqls = self.db_engine_spec.parse_sql(sql) - engine = self.get_sqla_engine(schema) + engine = self._get_sqla_engine(schema) + username = utils.get_username() + mutate_after_split = config["MUTATE_AFTER_SPLIT"] + sql_query_mutator = config["SQL_QUERY_MUTATOR"] def needs_conversion(df_series: pd.Series) -> bool: return ( @@ -447,15 +519,32 @@ def _log_query(sql: str) -> None: security_manager, ) - with closing(engine.raw_connection()) as conn: + with self.get_raw_connection(schema=schema) as conn: cursor = conn.cursor() for sql_ in sqls[:-1]: + if mutate_after_split: + sql_ = sql_query_mutator( + sql_, + user_name=username, + security_manager=security_manager, + database=None, + ) _log_query(sql_) self.db_engine_spec.execute(cursor, sql_) cursor.fetchall() - _log_query(sqls[-1]) - self.db_engine_spec.execute(cursor, sqls[-1]) + if mutate_after_split: + last_sql = sql_query_mutator( + sqls[-1], + user_name=username, + security_manager=security_manager, + database=None, + ) + _log_query(last_sql) + self.db_engine_spec.execute(cursor, last_sql) + else: + _log_query(sqls[-1]) + self.db_engine_spec.execute(cursor, sqls[-1]) data = self.db_engine_spec.fetch_data(cursor) result_set = SupersetResultSet( @@ -472,7 +561,7 @@ def _log_query(sql: str) -> None: return df def compile_sqla_query(self, qry: Select, schema: Optional[str] = None) -> str: - engine = self.get_sqla_engine(schema=schema) + engine = self._get_sqla_engine(schema=schema) sql = str(qry.compile(engine, compile_kwargs={"literal_binds": True})) @@ -493,7 +582,7 @@ def select_star( # pylint: disable=too-many-arguments cols: Optional[List[Dict[str, Any]]] = None, ) -> str: """Generates a ``select *`` statement in the proper dialect""" - eng = self.get_sqla_engine(schema=schema, source=utils.QuerySource.SQL_LAB) + eng = self._get_sqla_engine(schema=schema, source=utils.QuerySource.SQL_LAB) return self.db_engine_spec.select_star( self, table_name, @@ -518,52 +607,12 @@ def safe_sqlalchemy_uri(self) -> str: @property def inspector(self) -> Inspector: - engine = self.get_sqla_engine() + engine = self._get_sqla_engine() return sqla.inspect(engine) - @cache_util.memoized_func( - key="db:{self.id}:schema:None:table_list", - cache=cache_manager.data_cache, - ) - def get_all_table_names_in_database( # pylint: disable=unused-argument - self, - cache: bool = False, - cache_timeout: Optional[bool] = None, - force: bool = False, - ) -> List[Tuple[str, str]]: - """Parameters need to be passed as keyword arguments.""" - if not self.allow_multi_schema_metadata_fetch: - return [] - return [ - (datasource_name.table, datasource_name.schema) - for datasource_name in self.db_engine_spec.get_all_datasource_names( - self, "table" - ) - ] - - @cache_util.memoized_func( - key="db:{self.id}:schema:None:view_list", - cache=cache_manager.data_cache, - ) - def get_all_view_names_in_database( # pylint: disable=unused-argument - self, - cache: bool = False, - cache_timeout: Optional[bool] = None, - force: bool = False, - ) -> List[Tuple[str, str]]: - """Parameters need to be passed as keyword arguments.""" - if not self.allow_multi_schema_metadata_fetch: - return [] - return [ - (datasource_name.table, datasource_name.schema) - for datasource_name in self.db_engine_spec.get_all_datasource_names( - self, "view" - ) - ] - @cache_util.memoized_func( key="db:{self.id}:schema:{schema}:table_list", - cache=cache_manager.data_cache, + cache=cache_manager.cache, ) def get_all_table_names_in_schema( # pylint: disable=unused-argument self, @@ -571,7 +620,7 @@ def get_all_table_names_in_schema( # pylint: disable=unused-argument cache: bool = False, cache_timeout: Optional[int] = None, force: bool = False, - ) -> List[Tuple[str, str]]: + ) -> Set[Tuple[str, str]]: """Parameters need to be passed as keyword arguments. For unused parameters, they are referenced in @@ -581,20 +630,25 @@ def get_all_table_names_in_schema( # pylint: disable=unused-argument :param cache: whether cache is enabled for the function :param cache_timeout: timeout in seconds for the cache :param force: whether to force refresh the cache - :return: list of tables + :return: The table/schema pairs """ try: - tables = self.db_engine_spec.get_table_names( - database=self, inspector=self.inspector, schema=schema - ) - return [(table, schema) for table in tables] - except Exception: # pylint: disable=broad-except - logger.warning("Get all table names in schema failed", exc_info=True) - return [] + with self.get_inspector_with_context() as inspector: + tables = { + (table, schema) + for table in self.db_engine_spec.get_table_names( + database=self, + inspector=inspector, + schema=schema, + ) + } + return tables + except Exception as ex: + raise self.db_engine_spec.get_dbapi_mapped_exception(ex) @cache_util.memoized_func( key="db:{self.id}:schema:{schema}:view_list", - cache=cache_manager.data_cache, + cache=cache_manager.cache, ) def get_all_view_names_in_schema( # pylint: disable=unused-argument self, @@ -602,7 +656,7 @@ def get_all_view_names_in_schema( # pylint: disable=unused-argument cache: bool = False, cache_timeout: Optional[int] = None, force: bool = False, - ) -> List[Tuple[str, str]]: + ) -> Set[Tuple[str, str]]: """Parameters need to be passed as keyword arguments. For unused parameters, they are referenced in @@ -612,26 +666,40 @@ def get_all_view_names_in_schema( # pylint: disable=unused-argument :param cache: whether cache is enabled for the function :param cache_timeout: timeout in seconds for the cache :param force: whether to force refresh the cache - :return: list of views + :return: set of views """ try: - views = self.db_engine_spec.get_view_names( - database=self, inspector=self.inspector, schema=schema - ) - return [(view, schema) for view in views] - except Exception: # pylint: disable=broad-except - logger.warning("Get all view names failed", exc_info=True) - return [] + with self.get_inspector_with_context() as inspector: + return { + (view, schema) + for view in self.db_engine_spec.get_view_names( + database=self, + inspector=inspector, + schema=schema, + ) + } + except Exception as ex: + raise self.db_engine_spec.get_dbapi_mapped_exception(ex) + + @contextmanager + def get_inspector_with_context( + self, ssh_tunnel: Optional["SSHTunnel"] = None + ) -> Inspector: + with self.get_sqla_engine_with_context( + override_ssh_tunnel=ssh_tunnel + ) as engine: + yield sqla.inspect(engine) @cache_util.memoized_func( key="db:{self.id}:schema_list", - cache=cache_manager.data_cache, + cache=cache_manager.cache, ) def get_all_schema_names( # pylint: disable=unused-argument self, cache: bool = False, cache_timeout: Optional[int] = None, force: bool = False, + ssh_tunnel: Optional["SSHTunnel"] = None, ) -> List[str]: """Parameters need to be passed as keyword arguments. @@ -643,19 +711,28 @@ def get_all_schema_names( # pylint: disable=unused-argument :param force: whether to force refresh the cache :return: schema list """ - return self.db_engine_spec.get_schema_names(self.inspector) + try: + with self.get_inspector_with_context(ssh_tunnel=ssh_tunnel) as inspector: + return self.db_engine_spec.get_schema_names(inspector) + except Exception as ex: + raise self.db_engine_spec.get_dbapi_mapped_exception(ex) from ex @property def db_engine_spec(self) -> Type[db_engine_specs.BaseEngineSpec]: - return self.get_db_engine_spec_for_backend(self.backend) + url = make_url_safe(self.sqlalchemy_uri_decrypted) + return self.get_db_engine_spec(url) @classmethod @memoized - def get_db_engine_spec_for_backend( - cls, backend: str - ) -> Type[db_engine_specs.BaseEngineSpec]: - engines = db_engine_specs.get_engine_specs() - return engines.get(backend, db_engine_specs.BaseEngineSpec) + def get_db_engine_spec(cls, url: URL) -> Type[db_engine_specs.BaseEngineSpec]: + backend = url.get_backend_name() + try: + driver = url.get_driver_name() + except NoSuchModuleError: + # can't load the driver, fallback for backwards compatibility + driver = None + + return db_engine_specs.get_engine_spec(backend, driver) def grains(self) -> Tuple[TimeGrain, ...]: """Defines time granularity database-specific expressions. @@ -681,9 +758,6 @@ def get_encrypted_extra(self) -> Dict[str, Any]: raise ex return encrypted_extra - def update_encrypted_extra_params(self, params: Dict[str, Any]) -> None: - self.db_engine_spec.update_encrypted_extra_params(self, params) - def update_params_from_encrypted_extra( # pylint: disable=invalid-name self, params: Dict[str, Any] ) -> None: @@ -692,42 +766,61 @@ def update_params_from_encrypted_extra( # pylint: disable=invalid-name def get_table(self, table_name: str, schema: Optional[str] = None) -> Table: extra = self.get_extra() meta = MetaData(**extra.get("metadata_params", {})) - return Table( - table_name, - meta, - schema=schema or None, - autoload=True, - autoload_with=self.get_sqla_engine(), - ) + with self.get_sqla_engine_with_context() as engine: + return Table( + table_name, + meta, + schema=schema or None, + autoload=True, + autoload_with=engine, + ) def get_table_comment( self, table_name: str, schema: Optional[str] = None ) -> Optional[str]: - return self.db_engine_spec.get_table_comment(self.inspector, table_name, schema) + with self.get_inspector_with_context() as inspector: + return self.db_engine_spec.get_table_comment(inspector, table_name, schema) def get_columns( self, table_name: str, schema: Optional[str] = None ) -> List[Dict[str, Any]]: - return self.db_engine_spec.get_columns(self.inspector, table_name, schema) + with self.get_inspector_with_context() as inspector: + return self.db_engine_spec.get_columns(inspector, table_name, schema) + + def get_metrics( + self, + table_name: str, + schema: Optional[str] = None, + ) -> List[MetricType]: + with self.get_inspector_with_context() as inspector: + return self.db_engine_spec.get_metrics(self, inspector, table_name, schema) def get_indexes( self, table_name: str, schema: Optional[str] = None ) -> List[Dict[str, Any]]: - indexes = self.inspector.get_indexes(table_name, schema) - return self.db_engine_spec.normalize_indexes(indexes) + with self.get_inspector_with_context() as inspector: + indexes = inspector.get_indexes(table_name, schema) + return self.db_engine_spec.normalize_indexes(indexes) def get_pk_constraint( self, table_name: str, schema: Optional[str] = None ) -> Dict[str, Any]: - pk_constraint = self.inspector.get_pk_constraint(table_name, schema) or {} - return { - key: utils.base_json_conv(value) for key, value in pk_constraint.items() - } + with self.get_inspector_with_context() as inspector: + pk_constraint = inspector.get_pk_constraint(table_name, schema) or {} + + def _convert(value: Any) -> Any: + try: + return utils.base_json_conv(value) + except TypeError: + return None + + return {key: _convert(value) for key, value in pk_constraint.items()} def get_foreign_keys( self, table_name: str, schema: Optional[str] = None ) -> List[Dict[str, Any]]: - return self.inspector.get_foreign_keys(table_name, schema) + with self.get_inspector_with_context() as inspector: + return inspector.get_foreign_keys(table_name, schema) def get_schema_access_for_file_upload( # pylint: disable=invalid-name self, @@ -753,9 +846,9 @@ def sqlalchemy_uri_decrypted(self) -> str: # (so users see 500 less often) return "dialect://invalid_uri" if custom_password_store: - conn.password = custom_password_store(conn) + conn = conn.set(password=custom_password_store(conn)) else: - conn.password = self.password + conn = conn.set(password=self.password) return str(conn) @property @@ -776,12 +869,12 @@ def get_perm(self) -> str: return self.perm # type: ignore def has_table(self, table: Table) -> bool: - engine = self.get_sqla_engine() - return engine.has_table(table.table_name, table.schema or None) + with self.get_sqla_engine_with_context() as engine: + return engine.has_table(table.table_name, table.schema or None) def has_table_by_name(self, table_name: str, schema: Optional[str] = None) -> bool: - engine = self.get_sqla_engine() - return engine.has_table(table_name, schema) + with self.get_sqla_engine_with_context() as engine: + return engine.has_table(table_name, schema) @classmethod def _has_view( @@ -799,7 +892,7 @@ def _has_view( return view_name in view_names def has_view(self, view_name: str, schema: Optional[str] = None) -> bool: - engine = self.get_sqla_engine() + engine = self._get_sqla_engine() return engine.run_callable(self._has_view, engine.dialect, view_name, schema) def has_view_by_name(self, view_name: str, schema: Optional[str] = None) -> bool: @@ -811,8 +904,9 @@ def get_dialect(self) -> Dialect: return sqla_url.get_dialect()() -sqla.event.listen(Database, "after_insert", security_manager.set_perm) -sqla.event.listen(Database, "after_update", security_manager.set_perm) +sqla.event.listen(Database, "after_insert", security_manager.database_after_insert) +sqla.event.listen(Database, "after_update", security_manager.database_after_update) +sqla.event.listen(Database, "after_delete", security_manager.database_after_delete) class Log(Model): # pylint: disable=too-few-public-methods @@ -848,9 +942,3 @@ class FavStar(Model): # pylint: disable=too-few-public-methods class_name = Column(String(50)) obj_id = Column(Integer) dttm = Column(DateTime, default=datetime.utcnow) - - -# events for updating tags -if is_feature_enabled("TAGGING_SYSTEM"): - sqla.event.listen(FavStar, "after_insert", FavStarUpdater.after_insert) - sqla.event.listen(FavStar, "after_delete", FavStarUpdater.after_delete) diff --git a/superset/models/dashboard.py b/superset/models/dashboard.py index f2d53e1ff5e6a..0e0bf56f585d6 100644 --- a/superset/models/dashboard.py +++ b/superset/models/dashboard.py @@ -20,10 +20,9 @@ import logging from collections import defaultdict from functools import partial -from typing import Any, Callable, Dict, List, Set, Tuple, Type, Union +from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union import sqlalchemy as sqla -from flask import g from flask_appbuilder import Model from flask_appbuilder.models.decorators import renders from flask_appbuilder.security.sqla.models import User @@ -46,21 +45,21 @@ from sqlalchemy.sql import join, select from sqlalchemy.sql.elements import BinaryExpression -from superset import app, ConnectorRegistry, db, is_feature_enabled, security_manager -from superset.common.request_contexed_based import is_user_admin +from superset import app, db, is_feature_enabled, security_manager from superset.connectors.base.models import BaseDatasource -from superset.connectors.sqla.models import SqlMetric, TableColumn +from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn +from superset.datasource.dao import DatasourceDAO from superset.extensions import cache_manager from superset.models.filter_set import FilterSet from superset.models.helpers import AuditMixinNullable, ImportExportMixin from superset.models.slice import Slice -from superset.models.tags import DashboardUpdater from superset.models.user_attributes import UserAttribute from superset.tasks.thumbnails import cache_dashboard_thumbnail +from superset.tasks.utils import get_current_user +from superset.thumbnails.digest import get_dashboard_digest from superset.utils import core as utils +from superset.utils.core import get_user_id from superset.utils.decorators import debounce -from superset.utils.hashing import md5_sha_from_str -from superset.utils.urls import get_url_path metadata = Model.metadata # pylint: disable=no-member config = app.config @@ -178,6 +177,11 @@ def __repr__(self) -> str: def url(self) -> str: return f"/superset/dashboard/{self.slug or self.id}/" + @staticmethod + def get_url(id_: int, slug: Optional[str] = None) -> str: + # To be able to generate URL's without instanciating a Dashboard object + return f"/superset/dashboard/{slug or id_}/" + @property def datasources(self) -> Set[BaseDatasource]: # Verbose but efficient database enumeration of dashboard datasources. @@ -202,15 +206,14 @@ def filter_sets(self) -> Dict[int, FilterSet]: @property def filter_sets_lst(self) -> Dict[int, FilterSet]: - if is_user_admin(): + if security_manager.is_admin(): return self._filter_sets - current_user = g.user.id filter_sets_by_owner_type: Dict[str, List[Any]] = {"Dashboard": [], "User": []} for fs in self._filter_sets: filter_sets_by_owner_type[fs.owner_type].append(fs) user_filter_sets = list( filter( - lambda filter_set: filter_set.owner_id == current_user, + lambda filter_set: filter_set.owner_id == get_user_id(), filter_sets_by_owner_type["User"], ) ) @@ -226,8 +229,9 @@ def charts(self) -> List[str]: @property def sqla_metadata(self) -> None: # pylint: disable=no-member - meta = MetaData(bind=self.get_sqla_engine()) - meta.reflect() + with self.get_sqla_engine_with_context() as engine: + meta = MetaData(bind=engine) + meta.reflect() @property def status(self) -> utils.DashboardStatus: @@ -242,11 +246,7 @@ def dashboard_link(self) -> Markup: @property def digest(self) -> str: - """ - Returns a MD5 HEX digest that makes this dashboard unique - """ - unique_string = f"{self.position_json}.{self.css}.{self.json_metadata}" - return md5_sha_from_str(unique_string) + return get_dashboard_digest(self) @property def thumbnail_url(self) -> str: @@ -330,8 +330,11 @@ def position(self) -> Dict[str, Any]: return {} def update_thumbnail(self) -> None: - url = get_url_path("Superset.dashboard", dashboard_id_or_slug=self.id) - cache_dashboard_thumbnail.delay(url, self.digest, force=True) + cache_dashboard_thumbnail.delay( + current_user=get_current_user(), + dashboard_id=self.id, + force=True, + ) @debounce(0.1) def clear_cache(self) -> None: @@ -407,27 +410,24 @@ def export_dashboards( # pylint: disable=too-many-locals id_ = target.get("datasetId") if id_ is None: continue - datasource = ConnectorRegistry.get_datasource_by_id(session, id_) + datasource = DatasourceDAO.get_datasource( + session, utils.DatasourceType.TABLE, id_ + ) datasource_ids.add((datasource.id, datasource.type)) copied_dashboard.alter_params(remote_id=dashboard_id) copied_dashboards.append(copied_dashboard) eager_datasources = [] - for datasource_id, datasource_type in datasource_ids: - eager_datasource = ConnectorRegistry.get_eager_datasource( - db.session, datasource_type, datasource_id + for datasource_id, _ in datasource_ids: + eager_datasource = SqlaTable.get_eager_sqlatable_datasource( + db.session, datasource_id ) copied_datasource = eager_datasource.copy() copied_datasource.alter_params( remote_id=eager_datasource.id, database_name=eager_datasource.database.name, ) - datasource_class = copied_datasource.__class__ - for field_name in datasource_class.export_children: - field_val = getattr(eager_datasource, field_name).copy() - # set children without creating ORM relations - copied_datasource.__dict__[field_name] = field_val eager_datasources.append(copied_datasource) return json.dumps( @@ -437,18 +437,14 @@ def export_dashboards( # pylint: disable=too-many-locals ) @classmethod - def get(cls, id_or_slug: str) -> Dashboard: - session = db.session() - qry = session.query(Dashboard).filter(id_or_slug_filter(id_or_slug)) + def get(cls, id_or_slug: Union[str, int]) -> Dashboard: + qry = db.session.query(Dashboard).filter(id_or_slug_filter(id_or_slug)) return qry.one_or_none() - def is_actor_owner(self) -> bool: - if g.user is None or g.user.is_anonymous or not g.user.is_authenticated: - return False - return g.user.id in set(map(lambda user: user.id, self.owners)) - -def id_or_slug_filter(id_or_slug: str) -> BinaryExpression: +def id_or_slug_filter(id_or_slug: Union[int, str]) -> BinaryExpression: + if isinstance(id_or_slug, int): + return Dashboard.id == id_or_slug if id_or_slug.isdigit(): return Dashboard.id == int(id_or_slug) return Dashboard.slug == id_or_slug @@ -456,12 +452,6 @@ def id_or_slug_filter(id_or_slug: str) -> BinaryExpression: OnDashboardChange = Callable[[Mapper, Connection, Dashboard], Any] -# events for updating tags -if is_feature_enabled("TAGGING_SYSTEM"): - sqla.event.listen(Dashboard, "after_insert", DashboardUpdater.after_insert) - sqla.event.listen(Dashboard, "after_update", DashboardUpdater.after_update) - sqla.event.listen(Dashboard, "after_delete", DashboardUpdater.after_delete) - if is_feature_enabled("THUMBNAILS_SQLA_LISTENERS"): update_thumbnail: OnDashboardChange = lambda _, __, dash: dash.update_thumbnail() sqla.event.listen(Dashboard, "after_insert", update_thumbnail) diff --git a/superset/models/datasource_access_request.py b/superset/models/datasource_access_request.py index fa3b9d67113d3..60bfe08238284 100644 --- a/superset/models/datasource_access_request.py +++ b/superset/models/datasource_access_request.py @@ -21,7 +21,6 @@ from sqlalchemy import Column, Integer, String from superset import app, db, security_manager -from superset.connectors.connector_registry import ConnectorRegistry from superset.models.helpers import AuditMixinNullable from superset.utils.memoized import memoized @@ -44,7 +43,10 @@ class DatasourceAccessRequest(Model, AuditMixinNullable): @property def cls_model(self) -> Type["BaseDatasource"]: - return ConnectorRegistry.sources[self.datasource_type] + # pylint: disable=import-outside-toplevel + from superset.datasource.dao import DatasourceDAO + + return DatasourceDAO.sources[self.datasource_type] @property def username(self) -> Markup: diff --git a/superset/models/filter_set.py b/superset/models/filter_set.py index 2d3b218793dcf..4bbef264900d6 100644 --- a/superset/models/filter_set.py +++ b/superset/models/filter_set.py @@ -55,8 +55,9 @@ def url(self) -> str: @property def sqla_metadata(self) -> None: # pylint: disable=no-member - meta = MetaData(bind=self.get_sqla_engine()) - meta.reflect() + with self.get_sqla_engine_with_context() as engine: + meta = MetaData(bind=engine) + meta.reflect() @property def changed_by_name(self) -> str: diff --git a/superset/models/helpers.py b/superset/models/helpers.py index 3b4e99159f0b8..15b7a420a079e 100644 --- a/superset/models/helpers.py +++ b/superset/models/helpers.py @@ -15,34 +15,124 @@ # specific language governing permissions and limitations # under the License. """a collection of model-related helper classes and functions""" +# pylint: disable=too-many-lines import json import logging import re import uuid from datetime import datetime, timedelta from json.decoder import JSONDecodeError -from typing import Any, Dict, List, Optional, Set, Union - +from typing import ( + Any, + cast, + Dict, + List, + Mapping, + NamedTuple, + Optional, + Set, + Text, + Tuple, + Type, + TYPE_CHECKING, + Union, +) + +import dateutil.parser import humanize +import numpy as np import pandas as pd import pytz import sqlalchemy as sa +import sqlparse import yaml from flask import escape, g, Markup from flask_appbuilder import Model from flask_appbuilder.models.decorators import renders from flask_appbuilder.models.mixins import AuditMixin from flask_appbuilder.security.sqla.models import User -from sqlalchemy import and_, or_, UniqueConstraint +from flask_babel import lazy_gettext as _ +from jinja2.exceptions import TemplateError +from sqlalchemy import and_, Column, or_, UniqueConstraint from sqlalchemy.ext.declarative import declared_attr -from sqlalchemy.orm import Mapper, Session +from sqlalchemy.orm import Mapper, Session, validates from sqlalchemy.orm.exc import MultipleResultsFound +from sqlalchemy.sql.elements import ColumnElement, literal_column, TextClause +from sqlalchemy.sql.expression import Label, Select, TextAsFrom +from sqlalchemy.sql.selectable import Alias, TableClause from sqlalchemy_utils import UUIDType +from superset import app, is_feature_enabled, security_manager +from superset.advanced_data_type.types import AdvancedDataTypeResponse from superset.common.db_query_status import QueryStatus - +from superset.common.utils.time_range_utils import get_since_until_from_time_range +from superset.constants import EMPTY_STRING, NULL_STRING +from superset.db_engine_specs.base import TimestampExpression +from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.exceptions import ( + AdvancedDataTypeResponseError, + QueryClauseValidationException, + QueryObjectValidationError, + SupersetSecurityException, +) +from superset.extensions import feature_flag_manager +from superset.jinja_context import BaseTemplateProcessor +from superset.sql_parse import has_table_query, insert_rls, ParsedQuery, sanitize_clause +from superset.superset_typing import ( + AdhocMetric, + FilterValue, + FilterValues, + Metric, + OrderBy, + QueryObjectDict, +) +from superset.utils import core as utils +from superset.utils.core import get_user_id + +if TYPE_CHECKING: + from superset.connectors.sqla.models import SqlMetric, TableColumn + from superset.db_engine_specs import BaseEngineSpec + from superset.models.core import Database + + +config = app.config logger = logging.getLogger(__name__) +VIRTUAL_TABLE_ALIAS = "virtual_table" +ADVANCED_DATA_TYPES = config["ADVANCED_DATA_TYPES"] + + +def validate_adhoc_subquery( + sql: str, + database_id: int, + default_schema: str, +) -> str: + """ + Check if adhoc SQL contains sub-queries or nested sub-queries with table. + + If sub-queries are allowed, the adhoc SQL is modified to insert any applicable RLS + predicates to it. + + :param sql: adhoc sql expression + :raise SupersetSecurityException if sql contains sub-queries or + nested sub-queries with table + """ + statements = [] + for statement in sqlparse.parse(sql): + if has_table_query(statement): + if not is_feature_enabled("ALLOW_ADHOC_SUBQUERY"): + raise SupersetSecurityException( + SupersetError( + error_type=SupersetErrorType.ADHOC_SUBQUERY_NOT_ALLOWED_ERROR, + message=_("Custom SQL fields cannot contain sub-queries."), + level=ErrorLevel.ERROR, + ) + ) + statement = insert_rls(statement, database_id, default_schema) + statements.append(statement) + + return ";\n".join(str(statement) for statement in statements) + def json_to_dict(json_str: str) -> Dict[Any, Any]: if json_str: @@ -236,7 +326,10 @@ def import_from_dict( # Recursively create children if recursive: for child in cls.export_children: - child_class = cls.__mapper__.relationships[child].argument.class_ + argument = cls.__mapper__.relationships[child].argument + child_class = ( + argument.class_ if hasattr(argument, "class_") else argument + ) added = [] for c_obj in new_children.get(child, []): added.append( @@ -384,7 +477,7 @@ def created_by_fk(self) -> sa.Column: return sa.Column( sa.Integer, sa.ForeignKey("ab_user.id"), - default=self.get_user_id, + default=get_user_id, nullable=True, ) @@ -393,8 +486,8 @@ def changed_by_fk(self) -> sa.Column: return sa.Column( sa.Integer, sa.ForeignKey("ab_user.id"), - default=self.get_user_id, - onupdate=self.get_user_id, + default=get_user_id, + onupdate=get_user_id, nullable=True, ) @@ -477,14 +570,15 @@ class ExtraJSONMixin: @property def extra(self) -> Dict[str, Any]: try: - return json.loads(self.extra_json) if self.extra_json else {} + return json.loads(self.extra_json or "{}") or {} except (TypeError, JSONDecodeError) as exc: logger.error( "Unable to load an extra json: %r. Leaving empty.", exc, exc_info=True ) return {} - def set_extra_json(self, extras: Dict[str, Any]) -> None: + @extra.setter + def extra(self, extras: Dict[str, Any]) -> None: self.extra_json = json.dumps(extras) def set_extra_json_key(self, key: str, value: Any) -> None: @@ -492,6 +586,16 @@ def set_extra_json_key(self, key: str, value: Any) -> None: extra[key] = value self.extra_json = json.dumps(extra) + @validates("extra_json") + def ensure_extra_json_is_not_none( # pylint: disable=no-self-use + self, + _: str, + value: Optional[Dict[str, Any]], + ) -> Any: + if value is None: + return "{}" + return value + class CertificationMixin: """Mixin to add extra certification fields""" @@ -543,3 +647,1318 @@ def clone_model( data.update(kwargs) return target.__class__(**data) + + +# todo(hugh): centralize where this code lives +class QueryStringExtended(NamedTuple): + applied_template_filters: Optional[List[str]] + labels_expected: List[str] + prequeries: List[str] + sql: str + + +class SqlaQuery(NamedTuple): + applied_template_filters: List[str] + cte: Optional[str] + extra_cache_keys: List[Any] + labels_expected: List[str] + prequeries: List[str] + sqla_query: Select + + +class ExploreMixin: # pylint: disable=too-many-public-methods + """ + Allows any flask_appbuilder.Model (Query, Table, etc.) + to be used to power a chart inside /explore + """ + + sqla_aggregations = { + "COUNT_DISTINCT": lambda column_name: sa.func.COUNT(sa.distinct(column_name)), + "COUNT": sa.func.COUNT, + "SUM": sa.func.SUM, + "AVG": sa.func.AVG, + "MIN": sa.func.MIN, + "MAX": sa.func.MAX, + } + + @property + def query(self) -> str: + raise NotImplementedError() + + @property + def database_id(self) -> int: + raise NotImplementedError() + + @property + def owners_data(self) -> List[Any]: + raise NotImplementedError() + + @property + def metrics(self) -> List[Any]: + raise NotImplementedError() + + @property + def uid(self) -> str: + raise NotImplementedError() + + @property + def is_rls_supported(self) -> bool: + raise NotImplementedError() + + @property + def cache_timeout(self) -> int: + raise NotImplementedError() + + @property + def column_names(self) -> List[str]: + raise NotImplementedError() + + @property + def offset(self) -> int: + raise NotImplementedError() + + @property + def main_dttm_col(self) -> Optional[str]: + raise NotImplementedError() + + @property + def dttm_cols(self) -> List[str]: + raise NotImplementedError() + + @property + def db_engine_spec(self) -> Type["BaseEngineSpec"]: + raise NotImplementedError() + + @property + def database(self) -> Type["Database"]: + raise NotImplementedError() + + @property + def schema(self) -> str: + raise NotImplementedError() + + @property + def sql(self) -> str: + raise NotImplementedError() + + @property + def columns(self) -> List[Any]: + raise NotImplementedError() + + @property + def get_fetch_values_predicate(self) -> List[Any]: + raise NotImplementedError() + + @staticmethod + def get_extra_cache_keys(query_obj: Dict[str, Any]) -> List[str]: + raise NotImplementedError() + + def get_template_processor(self, **kwargs: Any) -> BaseTemplateProcessor: + raise NotImplementedError() + + def _process_sql_expression( # pylint: disable=no-self-use + self, + expression: Optional[str], + database_id: int, + schema: str, + template_processor: Optional[BaseTemplateProcessor], + ) -> Optional[str]: + if template_processor and expression: + expression = template_processor.process_template(expression) + if expression: + expression = validate_adhoc_subquery( + expression, + database_id, + schema, + ) + try: + expression = sanitize_clause(expression) + except QueryClauseValidationException as ex: + raise QueryObjectValidationError(ex.message) from ex + return expression + + def make_sqla_column_compatible( + self, sqla_col: ColumnElement, label: Optional[str] = None + ) -> ColumnElement: + """Takes a sqlalchemy column object and adds label info if supported by engine. + :param sqla_col: sqlalchemy column instance + :param label: alias/label that column is expected to have + :return: either a sql alchemy column or label instance if supported by engine + """ + label_expected = label or sqla_col.name + db_engine_spec = self.db_engine_spec + # add quotes to tables + if db_engine_spec.allows_alias_in_select: + label = db_engine_spec.make_label_compatible(label_expected) + sqla_col = sqla_col.label(label) + sqla_col.key = label_expected + return sqla_col + + def mutate_query_from_config(self, sql: str) -> str: + """Apply config's SQL_QUERY_MUTATOR + + Typically adds comments to the query with context""" + sql_query_mutator = config["SQL_QUERY_MUTATOR"] + if sql_query_mutator: + sql = sql_query_mutator( + sql, + user_name=utils.get_username(), # TODO(john-bodley): Deprecate in 3.0. + security_manager=security_manager, + database=self.database, + ) + return sql + + @staticmethod + def _apply_cte(sql: str, cte: Optional[str]) -> str: + """ + Append a CTE before the SELECT statement if defined + + :param sql: SELECT statement + :param cte: CTE statement + :return: + """ + if cte: + sql = f"{cte}\n{sql}" + return sql + + @staticmethod + def validate_adhoc_subquery( + sql: str, + database_id: int, + default_schema: str, + ) -> str: + """ + Check if adhoc SQL contains sub-queries or nested sub-queries with table. + + If sub-queries are allowed, the adhoc SQL is modified to insert any applicable RLS + predicates to it. + + :param sql: adhoc sql expression + :raise SupersetSecurityException if sql contains sub-queries or + nested sub-queries with table + """ + + statements = [] + for statement in sqlparse.parse(sql): + if has_table_query(statement): + if not is_feature_enabled("ALLOW_ADHOC_SUBQUERY"): + raise SupersetSecurityException( + SupersetError( + error_type=SupersetErrorType.ADHOC_SUBQUERY_NOT_ALLOWED_ERROR, + message=_("Custom SQL fields cannot contain sub-queries."), + level=ErrorLevel.ERROR, + ) + ) + statement = insert_rls(statement, database_id, default_schema) + statements.append(statement) + + return ";\n".join(str(statement) for statement in statements) + + def get_query_str_extended(self, query_obj: QueryObjectDict) -> QueryStringExtended: + sqlaq = self.get_sqla_query(**query_obj) + sql = self.database.compile_sqla_query(sqlaq.sqla_query) # type: ignore + sql = self._apply_cte(sql, sqlaq.cte) + sql = sqlparse.format(sql, reindent=True) + sql = self.mutate_query_from_config(sql) + return QueryStringExtended( + applied_template_filters=sqlaq.applied_template_filters, + labels_expected=sqlaq.labels_expected, + prequeries=sqlaq.prequeries, + sql=sql, + ) + + def _normalize_prequery_result_type( + self, + row: pd.Series, + dimension: str, + columns_by_name: Dict[str, "TableColumn"], + ) -> Union[str, int, float, bool, Text]: + """ + Convert a prequery result type to its equivalent Python type. + + Some databases like Druid will return timestamps as strings, but do not perform + automatic casting when comparing these strings to a timestamp. For cases like + this we convert the value via the appropriate SQL transform. + + :param row: A prequery record + :param dimension: The dimension name + :param columns_by_name: The mapping of columns by name + :return: equivalent primitive python type + """ + + value = row[dimension] + + if isinstance(value, np.generic): + value = value.item() + + column_ = columns_by_name[dimension] + db_extra: Dict[str, Any] = self.database.get_extra() # type: ignore + + if isinstance(column_, dict): + if ( + column_.get("type") + and column_.get("is_temporal") + and isinstance(value, str) + ): + sql = self.db_engine_spec.convert_dttm( + column_.get("type"), dateutil.parser.parse(value), db_extra=None + ) + + if sql: + value = self.db_engine_spec.get_text_clause(sql) + else: + if column_.type and column_.is_temporal and isinstance(value, str): + sql = self.db_engine_spec.convert_dttm( + column_.type, dateutil.parser.parse(value), db_extra=db_extra + ) + + if sql: + value = self.text(sql) + return value + + def make_orderby_compatible( + self, select_exprs: List[ColumnElement], orderby_exprs: List[ColumnElement] + ) -> None: + """ + If needed, make sure aliases for selected columns are not used in + `ORDER BY`. + + In some databases (e.g. Presto), `ORDER BY` clause is not able to + automatically pick the source column if a `SELECT` clause alias is named + the same as a source column. In this case, we update the SELECT alias to + another name to avoid the conflict. + """ + if self.db_engine_spec.allows_alias_to_source_column: + return + + def is_alias_used_in_orderby(col: ColumnElement) -> bool: + if not isinstance(col, Label): + return False + regexp = re.compile(f"\\(.*\\b{re.escape(col.name)}\\b.*\\)", re.IGNORECASE) + return any(regexp.search(str(x)) for x in orderby_exprs) + + # Iterate through selected columns, if column alias appears in orderby + # use another `alias`. The final output columns will still use the + # original names, because they are updated by `labels_expected` after + # querying. + for col in select_exprs: + if is_alias_used_in_orderby(col): + col.name = f"{col.name}__" + + def exc_query(self, qry: Any) -> QueryResult: + qry_start_dttm = datetime.now() + query_str_ext = self.get_query_str_extended(qry) + sql = query_str_ext.sql + status = QueryStatus.SUCCESS + errors = None + error_message = None + + def assign_column_label(df: pd.DataFrame) -> Optional[pd.DataFrame]: + """ + Some engines change the case or generate bespoke column names, either by + default or due to lack of support for aliasing. This function ensures that + the column names in the DataFrame correspond to what is expected by + the viz components. + Sometimes a query may also contain only order by columns that are not used + as metrics or groupby columns, but need to present in the SQL `select`, + filtering by `labels_expected` make sure we only return columns users want. + :param df: Original DataFrame returned by the engine + :return: Mutated DataFrame + """ + labels_expected = query_str_ext.labels_expected + if df is not None and not df.empty: + if len(df.columns) < len(labels_expected): + raise QueryObjectValidationError( + _("Db engine did not return all queried columns") + ) + if len(df.columns) > len(labels_expected): + df = df.iloc[:, 0 : len(labels_expected)] + df.columns = labels_expected + return df + + try: + df = self.database.get_df( + sql, self.schema, mutator=assign_column_label # type: ignore + ) + except Exception as ex: # pylint: disable=broad-except + df = pd.DataFrame() + status = QueryStatus.FAILED + logger.warning( + "Query %s on schema %s failed", sql, self.schema, exc_info=True + ) + error_message = utils.error_msg_from_exception(ex) + + return QueryResult( + status=status, + df=df, + duration=datetime.now() - qry_start_dttm, + query=sql, + errors=errors, + error_message=error_message, + ) + + def get_rendered_sql( + self, template_processor: Optional[BaseTemplateProcessor] = None + ) -> str: + """ + Render sql with template engine (Jinja). + """ + + sql = self.sql + if template_processor: + try: + sql = template_processor.process_template(sql) + except TemplateError as ex: + raise QueryObjectValidationError( + _( + "Error while rendering virtual dataset query: %(msg)s", + msg=ex.message, + ) + ) from ex + sql = sqlparse.format(sql.strip("\t\r\n; "), strip_comments=True) + if not sql: + raise QueryObjectValidationError(_("Virtual dataset query cannot be empty")) + if len(sqlparse.split(sql)) > 1: + raise QueryObjectValidationError( + _("Virtual dataset query cannot consist of multiple statements") + ) + return sql + + def text(self, clause: str) -> TextClause: + return self.db_engine_spec.get_text_clause(clause) + + def get_from_clause( + self, template_processor: Optional[BaseTemplateProcessor] = None + ) -> Tuple[Union[TableClause, Alias], Optional[str]]: + """ + Return where to select the columns and metrics from. Either a physical table + or a virtual table with it's own subquery. If the FROM is referencing a + CTE, the CTE is returned as the second value in the return tuple. + """ + + from_sql = self.get_rendered_sql(template_processor) + parsed_query = ParsedQuery(from_sql) + if not ( + parsed_query.is_unknown() + or self.db_engine_spec.is_readonly_query(parsed_query) + ): + raise QueryObjectValidationError( + _("Virtual dataset query must be read-only") + ) + + cte = self.db_engine_spec.get_cte_query(from_sql) + from_clause = ( + sa.table(self.db_engine_spec.cte_alias) + if cte + else TextAsFrom(self.text(from_sql), []).alias(VIRTUAL_TABLE_ALIAS) + ) + + return from_clause, cte + + def adhoc_metric_to_sqla( + self, + metric: AdhocMetric, + columns_by_name: Dict[str, "TableColumn"], # # pylint: disable=unused-argument + template_processor: Optional[BaseTemplateProcessor] = None, + ) -> ColumnElement: + """ + Turn an adhoc metric into a sqlalchemy column. + + :param dict metric: Adhoc metric definition + :param dict columns_by_name: Columns for the current table + :param template_processor: template_processor instance + :returns: The metric defined as a sqlalchemy column + :rtype: sqlalchemy.sql.column + """ + expression_type = metric.get("expressionType") + label = utils.get_metric_name(metric) + + if expression_type == utils.AdhocMetricExpressionType.SIMPLE: + metric_column = metric.get("column") or {} + column_name = cast(str, metric_column.get("column_name")) + sqla_column = sa.column(column_name) + sqla_metric = self.sqla_aggregations[metric["aggregate"]](sqla_column) + elif expression_type == utils.AdhocMetricExpressionType.SQL: + expression = self._process_sql_expression( + expression=metric["sqlExpression"], + database_id=self.database_id, + schema=self.schema, + template_processor=template_processor, + ) + sqla_metric = literal_column(expression) + else: + raise QueryObjectValidationError("Adhoc metric expressionType is invalid") + + return self.make_sqla_column_compatible(sqla_metric, label) + + @property + def template_params_dict(self) -> Dict[Any, Any]: + return {} + + @staticmethod + def filter_values_handler( # pylint: disable=too-many-arguments + values: Optional[FilterValues], + operator: str, + target_generic_type: utils.GenericDataType, + target_native_type: Optional[str] = None, + is_list_target: bool = False, + db_engine_spec: Optional[ + Type["BaseEngineSpec"] + ] = None, # fix(hughhh): Optional[Type[BaseEngineSpec]] + db_extra: Optional[Dict[str, Any]] = None, + ) -> Optional[FilterValues]: + if values is None: + return None + + def handle_single_value(value: Optional[FilterValue]) -> Optional[FilterValue]: + if operator == utils.FilterOperator.TEMPORAL_RANGE: + return value + if ( + isinstance(value, (float, int)) + and target_generic_type == utils.GenericDataType.TEMPORAL + and target_native_type is not None + and db_engine_spec is not None + ): + value = db_engine_spec.convert_dttm( + target_type=target_native_type, + dttm=datetime.utcfromtimestamp(value / 1000), + db_extra=db_extra, + ) + value = literal_column(value) + if isinstance(value, str): + value = value.strip("\t\n") + + if target_generic_type == utils.GenericDataType.NUMERIC: + # For backwards compatibility and edge cases + # where a column data type might have changed + return utils.cast_to_num(value) + if value == NULL_STRING: + return None + if value == EMPTY_STRING: + return "" + if target_generic_type == utils.GenericDataType.BOOLEAN: + return utils.cast_to_boolean(value) + return value + + if isinstance(values, (list, tuple)): + values = [handle_single_value(v) for v in values] # type: ignore + else: + values = handle_single_value(values) + if is_list_target and not isinstance(values, (tuple, list)): + values = [values] # type: ignore + elif not is_list_target and isinstance(values, (tuple, list)): + values = values[0] if values else None + return values + + def get_query_str(self, query_obj: QueryObjectDict) -> str: + query_str_ext = self.get_query_str_extended(query_obj) + all_queries = query_str_ext.prequeries + [query_str_ext.sql] + return ";\n\n".join(all_queries) + ";" + + def _get_series_orderby( + self, + series_limit_metric: Metric, + metrics_by_name: Mapping[str, "SqlMetric"], + columns_by_name: Mapping[str, "TableColumn"], + ) -> Column: + if utils.is_adhoc_metric(series_limit_metric): + assert isinstance(series_limit_metric, dict) + ob = self.adhoc_metric_to_sqla( + series_limit_metric, columns_by_name # type: ignore + ) + elif ( + isinstance(series_limit_metric, str) + and series_limit_metric in metrics_by_name + ): + ob = metrics_by_name[series_limit_metric].get_sqla_col() + else: + raise QueryObjectValidationError( + _("Metric '%(metric)s' does not exist", metric=series_limit_metric) + ) + return ob + + def adhoc_column_to_sqla( + self, + col: Type["AdhocColumn"], # type: ignore + template_processor: Optional[BaseTemplateProcessor] = None, + ) -> ColumnElement: + """ + Turn an adhoc column into a sqlalchemy column. + + :param col: Adhoc column definition + :param template_processor: template_processor instance + :returns: The metric defined as a sqlalchemy column + :rtype: sqlalchemy.sql.column + """ + label = utils.get_column_name(col) # type: ignore + expression = self._process_sql_expression( + expression=col["sqlExpression"], + database_id=self.database_id, + schema=self.schema, + template_processor=template_processor, + ) + sqla_column = literal_column(expression) + return self.make_sqla_column_compatible(sqla_column, label) + + def _get_top_groups( + self, + df: pd.DataFrame, + dimensions: List[str], + groupby_exprs: Dict[str, Any], + columns_by_name: Dict[str, "TableColumn"], + ) -> ColumnElement: + groups = [] + for _unused, row in df.iterrows(): + group = [] + for dimension in dimensions: + value = self._normalize_prequery_result_type( + row, + dimension, + columns_by_name, + ) + + group.append(groupby_exprs[dimension] == value) + groups.append(and_(*group)) + + return or_(*groups) + + def dttm_sql_literal(self, dttm: sa.DateTime, col_type: Optional[str]) -> str: + """Convert datetime object to a SQL expression string""" + + sql = ( + self.db_engine_spec.convert_dttm(col_type, dttm, db_extra=None) + if col_type + else None + ) + + if sql: + return sql + + return f'{dttm.strftime("%Y-%m-%d %H:%M:%S.%f")}' + + def get_time_filter( + self, + time_col: Dict[str, Any], + start_dttm: Optional[sa.DateTime], + end_dttm: Optional[sa.DateTime], + ) -> ColumnElement: + label = "__time" + col = time_col.get("column_name") + sqla_col = literal_column(col) + my_col = self.make_sqla_column_compatible(sqla_col, label) + l = [] + if start_dttm: + l.append( + my_col + >= self.db_engine_spec.get_text_clause( + self.dttm_sql_literal(start_dttm, time_col.get("type")) + ) + ) + if end_dttm: + l.append( + my_col + < self.db_engine_spec.get_text_clause( + self.dttm_sql_literal(end_dttm, time_col.get("type")) + ) + ) + return and_(*l) + + def values_for_column(self, column_name: str, limit: int = 10000) -> List[Any]: + """Runs query against sqla to retrieve some + sample values for the given column. + """ + cols = {} + for col in self.columns: + if isinstance(col, dict): + cols[col.get("column_name")] = col + else: + cols[col.column_name] = col + + target_col = cols[column_name] + tp = None # todo(hughhhh): add back self.get_template_processor() + tbl, cte = self.get_from_clause(tp) + + if isinstance(target_col, dict): + sql_column = sa.column(target_col.get("name")) + else: + sql_column = target_col + + qry = sa.select([sql_column]).select_from(tbl).distinct() + if limit: + qry = qry.limit(limit) + + with self.database.get_sqla_engine_with_context() as engine: # type: ignore + sql = qry.compile(engine, compile_kwargs={"literal_binds": True}) + sql = self._apply_cte(sql, cte) + sql = self.mutate_query_from_config(sql) + + df = pd.read_sql_query(sql=sql, con=engine) + return df[column_name].to_list() + + def get_timestamp_expression( + self, + column: Dict[str, Any], + time_grain: Optional[str], + label: Optional[str] = None, + template_processor: Optional[BaseTemplateProcessor] = None, + ) -> Union[TimestampExpression, Label]: + """ + Return a SQLAlchemy Core element representation of self to be used in a query. + + :param time_grain: Optional time grain, e.g. P1Y + :param label: alias/label that column is expected to have + :param template_processor: template processor + :return: A TimeExpression object wrapped in a Label if supported by db + """ + label = label or utils.DTTM_ALIAS + column_spec = self.db_engine_spec.get_column_spec(column.get("type")) + type_ = column_spec.sqla_type if column_spec else sa.DateTime + col = sa.column(column.get("column_name"), type_=type_) + + if template_processor: + expression = template_processor.process_template(column["column_name"]) + col = sa.literal_column(expression, type_=type_) + + time_expr = self.db_engine_spec.get_timestamp_expr(col, None, time_grain) + return self.make_sqla_column_compatible(time_expr, label) + + def get_sqla_col(self, col: Dict[str, Any]) -> Column: + label = col.get("column_name") + col_type = col.get("type") + col = sa.column(label, type_=col_type) + return self.make_sqla_column_compatible(col, label) + + def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements + self, + apply_fetch_values_predicate: bool = False, + columns: Optional[List[Column]] = None, + extras: Optional[Dict[str, Any]] = None, + filter: Optional[ # pylint: disable=redefined-builtin + List[utils.QueryObjectFilterClause] + ] = None, + from_dttm: Optional[datetime] = None, + granularity: Optional[str] = None, + groupby: Optional[List[Column]] = None, + inner_from_dttm: Optional[datetime] = None, + inner_to_dttm: Optional[datetime] = None, + is_rowcount: bool = False, + is_timeseries: bool = True, + metrics: Optional[List[Metric]] = None, + orderby: Optional[List[OrderBy]] = None, + order_desc: bool = True, + to_dttm: Optional[datetime] = None, + series_columns: Optional[List[Column]] = None, + series_limit: Optional[int] = None, + series_limit_metric: Optional[Metric] = None, + row_limit: Optional[int] = None, + row_offset: Optional[int] = None, + timeseries_limit: Optional[int] = None, + timeseries_limit_metric: Optional[Metric] = None, + time_shift: Optional[str] = None, + ) -> SqlaQuery: + """Querying any sqla table from this common interface""" + if granularity not in self.dttm_cols and granularity is not None: + granularity = self.main_dttm_col + + extras = extras or {} + time_grain = extras.get("time_grain_sqla") + + template_kwargs = { + "columns": columns, + "from_dttm": from_dttm.isoformat() if from_dttm else None, + "groupby": groupby, + "metrics": metrics, + "row_limit": row_limit, + "row_offset": row_offset, + "time_column": granularity, + "time_grain": time_grain, + "to_dttm": to_dttm.isoformat() if to_dttm else None, + "table_columns": [col.get("column_name") for col in self.columns], + "filter": filter, + } + columns = columns or [] + groupby = groupby or [] + series_column_names = utils.get_column_names(series_columns or []) + # deprecated, to be removed in 2.0 + if is_timeseries and timeseries_limit: + series_limit = timeseries_limit + series_limit_metric = series_limit_metric or timeseries_limit_metric + template_kwargs.update(self.template_params_dict) + extra_cache_keys: List[Any] = [] + template_kwargs["extra_cache_keys"] = extra_cache_keys + removed_filters: List[str] = [] + applied_template_filters: List[str] = [] + template_kwargs["removed_filters"] = removed_filters + template_kwargs["applied_filters"] = applied_template_filters + template_processor = self.get_template_processor(**template_kwargs) + db_engine_spec = self.db_engine_spec + prequeries: List[str] = [] + orderby = orderby or [] + need_groupby = bool(metrics is not None or groupby) + metrics = metrics or [] + + # For backward compatibility + if granularity not in self.dttm_cols and granularity is not None: + granularity = self.main_dttm_col + + columns_by_name: Dict[str, "TableColumn"] = { + col.get("column_name"): col + for col in self.columns # col.column_name: col for col in self.columns + } + + if not granularity and is_timeseries: + raise QueryObjectValidationError( + _( + "Datetime column not provided as part table configuration " + "and is required by this type of chart" + ) + ) + if not metrics and not columns and not groupby: + raise QueryObjectValidationError(_("Empty query?")) + + metrics_exprs: List[ColumnElement] = [] + for metric in metrics: + if utils.is_adhoc_metric(metric): + assert isinstance(metric, dict) + metrics_exprs.append( + self.adhoc_metric_to_sqla( + metric=metric, + columns_by_name=columns_by_name, + template_processor=template_processor, + ) + ) + else: + raise QueryObjectValidationError( + _("Metric '%(metric)s' does not exist", metric=metric) + ) + + if metrics_exprs: + main_metric_expr = metrics_exprs[0] + else: + main_metric_expr, label = literal_column("COUNT(*)"), "ccount" + main_metric_expr = self.make_sqla_column_compatible(main_metric_expr, label) + + # To ensure correct handling of the ORDER BY labeling we need to reference the + # metric instance if defined in the SELECT clause. + # use the key of the ColumnClause for the expected label + metrics_exprs_by_label = {m.key: m for m in metrics_exprs} + metrics_exprs_by_expr = {str(m): m for m in metrics_exprs} + + # Since orderby may use adhoc metrics, too; we need to process them first + orderby_exprs: List[ColumnElement] = [] + for orig_col, ascending in orderby: + col: Union[AdhocMetric, ColumnElement] = orig_col + if isinstance(col, dict): + col = cast(AdhocMetric, col) + if col.get("sqlExpression"): + col["sqlExpression"] = self._process_sql_expression( + expression=col["sqlExpression"], + database_id=self.database_id, + schema=self.schema, + template_processor=template_processor, + ) + if utils.is_adhoc_metric(col): + # add adhoc sort by column to columns_by_name if not exists + col = self.adhoc_metric_to_sqla(col, columns_by_name) + # if the adhoc metric has been defined before + # use the existing instance. + col = metrics_exprs_by_expr.get(str(col), col) + need_groupby = True + elif col in columns_by_name: + gb_column_obj = columns_by_name[col] + if isinstance(gb_column_obj, dict): + col = self.get_sqla_col(gb_column_obj) + else: + col = gb_column_obj.get_sqla_col() + elif col in metrics_exprs_by_label: + col = metrics_exprs_by_label[col] + need_groupby = True + + if isinstance(col, ColumnElement): + orderby_exprs.append(col) + else: + # Could not convert a column reference to valid ColumnElement + raise QueryObjectValidationError( + _("Unknown column used in orderby: %(col)s", col=orig_col) + ) + + select_exprs: List[Union[Column, Label]] = [] + groupby_all_columns = {} + groupby_series_columns = {} + + # filter out the pseudo column __timestamp from columns + columns = [col for col in columns if col != utils.DTTM_ALIAS] + dttm_col = columns_by_name.get(granularity) if granularity else None + + if need_groupby: + # dedup columns while preserving order + columns = groupby or columns + for selected in columns: + if isinstance(selected, str): + # if groupby field/expr equals granularity field/expr + if selected == granularity: + table_col = columns_by_name[selected] + if isinstance(table_col, dict): + outer = self.get_timestamp_expression( + column=table_col, + time_grain=time_grain, + label=selected, + template_processor=template_processor, + ) + else: + outer = table_col.get_timestamp_expression( + time_grain=time_grain, + label=selected, + template_processor=template_processor, + ) + # if groupby field equals a selected column + elif selected in columns_by_name: + if isinstance(columns_by_name[selected], dict): + outer = sa.column(f"{selected}") + outer = self.make_sqla_column_compatible(outer, selected) + else: + outer = columns_by_name[selected].get_sqla_col() + else: + selected = self.validate_adhoc_subquery( + selected, + self.database_id, + self.schema, + ) + outer = sa.column(f"{selected}") + outer = self.make_sqla_column_compatible(outer, selected) + else: + outer = self.adhoc_column_to_sqla( + col=selected, template_processor=template_processor + ) + groupby_all_columns[outer.name] = outer + if ( + is_timeseries and not series_column_names + ) or outer.name in series_column_names: + groupby_series_columns[outer.name] = outer + select_exprs.append(outer) + elif columns: + for selected in columns: + selected = self.validate_adhoc_subquery( + selected, + self.database_id, + self.schema, + ) + if isinstance(columns_by_name[selected], dict): + select_exprs.append(sa.column(f"{selected}")) + else: + select_exprs.append( + columns_by_name[selected].get_sqla_col() + if selected in columns_by_name + else self.make_sqla_column_compatible(literal_column(selected)) + ) + metrics_exprs = [] + + if granularity: + if granularity not in columns_by_name or not dttm_col: + raise QueryObjectValidationError( + _( + 'Time column "%(col)s" does not exist in dataset', + col=granularity, + ) + ) + time_filters: List[Any] = [] + + if is_timeseries: + if isinstance(dttm_col, dict): + timestamp = self.get_timestamp_expression( + dttm_col, time_grain, template_processor=template_processor + ) + else: + timestamp = dttm_col.get_timestamp_expression( + time_grain=time_grain, template_processor=template_processor + ) + # always put timestamp as the first column + select_exprs.insert(0, timestamp) + groupby_all_columns[timestamp.name] = timestamp + + # Use main dttm column to support index with secondary dttm columns. + if db_engine_spec.time_secondary_columns: + if isinstance(dttm_col, dict): + dttm_col_name = dttm_col.get("column_name") + else: + dttm_col_name = dttm_col.column_name + + if ( + self.main_dttm_col in self.dttm_cols + and self.main_dttm_col != dttm_col_name + ): + if isinstance(self.main_dttm_col, dict): + time_filters.append( + self.get_time_filter( + self.main_dttm_col, + from_dttm, + to_dttm, + ) + ) + else: + time_filters.append( + columns_by_name[self.main_dttm_col].get_time_filter( + from_dttm, + to_dttm, + ) + ) + + if isinstance(dttm_col, dict): + time_filters.append(self.get_time_filter(dttm_col, from_dttm, to_dttm)) + else: + time_filters.append(dttm_col.get_time_filter(from_dttm, to_dttm)) + + # Always remove duplicates by column name, as sometimes `metrics_exprs` + # can have the same name as a groupby column (e.g. when users use + # raw columns as custom SQL adhoc metric). + select_exprs = utils.remove_duplicates( + select_exprs + metrics_exprs, key=lambda x: x.name + ) + + # Expected output columns + labels_expected = [c.key for c in select_exprs] + + # Order by columns are "hidden" columns, some databases require them + # always be present in SELECT if an aggregation function is used + if not db_engine_spec.allows_hidden_ordeby_agg: + select_exprs = utils.remove_duplicates(select_exprs + orderby_exprs) + + qry = sa.select(select_exprs) + + tbl, cte = self.get_from_clause(template_processor) + + if groupby_all_columns: + qry = qry.group_by(*groupby_all_columns.values()) + + where_clause_and = [] + having_clause_and = [] + + for flt in filter: # type: ignore + if not all(flt.get(s) for s in ["col", "op"]): + continue + flt_col = flt["col"] + val = flt.get("val") + op = flt["op"].upper() + col_obj: Optional["TableColumn"] = None + sqla_col: Optional[Column] = None + if flt_col == utils.DTTM_ALIAS and is_timeseries and dttm_col: + col_obj = dttm_col + elif utils.is_adhoc_column(flt_col): + sqla_col = self.adhoc_column_to_sqla(flt_col) # type: ignore + else: + col_obj = columns_by_name.get(flt_col) + filter_grain = flt.get("grain") + + if is_feature_enabled("ENABLE_TEMPLATE_REMOVE_FILTERS"): + if utils.get_column_name(flt_col) in removed_filters: + # Skip generating SQLA filter when the jinja template handles it. + continue + + if col_obj or sqla_col is not None: + if sqla_col is not None: + pass + elif col_obj and filter_grain: + if isinstance(col_obj, dict): + sqla_col = self.get_timestamp_expression( + col_obj, time_grain, template_processor=template_processor + ) + else: + sqla_col = col_obj.get_timestamp_expression( + time_grain=filter_grain, + template_processor=template_processor, + ) + elif col_obj and isinstance(col_obj, dict): + sqla_col = sa.column(col_obj.get("column_name")) + elif col_obj: + sqla_col = col_obj.get_sqla_col() + + if col_obj and isinstance(col_obj, dict): + col_type = col_obj.get("type") + else: + col_type = col_obj.type if col_obj else None + col_spec = db_engine_spec.get_column_spec( + native_type=col_type, + db_extra=self.database.get_extra(), # type: ignore + ) + is_list_target = op in ( + utils.FilterOperator.IN.value, + utils.FilterOperator.NOT_IN.value, + ) + + if col_obj and isinstance(col_obj, dict): + col_advanced_data_type = "" + else: + col_advanced_data_type = ( + col_obj.advanced_data_type if col_obj else "" + ) + + if col_spec and not col_advanced_data_type: + target_generic_type = col_spec.generic_type + else: + target_generic_type = utils.GenericDataType.STRING + eq = self.filter_values_handler( + values=val, + operator=op, + target_generic_type=target_generic_type, + target_native_type=col_type, + is_list_target=is_list_target, + db_engine_spec=db_engine_spec, + db_extra=self.database.get_extra(), # type: ignore + ) + if ( + col_advanced_data_type != "" + and feature_flag_manager.is_feature_enabled( + "ENABLE_ADVANCED_DATA_TYPES" + ) + and col_advanced_data_type in ADVANCED_DATA_TYPES + ): + values = eq if is_list_target else [eq] # type: ignore + bus_resp: AdvancedDataTypeResponse = ADVANCED_DATA_TYPES[ + col_advanced_data_type + ].translate_type( + { + "type": col_advanced_data_type, + "values": values, + } + ) + if bus_resp["error_message"]: + raise AdvancedDataTypeResponseError( + _(bus_resp["error_message"]) + ) + + where_clause_and.append( + ADVANCED_DATA_TYPES[col_advanced_data_type].translate_filter( + sqla_col, op, bus_resp["values"] + ) + ) + elif is_list_target: + assert isinstance(eq, (tuple, list)) + if len(eq) == 0: + raise QueryObjectValidationError( + _("Filter value list cannot be empty") + ) + if len(eq) > len( + eq_without_none := [x for x in eq if x is not None] + ): + is_null_cond = sqla_col.is_(None) + if eq: + cond = or_(is_null_cond, sqla_col.in_(eq_without_none)) + else: + cond = is_null_cond + else: + cond = sqla_col.in_(eq) + if op == utils.FilterOperator.NOT_IN.value: + cond = ~cond + where_clause_and.append(cond) + elif op == utils.FilterOperator.IS_NULL.value: + where_clause_and.append(sqla_col.is_(None)) + elif op == utils.FilterOperator.IS_NOT_NULL.value: + where_clause_and.append(sqla_col.isnot(None)) + elif op == utils.FilterOperator.IS_TRUE.value: + where_clause_and.append(sqla_col.is_(True)) + elif op == utils.FilterOperator.IS_FALSE.value: + where_clause_and.append(sqla_col.is_(False)) + else: + if eq is None: + raise QueryObjectValidationError( + _( + "Must specify a value for filters " + "with comparison operators" + ) + ) + if op == utils.FilterOperator.EQUALS.value: + where_clause_and.append(sqla_col == eq) + elif op == utils.FilterOperator.NOT_EQUALS.value: + where_clause_and.append(sqla_col != eq) + elif op == utils.FilterOperator.GREATER_THAN.value: + where_clause_and.append(sqla_col > eq) + elif op == utils.FilterOperator.LESS_THAN.value: + where_clause_and.append(sqla_col < eq) + elif op == utils.FilterOperator.GREATER_THAN_OR_EQUALS.value: + where_clause_and.append(sqla_col >= eq) + elif op == utils.FilterOperator.LESS_THAN_OR_EQUALS.value: + where_clause_and.append(sqla_col <= eq) + elif op == utils.FilterOperator.LIKE.value: + where_clause_and.append(sqla_col.like(eq)) + elif op == utils.FilterOperator.ILIKE.value: + where_clause_and.append(sqla_col.ilike(eq)) + elif ( + op == utils.FilterOperator.TEMPORAL_RANGE.value + and isinstance(eq, str) + and col_obj is not None + ): + _since, _until = get_since_until_from_time_range( + time_range=eq, + time_shift=time_shift, + extras=extras, + ) + where_clause_and.append( + self.get_time_filter( + time_col=col_obj, + start_dttm=_since, + end_dttm=_until, + ) + ) + else: + raise QueryObjectValidationError( + _("Invalid filter operation type: %(op)s", op=op) + ) + # todo(hugh): fix this w/ template_processor + # where_clause_and += self.get_sqla_row_level_filters(template_processor) + if extras: + where = extras.get("where") + if where: + try: + where = template_processor.process_template(f"{where}") + except TemplateError as ex: + raise QueryObjectValidationError( + _( + "Error in jinja expression in WHERE clause: %(msg)s", + msg=ex.message, + ) + ) from ex + where_clause_and += [self.text(where)] + having = extras.get("having") + if having: + try: + having = template_processor.process_template(f"{having}") + except TemplateError as ex: + raise QueryObjectValidationError( + _( + "Error in jinja expression in HAVING clause: %(msg)s", + msg=ex.message, + ) + ) from ex + having_clause_and += [self.text(having)] + if apply_fetch_values_predicate and self.fetch_values_predicate: # type: ignore + qry = qry.where(self.get_fetch_values_predicate()) # type: ignore + if granularity: + qry = qry.where(and_(*(time_filters + where_clause_and))) + else: + qry = qry.where(and_(*where_clause_and)) + qry = qry.having(and_(*having_clause_and)) + + self.make_orderby_compatible(select_exprs, orderby_exprs) + + for col, (orig_col, ascending) in zip(orderby_exprs, orderby): + if not db_engine_spec.allows_alias_in_orderby and isinstance(col, Label): + # if engine does not allow using SELECT alias in ORDER BY + # revert to the underlying column + col = col.element + + if ( + db_engine_spec.allows_alias_in_select + and db_engine_spec.allows_hidden_cc_in_orderby + and col.name in [select_col.name for select_col in select_exprs] + ): + col = literal_column(col.name) + direction = sa.asc if ascending else sa.desc + qry = qry.order_by(direction(col)) + + if row_limit: + qry = qry.limit(row_limit) + if row_offset: + qry = qry.offset(row_offset) + + if series_limit and groupby_series_columns: + if db_engine_spec.allows_joins and db_engine_spec.allows_subqueries: + # some sql dialects require for order by expressions + # to also be in the select clause -- others, e.g. vertica, + # require a unique inner alias + inner_main_metric_expr = self.make_sqla_column_compatible( + main_metric_expr, "mme_inner__" + ) + inner_groupby_exprs = [] + inner_select_exprs = [] + for gby_name, gby_obj in groupby_series_columns.items(): + label = utils.get_column_name(gby_name) + inner = self.make_sqla_column_compatible(gby_obj, gby_name + "__") + inner_groupby_exprs.append(inner) + inner_select_exprs.append(inner) + + inner_select_exprs += [inner_main_metric_expr] + subq = sa.select(inner_select_exprs).select_from(tbl) + inner_time_filter = [] + + if dttm_col and not db_engine_spec.time_groupby_inline: + if isinstance(dttm_col, dict): + inner_time_filter = [ + self.get_time_filter( + dttm_col, + inner_from_dttm or from_dttm, + inner_to_dttm or to_dttm, + ) + ] + else: + inner_time_filter = [ + dttm_col.get_time_filter( + inner_from_dttm or from_dttm, + inner_to_dttm or to_dttm, + ) + ] + + subq = subq.where(and_(*(where_clause_and + inner_time_filter))) + subq = subq.group_by(*inner_groupby_exprs) + + ob = inner_main_metric_expr + direction = sa.desc if order_desc else sa.asc + subq = subq.order_by(direction(ob)) + subq = subq.limit(series_limit) + + on_clause = [] + for gby_name, gby_obj in groupby_series_columns.items(): + # in this case the column name, not the alias, needs to be + # conditionally mutated, as it refers to the column alias in + # the inner query + col_name = db_engine_spec.make_label_compatible(gby_name + "__") + on_clause.append(gby_obj == sa.column(col_name)) + + tbl = tbl.join(subq.alias(), and_(*on_clause)) + + # run prequery to get top groups + prequery_obj = { + "is_timeseries": False, + "row_limit": series_limit, + "metrics": metrics, + "granularity": granularity, + "groupby": groupby, + "from_dttm": inner_from_dttm or from_dttm, + "to_dttm": inner_to_dttm or to_dttm, + "filter": filter, + "orderby": orderby, + "extras": extras, + "columns": columns, + "order_desc": True, + } + result = self.exc_query(prequery_obj) + prequeries.append(result.query) + dimensions = [ + c + for c in result.df.columns + if c not in metrics and c in groupby_series_columns + ] + top_groups = self._get_top_groups( + result.df, dimensions, groupby_series_columns, columns_by_name + ) + qry = qry.where(top_groups) + + qry = qry.select_from(tbl) + + if is_rowcount: + if not db_engine_spec.allows_subqueries: + raise QueryObjectValidationError( + _("Database does not support subqueries") + ) + label = "rowcount" + col = self.make_sqla_column_compatible(literal_column("COUNT(*)"), label) + qry = sa.select([col]).select_from(qry.alias("rowcount_qry")) + labels_expected = [label] + + return SqlaQuery( + applied_template_filters=applied_template_filters, + cte=cte, + extra_cache_keys=extra_cache_keys, + labels_expected=labels_expected, + sqla_query=qry, + prequeries=prequeries, + ) diff --git a/superset/models/slice.py b/superset/models/slice.py index 862edb9ec8ce8..332d51d1af939 100644 --- a/superset/models/slice.py +++ b/superset/models/slice.py @@ -39,15 +39,14 @@ from sqlalchemy.orm import relationship from sqlalchemy.orm.mapper import Mapper -from superset import ConnectorRegistry, db, is_feature_enabled, security_manager +from superset import db, is_feature_enabled, security_manager from superset.legacy import update_time_range from superset.models.helpers import AuditMixinNullable, ImportExportMixin -from superset.models.tags import ChartUpdater from superset.tasks.thumbnails import cache_chart_thumbnail +from superset.tasks.utils import get_current_user +from superset.thumbnails.digest import get_chart_digest from superset.utils import core as utils -from superset.utils.hashing import md5_sha_from_str from superset.utils.memoized import memoized -from superset.utils.urls import get_url_path from superset.viz import BaseViz, viz_types if TYPE_CHECKING: @@ -111,6 +110,9 @@ class Slice( # pylint: disable=too-many-public-methods export_fields = [ "slice_name", + "description", + "certified_by", + "certification_details", "datasource_type", "datasource_name", "viz_type", @@ -126,7 +128,10 @@ def __repr__(self) -> str: @property def cls_model(self) -> Type["BaseDatasource"]: - return ConnectorRegistry.sources[self.datasource_type] + # pylint: disable=import-outside-toplevel + from superset.datasource.dao import DatasourceDAO + + return DatasourceDAO.sources[self.datasource_type] @property def datasource(self) -> Optional["BaseDatasource"]: @@ -232,10 +237,7 @@ def data(self) -> Dict[str, Any]: @property def digest(self) -> str: - """ - Returns a MD5 HEX digest that makes this dashboard unique - """ - return md5_sha_from_str(self.params or "") + return get_chart_digest(self) @property def thumbnail_url(self) -> str: @@ -283,14 +285,20 @@ def get_query_context(self) -> Optional[QueryContext]: def get_explore_url( self, - base_url: str = "/superset/explore", + base_url: str = "/explore", overrides: Optional[Dict[str, Any]] = None, + ) -> str: + return self.build_explore_url(self.id, base_url, overrides) + + @staticmethod + def build_explore_url( + id_: int, base_url: str = "/explore", overrides: Optional[Dict[str, Any]] = None ) -> str: overrides = overrides or {} - form_data = {"slice_id": self.id} + form_data = {"slice_id": id_} form_data.update(overrides) params = parse.quote(json.dumps(form_data)) - return f"{base_url}/?form_data={params}" + return f"{base_url}/?slice_id={id_}&form_data={params}" @property def slice_url(self) -> str: @@ -332,7 +340,7 @@ def icons(self) -> str: @property def url(self) -> str: - return f"/superset/explore/?form_data=%7B%22slice_id%22%3A%20{self.id}%7D" + return f"/explore/?slice_id={self.id}" def get_query_context_factory(self) -> QueryContextFactory: if self.query_context_factory is None: @@ -342,6 +350,11 @@ def get_query_context_factory(self) -> QueryContextFactory: self.query_context_factory = QueryContextFactory() return self.query_context_factory + @classmethod + def get(cls, id_: int) -> Slice: + qry = db.session.query(Slice).filter_by(id=id_) + return qry.one_or_none() + def set_related_perm(_mapper: Mapper, _connection: Connection, target: Slice) -> None: src_class = target.cls_model @@ -356,20 +369,16 @@ def set_related_perm(_mapper: Mapper, _connection: Connection, target: Slice) -> def event_after_chart_changed( _mapper: Mapper, _connection: Connection, target: Slice ) -> None: - url = get_url_path("Superset.slice", slice_id=target.id, standalone="true") - cache_chart_thumbnail.delay(url, target.digest, force=True) + cache_chart_thumbnail.delay( + current_user=get_current_user(), + chart_id=target.id, + force=True, + ) sqla.event.listen(Slice, "before_insert", set_related_perm) sqla.event.listen(Slice, "before_update", set_related_perm) -# events for updating tags -if is_feature_enabled("TAGGING_SYSTEM"): - sqla.event.listen(Slice, "after_insert", ChartUpdater.after_insert) - sqla.event.listen(Slice, "after_update", ChartUpdater.after_update) - sqla.event.listen(Slice, "after_delete", ChartUpdater.after_delete) - -# events for updating tags if is_feature_enabled("THUMBNAILS_SQLA_LISTENERS"): sqla.event.listen(Slice, "after_insert", event_after_chart_changed) sqla.event.listen(Slice, "after_update", event_after_chart_changed) diff --git a/superset/models/sql_lab.py b/superset/models/sql_lab.py index 74c43718ef781..23c13629b95ed 100644 --- a/superset/models/sql_lab.py +++ b/superset/models/sql_lab.py @@ -15,15 +15,18 @@ # specific language governing permissions and limitations # under the License. """A collection of ORM sqlalchemy models for SQL Lab""" +import inspect +import logging import re from datetime import datetime -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional, Type, TYPE_CHECKING import simplejson as json import sqlalchemy as sqla -from flask import Markup +from flask import current_app, Markup from flask_appbuilder import Model from flask_appbuilder.models.decorators import renders +from flask_babel import gettext as __ from humanize import naturaltime from sqlalchemy import ( Boolean, @@ -40,27 +43,37 @@ from sqlalchemy.orm import backref, relationship from superset import security_manager +from superset.jinja_context import BaseTemplateProcessor, get_template_processor from superset.models.helpers import ( AuditMixinNullable, + ExploreMixin, ExtraJSONMixin, ImportExportMixin, ) -from superset.models.tags import QueryUpdater from superset.sql_parse import CtasMethod, ParsedQuery, Table from superset.sqllab.limiting_factor import LimitingFactor -from superset.utils.core import QueryStatus, user_label +from superset.utils.core import GenericDataType, QueryStatus, user_label +if TYPE_CHECKING: + from superset.db_engine_specs import BaseEngineSpec -class Query(Model, ExtraJSONMixin): + +logger = logging.getLogger(__name__) + + +class Query( + Model, ExtraJSONMixin, ExploreMixin +): # pylint: disable=abstract-method,too-many-public-methods """ORM model for SQL query Now that SQL Lab support multi-statement execution, an entry in this table may represent multiple SQL statements executed sequentially""" __tablename__ = "query" + type = "query" id = Column(Integer, primary_key=True) client_id = Column(String(11), unique=True, nullable=False) - + query_language = "sql" database_id = Column(Integer, ForeignKey("dbs.id"), nullable=False) # Store the tmp table into the DB only if the user asks for it. @@ -98,7 +111,7 @@ class Query(Model, ExtraJSONMixin): start_running_time = Column(Numeric(precision=20, scale=6)) end_time = Column(Numeric(precision=20, scale=6)) end_result_backend_time = Column(Numeric(precision=20, scale=6)) - tracking_url = Column(Text) + tracking_url_raw = Column(Text, name="tracking_url") changed_on = Column( DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=True @@ -113,6 +126,9 @@ class Query(Model, ExtraJSONMixin): __table_args__ = (sqla.Index("ti_user_id_changed_on", user_id, changed_on),) + def get_template_processor(self, **kwargs: Any) -> BaseTemplateProcessor: + return get_template_processor(query=self, database=self.database, **kwargs) + def to_dict(self) -> Dict[str, Any]: return { "changedOn": self.changed_on, @@ -167,8 +183,70 @@ def sql_tables(self) -> List[Table]: return list(ParsedQuery(self.sql).tables) @property - def columns(self) -> List[Table]: - return self.extra.get("columns", []) + def columns(self) -> List[Dict[str, Any]]: + bool_types = ("BOOL",) + num_types = ( + "DOUBLE", + "FLOAT", + "INT", + "BIGINT", + "NUMBER", + "LONG", + "REAL", + "NUMERIC", + "DECIMAL", + "MONEY", + ) + date_types = ("DATE", "TIME") + str_types = ("VARCHAR", "STRING", "CHAR") + columns = [] + col_type = "" + for col in self.extra.get("columns", []): + computed_column = {**col} + col_type = col.get("type") + + if col_type and any(map(lambda t: t in col_type.upper(), str_types)): + computed_column["type_generic"] = GenericDataType.STRING + if col_type and any(map(lambda t: t in col_type.upper(), bool_types)): + computed_column["type_generic"] = GenericDataType.BOOLEAN + if col_type and any(map(lambda t: t in col_type.upper(), num_types)): + computed_column["type_generic"] = GenericDataType.NUMERIC + if col_type and any(map(lambda t: t in col_type.upper(), date_types)): + computed_column["type_generic"] = GenericDataType.TEMPORAL + + computed_column["column_name"] = col.get("name") + computed_column["groupby"] = True + columns.append(computed_column) + return columns + + @property + def data(self) -> Dict[str, Any]: + order_by_choices = [] + for col in self.columns: + column_name = str(col.get("column_name") or "") + order_by_choices.append( + (json.dumps([column_name, True]), f"{column_name} " + __("[asc]")) + ) + order_by_choices.append( + (json.dumps([column_name, False]), f"{column_name} " + __("[desc]")) + ) + + return { + "time_grain_sqla": [ + (g.duration, g.name) for g in self.database.grains() or [] + ], + "filter_select": True, + "name": self.tab_name, + "columns": self.columns, + "metrics": [], + "id": self.id, + "type": self.type, + "sql": self.sql, + "owners": self.owners_data, + "database": {"id": self.database_id, "backend": self.database.backend}, + "order_by_choices": order_by_choices, + "schema": self.schema, + } def raise_for_access(self) -> None: """ @@ -179,6 +257,90 @@ def raise_for_access(self) -> None: security_manager.raise_for_access(query=self) + @property + def db_engine_spec(self) -> Type["BaseEngineSpec"]: + return self.database.db_engine_spec + + @property + def owners_data(self) -> List[Dict[str, Any]]: + return [] + + @property + def uid(self) -> str: + return f"{self.id}__{self.type}" + + @property + def is_rls_supported(self) -> bool: + return False + + @property + def cache_timeout(self) -> int: + return 0 + + @property + def column_names(self) -> List[Any]: + return [col.get("column_name") for col in self.columns] + + @property + def offset(self) -> int: + return 0 + + @property + def main_dttm_col(self) -> Optional[str]: + for col in self.columns: + if col.get("is_dttm"): + return col.get("column_name") + return None + + @property + def dttm_cols(self) -> List[Any]: + return [col.get("column_name") for col in self.columns if col.get("is_dttm")] + + @property + def schema_perm(self) -> str: + return f"{self.database.database_name}.{self.schema}" + + @property + def perm(self) -> str: + return f"[{self.database.database_name}].[{self.tab_name}](id:{self.id})" + + @property + def default_endpoint(self) -> str: + return "" + + @staticmethod + def get_extra_cache_keys(query_obj: Dict[str, Any]) -> List[str]: + return [] + + @property + def tracking_url(self) -> Optional[str]: + """ + Transfrom tracking url at run time because the exact URL may depends + on query properties such as execution and finish time. + """ + transform = current_app.config.get("TRACKING_URL_TRANSFORMER") + url = self.tracking_url_raw + if url and transform: + sig = inspect.signature(transform) + # for backward compatibility, users may define a transformer function + # with only one parameter (`url`). + args = [url, self][: len(sig.parameters)] + url = transform(*args) + logger.debug("Transformed tracking url: %s", url) + return url + + @tracking_url.setter + def tracking_url(self, value: str) -> None: + self.tracking_url_raw = value + + def get_column(self, column_name: Optional[str]) -> Optional[Dict[str, Any]]: + if not column_name: + return None + for col in self.columns: + if col.get("column_name") == column_name: + return col + return None + class SavedQuery(Model, AuditMixinNullable, ExtraJSONMixin, ImportExportMixin): """ORM model for SQL query""" @@ -191,6 +353,7 @@ class SavedQuery(Model, AuditMixinNullable, ExtraJSONMixin, ImportExportMixin): label = Column(String(256)) description = Column(Text) sql = Column(Text) + template_parameters = Column(Text) user = relationship( security_manager.user_model, backref=backref("saved_queries", cascade="all, delete-orphan"), @@ -355,9 +518,3 @@ def to_dict(self) -> Dict[str, Any]: "description": description, "expanded": self.expanded, } - - -# events for updating tags -sqla.event.listen(SavedQuery, "after_insert", QueryUpdater.after_insert) -sqla.event.listen(SavedQuery, "after_update", QueryUpdater.after_update) -sqla.event.listen(SavedQuery, "after_delete", QueryUpdater.after_delete) diff --git a/superset/models/sql_types/presto_sql_types.py b/superset/models/sql_types/presto_sql_types.py index 5f36266ccaa4f..c496f750399c8 100644 --- a/superset/models/sql_types/presto_sql_types.py +++ b/superset/models/sql_types/presto_sql_types.py @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -# pylint: disable=abstract-method +# pylint: disable=abstract-method, no-init from typing import Any, Dict, List, Optional, Type from sqlalchemy.engine.interfaces import Dialect diff --git a/superset/proxy/api.py b/superset/proxy/api.py index 1defcf8ec8f5d..f0b321ba728fd 100644 --- a/superset/proxy/api.py +++ b/superset/proxy/api.py @@ -202,7 +202,6 @@ def get_ipstring(self, ip_string: str, **_kwargs: Any) -> Response: user_ip_string = user_ips[0] for index in range(1, len(user_ips)): user_ip_string += "%22%2C%20%22" + user_ips[index] - url = ( self.ALFRED_URL + "/rest/search/cypher?expression=MATCH%20(ip%3AIP_ADDRESS)%20WHERE%20ip.value%20IN%20%5B%22" diff --git a/superset/queries/api.py b/superset/queries/api.py index 460e2dd4667e0..1784edf167c80 100644 --- a/superset/queries/api.py +++ b/superset/queries/api.py @@ -15,16 +15,33 @@ # specific language governing permissions and limitations # under the License. import logging +from typing import Any +import backoff +from flask_appbuilder.api import expose, protect, request, rison, safe from flask_appbuilder.models.sqla.interface import SQLAInterface +from superset import db, event_logger from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod from superset.databases.filters import DatabaseFilter +from superset.exceptions import SupersetException from superset.models.sql_lab import Query +from superset.queries.dao import QueryDAO from superset.queries.filters import QueryFilter -from superset.queries.schemas import openapi_spec_methods_override, QuerySchema -from superset.views.base_api import BaseSupersetModelRestApi, RelatedFieldFilter -from superset.views.filters import FilterRelatedOwners +from superset.queries.schemas import ( + openapi_spec_methods_override, + queries_get_updated_since_schema, + QuerySchema, + StopQuerySchema, +) +from superset.superset_typing import FlaskResponse +from superset.views.base_api import ( + BaseSupersetModelRestApi, + RelatedFieldFilter, + requires_json, + statsd_metrics, +) +from superset.views.filters import BaseFilterRelatedUsers, FilterRelatedOwners logger = logging.getLogger(__name__) @@ -43,6 +60,12 @@ class QueryRestApi(BaseSupersetModelRestApi): RouteMethod.GET_LIST, RouteMethod.RELATED, RouteMethod.DISTINCT, + "stop_query", + "get_updated_since", + } + + apispec_parameter_schemas = { + "queries_get_updated_since_schema": queries_get_updated_since_schema, } list_columns = [ @@ -95,9 +118,11 @@ class QueryRestApi(BaseSupersetModelRestApi): base_filters = [["id", QueryFilter, lambda: []]] base_order = ("changed_on", "desc") list_model_schema = QuerySchema() + stop_query_schema = StopQuerySchema() openapi_spec_tag = "Queries" openapi_spec_methods = openapi_spec_methods_override + openapi_spec_component_schemas = (StopQuerySchema,) order_columns = [ "changed_on", @@ -109,7 +134,10 @@ class QueryRestApi(BaseSupersetModelRestApi): "tab_name", "user.first_name", ] - + base_related_field_filters = { + "created_by": [["id", BaseFilterRelatedUsers, lambda: []]], + "user": [["id", BaseFilterRelatedUsers, lambda: []]], + } related_field_filters = { "created_by": RelatedFieldFilter("first_name", FilterRelatedOwners), "user": RelatedFieldFilter("first_name", FilterRelatedOwners), @@ -117,6 +145,115 @@ class QueryRestApi(BaseSupersetModelRestApi): search_columns = ["changed_on", "database", "sql", "status", "user", "start_time"] - filter_rel_fields = {"database": [["id", DatabaseFilter, lambda: []]]} + base_related_field_filters = {"database": [["id", DatabaseFilter, lambda: []]]} allowed_rel_fields = {"database", "user"} allowed_distinct_fields = {"status"} + + @expose("/updated_since") + @protect() + @safe + @rison(queries_get_updated_since_schema) + @statsd_metrics + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" + f".get_updated_since", + log_to_statsd=False, + ) + def get_updated_since(self, **kwargs: Any) -> FlaskResponse: + """Get a list of queries that changed after last_updated_ms + --- + get: + summary: Get a list of queries that changed after last_updated_ms + parameters: + - in: query + name: q + content: + application/json: + schema: + $ref: '#/components/schemas/queries_get_updated_since_schema' + responses: + 200: + description: Queries list + content: + application/json: + schema: + type: object + properties: + result: + description: >- + A List of queries that changed after last_updated_ms + type: array + items: + $ref: '#/components/schemas/{{self.__class__.__name__}}.get' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 404: + $ref: '#/components/responses/404' + 500: + $ref: '#/components/responses/500' + """ + try: + last_updated_ms = kwargs["rison"].get("last_updated_ms", 0) + queries = QueryDAO.get_queries_changed_after(last_updated_ms) + payload = [q.to_dict() for q in queries] + return self.response(200, result=payload) + except SupersetException as ex: + return self.response(ex.status, message=ex.message) + + @expose("/stop", methods=["POST"]) + @protect() + @safe + @statsd_metrics + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" + f".stop_query", + log_to_statsd=False, + ) + @backoff.on_exception( + backoff.constant, + Exception, + interval=1, + on_backoff=lambda details: db.session.rollback(), + on_giveup=lambda details: db.session.rollback(), + max_tries=5, + ) + @requires_json + def stop_query(self) -> FlaskResponse: + """Manually stop a query with client_id + --- + post: + summary: Manually stop a query with client_id + requestBody: + description: Stop query schema + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/StopQuerySchema' + responses: + 200: + description: Query stopped + content: + application/json: + schema: + type: object + properties: + result: + type: string + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 404: + $ref: '#/components/responses/404' + 500: + $ref: '#/components/responses/500' + """ + try: + body = self.stop_query_schema.load(request.json) + QueryDAO.stop_query(body["client_id"]) + return self.response(200, result="OK") + except SupersetException as ex: + return self.response(ex.status, message=ex.message) diff --git a/superset/queries/dao.py b/superset/queries/dao.py index c7d59343e8587..642a5dd4cbb1c 100644 --- a/superset/queries/dao.py +++ b/superset/queries/dao.py @@ -16,12 +16,17 @@ # under the License. import logging from datetime import datetime -from typing import Any, Dict +from typing import Any, Dict, List, Union +from superset import sql_lab +from superset.common.db_query_status import QueryStatus from superset.dao.base import BaseDAO +from superset.exceptions import QueryNotFoundException, SupersetCancelQueryException from superset.extensions import db from superset.models.sql_lab import Query, SavedQuery from superset.queries.filters import QueryFilter +from superset.utils.core import get_user_id +from superset.utils.dates import now_as_float logger = logging.getLogger(__name__) @@ -56,3 +61,37 @@ def save_metadata(query: Query, payload: Dict[str, Any]) -> None: columns = payload.get("columns", {}) db.session.add(query) query.set_extra_json_key("columns", columns) + + @staticmethod + def get_queries_changed_after(last_updated_ms: Union[float, int]) -> List[Query]: + # UTC date time, same that is stored in the DB. + last_updated_dt = datetime.utcfromtimestamp(last_updated_ms / 1000) + + return ( + db.session.query(Query) + .filter(Query.user_id == get_user_id(), Query.changed_on >= last_updated_dt) + .all() + ) + + @staticmethod + def stop_query(client_id: str) -> None: + query = db.session.query(Query).filter_by(client_id=client_id).one_or_none() + if not query: + raise QueryNotFoundException(f"Query with client_id {client_id} not found") + + if query.status in [ + QueryStatus.FAILED, + QueryStatus.SUCCESS, + QueryStatus.TIMED_OUT, + ]: + logger.warning( + "Query with client_id could not be stopped: query already complete", + ) + return + + if not sql_lab.cancel_query(query): + raise SupersetCancelQueryException("Could not cancel query") + + query.status = QueryStatus.STOPPED + query.end_time = now_as_float() + db.session.commit() diff --git a/superset/queries/filters.py b/superset/queries/filters.py index 22cf45f323bf0..1890e38c2a5ed 100644 --- a/superset/queries/filters.py +++ b/superset/queries/filters.py @@ -16,11 +16,11 @@ # under the License. from typing import Any -from flask import g from flask_sqlalchemy import BaseQuery from superset import security_manager from superset.models.sql_lab import Query +from superset.utils.core import get_user_id from superset.views.base import BaseFilter @@ -33,5 +33,5 @@ def apply(self, query: BaseQuery, value: Any) -> BaseQuery: :returns: query """ if not security_manager.can_access_all_queries(): - query = query.filter(Query.user_id == g.user.get_user_id()) + query = query.filter(Query.user_id == get_user_id()) return query diff --git a/superset/queries/saved_queries/api.py b/superset/queries/saved_queries/api.py index 19d4191f257b7..2b70b582bb5f4 100644 --- a/superset/queries/saved_queries/api.py +++ b/superset/queries/saved_queries/api.py @@ -84,6 +84,7 @@ class SavedQueryRestApi(BaseSupersetModelRestApi): base_filters = [["id", SavedQueryFilter, lambda: []]] show_columns = [ + "changed_on_delta_humanized", "created_by.first_name", "created_by.id", "created_by.last_name", @@ -95,6 +96,7 @@ class SavedQueryRestApi(BaseSupersetModelRestApi): "schema", "sql", "sql_tables", + "template_parameters", ] list_columns = [ "changed_on_delta_humanized", @@ -115,7 +117,14 @@ class SavedQueryRestApi(BaseSupersetModelRestApi): "last_run_delta_humanized", "extra", ] - add_columns = ["db_id", "description", "label", "schema", "sql"] + add_columns = [ + "db_id", + "description", + "label", + "schema", + "sql", + "template_parameters", + ] edit_columns = add_columns order_columns = [ "schema", @@ -146,7 +155,7 @@ class SavedQueryRestApi(BaseSupersetModelRestApi): related_field_filters = { "database": "database_name", } - filter_rel_fields = {"database": [["id", DatabaseFilter, lambda: []]]} + base_related_field_filters = {"database": [["id", DatabaseFilter, lambda: []]]} allowed_rel_fields = {"database"} allowed_distinct_fields = {"schema"} @@ -195,7 +204,7 @@ def bulk_delete(self, **kwargs: Any) -> Response: """ item_ids = kwargs["rison"] try: - BulkDeleteSavedQueryCommand(g.user, item_ids).run() + BulkDeleteSavedQueryCommand(item_ids).run() return self.response( 200, message=ngettext( diff --git a/superset/queries/saved_queries/commands/bulk_delete.py b/superset/queries/saved_queries/commands/bulk_delete.py index 0d199378c7585..c96afd31e58a6 100644 --- a/superset/queries/saved_queries/commands/bulk_delete.py +++ b/superset/queries/saved_queries/commands/bulk_delete.py @@ -17,8 +17,6 @@ import logging from typing import List, Optional -from flask_appbuilder.security.sqla.models import User - from superset.commands.base import BaseCommand from superset.dao.exceptions import DAODeleteFailedError from superset.models.dashboard import Dashboard @@ -32,8 +30,7 @@ class BulkDeleteSavedQueryCommand(BaseCommand): - def __init__(self, user: User, model_ids: List[int]): - self._actor = user + def __init__(self, model_ids: List[int]): self._model_ids = model_ids self._models: Optional[List[Dashboard]] = None diff --git a/superset/queries/saved_queries/dao.py b/superset/queries/saved_queries/dao.py index 48dc67d069db8..c6bcfa035ccea 100644 --- a/superset/queries/saved_queries/dao.py +++ b/superset/queries/saved_queries/dao.py @@ -42,6 +42,5 @@ def bulk_delete(models: Optional[List[SavedQuery]], commit: bool = True) -> None if commit: db.session.commit() except SQLAlchemyError as ex: - if commit: - db.session.rollback() + db.session.rollback() raise DAODeleteFailedError() from ex diff --git a/superset/queries/schemas.py b/superset/queries/schemas.py index f11cf37127756..c29c1c03b6b69 100644 --- a/superset/queries/schemas.py +++ b/superset/queries/schemas.py @@ -33,6 +33,14 @@ }, } +queries_get_updated_since_schema = { + "type": "object", + "properties": { + "last_updated_ms": {"type": "number"}, + }, + "required": ["last_updated_ms"], +} + class DatabaseSchema(Schema): database_name = fields.String() @@ -67,3 +75,11 @@ class Meta: # pylint: disable=too-few-public-methods # pylint: disable=no-self-use def get_sql_tables(self, obj: Query) -> List[Table]: return obj.sql_tables + + +class StopQuerySchema(Schema): + """ + Schema for the stop_query API call. + """ + + client_id = fields.String() diff --git a/superset/reports/api.py b/superset/reports/api.py index 046fe90595ea8..d483576417315 100644 --- a/superset/reports/api.py +++ b/superset/reports/api.py @@ -17,7 +17,7 @@ import logging from typing import Any, Optional -from flask import g, request, Response +from flask import request, Response from flask_appbuilder.api import expose, permission_name, protect, rison, safe from flask_appbuilder.hooks import before_request from flask_appbuilder.models.sqla.interface import SQLAInterface @@ -30,7 +30,6 @@ from superset.dashboards.filters import DashboardAccessFilter from superset.databases.filters import DatabaseFilter from superset.extensions import event_logger -from superset.models.reports import ReportSchedule from superset.reports.commands.bulk_delete import BulkDeleteReportScheduleCommand from superset.reports.commands.create import CreateReportScheduleCommand from superset.reports.commands.delete import DeleteReportScheduleCommand @@ -44,7 +43,8 @@ ReportScheduleUpdateFailedError, ) from superset.reports.commands.update import UpdateReportScheduleCommand -from superset.reports.filters import ReportScheduleAllTextFilter +from superset.reports.filters import ReportScheduleAllTextFilter, ReportScheduleFilter +from superset.reports.models import ReportSchedule from superset.reports.schemas import ( get_delete_ids_schema, openapi_spec_methods_override, @@ -57,7 +57,7 @@ requires_json, statsd_metrics, ) -from superset.views.filters import FilterRelatedOwners +from superset.views.filters import BaseFilterRelatedUsers, FilterRelatedOwners logger = logging.getLogger(__name__) @@ -80,6 +80,10 @@ def ensure_alert_reports_enabled(self) -> Optional[Response]: resource_name = "report" allow_browser_login = True + base_filters = [ + ["id", ReportScheduleFilter, lambda: []], + ] + show_columns = [ "id", "active", @@ -94,6 +98,7 @@ def ensure_alert_reports_enabled(self) -> Optional[Response]: "database.database_name", "database.id", "description", + "extra", "force_screenshot", "grace_period", "last_eval_dttm", @@ -135,6 +140,7 @@ def ensure_alert_reports_enabled(self) -> Optional[Response]: "crontab_humanized", "dashboard_id", "description", + "extra", "id", "last_eval_dttm", "last_state", @@ -156,6 +162,7 @@ def ensure_alert_reports_enabled(self) -> Optional[Response]: "dashboard", "database", "description", + "extra", "force_screenshot", "grace_period", "log_retention", @@ -201,10 +208,13 @@ def ensure_alert_reports_enabled(self) -> Optional[Response]: ] search_filters = {"name": [ReportScheduleAllTextFilter]} allowed_rel_fields = {"owners", "chart", "dashboard", "database", "created_by"} - filter_rel_fields = { + + base_related_field_filters = { "chart": [["id", ChartFilter, lambda: []]], "dashboard": [["id", DashboardAccessFilter, lambda: []]], "database": [["id", DatabaseFilter, lambda: []]], + "owners": [["id", BaseFilterRelatedUsers, lambda: []]], + "created_by": [["id", BaseFilterRelatedUsers, lambda: []]], } text_field_rel_fields = { "dashboard": "dashboard_title", @@ -266,7 +276,7 @@ def delete(self, pk: int) -> Response: $ref: '#/components/responses/500' """ try: - DeleteReportScheduleCommand(g.user, pk).run() + DeleteReportScheduleCommand(pk).run() return self.response(200, message="OK") except ReportScheduleNotFoundError: return self.response_404() @@ -340,7 +350,7 @@ def post( except ValidationError as error: return self.response_400(message=error.messages) try: - new_model = CreateReportScheduleCommand(g.user, item).run() + new_model = CreateReportScheduleCommand(item).run() return self.response(201, id=new_model.id, result=item) except ReportScheduleNotFoundError as ex: return self.response_400(message=str(ex)) @@ -421,7 +431,7 @@ def put(self, pk: int) -> Response: except ValidationError as error: return self.response_400(message=error.messages) try: - new_model = UpdateReportScheduleCommand(g.user, pk, item).run() + new_model = UpdateReportScheduleCommand(pk, item).run() return self.response(200, id=new_model.id, result=item) except ReportScheduleNotFoundError: return self.response_404() @@ -483,7 +493,7 @@ def bulk_delete(self, **kwargs: Any) -> Response: """ item_ids = kwargs["rison"] try: - BulkDeleteReportScheduleCommand(g.user, item_ids).run() + BulkDeleteReportScheduleCommand(item_ids).run() return self.response( 200, message=ngettext( diff --git a/superset/reports/commands/alert.py b/superset/reports/commands/alert.py index 6382826aad54d..c5b4709447fa1 100644 --- a/superset/reports/commands/alert.py +++ b/superset/reports/commands/alert.py @@ -14,11 +14,13 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from __future__ import annotations + import json import logging from operator import eq, ge, gt, le, lt, ne from timeit import default_timer -from typing import Optional +from typing import Any, Optional import numpy as np import pandas as pd @@ -27,7 +29,6 @@ from superset import app, jinja_context, security_manager from superset.commands.base import BaseCommand -from superset.models.reports import ReportSchedule, ReportScheduleValidatorType from superset.reports.commands.exceptions import ( AlertQueryError, AlertQueryInvalidTypeError, @@ -36,6 +37,8 @@ AlertQueryTimeout, AlertValidatorConfigError, ) +from superset.reports.models import ReportSchedule, ReportScheduleValidatorType +from superset.tasks.utils import get_executor from superset.utils.core import override_user from superset.utils.retries import retry_call @@ -83,12 +86,12 @@ def run(self) -> bool: except (KeyError, json.JSONDecodeError) as ex: raise AlertValidatorConfigError() from ex - def _validate_not_null(self, rows: np.recarray) -> None: + def _validate_not_null(self, rows: np.recarray[Any, Any]) -> None: self._validate_result(rows) self._result = rows[0][1] @staticmethod - def _validate_result(rows: np.recarray) -> None: + def _validate_result(rows: np.recarray[Any, Any]) -> None: # check if query return more than one row if len(rows) > 1: raise AlertQueryMultipleRowsError( @@ -107,7 +110,7 @@ def _validate_result(rows: np.recarray) -> None: ) ) - def _validate_operator(self, rows: np.recarray) -> None: + def _validate_operator(self, rows: np.recarray[Any, Any]) -> None: self._validate_result(rows) if rows[0][1] in (0, None, np.nan): self._result = 0.0 @@ -148,11 +151,12 @@ def _execute_query(self) -> pd.DataFrame: rendered_sql, ALERT_SQL_LIMIT ) - with override_user( - security_manager.find_user( - username=app.config["THUMBNAIL_SELENIUM_USER"] - ) - ): + _, username = get_executor( + executor_types=app.config["ALERT_REPORTS_EXECUTE_AS"], + model=self._report_schedule, + ) + user = security_manager.find_user(username) + with override_user(user): start = default_timer() df = self._report_schedule.database.get_df(sql=limited_rendered_sql) stop = default_timer() diff --git a/superset/reports/commands/base.py b/superset/reports/commands/base.py index ee2eba7139ed0..81ad17d42e630 100644 --- a/superset/reports/commands/base.py +++ b/superset/reports/commands/base.py @@ -22,14 +22,15 @@ from superset.charts.dao import ChartDAO from superset.commands.base import BaseCommand from superset.dashboards.dao import DashboardDAO -from superset.models.reports import ReportCreationMethod from superset.reports.commands.exceptions import ( ChartNotFoundValidationError, ChartNotSavedValidationError, DashboardNotFoundValidationError, DashboardNotSavedValidationError, - ReportScheduleChartOrDashboardValidationError, + ReportScheduleEitherChartOrDashboardError, + ReportScheduleOnlyChartOrDashboardError, ) +from superset.reports.models import ReportCreationMethod logger = logging.getLogger(__name__) @@ -62,7 +63,8 @@ def validate_chart_dashboard( return if chart_id and dashboard_id: - exceptions.append(ReportScheduleChartOrDashboardValidationError()) + exceptions.append(ReportScheduleOnlyChartOrDashboardError()) + if chart_id: chart = ChartDAO.find_by_id(chart_id) if not chart: @@ -74,4 +76,4 @@ def validate_chart_dashboard( exceptions.append(DashboardNotFoundValidationError()) self._properties["dashboard"] = dashboard elif not update: - exceptions.append(ReportScheduleChartOrDashboardValidationError()) + exceptions.append(ReportScheduleEitherChartOrDashboardError()) diff --git a/superset/reports/commands/bulk_delete.py b/superset/reports/commands/bulk_delete.py index 4bff600d29dfa..28a39a2fb6ea2 100644 --- a/superset/reports/commands/bulk_delete.py +++ b/superset/reports/commands/bulk_delete.py @@ -17,26 +17,23 @@ import logging from typing import List, Optional -from flask_appbuilder.security.sqla.models import User - +from superset import security_manager from superset.commands.base import BaseCommand from superset.dao.exceptions import DAODeleteFailedError from superset.exceptions import SupersetSecurityException -from superset.models.reports import ReportSchedule from superset.reports.commands.exceptions import ( ReportScheduleBulkDeleteFailedError, ReportScheduleForbiddenError, ReportScheduleNotFoundError, ) from superset.reports.dao import ReportScheduleDAO -from superset.views.base import check_ownership +from superset.reports.models import ReportSchedule logger = logging.getLogger(__name__) class BulkDeleteReportScheduleCommand(BaseCommand): - def __init__(self, user: User, model_ids: List[int]): - self._actor = user + def __init__(self, model_ids: List[int]): self._model_ids = model_ids self._models: Optional[List[ReportSchedule]] = None @@ -58,6 +55,6 @@ def validate(self) -> None: # Check ownership for model in self._models: try: - check_ownership(model) + security_manager.raise_for_ownership(model) except SupersetSecurityException as ex: raise ReportScheduleForbiddenError() from ex diff --git a/superset/reports/commands/create.py b/superset/reports/commands/create.py index 6d9161445a268..aac5f07856e5e 100644 --- a/superset/reports/commands/create.py +++ b/superset/reports/commands/create.py @@ -18,14 +18,12 @@ import logging from typing import Any, Dict, List, Optional -from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User +from flask_babel import gettext as _ from marshmallow import ValidationError from superset.commands.base import CreateMixin from superset.dao.exceptions import DAOCreateFailedError from superset.databases.dao import DatabaseDAO -from superset.models.reports import ReportCreationMethod, ReportScheduleType from superset.reports.commands.base import BaseReportScheduleCommand from superset.reports.commands.exceptions import ( DatabaseNotFoundValidationError, @@ -37,16 +35,21 @@ ReportScheduleRequiredTypeValidationError, ) from superset.reports.dao import ReportScheduleDAO +from superset.reports.models import ( + ReportCreationMethod, + ReportSchedule, + ReportScheduleType, +) +from superset.reports.types import ReportScheduleExtra logger = logging.getLogger(__name__) class CreateReportScheduleCommand(CreateMixin, BaseReportScheduleCommand): - def __init__(self, user: User, data: Dict[str, Any]): - self._actor = user + def __init__(self, data: Dict[str, Any]): self._properties = data.copy() - def run(self) -> Model: + def run(self) -> ReportSchedule: self.validate() try: report_schedule = ReportScheduleDAO.create(self._properties) @@ -63,7 +66,6 @@ def validate(self) -> None: creation_method = self._properties.get("creation_method") chart_id = self._properties.get("chart") dashboard_id = self._properties.get("dashboard") - user_id = self._actor.id # Validate type is required if not report_type: @@ -99,7 +101,7 @@ def validate(self) -> None: if ( creation_method != ReportCreationMethod.ALERTS_REPORTS and not ReportScheduleDAO.validate_unique_creation_method( - user_id, dashboard_id, chart_id + dashboard_id, chart_id ) ): raise ReportScheduleCreationMethodUniquenessValidationError() @@ -110,7 +112,7 @@ def validate(self) -> None: ) try: - owners = self.populate_owners(self._actor, owner_ids) + owners = self.populate_owners(owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) @@ -120,20 +122,26 @@ def validate(self) -> None: raise exception def _validate_report_extra(self, exceptions: List[ValidationError]) -> None: - extra = self._properties.get("extra") + extra: Optional[ReportScheduleExtra] = self._properties.get("extra") dashboard = self._properties.get("dashboard") if extra is None or dashboard is None: return - dashboard_tab_ids = extra.get("dashboard_tab_ids") - if dashboard_tab_ids is None: + dashboard_state = extra.get("dashboard") + if not dashboard_state: return - position_data = json.loads(dashboard.position_json) - invalid_tab_ids = [ - tab_id for tab_id in dashboard_tab_ids if tab_id not in position_data - ] + + position_data = json.loads(dashboard.position_json or "{}") + active_tabs = dashboard_state.get("activeTabs") or [] + anchor = dashboard_state.get("anchor") + invalid_tab_ids = set(active_tabs) - set(position_data.keys()) + if anchor and anchor not in position_data: + invalid_tab_ids.add(anchor) if invalid_tab_ids: exceptions.append( - ValidationError(f"Invalid tab IDs selected: {invalid_tab_ids}", "extra") + ValidationError( + _("Invalid tab ids: %s(tab_ids)", tab_ids=str(invalid_tab_ids)), + "extra", + ) ) diff --git a/superset/reports/commands/delete.py b/superset/reports/commands/delete.py index eef7a56aff79f..4adf17683a6a5 100644 --- a/superset/reports/commands/delete.py +++ b/superset/reports/commands/delete.py @@ -18,26 +18,24 @@ from typing import Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User +from superset import security_manager from superset.commands.base import BaseCommand from superset.dao.exceptions import DAODeleteFailedError from superset.exceptions import SupersetSecurityException -from superset.models.reports import ReportSchedule from superset.reports.commands.exceptions import ( ReportScheduleDeleteFailedError, ReportScheduleForbiddenError, ReportScheduleNotFoundError, ) from superset.reports.dao import ReportScheduleDAO -from superset.views.base import check_ownership +from superset.reports.models import ReportSchedule logger = logging.getLogger(__name__) class DeleteReportScheduleCommand(BaseCommand): - def __init__(self, user: User, model_id: int): - self._actor = user + def __init__(self, model_id: int): self._model_id = model_id self._model: Optional[ReportSchedule] = None @@ -58,6 +56,6 @@ def validate(self) -> None: # Check ownership try: - check_ownership(self._model) + security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise ReportScheduleForbiddenError() from ex diff --git a/superset/reports/commands/exceptions.py b/superset/reports/commands/exceptions.py index db46503b93fd2..b908042f19a11 100644 --- a/superset/reports/commands/exceptions.py +++ b/superset/reports/commands/exceptions.py @@ -14,6 +14,8 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from typing import List + from flask_babel import lazy_gettext as _ from superset.commands.exceptions import ( @@ -24,7 +26,8 @@ ForbiddenError, ValidationError, ) -from superset.models.reports import ReportScheduleType +from superset.exceptions import SupersetError, SupersetErrorsException +from superset.reports.models import ReportScheduleType class DatabaseNotFoundValidationError(ValidationError): @@ -72,7 +75,7 @@ def __init__(self) -> None: super().__init__(_("Type is required"), field_name="type") -class ReportScheduleChartOrDashboardValidationError(ValidationError): +class ReportScheduleOnlyChartOrDashboardError(ValidationError): """ Marshmallow validation error for report schedule accept exlusive chart or dashboard """ @@ -81,6 +84,17 @@ def __init__(self) -> None: super().__init__(_("Choose a chart or dashboard not both"), field_name="chart") +class ReportScheduleEitherChartOrDashboardError(ValidationError): + """ + Marshmallow validation error for report schedule missing both dashboard and chart id + """ + + def __init__(self) -> None: + super().__init__( + _("Must choose either a chart or a dashboard"), field_name="chart" + ) + + class ChartNotSavedValidationError(ValidationError): """ Marshmallow validation error for charts that haven't been saved yet @@ -108,6 +122,7 @@ def __init__(self) -> None: class ReportScheduleInvalidError(CommandInvalidError): + status = 422 message = _("Report Schedule parameters are invalid.") @@ -124,6 +139,7 @@ class ReportScheduleUpdateFailedError(CreateFailedError): class ReportScheduleNotFoundError(CommandException): + status = 404 message = _("Report Schedule not found.") @@ -152,10 +168,12 @@ class ReportScheduleExecuteUnexpectedError(CommandException): class ReportSchedulePreviousWorkingError(CommandException): + status = 429 message = _("Report Schedule is still working, refusing to re-compute.") class ReportScheduleWorkingTimeoutError(CommandException): + status = 408 message = _("Report Schedule reached a working timeout.") @@ -177,68 +195,90 @@ class ReportScheduleCreationMethodUniquenessValidationError(CommandException): class AlertQueryMultipleRowsError(CommandException): - + status = 422 message = _("Alert query returned more than one row.") class AlertValidatorConfigError(CommandException): - + status = 422 message = _("Alert validator config error.") class AlertQueryMultipleColumnsError(CommandException): + status = 422 message = _("Alert query returned more than one column.") class AlertQueryInvalidTypeError(CommandException): + status = 422 message = _("Alert query returned a non-number value.") class AlertQueryError(CommandException): + """ + SQL query is not valid + """ + + status = 400 message = _("Alert found an error while executing a query.") class AlertQueryTimeout(CommandException): + status = 408 message = _("A timeout occurred while executing the query.") class ReportScheduleScreenshotTimeout(CommandException): + status = 408 message = _("A timeout occurred while taking a screenshot.") class ReportScheduleCsvTimeout(CommandException): + status = 408 message = _("A timeout occurred while generating a csv.") class ReportScheduleDataFrameTimeout(CommandException): + status = 408 message = _("A timeout occurred while generating a dataframe.") class ReportScheduleAlertGracePeriodError(CommandException): + status = 429 message = _("Alert fired during grace period.") class ReportScheduleAlertEndGracePeriodError(CommandException): + status = 429 message = _("Alert ended grace period.") class ReportScheduleNotificationError(CommandException): + status = 429 message = _("Alert on grace period") -class ReportScheduleSelleniumUserNotFoundError(CommandException): - message = _("Report Schedule sellenium user not found") - - class ReportScheduleStateNotFoundError(CommandException): message = _("Report Schedule state not found") +class ReportScheduleSystemErrorsException(CommandException, SupersetErrorsException): + errors: List[SupersetError] = [] + message = _("Report schedule system error") + + +class ReportScheduleClientErrorsException(CommandException, SupersetErrorsException): + status = 400 + errors: List[SupersetError] = [] + message = _("Report schedule client error") + + class ReportScheduleUnexpectedError(CommandException): message = _("Report schedule unexpected error") class ReportScheduleForbiddenError(ForbiddenError): + status = 403 message = _("Changing this report is forbidden") diff --git a/superset/reports/commands/execute.py b/superset/reports/commands/execute.py index ad1b1edcd2a76..c8edd928b4784 100644 --- a/superset/reports/commands/execute.py +++ b/superset/reports/commands/execute.py @@ -17,43 +17,38 @@ import json import logging from datetime import datetime, timedelta -from typing import Any, List, Optional +from typing import Any, List, Optional, Union from uuid import UUID import pandas as pd from celery.exceptions import SoftTimeLimitExceeded -from flask_appbuilder.security.sqla.models import User from sqlalchemy.orm import Session from superset import app, security_manager from superset.commands.base import BaseCommand from superset.commands.exceptions import CommandException from superset.common.chart_data import ChartDataResultFormat, ChartDataResultType -from superset.extensions import feature_flag_manager, machine_auth_provider_factory -from superset.models.reports import ( - ReportDataFormat, - ReportExecutionLog, - ReportRecipients, - ReportRecipientType, - ReportSchedule, - ReportScheduleType, - ReportState, +from superset.dashboards.permalink.commands.create import ( + CreateDashboardPermalinkCommand, ) +from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.exceptions import SupersetErrorsException, SupersetException +from superset.extensions import feature_flag_manager, machine_auth_provider_factory from superset.reports.commands.alert import AlertCommand from superset.reports.commands.exceptions import ( ReportScheduleAlertGracePeriodError, + ReportScheduleClientErrorsException, ReportScheduleCsvFailedError, ReportScheduleCsvTimeout, ReportScheduleDataFrameFailedError, ReportScheduleDataFrameTimeout, ReportScheduleExecuteUnexpectedError, ReportScheduleNotFoundError, - ReportScheduleNotificationError, ReportSchedulePreviousWorkingError, ReportScheduleScreenshotFailedError, ReportScheduleScreenshotTimeout, - ReportScheduleSelleniumUserNotFoundError, ReportScheduleStateNotFoundError, + ReportScheduleSystemErrorsException, ReportScheduleUnexpectedError, ReportScheduleWorkingTimeoutError, ) @@ -61,18 +56,25 @@ REPORT_SCHEDULE_ERROR_NOTIFICATION_MARKER, ReportScheduleDAO, ) +from superset.reports.models import ( + ReportDataFormat, + ReportExecutionLog, + ReportRecipients, + ReportRecipientType, + ReportSchedule, + ReportScheduleType, + ReportSourceFormat, + ReportState, +) from superset.reports.notifications import create_notification from superset.reports.notifications.base import NotificationContent from superset.reports.notifications.exceptions import NotificationError +from superset.tasks.utils import get_executor from superset.utils.celery import session_scope +from superset.utils.core import HeaderDataType, override_user from superset.utils.csv import get_chart_csv_data, get_chart_dataframe -from superset.utils.screenshots import ( - BaseScreenshot, - ChartScreenshot, - DashboardScreenshot, -) +from superset.utils.screenshots import ChartScreenshot, DashboardScreenshot from superset.utils.urls import get_url_path -from superset.utils.webdriver import DashboardStandaloneMode logger = logging.getLogger(__name__) @@ -103,7 +105,6 @@ def update_report_schedule_and_log( Update the report schedule state et al. and reflect the change in the execution log. """ - self.update_report_schedule(state) self.create_log(error_message) @@ -167,97 +168,84 @@ def _get_url( force=force, ) return get_url_path( - "Superset.explore", + "ExploreView.root", user_friendly=user_friendly, form_data=json.dumps({"slice_id": self._report_schedule.chart_id}), - standalone="true", force=force, **kwargs, ) + + # If we need to render dashboard in a specific state, use stateful permalink + dashboard_state = self._report_schedule.extra.get("dashboard") + if dashboard_state: + permalink_key = CreateDashboardPermalinkCommand( + dashboard_id=str(self._report_schedule.dashboard_id), + state=dashboard_state, + ).run() + return get_url_path("Superset.dashboard_permalink", key=permalink_key) + return get_url_path( "Superset.dashboard", user_friendly=user_friendly, dashboard_id_or_slug=self._report_schedule.dashboard_id, - standalone=DashboardStandaloneMode.REPORT.value, force=force, **kwargs, ) - @staticmethod - def _get_user() -> User: - user = security_manager.find_user( - username=app.config["THUMBNAIL_SELENIUM_USER"] - ) - if not user: - raise ReportScheduleSelleniumUserNotFoundError() - return user - def _get_screenshots(self) -> List[bytes]: """ Get chart or dashboard screenshots :raises: ReportScheduleScreenshotFailedError """ - image_data = [] - screenshots: List[BaseScreenshot] = [] + url = self._get_url() + _, username = get_executor( + executor_types=app.config["ALERT_REPORTS_EXECUTE_AS"], + model=self._report_schedule, + ) + user = security_manager.find_user(username) if self._report_schedule.chart: - url = self._get_url() - logger.info("Screenshotting chart at %s", url) - screenshots = [ - ChartScreenshot( - url, - self._report_schedule.chart.digest, - window_size=app.config["WEBDRIVER_WINDOW"]["slice"], - thumb_size=app.config["WEBDRIVER_WINDOW"]["slice"], - ) - ] + screenshot: Union[ChartScreenshot, DashboardScreenshot] = ChartScreenshot( + url, + self._report_schedule.chart.digest, + window_size=app.config["WEBDRIVER_WINDOW"]["slice"], + thumb_size=app.config["WEBDRIVER_WINDOW"]["slice"], + ) else: - tabs: Optional[List[str]] = json.loads(self._report_schedule.extra).get( - "dashboard_tab_ids", None + screenshot = DashboardScreenshot( + url, + self._report_schedule.dashboard.digest, + window_size=app.config["WEBDRIVER_WINDOW"]["dashboard"], + thumb_size=app.config["WEBDRIVER_WINDOW"]["dashboard"], ) - dashboard_base_url = self._get_url() - if tabs is None: - urls = [dashboard_base_url] - else: - urls = [f"{dashboard_base_url}#{tab_id}" for tab_id in tabs] - screenshots = [ - DashboardScreenshot( - url, - self._report_schedule.dashboard.digest, - window_size=app.config["WEBDRIVER_WINDOW"]["dashboard"], - thumb_size=app.config["WEBDRIVER_WINDOW"]["dashboard"], - ) - for url in urls - ] - user = self._get_user() - for screenshot in screenshots: - try: - image = screenshot.get_screenshot(user=user) - except SoftTimeLimitExceeded as ex: - logger.warning("A timeout occurred while taking a screenshot.") - raise ReportScheduleScreenshotTimeout() from ex - except Exception as ex: - raise ReportScheduleScreenshotFailedError( - f"Failed taking a screenshot {str(ex)}" - ) from ex - if image is not None: - image_data.append(image) - if not image_data: + try: + image = screenshot.get_screenshot(user=user) + except SoftTimeLimitExceeded as ex: + logger.warning("A timeout occurred while taking a screenshot.") + raise ReportScheduleScreenshotTimeout() from ex + except Exception as ex: + raise ReportScheduleScreenshotFailedError( + f"Failed taking a screenshot {str(ex)}" + ) from ex + if not image: raise ReportScheduleScreenshotFailedError() - return image_data + return [image] def _get_csv_data(self) -> bytes: url = self._get_url(result_format=ChartDataResultFormat.CSV) - auth_cookies = machine_auth_provider_factory.instance.get_auth_cookies( - self._get_user() + _, username = get_executor( + executor_types=app.config["ALERT_REPORTS_EXECUTE_AS"], + model=self._report_schedule, ) + user = security_manager.find_user(username) + auth_cookies = machine_auth_provider_factory.instance.get_auth_cookies(user) if self._report_schedule.chart.query_context is None: logger.warning("No query context found, taking a screenshot to generate it") self._update_query_context() try: - logger.info("Getting chart from %s", url) - csv_data = get_chart_csv_data(url, auth_cookies) + logger.info("Getting chart from %s as user %s", url, user.username) + csv_data = get_chart_csv_data(chart_url=url, auth_cookies=auth_cookies) except SoftTimeLimitExceeded as ex: raise ReportScheduleCsvTimeout() from ex except Exception as ex: @@ -273,16 +261,19 @@ def _get_embedded_data(self) -> pd.DataFrame: Return data as a Pandas dataframe, to embed in notifications as a table. """ url = self._get_url(result_format=ChartDataResultFormat.JSON) - auth_cookies = machine_auth_provider_factory.instance.get_auth_cookies( - self._get_user() + _, username = get_executor( + executor_types=app.config["ALERT_REPORTS_EXECUTE_AS"], + model=self._report_schedule, ) + user = security_manager.find_user(username) + auth_cookies = machine_auth_provider_factory.instance.get_auth_cookies(user) if self._report_schedule.chart.query_context is None: logger.warning("No query context found, taking a screenshot to generate it") self._update_query_context() try: - logger.info("Getting chart from %s", url) + logger.info("Getting chart from %s as user %s", url, user.username) dataframe = get_chart_dataframe(url, auth_cookies) except SoftTimeLimitExceeded as ex: raise ReportScheduleDataFrameTimeout() from ex @@ -315,6 +306,27 @@ def _update_query_context(self) -> None: "Please try loading the chart and saving it again." ) from ex + def _get_log_data(self) -> HeaderDataType: + chart_id = None + dashboard_id = None + report_source = None + if self._report_schedule.chart: + report_source = ReportSourceFormat.CHART + chart_id = self._report_schedule.chart_id + else: + report_source = ReportSourceFormat.DASHBOARD + dashboard_id = self._report_schedule.dashboard_id + + log_data: HeaderDataType = { + "notification_type": self._report_schedule.type, + "notification_source": report_source, + "notification_format": self._report_schedule.report_format, + "chart_id": chart_id, + "dashboard_id": dashboard_id, + "owners": self._report_schedule.owners, + } + return log_data + def _get_notification_content(self) -> NotificationContent: """ Gets a notification content, this is composed by a title and a screenshot @@ -325,6 +337,7 @@ def _get_notification_content(self) -> NotificationContent: embedded_data = None error_text = None screenshot_data = [] + header_data = self._get_log_data() url = self._get_url(user_friendly=True) if ( feature_flag_manager.is_feature_enabled("ALERTS_ATTACH_REPORTS") @@ -343,7 +356,9 @@ def _get_notification_content(self) -> NotificationContent: error_text = "Unexpected missing csv file" if error_text: return NotificationContent( - name=self._report_schedule.name, text=error_text + name=self._report_schedule.name, + text=error_text, + header_data=header_data, ) if ( @@ -362,6 +377,7 @@ def _get_notification_content(self) -> NotificationContent: f"{self._report_schedule.name}: " f"{self._report_schedule.dashboard.dashboard_title}" ) + return NotificationContent( name=name, url=url, @@ -369,6 +385,7 @@ def _get_notification_content(self) -> NotificationContent: description=self._report_schedule.description, csv=csv_data, embedded_data=embedded_data, + header_data=header_data, ) def _send( @@ -379,9 +396,9 @@ def _send( """ Sends a notification to all recipients - :raises: ReportScheduleNotificationError + :raises: CommandException """ - notification_errors = [] + notification_errors: List[SupersetError] = [] for recipient in recipients: notification = create_notification(recipient, notification_content) try: @@ -393,17 +410,32 @@ def _send( ) else: notification.send() - except NotificationError as ex: - # collect notification errors but keep processing them - notification_errors.append(str(ex)) + except (NotificationError, SupersetException) as ex: + # collect errors but keep processing them + notification_errors.append( + SupersetError( + message=ex.message, + error_type=SupersetErrorType.REPORT_NOTIFICATION_ERROR, + level=ErrorLevel.ERROR + if ex.status >= 500 + else ErrorLevel.WARNING, + ) + ) if notification_errors: - raise ReportScheduleNotificationError(";".join(notification_errors)) + # log all errors but raise based on the most severe + for error in notification_errors: + logger.warning(str(error)) + + if any(error.level == ErrorLevel.ERROR for error in notification_errors): + raise ReportScheduleSystemErrorsException(errors=notification_errors) + if any(error.level == ErrorLevel.WARNING for error in notification_errors): + raise ReportScheduleClientErrorsException(errors=notification_errors) def send(self) -> None: """ Creates the notification content and sends them to all recipients - :raises: ReportScheduleNotificationError + :raises: CommandException """ notification_content = self._get_notification_content() self._send(notification_content, self._report_schedule.recipients) @@ -412,9 +444,17 @@ def send_error(self, name: str, message: str) -> None: """ Creates and sends a notification for an error, to all recipients - :raises: ReportScheduleNotificationError + :raises: CommandException """ - notification_content = NotificationContent(name=name, text=message) + header_data = self._get_log_data() + logger.info( + "header_data in notifications for alerts and reports %s, taskid, %s", + header_data, + self._execution_id, + ) + notification_content = NotificationContent( + name=name, text=message, header_data=header_data + ) # filter recipients to recipients who are also owners owner_recipients = [ @@ -502,25 +542,34 @@ def next(self) -> None: return self.send() self.update_report_schedule_and_log(ReportState.SUCCESS) - except CommandException as first_ex: + except (SupersetErrorsException, Exception) as first_ex: + error_message = str(first_ex) + if isinstance(first_ex, SupersetErrorsException): + error_message = ";".join([error.message for error in first_ex.errors]) + self.update_report_schedule_and_log( - ReportState.ERROR, error_message=str(first_ex) + ReportState.ERROR, error_message=error_message ) + # TODO (dpgaspar) convert this logic to a new state eg: ERROR_ON_GRACE if not self.is_in_error_grace_period(): + second_error_message = REPORT_SCHEDULE_ERROR_NOTIFICATION_MARKER try: self.send_error( f"Error occurred for {self._report_schedule.type}:" f" {self._report_schedule.name}", str(first_ex), ) - self.update_report_schedule_and_log( - ReportState.ERROR, - error_message=REPORT_SCHEDULE_ERROR_NOTIFICATION_MARKER, + + except SupersetErrorsException as second_ex: + second_error_message = ";".join( + [error.message for error in second_ex.errors] ) - except CommandException as second_ex: + except Exception as second_ex: # pylint: disable=broad-except + second_error_message = str(second_ex) + finally: self.update_report_schedule_and_log( - ReportState.ERROR, error_message=str(second_ex) + ReportState.ERROR, error_message=second_error_message ) raise first_ex @@ -575,7 +624,7 @@ def next(self) -> None: if not AlertCommand(self._report_schedule).run(): self.update_report_schedule_and_log(ReportState.NOOP) return - except CommandException as ex: + except Exception as ex: self.send_error( f"Error occurred for {self._report_schedule.type}:" f" {self._report_schedule.name}", @@ -590,7 +639,7 @@ def next(self) -> None: try: self.send() self.update_report_schedule_and_log(ReportState.SUCCESS) - except CommandException as ex: + except Exception as ex: # pylint: disable=broad-except self.update_report_schedule_and_log( ReportState.ERROR, error_message=str(ex) ) @@ -652,9 +701,20 @@ def run(self) -> None: self.validate(session=session) if not self._model: raise ReportScheduleExecuteUnexpectedError() - ReportScheduleStateMachine( - session, self._execution_id, self._model, self._scheduled_dttm - ).run() + _, username = get_executor( + executor_types=app.config["ALERT_REPORTS_EXECUTE_AS"], + model=self._model, + ) + user = security_manager.find_user(username) + with override_user(user): + logger.info( + "Running report schedule %s as user %s", + self._execution_id, + username, + ) + ReportScheduleStateMachine( + session, self._execution_id, self._model, self._scheduled_dttm + ).run() except CommandException as ex: raise ex except Exception as ex: @@ -664,6 +724,13 @@ def validate( # pylint: disable=arguments-differ self, session: Session = None ) -> None: # Validate/populate model exists - self._model = ReportScheduleDAO.find_by_id(self._model_id, session=session) + logger.info( + "session is validated: id %s, executionid: %s", + self._model_id, + self._execution_id, + ) + self._model = ( + session.query(ReportSchedule).filter_by(id=self._model_id).one_or_none() + ) if not self._model: raise ReportScheduleNotFoundError() diff --git a/superset/reports/commands/log_prune.py b/superset/reports/commands/log_prune.py index 4b577b1f55dca..badd267ecfdd4 100644 --- a/superset/reports/commands/log_prune.py +++ b/superset/reports/commands/log_prune.py @@ -19,9 +19,9 @@ from superset.commands.base import BaseCommand from superset.dao.exceptions import DAODeleteFailedError -from superset.models.reports import ReportSchedule from superset.reports.commands.exceptions import ReportSchedulePruneLogError from superset.reports.dao import ReportScheduleDAO +from superset.reports.models import ReportSchedule from superset.utils.celery import session_scope logger = logging.getLogger(__name__) diff --git a/superset/reports/commands/update.py b/superset/reports/commands/update.py index 201d961863d4d..3399eca7b72cd 100644 --- a/superset/reports/commands/update.py +++ b/superset/reports/commands/update.py @@ -19,14 +19,13 @@ from typing import Any, Dict, List, Optional from flask_appbuilder.models.sqla import Model -from flask_appbuilder.security.sqla.models import User from marshmallow import ValidationError +from superset import security_manager from superset.commands.base import UpdateMixin from superset.dao.exceptions import DAOUpdateFailedError from superset.databases.dao import DatabaseDAO from superset.exceptions import SupersetSecurityException -from superset.models.reports import ReportSchedule, ReportScheduleType, ReportState from superset.reports.commands.base import BaseReportScheduleCommand from superset.reports.commands.exceptions import ( DatabaseNotFoundValidationError, @@ -37,14 +36,13 @@ ReportScheduleUpdateFailedError, ) from superset.reports.dao import ReportScheduleDAO -from superset.views.base import check_ownership +from superset.reports.models import ReportSchedule, ReportScheduleType, ReportState logger = logging.getLogger(__name__) class UpdateReportScheduleCommand(UpdateMixin, BaseReportScheduleCommand): - def __init__(self, user: User, model_id: int, data: Dict[str, Any]): - self._actor = user + def __init__(self, model_id: int, data: Dict[str, Any]): self._model_id = model_id self._properties = data.copy() self._model: Optional[ReportSchedule] = None @@ -113,7 +111,7 @@ def validate(self) -> None: # Check ownership try: - check_ownership(self._model) + security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise ReportScheduleForbiddenError() from ex @@ -121,7 +119,7 @@ def validate(self) -> None: if owner_ids is None: owner_ids = [owner.id for owner in self._model.owners] try: - owners = self.populate_owners(self._actor, owner_ids) + owners = self.populate_owners(owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) diff --git a/superset/reports/dao.py b/superset/reports/dao.py index 312710fe037c0..be5ee8053c48b 100644 --- a/superset/reports/dao.py +++ b/superset/reports/dao.py @@ -26,13 +26,15 @@ from superset.dao.base import BaseDAO from superset.dao.exceptions import DAOCreateFailedError, DAODeleteFailedError from superset.extensions import db -from superset.models.reports import ( +from superset.reports.filters import ReportScheduleFilter +from superset.reports.models import ( ReportExecutionLog, ReportRecipients, ReportSchedule, ReportScheduleType, ReportState, ) +from superset.utils.core import get_user_id logger = logging.getLogger(__name__) @@ -42,6 +44,7 @@ class ReportScheduleDAO(BaseDAO): model_cls = ReportSchedule + base_filter = ReportScheduleFilter @staticmethod def find_by_chart_id(chart_id: int) -> List[ReportSchedule]: @@ -110,20 +113,19 @@ def bulk_delete( if commit: db.session.commit() except SQLAlchemyError as ex: - if commit: - db.session.rollback() + db.session.rollback() raise DAODeleteFailedError(str(ex)) from ex @staticmethod def validate_unique_creation_method( - user_id: int, dashboard_id: Optional[int] = None, chart_id: Optional[int] = None + dashboard_id: Optional[int] = None, chart_id: Optional[int] = None ) -> bool: """ Validate if the user already has a chart or dashboard with a report attached form the self subscribe reports """ - query = db.session.query(ReportSchedule).filter_by(created_by_fk=user_id) + query = db.session.query(ReportSchedule).filter_by(created_by_fk=get_user_id()) if dashboard_id is not None: query = query.filter(ReportSchedule.dashboard_id == dashboard_id) @@ -154,7 +156,7 @@ def validate_update_uniqueness( return found_id is None or found_id == expect_id @classmethod - def create(cls, properties: Dict[str, Any], commit: bool = True) -> Model: + def create(cls, properties: Dict[str, Any], commit: bool = True) -> ReportSchedule: """ create a report schedule and nested recipients :raises: DAOCreateFailedError @@ -186,7 +188,7 @@ def create(cls, properties: Dict[str, Any], commit: bool = True) -> Model: @classmethod def update( cls, model: Model, properties: Dict[str, Any], commit: bool = True - ) -> Model: + ) -> ReportSchedule: """ create a report schedule and nested recipients :raises: DAOCreateFailedError @@ -323,6 +325,5 @@ def bulk_delete_logs( session.commit() return row_count except SQLAlchemyError as ex: - if commit: - session.rollback() + session.rollback() raise DAODeleteFailedError(str(ex)) from ex diff --git a/superset/reports/filters.py b/superset/reports/filters.py index 82ea73a91a9f0..5fb87e0563345 100644 --- a/superset/reports/filters.py +++ b/superset/reports/filters.py @@ -20,10 +20,26 @@ from sqlalchemy import or_ from sqlalchemy.orm.query import Query -from superset.models.reports import ReportSchedule +from superset import db, security_manager +from superset.reports.models import ReportSchedule from superset.views.base import BaseFilter +class ReportScheduleFilter(BaseFilter): # pylint: disable=too-few-public-methods + def apply(self, query: Query, value: Any) -> Query: + if security_manager.can_access_all_datasources(): + return query + owner_ids_query = ( + db.session.query(ReportSchedule.id) + .join(ReportSchedule.owners) + .filter( + security_manager.user_model.id + == security_manager.user_model.get_user_id() + ) + ) + return query.filter(ReportSchedule.id.in_(owner_ids_query)) + + class ReportScheduleAllTextFilter(BaseFilter): # pylint: disable=too-few-public-methods name = _("All Text") arg_name = "report_all_text" diff --git a/superset/reports/logs/api.py b/superset/reports/logs/api.py index 6b11da556f676..41c47e36522da 100644 --- a/superset/reports/logs/api.py +++ b/superset/reports/logs/api.py @@ -25,8 +25,8 @@ from superset import is_feature_enabled from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod -from superset.models.reports import ReportExecutionLog from superset.reports.logs.schemas import openapi_spec_methods_override +from superset.reports.models import ReportExecutionLog from superset.views.base_api import BaseSupersetModelRestApi logger = logging.getLogger(__name__) diff --git a/superset/models/reports.py b/superset/reports/models.py similarity index 92% rename from superset/models/reports.py rename to superset/reports/models.py index b0aa94d9a77c4..24d4657b7daea 100644 --- a/superset/models/reports.py +++ b/superset/reports/models.py @@ -16,8 +16,6 @@ # under the License. """A collection of ORM sqlalchemy models for Superset""" import enum -import json -from typing import Any, Dict, Optional from cron_descriptor import get_description from flask_appbuilder import Model @@ -33,15 +31,16 @@ Table, Text, ) -from sqlalchemy.orm import backref, relationship, validates +from sqlalchemy.orm import backref, relationship from sqlalchemy.schema import UniqueConstraint from sqlalchemy_utils import UUIDType from superset.extensions import security_manager from superset.models.core import Database from superset.models.dashboard import Dashboard -from superset.models.helpers import AuditMixinNullable +from superset.models.helpers import AuditMixinNullable, ExtraJSONMixin from superset.models.slice import Slice +from superset.reports.types import ReportScheduleExtra metadata = Model.metadata # pylint: disable=no-member @@ -83,6 +82,11 @@ class ReportCreationMethod(str, enum.Enum): ALERTS_REPORTS = "alerts_reports" +class ReportSourceFormat(str, enum.Enum): + CHART = "chart" + DASHBOARD = "dashboard" + + report_schedule_user = Table( "report_schedule_user", metadata, @@ -95,7 +99,7 @@ class ReportCreationMethod(str, enum.Enum): ) -class ReportSchedule(Model, AuditMixinNullable): +class ReportSchedule(Model, AuditMixinNullable, ExtraJSONMixin): """ Report Schedules, supports alerts and reports @@ -147,12 +151,11 @@ class ReportSchedule(Model, AuditMixinNullable): # (Alerts/Reports) Unlock a possible stalled working state working_timeout = Column(Integer, default=60 * 60 * 1) - # Store the selected dashboard tabs etc. - extra = Column(Text, default="{}") - # (Reports) When generating a screenshot, bypass the cache? force_screenshot = Column(Boolean, default=False) + extra: ReportScheduleExtra # type: ignore + def __repr__(self) -> str: return str(self.name) @@ -160,13 +163,6 @@ def __repr__(self) -> str: def crontab_humanized(self) -> str: return get_description(self.crontab) - @validates("extra") - # pylint: disable=unused-argument,no-self-use - def validate_extra(self, key: str, value: Dict[Any, Any]) -> Optional[str]: - if value is not None: - return json.dumps(value) - return None - class ReportRecipients(Model, AuditMixinNullable): """ diff --git a/superset/reports/notifications/__init__.py b/superset/reports/notifications/__init__.py index dae43d64c7cab..c466f59abd5b3 100644 --- a/superset/reports/notifications/__init__.py +++ b/superset/reports/notifications/__init__.py @@ -15,7 +15,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from superset.models.reports import ReportRecipients +from superset.reports.models import ReportRecipients from superset.reports.notifications.base import BaseNotification, NotificationContent from superset.reports.notifications.email import EmailNotification from superset.reports.notifications.slack import SlackNotification diff --git a/superset/reports/notifications/base.py b/superset/reports/notifications/base.py index 06bfecf790144..6eb2405d0ff67 100644 --- a/superset/reports/notifications/base.py +++ b/superset/reports/notifications/base.py @@ -20,12 +20,14 @@ import pandas as pd -from superset.models.reports import ReportRecipients, ReportRecipientType +from superset.reports.models import ReportRecipients, ReportRecipientType +from superset.utils.core import HeaderDataType @dataclass class NotificationContent: name: str + header_data: HeaderDataType # this is optional to account for error states csv: Optional[bytes] = None # bytes for csv file screenshots: Optional[List[bytes]] = None # bytes for a list of screenshots text: Optional[str] = None diff --git a/superset/reports/notifications/email.py b/superset/reports/notifications/email.py index 3991f24b9264d..22b1714f99fed 100644 --- a/superset/reports/notifications/email.py +++ b/superset/reports/notifications/email.py @@ -26,22 +26,48 @@ from flask_babel import gettext as __ from superset import app -from superset.models.reports import ReportRecipientType +from superset.exceptions import SupersetErrorsException +from superset.reports.models import ReportRecipientType from superset.reports.notifications.base import BaseNotification from superset.reports.notifications.exceptions import NotificationError -from superset.utils.core import send_email_smtp +from superset.utils.core import HeaderDataType, send_email_smtp from superset.utils.decorators import statsd_gauge -from superset.utils.urls import modify_url_query logger = logging.getLogger(__name__) TABLE_TAGS = ["table", "th", "tr", "td", "thead", "tbody", "tfoot"] TABLE_ATTRIBUTES = ["colspan", "rowspan", "halign", "border", "class"] +ALLOWED_TAGS = [ + "a", + "abbr", + "acronym", + "b", + "blockquote", + "br", + "code", + "div", + "em", + "i", + "li", + "ol", + "p", + "strong", + "ul", +] + TABLE_TAGS + +ALLOWED_ATTRIBUTES = { + "a": ["href", "title"], + "abbr": ["title"], + "acronym": ["title"], + **{tag: TABLE_ATTRIBUTES for tag in TABLE_TAGS}, +} + @dataclass class EmailContent: body: str + header_data: Optional[HeaderDataType] = None data: Optional[Dict[str, Any]] = None images: Optional[Dict[str, bytes]] = None @@ -82,25 +108,26 @@ def _get_content(self) -> EmailContent: } # Strip any malicious HTML from the description - description = bleach.clean(self._content.description or "") + description = bleach.clean( + self._content.description or "", + tags=ALLOWED_TAGS, + attributes=ALLOWED_ATTRIBUTES, + ) # Strip malicious HTML from embedded data, allowing only table elements if self._content.embedded_data is not None: df = self._content.embedded_data html_table = bleach.clean( - df.to_html(na_rep="", index=True), + df.to_html(na_rep="", index=True, escape=True), + # pandas will escape the HTML in cells already, so passing + # more allowed tags here will not work tags=TABLE_TAGS, attributes=TABLE_ATTRIBUTES, ) else: html_table = "" - call_to_action = __("Explore in Superset") - url = ( - modify_url_query(self._content.url, standalone="0") - if self._content.url is not None - else "" - ) + call_to_action = __(app.config["EMAIL_REPORTS_CTA"]) img_tags = [] for msgid in images.keys(): img_tags.append( @@ -127,8 +154,9 @@ def _get_content(self) -> EmailContent: </style> </head> <body> - <p>{description}</p> - <b><a href="{url}">{call_to_action}</a></b><p></p> + <div>{description}</div> + <br> + <b><a href="{self._content.url}">{call_to_action}</a></b><p></p> {html_table} {img_tag} </body> @@ -138,7 +166,12 @@ def _get_content(self) -> EmailContent: if self._content.csv: csv_data = {__("%(name)s.csv", name=self._content.name): self._content.csv} - return EmailContent(body=body, images=images, data=csv_data) + return EmailContent( + body=body, + images=images, + data=csv_data, + header_data=self._content.header_data, + ) def _get_subject(self) -> str: return __( @@ -167,7 +200,14 @@ def send(self) -> None: bcc="", mime_subtype="related", dryrun=False, + header_data=content.header_data, + ) + logger.info( + "Report sent to email, notification content is %s", content.header_data ) - logger.info("Report sent to email") + except SupersetErrorsException as ex: + raise NotificationError( + ";".join([error.message for error in ex.errors]) + ) from ex except Exception as ex: - raise NotificationError(ex) from ex + raise NotificationError(str(ex)) from ex diff --git a/superset/reports/notifications/exceptions.py b/superset/reports/notifications/exceptions.py index 749a91fd955b0..aa06906f826b7 100644 --- a/superset/reports/notifications/exceptions.py +++ b/superset/reports/notifications/exceptions.py @@ -14,7 +14,33 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from superset.exceptions import SupersetException -class NotificationError(Exception): - pass +class NotificationError(SupersetException): + """ + Generic unknown exception - only used when + bubbling up unknown exceptions from lower levels + """ + + +class NotificationParamException(SupersetException): + status = 422 + + +class NotificationAuthorizationException(SupersetException): + status = 401 + + +class NotificationUnprocessableException(SupersetException): + """ + When a third party client service is down. + The request should be retried. There is no further + action required on our part or the user's other than to retry + """ + + status = 400 + + +class NotificationMalformedException(SupersetException): + status = 400 diff --git a/superset/reports/notifications/slack.py b/superset/reports/notifications/slack.py index 2a198d66453c2..b89a700ef9c3e 100644 --- a/superset/reports/notifications/slack.py +++ b/superset/reports/notifications/slack.py @@ -22,15 +22,28 @@ import backoff from flask_babel import gettext as __ -from slack import WebClient -from slack.errors import SlackApiError, SlackClientError +from slack_sdk import WebClient +from slack_sdk.errors import ( + BotUserAccessError, + SlackApiError, + SlackClientConfigurationError, + SlackClientError, + SlackClientNotConnectedError, + SlackObjectFormationError, + SlackRequestError, + SlackTokenRotationError, +) from superset import app -from superset.models.reports import ReportRecipientType +from superset.reports.models import ReportRecipientType from superset.reports.notifications.base import BaseNotification -from superset.reports.notifications.exceptions import NotificationError +from superset.reports.notifications.exceptions import ( + NotificationAuthorizationException, + NotificationMalformedException, + NotificationParamException, + NotificationUnprocessableException, +) from superset.utils.decorators import statsd_gauge -from superset.utils.urls import modify_url_query logger = logging.getLogger(__name__) @@ -49,11 +62,6 @@ def _get_channel(self) -> str: return json.loads(self._recipient.recipient_config_json)["target"] def _message_template(self, table: str = "") -> str: - url = ( - modify_url_query(self._content.url, standalone="0") - if self._content.url is not None - else "" - ) return __( """*%(name)s* @@ -65,7 +73,7 @@ def _message_template(self, table: str = "") -> str: """, name=self._content.name, description=self._content.description or "", - url=url, + url=self._content.url, table=table, ) @@ -173,5 +181,19 @@ def send(self) -> None: else: client.chat_postMessage(channel=channel, text=body) logger.info("Report sent to slack") + except ( + BotUserAccessError, + SlackRequestError, + SlackClientConfigurationError, + ) as ex: + raise NotificationParamException(str(ex)) from ex + except SlackObjectFormationError as ex: + raise NotificationMalformedException(str(ex)) from ex + except SlackTokenRotationError as ex: + raise NotificationAuthorizationException(str(ex)) from ex + except (SlackClientNotConnectedError, SlackApiError) as ex: + raise NotificationUnprocessableException(str(ex)) from ex except SlackClientError as ex: - raise NotificationError(ex) from ex + # this is the base class for all slack client errors + # keep it last so that it doesn't interfere with @backoff + raise NotificationUnprocessableException(str(ex)) from ex diff --git a/superset/reports/schemas.py b/superset/reports/schemas.py index a0ce67d80dbbb..c64593f7f961b 100644 --- a/superset/reports/schemas.py +++ b/superset/reports/schemas.py @@ -23,7 +23,7 @@ from marshmallow_enum import EnumField from pytz import all_timezones -from superset.models.reports import ( +from superset.reports.models import ( ReportCreationMethod, ReportDataFormat, ReportRecipientType, @@ -297,4 +297,5 @@ class ReportSchedulePutSchema(Schema): default=ReportDataFormat.VISUALIZATION, validate=validate.OneOf(choices=tuple(key.value for key in ReportDataFormat)), ) + extra = fields.Dict(default=None) force_screenshot = fields.Boolean(default=False) diff --git a/superset/reports/types.py b/superset/reports/types.py new file mode 100644 index 0000000000000..d487e3ad23766 --- /dev/null +++ b/superset/reports/types.py @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from typing import TypedDict + +from superset.dashboards.permalink.types import DashboardPermalinkState + + +class ReportScheduleExtra(TypedDict): + dashboard: DashboardPermalinkState diff --git a/superset/result_set.py b/superset/result_set.py index 725bf1449cc79..1c4ae98dc9112 100644 --- a/superset/result_set.py +++ b/superset/result_set.py @@ -24,6 +24,7 @@ import numpy as np import pandas as pd import pyarrow as pa +from numpy.typing import NDArray from superset.db_engine_specs import BaseEngineSpec from superset.superset_typing import DbapiDescription, DbapiResult, ResultSetColumnType @@ -62,9 +63,23 @@ def stringify(obj: Any) -> str: return json.dumps(obj, default=utils.json_iso_dttm_ser) -def stringify_values(array: np.ndarray) -> np.ndarray: - vstringify = np.vectorize(stringify) - return vstringify(array) +def stringify_values(array: NDArray[Any]) -> NDArray[Any]: + result = np.copy(array) + + with np.nditer(result, flags=["refs_ok"], op_flags=[["readwrite"]]) as it: + for obj in it: + if na_obj := pd.isna(obj): + # pandas <NA> type cannot be converted to string + obj[na_obj] = None # type: ignore + else: + try: + # for simple string conversions + # this handles odd character types better + obj[...] = obj.astype(str) # type: ignore + except ValueError: + obj[...] = stringify(obj) # type: ignore + + return result def destringify(obj: str) -> Any: @@ -97,7 +112,7 @@ def __init__( # pylint: disable=too-many-locals pa_data: List[pa.Array] = [] deduped_cursor_desc: List[Tuple[Any, ...]] = [] numpy_dtype: List[Tuple[str, ...]] = [] - stringified_arr: np.ndarray + stringified_arr: NDArray[Any] if cursor_description: # get deduped list of column names @@ -126,6 +141,7 @@ def __init__( # pylint: disable=too-many-locals pa.lib.ArrowInvalid, pa.lib.ArrowTypeError, pa.lib.ArrowNotImplementedError, + ValueError, TypeError, # this is super hackey, # https://issues.apache.org/jira/browse/ARROW-7855 ): @@ -161,6 +177,9 @@ def __init__( # pylint: disable=too-many-locals except Exception as ex: # pylint: disable=broad-except logger.exception(ex) + if not pa_data: + column_names = [] + self.table = pa.Table.from_arrays(pa_data, names=column_names) self._type_dict: Dict[str, Any] = {} try: @@ -195,7 +214,7 @@ def convert_table_to_df(table: pa.Table) -> pd.DataFrame: return table.to_pandas(integer_object_nulls=True, timestamp_as_object=True) @staticmethod - def first_nonempty(items: List[Any]) -> Any: + def first_nonempty(items: NDArray[Any]) -> Any: return next((i for i in items if i), None) def is_temporal(self, db_type_str: Optional[str]) -> bool: diff --git a/superset/security/api.py b/superset/security/api.py index 2fa8c713ef24f..093a7c6d63eaa 100644 --- a/superset/security/api.py +++ b/superset/security/api.py @@ -33,7 +33,11 @@ ) from superset.extensions import event_logger from superset.security.guest_token import GuestTokenResourceType -from superset.views.base_api import BaseSupersetModelRestApi +from superset.views.base_api import ( + BaseSupersetApi, + BaseSupersetModelRestApi, + statsd_metrics, +) logger = logging.getLogger(__name__) @@ -80,7 +84,7 @@ class GuestTokenCreateSchema(PermissiveSchema): guest_token_create_schema = GuestTokenCreateSchema() -class SecurityRestApi(BaseApi): +class SecurityRestApi(BaseSupersetApi): resource_name = "security" allow_browser_login = True openapi_spec_tag = "Security" @@ -89,6 +93,7 @@ class SecurityRestApi(BaseApi): @event_logger.log_this @protect() @safe + @statsd_metrics @permission_name("read") def csrf_token(self) -> Response: """ @@ -118,6 +123,7 @@ def csrf_token(self) -> Response: @event_logger.log_this @protect() @safe + @statsd_metrics @permission_name("grant_guest_token") def guest_token(self) -> Response: """Response diff --git a/superset/security/manager.py b/superset/security/manager.py index f077298758379..49edc26639a84 100644 --- a/superset/security/manager.py +++ b/superset/security/manager.py @@ -40,9 +40,11 @@ from flask_appbuilder.security.sqla.models import ( assoc_permissionview_role, assoc_user_role, + Permission, PermissionView, Role, User, + ViewMenu, ) from flask_appbuilder.security.views import ( PermissionModelView, @@ -52,16 +54,16 @@ ViewMenuModelView, ) from flask_appbuilder.widgets import ListWidget +from flask_babel import lazy_gettext as _ from flask_login import AnonymousUserMixin, LoginManager from jwt.api_jwt import _jwt_global_obj -from sqlalchemy import and_, or_ +from sqlalchemy import and_, inspect, or_ from sqlalchemy.engine.base import Connection from sqlalchemy.orm import Session from sqlalchemy.orm.mapper import Mapper from sqlalchemy.orm.query import Query as SqlaQuery from superset import sql_parse -from superset.connectors.connector_registry import ConnectorRegistry from superset.constants import RouteMethod from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import ( @@ -76,12 +78,18 @@ GuestTokenUser, GuestUser, ) -from superset.utils.core import DatasourceName, RowLevelSecurityFilterType +from superset.utils.core import ( + DatasourceName, + DatasourceType, + get_user_id, + RowLevelSecurityFilterType, +) from superset.utils.urls import get_url_host if TYPE_CHECKING: from superset.common.query_context import QueryContext from superset.connectors.base.models import BaseDatasource + from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database from superset.models.dashboard import Dashboard from superset.models.sql_lab import Query @@ -156,6 +164,7 @@ class SupersetSecurityManager( # pylint: disable=too-many-public-methods GAMMA_READ_ONLY_MODEL_VIEWS = { "Dataset", "Datasource", + "CssTemplate", } | READ_ONLY_MODEL_VIEWS ADMIN_ONLY_VIEW_MENUS = { @@ -177,10 +186,11 @@ class SupersetSecurityManager( # pylint: disable=too-many-public-methods "Queries", "Import dashboards", "Upload a CSV", + "ReportSchedule", + "Alerts & Report", } ADMIN_ONLY_PERMISSIONS = { - "can_sql_json", # TODO: move can_sql_json to sql_lab role "can_override_role_permissions", "can_sync_druid_source", "can_override_role_permissions", @@ -215,11 +225,11 @@ class SupersetSecurityManager( # pylint: disable=too-many-public-methods ACCESSIBLE_PERMS = {"can_userinfo", "resetmypassword"} - SQLLAB_PERMISSION_VIEWS = { - ("can_csv", "Superset"), + SQLLAB_ONLY_PERMISSIONS = { + ("can_my_queries", "SqlLab"), ("can_read", "SavedQuery"), - ("can_read", "Database"), ("can_sql_json", "Superset"), + ("can_sqllab_history", "Superset"), ("can_sqllab_viz", "Superset"), ("can_sqllab_table_viz", "Superset"), ("can_sqllab", "Superset"), @@ -229,6 +239,12 @@ class SupersetSecurityManager( # pylint: disable=too-many-public-methods ("menu_access", "Query Search"), } + SQLLAB_EXTRA_PERMISSION_VIEWS = { + ("can_csv", "Superset"), + ("can_read", "Superset"), + ("can_read", "Database"), + } + data_access_permissions = ( "database_access", "schema_access", @@ -270,6 +286,14 @@ def get_schema_perm( # pylint: disable=no-self-use return None + @staticmethod + def get_database_perm(database_id: int, database_name: str) -> str: + return f"[{database_name}].(id:{database_id})" + + @staticmethod + def get_dataset_perm(dataset_id: int, dataset_name: str, database_name: str) -> str: + return f"[{database_name}].[{dataset_name}](id:{dataset_id})" + def unpack_database_and_schema( # pylint: disable=no-self-use self, schema_permission: str ) -> DatabaseAndSchema: @@ -384,8 +408,10 @@ def get_datasource_access_error_msg(datasource: "BaseDatasource") -> str: :returns: The error message """ - return f"""This endpoint requires the datasource {datasource.name}, database or - `all_datasource_access` permission""" + return ( + f"This endpoint requires the datasource {datasource.name}, " + "database or `all_datasource_access` permission" + ) @staticmethod def get_datasource_access_link( # pylint: disable=unused-argument @@ -472,23 +498,25 @@ def get_user_datasources(self) -> List["BaseDatasource"]: user_perms = self.user_view_menu_names("datasource_access") schema_perms = self.user_view_menu_names("schema_access") user_datasources = set() - for datasource_class in ConnectorRegistry.sources.values(): - user_datasources.update( - self.get_session.query(datasource_class) - .filter( - or_( - datasource_class.perm.in_(user_perms), - datasource_class.schema_perm.in_(schema_perms), - ) + + # pylint: disable=import-outside-toplevel + from superset.connectors.sqla.models import SqlaTable + + user_datasources.update( + self.get_session.query(SqlaTable) + .filter( + or_( + SqlaTable.perm.in_(user_perms), + SqlaTable.schema_perm.in_(schema_perms), ) - .all() ) + .all() + ) # group all datasources by database - all_datasources = ConnectorRegistry.get_all_datasources(self.get_session) - datasources_by_database: Dict["Database", Set["BaseDatasource"]] = defaultdict( - set - ) + session = self.get_session + all_datasources = SqlaTable.get_all_datasources(session) + datasources_by_database: Dict["Database", Set["SqlaTable"]] = defaultdict(set) for datasource in all_datasources: datasources_by_database[datasource.database].add(datasource) @@ -529,7 +557,7 @@ def user_view_menu_names(self, permission_name: str) -> Set[str]: view_menu_names = ( base_query.join(assoc_user_role) .join(self.user_model) - .filter(self.user_model.id == g.user.get_id()) + .filter(self.user_model.id == get_user_id()) .filter(self.permission_model.name == permission_name) ).all() return {s.name for s in view_menu_names} @@ -600,6 +628,8 @@ def get_datasources_accessible_by_user( # pylint: disable=invalid-name :param schema: The fallback SQL schema if not present in the table name :returns: The list of accessible SQL tables w/ schema """ + # pylint: disable=import-outside-toplevel + from superset.connectors.sqla.models import SqlaTable if self.can_access_database(database): return datasource_names @@ -611,7 +641,7 @@ def get_datasources_accessible_by_user( # pylint: disable=invalid-name user_perms = self.user_view_menu_names("datasource_access") schema_perms = self.user_view_menu_names("schema_access") - user_datasources = ConnectorRegistry.query_datasources_by_permissions( + user_datasources = SqlaTable.query_datasources_by_permissions( self.get_session, database, user_perms, schema_perms ) if schema: @@ -661,6 +691,7 @@ def create_missing_perms(self) -> None: """ # pylint: disable=import-outside-toplevel + from superset.connectors.sqla.models import SqlaTable from superset.models import core as models logger.info("Fetching a set of all perms to lookup which ones are missing") @@ -669,13 +700,13 @@ def create_missing_perms(self) -> None: if pv.permission and pv.view_menu: all_pvs.add((pv.permission.name, pv.view_menu.name)) - def merge_pv(view_menu: str, perm: str) -> None: + def merge_pv(view_menu: str, perm: Optional[str]) -> None: """Create permission view menu only if it doesn't exist""" if view_menu and perm and (view_menu, perm) not in all_pvs: self.add_permission_view_menu(view_menu, perm) logger.info("Creating missing datasource permissions.") - datasources = ConnectorRegistry.get_all_datasources(self.get_session) + datasources = SqlaTable.get_all_datasources(self.get_session) for datasource in datasources: merge_pv("datasource_access", datasource.get_perm()) merge_pv("schema_access", datasource.get_schema_perm()) @@ -887,7 +918,9 @@ def _is_alpha_pvm(self, pvm: PermissionView) -> bool: """ return not ( - self._is_user_defined_permission(pvm) or self._is_admin_only(pvm) + self._is_user_defined_permission(pvm) + or self._is_admin_only(pvm) + or self._is_sql_lab_only(pvm) ) or self._is_accessible_to_all(pvm) def _is_gamma_pvm(self, pvm: PermissionView) -> bool: @@ -903,8 +936,19 @@ def _is_gamma_pvm(self, pvm: PermissionView) -> bool: self._is_user_defined_permission(pvm) or self._is_admin_only(pvm) or self._is_alpha_only(pvm) + or self._is_sql_lab_only(pvm) ) or self._is_accessible_to_all(pvm) + def _is_sql_lab_only(self, pvm: PermissionView) -> bool: + """ + Return True if the FAB permission/view is only SQL Lab related, False + otherwise. + + :param pvm: The FAB permission/view + :returns: Whether the FAB object is SQL Lab related + """ + return (pvm.permission.name, pvm.view_menu.name) in self.SQLLAB_ONLY_PERMISSIONS + def _is_sql_lab_pvm(self, pvm: PermissionView) -> bool: """ Return True if the FAB permission/view is SQL Lab related, False @@ -913,7 +957,11 @@ def _is_sql_lab_pvm(self, pvm: PermissionView) -> bool: :param pvm: The FAB permission/view :returns: Whether the FAB object is SQL Lab related """ - return (pvm.permission.name, pvm.view_menu.name) in self.SQLLAB_PERMISSION_VIEWS + return ( + self._is_sql_lab_only(pvm) + or (pvm.permission.name, pvm.view_menu.name) + in self.SQLLAB_EXTRA_PERMISSION_VIEWS + ) def _is_granter_pvm( # pylint: disable=no-self-use self, pvm: PermissionView @@ -928,85 +976,776 @@ def _is_granter_pvm( # pylint: disable=no-self-use return pvm.permission.name in {"can_override_role_permissions", "can_approve"} - def set_perm( # pylint: disable=unused-argument - self, mapper: Mapper, connection: Connection, target: "BaseDatasource" + def database_after_insert( + self, + mapper: Mapper, + connection: Connection, + target: "Database", ) -> None: """ - Set the datasource permissions. + Handles permissions when a database is created. + Triggered by a SQLAlchemy after_insert event. - :param mapper: The table mapper - :param connection: The DB-API connection - :param target: The mapped instance being persisted + We need to create: + - The database PVM + + :param mapper: The SQLA mapper + :param connection: The SQLA connection + :param target: The changed database object + :return: + """ + self._insert_pvm_on_sqla_event( + mapper, connection, "database_access", target.get_perm() + ) + + def database_after_delete( + self, + mapper: Mapper, + connection: Connection, + target: "Database", + ) -> None: + """ + Handles permissions update when a database is deleted. + Triggered by a SQLAlchemy after_delete event. + + We need to delete: + - The database PVM + + :param mapper: The SQLA mapper + :param connection: The SQLA connection + :param target: The changed database object + :return: + """ + self._delete_vm_database_access( + mapper, connection, target.id, target.database_name + ) + + def database_after_update( + self, + mapper: Mapper, + connection: Connection, + target: "Database", + ) -> None: + """ + Handles all permissions update when a database is changed. + Triggered by a SQLAlchemy after_update event. + + We need to update: + - The database PVM + - All datasets PVMs that reference the db, and it's local perm name + - All datasets local schema perm that reference the db. + - All charts local perm related with said datasets + - All charts local schema perm related with said datasets + + :param mapper: The SQLA mapper + :param connection: The SQLA connection + :param target: The changed database object + :return: + """ + # Check if database name has changed + state = inspect(target) + history = state.get_history("database_name", True) + if not history.has_changes() or not history.deleted: + return + + old_database_name = history.deleted[0] + # update database access permission + self._update_vm_database_access(mapper, connection, old_database_name, target) + # update datasource access + self._update_vm_datasources_access( + mapper, connection, old_database_name, target + ) + # Note schema permissions are updated at the API level + # (database.commands.update). Since we need to fetch all existing schemas from + # the db + + def _delete_vm_database_access( + self, + mapper: Mapper, + connection: Connection, + database_id: int, + database_name: str, + ) -> None: + view_menu_name = self.get_database_perm(database_id, database_name) + # Clean database access permission + self._delete_pvm_on_sqla_event( + mapper, connection, "database_access", view_menu_name + ) + # Clean database schema permissions + schema_pvms = ( + self.get_session.query(self.permissionview_model) + .join(self.permission_model) + .join(self.viewmenu_model) + .filter(self.permission_model.name == "schema_access") + .filter(self.viewmenu_model.name.like(f"[{database_name}].[%]")) + .all() + ) + for schema_pvm in schema_pvms: + self._delete_pvm_on_sqla_event(mapper, connection, pvm=schema_pvm) + + def _update_vm_database_access( + self, + mapper: Mapper, + connection: Connection, + old_database_name: str, + target: "Database", + ) -> Optional[ViewMenu]: + """ + Helper method that Updates all database access permission + when a database name changes. + + :param connection: Current connection (called on SQLAlchemy event listener scope) + :param old_database_name: the old database name + :param target: The database object + :return: A list of changed view menus (permission resource names) + """ + view_menu_table = self.viewmenu_model.__table__ # pylint: disable=no-member + new_database_name = target.database_name + old_view_menu_name = self.get_database_perm(target.id, old_database_name) + new_view_menu_name = self.get_database_perm(target.id, new_database_name) + db_pvm = self.find_permission_view_menu("database_access", old_view_menu_name) + if not db_pvm: + logger.warning( + "Could not find previous database permission %s", + old_view_menu_name, + ) + self._insert_pvm_on_sqla_event( + mapper, connection, "database_access", new_view_menu_name + ) + return None + new_updated_pvm = self.find_permission_view_menu( + "database_access", new_view_menu_name + ) + if new_updated_pvm: + logger.info( + "New permission [%s] already exists, deleting the previous", + new_view_menu_name, + ) + self._delete_vm_database_access( + mapper, connection, target.id, old_database_name + ) + return None + connection.execute( + view_menu_table.update() + .where(view_menu_table.c.id == db_pvm.view_menu_id) + .values(name=new_view_menu_name) + ) + new_db_view_menu = self._find_view_menu_on_sqla_event( + connection, new_view_menu_name + ) + + self.on_view_menu_after_update(mapper, connection, new_db_view_menu) + return new_db_view_menu + + def _update_vm_datasources_access( # pylint: disable=too-many-locals + self, + mapper: Mapper, + connection: Connection, + old_database_name: str, + target: "Database", + ) -> List[ViewMenu]: + """ + Helper method that Updates all datasource access permission + when a database name changes. + + :param connection: Current connection (called on SQLAlchemy event listener scope) + :param old_database_name: the old database name + :param target: The database object + :return: A list of changed view menus (permission resource names) + """ + from superset.connectors.sqla.models import ( # pylint: disable=import-outside-toplevel + SqlaTable, + ) + from superset.models.slice import ( # pylint: disable=import-outside-toplevel + Slice, + ) + + view_menu_table = self.viewmenu_model.__table__ # pylint: disable=no-member + sqlatable_table = SqlaTable.__table__ # pylint: disable=no-member + chart_table = Slice.__table__ # pylint: disable=no-member + new_database_name = target.database_name + datasets = ( + self.get_session.query(SqlaTable) + .filter(SqlaTable.database_id == target.id) + .all() + ) + updated_view_menus: List[ViewMenu] = [] + for dataset in datasets: + old_dataset_vm_name = self.get_dataset_perm( + dataset.id, dataset.table_name, old_database_name + ) + new_dataset_vm_name = self.get_dataset_perm( + dataset.id, dataset.table_name, new_database_name + ) + new_dataset_view_menu = self.find_view_menu(new_dataset_vm_name) + if new_dataset_view_menu: + continue + connection.execute( + view_menu_table.update() + .where(view_menu_table.c.name == old_dataset_vm_name) + .values(name=new_dataset_vm_name) + ) + # After update refresh + new_dataset_view_menu = self._find_view_menu_on_sqla_event( + connection, new_dataset_vm_name + ) + + # Update dataset (SqlaTable perm field) + connection.execute( + sqlatable_table.update() + .where( + sqlatable_table.c.id == dataset.id, + sqlatable_table.c.perm == old_dataset_vm_name, + ) + .values(perm=new_dataset_vm_name) + ) + # Update charts (Slice perm field) + connection.execute( + chart_table.update() + .where(chart_table.c.perm == old_dataset_vm_name) + .values(perm=new_dataset_vm_name) + ) + self.on_view_menu_after_update(mapper, connection, new_dataset_view_menu) + updated_view_menus.append(new_dataset_view_menu) + return updated_view_menus + + def dataset_after_insert( + self, + mapper: Mapper, + connection: Connection, + target: "SqlaTable", + ) -> None: + """ + Handles permission creation when a dataset is inserted. + Triggered by a SQLAlchemy after_insert event. + + We need to create: + - The dataset PVM and set local and schema perm + + :param mapper: The SQLA mapper + :param connection: The SQLA connection + :param target: The changed dataset object + :return: """ + from superset.models.core import ( # pylint: disable=import-outside-toplevel + Database, + ) + try: - target_get_perm = target.get_perm() + dataset_perm = target.get_perm() + database = target.database except DatasetInvalidPermissionEvaluationException: - logger.warning("Dataset has no database refusing to set permission") - return - link_table = target.__table__ - if target.perm != target_get_perm: + logger.warning( + "Dataset has no database will retry with database_id to set permission" + ) + database = self.get_session.query(Database).get(target.database_id) + dataset_perm = self.get_dataset_perm( + target.id, target.table_name, database.database_name + ) + dataset_table = target.__table__ + + self._insert_pvm_on_sqla_event( + mapper, connection, "datasource_access", dataset_perm + ) + if target.perm != dataset_perm: + target.perm = dataset_perm connection.execute( - link_table.update() - .where(link_table.c.id == target.id) - .values(perm=target_get_perm) + dataset_table.update() + .where(dataset_table.c.id == target.id) + .values(perm=dataset_perm) ) - target.perm = target_get_perm - if ( - hasattr(target, "schema_perm") - and target.schema_perm != target.get_schema_perm() - ): + if target.schema: + dataset_schema_perm = self.get_schema_perm( + database.database_name, target.schema + ) + self._insert_pvm_on_sqla_event( + mapper, connection, "schema_access", dataset_schema_perm + ) + target.schema_perm = dataset_schema_perm connection.execute( - link_table.update() - .where(link_table.c.id == target.id) - .values(schema_perm=target.get_schema_perm()) + dataset_table.update() + .where(dataset_table.c.id == target.id) + .values(schema_perm=dataset_schema_perm) ) - target.schema_perm = target.get_schema_perm() - pvm_names = [] - if target.__tablename__ in {"dbs", "clusters"}: - pvm_names.append(("database_access", target_get_perm)) - else: - pvm_names.append(("datasource_access", target_get_perm)) - if target.schema: - pvm_names.append(("schema_access", target.get_schema_perm())) - - # TODO(bogdan): modify slice permissions as well. - for permission_name, view_menu_name in pvm_names: - permission = self.find_permission(permission_name) - view_menu = self.find_view_menu(view_menu_name) - pv = None - - if not permission: - permission_table = ( - self.permission_model.__table__ # pylint: disable=no-member - ) - connection.execute( - permission_table.insert().values(name=permission_name) - ) - permission = self.find_permission(permission_name) - if not view_menu: - view_menu_table = ( - self.viewmenu_model.__table__ # pylint: disable=no-member - ) - connection.execute(view_menu_table.insert().values(name=view_menu_name)) - view_menu = self.find_view_menu(view_menu_name) - - if permission and view_menu: - pv = ( - self.get_session.query(self.permissionview_model) - .filter_by(permission=permission, view_menu=view_menu) - .first() - ) - if not pv and permission and view_menu: - permission_view_table = ( - self.permissionview_model.__table__ # pylint: disable=no-member - ) - connection.execute( - permission_view_table.insert().values( - permission_id=permission.id, view_menu_id=view_menu.id - ) - ) + def dataset_after_delete( + self, + mapper: Mapper, + connection: Connection, + target: "SqlaTable", + ) -> None: + """ + Handles permissions update when a dataset is deleted. + Triggered by a SQLAlchemy after_delete event. + + We need to delete: + - The dataset PVM + + :param mapper: The SQLA mapper + :param connection: The SQLA connection + :param target: The changed dataset object + :return: + """ + dataset_vm_name = self.get_dataset_perm( + target.id, target.table_name, target.database.database_name + ) + self._delete_pvm_on_sqla_event( + mapper, connection, "datasource_access", dataset_vm_name + ) + + def dataset_after_update( + self, + mapper: Mapper, + connection: Connection, + target: "SqlaTable", + ) -> None: + """ + Handles all permissions update when a dataset is changed. + Triggered by a SQLAlchemy after_update event. + + We need to update: + - The dataset PVM and local perm + - All charts local perm related with said datasets + - All charts local schema perm related with said datasets + + :param mapper: The SQLA mapper + :param connection: The SQLA connection + :param target: The changed dataset object + :return: + """ + # Check if watched fields have changed + state = inspect(target) + history_database = state.get_history("database_id", True) + history_table_name = state.get_history("table_name", True) + history_schema = state.get_history("schema", True) + + # When database name changes + if history_database.has_changes() and history_database.deleted: + new_dataset_vm_name = self.get_dataset_perm( + target.id, target.table_name, target.database.database_name + ) + self._update_dataset_perm( + mapper, connection, target.perm, new_dataset_vm_name, target + ) + + # Updates schema permissions + new_dataset_schema_name = self.get_schema_perm( + target.database.database_name, target.schema + ) + self._update_dataset_schema_perm( + mapper, + connection, + new_dataset_schema_name, + target, + ) + + # When table name changes + if history_table_name.has_changes() and history_table_name.deleted: + old_dataset_name = history_table_name.deleted[0] + new_dataset_vm_name = self.get_dataset_perm( + target.id, target.table_name, target.database.database_name + ) + old_dataset_vm_name = self.get_dataset_perm( + target.id, old_dataset_name, target.database.database_name + ) + self._update_dataset_perm( + mapper, connection, old_dataset_vm_name, new_dataset_vm_name, target + ) + + # When schema changes + if history_schema.has_changes() and history_schema.deleted: + new_dataset_schema_name = self.get_schema_perm( + target.database.database_name, target.schema + ) + self._update_dataset_schema_perm( + mapper, + connection, + new_dataset_schema_name, + target, + ) + + def _update_dataset_schema_perm( + self, + mapper: Mapper, + connection: Connection, + new_schema_permission_name: Optional[str], + target: "SqlaTable", + ) -> None: + """ + Helper method that is called by SQLAlchemy events on datasets to update + a new schema permission name, propagates the name change to datasets and charts. + + If the schema permission name does not exist already has a PVM, + creates a new one. + + :param mapper: The SQLA event mapper + :param connection: The SQLA connection + :param new_schema_permission_name: The new schema permission name that changed + :param target: Dataset that was updated + :return: + """ + from superset.connectors.sqla.models import ( # pylint: disable=import-outside-toplevel + SqlaTable, + ) + from superset.models.slice import ( # pylint: disable=import-outside-toplevel + Slice, + ) + + sqlatable_table = SqlaTable.__table__ # pylint: disable=no-member + chart_table = Slice.__table__ # pylint: disable=no-member + + # insert new schema PVM if it does not exist + self._insert_pvm_on_sqla_event( + mapper, connection, "schema_access", new_schema_permission_name + ) + + # Update dataset (SqlaTable schema_perm field) + connection.execute( + sqlatable_table.update() + .where( + sqlatable_table.c.id == target.id, + ) + .values(schema_perm=new_schema_permission_name) + ) + + # Update charts (Slice schema_perm field) + connection.execute( + chart_table.update() + .where( + chart_table.c.datasource_id == target.id, + chart_table.c.datasource_type == DatasourceType.TABLE, + ) + .values(schema_perm=new_schema_permission_name) + ) + + def _update_dataset_perm( # pylint: disable=too-many-arguments + self, + mapper: Mapper, + connection: Connection, + old_permission_name: Optional[str], + new_permission_name: Optional[str], + target: "SqlaTable", + ) -> None: + """ + Helper method that is called by SQLAlchemy events on datasets to update + a permission name change, propagates the name change to VM, datasets and charts. + + :param mapper: + :param connection: + :param old_permission_name + :param new_permission_name: + :param target: + :return: + """ + from superset.connectors.sqla.models import ( # pylint: disable=import-outside-toplevel + SqlaTable, + ) + from superset.models.slice import ( # pylint: disable=import-outside-toplevel + Slice, + ) + + view_menu_table = self.viewmenu_model.__table__ # pylint: disable=no-member + sqlatable_table = SqlaTable.__table__ # pylint: disable=no-member + chart_table = Slice.__table__ # pylint: disable=no-member + + new_dataset_view_menu = self.find_view_menu(new_permission_name) + if new_dataset_view_menu: + return + # Update VM + connection.execute( + view_menu_table.update() + .where(view_menu_table.c.name == old_permission_name) + .values(name=new_permission_name) + ) + # VM changed, so call hook + new_dataset_view_menu = self.find_view_menu(new_permission_name) + self.on_view_menu_after_update(mapper, connection, new_dataset_view_menu) + # Update dataset (SqlaTable perm field) + connection.execute( + sqlatable_table.update() + .where( + sqlatable_table.c.id == target.id, + ) + .values(perm=new_permission_name) + ) + # Update charts (Slice perm field) + connection.execute( + chart_table.update() + .where( + chart_table.c.datasource_type == DatasourceType.TABLE, + chart_table.c.datasource_id == target.id, + ) + .values(perm=new_permission_name) + ) + + def _delete_pvm_on_sqla_event( # pylint: disable=too-many-arguments + self, + mapper: Mapper, + connection: Connection, + permission_name: Optional[str] = None, + view_menu_name: Optional[str] = None, + pvm: Optional[PermissionView] = None, + ) -> None: + """ + Helper method that is called by SQLAlchemy events. + Deletes a PVM. + + :param mapper: The SQLA event mapper + :param connection: The SQLA connection + :param permission_name: e.g.: datasource_access, schema_access + :param view_menu_name: e.g. [db1].[public] + :param pvm: Can be called with the actual PVM already + :return: + """ + view_menu_table = self.viewmenu_model.__table__ # pylint: disable=no-member + permission_view_menu_table = ( + self.permissionview_model.__table__ # pylint: disable=no-member + ) + + if not pvm: + pvm = self.find_permission_view_menu(permission_name, view_menu_name) + if not pvm: + return + # Delete Any Role to PVM association + connection.execute( + assoc_permissionview_role.delete().where( + assoc_permissionview_role.c.permission_view_id == pvm.id + ) + ) + # Delete the database access PVM + connection.execute( + permission_view_menu_table.delete().where( + permission_view_menu_table.c.id == pvm.id + ) + ) + self.on_permission_view_after_delete(mapper, connection, pvm) + connection.execute( + view_menu_table.delete().where(view_menu_table.c.id == pvm.view_menu_id) + ) + + def _find_permission_on_sqla_event( + self, connection: Connection, name: str + ) -> Permission: + """ + Find a FAB Permission using a SQLA connection. + + A session.query may not return the latest results on newly created/updated + objects/rows using connection. On this case we should use a connection also + + :param connection: SQLAlchemy connection + :param name: The permission name (it's unique) + :return: Permission + """ + permission_table = self.permission_model.__table__ # pylint: disable=no-member + + permission_ = connection.execute( + permission_table.select().where(permission_table.c.name == name) + ).fetchone() + permission = Permission() + # ensures this object is never persisted + permission.metadata = None + permission.id = permission_.id + permission.name = permission_.name + return permission + + def _find_view_menu_on_sqla_event( + self, connection: Connection, name: str + ) -> ViewMenu: + """ + Find a FAB ViewMenu using a SQLA connection. + + A session.query may not return the latest results on newly created/updated + objects/rows using connection. On this case we should use a connection also + + :param connection: SQLAlchemy connection + :param name: The ViewMenu name (it's unique) + :return: ViewMenu + """ + view_menu_table = self.viewmenu_model.__table__ # pylint: disable=no-member + + view_menu_ = connection.execute( + view_menu_table.select().where(view_menu_table.c.name == name) + ).fetchone() + view_menu = ViewMenu() + # ensures this object is never persisted + view_menu.metadata = None + view_menu.id = view_menu_.id + view_menu.name = view_menu_.name + return view_menu + + def _insert_pvm_on_sqla_event( + self, + mapper: Mapper, + connection: Connection, + permission_name: str, + view_menu_name: Optional[str], + ) -> None: + """ + Helper method that is called by SQLAlchemy events. + Inserts a new PVM (if it does not exist already) + + :param mapper: The SQLA event mapper + :param connection: The SQLA connection + :param permission_name: e.g.: datasource_access, schema_access + :param view_menu_name: e.g. [db1].[public] + :return: + """ + permission_table = self.permission_model.__table__ # pylint: disable=no-member + view_menu_table = self.viewmenu_model.__table__ # pylint: disable=no-member + permission_view_table = ( + self.permissionview_model.__table__ # pylint: disable=no-member + ) + if not view_menu_name: + return + pvm = self.find_permission_view_menu(permission_name, view_menu_name) + if pvm: + return + permission = self.find_permission(permission_name) + view_menu = self.find_view_menu(view_menu_name) + if not permission: + _ = connection.execute( + permission_table.insert().values(name=permission_name) + ) + permission = self._find_permission_on_sqla_event( + connection, permission_name + ) + self.on_permission_after_insert(mapper, connection, permission) + if not view_menu: + _ = connection.execute(view_menu_table.insert().values(name=view_menu_name)) + view_menu = self._find_view_menu_on_sqla_event(connection, view_menu_name) + self.on_view_menu_after_insert(mapper, connection, view_menu) + connection.execute( + permission_view_table.insert().values( + permission_id=permission.id, view_menu_id=view_menu.id + ) + ) + permission_view = connection.execute( + permission_view_table.select().where( + permission_view_table.c.permission_id == permission.id, + permission_view_table.c.view_menu_id == view_menu.id, + ) + ).fetchone() + permission_view_model = PermissionView() + permission_view_model.metadata = None + permission_view_model.id = permission_view.id + permission_view_model.permission_id = permission.id + permission_view_model.view_menu_id = view_menu.id + permission_view_model.permission = permission + permission_view_model.view_menu = view_menu + self.on_permission_view_after_insert(mapper, connection, permission_view_model) + + def on_role_after_update( + self, mapper: Mapper, connection: Connection, target: Role + ) -> None: + """ + Hook that allows for further custom operations when a Role update + is created by SQLAlchemy events. + + On SQLAlchemy after_insert events, we cannot + create new view_menu's using a session, so any SQLAlchemy events hooked to + `ViewMenu` will not trigger an after_insert. + + :param mapper: The table mapper + :param connection: The DB-API connection + :param target: The mapped instance being changed + """ + + def on_view_menu_after_insert( + self, mapper: Mapper, connection: Connection, target: ViewMenu + ) -> None: + """ + Hook that allows for further custom operations when a new ViewMenu + is created by set_perm. + + On SQLAlchemy after_insert events, we cannot + create new view_menu's using a session, so any SQLAlchemy events hooked to + `ViewMenu` will not trigger an after_insert. + + :param mapper: The table mapper + :param connection: The DB-API connection + :param target: The mapped instance being persisted + """ + + def on_view_menu_after_update( + self, mapper: Mapper, connection: Connection, target: ViewMenu + ) -> None: + """ + Hook that allows for further custom operations when a new ViewMenu + is updated + + Since the update may be performed on after_update event. We cannot + update ViewMenus using a session, so any SQLAlchemy events hooked to + `ViewMenu` will not trigger an after_update. + + :param mapper: The table mapper + :param connection: The DB-API connection + :param target: The mapped instance being persisted + """ + + def on_permission_after_insert( + self, mapper: Mapper, connection: Connection, target: Permission + ) -> None: + """ + Hook that allows for further custom operations when a new permission + is created by set_perm. + + Since set_perm is executed by SQLAlchemy after_insert events, we cannot + create new permissions using a session, so any SQLAlchemy events hooked to + `Permission` will not trigger an after_insert. + + :param mapper: The table mapper + :param connection: The DB-API connection + :param target: The mapped instance being persisted + """ + + def on_permission_view_after_insert( + self, mapper: Mapper, connection: Connection, target: PermissionView + ) -> None: + """ + Hook that allows for further custom operations when a new PermissionView + is created by SQLAlchemy events. + + On SQLAlchemy after_insert events, we cannot + create new pvms using a session, so any SQLAlchemy events hooked to + `PermissionView` will not trigger an after_insert. + + :param mapper: The table mapper + :param connection: The DB-API connection + :param target: The mapped instance being persisted + """ + + def on_permission_view_after_delete( + self, mapper: Mapper, connection: Connection, target: PermissionView + ) -> None: + """ + Hook that allows for further custom operations when a new PermissionView + is delete by SQLAlchemy events. + + On SQLAlchemy after_delete events, we cannot + delete pvms using a session, so any SQLAlchemy events hooked to + `PermissionView` will not trigger an after_delete. + + :param mapper: The table mapper + :param connection: The DB-API connection + :param target: The mapped instance being persisted + """ + + @staticmethod + def get_exclude_users_from_lists() -> List[str]: + """ + Override to dynamically identify a list of usernames to exclude from + all UI dropdown lists, owners, created_by filters etc... + + It will exclude all users from the all endpoints of the form + ``/api/v1/<modelview>/related/<column>`` + + Optionally you can also exclude them using the `EXCLUDE_USERS_FROM_LISTS` + config setting. + + :return: A list of usernames + """ + return [] def raise_for_access( # pylint: disable=too-many-arguments,too-many-locals @@ -1034,7 +1773,6 @@ def raise_for_access( from superset.connectors.sqla.models import SqlaTable from superset.extensions import feature_flag_manager from superset.sql_parse import Table - from superset.views.utils import is_owner if database and table or query: if query: @@ -1067,7 +1805,7 @@ def raise_for_access( for datasource_ in datasources: if self.can_access( "datasource_access", datasource_.perm - ) or is_owner(datasource_, getattr(g, "user", None)): + ) or self.is_owner(datasource_): break else: denied.add(table_) @@ -1093,7 +1831,7 @@ def raise_for_access( if not ( self.can_access_schema(datasource) or self.can_access("datasource_access", datasource.perm or "") - or is_owner(datasource, getattr(g, "user", None)) + or self.is_owner(datasource) or ( should_check_dashboard_access and self.can_access_based_on_dashboard(datasource) @@ -1148,25 +1886,16 @@ def get_guest_rls_filters( ] return [] - def get_rls_filters( - self, - table: "BaseDatasource", - username: Optional[str] = None, - ) -> List[SqlaQuery]: + def get_rls_filters(self, table: "BaseDatasource") -> List[SqlaQuery]: """ Retrieves the appropriate row level security filters for the current user and the passed table. - :param BaseDatasource table: The table to check against. - :param Optional[str] username: Optional username if there's no user in the Flask - global namespace. + :param table: The table to check against :returns: A list of filters """ - if hasattr(g, "user"): - user = g.user - elif username: - user = self.find_user(username=username) - else: + + if not (hasattr(g, "user") and g.user is not None): return [] # pylint: disable=import-outside-toplevel @@ -1176,7 +1905,7 @@ def get_rls_filters( RowLevelSecurityFilter, ) - user_roles = [role.id for role in self.get_user_roles(user)] + user_roles = [role.id for role in self.get_user_roles(g.user)] regular_filter_roles = ( self.get_session() .query(RLSFilterRoles.c.rls_filter_id) @@ -1185,7 +1914,6 @@ def get_rls_filters( RowLevelSecurityFilter.filter_type == RowLevelSecurityFilterType.REGULAR ) .filter(RLSFilterRoles.c.role_id.in_(user_roles)) - .subquery() ) base_filter_roles = ( self.get_session() @@ -1195,13 +1923,11 @@ def get_rls_filters( RowLevelSecurityFilter.filter_type == RowLevelSecurityFilterType.BASE ) .filter(RLSFilterRoles.c.role_id.in_(user_roles)) - .subquery() ) filter_tables = ( self.get_session() .query(RLSFilterTables.c.rls_filter_id) .filter(RLSFilterTables.c.table_id == table.id) - .subquery() ) query = ( self.get_session() @@ -1253,10 +1979,9 @@ def get_rls_cache_key(self, datasource: "BaseDatasource") -> List[str]: @staticmethod def raise_for_user_activity_access(user_id: int) -> None: - user = g.user if g.user and g.user.get_id() else None - if not user or ( + if not get_user_id() or ( not current_app.config["ENABLE_BROAD_ACTIVITY_ACCESS"] - and user_id != user.id + and user_id != get_user_id() ): raise SupersetSecurityException( SupersetError( @@ -1278,8 +2003,6 @@ def raise_for_dashboard_access(self, dashboard: "Dashboard") -> None: # pylint: disable=import-outside-toplevel from superset import is_feature_enabled from superset.dashboards.commands.exceptions import DashboardAccessDeniedError - from superset.views.base import is_user_admin - from superset.views.utils import is_owner def has_rbac_access() -> bool: return (not is_feature_enabled("DASHBOARD_RBAC")) or any( @@ -1292,8 +2015,8 @@ def has_rbac_access() -> bool: can_access = self.has_guest_access(dashboard) else: can_access = ( - is_user_admin() - or is_owner(dashboard, g.user) + self.is_admin() + or self.is_owner(dashboard) or (dashboard.published and has_rbac_access()) or (not dashboard.published and not dashboard.roles) ) @@ -1471,3 +2194,60 @@ def has_guest_access(self, dashboard: "Dashboard") -> bool: if str(resource["id"]) == str(dashboard.embedded[0].uuid): return True return False + + def raise_for_ownership(self, resource: Model) -> None: + """ + Raise an exception if the user does not own the resource. + + Note admins are deemed owners of all resources. + + :param resource: The dashboard, dataste, chart, etc. resource + :raises SupersetSecurityException: If the current user is not an owner + """ + + # pylint: disable=import-outside-toplevel + from superset import db + + if self.is_admin(): + return + + orig_resource = db.session.query(resource.__class__).get(resource.id) + owners = orig_resource.owners if hasattr(orig_resource, "owners") else [] + + if g.user.is_anonymous or g.user not in owners: + raise SupersetSecurityException( + SupersetError( + error_type=SupersetErrorType.MISSING_OWNERSHIP_ERROR, + message=_( + "You don't have the rights to alter %(resource)s", + resource=resource, + ), + level=ErrorLevel.ERROR, + ) + ) + + def is_owner(self, resource: Model) -> bool: + """ + Returns True if the current user is an owner of the resource, False otherwise. + + :param resource: The dashboard, dataste, chart, etc. resource + :returns: Whethe the current user is an owner of the resource + """ + + try: + self.raise_for_ownership(resource) + except SupersetSecurityException: + return False + + return True + + def is_admin(self) -> bool: + """ + Returns True if the current user is an admin user, False otherwise. + + :returns: Whehther the current user is an admin user + """ + + return current_app.config["AUTH_ROLE_ADMIN"] in [ + role.name for role in self.get_user_roles() + ] diff --git a/superset/sql_lab.py b/superset/sql_lab.py index 785d16327f7f2..149feb163926c 100644 --- a/superset/sql_lab.py +++ b/superset/sql_lab.py @@ -33,12 +33,14 @@ from superset import ( app, + db, is_feature_enabled, results_backend, results_backend_use_msgpack, security_manager, ) from superset.common.db_query_status import QueryStatus +from superset.constants import QUERY_CANCEL_KEY, QUERY_EARLY_CANCEL_KEY from superset.dataframe import df_to_records from superset.db_engine_specs import BaseEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType @@ -69,7 +71,6 @@ SQL_QUERY_MUTATOR = config["SQL_QUERY_MUTATOR"] log_query = config["QUERY_LOGGER"] logger = logging.getLogger(__name__) -cancel_query_key = "cancel_query" class SqlLabException(Exception): @@ -96,8 +97,13 @@ def handle_query_error( msg = f"{prefix_message} {str(ex)}".strip() troubleshooting_link = config["TROUBLESHOOTING_LINK"] query.error_message = msg - query.status = QueryStatus.FAILED query.tmp_table_name = None + query.status = QueryStatus.FAILED + # TODO: re-enable this after updating the frontend to properly display timeout status + # if query.status != QueryStatus.TIMED_OUT: + # query.status = QueryStatus.FAILED + if not query.end_time: + query.end_time = now_as_float() # extract DB-specific errors (invalid column, eg) if isinstance(ex, SupersetErrorException): @@ -208,7 +214,6 @@ def execute_sql_statement( # pylint: disable=too-many-arguments,too-many-statem parsed_query._parsed[0], # pylint: disable=protected-access database.id, query.schema, - username=get_username(), ) ) ) @@ -287,6 +292,8 @@ def execute_sql_statement( # pylint: disable=too-many-arguments,too-many-statem # return 1 row less than increased_query data = data[:-1] except SoftTimeLimitExceeded as ex: + query.status = QueryStatus.TIMED_OUT + logger.warning("Query %d: Time limit exceeded", query.id) logger.debug("Query %d: %s", query.id, ex) raise SupersetErrorException( @@ -307,7 +314,6 @@ def execute_sql_statement( # pylint: disable=too-many-arguments,too-many-statem if query.status == QueryStatus.STOPPED: raise SqlLabQueryStoppedException() from ex - logger.error("Query %d: %s", query.id, type(ex), exc_info=True) logger.debug("Query %d: %s", query.id, ex) raise SqlLabException(db_engine_spec.extract_error_message(ex)) from ex @@ -458,15 +464,13 @@ def execute_sql_statements( # pylint: disable=too-many-arguments, too-many-loca ) ) - engine = database.get_sqla_engine(query.schema, source=QuerySource.SQL_LAB) - # Sharing a single connection and cursor across the - # execution of all statements (if many) - with closing(engine.raw_connection()) as conn: - # closing the connection closes the cursor as well + with database.get_raw_connection(query.schema, source=QuerySource.SQL_LAB) as conn: + # Sharing a single connection and cursor across the + # execution of all statements (if many) cursor = conn.cursor() cancel_query_id = db_engine_spec.get_cancel_query_id(cursor, query) if cancel_query_id is not None: - query.set_extra_json_key(cancel_query_key, cancel_query_id) + query.set_extra_json_key(QUERY_CANCEL_KEY, cancel_query_id) session.commit() statement_count = len(statements) for i, statement in enumerate(statements): @@ -475,15 +479,17 @@ def execute_sql_statements( # pylint: disable=too-many-arguments, too-many-loca if query.status == QueryStatus.STOPPED: payload.update({"status": query.status}) return payload - # For CTAS we create the table only on the last statement apply_ctas = query.select_as_cta and ( query.ctas_method == CtasMethod.VIEW or (query.ctas_method == CtasMethod.TABLE and i == len(statements) - 1) ) - # Run statement - msg = f"Running statement {i+1} out of {statement_count}" + msg = __( + "Running statement %(statement_num)s out of %(statement_count)s", + statement_num=i + 1, + statement_count=statement_count, + ) logger.info("Query %s: %s", str(query_id), msg) query.set_extra_json_key("progress", msg) session.commit() @@ -502,7 +508,11 @@ def execute_sql_statements( # pylint: disable=too-many-arguments, too-many-loca except Exception as ex: # pylint: disable=broad-except msg = str(ex) prefix_message = ( - f"[Statement {i+1} out of {statement_count}]" + __( + "Statement %(statement_num)s out of %(statement_count)s", + statement_num=i + 1, + statement_count=statement_count, + ) if statement_count > 1 else "" ) @@ -510,7 +520,6 @@ def execute_sql_statements( # pylint: disable=too-many-arguments, too-many-loca ex, query, session, payload, prefix_message ) return payload - # Commit the connection so CTA queries will create the table. conn.commit() @@ -518,6 +527,7 @@ def execute_sql_statements( # pylint: disable=too-many-arguments, too-many-loca query.rows = result_set.size query.progress = 100 query.set_extra_json_key("progress", None) + query.set_extra_json_key("columns", result_set.columns) if query.select_as_cta: query.select_sql = database.select_star( query.tmp_table_name, @@ -602,7 +612,7 @@ def cancel_query(query: Query) -> bool: """ Cancel a running query. - Note some engines implicitly handle the cancelation of a query and thus no expliicit + Note some engines implicitly handle the cancelation of a query and thus no explicit action is required. :param query: Query to cancel @@ -612,14 +622,24 @@ def cancel_query(query: Query) -> bool: if query.database.db_engine_spec.has_implicit_cancel(): return True - cancel_query_id = query.extra.get(cancel_query_key) + # Some databases may need to make preparations for query cancellation + query.database.db_engine_spec.prepare_cancel_query(query, db.session) + + if query.extra.get(QUERY_EARLY_CANCEL_KEY): + # Query has been cancelled prior to being able to set the cancel key. + # This can happen if the query cancellation key can only be acquired after the + # query has been executed + return True + + cancel_query_id = query.extra.get(QUERY_CANCEL_KEY) if cancel_query_id is None: return False - engine = query.database.get_sqla_engine(query.schema, source=QuerySource.SQL_LAB) - - with closing(engine.raw_connection()) as conn: - with closing(conn.cursor()) as cursor: - return query.database.db_engine_spec.cancel_query( - cursor, query, cancel_query_id - ) + with query.database.get_sqla_engine_with_context( + query.schema, source=QuerySource.SQL_LAB + ) as engine: + with closing(engine.raw_connection()) as conn: + with closing(conn.cursor()) as cursor: + return query.database.db_engine_spec.cancel_query( + cursor, query, cancel_query_id + ) diff --git a/superset/sql_parse.py b/superset/sql_parse.py index b585810f785a2..ab2f04417249c 100644 --- a/superset/sql_parse.py +++ b/superset/sql_parse.py @@ -494,7 +494,7 @@ class InsertRLSState(str, Enum): def has_table_query(token_list: TokenList) -> bool: """ - Return if a stament has a query reading from a table. + Return if a statement has a query reading from a table. >>> has_table_query(sqlparse.parse("COUNT(*)")[0]) False @@ -553,7 +553,6 @@ def get_rls_for_table( candidate: Token, database_id: int, default_schema: Optional[str], - username: Optional[str] = None, ) -> Optional[TokenList]: """ Given a table name, return any associated RLS predicates. @@ -586,7 +585,7 @@ def get_rls_for_table( template_processor = dataset.get_template_processor() predicate = " AND ".join( str(filter_) - for filter_ in dataset.get_sqla_row_level_filters(template_processor, username) + for filter_ in dataset.get_sqla_row_level_filters(template_processor) ) if not predicate: return None @@ -601,7 +600,6 @@ def insert_rls( token_list: TokenList, database_id: int, default_schema: Optional[str], - username: Optional[str] = None, ) -> TokenList: """ Update a statement inplace applying any associated RLS predicates. @@ -623,7 +621,7 @@ def insert_rls( elif state == InsertRLSState.SEEN_SOURCE and ( isinstance(token, Identifier) or token.ttype == Keyword ): - rls = get_rls_for_table(token, database_id, default_schema, username) + rls = get_rls_for_table(token, database_id, default_schema) if rls: state = InsertRLSState.FOUND_TABLE diff --git a/superset/sql_validators/presto_db.py b/superset/sql_validators/presto_db.py index 70b324c900736..5bc844751b83b 100644 --- a/superset/sql_validators/presto_db.py +++ b/superset/sql_validators/presto_db.py @@ -162,16 +162,20 @@ def validate( statements = parsed_query.get_statements() logger.info("Validating %i statement(s)", len(statements)) - engine = database.get_sqla_engine(schema, source=QuerySource.SQL_LAB) - # Sharing a single connection and cursor across the - # execution of all statements (if many) - annotations: List[SQLValidationAnnotation] = [] - with closing(engine.raw_connection()) as conn: - cursor = conn.cursor() - for statement in parsed_query.get_statements(): - annotation = cls.validate_statement(statement, database, cursor) - if annotation: - annotations.append(annotation) - logger.debug("Validation found %i error(s)", len(annotations)) + # todo(hughhh): update this to use new database.get_raw_connection() + # this function keeps stalling CI + with database.get_sqla_engine_with_context( + schema, source=QuerySource.SQL_LAB + ) as engine: + # Sharing a single connection and cursor across the + # execution of all statements (if many) + annotations: List[SQLValidationAnnotation] = [] + with closing(engine.raw_connection()) as conn: + cursor = conn.cursor() + for statement in parsed_query.get_statements(): + annotation = cls.validate_statement(statement, database, cursor) + if annotation: + annotations.append(annotation) + logger.debug("Validation found %i error(s)", len(annotations)) return annotations diff --git a/superset/sqllab/api.py b/superset/sqllab/api.py new file mode 100644 index 0000000000000..afe68323fb6b0 --- /dev/null +++ b/superset/sqllab/api.py @@ -0,0 +1,311 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging +from typing import Any, cast, Dict, Optional +from urllib import parse + +import simplejson as json +from flask import request +from flask_appbuilder.api import expose, protect, rison +from flask_appbuilder.models.sqla.interface import SQLAInterface +from marshmallow import ValidationError + +from superset import app, is_feature_enabled +from superset.databases.dao import DatabaseDAO +from superset.extensions import event_logger +from superset.jinja_context import get_template_processor +from superset.models.sql_lab import Query +from superset.queries.dao import QueryDAO +from superset.sql_lab import get_sql_results +from superset.sqllab.command_status import SqlJsonExecutionStatus +from superset.sqllab.commands.execute import CommandResult, ExecuteSqlCommand +from superset.sqllab.commands.export import SqlResultExportCommand +from superset.sqllab.commands.results import SqlExecutionResultsCommand +from superset.sqllab.exceptions import ( + QueryIsForbiddenToAccessException, + SqlLabException, +) +from superset.sqllab.execution_context_convertor import ExecutionContextConvertor +from superset.sqllab.query_render import SqlQueryRenderImpl +from superset.sqllab.schemas import ( + ExecutePayloadSchema, + QueryExecutionResponseSchema, + sql_lab_get_results_schema, +) +from superset.sqllab.sql_json_executer import ( + ASynchronousSqlJsonExecutor, + SqlJsonExecutor, + SynchronousSqlJsonExecutor, +) +from superset.sqllab.sqllab_execution_context import SqlJsonExecutionContext +from superset.sqllab.validators import CanAccessQueryValidatorImpl +from superset.superset_typing import FlaskResponse +from superset.utils import core as utils +from superset.views.base import CsvResponse, generate_download_headers, json_success +from superset.views.base_api import BaseSupersetApi, requires_json, statsd_metrics + +config = app.config +logger = logging.getLogger(__name__) + + +class SqlLabRestApi(BaseSupersetApi): + datamodel = SQLAInterface(Query) + + resource_name = "sqllab" + allow_browser_login = True + + class_permission_name = "Query" + + execute_model_schema = ExecutePayloadSchema() + + apispec_parameter_schemas = { + "sql_lab_get_results_schema": sql_lab_get_results_schema, + } + openapi_spec_tag = "SQL Lab" + openapi_spec_component_schemas = ( + ExecutePayloadSchema, + QueryExecutionResponseSchema, + ) + + @expose("/export/<string:client_id>/") + @protect() + @statsd_metrics + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" + f".export_csv", + log_to_statsd=False, + ) + def export_csv(self, client_id: str) -> CsvResponse: + """Exports the SQL query results to a CSV + --- + get: + summary: >- + Exports the SQL query results to a CSV + parameters: + - in: path + schema: + type: integer + name: client_id + description: The SQL query result identifier + responses: + 200: + description: SQL query results + content: + text/csv: + schema: + type: string + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 403: + $ref: '#/components/responses/403' + 404: + $ref: '#/components/responses/404' + 500: + $ref: '#/components/responses/500' + """ + result = SqlResultExportCommand(client_id=client_id).run() + + query, data, row_count = result["query"], result["data"], result["count"] + + quoted_csv_name = parse.quote(query.name) + response = CsvResponse( + data, headers=generate_download_headers("csv", quoted_csv_name) + ) + event_info = { + "event_type": "data_export", + "client_id": client_id, + "row_count": row_count, + "database": query.database.name, + "schema": query.schema, + "sql": query.sql, + "exported_format": "csv", + } + event_rep = repr(event_info) + logger.debug( + "CSV exported: %s", event_rep, extra={"superset_event": event_info} + ) + return response + + @expose("/results/") + @protect() + @statsd_metrics + @rison(sql_lab_get_results_schema) + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" + f".get_results", + log_to_statsd=False, + ) + def get_results(self, **kwargs: Any) -> FlaskResponse: + """Gets the result of a SQL query execution + --- + get: + summary: >- + Gets the result of a SQL query execution + parameters: + - in: query + name: q + content: + application/json: + schema: + $ref: '#/components/schemas/sql_lab_get_results_schema' + responses: + 200: + description: SQL query execution result + content: + application/json: + schema: + $ref: '#/components/schemas/QueryExecutionResponseSchema' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 403: + $ref: '#/components/responses/403' + 404: + $ref: '#/components/responses/404' + 410: + $ref: '#/components/responses/410' + 500: + $ref: '#/components/responses/500' + """ + params = kwargs["rison"] + key = params.get("key") + rows = params.get("rows") + result = SqlExecutionResultsCommand(key=key, rows=rows).run() + # return the result without special encoding + return json_success( + json.dumps( + result, default=utils.json_iso_dttm_ser, ignore_nan=True, encoding=None + ), + 200, + ) + + @expose("/execute/", methods=["POST"]) + @protect() + @statsd_metrics + @requires_json + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" + f".get_results", + log_to_statsd=False, + ) + def execute_sql_query(self) -> FlaskResponse: + """Executes a SQL query + --- + post: + description: >- + Starts the execution of a SQL query + requestBody: + description: SQL query and params + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ExecutePayloadSchema' + responses: + 200: + description: Query execution result + content: + application/json: + schema: + $ref: '#/components/schemas/QueryExecutionResponseSchema' + 202: + description: Query execution result, query still running + content: + application/json: + schema: + $ref: '#/components/schemas/QueryExecutionResponseSchema' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 403: + $ref: '#/components/responses/403' + 404: + $ref: '#/components/responses/404' + 500: + $ref: '#/components/responses/500' + """ + try: + self.execute_model_schema.load(request.json) + except ValidationError as error: + return self.response_400(message=error.messages) + + try: + log_params = { + "user_agent": cast(Optional[str], request.headers.get("USER_AGENT")) + } + execution_context = SqlJsonExecutionContext(request.json) + command = self._create_sql_json_command(execution_context, log_params) + command_result: CommandResult = command.run() + + response_status = ( + 202 + if command_result["status"] == SqlJsonExecutionStatus.QUERY_IS_RUNNING + else 200 + ) + # return the execution result without special encoding + return json_success(command_result["payload"], response_status) + except SqlLabException as ex: + payload = {"errors": [ex.to_dict()]} + + response_status = ( + 403 if isinstance(ex, QueryIsForbiddenToAccessException) else ex.status + ) + return self.response(response_status, **payload) + + @staticmethod + def _create_sql_json_command( + execution_context: SqlJsonExecutionContext, log_params: Optional[Dict[str, Any]] + ) -> ExecuteSqlCommand: + query_dao = QueryDAO() + sql_json_executor = SqlLabRestApi._create_sql_json_executor( + execution_context, query_dao + ) + execution_context_convertor = ExecutionContextConvertor() + execution_context_convertor.set_max_row_in_display( + int(config.get("DISPLAY_MAX_ROW")) # type: ignore + ) + return ExecuteSqlCommand( + execution_context, + query_dao, + DatabaseDAO(), + CanAccessQueryValidatorImpl(), + SqlQueryRenderImpl(get_template_processor), + sql_json_executor, + execution_context_convertor, + config["SQLLAB_CTAS_NO_LIMIT"], + log_params, + ) + + @staticmethod + def _create_sql_json_executor( + execution_context: SqlJsonExecutionContext, query_dao: QueryDAO + ) -> SqlJsonExecutor: + sql_json_executor: SqlJsonExecutor + if execution_context.is_run_asynchronous(): + sql_json_executor = ASynchronousSqlJsonExecutor(query_dao, get_sql_results) + else: + sql_json_executor = SynchronousSqlJsonExecutor( + query_dao, + get_sql_results, + config.get("SQLLAB_TIMEOUT"), # type: ignore + is_feature_enabled("SQLLAB_BACKEND_PERSISTENCE"), + ) + return sql_json_executor diff --git a/superset/sqllab/commands/__init__.py b/superset/sqllab/commands/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/superset/sqllab/commands/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/superset/sqllab/command.py b/superset/sqllab/commands/execute.py similarity index 96% rename from superset/sqllab/command.py rename to superset/sqllab/commands/execute.py index ce41eb6de230f..35a761fab4018 100644 --- a/superset/sqllab/command.py +++ b/superset/sqllab/commands/execute.py @@ -26,7 +26,11 @@ from superset.common.db_query_status import QueryStatus from superset.dao.exceptions import DAOCreateFailedError from superset.errors import SupersetErrorType -from superset.exceptions import SupersetErrorsException, SupersetGenericErrorException +from superset.exceptions import ( + SupersetErrorException, + SupersetErrorsException, + SupersetGenericErrorException, +) from superset.models.core import Database from superset.models.sql_lab import Query from superset.sqllab.command_status import SqlJsonExecutionStatus @@ -110,7 +114,9 @@ def run( # pylint: disable=too-many-statements,useless-suppression "status": status, "payload": self._execution_context_convertor.serialize_payload(), } - except (SqlLabException, SupersetErrorsException) as ex: + except (SupersetErrorException, SupersetErrorsException) as ex: + # to make sure we raising the original + # SupersetErrorsException || SupersetErrorsException raise ex except Exception as ex: raise SqlLabException(self._execution_context, exception=ex) from ex diff --git a/superset/sqllab/commands/export.py b/superset/sqllab/commands/export.py new file mode 100644 index 0000000000000..e9559be3b97f4 --- /dev/null +++ b/superset/sqllab/commands/export.py @@ -0,0 +1,134 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import logging +from typing import Any, cast, List, TypedDict + +import pandas as pd +from flask_babel import gettext as __ + +from superset import app, db, results_backend, results_backend_use_msgpack +from superset.commands.base import BaseCommand +from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.exceptions import SupersetErrorException, SupersetSecurityException +from superset.models.sql_lab import Query +from superset.sql_parse import ParsedQuery +from superset.sqllab.limiting_factor import LimitingFactor +from superset.utils import core as utils, csv +from superset.views.utils import _deserialize_results_payload + +config = app.config + +logger = logging.getLogger(__name__) + + +class SqlExportResult(TypedDict): + query: Query + count: int + data: List[Any] + + +class SqlResultExportCommand(BaseCommand): + _client_id: str + _query: Query + + def __init__( + self, + client_id: str, + ) -> None: + self._client_id = client_id + + def validate(self) -> None: + self._query = ( + db.session.query(Query).filter_by(client_id=self._client_id).one_or_none() + ) + if self._query is None: + raise SupersetErrorException( + SupersetError( + message=__( + "The query associated with these results could not be found. " + "You need to re-run the original query." + ), + error_type=SupersetErrorType.RESULTS_BACKEND_ERROR, + level=ErrorLevel.ERROR, + ), + status=404, + ) + + try: + self._query.raise_for_access() + except SupersetSecurityException as ex: + raise SupersetErrorException( + SupersetError( + message=__("Cannot access the query"), + error_type=SupersetErrorType.QUERY_SECURITY_ACCESS_ERROR, + level=ErrorLevel.ERROR, + ), + status=403, + ) from ex + + def run( + self, + ) -> SqlExportResult: + self.validate() + blob = None + if results_backend and self._query.results_key: + logger.info( + "Fetching CSV from results backend [%s]", self._query.results_key + ) + blob = results_backend.get(self._query.results_key) + if blob: + logger.info("Decompressing") + payload = utils.zlib_decompress( + blob, decode=not results_backend_use_msgpack + ) + obj = _deserialize_results_payload( + payload, self._query, cast(bool, results_backend_use_msgpack) + ) + + df = pd.DataFrame( + data=obj["data"], + dtype=object, + columns=[c["name"] for c in obj["columns"]], + ) + + logger.info("Using pandas to convert to CSV") + else: + logger.info("Running a query to turn into CSV") + if self._query.select_sql: + sql = self._query.select_sql + limit = None + else: + sql = self._query.executed_sql + limit = ParsedQuery(sql).limit + if limit is not None and self._query.limiting_factor in { + LimitingFactor.QUERY, + LimitingFactor.DROPDOWN, + LimitingFactor.QUERY_AND_DROPDOWN, + }: + # remove extra row from `increased_limit` + limit -= 1 + df = self._query.database.get_df(sql, self._query.schema)[:limit] + + csv_data = csv.df_to_escaped_csv(df, index=False, **config["CSV_EXPORT"]) + + return { + "query": self._query, + "count": len(df.index), + "data": csv_data, + } diff --git a/superset/sqllab/commands/results.py b/superset/sqllab/commands/results.py new file mode 100644 index 0000000000000..d6c415a09fef6 --- /dev/null +++ b/superset/sqllab/commands/results.py @@ -0,0 +1,130 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import logging +from typing import Any, cast, Dict, Optional + +from flask_babel import gettext as __ + +from superset import app, db, results_backend, results_backend_use_msgpack +from superset.commands.base import BaseCommand +from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.exceptions import SerializationError, SupersetErrorException +from superset.models.sql_lab import Query +from superset.sqllab.utils import apply_display_max_row_configuration_if_require +from superset.utils import core as utils +from superset.utils.dates import now_as_float +from superset.views.utils import _deserialize_results_payload + +config = app.config +SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT = config["SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT"] +stats_logger = config["STATS_LOGGER"] + +logger = logging.getLogger(__name__) + + +class SqlExecutionResultsCommand(BaseCommand): + _key: str + _rows: Optional[int] + _blob: Any + _query: Query + + def __init__( + self, + key: str, + rows: Optional[int] = None, + ) -> None: + self._key = key + self._rows = rows + + def validate(self) -> None: + if not results_backend: + raise SupersetErrorException( + SupersetError( + message=__("Results backend is not configured."), + error_type=SupersetErrorType.RESULTS_BACKEND_NOT_CONFIGURED_ERROR, + level=ErrorLevel.ERROR, + ) + ) + + read_from_results_backend_start = now_as_float() + self._blob = results_backend.get(self._key) + stats_logger.timing( + "sqllab.query.results_backend_read", + now_as_float() - read_from_results_backend_start, + ) + + if not self._blob: + raise SupersetErrorException( + SupersetError( + message=__( + "Data could not be retrieved from the results backend. You " + "need to re-run the original query." + ), + error_type=SupersetErrorType.RESULTS_BACKEND_ERROR, + level=ErrorLevel.ERROR, + ), + status=410, + ) + + self._query = ( + db.session.query(Query).filter_by(results_key=self._key).one_or_none() + ) + if self._query is None: + raise SupersetErrorException( + SupersetError( + message=__( + "The query associated with these results could not be found. " + "You need to re-run the original query." + ), + error_type=SupersetErrorType.RESULTS_BACKEND_ERROR, + level=ErrorLevel.ERROR, + ), + status=404, + ) + + def run( + self, + ) -> Dict[str, Any]: + """Runs arbitrary sql and returns data as json""" + self.validate() + payload = utils.zlib_decompress( + self._blob, decode=not results_backend_use_msgpack + ) + try: + obj = _deserialize_results_payload( + payload, self._query, cast(bool, results_backend_use_msgpack) + ) + except SerializationError as ex: + raise SupersetErrorException( + SupersetError( + message=__( + "Data could not be deserialized from the results backend. The " + "storage format might have changed, rendering the old data " + "stake. You need to re-run the original query." + ), + error_type=SupersetErrorType.RESULTS_BACKEND_ERROR, + level=ErrorLevel.ERROR, + ), + status=404, + ) from ex + + if self._rows: + obj = apply_display_max_row_configuration_if_require(obj, self._rows) + + return obj diff --git a/superset/sqllab/exceptions.py b/superset/sqllab/exceptions.py index ac632d731d1ba..c0096d5db6b47 100644 --- a/superset/sqllab/exceptions.py +++ b/superset/sqllab/exceptions.py @@ -19,13 +19,13 @@ import os from typing import Optional, TYPE_CHECKING +from flask_babel import lazy_gettext as _ + from superset.errors import SupersetError, SupersetErrorType from superset.exceptions import SupersetException -MSG_FORMAT = "Failed to execute {}" - if TYPE_CHECKING: - from superset.utils.sqllab_execution_context import SqlJsonExecutionContext + from superset.sqllab.sqllab_execution_context import SqlJsonExecutionContext class SqlLabException(SupersetException): @@ -61,7 +61,10 @@ def __init__( # pylint: disable=too-many-arguments super().__init__(self._generate_message(), exception, error_type) def _generate_message(self) -> str: - msg = MSG_FORMAT.format(self.sql_json_execution_context.get_query_details()) + msg = _( + "Failed to execute %(query)s", + query=self.sql_json_execution_context.get_query_details(), + ) if self.failed_reason_msg: msg = msg + self.failed_reason_msg if self.suggestion_help_msg is not None: diff --git a/superset/sqllab/query_render.py b/superset/sqllab/query_render.py index c2f96542898d9..2854a7e390774 100644 --- a/superset/sqllab/query_render.py +++ b/superset/sqllab/query_render.py @@ -25,7 +25,7 @@ from superset import is_feature_enabled from superset.errors import SupersetErrorType -from superset.sqllab.command import SqlQueryRender +from superset.sqllab.commands.execute import SqlQueryRender from superset.sqllab.exceptions import SqlLabException from superset.utils import core as utils @@ -35,7 +35,7 @@ from superset.jinja_context import BaseTemplateProcessor from superset.sqllab.sqllab_execution_context import SqlJsonExecutionContext -PARAMETER_MISSING_ERR = ( +PARAMETER_MISSING_ERR = __( "Please check your template parameters for syntax errors and make sure " "they match across your SQL query and Set Parameters. Then, try running " "your query again." diff --git a/superset/sqllab/schemas.py b/superset/sqllab/schemas.py new file mode 100644 index 0000000000000..f238fda5c918f --- /dev/null +++ b/superset/sqllab/schemas.py @@ -0,0 +1,83 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from marshmallow import fields, Schema + +sql_lab_get_results_schema = { + "type": "object", + "properties": { + "key": {"type": "string"}, + }, + "required": ["key"], +} + + +class ExecutePayloadSchema(Schema): + database_id = fields.Integer(required=True) + sql = fields.String(required=True) + client_id = fields.String(allow_none=True) + queryLimit = fields.Integer(allow_none=True) + sql_editor_id = fields.String(allow_none=True) + schema = fields.String(allow_none=True) + tab = fields.String(allow_none=True) + ctas_method = fields.String(allow_none=True) + templateParams = fields.String(allow_none=True) + tmp_table_name = fields.String(allow_none=True) + select_as_cta = fields.Boolean(allow_none=True) + json = fields.Boolean(allow_none=True) + runAsync = fields.Boolean(allow_none=True) + expand_data = fields.Boolean(allow_none=True) + + +class QueryResultSchema(Schema): + changedOn = fields.DateTime() + changed_on = fields.String() + dbId = fields.Integer() + db = fields.String() # pylint: disable=invalid-name + endDttm = fields.Float() + errorMessage = fields.String(allow_none=True) + executedSql = fields.String() + id = fields.String() + queryId = fields.Integer() + limit = fields.Integer() + limitingFactor = fields.String() + progress = fields.Integer() + rows = fields.Integer() + schema = fields.String() + ctas = fields.Boolean() + serverId = fields.Integer() + sql = fields.String() + sqlEditorId = fields.String() + startDttm = fields.Float() + state = fields.String() + tab = fields.String() + tempSchema = fields.String(allow_none=True) + tempTable = fields.String(allow_none=True) + userId = fields.Integer() + user = fields.String() + resultsKey = fields.String() + trackingUrl = fields.String(allow_none=True) + extra = fields.Dict(keys=fields.String()) + + +class QueryExecutionResponseSchema(Schema): + status = fields.String() + data = fields.List(fields.Dict()) + columns = fields.List(fields.Dict()) + selected_columns = fields.List(fields.Dict()) + expanded_columns = fields.List(fields.Dict()) + query = fields.Nested(QueryResultSchema) + query_id = fields.Integer() diff --git a/superset/sqllab/sqllab_execution_context.py b/superset/sqllab/sqllab_execution_context.py index f8e9ac64dfa26..644c978b32765 100644 --- a/superset/sqllab/sqllab_execution_context.py +++ b/superset/sqllab/sqllab_execution_context.py @@ -28,7 +28,7 @@ from superset.models.sql_lab import Query from superset.sql_parse import CtasMethod from superset.utils import core as utils -from superset.utils.core import apply_max_row_limit +from superset.utils.core import apply_max_row_limit, get_user_id from superset.utils.dates import now_as_float from superset.views.utils import get_cta_schema_name @@ -64,7 +64,7 @@ def __init__(self, query_params: Dict[str, Any]): self.create_table_as_select = None self.database = None self._init_from_query_params(query_params) - self.user_id = self._get_user_id() + self.user_id = get_user_id() self.client_id_or_short_id = cast(str, self.client_id or utils.shortid()[:10]) def set_query(self, query: Query) -> None: @@ -111,12 +111,6 @@ def _get_limit_param(query_params: Dict[str, Any]) -> int: limit = 0 return limit - def _get_user_id(self) -> Optional[int]: # pylint: disable=no-self-use - try: - return g.user.get_id() if g.user else None - except RuntimeError: - return None - def is_run_asynchronous(self) -> bool: return self.async_flag diff --git a/superset/sqllab/validators.py b/superset/sqllab/validators.py index 726a2760e291d..5bc8a622531c2 100644 --- a/superset/sqllab/validators.py +++ b/superset/sqllab/validators.py @@ -20,7 +20,7 @@ from typing import TYPE_CHECKING from superset import security_manager -from superset.sqllab.command import CanAccessQueryValidator +from superset.sqllab.commands.execute import CanAccessQueryValidator if TYPE_CHECKING: from superset.models.sql_lab import Query diff --git a/superset/tags/__init__.py b/superset/tags/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/superset/tags/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/superset/tags/core.py b/superset/tags/core.py new file mode 100644 index 0000000000000..6c4f56a2e66f2 --- /dev/null +++ b/superset/tags/core.py @@ -0,0 +1,89 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# pylint: disable=import-outside-toplevel + + +def register_sqla_event_listeners() -> None: + import sqlalchemy as sqla + + from superset.connectors.sqla.models import SqlaTable + from superset.models.core import FavStar + from superset.models.dashboard import Dashboard + from superset.models.slice import Slice + from superset.models.sql_lab import SavedQuery + from superset.tags.models import ( + ChartUpdater, + DashboardUpdater, + DatasetUpdater, + FavStarUpdater, + QueryUpdater, + ) + + sqla.event.listen(SqlaTable, "after_insert", DatasetUpdater.after_insert) + sqla.event.listen(SqlaTable, "after_update", DatasetUpdater.after_update) + sqla.event.listen(SqlaTable, "after_delete", DatasetUpdater.after_delete) + + sqla.event.listen(Slice, "after_insert", ChartUpdater.after_insert) + sqla.event.listen(Slice, "after_update", ChartUpdater.after_update) + sqla.event.listen(Slice, "after_delete", ChartUpdater.after_delete) + + sqla.event.listen(Dashboard, "after_insert", DashboardUpdater.after_insert) + sqla.event.listen(Dashboard, "after_update", DashboardUpdater.after_update) + sqla.event.listen(Dashboard, "after_delete", DashboardUpdater.after_delete) + + sqla.event.listen(FavStar, "after_insert", FavStarUpdater.after_insert) + sqla.event.listen(FavStar, "after_delete", FavStarUpdater.after_delete) + + sqla.event.listen(SavedQuery, "after_insert", QueryUpdater.after_insert) + sqla.event.listen(SavedQuery, "after_update", QueryUpdater.after_update) + sqla.event.listen(SavedQuery, "after_delete", QueryUpdater.after_delete) + + +def clear_sqla_event_listeners() -> None: + import sqlalchemy as sqla + + from superset.connectors.sqla.models import SqlaTable + from superset.models.core import FavStar + from superset.models.dashboard import Dashboard + from superset.models.slice import Slice + from superset.models.sql_lab import SavedQuery + from superset.tags.models import ( + ChartUpdater, + DashboardUpdater, + DatasetUpdater, + FavStarUpdater, + QueryUpdater, + ) + + sqla.event.remove(SqlaTable, "after_insert", DatasetUpdater.after_insert) + sqla.event.remove(SqlaTable, "after_update", DatasetUpdater.after_update) + sqla.event.remove(SqlaTable, "after_delete", DatasetUpdater.after_delete) + + sqla.event.remove(Slice, "after_insert", ChartUpdater.after_insert) + sqla.event.remove(Slice, "after_update", ChartUpdater.after_update) + sqla.event.remove(Slice, "after_delete", ChartUpdater.after_delete) + + sqla.event.remove(Dashboard, "after_insert", DashboardUpdater.after_insert) + sqla.event.remove(Dashboard, "after_update", DashboardUpdater.after_update) + sqla.event.remove(Dashboard, "after_delete", DashboardUpdater.after_delete) + + sqla.event.remove(FavStar, "after_insert", FavStarUpdater.after_insert) + sqla.event.remove(FavStar, "after_delete", FavStarUpdater.after_delete) + + sqla.event.remove(SavedQuery, "after_insert", QueryUpdater.after_insert) + sqla.event.remove(SavedQuery, "after_update", QueryUpdater.after_update) + sqla.event.remove(SavedQuery, "after_delete", QueryUpdater.after_delete) diff --git a/superset/models/tags.py b/superset/tags/models.py similarity index 84% rename from superset/models/tags.py rename to superset/tags/models.py index 528206e672f62..89505146e2598 100644 --- a/superset/models/tags.py +++ b/superset/tags/models.py @@ -14,7 +14,13 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from __future__ import absolute_import, division, print_function, unicode_literals +from __future__ import ( + absolute_import, + annotations, + division, + print_function, + unicode_literals, +) import enum from typing import List, Optional, TYPE_CHECKING, Union @@ -28,6 +34,7 @@ from superset.models.helpers import AuditMixinNullable if TYPE_CHECKING: + from superset.connectors.sqla.models import SqlaTable from superset.models.core import FavStar from superset.models.dashboard import Dashboard from superset.models.slice import Slice @@ -41,7 +48,7 @@ class TagTypes(enum.Enum): """ Types for tags. - Objects (queries, charts and dashboards) will have with implicit tags based + Objects (queries, charts, dashboards, and datasets) will have with implicit tags based on metadata: types, owners and who favorited them. This way, user "alice" can find all their objects by querying for the tag `owner:alice`. """ @@ -64,11 +71,12 @@ class ObjectTypes(enum.Enum): query = 1 chart = 2 dashboard = 3 + dataset = 4 class Tag(Model, AuditMixinNullable): - """A tag attached to an object (query, chart or dashboard).""" + """A tag attached to an object (query, chart, dashboard, or dataset).""" __tablename__ = "tag" id = Column(Integer, primary_key=True) @@ -103,6 +111,7 @@ def get_object_type(class_name: str) -> ObjectTypes: "slice": ObjectTypes.chart, "dashboard": ObjectTypes.dashboard, "query": ObjectTypes.query, + "dataset": ObjectTypes.dataset, } try: return mapping[class_name.lower()] @@ -116,13 +125,15 @@ class ObjectUpdater: @classmethod def get_owners_ids( - cls, target: Union["Dashboard", "FavStar", "Slice"] + cls, target: Union[Dashboard, FavStar, Slice, Query, SqlaTable] ) -> List[int]: raise NotImplementedError("Subclass should implement `get_owners_ids`") @classmethod def _add_owners( - cls, session: Session, target: Union["Dashboard", "FavStar", "Slice"] + cls, + session: Session, + target: Union[Dashboard, FavStar, Slice, Query, SqlaTable], ) -> None: for owner_id in cls.get_owners_ids(target): name = "owner:{0}".format(owner_id) @@ -137,7 +148,7 @@ def after_insert( cls, _mapper: Mapper, connection: Connection, - target: Union["Dashboard", "FavStar", "Slice"], + target: Union[Dashboard, FavStar, Slice, Query, SqlaTable], ) -> None: session = Session(bind=connection) @@ -158,7 +169,7 @@ def after_update( cls, _mapper: Mapper, connection: Connection, - target: Union["Dashboard", "FavStar", "Slice"], + target: Union[Dashboard, FavStar, Slice, Query, SqlaTable], ) -> None: session = Session(bind=connection) @@ -187,7 +198,7 @@ def after_delete( cls, _mapper: Mapper, connection: Connection, - target: Union["Dashboard", "FavStar", "Slice"], + target: Union[Dashboard, FavStar, Slice, Query, SqlaTable], ) -> None: session = Session(bind=connection) @@ -205,7 +216,7 @@ class ChartUpdater(ObjectUpdater): object_type = "chart" @classmethod - def get_owners_ids(cls, target: "Slice") -> List[int]: + def get_owners_ids(cls, target: Slice) -> List[int]: return [owner.id for owner in target.owners] @@ -214,7 +225,7 @@ class DashboardUpdater(ObjectUpdater): object_type = "dashboard" @classmethod - def get_owners_ids(cls, target: "Dashboard") -> List[int]: + def get_owners_ids(cls, target: Dashboard) -> List[int]: return [owner.id for owner in target.owners] @@ -223,14 +234,23 @@ class QueryUpdater(ObjectUpdater): object_type = "query" @classmethod - def get_owners_ids(cls, target: "Query") -> List[int]: + def get_owners_ids(cls, target: Query) -> List[int]: return [target.user_id] +class DatasetUpdater(ObjectUpdater): + + object_type = "dataset" + + @classmethod + def get_owners_ids(cls, target: SqlaTable) -> List[int]: + return [owner.id for owner in target.owners] + + class FavStarUpdater: @classmethod def after_insert( - cls, _mapper: Mapper, connection: Connection, target: "FavStar" + cls, _mapper: Mapper, connection: Connection, target: FavStar ) -> None: session = Session(bind=connection) name = "favorited_by:{0}".format(target.user_id) @@ -246,7 +266,7 @@ def after_insert( @classmethod def after_delete( - cls, _mapper: Mapper, connection: Connection, target: "FavStar" + cls, _mapper: Mapper, connection: Connection, target: FavStar ) -> None: session = Session(bind=connection) name = "favorited_by:{0}".format(target.user_id) diff --git a/superset/tasks/async_queries.py b/superset/tasks/async_queries.py index 74adcd080c0c3..1157c5fd37e1f 100644 --- a/superset/tasks/async_queries.py +++ b/superset/tasks/async_queries.py @@ -33,6 +33,7 @@ security_manager, ) from superset.utils.cache import generate_cache_key, set_and_log_cache +from superset.utils.core import override_user from superset.views.utils import get_datasource_info, get_viz if TYPE_CHECKING: @@ -44,16 +45,6 @@ ] # TODO: new config key -def ensure_user_is_set(user_id: Optional[int]) -> None: - user_is_not_set = not (hasattr(g, "user") and g.user is not None) - if user_is_not_set and user_id is not None: - # pylint: disable=assigning-non-slot - g.user = security_manager.get_user_by_id(user_id) - elif user_is_not_set: - # pylint: disable=assigning-non-slot - g.user = security_manager.get_anonymous_user() - - def set_form_data(form_data: Dict[str, Any]) -> None: # pylint: disable=assigning-non-slot g.form_data = form_data @@ -76,30 +67,35 @@ def load_chart_data_into_cache( # pylint: disable=import-outside-toplevel from superset.charts.data.commands.get_data_command import ChartDataCommand - try: - ensure_user_is_set(job_metadata.get("user_id")) - set_form_data(form_data) - query_context = _create_query_context_from_form(form_data) - command = ChartDataCommand(query_context) - result = command.run(cache=True) - cache_key = result["cache_key"] - result_url = f"/api/v1/chart/data/{cache_key}" - async_query_manager.update_job( - job_metadata, - async_query_manager.STATUS_DONE, - result_url=result_url, - ) - except SoftTimeLimitExceeded as ex: - logger.warning("A timeout occurred while loading chart data, error: %s", ex) - raise ex - except Exception as ex: - # TODO: QueryContext should support SIP-40 style errors - error = ex.message if hasattr(ex, "message") else str(ex) # type: ignore # pylint: disable=no-member - errors = [{"message": error}] - async_query_manager.update_job( - job_metadata, async_query_manager.STATUS_ERROR, errors=errors - ) - raise ex + user = ( + security_manager.get_user_by_id(job_metadata.get("user_id")) + or security_manager.get_anonymous_user() + ) + + with override_user(user, force=False): + try: + set_form_data(form_data) + query_context = _create_query_context_from_form(form_data) + command = ChartDataCommand(query_context) + result = command.run(cache=True) + cache_key = result["cache_key"] + result_url = f"/api/v1/chart/data/{cache_key}" + async_query_manager.update_job( + job_metadata, + async_query_manager.STATUS_DONE, + result_url=result_url, + ) + except SoftTimeLimitExceeded as ex: + logger.warning("A timeout occurred while loading chart data, error: %s", ex) + raise ex + except Exception as ex: + # TODO: QueryContext should support SIP-40 style errors + error = ex.message if hasattr(ex, "message") else str(ex) # type: ignore # pylint: disable=no-member + errors = [{"message": error}] + async_query_manager.update_job( + job_metadata, async_query_manager.STATUS_ERROR, errors=errors + ) + raise ex @celery_app.task(name="load_explore_json_into_cache", soft_time_limit=query_timeout) @@ -110,53 +106,61 @@ def load_explore_json_into_cache( # pylint: disable=too-many-locals force: bool = False, ) -> None: cache_key_prefix = "ejr-" # ejr: explore_json request - try: - ensure_user_is_set(job_metadata.get("user_id")) - set_form_data(form_data) - datasource_id, datasource_type = get_datasource_info(None, None, form_data) - - # Perform a deep copy here so that below we can cache the original - # value of the form_data object. This is necessary since the viz - # objects modify the form_data object. If the modified version were - # to be cached here, it will lead to a cache miss when clients - # attempt to retrieve the value of the completed async query. - original_form_data = copy.deepcopy(form_data) - - viz_obj = get_viz( - datasource_type=cast(str, datasource_type), - datasource_id=datasource_id, - form_data=form_data, - force=force, - ) - # run query & cache results - payload = viz_obj.get_payload() - if viz_obj.has_error(payload): - raise SupersetVizException(errors=payload["errors"]) - - # Cache the original form_data value for async retrieval - cache_value = { - "form_data": original_form_data, - "response_type": response_type, - } - cache_key = generate_cache_key(cache_value, cache_key_prefix) - set_and_log_cache(cache_manager.cache, cache_key, cache_value) - result_url = f"/superset/explore_json/data/{cache_key}" - async_query_manager.update_job( - job_metadata, - async_query_manager.STATUS_DONE, - result_url=result_url, - ) - except SoftTimeLimitExceeded as ex: - logger.warning("A timeout occurred while loading explore json, error: %s", ex) - raise ex - except Exception as ex: - if isinstance(ex, SupersetVizException): - errors = ex.errors # pylint: disable=no-member - else: - error = ex.message if hasattr(ex, "message") else str(ex) # type: ignore # pylint: disable=no-member - errors = [error] - async_query_manager.update_job( - job_metadata, async_query_manager.STATUS_ERROR, errors=errors - ) - raise ex + user = ( + security_manager.get_user_by_id(job_metadata.get("user_id")) + or security_manager.get_anonymous_user() + ) + + with override_user(user, force=False): + try: + set_form_data(form_data) + datasource_id, datasource_type = get_datasource_info(None, None, form_data) + + # Perform a deep copy here so that below we can cache the original + # value of the form_data object. This is necessary since the viz + # objects modify the form_data object. If the modified version were + # to be cached here, it will lead to a cache miss when clients + # attempt to retrieve the value of the completed async query. + original_form_data = copy.deepcopy(form_data) + + viz_obj = get_viz( + datasource_type=cast(str, datasource_type), + datasource_id=datasource_id, + form_data=form_data, + force=force, + ) + # run query & cache results + payload = viz_obj.get_payload() + if viz_obj.has_error(payload): + raise SupersetVizException(errors=payload["errors"]) + + # Cache the original form_data value for async retrieval + cache_value = { + "form_data": original_form_data, + "response_type": response_type, + } + cache_key = generate_cache_key(cache_value, cache_key_prefix) + set_and_log_cache(cache_manager.cache, cache_key, cache_value) + result_url = f"/superset/explore_json/data/{cache_key}" + async_query_manager.update_job( + job_metadata, + async_query_manager.STATUS_DONE, + result_url=result_url, + ) + except SoftTimeLimitExceeded as ex: + logger.warning( + "A timeout occurred while loading explore json, error: %s", ex + ) + raise ex + except Exception as ex: + if isinstance(ex, SupersetVizException): + errors = ex.errors # pylint: disable=no-member + else: + error = ex.message if hasattr(ex, "message") else str(ex) # type: ignore # pylint: disable=no-member + errors = [error] + + async_query_manager.update_job( + job_metadata, async_query_manager.STATUS_ERROR, errors=errors + ) + raise ex diff --git a/superset/tasks/cache.py b/superset/tasks/cache.py index 137ec068e8843..bdbf8add7eaba 100644 --- a/superset/tasks/cache.py +++ b/superset/tasks/cache.py @@ -28,7 +28,7 @@ from superset.models.core import Log from superset.models.dashboard import Dashboard from superset.models.slice import Slice -from superset.models.tags import Tag, TaggedObject +from superset.tags.models import Tag, TaggedObject from superset.utils.date_parser import parse_human_datetime from superset.utils.machine_auth import MachineAuthProvider @@ -55,7 +55,7 @@ class Strategy: # pylint: disable=too-few-public-methods Strategies can be configured in `superset/config.py`: - CELERYBEAT_SCHEDULE = { + beat_schedule = { 'cache-warmup-hourly': { 'task': 'cache-warmup', 'schedule': crontab(minute=1, hour='*'), # @hourly @@ -82,7 +82,7 @@ class DummyStrategy(Strategy): # pylint: disable=too-few-public-methods This is a dummy strategy that will fetch all charts. Can be configured by: - CELERYBEAT_SCHEDULE = { + beat_schedule = { 'cache-warmup-hourly': { 'task': 'cache-warmup', 'schedule': crontab(minute=1, hour='*'), # @hourly @@ -105,7 +105,7 @@ class TopNDashboardsStrategy(Strategy): # pylint: disable=too-few-public-method """ Warm up charts in the top-n dashboards. - CELERYBEAT_SCHEDULE = { + beat_schedule = { 'cache-warmup-hourly': { 'task': 'cache-warmup', 'schedule': crontab(minute=1, hour='*'), # @hourly @@ -151,7 +151,7 @@ class DashboardTagsStrategy(Strategy): # pylint: disable=too-few-public-methods """ Warm up charts in dashboards with custom tags. - CELERYBEAT_SCHEDULE = { + beat_schedule = { 'cache-warmup-hourly': { 'task': 'cache-warmup', 'schedule': crontab(minute=1, hour='*'), # @hourly diff --git a/superset/tasks/exceptions.py b/superset/tasks/exceptions.py new file mode 100644 index 0000000000000..6698661754e5e --- /dev/null +++ b/superset/tasks/exceptions.py @@ -0,0 +1,24 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from flask_babel import lazy_gettext as _ + +from superset.exceptions import SupersetException + + +class ExecutorNotFoundError(SupersetException): + message = _("Scheduled task executor not found") diff --git a/superset/tasks/scheduler.py b/superset/tasks/scheduler.py index 7f0ea61c990c0..b3efa240fa52d 100644 --- a/superset/tasks/scheduler.py +++ b/superset/tasks/scheduler.py @@ -16,6 +16,7 @@ # under the License. import logging +from celery import Celery from celery.exceptions import SoftTimeLimitExceeded from dateutil import parser @@ -28,6 +29,8 @@ from superset.reports.dao import ReportScheduleDAO from superset.tasks.cron_util import cron_schedule_window from superset.utils.celery import session_scope +from superset.utils.core import LoggerLevel +from superset.utils.log import get_logger_from_status logger = logging.getLogger(__name__) @@ -66,16 +69,21 @@ def scheduler() -> None: active_schedule.id, schedule, ), - **async_options + **async_options, ) -@celery_app.task(name="reports.execute") -def execute(report_schedule_id: int, scheduled_dttm: str) -> None: +@celery_app.task(name="reports.execute", bind=True) +def execute(self: Celery.task, report_schedule_id: int, scheduled_dttm: str) -> None: task_id = None try: task_id = execute.request.id scheduled_dttm_ = parser.parse(scheduled_dttm) + logger.info( + "Executing alert/report, task id: %s, scheduled_dttm: %s", + task_id, + scheduled_dttm, + ) AsyncExecuteReportScheduleCommand( task_id, report_schedule_id, @@ -85,10 +93,17 @@ def execute(report_schedule_id: int, scheduled_dttm: str) -> None: logger.exception( "An unexpected occurred while executing the report: %s", task_id ) - except CommandException: - logger.exception( - "A downstream exception occurred while generating" " a report: %s", task_id + self.update_state(state="FAILURE") + except CommandException as ex: + logger_func, level = get_logger_from_status(ex.status) + logger_func( + "A downstream {} occurred while generating a report: {}. {}".format( + level, task_id, ex.message + ), + exc_info=True, ) + if level == LoggerLevel.EXCEPTION: + self.update_state(state="FAILURE") @celery_app.task(name="reports.prune_log") diff --git a/superset/tasks/slack_util.py b/superset/tasks/slack_util.py index 2f44d92605272..652fd89b6f589 100644 --- a/superset/tasks/slack_util.py +++ b/superset/tasks/slack_util.py @@ -23,9 +23,9 @@ import backoff from flask import current_app -from slack import WebClient -from slack.errors import SlackApiError -from slack.web.slack_response import SlackResponse +from slack_sdk import WebClient +from slack_sdk.errors import SlackApiError +from slack_sdk.web.slack_response import SlackResponse # Globals logger = logging.getLogger("tasks.slack_util") diff --git a/superset/tasks/thumbnails.py b/superset/tasks/thumbnails.py index 94b83ddb372cf..d76939a07e3a0 100644 --- a/superset/tasks/thumbnails.py +++ b/superset/tasks/thumbnails.py @@ -18,14 +18,16 @@ """Utility functions used across Superset""" import logging -from typing import Optional +from typing import cast, Optional from flask import current_app from superset import security_manager, thumbnail_cache from superset.extensions import celery_app -from superset.utils.celery import session_scope +from superset.tasks.utils import get_executor +from superset.utils.core import override_user from superset.utils.screenshots import ChartScreenshot, DashboardScreenshot +from superset.utils.urls import get_url_path from superset.utils.webdriver import WindowSize logger = logging.getLogger(__name__) @@ -33,21 +35,29 @@ @celery_app.task(name="cache_chart_thumbnail", soft_time_limit=300) def cache_chart_thumbnail( - url: str, - digest: str, + current_user: Optional[str], + chart_id: int, force: bool = False, window_size: Optional[WindowSize] = None, thumb_size: Optional[WindowSize] = None, ) -> None: + # pylint: disable=import-outside-toplevel + from superset.models.slice import Slice + if not thumbnail_cache: logger.warning("No cache set, refusing to compute") return None + chart = cast(Slice, Slice.get(chart_id)) + url = get_url_path("Superset.slice", slice_id=chart.id) logger.info("Caching chart: %s", url) - screenshot = ChartScreenshot(url, digest) - with session_scope(nullpool=True) as session: - user = security_manager.get_user_by_username( - current_app.config["THUMBNAIL_SELENIUM_USER"], session=session - ) + _, username = get_executor( + executor_types=current_app.config["THUMBNAIL_EXECUTE_AS"], + model=chart, + current_user=current_user, + ) + user = security_manager.find_user(username) + with override_user(user): + screenshot = ChartScreenshot(url, chart.digest) screenshot.compute_and_cache( user=user, cache=thumbnail_cache, @@ -60,17 +70,29 @@ def cache_chart_thumbnail( @celery_app.task(name="cache_dashboard_thumbnail", soft_time_limit=300) def cache_dashboard_thumbnail( - url: str, digest: str, force: bool = False, thumb_size: Optional[WindowSize] = None + current_user: Optional[str], + dashboard_id: int, + force: bool = False, + thumb_size: Optional[WindowSize] = None, ) -> None: + # pylint: disable=import-outside-toplevel + from superset.models.dashboard import Dashboard + if not thumbnail_cache: logging.warning("No cache set, refusing to compute") return + dashboard = Dashboard.get(dashboard_id) + url = get_url_path("Superset.dashboard", dashboard_id_or_slug=dashboard.id) + logger.info("Caching dashboard: %s", url) - screenshot = DashboardScreenshot(url, digest) - with session_scope(nullpool=True) as session: - user = security_manager.get_user_by_username( - current_app.config["THUMBNAIL_SELENIUM_USER"], session=session - ) + _, username = get_executor( + executor_types=current_app.config["THUMBNAIL_EXECUTE_AS"], + model=dashboard, + current_user=current_user, + ) + user = security_manager.find_user(username) + with override_user(user): + screenshot = DashboardScreenshot(url, dashboard.digest) screenshot.compute_and_cache( user=user, cache=thumbnail_cache, diff --git a/superset/tasks/types.py b/superset/tasks/types.py new file mode 100644 index 0000000000000..cc337a81edb6f --- /dev/null +++ b/superset/tasks/types.py @@ -0,0 +1,44 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from enum import Enum + + +class ExecutorType(str, Enum): + """ + Which user should scheduled tasks be executed as. Used as follows: + For Alerts & Reports: the "model" refers to the AlertSchedule object + For Thumbnails: The "model" refers to the Slice or Dashboard object + """ + + # See the THUMBNAIL_SELENIUM_USER config parameter + SELENIUM = "selenium" + # The creator of the model + CREATOR = "creator" + # The creator of the model, if found in the owners list + CREATOR_OWNER = "creator_owner" + # The currently logged in user. In the case of Alerts & Reports, this is always + # None. For Thumbnails, this is the user that requested the thumbnail + CURRENT_USER = "current_user" + # The last modifier of the model + MODIFIER = "modifier" + # The last modifier of the model, if found in the owners list + MODIFIER_OWNER = "modifier_owner" + # An owner of the model. If the last modifier is in the owners list, returns that + # user. If the modifier is not found, returns the creator if found in the owners + # list. Finally, if neither are present, returns the first user in the owners list. + OWNER = "owner" diff --git a/superset/tasks/utils.py b/superset/tasks/utils.py new file mode 100644 index 0000000000000..9c1dab82202b8 --- /dev/null +++ b/superset/tasks/utils.py @@ -0,0 +1,94 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from __future__ import annotations + +from typing import List, Optional, Tuple, TYPE_CHECKING, Union + +from flask import current_app, g + +from superset.tasks.exceptions import ExecutorNotFoundError +from superset.tasks.types import ExecutorType + +if TYPE_CHECKING: + from superset.models.dashboard import Dashboard + from superset.models.slice import Slice + from superset.reports.models import ReportSchedule + + +# pylint: disable=too-many-branches +def get_executor( + executor_types: List[ExecutorType], + model: Union[Dashboard, ReportSchedule, Slice], + current_user: Optional[str] = None, +) -> Tuple[ExecutorType, str]: + """ + Extract the user that should be used to execute a scheduled task. Certain executor + types extract the user from the underlying object (e.g. CREATOR), the constant + Selenium user (SELENIUM), or the user that initiated the request. + + :param executor_types: The requested executor type in descending order. When the + first user is found it is returned. + :param model: The underlying object + :param current_user: The username of the user that initiated the task. For + thumbnails this is the user that requested the thumbnail, while for alerts + and reports this is None (=initiated by Celery). + :return: User to execute the report as + :raises ScheduledTaskExecutorNotFoundError: If no users were found in after + iterating through all entries in `executor_types` + """ + owners = model.owners + owner_dict = {owner.id: owner for owner in owners} + for executor_type in executor_types: + if executor_type == ExecutorType.SELENIUM: + return executor_type, current_app.config["THUMBNAIL_SELENIUM_USER"] + if executor_type == ExecutorType.CURRENT_USER and current_user: + return executor_type, current_user + if executor_type == ExecutorType.CREATOR_OWNER: + if (user := model.created_by) and (owner := owner_dict.get(user.id)): + return executor_type, owner.username + if executor_type == ExecutorType.CREATOR: + if user := model.created_by: + return executor_type, user.username + if executor_type == ExecutorType.MODIFIER_OWNER: + if (user := model.changed_by) and (owner := owner_dict.get(user.id)): + return executor_type, owner.username + if executor_type == ExecutorType.MODIFIER: + if user := model.changed_by: + return executor_type, user.username + if executor_type == ExecutorType.OWNER: + owners = model.owners + if len(owners) == 1: + return executor_type, owners[0].username + if len(owners) > 1: + if modifier := model.changed_by: + if modifier and (user := owner_dict.get(modifier.id)): + return executor_type, user.username + if creator := model.created_by: + if creator and (user := owner_dict.get(creator.id)): + return executor_type, user.username + return executor_type, owners[0].username + + raise ExecutorNotFoundError() + + +def get_current_user() -> Optional[str]: + user = g.user if hasattr(g, "user") and g.user else None + if user and not user.is_anonymous: + return user.username + + return None diff --git a/superset/templates/appbuilder/navbar_right.html b/superset/templates/appbuilder/navbar_right.html deleted file mode 100644 index 334e7ea2adaae..0000000000000 --- a/superset/templates/appbuilder/navbar_right.html +++ /dev/null @@ -1,127 +0,0 @@ -{# - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -#} - -{% set bug_report_url = appbuilder.app.config['BUG_REPORT_URL'] %} -{% set documentation_url = appbuilder.app.config['DOCUMENTATION_URL'] %} -{% set documentation_text = appbuilder.app.config['DOCUMENTATION_TEXT'] %} -{% set documentation_icon = appbuilder.app.config['DOCUMENTATION_ICON'] %} -{% set version_string = appbuilder.app.config['VERSION_STRING'] %} -{% set version_sha = appbuilder.app.config['VERSION_SHA'] %} - -{% set locale = session['locale'] %} -{% if not locale %} - {% set locale = 'en' %} -{% endif %} - -{% if not current_user.is_anonymous %} - <li class="dropdown"> - <button type="button" style="margin-top: 12px; margin-right: 30px;" data-toggle="dropdown" class="dropdown-toggle btn btn-sm btn-primary"> - <i class="fa fa-plus"></i> {{ _("New") }} - </button> - <ul class="dropdown-menu"> - <li><a href="/superset/sqllab"><span class="fa fa-fw fa-search"></span> {{_("SQL Query")}}</a></li> - <li><a href="/chart/add"><span class="fa fa-fw fa-bar-chart"></span> {{_("Chart")}}</a></li> - <li><a href="/dashboard/new/"><span class="fa fa-fw fa-dashboard"></span> {{_("Dashboard")}}</a></li> - </ul> - </li> -{% endif %} -{% if documentation_url %} -<li> - <a - tabindex="-1" - href="{{ documentation_url }}" - title="{{ documentation_text }}" - target="_blank" - > - {% if documentation_icon %} - <img - width="100%" - src="{{ documentation_icon }}" - alt="{{ documentation_text }}" - /> - {% else %} - <i class="fa fa-question"></i>  - {% endif %} - </a> -</li> -{% endif %} -{% if bug_report_url %} -<li> - <a - tabindex="-1" - href="{{ bug_report_url }}" - target="_blank" - title="Report a bug" - > - <i class="fa fa-bug"></i>  - </a> -</li> -{% endif %} -{% if languages.keys()|length > 1 %} -<li class="dropdown"> - <a class="dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)"> - <div class="f16"><i class="flag {{languages[locale].get('flag')}}"></i> <b class="caret"></b> - </div> - </a> - <ul class="dropdown-menu" id="language-picker"> - <li class="dropdown"> - {% for lang in languages %} - {% if lang != locale %} - <a tabindex="-1" href="{{appbuilder.get_url_for_locale(lang)}}"> - <div class="f16"> - <i class="flag {{languages[lang].get('flag')}}"></i> - {{languages[lang].get('name')}} - </div> - </a> - {% endif %} - {% endfor %} - </li> - </ul> -</li> -{% endif %} - -{% if not current_user.is_anonymous %} - <li class="dropdown"> - <a - class="dropdown-toggle" - data-toggle="dropdown" - title="{{g.user.get_full_name()}}" - href="javascript:void(0)" - > - <i class="fa fa-user"></i> <b class="caret"></b> - </a> - <ul class="dropdown-menu"> - <li><a href="/superset/profile/{{g.user.username}}"><span class="fa fa-fw fa-user"></span>{{_("Profile")}}</a></li> - <li><a href="{{appbuilder.get_url_for_userinfo}}"><span class="fa fa-fw fa-user"></span>{{_("Info")}}</a></li> - <li><a href="{{appbuilder.get_url_for_logout}}"><span class="fa fa-fw fa-sign-out"></span>{{_("Logout")}}</a></li> - {% if version_string or version_sha %} - <li class="fineprint"> - {% if version_string %} - <div>Version: {{version_string}}</div> - {% endif %} - {% if version_sha %} - <div>SHA: {{version_sha}}</div> - {% endif %} - </li> - {% endif %} - </ul> - </li> -{% else %} - <li><a href="{{appbuilder.get_url_for_login}}"> - <i class="fa fa-fw fa-sign-in"></i>{{_("Login")}}</a></li> -{% endif %} diff --git a/superset/templates/email/role_extended.txt b/superset/templates/email/role_extended.txt index 89ba1b0f722b2..463fb32c9c46e 100644 --- a/superset/templates/email/role_extended.txt +++ b/superset/templates/email/role_extended.txt @@ -20,7 +20,7 @@ Dear {{ user.username }}, <br> <a href={{ url_for('Superset.profile', username=granter.username, _external=True) }}> {{ granter.username }}</a> has extended the role {{ role.name }} to include -<a href={{ url_for('Superset.explore', datasource_type=datasource.type, datasource_id=datasource.id, _external=True) }}> +<a href={{ url_for('ExploreView.root', datasource_type=datasource.type, datasource_id=datasource.id, _external=True) }}> {{datasource.full_name}}</a> and granted you access to it. <br> <br> diff --git a/superset/templates/email/role_granted.txt b/superset/templates/email/role_granted.txt index 8027f41ac489c..312a04947387d 100644 --- a/superset/templates/email/role_granted.txt +++ b/superset/templates/email/role_granted.txt @@ -21,7 +21,7 @@ Dear {{ user.username }}, <a href={{ url_for('Superset.profile', username=granter.username, _external=True) }}> {{ granter.username }}</a> has granted you the role {{ role.name }} that gives access to the - <a href={{ url_for('Superset.explore', datasource_type=datasource.type, datasource_id=datasource.id, _external=True) }}> + <a href={{ url_for('ExploreView.root', datasource_type=datasource.type, datasource_id=datasource.id, _external=True) }}> {{datasource.full_name}}</a> <br> <br> diff --git a/superset/templates/superset/add_slice.html b/superset/templates/superset/add_slice.html deleted file mode 100644 index b287de64e869d..0000000000000 --- a/superset/templates/superset/add_slice.html +++ /dev/null @@ -1,35 +0,0 @@ -{# - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -#} -{% extends "superset/basic.html" %} - -{% block title %} - Add new chart -{% endblock %} - -{% block body %} - <div - id="app" - data-bootstrap="{{ bootstrap_data }}" - ></div> -{% endblock %} - -{% block tail_js %} - {{ super() }} - {{ js_bundle("addSlice") }} -{% endblock %} diff --git a/superset/templates/superset/basic.html b/superset/templates/superset/basic.html index fff57fdb9fa18..fdd2e8e0de52d 100644 --- a/superset/templates/superset/basic.html +++ b/superset/templates/superset/basic.html @@ -40,7 +40,7 @@ rel="{{favicon.rel if favicon.rel else "icon"}}" type="{{favicon.type if favicon.type else "image/png"}}" {% if favicon.sizes %}sizes={{favicon.sizes}}{% endif %} - href="{{ assets_prefix }}{{favicon.href}}" + href="{{ "" if favicon.href.startswith("http") else assets_prefix }}{{favicon.href}}" > {% endfor %} <link rel="stylesheet" type="text/css" href="{{ assets_prefix }}/static/appbuilder/css/flags/flags16.css" /> diff --git a/superset/templates/superset/form_view/csv_macros.html b/superset/templates/superset/form_view/csv_macros.html new file mode 100644 index 0000000000000..40c7bf54a0b27 --- /dev/null +++ b/superset/templates/superset/form_view/csv_macros.html @@ -0,0 +1,75 @@ +{# +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +#} +{% macro render_delimiter_field(field, begin_sep_label='', end_sep_label='', begin_sep_field='', end_sep_field='') %} + {% if field.id != 'csrf_token' %} + {% if field.type == 'HiddenField' %} + {{ field}} + {% else %} + {{begin_sep_label|safe}} + <label for="{{field.id}}" control-label> + {{ field.label.text }} + {% if field.flags.required %} + <strong style="color: red">*</strong> + {% endif %} + </label> + {{end_sep_label|safe}} + {{begin_sep_field|safe}} + {{ field(**kwargs)|safe }} + <input class="form-control col-sm-9" style="margin: 10px 0px; display: none;" id="otherInput" name="otherInput" placeholder="Type your delimiter here" type="text" value=""> + <span class="help-block">{{ field.description }}</span> + {% endif %} + {% if field.errors %} + <div class="alert alert-danger"> + {% for error in field.errors %} + {{ _(error) }} + {% endfor %} + </div> + {% endif %} + {{end_sep_field|safe}} + {% endif %} +{% endmacro %} + +{% macro render_collapsable_form_group(id, section_title='') %} + <div class="form-group" id="{{id}}"> + <div class="col-xs-12" style="padding: 0;"> + <table class="table table-bordered"> + <tbody> + <tr data-toggle="collapse" data-target="#collapsable-content-{{id}}" class="accordion-toggle"> + <td class="col-xs-12" role="button" style="border: none;"> + <i class="fa fa-chevron-down" style="color: #666666; margin-right: 8px; margin-left: 12px;"></i> + {{section_title}} + </td> + </tr> + + <tr class="collapse" id="collapsable-content-{{id}}"> + <td colspan="12" style="padding: 0;"> + <div> + <table class="table table-bordered" style="margin-bottom: 0; background-color: transparent; border: none;"> + <tbody> + {{ caller() }} + </tbody> + </table> + </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> +{% endmacro %} diff --git a/superset/templates/superset/form_view/csv_scripts.html b/superset/templates/superset/form_view/csv_scripts.html new file mode 100644 index 0000000000000..bb7b94b1a37f7 --- /dev/null +++ b/superset/templates/superset/form_view/csv_scripts.html @@ -0,0 +1,37 @@ +{# +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +#} +<script> + $('#delimiter').on('change', function () { + var delimiterOptions = $('#delimiter').val(); + if (delimiterOptions?.includes("other")) { + document.getElementById("otherInput").style.display = 'block'; + $('#otherInput').attr('required', 'required'); + } else { + document.getElementById("otherInput").style.display = 'none'; + $('#otherInput').removeAttr('required'); + } + }).change(); + + $(".collapse").on("hide.bs.collapse show.bs.collapse", e => { + $(e.target) + .prev() + .find("i:last-child") + .toggleClass("fa-chevron-up fa-chevron-down"); + }); +</script> diff --git a/superset/templates/superset/form_view/csv_to_database_view/edit.html b/superset/templates/superset/form_view/csv_to_database_view/edit.html index 2bec3aa12abb1..b09f9bd3838b1 100644 --- a/superset/templates/superset/form_view/csv_to_database_view/edit.html +++ b/superset/templates/superset/form_view/csv_to_database_view/edit.html @@ -16,10 +16,122 @@ specific language governing permissions and limitations under the License. #} +{% extends "appbuilder/base.html" %} +{% import 'appbuilder/general/lib.html' as lib %} +{% set begin_sep_label = '<td class="col-sm-2" style="border-left: 0; border-top: 0;">' %} + {% set end_sep_label = '</td>' %} +{% set begin_sep_field = '<td style="border-right: 0; border-top: 0;">' %} + {% set end_sep_field = '</td>' %} {% import 'superset/form_view/database_schemas_selector.html' as schemas_selector %} -{% extends 'appbuilder/general/model/edit.html' %} - +{% import 'superset/form_view/csv_scripts.html' as csv_scripts %} +{% import 'superset/form_view/csv_macros.html' as csv_macros %} +{% block content %} +{{ lib.panel_begin(title, "edit") }} +<div id="Home" class="tab-pane active"> + <form id="model_form" action="" method="post" enctype="multipart/form-data"> + {{form.hidden_tag()}} + <div class="form-group"> + <div class="col-md-12" style="padding: 0;"> + <table class="table table-bordered"> + <tbody> + <tr> + {{ lib.render_field(form.csv_file, begin_sep_label, end_sep_label, begin_sep_field, end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.table_name, begin_sep_label, end_sep_label, begin_sep_field, end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.database, begin_sep_label, end_sep_label, begin_sep_field, end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.schema, begin_sep_label, end_sep_label, begin_sep_field, end_sep_field) }} + </tr> + <tr> + {{ csv_macros.render_delimiter_field(form.delimiter, begin_sep_label, end_sep_label, begin_sep_field, end_sep_field) }} + </tr> + </tbody> + </table> + </div> + </div> + {% call csv_macros.render_collapsable_form_group("accordion1", "File Settings") %} + <tr> + {{ lib.render_field(form.if_exists, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.skip_initial_space, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.skip_blank_lines, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.parse_dates, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.infer_datetime_format, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.decimal, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.null_values, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + {% endcall %} + {% call csv_macros.render_collapsable_form_group("accordion2", "Columns") %} + <tr> + {{ lib.render_field(form.index_col, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.dataframe_index, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.index_label, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.use_cols, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + <tr> + {{ lib.render_field(form.overwrite_duplicate, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + {% endcall %} + {% call csv_macros.render_collapsable_form_group("accordion3", "Rows") %} + <tr> + {{ lib.render_field(form.header, begin_sep_label, end_sep_label, begin_sep_field, end_sep_field) + }} + </tr> + <tr> + {{ lib.render_field(form.nrows, begin_sep_label, end_sep_label, begin_sep_field, end_sep_field) + }} + </tr> + <tr> + {{ lib.render_field(form.skiprows, begin_sep_label, end_sep_label, begin_sep_field, + end_sep_field) }} + </tr> + {% endcall %} + <div class="form-group"> + <div class="col-xs-12" style="padding: 0;"> + {{ lib.render_form_controls() }} + </div> + </div> + </form> +</div> +{% endblock %} +{% block add_tail_js %} +<script src="{{url_for('appbuilder.static',filename='js/ab_keep_tab.js')}}"></script> +{% endblock %} {% block tail_js %} {{ super() }} {{ schemas_selector }} + {{ csv_scripts }} {% endblock %} diff --git a/superset/templates/superset/form_view/database_schemas_selector.html b/superset/templates/superset/form_view/database_schemas_selector.html index 73955d0174e6c..b9efb68d7e5f7 100644 --- a/superset/templates/superset/form_view/database_schemas_selector.html +++ b/superset/templates/superset/form_view/database_schemas_selector.html @@ -17,7 +17,7 @@ under the License. #} <script> - var db = $("#con"); + var db = $("#database"); var schema = $("#schema"); // this element is a text input diff --git a/superset/templates/superset/models/database/macros.html b/superset/templates/superset/models/database/macros.html index f1d07220ef523..f1f7a36cde725 100644 --- a/superset/templates/superset/models/database/macros.html +++ b/superset/templates/superset/models/database/macros.html @@ -22,7 +22,7 @@ .append('<button id="testconn" class="btn btn-sm btn-primary">{{ _("Test Connection") }}</button>'); $("#testconn").click(function(e) { e.preventDefault(); - var url = "/api/v1/database/test_connection"; + var url = "/api/v1/database/test_connection/"; var csrf_token = "{{ csrf_token() if csrf_token else '' }}"; $.ajaxSetup({ diff --git a/superset/templates/tail_js_custom_extra.html b/superset/templates/tail_js_custom_extra.html index 598905402750e..92ad827614c47 100644 --- a/superset/templates/tail_js_custom_extra.html +++ b/superset/templates/tail_js_custom_extra.html @@ -18,7 +18,7 @@ #} {# - This file may be overriden in your custom deployment. + This file may be overridden in your custom deployment. It will be included in every view in superset and is a good place to include your custom frontend code, such as scripts to initialize google analytics, intercom, segment, etc. diff --git a/superset/temporary_cache/api.py b/superset/temporary_cache/api.py index bdbdda302e694..b6376c63c3b6f 100644 --- a/superset/temporary_cache/api.py +++ b/superset/temporary_cache/api.py @@ -20,8 +20,7 @@ from apispec import APISpec from apispec.exceptions import DuplicateComponentNameError -from flask import g, request, Response -from flask_appbuilder.api import BaseApi +from flask import request, Response from marshmallow import ValidationError from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod @@ -34,12 +33,12 @@ TemporaryCachePostSchema, TemporaryCachePutSchema, ) -from superset.views.base_api import requires_json +from superset.views.base_api import BaseSupersetApi, requires_json logger = logging.getLogger(__name__) -class TemporaryCacheRestApi(BaseApi, ABC): +class TemporaryCacheRestApi(BaseSupersetApi, ABC): add_model_schema = TemporaryCachePostSchema() edit_model_schema = TemporaryCachePutSchema() method_permission_name = MODEL_API_RW_METHOD_PERMISSION_MAP @@ -70,9 +69,7 @@ def post(self, pk: int) -> Response: try: item = self.add_model_schema.load(request.json) tab_id = request.args.get("tab_id") - args = CommandParameters( - actor=g.user, resource_id=pk, value=item["value"], tab_id=tab_id - ) + args = CommandParameters(resource_id=pk, value=item["value"], tab_id=tab_id) key = self.get_create_command()(args).run() return self.response(201, key=key) except ValidationError as ex: @@ -88,7 +85,6 @@ def put(self, pk: int, key: str) -> Response: item = self.edit_model_schema.load(request.json) tab_id = request.args.get("tab_id") args = CommandParameters( - actor=g.user, resource_id=pk, key=key, value=item["value"], @@ -105,7 +101,7 @@ def put(self, pk: int, key: str) -> Response: def get(self, pk: int, key: str) -> Response: try: - args = CommandParameters(actor=g.user, resource_id=pk, key=key) + args = CommandParameters(resource_id=pk, key=key) value = self.get_get_command()(args).run() if not value: return self.response_404() @@ -117,7 +113,7 @@ def get(self, pk: int, key: str) -> Response: def delete(self, pk: int, key: str) -> Response: try: - args = CommandParameters(actor=g.user, resource_id=pk, key=key) + args = CommandParameters(resource_id=pk, key=key) result = self.get_delete_command()(args).run() if not result: return self.response_404() diff --git a/superset/temporary_cache/commands/parameters.py b/superset/temporary_cache/commands/parameters.py index 4d98167c37231..74b9c1c6321e5 100644 --- a/superset/temporary_cache/commands/parameters.py +++ b/superset/temporary_cache/commands/parameters.py @@ -17,12 +17,9 @@ from dataclasses import dataclass from typing import Optional -from flask_appbuilder.security.sqla.models import User - @dataclass class CommandParameters: - actor: User resource_id: int tab_id: Optional[int] = None key: Optional[str] = None diff --git a/superset/thumbnails/__init__.py b/superset/thumbnails/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/superset/thumbnails/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/superset/thumbnails/digest.py b/superset/thumbnails/digest.py new file mode 100644 index 0000000000000..fb209fcd5072d --- /dev/null +++ b/superset/thumbnails/digest.py @@ -0,0 +1,83 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from __future__ import annotations + +import logging +from typing import TYPE_CHECKING + +from flask import current_app + +from superset.tasks.types import ExecutorType +from superset.tasks.utils import get_current_user, get_executor +from superset.utils.hashing import md5_sha_from_str + +if TYPE_CHECKING: + from superset.models.dashboard import Dashboard + from superset.models.slice import Slice + +logger = logging.getLogger(__name__) + + +def _adjust_string_for_executor( + unique_string: str, + executor_type: ExecutorType, + executor: str, +) -> str: + """ + Add the executor to the unique string if the thumbnail is + user-specific. + """ + if executor_type == ExecutorType.CURRENT_USER: + # add the user id to the string to make it unique + unique_string = f"{unique_string}\n{executor}" + + return unique_string + + +def get_dashboard_digest(dashboard: Dashboard) -> str: + config = current_app.config + executor_type, executor = get_executor( + executor_types=config["THUMBNAIL_EXECUTE_AS"], + model=dashboard, + current_user=get_current_user(), + ) + if func := config["THUMBNAIL_DASHBOARD_DIGEST_FUNC"]: + return func(dashboard, executor_type, executor) + + unique_string = ( + f"{dashboard.id}\n{dashboard.charts}\n{dashboard.position_json}\n" + f"{dashboard.css}\n{dashboard.json_metadata}" + ) + + unique_string = _adjust_string_for_executor(unique_string, executor_type, executor) + return md5_sha_from_str(unique_string) + + +def get_chart_digest(chart: Slice) -> str: + config = current_app.config + executor_type, executor = get_executor( + executor_types=config["THUMBNAIL_EXECUTE_AS"], + model=chart, + current_user=get_current_user(), + ) + if func := config["THUMBNAIL_CHART_DIGEST_FUNC"]: + return func(chart, executor_type, executor) + + unique_string = f"{chart.params or ''}.{executor}" + unique_string = _adjust_string_for_executor(unique_string, executor_type, executor) + return md5_sha_from_str(unique_string) diff --git a/superset/translations/de/LC_MESSAGES/messages.json b/superset/translations/de/LC_MESSAGES/messages.json index 9abf6b6d8a7e9..08678e6d07168 100644 --- a/superset/translations/de/LC_MESSAGES/messages.json +++ b/superset/translations/de/LC_MESSAGES/messages.json @@ -1963,7 +1963,7 @@ "Font size for the smallest value in the list": [ "Schriftgröße für den kleinsten Wert in der Liste" ], - "For Presto and Postgres, shows a button to compute cost before running a query.": [ + "For Bigquery, Presto and Postgres, shows a button to compute cost before running a query.": [ "Für Presto und Postgres wird ein Buttons angezeigt, um Kosten vor dem Ausführen einer Abfrage zu schätzen." ], "For regular filters, these are the roles this filter will be applied to. For base filters, these are the roles that the filter DOES NOT apply to, e.g. Admin if admin should see all data.": [ @@ -3988,7 +3988,7 @@ "The query associated with the results was deleted.": [ "Die den Ergebnissen zugeordnete Abfrage wurde gelöscht." ], - "The query associated with these results could not be find. You need to re-run the original query.": [ + "The query associated with these results could not be found. You need to re-run the original query.": [ "Die mit diesen Ergebnissen verknüpfte Abfrage konnte nicht gefunden werden. Sie müssen die ursprüngliche Abfrage erneut ausführen." ], "The query contains one or more malformed template parameters.": [ diff --git a/superset/translations/de/LC_MESSAGES/messages.po b/superset/translations/de/LC_MESSAGES/messages.po index 8726ceae19a23..54c069c1a3127 100644 --- a/superset/translations/de/LC_MESSAGES/messages.po +++ b/superset/translations/de/LC_MESSAGES/messages.po @@ -1271,10 +1271,6 @@ msgstr "Ein Fehler ist aufgetreten" msgid "An error occurred saving dataset" msgstr "Beim Speichern des Datensatz ist ein Fehler aufgetreten" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "Beim Aktualisieren von Abfragen ist ein Fehler aufgetreten" - #: superset/key_value/commands/exceptions.py:33 msgid "An error occurred while accessing the value." msgstr "Beim Zugriff auf den Wert ist ein Fehler aufgetreten." @@ -5929,18 +5925,6 @@ msgstr "Filtertyp" msgid "Filter box" msgstr "Filterkomponente" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "Filtern nach Datenbank" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "Nach Status filtern" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "Filtern nach Benutzer*in" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "Filterkonfiguration" @@ -6114,7 +6098,7 @@ msgstr "Schriftgröße für den kleinsten Wert in der Liste" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "" "Für Presto und Postgres wird ein Buttons angezeigt, um Kosten vor dem " @@ -6822,7 +6806,6 @@ msgstr "Problem 1000 - Die Datenquelle ist zu groß, um sie abzufragen." msgid "Issue 1001 - The database is under an unusual load." msgstr "Problem 1001 - Die Datenbank ist ungewöhnlich belastet." -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -9495,10 +9478,6 @@ msgstr "Abfragename" msgid "Query preview" msgstr "Abfragen-Voransicht" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "Abfragen suchen" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 msgid "Query was stopped" msgstr "Abfrage wurde angehalten" @@ -10541,7 +10520,6 @@ msgid "Scoping" msgstr "Auswahlverfahren" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -12595,7 +12573,7 @@ msgstr "Die den Ergebnissen zugeordnete Abfrage wurde gelöscht." #: superset/views/core.py:2297 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" "Die mit diesen Ergebnissen verknüpfte Abfrage konnte nicht gefunden " @@ -15498,10 +15476,6 @@ msgstr "Zoomstufe der Karte" msgid "[Alert] %(label)s" msgstr "[Alarm] %(label)s" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "[Von]-" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "" @@ -15521,10 +15495,6 @@ msgstr "[Fehlender Datensatz]" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "[Superset] Zugriff auf die Datenquelle %(name)s wurde gewährt" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "[Bis]-" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 msgid "[Untitled]" msgstr "[Unbenannt]" diff --git a/superset/translations/en/LC_MESSAGES/messages.po b/superset/translations/en/LC_MESSAGES/messages.po index 4fb9477b0ff36..6faf2b1c7565f 100644 --- a/superset/translations/en/LC_MESSAGES/messages.po +++ b/superset/translations/en/LC_MESSAGES/messages.po @@ -1141,10 +1141,6 @@ msgstr "" msgid "An error occurred saving dataset" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "" - #: superset/key_value/commands/exceptions.py:33 msgid "An error occurred while accessing the value." msgstr "" @@ -3526,7 +3522,7 @@ msgstr "" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:154 msgid "" "D3 number format for numbers between -1.0 and 1.0, useful when you want " -"to have different siginificant digits for small and large numbers" +"to have different significant digits for small and large numbers" msgstr "" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:220 @@ -5521,18 +5517,6 @@ msgstr "" msgid "Filter box" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "" @@ -5693,7 +5677,7 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "" @@ -6345,7 +6329,6 @@ msgstr "" msgid "Issue 1001 - The database is under an unusual load." msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -8614,7 +8597,7 @@ msgid "Position of column level subtotal" msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:163 -msgid "Position of intermidiate node label on tree" +msgid "Position of intermediate node label on tree" msgstr "" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:293 @@ -8889,10 +8872,6 @@ msgstr "" msgid "Query preview" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 msgid "Query was stopped" msgstr "" @@ -9885,7 +9864,6 @@ msgid "Scoping" msgstr "" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -10434,7 +10412,7 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:52 msgid "" -"Show hierarchical relationships of data, with with the value represented " +"Show hierarchical relationships of data, with the value represented " "by area, showing proportion and contribution to the whole." msgstr "" @@ -11737,7 +11715,7 @@ msgstr "" #: superset/views/core.py:2280 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" @@ -12160,7 +12138,7 @@ msgstr "" #: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:127 msgid "" -"This color scheme is being overriden by custom label colors.\n" +"This color scheme is being overridden by custom label colors.\n" " Check the JSON metadata in the Advanced settings" msgstr "" @@ -13434,7 +13412,7 @@ msgstr "" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:27 msgid "" "Visualizes how a single metric varies across a country's principal " -"subdivisions (states, provinces, etc) on a chloropleth map. Each " +"subdivisions (states, provinces, etc) on a choropleth map. Each " "subdivision's value is elevated when you hover over the corresponding " "geographic boundary." msgstr "" @@ -14280,10 +14258,6 @@ msgstr "" msgid "[Alert] %(label)s" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "" @@ -14301,10 +14275,6 @@ msgstr "" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 msgid "[Untitled]" msgstr "" diff --git a/superset/translations/es/LC_MESSAGES/messages.po b/superset/translations/es/LC_MESSAGES/messages.po index 54845502ec821..0b1d2361f3b15 100644 --- a/superset/translations/es/LC_MESSAGES/messages.po +++ b/superset/translations/es/LC_MESSAGES/messages.po @@ -1194,10 +1194,6 @@ msgstr "Se produjo un error" msgid "An error occurred saving dataset" msgstr "Se produjo un error al crear el origen de datos" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "" - #: superset/key_value/commands/exceptions.py:33 #, fuzzy msgid "An error occurred while accessing the value." @@ -5795,18 +5791,6 @@ msgstr "Filtrar por usuario" msgid "Filter box" msgstr "Caja de filtro" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "Filtrar por base de datos" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "Filtrar por estado" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "Filtrar por usuario" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "Configuración de filtros" @@ -5975,7 +5959,7 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 #, fuzzy msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "Estimar el costo antes de ejecutar una consulta" @@ -6672,7 +6656,6 @@ msgstr "Issue 1000 - La fuente de datos es demasiado grande para consultar." msgid "Issue 1001 - The database is under an unusual load." msgstr "Issue 1001 - La base de datos tiene una carga inusualmente elevada." -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -9340,10 +9323,6 @@ msgstr "Nombre de la consulta" msgid "Query preview" msgstr "Previsualización de Datos" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "Cadena de búsqueda de consulta" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 #, fuzzy msgid "Query was stopped" @@ -10398,7 +10377,6 @@ msgid "Scoping" msgstr "" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -12380,7 +12358,7 @@ msgstr "" #: superset/views/core.py:2280 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" @@ -13258,7 +13236,8 @@ msgstr "Serie Temporal - Gráfico de Barras" msgid "" "Time-series Bar Charts are used to show the changes in a metric over time" " as a series of bars." -msgstr "" +msgstr "Los gráficos de barras en las series de tiempo se utilizan para mostrar" +" los cambios en las métricas con el paso del tiempo, en forma de barras." #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:69 #, fuzzy @@ -13283,19 +13262,21 @@ msgstr "Serie Temporal - Pivote de periodo" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:69 #, fuzzy msgid "Time-series Scatter Plot" -msgstr "Tabla de serie temporal" +msgstr "Gráfico de Dispersión de Puntos (Series de Tiempo)" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:59 msgid "" "Time-series Scatter Plot has time on the horizontal axis in linear units," " and the points are connected in order. It shows a statistical " "relationship between two variables." -msgstr "" +msgstr "Gráfico de Dispersión de Puntos (en Series de tiempo), muestra en el eje " +"horizontal el tiempo en unidades lineales, conectando los puntos en orden. Muestra" +" una relación estadística entre dos variables-" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:69 #, fuzzy msgid "Time-series Smooth Line" -msgstr "Tabla de serie temporal" +msgstr "Tabla de serie temporal Suavizada" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:59 msgid "" @@ -13306,7 +13287,7 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:60 #, fuzzy msgid "Time-series Stepped Line" -msgstr "Tabla de serie temporal" +msgstr "Tabla de serie temporal por pasos" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:50 msgid "" @@ -13315,6 +13296,11 @@ msgid "" "points. A step chart can be useful when you want to show the changes that" " occur at irregular intervals." msgstr "" +"Gráfico de Series por tiempo en Pasos (conocida como Tabla de Pasos) " +"es una variación del gráfico de Linea, en la cual la linea que forma la serie " +"de tiempo forma una serie de 'pasos' entre los puntos de intervalos de datos. " +"Una tabla de paso es útil cuando se quieren mostrar los cambios ocurridos en " +"intervalos regulares." #: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:25 msgid "Time-series Table" @@ -13327,6 +13313,11 @@ msgid "" " information as a series of data points connected by straight line " "segments. It is a basic type of chart common in many fields." msgstr "" +"El gráfico de linea (en series de tiempo) es un gráfico de linea utilizado " +"para visualizar medidas tomadas en intervalos de tiempo regulares. " +"El gráfico de linea es un tipo de gráfico que muestra información de " +"una serie de puntos de datos conectados por segmentos de lineas rectas. " +"Es un tipo básico de gráfico en la estadística." #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:98 msgid "Timeout error" @@ -13378,7 +13369,7 @@ msgstr "Columna de Tiempo" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:45 #, fuzzy msgid "Title is required" -msgstr "El campo es obligatorio" +msgstr "El título es obligatorio" #: superset/dashboards/filters.py:33 msgid "Title or Slug" @@ -13426,7 +13417,7 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:439 msgid "Totals" -msgstr "" +msgstr "Totales" #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:820 msgid "Track job" @@ -13442,11 +13433,11 @@ msgstr "Seguir trabajo" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:67 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:76 msgid "Transformable" -msgstr "" +msgstr "Transformable" #: superset-frontend/src/dashboard/util/backgroundStyleOptions.ts:25 msgid "Transparent" -msgstr "" +msgstr "Transparente" #: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:110 msgid "Transpose Pivot" @@ -13454,7 +13445,7 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:173 msgid "Transpose pivot" -msgstr "" +msgstr "Transponer pivot" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:39 #, fuzzy @@ -13495,7 +13486,7 @@ msgstr "Modificado" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:226 msgid "Triangle" -msgstr "" +msgstr "Triángulo" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1168 msgid "Trigger Alert If..." @@ -13509,7 +13500,7 @@ msgstr "Disparar Alerta si..." #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:271 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:274 msgid "Truncate Y Axis" -msgstr "" +msgstr "Truncar el eje Y" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:343 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:258 @@ -13518,15 +13509,15 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:274 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:277 msgid "Truncate Y Axis. Can be overridden by specifying a min or max bound." -msgstr "" +msgstr "Truncar el eje Y. Puede ser sobreescrito al especificar un límite máximo o mínimo" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:58 msgid "Truncates the specified date to the accuracy specified by the date unit." -msgstr "" +msgstr "Trunca la fecha especificada a la precisión establecida en el formato de fecha" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:222 msgid "Try applying different filters or ensuring your datasource has data" -msgstr "" +msgstr "Intente aplicar filtros diferentes o asegúrese de que la fuente de datos tiene información" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:58 msgid "Tuesday" @@ -13592,7 +13583,7 @@ msgstr "Parámetros de URL" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:125 #, fuzzy msgid "URL could not be identified" -msgstr "El Gráfico no ha podido eliminarse" +msgstr "El Gráfico no ha podido identificarse" #: superset-frontend/src/explore/controlPanels/sections.tsx:60 msgid "URL parameters" @@ -13604,18 +13595,18 @@ msgstr "nombre para URL" #: superset-frontend/src/SqlLab/actions/sqlLab.js:531 msgid "Unable to add a new tab to the backend. Please contact your administrator." -msgstr "" +msgstr "No se pueden añadir nueva pestaña al back-end. Contacte al administrador." #: superset/db_engine_specs/presto.py:218 #, python-format msgid "Unable to connect to catalog named \"%(catalog_name)s\"." -msgstr "" +msgstr "No se puede conectar al catálogo \"%(catalog_name)s\"." #: superset/db_engine_specs/mysql.py:139 #: superset/db_engine_specs/postgres.py:145 #, python-format msgid "Unable to connect to database \"%(database)s\"." -msgstr "" +msgstr "No se puede conectar a la Base de Datos: \"%(database)s\ " #: superset/utils/date_parser.py:390 #, fuzzy, python-format @@ -13696,7 +13687,7 @@ msgstr "" #: superset-frontend/src/utils/getClientErrorObject.ts:55 #, fuzzy msgid "Unexpected error: " -msgstr "Error inesperado" +msgstr "Error inesperado: " #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:95 #, fuzzy @@ -13706,7 +13697,7 @@ msgstr "Error desconocido" #: superset/db_engine_specs/mysql.py:129 #, python-format msgid "Unknown MySQL server host \"%(hostname)s\"." -msgstr "" +msgstr "Host desconocido de MySQL: \"%(hostname)s\"" #: superset/db_engine_specs/presto.py:1005 msgid "Unknown Presto Error" @@ -13714,22 +13705,22 @@ msgstr "Error de Presto desconocido" #: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:111 msgid "Unknown Status" -msgstr "" +msgstr "EStado desconocido" #: superset/connectors/sqla/models.py:1121 #, python-format msgid "Unknown column used in orderby: %(col)s" -msgstr "" +msgstr "Columna desconocida utilizada al ordenar: %(col)s%" #: superset-frontend/src/SqlLab/actions/sqlLab.js:349 #: superset-frontend/src/SqlLab/actions/sqlLab.js:389 msgid "Unknown error" -msgstr "Error desconocido" +msgstr "Valor desconocido" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:45 #, fuzzy msgid "Unknown value" -msgstr "Error desconocido" +msgstr "Valor desconocido" #: superset/jinja_context.py:347 #, python-format @@ -13800,7 +13791,7 @@ msgstr "Subir" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:134 #, fuzzy msgid "Upload Credentials" -msgstr "Subir Excel" +msgstr "Subir Credenciales" #: superset/initialization/__init__.py:400 msgid "Upload Excel" @@ -13808,7 +13799,7 @@ msgstr "Subir Excel" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:102 msgid "Upload JSON file" -msgstr "" +msgstr "Subir un archivo JSON" #: superset/initialization/__init__.py:369 msgid "Upload a CSV" @@ -13834,19 +13825,19 @@ msgstr "Usar Pandas para interpretar el formato de fecha y hora automáticamente #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:207 msgid "Use a log scale" -msgstr "" +msgstr "Usar escala logarítimica" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:107 msgid "Use a log scale for the X-axis" -msgstr "" +msgstr "Usar escala logarítimica para el Eje X" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:230 msgid "Use a log scale for the Y-axis" -msgstr "" +msgstr "Usar escala logarítimica para el Eje Y" #: superset/db_engine_specs/base.py:1401 msgid "Use an encrypted connection to the database" -msgstr "" +msgstr "Usar una conexión encriptada a la base de datos" #: superset-frontend/src/components/Datasource/DatasourceModal.tsx:209 msgid "Use legacy datasource editor" @@ -13858,11 +13849,11 @@ msgstr "" #: superset-frontend/src/filters/components/Range/controlPanel.ts:68 msgid "Use only a single value." -msgstr "" +msgstr "Usar un único valor" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:124 msgid "Use the Advanced Analytics options below" -msgstr "" +msgstr "Usar la opción de Analítica Avanzada debajo " #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:136 msgid "" @@ -13877,7 +13868,7 @@ msgstr "Usa el botón 'editar' para cambiar este campo" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:176 #: superset-frontend/src/explore/controls.jsx:207 msgid "Use this to define a static color for all circles" -msgstr "" +msgstr "Use esto para definir un color estático para todos los círculos" #: superset/views/dynamic_plugins.py:48 msgid "" @@ -15068,10 +15059,6 @@ msgstr "" msgid "[Alert] %(label)s" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "[De]-" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "Las columnas [Longitud] y [Latitud] deben estar presentes en [Group By]" @@ -15090,10 +15077,6 @@ msgstr "Cambiar fuente" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "Se ha otorgado Acceso [Superset] a la fuente de datos %(name)" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "[A]-" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 #, fuzzy, python-format msgid "[Untitled]" diff --git a/superset/translations/fr/LC_MESSAGES/messages.json b/superset/translations/fr/LC_MESSAGES/messages.json index 954b9d8d40b8b..effeb47e45510 100644 --- a/superset/translations/fr/LC_MESSAGES/messages.json +++ b/superset/translations/fr/LC_MESSAGES/messages.json @@ -1380,7 +1380,7 @@ "Data could not be retrieved from the results backend. You need to re-run the original query.": [ "Impossible de récupérer les données depuis le backend. Rejouez la requête originale." ], - "The query associated with these results could not be find. You need to re-run the original query.": [ + "The query associated with these results could not be found. You need to re-run the original query.": [ "La requête associée à ces résultats n'a pu être trouvée. Rejouez la requête originale." ], "You are not authorized to see this query. If you think this is an error, please reach out to your administrator.": [ @@ -1923,8 +1923,8 @@ "Write a description for your query": [ "Ecrire une description à votre requête" ], - "Schedule query": ["Plannifier une requête"], - "Schedule": ["Plannifeir"], + "Schedule query": ["Planifier une requête"], + "Schedule": ["Planifier"], "There was an error with your request": [ "Il y avait une erreur avec vore requête" ], @@ -2280,7 +2280,7 @@ "OK": ["OK"], "Search all dashboards": ["Chercher tous les tableaux de bord"], "Edit Email Report": ["Modifier le rapport e-mail"], - "New Email Report": ["Nouveau rapoprt e-mail"], + "New Email Report": ["Nouveau rapport e-mail"], "Add": ["Ajouter"], "Message Content": ["Contenu du message"], "Text embedded in email": ["Text encapsulé dans l'e-mail"], @@ -2289,7 +2289,7 @@ "REPORT NAME ERROR": ["Erreur dans le nom du rapport"], "DESCRIPTION ERROR": ["Erreur de description"], "Scheduled reports will be sent to your email as a PNG": [ - "Les rapports planifiés seront envoyés à votre @ e-mail en PNG" + "Les rapports planifiés vous seront envoyés par e-mail en PNG" ], "Timezone": ["Fuseau horaire"], "Email reports active": ["Rapports par e-mail actifs"], @@ -3225,7 +3225,7 @@ "log": ["log"], "State": ["Etat"], "Execution ID": ["ID d'exécution"], - "Scheduled at (UTC)": ["Plannifié à (UTC)"], + "Scheduled at (UTC)": ["Planifié à (UTC)"], "Start at (UTC)": ["Début à (UTC)"], "Duration": ["Durée"], "Error message": ["Message d'erreur"], @@ -3419,7 +3419,7 @@ "Enable query cost estimation": [ "Activer l'estimation du coût de la requête" ], - "For Presto and Postgres, shows a button to compute cost before running a query.": [ + "For Bigquery, Presto and Postgres, shows a button to compute cost before running a query.": [ "Pour Presto et Postgres, affiche un bouton pour calculer le coût avant d'exécuter une requête." ], "Allow this database to be explored": [ diff --git a/superset/translations/fr/LC_MESSAGES/messages.po b/superset/translations/fr/LC_MESSAGES/messages.po index 5472d7459c74a..694b6c4b1d6af 100644 --- a/superset/translations/fr/LC_MESSAGES/messages.po +++ b/superset/translations/fr/LC_MESSAGES/messages.po @@ -1242,10 +1242,6 @@ msgstr "Un erreur s'est produite" msgid "An error occurred saving dataset" msgstr "Une erreur s'est produite durant la sauvegarde du jeu de données" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "Une erreur s'est produite en rafaîchissant les requêtes" - #: superset/key_value/commands/exceptions.py:33 #, fuzzy msgid "An error occurred while accessing the value." @@ -5932,18 +5928,6 @@ msgstr "Type du filtre" msgid "Filter box" msgstr "Boite de filtrage" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "Filtrer par base de données" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "Filtrer par statut" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "Filtrer par utilisateur" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "Configuration du filtre" @@ -6118,7 +6102,7 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "" "Pour Presto et Postgres, affiche un bouton pour calculer le coût avant " @@ -6837,7 +6821,6 @@ msgstr "Source de données trop volumineuse pour être interrogée." msgid "Issue 1001 - The database is under an unusual load." msgstr "La base de données est soumise à une charge inhabituelle." -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -9550,10 +9533,6 @@ msgstr "Nom de la requête" msgid "Query preview" msgstr "Prévisualisation de la requête" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "Chaîne de recherche" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 msgid "Query was stopped" msgstr "La requête a été arrêtée" @@ -10618,7 +10597,6 @@ msgid "Scoping" msgstr "Portée" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -12648,7 +12626,7 @@ msgstr "La requête associée aux résutlats a été supprimée." #: superset/views/core.py:2280 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" "La requête associée à ces résultats n'a pu être trouvée. Rejouez la " @@ -15466,10 +15444,6 @@ msgstr "" msgid "[Alert] %(label)s" msgstr "[Alert] %(label)s" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "[Depuis]-" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "" @@ -15489,10 +15463,6 @@ msgstr "[jeu de données manquant]" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "[Superset] Accès à la source de données %(name)s accordé" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "[à]-" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 msgid "[Untitled]" msgstr "[Sans titre]" diff --git a/superset/translations/it/LC_MESSAGES/messages.po b/superset/translations/it/LC_MESSAGES/messages.po index 3873a4b5a8921..d11c7b0021cce 100644 --- a/superset/translations/it/LC_MESSAGES/messages.po +++ b/superset/translations/it/LC_MESSAGES/messages.po @@ -1169,10 +1169,6 @@ msgstr "" msgid "An error occurred saving dataset" msgstr "Errore nel creare il datasource" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "Errore nel creare il datasource" - #: superset/key_value/commands/exceptions.py:33 #, fuzzy msgid "An error occurred while accessing the value." @@ -5672,18 +5668,6 @@ msgstr "Valore del filtro" msgid "Filter box" msgstr "Filtri" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "Mostra database" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "Valore del filtro" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "Valore del filtro" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "Controlli del filtro" @@ -5848,7 +5832,7 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "" @@ -6519,7 +6503,6 @@ msgstr "" msgid "Issue 1001 - The database is under an unusual load." msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -9140,10 +9123,6 @@ msgstr "Ricerca Query" msgid "Query preview" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "Ricerca Query" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 #, fuzzy msgid "Query was stopped" @@ -10165,7 +10144,6 @@ msgid "Scoping" msgstr "" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -12087,7 +12065,7 @@ msgstr "" #: superset/views/core.py:2280 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" @@ -14708,10 +14686,6 @@ msgstr "" msgid "[Alert] %(label)s" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "" @@ -14730,10 +14704,6 @@ msgstr "Seleziona una destinazione" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "[Superset] Accesso al datasource $(name) concesso" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 #, fuzzy, python-format msgid "[Untitled]" diff --git a/superset/translations/ja/LC_MESSAGES/messages.po b/superset/translations/ja/LC_MESSAGES/messages.po index d34ad5518cd6f..1d95ed1afe4c5 100644 --- a/superset/translations/ja/LC_MESSAGES/messages.po +++ b/superset/translations/ja/LC_MESSAGES/messages.po @@ -1162,10 +1162,6 @@ msgstr "エラーが発生しました" msgid "An error occurred saving dataset" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "" - #: superset/key_value/commands/exceptions.py:33 #, fuzzy msgid "An error occurred while accessing the value." @@ -5658,18 +5654,6 @@ msgstr "フィルタタイプ" msgid "Filter box" msgstr "フィルタボックス" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "フィルタ構成" @@ -5833,7 +5817,7 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "" @@ -6500,7 +6484,6 @@ msgstr "Issue 1000 - データ ソースが大きすぎてクエリを実行で msgid "Issue 1001 - The database is under an unusual load." msgstr "Issue 1001 - データベースに異常な負荷がかかっています。" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -9115,10 +9098,6 @@ msgstr "クエリ名" msgid "Query preview" msgstr "クエリプレビュー" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 msgid "Query was stopped" msgstr "" @@ -10136,7 +10115,6 @@ msgid "Scoping" msgstr "スコープ" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -12055,7 +12033,7 @@ msgstr "" #: superset/views/core.py:2280 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" @@ -14672,10 +14650,6 @@ msgstr "" msgid "[Alert] %(label)s" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "" @@ -14693,10 +14667,6 @@ msgstr "[データセットが見つかりません]" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "[Superset] データソース %(name)s へのアクセスは許可されました" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 msgid "[Untitled]" msgstr "" diff --git a/superset/translations/ko/LC_MESSAGES/messages.po b/superset/translations/ko/LC_MESSAGES/messages.po index 5b4530e0399dc..bfcb59867d15f 100644 --- a/superset/translations/ko/LC_MESSAGES/messages.po +++ b/superset/translations/ko/LC_MESSAGES/messages.po @@ -1160,10 +1160,6 @@ msgstr "" msgid "An error occurred saving dataset" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "" - #: superset/key_value/commands/exceptions.py:33 #, fuzzy, python-format msgid "An error occurred while accessing the value." @@ -5625,18 +5621,6 @@ msgstr "" msgid "Filter box" msgstr "필터" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "데이터베이스 선택" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "필터" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "필터" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "" @@ -5798,7 +5782,7 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "" @@ -6469,7 +6453,6 @@ msgstr "이슈 1000 - 데이터 소스가 쿼리하기에 너무 큽니다." msgid "Issue 1001 - The database is under an unusual load." msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -9052,10 +9035,6 @@ msgstr "Query 검색" msgid "Query preview" msgstr "데이터 미리보기" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "Query 검색" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 msgid "Query was stopped" msgstr "" @@ -10067,7 +10046,6 @@ msgid "Scoping" msgstr "" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -11975,7 +11953,7 @@ msgstr "" #: superset/views/core.py:2280 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" @@ -14557,10 +14535,6 @@ msgstr "" msgid "[Alert] %(label)s" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "" @@ -14578,10 +14552,6 @@ msgstr "" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 msgid "[Untitled]" msgstr "" diff --git a/superset/translations/messages.pot b/superset/translations/messages.pot index 98c91df9b68c6..ad475ef1e3572 100644 --- a/superset/translations/messages.pot +++ b/superset/translations/messages.pot @@ -1147,10 +1147,6 @@ msgstr "" msgid "An error occurred saving dataset" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "" - #: superset/key_value/commands/exceptions.py:33 msgid "An error occurred while accessing the value." msgstr "" @@ -3532,7 +3528,7 @@ msgstr "" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:154 msgid "" "D3 number format for numbers between -1.0 and 1.0, useful when you want " -"to have different siginificant digits for small and large numbers" +"to have different significant digits for small and large numbers" msgstr "" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:220 @@ -5526,18 +5522,6 @@ msgstr "" msgid "Filter box" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "" @@ -5698,7 +5682,7 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "" @@ -6351,7 +6335,6 @@ msgstr "" msgid "Issue 1001 - The database is under an unusual load." msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -8621,7 +8604,7 @@ msgid "Position of column level subtotal" msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:163 -msgid "Position of intermidiate node label on tree" +msgid "Position of intermediate node label on tree" msgstr "" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:293 @@ -8896,10 +8879,6 @@ msgstr "" msgid "Query preview" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 msgid "Query was stopped" msgstr "" @@ -9892,7 +9871,6 @@ msgid "Scoping" msgstr "" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -10440,7 +10418,7 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:52 msgid "" -"Show hierarchical relationships of data, with with the value represented " +"Show hierarchical relationships of data, with the value represented " "by area, showing proportion and contribution to the whole." msgstr "" @@ -11743,7 +11721,7 @@ msgstr "" #: superset/views/core.py:2280 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" @@ -12166,7 +12144,7 @@ msgstr "" #: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:127 msgid "" -"This color scheme is being overriden by custom label colors.\n" +"This color scheme is being overridden by custom label colors.\n" " Check the JSON metadata in the Advanced settings" msgstr "" @@ -13440,7 +13418,7 @@ msgstr "" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:27 msgid "" "Visualizes how a single metric varies across a country's principal " -"subdivisions (states, provinces, etc) on a chloropleth map. Each " +"subdivisions (states, provinces, etc) on a choropleth map. Each " "subdivision's value is elevated when you hover over the corresponding " "geographic boundary." msgstr "" @@ -14286,10 +14264,6 @@ msgstr "" msgid "[Alert] %(label)s" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "" @@ -14307,10 +14281,6 @@ msgstr "" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 msgid "[Untitled]" msgstr "" diff --git a/superset/translations/nl/LC_MESSAGES/messages.json b/superset/translations/nl/LC_MESSAGES/messages.json index 432ccca46b590..ece5bd80df9cc 100644 --- a/superset/translations/nl/LC_MESSAGES/messages.json +++ b/superset/translations/nl/LC_MESSAGES/messages.json @@ -1256,7 +1256,7 @@ "Data could not be retrieved from the results backend. You need to re-run the original query.": [ "" ], - "The query associated with these results could not be find. You need to re-run the original query.": [ + "The query associated with these results could not be found. You need to re-run the original query.": [ "" ], "You are not authorized to see this query. If you think this is an error, please reach out to your administrator.": [ @@ -2447,6 +2447,8 @@ ], "X-axis": [""], "Dimension to use on x-axis.": [""], + "Y-axis": [""], + "Dimension to use on y-axis.": [""], "Percentage threshold": [""], "Minimum threshold in percentage points for showing labels.": [""], "Rich tooltip": [""], @@ -4478,7 +4480,7 @@ "Sta manipulatie van de database toe met niet-SELECT statements zoals UPDATE, DELETE, CREATE, enz." ], "Enable query cost estimation": [""], - "For Presto and Postgres, shows a button to compute cost before running a query.": [ + "For Bigquery, Presto and Postgres, shows a button to compute cost before running a query.": [ "" ], "Allow this database to be explored": [""], diff --git a/superset/translations/nl/LC_MESSAGES/messages.po b/superset/translations/nl/LC_MESSAGES/messages.po index c81d13bba4464..2daaa619fdc8a 100644 --- a/superset/translations/nl/LC_MESSAGES/messages.po +++ b/superset/translations/nl/LC_MESSAGES/messages.po @@ -2769,7 +2769,6 @@ msgid "Filter List" msgstr "Filter Lijst" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:261 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:94 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -3369,7 +3368,7 @@ msgstr "" #: superset/views/core.py:2321 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" @@ -9922,39 +9921,10 @@ msgstr "SQL" msgid "No query history yet..." msgstr "Nog geen zoekgeschiedenis…" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:137 -msgid "An error occurred when refreshing queries" -msgstr "Er is een fout opgetreden bij het vernieuwen van de queries" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:185 #: superset-frontend/src/components/DatabaseSelector/index.tsx:184 msgid "It seems you don't have access to any database" msgstr "Het lijkt erop dat je geen toegang hebt tot een database" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:200 -msgid "Filter by user" -msgstr "Filter op gebruiker" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:209 -msgid "Filter by database" -msgstr "Filter op database" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:218 -msgid "Query search string" -msgstr "Query zoek string" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:224 -msgid "[From]-" -msgstr "[From]-" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:236 -msgid "[To]-" -msgstr "[To]-" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:245 -msgid "Filter by status" -msgstr "Filter op status" - #: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:117 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:54 #: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:142 @@ -15011,7 +14981,7 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "" diff --git a/superset/translations/pt/LC_MESSAGES/message.po b/superset/translations/pt/LC_MESSAGES/message.po index b944475c5591c..e06a21ce4f42f 100644 --- a/superset/translations/pt/LC_MESSAGES/message.po +++ b/superset/translations/pt/LC_MESSAGES/message.po @@ -2033,7 +2033,6 @@ msgstr "Nenhum registo encontrado" msgid "Filter List" msgstr "Filtros" -#: superset-frontend/src/SqlLab/components/QuerySearch.jsx:296 #: superset-frontend/src/explore/components/DataTableControl.tsx:73 #: superset-frontend/src/explore/components/controls/VizTypeControl.jsx:226 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:398 @@ -3599,40 +3598,11 @@ msgstr "SQL" msgid "No query history yet..." msgstr "Ainda não há histórico de queries ..." -#: superset-frontend/src/SqlLab/components/QuerySearch.jsx:193 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar.jsx:101 #: superset-frontend/src/components/DatabaseSelector.tsx:151 msgid "It seems you don't have access to any database" msgstr "Parece que não tem acesso a nenhuma base de dados" -#: superset-frontend/src/SqlLab/components/QuerySearch.jsx:220 -msgid "An error occurred when refreshing queries" -msgstr "Ocorreu um erro ao criar a origem dos dados" - -#: superset-frontend/src/SqlLab/components/QuerySearch.jsx:235 -msgid "Filter by user" -msgstr "Valor de filtro" - -#: superset-frontend/src/SqlLab/components/QuerySearch.jsx:244 -msgid "Filter by database" -msgstr "Selecione uma base de dados" - -#: superset-frontend/src/SqlLab/components/QuerySearch.jsx:253 -msgid "Query search string" -msgstr "Pesquisa de Query" - -#: superset-frontend/src/SqlLab/components/QuerySearch.jsx:259 -msgid "[From]-" -msgstr "[A partir de]-" - -#: superset-frontend/src/SqlLab/components/QuerySearch.jsx:271 -msgid "[To]-" -msgstr "[Para]-" - -#: superset-frontend/src/SqlLab/components/QuerySearch.jsx:280 -msgid "Filter by status" -msgstr "Valor de filtro" - #: superset-frontend/src/SqlLab/components/QueryTable.jsx:128 #: superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.jsx:34 #: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:134 diff --git a/superset/translations/pt_BR/LC_MESSAGES/messages.po b/superset/translations/pt_BR/LC_MESSAGES/messages.po index 2441b2c768325..77695a25b6dba 100644 --- a/superset/translations/pt_BR/LC_MESSAGES/messages.po +++ b/superset/translations/pt_BR/LC_MESSAGES/messages.po @@ -1238,10 +1238,6 @@ msgstr "Ocorreu um erro" msgid "An error occurred saving dataset" msgstr "Ocorreu um erro ao salvar o conjunto de dados" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "Ocorreu um erro ao atualizar as consultas" - #: superset/key_value/commands/exceptions.py:33 #, fuzzy msgid "An error occurred while accessing the value." @@ -5928,18 +5924,6 @@ msgstr "Filtrar por usuário" msgid "Filter box" msgstr "Caixa de filtro" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "Filtrar por banco de dados" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "Filtrar por status" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "Filtrar por usuário" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "Configuração do filtro" @@ -6115,7 +6099,7 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 #, fuzzy msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "Estima o custo antes de executar uma consulta" @@ -6830,7 +6814,6 @@ msgstr "Problema 1000 - A fonte de dados é muito grande para consulta." msgid "Issue 1001 - The database is under an unusual load." msgstr "Problema 1001 - O banco de dados está sob carga atípica." -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -9533,10 +9516,6 @@ msgstr "Nome da consulta" msgid "Query preview" msgstr "Pré-visualização da consulta" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "Texto da consulta de busca" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 #, fuzzy msgid "Query was stopped" @@ -10596,7 +10575,6 @@ msgid "Scoping" msgstr "Escopo" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -12619,7 +12597,7 @@ msgstr "" #: superset/views/core.py:2280 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" @@ -15404,10 +15382,6 @@ msgstr "" msgid "[Alert] %(label)s" msgstr "[Alert] %(label)s" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "[A partir de]-" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "[Longitude] e as colunas [Latitude] devem estar presentes em [Group By]" @@ -15426,10 +15400,6 @@ msgstr "Mudar conjunto de dados" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "[Superset] O acesso à fonte de dados %(name) s foi concedido" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "[Para]-" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 #, fuzzy, python-format msgid "[Untitled]" diff --git a/superset/translations/ru/LC_MESSAGES/messages.json b/superset/translations/ru/LC_MESSAGES/messages.json index be3a0f1212e4d..9f4009b692b8f 100644 --- a/superset/translations/ru/LC_MESSAGES/messages.json +++ b/superset/translations/ru/LC_MESSAGES/messages.json @@ -2,2688 +2,5989 @@ "domain": "superset", "locale_data": { "superset": { + "22": ["22"], "": { "domain": "superset", - "plural_forms": "nplurals=1; plural=0;", + "plural_forms": "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);", "lang": "ru" }, - "Home": ["Главная"], - "Annotation Layers": ["Слои аннотаций"], - "Manage": ["Управление"], - "Databases": ["Базы данных"], - "Data": ["БД"], - "Datasets": ["Датасеты"], - "Charts": ["Графики"], - "Dashboards": ["Дашборды"], - "Plugins": ["Плагины"], - "CSS Templates": ["Шаблоны CSS"], - "Row level security": ["Безопасность на уровне строк"], - "Security": ["Безопасность"], - "Import Dashboards": ["Импорт дашбордов"], - "SQL Editor": ["Редактор SQL"], - "SQL Lab": ["Лаборатория SQL"], - "Saved Queries": ["Сохраненные запросы"], - "Query History": ["История запросов"], - "Upload a CSV": ["Загрузить CSV"], - "Upload Excel": ["Загрузить файл Excel"], - "Action Log": ["Журнал Действий"], - "Dashboard Emails": ["Рассылка дашбордов"], - "Chart Email Schedules": ["Рассылка графиков"], - "Alerts": ["Оповещения"], - "Alerts & Reports": ["Оповещения и Рассылка"], - "Access requests": ["Запросы доступа"], - "Druid Datasources": ["Источники Данных Druid"], - "Druid Clusters": ["Список Кластеров Druid"], - "Scan New Datasources": ["Сканирование Новых Источников"], - "Refresh Druid Metadata": ["Обновить Метаданные Druid"], - "Issue 1000 - The datasource is too large to query.": [ - "Проблема 1000 - Источник данных слишком велик для запроса." + "\n This filter was inherited from the dashboard's context.\n It won't be saved when saving the chart.\n ": [ + "\n Фильтр был наследован из контекста дашборда.\n Он не будет сохранен при сохранении графика.\n " ], - "Issue 1001 - The database is under an unusual load.": [ - "Проблема 1001 - Необычная загрузка базы данных." + "\n Error: %(text)s\n ": [ + "\n Ошибка: %(text)s\n " ], - "Issue 1002 - The database returned an unexpected error.": [ - "Проблема 1002 - База данных вернула непредвиденную ошибку." + " (excluded)": [" (исключено)"], + " Set the opacity to 0 if you do not want to override the color specified in the GeoJSON": [ + " Установите прозрачность 0, если вы не хотите переписывать цвет, указанный в GeoJSON" ], - "Issue 1003 - There is a syntax error in the SQL query. Perhaps there was a misspelling or a typo.": [ - "Проблема 1003 - Ошибка в SQL-запросе. Возможно опечатка." + " a dashboard OR ": [" дашборд или "], + " a new one": [" новый"], + " expression which needs to adhere to the ": [ + ", который должен придерживаться " ], - "Issue 1004 - The column was deleted or renamed in the database.": [ - "Проблема 1004 - Столбец был удалён или переименован в базе данных." + " source code of Superset's sandboxed parser": [ + " исходный код sandboxed парсера Суперсета" ], - "Issue 1005 - The table was deleted or renamed in the database.": [ - "Проблема 1005 - Таблица была удалена или переименована в базе данных." + " standard to ensure that the lexicographical ordering\n coincides with the chronological ordering. If the\n timestamp format does not adhere to the ISO 8601 standard\n you will need to define an expression and type for\n transforming the string into a date or timestamp. Note\n currently time zones are not supported. If time is stored\n in epoch format, put `epoch_s` or `epoch_ms`. If no pattern\n is specified we fall back to using the optional defaults on a per\n database/column name level via the extra parameter.": [ + " стандарта для обеспечения того, чтобы лексикографический порядок совпадал с хронологическим порядком. Если формат временной метки не соответствует стандарту ISO 8601, вам нужно будет определить выражение и тип для преобразования строки в дату или временную метку. В настоящее время часовые пояса не поддерживаются. Если время хранится в формате эпохи, введите \\`epoch_s\\` или \\`epoch_ms\\`. Если шаблон не указан, будут использованы необязательные значения по умолчанию на уровне имен для каждой базы данных/столбца с помощью дополнительного параметра." ], - "Issue 1006 - One or more parameters specified in the query are missing.": [ - "Проблема 1006 - Отсутствуют один или несколько параметров, используемых в запросе." + " to add calculated columns": [" для добавления вычисляемых столбцов"], + " to add metrics": [" для добавления мер"], + " to edit or add columns and metrics.": [ + " для редактирования или добавления столбцов и мер." ], - "Invalid certificate": ["Недействительный сертификат"], - "Unsafe return type for function %(func)s: %(value_type)s": [ - "Небезопасный возвращаемый тип для функции %(func)s: %(value_type)s" + " to mark a column as a time column": [ + ", чтобы пометить столбец как столбец даты/времени" ], - "Unsupported return value for method %(name)s": [ - "Неподдерживаемое возвращаемое значение для метода %(name)s" + " to open SQL Lab. From there you can save the query as a dataset.": [ + " в Лаборатории SQL. Там вы сможете сохранить запрос как датасет." ], - "Unsafe template value for key %(key)s: %(value_type)s": [ - "Небезопасное значение для ключа шаблона %(key)s: %(value_type)s" + " to visualize your data.": [" для визуализации ваших данных."], + "!= (Is not equal)": ["!= (не равно)"], + "%(dialect)s cannot be used as a data source for security reasons.": [ + "%(dialect)s не может использоваться в качестве источника данных по соображениям безопасности." ], - "Unsupported template value for key %(key)s": [ - "Неподдерживаемое значение для ключа шаблона %(key)s" + "%(message)s\nThis may be triggered by: \n%(issues)s": [ + "%(message)s\nВозможные причины: \n%(issues)s" ], - "Only `SELECT` statements are allowed against this database": [ - "Для этой БД разрешены только выражения `SELECT`" + "%(name)s.csv": ["%(name)s.csv"], + "%(object)s does not exist in this database.": [ + "%(object)s не существует в этой базе данных." ], - "CTAS (create table as select) can only be run with a query where the last statement is a SELECT. Please make sure your query has a SELECT as its last statement. Then, try running your query again.": [ - "CTAS (create table as select) может быть выполнено только в запросе, последняя операция которого SELECT." + "%(other)s %(tableName)s will appear here": [ + "%(other)s %(tableName)s появятся здесь после добавления" ], - "CVAS (create view as select) can only be run with a query with a single SELECT statement. Please make sure your query has only a SELECT statement. Then, try running your query again.": [ - "может быть выполнено только в запросе, в котором есть только одна операция SELECT." + "%(prefix)s %(title)s": ["%(prefix)s %(title)s"], + "%(rows)d rows returned": ["Получено строк: %(rows)d"], + "%(subtitle)s\nThis may be triggered by:\n %(issue)s": [ + "%(subtitle)s\nВозможные причины:\n %(issue)s" ], - "Viz is missing a datasource": [ - "У визуализации отсутствует источник данных" + "%(suggestion)s instead of \"%(undefinedParameter)s?\"": [ + "%(suggestion)s вместо \"%(undefinedParameter)s\"?", + "%(firstSuggestions)s или %(lastSuggestion)s вместо \"%(undefinedParameter)s\"?", + "%(firstSuggestions)s или %(lastSuggestion)s вместо \"%(undefinedParameter)s\"?" ], - "Applied rolling window did not return any data. Please make sure the source query satisfies the minimum periods defined in the rolling window.": [ - "" + "%(user)s was granted the role %(role)s that gives access to the %(datasource)s": [ + "%(user)s была назначена роль %(role)s, которая дает доступ к %(datasource)s" ], - "From date cannot be larger than to date": [ - "Невозможно выбрать дату [from], которая позже текущего дня" + "%(user)s's profile": ["%(user)s - профиль"], + "%(validator)s was unable to check your query.\nPlease recheck your query.\nException: %(ex)s": [ + "%(validator)s не смог проверить ваш запрос.\nПожалуйста, перепроверьте ваш запрос.\nОшибка: %(ex)s" ], - "Cached value not found": ["Значение не найдено в кеше"], - "Columns missing in datasource: %(invalid_columns)s": [ - "В источнике данных отсутствуют столбцы: %(invalid_columns)s" + "%s Error": ["%s Ошибка"], + "%s PASSWORD": ["%s ПАРОЛЬ"], + "%s Selected": ["%s Выбрано"], + "%s Selected (%s Physical, %s Virtual)": [ + "%s Выбрано (%s Физические, %s Виртуальные)" ], - "Table View": ["Табличный вид"], - "You cannot use [Columns] in combination with [Group By]/[Metrics]/[Percentage Metrics]. Please choose one or the other.": [ - "Нельзя использовать [Столбцы] одновременно с [Группировка по][Показатели][Процентные показатели]. Пожалуйста, выберите что-то одно." + "%s Selected (Physical)": ["%s Выбрано (Физические)"], + "%s Selected (Virtual)": ["%s Выбрано (Виртуальные)"], + "%s aggregates(s)": ["Агрегатных функций: %s"], + "%s column(s)": ["Столбцов: %s"], + "%s operator(s)": ["%s параметр(ы)"], + "%s option": ["%s вариант", "%s варианта", "%s вариантов"], + "%s option(s)": ["%s вариант(ов)"], + "%s row": ["%s строка", "%s строки", "%s строк"], + "%s saved metric(s)": ["Сохраненная мер: %s"], + "%s updated": ["Обновлено: %s"], + "%s%s": ["%s%s"], + "%s-%s of %s": ["%s-%s из %s"], + "(Removed)": ["(Удалено)"], + "(deleted or invalid type)": ["(удалено или невалидный тип)"], + "(no description, click to see stack trace)": [ + "(нет описания, нажмите для просмотра трассировки стека)" ], - "Pick a granularity in the Time section or uncheck 'Include Time'": [ - "Выберите столбец с датой и необходимый период в секции «Время» или снимите флажок «Включая дату»" + "(optional) default value for the filter, when using the multiple option, you can use a semicolon-delimited list of options.": [ + "(опционально) значение по умолчанию для фильтра. Когда используются множественные значения, вы можете вставить список значений, разделённых символами точка с запятой" ], - "Time Table View": [""], - "Pick at least one metric": ["Выберите хотя бы один показатель"], - "When using 'Group By' you are limited to use a single metric": [ - "При использовании поля [Группировка] вы не ограничены использованием одного среза" + "), and they become available in your SQL (example:": [ + "), и они станут доступны в ваших SQL запросах (пример:" ], - "Pivot Table": ["Pivot Table"], - "Please choose at least one 'Group by' field ": [ - "Пожалуйста, выберите хотя бы один срез в поле ‘Группировка’ " + "*%(name)s*\n\n%(description)s\n\n<%(url)s|Explore in Superset>\n\n%(table)s\n": [ + "*%(name)s*\n\n%(description)s\n\n<%(url)s|Исследовать в Суперсете>\n\n%(table)s\n" ], - "Please choose at least one metric": [ - "Пожалуйста, выберите хотя бы один показатель" + "*%(name)s*\n\n%(description)s\n\nError: %(text)s\n": [ + "*%(name)s*\n\n%(description)s\n\nОшибка: %(text)s\n" ], - "Group By' and 'Columns' can't overlap": [ - "Нельзя использовать один и тот же срез в двух полях" - ], - "Treemap": ["Treemap"], - "Calendar Heatmap": ["Calendar Heatmap"], - "Bubble Chart": ["Bubble Chart"], - "Please use 3 different metric labels": [ - "Пожалуйста, выберите разные срезы данных для левой и правой оси" - ], - "Pick a metric for x, y and size": ["Выберите срез для X, Y и размер"], - "Bullet Chart": ["Bullet Chart"], - "Pick a metric to display": ["Выберите показатель для отображения"], - "Big Number with Trendline": ["Big Number with Trendline"], - "Pick a metric!": ["Выберите показатель!"], - "Big Number": ["Big Number"], - "Time Series - Line Chart": ["Time Series - Line Chart"], - "Pick a time granularity for your time series": [ - "Выберите период для временных рядов" + "+ %s more": ["+ еще %s"], + ",": [","], + "-- Note: Unless you save your query, these tabs will NOT persist if you clear your cookies or change browsers.\n\n": [ + "-- Примечание: Пока вы не сохраните ваш запрос, эти вкладки НЕ будут сохранены, если вы очистите куки или смените браузер.\n\n" ], - "An enclosed time range (both start and end) must be specified when using a Time Comparison.": [ - "" + ".": ["."], + "0 Selected": ["0 выбрано"], + "1 calendar day frequency": ["Дневная частота"], + "1 day": ["1 день"], + "1 day ago": ["1 день назад"], + "1 hour": ["1 час"], + "1 hourly frequency": ["Часовая частота"], + "1 minute": ["1 минута"], + "1 minutely frequency": ["Минутная частота"], + "1 month end frequency": ["Месячная частота (конец месяца)"], + "1 month start frequency": ["Месячная частота (начало месяца)"], + "1 week": ["1 неделя"], + "1 week ago": ["1 неделя назад"], + "1 week starting Monday (freq=W-MON)": [ + "1 неделя с началом в Понедельник (част=W-MON)" + ], + "1 week starting Sunday (freq=W-SUN)": [ + "1 неделя с началом в Воскресенье (част=W-SUN)" + ], + "1 year": ["1 год"], + "1 year ago": ["1 год назад"], + "1 year end frequency": ["Годовая частота (конец года)"], + "1 year start frequency": ["Годовая частота (начало года)"], + "10 minute": ["10 минут"], + "104 weeks": ["104 недели"], + "104 weeks ago": ["104 недели назад"], + "15 minute": ["15 минут"], + "156 weeks": ["156 недель"], + "156 weeks ago": ["156 недель назад"], + "1AS": ["1С"], + "1D": ["1Д"], + "1H": ["1Ч"], + "1M": ["1М"], + "1T": ["1МИН"], + "2 years": ["2 года"], + "2 years ago": ["2 года назад"], + "2/98 percentiles": ["2/98 перцентели"], + "28 days": ["28 дней"], + "28 days ago": ["28 дней назад"], + "2D": ["2D карты"], + "3 letter code of the country": ["3х буквенный код страны"], + "3 years": ["3 года"], + "3 years ago": ["3 года назад"], + "30 days": ["30 дней"], + "30 days ago": ["30 дней назад"], + "30 minute": ["30 минут"], + "30 minutes": ["30 минут"], + "30 second": ["30 секунд"], + "30 seconds": ["30 секунд"], + "3D": ["3D карты"], + "4 weeks (freq=4W-MON)": ["4 недели (част=4W-MON)"], + "5 minute": ["5 минут"], + "5 minutes": ["5 минут"], + "5 second": ["5 секунд"], + "5 seconds": ["5 секунд"], + "52 weeks": ["52 недели"], + "52 weeks ago": ["52 недели назад"], + "52 weeks starting Monday (freq=52W-MON)": [ + "52 недели с началом в Понедельник (част=52W-MON)" + ], + "6 hour": ["6 часов"], + "60 days": ["60 дней"], + "7 calendar day frequency": ["Недельная частота"], + "7 days": ["7 дней"], + "7D": ["7Д"], + "9/91 percentiles": ["9/91 перцентели"], + "90 days": ["90 дней"], + ":": [":"], + "< (Smaller than)": ["< (меньше чем)"], + "<= (Smaller or equal)": ["<= (меньше или равно)"], + "<enter SQL expression here>": ["<введите SQL выражение>"], + "<new column>": ["<новый столбец>"], + "<new metric>": ["<новая мера>"], + "<new spatial>": ["<новая пространственная мера>"], + "<no type>": ["<без типа>"], + "== (Is equal)": ["== (равно)"], + "> (Larger than)": ["> (больше чем)"], + ">= (Larger or equal)": [">= (больше или равно)"], + "A Big Number": ["Карточка"], + "A comma separated list of columns that should be parsed as dates": [ + "Разделённый запятыми список столбцов, которые должны быть интерпретированы как даты." ], - "Time Series - Multiple Line Charts": [ - "Time Series - Multiple Line Charts" + "A comma separated list of columns that should be parsed as dates.": [ + "Разделённый запятыми список столбцов, которые должны быть интерпретированы как даты." ], - "Time Series - Dual Axis Line Chart": [ - "Time Series - Dual Axis Line Chart" + "A comma-separated list of schemas that files are allowed to upload to.": [ + "Разделённый запятыми список схем, в которые можно загружать файлы." ], - "Pick a metric for left axis!": ["Выберите значение для левой оси!"], - "Pick a metric for right axis!": ["Выберите значение для правой оси!"], - "Please choose different metrics on left and right axis": [ - "Пожалуйста, выберите разные срезы данных для левой и правой оси" + "A database with the same name already exists.": [ + "База данных с таким же именем уже существует" ], - "Time Series - Bar Chart": ["Time Series - Bar Chart"], - "Time Series - Period Pivot": ["Time Series - Period Pivot"], - "Time Series - Percent Change": ["Time Series - Percent Change"], - "Time Series - Stacked": ["Time Series - Stacked"], - "Histogram": ["Histogram"], - "Must have at least one numeric column specified": [ - "Должен быть указан хотя бы один числовой столбец" + "A full URL pointing to the location of the built plugin (could be hosted on a CDN for example)": [ + "Полный URL, указывающий на местоположение плагина (например, ссылка на CDN)" ], - "Distribution - Bar Chart": ["Distribution - Bar Chart"], - "Can't have overlap between Series and Breakdowns": [ - "Срезы в полях [Столбцы данных] и [Ряды данных] должны быть разными" + "A handlebars template that is applied to the data": [ + "Шаблон handlebars, примененный к данным" ], - "Pick at least one field for [Series]": [ - "Выберите хотя бы одно значение для поля [Столбцы данных]" + "A human-friendly name": ["Человекочитаемое имя"], + "A list of domain names that can embed this dashboard. Leaving this field empty will allow embedding from any domain.": [ + "Список доменных имен, которые могут встраивать этот дашборд. Если оставить поле пустым, любой домен сможет сделать встраивание." ], - "Sunburst": ["Sunburst"], - "Sankey": ["Sankey"], - "Pick exactly 2 columns as [Source / Target]": [ - "Выберите ровно два среза в поле [Источник / Назначение]" + "A list of users who can alter the chart. Searchable by name or username.": [ + "Владельцы - это пользователи, которые могут изменять график" ], - "There's a loop in your Sankey, please provide a tree. Here's a faulty link: {}": [ - "В полях [Источника] и [Назначения] есть одинаковый срез данных - {}. Срезы не должны пересекаться!" + "A map of the world, that can indicate values in different countries.": [ + "Карта мира, на которой могут быть указаны значения в разных странах." ], - "Directed Force Layout": [""], - "Pick exactly 2 columns to 'Group By'": [ - "Выберите ровно два столбца в поле [Группировка]" + "A map that takes rendering circles with a variable radius at latitude/longitude coordinates": [ + "На карте отображаются маркеры переменного радиуса и цвета." ], - "Country Map": ["Карта Стран"], - "World Map": ["Карта Мира"], - "Filters": ["Фильтры"], - "Invalid filter configuration, please select a column": [""], - "Parallel Coordinates": [""], - "Heatmap": ["Heatmap"], - "Horizon Charts": ["Horizon Charts"], - "Mapbox": ["Mapbox"], - "[Longitude] and [Latitude] must be set": [ - "Столбцы [Долгота] и [Широта] должны присутствовать в поле [Группировка]" + "A metric to use for color": [ + "Показатель, используемый для расчета цвета" ], - "Must have a [Group By] column to have 'count' as the [Label]": [ - "Чтобы получить `count` как [Метку], должна быть заполнена [Группировка по]" + "A polar coordinate chart where the circle is broken into wedges of equal angle, and the value represented by any wedge is illustrated by its area, rather than its radius or sweep angle.": [ + "" ], - "Choice of [Label] must be present in [Group By]": [ - "Выбор для [Метки] должен присутствовать в [Группировке по]" + "A readable URL for your dashboard": ["Читаемый URL-адрес для дашборда"], + "A reference to the [Time] configuration, taking granularity into account": [ + "" ], - "Choice of [Point Radius] must be present in [Group By]": [ - "Срез [Радиуса точки] должен присутствовать в поле [Группировка]" + "A report named \"%(name)s\" already exists": [ + "Рассылка с именем \"%(name)s\" уже существует" ], - "[Longitude] and [Latitude] columns must be present in [Group By]": [ - "Столбцы [Долгота] и [Широта] должны присутствовать в поле [Группировка]" + "A reusable dataset will be saved with your chart.": [ + "Переиспользуемый датасет будет сохранен с вашим графиком." ], - "Deck.gl - Multiple Layers": ["Deck.gl - Multiple Layers"], - "Bad spatial key": [""], - "Invalid spatial point encountered: %s": [""], - "Encountered invalid NULL spatial entry, please consider filtering those out": [ - "" + "A screenshot of the dashboard will be sent to your email at": [ + "Скриншот дашборда будет отправлен на ваш электронный адрес" ], - "Deck.gl - Scatter plot": ["Deck.gl - Scatter plot"], - "Deck.gl - Screen Grid": ["Deck.gl - Screen Grid"], - "Deck.gl - 3D Grid": ["Deck.gl - 3D Grid"], - "Deck.gl - Paths": ["Deck.gl - Paths"], - "Deck.gl - Polygon": ["Deck.gl - Polygon"], - "Deck.gl - 3D HEX": ["Deck.gl - 3D HEX"], - "Deck.gl - GeoJSON": ["Deck.gl - GeoJSON"], - "Deck.gl - Arc": ["Deck.gl - Arc"], - "Event flow": ["Event flow"], - "Time Series - Paired t-test": ["Time Series - Paired t-test"], - "Time Series - Nightingale Rose Chart": [ - "Time Series - Nightingale Rose Chart" + "A set of parameters that become available in the query using Jinja templating syntax": [ + "Набор параметров, которые доступны в запросе через шаблонизацию Jinja." ], - "Partition Diagram": ["Partition Diagram"], - "Choose either fields to [Group By] and [Metrics] and/or [Percentage Metrics], or [Columns], not both": [ - "Выберите срез данных в полях [Показатели] или [Столбцы], но не в обоих одновременно" + "A time column must be specified when using a Time Comparison.": [ + "Столбец даты/времени должен быть указан при использовании сравнения по времени" ], - "Box Plot": ["Box Plot"], - "Distribution - NVD3 - Pie Chart": ["Distribution - NVD3 - Pie Chart"], - "iFrame": [""], - "Deleted %(num)d annotation layer": ["Удалено слоёв аннотации: %(num)d"], - "All Text": ["Весь текст"], - "Deleted %(num)d annotation": ["Удалено %(num)d аннотаций"], - "End date must be after start date": [ - "Невозможно выбрать дату [from], которая позже текущего дня" + "A time series chart that visualizes how a related metric from multiple groups vary over time. Each group is visualized using a different color.": [ + "Диаграмма временного ряда, которая визуализирует, как связанная метрика из нескольких групп изменяется с течением времени. Для каждой группы используется свой цвет." ], - "Short description must be unique for this layer": [ - "Краткое описание должно быть уникальным для этого слоя" + "A timeout occurred while executing the query.": [ + "Вышло время исполнения запроса." ], - "Annotations could not be deleted.": ["Аннотации не могут быть удалены."], - "Annotation not found.": ["Аннотация не найдена."], - "Annotation parameters are invalid.": [ - "Параметры аннотации недействительны." + "A timeout occurred while generating a csv.": [ + "Вышло время создания CSV файла." ], - "Annotation could not be created.": ["Аннотация не может быть создана."], - "Annotation could not be updated.": [ - "Аннотация не может быть обновлена." + "A timeout occurred while generating a dataframe.": [ + "Вышло время создания датафрейма." ], - "Annotation delete failed.": ["Удаление аннотации не удалось."], - "Annotation layer parameters are invalid.": [ - "Параметры слоя аннотации недействительны." + "A timeout occurred while taking a screenshot.": [ + "Вышло время создания скриншота." ], - "Annotation layer could not be deleted.": [ - "Слой аннотации не может быть удалён." + "A valid color scheme is required": [ + "Требуется корректная цветовая схема" ], - "Annotation layer could not be created.": [ - "Слой аннотаций не может быть создан." + "APPLY": ["ПРИМЕНИТЬ"], + "APR": ["АПР"], + "AQE": ["Асинхронные запросы"], + "AUG": ["АВГ"], + "AXIS TITLE MARGIN": ["ОТСТУП ЗАГОЛОВКА ОСИ"], + "AXIS TITLE POSITION": ["ПОЛОЖЕНИЕ ЗАГОЛОВКА ОСИ"], + "About": ["О программе"], + "Access": ["Доступ"], + "Access requests": ["Запросы доступа"], + "Access to user activity data is restricted": [ + "Запрещен доступ к истории действий пользователя" ], - "Annotation layer could not be updated.": [ - "Слой аннотаций не может быть обновлён." + "Access token": ["Токен доступа"], + "Access was requested": ["Доступ запрошен"], + "Action": ["Действие"], + "Action Log": ["Журнал действий"], + "Actions": ["Действия"], + "Active": ["Активен"], + "Actual Values": ["Фактические значения"], + "Actual time range": ["Фактический временной интервал"], + "Actual value": ["Фактическое значение"], + "Actual values": ["Фактические значения"], + "Adaptive formatting": ["Адаптивное форматирование"], + "Add": ["Добавить"], + "Add Alert": ["Добавить оповещение"], + "Add CSS Template": ["Добавить CSS шаблон"], + "Add CSS template": ["Добавить CSS шаблоны"], + "Add Chart": ["Добавить график"], + "Add Column": ["Добавить столбец"], + "Add Dashboard": ["Добавить дашборд"], + "Add Database": ["Добавить базу данных"], + "Add Dataset and Create Chart": ["Добавить датасет и создать график"], + "Add Log": ["Добавить запись"], + "Add Metric": ["Добавить меру"], + "Add Report": ["Добавить рассылку"], + "Add Saved Query": ["Добавить сохраненный запрос"], + "Add a Plugin": ["Добавить плагин"], + "Add a dataset": ["Добавить датасет"], + "Add a new tab": ["Новая вкладка"], + "Add a new tab to create SQL Query": [ + "Откройте новую вкладку для создания SQL запроса" + ], + "Add additional custom parameters": [ + "Добавление дополнительных пользовательских параметров" + ], + "Add an annotation layer": ["Добавить слой аннотации"], + "Add an item": ["Добавить запись"], + "Add and edit filters": ["Добавить и изменить фильтры"], + "Add annotation": ["Добавить аннотацию"], + "Add annotation layer": ["Добавить слой аннотации"], + "Add calculated columns to dataset in \"Edit datasource\" modal": [ + "Добавьте новые вычисляемые столбцы в датасет в настройках датасета" ], - "Annotation layer not found.": ["Слой аннотаций не найден."], - "Annotation layer delete failed.": ["Ошибка удаления слоя аннотаций."], - "Annotation layer has associated annotations.": [ - "Слой аннотаций имеет присвоенные аннотации." + "Add calculated temporal columns to dataset in \"Edit datasource\" modal": [ + "Добавьте новые столбцы формата дата/время в датасет в настройках датасета" ], - "Name must be unique": ["Имя должно быть уникальным"], - "Deleted %(num)d chart": ["Удалено %(num)d графиков"], - "Request is not JSON": ["Запрос не в формате JSON"], - "Request is incorrect: %(error)s": ["Запрос некорректен: %(error)s"], - "`confidence_interval` must be between 0 and 1 (exclusive)": [ - "`доверительный_интервал` должен быть между 0 и 1 (исключая)" + "Add dataset": ["Добавить датасет"], + "Add delivery method": ["Добавить способ оповещения"], + "Add extra connection information.": [ + "Дополнительная информация по подключению" ], - "lower percentile must be greater than 0 and less than 100. Must be lower than upper percentile.": [ - "нижний процентиль должен быть больше 0 и меньше верхнего процентиля." + "Add filter": ["Добавить фильтр"], + "Add filters and dividers": ["Добавить фильтры и разделители"], + "Add item": ["Добавить запись"], + "Add metric": ["Добавить меру"], + "Add metrics to dataset in \"Edit datasource\" modal": [ + "Добавьте меры в датасет в настройках датасета" + ], + "Add new color formatter": ["Добавить цветовое форматирование"], + "Add new formatter": ["Добавить форматирование"], + "Add notification method": ["Добавить способ уведомления"], + "Add required control values to preview chart": [ + "Добавьте обязательные значения для предпросмотра графика" + ], + "Add required control values to save chart": [ + "Добавьте обязательные значения для сохранения графика" + ], + "Add sheet": ["Добавить лист"], + "Add the name of the chart": ["Задайте имя графика"], + "Add the name of the dashboard": ["Задайте имя дашборда"], + "Add to dashboard": ["Добавить в дашборд"], + "Add/Edit Filters": ["Добавить/изменить фильтры"], + "Added": ["Добавлено"], + "Added to 1 dashboard": [ + "Добавлено в 1 дашборд", + "Добавлено в %s дашборда", + "Добавлено в %s дашбордов" + ], + "Additional Parameters": ["Дополнительные параметры"], + "Additional fields may be required": [""], + "Additional information": ["Дополнительная информация"], + "Additional metadata": ["Дополнительные метаданные"], + "Additional padding for legend.": ["Дополнительный отступ для легенды"], + "Additional parameters": ["Дополнительные параметры"], + "Additional settings.": ["Дополнительная настройка"], + "Additional text to add before or after the value, e.g. unit": [ + "Дополнительный текст перед значением, например, единица измерения" + ], + "Additive": ["Смешанный"], + "Adjust how this database will interact with SQL Lab.": [ + "Настройка взаимодействия базы данных с Лабораторией SQL" + ], + "Advanced": ["Продвинутая настройка"], + "Advanced Analytics": ["Расширенная аналитика"], + "Advanced Data type": ["Расширенный тип данных"], + "Advanced analytics": ["Расширенная аналитика"], + "Advanced analytics Query A": ["Расширенный анализ: запрос А"], + "Advanced analytics Query B": ["Расширенный анализ: запрос Б"], + "Advanced data type": ["Расширенный тип данных"], + "Advanced-Analytics": ["Продвинутая аналитика"], + "Aesthetic": ["Эстетично"], + "After": ["После"], + "Aggregate": ["Агрегация"], + "Aggregate Mean": ["Агрегированное среднее"], + "Aggregate Sum": ["Агрегированная сумма"], + "Aggregate function applied to the list of points in each cluster to produce the cluster label.": [ + "Агрегатная функция, применяемая для списка точек в каждом кластере для создания метки кластера." + ], + "Aggregate function to apply when pivoting and computing the total rows and columns": [ + "Агрегатная функция, применяемая для сводных таблиц и вычислении суммарных значений." + ], + "Aggregates data within the boundary of grid cells and maps the aggregated values to a dynamic color scale": [ + "" ], - "upper percentile must be greater than 0 and less than 100. Must be higher than lower percentile.": [ - "верхний процентиль должен быть больше нижнего процентиля и меньше 100." + "Aggregation function": ["Функция агрегирования"], + "Alert Triggered, In Grace Period": [ + "Оповещение сработало во время перерыва" ], - "`width` must be greater or equal to 0": [ - "`ширина` должна быть больше, чем 0" + "Alert condition": ["Условие оповещения"], + "Alert condition schedule": ["Расписание условия оповещения"], + "Alert ended grace period.": ["У оповещения закончился перерыв."], + "Alert failed": ["Оповещение не сработало"], + "Alert fired during grace period.": [ + "Оповещение сработало во время перерыва" ], - "`row_limit` must be greater than or equal to 1": [ - "`лимит_строк` должен быть больше или равен 1" + "Alert found an error while executing a query.": [ + "Возникла ошибка при выполнении запроса для оповещения." ], - "`row_offset` must be greater than or equal to 0": [ - "`смещение_строк` должно быть больше или равно 0" + "Alert name": ["Имя оповещения"], + "Alert on grace period": ["Оповещение во время перерыва"], + "Alert query returned a non-number value.": [ + "Запрос оповещения вернул нечисловое значение." ], - "There are associated alerts or reports: %s,": [ - "Существуют оповещения или рассылки: %s," + "Alert query returned more than one column.": [ + "Запрос оповещения вернул больше, чем один столбец." ], - "Database does not exist": ["База данных не существует"], - "Dashboards do not exist": ["Дашборды отсутствуют"], - "Datasource type is required when datasource_id is given": [ - "Тип источника данных обязателен, если задан ID" + "Alert query returned more than one column. %s columns returned": [ + "Запрос оповещения вернул больше, чем один столбец. Возвращено столбцов: %s" ], - "Chart parameters are invalid.": ["Параметры графика недействительны."], - "Chart could not be created.": ["График не может быть создан."], - "Chart could not be updated.": ["График не может быть обновлён."], - "Chart could not be deleted.": ["График не может быть удалён."], - "There are associated alerts or reports": [ - "Существуют привязанные оповещения или рассылки" + "Alert query returned more than one row.": [ + "Запрос оповещения вернул больше, чем одну строку." ], - "Changing this chart is forbidden": ["Изменение этого графика запрещено"], - "Charts could not be deleted.": ["Графики не могут быть удалены."], - "Import chart failed for an unknown reason": [ - "Импорт графика не удался по неизвестной причине" + "Alert query returned more than one row. %s rows returned": [ + "Запрос оповещения вернул больше, чем одну строку. Возвращено строк: %s" ], - "Database does not exist": ["База данных не существует"], - "Dashboards do not exist": ["Дашборды отсутствуют"], - "Datasource type is required when datasource_id is given": [ - "Тип источника данных обязателен, если задан ID" + "Alert running": ["Выполняется оповещение"], + "Alert triggered, notification sent": [ + "Сработало оповещение, уведомление отправлено" ], - "Chart parameters are invalid.": ["Параметры графика недействительны."], - "Chart could not be created.": ["График не может быть создан."], - "Chart could not be updated.": ["График не может быть обновлён."], - "Chart could not be deleted.": ["График не может быть удалён."], - "There are associated alerts or reports": [ - "Существуют привязанные оповещения или рассылки" + "Alert validator config error.": [ + "Неверная конфигурация валидатора оповещений." ], - "Changing this chart is forbidden": ["Изменение этого графика запрещено"], - "Charts could not be deleted.": ["Графики не могут быть удалены."], - "Import chart failed for an unknown reason": [ - "Импорт графика не удался по неизвестной причине" + "Alerts": ["Оповещения"], + "Alerts & Reports": ["Оповещения и отчеты"], + "Alerts & reports": ["Оповещения и отчеты"], + "Align +/-": ["Выровнять +/-"], + "All": ["Все"], + "All Text": ["Весь текст"], + "All charts": ["Все графики"], + "All filters": ["Все фильтры"], + "All filters (%(filterCount)d)": ["Все фильтры (%(filterCount)d)"], + "All panels": ["Все панели"], + "All panels with this column will be affected by this filter": [ + "Фильтр будет применён ко всем панелям с этим столбцом" ], - "Owners are invalid": ["Владельцы недействительны"], - "Dataset does not exist": ["Источник данных %(name)s уже существует"], - "`operation` property of post processing object undefined": [ - "Неопределено свойство `operation` объекта пост-процессинга" + "Allow CREATE TABLE AS": ["Разрешить CREATE TABLE AS"], + "Allow CREATE TABLE AS option in SQL Lab": [ + "Разрешить CREATE TABLE AS в Лаборатории SQL" ], - "Unsupported post processing operation: %(operation)s": [ - "Неподдерживаемая операция пост-процессинга: %(operation)s" + "Allow CREATE VIEW AS": ["Разрешить CREATE VIEW AS"], + "Allow CREATE VIEW AS option in SQL Lab": [ + "Разрешить CREATE VIEW AS в Лаборатории SQL" ], - "Adding new datasource [{}]": ["Добавление нового источника данных [{}]"], - "Refreshing datasource [{}]": ["Обновление источника данных [{}]"], - "Metric(s) {} must be aggregations.": [ - "Показатель(и) {} должны быть агрегированы." + "Allow Csv Upload": ["Разрешить загрузку CSV"], + "Allow DML": ["Разрешить DML"], + "Allow columns to be rearranged": ["Разрешить смену столбцов местами"], + "Allow creation of new tables based on queries": [ + "Разрешить создание новых таблиц на основе запросов" ], - "Unsupported extraction function: ": ["Неподдерживаемая функция: "], - "Columns": ["Столбцы"], - "Show Druid Column": ["Показать столбец Druid"], - "Add Druid Column": ["Добавить столбец Druid"], - "Edit Druid Column": ["Редактировать столбец Druid"], - "Column": ["Столбец"], - "Type": ["Тип"], - "Datasource": ["Источник данных"], - "Groupable": ["Группируемый"], - "Filterable": ["Фильтруемый"], - "Whether this column is exposed in the `Filters` section of the explore view.": [ - "Необходимо отметить, если столбец должен быть доступен в разделе «Фильтры»." + "Allow creation of new views based on queries": [ + "Разрешить создание новых представлений на основе запросов" ], - "Metrics": ["Показатели"], - "Show Druid Metric": ["Показать Druid Метрики"], - "Add Druid Metric": ["Добавить Druid Метрику"], - "Edit Druid Metric": ["Редактировать Druid Метрику"], - "Metric": ["Показатель"], - "Description": ["Описание"], - "Verbose Name": ["Полное имя"], - "JSON": ["JSON"], - "Druid Datasource": ["Druid - Источники Данных"], - "Warning Message": ["Предупреждающее сообщение"], - "Show Druid Cluster": ["Показать кластер Druid"], - "Add Druid Cluster": ["Добавить кластер Druid"], - "Edit Druid Cluster": ["Редактировать кластер Druid"], - "Cluster Name": ["Имя кластера"], - "Broker Host": ["Хост брокера"], - "Broker Port": ["Порт брокера"], - "Broker Username": ["Пользователь брокера"], - "Broker Password": ["Пароль брокера"], - "Broker Endpoint": ["Адрес брокера"], - "Cache Timeout": ["Тайм-аут кеша"], - "Metadata Last Refreshed": ["Метаданные обновлены"], - "Duration (in seconds) of the caching timeout for this cluster. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.": [ - "Тайм-аут кеша (в секундах) для этого кластера. Тайм-аут 0 означает, что кеш не может быть просрочен." - ], - "Druid supports basic authentication. See [auth](http://druid.io/docs/latest/design/auth.html) and druid-basic-security extension": [ - "Druid поддерживает обычную аутентификацию. См. [эту страницу](http://druid.io/docs/latest/design/auth.html) и расширения для druid-basic-security" - ], - "Show Druid Datasource": ["Показать источник данных Druid"], - "Add Druid Datasource": ["Добавить источник данных Druid"], - "Edit Druid Datasource": ["Редактировать источник данных Druid"], - "The list of charts associated with this table. By altering this datasource, you may change how these associated charts behave. Also note that charts need to point to a datasource, so this form will fail at saving if removing charts from a datasource. If you want to change the datasource for a chart, overwrite the chart from the 'explore view'": [ - "Список графиков, связанных с этой таблицей. Изменяя этот источник данных, можно изменить поведение связанных с ним графиков. Также обратите внимание, что графики должны указывать на источник данных, поэтому эта форма не будет сохранена при удалении срезов из источника данных. Если вы хотите изменить источник данных для среза, сделайте это в свойствах самого графика." + "Allow data manipulation language": [ + "Разрешить операции вставки, обновления и удаления данных" ], - "Timezone offset (in hours) for this datasource": [ - "Смещение часового пояса (в часах) для этого источника данных" + "Allow end user to drag-and-drop column headers to rearrange them. Note their changes won't persist for the next time they open the chart.": [ + "Разрешить конечному пользователю перемещать столбцы, удерживая их заголовки. Заметьте, такие изменения будут нейтрализованы при следующем обращении к дашборду." ], - "Time expression to use as a predicate when retrieving distinct values to populate the filter component. Only applies when `Enable Filter Select` is on. If you enter `7 days ago`, the distinct list of values in the filter will be populated based on the distinct value over the past week": [ - "Выражение времени для использования в качестве предиката при получении различных значений для заполнения компонента фильтра. Применяется только в том случае, если включен параметр «включить выбор фильтра». Если Вы введете «7 дней назад», то список различных значений в фильтре будет заполнен на основе определенного значения за последнюю неделю" + "Allow file uploads to database": [ + "Разрешить загрузку файлов в базу данных" ], - "Whether to populate the filter's dropdown in the explore view's filter section with a list of distinct values fetched from the backend on the fly": [ - "Получение списка фильтруемых значений, выполняя онлайн-запрос к серверу" + "Allow manipulation of the database using non-SELECT statements such as UPDATE, DELETE, CREATE, etc.": [ + "Разрешить управление базой данных, используя запросы UPDATE, DELETE, CREATE и т.п." ], - "Redirects to this endpoint when clicking on the datasource from the datasource list": [ - "Перенаправление на эту конечную точку при нажатии на источник данных из списка источников данных" + "Allow multiple selections": ["Разрешить множественный выбор"], + "Allow node selections": ["Разрешить выбор вершин"], + "Allow sending multiple polygons as a filter event": [""], + "Allow this database to be explored": [ + "Разрешить изучение этой базы данных" ], - "Duration (in seconds) of the caching timeout for this datasource. A timeout of 0 indicates that the cache never expires. Note this defaults to the cluster timeout if undefined.": [ - "Тайм-аут (в секундах) кеша для этого источника данных. Тайм-аут 0 означает, что кеш не может быть просрочен." + "Allow this database to be queried in SQL Lab": [ + "Разрешить запросы к этой базе данных в Лаборатории SQL" ], - "Associated Charts": ["Связанные графики"], - "Data Source": ["Источник данных"], - "Cluster": ["Кластер"], - "Owners": ["Владельцы"], - "Is Hidden": ["Скрыто"], - "Enable Filter Select": ["Включить выбор фильтра"], - "Default Endpoint": ["Адрес по-умолчанию"], - "Time Offset": ["Смещение времени"], - "Datasource Name": ["Имя источника данных"], - "Fetch Values From": ["Извлечь значения из"], - "Changed By": ["Изменено"], - "Modified": ["Изменено"], - "Refreshed metadata from cluster [{}]": [ - "Обновлённые метаданные из кластера [{}]" + "Allow users to run non-SELECT statements (UPDATE, DELETE, CREATE, ...) in SQL Lab": [ + "Разрешить управление базой данных, используя запросы UPDATE, DELETE, CREATE и т.п. в Лаборатории SQL" ], - "Only `SELECT` statements are allowed": [ - "Допустимы только выражения `SELECT`" + "Allowed Domains (comma separated)": [ + "Разрешенные домены (разделить запятыми)" ], - "Only single queries supported": [ - "Поддерживаются только одиночные запросы" + "Alphabetical": ["В алфавитном порядке"], + "Also known as a box and whisker plot, this visualization compares the distributions of a related metric across multiple groups. The box in the middle emphasizes the mean, median, and inner 2 quartiles. The whiskers around each box visualize the min, max, range, and outer 2 quartiles.": [ + "" ], - "Error in jinja expression in fetch values predicate: %(msg)s": [""], - "Error in jinja expression in FROM clause: %(msg)s": [""], - "Virtual dataset query cannot consist of multiple statements": [ - "Виртуальный датасет не может содержать несколько выражений" + "Altered": ["Измененено"], + "An Error Occurred": ["Произошла ошибка"], + "An alert named \"%(name)s\" already exists": [ + "Оповещение с именем \"%(name)s\" уже существует" ], - "Virtual dataset query must be read-only": [ - "Виртуальный датасет должен быть read-only" + "An enclosed time range (both start and end) must be specified when using a Time Comparison.": [ + "При использовании сравнения времени необходимо указать закрытый временной интервал (как начало, так и конец)." ], - "Error in jinja expression in RLS filters: %(msg)s": [""], - "Datetime column not provided as part table configuration and is required by this type of chart": [ - "Для данного графика необходим временной ряд. Укажите столбец с датой в соответствующем поле раздела [Время]" + "An engine must be specified when passing individual parameters to a database.": [ + "Движок должен быть указан при передаче индивидуальных параметров к базе." ], - "Empty query?": ["Пустой запрос?"], - "Metric '%(metric)s' does not exist": [ - "Показатель ‘%(metric)s’ не существует" + "An error has occurred": ["Произошла ошибка"], + "An error occurred": ["Произошла ошибка"], + "An error occurred saving dataset": [ + "Произошла ошибка при сохранении датасета" ], - "Invalid filter operation type: %(op)s": [ - "Недействительный тип операции фильтра: %(op)s" + "An error occurred while accessing the value.": [ + "Произошла ошибка при доступе к значению" ], - "Error in jinja expression in WHERE clause: %(msg)s": [""], - "Error in jinja expression in HAVING clause: %(msg)s": [""], - "Show Column": ["Показать столбец"], - "Add Column": ["Добавить столбец"], - "Edit Column": ["Редактировать столбец"], - "Whether to make this column available as a [Time Granularity] option, column has to be DATETIME or DATETIME-like": [ - "Сделать этот столбец доступным в разделе [Время]. Столбец должен быть в формате DATETIME" + "An error occurred while collapsing the table schema. Please contact your administrator.": [ + "Произошла ошибка при сворачивании схемы. Пожалуйста, свяжитесь с администратором." ], - "The data type that was inferred by the database. It may be necessary to input a type manually for expression-defined columns in some cases. In most case users should not need to alter this.": [ - "Задать тип данных. В некоторых случаях может потребоваться ввести тип вручную для столбцов, которые формируются специальными запросами. В большинстве случаев изменять содержимое этого поля не обязательно." + "An error occurred while creating %ss: %s": [ + "Произошла ошибка при создании %sов: %s" ], - "Table": ["Таблица"], - "Expression": ["Выражение SQL"], - "Is temporal": ["Содержит дату /время"], - "Datetime Format": ["Формат Datetime"], - "Invalid date/timestamp format": ["Формат Даты / Времени"], - "Show Metric": ["Показать показатель"], - "Add Metric": ["Добавить показатель"], - "Edit Metric": ["Редактировать показатель"], - "SQL Expression": ["Выражение SQL"], - "D3 Format": ["Формат D3"], - "Extra": ["Дополнительные параметры"], - "Row level security filter": ["Фильтр на уровне строк"], - "Show Row level security filter": ["Показать фильтр на уровне строк"], - "Add Row level security filter": ["Добавить фильтр на уровне строк"], - "Edit Row level security filter": ["Править фильтр на уровне строк"], - "Regular filters add where clauses to queries if a user belongs to a role referenced in the filter. Base filters apply filters to all queries except the roles defined in the filter, and can be used to define what users can see if no RLS filters within a filter group apply to them.": [ - "" + "An error occurred while creating the data source": [ + "Произошла ошибка при создании источника данных" ], - "These are the tables this filter will be applied to.": [ - "Это таблицы, к которым будет применён фильтр." + "An error occurred while creating the value.": [ + "Произошла ошибка при создании значения" ], - "For regular filters, these are the roles this filter will be applied to. For base filters, these are the roles that the filter DOES NOT apply to, e.g. Admin if admin should see all data.": [ - "" + "An error occurred while deleting the value.": [ + "Произошла ошибка при удалении значения" ], - "Filters with the same group key will be ORed together within the group, while different filter groups will be ANDed together. Undefined group keys are treated as unique groups, i.e. are not grouped together. For example, if a table has three filters, of which two are for departments Finance and Marketing (group key = 'department'), and one refers to the region Europe (group key = 'region'), the filter clause would apply the filter (department = 'Finance' OR department = 'Marketing') AND (region = 'Europe').": [ - "" + "An error occurred while expanding the table schema. Please contact your administrator.": [ + "Произошла ошибка при разворачивании схемы. Пожалуйста, свяжитесь с администратором." ], - "This is the condition that will be added to the WHERE clause. For example, to only return rows for a particular client, you might define a regular filter with the clause `client_id = 9`. To display no rows unless a user belongs to a RLS filter role, a base filter can be created with the clause `1 = 0` (always false).": [ - "" + "An error occurred while fetching %s info: %s": [ + "Произошла ошибка при получении информации о %s: %s" ], - "Tables": ["Таблицы"], - "Roles": ["Роли"], - "Clause": ["Условие"], - "Creator": ["Автор"], - "Show Table": ["Показать таблицу"], - "Import a table definition": ["Импортировать определение таблицы"], - "Edit Table": ["Редактировать таблицу"], - "Name of the table that exists in the source database": [ - "Имя таблицы, которая существует в исходной базе данных" + "An error occurred while fetching %ss: %s": [ + "Произошла ошибка при получении: %s: %s" ], - "Schema, as used only in some databases like Postgres, Redshift and DB2": [ - "Схема, используется только в некоторых базах данных, таких как Postgres, Redshift и DB2" + "An error occurred while fetching available CSS templates": [ + "Произошла ошибка при получении доступных CSS-шаблонов" ], - "This fields acts a Superset view, meaning that Superset will run a query against this string as a subquery.": [ - "Это поле будет выполнять запрос в качестве подзапроса." + "An error occurred while fetching chart created by values: %s": [ + "Произошла ошибка при получении создателя графика: %s" ], - "Predicate applied when fetching distinct value to populate the filter control component. Supports jinja template syntax. Applies only when `Enable Filter Select` is on.": [ - "Предикат применяется при получении значений для компонента - «Фильтр». Поддерживает синтаксис jinja. Применяется только в том случае, если включен параметр «Включить Онлайн Фильтр»." + "An error occurred while fetching chart owners values: %s": [ + "Произошла ошибка при получении владельцев графика: %s" ], - "Redirects to this endpoint when clicking on the table from the table list": [ - "Перенаправление на эту конечную точку при нажатии на таблицу в общем списке" + "An error occurred while fetching created by values: %s": [ + "Произошла ошибка при построении графика: %s" ], - "Whether the table was generated by the 'Visualize' flow in SQL Lab": [ - "" + "An error occurred while fetching dashboard created by values: %s": [ + "Произошла ошибка при получении создателя дашборда: %s" ], - "A set of parameters that become available in the query using Jinja templating syntax": [ - "" + "An error occurred while fetching dashboard owner values: %s": [ + "Произошла ошибка при получении владельца дашборда: %s" ], - "Duration (in seconds) of the caching timeout for this table. A timeout of 0 indicates that the cache never expires. Note this defaults to the database timeout if undefined.": [ - "" + "An error occurred while fetching dashboards": [ + "Произошла ошибка при получении дашбордов" ], - "Database": ["База данных"], - "Last Changed": ["Последнее изменение"], - "Schema": ["Схема"], - "Offset": ["Смещение"], - "Table Name": ["Имя Таблицы"], - "Fetch Values Predicate": ["Извлечь Значения Предиката"], - "Main Datetime Column": ["Основной столбец с датой"], - "SQL Lab View": ["Лаборатория SQL"], - "Template parameters": ["Параметры шаблона"], - "The table was created. As part of this two-phase configuration process, you should now click the edit button by the new table to configure it.": [ - "Таблица была создана. Теперь нажмите на кнопку редактирования напротив новой таблицы, чтобы настроить её." - ], - "Refresh Metadata": ["Обновить метаданные"], - "Refresh column metadata": ["Обновить метаданные столбцов"], - "Metadata refreshed for the following table(s): %(tables)s": [ - "Метаданные обновлены для следующих таблиц: %(tables)s" - ], - "The following tables added new columns: %(tables)s": [""], - "The following tables removed columns: %(tables)s": [""], - "The following tables update column metadata: %(tables)s": [""], - "Unable to refresh metadata for the following table(s): %(tables)s": [ - "Метаданные обновлены для следующих таблиц: %(tables)s" - ], - "Deleted %(num)d css template": ["Удалено %(num)d шаблонов CSS"], - "CSS template could not be deleted.": [ - "Шаблон CSS не может быть удалён." - ], - "CSS template not found.": ["Шаблон CSS не найден."], - "Deleted %(num)d dashboard": ["Удалено %(num)d дашбордов"], - "Title or Slug": ["Заголовок"], - "Must be unique": ["Должно быть уникально"], - "Dashboard parameters are invalid.": [ - "Параметры дашборда недействительны." - ], - "Dashboard not found.": ["Дашборд не найден."], - "Dashboard could not be created.": ["Дашборд не может быть создан."], - "Dashboards could not be deleted.": ["Дашборды не могут быть удалены."], - "Dashboard could not be updated.": ["Дашборд не может быть обновлён."], - "Dashboard could not be deleted.": ["Дашборд не может быть удалён."], - "Changing this Dashboard is forbidden": [ - "Изменение этого дашборда запрещено" + "An error occurred while fetching dashboards: %s": [ + "Произошла ошибка при получении дашбордов: %s" ], - "Import dashboard failed for an unknown reason": [ - "Импорт дашборда не удался по неизвестной причине" + "An error occurred while fetching database related data: %s": [ + "Произошла ошибка при получении данных о базе данных: %s" ], - "No data in file": ["Нет данных в файле"], - "Table name undefined": ["Имя таблицы не определено"], - "Invalid connection string, a valid string usually follows: driver://user:password@database-host/database-name": [ - "Недействительная строка подключения, правильная строка обычно следует следующему шаблону: драйвер://пользователь:пароль@хостБД/имяБД" + "An error occurred while fetching database values: %s": [ + "Произошла ошибка при получении значений базы данных: %s" ], - "SQLite database cannot be used as a data source for security reasons.": [ - "БД SQLite не может быть использована как источник данных из-за потенциальных проблем с безопасностью." + "An error occurred while fetching dataset datasource values: %s": [ + "Произошла ошибка при получении значений датасета: %s" ], - "Field cannot be decoded by JSON. %(msg)s": [""], - "The metadata_params in Extra field is not configured correctly. The key %(key)s is invalid.": [ - "" + "An error occurred while fetching dataset owner values: %s": [ + "Произошла ошибка при получении владельца датасета: %s" ], - "Database parameters are invalid.": [ - "Параметры базы данных недействительны." + "An error occurred while fetching dataset related data": [ + "Произошла ошибка при получении метаданных датасета" ], - "A database with the same name already exists": [ - "Источник данных %(name)s уже существует" + "An error occurred while fetching dataset related data: %s": [ + "Произошла ошибка при получении данных о датасете: %s" ], - "Field is required": ["Поле обязательно"], - "Field cannot be decoded by JSON. %{json_error}s": [""], - "The metadata_params in Extra field is not configured correctly. The key %{key}s is invalid.": [ - "" + "An error occurred while fetching datasets: %s": [ + "Произошла ошибка при получении датасетов: %s" ], - "Database not found.": ["База данных не найдена."], - "Database could not be created.": ["База данных не может быть создана."], - "Database could not be updated.": [ - "База данных не может быть обновлена." + "An error occurred while fetching function names.": [ + "Произошла ошибка при получении имен функций" ], - "Connection failed, please check your connection settings": [ - "Подключение не удалось, пожалуйста, проверьте строку подключения" + "An error occurred while fetching owners values: %s": [ + "Произошла ошибка при получении владельцев графика: %s" ], - "Cannot delete a database that has tables attached": [ - "Невозможно удалить базу данных, для которой созданы таблицы" + "An error occurred while fetching schema values: %s": [ + "Произошла ошибка при извлечении значений схемы: %s" ], - "Database could not be deleted.": ["База данных не может быть удалена."], - "Stopped an unsafe database connection": [ - "Выберите любые столбцы для проверки метаданных" + "An error occurred while fetching tab state": [ + "Произошла ошибка при получении данных вкладки" ], - "Could not load database driver": [ - "Невозможно загрузить драйвер базы данных" + "An error occurred while fetching table metadata": [ + "Произошла ошибка при получении метаданных из таблицы" ], - "Unexpected error occurred, please check your logs for details": [ - "Произошла непредвиденная ошибка, пожалуйста, проверьте логи для подробностей" + "An error occurred while fetching table metadata. Please contact your administrator.": [ + "Произошла ошибка при получении метаданных таблицы. Пожалуйста, свяжитесь с администратором." ], - "Import database failed for an unknown reason": [ - "Импорт базы данных не удался по неизвестной причине" + "An error occurred while fetching user values: %s": [ + "Произошла ошибка при извлечении пользовательских значений: %s" ], - "Could not load database driver: {}": [ - "Невозможно загрузить драйвер базы данных: {}" + "An error occurred while hiding the left bar. Please contact your administrator.": [ + "Произошла ошибка при сворачивании левой панели. Пожалуйста, свяжитесь с администратором." ], - "Deleted %(num)d dataset": ["Удалено датасетов: %(num)d"], - "Null or Empty": ["Null или пусто"], - "Database not allowed to change": ["Базу данных не разрешено изменять"], - "One or more columns do not exist": [ - "Один или несколько столбцов не существуют" + "An error occurred while importing %s: %s": [ + "Произошла ошибка при попытке импортировать %s: %s" ], - "One or more columns are duplicated": [ - "Один или несколько столбцов-дубликатов" + "An error occurred while loading the SQL": [ + "Произошла ошибка при загрузке SQL" ], - "One or more columns already exist": [ - "Один или несколько столбцов уже существуют" + "An error occurred while opening Explore": [ + "Произошла ошибка при открытии режима исследования" ], - "One or more metrics do not exist": [ - "Выберите один или несколько показателей для отображения" + "An error occurred while parsing the key.": [ + "Произошла ошибка при парсинге ключа." ], - "One or more metrics are duplicated": [ - "Выберите один или несколько показателей для отображения" + "An error occurred while pruning logs ": [ + "Произошла ошибка при удалении журналов " ], - "One or more metrics already exist": [ - "Выберите один или несколько показателей для отображения" + "An error occurred while removing query. Please contact your administrator.": [ + "Произошла ошибка при удалении запроса. Пожалуйста, свяжитесь с администратором." ], - "Table [%(table_name)s] could not be found, please double check your database connection, schema, and table name": [ - "Не удалось найти таблицу [%(table_name)s]. Пожалуйста, проверьте подключение к базе данных, схему и имя таблицы" + "An error occurred while removing tab. Please contact your administrator.": [ + "Произошла ошибка при удалении вкладки. Пожалуйста, свяжитесь с администратором." ], - "Dataset parameters are invalid.": [ - "Параметры датасета недействительны." + "An error occurred while removing the table schema. Please contact your administrator.": [ + "Произошла ошибка при удалении схемы. Пожалуйста, свяжитесь с администратором." ], - "Dataset could not be created.": ["Датасет не может быть создан."], - "Dataset could not be updated.": ["Датасет не может быть обновлён."], - "Dataset could not be deleted.": ["Датасет не может быть удалён."], - "Dataset(s) could not be bulk deleted.": [ - "Датасет(ы) не может быть удален." + "An error occurred while rendering the visualization: %s": [ + "Произошла ошибка при построении графика: %s" ], - "Changing this dataset is forbidden": [ - "Изменение этого датасета запрещено" + "An error occurred while setting the active tab. Please contact your administrator.": [ + "Произошла ошибка при установке активной вкладки. Пожалуйста, свяжитесь с администратором." ], - "Import dataset failed for an unknown reason": [ - "Импорт датасета не удался по неизвестной причине" + "An error occurred while setting the tab autorun. Please contact your administrator.": [ + "Произошла ошибка при настройке автозапуска вкладки. Пожалуйста, свяжитесь с администратором." ], - "Unknown Presto Error": ["Неизвестная ошибка"], - "We can't seem to resolve the column \"%(column_name)s\" at line %(location)s.": [ - "" + "An error occurred while setting the tab database ID. Please contact your administrator.": [ + "Произошла ошибка при установке ID базы данных для вкладки. Пожалуйста, свяжитесь с администратором." ], - "The table \"%(table_name)s\" does not exist. A valid table must be used to run this query.": [ - "" + "An error occurred while setting the tab name. Please contact your administrator.": [ + "Произошла ошибка при настройке заголовка вкладки. Пожалуйста, свяжитесь с администратором." ], - "Deleted %(num)d saved query": ["Удалено %(num)d сохранённых запросов"], - "Saved queries could not be deleted.": [ - "Сохранённые запросы не могут быть удалены." + "An error occurred while setting the tab schema. Please contact your administrator.": [ + "Произошла ошибка при настройке схемы. Пожалуйста, свяжитесь с администратором." ], - "Saved query not found.": ["Сохранённый запрос не найден."], - "Deleted %(num)d report schedule": ["Удалено %(num)d рассылок"], - "Alert query returned more than one row. %s rows returned": [ - "Запрос от оповещения вернул больше одной строки. %s строк возвращено" + "An error occurred while setting the tab template parameters. Please contact your administrator.": [ + "Произошла ошибка при установке параметров шаблона вкладки. Пожалуйста, свяжитесь с администратором." ], - "Alert query returned more than one column. %s columns returned": [ - "Запрос от оповещения вернул больше одного столбца. %s столбцов возвращено" + "An error occurred while starring this chart": [ + "Произошла ошибка при добавлении графика в избранное" ], - "Dashboard does not exist": ["Дашборд не существует"], - "Chart does not exist": ["График не существует"], - "Database is required for alerts": [ - "База данных требуется для уведомлений" + "An error occurred while storing the latest query id in the backend. Please contact your administrator if this problem persists.": [ + "Возникла ошибка при попытке сохранения ID последнего запроса на сервере. Пожалуйста, обратитесь к вашему администратору, если проблема останется." ], - "Type is required": ["Тип обязателен"], - "Choose a chart or dashboard not both": ["Удалить график из дашборда"], - "Report Schedule parameters are invalid.": [ - "Параметры графика рассылки недействительны." + "An error occurred while storing your query in the backend. To avoid losing your changes, please save your query using the \"Save Query\" button.": [ + "Произошла ошибка при сохранении запроса на сервере. Чтобы сохранить изменения, пожалуйста, сохраните ваш запрос через кнопку \"Сохранить как\"." ], - "Report Schedule could not be deleted.": [ - "Рассылка не может быть удалена." + "An error occurred while updating the value.": [ + "Произошла ошибка при обновлении значения" ], - "Report Schedule could not be created.": [ - "Рассылка не может быть создана." + "An error occurred while upserting the value.": [ + "Произошла ошибка при вставке значения." ], - "Report Schedule could not be updated.": [ - "Рассылка не может быть обновлена." + "An unexpected error occurred": ["Произошла неожиданная ошибка"], + "An unknown error occurred. Please contact your Superset administrator": [ + "Произошла неизвестная ошибка. Пожалуйста, свяжитесь с администратором." ], - "Report Schedule not found.": ["График рассылки не найден."], - "Report Schedule delete failed.": [ - "Удаление графика рассылки не удалось." + "Anchor to": ["Привязать к"], + "Angle at which to end progress axis": [ + "Угол, под которым заканчивается ось прогресса" ], - "Report Schedule log prune failed.": [ - "Удаление журнала рассылки не удалось." + "Angle at which to start progress axis": [ + "Угол, с которого начинается ось прогресса" ], - "Report Schedule execution failed when generating a screenshot.": [ - "Ошибка при генерировании скриншота во время выполнения рассылки." + "Animation": ["Анимация"], + "Annotation": ["Аннотация"], + "Annotation Layer %s": ["Слой аннотаций %s"], + "Annotation Layers": ["Слои аннотаций"], + "Annotation Slice Configuration": ["Настройки аннотации из графика"], + "Annotation could not be created.": ["Не удалось создать аннотацию"], + "Annotation could not be updated.": ["Не удалось обновить аннотацию"], + "Annotation delete failed.": ["Не удалось удалить аннотацию"], + "Annotation layer": ["Слой аннотаций"], + "Annotation layer could not be created.": [ + "Не удалось создать слой аннотации." ], - "Report Schedule execution got an unexpected error.": [ - "Во время выполнения рассылки произошла непредвиденная ошибка." + "Annotation layer could not be deleted.": [ + "Не удалось удалить слой аннотации." ], - "Report Schedule is still working, refusing to re-compute.": [""], - "Report Schedule reached a working timeout.": [ - "Рассылка достигла тайм-аута в работе." + "Annotation layer could not be updated.": [ + "Не удалось обновить слой аннотации." ], - "Alert query returned more than one row.": [ - "Запрос для оповещения вернул больше одной строки." + "Annotation layer delete failed.": ["Не удалось удалить слой аннотаций"], + "Annotation layer description columns": [ + "Описательные столбцы слоя аннотаций." ], - "Alert validator config error.": [ - "Неверная конфигурация широты и долготы." + "Annotation layer has associated annotations.": [ + "Слои аннотаций имеет связанные аннотации" ], - "Alert query returned more than one column.": [ - "Запрос для оповещения вернул больше одного столбца." + "Annotation layer interval end": ["Конечный интервал слоя аннотации"], + "Annotation layer name": ["Имя слоя аннотаций"], + "Annotation layer not found.": ["Слой аннотации не найден"], + "Annotation layer opacity": ["Непрозрачность слоя аннотации"], + "Annotation layer parameters are invalid.": [ + "Параметры слоя аннотаций недействительны" ], - "Alert query returned a non-number value.": [ - "Запрос для оповещения вернул не число." + "Annotation layer stroke": ["Штрих слоя аннотации"], + "Annotation layer type": ["Тип слоя аннотации"], + "Annotation layer value": ["Значение слоя аннотации"], + "Annotation layers": ["Слои аннотаций"], + "Annotation layers are still loading.": ["Слои аннотаций загружаются."], + "Annotation name": ["Имя аннотации"], + "Annotation not found.": ["Аннотация не найдена."], + "Annotation parameters are invalid.": [ + "Параметры аннотации недействительны." ], - "Alert found an error while executing a query.": [ - "Обнаружена ошибка в запросе." + "Annotation source": ["Источник аннотации"], + "Annotation source type": ["Тип источника аннотации"], + "Annotation template created": ["Шаблон аннотации создан"], + "Annotation template updated": ["Шаблон аннотации обновлен"], + "Annotations and Layers": ["Аннотации и слои"], + "Annotations and layers": ["Аннотации и слои"], + "Annotations could not be deleted.": ["Не удалось удалить аннотации."], + "Any": ["Любой"], + "Any additional detail to show in the certification tooltip.": [ + "Любые дополнительные сведения для всплывающей подсказки" ], - "Alert fired during grace period.": [""], - "Alert ended grace period.": [""], - "Alert on grace period": [""], - "Report Schedule sellenium user not found": [ - "Пользователь Selenium для графика рассылки не найден" + "Any color palette selected here will override the colors applied to this dashboard's individual charts": [ + "Любая палитра, выбранная здесь, будет перезаписывать цвета, применённые к отдельным графикам этого дашборда" ], - "Report Schedule state not found": [ - "Не найдено состояние графика рассылки" + "Any databases that allow connections via SQL Alchemy URIs can be added. ": [ + "Любые базы данных, подключаемые через SQL Alchemy URI, могут быть добавлены. " ], - "Report schedule unexpected error": [ - "Неожиданная ошибка графика рассылки" + "Any databases that allow connections via SQL Alchemy URIs can be added. Learn about how to connect a database driver ": [ + "Любые базы данных, подключаемые через SQL Alchemy URI, могут быть добавлены. Узнайте больше о том, как подключить драйвер базы данных " ], - "Changing this report is forbidden": ["Изменение этого отчёта запрещено"], - "An error occurred while pruning logs ": [ - "Произошла ошибка при удалении журналов " + "Append": ["Добавить"], + "Applied Cross Filters (%d)": ["Применено кросс-фильтров: (%d)"], + "Applied Filters (%d)": ["Применено фильтров: (%d)"], + "Applied filters: %s": ["Применены фильтры: %s"], + "Applied rolling window did not return any data. Please make sure the source query satisfies the minimum periods defined in the rolling window.": [ + "Применное скользязее окно не вернуло данных. Убедитесь, что исходный запрос удовлетворяет минимальному количеству периодов скользящего окна." ], - "\n <b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>\n <img src=\"cid:%(msgid)s\">\n ": [ - "\n <b><a href=“%(url)s”>Исследовать в Superset</a></b><p></p>\n <img src=“cid:%(msgid)s”>\n " + "Apply": ["Применить"], + "Apply conditional color formatting to metrics": [ + "Применить условное цветовое форматирование к мерам" ], - "%(prefix)s %(title)s": ["%(prefix)s %(title)s"], - "\n *%(name)s*\n\n <%(url)s|Explore in Superset>\n ": [ - "\n *%(name)s*\n\n <%(url)s|Исследовать в Superset>\n " + "Apply conditional color formatting to numeric columns": [ + "Применить условное цветовое форматирование к столбцам" ], - "\n *%(name)s*\n\n <%(url)s|Explore in Superset>\n ": [ - "\n *%(name)s*\n\n <%(url)s|Исследовать в Superset>\n " + "Apply filters": ["Применить фильтры"], + "Apply metrics on": ["Применить меры к"], + "Apply to all panels": ["Применить ко всем панелям"], + "Apply to specific panels": ["Применить к выбранным панелям"], + "April": ["Апрель"], + "Arc": ["Дуга"], + "Are you sure you intend to overwrite the following values?": [ + "Вы уверены, что хотите перезаписать эти значения?" ], - "<b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>": [ - "<b><a href=“%(url)s”>Исследовать в Superset</a></b><p></p>" + "Are you sure you want to cancel?": ["Вы уверены, что хотите отменить?"], + "Are you sure you want to delete": ["Вы уверены, что хотите удалить"], + "Are you sure you want to delete %s?": [ + "Вы уверены, что хотите удалить %s?" ], - "%(name)s.csv": ["%(name)s.csv"], - "\n *%(slice_name)s*\n\n <%(slice_url_user_friendly)s|Explore in Superset>\n ": [ - "\n *%(slice_name)s*\n\n <%(slice_url_user_friendly)s|Исследовать в Superset>\n " + "Are you sure you want to delete the selected %s?": [ + "Вы уверены, что хотите удалить выбранные %s?" ], - "[Alert] %(label)s": ["[Оповещение] %(label)s"], - "New": ["Новый"], - "SQL Query": ["Сохранить запрос"], - "Chart": ["График"], - "Dashboard": ["Дашборд"], - "Profile": ["Профиль"], - "Info": ["Инфо"], - "Logout": ["Выход из системы"], - "Login": ["Вход в систему"], - "Record Count": ["Количество записей"], - "No records found": ["Записи не найдены"], - "Filter List": ["Фильтры"], - "Search": ["Поиск"], - "Refresh": ["Принудительное обновление"], - "Import dashboards": ["Импорт дашбордов"], - "Import Dashboard(s)": ["Импорт дашборда(ов)"], - "File": ["Файл"], - "Choose File": ["Выберите файл"], - "Upload": ["Загрузить"], - "No Access!": ["Нет доступа!"], - "You do not have permissions to access the datasource(s): %(name)s.": [ - "У вас нет разрешений на доступ к источнику(ам) данных: %(name)s." + "Are you sure you want to delete the selected annotations?": [ + "Вы уверены, что хотите удалить выбранные аннотации?" ], - "Request Permissions": ["Запросить права доступа"], - "Cancel": ["Отменить"], - "Use the edit buttom to change this field": [ - "Используйте кнопку правки для изменения этого поля" + "Are you sure you want to delete the selected charts?": [ + "Вы уверены, что хотите удалить выбранные графики?" ], - "Test Connection": ["Тестовое соединение"], - "[Superset] Access to the datasource %(name)s was granted": [ - "Доступ к базе данных предоставлен для пользователя — %(name)s" + "Are you sure you want to delete the selected dashboards?": [ + "Вы уверены, что хотите удалить выбранные дашборды?" ], - "Unable to find such a holiday: [{}]": [ - "Невозможно найти такой выходной день: [{}]" + "Are you sure you want to delete the selected datasets?": [ + "Вы уверены, что хотите удалить выбранные датасеты?" ], - "Referenced columns not available in DataFrame.": [ - "Ссылочные столбца недоступны в DataFrame." + "Are you sure you want to delete the selected layers?": [ + "Вы уверены, что хотите удалить выбранные слои?" ], - "Column referenced by aggregate is undefined: %(column)s": [ - "Столбец, на который ссылается агрегат, не определён: %(column)s" + "Are you sure you want to delete the selected queries?": [ + "Вы уверены, что хотите удалить выбранные запросы?" ], - "Operator undefined for aggregator: %(name)s": [""], - "Invalid numpy function: %(operator)s": [ - "Недействительная функция numpy: %(operator)s" + "Are you sure you want to delete the selected templates?": [ + "Вы уверены, что хотите удалить выбранные шаблоны?" ], - "Pivot operation requires at least one index": [""], - "Pivot operation must include at least one aggregate": [""], - "Undefined window for rolling operation": [""], - "Invalid rolling_type: %(type)s": [""], - "Invalid options for %(rolling_type)s: %(options)s": [""], - "Invalid cumulative operator: %(operator)s": [""], - "Invalid geohash string": ["Недействительная строка geohash"], - "Invalid longitude/latitude": ["Долгота и Широта [Конец]"], - "Invalid geodetic string": ["Недействительная строка geodetic"], - "`fbprophet` package not installed": ["`fbprophet` пакет не установлен"], - "Time grain missing": ["Период времени"], - "Unsupported time grain: %(time_grain)s": [ - "Недействительная гранулярность времени: %(time_grain)s" + "Are you sure you want to overwrite this dataset?": [ + "Вы уверены, что хотите перезаписать этот датасет?" ], - "Periods must be a positive integer value": [ - "Периоды должны быть положительными делами числами" + "Are you sure you want to proceed?": [ + "Вы уверены, что хотите продолжить?" ], - "Confidence interval must be between 0 and 1 (exclusive)": [ - "Доверительный интервал должен быть между 0 и 1 (исключая)" + "Are you sure you want to save and apply changes?": [ + "Вы уверены, что хотите сохранить и применить изменения?" ], - "DataFrame must include temporal column": [ - "DataFrame должен включать временной столбец" + "Area Chart": ["Диаграмма с областями"], + "Area Chart (legacy)": ["Диаграмма с областями (устарело)"], + "Area chart": ["Диаграмма с областями"], + "Area chart opacity": ["Непрозрачность диаграммы с областями"], + "Area charts are similar to line charts in that they represent variables with the same scale, but area charts stack the metrics on top of each other.": [ + "Диаграммы с областями похожи на линейные диаграммы в том смысле, что они отображают показатели с одинаковым масштабом, но диаграммы областей накладывают эти показатели друг на друга." ], - "DataFrame include at least one series": [ - "Пожалуйста, выберите хотя бы один показатель" + "Arrow": ["Стрела"], + "Assign a set of parameters as": ["Задайте набор параметров в формате"], + "Associated Charts": ["Связанные графики"], + "Async Execution": ["Асинхронное выполнение"], + "Asynchronous query execution": ["Асинхронное выполнение запросов"], + "August": ["Август"], + "Auto": ["Автоматически"], + "Auto Zoom": ["Авто масштабирование"], + "Autocomplete": ["Автозаполнение"], + "Autocomplete filters": ["Фильтры автозаполнения"], + "Autocomplete query predicate": ["Предикат запроса автозаполнения"], + "Automatic Color": ["Автоматический цвет"], + "Available sorting modes:": ["Доступные режимы сортировки:"], + "Average": ["Среднее"], + "Axis": ["Ось"], + "Axis Bounds": ["Границы оси"], + "Axis Format": ["Формат Оси"], + "Axis Title": ["Название оси"], + "Axis ascending": ["Ось по возрастанию"], + "Axis descending": ["Ось по убыванию"], + "BOOLEAN": ["Булевый (BOOLEAN)"], + "Back": ["Назад"], + "Back to all": ["Вернуться ко всем"], + "Backend": ["Драйвер"], + "Backward values": ["Предыдущие значения"], + "Bad formula.": ["Неверная формула."], + "Bad spatial key": ["Неподходящий пространственный ключ"], + "Bar": ["Столбчатая"], + "Bar Chart": ["Столбчатая диаграмма"], + "Bar Chart (legacy)": ["Столбчатая диаграмма (устарело)"], + "Bar Charts are used to show metrics as a series of bars.": [ + "Столбчатые диаграммы используются для отображения показателей в виде серии столбцов." + ], + "Bar Values": ["Значения столбцов"], + "Bar orientation": ["Направление столбцов"], + "Base layer map style": [""], + "Based on a metric": ["На основе меры"], + "Based on granularity, number of time periods to compare against": [ + "Основываясь на группировке времени, количество периодов времени для сравнения" + ], + "Basic": ["Базовая настройка"], + "Basic information": ["Основная информация"], + "Batch editing %d filters:": [ + "Множественное редактирование фильтров: %d" ], - "percentiles must be a list or tuple with two numeric values, of which the first is lower than the second value": [ - "процентили должны быть списками из кортежами из двух числовых значений, в которых первое значение меньше второго" + "Battery level over time": ["Уровень заряда батареи с течением времени"], + "Be careful.": ["Будьте осторожны."], + "Before": ["До"], + "Big Number": ["Карточка"], + "Big Number Font Size": ["Размер шрифта числа"], + "Big Number with Trendline": ["Карточка с трендовой линией"], + "Bottom": ["Снизу"], + "Bottom Margin": ["Нижний отступ"], + "Bottom left": ["Снизу слева"], + "Bottom margin, in pixels, allowing for more room for axis labels": [ + "Нижний отступ (в пикселях), дает больше пространства меткам оси" + ], + "Bottom right": ["Снизу справа"], + "Bottom to Top": ["Снизу вверх"], + "Bounds for the Y-axis. When left empty, the bounds are dynamically defined based on the min/max of the data. Note that this feature will only expand the axis range. It won't narrow the data's extent.": [ + "Границы для оси Y. Если оставить поле пустым, границы динамически определяются на основе минимального/максимального значения данных. Обратите внимание, что эта функция только расширит диапазон осей. Она не изменит размер графика." + ], + "Bounds for the axis. When left empty, the bounds are dynamically defined based on the min/max of the data. Note that this feature will only expand the axis range. It won't narrow the data's extent.": [ + "Границы для оси. Если оставить поле пустым, границы динамически определяются на основе минимального/максимального значения данных. Обратите внимание, что эта функция только расширит диапазон осей. Она не изменит размер графика." + ], + "Box Plot": ["Ящик с усами"], + "Bubble Chart": ["Пузырьковая диаграмма"], + "Bubble Color": ["Цвет пузыря"], + "Bubble Size": ["Размер пузыря"], + "Bubble size": ["Размер маркера"], + "Bucket break points": [""], + "Build": ["Сборка"], + "Bulk select": ["Множественный выбор"], + "Bullet Chart": ["Диаграмма-шкала"], + "Business": ["Бизнес"], + "Business Data Type": ["Тип данных бизнеса"], + "By default, each filter loads at most 1000 choices at the initial page load. Check this box if you have more than 1000 filter values and want to enable dynamically searching that loads filter values as users type (may add stress to your database).": [ + "По умолчанию, каждый фильтр загружает не больше 1000 элементов выбора при начальной загрузке страницы. Установите этот флаг, если у вас больше 1000 значений фильтра и вы хотите включить динамический поиск, который загружает значения по мере их ввода пользователем (может увеличить нагрузку на вашу базу данных)." ], - "User": ["Пользователь"], - "User Roles": ["Роли пользователей"], - "Database URL": ["URL базы данных"], - "Roles to grant": ["Роли для предоставления"], - "Created On": ["Дата создания"], - "List Observations": ["Список показателей"], - "Show Observation": [""], - "Error Message": ["Предупреждающее сообщение"], - "Log Retentions (days)": ["Время жизни журналов (в днях)"], - "A semicolon ';' delimited list of email addresses": [ - "Список адресов, разделённый точкой с запятой ‘;’" + "By key: use column names as sorting key": [ + "По ключу: использовать имена столбцов как ключ сортировки" ], - "How long to keep the logs around for this alert": [ - "Как долго хранить логи для данного оповещения" + "By key: use row names as sorting key": [ + "По ключу: использовать имена строк как ключ сортировки" ], - "Once an alert is triggered, how long, in seconds, before Superset nags you again.": [ - "После срабатывания оповещения, как долго Superset не должен надоедать снова." + "By value: use metric values as sorting key": [ + "По значению: использовать значения мер как ключ сортировки" ], - "A SQL statement that defines whether the alert should get triggered or not. The query is expected to return either NULL or a number value.": [ - "SQL-выражение, которое определяет сработало оповещение или нет. Запрос должен вернуть NULL или числовое значение." + "CANCEL": ["ОТМЕНА"], + "CREATE DATASET": ["СОЗДАТЬ ДАТАСЕТ"], + "CREATE TABLE AS": ["CREATE TABLE AS"], + "CREATE VIEW AS": ["CREATE VIEW AS"], + "CREATE VIEW statement": ["Выражение CREATE VIEW"], + "CRON Schedule": ["CRON расписание"], + "CRON expression": ["CRON выражение"], + "CSS": ["CSS"], + "CSS Styles": ["CSS стили"], + "CSS Templates": ["CSS шаблоны"], + "CSS applied to the chart": ["CSS, примененный к графику"], + "CSS template": ["CSS шаблон"], + "CSS template could not be deleted.": ["Не удалось удалить CSS шаблон."], + "CSS template name": ["Имя CSS шаблона"], + "CSS template not found.": ["CSS шаблон не найден."], + "CSS templates": ["CSS шаблоны"], + "CSV Upload": ["Загрузка CSV"], + "CSV file \"%(csv_filename)s\" uploaded to table \"%(table_name)s\" in database \"%(db_name)s\"": [ + "CSV файл \"%(csv_filename)s\" загружен в таблицу \"%(table_name)s\" в базе данных \"%(db_name)s\"" ], - "annotation start time or end time is required.": [ - "время начала или окончания аннотации обязательно." + "CSV to Database configuration": [ + "Конфигурация CSV файла для импорта в базу данных" ], - "Annotation end time must be no earlier than start time.": [ - "Конец интервала для аннотации должен быть не раньше начала." + "CSV upload": ["Загрузка CSV"], + "CTAS & CVAS SCHEMA": ["СХЕМА CTAS & CVAS"], + "CTAS (create table as select) can only be run with a query where the last statement is a SELECT. Please make sure your query has a SELECT as its last statement. Then, try running your query again.": [ + "CTAS (CREATE TABLE AS SELECT) может быть выполнен в запросе с единственным SELECT запросом. Пожалуйста, убедитесь, что запрос содержит только один SELECT запрос. Затем выполните запрос заново." ], - "Annotations": ["Аннотации"], - "Show Annotation": ["Аннотации"], - "Add Annotation": ["Добавить слой аннотации"], - "Edit Annotation": ["Аннотации"], - "Layer": ["Слой"], - "Label": ["Метка"], - "Start": ["Время начала"], - "End": ["Конец"], - "JSON Metadata": ["Параметры JSON"], - "Show Annotation Layer": ["Слои аннотаций"], - "Add Annotation Layer": ["Добавить слой аннотации"], - "Edit Annotation Layer": ["Добавить слой аннотации"], - "Name": ["Название"], - "Dataset %(name)s already exists": [ - "Источник данных %(name)s уже существует" + "CTAS Schema": ["Схема CTAS"], + "CVAS (create view as select) can only be run with a query with a single SELECT statement. Please make sure your query has only a SELECT statement. Then, try running your query again.": [ + "CVAS (CREATE VIEW AS SELECT) может быть выполнен в запросе с единственным SELECT запросом. Пожалуйста, убедитесь, что запрос содержит только один SELECT запрос. Затем выполните запрос заново." ], - "Table [%{table}s] could not be found, please double check your database connection, schema, and table name, error: {}": [ - "Не удалось найти таблицу [{}]. Проверьте подключение к базе данных, схему и имя таблицы." + "CVAS (create view as select) query has more than one statement.": [ + "CVAS (CREATE VIEW AS SELECT) запрос содержит больше одного запроса." ], - "json isn't valid": ["json не валиден"], - "Export to YAML": ["Экспорт в YAML"], - "Export to YAML?": ["Экспорт в YAML?"], - "Delete": ["Удалить"], - "Delete all Really?": ["Удалить все?"], - "Is favorite": ["В Избранном"], - "The data source seems to have been deleted": [ - "Источник данных, похоже, был удален" + "CVAS (create view as select) query is not a SELECT statement.": [ + "CVAS (CREATE VIEW AS SELECT) запрос не является SELECT запросом." ], - "The user seems to have been deleted": [ - "Пользователь, кажется, был удален" + "Cache Timeout": ["Время жизни кэша"], + "Cache Timeout (seconds)": ["Время жизни кэша (секунды)"], + "Cache timeout": ["Время жизни кэша"], + "Cached": ["Добавлено в кэш"], + "Cached %s": ["Добавлено в кэш %s"], + "Cached value not found": ["Кэшированное значение не найдено"], + "Calculate contribution per series or row": [ + "Вычислить вклад в общую сумму (долю) по категории или строке. Установливает формат показателя в проценты" ], - "Access was requested": ["Запрошен доступ"], - "The access requests seem to have been deleted": [ - "Запросы доступа, похоже, были удалены" + "Calculated column [%s] requires an expression": [ + "Для вычисляемого столбца [%s] требуется выражение" ], - "%(user)s was granted the role %(role)s that gives access to the %(datasource)s": [ - "%(user)s была предоставлена роль %(role)s, которая дает доступ к ресурсам %(datasource)s" + "Calculated columns": ["Вычисляемые столбцы"], + "Calculation type": ["Тип расчёта"], + "Calendar Heatmap": ["Календарная тепловая карта"], + "Can not move top level tab into nested tabs": [ + "Невозможно перенести вкладку верхнего уровня во вложенную вкладку" ], - "Role %(r)s was extended to provide the access to the datasource %(ds)s": [ - "Роль %(r) s была расширена для обеспечения доступа к источнику данных %(ds)s" + "Can select multiple values": ["Можно выбрать несколько значений"], + "Can't have overlap between Series and Breakdowns": [""], + "Cancel": ["Отмена"], + "Cancel query on window unload event": [ + "Отменять запрос при закрытии вкладки" ], - "You have no permission to approve this request": [ - "У вас нет разрешения на утверждение этого запроса" + "Cannot delete a database that has datasets attached": [ + "Невозможно удалить базу данных с подключенными датасетами" ], "Cannot import dashboard: %(db_error)s.\nMake sure to create the database before importing the dashboard.": [ - "Невозможно импортировать дашборд: %(db_error)s.\nУбедитесь, что перед импортом дашборда была создана база данных." - ], - "An unknown error occurred. Please contact your Superset administrator": [ - "Произошла неизвестная ошибка. Пожалуйста, свяжитесь с администратором Superset" + "Невозможно импортировать дашборд: %(db_error)s.\nУбедитесь, что база даннах создана перед импортированием дашборда." + ], + "Cannot load filter": ["Невозможно загрузить фильтр"], + "Cannot parse time string [%(human_readable)s]": [ + "Не удается разобрать временную строку [%(human_readable)s]" + ], + "Categorical": ["Категориальный"], + "Categorical Color": ["Цвет категории"], + "Categories to group by on the x-axis.": [ + "Категории для группировки по оси x" + ], + "Category": ["Категория"], + "Category Name": ["Имя категории"], + "Category and Percentage": ["Категория и процентная доля"], + "Category and Value": ["Категория и значение"], + "Category of target nodes": ["Категория целевых вершин"], + "Category, Value and Percentage": [ + "Категория, значение и процентная доля" + ], + "Cell Padding": ["Расстояние между ячейками"], + "Cell Radius": ["Радиус ячейки"], + "Cell Size": ["Размер ячейки"], + "Cell bars": ["Гистограммы в ячейках"], + "Cell content": ["Содержимое ячейки"], + "Cell limit": ["Лимит ячеек"], + "Center": ["По центру"], + "Centroid (Longitude and Latitude): ": ["Центроид (Долгота и Широта): "], + "Certification": ["Утверждение"], + "Certification details": ["Детали утверждения"], + "Certified": ["Утверждено"], + "Certified By": ["Кем утверждено"], + "Certified by": ["Кем утверждено"], + "Certified by %s": ["Утверждено: %s"], + "Change order of columns.": ["Сменить порядок столбцов."], + "Change order of rows.": ["Сменить порядок строк."], + "Changed By": ["Кем изменено"], + "Changed on": ["Дата изменения"], + "Changes saved.": ["Изменения сохранены."], + "Changing the dataset may break the chart if the chart relies on columns or metadata that does not exist in the target dataset": [ + "Изменение датасета может привести к тому, что график станет нерабочим, если график использует несуществующие в целевом датасете столбцы или метаданные" ], - "Error occurred when opening the chart: %(error)s": [ - "Произошла ошибка при открытии графика: %(error)s" + "Changing these settings will affect all charts using this dataset, including charts owned by other people.": [ + "Изменение этих настроек будет влиять на все графики, использующие этот датасет, включая графики других пользователей." ], - "You don't have the rights to ": ["У вас нет прав на "], - "alter this ": ["изменить этот "], - "chart": ["график"], - "create a ": ["создать "], - "Explore - %(table)s": ["Исследовать - %(table)s"], - "Chart [{}] has been saved": ["График [{}] был сохранён"], - "Chart [{}] has been overwritten": ["График [{}] был перезаписан"], - "dashboard": ["дашборд"], - "Chart [{}] was added to dashboard [{}]": [ - "График [{}] был добавлен к дашборду [{}]" + "Changing this Dashboard is forbidden": [ + "Запрещено изменять этот дашборд" ], - "Dashboard [{}] just got created and chart [{}] was added to it": [ - "Дашборд [{}] был создан, и на него был добавлен график [{}]" + "Changing this chart is forbidden": ["Запрещено изменять этот график"], + "Changing this control takes effect instantly": [ + "Изменение этого элемента применяется сразу" ], - "This dashboard was changed recently. Please reload dashboard to get latest version.": [ - "Этот дашборд был недавно изменён. Пожалуйста, перезагрузите дашборд, чтобы получить последнюю версию." + "Changing this dataset is forbidden": ["Запрещено изменять этот датасет"], + "Changing this dataset is forbidden.": [ + "Запрещено изменять этот датасет" ], - "Could not load database driver: %(driver_name)s": [ - "Невозможно загрузить драйвер базы данных: %(driver_name)s" + "Changing this datasource is forbidden": [ + "Запрещено изменять этот источник данных" ], - "Invalid connection string, a valid string usually follows:\n'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'": [ - "Недействительная строка подключения, правильная строка обычно следует следующему шаблону:\n‘драйвер://пользователь:пароль@хостБД/имяБД’" + "Changing this report is forbidden": ["Запрещено изменять эту рассылку"], + "Character to interpret as decimal point": [ + "Символ десятичного разделителя" ], - "Malformed request. slice_id or table_name and db_name arguments are expected": [ - "Неправильный запрос. Ожидаются аргументы slice_id или table_name и db_name" + "Character to interpret as decimal point.": [ + "Символ десятичного разделителя" ], + "Chart": ["График"], "Chart %(id)s not found": ["График %(id)s не найден"], - "Table %(table)s wasn't found in the database %(db)s": [ - "Таблица %(table)s не найдена в базе данных %(db)s" + "Chart Cache Timeout": ["Время жизни кэша графика"], + "Chart Data: %s": ["Данные графика: %s"], + "Chart ID": ["ID графика"], + "Chart Options": ["Свойства графика"], + "Chart Orientation": ["Ориентация графика"], + "Chart Owner: %s": [ + "Владелец графика: %s", + "Владельцы графика: %s", + "Владельцы графика: %s" + ], + "Chart Title": ["Название графика"], + "Chart [%s] has been overwritten": ["График [%s] перезаписан"], + "Chart [%s] has been saved": ["График [%s] сохранен"], + "Chart [%s] was added to dashboard [%s]": [ + "График [%s] добавлен в дашборд [%s]" + ], + "Chart [{}] has been overwritten": ["График [{}] перезаписан"], + "Chart [{}] has been saved": ["График [{}] сохранен"], + "Chart [{}] was added to dashboard [{}]": [ + "График [{}] добавлен в дашборд [{}]" + ], + "Chart cache timeout": ["Время жизни кэша графика"], + "Chart changes": ["Изменения графика"], + "Chart component that lets you add a custom filter UI in your dashboard. When added to dashboard, a filter box lets users specify specific values or ranges to filter charts by. The charts that each filter box is applied to can be fine tuned as well in the dashboard view.\n\n Note that this plugin is being replaced with the new Filters feature that lives in the dashboard view itself. It's easier to use and has more capabilities!": [ + "" ], - "Can't find User '%(name)s', please ask your admin to create one.": [ - "Не удалось найти пользователя ‘%(name)s’. Обратитесь к администратору, чтобы создать его." + "Chart could not be created.": ["Не удалось создать график"], + "Chart could not be deleted.": ["Не удалось удалить график"], + "Chart could not be updated.": ["Не удалось обновить график"], + "Chart does not exist": ["График не существует"], + "Chart has no query context saved. Please save the chart again.": [ + "На графике не сохранен контекст запроса. Пожалуйста, сохраните диаграмму еще раз." ], - "Can't find DruidCluster with cluster_name = '%(name)s'": [ - "Не удалось найти DruidCluster с именем cluster_name = ‘%(name)s’" + "Chart height": ["Высота графика"], + "Chart imported": ["График импортирован"], + "Chart name": ["Имя графика"], + "Chart options": ["Свойства графика"], + "Chart parameters are invalid.": ["Параметры графика недопустимы."], + "Chart properties updated": ["Свойства графика обновлены"], + "Chart title": ["Название графика"], + "Chart type": ["Тип графика"], + "Chart type requires a dataset": [ + "Для данного типа графика необходим датасет" ], - "Data could not be deserialized. You may want to re-run the query.": [""], - "%(validator)s was unable to check your query.\nPlease recheck your query.\nException: %(ex)s": [ + "Chart width": ["Ширина графика"], + "Charts": ["Графики"], + "Charts could not be deleted.": ["Не удалось удалить графики."], + "Check configuration": ["Проверить конфигурацию"], + "Check for sorting ascending": ["Выберит для сортировки по возрастанию"], + "Check if the Rose Chart should use segment area instead of segment radius for proportioning": [ "" ], - "Failed to start remote query on a worker. Tell your administrator to verify the availability of the message queue.": [ - "Не удалось начать выполнение запроса на воркере. Сообщите администратору о необходимости проверить доступность очереди сообщений." + "Check out this chart in dashboard:": [ + "Посмотреть этот график в дашборде:" ], - "Query record was not created as expected.": [ - "Запись запроса не была создана должным образом." + "Check out this chart: ": ["Посмотреть график: "], + "Check out this dashboard: ": ["Посмотреть дашборд: "], + "Check to apply filters instantly as they change instead of displaying [Apply] button": [ + "Установите флажок, чтобы применять фильтры мгновенно по мере их изменения вместо отображения кнопки [Применить]" ], - "The parameter %(parameters)s in your query is undefined.": [ - "Следующие параметры в запросе не определены: %(parameters)s." - ], - "%(user)s's profile": ["Профиль пользователя %(user)s"], - "Show CSS Template": ["Шаблоны CSS"], - "Add CSS Template": ["Шаблоны CSS"], - "Edit CSS Template": ["Шаблоны CSS"], - "Template Name": ["Имя Шаблона"], - "A human-friendly name": ["Понятное человеку имя"], - "Used internally to identify the plugin. Should be set to the package name from the pluginʼs package.json": [ - "Используется системой для идентификации плагина. Должно быть установлено в имя пакета, которое указано в файле package.json" + "Check to force date partitions to have the same height": [""], + "Check to include time column dropdown": [""], + "Check to include time grain dropdown": [""], + "Child label position": ["Положение метки дочернего элемента"], + "Choice of [Label] must be present in [Group By]": [ + "[Метка] должна присутствовать в [Группировать по]" ], - "A full URL pointing to the location of the built plugin (could be hosted on a CDN for example)": [ - "" + "Choice of [Point Radius] must be present in [Group By]": [ + "[Радиус точки] должен присутствовать в [Группировать по]" ], - "Custom Plugins": ["Пользовательское условие WHERE"], - "Custom Plugin": ["Пользовательский плагин"], - "Add a Plugin": ["Добавить плагин"], - "Edit Plugin": ["Редактировать плагин"], - "Schedule Email Reports for Dashboards": [ - "Запланировать рассылку по email для дашбордов" - ], - "Manage Email Reports for Dashboards": [ - "Управление рассылками для дашбордов" - ], - "Changed On": ["Изменено"], - "Active": ["Действия"], - "Crontab": [""], - "Recipients": ["Получатели"], - "Slack Channel": ["Канал Slack"], - "Deliver As Group": [""], - "Delivery Type": ["Тип Подписи"], - "Schedule Email Reports for Charts": [ - "Запланировать рассылку по email для графиков" - ], - "Manage Email Reports for Charts": [ - "Управление рассылкой email для графиков" - ], - "Email Format": ["Формат значения"], - "List Saved Query": ["Список сохраненных запросов"], - "Show Saved Query": ["Показать сохраненный запрос"], - "Add Saved Query": ["Добавить сохраненный запрос"], - "Edit Saved Query": ["Изменить сохраненный запрос"], - "End Time": ["Время окончания"], - "Pop Tab Link": ["Открыть"], - "Changed on": ["Изменено"], - "Could not determine datasource type": [ - "Невозможно определить тип источника данных" + "Choose File": ["Выберите файл"], + "Choose a chart or dashboard not both": [ + "Выберите график или дашборд, не обоих" + ], + "Choose a database...": ["Выберите базу данных..."], + "Choose a dataset": ["Выберите датасет"], + "Choose a metric for left axis": ["Выберите меру для левой оси"], + "Choose a metric for right axis": ["Выберите меру для правой оси"], + "Choose a number format": ["Выберите числовой формат"], + "Choose a source": ["Выберите источник"], + "Choose a source and a target": ["Выберите источник и цель"], + "Choose a target": ["Выберите цель"], + "Choose a unique name": [""], + "Choose chart type": ["Выберите тип графика"], + "Choose one of the available databases from the panel on the left.": [ + "Выберите одну из доступных баз данных из панели слева." + ], + "Choose one or more charts for left axis": [ + "Выберите один или несколько графиков для левой оси" + ], + "Choose one or more charts for right axis": [ + "Выберите один или несколько графиков для правой оси" ], - "Could not find viz object": ["Невозможно найти объект визуализации"], - "Show Chart": ["Показать график"], - "Add Chart": ["Добавить график"], - "Edit Chart": ["Редактировать график"], - "These parameters are generated dynamically when clicking the save or overwrite button in the explore view. This JSON object is exposed here for reference and for power users who may want to alter specific parameters.": [ - "Эти параметры генерируются автоматически при нажатии кнопки сохранения. Опытные пользователи могут изменить определенные объекты в формате JSON." + "Choose the annotation layer type": ["Выбрать тип слоя аннотации"], + "Choose the format for legend values": [ + "Выберите формат значений легенды" ], - "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the datasource/table timeout if undefined.": [ - "Продолжительность (в секундах) таймаута кэширования для этого графика." + "Choose the position of the legend": ["Выберите позицию легенды"], + "Choose the source of your annotations": ["Выберите источник аннотаций"], + "Choose whether a country should be shaded by the metric, or assigned a color based on a categorical color palette": [ + "" ], - "Last Modified": ["Изменено"], - "Parameters": ["Параметры"], - "Visualization Type": ["Тип визуализации"], - "Show Dashboard": ["Показать дашборд"], - "Add Dashboard": ["Добавить дашборд"], - "Edit Dashboard": ["Редактировать дашборд"], - "This json object describes the positioning of the widgets in the dashboard. It is dynamically generated when adjusting the widgets size and positions by using drag & drop in the dashboard view": [ - "Этот объект JSON описывает расположение виджетов в дашборде. Он динамически генерируется при настройке размера и позиции виджетов в дашборде с помощью drag & drop" + "Chord Diagram": ["Хордовая диаграмма"], + "Chosen non-numeric column": ["Выбран нечисловой столбец"], + "Circle": ["Круг"], + "Circle -> Arrow": ["Круг -> Стрелка"], + "Circle -> Circle": ["Круг -> Круг"], + "Circle radar shape": ["Круглая форма радара"], + "Circular": ["Круглая форма"], + "Classic chart that visualizes how metrics change over time.": [ + "Классическая диаграмма для визуализации изменения показателей со временем." ], - "The CSS for individual dashboards can be altered here, or in the dashboard view where changes are immediately visible": [ - "В этом поле можно задать индивидуальный стиль для дашборда с помощью CSS" + "Classic row-by-column spreadsheet like view of a dataset. Use tables to showcase a view into the underlying data or to show aggregated metrics.": [ + "Классическое представление таблицы. Используйте таблицы для демонстрации отображения исходных или агрегированных данных." ], - "To get a readable URL for your dashboard": [ - "Получить читаемый URL-адрес для дашборда" + "Clause": ["Оператор"], + "Clear": ["Очистить"], + "Clear all": ["Сбросить фильтры"], + "Clear all data": ["Очистить все данные"], + "Clear form": ["Очистить форму"], + "Click on \"Create chart\" button in the control panel on the left to preview a visualization or": [ + "Нажмите на кнопку \"Создать график\" на панели управления слева для просмотра графика или" ], - "This JSON object is generated dynamically when clicking the save or overwrite button in the dashboard view. It is exposed here for reference and for power users who may want to alter specific parameters.": [ - "Этот JSON-объект генерируется автоматически при сохранении или перезаписи дашборда. Он размещён здесь справочно и для опытных пользователей." + "Click the button above to add a filter to the dashboard": [ + "Нажмите кнопку выше для добавления фильтров в дашборд" ], - "Owners is a list of users who can alter the dashboard.": [ - "Владельцы - это пользователи, которые могут изменять дашборд." + "Click the lock to make changes.": [ + "Нажмите на замок для внесения изменений" ], - "Determines whether or not this dashboard is visible in the list of all dashboards": [ - "Определяет видимость дашборда в списке всех дашбордов" - ], - "Title": ["Заголовок"], - "Slug": ["Читаемый URL"], - "Published": ["Опубликовано"], - "Position JSON": ["Позиция JSON"], - "CSS": ["CSS"], - "Underlying Tables": ["Базовые таблицы"], - "Export": ["Экспорт"], - "Export dashboards?": ["Экспортировать дашборд?"], - "Name of table to be created from csv data.": [ - "Имя таблицы, которая будет сформирована из данных csv." + "Click the lock to prevent further changes.": [ + "Нажмите на замок для запрета на внос изменений." ], - "CSV File": ["CSV-файл"], - "Select a CSV file to be uploaded to a database.": [ - "Выберите файл CSV, который будет загружен в БД." + "Click this link to switch to an alternate form that allows you to input the SQLAlchemy URL for this database manually.": [ + "Нажмите для переключения на альтернативную форму подключения, которая позволит вам вручную ввести SQLAlchemy URL для данной базы данных." ], - "Only the following file extensions are allowed: %(allowed_extensions)s": [ - "Разрешены файлы только в следующих расширениях: %(allowed_extensions)s" + "Click this link to switch to an alternate form that exposes only the required fields needed to connect this database.": [ + "Нажмите для переключения на альтернативную форму подключения, которая позволит вам ввести все данные в соответствующую форму для данной базы данных." ], - "Specify a schema (if database flavor supports this).": [ - "Укажите схему (если это поддерживается базой данных)." + "Click to cancel sorting": ["Нажмите для отмены сортировки"], + "Click to clear emitted filters": ["Нажмите для сброса кросс-фильтра"], + "Click to edit": ["Нажмите для редактирования"], + "Click to edit %s in a new tab": [ + "Нажмите для редактирования «%s» в новой вкладке" ], - "Delimiter": ["Разделитель"], - "Delimiter used by CSV file (for whitespace use \\s+).": [ - "Разделитель, используемый CSV-файлом (для пробелов используется \\s+)." + "Click to edit %s.": ["Нажмите для редактирования %s."], + "Click to edit chart.": ["Нажмите для редактирования графика."], + "Click to edit label": ["Нажмите для редактирования метки"], + "Click to favorite/unfavorite": ["Добавить в избранное"], + "Click to force-refresh": ["Нажмите для принудительного обновления"], + "Click to see difference": ["Нажмите для просмотра изменений"], + "Click to sort ascending": ["Нажмите для сортировки по возрастанию"], + "Click to sort descending": ["Нажмите для сортировки по убыванию"], + "Close": ["Закрыть"], + "Close all other tabs": ["Закрыть остальные вкладки"], + "Close tab": ["Закрыть вкладку"], + "Cluster label aggregator": ["Агрегатор меток кластера"], + "Clustering Radius": ["Радиус кластера"], + "Code": ["Редактор"], + "Collapse all": ["Свернуть всё"], + "Collapse data panel": ["Свернуть панель управления"], + "Collapse row": ["Свернуть строку"], + "Collapse tab content": ["Свернуть содержимое вкладки"], + "Collapse table preview": ["Свернуть предпросмотр таблицы"], + "Color": ["Цвет"], + "Color +/-": ["Раскрасить +/-"], + "Color Metric": ["Цвет меры"], + "Color Scheme": ["Цветовая схема"], + "Color Steps": ["Количество цветов"], + "Color bounds": ["Границы цвета"], + "Color by": ["Выбор цвета по"], + "Color metric": ["Мера для цвета"], + "Color of the target location": ["Цвет целевого местоположения"], + "Color scheme": ["Цветовая схема"], + "Color will be shaded based the normalized (0% to 100%) value of a given cell against the other cells in the selected range: ": [ + "" ], - "Table Exists": ["Метод добавления"], - "If table exists do one of the following: Fail (do nothing), Replace (drop and recreate table) or Append (insert data).": [ - "Если таблица уже существует, выполните одно из следующих действий: Fail (ничего не делать), Replace (удалить и заново создать таблицу) или Append (добавить данные)." + "Colors": ["Цвета"], + "Column": ["Столбец"], + "Column \"%(column)s\" is not numeric or does not exists in the query results.": [ + "Столбец \"%(column)s\" не является числовым или отсутствует в результатах запроса." ], - "Fail": ["Ошибка"], - "Replace": ["Заменить"], - "Append": ["Добавить"], - "Header Row": ["Строка заголовков"], - "Row containing the headers to use as column names (0 is first line of data). Leave empty if there is no header row.": [ - "Строка, содержащая заголовки для использования в качестве имен столбцов (0 - первая строка данных). Оставьте пустым, если строка заголовка отсутствует." + "Column Configuration": ["Свойства столбца"], + "Column Formatting": ["Форматирование столбца(ов)"], + "Column Label(s)": ["Метка(и) столбца(ов)"], + "Column containing ISO 3166-2 codes of region/province/department in your table.": [ + "Столбец, содержащий коды ISO 3166-2 региона/республики/области в вашей таблице" ], - "Index Column": ["Столбец индекса"], - "Column to use as the row labels of the dataframe. Leave empty if no index column.": [ - "Столбец для использования в качестве меток строк данных. Оставьте пустым, если столбец индекса отсутствует." + "Column containing latitude data": [ + "Столбец, содержащий данные о широте" ], - "Mangle Duplicate Columns": ["Дубликаты"], - "Specify duplicate columns as \"X.0, X.1\".": [ - "Если есть столбцы с одинаковым именем, то присвоить им порядковые номера - столбец1, столбец2, … и т.д." + "Column containing longitude data": [ + "Столбец, содержащий данные о долготе" ], - "Skip Initial Space": ["Убрать пробелы"], - "Skip spaces after delimiter.": ["Пропустить пробелы после разделителя."], - "Skip Rows": ["Игнорировать"], - "Number of rows to skip at start of file.": [ - "Количество первых строк, которые нужно проигнорировать." + "Column header tooltip": ["Всплывающая подсказка заголовка столбца"], + "Column is required": ["Столбец обязателен"], + "Column label for index column(s). If None is given and Dataframe Index is True, Index Names are used.": [ + "Метка для индексного(ых) столбца(ов). Если не задано и задан индекс датафрейма, будут использованы имена индексов." ], - "Rows to Read": ["Строки для чтения"], - "Number of rows of file to read.": ["Количество строк файла для чтения."], - "Skip Blank Lines": ["Пропустить пустые строки"], - "Skip blank lines rather than interpreting them as NaN values.": [ - "Пропустите пустые строки, а не интерпретировать их как значения NaN." + "Column label for index column(s). If None is given and Dataframe Index is checked, Index Names are used": [ + "Метка для индексного(ых) столбца(ов). Если не задано и задан индекс датафрейма, будут использованы имена индексов." ], - "Parse Dates": ["Разбор Дат"], - "A comma separated list of columns that should be parsed as dates.": [ - "Разделённый запятыми список столбцов, которые должен быть интерпретированы как даты." + "Column name": ["Имя столбца"], + "Column name [%s] is duplicated": [ + "Имя столбца [%s] является дубликатом" ], - "Infer Datetime Format": ["Формат даты и времени"], - "Use Pandas to interpret the datetime format automatically.": [ - "Используйте Pandas для автоматической интерпретации формата даты и времени." + "Column referenced by aggregate is undefined: %(column)s": [ + "Столбец, на который ссылается агрегат, не определен: %(column)s" ], - "Decimal Character": ["Десятичный символ"], - "Character to interpret as decimal point.": [ - "Символ, который интерпретируется как десятичная точка." + "Column select": ["Выбор столбца"], + "Column to use as the row labels of the dataframe. Leave empty if no index column": [ + "Столбец для использования в качестве метки для строки датафрейма. Оставьте пустым, если индексный столбец отсутствует." ], - "Dataframe Index": ["Индекс"], - "Write dataframe index as a column.": [ - "Записывайте индекс данных в виде столбца." + "Column to use as the row labels of the dataframe. Leave empty if no index column.": [ + "Столбец для использования в качестве метки для строки датафрейма. Оставьте пустым, если индексный столбец отсутствует." ], - "Column Label(s)": ["Обозначения столбцов"], - "Column label for index column(s). If None is given and Dataframe Index is True, Index Names are used.": [ - "Обозначение столбца для столбцов с индексами. Если поле пустое, а настройка [Индекс] включена, то используются имена индексов." + "Columnar File": ["Файл столбчатого формата"], + "Columnar file \"%(columnar_filename)s\" uploaded to table \"%(table_name)s\" in database \"%(db_name)s\"": [ + "Файл столбчатого формата \"%(columnar_filename)s\" загружен в таблицу \"%(table_name)s\" в базу данных \"%(db_name)s\"" ], - "Null values": ["Значение фильтра"], - "Json list of the values that should be treated as null. Examples: [\"\"], [\"None\", \"N/A\"], [\"nan\", \"null\"]. Warning: Hive database supports only single value. Use [\"\"] for empty string.": [ - "" + "Columnar to Database configuration": [ + "Конфигурация столбчатого файла для импорта в базу данных" ], - "Name of table to be created from excel data.": [ - "Имя таблицы, которая будет сформирована из данных csv." + "Columns": ["Столбцы"], + "Columns To Be Parsed as Dates": [ + "Список столбцов, которые должны быть интерпретированы как даты." ], - "Excel File": ["Файл Excel"], - "Select a Excel file to be uploaded to a database.": [ - "Выберите файл CSV, который будет загружен в БД." + "Columns To Read": ["Столбцы для чтения"], + "Columns missing in dataset: %(invalid_columns)s": [ + "Столбцы отсутствуют в датасете: %(invalid_columns)s" ], - "Sheet Name": ["Полное имя"], - "Strings used for sheet names (default is the first sheet).": [ - "Строки, используемые для имён листов (по-умолчанию это первый лист)." + "Columns missing in datasource: %(invalid_columns)s": [ + "Столбцы отсутствуют в источнике данных: %(invalid_columns)s" ], - "Show Database": ["Показать Базу Данных"], - "Add Database": ["Добавить Базу Данных"], - "Edit Database": ["Редактировать Базу Данных"], - "Expose this DB in SQL Lab": ["Показать базу данных в SQL Редакторе"], - "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.": [ - "" + "Columns subtotal position": ["Расположение столбцов подытогов"], + "Columns to calculate distribution across.": [""], + "Columns to display": ["Столбцы для отображения"], + "Columns to group by": ["Столбцы для группировки"], + "Columns to group by on the columns": [ + "Столбцы для группировки по столбцам" ], - "Allow CREATE TABLE AS option in SQL Lab": [ - "Разрешить выполнять инструкцию CREATE TABLE AS в редакторе SQL" + "Columns to group by on the rows": ["Столбцы для группировки по строкам"], + "Columns to show": ["Столбцы для отображения"], + "Combine Metrics": ["Объединить меры"], + "Combine metrics": ["Объединить меры"], + "Comma-separated color picks for the intervals, e.g. 1,2,4. Integers denote colors from the chosen color scheme and are 1-indexed. Length must be matching that of interval bounds.": [ + "Номера цветов, разделенные запятой, например, 1,2,4. Целые числа задают цвета из выбранной цветовой схемы и начинаются с 1 (не с нуля). Длина должна соответствовать границам интервала." ], - "Allow CREATE VIEW AS option in SQL Lab": [ - "Разрешить выполнять инструкцию CREATE TABLE AS в редакторе SQL" + "Comma-separated interval bounds, e.g. 2,4,5 for intervals 0-2, 2-4 and 4-5. Last number should match the value provided for MAX.": [ + "Границы интервала, разделенные запятой, например, 2,4,5 для интервалов 0-2, 2-4 и 4-5. Последнее число должно быть равно заданному максиму." ], - "Allow users to run non-SELECT statements (UPDATE, DELETE, CREATE, ...) in SQL Lab": [ - "Позволяет пользователям запускать инструкции (UPDATE, DELETE, CREATE, …) без SELECT в редакторе SQL" + "Comparator option": [""], + "Compare multiple time series charts (as sparklines) and related metrics quickly.": [ + "Быстрое сравнение нескольких графиков временных рядов (в виде спарклайнов) и связанных с ними показателей." ], - "When allowing CREATE TABLE AS option in SQL Lab, this option forces the table to be created in this schema": [ - "При разрешении опции CREATE TABLE AS в редакторе SQL эта опция создаст таблицу в выбранной схеме" + "Compare the same summarized metric across multiple groups.": [ + "Сравнивает один и тот же обобщенный показатель в нескольких группах" ], - "If Presto, Trino or Drill all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them.<br/>If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.": [ - "Если вы используете Presto, все запросы в SQL-Редакторе будут выполняться от авторизованного пользователя, который должен иметь разрешение на их выполнение. <br/> Если включен Hive, то запросы будут выполняться через техническую учетную запись, но ассоциировать зарегистрированного пользователя можно через свойство hive.server2.proxy.user." + "Compares how a metric changes over time between different groups. Each group is mapped to a row and change over time is visualized bar lengths and color.": [ + "" ], - "Allow SQL Lab to fetch a list of all tables and all views across all database schemas. For large data warehouse with thousands of tables, this can be expensive and put strain on the system.": [ + "Compares metrics from different categories using bars. Bar lengths are used to indicate the magnitude of each value and color is used to differentiate groups.": [ "" ], - "Duration (in seconds) of the caching timeout for charts of this database. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.": [ + "Compares the lengths of time different activities take in a shared timeline view.": [ "" ], - "If selected, please set the schemas allowed for csv upload in Extra.": [ - "Если включено, выберите схему, в которую разрешено загружать CSV на вкладке “Дополнительно”." + "Comparison": ["Сравнение"], + "Comparison Period Lag": ["Временной лаг для сравнения"], + "Comparison suffix": ["Текст рядом с процентным изменением"], + "Compose multiple layers together to form complex visuals.": [ + "Объединяет несколько слоев вместе для формирования сложных визуальных эффектов." ], - "Expose in SQL Lab": ["Открыть в SQL редакторе"], - "Allow CREATE TABLE AS": ["Разрешить CREATE TABLE AS"], - "Allow CREATE VIEW AS": ["Разрешить CREATE TABLE AS"], - "Allow DML": ["Allow DML"], - "CTAS Schema": ["Схема по умолчанию"], - "SQLAlchemy URI": ["SQLAlchemy URI"], - "Chart Cache Timeout": ["Тайм-аут Кэша"], - "Secure Extra": ["Безопасность"], - "Root certificate": ["Корневой сертификат"], - "Async Execution": ["Асинхронное выполнение"], - "Impersonate the logged on user": ["Ассоциировать пользователя"], - "Allow Csv Upload": ["Разрешить загрузку CSV"], - "Allow Multi Schema Metadata Fetch": [""], - "Backend": [""], - "Extra field cannot be decoded by JSON. %(msg)s": [""], - "Invalid connection string, a valid string usually follows:'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'<p>Example:'postgresql://user:password@your-postgres-db/database'</p>": [ - "Недействительная строка подключения, правильная строка обычно следует следующему шаблону: драйвер://пользователь:пароль@хостБД/имяБД<p>Пример:’postgresql://user:password@your-postgres-db/database'</p>" + "Compute the contribution to the total": [ + "Вычислить вклад в общую сумму (долю)" ], - "CSV to Database configuration": ["Настройка CSV для БД"], - "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for csv uploads. Please contact your Superset Admin.": [ - "Схема “%(schema_name)s” в базе данных “%(database_name)s” не разрешена для загрузки CSV. Пожалуйста, свяжитесь с администратором Superset." + "Condition": ["Условие"], + "Conditional formatting": ["Условное форматирование"], + "Confidence interval": ["Доверительный интервал"], + "Confidence interval must be between 0 and 1 (exclusive)": [ + "Доверительный интервал должен быть между 0 и 1 (не включая концы)" ], - "You cannot specify a namespace both in the name of the table: \"%(csv_table.table)s\" and in the schema field: \"%(csv_table.schema)s\". Please remove one": [ - "Нельзя указывать область имён одновременно и в имени таблицы: “%(csv_table.table)s” и в поле схемы: “%(csv_table.schema)s”. Пожалуйста, удалите в одном из мест" + "Configuration": ["Конфигурация"], + "Configure Advanced Time Range ": [ + "Установить особый временной интервал " ], - "Unable to upload CSV file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ - "Невозможно загрузить CSV-файл \"%(filename)s\" таблицу \"%(table_name)s\" базы данных \"%(db_name)s”. Сообщение об ошибке: %(error_msg)s" + "Configure Time Range: Last...": [ + "Установить временной интервал: последний..." ], - "CSV file \"%(csv_filename)s\" uploaded to table \"%(table_name)s\" in database \"%(db_name)s\"": [ - "CSV-файл \"%(csv_filename)s\" загружен в таблицу \"%(table_name)s\" базы данных \"%(db_name)s\"" + "Configure Time Range: Previous...": [ + "Установить временной интервал: предыдущий..." ], - "Excel to Database configuration": ["Настройка CSV для БД"], - "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for excel uploads. Please contact your Superset Admin.": [ - "Схема “%(schema_name)s” в базе данных “%(database_name)s” не разрешена для загрузок Excel-файлов. Пожалуйста, свяжитесь с администратором Superset." + "Configure custom time range": [ + "Установить пользовательский временной интервал" ], - "You cannot specify a namespace both in the name of the table: \"%(excel_table.table)s\" and in the schema field: \"%(excel_table.schema)s\". Please remove one": [ - "" + "Configure filter scopes": ["Настроить область действия фильтра"], + "Configure the basics of your Annotation Layer.": [ + "Настройте слой аннотации." ], - "Unable to upload Excel file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ - "Невозможно загрузить Excel-файл \"%(filename)s\" в таблицу \"%(table_name)s\" базы данных \"%(db_name)s”. Сообщение об ошибке: %(error_msg)s" + "Configure this dashboard to embed it into an external web application.": [ + "Настройте этот дашборд для встраивания во внешнее веб-приложение" ], - "Excel file \"%(excel_filename)s\" uploaded to table \"%(table_name)s\" in database \"%(db_name)s\"": [ - "Excel-файл “%(excel_filename)s\" загружен в таблицу \"%(table_name)s\" базы данных \"%(db_name)s\"" - ], - "Logs": ["Журналы"], - "Show Log": ["Показать итоги"], - "Add Log": ["Добавить журнал"], - "Edit Log": ["Редактировать"], - "Action": ["Действия"], - "dttm": ["dttm"], - "Add item": ["Добавить фильтр"], - "The query couldn't be loaded": ["Запрос невозможно загрузить"], - "Your query has been scheduled. To see details of your query, navigate to Saved queries": [ - "Запрос был запланирован. Чтобы посмотреть детали запроса, перейдите в Сохранённые запросы" + "Configure your how you overlay is displayed here.": [ + "Настройка отображения слоя аннотации поверх графика." ], - "Your query could not be scheduled": [ - "Ваш запрос не может быть сохранен" + "Confirm overwrite": ["Подтвердить перезапись"], + "Confirm save": ["Подтвердить сохранение"], + "Connect": ["Подключить"], + "Connect Google Sheet": ["Подключить Google Таблицы"], + "Connect Google Sheets as tables to this database": [ + "Подключить Google Таблицы как таблицы для этой базы данных" ], - "Failed at retrieving results": ["Невозможно выполнить запрос"], - "An error occurred while storing the latest query id in the backend. Please contact your administrator if this problem persists.": [ - "" + "Connect a database": ["Подключиться к базе данных"], + "Connect database": ["Подключиться к базе данных"], + "Connect this database using the dynamic form instead": [ + "Подключиться к этой базе, используя динамичную форму" ], - "Unknown error": ["Неизвестная ошибка"], - "Query was stopped.": ["Запрос прерван."], - "Unable to migrate table schema state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ - "" + "Connect this database with a SQLAlchemy URI string instead": [ + "Подключиться к этой базе через SQLAlchemy URI" ], - "Unable to migrate query state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ - "" + "Connection": ["База данных"], + "Connection failed, please check your connection settings": [ + "Сбой подключения, пожалуйста, проверьте настройки вашего подключения" ], - "Unable to migrate query editor state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ - "" + "Connection looks good!": ["Соединение в порядке!"], + "Continue": ["Продолжить"], + "Continuous": ["Непрерывный"], + "Contribution": ["Режим относительных значений"], + "Contribution Mode": ["Режим относительных значений"], + "Control": ["Элемент"], + "Control labeled ": ["Значение с именем "], + "Controls labeled ": ["Значения с именами "], + "Coordinates": ["Координаты"], + "Copied to clipboard!": ["Скопировано в буфер обмена"], + "Copy": ["Копировать"], + "Copy SELECT statement to the clipboard": [ + "Скопировать выражение SELECT в буфер обмена" ], - "Unable to add a new tab to the backend. Please contact your administrator.": [ - "" + "Copy and Paste JSON credentials": ["Скопировать и вставить JSON данные"], + "Copy and paste the entire service account .json file here": [ + "Скопировать и вставить .json файл сервисного аккаунта сюда" ], - "Copy of %s": ["Копирование %s"], - "An error occurred while setting the active tab. Please contact your administrator.": [ - "Произошла ошибка при установке активной вкладки. Пожалуйста, свяжитесь с администратором." + "Copy link": ["Скопировать ссылку"], + "Copy message": ["Скопировать сообщение"], + "Copy of %s": ["Копия %s"], + "Copy partition query to clipboard": [ + "Скопировать часть запроса в буфер обмена" ], - "An error occurred while fetching tab state": [ - "Произошла ошибка при получении метаданных из таблицы" + "Copy permalink to clipboard": ["Скопировать ссылку в буфер обмена"], + "Copy query URL": ["Скопировать ссылку на запрос"], + "Copy query link to your clipboard": [ + "Скопировать ссылку на запрос в буфер обмена" ], - "An error occurred while removing tab. Please contact your administrator.": [ - "Произошла ошибка при удалении вкладки. Пожалуйста, свяжитесь с администратором." + "Copy the account name of that database you are trying to connect to.": [ + "Впишите имя профиля базы данных, к которой вы пытаетесь подключиться." ], - "An error occurred while removing query. Please contact your administrator.": [ - "Произошла ошибка при удалении запроса. Пожалуйста, свяжитесь с администратором." + "Copy the name of the database you are trying to connect to.": [ + "Впишите имя базы данных, к которой вы пытаетесь подключиться" ], - "An error occurred while setting the tab database ID. Please contact your administrator.": [ - "Произошла ошибка при установке ID базы данных для вкладки. Пожалуйста, свяжитесь с администратором." + "Copy to Clipboard": ["Скопировать в буфер обмена"], + "Copy to clipboard": ["Скопировать в буфер обмена"], + "Correlation": ["Корреляция"], + "Cost estimate": ["Прогноз затрат"], + "Could not determine datasource type": [ + "Не удалось определить тип источника данных" ], - "An error occurred while setting the tab schema. Please contact your administrator.": [ - "Произошла ошибка при настройке схемы вкладок. Пожалуйста, свяжитесь с администратором." + "Could not fetch all saved charts": [ + "Не удалось получить все сохраненные графики" ], - "An error occurred while setting the tab autorun. Please contact your administrator.": [ - "Произошла ошибка при настройке автозапуска вкладки. Пожалуйста, свяжитесь с администратором." + "Could not find viz object": ["Не удалось найти объект визуализации"], + "Could not load database driver": [ + "Не удалось загрузить драйвер базы данных" ], - "An error occurred while setting the tab title. Please contact your administrator.": [ - "Произошла ошибка при настройке заголовка вкладки. Пожалуйста, свяжитесь с администратором." + "Could not load database driver: %(driver_name)s": [ + "Не удалось загрузить драйвер базы данных: %(driver_name)s" ], - "Your query was saved": ["Ваш запрос был сохранен"], - "Your query could not be saved": ["Ваш запрос не может быть сохранен"], - "Your query was updated": ["Ваш запрос был сохранен"], - "Your query could not be updated": ["Ваш запрос не может быть сохранен"], - "An error occurred while storing your query in the backend. To avoid losing your changes, please save your query using the \"Save Query\" button.": [ - "Произошла ошибка при сохранении запроса в бэкенд. Чтобы сохранить изменения, пожалуйста, сохраните ваш запрос через кнопку “Сохранить запрос”." + "Could not load database driver: {}": [ + "Не удалось загрузить драйвер базы данных: {}" + ], + "Count": ["Количество"], + "Count Unique Values": ["Количество уникальных значений"], + "Count as Fraction of Columns": ["Количество, как доля от столбцов"], + "Count as Fraction of Rows": ["Количество, как доля от строк"], + "Count as Fraction of Total": ["Количество, как доля от целого"], + "Country": ["Страна"], + "Country Color Scheme": ["Цветовая схема страны"], + "Country Column": ["Столбец со страной"], + "Country Field Type": ["Тип поля страны"], + "Country Map": ["Карта Стран"], + "Create": ["Создать"], + "Create Chart": ["Создать график"], + "Create Dataset": ["Создать датасет"], + "Create a dataset": ["Создать датасет"], + "Create a dataset to begin visualizing your data as a chart or go to\n SQL Lab to query your data.": [ + "Создайте датасет для визуализации ваших данных на графике или перейдите в Лабораторию SQL для просмотра данных." + ], + "Create a new chart": ["Создать новый график"], + "Create chart": ["Создать график"], + "Create dataset": ["Создать датасет"], + "Create new chart": ["Создать новый график"], + "Create new filter set": ["Создать новый набор фильтров"], + "Create or select schema...": ["Создать или выбрать схему..."], + "Created": ["Создано"], + "Created On": ["Дата создания"], + "Created by": ["Кем создано"], + "Created by me": ["Создано мной"], + "Created content": ["Созданный контент"], + "Created on": ["Дата создания"], + "Creating SSH Tunnel failed for an unknown reason": [ + "Не удалось создать SSH туннель по неизвестной причине" ], - "An error occurred while setting the tab template parameters. Please contact your administrator.": [ - "Произошла ошибка при установке параметров шаблона вкладки. Пожалуйста, свяжитесь с администратором." + "Creating a data source and creating a new tab": [ + "Создание источника данных и добавление новой вкладки..." ], - "An error occurred while fetching table metadata": [ - "Произошла ошибка при получении метаданных из таблицы" + "Creator": ["Автор"], + "Crimson": ["Малиновый"], + "Cross Filter Scoping": ["Область действия кросс-фильтра"], + "Cross-filter scoping": ["Задать область действия кросс-фильтра"], + "Cumulative": ["С накоплением"], + "Currently rendered: %s": ["Сейчас отрисовано: %s"], + "Custom": ["Пользовательский"], + "Custom Plugin": ["Пользовательский плагин"], + "Custom Plugins": ["Пользовательские плагины"], + "Custom SQL": ["Через SQL"], + "Custom SQL ad-hoc metrics are not enabled for this dataset": [ + "Пользовательские ad-hoc меры SQL не разрешены для этого датасета" ], - "An error occurred while fetching table metadata. Please contact your administrator.": [ - "Произошла ошибка при получении метаданных таблицы. Пожалуйста, свяжитесь с администратором." + "Custom SQL fields cannot contain sub-queries.": [ + "Пользовательские поля SQL не могут содержать подзапросы." ], - "An error occurred while expanding the table schema. Please contact your administrator.": [ - "Произошла ошибка при разворачивании схемы. Пожалуйста, свяжитесь с администратором." + "Custom time filter plugin": ["Пользовательский плагин фильтра времени"], + "Customize": ["Кастомизация"], + "Customize Metrics": ["Настроить меры"], + "Customize columns": ["Настроить столбцы"], + "Cyclic dependency detected": ["Обнаружена циклическая зависимость"], + "D3 Format": ["Формат даты/времени"], + "D3 format": ["Формат даты/времени"], + "D3 format syntax: https://github.com/d3/d3-format": [ + "Формат D3: https://github.com/d3/d3-format." ], - "An error occurred while collapsing the table schema. Please contact your administrator.": [ - "Произошла ошибка при сворачивании схемы. Пожалуйста, свяжитесь с администратором." + "D3 number format for numbers between -1.0 and 1.0, useful when you want to have different siginificant digits for small and large numbers": [ + "Числовой формат D3 для чисел от -1 до 1, полезно, если вы работаете как с маленькими числами, где нужна точность, так и с большими целыми числами" ], - "An error occurred while removing the table schema. Please contact your administrator.": [ - "Произошла ошибка при удалении схемы. Пожалуйста, свяжитесь с администратором." + "D3 time format for datetime columns": [ + "Формат времени D3 для столбцов типа дата/время" ], - "Shared query": ["Общий запрос"], - "The datasource couldn't be loaded": ["Запрос невозможно загрузить"], - "An error occurred while creating the data source": [ - "Произошла ошибка при создании источника данных" + "D3 time format syntax: https://github.com/d3/d3-time-format": [ + "Формат времени D3: https://github.com/d3/d3-time-format." ], - "SQL Lab uses your browser's local storage to store queries and results.\n Currently, you are using ${currentUsage.toFixed(\n 2,\n )} KB out of ${LOCALSTORAGE_MAX_USAGE_KB} KB. storage space.\n To keep SQL Lab from crashing, please delete some query tabs.\n You can re-access these queries by using the Save feature before you delete the tab. Note that you will need to close other SQL Lab windows before you do this.": [ - "Лаборатория SQL использует хранилище локального кеша вашего браузера, чтобы сохранить запросы и результаты из вкладок.\n Сейчас вы используете ${currentUsage.toFixed(\n 2,\n )} KB из ${LOCALSTORAGE_MAX_USAGE_KB} KB пространства.\n Чтобы уберечь Лабораторию SQL от ошибок, пожалуйста, удалите неиспользуемые вкладки с запросами.\n Вы можете получить доступ к этим запросам позже, если сохраните их перед удалением вкладки. Обратите внимание, что перед удалением вкладок нужно будет закрыть другие окна с Лабораторией SQL." + "DATETIME": ["Дата/Время (DATETIME/TIMESTAMP)"], + "DB column %(col_name)s has unknown type: %(value_type)s": [""], + "DEC": ["ДЕК"], + "DELETE": ["УДАЛИТЬ"], + "DML": ["DML"], + "Daily seasonality": ["Дневная сезонность"], + "Dark": ["Темный"], + "Dark Cyan": ["Темно-голубой"], + "Dark mode": ["Темная тема"], + "Dashboard": ["Дашборд"], + "Dashboard [%s] just got created and chart [%s] was added to it": [ + "Дашборд [%s] был только что создан и график [%s] был добавлен в него" ], - "Estimate selected query cost": ["Выполнить выбранный запрос"], - "Estimate cost": ["Выполнить выбранный запрос"], - "Cost estimate": ["Прогноз затрат"], - "Creating a data source and creating a new tab": [ - "Создание источника данных и добавление новой вкладки" + "Dashboard [{}] just got created and chart [{}] was added to it": [ + "Дашборд [{}] был только что создан и график [{}] был добавлен в него" ], - "An error occurred": ["Произошла ошибка"], - "Explore the result set in the data exploration view": [ - "Исследовать набор данных" + "Dashboard could not be created.": ["Не удалось создать дашборд"], + "Dashboard could not be deleted.": ["Не удалось удалить дашборд"], + "Dashboard could not be updated.": ["Не удалось обновить дашборд"], + "Dashboard does not exist": ["Дашборд не существует"], + "Dashboard imported": ["Дашборд импортирован"], + "Dashboard parameters are invalid.": ["Неверные параметры дашборда"], + "Dashboard properties": ["Свойства дашборда"], + "Dashboard properties updated": ["Свойства дашборда обновлены"], + "Dashboard scheme": ["Схема дашборда"], + "Dashboard time range filters apply to temporal columns defined in\n the filter section of each chart. Add temporal columns to the chart\n filters to have this dashboard filter impact those charts.": [ + "" ], - "Explore": ["Обзор графика"], - "This query took %s seconds to run, ": [ - "Выполнение этого запроса заняло %s секунд, " + "Dashboard title": ["Название дашборда"], + "Dashboards": ["Дашборды"], + "Dashboards added to": ["Добавлено в дашборды"], + "Dashboards could not be deleted.": ["Не удалось удалить дашборды."], + "Dashboards do not exist": ["Дашборды не существуют"], + "Dashed": ["Штрих"], + "Data": ["Данные"], + "Data Table": ["Таблица"], + "Data Zoom": ["Масштабирование графика"], + "Data could not be deserialized from the results backend. The storage format might have changed, rendering the old data stake. You need to re-run the original query.": [ + "Не удалось распознать данные с сервера . Формат хранилища мог измениться, что привело к потере старых данных. Вам нужно повторно запустить исходный запрос." + ], + "Data could not be retrieved from the results backend. You need to re-run the original query.": [ + "Не найдены сохраненные результаты на сервере, необходимо повторно выполнить запрос." + ], + "Data has no time steps": [""], + "Data preview": ["Предпросмотр данных"], + "Data refreshed": ["Данные обновлены"], + "Data type": ["Тип данных"], + "DataFrame include at least one series": [""], + "DataFrame must include temporal column": [ + "Датафрейм должен включать временной столбец" ], - "and the explore view times out at %s seconds ": [ - "а тайм-аут интерфейса исследования %s секунд " + "Database": ["База данных"], + "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for columnar uploads. Please contact your Superset Admin.": [ + "Схема \"%(schema_name)s\" базы данных \"%(database_name)s\" не предназначена для загрузки файлов столбчатого формата. Пожалуйста, свяжитесь с администратором." ], - "following this flow will most likely lead to your query timing out. ": [ - "" + "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for csv uploads. Please contact your Superset Admin.": [ + "Схема \"%(schema_name)s\" базы данных \"%(database_name)s\" не предназначена для загрузки CSV файлов. Пожалуйста, свяжитесь с администратором." ], - "We recommend your summarize your data further before following that flow. ": [ - "" + "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for excel uploads. Please contact your Superset Admin.": [ + "Схема \"%(schema_name)s\" базы данных \"%(database_name)s\" не предназначена для загрузки Excel файлов. Пожалуйста, свяжитесь с администратором." ], - "If activated you can use the ": [""], - "feature to store a summarized data set that you can then explore.": [""], - "Column name(s) ": ["Имена столбца(ов) "], - "cannot be used as a column name. The column name/alias \"__timestamp\"\n is reserved for the main temporal expression, and column aliases ending with\n double underscores followed by a numeric value (e.g. \"my_col__1\") are reserved\n for deduplicating duplicate column names. Please use aliases to rename the\n invalid column names.": [ - "" + "Database Connections": ["Базы данных"], + "Database Creation Error": ["Ошибка создания базы данных"], + "Database URL": ["URL базы данных"], + "Database connected": ["Соединение с базой данных установлено"], + "Database could not be created.": ["Не удалось создать базу данных."], + "Database could not be deleted.": ["Не удалось удалить базу данных."], + "Database could not be updated.": ["Не удалось обновить базу данных."], + "Database does not allow data manipulation.": [ + "База данных не позволяет изменять свои данные." ], - "Raw SQL": ["Raw SQL"], - "Source SQL": ["Источник SQL"], - "SQL": ["SQL"], - "No query history yet...": ["История запросов пуста…"], - "It seems you don't have access to any database": [ - "Кажется у Вас нет доступа к базе данных" + "Database does not exist": ["База данных не существует"], + "Database does not support subqueries": [ + "База данных не поддерживает подзапросы" ], - "An error occurred when refreshing queries": [ - "Произошла ошибка при создании источника данных" + "Database driver for importing maybe not installed. Visit the Superset documentation page for installation instructions: ": [ + "Драйвер базы данных для импорта может быть не установлен. Изучите документацию Суперсета для инструкций по установке: " ], - "Filter by user": ["Значение фильтра"], - "Filter by database": ["Выберите базу данных"], - "Query search string": ["Поиск запросов"], - "[From]-": ["[С]-"], - "[To]-": ["[До]-"], - "Filter by status": ["Значение фильтра"], - "Edit": ["Редактировать"], - "View results": ["Посмотреть результаты"], - "Data preview": ["Предпросмотр данных"], - "Overwrite text in the editor with a query on this table": [ - "Перезаписать текст в редакторе с запросом к этой таблице" + "Database error": ["Ошибка базы данных"], + "Database is offline.": ["База данных сейчас оффлайн."], + "Database is required for alerts": [ + "Для оповещений требуется база данных" ], - "Run query in a new tab": ["Выполнить запрос на новой вкладке"], - "Remove query from log": ["Удалить запрос из журнала"], - "An error occurred saving dataset": [ - "Произошла ошибка при создании источника данных" + "Database name": ["Имя базы данных"], + "Database not allowed to change": [ + "База данных недоступна для изменений" ], - ".CSV": ["Экспорт в CSV"], - "Clipboard": ["Скопировать в буфер обмена"], - "Filter results": ["Результаты поиска"], - "Database error": ["Database Expression"], - "was created": ["создан"], - "Query in a new tab": ["Запрос в отдельной вкладке"], - "The query returned no data": ["Результат пуст"], - "Fetch data preview": ["Получить данные для просмотра"], - "Refetch results": ["Результаты поиска"], - "Track job": ["Отслеживать работу"], - "Stop": ["Стоп"], - "Run selection": ["Выполнить выбранный запрос"], - "Run": ["Выполнить"], - "Stop running (Ctrl + x)": ["Остановить (Ctrl + x)"], - "Stop running (Ctrl + e)": ["Остановить (Ctrl + e)"], - "Run query (Ctrl + Return)": ["Выполнить запрос (Ctrl + Return)"], - "Save & Explore": ["Сохранить и исследовать"], - "Overwrite & Explore": ["Перезаписать и исследовать"], - "Undefined": ["Не определено"], - "Save": ["Сохранить"], - "Save as": ["Сохранить как"], - "Save query": ["Сохранить запрос"], - "Save as new": ["Сохранить как новый"], - "Update": ["Обновить"], - "Label for your query": ["Метка для вашего запроса"], - "Write a description for your query": [ - "Заполните описание к вашему запросу" + "Database not found.": ["База данных не найдена."], + "Database not found: %(id)s": ["База данных не найдена: %(id)s"], + "Database parameters are invalid.": [ + "Параметры базы данных недействительны." ], - "Schedule query": ["Сохранить запрос"], - "Schedule": ["Расписание"], - "There was an error with your request": [ - "С вашим запросом произошла ошибка" + "Database passwords": ["Пароли базы данных"], + "Database port": ["Порт базы данных"], + "Database settings updated": ["Обновлены настройки базы данных"], + "Databases": ["Базы данных"], + "Dataframe Index": ["Индекс датафрейма"], + "Dataset": ["Датасет"], + "Dataset %(name)s already exists": ["Датасет %(name)s уже существует"], + "Dataset Name": ["Имя датасета"], + "Dataset column delete failed.": ["Не удалось удалить столбец датасета"], + "Dataset column not found.": ["Столбец датасета не найден"], + "Dataset could not be created.": ["Не удалось создать датасет"], + "Dataset could not be deleted.": ["Не удалось удалить датасет"], + "Dataset could not be duplicated.": ["Датасет не может быть дублирован."], + "Dataset could not be updated.": ["Не удалось обновить датасет"], + "Dataset does not exist": ["Датасет не существует"], + "Dataset imported": ["Импортирован датасет"], + "Dataset is required": ["Требуется датасет"], + "Dataset metric delete failed.": ["Не удалось удалить меру датасета."], + "Dataset metric not found.": ["Мера датасета не найдена."], + "Dataset name": ["Имя датасета"], + "Dataset parameters are invalid.": ["Параметры датасета неверны."], + "Dataset schema is invalid, caused by: %(error)s": [ + "Схема датасета невалидна, причина: %(error)s" ], - "Please save the query to enable sharing": [ - "Пожалуйста, сохраните запрос, чтобы включить функцию “поделиться”" + "Dataset(s) could not be bulk deleted.": [ + "Датасет(ы) не могут быть массово удалены." ], - "Copy link": ["Скопировать ссылку"], - "Copy query link to your clipboard": [ - "Скопировать часть запроса в буфер обмена" + "Datasets": ["Датасеты"], + "Datasets can be created from database tables or SQL queries. Select a database table to the left or ": [ + "Датасеты могут быть созданы из таблиц базы данных или SQL запросов. Выберите таблицу из базы данных слева или " ], - "Save the query to copy the link": [ - "Сохраните запрос, чтобы скопировать ссылку" + "Datasets do not contain a temporal column": [ + "Датасет не содержит столбца формата дата/время" ], - "No stored results found, you need to re-run your query": [ - "Не найдены сохранённые результаты, необходимо повторно выполнить запрос" + "Datasource": ["Источник данных"], + "Datasource & Chart Type": ["Источник данных и Тип графика"], + "Datasource does not exist": ["Источник данных не существует"], + "Datasource type is invalid": ["Тип источниках данных неверный"], + "Datasource type is required when datasource_id is given": [ + "Тип источника данных обязателен, когда дан идентификатор источника данных (datasource_id)" ], - "Run a query to display results here": [ - "Выполнить запрос для отображения результатов" + "Date Time Format": ["Формат даты и времени"], + "Date filter": ["Временной фильтр"], + "Date format": ["Форматы даты"], + "Date format string": ["Формат временной строки"], + "Date/Time": ["Дата/Время"], + "Datetime Format": ["Формат даты и времени"], + "Datetime column not provided as part table configuration and is required by this type of chart": [ + "Столбец даты/времени не предусмотрен в настройках таблицы и является обязательным для этого типа графика" ], - "Preview: `%s`": ["Предпросмотр %s"], - "Results": ["Результаты"], - "Query history": ["История запросов"], - "Run query": ["Выполнить запрос"], - "New tab": ["Закрыть вкладку"], - "Untitled query": ["Запрос без имени"], - "Stop query": ["Остановить запрос"], - "Schedule the query periodically": [ - "Запланировать периодическое выполнение запроса" + "Datetime format": ["Формат даты/времени"], + "Day": ["День"], + "Day (freq=D)": ["День (част=D)"], + "Days %s": ["Дней %s"], + "Db engine did not return all queried columns": [ + "драйвер базы данных вернул не все запрошенные столбцы" ], - "You must run the query successfully first": [ - "Сначала необходимо успешно выполнить запрос" + "Deactivate": ["Выключить"], + "December": ["Декабрь"], + "Decimal Character": ["Десятичный разделитель"], + "Deck.gl - 3D Grid": ["Deck.gl - 3D сетка"], + "Deck.gl - Arc": ["Deck.gl - Дуга"], + "Deck.gl - GeoJSON": ["Deck.gl - GeoJSON"], + "Deck.gl - Multiple Layers": ["Deck.gl - Многослойный"], + "Deck.gl - Polygon": ["Deck.gl - Полигон"], + "Deck.gl - Scatter plot": ["Deck.gl - Точечная диаграмма"], + "Default": ["По умолчанию"], + "Default Endpoint": ["Эндпоинт по умолчанию"], + "Default URL": ["URL по умолчанию"], + "Default URL to redirect to when accessing from the dataset list page": [ + "URL по умолчанию, на который будет выполнен редирект при доступе из страницы со списком датасетов" ], - "It appears that the number of rows in the query results displayed\n was limited on the server side to\n the %s limit.": [ - "" + "Default Value": ["Значение по умолчанию"], + "Default datetime": ["Дата и время по умолчанию"], + "Default latitude": ["Широта по умолчанию"], + "Default longitude": ["Долгота по умолчанию"], + "Default minimal column width in pixels, actual width may still be larger than this if other columns don't need much space": [ + "Минимальная ширина столбца (в пикселях). Реальная ширина по-прежнему может быть больше, чем указанная, если остальным столбцам не будет хватать места." ], - "CREATE TABLE AS": ["Разрешить CREATE TABLE AS"], - "CREATE VIEW AS": ["Разрешить CREATE TABLE AS"], - "Estimate the cost before running a query": [ - "Спрогнозировать время до выполнения запроса" + "Default value is required": ["Требуется значение по умолчанию"], + "Default value must be set when \"Filter has default value\" is checked": [ + "Значение по умолчанию должно быть выбрано, когда установлен флаг \"Фильтр имеет значение по умолчанию\"" ], - "Reset state": ["Сбросить текущее состояние"], - "Enter a new title for the tab": ["Введите название для таблицы"], - "Untitled Query %s": ["Запрос без имени %s"], - "Close tab": ["Закрыть вкладку"], - "Rename tab": ["Переименовать вкладку"], - "Expand tool bar": ["Показать панель инструментов"], - "Hide tool bar": ["Скрыть панель инструментов"], - "Close all other tabs": ["Закрыть все вкладки"], - "Duplicate tab": ["Дублировать вкладку"], - "Copy partition query to clipboard": [ - "Скопировать часть запроса в буфер обмена" + "Default value must be set when \"Filter value is required\" is checked": [ + "Значение по умолчанию должно быть выбрано, когда установлен флаг \"Требуется значение фильтра\"" ], - "latest partition:": ["последний раздел:"], - "Keys for table": ["Ключевые поля таблицы"], - "View keys & indexes (%s)": ["Посмотреть ключи и индексы (%s)"], - "Sort columns alphabetically": [ - "Отсортировать столбцы в алфавитном порядке" + "Default value set automatically when \"Select first filter value by default\" is checked": [ + "Значение по умолчанию задается автоматически, когда установлен флаг \"Сделать первое значение фильтра значением по умолчанию\"" ], - "Original table column order": [ - "Расположение столбцов как в исходной таблице" + "Define a function that receives the input and outputs the content for a tooltip": [ + "Задайте функцию, которая получает на вход содержимое всплывающей подсказки" ], - "Copy SELECT statement to the clipboard": [ - "Скопировать выражение SELECT в буфер обмена" + "Define a function that returns a URL to navigate to when user clicks": [ + "Задайте функцию, которая возвращает URL для навигации при пользовательском нажатии" ], - "Show CREATE VIEW statement": ["Показать выражение CREATE VIEW"], - "CREATE VIEW statement": ["Выражение CREATE VIEW"], - "Remove table preview": ["Убрать предпросмотр таблицы"], - "Assign a set of parameters as": [""], - "below (example:": [""], - "), and they become available in your SQL (example:": [""], - ") by using": [""], - "Edit template parameters": ["Изменить параметры шаблона"], - "Invalid JSON": ["Недопустимый формат json"], - "Create a new chart": ["Создать новый срез"], - "Choose a dataset": ["Выберите источник данных"], - "If the dataset you are looking for is not available in the list, follow the instructions on how to add it in the Superset tutorial.": [ - "Если датасет, который вы ищете не доступен в списке, следуйте инструкциям по добавлению его в руководстве по Superset." - ], - "Choose a visualization type": ["Выберите тип визуализации"], - "Create new chart": ["Создать новый график"], - "An error occurred while loading the SQL": [ - "Произошла ошибка при создании источника данных" + "Define a javascript function that receives the data array used in the visualization and is expected to return a modified version of that array. This can be used to alter properties of the data, filter, or enrich the array.": [ + "Определите функцию javascript, которая получает массив данных, используемый в визуализации, и, как ожидается, вернет измененную версию этого массива. Это может быть использовано для изменения свойств данных, фильтрации или расширения массива." ], - "Updating chart was stopped": ["Обновление графика остановлено"], - "An error occurred while rendering the visualization: %s": [ - "Произошла ошибка при построении графика: %s" + "Defines a rolling window function to apply, works along with the [Periods] text box": [ + "Определяет функцию скользящего окна для применения, работает вместе с текстовым полем [Периоды]" ], - "Network error.": ["Ошибка сети."], - "every": ["каждый"], - "every month": ["месяц"], - "every day of the month": ["каждый день месяца"], - "day of the month": ["день месяца"], - "every day of the week": ["каждый день недели"], - "day of the week": ["день недели"], - "every hour": ["каждый час"], - "every minute UTC": [""], - "year": ["год"], - "month": ["месяц"], - "week": ["неделя"], - "day": ["день"], - "hour": ["час"], - "minute": ["минута"], - "reboot": [""], - "Every": [""], - "in": ["в"], - "on": [""], - "and": [""], - "at": [""], - ":": [":"], - "minute(s) UTC": ["5 минут"], - "Invalid cron expression": [""], - "Clear": ["Очистить"], - "Sunday": ["Воскресенье"], - "Monday": ["Понедельник"], - "Tuesday": ["Вторник"], - "Wednesday": ["Среда"], - "Thursday": ["Четверг"], + "Defines how each series is broken down": [ + "Определяет разложение каждой категории" + ], + "Defines the grid size in pixels": [ + "Определяет размер сетки (в пикселях)" + ], + "Defines the grouping of entities. Each series is shown as a specific color on the chart and has a legend toggle": [ + "Группировка в ряды данных. Каждая категория отображается в виде определенного цвета на графике и имеет легенду" + ], + "Defines the size of the rolling window function, relative to the time granularity selected": [ + "Определяет размер функции скользящего окна относительно выбранной детализации по времени" + ], + "Defines whether the step should appear at the beginning, middle or end between two data points": [ + "Определяет, должен ли шаг отображаться в начале, середине или конце между двумя точками данных" + ], + "Delete": ["Удалить"], + "Delete %s?": ["Удалить %s?"], + "Delete Annotation?": ["Удалить аннотацию?"], + "Delete Database?": ["Удалить базу данных?"], + "Delete Dataset?": ["Удалить датасет?"], + "Delete Layer?": ["Удалить слой?"], + "Delete Query?": ["Удалить запрос?"], + "Delete Report?": ["Удалить рассылку?"], + "Delete Template?": ["Удалить шаблон?"], + "Delete all Really?": ["Действительно удалить все?"], + "Delete annotation": ["Удалить аннотацию"], + "Delete dashboard tab?": ["Удалить вкладку дашборда?"], + "Delete database": ["Удалить базу данных"], + "Delete email report": ["Удалить рассылку по email"], + "Delete query": ["Удалить запрос"], + "Delete template": ["Удалить шаблон"], + "Delete this container and save to remove this message.": [ + "Удалите этот контейнер и сохраните изменения, чтобы убрать это сообщение." + ], + "Deleted %(num)d annotation": [ + "Удалалена %(num)d аннотация", + "Удалалены %(num)d аннотации", + "Удалалено %(num)d аннотаций" + ], + "Deleted %(num)d annotation layer": [ + "Удалален %(num)d слой аннотаций", + "Удалалены %(num)d слоя аннотаций", + "Удалалено %(num)d слоев аннотаций" + ], + "Deleted %(num)d chart": [ + "Удален %(num)d график", + "Удалены %(num)d графика", + "Удалено %(num)d графиков" + ], + "Deleted %(num)d css template": [ + "Удален %(num)d CSS шаблон", + "Удалены %(num)d CSS шаблона", + "Удалено %(num)d CSS шаблонов" + ], + "Deleted %(num)d dashboard": [ + "Удален %(num)d дашборд", + "Удалены %(num)d дашборда", + "Удалено %(num)d дашбордов" + ], + "Deleted %(num)d dataset": [ + "Удален %(num)d датасет", + "Удалены %(num)d датасета", + "Удалено %(num)d датасетов" + ], + "Deleted %(num)d report schedule": [ + "Удалено %(num)d расписание рассылок", + "Удалены %(num)d расписания рассылок", + "Удалено %(num)d расписаний рассылок" + ], + "Deleted %(num)d saved query": [ + "Удален %(num)d сохраненный запрос", + "Удалены %(num)d сохраненных запроса", + "Удалено %(num)d сохраненных запросов" + ], + "Deleted: %s": ["Удалено: %s"], + "Deleting a tab will remove all content within it. You may still reverse this action with the": [ + "Удаление вкладки удалит все ее содержимое. Вы можете отменить это действие при помощи сочетания клавиш" + ], + "Delimited long & lat single column": [ + "Долгота и широта в одном столбце" + ], + "Delimiter": ["Разделитель"], + "Delivery method": ["Способ оповещения"], + "Demographics": ["Демография"], + "Density": ["Концентрация"], + "Dependent on": ["Зависит от"], + "Deprecated": ["Устарело"], + "Description": ["Описание"], + "Description (this can be seen in the list)": [ + "Описание (будет видно в списке)" + ], + "Description Columns": ["Описательные столбцы"], + "Description text that shows up below your Big Number": [ + "Описание, отображаемое под Карточкой" + ], + "Deselect all": ["Снять выделение"], + "Details of the certification": ["Детали утверждения"], + "Determines how whiskers and outliers are calculated.": [ + "Определяет формулу расчета \"усов\" и выбросов." + ], + "Determines whether or not this dashboard is visible in the list of all dashboards": [ + "Определяет, виден ли этот дашборд в списке всех дашбордов" + ], + "Diamond": ["Ромб"], + "Did you mean:": ["Возможно вы имели в виду:"], + "Difference": ["Разница"], + "Dim Gray": ["Тускло-серый"], + "Dimension": ["Измерение"], + "Dimension to use on x-axis.": ["Измерение для использования на оси X"], + "Dimension to use on y-axis.": ["Измерение для использования на оси Y"], + "Dimensions": ["Измерения"], + "Directed Force Layout": [""], + "Directional": ["Направленный"], + "Disable SQL Lab data preview queries": [ + "Отключить предпросмотр данных в Лаборатории SQL" + ], + "Disable data preview when fetching table metadata in SQL Lab. Useful to avoid browser performance issues when using databases with very wide tables.": [ + "Отключить предварительный просмотр данных при извлечении метаданных таблицы в SQL Lab. Полезно для избежания проблем с производительностью браузера при использовании баз данных с очень широкими таблицами." + ], + "Disable embedding?": ["Выключить встраивание?"], + "Disabled": ["Отключено"], + "Discard": ["Отменить изменения"], + "Discrete": ["Обособленный"], + "Display Name": ["Отображаемое имя"], + "Display column level total": ["Отображать общий итог по столбцу"], + "Display configuration": ["Настройки отображения"], + "Display metrics side by side within each column, as opposed to each column being displayed side by side for each metric.": [ + "Отображать меры рядом в каждом столбце, в отличие от отображения каждого столбца рядом для каждой меры." + ], + "Display row level total": ["Отображать общий итог по строке"], + "Display settings": ["Настройки отображения"], + "Display total row/column": ["Отобразить общую строку/столбец"], + "Displays connections between entities in a graph structure. Useful for mapping relationships and showing which nodes are important in a network. Graph charts can be configured to be force-directed or circulate. If your data has a geospatial component, try the deck.gl Arc chart.": [ + "" + ], + "Distribution": ["Распределение"], + "Distribution - Bar Chart": ["Распределение - Столбчатая диаграмма"], + "Divider": ["Разделитель"], + "Do you want a donut or a pie?": ["Круговая/кольцевая диаграмма"], + "Documentation": ["Документация"], + "Domain": ["Блок"], + "Donut": ["Кольцевая диаграмма"], + "Dotted": ["Пунктир"], + "Download": ["Сохранить"], + "Download as image": ["Сохранить как изображение"], + "Download to CSV": ["Сохранить в CSV"], + "Draft": ["Черновик"], + "Drag and drop components and charts to the dashboard": [ + "Переместите элементы оформления и графики на дашборд" + ], + "Drag and drop components to this tab": [ + "Переместите элементы оформления и графики в эту вкладку" + ], + "Draw a marker on data points. Only applicable for line types.": [ + "Отобразить маркеры на данных. Применимо только для линий." + ], + "Draw area under curves. Only applicable for line types.": [ + "Отобразить область под кривыми. Применимо только для линий\"" + ], + "Draw line from Pie to label when labels outside?": [ + "Проводит линию от диаграммы к метке, когда метки находятся снаружи" + ], + "Draw split lines for minor axis ticks": [ + "Рисует разделительные линии для небольших отметок оси" + ], + "Draw split lines for minor y-axis ticks": [ + "Рисует разделительные линии для небольших отметок оси Y" + ], + "Drill to detail": [""], + "Drill to detail by": [""], + "Drill to detail by value is not yet supported for this chart type.": [ + "" + ], + "Drill to detail is disabled because this chart does not group data by dimension value.": [ + "" + ], + "Drill to detail: %s": [""], + "Drop a column here or click": [ + "Перетащите столбец сюда", + "Перетащите столбцы сюда", + "Перетащите столбцы сюда" + ], + "Drop a column/metric here or click": [ + "Перетащите столбец/меру сюда", + "Перетащите столбцы/меры сюда", + "Перетащите столбцы/меры сюда" + ], + "Drop a temporal column here or click": [ + "Перетащите столбец формата дата/время сюда" + ], + "Drop column here": [ + "Перетащите столбец сюда", + "Перетащите столбцы сюда", + "Перетащите столбцы сюда" + ], + "Drop column or metric here": [ + "Перетащите столбец или меру сюда", + "Перетащите столбцы или меры сюда", + "Перетащите столбцы или меры сюда" + ], + "Drop columns here": ["Перетащите столбцы сюда"], + "Drop columns or metrics here": ["Перетащите столбцы или меры сюда"], + "Drop columns/metrics here or click": ["Перетащите столбцы/меры сюда"], + "Drop temporal column here": [ + "Перетащите столбец формата дата/время сюда" + ], + "Duplicate": ["Дублировать"], + "Duplicate column name(s): %(columns)s": [ + "Повторяющееся имя столбца(ов): %(columns)s" + ], + "Duplicate column/metric labels: %(labels)s. Please make sure all columns and metrics have a unique label.": [ + "Повторяющиеся метки столбцов/мер: %(labels)s. Пожалуйста, убедитесь, что все столбцы и меры имеют уникальную метку." + ], + "Duplicate dataset": ["Дублировать датасет"], + "Duplicate tab": ["Дублировать вкладку"], + "Duration": ["Продолжительность"], + "Duration (in seconds) of the caching timeout for charts of this database. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.": [ + "Продолжительность (в секундах) таймаута кэша для графиков этой базы данных. Таймаут 0 означает, что кэш никогда не очистится. Обратите внимание, что если значение не задано, применяется значение по умолчанию из основной конфигурации." + ], + "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the dataset's timeout if undefined.": [ + "Продолжительность (в секундах) таймаута кэша для этого графикаОбратите внимание, что если значение не задано, применяется значение таймаута датасета." + ], + "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the datasource/table timeout if undefined.": [ + "Продолжительность (в секундах) таймаута кэша для этого графикаОбратите внимание, что если значение не задано, применяется значение источника данных/таблицы." + ], + "Duration (in seconds) of the caching timeout for this table. A timeout of 0 indicates that the cache never expires. Note this defaults to the database timeout if undefined.": [ + "Продолжительность (в секундах) таймаута кэша для этой таблицы. Обратите внимание, что если значение не задано, применяется значение базы данных." + ], + "Duration (in seconds) of the metadata caching timeout for schemas of this database. If left unset, the cache never expires.": [ + "Продолжительность (в секундах) таймаута кэша для схем этой базы данных. Обратите внимание, что если значение не задано, кэш никогда не очистится." + ], + "Duration (in seconds) of the metadata caching timeout for tables of this database. If left unset, the cache never expires. ": [ + "Продолжительность (в секундах) таймаута кэша для таблиц этой базы данных. Обратите внимание, что если значение не задано, кэш никогда не очистится." + ], + "Duration in ms (1.40008 => 1ms 400µs 80ns)": [ + "Продолжительность в мс (1.40008 => 1ms 400µs 80ns)" + ], + "Duration in ms (100.40008 => 100ms 400µs 80ns)": [ + "Продолжительность в мс (100.40008 => 100ms 400µs 80ns)" + ], + "Duration in ms (66000 => 1m 6s)": [ + "Продолжительность в мс (66000 => 1m 6s)" + ], + "Duration: %s": ["Продолжительность: %s"], + "Dynamic Aggregation Function": ["Динамическая агрегирующая функция"], + "Dynamically search all filter values": [ + "Динамически искать все значения фильтра" + ], + "ECharts": ["Графики Apache"], + "END (EXCLUSIVE)": ["КОНЕЦ (НЕ ВКЛЮЧИТЕЛЬНО)"], + "ERROR": ["ОШИБКА"], + "ERROR: %s": ["ОШИБКА: %s"], + "Edge length": ["Длина ребер"], + "Edge length between nodes": ["Длина ребер между вершинами"], + "Edge symbols": ["Оформление ребер"], + "Edge width": ["Толщина ребра"], + "Edit": ["Редактировать"], + "Edit Alert": ["Редактировать оповещение"], + "Edit CSS": ["Редактировать CSS"], + "Edit CSS Template": ["Редактировать CSS шаблон"], + "Edit CSS template properties": ["Редактировать свойств CSS шаблона"], + "Edit Chart": ["Редактировать график"], + "Edit Chart Properties": ["Редактировать свойства графика"], + "Edit Column": ["Редактировать столбец"], + "Edit Dashboard": ["Редактировать дашборд"], + "Edit Database": ["Редактировать Базу Данных"], + "Edit Dataset ": ["Редактировать датасет "], + "Edit Log": ["Редактировать запись"], + "Edit Metric": ["Редактировать меру"], + "Edit Plugin": ["Редактировать плагин"], + "Edit Report": ["Редактировать отчет"], + "Edit Saved Query": ["Редактировать сохраненный запрос"], + "Edit Table": ["Редактировать таблицу"], + "Edit annotation": ["Редактировать аннотацию"], + "Edit annotation layer": ["Редактировать слой аннотации"], + "Edit annotation layer properties": [ + "Редактировать свойства слоя аннотаций" + ], + "Edit chart": ["Редактировать график"], + "Edit chart properties": ["Редактировать свойства графика"], + "Edit dashboard": ["Редактировать дашборд"], + "Edit database": ["Редактировать Базу Данных"], + "Edit dataset": ["Редактировать датасет"], + "Edit email report": ["Редактировать рассылку"], + "Edit properties": ["Редактировать свойства"], + "Edit query": ["Редактировать запрос"], + "Edit template": ["Редактировать шаблон"], + "Edit template parameters": [ + "Редактировать параметры шаблонизации Jinja" + ], + "Edit the dashboard": ["Редактировать дашборд"], + "Edit time range": ["Изменить временной интервал"], + "Edited": ["Редактировано"], + "Editing 1 filter:": ["Редактирование 1 фильтра:"], + "Editing filter set:": ["Редактирование набора фильтров:"], + "Either the database is spelled incorrectly or does not exist.": [ + "Неверное или несуществующее имя базы данных." + ], + "Either the username \"%(username)s\" or the password is incorrect.": [ + "Неверное имя пользователя \"%(username)s\" или пароль." + ], + "Either the username \"%(username)s\", password, or database name \"%(database)s\" is incorrect.": [ + "Неверное имя пользователя \"%(username)s\", пароль или имя базы данных \"%(database)s\"." + ], + "Either the username or the password is wrong.": [ + "Неверное имя пользователя или пароль" + ], + "Email reports active": ["Включить рассылки"], + "Embed": ["Встроить"], + "Embed code": ["Встроенный код"], + "Embed dashboard": ["Встроить дашборд"], + "Embedding deactivated.": ["Встраивание отключено"], + "Emitted values": ["Отображаемые значения"], + "Emphasis": ["Акцент"], + "Employment and education": ["Трудоустройство и образование"], + "Empty circle": ["Пустой круг"], + "Empty collection": ["Пустая коллекция"], + "Empty query result": ["Пустой ответ запроса"], + "Empty query?": ["Пустой запрос?"], + "Empty row": [""], + "Enable 'Allow file uploads to database' in any database's settings": [ + "Включите \"Разрешить загрузку файлов в базу данных\" в настройках любой базы данных" + ], + "Enable data zooming controls": [ + "Включить элементы управления масштабированием данных" + ], + "Enable embedding": ["Разрешить встраивание"], + "Enable forecast": ["Включить прогноз в график"], + "Enable forecasting": ["Включить прогнозирование данных"], + "Enable graph roaming": ["Включить перемещение по графику"], + "Enable node dragging": ["Разрешить перемещение вершин"], + "Enable query cost estimation": ["Разрешить оценку стоимости запроса"], + "Enable server side pagination of results (experimental feature)": [ + "Включить серверную пагинацию результатов (экспериментально)" + ], + "Encountered invalid NULL spatial entry, please consider filtering those out": [ + "" + ], + "End": ["Конец"], + "End (Longitude, Latitude): ": ["Конец (Долгота, Широта)"], + "End Longitude & Latitude": ["Конечные Долгота и Широта"], + "End Time": ["Время окончания"], + "End angle": ["Конечный угол"], + "End date excluded from time range": [ + "Конечная дата исключена из временного интервала" + ], + "End date must be after start date": [ + "Конечная дата должна быть после начальной" + ], + "Engine \"%(engine)s\" cannot be configured through parameters.": [ + "Не удается настроить драйвер \"%(engine)s\" при данных параметрах." + ], + "Engine Parameters": ["Параметры драйвера"], + "Engine spec \"InvalidEngine\" does not support being configured via individual parameters.": [ + "" + ], + "Enter CA_BUNDLE": ["Введите CA_BUNDLE"], + "Enter Primary Credentials": ["Введите основные учетные данные"], + "Enter a delimiter for this data": ["Введите разделитель этих данных"], + "Enter a name for this sheet": ["Введите название для этого листа"], + "Enter a new title for the tab": ["Введите новое название для вкладки"], + "Enter duration in seconds": ["Введите время в секундах"], + "Enter fullscreen": ["Полноэкранный режим"], + "Enter the required %(dbModelName)s credentials": [ + "Введите обязательные данные для %(dbModelName)s" + ], + "Entity": ["Элемент"], + "Entity ID": ["ID элемента"], + "Equal Date Sizes": ["Одинаковые размеры дат"], + "Equal to (=)": [""], + "Error": ["Ошибка"], + "Error in jinja expression in HAVING clause: %(msg)s": [ + "Ошибка в jinja выражении в операторе HAVING: %(msg)s" + ], + "Error in jinja expression in RLS filters: %(msg)s": [ + "Ошибка в jinja выражении в RLS фильтрах: %(msg)s" + ], + "Error in jinja expression in WHERE clause: %(msg)s": [ + "Ошибка в jinja выражении в операторе WHERE: %(msg)s" + ], + "Error in jinja expression in fetch values predicate: %(msg)s": [ + "Ошибка в jinja выражении в предикате выборки значений: %(msg)s" + ], + "Error loading chart datasources. Filters may not work correctly.": [ + "Ошибка загрузки источников данных для графиков. Фильтры могут работать некорректно." + ], + "Error message": ["Сообщение об ошибке"], + "Error while fetching charts": ["Возникла ошибка при получении графиков"], + "Error while fetching data: %s": [ + "Возникла ошибка при получении данных: %s" + ], + "Error while rendering virtual dataset query: %(msg)s": [ + "Произошла ошибка при выполнении запроса виртуального датасета: %(msg)s" + ], + "Error: %(error)s": ["Ошибка: %(error)s"], + "Error: %(msg)s": ["Ошибка: %(msg)s"], + "Error: permalink state not found": [""], + "Estimate cost": ["Оценить стоимость запроса"], + "Estimate selected query cost": ["Оценить стоимость выбранного запроса"], + "Estimate the cost before running a query": [ + "Спрогнозировать стоимость до выполнения запроса" + ], + "Event": ["Событие"], + "Event Names": ["Имена событий"], + "Event definition": ["Определение события"], + "Event time column": ["Столбец формата дата/время"], + "Every": ["Каждый(ая)"], + "Evolution": ["Динамика"], + "Exact": ["Точное"], + "Example": ["Пример"], + "Examples": ["Примеры"], + "Excel File": ["Excel Файл"], + "Excel file \"%(excel_filename)s\" uploaded to table \"%(table_name)s\" in database \"%(db_name)s\"": [ + "Excel файл \"%(excel_filename)s\" загружен в таблицу \"%(table_name)s\" в базе данных \"%(db_name)s\"" + ], + "Excel to Database configuration": [ + "Конфигурация Excel файла для импорта в базу данных" + ], + "Exclude selected values": ["Исключить выбранные значения"], + "Executed SQL": ["Исполненный SQL"], + "Executed query": ["Выполненный запрос"], + "Execution ID": ["ID исполнения"], + "Execution log": ["Журнал Действий"], + "Existing dataset": ["Существующий датасет"], + "Exit fullscreen": ["Выйти из полноэкранного режима"], + "Expand": ["Расширить"], + "Expand all": ["Расширить все"], + "Expand data panel": ["Расширить панель данных"], + "Expand row": ["Развернуть строку"], + "Expand table preview": ["Расширить предпросмотр таблицы"], + "Expand tool bar": ["Показать панель инструментов"], + "Expects a formula with depending time parameter 'x'\n in milliseconds since epoch. mathjs is used to evaluate the formulas.\n Example: '2x+5'": [ + "Формула с зависимой переменной 'x' в милисекундах с 1970 года (Unix-время). Для рассчета используется mathjs. Например: '2x+5'" + ], + "Experimental": ["Экспериментальный"], + "Explore": ["Исследовать"], + "Explore - %(table)s": ["Исследовать - %(table)s"], + "Explore the result set in the data exploration view": [ + "Создать новый график на основе этих данных" + ], + "Export": ["Экспортировать"], + "Export dashboards?": ["Экспортировать дашборды?"], + "Export query": ["Экспорт запроса"], + "Export to .CSV": ["Экспорт в .CSV"], + "Export to .JSON": ["Экспорт в .JSON"], + "Export to YAML": ["Экспорт в YAML"], + "Export to YAML?": ["Экспортировать в YAML?"], + "Export to full .CSV": ["Экспорт в целый .CSV"], + "Export to original .CSV": ["Экспорт исходных данных в .CSV"], + "Export to pivoted .CSV": ["Экспорт сводной таблицы в .CSV"], + "Expose database in SQL Lab": [ + "Предоставить доступ к базе в Лаборатории SQL" + ], + "Expose in SQL Lab": ["Доступен в SQL редакторе"], + "Expose this DB in SQL Lab": [ + "Предоставить доступ к базе в Лаборатории SQL" + ], + "Expression": ["Выражение"], + "Extra": ["Дополнительные параметры"], + "Extra Controls": ["Дополнительные элементы управления"], + "Extra Parameters": ["Доп. параметры"], + "Extra data for JS": ["Доп. данные для JS"], + "Extra data to specify table metadata. Currently supports metadata of the format: `{ \"certification\": { \"certified_by\": \"Data Platform Team\", \"details\": \"This table is the source of truth.\" }, \"warning_markdown\": \"This is a warning.\" }`.": [ + "Дополнительные метаданные таблицы. В настоящий момент поддерживается следующий формат: `{ \"certification\": { \"certified_by\": \"Руководитель отдела\", \"details\": \"Эта таблица - источник правды.\" }, \"warning_markdown\": \"Это предупреждение.\" }`." + ], + "Extra field cannot be decoded by JSON. %(msg)s": [ + "Дополнительное поле не может быть декодировано с помощью JSON. %(msg)s" + ], + "Extra parameters for use in jinja templated queries": [ + "Дополнительные параметры для запросов, использующих шаблонизацию Jinja" + ], + "Extra parameters that any plugins can choose to set for use in Jinja templated queries": [ + "Дополнительные параметры для шаблонизации Jinja, которые могут быть использованы в графиках" + ], + "Extra url parameters for use in Jinja templated queries": [ + "Дополнительные url параметры для запросов, использующих шаблонизацию Jinja" + ], + "Extruded": [""], + "FEB": ["ФЕВ"], + "FRI": ["ПТ"], + "Factor": [""], + "Factor to multiply the metric by": ["Число, на которое умножается мера"], + "Fail": ["Ошибка"], + "Failed": ["Ошибка"], + "Failed at retrieving results": ["Невозможно выполнить запрос"], + "Failed at stopping query. %s": ["Не удалось остановить запрос. %s"], + "Failed to create report": ["Не удалось создать рассылку"], + "Failed to execute %(query)s": [""], + "Failed to load chart data": ["Не удалось загрузить данные графика"], + "Failed to load chart data.": ["Не удалось загрузить данные графика."], + "Failed to retrieve advanced type": [ + "Не удалось получить расширенный тип" + ], + "Failed to start remote query on a worker.": [ + "Не удалось запустить удаленный запрос на сервере." + ], + "Failed to update report": ["Не удалось обновить отчет"], + "Failed to verify select options: %s": [ + "Ошибка при проверке вариантов выбора: %s" + ], + "Favorite": ["Избранное"], + "Favorites": ["Избранное"], + "February": ["Февраль"], + "Fetch Values Predicate": [""], + "Fetch data preview": ["Получить данные для просмотра"], + "Fetched %s": ["Получено %s"], + "Fetching": ["Получение данных"], + "Field cannot be decoded by JSON. %(json_error)s": [ + "поле не может быть декодировано с помощью JSON. %(json_error)s" + ], + "Field cannot be decoded by JSON. %(msg)s": [ + "Поле не может быть декодировано с помощью JSON. %(msg)s" + ], + "Field is required": ["Поле обязательно к заполнению"], + "File": ["Файл"], + "Fill Color": ["Цвет заливки"], + "Fill all required fields to enable \"Default Value\"": [ + "Установить все требуемые флаги для включения \"Значения по умолчанию\"" + ], + "Fill method": ["Метод заполнения пропусков"], + "Filled": ["С заливкой"], + "Filter": ["Фильтр"], + "Filter Configuration": ["Конфигурация фильтра"], + "Filter List": ["Список фильтров"], + "Filter Settings": ["Настройки фильтра"], + "Filter Type": ["Тип фильтра"], + "Filter box": ["Фильтр-виджет"], + "Filter configuration": ["Настройки фильтра"], + "Filter configuration for the filter box": [ + "Настройки фильтра для \"Фильтр-виджета\"" + ], + "Filter has default value": ["Фильтр имеет значение по умолчанию"], + "Filter metadata changed in dashboard. It will not be applied.": [ + "Метаданные фильтра изменились в дашборде. Они не будут применены." + ], + "Filter name": ["Имя фильтра"], + "Filter only displays values relevant to selections made in other filters.": [ + "Фильтр предлагает только те значения, которые отобраны выбранными фильтрами" + ], + "Filter results": ["Фильтровать результаты"], + "Filter set already exists": ["Набор фильтров уже существует"], + "Filter set with this name already exists": [ + "Набор фильтров с этим именем уже существует" + ], + "Filter sets (%(filterSetCount)d)": [ + "Наборы фильтров (%(filterSetCount)d)" + ], + "Filter type": ["Тип фильтра"], + "Filter value (case sensitive)": [ + "Фильтровать значения (зависит от регистра)" + ], + "Filter value is required": ["Требуется значение фильтра"], + "Filter value list cannot be empty": [ + "Список для фильтрации не может быть пуст" + ], + "Filter your charts": ["Поиск"], + "Filterable": ["Фильтруемый"], + "Filters": ["Фильтры"], + "Filters (%d)": ["Фильтры (%d)"], + "Filters by columns": ["Фильтры по столбцам"], + "Filters by metrics": ["Фильтры по мерам"], + "Filters configuration": ["Конфигурация фильтров"], + "Filters out of scope (%d)": ["Фильтры вне рамок дашборда (%d)"], + "Filters with the same group key will be ORed together within the group, while different filter groups will be ANDed together. Undefined group keys are treated as unique groups, i.e. are not grouped together. For example, if a table has three filters, of which two are for departments Finance and Marketing (group key = 'department'), and one refers to the region Europe (group key = 'region'), the filter clause would apply the filter (department = 'Finance' OR department = 'Marketing') AND (region = 'Europe').": [ + "" + ], + "Finish": ["Завершить"], + "First": ["Первый"], + "Fix the trend line to the full time range specified in case filtered results do not include the start or end dates": [ + "Фиксирует линию тренда в полном временном интервале, указанном в случае, если отфильтрованные результаты не включают даты начала или окончания" + ], + "Fix to selected Time Range": ["Выбрать временной интервал"], + "Fixed": ["Фиксированный"], + "Fixed Color": ["Фиксированный цвет"], + "Fixed color": ["Фиксированный цвет"], + "Fixed point radius": ["Фиксированный радиус"], + "Flow": ["Поток"], + "Font size": ["Размер шрифта"], + "Font size for axis labels, detail value and other text elements": [ + "Размер шрифта для меток осей, значений деталей и других текстовых элементов" + ], + "Font size for the biggest value in the list": [ + "Размер шрифта для наибольшего значения в списке" + ], + "Font size for the smallest value in the list": [ + "Размер шрифта для наименьшего значения в списке" + ], + "For Bigquery, Presto and Postgres, shows a button to compute cost before running a query.": [ + "Для Bigquery, Presto и Postgres, показывать кнопку подсчета стоимости запроса перед его выполнением." + ], + "For further instructions, consult the": [ + "Для получения дальнейших инструкций обратитесь к" + ], + "For more information about objects are in context in the scope of this function, refer to the": [ + "" + ], + "For regular filters, these are the roles this filter will be applied to. For base filters, these are the roles that the filter DOES NOT apply to, e.g. Admin if admin should see all data.": [ + "" + ], + "Force": ["Силовой алгоритм"], + "Force all tables and views to be created in this schema when clicking CTAS or CVAS in SQL Lab.": [ + "Принудить создание новых таблиц через CTAS или CVAS в Лаборатории SQL в этой схеме при нажатии соответствующих кнопок" + ], + "Force date format": ["Принудительный перевод к формату дата/время"], + "Force refresh": ["Обновить"], + "Force refresh schema list": ["Принудительно обновить список схем"], + "Force refresh table list": ["Принудительно обновить список таблиц"], + "Forecast periods": ["Кол-во прогнозных периодов"], + "Foreign key": ["Внешний ключ"], + "Forest Green": ["Лесной зеленый"], + "Form data not found in cache, reverting to chart metadata.": [ + "Данные формы не найдены в кэше, возвращение к метаданным графика." + ], + "Form data not found in cache, reverting to dataset metadata.": [ + "Данные формы не найдены в кэше, возвращение к метаданным датасета." + ], + "Formattable": ["Форматируемый"], + "Formatted CSV attached in email": [ + "Форматированный CSV, прикрепленный к письму" + ], + "Formatted date": ["Форматированная дата"], + "Formatted value": ["Форматированное значение"], + "Formatting": ["Форматирование"], + "Formula": ["Формула"], + "Forward values": ["Будущие значения"], + "Found invalid orderby options": [""], + "Fraction digits": ["Десятичные знаки"], + "Frequency": ["Частота"], + "Friction": ["Трение"], + "Friction between nodes": ["Сила трения между вершинами"], "Friday": ["Пятница"], - "Saturday": ["Суббота"], + "From date cannot be larger than to date": [ + "Дата начала не может быть позже даты конца" + ], + "Full name": ["Полное имя"], + "Funnel Chart": ["Воронка"], + "Further customize how to display each column": [ + "Дальнейшая настройка отображения каждого столбца" + ], + "Further customize how to display each metric": [ + "Дальнейшая настройка отображения каждой меры" + ], + "GROUP BY": ["GROUP BY"], + "Gauge Chart": ["Индикаторная диаграмма"], + "General": ["Основные свойства"], + "Generating link, please wait..": [ + "Генерация ссылки, пожалуйста, ждите..." + ], + "Generic Chart": ["Общая диаграмма"], + "Geo": ["Карта"], + "GeoJson Column": ["Столбец GeoJson"], + "GeoJson Settings": ["Настройки GeoJson"], + "Geohash": ["Geohash"], + "Get the last date by the date unit.": [""], + "Get the specify date for the holiday": [""], + "Go to the edit mode to configure the dashboard and add charts": [ + "Перейдите в режим редактирования для изменения дашборда и добавьте графики" + ], + "Gold": ["Золотой"], + "Google Sheet Name and URL": ["Имя или URL Google Таблицы"], + "Grace period": ["Перерыв между оповещением"], + "Graph Chart": ["Сетевой график"], + "Graph layout": ["Формат сетевого графика"], + "Gravity": ["Гравитация"], + "Grid": ["Сетка"], + "Grid Size": ["Размер сетки"], + "Group By": ["Группировать по"], + "Group By filter plugin": [""], + "Group By' and 'Columns' can't overlap": [ + "Измерения и Столбцы не могут повторяться" + ], + "Group By, Metrics or Percentage Metrics must have a value": [ + "Измерения, Меры или Процентные меры должны иметь значение" + ], + "Group by": ["Группировать по"], + "Groupable": ["Группируемый"], + "Handlebars": ["Handlebars"], + "Handlebars Template": ["Шаблон Handlebars"], + "Hard value bounds applied for color coding. Is only relevant and applied when the normalization is applied against the whole heatmap.": [ + "" + ], + "Has created by": ["Создан(а)"], + "Header": ["Заголовок"], + "Header Row": ["Строка заголовка"], + "Heatmap": ["Тепловая карта"], + "Heatmap Options": ["Настройки тепловой карты"], + "Height": ["Высота"], + "Height of the sparkline": ["Высота спарклайна"], + "Hide Line": ["Скрыть линию"], + "Hide chart description": ["Скрыть описание графика"], + "Hide layer": ["Скрыть слой"], + "Hide password.": ["Скрыть пароль."], + "Hide tool bar": ["Скрыть панель инструментов"], + "Hides the Line for the time series": [""], + "Hierarchy": ["Иерархия"], + "Histogram": ["Гистограмма"], + "Home": ["Главная"], + "Horizontal": ["Горизонтально"], + "Horizontal (Top)": ["Горизонтально (сверху)"], + "Horizontal alignment": ["Выравнивание по горизонтали"], + "Host": ["Хост"], + "Hostname or IP address": ["Имя хоста или IP адрес"], + "Hour": ["Час"], + "Hours %s": ["Часов %s"], + "Hours offset": ["Смещение времени"], + "How do you want to enter service account credentials?": [""], + "How many buckets should the data be grouped in.": [""], + "How many periods into the future do we want to predict": [ + "На сколько периодов в будущем предсказывать" + ], + "How to display time shifts: as individual lines; as the difference between the main time series and each time shift; as the percentage change; or as the ratio between series and time shifts.": [ + "Как отображать смещения во времени: как отдельные линии; как абсолютную разницу между основным временным рядом и каждым смещением; как процентное изменение; или как соотношение между рядами и смещениями." + ], + "Huge": ["Огромный"], + "ISO 3166-2 Codes": ["Коды ISO 3166-2"], + "ISO 8601": ["ISO 8601"], + "Id": ["ID"], + "Id of root node of the tree.": ["Id корневой вершины дерева."], + "If Presto or Trino, all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them. If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.": [ + "Если вы используете Presto или Trino, все запросы в Лаборатории SQL будут выполняться от авторизованного пользователя, который должен иметь разрешение на их выполнение. Если включены Hive и hive.server2.enable.doAs, то запросы будут выполняться через техническую учетную запись, но имперсонировать зарегистрированного пользователя можно через свойство hive.server2.proxy.user." + ], + "If Presto, all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them.<br/>If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.": [ + "Если вы используете Presto, все запросы в Лаборатории SQL будут выполняться от авторизованного пользователя, который должен иметь разрешение на их выполнение. <br/> Если включены Hive и hive.server2.enable.doAs, то запросы будут выполняться через техническую учетную запись, но имперсонировать зарегистрированного пользователя можно через свойство hive.server2.proxy.user." + ], + "If Table Already Exists": ["Если таблица уже существует"], + "If a metric is specified, sorting will be done based on the metric value": [ + "Если мера задана, сортировка будет произведена на основании значений меры" + ], + "If duplicate columns are not overridden, they will be presented as \"X.1, X.2 ...X.x\"": [ + "Если повторяющиеся столбцы не перезаписываются, они будут представлены в формате \"X.0, X.1\"." + ], + "If selected, please set the schemas allowed for csv upload in Extra.": [ + "Если установлено, выберите схемы, в которые разрешена загрузка CSV на вкладке \"Дополнительно\"." + ], + "If table exists do one of the following: Fail (do nothing), Replace (drop and recreate table) or Append (insert data).": [ + "Если таблица уже существует, выберите действие: Ошибка (ничего не делать), Заменить (удалить и воссоздать таблицу) или Добавить (вставить данные)." + ], + "Ignore cache when generating screenshot": [ + "Игнорировать кэш при создании скриншота" + ], + "Ignore null locations": ["Игнорировать пустые локации"], + "Ignore time": ["Игнорировать время"], + "Image (PNG) embedded in email": [ + "Изображение (PNG), встроенное в email" + ], + "Image download failed, please refresh and try again.": [ + "Ошибка скачивания изображения, пожалуйста, обновите и попробуйте заново." + ], + "Impersonate logged in user (Presto, Trino, Drill, Hive, and GSheets)": [ + "Имперсонировать пользователя (Presto, Trino, Drill, Hive, и Google Таблицы)" + ], + "Impersonate the logged on user": ["Имперсонировать пользователя"], + "Import": ["Импорт"], + "Import %s": ["Импортировать %s"], + "Import Dashboard(s)": ["Импортировать дашборд(ы)"], + "Import Dashboards": ["Импортировать дашборды"], + "Import a table definition": [""], + "Import chart failed for an unknown reason": [ + "Не удалось импортировать график по неизвестной причине" + ], + "Import charts": ["Импортировать графики"], + "Import dashboard failed for an unknown reason": [ + "Не удалось импортировать дашборд по неизвестной причине" + ], + "Import dashboards": ["Импортировать дашборды"], + "Import database failed for an unknown reason": [ + "Не удалось импортировать базу данных по неизвестной причине" + ], + "Import database from file": ["Импортировать базу данных из файла"], + "Import dataset failed for an unknown reason": [ + "Не удалось импортировать датасет по неизвестной причине" + ], + "Import datasets": ["Импортировать датасеты"], + "Import queries": ["Импортировать запросы"], + "Import saved query failed for an unknown reason.": [ + "Не удалось импортировать сохраненный запрос по неизвестной причине" + ], + "Important! Select this if the table is not already sorted by entity id, else there is no guarantee that all events for each entity are returned.": [ + "" + ], + "Include Series": [""], + "Include a description that will be sent with your report": [ + "Описание, которое будет отправлено вместе с вашим отчетом" + ], + "Include series name as an axis": [ + "Включить имена категорий в качестве оси" + ], + "Include time": ["Включить время"], + "Incompatible Filters (%d)": ["Несовместимые фильтры (%d)"], + "Index": ["Индекс"], + "Index Column": ["Индесный столбец"], + "Info": ["Личные данные"], + "Inner Radius": ["Внутренний радиус"], + "Inner radius of donut hole": ["Внутренний радиус отверстия для кольца"], + "Input field supports custom rotation. e.g. 30 for 30°": [ + "Поле для ввода поддерживает пользовательские значения, например 30 для 30°" + ], + "Instant filtering": ["Мгновенная Фильтрация"], + "Intensity": ["Насыщенность"], + "Interpret Datetime Format Automatically": [ + "Автоматически интерпретировать формат дата/время" + ], + "Interpret the datetime format automatically": [ + "Автоматически интерпретировать формат дата/время" + ], + "Interval": ["Интервал"], + "Interval End column": ["Столбец с концом интервала"], + "Interval bounds": ["Граница интервала"], + "Interval colors": ["Цвета интервала"], + "Interval start column": ["Столбец с началом интервала"], + "Intervals": ["Интервалы"], + "Invalid JSON": ["Недопустимый формат JSON"], + "Invalid advanced data type: %(advanced_data_type)s": [ + "Невалидный расширенный тип данных: %(advanced_data_type)s" + ], + "Invalid certificate": ["Неверный сертификат"], + "Invalid connection string, a valid string usually follows:\n'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'": [ + "Недопустимая строка для подключения, валидная строка соответствует шаблону: ДРАЙВЕР://ИМЯ-ПОЛЬЗОВАТЕЛЯ:ПАРОЛЬ@ХОСТ/ИМЯ-БАЗЫ-ДАННЫХ" + ], + "Invalid connection string, a valid string usually follows: backend+driver://user:password@database-host/database-name": [ + "Недопустимая строка для подключения, валидная строка соответствует шаблону: драйвер://имя-пользователя:пароль@хост/имя-базы-данных" + ], + "Invalid connection string, a valid string usually follows:'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'<p>Example:'postgresql://user:password@your-postgres-db/database'</p>": [ + "Недопустимая строка для подключения, валидная строка соответствует шаблону:'ДРАЙВЕР://ИМЯ-ПОЛЬЗОВАТЕЛЯ:ПАРОЛЬ@ХОСТ/ИМЯ-БАЗЫ-ДАННЫХ'<p>Пример:'postgresql://user:password@postgres-db/database'</p>" + ], + "Invalid cron expression": ["Недопустимое CRON выражение"], + "Invalid cumulative operator: %(operator)s": [""], + "Invalid date/timestamp format": ["Недопустимый формат дата/время"], + "Invalid filter configuration, please select a column": [ + "Неверная конфигурация фильтра, пожалуйста, выберите столбец" + ], + "Invalid filter operation type: %(op)s": [""], + "Invalid geodetic string": [""], + "Invalid geohash string": [""], + "Invalid input": ["Недопустимые входные данные"], + "Invalid lat/long configuration.": [ + "Неверная конфигурация широты и долготы." + ], + "Invalid longitude/latitude": ["Недопустимые долгота/широта"], + "Invalid metric object: %(metric)s": [""], + "Invalid numpy function: %(operator)s": [ + "Недопустимая numpy функция: %(operator)s" + ], + "Invalid options for %(rolling_type)s: %(options)s": [ + "Недопустимые настройки для %(rolling_type)s: %(options)s" + ], + "Invalid permalink key": [""], + "Invalid result type: %(result_type)s": [ + "Недопустимый тип ответа: %(result_type)s" + ], + "Invalid rolling_type: %(type)s": [""], + "Invalid spatial point encountered: %s": [""], + "Invalid state.": [""], + "Invalid tab ids: %s(tab_ids)": [""], + "Inverse selection": ["Выбрать противоположные значения"], + "Invert current page": [""], + "Is certified": ["Одобрено"], + "Is dimension": ["Является измерением"], + "Is favorite": ["В избранном"], + "Is filterable": ["Фильтруемый"], + "Is temporal": ["Содержит дату/время"], + "Issue 1000 - The dataset is too large to query.": [ + "Ошибка 1000 - Источник данных слишком велик для запроса." + ], + "Issue 1001 - The database is under an unusual load.": [ + "Ошибка 1001 - Нетипичная загрузка базы данных." + ], + "It’s not recommended to truncate axis in Bar chart.": [ + "Не рекомендуется урезать интервал оси в столбчатой диаграмме" + ], + "JAN": ["ЯНВ"], + "JSON": ["JSON"], + "JSON Metadata": ["JSON Метаданные"], + "JSON metadata": ["JSON метаданные"], + "JSON metadata is invalid!": ["JSON метаданные не валидны!"], + "JSON string containing additional connection configuration. This is used to provide connection information for systems like Hive, Presto and BigQuery which do not conform to the username:password syntax normally used by SQLAlchemy.": [ + "JSON строка, содержащая дополнительную информацию о соединении. Это используется для указания информации о соединении с такими системами как Hive, Presto и BigQuery, которые не укладываются в шаблон \"пользователь:пароль\", который обычно используется в SQLAlchemy." + ], + "JUL": ["ИЮЛ"], + "JUN": ["ИЮН"], "January": ["Январь"], - "February": ["Февраль"], - "March": ["Март"], - "April": ["Апрель"], - "May": ["Май"], - "June": ["Июнь"], - "July": ["Июль"], - "August": ["Август"], - "September": ["Сентябрь"], - "October": ["Октябрь"], - "November": ["Ноябрь"], - "December": ["Декабрь"], - "SUN": ["ВС"], - "MON": ["ПН"], - "TUE": ["ВТ"], - "WED": ["СР"], - "THU": ["ЧТ"], - "FRI": ["ПТ"], - "SAT": ["СБ"], - "JAN": ["ЯНВ"], - "FEB": ["ФЕВ"], + "Javascript data interceptor": ["Javascript редактор данных"], + "Javascript onClick href": ["Javascript onClick href"], + "Javascript tooltip generator": [ + "Javascript генератор всплывающих подсказок" + ], + "Jinja templating": ["Шаблонизацию Jinja."], + "Json list of the column names that should be read": [ + "Список столбцов в формате JSON из файла, которые будут использованы." + ], + "Json list of the column names that should be read. If not None, only these columns will be read from the file.": [ + "Список столбцов в формате JSON из файла, которые будут использованы. Пример: [\"id\", \"name\", \"gender\", \"age\"]. Если в данном поле указаны названия столбцов, из файла будут загружены только указанные столбцы." + ], + "Json list of the values that should be treated as null. Examples: [\"\"] for empty strings, [\"None\", \"N/A\"], [\"nan\", \"null\"]. Warning: Hive database supports only a single value": [ + "Список JSON значений, которые следует рассматривать как нулевые. Примеры: [\"\"] для пустых строк, [\"None\", \"N/A\"], [\"nan\", \"null\"]. Предупреждение: База данных Hive поддерживает только одно значение." + ], + "Json list of the values that should be treated as null. Examples: [\"\"], [\"None\", \"N/A\"], [\"nan\", \"null\"]. Warning: Hive database supports only single value. Use [\"\"] for empty string.": [ + "Список JSON значений, которые следует рассматривать как нулевые. Примеры: [\"\"], [\"None\", \"N/A\"], [\"nan\", \"null\"]. Предупреждение: База данных Hive поддерживает только одно значение. Используйте [\"\"] для пустой строки." + ], + "July": ["Июль"], + "June": ["Июнь"], + "KPI": ["KPI"], + "Keep control settings?": ["Оставить прежние настройки?"], + "Keep editing": ["Продолжить редактирование"], + "Key": ["Ключ"], + "Kilometers": ["Километры"], + "LIMIT": ["ОГРАНИЧЕНИЕ"], + "Label": ["Метка"], + "Label Line": ["Линия метки"], + "Label Type": ["Тип метки"], + "Label already exists": ["Метка уже существует"], + "Label for your query": ["Метка для вашего запроса"], + "Label position": ["Положение метки"], + "Label threshold": ["Порог метки"], + "Labelling": ["Маркировка"], + "Labels": ["Метки"], + "Labels for the marker lines": ["Метки для линий маркера"], + "Labels for the markers": ["Метки для маркеров"], + "Labels for the ranges": ["Метки для диапазонов"], + "Large": ["Большой"], + "Last": ["Последний"], + "Last Changed": ["Дата изменения"], + "Last Modified": ["Дата изменения"], + "Last Updated %s": ["Дата изменения %s"], + "Last Updated %s by %s": ["Изменено %s пользователем %s"], + "Last available value seen on %s": ["Последнее доступное значение: %s"], + "Last modified": ["Последнее изменение"], + "Last modified by %s": ["Автор изменений %s"], + "Last run": ["Последнее изменение"], + "Latitude": ["Широта"], + "Latitude of default viewport": ["Широта для области просмотра"], + "Layer configuration": ["Настройки слоя"], + "Layout": ["Оформление"], + "Layout elements": ["Оформление"], + "Layout type of graph": [""], + "Layout type of tree": [""], + "Leaf nodes that represent fewer than this number of events will be initially hidden in the visualization": [ + "" + ], + "Least recently modified": ["Измененные давно"], + "Left": ["Слева"], + "Left Axis Format": ["Формат левой оси"], + "Left Axis Metric": ["Мера левой оси"], + "Left Axis chart(s)": ["График(и) по левой оси"], + "Left Margin": ["Левый отступ"], + "Left margin, in pixels, allowing for more room for axis labels": [ + "Левый отступ (в пикселях), дает больше пространства меткам оси" + ], + "Left to Right": ["Слева направо"], + "Left value": ["Левое значение"], + "Legacy": ["Устарел"], + "Legend": ["Легенда"], + "Legend Format": ["Формат легенды"], + "Legend Orientation": ["Ориентация легенды"], + "Legend Position": ["Расположение легенды"], + "Legend type": ["Тип легенды"], + "Less than (<)": [""], + "Lift percent precision": [""], + "Light": ["Светлый"], + "Light mode": ["Светлый режим"], + "Like": [""], + "Limit reached": ["Достигнут предел"], + "Limit selector values": [""], + "Limit type": ["Тип ограничения"], + "Limiting rows may result in incomplete data and misleading charts. Consider filtering or grouping source/target names instead.": [ + "" + ], + "Limits the number of cells that get retrieved.": [ + "Ограничивает количество извлекаемых ячеек" + ], + "Limits the number of rows that get displayed.": [ + "Ограничивает количество отображаемых строк" + ], + "Limits the number of series that get displayed. A joined subquery (or an extra phase where subqueries are not supported) is applied to limit the number of series that get fetched and rendered. This feature is useful when grouping by high cardinality column(s) though does increase the query complexity and cost.": [ + "Ограничивает количество отображаемых категорий. Эта опция полезна для столбцов с большим количеством уникальных значений, т.к. уменьшает сложность и стоимость запроса." + ], + "Line": ["Линейный"], + "Line Chart": ["Линейный график"], + "Line Chart (legacy)": ["Линейный график (устарело)"], + "Line Style": ["Тип линии"], + "Line chart is used to visualize measurements taken over a given category. Line chart is a type of chart which displays information as a series of data points connected by straight line segments. It is a basic type of chart common in many fields.": [ + "Линейная диаграмма используется для визуализации показателей, полученных в рамках одной категории. Линейная диаграмма - это тип диаграммы, который отображает информацию в виде ряда точек данных, соединенных прямыми отрезками. Это базовый тип диаграммы, распространенный во многих областях." + ], + "Line interpolation as defined by d3.js": [ + "Линейная интерполяция, определенная в d3.js" + ], + "Line width": ["Толщина линии"], + "Linear Color Scheme": ["Линейная цветовая схема"], + "Linear color scheme": ["Линейная цветовая схема"], + "Linear interpolation": ["Линейная интерполяция"], + "Link Copied!": ["Ссылка скопирована"], + "List Saved Query": [""], + "List Unique Values": ["Список уникальных значений"], + "List of extra columns made available in Javascript functions": [ + "Список дополнительных столбцов, доступных в функциях Javascript" + ], + "List of n+1 values for bucketing metric into n buckets.": [""], + "List of values to mark with lines": [ + "Список числовых значений для отображения в виде линий на графике. Например, 10,20,30" + ], + "List of values to mark with triangles": [ + "Список числовых значений для отображения в виде треугольников на графике. Например, 10,20,30" + ], + "List updated": ["Список обновлен"], + "Live CSS editor": ["Редактор CSS"], + "Live render": ["Мгновенная отрисовка"], + "Load a CSS template": ["Загрузить CSS шаблон"], + "Loaded data cached": ["Данные загружены в кэш"], + "Loaded from cache": ["Загружено из кэша"], + "Loading": ["Загрузка"], + "Loading...": ["Загрузка..."], + "Log Scale": ["Логарифмическая шкала"], + "Log retention": ["Хранение журнала"], + "Logarithmic axis": ["Логарифмическая ось"], + "Logarithmic scale on primary y-axis": [ + "Логарифмическая шкала для главной оси Y" + ], + "Logarithmic scale on secondary y-axis": [ + "Логарифмическая шкала для вторичной оси Y" + ], + "Logarithmic y-axis": ["Логарифмическая ось Y"], + "Login": ["Вход в систему"], + "Login with": ["Войти при помощи"], + "Logout": ["Выход из системы"], + "Logs": ["Записи"], + "Long dashed": ["Длинный штрих"], + "Longitude": ["Долгота"], + "Longitude & Latitude": ["Долгота и Широта"], + "Longitude & Latitude columns": ["Долгота и Широта"], + "Longitude and Latitude": ["Долгота и Широта"], + "Longitude of default viewport": ["Долгота для области просмотра"], "MAR": ["МАР"], - "APR": ["АПР"], "MAY": ["МАЙ"], - "JUN": ["ИЮН"], - "JUL": ["ИЮЛ"], - "AUG": ["АВГ"], - "SEP": ["СЕН"], - "OCT": ["ОКТ"], + "MON": ["ПН"], + "Main Datetime Column": ["Основной столбец с временем"], + "Make sure that the controls are configured properly and the datasource contains data for the selected time range": [ + "Убедитесь, что настройки графика верно сконфигурированы и источник данных содержит данные для выбранного временного интервала." + ], + "Malformed request. slice_id or table_name and db_name arguments are expected": [ + "Некорректный запрос. Ожидаются аргументы slice_id или table_name и db_name" + ], + "Manage": ["Управление"], + "Manage email report": ["Управление рассылкой по почте"], + "Manage your databases": ["Управляйте своими базами данных"], + "Mandatory": ["Обязательно"], + "Mangle Duplicate Columns": ["Управление повторяющимися столбцами"], + "Manually set min/max values for the y-axis.": [ + "Вручную задать мин./макс. значения для оси Y" + ], + "Map": ["Карта"], + "Map Style": ["Стиль карты"], + "MapBox": ["Mapbox"], + "Mapbox": ["Mapbox"], + "March": ["Март"], + "Margin": ["Отступ"], + "Mark a column as temporal in \"Edit datasource\" modal": [ + "Присвойте столбцу формат даты/времени в настройках датасета" + ], + "Marker": ["Маркер"], + "Marker Size": ["Размер маркера"], + "Marker labels": ["Метки маркера"], + "Marker line labels": ["Метки линий маркера"], + "Marker lines": ["Линии маркеров"], + "Marker size": ["Размер маркера"], + "Markers": ["Маркеры"], + "Markup type": ["Тип разметки"], + "Max": ["Максимум"], + "Max Bubble Size": ["Максимальный размер пузыря"], + "Max Events": ["Лимит событий"], + "Maximum": ["Максимум"], + "Maximum Font Size": ["Максимальный размер шрифта"], + "Maximum Radius": ["Максимальный радиус"], + "Maximum value on the gauge axis": ["Максимальное значение индикатора"], + "Maxium radius size of the circle, in pixels. As the zoom level changes, this insures that the circle respects this maximum radius.": [ + "Максимальный размер радиуса окружности (в пикселях). При изменении уровня масштабирования это гарантирует, что окружность соответствует этому максимальному радиусу" + ], + "May": ["Май"], + "Mean of values over specified period": [ + "Среднее значений за указанный период" + ], + "Mean values": ["Средние значения"], + "Median": ["Медиана"], + "Median edge width, the thickest edge will be 4 times thicker than the thinnest.": [ + "Медианная толщина ребра, самое толстое ребро будет в 4 раза толще самой тонкой." + ], + "Median node size, the largest node will be 4 times larger than the smallest": [ + "Медианный размер вершины, самая большая вершина будет в 4 раза больше самой маленькой." + ], + "Median values": ["Медианные значения"], + "Medium": ["Средний"], + "Menu actions trigger": [""], + "Message content": ["Содержимое сообщения"], + "Metadata": ["Метаданные"], + "Metadata Parameters": ["Параметры метаданных"], + "Metadata has been synced": ["Метаданные синхронизированы"], + "Method": ["Метод"], + "Metric": ["Мера"], + "Metric '%(metric)s' does not exist": ["Мера '%(metric)s' не существует"], + "Metric ascending": ["Мера по возрастанию"], + "Metric assigned to the [X] axis": ["Показатель, отраженный на оси X"], + "Metric assigned to the [Y] axis": ["Показатель, отраженный на оси Y"], + "Metric change in value from `since` to `until`": [ + "Изменение меры с `до` до `после`" + ], + "Metric descending": ["Мера по убыванию"], + "Metric factor change from `since` to `until`": [""], + "Metric for node values": ["Мера для значений вершин"], + "Metric name": ["Имя меры"], + "Metric name [%s] is duplicated": ["Дубль имени меры [%s]"], + "Metric percent change in value from `since` to `until`": [ + "Процентное изменение меры с `до` до `после`" + ], + "Metric that defines the size of the bubble": [ + "Показатель, определяющий размер пузяря" + ], + "Metric to display bottom title": [ + "Мера для отображения нижнего заголовка" + ], + "Metric to sort the results by": [ + "Показатель, по которому сортировать результаты" + ], + "Metric used as a weight for the grid's coloring": [ + "Мера, используемая как вес для раскрашивания сетки" + ], + "Metric used to calculate bubble size": [ + "Мера, используемая для расчета размера пузыря" + ], + "Metric used to control height": [ + "Мера, используемая для регулирования высоты" + ], + "Metric used to define how the top series are sorted if a series or cell limit is present. If undefined reverts to the first metric (where appropriate).": [ + "Мера, используемая для определения того, как сортируются верхние категории, если присутствует ограничение по категории или ячейке. Если не определено, возвращается к первой мере (где это уместно)." + ], + "Metric used to define how the top series are sorted if a series or row limit is present. If undefined reverts to the first metric (where appropriate).": [ + "Мера, используемая для определения того, как сортируются верхние категории, если присутствует ограничение по категории или строке. Если не определено, возвращается к первой мере (где это уместно)." + ], + "Metric used to order the limit if a series limit is present. If undefined reverts to the first metric (where appropriate).": [ + "" + ], + "Metrics": ["Меры"], + "Metrics for which percentage of total are to be displayed. Calculated from only data within the row limit.": [ + "Меры, для которых должен отображаться процент от общего числа. Вычисляется только из данных в пределах ограничения по строкам." + ], + "Middle": ["Середина"], + "Midnight": ["Полночь"], + "Miles": ["Мили"], + "Min": ["Минимум"], + "Min Periods": ["Минимальный период"], + "Min Width": ["Минимальная ширина"], + "Min periods": ["Минимальный период"], + "Min/max (no outliers)": ["Мин/макс (без выбросов)"], + "Mine": ["Мои"], + "Minimum": ["Минимум"], + "Minimum Font Size": ["Минимальный размер шрифта"], + "Minimum Radius": ["Минимальный радиус"], + "Minimum leaf node event count": [""], + "Minimum radius size of the circle, in pixels. As the zoom level changes, this insures that the circle respects this minimum radius.": [ + "Минимальный размер радиуса окружности (в пикселях). При изменении масштаба это гарантирует, что окружность соответствует этому минимальному радиусу." + ], + "Minimum threshold in percentage points for showing labels.": [ + "Минимальный порог в процентных пунктах для отображения меток" + ], + "Minimum value for label to be displayed on graph.": [ + "Минимальное значение метки для отображения на графике." + ], + "Minimum value on the gauge axis": ["Минимальное значение индикатора"], + "Minor Split Line": ["Разметка полотна линиями"], + "Minute": ["Минута"], + "Minutes %s": ["Минут %s"], + "Missing URL parameters": ["Пропущенные параметры URL"], + "Missing dataset": ["Отсутствующий датасет"], + "Mixed Chart": ["Смешанный график"], + "Mixed Time-Series": ["Смешанная диаграмма временных рядов"], + "Modified": ["Изменено"], + "Modified %s": ["Изменено %s"], + "Modified by": ["Кем изменено"], + "Modified columns: %s": ["Изменённые столбцы: %s"], + "Monday": ["Понедельник"], + "Month": ["Месяц"], + "Months %s": ["Месяцев %s"], + "More": ["Подробнее"], + "Move only": ["Только перемещение"], + "Moves the given set of dates by a specified interval.": [""], + "Multi-Dimensions": ["Многомерный"], + "Multi-Layers": ["Многослойный"], + "Multi-Levels": ["Многоуровневый"], + "Multi-Variables": ["Несколько переменных"], + "Multiple": ["Несколько"], + "Multiple Line Charts": ["Несколько линейных диаграмм"], + "Multiple file extensions are not allowed for columnar uploads. Please make sure all files are of the same extension.": [ + "Несколько расширений файлов столбчатого формата не разрешены к загрузке. Пожалуйста, убедитесь, что все файлы имеют одинаковое расширение." + ], + "Multiple filtering": ["Множественная фильтрация"], + "Multiple formats accepted, look the geopy.points Python library for more details": [ + "Для уточнения форматов и получения более подробной информации, посмотрите Python-библиотеку geopy.points" + ], + "Multiple selections allowed, otherwise filter is limited to a single value": [ + "Разрешён множественный выбор, иначе можно выбрать только одно значение фильтра" + ], + "Multiplier": ["Мультипликатор"], + "Must be unique": ["Должно быть уникальным"], + "Must choose either a chart or a dashboard": [ + "Выберите график или дашборд" + ], + "Must have a [Group By] column to have 'count' as the [Label]": [""], + "Must have at least one numeric column specified": [ + "Должен быть указан хотя бы один числовой столбец" + ], + "Must specify a value for filters with comparison operators": [ + "Необходимо указать значение для фильтров с операторами сравнения" + ], + "My beautiful colors": ["Мои красивые цвета"], + "My column": ["Мой столбец"], + "My metric": ["Моя мера"], + "N/A": ["Пусто"], + "NOT GROUPED BY": [""], "NOV": ["НОЯ"], - "DEC": ["ДЕК"], - "OK": [""], - "Click to see difference": ["Нажмите, чтобы увидеть разницу"], - "Altered": ["Изменения"], - "Chart changes": ["Изменения не сохранены"], - "Superset chart": ["График Superset"], - "Check out this chart in dashboard:": [ - "Посмотреть этот график в дашборде:" + "NOW": ["СЕЙЧАС"], + "NUMERIC": ["Числовой (NUMERIC/DECIMAL)"], + "Name": ["Имя"], + "Name is required": ["Имя обязательно"], + "Name must be unique": ["Имя должно быть уникальным"], + "Name of table to be created from columnar data.": [ + "Имя таблицы, созданной из файла столбчатого формата." + ], + "Name of table to be created from excel data.": [ + "Имя таблицы, созданной из Excel файла." + ], + "Name of table to be created with CSV file": [ + "Имя таблицы, созданной из CSV файла." + ], + "Name of the column containing the id of the parent node": [ + "Имя столбца, содержащее id родительской вершины" + ], + "Name of the id column": ["Имя столбца id"], + "Name of the source nodes": ["Имя исходных вершин"], + "Name of the table that exists in the source database": [ + "Имя таблицы, которая существует в базе данных" + ], + "Name of the target nodes": ["Имя конечных вершин"], + "Name your database": ["Дайте имя базе данных"], + "Need help? Learn how to connect your database": [ + "Нужна помощь? Узнайте, как подключаться к вашей базе данных" + ], + "Need help? Learn more about": ["Нужна помощь? Узнайте больше о"], + "Network error": ["Ошибка сети"], + "Network error.": ["Ошибка сети."], + "New chart": ["Новый график"], + "New columns added: %s": ["Добавленные столбцы: %s"], + "New dataset": ["Новый датасет"], + "New dataset name": ["Новое имя датасета"], + "New filter set": ["Новый набор фильтров"], + "New tab": ["Новая вкладка"], + "New tab (Ctrl + q)": ["Новая вкладка (CTRL + Q)"], + "New tab (Ctrl + t)": ["Новая вкладка (CTRL + T)"], + "Next": ["Следующий"], + "Nightingale Rose Chart": ["Диаграмма Найтингейл"], + "No": ["Нет"], + "No %s yet": ["Пока нет %s"], + "No Access!": ["Нет доступа!"], + "No Data": ["Нет данных"], + "No Results": ["Нет результатов"], + "No annotation layers": ["Нет слоев аннотаций"], + "No annotation layers yet": ["Пока нет слоев аннотаций"], + "No annotation yet": ["Пока нет аннотаций"], + "No applied filters": ["Фильтры не применены"], + "No available filters.": ["Нет доступных фильтров."], + "No charts": ["Нет графиков"], + "No columns": ["Нет столбцов"], + "No compatible columns found": ["Не найдено подходящих столбцов"], + "No dashboards": ["Нет дашбордов"], + "No data": ["Нет данных"], + "No data after filtering or data is NULL for the latest time record": [ + "Нет данных после фильтрации или данные отсутствуют за последний отрезок времени" + ], + "No data in file": ["В файле нет данных"], + "No database tables found": ["Не найдено таблиц в базе данных"], + "No databases match your search": [ + "Нет баз данных, удовлетворяющих вашему поиску" + ], + "No description available.": ["Описание отсутствует."], + "No favorite charts yet, go click on stars!": [ + "Пока нет избранных графиков, для добавления в избранное нажмите на звездочку рядом с графиком" + ], + "No favorite dashboards yet, go click on stars!": [ + "Пока нет избранных дашбордов, для добавления в избранное нажмите на звездочку рядом с дашбордом" + ], + "No filter": ["Без фильтрации"], + "No filter is selected.": ["Не выбраны фильтры."], + "No filters": ["Нет фильтров"], + "No filters are currently added": ["Не применено ни одного фильтра"], + "No filters are currently added to this dashboard.": [ + "Не применено ни одного фильтра к данному дашборду." + ], + "No form settings were maintained": [ + "Конфигурация графика не сохранилась" + ], + "No of Bins": ["Количество столбцов"], + "No records found": ["Записи не найдены"], + "No results": ["Нет результатов"], + "No results found": ["Записи не найдены"], + "No results match your filter criteria": [ + "Не найдено результатов по вашим критериям" + ], + "No results were returned for this query": [ + "Не было получено данных по этому запросу" + ], + "No results were returned for this query. If you expected results to be returned, ensure any filters are configured properly and the datasource contains data for the selected time range.": [ + "По этому запросу не было возвращено данных. Если вы ожидали увидеть результаты, убедитесь, что все фильтры настроены правильно и источник данных содержит записи для заданного временного интервала." + ], + "No rows were returned for this dataset": [ + "Не было получено данных для этого датасета" + ], + "No samples were returned for this dataset": [ + "Не было получено данных для этого датасета" + ], + "No saved expressions found": ["Не найдено сохраненных выражений"], + "No saved metrics found": ["Не найдено сохраненных мер"], + "No stored results found, you need to re-run your query": [ + "Не найдены сохраненные результаты, необходимо повторно выполнить запрос" + ], + "No such column found. To filter on a metric, try the Custom SQL tab.": [ + "Такой столбец не найден. Чтобы фильтровать по мере, попробуйте использовать вкладку Свой SQL." + ], + "No temporal columns found": ["Столбцы формата дата/время не найдены"], + "No time columns": ["Нет столбцов формата дата/время"], + "No validator found (configured for the engine)": [ + "Не найден валидатор (сконфигурированный для драйвера)" + ], + "No validator named {} found (configured for the {} engine)": [ + "Не найден валидатор с именем {} (сконфигурированный для драйвера {})" + ], + "Node label position": ["Расположение метки вершины"], + "Node select mode": ["Режим выбора вершин"], + "Node size": ["Размер вершины"], + "None": ["Пусто"], + "None -> Arrow": ["Ничего -> Стрелка"], + "None -> None": ["Ничего -> Ничего"], + "Normal": ["Обычный"], + "Normalize Across": [""], + "Normalized": ["Нормализовать"], + "Not Time Series": ["Не временные ряды"], + "Not added to any dashboard": ["Не добавлен ни в один дашборд"], + "Not available": ["Не доступно"], + "Not equal to (≠)": ["Не равно (≠)"], + "Not null": ["Не пусто"], + "Not triggered": ["Условие не выполнялось"], + "Not up to date": ["Не актуально"], + "Nothing triggered": ["Не срабатывало"], + "Notification method": ["Способ уведомления"], + "November": ["Ноябрь"], + "Now": ["Сейчас"], + "Null Values": ["Пустые значения"], + "Null imputation": ["Пустые значения"], + "Null or Empty": ["Null или Пусто"], + "Null values": ["Пустые значения"], + "Number Format": ["Числовой формат"], + "Number bounds used for color encoding from red to blue.\n Reverse the numbers for blue to red. To get pure red or blue,\n you can enter either only min or max.": [ + "" + ], + "Number format": ["Числовой формат"], + "Number format string": ["Числовой формат"], + "Number of buckets to group data": [""], + "Number of decimal digits to round numbers to": [ + "Кол-во десятичных разрядов для округления числа" + ], + "Number of decimal places with which to display lift values": [""], + "Number of decimal places with which to display p-values": [""], + "Number of periods to compare against": [ + "Количество периодов для сравнения" + ], + "Number of periods to ratio against": [ + "Количество периодов для сравнения" + ], + "Number of rows of file to read": ["Количество строк файла для чтения"], + "Number of rows of file to read.": ["Количество строк файла для чтения."], + "Number of rows to skip at start of file": [ + "Количество строк для пропуска в начале файла" + ], + "Number of rows to skip at start of file.": [ + "Количество строк для пропуска в начале файла." + ], + "Number of split segments on the axis": [ + "Количество разделенных сегментов на индикаторе" + ], + "Number of steps to take between ticks when displaying the X scale": [""], + "Number of steps to take between ticks when displaying the Y scale": [""], + "Numerical range": ["Числовой диапазон"], + "OCT": ["ОКТ"], + "OK": ["ОК"], + "OVERWRITE": ["ПЕРЕЗАПИСАТЬ"], + "October": ["Октябрь"], + "Offline": ["Оффлайн"], + "Offset": ["Смещение"], + "On Grace": ["На перерыве"], + "One or many columns to group by. High cardinality groupings should include a series limit to limit the number of fetched and rendered series.": [ + "Один или несколько столбцов для группировки. Столбцы с множеством уникальных значений должны включать порог количества категорий для снижения нагрузку на базу данных и на ускорения отображения графика." + ], + "One or many columns to group by. High cardinality groupings should include a sort by metric and series limit to limit the number of fetched and rendered series.": [ + "Один или несколько столбцов для группировки. Столбцы с множеством уникальных значений должны включать показатель для сортировки и порог количества значений для снижения нагрузку на базу данных и на ускорения отображения графика." + ], + "One or many columns to pivot as columns": [ + "Один или несколько столбцов, используемых в роли столбцов в сводной таблице" + ], + "One or many controls to group by. If grouping, latitude and longitude columns must be present.": [ + "" + ], + "One or many metrics to display": [ + "Выберите одну или несколько мер для отображения" + ], + "One or more columns already exist": [ + "Один или несколько столбцов уже существуют" + ], + "One or more columns are duplicated": [ + "Один или несколько столбцов дублируются" + ], + "One or more columns do not exist": [ + "Один или несколько столбцов не существуют" + ], + "One or more metrics already exist": [ + "Одна или несколько мер уже существуют" + ], + "One or more metrics are duplicated": [ + "Одна или несколько мер дублируются" + ], + "One or more metrics do not exist": [ + "Одна или несколько мер не существуют" + ], + "One or more parameters needed to configure a database are missing.": [ + "Один или несколько параметров, необходимых для настройки базы данных, отсутствуют" + ], + "One or more parameters specified in the query are malformatted.": [ + "Один или несколько параметров, указанных в запросе, неверно отформатированы" + ], + "One or more parameters specified in the query are missing.": [ + "Один или несколько параметров, указанных в запросе, отсутствуют" + ], + "One or more required fields are missing in the request. Please try again, and if the problem persists conctact your administrator.": [ + "" + ], + "One ore more annotation layers failed loading.": [ + "Один или несколько слоев аннотации не удалось загрузить." + ], + "Only SELECT statements are allowed against this database.": [ + "Только SELECT запросы доступны для этой базы данных." + ], + "Only Total": ["Только общий итог"], + "Only `SELECT` statements are allowed": [ + "Доступны только SELECT запросы" + ], + "Only selected panels will be affected by this filter": [ + "Фильтр будет применён только к выбранным панелям" + ], + "Only show the total value on the stacked chart, and not show on the selected category": [ + "Показывать только общий итог для столбцов с накоплением, и не показывать промежуточные итоги для каждой категории внутри столбца." + ], + "Only single queries supported": [ + "Поддерживаются только одиночные запросы" + ], + "Only the following file extensions are allowed: %(allowed_extensions)s": [ + "Доступные расширения файлов: %(allowed_extensions)s" + ], + "Oops! An error occurred!": ["Произошла ошибка!"], + "Opacity": ["Прозрачность"], + "Opacity of Area Chart. Also applies to confidence band.": [""], + "Opacity of all clusters, points, and labels. Between 0 and 1.": [ + "Непрозрачность всех кластеров, точек и меток. Между 0 и 1." + ], + "Opacity of area chart.": ["Непрозрачность диаграммы областей"], + "Opacity, expects values between 0 and 100": [ + "Непрозрачность, принимаются значения от 0 до 100" + ], + "Open Datasource tab": ["Открыть вкладку источника данных"], + "Open in SQL Lab": ["Открыть в SQL редакторе"], + "Open query in SQL Lab": ["Открыть в SQL редакторе"], + "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.": [ + "Работа с базой данных в асинхронном режиме означает, что запросы исполняются на удалённых воркерах, а не на веб-сервере Superset. Это подразумевает, что у вас есть установка с воркерами Celery. Обратитесь к документации по настройке за дополнительной информацией." + ], + "Operator": ["Оператор"], + "Operator undefined for aggregator: %(name)s": [ + "Оператор не определен для агрегатора: %(name)s" + ], + "Optional CA_BUNDLE contents to validate HTTPS requests. Only available on certain database engines.": [ + "Необязательное содержимое CA_BUNDLE для валидации HTTPS запросов. Доступно только в определенных драйверах баз данных" + ], + "Optional d3 date format string": ["Формат временной строки"], + "Optional d3 number format string": ["Формат числовой строки"], + "Optional name of the data column.": [ + "Необязательное имя столбца данныхэ" + ], + "Optional time column if time range should apply to another column than the default time column": [ + "" + ], + "Optional warning about use of this metric": [ + "Необязательное предупреждение об использовании этой меры" + ], + "Optionally add a detailed description": [""], + "Options": ["Опции"], + "Or choose from a list of other databases we support:": [ + "Или выберите из списка других поддерживаемых баз данных:" + ], + "Order by entity id": [""], + "Order results by selected columns": [ + "Упорядочить результаты по выбранным столбцам" + ], + "Ordering": ["Упорядочивание"], + "Orientation": ["Ориентация"], + "Orientation of bar chart": ["Ориентация диаграммы"], + "Orientation of tree": ["Ориентация дерева"], + "Original": ["Исходные данные"], + "Original table column order": [ + "Расположение столбцов как в исходной таблице" + ], + "Original value": ["Исходное значение"], + "Other": ["Прочее"], + "Outdoors": ["Туристический режим"], + "Outer Radius": ["Внешний радиус"], + "Outer edge of Pie chart": ["Внешний радиус круговой диаграммы"], + "Overlap": ["Перекрывание"], + "Overlay one or more timeseries from a relative time period. Expects relative time deltas in natural language (example: 24 hours, 7 days, 52 weeks, 365 days). Free text is supported.": [ + "Наложение одной или нескольких временных рядов из относительного периода времени." + ], + "Overlays a hexagonal grid on a map, and aggregates data within the boundary of each cell.": [ + "" + ], + "Override time grain": ["Переопределить единицу времени"], + "Override time range": ["Переопределить временной интервал"], + "Overwrite": ["Перезаписать"], + "Overwrite & Explore": ["Перезаписать и исследовать"], + "Overwrite Dashboard [%s]": ["Перезаписать дашборд [%s]"], + "Overwrite Duplicate Columns": ["Перезаписать повторяющиеся столбцы"], + "Overwrite existing": ["Перезаписать существующий"], + "Overwrite text in the editor with a query on this table": [ + "Вставить этот запрос в редактор SQL" + ], + "Owner": ["Владелец"], + "Owners": ["Владельцы"], + "Owners are invalid": ["Неверный список владельцев"], + "Owners is a list of users who can alter the dashboard.": [ + "Владельцы – это список пользователей, которые могут изменять дашборд." + ], + "Owners is a list of users who can alter the dashboard. Searchable by name or username.": [ + "Владельцы – это список пользователей, которые могут изменять дашборд. Можно искать по имени или никнейму." + ], + "Page length": ["Размер страницы"], + "Paired t-test Table": ["Таблица парного t-теста"], + "Pandas resample method": [ + "Метод ресемплирования данных библиотеки Pandas" + ], + "Pandas resample rule": [ + "Правило ресемплирования данных библиотеки Pandas" + ], + "Parallel Coordinates": [""], + "Parameter error": ["Ошибка параметра"], + "Parameters": ["Параметры"], + "Parameters ": ["Параметры "], + "Parameters related to the view and perspective on the map": [""], + "Parent": ["Родитель"], + "Parse Dates": ["Парсинг дат"], + "Part of a Whole": ["Покомпонентное сравнение"], + "Partition Limit": ["Количество разбиений"], + "Partition Threshold": [""], + "Partitions whose height to parent height proportions are below this value are pruned": [ + "" + ], + "Password": ["Пароль"], + "Paste Private Key here": [""], + "Paste the shareable Google Sheet URL here": [""], + "Pattern": ["Паттерн"], + "Percent Change": ["Процентное изменение"], + "Percentage": ["Процентная доля"], + "Percentage change": ["Процентное изменение"], + "Percentage metrics": ["Процентные меры"], + "Percentage threshold": ["Процентный порог"], + "Percentages": ["Проценты"], + "Performance": ["Производительность"], + "Period average": ["Среднее за период"], + "Periods": ["Периоды"], + "Periods must be a whole number": ["Периоды должны быть целым числом"], + "Person or group that has certified this chart.": [ + "Лицо или группа, которые утвердили этот график" + ], + "Person or group that has certified this dashboard.": [ + "Лицо или группа, которые утвердили этот дашборд" + ], + "Person or group that has certified this metric": [ + "Лицо или группа, которые утвердили этот показатель" + ], + "Physical": ["Физический"], + "Physical (table or view)": ["Физический (таблица или представление)"], + "Physical dataset": ["Физический датасет"], + "Pick a dimension from which categorical colors are defined": [ + "Выберите измерение, на основе которого определяются категориальные цвета" + ], + "Pick a granularity in the Time section or uncheck 'Include Time'": [ + "Выберите степень детализации в разделе Время или снимите флажок \"Включить время\"." + ], + "Pick a metric for left axis!": ["Выберите меру для левой оси"], + "Pick a metric for right axis!": ["Выберите меру для правой оси"], + "Pick a metric for x, y and size": ["Выберите меру для x, y и размера"], + "Pick a metric to display": ["Выберите меру для отображения"], + "Pick a metric!": ["Выберите меру!"], + "Pick a name to help you identify this database.": [ + "Выберите имя для базы данных." + ], + "Pick a nickname for how the database will display in Superset.": [ + "Выберите имя для базы данных, которое будет отображаться в Суперсете." + ], + "Pick a set of deck.gl charts to layer on top of one another": [""], + "Pick a time granularity for your time series": [ + "Выберите временную детализацию для вашего временного ряда" + ], + "Pick a title for you annotation.": [ + "Выберите название для вашей аннотации" + ], + "Pick at least one field for [Series]": [""], + "Pick at least one metric": ["Выберите хотя бы одну меру"], + "Pick exactly 2 columns as [Source / Target]": [""], + "Pick one or more columns that should be shown in the annotation. If you don't select a column all of them will be shown.": [ + "Выберите один или несколько столбцов, которые должны отображаться в аннотации. Если вы не выберите столбец, все столбцы будут отображены." + ], + "Pick your favorite markup language": [ + "Выберите свой любимый язык разметки" + ], + "Pie Chart": ["Круговая диаграмма"], + "Pie shape": ["Форма круговой диаграммы"], + "Pin": ["Закрепить"], + "Pivot Options": ["Параметры сводной таблицы"], + "Pivot Table": ["Сводная таблица"], + "Pivot Table (legacy)": ["Сводная таблица (устарело)"], + "Pivot operation must include at least one aggregate": [""], + "Pivot operation requires at least one index": [""], + "Pivoted": ["Сводные данные"], + "Pixel height of each series": ["Высота каждого ряда (в пикселях)"], + "Pixels": ["Пиксели"], + "Plain": ["Отобразить все"], + "Please DO NOT overwrite the \"filter_scopes\" key.": [""], + "Please apply filter changes": [ + "Пожалуйста, примените изменения фильтров" + ], + "Please check your query and confirm that all template parameters are surround by double braces, for example, \"{{ ds }}\". Then, try running your query again.": [ + "Пожалуйста, проверьте ваш запрос и подтвердите, что все параметры шаблона заключены в двойные фигурные скобки, например, \"{{ from_dttm }}\". Затем попробуйте повторно выполнить запрос." + ], + "Please check your query for syntax errors at or near \"%(syntax_error)s\". Then, try running your query again.": [ + "Пожалуйста, проверьте ваш запрос на синтаксические ошибки возле символа \"%(syntax_error)s\". Затем выполните запрос заново." + ], + "Please check your query for syntax errors near \"%(server_error)s\". Then, try running your query again.": [ + "Пожалуйста, проверьте ваш запрос на наличие синтаксических ошибок рядом с \"%(server_error)s\". Затем выполните запрос заново" + ], + "Please check your template parameters for syntax errors and make sure they match across your SQL query and Set Parameters. Then, try running your query again.": [ + "Пожалуйста, проверьте параметры вашего шаблона на наличие синтаксических ошибок и убедитесь, что они совпадают с вашим SQL-запросом и заданными параметрами. Затем попробуйте выполнить свой запрос еще раз." + ], + "Please choose at least one 'Group by' field": [ + "Выберите хотя бы одно поле \"Группировать по\"" + ], + "Please choose at least one metric": ["Выберите хотя бы одну меру"], + "Please choose different metrics on left and right axis": [ + "Выберите разные меры для левой и правой осей" + ], + "Please confirm": ["Пожалуйста, подтвердите действие"], + "Please confirm the overwrite values.": [""], + "Please enter a SQLAlchemy URI to test": [ + "Введите SQLAlchemy URI для тестирования" + ], + "Please filter set name": ["Введите имя набора фильтров"], + "Please re-enter the password.": ["Пожалуйста, введите пароль еще раз"], + "Please re-export your file and try importing again": [""], + "Please reach out to the Chart Owner for assistance.": [ + "Пожалуйста, обратитесь к создателю графика за помощью.", + "Пожалуйста, обратитесь к создателям графика за помощью.", + "Пожалуйста, обратитесь к создателям графика за помощью." + ], + "Please save the query to enable sharing": [ + "Пожалуйста, сохраните запрос, чтобы включить функцию \"поделиться\"" + ], + "Please save your chart first, then try creating a new email report.": [ + "Пожалуйста, сначала сохраните график перед тем, как создавать новую рассылку." + ], + "Please save your dashboard first, then try creating a new email report.": [ + "Пожалуйста, сначала сохраните дашборд перед тем, как создавать новую рассылку." + ], + "Please select both a Dataset and a Chart type to proceed": [ + "Пожалуйста, для продолжения выберите и датасет, и тип графика" + ], + "Please use 3 different metric labels": [""], + "Plot the distance (like flight paths) between origin and destination.": [ + "" + ], + "Plots the individual metrics for each row in the data vertically and links them together as a line. This chart is useful for comparing multiple metrics across all of the samples or rows in the data.": [ + "" + ], + "Plugins": ["Плагины"], + "Point Color": ["Цвет маркера"], + "Point Radius": ["Радиус маркера"], + "Point Radius Scale": ["Шкала радиуса маркера"], + "Point Radius Unit": ["Единица измерения радиуса маркера"], + "Point Size": ["Размер маркера"], + "Point Unit": ["Единица измерения маркера"], + "Point to your spatial columns": ["Указание на столбцы с расположением"], + "Points": ["Маркеры"], + "Points and clusters will update as the viewport is being changed": [ + "Точки и кластеры будут обновляться по мере изменения области просмотра" + ], + "Polygon Settings": ["Настройки полигона"], + "Popular": ["Популярно"], + "Populate \"Default value\" to enable this control": [""], + "Population age data": [""], + "Port": ["Порт"], + "Port %(port)s on hostname \"%(hostname)s\" refused the connection.": [ + "Порт %(port)s хоста \"%(hostname)s\" отказал в подключении." + ], + "Position of child node label on tree": [ + "Расположение метки дочерней вершины на дереве" + ], + "Position of column level subtotal": [ + "Расположение промежуточного итога на уровне столбца" + ], + "Position of intermidiate node label on tree": [""], + "Position of row level subtotal": [ + "Расположение промежуточного итога на уровне строки" + ], + "Powered by Apache Superset": ["На базе Apache Superset"], + "Pre-filter": ["Предварительная фильтрация"], + "Pre-filter available values": [ + "Предварительно выбрать доступные значения для фильтра" + ], + "Pre-filter is required": ["Предварительная фильтрация обязательна"], + "Predicate applied when fetching distinct value to populate the filter control component. Supports jinja template syntax. Applies only when `Enable Filter Select` is on.": [ + "" + ], + "Predictive": ["Прогноз"], + "Predictive Analytics": ["Предиктивная аналитика"], + "Prefix metric name with slice name": [""], + "Preview": ["Предпросмотр"], + "Preview: `%s`": ["Предпросмотр «%s»"], + "Previous": ["Предыдущий"], + "Previous Line": ["Предыдущая строка"], + "Primary": ["Первичная"], + "Primary Metric": ["Основная мера"], + "Primary key": ["Первичный ключ"], + "Primary or secondary y-axis": ["Первичная или вторичная ось Y"], + "Primary y-axis format": ["Формат первичной оси Y"], + "Private Key": ["Приватный ключ"], + "Private Key & Password": ["Приватный ключ и пароль"], + "Private Key Password": ["Пароль приватного ключа"], + "Proceed": ["Продолжить"], + "Profile": ["Профиль"], + "Profile picture provided by Gravatar": [ + "Изображение профиля, сгенерированное сервисом Gravatar" + ], + "Progress": ["Прогресс"], + "Progressive": ["Постепенный"], + "Propagate": [""], + "Proportional": ["Пропорция"], + "Public and privately shared sheets": [""], + "Publicly shared sheets only": [""], + "Published": ["Опубликовано"], + "Purple": ["Фиолетовый"], + "Put labels outside": ["Вынести метки наружу"], + "Put the labels outside of the pie?": [ + "Вынести метки за пределы диаграммы" + ], + "Put the labels outside the pie?": ["Вынести метки за пределы диаграммы"], + "Put your code here": [ + "Введите произвольный текст в формате html или markdown" + ], + "Python datetime string pattern": ["Шаблон строки даты и времени Python"], + "QUERY DATA IN SQL LAB": [""], + "Quarter": ["Квартал"], + "Quarters %s": ["Кварталов %s"], + "Query": ["Запрос"], + "Query %s: %s": ["Запрос %s: %s"], + "Query A": ["Запрос А"], + "Query B": ["Запрос Б"], + "Query History": ["История запросов"], + "Query does not exist": ["Запрос не существует"], + "Query history": ["История запросов"], + "Query imported": ["Запрос импортирован"], + "Query in a new tab": ["Запрос в отдельной вкладке"], + "Query is too complex and takes too long to run.": [ + "Запрос слишком тяжелый для выполнения и займет много времени." + ], + "Query mode": ["Режим запроса"], + "Query name": ["Имя запроса"], + "Query preview": ["Предпросмотр запроса"], + "Query was stopped": ["Запрос прерван"], + "Query was stopped.": ["Запрос прерван"], + "RANGE TYPE": ["ТИП ИНТЕРВАЛА"], + "RGB Color": ["Цвет RGB"], + "Radar": ["Радар"], + "Radar Chart": ["Диаграмма радар"], + "Radar render type, whether to display 'circle' shape.": [""], + "Radius in kilometers": ["Радиус в километрах"], + "Radius in meters": ["Радиус в метрах"], + "Radius in miles": ["Радиус в милях"], + "Ran %s": ["Запущен %s"], + "Range": ["Интервал"], + "Range filter": ["Диапазон"], + "Range filter plugin using AntD": [""], + "Range labels": ["Метки диапазона"], + "Ranges": ["Диапазоны"], + "Ranges to highlight with shading": [ + "Диапазоны для выделения с помощью затенения" + ], + "Ranking": ["Ранжирование"], + "Ratio": ["Отношение"], + "Raw records": ["Сырые записи"], + "Rebuild": [""], + "Recent activity": ["Последние действия"], + "Recently created charts, dashboards, and saved queries will appear here": [ + "Недавно созданные графики, дашборды и сохраненные запросы" + ], + "Recently edited charts, dashboards, and saved queries will appear here": [ + "Недавно измененные графики, дашборды и сохраненные запросы" + ], + "Recently modified": ["Измененные недавно"], + "Recently viewed charts, dashboards, and saved queries will appear here": [ + "Недавно просмотренные графики, дашборды и сохраненные запросы" + ], + "Recents": ["Недавние"], + "Recipients are separated by \",\" or \";\"": [ + "Получатели, разделенные \",\" или \";\"" + ], + "Recommended tags": ["Рекомендованные теги"], + "Record Count": ["Кол-во записей"], + "Rectangle": ["Прямоугольник"], + "Redirects to this endpoint when clicking on the table from the table list": [ + "" + ], + "Redo the action": ["Повторить действие"], + "Reduce X ticks": ["Уменьшить кол-во делений оси X"], + "Reduces the number of X-axis ticks to be rendered. If true, the x-axis will not overflow and labels may be missing. If false, a minimum width will be applied to columns and the width may overflow into an horizontal scroll.": [ + "Уменьшает количество отрисованных делений на оси X. Если флажок установлен, некоторые метки могут быть не отображены. " + ], + "Refer to the": ["Обратитесь к"], + "Referenced columns not available in DataFrame.": [""], + "Refetch results": ["Выполнить запрос повторно"], + "Refresh": ["Обновить"], + "Refresh dashboard": ["Обновить дашборд"], + "Refresh frequency": ["Частота обновления"], + "Refresh interval": ["Интервал обновления"], + "Refresh interval saved": ["Интервал обновления сохранен"], + "Refresh table list": ["Обновить список таблиц"], + "Refresh tables": ["Обновить таблицы"], + "Refresh the default values": ["Обновить значения по умолчанию"], + "Refreshing charts": ["Обновление графиков"], + "Refreshing columns": ["Обновление столбцов"], + "Relational": ["Относительный"], + "Relationships between community channels": [""], + "Relative Date/Time": ["Относительная дата/время"], + "Relative period": ["Относительный период"], + "Relative quantity": ["Относительное количество"], + "Reload": ["Обновить"], + "Remind me in 24 hours": ["Напомните мне через 24 часа"], + "Remove": ["Удалить"], + "Remove invalid filters": ["Удалить недействующие фильтры"], + "Remove item": ["Удалить элемент"], + "Remove query from log": ["Удалить запрос из истории"], + "Remove table preview": ["Убрать предпросмотр таблицы"], + "Removed columns: %s": ["Удалённые столбцы: %s"], + "Rename tab": ["Переименовать вкладку"], + "Rendering": ["Отрисовка"], + "Replace": ["Заменить"], + "Report": ["Отчет"], + "Report Name": ["Имя отчета"], + "Report Schedule could not be created.": [ + "Невозможно удалить расписание отчета." + ], + "Report Schedule could not be deleted.": [ + "Невозможно удалить расписание отчета." + ], + "Report Schedule could not be updated.": [ + "Невозможно обновить расписание отчета" + ], + "Report Schedule delete failed.": [ + "Ошибка при удалении расписания отчета." + ], + "Report Schedule execution failed when generating a csv.": [ + "Возникла ошибка при создании csv для отправки отчета" + ], + "Report Schedule execution failed when generating a dataframe.": [ + "Возникла ошибка при создании датафрейма для отправки отчета" + ], + "Report Schedule execution failed when generating a screenshot.": [ + "Возникла ошибка при создании скриншота для отправки отчета" + ], + "Report Schedule execution got an unexpected error.": [ + "Возникла неожиданная ошибка при отправке отчета" + ], + "Report Schedule is still working, refusing to re-compute.": [ + "Планировщик отчетов все еще работает, не имея возможности отправить отчет" + ], + "Report Schedule log prune failed.": [""], + "Report Schedule not found.": ["Расписание отчета не найдено"], + "Report Schedule parameters are invalid.": [ + "Параметры расписания отчета неверны." + ], + "Report Schedule reached a working timeout.": [ + "Достигнут таймаут для отчета" + ], + "Report Schedule state not found": [ + "Состояние расписания отчета не найдено" + ], + "Report a bug": ["Сообщить об ошибке"], + "Report failed": ["Рассылка не удалась"], + "Report name": ["Имя отчета"], + "Report schedule": ["Расписание отчета"], + "Report schedule client error": [ + "Возникла ошибка расписания отчета на стороне клиента" + ], + "Report schedule system error": [ + "Возникла ошибка расписания отчета на стороне системы" + ], + "Report schedule unexpected error": [ + "Неожиданная ошибка расписания отчета" + ], + "Report sending": ["Отчет выполняется"], + "Report sent": ["Отчет отправлен"], + "Report updated": ["Отчет обновлен"], + "Reports": ["Отчеты"], + "Repulsion": ["Отталкивание"], + "Repulsion strength between nodes": ["Сила отталкивания вершин"], + "Request Permissions": [""], + "Request is incorrect: %(error)s": ["Неверный запрос: %(error)s"], + "Request is not JSON": ["Запрос не является JSON"], + "Request missing data field.": ["В запросе отсутствует поле с данными."], + "Request timed out": ["Вышло время запроса"], + "Required": ["Обязательно"], + "Required control values have been removed": [ + "Обязательные значения были удалены" + ], + "Resample": ["Ресемплирование (изменение частоты данных)"], + "Resample method should in ": [""], + "Resample operation requires DatetimeIndex": [ + "Для ресемплирования требуется индекс формата дата/время" + ], + "Reset": ["Сбросить"], + "Reset state": ["Сбросить текущее состояние"], + "Resource already has an attached report.": [ + "Для этого компонента уже создан отчет." + ], + "Resource was not found.": ["Источник не был найден."], + "Restore Filter": ["Восстановить фильтр"], + "Results": ["Результаты"], + "Results %s": ["Результаты %s"], + "Results backend is not configured.": ["Results backend не нестроен"], + "Results backend needed for asynchronous queries is not configured.": [ + "Сервер, необходимый для асинхронных запросов, не настроен." + ], + "Return to specific datetime.": [""], + "Reverse Lat & Long": ["Поменять местами широту и долготу"], + "Reverse lat/long ": ["Поменять местами широту и долготу"], + "Rich Tooltip": ["Расширенная всплывающая подсказка"], + "Rich tooltip": ["Расширенная всплывающая подсказка"], + "Right": ["Справа"], + "Right Axis Format": ["Формат правой оси"], + "Right Axis Metric": ["Мера для правой оси"], + "Right Axis chart(s)": ["График(и) по правой оси"], + "Right axis metric": ["Мера для правой оси"], + "Right to Left": ["Справа налево"], + "Right value": ["Правое значение"], + "Right-click on a dimension value to drill to detail by that value.": [ + "" + ], + "Role": ["Роль"], + "Role %(r)s was extended to provide the access to the datasource %(ds)s": [ + "Роль %(r)s была расширена для предоставления доступа к источнику данных %(ds)s" + ], + "Roles": ["Роли"], + "Roles is a list which defines access to the dashboard. Granting a role access to a dashboard will bypass dataset level checks. If no roles are defined, then the dashboard is available to all roles.": [ + "Список ролей, определяющий доступ к дашборду. Предоставляя доступ определенной роли, пользователь сможет обойти ограничения своей роли. Если роли не указаны, дашборд доступен всем ролям." + ], + "Roles to grant": ["Роли для предоставления"], + "Rolling Function": ["Скользящая средняя"], + "Rolling Window": ["Скользящее окно"], + "Rolling function": ["Скользящая средняя"], + "Rolling window": ["Скользящее окно"], + "Root certificate": ["Корневой сертификат"], + "Root node id": [""], + "Rotate axis label": ["Повернуть метки осей"], + "Rotate x axis label": ["Повернуть метку оси X"], + "Rotation to apply to words in the cloud": [ + "Вращение для применения к словам в облаке" + ], + "Round cap": ["Закругление на концах"], + "Row": ["Строка"], + "Row Level Security": ["Безопасность на уровне строк"], + "Row containing the headers to use as column names (0 is first line of data). Leave empty if there is no header row": [ + "Строка, содержащая заголовки для использования в качестве имен столбцов (0, если первая строка в данных). Оставьте пустым, если заголовки отсутствуют" + ], + "Row containing the headers to use as column names (0 is first line of data). Leave empty if there is no header row.": [ + "Строка, содержащая заголовки для использования в качестве имен столбцов (0, если первая строка в данных). Оставьте пустым, если заголовки отсутствуют." + ], + "Row limit": ["Лимит строк"], + "Rows": ["Строки"], + "Rows per page, 0 means no pagination": [ + "Строчек на странице, 0 означает все строки" + ], + "Rows subtotal position": ["Расположение строк подытогов"], + "Rows to Read": ["Строки для чтения"], + "Rule": ["Правило"], + "Run": ["Выполнить"], + "Run a query to display query history": [ + "Выполните запрос для отображения истории" + ], + "Run a query to display results": [ + "Выполните запрос для отображения результатов" + ], + "Run in SQL Lab": ["Открыть в SQL редакторе"], + "Run query": ["Выполнить запрос"], + "Run query (Ctrl + Return)": ["Выполнить запрос (Ctrl + Enter)"], + "Run query in a new tab": ["Выполнить запрос на новой вкладке"], + "Run selection": ["Выполнить выбранное"], + "Running": ["Выполняется"], + "Running statement %(statement_num)s out of %(statement_count)s": [""], + "SAT": ["СБ"], + "SEP": ["СЕН"], + "SHA": [""], + "SQL": ["SQL"], + "SQL Copied!": ["SQL запрос скопирован!"], + "SQL Expression": ["SQL выражение"], + "SQL Lab": ["Лаборатория SQL"], + "SQL Lab View": [""], + "SQL Lab uses your browser's local storage to store queries and results.\nCurrently, you are using %(currentUsage)s KB out of %(maxStorage)d KB storage space.\nTo keep SQL Lab from crashing, please delete some query tabs.\nYou can re-access these queries by using the Save feature before you delete the tab.\nNote that you will need to close other SQL Lab windows before you do this.": [ + "SQL Lab использует локальное хранилище вашего браузера для хранения запросов и результатов.\nВ настоящее время вы используете %(currentUsage)s КБ из %(maxStorage)d КБ дискового пространства.\n Чтобы предотвратить сбой Лаборатории SQL, пожалуйста, удалите некоторые вкладки запросов.\n Вы можете повторно получить доступ к этим запросам, используя функцию сохранения перед удалением вкладки.\n Обратите внимание, что перед этим вам нужно будет закрыть другие окна Лаборатории SQL." + ], + "SQL Query": ["SQL запрос"], + "SQL expression": ["Выражение SQL"], + "SQL query": ["SQL запрос"], + "SQLAlchemy URI": ["SQLAlchemy URI"], + "SSH Host": [""], + "SSH Password": ["Пароль SSH"], + "SSH Port": ["SSH порт"], + "SSH Tunnel configuration parameters": [ + "Параметры конфигурации SSH туннеля" + ], + "SSH Tunnel could not be deleted.": ["Не удалось удалить SSH туннель."], + "SSH Tunnel could not be updated.": ["Не удалось обновить SSH туннель."], + "SSH Tunnel not found.": ["SSH туннель не найден."], + "SSH Tunnel parameters are invalid.": [ + "Параметры SSH туннеля недопустимы." + ], + "SSH Tunneling is not enabled": [""], + "SSL Mode \"require\" will be used.": [ + "Будет использовано шифрование SSL" + ], + "START (INCLUSIVE)": ["НАЧАЛО (ВКЛЮЧИТЕЛЬНО)"], + "STEP %(stepCurr)s OF %(stepLast)s": ["ШАГ %(stepCurr)s ИЗ %(stepLast)s"], + "STRING": ["Строчный (STRING/VARCHAR)"], + "SUN": ["ВС"], + "Sample Standard Deviation": ["Стандартное отклонение"], + "Sample Variance": ["Дисперсия"], + "Samples": ["Примеры данных"], + "Samples for dataset could not be retrieved.": [ + "Не удалось получить примеры записей датасета." + ], + "Samples for datasource could not be retrieved.": [ + "Не удалось получить примеры записей для источника данных." + ], + "Sankey": ["Санкей"], + "Sankey Diagram": ["Диаграмма Санкей"], + "Sankey Diagram with Loops": [""], + "Satellite": ["Спутник"], + "Satellite Streets": ["Гибридный режим"], + "Saturday": ["Суббота"], + "Save": ["Сохранить"], + "Save & Explore": ["Сохранить и исследовать"], + "Save & go to dashboard": ["Сохранить и перейти к дашборду"], + "Save & go to new dashboard": ["Сохранить и перейти к дашборду"], + "Save (Overwrite)": ["Сохранить (Перезаписать)"], + "Save as": ["Сохранить как"], + "Save as Dataset": ["Сохранить как датасет"], + "Save as dataset": ["Сохранить как датасет"], + "Save as new": ["Сохранить как новый"], + "Save as new chart": ["Сохранить как новый график"], + "Save as...": ["Сохранить как..."], + "Save as:": ["Сохранить как:"], + "Save changes": ["Сохранить изменения"], + "Save chart": ["Сохранить график"], + "Save dashboard": ["Сохранить дашборд"], + "Save dataset": ["Сохранить датасет"], + "Save for this session": ["Сохранить на время текущей сессии"], + "Save or Overwrite Dataset": ["Сохранить или перезаписать датасет"], + "Save query": ["Сохранить запрос"], + "Save the query to enable this feature": [ + "Сохраните запрос для включения этой опции" + ], + "Save this query as a virtual dataset to continue exploring": [ + "Сохраните данный запрос как виртуальный датасет для создания графика" + ], + "Save to new dashboard": ["Сохранить в новый дашборд"], + "Saved": ["Сохранено"], + "Saved Queries": ["Сохраненные запросы"], + "Saved expressions": ["Сохраненные выражения"], + "Saved metric": ["Сохраненная мера"], + "Saved queries": ["Сохраненные запросы"], + "Saved queries could not be deleted.": [ + "Не удалось удалить сохраненные запросы." + ], + "Saved query not found.": ["Сохраненный запрос не найден."], + "Saved query parameters are invalid.": [ + "Сохраненные параметры запроса недопустимы." + ], + "Scale and Move": ["Масштабирование и перемещение"], + "Scale only": ["Только масштабирование"], + "Scatter": ["Точечный"], + "Scatter Plot": ["Точечная диаграмма"], + "Scatter Plot has the horizontal axis in linear units, and the points are connected in order. It shows a statistical relationship between two variables.": [ + "" + ], + "Schedule": ["Расписание"], + "Schedule a new email report": ["Запланировать новую рассылку по почте"], + "Schedule email report": ["Запланировать рассылку по почте"], + "Schedule query": ["Сохранить запрос"], + "Schedule settings": ["Настройки расписания"], + "Schedule the query periodically": [ + "Запланировать периодическое выполнение запроса" + ], + "Scheduled": ["Запланировано"], + "Scheduled at (UTC)": ["Запланировано на (часовой пояс UTC)"], + "Scheduled task executor not found": [ + "Исполнитель регулярных отчетов не найден" + ], + "Schema": ["Схема"], + "Schema cache timeout": ["Время жизни кэша схемы"], + "Schema undefined": ["Схема не определена"], + "Schema, as used only in some databases like Postgres, Redshift and DB2": [ + "" + ], + "Schemas allowed for File upload": [ + "Схемы, в которые разрешена загрузка файлов" + ], + "Scope": ["Область"], + "Scoping": ["Область применения"], + "Scroll": ["Прокрутка"], + "Scroll down to the bottom to enable overwriting changes. ": [""], + "Search": ["Поиск"], + "Search / Filter": ["Поиск / Фильтр"], + "Search Metrics & Columns": ["Поиск по мерам и столбцам"], + "Search all charts": ["Поиск по всем графикам"], + "Search all filter options": ["Поиск по всем фильтрам"], + "Search box": ["Строка поиска"], + "Search by query text": ["Поиск по тексту запроса"], + "Search...": ["Поиск..."], + "Second": ["Секунда"], + "Secondary": ["Вторичная"], + "Secondary Metric": ["Вторичная мера"], + "Secondary y-axis format": ["Формат вторичной оси Y"], + "Secondary y-axis title": ["Название вторичной оси Y"], + "Seconds %s": ["Секунд %s"], + "Secure Extra": ["Доп. безопасность"], + "Secure extra": ["Безопасность"], + "Security": ["Безопасность"], + "Security & Access": ["Безопасность и Доступ"], + "See all %(tableName)s": ["Список %(tableName)s"], + "See less": ["Скрыть подробности"], + "See more": ["Подробнее"], + "See query details": ["Показать детали запроса"], + "See table schema": ["Таблица"], + "Select": ["Выбрать"], + "Select ...": ["Выбрать ..."], + "Select Delivery Method": ["Выберите способ оповещения"], + "Select Viz Type": ["Выберите тип визуализации"], + "Select a Columnar file to be uploaded to a database.": [ + "Выберите файл столбчатого формата, который будет загружен в базу данных." + ], + "Select a Excel file to be uploaded to a database.": [ + "Выберите Excel файл для загрузки в базу данных" + ], + "Select a column": ["Выберите столбец"], + "Select a dashboard": ["Выбрать дашборд"], + "Select a database table and create dataset": [ + "Выберите базу данных и создайте датасет" + ], + "Select a database table.": ["Выберите таблицу в базе данных."], + "Select a database to connect": ["Выберите базу данных для подключения"], + "Select a database to upload the file to": [ + "Выберите базу данных для загрузки файла" + ], + "Select a database to write a query": [ + "Выберите базу данных для написания запроса" + ], + "Select a dimension": ["Выберете измерение"], + "Select a file to be uploaded to the database": [ + "Выберите файл для загрузки в базу данных." + ], + "Select a schema if the database supports this": [ + "Укажите схему, если она поддерживается базой данных" + ], + "Select a visualization type": ["Выберите тип визуализации"], + "Select aggregate options": ["Выберите настройки агрегации"], + "Select all data": ["Выбрать все данные"], + "Select all items": ["Выбрать все записи"], + "Select any columns for metadata inspection": [""], + "Select charts": ["Выберите графики"], + "Select color scheme": ["Выберите цветовую схему"], + "Select column": ["Выберите столбец"], + "Select current page": ["Выбрать текущую страницу"], + "Select database & schema": ["Выберите базу данных и схему"], + "Select database or type database name": [ + "Выберите базу данных или введите ее имя" + ], + "Select database table": ["Выберите таблицу из базы данных"], + "Select databases require additional fields to be completed in the Advanced tab to successfully connect the database. Learn what requirements your databases has ": [ + "Некоторые базы данных требуют ручной настройки во вкладке Продвинутая настройка для успешного подключения. Вы можете ознакомиться с требованиями к вашей базе данных " + ], + "Select dataset source": ["Выберите источник датасета"], + "Select file": ["Выбрать файл"], + "Select filter": ["Селектор"], + "Select filter plugin using AntD": [""], + "Select first filter value by default": [ + "Сделать первое значение фильтра значением по умолчанию" + ], + "Select operator": ["Выбрать оператор"], + "Select or type a value": ["Выберите значение"], + "Select or type dataset name": ["Выберите/введите имя датасета"], + "Select owners": ["Выбрать владельцев"], + "Select saved metrics": ["Выберите сохраненные меры"], + "Select schema or type schema name": [ + "Выберите схему или введите ее имя" + ], + "Select scheme": ["Выберите схему"], + "Select start and end date": ["Выберите дату начала"], + "Select subject": [""], + "Select table or type table name": [ + "Выберите таблицу или введите ее имя" + ], + "Select the Annotation Layer you would like to use.": [ + "Выбрать слой аннотации, который вы хотите использовать." + ], + "Select the geojson column": ["Выберите geojson столбец"], + "Select the number of bins for the histogram": [ + "Выберите количество столбцов для гистограммы" + ], + "Select the numeric columns to draw the histogram": [ + "Выберите числовые столбцы для отрисовки гистограммы" + ], + "Select values in highlighted field(s) in the control panel. Then run the query by clicking on the %s button.": [ + "Выберите значения в обязательных полях на панели управления. Затем запустите запрос, нажав на кнопку %s." + ], + "Send as CSV": ["Отправить в формате CSV"], + "Send as PNG": ["Отправить в формате PNG"], + "Send as text": ["Отправить текстом"], + "Send range filter events to other charts": [""], + "September": ["Сентябрь"], + "Sequential": ["Последовательность"], + "Series": ["Ряд"], + "Series Height": ["Высота рядов"], + "Series Limit Sort By": ["Сортировка категорий по"], + "Series Style": ["Стиль категорий"], + "Series chart type (line, bar etc)": [""], + "Series limit": ["Лимит кол-ва категорий"], + "Server Page Length": ["Серверный размер страницы"], + "Server pagination": ["Серверная пагинация"], + "Service Account": ["Сервисный аккаунт"], + "Set auto-refresh interval": ["Задать интервал обновления"], + "Set filter mapping": ["Установить действие фильтра"], + "Set up an email report": ["Запланировать рассылку по почте"], + "Sets the hierarchy levels of the chart. Each level is\n represented by one ring with the innermost circle as the top of the hierarchy.": [ + "" + ], + "Settings": ["Настройки"], + "Settings for time series": ["Настройки временных рядов"], + "Share": ["Поделиться"], + "Share chart by email": ["Поделиться графиком по email"], + "Share permalink by email": ["Поделиться ссылкой по email"], + "Shared query": ["Общедоступный запрос"], + "Shared query fields": ["Поля общедоступного запроса"], + "Sheet Name": ["Имя листа"], + "Shift + Click to sort by multiple columns": [ + "Shift + Нажать для сортировки по нескольким столбцам" + ], + "Short description must be unique for this layer": [ + "Содержимое аннотации должно быть уникальным внутри слоя" + ], + "Should daily seasonality be applied. An integer value will specify Fourier order of seasonality.": [ + "Применяется дневная сезонность. Целочисленное значение будет указывать порядок сезонности Фурье." + ], + "Should weekly seasonality be applied. An integer value will specify Fourier order of seasonality.": [ + "Применяется недельная сезонность. Целочисленное значение будет указывать порядок сезонности Фурье." + ], + "Should yearly seasonality be applied. An integer value will specify Fourier order of seasonality.": [ + "Применяется годовая сезонность. Целочисленное значение будет указывать порядок сезонности Фурье." + ], + "Show Bubbles": ["Показать пузыри"], + "Show CREATE VIEW statement": ["Показать выражение CREATE VIEW"], + "Show CSS Template": ["Показать CSS шаблон"], + "Show Chart": ["Показать график"], + "Show Column": ["Показать столбец"], + "Show Dashboard": ["Показать дашборд"], + "Show Database": ["Показать базу данных"], + "Show Labels": ["Показывать метки"], + "Show Less...": ["Показать меньше..."], + "Show Log": ["Показать запись"], + "Show Markers": ["Показать маркеры"], + "Show Metric": ["Показатель меру"], + "Show Metric Names": ["Показать имена мер"], + "Show Range Filter": ["Показать фильтр Диапазон"], + "Show Saved Query": ["Показать сохраненный запрос"], + "Show Table": ["Показать таблицу"], + "Show Timestamp": ["Показать метку времени"], + "Show Total": ["Показать общий итог"], + "Show Trend Line": ["Показать трендовую линию"], + "Show Upper Labels": ["Показать верхние метки"], + "Show Value": ["Показать значение"], + "Show Values": ["Показать значения"], + "Show Y-axis": ["Показать ось Y"], + "Show Y-axis on the sparkline. Will display the manually set min/max if set or min/max values in the data otherwise.": [ + "Показывать ось Y на спарклайне." + ], + "Show all columns": ["Показать все столбцы"], + "Show all...": ["Показать все..."], + "Show axis line ticks": ["Показывать деления на оси"], + "Show cell bars": ["Наложить гистограммы на ячейки"], + "Show chart description": ["Показать описание графика"], + "Show columns total": ["Показать общий итог по столбцам"], + "Show data points as circle markers on the lines": [""], + "Show empty columns": ["Показывать пустые столбцы"], + "Show hierarchical relationships of data, with with the value represented by area, showing proportion and contribution to the whole.": [ + "Показывает иерархические взаимосвязи данных со значением, представленным областью, показывая пропорцию и вклад в целое." + ], + "Show info tooltip": ["Показать информационную подсказку"], + "Show label": ["Показывать метку"], + "Show labels when the node has children.": [ + "Показывать метки, когда у вершины есть дочерние элементы." + ], + "Show legend": ["Показывать легенду"], + "Show less columns": ["Показать меньше столбцов"], + "Show less...": ["Показать меньше..."], + "Show password.": ["Показать пароль."], + "Show percentage": ["Показывать долю"], + "Show pointer": ["Показывать указатель"], + "Show progress": ["Показывать прогресс"], + "Show rows total": ["Показать общий итог по строкам"], + "Show series values on the chart": [ + "Показать значения категорий на графике" + ], + "Show split lines": ["Показывать разделительные линии"], + "Show the value on top of the bar": [ + "Показать значение в верхней части столбца" + ], + "Show time column": ["Показать столбец времени"], + "Show total aggregations of selected metrics. Note that row limit does not apply to the result.": [ + "Показать общие итоговые значения выбранных показателей. Обратите внимание, что ограничение количества строк не применяется к результату." + ], + "Show totals": ["Показывать общий итог"], + "Showcases a single metric front-and-center. Big number is best used to call attention to a KPI or the one thing you want your audience to focus on.": [ + "Отображает один показатель по центру. Карточку лучше всего использовать, чтобы привлечь внимание к KPI." + ], + "Showcases a single number accompanied by a simple line chart, to call attention to an important metric along with its change over time or other dimension.": [ + "Отображает один показатель, сопровождаемый простой линейной диаграммой, чтобы привлечь внимание к KPI наряду с его изменением с течением времени или другим измерением." + ], + "Showcases how a metric changes as the funnel progresses. This classic chart is useful for visualizing drop-off between stages in a pipeline or lifecycle.": [ + "Отображает изменение показателя по мере сужения воронки. Эта классическая диаграмма полезна для визуализации перехода между этапами процесса или жизненного цикла." + ], + "Showcases the flow or link between categories using thickness of chords. The value and corresponding thickness can be different for each side.": [ + "" + ], + "Showcases the progress of a single metric against a given target. The higher the fill, the closer the metric is to the target.": [ + "Демонстрирует прогресс одного показателя по отношению к заданной цели. Чем больше заполнение, тем ближе показатель к целевому показателю." + ], + "Showing %s of %s": ["Отображено %s из %s"], + "Shows a list of all series available at that point in time": [ + "Показывает список всех данных, доступных в определенный момент времени" + ], + "Shows or hides markers for the time series": [ + "Показывает или скрывает маркеры для временных рядов" + ], + "Shows the composition of a dataset by segmenting a given rectangle as smaller rectangles with areas proportional to their value or contribution to the whole. Those rectangles may also, in turn, be further segmented hierarchically.": [ + "" + ], + "Significance Level": [""], + "Simple": ["Столбец"], + "Simple ad-hoc metrics are not enabled for this dataset": [""], + "Single": ["Один"], + "Single Metric": ["Одна мера"], + "Single Value": ["Единственное значение"], + "Single value": ["Единственное значение"], + "Single value type": ["Тип единственного значения"], + "Size of edge symbols": [""], + "Size of marker. Also applies to forecast observations.": [ + "Размер маркера. Также применяется к прогнозным значениям." + ], + "Sizes of vehicles": [""], + "Skip Blank Lines": ["Пропуск пустых строк"], + "Skip Initial Space": ["Пропуск начального пробела"], + "Skip Rows": ["Пропуск строк"], + "Skip blank lines rather than interpreting them as Not A Number values": [ + "Пропускать пустые строки, вместо их перевода в пустые строки (NaN)" + ], + "Skip spaces after delimiter": ["Пропускать пробелы после разделителя"], + "Slug": ["Читаемый URL"], + "Small": ["Маленький"], + "Small number format": ["Форматирование маленьких чисел"], + "Smooth Line": ["Гладкая линия"], + "Smooth-line is a variation of the line chart. Without angles and hard edges, Smooth-line sometimes looks smarter and more professional.": [ + "" + ], + "Solid": ["Сплошной"], + "Some roles do not exist": ["Некоторые роли не существуют"], + "Something went wrong.": [""], + "Sorry there was an error fetching database information: %s": [ + "К сожалению, произошла ошибка при получении информации о базе данных: %s" + ], + "Sorry there was an error fetching saved charts: ": [ + "Извините, произошла ошибка при загрузке графиков: " + ], + "Sorry, An error occurred": ["Извините, произошла ошибка"], + "Sorry, an error occurred": ["Извините, произошла ошибка"], + "Sorry, an unknown error occurred": [ + "Извините, произошла неизвестная ошибка" + ], + "Sorry, an unknown error occurred.": [ + "Извините, произошла неизвестная ошибка." + ], + "Sorry, something went wrong. Embedding could not be deactivated.": [ + "Извините, что-то пошло не так. Встраивание не может быть деактивировано." + ], + "Sorry, something went wrong. Try again later.": [ + "Извините, что-то пошло не так. Попробуйте еще раз позже." + ], + "Sorry, there appears to be no data": [ + "Извините, похоже, что данные отсутствуют" + ], + "Sorry, there was an error saving this dashboard: %s": [ + "Извините, произошла ошибка при сохранении дашборда: %s" + ], + "Sorry, your browser does not support copying.": [ + "Извините, Ваш браузер не поддерживание копирование. Используйте сочетание клавиш [CTRL + C] для WIN или [CMD + C] для MAC." + ], + "Sorry, your browser does not support copying. Use Ctrl / Cmd + C!": [ + "Извините, Ваш браузер не поддерживание копирование. Используйте сочетание клавиш [CTRL + C] для WIN или [CMD + C] для MAC!" + ], + "Sort": ["Сортировка"], + "Sort Bars": ["Сортировать столбцы"], + "Sort Descending": ["Сортировать по убыванию"], + "Sort Metric": ["Мера для сортировки"], + "Sort X Axis": ["Сортировка оси X"], + "Sort Y Axis": ["Сортировка оси Y"], + "Sort ascending": ["Сортировать по возрастанию"], + "Sort bars by x labels.": ["Сортировать столбцы по меткам на оси X"], + "Sort by": ["Сортировка"], + "Sort by %s": ["Сорт. по %s"], + "Sort by metric": ["Сортировка по мере"], + "Sort columns alphabetically": [ + "Отсортировать столбцы в алфавитном порядке" + ], + "Sort columns by": ["Сортировать столбцы по"], + "Sort descending": ["Сортировка по убыванию"], + "Sort filter values": ["Сортировать отфильтрованные значения"], + "Sort metric": ["Показатель для сортировки"], + "Sort rows by": ["Сортировка строк по"], + "Sort type": ["Тип сортировки"], + "Source": ["Источник"], + "Source / Target": ["Источник / Цель"], + "Source SQL": ["Исходный SQL"], + "Source category": ["Исходная категория"], + "Sparkline": ["Спарклайн"], + "Spatial": [""], + "Specific Date/Time": ["Конкретная дата/время"], + "Specify a schema (if database flavor supports this).": [ + "Укажите схему (если она поддерживается базой данных)." + ], + "Specify duplicate columns as \"X.0, X.1\".": [ + "Обозначить повторяющиеся столбцы как \"X.0, X.1\"." + ], + "Specify name to CREATE TABLE AS schema in: public": [ + "Укажите имя новой таблицы для CREATE TABLE AS" + ], + "Specify name to CREATE VIEW AS schema in: public": [ + "Укажите имя нового представления для CREATE VIEW AS" + ], + "Specify the database version. This should be used with Presto in order to enable query cost estimation.": [ + "Укажите версию базы данных. Это необходимо для Presto, чтобы включить оценку стоимости запроса" + ], + "Split number": ["Количество разделителей"], + "Square kilometers": ["Квадратные километры"], + "Square meters": ["Квадратные метры"], + "Square miles": ["Квадратные мили"], + "Stack": [""], + "Stack Trace:": [""], + "Stack series": ["Использовать накопление"], + "Stack series on top of each other": [ + "Совместить столбцы в один с накоплением" + ], + "Stacked": ["С наполнением"], + "Stacked Bars": ["Столбцы с накоплением"], + "Stacked Style": [""], + "Stacked style": [""], + "Standard time series": [""], + "Start": ["Начало"], + "Start (Longitude, Latitude): ": ["Старт (Долгота, Широта): "], + "Start Longitude & Latitude": ["Начальные долгота и широта"], + "Start angle": ["Начальный угол"], + "Start at (UTC)": ["Время начала (UTC)"], + "Start date included in time range": [ + "Начальная дата включена во временной интервал" + ], + "Start y-axis at 0": ["Начать ось Y с 0"], + "Start y-axis at zero. Uncheck to start y-axis at minimum value in the data.": [ + "Начать ось Y в нуле. Снимите флаг, чтобы ось Y начиналась на минимальном значении данных" + ], + "State": ["Состояние"], + "Statement %(statement_num)s out of %(statement_count)s": [""], + "Statistical": ["Статистический учет"], + "Status": ["Статус"], + "Step - end": [""], + "Step - middle": [""], + "Step - start": [""], + "Stepped-line graph (also called step chart) is a variation of line chart but with the line forming a series of steps between data points. A step chart can be useful when you want to show the changes that occur at irregular intervals.": [ + "" + ], + "Stop": ["Стоп"], + "Stop query": ["Остановить запрос"], + "Stop running (Ctrl + e)": ["Остановить выполнение (CTRL + X)"], + "Stop running (Ctrl + x)": ["Остановить выполнение (CTRL + X)"], + "Stopped an unsafe database connection": [""], + "Streets": ["Схема"], + "Strength to pull the graph toward center": [ + "Сила притяжения вершин к центру" + ], + "Stretched style": [""], + "Strings used for sheet names (default is the first sheet).": [ + "Имя листа (по умолчанию первый лист)" + ], + "Stroke Color": ["Цвет обводки"], + "Stroke Width": ["Ширина обводки"], + "Stroked": ["С обводкой"], + "Structural": ["Структура"], + "Style": ["Стиль"], + "Style the ends of the progress bar with a round cap": [ + "Оформление концов индикатора круглыми заглушками" + ], + "Subdomain": ["Подблок"], + "Subheader": ["Подзаголовок"], + "Subheader Font Size": ["Размер шрифта подзаголовка"], + "Submit": ["Отправить"], + "Subtotal": ["Подытог"], + "Success": ["Успешно"], + "Successfully changed dataset!": [""], + "Suffix to apply after the percentage display": [ + "Текст после отображения процентной доли" + ], + "Sum": ["Сумма"], + "Sum as Fraction of Columns": ["Сумма как доля столбцов"], + "Sum as Fraction of Rows": ["Сумма как доля строк"], + "Sum as Fraction of Total": ["Сумма как доля целого"], + "Sum of values over specified period": [ + "Сумма значений за обозначенный период" + ], + "Sum values": ["Суммарные значения"], + "Sunburst": ["Диаграмма Солнечные лучи"], + "Sunburst Chart": ["Диаграмма Солнечные лучи"], + "Sunday": ["Воскресенье"], + "Superset Chart": ["График Superset"], + "Superset Embedded SDK documentation.": [""], + "Superset chart": ["График Superset"], + "Superset dashboard": ["Дашборд Superset"], + "Superset encountered an error while running a command.": [ + "Суперсет столкнулся с ошибкой во время выполнения команды." + ], + "Superset encountered an unexpected error.": [ + "Суперсет столкнулся с неожиданной ошибкой." + ], + "Supported databases": ["Поддерживаемые базы данных"], + "Survey Responses": [""], + "Swap Groups and Columns": ["Поменять местами группы и столбцы"], + "Swap dataset": ["Сменить датасет"], + "Swap rows and columns": ["Поменять местами строки и столбцы"], + "Swiss army knife for visualizing data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.": [ + "" + ], + "Swiss army knife for visualizing time series data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.": [ + "" + ], + "Symbol": [""], + "Symbol of two ends of edge line": [""], + "Sync columns from source": ["Синхронизировать столбцы из источника"], + "Syntax": [""], + "TABLES": ["ТАБЛИЦЫ"], + "THU": ["ЧТ"], + "TUE": ["ВТ"], + "Tab name": ["Имя вкладки"], + "Tab title": ["Имя вкладки"], + "Table": ["Таблица"], + "Table %(table)s wasn't found in the database %(db)s": [""], + "Table Exists": ["Таблица существует"], + "Table Name": ["Имя таблицы"], + "Table [%(table_name)s] could not be found, please double check your database connection, schema, and table name": [ + "Не удается найти таблицу \"%(table_name)s\", пожалуйста, проверьте ваше соединение с базой данных, схему и имя таблицы" + ], + "Table [%{table}s] could not be found, please double check your database connection, schema, and table name, error: {}": [ + "Не удается найти таблицу \"%(table)s\", пожалуйста, проверьте ваше соединение с базой данных, схему и имя таблицы, ошибка: {}" + ], + "Table cache timeout": ["Время жизни кэша таблицы"], + "Table columns": ["Столбцы таблицы"], + "Table name cannot contain a schema": [ + "Имя таблицы не может содержать схему" + ], + "Table name undefined": ["Имя таблицы не определено"], + "Table that visualizes paired t-tests, which are used to understand statistical differences between groups.": [ + "Таблица, визуализирующая парные t-тесты, которые используются для нахождения статистических различий между группами." + ], + "Tables": ["Таблицы"], + "Tabs": ["Вкладки"], + "Tabular": ["Таблицы"], + "Tags": ["Теги"], + "Take your data points, and group them into \"bins\" to see where the densest areas of information lie": [ + "" + ], + "Target": ["Цель"], + "Target Color": ["Целевой цвет"], + "Target aspect ratio for treemap tiles.": [""], + "Target category": ["Целевая категория"], + "Target value": ["Целевое значение"], + "Template Name": ["Имя шаблона"], + "Template parameters": ["Параметры шаблона"], + "Templated link, it's possible to include {{ metric }} or other values coming from the controls.": [ + "Шаблонная ссылка, можно включить {{ metric }} или другие значения, поступающие из элементов управления." + ], + "Terminate running queries when browser window closed or navigated to another page. Available for Presto, Hive, MySQL, Postgres and Snowflake databases.": [ + "Завершать выполнение запросов после закрытия браузерной вкладки или пользователь переключился на другую вкладку. Доступно для баз данных Presto, Hive, MySQL, Postgres и Snowflake." + ], + "Test Connection": ["Тестовое соединение"], + "Test connection": ["Тестовое соединение"], + "Text": ["Текст"], + "Text align": ["Выравнивание текста"], + "Text embedded in email": ["Текст, включенный в email"], + "The CSS for individual dashboards can be altered here, or in the dashboard view where changes are immediately visible": [ + "" + ], + "The CTAS (create table as select) doesn't have a SELECT statement at the end. Please make sure your query has a SELECT as its last statement. Then, try running your query again.": [ + "CTAS (CREATE TABLE AS SELECT) не содержит SELECT запрос в конце. Пожалуйста, убедитесь, что ваш запрос имеет SELECT запрос в конце. Затем попробуйте повторно выполнить запрос." + ], + "The GeoJsonLayer takes in GeoJSON formatted data and renders it as interactive polygons, lines and points (circles, icons and/or texts).": [ + "Диаграмма принимает данные в формате GeoJSON и отображает их в виде интерактивных полигонов, линий и точек (кругов, значков и/или текста)." + ], + "The URL is missing the dataset_id or slice_id parameters.": [""], + "The X-axis is not on the filters list": [""], + "The X-axis is not on the filters list which will prevent it from being used in\n time range filters in dashboards. Would you like to add it to the filters list?": [ + "" + ], + "The access requests seem to have been deleted": [""], + "The annotation has been saved": ["Аннотация сохранена"], + "The annotation has been updated": ["Аннотация обновлена"], + "The category of source nodes used to assign colors. If a node is associated with more than one category, only the first will be used.": [ + "Категория исходных вершин предназначена для задания цветов. Если вершина связана более, чем с одной категорией, только первая будет использована." + ], + "The chart datasource does not exist": [ + "Источник данных графика не существует" + ], + "The chart does not exist": ["График не существует"], + "The classic. Great for showing how much of a company each investor gets, what demographics follow your blog, or what portion of the budget goes to the military industrial complex.\n\n Pie charts can be difficult to interpret precisely. If clarity of relative proportion is important, consider using a bar or other chart type instead.": [ + "Классическая круговая/кольцевая диаграмма." + ], + "The color for points and clusters in RGB": [ + "Цвет для маркеров и кластеров в RGB" + ], + "The color scheme for rendering chart": [ + "Цветовая схема, применяемая для раскрашивания графика" + ], + "The color scheme is determined by the related dashboard.\n Edit the color scheme in the dashboard properties.": [ + "Цветовая схема определена соответствующим дашбордом.\n Измените цветовую схему в свойствах дашборда." + ], + "The column header label": ["Заголовок столбца"], + "The column was deleted or renamed in the database.": [ + "Столбец был удален или переименован в базе данных." + ], + "The country code standard that Superset should expect to find in the [country] column": [ + "Код страны, который Суперсет ожидает найти в столбце со страной" + ], + "The dashboard has been saved": ["Дашборд сохранен"], + "The data source seems to have been deleted": [ + "Источник данных, похоже, был удален" + ], + "The data type that was inferred by the database. It may be necessary to input a type manually for expression-defined columns in some cases. In most case users should not need to alter this.": [ + "" + ], + "The database %s is linked to %s charts that appear on %s dashboards and users have %s SQL Lab tabs using this database open. Are you sure you want to continue? Deleting the database will break those objects.": [ + "База данных %s привязана к %s графику(-ам), который(-ые) используется(-ются) в %s дашборде(-ах), и пользователи имеют %s открытую(-ых) вкладку(-ок) в Лаборатории SQL. Вы уверены, что хотите продолжить? Удаление базы данных приведёт к неработоспособности этих компонентов." + ], + "The database columns that contains lines information": [""], + "The database is currently running too many queries.": [ + "В настоящий момент база данных обрабатывает слишком много запросов." + ], + "The database is under an unusual load.": [ + "Нетипично высокая загрузка базы данных" + ], + "The database referenced in this query was not found. Please contact an administrator for further assistance or try again.": [ + "База данных, указанная в этом запросе, не найдена. Пожалуйста, обратитесь к своему администратору или попробуйте еще раз." + ], + "The database returned an unexpected error.": [ + "База данных вернула неожиданную ошибку" + ], + "The database was deleted.": ["База данных была удалена"], + "The database was not found.": ["Не удалось найти базу данных"], + "The dataset %s is linked to %s charts that appear on %s dashboards. Are you sure you want to continue? Deleting the dataset will break those objects.": [ + "Датасет %s привязан к %s графику(-ам), который(-ые) используется(-ются) в %s дашборде(-ах). Вы уверены, что хотите продолжить? Удаление датасета приведёт к неработоспособности этих объектов." + ], + "The dataset associated with this chart no longer exists": [ + "Датасет, связанный с этим графиком, больше не существует" + ], + "The dataset configuration exposed here\n affects all the charts using this dataset.\n Be mindful that changing settings\n here may affect other charts\n in undesirable ways.": [ + "Представленная здесь конфигурация датасета\n влияет на все графики, использующие этот датасет.\n Помните, что изменение настроек\n может иметь неожиданный эффект\n на другие графики." + ], + "The dataset has been saved": ["Датасет сохранен"], + "The dataset linked to this chart may have been deleted.": [ + "Датасет, связанный с этим графиком, похоже, был удален." + ], + "The datasource couldn't be loaded": [ + "Невозможно загрузить источник данных" + ], + "The datasource is too large to query.": [ + "Источник данных слишком велик для запроса." + ], + "The description can be displayed as widget headers in the dashboard view. Supports markdown.": [ + "Описание может быть отображено как заголовок графика в дашборде. Поддерживает markdown-разметку" + ], + "The distance between cells, in pixels": [ + "Расстояние между ячейками (в пикселях)" + ], + "The duration of time in seconds before the cache is invalidated": [ + "Количество секунд до истечения срока действия кэша" + ], + "The engine_params object gets unpacked into the sqlalchemy.create_engine call.": [ + "Объект engine_params вызывает sqlalchemy.create_engine" + ], + "The following entries in `series_columns` are missing in `columns`: %(columns)s. ": [ + "" + ], + "The function to use when aggregating points into groups": [""], + "The host \"%(hostname)s\" might be down and can't be reached.": [ + "Хост \"%(hostname)s\" возможно, отключен, и с ним невозможно связаться" + ], + "The host \"%(hostname)s\" might be down, and can't be reached on port %(port)s.": [ + "Хост \"%(hostname)s\" возможно, отключен, и с ним невозможно связаться по порту %(port)s." + ], + "The host might be down, and can't be reached on the provided port.": [ + "Хост возможно, отключен, и с ним невозможно связаться по заданному порту." + ], + "The hostname \"%(hostname)s\" cannot be resolved.": [ + "Не удалось обнаружить хост \"%(hostname)s\"" + ], + "The hostname provided can't be resolved.": [ + "Не удалось обнаружить хост." + ], + "The id of the active chart": ["Идентификатор активного графика"], + "The list of charts associated with this table. By altering this datasource, you may change how these associated charts behave. Also note that charts need to point to a datasource, so this form will fail at saving if removing charts from a datasource. If you want to change the datasource for a chart, overwrite the chart from the 'explore view'": [ + "" + ], + "The maximum number of events to return, equivalent to the number of rows": [ + "Максимальное количество возвращаемых событий, эквивалентно количеству строк" + ], + "The maximum number of subdivisions of each group; lower values are pruned first": [ + "" + ], + "The maximum value of metrics. It is an optional configuration": [ + "Максимальное значение мер. Это необязательная настройка" + ], + "The metadata_params in Extra field is not configured correctly. The key %(key)s is invalid.": [ + "" + ], + "The metadata_params in Extra field is not configured correctly. The key %{key}s is invalid.": [ + "" + ], + "The metadata_params object gets unpacked into the sqlalchemy.MetaData call.": [ + "Объект metadata_params вызывает sqlalchemy.MetaData" + ], + "The minimum number of rolling periods required to show a value. For instance if you do a cumulative sum on 7 days you may want your \"Min Period\" to be 7, so that all data points shown are the total of 7 periods. This will hide the \"ramp up\" taking place over the first 7 periods": [ + "Минимальное количество скользящих периодов, необходимое для отображения значения. Например, если вы делаете накопительную сумму за 7 дней, вы можете указать, чтобы \"Минимальный период\" был равен 7, так что все показанные точки данных представляют собой общее количество 7 периодов." + ], + "The number color \"steps\"": ["Количество цветов в цветовой схеме"], + "The number of hours, negative or positive, to shift the time column. This can be used to move UTC time to local time.": [ + "Количество часов, отрицательное или положительное, для сдвига столбца формата дата/время. Это может быть использовано для приведения часового пояса UTC к местному времени." + ], + "The number of results displayed is limited to %(rows)d by the configuration DISPLAY_MAX_ROWS. Please add additional limits/filters or download to csv to see more rows up to the %(limit)d limit.": [ + "Количество отображаемых результатов ограничено %(rows)d переменной DISPLAY_MAX_ROWS. Пожалуйста, добавьте дополнительные ограничения/фильтры или загрузите в csv, чтобы увидеть больше строк до предела %(limit)d." + ], + "The number of results displayed is limited to %(rows)d. Please add additional limits/filters, download to csv, or contact an admin to see more rows up to the %(limit)d limit.": [ + "Количество отображаемых результатов ограничено %(rows)d. Пожалуйста, добавьте дополнительные ограничения/фильтры или загрузите в csv, чтобы увидеть больше строк до предела %(limit)d.\"" + ], + "The number of rows displayed is limited to %(rows)d by the limit dropdown.": [ + "Количество отображаемых строк ограничено: не более %(rows)d." + ], + "The number of rows displayed is limited to %(rows)d by the query": [ + "Количество отображаемых строк ограничено: не более %(rows)d." + ], + "The number of rows displayed is limited to %(rows)d by the query and limit dropdown.": [ + "Количество отображаемых строк ограничено: не более %(rows)d." + ], + "The number of seconds before expiring the cache": [ + "Количество секунд до истечения срока действия кэша" + ], + "The object does not exist in the given database.": [ + "Объект не существует в этой базе данных." + ], + "The parameter %(parameters)s in your query is undefined.": [ + "Параметр %(parameters)s в вашем запросе неопределен.", + "Следующие параметры неопределены в вашем запросе: %(parameters)s", + "Следующие параметры неопределены в вашем запросе: %(parameters)s" + ], + "The password provided for username \"%(username)s\" is incorrect.": [ + "Неверный пароль для пользователя \"%(username)s\"." + ], + "The password provided when connecting to a database is not valid.": [ + "Неверный пароль для базы данных." + ], + "The passwords for the databases below are needed in order to import them together with the charts. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "Для баз данных нужны пароли, чтобы импортировать их вместе с графиками. Пожалуйста, обратите внимание, что разделы \"Безопасность\" и \"Утверждение\" в настройках конфигурации базы данных отсутствуют в экспортируемых файлов и должны быть добавлены вручную после импорта, если необходимо." + ], + "The passwords for the databases below are needed in order to import them together with the dashboards. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "Для баз данных нужны пароли, чтобы импортировать их вместе с дашбордами. Пожалуйста, обратите внимание, что разделы \"Безопасность\" и \"Утверждение\" в настройках конфигурации базы данных отсутствуют в экспортируемых файлах и должны быть добавлены вручную после импорта, если необходимо." + ], + "The passwords for the databases below are needed in order to import them together with the datasets. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "Пароли к базам данных требуются, чтобы импортировать их вместе с датасетами. Пожалуйста, обратите внимание, что разделы \"Безопасность\" и \"Утверждение\" конфигурации базы данных отсутствуют в экспортируемых файлах и должны быть добавлены после импорта вручную, если необходимо." + ], + "The passwords for the databases below are needed in order to import them together with the saved queries. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "Для баз данных нужны пароли, чтобы импортировать их вместе с сохраненными запросами. Пожалуйста, обратите внимание, что разделы \"Безопасность\" и \"Утверждение\" в настройках конфигурации базы данных отсутствуют в экспортируемых файлах и должны быть добавлены вручную после импорта, если необходимо." + ], + "The passwords for the databases below are needed in order to import them. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in explore files and should be added manually after the import if they are needed.": [ + "Пароли к базам данных требуются, чтобы импортировать их. Пожалуйста, обратите внимание, что разделы \"Безопасность\" и \"Утверждение\" в настройках конфигурации базы данных отсутствуют в импортируемых файлах и должны быть добавлены вручную после импорта, если необходимо." + ], + "The pattern of timestamp format. For strings use ": [ + "Шаблон формата отметки времени (таймштампа). Для строк используйте " + ], + "The periodicity over which to pivot time. Users can provide\n \"Pandas\" offset alias.\n Click on the info bubble for more details on accepted \"freq\" expressions.": [ + "Периодичность для группировки по времени. Пользователи могут задавать собственную частоту. Для этого нажмите на иконку с информацией." + ], + "The pixel radius": ["Радиус ячейки (в пикселях)"], + "The pointer to a physical table (or view). Keep in mind that the chart is associated to this Superset logical table, and this logical table points the physical table referenced here.": [ + "Указатель на физическую таблицу (или представление). Следует помнить, что график связан с логической таблицей Superset, а эта логическая таблица указывает на физическую таблицу, указанную здесь." + ], + "The port is closed.": ["Порт закрыт."], + "The port number is invalid.": ["Недействительный порт."], + "The primary metric is used to define the arc segment sizes": [ + "Основная мера используется для определения размера сегмента дуги" + ], + "The provided `rows` argument is not a valid integer.": [""], + "The query associated with the results was deleted.": [ + "Запрос, связанный с результатами, был удален." + ], + "The query associated with these results could not be found. You need to re-run the original query.": [ + "" + ], + "The query contains one or more malformed template parameters.": [""], + "The query couldn't be loaded": ["Запрос невозможно загрузить"], + "The query has a syntax error.": ["Запрос имеет синтаксическую ошибку."], + "The query returned no data": ["Запрос не вернул данных"], + "The query was killed after %(sqllab_timeout)s seconds. It might be too complex, or the database might be under heavy load.": [ + "Запрос был прерван после %(sqllab_timeout)s секунд. Он мог быть слишком сложным, или база данных находилась под большой нагрузкой." + ], + "The radius (in pixels) the algorithm uses to define a cluster. Choose 0 to turn off clustering, but beware that a large number of points (>1000) will cause lag.": [ + "" + ], + "The radius of individual points (ones that are not in a cluster). Either a numerical column or `Auto`, which scales the point based on the largest cluster": [ + "Радиус маркеров (не находящихся в кластере). Выберите числовой столбец или `Автоматически`, который отмасштабирует маркеры по наибольшему маркеру." + ], + "The report has been created": ["Рассылка создана"], + "The results backend no longer has the data from the query.": [ + "Сервер не сохранил данные из этого запроса." + ], + "The results stored in the backend were stored in a different format, and no longer can be deserialized.": [ + "Данные, сохраненные на сервере, имели другой формат, и не могут быть распознаны." + ], + "The rich tooltip shows a list of all series for that point in time": [ + "Расширенная всплывающая подсказка показывает список всех категорий для этой точки." + ], + "The schema \"%(schema)s\" does not exist. A valid schema must be used to run this query.": [ + "" + ], + "The schema \"%(schema_name)s\" does not exist. A valid schema must be used to run this query.": [ + "" + ], + "The schema was deleted or renamed in the database.": [ + "Схема была удалена или переименована в базе данных." + ], + "The size of the square cell, in pixels": [ + "Размер квадратной ячейки (в пикселях)" + ], + "The submitted URL is not considered safe, only use URLs with the same domain as Superset.": [ + "" + ], + "The submitted payload has the incorrect format.": [ + "Загруженные данные имеют некорректный формат." + ], + "The submitted payload has the incorrect schema.": [ + "Загруженные данные имеют некорректную схему." + ], + "The table \"%(table)s\" does not exist. A valid table must be used to run this query.": [ + "Таблица \"%(table)s\" не существует. Для выполнения запроса должна использоваться существующая таблица" + ], + "The table \"%(table_name)s\" does not exist. A valid table must be used to run this query.": [ + "Таблица \"%(table_name)s\" не существует. Для выполнения запроса должна использоваться существующая таблица" + ], + "The table was created. As part of this two-phase configuration process, you should now click the edit button by the new table to configure it.": [ + "" + ], + "The table was deleted or renamed in the database.": [ + "Таблица была удалена или переименована в базе данных." + ], + "The time column for the visualization. Note that you can define arbitrary expression that return a DATETIME column in the table. Also note that the filter below is applied against this column or expression": [ + "Столбец данных формата дата/время. Вы можете определить произвольное выражение, которое будет возвращать столбец даты/времени в таблице. Фильтр ниже будет применён к этому столбцу или выражению" + ], + "The time granularity for the visualization. Note that you can type and use simple natural language as in `10 seconds`, `1 day` or `56 weeks`": [ + "Интервал времени, в границах которого строится график. Обратите внимание, что для определения диапазона времени, вы можете использовать естественный язык. Например, можно указать словосочетания - «10 seconds», «1 day» или «56 weeks»" + ], + "The time granularity for the visualization. Note that you can type and use simple natural language as in `10 seconds`,`1 day` or `56 weeks`": [ + "Интервал времени, в границах которого строится график. Обратите внимание, что для определения диапазона времени, вы можете использовать естественный язык. Например, можно указать словосочетания - «10 seconds», «1 day» или «56 weeks»" + ], + "The time granularity for the visualization. This applies a date transformation to alter your time column and defines a new time granularity. The options here are defined on a per database engine basis in the Superset source code.": [ + "Детализация времени для визуализации. Применяется преобразование столбца с датой/временем и определяется новая детализация (минута, день, год, и т.п.). Доступные варианты заданы в исходном коде Superset для каждого типа драйвера базы данных." + ], + "The time range for the visualization. All relative times, e.g. \"Last month\", \"Last 7 days\", \"now\", etc. are evaluated on the server using the server's local time (sans timezone). All tooltips and placeholder times are expressed in UTC (sans timezone). The timestamps are then evaluated by the database using the engine's local timezone. Note one can explicitly set the timezone per the ISO 8601 format if specifying either the start and/or end time.": [ + "Временной интервал для визуализации. Относительно время, например, \"Последний месяц\", \"Последние 7 дней\" и т.д. рассчитываются на сервере, используя локальное время сервера. Обратите внимание, что вы можете самостоятельно задать часовой пояс по формату ISO 8601 при пользовательской настройке, задав время начала и/или конца." + ], + "The time unit for each block. Should be a smaller unit than domain_granularity. Should be larger or equal to Time Grain": [ + "Единица времени для каждого подблока. Должна быть меньшей единицей, чем единица времени блока. Должно быть больше или равно единице времени" + ], + "The time unit used for the grouping of blocks": [ + "Единица времени для группировки блоков" + ], + "The type of visualization to display": [ + "Выберите необходимый тип визуализации" + ], + "The unit of measure for the specified point radius": [ + "Единица измерения для указанного радиуса маркера" + ], + "The user seems to have been deleted": [ + "Пользователь, похоже, был удален" + ], + "The username \"%(username)s\" does not exist.": [ + "Пользователь \"%(username)s\" не существует." + ], + "The username provided when connecting to a database is not valid.": [ + "Имя пользователя, указанное при подключении к базе данных, недействительно" + ], + "The way the ticks are laid out on the X-axis": [ + "Способ расположения делений по оси X" + ], + "The width of the lines": ["Ширина линий"], + "There are associated alerts or reports": [ + "Есть связанные оповещения или отчеты" + ], + "There are associated alerts or reports: %s,": [ + "Есть связанные оповещения или отчеты: %s" + ], + "There are no charts added to this dashboard": [ + "В этот дашборд еще не добавлен ни один график." + ], + "There are no components added to this tab": [ + "В этой вкладке нет компонентов" + ], + "There are no databases available": ["Нет доступных баз данных"], + "There are no filters in this dashboard.": [ + "В этом дашборде нет фильтров." + ], + "There are unsaved changes.": ["У вас есть несохраненные изменения."], + "There is a syntax error in the SQL query. Perhaps there was a misspelling or a typo.": [ + "В SQL-запросе имеется синтаксическая ошибка. Возможно, это орфографическая ошибка или опечатка." + ], + "There is no chart definition associated with this component, could it have been deleted?": [ + "С этим компонентом не связан ни один график, возможно, он был удален." + ], + "There is not enough space for this component. Try decreasing its width, or increasing the destination width.": [ + "Недостаточно пространства для этого компонента. Попробуйте уменьшить ширину или увеличить целевую ширину." + ], + "There was an error fetching the favorite status: %s": [ + "Произошла ошибка при получении статуса избранного: %s" + ], + "There was an error fetching your recent activity:": [ + "Произошла ошибка при получении вашей недавней активности:" + ], + "There was an error loading the dataset metadata": [ + "Возникла ошибка при загрузке метаданных датасета" + ], + "There was an error loading the schemas": [ + "Возникла ошибка при загрузке схем" + ], + "There was an error loading the tables": [ + "Возникла ошибка при загрузке таблиц" + ], + "There was an error saving the favorite status: %s": [ + "Произошла ошибка при сохранении статуса избранного: %s" + ], + "There was an error with your request": [ + "Произошла ошибка с вашим запросом" + ], + "There was an issue deleting %s: %s": [ + "Произошла ошибка при удалении %s: %s" + ], + "There was an issue deleting the selected %s: %s": [ + "Произошла ошибка при удалении выбранных %s: %s" + ], + "There was an issue deleting the selected annotations: %s": [ + "Произошла ошибка при удалении выбранных аннотаций: %s" + ], + "There was an issue deleting the selected charts: %s": [ + "Произошла ошибка при удалении выбранных графиков: %s" + ], + "There was an issue deleting the selected dashboards: ": [ + "Произошла ошибка при удалении выбранных дашбордов: " + ], + "There was an issue deleting the selected datasets: %s": [ + "Произошла ошибка при удалении выбранных датасетов: %s" + ], + "There was an issue deleting the selected layers: %s": [ + "Произошла ошибка при удалении выбранных слоёв: %s" + ], + "There was an issue deleting the selected queries: %s": [ + "Произошла ошибка при удалении выбранных запросов: %s" + ], + "There was an issue deleting the selected templates: %s": [ + "Произошла ошибка при удалении выбранных шаблонов: %s" + ], + "There was an issue deleting: %s": ["Произошла ошибка при удалении: %s"], + "There was an issue duplicating the dataset.": [ + "Произошла ошибка при дублировании датасета." + ], + "There was an issue duplicating the selected datasets: %s": [ + "Произошла ошибка при дублировании выбранных датасетов: %s" + ], + "There was an issue favoriting this dashboard.": [ + "Произошла ошибка при добавлении этого дашборда в избранное." ], - "Select ...": ["Выбрать …"], - "Loaded data cached": ["Данные были загружены в кэш"], - "Loaded from cache": ["Загружается из кэша"], - "Click to force-refresh": ["Нажмите для принудительного обновления"], - "cached": [""], - "Certified by %s": ["Сертифицирован: %s"], - "Copy to clipboard": ["Скопировать в буфер обмена"], - "Copied!": ["Скопировано!"], - "Sorry, your browser does not support copying. Use Ctrl / Cmd + C!": [ - "Извините, Ваш браузер не поддерживание копирование. Используйте сочетание клавиш [CTRL + C] для WIN или [CMD + C] для MAC!" + "There was an issue fetching reports attached to this dashboard.": [ + "Произошла ошибка с получением рассылок, связанных с этим дашбордом." ], - "Error while fetching schema list": ["Ошибка при получении списка схем"], - "Error while fetching database list": [ - "Ошибка при получении списка баз данных" - ], - "Database:": ["База данных:"], - "Select a database": ["Выберите базу данных"], - "Force refresh schema list": ["Принудительное обновление данных"], - "Select a schema (%s)": ["Выберите схему (%s)"], - "Schema:": ["Схема:"], - "datasource": ["источник данных"], - "schema": ["схема"], - "delete": ["удалить"], - "Type \"%s\" to confirm": ["Введите “%s” для подтверждения"], - "DELETE": ["DELETE"], - "Click to edit": ["Нажмите для редактирования"], - "You don't have the rights to alter this title.": [ - "Недостаточно прав для изменения заголовка." + "There was an issue fetching the favorite status of this dashboard.": [ + "Произошла ошибка с получением статуса избранного для этого дашборда." ], - "Unexpected error": ["Неожиданная ошибка"], - "Click to favorite/unfavorite": ["Отметить как избранное"], - "An error occurred while fetching dashboards": [ - "Произошла ошибка при создании источника данных" + "There was an issue fetching your chart: %s": [ + "Произошла ошибка при получении вашего графика: %s" ], - "Error while fetching table list": ["Ошибка при получении списка таблиц"], - "Select table or type table name": [""], - "Type to search ...": ["Введите для поиска…"], - "Select table ": ["Выберите таблицу "], - "Force refresh table list": ["Принудительное обновление данных"], - "See table schema": ["Выберите схему (%s)"], - "%s%s": [""], - "Share dashboard": ["Поделиться"], - "This may be triggered by:": ["Триггеры:"], - "Please reach out to the Chart Owner for assistance.": [ - "Пожалуйста, обратитесь к создателю графика за дополнительной информацией." + "There was an issue fetching your dashboards: %s": [ + "Произошла ошибка при получении вашего дашборда: %s" ], - "Chart Owner: %s": ["Параметры графика: %s"], - "%s Error": ["%s Ошибка"], - "See more": ["Подробности"], - "See less": ["Скрыть подробности"], - "Copy message": ["Предупреждающее сообщение"], - "Close": ["Закрыть"], - "This was triggered by:": ["Причина срабатывания:"], - "Did you mean:": [""], - "%(suggestion)s instead of \"%(undefinedParameter)s?\"": [""], - "Parameter error": ["Параметры"], - "We’re having trouble loading this visualization. Queries are set to timeout after %s second.": [ - "Возникла проблема при загрузке этой визуализации. Для запросов установлен тайм-аут %s секунд." + "There was an issue fetching your recent activity: %s": [ + "Произошла ошибка при получении вашей последней активности: %s" ], - "We’re having trouble loading these results. Queries are set to timeout after %s second.": [ - "Возникла проблема при загрузке результатов. Для запросов установлен тайм-аут %s секунд." + "There was an issue fetching your saved queries: %s": [ + "Произошла ошибка при получении ваших сохраненных запросов: %s" ], - "Timeout error": ["Тайм-аут"], - "Cell content": ["Созданный контент"], - "The import was successful": ["Неудачно"], - "OVERWRITE": ["OVERWRITE"], - "Overwrite": ["Перезаписать"], - "Import": ["Импорт"], - "Import %s": ["Импорт %s"], - "Last Updated %s": [""], - "%s Selected": ["%s Выбрано"], - "Deselect all": ["Выберите базу данных"], - "%s-%s of %s": [""], - "Settings": ["Настройки"], - "About": [""], - "SQL query": ["SQL-запрос"], - "There is not enough space for this component. Try decreasing its width, or increasing the destination width.": [ - "Недостаточно пространства для этого компонента. Попробуйте уменьшить ширину или увеличить целевую ширину." + "There was an issue previewing the selected query %s": [ + "Произошла ошибка при предпросмотре выбранного запроса %s" ], - "Can not move top level tab into nested tabs": [ - "Невозможно перенести вкладку верхнего уровня во вложенную вкладку" + "There was an issue previewing the selected query. %s": [ + "Произошла ошибка при предпросмотре выбранного запроса: %s" ], - "This chart has been moved to a different filter scope.": [ - "Этот график был перемещён в другой набор фильтров." + "There's a loop in your Sankey, please provide a tree. Here's a faulty link: {}": [ + "" ], - "There was an issue fetching the favorite status of this dashboard.": [ - "К сожалению, произошла ошибка при загрузке виджета." + "These are the tables this filter will be applied to.": [ + "Это таблицы, к которым будет применен этот фильтр." ], - "There was an issue favoriting this dashboard.": [ - "Произошла ошибка при добавлении этого дашборда в избранное." + "These filters apply to the values available in the dropdowns": [ + "Эти фильтры применяются к значениям, доступным в выпадающих списках" ], - "This dashboard is now ${nowPublished}": [ - "Этот дашборд теперь ${nowPublished}" + "These parameters are generated dynamically when clicking the save or overwrite button in the explore view. This JSON object is exposed here for reference and for power users who may want to alter specific parameters.": [ + "Эти параметры генерируются автоматически при нажатии кнопки сохранения. Опытные пользователи могут изменить определенные объекты в формате JSON." ], - "You do not have permissions to edit this dashboard.": [ - "У вас нет прав на редактирование этого дашборда: %(name)s." + "This JSON object is generated dynamically when clicking the save or overwrite button in the dashboard view. It is exposed here for reference and for power users who may want to alter specific parameters.": [ + "Этот JSON-объект генерируется автоматически при сохранении или перезаписи дашборда. Он размещён здесь справочно и для опытных пользователей." ], - "This dashboard was saved successfully.": ["Дашборд успешно сохранен."], - "Could not fetch all saved charts": [""], - "Sorry there was an error fetching saved charts: ": [ - "Извините, произошла ошибка при загрузке графиков: " + "This action will permanently delete %s.": [ + "Это действие навсегда удалит %s." ], - "Visualization": ["Визуализация"], - "Data source": ["Источник данных"], - "Added": ["Добавлено"], - "Components": ["Компоненты"], - "Any color palette selected here will override the colors applied to this dashboard's individual charts": [ - "Любая палитра, выбранная здесь, будет перезаписывать цвета, применённые к отдельным графикам этого дашборда" + "This action will permanently delete the layer.": [ + "Это действие навсегда удалит слой." ], - "Color scheme": ["Цветовая схема"], - "Load a template": ["Загрузить шаблон"], - "Load a CSS template": ["Загрузить шаблон стилей (CSS)"], - "Live CSS editor": ["Редактор CSS"], - "You have unsaved changes.": ["У вас есть несохраненные изменения."], - "This dashboard is currently force refreshing; the next force refresh will be in %s.": [ - "Для этого дашборда включено обновление; следующее обновление будет через %s." + "This action will permanently delete the saved query.": [ + "Это действие навсегда удалит сохранённый запрос." ], - "Your dashboard is too large. Please reduce the size before save it.": [ - "Дашборд слишком большой. Пожалуйста, уменьшите его размер перед сохранением." + "This action will permanently delete the template.": [ + "Это действие навсегда удалит шаблон." ], - "Discard changes": ["Отменить изменения"], - "An error occurred while fetching available CSS templates": [ - "Произошла ошибка при получении доступных CSS-шаблонов" + "This can be either an IP address (e.g. 127.0.0.1) or a domain name (e.g. mydatabase.com).": [ + "Это может быть как IP адрес (например, 127.0.0.1), так и доменное имя (например, моябазаданных.рф)." ], - "Superset dashboard": ["Дашборд Superset"], - "Check out this dashboard: ": ["Посмотреть дашборд: "], - "Refresh dashboard": ["Обновить дашборд"], - "Set auto-refresh interval": ["Интервал обновления"], - "Set filter mapping": ["Установить действие фильтра"], - "Edit dashboard properties": ["Редактировать свойства дашборда"], - "Edit CSS": ["Редактировать CSS"], - "Download as image": ["Сохранить как изображение"], - "Toggle fullscreen": ["Полноэкранный режим"], - "There is no chart definition associated with this component, could it have been deleted?": [ + "This chart has been moved to a different filter scope.": [ + "Этот график был перемещён в другой набор фильтров." + ], + "This chart is managed externally, and can't be edited in Superset": [""], + "This chart might be incompatible with the filter (datasets don't match)": [ + "Этот график может быть несовместим с этим фильтром (датасеты не совпадают)" + ], + "This chart type is not supported when using an unsaved query as a chart source. ": [ "" ], - "Delete this container and save to remove this message.": [ - "Удалите этот контейнер и сохраните изменения, чтобы убрать это сообщение." + "This color scheme is being overriden by custom label colors.\n Check the JSON metadata in the Advanced settings": [ + "" ], - "An error has occurred": ["Произошла ошибка"], - "You do not have permission to edit this dashboard": [ - "У вас нет доступа к этому источнику данных" + "This column might be incompatible with current dataset": [ + "Этот график может быть несовместим с этим датасетом" ], - "A valid color scheme is required": [ - "Требуется корректная цветовая схема" + "This column must contain date/time information.": [ + "В этом столбец должны быть данные формата дата/время." ], - "The dashboard has been saved": ["Дашборд сохранен"], - "Apply": ["Применить"], - "Dashboard properties": ["Свойства дашборда"], - "Basic information": ["Основная информация"], - "URL slug": ["Читаемый URL"], - "A readable URL for your dashboard": ["Читаемый URL-адрес для дашборда"], - "Access": ["Доступ"], - "Owners is a list of users who can alter the dashboard. Searchable by name or username.": [ - "Владельцы - это список пользователей, которые могут изменять дашборд." + "This controls whether the \"time_range\" field from the current\n view should be passed down to the chart containing the annotation data.": [ + "Должен ли временной интервал из этого представления переписать временной интервал графика, содержащего данные аннотации." ], - "Colors": ["Цвета"], - "Advanced": ["Дополнительно"], - "JSON metadata": ["JSON метаданные"], - "This dashboard is not published, it will not show up in the list of dashboards. Click here to publish this dashboard.": [ - "Этот дашборд не опубликован, он не будет отображён в списке дашбордов. Нажмите здесь, чтобы опубликовать этот дашборд." + "This controls whether the time grain field from the current\n view should be passed down to the chart containing the annotation data.": [ + "Должен ли единица времени из этой таблицы переписать единицу времени графика." + ], + "This dashboard is currently auto refreshing; the next auto refresh will be in %s.": [ + "В настоящий момент дашборд обновляется; следующее обновление будет через %s" + ], + "This dashboard is managed externally, and can't be edited in Superset": [ + "" ], "This dashboard is not published which means it will not show up in the list of dashboards. Favorite it to see it there or access it by using the URL directly.": [ "Этот дашборд не опубликован, что означает, что он не будет отображён в списке дашбордов. Добавьте его в избранное, чтобы увидеть там или воспользуйтесь доступом по прямой ссылке." ], + "This dashboard is not published, it will not show up in the list of dashboards. Click here to publish this dashboard.": [ + "Этот дашборд не опубликован, он не будет отображён в списке дашбордов. Нажмите, чтобы опубликовать этот дашборд." + ], + "This dashboard is now hidden": ["Дашборд теперь скрыт"], + "This dashboard is now published": ["Дашборд теперь опубликован"], "This dashboard is published. Click to make it a draft.": [ "Дашборд опубликован. Нажмите, чтобы сделать черновиком." ], - "Draft": ["Черновик"], - "Don't refresh": ["Не обновлять"], - "10 seconds": ["10 секунд"], - "30 seconds": ["30 секунд"], - "1 minute": ["1 минута"], - "5 minutes": ["5 минут"], - "30 minutes": ["30 минут"], - "1 hour": ["1 час"], - "6 hours": ["6 часов"], - "12 hours": ["12 часов"], - "24 hours": ["24 часа"], - "Refresh interval": ["Интервал обновления"], - "Refresh frequency": ["Частота"], - "Are you sure you want to proceed?": [ - "Вы уверены, что хотите продолжить?" + "This dashboard is ready to embed. In your application, pass the following id to the SDK:": [ + "" ], - "Save for this session": [""], - "You must pick a name for the new dashboard": [ - "Вы должны выбрать имя для нового дашборда" + "This dashboard was changed recently. Please reload dashboard to get latest version.": [ + "Этот дашборд был недавно изменен. Пожалуйста, обновите дашборд, чтобы увидеть изменения." ], - "Save dashboard": ["Сохранить дашборд"], - "Overwrite Dashboard [%s]": ["Перезаписать дашборд [%s]"], - "Save as:": ["Сохранить как:"], - "[dashboard name]": ["[название]"], - "also copy (duplicate) charts": [""], - "Filter your charts": ["Фильтровать графики"], - "Annotation layers are still loading.": ["Слои аннотаций загружаются."], - "One ore more annotation layers failed loading.": [ - "Один или несколько слоев аннотации не удалось загрузить." + "This dashboard was saved successfully.": ["Дашборд успешно сохранен"], + "This database is managed externally, and can't be edited in Superset": [ + "Эта база данных управляется извне и не может быть изменена в Суперсете" ], - "Cached %s": [""], - "Fetched %s": [""], - "Minimize chart": ["Свернуть график"], - "Maximize chart": ["Развернуть график"], - "Force refresh": ["Принудительное обновление"], - "Toggle chart description": ["Изменить описание графика"], - "View chart in Explore": ["Посмотреть график в режиме исследования"], - "Share chart": ["Поделиться графиком"], - "Export CSV": ["Экпспорт CSV"], - "Applied Filters (%d)": ["Применено фильтров (%d)"], - "Incompatible Filters (%d)": ["Несовместимые фильтры (%d)"], - "Unset Filters (%d)": ["Сбросить фильтры (%d)"], - "Search...": ["Поиск…"], - "No filter is selected.": ["Не выбраны фильтры."], - "Editing 1 filter:": [""], - "Batch editing %d filters:": [""], - "Configure filter scopes": ["Настроить области действия фильтра"], - "There are no filters in this dashboard.": [ - "В этом дашборде нет фильтров." + "This database table does not contain any data. Please select a different table.": [ + "" + ], + "This dataset is managed externally, and can't be edited in Superset": [ + "Этот датасет управляется извне и не может быть изменена в Суперсете" + ], + "This defines the element to be plotted on the chart": [ + "Элемент, который будет отражен на графике" + ], + "This defines the level of the hierarchy": [ + "Определяет уровень иерархии" + ], + "This fields acts a Superset view, meaning that Superset will run a query against this string as a subquery.": [ + "" + ], + "This filter doesn't exist in dashboard. It will not be applied.": [ + "Этот фильтр не существует в дашборде. Он не будет применен." + ], + "This filter is the last temporal filter. If you proceed,\n this chart won't be affected by time range filters in dashboards.": [ + "" + ], + "This filter might be incompatible with current dataset": [ + "Этот фильтр может быть несовместим с этим датасетом" + ], + "This filter set is identical to: \"%s\"": [ + "Этот набор фильтров идентичен \"%s\"" + ], + "This functionality is disabled in your environment for security reasons.": [ + "Эта функция отключена в вашей среде по соображениям безопасности." + ], + "This is the condition that will be added to the WHERE clause. For example, to only return rows for a particular client, you might define a regular filter with the clause `client_id = 9`. To display no rows unless a user belongs to a RLS filter role, a base filter can be created with the clause `1 = 0` (always false).": [ + "Это условие, которое будет добавлено к оператору WHERE. Например, чтобы возвращать строки только для определенного клиента, вы можете определить обычный фильтр с условием `client_id = 9`. Чтобы не отображать строки, если пользователь не принадлежит к роли фильтра RLS, можно создать базовый фильтр с предложением `1 = 0` (всегда false)." + ], + "This json object describes the positioning of the widgets in the dashboard. It is dynamically generated when adjusting the widgets size and positions by using drag & drop in the dashboard view": [ + "Этот JSON объект описывает расположение графиков в дашборде. Он генерируется динамически при изменении и перемещении графиков в дашборде." ], - "Expand all": ["Развернуть всё"], - "Collapse all": ["Свернуть всё"], "This markdown component has an error.": [ "Этот компонент содержит ошибки." ], "This markdown component has an error. Please revert your recent changes.": [ "Этот компонент содержит ошибки. Пожалуйста, отмените последние изменения." ], - "Delete dashboard tab?": ["Удалить вкладку дашборда?"], - "Divider": ["Разделитель"], - "Header": ["Строка заголовков"], - "Row": ["Строка"], - "Tabs": ["Вкладки"], - "Preview": ["Предпросмотр %s"], - "Yes, cancel": ["Да, отменить"], - "Keep editing": ["Продолжить редактирование"], - "Select parent filters": ["Выберите дату окончания"], - "Reset all": ["Сбросить текущее состояние"], - "You have removed this filter.": ["Вы удалили фильтр."], - "Restore filter": ["Фильтр результатов"], - "Filter name": ["Значение фильтра"], - "Name is required": ["Имя обязательно"], - "Datasource is required": ["Источники данных"], - "Field": ["Поле"], - "Parent filter": ["Временной фильтр"], - "None": [""], - "Apply changes instantly": ["Мгновенно применять изменения"], - "Allow multiple selections": ["Разрешить множественный фильтр"], - "Inverse selection": ["Инвертировать выбор"], - "Required": ["Обязательно"], - "Are you sure you want to cancel?": ["Вы уверены, что хотите отменить?"], - "will not be saved.": ["не будет сохранён."], - "Filter configuration and scoping": ["Фильтруемые срезы"], - "Add filter": ["Добавить фильтр"], - "(Removed)": ["(Удалено)"], - "Undo?": ["Отменить?"], - "Scoping": [""], - "Apply to all panels": ["Применить ко всем панелям"], - "Apply to specific panels": ["Применить к выбранным панелям"], - "Only selected panels will be affected by this filter": [ - "Фильтр будет применён только к выбранным панелям" + "This may be triggered by:": ["Возможные причины:"], + "This metric might be incompatible with current dataset": [ + "Эта мера может быть несовместима с этим датасетом" ], - "All panels with this column will be affected by this filter": [ - "Фильтр будет применён ко всем панелям с этим столбцом" + "This section contains options that allow for advanced analytical post processing of query results": [ + "В этом разделе содержатся параметры, которые позволяют производить аналитическую постобработку результатов запроса" ], - "All filters": ["Фильтры"], - "All charts": ["Все графики"], - "Warning! Changing the dataset may break the chart if the metadata does not exist.": [ - "Внимание! Изменение датасета может привести к тому, что график станет нерабочим, если будут отсутствовать метаданные." + "This section contains validation errors": [ + "В этом разделе содержатся ошибки валидации" ], - "Changing the dataset may break the chart if the chart relies on columns or metadata that does not exist in the target dataset": [ - "Изменения датасета может привести к тому, что график станет нерабочим, если график использует несуществующие в целевом датасете столбцы или метаданные" + "This session has encountered an interruption, and some controls may not work as intended. If you are the developer of this app, please check that the guest token is being generated correctly.": [ + "" ], - "dataset": ["датасет"], - "Change dataset": ["Выберите источник данных"], - "Warning!": ["Предупреждение!"], - "Search / Filter": ["Поиск / Фильтр"], - "Physical (table or view)": ["Физический (таблица или представление)"], - "Virtual (SQL)": ["Виртуальный (SQL)"], - "SQL expression": ["Выражение SQL"], - "Data type": ["Таблица Данных"], - "Datetime format": ["Формат Datetime"], - "The pattern of timestamp format. For strings use ": [""], - "Python datetime string pattern": [""], - " expression which needs to adhere to the ": [""], - "ISO 8601": ["ISO 8601"], - " standard to ensure that the lexicographical ordering\n coincides with the chronological ordering. If the\n timestamp format does not adhere to the ISO 8601 standard\n you will need to define an expression and type for\n transforming the string into a date or timestamp. Note\n currently time zones are not supported. If time is stored\n in epoch format, put `epoch_s` or `epoch_ms`. If no pattern\n is specified we fall back to using the optional defaults on a per\n database/column name level via the extra parameter.": [ + "This table already has a dataset": [""], + "This table already has a dataset associated with it. You can only associate one dataset with a table.\n": [ "" ], - "Is dimension": ["Измерение"], - "Is filterable": ["Фильтрующийся"], - "Modified columns: %s": ["Изменённые столбцы: %s"], - "Removed columns: %s": ["Удалённые столбцы: %s"], - "New columns added: %s": ["Добавленные столбцы: %s"], - "Metadata has been synced": ["Метаданные синхронизированы"], - "Column name [%s] is duplicated": ["Дубль имени столбца [%s]"], - "Metric name [%s] is duplicated": ["Дубль имения показателя [%s]"], - "Calculated column [%s] requires an expression": [ - "Для расчётного столбца [%s] требуется выражение" + "This value should be greater than the left target value": [ + "Это значение должно быть больше чем левое целевое значение" ], - "Basic": [""], - "Default URL": ["URL базы данных"], - "Default URL to redirect to when accessing from the dataset list page": [ - "URL по-умолчанию, на который будет выполнен редирект при доступе из страницы со списком датасетов" + "This value should be smaller than the right target value": [ + "Это значение должно быть больше чем правое целевое значение" ], - "Autocomplete filters": [""], - "Whether to populate autocomplete filters options": [ - "Включить фильтр на определенный интервал/диапазон времени" + "This visualization type is not supported.": [ + "Этот тип визуализации не поддерживается." ], - "Autocomplete query predicate": ["Извлечь Значения Предиката"], - "When using \"Autocomplete filters\", this can be used to improve performance of the query fetching the values. Use this option to apply a predicate (WHERE clause) to the query selecting the distinct values from the table. Typically the intent would be to limit the scan by applying a relative time filter on a partitioned or indexed time-related field.": [ + "This was triggered by:": [ + "Причина срабатывания:", + "Причины срабатывания", + "Причины срабатывания" + ], + "This will remove your current embed configuration.": [""], + "Threshold alpha level for determining significance": [ + "Пороговый альфа-уровень для определения значимости" + ], + "Threshold value should be double precision number": [ + "Пороговое значение должно быть числом двойной точности" + ], + "Thumbnails": ["Миниатюры"], + "Thursday": ["Четверг"], + "Time": ["Время"], + "Time Column": ["Столбец даты/времени"], + "Time Comparison": ["Сравнение по времени"], + "Time Format": ["Формат даты/времени"], + "Time Grain": ["Единица времени"], + "Time Granularity": ["Гранулярность времени"], + "Time Lag": ["Временной лаг"], + "Time Range": ["Временной интервал"], + "Time Ratio": ["Соотношение времени"], + "Time Series": ["Временной ряд"], + "Time Series - Bar Chart": ["Столбчатая диаграмма (временные ряды)"], + "Time Series - Dual Axis Line Chart": [ + "Диаграмма с двумя осями (временные ряды)" + ], + "Time Series - Line Chart": ["Линейная диаграмма (временные ряды)"], + "Time Series - Nightingale Rose Chart": [ + "Диаграмма Найтингейл (временные ряды)" + ], + "Time Series - Paired t-test": ["Парный t-test (временные ряды)"], + "Time Series - Percent Change": ["Процентное изменение (временные ряды)"], + "Time Series - Stacked": ["Диаграмма с накоплением (временные ряды)"], + "Time Series Options": ["Настройки временных рядов"], + "Time Shift": ["Временной сдвиг"], + "Time column": ["Столбец даты/времени"], + "Time column \"%(col)s\" does not exist in dataset": [ + "Столбец формата дата/время \"%(col)s\" не существует в датасете" + ], + "Time column filter plugin": [""], + "Time comparison": ["Столбец с датой"], + "Time delta in natural language\n (example: 24 hours, 7 days, 56 weeks, 365 days)": [ + "Временной сдвиг на естественном языке (например: 24 hours, 7 days, 56 weeks, 365 days)" + ], + "Time delta is ambiguous. Please specify [%(human_readable)s ago] or [%(human_readable)s later].": [ + "Неоднозначный временной сдвиг. Пожалуйста, укажите [%(human_readable)s до] или [%(human_readable)s после]." + ], + "Time filter": ["Временной фильтр"], + "Time format": ["Формат даты/времени"], + "Time grain": ["Единица времени"], + "Time grain missing": ["Единица времени отсутствует"], + "Time granularity": ["Гранулярность времени"], + "Time in seconds": ["Время в секундах"], + "Time lag": ["Временной лаг"], + "Time range": ["Временной интервал"], + "Time ratio": ["Соотношение времени"], + "Time related form attributes": ["Параметры, связанные со временем"], + "Time series": ["Временной ряд"], + "Time series columns": ["Столбцы временных рядов"], + "Time shift": ["Временной сдвиг"], + "Time string is ambiguous. Please specify [%(human_readable)s ago] or [%(human_readable)s later].": [ + "Временная строка неоднозначна. Пожалуйста, укажите [%(human_readable)s до] или [%(human_readable)s после]." + ], + "Time-series Area Chart": ["Диаграмма с областями (временные ряды)"], + "Time-series Area chart are similar to line chart in that they represent variables with the same scale, but area charts stack the metrics on top of each other. An area chart in Superset can be stream, stack, or expand.": [ + "Диаграмма с наполнением похожа на линейную диаграмму тем, что они представляют переменные с одинаковым масштабом, но диаграммы с наполнением накладывают показатели друг на друга." + ], + "Time-series Bar Chart": ["Столбчатая диаграмма"], + "Time-series Bar Chart (legacy)": ["Столбчатая диаграмма (устарело)"], + "Time-series Bar Charts are used to show the changes in a metric over time as a series of bars.": [ + "Столбчатые диаграммы временных рядов используются для отображения изменений меры с течением времени в виде серии столбцов." + ], + "Time-series Chart": ["Диаграмма (временные ряды)"], + "Time-series Line Chart": ["Линейная диаграмма (временные ряды)"], + "Time-series Percent Change": ["Процентное изменение (временные ряды)"], + "Time-series Scatter Plot": ["Точечная Диаграмма"], + "Time-series Scatter Plot has time on the horizontal axis in linear units, and the points are connected in order. It shows a statistical relationship between two variables.": [ + "На горизонтальной оси Точечной диаграммы откладывается время в линейных единицах, а точки соединяются по порядку. Он показывает статистическую зависимость между двумя переменными." + ], + "Time-series Smooth Line": [ + "Плавная линейная диаграмма (временные ряды)" + ], + "Time-series Smooth-line is a variation of the line chart. Without angles and hard edges, Smooth-line sometimes looks smarter and more professional.": [ "" ], - "Extra data to specify table metadata. Currently supports certification data of the format: `{ \"certification\": { \"certified_by\": \"Data Platform Team\", \"details\": \"This table is the source of truth.\" } }`.": [ + "Time-series Stepped Line": ["Диаграмма шагов (временные ряды)"], + "Time-series Stepped-line graph (also called step chart) is a variation of line chart but with the line forming a series of steps between data points. A step chart can be useful when you want to show the changes that occur at irregular intervals.": [ "" ], - "Owners of the dataset": ["Владельцы датасета"], - "Cache timeout": ["Тайм-аут Кэша"], - "The duration of time in seconds before the cache is invalidated": [ - "Количество секунд до истечения срока действия кэша" + "Time-series Table": ["Таблица временных рядов"], + "Time-series line chart is used to visualize repeated measurements taken over regular time intervals. Line chart is a type of chart which displays information as a series of data points connected by straight line segments. It is a basic type of chart common in many fields.": [ + "Линейная диаграмма временных рядов используется для визуализации повторяющихся измерений, происходящих через регулярные промежутки времени. Линейная диаграмма - это тип диаграммы, который отображает информацию в виде ряда точек данных, соединенных прямыми отрезками. Это базовый тип диаграммы, распространенный во многих областях." + ], + "Timeout error": ["Ошибка таймаута"], + "Timestamp format": ["Формат даты и времени"], + "Timezone": ["Часовой пояс"], + "Timezone offset (in hours) for this datasource": [ + "Смещение часового пояса (в часах) для этого источника данных" + ], + "Timezone selector": ["Выбор часового пояса"], + "Tiny": ["Крошечный"], + "Title": ["Заголовок"], + "Title Column": ["Столбец с названием"], + "Title is required": ["Название обязательно"], + "Title or Slug": ["Название или читаемый URL"], + "To filter on a metric, use Custom SQL tab.": [ + "Для фильтрации по мере используйте вкладку Свой SQL." + ], + "To get a readable URL for your dashboard": [ + "Для получения читаемого URL-адреса дашборда" + ], + "Too many columns to filter": ["Слишком много столбцов для фильтрации"], + "Tools": ["Инструменты"], + "Tooltip": ["Всплывающая подсказка"], + "Tooltip sort by metric": ["Сортировка данных подсказки по мере"], + "Tooltip time format": ["Формат времени всплывающей подсказки"], + "Top": ["Сверху"], + "Top left": ["Сверху слева"], + "Top right": ["Сверху справа"], + "Top to Bottom": ["Сверху вниз"], + "Total (%(aggfunc)s)": [""], + "Total (%(aggregatorName)s)": [""], + "Total: %s": ["Итого: %s"], + "Totals": ["Общая сумма"], + "Track job": ["Отслеживать работу"], + "Transformable": ["Трансформируемый"], + "Transparent": ["Прозрачный"], + "Transpose Pivot": ["Транспонировать таблицу"], + "Transpose pivot": ["Транспонировать таблицу"], + "Tree Chart": ["Древовидная диаграмма"], + "Tree layout": ["Оформление дерева"], + "Tree orientation": ["Ориентация дерева"], + "Treemap": ["Плоское дерево"], + "Treemap (legacy)": ["Плоское дерево (устарело)"], + "Trend": ["Тенденция"], + "Triangle": ["Треугольник"], + "Trigger Alert If...": ["Оповестить, если..."], + "Truncate Axis": ["Настройка интервала оси"], + "Truncate Metric": ["Убрать имя меры"], + "Truncate Y Axis": ["Урезать интервал оси Y"], + "Truncate Y Axis. Can be overridden by specifying a min or max bound.": [ + "Уменьшить интервал по умолчанию для оси Y. Необходимо задать минимальную и максимальную границы. Обратите внимание, что некоторые линии могут пропасть из области видимости." + ], + "Truncate long cells to the \"min width\" set above": [""], + "Truncates the specified date to the accuracy specified by the date unit.": [ + "Усекает указанную дату с точностью, указанной в единице измерения даты." + ], + "Try applying different filters or ensuring your datasource has data": [ + "Попробуйте использовать другие фильтры или убедитесь, что в вашем источнике данных есть данные" + ], + "Try different criteria to display results.": [ + "Попробуйте использовать другии критерии фильтрации" + ], + "Try selecting a different schema": [""], + "Tuesday": ["Вторник"], + "Type": ["Тип"], + "Type \"%s\" to confirm": ["Введите \"%s\" для подтверждения"], + "Type a value": ["Введите значение"], + "Type a value here": ["Введите значение здесь"], + "Type is required": ["Поле обязательно"], + "Type of Google Sheets allowed": ["Допустимый тип Google Таблиц"], + "Type of comparison, value difference or percentage": [ + "Тип сравнения, разница значений или доля" + ], + "Type or Select [%s]": ["Введите или выберите [%s]"], + "UI Configuration": ["Конфигурация UI"], + "URL": ["Ссылка (URL)"], + "URL Parameters": ["Параметры URL"], + "URL parameters": ["Параметры URL"], + "URL slug": ["Читаемый URL"], + "Unable to add a new tab to the backend. Please contact your administrator.": [ + "Не удается добавить новую вкладку на сервер. Пожалуйста, свяжитесь с администратором." + ], + "Unable to connect to catalog named \"%(catalog_name)s\".": [""], + "Unable to connect to database \"%(database)s\".": [ + "Невозможно подключиться к базе данных \"%(database)s\"." + ], + "Unable to connect. Verify that the following roles are set on the service account: \"BigQuery Data Viewer\", \"BigQuery Metadata Viewer\", \"BigQuery Job User\" and the following permissions are set \"bigquery.readsessions.create\", \"bigquery.readsessions.getData\"": [ + "" + ], + "Unable to create chart without a query id.": [""], + "Unable to find such a holiday: [%(holiday)s]": [ + "Не удалось найти такой праздник: [%(holiday)s]" + ], + "Unable to load columns for the selected table. Please select a different table.": [ + "Не удалось загрузить столбцы для выбранной таблицы. Пожалуйста, выберите другую таблицу." + ], + "Unable to migrate query editor state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ + "Не удается перенести состояние редактора запроса на сервер. Суперсет повторит попытку позже. Пожалуйста, свяжитесь с вашим администратором, если эта проблема не устранена." + ], + "Unable to migrate query state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ + "Не удается перенести состояние запроса на сервер. Суперсет повторит попытку позже. Пожалуйста, свяжитесь с вашим администратором, если эта проблема не устранена." + ], + "Unable to migrate table schema state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ + "Не удается перенести состояние схемы таблицы на сервер. Суперсет повторит попытку позже. Пожалуйста, свяжитесь с вашим администратором, если эта проблема не устранена." + ], + "Unable to process right-click on %s. Check you chart configuration.": [ + "Не удалось обработать ПКМ на %s. Проверьте настройки графика." + ], + "Unable to retrieve dashboard colors": [ + "Не удалось получать цветовую схему дашборда" + ], + "Unable to upload CSV file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ + "Не удалось загрузить CSV файл \"%(filename)s\" в таблицу \"%(table_name)s\" в базу данных \"%(db_name)s\". Ошибка: %(error_msg)s" + ], + "Unable to upload Columnar file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ + "Не удалось загрузить файл столбчатого типа \"%(filename)s\" в таблицу \"%(table_name)s\" в базу данных \"%(db_name)s\". Ошибка: %(error_msg)s" + ], + "Unable to upload Excel file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ + "Не удалось загрузить Excel файл \"%(filename)s\" в таблицу \"%(table_name)s\" в базу данных \"%(db_name)s\". Ошибка: %(error_msg)s" + ], + "Undefined": ["Не определено"], + "Undefined window for rolling operation": [ + "Неопределенное окно для скольжения" + ], + "Undo the action": ["Отменить действие"], + "Undo?": ["Отменить?"], + "Unexpected error": ["Неожиданная ошибка"], + "Unexpected error occurred, please check your logs for details": [ + "Возникла неожиданная ошибка, пожалуйста, проверьте историю действий для уточнения деталей" + ], + "Unexpected error: ": ["Неожиданная ошибка: "], + "Unknown": ["Неизвестно"], + "Unknown MySQL server host \"%(hostname)s\".": [ + "Неизвестный хост MySQL \"%(hostname)s\"." + ], + "Unknown Presto Error": ["Неизвестная ошибка Presto"], + "Unknown Status": ["Неизвестный статус"], + "Unknown column used in orderby: %(col)s": [ + "Неизвестный столбец использован для упорядочивания: %(col)s" + ], + "Unknown error": ["Неизвестная ошибка"], + "Unknown input format": ["Неизвестный формат ввода"], + "Unknown value": ["Неизвестная ошибка"], + "Unsafe return type for function %(func)s: %(value_type)s": [ + "Небезопасный возвращаемый тип для функции %(func)s: %(value_type)s" + ], + "Unsafe template value for key %(key)s: %(value_type)s": [ + "Небезопасное значение шаблона для ключа %(key)s: %(value_type)s" + ], + "Unset Filters (%d)": ["Сбросить фильтры (%d)"], + "Unsupported clause type: %(clause)s": [ + "Неподдерживаемый оператор: %(clause)s" + ], + "Unsupported post processing operation: %(operation)s": [ + "Неподдерживаемая операция постобработки: %(operation)s" ], - "Hours offset": ["Смещение часов"], - "Spatial": [""], - "virtual": [""], - "Dataset name": ["Наименование датасета"], - "When specifying SQL, the datasource acts as a view. Superset will use this statement as a subquery while grouping and filtering on the generated parent queries.": [ - "Когда указан SQL, источник данных работает как представление. Superset будет использовать это выражение в подзапросе, при необходимости группировки и фильтрации." + "Unsupported return value for method %(name)s": [ + "Неподдерживаемое значение для метода %(name)s" ], - "The JSON metric or post aggregation definition.": [""], - "Physical": [""], - "The pointer to a physical table (or view). Keep in mind that the chart is associated to this Superset logical table, and this logical table points the physical table referenced here.": [ - "Указатель на физическую таблицу (или представление). Следует помнить, что график связан с логической таблицей Superset, а эта логическая таблица указывает на физическую таблицу, указанную здесь." + "Unsupported template value for key %(key)s": [ + "Неподдерживаемое значение шаблона для ключа %(key)s" ], - "Click the lock to make changes.": [ - "Нажмите на замок, чтобы выполнить изменения." + "Unsupported time grain: %(time_grain)s": [ + "Неподдерживаемая единица времени: %(time_grain)s" ], - "Click the lock to prevent further changes.": [ - "Нажмите на замок, чтобы предотвратить будущие изменения." + "Untitled Dataset": ["Безымянный датасет"], + "Untitled query": ["Безымянный запрос"], + "Update": ["Обновить"], + "Update chart": ["Обновить график"], + "Updating chart was stopped": ["Обновление графика остановлено"], + "Upload": ["Загрузить"], + "Upload CSV": ["Загрузить CSV"], + "Upload CSV to database": ["Загрузить файл CSV в базу данных"], + "Upload Credentials": ["Загрузить учетные данные"], + "Upload Enabled": ["Загрузка включена"], + "Upload Excel file": ["Загрузить файл Excel"], + "Upload Excel file to database": ["Загрузить файл Excel в базу данных"], + "Upload JSON file": ["Загрузить JSON файл"], + "Upload columnar file": ["Загрузить файл столбчатого формата"], + "Upload columnar file to database": [ + "Загрузить файл столбчатого формата в базу данных" + ], + "Upload file to database": ["Загрузить файл в базу данных"], + "Use \"%(menuName)s\" menu instead.": [ + "Использовать меню \"%(menuName)s\" взамен." + ], + "Use %s to open in a new tab.": [ + "Используйте %s для открытия в отдельной вкладке." + ], + "Use Area Proportions": ["Использовать пропорции области"], + "Use Columns": ["Используемые столбцы"], + "Use a log scale": ["Использовать логарифмическую шкалу"], + "Use a log scale for the X-axis": [ + "Использовать логарифмическую шкалу для оси X" + ], + "Use a log scale for the Y-axis": [ + "Использовать логарифмическую шкалу для оси Y" + ], + "Use an encrypted connection to the database": [ + "Использовать зашифрованное соединение к Базе Данных" + ], + "Use another existing chart as a source for annotations and overlays.\n Your chart must be one of these visualization types: [%s]": [ + "" ], - "D3 format": ["Формат D3"], - "Warning message": ["Предупреждающее сообщение"], - "Warning message to display in the metric selector": [ - "Предупреждение для отображения на селекторе показателей" + "Use date formatting even when metric value is not a timestamp": [ + "Использовать перевод к формату дата/время даже если мера представляет другой тип данных" ], - "Certified by": ["Изменено"], - "Person or group that has certified this metric": [ - "Лицо или группа, которые сертифицировали данный показатель" + "Use legacy datasource editor": ["Использовать старый редактор"], + "Use metrics as a top level group for columns or for rows": [""], + "Use only a single value.": ["Используйте только одно значение."], + "Use the Advanced Analytics options below": [ + "Используйте настройки Расширенной аналитики ниже" ], - "Certification details": ["Детали сертификации"], - "Details of the certification": ["Детали сертификации"], - "Be careful.": ["Будьте осторожны."], - "Changing these settings will affect all charts using this dataset, including charts owned by other people.": [ - "Изменение этих настроек будет влиять на все графики, использующие этот датасет, включая графики других пользователей." + "Use the JSON file you automatically downloaded when creating your service account.": [ + "" ], - "Source": ["Источник"], - "Sync columns from source": ["Синхронизировать столбцы из источника"], - "Calculated columns": ["Расчётные столбцы"], - "The dataset has been saved": ["Источник данных, похоже, был удален"], - "The dataset configuration exposed here\n affects all the charts using this dataset.\n Be mindful that changing settings\n here may affect other charts\n in undesirable ways.": [ - "Здесь представлена конфигурация датасета\n влияет на все графики, использующие этот датасет.\n Помните, что изменение настроек\n может иметь неожиданный эффект\n на другие графики." + "Use the edit button to change this field": [ + "Используйте кнопку редактирования для изменения поля" ], - "Are you sure you want to save and apply changes?": [ - "Вы уверены, что хотите сохранить и применить изменения?" + "Use this section if you want a query that aggregates": [""], + "Use this section if you want to query atomic rows": [""], + "Use this to define a static color for all circles": [ + "Этот цвет используется для заливки" ], - "Confirm save": ["Подтвердить сохранение"], - "Edit Dataset ": ["Редактировать датасет "], - "Use legacy datasource editor": ["Использовать старый редактор"], - "Time range": ["Период времени"], - "Time column": ["Столбец с временем"], - "Time grain": ["Гранулярность времени"], - "Origin": ["Источник"], - "Time granularity": ["Гранулярность времени"], - "A reference to the [Time] configuration, taking granularity into account": [ + "Used internally to identify the plugin. Should be set to the package name from the pluginʼs package.json": [ "" ], - "Group by": ["Группировать по"], - "One or many controls to group by": [ - "Выберите один или несколько срезов в поле группировки данных" + "Used to summarize a set of data by grouping together multiple statistics along two axes. Examples: Sales numbers by region and month, tasks by status and assignee, active users by age and location.\n\n This chart is being deprecated and we recommend checking out Pivot Table V2 instead!": [ + "Используется для обобщения набора данных путем группировки нескольких показателей по двум осям. Примеры: показатели продаж по регионам и месяцам, задачи по статусу и назначенному лицу, активные пользователи по возрасту и местоположению.\n Этот график устарел, рекомендуется использовать график Сводная Таблица 2." ], - "One or many metrics to display": [ - "Выберите один или несколько показателей для отображения" + "Used to summarize a set of data by grouping together multiple statistics along two axes. Examples: Sales numbers by region and month, tasks by status and assignee, active users by age and location. Not the most visually stunning visualization, but highly informative and versatile.": [ + "Используется для обобщения набора данных путем группировки нескольких показателей по двум осям. Примеры: показатели продаж по регионам и месяцам, задачи по статусу и назначенному лицу, активные пользователи по возрасту и местоположению." ], - "Dataset": ["Датасет"], - "Visualization type": ["Тип визуализации"], - "The type of visualization to display": [ - "Выберите необходимый тип визуализации" + "User": ["Пользователь"], + "User Roles": ["Роли пользователя"], + "User doesn't have the proper permissions.": [ + "У пользователя нет надлежащего доступа." ], - "Fixed color": ["Фиксированный цвет"], - "Use this to define a static color for all circles": [ - "Используйте это цвет для заливки всех кругов одним цветом" + "User must select a value before applying the filter": [ + "Для использования фильтра пользователь будет обязан выбрать значение" ], - "Right axis metric": ["Показатель для правой оси"], - "Choose a metric for right axis": ["Выберите показатель для правой оси"], - "Linear color scheme": ["Цветовая схема"], - "Color metric": ["Цвет показателя"], - "A metric to use for color": [ - "Показатель, используемый для расчета цвета" + "User must select a value for this filter": [ + "Для использования фильтра пользователь будет обязан выбрать значение" ], - "One or many controls to pivot as columns": [ - "Выберите один или несколько срезов для отображения показателей в столбцах сводной таблицы" + "User query": ["Пользовательский запрос"], + "Username": ["Имя пользователя"], + "Uses a gauge to showcase progress of a metric towards a target. The position of the dial represents the progress and the terminal value in the gauge represents the target value.": [ + "Использует индикатор для демонстрации прогресса показателя в достижении цели. Положение циферблата показывает ход выполнения, а конечное значение на индикаторе представляет целевое значение." ], - "Defines the origin where time buckets start, accepts natural dates as in `now`, `sunday` or `1970-01-01`": [ + "Uses circles to visualize the flow of data through different stages of a system. Hover over individual paths in the visualization to understand the stages a value took. Useful for multi-stage, multi-group visualizing funnels and pipelines.": [ "" ], - "The time granularity for the visualization. Note that you can type and use simple natural language as in `10 seconds`, `1 day` or `56 weeks`": [ - "Интервал времени, в границах которого строится график. Обратите внимание, что для определения диапазона времени, вы можете использовать естественный язык. Например, можно указать словосочетания - «10 seconds», «1 day» или «56 weeks»" + "Value": ["Значение"], + "Value Domain": [""], + "Value Format": ["Формат значения"], + "Value bounds": ["Ограничения для значения"], + "Value format": ["Формат значения"], + "Value is required": ["Значение обязательно"], + "Value must be greater than 0": ["Значение должно быть больше 0"], + "Values are dependent on other filters": [ + "Значения зависят от других фильтров" + ], + "Values dependent on": ["Значения зависят от"], + "Values selected in other filters will affect the filter options to only show relevant values": [ + "" ], - "The time column for the visualization. Note that you can define arbitrary expression that return a DATETIME column in the table. Also note that the filter below is applied against this column or expression": [ - "Столбец данных с датой или временем. Вы можете определить произвольное выражение, которое будет возвращать столбец даты/времени в таблице. Фильтр ниже будет применён к этому столбцу или выражению" + "Vehicle Types": [""], + "Verbose Name": ["Удобочитаемое имя"], + "Version": ["Версия"], + "Version number": ["Номер версии"], + "Vertical": ["Вертикально"], + "Vertical (Left)": ["Вертикально (слева)"], + "Video game consoles": ["Игровые приставки"], + "View": ["Показать"], + "View All »": ["Смотреть все »"], + "View Dataset": ["Посмотреть датасет"], + "View all charts": ["Показать все графики"], + "View as table": ["Показать в виде таблицы"], + "View in SQL Lab": ["Открыть в Лаборатории SQL"], + "View keys & indexes (%s)": ["Показать ключи и индексы (%s)"], + "View query": ["Показать SQL запрос"], + "Viewed": ["Просмотрено"], + "Viewed %s": ["Просмотрено %s"], + "Viewport": ["Область просмотра"], + "Virtual": ["Виртуальный"], + "Virtual (SQL)": ["Виртуальный (SQL)"], + "Virtual dataset": ["Виртуальный датасет"], + "Virtual dataset query cannot be empty": [ + "Запрос виртуального датасета не может быть пустым" ], - "The time granularity for the visualization. This applies a date transformation to alter your time column and defines a new time granularity. The options here are defined on a per database engine basis in the Superset source code.": [ - "Гранулярность для визуализации. С помощью этого применяются преобразования к столбцу с датой/временем и определяет новую гранулярность (минута, день, год, и т.п.). Доступные опции определены в исходном коде Superset для каждого типа движка БД." + "Virtual dataset query cannot consist of multiple statements": [ + "Запрос виртуального датасета не может содержать несколько запросов" ], - "Last week": ["Последняя неделя"], - "The time range for the visualization. All relative times, e.g. \"Last month\", \"Last 7 days\", \"now\", etc. are evaluated on the server using the server's local time (sans timezone). All tooltips and placeholder times are expressed in UTC (sans timezone). The timestamps are then evaluated by the database using the engine's local timezone. Note one can explicitly set the timezone per the ISO 8601 format if specifying either the start and/or end time.": [ + "Virtual dataset query must be read-only": [ + "Запрос виртуального датасета должен быть доступен только для чтения" + ], + "Visual Tweaks": ["Визуальные настройки"], + "Visualization Type": ["Тип визуализации"], + "Visualization type": ["Тип визуализации"], + "Visualize a parallel set of metrics across multiple groups. Each group is visualized using its own line of points and each metric is represented as an edge in the chart.": [ "" ], - "Row limit": ["Лимит строк"], - "Series limit": ["Лимит кол-ва рядов"], - "Limits the number of time series that get displayed. A sub query (or an extra phase where sub queries are not supported) is applied to limit the number of time series that get fetched and displayed. This feature is useful when grouping by high cardinality dimension(s).": [ - "Ограничивает количество отображаемых временных рядов." + "Visualize a related metric across pairs of groups. Heatmaps excel at showcasing the correlation or strength between two groups. Color is used to emphasize the strength of the link between each pair of groups.": [ + "" ], - "Sort by": ["Сортировка"], - "Metric used to define the top series": [ - "Показатель, используемый для определения какие временные ряды будут отображаться при ограничении количества выводимых рядов" + "Visualize geospatial data like 3D buildings, landscapes, or objects in grid view.": [ + "Визуализирует геопространственные данные, такие как 3D-здания, ландшафты или объекты в виде сетки." ], - "Series": ["Ряд данных"], - "Defines the grouping of entities. Each series is shown as a specific color on the chart and has a legend toggle": [ - "Группировка в ряды данных. Каждый ряд отображается в виде определенного цвета на графике и имеет легенду" + "Visualize how a metric changes over time using bars. Add a group by column to visualize group level metrics and how they change over time.": [ + "Визуализирует изменение меры с течением времени, используя столбцы. Добавьте столбец для группировки, чтобы визуализировать показатели уровня группы и то, как они меняются с течением времени." ], - "Entity": ["Элемент"], - "This defines the element to be plotted on the chart": [ - "Элемент, который будет отражен на графике" + "Visualize multiple levels of hierarchy using a familiar tree-like structure.": [ + "Визуализирует несколько уровней иерархии, используя древовидную структуру." ], - "X Axis": ["Ось X"], - "Metric assigned to the [X] axis": ["Показатель, отраженный на оси X"], - "Y Axis": ["Ось Y"], - "Metric assigned to the [Y] axis": ["Показатель, отраженный на оси Y"], - "Bubble size": ["Размер маркера"], - "Y Axis Format": ["Формат Оси Y"], - "When `Calculation type` is set to \"Percentage change\", the Y Axis Format is forced to `.1%`": [ - "Когда `Тип расчёта` установлен в “Изменение процента”, формат оси Y устанавливается в `.1%`" + "Visualize two different series using the same x-axis. Note that both series can be visualized with a different chart type (e.g. 1 using bars and 1 using a line).": [ + "" ], - "The color scheme for rendering chart": [ - "Цветовая схема, применяемая для раскрашивания графика" + "Visualize two different time series using the same x-axis time range. This chart is being deprecated and we recommend using the Mixed Timeseries Chart instead!": [ + "" ], - "Color map": ["Цвет"], - "description": ["описание"], - "bolt": [""], - "Changing this control takes effect instantly": [ - "Изменение этого элемента применяется сразу" + "Visualize two different time series using the same x-axis. Note that each time series can be visualized differently (e.g. 1 using bars and 1 using a line).": [ + "" ], - "Customize": ["Настроить"], - "rows retrieved": ["строк получено"], - "Sorry, An error occurred": ["Извините, произошла ошибка"], - "No data": ["Метаданные"], - "View samples": ["Посмотреть примеры"], - "Search Metrics & Columns": ["Столбцы Временных Рядов"], - "Showing %s of %s": [""], - "New chart": ["Переместить график"], - "Edit properties": ["Редактирование свойств"], - "View query": ["Скопировать запрос"], - "Run in SQL Lab": ["Открыть в SQL редакторе"], - "Height": ["Высота"], - "Width": ["Ширина"], - "Export to .json": ["Экспортировать в JSON формат"], - "Export to .csv format": ["Экспортировать в CSV формат"], - "%s - untitled": ["%s - без названия"], - "Edit chart properties": ["Редактирование свойств"], - "Control labeled ": [""], - "Open Datasource tab": ["Открыть вкладку источника данных"], - "You do not have permission to edit this chart": [ - "У вас нет прав на редактирование этого графика" + "Visualizes 2 metrics as line plots using the same x-axis. This chart is useful for comparing metrics across the same time range.": [ + "" ], - "The description can be displayed as widget headers in the dashboard view. Supports markdown.": [ - "Описание может быть отображено как заголовок виджета в ракурсе дашбордов. Поддерживает markdown-разметку." + "Visualizes a metric across three dimensions of data in a single chart (X axis, Y axis, and bubble size). Bubbles from the same group can be showcased using bubble color.": [ + "" ], - "Configuration": ["Доля"], - "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the dataset's timeout if undefined.": [ - "Продолжительность (в секундах) таймаута кэширования для этого графика." + "Visualizes connected points, which form a path, on a map.": [ + "Визуализирует связанные точки, которые образуют путь, на карте." ], - "A list of users who can alter the chart. Searchable by name or username.": [ - "Владельцы - это пользователи, которые могут изменять график." + "Visualizes geographic areas from your data as polygons on a Mapbox rendered map. Polygons can be colored using a metric.": [ + "" ], - "rows": ["строк"], - "Limit reached": ["Достигнут предел"], - "**Select** a dashboard OR **create** a new one": [ - "**Выберите** дашборд ИЛИ **создайте** новый" + "Visualizes how a metric has changed over a time using a color scale and a calendar view. Gray values are used to indicate missing values and the linear color scheme is used to encode the magnitude of each day's value.": [ + "Визуализирует, как показатель изменился с течением времени, используя цветовую шкалу и календарь. Значения серого цвета используются для обозначения отсутствующих значений, а линейная цветовая схема используется для отображения величины значения каждого дня." ], - "Please enter a chart name": ["Введите имя графика"], - "Save chart": ["Сохранить график"], - "Save & go to dashboard": ["Сохранить и перейти к дашборду"], - "Save as new chart": ["Сохранить как новый график"], - "Save (Overwrite)": ["Сохранить (Перезаписать)"], - "Save as ...": ["Сохранить как …"], - "Chart name": ["Имя графика"], - "Add to dashboard": ["Добавить в дашборд"], - "Display configuration": ["Как отображать"], - "Configure your how you overlay is displayed here.": [ - "Настройте наложение здесь." + "Visualizes how a single metric varies across a country's principal subdivisions (states, provinces, etc) on a chloropleth map. Each subdivision's value is elevated when you hover over the corresponding geographic boundary.": [ + "" ], - "Style": ["Стиль"], - "Opacity": ["Прозрачность"], - "Color": ["Цвет"], - "Line width": ["Толщина линии"], - "Layer configuration": ["Конфигурация слоя"], - "Configure the basics of your Annotation Layer.": [ - "Настройте слой аннотации." + "Visualizes many different time-series objects in a single chart. This chart is being deprecated and we recommend using the Time-series Chart instead.": [ + "" ], - "Mandatory": [""], - "Hide layer": ["Скрыть слой"], - "Choose the annotation layer type": ["Выбрать тип слоя аннотации"], - "Annotation layer type": ["Тип слоя аннотации"], - "Remove": [""], - "Edit annotation layer": ["Редактировать слой аннотации"], - "Add annotation layer": ["Добавить слой аннотации"], - "`Min` value should be numeric or empty": [ - "Значение «Минимум» должно быть числовым или пустым" + "Visualizes the flow of different group's values through different stages of a system. New stages in the pipeline are visualized as nodes or layers. The thickness of the bars or edges represent the metric being visualized.": [ + "" ], - "`Max` value should be numeric or empty": [ - "Значение « Максимум» должно быть числовым или пустым" + "Visualizes the words in a column that appear the most often. Bigger font corresponds to higher frequency.": [ + "Визуализирует слова в столбце, которые появляются чаще всего. Более крупный шрифт соответствует более высокой частоте" ], - "Min": ["Минимум"], - "Max": ["Максимум"], - "Edit dataset": ["Редактировать датасет"], - "View in SQL Lab": ["Открыть в лаборатории SQL"], - "More dataset related options": ["Больше опций к датасету"], - "Superset supports smart date parsing. Strings like `3 weeks ago`, `last sunday`, or `2 weeks from now` can be used.": [ - "Superset поддерживает умную интерпретацию дат. Могут быть использованы такие строки как `3 weeks ago`, `last sunday`, или `2 weeks from now`." + "Viz is missing a datasource": [ + "У визуализации отсутствует источник данных" ], - "Default": ["Широта по умолчанию"], - "(optional) default value for the filter, when using the multiple option, you can use a semicolon-delimited list of options.": [ - "(опционально) значение по-умолчанию для фильтраю. Когда используются множественные значения, вы можете вставить список значений, разделённых символами точка с запятой" + "Viz type": ["Тип визуализации"], + "WED": ["СР"], + "Want to add a new database?": ["Хотите добавить новую базу данных?"], + "Warning": ["Предупреждение"], + "Warning Message": ["Предупреждение"], + "Warning!": ["Предупреждение!"], + "Warning! Changing the dataset may break the chart if the metadata does not exist.": [ + "Внимание! Изменение датасета может привести к тому, что график станет нерабочим, если будут отсутствовать метаданные." ], - "Sort metric": ["Показатель для сортировки"], - "Metric to sort the results by": [ - "Показатель, по которому сортировать результаты" + "Was unable to check your query": ["Не удалось проверить запрос"], + "We are unable to connect to your database. Click \"See more\" for database-provided information that may help troubleshoot the issue.": [ + "Не удалось подключиться к базе данных. Нажмите \"Подробнее\" для информации, предоставленной базой данных в ответ, для решения проблемы." ], - "Sort ascending": ["Направление сортировки"], - "Check for sorting ascending": [ - "Сортировка по убыванию или по возрастанию" + "We can't seem to resolve column \"%(column)s\" at line %(location)s.": [ + "Не удалось обнаружить столбец \"%(column)s\" в строке %(location)s." ], - "Multiple selections allowed, otherwise filter is limited to a single value": [ - "Разрешён множественный выбор, иначе можно выбрать только одно значение фильтра" + "We can't seem to resolve the column \"%(column_name)s\"": [ + "Не удалось обнаружить столбец \"%(column_name)s\"" ], - "Search all filter options": ["Поиск / Фильтр"], - "By default, each filter loads at most 1000 choices at the initial page load. Check this box if you have more than 1000 filter values and want to enable dynamically searching that loads filter values as users type (may add stress to your database).": [ - "По-умолчанию, каждый фильтр загружает не больше 1000 элементов выбора при начальной загрузке страницы. Установите этот флаг, если у вас больше 1000 значений фильтра и вы хотите включить динамический поиск, который загружает значения по мере их ввода пользователем (может увеличить нагрузку на вашу базу данных)." + "We can't seem to resolve the column \"%(column_name)s\" at line %(location)s.": [ + "Не удалось обнаружить столбец \"%(column_name)s\" в строке %(location)s." ], - "User must select a value for this filter": [ - "Пользователю нужно будет выбрать значение для этого фильтра" + "We have the following keys: %s": ["У нас есть следующие ключи: %s"], + "We were unable to active or deactivate this report.": [ + "Не удалось включить или выключить эту рассылку." ], - "Filter configuration": ["Фильтруемые срезы"], - "Error while fetching data": ["Возникла ошибка при получение данных"], - "No results found": ["Записи не найдены"], - "%s option(s)": ["%s параметр(ы)"], - "Invalid lat/long configuration.": [ - "Неверная конфигурация широты и долготы." + "We were unable to carry over any controls when switching to this new dataset.": [ + "Не удалось перенести настройки прошлого графика при переключении датасета." ], - "Reverse lat/long ": ["Поменять местами широту и долготу "], - "Longitude & Latitude columns": ["Долгота и Широта"], - "Delimited long & lat single column": [ - "Широта и Долгота в одном столбце с разделителем" + "We were unable to connect to your database named \"%(database)s\". Please verify your database name and try again.": [ + "Не удалось подключиться к вашей базе данных с именем \"%(database)s\". Пожалуйста, подтвердите имя вашей базы данных и попробуйте снова." ], - "Multiple formats accepted, look the geopy.points Python library for more details": [ - "Для уточнения форматов и получения более подробной информации, посмотрите Python-библиотеку geopy.points" + "Web": ["Сеть"], + "Wednesday": ["Среда"], + "Week": ["Неделя"], + "Week ending Saturday": ["Неделя, заканчивающаяся в субботу"], + "Week starting Monday": ["Неделя, начинающаяся в понедельник"], + "Week starting Sunday": ["Неделя, начинающаяся в воскресенье"], + "Week_ending Sunday": ["Неделя, заканчивающаяся в воскресенье"], + "Weekly Report": ["Еженедельный отчет"], + "Weekly Report for %s": ["Еженедельный отчет для %s"], + "Weekly seasonality": ["Недельная сезонность"], + "Weeks %s": ["Недель %s"], + "Weight": ["Вес"], + "We’re having trouble loading these results. Queries are set to timeout after %s second.": [ + "Возникла проблема при загрузке результатов. Для запросов установлен тайм-аут %s секунда.", + "Возникла проблема при загрузке результатов. Для запросов установлен тайм-аут %s секунды.", + "Возникла проблема при загрузке результатов. Для запросов установлен тайм-аут %s секунд." ], - "Geohash": ["Geohash"], - "textarea": ["текстовая область"], - "in modal": [""], - "Time series columns": ["Столбцы Временных Рядов"], - "This visualization type is not supported.": [ - "Этот тип визуализации не поддерживается." + "We’re having trouble loading this visualization. Queries are set to timeout after %s second.": [ + "Возникла проблема при загрузке этой визуализации. Для запросов установлен тайм-аут %s секунда.", + "Возникла проблема при загрузке этой визуализации. Для запросов установлен тайм-аут %s секунды.", + "Возникла проблема при загрузке этой визуализации. Для запросов установлен тайм-аут %s секунд." ], - "Click to change visualization type": ["Выберите тип визуализации"], - "Select a visualization type": ["Выберите тип визуализации"], - "Failed to verify select options: %s": [ - "Ошибка при проверке опций выбора: %s" + "What should be shown on the label?": ["Текст, отображаемый на метке"], + "What should happen if the table already exists": [ + "Что должно произойти, если таблица уже существует" ], - "RANGE TYPE": ["ТИП ИНТЕРВАЛА"], - "Actual time range": [""], - "CANCEL": ["ОТМЕНИТЬ"], - "APPLY": ["ПРИМЕНИТЬ"], - "Edit time range": ["Изменить параметры шаблона"], - "Configure advanced time range": ["Особый временной интервал"], - "START": ["НАЧАЛО"], - "END": ["КОНЕЦ"], - "Configure Time Range: Previous...": ["Предыдущие…"], - "Configure Time Range: Last...": ["Последние…"], - "Configure custom time range": ["Изменить параметры шаблона"], - "Relative quantity": ["Относительное количество"], - "Anchor to": ["Привязать к"], - "NOW": ["СЕЙЧАС"], - "Date/Time": ["Формат даты"], - "Simple": ["Простые"], - "Custom SQL": ["Через SQL"], - "No such column found. To filter on a metric, try the Custom SQL tab.": [ - "Такой столбец не найден. Чтобы фильтровать по показателю, попробуйте вкладку Через SQL." + "When `Calculation type` is set to \"Percentage change\", the Y Axis Format is forced to `.1%`": [ + "Когда `Тип расчёта` установлен в \"Процентное изменение\", формат оси Y устанавливается в `.1%`" ], - "%s column(s) and metric(s)": ["%s столбец(ы) и показатель(и)"], - "%s column(s)": ["Столбец(ы) %s"], - "To filter on a metric, use Custom SQL tab.": [ - "Фильтр на показателе, используйте вкладку Через SQL." + "When a secondary metric is provided, a linear color scale is used.": [ + "Когда предоставляется вторичная мера, используется линейная цветовая схема." ], - "%s operator(s)": ["%s параметр(ы)"], - "Type a value here": ["Введите значение здесь"], - "Filter value (case sensitive)": [ - "Фильтровать значения (зависит от регистра)" + "When allowing CREATE TABLE AS option in SQL Lab, this option forces the table to be created in this schema": [ + "При включении опции CREATE TABLE AS в Лаборатории SQL, новые таблицы будут добавлены в эту схему" ], - "choose WHERE or HAVING...": ["выберите WHERE или HAVING…"], - "Filters by columns": ["Фильтруемые срезы"], - "Filters by metrics": ["Список показателей"], - "\n This filter was inherited from the dashboard's context.\n It won't be saved when saving the chart.\n ": [ - "\n Фильтр был наследован из контекста дашборда.\n Это не будет сохранено при сохранении графика.\n " + "When checked, the map will zoom to your data after each query": [ + "Если отмечено, карта будет смасштабирована к вашим данным после каждого запроса" ], - "%s aggregates(s)": ["%s агрегат(ы)"], - "%s saved metric(s)": ["%s сохранённый показатель(и)"], - "Saved": ["Сохранить"], - "Saved metric": ["Сохранённый показатель"], - "column": ["столбец"], - "aggregate": ["агрегат"], - "My metric": ["Показатель"], - "Add metric": ["Добавить показатель"], - "Code": ["Редактор"], - "Markup type": ["Тип разметки"], - "Pick your favorite markup language": [ - "Выберите свой любимый язык разметки" + "When enabled, users are able to visualize SQL Lab results in Explore.": [ + "Если этот параметр включен, пользователи могут смотреть ответ запросов Лаборатории SQL в режиме исследования." ], - "Put your code here": [ - "Введите произвольный текст в формате html или markdown" + "When only a primary metric is provided, a categorical color scale is used.": [ + "Когда предоставляется только основная мера, используется категориальная цветовая схема." ], - "Query": ["Запрос"], - "URL": ["Ссылка (URL)"], - "Templated link, it's possible to include {{ metric }} or other values coming from the controls.": [ - "Шаблонная ссылка, можно включить {{ metric }} или другие значения, поступающие из элементов управления." + "When specifying SQL, the datasource acts as a view. Superset will use this statement as a subquery while grouping and filtering on the generated parent queries.": [ + "Когда указан SQL, источник данных работает как представление. Superset будет использовать это выражение в подзапросе, при необходимости группировки и фильтрации." ], - "Time": ["Время"], - "Time related form attributes": ["Параметры, связанные с временем"], - "Chart type": ["Тип графика"], - "Chart ID": ["График"], - "The id of the active chart": ["Идентификатор активного среза"], - "Cache Timeout (seconds)": ["Тайм-аут кэша (секунды)"], - "The number of seconds before expiring the cache": [ - "Количество секунд до истечения срока действия кэша" + "When using \"Autocomplete filters\", this can be used to improve performance of the query fetching the values. Use this option to apply a predicate (WHERE clause) to the query selecting the distinct values from the table. Typically the intent would be to limit the scan by applying a relative time filter on a partitioned or indexed time-related field.": [ + "При использовании \"Фильтров автозаполнения\" это может использоваться для улучшения быстродействия запроса. Используйте эту опцию для настройки предиката (оператор WHERE) запроса для уникальных значений из таблицы. Обычно целью является ограничение сканирования путем применения относительного временного фильтра к секционированному или индексированному полю типа дата/время." ], - "URL parameters": ["Параметры"], - "Extra parameters for use in jinja templated queries": [ - "Дополнительные параметры для запросов, использующих шаблоны jinja" + "When using 'Group By' you are limited to use a single metric": [ + "При использовании 'GROUP BY' вы ограничены использованием одной меры" ], - "Time range endpoints": ["Период времени"], - "Time range endpoints (SIP-15)": [""], - "Annotations and layers": ["Аннотация"], - "Sort descending": ["Сортировать"], - "Whether to sort descending or ascending": [ - "Сортировка по убыванию или по возрастанию" + "When using this option, default value can’t be set": [ + "При включении этой опции нельзя установить значение по умолчанию" ], - "Contribution": ["Доля"], - "Compute the contribution to the total": [ - "Вычислить вклад в общую сумму (долю). Установите формат показателя в проценты" + "Whether the progress bar overlaps when there are multiple groups of data": [ + "Индикатор прогресса накладывается при наличии нескольких групп данных" ], - "Advanced analytics": ["Расширенный анализ"], - "This section contains options that allow for advanced analytical post processing of query results": [ - "В этом разделе содержатся параметры, которые позволяют производить аналитическую пост-обработку результатов запроса" + "Whether the table was generated by the 'Visualize' flow in SQL Lab": [ + "" ], - "Rolling window": ["Rolling"], - "Rolling function": ["Rolling"], - "Defines a rolling window function to apply, works along with the [Periods] text box": [ - "Одна из функций (Rolling) библиотеки Pandas, которая определяет способ агрегации данных" + "Whether this column is exposed in the `Filters` section of the explore view.": [ + "" ], - "Periods": ["Период"], - "Defines the size of the rolling window function, relative to the time granularity selected": [ - "Одна из функций (Rolling) библиотеки Pandas, которая определяет период, к которому применяется функция агрегации" + "Whether to align background charts with both positive and negative values at 0": [ + "" ], - "Min periods": ["HIde Periods"], - "The minimum number of rolling periods required to show a value. For instance if you do a cumulative sum on 7 days you may want your \"Min Period\" to be 7, so that all data points shown are the total of 7 periods. This will hide the \"ramp up\" taking place over the first 7 periods": [ - "Скрыть необходимое количество периодов. Например, если вы делаете накопительную сумму показателя за 7 дней, но хотите скрыть нарастающий итог за первые 6 дней, то указав в данном столбце «6», вы скроете нарастание, происходящее в течение первых 6 периодов" + "Whether to align positive and negative values in cell bar chart at 0": [ + "Выравнивание гистограммы внутри ячеек по горизонтали слева" ], - "Time comparison": ["Столбец с датой"], - "Time shift": ["Временной сдвиг"], - "Overlay one or more timeseries from a relative time period. Expects relative time deltas in natural language (example: 24 hours, 7 days, 52 weeks, 365 days). Free text is supported.": [ - "" + "Whether to always show the annotation label": [ + "Всегда показывать метку аннотации" ], - "Calculation type": ["Тип расчёта"], - "How to display time shifts: as individual lines; as the absolute difference between the main time series and each time shift; as the percentage change; or as the ratio between series and time shifts.": [ - "Как отображать смещения во времени: как отдельные линии; как абсолютную разницу между основным временным рядом и каждым смещением; как процентное изменение; или как соотношение между рядами и смещениями." + "Whether to animate the progress and the value or just display them": [ + "Анимировать прогресс и значение или просто отображать их" ], - "Python functions": ["Python функции"], - "Rule": ["Правило"], - "Pandas resample rule": [ - "Одна из функций (Resample) библиотеки Pandas, которая определяет период, к которому применяется функция агрегации" + "Whether to apply a normal distribution based on rank on the color scale": [ + "Применять нормальное распределение на основе ранга в цветовой схеме" ], - "Method": ["Метод"], - "Pandas resample method": [ - "Одна из функций (Resample) библиотеки Pandas, которая определяет метод обработки данных" + "Whether to apply filter when items are clicked": [ + "Применять фильтр при щелчке по элементам" ], - "Favorites": ["Избранное"], - "Created content": ["Созданный контент"], - "Recent activity": ["Последние действия"], - "Security & Access": ["Безопасность и Доступ"], - "No charts": ["Переместить график"], - "No dashboards": ["Нет дашбордов"], - "No favorite charts yet, go click on stars!": [ - "В избранном нет графиков. Нажмите звёздочку для добавления!" + "Whether to colorize numeric values by if they are positive or negative": [ + "Окрашивать ячейки с числами в зависимости от их знака" ], - "No favorite dashboards yet, go click on stars!": [ - "В избранном нет дашбордов. Нажмите звёздочку для добавления!" + "Whether to display a bar chart background in table columns": [ + "Отображать гистограмм в колонках таблицы" ], - "Profile picture provided by Gravatar": [ - "Изображение профиля, сгенерированное сервисом Gravatar" + "Whether to display a legend for the chart": [ + "Отображать легенду для графика" ], - "joined": ["присоединился"], - "id:": ["идентификатор:"], - "There was an error fetching your recent activity:": [ - "К сожалению, произошла ошибка при загрузке виджета:" + "Whether to display bubbles on top of countries": [ + "Отображать пузыри поверх стран" ], - "Deleted: %s": ["Удалено: %s"], - "There was an issue deleting: %s": ["Произошла ошибка при удалении: %s"], - "There was an issue deleting %s: %s": [ - "Произошла ошибка при удалении %s: %s" + "Whether to display the aggregate count": [ + "Отображать совокупное количество" ], - "report": ["рассылка"], - "alert": ["предупреждение"], - "reports": ["рассылки"], - "alerts": ["предупреждения"], - "There was an issue deleting the selected %s: %s": [ - "Произошла ошибка при удалении выбранных %s: %s" + "Whether to display the interactive data table": [ + "Отображать интерактивную таблицу с данными" ], - "Last run": ["Последнее изменение"], - "Notification method": ["Добавить слой аннотации"], - "Execution log": ["Журнал Действий"], - "Actions": ["Действия"], - "Bulk select": ["Множественный выбор"], - "No %s yet": ["Пока нет %s"], - "Created by": ["Дата создания"], - "An error occurred while fetching created by values: %s": [ - "Произошла ошибка при построении графика: %s" + "Whether to display the labels.": ["Отображать метки"], + "Whether to display the labels. Note that the label only displays when the the 5% threshold.": [ + "Отображать метки. Обратите внимание, что метка отображается только при достижении порогового значения 5%." ], - "Status": ["Статус"], - "${AlertState.success}": ["${AlertState.success}"], - "${AlertState.working}": ["${AlertState.working}"], - "${AlertState.error}": ["${AlertState.error}"], - "${AlertState.noop}": ["${AlertState.noop}"], - "${AlertState.grace}": ["${AlertState.grace}"], - "Alerts & reports": ["Оповещения и рассылки"], - "Reports": ["Рассылки"], - "This action will permanently delete %s.": [ - "Это действие навсегда удалит %s." + "Whether to display the legend (toggles)": [ + "Отображать легенду (переключатель)" ], - "Delete %s?": ["Удалить %s?"], - "Please confirm": ["Пожалуйста, подтвердите"], - "Are you sure you want to delete the selected %s?": [ - "Вы уверены, что хотите удалить выбранные %s?" + "Whether to display the metric name as a title": [ + "Отображать имя меры как названия" ], - "< (Smaller than)": ["< (меньше чем)"], - "> (Larger than)": ["> (больше чем)"], - "<= (Smaller or equal)": ["<= (меньше или равно)"], - ">= (Larger or equal)": [">= (больше или равно)"], - "== (Is equal)": ["== (равно)"], - "!= (Is not equal)": ["!= (не равно)"], - "Not null": ["Не пусто"], - "30 days": ["30 дней"], - "60 days": ["60 дней"], - "90 days": ["90 дней"], - "Add notification method": ["Добавить слой аннотации"], - "Add delivery method": ["Добавить метод доставки"], - "Recipients are separated by \",\" or \";\"": [ - "Получатели, разделенные “,” или “;”" + "Whether to display the min and max values of the X-axis": [ + "Отображать минимальное и максимальное значение на оси X" ], - "Add": ["Добавить"], - "Edit ${isReport ? 'Report' : 'Alert'}": [ - "Править ${isReport ? ‘рассылку’ : ‘оповещение’}" + "Whether to display the min and max values of the Y-axis": [ + "Отображать минимальное и максимальное значение на оси Y" + ], + "Whether to display the numerical values within the cells": [ + "Отображение числовых значений в ячейках" + ], + "Whether to display the stroke": ["Отображение обводки"], + "Whether to display the time range interactive selector": [ + "Отображение интерактивного селектора временного интервала" ], - "Add ${isReport ? 'Report' : 'Alert'}": [ - "Добавить ${isReport ? ‘рассылку’ : ‘оповещение’}" + "Whether to display the timestamp": ["Отображение временную метку"], + "Whether to display the trend line": ["Отображение трендовой линии"], + "Whether to enable changing graph position and scaling.": [""], + "Whether to enable node dragging in force layout mode.": [ + "Включить перемещение вершин в режиме силового алгоритма." ], - "Report name": ["Имя Шаблона"], - "Alert name": ["Имя оповещения"], - "Alert condition": ["Условие оповещения"], - "Trigger Alert If...": ["Сделать оповещение, если…"], - "Value": ["Подписи"], - "Report schedule": ["Область просмотра"], - "Alert condition schedule": ["Расписание условия оповещения"], - "Schedule settings": ["Настройки расписания"], - "Log retention": ["Время жизни журнала"], - "Working timeout": [""], - "Time in seconds": ["Время в секундах"], - "Grace period": ["Период"], - "Message content": ["Содержимое сообщения"], - "log": ["журнал"], - "State": ["Состояние"], - "Scheduled at": ["Запланировано на"], - "Start at": ["Время начала"], - "Duration": ["Продолжительность"], - "Error message": ["Сообщение об ошибке"], - "${alertResource?.type}": ["${alertResource?.type}"], - "CRON expression": ["Выражение SQL"], - "Report sent": ["Рассылка отправлена"], - "Alert triggered, notification sent": [ - "Сработало оповещение, уведомление отправлено" + "Whether to fill the objects": ["Использовать заливку для объектов"], + "Whether to ignore locations that are null": [ + "Игнорировать местоположения, которые не содержат данных о расположении" ], - "Report sending": ["Выполняется рассылка"], - "Alert running": ["Выполняется оповещение"], - "Report failed": ["Рассылка не удалась"], - "Alert failed": ["Оповещение не удалось"], - "Nothing triggered": ["Ничего не сработало"], - "Alert Triggered, In Grace Period": ["Сработало оповещение"], - "${RecipientIconName.email}": ["${RecipientIconName.email}"], - "${RecipientIconName.slack}": ["${RecipientIconName.slack}"], - "annotation": ["аннотация"], - "There was an issue deleting the selected annotations: %s": [ - "Произошла ошибка при удалении выбранных аннотаций: %s" + "Whether to include a client-side search box": [ + "Отображение строки поиска" ], - "Edit annotation": ["Редактировать аннотацию"], - "Delete annotation": ["Удалить аннотацию"], - "Annotation": ["Аннотация"], - "No annotation yet": ["Пока нет аннотаций"], - "Annotation Layer ${annotationLayerName}": [ - "Слой аннотаций ${annotationLayerName}" + "Whether to include a time filter": [ + "Включить фильтр на определенный интервал/диапазон времени" ], - "Are you sure you want to delete ${annotationCurrentlyDeleting?.short_descr}?": [ - "Вы уверены, что хотите удалить ${annotationCurrentlyDeleting?.short_descr}?" + "Whether to include the percentage in the tooltip": [ + "Отображение процентной доли во всплывающей подсказке" ], - "Delete Annotation?": ["Удалить аннотацию?"], - "Are you sure you want to delete the selected annotations?": [ - "Вы уверены, что хотите удалить выбранные аннотации?" + "Whether to include the time granularity as defined in the time section": [ + "Добавляет столбец даты/времени с группировкой дат, как определено в разделе Время" ], - "Add annotation": ["Добавить слой аннотации"], - "Annotation name": ["Слои аннотаций"], - "date": ["дата"], - "Additional information": ["Дополнительные метаданные"], - "Description (this can be seen in the list)": [ - "Описание (будет видно в списке)" + "Whether to make the grid 3D": ["Сделать сетку 3D"], + "Whether to make the histogram cumulative": [ + "Сделать гистограмму нарастающей" ], - "annotation_layer": ["слой_аннотации"], - "Edit annotation layer properties": [ - "Редактировать свойства слоя аннотаций" + "Whether to make this column available as a [Time Granularity] option, column has to be DATETIME or DATETIME-like": [ + "" ], - "Annotation layer name": ["Имя слоя аннотаций"], - "Annotation layers": ["Слои аннотаций"], - "There was an issue deleting the selected layers: %s": [ - "Произошла ошибка при удалении выбранных слоёв: %s" + "Whether to normalize the histogram": ["Нормализовать гистограмму"], + "Whether to populate autocomplete filters options": [ + "Распространить настройки фильтров автозаполнения" ], - "Last modified": ["Изменено"], - "Created on": ["Дата создания"], - "Edit template": ["Загрузить шаблон"], - "Delete template": ["Загрузить шаблон"], - "Annotation layer": ["Слои аннотаций"], - "An error occurred while fetching dataset datasource values: %s": [ - "Произошла ошибка при получении значений датасета: %s" + "Whether to populate the filter's dropdown in the explore view's filter section with a list of distinct values fetched from the backend on the fly": [ + "" ], - "No annotation layers yet": ["Слои аннотаций"], - "This action will permanently delete the layer.": [ - "Это действие навсегда удалит слой." + "Whether to show extra controls or not. Extra controls include things like making mulitBar charts stacked or side by side.": [ + "Отображает дополнительные элементы управления на самом графике и позволяет менять отображение столбцов: без накопления и с ним." ], - "Delete Layer?": ["Удалить все?"], - "Are you sure you want to delete the selected layers?": [ - "Вы уверены, что хотите удалить выбранные слои?" + "Whether to show minor ticks on the axis": [ + "Отображение мелких отметок на оси" ], - "Are you sure you want to delete": ["Вы уверены, что хотите удалить"], - "Last modified %s": ["Изменено %s"], - "The passwords for the databases below are needed in order to import them together with the charts. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "Для баз данных нужны пароли, чтобы импортировать их вместе с графиками. Пожалуйста, обратите внимание, что разделы “Безопасность” и “Сертификат” в настройках конфигурации базы данных отсутствуют в экспортируемых файлов и должны быть добавлены вручную после импорта, если необходимо." + "Whether to show the pointer": ["Отображение указателя"], + "Whether to show the progress of gauge chart": [""], + "Whether to show the split lines on the axis": [ + "Отображение линий разделения на оси" ], - "You are importing one or more charts that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "Вы импортируете один или несколько графиков, которые уже существуют. Перезапись может привести к потере части вашей работы. Вы уверены, что хотите перезаписать?" + "Whether to sort descending or ascending": [ + "Сортировка по убыванию или по возрастанию" ], - "There was an issue deleting the selected charts: %s": [ - "Произошла ошибка при удалении выбранных графиков: %s" + "Whether to sort descending or ascending if a series limit is present": [ + "Сортировка по убыванию или по возрастанию, если есть ограничение на количество категорий" ], - "Modified by": ["Изменено"], - "Owner": ["Владелец"], - "An error occurred while fetching chart owners values: %s": [ - "Произошла ошибка при получении владельца графика: %s" + "Whether to sort descending or ascending on the X-Axis.": [ + "Сортировка по убыванию или по возрастанию для оси X" ], - "An error occurred while fetching chart created by values: %s": [ - "Произошла ошибка при получении создателя графика: %s" + "Whether to sort results by the selected metric in descending order.": [ + "Сортировка результатов по выбранной мере в порядке убывания" ], - "Viz type": ["Тип"], - "An error occurred while fetching chart dataset values: %s": [ - "Произошла ошибка при получении графиков датасета: %s" + "Whether to sort tooltip by the selected metric in descending order.": [ + "Сортировка выбранных мер по убыванию во всплывающей подсказке" ], - "Favorite": ["Избранное"], - "Yes": ["Да"], - "No": ["Нет"], - "Are you sure you want to delete the selected charts?": [ - "Вы уверены, что хотите удалить выбранные графики?" + "Whether to truncate metrics": [ + "Убирает меру (например, AVG(...)) с легенды рядом с именем измерения и из таблицы результатов" ], - "css_template": ["шаблон_css"], - "Edit CSS template properties": ["Редактирование свойств"], - "Add CSS template": ["Шаблоны CSS"], - "CSS template name": ["Имя Шаблона"], - "css": ["Css"], - "CSS templates": ["Шаблоны CSS"], - "There was an issue deleting the selected templates: %s": [ - "Произошла ошибка при удалении выбранных шаблонов: %s" + "Which country to plot the map for?": ["Выбор страны для графика"], + "Which relatives to highlight on hover": ["Подсвечивается при наведении"], + "Whisker/outlier options": ["Настройки усов/выбросов"], + "White": ["Белый"], + "Width": ["Ширина"], + "Width of the confidence interval. Should be between 0 and 1": [ + "Ширина доверительного интервала. Должна быть между 0 и 1" + ], + "Width of the sparkline": ["Ширина спарклайна"], + "Window must be > 0": ["Окно должно быть > 0"], + "With a subheader": ["С подзаголовком"], + "Word Cloud": ["Облако слов"], + "Word Rotation": ["Поворот текста"], + "Working": ["Обрабатывается"], + "Working timeout": ["Время на рассылку"], + "World Map": ["Карта Мира"], + "Write a description for your query": [ + "Заполните описание к вашему запросу" ], - "Last modified by %s": ["Автор изменений %s"], - "CSS template": ["Шаблоны CSS"], - "This action will permanently delete the template.": [ - "Это действие навсегда удалит шаблон." + "Write a handlebars template to render the data": [""], + "Write dataframe index as a column": [ + "Сделать индекс датафрейма столбцом." ], - "Delete Template?": ["Удалить шаблон?"], - "Are you sure you want to delete the selected templates?": [ - "Вы уверены, что хотите удалить выбранные шаблоны?" + "Write dataframe index as a column.": [ + "Сделать индекс датафрейма столбцом." ], - "The passwords for the databases below are needed in order to import them together with the dashboards. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "Для баз данных нужны пароли, чтобы импортировать их вместе с дашбордами. Пожалуйста, обратите внимание, что разделы “Безопасность” и “Сертификат” в настройках конфигурации базы данных отсутствуют в экспортируемых файлов и должны быть добавлены вручную после импорта, если необходимо." + "X AXIS TITLE BOTTOM MARGIN": ["Отступ снизу названия оси X"], + "X Axis": ["Ось X"], + "X Axis Format": ["Формат оси X"], + "X Axis Label": ["Метка оси X"], + "X Axis Title": ["Название оси X"], + "X Log Scale": ["Логарифмическая ось X"], + "X Tick Layout": ["Расположение делений оси X"], + "X bounds": ["Показывать границы оси X"], + "X-Axis Sort Ascending": ["Сортировать по возрастанию оси X"], + "X-Axis Sort By": [""], + "X-axis": ["Ось X"], + "XScale Interval": [""], + "Y 2 bounds": ["Границы оси Y 2"], + "Y AXIS TITLE MARGIN": ["Отступ названия оси Y"], + "Y AXIS TITLE POSITION": ["Положение названия оси Y"], + "Y Axis": ["Ось Y"], + "Y Axis 1": ["Ось Y 1"], + "Y Axis 2": ["Ось Y 2"], + "Y Axis 2 Bounds": ["Границы оси Y 2"], + "Y Axis Bounds": ["Границы оси Y"], + "Y Axis Format": ["Формат Оси Y"], + "Y Axis Label": ["Метка оси Y"], + "Y Axis Left": ["Ось Y слева"], + "Y Axis Right": ["Ось Y справа"], + "Y Axis Title": ["Название оси Y"], + "Y Log Scale": ["Логарифмическая ось Y"], + "Y bounds": ["Показывать границы оси Y"], + "Y-axis": ["Ось Y"], + "Y-axis bounds": ["Границы оси Y"], + "Year": ["Год"], + "Year (freq=AS)": ["Год (част=AS)"], + "Yearly seasonality": ["Годовая сезонность"], + "Years %s": ["Лет %s"], + "Yes": ["Да"], + "Yes, cancel": ["Да, отменить"], + "Yes, overwrite changes": ["Да, перезаписать изменения"], + "You are importing one or more charts that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "Вы импортируете один или несколько графиков, которые уже существуют. Перезапись может привести к потере части вашей работы. Вы уверены, что хотите перезаписать?" ], "You are importing one or more dashboards that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ "Вы импортируете один или несколько дашбордов, которые уже существуют. Перезапись может привести к потере части вашей работы. Вы уверены, что хотите перезаписать?" ], - "An error occurred while fetching dashboards: %s": [ - "Произошла ошибка при получении дашбордов: %s" - ], - "There was an issue deleting the selected dashboards: ": [ - "Произошла ошибка при удалении выбранных дашбордов: " + "You are importing one or more databases that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "Вы импортируете одну или несколько баз данных, которые уже существуют. Перезапись может привести к потере части вашей работы. Вы уверены, что хотите перезаписать?" ], - "An error occurred while fetching dashboard owner values: %s": [ - "Произошла ошибка при получении владельца дашборда: %s" + "You are importing one or more datasets that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "Вы импортируете один или несколько датасетов, которые уже существуют. Перезапись может привести к потере части вашей работы. Вы уверены, что хотите продолжить?" ], - "An error occurred while fetching dashboard created by values: %s": [ - "Произошла ошибка при получении создателя дашборда: %s" + "You are importing one or more saved queries that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "Вы импортируете один или несколько сохраненных запросов, которые уже существуют. Перезапись может привести к потере части вашей работы. Вы уверены, что хотите продолжить?" ], - "Unpublished": ["Неопубликованные"], - "Are you sure you want to delete the selected dashboards?": [ - "Вы уверены, что хотите удалить выбранные дашборды?" + "You are not authorized to see this query. If you think this is an error, please reach out to your administrator.": [ + "Вы не авторизованы для просмотра этого запроса. Если вы считаете, что это ошибка, пожалуйста, обратитесь к своему администратору" ], - "Sorry, your browser does not support copying.": [ - "Извините, Ваш браузер не поддерживание копирование. Используйте сочетание клавиш [CTRL + C] для WIN или [CMD + C] для MAC." + "You can": ["Вы можете"], + "You can add the components in the": ["Вы можете добавить компоненты в"], + "You can add the components in the edit mode.": [ + "Вы можете добавить компоненты в режиме редактирования." ], - "SQL Copied!": ["SQL скопирован!"], - "The passwords for the databases below are needed in order to import them. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "" + "You can create a new chart or use existing ones from the panel on the right": [ + "Вы можете создать новый график или использовать существующие из панели справа" ], - "You are importing one or more databases that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "You can preview the list of dashboards in the chart settings dropdown.": [ "" ], - "database": ["база данных"], - "An error occurred while fetching database related data: %s": [ - "Произошла ошибка при получении данных о базе данных: %s" - ], - "Asynchronous query execution": [""], - "AQE": ["AQE"], - "Allow data manipulation language": [ - "Разрешить язык манипулирования данными" + "You cannot use 45° tick layout along with the time range filter": [ + "Вы не можете использовать расположение делений под углом 45° при использовании временного фильтра" ], - "DML": ["DML"], - "CSV upload": ["Загрузить CSV"], - "Delete database": ["Выберите базу данных"], - "The database %s is linked to %s charts that appear on %s dashboards. Are you sure you want to continue? Deleting the database will break those objects.": [ - "" + "You cannot use [Columns] in combination with [Group By]/[Metrics]/[Percentage Metrics]. Please choose one or the other.": [ + "Вы не можете использовать [Столбцы] в сочетании с [Группировать по]/[Мерами]/[Процентными мерами]. Пожалуйста, выберите одно или другое." ], - "Delete Database?": ["Удалить базу данных?"], - "Please enter a SQLAlchemy URI to test": [ - "Введите SQLAlchemy URI для теста" + "You do not have permission to edit this chart": [ + "У вас нет прав на редактирование этого графика" ], - "Connection looks good!": ["Соединение в порядке!"], - "ERROR: Connection failed. ": ["ОШИБКА: Соединение не удалось."], - "Sorry there was an error fetching database information: %s": [ - "К сожалению, произошла ошибка при получении информации о базе данных: %s" + "You do not have permission to edit this dashboard": [ + "У вас нет прав на редактирование этого дашборда" ], - "Edit database": ["Редактировать Базу Данных"], - "Add database": ["Добавить Базу Данных"], - "Connection": ["Тестовое соединение"], - "Database name": ["Название таблицы"], - "Name your dataset": ["Назовите свой датасет"], - "dialect+driver://username:password@host:port/database": [ - "диалект+драйвер://пользователь:пароль@хост:порт/схема" + "You do not have permissions to access the datasource(s): %(name)s.": [ + "У вас нет доступа этого источника данных: %(name)s." ], - "Test connection": ["Тестовое соединение"], - "Refer to the ": ["Обратитесь сюда "], - "SQLAlchemy docs": ["SQLAlchemy URI"], - " for more information on how to structure your URI.": [ - " за подробной информацией по тому, как структурировать ваш URI" + "You do not have permissions to edit this dashboard.": [ + "У вас нет прав на редактирование этого дашборда." ], - "Performance": ["Производительность"], - "Chart cache timeout": ["Тайм-аут Кэша"], - "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.": [ - "Работа с базой данных в асинхронном режиме означает, что запросы исполняются на удалённых воркерах, а не на веб-сервере Superset. Это подразумевает, что у вас установка с воркерами Celery. Обратитесь к документации по настройке за дополнительной информацией." + "You don't have access to this chart.": [ + "Недостаточно прав для доступа к этому графику." ], - "SQL Lab settings": ["Лаборатория"], - "Allow users to run non-SELECT statements (UPDATE, DELETE, CREATE, ...)": [ - "Позволяет пользователям запускать инструкции (UPDATE, DELETE, CREATE, …) без SELECT в редакторе SQL" + "You don't have access to this dashboard.": [ + "Недостаточно прав для доступа к этому дашборду." ], - "Allow multi schema metadata fetch": [""], - "CTAS schema": ["Схема по умолчанию"], - "When allowing CREATE TABLE AS option in SQL Lab, this option forces the table to be created in this schema.": [ - "При разрешении опции CREATE TABLE AS в лаборатории SQL, эта опция создаст таблицу в выбранной схеме." + "You don't have access to this dataset.": [ + "Недостаточно прав для доступа к этому датасету." ], - "Secure extra": ["Безопасность"], - "JSON string containing additional connection configuration.": [ - "Строка JSON, содержащая дополнительные параметры соединения." + "You don't have access to this embedded dashboard config.": [ + "У вас нет прав на редактирование этого встраиваемого дашборда." ], - "This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.": [ - "Это используется для указания информации о соединении с такими системами как Hive, Presto и BigQuery, которые не укладываются в шаблон пользователь:пароль, который обычно используется в SQLAlchemy." + "You don't have any favorites yet!": ["У вас пока нет избранных!"], + "You don't have permission to modify the value.": [ + "Недостаточно прав для редактирования этого значения." ], - "Optional CA_BUNDLE contents to validate HTTPS requests. Only available on certain database engines.": [ - "" + "You don't have the rights to alter %(resource)s": [ + "Недостаточно прав для изменения %(resource)s" ], - "Impersonate Logged In User (Presto, Trino, Drill & Hive)": [ - "Ассоциировать пользователя" + "You don't have the rights to alter this chart": [ + "Недостаточно прав для изменения графика" ], - "If Presto, Trino or Drill all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them. If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.": [ - "Если вы используете Presto, все запросы в SQL-Редакторе будут выполняться от авторизованного пользователя, который должен иметь разрешение на их выполнение. <br/> Если включен Hive, то запросы будут выполняться через техническую учетную запись, но ассоциировать зарегистрированного пользователя можно через свойство hive.server2.proxy.user." + "You don't have the rights to alter this dashboard": [ + "Недостаточно прав для изменения дашборда" ], - "Allow data upload": ["Разрешить загрузку данных"], - "If selected, please set the schemas allowed for data upload in Extra.": [ - "Если установлено, выберите схемы, в которые разрешена загрузка на вкладке “Дополнительно”." + "You don't have the rights to alter this title.": [ + "Недостаточно прав для изменения названия." ], - "JSON string containing extra configuration elements.": [ - "Строка JSON, содержащая дополнительные элементы конфигурации." + "You don't have the rights to create a chart": [ + "Недостаточно прав для создания графика" ], - "1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.": [ - "" + "You don't have the rights to create a dashboard": [ + "Недостаточно прав для создания дашборда" ], - "2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.": [ - "" + "You don't have the rights to download as csv": [ + "Недостаточно прав для скачивания в CSV" ], - "3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty.": [ - "" + "You have no permission to approve this request": [ + "Недостаточно прав для одобрения этого запроса" ], - "4. The version field is a string specifying this db's version. This should be used with Presto DBs so that the syntax is correct.": [ + "You have removed this filter.": ["Вы удалили фильтр."], + "You have unsaved changes.": ["У вас есть несохраненные изменения."], + "You have used all %(historyLength)s undo slots and will not be able to fully undo subsequent actions. You may save your current state to reset the history.": [ "" ], - "5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.": [ - "" + "You must be a dataset owner in order to edit. Please reach out to a dataset owner to request modifications or edit access.": [ + "Вы должны быть владельцем датасета для его редактирования. Пожалуйста, обратитесь к владельцу с просьбой предоставить доступ." ], - "Error while saving dataset: %s": ["Ошибка при сохранении датасета: %s"], - "Add dataset": ["Добавить Базу Данных"], - "The passwords for the databases below are needed in order to import them together with the datasets. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "Пароли к базам данных требуются, чтобы импортировать их вместе с датасетами. Пожалуйста, обратите внимание, что разделы “Безопасность” и “Сертификат” конфигурации базы данных отсутствуют в экспортируемых файлах и должны быть добавлены после импорта вручную." + "You must pick a name for the new dashboard": [ + "Вы должны выбрать имя для нового дашборда" ], - "You are importing one or more datasets that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "Вы импортируете один или несколько датасетов, которые уже существуют. Перезапись может привести к потере части вашей работы. Вы уверены, что хотите продолжить?" + "You must run the query successfully first": [ + "Сначала необходимо успешно выполнить запрос" ], - "An error occurred while fetching dataset related data": [ - "Произошла ошибка при получении метаданных из таблицы" + "You need to configure HTML sanitization to use CSS": [""], + "You updated the values in the control panel, but the chart was not updated automatically. Run the query by clicking on the \"Update chart\" button or": [ + "Вы обновили значения в панели управления, но график не был обновлен автоматически. Сделайте запрос, нажав на кнопку \"Обновить график\" или" ], - "An error occurred while fetching dataset related data: %s": [ - "Произошла ошибка при получении данных о датасете: %s" + "You've changed datasets. Any controls with data (columns, metrics) that match this new dataset have been retained.": [ + "Вы изменили датасеты. Все элементы управления с данными (столбцами, мерами), которые соответствуют новому датасету, были сохранены." ], - "Physical dataset": ["Физический датасет"], - "Virtual dataset": ["Виртуальный датасет"], - "An error occurred while fetching dataset owner values: %s": [ - "Произошла ошибка при получении создателя датасета: %s" + "Your chart is not up to date": ["Ваш график не актуален"], + "Your chart is ready to go!": ["Ваш график готов!"], + "Your dashboard is too large. Please reduce its size before saving it.": [ + "Дашборд слишком большой. Пожалуйста, уменьшите его размер перед сохранением." ], - "An error occurred while fetching datasets: %s": [ - "Произошла ошибка при получении датасетов: %s" + "Your query could not be saved": ["Не удалось сохранить ваш запрос"], + "Your query could not be scheduled": [ + "Не удалось запланировать ваш запрос" ], - "An error occurred while fetching schema values: %s": [ - "Произошла ошибка при построении графика: %s" + "Your query could not be updated": ["Не удалось обновить ваш запрос"], + "Your query has been scheduled. To see details of your query, navigate to Saved queries": [ + "Запрос был запланирован. Чтобы посмотреть детали запроса, перейдите в Сохраненные запросы" ], - "There was an issue deleting the selected datasets: %s": [ - "Произошла ошибка при удалении выбранных датасетов: %s" + "Your query was not properly saved": [ + "Ваш запрос не был сохранен должным образом" ], - "The dataset %s is linked to %s charts that appear on %s dashboards. Are you sure you want to continue? Deleting the dataset will break those objects.": [ - "Датасет %s привязан к графикам %s, которые используются в дашбордах %s. Вы уверены, что хотите продолжить? Удаление датасета приведёт к неработоспособности этих объектов." + "Your query was saved": ["Ваш запрос был сохранен"], + "Your query was updated": ["Ваш запрос был сохранен"], + "Your report could not be deleted": ["Не удается удалить рассылку"], + "Zero imputation": ["Нулевые значения"], + "Zoom": ["Масштабирование"], + "Zoom level of the map": ["Уровень масштабирования карты"], + "[ untitled dashboard ]": ["[ безымянный дашборд ]"], + "[Longitude] and [Latitude] columns must be present in [Group By]": [ + "Столбцы [Долгота] и [Широта] должны присутствовать в [Группировать по]" ], - "Delete Dataset?": ["Удалить все?"], - "Are you sure you want to delete the selected datasets?": [ - "Вы уверены, что хотите удалить выбранные датасеты?" + "[Longitude] and [Latitude] must be set": [ + "[Долгота] и [Широта] должны быть заданы" ], - "0 Selected": ["Выполнить выбранный запрос"], - "%s Selected (Virtual)": ["%s Выбрано (Виртуальные)"], - "%s Selected (Physical)": ["%s Выбрано (Физические)"], - "%s Selected (%s Physical, %s Virtual)": [ - "%s Выбрано (%s Физические, %s Виртуальные)" + "[Missing Dataset]": ["[отсутствующий датасет]"], + "[Superset] Access to the datasource %(name)s was granted": [ + "[Суперсет] Предоставлен доступ к источнику данных %(name)s" ], - "There was an issue previewing the selected query. %s": [ - "Возникла ошибка при предпросмотре выбранных запросов: %s" + "[Untitled]": ["[Без названия]"], + "[dashboard name]": ["[имя дашборда]"], + "[desc]": [""], + "[optional] this secondary metric is used to define the color as a ratio against the primary metric. When omitted, the color is categorical and based on labels": [ + "[необязательно] вторичная мера используется для определения цвета как доли по отношению к основной мере. Если не выбрано, цвет задается согласно имени категории" ], - "Success": ["Успешно"], - "Failed": ["Ошибка"], - "Running": ["Выполняется"], - "Offline": [""], - "Scheduled": ["Запланировано"], - "Duration: %s": ["Продолжительность: %s"], - "Tab name": ["Имя Таблицы"], - "TABLES": ["ТАБЛИЦЫ"], - "Rows": ["Игнорировать"], - "Open query in SQL Lab": ["Открыть в SQL редакторе"], - "An error occurred while fetching database values: %s": [ - "Произошла ошибка при получении значений базы данных: %s" + "[untitled]": ["[без названия]"], + "`compare_columns` must have the same length as `source_columns`.": [""], + "`compare_type` must be `difference`, `percentage` or `ratio`": [""], + "`confidence_interval` must be between 0 and 1 (exclusive)": [ + "`доверительный_интервал` должен быть между 0 и 1 (не включая концы)" ], - "Search by query text": ["Поиск по тексту запроса"], - "Query preview": ["Предпросмотр данных"], - "Previous": ["Предпросмотр %s"], - "Next": ["След"], - "Open in SQL Lab": ["Открыть в SQL редакторе"], - "User query": ["Скопировать запрос"], - "Executed query": ["Выполнить выбранный запрос"], - "Saved queries": ["Сохраненные запросы"], - "There was an issue previewing the selected query %s": [ - "Произошла ошибка при предпросмотре выбранного запроса %s" + "`count` is COUNT(*) if a group by is used. Numerical columns will be aggregated with the aggregator. Non-numerical columns will be used to label points. Leave empty to get a count of points in each cluster.": [ + "" ], - "Link Copied!": ["Ссылка скопирована!"], - "There was an issue deleting the selected queries: %s": [ - "Произошла ошибка при удалении выбранных запросов: %s" + "`operation` property of post processing object undefined": [""], + "`prophet` package not installed": [""], + "`rename_columns` must have the same length as `columns`.": [""], + "`row_limit` must be greater than or equal to 0": [""], + "`row_offset` must be greater than or equal to 0": [""], + "`width` must be greater or equal to 0": [""], + "aggregate": ["агрегатная функция"], + "alert": ["оповещение"], + "alerts": ["оповещений"], + "all": ["Все"], + "also copy (duplicate) charts": [ + "также копировать (дублировать) графики" + ], + "ancestor": ["предок"], + "and": ["и"], + "annotation": ["аннотация"], + "annotation_layer": ["слой_аннотации"], + "asfreq": ["asfreq (без изменения)"], + "at": ["в"], + "auto": ["Автоматически"], + "auto (Smooth)": ["Автоматически (плавно)"], + "background": [""], + "below (example:": ["ниже (пример:"], + "between {down} and {up} {name}": [""], + "bfill": ["bfill (заполняет пропуски предыдущими значениями)"], + "bolt": [""], + "boolean type icon": [""], + "bottom": ["снизу"], + "button (cmd + z) until you save your changes.": [ + "(CTRL + Z), пока вы не сохраните изменения." ], - "Edit query": ["Редактировать запрос"], - "Copy query URL": ["Скопировать URL запроса"], - "Delete query": ["Удалить"], - "This action will permanently delete the saved query.": [ - "Это действие навсегда удалит сохранённый запрос." + "by using": [", используя"], + "cannot be empty": ["Необходимо заполнить"], + "chart": ["график"], + "charts": ["графики(ов)"], + "choose WHERE or HAVING...": ["выберите WHERE или HAVING..."], + "clear all filters": ["Сбросить все фильтры"], + "click here": ["нажмите сюда"], + "code ISO 3166-1 alpha-2 (cca2)": ["Код ISO 3166-1 alpha-2 (cca2)"], + "code ISO 3166-1 alpha-3 (cca3)": ["Код ISO 3166-1 alpha-3 (cca3)"], + "code International Olympic Committee (cioc)": [ + "Код Международного Олимпийского Комитета (cioc)" ], - "Delete Query?": ["Удалить запрос?"], - "Are you sure you want to delete the selected queries?": [ - "Вы уверены, что хотите удалить выбранные запросы?" + "column": ["столбец"], + "connecting to %(dbModelName)s.": ["подключении к %(dbModelName)s"], + "count": ["количество"], + "create": ["создать"], + "create a new chart": ["создать новый график"], + "create dataset from SQL query": ["создайте датасет из SQL запроса"], + "css": ["css"], + "css_template": ["шаблон_css"], + "cumsum": ["Кумулятивная сумма"], + "cumulative": ["кумулятивно"], + "dashboard": ["дашборд"], + "dashboards": ["дашборды(ов)"], + "database": ["база данных"], + "dataset": ["датасет"], + "dataset name": ["Имя датасета"], + "date": ["дата"], + "day": ["день"], + "day of the month": ["день месяца"], + "day of the week": ["день недели"], + "deck.gl 3D Hexagon": ["deck.gl 3D Шестигранники"], + "deck.gl Arc": ["deck.gl Дуга"], + "deck.gl Geojson": ["deck.gl GeoJSON"], + "deck.gl Grid": ["deck.gl Сетка"], + "deck.gl Multiple Layers": ["deck.gl Многослойный"], + "deck.gl Polygon": ["deck.gl Полигон"], + "deck.gl Scatterplot": ["deck.gl Точечная карта"], + "deckGL": ["Карта deckGL"], + "default": ["по умолчанию"], + "delete": ["удалить"], + "descendant": ["потомок"], + "description": ["описание"], + "dialect+driver://username:password@host:port/database": [ + "диалект+драйвер://пользователь:пароль@хост:порт/схема" ], - "Query name": ["Страна"], - "Edited": ["Редактировано"], - "Created": ["Создано"], - "Viewed": ["Просмотрено"], - "Examples": ["Примеры"], - "Mine": ["Мои"], - "Recently viewed charts, dashboards, and saved queries will appear here": [ - "Недавно просмотренные графики, дашборды и сохранённые запросы" + "draft": ["черновик"], + "dttm": ["Дата/время"], + "e.g. ********": ["например, ********"], + "e.g. 127.0.0.1": ["например, 127.0.0.1"], + "e.g. 5432": ["например, 5432"], + "e.g. AccountAdmin": [""], + "e.g. Analytics": ["например, Analytics"], + "e.g. compute_wh": [""], + "e.g. param1=value1¶m2=value2": [ + "например, параметр1=значение1&параметр2=значение2" + ], + "e.g. sql/protocolv1/o/12345": [""], + "e.g. world_population": ["например, health_medicine"], + "e.g. xy12345.us-east-2.aws": [""], + "e.g., a \"user id\" column": [ + "например, столбец \"идентификатор пользователя\"" + ], + "edit mode": ["режиме редактирования"], + "every": ["каждые"], + "every day of the month": ["каждый день месяца"], + "every day of the week": ["каждый день недели"], + "every hour": ["каждый час"], + "every minute": ["каждая минута"], + "every month": ["каждый месяц"], + "expand": ["развернуть"], + "explore": ["исследовать"], + "ffill": ["ffill (заполняет пропуски следующими значениями)"], + "filter_box will be deprecated in a future version of Superset. Please replace filter_box by dashboard filter components.": [ + "filter_box устарел и будет удален в будущей версии Суперсета. Пожалуйста, замените его фильтрами в левой панели дашборда." + ], + "flat": [""], + "for more information on how to structure your URI.": [ + " за подробной информацией по тому, как структурировать ваш URI" ], - "Recently created charts, dashboards, and saved queries will appear here": [ - "Недавно созданные графики, дашборды и сохранённые запросы" + "function type icon": [""], + "geohash (square)": [""], + "green": ["Зеленая"], + "heatmap": ["тепловая карта"], + "heatmap: values are normalized across the entire heatmap": [ + "тепловая карта: значения нормализованы внутри всей карты" ], - "Recent example charts, dashboards, and saved queries will appear here": [ - "Примеры графиков, дашбордов и сохранённых запросов" + "here": ["здесь"], + "hour": ["час"], + "id": ["идентификатор"], + "image-rendering CSS attribute of the canvas object that defines how the browser scales up the image": [ + "" ], - "Recently edited charts, dashboards, and saved queries will appear here": [ - "Недавно изменённые графики, дашборды и сохранённые запросы" + "in": ["в"], + "in modal": ["в модальном окне"], + "is expected to be a number": ["Ожидается число"], + "is expected to be an integer": ["Ожидается целое число"], + "joined": ["Присоединился"], + "json isn't valid": ["JSON не валиден"], + "key a-z": ["По алфавиту А-Я"], + "key z-a": ["По алфавиту Я-А"], + "label": ["метка"], + "last day": ["последний день"], + "last month": ["последний месяц"], + "last quarter": ["последний квартал"], + "last week": ["последняя неделя"], + "last year": ["последний год"], + "latest partition:": ["последний раздел:"], + "left": ["слева"], + "less than {min} {name}": [""], + "log": ["журнал"], + "lower percentile must be greater than 0 and less than 100. Must be lower than upper percentile.": [ + "Нижний процентиль должен быть больше 0 и меньше 100. Должен быть ниже верхнего процентиля" ], - "${tableName\n .split('')\n .slice(0, tableName.length - 1)\n .join('')}\n ": [ + "max": ["Максимум"], + "mean": ["Среднее"], + "median": ["Медиана"], + "metric": ["мера"], + "min": ["Минимум"], + "minute": ["минута"], + "minute(s)": ["минут"], + "month": ["месяц"], + "more than {max} {name}": [""], + "must have a value": ["значение обязательно"], + "name": ["имя"], + "no SQL validator is configured": ["не настроен ни один SQL валидатор"], + "no SQL validator is configured for {}": [ + "не настроен ни один SQL валидатор для {}" + ], + "numeric type icon": [""], + "nvd3": ["Графики nvd3"], + "on": ["по"], + "or use existing ones from the panel on the right": [ + "или использовать уже существующие из панели справа" + ], + "p-value precision": ["точность p-значения"], + "p1": ["p1"], + "p5": ["p5"], + "p95": ["p95"], + "p99": ["p99"], + "page_size.all": [""], + "page_size.entries": [""], + "page_size.show": [""], + "percentile (exclusive)": ["перцентиль (исключая)"], + "percentiles must be a list or tuple with two numeric values, of which the first is lower than the second value": [ "" ], - "You don't have any favorites yet!": ["У вас пока нет избранного!"], - "SQL Lab queries": ["Лаборатория"], - "${tableName}": ["Имя Таблицы"], + "permalink state not found": [""], + "pixelated (Sharp)": [""], + "previous calendar month": ["предыдущий календарный месяц"], + "previous calendar week": ["предыдущая календарная неделя"], + "previous calendar year": ["предыдущий календарный год"], + "published": ["опубликовано"], + "quarter": ["Квартал"], + "queries": ["запросы"], "query": ["запрос"], - "Share": ["Поделиться"], - "Last run %s": ["Последнее выполнение %s"], - "Recents": ["Последние"], - "Select start and end date": ["Выберите дату начала"], - "Type or Select [%s]": ["Выбрать [%s]"], - "Filter box": ["Фильтр"], - "Filters configuration": ["Изменение настроек таблицы"], - "Filter configuration for the filter box": ["Настройки фильтра"], - "Date filter": ["Временной фильтр"], - "Whether to include a time filter": [ - "Включить фильтр на определенный интервал/диапазон времени" + "random": ["случайно"], + "reboot": ["обновить"], + "recent": ["недавние"], + "recents": ["недавние(их)"], + "red": ["Красная"], + "report": ["рассылка"], + "reports": ["рассылки"], + "restore zoom": ["восстановить масштабирование"], + "right": ["справа"], + "saved queries": ["сохраненные(ых) запросы(ов)"], + "seconds": ["секунд"], + "series": ["категории"], + "series: Treat each series independently; overall: All series use the same scale; change: Show changes compared to the first data point in each series": [ + "" ], - "Instant filtering": ["Мгновенная Фильтрация"], - "Check to apply filters instantly as they change instead of displaying [Apply] button": [ + "std": ["Стандартное отклонение"], + "step-after": [""], + "step-before": [""], + "stream": ["поток"], + "string type icon": [""], + "sum": ["Сумма"], + "syntax.": [""], + "temporal type icon": [""], + "textarea": ["текстовая область"], + "to": ["по"], + "top": ["сверху"], + "undo": ["отмены"], + "unknown type icon": [""], + "upper percentile must be greater than 0 and less than 100. Must be higher than lower percentile.": [ "" ], - "Show SQL granularity dropdown": [""], - "Check to include SQL granularity dropdown": [""], - "Show SQL time column": ["Показать колонку Druid"], - "Check to include time column dropdown": [ - "Включить фильтр на определенный интервал/диапазон времени" + "value ascending": ["Значение по возрастанию"], + "value descending": ["Значение по убыванию"], + "var": ["Дисперсия"], + "variance": ["Дисперсия"], + "virtual": ["Виртуальный"], + "viz type": ["тип визуализации"], + "was created": ["создан(а)"], + "week": ["неделя"], + "week ending Saturday": ["неделя, заканчивающаяся в субботу"], + "week starting Sunday": ["неделя, начинающаяся в воскресенье"], + "x": ["x"], + "x: values are normalized within each column": [ + "x: значения нормализованы внутри каждого столбца" ], - "Show Druid granularity dropdown": [""], - "Check to include Druid granularity dropdown": [""], - "Show Druid time origin": ["Показать Druid Метрики"], - "Check to include time origin dropdown": [ - "Включить фильтр на определенный интервал/диапазон времени" + "y": ["y"], + "y: values are normalized within each row": [ + "y: значения нормализованы внутри каждой строки" ], - "Limit selector values": [""], - "These filters apply to the values available in the dropdowns": [""], - "Time-series Table": ["Таблица временных рядов"] + "year": ["год"], + "yellow": ["Желтая"], + "zoom area": ["область масштабирования"] } } } diff --git a/superset/translations/ru/LC_MESSAGES/messages.po b/superset/translations/ru/LC_MESSAGES/messages.po index 8cfde5eed55ce..5df8aae967d68 100644 --- a/superset/translations/ru/LC_MESSAGES/messages.po +++ b/superset/translations/ru/LC_MESSAGES/messages.po @@ -17,19 +17,20 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-12-08 12:22+0800\n" -"PO-Revision-Date: 2021-04-29 02:41+0300\n" -"Last-Translator: Aleksandr Gordienko\n" +"POT-Creation-Date: 2023-02-06 11:42+0300\n" +"PO-Revision-Date: 2023-01-09 14:32+0300\n" +"Last-Translator: Artem Shumeiko\n" "Language: ru\n" "Language-Team: Russian <>\n" -"Plural-Forms: nplurals=1; plural=0\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.11.0\n" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx:68 -#: superset-frontend/src/explore/components/controls/OptionControls/index.tsx:323 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx:71 +#: superset-frontend/src/explore/components/controls/OptionControls/index.tsx:329 msgid "" "\n" " This filter was inherited from the dashboard's context.\n" @@ -38,69 +39,50 @@ msgid "" msgstr "" "\n" " Фильтр был наследован из контекста дашборда.\n" -" Это не будет сохранено при сохранении графика.\n" +" Он не будет сохранен при сохранении графика.\n" " " -#: superset/tasks/schedules.py:184 +#: superset/reports/notifications/email.py:89 #, python-format msgid "" "\n" -" <b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>\n" -" <img src=\"cid:%(msgid)s\">\n" +" Error: %(text)s\n" " " msgstr "" "\n" -" <b><a href=“%(url)s”>Исследовать в Superset</a></b><p></p>\n" -" <img src=“cid:%(msgid)s”>\n" +" Ошибка: %(text)s\n" " " -#: superset/reports/notifications/email.py:60 -#, python-format -msgid "" -"\n" -" Error: %(text)s\n" -" " -msgstr "" +#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:129 +msgid " (excluded)" +msgstr " (исключено)" -#: superset/tasks/schedules.py:159 -#, python-format +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:222 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:235 msgid "" -"\n" -" *%(name)s*\n" -"\n" -" <%(url)s|Explore in Superset>\n" -" " +" Set the opacity to 0 if you do not want to override the color specified " +"in the GeoJSON" msgstr "" -"\n" -" *%(name)s*\n" -"\n" -" <%(url)s|Исследовать в Superset>\n" -" " +" Установите прозрачность 0, если вы не хотите переписывать цвет, " +"указанный в GeoJSON" -#: superset/tasks/schedules.py:372 -#, python-format -msgid "" -"\n" -" *%(slice_name)s*\n" -"\n" -" <%(slice_url_user_friendly)s|Explore in Superset>\n" -" " -msgstr "" -"\n" -" *%(slice_name)s*\n" -"\n" -" <%(slice_url_user_friendly)s|Исследовать в Superset>\n" -" " +#: superset-frontend/src/explore/components/SaveModal.tsx:354 +msgid " a dashboard OR " +msgstr " дашборд или " -#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:122 -msgid " (excluded)" -msgstr "" +#: superset-frontend/src/explore/components/SaveModal.tsx:356 +msgid " a new one" +msgstr " новый" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:235 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:302 msgid " expression which needs to adhere to the " -msgstr "" +msgstr ", который должен придерживаться " + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:48 +msgid " source code of Superset's sandboxed parser" +msgstr " исходный код sandboxed парсера Суперсета" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:239 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:306 msgid "" " standard to ensure that the lexicographical ordering\n" " coincides with the chronological ordering. If the\n" @@ -117,199 +99,260 @@ msgid "" "defaults on a per\n" " database/column name level via the extra parameter." msgstr "" +" стандарта для обеспечения того, чтобы лексикографический порядок " +"совпадал с хронологическим порядком. Если формат временной метки не " +"соответствует стандарту ISO 8601, вам нужно будет определить выражение и " +"тип для преобразования строки в дату или временную метку. В настоящее " +"время часовые пояса не поддерживаются. Если время хранится в формате " +"эпохи, введите \\`epoch_s\\` или \\`epoch_ms\\`. Если шаблон не указан, " +"будут использованы необязательные значения по умолчанию на уровне имен " +"для каждой базы данных/столбца с помощью дополнительного параметра." -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:111 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:332 +msgid " to add calculated columns" +msgstr " для добавления вычисляемых столбцов" + +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:397 +msgid " to add metrics" +msgstr " для добавления мер" + +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:381 +msgid " to edit or add columns and metrics." +msgstr " для редактирования или добавления столбцов и мер." + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:321 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:356 +msgid " to mark a column as a time column" +msgstr ", чтобы пометить столбец как столбец даты/времени" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx:46 +msgid " to open SQL Lab. From there you can save the query as a dataset." +msgstr " в Лаборатории SQL. Там вы сможете сохранить запрос как датасет." + +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:332 +msgid " to visualize your data." +msgstr " для визуализации ваших данных." + +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:109 msgid "!= (Is not equal)" msgstr "!= (не равно)" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:125 -msgid "" -"${tableName\n" -" .split('')\n" -" .slice(0, tableName.length - 1)\n" -" .join('')}\n" -" " -msgstr "" - #: superset/security/analytics_db_safety.py:44 -#, fuzzy, python-format +#, python-format msgid "%(dialect)s cannot be used as a data source for security reasons." msgstr "" -"БД SQLite не может быть использована как источник данных из-за " -"потенциальных проблем с безопасностью." +"%(dialect)s не может использоваться в качестве источника данных по " +"соображениям безопасности." -#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:84 -#, fuzzy, python-format +#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:83 +#, python-format msgid "" "%(message)s\n" "This may be triggered by: \n" "%(issues)s" -msgstr "Триггеры:" +msgstr "" +"%(message)s\n" +"Возможные причины: \n" +"%(issues)s" -#: superset/reports/notifications/email.py:122 superset/tasks/schedules.py:364 +#: superset/reports/notifications/email.py:174 #, python-format msgid "%(name)s.csv" msgstr "%(name)s.csv" -#: superset/db_engine_specs/snowflake.py:99 +#: superset/db_engine_specs/snowflake.py:108 #, python-format msgid "%(object)s does not exist in this database." -msgstr "" +msgstr "%(object)s не существует в этой базе данных." + +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:102 +#, python-format +msgid "%(other)s %(tableName)s will appear here" +msgstr "%(other)s %(tableName)s появятся здесь после добавления" -#: superset/reports/notifications/email.py:126 superset/tasks/schedules.py:296 -#: superset/tasks/schedules.py:465 +#: superset/reports/notifications/email.py:183 #, python-format msgid "%(prefix)s %(title)s" msgstr "%(prefix)s %(title)s" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:635 -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:642 -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:656 -#, fuzzy, python-format +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:342 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:360 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:374 +#, python-format msgid "%(rows)d rows returned" -msgstr "строк получено" +msgstr "Получено строк: %(rows)d" #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:93 -#, fuzzy, python-format +#, python-format msgid "" "%(subtitle)s\n" "This may be triggered by:\n" " %(issue)s" -msgstr "Триггеры:" +msgstr "" +"%(subtitle)s\n" +"Возможные причины:\n" +" %(issue)s" #: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:88 #, python-format msgid "%(suggestion)s instead of \"%(undefinedParameter)s?\"" -msgstr "" - -#: superset/views/core.py:366 +msgid_plural "" +"%(firstSuggestions)s or %(lastSuggestion)s instead of " +"\"%(undefinedParameter)s\"?" +msgstr[0] "%(suggestion)s вместо \"%(undefinedParameter)s\"?" +msgstr[1] "" +"%(firstSuggestions)s или %(lastSuggestion)s вместо " +"\"%(undefinedParameter)s\"?" +msgstr[2] "" +"%(firstSuggestions)s или %(lastSuggestion)s вместо " +"\"%(undefinedParameter)s\"?" + +#: superset/views/core.py:382 #, python-format msgid "" "%(user)s was granted the role %(role)s that gives access to the " "%(datasource)s" msgstr "" -"%(user)s была предоставлена роль %(role)s, которая дает доступ к ресурсам" -" %(datasource)s" +"%(user)s была назначена роль %(role)s, которая дает доступ к " +"%(datasource)s" -#: superset/views/core.py:2773 +#: superset/views/core.py:2647 #, python-format msgid "%(user)s's profile" -msgstr "Профиль пользователя %(user)s" +msgstr "%(user)s - профиль" -#: superset/views/core.py:2442 +#: superset/databases/commands/validate_sql.py:73 superset/views/core.py:2302 #, python-format msgid "" "%(validator)s was unable to check your query.\n" "Please recheck your query.\n" "Exception: %(ex)s" msgstr "" +"%(validator)s не смог проверить ваш запрос.\n" +"Пожалуйста, перепроверьте ваш запрос.\n" +"Ошибка: %(ex)s" -#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:170 -#, python-format -msgid "%s - untitled" -msgstr "%s - без названия" - -#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:90 +#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:89 #, python-format msgid "%s Error" msgstr "%s Ошибка" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1184 +#, python-format +msgid "%s PASSWORD" +msgstr "%s ПАРОЛЬ" + #: superset-frontend/src/components/ListView/ListView.tsx:244 #, python-format msgid "%s Selected" msgstr "%s Выбрано" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:685 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:836 #, python-format msgid "%s Selected (%s Physical, %s Virtual)" msgstr "%s Выбрано (%s Физические, %s Виртуальные)" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:678 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:829 #, python-format msgid "%s Selected (Physical)" msgstr "%s Выбрано (Физические)" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:671 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:822 #, python-format msgid "%s Selected (Virtual)" msgstr "%s Выбрано (Виртуальные)" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:311 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:310 #, python-format msgid "%s aggregates(s)" -msgstr "%s агрегат(ы)" +msgstr "Агрегатных функций: %s" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:249 -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:270 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:286 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:302 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:272 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:369 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:347 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:301 #, python-format msgid "%s column(s)" -msgstr "Столбец(ы) %s" +msgstr "Столбцов: %s" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:276 -#, python-format -msgid "%s column(s) and metric(s)" -msgstr "%s столбец(ы) и показатель(и)" - -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:297 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:357 #, python-format msgid "%s operator(s)" msgstr "%s параметр(ы)" -#: superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx:83 -#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:256 -#: superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx:82 -#: superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx:92 -#, fuzzy, python-format +#: superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx:87 +#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:264 +#: superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx:86 +#: superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx:96 +#, python-format msgid "%s option" -msgstr "%s параметр(ы)" +msgid_plural "%s options" +msgstr[0] "%s вариант" +msgstr[1] "%s варианта" +msgstr[2] "%s вариантов" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:252 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:322 #, python-format msgid "%s option(s)" -msgstr "%s параметр(ы)" +msgstr "%s вариант(ов)" + +#: superset-frontend/src/explore/components/RowCountLabel/index.tsx:43 +#, python-format +msgid "%s row" +msgid_plural "%s rows" +msgstr[0] "%s строка" +msgstr[1] "%s строки" +msgstr[2] "%s строк" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:320 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:319 #, python-format msgid "%s saved metric(s)" -msgstr "%s сохранённый показатель(и)" +msgstr "Сохраненная мер: %s" + +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:617 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:633 +#, python-format +msgid "%s updated" +msgstr "Обновлено: %s" -#: superset-frontend/src/components/URLShortLinkButton/index.jsx:59 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:123 +#: superset-frontend/src/SqlLab/utils/newQueryTabName.ts:43 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:127 #, python-format msgid "%s%s" -msgstr "" +msgstr "%s%s" -#: superset-frontend/src/components/ListView/ListView.tsx:419 -#: superset-frontend/src/components/TableView/TableView.tsx:237 +#: superset-frontend/src/components/ListView/ListView.tsx:438 +#: superset-frontend/src/components/TableView/TableView.tsx:250 #, python-format msgid "%s-%s of %s" -msgstr "" +msgstr "%s-%s из %s" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx:110 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx:115 msgid "(Removed)" msgstr "(Удалено)" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:637 -#, fuzzy -msgid "(deleted)" -msgstr "удалить" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:92 +msgid "(deleted or invalid type)" +msgstr "(удалено или невалидный тип)" -#: superset-frontend/src/utils/getClientErrorObject.ts:56 +#: superset-frontend/src/utils/getClientErrorObject.ts:76 msgid "(no description, click to see stack trace)" -msgstr "" +msgstr "(нет описания, нажмите для просмотра трассировки стека)" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:168 msgid "" "(optional) default value for the filter, when using the multiple option, " "you can use a semicolon-delimited list of options." msgstr "" -"(опционально) значение по-умолчанию для фильтраю. Когда используются " +"(опционально) значение по умолчанию для фильтра. Когда используются " "множественные значения, вы можете вставить список значений, разделённых " "символами точка с запятой" -#: superset/reports/notifications/slack.py:50 +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:71 +msgid "), and they become available in your SQL (example:" +msgstr "), и они станут доступны в ваших SQL запросах (пример:" + +#: superset/reports/notifications/slack.py:71 #, python-format msgid "" "*%(name)s*\n" @@ -320,8 +363,15 @@ msgid "" "\n" "%(table)s\n" msgstr "" +"*%(name)s*\n" +"\n" +"%(description)s\n" +"\n" +"<%(url)s|Исследовать в Суперсете>\n" +"\n" +"%(table)s\n" -#: superset/reports/notifications/slack.py:67 +#: superset/reports/notifications/slack.py:88 #, python-format msgid "" "*%(name)s*\n" @@ -330,112 +380,352 @@ msgid "" "\n" "Error: %(text)s\n" msgstr "" +"*%(name)s*\n" +"\n" +"%(description)s\n" +"\n" +"Ошибка: %(text)s\n" + +#: superset-frontend/src/components/ListView/CrossLinksTooltip.tsx:64 +#, python-format +msgid "+ %s more" +msgstr "+ еще %s" -#: superset-frontend/src/explore/components/SaveModal.tsx:35 -msgid "**Select** a dashboard OR **create** a new one" -msgstr "**Выберите** дашборд ИЛИ **создайте** новый" +#: superset/views/database/forms.py:153 +msgid "," +msgstr "," -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:260 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:626 msgid "" "-- Note: Unless you save your query, these tabs will NOT persist if you " "clear your cookies or change browsers.\n" "\n" msgstr "" +"-- Примечание: Пока вы не сохраните ваш запрос, эти вкладки НЕ будут " +"сохранены, если вы очистите куки или смените браузер.\n" +"\n" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:668 -msgid "0 Selected" -msgstr "Выполнить выбранный запрос" +#: superset/views/database/forms.py:154 +msgid "." +msgstr "." -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:35 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:819 +msgid "0 Selected" +msgstr "0 выбрано" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:165 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:238 +msgid "1 calendar day frequency" +msgstr "Дневная частота" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:168 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:306 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:188 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:456 +#: superset-frontend/src/explore/controlPanels/sections.tsx:184 +#: superset-frontend/src/explore/controls.jsx:262 +msgid "1 day" +msgstr "1 день" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:112 +msgid "1 day ago" +msgstr "1 день назад" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:166 +#: superset-frontend/src/explore/controls.jsx:260 msgid "1 hour" msgstr "1 час" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:32 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:164 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:237 +msgid "1 hourly frequency" +msgstr "Часовая частота" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:163 +#: superset-frontend/src/explore/controls.jsx:257 msgid "1 minute" msgstr "1 минута" -#: superset/db_engine_specs/base.py:91 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:163 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:236 +msgid "1 minutely frequency" +msgstr "Минутная частота" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:168 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:241 +msgid "1 month end frequency" +msgstr "Месячная частота (конец месяца)" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:167 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:240 +msgid "1 month start frequency" +msgstr "Месячная частота (начало месяца)" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:307 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:189 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:457 +#: superset-frontend/src/explore/controlPanels/sections.tsx:185 +msgid "1 week" +msgstr "1 неделя" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:113 +msgid "1 week ago" +msgstr "1 неделя назад" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:62 +msgid "1 week starting Monday (freq=W-MON)" +msgstr "1 неделя с началом в Понедельник (част=W-MON)" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:61 +msgid "1 week starting Sunday (freq=W-SUN)" +msgstr "1 неделя с началом в Воскресенье (част=W-SUN)" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:311 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:193 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:461 +#: superset-frontend/src/explore/controlPanels/sections.tsx:189 +msgid "1 year" +msgstr "1 год" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:117 +msgid "1 year ago" +msgstr "1 год назад" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:170 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:243 +msgid "1 year end frequency" +msgstr "Годовая частота (конец года)" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:169 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:242 +msgid "1 year start frequency" +msgstr "Годовая частота (начало года)" + +#: superset/db_engine_specs/base.py:105 msgid "10 minute" -msgstr "1 минута" +msgstr "10 минут" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:30 -msgid "10 seconds" -msgstr "10 секунд" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:312 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:194 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:462 +#: superset-frontend/src/explore/controlPanels/sections.tsx:190 +msgid "104 weeks" +msgstr "104 недели" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:37 -msgid "12 hours" -msgstr "12 часов" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:118 +msgid "104 weeks ago" +msgstr "104 недели назад" -#: superset/db_engine_specs/base.py:92 -#, fuzzy +#: superset/db_engine_specs/base.py:106 msgid "15 minute" -msgstr "1 минута" +msgstr "15 минут" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:38 -msgid "24 hours" -msgstr "24 часа" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:314 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:196 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:464 +#: superset-frontend/src/explore/controlPanels/sections.tsx:192 +msgid "156 weeks" +msgstr "156 недель" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:32 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:120 +msgid "156 weeks ago" +msgstr "156 недель назад" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:360 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:242 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:512 +#: superset-frontend/src/explore/controlPanels/sections.tsx:238 +msgid "1AS" +msgstr "1С" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:357 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:239 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:509 +#: superset-frontend/src/explore/controlPanels/sections.tsx:235 +msgid "1D" +msgstr "1Д" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:356 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:238 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:508 +#: superset-frontend/src/explore/controlPanels/sections.tsx:234 +msgid "1H" +msgstr "1Ч" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:359 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:241 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:511 +#: superset-frontend/src/explore/controlPanels/sections.tsx:237 +msgid "1M" +msgstr "1М" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:355 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:237 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:507 +#: superset-frontend/src/explore/controlPanels/sections.tsx:233 +msgid "1T" +msgstr "1МИН" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:313 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:195 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:463 +#: superset-frontend/src/explore/controlPanels/sections.tsx:191 +msgid "2 years" +msgstr "2 года" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:119 +msgid "2 years ago" +msgstr "2 года назад" + +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:96 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:49 +msgid "2/98 percentiles" +msgstr "2/98 перцентели" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:126 +msgid "22" +msgstr "22" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:308 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:190 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:458 +#: superset-frontend/src/explore/controlPanels/sections.tsx:186 +msgid "28 days" +msgstr "28 дней" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:114 +msgid "28 days ago" +msgstr "28 дней назад" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:35 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:35 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:37 msgid "2D" -msgstr "" +msgstr "2D карты" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:116 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:136 msgid "3 letter code of the country" -msgstr "каждый день месяца" +msgstr "3х буквенный код страны" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:128 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:315 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:197 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:465 +#: superset-frontend/src/explore/controlPanels/sections.tsx:193 +msgid "3 years" +msgstr "3 года" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:121 +msgid "3 years ago" +msgstr "3 года назад" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:309 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:191 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:459 +#: superset-frontend/src/explore/controlPanels/sections.tsx:187 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:124 msgid "30 days" msgstr "30 дней" -#: superset/db_engine_specs/base.py:93 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:115 +msgid "30 days ago" +msgstr "30 дней назад" + +#: superset/db_engine_specs/base.py:107 msgid "30 minute" msgstr "30 минут" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:34 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:165 +#: superset-frontend/src/explore/controls.jsx:259 msgid "30 minutes" msgstr "30 минут" -#: superset/db_engine_specs/base.py:88 -#, fuzzy +#: superset/db_engine_specs/base.py:102 msgid "30 second" msgstr "30 секунд" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:31 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:162 +#: superset-frontend/src/explore/controls.jsx:256 msgid "30 seconds" msgstr "30 секунд" -#: superset/db_engine_specs/base.py:90 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:35 +msgid "3D" +msgstr "3D карты" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:64 +msgid "4 weeks (freq=4W-MON)" +msgstr "4 недели (част=4W-MON)" + +#: superset/db_engine_specs/base.py:104 msgid "5 minute" msgstr "5 минут" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:33 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:164 +#: superset-frontend/src/explore/controls.jsx:258 msgid "5 minutes" msgstr "5 минут" -#: superset/db_engine_specs/base.py:87 -#, fuzzy +#: superset/db_engine_specs/base.py:101 msgid "5 second" -msgstr "30 секунд" - -#: superset/db_engine_specs/base.py:95 -#, fuzzy +msgstr "5 секунд" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:161 +#: superset-frontend/src/explore/controls.jsx:255 +msgid "5 seconds" +msgstr "5 секунд" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:310 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:192 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:460 +#: superset-frontend/src/explore/controlPanels/sections.tsx:188 +msgid "52 weeks" +msgstr "52 недели" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:116 +msgid "52 weeks ago" +msgstr "52 недели назад" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:60 +msgid "52 weeks starting Monday (freq=52W-MON)" +msgstr "52 недели с началом в Понедельник (част=52W-MON)" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:167 +#: superset-frontend/src/explore/controls.jsx:261 +#: superset/db_engine_specs/base.py:109 msgid "6 hour" msgstr "6 часов" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:36 -msgid "6 hours" -msgstr "6 часов" - -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:132 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:128 msgid "60 days" msgstr "60 дней" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:136 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:166 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:239 +msgid "7 calendar day frequency" +msgstr "Недельная частота" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:169 +#: superset-frontend/src/explore/controls.jsx:263 +msgid "7 days" +msgstr "7 дней" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:358 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:240 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:510 +#: superset-frontend/src/explore/controlPanels/sections.tsx:236 +msgid "7D" +msgstr "7Д" + +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:97 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:50 +msgid "9/91 percentiles" +msgstr "9/91 перцентели" + +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:132 msgid "90 days" msgstr "90 дней" @@ -443,24 +733,40 @@ msgstr "90 дней" msgid ":" msgstr ":" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:86 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:89 msgid "< (Smaller than)" msgstr "< (меньше чем)" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:96 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:97 msgid "<= (Smaller or equal)" msgstr "<= (меньше или равно)" -#: superset/tasks/schedules.py:171 superset/tasks/schedules.py:365 -#, python-format -msgid "<b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>" -msgstr "<b><a href=“%(url)s”>Исследовать в Superset</a></b><p></p>" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1424 +msgid "<enter SQL expression here>" +msgstr "<введите SQL выражение>" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:494 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1421 +msgid "<new column>" +msgstr "<новый столбец>" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1259 +msgid "<new metric>" +msgstr "<новая мера>" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:979 +msgid "<new spatial>" +msgstr "<новая пространственная мера>" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:106 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:980 +msgid "<no type>" +msgstr "<без типа>" + +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:105 msgid "== (Is equal)" msgstr "== (равно)" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:91 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:93 msgid "> (Larger than)" msgstr "> (больше чем)" @@ -468,119 +774,145 @@ msgstr "> (больше чем)" msgid ">= (Larger or equal)" msgstr ">= (больше или равно)" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:35 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:34 msgid "A Big Number" -msgstr "Big Number" +msgstr "Карточка" -#: superset/views/alerts.py:195 -msgid "" -"A SQL statement that defines whether the alert should get triggered or " -"not. The query is expected to return either NULL or a number value." +#: superset/views/database/forms.py:184 +msgid "A comma separated list of columns that should be parsed as dates" msgstr "" -"SQL-выражение, которое определяет сработало оповещение или нет. Запрос " -"должен вернуть NULL или числовое значение." +"Разделённый запятыми список столбцов, которые должны быть " +"интерпретированы как даты." -#: superset/views/database/forms.py:204 superset/views/database/forms.py:341 +#: superset/views/database/forms.py:367 msgid "A comma separated list of columns that should be parsed as dates." msgstr "" -"Разделённый запятыми список столбцов, которые должен быть " +"Разделённый запятыми список столбцов, которые должны быть " "интерпретированы как даты." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:383 -#, fuzzy -msgid "A comma-separated list of schemas that CSVs are allowed to upload to." -msgstr "" -"Разделённый запятыми список столбцов, которые должен быть " -"интерпретированы как даты." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:433 +msgid "A comma-separated list of schemas that files are allowed to upload to." +msgstr "Разделённый запятыми список схем, в которые можно загружать файлы." #: superset/databases/commands/exceptions.py:42 -#, fuzzy msgid "A database with the same name already exists." -msgstr "Источник данных %(name)s уже существует" +msgstr "База данных с таким же именем уже существует" #: superset/views/dynamic_plugins.py:52 msgid "" "A full URL pointing to the location of the built plugin (could be hosted " "on a CDN for example)" msgstr "" +"Полный URL, указывающий на местоположение плагина (например, ссылка на " +"CDN)" + +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/handlebarTemplate.tsx:61 +msgid "A handlebars template that is applied to the data" +msgstr "Шаблон handlebars, примененный к данным" #: superset/views/dynamic_plugins.py:47 msgid "A human-friendly name" -msgstr "Понятное человеку имя" +msgstr "Человекочитаемое имя" -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:300 +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:195 +msgid "" +"A list of domain names that can embed this dashboard. Leaving this field " +"empty will allow embedding from any domain." +msgstr "" +"Список доменных имен, которые могут встраивать этот дашборд. Если " +"оставить поле пустым, любой домен сможет сделать встраивание." + +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:313 msgid "A list of users who can alter the chart. Searchable by name or username." -msgstr "Владельцы - это пользователи, которые могут изменять график." +msgstr "Владельцы - это пользователи, которые могут изменять график" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:29 msgid "A map of the world, that can indicate values in different countries." -msgstr "" +msgstr "Карта мира, на которой могут быть указаны значения в разных странах." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:161 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:209 -#: superset-frontend/src/explore/controls.jsx:238 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:27 +msgid "" +"A map that takes rendering circles with a variable radius at " +"latitude/longitude coordinates" +msgstr "На карте отображаются маркеры переменного радиуса и цвета." + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:230 +#: superset-frontend/src/explore/controls.jsx:237 msgid "A metric to use for color" msgstr "Показатель, используемый для расчета цвета" -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:26 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:28 msgid "" "A polar coordinate chart where the circle is broken into wedges of equal " "angle, and the value represented by any wedge is illustrated by its area," " rather than its radius or sweep angle." msgstr "" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:523 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:599 msgid "A readable URL for your dashboard" msgstr "Читаемый URL-адрес для дашборда" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:39 +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:45 #: superset-frontend/src/explore/controls.jsx:113 msgid "A reference to the [Time] configuration, taking granularity into account" msgstr "" -#: superset/views/alerts.py:189 -msgid "A semicolon ';' delimited list of email addresses" -msgstr "Список адресов, разделённый точкой с запятой ‘;’" +#: superset/reports/commands/exceptions.py:186 +#, python-format +msgid "A report named \"%(name)s\" already exists" +msgstr "Рассылка с именем \"%(name)s\" уже существует" + +#: superset-frontend/src/explore/components/SaveModal.tsx:327 +msgid "A reusable dataset will be saved with your chart." +msgstr "Переиспользуемый датасет будет сохранен с вашим графиком." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:789 -#: superset/connectors/sqla/views.py:469 +#: superset-frontend/src/components/ReportModal/index.tsx:303 +msgid "A screenshot of the dashboard will be sent to your email at" +msgstr "Скриншот дашборда будет отправлен на ваш электронный адрес" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:957 +#: superset/connectors/sqla/views.py:459 msgid "" "A set of parameters that become available in the query using Jinja " "templating syntax" +msgstr "Набор параметров, которые доступны в запросе через шаблонизацию Jinja." + +#: superset/common/query_context_processor.py:413 +msgid "A time column must be specified when using a Time Comparison." msgstr "" +"Столбец даты/времени должен быть указан при использовании сравнения по " +"времени" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:32 msgid "" "A time series chart that visualizes how a related metric from multiple " "groups vary over time. Each group is visualized using a different color." msgstr "" +"Диаграмма временного ряда, которая визуализирует, как связанная метрика " +"из нескольких групп изменяется с течением времени. Для каждой группы " +"используется свой цвет." -#: superset/reports/commands/exceptions.py:198 -#, fuzzy +#: superset/reports/commands/exceptions.py:223 msgid "A timeout occurred while executing the query." -msgstr "Обнаружена ошибка в запросе." +msgstr "Вышло время исполнения запроса." -#: superset/reports/commands/exceptions.py:206 -#, fuzzy +#: superset/reports/commands/exceptions.py:233 msgid "A timeout occurred while generating a csv." -msgstr "Произошла ошибка при получении метаданных из таблицы" +msgstr "Вышло время создания CSV файла." -#: superset/reports/commands/exceptions.py:210 -#, fuzzy +#: superset/reports/commands/exceptions.py:238 msgid "A timeout occurred while generating a dataframe." -msgstr "Произошла ошибка при создании источника данных" +msgstr "Вышло время создания датафрейма." -#: superset/reports/commands/exceptions.py:202 -#, fuzzy +#: superset/reports/commands/exceptions.py:228 msgid "A timeout occurred while taking a screenshot." -msgstr "Произошла ошибка при получении метаданных из таблицы" +msgstr "Вышло время создания скриншота." -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:168 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:280 msgid "A valid color scheme is required" msgstr "Требуется корректная цветовая схема" -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:344 +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:337 msgid "APPLY" msgstr "ПРИМЕНИТЬ" @@ -588,105 +920,127 @@ msgstr "ПРИМЕНИТЬ" msgid "APR" msgstr "АПР" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:239 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:404 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:309 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:475 msgid "AQE" -msgstr "AQE" +msgstr "Асинхронные запросы" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:98 msgid "AUG" msgstr "АВГ" -#: superset-frontend/src/components/Menu/MenuRight.tsx:176 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:110 +msgid "AXIS TITLE MARGIN" +msgstr "ОТСТУП ЗАГОЛОВКА ОСИ" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:127 +msgid "AXIS TITLE POSITION" +msgstr "ПОЛОЖЕНИЕ ЗАГОЛОВКА ОСИ" + +#: superset-frontend/src/views/components/RightMenu.tsx:508 msgid "About" -msgstr "" +msgstr "О программе" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:354 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:397 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:287 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:406 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:449 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:300 msgid "Access" msgstr "Доступ" -#: superset/initialization/__init__.py:491 +#: superset/initialization/__init__.py:411 msgid "Access requests" msgstr "Запросы доступа" -#: superset/views/core.py:300 +#: superset-frontend/src/components/TableLoader/index.tsx:91 +msgid "Access to user activity data is restricted" +msgstr "Запрещен доступ к истории действий пользователя" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:175 +msgid "Access token" +msgstr "Токен доступа" + +#: superset/views/core.py:315 msgid "Access was requested" -msgstr "Запрошен доступ" +msgstr "Доступ запрошен" #: superset/views/log/__init__.py:31 msgid "Action" -msgstr "Действия" +msgstr "Действие" -#: superset/initialization/__init__.py:419 +#: superset/initialization/__init__.py:373 msgid "Action Log" -msgstr "Журнал Действий" +msgstr "Журнал действий" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:335 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:189 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:249 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:420 +#: superset-frontend/src/pages/ChartList/index.tsx:539 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:405 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:203 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:246 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:229 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:417 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:375 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:405 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:309 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:413 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:432 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:445 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:492 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:327 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:414 msgid "Actions" msgstr "Действия" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:290 -#: superset/views/schedules.py:240 superset/views/schedules.py:320 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:356 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:399 msgid "Active" -msgstr "Действия" +msgstr "Активен" -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:316 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:332 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:214 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:484 +msgid "Actual Values" +msgstr "Фактические значения" + +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:309 msgid "Actual time range" -msgstr "" +msgstr "Фактический временной интервал" + +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:64 +msgid "Actual value" +msgstr "Фактическое значение" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:140 +#: superset-frontend/src/explore/controlPanels/sections.tsx:210 +msgid "Actual values" +msgstr "Фактические значения" #: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:28 -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:49 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:51 +#: superset-frontend/src/explore/controls.jsx:78 +#: superset-frontend/src/explore/controls.jsx:101 msgid "Adaptive formatting" -msgstr "Формат Datetime" - -#: superset-frontend/src/components/ReportModal/index.tsx:267 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitlePane.tsx:133 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1039 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:273 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:226 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:220 -#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:119 +msgstr "Адаптивное форматирование" + +#: superset-frontend/src/components/ReportModal/index.tsx:223 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:390 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:272 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:230 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:218 msgid "Add" msgstr "Добавить" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1056 -#, fuzzy +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:394 msgid "Add Alert" -msgstr "оповещение" +msgstr "Добавить оповещение" -#: superset/views/annotations.py:60 -msgid "Add Annotation" -msgstr "Добавить слой аннотации" - -#: superset/views/annotations.py:119 -msgid "Add Annotation Layer" -msgstr "Добавить слой аннотации" - -#: superset/views/css_templates.py:38 +#: superset/views/css_templates.py:40 msgid "Add CSS Template" -msgstr "Шаблоны CSS" +msgstr "Добавить CSS шаблон" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:232 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:230 msgid "Add CSS template" -msgstr "Шаблоны CSS" +msgstr "Добавить CSS шаблоны" #: superset/views/chart/mixin.py:28 msgid "Add Chart" msgstr "Добавить график" -#: superset/connectors/sqla/views.py:65 +#: superset/connectors/sqla/views.py:75 msgid "Add Column" msgstr "Добавить столбец" @@ -696,42 +1050,30 @@ msgstr "Добавить дашборд" #: superset/views/database/mixins.py:35 msgid "Add Database" -msgstr "Добавить Базу Данных" +msgstr "Добавить базу данных" -#: superset/connectors/druid/views.py:215 -msgid "Add Druid Cluster" -msgstr "Добавить кластер Druid" - -#: superset/connectors/druid/views.py:72 -msgid "Add Druid Column" -msgstr "Добавить столбец Druid" - -#: superset/connectors/druid/views.py:279 -msgid "Add Druid Datasource" -msgstr "Добавить источник данных Druid" - -#: superset/connectors/druid/views.py:161 -msgid "Add Druid Metric" -msgstr "Добавить Druid Метрику" +#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:151 +msgid "Add Dataset and Create Chart" +msgstr "Добавить датасет и создать график" #: superset/views/log/__init__.py:23 msgid "Add Log" -msgstr "Добавить журнал" +msgstr "Добавить запись" -#: superset/connectors/sqla/views.py:214 +#: superset/connectors/sqla/views.py:210 msgid "Add Metric" -msgstr "Добавить показатель" +msgstr "Добавить меру" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1055 -#, fuzzy +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:393 msgid "Add Report" -msgstr "рассылка" +msgstr "Добавить рассылку" -#: superset/connectors/sqla/views.py:316 +#: superset/connectors/sqla/views.py:293 +#, fuzzy msgid "Add Row level security filter" -msgstr "Добавить фильтр на уровне строк" +msgstr "Безопасность на уровне строк" -#: superset/views/sql_lab.py:41 +#: superset/views/sql_lab/views.py:54 msgid "Add Saved Query" msgstr "Добавить сохраненный запрос" @@ -739,267 +1081,374 @@ msgstr "Добавить сохраненный запрос" msgid "Add a Plugin" msgstr "Добавить плагин" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:175 -#, fuzzy +#: superset-frontend/src/pages/ChartCreation/index.tsx:344 +msgid "Add a dataset" +msgstr "Добавить датасет" + +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:262 +msgid "Add a new tab" +msgstr "Новая вкладка" + +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:286 +msgid "Add a new tab to create SQL Query" +msgstr "Откройте новую вкладку для создания SQL запроса" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:220 msgid "Add additional custom parameters" -msgstr "Изменить параметры шаблона" +msgstr "Добавление дополнительных пользовательских параметров" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:117 +msgid "Add an annotation layer" +msgstr "Добавить слой аннотации" #: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:63 -#, fuzzy msgid "Add an item" -msgstr "Добавить фильтр" +msgstr "Добавить запись" -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:283 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx:571 +msgid "Add and edit filters" +msgstr "Добавить и изменить фильтры" + +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:282 msgid "Add annotation" -msgstr "Добавить слой аннотации" +msgstr "Добавить аннотацию" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:201 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:213 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:238 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:214 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:226 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:242 msgid "Add annotation layer" msgstr "Добавить слой аннотации" -#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:121 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:298 +msgid "Add calculated columns to dataset in \"Edit datasource\" modal" +msgstr "Добавьте новые вычисляемые столбцы в датасет в настройках датасета" + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:295 +msgid "Add calculated temporal columns to dataset in \"Edit datasource\" modal" +msgstr "Добавьте новые столбцы формата дата/время в датасет в настройках датасета" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:153 msgid "Add dataset" -msgstr "Добавить Базу Данных" +msgstr "Добавить датасет" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:387 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:388 msgid "Add delivery method" -msgstr "Добавить метод доставки" +msgstr "Добавить способ оповещения" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:330 +msgid "Add extra connection information." +msgstr "Дополнительная информация по подключению" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx:367 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:167 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx:384 msgid "Add filter" msgstr "Добавить фильтр" -#: superset-frontend/src/CRUD/CollectionTable.tsx:417 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitlePane.tsx:109 +msgid "Add filters and dividers" +msgstr "Добавить фильтры и разделители" + +#: superset-frontend/src/components/Datasource/CollectionTable.tsx:458 msgid "Add item" -msgstr "Добавить фильтр" +msgstr "Добавить запись" #: superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.jsx:336 msgid "Add metric" -msgstr "Добавить показатель" +msgstr "Добавить меру" + +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:377 +msgid "Add metrics to dataset in \"Edit datasource\" modal" +msgstr "Добавьте меры в датасет в настройках датасета" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:176 msgid "Add new color formatter" -msgstr "" +msgstr "Добавить цветовое форматирование" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:169 msgid "Add new formatter" -msgstr "" +msgstr "Добавить форматирование" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:386 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:387 msgid "Add notification method" -msgstr "Добавить слой аннотации" +msgstr "Добавить способ уведомления" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:99 -#, fuzzy +#: superset-frontend/src/components/Chart/Chart.jsx:273 +msgid "Add required control values to preview chart" +msgstr "Добавьте обязательные значения для предпросмотра графика" + +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:254 +msgid "Add required control values to save chart" +msgstr "Добавьте обязательные значения для сохранения графика" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:107 msgid "Add sheet" -msgstr "Добавить Базу Данных" +msgstr "Добавить лист" -#: superset-frontend/src/explore/components/SaveModal.tsx:258 +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:219 +msgid "Add the name of the chart" +msgstr "Задайте имя графика" + +#: superset-frontend/src/dashboard/components/Header/index.jsx:517 +msgid "Add the name of the dashboard" +msgstr "Задайте имя дашборда" + +#: superset-frontend/src/explore/components/SaveModal.tsx:341 msgid "Add to dashboard" msgstr "Добавить в дашборд" -#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:141 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:126 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx:115 +msgid "Add/Edit Filters" +msgstr "Добавить/изменить фильтры" + +#: superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.tsx:122 +#: superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.tsx:149 msgid "Added" msgstr "Добавлено" -#: superset/connectors/druid/models.py:256 -msgid "Adding new datasource [{}]" -msgstr "Добавление нового источника данных [{}]" +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:174 +#, python-format +msgid "Added to 1 dashboard" +msgid_plural "Added to %s dashboards" +msgstr[0] "Добавлено в 1 дашборд" +msgstr[1] "Добавлено в %s дашборда" +msgstr[2] "Добавлено в %s дашбордов" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:173 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:218 msgid "Additional Parameters" -msgstr "Изменить параметры шаблона" +msgstr "Дополнительные параметры" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1631 +msgid "Additional fields may be required" +msgstr "" #: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:324 msgid "Additional information" -msgstr "Дополнительные метаданные" +msgstr "Дополнительная информация" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:96 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:95 msgid "Additional metadata" msgstr "Дополнительные метаданные" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:50 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:52 msgid "Additional padding for legend." -msgstr "Дополнительные метаданные" +msgstr "Дополнительный отступ для легенды" -#: superset/db_engine_specs/base.py:1398 -#, fuzzy +#: superset/db_engine_specs/base.py:1743 msgid "Additional parameters" -msgstr "Изменить параметры шаблона" +msgstr "Дополнительные параметры" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:166 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:444 +msgid "Additional settings." +msgstr "Дополнительная настройка" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:162 msgid "Additional text to add before or after the value, e.g. unit" -msgstr "" +msgstr "Дополнительный текст перед значением, например, единица измерения" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:40 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:40 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:45 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:39 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:57 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:43 -#, fuzzy msgid "Additive" -msgstr "Добавить фильтр" - -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:765 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:580 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:267 +msgstr "Смешанный" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:75 +msgid "Adjust how this database will interact with SQL Lab." +msgstr "Настройка взаимодействия базы данных с Лабораторией SQL" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:132 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts:91 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts:64 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:93 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts:76 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:186 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:153 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:66 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:933 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:643 #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:34 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1146 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1655 msgid "Advanced" -msgstr "Дополнительно" +msgstr "Продвинутая настройка" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:122 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:242 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:125 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:148 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:375 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:115 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:235 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:117 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:385 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:169 msgid "Advanced Analytics" -msgstr "Расширенный анализ" +msgstr "Расширенная аналитика" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:285 +msgid "Advanced Data type" +msgstr "Расширенный тип данных" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:25 -#: superset-frontend/src/explore/controlPanels/sections.tsx:144 +#: superset-frontend/src/explore/controlPanels/sections.tsx:117 msgid "Advanced analytics" -msgstr "Расширенный анализ" +msgstr "Расширенная аналитика" -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:32 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:36 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:35 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:79 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:79 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:74 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:64 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:71 -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:124 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:289 +msgid "Advanced analytics Query A" +msgstr "Расширенный анализ: запрос А" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:291 +msgid "Advanced analytics Query B" +msgstr "Расширенный анализ: запрос Б" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:281 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:353 +msgid "Advanced data type" +msgstr "Расширенный тип данных" + +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:35 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:37 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:38 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:77 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:76 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:71 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:66 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:130 msgid "Advanced-Analytics" -msgstr "Расширенный анализ" +msgstr "Продвинутая аналитика" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:36 #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:33 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:35 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:39 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:70 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:78 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:65 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:80 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:80 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:75 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:74 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:74 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:65 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:72 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:77 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:72 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:67 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:58 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:41 msgid "Aesthetic" -msgstr "" +msgstr "Эстетично" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:84 -#, fuzzy +#: superset-frontend/src/components/AlteredSliceTag/index.jsx:182 +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:82 msgid "After" -msgstr "дата" +msgstr "После" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:45 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:57 msgid "Aggregate" -msgstr "агрегат" +msgstr "Агрегация" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:91 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:84 msgid "Aggregate Mean" -msgstr "агрегат" +msgstr "Агрегированное среднее" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:96 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:89 msgid "Aggregate Sum" -msgstr "агрегат" +msgstr "Агрегированная сумма" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:182 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:194 msgid "" "Aggregate function applied to the list of points in each cluster to " "produce the cluster label." msgstr "" +"Агрегатная функция, применяемая для списка точек в каждом кластере для " +"создания метки кластера." -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:74 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:137 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:63 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:202 msgid "" "Aggregate function to apply when pivoting and computing the total rows " "and columns" msgstr "" +"Агрегатная функция, применяемая для сводных таблиц и вычислении суммарных" +" значений." -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:63 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:114 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:27 +msgid "" +"Aggregates data within the boundary of grid cells and maps the aggregated" +" values to a dynamic color scale" +msgstr "" + +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:52 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:176 msgid "Aggregation function" -msgstr "Python функции" +msgstr "Функция агрегирования" + +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:574 +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:162 +#, fuzzy +msgid "Alert" +msgstr "оповещение" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:92 msgid "Alert Triggered, In Grace Period" -msgstr "Сработало оповещение" +msgstr "Оповещение сработало во время перерыва" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1123 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:400 msgid "Alert condition" msgstr "Условие оповещения" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1215 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:408 msgid "Alert condition schedule" msgstr "Расписание условия оповещения" -#: superset/reports/commands/exceptions.py:218 +#: superset/reports/commands/exceptions.py:248 msgid "Alert ended grace period." -msgstr "" +msgstr "У оповещения закончился перерыв." #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:82 msgid "Alert failed" -msgstr "Оповещение не удалось" +msgstr "Оповещение не сработало" -#: superset/reports/commands/exceptions.py:214 +#: superset/reports/commands/exceptions.py:243 msgid "Alert fired during grace period." -msgstr "" +msgstr "Оповещение сработало во время перерыва" -#: superset/reports/commands/exceptions.py:194 +#: superset/reports/commands/exceptions.py:218 msgid "Alert found an error while executing a query." -msgstr "Обнаружена ошибка в запросе." +msgstr "Возникла ошибка при выполнении запроса для оповещения." -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1064 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1072 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:396 msgid "Alert name" msgstr "Имя оповещения" -#: superset/reports/commands/exceptions.py:222 +#: superset/reports/commands/exceptions.py:253 msgid "Alert on grace period" -msgstr "" +msgstr "Оповещение во время перерыва" -#: superset/reports/commands/exceptions.py:190 +#: superset/reports/commands/exceptions.py:214 msgid "Alert query returned a non-number value." -msgstr "Запрос для оповещения вернул не число." +msgstr "Запрос оповещения вернул нечисловое значение." -#: superset/reports/commands/exceptions.py:186 +#: superset/reports/commands/exceptions.py:209 msgid "Alert query returned more than one column." -msgstr "Запрос для оповещения вернул больше одного столбца." +msgstr "Запрос оповещения вернул больше, чем один столбец." -#: superset/reports/commands/alert.py:105 +#: superset/reports/commands/alert.py:109 #, python-format msgid "Alert query returned more than one column. %s columns returned" -msgstr "Запрос от оповещения вернул больше одного столбца. %s столбцов возвращено" +msgstr "Запрос оповещения вернул больше, чем один столбец. Возвращено столбцов: %s" -#: superset/reports/commands/exceptions.py:177 +#: superset/reports/commands/exceptions.py:199 msgid "Alert query returned more than one row." -msgstr "Запрос для оповещения вернул больше одной строки." +msgstr "Запрос оповещения вернул больше, чем одну строку." -#: superset/reports/commands/alert.py:96 +#: superset/reports/commands/alert.py:100 #, python-format msgid "Alert query returned more than one row. %s rows returned" -msgstr "Запрос от оповещения вернул больше одной строки. %s строк возвращено" +msgstr "Запрос оповещения вернул больше, чем одну строку. Возвращено строк: %s" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:75 msgid "Alert running" @@ -1009,164 +1458,177 @@ msgstr "Выполняется оповещение" msgid "Alert triggered, notification sent" msgstr "Сработало оповещение, уведомление отправлено" -#: superset/reports/commands/exceptions.py:182 +#: superset/reports/commands/exceptions.py:204 msgid "Alert validator config error." -msgstr "Неверная конфигурация широты и долготы." +msgstr "Неверная конфигурация валидатора оповещений." -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:436 -#: superset/initialization/__init__.py:468 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:535 msgid "Alerts" msgstr "Оповещения" -#: superset/initialization/__init__.py:480 +#: superset/initialization/__init__.py:390 msgid "Alerts & Reports" -msgstr "Оповещения и Рассылка" +msgstr "Оповещения и отчеты" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:432 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:520 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:524 msgid "Alerts & reports" -msgstr "Оповещения и рассылки" +msgstr "Оповещения и отчеты" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:127 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:427 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:116 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:438 msgid "Align +/-" -msgstr "" - -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:457 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:478 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:499 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:524 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:454 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:475 +msgstr "Выровнять +/-" + +#: superset-frontend/src/pages/ChartList/index.tsx:583 +#: superset-frontend/src/pages/ChartList/index.tsx:605 +#: superset-frontend/src/pages/ChartList/index.tsx:627 +#: superset-frontend/src/pages/ChartList/index.tsx:653 +#: superset-frontend/src/pages/ChartList/index.tsx:663 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:458 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:288 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:278 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:483 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:505 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:462 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:482 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:354 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:430 +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:211 msgid "All" -msgstr "" +msgstr "Все" #: superset/annotation_layers/annotations/filters.py:28 -#: superset/annotation_layers/filters.py:30 superset/charts/filters.py:31 +#: superset/annotation_layers/filters.py:30 superset/charts/filters.py:33 #: superset/css_templates/filters.py:28 -#: superset/queries/saved_queries/filters.py:31 superset/reports/filters.py:28 +#: superset/queries/saved_queries/filters.py:31 superset/reports/filters.py:44 msgid "All Text" msgstr "Весь текст" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx:60 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useFilterScope.ts:69 #: superset-frontend/src/dashboard/util/getFilterScopeNodesTree.js:85 -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:122 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:128 msgid "All charts" msgstr "Все графики" #: superset-frontend/src/dashboard/util/getFilterFieldNodesTree.js:44 msgid "All filters" -msgstr "Фильтры" +msgstr "Все фильтры" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:326 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx:230 #, python-format msgid "All filters (%(filterCount)d)" -msgstr "" +msgstr "Все фильтры (%(filterCount)d)" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/state.ts:49 -#, fuzzy msgid "All panels" -msgstr "Применить ко всем панелям" +msgstr "Все панели" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:132 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:131 msgid "All panels with this column will be affected by this filter" msgstr "Фильтр будет применён ко всем панелям с этим столбцом" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:95 -#: superset/views/database/mixins.py:187 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:107 +#: superset/views/database/mixins.py:184 msgid "Allow CREATE TABLE AS" msgstr "Разрешить CREATE TABLE AS" -#: superset/views/database/mixins.py:113 +#: superset/views/database/mixins.py:112 msgid "Allow CREATE TABLE AS option in SQL Lab" -msgstr "Разрешить выполнять инструкцию CREATE TABLE AS в редакторе SQL" +msgstr "Разрешить CREATE TABLE AS в Лаборатории SQL" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:109 -#: superset/views/database/mixins.py:188 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:121 +#: superset/views/database/mixins.py:185 msgid "Allow CREATE VIEW AS" -msgstr "Разрешить CREATE TABLE AS" +msgstr "Разрешить CREATE VIEW AS" -#: superset/views/database/mixins.py:114 +#: superset/views/database/mixins.py:113 msgid "Allow CREATE VIEW AS option in SQL Lab" -msgstr "Разрешить выполнять инструкцию CREATE TABLE AS в редакторе SQL" +msgstr "Разрешить CREATE VIEW AS в Лаборатории SQL" -#: superset/views/database/mixins.py:201 +#: superset/views/database/mixins.py:198 msgid "Allow Csv Upload" msgstr "Разрешить загрузку CSV" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:142 -#: superset/views/database/mixins.py:189 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:154 +#: superset/views/database/mixins.py:186 msgid "Allow DML" -msgstr "Allow DML" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:158 -#: superset/views/database/mixins.py:203 -msgid "Allow Multi Schema Metadata Fetch" -msgstr "" +msgstr "Разрешить DML" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:161 -#: superset/views/database/mixins.py:170 -msgid "" -"Allow SQL Lab to fetch a list of all tables and all views across all " -"database schemas. For large data warehouse with thousands of tables, this" -" can be expensive and put strain on the system." -msgstr "" +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:464 +msgid "Allow columns to be rearranged" +msgstr "Разрешить смену столбцов местами" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:98 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:110 msgid "Allow creation of new tables based on queries" -msgstr "" +msgstr "Разрешить создание новых таблиц на основе запросов" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:112 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:124 msgid "Allow creation of new views based on queries" -msgstr "" +msgstr "Разрешить создание новых представлений на основе запросов" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:256 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:326 msgid "Allow data manipulation language" -msgstr "Разрешить язык манипулирования данными" +msgstr "Разрешить операции вставки, обновления и удаления данных" + +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:467 +msgid "" +"Allow end user to drag-and-drop column headers to rearrange them. Note " +"their changes won't persist for the next time they open the chart." +msgstr "" +"Разрешить конечному пользователю перемещать столбцы, удерживая их " +"заголовки. Заметьте, такие изменения будут нейтрализованы при следующем " +"обращении к дашборду." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:417 -msgid "Allow data upload" -msgstr "Разрешить загрузку данных" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:411 +msgid "Allow file uploads to database" +msgstr "Разрешить загрузку файлов в базу данных" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:145 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:157 msgid "" "Allow manipulation of the database using non-SELECT statements such as " "UPDATE, DELETE, CREATE, etc." msgstr "" +"Разрешить управление базой данных, используя запросы UPDATE, DELETE, " +"CREATE и т.п." #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:216 msgid "Allow multiple selections" -msgstr "Разрешить множественный фильтр" +msgstr "Разрешить множественный выбор" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:189 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:190 msgid "Allow node selections" -msgstr "Разрешить множественный фильтр" +msgstr "Разрешить выбор вершин" -#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:64 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:82 -msgid "Allow selecting multiple values" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:176 +msgid "Allow sending multiple polygons as a filter event" msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:192 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:186 msgid "Allow this database to be explored" -msgstr "" +msgstr "Разрешить изучение этой базы данных" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:79 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:91 msgid "Allow this database to be queried in SQL Lab" -msgstr "" +msgstr "Разрешить запросы к этой базе данных в Лаборатории SQL" -#: superset/views/database/mixins.py:115 +#: superset/views/database/mixins.py:114 msgid "" "Allow users to run non-SELECT statements (UPDATE, DELETE, CREATE, ...) in" " SQL Lab" msgstr "" -"Позволяет пользователям запускать инструкции (UPDATE, DELETE, CREATE, …) " -"без SELECT в редакторе SQL" +"Разрешить управление базой данных, используя запросы UPDATE, DELETE, " +"CREATE и т.п. в Лаборатории SQL" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:555 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:529 -#, fuzzy +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:193 +msgid "Allowed Domains (comma separated)" +msgstr "Разрешенные домены (разделить запятыми)" + +#: superset-frontend/src/pages/ChartList/index.tsx:696 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:555 msgid "Alphabetical" -msgstr "Отсортировать столбцы в алфавитном порядке" +msgstr "В алфавитном порядке" #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:50 msgid "" @@ -1176,51 +1638,60 @@ msgid "" "around each box visualize the min, max, range, and outer 2 quartiles." msgstr "" -#: superset-frontend/src/components/AlteredSliceTag/index.jsx:182 +#: superset-frontend/src/components/AlteredSliceTag/index.jsx:202 msgid "Altered" -msgstr "Изменения" +msgstr "Измененено" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx:71 +msgid "An Error Occurred" +msgstr "Произошла ошибка" -#: superset/common/query_context_processor.py:257 superset/viz.py:1415 +#: superset/reports/commands/exceptions.py:188 +#, python-format +msgid "An alert named \"%(name)s\" already exists" +msgstr "Оповещение с именем \"%(name)s\" уже существует" + +#: superset/common/query_context_processor.py:322 superset/viz.py:1444 msgid "" "An enclosed time range (both start and end) must be specified when using " "a Time Comparison." msgstr "" +"При использовании сравнения времени необходимо указать закрытый временной" +" интервал (как начало, так и конец)." -#: superset/databases/schemas.py:299 +#: superset/databases/schemas.py:280 msgid "" "An engine must be specified when passing individual parameters to a " "database." -msgstr "" +msgstr "Движок должен быть указан при передаче индивидуальных параметров к базе." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:623 -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:140 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:69 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:116 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:785 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:137 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:108 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:115 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx:46 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:64 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:67 msgid "An error has occurred" msgstr "Произошла ошибка" -#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.jsx:80 -#: superset-frontend/src/components/TableLoader/index.tsx:48 -#: superset-frontend/src/utils/getClientErrorObject.ts:135 +#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx:76 +#: superset-frontend/src/components/TableLoader/index.tsx:55 +#: superset-frontend/src/utils/getClientErrorObject.ts:197 msgid "An error occurred" msgstr "Произошла ошибка" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:347 +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:317 msgid "An error occurred saving dataset" -msgstr "Произошла ошибка при создании источника данных" +msgstr "Произошла ошибка при сохранении датасета" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "Произошла ошибка при создании источника данных" - -#: superset/key_value/commands/exceptions.py:33 -#, fuzzy +#: superset/dashboards/permalink/exceptions.py:31 +#: superset/explore/permalink/exceptions.py:31 +#: superset/key_value/exceptions.py:38 +#: superset/temporary_cache/commands/exceptions.py:33 msgid "An error occurred while accessing the value." -msgstr "Произошла ошибка при создании источника данных" +msgstr "Произошла ошибка при доступе к значению" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1165 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1342 msgid "" "An error occurred while collapsing the table schema. Please contact your " "administrator." @@ -1229,36 +1700,28 @@ msgstr "" "администратором." #: superset-frontend/src/views/CRUD/hooks.ts:301 -#, fuzzy, python-format +#, python-format msgid "An error occurred while creating %ss: %s" -msgstr "Произошла ошибка при получении датасетов: %s" +msgstr "Произошла ошибка при создании %sов: %s" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1313 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1335 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1503 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1525 msgid "An error occurred while creating the data source" msgstr "Произошла ошибка при создании источника данных" -#: superset/key_value/commands/exceptions.py:29 -#, fuzzy +#: superset/dashboards/permalink/exceptions.py:27 +#: superset/explore/permalink/exceptions.py:27 +#: superset/key_value/exceptions.py:34 +#: superset/temporary_cache/commands/exceptions.py:29 msgid "An error occurred while creating the value." -msgstr "Произошла ошибка при создании источника данных" +msgstr "Произошла ошибка при создании значения" -#: superset/key_value/commands/exceptions.py:37 -#, fuzzy, python-format +#: superset/key_value/exceptions.py:42 +#: superset/temporary_cache/commands/exceptions.py:37 msgid "An error occurred while deleting the value." -msgstr "Произошла ошибка при построении графика: %s" - -#: superset-frontend/src/reports/actions/reports.js:138 -#, fuzzy -msgid "An error occurred while editing this report." -msgstr "Произошла ошибка при создании источника данных" - -#: superset-frontend/src/reports/actions/reports.js:120 -#, fuzzy, python-format -msgid "An error occurred while editing this report: %s" -msgstr "Произошла ошибка при получении датасетов: %s" +msgstr "Произошла ошибка при удалении значения" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1141 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1318 msgid "" "An error occurred while expanding the table schema. Please contact your " "administrator." @@ -1267,114 +1730,118 @@ msgstr "" "администратором." #: superset-frontend/src/views/CRUD/hooks.ts:103 -#, fuzzy, python-format +#, python-format msgid "An error occurred while fetching %s info: %s" -msgstr "Произошла ошибка при получении дашбордов: %s" +msgstr "Произошла ошибка при получении информации о %s: %s" #: superset-frontend/src/views/CRUD/hooks.ts:171 #: superset-frontend/src/views/CRUD/hooks.ts:258 -#: superset-frontend/src/views/CRUD/hooks.ts:344 -#, fuzzy, python-format +#: superset-frontend/src/views/CRUD/hooks.ts:346 +#, python-format msgid "An error occurred while fetching %ss: %s" -msgstr "Произошла ошибка при получении датасетов: %s" +msgstr "Произошла ошибка при получении: %s: %s" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:132 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:135 msgid "An error occurred while fetching available CSS templates" msgstr "Произошла ошибка при получении доступных CSS-шаблонов" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:484 +#: superset-frontend/src/pages/ChartList/index.tsx:611 #, python-format msgid "An error occurred while fetching chart created by values: %s" msgstr "Произошла ошибка при получении создателя графика: %s" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:463 +#: superset-frontend/src/pages/ChartList/index.tsx:589 #, python-format msgid "An error occurred while fetching chart owners values: %s" -msgstr "Произошла ошибка при получении владельца графика: %s" +msgstr "Произошла ошибка при получении владельцев графика: %s" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:392 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:480 #, python-format msgid "An error occurred while fetching created by values: %s" msgstr "Произошла ошибка при построении графика: %s" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:481 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:511 #, python-format msgid "An error occurred while fetching dashboard created by values: %s" msgstr "Произошла ошибка при получении создателя дашборда: %s" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:460 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:489 #, python-format msgid "An error occurred while fetching dashboard owner values: %s" msgstr "Произошла ошибка при получении владельца дашборда: %s" -#: superset-frontend/src/components/OmniContainer/getDashboards.ts:48 +#: superset-frontend/src/pages/ChartList/index.tsx:290 msgid "An error occurred while fetching dashboards" -msgstr "Произошла ошибка при создании источника данных" +msgstr "Произошла ошибка при получении дашбордов" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:200 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:127 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:212 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:143 #, python-format msgid "An error occurred while fetching dashboards: %s" msgstr "Произошла ошибка при получении дашбордов: %s" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:129 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:145 #, python-format msgid "An error occurred while fetching database related data: %s" msgstr "Произошла ошибка при получении данных о базе данных: %s" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:341 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:360 #, python-format msgid "An error occurred while fetching database values: %s" msgstr "Произошла ошибка при получении значений базы данных: %s" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:295 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:282 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:434 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:293 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:283 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:436 #, python-format msgid "An error occurred while fetching dataset datasource values: %s" msgstr "Произошла ошибка при получении значений датасета: %s" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:426 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:514 #, python-format msgid "An error occurred while fetching dataset owner values: %s" -msgstr "Произошла ошибка при получении создателя датасета: %s" +msgstr "Произошла ошибка при получении владельца датасета: %s" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:184 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:226 msgid "An error occurred while fetching dataset related data" -msgstr "Произошла ошибка при получении метаданных из таблицы" +msgstr "Произошла ошибка при получении метаданных датасета" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:204 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:246 #, python-format msgid "An error occurred while fetching dataset related data: %s" msgstr "Произошла ошибка при получении данных о датасете: %s" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:445 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:534 #, python-format msgid "An error occurred while fetching datasets: %s" msgstr "Произошла ошибка при получении датасетов: %s" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1356 -#, fuzzy +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1555 msgid "An error occurred while fetching function names." -msgstr "Произошла ошибка при получении метаданных из таблицы" +msgstr "Произошла ошибка при получении имен функций" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:460 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:358 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:454 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:463 +#, python-format +msgid "An error occurred while fetching owners values: %s" +msgstr "Произошла ошибка при получении владельцев графика: %s" + +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:550 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:378 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:457 #, python-format msgid "An error occurred while fetching schema values: %s" -msgstr "Произошла ошибка при построении графика: %s" +msgstr "Произошла ошибка при извлечении значений схемы: %s" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:662 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:769 msgid "An error occurred while fetching tab state" -msgstr "Произошла ошибка при получении метаданных из таблицы" +msgstr "Произошла ошибка при получении данных вкладки" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1027 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1052 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1173 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1198 msgid "An error occurred while fetching table metadata" msgstr "Произошла ошибка при получении метаданных из таблицы" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1093 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1270 msgid "" "An error occurred while fetching table metadata. Please contact your " "administrator." @@ -1382,47 +1849,54 @@ msgstr "" "Произошла ошибка при получении метаданных таблицы. Пожалуйста, свяжитесь " "с администратором." -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:375 -#, fuzzy, python-format +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:396 +#, python-format msgid "An error occurred while fetching user values: %s" -msgstr "Произошла ошибка при построении графика: %s" +msgstr "Произошла ошибка при извлечении пользовательских значений: %s" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:698 -#, fuzzy +#: superset-frontend/src/SqlLab/actions/sqlLab.js:805 msgid "" "An error occurred while hiding the left bar. Please contact your " "administrator." msgstr "" -"Произошла ошибка при разворачивании схемы. Пожалуйста, свяжитесь с " +"Произошла ошибка при сворачивании левой панели. Пожалуйста, свяжитесь с " "администратором." -#: superset-frontend/src/views/CRUD/hooks.ts:438 -#: superset-frontend/src/views/CRUD/hooks.ts:451 -#, fuzzy, python-format +#: superset-frontend/src/views/CRUD/hooks.ts:460 +#: superset-frontend/src/views/CRUD/hooks.ts:476 +#, python-format msgid "An error occurred while importing %s: %s" -msgstr "Произошла ошибка при удалении журналов " +msgstr "Произошла ошибка при попытке импортировать %s: %s" -#: superset-frontend/src/chart/chartAction.js:569 +#: superset-frontend/src/components/Chart/chartAction.js:579 msgid "An error occurred while loading the SQL" -msgstr "Произошла ошибка при создании источника данных" +msgstr "Произошла ошибка при загрузке SQL" + +#: superset-frontend/src/dashboard/components/gridComponents/Chart.jsx:343 +msgid "An error occurred while opening Explore" +msgstr "Произошла ошибка при открытии режима исследования" + +#: superset/key_value/exceptions.py:30 +msgid "An error occurred while parsing the key." +msgstr "Произошла ошибка при парсинге ключа." -#: superset/reports/commands/exceptions.py:242 +#: superset/reports/commands/exceptions.py:281 msgid "An error occurred while pruning logs " msgstr "Произошла ошибка при удалении журналов " -#: superset-frontend/src/SqlLab/actions/sqlLab.js:744 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:862 msgid "An error occurred while removing query. Please contact your administrator." msgstr "" "Произошла ошибка при удалении запроса. Пожалуйста, свяжитесь с " "администратором." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:720 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:827 msgid "An error occurred while removing tab. Please contact your administrator." msgstr "" "Произошла ошибка при удалении вкладки. Пожалуйста, свяжитесь с " "администратором." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1188 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1370 msgid "" "An error occurred while removing the table schema. Please contact your " "administrator." @@ -1430,12 +1904,12 @@ msgstr "" "Произошла ошибка при удалении схемы. Пожалуйста, свяжитесь с " "администратором." -#: superset-frontend/src/chart/chartReducer.ts:94 +#: superset-frontend/src/components/Chart/chartReducer.ts:95 #, python-format msgid "An error occurred while rendering the visualization: %s" msgstr "Произошла ошибка при построении графика: %s" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:575 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:680 msgid "" "An error occurred while setting the active tab. Please contact your " "administrator." @@ -1443,7 +1917,7 @@ msgstr "" "Произошла ошибка при установке активной вкладки. Пожалуйста, свяжитесь с " "администратором." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:825 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:949 msgid "" "An error occurred while setting the tab autorun. Please contact your " "administrator." @@ -1451,7 +1925,7 @@ msgstr "" "Произошла ошибка при настройке автозапуска вкладки. Пожалуйста, свяжитесь" " с администратором." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:767 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:885 msgid "" "An error occurred while setting the tab database ID. Please contact your " "administrator." @@ -1459,15 +1933,24 @@ msgstr "" "Произошла ошибка при установке ID базы данных для вкладки. Пожалуйста, " "свяжитесь с администратором." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:792 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:978 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1102 +msgid "" +"An error occurred while setting the tab name. Please contact your " +"administrator." +msgstr "" +"Произошла ошибка при настройке заголовка вкладки. Пожалуйста, свяжитесь с" +" администратором." + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:916 msgid "" "An error occurred while setting the tab schema. Please contact your " "administrator." msgstr "" -"Произошла ошибка при настройке схемы вкладок. Пожалуйста, свяжитесь с " +"Произошла ошибка при настройке схемы. Пожалуйста, свяжитесь с " "администратором." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:967 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1128 msgid "" "An error occurred while setting the tab template parameters. Please " "contact your administrator." @@ -1475,197 +1958,181 @@ msgstr "" "Произошла ошибка при установке параметров шаблона вкладки. Пожалуйста, " "свяжитесь с администратором." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:850 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:941 -msgid "" -"An error occurred while setting the tab title. Please contact your " -"administrator." -msgstr "" -"Произошла ошибка при настройке заголовка вкладки. Пожалуйста, свяжитесь с" -" администратором." - -#: superset-frontend/src/explore/actions/exploreActions.ts:95 -#, fuzzy +#: superset-frontend/src/explore/actions/exploreActions.ts:88 msgid "An error occurred while starring this chart" -msgstr "Произошла ошибка при создании источника данных" +msgstr "Произошла ошибка при добавлении графика в избранное" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:232 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:258 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:249 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:275 msgid "" "An error occurred while storing the latest query id in the backend. " "Please contact your administrator if this problem persists." msgstr "" +"Возникла ошибка при попытке сохранения ID последнего запроса на сервере. " +"Пожалуйста, обратитесь к вашему администратору, если проблема останется." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:908 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1069 msgid "" "An error occurred while storing your query in the backend. To avoid " "losing your changes, please save your query using the \"Save Query\" " "button." msgstr "" -"Произошла ошибка при сохранении запроса в бэкенд. Чтобы сохранить " -"изменения, пожалуйста, сохраните ваш запрос через кнопку “Сохранить " -"запрос”." +"Произошла ошибка при сохранении запроса на сервере. Чтобы сохранить " +"изменения, пожалуйста, сохраните ваш запрос через кнопку \"Сохранить " +"как\"." -#: superset/key_value/commands/exceptions.py:41 -#, fuzzy +#: superset/key_value/exceptions.py:46 +#: superset/temporary_cache/commands/exceptions.py:41 msgid "An error occurred while updating the value." -msgstr "Произошла ошибка при создании источника данных" +msgstr "Произошла ошибка при обновлении значения" -#: superset/views/core.py:711 +#: superset/key_value/exceptions.py:50 +msgid "An error occurred while upserting the value." +msgstr "Произошла ошибка при вставке значения." + +#: superset/databases/commands/exceptions.py:162 +msgid "An unexpected error occurred" +msgstr "Произошла неожиданная ошибка" + +#: superset/views/core.py:732 msgid "An unknown error occurred. Please contact your Superset administrator" -msgstr "" -"Произошла неизвестная ошибка. Пожалуйста, свяжитесь с администратором " -"Superset" +msgstr "Произошла неизвестная ошибка. Пожалуйста, свяжитесь с администратором." -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:223 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:235 msgid "Anchor to" msgstr "Привязать к" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:121 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:117 msgid "Angle at which to end progress axis" -msgstr "" +msgstr "Угол, под которым заканчивается ось прогресса" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:111 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:107 msgid "Angle at which to start progress axis" -msgstr "" +msgstr "Угол, с которого начинается ось прогресса" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:191 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:187 msgid "Animation" -msgstr "аннотация" +msgstr "Анимация" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:202 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:248 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:216 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:249 msgid "Annotation" msgstr "Аннотация" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:263 -msgid "Annotation Layer ${annotationLayerName}" -msgstr "Слой аннотаций ${annotationLayerName}" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:259 +#, python-format +msgid "Annotation Layer %s" +msgstr "Слой аннотаций %s" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/annotationsAndLayers.tsx:35 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:124 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:271 -#: superset/initialization/__init__.py:229 superset/views/annotations.py:117 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/annotationsAndLayers.tsx:36 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:127 +#: superset/initialization/__init__.py:400 msgid "Annotation Layers" msgstr "Слои аннотаций" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:465 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:513 msgid "Annotation Slice Configuration" -msgstr "Фильтруемые срезы" - -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:758 -#, fuzzy -msgid "Annotation Source" -msgstr "аннотация" +msgstr "Настройки аннотации из графика" #: superset/annotation_layers/annotations/commands/exceptions.py:64 msgid "Annotation could not be created." -msgstr "Аннотация не может быть создана." +msgstr "Не удалось создать аннотацию" #: superset/annotation_layers/annotations/commands/exceptions.py:68 msgid "Annotation could not be updated." -msgstr "Аннотация не может быть обновлена." +msgstr "Не удалось обновить аннотацию" #: superset/annotation_layers/annotations/commands/exceptions.py:72 msgid "Annotation delete failed." -msgstr "Удаление аннотации не удалось." - -#: superset/views/annotations.py:47 -msgid "Annotation end time must be no earlier than start time." -msgstr "Конец интервала для аннотации должен быть не раньше начала." +msgstr "Не удалось удалить аннотацию" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:265 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:322 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:429 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:262 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:319 msgid "Annotation layer" -msgstr "Слои аннотаций" +msgstr "Слой аннотаций" #: superset/annotation_layers/commands/exceptions.py:37 msgid "Annotation layer could not be created." -msgstr "Слой аннотаций не может быть создан." +msgstr "Не удалось создать слой аннотации." #: superset/annotation_layers/commands/exceptions.py:33 msgid "Annotation layer could not be deleted." -msgstr "Слой аннотаций не может быть удалён." +msgstr "Не удалось удалить слой аннотации." #: superset/annotation_layers/commands/exceptions.py:41 msgid "Annotation layer could not be updated." -msgstr "Слой аннотаций не может быть обновлён." +msgstr "Не удалось обновить слой аннотации." #: superset/annotation_layers/commands/exceptions.py:49 msgid "Annotation layer delete failed." -msgstr "Ошибка удаления слоя аннотаций." +msgstr "Не удалось удалить слой аннотаций" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:517 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:565 msgid "Annotation layer description columns" -msgstr "Слой аннотаций не найден." +msgstr "Описательные столбцы слоя аннотаций." #: superset/annotation_layers/commands/exceptions.py:53 #: superset/annotation_layers/commands/exceptions.py:57 msgid "Annotation layer has associated annotations." -msgstr "Слой аннотаций имеет присвоенные аннотации." +msgstr "Слои аннотаций имеет связанные аннотации" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:492 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:540 msgid "Annotation layer interval end" -msgstr "Имя слоя аннотаций" +msgstr "Конечный интервал слоя аннотации" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:247 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:251 msgid "Annotation layer name" msgstr "Имя слоя аннотаций" #: superset/annotation_layers/commands/exceptions.py:45 msgid "Annotation layer not found." -msgstr "Слой аннотаций не найден." +msgstr "Слой аннотации не найден" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:634 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:682 msgid "Annotation layer opacity" -msgstr "Тип слоя аннотации" +msgstr "Непрозрачность слоя аннотации" #: superset/annotation_layers/commands/exceptions.py:29 msgid "Annotation layer parameters are invalid." -msgstr "Параметры слоя аннотации недействительны." +msgstr "Параметры слоя аннотаций недействительны" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:619 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:667 msgid "Annotation layer stroke" -msgstr "Тип слоя аннотации" +msgstr "Штрих слоя аннотации" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:472 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:520 #, fuzzy msgid "Annotation layer time column" msgstr "Тип слоя аннотации" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:506 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:554 #, fuzzy msgid "Annotation layer title column" -msgstr "Тип слоя аннотации" +msgstr "Название столбца слоя аннотации" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:743 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:746 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:793 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:796 msgid "Annotation layer type" msgstr "Тип слоя аннотации" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:403 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:450 msgid "Annotation layer value" -msgstr "Имя слоя аннотаций" +msgstr "Значение слоя аннотации" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:72 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:343 +#: superset-frontend/src/explore/controlPanels/sections.tsx:83 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:71 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:335 msgid "Annotation layers" msgstr "Слои аннотаций" -#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:45 +#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:58 msgid "Annotation layers are still loading." msgstr "Слои аннотаций загружаются." -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:292 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:291 msgid "Annotation name" -msgstr "Слои аннотаций" +msgstr "Имя аннотации" #: superset/annotation_layers/annotations/commands/exceptions.py:56 msgid "Annotation not found." @@ -1675,43 +2142,48 @@ msgstr "Аннотация не найдена." msgid "Annotation parameters are invalid." msgstr "Параметры аннотации недействительны." -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:755 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:808 +msgid "Annotation source" +msgstr "Источник аннотации" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:805 msgid "Annotation source type" -msgstr "Тип слоя аннотации" +msgstr "Тип источника аннотации" -#: superset/views/annotations.py:58 -msgid "Annotations" -msgstr "Аннотации" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:154 +msgid "Annotation template created" +msgstr "Шаблон аннотации создан" + +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:139 +msgid "Annotation template updated" +msgstr "Шаблон аннотации обновлен" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/annotationsAndLayers.tsx:25 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:113 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:261 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:116 msgid "Annotations and Layers" -msgstr "Аннотация" +msgstr "Аннотации и слои" -#: superset-frontend/src/explore/controlPanels/sections.tsx:91 +#: superset-frontend/src/explore/controlPanels/sections.tsx:72 msgid "Annotations and layers" -msgstr "Аннотация" +msgstr "Аннотации и слои" #: superset/annotation_layers/annotations/commands/exceptions.py:52 msgid "Annotations could not be deleted." -msgstr "Аннотации не могут быть удалены." +msgstr "Не удалось удалить аннотации." -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:441 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:535 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:438 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:496 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:509 -#, fuzzy +#: superset-frontend/src/pages/ChartList/index.tsx:566 +#: superset-frontend/src/pages/ChartList/index.tsx:675 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:459 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:527 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:541 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:574 msgid "Any" -msgstr "день" +msgstr "Любой" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:563 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:269 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:628 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:282 msgid "Any additional detail to show in the certification tooltip." -msgstr "" +msgstr "Любые дополнительные сведения для всплывающей подсказки" #: superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx:56 msgid "" @@ -1721,63 +2193,77 @@ msgstr "" "Любая палитра, выбранная здесь, будет перезаписывать цвета, применённые к" " отдельным графикам этого дашборда" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:702 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:903 msgid "Any databases that allow connections via SQL Alchemy URIs can be added. " msgstr "" +"Любые базы данных, подключаемые через SQL Alchemy URI, могут быть " +"добавлены. " -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:716 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:917 msgid "" "Any databases that allow connections via SQL Alchemy URIs can be added. " "Learn about how to connect a database driver " msgstr "" +"Любые базы данных, подключаемые через SQL Alchemy URI, могут быть " +"добавлены. Узнайте больше о том, как подключить драйвер базы данных " -#: superset/views/database/forms.py:147 superset/views/database/forms.py:300 -#: superset/views/database/forms.py:428 +#: superset/views/database/forms.py:169 superset/views/database/forms.py:326 +#: superset/views/database/forms.py:457 msgid "Append" msgstr "Добавить" -#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:186 -#, fuzzy, python-format +#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:187 +#, python-format msgid "Applied Cross Filters (%d)" -msgstr "Применено фильтров (%d)" +msgstr "Применено кросс-фильтров: (%d)" -#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:210 +#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:211 #, python-format msgid "Applied Filters (%d)" -msgstr "Применено фильтров (%d)" +msgstr "Применено фильтров: (%d)" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx:191 +#, python-format +msgid "Applied filters: %s" +msgstr "Применены фильтры: %s" -#: superset/viz.py:237 +#: superset/viz.py:245 msgid "" "Applied rolling window did not return any data. Please make sure the " "source query satisfies the minimum periods defined in the rolling window." msgstr "" +"Применное скользязее окно не вернуло данных. Убедитесь, что исходный " +"запрос удовлетворяет минимальному количеству периодов скользящего окна." -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:458 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:144 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:788 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:103 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx:142 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:839 #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:228 -#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:433 +#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:476 msgid "Apply" msgstr "Применить" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:321 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:386 msgid "Apply conditional color formatting to metrics" -msgstr "" +msgstr "Применить условное цветовое форматирование к мерам" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:474 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:501 msgid "Apply conditional color formatting to numeric columns" -msgstr "" +msgstr "Применить условное цветовое форматирование к столбцам" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:79 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx:142 +msgid "Apply filters" +msgstr "Применить фильтры" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:116 msgid "Apply metrics on" -msgstr "Показатель" +msgstr "Применить меры к" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:123 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:122 msgid "Apply to all panels" msgstr "Применить ко всем панелям" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:125 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:124 msgid "Apply to specific panels" msgstr "Применить к выбранным панелям" @@ -1785,730 +2271,873 @@ msgstr "Применить к выбранным панелям" msgid "April" msgstr "Апрель" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:85 +msgid "Arc" +msgstr "Дуга" + +#: superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.tsx:163 +msgid "Are you sure you intend to overwrite the following values?" +msgstr "Вы уверены, что хотите перезаписать эти значения?" + #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:49 msgid "Are you sure you want to cancel?" msgstr "Вы уверены, что хотите отменить?" -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:80 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:360 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:108 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:358 +#: superset-frontend/src/pages/ChartList/ChartCard.tsx:83 +#: superset-frontend/src/pages/ChartList/index.tsx:479 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:107 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:373 msgid "Are you sure you want to delete" msgstr "Вы уверены, что хотите удалить" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:286 -msgid "" -"Are you sure you want to delete " -"${annotationCurrentlyDeleting?.short_descr}?" -msgstr "" -"Вы уверены, что хотите удалить " -"${annotationCurrentlyDeleting?.short_descr}?" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:282 +#, python-format +msgid "Are you sure you want to delete %s?" +msgstr "Вы уверены, что хотите удалить %s?" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:486 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:585 #, python-format msgid "Are you sure you want to delete the selected %s?" msgstr "Вы уверены, что хотите удалить выбранные %s?" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:301 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:298 msgid "Are you sure you want to delete the selected annotations?" msgstr "Вы уверены, что хотите удалить выбранные аннотации?" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:645 +#: superset-frontend/src/pages/ChartList/index.tsx:797 msgid "Are you sure you want to delete the selected charts?" msgstr "Вы уверены, что хотите удалить выбранные графики?" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:612 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:651 msgid "Are you sure you want to delete the selected dashboards?" msgstr "Вы уверены, что хотите удалить выбранные дашборды?" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:618 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:769 msgid "Are you sure you want to delete the selected datasets?" msgstr "Вы уверены, что хотите удалить выбранные датасеты?" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:366 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:358 msgid "Are you sure you want to delete the selected layers?" msgstr "Вы уверены, что хотите удалить выбранные слои?" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:500 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:504 msgid "Are you sure you want to delete the selected queries?" msgstr "Вы уверены, что хотите удалить выбранные запросы?" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:326 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:328 msgid "Are you sure you want to delete the selected templates?" msgstr "Вы уверены, что хотите удалить выбранные шаблоны?" +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:426 +msgid "Are you sure you want to overwrite this dataset?" +msgstr "Вы уверены, что хотите перезаписать этот датасет?" + #: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:133 msgid "Are you sure you want to proceed?" msgstr "Вы уверены, что хотите продолжить?" -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:173 +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:500 +#, fuzzy +msgid "Are you sure you want to remove the last temporal filter?" +msgstr "Вы уверены, что хотите удалить выбранные шаблоны?" + +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:170 msgid "Are you sure you want to save and apply changes?" msgstr "Вы уверены, что хотите сохранить и применить изменения?" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:41 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:132 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:135 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:71 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:92 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:89 msgid "Area Chart" -msgstr "Поделиться графиком" +msgstr "Диаграмма с областями" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:168 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:41 +msgid "Area Chart (legacy)" +msgstr "Диаграмма с областями (устарело)" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:170 msgid "Area chart" -msgstr "Поделиться графиком" +msgstr "Диаграмма с областями" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:131 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:146 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:149 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:90 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:106 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:103 msgid "Area chart opacity" -msgstr "Поделиться графиком" +msgstr "Непрозрачность диаграммы с областями" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:238 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:57 +msgid "" +"Area charts are similar to line charts in that they represent variables " +"with the same scale, but area charts stack the metrics on top of each " +"other." +msgstr "" +"Диаграммы с областями похожи на линейные диаграммы в том смысле, что они " +"отображают показатели с одинаковым масштабом, но диаграммы областей " +"накладывают эти показатели друг на друга." + +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:239 msgid "Arrow" -msgstr "строк" +msgstr "Стрела" + +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:67 +msgid "Assign a set of parameters as" +msgstr "Задайте набор параметров в формате" -#: superset/connectors/druid/views.py:342 superset/connectors/sqla/views.py:487 +#: superset/connectors/sqla/views.py:477 msgid "Associated Charts" msgstr "Связанные графики" -#: superset/views/database/mixins.py:199 +#: superset/views/database/mixins.py:196 msgid "Async Execution" msgstr "Асинхронное выполнение" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:236 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:401 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:285 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:306 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:472 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:295 msgid "Asynchronous query execution" -msgstr "" +msgstr "Асинхронное выполнение запросов" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:73 msgid "August" msgstr "Август" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:523 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:127 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:146 +msgid "Auto" +msgstr "Автоматически" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:97 +msgid "Auto Zoom" +msgstr "Авто масштабирование" + +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:508 msgid "Autocomplete" -msgstr "" +msgstr "Автозаполнение" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:708 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:874 msgid "Autocomplete filters" -msgstr "" +msgstr "Фильтры автозаполнения" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:715 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:881 msgid "Autocomplete query predicate" -msgstr "Извлечь Значения Предиката" +msgstr "Предикат запроса автозаполнения" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:709 +msgid "Automatic Color" +msgstr "Автоматический цвет" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:242 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:270 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:307 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:335 msgid "Available sorting modes:" -msgstr "" +msgstr "Доступные режимы сортировки:" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:200 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:183 +msgid "Average" +msgstr "Среднее" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:196 msgid "Axis" -msgstr "Ось Y" +msgstr "Ось" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:36 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:241 +msgid "Axis Bounds" +msgstr "Границы оси" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:188 +msgid "Axis Format" +msgstr "Формат Оси" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:63 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:94 +msgid "Axis Title" +msgstr "Название оси" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:37 msgid "Axis ascending" -msgstr "Направление сортировки" +msgstr "Ось по возрастанию" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:37 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:38 msgid "Axis descending" -msgstr "Сортировать" +msgstr "Ось по убыванию" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:770 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:786 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:140 +msgid "BOOLEAN" +msgstr "Булевый (BOOLEAN)" + +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:366 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:989 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1006 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1026 msgid "Back" -msgstr "" +msgstr "Назад" + +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:181 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:262 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:264 +msgid "Back to all" +msgstr "Вернуться ко всем" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:227 -#: superset/views/database/mixins.py:204 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:297 +#: superset/views/database/mixins.py:200 msgid "Backend" -msgstr "" +msgstr "Драйвер" -#: superset/viz.py:2472 superset/viz.py:2508 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:188 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:262 +msgid "Backward values" +msgstr "Предыдущие значения" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:480 +msgid "Bad formula." +msgstr "Неверная формула." + +#: superset/viz.py:2506 superset/viz.py:2542 msgid "Bad spatial key" -msgstr "" +msgstr "Неподходящий пространственный ключ" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:85 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:38 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:46 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:144 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:88 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:77 msgid "Bar" -msgstr "" +msgstr "Столбчатая" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:38 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:78 msgid "Bar Chart" -msgstr "Поделиться графиком" +msgstr "Столбчатая диаграмма" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:294 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:43 +msgid "Bar Chart (legacy)" +msgstr "Столбчатая диаграмма (устарело)" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:63 +msgid "Bar Charts are used to show metrics as a series of bars." +msgstr "" +"Столбчатые диаграммы используются для отображения показателей в виде " +"серии столбцов." + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:314 msgid "Bar Values" -msgstr "Значение фильтра" +msgstr "Значения столбцов" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:227 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:276 +msgid "Bar orientation" +msgstr "Направление столбцов" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:239 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:382 msgid "Base layer map style" msgstr "" #: superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx:165 -#, fuzzy msgid "Based on a metric" -msgstr "Сохранённый показатель" +msgstr "На основе меры" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:50 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:56 msgid "Based on granularity, number of time periods to compare against" msgstr "" +"Основываясь на группировке времени, количество периодов времени для " +"сравнения" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:686 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:263 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1034 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:848 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1534 msgid "Basic" -msgstr "" +msgstr "Базовая настройка" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:497 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:229 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:288 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:243 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:237 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:581 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:242 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:287 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:247 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:235 msgid "Basic information" msgstr "Основная информация" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:486 +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:749 #, python-format msgid "Batch editing %d filters:" -msgstr "" +msgstr "Множественное редактирование фильтров: %d" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:36 msgid "Battery level over time" -msgstr "" +msgstr "Уровень заряда батареи с течением времени" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1175 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1335 msgid "Be careful." msgstr "Будьте осторожны." -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:76 -#, fuzzy +#: superset-frontend/src/components/AlteredSliceTag/index.jsx:178 +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:75 msgid "Before" -msgstr "Принудительное обновление" +msgstr "До" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:38 -#: superset/viz.py:1254 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:37 +#: superset/viz.py:1283 msgid "Big Number" -msgstr "Big Number" +msgstr "Карточка" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:28 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:28 msgid "Big Number Font Size" -msgstr "" +msgstr "Размер шрифта числа" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:34 -#: superset/viz.py:1220 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:36 +#: superset/viz.py:1249 msgid "Big Number with Trendline" -msgstr "Big Number with Trendline" +msgstr "Карточка с трендовой линией" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:290 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:84 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:355 msgid "Bottom" -msgstr "dttm" +msgstr "Снизу" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:212 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:187 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:226 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:194 msgid "Bottom Margin" -msgstr "" +msgstr "Нижний отступ" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:185 +msgid "Bottom left" +msgstr "Снизу слева" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:224 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:191 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:238 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:206 msgid "Bottom margin, in pixels, allowing for more room for axis labels" -msgstr "" +msgstr "Нижний отступ (в пикселях), дает больше пространства меткам оси" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:140 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:186 +msgid "Bottom right" +msgstr "Снизу справа" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:141 msgid "Bottom to Top" -msgstr "" +msgstr "Снизу вверх" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:241 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:257 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:357 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:272 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:235 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:215 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:232 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:288 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:291 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:261 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:277 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:373 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:261 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:248 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:192 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:192 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:245 msgid "" "Bounds for the Y-axis. When left empty, the bounds are dynamically " "defined based on the min/max of the data. Note that this feature will " "only expand the axis range. It won't narrow the data's extent." msgstr "" +"Границы для оси Y. Если оставить поле пустым, границы динамически " +"определяются на основе минимального/максимального значения данных. " +"Обратите внимание, что эта функция только расширит диапазон осей. Она не " +"изменит размер графика." + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:244 +msgid "" +"Bounds for the axis. When left empty, the bounds are dynamically defined " +"based on the min/max of the data. Note that this feature will only expand" +" the axis range. It won't narrow the data's extent." +msgstr "" +"Границы для оси. Если оставить поле пустым, границы динамически " +"определяются на основе минимального/максимального значения данных. " +"Обратите внимание, что эта функция только расширит диапазон осей. Она не " +"изменит размер графика." #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/BoxPlot/index.js:26 #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:54 #: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/createMetadata.ts:27 msgid "Box Plot" -msgstr "Box Plot" +msgstr "Ящик с усами" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:133 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:123 #, fuzzy msgid "Breakdowns" msgstr "Дата создания" -#: superset/connectors/druid/views.py:237 -msgid "Broker Endpoint" -msgstr "Адрес брокера" - -#: superset/connectors/druid/views.py:233 -msgid "Broker Host" -msgstr "Хост брокера" - -#: superset/connectors/druid/views.py:236 -msgid "Broker Password" -msgstr "Пароль брокера" - -#: superset/connectors/druid/views.py:234 -msgid "Broker Port" -msgstr "Порт брокера" - -#: superset/connectors/druid/views.py:235 -msgid "Broker Username" -msgstr "Пользователь брокера" - -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:30 -#: superset/viz.py:1139 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:32 +#: superset/viz.py:1168 msgid "Bubble Chart" -msgstr "Bubble Chart" +msgstr "Пузырьковая диаграмма" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:127 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:143 msgid "Bubble Color" -msgstr "Фиксированный цвет" +msgstr "Цвет пузыря" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:141 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:420 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:123 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:206 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:139 msgid "Bubble Size" -msgstr "Размер маркера" +msgstr "Размер пузыря" -#: superset-frontend/src/explore/controls.jsx:435 +#: superset-frontend/src/explore/controls.jsx:415 msgid "Bubble size" msgstr "Размер маркера" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:362 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:212 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:277 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:597 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:149 +msgid "Bucket break points" +msgstr "" + +#: superset-frontend/src/views/components/RightMenu.tsx:527 +msgid "Build" +msgstr "Сборка" + +#: superset-frontend/src/pages/ChartList/index.tsx:748 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:432 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:226 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:274 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:262 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:572 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:495 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:169 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:611 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:600 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:168 msgid "Bulk select" msgstr "Множественный выбор" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:30 -#: superset/viz.py:1190 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:32 +#: superset/viz.py:1219 msgid "Bullet Chart" -msgstr "Bullet Chart" +msgstr "Диаграмма-шкала" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:32 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:34 #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:40 #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:35 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:41 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:54 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:45 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:55 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:33 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:40 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:56 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:48 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:58 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:44 msgid "Business" -msgstr "" +msgstr "Бизнес" + +#: superset/connectors/sqla/views.py:166 +msgid "Business Data Type" +msgstr "Тип данных бизнеса" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:233 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:139 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:138 msgid "" "By default, each filter loads at most 1000 choices at the initial page " "load. Check this box if you have more than 1000 filter values and want to" " enable dynamically searching that loads filter values as users type (may" " add stress to your database)." msgstr "" -"По-умолчанию, каждый фильтр загружает не больше 1000 элементов выбора при" +"По умолчанию, каждый фильтр загружает не больше 1000 элементов выбора при" " начальной загрузке страницы. Установите этот флаг, если у вас больше " "1000 значений фильтра и вы хотите включить динамический поиск, который " "загружает значения по мере их ввода пользователем (может увеличить " "нагрузку на вашу базу данных)." -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:272 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:337 msgid "By key: use column names as sorting key" -msgstr "" +msgstr "По ключу: использовать имена столбцов как ключ сортировки" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:244 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:309 msgid "By key: use row names as sorting key" -msgstr "" +msgstr "По ключу: использовать имена строк как ключ сортировки" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:245 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:273 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:310 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:338 msgid "By value: use metric values as sorting key" -msgstr "" +msgstr "По значению: использовать значения мер как ключ сортировки" -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:334 +#: superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx:242 +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:327 msgid "CANCEL" -msgstr "ОТМЕНИТЬ" +msgstr "ОТМЕНА" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:601 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1356 +msgid "CREATE DATASET" +msgstr "СОЗДАТЬ ДАТАСЕТ" + +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:563 msgid "CREATE TABLE AS" -msgstr "Разрешить CREATE TABLE AS" +msgstr "CREATE TABLE AS" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:614 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:574 msgid "CREATE VIEW AS" -msgstr "Разрешить CREATE TABLE AS" +msgstr "CREATE VIEW AS" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:205 +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:234 msgid "CREATE VIEW statement" msgstr "Выражение CREATE VIEW" -#: superset-frontend/src/views/CRUD/alert/components/AlertReportCronScheduler.tsx:75 +#: superset-frontend/src/views/CRUD/alert/components/AlertReportCronScheduler.tsx:83 +msgid "CRON Schedule" +msgstr "CRON расписание" + +#: superset-frontend/src/views/CRUD/alert/components/AlertReportCronScheduler.tsx:94 msgid "CRON expression" -msgstr "Выражение SQL" +msgstr "CRON выражение" -#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:104 +#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:105 #: superset/views/dashboard/mixin.py:88 msgid "CSS" msgstr "CSS" -#: superset/initialization/__init__.py:265 superset/views/css_templates.py:36 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/style.tsx:75 +msgid "CSS Styles" +msgstr "CSS стили" + +#: superset/initialization/__init__.py:282 superset/views/css_templates.py:38 msgid "CSS Templates" -msgstr "Шаблоны CSS" +msgstr "CSS шаблоны" + +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/style.tsx:76 +msgid "CSS applied to the chart" +msgstr "CSS, примененный к графику" #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:249 msgid "CSS template" -msgstr "Шаблоны CSS" +msgstr "CSS шаблон" #: superset/css_templates/commands/exceptions.py:23 msgid "CSS template could not be deleted." -msgstr "Шаблон CSS не может быть удалён." +msgstr "Не удалось удалить CSS шаблон." -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:241 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:239 msgid "CSS template name" -msgstr "Имя Шаблона" +msgstr "Имя CSS шаблона" #: superset/css_templates/commands/exceptions.py:27 msgid "CSS template not found." -msgstr "Шаблон CSS не найден." +msgstr "CSS шаблон не найден." #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:71 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:240 msgid "CSS templates" -msgstr "Шаблоны CSS" +msgstr "CSS шаблоны" -#: superset/views/database/forms.py:101 -msgid "CSV File" -msgstr "CSV-файл" +#: superset/views/database/forms.py:109 +msgid "CSV Upload" +msgstr "Загрузка CSV" -#: superset/views/database/views.py:252 +#: superset/views/database/views.py:287 #, python-format msgid "" "CSV file \"%(csv_filename)s\" uploaded to table \"%(table_name)s\" in " "database \"%(db_name)s\"" msgstr "" -"CSV-файл \"%(csv_filename)s\" загружен в таблицу \"%(table_name)s\" базы " -"данных \"%(db_name)s\"" +"CSV файл \"%(csv_filename)s\" загружен в таблицу \"%(table_name)s\" в " +"базе данных \"%(db_name)s\"" -#: superset/views/database/views.py:118 +#: superset/views/database/views.py:160 msgid "CSV to Database configuration" -msgstr "Настройка CSV для БД" +msgstr "Конфигурация CSV файла для импорта в базу данных" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:271 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:341 msgid "CSV upload" -msgstr "Загрузить CSV" +msgstr "Загрузка CSV" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:118 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:130 msgid "CTAS & CVAS SCHEMA" -msgstr "" +msgstr "СХЕМА CTAS & CVAS" -#: superset/sql_lab.py:405 +#: superset/sql_lab.py:440 msgid "" "CTAS (create table as select) can only be run with a query where the last" " statement is a SELECT. Please make sure your query has a SELECT as its " "last statement. Then, try running your query again." msgstr "" -"CTAS (create table as select) может быть выполнено только в запросе, " -"последняя операция которого SELECT." +"CTAS (CREATE TABLE AS SELECT) может быть выполнен в запросе с " +"единственным SELECT запросом. Пожалуйста, убедитесь, что запрос содержит " +"только один SELECT запрос. Затем выполните запрос заново." -#: superset/views/database/mixins.py:190 +#: superset/views/database/mixins.py:187 msgid "CTAS Schema" -msgstr "Схема по умолчанию" +msgstr "Схема CTAS" -#: superset/sql_lab.py:422 +#: superset/sql_lab.py:457 msgid "" "CVAS (create view as select) can only be run with a query with a single " "SELECT statement. Please make sure your query has only a SELECT " "statement. Then, try running your query again." msgstr "" -"может быть выполнено только в запросе, в котором есть только одна " -"операция SELECT." +"CVAS (CREATE VIEW AS SELECT) может быть выполнен в запросе с единственным" +" SELECT запросом. Пожалуйста, убедитесь, что запрос содержит только один " +"SELECT запрос. Затем выполните запрос заново." -#: superset/errors.py:123 +#: superset/errors.py:129 msgid "CVAS (create view as select) query has more than one statement." -msgstr "" +msgstr "CVAS (CREATE VIEW AS SELECT) запрос содержит больше одного запроса." -#: superset/errors.py:124 +#: superset/errors.py:130 msgid "CVAS (create view as select) query is not a SELECT statement." -msgstr "" +msgstr "CVAS (CREATE VIEW AS SELECT) запрос не является SELECT запросом." -#: superset/connectors/druid/views.py:239 -#: superset/connectors/druid/views.py:351 superset/connectors/sqla/views.py:497 -#: superset/views/chart/mixin.py:77 +#: superset/connectors/sqla/views.py:487 superset/views/chart/mixin.py:77 msgid "Cache Timeout" -msgstr "Тайм-аут кеша" +msgstr "Время жизни кэша" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:67 -#: superset-frontend/src/explore/controlPanels/sections.tsx:51 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:79 +#: superset-frontend/src/explore/controlPanels/sections.tsx:41 msgid "Cache Timeout (seconds)" -msgstr "Тайм-аут кэша (секунды)" +msgstr "Время жизни кэша (секунды)" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:771 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:278 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:939 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:291 msgid "Cache timeout" -msgstr "Тайм-аут Кэша" +msgstr "Время жизни кэша" + +#: superset-frontend/src/components/CachedLabel/index.tsx:51 +msgid "Cached" +msgstr "Добавлено в кэш" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:241 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:366 #, python-format msgid "Cached %s" -msgstr "" +msgstr "Добавлено в кэш %s" -#: superset/viz.py:539 +#: superset/viz.py:559 msgid "Cached value not found" -msgstr "Значение не найдено в кеше" +msgstr "Кэшированное значение не найдено" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:70 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:77 -#, fuzzy -msgid "Calculate contribution per series or total" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx:45 +msgid "Calculate contribution per series or row" msgstr "" -"Вычислить вклад в общую сумму (долю). Установите формат показателя в " -"проценты" +"Вычислить вклад в общую сумму (долю) по категории или строке. " +"Установливает формат показателя в проценты" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:667 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:829 #, python-format msgid "Calculated column [%s] requires an expression" -msgstr "Для расчётного столбца [%s] требуется выражение" +msgstr "Для вычисляемого столбца [%s] требуется выражение" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1241 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1403 msgid "Calculated columns" -msgstr "Расчётные столбцы" +msgstr "Вычисляемые столбцы" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:121 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:334 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:217 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:469 -#: superset-frontend/src/explore/controlPanels/sections.tsx:232 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:137 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:329 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:211 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:481 +#: superset-frontend/src/explore/controlPanels/sections.tsx:207 msgid "Calculation type" msgstr "Тип расчёта" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:30 -#: superset/viz.py:1048 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:32 +#: superset/viz.py:1077 msgid "Calendar Heatmap" -msgstr "Calendar Heatmap" +msgstr "Календарная тепловая карта" -#: superset-frontend/src/dashboard/actions/dashboardLayout.js:211 +#: superset-frontend/src/dashboard/actions/dashboardLayout.js:213 msgid "Can not move top level tab into nested tabs" msgstr "Невозможно перенести вкладку верхнего уровня во вложенную вкладку" -#: superset/views/core.py:2010 -#, python-format -msgid "Can't find DruidCluster with cluster_name = '%(name)s'" -msgstr "Не удалось найти DruidCluster с именем cluster_name = ‘%(name)s’" - -#: superset/views/core.py:1998 -#, python-format -msgid "Can't find User '%(name)s', please ask your admin to create one." -msgstr "" -"Не удалось найти пользователя ‘%(name)s’. Обратитесь к администратору, " -"чтобы создать его." +#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:59 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:77 +msgid "Can select multiple values" +msgstr "Можно выбрать несколько значений" -#: superset/viz.py:1778 +#: superset/viz.py:1807 msgid "Can't have overlap between Series and Breakdowns" -msgstr "Срезы в полях [Столбцы данных] и [Ряды данных] должны быть разными" +msgstr "" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:173 -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:218 -#: superset-frontend/src/components/Modal/Modal.tsx:240 -#: superset-frontend/src/components/ReportModal/index.tsx:259 -#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:80 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:207 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:737 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:263 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:181 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:222 +#: superset-frontend/src/components/Modal/Modal.tsx:262 +#: superset-frontend/src/components/ReportModal/index.tsx:214 +#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:92 #: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:72 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:474 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:548 #: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:151 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:137 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:136 #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:76 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:62 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:194 -#: superset-frontend/src/explore/components/SaveModal.tsx:179 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:775 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:200 +#: superset-frontend/src/explore/components/SaveModal.tsx:368 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:826 +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx:121 #: superset/templates/superset/request_access.html:34 msgid "Cancel" -msgstr "Отменить" +msgstr "Отмена" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:304 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:314 msgid "Cancel query on window unload event" -msgstr "" - -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts:83 -msgid "Cannot create cyclic hierarchy" -msgstr "" +msgstr "Отменять запрос при закрытии вкладки" -#: superset/databases/commands/exceptions.py:109 -#, fuzzy +#: superset/databases/commands/exceptions.py:111 msgid "Cannot delete a database that has datasets attached" -msgstr "Невозможно удалить базу данных, для которой созданы таблицы" +msgstr "Невозможно удалить базу данных с подключенными датасетами" -#: superset/views/core.py:700 +#: superset/views/core.py:721 #, python-format msgid "" "Cannot import dashboard: %(db_error)s.\n" "Make sure to create the database before importing the dashboard." msgstr "" "Невозможно импортировать дашборд: %(db_error)s.\n" -"Убедитесь, что перед импортом дашборда была создана база данных." +"Убедитесь, что база даннах создана перед импортированием дашборда." -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:242 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:944 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:288 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1193 msgid "Cannot load filter" -msgstr "Временной фильтр" +msgstr "Невозможно загрузить фильтр" #: superset/charts/commands/exceptions.py:51 #, python-format msgid "Cannot parse time string [%(human_readable)s]" -msgstr "" +msgstr "Не удается разобрать временную строку [%(human_readable)s]" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:30 #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:38 #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:42 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:41 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:47 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:66 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:41 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:59 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:42 msgid "Categorical" -msgstr "" +msgstr "Категориальный" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:105 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:142 +msgid "Categorical Color" +msgstr "Цвет категории" -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:129 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:166 msgid "Categories to group by on the x-axis." -msgstr "" +msgstr "Категории для группировки по оси x" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:602 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/Scatter.jsx:46 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:678 msgid "Category" -msgstr "" - -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:87 +msgstr "Категория" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:51 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:88 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:102 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:115 +msgid "Category Name" +msgstr "Имя категории" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:55 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:94 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:106 +msgid "Category and Percentage" +msgstr "Категория и процентная доля" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:54 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:91 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:105 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:110 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:117 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:100 +msgid "Category and Value" +msgstr "Категория и значение" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:88 msgid "Category of target nodes" -msgstr "" +msgstr "Категория целевых вершин" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:56 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:98 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:107 +msgid "Category, Value and Percentage" +msgstr "Категория, значение и процентная доля" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:103 msgid "Cell Padding" -msgstr "" +msgstr "Расстояние между ячейками" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:117 msgid "Cell Radius" -msgstr "" +msgstr "Радиус ячейки" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:91 -#, fuzzy msgid "Cell Size" -msgstr "Файл Excel" +msgstr "Размер ячейки" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:413 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:424 msgid "Cell bars" -msgstr "Все графики" +msgstr "Гистограммы в ячейках" -#: superset-frontend/src/components/FilterableTable/FilterableTable.tsx:319 +#: superset-frontend/src/components/FilterableTable/index.tsx:431 msgid "Cell content" -msgstr "Созданный контент" +msgstr "Содержимое ячейки" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:112 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:135 +msgid "Cell limit" +msgstr "Лимит ячеек" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:101 msgid "Center" -msgstr "Последние" +msgstr "По центру" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:533 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:252 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/Hex.jsx:33 +msgid "Centroid (Longitude and Latitude): " +msgstr "Центроид (Долгота и Широта): " + +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:608 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:265 msgid "Certification" -msgstr "Детали сертификации" - -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:270 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:275 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1079 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1085 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:553 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:555 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:263 +msgstr "Утверждение" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:337 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:342 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1229 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1235 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:622 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:276 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:279 msgid "Certification details" -msgstr "Детали сертификации" +msgstr "Детали утверждения" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:530 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:504 -#, fuzzy +#: superset-frontend/src/pages/ChartList/index.tsx:669 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:535 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:568 msgid "Certified" -msgstr "Изменено" +msgstr "Утверждено" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:259 -#, fuzzy +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:326 msgid "Certified By" -msgstr "Изменено" - -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:264 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1066 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1074 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:538 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:540 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:254 +msgstr "Кем утверждено" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:331 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1216 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1224 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:613 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:267 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:268 msgid "Certified by" -msgstr "Изменено" +msgstr "Кем утверждено" #: superset-frontend/packages/superset-ui-chart-controls/src/components/CertifiedIconWithTooltip.tsx:46 -#: superset-frontend/src/components/CertifiedIcon/index.tsx:42 +#: superset-frontend/src/components/CertifiedBadge/index.tsx:44 #, python-format msgid "Certified by %s" -msgstr "Сертифицирован: %s" +msgstr "Утверждено: %s" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:253 -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:195 -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:267 -msgid "Change dataset" -msgstr "Выберите источник данных" - -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:269 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:334 msgid "Change order of columns." -msgstr "" +msgstr "Сменить порядок столбцов." -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:241 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:306 msgid "Change order of rows." -msgstr "" +msgstr "Сменить порядок строк." -#: superset/connectors/druid/views.py:354 superset/connectors/sqla/views.py:489 +#: superset/connectors/sqla/views.py:479 msgid "Changed By" -msgstr "Изменено" - -#: superset/views/schedules.py:238 superset/views/schedules.py:318 -msgid "Changed On" -msgstr "Изменено" +msgstr "Кем изменено" -#: superset/views/sql_lab.py:75 +#: superset/views/sql_lab/views.py:88 msgid "Changed on" -msgstr "Изменено" +msgstr "Дата изменения" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:50 +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:80 +msgid "Changes saved." +msgstr "Изменения сохранены." + +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:51 msgid "" "Changing the dataset may break the chart if the chart relies on columns " "or metadata that does not exist in the target dataset" msgstr "" -"Изменения датасета может привести к тому, что график станет нерабочим, " +"Изменение датасета может привести к тому, что график станет нерабочим, " "если график использует несуществующие в целевом датасете столбцы или " "метаданные" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1176 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1336 msgid "" "Changing these settings will affect all charts using this dataset, " "including charts owned by other people." @@ -2518,155 +3147,185 @@ msgstr "" #: superset/dashboards/commands/exceptions.py:78 msgid "Changing this Dashboard is forbidden" -msgstr "Изменение этого дашборда запрещено" +msgstr "Запрещено изменять этот дашборд" -#: superset/charts/commands/exceptions.py:131 +#: superset/charts/commands/exceptions.py:135 msgid "Changing this chart is forbidden" -msgstr "Изменение этого графика запрещено" +msgstr "Запрещено изменять этот график" #: superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx:75 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:40 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:55 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:68 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:83 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:98 -#: superset-frontend/src/explore/components/ControlHeader.jsx:77 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:45 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:60 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:73 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:88 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:103 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:66 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:97 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:114 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:131 +#: superset-frontend/src/explore/components/ControlHeader.tsx:123 msgid "Changing this control takes effect instantly" msgstr "Изменение этого элемента применяется сразу" -#: superset/datasets/commands/exceptions.py:177 +#: superset/datasets/commands/exceptions.py:181 msgid "Changing this dataset is forbidden" -msgstr "Изменение этого датасета запрещено" +msgstr "Запрещено изменять этот датасет" #: superset/datasets/columns/commands/exceptions.py:31 #: superset/datasets/metrics/commands/exceptions.py:31 -#, fuzzy msgid "Changing this dataset is forbidden." -msgstr "Изменение этого датасета запрещено" - -#: superset/reports/commands/exceptions.py:238 -msgid "Changing this report is forbidden" -msgstr "Изменение этого отчёта запрещено" +msgstr "Запрещено изменять этот датасет" -#: superset/views/database/forms.py:216 superset/views/database/forms.py:349 -msgid "Character to interpret as decimal point." -msgstr "Символ, который интерпретируется как десятичная точка." +#: superset/explore/exceptions.py:49 +msgid "Changing this datasource is forbidden" +msgstr "Запрещено изменять этот источник данных" -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:81 -#, fuzzy -msgid "Charge" -msgstr "график" +#: superset/reports/commands/exceptions.py:277 +msgid "Changing this report is forbidden" +msgstr "Запрещено изменять эту рассылку" -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:95 -msgid "Charge in the force layout" -msgstr "" +#: superset/views/database/forms.py:196 +msgid "Character to interpret as decimal point" +msgstr "Символ десятичного разделителя" -#: superset-frontend/src/components/Menu/MenuRight.tsx:39 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:387 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1297 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1300 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:261 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:607 -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:208 -#: superset/templates/appbuilder/navbar_right.html:39 -#: superset/views/chart/mixin.py:85 superset/views/chart/views.py:108 -#: superset/views/schedules.py:316 +#: superset/views/database/forms.py:375 +msgid "Character to interpret as decimal point." +msgstr "Символ десятичного разделителя" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:432 +#: superset-frontend/src/pages/ChartList/index.tsx:360 +#: superset-frontend/src/pages/ChartList/index.tsx:758 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:418 +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:191 +#: superset-frontend/src/views/components/RightMenu.tsx:217 +#: superset/views/chart/mixin.py:85 superset/views/chart/views.py:90 msgid "Chart" msgstr "График" -#: superset/views/core.py:1748 +#: superset/views/core.py:1713 #, python-format msgid "Chart %(id)s not found" msgstr "График %(id)s не найден" -#: superset/views/database/mixins.py:195 +#: superset/views/database/mixins.py:192 msgid "Chart Cache Timeout" -msgstr "Тайм-аут Кэша" +msgstr "Время жизни кэша графика" -#: superset/initialization/__init__.py:453 -msgid "Chart Email Schedules" -msgstr "Рассылка графиков" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:454 +#, python-format +msgid "Chart Data: %s" +msgstr "Данные графика: %s" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:58 -#: superset-frontend/src/explore/controlPanels/sections.tsx:42 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:70 +#: superset-frontend/src/explore/controlPanels/sections.tsx:32 msgid "Chart ID" -msgstr "График" +msgstr "ID графика" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:77 -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:49 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:54 -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:48 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:75 -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:61 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:140 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:65 +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:53 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:55 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:61 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:53 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:133 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:57 #: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:36 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:65 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:49 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:53 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:139 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:88 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:69 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:43 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:42 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:48 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:77 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:85 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:78 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:31 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:40 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:79 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:44 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:70 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:35 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:49 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:54 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:39 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:81 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:69 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:75 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:279 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:83 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:103 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:100 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:80 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:97 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:103 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:104 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:61 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:35 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:58 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:131 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:106 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:72 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:73 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:295 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:71 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:61 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:62 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:300 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:61 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:57 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:57 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:60 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:60 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:31 +#: superset-frontend/src/explore/fixtures.tsx:34 +#: superset-frontend/src/explore/fixtures.tsx:77 +#: superset-frontend/src/explore/fixtures.tsx:86 msgid "Chart Options" -msgstr "Редактирование свойств" +msgstr "Свойства графика" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:267 +msgid "Chart Orientation" +msgstr "Ориентация графика" #: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:70 #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:83 #, python-format msgid "Chart Owner: %s" -msgstr "Параметры графика: %s" +msgid_plural "Chart Owners: %s" +msgstr[0] "Владелец графика: %s" +msgstr[1] "Владельцы графика: %s" +msgstr[2] "Владельцы графика: %s" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:27 +#: superset-frontend/src/explore/components/ExploreViewContainer/index.jsx:611 #, fuzzy +msgid "Chart Source" +msgstr "Источник графика" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:32 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:289 msgid "Chart Title" -msgstr "Тип графика" +msgstr "Название графика" + +#: superset-frontend/src/explore/actions/saveModalActions.js:127 +#, python-format +msgid "Chart [%s] has been overwritten" +msgstr "График [%s] перезаписан" + +#: superset-frontend/src/explore/actions/saveModalActions.js:124 +#, python-format +msgid "Chart [%s] has been saved" +msgstr "График [%s] сохранен" + +#: superset-frontend/src/explore/actions/saveModalActions.js:145 +#, python-format +msgid "Chart [%s] was added to dashboard [%s]" +msgstr "График [%s] добавлен в дашборд [%s]" -#: superset/views/core.py:979 +#: superset/views/core.py:1072 msgid "Chart [{}] has been overwritten" -msgstr "График [{}] был перезаписан" +msgstr "График [{}] перезаписан" -#: superset/views/core.py:975 +#: superset/views/core.py:1068 msgid "Chart [{}] has been saved" -msgstr "График [{}] был сохранён" +msgstr "График [{}] сохранен" -#: superset/views/core.py:1006 +#: superset/views/core.py:1097 msgid "Chart [{}] was added to dashboard [{}]" -msgstr "График [{}] был добавлен к дашборду [{}]" +msgstr "График [{}] добавлен в дашборд [{}]" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:216 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:228 msgid "Chart cache timeout" -msgstr "Тайм-аут Кэша" +msgstr "Время жизни кэша графика" -#: superset-frontend/src/components/AlteredSliceTag/index.jsx:199 +#: superset-frontend/src/components/AlteredSliceTag/index.jsx:218 msgid "Chart changes" -msgstr "Изменения не сохранены" +msgstr "Изменения графика" -#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:28 +#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:30 msgid "" "Chart component that lets you add a custom filter UI in your dashboard. " "When added to dashboard, a filter box lets users specify specific values " @@ -2680,344 +3339,413 @@ msgstr "" #: superset/charts/commands/exceptions.py:115 msgid "Chart could not be created." -msgstr "График не может быть создан." +msgstr "Не удалось создать график" #: superset/charts/commands/exceptions.py:123 msgid "Chart could not be deleted." -msgstr "График не может быть удалён." +msgstr "Не удалось удалить график" #: superset/charts/commands/exceptions.py:119 msgid "Chart could not be updated." -msgstr "График не может быть обновлён." +msgstr "Не удалось обновить график" -#: superset/reports/commands/exceptions.py:53 +#: superset/reports/commands/exceptions.py:57 msgid "Chart does not exist" msgstr "График не существует" -#: superset/charts/data/api.py:125 +#: superset/charts/data/api.py:129 msgid "Chart has no query context saved. Please save the chart again." msgstr "" +"На графике не сохранен контекст запроса. Пожалуйста, сохраните диаграмму " +"еще раз." -#: superset-frontend/src/explore/components/SaveModal.tsx:247 +#: superset-frontend/src/explore/components/EmbedCodeContent.jsx:130 +msgid "Chart height" +msgstr "Высота графика" + +#: superset-frontend/src/pages/ChartList/index.tsx:219 +msgid "Chart imported" +msgstr "График импортирован" + +#: superset-frontend/src/explore/components/SaveModal.tsx:314 msgid "Chart name" msgstr "Имя графика" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:96 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:107 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:97 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:108 msgid "Chart options" -msgstr "Редактирование свойств" +msgstr "Свойства графика" #: superset/charts/commands/exceptions.py:111 msgid "Chart parameters are invalid." -msgstr "Параметры графика недействительны." +msgstr "Параметры графика недопустимы." -#: superset-frontend/src/explore/controlPanels/sections.tsx:32 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:165 +msgid "Chart properties updated" +msgstr "Свойства графика обновлены" + +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:220 +msgid "Chart title" +msgstr "Название графика" + +#: superset-frontend/src/pages/ChartList/index.tsx:622 msgid "Chart type" msgstr "Тип графика" -#: superset-frontend/src/dashboard/components/BuilderComponentPane.tsx:112 -#: superset-frontend/src/profile/components/CreatedContent.tsx:76 -#: superset-frontend/src/profile/components/Favorites.tsx:77 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:634 -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:306 -#: superset/initialization/__init__.py:246 superset/views/chart/mixin.py:26 +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:314 +msgid "Chart type requires a dataset" +msgstr "Для данного типа графика необходим датасет" + +#: superset-frontend/src/explore/components/EmbedCodeContent.jsx:139 +msgid "Chart width" +msgstr "Ширина графика" + +#: superset-frontend/src/dashboard/components/BuilderComponentPane/index.tsx:74 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx:65 +#: superset-frontend/src/pages/ChartList/index.tsx:786 +#: superset-frontend/src/profile/components/CreatedContent.tsx:104 +#: superset-frontend/src/profile/components/Favorites.tsx:87 +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:390 +#: superset/initialization/__init__.py:253 superset/views/chart/mixin.py:26 #: superset/views/dashboard/mixin.py:81 msgid "Charts" msgstr "Графики" -#: superset/charts/commands/exceptions.py:135 +#: superset/charts/commands/exceptions.py:139 msgid "Charts could not be deleted." -msgstr "Графики не могут быть удалены." +msgstr "Не удалось удалить графики." -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:162 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:488 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:505 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:182 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:516 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:533 msgid "Check configuration" -msgstr "Конфигурация слоя" +msgstr "Проверить конфигурацию" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:206 #: superset-frontend/src/filters/components/Select/controlPanel.ts:68 msgid "Check for sorting ascending" -msgstr "Сортировка по убыванию или по возрастанию" +msgstr "Выберит для сортировки по возрастанию" -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:113 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:105 +#: superset-frontend/src/explore/controlUtils/controlUtils.test.tsx:114 +#: superset-frontend/src/explore/fixtures.tsx:44 msgid "" "Check if the Rose Chart should use segment area instead of segment radius" " for proportioning" msgstr "" -#: superset-frontend/src/components/AnchorLink/index.jsx:85 +#: superset-frontend/src/dashboard/components/AnchorLink/index.tsx:73 msgid "Check out this chart in dashboard:" msgstr "Посмотреть этот график в дашборде:" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:319 -#, fuzzy +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:499 msgid "Check out this chart: " -msgstr "Посмотреть дашборд: " +msgstr "Посмотреть график: " -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:220 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:241 msgid "Check out this dashboard: " msgstr "Посмотреть дашборд: " -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:93 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:63 msgid "" "Check to apply filters instantly as they change instead of displaying " "[Apply] button" msgstr "" +"Установите флажок, чтобы применять фильтры мгновенно по мере их изменения" +" вместо отображения кнопки [Применить]" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:219 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:212 msgid "Check to force date partitions to have the same height" msgstr "" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:35 -msgid "Check to include Druid granularity dropdown" -msgstr "" - -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:109 -#, fuzzy -msgid "Check to include SQL time grain dropdown" -msgstr "Включить фильтр на определенный интервал/диапазон времени" - -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:123 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:87 msgid "Check to include time column dropdown" -msgstr "Включить фильтр на определенный интервал/диапазон времени" +msgstr "" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:110 -#, fuzzy +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:76 msgid "Check to include time grain dropdown" -msgstr "Включить фильтр на определенный интервал/диапазон времени" - -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:46 -msgid "Check to include time origin dropdown" -msgstr "Включить фильтр на определенный интервал/диапазон времени" +msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:173 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:174 msgid "Child label position" -msgstr "" +msgstr "Положение метки дочернего элемента" -#: superset/viz.py:2333 +#: superset/viz.py:2367 msgid "Choice of [Label] must be present in [Group By]" -msgstr "Выбор для [Метки] должен присутствовать в [Группировке по]" +msgstr "[Метка] должна присутствовать в [Группировать по]" -#: superset/viz.py:2341 +#: superset/viz.py:2375 msgid "Choice of [Point Radius] must be present in [Group By]" -msgstr "Срез [Радиуса точки] должен присутствовать в поле [Группировка]" +msgstr "[Радиус точки] должен присутствовать в [Группировать по]" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:150 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:151 #: superset/templates/superset/import_dashboards.html:47 msgid "Choose File" msgstr "Выберите файл" -#: superset/reports/commands/exceptions.py:80 +#: superset/reports/commands/exceptions.py:84 msgid "Choose a chart or dashboard not both" -msgstr "Удалить график из дашборда" +msgstr "Выберите график или дашборд, не обоих" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:674 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:874 msgid "Choose a database..." -msgstr "Выберите источник данных" +msgstr "Выберите базу данных..." -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:278 -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:288 +#: superset-frontend/src/pages/ChartCreation/index.tsx:377 +#: superset-frontend/src/pages/ChartCreation/index.tsx:388 msgid "Choose a dataset" -msgstr "Выберите источник данных" +msgstr "Выберите датасет" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:69 -#, fuzzy msgid "Choose a metric for left axis" -msgstr "Выберите показатель для правой оси" +msgstr "Выберите меру для левой оси" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:120 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:185 -#: superset-frontend/src/explore/controls.jsx:217 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:183 +#: superset-frontend/src/explore/controls.jsx:216 msgid "Choose a metric for right axis" -msgstr "Выберите показатель для правой оси" +msgstr "Выберите меру для правой оси" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:57 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:61 msgid "Choose a number format" -msgstr "Выберите показатель для правой оси" +msgstr "Выберите числовой формат" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:63 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:67 msgid "Choose a source" -msgstr "Выберите источник данных" +msgstr "Выберите источник" -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:105 #: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:44 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:34 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:38 msgid "Choose a source and a target" -msgstr "Выберите источник данных" +msgstr "Выберите источник и цель" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:69 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:73 msgid "Choose a target" -msgstr "Выберите источник данных" +msgstr "Выберите цель" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:308 -#, fuzzy +#: superset/connectors/sqla/views.py:328 +msgid "Choose a unique name" +msgstr "" + +#: superset-frontend/src/pages/ChartCreation/index.tsx:397 msgid "Choose chart type" -msgstr "Тип графика" +msgstr "Выберите тип графика" + +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:723 +msgid "Choose one of the available databases from the panel on the left." +msgstr "Выберите одну из доступных баз данных из панели слева." #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:100 -#, fuzzy msgid "Choose one or more charts for left axis" -msgstr "Выберите показатель для правой оси" +msgstr "Выберите один или несколько графиков для левой оси" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:135 -#, fuzzy msgid "Choose one or more charts for right axis" -msgstr "Выберите показатель для правой оси" +msgstr "Выберите один или несколько графиков для правой оси" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:745 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:795 msgid "Choose the annotation layer type" msgstr "Выбрать тип слоя аннотации" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:757 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:163 +msgid "Choose the format for legend values" +msgstr "Выберите формат значений легенды" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:177 +msgid "Choose the position of the legend" +msgstr "Выберите позицию легенды" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:807 msgid "Choose the source of your annotations" -msgstr "Настройте слой аннотации." +msgstr "Выберите источник аннотаций" + +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:122 +msgid "" +"Choose whether a country should be shaded by the metric, or assigned a " +"color based on a categorical color palette" +msgstr "" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:34 msgid "Chord Diagram" -msgstr "" +msgstr "Хордовая диаграмма" -#: superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx:281 +#: superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx:306 msgid "Chosen non-numeric column" -msgstr "" +msgstr "Выбран нечисловой столбец" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:218 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:219 msgid "Circle" -msgstr "Файл" +msgstr "Круг" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:130 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:131 msgid "Circle -> Arrow" -msgstr "" +msgstr "Круг -> Стрелка" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:131 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:132 msgid "Circle -> Circle" -msgstr "" +msgstr "Круг -> Круг" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:198 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:200 msgid "Circle radar shape" -msgstr "" +msgstr "Круглая форма радара" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:37 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:33 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:112 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:40 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:36 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:113 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:42 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:67 msgid "Circular" -msgstr "" +msgstr "Круглая форма" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:32 msgid "Classic chart that visualizes how metrics change over time." -msgstr "" +msgstr "Классическая диаграмма для визуализации изменения показателей со временем." #: superset-frontend/plugins/plugin-chart-table/src/index.ts:37 msgid "" "Classic row-by-column spreadsheet like view of a dataset. Use tables to " "showcase a view into the underlying data or to show aggregated metrics." msgstr "" +"Классическое представление таблицы. Используйте таблицы для демонстрации " +"отображения исходных или агрегированных данных." -#: superset/connectors/sqla/views.py:369 +#: superset/connectors/sqla/views.py:366 msgid "Clause" -msgstr "Условие" +msgstr "Оператор" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:53 msgid "Clear" msgstr "Очистить" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:133 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx:152 msgid "Clear all" +msgstr "Сбросить фильтры" + +#: superset-frontend/src/components/Table/index.tsx:264 +msgid "Clear all data" +msgstr "Очистить все данные" + +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:675 +msgid "Clear form" +msgstr "Очистить форму" + +#: superset-frontend/src/components/Chart/Chart.jsx:292 +msgid "" +"Click on \"Create chart\" button in the control panel on the left to " +"preview a visualization or" msgstr "" +"Нажмите на кнопку \"Создать график\" на панели управления слева для " +"просмотра графика или" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:997 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx:251 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx:293 +msgid "Click the button above to add a filter to the dashboard" +msgstr "Нажмите кнопку выше для добавления фильтров в дашборд" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1012 msgid "Click the lock to make changes." -msgstr "Нажмите на замок, чтобы выполнить изменения." +msgstr "Нажмите на замок для внесения изменений" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1000 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1015 msgid "Click the lock to prevent further changes." -msgstr "Нажмите на замок, чтобы предотвратить будущие изменения." +msgstr "Нажмите на замок для запрета на внос изменений." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1306 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1854 msgid "" "Click this link to switch to an alternate form that allows you to input " "the SQLAlchemy URL for this database manually." msgstr "" +"Нажмите для переключения на альтернативную форму подключения, которая " +"позволит вам вручную ввести SQLAlchemy URL для данной базы данных." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1071 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1573 msgid "" "Click this link to switch to an alternate form that exposes only the " "required fields needed to connect this database." msgstr "" +"Нажмите для переключения на альтернативную форму подключения, которая " +"позволит вам ввести все данные в соответствующую форму для данной базы " +"данных." -#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:114 -msgid "Click to change visualization type" -msgstr "Выберите тип визуализации" +#: superset-frontend/src/components/Table/index.tsx:271 +msgid "Click to cancel sorting" +msgstr "Нажмите для отмены сортировки" -#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:151 +#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:256 msgid "Click to clear emitted filters" -msgstr "" +msgstr "Нажмите для сброса кросс-фильтра" -#: superset-frontend/src/components/EditableTitle/index.tsx:197 +#: superset-frontend/src/components/EditableTitle/index.tsx:211 msgid "Click to edit" msgstr "Нажмите для редактирования" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.jsx:76 -#, fuzzy +#: superset-frontend/src/dashboard/util/getSliceHeaderTooltip.tsx:27 +#, python-format +msgid "Click to edit %s in a new tab" +msgstr "Нажмите для редактирования «%s» в новой вкладке" + +#: superset-frontend/src/dashboard/util/getSliceHeaderTooltip.tsx:32 +#, python-format +msgid "Click to edit %s." +msgstr "Нажмите для редактирования %s." + +#: superset-frontend/src/dashboard/util/getSliceHeaderTooltip.tsx:28 +#: superset-frontend/src/dashboard/util/getSliceHeaderTooltip.tsx:33 +msgid "Click to edit chart." +msgstr "Нажмите для редактирования графика." + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.jsx:81 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx:105 msgid "Click to edit label" -msgstr "Нажмите для редактирования" +msgstr "Нажмите для редактирования метки" -#: superset-frontend/src/components/FaveStar/index.tsx:81 +#: superset-frontend/src/components/FaveStar/index.tsx:79 msgid "Click to favorite/unfavorite" -msgstr "Отметить как избранное" +msgstr "Добавить в избранное" #: superset-frontend/src/components/CachedLabel/TooltipContent.tsx:39 msgid "Click to force-refresh" msgstr "Нажмите для принудительного обновления" -#: superset-frontend/src/components/AlteredSliceTag/index.jsx:177 +#: superset-frontend/src/components/AlteredSliceTag/index.jsx:201 msgid "Click to see difference" -msgstr "Нажмите, чтобы увидеть разницу" +msgstr "Нажмите для просмотра изменений" -#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:192 -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:523 -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:307 +#: superset-frontend/src/components/Table/index.tsx:270 +msgid "Click to sort ascending" +msgstr "Нажмите для сортировки по возрастанию" + +#: superset-frontend/src/components/Table/index.tsx:269 +msgid "Click to sort descending" +msgstr "Нажмите для сортировки по убыванию" + +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailModal.tsx:52 +#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:209 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:223 +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:786 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:406 #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:247 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:476 -#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:337 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:805 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:487 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:339 +#: superset-frontend/src/explore/components/controls/ViewQueryModalFooter.tsx:36 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1047 msgid "Close" msgstr "Закрыть" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:360 +#: superset-frontend/src/SqlLab/components/SqlEditorTabHeader/index.tsx:133 msgid "Close all other tabs" -msgstr "Закрыть все вкладки" +msgstr "Закрыть остальные вкладки" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:339 +#: superset-frontend/src/SqlLab/components/SqlEditorTabHeader/index.tsx:103 msgid "Close tab" msgstr "Закрыть вкладку" -#: superset/connectors/druid/views.py:344 -msgid "Cluster" -msgstr "Кластер" - -#: superset/connectors/druid/views.py:232 -msgid "Cluster Name" -msgstr "Имя кластера" - -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:171 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:183 msgid "Cluster label aggregator" -msgstr "" +msgstr "Агрегатор меток кластера" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:74 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:84 msgid "Clustering Radius" -msgstr "" +msgstr "Радиус кластера" #: superset-frontend/src/explore/controlPanels/Separator.js:25 #: superset-frontend/src/explore/controlPanels/Separator.js:46 @@ -3028,244 +3756,316 @@ msgstr "Редактор" msgid "Collapse all" msgstr "Свернуть всё" -#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:152 -#, fuzzy +#: superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:162 +msgid "Collapse data panel" +msgstr "Свернуть панель управления" + +#: superset-frontend/src/components/Table/index.tsx:268 +msgid "Collapse row" +msgstr "Свернуть строку" + +#: superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx:595 +msgid "Collapse tab content" +msgstr "Свернуть содержимое вкладки" + +#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx:198 msgid "Collapse table preview" -msgstr "Убрать предпросмотр таблицы" +msgstr "Свернуть предпросмотр таблицы" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:648 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:696 msgid "Color" msgstr "Цвет" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:137 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:439 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:126 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:450 msgid "Color +/-" -msgstr "" +msgstr "Раскрасить +/-" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:159 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:206 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:227 msgid "Color Metric" -msgstr "Цвет показателя" +msgstr "Цвет меры" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:108 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:474 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:111 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:337 msgid "Color Scheme" msgstr "Цветовая схема" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:129 -#, fuzzy msgid "Color Steps" -msgstr "Цветовая схема" +msgstr "Количество цветов" + +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:306 +msgid "Color bounds" +msgstr "Границы цвета" + +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:116 +msgid "Color by" +msgstr "Выбор цвета по" -#: superset-frontend/src/explore/controls.jsx:235 +#: superset-frontend/src/explore/controls.jsx:234 msgid "Color metric" -msgstr "Цвет показателя" +msgstr "Мера для цвета" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:93 +msgid "Color of the target location" +msgstr "Цвет целевого местоположения" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:50 +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx:87 #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:214 #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:218 -#: superset-frontend/src/explore/controlPanels/sections.tsx:79 -#: superset-frontend/src/explore/controls.jsx:480 +#: superset-frontend/src/explore/controlPanels/sections.tsx:60 +#: superset-frontend/src/explore/controls.jsx:460 msgid "Color scheme" msgstr "Цветовая схема" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:172 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:176 msgid "" -"Color will be rendered based on a ratio of the cell against the sum of " -"across this criteria" +"Color will be shaded based the normalized (0% to 100%) value of a given " +"cell against the other cells in the selected range: " msgstr "" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:374 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:427 msgid "Colors" msgstr "Цвета" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:283 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:352 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:361 #: superset-frontend/src/dashboard/components/gridComponents/new/NewColumn.jsx:31 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:109 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:112 #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:204 -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:227 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:248 #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:137 #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:140 #: superset-frontend/src/explore/components/controls/SpatialControl.jsx:194 -#: superset/connectors/druid/views.py:91 superset/connectors/sqla/views.py:143 +#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:209 +#: superset-frontend/src/filters/components/Range/controlPanel.ts:39 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:49 +#: superset-frontend/src/filters/components/Time/controlPanel.ts:37 +#: superset/connectors/sqla/views.py:156 msgid "Column" msgstr "Столбец" -#: superset/utils/pandas_postprocessing.py:712 +#: superset/utils/pandas_postprocessing/contribution.py:59 #, python-format msgid "" "Column \"%(column)s\" is not numeric or does not exists in the query " "results." msgstr "" +"Столбец \"%(column)s\" не является числовым или отсутствует в результатах" +" запроса." + +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:361 +msgid "Column Configuration" +msgstr "Свойства столбца" -#: superset/views/database/forms.py:224 superset/views/database/forms.py:357 -#: superset/views/database/forms.py:445 +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:194 +msgid "Column Formatting" +msgstr "Форматирование столбца(ов)" + +#: superset/views/database/forms.py:222 superset/views/database/forms.py:383 +#: superset/views/database/forms.py:474 msgid "Column Label(s)" -msgstr "Обозначения столбцов" +msgstr "Метка(и) столбца(ов)" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:79 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:80 msgid "" "Column containing ISO 3166-2 codes of region/province/department in your " "table." msgstr "" +"Столбец, содержащий коды ISO 3166-2 региона/республики/области в вашей " +"таблице" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:64 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:74 msgid "Column containing latitude data" -msgstr "" +msgstr "Столбец, содержащий данные о широте" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:64 msgid "Column containing longitude data" -msgstr "" +msgstr "Столбец, содержащий данные о долготе" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:115 -#, fuzzy +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:206 +msgid "Column header tooltip" +msgstr "Всплывающая подсказка заголовка столбца" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:118 msgid "Column is required" -msgstr "Имя обязательно" +msgstr "Столбец обязателен" -#: superset/views/database/forms.py:225 superset/views/database/forms.py:358 -#: superset/views/database/forms.py:446 +#: superset/views/database/forms.py:384 superset/views/database/forms.py:475 msgid "" "Column label for index column(s). If None is given and Dataframe Index is" " True, Index Names are used." msgstr "" -"Обозначение столбца для столбцов с индексами. Если поле пустое, а " -"настройка [Индекс] включена, то используются имена индексов." +"Метка для индексного(ых) столбца(ов). Если не задано и задан индекс " +"датафрейма, будут использованы имена индексов." + +#: superset/views/database/forms.py:223 +msgid "" +"Column label for index column(s). If None is given and Dataframe Index is" +" checked, Index Names are used" +msgstr "" +"Метка для индексного(ых) столбца(ов). Если не задано и задан индекс " +"датафрейма, будут использованы имена индексов." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:652 +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:77 +msgid "Column name" +msgstr "Имя столбца" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:814 #, python-format msgid "Column name [%s] is duplicated" -msgstr "Дубль имени столбца [%s]" - -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:139 -msgid "Column name(s) " -msgstr "Имена столбца(ов) " +msgstr "Имя столбца [%s] является дубликатом" -#: superset/utils/pandas_postprocessing.py:168 +#: superset/utils/pandas_postprocessing/utils.py:151 #, python-format msgid "Column referenced by aggregate is undefined: %(column)s" -msgstr "Столбец, на который ссылается агрегат, не определён: %(column)s" +msgstr "Столбец, на который ссылается агрегат, не определен: %(column)s" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:130 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:129 msgid "Column select" -msgstr "Выполнить выбранный запрос" +msgstr "Выбор столбца" + +#: superset/views/database/forms.py:211 +msgid "" +"Column to use as the row labels of the dataframe. Leave empty if no index" +" column" +msgstr "" +"Столбец для использования в качестве метки для строки датафрейма. " +"Оставьте пустым, если индексный столбец отсутствует." -#: superset/views/database/forms.py:163 superset/views/database/forms.py:316 +#: superset/views/database/forms.py:342 msgid "" "Column to use as the row labels of the dataframe. Leave empty if no index" " column." msgstr "" -"Столбец для использования в качестве меток строк данных. Оставьте пустым," -" если столбец индекса отсутствует." +"Столбец для использования в качестве метки для строки датафрейма. " +"Оставьте пустым, если индексный столбец отсутствует." -#: superset/views/database/forms.py:385 -#, fuzzy +#: superset/views/database/forms.py:414 msgid "Columnar File" -msgstr "столбец" +msgstr "Файл столбчатого формата" -#: superset/views/database/views.py:550 -#, fuzzy, python-format +#: superset/views/database/views.py:565 +#, python-format msgid "" "Columnar file \"%(columnar_filename)s\" uploaded to table " "\"%(table_name)s\" in database \"%(db_name)s\"" msgstr "" -"Excel-файл “%(excel_filename)s\" загружен в таблицу \"%(table_name)s\" " -"базы данных \"%(db_name)s\"" +"Файл столбчатого формата \"%(columnar_filename)s\" загружен в таблицу " +"\"%(table_name)s\" в базу данных \"%(db_name)s\"" -#: superset/views/database/views.py:414 -#, fuzzy +#: superset/views/database/views.py:440 msgid "Columnar to Database configuration" -msgstr "Настройка CSV для БД" - -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:55 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:214 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:36 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:59 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:82 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:101 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:124 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1207 -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:334 -#: superset-frontend/src/explore/controls.jsx:245 -#: superset/connectors/druid/views.py:70 superset/connectors/sqla/views.py:63 +msgstr "Конфигурация столбчатого файла для импорта в базу данных" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:110 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:33 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:38 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:62 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:52 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:119 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:102 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1367 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:431 +#: superset-frontend/src/explore/controls.jsx:244 +#: superset-frontend/src/explore/fixtures.tsx:97 +#: superset/connectors/sqla/views.py:73 msgid "Columns" msgstr "Столбцы" -#: superset/common/query_context_processor.py:114 superset/viz.py:554 +#: superset/views/database/forms.py:183 +msgid "Columns To Be Parsed as Dates" +msgstr "Список столбцов, которые должны быть интерпретированы как даты." + +#: superset/views/database/forms.py:231 +msgid "Columns To Read" +msgstr "Столбцы для чтения" + +#: superset/common/query_context_processor.py:130 +#, python-format +msgid "Columns missing in dataset: %(invalid_columns)s" +msgstr "Столбцы отсутствуют в датасете: %(invalid_columns)s" + +#: superset/viz.py:574 #, python-format msgid "Columns missing in datasource: %(invalid_columns)s" -msgstr "В источнике данных отсутствуют столбцы: %(invalid_columns)s" +msgstr "Столбцы отсутствуют в источнике данных: %(invalid_columns)s" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:302 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:367 msgid "Columns subtotal position" -msgstr "" +msgstr "Расположение столбцов подытогов" -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:134 -msgid "" -"Columns to calculate distribution across. Defaults to temporal column if " -"left empty." +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:171 +msgid "Columns to calculate distribution across." msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:44 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:45 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:54 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:102 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:125 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:45 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:46 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:55 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:39 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:63 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:103 +#: superset-frontend/src/explore/fixtures.tsx:99 msgid "Columns to display" -msgstr "Выберите показатель для отображения" +msgstr "Столбцы для отображения" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:43 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:42 msgid "Columns to group by" -msgstr "Выберите один или несколько срезов в поле группировки данных" +msgstr "Столбцы для группировки" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:60 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:53 msgid "Columns to group by on the columns" -msgstr "" +msgstr "Столбцы для группировки по столбцам" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:50 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:63 msgid "Columns to group by on the rows" -msgstr "" +msgstr "Столбцы для группировки по строкам" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:96 -#, fuzzy +#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:42 +msgid "Columns to show" +msgstr "Столбцы для отображения" + +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:85 msgid "Combine Metrics" -msgstr "Показатель для сортировки" +msgstr "Объединить меры" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:185 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:250 msgid "Combine metrics" -msgstr "Показатель для сортировки" +msgstr "Объединить меры" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:301 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:297 msgid "" "Comma-separated color picks for the intervals, e.g. 1,2,4. Integers " "denote colors from the chosen color scheme and are 1-indexed. Length must" " be matching that of interval bounds." msgstr "" +"Номера цветов, разделенные запятой, например, 1,2,4. Целые числа задают " +"цвета из выбранной цветовой схемы и начинаются с 1 (не с нуля). Длина " +"должна соответствовать границам интервала." -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:287 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:283 msgid "" "Comma-separated interval bounds, e.g. 2,4,5 for intervals 0-2, 2-4 and " "4-5. Last number should match the value provided for MAX." msgstr "" +"Границы интервала, разделенные запятой, например, 2,4,5 для интервалов " +"0-2, 2-4 и 4-5. Последнее число должно быть равно заданному максиму." -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:312 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:372 msgid "Comparator option" msgstr "" -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:26 +#: superset-frontend/src/visualizations/TimeTable/index.ts:28 msgid "" "Compare multiple time series charts (as sparklines) and related metrics " "quickly." msgstr "" +"Быстрое сравнение нескольких графиков временных рядов (в виде " +"спарклайнов) и связанных с ними показателей." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:26 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:27 msgid "Compare the same summarized metric across multiple groups." -msgstr "" +msgstr "Сравнивает один и тот же обобщенный показатель в нескольких группах" #: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:28 msgid "" @@ -3274,433 +4074,509 @@ msgid "" "and color." msgstr "" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:30 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:35 msgid "" "Compares metrics from different categories using bars. Bar lengths are " "used to indicate the magnitude of each value and color is used to " "differentiate groups." msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:26 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:27 msgid "" "Compares the lengths of time different activities take in a shared " "timeline view." msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:33 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:33 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:35 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:36 #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:30 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:37 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:35 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:35 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:34 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:36 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:42 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:35 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:46 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:41 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:38 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:48 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:37 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:49 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:43 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:68 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:56 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:59 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:60 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:43 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:31 -#, fuzzy +#: superset-frontend/src/visualizations/TimeTable/index.ts:34 msgid "Comparison" -msgstr "Столбец с датой" +msgstr "Сравнение" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:48 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:54 msgid "Comparison Period Lag" -msgstr "" +msgstr "Временной лаг для сравнения" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:61 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:67 msgid "Comparison suffix" -msgstr "Столбец с датой" +msgstr "Текст рядом с процентным изменением" -#: superset-frontend/src/dashboard/components/BuilderComponentPane.tsx:102 -msgid "Components" -msgstr "Компоненты" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/index.js:27 +msgid "Compose multiple layers together to form complex visuals." +msgstr "" +"Объединяет несколько слоев вместе для формирования сложных визуальных " +"эффектов." -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:53 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:56 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:59 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:57 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:72 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:367 -#: superset-frontend/src/explore/controlPanels/sections.tsx:136 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:48 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:52 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:49 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:63 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:377 +#: superset-frontend/src/explore/controlPanels/sections.tsx:109 msgid "Compute the contribution to the total" -msgstr "" -"Вычислить вклад в общую сумму (долю). Установите формат показателя в " -"проценты" +msgstr "Вычислить вклад в общую сумму (долю)" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1173 -#, fuzzy +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:404 msgid "Condition" -msgstr "Условие оповещения" +msgstr "Условие" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:320 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:473 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:385 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:500 msgid "Conditional formatting" -msgstr "Дополнительные метаданные" +msgstr "Условное форматирование" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:70 -#, fuzzy msgid "Confidence interval" -msgstr "Интервал обновления" +msgstr "Доверительный интервал" -#: superset/utils/pandas_postprocessing.py:827 +#: superset/utils/pandas_postprocessing/prophet.py:129 msgid "Confidence interval must be between 0 and 1 (exclusive)" -msgstr "Доверительный интервал должен быть между 0 и 1 (исключая)" +msgstr "Доверительный интервал должен быть между 0 и 1 (не включая концы)" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:252 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:276 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:289 msgid "Configuration" -msgstr "Доля" +msgstr "Конфигурация" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:58 -#, fuzzy msgid "Configure Advanced Time Range " -msgstr "Особый временной интервал" +msgstr "Установить особый временной интервал " -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx:41 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx:46 msgid "Configure Time Range: Last..." -msgstr "Последние…" +msgstr "Установить временной интервал: последний..." #: superset-frontend/src/explore/components/controls/DateFilterControl/components/CalendarFrame.tsx:46 msgid "Configure Time Range: Previous..." -msgstr "Предыдущие…" +msgstr "Установить временной интервал: предыдущий..." -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:111 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:125 msgid "Configure custom time range" -msgstr "Изменить параметры шаблона" +msgstr "Установить пользовательский временной интервал" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:500 +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:763 msgid "Configure filter scopes" -msgstr "Настроить области действия фильтра" +msgstr "Настроить область действия фильтра" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:718 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:768 msgid "Configure the basics of your Annotation Layer." msgstr "Настройте слой аннотации." -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:616 +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:177 +msgid "Configure this dashboard to embed it into an external web application." +msgstr "Настройте этот дашборд для встраивания во внешнее веб-приложение" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:664 msgid "Configure your how you overlay is displayed here." -msgstr "Настройте наложение здесь." +msgstr "Настройка отображения слоя аннотации поверх графика." + +#: superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.tsx:132 +msgid "Confirm overwrite" +msgstr "Подтвердить перезапись" -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:179 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:176 msgid "Confirm save" msgstr "Подтвердить сохранение" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:777 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1006 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1193 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:997 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1035 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1467 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1506 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1701 msgid "Connect" -msgstr "Тестовое соединение" +msgstr "Подключить" + +#: superset-frontend/src/views/components/RightMenu.tsx:185 +msgid "Connect Google Sheet" +msgstr "Подключить Google Таблицы" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:41 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:40 msgid "Connect Google Sheets as tables to this database" -msgstr "" +msgstr "Подключить Google Таблицы как таблицы для этой базы данных" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1011 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1197 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1471 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1511 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1705 msgid "Connect a database" -msgstr "Выберите базу данных" +msgstr "Подключиться к базе данных" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1068 +#: superset-frontend/src/views/components/RightMenu.tsx:175 +msgid "Connect database" +msgstr "Подключиться к базе данных" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1570 msgid "Connect this database using the dynamic form instead" -msgstr "" +msgstr "Подключиться к этой базе, используя динамичную форму" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1301 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1849 msgid "Connect this database with a SQLAlchemy URI string instead" -msgstr "" +msgstr "Подключиться к этой базе через SQLAlchemy URI" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:224 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:225 msgid "Connection" -msgstr "Тестовое соединение" +msgstr "База данных" -#: superset/databases/commands/exceptions.py:105 -#: superset/databases/commands/exceptions.py:122 superset/views/core.py:1383 +#: superset/databases/commands/exceptions.py:107 +#: superset/databases/commands/exceptions.py:124 superset/views/core.py:1418 msgid "Connection failed, please check your connection settings" -msgstr "Подключение не удалось, пожалуйста, проверьте строку подключения" +msgstr "Сбой подключения, пожалуйста, проверьте настройки вашего подключения" -#: superset-frontend/src/views/CRUD/hooks.ts:625 +#: superset-frontend/src/views/CRUD/hooks.ts:653 msgid "Connection looks good!" msgstr "Соединение в порядке!" +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:674 +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:685 +msgid "Continue" +msgstr "Продолжить" + #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:46 msgid "Continuous" -msgstr "" +msgstr "Непрерывный" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:51 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:54 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:57 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:55 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:70 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:365 -#: superset-frontend/src/explore/controlPanels/sections.tsx:134 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:46 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:50 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:47 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:61 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:375 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:72 +#: superset-frontend/src/explore/controlPanels/sections.tsx:107 msgid "Contribution" -msgstr "Доля" +msgstr "Режим относительных значений" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:69 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:69 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:70 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx:38 msgid "Contribution Mode" -msgstr "Доля" +msgstr "Режим относительных значений" + +#: superset-frontend/src/components/AlteredSliceTag/index.jsx:174 +msgid "Control" +msgstr "Элемент" -#: superset-frontend/src/explore/components/ExploreViewContainer.jsx:430 +#: superset-frontend/src/explore/components/ExploreViewContainer/index.jsx:513 msgid "Control labeled " -msgstr "" +msgstr "Значение с именем " -#: superset-frontend/src/explore/components/ExploreViewContainer.jsx:430 +#: superset-frontend/src/explore/components/ExploreViewContainer/index.jsx:513 msgid "Controls labeled " -msgstr "" +msgstr "Значения с именами " -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:57 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:34 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:60 msgid "Coordinates" -msgstr "Избранное" +msgstr "Координаты" -#: superset-frontend/src/components/CopyToClipboard/index.jsx:75 -#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:53 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:113 -#, fuzzy +#: superset-frontend/src/components/CopyToClipboard/index.jsx:77 +#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:68 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:185 msgid "Copied to clipboard!" -msgstr "Скопировать в буфер обмена" +msgstr "Скопировано в буфер обмена" -#: superset-frontend/src/explore/components/DataTableControl/index.tsx:48 +#: superset-frontend/src/components/CopyToClipboard/index.jsx:40 +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:84 msgid "Copy" -msgstr "" +msgstr "Копировать" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:192 +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:221 msgid "Copy SELECT statement to the clipboard" msgstr "Скопировать выражение SELECT в буфер обмена" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:106 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:105 msgid "Copy and Paste JSON credentials" -msgstr "" +msgstr "Скопировать и вставить JSON данные" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:124 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:125 msgid "Copy and paste the entire service account .json file here" -msgstr "" - -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:316 -#, fuzzy -msgid "Copy chart URL" -msgstr "Переместить график" - -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:103 -#, fuzzy -msgid "Copy chart URL to clipboard" -msgstr "Скопировать часть запроса в буфер обмена" - -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:263 -#, fuzzy -msgid "Copy dashboard URL" -msgstr "Нет дашбордов" +msgstr "Скопировать и вставить .json файл сервисного аккаунта сюда" -#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:98 +#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:108 msgid "Copy link" msgstr "Скопировать ссылку" -#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:184 +#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:201 msgid "Copy message" -msgstr "Предупреждающее сообщение" +msgstr "Скопировать сообщение" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:548 -#: superset-frontend/src/SqlLab/reducers/sqlLab.js:74 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:653 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1443 +#: superset-frontend/src/SqlLab/reducers/sqlLab.js:107 #, python-format msgid "Copy of %s" -msgstr "Копирование %s" +msgstr "Копия %s" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:103 +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:136 msgid "Copy partition query to clipboard" msgstr "Скопировать часть запроса в буфер обмена" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:390 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:335 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:496 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:340 +msgid "Copy permalink to clipboard" +msgstr "Скопировать ссылку в буфер обмена" + +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:391 msgid "Copy query URL" -msgstr "Скопировать URL запроса" +msgstr "Скопировать ссылку на запрос" -#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:88 +#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:98 msgid "Copy query link to your clipboard" -msgstr "Скопировать часть запроса в буфер обмена" +msgstr "Скопировать ссылку на запрос в буфер обмена" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx:26 msgid "Copy the account name of that database you are trying to connect to." -msgstr "" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:91 -msgid "Copy the name of the database you are trying to connect to." -msgstr "" +msgstr "Впишите имя профиля базы данных, к которой вы пытаетесь подключиться." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:552 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:93 #, fuzzy +msgid "Copy the name of the HTTP Path of your cluster." +msgstr "Скопировать имя HTTP пути вашего кластера." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:115 +msgid "Copy the name of the database you are trying to connect to." +msgstr "Впишите имя базы данных, к которой вы пытаетесь подключиться" + +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:270 msgid "Copy to Clipboard" msgstr "Скопировать в буфер обмена" -#: superset-frontend/src/components/CopyToClipboard/index.jsx:43 -#: superset-frontend/src/components/URLShortLinkButton/index.jsx:65 -#: superset-frontend/src/explore/components/EmbedCodeButton.jsx:106 +#: superset-frontend/src/components/CopyToClipboard/index.jsx:44 +#: superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx:89 msgid "Copy to clipboard" msgstr "Скопировать в буфер обмена" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:25 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:26 #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:28 #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:25 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:25 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:26 msgid "Correlation" -msgstr "Продолжительность" +msgstr "Корреляция" -#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:95 +#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:104 msgid "Cost estimate" msgstr "Прогноз затрат" -#: superset/views/utils.py:547 +#: superset/views/utils.py:497 msgid "Could not determine datasource type" -msgstr "Невозможно определить тип источника данных" +msgstr "Не удалось определить тип источника данных" -#: superset-frontend/src/dashboard/actions/sliceEntities.js:116 +#: superset-frontend/src/dashboard/actions/sliceEntities.js:127 #: superset-frontend/src/dashboard/reducers/sliceEntities.js:65 msgid "Could not fetch all saved charts" -msgstr "" +msgstr "Не удалось получить все сохраненные графики" -#: superset/views/utils.py:563 +#: superset/views/utils.py:513 msgid "Could not find viz object" -msgstr "Невозможно найти объект визуализации" +msgstr "Не удалось найти объект визуализации" -#: superset/databases/commands/exceptions.py:130 +#: superset/databases/commands/exceptions.py:132 msgid "Could not load database driver" -msgstr "Невозможно загрузить драйвер базы данных" +msgstr "Не удалось загрузить драйвер базы данных" -#: superset/views/core.py:1366 +#: superset/views/core.py:1401 #, python-format msgid "Could not load database driver: %(driver_name)s" -msgstr "Невозможно загрузить драйвер базы данных: %(driver_name)s" +msgstr "Не удалось загрузить драйвер базы данных: %(driver_name)s" -#: superset/databases/commands/test_connection.py:99 +#: superset/databases/commands/test_connection.py:180 msgid "Could not load database driver: {}" -msgstr "Невозможно загрузить драйвер базы данных: {}" +msgstr "Не удалось загрузить драйвер базы данных: {}" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:97 -msgid "Could not verify the host" -msgstr "" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:179 +msgid "Count" +msgstr "Количество" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:40 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:180 +msgid "Count Unique Values" +msgstr "Количество уникальных значений" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:198 +msgid "Count as Fraction of Columns" +msgstr "Количество, как доля от столбцов" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:195 +msgid "Count as Fraction of Rows" +msgstr "Количество, как доля от строк" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:194 +msgid "Count as Fraction of Total" +msgstr "Количество, как доля от целого" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:41 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:120 msgid "Country" -msgstr "Карта Стран" +msgstr "Страна" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:130 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:146 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:151 msgid "Country Color Scheme" -msgstr "Цветовая схема" +msgstr "Цветовая схема страны" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:115 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:135 msgid "Country Column" -msgstr "Фильтруемые срезы" +msgstr "Столбец со страной" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:39 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:41 msgid "Country Field Type" -msgstr "" +msgstr "Тип поля страны" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:30 -#: superset/viz.py:2007 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:33 +#: superset/viz.py:2041 msgid "Country Map" msgstr "Карта Стран" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:745 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:754 #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:96 -#, fuzzy msgid "Create" -msgstr "создать " +msgstr "Создать" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:275 +#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx:49 +msgid "Create Chart" +msgstr "Создать график" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx:113 +msgid "Create Dataset" +msgstr "Создать датасет" + +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:379 +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:330 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:319 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:330 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:354 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:395 +msgid "Create a dataset" +msgstr "Создать датасет" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:124 +msgid "" +"Create a dataset to begin visualizing your data as a chart or go to\n" +" SQL Lab to query your data." +msgstr "" +"Создайте датасет для визуализации ваших данных на графике или перейдите в" +" Лабораторию SQL для просмотра данных." + +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:201 +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:224 +#: superset-frontend/src/pages/ChartCreation/index.tsx:374 msgid "Create a new chart" -msgstr "Создать новый срез" +msgstr "Создать новый график" + +#: superset-frontend/src/explore/components/RunQueryButton/index.tsx:54 +#: superset-frontend/src/utils/getChartRequiredFieldsMissingMessage.ts:22 +msgid "Create chart" +msgstr "Создать график" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:330 +#: superset-frontend/src/views/components/RightMenu.tsx:180 +msgid "Create dataset" +msgstr "Создать датасет" + +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:306 +#: superset-frontend/src/pages/ChartCreation/index.tsx:423 msgid "Create new chart" msgstr "Создать новый график" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:111 -#, fuzzy msgid "Create new filter set" -msgstr "Создать новый график" +msgstr "Создать новый набор фильтров" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:124 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:135 msgid "Create or select schema..." -msgstr "" +msgstr "Создать или выбрать схему..." -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:169 +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:161 msgid "Created" msgstr "Создано" -#: superset/views/access_requests.py:46 superset/views/schedules.py:237 -#: superset/views/schedules.py:317 +#: superset/views/access_requests.py:49 msgid "Created On" msgstr "Дата создания" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:383 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:212 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:286 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:333 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:474 +#: superset-frontend/src/components/MetadataBar/ContentConfig.tsx:92 +#: superset-frontend/src/pages/ChartList/index.tsx:452 +#: superset-frontend/src/pages/ChartList/index.tsx:600 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:314 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:470 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:209 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:283 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:192 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:273 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:323 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:471 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:292 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:338 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:500 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:362 msgid "Created by" -msgstr "Дата создания" +msgstr "Кем создано" + +#: superset/charts/filters.py:116 superset/dashboards/filters.py:54 +msgid "Created by me" +msgstr "Создано мной" #: superset-frontend/src/profile/components/App.tsx:62 msgid "Created content" msgstr "Созданный контент" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:205 +#: superset-frontend/src/components/MetadataBar/ContentConfig.tsx:94 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:202 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:184 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:349 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:350 msgid "Created on" msgstr "Дата создания" -#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.jsx:72 +#: superset/databases/ssh_tunnel/commands/exceptions.py:46 +msgid "Creating SSH Tunnel failed for an unknown reason" +msgstr "Не удалось создать SSH туннель по неизвестной причине" + +#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx:70 msgid "Creating a data source and creating a new tab" -msgstr "Создание источника данных и добавление новой вкладки" +msgstr "Создание источника данных и добавление новой вкладки..." -#: superset/connectors/sqla/views.py:370 superset/views/chart/mixin.py:78 -#: superset/views/dashboard/mixin.py:85 superset/views/dashboard/views.py:157 -#: superset/views/database/mixins.py:192 +#: superset/connectors/sqla/views.py:367 superset/views/chart/mixin.py:78 +#: superset/views/dashboard/mixin.py:85 superset/views/dashboard/views.py:193 +#: superset/views/database/mixins.py:189 msgid "Creator" msgstr "Автор" -#: superset/views/schedules.py:241 superset/views/schedules.py:321 -msgid "Crontab" -msgstr "" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:47 +msgid "Crimson" +msgstr "Малиновый" -#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:65 -#, fuzzy +#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:77 msgid "Cross Filter Scoping" -msgstr "Установить действие фильтра" +msgstr "Область действия кросс-фильтра" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:349 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:485 msgid "Cross-filter scoping" -msgstr "" +msgstr "Задать область действия кросс-фильтра" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:153 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:139 msgid "Cumulative" -msgstr "Действия" +msgstr "С накоплением" + +#: superset-frontend/src/explore/components/controls/VizTypeControl/FastVizSwitcher.tsx:131 +#, python-format +msgid "Currently rendered: %s" +msgstr "Сейчас отрисовано: %s" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:33 -#, fuzzy msgid "Custom" -msgstr "Настроить" +msgstr "Пользовательский" #: superset/views/dynamic_plugins.py:59 msgid "Custom Plugin" @@ -3708,74 +4584,83 @@ msgstr "Пользовательский плагин" #: superset/views/dynamic_plugins.py:58 msgid "Custom Plugins" -msgstr "Пользовательское условие WHERE" +msgstr "Пользовательские плагины" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:283 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:226 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:229 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:440 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:443 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:383 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:232 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:451 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:454 msgid "Custom SQL" msgstr "Через SQL" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:222 -msgid "Custom SQL ad-hoc filters are not available for the native Druid connector" -msgstr "" - -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:432 -msgid "Custom SQL ad-hoc metrics are not available for the native Druid connector" -msgstr "" - -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:435 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:447 msgid "Custom SQL ad-hoc metrics are not enabled for this dataset" -msgstr "" +msgstr "Пользовательские ad-hoc меры SQL не разрешены для этого датасета" + +#: superset/connectors/sqla/utils.py:193 superset/errors.py:145 +#: superset/models/helpers.py:128 superset/models/helpers.py:849 +msgid "Custom SQL fields cannot contain sub-queries." +msgstr "Пользовательские поля SQL не могут содержать подзапросы." #: superset-frontend/src/filters/components/Time/index.ts:28 msgid "Custom time filter plugin" -msgstr "" +msgstr "Пользовательский плагин фильтра времени" -#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:417 +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:765 msgid "Customize" -msgstr "Настроить" +msgstr "Кастомизация" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:167 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:166 msgid "Customize Metrics" -msgstr "Настроить" +msgstr "Настроить меры" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:453 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:478 msgid "Customize columns" -msgstr "Расчётные столбцы" +msgstr "Настроить столбцы" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx:435 +msgid "Cyclic dependency detected" +msgstr "Обнаружена циклическая зависимость" -#: superset/connectors/sqla/views.py:261 +#: superset/connectors/sqla/views.py:257 msgid "D3 Format" -msgstr "Формат D3" +msgstr "Формат даты/времени" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:47 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:58 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:69 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1060 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1210 msgid "D3 format" -msgstr "Формат D3" +msgstr "Формат даты/времени" #: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:22 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:150 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:146 msgid "D3 format syntax: https://github.com/d3/d3-format" -msgstr "" +msgstr "Формат D3: https://github.com/d3/d3-format." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:154 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:150 msgid "" "D3 number format for numbers between -1.0 and 1.0, useful when you want " "to have different siginificant digits for small and large numbers" msgstr "" +"Числовой формат D3 для чисел от -1 до 1, полезно, если вы работаете как с" +" маленькими числами, где нужна точность, так и с большими целыми числами" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:220 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:377 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:285 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:388 msgid "D3 time format for datetime columns" -msgstr "" +msgstr "Формат времени D3 для столбцов типа дата/время" -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:44 +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:46 msgid "D3 time format syntax: https://github.com/d3/d3-time-format" +msgstr "Формат времени D3: https://github.com/d3/d3-time-format." + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:139 +msgid "DATETIME" +msgstr "Дата/Время (DATETIME/TIMESTAMP)" + +#: superset/utils/encrypt.py:117 +#, python-format +msgid "DB column %(col_name)s has unknown type: %(value_type)s" msgstr "" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:102 @@ -3783,931 +4668,1118 @@ msgid "DEC" msgstr "ДЕК" #: superset-frontend/src/components/DeleteModal/index.tsx:69 +#: superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx:241 msgid "DELETE" -msgstr "DELETE" +msgstr "УДАЛИТЬ" -#: superset-frontend/src/components/ReportModal/index.tsx:345 -#, fuzzy -msgid "DESCRIPTION ERROR" -msgstr "описание" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:259 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:329 msgid "DML" msgstr "DML" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:123 +msgid "Daily seasonality" +msgstr "Дневная сезонность" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:229 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:375 +msgid "Dark" +msgstr "Темный" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:43 +msgid "Dark Cyan" +msgstr "Темно-голубой" + #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:31 msgid "Dark mode" -msgstr "" +msgstr "Темная тема" -#: superset-frontend/src/components/Menu/MenuRight.tsx:46 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1296 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1317 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:582 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:210 -#: superset/templates/appbuilder/navbar_right.html:40 -#: superset/views/dashboard/mixin.py:78 superset/views/dashboard/views.py:155 -#: superset/views/schedules.py:236 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:417 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:621 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:189 +#: superset-frontend/src/views/components/RightMenu.tsx:226 +#: superset/views/dashboard/mixin.py:78 superset/views/dashboard/views.py:191 msgid "Dashboard" msgstr "Дашборд" -#: superset/initialization/__init__.py:444 -msgid "Dashboard Emails" -msgstr "Рассылка дашбордов" +#: superset-frontend/src/explore/actions/saveModalActions.js:135 +#, python-format +msgid "Dashboard [%s] just got created and chart [%s] was added to it" +msgstr "Дашборд [%s] был только что создан и график [%s] был добавлен в него" -#: superset/views/core.py:1028 +#: superset/views/core.py:1117 msgid "Dashboard [{}] just got created and chart [{}] was added to it" -msgstr "Дашборд [{}] был создан, и на него был добавлен график [{}]" +msgstr "Дашборд [{}] был только что создан и график [{}] был добавлен в него" #: superset/dashboards/commands/exceptions.py:54 msgid "Dashboard could not be created." -msgstr "Дашборд не может быть создан." +msgstr "Не удалось создать дашборд" #: superset/dashboards/commands/exceptions.py:70 msgid "Dashboard could not be deleted." -msgstr "Дашборд не может быть удалён." +msgstr "Не удалось удалить дашборд" #: superset/dashboards/commands/exceptions.py:66 msgid "Dashboard could not be updated." -msgstr "Дашборд не может быть обновлён." +msgstr "Не удалось обновить дашборд" -#: superset/reports/commands/exceptions.py:44 +#: superset/reports/commands/exceptions.py:48 msgid "Dashboard does not exist" msgstr "Дашборд не существует" +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:152 +msgid "Dashboard imported" +msgstr "Дашборд импортирован" + #: superset/dashboards/commands/exceptions.py:43 msgid "Dashboard parameters are invalid." -msgstr "Параметры дашборда недействительны." +msgstr "Неверные параметры дашборда" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:464 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:538 msgid "Dashboard properties" msgstr "Свойства дашборда" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:153 -#, fuzzy +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:374 +msgid "Dashboard properties updated" +msgstr "Свойства дашборда обновлены" + +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx:117 msgid "Dashboard scheme" -msgstr "[название]" +msgstr "Схема дашборда" -#: superset-frontend/src/profile/components/CreatedContent.tsx:73 -#: superset-frontend/src/profile/components/Favorites.tsx:74 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:609 -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:294 -#: superset/initialization/__init__.py:238 superset/views/chart/mixin.py:79 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:813 +msgid "" +"Dashboard time range filters apply to temporal columns defined in\n" +" the filter section of each chart. Add temporal columns to the " +"chart\n" +" filters to have this dashboard filter impact those charts." +msgstr "" + +#: superset-frontend/src/dashboard/components/Header/index.jsx:518 +msgid "Dashboard title" +msgstr "Название дашборда" + +#: superset-frontend/src/pages/ChartList/index.tsx:658 +#: superset-frontend/src/profile/components/CreatedContent.tsx:101 +#: superset-frontend/src/profile/components/Favorites.tsx:84 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:648 +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:376 +#: superset/initialization/__init__.py:245 superset/views/chart/mixin.py:79 #: superset/views/dashboard/mixin.py:25 msgid "Dashboards" msgstr "Дашборды" +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:282 +#: superset-frontend/src/pages/ChartList/index.tsx:402 +msgid "Dashboards added to" +msgstr "Добавлено в дашборды" + #: superset/dashboards/commands/exceptions.py:58 msgid "Dashboards could not be deleted." -msgstr "Дашборды не могут быть удалены." +msgstr "Не удалось удалить дашборды." #: superset/charts/commands/exceptions.py:91 msgid "Dashboards do not exist" -msgstr "Дашборды отсутствуют" +msgstr "Дашборды не существуют" -#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:401 -#: superset-frontend/src/explore/components/DataTablesPane/index.tsx:388 -#: superset-frontend/src/views/CRUD/data/common.ts:22 -#: superset/initialization/__init__.py:354 -#: superset/initialization/__init__.py:363 -#: superset/initialization/__init__.py:373 -#: superset/initialization/__init__.py:387 -#: superset/initialization/__init__.py:404 -#: superset/initialization/__init__.py:509 -#: superset/initialization/__init__.py:519 -#: superset/initialization/__init__.py:532 -#: superset/initialization/__init__.py:545 -msgid "Data" -msgstr "БД" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:673 +msgid "Dashed" +msgstr "Штрих" -#: superset/connectors/druid/views.py:343 -msgid "Data Source" -msgstr "Источник данных" +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:708 +#: superset-frontend/src/views/components/RightMenu.tsx:171 +#: superset/initialization/__init__.py:240 +msgid "Data" +msgstr "Данные" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:57 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:47 msgid "Data Table" -msgstr "Редактировать таблицу" +msgstr "Таблица" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:290 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:181 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:142 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:122 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:139 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:197 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:200 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:306 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:170 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:310 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:157 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:99 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:99 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:154 msgid "Data Zoom" -msgstr "" +msgstr "Масштабирование графика" -#: superset/views/core.py:2313 +#: superset/sqllab/commands/results.py:117 superset/views/core.py:2170 msgid "" "Data could not be deserialized from the results backend. The storage " "format might have changed, rendering the old data stake. You need to re-" "run the original query." msgstr "" +"Не удалось распознать данные с сервера . Формат хранилища мог измениться," +" что привело к потере старых данных. Вам нужно повторно запустить " +"исходный запрос." -#: superset/views/core.py:2266 -#, fuzzy +#: superset/sqllab/commands/results.py:76 superset/views/core.py:2123 msgid "" "Data could not be retrieved from the results backend. You need to re-run " "the original query." -msgstr "Не найдены сохранённые результаты, необходимо повторно выполнить запрос" +msgstr "" +"Не найдены сохраненные результаты на сервере, необходимо повторно " +"выполнить запрос." + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/components/PlaySlider.jsx:182 +msgid "Data has no time steps" +msgstr "" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:219 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:233 msgid "Data preview" msgstr "Предпросмотр данных" -#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:136 -msgid "Data source" -msgstr "Источник данных" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:288 +msgid "Data refreshed" +msgstr "Данные обновлены" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:213 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:216 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:284 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:266 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:269 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:354 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:362 msgid "Data type" -msgstr "Таблица Данных" +msgstr "Тип данных" -#: superset/utils/pandas_postprocessing.py:832 +#: superset/utils/pandas_postprocessing/prophet.py:134 msgid "DataFrame include at least one series" -msgstr "Пожалуйста, выберите хотя бы один показатель" +msgstr "" -#: superset/utils/pandas_postprocessing.py:830 +#: superset/utils/pandas_postprocessing/prophet.py:132 msgid "DataFrame must include temporal column" -msgstr "DataFrame должен включать временной столбец" - -#: superset-frontend/src/components/DatabaseSelector/index.tsx:271 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1127 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1132 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:179 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:223 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:294 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:436 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:223 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:331 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:277 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:424 -#: superset/connectors/sqla/views.py:490 superset/connectors/sqla/views.py:491 +msgstr "Датафрейм должен включать временной столбец" + +#: superset-frontend/src/components/DatabaseSelector/index.tsx:296 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:401 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:264 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:293 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:353 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:524 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:241 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:349 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:278 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:425 +#: superset/connectors/sqla/views.py:480 superset/connectors/sqla/views.py:481 #: superset/templates/superset/import_dashboards.html:53 -#: superset/views/database/forms.py:120 superset/views/database/forms.py:279 -#: superset/views/database/forms.py:407 superset/views/database/mixins.py:191 -#: superset/views/sql_lab.py:70 +#: superset/views/database/forms.py:137 superset/views/database/forms.py:305 +#: superset/views/database/forms.py:436 superset/views/database/mixins.py:188 +#: superset/views/sql_lab/views.py:83 msgid "Database" msgstr "База данных" -#: superset/views/database/views.py:452 -#, fuzzy, python-format +#: superset/views/database/views.py:478 +#, python-format msgid "" "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed " "for columnar uploads. Please contact your Superset Admin." msgstr "" -"Схема “%(schema_name)s” в базе данных “%(database_name)s” не разрешена " -"для загрузок Excel-файлов. Пожалуйста, свяжитесь с администратором " -"Superset." +"Схема \"%(schema_name)s\" базы данных \"%(database_name)s\" не " +"предназначена для загрузки файлов столбчатого формата. Пожалуйста, " +"свяжитесь с администратором." -#: superset/views/database/views.py:136 +#: superset/views/database/views.py:179 #, python-format msgid "" "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed " "for csv uploads. Please contact your Superset Admin." msgstr "" -"Схема “%(schema_name)s” в базе данных “%(database_name)s” не разрешена " -"для загрузки CSV. Пожалуйста, свяжитесь с администратором Superset." +"Схема \"%(schema_name)s\" базы данных \"%(database_name)s\" не " +"предназначена для загрузки CSV файлов. Пожалуйста, свяжитесь с " +"администратором." -#: superset/views/database/views.py:283 +#: superset/views/database/views.py:318 #, python-format msgid "" "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed " "for excel uploads. Please contact your Superset Admin." msgstr "" -"Схема “%(schema_name)s” в базе данных “%(database_name)s” не разрешена " -"для загрузок Excel-файлов. Пожалуйста, свяжитесь с администратором " -"Superset." +"Схема \"%(schema_name)s\" базы данных \"%(database_name)s\" не " +"предназначена для загрузки Excel файлов. Пожалуйста, свяжитесь с " +"администратором." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:910 -#, fuzzy +#: superset/initialization/__init__.py:237 +msgid "Database Connections" +msgstr "Базы данных" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1294 msgid "Database Creation Error" -msgstr "Database Expression" +msgstr "Ошибка создания базы данных" -#: superset/views/access_requests.py:43 +#: superset/views/access_requests.py:46 msgid "Database URL" msgstr "URL базы данных" -#: superset/databases/commands/exceptions.py:95 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:122 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:780 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:799 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1085 +msgid "Database connected" +msgstr "Соединение с базой данных установлено" + +#: superset/databases/commands/exceptions.py:96 msgid "Database could not be created." -msgstr "База данных не может быть создана." +msgstr "Не удалось создать базу данных." -#: superset/databases/commands/exceptions.py:113 +#: superset/databases/commands/exceptions.py:115 msgid "Database could not be deleted." -msgstr "База данных не может быть удалена." +msgstr "Не удалось удалить базу данных." -#: superset/databases/commands/exceptions.py:99 +#: superset/databases/commands/exceptions.py:100 msgid "Database could not be updated." -msgstr "База данных не может быть обновлена." +msgstr "Не удалось обновить базу данных." -#: superset/errors.py:117 +#: superset/errors.py:123 msgid "Database does not allow data manipulation." -msgstr "" +msgstr "База данных не позволяет изменять свои данные." #: superset/charts/commands/exceptions.py:82 #: superset/datasets/commands/exceptions.py:41 -#: superset/reports/commands/exceptions.py:35 +#: superset/reports/commands/exceptions.py:39 msgid "Database does not exist" msgstr "База данных не существует" -#: superset/connectors/sqla/models.py:1478 -#, fuzzy +#: superset/connectors/sqla/models.py:1766 superset/models/helpers.py:1951 msgid "Database does not support subqueries" -msgstr "База данных не существует" +msgstr "База данных не поддерживает подзапросы" + +#: superset-frontend/src/components/ImportModal/ErrorAlert.tsx:51 +msgid "" +"Database driver for importing maybe not installed. Visit the Superset " +"documentation page for installation instructions: " +msgstr "" +"Драйвер базы данных для импорта может быть не установлен. Изучите " +"документацию Суперсета для инструкций по установке: " -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:688 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:426 msgid "Database error" -msgstr "Database Expression" +msgstr "Ошибка базы данных" -#: superset/databases/commands/validate.py:136 -#, fuzzy +#: superset/databases/commands/validate.py:124 msgid "Database is offline." -msgstr "Название таблицы" +msgstr "База данных сейчас оффлайн." -#: superset/reports/commands/exceptions.py:62 +#: superset/reports/commands/exceptions.py:66 msgid "Database is required for alerts" -msgstr "База данных требуется для уведомлений" +msgstr "Для оповещений требуется база данных" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:89 -#: superset/db_engine_specs/base.py:1396 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:113 +#: superset/db_engine_specs/base.py:1741 msgid "Database name" -msgstr "Название таблицы" +msgstr "Имя базы данных" #: superset/datasets/commands/exceptions.py:50 msgid "Database not allowed to change" -msgstr "Базу данных не разрешено изменять" +msgstr "База данных недоступна для изменений" -#: superset/databases/commands/exceptions.py:91 +#: superset/databases/commands/exceptions.py:92 msgid "Database not found." msgstr "База данных не найдена." +#: superset/views/core.py:1174 +#, python-format +msgid "Database not found: %(id)s" +msgstr "База данных не найдена: %(id)s" + #: superset/databases/commands/exceptions.py:32 msgid "Database parameters are invalid." msgstr "Параметры базы данных недействительны." -#: superset/db_engine_specs/base.py:1393 -#, fuzzy +#: superset-frontend/src/components/ImportModal/index.tsx:219 +msgid "Database passwords" +msgstr "Пароли базы данных" + +#: superset/db_engine_specs/base.py:1738 +#: superset/db_engine_specs/databricks.py:52 msgid "Database port" -msgstr "база данных" +msgstr "Порт базы данных" -#: superset-frontend/src/profile/components/Security.tsx:46 -#: superset-frontend/src/views/CRUD/data/common.ts:26 -#: superset/initialization/__init__.py:351 superset/views/database/mixins.py:33 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:764 +msgid "Database settings updated" +msgstr "Обновлены настройки базы данных" + +#: superset-frontend/src/profile/components/Security.tsx:47 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:255 +#: superset/views/database/mixins.py:33 msgid "Databases" msgstr "Базы данных" -#: superset/views/database/forms.py:221 superset/views/database/forms.py:354 -#: superset/views/database/forms.py:442 +#: superset/views/database/forms.py:219 superset/views/database/forms.py:380 +#: superset/views/database/forms.py:471 msgid "Dataframe Index" -msgstr "Индекс" +msgstr "Индекс датафрейма" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:284 +#: superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.tsx:267 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx:89 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:833 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:862 -#: superset-frontend/src/explore/components/ExploreViewContainer.jsx:521 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:823 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:852 #: superset-frontend/src/explore/controls.jsx:189 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:283 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:520 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:505 +#: superset-frontend/src/pages/ChartCreation/index.tsx:383 +#: superset-frontend/src/pages/ChartList/index.tsx:382 +#: superset-frontend/src/pages/ChartList/index.tsx:648 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:630 msgid "Dataset" msgstr "Датасет" #: superset/datasets/commands/exceptions.py:32 #, python-format msgid "Dataset %(name)s already exists" -msgstr "Источник данных %(name)s уже существует" +msgstr "Датасет %(name)s уже существует" + +#: superset-frontend/src/explore/components/SaveModal.tsx:325 +msgid "Dataset Name" +msgstr "Имя датасета" #: superset/datasets/columns/commands/exceptions.py:27 -#, fuzzy msgid "Dataset column delete failed." -msgstr "Удаление аннотации не удалось." +msgstr "Не удалось удалить столбец датасета" #: superset/datasets/columns/commands/exceptions.py:23 -#, fuzzy msgid "Dataset column not found." -msgstr "База данных не найдена." +msgstr "Столбец датасета не найден" #: superset/datasets/commands/exceptions.py:157 msgid "Dataset could not be created." -msgstr "Датасет не может быть создан." +msgstr "Не удалось создать датасет" #: superset/datasets/commands/exceptions.py:165 msgid "Dataset could not be deleted." -msgstr "Датасет не может быть удалён." +msgstr "Не удалось удалить датасет" + +#: superset/datasets/commands/exceptions.py:193 +msgid "Dataset could not be duplicated." +msgstr "Датасет не может быть дублирован." #: superset/datasets/commands/exceptions.py:161 #: superset/datasets/commands/exceptions.py:173 msgid "Dataset could not be updated." -msgstr "Датасет не может быть обновлён." +msgstr "Не удалось обновить датасет" -#: superset/commands/exceptions.py:119 #: superset/datasets/commands/exceptions.py:149 msgid "Dataset does not exist" -msgstr "Источник данных %(name)s уже существует" +msgstr "Датасет не существует" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:843 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:183 +msgid "Dataset imported" +msgstr "Импортирован датасет" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:833 msgid "Dataset is required" -msgstr "Источники данных" +msgstr "Требуется датасет" #: superset/datasets/metrics/commands/exceptions.py:27 -#, fuzzy msgid "Dataset metric delete failed." -msgstr "Удаление аннотации не удалось." +msgstr "Не удалось удалить меру датасета." #: superset/datasets/metrics/commands/exceptions.py:23 -#, fuzzy msgid "Dataset metric not found." -msgstr "База данных не найдена." +msgstr "Мера датасета не найдена." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:881 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:888 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1066 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1073 msgid "Dataset name" -msgstr "Наименование датасета" +msgstr "Имя датасета" #: superset/datasets/commands/exceptions.py:153 msgid "Dataset parameters are invalid." -msgstr "Параметры датасета недействительны." +msgstr "Параметры датасета неверны." + +#: superset/dashboards/api.py:405 +#, python-format +msgid "Dataset schema is invalid, caused by: %(error)s" +msgstr "Схема датасета невалидна, причина: %(error)s" #: superset/datasets/commands/exceptions.py:169 msgid "Dataset(s) could not be bulk deleted." -msgstr "Датасет(ы) не может быть удален." +msgstr "Датасет(ы) не могут быть массово удалены." -#: superset-frontend/src/profile/components/Security.tsx:60 -#: superset-frontend/src/views/CRUD/data/common.ts:32 -#: superset/initialization/__init__.py:359 +#: superset-frontend/src/profile/components/Security.tsx:61 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:593 +#: superset/initialization/__init__.py:261 msgid "Datasets" msgstr "Датасеты" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:809 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx:42 +msgid "" +"Datasets can be created from database tables or SQL queries. Select a " +"database table to the left or " +msgstr "" +"Датасеты могут быть созданы из таблиц базы данных или SQL запросов. " +"Выберите таблицу из базы данных слева или " + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:792 msgid "Datasets do not contain a temporal column" -msgstr "DataFrame должен включать временной столбец" +msgstr "Датасет не содержит столбца формата дата/время" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:157 -#: superset/connectors/druid/views.py:93 superset/views/access_requests.py:44 -#: superset/views/chart/mixin.py:80 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:110 +#: superset/views/access_requests.py:47 superset/views/chart/mixin.py:80 msgid "Datasource" msgstr "Источник данных" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:48 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:60 msgid "Datasource & Chart Type" -msgstr "Имя источника данных" +msgstr "Источник данных и Тип графика" -#: superset/connectors/druid/views.py:352 -msgid "Datasource Name" -msgstr "Имя источника данных" +#: superset/commands/exceptions.py:131 +msgid "Datasource does not exist" +msgstr "Источник данных не существует" -#: superset/connectors/connector_registry.py:99 -#, fuzzy, python-format -msgid "Datasource id not found: %(id)s" -msgstr "База данных не найдена." +#: superset/commands/exceptions.py:123 +msgid "Datasource type is invalid" +msgstr "Тип источниках данных неверный" #: superset/charts/commands/exceptions.py:101 msgid "Datasource type is required when datasource_id is given" -msgstr "Тип источника данных обязателен, если задан ID" +msgstr "" +"Тип источника данных обязателен, когда дан идентификатор источника данных" +" (datasource_id)" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:163 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:87 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:156 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:79 msgid "Date Time Format" -msgstr "Формат Datetime" +msgstr "Формат даты и времени" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:79 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:49 msgid "Date filter" msgstr "Временной фильтр" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:142 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:115 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:131 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:70 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:144 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:152 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:136 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:153 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:129 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:216 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:152 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:145 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:128 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:281 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:328 msgid "Date format" -msgstr "Формат Datetime" +msgstr "Форматы даты" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:235 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:334 +msgid "Date format string" +msgstr "Формат временной строки" + +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:247 msgid "Date/Time" -msgstr "Формат даты" +msgstr "Дата/Время" -#: superset/connectors/sqla/views.py:151 +#: superset/connectors/sqla/views.py:164 msgid "Datetime Format" -msgstr "Формат Datetime" +msgstr "Формат даты и времени" -#: superset/connectors/sqla/models.py:1062 +#: superset/connectors/sqla/models.py:1219 superset/models/helpers.py:1412 msgid "" "Datetime column not provided as part table configuration and is required " "by this type of chart" msgstr "" -"Для данного графика необходим временной ряд. Укажите столбец с датой в " -"соответствующем поле раздела [Время]" +"Столбец даты/времени не предусмотрен в настройках таблицы и является " +"обязательным для этого типа графика" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:227 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:294 msgid "Datetime format" -msgstr "Формат Datetime" +msgstr "Формат даты/времени" -#: superset/db_engine_specs/base.py:96 -#, fuzzy +#: superset/db_engine_specs/base.py:110 msgid "Day" -msgstr "день" +msgstr "День" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:66 -#, fuzzy, python-format +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:63 +msgid "Day (freq=D)" +msgstr "День (част=D)" + +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:65 +#, python-format msgid "Days %s" -msgstr "день" +msgstr "Дней %s" -#: superset/connectors/sqla/models.py:1593 +#: superset/connectors/sqla/models.py:1890 superset/models/helpers.py:973 msgid "Db engine did not return all queried columns" -msgstr "" +msgstr "драйвер базы данных вернул не все запрошенные столбцы" + +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:215 +msgid "Deactivate" +msgstr "Выключить" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:77 msgid "December" msgstr "Декабрь" -#: superset/views/database/forms.py:214 superset/views/database/forms.py:347 +#: superset/views/database/forms.py:194 superset/views/database/forms.py:373 msgid "Decimal Character" -msgstr "Десятичный символ" +msgstr "Десятичный разделитель" -#: superset/viz.py:2706 +#: superset/viz.py:2740 msgid "Deck.gl - 3D Grid" -msgstr "Deck.gl - 3D Grid" +msgstr "Deck.gl - 3D сетка" -#: superset/viz.py:2822 +#: superset/viz.py:2856 +#, fuzzy msgid "Deck.gl - 3D HEX" msgstr "Deck.gl - 3D HEX" -#: superset/viz.py:2862 +#: superset/viz.py:2896 msgid "Deck.gl - Arc" -msgstr "Deck.gl - Arc" +msgstr "Deck.gl - Дуга" -#: superset/viz.py:2843 +#: superset/viz.py:2877 msgid "Deck.gl - GeoJSON" msgstr "Deck.gl - GeoJSON" -#: superset/viz.py:2431 +#: superset/viz.py:2465 msgid "Deck.gl - Multiple Layers" -msgstr "Deck.gl - Multiple Layers" +msgstr "Deck.gl - Многослойный" -#: superset/viz.py:2738 +#: superset/viz.py:2772 +#, fuzzy msgid "Deck.gl - Paths" msgstr "Deck.gl - Paths" -#: superset/viz.py:2789 +#: superset/viz.py:2823 msgid "Deck.gl - Polygon" -msgstr "Deck.gl - Polygon" +msgstr "Deck.gl - Полигон" -#: superset/viz.py:2625 +#: superset/viz.py:2659 msgid "Deck.gl - Scatter plot" -msgstr "Deck.gl - Scatter plot" +msgstr "Deck.gl - Точечная диаграмма" -#: superset/viz.py:2677 +#: superset/viz.py:2711 +#, fuzzy msgid "Deck.gl - Screen Grid" msgstr "Deck.gl - Screen Grid" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:167 msgid "Default" -msgstr "Широта по умолчанию" +msgstr "По умолчанию" -#: superset/connectors/druid/views.py:349 superset/connectors/sqla/views.py:495 +#: superset/connectors/sqla/views.py:485 msgid "Default Endpoint" -msgstr "Адрес по-умолчанию" +msgstr "Эндпоинт по умолчанию" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:699 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:865 msgid "Default URL" -msgstr "URL базы данных" +msgstr "URL по умолчанию" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:700 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:866 msgid "Default URL to redirect to when accessing from the dataset list page" msgstr "" -"URL по-умолчанию, на который будет выполнен редирект при доступе из " +"URL по умолчанию, на который будет выполнен редирект при доступе из " "страницы со списком датасетов" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:907 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1156 msgid "Default Value" -msgstr "Значение фильтра" +msgstr "Значение по умолчанию" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:357 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:365 +msgid "Default datetime" +msgstr "Дата и время по умолчанию" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:290 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:295 msgid "Default latitude" -msgstr "" +msgstr "Широта по умолчанию" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:276 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:281 msgid "Default longitude" -msgstr "" +msgstr "Долгота по умолчанию" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:91 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:80 msgid "" "Default minimal column width in pixels, actual width may still be larger " "than this if other columns don't need much space" msgstr "" +"Минимальная ширина столбца (в пикселях). Реальная ширина по-прежнему " +"может быть больше, чем указанная, если остальным столбцам не будет " +"хватать места." -#: superset-frontend/src/filters/components/Select/controlPanel.ts:105 -msgid "Default to first item" -msgstr "" - -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:936 -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:222 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1185 msgid "Default value is required" -msgstr "Источники данных" +msgstr "Требуется значение по умолчанию" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:95 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:96 msgid "Default value must be set when \"Filter has default value\" is checked" msgstr "" +"Значение по умолчанию должно быть выбрано, когда установлен флаг \"Фильтр" +" имеет значение по умолчанию\"" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:92 +msgid "Default value must be set when \"Filter value is required\" is checked" +msgstr "" +"Значение по умолчанию должно быть выбрано, когда установлен флаг " +"\"Требуется значение фильтра\"" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:88 +msgid "" +"Default value set automatically when \"Select first filter value by " +"default\" is checked" +msgstr "" +"Значение по умолчанию задается автоматически, когда установлен флаг " +"\"Сделать первое значение фильтра значением по умолчанию\"" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:93 -msgid "Default value must be set when \"Required\" is checked" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:145 +msgid "" +"Define a function that receives the input and outputs the content for a " +"tooltip" +msgstr "Задайте функцию, которая получает на вход содержимое всплывающей подсказки" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:155 +msgid "Define a function that returns a URL to navigate to when user clicks" msgstr "" +"Задайте функцию, которая возвращает URL для навигации при " +"пользовательском нажатии" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:89 -msgid "Default value set automatically when \"Default to first item\" is checked" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:133 +msgid "" +"Define a javascript function that receives the data array used in the " +"visualization and is expected to return a modified version of that array." +" This can be used to alter properties of the data, filter, or enrich the " +"array." msgstr "" +"Определите функцию javascript, которая получает массив данных, " +"используемый в визуализации, и, как ожидается, вернет измененную версию " +"этого массива. Это может быть использовано для изменения свойств данных, " +"фильтрации или расширения массива." #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:44 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:266 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:149 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:167 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:398 -#: superset-frontend/src/explore/controlPanels/sections.tsx:167 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:259 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:141 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:408 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:188 +#: superset-frontend/src/explore/controlPanels/sections.tsx:140 msgid "" "Defines a rolling window function to apply, works along with the " "[Periods] text box" msgstr "" -"Одна из функций (Rolling) библиотеки Pandas, которая определяет способ " -"агрегации данных" +"Определяет функцию скользящего окна для применения, работает вместе с " +"текстовым полем [Периоды]" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:134 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:124 msgid "Defines how each series is broken down" -msgstr "" +msgstr "Определяет разложение каждой категории" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:64 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:388 -#: superset-frontend/src/explore/controls.jsx:403 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:285 +msgid "Defines the grid size in pixels" +msgstr "Определяет размер сетки (в пикселях)" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:119 +#: superset-frontend/src/explore/controls.jsx:383 msgid "" "Defines the grouping of entities. Each series is shown as a specific " "color on the chart and has a legend toggle" msgstr "" -"Группировка в ряды данных. Каждый ряд отображается в виде определенного " -"цвета на графике и имеет легенду" - -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:227 -#: superset-frontend/src/explore/controls.jsx:258 -msgid "" -"Defines the origin where time buckets start, accepts natural dates as in " -"`now`, `sunday` or `1970-01-01`" -msgstr "" +"Группировка в ряды данных. Каждая категория отображается в виде " +"определенного цвета на графике и имеет легенду" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:58 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:280 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:163 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:181 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:412 -#: superset-frontend/src/explore/controlPanels/sections.tsx:179 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:273 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:155 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:422 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:202 +#: superset-frontend/src/explore/controlPanels/sections.tsx:152 msgid "" "Defines the size of the rolling window function, relative to the time " "granularity selected" msgstr "" -"Одна из функций (Rolling) библиотеки Pandas, которая определяет период, к" -" которому применяется функция агрегации" +"Определяет размер функции скользящего окна относительно выбранной " +"детализации по времени" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:120 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:77 msgid "" "Defines whether the step should appear at the beginning, middle or end " "between two data points" msgstr "" +"Определяет, должен ли шаг отображаться в начале, середине или конце между" +" двумя точками данных" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:82 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:325 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:497 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:310 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:374 -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:103 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:369 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:653 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:336 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:131 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:367 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:622 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:357 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:628 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:508 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:238 -#: superset/views/base.py:595 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:90 +#: superset-frontend/src/pages/ChartList/ChartCard.tsx:106 +#: superset-frontend/src/pages/ChartList/index.tsx:488 +#: superset-frontend/src/pages/ChartList/index.tsx:805 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:395 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:596 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:307 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:366 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:338 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:130 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:382 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:661 +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/index.tsx:59 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:422 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:779 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:512 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:220 +#: superset/views/base.py:659 msgid "Delete" msgstr "Удалить" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:481 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:580 #, python-format msgid "Delete %s?" msgstr "Удалить %s?" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:296 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:293 msgid "Delete Annotation?" msgstr "Удалить аннотацию?" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:453 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:526 msgid "Delete Database?" msgstr "Удалить базу данных?" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:605 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:751 msgid "Delete Dataset?" -msgstr "Удалить все?" +msgstr "Удалить датасет?" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:361 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:353 msgid "Delete Layer?" -msgstr "Удалить все?" +msgstr "Удалить слой?" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:485 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:261 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:489 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:243 msgid "Delete Query?" msgstr "Удалить запрос?" -#: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:110 -#, fuzzy +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:322 msgid "Delete Report?" -msgstr "Удалить шаблон?" +msgstr "Удалить рассылку?" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:321 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:323 msgid "Delete Template?" msgstr "Удалить шаблон?" -#: superset/views/base.py:595 +#: superset/views/base.py:659 msgid "Delete all Really?" -msgstr "Удалить все?" +msgstr "Действительно удалить все?" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:181 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:195 msgid "Delete annotation" msgstr "Удалить аннотацию" -#: superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx:202 +#: superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx:224 msgid "Delete dashboard tab?" msgstr "Удалить вкладку дашборда?" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:332 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:402 msgid "Delete database" -msgstr "Выберите базу данных" +msgstr "Удалить базу данных" -#: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:78 -#, fuzzy +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:219 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:257 msgid "Delete email report" -msgstr "Оповещения и рассылки" +msgstr "Удалить рассылку по email" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:404 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:405 msgid "Delete query" -msgstr "Удалить" +msgstr "Удалить запрос" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:239 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:236 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:219 msgid "Delete template" -msgstr "Загрузить шаблон" +msgstr "Удалить шаблон" #: superset-frontend/src/dashboard/components/MissingChart.jsx:36 msgid "Delete this container and save to remove this message." msgstr "Удалите этот контейнер и сохраните изменения, чтобы убрать это сообщение." -#: superset/annotation_layers/annotations/api.py:502 +#: superset/annotation_layers/annotations/api.py:504 #, python-format msgid "Deleted %(num)d annotation" msgid_plural "Deleted %(num)d annotations" -msgstr[0] "Удалено %(num)d аннотаций" +msgstr[0] "Удалалена %(num)d аннотация" +msgstr[1] "Удалалены %(num)d аннотации" +msgstr[2] "Удалалено %(num)d аннотаций" -#: superset/annotation_layers/api.py:353 +#: superset/annotation_layers/api.py:355 #, python-format msgid "Deleted %(num)d annotation layer" msgid_plural "Deleted %(num)d annotation layers" -msgstr[0] "Удалено слоёв аннотации: %(num)d" +msgstr[0] "Удалален %(num)d слой аннотаций" +msgstr[1] "Удалалены %(num)d слоя аннотаций" +msgstr[2] "Удалалено %(num)d слоев аннотаций" -#: superset/charts/api.py:480 +#: superset/charts/api.py:501 #, python-format msgid "Deleted %(num)d chart" msgid_plural "Deleted %(num)d charts" -msgstr[0] "Удалено %(num)d графиков" +msgstr[0] "Удален %(num)d график" +msgstr[1] "Удалены %(num)d графика" +msgstr[2] "Удалено %(num)d графиков" -#: superset/css_templates/api.py:137 +#: superset/css_templates/api.py:139 #, python-format msgid "Deleted %(num)d css template" msgid_plural "Deleted %(num)d css templates" -msgstr[0] "Удалено %(num)d шаблонов CSS" +msgstr[0] "Удален %(num)d CSS шаблон" +msgstr[1] "Удалены %(num)d CSS шаблона" +msgstr[2] "Удалено %(num)d CSS шаблонов" -#: superset/dashboards/api.py:674 +#: superset/dashboards/api.py:735 #, python-format msgid "Deleted %(num)d dashboard" msgid_plural "Deleted %(num)d dashboards" -msgstr[0] "Удалено %(num)d дашбордов" +msgstr[0] "Удален %(num)d дашборд" +msgstr[1] "Удалены %(num)d дашборда" +msgstr[2] "Удалено %(num)d дашбордов" -#: superset/datasets/api.py:666 +#: superset/datasets/api.py:780 #, python-format msgid "Deleted %(num)d dataset" msgid_plural "Deleted %(num)d datasets" -msgstr[0] "Удалено датасетов: %(num)d" +msgstr[0] "Удален %(num)d датасет" +msgstr[1] "Удалены %(num)d датасета" +msgstr[2] "Удалено %(num)d датасетов" -#: superset/reports/api.py:452 +#: superset/reports/api.py:502 #, python-format msgid "Deleted %(num)d report schedule" msgid_plural "Deleted %(num)d report schedules" -msgstr[0] "Удалено %(num)d рассылок" +msgstr[0] "Удалено %(num)d расписание рассылок" +msgstr[1] "Удалены %(num)d расписания рассылок" +msgstr[2] "Удалено %(num)d расписаний рассылок" -#: superset/queries/saved_queries/api.py:197 +#: superset/queries/saved_queries/api.py:213 #, python-format msgid "Deleted %(num)d saved query" msgid_plural "Deleted %(num)d saved queries" -msgstr[0] "Удалено %(num)d сохранённых запросов" +msgstr[0] "Удален %(num)d сохраненный запрос" +msgstr[1] "Удалены %(num)d сохраненных запроса" +msgstr[2] "Удалено %(num)d сохраненных запросов" -#: superset-frontend/src/reports/actions/reports.js:176 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:162 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:103 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:91 +#: superset-frontend/src/reports/actions/reports.js:156 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:184 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:117 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:90 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:93 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:142 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:546 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:232 -#: superset-frontend/src/views/CRUD/utils.tsx:246 -#: superset-frontend/src/views/CRUD/utils.tsx:285 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:158 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:675 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:233 +#: superset-frontend/src/views/CRUD/utils.tsx:268 +#: superset-frontend/src/views/CRUD/utils.tsx:307 #: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:172 #, python-format msgid "Deleted: %s" msgstr "Удалено: %s" +#: superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx:227 +msgid "" +"Deleting a tab will remove all content within it. You may still reverse " +"this action with the" +msgstr "" +"Удаление вкладки удалит все ее содержимое. Вы можете отменить это " +"действие при помощи сочетания клавиш" + #: superset-frontend/src/explore/components/controls/SpatialControl.jsx:184 msgid "Delimited long & lat single column" -msgstr "Широта и Долгота в одном столбце с разделителем" +msgstr "Долгота и широта в одном столбце" -#: superset/views/database/forms.py:132 +#: superset/views/database/forms.py:150 msgid "Delimiter" msgstr "Разделитель" -#: superset/views/database/forms.py:133 -msgid "Delimiter used by CSV file (for whitespace use \\s+)." -msgstr "Разделитель, используемый CSV-файлом (для пробелов используется \\s+)." - -#: superset/views/schedules.py:244 superset/views/schedules.py:324 -msgid "Deliver As Group" -msgstr "" - -#: superset/views/schedules.py:245 superset/views/schedules.py:325 -msgid "Delivery Type" -msgstr "Тип Подписи" - #: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:124 -#, fuzzy msgid "Delivery method" -msgstr "Добавить метод доставки" +msgstr "Способ оповещения" #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:33 msgid "Demographics" -msgstr "" +msgstr "Демография" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:43 #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:38 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:40 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:38 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:45 -#, fuzzy msgid "Density" -msgstr "Элемент" +msgstr "Концентрация" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/DependenciesRow.tsx:90 +msgid "Dependent on" +msgstr "Зависит от" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:55 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:38 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:40 msgid "Deprecated" -msgstr "Создано" +msgstr "Устарело" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:42 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:47 +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:83 +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:114 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:46 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:44 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:51 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:44 -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:131 -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:163 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:202 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:206 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:692 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1050 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1054 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:52 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:994 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:243 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1100 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1106 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:147 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:157 -#: superset/connectors/druid/views.py:188 -#: superset/connectors/druid/views.py:345 superset/connectors/sqla/views.py:145 -#: superset/connectors/sqla/views.py:256 superset/connectors/sqla/views.py:502 -#: superset/views/annotations.py:78 superset/views/annotations.py:126 -#: superset/views/chart/mixin.py:81 superset/views/sql_lab.py:71 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:158 +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:183 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:255 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:259 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:854 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1200 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1204 +#: superset-frontend/src/components/ReportModal/index.tsx:288 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:51 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1125 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:256 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:398 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:161 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:154 +#: superset/connectors/sqla/views.py:158 superset/connectors/sqla/views.py:252 +#: superset/connectors/sqla/views.py:363 superset/connectors/sqla/views.py:492 +#: superset/views/chart/mixin.py:81 superset/views/sql_lab/views.py:84 msgid "Description" msgstr "Описание" #: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:331 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:262 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:266 msgid "Description (this can be seen in the list)" msgstr "Описание (будет видно в списке)" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:520 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:568 msgid "Description Columns" -msgstr "описание" +msgstr "Описательные столбцы" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:48 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:49 msgid "Description text that shows up below your Big Number" -msgstr "" +msgstr "Описание, отображаемое под Карточкой" -#: superset-frontend/src/components/ListView/ListView.tsx:348 +#: superset-frontend/src/components/ListView/ListView.tsx:358 msgid "Deselect all" -msgstr "Выберите базу данных" +msgstr "Снять выделение" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:271 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1081 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:338 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1231 msgid "Details of the certification" -msgstr "Детали сертификации" +msgstr "Детали утверждения" -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:53 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:47 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:90 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:43 msgid "Determines how whiskers and outliers are calculated." -msgstr "" +msgstr "Определяет формулу расчета \"усов\" и выбросов." #: superset/views/dashboard/mixin.py:71 msgid "" "Determines whether or not this dashboard is visible in the list of all " "dashboards" -msgstr "Определяет видимость дашборда в списке всех дашбордов" +msgstr "Определяет, виден ли этот дашборд в списке всех дашбордов" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:230 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:231 msgid "Diamond" -msgstr "" +msgstr "Ромб" #: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:77 msgid "Did you mean:" -msgstr "" +msgstr "Возможно вы имели в виду:" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:101 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:141 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:94 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:333 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:215 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:485 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:65 +#: superset-frontend/src/explore/controlPanels/sections.tsx:211 msgid "Difference" -msgstr "Нажмите, чтобы увидеть разницу" +msgstr "Разница" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:46 +msgid "Dim Gray" +msgstr "Тускло-серый" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:116 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:110 +msgid "Dimension" +msgstr "Измерение" -#: superset/viz.py:1968 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/mixins.tsx:35 +msgid "Dimension to use on x-axis." +msgstr "Измерение для использования на оси X" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/mixins.tsx:34 +msgid "Dimension to use on y-axis." +msgstr "Измерение для использования на оси Y" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:67 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:165 +#: superset-frontend/src/explore/controls.jsx:123 +#: superset-frontend/src/explore/controls.jsx:380 +msgid "Dimensions" +msgstr "Измерения" + +#: superset/viz.py:2002 msgid "Directed Force Layout" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:34 #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:39 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:42 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:44 msgid "Directional" -msgstr "описание" +msgstr "Направленный" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:165 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:185 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:274 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:202 +msgid "Disable SQL Lab data preview queries" +msgstr "Отключить предпросмотр данных в Лаборатории SQL" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:205 +msgid "" +"Disable data preview when fetching table metadata in SQL Lab. Useful to " +"avoid browser performance issues when using databases with very wide " +"tables." +msgstr "" +"Отключить предварительный просмотр данных при извлечении метаданных " +"таблицы в SQL Lab. Полезно для избежания проблем с производительностью " +"браузера при использовании баз данных с очень широкими таблицами." + +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:98 +msgid "Disable embedding?" +msgstr "Выключить встраивание?" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:166 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:186 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:275 msgid "Disabled" -msgstr "Редактировать таблицу" +msgstr "Отключено" -#: superset-frontend/src/dashboard/components/Header/index.jsx:579 -msgid "Discard changes" +#: superset-frontend/src/dashboard/components/Header/index.jsx:598 +#: superset-frontend/src/dashboard/components/Header/index.jsx:600 +msgid "Discard" msgstr "Отменить изменения" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:43 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:49 msgid "Discrete" -msgstr "создан" +msgstr "Обособленный" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:149 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:42 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:194 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:57 msgid "Display Name" -msgstr "Значение фильтра" +msgstr "Отображаемое имя" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:164 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:229 msgid "Display column level total" -msgstr "" +msgstr "Отображать общий итог по столбцу" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:615 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:663 msgid "Display configuration" -msgstr "Как отображать" +msgstr "Настройки отображения" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:98 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:187 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:87 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:252 msgid "" "Display metrics side by side within each column, as opposed to each " "column being displayed side by side for each metric." msgstr "" +"Отображать меры рядом в каждом столбце, в отличие от отображения каждого " +"столбца рядом для каждой меры." -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:152 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:217 msgid "Display row level total" -msgstr "" +msgstr "Отображать общий итог по строке" + +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:38 +msgid "Display settings" +msgstr "Настройки отображения" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:89 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:78 msgid "Display total row/column" -msgstr "" +msgstr "Отобразить общую строку/столбец" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:34 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:35 msgid "" "Displays connections between entities in a graph structure. Useful for " "mapping relationships and showing which nodes are important in a network." @@ -4715,7 +5787,7 @@ msgid "" "your data has a geospatial component, try the deck.gl Arc chart." msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:132 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:169 #, fuzzy msgid "Distribute across" msgstr "Выполнить выбранный запрос" @@ -4724,341 +5796,392 @@ msgstr "Выполнить выбранный запрос" #: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:26 #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:48 #: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/createMetadata.ts:25 -#, fuzzy msgid "Distribution" -msgstr "Доля" +msgstr "Распределение" -#: superset/viz.py:1769 +#: superset/viz.py:1798 msgid "Distribution - Bar Chart" -msgstr "Distribution - Bar Chart" +msgstr "Распределение - Столбчатая диаграмма" #: superset-frontend/src/dashboard/components/gridComponents/new/NewDivider.jsx:31 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitlePane.tsx:57 msgid "Divider" msgstr "Разделитель" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:86 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:211 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:223 msgid "Do you want a donut or a pie?" -msgstr "" +msgstr "Круговая/кольцевая диаграмма" -#: superset-frontend/src/components/Menu/MenuRight.tsx:214 -#, fuzzy +#: superset-frontend/src/views/components/RightMenu.tsx:547 msgid "Documentation" -msgstr "аннотация" +msgstr "Документация" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:40 msgid "Domain" -msgstr "" - -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:29 -msgid "Don't refresh" -msgstr "Не обновлять" +msgstr "Блок" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:83 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:208 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:220 msgid "Donut" -msgstr "месяц" +msgstr "Кольцевая диаграмма" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:675 +msgid "Dotted" +msgstr "Пунктир" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:319 -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:328 -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:105 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:508 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:292 +msgid "Download" +msgstr "Сохранить" + +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:323 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:532 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:329 msgid "Download as image" msgstr "Сохранить как изображение" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:543 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:261 msgid "Download to CSV" -msgstr "" +msgstr "Сохранить в CSV" #: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:72 #: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:83 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:301 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:499 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:316 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:530 msgid "Draft" msgstr "Черновик" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:214 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:152 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:113 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:93 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:110 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:168 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:171 +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:194 +msgid "Drag and drop components and charts to the dashboard" +msgstr "Переместите элементы оформления и графики на дашборд" + +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:217 +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:185 +msgid "Drag and drop components to this tab" +msgstr "Переместите элементы оформления и графики в эту вкладку" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:216 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:141 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:128 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:70 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:70 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:125 msgid "Draw a marker on data points. Only applicable for line types." -msgstr "" +msgstr "Отобразить маркеры на данных. Применимо только для линий." -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:171 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:135 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:138 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:173 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:95 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:92 msgid "Draw area under curves. Only applicable for line types." -msgstr "" +msgstr "Отобразить область под кривыми. Применимо только для линий\"" #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:178 msgid "Draw line from Pie to label when labels outside?" +msgstr "Проводит линию от диаграммы к метке, когда метки находятся снаружи" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:216 +msgid "Draw split lines for minor axis ticks" +msgstr "Рисует разделительные линии для небольших отметок оси" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:347 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:235 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:222 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:166 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:166 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:219 +msgid "Draw split lines for minor y-axis ticks" +msgstr "Рисует разделительные линии для небольших отметок оси Y" + +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx:142 +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx:157 +msgid "Drill to detail" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:331 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:246 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:209 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:189 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:206 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:262 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:265 -msgid "Draw split lines for minor y-axis ticks" +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx:166 +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx:179 +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx:198 +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx:229 +msgid "Drill to detail by" msgstr "" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:217 -msgid "Drop a column here or click" +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx:168 +msgid "Drill to detail by value is not yet supported for this chart type." msgstr "" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:367 -msgid "Drop a column/metric here or click" +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx:144 +msgid "" +"Drill to detail is disabled because this chart does not group data by " +"dimension value." msgstr "" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:222 -msgid "Drop column here" +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailModal.tsx:99 +#, python-format +msgid "Drill to detail: %s" msgstr "" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:372 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:206 +msgid "Drop a column here or click" +msgid_plural "Drop columns here or click" +msgstr[0] "Перетащите столбец сюда" +msgstr[1] "Перетащите столбцы сюда" +msgstr[2] "Перетащите столбцы сюда" + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:335 +msgid "Drop a column/metric here or click" +msgid_plural "Drop columns/metrics here or click" +msgstr[0] "Перетащите столбец/меру сюда" +msgstr[1] "Перетащите столбцы/меры сюда" +msgstr[2] "Перетащите столбцы/меры сюда" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:248 +msgid "Drop a temporal column here or click" +msgstr "Перетащите столбец формата дата/время сюда" + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:216 +msgid "Drop column here" +msgid_plural "Drop columns here" +msgstr[0] "Перетащите столбец сюда" +msgstr[1] "Перетащите столбцы сюда" +msgstr[2] "Перетащите столбцы сюда" + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:340 msgid "Drop column or metric here" -msgstr "" +msgid_plural "Drop columns or metrics here" +msgstr[0] "Перетащите столбец или меру сюда" +msgstr[1] "Перетащите столбцы или меры сюда" +msgstr[2] "Перетащите столбцы или меры сюда" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx:80 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx:83 msgid "Drop columns here" -msgstr "" +msgstr "Перетащите столбцы сюда" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx:389 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx:417 msgid "Drop columns or metrics here" -msgstr "%s столбец(ы) и показатель(и)" +msgstr "Перетащите столбцы или меры сюда" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx:388 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx:416 msgid "Drop columns/metrics here or click" -msgstr "" +msgstr "Перетащите столбцы/меры сюда" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:176 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:247 msgid "Drop temporal column here" -msgstr "" - -#: superset/connectors/druid/views.py:213 -#: superset/initialization/__init__.py:516 -msgid "Druid Clusters" -msgstr "Список Кластеров Druid" - -#: superset/connectors/druid/views.py:192 -msgid "Druid Datasource" -msgstr "Druid - Источники Данных" - -#: superset/connectors/druid/views.py:277 -#: superset/initialization/__init__.py:507 -msgid "Druid Datasources" -msgstr "Источники Данных Druid" - -#: superset/connectors/druid/views.py:248 -#: superset/connectors/druid/views.py:253 -msgid "" -"Druid supports basic authentication. See " -"[auth](http://druid.io/docs/latest/design/auth.html) and druid-basic-" -"security extension" -msgstr "" -"Druid поддерживает обычную аутентификацию. См. [эту " -"страницу](http://druid.io/docs/latest/design/auth.html) и расширения для " -"druid-basic-security" +msgstr "Перетащите столбец формата дата/время сюда" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:30 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:32 #, fuzzy msgid "Dual Line Chart" msgstr "Bullet Chart" -#: superset/views/datasource/views.py:119 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:476 +#: superset-frontend/src/views/CRUD/data/dataset/DuplicateDatasetModal.tsx:64 +msgid "Duplicate" +msgstr "Дублировать" + +#: superset/views/datasource/views.py:122 #, python-format msgid "Duplicate column name(s): %(columns)s" -msgstr "" +msgstr "Повторяющееся имя столбца(ов): %(columns)s" -#: superset/common/query_object.py:284 +#: superset/common/query_object.py:291 #, python-format msgid "" "Duplicate column/metric labels: %(labels)s. Please make sure all columns " "and metrics have a unique label." msgstr "" +"Повторяющиеся метки столбцов/мер: %(labels)s. Пожалуйста, убедитесь, что " +"все столбцы и меры имеют уникальную метку." -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:366 +#: superset-frontend/src/views/CRUD/data/dataset/DuplicateDatasetModal.tsx:61 +msgid "Duplicate dataset" +msgstr "Дублировать датасет" + +#: superset-frontend/src/SqlLab/components/SqlEditorTabHeader/index.tsx:143 msgid "Duplicate tab" msgstr "Дублировать вкладку" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:135 +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:138 msgid "Duration" msgstr "Продолжительность" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:227 -#: superset/views/database/mixins.py:175 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:239 +#: superset/views/database/mixins.py:172 msgid "" "Duration (in seconds) of the caching timeout for charts of this database." " A timeout of 0 indicates that the cache never expires. Note this " "defaults to the global timeout if undefined." msgstr "" +"Продолжительность (в секундах) таймаута кэша для графиков этой базы " +"данных. Таймаут 0 означает, что кэш никогда не очистится. Обратите " +"внимание, что если значение не задано, применяется значение по умолчанию " +"из основной конфигурации." -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:282 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:295 msgid "" "Duration (in seconds) of the caching timeout for this chart. Note this " "defaults to the dataset's timeout if undefined." -msgstr "Продолжительность (в секундах) таймаута кэширования для этого графика." +msgstr "" +"Продолжительность (в секундах) таймаута кэша для этого графикаОбратите " +"внимание, что если значение не задано, применяется значение таймаута " +"датасета." #: superset/views/chart/mixin.py:70 msgid "" "Duration (in seconds) of the caching timeout for this chart. Note this " "defaults to the datasource/table timeout if undefined." -msgstr "Продолжительность (в секундах) таймаута кэширования для этого графика." +msgstr "" +"Продолжительность (в секундах) таймаута кэша для этого графикаОбратите " +"внимание, что если значение не задано, применяется значение источника " +"данных/таблицы." -#: superset/connectors/druid/views.py:243 -msgid "" -"Duration (in seconds) of the caching timeout for this cluster. A timeout " -"of 0 indicates that the cache never expires. Note this defaults to the " -"global timeout if undefined." -msgstr "" -"Тайм-аут кеша (в секундах) для этого кластера. Тайм-аут 0 означает, что " -"кеш не может быть просрочен." - -#: superset/connectors/druid/views.py:334 -msgid "" -"Duration (in seconds) of the caching timeout for this datasource. A " -"timeout of 0 indicates that the cache never expires. Note this defaults " -"to the cluster timeout if undefined." -msgstr "" -"Тайм-аут (в секундах) кеша для этого источника данных. Тайм-аут 0 " -"означает, что кеш не может быть просрочен." - -#: superset/connectors/sqla/views.py:473 +#: superset/connectors/sqla/views.py:463 msgid "" "Duration (in seconds) of the caching timeout for this table. A timeout of" " 0 indicates that the cache never expires. Note this defaults to the " "database timeout if undefined." msgstr "" +"Продолжительность (в секундах) таймаута кэша для этой таблицы. Обратите " +"внимание, что если значение не задано, применяется значение базы данных." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:250 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:261 msgid "" "Duration (in seconds) of the metadata caching timeout for schemas of this" " database. If left unset, the cache never expires." msgstr "" -"Тайм-аут (в секундах) кеша для этого источника данных. Тайм-аут 0 " -"означает, что кеш не может быть просрочен." +"Продолжительность (в секундах) таймаута кэша для схем этой базы данных. " +"Обратите внимание, что если значение не задано, кэш никогда не очистится." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:272 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:282 msgid "" "Duration (in seconds) of the metadata caching timeout for tables of this " "database. If left unset, the cache never expires. " msgstr "" -"Тайм-аут (в секундах) кеша для этого источника данных. Тайм-аут 0 " -"означает, что кеш не может быть просрочен." +"Продолжительность (в секундах) таймаута кэша для таблиц этой базы данных." +" Обратите внимание, что если значение не задано, кэш никогда не " +"очистится." -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:41 +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:43 msgid "Duration in ms (1.40008 => 1ms 400µs 80ns)" -msgstr "" +msgstr "Продолжительность в мс (1.40008 => 1ms 400µs 80ns)" + +#: superset-frontend/src/explore/controls.jsx:90 +msgid "Duration in ms (100.40008 => 100ms 400µs 80ns)" +msgstr "Продолжительность в мс (100.40008 => 100ms 400µs 80ns)" -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:40 +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:42 +#: superset-frontend/src/explore/controls.jsx:89 msgid "Duration in ms (66000 => 1m 6s)" -msgstr "" +msgstr "Продолжительность в мс (66000 => 1m 6s)" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:205 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:223 #, python-format msgid "Duration: %s" msgstr "Продолжительность: %s" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:66 +msgid "Dynamic Aggregation Function" +msgstr "Динамическая агрегирующая функция" + +#: superset-frontend/src/filters/components/Select/controlPanel.ts:136 +msgid "Dynamically search all filter values" +msgstr "Динамически искать все значения фильтра" + #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:55 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:47 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:43 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:71 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:57 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:50 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:45 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:79 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:61 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:77 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:77 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:71 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:71 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:62 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:64 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:74 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:78 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:78 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:69 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:42 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:61 -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:124 -#, fuzzy +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:130 msgid "ECharts" -msgstr "график" +msgstr "Графики Apache" + +#: superset/reports/notifications/email.py:131 +#, fuzzy +msgid "EMAIL_REPORTS_CTA" +msgstr "Включить рассылки" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:76 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:169 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:176 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:182 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:189 msgid "END (EXCLUSIVE)" -msgstr "" +msgstr "КОНЕЦ (НЕ ВКЛЮЧИТЕЛЬНО)" + +#: superset-frontend/packages/superset-ui-core/src/chart/components/SuperChartCore.tsx:171 +msgid "ERROR" +msgstr "ОШИБКА" -#: superset-frontend/src/views/CRUD/hooks.ts:628 +#: superset-frontend/src/views/CRUD/hooks.ts:656 #, python-format msgid "ERROR: %s" -msgstr "" +msgstr "ОШИБКА: %s" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:241 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:242 msgid "Edge length" -msgstr "" +msgstr "Длина ребер" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:247 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:248 msgid "Edge length between nodes" -msgstr "" +msgstr "Длина ребер между вершинами" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:124 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:125 msgid "Edge symbols" -msgstr "" +msgstr "Оформление ребер" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:226 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:227 msgid "Edge width" -msgstr "Толщина линии" +msgstr "Толщина ребра" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:197 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:211 #: superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.tsx:35 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:75 -#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:121 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:316 -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:128 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:404 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:85 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:401 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:358 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:389 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:219 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:83 +#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:144 +#: superset-frontend/src/pages/ChartList/ChartCard.tsx:131 +#: superset-frontend/src/pages/ChartList/index.tsx:523 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:386 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:84 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:416 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:428 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:456 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:201 msgid "Edit" msgstr "Редактировать" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1053 -#, fuzzy +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:392 msgid "Edit Alert" -msgstr "Редактировать таблицу" - -#: superset/views/annotations.py:61 -msgid "Edit Annotation" -msgstr "Аннотации" - -#: superset/views/annotations.py:120 -msgid "Edit Annotation Layer" -msgstr "Добавить слой аннотации" +msgstr "Редактировать оповещение" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:309 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:285 msgid "Edit CSS" msgstr "Редактировать CSS" -#: superset/views/css_templates.py:39 +#: superset/views/css_templates.py:41 msgid "Edit CSS Template" -msgstr "Шаблоны CSS" +msgstr "Редактировать CSS шаблон" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:231 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:229 msgid "Edit CSS template properties" -msgstr "Редактирование свойств" +msgstr "Редактировать свойств CSS шаблона" #: superset/views/chart/mixin.py:29 msgid "Edit Chart" msgstr "Редактировать график" -#: superset/connectors/sqla/views.py:66 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:190 +msgid "Edit Chart Properties" +msgstr "Редактировать свойства графика" + +#: superset/connectors/sqla/views.py:76 msgid "Edit Column" msgstr "Редактировать столбец" @@ -5070,535 +6193,618 @@ msgstr "Редактировать дашборд" msgid "Edit Database" msgstr "Редактировать Базу Данных" -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:192 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:195 msgid "Edit Dataset " msgstr "Редактировать датасет " -#: superset/connectors/druid/views.py:216 -msgid "Edit Druid Cluster" -msgstr "Редактировать кластер Druid" - -#: superset/connectors/druid/views.py:73 -msgid "Edit Druid Column" -msgstr "Редактировать столбец Druid" - -#: superset/connectors/druid/views.py:280 -msgid "Edit Druid Datasource" -msgstr "Редактировать источник данных Druid" - -#: superset/connectors/druid/views.py:162 -msgid "Edit Druid Metric" -msgstr "Редактировать Druid Метрику" - -#: superset-frontend/src/components/ReportModal/index.tsx:251 -msgid "Edit Email Report" -msgstr "" - #: superset/views/log/__init__.py:24 msgid "Edit Log" -msgstr "Редактировать" +msgstr "Редактировать запись" -#: superset/connectors/sqla/views.py:215 +#: superset/connectors/sqla/views.py:211 msgid "Edit Metric" -msgstr "Редактировать показатель" +msgstr "Редактировать меру" #: superset/views/dynamic_plugins.py:61 msgid "Edit Plugin" msgstr "Редактировать плагин" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1051 -#, fuzzy +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:391 msgid "Edit Report" -msgstr "рассылка" +msgstr "Редактировать отчет" -#: superset/connectors/sqla/views.py:317 +#: superset/connectors/sqla/views.py:294 +#, fuzzy msgid "Edit Row level security filter" -msgstr "Править фильтр на уровне строк" +msgstr "Безопасность на уровне строк" -#: superset/views/sql_lab.py:42 +#: superset/views/sql_lab/views.py:55 msgid "Edit Saved Query" -msgstr "Изменить сохраненный запрос" +msgstr "Редактировать сохраненный запрос" -#: superset/connectors/sqla/views.py:398 +#: superset/connectors/sqla/views.py:388 msgid "Edit Table" msgstr "Редактировать таблицу" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:174 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:283 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:188 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:282 msgid "Edit annotation" msgstr "Редактировать аннотацию" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:170 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:184 msgid "Edit annotation layer" msgstr "Редактировать слой аннотации" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:237 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:241 msgid "Edit annotation layer properties" msgstr "Редактировать свойства слоя аннотаций" -#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:305 -#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:308 +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailModal.tsx:44 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:216 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:422 +msgid "Edit chart" +msgstr "Редактировать график" + +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:278 msgid "Edit chart properties" -msgstr "Редактирование свойств" +msgstr "Редактировать свойства графика" -#: superset-frontend/src/dashboard/components/Header/index.jsx:605 -#, fuzzy +#: superset-frontend/src/dashboard/components/Header/index.jsx:632 +#: superset-frontend/src/dashboard/components/Header/index.jsx:634 msgid "Edit dashboard" msgstr "Редактировать дашборд" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:302 -msgid "Edit dashboard properties" -msgstr "Редактировать свойства дашборда" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1011 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1511 msgid "Edit database" msgstr "Редактировать Базу Данных" -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:192 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:288 msgid "Edit dataset" msgstr "Редактировать датасет" -#: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:73 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:216 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:251 +#: superset-frontend/src/components/ReportModal/index.tsx:206 msgid "Edit email report" -msgstr "" +msgstr "Редактировать рассылку" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:151 #, fuzzy msgid "Edit formatter" msgstr "Формат D3" -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:80 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:279 msgid "Edit properties" -msgstr "Редактирование свойств" +msgstr "Редактировать свойства" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:383 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:384 msgid "Edit query" msgstr "Редактировать запрос" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:230 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:227 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:210 msgid "Edit template" -msgstr "Загрузить шаблон" +msgstr "Редактировать шаблон" -#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:99 +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:104 msgid "Edit template parameters" -msgstr "Изменить параметры шаблона" +msgstr "Редактировать параметры шаблонизации Jinja" + +#: superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx:717 +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:242 +msgid "Edit the dashboard" +msgstr "Редактировать дашборд" -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:353 +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:346 msgid "Edit time range" -msgstr "Изменить параметры шаблона" +msgstr "Изменить временной интервал" -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:161 +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:153 msgid "Edited" msgstr "Редактировано" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:484 +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:747 msgid "Editing 1 filter:" -msgstr "" +msgstr "Редактирование 1 фильтра:" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:119 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:118 msgid "Editing filter set:" -msgstr "" +msgstr "Редактирование набора фильтров:" -#: superset/errors.py:110 +#: superset/errors.py:116 msgid "Either the database is spelled incorrectly or does not exist." -msgstr "" +msgstr "Неверное или несуществующее имя базы данных." -#: superset/db_engine_specs/mysql.py:124 superset/db_engine_specs/presto.py:195 -#: superset/db_engine_specs/redshift.py:63 +#: superset/db_engine_specs/mysql.py:148 superset/db_engine_specs/presto.py:627 +#: superset/db_engine_specs/redshift.py:67 #, python-format msgid "Either the username \"%(username)s\" or the password is incorrect." -msgstr "" +msgstr "Неверное имя пользователя \"%(username)s\" или пароль." -#: superset/db_engine_specs/mssql.py:74 +#: superset/db_engine_specs/mssql.py:85 #, python-format msgid "" "Either the username \"%(username)s\", password, or database name " "\"%(database)s\" is incorrect." msgstr "" +"Неверное имя пользователя \"%(username)s\", пароль или имя базы данных " +"\"%(database)s\"." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:114 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:118 -msgid "Either the username or password is incorrect." -msgstr "" - -#: superset/errors.py:109 +#: superset/errors.py:115 msgid "Either the username or the password is wrong." -msgstr "" +msgstr "Неверное имя пользователя или пароль" -#: superset/views/schedules.py:326 -msgid "Email Format" -msgstr "Формат значения" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:88 +#, fuzzy +msgid "Elevation" +msgstr "Продолжительность" -#: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:64 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:212 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:241 msgid "Email reports active" -msgstr "" +msgstr "Включить рассылки" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:47 -#, fuzzy -msgid "Emit Target" -msgstr "Редактировать датасет" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:244 +msgid "Embed" +msgstr "Встроить" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx:30 -#, fuzzy -msgid "Emit dashboard cross filters" -msgstr "Редактировать свойства дашборда" +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:349 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:351 +msgid "Embed code" +msgstr "Встроенный код" + +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:350 +msgid "Embed dashboard" +msgstr "Встроить дашборд" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx:33 +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:108 +msgid "Embedding deactivated." +msgstr "Встраивание отключено" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:163 #, fuzzy -msgid "Emit dashboard cross filters." -msgstr "Редактировать свойства дашборда" +msgid "Emit Filter Events" +msgstr "Фильтрующийся" -#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:95 +#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:179 msgid "Emitted values" -msgstr "" +msgstr "Отображаемые значения" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:191 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:192 msgid "Emphasis" -msgstr "" +msgstr "Акцент" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:36 msgid "Employment and education" -msgstr "" +msgstr "Трудоустройство и образование" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:214 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:215 msgid "Empty circle" -msgstr "" +msgstr "Пустой круг" #: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:59 -#, fuzzy msgid "Empty collection" -msgstr "Тестовое соединение" +msgstr "Пустая коллекция" + +#: superset-frontend/src/dashboard/components/gridComponents/Column.jsx:220 +#, fuzzy +msgid "Empty column" +msgstr "Показывать пустые столбцы" -#: superset/connectors/sqla/models.py:1068 +#: superset/charts/data/api.py:362 +msgid "Empty query result" +msgstr "Пустой ответ запроса" + +#: superset/connectors/sqla/models.py:1225 superset/models/helpers.py:1418 msgid "Empty query?" msgstr "Пустой запрос?" -#: superset/connectors/druid/views.py:348 superset/connectors/sqla/views.py:493 +#: superset-frontend/src/dashboard/components/gridComponents/Row.jsx:250 +msgid "Empty row" +msgstr "" + +#: superset-frontend/src/views/components/RightMenu.tsx:305 +#: superset-frontend/src/views/components/SubMenu.tsx:304 +msgid "Enable 'Allow file uploads to database' in any database's settings" +msgstr "" +"Включите \"Разрешить загрузку файлов в базу данных\" в настройках любой " +"базы данных" + +#: superset/connectors/sqla/views.py:483 +#, fuzzy msgid "Enable Filter Select" -msgstr "Включить выбор фильтра" - -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:293 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:184 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:145 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:125 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:142 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:200 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:203 +msgstr "Настроить области действия фильтра" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx:139 +#, fuzzy +msgid "Enable cross-filtering" +msgstr "Задать область действия кросс-фильтра" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:309 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:173 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:313 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:160 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:102 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:102 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:157 msgid "Enable data zooming controls" -msgstr "" +msgstr "Включить элементы управления масштабированием данных" + +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:232 +msgid "Enable embedding" +msgstr "Разрешить встраивание" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:44 msgid "Enable forecast" -msgstr "" +msgstr "Включить прогноз в график" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:47 msgid "Enable forecasting" -msgstr "" +msgstr "Включить прогнозирование данных" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:161 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:270 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:162 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:271 msgid "Enable graph roaming" -msgstr "" +msgstr "Включить перемещение по графику" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:141 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:142 msgid "Enable node dragging" -msgstr "" +msgstr "Разрешить перемещение вершин" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:176 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:170 msgid "Enable query cost estimation" -msgstr "" +msgstr "Разрешить оценку стоимости запроса" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:290 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/pagination.tsx:36 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:299 msgid "Enable server side pagination of results (experimental feature)" -msgstr "" +msgstr "Включить серверную пагинацию результатов (экспериментально)" -#: superset/viz.py:2530 +#: superset/viz.py:2564 msgid "" "Encountered invalid NULL spatial entry," " please consider filtering those " "out" msgstr "" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:164 -#: superset/views/annotations.py:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:75 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:178 msgid "End" msgstr "Конец" -#: superset/views/sql_lab.py:73 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/Arc.jsx:44 +msgid "End (Longitude, Latitude): " +msgstr "Конец (Долгота, Широта)" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:64 +msgid "End Longitude & Latitude" +msgstr "Конечные Долгота и Широта" + +#: superset/views/sql_lab/views.py:86 msgid "End Time" msgstr "Время окончания" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:120 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:116 msgid "End angle" -msgstr "Период времени" +msgstr "Конечный угол" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:78 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:171 +#: superset-frontend/src/components/ListView/Filters/DateRange.tsx:67 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:307 #, fuzzy +msgid "End date" +msgstr "Отправить текстом" + +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:78 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:184 msgid "End date excluded from time range" -msgstr "Изменить параметры шаблона" +msgstr "Конечная дата исключена из временного интервала" #: superset/annotation_layers/annotations/commands/exceptions.py:35 msgid "End date must be after start date" -msgstr "Невозможно выбрать дату [from], которая позже текущего дня" +msgstr "Конечная дата должна быть после начальной" -#: superset/databases/commands/validate.py:71 +#: superset/databases/commands/validate.py:59 #, python-format msgid "Engine \"%(engine)s\" cannot be configured through parameters." -msgstr "" - -#: superset/databases/commands/validate.py:59 superset/databases/schemas.py:308 -#, python-format -msgid "Engine \"%(engine)s\" is not a valid engine." -msgstr "" +msgstr "Не удается настроить драйвер \"%(engine)s\" при данных параметрах." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:459 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:464 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:476 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:480 msgid "Engine Parameters" -msgstr "Параметры шаблона" +msgstr "Параметры драйвера" -#: superset/databases/schemas.py:272 +#: superset/databases/schemas.py:293 msgid "" "Engine spec \"InvalidEngine\" does not support being configured via " "individual parameters." msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:356 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:366 msgid "Enter CA_BUNDLE" -msgstr "" +msgstr "Введите CA_BUNDLE" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:55 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:98 +msgid "Enter Primary Credentials" +msgstr "Введите основные учетные данные" + +#: superset/views/database/forms.py:151 +msgid "Enter a delimiter for this data" +msgstr "Введите разделитель этих данных" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:54 msgid "Enter a name for this sheet" -msgstr "Введите название для таблицы" +msgstr "Введите название для этого листа" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:238 +#: superset-frontend/src/SqlLab/components/SqlEditorTabHeader/index.tsx:82 msgid "Enter a new title for the tab" -msgstr "Введите название для таблицы" +msgstr "Введите новое название для вкладки" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:222 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:244 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:266 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:234 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:255 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:276 msgid "Enter duration in seconds" -msgstr "Время в секундах" +msgstr "Введите время в секундах" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:327 -#, fuzzy +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:271 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:384 msgid "Enter fullscreen" msgstr "Полноэкранный режим" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:73 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:397 -#: superset-frontend/src/explore/controls.jsx:412 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:141 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:184 +#, python-format +msgid "Enter the required %(dbModelName)s credentials" +msgstr "Введите обязательные данные для %(dbModelName)s" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:128 +#: superset-frontend/src/explore/controls.jsx:392 msgid "Entity" msgstr "Элемент" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:125 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:124 msgid "Entity ID" -msgstr "Элемент" +msgstr "ID элемента" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:216 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:209 msgid "Equal Date Sizes" +msgstr "Одинаковые размеры дат" + +#: superset-frontend/src/explore/constants.ts:59 +msgid "Equal to (=)" msgstr "" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:56 -#, fuzzy, python-format +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:136 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:120 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:279 +#: superset-frontend/src/explore/components/EmbedCodeContent.jsx:57 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:72 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:65 msgid "Error" -msgstr "%s Ошибка" - -#: superset/views/alerts.py:83 -msgid "Error Message" -msgstr "Предупреждающее сообщение" +msgstr "Ошибка" -#: superset/connectors/sqla/models.py:1349 +#: superset/connectors/sqla/models.py:1623 superset/models/helpers.py:1828 #, python-format msgid "Error in jinja expression in HAVING clause: %(msg)s" -msgstr "" +msgstr "Ошибка в jinja выражении в операторе HAVING: %(msg)s" -#: superset/connectors/sqla/models.py:976 +#: superset/connectors/sqla/models.py:1129 #, python-format msgid "Error in jinja expression in RLS filters: %(msg)s" -msgstr "" +msgstr "Ошибка в jinja выражении в RLS фильтрах: %(msg)s" -#: superset/connectors/sqla/models.py:1337 +#: superset/connectors/sqla/models.py:1606 superset/models/helpers.py:1816 #, python-format msgid "Error in jinja expression in WHERE clause: %(msg)s" -msgstr "" +msgstr "Ошибка в jinja выражении в операторе WHERE: %(msg)s" -#: superset/connectors/sqla/models.py:735 +#: superset/connectors/sqla/models.py:824 #, python-format msgid "Error in jinja expression in fetch values predicate: %(msg)s" -msgstr "" +msgstr "Ошибка в jinja выражении в предикате выборки значений: %(msg)s" -#: superset-frontend/src/dashboard/containers/DashboardPage.tsx:190 +#: superset-frontend/src/dashboard/containers/DashboardPage.tsx:356 msgid "Error loading chart datasources. Filters may not work correctly." msgstr "" +"Ошибка загрузки источников данных для графиков. Фильтры могут работать " +"некорректно." -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:144 +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:147 msgid "Error message" msgstr "Сообщение об ошибке" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:46 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:104 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:139 -#, fuzzy msgid "Error while fetching charts" -msgstr "Возникла ошибка при получение данных" +msgstr "Возникла ошибка при получении графиков" #: superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx:89 -#, fuzzy, python-format +#, python-format msgid "Error while fetching data: %s" -msgstr "Возникла ошибка при получение данных" +msgstr "Возникла ошибка при получении данных: %s" -#: superset/connectors/sqla/models.py:842 -#, fuzzy, python-format +#: superset/connectors/sqla/models.py:944 superset/models/helpers.py:1014 +#, python-format msgid "Error while rendering virtual dataset query: %(msg)s" -msgstr "Ошибка при сохранении датасета: %s" +msgstr "Произошла ошибка при выполнении запроса виртуального датасета: %(msg)s" + +#: superset/charts/data/commands/get_data_command.py:55 +#, python-format +msgid "Error: %(error)s" +msgstr "Ошибка: %(error)s" + +#: superset/views/core.py:818 superset/views/core.py:1897 +#, python-format +msgid "Error: %(msg)s" +msgstr "Ошибка: %(msg)s" + +#: superset/views/core.py:815 +msgid "Error: permalink state not found" +msgstr "" -#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:91 +#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:100 msgid "Estimate cost" -msgstr "Выполнить выбранный запрос" +msgstr "Оценить стоимость запроса" -#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:90 +#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:99 msgid "Estimate selected query cost" -msgstr "Выполнить выбранный запрос" +msgstr "Оценить стоимость выбранного запроса" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:648 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:599 msgid "Estimate the cost before running a query" -msgstr "Спрогнозировать время до выполнения запроса" +msgstr "Спрогнозировать стоимость до выполнения запроса" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/AnnotationTypes.js:37 +#: superset-frontend/src/modules/AnnotationTypes.js:36 +msgid "Event" +msgstr "Событие" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:29 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:31 #, fuzzy msgid "Event Flow" msgstr "Event flow" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:43 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:44 msgid "Event Names" -msgstr "Полное имя" +msgstr "Имена событий" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:35 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:36 msgid "Event definition" -msgstr "" +msgstr "Определение события" -#: superset/viz.py:2896 +#: superset/viz.py:2930 +#, fuzzy msgid "Event flow" msgstr "Event flow" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:478 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:526 msgid "Event time column" -msgstr "Столбец с временем" +msgstr "Столбец формата дата/время" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:43 msgid "Every" -msgstr "" +msgstr "Каждый(ая)" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:30 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:29 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:25 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:26 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:26 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:30 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:26 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:25 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:56 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:59 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:58 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:57 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:57 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:48 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:57 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:58 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:54 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:60 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:59 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:58 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:58 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:49 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:48 msgid "Evolution" -msgstr "" +msgstr "Динамика" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1263 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1105 msgid "Exact" -msgstr "След" +msgstr "Точное" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:34 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:49 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:67 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:81 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:95 -#, fuzzy msgid "Example" -msgstr "Примеры" - -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:92 -#, python-format -msgid "Example %(tableName)s will appear here" -msgstr "" +msgstr "Пример" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:759 -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:180 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:178 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:853 +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:214 msgid "Examples" msgstr "Примеры" -#: superset/views/database/forms.py:252 +#: superset/views/database/forms.py:278 msgid "Excel File" -msgstr "Файл Excel" +msgstr "Excel Файл" -#: superset/views/database/views.py:398 +#: superset/views/database/views.py:424 #, python-format msgid "" "Excel file \"%(excel_filename)s\" uploaded to table \"%(table_name)s\" in" " database \"%(db_name)s\"" msgstr "" -"Excel-файл “%(excel_filename)s\" загружен в таблицу \"%(table_name)s\" " -"базы данных \"%(db_name)s\"" +"Excel файл \"%(excel_filename)s\" загружен в таблицу \"%(table_name)s\" в" +" базе данных \"%(db_name)s\"" -#: superset/views/database/views.py:268 +#: superset/views/database/views.py:303 msgid "Excel to Database configuration" -msgstr "Настройка CSV для БД" +msgstr "Конфигурация Excel файла для импорта в базу данных" -#: superset-frontend/src/filters/components/Select/controlPanel.ts:126 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:125 msgid "Exclude selected values" -msgstr "" +msgstr "Исключить выбранные значения" #: superset-frontend/src/SqlLab/components/HighlightedSql/index.tsx:82 -#, fuzzy msgid "Executed SQL" -msgstr "Выполнить выбранный запрос" +msgstr "Исполненный SQL" -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:162 +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:164 msgid "Executed query" -msgstr "Выполнить выбранный запрос" +msgstr "Выполненный запрос" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:105 -#, fuzzy +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:108 msgid "Execution ID" -msgstr "Журнал Действий" +msgstr "ID исполнения" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:307 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:377 msgid "Execution log" msgstr "Журнал Действий" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:326 -#, fuzzy +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:411 +msgid "Existing dataset" +msgstr "Существующий датасет" + +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:270 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:383 msgid "Exit fullscreen" -msgstr "Полноэкранный режим" +msgstr "Выйти из полноэкранного режима" + +#: superset-frontend/plugins/plugin-chart-echarts/src/constants.ts:83 +msgid "Expand" +msgstr "Расширить" #: superset-frontend/src/dashboard/components/filterscope/treeIcons.jsx:36 msgid "Expand all" -msgstr "Развернуть всё" +msgstr "Расширить все" -#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:152 -#, fuzzy +#: superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:167 +msgid "Expand data panel" +msgstr "Расширить панель данных" + +#: superset-frontend/src/components/Table/index.tsx:267 +msgid "Expand row" +msgstr "Развернуть строку" + +#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx:198 msgid "Expand table preview" -msgstr "Убрать предпросмотр таблицы" +msgstr "Расширить предпросмотр таблицы" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:351 +#: superset-frontend/src/SqlLab/components/SqlEditorTabHeader/index.tsx:123 msgid "Expand tool bar" msgstr "Показать панель инструментов" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:72 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:443 +msgid "" +"Expects a formula with depending time parameter 'x'\n" +" in milliseconds since epoch. mathjs is used to evaluate the " +"formulas.\n" +" Example: '2x+5'" +msgstr "" +"Формула с зависимой переменной 'x' в милисекундах с 1970 года " +"(Unix-время). Для рассчета используется mathjs. Например: '2x+5'" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:38 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:37 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:80 #: superset-frontend/src/filters/components/GroupBy/index.ts:31 #: superset-frontend/src/filters/components/Range/index.ts:31 #: superset-frontend/src/filters/components/Select/index.ts:32 @@ -5606,139 +6812,152 @@ msgstr "Показать панель инструментов" #: superset-frontend/src/filters/components/TimeColumn/index.ts:31 #: superset-frontend/src/filters/components/TimeGrain/index.ts:31 msgid "Experimental" -msgstr "" +msgstr "Экспериментальный" -#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.jsx:98 -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:168 -#: superset/views/core.py:883 +#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx:91 +#: superset/views/core.py:985 msgid "Explore" -msgstr "Обзор графика" +msgstr "Исследовать" -#: superset/views/core.py:881 +#: superset/views/core.py:983 #, python-format msgid "Explore - %(table)s" msgstr "Исследовать - %(table)s" -#: superset/reports/notifications/email.py:91 -msgid "Explore in Superset" -msgstr "" - -#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.jsx:91 -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:161 +#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx:84 +#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx:41 msgid "Explore the result set in the data exploration view" -msgstr "Исследовать набор данных" - -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:116 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:388 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:661 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:98 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:385 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:630 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:342 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:373 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:636 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:516 -#: superset/views/dashboard/views.py:67 +msgstr "Создать новый график на основе этих данных" + +#: superset-frontend/src/pages/ChartList/ChartCard.tsx:119 +#: superset-frontend/src/pages/ChartList/index.tsx:507 +#: superset-frontend/src/pages/ChartList/index.tsx:813 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:97 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:400 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:669 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:412 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:438 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:787 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:520 +#: superset/views/dashboard/views.py:65 msgid "Export" -msgstr "Экспорт" +msgstr "Экспортировать" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:333 -msgid "Export CSV" -msgstr "Экпспорт CSV" - -#: superset/views/dashboard/views.py:67 +#: superset/views/dashboard/views.py:65 msgid "Export dashboards?" -msgstr "Экспортировать дашборд?" - -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:341 -msgid "Export full CSV" -msgstr "" +msgstr "Экспортировать дашборды?" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:397 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:398 msgid "Export query" -msgstr "Скопировать запрос" +msgstr "Экспорт запроса" -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:202 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:210 -#, fuzzy -msgid "Export to .CSV format" -msgstr "Экспортировать в CSV формат" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:513 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:316 +msgid "Export to .CSV" +msgstr "Экспорт в .CSV" + +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:323 +msgid "Export to .JSON" +msgstr "Экспорт в .JSON" -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:182 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:335 #, fuzzy -msgid "Export to .JSON format" -msgstr "Экспортировать в CSV формат" +msgid "Export to Excel" +msgstr "Экспорт в YAML" -#: superset/views/base.py:538 +#: superset/views/base.py:602 msgid "Export to YAML" msgstr "Экспорт в YAML" -#: superset/views/base.py:538 +#: superset/views/base.py:602 msgid "Export to YAML?" -msgstr "Экспорт в YAML?" +msgstr "Экспортировать в YAML?" + +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:524 +msgid "Export to full .CSV" +msgstr "Экспорт в целый .CSV" + +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:300 +msgid "Export to original .CSV" +msgstr "Экспорт исходных данных в .CSV" + +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:307 +msgid "Export to pivoted .CSV" +msgstr "Экспорт сводной таблицы в .CSV" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:76 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:88 msgid "Expose database in SQL Lab" -msgstr "" +msgstr "Предоставить доступ к базе в Лаборатории SQL" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:281 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:387 -#: superset/views/database/mixins.py:186 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:351 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:457 +#: superset/views/database/mixins.py:183 msgid "Expose in SQL Lab" -msgstr "Открыть в SQL редакторе" +msgstr "Доступен в SQL редакторе" -#: superset/views/database/mixins.py:104 +#: superset/views/database/mixins.py:103 msgid "Expose this DB in SQL Lab" -msgstr "Показать базу данных в SQL Редакторе" +msgstr "Предоставить доступ к базе в Лаборатории SQL" -#: superset/connectors/sqla/views.py:149 +#: superset/connectors/sqla/views.py:162 msgid "Expression" -msgstr "Выражение SQL" +msgstr "Выражение" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:735 -#: superset/connectors/sqla/views.py:262 superset/connectors/sqla/views.py:505 -#: superset/views/database/mixins.py:196 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:902 +#: superset/connectors/sqla/views.py:258 superset/connectors/sqla/views.py:495 +#: superset/views/database/mixins.py:193 msgid "Extra" msgstr "Дополнительные параметры" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:160 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:167 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:122 msgid "Extra Controls" -msgstr "" +msgstr "Дополнительные элементы управления" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:87 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:99 msgid "Extra Parameters" -msgstr "Параметры шаблона" +msgstr "Доп. параметры" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:736 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:121 +msgid "Extra data for JS" +msgstr "Доп. данные для JS" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:903 msgid "" "Extra data to specify table metadata. Currently supports metadata of the " "format: `{ \"certification\": { \"certified_by\": \"Data Platform Team\"," " \"details\": \"This table is the source of truth.\" }, " "\"warning_markdown\": \"This is a warning.\" }`." msgstr "" +"Дополнительные метаданные таблицы. В настоящий момент поддерживается " +"следующий формат: `{ \"certification\": { \"certified_by\": " +"\"Руководитель отдела\", \"details\": \"Эта таблица - источник правды.\" " +"}, \"warning_markdown\": \"Это предупреждение.\" }`." -#: superset/views/database/mixins.py:244 superset/views/database/mixins.py:268 +#: superset/views/database/mixins.py:240 superset/views/database/mixins.py:264 #, python-format msgid "Extra field cannot be decoded by JSON. %(msg)s" -msgstr "" +msgstr "Дополнительное поле не может быть декодировано с помощью JSON. %(msg)s" -#: superset-frontend/src/explore/controlPanels/sections.tsx:62 +#: superset-frontend/src/explore/controlPanels/sections.tsx:52 msgid "Extra parameters for use in jinja templated queries" -msgstr "Дополнительные параметры для запросов, использующих шаблоны jinja" +msgstr "Дополнительные параметры для запросов, использующих шаблонизацию Jinja" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:89 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:101 msgid "" "Extra parameters that any plugins can choose to set for use in Jinja " "templated queries" -msgstr "Дополнительные параметры для запросов, использующих шаблоны jinja" +msgstr "" +"Дополнительные параметры для шаблонизации Jinja, которые могут быть " +"использованы в графиках" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:78 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:90 msgid "Extra url parameters for use in Jinja templated queries" -msgstr "Дополнительные параметры для запросов, использующих шаблоны jinja" +msgstr "Дополнительные url параметры для запросов, использующих шаблонизацию Jinja" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:270 +msgid "Extruded" +msgstr "" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:92 msgid "FEB" @@ -5748,45 +6967,73 @@ msgstr "ФЕВ" msgid "FRI" msgstr "ПТ" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:115 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:108 msgid "Factor" -msgstr "Октябрь" +msgstr "" -#: superset/views/database/forms.py:145 superset/views/database/forms.py:298 -#: superset/views/database/forms.py:426 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:337 +msgid "Factor to multiply the metric by" +msgstr "Число, на которое умножается мера" + +#: superset/views/database/forms.py:167 superset/views/database/forms.py:324 +#: superset/views/database/forms.py:455 msgid "Fail" msgstr "Ошибка" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:69 -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:75 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:153 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:120 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:126 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:168 msgid "Failed" msgstr "Ошибка" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:194 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:305 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:208 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:324 msgid "Failed at retrieving results" msgstr "Невозможно выполнить запрос" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:409 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:470 #, python-format msgid "Failed at stopping query. %s" +msgstr "Не удалось остановить запрос. %s" + +#: superset-frontend/src/components/ReportModal/index.tsx:337 +msgid "Failed to create report" +msgstr "Не удалось создать рассылку" + +#: superset/sqllab/exceptions.py:66 +#, python-format +msgid "Failed to execute %(query)s" msgstr "" -#: superset/errors.py:137 superset/sqllab/sql_json_executer.py:194 +#: superset-frontend/src/explore/ExplorePage.tsx:57 +msgid "Failed to load chart data" +msgstr "Не удалось загрузить данные графика" + +#: superset-frontend/src/explore/ExplorePage.tsx:69 +msgid "Failed to load chart data." +msgstr "Не удалось загрузить данные графика." + +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/useAdvancedDataTypes.ts:70 +msgid "Failed to retrieve advanced type" +msgstr "Не удалось получить расширенный тип" + +#: superset/errors.py:143 superset/sqllab/sql_json_executer.py:190 msgid "Failed to start remote query on a worker." -msgstr "" +msgstr "Не удалось запустить удаленный запрос на сервере." + +#: superset-frontend/src/components/ReportModal/index.tsx:336 +msgid "Failed to update report" +msgstr "Не удалось обновить отчет" #: superset-frontend/src/explore/components/controls/withAsyncVerification.tsx:201 #, python-format msgid "Failed to verify select options: %s" -msgstr "Ошибка при проверке опций выбора: %s" +msgstr "Ошибка при проверке вариантов выбора: %s" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:436 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:433 -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:162 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:159 +#: superset-frontend/src/pages/ChartList/index.tsx:560 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:453 +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:145 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:151 msgid "Favorite" msgstr "Избранное" @@ -5798,180 +7045,195 @@ msgstr "Избранное" msgid "February" msgstr "Февраль" -#: superset/connectors/druid/views.py:353 -msgid "Fetch Values From" -msgstr "Извлечь значения из" - -#: superset/connectors/sqla/views.py:499 +#: superset/connectors/sqla/views.py:489 msgid "Fetch Values Predicate" -msgstr "Извлечь Значения Предиката" +msgstr "" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:788 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:535 msgid "Fetch data preview" msgstr "Получить данные для просмотра" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:244 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:369 #, python-format msgid "Fetched %s" -msgstr "" +msgstr "Получено %s" + +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:138 +msgid "Fetching" +msgstr "Получение данных" -#: superset/databases/commands/exceptions.py:62 +#: superset/databases/commands/exceptions.py:63 #, python-format msgid "Field cannot be decoded by JSON. %(json_error)s" -msgstr "" +msgstr "поле не может быть декодировано с помощью JSON. %(json_error)s" -#: superset/databases/schemas.py:183 superset/databases/schemas.py:198 +#: superset/databases/schemas.py:194 superset/databases/schemas.py:209 #, python-format msgid "Field cannot be decoded by JSON. %(msg)s" -msgstr "" +msgstr "Поле не может быть декодировано с помощью JSON. %(msg)s" #: superset/databases/commands/exceptions.py:50 +#: superset/databases/ssh_tunnel/commands/exceptions.py:57 msgid "Field is required" -msgstr "Поле обязательно" +msgstr "Поле обязательно к заполнению" #: superset/templates/superset/import_dashboards.html:37 msgid "File" msgstr "Файл" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:982 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:221 +msgid "Fill Color" +msgstr "Цвет заливки" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1231 msgid "Fill all required fields to enable \"Default Value\"" -msgstr "" +msgstr "Установить все требуемые флаги для включения \"Значения по умолчанию\"" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:166 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:181 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:255 msgid "Fill method" -msgstr "Добавить слой аннотации" +msgstr "Метод заполнения пропусков" -#: superset-frontend/src/components/ListView/Filters/Select.tsx:77 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:248 +msgid "Filled" +msgstr "С заливкой" + +#: superset-frontend/src/components/ListView/Filters/Select.tsx:93 +#: superset-frontend/src/components/ListView/Filters/Select.tsx:106 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitlePane.tsx:56 msgid "Filter" -msgstr "Фильтры" +msgstr "Фильтр" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:288 +msgid "Filter Configuration" +msgstr "Конфигурация фильтра" #: superset/templates/appbuilder/general/widgets/search.html:24 msgid "Filter List" -msgstr "Фильтры" +msgstr "Список фильтров" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:787 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:292 +msgid "Filter Settings" +msgstr "Настройки фильтра" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:770 msgid "Filter Type" -msgstr "Значение фильтра" +msgstr "Тип фильтра" -#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:26 +#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:28 msgid "Filter box" -msgstr "Фильтр" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "Выберите базу данных" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "Значение фильтра" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "Значение фильтра" +msgstr "Фильтр-виджет" -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:281 msgid "Filter configuration" -msgstr "Фильтруемые срезы" +msgstr "Настройки фильтра" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:66 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:36 msgid "Filter configuration for the filter box" -msgstr "Настройки фильтра" +msgstr "Настройки фильтра для \"Фильтр-виджета\"" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:895 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1139 msgid "Filter has default value" -msgstr "" +msgstr "Фильтр имеет значение по умолчанию" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1010 -msgid "Filter is hierarchical" -msgstr "" +#: superset-frontend/src/components/Table/index.tsx:255 +#, fuzzy +msgid "Filter menu" +msgstr "Имя фильтра" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:109 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:113 msgid "Filter metadata changed in dashboard. It will not be applied." -msgstr "" +msgstr "Метаданные фильтра изменились в дашборде. Они не будут применены." -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:777 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:760 msgid "Filter name" -msgstr "Значение фильтра" +msgstr "Имя фильтра" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/DependenciesRow.tsx:92 +msgid "Filter only displays values relevant to selections made in other filters." +msgstr "" +"Фильтр предлагает только те значения, которые отобраны выбранными " +"фильтрами" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:563 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:286 msgid "Filter results" -msgstr "Результаты поиска" +msgstr "Фильтровать результаты" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:144 -#, fuzzy, python-format +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:143 msgid "Filter set already exists" -msgstr "Источник данных %(name)s уже существует" +msgstr "Набор фильтров уже существует" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:143 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:142 #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:83 -#, fuzzy msgid "Filter set with this name already exists" -msgstr "Источник данных %(name)s уже существует" +msgstr "Набор фильтров с этим именем уже существует" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:348 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx:269 #, python-format msgid "Filter sets (%(filterSetCount)d)" -msgstr "" +msgstr "Наборы фильтров (%(filterSetCount)d)" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:791 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/TypeRow.tsx:31 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:774 msgid "Filter type" -msgstr "Значение фильтра" +msgstr "Тип фильтра" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:417 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:530 msgid "Filter value (case sensitive)" msgstr "Фильтровать значения (зависит от регистра)" -#: superset/connectors/sqla/models.py:1278 +#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:72 +#: superset-frontend/src/filters/components/Range/controlPanel.ts:55 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:90 +#: superset-frontend/src/filters/components/Time/controlPanel.ts:53 +#: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:33 +#: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:33 +msgid "Filter value is required" +msgstr "Требуется значение фильтра" + +#: superset/connectors/sqla/models.py:1522 superset/models/helpers.py:1739 msgid "Filter value list cannot be empty" -msgstr "" +msgstr "Список для фильтрации не может быть пуст" -#: superset-frontend/src/dashboard/components/SliceAdder.jsx:245 +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:311 msgid "Filter your charts" -msgstr "Фильтровать графики" +msgstr "Поиск" -#: superset/connectors/druid/views.py:95 superset/connectors/sqla/views.py:147 +#: superset/connectors/sqla/views.py:160 msgid "Filterable" msgstr "Фильтруемый" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:82 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:459 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:103 -#: superset-frontend/src/explore/controls.jsx:466 superset/viz.py:2105 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:139 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:109 +#: superset-frontend/src/explore/controls.jsx:446 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:35 +#: superset/viz.py:2139 msgid "Filters" msgstr "Фильтры" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:84 -#, fuzzy, python-format +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:88 +#, python-format msgid "Filters (%d)" -msgstr "Сбросить фильтры (%d)" +msgstr "Фильтры (%d)" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:134 msgid "Filters by columns" -msgstr "Фильтруемые срезы" +msgstr "Фильтры по столбцам" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:136 msgid "Filters by metrics" -msgstr "Список показателей" +msgstr "Фильтры по мерам" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:57 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:27 msgid "Filters configuration" -msgstr "Изменение настроек таблицы" - -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx:467 -#, fuzzy -msgid "Filters configuration and scoping" -msgstr "Фильтруемые срезы" +msgstr "Конфигурация фильтров" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx:159 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersOutOfScopeCollapsible/index.tsx:83 #, python-format msgid "Filters out of scope (%d)" -msgstr "" +msgstr "Фильтры вне рамок дашборда (%d)" -#: superset/connectors/sqla/views.py:348 +#: superset/connectors/sqla/views.py:343 msgid "" "Filters with the same group key will be ORed together within the group, " "while different filter groups will be ANDed together. Undefined group " @@ -5983,172 +7245,256 @@ msgid "" " 'Europe')." msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:794 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:808 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1193 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1015 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1063 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1701 msgid "Finish" -msgstr "" +msgstr "Завершить" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:124 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:189 +msgid "First" +msgstr "Первый" + +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:116 msgid "" "Fix the trend line to the full time range specified in case filtered " "results do not include the start or end dates" msgstr "" +"Фиксирует линию тренда в полном временном интервале, указанном в случае, " +"если отфильтрованные результаты не включают даты начала или окончания" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:123 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:115 msgid "Fix to selected Time Range" -msgstr "Особый временной интервал" +msgstr "Выбрать временной интервал" #: superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx:149 -#, fuzzy msgid "Fixed" -msgstr "Изменено" +msgstr "Фиксированный" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:175 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:129 msgid "Fixed Color" msgstr "Фиксированный цвет" -#: superset-frontend/src/explore/controls.jsx:206 +#: superset-frontend/src/explore/controls.jsx:205 msgid "Fixed color" msgstr "Фиксированный цвет" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:322 +msgid "Fixed point radius" +msgstr "Фиксированный радиус" + #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:26 -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:24 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:25 #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:27 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:32 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:33 msgid "Flow" -msgstr "" +msgstr "Поток" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:133 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:129 msgid "Font size" -msgstr "" +msgstr "Размер шрифта" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:134 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:130 msgid "Font size for axis labels, detail value and other text elements" msgstr "" +"Размер шрифта для меток осей, значений деталей и других текстовых " +"элементов" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:71 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:75 msgid "Font size for the biggest value in the list" -msgstr "" +msgstr "Размер шрифта для наибольшего значения в списке" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:60 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:64 msgid "Font size for the smallest value in the list" +msgstr "Размер шрифта для наименьшего значения в списке" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:173 +msgid "" +"For Bigquery, Presto and Postgres, shows a button to compute cost before " +"running a query." msgstr "" +"Для Bigquery, Presto и Postgres, показывать кнопку подсчета стоимости " +"запроса перед его выполнением." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 -#, fuzzy +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:183 +msgid "For further instructions, consult the" +msgstr "Для получения дальнейших инструкций обратитесь к" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:45 msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " -"query." -msgstr "Спрогнозировать время до выполнения запроса" +"For more information about objects are in context in the scope of this " +"function, refer to the" +msgstr "" -#: superset/connectors/sqla/views.py:342 +#: superset/connectors/sqla/views.py:337 msgid "" "For regular filters, these are the roles this filter will be applied to. " "For base filters, these are the roles that the filter DOES NOT apply to, " "e.g. Admin if admin should see all data." msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:111 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:112 msgid "Force" -msgstr "Источник" +msgstr "Силовой алгоритм" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:129 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:141 msgid "" "Force all tables and views to be created in this schema when clicking " "CTAS or CVAS in SQL Lab." msgstr "" +"Принудить создание новых таблиц через CTAS или CVAS в Лаборатории SQL в " +"этой схеме при нажатии соответствующих кнопок" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:270 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:157 +msgid "Force date format" +msgstr "Принудительный перевод к формату дата/время" + +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:398 msgid "Force refresh" -msgstr "Принудительное обновление" +msgstr "Обновить" -#: superset-frontend/src/components/DatabaseSelector/index.tsx:287 +#: superset-frontend/src/components/DatabaseSelector/index.tsx:313 msgid "Force refresh schema list" -msgstr "Принудительное обновление данных" +msgstr "Принудительно обновить список схем" -#: superset-frontend/src/components/TableSelector/index.tsx:317 +#: superset-frontend/src/components/TableSelector/index.tsx:340 msgid "Force refresh table list" -msgstr "Принудительное обновление данных" - -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/index.js:27 -msgid "Force-directed Graph" -msgstr "" +msgstr "Принудительно обновить список таблиц" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:56 -#, fuzzy msgid "Forecast periods" -msgstr "Период" +msgstr "Кол-во прогнозных периодов" + +#: superset-frontend/src/SqlLab/components/ColumnElement/index.tsx:64 +msgid "Foreign key" +msgstr "Внешний ключ" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:48 +msgid "Forest Green" +msgstr "Лесной зеленый" + +#: superset/explore/commands/get.py:87 superset/views/core.py:832 +msgid "Form data not found in cache, reverting to chart metadata." +msgstr "Данные формы не найдены в кэше, возвращение к метаданным графика." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:37 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:42 +#: superset/explore/commands/get.py:95 superset/views/core.py:838 +msgid "Form data not found in cache, reverting to dataset metadata." +msgstr "Данные формы не найдены в кэше, возвращение к метаданным датасета." + +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:39 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:45 -#, fuzzy msgid "Formattable" -msgstr "Ключевые поля таблицы" +msgstr "Форматируемый" -#: superset-frontend/src/components/ReportModal/index.tsx:296 +#: superset-frontend/src/components/ReportModal/index.tsx:249 msgid "Formatted CSV attached in email" -msgstr "" +msgstr "Форматированный CSV, прикрепленный к письму" + +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:142 +msgid "Formatted date" +msgstr "Форматированная дата" + +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.tsx:137 +msgid "Formatted value" +msgstr "Форматированное значение" + +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.tsx:133 +msgid "Formatting" +msgstr "Форматирование" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/AnnotationTypes.js:33 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:442 +#: superset-frontend/src/modules/AnnotationTypes.js:32 +msgid "Formula" +msgstr "Формула" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:187 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:261 +msgid "Forward values" +msgstr "Будущие значения" #: superset-frontend/packages/superset-ui-core/src/query/extractQueryFields.ts:130 msgid "Found invalid orderby options" msgstr "" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:80 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:69 msgid "Fraction digits" -msgstr "" +msgstr "Десятичные знаки" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:53 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:54 msgid "Frequency" msgstr "Частота" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:304 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:305 msgid "Friction" -msgstr "Действия" +msgstr "Трение" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:310 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:311 msgid "Friction between nodes" -msgstr "" +msgstr "Сила трения между вершинами" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:61 msgid "Friday" msgstr "Пятница" -#: superset/utils/date_parser.py:264 superset/viz.py:370 +#: superset/utils/date_parser.py:267 superset/viz.py:390 msgid "From date cannot be larger than to date" -msgstr "Невозможно выбрать дату [from], которая позже текущего дня" +msgstr "Дата начала не может быть позже даты конца" -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:52 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:44 +msgid "Full name" +msgstr "Полное имя" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:54 msgid "Funnel Chart" -msgstr "Переместить график" +msgstr "Воронка" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:454 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:479 msgid "Further customize how to display each column" -msgstr "" +msgstr "Дальнейшая настройка отображения каждого столбца" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:168 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:167 msgid "Further customize how to display each metric" -msgstr "" +msgstr "Дальнейшая настройка отображения каждой меры" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:42 -#, fuzzy +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:38 +msgid "GROUP BY" +msgstr "GROUP BY" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:45 msgid "Gauge Chart" -msgstr "Сохранить график" +msgstr "Индикаторная диаграмма" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:78 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:76 msgid "General" -msgstr "" +msgstr "Основные свойства" + +#: superset-frontend/src/explore/components/EmbedCodeContent.jsx:82 +msgid "Generating link, please wait.." +msgstr "Генерация ссылки, пожалуйста, ждите..." -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:34 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:64 +msgid "Generic Chart" +msgstr "Общая диаграмма" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:37 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:37 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:38 msgid "Geo" -msgstr "" +msgstr "Карта" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:390 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx:36 +msgid "GeoJson Column" +msgstr "Столбец GeoJson" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts:68 +msgid "GeoJson Settings" +msgstr "Настройки GeoJson" #: superset-frontend/src/explore/components/controls/SpatialControl.jsx:203 msgid "Geohash" @@ -6162,30 +7508,54 @@ msgstr "" msgid "Get the specify date for the holiday" msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:47 +#: superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx:713 +msgid "Go to the edit mode to configure the dashboard and add charts" +msgstr "Перейдите в режим редактирования для изменения дашборда и добавьте графики" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:45 +msgid "Gold" +msgstr "Золотой" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:46 msgid "Google Sheet Name and URL" -msgstr "" +msgstr "Имя или URL Google Таблицы" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1275 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:415 msgid "Grace period" -msgstr "Период" +msgstr "Перерыв между оповещением" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:37 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:39 msgid "Graph Chart" -msgstr "Сохранить график" +msgstr "Сетевой график" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:108 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:109 msgid "Graph layout" -msgstr "" +msgstr "Формат сетевого графика" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:262 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:263 msgid "Gravity" -msgstr "" +msgstr "Гравитация" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:299 -#: superset-frontend/src/filters/components/GroupBy/index.ts:28 +#: superset-frontend/src/explore/constants.ts:68 +#, fuzzy +msgid "Greater or equal (>=)" +msgstr ">= (больше или равно)" + +#: superset-frontend/src/explore/constants.ts:66 #, fuzzy +msgid "Greater than (>)" +msgstr "Агрегированное среднее" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:61 +msgid "Grid" +msgstr "Сетка" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:281 +msgid "Grid Size" +msgstr "Размер сетки" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:320 +#: superset-frontend/src/filters/components/GroupBy/index.ts:28 msgid "Group By" msgstr "Группировать по" @@ -6193,72 +7563,107 @@ msgstr "Группировать по" msgid "Group By filter plugin" msgstr "" -#: superset/viz.py:895 +#: superset/viz.py:924 msgid "Group By' and 'Columns' can't overlap" -msgstr "Нельзя использовать один и тот же срез в двух полях" +msgstr "Измерения и Столбцы не могут повторяться" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:83 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/shared.ts:59 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:84 msgid "Group By, Metrics or Percentage Metrics must have a value" -msgstr "" +msgstr "Измерения, Меры или Процентные меры должны иметь значение" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:31 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:99 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:42 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:299 -#: superset-frontend/src/explore/controls.jsx:123 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:320 msgid "Group by" msgstr "Группировать по" -#: superset/connectors/druid/views.py:94 superset/connectors/sqla/views.py:146 +#: superset/connectors/sqla/views.py:159 msgid "Groupable" msgstr "Группируемый" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:238 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/index.ts:41 +msgid "Handlebars" +msgstr "Handlebars" + +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/handlebarTemplate.tsx:60 +msgid "Handlebars Template" +msgstr "Шаблон Handlebars" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:252 msgid "" "Hard value bounds applied for color coding. Is only relevant and applied " "when the normalization is applied against the whole heatmap." msgstr "" +#: superset/charts/filters.py:104 superset/dashboards/filters.py:242 +msgid "Has created by" +msgstr "Создан(а)" + #: superset-frontend/src/dashboard/components/gridComponents/new/NewHeader.jsx:31 msgid "Header" -msgstr "Строка заголовков" +msgstr "Заголовок" -#: superset/views/database/forms.py:152 superset/views/database/forms.py:305 +#: superset/views/database/forms.py:244 superset/views/database/forms.py:331 msgid "Header Row" -msgstr "Строка заголовков" +msgstr "Строка заголовка" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:38 -#: superset/viz.py:2212 +#: superset/viz.py:2246 msgid "Heatmap" -msgstr "Heatmap" +msgstr "Тепловая карта" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:104 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:105 msgid "Heatmap Options" -msgstr "" +msgstr "Настройки тепловой карты" -#: superset-frontend/src/explore/components/EmbedCodeButton.jsx:116 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/Grid.jsx:39 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts:75 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/Hex.jsx:38 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:239 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:245 msgid "Height" msgstr "Высота" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:730 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:240 +msgid "Height of the sparkline" +msgstr "Высота спарклайна" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:734 +msgid "Hide Line" +msgstr "Скрыть линию" + +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:411 +msgid "Hide chart description" +msgstr "Скрыть описание графика" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:780 msgid "Hide layer" msgstr "Скрыть слой" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:351 +#: superset-frontend/src/components/Form/LabeledErrorBoundInput.tsx:136 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:196 +msgid "Hide password." +msgstr "Скрыть пароль." + +#: superset-frontend/src/SqlLab/components/SqlEditorTabHeader/index.tsx:123 msgid "Hide tool bar" msgstr "Скрыть панель инструментов" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:81 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:735 +msgid "Hides the Line for the time series" +msgstr "" + +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:96 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:193 msgid "Hierarchy" -msgstr "Поиск" +msgstr "Иерархия" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:37 -#: superset/viz.py:1711 +#: superset/viz.py:1740 msgid "Histogram" -msgstr "Histogram" +msgstr "Гистограмма" -#: superset/initialization/__init__.py:222 +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:345 +#: superset/initialization/__init__.py:229 msgid "Home" msgstr "Главная" @@ -6267,54 +7672,61 @@ msgstr "Главная" msgid "Horizon Chart" msgstr "Horizon Charts" -#: superset/viz.py:2273 +#: superset/viz.py:2307 +#, fuzzy msgid "Horizon Charts" msgstr "Horizon Charts" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:106 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:280 +msgid "Horizontal" +msgstr "Горизонтально" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx:166 +msgid "Horizontal (Top)" +msgstr "Горизонтально (сверху)" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:95 msgid "Horizontal alignment" -msgstr "" +msgstr "Выравнивание по горизонтали" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:47 msgid "Host" -msgstr "" +msgstr "Хост" -#: superset/db_engine_specs/base.py:1390 +#: superset/db_engine_specs/base.py:1735 msgid "Hostname or IP address" -msgstr "" +msgstr "Имя хоста или IP адрес" -#: superset/db_engine_specs/base.py:94 -#, fuzzy +#: superset/db_engine_specs/base.py:108 msgid "Hour" -msgstr "час" +msgstr "Час" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:65 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:64 +#, python-format msgid "Hours %s" -msgstr "час" +msgstr "Часов %s" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:779 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:947 msgid "Hours offset" -msgstr "Смещение часов" +msgstr "Смещение времени" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:94 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:93 msgid "How do you want to enter service account credentials?" msgstr "" -#: superset/views/alerts.py:190 -msgid "How long to keep the logs around for this alert" -msgstr "Как долго хранить логи для данного оповещения" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:139 +msgid "How many buckets should the data be grouped in." +msgstr "" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:59 msgid "How many periods into the future do we want to predict" -msgstr "" +msgstr "На сколько периодов в будущем предсказывать" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:129 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:342 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:225 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:477 -#: superset-frontend/src/explore/controlPanels/sections.tsx:240 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:145 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:337 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:219 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:489 +#: superset-frontend/src/explore/controlPanels/sections.tsx:215 msgid "" "How to display time shifts: as individual lines; as the difference " "between the main time series and each time shift; as the percentage " @@ -6324,30 +7736,28 @@ msgstr "" "разницу между основным временным рядом и каждым смещением; как процентное" " изменение; или как соотношение между рядами и смещениями." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:51 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:51 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:85 msgid "Huge" -msgstr "" +msgstr "Огромный" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:78 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:79 msgid "ISO 3166-2 Codes" -msgstr "" +msgstr "Коды ISO 3166-2" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:237 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:304 msgid "ISO 8601" msgstr "ISO 8601" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:50 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:51 msgid "Id" -msgstr "идентификатор:" +msgstr "ID" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:86 msgid "Id of root node of the tree." -msgstr "" +msgstr "Id корневой вершины дерева." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:400 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:391 msgid "" "If Presto or Trino, all the queries in SQL Lab are going to be executed " "as the currently logged on user who must have permission to run them. If " @@ -6355,13 +7765,14 @@ msgid "" "service account, but impersonate the currently logged on user via " "hive.server2.proxy.user property." msgstr "" -"Если вы используете Presto, все запросы в SQL-Редакторе будут выполняться" -" от авторизованного пользователя, который должен иметь разрешение на их " -"выполнение. <br/> Если включен Hive, то запросы будут выполняться через " -"техническую учетную запись, но ассоциировать зарегистрированного " -"пользователя можно через свойство hive.server2.proxy.user." +"Если вы используете Presto или Trino, все запросы в Лаборатории SQL будут" +" выполняться от авторизованного пользователя, который должен иметь " +"разрешение на их выполнение. Если включены Hive и " +"hive.server2.enable.doAs, то запросы будут выполняться через техническую " +"учетную запись, но имперсонировать зарегистрированного пользователя можно" +" через свойство hive.server2.proxy.user." -#: superset/views/database/mixins.py:163 +#: superset/views/database/mixins.py:165 msgid "" "If Presto, all the queries in SQL Lab are going to be executed as the " "currently logged on user who must have permission to run them.<br/>If " @@ -6369,270 +7780,273 @@ msgid "" "service account, but impersonate the currently logged on user via " "hive.server2.proxy.user property." msgstr "" -"Если вы используете Presto, все запросы в SQL-Редакторе будут выполняться" -" от авторизованного пользователя, который должен иметь разрешение на их " -"выполнение. <br/> Если включен Hive, то запросы будут выполняться через " -"техническую учетную запись, но ассоциировать зарегистрированного " -"пользователя можно через свойство hive.server2.proxy.user." +"Если вы используете Presto, все запросы в Лаборатории SQL будут " +"выполняться от авторизованного пользователя, который должен иметь " +"разрешение на их выполнение. <br/> Если включены Hive и " +"hive.server2.enable.doAs, то запросы будут выполняться через техническую " +"учетную запись, но имперсонировать зарегистрированного пользователя можно" +" через свойство hive.server2.proxy.user." + +#: superset/views/database/forms.py:164 +msgid "If Table Already Exists" +msgstr "Если таблица уже существует" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1201 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1043 msgid "If a metric is specified, sorting will be done based on the metric value" -msgstr "" +msgstr "Если мера задана, сортировка будет произведена на основании значений меры" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:121 -msgid "If activated you can use the " +#: superset/views/database/forms.py:238 +msgid "" +"If duplicate columns are not overridden, they will be presented as \"X.1," +" X.2 ...X.x\"" msgstr "" +"Если повторяющиеся столбцы не перезаписываются, они будут представлены в " +"формате \"X.0, X.1\"." -#: superset/views/database/mixins.py:180 +#: superset/views/database/mixins.py:177 msgid "If selected, please set the schemas allowed for csv upload in Extra." msgstr "" -"Если включено, выберите схему, в которую разрешено загружать CSV на " -"вкладке “Дополнительно”." +"Если установлено, выберите схемы, в которые разрешена загрузка CSV на " +"вкладке \"Дополнительно\"." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:420 -msgid "If selected, please set the schemas allowed for data upload in Extra." -msgstr "" -"Если установлено, выберите схемы, в которые разрешена загрузка на вкладке" -" “Дополнительно”." - -#: superset/views/database/forms.py:139 superset/views/database/forms.py:292 -#: superset/views/database/forms.py:420 +#: superset/views/database/forms.py:318 superset/views/database/forms.py:449 msgid "" "If table exists do one of the following: Fail (do nothing), Replace (drop" " and recreate table) or Append (insert data)." msgstr "" -"Если таблица уже существует, выполните одно из следующих действий: Fail " -"(ничего не делать), Replace (удалить и заново создать таблицу) или Append" -" (добавить данные)." +"Если таблица уже существует, выберите действие: Ошибка (ничего не " +"делать), Заменить (удалить и воссоздать таблицу) или Добавить (вставить " +"данные)." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:48 -msgid "" -"If you wish to specify a different target column than the original " -"column, it can be entered here" -msgstr "" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:422 +msgid "Ignore cache when generating screenshot" +msgstr "Игнорировать кэш при создании скриншота" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:83 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:87 +msgid "Ignore null locations" +msgstr "Игнорировать пустые локации" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:76 msgid "Ignore time" -msgstr "" +msgstr "Игнорировать время" -#: superset-frontend/src/components/ReportModal/index.tsx:293 +#: superset-frontend/src/components/ReportModal/index.tsx:246 msgid "Image (PNG) embedded in email" -msgstr "" +msgstr "Изображение (PNG), встроенное в email" -#: superset-frontend/src/utils/downloadAsImage.ts:63 +#: superset-frontend/src/utils/downloadAsImage.ts:55 msgid "Image download failed, please refresh and try again." -msgstr "" +msgstr "Ошибка скачивания изображения, пожалуйста, обновите и попробуйте заново." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:395 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:386 msgid "Impersonate logged in user (Presto, Trino, Drill, Hive, and GSheets)" -msgstr "Ассоциировать пользователя" +msgstr "" +"Имперсонировать пользователя (Presto, Trino, Drill, Hive, и Google " +"Таблицы)" -#: superset/views/database/mixins.py:200 +#: superset/views/database/mixins.py:197 msgid "Impersonate the logged on user" -msgstr "Ассоциировать пользователя" +msgstr "Имперсонировать пользователя" -#: superset-frontend/src/components/ImportModal/index.tsx:282 +#: superset-frontend/src/components/ImportModal/index.tsx:281 msgid "Import" msgstr "Импорт" -#: superset-frontend/src/components/ImportModal/index.tsx:286 +#: superset-frontend/src/components/ImportModal/index.tsx:285 #, python-format msgid "Import %s" -msgstr "Импорт %s" +msgstr "Импортировать %s" #: superset/templates/superset/import_dashboards.html:26 msgid "Import Dashboard(s)" -msgstr "Импорт дашборда(ов)" +msgstr "Импортировать дашборд(ы)" -#: superset/initialization/__init__.py:314 +#: superset/initialization/__init__.py:332 msgid "Import Dashboards" -msgstr "Импорт дашбордов" +msgstr "Импортировать дашборды" -#: superset/connectors/sqla/views.py:397 +#: superset/connectors/sqla/views.py:387 msgid "Import a table definition" -msgstr "Импортировать определение таблицы" +msgstr "" -#: superset/charts/commands/exceptions.py:151 +#: superset/charts/commands/exceptions.py:155 msgid "Import chart failed for an unknown reason" -msgstr "Импорт графика не удался по неизвестной причине" +msgstr "Не удалось импортировать график по неизвестной причине" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:621 -#, fuzzy +#: superset-frontend/src/pages/ChartList/index.tsx:772 msgid "Import charts" -msgstr "Переместить график" +msgstr "Импортировать графики" #: superset/dashboards/commands/exceptions.py:82 msgid "Import dashboard failed for an unknown reason" -msgstr "Импорт дашборда не удался по неизвестной причине" +msgstr "Не удалось импортировать дашборд по неизвестной причине" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:596 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:635 #: superset/templates/superset/import_dashboards.html:21 msgid "Import dashboards" -msgstr "Импорт дашбордов" +msgstr "Импортировать дашборды" -#: superset/databases/commands/exceptions.py:139 +#: superset/databases/commands/exceptions.py:171 msgid "Import database failed for an unknown reason" -msgstr "Импорт базы данных не удался по неизвестной причине" +msgstr "Не удалось импортировать базу данных по неизвестной причине" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:195 -#, fuzzy -msgid "Import databases" -msgstr "Редактировать Базу Данных" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1756 +msgid "Import database from file" +msgstr "Импортировать базу данных из файла" -#: superset/datasets/commands/exceptions.py:181 +#: superset/datasets/commands/exceptions.py:185 msgid "Import dataset failed for an unknown reason" -msgstr "Импорт датасета не удался по неизвестной причине" +msgstr "Не удалось импортировать датасет по неизвестной причине" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:517 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:642 msgid "Import datasets" -msgstr "Редактировать датасет" +msgstr "Импортировать датасеты" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:190 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:189 msgid "Import queries" -msgstr "Пустой запрос?" +msgstr "Импортировать запросы" #: superset/queries/saved_queries/commands/exceptions.py:36 -#, fuzzy msgid "Import saved query failed for an unknown reason." -msgstr "Импорт графика не удался по неизвестной причине" +msgstr "Не удалось импортировать сохраненный запрос по неизвестной причине" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:64 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:63 msgid "" "Important! Select this if the table is not already sorted by entity id, " "else there is no guarantee that all events for each entity are returned." msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:67 +#: superset-frontend/src/explore/constants.ts:71 +#, fuzzy +msgid "In" +msgstr "в" + +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:57 msgid "Include Series" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:70 +#: superset-frontend/src/components/ReportModal/index.tsx:289 +msgid "Include a description that will be sent with your report" +msgstr "Описание, которое будет отправлено вместе с вашим отчетом" + +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:60 msgid "Include series name as an axis" -msgstr "" +msgstr "Включить имена категорий в качестве оси" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:325 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/includeTime.ts:27 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:335 msgid "Include time" -msgstr "Время окончания" +msgstr "Включить время" -#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:231 +#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:232 #, python-format msgid "Incompatible Filters (%d)" msgstr "Несовместимые фильтры (%d)" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:121 -msgid "Incorrect Fields" -msgstr "" +#: superset-frontend/src/SqlLab/components/ColumnElement/index.tsx:65 +msgid "Index" +msgstr "Индекс" -#: superset/views/database/forms.py:162 superset/views/database/forms.py:315 +#: superset/views/database/forms.py:210 superset/views/database/forms.py:341 msgid "Index Column" -msgstr "Столбец индекса" +msgstr "Индесный столбец" -#: superset/views/database/forms.py:210 -msgid "Infer Datetime Format" -msgstr "Формат даты и времени" - -#: superset-frontend/src/components/Menu/MenuRight.tsx:166 -#: superset/templates/appbuilder/navbar_right.html:110 +#: superset-frontend/src/views/components/RightMenu.tsx:498 msgid "Info" -msgstr "Инфо" +msgstr "Личные данные" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:220 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:232 msgid "Inner Radius" -msgstr "" +msgstr "Внутренний радиус" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:226 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:238 msgid "Inner radius of donut hole" -msgstr "" - -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:314 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:216 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:177 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:158 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:174 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:232 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:235 +msgstr "Внутренний радиус отверстия для кольца" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:330 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:205 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:175 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:192 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:135 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:134 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:189 msgid "Input field supports custom rotation. e.g. 30 for 30°" -msgstr "" +msgstr "Поле для ввода поддерживает пользовательские значения, например 30 для 30°" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:90 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:60 msgid "Instant filtering" msgstr "Мгновенная Фильтрация" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:293 -msgid "Instructions to add a dataset are available in the Superset tutorial." -msgstr "" - -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:34 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:36 #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:41 #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:36 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:38 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:39 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:36 msgid "Intensity" -msgstr "Элемент" +msgstr "Насыщенность" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:495 -#, fuzzy +#: superset/views/database/forms.py:190 +msgid "Interpret Datetime Format Automatically" +msgstr "Автоматически интерпретировать формат дата/время" + +#: superset/views/database/forms.py:191 +msgid "Interpret the datetime format automatically" +msgstr "Автоматически интерпретировать формат дата/время" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/AnnotationTypes.js:42 +#: superset-frontend/src/modules/AnnotationTypes.js:41 +msgid "Interval" +msgstr "Интервал" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:543 msgid "Interval End column" -msgstr "Фильтруемые срезы" +msgstr "Столбец с концом интервала" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:286 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:282 msgid "Interval bounds" -msgstr "Фильтруемые срезы" +msgstr "Граница интервала" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:300 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:296 msgid "Interval colors" -msgstr "Цветовая схема" +msgstr "Цвета интервала" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:477 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:525 msgid "Interval start column" -msgstr "Фильтруемые срезы" +msgstr "Столбец с началом интервала" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:280 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:276 msgid "Intervals" -msgstr "Интервал обновления" +msgstr "Интервалы" -#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:109 +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:114 msgid "Invalid JSON" -msgstr "Недопустимый формат json" +msgstr "Недопустимый формат JSON" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:107 -msgid "Invalid Port Number" -msgstr "" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:113 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:117 -#, fuzzy -msgid "Invalid account information" -msgstr "Основная информация" +#: superset/advanced_data_type/api.py:100 +#, python-format +msgid "Invalid advanced data type: %(advanced_data_type)s" +msgstr "Невалидный расширенный тип данных: %(advanced_data_type)s" -#: superset/databases/schemas.py:170 superset/exceptions.py:182 +#: superset/databases/schemas.py:181 superset/exceptions.py:196 msgid "Invalid certificate" -msgstr "Недействительный сертификат" +msgstr "Неверный сертификат" -#: superset/views/core.py:1375 +#: superset/views/core.py:1410 msgid "" "Invalid connection string, a valid string usually follows:\n" "'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'" msgstr "" -"Недействительная строка подключения, правильная строка обычно следует " -"следующему шаблону:\n" -"‘драйвер://пользователь:пароль@хостБД/имяБД’" +"Недопустимая строка для подключения, валидная строка соответствует " +"шаблону: ДРАЙВЕР://ИМЯ-ПОЛЬЗОВАТЕЛЯ:ПАРОЛЬ@ХОСТ/ИМЯ-БАЗЫ-ДАННЫХ" -#: superset/databases/schemas.py:148 +#: superset/databases/schemas.py:159 msgid "" "Invalid connection string, a valid string usually follows: " -"driver://user:password@database-host/database-name" +"backend+driver://user:password@database-host/database-name" msgstr "" -"Недействительная строка подключения, правильная строка обычно следует " -"следующему шаблону: драйвер://пользователь:пароль@хостБД/имяБД" +"Недопустимая строка для подключения, валидная строка соответствует " +"шаблону: драйвер://имя-пользователя:пароль@хост/имя-базы-данных" #: superset/views/database/validators.py:40 msgid "" @@ -6641,157 +8055,195 @@ msgid "" "NAME'<p>Example:'postgresql://user:password@your-postgres-" "db/database'</p>" msgstr "" -"Недействительная строка подключения, правильная строка обычно следует " -"следующему шаблону: " -"драйвер://пользователь:пароль@хостБД/имяБД<p>Пример:’postgresql://user:password" -"@your-postgres-db/database'</p>" +"Недопустимая строка для подключения, валидная строка соответствует " +"шаблону:'ДРАЙВЕР://ИМЯ-ПОЛЬЗОВАТЕЛЯ:ПАРОЛЬ@ХОСТ/ИМЯ-БАЗЫ-ДАННЫХ'<p>Пример:'postgresql://user:password" +"@postgres-db/database'</p>" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:52 msgid "Invalid cron expression" -msgstr "" +msgstr "Недопустимое CRON выражение" -#: superset/utils/pandas_postprocessing.py:578 +#: superset/utils/pandas_postprocessing/cum.py:55 #, python-format msgid "Invalid cumulative operator: %(operator)s" msgstr "" -#: superset/connectors/sqla/views.py:168 superset/datasets/schemas.py:39 +#: superset/connectors/sqla/views.py:182 superset/datasets/schemas.py:44 msgid "Invalid date/timestamp format" -msgstr "Формат Даты / Времени" +msgstr "Недопустимый формат дата/время" -#: superset/viz.py:2123 +#: superset/viz.py:2157 msgid "Invalid filter configuration, please select a column" -msgstr "" +msgstr "Неверная конфигурация фильтра, пожалуйста, выберите столбец" -#: superset/connectors/sqla/models.py:1326 +#: superset/connectors/sqla/models.py:1596 superset/models/helpers.py:1805 #, python-format msgid "Invalid filter operation type: %(op)s" -msgstr "Недействительный тип операции фильтра: %(op)s" +msgstr "" -#: superset/utils/pandas_postprocessing.py:679 +#: superset/utils/pandas_postprocessing/geography.py:118 msgid "Invalid geodetic string" -msgstr "Недействительная строка geodetic" +msgstr "" -#: superset/utils/pandas_postprocessing.py:614 +#: superset/utils/pandas_postprocessing/geography.py:49 msgid "Invalid geohash string" -msgstr "Недействительная строка geohash" +msgstr "" + +#: superset-frontend/src/utils/getClientErrorObject.ts:65 +msgid "Invalid input" +msgstr "Недопустимые входные данные" #: superset-frontend/src/explore/components/controls/SpatialControl.jsx:82 msgid "Invalid lat/long configuration." msgstr "Неверная конфигурация широты и долготы." -#: superset/utils/pandas_postprocessing.py:637 +#: superset/utils/pandas_postprocessing/geography.py:76 msgid "Invalid longitude/latitude" -msgstr "Долгота и Широта [Конец]" +msgstr "Недопустимые долгота/широта" -#: superset/utils/core.py:1318 -#, fuzzy -msgid "Invalid metric object" -msgstr "Недействительный сертификат" +#: superset/utils/core.py:1363 +#, python-format +msgid "Invalid metric object: %(metric)s" +msgstr "" -#: superset/utils/pandas_postprocessing.py:184 +#: superset/utils/pandas_postprocessing/utils.py:170 #, python-format msgid "Invalid numpy function: %(operator)s" -msgstr "Недействительная функция numpy: %(operator)s" +msgstr "Недопустимая numpy функция: %(operator)s" -#: superset/utils/pandas_postprocessing.py:414 +#: superset/utils/pandas_postprocessing/rolling.py:90 #, python-format msgid "Invalid options for %(rolling_type)s: %(options)s" +msgstr "Недопустимые настройки для %(rolling_type)s: %(options)s" + +#: superset/key_value/utils.py:60 +msgid "Invalid permalink key" msgstr "" -#: superset/common/query_actions.py:192 +#: superset/common/query_actions.py:230 #, python-format msgid "Invalid result type: %(result_type)s" -msgstr "" +msgstr "Недопустимый тип ответа: %(result_type)s" -#: superset/utils/pandas_postprocessing.py:408 +#: superset/utils/pandas_postprocessing/rolling.py:84 #, python-format msgid "Invalid rolling_type: %(type)s" msgstr "" -#: superset/viz.py:2493 +#: superset/viz.py:2527 #, python-format msgid "Invalid spatial point encountered: %s" msgstr "" -#: superset-frontend/src/filters/components/Select/controlPanel.ts:124 +#: superset/dashboards/permalink/exceptions.py:23 +#: superset/explore/permalink/exceptions.py:23 +msgid "Invalid state." +msgstr "" + +#: superset/reports/commands/create.py:144 +#, python-format +msgid "Invalid tab ids: %s(tab_ids)" +msgstr "" + +#: superset-frontend/src/filters/components/Select/controlPanel.ts:123 msgid "Inverse selection" -msgstr "Инвертировать выбор" +msgstr "Выбрать противоположные значения" -#: superset/connectors/druid/views.py:347 -msgid "Is Hidden" -msgstr "Скрыто" +#: superset-frontend/src/components/Table/index.tsx:263 +msgid "Invert current page" +msgstr "" -#: superset/charts/filters.py:63 superset/dashboards/filters.py:168 -#, fuzzy +#: superset/charts/filters.py:65 superset/dashboards/filters.py:216 +#: superset/datasets/filters.py:39 msgid "Is certified" -msgstr "Изменено" +msgstr "Одобрено" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:285 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:355 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:363 msgid "Is dimension" -msgstr "Измерение" +msgstr "Является измерением" + +#: superset-frontend/src/explore/constants.ts:89 +#, fuzzy +msgid "Is false" +msgstr "Отключено" -#: superset/views/base_api.py:107 +#: superset/views/base_api.py:138 msgid "Is favorite" -msgstr "В Избранном" +msgstr "В избранном" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:287 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:358 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:366 msgid "Is filterable" -msgstr "Фильтрующийся" - -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:286 -#: superset/connectors/sqla/views.py:150 -msgid "Is temporal" -msgstr "Содержит дату /время" +msgstr "Фильтруемый" -#: superset-frontend/src/utils/getClientErrorObject.ts:112 +#: superset-frontend/src/explore/constants.ts:80 #, fuzzy +msgid "Is not null" +msgstr "Не пусто" + +#: superset-frontend/src/explore/constants.ts:83 +#, fuzzy +msgid "Is null" +msgstr "Не пусто" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:356 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:364 +#: superset/connectors/sqla/views.py:163 +msgid "Is temporal" +msgstr "Содержит дату/время" + +#: superset-frontend/src/explore/constants.ts:88 +#, fuzzy +msgid "Is true" +msgstr "поток" + +#: superset-frontend/src/utils/getClientErrorObject.ts:153 msgid "Issue 1000 - The dataset is too large to query." -msgstr "Проблема 1000 - Источник данных слишком велик для запроса." +msgstr "Ошибка 1000 - Источник данных слишком велик для запроса." -#: superset-frontend/src/utils/getClientErrorObject.ts:118 +#: superset-frontend/src/utils/getClientErrorObject.ts:157 msgid "Issue 1001 - The database is under an unusual load." -msgstr "Проблема 1001 - Необычная загрузка базы данных." - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 -#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 -#: superset-frontend/src/components/DatabaseSelector/index.tsx:183 -msgid "It seems you don't have access to any database" -msgstr "Кажется у Вас нет доступа к базе данных" +msgstr "Ошибка 1001 - Нетипичная загрузка базы данных." -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:221 -msgid "It’s not recommended to truncate y-axis in Bar chart." -msgstr "" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:230 +msgid "It’s not recommended to truncate axis in Bar chart." +msgstr "Не рекомендуется урезать интервал оси в столбчатой диаграмме" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:91 msgid "JAN" msgstr "ЯНВ" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:918 -#: superset/connectors/druid/views.py:191 superset/views/log/__init__.py:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts:56 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:351 +#: superset/views/log/__init__.py:33 msgid "JSON" msgstr "JSON" -#: superset/views/annotations.py:81 superset/views/dashboard/mixin.py:89 +#: superset/views/dashboard/mixin.py:89 msgid "JSON Metadata" -msgstr "Параметры JSON" +msgstr "JSON Метаданные" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:584 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:648 #: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:336 msgid "JSON metadata" msgstr "JSON метаданные" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:341 -#, fuzzy +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:314 +msgid "JSON metadata is invalid!" +msgstr "JSON метаданные не валидны!" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:351 msgid "" "JSON string containing additional connection configuration. This is used " "to provide connection information for systems like Hive, Presto and " "BigQuery which do not conform to the username:password syntax normally " "used by SQLAlchemy." msgstr "" -"Это используется для указания информации о соединении с такими системами " -"как Hive, Presto и BigQuery, которые не укладываются в шаблон " -"пользователь:пароль, который обычно используется в SQLAlchemy." +"JSON строка, содержащая дополнительную информацию о соединении. Это " +"используется для указания информации о соединении с такими системами как " +"Hive, Presto и BigQuery, которые не укладываются в шаблон " +"\"пользователь:пароль\", который обычно используется в SQLAlchemy." #: superset-frontend/src/components/CronPicker/CronPicker.tsx:97 msgid "JUL" @@ -6805,18 +8257,56 @@ msgstr "ИЮН" msgid "January" msgstr "Январь" -#: superset/views/database/forms.py:177 superset/views/database/forms.py:435 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:132 +msgid "Javascript data interceptor" +msgstr "Javascript редактор данных" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:154 +msgid "Javascript onClick href" +msgstr "Javascript onClick href" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:144 +msgid "Javascript tooltip generator" +msgstr "Javascript генератор всплывающих подсказок" + +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:78 +msgid "Jinja templating" +msgstr "Шаблонизацию Jinja." + +#: superset/views/database/forms.py:233 +msgid "Json list of the column names that should be read" +msgstr "Список столбцов в формате JSON из файла, которые будут использованы." + +#: superset/views/database/forms.py:464 msgid "" "Json list of the column names that should be read. If not None, only " "these columns will be read from the file." msgstr "" +"Список столбцов в формате JSON из файла, которые будут использованы. " +"Пример: [\"id\", \"name\", \"gender\", \"age\"]. Если в данном поле " +"указаны названия столбцов, из файла будут загружены только указанные " +"столбцы." -#: superset/views/database/forms.py:235 superset/views/database/forms.py:368 +#: superset/views/database/forms.py:203 +msgid "" +"Json list of the values that should be treated as null. Examples: [\"\"] " +"for empty strings, [\"None\", \"N/A\"], [\"nan\", \"null\"]. Warning: " +"Hive database supports only a single value" +msgstr "" +"Список JSON значений, которые следует рассматривать как нулевые. Примеры:" +" [\"\"] для пустых строк, [\"None\", \"N/A\"], [\"nan\", \"null\"]. " +"Предупреждение: База данных Hive поддерживает только одно значение." + +#: superset/views/database/forms.py:394 msgid "" "Json list of the values that should be treated as null. Examples: [\"\"]," " [\"None\", \"N/A\"], [\"nan\", \"null\"]. Warning: Hive database " "supports only single value. Use [\"\"] for empty string." msgstr "" +"Список JSON значений, которые следует рассматривать как нулевые. Примеры:" +" [\"\"], [\"None\", \"N/A\"], [\"nan\", \"null\"]. Предупреждение: База " +"данных Hive поддерживает только одно значение. Используйте [\"\"] для " +"пустой строки." #: superset-frontend/src/components/CronPicker/CronPicker.tsx:72 msgid "July" @@ -6826,453 +8316,584 @@ msgstr "Июль" msgid "June" msgstr "Июнь" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:29 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:30 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:25 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:47 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:37 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:26 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:29 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:31 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:48 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:39 msgid "KPI" -msgstr "" +msgstr "KPI" + +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:668 +msgid "Keep control settings?" +msgstr "Оставить прежние настройки?" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx:56 msgid "Keep editing" msgstr "Продолжить редактирование" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:157 -msgid "Keys for table" -msgstr "Ключевые поля таблицы" +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:98 +msgid "Key" +msgstr "Ключ" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:145 +msgid "Kilometers" +msgstr "Километры" + +#: superset-frontend/src/SqlLab/components/QueryLimitSelect/index.tsx:101 +msgid "LIMIT" +msgstr "ОГРАНИЧЕНИЕ" -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:149 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:192 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:196 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1037 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1045 +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:80 +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:109 +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:169 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:245 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:249 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1192 #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:157 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:143 -#: superset/views/annotations.py:77 superset/views/sql_lab.py:68 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:195 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:201 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:157 +#: superset/views/sql_lab/views.py:81 msgid "Label" msgstr "Метка" #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:175 msgid "Label Line" -msgstr "" +msgstr "Линия метки" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:47 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:85 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:99 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:106 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:95 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:98 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:105 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:111 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:94 msgid "Label Type" -msgstr "Таблица Данных" +msgstr "Тип метки" + +#: superset/utils/pandas_postprocessing/rename.py:53 +msgid "Label already exists" +msgstr "Метка уже существует" -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:152 +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:172 msgid "Label for your query" msgstr "Метка для вашего запроса" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:123 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:122 msgid "Label position" -msgstr "последний раздел:" +msgstr "Положение метки" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:198 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:199 msgid "Label threshold" -msgstr "" +msgstr "Порог метки" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:144 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:156 msgid "Labelling" -msgstr "" +msgstr "Маркировка" -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:79 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:93 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:88 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:65 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:78 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:92 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:87 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:66 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:64 msgid "Labels" -msgstr "Метка" +msgstr "Метки" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:90 msgid "Labels for the marker lines" -msgstr "" +msgstr "Метки для линий маркера" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:70 msgid "Labels for the markers" -msgstr "" +msgstr "Метки для маркеров" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:50 msgid "Labels for the ranges" -msgstr "" +msgstr "Метки для диапазонов" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:47 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:47 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:81 #: superset-frontend/src/dashboard/util/headerStyleOptions.ts:35 -#, fuzzy msgid "Large" -msgstr "Поделиться" +msgstr "Большой" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:190 #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:31 -#, fuzzy msgid "Last" -msgstr "Условие" +msgstr "Последний" -#: superset/connectors/sqla/views.py:492 superset/views/database/mixins.py:193 +#: superset/connectors/sqla/views.py:482 superset/views/database/mixins.py:190 msgid "Last Changed" -msgstr "Последнее изменение" +msgstr "Дата изменения" #: superset/views/chart/mixin.py:82 msgid "Last Modified" -msgstr "Изменено" +msgstr "Дата изменения" #: superset-frontend/src/components/LastUpdated/index.tsx:74 #, python-format msgid "Last Updated %s" -msgstr "" +msgstr "Дата изменения %s" + +#: superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.tsx:182 +#, python-format +msgid "Last Updated %s by %s" +msgstr "Изменено %s пользователем %s" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:149 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:86 #, python-format msgid "Last available value seen on %s" -msgstr "" +msgstr "Последнее доступное значение: %s" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:180 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:317 +#: superset-frontend/src/components/MetadataBar/ContentConfig.tsx:80 +#: superset-frontend/src/pages/ChartList/index.tsx:436 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:177 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:158 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:307 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:377 msgid "Last modified" -msgstr "Изменено" +msgstr "Последнее изменение" #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:151 #, python-format msgid "Last modified by %s" msgstr "Автор изменений %s" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:228 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:268 msgid "Last run" msgstr "Последнее изменение" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:63 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:73 +#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:178 msgid "Latitude" -msgstr "" +msgstr "Широта" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:294 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:299 msgid "Latitude of default viewport" -msgstr "" - -#: superset/views/annotations.py:76 -msgid "Layer" -msgstr "Слой" +msgstr "Широта для области просмотра" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:717 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:767 msgid "Layer configuration" -msgstr "Конфигурация слоя" +msgstr "Настройки слоя" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:101 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:110 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:102 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:111 msgid "Layout" -msgstr "" +msgstr "Оформление" + +#: superset-frontend/src/dashboard/components/BuilderComponentPane/index.tsx:81 +msgid "Layout elements" +msgstr "Оформление" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:114 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:115 msgid "Layout type of graph" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:123 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:246 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:124 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:247 msgid "Layout type of tree" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:81 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:80 msgid "" "Leaf nodes that represent fewer than this number of events will be " "initially hidden in the visualization" msgstr "" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:567 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:541 -#, fuzzy +#: superset-frontend/src/pages/ChartList/index.tsx:708 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:567 msgid "Least recently modified" -msgstr "Изменено" +msgstr "Измененные давно" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:111 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:306 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:28 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:100 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:85 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:371 msgid "Left" -msgstr "оповещение" +msgstr "Слева" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:72 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:166 -#, fuzzy msgid "Left Axis Format" -msgstr "Формат Оси Y" +msgstr "Формат левой оси" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:68 -#, fuzzy msgid "Left Axis Metric" -msgstr "Показатель для правой оси" +msgstr "Мера левой оси" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:97 -#, fuzzy, python-format msgid "Left Axis chart(s)" -msgstr "Выберите схему (%s)" +msgstr "График(и) по левой оси" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:187 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:77 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:201 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:76 msgid "Left Margin" -msgstr "" +msgstr "Левый отступ" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:199 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:81 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:213 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:88 msgid "Left margin, in pixels, allowing for more room for axis labels" -msgstr "" +msgstr "Левый отступ (в пикселях), дает больше пространства меткам оси" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:137 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:138 msgid "Left to Right" -msgstr "" +msgstr "Слева направо" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:147 -#, fuzzy +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:144 msgid "Left value" -msgstr "Значение фильтра" +msgstr "Левое значение" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:38 -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:30 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:32 #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:42 #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 #: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:33 #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:37 #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:31 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:31 +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:34 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:30 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:33 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:34 #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:40 #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:43 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:39 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:43 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:47 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:35 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:32 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:37 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:34 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:50 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:33 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:35 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:32 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:42 +#: superset-frontend/src/visualizations/TimeTable/index.ts:35 msgid "Legacy" -msgstr "" +msgstr "Устарел" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:154 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:275 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:129 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:149 -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:95 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:289 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:115 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:156 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:97 msgid "Legend" -msgstr "Изменения" +msgstr "Легенда" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:68 -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:88 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:162 +msgid "Legend Format" +msgstr "Формат легенды" + +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:90 +msgid "Legend Orientation" +msgstr "Ориентация легенды" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:176 +msgid "Legend Position" +msgstr "Расположение легенды" + +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:70 msgid "Legend type" +msgstr "Тип легенды" + +#: superset-frontend/src/explore/constants.ts:63 +#, fuzzy +msgid "Less or equal (<=)" +msgstr "<= (меньше или равно)" + +#: superset-frontend/src/explore/constants.ts:61 +msgid "Less than (<)" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:98 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:90 msgid "Lift percent precision" msgstr "" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:230 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:376 +msgid "Light" +msgstr "Светлый" + #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:30 msgid "Light mode" +msgstr "Светлый режим" + +#: superset-frontend/src/explore/constants.ts:73 +msgid "Like" msgstr "" -#: superset-frontend/src/explore/components/RowCountLabel.jsx:45 +#: superset-frontend/src/explore/constants.ts:75 +#, fuzzy +msgid "Like (case insensitive)" +msgstr "Фильтровать значения (зависит от регистра)" + +#: superset-frontend/src/explore/components/RowCountLabel/index.tsx:49 msgid "Limit reached" msgstr "Достигнут предел" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:134 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:97 msgid "Limit selector values" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:44 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:98 +msgid "Limit type" +msgstr "Тип ограничения" + +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:48 msgid "" "Limiting rows may result in incomplete data and misleading charts. " "Consider filtering or grouping source/target names instead." msgstr "" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:335 -#: superset-frontend/src/explore/controls.jsx:364 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:136 +msgid "Limits the number of cells that get retrieved." +msgstr "Ограничивает количество извлекаемых ячеек" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:251 +#: superset-frontend/src/explore/controls.jsx:344 msgid "Limits the number of rows that get displayed." -msgstr "" +msgstr "Ограничивает количество отображаемых строк" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:345 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:359 -#: superset-frontend/src/explore/controls.jsx:374 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:274 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:289 +#: superset-frontend/src/explore/controls.jsx:354 msgid "" "Limits the number of series that get displayed. A joined subquery (or an " "extra phase where subqueries are not supported) is applied to limit the " "number of series that get fetched and rendered. This feature is useful " "when grouping by high cardinality column(s) though does increase the " "query complexity and cost." -msgstr "Ограничивает количество отображаемых временных рядов." +msgstr "" +"Ограничивает количество отображаемых категорий. Эта опция полезна для " +"столбцов с большим количеством уникальных значений, т.к. уменьшает " +"сложность и стоимость запроса." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:38 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:48 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:37 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:82 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:73 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:39 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:40 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:141 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:75 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:74 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:68 msgid "Line" -msgstr "Мои" +msgstr "Линейный" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:38 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:76 #: superset-frontend/plugins/preset-chart-xy/src/Line/createMetadata.ts:26 -#, fuzzy msgid "Line Chart" -msgstr "Свернуть график" +msgstr "Линейный график" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:38 +msgid "Line Chart (legacy)" +msgstr "Линейный график (устарело)" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:113 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:120 msgid "Line Style" +msgstr "Тип линии" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:62 +msgid "" +"Line chart is used to visualize measurements taken over a given category." +" Line chart is a type of chart which displays information as a series of " +"data points connected by straight line segments. It is a basic type of " +"chart common in many fields." msgstr "" +"Линейная диаграмма используется для визуализации показателей, полученных " +"в рамках одной категории. Линейная диаграмма - это тип диаграммы, который" +" отображает информацию в виде ряда точек данных, соединенных прямыми " +"отрезками. Это базовый тип диаграммы, распространенный во многих " +"областях." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:124 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:131 msgid "Line interpolation as defined by d3.js" -msgstr "" +msgstr "Линейная интерполяция, определенная в d3.js" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:667 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:210 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:715 msgid "Line width" msgstr "Толщина линии" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:190 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:137 msgid "Linear Color Scheme" -msgstr "Цветовая схема" +msgstr "Линейная цветовая схема" -#: superset-frontend/src/explore/controls.jsx:222 +#: superset-frontend/src/explore/controls.jsx:221 msgid "Linear color scheme" -msgstr "Цветовая схема" +msgstr "Линейная цветовая схема" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:186 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:260 +msgid "Linear interpolation" +msgstr "Линейная интерполяция" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:196 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx:27 +#, fuzzy +msgid "Lines column" +msgstr "Столбец с временем" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:345 +#, fuzzy +msgid "Lines encoding" +msgstr "Направление сортировки" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:216 -#: superset-frontend/src/views/CRUD/hooks.ts:601 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:217 +#: superset-frontend/src/views/CRUD/hooks.ts:629 msgid "Link Copied!" -msgstr "Ссылка скопирована!" +msgstr "Ссылка скопирована" -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:58 -msgid "Link Length" +#: superset/views/sql_lab/views.py:52 +msgid "List Saved Query" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:70 -msgid "Link length in the force layout" -msgstr "" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:181 +msgid "List Unique Values" +msgstr "Список уникальных значений" -#: superset/views/alerts.py:75 -msgid "List Observations" -msgstr "Список показателей" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:123 +msgid "List of extra columns made available in Javascript functions" +msgstr "Список дополнительных столбцов, доступных в функциях Javascript" -#: superset/views/sql_lab.py:39 -msgid "List Saved Query" -msgstr "Список сохраненных запросов" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:151 +msgid "List of n+1 values for bucketing metric into n buckets." +msgstr "" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:81 msgid "List of values to mark with lines" msgstr "" +"Список числовых значений для отображения в виде линий на графике. " +"Например, 10,20,30" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:61 msgid "List of values to mark with triangles" msgstr "" +"Список числовых значений для отображения в виде треугольников на графике." +" Например, 10,20,30" + +#: superset-frontend/src/components/DatabaseSelector/index.tsx:251 +#, fuzzy +msgid "List refreshed" +msgstr "Данные обновлены" -#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:108 +#: superset-frontend/src/components/TableSelector/index.tsx:190 +msgid "List updated" +msgstr "Список обновлен" + +#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:109 msgid "Live CSS editor" msgstr "Редактор CSS" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:199 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:211 msgid "Live render" -msgstr "" +msgstr "Мгновенная отрисовка" -#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:93 +#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:94 msgid "Load a CSS template" -msgstr "Загрузить шаблон стилей (CSS)" +msgstr "Загрузить CSS шаблон" #: superset-frontend/src/components/CachedLabel/TooltipContent.tsx:30 msgid "Loaded data cached" -msgstr "Данные были загружены в кэш" +msgstr "Данные загружены в кэш" #: superset-frontend/src/components/CachedLabel/TooltipContent.tsx:34 msgid "Loaded from cache" -msgstr "Загружается из кэша" - -#: superset-frontend/src/components/Select/Select.tsx:603 -#: superset-frontend/src/components/Select/Select.tsx:714 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:110 +msgstr "Загружено из кэша" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx:177 +msgid "Loading" +msgstr "Загрузка" + +#: superset-frontend/plugins/plugin-chart-handlebars/src/components/Handlebars/HandlebarsViewer.tsx:74 +#: superset-frontend/src/components/Select/AsyncSelect.tsx:495 +#: superset-frontend/src/components/Select/Select.tsx:452 +#: superset-frontend/src/components/Select/utils.tsx:152 +#: superset-frontend/src/dashboard/components/gridComponents/DynamicComponent.tsx:165 +#: superset-frontend/src/explore/components/RowCountLabel/index.tsx:40 msgid "Loading..." -msgstr "" +msgstr "Загрузка..." -#: superset/views/alerts.py:180 -msgid "Log Retentions (days)" -msgstr "Время жизни журналов (в днях)" - -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:204 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:197 msgid "Log Scale" -msgstr "" +msgstr "Логарифмическая шкала" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1238 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1243 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1244 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:411 msgid "Log retention" -msgstr "Время жизни журнала" +msgstr "Хранение журнала" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:383 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:199 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:202 +msgid "Logarithmic axis" +msgstr "Логарифмическая ось" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:399 msgid "Logarithmic scale on primary y-axis" -msgstr "" +msgstr "Логарифмическая шкала для главной оси Y" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:416 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:432 msgid "Logarithmic scale on secondary y-axis" -msgstr "" - -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:380 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:404 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:413 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:231 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:234 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:194 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:197 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:174 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:177 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:191 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:194 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:247 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:250 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:250 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:253 +msgstr "Логарифмическая шкала для вторичной оси Y" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:396 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:420 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:429 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:220 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:223 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:207 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:210 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:151 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:154 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:151 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:154 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:204 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:207 msgid "Logarithmic y-axis" -msgstr "" +msgstr "Логарифмическая ось Y" -#: superset-frontend/src/components/Menu/MenuRight.tsx:233 -#: superset/templates/appbuilder/navbar_right.html:126 +#: superset-frontend/src/views/components/RightMenu.tsx:578 msgid "Login" msgstr "Вход в систему" -#: superset-frontend/src/components/Menu/MenuRight.tsx:170 -#: superset/templates/appbuilder/navbar_right.html:111 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:155 +msgid "Login with" +msgstr "Войти при помощи" + +#: superset-frontend/src/views/components/RightMenu.tsx:502 msgid "Logout" msgstr "Выход из системы" #: superset/views/log/__init__.py:21 msgid "Logs" -msgstr "Журналы" +msgstr "Записи" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:674 +msgid "Long dashed" +msgstr "Длинный штрих" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:53 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:63 +#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:174 msgid "Longitude" -msgstr "" +msgstr "Долгота" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:307 +msgid "Longitude & Latitude" +msgstr "Долгота и Широта" #: superset-frontend/src/explore/components/controls/SpatialControl.jsx:168 msgid "Longitude & Latitude columns" msgstr "Долгота и Широта" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:280 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/Grid.jsx:34 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/Scatter.jsx:40 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/Screengrid.jsx:44 +msgid "Longitude and Latitude" +msgstr "Долгота и Широта" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:285 msgid "Longitude of default viewport" -msgstr "" +msgstr "Долгота для области просмотра" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:93 msgid "MAR" @@ -7286,62 +8907,88 @@ msgstr "МАЙ" msgid "MON" msgstr "ПН" -#: superset/connectors/sqla/views.py:501 +#: superset/connectors/sqla/views.py:491 msgid "Main Datetime Column" -msgstr "Основной столбец с датой" +msgstr "Основной столбец с временем" + +#: superset-frontend/src/components/Chart/ChartRenderer.jsx:282 +msgid "" +"Make sure that the controls are configured properly and the datasource " +"contains data for the selected time range" +msgstr "" +"Убедитесь, что настройки графика верно сконфигурированы и источник данных" +" содержит данные для выбранного временного интервала." -#: superset/views/core.py:1738 +#: superset/views/core.py:1703 msgid "" "Malformed request. slice_id or table_name and db_name arguments are " "expected" -msgstr "Неправильный запрос. Ожидаются аргументы slice_id или table_name и db_name" - -#: superset/initialization/__init__.py:232 -#: superset/initialization/__init__.py:256 -#: superset/initialization/__init__.py:268 -#: superset/initialization/__init__.py:318 -#: superset/initialization/__init__.py:446 -#: superset/initialization/__init__.py:455 -#: superset/initialization/__init__.py:470 -#: superset/initialization/__init__.py:482 +msgstr "Некорректный запрос. Ожидаются аргументы slice_id или table_name и db_name" + +#: superset/initialization/__init__.py:273 +#: superset/initialization/__init__.py:285 +#: superset/initialization/__init__.py:336 +#: superset/initialization/__init__.py:392 +#: superset/initialization/__init__.py:405 msgid "Manage" msgstr "Управление" -#: superset/views/schedules.py:276 -msgid "Manage Email Reports for Charts" -msgstr "Управление рассылкой email для графиков" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:357 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:368 +msgid "Manage email report" +msgstr "Управление рассылкой по почте" -#: superset/views/schedules.py:198 -msgid "Manage Email Reports for Dashboards" -msgstr "Управление рассылками для дашбордов" +#: superset-frontend/src/components/EmptyState/index.tsx:236 +msgid "Manage your databases" +msgstr "Управляйте своими базами данных" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:726 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:763 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:776 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:814 msgid "Mandatory" -msgstr "" +msgstr "Обязательно" -#: superset/views/database/forms.py:171 superset/views/database/forms.py:324 +#: superset/views/database/forms.py:350 msgid "Mangle Duplicate Columns" -msgstr "Дубликаты" +msgstr "Управление повторяющимися столбцами" + +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:297 +msgid "Manually set min/max values for the y-axis." +msgstr "Вручную задать мин./макс. значения для оси Y" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:25 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:27 #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:26 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:27 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:27 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:78 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts:64 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts:67 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:98 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:63 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:25 msgid "Map" -msgstr "Treemap" +msgstr "Карта" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:212 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:224 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:370 msgid "Map Style" -msgstr "Тип разметки" +msgstr "Стиль карты" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:33 -#, fuzzy msgid "MapBox" msgstr "Mapbox" -#: superset/viz.py:2285 +#: superset/viz.py:2319 msgid "Mapbox" msgstr "Mapbox" @@ -7349,391 +8996,446 @@ msgstr "Mapbox" msgid "March" msgstr "Март" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:46 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:48 msgid "Margin" -msgstr "Источник" - -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:211 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:149 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:110 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:90 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:107 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:165 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:168 +msgstr "Отступ" + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:346 +msgid "Mark a column as temporal in \"Edit datasource\" modal" +msgstr "Присвойте столбцу формат даты/времени в настройках датасета" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:213 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:138 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:125 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:67 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:67 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:122 msgid "Marker" -msgstr "" +msgstr "Маркер" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:163 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:124 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:104 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:121 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:179 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:182 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:152 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:139 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:136 msgid "Marker Size" -msgstr "" +msgstr "Размер маркера" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:68 -#, fuzzy, python-format msgid "Marker labels" -msgstr "[Оповещение] %(label)s" +msgstr "Метки маркера" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:88 msgid "Marker line labels" -msgstr "" +msgstr "Метки линий маркера" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:79 msgid "Marker lines" -msgstr "" +msgstr "Линии маркеров" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:225 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:227 msgid "Marker size" -msgstr "" +msgstr "Размер маркера" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:59 -#, fuzzy msgid "Markers" -msgstr "оповещения" +msgstr "Маркеры" #: superset-frontend/src/explore/controlPanels/Separator.js:32 msgid "Markup type" msgstr "Тип разметки" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:100 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:96 #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:48 -#: superset-frontend/src/explore/components/controls/BoundsControl.jsx:118 +#: superset-frontend/src/explore/components/controls/BoundsControl.tsx:96 msgid "Max" msgstr "Максимум" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:94 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:59 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:96 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:60 msgid "Max Bubble Size" -msgstr "Размер маркера" +msgstr "Максимальный размер пузыря" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:129 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:128 msgid "Max Events" -msgstr "" - -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:257 -msgid "Maximize chart" -msgstr "Развернуть график" +msgstr "Лимит событий" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1266 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:188 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1108 msgid "Maximum" -msgstr "" +msgstr "Максимум" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:68 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:72 msgid "Maximum Font Size" -msgstr "" +msgstr "Максимальный размер шрифта" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:116 +msgid "Maximum Radius" +msgstr "Максимальный радиус" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:101 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:97 msgid "Maximum value on the gauge axis" +msgstr "Максимальное значение индикатора" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:121 +msgid "" +"Maxium radius size of the circle, in pixels. As the zoom level changes, " +"this insures that the circle respects this maximum radius." msgstr "" +"Максимальный размер радиуса окружности (в пикселях). При изменении уровня" +" масштабирования это гарантирует, что окружность соответствует этому " +"максимальному радиусу" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:70 msgid "May" msgstr "Май" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:93 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:86 msgid "Mean of values over specified period" -msgstr "" +msgstr "Среднее значений за указанный период" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:230 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:190 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:264 +msgid "Mean values" +msgstr "Средние значения" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:184 +msgid "Median" +msgstr "Медиана" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:231 msgid "" "Median edge width, the thickest edge will be 4 times thicker than the " "thinnest." msgstr "" +"Медианная толщина ребра, самое толстое ребро будет в 4 раза толще самой " +"тонкой." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:217 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:218 msgid "" "Median node size, the largest node will be 4 times larger than the " "smallest" msgstr "" +"Медианный размер вершины, самая большая вершина будет в 4 раза больше " +"самой маленькой." + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:189 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:263 +msgid "Median values" +msgstr "Медианные значения" #: superset-frontend/src/dashboard/util/headerStyleOptions.ts:30 msgid "Medium" -msgstr "" +msgstr "Средний" -#: superset-frontend/src/components/ReportModal/index.tsx:275 -#, fuzzy -msgid "Message Content" -msgstr "Содержимое сообщения" +#: superset-frontend/src/components/PageHeaderWithActions/index.tsx:160 +msgid "Menu actions trigger" +msgstr "" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1292 +#: superset-frontend/src/components/ReportModal/index.tsx:231 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:416 msgid "Message content" msgstr "Содержимое сообщения" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:105 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:104 msgid "Metadata" -msgstr "JSON метаданные" - -#: superset/connectors/druid/views.py:240 -msgid "Metadata Last Refreshed" -msgstr "Метаданные обновлены" +msgstr "Метаданные" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:437 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:442 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:450 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:454 msgid "Metadata Parameters" -msgstr "Параметры шаблона" +msgstr "Параметры метаданных" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:617 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:779 msgid "Metadata has been synced" msgstr "Метаданные синхронизированы" -#: superset/connectors/sqla/views.py:602 -#, python-format -msgid "Metadata refreshed for the following table(s): %(tables)s" -msgstr "Метаданные обновлены для следующих таблиц: %(tables)s" - -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:378 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:261 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:506 -#: superset-frontend/src/explore/controlPanels/sections.tsx:268 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:370 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:252 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:524 +#: superset-frontend/src/explore/controlPanels/sections.tsx:248 msgid "Method" msgstr "Метод" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:113 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:114 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:151 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:152 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:84 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:97 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1036 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:175 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:176 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/Calendar.js:88 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:85 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:119 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:98 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1191 #: superset-frontend/src/explore/controls.jsx:167 #: superset-frontend/src/explore/controls.jsx:168 -#: superset/connectors/druid/views.py:187 superset/connectors/sqla/views.py:255 +#: superset-frontend/src/visualizations/TimeTable/TimeTable.jsx:122 +#: superset/connectors/sqla/views.py:251 msgid "Metric" -msgstr "Показатель" +msgstr "Мера" -#: superset/connectors/sqla/models.py:1079 -#: superset/connectors/sqla/models.py:1509 +#: superset/connectors/sqla/models.py:1246 +#: superset/connectors/sqla/models.py:1801 superset/models/helpers.py:1177 +#: superset/models/helpers.py:1433 #, python-format msgid "Metric '%(metric)s' does not exist" -msgstr "Показатель ‘%(metric)s’ не существует" +msgstr "Мера '%(metric)s' не существует" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:38 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:39 msgid "Metric ascending" -msgstr "Направление сортировки" +msgstr "Мера по возрастанию" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:148 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:407 -#: superset-frontend/src/explore/controls.jsx:422 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:214 +#: superset-frontend/src/explore/controls.jsx:402 msgid "Metric assigned to the [X] axis" msgstr "Показатель, отраженный на оси X" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:154 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:415 -#: superset-frontend/src/explore/controls.jsx:430 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:221 +#: superset-frontend/src/explore/controls.jsx:410 msgid "Metric assigned to the [Y] axis" msgstr "Показатель, отраженный на оси Y" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:103 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:96 msgid "Metric change in value from `since` to `until`" -msgstr "" +msgstr "Изменение меры с `до` до `после`" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:39 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:40 msgid "Metric descending" -msgstr "Сортировать" +msgstr "Мера по убыванию" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:117 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:110 msgid "Metric factor change from `since` to `until`" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:119 -#, fuzzy -msgid "Metric for Color" -msgstr "Показатель, используемый для расчета цвета" - -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:98 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:99 msgid "Metric for node values" -msgstr "" +msgstr "Мера для значений вершин" + +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:106 +msgid "Metric name" +msgstr "Имя меры" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:658 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:820 #, python-format msgid "Metric name [%s] is duplicated" -msgstr "Дубль имения показателя [%s]" +msgstr "Дубль имени меры [%s]" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:110 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:103 msgid "Metric percent change in value from `since` to `until`" -msgstr "" - -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:120 -msgid "Metric that defines the color of the country" -msgstr "" +msgstr "Процентное изменение меры с `до` до `после`" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:124 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:140 msgid "Metric that defines the size of the bubble" -msgstr "" +msgstr "Показатель, определяющий размер пузяря" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:85 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:86 msgid "Metric to display bottom title" -msgstr "Выберите показатель для отображения" +msgstr "Мера для отображения нижнего заголовка" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:185 msgid "Metric to sort the results by" msgstr "Показатель, по которому сортировать результаты" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:142 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:421 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:78 +msgid "Metric used as a weight for the grid's coloring" +msgstr "Мера, используемая как вес для раскрашивания сетки" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:207 msgid "Metric used to calculate bubble size" +msgstr "Мера, используемая для расчета размера пузыря" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts:76 +msgid "Metric used to control height" +msgstr "Мера, используемая для регулирования высоты" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:146 +msgid "" +"Metric used to define how the top series are sorted if a series or cell " +"limit is present. If undefined reverts to the first metric (where " +"appropriate)." msgstr "" +"Мера, используемая для определения того, как сортируются верхние " +"категории, если присутствует ограничение по категории или ячейке. Если не" +" определено, возвращается к первой мере (где это уместно)." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:127 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:371 -#: superset-frontend/src/explore/controls.jsx:387 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:192 +#: superset-frontend/src/explore/controls.jsx:367 msgid "" "Metric used to define how the top series are sorted if a series or row " "limit is present. If undefined reverts to the first metric (where " "appropriate)." msgstr "" +"Мера, используемая для определения того, как сортируются верхние " +"категории, если присутствует ограничение по категории или строке. Если не" +" определено, возвращается к первой мере (где это уместно)." -#: superset/connectors/druid/models.py:1072 -msgid "Metric(s) {} must be aggregations." -msgstr "Показатель(и) {} должны быть агрегированы." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:55 +msgid "" +"Metric used to order the limit if a series limit is present. If undefined" +" reverts to the first metric (where appropriate)." +msgstr "" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:99 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:137 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1196 -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:301 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:161 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1356 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:394 #: superset-frontend/src/explore/controls.jsx:152 -#: superset/connectors/druid/views.py:159 superset/connectors/sqla/views.py:212 +#: superset/connectors/sqla/views.py:208 msgid "Metrics" -msgstr "Показатели" +msgstr "Меры" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:148 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx:34 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:126 msgid "" "Metrics for which percentage of total are to be displayed. Calculated " "from only data within the row limit." msgstr "" +"Меры, для которых должен отображаться процент от общего числа. " +"Вычисляется только из данных в пределах ограничения по строкам." -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:93 -msgid "Midnight" -msgstr "" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:74 +msgid "Middle" +msgstr "Середина" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:88 -#: superset-frontend/src/explore/components/controls/BoundsControl.jsx:112 +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:90 +msgid "Midnight" +msgstr "Полночь" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:144 +msgid "Miles" +msgstr "Мили" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:85 +#: superset-frontend/src/explore/components/controls/BoundsControl.tsx:88 msgid "Min" msgstr "Минимум" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:290 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:173 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:193 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:424 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:283 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:165 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:434 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:214 msgid "Min Periods" -msgstr "HIde Periods" +msgstr "Минимальный период" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:90 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:79 msgid "Min Width" -msgstr "Толщина линии" +msgstr "Минимальная ширина" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:73 -#: superset-frontend/src/explore/controlPanels/sections.tsx:189 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:80 +#: superset-frontend/src/explore/controlPanels/sections.tsx:162 msgid "Min periods" -msgstr "HIde Periods" +msgstr "Минимальный период" + +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:95 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:48 +msgid "Min/max (no outliers)" +msgstr "Мин/макс (без выбросов)" -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:170 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:167 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:278 +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:153 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:159 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:251 msgid "Mine" msgstr "Мои" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:257 -msgid "Minimize chart" -msgstr "Свернуть график" - -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1260 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:187 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1102 msgid "Minimum" -msgstr "минута" +msgstr "Минимум" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:57 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:61 msgid "Minimum Font Size" -msgstr "" +msgstr "Минимальный размер шрифта" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:101 +msgid "Minimum Radius" +msgstr "Минимальный радиус" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:78 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:77 msgid "Minimum leaf node event count" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:85 -msgid "Minimum threshold in percentage points for showing labels." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:106 +msgid "" +"Minimum radius size of the circle, in pixels. As the zoom level changes, " +"this insures that the circle respects this minimum radius." msgstr "" +"Минимальный размер радиуса окружности (в пикселях). При изменении " +"масштаба это гарантирует, что окружность соответствует этому минимальному" +" радиусу." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:202 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:88 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:149 +msgid "Minimum threshold in percentage points for showing labels." +msgstr "Минимальный порог в процентных пунктах для отображения меток" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:203 msgid "Minimum value for label to be displayed on graph." -msgstr "" +msgstr "Минимальное значение метки для отображения на графике." -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:89 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:86 msgid "Minimum value on the gauge axis" -msgstr "" - -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:328 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:243 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:206 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:186 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:203 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:259 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:262 +msgstr "Минимальное значение индикатора" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:344 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:232 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:213 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:219 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:163 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:163 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:216 msgid "Minor Split Line" -msgstr "" +msgstr "Разметка полотна линиями" -#: superset/db_engine_specs/base.py:89 -#, fuzzy +#: superset/db_engine_specs/base.py:103 msgid "Minute" -msgstr "минута" +msgstr "Минута" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:64 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:63 +#, python-format msgid "Minutes %s" -msgstr "минута" +msgstr "Минут %s" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:93 -#, fuzzy -msgid "Missing Required Fields" -msgstr "Имя обязательно" +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:401 +msgid "Missing URL parameters" +msgstr "Пропущенные параметры URL" #: superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.tsx:34 -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:251 -#, fuzzy +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:363 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:419 msgid "Missing dataset" -msgstr "Выберите источник данных" +msgstr "Отсутствующий датасет" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:67 -msgid "Mixed Time-Series" -msgstr "" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:74 +msgid "Mixed Chart" +msgstr "Смешанный график" -#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:128 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:312 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:309 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:359 -#: superset/connectors/druid/views.py:355 superset/connectors/sqla/views.py:371 -#: superset/connectors/sqla/views.py:506 superset/views/dashboard/mixin.py:86 -#: superset/views/dashboard/views.py:158 superset/views/database/mixins.py:202 -#: superset/views/sql_lab.py:72 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:74 +msgid "Mixed Time-Series" +msgstr "Смешанная диаграмма временных рядов" + +#: superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.tsx:278 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:336 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:327 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:368 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:360 +#: superset/connectors/sqla/views.py:368 superset/connectors/sqla/views.py:496 +#: superset/views/dashboard/mixin.py:86 superset/views/dashboard/views.py:194 +#: superset/views/database/mixins.py:199 superset/views/sql_lab/views.py:85 msgid "Modified" msgstr "Изменено" -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:155 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:164 -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:130 -#, fuzzy, python-format +#: superset-frontend/src/pages/ChartList/ChartCard.tsx:158 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:163 +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:123 +#, python-format msgid "Modified %s" msgstr "Изменено %s" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:303 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:291 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:319 +#: superset-frontend/src/components/MetadataBar/ContentConfig.tsx:81 +#: superset-frontend/src/pages/ChartList/index.tsx:422 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:306 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:378 msgid "Modified by" -msgstr "Изменено" +msgstr "Кем изменено" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:604 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:766 #, python-format msgid "Modified columns: %s" msgstr "Изменённые столбцы: %s" @@ -7742,71 +9444,82 @@ msgstr "Изменённые столбцы: %s" msgid "Monday" msgstr "Понедельник" -#: superset/db_engine_specs/base.py:98 -#, fuzzy +#: superset/db_engine_specs/base.py:112 msgid "Month" -msgstr "месяц" +msgstr "Месяц" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:68 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:67 +#, python-format msgid "Months %s" -msgstr "месяц" +msgstr "Месяцев %s" -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:238 -msgid "More dataset related options" -msgstr "Больше опций к датасету" +#: superset-frontend/src/components/DropdownContainer/index.tsx:122 +msgid "More" +msgstr "Подробнее" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:167 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:276 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx:182 +#, fuzzy +msgid "More filters" +msgstr "Временной фильтр" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:168 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:277 msgid "Move only" -msgstr "" +msgstr "Только перемещение" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:43 msgid "Moves the given set of dates by a specified interval." msgstr "" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:40 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:32 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:34 msgid "Multi-Dimensions" -msgstr "Измерение" +msgstr "Многомерный" -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:34 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:37 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:41 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:37 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:39 msgid "Multi-Layers" -msgstr "" +msgstr "Многослойный" #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts:45 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:43 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:62 msgid "Multi-Levels" -msgstr "" +msgstr "Многоуровневый" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:42 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:32 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:44 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:74 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:58 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:30 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:34 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:47 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:61 +#: superset-frontend/src/visualizations/TimeTable/index.ts:33 msgid "Multi-Variables" -msgstr "" +msgstr "Несколько переменных" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:187 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:188 msgid "Multiple" -msgstr "" +msgstr "Несколько" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:30 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:32 msgid "Multiple Line Charts" -msgstr "Time Series - Multiple Line Charts" +msgstr "Несколько линейных диаграмм" -#: superset/views/database/views.py:439 +#: superset/views/database/views.py:465 msgid "" "Multiple file extensions are not allowed for columnar uploads. Please " "make sure all files are of the same extension." msgstr "" +"Несколько расширений файлов столбчатого формата не разрешены к загрузке. " +"Пожалуйста, убедитесь, что все файлы имеют одинаковое расширение." + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:173 +msgid "Multiple filtering" +msgstr "Множественная фильтрация" #: superset-frontend/src/explore/components/controls/SpatialControl.jsx:185 msgid "" @@ -7816,183 +9529,213 @@ msgstr "" "Для уточнения форматов и получения более подробной информации, посмотрите" " Python-библиотеку geopy.points" -#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:59 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:77 -#, fuzzy -msgid "Multiple select" -msgstr "Разрешить множественный фильтр" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:218 msgid "Multiple selections allowed, otherwise filter is limited to a single value" msgstr "" "Разрешён множественный выбор, иначе можно выбрать только одно значение " "фильтра" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:333 +msgid "Multiplier" +msgstr "Мультипликатор" + #: superset/dashboards/commands/exceptions.py:39 msgid "Must be unique" -msgstr "Должно быть уникально" +msgstr "Должно быть уникальным" + +#: superset/reports/commands/exceptions.py:94 +msgid "Must choose either a chart or a dashboard" +msgstr "Выберите график или дашборд" -#: superset/viz.py:2309 +#: superset/viz.py:2343 msgid "Must have a [Group By] column to have 'count' as the [Label]" -msgstr "Чтобы получить `count` как [Метку], должна быть заполнена [Группировка по]" +msgstr "" -#: superset/viz.py:1720 +#: superset/viz.py:1749 msgid "Must have at least one numeric column specified" msgstr "Должен быть указан хотя бы один числовой столбец" -#: superset/connectors/sqla/models.py:1303 +#: superset/connectors/sqla/models.py:1555 superset/models/helpers.py:1765 msgid "Must specify a value for filters with comparison operators" -msgstr "" +msgstr "Необходимо указать значение для фильтров с операторами сравнения" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx:47 -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.jsx:59 -#, fuzzy +#: superset-frontend/src/explore/controlUtils/controlUtils.test.tsx:74 +msgid "My beautiful colors" +msgstr "Мои красивые цвета" + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx:41 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.jsx:65 msgid "My column" -msgstr "столбец" +msgstr "Мой столбец" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.jsx:73 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx:55 msgid "My metric" -msgstr "Показатель" +msgstr "Моя мера" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:76 +#: superset-frontend/src/constants.ts:147 +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:239 msgid "N/A" +msgstr "Пусто" + +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:52 +msgid "NOT GROUPED BY" msgstr "" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:101 msgid "NOV" msgstr "НОЯ" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:232 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:244 msgid "NOW" msgstr "СЕЙЧАС" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:72 -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:123 -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:211 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:230 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:232 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:722 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:233 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:131 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:138 +msgid "NUMERIC" +msgstr "Числовой (NUMERIC/DECIMAL)" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:73 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:150 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:760 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:212 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:243 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:245 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:772 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:273 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:130 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:131 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:279 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:273 -#: superset/views/annotations.py:126 superset/views/chart/mixin.py:86 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:338 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:274 +#: superset/connectors/sqla/views.py:362 superset/views/chart/mixin.py:86 msgid "Name" -msgstr "Название" +msgstr "Имя" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:779 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:785 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:762 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:768 msgid "Name is required" msgstr "Имя обязательно" #: superset/annotation_layers/commands/exceptions.py:66 -#: superset/reports/commands/exceptions.py:167 msgid "Name must be unique" msgstr "Имя должно быть уникальным" -#: superset/views/database/forms.py:380 -#, fuzzy +#: superset/views/database/forms.py:406 msgid "Name of table to be created from columnar data." -msgstr "Имя таблицы, которая будет сформирована из данных csv." - -#: superset/views/database/forms.py:96 -msgid "Name of table to be created from csv data." -msgstr "Имя таблицы, которая будет сформирована из данных csv." +msgstr "Имя таблицы, созданной из файла столбчатого формата." -#: superset/views/database/forms.py:247 +#: superset/views/database/forms.py:270 msgid "Name of table to be created from excel data." -msgstr "Имя таблицы, которая будет сформирована из данных csv." +msgstr "Имя таблицы, созданной из Excel файла." -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:61 +#: superset/views/database/forms.py:129 +msgid "Name of table to be created with CSV file" +msgstr "Имя таблицы, созданной из CSV файла." + +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:62 msgid "Name of the column containing the id of the parent node" -msgstr "" +msgstr "Имя столбца, содержащее id родительской вершины" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:51 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:52 msgid "Name of the id column" -msgstr "Столбцы Временных Рядов" +msgstr "Имя столбца id" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:53 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:54 msgid "Name of the source nodes" -msgstr "" +msgstr "Имя исходных вершин" -#: superset/connectors/sqla/views.py:439 +#: superset/connectors/sqla/views.py:429 msgid "Name of the table that exists in the source database" -msgstr "Имя таблицы, которая существует в исходной базе данных" +msgstr "Имя таблицы, которая существует в базе данных" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:63 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:64 msgid "Name of the target nodes" -msgstr "Владельцы датасета" +msgstr "Имя конечных вершин" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:51 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:66 msgid "Name your database" -msgstr "Назовите свой датасет" +msgstr "Дайте имя базе данных" -#: superset-frontend/src/chart/chartReducer.ts:106 -#: superset-frontend/src/chart/chartReducer.ts:170 -msgid "Network error." -msgstr "Ошибка сети." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:100 +msgid "Need help? Learn how to connect your database" +msgstr "Нужна помощь? Узнайте, как подключаться к вашей базе данных" -#: superset/templates/appbuilder/navbar_right.html:35 -msgid "New" -msgstr "Новый" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:146 +msgid "Need help? Learn more about" +msgstr "Нужна помощь? Узнайте больше о" -#: superset-frontend/src/components/ReportModal/index.tsx:251 -msgid "New Email Report" -msgstr "" +#: superset-frontend/src/utils/getClientErrorObject.ts:132 +msgid "Network error" +msgstr "Ошибка сети" + +#: superset-frontend/src/components/Chart/chartReducer.ts:107 +#: superset-frontend/src/components/Chart/chartReducer.ts:168 +msgid "Network error." +msgstr "Ошибка сети." -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:61 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:223 msgid "New chart" -msgstr "Переместить график" +msgstr "Новый график" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:614 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:776 #, python-format msgid "New columns added: %s" msgstr "Добавленные столбцы: %s" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx:81 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/index.tsx:36 +msgid "New dataset" +msgstr "Новый датасет" + +#: superset-frontend/src/views/CRUD/data/dataset/DuplicateDatasetModal.tsx:66 +msgid "New dataset name" +msgstr "Новое имя датасета" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx:90 msgid "New filter set" -msgstr "Настроить области действия фильтра" +msgstr "Новый набор фильтров" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:327 +#: superset-frontend/src/dashboard/util/newComponentFactory.js:49 +#, fuzzy +msgid "New header" +msgstr "Подзаголовок" + +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:320 msgid "New tab" -msgstr "Закрыть вкладку" +msgstr "Новая вкладка" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:420 +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:268 +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:310 msgid "New tab (Ctrl + q)" -msgstr "" +msgstr "Новая вкладка (CTRL + Q)" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:421 +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:269 +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:311 msgid "New tab (Ctrl + t)" -msgstr "" +msgstr "Новая вкладка (CTRL + T)" -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:133 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:113 +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:134 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:114 msgid "Next" -msgstr "След" +msgstr "Следующий" -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:29 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:32 msgid "Nightingale Rose Chart" -msgstr "Time Series - Nightingale Rose Chart" - -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:444 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:538 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:441 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:512 +msgstr "Диаграмма Найтингейл" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:89 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:108 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:127 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:145 +#: superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.tsx:143 +#: superset-frontend/src/pages/ChartList/index.tsx:569 +#: superset-frontend/src/pages/ChartList/index.tsx:678 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:462 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:544 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:465 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:485 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:577 msgid "No" msgstr "Нет" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:74 -#, python-format -msgid "No %(tableName)s yet" -msgstr "" - -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:376 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:440 #, python-format msgid "No %s yet" msgstr "Пока нет %s" @@ -8001,349 +9744,539 @@ msgstr "Пока нет %s" msgid "No Access!" msgstr "Нет доступа!" -#: superset-frontend/src/components/ListView/ListView.tsx:398 -#, fuzzy +#: superset-frontend/src/components/ListView/ListView.tsx:417 +#: superset-frontend/src/profile/components/RecentActivity.tsx:52 msgid "No Data" -msgstr "Метаданные" +msgstr "Нет данных" -#: superset-frontend/packages/superset-ui-core/src/chart/components/NoResultsComponent.tsx:75 -#, fuzzy +#: superset-frontend/packages/superset-ui-core/src/chart/components/NoResultsComponent.tsx:78 msgid "No Results" -msgstr "Посмотреть результаты" +msgstr "Нет результатов" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:328 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:114 +msgid "No annotation layers" +msgstr "Нет слоев аннотаций" + +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:314 msgid "No annotation layers yet" -msgstr "Слои аннотаций" +msgstr "Пока нет слоев аннотаций" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:254 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:242 msgid "No annotation yet" msgstr "Пока нет аннотаций" -#: superset-frontend/src/profile/components/CreatedContent.tsx:45 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx:186 +msgid "No applied filters" +msgstr "Фильтры не применены" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:148 +msgid "No available filters." +msgstr "Нет доступных фильтров." + +#: superset-frontend/src/profile/components/CreatedContent.tsx:61 msgid "No charts" -msgstr "Переместить график" +msgstr "Нет графиков" -#: superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx:82 +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:34 #, fuzzy +msgid "No charts yet" +msgstr "Нет графиков" + +#: superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx:86 msgid "No columns" -msgstr "столбец" +msgstr "Нет столбцов" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:134 -#, fuzzy, python-format +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:133 msgid "No compatible columns found" -msgstr "Несовместимые фильтры (%d)" +msgstr "Не найдено подходящих столбцов" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx:93 +#, fuzzy +msgid "No compatible datasets found" +msgstr "Не найдено подходящих столбцов" + +#: superset-frontend/src/components/DatabaseSelector/index.tsx:324 +#, fuzzy +msgid "No compatible schema found" +msgstr "Не найдено подходящих столбцов" -#: superset-frontend/src/profile/components/CreatedContent.tsx:63 +#: superset-frontend/src/profile/components/CreatedContent.tsx:91 msgid "No dashboards" msgstr "Нет дашбордов" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:189 -#: superset-frontend/src/explore/components/DataTablesPane/index.tsx:146 -#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:255 -#: superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx:91 +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:35 +#, fuzzy +msgid "No dashboards yet" +msgstr "Нет дашбордов" + +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:133 +#: superset-frontend/src/components/Table/index.tsx:261 +#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:263 +#: superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx:95 msgid "No data" -msgstr "Метаданные" +msgstr "Нет данных" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:219 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:171 msgid "No data after filtering or data is NULL for the latest time record" msgstr "" +"Нет данных после фильтрации или данные отсутствуют за последний отрезок " +"времени" -#: superset/dashboards/commands/importers/v0.py:321 +#: superset/dashboards/commands/importers/v0.py:304 msgid "No data in file" -msgstr "Нет данных в файле" +msgstr "В файле нет данных" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:752 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx:247 +msgid "No database tables found" +msgstr "Не найдено таблиц в базе данных" + +#: superset-frontend/src/components/EmptyState/index.tsx:234 +msgid "No databases match your search" +msgstr "Нет баз данных, удовлетворяющих вашему поиску" + +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:846 msgid "No description available." -msgstr "описание" +msgstr "Описание отсутствует." #: superset-frontend/src/profile/components/Favorites.tsx:46 msgid "No favorite charts yet, go click on stars!" -msgstr "В избранном нет графиков. Нажмите звёздочку для добавления!" +msgstr "" +"Пока нет избранных графиков, для добавления в избранное нажмите на " +"звездочку рядом с графиком" -#: superset-frontend/src/profile/components/Favorites.tsx:64 +#: superset-frontend/src/profile/components/Favorites.tsx:74 msgid "No favorite dashboards yet, go click on stars!" -msgstr "В избранном нет дашбордов. Нажмите звёздочку для добавления!" +msgstr "" +"Пока нет избранных дашбордов, для добавления в избранное нажмите на " +"звездочку рядом с дашбордом" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:313 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:948 #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:35 -#: superset-frontend/src/explore/controls.jsx:342 -#, fuzzy +#: superset-frontend/src/explore/controls.jsx:326 msgid "No filter" -msgstr "Добавить фильтр" +msgstr "Без фильтрации" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:483 +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:746 msgid "No filter is selected." msgstr "Не выбраны фильтры." -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:86 -#, fuzzy, python-format +#: superset-frontend/src/components/Table/index.tsx:258 +msgid "No filters" +msgstr "Нет фильтров" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx:247 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx:289 +msgid "No filters are currently added" +msgstr "Не применено ни одного фильтра" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx:121 +msgid "No filters are currently added to this dashboard." +msgstr "Не применено ни одного фильтра к данному дашборду." + +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:680 +msgid "No form settings were maintained" +msgstr "Конфигурация графика не сохранилась" + +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:201 +#, fuzzy +msgid "No matching records found" +msgstr "Записи не найдены" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:72 msgid "No of Bins" -msgstr "Копирование %s" +msgstr "Количество столбцов" -#: superset-frontend/src/SqlLab/components/QueryHistory/index.tsx:49 -msgid "No query history yet..." -msgstr "История запросов пуста…" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:36 +#, fuzzy +msgid "No recents yet" +msgstr "недавние(их)" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:494 +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:201 #: superset/templates/appbuilder/general/widgets/base_list.html:64 msgid "No records found" msgstr "Записи не найдены" -#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:400 +#: superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx:137 +#: superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx:64 +msgid "No results" +msgstr "Нет результатов" + +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/DashboardsSubMenu.tsx:127 +#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:425 msgid "No results found" msgstr "Записи не найдены" -#: superset-frontend/packages/superset-ui-core/src/chart/components/NoResultsComponent.tsx:63 +#: superset-frontend/src/components/ListView/ListView.tsx:408 +msgid "No results match your filter criteria" +msgstr "Не найдено результатов по вашим критериям" + +#: superset-frontend/src/components/Chart/ChartRenderer.jsx:279 +#: superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:133 +msgid "No results were returned for this query" +msgstr "Не было получено данных по этому запросу" + +#: superset-frontend/packages/superset-ui-core/src/chart/components/NoResultsComponent.tsx:65 msgid "" "No results were returned for this query. If you expected results to be " "returned, ensure any filters are configured properly and the datasource " "contains data for the selected time range." msgstr "" +"По этому запросу не было возвращено данных. Если вы ожидали увидеть " +"результаты, убедитесь, что все фильтры настроены правильно и источник " +"данных содержит записи для заданного временного интервала." + +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.tsx:291 +msgid "No rows were returned for this dataset" +msgstr "Не было получено данных для этого датасета" + +#: superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx:119 +msgid "No samples were returned for this dataset" +msgstr "Не было получено данных для этого датасета" + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:291 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:309 +msgid "No saved expressions found" +msgstr "Не найдено сохраненных выражений" -#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:133 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:376 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:384 +msgid "No saved metrics found" +msgstr "Не найдено сохраненных мер" + +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:37 +#, fuzzy +msgid "No saved queries yet" +msgstr "сохраненные(ых) запросы(ов)" + +#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:173 msgid "No stored results found, you need to re-run your query" -msgstr "Не найдены сохранённые результаты, необходимо повторно выполнить запрос" +msgstr "Не найдены сохраненные результаты, необходимо повторно выполнить запрос" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:268 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:338 msgid "No such column found. To filter on a metric, try the Custom SQL tab." msgstr "" -"Такой столбец не найден. Чтобы фильтровать по показателю, попробуйте " -"вкладку Через SQL." +"Такой столбец не найден. Чтобы фильтровать по мере, попробуйте " +"использовать вкладку Свой SQL." -#: superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx:81 +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx:67 #, fuzzy +msgid "No table columns" +msgstr "Нет столбцов формата дата/время" + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:290 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:308 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:343 +msgid "No temporal columns found" +msgstr "Столбцы формата дата/время не найдены" + +#: superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx:85 msgid "No time columns" -msgstr "Столбец с временем" +msgstr "Нет столбцов формата дата/время" + +#: superset/databases/commands/exceptions.py:152 +msgid "No validator found (configured for the engine)" +msgstr "Не найден валидатор (сконфигурированный для драйвера)" + +#: superset/databases/commands/validate_sql.py:114 +msgid "No validator named {} found (configured for the {} engine)" +msgstr "Не найден валидатор с именем {} (сконфигурированный для драйвера {})" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:155 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:156 msgid "Node label position" -msgstr "" +msgstr "Расположение метки вершины" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:182 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:183 msgid "Node select mode" -msgstr "Выполнить выбранный запрос" +msgstr "Режим выбора вершин" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:213 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:214 msgid "Node size" -msgstr "Размер маркера" +msgstr "Размер вершины" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:41 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:242 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:120 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:644 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:124 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx:41 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:187 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:270 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:286 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:253 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:135 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:182 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:402 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:182 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:243 +#: superset-frontend/plugins/plugin-chart-echarts/src/constants.ts:81 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:124 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx:83 +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:196 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:559 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:48 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/DashboardsSubMenu.tsx:138 +#: superset-frontend/src/explore/controlPanels/sections.tsx:134 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:120 msgid "None" -msgstr "" +msgstr "Пусто" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:129 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:130 msgid "None -> Arrow" -msgstr "" +msgstr "Ничего -> Стрелка" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:128 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:129 msgid "None -> None" -msgstr "" +msgstr "Ничего -> Ничего" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:43 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:77 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:77 msgid "Normal" -msgstr "" +msgstr "Обычный" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:165 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:166 msgid "Normalize Across" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:315 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:141 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:329 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:127 msgid "Normalized" -msgstr "" +msgstr "Нормализовать" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:81 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:74 msgid "Not Time Series" -msgstr "Изменить параметры шаблона" +msgstr "Не временные ряды" + +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:180 +msgid "Not added to any dashboard" +msgstr "Не добавлен ни в один дашборд" + +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.tsx:328 +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:191 +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:195 +msgid "Not available" +msgstr "Не доступно" + +#: superset-frontend/src/explore/constants.ts:60 +msgid "Not equal to (≠)" +msgstr "Не равно (≠)" + +#: superset-frontend/src/explore/constants.ts:72 +#, fuzzy +msgid "Not in" +msgstr "аннотация" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:116 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:113 msgid "Not null" msgstr "Не пусто" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:57 -#, fuzzy +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:66 msgid "Not triggered" -msgstr "Ничего не сработало" +msgstr "Условие не выполнялось" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:152 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:89 msgid "Not up to date" -msgstr "" +msgstr "Не актуально" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:87 #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:97 msgid "Nothing triggered" -msgstr "Ничего не сработало" +msgstr "Не срабатывало" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:260 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1348 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:303 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:423 msgid "Notification method" -msgstr "Добавить слой аннотации" +msgstr "Способ уведомления" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:76 msgid "November" msgstr "Ноябрь" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:92 -#, fuzzy +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:89 msgid "Now" -msgstr "Строка" +msgstr "Сейчас" + +#: superset/views/database/forms.py:201 +msgid "Null Values" +msgstr "Пустые значения" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:184 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:258 +msgid "Null imputation" +msgstr "Пустые значения" #: superset/datasets/filters.py:26 msgid "Null or Empty" -msgstr "Null или пусто" +msgstr "Null или Пусто" -#: superset/views/database/forms.py:233 superset/views/database/forms.py:366 +#: superset/views/database/forms.py:392 msgid "Null values" -msgstr "Значение фильтра" +msgstr "Пустые значения" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:191 -#, fuzzy msgid "Number Format" -msgstr "Формат D3" +msgstr "Числовой формат" + +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:307 +msgid "" +"Number bounds used for color encoding from red to blue.\n" +" Reverse the numbers for blue to red. To get pure red or " +"blue,\n" +" you can enter either only min or max." +msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:56 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:64 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:151 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:128 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:75 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:77 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:210 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:95 +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:60 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:65 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:144 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:117 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:67 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:67 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:99 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:112 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:149 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:120 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:137 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:113 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:97 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:276 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:136 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:111 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:145 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:119 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:136 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:129 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:112 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:317 msgid "Number format" -msgstr "Формат D3" +msgstr "Числовой формат" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:81 -msgid "Number of decimal digits to round numbers to" +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:323 +msgid "Number format string" +msgstr "Числовой формат" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:136 +msgid "Number of buckets to group data" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:100 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:70 +msgid "Number of decimal digits to round numbers to" +msgstr "Кол-во десятичных разрядов для округления числа" + +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:92 msgid "Number of decimal places with which to display lift values" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:87 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:79 msgid "Number of decimal places with which to display p-values" msgstr "" -#: superset/views/database/forms.py:194 superset/views/database/forms.py:335 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:251 +msgid "Number of periods to compare against" +msgstr "Количество периодов для сравнения" + +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:262 +msgid "Number of periods to ratio against" +msgstr "Количество периодов для сравнения" + +#: superset/views/database/forms.py:255 +msgid "Number of rows of file to read" +msgstr "Количество строк файла для чтения" + +#: superset/views/database/forms.py:361 msgid "Number of rows of file to read." msgstr "Количество строк файла для чтения." -#: superset/views/database/forms.py:188 superset/views/database/forms.py:329 +#: superset/views/database/forms.py:261 +msgid "Number of rows to skip at start of file" +msgstr "Количество строк для пропуска в начале файла" + +#: superset/views/database/forms.py:355 msgid "Number of rows to skip at start of file." -msgstr "Количество первых строк, которые нужно проигнорировать." +msgstr "Количество строк для пропуска в начале файла." -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:231 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:227 msgid "Number of split segments on the axis" -msgstr "" +msgstr "Количество разделенных сегментов на индикаторе" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:119 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:120 msgid "Number of steps to take between ticks when displaying the X scale" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:135 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:136 msgid "Number of steps to take between ticks when displaying the Y scale" msgstr "" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:295 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:316 msgid "Numerical range" -msgstr "Период времени" +msgstr "Числовой диапазон" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:100 msgid "OCT" msgstr "ОКТ" -#: superset-frontend/src/components/Modal/Modal.tsx:198 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:797 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:180 +#: superset-frontend/src/components/Modal/Modal.tsx:231 +#: superset-frontend/src/components/Table/index.tsx:256 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:848 msgid "OK" -msgstr "" +msgstr "ОК" -#: superset-frontend/src/components/ImportModal/index.tsx:210 +#: superset-frontend/src/components/ImportModal/index.tsx:209 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1206 msgid "OVERWRITE" -msgstr "OVERWRITE" +msgstr "ПЕРЕЗАПИСАТЬ" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:75 msgid "October" msgstr "Октябрь" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:93 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:163 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:144 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:178 msgid "Offline" -msgstr "" +msgstr "Оффлайн" -#: superset/connectors/sqla/views.py:496 +#: superset/connectors/sqla/views.py:486 msgid "Offset" msgstr "Смещение" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:58 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:67 msgid "On Grace" -msgstr "" - -#: superset/views/alerts.py:191 -msgid "" -"Once an alert is triggered, how long, in seconds, before Superset nags " -"you again." -msgstr "" -"После срабатывания оповещения, как долго Superset не должен надоедать " -"снова." +msgstr "На перерыве" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:33 #: superset-frontend/src/explore/controls.jsx:126 msgid "" "One or many columns to group by. High cardinality groupings should " "include a series limit to limit the number of fetched and rendered " "series." msgstr "" +"Один или несколько столбцов для группировки. Столбцы с множеством " +"уникальных значений должны включать порог количества категорий для " +"снижения нагрузку на базу данных и на ускорения отображения графика." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:105 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:73 msgid "" "One or many columns to group by. High cardinality groupings should " "include a sort by metric and series limit to limit the number of fetched " "and rendered series." msgstr "" +"Один или несколько столбцов для группировки. Столбцы с множеством " +"уникальных значений должны включать показатель для сортировки и порог " +"количества значений для снижения нагрузку на базу данных и на ускорения " +"отображения графика." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:56 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:215 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:111 msgid "One or many columns to pivot as columns" msgstr "" -"Выберите один или несколько срезов для отображения показателей в столбцах" -" сводной таблицы" +"Один или несколько столбцов, используемых в роли столбцов в сводной " +"таблице" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:323 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:328 msgid "" "One or many controls to group by. If grouping, latitude and longitude " "columns must be present." msgstr "" -#: superset-frontend/src/explore/controls.jsx:246 +#: superset-frontend/src/explore/controls.jsx:245 +#, fuzzy msgid "One or many controls to pivot as columns" msgstr "" -"Выберите один или несколько срезов для отображения показателей в столбцах" -" сводной таблицы" +"Выберите один или несколько ... для отображения показателей в столбцах " +"сводной таблицы" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:107 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:145 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:169 #: superset-frontend/src/explore/controls.jsx:162 msgid "One or many metrics to display" -msgstr "Выберите один или несколько показателей для отображения" +msgstr "Выберите одну или несколько мер для отображения" #: superset/datasets/commands/exceptions.py:90 msgid "One or more columns already exist" @@ -8351,7 +10284,7 @@ msgstr "Один или несколько столбцов уже сущест #: superset/datasets/commands/exceptions.py:80 msgid "One or more columns are duplicated" -msgstr "Один или несколько столбцов-дубликатов" +msgstr "Один или несколько столбцов дублируются" #: superset/datasets/commands/exceptions.py:70 msgid "One or more columns do not exist" @@ -8359,122 +10292,121 @@ msgstr "Один или несколько столбцов не существ #: superset/datasets/commands/exceptions.py:119 msgid "One or more metrics already exist" -msgstr "Выберите один или несколько показателей для отображения" +msgstr "Одна или несколько мер уже существуют" #: superset/datasets/commands/exceptions.py:109 msgid "One or more metrics are duplicated" -msgstr "Выберите один или несколько показателей для отображения" +msgstr "Одна или несколько мер дублируются" #: superset/datasets/commands/exceptions.py:99 msgid "One or more metrics do not exist" -msgstr "Выберите один или несколько показателей для отображения" +msgstr "Одна или несколько мер не существуют" -#: superset/errors.py:113 -#, fuzzy +#: superset/errors.py:119 msgid "One or more parameters needed to configure a database are missing." msgstr "" -"Проблема 1006 - Отсутствуют один или несколько параметров, используемых в" -" запросе." +"Один или несколько параметров, необходимых для настройки базы данных, " +"отсутствуют" -#: superset/errors.py:127 -#, fuzzy +#: superset/errors.py:133 msgid "One or more parameters specified in the query are malformatted." msgstr "" -"Проблема 1006 - Отсутствуют один или несколько параметров, используемых в" -" запросе." +"Один или несколько параметров, указанных в запросе, неверно " +"отформатированы" -#: superset/errors.py:101 -#, fuzzy +#: superset/errors.py:107 msgid "One or more parameters specified in the query are missing." -msgstr "" -"Проблема 1006 - Отсутствуют один или несколько параметров, используемых в" -" запросе." +msgstr "Один или несколько параметров, указанных в запросе, отсутствуют" -#: superset/views/core.py:2075 +#: superset/views/core.py:1970 msgid "" "One or more required fields are missing in the request. Please try again," " and if the problem persists conctact your administrator." msgstr "" -#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:46 +#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:59 msgid "One ore more annotation layers failed loading." msgstr "Один или несколько слоев аннотации не удалось загрузить." -#: superset/sql_lab.py:201 -#, fuzzy +#: superset/sql_lab.py:230 msgid "Only SELECT statements are allowed against this database." -msgstr "Для этой БД разрешены только выражения `SELECT`" +msgstr "Только SELECT запросы доступны для этой базы данных." -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:128 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:130 msgid "Only Total" -msgstr "" +msgstr "Только общий итог" -#: superset/connectors/sqla/utils.py:96 +#: superset/connectors/sqla/utils.py:122 msgid "Only `SELECT` statements are allowed" -msgstr "Допустимы только выражения `SELECT`" +msgstr "Доступны только SELECT запросы" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:131 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:130 msgid "Only selected panels will be affected by this filter" msgstr "Фильтр будет применён только к выбранным панелям" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:131 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:133 msgid "" "Only show the total value on the stacked chart, and not show on the " "selected category" msgstr "" +"Показывать только общий итог для столбцов с накоплением, и не показывать " +"промежуточные итоги для каждой категории внутри столбца." -#: superset/connectors/sqla/utils.py:105 +#: superset/connectors/sqla/utils.py:131 msgid "Only single queries supported" msgstr "Поддерживаются только одиночные запросы" -#: superset/views/database/forms.py:111 superset/views/database/forms.py:262 -#: superset/views/database/forms.py:397 +#: superset/views/database/forms.py:119 superset/views/database/forms.py:288 +#: superset/views/database/forms.py:426 #, python-format msgid "Only the following file extensions are allowed: %(allowed_extensions)s" -msgstr "Разрешены файлы только в следующих расширениях: %(allowed_extensions)s" +msgstr "Доступные расширения файлов: %(allowed_extensions)s" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:236 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:196 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:636 +#: superset-frontend/packages/superset-ui-core/src/chart/components/FallbackComponent.tsx:45 +msgid "Oops! An error occurred!" +msgstr "Произошла ошибка!" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:248 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:119 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:198 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:684 msgid "Opacity" msgstr "Прозрачность" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:137 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:152 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:155 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:96 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:112 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:109 msgid "Opacity of Area Chart. Also applies to confidence band." msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:239 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:251 msgid "Opacity of all clusters, points, and labels. Between 0 and 1." -msgstr "" +msgstr "Непрозрачность всех кластеров, точек и меток. Между 0 и 1." -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:202 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:204 msgid "Opacity of area chart." -msgstr "" +msgstr "Непрозрачность диаграммы областей" -#: superset-frontend/src/explore/components/ExploreViewContainer.jsx:550 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:125 +msgid "Opacity, expects values between 0 and 100" +msgstr "Непрозрачность, принимаются значения от 0 до 100" + +#: superset-frontend/src/explore/components/ExploreViewContainer/index.jsx:643 msgid "Open Datasource tab" msgstr "Открыть вкладку источника данных" -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:141 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:121 +#: superset-frontend/src/explore/components/controls/ViewQueryModalFooter.tsx:38 +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:142 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:122 msgid "Open in SQL Lab" msgstr "Открыть в SQL редакторе" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:317 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:335 msgid "Open query in SQL Lab" msgstr "Открыть в SQL редакторе" -#: superset/views/database/mixins.py:105 -msgid "" -"Operate the database in asynchronous mode, meaning that the queries are " -"executed on remote workers as opposed to on the web server itself. This " -"assumes that you have a Celery worker setup as well as a results backend." -" Refer to the installation docs for more information." -msgstr "" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:288 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:298 +#: superset/views/database/mixins.py:104 msgid "" "Operate the database in asynchronous mode, meaning that the queries are " "executed on remote workers as opposed to on the web server itself. This " @@ -8483,429 +10415,538 @@ msgid "" msgstr "" "Работа с базой данных в асинхронном режиме означает, что запросы " "исполняются на удалённых воркерах, а не на веб-сервере Superset. Это " -"подразумевает, что у вас установка с воркерами Celery. Обратитесь к " +"подразумевает, что у вас есть установка с воркерами Celery. Обратитесь к " "документации по настройке за дополнительной информацией." -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:125 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:126 #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:130 -#, fuzzy, python-format msgid "Operator" -msgstr "%s параметр(ы)" +msgstr "Оператор" -#: superset/utils/pandas_postprocessing.py:175 +#: superset/utils/pandas_postprocessing/utils.py:158 #, python-format msgid "Operator undefined for aggregator: %(name)s" -msgstr "" +msgstr "Оператор не определен для агрегатора: %(name)s" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:361 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:371 msgid "" "Optional CA_BUNDLE contents to validate HTTPS requests. Only available on" " certain database engines." msgstr "" +"Необязательное содержимое CA_BUNDLE для валидации HTTPS запросов. " +"Доступно только в определенных драйверах баз данных" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:73 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:329 +msgid "Optional d3 date format string" +msgstr "Формат временной строки" + +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:318 +msgid "Optional d3 number format string" +msgstr "Формат числовой строки" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:74 msgid "Optional name of the data column." -msgstr "" +msgstr "Необязательное имя столбца данныхэ" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1135 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:977 msgid "" "Optional time column if time range should apply to another column than " "the default time column" msgstr "" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1092 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1242 msgid "Optional warning about use of this metric" +msgstr "Необязательное предупреждение об использовании этой меры" + +#: superset/connectors/sqla/views.py:329 +msgid "Optionally add a detailed description" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:49 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:75 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:119 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:72 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:39 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:37 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:105 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:198 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:363 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:48 -#, fuzzy, python-format +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:39 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:68 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:108 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:74 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:45 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx:70 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:167 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:263 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:374 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:52 +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:67 msgid "Options" -msgstr "%s параметр(ы)" +msgstr "Опции" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:668 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:868 msgid "Or choose from a list of other databases we support:" -msgstr "" +msgstr "Или выберите из списка других поддерживаемых баз данных:" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:63 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:62 msgid "Order by entity id" msgstr "" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:272 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/orderBy.tsx:29 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:278 msgid "Order results by selected columns" -msgstr "" +msgstr "Упорядочить результаты по выбранным столбцам" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:271 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/orderBy.tsx:28 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:277 msgid "Ordering" -msgstr "Сортировать" +msgstr "Упорядочивание" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:142 -msgid "Orientation of tree" -msgstr "" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:81 +msgid "Orientation" +msgstr "Ориентация" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:27 -#: superset-frontend/src/explore/constants.ts:116 -msgid "Origin" -msgstr "Источник" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:282 +msgid "Orientation of bar chart" +msgstr "Ориентация диаграммы" -#: superset-frontend/src/explore/components/ExportToCSVDropdown/index.tsx:74 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx:158 #, fuzzy +msgid "Orientation of filter bar" +msgstr "Ориентация дерева" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:143 +msgid "Orientation of tree" +msgstr "Ориентация дерева" + +#: superset-frontend/src/explore/components/ExportToCSVDropdown/index.tsx:75 msgid "Original" -msgstr "Источник" +msgstr "Исходные данные" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:183 +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:212 msgid "Original table column order" msgstr "Расположение столбцов как в исходной таблице" #: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:29 -#: superset/db_engine_specs/base.py:85 +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.tsx:135 +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:143 +#: superset-frontend/src/explore/controls.jsx:79 msgid "Original value" -msgstr "" +msgstr "Исходное значение" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:120 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:121 +#, fuzzy msgid "Orthogonal" -msgstr "" +msgstr "Перпендикулярно" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:120 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:687 -#, fuzzy +# здесь идет речь про прочие категории графиков, помимо основных категорий +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:126 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:443 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:888 +#: superset/views/database/forms.py:155 superset/views/database/forms.py:161 msgid "Other" -msgstr "месяц" +msgstr "Прочее" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:236 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:379 +msgid "Outdoors" +msgstr "Туристический режим" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:193 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:205 msgid "Outer Radius" -msgstr "" +msgstr "Внешний радиус" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:199 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:211 msgid "Outer edge of Pie chart" -msgstr "Идентификатор активного среза" +msgstr "Внешний радиус круговой диаграммы" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:257 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:253 msgid "Overlap" -msgstr "Карта Мира" +msgstr "Перекрывание" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:107 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:322 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:205 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:455 -#: superset-frontend/src/explore/controlPanels/sections.tsx:220 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:123 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:199 msgid "" "Overlay one or more timeseries from a relative time period. Expects " "relative time deltas in natural language (example: 24 hours, 7 days, 52 " "weeks, 365 days). Free text is supported." msgstr "" +"Наложение одной или нескольких временных рядов из относительного периода " +"времени." + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:317 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:467 +#: superset-frontend/src/explore/controlPanels/sections.tsx:195 +#, fuzzy +msgid "" +"Overlay one or more timeseries from a relative time period. Expects " +"relative time deltas in natural language (example: 24 hours, 7 days, 52 " +"weeks, 365 days). Free text is supported." +msgstr "" +"Наложение одной или нескольких временных рядов из относительного периода " +"времени." + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:27 +msgid "" +"Overlays a hexagonal grid on a map, and aggregates data within the " +"boundary of each cell." +msgstr "" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:600 +msgid "Override time grain" +msgstr "Переопределить единицу времени" -#: superset-frontend/src/components/ImportModal/index.tsx:282 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:582 +msgid "Override time range" +msgstr "Переопределить временной интервал" + +#: superset-frontend/src/components/ImportModal/index.tsx:281 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:492 +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:458 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:464 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx:148 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx:245 msgid "Overwrite" msgstr "Перезаписать" -#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:120 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:246 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:193 msgid "Overwrite & Explore" msgstr "Перезаписать и исследовать" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:191 +#: superset-frontend/src/dashboard/components/SaveModal.tsx:183 #, python-format msgid "Overwrite Dashboard [%s]" msgstr "Перезаписать дашборд [%s]" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:264 +#: superset/views/database/forms.py:237 +msgid "Overwrite Duplicate Columns" +msgstr "Перезаписать повторяющиеся столбцы" + +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:404 +msgid "Overwrite existing" +msgstr "Перезаписать существующий" + +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:272 msgid "Overwrite text in the editor with a query on this table" -msgstr "Перезаписать текст в редакторе с запросом к этой таблице" +msgstr "Вставить этот запрос в редактор SQL" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:453 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:450 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:417 +#: superset-frontend/src/pages/ChartList/index.tsx:578 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:453 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:478 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:504 msgid "Owner" msgstr "Владелец" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:234 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:399 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:355 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:358 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:402 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:405 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:168 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:276 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1079 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1084 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:334 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:334 -#: superset/connectors/druid/views.py:346 superset/connectors/sqla/views.py:500 -#: superset/views/chart/mixin.py:83 superset/views/dashboard/mixin.py:82 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:235 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:561 +#: superset-frontend/src/components/MetadataBar/ContentConfig.tsx:93 +#: superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx:406 +#: superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx:420 +#: superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx:439 +#: superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx:453 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:407 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:410 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:454 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:457 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:174 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:325 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:397 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:349 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:393 +#: superset/connectors/sqla/views.py:490 superset/views/chart/mixin.py:83 +#: superset/views/dashboard/mixin.py:82 msgid "Owners" msgstr "Владельцы" -#: superset/commands/exceptions.py:105 +#: superset/commands/exceptions.py:108 #: superset/datasets/commands/exceptions.py:144 msgid "Owners are invalid" -msgstr "Владельцы недействительны" +msgstr "Неверный список владельцев" #: superset/views/dashboard/mixin.py:65 msgid "Owners is a list of users who can alter the dashboard." -msgstr "Владельцы - это пользователи, которые могут изменять дашборд." +msgstr "Владельцы – это список пользователей, которые могут изменять дашборд." -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:367 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:414 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:421 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:468 msgid "" "Owners is a list of users who can alter the dashboard. Searchable by name" " or username." -msgstr "Владельцы - это список пользователей, которые могут изменять дашборд." +msgstr "" +"Владельцы – это список пользователей, которые могут изменять дашборд. " +"Можно искать по имени или никнейму." -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:388 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:399 msgid "Page length" -msgstr "" +msgstr "Размер страницы" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:29 msgid "Paired t-test Table" -msgstr "" - -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:177 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:388 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:271 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:516 -#: superset-frontend/src/explore/controlPanels/sections.tsx:278 +msgstr "Таблица парного t-теста" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:193 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:380 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:262 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:534 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:267 +#: superset-frontend/src/explore/controlPanels/sections.tsx:258 msgid "Pandas resample method" -msgstr "" -"Одна из функций (Resample) библиотеки Pandas, которая определяет метод " -"обработки данных" +msgstr "Метод ресемплирования данных библиотеки Pandas" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:156 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:370 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:253 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:496 -#: superset-frontend/src/explore/controlPanels/sections.tsx:260 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:172 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:362 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:244 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:514 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:245 +#: superset-frontend/src/explore/controlPanels/sections.tsx:240 msgid "Pandas resample rule" -msgstr "" -"Одна из функций (Resample) библиотеки Pandas, которая определяет период, " -"к которому применяется функция агрегации" +msgstr "Правило ресемплирования данных библиотеки Pandas" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:30 -#: superset/viz.py:2182 +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:33 +#: superset/viz.py:2216 msgid "Parallel Coordinates" msgstr "" #: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:116 msgid "Parameter error" -msgstr "Параметры" +msgstr "Ошибка параметра" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:64 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:56 #: superset/views/chart/mixin.py:84 msgid "Parameters" msgstr "Параметры" -#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:103 -#, fuzzy +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:108 msgid "Parameters " -msgstr "Параметры" +msgstr "Параметры " -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:60 -msgid "Parent" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:295 +msgid "Parameters related to the view and perspective on the map" msgstr "" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:643 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1037 -msgid "Parent filter" -msgstr "Временной фильтр" - -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1045 -#, fuzzy -msgid "Parent filter is required" -msgstr "Тип обязателен" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:61 +msgid "Parent" +msgstr "Родитель" -#: superset/views/database/forms.py:203 superset/views/database/forms.py:340 +#: superset/views/database/forms.py:366 msgid "Parse Dates" -msgstr "Разбор Дат" +msgstr "Парсинг дат" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:25 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:26 #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:26 #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:29 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:51 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts:35 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:33 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:50 msgid "Part of a Whole" -msgstr "" +msgstr "Покомпонентное сравнение" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:27 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:29 #, fuzzy msgid "Partition Chart" msgstr "Partition Diagram" -#: superset/viz.py:3035 +#: superset/viz.py:3069 +#, fuzzy msgid "Partition Diagram" msgstr "Partition Diagram" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:176 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:169 msgid "Partition Limit" -msgstr "Partition Diagram" +msgstr "Количество разбиений" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:189 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:182 msgid "Partition Threshold" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:192 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:185 msgid "" "Partitions whose height to parent height proportions are below this value" " are pruned" msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:130 -#: superset/db_engine_specs/base.py:1389 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:154 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:168 +#: superset/db_engine_specs/base.py:1734 msgid "Password" -msgstr "Пароль брокера" +msgstr "Пароль" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:221 +msgid "Paste Private Key here" +msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:79 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:120 +#, fuzzy +msgid "Paste content of service credentials JSON file here" +msgstr "Скопировать и вставить .json файл сервисного аккаунта сюда" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:87 msgid "Paste the shareable Google Sheet URL here" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:35 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:37 #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:35 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:38 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:46 -#, fuzzy msgid "Pattern" -msgstr "Обновить" +msgstr "Паттерн" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:108 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:101 msgid "Percent Change" -msgstr "Изменения не сохранены" +msgstr "Процентное изменение" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:147 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:53 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:90 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:104 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:66 +msgid "Percentage" +msgstr "Процентная доля" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:142 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:334 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:216 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:486 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:67 +#: superset-frontend/src/explore/controlPanels/sections.tsx:212 +msgid "Percentage change" +msgstr "Процентное изменение" + +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx:33 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:125 msgid "Percentage metrics" -msgstr "Показатель для сортировки" +msgstr "Процентные меры" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:145 msgid "Percentage threshold" -msgstr "" +msgstr "Процентный порог" #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:41 #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:45 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:39 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:44 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:49 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:42 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:38 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:43 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:40 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:51 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:41 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:69 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:63 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:33 -#, fuzzy +#: superset-frontend/src/visualizations/TimeTable/index.ts:36 msgid "Percentages" -msgstr "Последние" +msgstr "Проценты" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:219 +msgid "Performance" +msgstr "Производительность" + +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:74 +msgid "Period average" +msgstr "Среднее за период" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:56 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:278 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:161 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:179 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:410 -#: superset-frontend/src/explore/controlPanels/sections.tsx:177 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:271 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:153 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:420 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:200 +#: superset-frontend/src/explore/controlPanels/sections.tsx:150 msgid "Periods" -msgstr "Период" +msgstr "Периоды" -#: superset/utils/pandas_postprocessing.py:824 -msgid "Periods must be a positive integer value" -msgstr "Периоды должны быть положительными делами числами" +#: superset/utils/pandas_postprocessing/prophet.py:126 +msgid "Periods must be a whole number" +msgstr "Периоды должны быть целым числом" -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:258 -#, fuzzy +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:271 msgid "Person or group that has certified this chart." -msgstr "Лицо или группа, которые сертифицировали данный показатель" +msgstr "Лицо или группа, которые утвердили этот график" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:548 -#, fuzzy +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:617 msgid "Person or group that has certified this dashboard." -msgstr "Лицо или группа, которые сертифицировали данный показатель" +msgstr "Лицо или группа, которые утвердили этот дашборд" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:260 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1068 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:327 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1218 msgid "Person or group that has certified this metric" -msgstr "Лицо или группа, которые сертифицировали данный показатель" +msgstr "Лицо или группа, которые утвердили этот показатель" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:936 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1108 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:564 msgid "Physical" -msgstr "" +msgstr "Физический" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:132 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:144 msgid "Physical (table or view)" msgstr "Физический (таблица или представление)" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:223 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:277 msgid "Physical dataset" msgstr "Физический датасет" -#: superset/viz.py:742 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:106 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:143 +msgid "Pick a dimension from which categorical colors are defined" +msgstr "Выберите измерение, на основе которого определяются категориальные цвета" + +#: superset/viz.py:766 msgid "Pick a granularity in the Time section or uncheck 'Include Time'" msgstr "" -"Выберите столбец с датой и необходимый период в секции «Время» или " -"снимите флажок «Включая дату»" +"Выберите степень детализации в разделе Время или снимите флажок " +"\"Включить время\"." -#: superset/viz.py:1573 +#: superset/viz.py:1602 msgid "Pick a metric for left axis!" -msgstr "Выберите значение для левой оси!" +msgstr "Выберите меру для левой оси" -#: superset/viz.py:1575 +#: superset/viz.py:1604 msgid "Pick a metric for right axis!" -msgstr "Выберите значение для правой оси!" +msgstr "Выберите меру для правой оси" -#: superset/viz.py:1163 +#: superset/viz.py:1192 msgid "Pick a metric for x, y and size" -msgstr "Выберите срез для X, Y и размер" +msgstr "Выберите меру для x, y и размера" -#: superset/viz.py:1202 +#: superset/viz.py:1231 msgid "Pick a metric to display" -msgstr "Выберите показатель для отображения" +msgstr "Выберите меру для отображения" -#: superset/viz.py:1228 superset/viz.py:1262 +#: superset/viz.py:1257 superset/viz.py:1291 msgid "Pick a metric!" -msgstr "Выберите показатель!" +msgstr "Выберите меру!" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:56 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:71 msgid "Pick a name to help you identify this database." -msgstr "" +msgstr "Выберите имя для базы данных." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:151 -msgid "Pick a nickname for this database to display as in Superset." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:196 +msgid "Pick a nickname for how the database will display in Superset." +msgstr "Выберите имя для базы данных, которое будет отображаться в Суперсете." + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:40 +msgid "Pick a set of deck.gl charts to layer on top of one another" msgstr "" -#: superset/viz.py:1358 superset/viz.py:1621 +#: superset/viz.py:1387 superset/viz.py:1650 msgid "Pick a time granularity for your time series" -msgstr "Выберите период для временных рядов" +msgstr "Выберите временную детализацию для вашего временного ряда" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:510 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:558 msgid "Pick a title for you annotation." -msgstr "" +msgstr "Выберите название для вашей аннотации" -#: superset/viz.py:1783 +#: superset/viz.py:1812 msgid "Pick at least one field for [Series]" -msgstr "Выберите хотя бы одно значение для поля [Столбцы данных]" +msgstr "" -#: superset/viz.py:830 superset/viz.py:1781 +#: superset/viz.py:854 superset/viz.py:1810 msgid "Pick at least one metric" -msgstr "Выберите хотя бы один показатель" +msgstr "Выберите хотя бы одну меру" -#: superset/viz.py:1911 +#: superset/viz.py:1940 msgid "Pick exactly 2 columns as [Source / Target]" -msgstr "Выберите ровно два среза в поле [Источник / Назначение]" +msgstr "" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:521 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:569 msgid "" "Pick one or more columns that should be shown in the annotation. If you " "don't select a column all of them will be shown." msgstr "" +"Выберите один или несколько столбцов, которые должны отображаться в " +"аннотации. Если вы не выберите столбец, все столбцы будут отображены." #: superset-frontend/src/explore/controlPanels/Separator.js:37 msgid "Pick your favorite markup language" @@ -8913,209 +10954,282 @@ msgstr "Выберите свой любимый язык разметки" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/index.js:27 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:63 -#, fuzzy msgid "Pie Chart" -msgstr "Переместить график" +msgstr "Круговая диаграмма" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:187 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:199 msgid "Pie shape" -msgstr "Посмотреть примеры" +msgstr "Форма круговой диаграммы" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:234 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:235 msgid "Pin" -msgstr "в" +msgstr "Закрепить" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:56 -#, fuzzy, python-format +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:45 msgid "Pivot Options" -msgstr "%s параметр(ы)" +msgstr "Параметры сводной таблицы" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:30 -#: superset/viz.py:862 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:56 +#: superset/viz.py:891 msgid "Pivot Table" -msgstr "Pivot Table" +msgstr "Сводная таблица" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:54 -#, fuzzy -msgid "Pivot Table v2" -msgstr "Pivot Table" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:32 +msgid "Pivot Table (legacy)" +msgstr "Сводная таблица (устарело)" -#: superset/utils/pandas_postprocessing.py:260 +#: superset/utils/pandas_postprocessing/pivot.py:70 msgid "Pivot operation must include at least one aggregate" msgstr "" -#: superset/utils/pandas_postprocessing.py:256 +#: superset/utils/pandas_postprocessing/pivot.py:66 msgid "Pivot operation requires at least one index" msgstr "" -#: superset-frontend/src/explore/components/ExportToCSVDropdown/index.tsx:80 -#, fuzzy +#: superset-frontend/src/explore/components/ExportToCSVDropdown/index.tsx:81 msgid "Pivoted" -msgstr "Редактировано" +msgstr "Сводные данные" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:83 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:75 msgid "Pixel height of each series" +msgstr "Высота каждого ряда (в пикселях)" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:143 +msgid "Pixels" +msgstr "Пиксели" + +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:66 +msgid "Plain" +msgstr "Отобразить все" + +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:667 +msgid "Please DO NOT overwrite the \"filter_scopes\" key." msgstr "" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:28 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:26 msgid "Please apply filter changes" -msgstr "" +msgstr "Пожалуйста, примените изменения фильтров" -#: superset/sqllab/query_render.py:116 +#: superset/sqllab/query_render.py:121 msgid "" "Please check your query and confirm that all template parameters are " "surround by double braces, for example, \"{{ ds }}\". Then, try running " "your query again." msgstr "" +"Пожалуйста, проверьте ваш запрос и подтвердите, что все параметры шаблона" +" заключены в двойные фигурные скобки, например, \"{{ from_dttm }}\". " +"Затем попробуйте повторно выполнить запрос." -#: superset/db_engine_specs/athena.py:55 -#: superset/db_engine_specs/bigquery.py:179 -#: superset/db_engine_specs/postgres.py:158 -#: superset/db_engine_specs/snowflake.py:104 +#: superset/db_engine_specs/athena.py:56 +#: superset/db_engine_specs/bigquery.py:191 +#: superset/db_engine_specs/postgres.py:140 +#: superset/db_engine_specs/snowflake.py:113 #, python-format msgid "" "Please check your query for syntax errors at or near " "\"%(syntax_error)s\". Then, try running your query again." msgstr "" +"Пожалуйста, проверьте ваш запрос на синтаксические ошибки возле символа " +"\"%(syntax_error)s\". Затем выполните запрос заново." -#: superset/db_engine_specs/gsheets.py:74 superset/db_engine_specs/mysql.py:144 +#: superset/db_engine_specs/gsheets.py:80 superset/db_engine_specs/mysql.py:168 #, python-format msgid "" "Please check your query for syntax errors near \"%(server_error)s\". " "Then, try running your query again." msgstr "" +"Пожалуйста, проверьте ваш запрос на наличие синтаксических ошибок рядом с" +" \"%(server_error)s\". Затем выполните запрос заново" + +#: superset/sqllab/query_render.py:38 superset/views/core.py:197 +msgid "" +"Please check your template parameters for syntax errors and make sure " +"they match across your SQL query and Set Parameters. Then, try running " +"your query again." +msgstr "" +"Пожалуйста, проверьте параметры вашего шаблона на наличие синтаксических " +"ошибок и убедитесь, что они совпадают с вашим SQL-запросом и заданными " +"параметрами. Затем попробуйте выполнить свой запрос еще раз." -#: superset/viz.py:879 -msgid "Please choose at least one 'Group by' field " -msgstr "Пожалуйста, выберите хотя бы один срез в поле ‘Группировка’ " +#: superset/viz.py:908 +msgid "Please choose at least one 'Group by' field" +msgstr "Выберите хотя бы одно поле \"Группировать по\"" -#: superset/viz.py:891 +#: superset/viz.py:3227 +#, fuzzy +msgid "Please choose at least one groupby" +msgstr "Выберите хотя бы одно поле \"Группировать по\"" + +#: superset/viz.py:920 msgid "Please choose at least one metric" -msgstr "Пожалуйста, выберите хотя бы один показатель" +msgstr "Выберите хотя бы одну меру" -#: superset/viz.py:1578 +#: superset/viz.py:1607 msgid "Please choose different metrics on left and right axis" -msgstr "Пожалуйста, выберите разные срезы данных для левой и правой оси" +msgstr "Выберите разные меры для левой и правой осей" + +#: superset-frontend/src/pages/ChartList/ChartCard.tsx:80 +#: superset-frontend/src/pages/ChartList/index.tsx:476 +#: superset-frontend/src/pages/ChartList/index.tsx:796 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:584 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:297 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:357 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:327 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:104 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:370 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:650 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:768 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:503 +msgid "Please confirm" +msgstr "Пожалуйста, подтвердите действие" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:94 -msgid "Please complete all required fields." +#: superset-frontend/src/dashboard/actions/dashboardState.js:442 +msgid "Please confirm the overwrite values." msgstr "" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:485 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:300 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:365 -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:77 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:357 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:644 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:325 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:105 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:355 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:611 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:617 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:499 -msgid "Please confirm" -msgstr "Пожалуйста, подтвердите" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:485 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:597 msgid "Please enter a SQLAlchemy URI to test" -msgstr "Введите SQLAlchemy URI для теста" - -#: superset-frontend/src/explore/components/SaveModal.tsx:133 -msgid "Please enter a chart name" -msgstr "Введите имя графика" +msgstr "Введите SQLAlchemy URI для тестирования" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:81 -#, fuzzy msgid "Please filter set name" -msgstr "Введите имя графика" +msgstr "Введите имя набора фильтров" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:122 -msgid "Please make sure all fields are filled out correctly" -msgstr "" - -#: superset/db_engine_specs/postgres.py:122 +#: superset/db_engine_specs/postgres.py:104 msgid "Please re-enter the password." +msgstr "Пожалуйста, введите пароль еще раз" + +#: superset-frontend/src/views/CRUD/hooks.ts:423 +msgid "Please re-export your file and try importing again" msgstr "" #: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:59 #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:72 msgid "Please reach out to the Chart Owner for assistance." -msgstr "Пожалуйста, обратитесь к создателю графика за дополнительной информацией." +msgid_plural "Please reach out to the Chart Owners for assistance." +msgstr[0] "Пожалуйста, обратитесь к создателю графика за помощью." +msgstr[1] "Пожалуйста, обратитесь к создателям графика за помощью." +msgstr[2] "Пожалуйста, обратитесь к создателям графика за помощью." -#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:75 +#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:85 msgid "Please save the query to enable sharing" -msgstr "Пожалуйста, сохраните запрос, чтобы включить функцию “поделиться”" +msgstr "Пожалуйста, сохраните запрос, чтобы включить функцию \"поделиться\"" -#: superset/reports/commands/exceptions.py:90 +#: superset/reports/commands/exceptions.py:105 msgid "Please save your chart first, then try creating a new email report." msgstr "" +"Пожалуйста, сначала сохраните график перед тем, как создавать новую " +"рассылку." -#: superset/reports/commands/exceptions.py:102 +#: superset/reports/commands/exceptions.py:117 msgid "Please save your dashboard first, then try creating a new email report." msgstr "" +"Пожалуйста, сначала сохраните дашборд перед тем, как создавать новую " +"рассылку." -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:322 +#: superset-frontend/src/pages/ChartCreation/index.tsx:415 msgid "Please select both a Dataset and a Chart type to proceed" -msgstr "" +msgstr "Пожалуйста, для продолжения выберите и датасет, и тип графика" -#: superset/viz.py:1161 +#: superset/viz.py:1190 msgid "Please use 3 different metric labels" -msgstr "Пожалуйста, выберите разные срезы данных для левой и правой оси" +msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:104 -msgid "Please verify that port is open to connect." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:27 +msgid "Plot the distance (like flight paths) between origin and destination." msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:27 +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:29 msgid "" "Plots the individual metrics for each row in the data vertically and " "links them together as a line. This chart is useful for comparing " "multiple metrics across all of the samples or rows in the data." msgstr "" -#: superset/initialization/__init__.py:254 +#: superset/initialization/__init__.py:271 msgid "Plugins" msgstr "Плагины" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:108 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:132 +msgid "Point Color" +msgstr "Цвет маркера" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:118 msgid "Point Radius" -msgstr "" +msgstr "Радиус маркера" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts:80 +msgid "Point Radius Scale" +msgstr "Шкала радиуса маркера" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:132 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:140 msgid "Point Radius Unit" -msgstr "" +msgstr "Единица измерения радиуса маркера" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:101 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:71 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:320 +msgid "Point Size" +msgstr "Размер маркера" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:79 +msgid "Point Unit" +msgstr "Единица измерения маркера" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:66 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:309 +msgid "Point to your spatial columns" +msgstr "Указание на столбцы с расположением" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:111 msgid "Points" -msgstr "Компоненты" +msgstr "Маркеры" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:201 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:213 msgid "Points and clusters will update as the viewport is being changed" -msgstr "" +msgstr "Точки и кластеры будут обновляться по мере изменения области просмотра" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:68 +#, fuzzy +msgid "Polygon Column" +msgstr "столбец" -#: superset/views/sql_lab.py:74 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:77 +#, fuzzy +msgid "Polygon Encoding" +msgstr "Выполняется рассылка" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:106 +msgid "Polygon Settings" +msgstr "Настройки полигона" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts:55 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:350 +#, fuzzy +msgid "Polyline" +msgstr "Линия" + +#: superset/views/sql_lab/views.py:87 +#, fuzzy msgid "Pop Tab Link" -msgstr "Открыть" +msgstr "Скопировать ссылку" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:44 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:40 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:46 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:52 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:42 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:70 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:85 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:86 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:77 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:78 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:89 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:85 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:57 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:47 -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:124 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:130 msgid "Popular" -msgstr "" +msgstr "Популярно" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:170 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:173 msgid "Populate \"Default value\" to enable this control" msgstr "" @@ -9123,85 +11237,77 @@ msgstr "" msgid "Population age data" msgstr "" -#: superset/db_engine_specs/mssql.py:87 -#: superset/db_engine_specs/postgres.py:132 -#: superset/db_engine_specs/presto.py:213 -#: superset/db_engine_specs/redshift.py:73 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:69 +msgid "Port" +msgstr "Порт" + +#: superset/db_engine_specs/mssql.py:98 +#: superset/db_engine_specs/postgres.py:114 +#: superset/db_engine_specs/presto.py:645 +#: superset/db_engine_specs/redshift.py:77 #, python-format msgid "Port %(port)s on hostname \"%(hostname)s\" refused the connection." -msgstr "" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:103 -#, fuzzy -msgid "Port is closed" -msgstr "Рассылка не удалась" +msgstr "Порт %(port)s хоста \"%(hostname)s\" отказал в подключении." #: superset/views/dashboard/mixin.py:87 +#, fuzzy msgid "Position JSON" -msgstr "Позиция JSON" +msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:181 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:182 msgid "Position of child node label on tree" -msgstr "" +msgstr "Расположение метки дочерней вершины на дереве" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:310 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:375 msgid "Position of column level subtotal" -msgstr "" +msgstr "Расположение промежуточного итога на уровне столбца" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:163 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:164 msgid "Position of intermidiate node label on tree" msgstr "" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:293 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:358 msgid "Position of row level subtotal" -msgstr "" +msgstr "Расположение промежуточного итога на уровне строки" -#: superset-frontend/src/components/Menu/MenuRight.tsx:180 +#: superset-frontend/src/views/components/RightMenu.tsx:512 msgid "Powered by Apache Superset" -msgstr "" +msgstr "На базе Apache Superset" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1096 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:937 msgid "Pre-filter" -msgstr "Временной фильтр" +msgstr "Предварительная фильтрация" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1061 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:902 msgid "Pre-filter available values" -msgstr "" +msgstr "Предварительно выбрать доступные значения для фильтра" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:623 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:652 msgid "Pre-filter is required" -msgstr "Тип обязателен" +msgstr "Предварительная фильтрация обязательна" -#: superset/connectors/sqla/views.py:451 +#: superset/connectors/sqla/views.py:441 msgid "" "Predicate applied when fetching distinct value to populate the filter " "control component. Supports jinja template syntax. Applies only when " "`Enable Filter Select` is on." msgstr "" -"Предикат применяется при получении значений для компонента - «Фильтр». " -"Поддерживает синтаксис jinja. Применяется только в том случае, если " -"включен параметр «Включить Онлайн Фильтр»." #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:39 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:75 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:78 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:78 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:74 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:75 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:70 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:69 msgid "Predictive" -msgstr "Действия" +msgstr "Прогноз" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:36 -#, fuzzy msgid "Predictive Analytics" -msgstr "Расширенный анализ" +msgstr "Предиктивная аналитика" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:64 msgid "Prefix metric name with slice name" @@ -9209,39 +11315,61 @@ msgstr "" #: superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.tsx:39 msgid "Preview" -msgstr "Предпросмотр %s" +msgstr "Предпросмотр" -#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:166 +#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:209 #, python-format msgid "Preview: `%s`" -msgstr "Предпросмотр %s" +msgstr "Предпросмотр «%s»" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:32 -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:125 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:105 +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:126 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:106 msgid "Previous" -msgstr "Предпросмотр %s" +msgstr "Предыдущий" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:243 -#, fuzzy +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:337 +msgid "Previous Line" +msgstr "Предыдущая строка" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:245 msgid "Primary" -msgstr "Пятница" +msgstr "Первичная" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:56 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:61 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:158 msgid "Primary Metric" -msgstr "Показатель" +msgstr "Основная мера" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:248 +#: superset-frontend/src/SqlLab/components/ColumnElement/index.tsx:63 +msgid "Primary key" +msgstr "Первичный ключ" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:251 msgid "Primary or secondary y-axis" -msgstr "" +msgstr "Первичная или вторичная ось Y" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:371 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:387 msgid "Primary y-axis format" -msgstr "" +msgstr "Формат первичной оси Y" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:217 +msgid "Private Key" +msgstr "Приватный ключ" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:174 +msgid "Private Key & Password" +msgstr "Приватный ключ и пароль" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:234 +msgid "Private Key Password" +msgstr "Пароль приватного ключа" -#: superset-frontend/src/components/Menu/MenuRight.tsx:161 -#: superset/templates/appbuilder/navbar_right.html:109 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:269 +msgid "Proceed" +msgstr "Продолжить" + +#: superset-frontend/src/views/components/RightMenu.tsx:493 msgid "Profile" msgstr "Профиль" @@ -9249,258 +11377,269 @@ msgstr "Профиль" msgid "Profile picture provided by Gravatar" msgstr "Изображение профиля, сгенерированное сервисом Gravatar" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:239 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:235 msgid "Progress" -msgstr "" +msgstr "Прогресс" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:30 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:56 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:32 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:58 msgid "Progressive" -msgstr "" +msgstr "Постепенный" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:55 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:59 msgid "Propagate" msgstr "" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:39 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:30 #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:42 #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:46 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:50 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:43 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:44 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:71 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts:46 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:64 msgid "Proportional" -msgstr "" +msgstr "Пропорция" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:86 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:85 msgid "Public and privately shared sheets" msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:83 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:82 msgid "Publicly shared sheets only" msgstr "" #: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:101 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:301 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:498 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:316 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:529 #: superset/views/dashboard/mixin.py:84 msgid "Published" msgstr "Опубликовано" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:44 +msgid "Purple" +msgstr "Фиолетовый" + #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:109 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:161 msgid "Put labels outside" -msgstr "" +msgstr "Вынести метки наружу" #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:164 msgid "Put the labels outside of the pie?" -msgstr "" +msgstr "Вынести метки за пределы диаграммы" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:112 msgid "Put the labels outside the pie?" -msgstr "" +msgstr "Вынести метки за пределы диаграммы" #: superset-frontend/src/explore/controlPanels/Separator.js:47 msgid "Put your code here" msgstr "Введите произвольный текст в формате html или markdown" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:351 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:234 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:485 -#, fuzzy -msgid "Python Functions" -msgstr "Python функции" - -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:233 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:300 msgid "Python datetime string pattern" +msgstr "Шаблон строки даты и времени Python" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1367 +msgid "QUERY DATA IN SQL LAB" msgstr "" -#: superset-frontend/src/explore/controlPanels/sections.tsx:248 -msgid "Python functions" -msgstr "Python функции" - -#: superset/db_engine_specs/base.py:99 -#, fuzzy +#: superset/db_engine_specs/base.py:113 msgid "Quarter" -msgstr "запрос" +msgstr "Квартал" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:69 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:68 +#, python-format msgid "Quarters %s" -msgstr "Параметры графика: %s" +msgstr "Кварталов %s" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/echartsTimeSeriesQuery.tsx:41 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/echartsTimeSeriesQuery.tsx:51 #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:32 -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:32 -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:91 -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:65 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:60 +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:30 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:33 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:90 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:66 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:46 #: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:30 -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:55 #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:26 #: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:26 #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:36 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:33 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:32 #: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:34 #: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:26 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:30 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:31 #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:31 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:30 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:34 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:32 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:44 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:32 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:63 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:44 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts:41 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:60 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:45 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:46 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:60 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:158 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:341 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:361 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:29 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:43 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:34 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:33 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:35 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:43 #: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:41 #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:34 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:45 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:48 #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:59 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:56 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:52 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:53 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:59 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:60 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:42 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:38 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:43 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:38 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:41 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:179 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:26 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:30 -#: superset-frontend/src/explore/controlPanels/TimeTable.js:26 -#: superset-frontend/src/explore/controlPanels/sections.tsx:113 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx:53 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:44 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:152 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:30 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:26 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1453 +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:62 +#: superset-frontend/src/explore/controlPanels/sections.tsx:94 #: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:34 #: superset-frontend/src/filters/components/Range/controlPanel.ts:31 #: superset-frontend/src/filters/components/Select/controlPanel.ts:41 #: superset-frontend/src/filters/components/Time/controlPanel.ts:29 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:178 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:177 +#: superset-frontend/src/visualizations/TimeTable/controlPanel.js:26 msgid "Query" msgstr "Запрос" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:253 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:378 #, python-format msgid "Query %s: %s" -msgstr "" +msgstr "Запрос %s: %s" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:258 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:283 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:288 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:299 msgid "Query A" -msgstr "запрос" +msgstr "Запрос А" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:259 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:284 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:290 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:300 msgid "Query B" -msgstr "запрос" +msgstr "Запрос Б" -#: superset/initialization/__init__.py:341 +#: superset/initialization/__init__.py:361 msgid "Query History" msgstr "История запросов" -#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:197 -#: superset-frontend/src/views/CRUD/data/common.ts:44 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:89 +#: superset/commands/exceptions.py:138 +msgid "Query does not exist" +msgstr "Запрос не существует" + +#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:244 +#: superset-frontend/src/views/CRUD/data/common.ts:32 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:95 msgid "Query history" msgstr "История запросов" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:722 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:128 +msgid "Query imported" +msgstr "Запрос импортирован" + +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:462 msgid "Query in a new tab" msgstr "Запрос в отдельной вкладке" -#: superset/errors.py:125 +#: superset/errors.py:131 msgid "Query is too complex and takes too long to run." -msgstr "" +msgstr "Запрос слишком тяжелый для выполнения и займет много времени." -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:89 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/queryMode.tsx:29 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:90 msgid "Query mode" -msgstr "Имя запроса" +msgstr "Режим запроса" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:125 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:127 msgid "Query name" msgstr "Имя запроса" +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:323 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:325 #: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:117 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:376 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:377 #: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:97 msgid "Query preview" -msgstr "Предпросмотр данных" +msgstr "Предпросмотр запроса" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "Поиск запросов" - -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 -#, fuzzy +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:419 msgid "Query was stopped" -msgstr "Запрос прерван." +msgstr "Запрос прерван" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:407 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:468 msgid "Query was stopped." -msgstr "Запрос прерван." +msgstr "Запрос прерван" -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:292 -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:294 +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:284 +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:286 msgid "RANGE TYPE" msgstr "ТИП ИНТЕРВАЛА" -#: superset-frontend/src/components/ReportModal/index.tsx:327 -#, fuzzy -msgid "REPORT NAME ERROR" -msgstr "Имя Шаблона" - -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:251 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:263 msgid "RGB Color" -msgstr "Фиксированный цвет" +msgstr "Цвет RGB" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:161 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:160 msgid "Radar" -msgstr "" +msgstr "Радар" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:53 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:56 msgid "Radar Chart" -msgstr "Поделиться графиком" +msgstr "Диаграмма радар" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:201 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:203 msgid "Radar render type, whether to display 'circle' shape." msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:121 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:122 #, fuzzy msgid "Radial" msgstr "Ошибка" -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:318 -#, fuzzy, python-format +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:87 +msgid "Radius in kilometers" +msgstr "Радиус в километрах" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:86 +msgid "Radius in meters" +msgstr "Радиус в метрах" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:88 +msgid "Radius in miles" +msgstr "Радиус в милях" + +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:292 +#, python-format msgid "Ran %s" -msgstr "Продолжительность: %s" +msgstr "Запущен %s" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:35 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:38 #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 -#, fuzzy msgid "Range" -msgstr "Управление" +msgstr "Интервал" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:295 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:316 #: superset-frontend/src/filters/components/Range/index.ts:28 -#, fuzzy msgid "Range filter" -msgstr "Временной фильтр" +msgstr "Диапазон" #: superset-frontend/src/filters/components/Range/index.ts:29 msgid "Range filter plugin using AntD" @@ -9508,41 +11647,43 @@ msgstr "" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:48 msgid "Range labels" -msgstr "" +msgstr "Метки диапазона" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:39 -#, fuzzy msgid "Ranges" -msgstr "Управление" +msgstr "Диапазоны" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:41 msgid "Ranges to highlight with shading" -msgstr "" +msgstr "Диапазоны для выделения с помощью затенения" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:25 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:25 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:28 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:48 +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:27 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:27 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:33 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:50 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:33 -#, fuzzy msgid "Ranking" -msgstr "Предупреждение!" +msgstr "Ранжирование" -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:63 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:143 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:335 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:217 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:53 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:487 +#: superset-frontend/src/explore/controlPanels/sections.tsx:213 msgid "Ratio" -msgstr "Продолжительность" +msgstr "Отношение" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:46 +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:58 msgid "Raw records" -msgstr "" +msgstr "Сырые записи" #: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:64 #, fuzzy msgid "Ready to review filters in this dashboard?" msgstr "В этом дашборде нет фильтров." -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:78 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:86 msgid "Rebuild" msgstr "" @@ -9550,618 +11691,694 @@ msgstr "" msgid "Recent activity" msgstr "Последние действия" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:86 +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:95 msgid "Recently created charts, dashboards, and saved queries will appear here" -msgstr "Недавно созданные графики, дашборды и сохранённые запросы" +msgstr "Недавно созданные графики, дашборды и сохраненные запросы" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:96 +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:106 msgid "Recently edited charts, dashboards, and saved queries will appear here" -msgstr "Недавно изменённые графики, дашборды и сохранённые запросы" +msgstr "Недавно измененные графики, дашборды и сохраненные запросы" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:561 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:535 -#, fuzzy +#: superset-frontend/src/pages/ChartList/index.tsx:702 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:561 msgid "Recently modified" -msgstr "Изменено" +msgstr "Измененные недавно" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:81 +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:90 msgid "Recently viewed charts, dashboards, and saved queries will appear here" -msgstr "Недавно просмотренные графики, дашборды и сохранённые запросы" +msgstr "Недавно просмотренные графики, дашборды и сохраненные запросы" -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:277 +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:359 msgid "Recents" -msgstr "Последние" - -#: superset/views/schedules.py:242 superset/views/schedules.py:322 -msgid "Recipients" -msgstr "Получатели" +msgstr "Недавние" #: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:160 msgid "Recipients are separated by \",\" or \";\"" -msgstr "Получатели, разделенные “,” или “;”" +msgstr "Получатели, разделенные \",\" или \";\"" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:597 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:673 msgid "Recommended tags" -msgstr "" +msgstr "Рекомендованные теги" #: superset/templates/appbuilder/general/widgets/base_list.html:55 msgid "Record Count" -msgstr "Количество записей" +msgstr "Кол-во записей" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:222 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:223 msgid "Rectangle" -msgstr "" - -#: superset/connectors/druid/views.py:330 -msgid "" -"Redirects to this endpoint when clicking on the datasource from the " -"datasource list" -msgstr "" -"Перенаправление на эту конечную точку при нажатии на источник данных из " -"списка источников данных" +msgstr "Прямоугольник" -#: superset/connectors/sqla/views.py:457 +#: superset/connectors/sqla/views.py:447 msgid "Redirects to this endpoint when clicking on the table from the table list" msgstr "" -"Перенаправление на эту конечную точку при нажатии на таблицу в общем " -"списке" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:316 +#: superset-frontend/src/dashboard/components/Header/index.jsx:573 +msgid "Redo the action" +msgstr "Повторить действие" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:336 msgid "Reduce X ticks" -msgstr "" +msgstr "Уменьшить кол-во делений оси X" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:319 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:339 msgid "" "Reduces the number of X-axis ticks to be rendered. If true, the x-axis " "will not overflow and labels may be missing. If false, a minimum width " "will be applied to columns and the width may overflow into an horizontal " "scroll." msgstr "" +"Уменьшает количество отрисованных делений на оси X. Если флажок " +"установлен, некоторые метки могут быть не отображены. " -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:78 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:93 msgid "Refer to the" -msgstr "Обратитесь сюда " +msgstr "Обратитесь к" -#: superset/utils/pandas_postprocessing.py:143 +#: superset/utils/pandas_postprocessing/utils.py:125 msgid "Referenced columns not available in DataFrame." -msgstr "Ссылочные столбца недоступны в DataFrame." +msgstr "" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:799 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:546 msgid "Refetch results" -msgstr "Результаты поиска" +msgstr "Выполнить запрос повторно" #: superset/templates/appbuilder/general/widgets/search.html:57 msgid "Refresh" -msgstr "Принудительное обновление" - -#: superset/initialization/__init__.py:542 -msgid "Refresh Druid Metadata" -msgstr "Обновить Метаданные Druid" - -#: superset/connectors/sqla/views.py:565 -msgid "Refresh Metadata" -msgstr "Обновить метаданные" - -#: superset/connectors/sqla/views.py:565 -msgid "Refresh column metadata" -msgstr "Обновить метаданные столбцов" +msgstr "Обновить" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:276 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:261 msgid "Refresh dashboard" msgstr "Обновить дашборд" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:117 +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:114 msgid "Refresh frequency" -msgstr "Частота" +msgstr "Частота обновления" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:114 -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:119 +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:111 +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:116 msgid "Refresh interval" msgstr "Интервал обновления" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:976 +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:79 +msgid "Refresh interval saved" +msgstr "Интервал обновления сохранен" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx:250 +msgid "Refresh table list" +msgstr "Обновить список таблиц" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx:251 +msgid "Refresh tables" +msgstr "Обновить таблицы" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1225 msgid "Refresh the default values" -msgstr "" +msgstr "Обновить значения по умолчанию" -#: superset/connectors/druid/views.py:420 -msgid "Refreshed metadata from cluster [{}]" -msgstr "Обновлённые метаданные из кластера [{}]" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:168 +msgid "Refreshing charts" +msgstr "Обновление графиков" -#: superset/connectors/druid/models.py:259 -msgid "Refreshing datasource [{}]" -msgstr "Обновление источника данных [{}]" +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx:175 +msgid "Refreshing columns" +msgstr "Обновление столбцов" -#: superset/connectors/sqla/views.py:335 +#: superset-frontend/src/explore/constants.ts:78 +#, fuzzy +msgid "Regex" +msgstr "Зеленая" + +#: superset/connectors/sqla/views.py:330 +#, fuzzy msgid "" "Regular filters add where clauses to queries if a user belongs to a role " "referenced in the filter. Base filters apply filters to all queries " "except the roles defined in the filter, and can be used to define what " "users can see if no RLS filters within a filter group apply to them." msgstr "" +"Обычные фильтры добавляют операторы where к запросам, если пользователь " +"принадлежит к роли, на которую ссылается фильтр. Базовые фильтры " +"применяют фильтры ко всем запросам, кроме ролей, определенных в фильтре, " +"и могут использоваться для определения того, что пользователи могут " +"видеть, если к ним не применяются фильтры RLS в группе фильтров." #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:40 -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:34 #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:43 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:44 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:33 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:46 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:44 -#, fuzzy msgid "Relational" -msgstr "Продолжительность" +msgstr "Относительный" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:32 #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:35 msgid "Relationships between community channels" msgstr "" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:91 -#, fuzzy +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:88 msgid "Relative Date/Time" -msgstr "Относительное количество" +msgstr "Относительная дата/время" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:157 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:210 -#, fuzzy +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:171 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:223 msgid "Relative period" -msgstr "Период" +msgstr "Относительный период" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:145 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:198 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:159 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:211 msgid "Relative quantity" msgstr "Относительное количество" +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.tsx:133 +msgid "Reload" +msgstr "Обновить" + #: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:69 msgid "Remind me in 24 hours" -msgstr "" +msgstr "Напомните мне через 24 часа" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:779 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:830 msgid "Remove" -msgstr "" +msgstr "Удалить" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:77 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:85 msgid "Remove invalid filters" -msgstr "" +msgstr "Удалить недействующие фильтры" #: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:142 msgid "Remove item" -msgstr "" +msgstr "Удалить элемент" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:282 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:288 msgid "Remove query from log" -msgstr "Удалить запрос из журнала" +msgstr "Удалить запрос из истории" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:211 +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:240 msgid "Remove table preview" msgstr "Убрать предпросмотр таблицы" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:609 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:771 #, python-format msgid "Removed columns: %s" msgstr "Удалённые столбцы: %s" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:345 +#: superset-frontend/src/SqlLab/components/SqlEditorTabHeader/index.tsx:113 msgid "Rename tab" msgstr "Переименовать вкладку" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:146 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:147 msgid "Rendering" -msgstr "Направление сортировки" +msgstr "Отрисовка" -#: superset/views/database/forms.py:146 superset/views/database/forms.py:299 -#: superset/views/database/forms.py:427 +#: superset/views/database/forms.py:168 superset/views/database/forms.py:325 +#: superset/views/database/forms.py:456 msgid "Replace" msgstr "Заменить" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:36 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:36 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:41 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:46 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:57 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:48 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:59 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:38 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:39 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:33 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:45 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:59 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:51 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:62 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:57 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:48 -#, fuzzy +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:574 +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:163 msgid "Report" -msgstr "рассылка" +msgstr "Отчет" -#: superset/reports/commands/exceptions.py:118 +#: superset-frontend/src/components/ReportModal/index.tsx:276 +msgid "Report Name" +msgstr "Имя отчета" + +#: superset/reports/commands/exceptions.py:134 msgid "Report Schedule could not be created." -msgstr "Рассылка не может быть создана." +msgstr "Невозможно удалить расписание отчета." -#: superset/reports/commands/exceptions.py:114 +#: superset/reports/commands/exceptions.py:130 msgid "Report Schedule could not be deleted." -msgstr "Рассылка не может быть удалена." +msgstr "Невозможно удалить расписание отчета." -#: superset/reports/commands/exceptions.py:122 +#: superset/reports/commands/exceptions.py:138 msgid "Report Schedule could not be updated." -msgstr "Рассылка не может быть обновлена." +msgstr "Невозможно обновить расписание отчета" -#: superset/reports/commands/exceptions.py:130 +#: superset/reports/commands/exceptions.py:147 msgid "Report Schedule delete failed." -msgstr "Удаление графика рассылки не удалось." +msgstr "Ошибка при удалении расписания отчета." -#: superset/reports/commands/exceptions.py:142 -#, fuzzy +#: superset/reports/commands/exceptions.py:159 msgid "Report Schedule execution failed when generating a csv." -msgstr "Ошибка при генерировании скриншота во время выполнения рассылки." +msgstr "Возникла ошибка при создании csv для отправки отчета" -#: superset/reports/commands/exceptions.py:146 -#, fuzzy +#: superset/reports/commands/exceptions.py:163 msgid "Report Schedule execution failed when generating a dataframe." -msgstr "Ошибка при генерировании скриншота во время выполнения рассылки." +msgstr "Возникла ошибка при создании датафрейма для отправки отчета" -#: superset/reports/commands/exceptions.py:138 +#: superset/reports/commands/exceptions.py:155 msgid "Report Schedule execution failed when generating a screenshot." -msgstr "Ошибка при генерировании скриншота во время выполнения рассылки." +msgstr "Возникла ошибка при создании скриншота для отправки отчета" -#: superset/reports/commands/exceptions.py:150 +#: superset/reports/commands/exceptions.py:167 msgid "Report Schedule execution got an unexpected error." -msgstr "Во время выполнения рассылки произошла непредвиденная ошибка." +msgstr "Возникла неожиданная ошибка при отправке отчета" -#: superset/reports/commands/exceptions.py:154 +#: superset/reports/commands/exceptions.py:172 msgid "Report Schedule is still working, refusing to re-compute." -msgstr "" +msgstr "Планировщик отчетов все еще работает, не имея возможности отправить отчет" -#: superset/reports/commands/exceptions.py:134 +#: superset/reports/commands/exceptions.py:151 msgid "Report Schedule log prune failed." -msgstr "Удаление журнала рассылки не удалось." +msgstr "" -#: superset/reports/commands/exceptions.py:126 +#: superset/reports/commands/exceptions.py:143 msgid "Report Schedule not found." -msgstr "График рассылки не найден." +msgstr "Расписание отчета не найдено" -#: superset/reports/commands/exceptions.py:110 +#: superset/reports/commands/exceptions.py:126 msgid "Report Schedule parameters are invalid." -msgstr "Параметры графика рассылки недействительны." +msgstr "Параметры расписания отчета неверны." -#: superset/reports/commands/exceptions.py:158 +#: superset/reports/commands/exceptions.py:177 msgid "Report Schedule reached a working timeout." -msgstr "Рассылка достигла тайм-аута в работе." - -#: superset/reports/commands/exceptions.py:226 -msgid "Report Schedule sellenium user not found" -msgstr "Пользователь Selenium для графика рассылки не найден" +msgstr "Достигнут таймаут для отчета" -#: superset/reports/commands/exceptions.py:230 +#: superset/reports/commands/exceptions.py:257 msgid "Report Schedule state not found" -msgstr "Не найдено состояние графика рассылки" +msgstr "Состояние расписания отчета не найдено" -#: superset-frontend/src/components/Menu/MenuRight.tsx:225 -#, fuzzy +#: superset-frontend/src/views/components/RightMenu.tsx:564 msgid "Report a bug" -msgstr "рассылка" +msgstr "Сообщить об ошибке" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:81 msgid "Report failed" msgstr "Рассылка не удалась" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1064 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1072 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:395 msgid "Report name" -msgstr "Имя Шаблона" +msgstr "Имя отчета" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1214 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:407 msgid "Report schedule" -msgstr "Область просмотра" +msgstr "Расписание отчета" + +#: superset/reports/commands/exceptions.py:268 +msgid "Report schedule client error" +msgstr "Возникла ошибка расписания отчета на стороне клиента" -#: superset/reports/commands/exceptions.py:234 +#: superset/reports/commands/exceptions.py:262 +msgid "Report schedule system error" +msgstr "Возникла ошибка расписания отчета на стороне системы" + +#: superset/reports/commands/exceptions.py:272 msgid "Report schedule unexpected error" -msgstr "Неожиданная ошибка графика рассылки" +msgstr "Неожиданная ошибка расписания отчета" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:74 msgid "Report sending" -msgstr "Выполняется рассылка" +msgstr "Отчет выполняется" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:67 msgid "Report sent" -msgstr "Рассылка отправлена" +msgstr "Отчет отправлен" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:443 +#: superset-frontend/src/reports/actions/reports.js:121 +msgid "Report updated" +msgstr "Отчет обновлен" + +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:542 msgid "Reports" -msgstr "Рассылки" +msgstr "Отчеты" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:283 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:284 msgid "Repulsion" -msgstr "Выражение SQL" +msgstr "Отталкивание" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:289 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:290 msgid "Repulsion strength between nodes" -msgstr "" +msgstr "Сила отталкивания вершин" #: superset/templates/superset/request_access.html:31 msgid "Request Permissions" -msgstr "Запросить права доступа" +msgstr "" -#: superset/charts/data/api.py:145 superset/charts/data/api.py:233 -#: superset/charts/data/api.py:297 +#: superset/charts/data/api.py:152 superset/charts/data/api.py:242 +#: superset/charts/data/api.py:308 #, python-format msgid "Request is incorrect: %(error)s" -msgstr "Запрос некорректен: %(error)s" +msgstr "Неверный запрос: %(error)s" -#: superset/charts/data/api.py:222 +#: superset/charts/data/api.py:229 msgid "Request is not JSON" -msgstr "Запрос не в формате JSON" +msgstr "Запрос не является JSON" -#: superset/views/datasource/views.py:71 +#: superset/views/datasource/views.py:75 msgid "Request missing data field." -msgstr "" +msgstr "В запросе отсутствует поле с данными." -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:93 -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:97 -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:104 +#: superset-frontend/src/utils/getClientErrorObject.ts:144 +msgid "Request timed out" +msgstr "Вышло время запроса" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:94 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:98 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:105 #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:252 -#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:73 -#: superset-frontend/src/filters/components/Range/controlPanel.ts:55 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:91 -#: superset-frontend/src/filters/components/Time/controlPanel.ts:53 -#: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:33 -#: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:33 msgid "Required" msgstr "Обязательно" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:137 -#, fuzzy +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:341 +msgid "Required control values have been removed" +msgstr "Обязательные значения были удалены" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:153 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:345 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:227 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:497 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:226 +#: superset-frontend/src/explore/controlPanels/sections.tsx:223 msgid "Resample" -msgstr "Посмотреть примеры" +msgstr "Ресемплирование (изменение частоты данных)" + +#: superset/utils/pandas_postprocessing/resample.py:46 +msgid "Resample method should in " +msgstr "" -#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:231 +#: superset/utils/pandas_postprocessing/resample.py:43 +msgid "Resample operation requires DatetimeIndex" +msgstr "Для ресемплирования требуется индекс формата дата/время" + +#: superset-frontend/src/components/Table/index.tsx:257 +msgid "Reset" +msgstr "Сбросить" + +#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx:289 msgid "Reset state" msgstr "Сбросить текущее состояние" +#: superset/reports/commands/exceptions.py:194 +msgid "Resource already has an attached report." +msgstr "Для этого компонента уже создан отчет." + +#: superset/temporary_cache/commands/exceptions.py:49 +msgid "Resource was not found." +msgstr "Источник не был найден." + #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/RemovedFilter.tsx:46 -#, fuzzy msgid "Restore Filter" -msgstr "Фильтр результатов" +msgstr "Восстановить фильтр" -#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:194 +#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:241 +#: superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:204 +#: superset-frontend/src/explore/components/DataTablesPane/components/ResultsPaneOnDashboard.tsx:76 msgid "Results" msgstr "Результаты" -#: superset/sql_lab.py:375 superset/views/core.py:2251 +#: superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:212 +#: superset-frontend/src/explore/components/DataTablesPane/components/ResultsPaneOnDashboard.tsx:84 +#, python-format +msgid "Results %s" +msgstr "Результаты %s" + +#: superset/sql_lab.py:410 superset/sqllab/commands/results.py:60 +#: superset/views/core.py:2108 msgid "Results backend is not configured." -msgstr "" +msgstr "Results backend не нестроен" -#: superset/errors.py:116 +#: superset/errors.py:122 msgid "Results backend needed for asynchronous queries is not configured." -msgstr "" +msgstr "Сервер, необходимый для асинхронных запросов, не настроен." #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:29 msgid "Return to specific datetime." msgstr "" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:361 +msgid "Reverse Lat & Long" +msgstr "Поменять местами широту и долготу" + #: superset-frontend/src/explore/components/controls/SpatialControl.jsx:155 msgid "Reverse lat/long " -msgstr "Поменять местами широту и долготу " +msgstr "Поменять местами широту и долготу" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:230 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:100 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:281 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:223 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:92 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:301 msgid "Rich Tooltip" -msgstr "" +msgstr "Расширенная всплывающая подсказка" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:149 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:175 msgid "Rich tooltip" -msgstr "" +msgstr "Расширенная всплывающая подсказка" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:113 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:307 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:102 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:86 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:372 msgid "Right" -msgstr "Высота" +msgstr "Справа" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:53 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:52 msgid "Right Axis Format" -msgstr "Показатель для правой оси" +msgstr "Формат правой оси" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:119 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:183 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:181 msgid "Right Axis Metric" -msgstr "Показатель для правой оси" +msgstr "Мера для правой оси" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:132 -#, fuzzy msgid "Right Axis chart(s)" -msgstr "Показатель для правой оси" +msgstr "График(и) по правой оси" -#: superset-frontend/src/explore/controls.jsx:215 +#: superset-frontend/src/explore/controls.jsx:214 msgid "Right axis metric" -msgstr "Показатель для правой оси" +msgstr "Мера для правой оси" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:138 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:139 msgid "Right to Left" -msgstr "" +msgstr "Справа налево" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:160 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:157 msgid "Right value" +msgstr "Правое значение" + +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx:231 +msgid "Right-click on a dimension value to drill to detail by that value." msgstr "" -#: superset/dashboards/filters.py:153 -#, fuzzy +#: superset/dashboards/filters.py:199 msgid "Role" -msgstr "Профиль" +msgstr "Роль" -#: superset/views/core.py:389 +#: superset/views/core.py:405 #, python-format msgid "Role %(r)s was extended to provide the access to the datasource %(ds)s" msgstr "" -"Роль %(r) s была расширена для обеспечения доступа к источнику данных " +"Роль %(r)s была расширена для предоставления доступа к источнику данных " "%(ds)s" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:421 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:424 +#: superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx:373 +#: superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx:387 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:474 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:477 #: superset-frontend/src/profile/components/Security.tsx:35 -#: superset/connectors/sqla/views.py:368 superset/views/dashboard/mixin.py:83 +#: superset/connectors/sqla/views.py:365 superset/views/dashboard/mixin.py:83 msgid "Roles" msgstr "Роли" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:433 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:488 msgid "" "Roles is a list which defines access to the dashboard. Granting a role " -"access to a dashboard will bypass dataset level checks. If no roles " -"defined then the dashboard is available to all roles." +"access to a dashboard will bypass dataset level checks. If no roles are " +"defined, then the dashboard is available to all roles." msgstr "" +"Список ролей, определяющий доступ к дашборду. Предоставляя доступ " +"определенной роли, пользователь сможет обойти ограничения своей роли. " +"Если роли не указаны, дашборд доступен всем ролям." #: superset/views/dashboard/mixin.py:66 +#, fuzzy msgid "" "Roles is a list which defines access to the dashboard. Granting a role " -"access to a dashboard will bypass dataset level checks.If no roles " +"access to a dashboard will bypass dataset level checks.If no roles are " "defined then the dashboard is available to all roles." msgstr "" +"Список ролей, определяющий доступ к дашборду. Предоставляя доступ " +"определенной роли, пользователь сможет обойти ограничения своей роли. " +"Если роли не указаны, дашборд доступен всем ролям." -#: superset/views/access_requests.py:45 +#: superset/views/access_requests.py:48 msgid "Roles to grant" msgstr "Роли для предоставления" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:257 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:140 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:158 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:389 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:250 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:132 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:399 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:179 msgid "Rolling Function" -msgstr "Rolling" +msgstr "Скользящая средняя" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:251 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:134 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:152 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:383 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:244 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:126 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:393 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:173 msgid "Rolling Window" -msgstr "Rolling" +msgstr "Скользящее окно" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:39 -#: superset-frontend/src/explore/controlPanels/sections.tsx:158 +#: superset-frontend/src/explore/controlPanels/sections.tsx:131 msgid "Rolling function" -msgstr "Rolling" +msgstr "Скользящая средняя" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:33 -#: superset-frontend/src/explore/controlPanels/sections.tsx:152 +#: superset-frontend/src/explore/controlPanels/sections.tsx:125 msgid "Rolling window" -msgstr "Rolling" +msgstr "Скользящее окно" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:351 -#: superset/views/database/mixins.py:198 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:361 +#: superset/views/database/mixins.py:195 msgid "Root certificate" msgstr "Корневой сертификат" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:85 msgid "Root node id" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:307 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:209 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:170 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:151 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:167 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:225 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:228 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:168 +msgid "Rotate axis label" +msgstr "Повернуть метки осей" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:323 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:198 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:185 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:128 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:127 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:182 msgid "Rotate x axis label" -msgstr "" +msgstr "Повернуть метку оси X" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:89 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:93 msgid "Rotation to apply to words in the cloud" -msgstr "" +msgstr "Вращение для применения к словам в облаке" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:271 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:267 msgid "Round cap" -msgstr "Карта Стран" +msgstr "Закругление на концах" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx:42 #: superset-frontend/src/dashboard/components/gridComponents/new/NewRow.jsx:31 msgid "Row" msgstr "Строка" -#: superset/initialization/__init__.py:274 -#, fuzzy +#: superset/initialization/__init__.py:291 msgid "Row Level Security" msgstr "Безопасность на уровне строк" -#: superset/views/database/forms.py:153 superset/views/database/forms.py:306 +#: superset/views/database/forms.py:245 +msgid "" +"Row containing the headers to use as column names (0 is first line of " +"data). Leave empty if there is no header row" +msgstr "" +"Строка, содержащая заголовки для использования в качестве имен столбцов " +"(0, если первая строка в данных). Оставьте пустым, если заголовки " +"отсутствуют" + +#: superset/views/database/forms.py:332 msgid "" "Row containing the headers to use as column names (0 is first line of " "data). Leave empty if there is no header row." msgstr "" "Строка, содержащая заголовки для использования в качестве имен столбцов " -"(0 - первая строка данных). Оставьте пустым, если строка заголовка " -"отсутствует." +"(0, если первая строка в данных). Оставьте пустым, если заголовки " +"отсутствуют." -#: superset/connectors/sqla/views.py:314 +#: superset/connectors/sqla/views.py:291 +#, fuzzy msgid "Row level security filter" -msgstr "Фильтр на уровне строк" +msgstr "Безопасность на уровне строк" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:331 -#: superset-frontend/src/explore/controls.jsx:360 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:247 +#: superset-frontend/src/explore/controls.jsx:340 msgid "Row limit" msgstr "Лимит строк" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:49 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:83 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:289 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:62 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:120 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:307 msgid "Rows" -msgstr "Игнорировать" +msgstr "Строки" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:314 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:391 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/pagination.tsx:53 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:324 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:402 msgid "Rows per page, 0 means no pagination" -msgstr "" +msgstr "Строчек на странице, 0 означает все строки" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:285 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:350 msgid "Rows subtotal position" -msgstr "" +msgstr "Расположение строк подытогов" -#: superset/views/database/forms.py:193 superset/views/database/forms.py:334 +#: superset/views/database/forms.py:254 superset/views/database/forms.py:360 msgid "Rows to Read" msgstr "Строки для чтения" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:144 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:360 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:243 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:493 -#: superset-frontend/src/explore/controlPanels/sections.tsx:257 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:160 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:352 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:234 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:504 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:233 +#: superset-frontend/src/explore/controlPanels/sections.tsx:230 msgid "Rule" msgstr "Правило" -#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:56 -#: superset-frontend/src/explore/components/QueryAndSaveBtns.jsx:76 +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:53 msgid "Run" msgstr "Выполнить" -#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:157 -msgid "Run a query to display results here" -msgstr "Выполнить запрос для отображения результатов" +#: superset-frontend/src/SqlLab/components/QueryHistory/index.tsx:65 +msgid "Run a query to display query history" +msgstr "Выполните запрос для отображения истории" + +#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:197 +#: superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:109 +msgid "Run a query to display results" +msgstr "Выполните запрос для отображения результатов" -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:101 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:407 msgid "Run in SQL Lab" msgstr "Открыть в SQL редакторе" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:307 -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:317 -#: superset-frontend/src/chart/Chart.jsx:280 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:300 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:310 msgid "Run query" msgstr "Выполнить запрос" -#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:116 +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:132 msgid "Run query (Ctrl + Return)" -msgstr "Выполнить запрос (Ctrl + Return)" +msgstr "Выполнить запрос (Ctrl + Enter)" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:273 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:281 msgid "Run query in a new tab" msgstr "Выполнить запрос на новой вкладке" -#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:54 +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:51 msgid "Run selection" -msgstr "Выполнить выбранный запрос" +msgstr "Выполнить выбранное" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:81 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:158 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:132 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:173 msgid "Running" msgstr "Выполняется" +#: superset/sql_lab.py:488 +#, python-format +msgid "Running statement %(statement_num)s out of %(statement_count)s" +msgstr "" + #: superset-frontend/src/components/CronPicker/CronPicker.tsx:87 msgid "SAT" msgstr "СБ" @@ -10170,34 +12387,38 @@ msgstr "СБ" msgid "SEP" msgstr "СЕН" +#: superset-frontend/src/views/components/RightMenu.tsx:522 +msgid "SHA" +msgstr "" + #: superset-frontend/src/SqlLab/components/HighlightedSql/index.tsx:101 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:897 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:294 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1082 +#: superset-frontend/src/views/CRUD/data/common.ts:22 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:312 +#: superset/initialization/__init__.py:349 +#: superset/initialization/__init__.py:357 +#: superset/initialization/__init__.py:366 msgid "SQL" msgstr "SQL" #: superset-frontend/src/views/CRUD/data/components/SyntaxHighlighterCopy/index.tsx:71 msgid "SQL Copied!" -msgstr "SQL скопирован!" +msgstr "SQL запрос скопирован!" -#: superset/initialization/__init__.py:326 -msgid "SQL Editor" -msgstr "Редактор SQL" - -#: superset/connectors/sqla/views.py:259 +#: superset/connectors/sqla/views.py:255 msgid "SQL Expression" -msgstr "Выражение SQL" +msgstr "SQL выражение" -#: superset/initialization/__init__.py:331 -#: superset/initialization/__init__.py:346 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:73 +#: superset/initialization/__init__.py:344 msgid "SQL Lab" msgstr "Лаборатория SQL" -#: superset/connectors/sqla/views.py:503 +#: superset/connectors/sqla/views.py:493 msgid "SQL Lab View" -msgstr "Лаборатория SQL" +msgstr "" -#: superset-frontend/src/SqlLab/components/App/index.jsx:91 +#: superset-frontend/src/SqlLab/components/App/index.jsx:152 #, python-format msgid "" "SQL Lab uses your browser's local storage to store queries and results.\n" @@ -10208,376 +12429,516 @@ msgid "" "delete the tab.\n" "Note that you will need to close other SQL Lab windows before you do this." msgstr "" - -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1150 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:287 -#: superset/templates/appbuilder/navbar_right.html:38 +"SQL Lab использует локальное хранилище вашего браузера для хранения " +"запросов и результатов.\n" +"В настоящее время вы используете %(currentUsage)s КБ из %(maxStorage)d КБ" +" дискового пространства.\n" +" Чтобы предотвратить сбой Лаборатории SQL, пожалуйста, удалите некоторые " +"вкладки запросов.\n" +" Вы можете повторно получить доступ к этим запросам, используя функцию " +"сохранения перед удалением вкладки.\n" +" Обратите внимание, что перед этим вам нужно будет закрыть другие окна " +"Лаборатории SQL." + +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:402 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:261 msgid "SQL Query" -msgstr "Сохранить запрос" +msgstr "SQL запрос" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:181 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1038 +#: superset-frontend/packages/superset-ui-chart-controls/src/components/SQLPopover.tsx:64 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:233 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1193 msgid "SQL expression" msgstr "Выражение SQL" -#: superset-frontend/src/components/Menu/MenuRight.tsx:32 -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:124 +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:141 +#: superset-frontend/src/views/components/RightMenu.tsx:210 msgid "SQL query" -msgstr "SQL-запрос" +msgstr "SQL запрос" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:61 -#: superset/views/database/mixins.py:194 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:76 +#: superset/views/database/mixins.py:191 msgid "SQLAlchemy URI" msgstr "SQLAlchemy URI" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:202 -msgid "SSL Mode \"require\" will be used." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:106 +msgid "SSH Host" +msgstr "" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:186 +msgid "SSH Password" +msgstr "Пароль SSH" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:121 +msgid "SSH Port" +msgstr "SSH порт" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:95 +msgid "SSH Tunnel configuration parameters" +msgstr "Параметры конфигурации SSH туннеля" + +#: superset/databases/ssh_tunnel/commands/exceptions.py:29 +msgid "SSH Tunnel could not be deleted." +msgstr "Не удалось удалить SSH туннель." + +#: superset/databases/ssh_tunnel/commands/exceptions.py:42 +msgid "SSH Tunnel could not be updated." +msgstr "Не удалось обновить SSH туннель." + +#: superset/databases/ssh_tunnel/commands/exceptions.py:34 +msgid "SSH Tunnel not found." +msgstr "SSH туннель не найден." + +#: superset/databases/ssh_tunnel/commands/exceptions.py:38 +msgid "SSH Tunnel parameters are invalid." +msgstr "Параметры SSH туннеля недопустимы." + +#: superset/databases/ssh_tunnel/commands/exceptions.py:51 +msgid "SSH Tunneling is not enabled" msgstr "" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:247 +msgid "SSL Mode \"require\" will be used." +msgstr "Будет использовано шифрование SSL" + #: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:64 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:115 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:122 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:129 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:136 msgid "START (INCLUSIVE)" -msgstr "" +msgstr "НАЧАЛО (ВКЛЮЧИТЕЛЬНО)" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:93 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:117 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:135 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:164 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:178 +#, python-format +msgid "STEP %(stepCurr)s OF %(stepLast)s" +msgstr "ШАГ %(stepCurr)s ИЗ %(stepLast)s" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:137 +msgid "STRING" +msgstr "Строчный (STRING/VARCHAR)" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:81 msgid "SUN" msgstr "ВС" -#: superset/viz.py:1903 -msgid "Sankey" -msgstr "Sankey" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:186 +msgid "Sample Standard Deviation" +msgstr "Стандартное отклонение" -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:36 -msgid "Sankey Diagram" -msgstr "" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:185 +msgid "Sample Variance" +msgstr "Дисперсия" -#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/index.js:27 +#: superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:231 +msgid "Samples" +msgstr "Примеры данных" + +#: superset/datasets/commands/exceptions.py:177 +msgid "Samples for dataset could not be retrieved." +msgstr "Не удалось получить примеры записей датасета." + +#: superset/explore/exceptions.py:45 +msgid "Samples for datasource could not be retrieved." +msgstr "Не удалось получить примеры записей для источника данных." + +#: superset/viz.py:1932 +msgid "Sankey" +msgstr "Санкей" + +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:36 +msgid "Sankey Diagram" +msgstr "Диаграмма Санкей" + +#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/index.js:27 msgid "Sankey Diagram with Loops" msgstr "" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:235 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:378 +msgid "Satellite" +msgstr "Спутник" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:233 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:377 +msgid "Satellite Streets" +msgstr "Гибридный режим" + #: superset-frontend/src/components/CronPicker/CronPicker.tsx:62 msgid "Saturday" msgstr "Суббота" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:160 -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:166 -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:181 -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:227 -#: superset-frontend/src/components/ReportModal/index.tsx:267 -#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:88 -#: superset-frontend/src/dashboard/components/Header/index.jsx:588 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:458 +#: superset-frontend/src/SqlLab/components/SaveDatasetActionButton/index.tsx:66 +#: superset-frontend/src/SqlLab/components/SaveDatasetActionButton/index.tsx:80 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:200 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:215 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:242 +#: superset-frontend/src/components/ReportModal/index.tsx:223 +#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:100 +#: superset-frontend/src/dashboard/components/Header/index.jsx:609 +#: superset-frontend/src/dashboard/components/Header/index.jsx:611 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:103 #: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:148 -#: superset-frontend/src/dashboard/components/SaveModal.tsx:224 -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:531 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:157 +#: superset-frontend/src/dashboard/components/SaveModal.tsx:216 +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:794 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:156 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:71 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:205 -#: superset-frontend/src/explore/components/QueryAndSaveBtns.jsx:112 -#: superset-frontend/src/explore/components/SaveModal.tsx:202 -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:318 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:260 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:488 -#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:345 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1039 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:273 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:226 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:220 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1006 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:491 +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:268 +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:457 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:218 +#: superset-frontend/src/explore/components/SaveModal.tsx:402 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:463 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:416 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx:147 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:262 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:497 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx:244 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:347 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:389 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:272 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:230 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:218 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1506 +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/index.tsx:52 msgid "Save" msgstr "Сохранить" -#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:108 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:245 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:192 msgid "Save & Explore" msgstr "Сохранить и исследовать" -#: superset-frontend/src/explore/components/SaveModal.tsx:190 +#: superset-frontend/src/explore/components/SaveModal.tsx:383 msgid "Save & go to dashboard" msgstr "Сохранить и перейти к дашборду" -#: superset-frontend/src/explore/components/SaveModal.tsx:234 +#: superset-frontend/src/explore/components/SaveModal.tsx:382 +msgid "Save & go to new dashboard" +msgstr "Сохранить и перейти к дашборду" + +#: superset-frontend/src/explore/components/SaveModal.tsx:302 msgid "Save (Overwrite)" msgstr "Сохранить (Перезаписать)" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:160 -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:166 -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:254 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:200 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:312 msgid "Save as" msgstr "Сохранить как" -#: superset-frontend/src/explore/components/SaveModal.tsx:243 -msgid "Save as ..." -msgstr "Сохранить как …" +#: superset-frontend/src/explore/components/controls/ViewQueryModalFooter.tsx:37 +msgid "Save as Dataset" +msgstr "Сохранить как датасет" + +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:345 +msgid "Save as dataset" +msgstr "Сохранить как датасет" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:181 +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:394 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:215 msgid "Save as new" msgstr "Сохранить как новый" -#: superset-frontend/src/explore/components/SaveModal.tsx:201 +#: superset-frontend/src/explore/components/SaveModal.tsx:399 msgid "Save as new chart" msgstr "Сохранить как новый график" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:199 +#: superset-frontend/src/explore/components/SaveModal.tsx:310 +msgid "Save as..." +msgstr "Сохранить как..." + +#: superset-frontend/src/dashboard/components/SaveModal.tsx:191 msgid "Save as:" msgstr "Сохранить как:" -#: superset-frontend/src/explore/components/SaveModal.tsx:171 +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:223 +msgid "Save changes" +msgstr "Сохранить изменения" + +#: superset-frontend/src/explore/components/SaveModal.tsx:419 msgid "Save chart" msgstr "Сохранить график" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:182 +#: superset-frontend/src/dashboard/components/SaveModal.tsx:174 msgid "Save dashboard" msgstr "Сохранить дашборд" +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:107 +msgid "Save dataset" +msgstr "Сохранить датасет" + #: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:148 msgid "Save for this session" -msgstr "" +msgstr "Сохранить на время текущей сессии" + +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:350 +msgid "Save or Overwrite Dataset" +msgstr "Сохранить или перезаписать датасет" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:169 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:203 msgid "Save query" msgstr "Сохранить запрос" -#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:89 -#, fuzzy +#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:99 msgid "Save the query to enable this feature" -msgstr "Пожалуйста, сохраните запрос, чтобы включить функцию “поделиться”" +msgstr "Сохраните запрос для включения этой опции" + +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:247 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:465 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx:149 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx:246 +msgid "Save this query as a virtual dataset to continue exploring" +msgstr "Сохраните данный запрос как виртуальный датасет для создания графика" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:241 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:368 +#: superset-frontend/src/explore/components/SaveModal.tsx:401 +msgid "Save to new dashboard" +msgstr "Сохранить в новый дашборд" + +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:263 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:358 msgid "Saved" -msgstr "Сохранить" +msgstr "Сохранено" -#: superset/initialization/__init__.py:334 +#: superset/initialization/__init__.py:353 msgid "Saved Queries" msgstr "Сохраненные запросы" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:226 -#, fuzzy +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:247 msgid "Saved expressions" -msgstr "Выражение SQL" +msgstr "Сохраненные выражения" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:369 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:360 msgid "Saved metric" -msgstr "Сохранённый показатель" +msgstr "Сохраненная мера" -#: superset-frontend/src/views/CRUD/data/common.ts:38 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:108 -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:318 +#: superset-frontend/src/views/CRUD/data/common.ts:26 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:106 +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:405 msgid "Saved queries" msgstr "Сохраненные запросы" #: superset/queries/saved_queries/commands/exceptions.py:28 msgid "Saved queries could not be deleted." -msgstr "Сохранённые запросы не могут быть удалены." +msgstr "Не удалось удалить сохраненные запросы." #: superset/queries/saved_queries/commands/exceptions.py:32 msgid "Saved query not found." -msgstr "Сохранённый запрос не найден." +msgstr "Сохраненный запрос не найден." #: superset/queries/saved_queries/commands/exceptions.py:40 -#, fuzzy msgid "Saved query parameters are invalid." -msgstr "Параметры графика недействительны." +msgstr "Сохраненные параметры запроса недопустимы." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:168 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:277 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:169 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:278 msgid "Scale and Move" -msgstr "" +msgstr "Масштабирование и перемещение" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:166 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:275 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:167 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:276 msgid "Scale only" -msgstr "" - -#: superset/initialization/__init__.py:529 -msgid "Scan New Datasources" -msgstr "Сканирование Новых Источников" +msgstr "Только масштабирование" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:39 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:43 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:36 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:77 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:38 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:142 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:75 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:84 msgid "Scatter" -msgstr "" +msgstr "Точечный" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:75 #: superset-frontend/plugins/preset-chart-xy/src/ScatterPlot/createMetadata.ts:26 -#, fuzzy msgid "Scatter Plot" -msgstr "Deck.gl - Scatter plot" +msgstr "Точечная диаграмма" -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:221 -#: superset-frontend/src/components/ReportModal/index.tsx:357 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:237 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:61 +msgid "" +"Scatter Plot has the horizontal axis in linear units, and the points are " +"connected in order. It shows a statistical relationship between two " +"variables." +msgstr "" + +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:239 +#: superset-frontend/src/components/ReportModal/index.tsx:300 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:277 msgid "Schedule" msgstr "Расписание" -#: superset/views/schedules.py:274 -msgid "Schedule Email Reports for Charts" -msgstr "Запланировать рассылку по email для графиков" - -#: superset/views/schedules.py:196 -msgid "Schedule Email Reports for Dashboards" -msgstr "Запланировать рассылку по email для дашбордов" +#: superset-frontend/src/components/ReportModal/index.tsx:206 +msgid "Schedule a new email report" +msgstr "Запланировать новую рассылку по почте" -#: superset-frontend/src/dashboard/components/Header/index.jsx:423 -#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:218 -#, fuzzy +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:284 msgid "Schedule email report" -msgstr "Запланировать рассылку по email для графиков" +msgstr "Запланировать рассылку по почте" -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:211 +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:229 msgid "Schedule query" msgstr "Сохранить запрос" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1234 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:410 msgid "Schedule settings" msgstr "Настройки расписания" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:517 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:502 msgid "Schedule the query periodically" msgstr "Запланировать периодическое выполнение запроса" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:99 -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:105 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:168 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:150 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:156 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:186 msgid "Scheduled" msgstr "Запланировано" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:117 -#, fuzzy +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:120 msgid "Scheduled at (UTC)" -msgstr "Запланировано на" +msgstr "Запланировано на (часовой пояс UTC)" -#: superset-frontend/src/components/ReportModal/index.tsx:359 -msgid "Scheduled reports will be sent to your email as a PNG" -msgstr "" +#: superset/tasks/exceptions.py:24 +msgid "Scheduled task executor not found" +msgstr "Исполнитель регулярных отчетов не найден" -#: superset-frontend/src/components/DatabaseSelector/index.tsx:295 -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:220 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:299 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:451 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:232 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:287 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:444 -#: superset/connectors/sqla/views.py:494 superset/views/database/forms.py:126 -#: superset/views/database/forms.py:285 superset/views/database/forms.py:413 +#: superset-frontend/src/components/DatabaseSelector/index.tsx:320 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:221 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:358 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:540 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:250 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:288 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:446 +#: superset/connectors/sqla/views.py:484 superset/views/database/forms.py:144 +#: superset/views/database/forms.py:311 superset/views/database/forms.py:442 msgid "Schema" msgstr "Схема" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:235 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:247 msgid "Schema cache timeout" -msgstr "Тайм-аут Кэша" +msgstr "Время жизни кэша схемы" -#: superset/connectors/sqla/views.py:440 +#: superset/views/core.py:1159 +msgid "Schema undefined" +msgstr "Схема не определена" + +#: superset/connectors/sqla/views.py:430 msgid "Schema, as used only in some databases like Postgres, Redshift and DB2" msgstr "" -"Схема, используется только в некоторых базах данных, таких как Postgres, " -"Redshift и DB2" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:369 -#, fuzzy -msgid "Schemas allowed for CSV upload" -msgstr "" -"Если включено, выберите схему, в которую разрешено загружать CSV на " -"вкладке “Дополнительно”." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:419 +msgid "Schemas allowed for File upload" +msgstr "Схемы, в которые разрешена загрузка файлов" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx:72 +msgid "Scope" +msgstr "Область" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:256 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:281 msgid "Scoping" +msgstr "Область применения" + +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:65 +msgid "Scroll" +msgstr "Прокрутка" + +#: superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.tsx:135 +msgid "Scroll down to the bottom to enable overwriting changes. " msgstr "" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 -#: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:542 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:292 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:516 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:417 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:477 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:461 +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:157 +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:107 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/DashboardsSubMenu.tsx:59 +#: superset-frontend/src/pages/ChartList/index.tsx:682 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:508 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:303 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:293 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:471 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:489 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:581 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:464 #: superset/templates/appbuilder/general/widgets/search.html:40 msgid "Search" msgstr "Поиск" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:293 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:294 msgid "Search / Filter" msgstr "Поиск / Фильтр" -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:291 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:361 msgid "Search Metrics & Columns" -msgstr "Столбцы Временных Рядов" +msgstr "Поиск по мерам и столбцам" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:703 -#, fuzzy +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:779 msgid "Search all charts" -msgstr "Все графики" - -#: superset-frontend/src/components/OmniContainer/index.tsx:102 -#, fuzzy -msgid "Search all dashboards" -msgstr "Обновить дашборд" +msgstr "Поиск по всем графикам" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:232 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:137 msgid "Search all filter options" -msgstr "Поиск / Фильтр" +msgstr "Поиск по всем фильтрам" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:403 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:414 msgid "Search box" -msgstr "Поиск" +msgstr "Строка поиска" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:388 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:410 msgid "Search by query text" msgstr "Поиск по тексту запроса" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:452 -msgid "Search..." -msgstr "Поиск…" +#: superset-frontend/src/components/Table/index.tsx:260 +#, fuzzy +msgid "Search in filters" +msgstr "Поиск / Фильтр" -#: superset/db_engine_specs/base.py:86 +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx:252 #, fuzzy +msgid "Search tables" +msgstr "Показать в виде таблицы" + +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:715 +msgid "Search..." +msgstr "Поиск..." + +#: superset/db_engine_specs/base.py:100 msgid "Second" -msgstr "30 секунд" +msgstr "Секунда" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:244 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:246 msgid "Secondary" -msgstr "Понедельник" +msgstr "Вторичная" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:62 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:67 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:164 msgid "Secondary Metric" -msgstr "Показатель для сортировки" +msgstr "Вторичная мера" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:392 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:408 msgid "Secondary y-axis format" -msgstr "" +msgstr "Формат вторичной оси Y" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:401 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:417 msgid "Secondary y-axis title" -msgstr "" +msgstr "Название вторичной оси Y" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:63 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:62 +#, python-format msgid "Seconds %s" -msgstr "30 секунд" +msgstr "Секунд %s" -#: superset/views/database/mixins.py:197 +#: superset/views/database/mixins.py:194 msgid "Secure Extra" -msgstr "Безопасность" +msgstr "Доп. безопасность" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:326 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:331 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:336 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:341 msgid "Secure extra" msgstr "Безопасность" -#: superset/initialization/__init__.py:276 -#: superset/initialization/__init__.py:421 -#: superset/initialization/__init__.py:493 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:329 +#: superset/initialization/__init__.py:293 +#: superset/initialization/__init__.py:375 +#: superset/initialization/__init__.py:413 msgid "Security" msgstr "Безопасность" @@ -10585,196 +12946,264 @@ msgstr "Безопасность" msgid "Security & Access" msgstr "Безопасность и Доступ" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:157 -#, fuzzy, python-format +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:173 +#, python-format msgid "See all %(tableName)s" -msgstr "Исследовать - %(table)s" +msgstr "Список %(tableName)s" -#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:155 +#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:172 msgid "See less" msgstr "Скрыть подробности" -#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:126 +#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:128 #: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:142 +#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:159 msgid "See more" -msgstr "Подробности" +msgstr "Подробнее" + +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:409 +msgid "See query details" +msgstr "Показать детали запроса" -#: superset-frontend/src/components/TableSelector/index.tsx:291 +#: superset-frontend/src/components/TableSelector/index.tsx:311 msgid "See table schema" -msgstr "Выберите схему (%s)" +msgstr "Таблица" -#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:132 -#, fuzzy +#: superset-frontend/src/explore/components/SaveModal.tsx:353 +#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:135 msgid "Select" -msgstr "Множественный выбор" +msgstr "Выбрать" #: superset-frontend/src/components/AsyncSelect/index.jsx:41 -#: superset-frontend/src/components/Select/Select.tsx:290 +#: superset-frontend/src/components/Select/AsyncSelect.tsx:123 +#: superset-frontend/src/components/Select/Select.tsx:100 #: superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx:106 -#: superset-frontend/src/explore/components/controls/SelectControl.jsx:227 +#: superset-frontend/src/explore/components/controls/SelectControl.jsx:230 msgid "Select ..." -msgstr "Выбрать …" +msgstr "Выбрать ..." #: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:127 -#, fuzzy msgid "Select Delivery Method" -msgstr "Добавить метод доставки" +msgstr "Выберите способ оповещения" -#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:106 -#, fuzzy +#: superset-frontend/src/explore/components/controls/VizTypeControl/FastVizSwitcher.tsx:94 msgid "Select Viz Type" msgstr "Выберите тип визуализации" -#: superset/views/database/forms.py:102 -msgid "Select a CSV file to be uploaded to a database." -msgstr "Выберите файл CSV, который будет загружен в БД." - -#: superset/views/database/forms.py:386 -#, fuzzy +#: superset/views/database/forms.py:415 msgid "Select a Columnar file to be uploaded to a database." -msgstr "Выберите файл CSV, который будет загружен в БД." +msgstr "Выберите файл столбчатого формата, который будет загружен в базу данных." -#: superset/views/database/forms.py:253 +#: superset/views/database/forms.py:279 msgid "Select a Excel file to be uploaded to a database." -msgstr "Выберите файл CSV, который будет загружен в БД." +msgstr "Выберите Excel файл для загрузки в базу данных" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:133 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:132 msgid "Select a column" -msgstr "Выберите базу данных" +msgstr "Выберите столбец" -#: superset-frontend/src/explore/components/SaveModal.tsx:264 -#, fuzzy +#: superset-frontend/src/explore/components/SaveModal.tsx:347 msgid "Select a dashboard" -msgstr "Дашборд Superset" +msgstr "Выбрать дашборд" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/index.tsx:39 +msgid "Select a database table and create dataset" +msgstr "Выберите базу данных и создайте датасет" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx:91 +msgid "Select a database table." +msgstr "Выберите таблицу в базе данных." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:169 +msgid "Select a database to connect" +msgstr "Выберите базу данных для подключения" + +#: superset/views/database/forms.py:138 +msgid "Select a database to upload the file to" +msgstr "Выберите базу данных для загрузки файла" + +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:722 +msgid "Select a database to write a query" +msgstr "Выберите базу данных для написания запроса" -#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:131 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:111 +msgid "Select a dimension" +msgstr "Выберете измерение" + +#: superset/views/database/forms.py:110 +msgid "Select a file to be uploaded to the database" +msgstr "Выберите файл для загрузки в базу данных." + +#: superset/views/database/forms.py:145 +msgid "Select a schema if the database supports this" +msgstr "Укажите схему, если она поддерживается базой данных" + +#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:134 msgid "Select a visualization type" msgstr "Выберите тип визуализации" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:310 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:309 msgid "Select aggregate options" -msgstr "%s агрегат(ы)" +msgstr "Выберите настройки агрегации" + +#: superset-frontend/src/components/Table/index.tsx:265 +msgid "Select all data" +msgstr "Выбрать все данные" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:107 +#: superset-frontend/src/components/Table/index.tsx:259 +msgid "Select all items" +msgstr "Выбрать все записи" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:106 msgid "Select any columns for metadata inspection" msgstr "" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:45 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:103 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:138 -#, fuzzy msgid "Select charts" -msgstr "Все графики" +msgstr "Выберите графики" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:188 -#, fuzzy +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx:177 msgid "Select color scheme" -msgstr "Цветовая схема" +msgstr "Выберите цветовую схему" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:208 #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:63 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:301 -#, fuzzy +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:300 msgid "Select column" -msgstr "Столбец с временем" +msgstr "Выберите столбец" + +#: superset-frontend/src/components/Table/index.tsx:262 +msgid "Select current page" +msgstr "Выбрать текущую страницу" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx:245 +msgid "Select database & schema" +msgstr "Выберите базу данных и схему" -#: superset-frontend/src/components/DatabaseSelector/index.tsx:268 -#: superset-frontend/src/components/DatabaseSelector/index.tsx:275 +#: superset-frontend/src/components/DatabaseSelector/index.tsx:293 +#: superset-frontend/src/components/DatabaseSelector/index.tsx:301 msgid "Select database or type database name" -msgstr "" +msgstr "Выберите базу данных или введите ее имя" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1127 +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx:249 +msgid "Select database table" +msgstr "Выберите таблицу из базы данных" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1635 msgid "" "Select databases require additional fields to be completed in the " "Advanced tab to successfully connect the database. Learn what " "requirements your databases has " msgstr "" +"Некоторые базы данных требуют ручной настройки во вкладке Продвинутая " +"настройка для успешного подключения. Вы можете ознакомиться с " +"требованиями к вашей базе данных " + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx:66 +msgid "Select dataset source" +msgstr "Выберите источник датасета" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:294 +#: superset-frontend/src/components/ImportModal/index.tsx:300 +msgid "Select file" +msgstr "Выбрать файл" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:315 #: superset-frontend/src/filters/components/Select/index.ts:28 -#, fuzzy msgid "Select filter" -msgstr "Выберите дату окончания" +msgstr "Селектор" #: superset-frontend/src/filters/components/Select/index.ts:29 msgid "Select filter plugin using AntD" msgstr "" -#: superset-frontend/src/filters/components/Select/controlPanel.ts:111 -msgid "" -"Select first item by default (when using this option, default value can’t" -" be set)" -msgstr "" +#: superset-frontend/src/filters/components/Select/controlPanel.ts:104 +msgid "Select first filter value by default" +msgstr "Сделать первое значение фильтра значением по умолчанию" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:303 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:363 msgid "Select operator" -msgstr "%s параметр(ы)" +msgstr "Выбрать оператор" -#: superset-frontend/src/components/ListView/Filters/Select.tsx:84 +#: superset-frontend/src/components/ListView/Filters/Select.tsx:99 +#: superset-frontend/src/components/ListView/Filters/Select.tsx:113 msgid "Select or type a value" -msgstr "" +msgstr "Выберите значение" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:393 -#, fuzzy -msgid "Select owners" -msgstr "Выполнить выбранный запрос" +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:410 +msgid "Select or type dataset name" +msgstr "Выберите/введите имя датасета" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadeFilters/CascadePopover/index.tsx:177 -msgid "Select parent filters" -msgstr "Выберите дату окончания" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:555 +msgid "Select owners" +msgstr "Выбрать владельцев" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:319 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:318 msgid "Select saved metrics" -msgstr "%s сохранённый показатель(и)" +msgstr "Выберите сохраненные меры" -#: superset-frontend/src/components/DatabaseSelector/index.tsx:293 -#: superset-frontend/src/components/DatabaseSelector/index.tsx:300 +#: superset-frontend/src/components/DatabaseSelector/index.tsx:318 +#: superset-frontend/src/components/DatabaseSelector/index.tsx:325 msgid "Select schema or type schema name" -msgstr "" +msgstr "Выберите схему или введите ее имя" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:194 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx:183 msgid "Select scheme" -msgstr "Выберите схему (%s)" +msgstr "Выберите схему" -#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:273 +#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:304 msgid "Select start and end date" msgstr "Выберите дату начала" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:265 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:335 msgid "Select subject" msgstr "" -#: superset-frontend/src/components/TableSelector/index.tsx:298 -#: superset-frontend/src/components/TableSelector/index.tsx:308 +#: superset-frontend/src/components/TableSelector/index.tsx:318 +#: superset-frontend/src/components/TableSelector/index.tsx:329 msgid "Select table or type table name" -msgstr "" +msgstr "Выберите таблицу или введите ее имя" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:430 +msgid "Select the Annotation Layer you would like to use." +msgstr "Выбрать слой аннотации, который вы хотите использовать." -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:98 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:392 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx:37 +msgid "Select the geojson column" +msgstr "Выберите geojson столбец" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:84 msgid "Select the number of bins for the histogram" -msgstr "" +msgstr "Выберите количество столбцов для гистограммы" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:38 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:48 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:34 msgid "Select the numeric columns to draw the histogram" +msgstr "Выберите числовые столбцы для отрисовки гистограммы" + +#: superset-frontend/src/utils/getChartRequiredFieldsMissingMessage.ts:26 +#, python-format +msgid "" +"Select values in highlighted field(s) in the control panel. Then run the " +"query by clicking on the %s button." msgstr "" +"Выберите значения в обязательных полях на панели управления. Затем " +"запустите запрос, нажав на кнопку %s." -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1340 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:420 msgid "Send as CSV" -msgstr "" +msgstr "Отправить в формате CSV" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1339 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:419 msgid "Send as PNG" -msgstr "" +msgstr "Отправить в формате PNG" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1342 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:421 msgid "Send as text" -msgstr "" +msgstr "Отправить текстом" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:58 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:62 msgid "Send range filter events to other charts" msgstr "" @@ -10782,147 +13211,178 @@ msgstr "" msgid "September" msgstr "Сентябрь" -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:58 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:60 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:49 msgid "Sequential" -msgstr "" +msgstr "Последовательность" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:61 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:385 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:119 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:128 -#: superset-frontend/src/explore/controls.jsx:400 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx:43 msgid "Series" -msgstr "Ряд данных" +msgstr "Ряд" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:71 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:63 msgid "Series Height" -msgstr "Лимит кол-ва рядов" +msgstr "Высота рядов" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:112 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:113 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:54 +msgid "Series Limit Sort By" +msgstr "Сортировка категорий по" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:73 #, fuzzy +msgid "Series Limit Sort Descending" +msgstr "Сортировать" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:71 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:70 msgid "Series Style" -msgstr "Таблица временных рядов" +msgstr "Стиль категорий" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:147 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:122 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:125 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:149 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:82 msgid "Series chart type (line, bar etc)" msgstr "" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:341 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:356 -#: superset-frontend/src/explore/controls.jsx:370 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:269 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:285 +#: superset-frontend/src/explore/controls.jsx:350 msgid "Series limit" -msgstr "Лимит кол-ва рядов" +msgstr "Лимит кол-ва категорий" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:135 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:137 #, fuzzy msgid "Series type" -msgstr "Тип" +msgstr "Тип рядов" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:311 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/pagination.tsx:50 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:321 msgid "Server Page Length" -msgstr "" +msgstr "Серверный размер страницы" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:289 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/pagination.tsx:35 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:298 msgid "Server pagination" -msgstr "" +msgstr "Серверная пагинация" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:115 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:114 msgid "Service Account" -msgstr "" +msgstr "Сервисный аккаунт" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:286 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:400 msgid "Set auto-refresh interval" -msgstr "Интервал обновления" +msgstr "Задать интервал обновления" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:295 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:386 msgid "Set filter mapping" msgstr "Установить действие фильтра" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1264 -#: superset-frontend/src/components/Menu/MenuRight.tsx:133 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:228 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:232 +msgid "Set up an email report" +msgstr "Запланировать рассылку по почте" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:194 +msgid "" +"Sets the hierarchy levels of the chart. Each level is\n" +" represented by one ring with the innermost circle as the top of " +"the hierarchy." +msgstr "" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1430 +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:190 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:277 +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/index.tsx:58 +#: superset-frontend/src/views/components/RightMenu.tsx:455 msgid "Settings" msgstr "Настройки" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:133 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:126 msgid "Settings for time series" -msgstr "" +msgstr "Настройки временных рядов" -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:229 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:331 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:492 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:338 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:211 msgid "Share" msgstr "Поделиться" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:317 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:175 -#, fuzzy +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:497 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:343 msgid "Share chart by email" -msgstr "Поделиться графиком" +msgstr "Поделиться графиком по email" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:264 -#, fuzzy -msgid "Share dashboard by email" -msgstr "Поделиться" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:336 +msgid "Share permalink by email" +msgstr "Поделиться ссылкой по email" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1221 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1403 msgid "Shared query" -msgstr "Общий запрос" +msgstr "Общедоступный запрос" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:283 +msgid "Shared query fields" +msgstr "Поля общедоступного запроса" -#: superset/views/database/forms.py:272 +#: superset/views/database/forms.py:298 msgid "Sheet Name" -msgstr "Полное имя" +msgstr "Имя листа" + +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:510 +msgid "Shift + Click to sort by multiple columns" +msgstr "Shift + Нажать для сортировки по нескольким столбцам" #: superset/annotation_layers/annotations/commands/exceptions.py:46 msgid "Short description must be unique for this layer" -msgstr "Краткое описание должно быть уникальным для этого слоя" +msgstr "Содержимое аннотации должно быть уникальным внутри слоя" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:126 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:130 msgid "" "Should daily seasonality be applied. An integer value will specify " "Fourier order of seasonality." msgstr "" +"Применяется дневная сезонность. Целочисленное значение будет указывать " +"порядок сезонности Фурье." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:109 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:111 msgid "" "Should weekly seasonality be applied. An integer value will specify " "Fourier order of seasonality." msgstr "" +"Применяется недельная сезонность. Целочисленное значение будет указывать " +"порядок сезонности Фурье." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:90 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:92 msgid "" "Should yearly seasonality be applied. An integer value will specify " "Fourier order of seasonality." msgstr "" +"Применяется годовая сезонность. Целочисленное значение будет указывать " +"порядок сезонности Фурье." -#: superset/views/annotations.py:59 -msgid "Show Annotation" -msgstr "Аннотации" - -#: superset/views/annotations.py:118 -msgid "Show Annotation Layer" -msgstr "Слои аннотаций" - -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:80 +#: superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx:38 #, fuzzy +msgid "Show" +msgstr "%s строка" + +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:82 msgid "Show Bubbles" -msgstr "Показать таблицу" +msgstr "Показать пузыри" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:204 +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:233 msgid "Show CREATE VIEW statement" msgstr "Показать выражение CREATE VIEW" -#: superset/views/css_templates.py:37 +#: superset/views/css_templates.py:39 msgid "Show CSS Template" -msgstr "Шаблоны CSS" +msgstr "Показать CSS шаблон" #: superset/views/chart/mixin.py:27 msgid "Show Chart" msgstr "Показать график" -#: superset/connectors/sqla/views.py:64 +#: superset/connectors/sqla/views.py:74 msgid "Show Column" msgstr "Показать столбец" @@ -10932,245 +13392,243 @@ msgstr "Показать дашборд" #: superset/views/database/mixins.py:34 msgid "Show Database" -msgstr "Показать Базу Данных" - -#: superset/connectors/druid/views.py:214 -msgid "Show Druid Cluster" -msgstr "Показать кластер Druid" - -#: superset/connectors/druid/views.py:71 -msgid "Show Druid Column" -msgstr "Показать столбец Druid" - -#: superset/connectors/druid/views.py:278 -msgid "Show Druid Datasource" -msgstr "Показать источник данных Druid" - -#: superset/connectors/druid/views.py:160 -msgid "Show Druid Metric" -msgstr "Показать Druid Метрики" - -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:33 -msgid "Show Druid granularity dropdown" -msgstr "" - -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:44 -msgid "Show Druid time origin" -msgstr "Показать Druid Метрики" +msgstr "Показать базу данных" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:96 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:127 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:126 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:149 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:94 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:71 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:93 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:72 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:70 msgid "Show Labels" -msgstr "Показать таблицу" +msgstr "Показывать метки" -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:359 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:459 msgid "Show Less..." -msgstr "" +msgstr "Показать меньше..." #: superset/views/log/__init__.py:22 msgid "Show Log" -msgstr "Показать итоги" +msgstr "Показать запись" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:64 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:63 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:724 msgid "Show Markers" -msgstr "" +msgstr "Показать маркеры" -#: superset/connectors/sqla/views.py:213 +#: superset/connectors/sqla/views.py:209 msgid "Show Metric" -msgstr "Показать показатель" +msgstr "Показатель меру" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:178 -#, fuzzy msgid "Show Metric Names" -msgstr "Показать показатель" - -#: superset/views/alerts.py:76 -msgid "Show Observation" -msgstr "" +msgstr "Показать имена мер" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:132 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:139 msgid "Show Range Filter" -msgstr "Фильтр результатов" +msgstr "Показать фильтр Диапазон" -#: superset/connectors/sqla/views.py:315 -msgid "Show Row level security filter" -msgstr "Показать фильтр на уровне строк" - -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:120 -msgid "Show SQL time column" -msgstr "Показать колонку Druid" - -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:105 +#: superset/connectors/sqla/views.py:292 #, fuzzy -msgid "Show SQL time grain dropdown" -msgstr "Включить фильтр на определенный интервал/диапазон времени" +msgid "Show Row level security filter" +msgstr "Безопасность на уровне строк" -#: superset/views/sql_lab.py:40 +#: superset/views/sql_lab/views.py:53 msgid "Show Saved Query" msgstr "Показать сохраненный запрос" -#: superset/connectors/sqla/views.py:396 +#: superset/connectors/sqla/views.py:386 msgid "Show Table" msgstr "Показать таблицу" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:77 msgid "Show Timestamp" -msgstr "" +msgstr "Показать метку времени" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:191 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:99 +msgid "Show Total" +msgstr "Показать общий итог" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:97 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:89 msgid "Show Trend Line" -msgstr "" +msgstr "Показать трендовую линию" -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:82 msgid "Show Upper Labels" -msgstr "" +msgstr "Показать верхние метки" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:106 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:108 msgid "Show Value" -msgstr "Показать таблицу" +msgstr "Показать значение" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:164 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:301 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:182 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:315 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:184 msgid "Show Values" -msgstr "Показать таблицу" +msgstr "Показать значения" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx:173 -#, fuzzy +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:284 +msgid "Show Y-axis" +msgstr "Показать ось Y" + +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:285 +msgid "" +"Show Y-axis on the sparkline. Will display the manually set min/max if " +"set or min/max values in the data otherwise." +msgstr "Показывать ось Y на спарклайне." + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx:156 msgid "Show all columns" -msgstr "Показать столбец" +msgstr "Показать все столбцы" -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:326 -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:359 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:422 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:459 msgid "Show all..." -msgstr "" +msgstr "Показать все..." -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:206 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:202 msgid "Show axis line ticks" -msgstr "" +msgstr "Показывать деления на оси" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:119 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:108 msgid "Show cell bars" -msgstr "" +msgstr "Наложить гистограммы на ячейки" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:161 -#, fuzzy +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:412 +msgid "Show chart description" +msgstr "Показать описание графика" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:226 msgid "Show columns total" -msgstr "Показать столбец" +msgstr "Показать общий итог по столбцам" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:67 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:66 msgid "Show data points as circle markers on the lines" msgstr "" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:357 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:359 +msgid "Show empty columns" +msgstr "Показывать пустые столбцы" + #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:52 msgid "" "Show hierarchical relationships of data, with with the value represented " "by area, showing proportion and contribution to the whole." msgstr "" +"Показывает иерархические взаимосвязи данных со значением, представленным " +"областью, показывая пропорцию и вклад в целое." -#: superset-frontend/packages/superset-ui-chart-controls/src/components/InfoTooltipWithTrigger.tsx:50 +#: superset-frontend/packages/superset-ui-chart-controls/src/components/InfoTooltipWithTrigger.tsx:52 msgid "Show info tooltip" -msgstr "" +msgstr "Показать информационную подсказку" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:736 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:786 msgid "Show label" -msgstr "Показать таблицу" +msgstr "Показывать метку" -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:86 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:85 msgid "Show labels when the node has children." -msgstr "" +msgstr "Показывать метки, когда у вершины есть дочерние элементы." -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:35 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:37 msgid "Show legend" -msgstr "" +msgstr "Показывать легенду" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx:168 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx:151 msgid "Show less columns" -msgstr "Показать колонку Druid" +msgstr "Показать меньше столбцов" -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:326 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:422 msgid "Show less..." -msgstr "" +msgstr "Показать меньше..." + +#: superset-frontend/src/components/Form/LabeledErrorBoundInput.tsx:140 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:200 +msgid "Show password." +msgstr "Показать пароль." -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:287 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:301 msgid "Show percentage" -msgstr "" +msgstr "Показывать долю" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:179 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:175 msgid "Show pointer" -msgstr "" +msgstr "Показывать указатель" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:245 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:241 msgid "Show progress" -msgstr "Свойства дашборда" +msgstr "Показывать прогресс" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:149 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:214 msgid "Show rows total" -msgstr "" +msgstr "Показать общий итог по строкам" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:109 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:111 msgid "Show series values on the chart" -msgstr "" +msgstr "Показать значения категорий на графике" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:218 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:214 msgid "Show split lines" -msgstr "" +msgstr "Показывать разделительные линии" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:297 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:317 msgid "Show the value on top of the bar" -msgstr "" +msgstr "Показать значение в верхней части столбца" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:121 -#, fuzzy +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:85 msgid "Show time column" -msgstr "Показать колонку Druid" +msgstr "Показать столбец времени" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:106 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:74 #, fuzzy msgid "Show time grain dropdown" -msgstr "Включить фильтр на определенный интервал/диапазон времени" +msgstr "Включить фильтр на определенный интервал времени" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:351 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx:107 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:363 msgid "" "Show total aggregations of selected metrics. Note that row limit does not" " apply to the result." msgstr "" +"Показать общие итоговые значения выбранных показателей. Обратите " +"внимание, что ограничение количества строк не применяется к результату." -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:87 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:349 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:76 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx:105 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:361 msgid "Show totals" -msgstr "" +msgstr "Показывать общий итог" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:31 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:30 msgid "" "Showcases a single metric front-and-center. Big number is best used to " "call attention to a KPI or the one thing you want your audience to focus " "on." msgstr "" +"Отображает один показатель по центру. Карточку лучше всего использовать, " +"чтобы привлечь внимание к KPI." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:30 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:32 msgid "" "Showcases a single number accompanied by a simple line chart, to call " "attention to an important metric along with its change over time or other" " dimension." msgstr "" +"Отображает один показатель, сопровождаемый простой линейной диаграммой, " +"чтобы привлечь внимание к KPI наряду с его изменением с течением времени " +"или другим измерением." -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:49 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:50 msgid "" "Showcases how a metric changes as the funnel progresses. This classic " "chart is useful for visualizing drop-off between stages in a pipeline or " "lifecycle." msgstr "" +"Отображает изменение показателя по мере сужения воронки. Эта классическая" +" диаграмма полезна для визуализации перехода между этапами процесса или " +"жизненного цикла." #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:28 msgid "" @@ -11178,21 +13636,27 @@ msgid "" "The value and corresponding thickness can be different for each side." msgstr "" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:27 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:28 msgid "" "Showcases the progress of a single metric against a given target. The " "higher the fill, the closer the metric is to the target." msgstr "" +"Демонстрирует прогресс одного показателя по отношению к заданной цели. " +"Чем больше заполнение, тем ближе показатель к целевому показателю." -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:305 -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:338 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:398 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:435 #, python-format msgid "Showing %s of %s" -msgstr "" +msgstr "Отображено %s из %s" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:152 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:178 msgid "Shows a list of all series available at that point in time" -msgstr "" +msgstr "Показывает список всех данных, доступных в определенный момент времени" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:725 +msgid "Shows or hides markers for the time series" +msgstr "Показывает или скрывает маркеры для временных рядов" #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:31 msgid "" @@ -11202,146 +13666,180 @@ msgid "" "hierarchically." msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:72 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:64 msgid "Significance Level" msgstr "" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:262 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:201 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:394 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:397 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:339 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:213 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:412 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:415 msgid "Simple" -msgstr "Простые" +msgstr "Столбец" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:390 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:408 msgid "Simple ad-hoc metrics are not enabled for this dataset" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:186 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:187 msgid "Single" -msgstr "Мои" +msgstr "Один" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:45 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:46 -#, fuzzy msgid "Single Metric" -msgstr "Список показателей" +msgstr "Одна мера" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1234 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1076 msgid "Single Value" -msgstr "Значение фильтра" +msgstr "Единственное значение" -#: superset-frontend/src/filters/components/Range/controlPanel.ts:65 -#, fuzzy +#: superset-frontend/src/filters/components/Range/controlPanel.ts:67 msgid "Single value" -msgstr "Значение фильтра" +msgstr "Единственное значение" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1251 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1093 msgid "Single value type" -msgstr "" +msgstr "Тип единственного значения" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:261 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:262 msgid "Size of edge symbols" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:230 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:168 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:129 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:109 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:126 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:184 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:187 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:232 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:157 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:144 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:86 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:86 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:141 msgid "Size of marker. Also applies to forecast observations." -msgstr "" +msgstr "Размер маркера. Также применяется к прогнозным значениям." #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:34 msgid "Sizes of vehicles" msgstr "" -#: superset/views/database/forms.py:199 +#: superset/views/database/forms.py:177 msgid "Skip Blank Lines" -msgstr "Пропустить пустые строки" +msgstr "Пропуск пустых строк" -#: superset/views/database/forms.py:184 +#: superset/views/database/forms.py:174 msgid "Skip Initial Space" -msgstr "Убрать пробелы" +msgstr "Пропуск начального пробела" -#: superset/views/database/forms.py:187 superset/views/database/forms.py:328 +#: superset/views/database/forms.py:260 superset/views/database/forms.py:354 msgid "Skip Rows" -msgstr "Игнорировать" - -#: superset/views/database/forms.py:200 -msgid "Skip blank lines rather than interpreting them as NaN values." -msgstr "Пропустите пустые строки, а не интерпретировать их как значения NaN." +msgstr "Пропуск строк" -#: superset/views/database/forms.py:184 -msgid "Skip spaces after delimiter." -msgstr "Пропустить пробелы после разделителя." +#: superset/views/database/forms.py:178 +msgid "Skip blank lines rather than interpreting them as Not A Number values" +msgstr "Пропускать пустые строки, вместо их перевода в пустые строки (NaN)" -#: superset/views/schedules.py:243 superset/views/schedules.py:323 -msgid "Slack Channel" -msgstr "Канал Slack" +#: superset/views/database/forms.py:174 +msgid "Skip spaces after delimiter" +msgstr "Пропускать пробелы после разделителя" #: superset/views/dashboard/mixin.py:80 msgid "Slug" msgstr "Читаемый URL" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:39 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:73 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:39 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:73 #: superset-frontend/src/dashboard/util/headerStyleOptions.ts:25 msgid "Small" -msgstr "" +msgstr "Маленький" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:153 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:149 msgid "Small number format" +msgstr "Форматирование маленьких чисел" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:143 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:76 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:76 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:75 +msgid "Smooth Line" +msgstr "Гладкая линия" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:61 +msgid "" +"Smooth-line is a variation of the line chart. Without angles and hard " +"edges, Smooth-line sometimes looks smarter and more professional." msgstr "" -#: superset/commands/exceptions.py:112 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:672 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:687 +msgid "Solid" +msgstr "Сплошной" + +#: superset/commands/exceptions.py:115 msgid "Some roles do not exist" -msgstr "Дашборды отсутствуют" +msgstr "Некоторые роли не существуют" + +#: superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx:64 +msgid "Something went wrong." +msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:623 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:814 #, python-format msgid "Sorry there was an error fetching database information: %s" msgstr "К сожалению, произошла ошибка при получении информации о базе данных: %s" -#: superset-frontend/src/dashboard/actions/sliceEntities.js:121 +#: superset-frontend/src/dashboard/actions/sliceEntities.js:131 msgid "Sorry there was an error fetching saved charts: " msgstr "Извините, произошла ошибка при загрузке графиков: " -#: superset-frontend/src/explore/components/DataTablesPane/index.tsx:273 -#: superset-frontend/src/explore/components/controls/ViewQueryModal.tsx:84 +#: superset-frontend/src/explore/components/controls/ViewQueryModal.tsx:64 msgid "Sorry, An error occurred" msgstr "Извините, произошла ошибка" -#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:65 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:126 +#: superset-frontend/src/components/Chart/chartAction.js:639 +#: superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:89 +msgid "Sorry, an error occurred" +msgstr "Извините, произошла ошибка" + +#: superset-frontend/src/dashboard/actions/dashboardState.js:357 +msgid "Sorry, an unknown error occurred" +msgstr "Извините, произошла неизвестная ошибка" + +#: superset-frontend/src/utils/getClientErrorObject.ts:97 +msgid "Sorry, an unknown error occurred." +msgstr "Извините, произошла неизвестная ошибка." + +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:114 +msgid "Sorry, something went wrong. Embedding could not be deactivated." +msgstr "Извините, что-то пошло не так. Встраивание не может быть деактивировано." + +#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:71 +#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:84 +#: superset-frontend/src/explore/components/EmbedCodeContent.jsx:58 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:130 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:187 msgid "Sorry, something went wrong. Try again later." -msgstr "" +msgstr "Извините, что-то пошло не так. Попробуйте еще раз позже." #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/EventFlow.tsx:50 msgid "Sorry, there appears to be no data" -msgstr "" +msgstr "Извините, похоже, что данные отсутствуют" -#: superset-frontend/src/dashboard/actions/dashboardState.js:238 +#: superset-frontend/src/utils/getClientErrorObject.ts:100 #, fuzzy, python-format +msgid "Sorry, there was an error saving this %s: %s" +msgstr "Извините, произошла ошибка при сохранении дашборда: %s" + +#: superset-frontend/src/dashboard/actions/dashboardState.js:360 +#, python-format msgid "Sorry, there was an error saving this dashboard: %s" -msgstr "Извините, произошла ошибка при загрузке графиков: " +msgstr "Извините, произошла ошибка при сохранении дашборда: %s" -#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:55 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:115 #: superset-frontend/src/views/CRUD/data/components/SyntaxHighlighterCopy/index.tsx:76 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:219 -#: superset-frontend/src/views/CRUD/hooks.ts:604 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:220 +#: superset-frontend/src/views/CRUD/hooks.ts:632 msgid "Sorry, your browser does not support copying." msgstr "" "Извините, Ваш браузер не поддерживание копирование. Используйте сочетание" " клавиш [CTRL + C] для WIN или [CMD + C] для MAC." -#: superset-frontend/src/components/CopyToClipboard/index.jsx:79 +#: superset-frontend/src/components/CopyToClipboard/index.jsx:81 msgid "Sorry, your browser does not support copying. Use Ctrl / Cmd + C!" msgstr "" "Извините, Ваш браузер не поддерживание копирование. Используйте сочетание" @@ -11349,199 +13847,206 @@ msgstr "" #: superset-frontend/src/components/ListView/CardSortSelect.tsx:82 #: superset-frontend/src/components/ListView/CardSortSelect.tsx:83 -#, fuzzy +#: superset-frontend/src/components/Table/index.tsx:266 msgid "Sort" -msgstr "рассылка" +msgstr "Сортировка" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:92 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:83 msgid "Sort Bars" -msgstr "Сортировка" +msgstr "Сортировать столбцы" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:42 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:45 -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:40 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:48 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:47 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:46 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:59 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:354 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:105 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:89 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:86 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:83 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:89 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:90 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:256 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:98 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:158 msgid "Sort Descending" -msgstr "Сортировать" +msgstr "Сортировать по убыванию" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1198 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1040 msgid "Sort Metric" -msgstr "Показатель для сортировки" +msgstr "Мера для сортировки" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:251 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:265 msgid "Sort X Axis" -msgstr "" +msgstr "Сортировка оси X" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:263 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:277 msgid "Sort Y Axis" -msgstr "" +msgstr "Сортировка оси Y" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1188 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1030 #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:205 #: superset-frontend/src/filters/components/Select/controlPanel.ts:66 msgid "Sort ascending" -msgstr "Направление сортировки" +msgstr "Сортировать по возрастанию" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:95 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:86 msgid "Sort bars by x labels." -msgstr "" +msgstr "Сортировать столбцы по меткам на оси X" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:125 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:369 -#: superset-frontend/src/dashboard/components/SliceAdder.jsx:259 -#: superset-frontend/src/explore/controls.jsx:384 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:190 +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:325 +#: superset-frontend/src/explore/controls.jsx:364 msgid "Sort by" msgstr "Сортировка" -#: superset-frontend/src/dashboard/components/SliceAdder.jsx:256 -#, fuzzy, python-format +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:322 +#, python-format msgid "Sort by %s" -msgstr "Сортировка" - -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:39 -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:38 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:94 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:55 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:39 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:62 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:65 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:62 +msgstr "Сорт. по %s" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:95 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:59 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:44 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:64 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:62 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:63 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:61 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:51 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:49 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:38 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:42 msgid "Sort by metric" -msgstr "Показатель для сортировки" +msgstr "Сортировка по мере" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:184 +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:213 msgid "Sort columns alphabetically" msgstr "Отсортировать столбцы в алфавитном порядке" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:257 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:322 msgid "Sort columns by" -msgstr "Отсортировать столбцы в алфавитном порядке" +msgstr "Сортировать столбцы по" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/legacySortBy.tsx:29 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:337 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1189 -#: superset-frontend/src/explore/controlPanels/sections.tsx:125 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/orderBy.tsx:46 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:348 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1031 msgid "Sort descending" -msgstr "Сортировать" +msgstr "Сортировка по убыванию" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1167 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1009 msgid "Sort filter values" -msgstr "Фильтрующийся" +msgstr "Сортировать отфильтрованные значения" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1211 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1053 #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:184 #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:188 msgid "Sort metric" msgstr "Показатель для сортировки" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:229 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:294 msgid "Sort rows by" -msgstr "Сортировка" +msgstr "Сортировка строк по" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1181 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1023 msgid "Sort type" -msgstr "Тип графика" +msgstr "Тип сортировки" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:60 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:52 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1189 +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:64 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:53 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1349 msgid "Source" msgstr "Источник" -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:104 #: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:43 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:33 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:37 msgid "Source / Target" -msgstr "Имя источника данных" +msgstr "Источник / Цель" #: superset-frontend/src/SqlLab/components/HighlightedSql/index.tsx:76 msgid "Source SQL" -msgstr "Источник SQL" +msgstr "Исходный SQL" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:73 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:74 msgid "Source category" -msgstr "Имя источника данных" +msgstr "Исходная категория" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:804 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:73 +msgid "Sparkline" +msgstr "Спарклайн" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:972 msgid "Spatial" msgstr "" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:90 +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:87 msgid "Specific Date/Time" -msgstr "" +msgstr "Конкретная дата/время" -#: superset/views/database/forms.py:127 superset/views/database/forms.py:286 -#: superset/views/database/forms.py:414 +#: superset/views/database/forms.py:312 superset/views/database/forms.py:443 msgid "Specify a schema (if database flavor supports this)." -msgstr "Укажите схему (если это поддерживается базой данных)." +msgstr "Укажите схему (если она поддерживается базой данных)." -#: superset/views/database/forms.py:172 superset/views/database/forms.py:325 +#: superset/views/database/forms.py:351 msgid "Specify duplicate columns as \"X.0, X.1\"." -msgstr "" -"Если есть столбцы с одинаковым именем, то присвоить им порядковые номера " -"- столбец1, столбец2, … и т.д." +msgstr "Обозначить повторяющиеся столбцы как \"X.0, X.1\"." + +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:689 +msgid "Specify name to CREATE TABLE AS schema in: public" +msgstr "Укажите имя новой таблицы для CREATE TABLE AS" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:494 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:688 +msgid "Specify name to CREATE VIEW AS schema in: public" +msgstr "Укажите имя нового представления для CREATE VIEW AS" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:515 msgid "" "Specify the database version. This should be used with Presto in order to" " enable query cost estimation." msgstr "" +"Укажите версию базы данных. Это необходимо для Presto, чтобы включить " +"оценку стоимости запроса" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:230 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:226 msgid "Split number" -msgstr "Big Number" +msgstr "Количество разделителей" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:156 -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:117 -msgid "Stack series" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:84 +msgid "Square kilometers" +msgstr "Квадратные километры" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:83 +msgid "Square meters" +msgstr "Квадратные метры" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:85 +msgid "Square miles" +msgstr "Квадратные мили" + +#: superset-frontend/plugins/plugin-chart-echarts/src/constants.ts:82 +msgid "Stack" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:159 -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:120 -msgid "Stack series on top of each other" +#: superset-frontend/packages/superset-ui-core/src/chart/components/FallbackComponent.tsx:51 +msgid "Stack Trace:" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:37 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:158 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:119 +msgid "Stack series" +msgstr "Использовать накопление" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:161 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:112 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:122 +msgid "Stack series on top of each other" +msgstr "Совместить столбцы в один с накоплением" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:40 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:51 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:40 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:47 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:84 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:83 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:68 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:41 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:53 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:86 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:75 msgid "Stacked" -msgstr "" +msgstr "С наполнением" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:305 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:325 msgid "Stacked Bars" -msgstr "" +msgstr "Столбцы с накоплением" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:52 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:108 +#: superset-frontend/src/explore/fixtures.tsx:58 msgid "Stacked Style" msgstr "" @@ -11549,210 +14054,333 @@ msgstr "" msgid "Stacked style" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:88 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:81 msgid "Standard time series" msgstr "" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:155 -#: superset/views/annotations.py:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:73 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:169 msgid "Start" -msgstr "Время начала" +msgstr "Начало" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/Arc.jsx:40 +msgid "Start (Longitude, Latitude): " +msgstr "Старт (Долгота, Широта): " + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:52 +msgid "Start Longitude & Latitude" +msgstr "Начальные долгота и широта" #: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:79 #, fuzzy msgid "Start Review" -msgstr "Предпросмотр данных" +msgstr "Начать предпросмотр" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:110 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:106 msgid "Start angle" -msgstr "Изменения не сохранены" +msgstr "Начальный угол" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:125 -#, fuzzy +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:128 msgid "Start at (UTC)" -msgstr "Время начала" +msgstr "Время начала (UTC)" + +#: superset-frontend/src/components/ListView/Filters/DateRange.tsx:67 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:307 +#, fuzzy +msgid "Start date" +msgstr "Начальный угол" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:66 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:117 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:131 msgid "Start date included in time range" -msgstr "" +msgstr "Начальная дата включена во временной интервал" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:109 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:101 msgid "Start y-axis at 0" -msgstr "" +msgstr "Начать ось Y с 0" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:112 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:104 msgid "" "Start y-axis at zero. Uncheck to start y-axis at minimum value in the " "data." msgstr "" +"Начать ось Y в нуле. Снимите флаг, чтобы ось Y начиналась на минимальном " +"значении данных" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:94 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:348 +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:97 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:367 msgid "State" msgstr "Состояние" +#: superset/sql_lab.py:511 +#, python-format +msgid "Statement %(statement_num)s out of %(statement_count)s" +msgstr "" + #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 msgid "Statistical" -msgstr "" +msgstr "Статистический учет" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:399 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:302 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:492 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:487 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:317 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:522 msgid "Status" msgstr "Статус" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:112 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:147 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:80 +msgid "Step - end" +msgstr "" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:146 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:78 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:79 +msgid "Step - middle" +msgstr "" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:145 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:77 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:78 +msgid "Step - start" +msgstr "" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:69 #, fuzzy msgid "Step type" msgstr "Таблица Данных" -#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:49 -#: superset-frontend/src/explore/components/QueryAndSaveBtns.jsx:66 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:66 +#, fuzzy +msgid "Stepped Line" +msgstr "Таблица временных рядов" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:52 +msgid "" +"Stepped-line graph (also called step chart) is a variation of line chart " +"but with the line forming a series of steps between data points. A step " +"chart can be useful when you want to show the changes that occur at " +"irregular intervals." +msgstr "" + +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:46 +#: superset-frontend/src/explore/components/RunQueryButton/index.tsx:45 msgid "Stop" msgstr "Стоп" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:339 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:328 msgid "Stop query" msgstr "Остановить запрос" +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:116 +msgid "Stop running (Ctrl + e)" +msgstr "Остановить выполнение (CTRL + X)" + #: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:115 msgid "Stop running (Ctrl + x)" -msgstr "Остановить (Ctrl + x)" +msgstr "Остановить выполнение (CTRL + X)" -#: superset/databases/commands/exceptions.py:126 +#: superset/databases/commands/exceptions.py:128 msgid "Stopped an unsafe database connection" -msgstr "Выберите любые столбцы для проверки метаданных" +msgstr "" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:228 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:374 +msgid "Streets" +msgstr "Схема" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:268 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:269 msgid "Strength to pull the graph toward center" -msgstr "" +msgstr "Сила притяжения вершин к центру" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:36 msgid "Stretched style" msgstr "" -#: superset/views/database/forms.py:273 +#: superset/views/database/forms.py:299 msgid "Strings used for sheet names (default is the first sheet)." -msgstr "Строки, используемые для имён листов (по-умолчанию это первый лист)." +msgstr "Имя листа (по умолчанию первый лист)" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:45 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:234 +msgid "Stroke Color" +msgstr "Цвет обводки" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:119 +msgid "Stroke Width" +msgstr "Ширина обводки" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:259 +msgid "Stroked" +msgstr "С обводкой" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:47 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:45 msgid "Structural" -msgstr "" +msgstr "Структура" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:621 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:669 msgid "Style" msgstr "Стиль" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:272 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:268 msgid "Style the ends of the progress bar with a round cap" -msgstr "" +msgstr "Оформление концов индикатора круглыми заглушками" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:56 msgid "Subdomain" -msgstr "" +msgstr "Подблок" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:46 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:47 msgid "Subheader" -msgstr "Строка заголовков" +msgstr "Подзаголовок" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:62 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:62 msgid "Subheader Font Size" -msgstr "" - -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:63 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:54 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:142 +msgstr "Размер шрифта подзаголовка" + +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:209 +msgid "Submit" +msgstr "Отправить" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx:466 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx:666 +#: superset/charts/post_processing.py:160 +#: superset/charts/post_processing.py:177 +msgid "Subtotal" +msgstr "Подытог" + +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:114 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:63 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:154 msgid "Success" msgstr "Успешно" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:62 -msgid "Suffix to apply after the percentage display" +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:193 +msgid "Successfully changed dataset!" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:98 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:68 +msgid "Suffix to apply after the percentage display" +msgstr "Текст после отображения процентной доли" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:182 +msgid "Sum" +msgstr "Сумма" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:193 +msgid "Sum as Fraction of Columns" +msgstr "Сумма как доля столбцов" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:192 +msgid "Sum as Fraction of Rows" +msgstr "Сумма как доля строк" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:191 +msgid "Sum as Fraction of Total" +msgstr "Сумма как доля целого" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:91 msgid "Sum of values over specified period" -msgstr "" +msgstr "Сумма значений за обозначенный период" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:191 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:265 +msgid "Sum values" +msgstr "Суммарные значения" -#: superset/viz.py:1856 +#: superset/viz.py:1885 msgid "Sunburst" -msgstr "Sunburst" +msgstr "Диаграмма Солнечные лучи" #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:32 -#, fuzzy msgid "Sunburst Chart" -msgstr "График Superset" +msgstr "Диаграмма Солнечные лучи" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts:41 +#, fuzzy +msgid "Sunburst Chart v2" +msgstr "Диаграмма Солнечные лучи" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:56 msgid "Sunday" msgstr "Воскресенье" -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:121 -#, fuzzy +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:125 msgid "Superset Chart" msgstr "График Superset" -#: superset-frontend/src/components/AnchorLink/index.jsx:84 -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:318 +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:187 +msgid "Superset Embedded SDK documentation." +msgstr "" + +#: superset-frontend/src/dashboard/components/AnchorLink/index.tsx:72 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:498 msgid "Superset chart" msgstr "График Superset" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:218 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:239 msgid "Superset dashboard" msgstr "Дашборд Superset" -#: superset/errors.py:105 -#, fuzzy +#: superset/errors.py:111 msgid "Superset encountered an error while running a command." -msgstr "Обнаружена ошибка в запросе." +msgstr "Суперсет столкнулся с ошибкой во время выполнения команды." -#: superset/errors.py:106 -#, fuzzy +#: superset/errors.py:112 msgid "Superset encountered an unexpected error." -msgstr "Неожиданная ошибка графика рассылки" +msgstr "Суперсет столкнулся с неожиданной ошибкой." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:670 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:870 msgid "Supported databases" -msgstr "Выберите базу данных" +msgstr "Поддерживаемые базы данных" #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:34 msgid "Survey Responses" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:112 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:101 msgid "Swap Groups and Columns" -msgstr "" +msgstr "Поменять местами группы и столбцы" + +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:254 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:311 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:435 +msgid "Swap dataset" +msgstr "Сменить датасет" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:175 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:240 msgid "Swap rows and columns" +msgstr "Поменять местами строки и столбцы" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:51 +msgid "" +"Swiss army knife for visualizing data. Choose between step, line, " +"scatter, and bar charts. This viz type has many customization options as " +"well." msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:59 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:54 msgid "" -"Swiss army knife for visualizing time series data. Choose between step, " +"Swiss army knife for visualizing time series data. Choose between step, " "line, scatter, and bar charts. This viz type has many customization " "options as well." msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:210 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:211 msgid "Symbol" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:125 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:126 msgid "Symbol of two ends of edge line" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:255 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:256 #, fuzzy msgid "Symbol size" msgstr "Размер маркера" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1223 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1383 msgid "Sync columns from source" msgstr "Синхронизировать столбцы из источника" @@ -11764,11 +14392,21 @@ msgstr "Синхронизировать столбцы из источника" msgid "Syntax" msgstr "" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:250 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:305 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:268 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:306 msgid "TABLES" msgstr "ТАБЛИЦЫ" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:279 +#, fuzzy +msgid "TEMPORAL X-AXIS" +msgstr "Содержит дату/время" + +#: superset-frontend/src/explore/constants.ts:91 +#, fuzzy +msgid "TEMPORAL_RANGE" +msgstr "Содержит дату/время" + #: superset-frontend/src/components/CronPicker/CronPicker.tsx:85 msgid "THU" msgstr "ЧТ" @@ -11777,45 +14415,45 @@ msgstr "ЧТ" msgid "TUE" msgstr "ВТ" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:218 -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:145 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:236 +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:147 msgid "Tab name" -msgstr "Имя Таблицы" +msgstr "Имя вкладки" -#: superset-frontend/src/dashboard/util/newComponentFactory.js:56 -#: superset-frontend/src/dashboard/util/newComponentFactory.js:57 +#: superset-frontend/src/dashboard/util/newComponentFactory.js:58 +#: superset-frontend/src/dashboard/util/newComponentFactory.js:59 msgid "Tab title" -msgstr "" +msgstr "Имя вкладки" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:25 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:50 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:26 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:51 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:35 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:41 -#: superset-frontend/src/components/TableSelector/index.tsx:293 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:24 -#: superset/connectors/sqla/views.py:148 superset/connectors/sqla/views.py:260 -#: superset/connectors/sqla/views.py:488 superset/views/chart/mixin.py:87 +#: superset-frontend/src/components/TableSelector/index.tsx:313 +#: superset-frontend/src/visualizations/TimeTable/index.ts:26 +#: superset/connectors/sqla/views.py:161 superset/connectors/sqla/views.py:256 +#: superset/connectors/sqla/views.py:478 superset/views/chart/mixin.py:87 msgid "Table" msgstr "Таблица" -#: superset/views/core.py:1761 +#: superset/views/core.py:1726 #, python-format msgid "Table %(table)s wasn't found in the database %(db)s" -msgstr "Таблица %(table)s не найдена в базе данных %(db)s" +msgstr "" -#: superset/views/database/forms.py:138 superset/views/database/forms.py:291 -#: superset/views/database/forms.py:419 +#: superset/views/database/forms.py:317 superset/views/database/forms.py:448 msgid "Table Exists" -msgstr "Метод добавления" +msgstr "Таблица существует" -#: superset/connectors/sqla/views.py:498 superset/views/database/forms.py:95 -#: superset/views/database/forms.py:246 superset/views/database/forms.py:379 +#: superset/connectors/sqla/views.py:488 superset/views/database/forms.py:128 +#: superset/views/database/forms.py:269 superset/views/database/forms.py:405 msgid "Table Name" -msgstr "Имя Таблицы" +msgstr "Имя таблицы" -#: superset/viz.py:671 +#: superset/viz.py:695 +#, fuzzy msgid "Table View" -msgstr "Табличный вид" +msgstr "Убрать предпросмотр таблицы" #: superset/datasets/commands/exceptions.py:130 #, python-format @@ -11823,23 +14461,36 @@ msgid "" "Table [%(table_name)s] could not be found, please double check your " "database connection, schema, and table name" msgstr "" -"Не удалось найти таблицу [%(table_name)s]. Пожалуйста, проверьте " -"подключение к базе данных, схему и имя таблицы" +"Не удается найти таблицу \"%(table_name)s\", пожалуйста, проверьте ваше " +"соединение с базой данных, схему и имя таблицы" -#: superset/views/base.py:251 +#: superset/views/base.py:293 msgid "" "Table [%{table}s] could not be found, please double check your database " "connection, schema, and table name, error: {}" msgstr "" -"Не удалось найти таблицу [{}]. Проверьте подключение к базе данных, схему" -" и имя таблицы." +"Не удается найти таблицу \"%(table)s\", пожалуйста, проверьте ваше " +"соединение с базой данных, схему и имя таблицы, ошибка: {}" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:257 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:268 msgid "Table cache timeout" -msgstr "Тайм-аут Кэша" +msgstr "Время жизни кэша таблицы" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx:176 +msgid "Table columns" +msgstr "Столбцы таблицы" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx:246 +#, fuzzy +msgid "Table loading" +msgstr "Загрузка таблицы" + +#: superset/views/database/forms.py:132 superset/views/database/forms.py:273 +#: superset/views/database/forms.py:409 +msgid "Table name cannot contain a schema" +msgstr "Имя таблицы не может содержать схему" -#: superset/databases/decorators.py:46 +#: superset/databases/decorators.py:47 msgid "Table name undefined" msgstr "Имя таблицы не определено" @@ -11848,28 +14499,31 @@ msgid "" "Table that visualizes paired t-tests, which are used to understand " "statistical differences between groups." msgstr "" +"Таблица, визуализирующая парные t-тесты, которые используются для " +"нахождения статистических различий между группами." -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:269 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:324 -#: superset/connectors/sqla/views.py:367 superset/connectors/sqla/views.py:395 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:287 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:325 +#: superset/connectors/sqla/views.py:364 superset/connectors/sqla/views.py:385 msgid "Tables" msgstr "Таблицы" #: superset-frontend/src/dashboard/components/gridComponents/new/NewTabs.jsx:31 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx:64 msgid "Tabs" msgstr "Вкладки" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:57 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:50 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:34 +#: superset-frontend/src/visualizations/TimeTable/index.ts:37 msgid "Tabular" -msgstr "" +msgstr "Таблицы" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:607 -#, fuzzy +#: superset-frontend/src/components/MetadataBar/ContentConfig.tsx:126 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:683 msgid "Tags" -msgstr "Статус" +msgstr "Теги" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:29 msgid "" @@ -11877,37 +14531,38 @@ msgid "" "densest areas of information lie" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:62 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:70 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:63 msgid "Target" -msgstr "Время начала" +msgstr "Цель" -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:67 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:92 +msgid "Target Color" +msgstr "Целевой цвет" + +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:57 msgid "Target aspect ratio for treemap tiles." msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:86 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:87 msgid "Target category" -msgstr "Время начала" +msgstr "Целевая категория" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:176 -#, fuzzy +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:173 msgid "Target value" -msgstr "Время начала" +msgstr "Целевое значение" -#: superset/views/css_templates.py:44 +#: superset/views/css_templates.py:46 msgid "Template Name" -msgstr "Имя Шаблона" +msgstr "Имя шаблона" -#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:94 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:788 -#: superset/connectors/sqla/views.py:504 +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:99 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:956 +#: superset/connectors/sqla/views.py:494 msgid "Template parameters" msgstr "Параметры шаблона" -#: superset-frontend/src/explore/controlPanels/TimeTable.js:52 +#: superset-frontend/src/visualizations/TimeTable/controlPanel.js:52 msgid "" "Templated link, it's possible to include {{ metric }} or other values " "coming from the controls." @@ -11915,87 +14570,102 @@ msgstr "" "Шаблонная ссылка, можно включить {{ metric }} или другие значения, " "поступающие из элементов управления." -#: superset/models/sql_types/base.py:54 -#, python-format -msgid "Temporal expression not supported for type: %(col_type)s" -msgstr "" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:307 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:317 msgid "" "Terminate running queries when browser window closed or navigated to " "another page. Available for Presto, Hive, MySQL, Postgres and Snowflake " "databases." msgstr "" +"Завершать выполнение запросов после закрытия браузерной вкладки или " +"пользователь переключился на другую вкладку. Доступно для баз данных " +"Presto, Hive, MySQL, Postgres и Snowflake." #: superset/templates/superset/models/database/macros.html:22 msgid "Test Connection" msgstr "Тестовое соединение" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:95 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:112 msgid "Test connection" msgstr "Тестовое соединение" -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:35 -#, fuzzy +#: superset-frontend/src/dashboard/components/gridComponents/new/NewMarkdown.jsx:31 +#: superset-frontend/src/visualizations/TimeTable/index.ts:38 msgid "Text" -msgstr "След" +msgstr "Текст" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:105 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:94 msgid "Text align" -msgstr "" +msgstr "Выравнивание текста" -#: superset-frontend/src/components/ReportModal/index.tsx:289 +#: superset-frontend/src/components/ReportModal/index.tsx:242 msgid "Text embedded in email" -msgstr "" +msgstr "Текст, включенный в email" #: superset/views/dashboard/mixin.py:53 msgid "" "The CSS for individual dashboards can be altered here, or in the " "dashboard view where changes are immediately visible" -msgstr "В этом поле можно задать индивидуальный стиль для дашборда с помощью CSS" +msgstr "" -#: superset/errors.py:118 -#, fuzzy +#: superset/errors.py:124 msgid "" "The CTAS (create table as select) doesn't have a SELECT statement at the " "end. Please make sure your query has a SELECT as its last statement. " "Then, try running your query again." msgstr "" -"CTAS (create table as select) может быть выполнено только в запросе, " -"последняя операция которого SELECT." +"CTAS (CREATE TABLE AS SELECT) не содержит SELECT запрос в конце. " +"Пожалуйста, убедитесь, что ваш запрос имеет SELECT запрос в конце. Затем " +"попробуйте повторно выполнить запрос." + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:27 +msgid "" +"The GeoJsonLayer takes in GeoJSON formatted data and renders it as " +"interactive polygons, lines and points (circles, icons and/or texts)." +msgstr "" +"Диаграмма принимает данные в формате GeoJSON и отображает их в виде " +"интерактивных полигонов, линий и точек (кругов, значков и/или текста)." + +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:406 +msgid "The URL is missing the dataset_id or slice_id parameters." +msgstr "" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:921 -msgid "The JSON metric or post aggregation definition." +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:307 +msgid "The X-axis is not on the filters list" msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:126 +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:309 msgid "" -"The URL could not be identified. Please check for typos and make sure " -"that \"Type of google sheet allowed\" selection matches the input" +"The X-axis is not on the filters list which will prevent it from being " +"used in\n" +" time range filters in dashboards. Would you like to add it to" +" the filters list?" msgstr "" -#: superset/views/core.py:354 +#: superset/views/core.py:370 msgid "The access requests seem to have been deleted" -msgstr "Запросы доступа, похоже, были удалены" +msgstr "" #: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:168 -#, fuzzy msgid "The annotation has been saved" -msgstr "Дашборд сохранен" +msgstr "Аннотация сохранена" #: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:152 -#, fuzzy msgid "The annotation has been updated" -msgstr "Аннотация не может быть обновлена." +msgstr "Аннотация обновлена" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:74 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:75 msgid "" "The category of source nodes used to assign colors. If a node is " "associated with more than one category, only the first will be used." msgstr "" +"Категория исходных вершин предназначена для задания цветов. Если вершина " +"связана более, чем с одной категорией, только первая будет использована." -#: superset/common/query_context_processor.py:449 -#, fuzzy +#: superset/common/query_context_processor.py:582 +msgid "The chart datasource does not exist" +msgstr "Источник данных графика не существует" + +#: superset/common/query_context_processor.py:580 msgid "The chart does not exist" msgstr "График не существует" @@ -12008,109 +14678,117 @@ msgid "" " Pie charts can be difficult to interpret precisely. If clarity of" " relative proportion is important, consider using a bar or other chart " "type instead." -msgstr "" +msgstr "Классическая круговая/кольцевая диаграмма." -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:261 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:266 msgid "The color for points and clusters in RGB" -msgstr "" +msgstr "Цвет для маркеров и кластеров в RGB" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:478 -#: superset-frontend/src/explore/controls.jsx:484 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:341 +#: superset-frontend/src/explore/controls.jsx:464 msgid "The color scheme for rendering chart" msgstr "Цветовая схема, применяемая для раскрашивания графика" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:66 +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx:55 msgid "" "The color scheme is determined by the related dashboard.\n" -" Edit the color scheme in the dashboard properties." +" Edit the color scheme in the dashboard properties." msgstr "" +"Цветовая схема определена соответствующим дашбордом.\n" +" Измените цветовую схему в свойствах дашборда." -#: superset/errors.py:99 -#, fuzzy +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:196 +msgid "The column header label" +msgstr "Заголовок столбца" + +#: superset/errors.py:105 msgid "The column was deleted or renamed in the database." -msgstr "Проблема 1004 - Столбец был удалён или переименован в базе данных." +msgstr "Столбец был удален или переименован в базе данных." -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:47 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:49 msgid "" "The country code standard that Superset should expect to find in the " "[country] column" -msgstr "" +msgstr "Код страны, который Суперсет ожидает найти в столбце со страной" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:327 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:392 msgid "The dashboard has been saved" msgstr "Дашборд сохранен" -#: superset/views/core.py:182 +#: superset/views/core.py:195 msgid "The data source seems to have been deleted" msgstr "Источник данных, похоже, был удален" -#: superset/connectors/sqla/views.py:103 +#: superset/connectors/sqla/views.py:116 msgid "" "The data type that was inferred by the database. It may be necessary to " "input a type manually for expression-defined columns in some cases. In " "most case users should not need to alter this." msgstr "" -"Задать тип данных. В некоторых случаях может потребоваться ввести тип " -"вручную для столбцов, которые формируются специальными запросами. В " -"большинстве случаев изменять содержимое этого поля не обязательно." -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:439 -#, fuzzy, python-format +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:512 +#, python-format msgid "" "The database %s is linked to %s charts that appear on %s dashboards and " "users have %s SQL Lab tabs using this database open. Are you sure you " "want to continue? Deleting the database will break those objects." msgstr "" -"Датасет %s привязан к графикам %s, которые используются в дашбордах %s. " -"Вы уверены, что хотите продолжить? Удаление датасета приведёт к " -"неработоспособности этих объектов." +"База данных %s привязана к %s графику(-ам), который(-ые) " +"используется(-ются) в %s дашборде(-ах), и пользователи имеют %s " +"открытую(-ых) вкладку(-ок) в Лаборатории SQL. Вы уверены, что хотите " +"продолжить? Удаление базы данных приведёт к неработоспособности этих " +"компонентов." -#: superset/errors.py:126 -msgid "The database is currently running too many queries." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:198 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx:28 +msgid "The database columns that contains lines information" msgstr "" -#: superset/errors.py:93 -#, fuzzy +#: superset/errors.py:132 +msgid "The database is currently running too many queries." +msgstr "В настоящий момент база данных обрабатывает слишком много запросов." + +#: superset/errors.py:99 msgid "The database is under an unusual load." -msgstr "Проблема 1001 - Необычная загрузка базы данных." +msgstr "Нетипично высокая загрузка базы данных" -#: superset/sqllab/command.py:149 +#: superset/sqllab/commands/execute.py:168 msgid "" "The database referenced in this query was not found. Please contact an " "administrator for further assistance or try again." msgstr "" +"База данных, указанная в этом запросе, не найдена. Пожалуйста, обратитесь" +" к своему администратору или попробуйте еще раз." -#: superset/errors.py:94 -#, fuzzy +#: superset/errors.py:100 msgid "The database returned an unexpected error." -msgstr "Проблема 1002 - База данных вернула непредвиденную ошибку." +msgstr "База данных вернула неожиданную ошибку" -#: superset/errors.py:138 -#, fuzzy +#: superset/errors.py:144 msgid "The database was deleted." -msgstr "Источник данных, похоже, был удален" +msgstr "База данных была удалена" -#: superset/views/core.py:2085 superset/views/core.py:2155 -#, fuzzy +#: superset/datasets/commands/duplicate.py:60 superset/views/core.py:1980 msgid "The database was not found." -msgstr "База данных не найдена." +msgstr "Не удалось найти базу данных" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:592 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:738 #, python-format msgid "" "The dataset %s is linked to %s charts that appear on %s dashboards. Are " "you sure you want to continue? Deleting the dataset will break those " "objects." msgstr "" -"Датасет %s привязан к графикам %s, которые используются в дашбордах %s. " -"Вы уверены, что хотите продолжить? Удаление датасета приведёт к " -"неработоспособности этих объектов." +"Датасет %s привязан к %s графику(-ам), который(-ые) используется(-ются) в" +" %s дашборде(-ах). Вы уверены, что хотите продолжить? Удаление датасета " +"приведёт к неработоспособности этих объектов." -#: superset-frontend/src/chart/Chart.jsx:73 superset/views/utils.py:268 +#: superset-frontend/src/components/Chart/Chart.jsx:84 +#: superset/views/utils.py:273 msgid "The dataset associated with this chart no longer exists" -msgstr "" +msgstr "Датасет, связанный с этим графиком, больше не существует" -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:167 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:164 msgid "" "The dataset configuration exposed here\n" " affects all the charts using this dataset.\n" @@ -12118,120 +14796,106 @@ msgid "" " here may affect other charts\n" " in undesirable ways." msgstr "" -"Здесь представлена конфигурация датасета\n" +"Представленная здесь конфигурация датасета\n" " влияет на все графики, использующие этот датасет.\n" " Помните, что изменение настроек\n" " может иметь неожиданный эффект\n" " на другие графики." -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:128 -#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:109 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:125 +#: superset-frontend/src/pages/ChartCreation/index.tsx:252 msgid "The dataset has been saved" -msgstr "Источник данных, похоже, был удален" +msgstr "Датасет сохранен" -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:256 -#, fuzzy +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:424 msgid "The dataset linked to this chart may have been deleted." -msgstr "Источник данных, похоже, был удален" +msgstr "Датасет, связанный с этим графиком, похоже, был удален." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1283 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1470 msgid "The datasource couldn't be loaded" -msgstr "Запрос невозможно загрузить" +msgstr "Невозможно загрузить источник данных" -#: superset/errors.py:92 -#, fuzzy +#: superset/errors.py:98 msgid "The datasource is too large to query." -msgstr "Проблема 1000 - Источник данных слишком велик для запроса." +msgstr "Источник данных слишком велик для запроса." -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:247 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:260 msgid "" "The description can be displayed as widget headers in the dashboard view." " Supports markdown." msgstr "" -"Описание может быть отображено как заголовок виджета в ракурсе дашбордов." -" Поддерживает markdown-разметку." +"Описание может быть отображено как заголовок графика в дашборде. " +"Поддерживает markdown-разметку" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:104 msgid "The distance between cells, in pixels" -msgstr "" +msgstr "Расстояние между ячейками (в пикселях)" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:772 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:940 msgid "The duration of time in seconds before the cache is invalidated" msgstr "Количество секунд до истечения срока действия кэша" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:474 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:348 +#, fuzzy +msgid "The encoding format of the lines" +msgstr "Показатель, по которому сортировать результаты" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:495 msgid "" "The engine_params object gets unpacked into the sqlalchemy.create_engine " "call." -msgstr "" +msgstr "Объект engine_params вызывает sqlalchemy.create_engine" -#: superset/common/query_object.py:295 +#: superset/common/query_object.py:313 #, python-format msgid "" "The following entries in `series_columns` are missing in `columns`: " "%(columns)s. " msgstr "" -#: superset/connectors/sqla/views.py:612 -#, python-format -msgid "The following tables added new columns: %(tables)s" -msgstr "" - -#: superset/connectors/sqla/views.py:623 -#, python-format -msgid "The following tables removed columns: %(tables)s" -msgstr "" - -#: superset/connectors/sqla/views.py:634 -#, python-format -msgid "The following tables update column metadata: %(tables)s" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:67 +msgid "The function to use when aggregating points into groups" msgstr "" -#: superset/db_engine_specs/mysql.py:134 +#: superset/db_engine_specs/mysql.py:158 #, python-format msgid "The host \"%(hostname)s\" might be down and can't be reached." -msgstr "" +msgstr "Хост \"%(hostname)s\" возможно, отключен, и с ним невозможно связаться" -#: superset/db_engine_specs/mssql.py:92 -#: superset/db_engine_specs/postgres.py:137 -#: superset/db_engine_specs/presto.py:205 -#: superset/db_engine_specs/redshift.py:78 +#: superset/db_engine_specs/mssql.py:103 +#: superset/db_engine_specs/postgres.py:119 +#: superset/db_engine_specs/presto.py:637 +#: superset/db_engine_specs/redshift.py:82 #, python-format msgid "" "The host \"%(hostname)s\" might be down, and can't be reached on port " "%(port)s." msgstr "" +"Хост \"%(hostname)s\" возможно, отключен, и с ним невозможно связаться по" +" порту %(port)s." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:98 -msgid "The host is invalid. Please verify that this field is entered correctly." -msgstr "" - -#: superset/errors.py:104 +#: superset/errors.py:110 msgid "The host might be down, and can't be reached on the provided port." -msgstr "" +msgstr "Хост возможно, отключен, и с ним невозможно связаться по заданному порту." -#: superset/db_engine_specs/mssql.py:82 -#: superset/db_engine_specs/postgres.py:127 -#: superset/db_engine_specs/presto.py:200 -#: superset/db_engine_specs/redshift.py:68 +#: superset/db_engine_specs/mssql.py:93 +#: superset/db_engine_specs/postgres.py:109 +#: superset/db_engine_specs/presto.py:632 +#: superset/db_engine_specs/redshift.py:72 #, python-format msgid "The hostname \"%(hostname)s\" cannot be resolved." -msgstr "" +msgstr "Не удалось обнаружить хост \"%(hostname)s\"" -#: superset/errors.py:102 +#: superset/errors.py:108 msgid "The hostname provided can't be resolved." -msgstr "" +msgstr "Не удалось обнаружить хост." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:60 -#: superset-frontend/src/explore/controlPanels/sections.tsx:44 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:72 +#: superset-frontend/src/explore/controlPanels/sections.tsx:34 msgid "The id of the active chart" -msgstr "Идентификатор активного среза" +msgstr "Идентификатор активного графика" -#: superset-frontend/src/components/ImportModal/index.tsx:187 -msgid "The import was successful" -msgstr "Неудачно" - -#: superset/connectors/druid/views.py:303 superset/connectors/sqla/views.py:429 +#: superset/connectors/sqla/views.py:419 msgid "" "The list of charts associated with this table. By altering this " "datasource, you may change how these associated charts behave. Also note " @@ -12239,18 +14903,14 @@ msgid "" "saving if removing charts from a datasource. If you want to change the " "datasource for a chart, overwrite the chart from the 'explore view'" msgstr "" -"Список графиков, связанных с этой таблицей. Изменяя этот источник данных," -" можно изменить поведение связанных с ним графиков. Также обратите " -"внимание, что графики должны указывать на источник данных, поэтому эта " -"форма не будет сохранена при удалении срезов из источника данных. Если вы" -" хотите изменить источник данных для среза, сделайте это в свойствах " -"самого графика." -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:130 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:129 msgid "The maximum number of events to return, equivalent to the number of rows" msgstr "" +"Максимальное количество возвращаемых событий, эквивалентно количеству " +"строк" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:179 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:172 msgid "" "The maximum number of subdivisions of each group; lower values are pruned" " first" @@ -12258,34 +14918,34 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:49 msgid "The maximum value of metrics. It is an optional configuration" -msgstr "" +msgstr "Максимальное значение мер. Это необязательная настройка" -#: superset/databases/schemas.py:206 +#: superset/databases/schemas.py:217 #, python-format msgid "" "The metadata_params in Extra field is not configured correctly. The key " "%(key)s is invalid." msgstr "" -#: superset/databases/commands/exceptions.py:79 -#: superset/views/database/mixins.py:252 +#: superset/databases/commands/exceptions.py:80 +#: superset/views/database/mixins.py:248 msgid "" "The metadata_params in Extra field is not configured correctly. The key " "%{key}s is invalid." msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:452 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:469 msgid "" "The metadata_params object gets unpacked into the sqlalchemy.MetaData " "call." -msgstr "" +msgstr "Объект metadata_params вызывает sqlalchemy.MetaData" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:75 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:292 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:175 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:195 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:426 -#: superset-frontend/src/explore/controlPanels/sections.tsx:191 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:82 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:285 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:167 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:436 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:216 +#: superset-frontend/src/explore/controlPanels/sections.tsx:164 msgid "" "The minimum number of rolling periods required to show a value. For " "instance if you do a cumulative sum on 7 days you may want your \"Min " @@ -12293,85 +14953,95 @@ msgid "" "periods. This will hide the \"ramp up\" taking place over the first 7 " "periods" msgstr "" -"Скрыть необходимое количество периодов. Например, если вы делаете " -"накопительную сумму показателя за 7 дней, но хотите скрыть нарастающий " -"итог за первые 6 дней, то указав в данном столбце «6», вы скроете " -"нарастание, происходящее в течение первых 6 периодов" +"Минимальное количество скользящих периодов, необходимое для отображения " +"значения. Например, если вы делаете накопительную сумму за 7 дней, вы " +"можете указать, чтобы \"Минимальный период\" был равен 7, так что все " +"показанные точки данных представляют собой общее количество 7 периодов." #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:130 msgid "The number color \"steps\"" -msgstr "" +msgstr "Количество цветов в цветовой схеме" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:781 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:949 msgid "" "The number of hours, negative or positive, to shift the time column. This" " can be used to move UTC time to local time." msgstr "" +"Количество часов, отрицательное или положительное, для сдвига столбца " +"формата дата/время. Это может быть использовано для приведения часового " +"пояса UTC к местному времени." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:583 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:305 #, python-format msgid "" "The number of results displayed is limited to %(rows)d by the " "configuration DISPLAY_MAX_ROWS. Please add additional limits/filters or " "download to csv to see more rows up to the %(limit)d limit." msgstr "" +"Количество отображаемых результатов ограничено %(rows)d переменной " +"DISPLAY_MAX_ROWS. Пожалуйста, добавьте дополнительные ограничения/фильтры" +" или загрузите в csv, чтобы увидеть больше строк до предела %(limit)d." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:589 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:311 #, python-format msgid "" "The number of results displayed is limited to %(rows)d. Please add " "additional limits/filters, download to csv, or contact an admin to see " "more rows up to the %(limit)d limit." msgstr "" +"Количество отображаемых результатов ограничено %(rows)d. Пожалуйста, " +"добавьте дополнительные ограничения/фильтры или загрузите в csv, чтобы " +"увидеть больше строк до предела %(limit)d.\"" + +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:362 +#, fuzzy, python-format +msgid "The number of rows displayed is limited to %(rows)d by the dropdown." +msgstr "Количество отображаемых строк ограничено: не более %(rows)d." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:615 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:331 #, python-format msgid "The number of rows displayed is limited to %(rows)d by the limit dropdown." -msgstr "" +msgstr "Количество отображаемых строк ограничено: не более %(rows)d." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:603 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:323 #, python-format msgid "The number of rows displayed is limited to %(rows)d by the query" -msgstr "" +msgstr "Количество отображаемых строк ограничено: не более %(rows)d." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:624 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:336 #, python-format msgid "" "The number of rows displayed is limited to %(rows)d by the query and " "limit dropdown." -msgstr "" - -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:644 -#, python-format -msgid "The number of rows displayed is limited to %s by the dropdown." -msgstr "" +msgstr "Количество отображаемых строк ограничено: не более %(rows)d." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:69 -#: superset-frontend/src/explore/controlPanels/sections.tsx:53 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:81 +#: superset-frontend/src/explore/controlPanels/sections.tsx:43 msgid "The number of seconds before expiring the cache" msgstr "Количество секунд до истечения срока действия кэша" -#: superset/errors.py:128 -#, fuzzy +#: superset/errors.py:134 msgid "The object does not exist in the given database." -msgstr "Имя таблицы, которая существует в исходной базе данных" +msgstr "Объект не существует в этой базе данных." #: superset/sqllab/query_render.py:97 #, python-format msgid "The parameter %(parameters)s in your query is undefined." msgid_plural "The following parameters in your query are undefined: %(parameters)s." -msgstr[0] "Следующие параметры в запросе не определены: %(parameters)s." +msgstr[0] "Параметр %(parameters)s в вашем запросе неопределен." +msgstr[1] "Следующие параметры неопределены в вашем запросе: %(parameters)s" +msgstr[2] "Следующие параметры неопределены в вашем запросе: %(parameters)s" -#: superset/db_engine_specs/postgres.py:117 +#: superset/db_engine_specs/postgres.py:99 #, python-format msgid "The password provided for username \"%(username)s\" is incorrect." -msgstr "" +msgstr "Неверный пароль для пользователя \"%(username)s\"." -#: superset/errors.py:108 +#: superset/errors.py:114 msgid "The password provided when connecting to a database is not valid." -msgstr "" +msgstr "Неверный пароль для базы данных." -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:65 +#: superset-frontend/src/pages/ChartList/index.tsx:89 msgid "" "The passwords for the databases below are needed in order to import them " "together with the charts. Please note that the \"Secure Extra\" and " @@ -12380,9 +15050,10 @@ msgid "" "needed." msgstr "" "Для баз данных нужны пароли, чтобы импортировать их вместе с графиками. " -"Пожалуйста, обратите внимание, что разделы “Безопасность” и “Сертификат” " -"в настройках конфигурации базы данных отсутствуют в экспортируемых файлов" -" и должны быть добавлены вручную после импорта, если необходимо." +"Пожалуйста, обратите внимание, что разделы \"Безопасность\" и " +"\"Утверждение\" в настройках конфигурации базы данных отсутствуют в " +"экспортируемых файлов и должны быть добавлены вручную после импорта, если" +" необходимо." #: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:57 msgid "" @@ -12393,9 +15064,10 @@ msgid "" "needed." msgstr "" "Для баз данных нужны пароли, чтобы импортировать их вместе с дашбордами. " -"Пожалуйста, обратите внимание, что разделы “Безопасность” и “Сертификат” " -"в настройках конфигурации базы данных отсутствуют в экспортируемых файлов" -" и должны быть добавлены вручную после импорта, если необходимо." +"Пожалуйста, обратите внимание, что разделы \"Безопасность\" и " +"\"Утверждение\" в настройках конфигурации базы данных отсутствуют в " +"экспортируемых файлах и должны быть добавлены вручную после импорта, если" +" необходимо." #: superset-frontend/src/views/CRUD/data/dataset/constants.ts:23 msgid "" @@ -12406,12 +15078,11 @@ msgid "" "needed." msgstr "" "Пароли к базам данных требуются, чтобы импортировать их вместе с " -"датасетами. Пожалуйста, обратите внимание, что разделы “Безопасность” и " -"“Сертификат” конфигурации базы данных отсутствуют в экспортируемых файлах" -" и должны быть добавлены после импорта вручную." +"датасетами. Пожалуйста, обратите внимание, что разделы \"Безопасность\" и" +" \"Утверждение\" конфигурации базы данных отсутствуют в экспортируемых " +"файлах и должны быть добавлены после импорта вручную, если необходимо." -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:56 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:57 msgid "" "The passwords for the databases below are needed in order to import them " "together with the saved queries. Please note that the \"Secure Extra\" " @@ -12419,36 +15090,43 @@ msgid "" "present in export files, and should be added manually after the import if" " they are needed." msgstr "" -"Для баз данных нужны пароли, чтобы импортировать их вместе с графиками. " -"Пожалуйста, обратите внимание, что разделы “Безопасность” и “Сертификат” " -"в настройках конфигурации базы данных отсутствуют в экспортируемых файлов" -" и должны быть добавлены вручную после импорта, если необходимо." +"Для баз данных нужны пароли, чтобы импортировать их вместе с сохраненными" +" запросами. Пожалуйста, обратите внимание, что разделы \"Безопасность\" и" +" \"Утверждение\" в настройках конфигурации базы данных отсутствуют в " +"экспортируемых файлах и должны быть добавлены вручную после импорта, если" +" необходимо." -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:39 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1169 msgid "" "The passwords for the databases below are needed in order to import them." " Please note that the \"Secure Extra\" and \"Certificate\" sections of " -"the database configuration are not present in export files, and should be" +"the database configuration are not present in explore files and should be" " added manually after the import if they are needed." msgstr "" +"Пароли к базам данных требуются, чтобы импортировать их. Пожалуйста, " +"обратите внимание, что разделы \"Безопасность\" и \"Утверждение\" в " +"настройках конфигурации базы данных отсутствуют в импортируемых файлах и " +"должны быть добавлены вручную после импорта, если необходимо." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:231 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:298 msgid "The pattern of timestamp format. For strings use " -msgstr "" +msgstr "Шаблон формата отметки времени (таймштампа). Для строк используйте " -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:65 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:66 msgid "" "The periodicity over which to pivot time. Users can provide\n" " \"Pandas\" offset alias.\n" " Click on the info bubble for more details on accepted " "\"freq\" expressions." msgstr "" +"Периодичность для группировки по времени. Пользователи могут задавать " +"собственную частоту. Для этого нажмите на иконку с информацией." #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:118 msgid "The pixel radius" -msgstr "" +msgstr "Радиус ячейки (в пикселях)" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:977 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1149 msgid "" "The pointer to a physical table (or view). Keep in mind that the chart is" " associated to this Superset logical table, and this logical table points" @@ -12458,172 +15136,175 @@ msgstr "" " график связан с логической таблицей Superset, а эта логическая таблица " "указывает на физическую таблицу, указанную здесь." -#: superset/errors.py:103 -#, fuzzy +#: superset/errors.py:109 msgid "The port is closed." -msgstr "Рассылка не удалась" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:108 -#, fuzzy -msgid "The port must be a whole number less than or equal to 65535." -msgstr "`лимит_строк` должен быть больше или равен 1" +msgstr "Порт закрыт." -#: superset/errors.py:136 -#, fuzzy +#: superset/errors.py:142 msgid "The port number is invalid." -msgstr "Параметры базы данных недействительны." +msgstr "Недействительный порт." -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:57 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:62 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:159 msgid "The primary metric is used to define the arc segment sizes" -msgstr "" -"Показатель, используемый для определения какие временные ряды будут " -"отображаться при ограничении количества выводимых рядов" +msgstr "Основная мера используется для определения размера сегмента дуги" -#: superset/views/core.py:2330 +#: superset/views/core.py:2187 msgid "The provided `rows` argument is not a valid integer." msgstr "" -#: superset/errors.py:131 +#: superset/errors.py:137 msgid "The query associated with the results was deleted." -msgstr "" +msgstr "Запрос, связанный с результатами, был удален." -#: superset/views/core.py:2280 +#: superset/sqllab/commands/results.py:92 superset/views/core.py:2137 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" -#: superset/sqllab/query_render.py:113 +#: superset/sqllab/query_render.py:118 msgid "The query contains one or more malformed template parameters." msgstr "" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:106 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:107 msgid "The query couldn't be loaded" msgstr "Запрос невозможно загрузить" -#: superset/errors.py:129 +#: superset/errors.py:135 msgid "The query has a syntax error." -msgstr "" +msgstr "Запрос имеет синтаксическую ошибку." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:771 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:516 msgid "The query returned no data" -msgstr "Результат пуст" +msgstr "Запрос не вернул данных" -#: superset/sql_lab.py:265 +#: superset/sql_lab.py:301 #, python-format msgid "" "The query was killed after %(sqllab_timeout)s seconds. It might be too " "complex, or the database might be under heavy load." msgstr "" +"Запрос был прерван после %(sqllab_timeout)s секунд. Он мог быть слишком " +"сложным, или база данных находилась под большой нагрузкой." -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:87 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:97 msgid "" "The radius (in pixels) the algorithm uses to define a cluster. Choose 0 " "to turn off clustering, but beware that a large number of points (>1000) " "will cause lag." msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:110 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:120 msgid "" "The radius of individual points (ones that are not in a cluster). Either " "a numerical column or `Auto`, which scales the point based on the largest" " cluster" msgstr "" +"Радиус маркеров (не находящихся в кластере). Выберите числовой столбец " +"или `Автоматически`, который отмасштабирует маркеры по наибольшему " +"маркеру." -#: superset-frontend/src/reports/actions/reports.js:111 -#, fuzzy +#: superset-frontend/src/reports/actions/reports.js:110 msgid "The report has been created" -msgstr "Источник данных, похоже, был удален" +msgstr "Рассылка создана" -#: superset/errors.py:130 +#: superset/errors.py:136 msgid "The results backend no longer has the data from the query." -msgstr "" +msgstr "Сервер не сохранил данные из этого запроса." -#: superset/errors.py:132 +#: superset/errors.py:138 msgid "" "The results stored in the backend were stored in a different format, and " "no longer can be deserialized." msgstr "" +"Данные, сохраненные на сервере, имели другой формат, и не могут быть " +"распознаны." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:233 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:103 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:284 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:226 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:95 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:304 msgid "The rich tooltip shows a list of all series for that point in time" msgstr "" +"Расширенная всплывающая подсказка показывает список всех категорий для " +"этой точки." -#: superset/db_engine_specs/bigquery.py:171 +#: superset/db_engine_specs/bigquery.py:183 #, python-format msgid "" "The schema \"%(schema)s\" does not exist. A valid schema must be used to " "run this query." msgstr "" -#: superset/db_engine_specs/presto.py:187 +#: superset/db_engine_specs/presto.py:619 #, python-format msgid "" "The schema \"%(schema_name)s\" does not exist. A valid schema must be " "used to run this query." msgstr "" -#: superset/errors.py:111 -#, fuzzy +#: superset/errors.py:117 msgid "The schema was deleted or renamed in the database." -msgstr "Проблема 1004 - Столбец был удалён или переименован в базе данных." +msgstr "Схема была удалена или переименована в базе данных." #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:92 msgid "The size of the square cell, in pixels" +msgstr "Размер квадратной ячейки (в пикселях)" + +#: superset/views/datasource/views.py:88 +msgid "" +"The submitted URL is not considered safe, only use URLs with the same " +"domain as Superset." msgstr "" -#: superset/errors.py:114 +#: superset/errors.py:120 msgid "The submitted payload has the incorrect format." -msgstr "" +msgstr "Загруженные данные имеют некорректный формат." -#: superset/errors.py:115 +#: superset/errors.py:121 msgid "The submitted payload has the incorrect schema." -msgstr "" +msgstr "Загруженные данные имеют некорректную схему." -#: superset/db_engine_specs/bigquery.py:158 +#: superset/db_engine_specs/bigquery.py:170 #, python-format msgid "" "The table \"%(table)s\" does not exist. A valid table must be used to run" " this query." msgstr "" +"Таблица \"%(table)s\" не существует. Для выполнения запроса должна " +"использоваться существующая таблица" -#: superset/db_engine_specs/presto.py:179 +#: superset/db_engine_specs/presto.py:611 #, python-format msgid "" "The table \"%(table_name)s\" does not exist. A valid table must be used " "to run this query." msgstr "" +"Таблица \"%(table_name)s\" не существует. Для выполнения запроса должна " +"использоваться существующая таблица" -#: superset/connectors/sqla/views.py:540 +#: superset/connectors/sqla/views.py:517 msgid "" "The table was created. As part of this two-phase configuration process, " "you should now click the edit button by the new table to configure it." msgstr "" -"Таблица была создана. Теперь нажмите на кнопку редактирования напротив " -"новой таблицы, чтобы настроить её." -#: superset/errors.py:100 -#, fuzzy +#: superset/errors.py:106 msgid "The table was deleted or renamed in the database." -msgstr "Проблема 1005 - Таблица была удалена или переименована в базе данных." +msgstr "Таблица была удалена или переименована в базе данных." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:167 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:266 -#: superset-frontend/src/explore/controls.jsx:297 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:237 +#: superset-frontend/src/explore/controls.jsx:281 msgid "" "The time column for the visualization. Note that you can define arbitrary" " expression that return a DATETIME column in the table. Also note that " "the filter below is applied against this column or expression" msgstr "" -"Столбец данных с датой или временем. Вы можете определить произвольное " +"Столбец данных формата дата/время. Вы можете определить произвольное " "выражение, которое будет возвращать столбец даты/времени в таблице. " "Фильтр ниже будет применён к этому столбцу или выражению" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:256 -#: superset-frontend/src/explore/controls.jsx:287 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:177 msgid "" "The time granularity for the visualization. Note that you can type and " "use simple natural language as in `10 seconds`, `1 day` or `56 weeks`" @@ -12633,21 +15314,31 @@ msgstr "" "естественный язык. Например, можно указать словосочетания - «10 seconds»," " «1 day» или «56 weeks»" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:297 -#: superset-frontend/src/explore/controls.jsx:326 +#: superset-frontend/src/explore/controls.jsx:271 +msgid "" +"The time granularity for the visualization. Note that you can type and " +"use simple natural language as in `10 seconds`,`1 day` or `56 weeks`" +msgstr "" +"Интервал времени, в границах которого строится график. Обратите внимание," +" что для определения диапазона времени, вы можете использовать " +"естественный язык. Например, можно указать словосочетания - «10 seconds»," +" «1 day» или «56 weeks»" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:200 +#: superset-frontend/src/explore/controls.jsx:310 msgid "" "The time granularity for the visualization. This applies a date " "transformation to alter your time column and defines a new time " "granularity. The options here are defined on a per database engine basis " "in the Superset source code." msgstr "" -"Гранулярность для визуализации. С помощью этого применяются " -"преобразования к столбцу с датой/временем и определяет новую " -"гранулярность (минута, день, год, и т.п.). Доступные опции определены в " -"исходном коде Superset для каждого типа движка БД." +"Детализация времени для визуализации. Применяется преобразование столбца " +"с датой/временем и определяется новая детализация (минута, день, год, и " +"т.п.). Доступные варианты заданы в исходном коде Superset для каждого " +"типа драйвера базы данных." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:314 -#: superset-frontend/src/explore/controls.jsx:343 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:234 +#: superset-frontend/src/explore/controls.jsx:327 msgid "" "The time range for the visualization. All relative times, e.g. \"Last " "month\", \"Last 7 days\", \"now\", etc. are evaluated on the server using" @@ -12657,85 +15348,110 @@ msgid "" " explicitly set the timezone per the ISO 8601 format if specifying either" " the start and/or end time." msgstr "" +"Временной интервал для визуализации. Относительно время, например, " +"\"Последний месяц\", \"Последние 7 дней\" и т.д. рассчитываются на " +"сервере, используя локальное время сервера. Обратите внимание, что вы " +"можете самостоятельно задать часовой пояс по формату ISO 8601 при " +"пользовательской настройке, задав время начала и/или конца." #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:65 msgid "" "The time unit for each block. Should be a smaller unit than " "domain_granularity. Should be larger or equal to Time Grain" msgstr "" +"Единица времени для каждого подблока. Должна быть меньшей единицей, чем " +"единица времени блока. Должно быть больше или равно единице времени" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:49 msgid "The time unit used for the grouping of blocks" -msgstr "" +msgstr "Единица времени для группировки блоков" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:170 -#: superset-frontend/src/explore/controls.jsx:202 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:124 +#: superset-frontend/src/explore/controls.jsx:201 msgid "The type of visualization to display" msgstr "Выберите необходимый тип визуализации" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:135 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:147 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:90 msgid "The unit of measure for the specified point radius" -msgstr "" +msgstr "Единица измерения для указанного радиуса маркера" -#: superset/views/core.py:183 +#: superset/views/core.py:196 msgid "The user seems to have been deleted" -msgstr "Пользователь, кажется, был удален" +msgstr "Пользователь, похоже, был удален" -#: superset/db_engine_specs/postgres.py:112 -#, fuzzy, python-format +#: superset/db_engine_specs/postgres.py:94 +#, python-format msgid "The username \"%(username)s\" does not exist." -msgstr "Показатель ‘%(metric)s’ не существует" +msgstr "Пользователь \"%(username)s\" не существует." -#: superset/errors.py:107 +#: superset/errors.py:113 msgid "The username provided when connecting to a database is not valid." -msgstr "" +msgstr "Имя пользователя, указанное при подключении к базе данных, недействительно" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:206 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:89 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:72 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:226 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:126 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:68 msgid "The way the ticks are laid out on the X-axis" -msgstr "" +msgstr "Способ расположения делений по оси X" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:214 +msgid "The width of the lines" +msgstr "Ширина линий" #: superset/charts/commands/exceptions.py:127 -#: superset/charts/commands/exceptions.py:147 +#: superset/charts/commands/exceptions.py:151 #: superset/dashboards/commands/exceptions.py:62 #: superset/dashboards/commands/exceptions.py:74 -#: superset/databases/commands/exceptions.py:117 +#: superset/databases/commands/exceptions.py:119 msgid "There are associated alerts or reports" -msgstr "Существуют привязанные оповещения или рассылки" +msgstr "Есть связанные оповещения или отчеты" -#: superset/charts/commands/bulk_delete.py:64 -#: superset/charts/commands/delete.py:68 -#: superset/dashboards/commands/bulk_delete.py:65 -#: superset/dashboards/commands/delete.py:66 -#: superset/databases/commands/delete.py:65 +#: superset/charts/commands/bulk_delete.py:62 +#: superset/charts/commands/delete.py:66 +#: superset/dashboards/commands/bulk_delete.py:63 +#: superset/dashboards/commands/delete.py:64 +#: superset/databases/commands/delete.py:63 #, python-format msgid "There are associated alerts or reports: %s," -msgstr "Существуют оповещения или рассылки: %s," +msgstr "Есть связанные оповещения или отчеты: %s" + +#: superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx:710 +msgid "There are no charts added to this dashboard" +msgstr "В этот дашборд еще не добавлен ни один график." + +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:238 +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:186 +msgid "There are no components added to this tab" +msgstr "В этой вкладке нет компонентов" + +#: superset-frontend/src/components/EmptyState/index.tsx:235 +msgid "There are no databases available" +msgstr "Нет доступных баз данных" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:507 +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:770 msgid "There are no filters in this dashboard." msgstr "В этом дашборде нет фильтров." #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:45 -#, fuzzy msgid "There are unsaved changes." msgstr "У вас есть несохраненные изменения." -#: superset/errors.py:95 -#, fuzzy +#: superset/errors.py:101 msgid "" "There is a syntax error in the SQL query. Perhaps there was a misspelling" " or a typo." -msgstr "Проблема 1003 - Ошибка в SQL-запросе. Возможно опечатка." +msgstr "" +"В SQL-запросе имеется синтаксическая ошибка. Возможно, это " +"орфографическая ошибка или опечатка." #: superset-frontend/src/dashboard/components/MissingChart.jsx:31 msgid "" "There is no chart definition associated with this component, could it " "have been deleted?" -msgstr "" +msgstr "С этим компонентом не связан ни один график, возможно, он был удален." -#: superset-frontend/src/dashboard/actions/dashboardLayout.js:180 +#: superset-frontend/src/dashboard/actions/dashboardLayout.js:182 msgid "" "There is not enough space for this component. Try decreasing its width, " "or increasing the destination width." @@ -12743,77 +15459,79 @@ msgstr "" "Недостаточно пространства для этого компонента. Попробуйте уменьшить " "ширину или увеличить целевую ширину." -#: superset-frontend/src/views/CRUD/hooks.ts:522 -#, fuzzy, python-format +#: superset-frontend/src/views/CRUD/hooks.ts:547 +#, python-format msgid "There was an error fetching the favorite status: %s" -msgstr "К сожалению, произошла ошибка при загрузке виджета." +msgstr "Произошла ошибка при получении статуса избранного: %s" -#: superset-frontend/src/views/CRUD/utils.tsx:181 +#: superset-frontend/src/views/CRUD/utils.tsx:205 msgid "There was an error fetching your recent activity:" -msgstr "К сожалению, произошла ошибка при загрузке виджета:" +msgstr "Произошла ошибка при получении вашей недавней активности:" -#: superset-frontend/src/components/DatabaseSelector/index.tsx:230 -#, fuzzy +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailPane.tsx:375 +msgid "There was an error loading the dataset metadata" +msgstr "Возникла ошибка при загрузке метаданных датасета" + +#: superset-frontend/src/components/DatabaseSelector/index.tsx:258 msgid "There was an error loading the schemas" -msgstr "Извините, произошла ошибка при загрузке графиков: " +msgstr "Возникла ошибка при загрузке схем" -#: superset-frontend/src/components/TableSelector/index.tsx:218 -#, fuzzy +#: superset-frontend/src/components/TableSelector/index.tsx:197 msgid "There was an error loading the tables" -msgstr "С вашим запросом произошла ошибка" +msgstr "Возникла ошибка при загрузке таблиц" -#: superset-frontend/src/views/CRUD/hooks.ts:543 -#, fuzzy, python-format +#: superset-frontend/src/views/CRUD/hooks.ts:568 +#, python-format msgid "There was an error saving the favorite status: %s" -msgstr "К сожалению, произошла ошибка при загрузке виджета." +msgstr "Произошла ошибка при сохранении статуса избранного: %s" -#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:61 +#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:71 msgid "There was an error with your request" -msgstr "С вашим запросом произошла ошибка" +msgstr "Произошла ошибка с вашим запросом" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:165 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:107 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:94 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:187 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:121 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:93 #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:97 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:148 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:550 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:235 -#: superset-frontend/src/views/CRUD/utils.tsx:289 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:164 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:679 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:236 +#: superset-frontend/src/views/CRUD/utils.tsx:311 #: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:175 #, python-format msgid "There was an issue deleting %s: %s" msgstr "Произошла ошибка при удалении %s: %s" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:180 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:202 #, python-format msgid "There was an issue deleting the selected %s: %s" msgstr "Произошла ошибка при удалении выбранных %s: %s" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:127 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:141 #, python-format msgid "There was an issue deleting the selected annotations: %s" msgstr "Произошла ошибка при удалении выбранных аннотаций: %s" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:209 +#: superset-frontend/src/pages/ChartList/index.tsx:254 #, python-format msgid "There was an issue deleting the selected charts: %s" msgstr "Произошла ошибка при удалении выбранных графиков: %s" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:226 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:238 msgid "There was an issue deleting the selected dashboards: " msgstr "Произошла ошибка при удалении выбранных дашбордов: " -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:568 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:697 #, python-format msgid "There was an issue deleting the selected datasets: %s" msgstr "Произошла ошибка при удалении выбранных датасетов: %s" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:111 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:110 #, python-format msgid "There was an issue deleting the selected layers: %s" msgstr "Произошла ошибка при удалении выбранных слоёв: %s" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:262 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:263 #, python-format msgid "There was an issue deleting the selected queries: %s" msgstr "Произошла ошибка при удалении выбранных запросов: %s" @@ -12823,69 +15541,75 @@ msgstr "Произошла ошибка при удалении выбранны msgid "There was an issue deleting the selected templates: %s" msgstr "Произошла ошибка при удалении выбранных шаблонов: %s" -#: superset-frontend/src/views/CRUD/utils.tsx:249 +#: superset-frontend/src/views/CRUD/utils.tsx:271 #, python-format msgid "There was an issue deleting: %s" msgstr "Произошла ошибка при удалении: %s" -#: superset-frontend/src/dashboard/actions/dashboardState.js:100 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:705 +msgid "There was an issue duplicating the dataset." +msgstr "Произошла ошибка при дублировании датасета." + +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:721 +#, python-format +msgid "There was an issue duplicating the selected datasets: %s" +msgstr "Произошла ошибка при дублировании выбранных датасетов: %s" + +#: superset-frontend/src/dashboard/actions/dashboardState.js:121 msgid "There was an issue favoriting this dashboard." msgstr "Произошла ошибка при добавлении этого дашборда в избранное." #: superset-frontend/src/reports/actions/reports.js:68 -#, fuzzy msgid "There was an issue fetching reports attached to this dashboard." -msgstr "К сожалению, произошла ошибка при загрузке виджета." +msgstr "Произошла ошибка с получением рассылок, связанных с этим дашбордом." -#: superset-frontend/src/dashboard/actions/dashboardState.js:79 +#: superset-frontend/src/dashboard/actions/dashboardState.js:100 msgid "There was an issue fetching the favorite status of this dashboard." -msgstr "К сожалению, произошла ошибка при загрузке виджета." +msgstr "Произошла ошибка с получением статуса избранного для этого дашборда." -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:195 -#, fuzzy, python-format +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:287 +#, python-format +msgid "There was an issue fetching your chart: %s" +msgstr "Произошла ошибка при получении вашего графика: %s" + +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:276 +#, python-format +msgid "There was an issue fetching your dashboards: %s" +msgstr "Произошла ошибка при получении вашего дашборда: %s" + +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:254 +#, python-format msgid "There was an issue fetching your recent activity: %s" -msgstr "К сожалению, произошла ошибка при загрузке виджета:" +msgstr "Произошла ошибка при получении вашей последней активности: %s" + +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:299 +#, python-format +msgid "There was an issue fetching your saved queries: %s" +msgstr "Произошла ошибка при получении ваших сохраненных запросов: %s" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:152 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:151 #, python-format msgid "There was an issue previewing the selected query %s" msgstr "Произошла ошибка при предпросмотре выбранного запроса %s" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:109 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:115 #, python-format msgid "There was an issue previewing the selected query. %s" -msgstr "Возникла ошибка при предпросмотре выбранных запросов: %s" - -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:222 -#, fuzzy, python-format -msgid "There was an issues fetching your chart: %s" -msgstr "Произошла ошибка при удалении: %s" +msgstr "Произошла ошибка при предпросмотре выбранного запроса: %s" -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:211 -#, fuzzy, python-format -msgid "There was an issues fetching your dashboards: %s" -msgstr "Произошла ошибка при удалении выбранных дашбордов: " - -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:233 -#, fuzzy, python-format -msgid "There was an issues fetching your saved queries: %s" -msgstr "Произошла ошибка при удалении выбранных запросов: %s" - -#: superset/viz.py:1955 +#: superset/viz.py:1989 msgid "" "There's a loop in your Sankey, please provide a tree. Here's a faulty " "link: {}" msgstr "" -"В полях [Источника] и [Назначения] есть одинаковый срез данных - {}. " -"Срезы не должны пересекаться!" -#: superset/connectors/sqla/views.py:341 +#: superset/connectors/sqla/views.py:336 msgid "These are the tables this filter will be applied to." -msgstr "Это таблицы, к которым будет применён фильтр." +msgstr "Это таблицы, к которым будет применен этот фильтр." -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:135 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:98 msgid "These filters apply to the values available in the dropdowns" -msgstr "" +msgstr "Эти фильтры применяются к значениям, доступным в выпадающих списках" #: superset/views/chart/mixin.py:64 msgid "" @@ -12897,7 +15621,7 @@ msgstr "" "Эти параметры генерируются автоматически при нажатии кнопки сохранения. " "Опытные пользователи могут изменить определенные объекты в формате JSON." -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:597 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:661 #: superset/views/dashboard/mixin.py:59 msgid "" "This JSON object is generated dynamically when clicking the save or " @@ -12907,22 +15631,22 @@ msgstr "" "Этот JSON-объект генерируется автоматически при сохранении или перезаписи" " дашборда. Он размещён здесь справочно и для опытных пользователей." -#: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:99 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:470 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:311 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:569 #, python-format msgid "This action will permanently delete %s." msgstr "Это действие навсегда удалит %s." -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:353 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:345 msgid "This action will permanently delete the layer." msgstr "Это действие навсегда удалит слой." -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:475 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:249 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:479 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:231 msgid "This action will permanently delete the saved query." msgstr "Это действие навсегда удалит сохранённый запрос." -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:313 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:315 msgid "This action will permanently delete the template." msgstr "Это действие навсегда удалит шаблон." @@ -12931,34 +15655,72 @@ msgid "" "This can be either an IP address (e.g. 127.0.0.1) or a domain name (e.g. " "mydatabase.com)." msgstr "" +"Это может быть как IP адрес (например, 127.0.0.1), так и доменное имя " +"(например, моябазаданных.рф)." -#: superset-frontend/src/dashboard/actions/dashboardLayout.js:258 +#: superset-frontend/src/dashboard/actions/dashboardLayout.js:260 msgid "This chart has been moved to a different filter scope." msgstr "Этот график был перемещён в другой набор фильтров." -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.ts:56 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:211 +msgid "This chart is managed externally, and can't be edited in Superset" +msgstr "" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.ts:61 msgid "This chart might be incompatible with the filter (datasets don't match)" +msgstr "Этот график может быть несовместим с этим фильтром (датасеты не совпадают)" + +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:321 +msgid "" +"This chart type is not supported when using an unsaved query as a chart " +"source. " msgstr "" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:127 +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx:50 msgid "" "This color scheme is being overriden by custom label colors.\n" -" Check the JSON metadata in the Advanced settings" +" Check the JSON metadata in the Advanced settings" msgstr "" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:480 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:496 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:121 +msgid "This column might be incompatible with current dataset" +msgstr "Этот график может быть несовместим с этим датасетом" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:528 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:544 msgid "This column must contain date/time information." +msgstr "В этом столбец должны быть данные формата дата/время." + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:583 +msgid "" +"This controls whether the \"time_range\" field from the current\n" +" view should be passed down to the chart containing the " +"annotation data." msgstr "" +"Должен ли временной интервал из этого представления переписать временной " +"интервал графика, содержащего данные аннотации." -#: superset-frontend/src/dashboard/components/Header/index.jsx:303 -#, fuzzy, python-format +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:601 +msgid "" +"This controls whether the time grain field from the current\n" +" view should be passed down to the chart containing the " +"annotation data." +msgstr "" +"Должен ли единица времени из этой таблицы переписать единицу времени " +"графика." + +#: superset-frontend/src/dashboard/components/Header/index.jsx:320 +#, python-format msgid "" "This dashboard is currently auto refreshing; the next auto refresh will " "be in %s." msgstr "" -"Для этого дашборда включено обновление; следующее обновление будет через " -"%s." +"В настоящий момент дашборд обновляется; следующее обновление будет через " +"%s" + +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:560 +msgid "This dashboard is managed externally, and can't be edited in Superset" +msgstr "" #: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:38 msgid "" @@ -12976,70 +15738,93 @@ msgid "" "dashboards. Click here to publish this dashboard." msgstr "" "Этот дашборд не опубликован, он не будет отображён в списке дашбордов. " -"Нажмите здесь, чтобы опубликовать этот дашборд." +"Нажмите, чтобы опубликовать этот дашборд." -#: superset-frontend/src/dashboard/actions/dashboardState.js:125 -#, fuzzy +#: superset-frontend/src/dashboard/actions/dashboardState.js:146 msgid "This dashboard is now hidden" -msgstr "Изменение этого дашборда запрещено" +msgstr "Дашборд теперь скрыт" -#: superset-frontend/src/dashboard/actions/dashboardState.js:124 -#, fuzzy +#: superset-frontend/src/dashboard/actions/dashboardState.js:145 msgid "This dashboard is now published" -msgstr "Этот дашборд теперь ${nowPublished}" +msgstr "Дашборд теперь опубликован" #: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:43 msgid "This dashboard is published. Click to make it a draft." msgstr "Дашборд опубликован. Нажмите, чтобы сделать черновиком." -#: superset/views/core.py:1273 +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:168 +msgid "" +"This dashboard is ready to embed. In your application, pass the following" +" id to the SDK:" +msgstr "" + +#: superset/views/core.py:1311 msgid "" "This dashboard was changed recently. Please reload dashboard to get " "latest version." msgstr "" -"Этот дашборд был недавно изменён. Пожалуйста, перезагрузите дашборд, " -"чтобы получить последнюю версию." +"Этот дашборд был недавно изменен. Пожалуйста, обновите дашборд, чтобы " +"увидеть изменения." -#: superset-frontend/src/dashboard/actions/dashboardState.js:231 +#: superset-frontend/src/dashboard/actions/dashboardState.js:311 +#: superset-frontend/src/dashboard/actions/dashboardState.js:350 msgid "This dashboard was saved successfully." -msgstr "Дашборд успешно сохранен." +msgstr "Дашборд успешно сохранен" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1057 +msgid "This database is managed externally, and can't be edited in Superset" +msgstr "Эта база данных управляется извне и не может быть изменена в Суперсете" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx:68 +msgid "" +"This database table does not contain any data. Please select a different " +"table." +msgstr "" + +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:236 +msgid "This dataset is managed externally, and can't be edited in Superset" +msgstr "Этот датасет управляется извне и не может быть изменена в Суперсете" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:77 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:401 -#: superset-frontend/src/explore/controls.jsx:416 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:132 +#: superset-frontend/src/explore/controls.jsx:396 msgid "This defines the element to be plotted on the chart" msgstr "Элемент, который будет отражен на графике" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:82 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:97 msgid "This defines the level of the hierarchy" -msgstr "Элемент, который будет отражен на графике" - -#: superset/views/alerts.py:232 superset/views/schedules.py:253 -#: superset/views/schedules.py:334 -msgid "" -"This feature is deprecated and will be removed on 2.0. Take a look at the" -" replacement feature <a " -"href='https://superset.apache.org/docs/installation/alerts-" -"reports'>Alerts & Reports documentation</a>" -msgstr "" +msgstr "Определяет уровень иерархии" -#: superset/connectors/sqla/views.py:447 +#: superset/connectors/sqla/views.py:437 msgid "" "This fields acts a Superset view, meaning that Superset will run a query " "against this string as a subquery." -msgstr "Это поле будет выполнять запрос в качестве подзапроса." +msgstr "" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:105 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:109 msgid "This filter doesn't exist in dashboard. It will not be applied." +msgstr "Этот фильтр не существует в дашборде. Он не будет применен." + +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:503 +msgid "" +"This filter is the last temporal filter. If you proceed,\n" +" this chart won't be affected by time range filters in " +"dashboards." msgstr "" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:165 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndAdhocFilterOption.tsx:72 +msgid "This filter might be incompatible with current dataset" +msgstr "Этот фильтр может быть несовместим с этим датасетом" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:164 #, python-format msgid "This filter set is identical to: \"%s\"" -msgstr "" +msgstr "Этот набор фильтров идентичен \"%s\"" -#: superset/connectors/sqla/views.py:358 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:75 +msgid "This functionality is disabled in your environment for security reasons." +msgstr "Эта функция отключена в вашей среде по соображениям безопасности." + +#: superset/connectors/sqla/views.py:353 msgid "" "This is the condition that will be added to the WHERE clause. For " "example, to only return rows for a particular client, you might define a " @@ -13047,6 +15832,11 @@ msgid "" " a user belongs to a RLS filter role, a base filter can be created with " "the clause `1 = 0` (always false)." msgstr "" +"Это условие, которое будет добавлено к оператору WHERE. Например, чтобы " +"возвращать строки только для определенного клиента, вы можете определить " +"обычный фильтр с условием `client_id = 9`. Чтобы не отображать строки, " +"если пользователь не принадлежит к роли фильтра RLS, можно создать " +"базовый фильтр с предложением `1 = 0` (всегда false)." #: superset/views/dashboard/mixin.py:47 msgid "" @@ -13054,291 +15844,324 @@ msgid "" "dashboard. It is dynamically generated when adjusting the widgets size " "and positions by using drag & drop in the dashboard view" msgstr "" -"Этот объект JSON описывает расположение виджетов в дашборде. Он " -"динамически генерируется при настройке размера и позиции виджетов в " -"дашборде с помощью drag & drop" +"Этот JSON объект описывает расположение графиков в дашборде. Он " +"генерируется динамически при изменении и перемещении графиков в дашборде." -#: superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx:80 +#: superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx:84 msgid "This markdown component has an error." msgstr "Этот компонент содержит ошибки." -#: superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx:167 +#: superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx:202 msgid "This markdown component has an error. Please revert your recent changes." msgstr "Этот компонент содержит ошибки. Пожалуйста, отмените последние изменения." #: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:47 #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:62 msgid "This may be triggered by:" -msgstr "Триггеры:" +msgstr "Возможные причины:" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:109 -#, python-format -msgid "This query took %s seconds to run, " -msgstr "Выполнение этого запроса заняло %s секунд, " +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:258 +msgid "This metric might be incompatible with current dataset" +msgstr "Эта мера может быть несовместима с этим датасетом" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:466 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:514 +#, fuzzy msgid "" "This section allows you to configure how to use the slice\n" -" to generate annotations." +" to generate annotations." msgstr "" +"Этот раздел позволяет вам настроить использования графика для создания " +"аннотаций." #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:27 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:244 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:127 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:377 -#: superset-frontend/src/explore/controlPanels/sections.tsx:146 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:237 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:119 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:387 +#: superset-frontend/src/explore/controlPanels/sections.tsx:119 msgid "" "This section contains options that allow for advanced analytical post " "processing of query results" msgstr "" "В этом разделе содержатся параметры, которые позволяют производить " -"аналитическую пост-обработку результатов запроса" +"аналитическую постобработку результатов запроса" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:84 -msgid "This value should be greater than the left target value" +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:583 +msgid "This section contains validation errors" +msgstr "В этом разделе содержатся ошибки валидации" + +#: superset-frontend/src/embedded/index.tsx:109 +msgid "" +"This session has encountered an interruption, and some controls may not " +"work as intended. If you are the developer of this app, please check that" +" the guest token is being generated correctly." msgstr "" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:79 -msgid "This value should be smaller than the right target value" +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx:234 +msgid "This table already has a dataset" +msgstr "" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx:224 +msgid "" +"This table already has a dataset associated with it. You can only " +"associate one dataset with a table.\n" msgstr "" -#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:67 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:85 +msgid "This value should be greater than the left target value" +msgstr "Это значение должно быть больше чем левое целевое значение" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:80 +msgid "This value should be smaller than the right target value" +msgstr "Это значение должно быть больше чем правое целевое значение" + +#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:66 msgid "This visualization type is not supported." msgstr "Этот тип визуализации не поддерживается." #: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:61 msgid "This was triggered by:" -msgstr "Причина срабатывания:" +msgid_plural "This may be triggered by:" +msgstr[0] "Причина срабатывания:" +msgstr[1] "Причины срабатывания" +msgstr[2] "Причины срабатывания" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:74 -msgid "Threshold alpha level for determining significance" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:99 +msgid "This will remove your current embed configuration." msgstr "" +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:66 +msgid "Threshold alpha level for determining significance" +msgstr "Пороговый альфа-уровень для определения значимости" + +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:406 +msgid "Threshold value should be double precision number" +msgstr "Пороговое значение должно быть числом двойной точности" + +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:349 +msgid "Thumbnails" +msgstr "Миниатюры" + #: superset-frontend/src/components/CronPicker/CronPicker.tsx:60 msgid "Thursday" msgstr "Четверг" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:32 +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:38 #: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:26 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:36 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:39 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:52 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:38 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:37 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:33 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:39 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:39 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:35 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:38 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:81 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:81 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:75 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:75 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:75 -#: superset-frontend/src/explore/controlPanels/sections.tsx:25 -#: superset-frontend/src/explore/controlPanels/sections.tsx:84 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:182 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:78 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:73 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:70 +#: superset-frontend/src/explore/controlPanels/sections.tsx:65 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:200 msgid "Time" msgstr "Время" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:25 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:32 msgid "Time Column" -msgstr "Столбец с временем" +msgstr "Столбец даты/времени" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:303 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:186 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:436 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:296 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:178 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:446 msgid "Time Comparison" -msgstr "Столбец с датой" +msgstr "Сравнение по времени" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:141 -#, fuzzy msgid "Time Format" -msgstr "Формат Datetime" +msgstr "Формат даты/времени" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:26 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:33 msgid "Time Grain" -msgstr "Гранулярность времени" +msgstr "Единица времени" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:28 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:34 msgid "Time Granularity" msgstr "Гранулярность времени" -#: superset/connectors/druid/views.py:350 -msgid "Time Offset" -msgstr "Смещение времени" +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:256 +msgid "Time Lag" +msgstr "Временной лаг" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:24 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:31 +#: superset-frontend/src/explore/components/controls/FilterControl/utils/useDatePickerInAdhocFilter.tsx:43 msgid "Time Range" -msgstr "Период времени" +msgstr "Временной интервал" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:86 -#, fuzzy +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:267 +msgid "Time Ratio" +msgstr "Соотношение времени" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:79 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/AnnotationTypes.js:47 msgid "Time Series" -msgstr "Столбцы Временных Рядов" +msgstr "Временной ряд" -#: superset/viz.py:1638 +#: superset/viz.py:1667 msgid "Time Series - Bar Chart" -msgstr "Time Series - Bar Chart" +msgstr "Столбчатая диаграмма (временные ряды)" -#: superset/viz.py:1564 +#: superset/viz.py:1593 msgid "Time Series - Dual Axis Line Chart" -msgstr "Time Series - Dual Axis Line Chart" +msgstr "Диаграмма с двумя осями (временные ряды)" -#: superset/viz.py:1276 +#: superset/viz.py:1305 msgid "Time Series - Line Chart" -msgstr "Time Series - Line Chart" +msgstr "Линейная диаграмма (временные ряды)" -#: superset/viz.py:1486 +#: superset/viz.py:1515 +#, fuzzy msgid "Time Series - Multiple Line Charts" -msgstr "Time Series - Multiple Line Charts" +msgstr "Multiple Line Charts (временные ряды)" -#: superset/viz.py:3000 +#: superset/viz.py:3034 msgid "Time Series - Nightingale Rose Chart" -msgstr "Time Series - Nightingale Rose Chart" +msgstr "Диаграмма Найтингейл (временные ряды)" -#: superset/viz.py:2928 +#: superset/viz.py:2962 msgid "Time Series - Paired t-test" -msgstr "Time Series - Paired t-test" +msgstr "Парный t-test (временные ряды)" -#: superset/viz.py:1693 +#: superset/viz.py:1722 msgid "Time Series - Percent Change" -msgstr "Time Series - Percent Change" +msgstr "Процентное изменение (временные ряды)" -#: superset/viz.py:1647 +#: superset/viz.py:1676 +#, fuzzy msgid "Time Series - Period Pivot" -msgstr "Time Series - Period Pivot" +msgstr "Period Pivot (временные ряды)" -#: superset/viz.py:1701 +#: superset/viz.py:1730 msgid "Time Series - Stacked" -msgstr "Time Series - Stacked" +msgstr "Диаграмма с накоплением (временные ряды)" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:67 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:60 msgid "Time Series Options" -msgstr "Столбцы Временных Рядов" +msgstr "Настройки временных рядов" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:311 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:194 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:444 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:304 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:186 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:454 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:623 msgid "Time Shift" msgstr "Временной сдвиг" -#: superset/viz.py:822 +#: superset/viz.py:846 +#, fuzzy msgid "Time Table View" -msgstr "" +msgstr "Убрать предпросмотр таблицы" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:297 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1132 -#: superset-frontend/src/explore/constants.ts:114 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:318 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:974 +#: superset-frontend/src/explore/constants.ts:133 #: superset-frontend/src/filters/components/TimeColumn/index.ts:28 msgid "Time column" -msgstr "Столбец с временем" +msgstr "Столбец даты/времени" -#: superset/connectors/sqla/models.py:1173 +#: superset/connectors/sqla/models.py:1374 superset/models/helpers.py:1560 #, python-format msgid "Time column \"%(col)s\" does not exist in dataset" -msgstr "" +msgstr "Столбец формата дата/время \"%(col)s\" не существует в датасете" #: superset-frontend/src/filters/components/TimeColumn/index.ts:29 msgid "Time column filter plugin" msgstr "" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:88 -#: superset-frontend/src/explore/controlPanels/sections.tsx:201 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:102 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:71 +#: superset-frontend/src/explore/controlPanels/sections.tsx:174 msgid "Time comparison" msgstr "Столбец с датой" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:624 +msgid "" +"Time delta in natural language\n" +" (example: 24 hours, 7 days, 56 weeks, 365 days)" +msgstr "" +"Временной сдвиг на естественном языке (например: 24 hours, 7 days, 56 " +"weeks, 365 days)" + #: superset/charts/commands/exceptions.py:66 #, python-format msgid "" "Time delta is ambiguous. Please specify [%(human_readable)s ago] or " "[%(human_readable)s later]." msgstr "" +"Неоднозначный временной сдвиг. Пожалуйста, укажите [%(human_readable)s " +"до] или [%(human_readable)s после]." -#: superset/connectors/druid/views.py:317 -msgid "" -"Time expression to use as a predicate when retrieving distinct values to " -"populate the filter component. Only applies when `Enable Filter Select` " -"is on. If you enter `7 days ago`, the distinct list of values in the " -"filter will be populated based on the distinct value over the past week" -msgstr "" -"Выражение времени для использования в качестве предиката при получении " -"различных значений для заполнения компонента фильтра. Применяется только " -"в том случае, если включен параметр «включить выбор фильтра». Если Вы " -"введете «7 дней назад», то список различных значений в фильтре будет " -"заполнен на основе определенного значения за последнюю неделю" - -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:296 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:317 #: superset-frontend/src/filters/components/Time/index.ts:27 -#, fuzzy msgid "Time filter" msgstr "Временной фильтр" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:450 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:326 msgid "Time format" -msgstr "Формат Datetime" +msgstr "Формат даты/времени" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:298 -#: superset-frontend/src/explore/constants.ts:115 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:319 +#: superset-frontend/src/explore/constants.ts:134 #: superset-frontend/src/filters/components/TimeGrain/index.ts:28 msgid "Time grain" -msgstr "Гранулярность времени" +msgstr "Единица времени" #: superset-frontend/src/filters/components/TimeGrain/index.ts:29 #, fuzzy msgid "Time grain filter plugin" msgstr "Период времени" -#: superset/utils/pandas_postprocessing.py:815 +#: superset/utils/pandas_postprocessing/prophet.py:114 msgid "Time grain missing" -msgstr "Период времени" +msgstr "Единица времени отсутствует" -#: superset-frontend/src/explore/constants.ts:117 +#: superset-frontend/src/explore/constants.ts:135 msgid "Time granularity" msgstr "Гранулярность времени" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1267 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1282 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:413 msgid "Time in seconds" msgstr "Время в секундах" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:296 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1105 -#: superset-frontend/src/explore/constants.ts:113 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:382 -msgid "Time range" -msgstr "Период времени" +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:250 +msgid "Time lag" +msgstr "Временной лаг" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:98 -#: superset-frontend/src/explore/controlPanels/sections.tsx:69 -msgid "Time range endpoints" -msgstr "Период времени" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:317 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:946 +#: superset-frontend/src/explore/constants.ts:132 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:403 +msgid "Time range" +msgstr "Временной интервал" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:100 -#: superset-frontend/src/explore/controlPanels/sections.tsx:71 -msgid "Time range endpoints (SIP-15)" -msgstr "" +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:261 +msgid "Time ratio" +msgstr "Соотношение времени" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:28 -#: superset-frontend/src/explore/controlPanels/sections.tsx:27 -#: superset-frontend/src/explore/controlPanels/sections.tsx:85 +#: superset-frontend/src/explore/controlPanels/sections.tsx:66 msgid "Time related form attributes" -msgstr "Параметры, связанные с временем" +msgstr "Параметры, связанные со временем" + +#: superset-frontend/src/modules/AnnotationTypes.js:46 +msgid "Time series" +msgstr "Временной ряд" #: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:48 -#: superset-frontend/src/explore/controlPanels/TimeTable.js:38 +#: superset-frontend/src/visualizations/TimeTable/controlPanel.js:38 msgid "Time series columns" -msgstr "Столбцы Временных Рядов" +msgstr "Столбцы временных рядов" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:96 -#: superset-frontend/src/explore/controlPanels/sections.tsx:209 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:110 +#: superset-frontend/src/explore/controlPanels/sections.tsx:182 msgid "Time shift" msgstr "Временной сдвиг" @@ -13348,84 +16171,86 @@ msgid "" "Time string is ambiguous. Please specify [%(human_readable)s ago] or " "[%(human_readable)s later]." msgstr "" +"Временная строка неоднозначна. Пожалуйста, укажите [%(human_readable)s " +"до] или [%(human_readable)s после]." -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:75 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:72 msgid "Time-series Area Chart" -msgstr "Time Series - Bar Chart" +msgstr "Диаграмма с областями (временные ряды)" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:65 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:60 msgid "" "Time-series Area chart are similar to line chart in that they represent " "variables with the same scale, but area charts stack the metrics on top " "of each other. An area chart in Superset can be stream, stack, or expand." msgstr "" +"Диаграмма с наполнением похожа на линейную диаграмму тем, что они " +"представляют переменные с одинаковым масштабом, но диаграммы с " +"наполнением накладывают показатели друг на друга." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:35 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:78 msgid "Time-series Bar Chart" -msgstr "Time Series - Bar Chart" +msgstr "Столбчатая диаграмма" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:75 -#, fuzzy -msgid "Time-series Bar Chart v2" -msgstr "Time Series - Bar Chart" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:35 +msgid "Time-series Bar Chart (legacy)" +msgstr "Столбчатая диаграмма (устарело)" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:61 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:64 msgid "" "Time-series Bar Charts are used to show the changes in a metric over time" " as a series of bars." msgstr "" +"Столбчатые диаграммы временных рядов используются для отображения " +"изменений меры с течением времени в виде серии столбцов." -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:69 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:64 msgid "Time-series Chart" -msgstr "Таблица временных рядов" +msgstr "Диаграмма (временные ряды)" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:70 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:77 msgid "Time-series Line Chart" -msgstr "Time Series - Line Chart" +msgstr "Линейная диаграмма (временные ряды)" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:30 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:32 msgid "Time-series Percent Change" -msgstr "Time Series - Percent Change" +msgstr "Процентное изменение (временные ряды)" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:28 #, fuzzy msgid "Time-series Period Pivot" msgstr "Time Series - Period Pivot" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:69 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:76 msgid "Time-series Scatter Plot" -msgstr "Таблица временных рядов" +msgstr "Точечная Диаграмма" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:59 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:64 msgid "" "Time-series Scatter Plot has time on the horizontal axis in linear units," " and the points are connected in order. It shows a statistical " "relationship between two variables." msgstr "" +"На горизонтальной оси Точечной диаграммы откладывается время в линейных " +"единицах, а точки соединяются по порядку. Он показывает статистическую " +"зависимость между двумя переменными." -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:69 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:76 msgid "Time-series Smooth Line" -msgstr "Таблица временных рядов" +msgstr "Плавная линейная диаграмма (временные ряды)" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:59 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:64 msgid "" -"Time-series Smooth-line is a variation of line chart. Without angles and " -"hard edges, Smooth-line looks more smarter and more professional." +"Time-series Smooth-line is a variation of the line chart. Without angles " +"and hard edges, Smooth-line sometimes looks smarter and more " +"professional." msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:60 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:67 msgid "Time-series Stepped Line" -msgstr "Таблица временных рядов" +msgstr "Диаграмма шагов (временные ряды)" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:50 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:55 msgid "" "Time-series Stepped-line graph (also called step chart) is a variation of" " line chart but with the line forming a series of steps between data " @@ -13433,259 +16258,319 @@ msgid "" " occur at irregular intervals." msgstr "" -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:25 +#: superset-frontend/src/visualizations/TimeTable/index.ts:27 msgid "Time-series Table" msgstr "Таблица временных рядов" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:60 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:65 msgid "" "Time-series line chart is used to visualize repeated measurements taken " "over regular time intervals. Line chart is a type of chart which displays" " information as a series of data points connected by straight line " "segments. It is a basic type of chart common in many fields." msgstr "" +"Линейная диаграмма временных рядов используется для визуализации " +"повторяющихся измерений, происходящих через регулярные промежутки " +"времени. Линейная диаграмма - это тип диаграммы, который отображает " +"информацию в виде ряда точек данных, соединенных прямыми отрезками. Это " +"базовый тип диаграммы, распространенный во многих областях." #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:98 msgid "Timeout error" -msgstr "Тайм-аут" - -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:60 -#, fuzzy -msgid "Timestamp Format" -msgstr "Формат Даты / Времени" +msgstr "Ошибка таймаута" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:73 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:372 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:383 msgid "Timestamp format" -msgstr "Формат Даты / Времени" +msgstr "Формат даты и времени" -#: superset-frontend/src/components/ReportModal/index.tsx:378 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1223 +#: superset-frontend/src/components/ReportModal/index.tsx:320 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:409 msgid "Timezone" -msgstr "" +msgstr "Часовой пояс" -#: superset/connectors/druid/views.py:312 superset/connectors/sqla/views.py:438 +#: superset/connectors/sqla/views.py:428 msgid "Timezone offset (in hours) for this datasource" msgstr "Смещение часового пояса (в часах) для этого источника данных" -#: superset-frontend/src/components/TimezoneSelector/index.tsx:120 -#, fuzzy +#: superset-frontend/src/components/TimezoneSelector/index.tsx:129 msgid "Timezone selector" -msgstr "Выполнить выбранный запрос" +msgstr "Выбор часового пояса" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:35 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:69 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:35 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:69 msgid "Tiny" -msgstr "в" - -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:502 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:42 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:278 -#: superset/views/dashboard/mixin.py:79 superset/views/dashboard/views.py:156 +msgstr "Крошечный" + +#: superset-frontend/src/components/DynamicEditableTitle/index.tsx:186 +#: superset-frontend/src/components/DynamicEditableTitle/index.tsx:207 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:586 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:41 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:288 +#: superset/views/dashboard/mixin.py:79 superset/views/dashboard/views.py:192 msgid "Title" msgstr "Заголовок" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:509 -#, fuzzy +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:557 msgid "Title Column" -msgstr "Столбец с временем" +msgstr "Столбец с названием" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:45 -#, fuzzy +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:44 msgid "Title is required" -msgstr "Поле обязательно" +msgstr "Название обязательно" -#: superset/dashboards/filters.py:33 +#: superset/dashboards/filters.py:38 msgid "Title or Slug" -msgstr "Заголовок" +msgstr "Название или читаемый URL" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:287 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:348 msgid "To filter on a metric, use Custom SQL tab." -msgstr "Фильтр на показателе, используйте вкладку Через SQL." +msgstr "Для фильтрации по мере используйте вкладку Свой SQL." #: superset/views/dashboard/mixin.py:58 msgid "To get a readable URL for your dashboard" -msgstr "Получить читаемый URL-адрес для дашборда" +msgstr "Для получения читаемого URL-адреса дашборда" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:280 -msgid "Toggle chart description" -msgstr "Изменить описание графика" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:285 +msgid "Too many columns to filter" +msgstr "Слишком много столбцов для фильтрации" -#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:25 -#, fuzzy +#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:27 msgid "Tools" -msgstr "Роли" +msgstr "Инструменты" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:184 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:210 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:205 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:211 msgid "Tooltip" -msgstr "" +msgstr "Всплывающая подсказка" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:172 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:198 msgid "Tooltip sort by metric" -msgstr "Список показателей" +msgstr "Сортировка данных подсказки по мере" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:162 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:188 msgid "Tooltip time format" -msgstr "Формат Datetime" +msgstr "Формат времени всплывающей подсказки" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:289 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:29 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:83 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:354 msgid "Top" -msgstr "Стоп" +msgstr "Сверху" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:139 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:183 +msgid "Top left" +msgstr "Сверху слева" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:184 +msgid "Top right" +msgstr "Сверху справа" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:140 msgid "Top to Bottom" +msgstr "Сверху вниз" + +#: superset/charts/post_processing.py:72 +#, python-format +msgid "Total (%(aggfunc)s)" msgstr "" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:439 -msgid "Totals" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx:491 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx:556 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx:772 +#, python-format +msgid "Total (%(aggregatorName)s)" msgstr "" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:820 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts:326 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts:359 +#, python-format +msgid "Total: %s" +msgstr "Итого: %s" + +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:550 +msgid "Totals" +msgstr "Общая сумма" + +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:408 msgid "Track job" msgstr "Отслеживать работу" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:40 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:46 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:77 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:83 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:82 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:77 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:67 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:76 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:48 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:74 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:71 msgid "Transformable" -msgstr "" +msgstr "Трансформируемый" #: superset-frontend/src/dashboard/util/backgroundStyleOptions.ts:25 msgid "Transparent" -msgstr "" +msgstr "Прозрачный" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:110 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:99 msgid "Transpose Pivot" -msgstr "" +msgstr "Транспонировать таблицу" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:173 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:238 msgid "Transpose pivot" -msgstr "" +msgstr "Транспонировать таблицу" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:39 -#, fuzzy msgid "Tree Chart" -msgstr "Поделиться графиком" +msgstr "Древовидная диаграмма" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:117 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:118 msgid "Tree layout" -msgstr "" +msgstr "Оформление дерева" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:134 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:135 msgid "Tree orientation" -msgstr "Удалить аннотацию" +msgstr "Ориентация дерева" -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:40 -#: superset/viz.py:1003 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:56 +#: superset/viz.py:1032 msgid "Treemap" -msgstr "Treemap" +msgstr "Плоское дерево" -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:56 -#, fuzzy -msgid "Treemap v2" -msgstr "Treemap" +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:40 +msgid "Treemap (legacy)" +msgstr "Плоское дерево (устарело)" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:37 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:37 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:43 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:39 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:40 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:53 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:39 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:38 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:40 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:59 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:36 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:40 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:40 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:42 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:45 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:61 +#: superset-frontend/src/visualizations/TimeTable/index.ts:39 msgid "Trend" -msgstr "Изменения" +msgstr "Тенденция" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:226 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:227 msgid "Triangle" -msgstr "" +msgstr "Треугольник" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1168 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:403 msgid "Trigger Alert If..." -msgstr "Сделать оповещение, если…" - -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:340 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:255 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:218 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:198 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:215 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:271 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:274 +msgstr "Оповестить, если..." + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:227 +msgid "Truncate Axis" +msgstr "Настройка интервала оси" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:136 +#, fuzzy +msgid "Truncate Cells" +msgstr "Настройка интервала оси" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:350 +msgid "Truncate Metric" +msgstr "Убрать имя меры" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:356 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:244 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:231 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:175 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:175 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:228 msgid "Truncate Y Axis" +msgstr "Урезать интервал оси Y" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:359 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:247 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:234 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:178 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:178 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:231 +msgid "Truncate Y Axis. Can be overridden by specifying a min or max bound." msgstr "" +"Уменьшить интервал по умолчанию для оси Y. Необходимо задать минимальную " +"и максимальную границы. Обратите внимание, что некоторые линии могут " +"пропасть из области видимости." -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:343 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:258 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:201 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:218 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:274 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:277 -msgid "Truncate Y Axis. Can be overridden by specifying a min or max bound." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:137 +msgid "Truncate long cells to the \"min width\" set above" msgstr "" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:58 msgid "Truncates the specified date to the accuracy specified by the date unit." -msgstr "" +msgstr "Усекает указанную дату с точностью, указанной в единице измерения даты." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:222 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:174 msgid "Try applying different filters or ensuring your datasource has data" msgstr "" +"Попробуйте использовать другие фильтры или убедитесь, что в вашем " +"источнике данных есть данные" + +#: superset-frontend/src/components/ListView/ListView.tsx:409 +msgid "Try different criteria to display results." +msgstr "Попробуйте использовать другии критерии фильтрации" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/LeftPanel/index.tsx:248 +msgid "Try selecting a different schema" +msgstr "" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:58 msgid "Tuesday" msgstr "Вторник" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:215 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:94 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:47 +#, fuzzy +msgid "Tukey" +msgstr "запрос" + +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:63 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:216 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:215 #: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:219 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:272 #: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:276 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:288 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:466 -#: superset/connectors/druid/views.py:92 superset/connectors/druid/views.py:190 -#: superset/connectors/sqla/views.py:152 superset/connectors/sqla/views.py:258 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:347 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:556 +#: superset/connectors/sqla/views.py:165 superset/connectors/sqla/views.py:254 msgid "Type" msgstr "Тип" #: superset-frontend/src/components/DeleteModal/index.tsx:92 -#: superset-frontend/src/components/ImportModal/index.tsx:253 +#: superset-frontend/src/components/ImportModal/index.tsx:252 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1232 #, python-format msgid "Type \"%s\" to confirm" -msgstr "Введите “%s” для подтверждения" +msgstr "Введите \"%s\" для подтверждения" -#: superset-frontend/src/components/ListView/Filters/Search.tsx:71 -#, fuzzy +#: superset-frontend/src/components/ListView/Filters/Search.tsx:75 msgid "Type a value" -msgstr "Введите значение здесь" +msgstr "Введите значение" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:319 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:379 msgid "Type a value here" msgstr "Введите значение здесь" -#: superset/reports/commands/exceptions.py:71 +#: superset/reports/commands/exceptions.py:75 msgid "Type is required" -msgstr "Тип обязателен" +msgstr "Поле обязательно" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:73 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:72 msgid "Type of Google Sheets allowed" -msgstr "" +msgstr "Допустимый тип Google Таблиц" -#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:379 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:216 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:273 +msgid "Type of comparison, value difference or percentage" +msgstr "Тип сравнения, разница значений или доля" + +#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:404 #, python-format msgid "Type or Select [%s]" -msgstr "Выбрать [%s]" +msgstr "Введите или выберите [%s]" #: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:51 #: superset-frontend/src/filters/components/Range/controlPanel.ts:47 @@ -13693,226 +16578,267 @@ msgstr "Выбрать [%s]" #: superset-frontend/src/filters/components/Time/controlPanel.ts:45 #: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:25 #: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:25 -#, fuzzy msgid "UI Configuration" -msgstr "Фильтруемые срезы" +msgstr "Конфигурация UI" -#: superset-frontend/src/explore/controlPanels/TimeTable.js:51 +#: superset-frontend/src/visualizations/TimeTable/controlPanel.js:51 msgid "URL" msgstr "Ссылка (URL)" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:76 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:88 msgid "URL Parameters" -msgstr "Параметры" +msgstr "Параметры URL" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:125 -#, fuzzy -msgid "URL could not be identified" -msgstr "График не может быть удалён." - -#: superset-frontend/src/explore/controlPanels/sections.tsx:60 +#: superset-frontend/src/explore/controlPanels/sections.tsx:50 msgid "URL parameters" -msgstr "Параметры" +msgstr "Параметры URL" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:514 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:595 msgid "URL slug" msgstr "Читаемый URL" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:531 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:592 msgid "Unable to add a new tab to the backend. Please contact your administrator." msgstr "" +"Не удается добавить новую вкладку на сервер. Пожалуйста, свяжитесь с " +"администратором." -#: superset/db_engine_specs/presto.py:218 +#: superset/db_engine_specs/presto.py:650 #, python-format msgid "Unable to connect to catalog named \"%(catalog_name)s\"." msgstr "" -#: superset/db_engine_specs/mysql.py:139 -#: superset/db_engine_specs/postgres.py:145 +#: superset/db_engine_specs/mysql.py:163 +#: superset/db_engine_specs/postgres.py:127 #, python-format msgid "Unable to connect to database \"%(database)s\"." +msgstr "Невозможно подключиться к базе данных \"%(database)s\"." + +#: superset/db_engine_specs/bigquery.py:158 +msgid "" +"Unable to connect. Verify that the following roles are set on the service" +" account: \"BigQuery Data Viewer\", \"BigQuery Metadata Viewer\", " +"\"BigQuery Job User\" and the following permissions are set " +"\"bigquery.readsessions.create\", \"bigquery.readsessions.getData\"" msgstr "" -#: superset/utils/date_parser.py:390 -#, fuzzy, python-format +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:218 +msgid "Unable to create chart without a query id." +msgstr "" + +#: superset/utils/date_parser.py:393 +#, python-format msgid "Unable to find such a holiday: [%(holiday)s]" -msgstr "Невозможно найти такой выходной день: [{}]" +msgstr "Не удалось найти такой праздник: [%(holiday)s]" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx:72 +msgid "" +"Unable to load columns for the selected table. Please select a different " +"table." +msgstr "" +"Не удалось загрузить столбцы для выбранной таблицы. Пожалуйста, выберите " +"другую таблицу." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:498 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:559 msgid "" "Unable to migrate query editor state to backend. Superset will retry " "later. Please contact your administrator if this problem persists." msgstr "" +"Не удается перенести состояние редактора запроса на сервер. Суперсет " +"повторит попытку позже. Пожалуйста, свяжитесь с вашим администратором, " +"если эта проблема не устранена." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:452 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:513 msgid "" "Unable to migrate query state to backend. Superset will retry later. " "Please contact your administrator if this problem persists." msgstr "" +"Не удается перенести состояние запроса на сервер. Суперсет повторит " +"попытку позже. Пожалуйста, свяжитесь с вашим администратором, если эта " +"проблема не устранена." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:434 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:495 msgid "" "Unable to migrate table schema state to backend. Superset will retry " "later. Please contact your administrator if this problem persists." msgstr "" +"Не удается перенести состояние схемы таблицы на сервер. Суперсет повторит" +" попытку позже. Пожалуйста, свяжитесь с вашим администратором, если эта " +"проблема не устранена." -#: superset/connectors/sqla/views.py:641 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/WorldMap.js:128 #, python-format -msgid "Unable to refresh metadata for the following table(s): %(tables)s" -msgstr "Метаданные обновлены для следующих таблиц: %(tables)s" +msgid "Unable to process right-click on %s. Check you chart configuration." +msgstr "Не удалось обработать ПКМ на %s. Проверьте настройки графика." + +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:126 +msgid "Unable to retrieve dashboard colors" +msgstr "Не удалось получать цветовую схему дашборда" -#: superset/views/database/views.py:240 +#: superset/views/database/views.py:275 #, python-format msgid "" "Unable to upload CSV file \"%(filename)s\" to table \"%(table_name)s\" in" " database \"%(db_name)s\". Error message: %(error_msg)s" msgstr "" -"Невозможно загрузить CSV-файл \"%(filename)s\" таблицу \"%(table_name)s\"" -" базы данных \"%(db_name)s”. Сообщение об ошибке: %(error_msg)s" +"Не удалось загрузить CSV файл \"%(filename)s\" в таблицу " +"\"%(table_name)s\" в базу данных \"%(db_name)s\". Ошибка: %(error_msg)s" -#: superset/views/database/views.py:538 -#, fuzzy, python-format +#: superset/views/database/views.py:553 +#, python-format msgid "" "Unable to upload Columnar file \"%(filename)s\" to table " "\"%(table_name)s\" in database \"%(db_name)s\". Error message: " "%(error_msg)s" msgstr "" -"Невозможно загрузить Excel-файл \"%(filename)s\" в таблицу " -"\"%(table_name)s\" базы данных \"%(db_name)s”. Сообщение об ошибке: " -"%(error_msg)s" +"Не удалось загрузить файл столбчатого типа \"%(filename)s\" в таблицу " +"\"%(table_name)s\" в базу данных \"%(db_name)s\". Ошибка: %(error_msg)s" -#: superset/views/database/views.py:386 +#: superset/views/database/views.py:412 #, python-format msgid "" "Unable to upload Excel file \"%(filename)s\" to table \"%(table_name)s\" " "in database \"%(db_name)s\". Error message: %(error_msg)s" msgstr "" -"Невозможно загрузить Excel-файл \"%(filename)s\" в таблицу " -"\"%(table_name)s\" базы данных \"%(db_name)s”. Сообщение об ошибке: " -"%(error_msg)s" +"Не удалось загрузить Excel файл \"%(filename)s\" в таблицу " +"\"%(table_name)s\" в базу данных \"%(db_name)s\". Ошибка: %(error_msg)s" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:75 -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:114 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:94 +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:134 msgid "Undefined" msgstr "Не определено" -#: superset/utils/pandas_postprocessing.py:391 +#: superset/utils/pandas_postprocessing/rolling.py:67 msgid "Undefined window for rolling operation" -msgstr "" +msgstr "Неопределенное окно для скольжения" + +#: superset-frontend/src/dashboard/components/Header/index.jsx:553 +msgid "Undo the action" +msgstr "Отменить действие" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx:126 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx:131 msgid "Undo?" msgstr "Отменить?" #: superset-frontend/src/components/ErrorBoundary/index.jsx:51 -#: superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx:26 +#: superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx:25 msgid "Unexpected error" msgstr "Неожиданная ошибка" -#: superset/databases/commands/exceptions.py:135 superset/views/core.py:1391 +#: superset/databases/commands/exceptions.py:137 +#: superset/databases/commands/exceptions.py:142 superset/views/core.py:1426 msgid "Unexpected error occurred, please check your logs for details" msgstr "" -"Произошла непредвиденная ошибка, пожалуйста, проверьте логи для " -"подробностей" +"Возникла неожиданная ошибка, пожалуйста, проверьте историю действий для " +"уточнения деталей" -#: superset-frontend/src/utils/getClientErrorObject.ts:55 -#, fuzzy +#: superset-frontend/src/utils/getClientErrorObject.ts:75 msgid "Unexpected error: " -msgstr "Неожиданная ошибка" +msgstr "Неожиданная ошибка: " -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:95 -#, fuzzy +#: superset/views/api.py:109 +#, fuzzy, python-format +msgid "Unexpected time range: %s" +msgstr "Неожиданная ошибка: " + +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:88 msgid "Unknown" -msgstr "Неизвестная ошибка" +msgstr "Неизвестно" -#: superset/db_engine_specs/mysql.py:129 +#: superset/db_engine_specs/mysql.py:153 #, python-format msgid "Unknown MySQL server host \"%(hostname)s\"." -msgstr "" +msgstr "Неизвестный хост MySQL \"%(hostname)s\"." -#: superset/db_engine_specs/presto.py:1005 +#: superset/db_engine_specs/presto.py:1281 msgid "Unknown Presto Error" -msgstr "Неизвестная ошибка" +msgstr "Неизвестная ошибка Presto" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:111 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:162 msgid "Unknown Status" -msgstr "" +msgstr "Неизвестный статус" -#: superset/connectors/sqla/models.py:1121 +#: superset/connectors/sqla/models.py:1299 superset/models/helpers.py:1483 #, python-format msgid "Unknown column used in orderby: %(col)s" -msgstr "" +msgstr "Неизвестный столбец использован для упорядочивания: %(col)s" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:349 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:389 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:372 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:450 msgid "Unknown error" msgstr "Неизвестная ошибка" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:45 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.js:842 +msgid "Unknown input format" +msgstr "Неизвестный формат ввода" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:43 msgid "Unknown value" msgstr "Неизвестная ошибка" -#: superset/jinja_context.py:347 +#: superset/jinja_context.py:353 #, python-format msgid "Unsafe return type for function %(func)s: %(value_type)s" msgstr "Небезопасный возвращаемый тип для функции %(func)s: %(value_type)s" -#: superset/jinja_context.py:371 +#: superset/jinja_context.py:380 #, python-format msgid "Unsafe template value for key %(key)s: %(value_type)s" -msgstr "Небезопасное значение для ключа шаблона %(key)s: %(value_type)s" +msgstr "Небезопасное значение шаблона для ключа %(key)s: %(value_type)s" -#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:255 +#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:256 #, python-format msgid "Unset Filters (%d)" msgstr "Сбросить фильтры (%d)" -#: superset/utils/core.py:1048 +#: superset/utils/core.py:1103 #, python-format msgid "Unsupported clause type: %(clause)s" -msgstr "" - -#: superset/connectors/druid/models.py:1492 -msgid "Unsupported extraction function: " -msgstr "Неподдерживаемая функция: " +msgstr "Неподдерживаемый оператор: %(clause)s" -#: superset/common/query_object.py:392 +#: superset/common/query_object.py:438 #, python-format msgid "Unsupported post processing operation: %(operation)s" -msgstr "Неподдерживаемая операция пост-процессинга: %(operation)s" +msgstr "Неподдерживаемая операция постобработки: %(operation)s" -#: superset/jinja_context.py:358 +#: superset/jinja_context.py:364 #, python-format msgid "Unsupported return value for method %(name)s" -msgstr "Неподдерживаемое возвращаемое значение для метода %(name)s" +msgstr "Неподдерживаемое значение для метода %(name)s" -#: superset/jinja_context.py:382 +#: superset/jinja_context.py:391 #, python-format msgid "Unsupported template value for key %(key)s" -msgstr "Неподдерживаемое значение для ключа шаблона %(key)s" +msgstr "Неподдерживаемое значение шаблона для ключа %(key)s" -#: superset/utils/pandas_postprocessing.py:818 +#: superset/utils/pandas_postprocessing/prophet.py:117 #, python-format msgid "Unsupported time grain: %(time_grain)s" -msgstr "Недействительная гранулярность времени: %(time_grain)s" +msgstr "Неподдерживаемая единица времени: %(time_grain)s" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:264 -#, python-format -msgid "Untitled Query %s" -msgstr "Запрос без имени %s" +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:148 +msgid "Untitled Dataset" +msgstr "Безымянный датасет" + +#: superset/views/sql_lab/views.py:148 +#, fuzzy +msgid "Untitled Query" +msgstr "Безымянный запрос" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:331 #: superset-frontend/src/SqlLab/reducers/getInitialState.js:44 msgid "Untitled query" -msgstr "Запрос без имени" +msgstr "Безымянный запрос" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:190 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:224 msgid "Update" msgstr "Обновить" -#: superset-frontend/src/chart/chartReducer.ts:82 +#: superset-frontend/src/explore/components/RunQueryButton/index.tsx:54 +#: superset-frontend/src/utils/getChartRequiredFieldsMissingMessage.ts:23 +msgid "Update chart" +msgstr "Обновить график" + +#: superset-frontend/src/components/Chart/chartReducer.ts:83 msgid "Updating chart was stopped" msgstr "Обновление графика остановлено" @@ -13920,99 +16846,143 @@ msgstr "Обновление графика остановлено" msgid "Upload" msgstr "Загрузить" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:134 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:199 +msgid "Upload CSV" +msgstr "Загрузить CSV" + +#: superset-frontend/src/views/components/RightMenu.tsx:190 +msgid "Upload CSV to database" +msgstr "Загрузить файл CSV в базу данных" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:135 msgid "Upload Credentials" -msgstr "Загрузить файл Excel" +msgstr "Загрузить учетные данные" -#: superset/initialization/__init__.py:400 -msgid "Upload Excel" +#: superset/databases/filters.py:66 +msgid "Upload Enabled" +msgstr "Загрузка включена" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:213 +msgid "Upload Excel file" msgstr "Загрузить файл Excel" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:102 +#: superset-frontend/src/views/components/RightMenu.tsx:202 +msgid "Upload Excel file to database" +msgstr "Загрузить файл Excel в базу данных" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:101 msgid "Upload JSON file" -msgstr "" +msgstr "Загрузить JSON файл" -#: superset/initialization/__init__.py:369 -msgid "Upload a CSV" -msgstr "Загрузить CSV" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:206 +msgid "Upload columnar file" +msgstr "Загрузить файл столбчатого формата" -#: superset/initialization/__init__.py:383 -msgid "Upload a Columnar File" -msgstr "" +#: superset-frontend/src/views/components/RightMenu.tsx:196 +msgid "Upload columnar file to database" +msgstr "Загрузить файл столбчатого формата в базу данных" -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:112 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:196 +msgid "Upload file to database" +msgstr "Загрузить файл в базу данных" + +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:674 +#, python-format +msgid "Use \"%(menuName)s\" menu instead." +msgstr "Использовать меню \"%(menuName)s\" взамен." + +#: superset-frontend/src/dashboard/util/getSliceHeaderTooltip.tsx:34 +#, python-format +msgid "Use %s to open in a new tab." +msgstr "Используйте %s для открытия в отдельной вкладке." + +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:104 +#: superset-frontend/src/explore/controlUtils/controlUtils.test.tsx:113 +#: superset-frontend/src/explore/fixtures.tsx:43 msgid "Use Area Proportions" -msgstr "Свойства дашборда" +msgstr "Использовать пропорции области" -#: superset/views/database/forms.py:175 superset/views/database/forms.py:433 -#, fuzzy, python-format +#: superset/views/database/forms.py:462 msgid "Use Columns" -msgstr "Столбец(ы) %s" - -#: superset/views/database/forms.py:211 -msgid "Use Pandas to interpret the datetime format automatically." -msgstr "" -"Используйте Pandas для автоматической интерпретации формата даты и " -"времени." +msgstr "Используемые столбцы" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:207 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:200 msgid "Use a log scale" -msgstr "" +msgstr "Использовать логарифмическую шкалу" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:107 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:108 msgid "Use a log scale for the X-axis" -msgstr "" +msgstr "Использовать логарифмическую шкалу для оси X" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:230 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:250 msgid "Use a log scale for the Y-axis" -msgstr "" +msgstr "Использовать логарифмическую шкалу для оси Y" -#: superset/db_engine_specs/base.py:1401 +#: superset/db_engine_specs/base.py:1746 +#: superset/db_engine_specs/databricks.py:57 msgid "Use an encrypted connection to the database" +msgstr "Использовать зашифрованное соединение к Базе Данных" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:438 +#, python-format +msgid "" +"Use another existing chart as a source for annotations and overlays.\n" +" Your chart must be one of these visualization types: [%s]" +msgstr "" + +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:86 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:160 +msgid "Use date formatting even when metric value is not a timestamp" msgstr "" +"Использовать перевод к формату дата/время даже если мера представляет " +"другой тип данных" -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:209 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:213 msgid "Use legacy datasource editor" msgstr "Использовать старый редактор" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:85 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:122 msgid "Use metrics as a top level group for columns or for rows" msgstr "" -#: superset-frontend/src/filters/components/Range/controlPanel.ts:68 +#: superset-frontend/src/filters/components/Range/controlPanel.ts:70 msgid "Use only a single value." -msgstr "" +msgstr "Используйте только одно значение." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:124 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:117 msgid "Use the Advanced Analytics options below" -msgstr "" +msgstr "Используйте настройки Расширенной аналитики ниже" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:136 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:137 msgid "" "Use the JSON file you automatically downloaded when creating your service" " account." msgstr "" #: superset/templates/superset/fab_overrides/list_with_checkboxes.html:82 -msgid "Use the edit buttom to change this field" -msgstr "Используйте кнопку правки для изменения этого поля" +msgid "Use the edit button to change this field" +msgstr "Используйте кнопку редактирования для изменения поля" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:176 -#: superset-frontend/src/explore/controls.jsx:207 +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:39 +msgid "Use this section if you want a query that aggregates" +msgstr "" + +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:53 +msgid "Use this section if you want to query atomic rows" +msgstr "" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:130 +#: superset-frontend/src/explore/controls.jsx:206 msgid "Use this to define a static color for all circles" -msgstr "Используйте это цвет для заливки всех кругов одним цветом" +msgstr "Этот цвет используется для заливки" #: superset/views/dynamic_plugins.py:48 msgid "" "Used internally to identify the plugin. Should be set to the package name" " from the pluginʼs package.json" msgstr "" -"Используется системой для идентификации плагина. Должно быть установлено " -"в имя пакета, которое указано в файле package.json" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:27 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:28 msgid "" "Used to summarize a set of data by grouping together multiple statistics " "along two axes. Examples: Sales numbers by region and month, tasks by " @@ -14021,69 +16991,75 @@ msgid "" " This chart is being deprecated and we recommend checking out Pivot " "Table V2 instead!" msgstr "" +"Используется для обобщения набора данных путем группировки нескольких " +"показателей по двум осям. Примеры: показатели продаж по регионам и " +"месяцам, задачи по статусу и назначенному лицу, активные пользователи по " +"возрасту и местоположению.\n" +" Этот график устарел, рекомендуется использовать график Сводная Таблица 2." -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:51 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:52 msgid "" "Used to summarize a set of data by grouping together multiple statistics " "along two axes. Examples: Sales numbers by region and month, tasks by " "status and assignee, active users by age and location. Not the most " "visually stunning visualization, but highly informative and versatile." msgstr "" +"Используется для обобщения набора данных путем группировки нескольких " +"показателей по двум осям. Примеры: показатели продаж по регионам и " +"месяцам, задачи по статусу и назначенному лицу, активные пользователи по " +"возрасту и местоположению." -#: superset-frontend/src/components/Menu/MenuRight.tsx:158 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:275 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:365 -#: superset/views/access_requests.py:41 superset/views/log/__init__.py:30 -#: superset/views/schedules.py:239 superset/views/schedules.py:319 -#: superset/views/sql_lab.py:69 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:293 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:385 +#: superset-frontend/src/views/components/RightMenu.tsx:490 +#: superset/views/access_requests.py:44 superset/views/log/__init__.py:30 +#: superset/views/sql_lab/views.py:82 msgid "User" msgstr "Пользователь" -#: superset/views/access_requests.py:42 +#: superset/views/access_requests.py:45 msgid "User Roles" -msgstr "Роли пользователей" +msgstr "Роли пользователя" -#: superset/errors.py:112 -#, fuzzy +#: superset/errors.py:118 msgid "User doesn't have the proper permissions." -msgstr "У вас нет прав на " - -#: superset-frontend/src/filters/components/Select/controlPanel.ts:94 -#, fuzzy -msgid "User must select a value before applying the filter" -msgstr "Пользователю нужно будет выбрать значение для этого фильтра" - -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:253 -msgid "User must select a value for this filter" -msgstr "Пользователю нужно будет выбрать значение для этого фильтра" +msgstr "У пользователя нет надлежащего доступа." -#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:76 +#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:75 #: superset-frontend/src/filters/components/Range/controlPanel.ts:58 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:93 #: superset-frontend/src/filters/components/Time/controlPanel.ts:56 #: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:36 #: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:36 -#, fuzzy -msgid "User must select a value for this filter." -msgstr "Пользователю нужно будет выбрать значение для этого фильтра" +msgid "User must select a value before applying the filter" +msgstr "Для использования фильтра пользователь будет обязан выбрать значение" + +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:253 +msgid "User must select a value for this filter" +msgstr "Для использования фильтра пользователь будет обязан выбрать значение" -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:154 +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:156 msgid "User query" -msgstr "Скопировать запрос" +msgstr "Пользовательский запрос" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:109 -#: superset/db_engine_specs/base.py:1388 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:133 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:138 +#: superset/db_engine_specs/base.py:1733 msgid "Username" -msgstr "Имя запроса" +msgstr "Имя пользователя" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:39 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:41 msgid "" "Uses a gauge to showcase progress of a metric towards a target. The " "position of the dial represents the progress and the terminal value in " "the gauge represents the target value." msgstr "" +"Использует индикатор для демонстрации прогресса показателя в достижении " +"цели. Положение циферблата показывает ход выполнения, а конечное значение" +" на индикаторе представляет целевое значение." #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:28 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts:37 msgid "" "Uses circles to visualize the flow of data through different stages of a " "system. Hover over individual paths in the visualization to understand " @@ -14091,161 +17067,185 @@ msgid "" "funnels and pipelines." msgstr "" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:294 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1186 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1202 -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:140 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:52 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:89 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:103 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:109 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:116 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:99 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:315 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:405 +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:143 msgid "Value" -msgstr "Подписи" +msgstr "Значение" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:91 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:83 msgid "Value Domain" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:329 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:343 msgid "Value Format" msgstr "Формат значения" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:235 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:249 msgid "Value bounds" -msgstr "" +msgstr "Ограничения для значения" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:165 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:206 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:161 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:271 msgid "Value format" msgstr "Формат значения" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx:75 -#, fuzzy msgid "Value is required" -msgstr "Имя обязательно" +msgstr "Значение обязательно" -#: superset/reports/schemas.py:185 superset/reports/schemas.py:191 -#: superset/reports/schemas.py:197 superset/reports/schemas.py:275 -#: superset/reports/schemas.py:281 superset/reports/schemas.py:288 -#, fuzzy +#: superset/reports/schemas.py:186 superset/reports/schemas.py:192 +#: superset/reports/schemas.py:198 superset/reports/schemas.py:280 +#: superset/reports/schemas.py:286 superset/reports/schemas.py:293 msgid "Value must be greater than 0" -msgstr "`смещение_строк` должно быть больше или равно 0" +msgstr "Значение должно быть больше 0" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:194 +msgid "Values are dependent on other filters" +msgstr "Значения зависят от других фильтров" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:201 +msgid "Values dependent on" +msgstr "Значения зависят от" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:197 +msgid "" +"Values selected in other filters will affect the filter options to only " +"show relevant values" +msgstr "" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:39 msgid "Vehicle Types" msgstr "" -#: superset/connectors/druid/views.py:189 -#: superset/connectors/druid/views.py:238 superset/connectors/sqla/views.py:144 -#: superset/connectors/sqla/views.py:257 +#: superset/connectors/sqla/views.py:157 superset/connectors/sqla/views.py:253 msgid "Verbose Name" -msgstr "Полное имя" +msgstr "Удобочитаемое имя" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:482 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:503 +#: superset-frontend/src/views/components/RightMenu.tsx:517 msgid "Version" -msgstr "" +msgstr "Версия" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:489 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:509 msgid "Version number" -msgstr "" +msgstr "Номер версии" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:41 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:48 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:84 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:42 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:54 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:279 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:87 msgid "Vertical" -msgstr "" +msgstr "Вертикально" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx:162 +msgid "Vertical (Left)" +msgstr "Вертикально (слева)" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:38 msgid "Video game consoles" -msgstr "" +msgstr "Игровые приставки" + +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:230 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:386 +msgid "View" +msgstr "Показать" -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:217 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:219 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:296 +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:200 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:198 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:270 msgid "View All »" -msgstr "" +msgstr "Смотреть все »" + +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/DatasetPanel.tsx:227 +msgid "View Dataset" +msgstr "Посмотреть датасет" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:287 -msgid "View chart in Explore" -msgstr "Посмотреть график в режиме исследования" +#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:128 +msgid "View all charts" +msgstr "Показать все графики" -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:197 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:451 +msgid "View as table" +msgstr "Показать в виде таблицы" + +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:313 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:343 msgid "View in SQL Lab" -msgstr "Открыть в лаборатории SQL" +msgstr "Открыть в Лаборатории SQL" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:166 +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:195 #, python-format msgid "View keys & indexes (%s)" -msgstr "Посмотреть ключи и индексы (%s)" +msgstr "Показать ключи и индексы (%s)" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:296 -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:298 -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:86 -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:88 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:432 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:434 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:394 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:396 msgid "View query" -msgstr "Скопировать запрос" - -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:216 -#: superset-frontend/src/explore/components/DataTablesPane/index.tsx:396 -msgid "View results" -msgstr "Посмотреть результаты" +msgstr "Показать SQL запрос" -#: superset-frontend/src/explore/components/DataTablesPane/index.tsx:409 -msgid "View samples" -msgstr "Посмотреть примеры" - -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:180 +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:172 msgid "Viewed" msgstr "Просмотрено" -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:124 -#, fuzzy, python-format +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:117 +#, python-format msgid "Viewed %s" -msgstr "Просмотрено" +msgstr "Просмотрено %s" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:268 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:273 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:293 +#: superset-frontend/src/explore/components/controls/ViewportControl.jsx:111 msgid "Viewport" -msgstr "рассылка" +msgstr "Область просмотра" + +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:563 +msgid "Virtual" +msgstr "Виртуальный" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:133 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:145 msgid "Virtual (SQL)" msgstr "Виртуальный (SQL)" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:231 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:285 msgid "Virtual dataset" msgstr "Виртуальный датасет" -#: superset/connectors/sqla/models.py:849 superset/connectors/sqla/utils.py:83 -#, fuzzy +#: superset/connectors/sqla/models.py:951 superset/connectors/sqla/utils.py:110 +#: superset/models/helpers.py:1021 msgid "Virtual dataset query cannot be empty" -msgstr "Виртуальный датасет должен быть read-only" +msgstr "Запрос виртуального датасета не может быть пустым" -#: superset/connectors/sqla/models.py:852 +#: superset/connectors/sqla/models.py:954 superset/models/helpers.py:1024 msgid "Virtual dataset query cannot consist of multiple statements" -msgstr "Виртуальный датасет не может содержать несколько выражений" +msgstr "Запрос виртуального датасета не может содержать несколько запросов" -#: superset/connectors/sqla/models.py:825 +#: superset/connectors/sqla/models.py:919 superset/models/helpers.py:1047 msgid "Virtual dataset query must be read-only" -msgstr "Виртуальный датасет должен быть read-only" +msgstr "Запрос виртуального датасета должен быть доступен только для чтения" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:192 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:204 msgid "Visual Tweaks" -msgstr "" +msgstr "Визуальные настройки" -#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:132 -msgid "Visualization" -msgstr "Визуализация" - -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:168 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:122 #: superset/views/chart/mixin.py:88 msgid "Visualization Type" msgstr "Тип визуализации" -#: superset-frontend/src/explore/controls.jsx:200 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:270 +#: superset-frontend/src/pages/ChartList/index.tsx:369 msgid "Visualization type" msgstr "Тип визуализации" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:50 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:52 msgid "" "Visualize a parallel set of metrics across multiple groups. Each group is" " visualized using its own line of points and each metric is represented " @@ -14259,53 +17259,85 @@ msgid "" "to emphasize the strength of the link between each pair of groups." msgstr "" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:27 +msgid "" +"Visualize geospatial data like 3D buildings, landscapes, or objects in " +"grid view." +msgstr "" +"Визуализирует геопространственные данные, такие как 3D-здания, ландшафты " +"или объекты в виде сетки." + #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:31 msgid "" "Visualize how a metric changes over time using bars. Add a group by " "column to visualize group level metrics and how they change over time." msgstr "" +"Визуализирует изменение меры с течением времени, используя столбцы. " +"Добавьте столбец для группировки, чтобы визуализировать показатели уровня" +" группы и то, как они меняются с течением времени." #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:35 msgid "" "Visualize multiple levels of hierarchy using a familiar tree-like " "structure." -msgstr "" +msgstr "Визуализирует несколько уровней иерархии, используя древовидную структуру." -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:58 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:61 msgid "" -"Visualize two different time series using the same x-axis time range. " -"Note that each time series can be visualized differently (e.g. 1 using " -"bars and 1 using a line)." +"Visualize two different series using the same x-axis. Note that both " +"series can be visualized with a different chart type (e.g. 1 using bars " +"and 1 using a line)." msgstr "" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:27 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:28 msgid "" "Visualize two different time series using the same x-axis time range. " "This chart is being deprecated and we recommend using the Mixed " "Timeseries Chart instead!" msgstr "" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:27 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:64 +msgid "" +"Visualize two different time series using the same x-axis. Note that each" +" time series can be visualized differently (e.g. 1 using bars and 1 using" +" a line)." +msgstr "" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:28 msgid "" "Visualizes 2 metrics as line plots using the same x-axis. This chart is " "useful for comparing metrics across the same time range." msgstr "" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:27 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:28 msgid "" "Visualizes a metric across three dimensions of data in a single chart (X " "axis, Y axis, and bubble size). Bubbles from the same group can be " "showcased using bubble color." msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:27 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/index.js:27 +msgid "Visualizes connected points, which form a path, on a map." +msgstr "Визуализирует связанные точки, которые образуют путь, на карте." + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:27 +msgid "" +"Visualizes geographic areas from your data as polygons on a Mapbox " +"rendered map. Polygons can be colored using a metric." +msgstr "" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:28 msgid "" "Visualizes how a metric has changed over a time using a color scale and a" " calendar view. Gray values are used to indicate missing values and the " "linear color scheme is used to encode the magnitude of each day's value." msgstr "" +"Визуализирует, как показатель изменился с течением времени, используя " +"цветовую шкалу и календарь. Значения серого цвета используются для " +"обозначения отсутствующих значений, а линейная цветовая схема " +"используется для отображения величины значения каждого дня." -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:27 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:29 msgid "" "Visualizes how a single metric varies across a country's principal " "subdivisions (states, provinces, etc) on a chloropleth map. Each " @@ -14313,7 +17345,7 @@ msgid "" "geographic boundary." msgstr "" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:27 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:28 msgid "" "Visualizes many different time-series objects in a single chart. This " "chart is being deprecated and we recommend using the Time-series Chart " @@ -14333,37 +17365,38 @@ msgid "" "Visualizes the words in a column that appear the most often. Bigger font " "corresponds to higher frequency." msgstr "" +"Визуализирует слова в столбце, которые появляются чаще всего. Более " +"крупный шрифт соответствует более высокой частоте" -#: superset/viz.py:133 +#: superset/viz.py:141 msgid "Viz is missing a datasource" msgstr "У визуализации отсутствует источник данных" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:495 +#: superset-frontend/src/dashboard/components/AddSliceCard/AddSliceCard.tsx:265 msgid "Viz type" -msgstr "Тип" +msgstr "Тип визуализации" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:84 msgid "WED" msgstr "СР" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:697 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:898 msgid "Want to add a new database?" -msgstr "" +msgstr "Хотите добавить новую базу данных?" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1090 -#, fuzzy +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1240 msgid "Warning" -msgstr "Предупреждение!" +msgstr "Предупреждение" -#: superset/connectors/druid/views.py:193 superset/connectors/sqla/views.py:263 +#: superset/connectors/sqla/views.py:259 msgid "Warning Message" -msgstr "Предупреждающее сообщение" +msgstr "Предупреждение" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:285 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:286 msgid "Warning!" msgstr "Предупреждение!" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:46 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:47 msgid "" "Warning! Changing the dataset may break the chart if the metadata does " "not exist." @@ -14371,85 +17404,129 @@ msgstr "" "Внимание! Изменение датасета может привести к тому, что график станет " "нерабочим, если будут отсутствовать метаданные." -#: superset/db_engine_specs/bigquery.py:166 +#: superset/databases/commands/exceptions.py:157 +#: superset/databases/commands/exceptions.py:167 +msgid "Was unable to check your query" +msgstr "Не удалось проверить запрос" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1295 +msgid "" +"We are unable to connect to your database. Click \"See more\" for " +"database-provided information that may help troubleshoot the issue." +msgstr "" +"Не удалось подключиться к базе данных. Нажмите \"Подробнее\" для " +"информации, предоставленной базой данных в ответ, для решения проблемы." + +#: superset/db_engine_specs/bigquery.py:178 #, python-format msgid "We can't seem to resolve column \"%(column)s\" at line %(location)s." -msgstr "" +msgstr "Не удалось обнаружить столбец \"%(column)s\" в строке %(location)s." -#: superset/db_engine_specs/sqlite.py:63 +#: superset/db_engine_specs/duckdb.py:56 superset/db_engine_specs/sqlite.py:65 #, python-format msgid "We can't seem to resolve the column \"%(column_name)s\"" -msgstr "" +msgstr "Не удалось обнаружить столбец \"%(column_name)s\"" -#: superset/db_engine_specs/postgres.py:150 -#: superset/db_engine_specs/presto.py:171 +#: superset/db_engine_specs/postgres.py:132 +#: superset/db_engine_specs/presto.py:603 #, python-format msgid "" "We can't seem to resolve the column \"%(column_name)s\" at line " "%(location)s." -msgstr "" +msgstr "Не удалось обнаружить столбец \"%(column_name)s\" в строке %(location)s." -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:118 -msgid "We recommend your summarize your data further before following that flow. " -msgstr "" +#: superset-frontend/src/visualizations/dashboardComponents/ExampleComponent/ExampleComponent.tsx:29 +#, python-format +msgid "We have the following keys: %s" +msgstr "У нас есть следующие ключи: %s" -#: superset-frontend/src/reports/actions/reports.js:156 +#: superset-frontend/src/reports/actions/reports.js:136 msgid "We were unable to active or deactivate this report." -msgstr "" +msgstr "Не удалось включить или выключить эту рассылку." -#: superset/db_engine_specs/redshift.py:86 +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:681 +msgid "" +"We were unable to carry over any controls when switching to this new " +"dataset." +msgstr "Не удалось перенести настройки прошлого графика при переключении датасета." + +#: superset/db_engine_specs/redshift.py:90 #, python-format msgid "" "We were unable to connect to your database named \"%(database)s\". Please" " verify your database name and try again." msgstr "" +"Не удалось подключиться к вашей базе данных с именем \"%(database)s\". " +"Пожалуйста, подтвердите имя вашей базы данных и попробуйте снова." -#: superset/db_engine_specs/bigquery.py:149 -msgid "" -"We were unable to connect to your database. Please confirm that your " -"service account has the Viewer and Job User roles on the project." -msgstr "" - -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:60 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/index.js:31 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:63 msgid "Web" -msgstr "" +msgstr "Сеть" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:59 msgid "Wednesday" msgstr "Среда" -#: superset/db_engine_specs/base.py:97 -#, fuzzy +#: superset/db_engine_specs/base.py:111 msgid "Week" -msgstr "неделя" +msgstr "Неделя" -#: superset/db_engine_specs/base.py:103 +#: superset/db_engine_specs/base.py:117 msgid "Week ending Saturday" -msgstr "" +msgstr "Неделя, заканчивающаяся в субботу" -#: superset/db_engine_specs/base.py:102 +#: superset/db_engine_specs/base.py:116 msgid "Week starting Monday" -msgstr "" +msgstr "Неделя, начинающаяся в понедельник" -#: superset/db_engine_specs/base.py:101 +#: superset/db_engine_specs/base.py:115 msgid "Week starting Sunday" -msgstr "" +msgstr "Неделя, начинающаяся в воскресенье" -#: superset/db_engine_specs/base.py:104 +#: superset/db_engine_specs/base.py:118 msgid "Week_ending Sunday" -msgstr "" +msgstr "Неделя, заканчивающаяся в воскресенье" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:67 -#, fuzzy, python-format +#: superset-frontend/src/components/ReportModal/index.tsx:120 +msgid "Weekly Report" +msgstr "Еженедельный отчет" + +#: superset-frontend/src/components/ReportModal/index.tsx:119 +#, python-format +msgid "Weekly Report for %s" +msgstr "Еженедельный отчет для %s" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:104 +msgid "Weekly seasonality" +msgstr "Недельная сезонность" + +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:66 +#, python-format msgid "Weeks %s" -msgstr "неделя" +msgstr "Недель %s" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/Screengrid.jsx:49 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:77 +msgid "Weight" +msgstr "Вес" #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:52 #, python-format msgid "" "We’re having trouble loading these results. Queries are set to timeout " "after %s second." -msgstr "" +msgid_plural "" +"We’re having trouble loading these results. Queries are set to timeout " +"after %s seconds." +msgstr[0] "" +"Возникла проблема при загрузке результатов. Для запросов установлен " +"тайм-аут %s секунда." +msgstr[1] "" +"Возникла проблема при загрузке результатов. Для запросов установлен " +"тайм-аут %s секунды." +msgstr[2] "" "Возникла проблема при загрузке результатов. Для запросов установлен " "тайм-аут %s секунд." @@ -14458,48 +17535,75 @@ msgstr "" msgid "" "We’re having trouble loading this visualization. Queries are set to " "timeout after %s second." -msgstr "" +msgid_plural "" +"We’re having trouble loading this visualization. Queries are set to " +"timeout after %s seconds." +msgstr[0] "" +"Возникла проблема при загрузке этой визуализации. Для запросов установлен" +" тайм-аут %s секунда." +msgstr[1] "" +"Возникла проблема при загрузке этой визуализации. Для запросов установлен" +" тайм-аут %s секунды." +msgstr[2] "" "Возникла проблема при загрузке этой визуализации. Для запросов установлен" " тайм-аут %s секунд." #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:58 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:102 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:110 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:113 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:103 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:101 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:109 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:112 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:119 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:102 msgid "What should be shown on the label?" -msgstr "" +msgstr "Текст, отображаемый на метке" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:437 -#: superset-frontend/src/explore/controls.jsx:454 +#: superset/views/database/forms.py:165 +msgid "What should happen if the table already exists" +msgstr "Что должно произойти, если таблица уже существует" + +#: superset-frontend/src/explore/controls.jsx:434 msgid "" "When `Calculation type` is set to \"Percentage change\", the Y Axis " "Format is forced to `.1%`" msgstr "" -"Когда `Тип расчёта` установлен в “Изменение процента”, формат оси Y " +"Когда `Тип расчёта` установлен в \"Процентное изменение\", формат оси Y " "устанавливается в `.1%`" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:76 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:86 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:183 msgid "When a secondary metric is provided, a linear color scale is used." msgstr "" +"Когда предоставляется вторичная мера, используется линейная цветовая " +"схема." -#: superset/views/database/mixins.py:120 +#: superset/views/database/mixins.py:119 msgid "" "When allowing CREATE TABLE AS option in SQL Lab, this option forces the " "table to be created in this schema" msgstr "" -"При разрешении опции CREATE TABLE AS в редакторе SQL эта опция создаст " -"таблицу в выбранной схеме" +"При включении опции CREATE TABLE AS в Лаборатории SQL, новые таблицы " +"будут добавлены в эту схему" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:100 +msgid "When checked, the map will zoom to your data after each query" +msgstr "" +"Если отмечено, карта будет смасштабирована к вашим данным после каждого " +"запроса" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:195 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:189 msgid "When enabled, users are able to visualize SQL Lab results in Explore." msgstr "" +"Если этот параметр включен, пользователи могут смотреть ответ запросов " +"Лаборатории SQL в режиме исследования." -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:71 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:76 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:173 msgid "When only a primary metric is provided, a categorical color scale is used." msgstr "" +"Когда предоставляется только основная мера, используется категориальная " +"цветовая схема." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:898 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1083 msgid "" "When specifying SQL, the datasource acts as a view. Superset will use " "this statement as a subquery while grouping and filtering on the " @@ -14509,7 +17613,7 @@ msgstr "" "будет использовать это выражение в подзапросе, при необходимости " "группировки и фильтрации." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:716 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:882 msgid "" "When using \"Autocomplete filters\", this can be used to improve " "performance of the query fetching the values. Use this option to apply a " @@ -14517,483 +17621,552 @@ msgid "" "the table. Typically the intent would be to limit the scan by applying a " "relative time filter on a partitioned or indexed time-related field." msgstr "" +"При использовании \"Фильтров автозаполнения\" это может использоваться " +"для улучшения быстродействия запроса. Используйте эту опцию для настройки" +" предиката (оператор WHERE) запроса для уникальных значений из таблицы. " +"Обычно целью является ограничение сканирования путем применения " +"относительного временного фильтра к секционированному или " +"индексированному полю типа дата/время." -#: superset/viz.py:834 +#: superset/viz.py:858 msgid "When using 'Group By' you are limited to use a single metric" -msgstr "" -"При использовании поля [Группировка] вы не ограничены использованием " -"одного среза" +msgstr "При использовании 'GROUP BY' вы ограничены использованием одной меры" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:258 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:110 +msgid "When using this option, default value can’t be set" +msgstr "При включении этой опции нельзя установить значение по умолчанию" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:254 msgid "Whether the progress bar overlaps when there are multiple groups of data" -msgstr "" +msgstr "Индикатор прогресса накладывается при наличии нескольких групп данных" -#: superset/connectors/sqla/views.py:466 +#: superset/connectors/sqla/views.py:456 msgid "Whether the table was generated by the 'Visualize' flow in SQL Lab" msgstr "" -#: superset/connectors/druid/views.py:98 superset/connectors/sqla/views.py:99 +#: superset/connectors/sqla/views.py:112 msgid "" "Whether this column is exposed in the `Filters` section of the explore " "view." msgstr "" -"Необходимо отметить, если столбец должен быть доступен в разделе " -"«Фильтры»." -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:430 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:441 msgid "" "Whether to align background charts with both positive and negative values" " at 0" msgstr "" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:128 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:117 msgid "Whether to align positive and negative values in cell bar chart at 0" -msgstr "" +msgstr "Выравнивание гистограммы внутри ячеек по горизонтали слева" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:739 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:789 msgid "Whether to always show the annotation label" -msgstr "" +msgstr "Всегда показывать метку аннотации" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:192 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:188 msgid "Whether to animate the progress and the value or just display them" -msgstr "" +msgstr "Анимировать прогресс и значение или просто отображать их" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:317 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:331 msgid "Whether to apply a normal distribution based on rank on the color scale" -msgstr "" +msgstr "Применять нормальное распределение на основе ранга в цветовой схеме" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:138 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:442 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:166 +msgid "Whether to apply filter when items are clicked" +msgstr "Применять фильтр при щелчке по элементам" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:127 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:453 msgid "Whether to colorize numeric values by if they are positive or negative" -msgstr "" +msgstr "Окрашивать ячейки с числами в зависимости от их знака" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:120 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:416 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:109 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:427 msgid "Whether to display a bar chart background in table columns" -msgstr "" +msgstr "Отображать гистограмм в колонках таблицы" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:38 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:40 msgid "Whether to display a legend for the chart" -msgstr "" +msgstr "Отображать легенду для графика" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:83 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:85 msgid "Whether to display bubbles on top of countries" -msgstr "" +msgstr "Отображать пузыри поверх стран" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:60 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:194 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:102 +msgid "Whether to display the aggregate count" +msgstr "Отображать совокупное количество" + +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:50 msgid "Whether to display the interactive data table" -msgstr "" +msgstr "Отображать интерактивную таблицу с данными" -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:130 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:129 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:152 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:97 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:74 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:96 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:75 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:73 msgid "Whether to display the labels." -msgstr "" +msgstr "Отображать метки" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:99 msgid "" "Whether to display the labels. Note that the label only displays when the" " the 5% threshold." msgstr "" +"Отображать метки. Обратите внимание, что метка отображается только при " +"достижении порогового значения 5%." #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:157 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:278 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:132 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:152 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:292 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:118 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:159 msgid "Whether to display the legend (toggles)" -msgstr "" +msgstr "Отображать легенду (переключатель)" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:181 msgid "Whether to display the metric name as a title" -msgstr "" +msgstr "Отображать имя меры как названия" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:273 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:293 msgid "Whether to display the min and max values of the X-axis" -msgstr "" +msgstr "Отображать минимальное и максимальное значение на оси X" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:94 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:105 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:101 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:112 msgid "Whether to display the min and max values of the Y-axis" -msgstr "" +msgstr "Отображать минимальное и максимальное значение на оси Y" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:167 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:304 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:185 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:318 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:187 msgid "Whether to display the numerical values within the cells" -msgstr "" +msgstr "Отображение числовых значений в ячейках" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:141 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:261 +msgid "Whether to display the stroke" +msgstr "Отображение обводки" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:148 msgid "Whether to display the time range interactive selector" -msgstr "Предупреждение для отображения на селекторе показателей" +msgstr "Отображение интерактивного селектора временного интервала" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:88 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:80 msgid "Whether to display the timestamp" -msgstr "" +msgstr "Отображение временную метку" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:100 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:92 msgid "Whether to display the trend line" -msgstr "" +msgstr "Отображение трендовой линии" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:170 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:279 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:171 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:280 msgid "Whether to enable changing graph position and scaling." msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:144 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:145 msgid "Whether to enable node dragging in force layout mode." -msgstr "" +msgstr "Включить перемещение вершин в режиме силового алгоритма." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:63 -#, fuzzy -msgid "Whether to format the timestamp" -msgstr "Показатель, по которому сортировать результаты" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:250 +msgid "Whether to fill the objects" +msgstr "Использовать заливку для объектов" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:406 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:89 +msgid "Whether to ignore locations that are null" +msgstr "Игнорировать местоположения, которые не содержат данных о расположении" + +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:417 msgid "Whether to include a client-side search box" -msgstr "Включить фильтр на определенный интервал/диапазон времени" +msgstr "Отображение строки поиска" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:81 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:51 msgid "Whether to include a time filter" msgstr "Включить фильтр на определенный интервал/диапазон времени" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:289 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:303 msgid "Whether to include the percentage in the tooltip" -msgstr "Включить фильтр на определенный интервал/диапазон времени" +msgstr "Отображение процентной доли во всплывающей подсказке" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:326 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/includeTime.ts:28 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:336 msgid "Whether to include the time granularity as defined in the time section" msgstr "" +"Добавляет столбец даты/времени с группировкой дат, как определено в " +"разделе Время" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:155 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:273 +msgid "Whether to make the grid 3D" +msgstr "Сделать сетку 3D" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:141 msgid "Whether to make the histogram cumulative" -msgstr "" +msgstr "Сделать гистограмму нарастающей" -#: superset/connectors/sqla/views.py:94 +#: superset/connectors/sqla/views.py:107 msgid "" "Whether to make this column available as a [Time Granularity] option, " "column has to be DATETIME or DATETIME-like" msgstr "" -"Сделать этот столбец доступным в разделе [Время]. Столбец должен быть в " -"формате DATETIME" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:143 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:129 msgid "Whether to normalize the histogram" -msgstr "" +msgstr "Нормализовать гистограмму" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:709 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:875 msgid "Whether to populate autocomplete filters options" -msgstr "Включить фильтр на определенный интервал/диапазон времени" +msgstr "Распространить настройки фильтров автозаполнения" -#: superset/connectors/druid/views.py:325 superset/connectors/sqla/views.py:461 +#: superset/connectors/sqla/views.py:451 msgid "" "Whether to populate the filter's dropdown in the explore view's filter " "section with a list of distinct values fetched from the backend on the " "fly" -msgstr "Получение списка фильтруемых значений, выполняя онлайн-запрос к серверу" +msgstr "" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:163 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:170 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:125 msgid "" "Whether to show extra controls or not. Extra controls include things like" " making mulitBar charts stacked or side by side." msgstr "" +"Отображает дополнительные элементы управления на самом графике и " +"позволяет менять отображение столбцов: без накопления и с ним." -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:207 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:203 msgid "Whether to show minor ticks on the axis" -msgstr "" +msgstr "Отображение мелких отметок на оси" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:180 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:176 msgid "Whether to show the pointer" -msgstr "" +msgstr "Отображение указателя" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:246 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:242 msgid "Whether to show the progress of gauge chart" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:219 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:215 msgid "Whether to show the split lines on the axis" -msgstr "" +msgstr "Отображение линий разделения на оси" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:44 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:47 -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:42 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:50 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:49 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:48 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:46 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:61 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:356 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:107 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:91 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:88 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:68 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:85 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:91 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:92 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:339 -#: superset-frontend/src/explore/controlPanels/sections.tsx:127 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:258 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:100 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/orderBy.tsx:48 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:160 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:350 msgid "Whether to sort descending or ascending" msgstr "Сортировка по убыванию или по возрастанию" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/legacySortBy.tsx:31 -#, fuzzy -msgid "" -"Whether to sort descending or ascending. Takes effect only when \"Sort " -"by\" is set" -msgstr "Сортировка по убыванию или по возрастанию" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:75 +msgid "Whether to sort descending or ascending if a series limit is present" +msgstr "" +"Сортировка по убыванию или по возрастанию, если есть ограничение на " +"количество категорий" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:40 -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:39 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:95 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:56 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:40 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:64 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:63 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx:63 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx:119 +msgid "Whether to sort descending or ascending on the X-Axis." +msgstr "Сортировка по убыванию или по возрастанию для оси X" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:44 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:96 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:60 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:65 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:63 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:64 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:62 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:52 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:50 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:39 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:43 msgid "Whether to sort results by the selected metric in descending order." -msgstr "" +msgstr "Сортировка результатов по выбранной мере в порядке убывания" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:175 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:201 msgid "Whether to sort tooltip by the selected metric in descending order." +msgstr "Сортировка выбранных мер по убыванию во всплывающей подсказке" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:352 +msgid "Whether to truncate metrics" msgstr "" +"Убирает меру (например, AVG(...)) с легенды рядом с именем измерения и из" +" таблицы результатов" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:44 msgid "Which country to plot the map for?" -msgstr "" +msgstr "Выбор страны для графика" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:197 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:198 msgid "Which relatives to highlight on hover" -msgstr "" +msgstr "Подсвечивается при наведении" -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:51 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:45 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:88 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:41 msgid "Whisker/outlier options" -msgstr "" +msgstr "Настройки усов/выбросов" #: superset-frontend/src/dashboard/util/backgroundStyleOptions.ts:30 -#, fuzzy msgid "White" -msgstr "Заголовок" +msgstr "Белый" -#: superset-frontend/src/explore/components/EmbedCodeButton.jsx:130 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:228 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:234 msgid "Width" msgstr "Ширина" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:73 -#, fuzzy msgid "Width of the confidence interval. Should be between 0 and 1" -msgstr "Доверительный интервал должен быть между 0 и 1 (исключая)" +msgstr "Ширина доверительного интервала. Должна быть между 0 и 1" -#: superset/utils/pandas_postprocessing.py:393 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:229 +msgid "Width of the sparkline" +msgstr "Ширина спарклайна" + +#: superset/utils/pandas_postprocessing/rolling.py:69 msgid "Window must be > 0" -msgstr "" +msgstr "Окно должно быть > 0" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:36 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:35 msgid "With a subheader" -msgstr "" +msgstr "С подзаголовком" #: superset-frontend/plugins/plugin-chart-word-cloud/src/legacyPlugin/index.ts:29 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:39 msgid "Word Cloud" -msgstr "" +msgstr "Облако слов" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:80 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:84 msgid "Word Rotation" -msgstr "Добавить слой аннотации" +msgstr "Поворот текста" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:55 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:64 msgid "Working" -msgstr "" +msgstr "Обрабатывается" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1258 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:412 msgid "Working timeout" -msgstr "" +msgstr "Время на рассылку" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:33 -#: superset/viz.py:2042 +#: superset/viz.py:2076 msgid "World Map" msgstr "Карта Мира" -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:166 +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:186 msgid "Write a description for your query" msgstr "Заполните описание к вашему запросу" -#: superset/views/database/forms.py:221 superset/views/database/forms.py:354 -#: superset/views/database/forms.py:442 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/index.ts:40 +msgid "Write a handlebars template to render the data" +msgstr "" + +#: superset/views/database/forms.py:219 +msgid "Write dataframe index as a column" +msgstr "Сделать индекс датафрейма столбцом." + +#: superset/views/database/forms.py:380 superset/views/database/forms.py:471 msgid "Write dataframe index as a column." -msgstr "Записывайте индекс данных в виде столбца." +msgstr "Сделать индекс датафрейма столбцом." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:51 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:56 msgid "X AXIS TITLE BOTTOM MARGIN" -msgstr "" +msgstr "Отступ снизу названия оси X" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:31 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:147 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:406 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:36 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:213 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:74 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:69 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:63 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:83 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:107 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:69 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:100 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:84 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:49 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:98 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:73 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:77 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:90 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:298 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:189 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:150 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:130 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:147 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:205 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:208 -#: superset-frontend/src/explore/controls.jsx:421 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:91 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:314 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:178 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:293 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:318 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:165 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:107 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:107 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:162 +#: superset-frontend/src/explore/controls.jsx:401 msgid "X Axis" msgstr "Ось X" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:215 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:235 msgid "X Axis Format" -msgstr "Формат Оси Y" +msgstr "Формат оси X" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:107 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:175 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:93 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:182 msgid "X Axis Label" -msgstr "" +msgstr "Метка оси X" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:37 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:42 msgid "X Axis Title" -msgstr "" +msgstr "Название оси X" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:104 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:105 msgid "X Log Scale" -msgstr "" +msgstr "Логарифмическая ось X" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:201 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:78 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:62 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:216 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:115 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:58 msgid "X Tick Layout" -msgstr "" +msgstr "Расположение делений оси X" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:270 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:290 msgid "X bounds" +msgstr "Показывать границы оси X" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx:117 +msgid "X-Axis Sort Ascending" +msgstr "Сортировать по возрастанию оси X" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx:62 +msgid "X-Axis Sort By" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:114 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/mixins.tsx:35 +msgid "X-axis" +msgstr "Ось X" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:115 msgid "XScale Interval" -msgstr "Интервал обновления" +msgstr "" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:102 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:109 msgid "Y 2 bounds" -msgstr "" +msgstr "Границы оси Y 2" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:79 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:84 msgid "Y AXIS TITLE MARGIN" -msgstr "" +msgstr "Отступ названия оси Y" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:94 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:99 msgid "Y AXIS TITLE POSITION" -msgstr "" +msgstr "Положение названия оси Y" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:59 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:153 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:413 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:64 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:220 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:83 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:79 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:75 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:115 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:54 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:80 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:109 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:241 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:322 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:224 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:186 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:167 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:183 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:240 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:243 -#: superset-frontend/src/explore/controls.jsx:428 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:112 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:116 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:58 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:84 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:110 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:243 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:338 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:213 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:295 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:321 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:200 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:144 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:143 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:197 +#: superset-frontend/src/explore/controls.jsx:408 msgid "Y Axis" msgstr "Ось Y" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:40 msgid "Y Axis 1" -msgstr "" +msgstr "Ось Y 1" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:50 msgid "Y Axis 2" -msgstr "" +msgstr "Ось Y 2" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:254 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:274 msgid "Y Axis 2 Bounds" -msgstr "" +msgstr "Границы оси Y 2" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:238 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:354 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:269 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:232 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:212 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:229 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:285 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:288 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:258 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:370 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:258 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/controlPanel.tsx:245 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:189 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/controlPanel.tsx:189 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:242 msgid "Y Axis Bounds" -msgstr "" +msgstr "Границы оси Y" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:428 -#: superset-frontend/src/explore/controls.jsx:442 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:301 +#: superset-frontend/src/explore/controls.jsx:422 msgid "Y Axis Format" msgstr "Формат Оси Y" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:118 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:333 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:104 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:353 msgid "Y Axis Label" -msgstr "" +msgstr "Метка оси Y" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:88 msgid "Y Axis Left" -msgstr "" +msgstr "Ось Y слева" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:123 msgid "Y Axis Right" -msgstr "" +msgstr "Ось Y справа" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:65 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:70 msgid "Y Axis Title" -msgstr "" +msgstr "Название оси Y" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:227 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:247 msgid "Y Log Scale" -msgstr "" +msgstr "Логарифмическая ось Y" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:91 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:98 msgid "Y bounds" -msgstr "" +msgstr "Показывать границы оси Y" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/mixins.tsx:34 +msgid "Y-axis" +msgstr "Ось Y" + +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:296 +msgid "Y-axis bounds" +msgstr "Границы оси Y" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:130 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:131 #, fuzzy msgid "YScale Interval" msgstr "Интервал обновления" -#: superset/db_engine_specs/base.py:100 -#, fuzzy +#: superset/db_engine_specs/base.py:114 msgid "Year" -msgstr "год" +msgstr "Год" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:70 -#, fuzzy, python-format +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:59 +msgid "Year (freq=AS)" +msgstr "Год (част=AS)" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:85 +msgid "Yearly seasonality" +msgstr "Годовая сезонность" + +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:69 +#, python-format msgid "Years %s" -msgstr "год" +msgstr "Лет %s" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:443 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:537 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:440 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:511 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:88 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:107 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:126 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:144 +#: superset-frontend/src/pages/ChartList/index.tsx:568 +#: superset-frontend/src/pages/ChartList/index.tsx:677 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:461 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:543 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:464 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:484 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:576 msgid "Yes" msgstr "Да" @@ -15001,7 +18174,12 @@ msgstr "Да" msgid "Yes, cancel" msgstr "Да, отменить" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:72 +#: superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.tsx:154 +#: superset-frontend/src/dashboard/components/OverwriteConfirm/OverwriteConfirmModal.tsx:199 +msgid "Yes, overwrite changes" +msgstr "Да, перезаписать изменения" + +#: superset-frontend/src/pages/ChartList/index.tsx:96 msgid "" "You are importing one or more charts that already exist. Overwriting " "might cause you to lose some of your work. Are you sure you want to " @@ -15021,12 +18199,15 @@ msgstr "" "Перезапись может привести к потере части вашей работы. Вы уверены, что " "хотите перезаписать?" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:45 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1221 msgid "" "You are importing one or more databases that already exist. Overwriting " "might cause you to lose some of your work. Are you sure you want to " "overwrite?" msgstr "" +"Вы импортируете одну или несколько баз данных, которые уже существуют. " +"Перезапись может привести к потере части вашей работы. Вы уверены, что " +"хотите перезаписать?" #: superset-frontend/src/views/CRUD/data/dataset/constants.ts:30 msgid "" @@ -15038,425 +18219,608 @@ msgstr "" "Перезапись может привести к потере части вашей работы. Вы уверены, что " "хотите продолжить?" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:63 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:64 msgid "" "You are importing one or more saved queries that already exist. " "Overwriting might cause you to lose some of your work. Are you sure you " "want to overwrite?" msgstr "" -"Вы импортируете один или несколько графиков, которые уже существуют. " -"Перезапись может привести к потере части вашей работы. Вы уверены, что " -"хотите перезаписать?" - -#: superset/views/core.py:2175 -msgid "" -"You are not authorized to fetch samples from this table. If you think " -"this is an error, please reach out to your administrator." -msgstr "" +"Вы импортируете один или несколько сохраненных запросов, которые уже " +"существуют. Перезапись может привести к потере части вашей работы. Вы " +"уверены, что хотите продолжить?" -#: superset/views/core.py:2295 +#: superset/views/core.py:2152 msgid "" "You are not authorized to see this query. If you think this is an error, " "please reach out to your administrator." msgstr "" +"Вы не авторизованы для просмотра этого запроса. Если вы считаете, что это" +" ошибка, пожалуйста, обратитесь к своему администратору" -#: superset/views/database/views.py:463 -#, fuzzy -msgid "" -"You cannot specify a namespace both in the name of the table: " -"\"%(columnar_table.table)s\" and in the schema field: " -"\"%(columnar_table.schema)s\". Please remove one" -msgstr "" -"Нельзя указывать область имён одновременно и в имени таблицы: " -"“%(csv_table.table)s” и в поле схемы: “%(csv_table.schema)s”. Пожалуйста," -" удалите в одном из мест" +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:192 +msgid "You can" +msgstr "Вы можете" + +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:204 +msgid "You can add the components in the" +msgstr "Вы можете добавить компоненты в" + +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:240 +msgid "You can add the components in the edit mode." +msgstr "Вы можете добавить компоненты в режиме редактирования." -#: superset/views/database/views.py:146 +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:195 +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:218 msgid "" -"You cannot specify a namespace both in the name of the table: " -"\"%(csv_table.table)s\" and in the schema field: " -"\"%(csv_table.schema)s\". Please remove one" +"You can create a new chart or use existing ones from the panel on the " +"right" msgstr "" -"Нельзя указывать область имён одновременно и в имени таблицы: " -"“%(csv_table.table)s” и в поле схемы: “%(csv_table.schema)s”. Пожалуйста," -" удалите в одном из мест" +"Вы можете создать новый график или использовать существующие из панели " +"справа" -#: superset/views/database/views.py:293 -msgid "" -"You cannot specify a namespace both in the name of the table: " -"\"%(excel_table.table)s\" and in the schema field: " -"\"%(excel_table.schema)s\". Please remove one" +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:183 +msgid "You can preview the list of dashboards in the chart settings dropdown." msgstr "" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Vis.js:366 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Vis.js:367 msgid "You cannot use 45° tick layout along with the time range filter" msgstr "" +"Вы не можете использовать расположение делений под углом 45° при " +"использовании временного фильтра" -#: superset/viz.py:696 +#: superset/viz.py:720 msgid "" "You cannot use [Columns] in combination with [Group " "By]/[Metrics]/[Percentage Metrics]. Please choose one or the other." msgstr "" -"Нельзя использовать [Столбцы] одновременно с [Группировка " -"по][Показатели][Процентные показатели]. Пожалуйста, выберите что-то одно." +"Вы не можете использовать [Столбцы] в сочетании с [Группировать " +"по]/[Мерами]/[Процентными мерами]. Пожалуйста, выберите одно или другое." + +#: superset-frontend/src/utils/getClientErrorObject.ts:107 +#, fuzzy, python-format +msgid "You do not have permission to edit this %s" +msgstr "У вас нет прав на редактирование этого графика" -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:66 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:69 msgid "You do not have permission to edit this chart" msgstr "У вас нет прав на редактирование этого графика" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:77 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:118 +#: superset-frontend/src/dashboard/actions/dashboardState.js:366 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:115 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:117 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx:48 msgid "You do not have permission to edit this dashboard" -msgstr "У вас нет доступа к этому источнику данных" +msgstr "У вас нет прав на редактирование этого дашборда" #: superset/templates/superset/request_access.html:25 #, python-format msgid "You do not have permissions to access the datasource(s): %(name)s." -msgstr "У вас нет разрешений на доступ к источнику(ам) данных: %(name)s." +msgstr "У вас нет доступа этого источника данных: %(name)s." -#: superset-frontend/src/dashboard/actions/dashboardState.js:133 +#: superset-frontend/src/dashboard/actions/dashboardState.js:154 msgid "You do not have permissions to edit this dashboard." -msgstr "У вас нет прав на редактирование этого дашборда: %(name)s." +msgstr "У вас нет прав на редактирование этого дашборда." + +#: superset/charts/commands/exceptions.py:131 +msgid "You don't have access to this chart." +msgstr "Недостаточно прав для доступа к этому графику." #: superset/dashboards/commands/exceptions.py:86 -#, fuzzy msgid "You don't have access to this dashboard." -msgstr "У вас нет прав на редактирование этого дашборда: %(name)s." +msgstr "Недостаточно прав для доступа к этому дашборду." + +#: superset/datasets/commands/exceptions.py:189 +msgid "You don't have access to this dataset." +msgstr "Недостаточно прав для доступа к этому датасету." -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:144 +#: superset/embedded_dashboard/commands/exceptions.py:34 +msgid "You don't have access to this embedded dashboard config." +msgstr "У вас нет прав на редактирование этого встраиваемого дашборда." + +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:160 msgid "You don't have any favorites yet!" -msgstr "У вас пока нет избранного!" +msgstr "У вас пока нет избранных!" -#: superset/key_value/commands/exceptions.py:45 -#, fuzzy +#: superset/key_value/exceptions.py:54 +#: superset/temporary_cache/commands/exceptions.py:45 msgid "You don't have permission to modify the value." -msgstr "У вас нет прав на редактирование этого графика" +msgstr "Недостаточно прав для редактирования этого значения." + +#: superset/security/manager.py:2219 +#, python-format +msgid "You don't have the rights to alter %(resource)s" +msgstr "Недостаточно прав для изменения %(resource)s" + +#: superset/views/core.py:921 +msgid "You don't have the rights to alter this chart" +msgstr "Недостаточно прав для изменения графика" -#: superset/views/core.py:618 superset/views/core.py:823 -#: superset/views/core.py:829 superset/views/core.py:999 -#: superset/views/core.py:1017 -msgid "You don't have the rights to " -msgstr "У вас нет прав на " +#: superset/views/core.py:1092 +msgid "You don't have the rights to alter this dashboard" +msgstr "Недостаточно прав для изменения дашборда" -#: superset-frontend/src/components/EditableTitle/index.tsx:199 +#: superset-frontend/src/components/EditableTitle/index.tsx:213 msgid "You don't have the rights to alter this title." -msgstr "Недостаточно прав для изменения заголовка." +msgstr "Недостаточно прав для изменения названия." + +#: superset/views/core.py:927 +msgid "You don't have the rights to create a chart" +msgstr "Недостаточно прав для создания графика" + +#: superset/views/core.py:1108 +msgid "You don't have the rights to create a dashboard" +msgstr "Недостаточно прав для создания дашборда" -#: superset/views/core.py:406 +#: superset/views/core.py:642 +msgid "You don't have the rights to download as csv" +msgstr "Недостаточно прав для скачивания в CSV" + +#: superset/views/core.py:422 msgid "You have no permission to approve this request" -msgstr "У вас нет разрешения на утверждение этого запроса" +msgstr "Недостаточно прав для одобрения этого запроса" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/RemovedFilter.tsx:39 msgid "You have removed this filter." msgstr "Вы удалили фильтр." -#: superset-frontend/src/dashboard/components/Dashboard.jsx:88 +#: superset-frontend/src/dashboard/components/Dashboard.jsx:87 msgid "You have unsaved changes." msgstr "У вас есть несохраненные изменения." -#: superset-frontend/src/dashboard/components/SaveModal.tsx:160 +#: superset-frontend/src/dashboard/actions/dashboardState.js:655 +#, python-format +msgid "" +"You have used all %(historyLength)s undo slots and will not be able to " +"fully undo subsequent actions. You may save your current state to reset " +"the history." +msgstr "" + +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:300 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:457 +msgid "" +"You must be a dataset owner in order to edit. Please reach out to a " +"dataset owner to request modifications or edit access." +msgstr "" +"Вы должны быть владельцем датасета для его редактирования. Пожалуйста, " +"обратитесь к владельцу с просьбой предоставить доступ." + +#: superset-frontend/src/dashboard/components/SaveModal.tsx:152 msgid "You must pick a name for the new dashboard" msgstr "Вы должны выбрать имя для нового дашборда" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:518 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:503 msgid "You must run the query successfully first" msgstr "Сначала необходимо успешно выполнить запрос" -#: superset-frontend/src/dashboard/components/Header/index.jsx:382 -#, fuzzy -msgid "Your dashboard is too large. Please reduce its size before saving it." +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/style.tsx:53 +msgid "You need to configure HTML sanitization to use CSS" msgstr "" -"Дашборд слишком большой. Пожалуйста, уменьшите его размер перед " -"сохранением." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:876 -msgid "Your query could not be saved" -msgstr "Ваш запрос не может быть сохранен" +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:349 +msgid "" +"You updated the values in the control panel, but the chart was not " +"updated automatically. Run the query by clicking on the \"Update chart\" " +"button or" +msgstr "" +"Вы обновили значения в панели управления, но график не был обновлен " +"автоматически. Сделайте запрос, нажав на кнопку \"Обновить график\" или" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:166 +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:669 +msgid "" +"You've changed datasets. Any controls with data (columns, metrics) that " +"match this new dataset have been retained." +msgstr "" +"Вы изменили датасеты. Все элементы управления с данными (столбцами, " +"мерами), которые соответствуют новому датасету, были сохранены." + +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:342 +msgid "Your chart is not up to date" +msgstr "Ваш график не актуален" + +#: superset-frontend/src/components/Chart/Chart.jsx:289 +msgid "Your chart is ready to go!" +msgstr "Ваш график готов!" + +#: superset-frontend/src/dashboard/components/Header/index.jsx:409 +msgid "Your dashboard is too large. Please reduce its size before saving it." +msgstr "" +"Дашборд слишком большой. Пожалуйста, уменьшите его размер перед " +"сохранением." + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1010 +msgid "Your query could not be saved" +msgstr "Не удалось сохранить ваш запрос" + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:178 msgid "Your query could not be scheduled" -msgstr "Ваш запрос не может быть сохранен" +msgstr "Не удалось запланировать ваш запрос" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:892 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1045 msgid "Your query could not be updated" -msgstr "Ваш запрос не может быть сохранен" +msgstr "Не удалось обновить ваш запрос" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:159 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:171 msgid "" "Your query has been scheduled. To see details of your query, navigate to " "Saved queries" msgstr "" "Запрос был запланирован. Чтобы посмотреть детали запроса, перейдите в " -"Сохранённые запросы" +"Сохраненные запросы" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:872 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1025 +msgid "Your query was not properly saved" +msgstr "Ваш запрос не был сохранен должным образом" + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1028 msgid "Your query was saved" msgstr "Ваш запрос был сохранен" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:888 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1041 msgid "Your query was updated" msgstr "Ваш запрос был сохранен" -#: superset-frontend/src/reports/actions/reports.js:172 -#, fuzzy +#: superset-frontend/src/reports/actions/reports.js:152 msgid "Your report could not be deleted" -msgstr "График не может быть удалён." +msgstr "Не удается удалить рассылку" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:306 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:185 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:259 +msgid "Zero imputation" +msgstr "Нулевые значения" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:311 msgid "Zoom" -msgstr "" +msgstr "Масштабирование" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:310 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:315 msgid "Zoom level of the map" -msgstr "" - -#: superset/tasks/schedules.py:658 -#, python-format -msgid "[Alert] %(label)s" -msgstr "[Оповещение] %(label)s" +msgstr "Уровень масштабирования карты" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "[С]-" +#: superset-frontend/src/dashboard/actions/dashboardState.js:254 +msgid "[ untitled dashboard ]" +msgstr "[ безымянный дашборд ]" -#: superset/viz.py:2349 +#: superset/viz.py:2383 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" -msgstr "Столбцы [Долгота] и [Широта] должны присутствовать в поле [Группировка]" +msgstr "Столбцы [Долгота] и [Широта] должны присутствовать в [Группировать по]" -#: superset/viz.py:2299 +#: superset/viz.py:2333 msgid "[Longitude] and [Latitude] must be set" -msgstr "Столбцы [Долгота] и [Широта] должны присутствовать в поле [Группировка]" +msgstr "[Долгота] и [Широта] должны быть заданы" -#: superset/views/core.py:783 -#, fuzzy +#: superset/explore/commands/get.py:121 superset/views/core.py:868 msgid "[Missing Dataset]" -msgstr "Выберите источник данных" +msgstr "[отсутствующий датасет]" -#: superset/utils/core.py:864 +#: superset/utils/core.py:907 #, python-format msgid "[Superset] Access to the datasource %(name)s was granted" -msgstr "Доступ к базе данных предоставлен для пользователя — %(name)s" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "[До]-" +msgstr "[Суперсет] Предоставлен доступ к источнику данных %(name)s" -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 -#, fuzzy, python-format +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:87 msgid "[Untitled]" -msgstr "%s - без названия" +msgstr "[Без названия]" + +#: superset/connectors/base/models.py:252 superset/models/sql_lab.py:228 +#, fuzzy +msgid "[asc]" +msgstr "Базовая настройка" + +#: superset-frontend/src/dashboard/components/SaveModal.tsx:84 +#, fuzzy +msgid "[copy]" +msgstr "Копировать" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:203 +#: superset-frontend/src/dashboard/components/SaveModal.tsx:195 msgid "[dashboard name]" -msgstr "[название]" +msgstr "[имя дашборда]" + +#: superset/connectors/base/models.py:255 superset/models/sql_lab.py:231 +msgid "[desc]" +msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:64 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:69 +#: superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx:166 msgid "" "[optional] this secondary metric is used to define the color as a ratio " "against the primary metric. When omitted, the color is categorical and " "based on labels" msgstr "" +"[необязательно] вторичная мера используется для определения цвета как " +"доли по отношению к основной мере. Если не выбрано, цвет задается " +"согласно имени категории" -#: superset/utils/pandas_postprocessing.py:519 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx:265 +msgid "[untitled]" +msgstr "[без названия]" + +#: superset/utils/pandas_postprocessing/compare.py:53 msgid "`compare_columns` must have the same length as `source_columns`." msgstr "" -#: superset/utils/pandas_postprocessing.py:523 +#: superset/utils/pandas_postprocessing/compare.py:57 msgid "`compare_type` must be `difference`, `percentage` or `ratio`" msgstr "" -#: superset/charts/schemas.py:557 +#: superset/charts/schemas.py:567 msgid "`confidence_interval` must be between 0 and 1 (exclusive)" -msgstr "`доверительный_интервал` должен быть между 0 и 1 (исключая)" +msgstr "`доверительный_интервал` должен быть между 0 и 1 (не включая концы)" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:154 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:166 msgid "" "`count` is COUNT(*) if a group by is used. Numerical columns will be " "aggregated with the aggregator. Non-numerical columns will be used to " "label points. Leave empty to get a count of points in each cluster." msgstr "" -#: superset/common/query_object.py:388 +#: superset/common/query_object.py:434 msgid "`operation` property of post processing object undefined" -msgstr "Неопределено свойство `operation` объекта пост-процессинга" +msgstr "" -#: superset/utils/pandas_postprocessing.py:765 -#, fuzzy +#: superset/utils/pandas_postprocessing/prophet.py:61 msgid "`prophet` package not installed" -msgstr "`fbprophet` пакет не установлен" +msgstr "" -#: superset/utils/pandas_postprocessing.py:722 +#: superset/utils/pandas_postprocessing/contribution.py:69 msgid "`rename_columns` must have the same length as `columns`." msgstr "" -#: superset/charts/schemas.py:1070 -#, fuzzy +#: superset/charts/schemas.py:1109 msgid "`row_limit` must be greater than or equal to 0" -msgstr "`лимит_строк` должен быть больше или равен 1" +msgstr "" -#: superset/charts/schemas.py:1077 +#: superset/charts/schemas.py:1116 msgid "`row_offset` must be greater than or equal to 0" -msgstr "`смещение_строк` должно быть больше или равно 0" +msgstr "" -#: superset/charts/schemas.py:932 +#: superset/charts/schemas.py:967 msgid "`width` must be greater or equal to 0" -msgstr "`ширина` должна быть больше, чем 0" +msgstr "" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:413 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:431 msgid "aggregate" -msgstr "агрегат" +msgstr "агрегатная функция" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:90 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:111 msgid "alert" msgstr "оповещение" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:91 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:112 msgid "alerts" -msgstr "оповещения" +msgstr "оповещений" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:213 -msgid "also copy (duplicate) charts" -msgstr "" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:160 +#: superset-frontend/src/components/Chart/DrillDetail/DrillDetailMenuItems.tsx:218 +#: superset-frontend/src/explore/controls.jsx:254 +msgid "all" +msgstr "Все" -#: superset/views/core.py:823 superset/views/core.py:1000 -msgid "alter this " -msgstr "изменить этот " +#: superset-frontend/src/dashboard/components/SaveModal.tsx:205 +msgid "also copy (duplicate) charts" +msgstr "также копировать (дублировать) графики" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:194 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:195 msgid "ancestor" -msgstr "" +msgstr "предок" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:47 msgid "and" -msgstr "" - -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:111 -#, python-format -msgid "and the explore view times out at %s seconds " -msgstr "а тайм-аут интерфейса исследования %s секунд " +msgstr "и" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:64 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:78 #: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:106 msgid "annotation" msgstr "аннотация" -#: superset/views/annotations.py:40 -msgid "annotation start time or end time is required." -msgstr "время начала или окончания аннотации обязательно." - -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:102 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:104 msgid "annotation_layer" msgstr "слой_аннотации" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:373 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:255 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:527 +#: superset-frontend/src/explore/controlPanels/sections.tsx:251 +msgid "asfreq" +msgstr "asfreq (без изменения)" + #: superset-frontend/src/components/CronPicker/CronPicker.tsx:48 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:50 msgid "at" +msgstr "в" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:84 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:203 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:228 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:78 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:196 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:218 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:117 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:53 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:60 +msgid "auto" +msgstr "Автоматически" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:151 +msgid "auto (Smooth)" +msgstr "Автоматически (плавно)" + +#: superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.tsx:76 +msgid "background" +msgstr "" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:124 +#, fuzzy +msgid "basis" +msgstr "Акцент" + +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:69 +msgid "below (example:" +msgstr "ниже (пример:" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/vendor/cal-heatmap.js:260 +msgid "between {down} and {up} {name}" msgstr "" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:374 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:256 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:528 +#: superset-frontend/src/explore/controlPanels/sections.tsx:252 +msgid "bfill" +msgstr "bfill (заполняет пропуски предыдущими значениями)" + #: superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx:74 -#: superset-frontend/src/explore/components/ControlHeader.jsx:76 +#: superset-frontend/src/explore/components/ControlHeader.tsx:122 msgid "bolt" msgstr "" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:161 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:179 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:63 +msgid "boolean type icon" +msgstr "" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:162 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:180 msgid "bottom" -msgstr "dttm" +msgstr "снизу" -#: superset-frontend/src/components/CachedLabel/index.tsx:51 -msgid "cached" -msgstr "" +#: superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx:232 +msgid "button (cmd + z) until you save your changes." +msgstr "(CTRL + Z), пока вы не сохраните изменения." + +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:72 +msgid "by using" +msgstr ", используя" #: superset-frontend/packages/superset-ui-core/src/validator/validateNonEmpty.ts:29 msgid "cannot be empty" -msgstr "" +msgstr "Необходимо заполнить" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:143 -msgid "" -"cannot be used as a column name. The column name/alias \"__timestamp\"\n" -" is reserved for the main temporal expression, and column " -"aliases ending with\n" -" double underscores followed by a numeric value (e.g. " -"\"my_col__1\") are reserved\n" -" for deduplicating duplicate column names. Please use aliases to" -" rename the\n" -" invalid column names." -msgstr "" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:125 +#, fuzzy +msgid "cardinal" +msgstr "Ошибка" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:146 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:699 -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:81 -#: superset/views/core.py:823 superset/views/core.py:829 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:87 +#, fuzzy +msgid "change" +msgstr "изменение" + +#: superset-frontend/src/pages/ChartList/index.tsx:183 +#: superset-frontend/src/pages/ChartList/index.tsx:851 +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:89 msgid "chart" msgstr "график" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:26 -#, fuzzy +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:27 msgid "charts" -msgstr "график" +msgstr "графики(ов)" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:101 msgid "choose WHERE or HAVING..." -msgstr "выберите WHERE или HAVING…" +msgstr "выберите WHERE или HAVING..." + +#: superset-frontend/src/components/ListView/ListView.tsx:412 +msgid "clear all filters" +msgstr "Сбросить все фильтры" + +#: superset-frontend/src/components/Chart/Chart.jsx:296 +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:353 +msgid "click here" +msgstr "нажмите сюда" + +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:46 +msgid "code ISO 3166-1 alpha-2 (cca2)" +msgstr "Код ISO 3166-1 alpha-2 (cca2)" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:402 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:47 +msgid "code ISO 3166-1 alpha-3 (cca3)" +msgstr "Код ISO 3166-1 alpha-3 (cca3)" + +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:45 +msgid "code International Olympic Committee (cioc)" +msgstr "Код Международного Олимпийского Комитета (cioc)" + +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:420 msgid "column" msgstr "столбец" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:116 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:152 +#, python-format +msgid "connecting to %(dbModelName)s." +msgstr "подключении к %(dbModelName)s" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:117 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:79 msgid "count" -msgstr "столбец" +msgstr "количество" + +#: superset-frontend/src/explore/components/SaveModal.tsx:355 +msgid "create" +msgstr "создать" -#: superset/views/core.py:829 superset/views/core.py:1018 -msgid "create a " -msgstr "создать " +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:198 +msgid "create a new chart" +msgstr "создать новый график" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:253 +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/DatasetPanel/MessageContent.tsx:45 +msgid "create dataset from SQL query" +msgstr "создайте датасет из SQL запроса" + +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:251 msgid "css" -msgstr "Css" +msgstr "css" #: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:91 msgid "css_template" msgstr "шаблон_css" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:120 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:257 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:139 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:406 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:186 +#: superset-frontend/src/explore/controlPanels/sections.tsx:138 +msgid "cumsum" +msgstr "Кумулятивная сумма" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:121 msgid "cumulative" -msgstr "Действия" +msgstr "кумулятивно" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:115 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:678 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:77 -#: superset/views/core.py:1001 superset/views/core.py:1019 +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx:115 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:121 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:717 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:75 msgid "dashboard" msgstr "дашборд" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:27 -#, fuzzy +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:28 msgid "dashboards" -msgstr "дашборд" +msgstr "дашборды(ов)" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:89 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:471 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:464 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:91 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:537 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:665 msgid "database" msgstr "база данных" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:116 -#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:61 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:123 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:699 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:117 +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:75 +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/Footer/index.tsx:60 +#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:71 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:153 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:850 msgid "dataset" msgstr "датасет" -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:304 +#: superset-frontend/src/views/CRUD/data/dataset/AddDataset/Header/index.tsx:83 +msgid "dataset name" +msgstr "Имя датасета" + +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:303 msgid "date" msgstr "дата" +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:44 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:61 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:39 msgid "day" msgstr "день" @@ -15469,74 +18833,167 @@ msgstr "день месяца" msgid "day of the week" msgstr "день недели" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:30 +msgid "deck.gl 3D Hexagon" +msgstr "deck.gl 3D Шестигранники" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:30 +msgid "deck.gl Arc" +msgstr "deck.gl Дуга" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:30 +msgid "deck.gl Geojson" +msgstr "deck.gl GeoJSON" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:30 +msgid "deck.gl Grid" +msgstr "deck.gl Сетка" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/index.js:28 +msgid "deck.gl Multiple Layers" +msgstr "deck.gl Многослойный" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/index.js:28 +#, fuzzy +msgid "deck.gl Path" +msgstr "" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:30 +msgid "deck.gl Polygon" +msgstr "deck.gl Полигон" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:30 +msgid "deck.gl Scatterplot" +msgstr "deck.gl Точечная карта" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:30 +#, fuzzy +msgid "deck.gl Screen Grid" +msgstr "deck.gl Screen Grid" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:37 +#, fuzzy +msgid "deck.gl charts" +msgstr "" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:34 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:34 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:34 +msgid "deckGL" +msgstr "Карта deckGL" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:87 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:106 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:125 +msgid "default" +msgstr "по умолчанию" + #: superset-frontend/src/components/DeleteModal/index.tsx:84 msgid "delete" msgstr "удалить" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:195 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:196 msgid "descendant" -msgstr "Сортировать" +msgstr "потомок" #: superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx:64 -#: superset-frontend/src/explore/components/ControlHeader.jsx:66 #: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:327 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:258 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:262 msgid "description" msgstr "описание" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:71 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:81 +#, fuzzy +msgid "deviation" +msgstr "Продолжительность" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:86 msgid "dialect+driver://username:password@host:port/database" msgstr "диалект+драйвер://пользователь:пароль@хост:порт/схема" -#: superset/views/core.py:618 -#, fuzzy -msgid "download as csv" -msgstr "Сохранить как изображение" - -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:153 -#, fuzzy +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:152 msgid "draft" -msgstr "Черновик" +msgstr "черновик" #: superset/views/log/__init__.py:32 msgid "dttm" -msgstr "dttm" +msgstr "Дата/время" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:129 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:153 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:174 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:190 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:238 msgid "e.g. ********" -msgstr "" +msgstr "например, ********" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:45 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:111 msgid "e.g. 127.0.0.1" -msgstr "" +msgstr "например, 127.0.0.1" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:67 msgid "e.g. 5432" +msgstr "например, 5432" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx:36 +msgid "e.g. AccountAdmin" msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:108 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:132 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SSHTunnelForm.tsx:143 msgid "e.g. Analytics" -msgstr "Расширенный анализ" +msgstr "например, Analytics" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:172 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx:32 +msgid "e.g. compute_wh" +msgstr "" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:217 msgid "e.g. param1=value1¶m2=value2" +msgstr "например, параметр1=значение1&параметр2=значение2" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:90 +msgid "e.g. sql/protocolv1/o/12345" msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:88 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:112 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx:29 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:630 msgid "e.g. world_population" +msgstr "например, health_medicine" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:628 +msgid "e.g. xy12345.us-east-2.aws" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:126 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:125 msgid "e.g., a \"user id\" column" -msgstr "Столбцы Временных Рядов" +msgstr "например, столбец \"идентификатор пользователя\"" + +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:210 +msgid "edit mode" +msgstr "режиме редактирования" + +#: superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx:58 +#, fuzzy +msgid "entries" +msgstr "категории" + +#: superset/connectors/sqla/models.py:1510 superset/models/helpers.py:1727 +#, fuzzy +msgid "error_message" +msgstr "Сообщение об ошибке" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:27 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:35 msgid "every" -msgstr "каждый" +msgstr "каждые" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:29 msgid "every day of the month" @@ -15551,58 +19008,101 @@ msgid "every hour" msgstr "каждый час" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:34 -#, fuzzy msgid "every minute" -msgstr "месяц" +msgstr "каждая минута" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:28 msgid "every month" -msgstr "месяц" +msgstr "каждый месяц" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:123 -msgid "feature to store a summarized data set that you can then explore." -msgstr "" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:57 +#: superset-frontend/src/explore/fixtures.tsx:63 +msgid "expand" +msgstr "развернуть" + +#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx:89 +#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx:47 +msgid "explore" +msgstr "исследовать" + +#: superset-frontend/src/SqlLab/constants.ts:33 +#: superset-frontend/src/SqlLab/constants.ts:51 +#, fuzzy +msgid "failed" +msgstr "Ошибка" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:87 +#: superset-frontend/src/SqlLab/constants.ts:35 #, fuzzy msgid "fetching" -msgstr "Настройки" +msgstr "Получение данных" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:375 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:257 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:529 +#: superset-frontend/src/explore/controlPanels/sections.tsx:253 +msgid "ffill" +msgstr "ffill (заполняет пропуски следующими значениями)" #: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:86 -#: superset-frontend/src/dashboard/containers/DashboardPage.tsx:143 +#: superset-frontend/src/dashboard/containers/DashboardPage.tsx:262 msgid "" "filter_box will be deprecated in a future version of Superset. Please " "replace filter_box by dashboard filter components." msgstr "" +"filter_box устарел и будет удален в будущей версии Суперсета. Пожалуйста," +" замените его фильтрами в левой панели дашборда." -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:115 -msgid "following this flow will most likely lead to your query timing out. " +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:219 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:118 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:87 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:61 +msgid "flat" msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:86 -#, fuzzy +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:101 msgid "for more information on how to structure your URI." msgstr " за подробной информацией по тому, как структурировать ваш URI" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:41 -msgid "green" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:57 +msgid "function type icon" msgstr "" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:724 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1136 -#, fuzzy +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:352 +msgid "geohash (square)" +msgstr "" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:42 +msgid "green" +msgstr "Зеленая" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:168 +msgid "heatmap" +msgstr "тепловая карта" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:184 +msgid "heatmap: values are normalized across the entire heatmap" +msgstr "тепловая карта: значения нормализованы внутри всей карты" + +#: superset-frontend/src/components/EmptyState/index.tsx:237 +#: superset-frontend/src/components/ImportModal/ErrorAlert.tsx:60 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:123 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ModalHeader.tsx:106 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:925 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1644 msgid "here" -msgstr "Поделиться" +msgstr "здесь" +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:60 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:40 msgid "hour" msgstr "час" -#: superset-frontend/src/profile/components/UserInfo.tsx:75 -msgid "id:" -msgstr "идентификатор:" +#: superset-frontend/src/profile/components/UserInfo.tsx:76 +msgid "id" +msgstr "идентификатор" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:153 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:154 msgid "" "image-rendering CSS attribute of the canvas object that defines how the " "browser scales up the image" @@ -15612,280 +19112,571 @@ msgstr "" msgid "in" msgstr "в" -#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:122 +#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:145 msgid "in modal" -msgstr "" +msgstr "в модальном окне" #: superset-frontend/packages/superset-ui-core/src/validator/legacyValidateNumber.ts:28 #: superset-frontend/packages/superset-ui-core/src/validator/validateNumber.ts:32 msgid "is expected to be a number" -msgstr "" +msgstr "Ожидается число" #: superset-frontend/packages/superset-ui-core/src/validator/legacyValidateInteger.ts:31 #: superset-frontend/packages/superset-ui-core/src/validator/validateInteger.ts:32 msgid "is expected to be an integer" -msgstr "" +msgstr "Ожидается целое число" #: superset-frontend/src/profile/components/UserInfo.tsx:64 msgid "joined" -msgstr "присоединился" +msgstr "Присоединился" -#: superset/views/base.py:527 +#: superset/views/base.py:591 msgid "json isn't valid" -msgstr "json не валиден" +msgstr "JSON не валиден" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:233 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:261 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:298 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:326 msgid "key a-z" -msgstr "" +msgstr "По алфавиту А-Я" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:234 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:262 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:299 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:327 msgid "key z-a" -msgstr "" +msgstr "По алфавиту Я-А" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:152 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:164 msgid "label" -msgstr "Метка" +msgstr "метка" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:39 -#, fuzzy msgid "last day" -msgstr "Суббота" +msgstr "последний день" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:41 -#, fuzzy msgid "last month" -msgstr "месяц" +msgstr "последний месяц" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:42 msgid "last quarter" -msgstr "" +msgstr "последний квартал" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:40 -#, fuzzy msgid "last week" -msgstr "Последняя неделя" +msgstr "последняя неделя" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:43 -#, fuzzy msgid "last year" -msgstr "Кластер" +msgstr "последний год" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:120 +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:153 msgid "latest partition:" msgstr "последний раздел:" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:158 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:176 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:159 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:177 msgid "left" -msgstr "оповещение" +msgstr "слева" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:63 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/vendor/cal-heatmap.js:259 +msgid "less than {min} {name}" +msgstr "" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:123 +#, fuzzy +msgid "linear" +msgstr "" + +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:66 msgid "log" msgstr "журнал" -#: superset/charts/schemas.py:624 +#: superset/charts/schemas.py:639 msgid "" "lower percentile must be greater than 0 and less than 100. Must be lower " "than upper percentile." -msgstr "нижний процентиль должен быть больше 0 и меньше верхнего процентиля." +msgstr "" +"Нижний процентиль должен быть больше 0 и меньше 100. Должен быть ниже " +"верхнего процентиля" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:189 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:58 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:76 +#: superset-frontend/src/filters/components/Range/buildQuery.ts:69 +msgid "max" +msgstr "Максимум" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:187 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:254 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:377 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:56 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:136 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:259 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:77 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:403 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:531 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:183 +#: superset-frontend/src/explore/controlPanels/sections.tsx:135 +#: superset-frontend/src/explore/controlPanels/sections.tsx:255 +msgid "mean" +msgstr "Среднее" + +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:376 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:258 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:78 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:530 +#: superset-frontend/src/explore/controlPanels/sections.tsx:254 +msgid "median" +msgstr "Медиана" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx:59 +#: superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx:136 +msgid "metric" +msgstr "мера" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:59 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:188 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:57 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:75 +#: superset-frontend/src/filters/components/Range/buildQuery.ts:58 +msgid "min" +msgstr "Минимум" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:41 msgid "minute" msgstr "минута" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:51 -#, fuzzy msgid "minute(s)" -msgstr "5 минут" +msgstr "минут" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:126 +#, fuzzy +msgid "monotone" +msgstr "Гладкая линия" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:173 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:46 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:63 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:37 +#: superset-frontend/src/explore/controls.jsx:267 msgid "month" msgstr "месяц" +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/vendor/cal-heatmap.js:261 +msgid "more than {max} {name}" +msgstr "" + +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:53 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:78 #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:116 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:138 msgid "must have a value" +msgstr "значение обязательно" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/Polygon.jsx:63 +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:73 +msgid "name" +msgstr "имя" + +#: superset/databases/commands/exceptions.py:147 +msgid "no SQL validator is configured" +msgstr "не настроен ни один SQL валидатор" + +#: superset/databases/commands/validate_sql.py:101 +msgid "no SQL validator is configured for {}" +msgstr "не настроен ни один SQL валидатор для {}" + +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:61 +msgid "numeric type icon" msgstr "" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:54 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:39 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:34 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:49 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:46 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:41 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:55 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:33 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:34 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:36 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 msgid "nvd3" -msgstr "" +msgstr "Графики nvd3" + +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/Sunburst.js:388 +#, fuzzy +msgid "of parent" +msgstr "Родитель" + +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/Sunburst.js:386 +#, fuzzy +msgid "of total" +msgstr "Показывать общий итог" + +#: superset-frontend/src/SqlLab/constants.ts:32 +#: superset-frontend/src/SqlLab/constants.ts:53 +#, fuzzy +msgid "offline" +msgstr "Оффлайн" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:45 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:46 msgid "on" -msgstr "" +msgstr "по" + +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:200 +msgid "or use existing ones from the panel on the right" +msgstr "или использовать уже существующие из панели справа" -#: superset/charts/schemas.py:1098 +#: superset/charts/schemas.py:1138 #, fuzzy msgid "orderby column must be populated" msgstr "Ваш запрос не может быть сохранен" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:85 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:86 +#, fuzzy +msgid "overall" +msgstr "Сбросить фильтры" + +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:77 msgid "p-value precision" -msgstr "" +msgstr "точность p-значения" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:82 +msgid "p1" +msgstr "p1" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:83 +msgid "p5" +msgstr "p5" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:84 +msgid "p95" +msgstr "p95" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:85 +msgid "p99" +msgstr "p99" + +#: superset-frontend/plugins/plugin-chart-handlebars/src/consts.ts:24 #: superset-frontend/plugins/plugin-chart-table/src/consts.ts:26 msgid "page_size.all" msgstr "" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:159 +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:195 msgid "page_size.entries" msgstr "" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:139 +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:175 msgid "page_size.show" msgstr "" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:124 +#: superset-frontend/src/SqlLab/constants.ts:34 +#: superset-frontend/src/SqlLab/constants.ts:54 +#, fuzzy +msgid "pending" +msgstr "Отрисовка" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:125 msgid "percentile (exclusive)" -msgstr "" +msgstr "перцентиль (исключая)" -#: superset/utils/pandas_postprocessing.py:921 +#: superset/utils/pandas_postprocessing/boxplot.py:88 msgid "" "percentiles must be a list or tuple with two numeric values, of which the" " first is lower than the second value" msgstr "" -"процентили должны быть списками из кортежами из двух числовых значений, в" -" которых первое значение меньше второго" + +#: superset/views/core.py:1900 +msgid "permalink state not found" +msgstr "" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:150 +msgid "pixelated (Sharp)" +msgstr "" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:53 msgid "previous calendar month" -msgstr "" +msgstr "предыдущий календарный месяц" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:50 msgid "previous calendar week" -msgstr "" +msgstr "предыдущая календарная неделя" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:56 +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:55 msgid "previous calendar year" -msgstr "" +msgstr "предыдущий календарный год" -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:153 -#, fuzzy +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:152 msgid "published" -msgstr "Неопубликованные" +msgstr "опубликовано" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:543 -#, fuzzy +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:174 +#: superset-frontend/src/explore/controls.jsx:268 +msgid "quarter" +msgstr "Квартал" + +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:547 msgid "queries" -msgstr "Ряд данных" +msgstr "запросы" -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:129 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:131 msgid "query" msgstr "запрос" +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:86 +msgid "random" +msgstr "случайно" + #: superset-frontend/src/components/CronPicker/CronPicker.tsx:42 msgid "reboot" -msgstr "" +msgstr "обновить" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:28 -#, fuzzy +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:76 +msgid "recent" +msgstr "недавние" + +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:29 msgid "recents" -msgstr "Последние" +msgstr "недавние(их)" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:43 -#, fuzzy +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:44 msgid "red" -msgstr "Создано" +msgstr "Красная" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:90 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:484 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:111 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:544 msgid "report" msgstr "рассылка" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:91 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:117 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:126 -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:72 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:112 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:139 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:148 +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:75 msgid "reports" msgstr "рассылки" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:160 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:178 -#, fuzzy -msgid "right" -msgstr "Высота" - -#: superset-frontend/src/explore/components/RowCountLabel.jsx:35 -msgid "rows" -msgstr "строк" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts:432 +msgid "restore zoom" +msgstr "восстановить масштабирование" -#: superset-frontend/src/explore/components/DataTableControl/index.tsx:96 -msgid "rows retrieved" -msgstr "строк получено" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:161 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:179 +msgid "right" +msgstr "справа" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:29 +#: superset-frontend/src/SqlLab/constants.ts:36 +#: superset-frontend/src/SqlLab/constants.ts:52 #, fuzzy +msgid "running" +msgstr "Выполняется" + +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:30 msgid "saved queries" -msgstr "Сохраненные запросы" +msgstr "сохраненные(ых) запросы(ов)" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:124 -msgid "search.num_records" -msgstr "" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:414 +msgid "seconds" +msgstr "секунд" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:98 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:85 +msgid "series" +msgstr "категории" + +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:90 msgid "" "series: Treat each series independently; overall: All series use the same" " scale; change: Show changes compared to the first data point in each " "series" msgstr "" -#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:92 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:88 +#, fuzzy +msgid "square" +msgstr "последний квартал" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:55 +#: superset-frontend/src/explore/fixtures.tsx:61 +#, fuzzy +msgid "stack" +msgstr "С наполнением" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:221 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:121 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:63 +#, fuzzy +msgid "staggered" +msgstr "Запущен" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:190 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:256 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:59 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:138 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:405 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:185 +#: superset-frontend/src/explore/controlPanels/sections.tsx:137 +msgid "std" +msgstr "Стандартное отклонение" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:128 +msgid "step-after" +msgstr "" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:127 +msgid "step-before" +msgstr "" + +#: superset-frontend/src/SqlLab/constants.ts:37 +#, fuzzy +msgid "stopped" +msgstr "Добавить" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:56 +#: superset-frontend/src/explore/fixtures.tsx:62 +msgid "stream" +msgstr "поток" + +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:59 +msgid "string type icon" +msgstr "" + +#: superset-frontend/src/SqlLab/constants.ts:38 +#: superset-frontend/src/SqlLab/constants.ts:50 +#, fuzzy +msgid "success" +msgstr "Успешно" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:186 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:255 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:378 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:55 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:137 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:260 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:74 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:404 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:532 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:184 +#: superset-frontend/src/explore/controlPanels/sections.tsx:136 +#: superset-frontend/src/explore/controlPanels/sections.tsx:256 +msgid "sum" +msgstr "Сумма" + +# Не нужно переводить +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:80 +msgid "syntax." +msgstr "" + +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:65 +msgid "temporal type icon" +msgstr "" + +#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:115 msgid "textarea" msgstr "текстовая область" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:159 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:177 -#, fuzzy +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:114 +msgid "to" +msgstr "по" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:160 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:178 msgid "top" -msgstr "Стоп" +msgstr "сверху" -#: superset/charts/schemas.py:639 +#: superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx:231 +msgid "undo" +msgstr "отмены" + +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:53 +msgid "unknown type icon" +msgstr "" + +#: superset/charts/schemas.py:654 msgid "" "upper percentile must be greater than 0 and less than 100. Must be higher" " than lower percentile." -msgstr "верхний процентиль должен быть больше нижнего процентиля и меньше 100." +msgstr "" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:235 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:263 +#: superset-frontend/src/explore/constants.ts:85 #, fuzzy +msgid "use latest_partition template" +msgstr "последний раздел:" + +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:300 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:328 msgid "value ascending" -msgstr "Направление сортировки" +msgstr "Значение по возрастанию" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:236 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:264 -#, fuzzy +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:301 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:329 msgid "value descending" -msgstr "Сортировать" +msgstr "Значение по убыванию" + +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:191 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:60 +msgid "var" +msgstr "Дисперсия" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:80 +msgid "variance" +msgstr "Дисперсия" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:857 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1042 msgid "virtual" -msgstr "" +msgstr "Виртуальный" + +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:74 +msgid "viz type" +msgstr "тип визуализации" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:715 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:455 msgid "was created" -msgstr "создан" +msgstr "создан(а)" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:170 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:62 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:38 +#: superset-frontend/src/explore/controls.jsx:264 msgid "week" msgstr "неделя" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:172 +#: superset-frontend/src/explore/controls.jsx:266 +msgid "week ending Saturday" +msgstr "неделя, заканчивающаяся в субботу" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:171 +#: superset-frontend/src/explore/controls.jsx:265 +msgid "week starting Sunday" +msgstr "неделя, начинающаяся в воскресенье" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:169 +msgid "x" +msgstr "x" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:181 +msgid "x: values are normalized within each column" +msgstr "x: значения нормализованы внутри каждого столбца" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:170 +msgid "y" +msgstr "y" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:182 +msgid "y: values are normalized within each row" +msgstr "y: значения нормализованы внутри каждой строки" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx:175 +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:47 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:36 +#: superset-frontend/src/explore/controls.jsx:269 msgid "year" msgstr "год" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:42 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:43 msgid "yellow" -msgstr "" +msgstr "Желтая" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts:431 +msgid "zoom area" +msgstr "область масштабирования" diff --git a/superset/translations/sk/LC_MESSAGES/messages.po b/superset/translations/sk/LC_MESSAGES/messages.po index 6429587f83a59..9e8eea66a469c 100644 --- a/superset/translations/sk/LC_MESSAGES/messages.po +++ b/superset/translations/sk/LC_MESSAGES/messages.po @@ -1141,10 +1141,6 @@ msgstr "" msgid "An error occurred saving dataset" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "" - #: superset/key_value/commands/exceptions.py:33 msgid "An error occurred while accessing the value." msgstr "" @@ -5538,18 +5534,6 @@ msgstr "" msgid "Filter box" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "" @@ -5710,7 +5694,7 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." msgstr "" @@ -6362,7 +6346,6 @@ msgstr "" msgid "Issue 1001 - The database is under an unusual load." msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -8906,10 +8889,6 @@ msgstr "" msgid "Query preview" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 msgid "Query was stopped" msgstr "" @@ -9906,7 +9885,6 @@ msgid "Scoping" msgstr "" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -11760,7 +11738,7 @@ msgstr "" #: superset/views/core.py:2280 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" @@ -14304,10 +14282,6 @@ msgstr "" msgid "[Alert] %(label)s" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "" @@ -14325,10 +14299,6 @@ msgstr "" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 msgid "[Untitled]" msgstr "" diff --git a/superset/translations/sl/LC_MESSAGES/messages.json b/superset/translations/sl/LC_MESSAGES/messages.json index ab5e2067a7101..ca9a838bf28df 100644 --- a/superset/translations/sl/LC_MESSAGES/messages.json +++ b/superset/translations/sl/LC_MESSAGES/messages.json @@ -110,6 +110,9 @@ "Na delavcu ni bilo mogoče zagnati oddaljene poizvedbe." ], "The database was deleted.": ["Podatkovna baza je bila izbrisana."], + "Custom SQL fields cannot contain sub-queries.": [ + "Prilagojena SQL-polja ne smejo vsebovati podpoizvedb." + ], "Invalid certificate": ["Neveljaven certifikat"], "Unsafe return type for function %(func)s: %(value_type)s": [ "Nevaren tip rezultata, ki ga vrne funkcija %(func)s: %(value_type)s" @@ -274,6 +277,9 @@ "Časovna vrsta - Nightingale Rose grafikon" ], "Partition Diagram": ["Grafikon s pravokotniki"], + "Invalid advanced data type: %(advanced_data_type)s": [ + "Neveljaven napreden tip rezultata: %(advanced_data_type)s" + ], "Deleted %(num)d annotation layer": [ "Izbrisan je %(num)d sloj z oznakami", "Izbrisana sta %(num)d sloja z oznakami", @@ -323,6 +329,7 @@ "Izbrisani so %(num)d grafikoni", "Izbrisanih je %(num)d grafikonov" ], + "Is certified": ["Certificiran"], "`confidence_interval` must be between 0 and 1 (exclusive)": [ "`confidence_interval` mora biti med 0 in 1 (odprt)" ], @@ -368,6 +375,9 @@ "There are associated alerts or reports": [ "Prisotna so povezana opozorila in poročila" ], + "You don't have access to this chart.": [ + "Nimate dostopa do tega grafikona." + ], "Changing this chart is forbidden": [ "Spreminjanje tega grafikona ni dovoljeno" ], @@ -380,9 +390,12 @@ ], "Request is incorrect: %(error)s": ["Zahtevek je napačen: %(error)s"], "Request is not JSON": ["Zahtevek ni JSON"], + "Empty query result": ["Rezultat prazne poizvedbe"], "Owners are invalid": ["Lastniki niso veljavni"], "Some roles do not exist": ["Nekatere vloge ne obstajajo"], - "Dataset does not exist": ["Podatkovni set ne obstaja"], + "Datasource type is invalid": ["Neveljaven tip podatkovnega vira"], + "Datasource does not exist": ["Podatkovni vir ne obstaja"], + "Query does not exist": ["Poizvedba ne obstaja"], "Invalid result type: %(result_type)s": [ "Neveljaven tip rezultata: %(result_type)s" ], @@ -402,89 +415,6 @@ "Datasource id not found: %(id)s": [ "ID podatkovnega vira ni bil najden: %(id)s" ], - "Adding new datasource [{}]": ["Dodajanje novega podatkovnega vira [{}]"], - "Refreshing datasource [{}]": ["Osveževanje podatkovnega vira [{}]"], - "Metric(s) {} must be aggregations.": ["Mere {} morajo biti agregacije."], - "Unsupported extraction function: ": [ - "Nepodprta ekstrakcijska funkcija: " - ], - "Columns": ["Stolpci"], - "Show Druid Column": ["Pokaži Druid stolpec"], - "Add Druid Column": ["Dodaj Druid stolpec"], - "Edit Druid Column": ["Uredi Druid stolpec"], - "Column": ["Stolpec"], - "Type": ["Tip"], - "Datasource": ["Podatkovni vir"], - "Groupable": ["Združevanje"], - "Filterable": ["Filtriranje"], - "Whether this column is exposed in the `Filters` section of the explore view.": [ - "Če želite, da je ta stolpec na voljo v sekciji `Filtri` v raziskovalnem pogledu." - ], - "Metrics": ["Mere"], - "Show Druid Metric": ["Prikaži Druid mere"], - "Add Druid Metric": ["Dodaj Druid mere"], - "Edit Druid Metric": ["Uredi Druid mere"], - "Metric": ["Mera"], - "Description": ["Opis"], - "Verbose Name": ["Podrobno ime"], - "JSON": ["JSON"], - "Druid Datasource": ["Podatkovni vir Druid"], - "Warning Message": ["Opozorilo"], - "Druid Clusters": ["Druid gruče"], - "Show Druid Cluster": ["Pokaži Druid gručo"], - "Add Druid Cluster": ["Dodaj Druid gručo"], - "Edit Druid Cluster": ["Uredi Druid gručo"], - "Cluster Name": ["Ime gruče"], - "Broker Host": ["Gostitelj posrednika"], - "Broker Port": ["Vrata posrednika"], - "Broker Username": ["Uporabniško ime posrednika"], - "Broker Password": ["Geslo posrednika"], - "Broker Endpoint": ["Končna točka posrednika"], - "Cache Timeout": ["Trajanje predpomnilnika"], - "Metadata Last Refreshed": ["Meta-podatki nazadnje osveženi"], - "Duration (in seconds) of the caching timeout for this cluster. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.": [ - "Trajanje (v sekundah) predpomnjenja za to gručo. Vrednost 0 označuje, da predpomnilnik nikoli ne poteče. V primeru, da ni definirano, ima globalno nastavitev trajanja." - ], - "Druid supports basic authentication. See [auth](http://druid.io/docs/latest/design/auth.html) and druid-basic-security extension": [ - "Druid podpira osnovno avtentikacijo. Glejte [auth](http://druid.io/docs/latest/design/auth.html) in razširitev druid-basic-security" - ], - "Druid Datasources": ["Druid podatkovni viri"], - "Show Druid Datasource": ["Prikaži podatkovni vir za Druid"], - "Add Druid Datasource": ["Dodaj podatkovni vir za Druid"], - "Edit Druid Datasource": ["Uredi podatkovni vir za Druid"], - "The list of charts associated with this table. By altering this datasource, you may change how these associated charts behave. Also note that charts need to point to a datasource, so this form will fail at saving if removing charts from a datasource. If you want to change the datasource for a chart, overwrite the chart from the 'explore view'": [ - "Seznam grafikonov, povezanih s to tabelo. S spreminjanjem podatkovnega vira lahko spremenite, kako se povezani grafikoni obnašajo. Poleg tega morajo biti grafikoni povezani s podatkovnim virom. Če odstranite grafikon s podatkovnega vira ne bo mogoče shraniti tega vnosa. Če želite spremeniti podatkovni vir grafikona, prepišite grafikon v raziskovalnem pogledu." - ], - "Timezone offset (in hours) for this datasource": [ - "Razlika časovnega pasu (v urah) za ta podatkovni vir" - ], - "Time expression to use as a predicate when retrieving distinct values to populate the filter component. Only applies when `Enable Filter Select` is on. If you enter `7 days ago`, the distinct list of values in the filter will be populated based on the distinct value over the past week": [ - "Prednastavljeni časovni izraz za pridobitev različnih vrednosti filtrirne komponente. Upošteva se le v primeru, da je vključeno `Omogoči izbiro filtra`. Če vnesete `7 days ago`, bo seznam vrednosti filtra napolnjen na podlagi različnih vrednosti v prejšnjem tednu" - ], - "Whether to populate the filter's dropdown in the explore view's filter section with a list of distinct values fetched from the backend on the fly": [ - "Če želite napolniti spustni seznam filtra v raziskovalnem pogledu filtrske sekcije z različnimi vrednostmi, pridobljenimi sproti v ozadju" - ], - "Redirects to this endpoint when clicking on the datasource from the datasource list": [ - "Preusmeri v to končno točko, ko kliknete na podatkovni vir v seznamu podatkovnih virov" - ], - "Duration (in seconds) of the caching timeout for this datasource. A timeout of 0 indicates that the cache never expires. Note this defaults to the cluster timeout if undefined.": [ - "Trajanje (v sekundah) predpomnjenja za ta podatkovni vir. Vrednost 0 označuje, da predpomnilnik nikoli ne poteče. V primeru, da ni definirano, ima nastavitev trajanja za gručo." - ], - "Associated Charts": ["Povezani grafikoni"], - "Data Source": ["Podatkovni vir"], - "Cluster": ["Gruča"], - "Owners": ["Lastniki"], - "Is Hidden": ["Skrito"], - "Enable Filter Select": ["Omogoči izbiro filtra"], - "Default Endpoint": ["Privzeta končna točka"], - "Time Offset": ["Časovni zamik"], - "Datasource Name": ["Ime podatkovnega vira"], - "Fetch Values From": ["Pridobi vrednosti iz"], - "Changed By": ["Spremenil"], - "Modified": ["Spremenjeno"], - "Refreshed metadata from cluster [{}]": [ - "Osveženi meta-podatki iz gruče [{}]" - ], "Error in jinja expression in fetch values predicate: %(msg)s": [ "Napaka v jinja izrazu za pridobivanje vrednosti predikatov: %(msg)s" ], @@ -514,6 +444,7 @@ "Time column \"%(col)s\" does not exist in dataset": [ "Časovni stolpec \"%(col)s\" ne obstaja v podatkovnem setu" ], + "error_message": ["error_message"], "Filter value list cannot be empty": [ "Seznam vrednosti filtra ne sme biti prazen" ], @@ -539,26 +470,40 @@ "Dovoljeni so le `SELECT` stavki" ], "Only single queries supported": ["Podprte so le enojne poizvedbe"], + "Columns": ["Stolpci"], "Show Column": ["Pokaži stolpec"], "Add Column": ["Dodaj stolpec"], "Edit Column": ["Uredi stolpec"], "Whether to make this column available as a [Time Granularity] option, column has to be DATETIME or DATETIME-like": [ "Če želite, da bo ta stolpec na razpolago kot možnost [Granulacija časa]. Stolpec mora biti tipa DATETIME ali DATETIME-like" ], + "Whether this column is exposed in the `Filters` section of the explore view.": [ + "Če želite, da je ta stolpec na voljo v sekciji `Filtri` v raziskovalnem pogledu." + ], "The data type that was inferred by the database. It may be necessary to input a type manually for expression-defined columns in some cases. In most case users should not need to alter this.": [ "Podatkovni tip, ki izvira iz podatkovne baze. V nekaterih primerih je potrebno ročno vnesti tip za stolpce, ki temeljijo na izrazih. V večini primerov uporabniku tega ni potrebno spreminjati." ], + "Column": ["Stolpec"], + "Verbose Name": ["Podrobno ime"], + "Description": ["Opis"], + "Groupable": ["Združevanje"], + "Filterable": ["Filtriranje"], "Table": ["Tabela"], "Expression": ["Izraz"], "Is temporal": ["Časoven"], "Datetime Format": ["Oblika zapisa datuma,časa"], + "Type": ["Tip"], + "Business Data Type": ["Poslovni podatkovni tip"], "Invalid date/timestamp format": ["Neveljaven zapis datuma/časa"], + "Metrics": ["Mere"], "Show Metric": ["Pokaži mero"], "Add Metric": ["Dodaj mero"], "Edit Metric": ["Uredi mero"], + "Metric": ["Mera"], "SQL Expression": ["SQL izraz"], "D3 Format": ["D3 zapis"], "Extra": ["Dodatno"], + "Warning Message": ["Opozorilo"], "Row level security filter": ["Filter za varnost na nivoju vrstic"], "Show Row level security filter": [ "Prikaži filter za varnost na nivoju vrstic" @@ -588,9 +533,16 @@ "Roles": ["Vloge"], "Clause": ["Stavek"], "Creator": ["Avtor"], + "Modified": ["Spremenjeno"], "Show Table": ["Prikaži tabelo"], "Import a table definition": ["Uvozi definicijo tabele"], "Edit Table": ["Uredi tabelo"], + "The list of charts associated with this table. By altering this datasource, you may change how these associated charts behave. Also note that charts need to point to a datasource, so this form will fail at saving if removing charts from a datasource. If you want to change the datasource for a chart, overwrite the chart from the 'explore view'": [ + "Seznam grafikonov, povezanih s to tabelo. S spreminjanjem podatkovnega vira lahko spremenite, kako se povezani grafikoni obnašajo. Poleg tega morajo biti grafikoni povezani s podatkovnim virom. Če odstranite grafikon s podatkovnega vira ne bo mogoče shraniti tega vnosa. Če želite spremeniti podatkovni vir grafikona, prepišite grafikon v raziskovalnem pogledu." + ], + "Timezone offset (in hours) for this datasource": [ + "Razlika časovnega pasu (v urah) za ta podatkovni vir" + ], "Name of the table that exists in the source database": [ "Ime tabele, ki obstaja v izvorni podatkovni bazi" ], @@ -606,6 +558,9 @@ "Redirects to this endpoint when clicking on the table from the table list": [ "Preusmeri v to končno točko, ko kliknete na tabelo v seznamu tabel" ], + "Whether to populate the filter's dropdown in the explore view's filter section with a list of distinct values fetched from the backend on the fly": [ + "Če želite napolniti spustni seznam filtra v raziskovalnem pogledu filtrske sekcije z različnimi vrednostmi, pridobljenimi sproti v ozadju" + ], "Whether the table was generated by the 'Visualize' flow in SQL Lab": [ "Če želite, da je tabela ustvarjena s postopkom 'Vizualizacija' v SQL laboratoriju" ], @@ -615,35 +570,24 @@ "Duration (in seconds) of the caching timeout for this table. A timeout of 0 indicates that the cache never expires. Note this defaults to the database timeout if undefined.": [ "Trajanje (v sekundah) predpomnjenja za to tabelo. Vrednost 0 označuje, da predpomnilnik nikoli ne poteče. V primeru, da ni definirano, ima nastavitev trajanja za podatkovno bazo." ], + "Associated Charts": ["Povezani grafikoni"], + "Changed By": ["Spremenil"], "Database": ["Podatkovna baza"], "Last Changed": ["Zadnja sprememba"], + "Enable Filter Select": ["Omogoči izbiro filtra"], "Schema": ["Shema"], + "Default Endpoint": ["Privzeta končna točka"], "Offset": ["Odmik"], + "Cache Timeout": ["Trajanje predpomnilnika"], "Table Name": ["Ime tabele"], "Fetch Values Predicate": ["Pridobi vrednosti predikatov"], + "Owners": ["Lastniki"], "Main Datetime Column": ["Glavni stolpec Datum-Čas"], "SQL Lab View": ["Pogled SQL laboratorija"], "Template parameters": ["Parametri predlog"], "The table was created. As part of this two-phase configuration process, you should now click the edit button by the new table to configure it.": [ "Tabela je ustvarjena. Sedaj morate v tem dvodelnem postopku klikniti gumb za urejanje nove tabele." ], - "Refresh Metadata": ["Osveži metapodatke"], - "Refresh column metadata": ["Osveži metapodatke stolpca"], - "Metadata refreshed for the following table(s): %(tables)s": [ - "Metapodatki osveženi za naslednje tabele: %(tables)s" - ], - "The following tables added new columns: %(tables)s": [ - "Nove stolpce so dodale naslednje tabele: %(tables)s" - ], - "The following tables removed columns: %(tables)s": [ - "Stolpce so odstranile naslednje tabele: %(tables)s" - ], - "The following tables update column metadata: %(tables)s": [ - "Metapodatke stolpcev so posodobile naslednje tabele: %(tables)s" - ], - "Unable to refresh metadata for the following table(s): %(tables)s": [ - "Ni mogoče osvežiti metapodatkov za naslednje tabele: %(tables)s" - ], "Deleted %(num)d css template": [ "Izbrisana %(num)d css predloga", "Izbrisani %(num)d css predlogi", @@ -661,6 +605,7 @@ "Izbrisanih je %(num)d nadzornih plošč" ], "Title or Slug": ["Naslov ali `Slug`"], + "Created by me": ["Ustvarjeno z moje strani"], "Role": ["Vloga"], "Must be unique": ["Mora biti unikaten"], "Dashboard parameters are invalid.": [ @@ -688,7 +633,15 @@ "Nimate dostopa do te nadzorne plošče." ], "No data in file": ["V datoteki ni podatkov"], + "Invalid state.": ["Neveljavno stanje."], + "An error occurred while creating the value.": [ + "Pri ustvarjanju vrednosti je prišlo do težave." + ], + "An error occurred while accessing the value.": [ + "Pri dostopanju do vednosti je prišlo do težave." + ], "Table name undefined": ["Ime tabele ni definirano"], + "Upload Enabled": ["Nalaganje omogočeno"], "Invalid connection string, a valid string usually follows: driver://user:password@database-host/database-name": [ "Neveljaven niz povezave - veljaven niz običajno sledi: driver://user:password@database-host/database-name" ], @@ -714,8 +667,8 @@ "Podatkovna baza z enakim imenom že obstaja." ], "Field is required": ["Polje je obvezno"], - "Field cannot be decoded by JSON. %{json_error}s": [ - "Polja ni mogoče dekodirati z JSON. %{json_error}s" + "Field cannot be decoded by JSON. %(json_error)s": [ + "Polja ni mogoče dekodirati z JSON. %(json_error)s" ], "The metadata_params in Extra field is not configured correctly. The key %{key}s is invalid.": [ "Metadata_params v polju Dodatno niso pravilno nastavljeni. Ključ %{key}s je neveljaven." @@ -745,6 +698,12 @@ "Unexpected error occurred, please check your logs for details": [ "Zgodila se je nepričakovana napaka. Podrobnosti preverite v dnevnikih" ], + "no SQL validator is configured": ["SQL potrjevalnik ni nastavljen"], + "No validator found (configured for the engine)": [ + "Potrjevalnik ni najden (nastavljen za podatkovno bazo)" + ], + "Was unable to check your query": ["Poizvedbe ni bilo mogoče preveriti"], + "An unexpected error occurred": ["Prišlo je do nepričakovane napake"], "Import database failed for an unknown reason": [ "Uvoz podatkovne baze ni uspel zaradi neznanega razloga" ], @@ -755,6 +714,15 @@ "Podatkovne baze tipa \"%(engine)s\" ni mogoče konfigurirati s parametri." ], "Database is offline.": ["Podatkovna baza ni povezana."], + "%(validator)s was unable to check your query.\nPlease recheck your query.\nException: %(ex)s": [ + "%(validator)s ni mogel preveriti vaše poizvedbe.\nPonovno preverite poizvedbo.\nIzjema: %(ex)s" + ], + "no SQL validator is configured for {}": [ + "SQL potrjevalnik ni nastavljen za {}" + ], + "No validator named {} found (configured for the {} engine)": [ + "Potrjevalnik {} ni bil najden (nastavljen za podatkovno bazo {})" + ], "Deleted %(num)d dataset": [ "Izbrisan %(num)d podatkovni set", "Izbrisana %(num)d podatkovna niza", @@ -784,6 +752,7 @@ "Table [%(table_name)s] could not be found, please double check your database connection, schema, and table name": [ "Tabele [%(table_name)s] ni mogoče najti. Preverite povezavo, shemo in ime podatkovne baze" ], + "Dataset does not exist": ["Podatkovni set ne obstaja"], "Dataset parameters are invalid.": [ "Parametri podatkovnega seta so neveljavni." ], @@ -799,12 +768,18 @@ "Dataset(s) could not be bulk deleted.": [ "Podatkovnih nizov ni mogoče množično izbrisati." ], + "Samples for dataset could not be retrieved.": [ + "Vzorcev za podatkovni set ni bilo mogoče pridobiti." + ], "Changing this dataset is forbidden": [ "Spreminjanje tega podatkovnega seta ni dovoljeno" ], "Import dataset failed for an unknown reason": [ "Uvoz podatkovnega seta ni uspel zaradi neznanega razloga" ], + "You don't have access to this dataset.": [ + "Nimate dostopa do tega podatkovnega seta." + ], "Dataset metric not found.": ["Mer podatkovnega seta ni najdena."], "Dataset metric delete failed.": [ "Brisanje mere podatkovnega seta ni uspelo." @@ -853,6 +828,9 @@ "The schema \"%(schema)s\" does not exist. A valid schema must be used to run this query.": [ "Shema \"%(schema)s\" ne obstaja. Za poizvedbo mora biti uporabljena veljavna shema." ], + "We can't seem to resolve the column \"%(column_name)s\"": [ + "Zdi se, da ni mogoče razrešiti stolpca \"%(column_name)s\"" + ], "Please check your query for syntax errors near \"%(server_error)s\". Then, try running your query again.": [ "Preverite, če ima vaša poizvedba sintaktične napake pri \"%(server_error)s\". Potem ponovno poženite poizvedbo." ], @@ -906,8 +884,8 @@ "%(object)s does not exist in this database.": [ "%(object)s ne obstaja v tej podatkovni bazi." ], - "We can't seem to resolve the column \"%(column_name)s\"": [ - "Zdi se, da ni mogoče razrešiti stolpca \"%(column_name)s\"" + "You don't have access to this embedded dashboard config.": [ + "Nimate dostopa do konfiguracije te vgrajene nadzorne plošče." ], "Home": ["Domov"], "Annotation Layers": ["Sloji z oznakami"], @@ -926,20 +904,22 @@ "Databases": ["Podatkovne baze"], "Data": ["Podatki"], "Datasets": ["Podatkovni seti"], - "Upload a CSV": ["Naloži CSV"], - "Upload a Columnar File": ["Naloži datoteko s stolpci"], - "Upload Excel": ["Naloži Excel"], "Action Log": ["Dnevnik aktivnosti"], - "Dashboard Emails": ["E-pošta za nadzorno ploščo"], - "Chart Email Schedules": ["Urniki za e-pošto grafikonov"], - "Alerts": ["Opozorila"], "Alerts & Reports": ["Opozorila in poročila"], "Access requests": ["Zahteve za dostop"], - "Scan New Datasources": ["Preišči nove podatkovne vire"], - "Refresh Druid Metadata": ["Osveži metapodatke za Druid"], - "Temporal expression not supported for type: %(col_type)s": [ - "Časovni izraz ni podprt za podatkovne tipe: %(col_type)s" + "An error occurred while parsing the key.": [ + "Pri branju ključa je prišlo do težave." + ], + "An error occurred while deleting the value.": [ + "Pri brisanju vrednosti je prišlo do napake." + ], + "An error occurred while updating the value.": [ + "Pri posodabljanju vrednosti je prišlo do težave." + ], + "You don't have permission to modify the value.": [ + "Nimate dovoljenja za spreminjanje vrednosti." ], + "Invalid permalink key": ["Neveljaven ključ povezave"], "Deleted %(num)d saved query": [ "Izbrisana %(num)d shranjena poizvedba", "Izbrisani %(num)d shranjeni poizvedbi", @@ -964,10 +944,10 @@ ], "Value must be greater than 0": ["Vrednost mora biti večja od 0"], "Alert query returned more than one row. %s rows returned": [ - "Opozorilna poizvedba je vrnila več kot eno vrstico. Število vrnjenih vrstic: %s" + "Poizvedba za opozorilo je vrnila več kot eno vrstico. Št. vrnjenih vrstic: %s" ], "Alert query returned more than one column. %s columns returned": [ - "Opozorilna poizvedba je vrnila več kot en stolpec. Število vrnjenih stolpcev: %s" + "Poizvedba za opozorilo je vrnila več kot en stolpec. Število vrnjenih stolpcev: %s" ], "Dashboard does not exist": ["Nadzorna plošča ne obstaja"], "Chart does not exist": ["Grafikon ne obstaja"], @@ -1019,17 +999,26 @@ "Report Schedule reached a working timeout.": [ "Urnik poročanja je dosegel mejo časa izvedbe." ], + "A report named \"%(name)s\" already exists": [ + "Poročilo poimenovano %(name)s že obstaja" + ], + "An alert named \"%(name)s\" already exists": [ + "Opozorilo poimenovano %(name)s že obstaja" + ], + "Resource already has an attached report.": [ + "Vir že ima povezano poročilo." + ], "Alert query returned more than one row.": [ - "Opozorilna poizvedba je vrnila več kot eno vrstico." + "Poizvedba za opozorilo je vrnila več kot eno vrstico." ], "Alert validator config error.": [ "Napaka nastavitev potrjevalnika opozoril." ], "Alert query returned more than one column.": [ - "Opozorilna poizvedba je vrnila več kot en stolpec." + "Poizvedba za opozorilo je vrnila več kot en stolpec." ], "Alert query returned a non-number value.": [ - "Opozorilna poizvedba je vrnila neštevilsko vrednost." + "Poizvedba za opozorilo je vrnila neštevilsko vrednost." ], "Alert found an error while executing a query.": [ "Opozorilo je našlo napako pri izvajanju poizvedbe." @@ -1094,19 +1083,6 @@ "Please check your query and confirm that all template parameters are surround by double braces, for example, \"{{ ds }}\". Then, try running your query again.": [ "V poizvedbi preverite, da so vsi parametri obdani z dvojnimi oklepaji, npr. \"{{ ds }}\". Potem poskusite ponovno." ], - "\n *%(name)s*\n\n <%(url)s|Explore in Superset>\n ": [ - "\n *%(name)s*\n\n <%(url)s|Razišči v Supersetu>\n " - ], - "<b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>": [ - "<b><a href=\"%(url)s\">Razišči v Supersetu</a></b><p></p>" - ], - "\n <b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>\n <img src=\"cid:%(msgid)s\">\n ": [ - "\n <b><a href=\"%(url)s\">Razišči v Supersetu</a></b><p></p>\n <img src=\"cid:%(msgid)s\">\n " - ], - "\n *%(slice_name)s*\n\n <%(slice_url_user_friendly)s|Explore in Superset>\n ": [ - "\n *%(slice_name)s*\n\n <%(slice_url_user_friendly)s|Razišči v Supersetu>\n " - ], - "[Alert] %(label)s": ["[Alert] %(label)s"], "New": ["Nov"], "SQL Query": ["SQL poizvedba"], "Chart": ["Grafikon"], @@ -1131,10 +1107,11 @@ ], "Request Permissions": ["Zahtevaj dovoljenja"], "Cancel": ["Prekliči"], - "Use the edit buttom to change this field": [ + "Use the edit button to change this field": [ "Za spreminjanje tega polja uporabite gumb za urejanje" ], "Test Connection": ["Preizkusi povezavo"], + "Resource was not found.": ["Vir ni bil najden."], "[Superset] Access to the datasource %(name)s was granted": [ "[Superset] dostop do podatkovnega vira %(name)s je odobren" ], @@ -1145,31 +1122,8 @@ "Unable to find such a holiday: [%(holiday)s]": [ "Ni mogoče najti takšnega praznika: [%(holiday)s]" ], - "Referenced columns not available in DataFrame.": [ - "Referencirani stolpci niso razpoložljivi v Dataframe-u." - ], - "Column referenced by aggregate is undefined: %(column)s": [ - "Stolpec referenciran z agregacijo ni definiran: %(column)s" - ], - "Operator undefined for aggregator: %(name)s": [ - "Operand ni definiran za agregatorja: %(name)s" - ], - "Invalid numpy function: %(operator)s": [ - "Neveljavna numpy funkcija: %(operator)s" - ], - "Pivot operation requires at least one index": [ - "Vrtilna operacija zahteva vsaj en indeks" - ], - "Pivot operation must include at least one aggregate": [ - "Vrtilna operacija mora vsebovati vsaj en agregat" - ], - "Undefined window for rolling operation": [ - "Nedefinirano okno za drsečo operacijo" - ], - "Window must be > 0": ["Okno mora biti > 0"], - "Invalid rolling_type: %(type)s": ["Neveljaven rolling_type: %(type)s"], - "Invalid options for %(rolling_type)s: %(options)s": [ - "Neveljavne možnosti za %(rolling_type)s: %(options)s" + "percentiles must be a list or tuple with two numeric values, of which the first is lower than the second value": [ + "percentili morajo biti tipa list ali tuple z vsaj dvema numeričnima vrednostma, pri čemer je prva manjša od druge" ], "`compare_columns` must have the same length as `source_columns`.": [ "`compare_columns` morajo imeti enako dolžino kot `source_columns`." @@ -1177,26 +1131,30 @@ "`compare_type` must be `difference`, `percentage` or `ratio`": [ "`compare_type` mora biti `difference`, `percentage` ali `ratio`" ], + "Column \"%(column)s\" is not numeric or does not exists in the query results.": [ + "Stolpec \"%(column)s\" ni numeričen ali ne obstaja v rezultatu poizvedbe." + ], + "`rename_columns` must have the same length as `columns`.": [ + "`rename_columns` morajo imeti enako dolžino kot `columns`." + ], "Invalid cumulative operator: %(operator)s": [ "Neveljaven kumulativni operand: %(operator)s" ], "Invalid geohash string": ["Neveljaven niz za geohash"], "Invalid longitude/latitude": ["Neveljavna zemljepisna dolžina/širina"], "Invalid geodetic string": ["Neveljaven geodetski niz"], - "Column \"%(column)s\" is not numeric or does not exists in the query results.": [ - "Stolpec \"%(column)s\" ni numeričen ali ne obstaja v rezultatu poizvedbe." + "Pivot operation requires at least one index": [ + "Vrtilna operacija zahteva vsaj en indeks" ], - "`rename_columns` must have the same length as `columns`.": [ - "`rename_columns` morajo imeti enako dolžino kot `columns`." + "Pivot operation must include at least one aggregate": [ + "Vrtilna operacija mora vsebovati vsaj en agregat" ], "`prophet` package not installed": ["Knjižnica `prophet` ni nameščena"], "Time grain missing": ["Časovna granulacija manjka"], "Unsupported time grain: %(time_grain)s": [ "Nepodprta časovna granulacija: %(time_grain)s" ], - "Periods must be a positive integer value": [ - "Periode morajo biti pozitivno celo število" - ], + "Periods must be a whole number": ["Periode morajo biti celo število"], "Confidence interval must be between 0 and 1 (exclusive)": [ "Interval zaupanja mora biti med 0 in 1 (odprt)" ], @@ -1206,33 +1164,37 @@ "DataFrame include at least one series": [ "DataFrame vsebuje vsaj eno serijo" ], - "percentiles must be a list or tuple with two numeric values, of which the first is lower than the second value": [ - "percentili morajo biti tipa list ali tuple z vsaj dvema numeričnima vrednostma, pri čemer je prva manjša od druge" + "Label already exists": ["Oznaka že obstaja"], + "Resample operation requires DatetimeIndex": [ + "Prevzorčevalna operacija zahteva indeks tipa datumčas" ], - "User": ["Uporabnik"], - "User Roles": ["Vloge uporabnikov"], - "Database URL": ["URL podatkovne baze"], - "Roles to grant": ["Vloge za dovoljevanje"], - "Created On": ["Ustvarjeno"], - "List Observations": ["Naštej opažanja"], - "Show Observation": ["Prikaži opažanja"], - "Error Message": ["Sporočilo napake"], - "Log Retentions (days)": ["Ohranjanje dnevnika (dnevi)"], - "A semicolon ';' delimited list of email addresses": [ - "S podpičjem ';' ločen seznam naslovov e-pošte" + "Resample method should in ": ["Metoda za prevzorčenje v Pandas mora "], + "Undefined window for rolling operation": [ + "Nedefinirano okno za drsečo operacijo" + ], + "Window must be > 0": ["Okno mora biti > 0"], + "Invalid rolling_type: %(type)s": ["Neveljaven rolling_type: %(type)s"], + "Invalid options for %(rolling_type)s: %(options)s": [ + "Neveljavne možnosti za %(rolling_type)s: %(options)s" ], - "How long to keep the logs around for this alert": [ - "Kako dolgo ohraniti dnevnike za to opozorilo" + "Referenced columns not available in DataFrame.": [ + "Referencirani stolpci niso razpoložljivi v Dataframe-u." ], - "Once an alert is triggered, how long, in seconds, before Superset nags you again.": [ - "Kako dolgo naj traja (v sekundah), da vas Superset ponovno opomni, ko je opozorilo sproženo." + "Column referenced by aggregate is undefined: %(column)s": [ + "Stolpec referenciran z agregacijo ni definiran: %(column)s" ], - "A SQL statement that defines whether the alert should get triggered or not. The query is expected to return either NULL or a number value.": [ - "SQL izraz, ki definira ali naj se opozorilo sproži ali ne. Od poizvedbe se pričakuje, da vrne bodisi NULL bodisi številsko vrednost." + "Operator undefined for aggregator: %(name)s": [ + "Operand ni definiran za agregatorja: %(name)s" ], - "This feature is deprecated and will be removed on 2.0. Take a look at the replacement feature <a href='https://superset.apache.org/docs/installation/alerts-reports'>Alerts & Reports documentation</a>": [ - "Ta funkcija je zastarela in bo odstranjena v verziji 2.0. Oglejte si zamenjavo <a href='https://superset.apache.org/docs/installation/alerts-reports'>Dokumentacija za Opozorila & Poročila</a>" + "Invalid numpy function: %(operator)s": [ + "Neveljavna numpy funkcija: %(operator)s" ], + "User": ["Uporabnik"], + "User Roles": ["Vloge uporabnikov"], + "Database URL": ["URL podatkovne baze"], + "Datasource": ["Podatkovni vir"], + "Roles to grant": ["Vloge za dovoljevanje"], + "Created On": ["Ustvarjeno"], "annotation start time or end time is required.": [ "začetni in končni čas oznake je obvezen." ], @@ -1288,6 +1250,16 @@ "An unknown error occurred. Please contact your Superset administrator": [ "Zgodila se je neznana napaka. Kontaktirajte svojega administratorja za Superset" ], + "Error: permalink state not found": [ + "Napaka: stanje povezave ni najdeno" + ], + "Error: %(msg)s": ["Napaka: %(msg)s"], + "Form data not found in cache, reverting to chart metadata.": [ + "Podatkov ni mogoče najti v predpomnilniku. Uporabljeni bodo metapodatki grafikona." + ], + "Form data not found in cache, reverting to dataset metadata.": [ + "Podatkov ni mogoče najti v predpomnilniku. Uporabljeni bodo metapodatki podatkovnega seta." + ], "[Missing Dataset]": ["[Manjka podatkovni set]"], "alter this ": ["spreminjanje tega "], "chart": ["grafikona"], @@ -1319,23 +1291,15 @@ "Table %(table)s wasn't found in the database %(db)s": [ "Tabela %(table)s ni bila najdena v podatkovni bazi %(db)s" ], - "Can't find User '%(name)s', please ask your admin to create one.": [ - "Uporabnika '%(name)s' ni mogoče najti. Prosite administratorja, da ga ustvari." - ], - "Can't find DruidCluster with cluster_name = '%(name)s'": [ - "Ni mogoče najti DruidCluster s cluster_name = '%(name)s'" - ], + "permalink state not found": ["stanje povezave ni najdeno"], "One or more required fields are missing in the request. Please try again, and if the problem persists conctact your administrator.": [ "Eno ali več zahtevanih polj manjka v zahtevi. Poskusite znova, če težava ostane, kontaktirajte administratorja." ], "The database was not found.": ["Podatkovna baza ni bila najdena."], - "You are not authorized to fetch samples from this table. If you think this is an error, please reach out to your administrator.": [ - "Nimate dovoljenja za pridobitev vzorcev iz te tabele. Če menite, da je to napaka, kontaktirajte administratorja." - ], "Data could not be retrieved from the results backend. You need to re-run the original query.": [ "Podatkov ni bilo mogoče pridobiti iz zalednega sistema rezultatov. Ponovno morate zagnati izvorno poizvedbo." ], - "The query associated with these results could not be find. You need to re-run the original query.": [ + "The query associated with these results could not be found. You need to re-run the original query.": [ "Poizvedbe, povezane s temi rezultati, ni bilo mogoče najti. Ponovno morate zagnati izvorno poizvedbo." ], "You are not authorized to see this query. If you think this is an error, please reach out to your administrator.": [ @@ -1347,9 +1311,6 @@ "The provided `rows` argument is not a valid integer.": [ "Podani argument `rows` ni veljavno celo število." ], - "%(validator)s was unable to check your query.\nPlease recheck your query.\nException: %(ex)s": [ - "%(validator)s ni mogel preveriti vaše poizvedbe.\nPonovno preverite poizvedbo.\nIzjema: %(ex)s" - ], "%(user)s's profile": ["Profil uporabnika: %(user)s"], "Show CSS Template": ["Prikaži CSS predlogo"], "Add CSS Template": ["Dodaj CSS predlogo"], @@ -1366,26 +1327,6 @@ "Custom Plugin": ["Prilagojeni vtičnik"], "Add a Plugin": ["Dodaj vtičnik"], "Edit Plugin": ["Uredi vtičnik"], - "Schedule Email Reports for Dashboards": [ - "Razporedi e-poštna poročila za nadzorne plošče" - ], - "Manage Email Reports for Dashboards": [ - "Upravljaj e-poštna poročila za nadzorne plošče" - ], - "Changed On": ["Spremenjeno"], - "Active": ["Aktiven"], - "Crontab": ["Crontab"], - "Recipients": ["Prejemniki"], - "Slack Channel": ["Slack Channel"], - "Deliver As Group": ["Dostavi kot skupino"], - "Delivery Type": ["Tip dostave"], - "Schedule Email Reports for Charts": [ - "Razporedi e-poštna poročila za grafikone" - ], - "Manage Email Reports for Charts": [ - "Upravljaj e-poštna poročila za grafikone" - ], - "Email Format": ["Oblika e-pošte"], "List Saved Query": ["Seznam shranjenih poizvedb"], "Show Saved Query": ["Prikaži shranjeno poizvedbo"], "Add Saved Query": ["Dodaj shranjeno poizvedbo"], @@ -1448,6 +1389,9 @@ "Name of table to be created from csv data.": [ "Ime tabele, ki bo ustvarjena iz CSV podatkov." ], + "Table name cannot contain a schema": [ + "Ime tabele ne sme vsebovati sheme" + ], "CSV File": ["CSV datoteka"], "Select a CSV file to be uploaded to a database.": [ "Izberite CSV datoteko, ki bo naložena v podatkovno bazo." @@ -1604,9 +1548,6 @@ "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for csv uploads. Please contact your Superset Admin.": [ "Shema \"%(schema_name)s\" podatkovne baze \"%(database_name)s\" ni dovoljena za nalaganje CSV. Kontaktirajte administratorja za Superset." ], - "You cannot specify a namespace both in the name of the table: \"%(csv_table.table)s\" and in the schema field: \"%(csv_table.schema)s\". Please remove one": [ - "Imenskega prostora ni mogoče podati hkrati v tabeli: \"%(csv_table.table)s\" in polju sheme: \"%(csv_table.schema)s\". Odstranite enega" - ], "Unable to upload CSV file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ "CSV datoteke \"%(filename)s\" ni mogoče naložiti v tabelo \"%(table_name)s\" v podatkovni bazi \"%(db_name)s\". Sporočilo napake: %(error_msg)s" ], @@ -1619,9 +1560,6 @@ "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for excel uploads. Please contact your Superset Admin.": [ "Shema \"%(schema_name)s\" podatkovne baze \"%(database_name)s\" ni dovoljena za nalaganje Excel datotek. Kontaktirajte administratorja za Superset." ], - "You cannot specify a namespace both in the name of the table: \"%(excel_table.table)s\" and in the schema field: \"%(excel_table.schema)s\". Please remove one": [ - "Imenskega prostora ni mogoče podati hkrati v tabeli: \"%(excel_table.table)s\" in polju sheme: \"%(excel_table.schema)s\". Odstranite enega" - ], "Unable to upload Excel file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ "Excel datoteke \"%(filename)s\" ni mogoče naložiti v tabelo \"%(table_name)s\" v podatkovni bazi \"%(db_name)s\". Sporočilo napake: %(error_msg)s" ], @@ -1637,9 +1575,6 @@ "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for columnar uploads. Please contact your Superset Admin.": [ "Shema \"%(schema_name)s\" podatkovne baze \"%(database_name)s\" ni dovoljena za nalaganje stolpčnih datotek. Kontaktirajte administratorja za Superset." ], - "You cannot specify a namespace both in the name of the table: \"%(columnar_table.table)s\" and in the schema field: \"%(columnar_table.schema)s\". Please remove one": [ - "Imenskega prostora ni mogoče podati hkrati v imenu tabele: \"%(columnar_table.table)s\" in polju sheme: \"%(columnar_table.schema)s\". Odstranite enega" - ], "Unable to upload Columnar file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ "Stolpčne datoteke \"%(filename)s\" ni mogoče naložiti v tabelo \"%(table_name)s\" v podatkovni bazi \"%(db_name)s\". Sporočilo napake: %(error_msg)s" ], @@ -1656,3568 +1591,3910 @@ "Edit Log": ["Uredi dnevnik"], "Action": ["Aktivnost"], "dttm": ["dttm"], - "Add item": ["Dodaj"], - "The query couldn't be loaded": ["Poizvedbe ni mogoče naložiti"], - "Your query has been scheduled. To see details of your query, navigate to Saved queries": [ - "Vaša poizvedba je v urniku. Za ogled podrobnosti poizvedbe pojdite na shranjene poizvedbe" - ], - "Your query could not be scheduled": [ - "Vaše poizvedbe ni mogoče uvrstiti v urnik" - ], - "Failed at retrieving results": ["Napaka pri pridobivanju rezultatov"], - "An error occurred while storing the latest query id in the backend. Please contact your administrator if this problem persists.": [ - "Pri shranjevanju zadnjega id-ja poizvedbe v sistem je prišlo do napake. Če se težava ponavlja, kontaktirajte administratorja." + "JSON": ["JSON"], + "Time Range": ["Časovno obdobje"], + "Time Column": ["Časovni stolpec"], + "Time Grain": ["Granulacija časa"], + "Origin": ["Izhodišče"], + "Time Granularity": ["Granulacija časa"], + "Time": ["Čas"], + "A reference to the [Time] configuration, taking granularity into account": [ + "Sklic na nastavitve za [Čas], ki upošteva granulacijo" ], - "Unknown error": ["Neznana napaka"], - "Query was stopped.": ["Poizvedba je bila ustavljena."], - "Unable to migrate table schema state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ - "Stanja sheme tabele ni mogoče prenesti v sistem. Superset bo ponovil poskus kasneje. Če se težava ponavlja, kontaktirajte administratorja." + "Aggregate": ["Agregacija"], + "Raw records": ["Surovi podatki"], + "Certified by %s": ["Certificiral/a %s"], + "description": ["opis"], + "bolt": ["vijak"], + "Changing this control takes effect instantly": [ + "Sprememba tega kontrolnika se odrazi takoj" ], - "Unable to migrate query state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ - "Stanja poizvedbe ni mogoče prenesti v sistem. Superset bo ponovil poskus kasneje. Če se težava ponavlja, kontaktirajte administratorja." + "Show info tooltip": ["Prikaži opis orodja"], + "SQL expression": ["SQL izraz"], + "Column name": ["Ime stolpca"], + "Metric name": ["Ime mere"], + "unknown type icon": ["ikona neznanega tipa"], + "function type icon": ["ikona funkcijskega tipa"], + "string type icon": ["ikona znakovnega tipa"], + "numeric type icon": ["ikona numeričnega tipa"], + "boolean type icon": ["ikona binarnega tipa"], + "temporal type icon": ["ikona časovnega tipa"], + "Advanced analytics": ["Napredna analitika"], + "This section contains options that allow for advanced analytical post processing of query results": [ + "Ta sekcija vsebuje možnosti, ki omogočajo napredno analitično poprocesiranje rezultatov poizvedb" ], - "Unable to migrate query editor state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ - "Stanja urejevalnika poizvedb ni mogoče prenesti v sistem. Superset bo ponovil poskus kasneje. Če se težava ponavlja, kontaktirajte administratorja." + "Rolling window": ["Drseče okno"], + "Rolling function": ["Drseča funkcija"], + "None": ["Brez"], + "Defines a rolling window function to apply, works along with the [Periods] text box": [ + "Določi funkcijo drsečega okna. Dela skupaj s tekstovnim okvirjem [Obdobja]" ], - "Unable to add a new tab to the backend. Please contact your administrator.": [ - "Novega zavihka ni mogoče dodati v sistem. Kontaktirajte administratorja." + "Periods": ["Št. period"], + "Defines the size of the rolling window function, relative to the time granularity selected": [ + "Določi velikost funkcije drsečega okna, glede na izbrano granulacijo časa" ], - "Copy of %s": ["Kopija %s"], - "An error occurred while setting the active tab. Please contact your administrator.": [ - "Pri določanju aktivnega zavihka je prišlo do napake. Kontaktirajte administratorja." + "Min periods": ["Min. št. period"], + "The minimum number of rolling periods required to show a value. For instance if you do a cumulative sum on 7 days you may want your \"Min Period\" to be 7, so that all data points shown are the total of 7 periods. This will hide the \"ramp up\" taking place over the first 7 periods": [ + "Minimalno število drsečih obdobij, potrebnih za prikaz vrednosti. Če računate kumulativno vsoto 7-dnevnega obdobja, boste nastavili \"Min. št. period\" na 7. Tako bodo vse prikazane točke skupaj obsegale 7 obdobij. To bo prikrilo rampo, ki bi trajala prvih 7 obdobij" ], - "An error occurred while fetching tab state": [ - "Pri pridobivanju stanja zavihka je prišlo do napake" + "Time comparison": ["Časovna primerjava"], + "Time shift": ["Časovni zamik"], + "Overlay one or more timeseries from a relative time period. Expects relative time deltas in natural language (example: 24 hours, 7 days, 52 weeks, 365 days). Free text is supported.": [ + "Zamaknite eno ali več časovnih vrst za relativno časovno obdobje. Vnaša se relativne časovne razlike v naravnem jeziku (npr. 24 ur, 7 dni, 52 tednov, 365 dni). Prosto besedilo je podprto." ], - "An error occurred while hiding the left bar. Please contact your administrator.": [ - "Pri skrivanju leve vrstice je prišlo do napake. Kontaktirajte administratorja." + "Calculation type": ["Tip izračuna"], + "How to display time shifts: as individual lines; as the difference between the main time series and each time shift; as the percentage change; or as the ratio between series and time shifts.": [ + "Način prikaza časovnih zamikov: kot samostojne črte; kot razlike med osnovno časovno vrsto in vsakim časovnim zamikom; kot procentualna sprememba; kot razmerje med vrsto in časovnim zamikom." ], - "An error occurred while removing tab. Please contact your administrator.": [ - "Pri odstranjevanju zavihka je prišlo do napake. Kontaktirajte administratorja." + "Resample": ["Prevzorči"], + "Rule": ["Pravilo"], + "Pandas resample rule": ["Pravilo za prevzorčenje v Pandas"], + "Fill method": ["Način polnjenja"], + "Pandas resample method": ["Metoda za prevzorčenje v Pandas"], + "Annotations and Layers": ["Oznake in sloji"], + "Chart Title": ["Naslov grafikona"], + "X Axis": ["X os"], + "X Axis Title": ["Naslov X osi"], + "X AXIS TITLE BOTTOM MARGIN": ["SPODNJA OBROBA NASLOVA X OSI"], + "Y Axis": ["Y os"], + "Y Axis Title": ["Naslov Y osi"], + "Y AXIS TITLE MARGIN": ["OBROBA NASLOVA Y OSI"], + "Y AXIS TITLE POSITION": ["POZICIJA NASLOVA Y OSI"], + "Predictive Analytics": ["Prediktivna analitika"], + "Enable forecast": ["Omogoči napoved"], + "Enable forecasting": ["Omogoči napovedovanje"], + "Forecast periods": ["Periode napovedi"], + "How many periods into the future do we want to predict": [ + "Za koliko period v prihodnosti želite napoved" ], - "An error occurred while removing query. Please contact your administrator.": [ - "Pri odstranjevanju poizvedbe je prišlo do napake. Kontaktirajte administratorja." + "Confidence interval": ["Interval zaupanja"], + "Width of the confidence interval. Should be between 0 and 1": [ + "Širina intervala zaupanja. Mora bit med 0 in 1" ], - "An error occurred while setting the tab database ID. Please contact your administrator.": [ - "Pri določanju ID-ja v podatkovne baze za zavihek je prišlo do napake. Kontaktirajte administratorja." + "Should yearly seasonality be applied. An integer value will specify Fourier order of seasonality.": [ + "Če želite letno sezonskost. Celo število določa Fourier-jev red sezonskosti." ], - "An error occurred while setting the tab schema. Please contact your administrator.": [ - "Pri določanju sheme zavihka je prišlo do napake. Kontaktirajte administratorja." + "Should weekly seasonality be applied. An integer value will specify Fourier order of seasonality.": [ + "Če želite tedensko sezonskost. Celo število določa Fourier-jev red sezonskosti." ], - "An error occurred while setting the tab autorun. Please contact your administrator.": [ - "Pri določanju samodejnega zagona zavihka je prišlo do napake. Kontaktirajte administratorja." + "Should daily seasonality be applied. An integer value will specify Fourier order of seasonality.": [ + "Če želite dnevno sezonskost. Celo število določa Fourier-jev red sezonskosti." ], - "An error occurred while setting the tab title. Please contact your administrator.": [ - "Pri določanju naslova zavihka je prišlo do napake. Kontaktirajte administratorja." + "Time related form attributes": ["S časom povezani atributi prikaza"], + "Datasource & Chart Type": ["Tip podatkovnega vira in grafikona"], + "Chart ID": ["ID grafikona"], + "The id of the active chart": ["Identifikator aktivnega grafikona"], + "Cache Timeout (seconds)": ["Trajanje predpomnilnika (sekunde)"], + "The number of seconds before expiring the cache": [ + "Trajanje (v sekundah) do razveljavitve predpomnilnika" ], - "Your query was saved": ["Vaša poizvedba je shranjena"], - "Your query could not be saved": ["Vaše poizvedbe ni mogoče shraniti"], - "Your query was updated": ["Vaša poizvedba je posodobljena"], - "Your query could not be updated": [ - "Vaše poizvedbe ni mogoče posodobiti" + "URL Parameters": ["Parametri URL"], + "Extra url parameters for use in Jinja templated queries": [ + "Dodatni parametri za poizvedbe z Jinja predlogami" ], - "An error occurred while storing your query in the backend. To avoid losing your changes, please save your query using the \"Save Query\" button.": [ - "Pri shranjevanju vaše poizvedbe v sistem je prišlo do napake. Da ne izgubite sprememb, shranite poizvedbo z gumbom \"Shrani poizvedbo\"." + "Extra Parameters": ["Dodatni parametri"], + "Extra parameters that any plugins can choose to set for use in Jinja templated queries": [ + "Dodatni parametri, ki jih lahko uporabi kateri koli vtičnik za poizvedbe z Jinja predlogami" ], - "An error occurred while setting the tab template parameters. Please contact your administrator.": [ - "Pri določanju parametrov predloge zavihka je prišlo do napake. Kontaktirajte administratorja." + "Color Scheme": ["Barvna shema"], + "Dimensions": ["Dimenzije"], + "One or many columns to group by. High cardinality groupings should include a series limit to limit the number of fetched and rendered series.": [ + "Eden ali več stolpcev za združevanje. Združevanje z visoko kardinalnostjo naj vsebuje omejitev serij, s čimer omejite število pridobljenih in prikazanih serij." ], - "An error occurred while fetching table metadata": [ - "Pri pridobivanju metapodatkov tabele je prišlo do napake" + "One or many columns to pivot as columns": [ + "En ali več stolpcev za stolpčno vrtenje" ], - "An error occurred while fetching table metadata. Please contact your administrator.": [ - "Pri pridobivanju metapodatkov tabele je prišlo do napake. Kontaktirajte administratorja." + "Defines the grouping of entities. Each series is shown as a specific color on the chart and has a legend toggle": [ + "Določa združevanje entitet. Vsak niz je na grafikonu prikazan z določeno barvo in ima lahko prikazano legendo" ], - "An error occurred while expanding the table schema. Please contact your administrator.": [ - "Pri širitvi sheme tabele je prišlo do napake. Kontaktirajte administratorja." + "Entity": ["Entiteta"], + "This defines the element to be plotted on the chart": [ + "Določa element, ki bo izrisan na grafikonu" ], - "An error occurred while collapsing the table schema. Please contact your administrator.": [ - "Pri krčenju sheme tabele je prišlo do napake. Kontaktirajte administratorja." + "One or many metrics to display": ["Ena ali več mer za prikaz"], + "Right Axis Metric": ["Mera desne osi"], + "Choose a metric for right axis": ["Izberite mero za desno os"], + "Sort by": ["Razvrščanje"], + "Metric used to define how the top series are sorted if a series or row limit is present. If undefined reverts to the first metric (where appropriate).": [ + "Mera, ki določa kako so razvrščene prve serije, če je določena omejitev serij ali vrstic. Če ni določena, se uporabi prva mera (kjer je ustrezno)." ], - "An error occurred while removing the table schema. Please contact your administrator.": [ - "Pri odstranjevanju sheme tabele je prišlo do napake. Kontaktirajte administratorja." + "Bubble Size": ["Velikost mehurčka"], + "Metric used to calculate bubble size": [ + "Mera za izračun velikosti mehurčkov" ], - "Shared query": ["Deljene poizvedbe"], - "The datasource couldn't be loaded": [ - "Podatkovnega vira ni mogoče naložiti" + "Metric assigned to the [X] axis": ["Mera za [X] os"], + "Metric assigned to the [Y] axis": ["Mera za [Y] os"], + "Color Metric": ["Mera za barvo"], + "A metric to use for color": ["Mera za barvo"], + "The time column for the visualization. Note that you can define arbitrary expression that return a DATETIME column in the table. Also note that the filter below is applied against this column or expression": [ + "Časovni stolpec za vizualizacijo. Določite lahko poljuben izraz, ki vrne DATETIME stolpec v tabeli. Spodnji filter se nanaša na ta stolpec ali izraz" ], - "An error occurred while creating the data source": [ - "Pri ustvarjanju podatkovnega vira je prišlo do težave" + "Drop temporal column here": ["Spustite časovni stolpec sem"], + "Enable dashboard cross filters": [ + "Omogoči medsebojne filtre nadzorne plošče" ], - "An error occurred while fetching function names.": [ - "Pri pridobivanju imen funkcij je prišlo do napake." + "One or many columns to group by. High cardinality groupings should include a sort by metric and series limit to limit the number of fetched and rendered series.": [ + "Eden ali več stolpcev za združevanje. Združevanje z visoko kardinalnostjo naj vsebuje mero za razvrščanje in omjitev serij, s čimer omejite število pridobljenih in prikazanih serij." ], - "SQL Lab uses your browser's local storage to store queries and results.\n Currently, you are using ${currentUsage.toFixed(\r\n 2,\r\n )} KB out of ${LOCALSTORAGE_MAX_USAGE_KB} KB. storage space.\n To keep SQL Lab from crashing, please delete some query tabs.\n You can re-access these queries by using the Save feature before you delete the tab. Note that you will need to close other SQL Lab windows before you do this.": [ - "SQL laboratorij za shranjevanje poizvedb in rezultatov uporablja brskalnikovo lokalno shrambo.\nTrenutno uporabljate ${currentUsage.toFixed(\r\n 2,\r\n )} KB od ${LOCALSTORAGE_MAX_USAGE_KB} KB prostora shrambe.\nDa se izognete sesutju SQL laboratorija, izbrišite nekaj zavihkov s poizvedbami.\nTe poizvedbe lahko ponovno uporabite, tako da jih pred izbrisom shranite. Preden storite to, boste morali zapreti druga okna SQL laboratorija." + "The type of visualization to display": ["Tip vizualizacije za prikaz"], + "Fixed Color": ["Izbrana barva"], + "Use this to define a static color for all circles": [ + "S tem definirate določeno barvo za vse kroge" ], - "Estimate selected query cost": ["Oceni potratnost izbrane poizvedbe"], - "Estimate cost": ["Oceni potratnost"], - "Cost estimate": ["Ocena potratnosti"], - "Creating a data source and creating a new tab": [ - "Ustvarjanje podatkovnega vira in novega zavihka" + "Linear Color Scheme": ["Linearna barvna shema"], + "Defines the origin where time buckets start, accepts natural dates as in `now`, `sunday` or `1970-01-01`": [ + "Določa izhodišče, kadar se začnejo časovni razdelki. Sprejema naravne zapise kot so `zdaj`, `nedelja` ali `1970-01-01`" ], - "An error occurred": ["Prišlo je do napake"], - "Explore the result set in the data exploration view": [ - "Raziščite rezultate v pogledu raziskovanja podatkov" + "The time granularity for the visualization. Note that you can type and use simple natural language as in `10 seconds`, `1 day` or `56 weeks`": [ + "Granulacija časa za vizualizacijo. Uporabite lahko vnos z naravnim jezikom, kot npr. `10 sekund`, `1 dni` ali `56 tednov`" ], - "This query took %s seconds to run, ": [ - "Trajanje poizvedbe v sekundah: %s, " + "The time granularity for the visualization. This applies a date transformation to alter your time column and defines a new time granularity. The options here are defined on a per database engine basis in the Superset source code.": [ + "Granulacija časa za to vizualizacijo. Izvede transformacijo podatkov, ki spremeni vaš časovni stolpec in določi novo časovno granulacija. Ta možnost je definirana na ravni sistema podatkovne baze v izvorni kodi Superseta." ], - "and the explore view times out at %s seconds ": [ - "čas izteka raziskovalnega pogleda v sekundah: %s " + "No filter": ["Brez filtra"], + "The time range for the visualization. All relative times, e.g. \"Last month\", \"Last 7 days\", \"now\", etc. are evaluated on the server using the server's local time (sans timezone). All tooltips and placeholder times are expressed in UTC (sans timezone). The timestamps are then evaluated by the database using the engine's local timezone. Note one can explicitly set the timezone per the ISO 8601 format if specifying either the start and/or end time.": [ + "Časovno obdobje za vizualizacijo. Vsi relativni časi, kot npr. \"Zadnji mesec\", Zadnjih 7 dni\", \"Zdaj\" so izračunani na strežniku z njegovim lokalnim časom. Vsi opisi orodij in časi so izraženi v UTC. Časovne značke se nato izračunajo v podatkovni bazi z njenim lokalnim časovnim pasom. Eksplicitno lahko nastavite časovni pas v ISO 8601 formatu, če določite čas začetka ali konca." ], - "following this flow will most likely lead to your query timing out. ": [ - "s takšnim potekom, bo poizvedba najverjetneje potekla. " + "Row limit": ["Omejitev števila vrstic"], + "Limits the number of rows that get displayed.": [ + "Omeji število vrstic za prikaz." ], - "We recommend your summarize your data further before following that flow. ": [ - "Priporočamo, da zahtevane podatke pred nadaljevanjem strnete. " + "Sort Descending": ["Razvrsti padajoče"], + "Whether to sort descending or ascending": [ + "Če želite padajoče ali naraščajoče razvrščanje" ], - "If activated you can use the ": ["Če je aktivirana, lahko uporabite "], - "feature to store a summarized data set that you can then explore.": [ - "funkcijo shranjevanja strnjenega podatkovnega seta, ki ga lahko raziščete." + "Series limit": ["Omejitev števila serij"], + "Limits the number of series that get displayed. A joined subquery (or an extra phase where subqueries are not supported) is applied to limit the number of series that get fetched and rendered. This feature is useful when grouping by high cardinality column(s) though does increase the query complexity and cost.": [ + "Omeji število časovnih vrst za prikaz. S podpoizvedbo (ali dodatno fazo, kjer podpoizvedbe niso podprte) se omeji število časovnih vrst, ki bodo pridobljene za prikaz. Ta funkcija je uporabna pri združevanju s stolpci z veliko kardinalnostjo, vendar poveča kompleksnost poizvedbe." ], - "Column name(s) ": ["Imena stolpcev "], - "cannot be used as a column name. The column name/alias \"__timestamp\"\r\n is reserved for the main temporal expression, and column aliases ending with\r\n double underscores followed by a numeric value (e.g. \"my_col__1\") are reserved\r\n for deduplicating duplicate column names. Please use aliases to rename the\r\n invalid column names.": [ - "ni mogoče uporabiti kot imena stolpcev. Ime stolpca \"__timestamp\"\r\n je rezervirano za glavni časovni izraz. Imena stolpcev, ki se končajo z\r\n dvojnim podčrtajem, ki mu sledi številska vrednost (npr. \"moj_stolpec__1\") so rezervirana\r\n za deduplikacijo duplikatov imen stolpcev. Za preimenovanje neustreznih imen\r\n uporabite psevdonime." + "Y Axis Format": ["Oblika Y osi"], + "Time format": ["Oblika zapisa časa"], + "The color scheme for rendering chart": [ + "Barvna shema za izris grafikona" ], - "Source SQL": ["Izvorni SQL"], - "Executed SQL": ["Izvedena poizvedba"], - "SQL": ["SQL"], - "No query history yet...": ["Zgodovine poizvedb še ni."], - "An error occurred when refreshing queries": [ - "Pri osveževanju poizvedb je prišlo do napake" + "Truncate Metric": ["Odstrani mero"], + "Whether to truncate metrics": ["Če želite odstraniti naziv mere"], + "Sort descending": ["Razvrsti padajoče"], + "Whether to sort descending or ascending. Takes effect only when \"Sort by\" is set": [ + "Če želite padajoče ali naraščajoče razvrščanje. Učinkuje samo, ko je vključen \"Sort by\"" ], - "It seems you don't have access to any database": [ - "Zdi se, da nimate dostopa do nobene podatkovne baz" + "Show less columns": ["Prikaži manj stolpcev"], + "Show all columns": ["Prikaži vse stolpce"], + "Emit Target": ["Cilj oddajanja"], + "If you wish to specify a different target column than the original column, it can be entered here": [ + "Če želite nastaviti drug ciljni stolpec od izvornega, ga lahko vnesete tukaj" ], - "Filter by user": ["Filtriraj po uporabniku"], - "Filter by database": ["Filtriraj po podatkovni bazi"], - "Query search string": ["Iskalni niz za poizvedbo"], - "[From]-": ["[Od]-"], - "[To]-": ["[Do]-"], - "Filter by status": ["Filtriraj po statusu"], - "Success": ["Uspelo"], - "Failed": ["Ni uspelo"], - "Running": ["V teku"], - "fetching": ["pridobivam"], - "Offline": ["Offline"], - "Scheduled": ["V urniku"], - "Unknown Status": ["Neznan status"], - "Edit": ["Urejanje"], - "View results": ["Ogled rezultatov"], - "Data preview": ["Ogled podatkov"], - "Overwrite text in the editor with a query on this table": [ - "Besedilo v urejevalniku prepišite s poizvedbo na to tabelo" + "D3 format": ["D3 format"], + "Fraction digits": ["Število decimalk"], + "Number of decimal digits to round numbers to": [ + "Število decimalnih mest za zaokroževanje števil" ], - "Run query in a new tab": ["Zaženi poizvedbo v novem zavihku"], - "Remove query from log": ["Odstrani poizvedbo iz dnevnika"], - "An error occurred saving dataset": [ - "Pri shranjevanju podatkovnega seta je prišlo do napake" + "Min Width": ["Min. širina"], + "Default minimal column width in pixels, actual width may still be larger than this if other columns don't need much space": [ + "Privzeta min. širina stolpca v pikslih. Dejanska širina bo lahko večja, če drugi stolpci ne potrebujejo veliko prostora" ], - "Download to CSV": ["Izvozi kot CSV"], - "Copy to Clipboard": ["Kopiraj na odložišče"], - "Filter results": ["Filtriraj rezultate"], - "The number of results displayed is limited to %(rows)d by the configuration DISPLAY_MAX_ROWS. ": [ - "Število prikazanih rezultatov je omejeno na %(rows)d preko parametra DISPLAY_MAX_ROWS. " + "Text align": ["Poravnava besedila"], + "Horizontal alignment": ["Vodoravna poravnava"], + "Left": ["Levo"], + "Center": ["Na sredino"], + "Right": ["Desno"], + "Show cell bars": ["Prikaži stolp. graf v celicah"], + "Whether to display a bar chart background in table columns": [ + "Če želite omogočiti prikaz manjših stolpčnih grafikonov v ozadju stolpcev tabele" ], - "Please add additional limits/filters or download to csv to see more rows up to ": [ - "Dodajte omejitve/filtre ali izvozite csv, če želite videti več vrstic do " + "Align +/-": ["Poravnaj +/-"], + "Whether to align positive and negative values in cell bar chart at 0": [ + "Če želite poravnati pozitivne in negativne vrednosti v stolpčnem grafikonu celic pri 0" ], - "the %(limit)d limit.": ["omejitve %(limit)d ."], - "The number of results displayed is limited to %(rows)d. ": [ - "Število prikazanih rezultatov je omejeno na %(rows)d. " + "Color +/-": ["Barva +/-"], + "Whether to colorize numeric values by if they are positive or negative": [ + "Če želite obarvati številske vrednosti, ko so le-te pozitivne ali negativne" ], - "Please add additional limits/filters, download to csv, or contact an admin ": [ - "Dodajte omejitve/filtre ali izvozite csv oz. kontaktirajte administratorja " + "Small number format": ["Oblika zapisa majhnih števil"], + "D3 number format for numbers between -1.0 and 1.0, useful when you want to have different siginificant digits for small and large numbers": [ + "D3 oblika zapisa za števila med -1.0 in 1.0. Uporabno, če želite različno število števk za majhna in velika števila" ], - "to see more rows up to the %(limit)d limit.": [ - "za prikaz več vrstic, kot je omejitev %(limit)d ." + "D3 format syntax: https://github.com/d3/d3-format": [ + "Sintaksa D3 formata: https://github.com/d3/d3-format" ], - "The number of rows displayed is limited to %(rows)d by the query": [ - "Število prikazanih vrstic je omejeno na %(rows)d s poizvedbo" + "Adaptive formatting": ["Adaptivno oblikovanje"], + "Duration in ms (66000 => 1m 6s)": ["Trajanje v ms (66000 => 1m 6s)"], + "Duration in ms (1.40008 => 1ms 400µs 80ns)": [ + "Trajanje v ms (1.40008 => 1ms 400µs 80ns)" ], - "The number of rows displayed is limited to %(rows)d by the limit dropdown.": [ - "Število prikazanih rezultatov je omejeno na %(rows)d s poizvedbo." + "D3 time format syntax: https://github.com/d3/d3-time-format": [ + "Sintaksa D3 časovnega formata:: https://github.com/d3/d3-time-format" ], - "The number of rows displayed is limited to %(rows)d by the query and limit dropdown.": [ - "Število prikazanih vrstic je omejeno na %(rows)d s poizvedbo in spustnim izbirnikom omejitev." + "No results were returned for this query. If you expected results to be returned, ensure any filters are configured properly and the datasource contains data for the selected time range.": [ + "Poizvedba ni vrnila rezultatov. Če ste pričakovali rezultate, poskrbite, da so filtri pravilno nastavljeni in podatkovni vir vsebuje podatke za izbrano časovno obdobje." ], - "%(rows)d rows returned": ["%(rows)d vrnjenih vrstic"], - "The number of rows displayed is limited to %s by the dropdown.": [ - "Število prikazanih vrstic je omejeno na %s s spustnim izbirnikom." + "No Results": ["Ni rezultatov"], + "Found invalid orderby options": [ + "Najdene so neveljavne možnosti razvrščanja" ], - "Query was stopped": ["Poizvedba je bila ustavljena"], - "Database error": ["Napaka podatkovne baze"], - "was created": ["ustvarjeno"], - "Query in a new tab": ["Poizvedba v novem zavihku"], - "The query returned no data": ["Poizvedba ni vrnila podatkov"], - "Fetch data preview": ["Pridobi predogled podatkov"], - "Refetch results": ["Ponovno pridobi rezultate"], - "Track job": ["Sledi opravilom"], - "Stop": ["Ustavi"], - "Run selection": ["Zaženi izbrano"], - "Run": ["Zaženi"], - "Stop running (Ctrl + x)": ["Ustavi (Ctrl + x)"], - "Stop running (Ctrl + e)": ["Ustavi (Ctrl + e)"], - "Run query (Ctrl + Return)": ["Zaženi poizvedbo (Ctrl + Return)"], - "Save & Explore": ["Shrani & Razišči"], - "Overwrite & Explore": ["Prepiši & Razišči"], - "Undefined": ["Ni definirano"], - "Save": ["Shrani"], - "Save as": ["Shrani kot"], - "Save query": ["Shrani poizvedbo"], - "Save as new": ["Shrani kot novo"], - "Update": ["Posodobi"], - "Label for your query": ["Ime vaše poizvedbe"], - "Write a description for your query": ["Dodajte opis vaše poizvedbe"], - "Schedule query": ["Urnik poizvedb"], - "Schedule": ["Urnik"], - "There was an error with your request": [ - "Pri zahtevi je prišlo do napake" + "is expected to be an integer": ["pričakovano je celo število"], + "is expected to be a number": ["pričakovano je število"], + "cannot be empty": ["ne sme biti prazno"], + "Query": ["Poizvedba"], + "Domain": ["Domena"], + "The time unit used for the grouping of blocks": [ + "Časovna enota za združevanje blokov" ], - "Please save the query to enable sharing": [ - "Shranite poizvedbo za deljenje" + "Subdomain": ["Poddomena"], + "The time unit for each block. Should be a smaller unit than domain_granularity. Should be larger or equal to Time Grain": [ + "Časovna enota za vsak blok. Mora biti manjša enota kot domenska_granulacija. Mora biti večja ali enaka Granulaciji časa" ], - "Copy query link to your clipboard": [ - "Kopiraj povezavo do poizvedbe v odložišče" + "Chart Options": ["Možnosti grafikona"], + "Cell Size": ["Velikost celice"], + "The size of the square cell, in pixels": [ + "Velikost kvadratne celice v pikslih" ], - "Save the query to enable this feature": [ - "Za omogočenje te funkcije shranite poizvedbo" + "Cell Padding": ["Razmak med celicami"], + "The distance between cells, in pixels": [ + "Razdalja med celicami v pikslih" ], - "Copy link": ["Kopiraj povezavo"], - "No stored results found, you need to re-run your query": [ - "Rezultatov še ni shranjenih, ponovno morate zagnati poizvedbo" + "Cell Radius": ["Polmer celice"], + "The pixel radius": ["Polmer piksla"], + "Color Steps": ["Barvni koraki"], + "The number color \"steps\"": ["Število barvnih korakov"], + "Time Format": ["Oblika zapisa časa"], + "Legend": ["Legenda"], + "Whether to display the legend (toggles)": [ + "Preklapljanje prikaza legende" ], - "Run a query to display results here": [ - "Za prikaz rezultatov morate zagnati poizvedbo" + "Show Values": ["Pokaži vrednosti"], + "Whether to display the numerical values within the cells": [ + "Če želite v celicah prikazati numerične vrednosti" ], - "Preview: `%s`": ["Predogled: `%s`"], - "Results": ["Rezultati"], - "Query history": ["Zgodovina poizvedb"], - "Run query": ["Zaženi poizvedbo"], - "New tab": ["Nov zavihek"], - "Untitled query": ["Neimenovana poizvedba"], - "Stop query": ["Ustavi poizvedbo"], - "Schedule the query periodically": ["Periodično zaganjaj poizvedbo"], - "You must run the query successfully first": [ - "Najprej morate uspešno izvesti poizvedbo" + "Show Metric Names": ["Pokaži imena mer"], + "Whether to display the metric name as a title": [ + "Če želite prikazati ime mere kot naslov" ], - "Autocomplete": ["Samodokončaj"], - "CREATE TABLE AS": ["CREATE TABLE AS"], - "CREATE VIEW AS": ["CREATE VIEW AS"], - "Estimate the cost before running a query": [ - "Oceni potratnost pred zagonom poizvedbe" + "Number Format": ["Oblika zapisa števila"], + "Correlation": ["Korelacija"], + "Visualizes how a metric has changed over a time using a color scale and a calendar view. Gray values are used to indicate missing values and the linear color scheme is used to encode the magnitude of each day's value.": [ + "Prikaže kako se je mera spreminjala s časom s pomočjo barvne lestvice in koledarskega pogleda. Sive vrednosti ponazarjajo manjkajoče vrednosti. Amplituda dnevnih vrednosti je ponazorjena z linearno barvno shemo." ], - "${isActive ? 'Collapse' : 'Expand'} table preview": [ - "${isActive ? 'Collapse' : 'Expand'} predogled tabele" + "Business": ["Aktivnost"], + "Comparison": ["Primerjava"], + "Intensity": ["Intenzivnost"], + "Pattern": ["Vzorec"], + "Report": ["Poročilo"], + "Trend": ["Trend"], + "Sort by metric": ["Mera za razvrščanje"], + "Whether to sort results by the selected metric in descending order.": [ + "Če želite padajoče razvrstiti rezultate z izbrano mero." ], - "Reset state": ["Ponastavi stanje"], - "Enter a new title for the tab": ["Vnesite novo naslov zavihka"], - "Untitled Query %s": ["Neimenovana poizvedba %s"], - "Close tab": ["Zapri zavihek"], - "Rename tab": ["Preimenuj zavihek"], - "Expand tool bar": ["Razširi orodno vrstico"], - "Hide tool bar": ["Skrij orodno vrstico"], - "Close all other tabs": ["Zapri vse ostale zavihke"], - "Duplicate tab": ["Podvoji zavihek"], - "New tab (Ctrl + q)": ["Nov zavihek (Ctrl + q)"], - "New tab (Ctrl + t)": ["Nov zavihek (Ctrl + t)"], - "Copy partition query to clipboard": [ - "Kopiraj particijsko poizvedbo na odložišče" + "Number format": ["Oblika zapisa števila"], + "Choose a number format": ["Izberite obliko zapisa števila"], + "Source": ["Izvor"], + "Choose a source": ["Izberite izvor"], + "Target": ["Cilj"], + "Choose a target": ["Izberite cilj"], + "Flow": ["Potek"], + "Showcases the flow or link between categories using thickness of chords. The value and corresponding thickness can be different for each side.": [ + "Prikaže potek ali povezave med kategorijami z debelino tetiv. Vrednost in debelina sta lahko različni za vsako stran." ], - "latest partition:": ["zadnja particija:"], - "Keys for table": ["Ključi za tabele"], - "View keys & indexes (%s)": ["Ogled ključev in indeksov (%s)"], - "Original table column order": ["Vrstni red stolpcev izvorne tabele"], - "Sort columns alphabetically": ["Razvrsti stolpce po abecedi"], - "Copy SELECT statement to the clipboard": [ - "Kopiraj stavek SELECT na odložišče" + "Relationships between community channels": [ + "Razmerja med skupnostnimi kanali" ], - "Show CREATE VIEW statement": ["Prikaži CREATE VIEW stavek"], - "CREATE VIEW statement": ["CREATE VIEW stavek"], - "Remove table preview": ["Odstrani predogled tabele"], - "Edit template parameters": ["Uredi parametre predloge"], - "Invalid JSON": ["Neveljaven JSON"], - "Create a new chart": ["Ustvari nov grafikon"], - "Choose a dataset": ["Izberite podatkovni set"], - "Dataset": ["Podatkovni set"], - "Instructions to add a dataset are available in the Superset tutorial.": [ - "Navodila za dodajanje podatkovnega seta so v vodiču za Superset." + "Chord Diagram": ["Tetivni grafikon"], + "Aesthetic": ["Estetika"], + "Circular": ["Krožno"], + "Legacy": ["Staro"], + "Proportional": ["Proporcionalno"], + "Relational": ["Relacijsko"], + "Country": ["Država"], + "Which country to plot the map for?": [ + "Za katero državo želite grafikon?" ], - "Choose chart type": ["Izberite tip grafikona"], - "Please select both a Dataset and a Chart type to proceed": [ - "Za nadaljevanje izberite podatkovni set in tip grafikona" + "ISO 3166-2 Codes": ["Oznake po ISO 3166-2"], + "Column containing ISO 3166-2 codes of region/province/department in your table.": [ + "Stolpec, ki vsebuje ISO 3166-2 oznake regij/provinc/departmajev v vaši tabeli." + ], + "Metric to display bottom title": ["Mera za prikaz spodnjega naslova"], + "Map": ["Zemljevid"], + "Visualizes how a single metric varies across a country's principal subdivisions (states, provinces, etc) on a chloropleth map. Each subdivision's value is elevated when you hover over the corresponding geographic boundary.": [ + "Prikaže kako se posamezna mera spreminja glede na območja države (dežele, province, itd.) na kloropletnem zemljevidu. Vsak podrazdelek se dvigne, ko z miško preidete mejo njegovega območja." + ], + "2D": ["2D"], + "Geo": ["Geo"], + "Range": ["Doseg"], + "Stacked": ["Naložen"], + "Sorry, there appears to be no data": ["Ni podatkov"], + "Event definition": ["Definicija dogodka"], + "Event Names": ["Imena dogodkov"], + "Columns to display": ["Stolpci za prikaz"], + "Order by entity id": ["Uredi po ID entitete"], + "Important! Select this if the table is not already sorted by entity id, else there is no guarantee that all events for each entity are returned.": [ + "Pomembno! Izberite, če tabela še ni razvrščena po ID entitete, v nasprotnem primeru ni nujno, da bodo vrnjeni vsi dogodki za posamezno entiteto." + ], + "Minimum leaf node event count": ["Min. število dogodkov za list"], + "Leaf nodes that represent fewer than this number of events will be initially hidden in the visualization": [ + "Listna vozlišča, ki predstavljajo manjše število dogodkov od te vrednosti, bodo v vizualizaciji skrita" + ], + "Additional metadata": ["Dodatni metapodatki"], + "Metadata": ["Metapodatki"], + "Select any columns for metadata inspection": [ + "Izberite poljubne stolpce za pregled metapodatkov" + ], + "Entity ID": ["ID entitete"], + "e.g., a \"user id\" column": ["t.j. stolpec \"id uporabnika\""], + "Max Events": ["Max. dogodkov"], + "The maximum number of events to return, equivalent to the number of rows": [ + "Največje število dogodkov, ki bodo vrnjeni - enako številu vrstic" + ], + "Compares the lengths of time different activities take in a shared timeline view.": [ + "Primerja dolžine časovno različnih aktivnosti na skupni časovnici." + ], + "Event Flow": ["Potek dogodkov"], + "Progressive": ["Progresivno"], + "Axis ascending": ["Naraščajoča os"], + "Axis descending": ["Padajoča os"], + "Metric ascending": ["Naraščajoča mera"], + "Metric descending": ["Padajoča mera"], + "Heatmap Options": ["Možnosti toplotnega prikaza"], + "XScale Interval": ["Interval X-osi"], + "Number of steps to take between ticks when displaying the X scale": [ + "Število korakov med oznakami pri prikazu X-osi" + ], + "YScale Interval": ["Interval Y-osi"], + "Number of steps to take between ticks when displaying the Y scale": [ + "Število korakov med oznakami pri prikazu Y-osi" + ], + "Rendering": ["Izris"], + "image-rendering CSS attribute of the canvas object that defines how the browser scales up the image": [ + "atribut CSS za izris objekta platna, ki določa, kako brskalnik poveča sliko" + ], + "Normalize Across": ["Normiraj glede na"], + "Color will be rendered based on a ratio of the cell against the sum of across this criteria": [ + "Barva bo prikazana na osnovi razmerja med celico in vsoto glede na ta kriterij" + ], + "Left Margin": ["Levi rob"], + "Left margin, in pixels, allowing for more room for axis labels": [ + "Levi rob, v pikslih, s katerim povečamo prostor za oznake osi" + ], + "Bottom Margin": ["Spodnji rob"], + "Bottom margin, in pixels, allowing for more room for axis labels": [ + "Spodnji rob, v pikslih, s katerim povečamo prostor za oznake osi" + ], + "Value bounds": ["Meje vrednosti"], + "Hard value bounds applied for color coding. Is only relevant and applied when the normalization is applied against the whole heatmap.": [ + "Mejne vrednosti za barvno lestvico. Upošteva se le, če je normiranje uporabljeno glede na celotni toplotni prikaz." + ], + "Sort X Axis": ["Razvrsti X-os"], + "Sort Y Axis": ["Razvrsti Y-os"], + "Show percentage": ["Prikaži procente"], + "Whether to include the percentage in the tooltip": [ + "Če želite prikaz procentov v opisu orodja" + ], + "Normalized": ["Normiran"], + "Whether to apply a normal distribution based on rank on the color scale": [ + "Če želite uporabiti normalno porazdelitev glede na stopnjo na barvni lestvici" + ], + "Value Format": ["Oblika zapisa vrednosti"], + "Visualize a related metric across pairs of groups. Heatmaps excel at showcasing the correlation or strength between two groups. Color is used to emphasize the strength of the link between each pair of groups.": [ + "Vizualizacija povezanih mer med pari skupin." + ], + "Sizes of vehicles": ["Velikosti vozil"], + "Employment and education": ["Zaposlitev in izobrazba"], + "Density": ["Gostota"], + "Predictive": ["Prediktivno"], + "Single Metric": ["Ena mera"], + "count": ["število"], + "cumulative": ["kumulativno"], + "percentile (exclusive)": ["percentil (ekskluzivno)"], + "Select the numeric columns to draw the histogram": [ + "Izberite numerične stolpce za izris histograma" + ], + "No of Bins": ["Št. razdelkov"], + "Select the number of bins for the histogram": [ + "Izberite število razdelkov za histogram" + ], + "X Axis Label": ["Naslov X osi"], + "Y Axis Label": ["Naslov Y osi"], + "Whether to normalize the histogram": ["Če želite normirati histogram"], + "Cumulative": ["Kumulativno"], + "Whether to make the histogram cumulative": [ + "Če želite kumulativni histogram" + ], + "Distribution": ["Porazdelitev"], + "Take your data points, and group them into \"bins\" to see where the densest areas of information lie": [ + "Vzame podatkovne točke in jih razporedi v razdelke, kjer se vidi območja z največjo gostoto informacij" + ], + "Population age data": ["Podatki starosti populacije"], + "Contribution": ["Prispevek"], + "Compute the contribution to the total": ["Izračunaj prispevek k celoti"], + "Series Height": ["Višina serije"], + "Pixel height of each series": ["Višina vsake serije v pikslih"], + "Value Domain": ["Domena vrednosti"], + "series: Treat each series independently; overall: All series use the same scale; change: Show changes compared to the first data point in each series": [ + "serije: Obravnavaj vsako podatkovno serijo neodvisno; skupno: Vse vrste uporabljajo enako skalo; razlika: Pokaži razlike glede na prvo točko vsake serije" + ], + "Compares how a metric changes over time between different groups. Each group is mapped to a row and change over time is visualized bar lengths and color.": [ + "Primerja kako se mera spreminja s časom med različnimi skupinami. Vsaka skupina predstavlja eno vrstico, časovne spremembe pa so prikazane z dolžino stolpcev in barvami." + ], + "Horizon Chart": ["Horizontni grafikon"], + "Longitude": ["Dolžina"], + "Column containing longitude data": [ + "Stolpec s podatki zemljepisne dolžine" + ], + "Latitude": ["Širina"], + "Column containing latitude data": [ + "Stolpec s podatki zemljepisne širine" + ], + "Clustering Radius": ["Radij gručenja"], + "The radius (in pixels) the algorithm uses to define a cluster. Choose 0 to turn off clustering, but beware that a large number of points (>1000) will cause lag.": [ + "Radij (v pikslih), s katerim algoritem definira gručo. Izberite 0 za izklop gručenja - veliko število točk (>1000) bo povzročilo upočasnitev." + ], + "Points": ["Točke"], + "Point Radius": ["Radij točk"], + "The radius of individual points (ones that are not in a cluster). Either a numerical column or `Auto`, which scales the point based on the largest cluster": [ + "Radij posameznih točk (tistih, ki niso v gruči). Numerični stolpec ali `Auto` (skalira točke na osnovi največje gruče)" + ], + "Point Radius Unit": ["Enota radija točk"], + "The unit of measure for the specified point radius": [ + "Enota merila za definiran radij točk" + ], + "Labelling": ["Oznake"], + "label": ["oznaka"], + "`count` is COUNT(*) if a group by is used. Numerical columns will be aggregated with the aggregator. Non-numerical columns will be used to label points. Leave empty to get a count of points in each cluster.": [ + "`število` je COUNT(*), če je uporabljeno združevanje (group by). Numerični stolpci bodo agregirani z agregatorjem. Ne-numerični stolpci, bodo uporabljeni za oznake točk. Pustite prazno, da dobite število točk v posamezni gruči." + ], + "Cluster label aggregator": ["Agregator za oznako gruče"], + "Aggregate function applied to the list of points in each cluster to produce the cluster label.": [ + "Agregacijska funkcija za seznam točk v vsaki gruči, s katero se ustvari oznaka gruče." + ], + "Visual Tweaks": ["Nastavitve izgleda"], + "Live render": ["Sprotni izris"], + "Points and clusters will update as the viewport is being changed": [ + "Točke in gruče se bodo posodabljale, če se bo spremenil pogled" + ], + "Map Style": ["Slog zemljevida"], + "Base layer map style": ["Slog osnovnega sloja zemljevida"], + "Opacity": ["Prosojnost"], + "Opacity of all clusters, points, and labels. Between 0 and 1.": [ + "Prosojnost vseh gruč, točk in oznak (vrednost med 0 in 1)." + ], + "RGB Color": ["RGB barva"], + "The color for points and clusters in RGB": [ + "Barva točk in gruč v RGB zapisu" + ], + "Viewport": ["Pogled"], + "Default longitude": ["Privzeta dolžina"], + "Longitude of default viewport": ["Dolžina privzetega pogleda"], + "Default latitude": ["Privzeta širina"], + "Latitude of default viewport": ["Širina privzetega pogleda"], + "Zoom": ["Povečava"], + "Zoom level of the map": ["Stopnja povečave zemljevida"], + "One or many controls to group by. If grouping, latitude and longitude columns must be present.": [ + "Eden ali več kontrolnikov za združevanje. Pri združevanju morata biti prisotna stolpca širine in dolžine." + ], + "Light mode": ["Svetli način"], + "Dark mode": ["Temni način"], + "MapBox": ["MapBox"], + "Scatter": ["Raztreseni"], + "Transformable": ["Prilagodljiv"], + "Significance Level": ["Stopnja značilnosti"], + "Threshold alpha level for determining significance": [ + "Mejna vrednost alfa za določanje značilnosti" + ], + "p-value precision": ["točnost p-vrednosti"], + "Number of decimal places with which to display p-values": [ + "Število decimalnih mest za prikaz p-vrednosti" + ], + "Lift percent precision": ["Točnost procentualnega dviga"], + "Number of decimal places with which to display lift values": [ + "Število decimalnih mest za prikaz vrednosti dviga" + ], + "Table that visualizes paired t-tests, which are used to understand statistical differences between groups.": [ + "Tabela, ki prikazuje uparjene t-teste, ki se uporabljajo za prikaz statističnih razlik med skupinami." + ], + "Paired t-test Table": ["Tabela t-testa za odvisne vzorce"], + "Statistical": ["Statistično"], + "Tabular": ["Tabelarično"], + "Options": ["Možnosti"], + "Data Table": ["Tabela podatkov"], + "Whether to display the interactive data table": [ + "Če želite prikaz interaktivne podatkovne tabele" + ], + "Include Series": ["Vključi serijo"], + "Include series name as an axis": [ + "Vključi ime podatkovne serije v naslov osi" + ], + "Ranking": ["Rangiranje"], + "Plots the individual metrics for each row in the data vertically and links them together as a line. This chart is useful for comparing multiple metrics across all of the samples or rows in the data.": [ + "Izriše posamezne mere za vsako vrstico podatkov navpično in jih med seboj poveže kot črto. Grafikon je uporaben za primerjavo več mer med vsemi vzorci ali vrsticami podatkov." + ], + "Coordinates": ["Koordinate"], + "Directional": ["Usmerjeni"], + "Time Series Options": ["Možnosti časovne vrste"], + "Not Time Series": ["Ni časovna vrsta"], + "Ignore time": ["Ne upoštevaj časa"], + "Time Series": ["Časovna vrsta"], + "Standard time series": ["Standardna časovna vrsta"], + "Aggregate Mean": ["Agregirano povprečje"], + "Mean of values over specified period": [ + "Povprečna vrednost v dani periodi" + ], + "Aggregate Sum": ["Agregirana vsota"], + "Sum of values over specified period": ["Vsota vrednosti v dani periodi"], + "Difference": ["Razlika"], + "Metric change in value from `since` to `until`": [ + "Sprememba mere od vrednosti \"OD\" do \"DO\"" + ], + "Percent Change": ["Procentualna sprememba"], + "Metric percent change in value from `since` to `until`": [ + "Procentualna sprememba mere od vrednosti \"OD\" do \"DO\"" + ], + "Factor": ["Faktor"], + "Metric factor change from `since` to `until`": [ + "Sprememba faktorja mere od vrednosti \"OD\" do \"DO\"" + ], + "Advanced Analytics": ["Napredna analitika"], + "Use the Advanced Analytics options below": [ + "Uporabite spodnje možnosti napredne analitike" + ], + "Settings for time series": ["Nastavitve časovne vrste"], + "Date Time Format": ["Oblika zapisa Datum-Časa"], + "Partition Limit": ["Omejitev particij"], + "The maximum number of subdivisions of each group; lower values are pruned first": [ + "Največje število podrazdelkov posamezne skupine; nižje vrednosti so zanemarjene prve" + ], + "Partition Threshold": ["Prag particije"], + "Partitions whose height to parent height proportions are below this value are pruned": [ + "Particije z nižjim razmerjem med njihovo višino in dolžino starša so zanemarjene" + ], + "Log Scale": ["Logaritemska skala"], + "Use a log scale": ["Uporabi logaritemsko skalo"], + "Equal Date Sizes": ["Enaki datumi"], + "Check to force date partitions to have the same height": [ + "Če želite, da imajo datumske particije enako višino" + ], + "Rich Tooltip": ["Podroben opis orodja"], + "The rich tooltip shows a list of all series for that point in time": [ + "Podroben opis orodja prikaže seznam vseh podatkovnih serij za posamezno časovno točko" + ], + "Rolling Window": ["Drseče okno"], + "Rolling Function": ["Drseča funkcija"], + "Min Periods": ["Min. št. period"], + "Time Comparison": ["Časovna primerjava"], + "Time Shift": ["Časovni zamik"], + "Method": ["Metoda"], + "Part of a Whole": ["Del celote"], + "Compare the same summarized metric across multiple groups.": [ + "Primerja isto mero med različnimi skupinami." ], - "Create new chart": ["Ustvari nov grafikon"], - "An error occurred while loading the SQL": [ - "Pri nalaganju SQL je prišlo do napake" + "Partition Chart": ["Grafikon razdelkov"], + "Categorical": ["Kategorični"], + "Pivot Options": ["Vrtilne možnosti"], + "Aggregation function": ["Agregacijska funkcija"], + "Aggregate function to apply when pivoting and computing the total rows and columns": [ + "Agregacijska funkcija za vrtenje in izračun vseh vrstic in stolpcev" ], - "Updating chart was stopped": [ - "Posodabljanje grafikona je bilo ustavljeno" + "Show totals": ["Pokaži vsote"], + "Display total row/column": ["Pokaži vsote vrstic/stolpcev"], + "Combine Metrics": ["Združuj mere"], + "Display metrics side by side within each column, as opposed to each column being displayed side by side for each metric.": [ + "Prikazuj mere eno ob drugi ob vsakem stolpcu, drugače je vsak stolpec prikazan en ob drugem za vsako mero." ], - "An error occurred while rendering the visualization: %s": [ - "Pri prikazovanju vizualizacije je prišlo do napake: %s" + "Transpose Pivot": ["Transponirano vrtenje"], + "Swap Groups and Columns": ["Zamenjaj Skupine in Stolpce"], + "Date format": ["Oblika zapisa datuma"], + "Used to summarize a set of data by grouping together multiple statistics along two axes. Examples: Sales numbers by region and month, tasks by status and assignee, active users by age and location.\n\n This chart is being deprecated and we recommend checking out Pivot Table V2 instead!": [ + "Uporablja se za predstavitev podatkov z združevanjem različnih statistik na dveh oseh. Npr. Prodaja po regijah in mesecih, Naloge po statusih in izvajalcih, aktivni uporabniki po starosti in lokaciji.\n\n Ta grafikon se opušča. Priporočamo uporabo Vrtilne tabele V2!" ], - "Network error.": ["Napaka omrežja."], - "Click to see difference": ["Kliknite za prikaz razlike"], - "Altered": ["Spremenjeno"], - "Chart changes": ["Spremembe grafikona"], - "Superset chart": ["Superset grafikon"], - "Check out this chart in dashboard:": [ - "Preizkusite ta grafikon v nadzorni plošči:" + "Use Area Proportions": ["Uporabi razmerje površin"], + "Check if the Rose Chart should use segment area instead of segment radius for proportioning": [ + "Če želite, da grafikon \"Rose\" uporablja površino segmenta namesto radija za proporcioniranje" ], - "Select ...": ["Izberite ..."], - "Loaded data cached": ["Podatki so naloženi v predpomnilnik"], - "Loaded from cache": ["Naloženo iz predpomnilnika"], - "Click to force-refresh": ["Kliknite za prisilno osvežitev"], - "cached": ["predpomnjen"], - "Certified by %s": ["Certificiral/a %s"], - "Copy to clipboard": ["Kopiraj na odložišče"], - "Copied to clipboard!": ["Kopirano na odložišče!"], - "Sorry, your browser does not support copying. Use Ctrl / Cmd + C!": [ - "Vaš brskalnik ne podpira kopiranja. Uporabite Ctrl / Cmd + C!" + "A polar coordinate chart where the circle is broken into wedges of equal angle, and the value represented by any wedge is illustrated by its area, rather than its radius or sweep angle.": [ + "Grafikon s polarnimi koordinatami, kjer je krog razdeljen na enakokotne izseke, vrednosti pa so ponazorjene s ploščino izseka (namesto polmera ali kota)." ], - "every": ["vsak"], - "every month": ["vsak mesec"], - "every day of the month": ["vsak dan v mesecu"], - "day of the month": ["dan v mesecu"], - "every day of the week": ["vsak dan v tednu"], - "day of the week": ["dan v tednu"], - "every hour": ["vsako uro"], - "every minute": ["vsako minuto"], - "year": ["leto"], - "month": ["mesec"], - "week": ["teden"], - "day": ["dan"], - "hour": ["ura"], - "minute": ["minuta"], - "reboot": ["ponovni zagon"], - "Every": ["Vsak"], - "in": ["v"], - "on": ["v"], - "and": ["in"], - "at": ["ob"], - ":": [":"], - "minute(s)": ["minuta/e"], - "Invalid cron expression": ["Neveljaven cron izraz"], - "Clear": ["Počisti"], - "Sunday": ["Nedelja"], - "Monday": ["Ponedeljek"], - "Tuesday": ["Torek"], - "Wednesday": ["Sreda"], - "Thursday": ["Četrtek"], - "Friday": ["Petek"], - "Saturday": ["Sobota"], - "January": ["Januar"], - "February": ["Februar"], - "March": ["Marec"], - "April": ["April"], - "May": ["Maj"], - "June": ["Junij"], - "July": ["Julij"], - "August": ["Avgust"], - "September": ["September"], - "October": ["Oktober"], - "November": ["November"], - "December": ["December"], - "SUN": ["NED"], - "MON": ["PON"], - "TUE": ["TOR"], - "WED": ["SRE"], - "THU": ["ČET"], - "FRI": ["PET"], - "SAT": ["SOB"], - "JAN": ["JAN"], - "FEB": ["FEB"], - "MAR": ["MAR"], - "APR": ["APR"], - "MAY": ["MAJ"], - "JUN": ["JUN"], - "JUL": ["JUL"], - "AUG": ["AVG"], - "SEP": ["SEP"], - "OCT": ["OKT"], - "NOV": ["NOV"], - "DEC": ["DEC"], - "There was an error loading the schemas": ["Napaka pri nalaganju shem"], - "Select database or type database name": [ - "Izberite ali vnesite ime podatkovne baze" + "Nightingale Rose Chart": ["Nightingale Rose grafikon"], + "Advanced-Analytics": ["Napredna analitika"], + "Multi-Layers": ["Večplastni"], + "Source / Target": ["Izhodišče/Cilj"], + "Choose a source and a target": ["Izberite izhodišče in cilj"], + "Limiting rows may result in incomplete data and misleading charts. Consider filtering or grouping source/target names instead.": [ + "Omejitev vrstic lahko povzroči nepopolne podatke in zavajajoč grafikon. Premislite o uporabi filtriranja ali združevanja imen izvorov/ciljev." ], - "Force refresh schema list": ["Osveži seznam shem"], - "Select schema or type schema name": ["Izberite ali vnesite ime sheme"], - "Warning! Changing the dataset may break the chart if the metadata does not exist.": [ - "Opozorilo! Sprememba podatkovnega seta lahko pokvari grafikon, če metapodatki ne obstajajo." + "Visualizes the flow of different group's values through different stages of a system. New stages in the pipeline are visualized as nodes or layers. The thickness of the bars or edges represent the metric being visualized.": [ + "Prikaže potek vrednosti različnih skupin na različnih nivojih sistema. Novi nivoji so prikazani kot točke ali plasti. Debelina stolpcev ali povezav predstavlja prikazano mero." ], - "Changing the dataset may break the chart if the chart relies on columns or metadata that does not exist in the target dataset": [ - "Sprememba podatkovnega seta lahko pokvari grafikon, če se le-ta zanaša na stolpce ali metapodatke, ki ne obstajajo v ciljnem podatkovnem nizu" + "Demographics": ["Demografija"], + "Survey Responses": ["Rezultati anket"], + "Sankey Diagram": ["Sankey grafikon"], + "Percentages": ["Procenti"], + "Sankey Diagram with Loops": ["Sankey grafikon z zankami"], + "Primary Metric": ["Primarna mera"], + "The primary metric is used to define the arc segment sizes": [ + "Primarna mera določa velikost lokov segmentov" ], - "dataset": ["podatkovni set"], - "Connection": ["Povezava"], - "Change dataset": ["Spremeni podatkovni set"], - "Warning!": ["Opozorilo!"], - "Search / Filter": ["Iskanje / Filter"], - "Physical (table or view)": ["Fizičen (tabela ali pogled)"], - "Virtual (SQL)": ["Virtualen (SQL)"], - "SQL expression": ["SQL izraz"], - "Data type": ["Tip podatka"], - "Datetime format": ["Oblika datum-časa"], - "The pattern of timestamp format. For strings use ": [ - "Vzorec zapisa časovne značke. Za znakovne nize uporabite " + "Secondary Metric": ["Sekundarna mera"], + "[optional] this secondary metric is used to define the color as a ratio against the primary metric. When omitted, the color is categorical and based on labels": [ + "[opcijsko] sekundarna mera določa barvo kot razmerje do primarne mere. Če je izpuščena, je barva določena kategorično na podlagi oznak" ], - "Python datetime string pattern": ["Pythonov vzorec zapisa datum-časa"], - " expression which needs to adhere to the ": [" , ki mora upoštevati "], - "ISO 8601": ["ISO 8601"], - " standard to ensure that the lexicographical ordering\r\n coincides with the chronological ordering. If the\r\n timestamp format does not adhere to the ISO 8601 standard\r\n you will need to define an expression and type for\r\n transforming the string into a date or timestamp. Note\r\n currently time zones are not supported. If time is stored\r\n in epoch format, put `epoch_s` or `epoch_ms`. If no pattern\r\n is specified we fall back to using the optional defaults on a per\r\n database/column name level via the extra parameter.": [ - " standard, ki zagotavlja, de se leksikografsko razvrščanje\r\n sklada s kronološkim razvrščanjem. Če oblika\r\n časovne značke ni v skladu s standardom ISO 8601,\r\n boste morali definirati izraz in tip za transformacijo\r\n znakovnega niza v datum ali časovno značko.\r\n Trenutno časovni pasovi niso podprti.\r\n Če je čas shranjen v obliki epohe, dodajte `epoch_s` ali `epoch_ms`.\r\n Če ni podan vzorec, se uporabijo privzete vrednosti na podlagi imena\r\n podatkovne baze oz. stolpca s pomočjo dodatnega parametra." + "When only a primary metric is provided, a categorical color scale is used.": [ + "Če je podana samo primarna metrika, je uporabljena kategorična barvna skala." ], - "Certified By": ["Certificiral/a"], - "Person or group that has certified this metric": [ - "Oseba ali skupina, ki je certificirala to mero" + "When a secondary metric is provided, a linear color scale is used.": [ + "Če je podana sekundarna metrika, je uporabljena linearna barvna skala." ], - "Certified by": ["Certificiral/a"], - "Certification details": ["Podrobnosti certifikacije"], - "Details of the certification": ["Podrobnosti certifikacije"], - "Is dimension": ["Dimenzija"], - "Is filterable": ["Filtriranje"], - "Select owners": ["Izberite lastnike"], - "Modified columns: %s": ["Spremenjeni stolpci: %s"], - "Removed columns: %s": ["Odstranjeni stolpci: %s"], - "New columns added: %s": ["Dodani novi stolpci: %s"], - "Metadata has been synced": ["Metapodatki so sinhronizirani"], - "An error has occurred": ["Prišlo je do napake"], - "Column name [%s] is duplicated": ["Ime stolpca [%s] je podvojeno"], - "Metric name [%s] is duplicated": ["Ime mere [%s] je podvojeno"], - "Calculated column [%s] requires an expression": [ - "Izračunan stolpec [%s] zahteva izraz" + "Hierarchy": ["Hierarhija"], + "This defines the level of the hierarchy": ["Določa stopnjo hierarhije"], + "Uses circles to visualize the flow of data through different stages of a system. Hover over individual paths in the visualization to understand the stages a value took. Useful for multi-stage, multi-group visualizing funnels and pipelines.": [ + "S pomočjo krogov prikaže potek podatkov na različnih nivojih sistema. S premikom kurzorja prikaže vrednosti na posameznem nivoju. Uporabno za večnivojsko, večskupinsko vizualizacijo." ], - "Basic": ["Osnovno"], - "Default URL": ["Privzeti URL"], - "Default URL to redirect to when accessing from the dataset list page": [ - "Privzeti URL za preusmeritev, ko dostopate iz strani s seznamom podatkovnih setov" + "Sunburst Chart": ["Večnivojski tortni grafikon"], + "Multi-Levels": ["Večplastni"], + "Ratio": ["Razmerje"], + "Target aspect ratio for treemap tiles.": [ + "Ciljno razmerje za razdelke drevesnega grafikona." ], - "Autocomplete filters": ["Samodokončaj filtre"], - "Whether to populate autocomplete filters options": [ - "Če želite napolniti možnosti za samodokončanje filtrov" + "Shows the composition of a dataset by segmenting a given rectangle as smaller rectangles with areas proportional to their value or contribution to the whole. Those rectangles may also, in turn, be further segmented hierarchically.": [ + "Prikaže zgradbo podatkovnega seta na podlagi segmentacije danega pravokotnika na manjše pravokotnike, pri čemer je ploščina sorazmerna vrednostim oz. deležem. Pravokotniki se lahko dodatno hierarhično segmentirajo." ], - "Autocomplete query predicate": ["Predikat za samodokončanje poizvedb"], - "When using \"Autocomplete filters\", this can be used to improve performance of the query fetching the values. Use this option to apply a predicate (WHERE clause) to the query selecting the distinct values from the table. Typically the intent would be to limit the scan by applying a relative time filter on a partitioned or indexed time-related field.": [ - "Ko uporabljate \"Samodokončaj filtre\", lahko s tem izboljšate hitrost pridobivanja rezultatov s poizvedbo. Z uporabo te možnosti dodate predikat (WHERE stavek) k poizvedbi za izbiro različnih vrednosti iz tabele. Običajno je namen omejiti poizvedbo z uporabo filtra za relativni čas na particioniranem ali indeksiranem časovnem polju." + "Country Field Type": ["Tip polja za države"], + "The country code standard that Superset should expect to find in the [country] column": [ + "Standard za oznake držav, ki bodo podane v stolpcu z državami" ], - "Extra data to specify table metadata. Currently supports metadata of the format: `{ \"certification\": { \"certified_by\": \"Data Platform Team\", \"details\": \"This table is the source of truth.\" }, \"warning_markdown\": \"This is a warning.\" }`.": [ - "Dodatni podatki za tabelo metapodatkov. Trenutno je podprta naslednja oblika zapisa metapodatkov: `{ \"certification\": { \"certified_by\": \"Tim za razvoj\", \"details\": \"Ta tabela je vir resnice.\" }, \"warning_markdown\": \"To je opozorilo.\" }`." + "Show Bubbles": ["Prikaži mehurčke"], + "Whether to display bubbles on top of countries": [ + "Če želite prikaz mehurčkov nad državami" ], - "Advanced": ["Napredno"], - "Cache timeout": ["Časovna omejitev predpomnilnika"], - "The duration of time in seconds before the cache is invalidated": [ - "Trajanje (v sekundah) do razveljavitve predpomnilnika" + "Max Bubble Size": ["Max. velikost mehurčka"], + "Color by": ["Barva glede na"], + "Choose whether a country should be shaded by the metric, or assigned a color based on a categorical color palette": [ + "Izberite, če želite barvanje držav glede na mero ali kategorično določeno barvno paleto" ], - "Hours offset": ["Urni premik"], - "The number of hours, negative or positive, to shift the time column. This can be used to move UTC time to local time.": [ - "Število ur, negativno ali pozitivno, za zamik časovnega stolpca. Na ta način je mogoče UTC čas prestaviti na lokalni čas." + "Country Column": ["Stolpec z državami"], + "3 letter code of the country": ["Tričrkovna oznaka države"], + "Metric that defines the size of the bubble": [ + "Mera, ki določa velikost mehurčka" ], - "Spatial": ["Prostorski"], - "virtual": ["virtualni"], - "Dataset name": ["Ime podatkovnega seta"], - "When specifying SQL, the datasource acts as a view. Superset will use this statement as a subquery while grouping and filtering on the generated parent queries.": [ - "Ko podajate SQL, se podatkovni vir obnaša kot pogled (view). Superset bo ta zapis uporabil kot podpoizvedbo, pri čemer bo združeval in filtriral na podlagi ustvarjenih starševskih poizvedb." + "Bubble Color": ["Barva mehurčka"], + "Country Color Scheme": ["Barvna shema držav"], + "A map of the world, that can indicate values in different countries.": [ + "Zemljevid sveta, ki lahko prikazuje vrednosti po državah." ], - "The JSON metric or post aggregation definition.": [ - "JSON mera ali po-agregacijska definicija." + "Multi-Dimensions": ["Večdimenzionalni"], + "Multi-Variables": ["Več spremenljivk"], + "Popular": ["Priljubljeni"], + "deck.gl charts": ["grafikoni deck.gl"], + "Pick a set of deck.gl charts to layer on top of one another": [ + "Izberite nabor deck.gl grafikonov, ki bodo nanizani en na drugem" ], - "Physical": ["Fizičen"], - "The pointer to a physical table (or view). Keep in mind that the chart is associated to this Superset logical table, and this logical table points the physical table referenced here.": [ - "Kazalec na fizično tabelo (ali pogled). Grafikon je povezan s to Supersetovo logično tabelo, ki kaže na tukaj referencirano fizično tabelo." + "Select charts": ["Izberi grafikone"], + "Error while fetching charts": ["Napaka pri pridobivanju grafikonov"], + "Compose multiple layers together to form complex visuals.": [ + "Združi več plasti za oblikovanje kompleksnih vizualizacij." ], - "Click the lock to make changes.": [ - "Kliknite ključavnico, da omogočite spreminjanje." + "deck.gl Multiple Layers": ["deck.gl - večplastni grafikon"], + "deckGL": ["deckGL"], + "Data has no time steps": ["Podatki nimajo časovnih korakov"], + "Start Longitude & Latitude": ["Začetna Dolž. in Širina"], + "Point to your spatial columns": [ + "Pokažite na stolpec z lokacijskimi podatki" ], - "Click the lock to prevent further changes.": [ - "Kliknite ključavnico, da onemogočite spreminjanje." + "End Longitude & Latitude": ["Končna Dolž. in Širina"], + "Arc": ["Lok"], + "Target Color": ["Ciljna barva"], + "Color of the target location": ["Barva ciljne lokacije"], + "Categorical Color": ["Kategorična barva"], + "Pick a dimension from which categorical colors are defined": [ + "Izberite dimenzijo, ki bo določala kategorične barve" + ], + "Stroke Width": ["Debelina obrobe"], + "Advanced": ["Napredno"], + "Plot the distance (like flight paths) between origin and destination.": [ + "Izriši razdalje (kot letalske koridorje) med izhodiščem in ciljem." ], - "D3 format": ["D3 format"], - "Warning": ["Opozorilo"], - "Optional warning about use of this metric": [ - "Opcijsko opozorilo za uporabo te mere" + "deck.gl Arc": ["deck.gl - grafikon lokov"], + "3D": ["3D"], + "Web": ["Mreža"], + "GeoJson Settings": ["GeoJson nastavitve"], + "Point Radius Scale": ["Skaliranje radija točk"], + "The GeoJsonLayer takes in GeoJSON formatted data and renders it as interactive polygons, lines and points (circles, icons and/or texts).": [ + "GeoJsonLayer uporablja podatke v formatu GeoJSON in jih izriše kot interaktivne poligone, črte in točke (krogi, ikone in/ali besedila)." ], - "Be careful.": ["Bodite previdni."], - "Changing these settings will affect all charts using this dataset, including charts owned by other people.": [ - "Spreminjanje teh nastavitev bo vplivalo na vse grafikone, ki uporabljajo ta podatkovni set, vključno z grafikoni v lasti drugih oseb." + "deck.gl Geojson": ["deck.gl - GeoJson grafikon"], + "Height": ["Višina"], + "Metric used to control height": ["Mera za določanje višine"], + "Visualize geospatial data like 3D buildings, landscapes, or objects in grid view.": [ + "Prikaz geoprostorskih podatkov kot so 3D zgradbe, parcele ali objekti v mrežnem pogledu." ], - "Source": ["Izvor"], - "Sync columns from source": ["Sinhroniziraj stolpce z virom"], - "Calculated columns": ["Izračunani stolpci"], - "Settings": ["Nastavitve"], - "The dataset has been saved": ["Podatkovni set je shranjen"], - "The dataset configuration exposed here\r\n affects all the charts using this dataset.\r\n Be mindful that changing settings\r\n here may affect other charts\r\n in undesirable ways.": [ - "Tukaj prikazane nastavitve podatkovnega seta\r\n vplivajo na vse grafikone, ki uporabljajo\r\n ta podatkovni set. Spreminjanje\r\n nastavitev lahko nezaželeno vpliva\r\n na druge grafikone." + "deck.gl Grid": ["deck.gl - grafikon mreže"], + "Experimental": ["Eksperimentalno"], + "Dynamic Aggregation Function": ["Dinamična agregacijska funkcija"], + "The function to use when aggregating points into groups": [ + "Funkcija za agregacijo točk v skupine" ], - "Are you sure you want to save and apply changes?": [ - "Ali resnično želite shraniti in uporabiti spremembe?" + "Overlays a hexagonal grid on a map, and aggregates data within the boundary of each cell.": [ + "Prikaže šestkotno mrežo na zemljevidu in agregira podatke znotraj meja vsake celice." ], - "Confirm save": ["Potrdite shranjevanje"], - "Edit Dataset ": ["Uredi podatkovni set "], - "Use legacy datasource editor": [ - "Uporabi starejši urejevalnik podatkovnega vira" + "deck.gl 3D Hexagon": ["deck.gl - grafikon 3D šestkotnikov"], + "Visualizes connected points, which form a path, on a map.": [ + "Na zemljevidu prikaže povezane točke, ki tvorijo pot." ], - "DELETE": ["IZBRIŠI"], - "delete": ["izbriši"], - "Type \"%s\" to confirm": ["Vnesite \"%s\" za potrditev"], - "Click to edit": ["Kliknite za urejanje"], - "You don't have the rights to alter this title.": [ - "Nimate pravic za spreminjanje tega naslova." + "deck.gl Path": ["deck.gl - grafikon poti"], + "Polygon Column": ["Stolpec poligonov"], + "Polygon Encoding": ["Kodiranje poligonov"], + "Elevation": ["Višina"], + "Polygon Settings": ["Nastavitve poligonov"], + "Opacity, expects values between 0 and 100": [ + "Prosojnost, vnesite vrednosti med 0 in 100" ], - "Unexpected error": ["Nepričakovana napaka"], - "This may be triggered by:": ["To je lahko sproženo z/s:"], - "Please reach out to the Chart Owner for assistance.": [ - "Za pomoč se obrnite na lastnika grafikona." + "Number of buckets to group data": [ + "Število razdelkov za združevanje podatkov" ], - "Chart Owner: %s": ["Lastnik grafikona: %s"], - "%s Error": ["%s napaka"], - "Missing dataset": ["Manjka podatkovni set"], - "See more": ["Oglejte si več"], - "See less": ["Oglejte si manj"], - "Copy message": ["Kopiraj sporočilo"], - "Close": ["Zapri"], - "This was triggered by:": ["To je bilo sproženo z/s:"], - "Did you mean:": ["Ste mislili:"], - "%(suggestion)s instead of \"%(undefinedParameter)s?\"": [ - "%(suggestion)s namesto \"%(undefinedParameter)s?\"" + "How many buckets should the data be grouped in.": [ + "V koliko razdelkov bodo razvrščeni podatki." ], - "Parameter error": ["Napaka parametra"], - "We’re having trouble loading this visualization. Queries are set to timeout after %s second.": [ - "Težava pri nalaganju vizualizacije. Časovni iztek poizvedb je nastavljen na %s sekund." + "Bucket break points": ["Točke za razčlenitev razdelkov"], + "List of n+1 values for bucketing metric into n buckets.": [ + "Seznam n+1 vrednosti za mero razvrščanja v n razdelkov." ], - "We’re having trouble loading these results. Queries are set to timeout after %s second.": [ - "Težava pri nalaganju rezultatov. Časovni iztek poizvedb je nastavljen na %s sekund." + "Emit Filter Events": ["Oddajaj dogodke filtrov"], + "Whether to apply filter when items are clicked": [ + "Če želite uporabiti filter, ko kliknete na elemente" ], - "Timeout error": ["Napaka pretečenega časa"], - "Click to favorite/unfavorite": [ - "Kliknite za priljubljeno/nepriljubljeno" + "Multiple filtering": ["Večkratno filtriranje"], + "Allow sending multiple polygons as a filter event": [ + "Dovoli pošiljanje več poligonov kot dogodek filtra" ], - "Cell content": ["Vsebina celice"], - "The import was successful": ["Uvoz je uspel"], - "OVERWRITE": ["OVERWRITE"], - "Overwrite": ["Prepiši"], - "Import": ["Uvozi"], - "Import %s": ["Uvozi %s"], - "Last Updated %s": ["Zadnja posodobitev %s"], - "Sort": ["Razvrsti"], - "%s Selected": ["Izbranih: %s"], - "Deselect all": ["Počisti izbor"], - "No Data": ["Ni podatkov"], - "%s-%s of %s": ["%s-%s od %s"], - "Type a value": ["Vnesite vrednost"], - "Filter": ["Filter"], - "Select or type a value": ["Izberite ali vnesite vrednost"], - "SQL query": ["SQL poizvedba"], - "About": ["O programu"], - "Powered by Apache Superset": ["Omogoča Apache Superset"], - "Documentation": ["Dokumentacija"], - "Report a bug": ["Sporočite napako"], - "OK": ["OK"], - "An error occurred while fetching dashboards": [ - "Prišlo je do napake pri pridobivanju nadzornih plošč" + "Visualizes geographic areas from your data as polygons on a Mapbox rendered map. Polygons can be colored using a metric.": [ + "Prikaže geografsko območje kot poligone na zemljevidu zagotovljenim preko storitve Mapbox. Poligoni so lahko obarvani glede na mero." ], - "Search all dashboards": ["Išči vse nadzorne plošče"], - "Edit Email Report": ["Uredi e-poštno poročilo"], - "New Email Report": ["Novo e-poštno poročilo"], - "Add": ["Dodaj"], - "Message Content": ["Vsebina sporočila"], - "Text embedded in email": ["Besedilo vključeno v e-pošto"], - "Image (PNG) embedded in email": ["Slika (PNG) vključena v e-pošto"], - "Formatted CSV attached in email": ["Oblikovan CSV pripet e-pošti"], - "REPORT NAME ERROR": ["NAPAKA NAZIVA POROČILA"], - "DESCRIPTION ERROR": ["NAPAKA OPISA"], - "Scheduled reports will be sent to your email as a PNG": [ - "Poročila na urniku bodo poslana na vaš e-naslov kot PNG" + "deck.gl Polygon": ["deck.gl - grafikon poligonov"], + "Point Size": ["Velikost točke"], + "Point Unit": ["Enota točke"], + "Minimum Radius": ["Min. polmer"], + "Minimum radius size of the circle, in pixels. As the zoom level changes, this insures that the circle respects this minimum radius.": [ + "Minimalni polmer kroga v pikslih. S tem je določen minimalni polmer kroga, ko se spreminja stopnja povečave." ], - "Timezone": ["Časovni pas"], - "Email reports active": ["E-poštna poročila aktivna"], - "Edit email report": ["Uredi e-poštno poročilo"], - "Delete email report": ["Izbriši e-poštno poročilo"], - "This action will permanently delete %s.": [ - "S tem dejanjem boste trajno izbrisali %s." + "Maximum Radius": ["Max. polmer"], + "Maxium radius size of the circle, in pixels. As the zoom level changes, this insures that the circle respects this maximum radius.": [ + "Maksimalni polmer kroga v pikslih. S tem je določen maksimalni polmer kroga, ko se spreminja stopnja povečave." ], - "Delete Report?": ["Izbrišem poročilo?"], - "Loading...": ["Nalagam ..."], - "There was an error loading the tables": ["Napaka pri nalaganju tabel"], - "See table schema": ["Ogled sheme tabele"], - "Select table or type table name": ["Izberite ali vnesite ime tabele"], - "Force refresh table list": ["Osveži seznam tabel"], - "Timezone selector": ["Izbira časovnega pasa"], - "%s%s": ["%s%s"], - "There is not enough space for this component. Try decreasing its width, or increasing the destination width.": [ - "Za to komponento ni dovolj prostora. Poskusite zmanjšati širino ali pa povečati širino cilja." + "Point Color": ["Barva točke"], + "A map that takes rendering circles with a variable radius at latitude/longitude coordinates": [ + "Zemljevid, ki na zemljepisnih koordinatah prikazuje kroge s spremenljivim polmerom" ], - "Can not move top level tab into nested tabs": [ - "Najvišjega zavihka ni mogoče premakniti v gnezdene zavihke" + "deck.gl Scatterplot": ["deck.gl - raztreseni grafikon"], + "Grid": ["Mreža"], + "Weight": ["Utež"], + "Metric used as a weight for the grid's coloring": [ + "Mera, ki služi kot utež za barvo mreže" ], - "This chart has been moved to a different filter scope.": [ - "Ta grafikon je bil prestavljen v drug doseg filtrov." + "Aggregates data within the boundary of grid cells and maps the aggregated values to a dynamic color scale": [ + "Agregira podatke znotraj meja celic in agregirane vrednosti ponazori z dinamično barvno lestvico" ], - "There was an issue fetching the favorite status of this dashboard.": [ - "Pri pridobivanju statusa \"priljubljeno\" za to nadzorno ploščo je prišlo do težave." + "deck.gl Screen Grid": ["deck.gl - grafikon mreže"], + "For more information about objects are in context in the scope of this function, refer to the": [ + "Za dodatne informacije o objektih v kontekstu te funkcije si oglejte" ], - "There was an issue favoriting this dashboard.": [ - "Pri uvrščanju nadzorne plošče med priljubljene je prišlo do težave." + " source code of Superset's sandboxed parser": [ + " izvorno kodo za Supersetov \"sandboxed parser\"" ], - "This dashboard is now ${nowPublished}": [ - "Ta nadzorna plošča je sedaj ${nowPublished}" + "This functionality is disabled in your environment for security reasons.": [ + "Ta funkcionalnost je v vašem okolju onemogočena zaradi varnosti." ], - "You do not have permissions to edit this dashboard.": [ - "Nimate dovoljenj za urejanje te nadzorne plošče." + "Ignore null locations": ["Izpusti prazne lokacije"], + "Whether to ignore locations that are null": [ + "Če ne želite upoštevati praznih (NULL) lokacij" ], - "This dashboard was saved successfully.": [ - "Nadzorna plošča je bila uspešno shranjena." + "Auto Zoom": ["Samodejna povečava"], + "When checked, the map will zoom to your data after each query": [ + "Če želite, da se zemljevid prilagodi vašim podatkom po vsaki poizvedbi" ], - "Could not fetch all saved charts": [ - "Vseh shranjenih grafikonov ni bilo mogoče pridobiti" + "Dimension": ["Dimenzija"], + "Select a dimension": ["Izberite dimenzijo"], + "Extra data for JS": ["Dodatni podatki za JS"], + "List of extra columns made available in Javascript functions": [ + "Seznam dodatnih podatkov, ki so na razpolago v Javascript funkcijah" ], - "Sorry there was an error fetching saved charts: ": [ - "Prišlo je do napake pri pridobivanju shranjenih grafikonov: " + "Javascript data interceptor": ["Javascript prestreznik podatkov"], + "Define a javascript function that receives the data array used in the visualization and is expected to return a modified version of that array. This can be used to alter properties of the data, filter, or enrich the array.": [ + "Določite Javascript funkcijo, ki sprejme podatkovni niz za vizualizacijo in vrne spremenjeno verzijo tega niza. Lahko se uporabi za spreminjanje lastnosti podatkov, filtra ali obogatitve niza." ], - "Visualization": ["Vizualizacija"], - "Data source": ["Podatkovni vir"], - "Added": ["Dodano"], - "Components": ["Komponente"], - "Any color palette selected here will override the colors applied to this dashboard's individual charts": [ - "Na tem mestu izbrana barvna shema bo nadomestila barve posameznih grafikonov v tej nadzorni plošči" + "Javascript tooltip generator": ["Javascript generator opisa orodja"], + "Define a function that receives the input and outputs the content for a tooltip": [ + "Določite funkcijo, ki sprejme vhodne podatke in vrne vsebino opisa orodja" ], - "Color scheme": ["Barvna shema"], - "You have unsaved changes.": ["Imate neshranjene spremembe."], - "Ready to review filters in this dashboard?": [ - "Ste pripravljeni za pregled filtrov v tej nadzorni plošči?" + "Javascript onClick href": ["Javascript onClick href"], + "Define a function that returns a URL to navigate to when user clicks": [ + "Določite funkcijo, ki vrne URL za navigacijo, ko uporabnik klikne" ], - "Remind me in 24 hours": ["Opomni me čez 24 ur"], - "Start Review": ["Začetek pregleda"], - "filter_box will be deprecated in a future version of Superset. Please replace filter_box by dashboard filter components.": [ - "Element filter_box bo v prihodnjih verzijah Superseta opuščen. Nadomestite ga s filtri nadzorne plošče." + "Legend Format": ["Oblika legende"], + "Choose the format for legend values": [ + "Izberite obliko vrednosti legende" ], - "There is no chart definition associated with this component, could it have been deleted?": [ - "S to komponento ni povezana nobena definicija grafikona. Ali je bila izbrisana?" + "Legend Position": ["Položaj legende"], + "Choose the position of the legend": ["Izberite položaj legende"], + "Lines column": ["Stolpec črt"], + "The database columns that contains lines information": [ + "Stolpec v podatkovni bazi, ki vsebuje podatke črt" ], - "Delete this container and save to remove this message.": [ - "Izbrišite ta okvir in shranite za odpravo tega sporočila." + "Line width": ["Debelina črte"], + "The width of the lines": ["Debelina črt"], + "Fill Color": ["Barva polnila"], + " Set the opacity to 0 if you do not want to override the color specified in the GeoJSON": [ + " Nastavite prosojnost na 0, če želite obdržati barvo določeno v GeoJSON" ], - "Don't refresh": ["Ne osvežuj"], - "10 seconds": ["10 sekund"], - "30 seconds": ["30 sekund"], - "1 minute": ["1 minuta"], - "5 minutes": ["5 minut"], - "30 minutes": ["30 minut"], - "1 hour": ["1 ura"], - "6 hours": ["6 ur"], - "12 hours": ["12 ur"], - "24 hours": ["24 ur"], - "Refresh interval": ["Interval osveževanja"], - "Refresh frequency": ["Frekvenca osveževanja"], - "Are you sure you want to proceed?": ["Ali želite nadaljevati?"], - "Save for this session": ["Shranite za to sejo"], - "You must pick a name for the new dashboard": [ - "Izbrati morate ime nove nadzorne plošče" + "Stroke Color": ["Barva obrobe"], + "Filled": ["Zapolnjeno"], + "Whether to fill the objects": ["Če želite zapolniti objekte"], + "Stroked": ["Obrobljeno"], + "Whether to display the stroke": ["Če želite prikazati obrobe"], + "Extruded": ["Relief"], + "Grid Size": ["Velikost mreže"], + "Defines the grid size in pixels": ["Določa velikost mreže v pikslih"], + "Parameters related to the view and perspective on the map": [ + "Parametri povezani s pogledom in perspektivo zemljevida" ], - "Save dashboard": ["Shrani nadzorno ploščo"], - "Overwrite Dashboard [%s]": ["Prepiši nadzorno ploščo [%s]"], - "Save as:": ["Shrani kot:"], - "[dashboard name]": ["[ime nadzorne plošče]"], - "also copy (duplicate) charts": ["kopiraj (podvoji) tudi grafikone"], - "Filter your charts": ["Filtriraj grafikone"], - "Sort by": ["Razvrščanje"], - "Cross Filter Scoping": ["Doseg medsebojnega filtra"], - "Load a CSS template": ["Naloži CSS predlogo"], - "Live CSS editor": ["CSS urejevalnik v živo"], - "Applied Cross Filters (%d)": ["Uporabljeni medsebojni filtri (%d)"], - "Applied Filters (%d)": ["Uporabljeni filtri (%d)"], - "Incompatible Filters (%d)": ["Neskladni filtri (%d)"], - "Unset Filters (%d)": ["Neuporabljeni filtri (%d)"], - "This dashboard is currently auto refreshing; the next auto refresh will be in %s.": [ - "Nadzorna plošča se trenutno samodejno osvežuje. Naslednja samodejna osvežitev bo čez %s." + "Longitude & Latitude": ["Dolžina in širina"], + "Fixed point radius": ["Fiksni radij točk"], + "Multiplier": ["Množitelj"], + "Factor to multiply the metric by": ["Faktor, s katerim množite mero"], + "Lines encoding": ["Kodiranje črt"], + "The encoding format of the lines": ["Oblika kodiranja črt"], + "Reverse Lat & Long": ["Zamenjaj širino in dolžino"], + "GeoJson Column": ["GeoJson stolpec"], + "Select the geojson column": ["Izberite geojson stolpec"], + "Right Axis Format": ["Oblika desne osi"], + "Show Markers": ["Prikaži markerje"], + "Show data points as circle markers on the lines": [ + "Pokaži točke kot krožne markerje na krivuljah" ], - "Your dashboard is too large. Please reduce its size before saving it.": [ - "Vaša nadzorna plošča je prevelika. Pred shranjevanjem jo zmanjšajte." + "Y bounds": ["Y meje"], + "Whether to display the min and max values of the Y-axis": [ + "Če želite prikaz min. in max. vrednosti Y-osi" ], - "Schedule email report": ["Dodaj e-poštno poročilo na urnik"], - "Discard changes": ["Zavrzi spremembe"], - "Edit dashboard": ["Uredi nadzorno ploščo"], - "An error occurred while fetching available CSS templates": [ - "Pri pridobivanju CSS predlog je prišlo do napake" + "Y 2 bounds": ["Meje Y 2"], + "Line Style": ["Slog črte"], + "Line interpolation as defined by d3.js": [ + "Interpolacija krivulje na osnovi d3.js" ], - "Superset dashboard": ["Superset nadzorna plošča"], - "Check out this dashboard: ": ["Preizkusite to nadzorno ploščo: "], - "Copy dashboard URL": ["Kopiraj URL nadzorne plošče"], - "Share dashboard by email": ["Deli nadzorno ploščo po e-pošti"], - "Refresh dashboard": ["Osveži nadzorno ploščo"], - "Set auto-refresh interval": ["Nastavi interval samodejnega osveževanja"], - "Set filter mapping": ["Nastavi shemo filtrov"], - "Edit dashboard properties": ["Uredi lastnosti nadzorne plošče"], - "Edit CSS": ["Uredi CSS"], - "Download as image": ["Izvozi kot sliko"], - "Exit fullscreen": ["Izhod iz celozaslonskega načina"], - "Enter fullscreen": ["Vklopi celozaslonski način"], - "You do not have permission to edit this dashboard": [ - "Nimate dovoljenja za urejanje te nadzorne plošče" + "Show Range Filter": ["Pokaži filter obdobja"], + "Whether to display the time range interactive selector": [ + "Če želite prikaz interaktivnega izbirnika časovnega obdobja" ], - "A valid color scheme is required": [ - "Zahtevana je veljavna barvna shema" + "Extra Controls": ["Dodatni kontrolniki"], + "Whether to show extra controls or not. Extra controls include things like making mulitBar charts stacked or side by side.": [ + "Če želite prikaz dodatnih kontrolnikov. Dodatni kontrolniki vključujejo možnost izdelave večstolpčnih grafikonov, naloženih ali drug ob drugem." ], - "The dashboard has been saved": ["Nadzorna plošča je bila shranjena"], - "Access": ["Dostop"], - "Owners is a list of users who can alter the dashboard. Searchable by name or username.": [ - "\"Lastniki\" je seznam uporabnikov, ki lahko spreminjajo nadzorno ploščo. Iskanje je možno po imenu ali uporabniškem imenu." + "X Tick Layout": ["Postavitev oznak na X-osi"], + "The way the ticks are laid out on the X-axis": [ + "Način razporeditve oznak na X-osi" ], - "Colors": ["Barve"], - "Roles is a list which defines access to the dashboard. Granting a role access to a dashboard will bypass dataset level checks. If no roles defined then the dashboard is available to all roles.": [ - "\"Vloge\" je seznam, ki definira dostop do nadzorne plošče. Dodelitev vloge za dostop do nadzorne plošče bo obšlo preverjanje na nivoju podatkovnega seta. Če vloga ni definirana, bo nadzorna plošča dostopna vsem vlogam." + "X Axis Format": ["Oblika X-osi"], + "Y Log Scale": ["Logaritemska Y-os"], + "Use a log scale for the Y-axis": ["Uporabi logaritemsko skalo za Y-os"], + "Y Axis Bounds": ["Meje Y-osi"], + "Bounds for the Y-axis. When left empty, the bounds are dynamically defined based on the min/max of the data. Note that this feature will only expand the axis range. It won't narrow the data's extent.": [ + "Meje Y-osi. Če je prazno, se meje nastavijo dinamično na podlagi min./max. vrednosti podatkov. Funkcija omeji le prikaz, obseg podatkov pa ostane enak." ], - "Apply": ["Uporabi"], - "Dashboard properties": ["Lastnosti nadzorne plošče"], - "Basic information": ["Osnovne informacije"], - "URL slug": ["URL slug"], - "A readable URL for your dashboard": [ - "Berljiv URL za vašo nadzorno ploščo" + "Y Axis 2 Bounds": ["Meje Y 2-osi"], + "X bounds": ["Meje X-osi"], + "Whether to display the min and max values of the X-axis": [ + "Če želite prikaz min. in max. vrednosti X-osi" ], - "JSON metadata": ["JSON metapodatki"], - "This dashboard is not published, it will not show up in the list of dashboards. Click here to publish this dashboard.": [ - "Ta nadzorna plošča ni objavljena in se ne bo prikazala na seznamu nadzornih plošč. Kliknite tukaj za njeno objavo." + "Bar Values": ["Vrednosti stolpcev"], + "Show the value on top of the bar": [ + "Prikaži vrednosti na vrhu stolpcev" ], - "This dashboard is not published which means it will not show up in the list of dashboards. Favorite it to see it there or access it by using the URL directly.": [ - "Ta nadzorna plošča ni objavljena in se ne bo prikazala na seznamu nadzornih plošč. Uvrstite jo med priljubljene, da jo boste videli tam, ali pa uporabite URL za neposredni dostop." + "Stacked Bars": ["Naloženi stolpci"], + "Reduce X ticks": ["Manj oznak X-osi"], + "Reduces the number of X-axis ticks to be rendered. If true, the x-axis will not overflow and labels may be missing. If false, a minimum width will be applied to columns and the width may overflow into an horizontal scroll.": [ + "Zmanjša število izrisanih oznak na X-osi. Če je vklopljeno, se x-os ne bo prelila in lahko oznake manjkajo. Če je izklopljeno, bo upoštevana min. širina stolpcev, ki pa se lahko prelije v horizontalni drsnik." ], - "This dashboard is published. Click to make it a draft.": [ - "Ta nadzorna plošča je objavljena. Kliknite, da jo uvrstite med osnutke." + "You cannot use 45° tick layout along with the time range filter": [ + "Skupaj s filtriranjem časovnega obdobja ne morete uporabiti oznak pod 45° kotom" ], - "Draft": ["Osnutek"], - "Annotation layers are still loading.": [ - "Sloj z oznakami se še vedno nalaga." + "Stacked Style": ["Slog nalaganja"], + "Evolution": ["Evolucija"], + "A time series chart that visualizes how a related metric from multiple groups vary over time. Each group is visualized using a different color.": [ + "Grafikon časovne vrste, ki prikaže kako se povezane mere skupin spreminjajo skozi čas. Vsaka skupina je prikazana s svojo barvo." ], - "One ore more annotation layers failed loading.": [ - "Eden ali več slojev z oznakami se ni naložil." + "Stretched style": ["Raztegnjen slog"], + "Stacked style": ["Naložen slog"], + "Video game consoles": ["Igralne konzole"], + "Vehicle Types": ["Vrste vozil"], + "Area Chart": ["Ploščinski grafikon"], + "Continuous": ["Zvezno"], + "Line": ["Črta"], + "nvd3": ["nvd3"], + "Deprecated": ["Zastarelo"], + "Series Limit Sort By": ["Razvrščanje omejitev serije"], + "Metric used to order the limit if a series limit is present. If undefined reverts to the first metric (where appropriate).": [ + "Mera, ki določa kako je razvrščena meja, če je določena omejitev serij. Če ni določena, se uporabi prva mera (kjer je to ustrezno)." ], - "Emitted values": ["Oddane vrednosti"], - "Click to clear emitted filters": ["S klikom počistite oddane filtre"], - "Cached %s": ["Predpomnjeno %s"], - "Fetched %s": ["Pridobljeno %s"], - "Minimize chart": ["Pomanjšaj grafikon"], - "Maximize chart": ["Povečaj grafikon"], - "Force refresh": ["Osveži"], - "Toggle chart description": ["Preklopi opis grafikona"], - "View chart in Explore": ["Ogled grafikona v Raziskovalcu"], - "View query": ["Ogled poizvedbe"], - "Copy chart URL": ["Kopiraj URL grafikona"], - "Share chart by email": ["Deli grafikon po e-pošti"], - "Check out this chart: ": ["Preizkusite ta grafikon: "], - "Export CSV": ["Izvozi CSV"], - "Export full CSV": ["Izvozi celoten CSV"], - "Cross-filter scoping": ["Doseg medsebojnega filtra"], - "Search...": ["Iskanje ..."], - "No filter is selected.": ["Noben filter ni izbran."], - "Editing 1 filter:": ["Urejanje enega filtra:"], - "Batch editing %d filters:": ["Skupinsko urejanje %d filtrov:"], - "Configure filter scopes": ["Nastavi doseg filtrov"], - "There are no filters in this dashboard.": [ - "V nadzorni plošči ni filtrov." + "Series Limit Sort Descending": ["Razvrsti padajoče"], + "Whether to sort descending or ascending if a series limit is present": [ + "Če želite padajoče ali naraščajoče razvrščanje, ko je prisotna omejitev serije" ], - "Expand all": ["Razširi vse"], - "Collapse all": ["Skrči vse"], - "This markdown component has an error.": [ - "Markdown komponenta ima napako." + "Visualize how a metric changes over time using bars. Add a group by column to visualize group level metrics and how they change over time.": [ + "Prikaže spreminjanje mere skozi čas s pomočjo stolpcev. Z dodajanjem stolpcev za združevanje prikaže mere skupin in njihovo spreminjanje." ], - "This markdown component has an error. Please revert your recent changes.": [ - "Markdown komponenta ima napako. Povrnite nedavne spremembe." + "Time-series Bar Chart": ["Stolpčni grafikon za časovno vrsto"], + "Bar": ["Stolpec"], + "Vertical": ["Navpično"], + "Box Plot": ["Box Plot"], + "X Log Scale": ["Logaritemska X-os"], + "Use a log scale for the X-axis": ["Uporabi logaritemsko skalo za X-os"], + "Visualizes a metric across three dimensions of data in a single chart (X axis, Y axis, and bubble size). Bubbles from the same group can be showcased using bubble color.": [ + "Prikaže mero v treh dimenzijah podatkov na istem grafikonu (x os, y os, velikost mehurčka). Mehurčki v isti skupini so predstavljeni z barvo." ], - "Delete dashboard tab?": ["Ali izbrišem zavihek nadzorne plošče?"], - "Divider": ["Ločilnik"], - "Header": ["Glava"], - "Row": ["Vrstica"], - "Tabs": ["Zavihki"], - "Preview": ["Predogled"], - "Sorry, your browser does not support copying.": [ - "Vaš brskalnik ne podpira kopiranja." + "Ranges": ["Razponi"], + "Ranges to highlight with shading": ["Razponi za označitev s senčenjem"], + "Range labels": ["Oznake razponov"], + "Labels for the ranges": ["Oznake za razpone"], + "Markers": ["Markerji"], + "List of values to mark with triangles": [ + "Seznam vrednosti, ki bodo markirane s trikotniki" ], - "Sorry, something went wrong. Try again later.": [ - "Nekaj je šlo narobe. Poskusite ponovno kasneje." + "Marker labels": ["Oznake markerjev"], + "Labels for the markers": ["Oznake za markerje"], + "Marker lines": ["Markirne črtice"], + "List of values to mark with lines": [ + "Seznam vrednosti, ki bodo markirane s črticami" ], - "All Filters (${filterValues.length})": [ - "Vsi filtri (${filterValues.length})" + "Marker line labels": ["Oznake markirnih črtic"], + "Labels for the marker lines": ["Oznake za markirne črtice"], + "KPI": ["KPI"], + "Showcases the progress of a single metric against a given target. The higher the fill, the closer the metric is to the target.": [ + "Prikaže napredovanje posamezne mere glede na cilj. Večja napolnjenost, pomeni, da je mera bližje cilju." ], - "Filter Sets (${filterSetFilterValues.length})": [ - "Nastavljeni filtri (${filterSetFilterValues.length})" + "Visualizes many different time-series objects in a single chart. This chart is being deprecated and we recommend using the Time-series Chart instead.": [ + "Prikaže več različnih časovnih vrst na istem grafikonu. Grafikon se opušča, zato priporočamo uporabo Grafikona časovne vrste." ], - "Select parent filters": ["Izberi starševske filtre"], - "Check configuration": ["Preveri nastavitve"], - "Cannot load filter": ["Filtra ni mogoče naložiti"], - "Editing filter set:": ["Urejanje seta filtrov:"], - "Filter set with this name already exists": [ - "Set filtrov z enakim imenom že obstaja" + "Time-series Percent Change": ["Časovna vrsta - Procentualna sprememba"], + "Sort Bars": ["Uredi stolpce"], + "Sort bars by x labels.": ["Uredi stolpce po x-oznakah."], + "Breakdowns": ["Razčlenitev"], + "Defines how each series is broken down": [ + "Določa, kako se vsaka podatkovna serija razčleni" ], - "Filter set already exists": ["Set filtrov že obstaja"], - "This filter set is identical to: \"%s\"": [ - "Ta set filtrov je enak: \"%s\"" + "Compares metrics from different categories using bars. Bar lengths are used to indicate the magnitude of each value and color is used to differentiate groups.": [ + "Primerjava mer različnih kategorij s pomočjo stolpcev. Dolžina stolpca prestavlja višino vrednosti, z barvami pa so ločene skupine." ], - "Remove invalid filters": ["Odstrani neveljavne filtre"], - "Rebuild": ["Obnovi"], - "Filters (%d)": ["Filtri (%d)"], - "This filter doesn't exist in dashboard. It will not be applied.": [ - "Ta filter ne obstaja v nadzorni plošči in ne bo uveljavljen." + "Bar Chart": ["Stolpčni grafikon"], + "Additive": ["Aditivno"], + "Discrete": ["Diskretno"], + "Y Axis 1": ["Y-os 1"], + "Y Axis 2": ["Y-os 2"], + "Left Axis Metric": ["Mera za levo os"], + "Choose a metric for left axis": ["Izberite mero za levo os"], + "Left Axis Format": ["Oblika leve osi"], + "Visualizes 2 metrics as line plots using the same x-axis. This chart is useful for comparing metrics across the same time range.": [ + "Prikaže dve meri na črtnem grafu z isto x-osjo. Grafikon je uporaben za primerjavo mer v istem časovnem obdobju." ], - "Filter metadata changed in dashboard. It will not be applied.": [ - "Metapodatki filtra so se spremenili v nadzorni plošči. Ne bo uveljavljen." + "Dual Line Chart": ["Grafikon z dvojno krivuljo"], + "Propagate": ["Razširi"], + "Send range filter events to other charts": [ + "Pošlji dogodke filtra obdobja na druge grafikone" ], - "None": ["Brez"], - "Please filter set name": ["Vnesite ime seta filtrov"], - "Create": ["Ustvari"], - "Create new filter set": ["Ustvarite nov set filtrov"], - "New filter set": ["Nov set filtrov"], - "Please apply filter changes": ["Potrdite spremembe filtra"], - "Unknown value": ["Neznana vrednost"], - "Clear all": ["Počisti vse"], - "(Removed)": ["(Odstranjeno)"], - "Undo?": ["Povrni?"], - "Add filter": ["Dodaj filter"], - "[untitled]": ["[neimenovana]"], - "Filters configuration and scoping": ["Nastavitve in doseg filtrov"], - "Cannot create cyclic hierarchy": [ - "Ciklične hierarhije ni mogoče ustvariti" + "Classic chart that visualizes how metrics change over time.": [ + "Standardni grafikon za prikaz spreminjanje mere skozi čas." ], - "Column select": ["Izbira stolpca"], - "Select a column": ["Izberite stolpec"], - "No compatible columns found": ["Ni najdenih skladnih stolpcev"], - "Value is required": ["Zahtevana je vrednost"], - "Configuration": ["Nastavitve"], - "Scoping": ["Doseg"], - "Select filter": ["Izbirni filter"], - "Value": ["Vrednost"], - "Range filter": ["Filter obdobja"], - "Numerical range": ["Številski obseg"], - "Time filter": ["Časovni filter"], - "Time range": ["Časovno obdobje"], - "Time column": ["Časovni stolpec"], - "Time grain": ["Granulacija časa"], - "Group By": ["Združevanje (Group by)"], - "Group by": ["Združevanje (Group by)"], - "Pre-filter is required": ["Zahtevan je predfilter"], - "(deleted)": ["(izbrisano)"], - "Parent filter": ["Nadrejeni filter"], - "Filter name": ["Ime filtra"], - "Name is required": ["Zahtevano je ime"], - "Filter Type": ["Tip filtra"], - "Filter type": ["Tip filtra"], - "Datasets do not contain a temporal column": [ - "Podatkovni seti ne vsebujejo časovnega stolpca" + "Battery level over time": ["Napolnjenost baterije skozi čas"], + "Line Chart": ["Črtni grafikon"], + "Prefix metric name with slice name": ["Imenu mere pripni ime rezine"], + "Y Axis Left": ["Y-os levo"], + "Left Axis chart(s)": ["Grafikoni leve osi"], + "Choose one or more charts for left axis": [ + "Izberite enega ali več grafikonov za levo os" ], - "Dataset is required": ["Zahtevan je podatkovni set"], - "Filter has default value": ["Filter ima privzeto vrednost"], - "Default Value": ["Privzeta vrednost"], - "Default value is required": ["Zahtevana je privzeta vrednost"], - "Refresh the default values": ["Osveži privzete vrednosti"], - "Fill all required fields to enable \"Default Value\"": [ - "Izpolnite vsa polja, da omogočite \"Privzeto vrednost\"" + "Y Axis Right": ["Y-os desno"], + "Right Axis chart(s)": ["Grafikoni desne osi"], + "Choose one or more charts for right axis": [ + "Izberite enega ali več grafikonov za desno os" + ], + "Visualize two different time series using the same x-axis time range. This chart is being deprecated and we recommend using the Mixed Timeseries Chart instead!": [ + "Prikaže dve različni časovni vrsti z isto x-osjo oz. časovnim obdobjem. Grafikon se opušča, zato priporočamo uporabo kombiniranega grafikona časovne vrste!" ], - "Filter is hierarchical": ["Filter je hierarhičen"], - "Parent filter is required": ["Zahtevan je nadrejeni filter"], - "Pre-filter available values": ["Predfiltriraj razpoložljive vrednosti"], - "Pre-filter": ["Predfilter"], - "Optional time column if time range should apply to another column than the default time column": [ - "Izbirni časovni stolpec se mora nanašati na drug stolpec kot privzeti časovni stolpec" + "Multiple Line Charts": ["Veččrtni grafikon"], + "Label Type": ["Oblika oznake"], + "What should be shown on the label?": ["Kaj bo prikazano na oznaki?"], + "Donut": ["Kolobar"], + "Do you want a donut or a pie?": ["Želite kolobar ali torto?"], + "Show Labels": ["Pokaži oznake"], + "Whether to display the labels. Note that the label only displays when the the 5% threshold.": [ + "Če želite prikazati oznake. Oznake so prikazane le pri vsaj 5-odstotnem pragu." ], - "Sort filter values": ["Razvrsti vrednosti filtra"], - "Sort type": ["Način razvrščanja"], - "Sort ascending": ["Razvrsti naraščajoče"], - "Sort descending": ["Razvrsti padajoče"], - "Sort Metric": ["Mera za razvrščanje"], - "If a metric is specified, sorting will be done based on the metric value": [ - "Če je določena mera, bo razvrščanje izvedeno na podlagi vrednosti mere" + "Put labels outside": ["Postavi oznake zunaj"], + "Put the labels outside the pie?": ["Postavim oznake zunaj torte?"], + "Pie Chart": ["Tortni grafikon"], + "Frequency": ["Frekvenca"], + "The periodicity over which to pivot time. Users can provide\n \"Pandas\" offset alias.\n Click on the info bubble for more details on accepted \"freq\" expressions.": [ + "Periodičnost za vrtenje časa. Uporabnik lahko poda\n psevdonim za zamik v \"Pandas\".\n Kliknite na mehurček za podrobnosti dovoljenih izrazov za \"freq\"." ], - "Sort metric": ["Mera za razvrščanje"], - "You have removed this filter.": ["Odstranili ste ta filter."], - "Restore Filter": ["Povrni filter"], - "${mainControlItem.config?.label}": ["${mainControlItem.config?.label}"], - "Column is required": ["Zahtevan je stolpec"], - "Populate \"Default value\" to enable this control": [ - "Izpolnite \"Privzeto vrednost\", da omogočite ta kontrolnik" + "Time-series Period Pivot": ["Časovna serija - Vrtenje periode"], + "Stack": ["Naloži"], + "Expand": ["Razširi"], + "Show legend": ["Prikaži legendo"], + "Whether to display a legend for the chart": [ + "Če želite prikaz legende za grafikon" ], - "Default value set automatically when \"Default to first item\" is checked": [ - "Privzeta vrednost je samodejno izbrana, če je izbrano \"Privzet prvi element\"" + "Margin": ["Rob"], + "Additional padding for legend.": ["Dodatni razmak za legendo."], + "Legend type": ["Tip legende"], + "Show Value": ["Prikaži vrednost"], + "Show series values on the chart": [ + "Na grafikonu prikaži vrednosti serij" ], - "Default value must be set when \"Required\" is checked": [ - "Privzeta vrednost mora biti določena, če je izbrano \"Obvezno\"" + "Stack series": ["Nalagaj serije"], + "Stack series on top of each other": ["Nalagaj serije eno na drugo"], + "Only Total": ["Samo vsota"], + "Only show the total value on the stacked chart, and not show on the selected category": [ + "Na naloženem grafikonu prikaži samo skupno vsoto, za izbrane kategorije pa ne" ], - "Default value must be set when \"Filter has default value\" is checked": [ - "Privzeta vrednost mora biti določena, če je izbrano \"Filter ima privzeto vrednost\"" + "X-axis": ["X-os"], + "Dimension to use on x-axis.": ["Dimenzija z x-os."], + "Percentage threshold": ["Procentualni prag"], + "Minimum threshold in percentage points for showing labels.": [ + "Minimalni prag v odstotnih točkah za prikaz oznak." ], - "Apply to all panels": ["Uporabi za vse panele"], - "Apply to specific panels": ["Uporabi za določene panele"], - "Only selected panels will be affected by this filter": [ - "Ta filter bo vplival le na izbrane panele" + "Rich tooltip": ["Podroben opis orodja"], + "Shows a list of all series available at that point in time": [ + "Prikaže seznam vseh razpoložljivih podatkovnih serij za istočasno točko" ], - "All panels with this column will be affected by this filter": [ - "Ta filter bo vplival na vse panele s tem stolpcem" + "Tooltip time format": ["Oblika zapisa časa v opisu orodja"], + "Tooltip sort by metric": ["Mera za razvrščanje opisa orodja"], + "Whether to sort tooltip by the selected metric in descending order.": [ + "Če želite padajoče razvrstiti opis orodja z izbrano mero." ], - "All panels": ["Vsi paneli"], - "This chart might be incompatible with the filter (datasets don't match)": [ - "Ta grafikon je lahko nekompatibilen s filtrom (podatkovni seti se ne ujemajo)" + "Tooltip": ["Opis orodja"], + "Last available value seen on %s": [ + "Zadnja razpoložljiva vrednost na %s" ], - "Keep editing": ["Nadaljuj z urejanjem"], - "Yes, cancel": ["Da, prekini"], - "There are unsaved changes.": ["Imate neshranjene spremembe."], - "Are you sure you want to cancel?": ["Ali želite prekiniti?"], - "Error loading chart datasources. Filters may not work correctly.": [ - "Napaka pri nalaganju podatkovnih virov grafikona. Filtri lahko ne delujejo pravilno." + "Not up to date": ["Ni posodobljeno"], + "No data": ["Ni podatkov"], + "No data after filtering or data is NULL for the latest time record": [ + "Ni podatkov po filtriranju ali pa imajo vrednost NULL za zadnji časovni zapis" ], - "Transparent": ["Prozorno"], - "White": ["Belo"], - "All filters": ["Vsi filtri"], - "All charts": ["Vsi grafikoni"], + "Try applying different filters or ensuring your datasource has data": [ + "Poskusite uporabiti druge filtre oz. zagotovite, da so v podatkovnem viru podatki" + ], + "Big Number Font Size": ["Velikost pisave Velike številke"], + "Tiny": ["Drobna"], "Small": ["Majhno"], - "Medium": ["Srednje"], + "Normal": ["Normalna"], "Large": ["Veliko"], - "Tab title": ["Naslov zavihka"], - "Origin": ["Izhodišče"], - "Time granularity": ["Granulacija časa"], - "A reference to the [Time] configuration, taking granularity into account": [ - "Sklic na nastavitve za [Čas], ki upošteva granulacijo" + "Huge": ["Ogromna"], + "Subheader Font Size": ["Velikost pisave podnaslova"], + "Display settings": ["Nastavitve prikaza"], + "Subheader": ["Podnaslov"], + "Description text that shows up below your Big Number": [ + "Besedilo, ki se prikaže pod veliko številko" ], - "One or many columns to group by. High cardinality groupings should include a series limit to limit the number of fetched and rendered series.": [ - "Eden ali več stolpcev za združevanje. Združevanje z visoko kardinalnostjo naj vsebuje omejitev serij, s čimer omejite število pridobljenih in prikazanih serij." + "Force date format": ["Vsili obliko zapisa datuma"], + "Use date formatting even when metric value is not a timestamp": [ + "Oblikovanje datuma uporabi tudi, ko vrednost mere ni časovna značka" ], - "One or many metrics to display": ["Ena ali več mer za prikaz"], - "Visualization type": ["Tip vizualizacije"], - "The type of visualization to display": ["Tip vizualizacije za prikaz"], - "Fixed color": ["Izbrana barva"], - "Use this to define a static color for all circles": [ - "S tem definirate določeno barvo za vse kroge" + "Showcases a single metric front-and-center. Big number is best used to call attention to a KPI or the one thing you want your audience to focus on.": [ + "Prikaže eno vrednost. Velika številka je primerna za poudarek KPI-ja ali vrednosti, na katero želite usmeriti pozornost." ], - "Right axis metric": ["Mera desne osi"], - "Choose a metric for right axis": ["Izberite mero za desno os"], - "Linear color scheme": ["Linearna barvna shema"], - "Color metric": ["P"], - "A metric to use for color": ["Mera za barvo"], - "One or many controls to pivot as columns": [ - "En ali več kontrolnikov za stolpčno vrtenje" + "A Big Number": ["Velika številka"], + "With a subheader": ["S podnaslovom"], + "Formattable": ["Prilagodljiv"], + "Comparison Period Lag": ["Zaostanek obdobja za primerjavo"], + "Based on granularity, number of time periods to compare against": [ + "Na osnovi granulacije, število časovnih obdobij za primerjavo" ], - "Defines the origin where time buckets start, accepts natural dates as in `now`, `sunday` or `1970-01-01`": [ - "Določa izhodišče, kadar se začnejo časovni razdelki. Sprejema naravne zapise kot so `zdaj`, `nedelja` ali `1970-01-01`" + "Comparison suffix": ["Pripona za primerjavo"], + "Suffix to apply after the percentage display": [ + "Pripona za prikaz procenta" ], - "The time granularity for the visualization. Note that you can type and use simple natural language as in `10 seconds`, `1 day` or `56 weeks`": [ - "Granulacija časa za vizualizacijo. Uporabite lahko vnos z naravnim jezikom, kot npr. `10 sekund`, `1 dni` ali `56 tednov`" + "Show Timestamp": ["Prikaži časovno značko"], + "Whether to display the timestamp": [ + "Če želite prikazati časovno značko" ], - "The time column for the visualization. Note that you can define arbitrary expression that return a DATETIME column in the table. Also note that the filter below is applied against this column or expression": [ - "Časovni stolpec za vizualizacijo. Določite lahko poljuben izraz, ki vrne DATETIME stolpec v tabeli. Spodnji filter se nanaša na ta stolpec ali izraz" + "Show Trend Line": ["Pokaži trendno črto"], + "Whether to display the trend line": ["Če želite prikazati trendno črto"], + "Start y-axis at 0": ["Začni y-os z 0"], + "Start y-axis at zero. Uncheck to start y-axis at minimum value in the data.": [ + "Začni y-os z nič. Ne izberite, če želite, da se y-os začne z najmanjšo vrednostjo podatkov." ], - "The time granularity for the visualization. This applies a date transformation to alter your time column and defines a new time granularity. The options here are defined on a per database engine basis in the Superset source code.": [ - "Granulacija časa za to vizualizacijo. Izvede transformacijo podatkov, ki spremeni vaš časovni stolpec in določi novo časovno granulacija. Ta možnost je definirana na ravni sistema podatkovne baze v izvorni kodi Superseta." + "Fix to selected Time Range": ["Nastavi na izbrano časovno obdobje"], + "Fix the trend line to the full time range specified in case filtered results do not include the start or end dates": [ + "Trendno črto nastavite na izbrano obdobje, v primeru, da filtrirani rezultati ne vsebujejo začetnega in/ali končnega datuma" ], - "No filter": ["Brez filtra"], - "The time range for the visualization. All relative times, e.g. \"Last month\", \"Last 7 days\", \"now\", etc. are evaluated on the server using the server's local time (sans timezone). All tooltips and placeholder times are expressed in UTC (sans timezone). The timestamps are then evaluated by the database using the engine's local timezone. Note one can explicitly set the timezone per the ISO 8601 format if specifying either the start and/or end time.": [ - "Časovno obdobje za vizualizacijo. Vsi relativni časi, kot npr. \"Zadnji mesec\", Zadnjih 7 dni\", \"Zdaj\" so izračunani na strežniku z njegovim lokalnim časom. Vsi opisi orodij in časi so izraženi v UTC. Časovne značke se nato izračunajo v podatkovni bazi z njenim lokalnim časovnim pasom. Eksplicitno lahko nastavite časovni pas v ISO 8601 formatu, če določite čas začetka ali konca." + "Showcases a single number accompanied by a simple line chart, to call attention to an important metric along with its change over time or other dimension.": [ + "Prikaže eno vrednost skupaj s preprostim črtnim grafikonom, za poudarek pomembne mere skupaj z njeno časovno spremembo." ], - "Row limit": ["Omejitev št. vrstic"], - "Limits the number of rows that get displayed.": [ - "Omeji število vrstic za prikaz." + "Whisker/outlier options": ["Možnosti grafikona kvantilov"], + "Determines how whiskers and outliers are calculated.": [ + "Določa kako so izračunani kvantili in izstopajoče vrednosti." ], - "Series limit": ["Omejitev št. serij"], - "Limits the number of series that get displayed. A joined subquery (or an extra phase where subqueries are not supported) is applied to limit the number of series that get fetched and rendered. This feature is useful when grouping by high cardinality column(s) though does increase the query complexity and cost.": [ - "Omeji število časovnih vrst za prikaz. S podpoizvedbo (ali dodatno fazo, kjer podpoizvedbe niso podprte) se omeji število časovnih vrst, ki bodo pridobljene za prikaz. Ta funkcija je uporabna pri združevanju s stolpci z veliko kardinalnostjo, vendar poveča kompleksnost poizvedbe." + "Categories to group by on the x-axis.": [ + "Kategorije za združevanje po x-osi." ], - "Metric used to define how the top series are sorted if a series or row limit is present. If undefined reverts to the first metric (where appropriate).": [ - "Mera, ki določa kako so razvrščene prve serije, če je določena omejitev serij ali vrstic. Če ni določena, se uporabi prva mera (kjer je ustrezno)." + "Distribute across": ["Porazdeli glede na"], + "Columns to calculate distribution across. Defaults to temporal column if left empty.": [ + "Stolpci za izračun porazdelitve. Privzeto je izbran časovni stolpec (če je prazno)." ], - "Series": ["Niz"], - "Defines the grouping of entities. Each series is shown as a specific color on the chart and has a legend toggle": [ - "Določa združevanje entitet. Vsak niz je na grafikonu prikazan z določeno barvo in ima lahko prikazano legendo" + "Also known as a box and whisker plot, this visualization compares the distributions of a related metric across multiple groups. The box in the middle emphasizes the mean, median, and inner 2 quartiles. The whiskers around each box visualize the min, max, range, and outer 2 quartiles.": [ + "Znan tudi kot grafikon škatla z brki. prikaže primerjavo porazdelitev povezanih mer v različnih skupinah. Škatla na sredini predstavlja povprečje, mediano in notranja 2 kvartila. Brki na vsaki škatli prikazujejo minimum, maksimum, območje in zunanja dva kvartila." ], - "Entity": ["Entiteta"], - "This defines the element to be plotted on the chart": [ - "Določa element, ki bo izrisan na grafikonu" + "ECharts": ["ECharts"], + "Labels": ["Oznake"], + "Whether to display the labels.": ["Če želite prikaz oznak."], + "Showcases how a metric changes as the funnel progresses. This classic chart is useful for visualizing drop-off between stages in a pipeline or lifecycle.": [ + "Prikaže kako se mera spreminja, ko lijak napreduje. Standardni grafikon za prikaz sprememb med nivoji v procesu ali življenjskem ciklu." ], - "X Axis": ["X os"], - "Metric assigned to the [X] axis": ["Mera za [X] os"], - "Y Axis": ["Y os"], - "Metric assigned to the [Y] axis": ["Mera za [Y] os"], - "Bubble size": ["Velikost mehurčka"], - "Y Axis Format": ["Oblika Y osi"], - "When `Calculation type` is set to \"Percentage change\", the Y Axis Format is forced to `.1%`": [ - "Če je `Vrsta izračuna` nastavljena na \"Procentualna sprememba\", bo oblika Y-osi vsiljena na `.1%`" + "Funnel Chart": ["Lijakasti grafikon"], + "Sequential": ["Sekvenčni"], + "Columns to group by": ["Stolpci za združevanje"], + "General": ["Splošno"], + "Min": ["Min"], + "Minimum value on the gauge axis": ["Najmanjša vrednost na številčnici"], + "Max": ["Max"], + "Maximum value on the gauge axis": ["Največja vrednost na številčnici"], + "Start angle": ["Začetni kot"], + "Angle at which to start progress axis": [ + "Kot, pri katerem se začne os območja" ], - "The color scheme for rendering chart": [ - "Barvna shema za izris grafikona" + "End angle": ["Končni kot"], + "Angle at which to end progress axis": [ + "Kot, pri katerem se konča os območja" ], - "An error occurred while starring this chart": [ - "Pri ocenjevanju grafikona je prišlo do napake" + "Font size": ["Velikost pisave"], + "Font size for axis labels, detail value and other text elements": [ + "Velikost pisave za oznake osi, podrobnosti in druge besedilne elemente" ], - "description": ["opis"], - "bolt": ["vijak"], - "Changing this control takes effect instantly": [ - "Sprememba tega kontrolnika se odrazi takoj" + "Value format": ["Oblika zapisa vrednosti"], + "Additional text to add before or after the value, e.g. unit": [ + "Dodatno besedilo, ki ga dodate pred ali za vrednost, npr. enota" ], - "Customize": ["Prilagodi"], - "Height": ["Višina"], - "Width": ["Širina"], - "Copy chart URL to clipboard": ["Kopiraj URL grafikona na odložišče"], - "Superset Chart": ["Superset grafikon"], - "Export to .JSON format": ["Izvozi v .json format"], - "Export to .CSV format": ["Izvozi v .csv format"], - "Controls labeled ": ["Kontrolniki imenovani "], - "Control labeled ": ["Nastavitev "], - "Open Datasource tab": ["Odpri zavihek s podatkovnim virom"], - "rows": ["vrstic"], - "Limit reached": ["Omejitev dosežena"], - "**Select** a dashboard OR **create** a new one": [ - "**Izberite** nadzorno ploščo ALI **ustvarite** novo" + "Show pointer": ["Prikaži kazalec"], + "Whether to show the pointer": ["Če želite prikazati kazalec"], + "Animation": ["Animacija"], + "Whether to animate the progress and the value or just display them": [ + "Če želite animiran prikaz grafikona" ], - "Please enter a chart name": ["Vnesite ime grafikona"], - "Save chart": ["Shrani grafikon"], - "Save & go to dashboard": ["Shrani in pojdi na nadzorno ploščo"], - "Save as new chart": ["Shrani kot nov grafikon"], - "Save (Overwrite)": ["Shrani (prepiši)"], - "Save as ...": ["Shrani kot ..."], - "Chart name": ["Ime grafikona"], - "Add to dashboard": ["Dodaj na nadzorno ploščo"], - "Select a dashboard": ["Izberite nadzorno ploščo"], - "Copy": ["Kopiraj"], - "rows retrieved": ["vrnjenih vrstic"], - "Sorry, An error occurred": ["Prišlo je do napake"], - "No data": ["Ni podatkov"], - "View samples": ["Ogled vzorcev"], - "Search Metrics & Columns": ["Iskanje mer in stolpcev"], - "Showing %s of %s": ["Prikazanih %s od %s"], - "Show less...": ["Prikaži manj..."], - "Show all...": ["Prikaži vse..."], - "Show Less...": ["Prikaži manj..."], - "New chart": ["Nov grafikon"], - "Edit properties": ["Uredi lastnosti"], - "Run in SQL Lab": ["Zaženi v SQL laboratoriju"], - "%s - untitled": ["%s - neimenovan"], - "Edit chart properties": ["Uredi lastnosti grafikona"], - "You do not have permission to edit this chart": [ - "Nimate dovoljenja za urejanje tega grafikona" + "Axis": ["Os"], + "Show axis line ticks": ["Prikaži oznake na X-osi"], + "Whether to show minor ticks on the axis": [ + "Če želite prikaz manjših oznak na osi" + ], + "Show split lines": ["Prikaži razdelitvene črte"], + "Whether to show the split lines on the axis": [ + "Če želite prikazati razdelitvene črte na osi" ], - "The description can be displayed as widget headers in the dashboard view. Supports markdown.": [ - "Opis je lahko prikazan kot glava gradnika in pogledu nadzorne plošče. Podpira markdown." + "Split number": ["Število razdelitev"], + "Number of split segments on the axis": ["Število razdelkov na osi"], + "Progress": ["Območje"], + "Show progress": ["Prikaži območje"], + "Whether to show the progress of gauge chart": [ + "Prikaži merilno območje števčnega grafikona" ], - "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the dataset's timeout if undefined.": [ - "Časovna veljavnost (v sekundah) predpomnjenja za ta grafikon. Če ni definirana, je uporabljena vrednost za podatkovni set." + "Overlap": ["Prekrivanje"], + "Whether the progress bar overlaps when there are multiple groups of data": [ + "Če želite prekrivanje območij, ko imate več skupin podatkov" ], - "A list of users who can alter the chart. Searchable by name or username.": [ - "Seznam uporabnikov, ki lahko spreminjajo ta grafikon. Možno je iskanje po imenu ali uporabniškem imenu." + "Round cap": ["Zaobljeni konci"], + "Style the ends of the progress bar with a round cap": [ + "Zaobljena oblika koncev območja" ], - "Min": ["Min"], - "Max": ["Max"], - "Select color scheme": ["Izberite barvno shemo"], - "Invalid lat/long configuration.": [ - "Neveljavna nastavitev zemljepisne dolžine/širine." + "Intervals": ["Intervali"], + "Interval bounds": ["Meje intervalov"], + "Comma-separated interval bounds, e.g. 2,4,5 for intervals 0-2, 2-4 and 4-5. Last number should match the value provided for MAX.": [ + "Z vejico ločeni intervali, npr. 2,4,5 za intervale 0-2, 2-4 in 4-5. Zadnja številka naj bo enaka vrednosti za MAX." ], - "Reverse lat/long ": ["Zamenjaj zemljepisno dolžino/širino "], - "Longitude & Latitude columns": ["Stolpci zemljepisne dolžine in širine"], - "Delimited long & lat single column": [ - "En stolpec z ločenima zemljepisno dolžino in širino" + "Interval colors": ["Barve intervalov"], + "Comma-separated color picks for the intervals, e.g. 1,2,4. Integers denote colors from the chosen color scheme and are 1-indexed. Length must be matching that of interval bounds.": [ + "Z vejico ločene barve za intervale, npr. 1,2,4. Cela števila predstavljajo barve iz barvne sheme (začnejo se z 1). Dolžina mora ustrezati mejam intervala." ], - "Multiple formats accepted, look the geopy.points Python library for more details": [ - "Sprejema različne zapise - podrobnosti najdete v Pythonovi knjižnici geopy.points" + "Uses a gauge to showcase progress of a metric towards a target. The position of the dial represents the progress and the terminal value in the gauge represents the target value.": [ + "Uporablja števec za prikaz napredovanja mere k ciljni vrednosti. Položaj kazalca predstavlja napredek, končna vrednost na števcu pa ciljno vrednost." ], - "Geohash": ["Geohash"], - "textarea": ["področje besedila"], - "in modal": ["v modalnem"], - "Failed to verify select options: %s": [ - "Preverjanje možnosti izbire ni uspelo: %s" + "Gauge Chart": ["Števčni grafikon"], + "Name of the source nodes": ["Imena izvornih vozlišč"], + "Name of the target nodes": ["Imena ciljnih vozlišč"], + "Source category": ["Kategorija izvora"], + "The category of source nodes used to assign colors. If a node is associated with more than one category, only the first will be used.": [ + "Kategorija izvornih vozlišč, na podlagi katere je določena barva. Če je vozlišče povezano z več kot eno kategorijo, bo uporabljena samo prva." ], - "Annotation layer value": ["Vrednost sloja z oznakami"], - "Annotation Slice Configuration": ["Nastavitve rezine z oznakami"], - "This section allows you to configure how to use the slice\r\n to generate annotations.": [ - "V tem sklopu lahko nastavite način uporabe rezine\r\n za ustvarjanje oznak." + "Target category": ["Kategorija cilja"], + "Category of target nodes": ["Kategorija ciljnih vozlišč"], + "Chart options": ["Možnosti grafikona"], + "Layout": ["Izgled"], + "Graph layout": ["Izgled grafikona"], + "Force": ["Sila"], + "Layout type of graph": ["Tip izgleda grafikona"], + "Edge symbols": ["Simboli povezav"], + "Symbol of two ends of edge line": ["Simbol za konca povezave"], + "None -> None": ["Brez -> Brez"], + "None -> Arrow": ["Brez -> Puščica"], + "Circle -> Arrow": ["Krog -> Puščica"], + "Circle -> Circle": ["Krog -> Krog"], + "Enable node dragging": ["Omogoči premikanje vozlišč"], + "Whether to enable node dragging in force layout mode.": [ + "Če želite omogočiti premikanje vozlišč v načinu vsiljenega prikaza." ], - "Annotation layer time column": ["Časovni stolpec sloja z oznakami"], - "Interval start column": ["Stolpec začetka intervala"], - "Event time column": ["Stolpec časa dogodka"], - "This column must contain date/time information.": [ - "Ta stolpec mora vsebovati informacijo o datumu/času." + "Enable graph roaming": ["Omogoči preoblikovanje grafikona"], + "Disabled": ["Onemogočeno"], + "Scale only": ["Samo povečava"], + "Move only": ["Samo premikanje"], + "Scale and Move": ["Povečava in premikanje"], + "Whether to enable changing graph position and scaling.": [ + "Če želite omogočiti premikanje in povečevanje/zmanjševanje grafikona." ], - "Annotation layer interval end": ["Konec intervala sloja z oznakami"], - "Interval End column": ["Stolpec konca intervala"], - "Annotation layer title column": ["Stolpec z naslovom sloja z oznakami"], - "Title Column": ["Stolpec z naslovi"], - "Pick a title for you annotation.": ["Izberite naslov za oznako."], - "Annotation layer description columns": [ - "Stolpci z opisi slojev z oznakami" + "Node select mode": ["Način izbire vozlišč"], + "Single": ["Posamezno"], + "Multiple": ["Več"], + "Allow node selections": ["Dovoli izbiro vozlišča"], + "Label threshold": ["Prag oznak"], + "Minimum value for label to be displayed on graph.": [ + "Najmanjša vrednost, za katero bo na grafikonu prikazana oznaka." ], - "Description Columns": ["Stolpci z opisi"], - "Pick one or more columns that should be shown in the annotation. If you don't select a column all of them will be shown.": [ - "Izberite enega ali več stolpcev, ki bodo prikazani v oznakah. Če ne izberete stolpca, bodo prikazani vsi." + "Node size": ["Velikost vozlišča"], + "Median node size, the largest node will be 4 times larger than the smallest": [ + "Mediana velikosti vozlišča. Največje vozlišče bo 4-krat večje od najmanjšega" ], - "Display configuration": ["Prikaži nastavitve"], - "Configure your how you overlay is displayed here.": [ - "Nastavite kako se tukaj prikazuje vrhnja plast." + "Edge width": ["Debelina povezave"], + "Median edge width, the thickest edge will be 4 times thicker than the thinnest.": [ + "Mediana debeline povezave. Najdebelejša povezava bo 4-krat debelejša od najtanjše." ], - "Annotation layer stroke": ["Obroba sloja z oznakami"], - "Style": ["Slog"], - "Annotation layer opacity": ["Prosojnost sloja z oznakami"], - "Opacity": ["Prosojnost"], - "Color": ["Barva"], - "Line width": ["Debelina črte"], - "Layer configuration": ["Nastavitve sloja"], - "Configure the basics of your Annotation Layer.": [ - "Osnovne nastavitve sloja z oznakami." + "Edge length": ["Dolžina povezave"], + "Edge length between nodes": ["Dolžina povezave med vozlišči"], + "Gravity": ["Gravitacija"], + "Strength to pull the graph toward center": [ + "Sila privlačnosti med grafikonom in središčem" ], - "Mandatory": ["Obvezno"], - "Hide layer": ["Skrij sloj"], - "Annotation layer type": ["Tip sloja z oznakami"], - "Choose the annotation layer type": ["Izberite tip sloja z oznakami"], - "Annotation source type": ["Tip vira oznak"], - "Choose the source of your annotations": ["Izberite vir svojih oznak"], - "Annotation Source": ["Vir oznak"], - "Remove": ["Odstrani"], - "Edit annotation layer": ["Uredi sloj z oznakami"], - "Add annotation layer": ["Dodaj sloj z oznakami"], - "Empty collection": ["Prazen izbor"], - "Add an item": ["Dodaj element"], - "Remove item": ["Odstrani element"], - "Edit formatter": ["Uredi oblikovanje"], - "Add new formatter": ["Dodaj novo oblikovanje"], - "Add new color formatter": ["Dodaj novo oblikovanje barve"], - "green": ["zelena"], - "yellow": ["rumena"], - "red": ["rdeča"], - "This value should be smaller than the right target value": [ - "Ta vrednost mora biti manjša od desne ciljne vrednosti" + "Repulsion": ["Odbijanje"], + "Repulsion strength between nodes": ["Odbojna sila med vozlišči"], + "Friction": ["Trenje"], + "Friction between nodes": ["Trenje med vozlišči"], + "Displays connections between entities in a graph structure. Useful for mapping relationships and showing which nodes are important in a network. Graph charts can be configured to be force-directed or circulate. If your data has a geospatial component, try the deck.gl Arc chart.": [ + "Prikaže povezave med entitetami v strukturi grafa. Uporabno za prikaz razmerij in pomembnih točk v omrežju. Grafikon je lahko krožnega tipa ali z usmerjenimi silami. Če imajo podatki geoprostorsko komponento, poskusite grafikon decl.gl - Arc." ], - "This value should be greater than the left target value": [ - "Ta vrednost mora biti večja od leve ciljne vrednosti" + "Graph Chart": ["Graf"], + "Structural": ["Strukturni"], + "Series type": ["Tip serije"], + "Series chart type (line, bar etc)": [ + "Tip grafikona za posamezno podatkovno serijo (črtni, stolpčni, ...)" ], - "Required": ["Obvezno"], - "Operator": ["Operator"], - "Left value": ["Leva vrednost"], - "Right value": ["Desna vrednost"], - "Target value": ["Ciljna vrednost"], - "Select column": ["Izberite stolpec"], - "Edit dataset": ["Uredi podatkovni set"], - "View in SQL Lab": ["Ogled v SQL laboratoriju"], - "More dataset related options": ["Več nastavitev za podatkovni set"], - "The dataset linked to this chart may have been deleted.": [ - "Podatkovni set, povezan s tem grafikonom, je bil izbrisan." + "Area chart": ["Ploščinski grafikon"], + "Draw area under curves. Only applicable for line types.": [ + "Izriši površino pod krivuljo. Samo za črtne grafikone." ], - "RANGE TYPE": ["TIP OBDOBJA"], - "Actual time range": ["Dejansko časovno obdobje"], - "CANCEL": ["PREKINI"], - "APPLY": ["UPORABI"], - "Edit time range": ["Uredi časovno obdobje"], - "Configure Advanced Time Range ": ["Nastavi napredno časovno obdobje "], - "START (INCLUSIVE)": ["ZAČETEK (VKLJUČEN)"], - "Start date included in time range": [ - "Začetni datum je vključen v časovno obdobje" + "Opacity of area chart.": ["Prosojnost ploščinskega grafikona."], + "Marker": ["Marker"], + "Draw a marker on data points. Only applicable for line types.": [ + "Nariši markerje na točke grafikona. Samo za črtne grafikone." ], - "END (EXCLUSIVE)": ["KONEC (NI VKLJUČEN)"], - "End date excluded from time range": [ - "Končni datum ni vključen v časovno obdobje" + "Marker size": ["Velikost markerja"], + "Size of marker. Also applies to forecast observations.": [ + "Velikost markerja. Upošteva se tudi za napovedi." ], - "Configure Time Range: Previous...": [ - "Nastavi časovno obdobje: Prejšnji ..." + "Primary": ["Primarna"], + "Secondary": ["Sekundarna"], + "Primary or secondary y-axis": ["Primarna ali sekundarna y-os"], + "Shared query fields": ["Polja deljenih poizvedb"], + "Query A": ["Poizvedba A"], + "Advanced analytics Query A": ["Poizvedba A za napredno analitiko"], + "Query B": ["Poizvedba B"], + "Advanced analytics Query B": ["Poizvedba B za napredno analitiko"], + "Data Zoom": ["Zoom funkcija"], + "Enable data zooming controls": [ + "Omogoči kontrolnik za povečavo podatkov" ], - "Configure Time Range: Last...": ["Nastavi časovno obdobje: Zadnji ..."], - "Configure custom time range": ["Nastavi prilagojeno časovno obdobje"], - "Relative quantity": ["Relativne vrednosti"], - "Relative period": ["Relativno obdobje"], - "Anchor to": ["Sidraj na"], - "NOW": ["ZDAJ"], - "Date/Time": ["Datum/Čas"], - "Return to specific datetime.": ["Vrne določen datum-čas."], - "Syntax": ["Sintaksa"], - "Example": ["Primer"], - "Moves the given set of dates by a specified interval.": [ - "Premakne dani nabor datumov za definirano obdobje." + "Rotate x axis label": ["Zavrti oznako x-osi"], + "Input field supports custom rotation. e.g. 30 for 30°": [ + "Vnosno polje omogoča poljubno rotacijo (vnesite 30 za 30°)" ], - "Truncates the specified date to the accuracy specified by the date unit.": [ - "Zaokroži določen datum, glede na natančnost, definirano s časovno enoto." + "Minor Split Line": ["Manjša ločilna črta"], + "Draw split lines for minor y-axis ticks": [ + "Izriši ločilne črte za pomožne oznake y-osi" ], - "Get the last date by the date unit.": [ - "Pridobi zadnji datum glede na časovno enoto." + "Truncate Y Axis": ["Prireži Y-os"], + "Truncate Y Axis. Can be overridden by specifying a min or max bound.": [ + "Prireži Y-os. Če določite spodnjo ali zgornjo mejo, preprečite prirezovanje." ], - "Get the specify date for the holiday": ["Določi datum praznika"], - "Last": ["Zadnji"], - "Previous": ["Prejšnji"], - "Custom": ["Prilagojen"], - "last day": ["zadnji dan"], - "last week": ["zadnji teden"], - "last month": ["zadnji mesec"], - "last quarter": ["zadnje četrletje"], - "last year": ["zadnje leto"], - "previous calendar week": ["prejšnji koledarski teden"], - "previous calendar month": ["prejšnji koledarski mesec"], - "previous calendar year": ["prejšnje koledarsko leto"], - "Before": ["PRED"], - "After": ["PO"], - "Specific Date/Time": ["Fiksen Datum/Čas"], - "Relative Date/Time": ["Relativen Datum/Čas"], - "Now": ["Zdaj"], - "Midnight": ["Polnoč"], - "Saved expressions": ["Shranjeni izrazi"], - "Saved": ["Shranjeno"], - "%s column(s)": ["Stolpci: %s"], - "Simple": ["Preprosto"], - "Drop a column here or click": ["Spustite stolpec sem ali kliknite"], - "Drop column here": ["Spustite stolpec sem"], - "Drop columns/metrics here or click": [ - "Spustite stolpce/mere sem ali kliknite" + "Primary y-axis format": ["Oblika primarne y-osi"], + "Logarithmic y-axis": ["Logaritemska y-os"], + "Logarithmic scale on primary y-axis": [ + "Logaritemska skala na primarni y-osi" + ], + "Secondary y-axis format": ["Oblika sekundarne y-osi"], + "Secondary y-axis title": ["Naslov sekundarne y-osi"], + "Logarithmic scale on secondary y-axis": [ + "Logaritemska skala na sekundarni y-osi" + ], + "Visualize two different series using the same x-axis. Note that both series can be visualized with a different chart type (e.g. 1 using bars and 1 using a line).": [ + "Prikaže dva različna niza na isti x-osi. Niza sta lahko prikazana z različnim tipom grafikona (npr. en s stolpci in drug s črto)." + ], + "Visualize two different time series using the same x-axis. Note that each time series can be visualized differently (e.g. 1 using bars and 1 using a line).": [ + "Prikaže dve različni časovni vrsti na isti x-osi. Časovni vrsti sta lahko prikazani različno (npr. ena s stolpci in druga s črto)." ], - "Drop columns or metrics here": ["Spustite stolpce ali mere sem"], - "Drop a column/metric here or click": [ - "Spustite stolpec/mero sem ali kliknite" + "Mixed Chart": ["Kombinirani grafikon"], + "Mixed Time-Series": ["Kombiniran grafikon časovne vrste"], + "Put the labels outside of the pie?": ["Postavim oznake zunaj torte?"], + "Label Line": ["Črta oznake"], + "Draw line from Pie to label when labels outside?": [ + "Ali želite črto do oznake, ko so le-te zunaj?" ], - "Drop column or metric here": ["Spustite stolpec ali mero sem"], - "Drop columns here": ["Spustite stolpce sem"], - "\r\n This filter was inherited from the dashboard's context.\r\n It won't be saved when saving the chart.\r\n ": [ - "\r\n Ta filter izvira iz konteksta nadzorne plošče.\r\n Pri shranjevanju grafikona se ne bo shranil.\r\n " + "Show Total": ["Pokaži vsoto"], + "Whether to display the aggregate count": [ + "Če želite prikazati agregirano število" ], - "Default": ["Privzeto"], - "(optional) default value for the filter, when using the multiple option, you can use a semicolon-delimited list of options.": [ - "(opcijsko) privzeta vrednost za filter, če uporabite opcijo izbire večih , lahko uporabite seznam nastavitev ločen s podpičji." + "Pie shape": ["Oblika torte"], + "Outer Radius": ["Zunanji polmer"], + "Outer edge of Pie chart": ["Zunanji rob tortnega grafikona"], + "Inner Radius": ["Notranji polmer"], + "Inner radius of donut hole": ["Notranji polmer kolobarja"], + "The classic. Great for showing how much of a company each investor gets, what demographics follow your blog, or what portion of the budget goes to the military industrial complex.\n\n Pie charts can be difficult to interpret precisely. If clarity of relative proportion is important, consider using a bar or other chart type instead.": [ + "Standardni grafikon za prikaz deležev. Tortne grafikone je težje natančno interpretirati, takrat lahko uporabite npr. stolpčni grafikon." ], - "Metric to sort the results by": ["Mera za razvrščanje rezultatov"], - "Check for sorting ascending": ["Označi za naraščajoče razvrščanje"], - "Allow multiple selections": ["Dovoli več izbir"], - "Multiple selections allowed, otherwise filter is limited to a single value": [ - "Lahko izberete več elementov, drugače pa je filter omejen na eno vrednost" + "Total: %s": ["Vsota: %s"], + "The maximum value of metrics. It is an optional configuration": [ + "Največja vrednost mere. To je opcijska nastavitev" ], - "Search all filter options": ["Poišči vse možnosti filtra"], - "By default, each filter loads at most 1000 choices at the initial page load. Check this box if you have more than 1000 filter values and want to enable dynamically searching that loads filter values as users type (may add stress to your database).": [ - "Privzeto vsak filter pri nalaganju začetne strani naloži največ 1000 možnosti. Označite polje, če imate več kot 1000 vrednosti filtra in želite omogočiti dinamično iskanje, ki nalaga vrednosti filtra ko uporabnik tipka (to lahko preobremeni vašo podatkovno bazo)." + "Label position": ["Položaj oznake"], + "Radar": ["Radar"], + "Customize Metrics": ["Prilagodi mere"], + "Further customize how to display each metric": [ + "Dodatne prilagoditve prikaza posameznih mer" ], - "User must select a value for this filter": [ - "Uporabnik mora izbrati vrednost za ta filter" + "Circle radar shape": ["Okrogla oblika radarja"], + "Radar render type, whether to display 'circle' shape.": [ + "Način prikaza radarja - če se prikaže okrogla oblika." ], - "Filter configuration": ["Nastavitve filtra"], - "Custom SQL ad-hoc filters are not available for the native Druid connector": [ - "Ad-hoc SQL filtri po meri niso na voljo za nativni konektor za Druid" + "Visualize a parallel set of metrics across multiple groups. Each group is visualized using its own line of points and each metric is represented as an edge in the chart.": [ + "Prikaže vzporedni nabor mer za različne skupine. Vsaka skupina je prikazana s svojim naborom točk in vsaka mera s povezavo na grafikonu." ], - "Custom SQL": ["Prilagojen SQL"], - "%s option(s)": ["Možnosti: %s"], - "Select subject": ["Izberite zadevo"], - "No such column found. To filter on a metric, try the Custom SQL tab.": [ - "Tak stolpec ni najden. Za filtriranje po meri uporabite prilagojen SQL zavihek." + "Radar Chart": ["Radarski grafikon"], + "Contribution Mode": ["Način deležev"], + "Calculate contribution per series or row": [ + "Izračunaj delež za serijo ali vrstico" ], - "%s column(s) and metric(s)": ["Stolpcev in mer: %s"], - "To filter on a metric, use Custom SQL tab.": [ - "Za filtriranje po meri uporabite prilagojen SQL zavihek." + "Series Style": ["Slog serije"], + "Area chart opacity": ["Prosojnost ploščinskega grafikona"], + "Opacity of Area Chart. Also applies to confidence band.": [ + "Prosojnost ploščinskega grafikona. Upošteva se tudi za interval zaupanja." ], - "%s operator(s)": ["Operatorji: %s"], - "Select operator": ["Izberite operator"], - "Comparator option": ["Možnosti komparatorja"], - "Type a value here": ["Vnesite vrednost sem"], - "Filter value (case sensitive)": [ - "Vrednost filtra (razlik. velikih/malih črk)" + "Marker Size": ["Velikost markerja"], + "Swiss army knife for visualizing data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.": [ + "Univerzalni grafikon za vizualizacijo podatkov. Izbirajte med stopničastimi, črtnimi, raztresenimi in stolpčnimi grafikoni. Grafikon ima širok nabor prilagoditev." ], - "choose WHERE or HAVING...": ["izberite WHERE ali HAVING..."], - "Filters by columns": ["Filtrira po stolpcu"], - "Filters by metrics": ["Filtrira po merah"], - "Fixed": ["Fiksno"], - "Based on a metric": ["Osnovan na meri"], - "My metric": ["Moja mera"], - "Add metric": ["Dodaj mero"], - "Select aggregate options": ["Izberite agregacijske možnosti"], - "%s aggregates(s)": ["Agreg. funkcije: %s"], - "Select saved metrics": ["Izberite shranjene mere"], - "%s saved metric(s)": ["Shranjene mere: %s"], - "Saved metric": ["Shranjena mera"], - "Simple ad-hoc metrics are not enabled for this dataset": [ - "Preproste ad-hoc mere za ta podatkovni set niso omogočene" + "Swiss army knife for visualizing time series data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.": [ + "Univerzalni grafikon za prikaz časovnih vrst. Izbirajte med stopničnimi, črtnimi, raztresenimi in stolpčnimi grafikoni. Grafikon ima širok nabor prilagoditev." ], - "column": ["stolpec"], - "aggregate": ["agregacija"], - "Custom SQL ad-hoc metrics are not available for the native Druid connector": [ - "Ad-hoc SQL mere po meri niso na voljo za nativni konektor za Druid" + "Generic Chart": ["Generičen grafikon"], + "Time-series Chart": ["Grafikon časovne vrste"], + "zoom area": ["približaj območje"], + "restore zoom": ["ponastavi prikaz"], + "Area charts are similar to line charts in that they represent variables with the same scale, but area charts stack the metrics on top of each other.": [ + "Ploščinski grafikoni so podobni črtnim grafikonom, saj predstavljajo spremenljivke v istem razmerju, vendar se pri ploščinskih grafikonih mere nalagajo ena na drugo." ], - "Custom SQL ad-hoc metrics are not enabled for this dataset": [ - "Ad-hoc SQL mere po meri za ta podatkovni set niso omogočene" + "Time-series Area chart are similar to line chart in that they represent variables with the same scale, but area charts stack the metrics on top of each other. An area chart in Superset can be stream, stack, or expand.": [ + "Ploščinski grafikoni časovne vrste so podobni črtnim grafikonom, saj predstavljajo spremenljivke v istem razmerju, vendar se pri ploščinskih grafikonih mere nalagajo ena na drugo." ], - "Time series columns": ["Stolpci s časovnimi vrstami"], - "Other": ["Ostali"], - "Popular": ["Priljubljeni"], - "ECharts": ["ECharts"], - "Advanced-Analytics": ["Napredna analitika"], - "Recommended tags": ["Priporočene značke"], - "Category": ["Kategorija"], - "Tags": ["Značke"], - "Search all charts": ["Išči vse grafikone"], - "No description available.": ["Opisa ni na razpolago."], - "Examples": ["Vzorci"], - "This visualization type is not supported.": [ - "Ta tip vizualizacije ni podprt." + "Area Chart v2": ["Ploščinski grafikon v2"], + "Time-series Area Chart": ["Ploščinski grafikon časovne vrste"], + "Axis Title": ["Naslov osi"], + "AXIS TITLE MARGIN": ["OBROBA OZNAKE OSI"], + "AXIS TITLE POSITION": ["POLOŽAJ OZNAKE OSI"], + "Rotate axis label": ["Zavrti oznako osi"], + "Axis Format": ["Oblika osi"], + "Logarithmic axis": ["Logaritemska os"], + "Draw split lines for minor axis ticks": [ + "Izriši ločilne črte za pomožne oznake osi" + ], + "Truncate Axis": ["Prireži os"], + "It’s not recommended to truncate axis in Bar chart.": [ + "V stolpčnem grafikonu ni priporočljivo omejiti osi." + ], + "Axis Bounds": ["Meje osi"], + "Bounds for the axis. When left empty, the bounds are dynamically defined based on the min/max of the data. Note that this feature will only expand the axis range. It won't narrow the data's extent.": [ + "Meje osi. Če je prazno, se meje nastavijo dinamično na podlagi min./max. vrednosti podatkov. Funkcija omeji le prikaz, obseg podatkov pa ostane enak." + ], + "Chart Orientation": ["Orientacija grafikona"], + "Bar orientation": ["Orientacija stolpcev"], + "Horizontal": ["Vodoravno"], + "Orientation of bar chart": ["Orientacija stolpčnega grafikona"], + "Bar Charts are used to show metrics as a series of bars.": [ + "Stolpčni grafikoni se uporabljajo za prikaz mer z nizi stolpcev." ], - "Select Viz Type": ["Izberite tip vizualizacije"], - "Click to change visualization type": [ - "Kliknite za spremembo tipa vizualizacije" + "Time-series Bar Charts are used to show the changes in a metric over time as a series of bars.": [ + "Stolpčni grafikoni časovne vrste se uporabljajo za prikaz sprememb mere skozi čas s pomočjo niza stolpcev." ], - "Select a visualization type": ["Izberite tip vizualizacije"], - "Select": ["Izberi"], - "Code": ["Koda"], - "Markup type": ["Tip označevanja"], - "Pick your favorite markup language": [ - "Izberite svoj priljubljen označevalni jezik" + "Bar Chart v2": ["Stolpčni grafikon v2"], + "Time-series Bar Chart v2": ["Stolpčni grafikon časovne vrste v2"], + "Line chart is used to visualize measurements taken over a given category. Line chart is a type of chart which displays information as a series of data points connected by straight line segments. It is a basic type of chart common in many fields.": [ + "Črtni grafikon se uporablja se za vizualizacijo meritev zajetih skozi čas. Posamezne točke so med seboj povezane z ravnimi črtami." ], - "Put your code here": ["Vstavite svojo kodo sem"], - "Query": ["Poizvedba"], - "URL": ["URL"], - "Templated link, it's possible to include {{ metric }} or other values coming from the controls.": [ - "Vzorčna povezava, vključiti je mogoče {{ metric }} ali drugo vrednost iz kontrolnikov." + "Time-series line chart is used to visualize repeated measurements taken over regular time intervals. Line chart is a type of chart which displays information as a series of data points connected by straight line segments. It is a basic type of chart common in many fields.": [ + "Črtni grafikon časovne vrste je osnovni grafikon, ki se uporablja na različnih področjih. Uporablja se za vizualizacijo meritev zajetih skozi čas. Posamezne točke so med seboj povezane z ravnimi črtami." ], - "Time": ["Čas"], - "Time related form attributes": ["S časom povezani atributi prikaza"], - "Chart type": ["Tip grafikona"], - "Chart ID": ["ID grafikona"], - "The id of the active chart": ["Identifikator aktivnega grafikona"], - "Cache Timeout (seconds)": ["Trajanje predpomnilnika (sekunde)"], - "The number of seconds before expiring the cache": [ - "Trajanje (v sekundah) do razveljavitve predpomnilnika" + "Time-series Line Chart": ["Črtni grafikon časovne vrste"], + "Scatter Plot has the horizontal axis in linear units, and the points are connected in order. It shows a statistical relationship between two variables.": [ + "Raztreseni grafikon ima vodoravno os v linearnih enotah, prikazuje podatkovne točke v povezanem redu in prikazuje statistično razmerje med dvema spremenljivkama." ], - "URL parameters": ["Parametri URL"], - "Extra parameters for use in jinja templated queries": [ - "Dodatni parametri za poizvedbe z jinja predlogami" + "Time-series Scatter Plot has time on the horizontal axis in linear units, and the points are connected in order. It shows a statistical relationship between two variables.": [ + "Raztreseni grafikon časovne vrste prikazuje podatkovne točke v povezanem redu in prikazuje statistično razmerje med spremenljivkami." ], - "Time range endpoints": ["Krajne točke časovnega obdobja"], - "Time range endpoints (SIP-15)": [ - "Krajne točke časovnega obdobja (SIP-15)" + "Scatter Plot": ["Raztreseni grafikon"], + "Time-series Scatter Plot": ["Raztreseni grafikon časovne vrste"], + "Smooth-line is a variation of the line chart. Without angles and hard edges, Smooth-line sometimes looks smarter and more professional.": [ + "Zglajeni črtni grafikon je izpeljanka črtnega grafikona, ki zgladi ostre robove krivulje." ], - "Annotations and layers": ["Oznake in sloji"], - "Whether to sort descending or ascending": [ - "Če želite padajoče ali naraščajoče razvrščanje" + "Time-series Smooth-line is a variation of the line chart. Without angles and hard edges, Smooth-line sometimes looks smarter and more professional.": [ + "Zglajeni grafikon časovne vrste je izpeljanka črtnega grafikona, ki zgladi ostre robove krivulje." ], - "Contribution": ["Prispevek"], - "Compute the contribution to the total": ["Izračunaj prispevek k celoti"], - "Advanced analytics": ["Napredna analitika"], - "This section contains options that allow for advanced analytical post processing of query results": [ - "Ta sekcija vsebuje možnosti, ki omogočajo napredno analitično poprocesiranje rezultatov poizvedb" + "Smooth Line": ["Zglajena črta"], + "Time-series Smooth Line": ["Zglajeni črtni grafikon časovne vrste"], + "Step type": ["Stopnični tip"], + "Defines whether the step should appear at the beginning, middle or end between two data points": [ + "Določa, če se na začetku, na sredini ali na koncu pojavi stopnica med dvema točkama" ], - "Rolling window": ["Drseče okno"], - "Rolling function": ["Drseča funkcija"], - "Defines a rolling window function to apply, works along with the [Periods] text box": [ - "Določi funkcijo drsečega okna. Dela skupaj s tekstovnim okvirjem [Obdobja]" + "Stepped-line graph (also called step chart) is a variation of line chart but with the line forming a series of steps between data points. A step chart can be useful when you want to show the changes that occur at irregular intervals.": [ + "Stopničasti grafikon je izpeljanka črtnega grafikona, pri čemer krivuljo tvorijo stopnice med posameznimi točkami. Koristen je za prikaz sprememb na posameznih intervalih." ], - "Periods": ["Št. period"], - "Defines the size of the rolling window function, relative to the time granularity selected": [ - "Določi velikost funkcije drsečega okna, glede na izbrano granulacijo časa" + "Time-series Stepped-line graph (also called step chart) is a variation of line chart but with the line forming a series of steps between data points. A step chart can be useful when you want to show the changes that occur at irregular intervals.": [ + "Stopnični grafikon časovne vrste je izpeljanka črtnega grafikona, pri čemer krivuljo tvorijo stopnice med posameznimi točkami. Koristen je za prikaz sprememb na posameznih intervalih." ], - "Min periods": ["Min. št. period"], - "The minimum number of rolling periods required to show a value. For instance if you do a cumulative sum on 7 days you may want your \"Min Period\" to be 7, so that all data points shown are the total of 7 periods. This will hide the \"ramp up\" taking place over the first 7 periods": [ - "Minimalno število drsečih obdobij, potrebnih za prikaz vrednosti. Če računate kumulativno vsoto 7-dnevnega obdobja, boste nastavili \"Min. št. period\" na 7. Tako bodo vse prikazane točke skupaj obsegale 7 obdobij. To bo prikrilo rampo, ki bi trajala prvih 7 obdobij" + "Stepped Line": ["Stopničasta črta"], + "Time-series Stepped Line": ["Stopnični črtni grafikon časovne vrste"], + "Id": ["Id"], + "Name of the id column": ["Naziv id-stolpca"], + "Parent": ["Nadrejeni"], + "Name of the column containing the id of the parent node": [ + "Ime stolpca, ki vsebuje id nadrejenega vozlišča" ], - "Time comparison": ["Časovna primerjava"], - "Time shift": ["Časovni zamik"], - "Overlay one or more timeseries from a relative time period. Expects relative time deltas in natural language (example: 24 hours, 7 days, 52 weeks, 365 days). Free text is supported.": [ - "Zamaknite eno ali več časovnih vrst za relativno časovno obdobje. Vnaša se relativne časovne razlike v naravnem jeziku (npr. 24 ur, 7 dni, 52 tednov, 365 dni). Prosto besedilo je podprto." + "Optional name of the data column.": [ + "Opcijsko ime podatkovnega stolpca." ], - "Calculation type": ["Tip izračuna"], - "How to display time shifts: as individual lines; as the difference between the main time series and each time shift; as the percentage change; or as the ratio between series and time shifts.": [ - "Način prikaza časovnih zamikov: kot samostojne črte; kot razlike med osnovno časovno vrsto in vsakim časovnim zamikom; kot procentualna sprememba; kot razmerje med vrsto in časovnim zamikom." + "Root node id": ["Id korenskega vozlišča"], + "Id of root node of the tree.": ["Id korenskega vozlišča drevesa."], + "Metric for node values": ["Mera za vrednosti vozlišč"], + "Tree layout": ["Oblika drevesa"], + "Orthogonal": ["Pravokotna"], + "Radial": ["Radialna"], + "Layout type of tree": ["Način izgleda drevesa"], + "Tree orientation": ["Orientacija drevesa"], + "Left to Right": ["Iz leve proti desni"], + "Right to Left": ["Iz desne proti levi"], + "Top to Bottom": ["Iz vrha proti dnu"], + "Bottom to Top": ["Iz dna proti vrhu"], + "Orientation of tree": ["Orientacija drevesa"], + "Node label position": ["Položaj oznake vozlišča"], + "left": ["levo"], + "top": ["zgoraj"], + "right": ["desno"], + "bottom": ["spodaj"], + "Position of intermidiate node label on tree": [ + "Položaj vmesne oznake vozlišča na drevesu" ], - "Python functions": ["Pythonove funkcije"], - "Rule": ["Pravilo"], - "Pandas resample rule": ["Pravilo za prevzorčenje v Pandas"], - "Method": ["Metoda"], - "Pandas resample method": ["Metoda za prevzorčenje v Pandas"], - "No columns": ["Brez stolpcev"], - "%s option": ["%s možnost"], - "UI Configuration": ["UI nastavitve"], - "Multiple select": ["Več izborov"], - "Allow selecting multiple values": ["Dovoli izbiro več vrednosti"], - "User must select a value for this filter.": [ - "Uporabnik mora izbrati vrednost za ta filter." + "Child label position": ["Položaj podrejene oznake"], + "Position of child node label on tree": [ + "Položaj oznake podrejenega vozlišča na drevesu" ], - "Group By filter plugin": ["Vtičnik za filter za združevanje"], - "Experimental": ["Eksperimentalno"], - "Chosen non-numeric column": ["Izbran ne-numeričen stolpec"], - "Range filter plugin using AntD": [ - "Vtičnik za filter obdobja z uporabo AntD" + "Emphasis": ["Poudari"], + "ancestor": ["nadrejeni"], + "descendant": ["podrejeni"], + "Which relatives to highlight on hover": [ + "Kateri element se poudari na prehodu z miško" ], - "User must select a value before applying the filter": [ - "Uporabnik mora izbrati vrednost pred uporabo filtra" + "Symbol": ["Simbol"], + "Empty circle": ["Prazen krog"], + "Circle": ["Krog"], + "Rectangle": ["Pravokotnik"], + "Triangle": ["Trikotnik"], + "Diamond": ["Karo"], + "Pin": ["Žebljiček"], + "Arrow": ["Puščica"], + "Symbol size": ["Velikost simbola"], + "Size of edge symbols": ["Velikost simbola povezave"], + "Visualize multiple levels of hierarchy using a familiar tree-like structure.": [ + "Prikaz več hierarhičnih nivojev z drevesno strukturo." + ], + "Tree Chart": ["Drevesni grafikon"], + "Show Upper Labels": ["Prikaži zgornje oznake"], + "Show labels when the node has children.": [ + "Prikaži oznake, ko ima vozlišče podrejene elemente." + ], + "Show hierarchical relationships of data, with with the value represented by area, showing proportion and contribution to the whole.": [ + "Prikaže hierarhična razmerja podatkov, pri čemer je vrednost ponazorjena s ploščino, in deleže oz. prispevke k celoti." ], - "Default to first item": ["Privzet prvi element"], - "Select first item by default (when using this option, default value can’t be set)": [ - "Izberi prvi element kot privzet (ko uporabljate to možnost, privzete vrednost ni mogoče nastaviti)" + "Treemap v2": ["Drevesni grafikon s pravokotniki v2"], + "page_size.all": ["page_size.all"], + "Handlebars": ["Handlebars"], + "must have a value": ["mora imeti vrednost"], + "Handlebars Template": ["Predloga za Handlebars"], + "A handlebars template that is applied to the data": [ + "Predloga za Handlebars, ki je uporabljena za podatke" + ], + "Include time": ["Vključi čas"], + "Whether to include the time granularity as defined in the time section": [ + "Če želite vključiti granulacijo časa, ki je določena v sekciji Čas" + ], + "Percentage metrics": ["Procentualne mere"], + "Metrics for which percentage of total are to be displayed. Calculated from only data within the row limit.": [ + "Mera, za katero je prikazan odstotek od celote. Izračunan je samo iz podatkov znotraj omejitve števila vrstic." + ], + "Show total aggregations of selected metrics. Note that row limit does not apply to the result.": [ + "Prikaži skupno agregacijo izbrane mere. Omejitev števila vrstic ne vpliva na rezultat." + ], + "Ordering": ["Razvrščanje"], + "Order results by selected columns": [ + "Razvrsti rezultate glede na izbrani stolpec" ], - "Inverse selection": ["Invertiraj izbiro"], - "Exclude selected values": ["Izloči izbrane vrednosti"], - "Select filter plugin using AntD": [ - "Izberite Vtičnik za filter z uporabo AntD" + "Server pagination": ["Paginacija na strani strežnika"], + "Enable server side pagination of results (experimental feature)": [ + "Omogoči številčenje strani rezultatov na strani strežnika (preizkusna funkcija)" ], - "Custom time filter plugin": ["Prilagojeni vtičnik za časovni filter"], - "No time columns": ["Ni časovnih stolpcev"], - "Time column filter plugin": ["Vtičnik za časovni filter"], - "Time grain filter plugin": ["Vtičnik za filter časovne granulacije"], - "Favorites": ["Priljubljene"], - "Created content": ["Ustvarjena vsebina"], - "Recent activity": ["Nedavna aktivnost"], - "Security & Access": ["Varnost in Dostopi"], - "No charts": ["Ni grafikonov"], - "No dashboards": ["Ni nadzornih plošč"], - "No favorite charts yet, go click on stars!": [ - "Priljubljenih grafikonov še ni. Kliknite na zvezdice!" + "Server Page Length": ["Dolžina strani strežnika"], + "Rows per page, 0 means no pagination": [ + "Vrstic na stran (0 pomeni brez številčenja strani)" ], - "No favorite dashboards yet, go click on stars!": [ - "Priljubljenih nadzornih plošč še ni. Kliknite na zvezdice!" + "Query mode": ["Poizvedbeni način"], + "Group By, Metrics or Percentage Metrics must have a value": [ + "Združevanje, Mera ali Procentualna mera morajo imeti vrednost" ], - "Profile picture provided by Gravatar": [ - "Profilno sliko je zagotovil Gravatar" + "CSS Styles": ["CSS slogi"], + "CSS applied to the chart": ["CSS slogi uporabljeni za grafikon"], + "Columns to group by on the columns": ["Stolpci za združevanje stolpcev"], + "Rows": ["Vrstice"], + "Columns to group by on the rows": ["Stolpci za združevanje vrstic"], + "Apply metrics on": ["Uporabi mero na"], + "Use metrics as a top level group for columns or for rows": [ + "Uporabi mere kot vrhovni nivo grupiranja za stolpce ali vrstice" ], - "joined": ["pridružen"], - "id:": ["id:"], - "There was an issue fetching reports attached to this dashboard.": [ - "Pri pridobivanju poročil za to nadzorno ploščo je prišlo do težave." + "Cell limit": ["Omejitev celice"], + "Limits the number of cells that get retrieved.": [ + "Omeji število pridobljenih celic." ], - "The report has been created": ["Poročilo je bilo ustvarjeno"], - "An error occurred while editing this report: %s": [ - "Pri urejanju tega poročila je prišlo do napake: %s" + "Metric used to define how the top series are sorted if a series or cell limit is present. If undefined reverts to the first metric (where appropriate).": [ + "Mera, ki določa kako so razvrščene prve serije, če je določena omejitev serij ali vrstic. Če ni določena, se uporabi prva mera (kjer je ustrezno)." ], - "An error occurred while editing this report.": [ - "Pri urejanju tega poročila je prišlo do napake." + "Show rows total": ["Prikaži vsoto vrstic"], + "Display row level total": ["Prikaži vsote na nivoju vrstic"], + "Show columns total": ["Prikaži vsoto stolpcev"], + "Display column level total": ["Prikaži vsote na nivoju stolpcev"], + "Transpose pivot": ["Transponirano vrtenje"], + "Swap rows and columns": ["Zamenjaj vrstice in stolpce"], + "Combine metrics": ["Združuj mere"], + "D3 time format for datetime columns": [ + "D3 oblika zapisa za časovne stolpce" ], - "We were unable to active or deactivate this report.": [ - "Aktiviranje ali deaktiviranje poročila ni uspelo." + "Sort rows by": ["Razvrsti vrstice"], + "key a-z": ["a - ž"], + "key z-a": ["ž - a"], + "value ascending": ["0 - 9"], + "value descending": ["9 - 0"], + "Change order of rows.": ["Spremeni vrstni red vrstic."], + "Available sorting modes:": ["Razpoložljivi načini razvrščanja:"], + "By key: use row names as sorting key": [ + "Po ključu: za razvrščanje uporabite imena vrstic" ], - "Your report could not be deleted": [ - "Vašega poročila ni mogoče izbrisati" + "By value: use metric values as sorting key": [ + "Po vrednosti: za razvrščanje uporabite vrednosti mere" ], - "Deleted: %s": ["Izbrisano: %s"], - "Image download failed, please refresh and try again.": [ - "Prenos slike ni uspel. Osvežite in poskusite ponovno." + "Sort columns by": ["Razvrsti stolpce"], + "Change order of columns.": ["Spremeni vrstni red stolpcev."], + "By key: use column names as sorting key": [ + "Po ključu: za razvrščanje uporabite imena stolpcev" ], - "Unexpected error: ": ["Nepričakovana napaka: "], - "(no description, click to see stack trace)": [ - "(ni opisa, kliknite za ogled zapisov)" + "Rows subtotal position": ["Položaj vsot vrstic"], + "Top": ["Zgoraj"], + "Bottom": ["Spodaj"], + "Position of row level subtotal": ["Položaj vsot na nivoju vrstic"], + "Columns subtotal position": ["Položaj delnih vsot stolpcev"], + "Position of column level subtotal": ["Položaj vsot na nivoju stolpcev"], + "Conditional formatting": ["Pogojno oblikovanje"], + "Apply conditional color formatting to metrics": [ + "Za mere uporabi pogojno oblikovanje z barvami" ], - "Issue 1000 - The dataset is too large to query.": [ - "Težava 1000 - podatkovni vir je prevelik za poizvedbo." + "Used to summarize a set of data by grouping together multiple statistics along two axes. Examples: Sales numbers by region and month, tasks by status and assignee, active users by age and location. Not the most visually stunning visualization, but highly informative and versatile.": [ + "Ponazori podatke na podlagi združevanja več statistik vzdolž dveh osi. Npr. prodaja po regijah in mesecih, opravila po statusih in izvajalcih, itd." ], - "Issue 1001 - The database is under an unusual load.": [ - "Težava 1001 - podatkovni vir je neobičajno obremenjen." + "Pivot Table v2": ["Vrtilna tabela v2"], + "Unknown input format": ["Neznana oblika vnosa"], + "search.num_records": ["search.num_records"], + "page_size.show": ["page_size.show"], + "page_size.entries": ["page_size.entries"], + "Totals": ["Vsote"], + "Timestamp format": ["Oblika zapisa časovne značke"], + "Page length": ["Dolžina strani"], + "Search box": ["Iskalno polje"], + "Whether to include a client-side search box": [ + "Če želite vključiti iskalno polje za uporabnika" ], - "An error occurred while fetching %s info: %s": [ - "Napaka pri pridobivanju informacij za %s: %s" + "Cell bars": ["Stolp. graf v celicah"], + "Whether to align background charts with both positive and negative values at 0": [ + "Če želite poravnati graf v ozadju celic za negativne in pozitivne vrednosti okrog 0" ], - "An error occurred while fetching %ss: %s": [ - "Napaka pri pridobivanju informacij za %s: %s" + "Allow columns to be rearranged": ["Omogoči razvrščanje stolpcev"], + "Allow end user to drag-and-drop column headers to rearrange them. Note their changes won't persist for the next time they open the chart.": [ + "Uporabniku omogočite, da s potegom razvrsti stolpce. Sprememba se ne bo ohranila, ko bo grafikon ponovno naložen." ], - "An error occurred while creating %ss: %s": [ - "Napaka pri ustvarjanju %s: %s" + "Customize columns": ["Prilagodi stolpce"], + "Further customize how to display each column": [ + "Dodatne prilagoditve prikaza posameznih stolpcev" ], - "An error occurred while importing %s: %s": [ - "Napaka pri uvažanju %s: %s" + "Apply conditional color formatting to numeric columns": [ + "Za numerične stolpce uporabi pogojno oblikovanje z barvami" ], - "There was an error fetching the favorite status: %s": [ - "Napaka pri pridobivanju statusa \"Priljubljeno\": %s" + "Classic row-by-column spreadsheet like view of a dataset. Use tables to showcase a view into the underlying data or to show aggregated metrics.": [ + "Standardna razpredelnica za prikaz podatkovnega seta." ], - "There was an error saving the favorite status: %s": [ - "Napaka pri shranjevanju statusa \"Priljubljeno\": %s" + "Word Cloud": ["Oblak besed"], + "Minimum Font Size": ["Min. velikost pisave"], + "Font size for the smallest value in the list": [ + "Velikost pisave za najmanjšo vrednost na seznamu" ], - "Link Copied!": ["Povezava kopirana!"], - "Connection looks good!": ["Povezava izgleda v redu!"], - "${t('ERROR: ')}${parsedErrorMessage(errMsg)}": [ - "${t('NAPAKA: ')}${parsedErrorMessage(errMsg)}" + "Maximum Font Size": ["Max. velikost pisave"], + "Font size for the biggest value in the list": [ + "Velikost pisave za največjo vrednost na seznamu" ], - "There was an error fetching your recent activity:": [ - "Pri pridobivanju nedavnih aktivnosti je prišlo do napake:" + "Word Rotation": ["Vrtenje besed"], + "Rotation to apply to words in the cloud": [ + "Če želite vrtenje besed v oblaku" ], - "There was an issue deleting: %s": ["Težava pri brisanju: %s"], - "There was an issue deleting %s: %s": ["Težava pri brisanju %s: %s"], - "report": ["poročilo"], - "alert": ["opozorilo"], - "reports": ["poročila"], - "alerts": ["opozorila"], - "There was an issue deleting the selected %s: %s": [ - "Težava pri brisanju izbranih %s: %s" + "Visualizes the words in a column that appear the most often. Bigger font corresponds to higher frequency.": [ + "Prikaže besede v stolpcu, glede na pogostost pojavljanja. Večja pisava pomeni večjo frekvenco." ], - "Last run": ["Zadnji zagon"], - "Notification method": ["Način obveščanja"], - "Execution log": ["Dnevnik izvajanja"], - "Actions": ["Aktivnosti"], - "Bulk select": ["Izberi hkrati"], - "No %s yet": ["%s še ne obstajajo"], - "Created by": ["Ustvaril"], - "An error occurred while fetching created by values: %s": [ - "Pri pridobivanju vrednosti \"Ustvaril\" je prišlo do napake: %s" + "The query couldn't be loaded": ["Poizvedbe ni mogoče naložiti"], + "Your query has been scheduled. To see details of your query, navigate to Saved queries": [ + "Vaša poizvedba je v urniku. Za ogled podrobnosti poizvedbe pojdite na shranjene poizvedbe" ], - "Status": ["Status"], - "${AlertState.success}": ["${AlertState.success}"], - "${AlertState.working}": ["${AlertState.working}"], - "${AlertState.error}": ["${AlertState.error}"], - "${AlertState.noop}": ["${AlertState.noop}"], - "${AlertState.grace}": ["${AlertState.grace}"], - "Alerts & reports": ["Opozorila in poročila"], - "Reports": ["Poročila"], - "Delete %s?": ["Izbrišem %s?"], - "Please confirm": ["Prosim, potrdite"], - "Are you sure you want to delete the selected %s?": [ - "Ali ste prepričani, da želite izbrisati izbrane %s?" + "Your query could not be scheduled": [ + "Vaše poizvedbe ni mogoče uvrstiti v urnik" ], - "< (Smaller than)": ["< (manjše kot)"], - "> (Larger than)": ["> (večje kot)"], - "<= (Smaller or equal)": ["<= (manjše ali enako)"], - ">= (Larger or equal)": [">= (večje ali enako)"], - "== (Is equal)": ["== (je enako)"], - "!= (Is not equal)": ["!= (ni enako)"], - "Not null": ["Ni nič (null)"], - "30 days": ["30 dni"], - "60 days": ["60 dni"], - "90 days": ["90 dni"], - "Add notification method": ["Dodajte način obveščanja"], - "Add delivery method": ["Dodajte način dostave"], - "Edit ${isReport ? 'Report' : 'Alert'}": [ - "Uredi ${isReport ? 'Report' : 'Alert'}" + "Failed at retrieving results": ["Napaka pri pridobivanju rezultatov"], + "An error occurred while storing the latest query id in the backend. Please contact your administrator if this problem persists.": [ + "Pri shranjevanju zadnjega id-ja poizvedbe v sistem je prišlo do napake. Če se težava ponavlja, kontaktirajte administratorja." ], - "Add ${isReport ? 'Report' : 'Alert'}": [ - "Add ${isReport ? 'Report' : 'Alert'}" + "Unknown error": ["Neznana napaka"], + "Query was stopped.": ["Poizvedba je bila ustavljena."], + "Failed at stopping query. %s": ["Neuspešno ustavljanje poizvedbe. %s"], + "Unable to migrate table schema state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ + "Stanja sheme tabele ni mogoče prenesti v sistem. Superset bo ponovil poskus kasneje. Če se težava ponavlja, kontaktirajte administratorja." ], - "Report name": ["Naslov poročila"], - "Alert name": ["Naslov opozorila"], - "Alert condition": ["Status opozorila"], - "Trigger Alert If...": ["Sproži opozorilo v primeru ..."], - "Condition": ["Pogoj"], - "Report schedule": ["Urnik poročanja"], - "Alert condition schedule": ["Urnik statusov opozoril"], - "Schedule settings": ["Nastavitve urnika"], - "Log retention": ["Hranjenje dnevnikov"], - "Working timeout": ["Pretek delovanja"], - "Time in seconds": ["Čas v sekundah"], - "Grace period": ["Obdobje mirovanja"], - "Message content": ["Vsebina sporočila"], - "Send as PNG": ["Pošlji kot PNG"], - "Send as CSV": ["Pošlji kot CSV"], - "Send as text": ["Pošlji kot besedilo"], - "log": ["dnevnik"], - "State": ["Status"], - "Execution ID": ["ID izvedbe"], - "Scheduled at (UTC)": ["Izvede se ob (UTC)"], - "Start at (UTC)": ["Zažene se ob (UTC)"], - "Duration": ["Trajanje"], - "Error message": ["Sporočilo napake"], - "${alertResource?.type}": ["${alertResource?.type}"], - "CRON expression": ["Izraz CRON"], - "Report sent": ["Poročilo poslano"], - "Alert triggered, notification sent": [ - "Opozorilo sproženo, obvestilo poslano" + "Unable to migrate query state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ + "Stanja poizvedbe ni mogoče prenesti v sistem. Superset bo ponovil poskus kasneje. Če se težava ponavlja, kontaktirajte administratorja." ], - "Report sending": ["Pošiljanje poročila"], - "Alert running": ["Opozorilo aktivno"], - "Report failed": ["Poročilo ni uspelo"], - "Alert failed": ["Opozorilo ni uspelo"], - "Nothing triggered": ["Ni ni sproženo"], - "Alert Triggered, In Grace Period": [ - "Opozorilo sproženo, v obdobju mirovanja" + "Unable to migrate query editor state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ + "Stanja urejevalnika poizvedb ni mogoče prenesti v sistem. Superset bo ponovil poskus kasneje. Če se težava ponavlja, kontaktirajte administratorja." ], - "Delivery method": ["Način dostave"], - "Select Delivery Method": ["Izberite način dostave"], - "Recipients are separated by \",\" or \";\"": [ - "Prejemniki so ločeni z \",\" ali \";\"" + "Unable to add a new tab to the backend. Please contact your administrator.": [ + "Novega zavihka ni mogoče dodati v sistem. Kontaktirajte administratorja." ], - "${RecipientIconName.email}": ["${RecipientIconName.email}"], - "${RecipientIconName.slack}": ["${RecipientIconName.slack}"], - "annotation": ["oznaka"], - "There was an issue deleting the selected annotations: %s": [ - "Pri brisanju izbranih oznak je prišlo do težave: %s" + "Copy of %s": ["Kopija %s"], + "An error occurred while setting the active tab. Please contact your administrator.": [ + "Pri določanju aktivnega zavihka je prišlo do napake. Kontaktirajte administratorja." ], - "Edit annotation": ["Uredi oznako"], - "Delete annotation": ["Izbriši oznako"], - "Annotation": ["Oznaka"], - "No annotation yet": ["Oznak še ni"], - "Annotation Layer ${annotationLayerName}": [ - "Sloj z oznakami ${annotationLayerName}" + "An error occurred while fetching tab state": [ + "Pri pridobivanju stanja zavihka je prišlo do napake" ], - "Are you sure you want to delete ${annotationCurrentlyDeleting?.short_descr}?": [ - "Ste prepričani, da želite izbrisati ${annotationCurrentlyDeleting?.short_descr}?" + "An error occurred while hiding the left bar. Please contact your administrator.": [ + "Pri skrivanju leve vrstice je prišlo do napake. Kontaktirajte administratorja." ], - "Delete Annotation?": ["Izbrišem oznako?"], - "Are you sure you want to delete the selected annotations?": [ - "Ali ste prepričani, da želite izbrisati izbrane oznake?" + "An error occurred while removing tab. Please contact your administrator.": [ + "Pri odstranjevanju zavihka je prišlo do napake. Kontaktirajte administratorja." ], - "The annotation has been updated": ["Označba je bila posodobljena"], - "The annotation has been saved": ["Označba je bila shranjena"], - "Add annotation": ["Dodaj oznako"], - "Annotation name": ["Ime oznake"], - "date": ["datum"], - "Additional information": ["Dodatne informacije"], - "Description (this can be seen in the list)": [ - "Opis (lahko je viden na seznamu)" + "An error occurred while removing query. Please contact your administrator.": [ + "Pri odstranjevanju poizvedbe je prišlo do napake. Kontaktirajte administratorja." ], - "annotation_layer": ["annotation_layer"], - "Edit annotation layer properties": ["Uredi lastnosti sloja z oznakami"], - "Annotation layer name": ["Ime sloja z oznakami"], - "Annotation layers": ["Sloji z oznakami"], - "There was an issue deleting the selected layers: %s": [ - "Pri brisanju izbranih slojev je prišlo do težave: %s" + "An error occurred while setting the tab database ID. Please contact your administrator.": [ + "Pri določanju ID-ja v podatkovne baze za zavihek je prišlo do napake. Kontaktirajte administratorja." ], - "Last modified": ["Zadnja sprememba"], - "Created on": ["Ustvarjeno"], - "Edit template": ["Uredi predlogo"], - "Delete template": ["Izbriši predlogo"], - "Annotation layer": ["Sloj z oznakami"], - "An error occurred while fetching dataset datasource values: %s": [ - "Pri pridobivanju vrednosti podatkovnega vira podatkovnega seta je prišlo do napake: %s" + "An error occurred while setting the tab schema. Please contact your administrator.": [ + "Pri določanju sheme zavihka je prišlo do napake. Kontaktirajte administratorja." ], - "No annotation layers yet": ["Slojev z oznakami še ni"], - "This action will permanently delete the layer.": [ - "S tem dejanjem boste trajno izbrisali sloj." + "An error occurred while setting the tab autorun. Please contact your administrator.": [ + "Pri določanju samodejnega zagona zavihka je prišlo do napake. Kontaktirajte administratorja." ], - "Delete Layer?": ["Izbrišem sloj?"], - "Are you sure you want to delete the selected layers?": [ - "Ali ste prepričani, da želite izbrisati izbrane sloje?" + "An error occurred while setting the tab title. Please contact your administrator.": [ + "Pri določanju naslova zavihka je prišlo do napake. Kontaktirajte administratorja." ], - "Are you sure you want to delete": [ - "Ali ste prepričani, da želite izbrisati" + "Your query could not be saved": ["Vaše poizvedbe ni mogoče shraniti"], + "Your query was not properly saved": [ + "Vaša poizvedba ni bila pravilno shranjena" ], - "Modified %s": ["Zadnja sprememba %s"], - "The passwords for the databases below are needed in order to import them together with the charts. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj z grafikoni. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." + "Your query was saved": ["Vaša poizvedba je shranjena"], + "Your query was updated": ["Vaša poizvedba je posodobljena"], + "Your query could not be updated": [ + "Vaše poizvedbe ni mogoče posodobiti" ], - "You are importing one or more charts that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "Uvažate enega ali več grafikonov, ki že obstajajo. S prepisom lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" + "An error occurred while storing your query in the backend. To avoid losing your changes, please save your query using the \"Save Query\" button.": [ + "Pri shranjevanju vaše poizvedbe v sistem je prišlo do napake. Da ne izgubite sprememb, shranite poizvedbo z gumbom \"Shrani poizvedbo\"." ], - "There was an issue deleting the selected charts: %s": [ - "Pri brisanju izbranih grafikonov je prišlo do težave: %s" + "An error occurred while setting the tab template parameters. Please contact your administrator.": [ + "Pri določanju parametrov predloge zavihka je prišlo do napake. Kontaktirajte administratorja." ], - "Modified by": ["Spremenil"], - "Favorite": ["Priljubljene"], - "Any": ["Katerikoli"], - "Yes": ["Da"], - "No": ["Ne"], - "Owner": ["Lastnik"], - "All": ["Vsi"], - "An error occurred while fetching chart owners values: %s": [ - "Pri pridobivanju polja lastnik grafikona je prišlo do napake: %s" + "An error occurred while fetching table metadata": [ + "Pri pridobivanju metapodatkov tabele je prišlo do napake" ], - "An error occurred while fetching chart created by values: %s": [ - "Pri pridobivanju polja Grafikon ustvaril je prišlo do napake: %s" + "An error occurred while fetching table metadata. Please contact your administrator.": [ + "Pri pridobivanju metapodatkov tabele je prišlo do napake. Kontaktirajte administratorja." ], - "Viz type": ["Tip vizualizacije"], - "Alphabetical": ["Po abecedi"], - "Recently modified": ["Nedavno spremenjeno"], - "Least recently modified": ["Zadnje spremenjeno"], - "Import charts": ["Uvozi grafikone"], - "Are you sure you want to delete the selected charts?": [ - "Ali ste prepričani, da želite izbrisati izbrane grafikone?" + "An error occurred while expanding the table schema. Please contact your administrator.": [ + "Pri širitvi sheme tabele je prišlo do napake. Kontaktirajte administratorja." ], - "css_template": ["css_template"], - "Edit CSS template properties": ["Uredi lastnosti CSS predloge"], - "Add CSS template": ["Dodaj CSS predlogo"], - "CSS template name": ["Ime CSS predloge"], - "css": ["css"], - "CSS templates": ["CSS predloge"], - "There was an issue deleting the selected templates: %s": [ - "Pri brisanju izbranih predlog je prišlo do težave: %s" + "An error occurred while collapsing the table schema. Please contact your administrator.": [ + "Pri krčenju sheme tabele je prišlo do napake. Kontaktirajte administratorja." ], - "Last modified by %s": ["Nazadnje spremenil %s"], - "CSS template": ["CSS predloga"], - "This action will permanently delete the template.": [ - "S tem dejanjem boste trajno izbrisali predlogo." + "An error occurred while removing the table schema. Please contact your administrator.": [ + "Pri odstranjevanju sheme tabele je prišlo do napake. Kontaktirajte administratorja." ], - "Delete Template?": ["Izbrišem predlogo?"], - "Are you sure you want to delete the selected templates?": [ - "Ali ste prepričani, da želite izbrisati izbrane predloge?" + "Shared query": ["Deljene poizvedbe"], + "The datasource couldn't be loaded": [ + "Podatkovnega vira ni mogoče naložiti" ], - "published": ["objavljeno"], - "draft": ["osnutek"], - "The passwords for the databases below are needed in order to import them together with the dashboards. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj z nadzornimi ploščami. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." + "An error occurred while creating the data source": [ + "Pri ustvarjanju podatkovnega vira je prišlo do težave" ], - "You are importing one or more dashboards that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "Uvažate eno ali več nadzornih plošč, ki že obstajajo. S prepisom lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" + "An error occurred while fetching function names.": [ + "Pri pridobivanju imen funkcij je prišlo do napake." ], - "An error occurred while fetching dashboards: %s": [ - "Prišlo je do napake pri pridobivanju nadzornih plošč: %s" + "SQL Lab uses your browser's local storage to store queries and results.\nCurrently, you are using %(currentUsage)s KB out of %(maxStorage)d KB storage space.\nTo keep SQL Lab from crashing, please delete some query tabs.\nYou can re-access these queries by using the Save feature before you delete the tab.\nNote that you will need to close other SQL Lab windows before you do this.": [ + "SQL laboratorij uporablja lokalno shrambo brskalnika za shranjevanje poizvedb in rezultatov.\nTrenutno uporabljate %(currentUsage)s KB od %(maxStorage)d KB prostora.\nDa preprečite sesutje SQL laba, izbrišite nekaj zavihkov s poizvedbami.\nPoizvedbe lahko ponovno pridobite, če pred brisanjem uporabite funkcijo Shrani.\nPred tem morate zapreti druga okna SQL laboratorija." ], - "There was an issue deleting the selected dashboards: ": [ - "Pri brisanju izbranih nadzornih plošč je prišlo do težave: " + "Estimate selected query cost": ["Oceni potratnost izbrane poizvedbe"], + "Estimate cost": ["Oceni potratnost"], + "Cost estimate": ["Ocena potratnosti"], + "Creating a data source and creating a new tab": [ + "Ustvarjanje podatkovnega vira in novega zavihka" ], - "An error occurred while fetching dashboard owner values: %s": [ - "Pri pridobivanju polja lastnik nadzorne plošče je prišlo do napake: %s" + "An error occurred": ["Prišlo je do napake"], + "Explore the result set in the data exploration view": [ + "Raziščite rezultate v pogledu raziskovanja podatkov" ], - "An error occurred while fetching dashboard created by values: %s": [ - "Pri pridobivanju polja Nadzorno ploščo ustvaril je prišlo do napake: %s" + "Create Chart": ["Ustvarite grafikon"], + "Source SQL": ["Izvorni SQL"], + "Executed SQL": ["Izvedena poizvedba"], + "SQL": ["SQL"], + "Run a query to display query history": [ + "Za prikaz zgodovine poizvedb zaženite poizvedbo" ], - "Are you sure you want to delete the selected dashboards?": [ - "Ali ste prepričani, da želite izbrisati izbrane nadzorne plošče?" + "An error occurred when refreshing queries": [ + "Pri osveževanju poizvedb je prišlo do napake" ], - "Saved queries": ["Shranjene poizvedbe"], - "SQL Copied!": ["SQL kopiran!"], - "The passwords for the databases below are needed in order to import them. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "Gesla za spodnje podatkovne baze so potrebna za njihov uvoz. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." + "It seems you don't have access to any database": [ + "Zdi se, da nimate dostopa do nobene podatkovne baz" ], - "You are importing one or more databases that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "Uvažate eno ali več podatkovnih baz, ki že obstajajo. S prepisom lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" + "Filter by user": ["Filtriraj po uporabniku"], + "Filter by database": ["Filtriraj po podatkovni bazi"], + "Query search string": ["Iskalni niz za poizvedbo"], + "[From]-": ["[Od]-"], + "[To]-": ["[Do]-"], + "Filter by status": ["Filtriraj po statusu"], + "Success": ["Uspelo"], + "Failed": ["Ni uspelo"], + "Running": ["V teku"], + "Fetching": ["Pridobivam"], + "Offline": ["Offline"], + "Scheduled": ["V urniku"], + "Unknown Status": ["Neznan status"], + "Edit": ["Urejanje"], + "View": ["Pogled"], + "Data preview": ["Ogled podatkov"], + "Overwrite text in the editor with a query on this table": [ + "Besedilo v urejevalniku prepišite s poizvedbo na to tabelo" ], - "database": ["podatkovna baza"], - "An error occurred while fetching database related data: %s": [ - "Pri pridobivanju podatkov iz podatkovne baze je prišlo do napake: %s" + "Run query in a new tab": ["Zaženi poizvedbo v novem zavihku"], + "Remove query from log": ["Odstrani poizvedbo iz dnevnika"], + "Save & Explore": ["Shrani & Razišči"], + "Overwrite & Explore": ["Prepiši & Razišči"], + "Save this query as a virtual dataset to continue exploring": [ + "Shranite poizvedbo kot virtualni podatkovni set" ], - "Import databases": ["Uvozi podatkovne baze"], - "Asynchronous query execution": ["Asinhroni zagon poizvedb"], - "AQE": ["AQE"], - "Allow data manipulation language": [ - "Dovoli jezik za manipulacijo podatkov (DML)" + "Download to CSV": ["Izvozi kot CSV"], + "Copy to Clipboard": ["Kopiraj na odložišče"], + "Too many columns to filter": ["Preveč stolpcev za filtriranje"], + "Filter results": ["Filtriraj rezultate"], + "The number of results displayed is limited to %(rows)d by the configuration DISPLAY_MAX_ROWS. Please add additional limits/filters or download to csv to see more rows up to the %(limit)d limit.": [ + "Število prikazanih rezultatov je omejeno na %(rows)d na podlagi parametra DISPLAY_MAX_ROWS. V csv dodajte dodatne omejitve/filtre, da boste lahko videli več vrstic do meje %(limit)d ." ], - "DML": ["DML"], - "CSV upload": ["Nalaganje CSV"], - "Delete database": ["Izbriši podatkovno bazo"], - "The database %s is linked to %s charts that appear on %s dashboards and users have %s SQL Lab tabs using this database open. Are you sure you want to continue? Deleting the database will break those objects.": [ - "Podatkovna baza %s je povezana z grafikoni %s, ki so prisotni na nadzorni plošči %s in uporabniki imajo odprtih %s zavihkov SQL laboratorija. Ali želite nadaljevati? Izbris podatkovne baze bo pokvaril te objekte." + "The number of results displayed is limited to %(rows)d. Please add additional limits/filters, download to csv, or contact an admin to see more rows up to the %(limit)d limit.": [ + "Število prikazanih rezultatov je omejeno na %(rows)d . V csv dodajte dodatne omejitve/filtre, da boste lahko videli več vrstic do meje %(limit)d ." ], - "Delete Database?": ["Izbrišem podatkovno bazo?"], - "Expose database in SQL Lab": [ - "Razkrij podatkovno bazo v SQL laboratoriju" + "The number of rows displayed is limited to %(rows)d by the query": [ + "Število prikazanih vrstic je omejeno na %(rows)d s poizvedbo" ], - "Allow this database to be queried in SQL Lab": [ - "Dovoli poizvedbo na to podatkovno bazo v SQL laboratoriju" + "The number of rows displayed is limited to %(rows)d by the limit dropdown.": [ + "Število prikazanih rezultatov je omejeno na %(rows)d s poizvedbo." ], - "Allow creation of new tables based on queries": [ - "Dovoli ustvarjanje novih tabel s poizvedbami" + "The number of rows displayed is limited to %(rows)d by the query and limit dropdown.": [ + "Število prikazanih vrstic je omejeno na %(rows)d s poizvedbo in spustnim izbirnikom omejitev." ], - "Allow creation of new views based on queries": [ - "Dovoli ustvarjanje novih pogledov s poizvedbami" + "%(rows)d rows returned": ["%(rows)d vrnjenih vrstic"], + "The number of rows displayed is limited to %s by the dropdown.": [ + "Število prikazanih vrstic je omejeno na %s s spustnim izbirnikom." ], - "CTAS & CVAS SCHEMA": ["CTAS & CVAS SHEMA"], - "Create or select schema...": ["Ustvarite ali izberite shemo..."], - "Force all tables and views to be created in this schema when clicking CTAS or CVAS in SQL Lab.": [ - "Vsilite, da bodo vse tabele in pogledi ustvarjeni s to shemo, ko kliknete CTAS ali CVAS v SQL laboratoriju." + "Query was stopped": ["Poizvedba je bila ustavljena"], + "Database error": ["Napaka podatkovne baze"], + "was created": ["ustvarjeno"], + "Query in a new tab": ["Poizvedba v novem zavihku"], + "The query returned no data": ["Poizvedba ni vrnila podatkov"], + "Fetch data preview": ["Pridobi predogled podatkov"], + "Refetch results": ["Ponovno pridobi rezultate"], + "Track job": ["Sledi opravilom"], + "Stop": ["Ustavi"], + "Run selection": ["Zaženi izbrano"], + "Run": ["Zaženi"], + "Stop running (Ctrl + x)": ["Ustavi (Ctrl + x)"], + "Stop running (Ctrl + e)": ["Ustavi (Ctrl + e)"], + "Run query (Ctrl + Return)": ["Zaženi poizvedbo (Ctrl + Return)"], + "An error occurred saving dataset": [ + "Pri shranjevanju podatkovnega seta je prišlo do napake" ], - "Allow manipulation of the database using non-SELECT statements such as UPDATE, DELETE, CREATE, etc.": [ - "Dovoli manipulacije podatkovne baze z uporabo ne-SELECT stavkov, kot so UPDATE, DELETE, CREATE, itd." + "Save or Overwrite Dataset": ["Shrani ali prepiši podatkovni set"], + "Save as new": ["Shrani kot novo"], + "Overwrite existing": ["Prepiši obstoječe"], + "Select or type dataset name": [ + "Izberite ali vnesite naziv podatkovnega seta" ], - "Enable query cost estimation": [ - "Omogoči ocenjevanje potratnosti poizvedbe" + "Are you sure you want to overwrite this dataset?": [ + "Ali ste prepričani, da želite prepisati podatkovni set?" ], - "For Presto and Postgres, shows a button to compute cost before running a query.": [ + "For Bigquery, Presto and Postgres, shows a button to compute cost before running a query.": [ "Za Presto in Postgres prikaže gumb za izračun potratnosti pred zagonom poizvedbe." ], - "Allow this database to be explored": [ - "Dovoli raziskovanje te podatkovne baze" + "Please save the query to enable sharing": [ + "Shranite poizvedbo za deljenje" ], - "When enabled, users are able to visualize SQL Lab results in Explore.": [ - "Ko je omogočeno, lahko uporabniki prikazujejo rezultate SQL laboratorija v raziskovalcu." + "Copy query link to your clipboard": [ + "Kopiraj povezavo do poizvedbe v odložišče" ], - "Chart cache timeout": ["Trajanje predpomnilnika grafikona"], - "Enter duration in seconds": ["Vnesite trajanje v sekundah"], - "Schema cache timeout": ["Trajanje prepomnilnika sheme"], - "Duration (in seconds) of the metadata caching timeout for schemas of this database. If left unset, the cache never expires.": [ - "Trajanje (v sekundah) predpomnilnika metapodatkov za sheme v tej podatkovni bazi. Če ni nastavljeno, predpomnilnik ne poteče." + "Save the query to enable this feature": [ + "Za omogočenje te funkcije shranite poizvedbo" ], - "Table cache timeout": ["Trajanje predpomnilnika tabele"], - "Duration (in seconds) of the metadata caching timeout for tables of this database. If left unset, the cache never expires. ": [ - "Trajanje (v sekundah) predpomnilnika metapodatkov za tabele v tej podatkovni bazi. Če ni nastavljeno, predpomnilnik ne poteče. " + "Copy link": ["Kopiraj povezavo"], + "No stored results found, you need to re-run your query": [ + "Rezultatov še ni shranjenih, ponovno morate zagnati poizvedbo" ], - "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.": [ - "Upravljanje podatkovne baze v asinhronem načinu pomeni, da se poizvedbe zaženejo na oddaljenih »delavcih« in ne na samem spletnem strežniku. S tem je predpostavljeno, da imate nastavljenega »delavca« za Celery in zaledni sistem za rezultate. Več informacij je v navodilih za namestitev." + "Run a query to display results": [ + "Za prikaz rezultatov morate zagnati poizvedbo" ], - "Cancel query on window unload event": [ - "Prekini poizvedbo pri dogodku zaprtja okna (window unload event)" + "Preview: `%s`": ["Predogled: `%s`"], + "Results": ["Rezultati"], + "Query history": ["Zgodovina poizvedb"], + "Run query": ["Zaženi poizvedbo"], + "New tab": ["Nov zavihek"], + "Stop query": ["Ustavi poizvedbo"], + "Previous Line": ["Prejšnja linija"], + "Schedule the query periodically": ["Periodično zaganjaj poizvedbo"], + "You must run the query successfully first": [ + "Najprej morate uspešno izvesti poizvedbo" ], - "Terminate running queries when browser window closed or navigated to another page. Available for Presto, Hive, MySQL, Postgres and Snowflake databases.": [ - "Ustavi zagnane poizvedbe, ko se zapre okno brskalnika ali gre na drugo stran. na razpolago za Presto, Hive, MySQL, Postgres in Snowflake podatkovne baze." + "Autocomplete": ["Samodokončaj"], + "CREATE TABLE AS": ["CREATE TABLE AS"], + "CREATE VIEW AS": ["CREATE VIEW AS"], + "Estimate the cost before running a query": [ + "Oceni potratnost pred zagonom poizvedbe" ], - "Secure extra": ["Dodatna varnost"], - "JSON string containing additional connection configuration. This is used to provide connection information for systems like Hive, Presto and BigQuery which do not conform to the username:password syntax normally used by SQLAlchemy.": [ - "JSON niz, ki vsebuje dodatno konfiguracijo povezave. Uporablja se za zagotavljanje dodatnih informacij povezave za sisteme kot sta Presto in BigQuery, ki nista skladna s sintakso username:password, ki jo običajno uporablja SQLAlchemy." + "Select a database to write a query": [ + "Izberite podatkovno bazo za poizvedbo" + ], + "Choose one of the available databases from the panel on the left.": [ + "Izberite eno od razpoložljivih podatkovnih baz v panelu na levi." + ], + "Collapse table preview": ["Zapri predogled tabele"], + "Expand table preview": ["Odpri predogled tabele"], + "No databases match your search": [ + "Nobena podatkovna baza ne ustreza iskanju" + ], + "There are no databases available": ["Podatkovnih baz ni na voljo"], + "Manage your databases": ["Upravljajte podatkovne baze"], + "here": ["tukaj"], + "Reset state": ["Ponastavi stanje"], + "Enter a new title for the tab": ["Vnesite novo naslov zavihka"], + "-- Note: Unless you save your query, these tabs will NOT persist if you clear your cookies or change browsers.\n\n": [ + "-- Opomba: Če ne shranite poizvedbe, se ti zavihki NE bodo ohranili, ko boste počistili piškote ali zamenjali brskalnik.\n\n" + ], + "Close tab": ["Zapri zavihek"], + "Rename tab": ["Preimenuj zavihek"], + "Expand tool bar": ["Razširi orodno vrstico"], + "Hide tool bar": ["Skrij orodno vrstico"], + "Close all other tabs": ["Zapri vse ostale zavihke"], + "Duplicate tab": ["Podvoji zavihek"], + "Add a new tab": ["Dodaj nov zavihek"], + "New tab (Ctrl + q)": ["Nov zavihek (Ctrl + q)"], + "New tab (Ctrl + t)": ["Nov zavihek (Ctrl + t)"], + "Add a new tab to create SQL Query": [ + "Dodaj nov zavihek za SQL-poizvedbo" ], - "Enter CA_BUNDLE": ["Vnesite CA_BUNDLE"], - "Optional CA_BUNDLE contents to validate HTTPS requests. Only available on certain database engines.": [ - "Opcijska CA_BUNDLE vsebina, za potrjevanje HTTPS zahtev. Razpoložljivo le na določenih sistemih podatkovnih baz." + "Copy partition query to clipboard": [ + "Kopiraj particijsko poizvedbo na odložišče" ], - "Schemas allowed for CSV upload": ["Dovoljene sheme za nalaganje CSV"], - "A comma-separated list of schemas that CSVs are allowed to upload to.": [ - "Z vejicami ločen seznam shem, kjer je dovoljeno nalaganje CSV-jev." + "latest partition:": ["zadnja particija:"], + "Keys for table": ["Ključi za tabele"], + "View keys & indexes (%s)": ["Ogled ključev in indeksov (%s)"], + "Original table column order": ["Vrstni red stolpcev izvorne tabele"], + "Sort columns alphabetically": ["Razvrsti stolpce po abecedi"], + "Copy SELECT statement to the clipboard": [ + "Kopiraj stavek SELECT na odložišče" ], - "Impersonate logged in user (Presto, Trino, Drill, Hive, and GSheets)": [ - "Predstavljanje kot prijavljeni uporabnik (Presto, Trino, Drill, Hive in GSheets)" + "Show CREATE VIEW statement": ["Prikaži CREATE VIEW stavek"], + "CREATE VIEW statement": ["CREATE VIEW stavek"], + "Remove table preview": ["Odstrani predogled tabele"], + "Edit template parameters": ["Uredi parametre predloge"], + "Parameters ": ["Parametri "], + "Invalid JSON": ["Neveljaven JSON"], + "Untitled query": ["Neimenovana poizvedba"], + "%s%s": ["%s%s"], + "Create a new chart": ["Ustvari nov grafikon"], + "Choose a dataset": ["Izberite podatkovni set"], + "Dataset": ["Podatkovni set"], + "Instructions to add a dataset are available in the Superset tutorial.": [ + "Navodila za dodajanje podatkovnega seta so v vodiču za Superset." ], - "If Presto or Trino, all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them. If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.": [ - "V primeru Presto ali Trino se vse poizvedbe v SQL laboratoriju zaženejo pod trenutno prijavljenim uporabnikom, ki mora imeti pravice za poganjanje. Če je omogočen Hive in hive.server2.enable.doAs, poizvedbe tečejo pod servisnim računom, vendar je trenutno prijavljen uporabnik predstavljen z lastnostjo hive.server2.proxy.user." + "Choose chart type": ["Izberite tip grafikona"], + "Please select both a Dataset and a Chart type to proceed": [ + "Za nadaljevanje izberite podatkovni set in tip grafikona" ], - "Allow data upload": ["Dovoli nalaganje podatkov"], - "If selected, please set the schemas allowed for data upload in Extra.": [ - "Če je izbrano, nastavite dovoljene sheme za nalaganje podatkov v Dodatno." + "Create new chart": ["Ustvari nov grafikon"], + "Click to see difference": ["Kliknite za prikaz razlike"], + "Altered": ["Spremenjeno"], + "Chart changes": ["Spremembe grafikona"], + "Select ...": ["Izberite ..."], + "Loaded data cached": ["Podatki so naloženi v predpomnilnik"], + "Loaded from cache": ["Naloženo iz predpomnilnika"], + "Click to force-refresh": ["Kliknite za prisilno osvežitev"], + "Cached": ["Predpomnjeno"], + "Add required control values to preview chart": [ + "Dodaj potrebne parametre za predogled grafikona" ], - "Metadata Parameters": ["Parametri metapodatkov"], - "The metadata_params object gets unpacked into the sqlalchemy.MetaData call.": [ - "Objekt metadata_params se razpakira v klic sqlalchemy.MetaData." + "Your chart is ready to go!": ["Grafikon je pripravljen!"], + "Click on \"Create chart\" button in the control panel on the left to preview a visualization or": [ + "Kliknite na gumb \"Ustvari grafikon\" v kontrolni plošči na levi za predogled ali" ], - "Engine Parameters": ["Parametri podatkovne baze"], - "The engine_params object gets unpacked into the sqlalchemy.create_engine call.": [ - "Objekt engine_params se razširi v klic sqlalchemy.create_engine." + "click here": ["kliknite tukaj"], + "No results were returned for this query": [ + "Poizvedba ni vrnila rezultatov" ], - "Version": ["Verzija"], - "Version number": ["Številka verzije"], - "Specify the database version. This should be used with Presto in order to enable query cost estimation.": [ - "Podajte verzijo podatkovne baze. Uporablja se s Presto, za potrebe ocenjevanja potratnosti poizvedbe." + "Make sure that the controls are configured properly and the datasource contains data for the selected time range": [ + "Poskrbite, da so kontrolniki pravilno nastavljeni in podatkovni vir vsebuje podatke za izbrano časovno obdobje" ], - "Display Name": ["Ime za prikaz"], - "Name your database": ["Poimenujte podatkovno bazo"], - "Pick a name to help you identify this database.": [ - "Izberite ime za lažjo prepoznavo podatkovne baze." + "An error occurred while loading the SQL": [ + "Pri nalaganju SQL je prišlo do napake" ], - "dialect+driver://username:password@host:port/database": [ - "dialect+driver://username:password@host:port/database" + "Sorry, an error occurred": ["Prišlo je do napake"], + "Updating chart was stopped": [ + "Posodabljanje grafikona je bilo ustavljeno" ], - "Refer to the": ["Obrnite se na"], - "for more information on how to structure your URI.": [ - "za več informacij o oblikovanju URI." + "An error occurred while rendering the visualization: %s": [ + "Pri prikazovanju vizualizacije je prišlo do napake: %s" ], - "Test connection": ["Preizkus povezave"], - "Please enter a SQLAlchemy URI to test": [ - "Vnesite SQLAlchemy URI za test" + "Network error.": ["Napaka omrežja."], + "Copy to clipboard": ["Kopiraj na odložišče"], + "Copied to clipboard!": ["Kopirano na odložišče!"], + "Sorry, your browser does not support copying. Use Ctrl / Cmd + C!": [ + "Vaš brskalnik ne podpira kopiranja. Uporabite Ctrl / Cmd + C!" ], - "Sorry there was an error fetching database information: %s": [ - "Pri pridobivanju informacij o podatkovni bazi je prišlo do napake: %s" + "every": ["vsak"], + "every month": ["vsak mesec"], + "every day of the month": ["vsak dan v mesecu"], + "day of the month": ["dan v mesecu"], + "every day of the week": ["vsak dan v tednu"], + "day of the week": ["dan v tednu"], + "every hour": ["vsako uro"], + "every minute": ["vsako minuto"], + "year": ["leto"], + "month": ["mesec"], + "week": ["teden"], + "day": ["dan"], + "hour": ["ura"], + "minute": ["minuta"], + "reboot": ["ponovni zagon"], + "Every": ["Vsak"], + "in": ["v"], + "on": ["v"], + "and": ["in"], + "at": ["ob"], + ":": [":"], + "minute(s)": ["minuta/e"], + "Invalid cron expression": ["Neveljaven cron izraz"], + "Clear": ["Počisti"], + "Sunday": ["Nedelja"], + "Monday": ["Ponedeljek"], + "Tuesday": ["Torek"], + "Wednesday": ["Sreda"], + "Thursday": ["Četrtek"], + "Friday": ["Petek"], + "Saturday": ["Sobota"], + "January": ["Januar"], + "February": ["Februar"], + "March": ["Marec"], + "April": ["April"], + "May": ["Maj"], + "June": ["Junij"], + "July": ["Julij"], + "August": ["Avgust"], + "September": ["September"], + "October": ["Oktober"], + "November": ["November"], + "December": ["December"], + "SUN": ["NED"], + "MON": ["PON"], + "TUE": ["TOR"], + "WED": ["SRE"], + "THU": ["ČET"], + "FRI": ["PET"], + "SAT": ["SOB"], + "JAN": ["JAN"], + "FEB": ["FEB"], + "MAR": ["MAR"], + "APR": ["APR"], + "MAY": ["MAJ"], + "JUN": ["JUN"], + "JUL": ["JUL"], + "AUG": ["AVG"], + "SEP": ["SEP"], + "OCT": ["OKT"], + "NOV": ["NOV"], + "DEC": ["DEC"], + "There was an error loading the schemas": ["Napaka pri nalaganju shem"], + "Select database or type database name": [ + "Izberite ali vnesite ime podatkovne baze" ], - "Want to add a new database?": ["Želite dodati novo podatkovno bazo?"], - "Connect": ["Poveži"], - "Edit database": ["Uredi podatkovno bazo"], - "Connect a database": ["Poveži se s podatkovno bazo"], - "Click this link to switch to an alternate form that exposes only the required fields needed to connect this database.": [ - "Kliknite to povezavo za drugo vnosno formo, ki prikaže samo zahtevana polja za povezavo s podatkovno bazo." + "Force refresh schema list": ["Osveži seznam shem"], + "Select schema or type schema name": ["Izberite ali vnesite ime sheme"], + "Warning! Changing the dataset may break the chart if the metadata does not exist.": [ + "Opozorilo! Sprememba podatkovnega seta lahko pokvari grafikon, če metapodatki ne obstajajo." ], - "Finish": ["Končaj"], - "Click this link to switch to an alternate form that allows you to input the SQLAlchemy URL for this database manually.": [ - "Kliknite to povezavo za drugo vnosno formo, ki omogoča ročni vnos SQLAlchemy URL-ja za to podatkovno bazo." + "Changing the dataset may break the chart if the chart relies on columns or metadata that does not exist in the target dataset": [ + "Sprememba podatkovnega seta lahko pokvari grafikon, če se le-ta zanaša na stolpce ali metapodatke, ki ne obstajajo v ciljnem podatkovnem nizu" ], - "This can be either an IP address (e.g. 127.0.0.1) or a domain name (e.g. mydatabase.com).": [ - "To je lahko bodisi IP naslov (npr. 127.0.0.1) bodisi ime domene (npr. mydatabase.com)." + "dataset": ["podatkovni set"], + "Connection": ["Povezava"], + "Change dataset": ["Spremeni podatkovni set"], + "Warning!": ["Opozorilo!"], + "Search / Filter": ["Iskanje / Filter"], + "Add item": ["Dodaj"], + "Physical (table or view)": ["Fizičen (tabela ali pogled)"], + "Virtual (SQL)": ["Virtualen (SQL)"], + "Data type": ["Tip podatka"], + "Advanced data type": ["Napredni podatkovni tip"], + "Advanced Data type": ["Napredni podatkovni tip"], + "Datetime format": ["Oblika datum-časa"], + "The pattern of timestamp format. For strings use ": [ + "Vzorec zapisa časovne značke. Za znakovne nize uporabite " ], - "Copy the name of the database you are trying to connect to.": [ - "Kopirajte ime podatkovne baze, s katero se skušate povezati." + "Python datetime string pattern": ["Pythonov vzorec zapisa datum-časa"], + " expression which needs to adhere to the ": [" , ki mora upoštevati "], + "ISO 8601": ["ISO 8601"], + " standard to ensure that the lexicographical ordering\n coincides with the chronological ordering. If the\n timestamp format does not adhere to the ISO 8601 standard\n you will need to define an expression and type for\n transforming the string into a date or timestamp. Note\n currently time zones are not supported. If time is stored\n in epoch format, put `epoch_s` or `epoch_ms`. If no pattern\n is specified we fall back to using the optional defaults on a per\n database/column name level via the extra parameter.": [ + " standard, ki zagotavlja, de se leksikografsko razvrščanje\n sklada s kronološkim razvrščanjem. Če oblika\n časovne značke ni v skladu s standardom ISO 8601,\n boste morali definirati izraz in tip za transformacijo\n znakovnega niza v datum ali časovno značko.\n Trenutno časovni pasovi niso podprti.\n Če je čas shranjen v obliki epohe, dodajte `epoch_s` ali `epoch_ms`.\n Če ni podan vzorec, se uporabijo privzete vrednosti na podlagi imena\n podatkovne baze oz. stolpca s pomočjo dodatnega parametra." ], - "Pick a nickname for this database to display as in Superset.": [ - "Izberite vzdevek za to podatkovno bazo, ki bo prikazan v Supersetu." + "Certified By": ["Certificiral/a"], + "Person or group that has certified this metric": [ + "Oseba ali skupina, ki je certificirala to mero" ], - "Add additional custom parameters": ["Dodaj dodatne parametre po meri"], - "SSL Mode \"require\" will be used.": [ - "Uporabljen bo SSL način \"require\"." + "Certified by": ["Certificiral/a"], + "Certification details": ["Podrobnosti certifikacije"], + "Details of the certification": ["Podrobnosti certifikacije"], + "Is dimension": ["Dimenzija"], + "Default datetime": ["Privzet datumčas"], + "Is filterable": ["Filtriranje"], + "Select owners": ["Izberite lastnike"], + "Modified columns: %s": ["Spremenjeni stolpci: %s"], + "Removed columns: %s": ["Odstranjeni stolpci: %s"], + "New columns added: %s": ["Dodani novi stolpci: %s"], + "Metadata has been synced": ["Metapodatki so sinhronizirani"], + "An error has occurred": ["Prišlo je do napake"], + "Column name [%s] is duplicated": ["Ime stolpca [%s] je podvojeno"], + "Metric name [%s] is duplicated": ["Ime mere [%s] je podvojeno"], + "Calculated column [%s] requires an expression": [ + "Izračunan stolpec [%s] zahteva izraz" ], - "Type of Google Sheets allowed": ["Dovoljeni tipi Googlovih preglednic"], - "Publicly shared sheets only": ["Samo javno deljene preglednice"], - "Public and privately shared sheets": [ - "Javno in zasebno deljene preglednice" + "Basic": ["Osnovno"], + "Default URL": ["Privzeti URL"], + "Default URL to redirect to when accessing from the dataset list page": [ + "Privzeti URL za preusmeritev, ko dostopate iz strani s seznamom podatkovnih setov" ], - "How do you want to enter service account credentials?": [ - "Kako želite vnesti prijavne podatke servisnega računa?" + "Autocomplete filters": ["Samodokončaj filtre"], + "Whether to populate autocomplete filters options": [ + "Če želite napolniti možnosti za samodokončanje filtrov" ], - "Upload JSON file": ["Naloži JSON datoteko"], - "Copy and Paste JSON credentials": [ - "Kopiraj in prilepi JSON prijavne podatke" + "Autocomplete query predicate": ["Predikat za samodokončanje poizvedb"], + "When using \"Autocomplete filters\", this can be used to improve performance of the query fetching the values. Use this option to apply a predicate (WHERE clause) to the query selecting the distinct values from the table. Typically the intent would be to limit the scan by applying a relative time filter on a partitioned or indexed time-related field.": [ + "Ko uporabljate \"Samodokončaj filtre\", lahko s tem izboljšate hitrost pridobivanja rezultatov s poizvedbo. Z uporabo te možnosti dodate predikat (WHERE stavek) k poizvedbi za izbiro različnih vrednosti iz tabele. Običajno je namen omejiti poizvedbo z uporabo filtra za relativni čas na particioniranem ali indeksiranem časovnem polju." ], - "Service Account": ["Servisni račun"], - "Copy and paste the entire service account .json file here": [ - "Tukaj kopirajte in prilepite celotno json datoteko servisnega računa" + "Extra data to specify table metadata. Currently supports metadata of the format: `{ \"certification\": { \"certified_by\": \"Data Platform Team\", \"details\": \"This table is the source of truth.\" }, \"warning_markdown\": \"This is a warning.\" }`.": [ + "Dodatni podatki za tabelo metapodatkov. Trenutno je podprta naslednja oblika zapisa metapodatkov: `{ \"certification\": { \"certified_by\": \"Tim za razvoj\", \"details\": \"Ta tabela je vir resnice.\" }, \"warning_markdown\": \"To je opozorilo.\" }`." ], - "Upload Credentials": ["Naloži prijavne podatke"], - "Use the JSON file you automatically downloaded when creating your service account.": [ - "Uporabite JSON datoteko, ki ste jo prenesli pri ustvarjanju servisnega računa." + "Cache timeout": ["Časovna omejitev predpomnilnika"], + "The duration of time in seconds before the cache is invalidated": [ + "Trajanje (v sekundah) do razveljavitve predpomnilnika" ], - "Connect Google Sheets as tables to this database": [ - "Googlove preglednice poveži s to podatkovno bazo kot tabele" + "Hours offset": ["Urni premik"], + "The number of hours, negative or positive, to shift the time column. This can be used to move UTC time to local time.": [ + "Število ur, negativno ali pozitivno, za zamik časovnega stolpca. Na ta način je mogoče UTC čas prestaviti na lokalni čas." ], - "Google Sheet Name and URL": ["Ime Googlove preglednice in URL"], - "Enter a name for this sheet": ["Vnesite ime te preglednice"], - "Paste the shareable Google Sheet URL here": [ - "Prilepite deljeni URL Googlove preglednice sem" + "Spatial": ["Prostorski"], + "Click the lock to make changes.": [ + "Kliknite ključavnico, da omogočite spreminjanje." ], - "Add sheet": ["Dodaj preglednico"], - "Copy the account name of that database you are trying to connect to.": [ - "Kopirajte ime računa podatkovne baze, s katero se skušate povezati." + "Click the lock to prevent further changes.": [ + "Kliknite ključavnico, da onemogočite spreminjanje." ], - "Add dataset": ["Dodaj podatkovni set"], - "An error occurred while fetching dataset related data": [ - "Napaka pri pridobivanju podatkov iz podatkovnega seta" + "virtual": ["virtualni"], + "Dataset name": ["Ime podatkovnega seta"], + "When specifying SQL, the datasource acts as a view. Superset will use this statement as a subquery while grouping and filtering on the generated parent queries.": [ + "Ko podajate SQL, se podatkovni vir obnaša kot pogled (view). Superset bo ta zapis uporabil kot podpoizvedbo, pri čemer bo združeval in filtriral na podlagi ustvarjenih starševskih poizvedb." ], - "An error occurred while fetching dataset related data: %s": [ - "Napaka pri pridobivanju podatkov iz podatkovnega seta: %s" + "The JSON metric or post aggregation definition.": [ + "JSON mera ali po-agregacijska definicija." ], - "Physical dataset": ["Fizičen podatkovni set"], - "Virtual dataset": ["Virtualen podatkovni set"], - "An error occurred while fetching dataset owner values: %s": [ - "Pri pridobivanju polja lastnik podatkovnega seta je prišlo do napake: %s" + "Physical": ["Fizičen"], + "The pointer to a physical table (or view). Keep in mind that the chart is associated to this Superset logical table, and this logical table points the physical table referenced here.": [ + "Kazalec na fizično tabelo (ali pogled). Grafikon je povezan s to Supersetovo logično tabelo, ki kaže na tukaj referencirano fizično tabelo." ], - "An error occurred while fetching datasets: %s": [ - "Prišlo je do napake pri pridobivanju podatkovnih setov: %s" + "Warning": ["Opozorilo"], + "Optional warning about use of this metric": [ + "Opcijsko opozorilo za uporabo te mere" ], - "An error occurred while fetching schema values: %s": [ - "Pri pridobivanju vrednosti shem je prišlo do napake: %s" + "Be careful.": ["Bodite previdni."], + "Changing these settings will affect all charts using this dataset, including charts owned by other people.": [ + "Spreminjanje teh nastavitev bo vplivalo na vse grafikone, ki uporabljajo ta podatkovni set, vključno z grafikoni v lasti drugih oseb." ], - "Import datasets": ["Uvozi podatkovne sete"], - "There was an issue deleting the selected datasets: %s": [ - "Pri brisanju izbranih podatkovnih setov je prišlo do težave: %s" + "Sync columns from source": ["Sinhroniziraj stolpce z virom"], + "Calculated columns": ["Izračunani stolpci"], + "Settings": ["Nastavitve"], + "The dataset has been saved": ["Podatkovni set je shranjen"], + "The dataset configuration exposed here\n affects all the charts using this dataset.\n Be mindful that changing settings\n here may affect other charts\n in undesirable ways.": [ + "Tukaj prikazane nastavitve podatkovnega seta\n vplivajo na vse grafikone, ki uporabljajo\n ta podatkovni set. Spreminjanje\n nastavitev lahko nezaželeno vpliva\n na druge grafikone." ], - "The dataset %s is linked to %s charts that appear on %s dashboards. Are you sure you want to continue? Deleting the dataset will break those objects.": [ - "Podatkovni set %s je povezan z grafikoni %s, ki so prisotni na nadzorni plošči %s. Ali želite nadaljevati? Izbris podatkovnega seta bo pokvaril te objekte." + "Are you sure you want to save and apply changes?": [ + "Ali resnično želite shraniti in uporabiti spremembe?" ], - "Delete Dataset?": ["Izbrišem podatkovni set?"], - "Are you sure you want to delete the selected datasets?": [ - "Ali ste prepričani, da želite izbrisati izbrane podatkovne sete?" + "Confirm save": ["Potrdite shranjevanje"], + "Edit Dataset ": ["Uredi podatkovni set "], + "Use legacy datasource editor": [ + "Uporabi starejši urejevalnik podatkovnega vira" ], - "0 Selected": ["Izbranih: 0"], - "%s Selected (Virtual)": ["Izbranih: %s (virtualni)"], - "%s Selected (Physical)": ["Izbranih: %s (fizični)"], - "%s Selected (%s Physical, %s Virtual)": [ - "Izbranih: %s (fizični: %s, virtualni: %s)" + "This dataset is managed externally, and can't be edited in Superset": [ + "Ta podatkovni set se ne ureja znotraj Superseta" ], - "The passwords for the databases below are needed in order to import them together with the datasets. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj s podatkovnimi seti. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." + "DELETE": ["IZBRIŠI"], + "delete": ["izbriši"], + "Type \"%s\" to confirm": ["Vnesite \"%s\" za potrditev"], + "Click to edit": ["Kliknite za urejanje"], + "You don't have the rights to alter this title.": [ + "Nimate pravic za spreminjanje tega naslova." ], - "You are importing one or more datasets that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "Uvažate enega ali več podatkovnih setov, ki že obstajajo. S prepisom lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" + "Unexpected error": ["Nepričakovana napaka"], + "This may be triggered by:": ["To je lahko sproženo z/s:"], + "Please reach out to the Chart Owner for assistance.": [ + "Za pomoč se obrnite na lastnika grafikona." ], - "There was an issue previewing the selected query. %s": [ - "Pri predogledu izbrane poizvedbe je prišlo do težave. %s" + "Chart Owner: %s": ["Lastnik grafikona: %s"], + "%(message)s\nThis may be triggered by: \n%(issues)s": [ + "%(message)s\nTo je lahko sproženo z/s: \n%(issues)s" ], - "Duration: %s": ["Trajanje: %s"], - "Tab name": ["Naslov zavihka"], - "TABLES": ["TABELE"], - "Rows": ["Vrstice"], - "Open query in SQL Lab": ["Odpri poizvedbo v SQL laboratoriju"], - "An error occurred while fetching database values: %s": [ - "Pri pridobivanju vrednosti podatkovne baze je prišlo do napake: %s" + "%s Error": ["%s napaka"], + "Missing dataset": ["Manjka podatkovni set"], + "See more": ["Oglejte si več"], + "See less": ["Oglejte si manj"], + "Copy message": ["Kopiraj sporočilo"], + "Close": ["Zapri"], + "This was triggered by:": ["To je bilo sproženo z/s:"], + "Did you mean:": ["Ste mislili:"], + "%(suggestion)s instead of \"%(undefinedParameter)s?\"": [ + "%(suggestion)s namesto \"%(undefinedParameter)s?\"" ], - "An error occurred while fetching user values: %s": [ - "Pri pridobivanju vrednosti uporabnika je prišlo do napake: %s" + "Parameter error": ["Napaka parametra"], + "We’re having trouble loading this visualization. Queries are set to timeout after %s second.": [ + "Težava pri nalaganju vizualizacije. Časovni iztek poizvedb je nastavljen na %s sekund." ], - "Search by query text": ["Išči z besedilom poizvedbe"], - "Query preview": ["Predogled poizvedbe"], - "Next": ["Naslednji"], - "Open in SQL Lab": ["Odpri v SQL laboratoriju"], - "User query": ["Uporabnikova poizvedba"], - "Executed query": ["Zagnana poizvedba"], - "The passwords for the databases below are needed in order to import them together with the saved queries. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj s shranjenimi poizvedbami. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." + "We’re having trouble loading these results. Queries are set to timeout after %s second.": [ + "Težava pri nalaganju rezultatov. Časovni iztek poizvedb je nastavljen na %s sekund." ], - "You are importing one or more saved queries that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "Uvažate eno ali več shranjenih poizvedb, ki že obstajajo. S prepisom lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" + "%(subtitle)s\nThis may be triggered by:\n %(issue)s": [ + "%(subtitle)s\nTo je lahko sproženo z/s: \n %(issue)s" ], - "There was an issue previewing the selected query %s": [ - "Do težave je prišlo pri predogledu izbrane poizvedbe %s" + "Timeout error": ["Napaka pretečenega časa"], + "Click to favorite/unfavorite": [ + "Kliknite za priljubljeno/nepriljubljeno" ], - "Import queries": ["Uvozi poizvedbe"], - "There was an issue deleting the selected queries: %s": [ - "Do težave je prišlo pri brisanju izbranih poizvedb: %s" + "Cell content": ["Vsebina celice"], + "Database driver for importing maybe not installed. Visit the Superset documentation page for installation instructions:": [ + "Gonilnik podatkovne baze za uvoz ni nameščen. Za navodila pojdite na dokumentacijo Superseta:" ], - "Edit query": ["Uredi poizvedbo"], - "Copy query URL": ["Kopiraj URL poizvedbe"], - "Export query": ["Izvozi poizvedbe"], - "Delete query": ["Izbriši poizvedbo"], - "This action will permanently delete the saved query.": [ - "S tem dejanjem boste trajno izbrisali shranjeno poizvedbo." + "OVERWRITE": ["OVERWRITE"], + "Overwrite": ["Prepiši"], + "Import": ["Uvozi"], + "Import %s": ["Uvozi %s"], + "Last Updated %s": ["Zadnja posodobitev %s"], + "Sort": ["Razvrsti"], + "%s Selected": ["Izbranih: %s"], + "Deselect all": ["Počisti izbor"], + "No results match your filter criteria": [ + "Noben rezultat ne ustreza vašim kriterijem" ], - "Delete Query?": ["Izbrišem poizvedbo?"], - "Are you sure you want to delete the selected queries?": [ - "Ali ste prepričani, da želite izbrisati izbrane poizvedbe?" + "Try different criteria to display results.": [ + "Za prikaz rezultatov poskusite z drugačnimi kriteriji." ], - "queries": ["poizvedbe"], - "Query name": ["Ime poizvedbe"], - "[Untitled]": ["[Neimenovana]"], - "Unknown": ["Neznano"], - "Edited": ["Urejane"], - "Created": ["Ustvarjene"], - "Viewed": ["Ogledane"], - "Mine": ["Moje"], - "Recently viewed charts, dashboards, and saved queries will appear here": [ - "Nedavno ogledani grafikoni, nadzorne plošče in shranjene poizvedbe bodo prikazane tukaj" + "clear all filters": ["počisti vse filtre"], + "No Data": ["Ni podatkov"], + "%s-%s of %s": ["%s-%s od %s"], + "Type a value": ["Vnesite vrednost"], + "Filter": ["Filter"], + "Select or type a value": ["Izberite ali vnesite vrednost"], + "OK": ["OK"], + "Menu actions trigger": ["Preklapljanje funkcionalnosti menijev"], + "Weekly Report for %s": ["Tedensko poročilo za %s"], + "Weekly Report": ["Tedensko poročilo"], + "Edit email report": ["Uredi e-poštno poročilo"], + "Schedule a new email report": ["Dodaj novo e-poštno poročilo na urnik"], + "Add": ["Dodaj"], + "Message content": ["Vsebina sporočila"], + "Text embedded in email": ["Besedilo vključeno v e-pošto"], + "Image (PNG) embedded in email": ["Slika (PNG) vključena v e-pošto"], + "Formatted CSV attached in email": ["Oblikovan CSV pripet e-pošti"], + "Include a description that will be sent with your report": [ + "Vključite opis, ki bo vključen v poročilo" ], - "Recently created charts, dashboards, and saved queries will appear here": [ - "Nedavno ustvarjeni grafikoni, nadzorne plošče in shranjene poizvedbe bodo prikazane tukaj" + "A screenshot of the dashboard will be sent to your email at": [ + "Zaslonska slika nadzorne plošče bo poslana na vaš e-naslov ob" ], - "Example ${tableName.toLowerCase()} will appear here": [ - "Primer ${tableName.toLowerCase()} se bo prikazal tukaj" + "Timezone": ["Časovni pas"], + "Failed to update report": ["Posodabljanje poročila neuspešno"], + "Failed to create report": ["Ustvarjanje poročila nesupešno"], + "Email reports active": ["E-poštna poročila aktivna"], + "Delete email report": ["Izbriši e-poštno poročilo"], + "Set up an email report": ["Nastavite e-poštno poročilo"], + "Schedule email report": ["Dodaj e-poštno poročilo na urnik"], + "This action will permanently delete %s.": [ + "S tem dejanjem boste trajno izbrisali %s." ], - "Recently edited charts, dashboards, and saved queries will appear here": [ - "Nedavno urejani grafikoni, nadzorne plošče in shranjene poizvedbe bodo prikazane tukaj" + "Delete Report?": ["Izbrišem poročilo?"], + "Loading...": ["Nalagam ..."], + "Access to user activity data is restricted": [ + "Dostop do aktivnosti uporabnikov je omejen" ], - "${tableName\r\n .split('')\r\n .slice(0, tableName.length - 1)\r\n .join('')}\r\n ": [ - "${tableName\r\n .split('')\r\n .slice(0, tableName.length - 1)\r\n .join('')}\r\n " + "There was an error loading the tables": ["Napaka pri nalaganju tabel"], + "See table schema": ["Ogled sheme tabele"], + "Select table or type table name": ["Izberite ali vnesite ime tabele"], + "Force refresh table list": ["Osveži seznam tabel"], + "Timezone selector": ["Izbira časovnega pasa"], + "There is not enough space for this component. Try decreasing its width, or increasing the destination width.": [ + "Za to komponento ni dovolj prostora. Poskusite zmanjšati širino ali pa povečati širino cilja." ], - "You don't have any favorites yet!": ["Priljubljenih še niste izbrali!"], - "SQL Lab queries": ["Poizvedbe SQL laboratorija"], - "${tableName}": ["${tableName}"], - "query": ["poizvedba"], - "Share": ["Deljenje"], - "Ran %s": ["Pretečeno %s"], - "There was an issue fetching your recent activity: %s": [ - "Pri pridobivanju vaše nedavne aktivnosti je prišlo do napake: %s" + "Can not move top level tab into nested tabs": [ + "Najvišjega zavihka ni mogoče premakniti v gnezdene zavihke" ], - "There was an issues fetching your dashboards: %s": [ - "Prišlo je do napake pri pridobivanju nadzornih plošč: %s" + "This chart has been moved to a different filter scope.": [ + "Ta grafikon je bil prestavljen v drug doseg filtrov." ], - "There was an issues fetching your chart: %s": [ - "Prišlo je do napake pri pridobivanju grafikona: %s" + "There was an issue fetching the favorite status of this dashboard.": [ + "Pri pridobivanju statusa \"priljubljeno\" za to nadzorno ploščo je prišlo do težave." ], - "There was an issues fetching your saved queries: %s": [ - "Prišlo je do napake pri pridobivanju shranjenih poizvedb: %s" + "There was an issue favoriting this dashboard.": [ + "Pri uvrščanju nadzorne plošče med priljubljene je prišlo do težave." ], - "Recents": ["Nedavno"], - "Select start and end date": ["Izberite začetni in končni datum"], - "Type or Select [%s]": ["Vnesite ali izberite [%s]"], - "No results found": ["Rezultati niso najdeni"], - "Tools": ["Orodja"], - "Filter box": ["Izbirnik za filtriranje"], - "Chart component that lets you add a custom filter UI in your dashboard. When added to dashboard, a filter box lets users specify specific values or ranges to filter charts by. The charts that each filter box is applied to can be fine tuned as well in the dashboard view.\r\n\r\n Note that this plugin is being replaced with the new Filters feature that lives in the dashboard view itself. It's easier to use and has more capabilities!": [ - "Komponenta grafikona, ki omogoča dodajanje vmesnika filtrov po meri v nadzorno ploščo. Ko je dodana na nadzorno ploščo, lahko uporabnik določi poljubne vrednosti ali obsege filtrov. Grafikoni, na katere se nanašajo filtri, so lahko precizno izbrani tudi v pogledu nadzorne plošče.\r\n\r\n Vedite, da bo ta vtičnik v prihodnosti zamenjan z novim konceptom filtrov, ki bodo živeli v kontekstu same nadzorne plošče in bodo zmogljivejši ter enostavnejši za uporabo!" + "This dashboard is now published": [ + "Ta nadzorna plošča je sedaj objavljena" ], - "Show Druid granularity dropdown": [ - "Prikaži spustni seznam za Druid granulacijo" + "This dashboard is now hidden": ["Ta nadzorna plošča je sedaj skrita"], + "You do not have permissions to edit this dashboard.": [ + "Nimate dovoljenj za urejanje te nadzorne plošče." ], - "Check to include Druid granularity dropdown": [ - "Izberite za vključitev spustnega seznama za Druid granulacijo" + "[ untitled dashboard ]": ["[ neimenovana nadzorna plošča ]"], + "This dashboard was saved successfully.": [ + "Nadzorna plošča je bila uspešno shranjena." ], - "Show Druid time origin": ["Prikaži časovno izhodišče za Druid"], - "Check to include time origin dropdown": [ - "Izberi za vključitev spustnega seznama za časovno izhodišče" + "Sorry, an unknown error occured": ["Prišlo je do neznane napake"], + "Sorry, there was an error saving this dashboard: %s": [ + "Prišlo je do napake pri shranjevanju nadzorne plošče: %s" ], - "Filters configuration": ["Nastavitve filtrov"], - "Filter configuration for the filter box": ["Nastavitve za polje filtra"], - "Date filter": ["Filter po datumu"], - "Whether to include a time filter": [ - "Če želite vključiti časovni filter" + "You do not have permission to edit this dashboard": [ + "Nimate dovoljenja za urejanje te nadzorne plošče" ], - "Instant filtering": ["Takojšnje filtriranje"], - "Check to apply filters instantly as they change instead of displaying [Apply] button": [ - "Izberite za takojšnjo uporabo filtrov, ko se spremenijo, brez prikazovanja gumba Uveljavi" + "Could not fetch all saved charts": [ + "Vseh shranjenih grafikonov ni bilo mogoče pridobiti" ], - "Show SQL time grain dropdown": [ - "Prikaži SQL spustni seznam za časovno granulacijo" + "Sorry there was an error fetching saved charts: ": [ + "Prišlo je do napake pri pridobivanju shranjenih grafikonov: " ], - "Show time grain dropdown": [ - "Prikaži spustni seznam za časovno granulacijo" + "Visualization": ["Vizualizacija"], + "Data source": ["Podatkovni vir"], + "Added": ["Dodano"], + "Any color palette selected here will override the colors applied to this dashboard's individual charts": [ + "Na tem mestu izbrana barvna shema bo nadomestila barve posameznih grafikonov v tej nadzorni plošči" ], - "Check to include SQL time grain dropdown": [ - "Izberite za vključitev spustnega seznama za časovno granulacijo SQL" + "You have unsaved changes.": ["Imate neshranjene spremembe."], + "Changes saved.": ["Spremembe shranjene."], + "Disable embedding?": ["Onemogočite vgrajevanje?"], + "This will remove your current embed configuration.": [ + "To bo odstranilo trenutno konfiguracijo za vgrajevanje." ], - "Check to include time grain dropdown": [ - "Izberite za vključitev spustnega seznama za časovno granullacijo" + "Embedding deactivated.": ["Vgrajevanje deaktivirano."], + "Sorry, something went wrong. Embedding could not be deactivated.": [ + "Nekaj je šlo narobe. Vgrajevanja ni mogoče deaktivirati." ], - "Show SQL time column": ["Prikaži stolpec SQL čas"], - "Show time column": ["Prikaži časovni stolpec"], - "Check to include time column dropdown": [ - "Izberite za vključitev časovnega stolpca v spustni seznam" + "This dashboard is ready to embed. In your application, pass the following id to the SDK:": [ + "Nadzorna plošča je pripravljena za vgradnjo. V svoji aplikaciji v SDK vključite naslednji ID:" ], - "Limit selector values": ["Omeji vrednosti izbirnikov"], - "These filters apply to the values available in the dropdowns": [ - "Ti filtri se nanašajo na vrednosti v spustnih seznamih" + "Configure this dashboard to embed it into an external web application.": [ + "Nastavite nadzorno ploščo za vgradnjo v zunanjo spletno aplikacijo." ], - "Time-series Table": ["Tabela s časovno vrsto"], - "Compare multiple time series charts (as sparklines) and related metrics quickly.": [ - "Hitra primerjava več grafikonov časovnih vrst (sparkline način) in povezanih mer." + "For further instructions, consult the": [ + "Za nadaljnja navodila se posvetujte z" ], - "Multi-Variables": ["Več spremenljivk"], - "Comparison": ["Primerjava"], - "Legacy": ["Staro"], - "Percentages": ["Procenti"], - "Tabular": ["Tabelarično"], - "Text": ["Besedilo"], - "Trend": ["Trend"], - "Time Range": ["Časovno obdobje"], - "Time Column": ["Časovni stolpec"], - "Time Grain": ["Granulacija časa"], - "Time Granularity": ["Granulacija časa"], - "Aggregate": ["Agregacija"], - "Raw records": ["Surovi podatki"], - "Show info tooltip": ["Prikaži opis orodja"], - "Resample": ["Prevzorči"], - "Fill method": ["Način polnjenja"], - "Annotations and Layers": ["Oznake in sloji"], - "Chart Title": ["Naslov grafikona"], - "X Axis Title": ["Naslov X osi"], - "X AXIS TITLE BOTTOM MARGIN": ["SPODNJA OBROBA NASLOVA X OSI"], - "Y Axis Title": ["Naslov Y osi"], - "Y AXIS TITLE MARGIN": ["OBROBA NASLOVA Y OSI"], - "Y AXIS TITLE POSITION": ["POZICIJA NASLOVA Y OSI"], - "Predictive Analytics": ["Prediktivna analitika"], - "Enable forecast": ["Omogoči napoved"], - "Enable forecasting": ["Omogoči napovedovanje"], - "Forecast periods": ["Periode napovedi"], - "How many periods into the future do we want to predict": [ - "Za koliko period v prihodnosti želite napoved" + "Superset Embedded SDK documentation.": [ + "Dokumentacija SDK za vgrajevanje." ], - "Confidence interval": ["Interval zaupanja"], - "Width of the confidence interval. Should be between 0 and 1": [ - "Širina intervala zaupanja. Mora bit med 0 in 1" + "Allowed Domains (comma separated)": [ + "Dovoljene domene (ločeno z vejico)" ], - "Should yearly seasonality be applied. An integer value will specify Fourier order of seasonality.": [ - "Če želite letno sezonskost. Celo število določa Fourier-jev red sezonskosti." + "A list of domain names that can embed this dashboard. Leaving this field empty will allow embedding from any domain.": [ + "Seznam imen domen, ki lahko vgradijo to nadzorno ploščo. Če polje ostane prazno, je vgrajevanje dovoljeno iz vseh domen." ], - "Should weekly seasonality be applied. An integer value will specify Fourier order of seasonality.": [ - "Če želite tedensko sezonskost. Celo število določa Fourier-jev red sezonskosti." + "Deactivate": ["Deaktiviraj"], + "Save changes": ["Shrani spremembe"], + "Enable embedding": ["Omogoči vgrajevanje"], + "Embed": ["Vgradi"], + "Drag and drop components and charts to the dashboard": [ + "Povlecite in spustite elemente in grafikone na nadzorno ploščo" ], - "Should daily seasonality be applied. An integer value will specify Fourier order of seasonality.": [ - "Če želite dnevno sezonskost. Celo število določa Fourier-jev red sezonskosti." + "You can create a new chart or use existing ones from the panel on the right": [ + "Ustvarite lahko nove grafikone ali uporabite obstoječe iz panela na desni" ], - "Datasource & Chart Type": ["Tip podatkovnega vira in grafikona"], - "URL Parameters": ["Parametri URL"], - "Extra url parameters for use in Jinja templated queries": [ - "Dodatni parametri za poizvedbe z Jinja predlogami" + "Drag and drop components to this tab": [ + "Povlecite in spustite elemente na zavihek" ], - "Extra Parameters": ["Dodatni parametri"], - "Extra parameters that any plugins can choose to set for use in Jinja templated queries": [ - "Dodatni parametri, ki jih lahko uporabi kateri koli vtičnik za poizvedbe z Jinja predlogami" + "There are no components added to this tab": [ + "Na zavihek niso bili dodani elementi" ], - "Color Scheme": ["Barvna shema"], - "One or many columns to pivot as columns": [ - "En ali več stolpcev za stolpčno vrtenje" + "You can add the components in the edit mode.": [ + "Elemente lahko dodate v načinu urejanja." ], - "Right Axis Metric": ["Mera desne osi"], - "Bubble Size": ["Velikost mehurčka"], - "Metric used to calculate bubble size": [ - "Mera za izračun velikosti mehurčkov" + "Edit the dashboard": ["Uredi nadzorno ploščo"], + "Ready to review filters in this dashboard?": [ + "Ste pripravljeni za pregled filtrov v tej nadzorni plošči?" ], - "Color Metric": ["Mera za barvo"], - "Drop temporal column here": ["Spustite časovni stolpec sem"], - "Emit dashboard cross filters": [ - "Oddajaj medsebojne filtre nadzorne plošče" + "Remind me in 24 hours": ["Opomni me čez 24 ur"], + "Start Review": ["Začetek pregleda"], + "filter_box will be deprecated in a future version of Superset. Please replace filter_box by dashboard filter components.": [ + "Element filter_box bo v prihodnjih verzijah Superseta opuščen. Nadomestite ga s filtri nadzorne plošče." ], - "Emit dashboard cross filters.": [ - "Oddajaj medsebojne filtre nadzorne plošče." + "There is no chart definition associated with this component, could it have been deleted?": [ + "S to komponento ni povezana nobena definicija grafikona. Ali je bila izbrisana?" ], - "One or many columns to group by. High cardinality groupings should include a sort by metric and series limit to limit the number of fetched and rendered series.": [ - "Eden ali več stolpcev za združevanje. Združevanje z visoko kardinalnostjo naj vsebuje mero za razvrščanje in omjitev serij, s čimer omejite število pridobljenih in prikazanih serij." + "Delete this container and save to remove this message.": [ + "Izbrišite ta okvir in shranite za odpravo tega sporočila." ], - "Fixed Color": ["Izbrana barva"], - "Linear Color Scheme": ["Linearna barvna shema"], - "Time format": ["Oblika zapisa časa"], - "Whether to sort descending or ascending. Takes effect only when \"Sort by\" is set": [ - "Če želite padajoče ali naraščajoče razvrščanje. Učinkuje samo, ko je vključen \"Sort by\"" + "Don't refresh": ["Ne osvežuj"], + "10 seconds": ["10 sekund"], + "30 seconds": ["30 sekund"], + "1 minute": ["1 minuta"], + "5 minutes": ["5 minut"], + "30 minutes": ["30 minut"], + "1 hour": ["1 ura"], + "6 hours": ["6 ur"], + "12 hours": ["12 ur"], + "24 hours": ["24 ur"], + "Refresh interval saved": ["Interval osveževanja shranjen"], + "Refresh interval": ["Interval osveževanja"], + "Refresh frequency": ["Frekvenca osveževanja"], + "Are you sure you want to proceed?": ["Ali želite nadaljevati?"], + "Save for this session": ["Shranite za to sejo"], + "You must pick a name for the new dashboard": [ + "Izbrati morate ime nove nadzorne plošče" ], - "Show less columns": ["Prikaži manj stolpcev"], - "Show all columns": ["Prikaži vse stolpce"], - "Emit Target": ["Cilj oddajanja"], - "If you wish to specify a different target column than the original column, it can be entered here": [ - "Če želite nastaviti drug ciljni stolpec od izvornega, ga lahko vnesete tukaj" + "Save dashboard": ["Shrani nadzorno ploščo"], + "Overwrite Dashboard [%s]": ["Prepiši nadzorno ploščo [%s]"], + "Save as:": ["Shrani kot:"], + "[dashboard name]": ["[ime nadzorne plošče]"], + "also copy (duplicate) charts": ["kopiraj (podvoji) tudi grafikone"], + "Filter your charts": ["Filtriraj grafikone"], + "Sort by %s": ["Razvrščanje po %s"], + "Superset chart": ["Superset grafikon"], + "Check out this chart in dashboard:": [ + "Preizkusite ta grafikon v nadzorni plošči:" ], - "Fraction digits": ["Število decimalk"], - "Number of decimal digits to round numbers to": [ - "Število decimalnih mest za zaokroževanje števil" + "Layout elements": ["Postavitev elementov"], + "Cross Filter Scoping": ["Doseg medsebojnega filtra"], + "Load a CSS template": ["Naloži CSS predlogo"], + "Live CSS editor": ["CSS urejevalnik v živo"], + "There are no charts added to this dashboard": [ + "V nadzorni plošči ni grafikonov" ], - "Min Width": ["Min. širina"], - "Default minimal column width in pixels, actual width may still be larger than this if other columns don't need much space": [ - "Privzeta min. širina stolpca v pikslih. Dejanska širina bo lahko večja, če drugi stolpci ne potrebujejo veliko prostora" + "Go to the edit mode to configure the dashboard and add charts": [ + "Za nastavitve nadzorne plošče in dodajanje grafikonov pojdite v način urejanja" ], - "Text align": ["Poravnava besedila"], - "Horizontal alignment": ["Vodoravna poravnava"], - "Left": ["Levo"], - "Center": ["Na sredino"], - "Right": ["Desno"], - "Show cell bars": ["Prikaži stolp. graf v celicah"], - "Whether to display a bar chart background in table columns": [ - "Če želite omogočiti prikaz manjših stolpčnih grafikonov v ozadju stolpcev tabele" + "Applied Cross Filters (%d)": ["Uporabljeni medsebojni filtri (%d)"], + "Applied Filters (%d)": ["Uporabljeni filtri (%d)"], + "Incompatible Filters (%d)": ["Neskladni filtri (%d)"], + "Unset Filters (%d)": ["Neuporabljeni filtri (%d)"], + "This dashboard is currently auto refreshing; the next auto refresh will be in %s.": [ + "Nadzorna plošča se trenutno samodejno osvežuje. Naslednja samodejna osvežitev bo čez %s." ], - "Align +/-": ["Poravnaj +/-"], - "Whether to align positive and negative values in cell bar chart at 0": [ - "Če želite poravnati pozitivne in negativne vrednosti v stolpčnem grafikonu celic pri 0" + "Your dashboard is too large. Please reduce its size before saving it.": [ + "Vaša nadzorna plošča je prevelika. Pred shranjevanjem jo zmanjšajte." ], - "Color +/-": ["Barva +/-"], - "Whether to colorize numeric values by if they are positive or negative": [ - "Če želite obarvati številske vrednosti, ko so le-te pozitivne ali negativne" + "Add the name of the dashboard": ["Dodajte naziv nadzorne plošče"], + "Dashboard title": ["Naziv nadzorne plošče"], + "Undo the action": ["Razveljavi dejanje"], + "Redo the action": ["Ponovno uveljavi dejanje"], + "Discard": ["Zavrzi"], + "Edit dashboard": ["Uredi nadzorno ploščo"], + "An error occurred while fetching available CSS templates": [ + "Pri pridobivanju CSS predlog je prišlo do napake" ], - "Small number format": ["Oblika zapisa majhnih števil"], - "D3 number format for numbers between -1.0 and 1.0, useful when you want to have different siginificant digits for small and large numbers": [ - "D3 oblika zapisa za števila med -1.0 in 1.0. Uporabno, če želite različno število števk za majhna in velika števila" + "Refreshing charts": ["Osveževanje grafikonov"], + "Superset dashboard": ["Superset nadzorna plošča"], + "Check out this dashboard: ": ["Preizkusite to nadzorno ploščo: "], + "Refresh dashboard": ["Osveži nadzorno ploščo"], + "Exit fullscreen": ["Izhod iz celozaslonskega načina"], + "Enter fullscreen": ["Vklopi celozaslonski način"], + "Edit properties": ["Uredi lastnosti"], + "Edit CSS": ["Uredi CSS"], + "Download as image": ["Izvozi kot sliko"], + "Share": ["Deljenje"], + "Copy permalink to clipboard": ["Kopiraj povezavo v odložišče"], + "Share permalink by email": ["Deli povezavo po e-pošti"], + "Embed dashboard": ["Vgradi nadzorno ploščo"], + "Manage email report": ["Upravljaj e-poštno poročilo"], + "Set filter mapping": ["Nastavi shemo filtrov"], + "Set auto-refresh interval": ["Nastavi interval samodejnega osveževanja"], + "Apply": ["Uporabi"], + "A valid color scheme is required": [ + "Zahtevana je veljavna barvna shema" ], - "D3 format syntax: https://github.com/d3/d3-format": [ - "Sintaksa D3 formata: https://github.com/d3/d3-format" + "Dashboard properties updated": [ + "Lastnosti nadzorne plošče posodobljene" ], - "Adaptive formatting": ["Adaptivno oblikovanje"], - "Duration in ms (66000 => 1m 6s)": ["Trajanje v ms (66000 => 1m 6s)"], - "Duration in ms (1.40008 => 1ms 400µs 80ns)": [ - "Trajanje v ms (1.40008 => 1ms 400µs 80ns)" + "The dashboard has been saved": ["Nadzorna plošča je bila shranjena"], + "Access": ["Dostop"], + "Owners is a list of users who can alter the dashboard. Searchable by name or username.": [ + "\"Lastniki\" je seznam uporabnikov, ki lahko spreminjajo nadzorno ploščo. Iskanje je možno po imenu ali uporabniškem imenu." ], - "D3 time format syntax: https://github.com/d3/d3-time-format": [ - "Sintaksa D3 časovnega formata:: https://github.com/d3/d3-time-format" + "Colors": ["Barve"], + "Roles is a list which defines access to the dashboard. Granting a role access to a dashboard will bypass dataset level checks. If no roles are defined, then the dashboard is available to all roles.": [ + "\"Vloge\" je seznam, ki definira dostop do nadzorne plošče. Dodelitev vloge za dostop do nadzorne plošče bo obšlo preverjanje na nivoju podatkovnega seta. Če vloga ni definirana, bo nadzorna plošča dostopna vsem vlogam." ], - "No results were returned for this query. If you expected results to be returned, ensure any filters are configured properly and the datasource contains data for the selected time range.": [ - "Poizvedba ni vrnila rezultatov. Če ste pričakovali rezultate, poskrbite, da so filtri pravilno nastavljeni in podatkovni vir vsebuje podatke za izbrano časovno obdobje." + "Dashboard properties": ["Lastnosti nadzorne plošče"], + "This dashboard is managed externally, and can't be edited in Superset": [ + "Ta nadzorna plošča se ne ureja znotraj Superseta" ], - "No Results": ["Ni rezultatov"], - "Found invalid orderby options": [ - "Najdene so neveljavne možnosti razvrščanja" + "Basic information": ["Osnovne informacije"], + "URL slug": ["URL slug"], + "A readable URL for your dashboard": [ + "Berljiv URL za vašo nadzorno ploščo" ], - "is expected to be an integer": ["pričakovano je celo število"], - "is expected to be a number": ["pričakovano je število"], - "cannot be empty": ["ne sme biti prazno"], - "haha": ["haha"], - "foo": ["foo"], - "bar": ["bar"], - "yes": ["da"], - "second": ["sekunda"], - "ox": ["ox"], - "Domain": ["Domena"], - "The time unit used for the grouping of blocks": [ - "Časovna enota za združevanje blokov" + "Certification": ["Certifikacija"], + "Person or group that has certified this dashboard.": [ + "Oseba ali skupina, ki je certificirala to nadzorno ploščo." ], - "Subdomain": ["Poddomena"], - "The time unit for each block. Should be a smaller unit than domain_granularity. Should be larger or equal to Time Grain": [ - "Časovna enota za vsak blok. Mora biti manjša enota kot domenska_granulacija. Mora biti večja ali enaka Granulaciji časa" + "Any additional detail to show in the certification tooltip.": [ + "Dodatne podrobnosti za prikaz v certifikacijskem orodju." ], - "Chart Options": ["Možnosti grafikona"], - "Cell Size": ["Velikost celice"], - "The size of the square cell, in pixels": [ - "Velikost kvadratne celice v pikslih" + "JSON metadata": ["JSON metapodatki"], + "This dashboard is not published, it will not show up in the list of dashboards. Click here to publish this dashboard.": [ + "Ta nadzorna plošča ni objavljena in se ne bo prikazala na seznamu nadzornih plošč. Kliknite tukaj za njeno objavo." ], - "Cell Padding": ["Razmak med celicami"], - "The distance between cells, in pixels": [ - "Razdalja med celicami v pikslih" + "This dashboard is not published which means it will not show up in the list of dashboards. Favorite it to see it there or access it by using the URL directly.": [ + "Ta nadzorna plošča ni objavljena in se ne bo prikazala na seznamu nadzornih plošč. Uvrstite jo med priljubljene, da jo boste videli tam, ali pa uporabite URL za neposredni dostop." ], - "Cell Radius": ["Polmer celice"], - "The pixel radius": ["Polmer piksla"], - "Color Steps": ["Barvni koraki"], - "The number color \"steps\"": ["Število barvnih korakov"], - "Time Format": ["Oblika zapisa časa"], - "Legend": ["Legenda"], - "Whether to display the legend (toggles)": [ - "Preklapljanje prikaza legende" + "This dashboard is published. Click to make it a draft.": [ + "Ta nadzorna plošča je objavljena. Kliknite, da jo uvrstite med osnutke." ], - "Show Values": ["Pokaži vrednosti"], - "Whether to display the numerical values within the cells": [ - "Če želite v celicah prikazati numerične vrednosti" + "Draft": ["Osnutek"], + "Annotation layers are still loading.": [ + "Sloj z oznakami se še vedno nalaga." ], - "Show Metric Names": ["Pokaži imena mer"], - "Whether to display the metric name as a title": [ - "Če želite prikazati ime mere kot naslov" + "One ore more annotation layers failed loading.": [ + "Eden ali več slojev z oznakami se ni naložil." ], - "Number Format": ["Oblika zapisa števila"], - "Correlation": ["Korelacija"], - "Visualizes how a metric has changed over a time using a color scale and a calendar view. Gray values are used to indicate missing values and the linear color scheme is used to encode the magnitude of each day's value.": [ - "Prikaže kako se je mera spreminjala s časom s pomočjo barvne lestvice in koledarskega pogleda. Sive vrednosti ponazarjajo manjkajoče vrednosti. Amplituda dnevnih vrednosti je ponazorjena z linearno barvno shemo." + "Emitted values": ["Oddane vrednosti"], + "Click to edit %s in a new tab": [ + "Kliknite za urejanje %s v novem zavihku" ], - "Business": ["Aktivnost"], - "Intensity": ["Intenzivnost"], - "Pattern": ["Vzorec"], - "Report": ["Poročilo"], - "Sort by metric": ["Mera za razvrščanje"], - "Whether to sort results by the selected metric in descending order.": [ - "Če želite padajoče razvrstiti rezultate z izbrano mero." + "Click to edit chart in a new tab": [ + "Kliknite za urejanje grafikona v novem zavihku" ], - "Number format": ["Oblika zapisa števila"], - "Choose a number format": ["Izberite obliko zapisa števila"], - "Choose a source": ["Izberite izvor"], - "Target": ["Cilj"], - "Choose a target": ["Izberite cilj"], - "Flow": ["Potek"], - "Showcases the flow or link between categories using thickness of chords. The value and corresponding thickness can be different for each side.": [ - "Prikaže potek ali povezave med kategorijami z debelino tetiv. Vrednost in debelina sta lahko različni za vsako stran." + "Click to clear emitted filters": ["S klikom počistite oddane filtre"], + "Data refreshed": ["Podatki osveženi"], + "Cached %s": ["Predpomnjeno %s"], + "Fetched %s": ["Pridobljeno %s"], + "Query %s: %s": ["Poizvedba %s: %s"], + "Force refresh": ["Osveži"], + "Hide chart description": ["Skrij opis grafikona"], + "Show chart description": ["Prikaži opis grafikona"], + "Edit chart": ["Uredi grafikon"], + "View query": ["Ogled poizvedbe"], + "Drill to detail": ["Vrtaj v podrobnosti"], + "Chart Data: %s": ["Podatki grafikona: %s"], + "Cross-filter scoping": ["Doseg medsebojnega filtra"], + "Share chart by email": ["Deli grafikon po e-pošti"], + "Check out this chart: ": ["Preizkusite ta grafikon: "], + "Download": ["Prenos"], + "Export to .CSV": ["Izvozi v .CSV"], + "Export to full .CSV": ["Izvozi v celoten .CSV"], + "Search...": ["Iskanje ..."], + "No filter is selected.": ["Noben filter ni izbran."], + "Editing 1 filter:": ["Urejanje enega filtra:"], + "Batch editing %d filters:": ["Skupinsko urejanje %d filtrov:"], + "Configure filter scopes": ["Nastavi doseg filtrov"], + "There are no filters in this dashboard.": [ + "V nadzorni plošči ni filtrov." ], - "Relationships between community channels": [ - "Razmerja med skupnostnimi kanali" + "Expand all": ["Razširi vse"], + "Collapse all": ["Skrči vse"], + "An error occurred while opening Explore": [ + "Pri odpiranju Raziskovalca je prišlo do napake" ], - "Chord Diagram": ["Tetivni grafikon"], - "Aesthetic": ["Estetika"], - "Circular": ["Krožno"], - "Proportional": ["Proporcionalno"], - "Relational": ["Relacijsko"], - "Country": ["Država"], - "Which country to plot the map for?": [ - "Za katero državo želite grafikon?" + "This markdown component has an error.": [ + "Markdown komponenta ima napako." ], - "ISO 3166-2 Codes": ["Oznake po ISO 3166-2"], - "Column containing ISO 3166-2 codes of region/province/department in your table.": [ - "Stolpec, ki vsebuje ISO 3166-2 oznake regij/provinc/departmajev v vaši tabeli." + "This markdown component has an error. Please revert your recent changes.": [ + "Markdown komponenta ima napako. Povrnite nedavne spremembe." ], - "Metric to display bottom title": ["Mera za prikaz spodnjega naslova"], - "Map": ["Zemljevid"], - "Visualizes how a single metric varies across a country's principal subdivisions (states, provinces, etc) on a chloropleth map. Each subdivision's value is elevated when you hover over the corresponding geographic boundary.": [ - "Prikaže kako se posamezna mera spreminja glede na območja države (dežele, province, itd.) na kloropletnem zemljevidu. Vsak podrazdelek se dvigne, ko z miško preidete mejo njegovega območja." + "You can": ["Lahko"], + "create a new chart": ["ustvarite nov grafikon"], + "or use existing ones from the panel on the right": [ + "ali uporabite obstoječe iz panela na desni" ], - "2D": ["2D"], - "Geo": ["Geo"], - "Range": ["Doseg"], - "Stacked": ["Naložen"], - "Sorry, there appears to be no data": ["Ni podatkov"], - "Event definition": ["Definicija dogodka"], - "Event Names": ["Imena dogodkov"], - "Columns to display": ["Stolpci za prikaz"], - "Order by entity id": ["Uredi po ID entitete"], - "Important! Select this if the table is not already sorted by entity id, else there is no guarantee that all events for each entity are returned.": [ - "Pomembno! Izberite, če tabela še ni razvrščena po ID entitete, v nasprotnem primeru ni nujno, da bodo vrnjeni vsi dogodki za posamezno entiteto." + "You can add the components in the": ["Lahko dodate elemente v"], + "edit mode": ["načinu urejanja"], + "Delete dashboard tab?": ["Ali izbrišem zavihek nadzorne plošče?"], + "Divider": ["Ločilnik"], + "Header": ["Glava"], + "Row": ["Vrstica"], + "Tabs": ["Zavihki"], + "Preview": ["Predogled"], + "Sorry, something went wrong. Try again later.": [ + "Nekaj je šlo narobe. Poskusite ponovno kasneje." ], - "Minimum leaf node event count": ["Min. število dogodkov za list"], - "Leaf nodes that represent fewer than this number of events will be initially hidden in the visualization": [ - "Listna vozlišča, ki predstavljajo manjše število dogodkov od te vrednosti, bodo v vizualizaciji skrita" + "All filters (%(filterCount)d)": ["Vsi filtri (%(filterCount)d)"], + "No filters are currently added": ["Trenutno ni dodanih filtrov"], + "Click the button above to add a filter to the dashboard": [ + "S klikom gumba zgoraj dodate filter na nadzorno ploščo" ], - "Additional metadata": ["Dodatni metapodatki"], - "Metadata": ["Metapodatki"], - "Select any columns for metadata inspection": [ - "Izberite poljubne stolpce za pregled metapodatkov" + "Filter sets (%(filterSetCount)d)": [ + "Nastavljeni filtri (%(filterSetCount)d)" ], - "Entity ID": ["ID entitete"], - "e.g., a \"user id\" column": ["t.j. stolpec \"id uporabnika\""], - "Max Events": ["Max. dogodkov"], - "The maximum number of events to return, equivalent to the number of rows": [ - "Največje število dogodkov, ki bodo vrnjeni - enako številu vrstic" + "Apply filters": ["Uporabi filtre"], + "Clear all": ["Počisti vse"], + "Filters out of scope (%d)": ["Filtri izven dosega (%d)"], + "Check configuration": ["Preveri nastavitve"], + "Cannot load filter": ["Filtra ni mogoče naložiti"], + "Editing filter set:": ["Urejanje seta filtrov:"], + "Filter set with this name already exists": [ + "Set filtrov z enakim imenom že obstaja" ], - "Compares the lengths of time different activities take in a shared timeline view.": [ - "Primerja dolžine časovno različnih aktivnosti na skupni časovnici." + "Filter set already exists": ["Set filtrov že obstaja"], + "This filter set is identical to: \"%s\"": [ + "Ta set filtrov je enak: \"%s\"" ], - "Event Flow": ["Potek dogodkov"], - "Progressive": ["Progresivno"], - "Link Length": ["Dolžina povezave"], - "Link length in the force layout": ["Dolžina povezave v postavitvi sil"], - "Charge": ["Naboj"], - "Charge in the force layout": ["Naboj v postavitvi sil"], - "Source / Target": ["Izhodišče/Cilj"], - "Choose a source and a target": ["Izberite izhodišče in cilj"], - "Force-directed Graph": ["Graf usmerjenih sil"], - "Axis ascending": ["Naraščajoča os"], - "Axis descending": ["Padajoča os"], - "Metric ascending": ["Naraščajoča mera"], - "Metric descending": ["Padajoča mera"], - "Heatmap Options": ["Možnosti toplotnega prikaza"], - "XScale Interval": ["Interval X-osi"], - "Number of steps to take between ticks when displaying the X scale": [ - "Število korakov med oznakami pri prikazu X-osi" + "Remove invalid filters": ["Odstrani neveljavne filtre"], + "Rebuild": ["Obnovi"], + "Filters (%d)": ["Filtri (%d)"], + "This filter doesn't exist in dashboard. It will not be applied.": [ + "Ta filter ne obstaja v nadzorni plošči in ne bo uveljavljen." ], - "YScale Interval": ["Interval Y-osi"], - "Number of steps to take between ticks when displaying the Y scale": [ - "Število korakov med oznakami pri prikazu Y-osi" + "Filter metadata changed in dashboard. It will not be applied.": [ + "Metapodatki filtra so se spremenili v nadzorni plošči. Ne bo uveljavljen." ], - "Rendering": ["Izris"], - "image-rendering CSS attribute of the canvas object that defines how the browser scales up the image": [ - "atribut CSS za izris objekta platna, ki določa, kako brskalnik poveča sliko" + "Please filter set name": ["Vnesite ime seta filtrov"], + "Create": ["Ustvari"], + "Create new filter set": ["Ustvarite nov set filtrov"], + "New filter set": ["Nov set filtrov"], + "Please apply filter changes": ["Potrdite spremembe filtra"], + "Unknown value": ["Neznana vrednost"], + "Add/Edit Filters": ["Dodaj/uredi filter"], + "Dependent on": ["Odvisen od"], + "Filter only displays values relevant to selections made in other filters.": [ + "Filter prikazuje samo vrednosti vezane na izbire v drugih filtrih." ], - "Normalize Across": ["Normiraj glede na"], - "Color will be rendered based on a ratio of the cell against the sum of across this criteria": [ - "Barva bo prikazana na osnovi razmerja med celico in vsoto glede na ta kriterij" + "All charts": ["Vsi grafikoni"], + "Scope": ["Doseg"], + "Filter type": ["Tip filtra"], + "Title is required": ["Naslov je obvezen"], + "(Removed)": ["(Odstranjeno)"], + "Undo?": ["Povrni?"], + "Add filters and dividers": ["Dodaj filtre in ločilnike"], + "[untitled]": ["[neimenovana]"], + "Cyclic dependency detected": ["Zaznana krožna odvisnost"], + "Add and edit filters": ["Dodaj in uredi filtre"], + "Column select": ["Izbira stolpca"], + "Select a column": ["Izberite stolpec"], + "No compatible columns found": ["Ni najdenih skladnih stolpcev"], + "Value is required": ["Zahtevana je vrednost"], + "(deleted or invalid type)": ["(izbrisan ali neveljaven tip)"], + "Limit type": ["Tip omejitve"], + "No available filters.": ["Ni razpoložljivih filtrov."], + "Add filter": ["Dodaj filter"], + "Values are dependent on other filters": [ + "Vrednosti so odvisne od drugih filtrov" ], - "Left Margin": ["Levi rob"], - "Left margin, in pixels, allowing for more room for axis labels": [ - "Levi rob, v pikslih, s katerim povečamo prostor za oznake osi" + "Values selected in other filters will affect the filter options to only show relevant values": [ + "Vrednosti izbrane v drugih filtrih bodo vplivale na možnosti filtra" ], - "Bottom Margin": ["Spodnji rob"], - "Bottom margin, in pixels, allowing for more room for axis labels": [ - "Spodnji rob, v pikslih, s katerim povečamo prostor za oznake osi" + "Values dependent on": ["Vrednosti so odvisne od"], + "Scoping": ["Doseg"], + "Filter Configuration": ["Nastavitve filtra"], + "Filter Settings": ["Nastavitve filtra"], + "Select filter": ["Izbirni filter"], + "Value": ["Vrednost"], + "Range filter": ["Filter obdobja"], + "Numerical range": ["Številski obseg"], + "Time filter": ["Časovni filter"], + "Time range": ["Časovno obdobje"], + "Time column": ["Časovni stolpec"], + "Time grain": ["Granulacija časa"], + "Group By": ["Združevanje (Group by)"], + "Group by": ["Združevanje (Group by)"], + "Pre-filter is required": ["Zahtevan je predfilter"], + "Filter name": ["Ime filtra"], + "Name is required": ["Zahtevano je ime"], + "Filter Type": ["Tip filtra"], + "Datasets do not contain a temporal column": [ + "Podatkovni seti ne vsebujejo časovnega stolpca" ], - "Value bounds": ["Meje vrednosti"], - "Hard value bounds applied for color coding. Is only relevant and applied when the normalization is applied against the whole heatmap.": [ - "Mejne vrednosti za barvno lestvico. Upošteva se le, če je normiranje uporabljeno glede na celotni toplotni prikaz." + "Dataset is required": ["Zahtevan je podatkovni set"], + "Pre-filter available values": ["Predfiltriraj razpoložljive vrednosti"], + "Pre-filter": ["Predfilter"], + "Optional time column if time range should apply to another column than the default time column": [ + "Izbirni časovni stolpec se mora nanašati na drug stolpec kot privzeti časovni stolpec" ], - "Sort X Axis": ["Razvrsti X-os"], - "Sort Y Axis": ["Razvrsti Y-os"], - "Show percentage": ["Prikaži procente"], - "Whether to include the percentage in the tooltip": [ - "Če želite prikaz procentov v opisu orodja" + "Sort filter values": ["Razvrsti vrednosti filtra"], + "Sort type": ["Način razvrščanja"], + "Sort ascending": ["Razvrsti naraščajoče"], + "Sort Metric": ["Mera za razvrščanje"], + "If a metric is specified, sorting will be done based on the metric value": [ + "Če je določena mera, bo razvrščanje izvedeno na podlagi vrednosti mere" ], - "Normalized": ["Normiran"], - "Whether to apply a normal distribution based on rank on the color scale": [ - "Če želite uporabiti normalno porazdelitev glede na stopnjo na barvni lestvici" + "Sort metric": ["Mera za razvrščanje"], + "Single Value": ["Ena vrednost"], + "Single value type": ["Tip z eno vrednostjo"], + "Minimum": ["Minimum"], + "Exact": ["Natančno"], + "Maximum": ["Maksimum"], + "Filter has default value": ["Filter ima privzeto vrednost"], + "Default Value": ["Privzeta vrednost"], + "Default value is required": ["Zahtevana je privzeta vrednost"], + "Refresh the default values": ["Osveži privzete vrednosti"], + "Fill all required fields to enable \"Default Value\"": [ + "Izpolnite vsa polja, da omogočite \"Privzeto vrednost\"" ], - "Value Format": ["Oblika zapisa vrednosti"], - "Visualize a related metric across pairs of groups. Heatmaps excel at showcasing the correlation or strength between two groups. Color is used to emphasize the strength of the link between each pair of groups.": [ - "Vizualizacija povezanih mer med pari skupin." + "You have removed this filter.": ["Odstranili ste ta filter."], + "Restore Filter": ["Povrni filter"], + "Column is required": ["Zahtevan je stolpec"], + "Populate \"Default value\" to enable this control": [ + "Izpolnite \"Privzeto vrednost\", da omogočite ta kontrolnik" ], - "Sizes of vehicles": ["Velikosti vozil"], - "Employment and education": ["Zaposlitev in izobrazba"], - "Density": ["Gostota"], - "Predictive": ["Prediktivno"], - "Single Metric": ["Ena mera"], - "count": ["število"], - "cumulative": ["kumulativno"], - "percentile (exclusive)": ["percentil (ekskluzivno)"], - "Select the numeric columns to draw the histogram": [ - "Izberite numerične stolpce za izris histograma" + "Default value set automatically when \"Select first filter value by default\" is checked": [ + "Privzeta vrednost je samodejno izbrana, če je izbrano \"Prvi element je izbran kot privzet\"" ], - "No of Bins": ["Št. razdelkov"], - "Select the number of bins for the histogram": [ - "Izberite število razdelkov za histogram" + "Default value must be set when \"Filter value is required\" is checked": [ + "Privzeta vrednost mora biti določena, če je izbrano \"Vrednost filtra obvezna\"" ], - "X Axis Label": ["Naslov X osi"], - "Y Axis Label": ["Naslov Y osi"], - "Whether to normalize the histogram": ["Če želite normirati histogram"], - "Cumulative": ["Kumulativno"], - "Whether to make the histogram cumulative": [ - "Če želite kumulativni histogram" + "Default value must be set when \"Filter has default value\" is checked": [ + "Privzeta vrednost mora biti določena, če je izbrano \"Filter ima privzeto vrednost\"" ], - "Distribution": ["Porazdelitev"], - "Take your data points, and group them into \"bins\" to see where the densest areas of information lie": [ - "Vzame podatkovne točke in jih razporedi v razdelke, kjer se vidi območja z največjo gostoto informacij" + "Apply to all panels": ["Uporabi za vse panele"], + "Apply to specific panels": ["Uporabi za določene panele"], + "Only selected panels will be affected by this filter": [ + "Ta filter bo vplival le na izbrane panele" ], - "Population age data": ["Podatki starosti populacije"], - "Sort Descending": ["Razvrsti padajoče"], - "Series Height": ["Višina serije"], - "Pixel height of each series": ["Višina vsake serije v pikslih"], - "Value Domain": ["Domena vrednosti"], - "series: Treat each series independently; overall: All series use the same scale; change: Show changes compared to the first data point in each series": [ - "serije: Obravnavaj vsako podatkovno serijo neodvisno; skupno: Vse vrste uporabljajo enako skalo; razlika: Pokaži razlike glede na prvo točko vsake serije" + "All panels with this column will be affected by this filter": [ + "Ta filter bo vplival na vse panele s tem stolpcem" ], - "Compares how a metric changes over time between different groups. Each group is mapped to a row and change over time is visualized bar lengths and color.": [ - "Primerja kako se mera spreminja s časom med različnimi skupinami. Vsaka skupina predstavlja eno vrstico, časovne spremembe pa so prikazane z dolžino stolpcev in barvami." + "All panels": ["Vsi paneli"], + "This chart might be incompatible with the filter (datasets don't match)": [ + "Ta grafikon je lahko nekompatibilen s filtrom (podatkovni seti se ne ujemajo)" ], - "Horizon Chart": ["Horizontni grafikon"], - "Longitude": ["Dolžina"], - "Column containing longitude data": [ - "Stolpec s podatki zemljepisne dolžine" + "Keep editing": ["Nadaljuj z urejanjem"], + "Yes, cancel": ["Da, prekini"], + "There are unsaved changes.": ["Imate neshranjene spremembe."], + "Are you sure you want to cancel?": ["Ali želite prekiniti?"], + "Error loading chart datasources. Filters may not work correctly.": [ + "Napaka pri nalaganju podatkovnih virov grafikona. Filtri lahko ne delujejo pravilno." ], - "Latitude": ["Širina"], - "Column containing latitude data": [ - "Stolpec s podatki zemljepisne širine" + "Transparent": ["Prozorno"], + "White": ["Belo"], + "All filters": ["Vsi filtri"], + "Medium": ["Srednje"], + "Tab title": ["Naslov zavihka"], + "This session has encountered an interruption, and some controls may not work as intended. If you are the developer of this app, please check that the guest token is being generated correctly.": [ + "Ta seja je bila prekinjena in nekateri kontrolniki mogoče ne delujejo kot bi morali. Če ste razvijalec te aplikacije, preverite, da je žeton za gosta pravilno generiran." ], - "Clustering Radius": ["Radij gručenja"], - "The radius (in pixels) the algorithm uses to define a cluster. Choose 0 to turn off clustering, but beware that a large number of points (>1000) will cause lag.": [ - "Radij (v pikslih), s katerim algoritem definira gručo. Izberite 0 za izklop gručenja - veliko število točk (>1000) bo povzročilo upočasnitev." + "Time granularity": ["Granulacija časa"], + "Visualization type": ["Tip vizualizacije"], + "Fixed color": ["Izbrana barva"], + "Right axis metric": ["Mera desne osi"], + "Linear color scheme": ["Linearna barvna shema"], + "Color metric": ["P"], + "One or many controls to pivot as columns": [ + "En ali več kontrolnikov za stolpčno vrtenje" ], - "Points": ["Točke"], - "Point Radius": ["Radij točk"], - "The radius of individual points (ones that are not in a cluster). Either a numerical column or `Auto`, which scales the point based on the largest cluster": [ - "Radij posameznih točk (tistih, ki niso v gruči). Numerični stolpec ali `Auto` (skalira točke na osnovi največje gruče)" + "Bubble size": ["Velikost mehurčka"], + "When `Calculation type` is set to \"Percentage change\", the Y Axis Format is forced to `.1%`": [ + "Če je `Vrsta izračuna` nastavljena na \"Procentualna sprememba\", bo oblika Y-osi vsiljena na `.1%`" ], - "Point Radius Unit": ["Enota radija točk"], - "The unit of measure for the specified point radius": [ - "Enota merila za definiran radij točk" + "Color scheme": ["Barvna shema"], + "An error occurred while starring this chart": [ + "Pri ocenjevanju grafikona je prišlo do napake" ], - "Labelling": ["Oznake"], - "label": ["oznaka"], - "`count` is COUNT(*) if a group by is used. Numerical columns will be aggregated with the aggregator. Non-numerical columns will be used to label points. Leave empty to get a count of points in each cluster.": [ - "`število` je COUNT(*), če je uporabljeno združevanje (group by). Numerični stolpci bodo agregirani z agregatorjem. Ne-numerični stolpci, bodo uporabljeni za oznake točk. Pustite prazno, da dobite število točk v posamezni gruči." + "GROUP BY": ["GROUP BY"], + "Use this section if you want a query that aggregates": [ + "Ta sklop uporabite če želite poizvedbo za agregacijo" ], - "Cluster label aggregator": ["Agregator za oznako gruče"], - "Aggregate function applied to the list of points in each cluster to produce the cluster label.": [ - "Agregacijska funkcija za seznam točk v vsaki gruči, s katero se ustvari oznaka gruče." + "NOT GROUPED BY": ["NOT GROUPED BY"], + "Use this section if you want to query atomic rows": [ + "Ta sklop uporabite, če želite poizvedbo za posamezne vrstice" ], - "Visual Tweaks": ["Nastavitve izgleda"], - "Live render": ["Sprotni izris"], - "Points and clusters will update as the viewport is being changed": [ - "Točke in gruče se bodo posodabljale, če se bo spremenil pogled" + "Keep control settings?": ["Obdržim nastavitve kontrolnika?"], + "You've changed datasets. Any controls with data (columns, metrics) that match this new dataset have been retained.": [ + "Spremenili ste podatkovne sete. Vsi kontrolniki nad podatki (stolpci, mere), ki se ujemajo z novim podatkovnim setom, se bodo ohranili." ], - "Map Style": ["Slog zemljevida"], - "Base layer map style": ["Slog osnovnega sloja zemljevida"], - "Opacity of all clusters, points, and labels. Between 0 and 1.": [ - "Prosojnost vseh gruč, točk in oznak (vrednost med 0 in 1)." + "Continue": ["Nadaljuj"], + "Clear form": ["Počisti polja"], + "No form settings were maintained": ["Nastavitve forme se niso ohranile"], + "We were unable to carry over any controls when switching to this new dataset.": [ + "Prenos kontrolnikov pri preklopu na nov podatkovni set ni bil uspešen." ], - "RGB Color": ["RGB barva"], - "The color for points and clusters in RGB": [ - "Barva točk in gruč v RGB zapisu" + "Customize": ["Prilagodi"], + "Error": ["Napaka"], + "Generating link, please wait..": [ + "Ustvarjam povezavo, prosim počakajte..." ], - "Viewport": ["Pogled"], - "Default longitude": ["Privzeta dolžina"], - "Longitude of default viewport": ["Dolžina privzetega pogleda"], - "Default latitude": ["Privzeta širina"], - "Latitude of default viewport": ["Širina privzetega pogleda"], - "Zoom": ["Povečava"], - "Zoom level of the map": ["Stopnja povečave zemljevida"], - "One or many controls to group by. If grouping, latitude and longitude columns must be present.": [ - "Eden ali več kontrolnikov za združevanje. Pri združevanju morata biti prisotna stolpca širine in dolžine." + "Chart height": ["Višina grafikona"], + "Chart width": ["Širina grafikona"], + "Required control values have been removed": [ + "Zahtevane kontrolne vrednosti so bile odstranjene" + ], + "Your chart is not up to date": ["Grafikon ni aktualen"], + "You updated the values in the control panel, but the chart was not updated automatically. Run the query by clicking on the \"Update chart\" button or": [ + "Posodobili ste vrednosti v kontrolni plošči, vendar se grafikon ni samodejno posodobil. Zaženite poizvedbo z gumbom \"Posodobi grafikon\" ali" + ], + "**Select** a dashboard OR **create** a new one": [ + "**Izberite** nadzorno ploščo ALI **ustvarite** novo" + ], + "Please enter a chart name": ["Vnesite ime grafikona"], + "Save chart": ["Shrani grafikon"], + "Save & go to new dashboard": ["Shrani in pojdi na novo nadzorno ploščo"], + "Save & go to dashboard": ["Shrani in pojdi na nadzorno ploščo"], + "Save as new chart": ["Shrani kot nov grafikon"], + "Save to new dashboard": ["Shrani v novo nadzorno ploščo"], + "Save (Overwrite)": ["Shrani (prepiši)"], + "Save as...": ["Shrani kot ..."], + "Chart name": ["Ime grafikona"], + "Add to dashboard": ["Dodaj na nadzorno ploščo"], + "Select a dashboard": ["Izberite nadzorno ploščo"], + "Copy": ["Kopiraj"], + "Formatted date": ["Oblikovan datum"], + "Column Formatting": ["Oblikovanje stolpca"], + "N/A": ["N/A"], + "Collapse data panel": ["Skrij podatkovni panel"], + "Expand data panel": ["Razširi podatkovni panel"], + "Results %s": ["Rezultati %s"], + "Samples": ["Vzorci"], + "No samples were returned for this dataset": [ + "Za podatkovni set ni vrnjenih vzorcev" + ], + "No results": ["Ni rezultatov"], + "Search Metrics & Columns": ["Iskanje mer in stolpcev"], + "Create a dataset": ["Ustvarite podatkovni set"], + " to edit or add columns and metrics.": [ + " za urejanje ali dodajanje stolpcev in mer." ], - "Light mode": ["Svetli način"], - "Dark mode": ["Temni način"], - "MapBox": ["MapBox"], - "Scatter": ["Raztreseni"], - "Transformable": ["Prilagodljiv"], - "Significance Level": ["Stopnja značilnosti"], - "Threshold alpha level for determining significance": [ - "Mejna vrednost alfa za določanje značilnosti" + "Showing %s of %s": ["Prikazanih %s od %s"], + "Show less...": ["Prikaži manj..."], + "Show all...": ["Prikaži vse..."], + "Show Less...": ["Prikaži manj..."], + "Add the name of the chart": ["Dodajte naslov grafikona"], + "Chart title": ["Naslov grafikona"], + "Add required control values to save chart": [ + "Dodaj potrebne parametre za shranjenje grafikona" ], - "p-value precision": ["točnost p-vrednosti"], - "Number of decimal places with which to display p-values": [ - "Število decimalnih mest za prikaz p-vrednosti" + "Controls labeled ": ["Kontrolniki imenovani "], + "Control labeled ": ["Nastavitev "], + "Open Datasource tab": ["Odpri zavihek s podatkovnim virom"], + "Original": ["Izvoren"], + "Pivoted": ["Vrtilni"], + "You do not have permission to edit this chart": [ + "Nimate dovoljenja za urejanje tega grafikona" ], - "Lift percent precision": ["Točnost procentualnega dviga"], - "Number of decimal places with which to display lift values": [ - "Število decimalnih mest za prikaz vrednosti dviga" + "Chart properties updated": ["Lastnosti grafikona posodobljene"], + "This chart is managed externally, and can't be edited in Superset": [ + "Ta grafikon se ne ureja znotraj Superseta" ], - "Table that visualizes paired t-tests, which are used to understand statistical differences between groups.": [ - "Tabela, ki prikazuje uparjene t-teste, ki se uporabljajo za prikaz statističnih razlik med skupinami." + "The description can be displayed as widget headers in the dashboard view. Supports markdown.": [ + "Opis je lahko prikazan kot glava gradnika in pogledu nadzorne plošče. Podpira markdown." ], - "Paired t-test Table": ["Tabela t-testa za odvisne vzorce"], - "Statistical": ["Statistično"], - "Options": ["Možnosti"], - "Data Table": ["Tabela podatkov"], - "Whether to display the interactive data table": [ - "Če želite prikaz interaktivne podatkovne tabele" + "Person or group that has certified this chart.": [ + "Oseba ali skupina, ki je certificirala ta grafikon." ], - "Include Series": ["Vključi serijo"], - "Include series name as an axis": [ - "Vključi ime podatkovne serije v naslov osi" + "Configuration": ["Nastavitve"], + "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the dataset's timeout if undefined.": [ + "Časovna veljavnost (v sekundah) predpomnjenja za ta grafikon. Če ni definirana, je uporabljena vrednost za podatkovni set." ], - "Ranking": ["Rangiranje"], - "Plots the individual metrics for each row in the data vertically and links them together as a line. This chart is useful for comparing multiple metrics across all of the samples or rows in the data.": [ - "Izriše posamezne mere za vsako vrstico podatkov navpično in jih med seboj poveže kot črto. Grafikon je uporaben za primerjavo več mer med vsemi vzorci ali vrsticami podatkov." + "A list of users who can alter the chart. Searchable by name or username.": [ + "Seznam uporabnikov, ki lahko spreminjajo ta grafikon. Možno je iskanje po imenu ali uporabniškem imenu." ], - "Coordinates": ["Koordinate"], - "Directional": ["Usmerjeni"], - "Time Series Options": ["Možnosti časovne vrste"], - "Not Time Series": ["Ni časovna vrsta"], - "Ignore time": ["Ne upoštevaj časa"], - "Time Series": ["Časovna vrsta"], - "Standard time series": ["Standardna časovna vrsta"], - "Aggregate Mean": ["Agregirano povprečje"], - "Mean of values over specified period": [ - "Povprečna vrednost v dani periodi" + "%s row": ["%s vrstica"], + "Limit reached": ["Omejitev dosežena"], + "Create chart": ["Ustvari grafikon"], + "Update chart": ["Posodobi grafikon"], + "Invalid lat/long configuration.": [ + "Neveljavna nastavitev zemljepisne dolžine/širine." ], - "Aggregate Sum": ["Agregirana vsota"], - "Sum of values over specified period": ["Vsota vrednosti v dani periodi"], - "Difference": ["Razlika"], - "Metric change in value from `since` to `until`": [ - "Sprememba mere od vrednosti \"OD\" do \"DO\"" + "Reverse lat/long ": ["Zamenjaj zemljepisno dolžino/širino "], + "Longitude & Latitude columns": ["Stolpci zemljepisne dolžine in širine"], + "Delimited long & lat single column": [ + "En stolpec z ločenima zemljepisno dolžino in širino" ], - "Percent Change": ["Procentualna sprememba"], - "Metric percent change in value from `since` to `until`": [ - "Procentualna sprememba mere od vrednosti \"OD\" do \"DO\"" + "Multiple formats accepted, look the geopy.points Python library for more details": [ + "Sprejema različne zapise - podrobnosti najdete v Pythonovi knjižnici geopy.points" ], - "Factor": ["Faktor"], - "Metric factor change from `since` to `until`": [ - "Sprememba faktorja mere od vrednosti \"OD\" do \"DO\"" + "Geohash": ["Geohash"], + "textarea": ["področje besedila"], + "in modal": ["v modalnem oknu"], + "Sorry, An error occurred": ["Prišlo je do napake"], + "Failed to verify select options: %s": [ + "Preverjanje možnosti izbire ni uspelo: %s" ], - "Advanced Analytics": ["Napredna analitika"], - "Use the Advanced Analytics options below": [ - "Uporabite spodnje možnosti napredne analitike" + "No annotation layers": ["Ni slojev z oznakami"], + "Add an annotation layer": ["Dodaj sloj z oznakami"], + "Use another existing chart as a source for annotations and overlays.\n Your chart must be one of these visualization types: [%s]": [ + "Uporabite enega izmed obstoječih grafikonov kot vir oznak.\n Grafikon mora biti naslednjega tipa: [%s]" ], - "Settings for time series": ["Nastavitve časovne vrste"], - "Date Time Format": ["Oblika zapisa Datum-Časa"], - "Partition Limit": ["Omejitev particij"], - "The maximum number of subdivisions of each group; lower values are pruned first": [ - "Največje število podrazdelkov posamezne skupine; nižje vrednosti so zanemarjene prve" + "Annotation layer value": ["Vrednost sloja z oznakami"], + "Annotation Slice Configuration": ["Nastavitve rezine z oznakami"], + "This section allows you to configure how to use the slice\n to generate annotations.": [ + "V tem sklopu lahko nastavite način uporabe rezine\n za ustvarjanje oznak." ], - "Partition Threshold": ["Prag particije"], - "Partitions whose height to parent height proportions are below this value are pruned": [ - "Particije z nižjim razmerjem med njihovo višino in dolžino starša so zanemarjene" + "Annotation layer time column": ["Časovni stolpec sloja z oznakami"], + "Interval start column": ["Stolpec začetka intervala"], + "Event time column": ["Stolpec časa dogodka"], + "This column must contain date/time information.": [ + "Ta stolpec mora vsebovati informacijo o datumu/času." ], - "Log Scale": ["Logaritemska skala"], - "Use a log scale": ["Uporabi logaritemsko skalo"], - "Equal Date Sizes": ["Enaki datumi"], - "Check to force date partitions to have the same height": [ - "Če želite, da imajo datumske particije enako višino" + "Annotation layer interval end": ["Konec intervala sloja z oznakami"], + "Interval End column": ["Stolpec konca intervala"], + "Annotation layer title column": ["Stolpec z naslovom sloja z oznakami"], + "Title Column": ["Stolpec z naslovi"], + "Pick a title for you annotation.": ["Izberite naslov za oznako."], + "Annotation layer description columns": [ + "Stolpci z opisi slojev z oznakami" ], - "Rich Tooltip": ["Podroben opis orodja"], - "The rich tooltip shows a list of all series for that point in time": [ - "Podroben opis orodja prikaže seznam vseh podatkovnih serij za posamezno časovno točko" + "Description Columns": ["Stolpci z opisi"], + "Pick one or more columns that should be shown in the annotation. If you don't select a column all of them will be shown.": [ + "Izberite enega ali več stolpcev, ki bodo prikazani v oznakah. Če ne izberete stolpca, bodo prikazani vsi." ], - "Rolling Window": ["Drseče okno"], - "Rolling Function": ["Drseča funkcija"], - "Min Periods": ["Min. št. period"], - "Time Comparison": ["Časovna primerjava"], - "Time Shift": ["Časovni zamik"], - "Python Functions": ["Pythonove funkcije"], - "Part of a Whole": ["Del celote"], - "Compare the same summarized metric across multiple groups.": [ - "Primerja isto mero med različnimi skupinami." + "Display configuration": ["Prikaži nastavitve"], + "Configure your how you overlay is displayed here.": [ + "Nastavite kako se tukaj prikazuje vrhnja plast." ], - "Partition Chart": ["Grafikon razdelkov"], - "Categorical": ["Kategorični"], - "Pivot Options": ["Vrtilne možnosti"], - "Aggregation function": ["Agregacijska funkcija"], - "Aggregate function to apply when pivoting and computing the total rows and columns": [ - "Agregacijska funkcija za vrtenje in izračun vseh vrstic in stolpcev" + "Annotation layer stroke": ["Obroba sloja z oznakami"], + "Style": ["Slog"], + "Annotation layer opacity": ["Prosojnost sloja z oznakami"], + "Color": ["Barva"], + "Layer configuration": ["Nastavitve sloja"], + "Configure the basics of your Annotation Layer.": [ + "Osnovne nastavitve sloja z oznakami." ], - "Show totals": ["Pokaži vsote"], - "Display total row/column": ["Pokaži vsote vrstic/stolpcev"], - "Combine Metrics": ["Združuj mere"], - "Display metrics side by side within each column, as opposed to each column being displayed side by side for each metric.": [ - "Prikazuj mere eno ob drugi ob vsakem stolpcu, drugače je vsak stolpec prikazan en ob drugem za vsako mero." + "Mandatory": ["Obvezno"], + "Hide layer": ["Skrij sloj"], + "Show label": ["Pokaži oznako"], + "Whether to always show the annotation label": [ + "Če želite vedno prikazati naslov oznake" ], - "Transpose Pivot": ["Transponirano vrtenje"], - "Swap Groups and Columns": ["Zamenjaj Skupine in Stolpce"], - "Date format": ["Oblika zapisa datuma"], - "Used to summarize a set of data by grouping together multiple statistics along two axes. Examples: Sales numbers by region and month, tasks by status and assignee, active users by age and location.\r\n\r\n This chart is being deprecated and we recommend checking out Pivot Table V2 instead!": [ - "Uporablja se za predstavitev podatkov z združevanjem različnih statistik na dveh oseh. Npr. Prodaja po regijah in mesecih, Naloge po statusih in izvajalcih, aktivni uporabniki po starosti in lokaciji.\r\n\r\n Ta grafikon se opušča. Priporočamo uporabo Vrtilne tabele V2!" + "Annotation layer type": ["Tip sloja z oznakami"], + "Choose the annotation layer type": ["Izberite tip sloja z oznakami"], + "Annotation source type": ["Tip vira oznak"], + "Choose the source of your annotations": ["Izberite vir svojih oznak"], + "Annotation source": ["Vir oznak"], + "Remove": ["Odstrani"], + "Edit annotation layer": ["Uredi sloj z oznakami"], + "Add annotation layer": ["Dodaj sloj z oznakami"], + "Empty collection": ["Prazen izbor"], + "Add an item": ["Dodaj element"], + "Remove item": ["Odstrani element"], + "The color scheme is determined by the related dashboard.\n Edit the color scheme in the dashboard properties.": [ + "Barvna shema je določena s povezano nadzorno ploščo.\n Barvno shemo uredite v nastavitvah nadzorne plošče." ], - "Use Area Proportions": ["Uporabi razmerje površin"], - "Check if the Rose Chart should use segment area instead of segment radius for proportioning": [ - "Če želite, da grafikon \"Rose\" uporablja površino segmenta namesto radija za proporcioniranje" + "This color scheme is being overriden by custom label colors.\n Check the JSON metadata in the Advanced settings": [ + "Barvna shema je bila preglasovana z barvo oznake po meri.\n Preverite JSON metapodatke v naprednih nastavitvah" ], - "A polar coordinate chart where the circle is broken into wedges of equal angle, and the value represented by any wedge is illustrated by its area, rather than its radius or sweep angle.": [ - "Grafikon s polarnimi koordinatami, kjer je krog razdeljen na enakokotne izseke, vrednosti pa so ponazorjene s ploščino izseka (namesto polmera ali kota)." + "Dashboard scheme": ["Shema nadzorne plošče"], + "Select color scheme": ["Izberite barvno shemo"], + "Select scheme": ["Izberite shemo"], + "Edit formatter": ["Uredi oblikovanje"], + "Add new formatter": ["Dodaj novo oblikovanje"], + "Add new color formatter": ["Dodaj novo oblikovanje barve"], + "green": ["zelena"], + "yellow": ["rumena"], + "red": ["rdeča"], + "This value should be smaller than the right target value": [ + "Ta vrednost mora biti manjša od desne ciljne vrednosti" ], - "Nightingale Rose Chart": ["Nightingale Rose grafikon"], - "Multi-Layers": ["Večplastni"], - "Limiting rows may result in incomplete data and misleading charts. Consider filtering or grouping source/target names instead.": [ - "Omejitev vrstic lahko povzroči nepopolne podatke in zavajajoč grafikon. Premislite o uporabi filtriranja ali združevanja imen izvorov/ciljev." + "This value should be greater than the left target value": [ + "Ta vrednost mora biti večja od leve ciljne vrednosti" ], - "Visualizes the flow of different group's values through different stages of a system. New stages in the pipeline are visualized as nodes or layers. The thickness of the bars or edges represent the metric being visualized.": [ - "Prikaže potek vrednosti različnih skupin na različnih nivojih sistema. Novi nivoji so prikazani kot točke ali plasti. Debelina stolpcev ali povezav predstavlja prikazano mero." + "Required": ["Obvezno"], + "Operator": ["Operator"], + "Left value": ["Leva vrednost"], + "Right value": ["Desna vrednost"], + "Target value": ["Ciljna vrednost"], + "Select column": ["Izberite stolpec"], + "Edit dataset": ["Uredi podatkovni set"], + "You must be a dataset owner in order to edit. Please reach out to a dataset owner to request modifications or edit access.": [ + "Za urejanje morate biti lastnik podatkovnega seta. Za dostop do urejanja kontaktirajte lastnika podatkovnega seta." ], - "Demographics": ["Demografija"], - "Survey Responses": ["Rezultati anket"], - "Sankey Diagram": ["Sankey grafikon"], - "Sankey Diagram with Loops": ["Sankey grafikon z zankami"], - "Primary Metric": ["Primarna mera"], - "The primary metric is used to define the arc segment sizes": [ - "Primarna mera določa velikost lokov segmentov" + "View in SQL Lab": ["Ogled v SQL laboratoriju"], + "Query preview": ["Predogled poizvedbe"], + "Save as dataset": ["Shrani kot podatkovni set"], + "More dataset related options": ["Več nastavitev za podatkovni set"], + "Missing URL parameters": ["Manjkajo parametri URL-ja"], + "The URL is missing the dataset_id or slice_id parameters.": [ + "V URL-ju manjkata parametra dataset_id ali slice_id." ], - "Secondary Metric": ["Sekundarna mera"], - "[optional] this secondary metric is used to define the color as a ratio against the primary metric. When omitted, the color is categorical and based on labels": [ - "[opcijsko] sekundarna mera določa barvo kot razmerje do primarne mere. Če je izpuščena, je barva določena kategorično na podlagi oznak" + "The dataset linked to this chart may have been deleted.": [ + "Podatkovni set, povezan s tem grafikonom, je bil izbrisan." ], - "When only a primary metric is provided, a categorical color scale is used.": [ - "Če je podana samo primarna metrika, je uporabljena kategorična barvna skala." + "RANGE TYPE": ["TIP OBDOBJA"], + "Actual time range": ["Dejansko časovno obdobje"], + "CANCEL": ["PREKINI"], + "APPLY": ["UPORABI"], + "Edit time range": ["Uredi časovno obdobje"], + "Configure Advanced Time Range ": ["Nastavi napredno časovno obdobje "], + "START (INCLUSIVE)": ["ZAČETEK (VKLJUČEN)"], + "Start date included in time range": [ + "Začetni datum je vključen v časovno obdobje" ], - "When a secondary metric is provided, a linear color scale is used.": [ - "Če je podana sekundarna metrika, je uporabljena linearna barvna skala." + "END (EXCLUSIVE)": ["KONEC (NI VKLJUČEN)"], + "End date excluded from time range": [ + "Končni datum ni vključen v časovno obdobje" ], - "Hierarchy": ["Hierarhija"], - "This defines the level of the hierarchy": ["Določa stopnjo hierarhije"], - "Uses circles to visualize the flow of data through different stages of a system. Hover over individual paths in the visualization to understand the stages a value took. Useful for multi-stage, multi-group visualizing funnels and pipelines.": [ - "S pomočjo krogov prikaže potek podatkov na različnih nivojih sistema. S premikom kurzorja prikaže vrednosti na posameznem nivoju. Uporabno za večnivojsko, večskupinsko vizualizacijo." + "Configure Time Range: Previous...": [ + "Nastavi časovno obdobje: Prejšnji ..." ], - "Sunburst Chart": ["Večnivojski tortni grafikon"], - "Multi-Levels": ["Večplastni"], - "Time Series Columns": ["Stolpci s časovnimi vrstami"], - "Compare multiple time series charts (as sparklines) and related metrics quickly. ": [ - "Hitra primerjava več grafikonov časovnih vrst (sparkline način) in povezanih mer. " + "Configure Time Range: Last...": ["Nastavi časovno obdobje: Zadnji ..."], + "Configure custom time range": ["Nastavi prilagojeno časovno obdobje"], + "Relative quantity": ["Relativne vrednosti"], + "Relative period": ["Relativno obdobje"], + "Anchor to": ["Sidraj na"], + "NOW": ["ZDAJ"], + "Date/Time": ["Datum/Čas"], + "Return to specific datetime.": ["Vrne določen datum-čas."], + "Syntax": ["Sintaksa"], + "Example": ["Primer"], + "Moves the given set of dates by a specified interval.": [ + "Premakne dani nabor datumov za definirano obdobje." ], - "Ratio": ["Razmerje"], - "Target aspect ratio for treemap tiles.": [ - "Ciljno razmerje za razdelke drevesnega grafikona." + "Truncates the specified date to the accuracy specified by the date unit.": [ + "Zaokroži določen datum, glede na natančnost, definirano s časovno enoto." + ], + "Get the last date by the date unit.": [ + "Pridobi zadnji datum glede na časovno enoto." + ], + "Get the specify date for the holiday": ["Določi datum praznika"], + "Last": ["Zadnji"], + "Previous": ["Prejšnji"], + "Custom": ["Prilagojen"], + "last day": ["zadnji dan"], + "last week": ["zadnji teden"], + "last month": ["zadnji mesec"], + "last quarter": ["zadnje četrletje"], + "last year": ["zadnje leto"], + "previous calendar week": ["prejšnji koledarski teden"], + "previous calendar month": ["prejšnji koledarski mesec"], + "previous calendar year": ["prejšnje koledarsko leto"], + "Seconds %s": ["Sekunde %s"], + "Minutes %s": ["Minute %s"], + "Hours %s": ["Ure %s"], + "Days %s": ["Dnevi %s"], + "Weeks %s": ["Tedni %s"], + "Months %s": ["Meseci %s"], + "Quarters %s": ["Četrtletja %s"], + "Years %s": ["Leta %s"], + "Before": ["PRED"], + "After": ["PO"], + "Specific Date/Time": ["Fiksen Datum/Čas"], + "Relative Date/Time": ["Relativen Datum/Čas"], + "Now": ["Zdaj"], + "Midnight": ["Polnoč"], + "Saved expressions": ["Shranjeni izrazi"], + "Saved": ["Shranjeno"], + "%s column(s)": ["Stolpci: %s"], + "No temporal columns found": ["Ni najdenih časovnih stolpcev"], + "No saved expressions found": ["Shranjeni izrazi niso najdeni"], + "Add calculated temporal columns to dataset in \"Edit datasource\" modal": [ + "Dodaj izračunan časovni stolpec v podatkovni set v oknu \"Uredi podatkovni vir\"" ], - "Shows the composition of a dataset by segmenting a given rectangle as smaller rectangles with areas proportional to their value or contribution to the whole. Those rectangles may also, in turn, be further segmented hierarchically.": [ - "Prikaže zgradbo podatkovnega seta na podlagi segmentacije danega pravokotnika na manjše pravokotnike, pri čemer je ploščina sorazmerna vrednostim oz. deležem. Pravokotniki se lahko dodatno hierarhično segmentirajo." + "Add calculated columns to dataset in \"Edit datasource\" modal": [ + "Dodaj izračunan stolpec v podatkovni set v oknu \"Uredi podatkovni vir\"" ], - "Country Field Type": ["Tip polja za države"], - "The country code standard that Superset should expect to find in the [country] column": [ - "Standard za oznake držav, ki bodo podane v stolpcu z državami" + "Simple": ["Preprosto"], + "Mark a column as temporal in \"Edit datasource\" modal": [ + "Označite stolpec kot časoven preko okna \"Uredi podatkovni vir\"" ], - "Show Bubbles": ["Prikaži mehurčke"], - "Whether to display bubbles on top of countries": [ - "Če želite prikaz mehurčkov nad državami" + "Custom SQL": ["Prilagojen SQL"], + "My column": ["Moj stolpec"], + "Drop a column here or click": ["Spustite stolpec sem ali kliknite"], + "Drop column here": ["Spustite stolpec sem"], + "Click to edit label": ["Kliknite za urejanje oznake"], + "Drop columns/metrics here or click": [ + "Spustite stolpce/mere sem ali kliknite" ], - "Max Bubble Size": ["Max. velikost mehurčka"], - "Country Column": ["Stolpec z državami"], - "3 letter code of the country": ["Tričrkovna oznaka države"], - "Metric for Color": ["Mera za barvo"], - "Metric that defines the color of the country": [ - "Mera, ki določa barvo države" + "Drop columns or metrics here": ["Spustite stolpce ali mere sem"], + "Drop a column/metric here or click": [ + "Spustite stolpec/mero sem ali kliknite" ], - "Metric that defines the size of the bubble": [ - "Mera, ki določa velikost mehurčka" + "Drop column or metric here": ["Spustite stolpec ali mero sem"], + "Drop columns here": ["Spustite stolpce sem"], + "\n This filter was inherited from the dashboard's context.\n It won't be saved when saving the chart.\n ": [ + "\n Ta filter izvira iz konteksta nadzorne plošče.\n Pri shranjevanju grafikona se ne bo shranil.\n " ], - "Bubble Color": ["Barva mehurčka"], - "Country Color Scheme": ["Barvna shema držav"], - "A map of the world, that can indicate values in different countries.": [ - "Zemljevid sveta, ki lahko prikazuje vrednosti po državah." + "Default": ["Privzeto"], + "(optional) default value for the filter, when using the multiple option, you can use a semicolon-delimited list of options.": [ + "(opcijsko) privzeta vrednost za filter, če uporabite opcijo izbire večih , lahko uporabite seznam nastavitev ločen s podpičji." ], - "Multi-Dimensions": ["Večdimenzionalni"], - "Big Number Font Size": ["Velikost pisave Velike številke"], - "Tiny": ["Drobna"], - "Normal": ["Normalna"], - "Huge": ["Ogromna"], - "Subheader Font Size": ["Velikost pisave podnaslova"], - "N/A": ["N/A"], - "Last available value seen on %s": [ - "Zadnja razpoložljiva vrednost na %s" + "Metric to sort the results by": ["Mera za razvrščanje rezultatov"], + "Check for sorting ascending": ["Označi za naraščajoče razvrščanje"], + "Allow multiple selections": ["Dovoli več izbir"], + "Multiple selections allowed, otherwise filter is limited to a single value": [ + "Lahko izberete več elementov, drugače pa je filter omejen na eno vrednost" ], - "Not up to date": ["Ni posodobljeno"], - "No data after filtering or data is NULL for the latest time record": [ - "Ni podatkov po filtriranju ali pa imajo vrednost NULL za zadnji časovni zapis" + "Search all filter options": ["Poišči vse možnosti filtra"], + "By default, each filter loads at most 1000 choices at the initial page load. Check this box if you have more than 1000 filter values and want to enable dynamically searching that loads filter values as users type (may add stress to your database).": [ + "Privzeto vsak filter pri nalaganju začetne strani naloži največ 1000 možnosti. Označite polje, če imate več kot 1000 vrednosti filtra in želite omogočiti dinamično iskanje, ki nalaga vrednosti filtra ko uporabnik tipka (to lahko preobremeni vašo podatkovno bazo)." ], - "Try applying different filters or ensuring your datasource has data": [ - "Poskusite uporabiti druge filtre oz. zagotovite, da so v podatkovnem viru podatki" + "User must select a value for this filter": [ + "Uporabnik mora izbrati vrednost za ta filter" ], - "Comparison Period Lag": ["Zaostanek obdobja za primerjavo"], - "Based on granularity, number of time periods to compare against": [ - "Na osnovi granulacije, število časovnih obdobij za primerjavo" + "Filter configuration": ["Nastavitve filtra"], + "Custom SQL ad-hoc filters are not available for the native Druid connector": [ + "Ad-hoc SQL filtri po meri niso na voljo za nativni konektor za Druid" ], - "Comparison suffix": ["Pripona za primerjavo"], - "Suffix to apply after the percentage display": [ - "Pripona za prikaz procenta" + "%s option(s)": ["Možnosti: %s"], + "Select subject": ["Izberite zadevo"], + "No such column found. To filter on a metric, try the Custom SQL tab.": [ + "Tak stolpec ni najden. Za filtriranje po meri uporabite prilagojen SQL zavihek." ], - "Timestamp format": ["Oblika zapisa časovne značke"], - "Show Timestamp": ["Prikaži časovno značko"], - "Whether to display the timestamp": [ - "Če želite prikazati časovno značko" + "%s column(s) and metric(s)": ["Stolpcev in mer: %s"], + "To filter on a metric, use Custom SQL tab.": [ + "Za filtriranje po meri uporabite prilagojen SQL zavihek." ], - "Show Trend Line": ["Pokaži trendno črto"], - "Whether to display the trend line": ["Če želite prikazati trendno črto"], - "Start y-axis at 0": ["Začni y-os z 0"], - "Start y-axis at zero. Uncheck to start y-axis at minimum value in the data.": [ - "Začni y-os z nič. Ne izberite, če želite, da se y-os začne z najmanjšo vrednostjo podatkov." + "%s operator(s)": ["Operatorji: %s"], + "Select operator": ["Izberite operator"], + "Comparator option": ["Možnosti komparatorja"], + "Type a value here": ["Vnesite vrednost sem"], + "Filter value (case sensitive)": [ + "Vrednost filtra (razlik. velikih/malih črk)" ], - "Fix to selected Time Range": ["Nastavi na izbrano časovno obdobje"], - "Fix the trend line to the full time range specified in case filtered results do not include the start or end dates": [ - "Trendno črto nastavite na izbrano obdobje, v primeru, da filtrirani rezultati ne vsebujejo začetnega in/ali končnega datuma" + "Failed to retrieve advanced type": [ + "Napaka pri pridobivanju naprednega tipa" ], - "KPI": ["KPI"], - "Showcases a single number accompanied by a simple line chart, to call attention to an important metric along with its change over time or other dimension.": [ - "Prikaže eno vrednost skupaj s preprostim črtnim grafikonom, za poudarek pomembne mere skupaj z njeno časovno spremembo." + "choose WHERE or HAVING...": ["izberite WHERE ali HAVING..."], + "Filters by columns": ["Filtrira po stolpcu"], + "Filters by metrics": ["Filtrira po merah"], + "Fixed": ["Fiksno"], + "Based on a metric": ["Osnovan na meri"], + "My metric": ["Moja mera"], + "Add metric": ["Dodaj mero"], + "Select aggregate options": ["Izberite agregacijske možnosti"], + "%s aggregates(s)": ["Agreg. funkcije: %s"], + "Select saved metrics": ["Izberite shranjene mere"], + "%s saved metric(s)": ["Shranjene mere: %s"], + "Saved metric": ["Shranjena mera"], + "No saved metrics found": ["Shranjene mere niso najdene"], + "Add metrics to dataset in \"Edit datasource\" modal": [ + "Dodaj mero v podatkovni set v oknu \"Uredi podatkovni vir\"" ], - "Formattable": ["Prilagodljiv"], - "Line": ["Črta"], - "Subheader": ["Podnaslov"], - "Description text that shows up below your Big Number": [ - "Besedilo, ki se prikaže pod veliko številko" + "Simple ad-hoc metrics are not enabled for this dataset": [ + "Preproste ad-hoc mere za ta podatkovni set niso omogočene" ], - "Timestamp Format": ["Oblika časovne značke"], - "Whether to format the timestamp": [ - "Če želite oblikovati časovno značko" + "column": ["stolpec"], + "aggregate": ["agregacija"], + "Custom SQL ad-hoc metrics are not available for the native Druid connector": [ + "Ad-hoc SQL mere po meri niso na voljo za nativni konektor za Druid" ], - "Showcases a single metric front-and-center. Big number is best used to call attention to a KPI or the one thing you want your audience to focus on.": [ - "Prikaže eno vrednost. Velika številka je primerna za poudarek KPI-ja ali vrednosti, na katero želite usmeriti pozornost." + "Custom SQL ad-hoc metrics are not enabled for this dataset": [ + "Ad-hoc SQL mere po meri za ta podatkovni set niso omogočene" ], - "A Big Number": ["Velika številka"], - "With a subheader": ["S podnaslovom"], - "Additive": ["Aditivno"], - "Right Axis Format": ["Oblika desne osi"], - "Show Markers": ["Prikaži markerje"], - "Show data points as circle markers on the lines": [ - "Pokaži točke kot krožne markerje na krivuljah" + "Error while fetching data: %s": ["Napaka pri pridobivanju podatkov: %s"], + "Time series columns": ["Stolpci s časovnimi vrstami"], + "Select Viz Type": ["Izberite tip vizualizacije"], + "Currently rendered: %s": ["Trenutno izrisano: %s"], + "Other": ["Ostali"], + "Recommended tags": ["Priporočene značke"], + "Category": ["Kategorija"], + "Tags": ["Značke"], + "Search all charts": ["Išči vse grafikone"], + "No description available.": ["Opisa ni na razpolago."], + "Examples": ["Vzorci"], + "This visualization type is not supported.": [ + "Ta tip vizualizacije ni podprt." ], - "Y bounds": ["Y meje"], - "Whether to display the min and max values of the Y-axis": [ - "Če želite prikaz min. in max. vrednosti Y-osi" + "View all charts": ["Pokaži vse grafikone"], + "Select a visualization type": ["Izberite tip vizualizacije"], + "Select": ["Izberi"], + "Superset Chart": ["Superset grafikon"], + "New chart": ["Nov grafikon"], + "Edit chart properties": ["Uredi lastnosti grafikona"], + "Export to original .CSV": ["Izvozi v izvorni .CSV"], + "Export to pivoted .CSV": ["Izvozi v vrtilni .CSV"], + "Export to .JSON": ["Izvozi v .JSON"], + "Embed code": ["Vgradi kodo"], + "Run in SQL Lab": ["Zaženi v SQL laboratoriju"], + "Code": ["Koda"], + "Markup type": ["Tip označevanja"], + "Pick your favorite markup language": [ + "Izberite svoj priljubljen označevalni jezik" ], - "Y 2 bounds": ["Meje Y 2"], - "Line Style": ["Slog črte"], - "Line interpolation as defined by d3.js": [ - "Interpolacija krivulje na osnovi d3.js" + "Put your code here": ["Vstavite svojo kodo sem"], + "URL parameters": ["Parametri URL"], + "Extra parameters for use in jinja templated queries": [ + "Dodatni parametri za poizvedbe z jinja predlogami" ], - "Show Range Filter": ["Pokaži filter obdobja"], - "Whether to display the time range interactive selector": [ - "Če želite prikaz interaktivnega izbirnika časovnega obdobja" + "Annotations and layers": ["Oznake in sloji"], + "My beautiful colors": ["Moje čudovite barve"], + "No columns": ["Brez stolpcev"], + "%s option": ["%s možnost"], + "UI Configuration": ["UI nastavitve"], + "Can select multiple values": ["Dovoli izbiro več vrednosti"], + "Filter value is required": ["Vrednost filtra je obvezna"], + "User must select a value before applying the filter": [ + "Uporabnik mora izbrati vrednost pred uporabo filtra" ], - "Extra Controls": ["Dodatni kontrolniki"], - "Whether to show extra controls or not. Extra controls include things like making mulitBar charts stacked or side by side.": [ - "Če želite prikaz dodatnih kontrolnikov. Dodatni kontrolniki vključujejo možnost izdelave večstolpčnih grafikonov, naloženih ali drug ob drugem." + "Group By filter plugin": ["Vtičnik za filter za združevanje"], + "Chosen non-numeric column": ["Izbran ne-numeričen stolpec"], + "Single value": ["Ena vrednost"], + "Use only a single value.": ["Uporabite le eno vrednost."], + "Range filter plugin using AntD": [ + "Vtičnik za filter obdobja z uporabo AntD" ], - "X Tick Layout": ["Postavitev oznak na X-osi"], - "The way the ticks are laid out on the X-axis": [ - "Način razporeditve oznak na X-osi" + " (excluded)": [" (ni vključeno)"], + "Select first filter value by default": [ + "Izberi prvo vrednost kot privzeto" ], - "X Axis Format": ["Oblika X-osi"], - "Y Log Scale": ["Logaritemska Y-os"], - "Use a log scale for the Y-axis": ["Uporabi logaritemsko skalo za Y-os"], - "Y Axis Bounds": ["Meje Y-osi"], - "Bounds for the Y-axis. When left empty, the bounds are dynamically defined based on the min/max of the data. Note that this feature will only expand the axis range. It won't narrow the data's extent.": [ - "Meje Y-osi. Če je prazno, se meje nastavijo dinamično na podlagi min./max. vrednosti podatkov. Funkcija omeji le prikaz, obseg podatkov pa ostane enak." + "When using this option, default value can’t be set": [ + "Če uporabite to možnost, privzeta vrednost ne more biti nastavljena" ], - "Y Axis 2 Bounds": ["Meje Y 2-osi"], - "X bounds": ["Meje X-osi"], - "Whether to display the min and max values of the X-axis": [ - "Če želite prikaz min. in max. vrednosti X-osi" + "Inverse selection": ["Invertiraj izbiro"], + "Exclude selected values": ["Izloči izbrane vrednosti"], + "Dynamically search all filter values": [ + "Dinamično poišče vse možnosti filtra" ], - "Bar Values": ["Vrednosti stolpcev"], - "Show the value on top of the bar": [ - "Prikaži vrednosti na vrhu stolpcev" + "Select filter plugin using AntD": [ + "Izberite Vtičnik za filter z uporabo AntD" ], - "Stacked Bars": ["Naloženi stolpci"], - "Reduce X ticks": ["Manj oznak X-osi"], - "Reduces the number of X-axis ticks to be rendered. If true, the x-axis will not overflow and labels may be missing. If false, a minimum width will be applied to columns and the width may overflow into an horizontal scroll.": [ - "Zmanjša število izrisanih oznak na X-osi. Če je vklopljeno, se x-os ne bo prelila in lahko oznake manjkajo. Če je izklopljeno, bo upoštevana min. širina stolpcev, ki pa se lahko prelije v horizontalni drsnik." + "Custom time filter plugin": ["Prilagojeni vtičnik za časovni filter"], + "No time columns": ["Ni časovnih stolpcev"], + "Time column filter plugin": ["Vtičnik za časovni filter"], + "Time grain filter plugin": ["Vtičnik za filter časovne granulacije"], + "Favorites": ["Priljubljene"], + "Created content": ["Ustvarjena vsebina"], + "Recent activity": ["Nedavna aktivnost"], + "Security & Access": ["Varnost in Dostopi"], + "No charts": ["Ni grafikonov"], + "No dashboards": ["Ni nadzornih plošč"], + "No favorite charts yet, go click on stars!": [ + "Priljubljenih grafikonov še ni. Kliknite na zvezdice!" ], - "You cannot use 45° tick layout along with the time range filter": [ - "Skupaj s filtriranjem časovnega obdobja ne morete uporabiti oznak pod 45° kotom" + "No favorite dashboards yet, go click on stars!": [ + "Priljubljenih nadzornih plošč še ni. Kliknite na zvezdice!" ], - "Stacked Style": ["Slog nalaganja"], - "Evolution": ["Evolucija"], - "A time series chart that visualizes how a related metric from multiple groups vary over time. Each group is visualized using a different color.": [ - "Grafikon časovne vrste, ki prikaže kako se povezane mere skupin spreminjajo skozi čas. Vsaka skupina je prikazana s svojo barvo." + "Profile picture provided by Gravatar": [ + "Profilno sliko je zagotovil Gravatar" ], - "Stretched style": ["Raztegnjen slog"], - "Stacked style": ["Naložen slog"], - "Video game consoles": ["Igralne konzole"], - "Vehicle Types": ["Vrste vozil"], - "Area Chart": ["Ploščinski grafikon"], - "Continuous": ["Zvezno"], - "nvd3": ["nvd3"], - "Deprecated": ["Zastarelo"], - "Visualize how a metric changes over time using bars. Add a group by column to visualize group level metrics and how they change over time.": [ - "Prikaže spreminjanje mere skozi čas s pomočjo stolpcev. Z dodajanjem stolpcev za združevanje prikaže mere skupin in njihovo spreminjanje." + "joined": ["pridružen"], + "id:": ["id:"], + "There was an issue fetching reports attached to this dashboard.": [ + "Pri pridobivanju poročil za to nadzorno ploščo je prišlo do težave." ], - "Time-series Bar Chart": ["Stolpčni grafikon za časovno vrsto"], - "Vertical": ["Navpično"], - "Box Plot": ["Box Plot"], - "X Log Scale": ["Logaritemska X-os"], - "Use a log scale for the X-axis": ["Uporabi logaritemsko skalo za X-os"], - "Visualizes a metric across three dimensions of data in a single chart (X axis, Y axis, and bubble size). Bubbles from the same group can be showcased using bubble color.": [ - "Prikaže mero v treh dimenzijah podatkov na istem grafikonu (x os, y os, velikost mehurčka). Mehurčki v isti skupini so predstavljeni z barvo." + "The report has been created": ["Poročilo je bilo ustvarjeno"], + "Report updated": ["Poročilo posodobljeno"], + "We were unable to active or deactivate this report.": [ + "Aktiviranje ali deaktiviranje poročila ni uspelo." ], - "Ranges": ["Razponi"], - "Ranges to highlight with shading": ["Razponi za označitev s senčenjem"], - "Range labels": ["Oznake razponov"], - "Labels for the ranges": ["Oznake za razpone"], - "Markers": ["Markerji"], - "List of values to mark with triangles": [ - "Seznam vrednosti, ki bodo markirane s trikotniki" + "Your report could not be deleted": [ + "Vašega poročila ni mogoče izbrisati" ], - "Marker labels": ["Oznake markerjev"], - "Labels for the markers": ["Oznake za markerje"], - "Marker lines": ["Markirne črtice"], - "List of values to mark with lines": [ - "Seznam vrednosti, ki bodo markirane s črticami" + "Deleted: %s": ["Izbrisano: %s"], + "Image download failed, please refresh and try again.": [ + "Prenos slike ni uspel. Osvežite in poskusite ponovno." ], - "Marker line labels": ["Oznake markirnih črtic"], - "Labels for the marker lines": ["Oznake za markirne črtice"], - "Showcases the progress of a single metric against a given target. The higher the fill, the closer the metric is to the target.": [ - "Prikaže napredovanje posamezne mere glede na cilj. Večja napolnjenost, pomeni, da je mera bližje cilju." + "Select values in highlighted field(s) in the control panel. Then run the query by clicking on the %s button.": [ + "Izberite vrednosti v osvetljenih poljih na levi strani kontrolnika in zaženite poizvedbo z gumbom %s." ], - "Visualizes many different time-series objects in a single chart. This chart is being deprecated and we recommend using the Time-series Chart instead.": [ - "Prikaže več različnih časovnih vrst na istem grafikonu. Grafikon se opušča, zato priporočamo uporabo Grafikona časovne vrste." + "Invalid input": ["Neveljaven vnos"], + "Unexpected error: ": ["Nepričakovana napaka: "], + "(no description, click to see stack trace)": [ + "(ni opisa, kliknite za ogled zapisov)" ], - "Time-series Percent Change": ["Časovna vrsta - Procentualna sprememba"], - "Sort Bars": ["Uredi stolpce"], - "Sort bars by x labels.": ["Uredi stolpce po x-oznakah."], - "Breakdowns": ["Razčlenitev"], - "Defines how each series is broken down": [ - "Določa, kako se vsaka podatkovna serija razčleni" + "Network error": ["Napaka omrežja"], + "Request timed out": ["Zahtevek pretečen"], + "Issue 1000 - The dataset is too large to query.": [ + "Težava 1000 - podatkovni vir je prevelik za poizvedbo." ], - "Compares metrics from different categories using bars. Bar lengths are used to indicate the magnitude of each value and color is used to differentiate groups.": [ - "Primerjava mer različnih kategorij s pomočjo stolpcev. Dolžina stolpca prestavlja višino vrednosti, z barvami pa so ločene skupine." + "Issue 1001 - The database is under an unusual load.": [ + "Težava 1001 - podatkovni vir je neobičajno obremenjen." ], - "Bar Chart": ["Stolpčni grafikon"], - "Discrete": ["Diskretno"], - "Y Axis 1": ["Y-os 1"], - "Y Axis 2": ["Y-os 2"], - "Left Axis Metric": ["Mera za levo os"], - "Choose a metric for left axis": ["Izberite mero za levo os"], - "Left Axis Format": ["Oblika leve osi"], - "Visualizes 2 metrics as line plots using the same x-axis. This chart is useful for comparing metrics across the same time range.": [ - "Prikaže dve meri na črtnem grafu z isto x-osjo. Grafikon je uporaben za primerjavo mer v istem časovnem obdobju." + "An error occurred while fetching %s info: %s": [ + "Napaka pri pridobivanju informacij za %s: %s" ], - "Dual Line Chart": ["Grafikon z dvojno krivuljo"], - "Propagate": ["Razširi"], - "Send range filter events to other charts": [ - "Pošlji dogodke filtra obdobja na druge grafikone" + "An error occurred while fetching %ss: %s": [ + "Napaka pri pridobivanju informacij za %s: %s" ], - "Classic chart that visualizes how metrics change over time.": [ - "Standardni grafikon za prikaz spreminjanje mere skozi čas." + "An error occurred while creating %ss: %s": [ + "Napaka pri ustvarjanju %s: %s" ], - "Battery level over time": ["Napolnjenost baterije skozi čas"], - "Line Chart": ["Črtni grafikon"], - "Prefix metric name with slice name": ["Imenu mere pripni ime rezine"], - "Y Axis Left": ["Y-os levo"], - "Left Axis chart(s)": ["Grafikoni leve osi"], - "Choose one or more charts for left axis": [ - "Izberite enega ali več grafikonov za levo os" + "An error occurred while importing %s: %s": [ + "Napaka pri uvažanju %s: %s" ], - "Select charts": ["Izberi grafikone"], - "Error while fetching charts": ["Napaka pri pridobivanju grafikonov"], - "Y Axis Right": ["Y-os desno"], - "Right Axis chart(s)": ["Grafikoni desne osi"], - "Choose one or more charts for right axis": [ - "Izberite enega ali več grafikonov za desno os" + "There was an error fetching the favorite status: %s": [ + "Napaka pri pridobivanju statusa \"Priljubljeno\": %s" ], - "Visualize two different time series using the same x-axis time range. This chart is being deprecated and we recommend using the Mixed Timeseries Chart instead!": [ - "Prikaže dve različni časovni vrsti z isto x-osjo oz. časovnim obdobjem. Grafikon se opušča, zato priporočamo uporabo kombiniranega grafikona časovne vrste!" + "There was an error saving the favorite status: %s": [ + "Napaka pri shranjevanju statusa \"Priljubljeno\": %s" ], - "Multiple Line Charts": ["Veččrtni grafikon"], - "Label Type": ["Oblika oznake"], - "What should be shown on the label?": ["Kaj bo prikazano na oznaki?"], - "Donut": ["Kolobar"], - "Do you want a donut or a pie?": ["Želite kolobar ali torto?"], - "Show Labels": ["Pokaži oznake"], - "Whether to display the labels. Note that the label only displays when the the 5% threshold.": [ - "Če želite prikazati oznake. Oznake so prikazane le pri vsaj 5-odstotnem pragu." + "Link Copied!": ["Povezava kopirana!"], + "Sorry, your browser does not support copying.": [ + "Vaš brskalnik ne podpira kopiranja." ], - "Put labels outside": ["Postavi oznake zunaj"], - "Put the labels outside the pie?": ["Postavim oznake zunaj torte?"], - "Pie Chart": ["Tortni grafikon"], - "Frequency": ["Frekvenca"], - "The periodicity over which to pivot time. Users can provide\r\n \"Pandas\" offset alias.\r\n Click on the info bubble for more details on accepted \"freq\" expressions.": [ - "Periodičnost za vrtenje časa. Uporabnik lahko poda\n psevdonim za zamik v \"Pandas\".\n Kliknite na mehurček za podrobnosti dovoljenih izrazov za \"freq\"." + "Connection looks good!": ["Povezava izgleda v redu!"], + "ERROR: %s": ["NAPAKA: %s"], + "There was an error fetching your recent activity:": [ + "Pri pridobivanju nedavnih aktivnosti je prišlo do napake:" ], - "Time-series Period Pivot": ["Časovna serija - Vrtenje periode"], - "Show legend": ["Prikaži legendo"], - "Whether to display a legend for the chart": [ - "Če želite prikaz legende za grafikon" + "There was an issue deleting: %s": ["Težava pri brisanju: %s"], + "There was an issue deleting %s: %s": ["Težava pri brisanju %s: %s"], + "Working": ["Delam"], + "Not triggered": ["Ni sproženo"], + "On Grace": ["V mirovanju"], + "report": ["poročilo"], + "alert": ["opozorilo"], + "reports": ["poročila"], + "alerts": ["opozorila"], + "There was an issue deleting the selected %s: %s": [ + "Težava pri brisanju izbranih %s: %s" ], - "Margin": ["Rob"], - "Additional padding for legend.": ["Dodatni razmak za legendo."], - "Legend type": ["Tip legende"], - "Show Value": ["Prikaži vrednost"], - "Show series values on the chart": [ - "Na grafikonu prikaži vrednosti serij" + "Last run": ["Zadnji zagon"], + "Notification method": ["Način obveščanja"], + "Created by": ["Ustvaril"], + "Active": ["Aktiven"], + "Execution log": ["Dnevnik izvajanja"], + "Actions": ["Aktivnosti"], + "Bulk select": ["Izberi hkrati"], + "No %s yet": ["%s še ne obstajajo"], + "Owner": ["Lastnik"], + "An error occurred while fetching owners values: %s": [ + "Pri pridobivanju polja lastnik je prišlo do napake: %s" ], - "Stack series": ["Nalagaj serije"], - "Stack series on top of each other": ["Nalagaj serije eno na drugo"], - "Only Total": ["Samo vsota"], - "Only show the total value on the stacked chart, and not show on the selected category": [ - "Na naloženem grafikonu prikaži samo skupno vsoto, za izbrane kategorije pa ne" + "An error occurred while fetching created by values: %s": [ + "Pri pridobivanju vrednosti \"Ustvaril\" je prišlo do napake: %s" ], - "Rich tooltip": ["Podroben opis orodja"], - "Shows a list of all series available at that point in time": [ - "Prikaže seznam vseh razpoložljivih podatkovnih serij za istočasno točko" + "Status": ["Status"], + "Alerts & reports": ["Opozorila in poročila"], + "Alerts": ["Opozorila"], + "Reports": ["Poročila"], + "Delete %s?": ["Izbrišem %s?"], + "Please confirm": ["Prosim, potrdite"], + "Are you sure you want to delete the selected %s?": [ + "Ali ste prepričani, da želite izbrisati izbrane %s?" ], - "Tooltip time format": ["Oblika zapisa časa v opisu orodja"], - "Tooltip sort by metric": ["Mera za razvrščanje opisa orodja"], - "Whether to sort tooltip by the selected metric in descending order.": [ - "Če želite padajoče razvrstiti opis orodja z izbrano mero." + "< (Smaller than)": ["< (manjše kot)"], + "> (Larger than)": ["> (večje kot)"], + "<= (Smaller or equal)": ["<= (manjše ali enako)"], + ">= (Larger or equal)": [">= (večje ali enako)"], + "== (Is equal)": ["== (je enako)"], + "!= (Is not equal)": ["!= (ni enako)"], + "Not null": ["Ni nič (null)"], + "30 days": ["30 dni"], + "60 days": ["60 dni"], + "90 days": ["90 dni"], + "Add notification method": ["Dodajte način obveščanja"], + "Add delivery method": ["Dodajte način dostave"], + "%s updated": ["%s posodobljeni"], + "Edit Report": ["Uredi poročilo"], + "Edit Alert": ["Uredi opozorilo"], + "Add Report": ["Dodaj poročilo"], + "Add Alert": ["Dodaj opozorilo"], + "Report name": ["Naslov poročila"], + "Alert name": ["Naslov opozorila"], + "Alert condition": ["Status opozorila"], + "Trigger Alert If...": ["Sproži opozorilo v primeru ..."], + "Condition": ["Pogoj"], + "Threshold value should be double precision number": [ + "Mejna vrednost naj bo število z dvojno natančnostjo (double)" ], - "Tooltip": ["Opis orodja"], - "Whisker/outlier options": ["Možnosti grafikona kvantilov"], - "Determines how whiskers and outliers are calculated.": [ - "Določa kako so izračunani kvantili in izstopajoče vrednosti." + "Report schedule": ["Urnik poročanja"], + "Alert condition schedule": ["Urnik statusov opozoril"], + "Schedule settings": ["Nastavitve urnika"], + "Log retention": ["Hranjenje dnevnikov"], + "Working timeout": ["Pretek delovanja"], + "Time in seconds": ["Čas v sekundah"], + "Grace period": ["Obdobje mirovanja"], + "Send as PNG": ["Pošlji kot PNG"], + "Send as CSV": ["Pošlji kot CSV"], + "Send as text": ["Pošlji kot besedilo"], + "log": ["dnevnik"], + "State": ["Status"], + "Execution ID": ["ID izvedbe"], + "Scheduled at (UTC)": ["Izvede se ob (UTC)"], + "Start at (UTC)": ["Zažene se ob (UTC)"], + "Duration": ["Trajanje"], + "Error message": ["Sporočilo napake"], + "CRON expression": ["Izraz CRON"], + "Report sent": ["Poročilo poslano"], + "Alert triggered, notification sent": [ + "Opozorilo sproženo, obvestilo poslano" ], - "Categories to group by on the x-axis.": [ - "Kategorije za združevanje po x-osi." + "Report sending": ["Pošiljanje poročila"], + "Alert running": ["Opozorilo aktivno"], + "Report failed": ["Poročilo ni uspelo"], + "Alert failed": ["Opozorilo ni uspelo"], + "Nothing triggered": ["Ni ni sproženo"], + "Alert Triggered, In Grace Period": [ + "Opozorilo sproženo, v obdobju mirovanja" ], - "Distribute across": ["Porazdeli glede na"], - "Columns to calculate distribution across. Defaults to temporal column if left empty.": [ - "Stolpci za izračun porazdelitve. Privzeto je izbran časovni stolpec (če je prazno)." + "Delivery method": ["Način dostave"], + "Select Delivery Method": ["Izberite način dostave"], + "Recipients are separated by \",\" or \";\"": [ + "Prejemniki so ločeni z \",\" ali \";\"" ], - "Also known as a box and whisker plot, this visualization compares the distributions of a related metric across multiple groups. The box in the middle emphasizes the mean, median, and inner 2 quartiles. The whiskers around each box visualize the min, max, range, and outer 2 quartiles.": [ - "Znan tudi kot grafikon škatla z brki. prikaže primerjavo porazdelitev povezanih mer v različnih skupinah. Škatla na sredini predstavlja povprečje, mediano in notranja 2 kvartila. Brki na vsaki škatli prikazujejo minimum, maksimum, območje in zunanja dva kvartila." + "annotation": ["oznaka"], + "There was an issue deleting the selected annotations: %s": [ + "Pri brisanju izbranih oznak je prišlo do težave: %s" ], - "Labels": ["Oznake"], - "Whether to display the labels.": ["Če želite prikaz oznak."], - "Showcases how a metric changes as the funnel progresses. This classic chart is useful for visualizing drop-off between stages in a pipeline or lifecycle.": [ - "Prikaže kako se mera spreminja, ko lijak napreduje. Standardni grafikon za prikaz sprememb med nivoji v procesu ali življenjskem ciklu." + "Edit annotation": ["Uredi oznako"], + "Delete annotation": ["Izbriši oznako"], + "Annotation": ["Oznaka"], + "No annotation yet": ["Oznak še ni"], + "Annotation Layer %s": ["Sloj z oznakami %s"], + "Are you sure you want to delete %s?": [ + "Ali ste prepričani, da želite izbrisati %s?" ], - "Funnel Chart": ["Lijakasti grafikon"], - "Sequential": ["Sekvenčni"], - "Columns to group by": ["Stolpci za združevanje"], - "General": ["Splošno"], - "Minimum value on the gauge axis": ["Najmanjša vrednost na številčnici"], - "Maximum value on the gauge axis": ["Največja vrednost na številčnici"], - "Start angle": ["Začetni kot"], - "Angle at which to start progress axis": [ - "Kot, pri katerem se začne os območja" + "Delete Annotation?": ["Izbrišem oznako?"], + "Are you sure you want to delete the selected annotations?": [ + "Ali ste prepričani, da želite izbrisati izbrane oznake?" ], - "End angle": ["Končni kot"], - "Angle at which to end progress axis": [ - "Kot, pri katerem se konča os območja" + "The annotation has been updated": ["Označba je bila posodobljena"], + "The annotation has been saved": ["Označba je bila shranjena"], + "Add annotation": ["Dodaj oznako"], + "Annotation name": ["Ime oznake"], + "date": ["datum"], + "Additional information": ["Dodatne informacije"], + "Description (this can be seen in the list)": [ + "Opis (lahko je viden na seznamu)" + ], + "annotation_layer": ["annotation_layer"], + "Annotation template updated": ["Predloga oznake posodobljena"], + "Annotation template created": ["Predloga oznake ustvarjena"], + "Edit annotation layer properties": ["Uredi lastnosti sloja z oznakami"], + "Annotation layer name": ["Ime sloja z oznakami"], + "Annotation layers": ["Sloji z oznakami"], + "There was an issue deleting the selected layers: %s": [ + "Pri brisanju izbranih slojev je prišlo do težave: %s" + ], + "Last modified": ["Zadnja sprememba"], + "Created on": ["Ustvarjeno"], + "Edit template": ["Uredi predlogo"], + "Delete template": ["Izbriši predlogo"], + "Annotation layer": ["Sloj z oznakami"], + "An error occurred while fetching dataset datasource values: %s": [ + "Pri pridobivanju vrednosti podatkovnega vira podatkovnega seta je prišlo do napake: %s" ], - "Font size": ["Velikost pisave"], - "Font size for axis labels, detail value and other text elements": [ - "Velikost pisave za oznake osi, podrobnosti in druge besedilne elemente" + "No annotation layers yet": ["Slojev z oznakami še ni"], + "This action will permanently delete the layer.": [ + "S tem dejanjem boste trajno izbrisali sloj." ], - "Value format": ["Oblika zapisa vrednosti"], - "Additional text to add before or after the value, e.g. unit": [ - "Dodatno besedilo, ki ga dodate pred ali za vrednost, npr. enota" + "Delete Layer?": ["Izbrišem sloj?"], + "Are you sure you want to delete the selected layers?": [ + "Ali ste prepričani, da želite izbrisati izbrane sloje?" ], - "Show pointer": ["Prikaži kazalec"], - "Whether to show the pointer": ["Če želite prikazati kazalec"], - "Animation": ["Animacija"], - "Whether to animate the progress and the value or just display them": [ - "Če želite animiran prikaz grafikona" + "Are you sure you want to delete": [ + "Ali ste prepričani, da želite izbrisati" ], - "Axis": ["Os"], - "Show axis line ticks": ["Prikaži oznake na X-osi"], - "Whether to show minor ticks on the axis": [ - "Če želite prikaz manjših oznak na osi" + "Modified %s": ["Zadnja sprememba %s"], + "The passwords for the databases below are needed in order to import them together with the charts. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj z grafikoni. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." ], - "Show split lines": ["Prikaži razdelitvene črte"], - "Whether to show the split lines on the axis": [ - "Če želite prikazati razdelitvene črte na osi" + "You are importing one or more charts that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "Uvažate enega ali več grafikonov, ki že obstajajo. S prepisom lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" ], - "Split number": ["Število razdelitev"], - "Number of split segments on the axis": ["Število razdelkov na osi"], - "Progress": ["Območje"], - "Show progress": ["Prikaži območje"], - "Whether to show the progress of gauge chart": [ - "Prikaži merilno območje števčnega grafikona" + "Chart imported": ["Grafikon uvožen"], + "There was an issue deleting the selected charts: %s": [ + "Pri brisanju izbranih grafikonov je prišlo do težave: %s" ], - "Overlap": ["Prekrivanje"], - "Whether the progress bar overlaps when there are multiple groups of data": [ - "Če želite prekrivanje območij, ko imate več skupin podatkov" + "Modified by": ["Spremenil"], + "Favorite": ["Priljubljene"], + "Any": ["Katerikoli"], + "Yes": ["Da"], + "No": ["Ne"], + "All": ["Vsi"], + "An error occurred while fetching chart owners values: %s": [ + "Pri pridobivanju polja lastnik grafikona je prišlo do napake: %s" ], - "Round cap": ["Zaobljeni konci"], - "Style the ends of the progress bar with a round cap": [ - "Zaobljena oblika koncev območja" + "An error occurred while fetching chart created by values: %s": [ + "Pri pridobivanju polja Grafikon ustvaril je prišlo do napake: %s" ], - "Intervals": ["Intervali"], - "Interval bounds": ["Meje intervalov"], - "Comma-separated interval bounds, e.g. 2,4,5 for intervals 0-2, 2-4 and 4-5. Last number should match the value provided for MAX.": [ - "Z vejico ločeni intervali, npr. 2,4,5 za intervale 0-2, 2-4 in 4-5. Zadnja številka naj bo enaka vrednosti za MAX." + "Chart type": ["Tip grafikona"], + "Certified": ["Certificirano"], + "Alphabetical": ["Po abecedi"], + "Recently modified": ["Nedavno spremenjeno"], + "Least recently modified": ["Zadnje spremenjeno"], + "Import charts": ["Uvozi grafikone"], + "Are you sure you want to delete the selected charts?": [ + "Ali ste prepričani, da želite izbrisati izbrane grafikone?" ], - "Interval colors": ["Barve intervalov"], - "Comma-separated color picks for the intervals, e.g. 1,2,4. Integers denote colors from the chosen color scheme and are 1-indexed. Length must be matching that of interval bounds.": [ - "Z vejico ločene barve za intervale, npr. 1,2,4. Cela števila predstavljajo barve iz barvne sheme (začnejo se z 1). Dolžina mora ustrezati mejam intervala." + "css_template": ["css_template"], + "Edit CSS template properties": ["Uredi lastnosti CSS predloge"], + "Add CSS template": ["Dodaj CSS predlogo"], + "CSS template name": ["Ime CSS predloge"], + "css": ["css"], + "CSS templates": ["CSS predloge"], + "There was an issue deleting the selected templates: %s": [ + "Pri brisanju izbranih predlog je prišlo do težave: %s" ], - "Uses a gauge to showcase progress of a metric towards a target. The position of the dial represents the progress and the terminal value in the gauge represents the target value.": [ - "Uporablja števec za prikaz napredovanja mere k ciljni vrednosti. Položaj kazalca predstavlja napredek, končna vrednost na števcu pa ciljno vrednost." + "Last modified by %s": ["Nazadnje spremenil %s"], + "CSS template": ["CSS predloga"], + "This action will permanently delete the template.": [ + "S tem dejanjem boste trajno izbrisali predlogo." ], - "Gauge Chart": ["Števčni grafikon"], - "Name of the source nodes": ["Imena izvornih vozlišč"], - "Name of the target nodes": ["Imena ciljnih vozlišč"], - "Source category": ["Kategorija izvora"], - "The category of source nodes used to assign colors. If a node is associated with more than one category, only the first will be used.": [ - "Kategorija izvornih vozlišč, na podlagi katere je določena barva. Če je vozlišče povezano z več kot eno kategorijo, bo uporabljena samo prva." + "Delete Template?": ["Izbrišem predlogo?"], + "Are you sure you want to delete the selected templates?": [ + "Ali ste prepričani, da želite izbrisati izbrane predloge?" ], - "Target category": ["Kategorija cilja"], - "Category of target nodes": ["Kategorija ciljnih vozlišč"], - "Chart options": ["Možnosti grafikona"], - "Layout": ["Izgled"], - "Graph layout": ["Izgled grafikona"], - "Force": ["Sila"], - "Layout type of graph": ["Tip izgleda grafikona"], - "Edge symbols": ["Simboli povezav"], - "Symbol of two ends of edge line": ["Simbol za konca povezave"], - "None -> None": ["Brez -> Brez"], - "None -> Arrow": ["Brez -> Puščica"], - "Circle -> Arrow": ["Krog -> Puščica"], - "Circle -> Circle": ["Krog -> Krog"], - "Enable node dragging": ["Omogoči premikanje vozlišč"], - "Whether to enable node dragging in force layout mode.": [ - "Če želite omogočiti premikanje vozlišč v načinu vsiljenega prikaza." + "published": ["objavljeno"], + "draft": ["osnutek"], + "The passwords for the databases below are needed in order to import them together with the dashboards. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj z nadzornimi ploščami. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." ], - "Enable graph roaming": ["Omogoči preoblikovanje grafikona"], - "Disabled": ["Onemogočeno"], - "Scale only": ["Samo povečava"], - "Move only": ["Samo premikanje"], - "Scale and Move": ["Povečava in premikanje"], - "Whether to enable changing graph position and scaling.": [ - "Če želite omogočiti premikanje in povečevanje/zmanjševanje grafikona." + "You are importing one or more dashboards that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "Uvažate eno ali več nadzornih plošč, ki že obstajajo. S prepisom lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" ], - "Node select mode": ["Način izbire vozlišč"], - "Single": ["Posamezno"], - "Multiple": ["Več"], - "Allow node selections": ["Dovoli izbiro vozlišča"], - "Label threshold": ["Prag oznak"], - "Minimum value for label to be displayed on graph.": [ - "Najmanjša vrednost, za katero bo na grafikonu prikazana oznaka." + "Dashboard imported": ["Nadzorna plošča uvožena"], + "An error occurred while fetching dashboards: %s": [ + "Prišlo je do napake pri pridobivanju nadzornih plošč: %s" ], - "Node size": ["Velikost vozlišča"], - "Median node size, the largest node will be 4 times larger than the smallest": [ - "Mediana velikosti vozlišča. Največje vozlišče bo 4-krat večje od najmanjšega" + "There was an issue deleting the selected dashboards: ": [ + "Pri brisanju izbranih nadzornih plošč je prišlo do težave: " ], - "Edge width": ["Debelina povezave"], - "Median edge width, the thickest edge will be 4 times thicker than the thinnest.": [ - "Mediana debeline povezave. Najdebelejša povezava bo 4-krat debelejša od najtanjše." + "An error occurred while fetching dashboard owner values: %s": [ + "Pri pridobivanju polja lastnik nadzorne plošče je prišlo do napake: %s" ], - "Edge length": ["Dolžina povezave"], - "Edge length between nodes": ["Dolžina povezave med vozlišči"], - "Gravity": ["Gravitacija"], - "Strength to pull the graph toward center": [ - "Sila privlačnosti med grafikonom in središčem" + "An error occurred while fetching dashboard created by values: %s": [ + "Pri pridobivanju polja Nadzorno ploščo ustvaril je prišlo do napake: %s" ], - "Repulsion": ["Odbijanje"], - "Repulsion strength between nodes": ["Odbojna sila med vozlišči"], - "Friction": ["Trenje"], - "Friction between nodes": ["Trenje med vozlišči"], - "Displays connections between entities in a graph structure. Useful for mapping relationships and showing which nodes are important in a network. Graph charts can be configured to be force-directed or circulate. If your data has a geospatial component, try the deck.gl Arc chart.": [ - "Prikaže povezave med entitetami v strukturi grafa. Uporabno za prikaz razmerij in pomembnih točk v omrežju. Grafikon je lahko krožnega tipa ali z usmerjenimi silami. Če imajo podatki geoprostorsko komponento, poskusite grafikon decl.gl - Arc." + "Are you sure you want to delete the selected dashboards?": [ + "Ali ste prepričani, da želite izbrisati izbrane nadzorne plošče?" ], - "Graph Chart": ["Graf"], - "Structural": ["Strukturni"], - "Series type": ["Tip serije"], - "Series chart type (line, bar etc)": [ - "Tip grafikona za posamezno podatkovno serijo (črtni, stolpčni, ...)" + "Saved queries": ["Shranjene poizvedbe"], + "SQL Copied!": ["SQL kopiran!"], + "database": ["podatkovna baza"], + "An error occurred while fetching database related data: %s": [ + "Pri pridobivanju podatkov iz podatkovne baze je prišlo do napake: %s" ], - "Area chart": ["Ploščinski grafikon"], - "Draw area under curves. Only applicable for line types.": [ - "Izriši površino pod krivuljo. Samo za črtne grafikone." + "Upload file to database": ["Naloži datoteko v podatkovno bazo"], + "Upload CSV": ["Naloži CSV"], + "Upload columnar file": ["Naloži datoteko s stolpci"], + "Upload Excel file": ["Naloži Excel-ovo datoteko"], + "Asynchronous query execution": ["Asinhroni zagon poizvedb"], + "AQE": ["AQE"], + "Allow data manipulation language": [ + "Dovoli jezik za manipulacijo podatkov (DML)" ], - "Opacity of area chart.": ["Prosojnost ploščinskega grafikona."], - "Marker": ["Marker"], - "Draw a marker on data points. Only applicable for line types.": [ - "Nariši markerje na točke grafikona. Samo za črtne grafikone." + "DML": ["DML"], + "CSV upload": ["Nalaganje CSV"], + "Delete database": ["Izbriši podatkovno bazo"], + "The database %s is linked to %s charts that appear on %s dashboards and users have %s SQL Lab tabs using this database open. Are you sure you want to continue? Deleting the database will break those objects.": [ + "Podatkovna baza %s je povezana z grafikoni %s, ki so prisotni na nadzorni plošči %s in uporabniki imajo odprtih %s zavihkov SQL laboratorija. Ali želite nadaljevati? Izbris podatkovne baze bo pokvaril te objekte." ], - "Marker size": ["Velikost markerja"], - "Size of marker. Also applies to forecast observations.": [ - "Velikost markerja. Upošteva se tudi za napovedi." + "Delete Database?": ["Izbrišem podatkovno bazo?"], + "Expose database in SQL Lab": [ + "Razkrij podatkovno bazo v SQL laboratoriju" ], - "Primary": ["Primarna"], - "Secondary": ["Sekundarna"], - "Primary or secondary y-axis": ["Primarna ali sekundarna y-os"], - "Query A": ["Poizvedba A"], - "Query B": ["Poizvedba B"], - "Data Zoom": ["Zoom funkcija"], - "Enable data zooming controls": [ - "Omogoči kontrolnik za povečavo podatkov" + "Allow this database to be queried in SQL Lab": [ + "Dovoli poizvedbo na to podatkovno bazo v SQL laboratoriju" ], - "Rotate x axis label": ["Zavrti oznako x-osi"], - "Input field supports custom rotation. e.g. 30 for 30°": [ - "Vnosno polje omogoča poljubno rotacijo (vnesite 30 za 30°)" + "Allow creation of new tables based on queries": [ + "Dovoli ustvarjanje novih tabel s poizvedbami" ], - "Minor Split Line": ["Manjša ločilna črta"], - "Draw split lines for minor y-axis ticks": [ - "Izriši ločilne črte za pomožne oznake y-osi" + "Allow creation of new views based on queries": [ + "Dovoli ustvarjanje novih pogledov s poizvedbami" ], - "Truncate Y Axis": ["Prireži Y-os"], - "Truncate Y Axis. Can be overridden by specifying a min or max bound.": [ - "Prireži Y-os. Če določite spodnjo ali zgornjo mejo, preprečite prirezovanje." + "CTAS & CVAS SCHEMA": ["CTAS & CVAS SHEMA"], + "Create or select schema...": ["Ustvarite ali izberite shemo..."], + "Force all tables and views to be created in this schema when clicking CTAS or CVAS in SQL Lab.": [ + "Vsilite, da bodo vse tabele in pogledi ustvarjeni s to shemo, ko kliknete CTAS ali CVAS v SQL laboratoriju." ], - "Primary y-axis format": ["Oblika primarne y-osi"], - "Logarithmic y-axis": ["Logaritemska y-os"], - "Logarithmic scale on primary y-axis": [ - "Logaritemska skala na primarni y-osi" + "Allow manipulation of the database using non-SELECT statements such as UPDATE, DELETE, CREATE, etc.": [ + "Dovoli manipulacije podatkovne baze z uporabo ne-SELECT stavkov, kot so UPDATE, DELETE, CREATE, itd." ], - "Secondary y-axis format": ["Oblika sekundarne y-osi"], - "Secondary y-axis title": ["Naslov sekundarne y-osi"], - "Logarithmic scale on secondary y-axis": [ - "Logaritemska skala na sekundarni y-osi" + "Enable query cost estimation": [ + "Omogoči ocenjevanje potratnosti poizvedbe" ], - "Visualize two different time series using the same x-axis time range. Note that each time series can be visualized differently (e.g. 1 using bars and 1 using a line).": [ - "Prikaže dve različni časovni vrsti na isti x-osi. Časovni vrsti sta lahko prikazani različno (npr. ena s stolpci in druga s črto)." + "For Bigquery, Presto and Postgres, shows a button to compute cost before running a query.": [ + "Za Presto in Postgres prikaže gumb za izračun potratnosti pred zagonom poizvedbe." ], - "Mixed Time-Series": ["Kombiniran grafikon časovne vrste"], - "Percentage threshold": ["Procentualni prag"], - "Minimum threshold in percentage points for showing labels.": [ - "Minimalni prag v odstotnih točkah za prikaz oznak." + "Allow this database to be explored": [ + "Dovoli raziskovanje te podatkovne baze" ], - "Put the labels outside of the pie?": ["Postavim oznake zunaj torte?"], - "Label Line": ["Črta oznake"], - "Draw line from Pie to label when labels outside?": [ - "Ali želite črto do oznake, ko so le-te zunaj?" + "When enabled, users are able to visualize SQL Lab results in Explore.": [ + "Ko je omogočeno, lahko uporabniki prikazujejo rezultate SQL laboratorija v raziskovalcu." ], - "Pie shape": ["Oblika torte"], - "Outer Radius": ["Zunanji polmer"], - "Outer edge of Pie chart": ["Zunanji rob tortnega grafikona"], - "Inner Radius": ["Notranji polmer"], - "Inner radius of donut hole": ["Notranji polmer kolobarja"], - "The classic. Great for showing how much of a company each investor gets, what demographics follow your blog, or what portion of the budget goes to the military industrial complex.\r\n\r\n Pie charts can be difficult to interpret precisely. If clarity of relative proportion is important, consider using a bar or other chart type instead.": [ - "Standardni grafikon za prikaz deležev. Tortne grafikone je težje natančno interpretirati, takrat lahko uporabite npr. stolpčni grafikon." + "Disable SQL Lab data preview queries": [ + "Izključite poizvedbe za predogled podatkov v SQL Laboratoriju" ], - "The maximum value of metrics. It is an optional configuration": [ - "Največja vrednost mere. To je opcijska nastavitev" + "Disable data preview when fetching table metadata in SQL Lab. Useful to avoid browser performance issues when using databases with very wide tables.": [ + "Izključite predogled podatkov pri pridobivanju metapodatkov v SQL laboratoriju. S tem se zmanjša obremenitev brskalnika pri podatkovnih bazah z zelo širokimi tabelami." ], - "Label position": ["Položaj oznake"], - "Radar": ["Radar"], - "Customize Metrics": ["Prilagodi mere"], - "Further customize how to display each metric": [ - "Dodatne prilagoditve prikaza posameznih mer" + "Chart cache timeout": ["Trajanje predpomnilnika grafikona"], + "Enter duration in seconds": ["Vnesite trajanje v sekundah"], + "Schema cache timeout": ["Trajanje prepomnilnika sheme"], + "Duration (in seconds) of the metadata caching timeout for schemas of this database. If left unset, the cache never expires.": [ + "Trajanje (v sekundah) predpomnilnika metapodatkov za sheme v tej podatkovni bazi. Če ni nastavljeno, predpomnilnik ne poteče." ], - "Circle radar shape": ["Okrogla oblika radarja"], - "Radar render type, whether to display 'circle' shape.": [ - "Način prikaza radarja - če se prikaže okrogla oblika." + "Table cache timeout": ["Trajanje predpomnilnika tabele"], + "Duration (in seconds) of the metadata caching timeout for tables of this database. If left unset, the cache never expires. ": [ + "Trajanje (v sekundah) predpomnilnika metapodatkov za tabele v tej podatkovni bazi. Če ni nastavljeno, predpomnilnik ne poteče. " ], - "Visualize a parallel set of metrics across multiple groups. Each group is visualized using its own line of points and each metric is represented as an edge in the chart.": [ - "Prikaže vzporedni nabor mer za različne skupine. Vsaka skupina je prikazana s svojim naborom točk in vsaka mera s povezavo na grafikonu." + "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.": [ + "Upravljanje podatkovne baze v asinhronem načinu pomeni, da se poizvedbe zaženejo na oddaljenih »delavcih« in ne na samem spletnem strežniku. S tem je predpostavljeno, da imate nastavljenega »delavca« za Celery in zaledni sistem za rezultate. Več informacij je v navodilih za namestitev." ], - "Radar Chart": ["Radarski grafikon"], - "Web": ["Mreža"], - "Contribution Mode": ["Način deležev"], - "Calculate contribution per series or total": [ - "Izračunaj delež za podatkovno serijo ali skupnega" + "Cancel query on window unload event": [ + "Prekini poizvedbo pri dogodku zaprtja okna (window unload event)" ], - "Series Style": ["Slog serije"], - "Area chart opacity": ["Prosojnost ploščinskega grafikona"], - "Opacity of Area Chart. Also applies to confidence band.": [ - "Prosojnost ploščinskega grafikona. Upošteva se tudi za interval zaupanja." + "Terminate running queries when browser window closed or navigated to another page. Available for Presto, Hive, MySQL, Postgres and Snowflake databases.": [ + "Ustavi zagnane poizvedbe, ko se zapre okno brskalnika ali gre na drugo stran. na razpolago za Presto, Hive, MySQL, Postgres in Snowflake podatkovne baze." ], - "Marker Size": ["Velikost markerja"], - "Swiss army knife for visualizing time series data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.": [ - "Univerzalni grafikon za prikaz časovnih vrst. Izbirajte med stopničnimi, črtnimi, raztresenimi in stolpčnimi grafikoni. Grafikon ima širok nabor prilagoditev." + "Secure extra": ["Dodatna varnost"], + "JSON string containing additional connection configuration. This is used to provide connection information for systems like Hive, Presto and BigQuery which do not conform to the username:password syntax normally used by SQLAlchemy.": [ + "JSON niz, ki vsebuje dodatno konfiguracijo povezave. Uporablja se za zagotavljanje dodatnih informacij povezave za sisteme kot sta Presto in BigQuery, ki nista skladna s sintakso username:password, ki jo običajno uporablja SQLAlchemy." ], - "Time-series Chart": ["Grafikon časovne vrste"], - "Time-series Area chart are similar to line chart in that they represent variables with the same scale, but area charts stack the metrics on top of each other. An area chart in Superset can be stream, stack, or expand.": [ - "Ploščinski grafikoni časovne vrste so podobni črtnim grafikonom, saj predstavljajo spremenljivke v istem razmerju, vendar se pri ploščinskih grafikonih mere nalagajo ena na drugo." + "Enter CA_BUNDLE": ["Vnesite CA_BUNDLE"], + "Optional CA_BUNDLE contents to validate HTTPS requests. Only available on certain database engines.": [ + "Opcijska CA_BUNDLE vsebina, za potrjevanje HTTPS zahtev. Razpoložljivo le na določenih sistemih podatkovnih baz." ], - "Time-series Area Chart": ["Ploščinski grafikon časovne vrste"], - "It’s not recommended to truncate y-axis in Bar chart.": [ - "V stolpčnem grafikonu ni priporočljivo omejiti y-osi." + "Schemas allowed for CSV upload": ["Dovoljene sheme za nalaganje CSV"], + "A comma-separated list of schemas that CSVs are allowed to upload to.": [ + "Z vejicami ločen seznam shem, kjer je dovoljeno nalaganje CSV-jev." ], - "Time-series Bar Charts are used to show the changes in a metric over time as a series of bars.": [ - "Stolpčni grafikoni časovne vrste se uporabljajo za prikaz sprememb mere skozi čas s pomočjo niza stolpcev." + "Impersonate logged in user (Presto, Trino, Drill, Hive, and GSheets)": [ + "Predstavljanje kot prijavljeni uporabnik (Presto, Trino, Drill, Hive in GSheets)" ], - "Time-series Bar Chart v2": ["Stolpčni grafikon časovne vrste v2"], - "Bar": ["Stolpec"], - "Time-series line chart is used to visualize repeated measurements taken over regular time intervals. Line chart is a type of chart which displays information as a series of data points connected by straight line segments. It is a basic type of chart common in many fields.": [ - "Črtni grafikon časovne vrste je osnovni grafikon, ki se uporablja na različnih področjih. Uporablja se za vizualizacijo meritev zajetih skozi čas. Posamezne točke so med seboj povezane z ravnimi črtami." + "If Presto or Trino, all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them. If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.": [ + "V primeru Presto ali Trino se vse poizvedbe v SQL laboratoriju zaženejo pod trenutno prijavljenim uporabnikom, ki mora imeti pravice za poganjanje. Če je omogočen Hive in hive.server2.enable.doAs, poizvedbe tečejo pod servisnim računom, vendar je trenutno prijavljen uporabnik predstavljen z lastnostjo hive.server2.proxy.user." ], - "Time-series Line Chart": ["Črtni grafikon časovne vrste"], - "Time-series Scatter Plot has time on the horizontal axis in linear units, and the points are connected in order. It shows a statistical relationship between two variables.": [ - "Raztreseni grafikon časovne vrste prikazuje podatkovne točke v povezanem redu in prikazuje statistično razmerje med spremenljivkami." + "Allow data upload": ["Dovoli nalaganje podatkov"], + "If selected, please set the schemas allowed for data upload in Extra.": [ + "Če je izbrano, nastavite dovoljene sheme za nalaganje podatkov v Dodatno." ], - "Time-series Scatter Plot": ["Raztreseni grafikon časovne vrste"], - "Time-series Smooth-line is a variation of line chart. Without angles and hard edges, Smooth-line looks more smarter and more professional.": [ - "Zglajeni grafikon časovne vrste je izpeljanka črtnega grafikona, ki zgladi ostre robove krivulje." + "Metadata Parameters": ["Parametri metapodatkov"], + "The metadata_params object gets unpacked into the sqlalchemy.MetaData call.": [ + "Objekt metadata_params se razpakira v klic sqlalchemy.MetaData." ], - "Time-series Smooth Line": ["Zglajeni črtni grafikon časovne vrste"], - "Step type": ["Stopnični tip"], - "Defines whether the step should appear at the beginning, middle or end between two data points": [ - "Določa, če se na začetku, na sredini ali na koncu pojavi stopnica med dvema točkama" + "Engine Parameters": ["Parametri podatkovne baze"], + "The engine_params object gets unpacked into the sqlalchemy.create_engine call.": [ + "Objekt engine_params se razširi v klic sqlalchemy.create_engine." ], - "Time-series Stepped-line graph (also called step chart) is a variation of line chart but with the line forming a series of steps between data points. A step chart can be useful when you want to show the changes that occur at irregular intervals.": [ - "Stopnični grafikon časovne vrste je izpeljanka črtnega grafikona, pri čemer krivuljo tvorijo stopnice med posameznimi točkami. Koristen je za prikaz sprememb na posameznih intervalih." + "Version": ["Verzija"], + "Version number": ["Številka verzije"], + "Specify the database version. This should be used with Presto in order to enable query cost estimation.": [ + "Podajte verzijo podatkovne baze. Uporablja se s Presto, za potrebe ocenjevanja potratnosti poizvedbe." ], - "Time-series Stepped Line": ["Stopnični črtni grafikon časovne vrste"], - "Id": ["Id"], - "Name of the id column": ["Naziv id-stolpca"], - "Parent": ["Nadrejeni"], - "Name of the column containing the id of the parent node": [ - "Ime stolpca, ki vsebuje id nadrejenega vozlišča" + "Display Name": ["Ime za prikaz"], + "Name your database": ["Poimenujte podatkovno bazo"], + "Pick a name to help you identify this database.": [ + "Izberite ime za lažjo prepoznavo podatkovne baze." ], - "Optional name of the data column.": [ - "Opcijsko ime podatkovnega stolpca." + "dialect+driver://username:password@host:port/database": [ + "dialect+driver://username:password@host:port/database" ], - "Root node id": ["Id korenskega vozlišča"], - "Id of root node of the tree.": ["Id korenskega vozlišča drevesa."], - "Metric for node values": ["Mera za vrednosti vozlišč"], - "Tree layout": ["Oblika drevesa"], - "Orthogonal": ["Pravokotna"], - "Radial": ["Radialna"], - "Layout type of tree": ["Način izgleda drevesa"], - "Tree orientation": ["Orientacija drevesa"], - "Left to Right": ["Iz leve proti desni"], - "Right to Left": ["Iz desne proti levi"], - "Top to Bottom": ["Iz vrha proti dnu"], - "Bottom to Top": ["Iz dna proti vrhu"], - "Orientation of tree": ["Orientacija drevesa"], - "Node label position": ["Položaj oznake vozlišča"], - "left": ["levo"], - "top": ["zgoraj"], - "right": ["desno"], - "bottom": ["spodaj"], - "Position of intermidiate node label on tree": [ - "Položaj vmesne oznake vozlišča na drevesu" + "Refer to the": ["Obrnite se na"], + "for more information on how to structure your URI.": [ + "za več informacij o oblikovanju URI." ], - "Child label position": ["Položaj podrejene oznake"], - "Position of child node label on tree": [ - "Položaj oznake podrejenega vozlišča na drevesu" + "Test connection": ["Preizkus povezave"], + "Please enter a SQLAlchemy URI to test": [ + "Vnesite SQLAlchemy URI za test" ], - "Emphasis": ["Poudari"], - "ancestor": ["nadrejeni"], - "descendant": ["podrejeni"], - "Which relatives to highlight on hover": [ - "Kateri element se poudari na prehodu z miško" + "Database settings updated": ["Nastavitve podatkovne baze posodobljene"], + "Database connected": ["Podatkovna baza povezana"], + "Sorry there was an error fetching database information: %s": [ + "Pri pridobivanju informacij o podatkovni bazi je prišlo do napake: %s" ], - "Symbol": ["Simbol"], - "Empty circle": ["Prazen krog"], - "Circle": ["Krog"], - "Rectangle": ["Pravokotnik"], - "Triangle": ["Trikotnik"], - "Diamond": ["Karo"], - "Pin": ["Žebljiček"], - "Arrow": ["Puščica"], - "Symbol size": ["Velikost simbola"], - "Size of edge symbols": ["Velikost simbola povezave"], - "Visualize multiple levels of hierarchy using a familiar tree-like structure.": [ - "Prikaz več hierarhičnih nivojev z drevesno strukturo." + "Or choose from a list of other databases we support:": [ + "Ali izberite iz seznama drugih podatkovnih baz, ki jih podpiramo:" ], - "Tree Chart": ["Drevesni grafikon"], - "Show Upper Labels": ["Prikaži zgornje oznake"], - "Show labels when the node has children.": [ - "Prikaži oznake, ko ima vozlišče podrejene elemente." + "Supported databases": ["Podprte podatkovne baze"], + "Choose a database...": ["Izberite podatkovno bazo..."], + "Want to add a new database?": ["Želite dodati novo podatkovno bazo?"], + "Any databases that allow connections via SQL Alchemy URIs can be added. ": [ + "Dodate lahko katerokoli podatkovno bazo, ki podpira konekcije z SQL Alchemy URI-ji. " ], - "Show hierarchical relationships of data, with with the value represented by area, showing proportion and contribution to the whole.": [ - "Prikaže hierarhična razmerja podatkov, pri čemer je vrednost ponazorjena s ploščino, in deleže oz. prispevke k celoti." + "Any databases that allow connections via SQL Alchemy URIs can be added. Learn about how to connect a database driver ": [ + "Dodate lahko katerokoli podatkovno bazo, ki podpira konekcije z SQL Alchemy URI-ji. Naučite se kako povezati gonilnik podatkovne baze " ], - "Treemap v2": ["Drevesni grafikon s pravokotniki v2"], - "Columns to group by on the rows": ["Stolpci za združevanje vrstic"], - "Columns to group by on the columns": ["Stolpci za združevanje stolpcev"], - "Apply metrics on": ["Uporabi mero na"], - "Use metrics as a top level group for columns or for rows": [ - "Uporabi mere kot vrhovni nivo grupiranja za stolpce ali vrstice" + "Back": ["Nazaj"], + "Connect": ["Poveži"], + "Finish": ["Zaključi"], + "This database is managed externally, and can't be edited in Superset": [ + "Ta podatkovna baza se ne ureja znotraj Superseta" ], - "Show rows total": ["Prikaži vsoto vrstic"], - "Display row level total": ["Prikaži vsote na nivoju vrstic"], - "Show columns total": ["Prikaži vsoto stolpcev"], - "Display column level total": ["Prikaži vsote na nivoju stolpcev"], - "Transpose pivot": ["Transponirano vrtenje"], - "Swap rows and columns": ["Zamenjaj vrstice in stolpce"], - "Combine metrics": ["Združuj mere"], - "D3 time format for datetime columns": [ - "D3 oblika zapisa za časovne stolpce" + "The passwords for the databases below are needed in order to import them. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in explore files and should be added manually after the import if they are needed.": [ + "Gesla za spodnje podatkovne baze so potrebna za njihov uvoz. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." ], - "Rows sort by": ["Razvrsti vrstice"], - "key a-z": ["a - ž"], - "key z-a": ["ž - a"], - "value ascending": ["0 - 9"], - "value descending": ["9 - 0"], - "Order of rows": ["Vrstni red vrstic"], - "Cols sort by": ["Razvrsti stolpce"], - "Order of columns": ["Vrstni red stolpcev"], - "Rows subtotal position": ["Položaj vsot vrstic"], - "Top": ["Zgoraj"], - "Bottom": ["Spodaj"], - "Position of row level subtotal": ["Položaj vsot na nivoju vrstic"], - "Cols subtotal position": ["Položaj vsot stolpcev"], - "Position of column level subtotal": ["Položaj vsot na nivoju stolpcev"], - "Conditional formatting": ["Pogojno oblikovanje"], - "Apply conditional color formatting to metrics": [ - "Za mere uporabi pogojno oblikovanje z barvami" + "%s PASSWORD": ["%s GESLO"], + "You are importing one or more databases that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "Uvažate eno ali več podatkovnih baz, ki že obstajajo. S prepisom lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" ], - "Used to summarize a set of data by grouping together multiple statistics along two axes. Examples: Sales numbers by region and month, tasks by status and assignee, active users by age and location. Not the most visually stunning visualization, but highly informative and versatile.": [ - "Ponazori podatke na podlagi združevanja več statistik vzdolž dveh osi. Npr. prodaja po regijah in mesecih, opravila po statusih in izvajalcih, itd." + "TYPE \"OVERWRITE\" TO CONFIRM": ["VNESITE \"PREPIŠI\" ZA POTRDITEV"], + "Database Creation Error": ["Napaka pri ustvarjanju podatkovne baze"], + "Connect a database": ["Poveži se s podatkovno bazo"], + "Edit database": ["Uredi podatkovno bazo"], + "Connect this database using the dynamic form instead": [ + "S podatkovno bazo se povežite z dinamičnim obrazcem" ], - "Pivot Table v2": ["Vrtilna tabela v2"], - "search.num_records": ["search.num_records"], - "page_size.show": ["page_size.show"], - "page_size.entries": ["page_size.entries"], - "Totals": ["Vsote"], - "page_size.all": ["page_size.all"], - "Group By, Metrics or Percentage Metrics must have a value": [ - "Združevanje, Mera ali Procentualna mera morajo imeti vrednost" + "Click this link to switch to an alternate form that exposes only the required fields needed to connect this database.": [ + "Kliknite to povezavo za drugo vnosno formo, ki prikaže samo zahtevana polja za povezavo s podatkovno bazo." ], - "Query mode": ["Poizvedbeni način"], - "must have a value": ["mora imeti vrednost"], - "Percentage metrics": ["Procentualne mere"], - "Metrics for which percentage of total are to be displayed. Calculated from only data within the row limit.": [ - "Mera, za katero je prikazan odstotek od celote. Izračunan je samo iz podatkov znotraj omejitve števila vrstic." + "Select databases require additional fields to be completed in the Advanced tab to successfully connect the database. Learn what requirements your databases has ": [ + "Izbira podatkovnih baz za uspešno povezavo zahteva izpolnitev dodatnih polj v zavihku Napredno. Naučite se, kaj zahteva vaša podatkovna baza " ], - "Ordering": ["Razvrščanje"], - "Order results by selected columns": [ - "Razvrsti rezultate glede na izbrani stolpec" + "Import database from file": ["Uvozi podatkovno bazo iz datoteke"], + "Connect this database with a SQLAlchemy URI string instead": [ + "S to podatkovno bazo se raje povežite z SQLAlchemy URI nizom" ], - "Server pagination": ["Paginacija na strani strežnika"], - "Enable server side pagination of results (experimental feature)": [ - "Omogoči številčenje strani rezultatov na strani strežnika (preizkusna funkcija)" + "Click this link to switch to an alternate form that allows you to input the SQLAlchemy URL for this database manually.": [ + "Kliknite to povezavo za drugo vnosno formo, ki omogoča ročni vnos SQLAlchemy URL-ja za to podatkovno bazo." ], - "Server Page Length": ["Dolžina strani strežnika"], - "Rows per page, 0 means no pagination": [ - "Vrstic na stran (0 pomeni brez številčenja strani)" + "This can be either an IP address (e.g. 127.0.0.1) or a domain name (e.g. mydatabase.com).": [ + "To je lahko bodisi IP naslov (npr. 127.0.0.1) bodisi ime domene (npr. mydatabase.com)." ], - "Include time": ["Vključi čas"], - "Whether to include the time granularity as defined in the time section": [ - "Če želite vključiti granulacijo časa, ki je določena v sekciji Čas" + "e.g. 127.0.0.1": ["npr. 127.0.0.1"], + "Host": ["Gostitelj"], + "e.g. 5432": ["npr. 5432"], + "e.g. world_population": ["npr. world_population"], + "Copy the name of the database you are trying to connect to.": [ + "Kopirajte ime podatkovne baze, s katero se skušate povezati." ], - "Show total aggregations of selected metrics. Note that row limit does not apply to the result.": [ - "Prikaži skupno agregacijo izbrane mere. Omejitev števila vrstic ne vpliva na rezultat." + "e.g. Analytics": ["npr. Analitika"], + "e.g. ********": ["npr. ********"], + "Pick a nickname for this database to display as in Superset.": [ + "Izberite vzdevek za to podatkovno bazo, ki bo prikazan v Supersetu." ], - "Page length": ["Dolžina strani"], - "Search box": ["Iskalno polje"], - "Whether to include a client-side search box": [ - "Če želite vključiti iskalno polje za uporabnika" + "e.g. param1=value1¶m2=value2": ["npr. param1=value1¶m2=value2"], + "Additional Parameters": ["Dodatni parametri"], + "Add additional custom parameters": ["Dodaj dodatne parametre po meri"], + "SSL Mode \"require\" will be used.": [ + "Uporabljen bo SSL način tipa \"require\"." ], - "Cell bars": ["Stolp. graf v celicah"], - "Whether to align background charts with both positive and negative values at 0": [ - "Če želite poravnati graf v ozadju celic za negativne in pozitivne vrednosti okrog 0" + "Type of Google Sheets allowed": ["Dovoljeni tipi Googlovih preglednic"], + "Publicly shared sheets only": ["Samo javno deljene preglednice"], + "Public and privately shared sheets": [ + "Javno in zasebno deljene preglednice" ], - "Customize columns": ["Prilagodi stolpce"], - "Further customize how to display each column": [ - "Dodatne prilagoditve prikaza posameznih stolpcev" + "How do you want to enter service account credentials?": [ + "Kako želite vnesti prijavne podatke servisnega računa?" ], - "Apply conditional color formatting to numeric columns": [ - "Za numerične stolpce uporabi pogojno oblikovanje z barvami" + "Upload JSON file": ["Naloži JSON datoteko"], + "Copy and Paste JSON credentials": [ + "Kopiraj in prilepi JSON prijavne podatke" ], - "Classic row-by-column spreadsheet like view of a dataset. Use tables to showcase a view into the underlying data or to show aggregated metrics.": [ - "Standardna razpredelnica za prikaz podatkovnega seta." + "Service Account": ["Servisni račun"], + "Copy and paste the entire service account .json file here": [ + "Tukaj kopirajte in prilepite celotno json datoteko servisnega računa" ], - "Word Cloud": ["Oblak besed"], - "Minimum Font Size": ["Min. velikost pisave"], - "Font size for the smallest value in the list": [ - "Velikost pisave za najmanjšo vrednost na seznamu" + "Upload Credentials": ["Naloži prijavne podatke"], + "Use the JSON file you automatically downloaded when creating your service account.": [ + "Uporabite JSON datoteko, ki ste jo prenesli pri ustvarjanju servisnega računa." ], - "Maximum Font Size": ["Max. velikost pisave"], - "Font size for the biggest value in the list": [ - "Velikost pisave za največjo vrednost na seznamu" + "Connect Google Sheets as tables to this database": [ + "Googlove preglednice poveži s to podatkovno bazo kot tabele" ], - "Word Rotation": ["Vrtenje besed"], - "Rotation to apply to words in the cloud": [ - "Če želite vrtenje besed v oblaku" + "Google Sheet Name and URL": ["Ime Googlove preglednice in URL"], + "Enter a name for this sheet": ["Vnesite ime te preglednice"], + "Paste the shareable Google Sheet URL here": [ + "Prilepite deljeni URL Googlove preglednice sem" ], - "Visualizes the words in a column that appear the most often. Bigger font corresponds to higher frequency.": [ - "Prikaže besede v stolpcu, glede na pogostost pojavljanja. Večja pisava pomeni večjo frekvenco." + "Add sheet": ["Dodaj preglednico"], + "Copy the account name of that database you are trying to connect to.": [ + "Kopirajte ime računa podatkovne baze, s katero se skušate povezati." ], - "Scatter Plot": ["Raztreseni grafikon"], - "Hide Mini Map": ["Skrij majhen zemljevid"], - "Show Mini Map": ["Prikaži majhen zemljevid"], - "Choropleth Map": ["Koroplet zemljevid"], - "ChoroplethMap": ["ChoroplethMap"], - "Icicle Event Chart": ["Grafikon Icicle dogodkov"], - "deck.gl charts": ["grafikoni deck.gl"], - "Pick a set of deck.gl charts to layer on top of one another": [ - "Izberite nabor deck.gl grafikonov, ki bodo nanizani en na drugem" + "Add dataset": ["Dodaj podatkovni set"], + "Dataset imported": ["Podatkovni set uvožen"], + "An error occurred while fetching dataset related data": [ + "Napaka pri pridobivanju podatkov iz podatkovnega seta" ], - "Compose multiple layers together to form complex visuals.": [ - "Združi več plasti za oblikovanje kompleksnih vizualizacij." + "An error occurred while fetching dataset related data: %s": [ + "Napaka pri pridobivanju podatkov iz podatkovnega seta: %s" ], - "deck.gl Multiple Layers": ["deck.gl - Večplastni grafikon"], - "deckGL": ["deckGL"], - "Data has no time steps": ["Podatki nimajo časovnih korakov"], - "Start Longitude & Latitude": ["Začetna Dolž. in Širina"], - "Point to your spatial columns": [ - "Pokažite na stolpec z lokacijskimi podatki" + "Physical dataset": ["Fizičen podatkovni set"], + "Virtual dataset": ["Virtualen podatkovni set"], + "An error occurred while fetching dataset owner values: %s": [ + "Pri pridobivanju polja lastnik podatkovnega seta je prišlo do napake: %s" ], - "End Longitude & Latitude": ["Končna Dolž. in Širina"], - "Arc": ["Lok"], - "Target Color": ["Ciljna barva"], - "Color of the target location": ["Barva ciljne lokacije"], - "Categorical Color": ["Kategorična barva"], - "Pick a dimension from which categorical colors are defined": [ - "Izberite dimenzijo, ki bo določala kategorične barve" + "An error occurred while fetching datasets: %s": [ + "Prišlo je do napake pri pridobivanju podatkovnih setov: %s" ], - "Stroke Width": ["Debelina obrobe"], - "Plot the distance (like flight paths) between origin and destination.": [ - "Izriši razdalje (kot letalske koridorje) med izhodiščem in ciljem." + "An error occurred while fetching schema values: %s": [ + "Pri pridobivanju vrednosti shem je prišlo do napake: %s" ], - "deck.gl Arc": ["deck.gl - Lok"], - "3D": ["3D"], - "GeoJson Settings": ["GeoJson nastavitve"], - "Point Radius Scale": ["Skaliranje radija točk"], - "The GeoJsonLayer takes in GeoJSON formatted data and renders it as interactive polygons, lines and points (circles, icons and/or texts).": [ - "GeoJsonLayer uporablja podatke v formatu GeoJSON in jih izriše kot interaktivne poligone, črte in točke (krogi, ikone in/ali besedila)." + "Import datasets": ["Uvozi podatkovne sete"], + "There was an issue deleting the selected datasets: %s": [ + "Pri brisanju izbranih podatkovnih setov je prišlo do težave: %s" ], - "deck.gl Geojson": ["deck.gl - GeoJSON"], - "Metric used to control height": ["Mera za določanje višine"], - "Visualize geospatial data like 3D buildings, landscapes, or objects in grid view.": [ - "Prikaz geoprostorskih podatkov kot so 3D zgradbe, parcele ali objekti v mrežnem pogledu." + "The dataset %s is linked to %s charts that appear on %s dashboards. Are you sure you want to continue? Deleting the dataset will break those objects.": [ + "Podatkovni set %s je povezan z grafikoni %s, ki so prisotni na nadzorni plošči %s. Ali želite nadaljevati? Izbris podatkovnega seta bo pokvaril te objekte." ], - "deck.gl Grid": ["deck.gl - Mreža"], - "Dynamic Aggregation Function": ["Dinamična agregacijska funkcija"], - "The function to use when aggregating points into groups": [ - "Funkcija za agregacijo točk v skupine" + "Delete Dataset?": ["Izbrišem podatkovni set?"], + "Are you sure you want to delete the selected datasets?": [ + "Ali ste prepričani, da želite izbrisati izbrane podatkovne sete?" ], - "Overlays a hexagonal grid on a map, and aggregates data within the boundary of each cell.": [ - "Prikaže šestkotno mrežo na zemljevidu in agregira podatke znotraj meja vsake celice." + "0 Selected": ["Izbranih: 0"], + "%s Selected (Virtual)": ["Izbranih: %s (virtualni)"], + "%s Selected (Physical)": ["Izbranih: %s (fizični)"], + "%s Selected (%s Physical, %s Virtual)": [ + "Izbranih: %s (fizični: %s, virtualni: %s)" ], - "deck.gl 3D Hexagon": ["deck.gl - 3D HEX"], - "Visualizes connected points, which form a path, on a map.": [ - "Na zemljevidu prikaže povezane točke, ki tvorijo pot." + "The passwords for the databases below are needed in order to import them together with the datasets. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj s podatkovnimi seti. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." ], - "deck.gl Path": ["deck.gl - Poti"], - "Polygon Column": ["Stolpec poligonov"], - "Polygon Encoding": ["Kodiranje poligonov"], - "Elevation": ["Višina"], - "Polygon Settings": ["Nastavitve poligonov"], - "Opacity, expects values between 0 and 100": [ - "Prosojnost, vnesite vrednosti med 0 in 100" + "You are importing one or more datasets that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "Uvažate enega ali več podatkovnih setov, ki že obstajajo. S prepisom lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" ], - "Number of buckets to group data": [ - "Število razdelkov za združevanje podatkov" + "There was an issue previewing the selected query. %s": [ + "Pri predogledu izbrane poizvedbe je prišlo do težave. %s" ], - "How many buckets should the data be grouped in.": [ - "V koliko razdelkov bodo razvrščeni podatki." + "Duration: %s": ["Trajanje: %s"], + "Tab name": ["Naslov zavihka"], + "TABLES": ["TABELE"], + "Open query in SQL Lab": ["Odpri poizvedbo v SQL laboratoriju"], + "An error occurred while fetching database values: %s": [ + "Pri pridobivanju vrednosti podatkovne baze je prišlo do napake: %s" ], - "Bucket break points": ["Točke za razčlenitev razdelkov"], - "List of n+1 values for bucketing metric into n buckets.": [ - "Seznam n+1 vrednosti za mero razvrščanja v n razdelkov." + "An error occurred while fetching user values: %s": [ + "Pri pridobivanju vrednosti uporabnika je prišlo do napake: %s" ], - "Emit Filter Events": ["Prikaži dogodke filtrov"], - "Whether to apply filter when items are clicked": [ - "Če želite uporabiti filter, ko kliknete na elemente" + "Search by query text": ["Išči z besedilom poizvedbe"], + "Next": ["Naslednji"], + "Open in SQL Lab": ["Odpri v SQL laboratoriju"], + "User query": ["Uporabnikova poizvedba"], + "Executed query": ["Zagnana poizvedba"], + "The passwords for the databases below are needed in order to import them together with the saved queries. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj s shranjenimi poizvedbami. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." ], - "Multiple filtering": ["Večkratno filtriranje"], - "Allow sending multiple polygons as a filter event": [ - "Dovoli pošiljanje več poligonov kot dogodek filtra" + "You are importing one or more saved queries that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "Uvažate eno ali več shranjenih poizvedb, ki že obstajajo. S prepisom lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" ], - "Visualizes geographic areas from your data as polygons on a Mapbox rendered map. Polygons can be colored using a metric.": [ - "Prikaže geografsko območje kot poligone na zemljevidu zagotovljenim preko storitve Mapbox. Poligoni so lahko obarvani glede na mero." + "Query imported": ["Poizvedba uvožena"], + "There was an issue previewing the selected query %s": [ + "Do težave je prišlo pri predogledu izbrane poizvedbe %s" ], - "deck.gl Polygon": ["deck.gl - Poligon"], - "Point Size": ["Velikost točke"], - "Point Unit": ["Enota točke"], - "Minimum Radius": ["Min. polmer"], - "Minimum radius size of the circle, in pixels. As the zoom level changes, this insures that the circle respects this minimum radius.": [ - "Minimalni polmer kroga v pikslih. S tem je določen min. polmer kroga, ko se spreminja stopnja povečave." + "Import queries": ["Uvozi poizvedbe"], + "There was an issue deleting the selected queries: %s": [ + "Do težave je prišlo pri brisanju izbranih poizvedb: %s" ], - "Maximum Radius": ["Max. polmer"], - "Maxium radius size of the circle, in pixels. As the zoom level changes, this insures that the circle respects this maximum radius.": [ - "Maksimalni polmer kroga v pikslih. S tem je določen max. polmer kroga, ko se spreminja stopnja povečave." + "Edit query": ["Uredi poizvedbo"], + "Copy query URL": ["Kopiraj URL poizvedbe"], + "Export query": ["Izvozi poizvedbe"], + "Delete query": ["Izbriši poizvedbo"], + "This action will permanently delete the saved query.": [ + "S tem dejanjem boste trajno izbrisali shranjeno poizvedbo." ], - "Point Color": ["Barva točke"], - "A map that takes rendering circles with a variable radius at latitude/longitude coordinates": [ - "Zemljevid, ki na zemljepisnih koordinatah prikazuje kroge s spremenljivim polmerom" + "Delete Query?": ["Izbrišem poizvedbo?"], + "Are you sure you want to delete the selected queries?": [ + "Ali ste prepričani, da želite izbrisati izbrane poizvedbe?" ], - "deck.gl Scatterplot": ["deck.gl - Raztreseni grafikon"], - "Grid": ["Mreža"], - "Weight": ["Utež"], - "Metric used as a weight for the grid's coloring": [ - "Mera, ki služi kot utež za barvo mreže" + "queries": ["poizvedbe"], + "Query name": ["Ime poizvedbe"], + "[Untitled]": ["[Neimenovana]"], + "Unknown": ["Neznano"], + "Viewed %s": ["Ogledane %s"], + "Edited": ["Urejane"], + "Created": ["Ustvarjene"], + "Viewed": ["Ogledane"], + "Mine": ["Moje"], + "View All »": ["Poglejte vse »"], + "charts": ["grafikoni"], + "dashboards": ["nadzorne plošče"], + "recents": ["nedavne"], + "saved queries": ["shranjene poizvedbe"], + "No %(tableName)s yet": ["%(tableName)s še ni"], + "Recently viewed charts, dashboards, and saved queries will appear here": [ + "Nedavno ogledani grafikoni, nadzorne plošče in shranjene poizvedbe bodo prikazane tukaj" ], - "Aggregates data within the boundary of grid cells and maps the aggregated values to a dynamic color scale": [ - "Agregira podatke znotraj meja celic in agregiranim vrednostim pripiše barvno lestvico" + "Recently created charts, dashboards, and saved queries will appear here": [ + "Nedavno ustvarjeni grafikoni, nadzorne plošče in shranjene poizvedbe bodo prikazane tukaj" ], - "deck.gl Screen Grid": ["deck.gl - Mreža"], - "For more information about objects are in context in the scope of this function, refer to the": [ - "Za dodatne informacije o objektih v kontekstu te funkcije si oglejte" + "Example %(tableName)s will appear here": [ + "Primer %(tableName)s se bo prikazal tukaj" ], - " source code of Superset's sandboxed parser": [ - " izvorno kodo za Supersetov \"sandboxed parser\"" + "Recently edited charts, dashboards, and saved queries will appear here": [ + "Nedavno urejani grafikoni, nadzorne plošče in shranjene poizvedbe bodo prikazane tukaj" ], - "This functionality is disabled in your environment for security reasons.": [ - "Ta funkcionalnost je v vašem okolju onemogočena zaradi varnosti." + "SQL query": ["SQL poizvedba"], + "You don't have any favorites yet!": ["Priljubljenih še niste izbrali!"], + "See all %(tableName)s": ["Poglej vse %(tableName)s"], + "query": ["poizvedba"], + "Ran %s": ["Pretečeno %s"], + "There was an issue fetching your recent activity: %s": [ + "Pri pridobivanju vaše nedavne aktivnosti je prišlo do napake: %s" ], - "Ignore null locations": ["Izpusti prazne lokacije"], - "Whether to ignore locations that are null": [ - "Če ne želite upoštevati praznih (NULL) lokacij" + "There was an issue fetching your dashboards: %s": [ + "Prišlo je do napake pri pridobivanju nadzornih plošč: %s" ], - "Auto Zoom": ["Samodejna povečava"], - "When checked, the map will zoom to your data after each query": [ - "Če želite, da se zemljevid prilagodi vašim podatkom po vsaki poizvedbi" + "There was an issue fetching your chart: %s": [ + "Prišlo je do napake pri pridobivanju grafikona: %s" ], - "Dimension": ["Dimenzija"], - "Select a dimension": ["Izberite dimenzijo"], - "Extra data for JS": ["Dodatni podatki za JS"], - "List of extra columns made available in Javascript functions": [ - "Seznam dodatnih podatkov, ki so na razpolago v Javascript funkcijah" + "There was an issues fetching your saved queries: %s": [ + "Prišlo je do napake pri pridobivanju shranjenih poizvedb: %s" ], - "Javascript data interceptor": ["Javascript prestreznik podatkov"], - "Define a javascript function that receives the data array used in the visualization and is expected to return a modified version of that array. This can be used to alter properties of the data, filter, or enrich the array.": [ - "Določite Javascript funkcijo, ki sprejme podatkovni niz za vizualizacijo in vrne spremenjeno verzijo tega niza. Lahko se uporabi za spreminjanje lastnosti podatkov, filtra ali obogatitve niza." + "Recents": ["Nedavno"], + "Connect database": ["Poveži se s podatkovno bazo"], + "Connect Google Sheet": ["Povežite Googlovo preglednico"], + "Upload CSV to database": ["Naloži CSV v podatkovno bazo"], + "Upload columnar file to database": [ + "Naloži datoteko s stolpci v podatkovno bazo" ], - "Javascript tooltip generator": ["Javascript generator opisa orodja"], - "Define a function that receives the input and outputs the content for a tooltip": [ - "Določite funkcijo, ki sprejme vhodne podatke in vrne vsebino opisa orodja" + "Upload Excel file to database": [ + "Naloži Excel-ovo datoteko v podatkovno bazo" ], - "Javascript onClick href": ["Javascript onClick href"], - "Define a function that returns a URL to navigate to when user clicks": [ - "Določite funkcijo, ki vrne URL za navigacijo, ko uporabnik klikne" + "Enable 'Allow data upload' in any database's settings": [ + "Omogoči 'Dovoli nalaganje podatkov' za vse podatkovne baze" ], - "Legend Format": ["Oblika legende"], - "Choose the format for legend values": [ - "Izberite obliko vrednosti legende" + "About": ["O programu"], + "Powered by Apache Superset": ["Omogoča Apache Superset"], + "Documentation": ["Dokumentacija"], + "Report a bug": ["Sporočite napako"], + "Select start and end date": ["Izberite začetni in končni datum"], + "Type or Select [%s]": ["Vnesite ali izberite [%s]"], + "No results found": ["Rezultati niso najdeni"], + "Tools": ["Orodja"], + "Filter box": ["Izbirnik za filtriranje"], + "Chart component that lets you add a custom filter UI in your dashboard. When added to dashboard, a filter box lets users specify specific values or ranges to filter charts by. The charts that each filter box is applied to can be fine tuned as well in the dashboard view.\n\n Note that this plugin is being replaced with the new Filters feature that lives in the dashboard view itself. It's easier to use and has more capabilities!": [ + "Komponenta grafikona, ki omogoča dodajanje vmesnika filtrov po meri v nadzorno ploščo. Ko je dodana na nadzorno ploščo, lahko uporabnik določi poljubne vrednosti ali obsege filtrov. Grafikoni, na katere se nanašajo filtri, so lahko precizno izbrani tudi v pogledu nadzorne plošče.\n\n Vedite, da bo ta vtičnik v prihodnosti zamenjan z novim konceptom filtrov, ki bodo živeli v kontekstu same nadzorne plošče in bodo zmogljivejši ter enostavnejši za uporabo!" ], - "Legend Position": ["Položaj legende"], - "Choose the position of the legend": ["Izberite položaj legende"], - "Lines column": ["Stolpec črt"], - "The database columns that contains lines information": [ - "Stolpec v podatkovni bazi, ki vsebuje podatke črt" + "Filters configuration": ["Nastavitve filtrov"], + "Filter configuration for the filter box": ["Nastavitve za polje filtra"], + "Date filter": ["Filter po datumu"], + "Whether to include a time filter": [ + "Če želite vključiti časovni filter" ], - "The width of the lines": ["Debelina črt"], - "Fill Color": ["Barva polnila"], - " Set the opacity to 0 if you do not want to override the color specified in the GeoJSON": [ - " Nastavite prosojnost na 0, če želite obdržati barvo določeno v GeoJSON" + "Instant filtering": ["Takojšnje filtriranje"], + "Check to apply filters instantly as they change instead of displaying [Apply] button": [ + "Izberite za takojšnjo uporabo filtrov, ko se spremenijo, brez prikazovanja gumba Uveljavi" ], - "Stroke Color": ["Barva obrobe"], - "Filled": ["Zapolnjeno"], - "Whether to fill the objects": ["Če želite zapolniti objekte"], - "Stroked": ["Obrobljeno"], - "Whether to display the stroke": ["Če želite prikazati obrobe"], - "Extruded": ["Relief"], - "Grid Size": ["Velikost mreže"], - "Defines the grid size in pixels": ["Določa velikost mreže v pikslih"], - "Parameters related to the view and perspective on the map": [ - "Parametri povezani s pogledom in perspektivo zemljevida" + "Limit selector values": ["Omeji vrednosti izbirnikov"], + "These filters apply to the values available in the dropdowns": [ + "Ti filtri se nanašajo na vrednosti v spustnih seznamih" ], - "Longitude & Latitude": ["Dolžina in širina"], - "Fixed point radius": ["Fiksni radij točk"], - "Multiplier": ["Množitelj"], - "Factor to multiply the metric by": ["Faktor, s katerim množite mero"], - "Lines encoding": ["Kodiranje črt"], - "The encoding format of the lines": ["Oblika kodiranja črt"], - "Reverse Lat & Long": ["Zamenjaj Dolž. in Širino"], - "GeoJson Column": ["GeoJson stolpec"], - "Select the geojson column": ["Izberite geojson stolpec"], - "Kepler.gl": ["Kepler.gl"], - "List Users": ["Seznam uporabnikov"], - "List Roles": ["Seznam vlog"], - "Your user information": ["Vaše uporabniške informacije"], - "User info": ["Informacije o uporabniku"], - "User Name": ["Uporabniško ime"], - "Is Active?": ["Aktiven?"], - "Login count": ["Število prijav"], - "Personal Info": ["Osebne informacije"], - "First Name": ["Ime"], - "Last Name": ["Priimek"], - "Email": ["E-pošta"], - "Audit Info": ["Revizijske informacije"], - "Last login": ["Zadnja prijava"], - "Failed login count": ["Število neuspešnih prijav"], - "Changed by": ["Spremenil"], - "Reset Password": ["Ponastavi geslo"], - "Show User": ["Prikaži uporabnika"], - "Username valid for authentication on DB or LDAP, unused for OID auth": [ - "Uporabniško ime za DB ali LDAP avtentikacijo. Ni uporabljeno za OID avtentikacijo" - ], - "It's not a good policy to remove a user, just make it inactive": [ - "Izbris uporabnika ni dobra praksa, raje ga deaktivirajte" - ], - "The user's email, this will also be used for OID auth": [ - "Uporabnikov e-naslov, uporabljen bo tudi za OID avtentikacijo" - ], - "The user role on the application, this will associate with a list of permissions": [ - "Uporabnikova vloga v tej aplikaciji, povezana bo s seznamom dovoljenj" - ], - "User confirmation needed": ["Potrebna je potrditev s strani uporabnika"], - "You sure you want to delete this item?": [ - "Ste prepričani, da želite izbrisati ta vnos?" - ], - "Reset my password": ["Ponastavi geslo"], - "Reset Password Form": ["Obrazec za ponastavitev gesla"], - "Please use a good password policy, this application does not check this for you": [ - "Uporabite varno geslo. Ta aplikacija tega ne bo preverila" - ], - "Confirm Password": ["Potrdite geslo"], - "Please rewrite the password to confirm": [ - "Ponovno vpišite geslo za potrditev" + "URL": ["URL"], + "Templated link, it's possible to include {{ metric }} or other values coming from the controls.": [ + "Vzorčna povezava, vključiti je mogoče {{ metric }} ali drugo vrednost iz kontrolnikov." ], - "Back": ["Nazaj"], - "Edit User": ["Uredite uporabnika"], - "Edit User Information": ["Uredite informacije o uporabniku"], - "Write the user first name or names": ["Vpišite ime uporabnika"], - "Write the user last name": ["Vpišite priimek uporabnika"], - "Embed code": ["Vstavi kodo"], - "creator": ["avtor"], - "favorited": ["priljubljeno"], - "name": ["ime"], - "type": ["tip"], - "time": ["čas"], - "Toggle SortBy": ["Preklopite razvrščanje"], - "Page size": ["Velikost strani"], - "Edit record": ["Uredi zapis"], - "Delete record": ["Izbriši zapis"], - "Show record": ["Pokaži zapis"], - "Orientation": ["Postavitev"], - "Scroll": ["Drsnik"], - "Plain": ["Celotna"] + "Time-series Table": ["Tabela s časovno vrsto"], + "Compare multiple time series charts (as sparklines) and related metrics quickly.": [ + "Hitra primerjava več grafikonov časovnih vrst (sparkline način) in povezanih mer." + ], + "Text": ["Besedilo"], + "We have the following keys: %s": ["Imamo naslednje ključe: %s"] } } } diff --git a/superset/translations/sl/LC_MESSAGES/messages.po b/superset/translations/sl/LC_MESSAGES/messages.po index 2c9ad7bfcb09c..c9b76c8afe8df 100644 --- a/superset/translations/sl/LC_MESSAGES/messages.po +++ b/superset/translations/sl/LC_MESSAGES/messages.po @@ -15,6817 +15,7831 @@ # under the License. msgid "" msgstr "" -"Project-Id-Version: Superset\n" +"Project-Id-Version: Superset\n" "Report-Msgid-Bugs-To: dkrat7 @github.com\n" -"POT-Creation-Date: 2021-12-08 12:22+0800\n" -"PO-Revision-Date: 2021-11-13 21:21+0100\n" +"POT-Creation-Date: 2022-06-19 18:59+0200\n" +"PO-Revision-Date: 2022-06-19 20:59+0200\n" "Last-Translator: dkrat7 <dkrat7 @github.com>\n" "Language: sl_SI\n" "Language-Team: \n" -"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100>=3 " -"&& n%100<=4 ? 2 : 3)\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100>=3 && n" +"%100<=4 ? 2 : 3);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.9.1\n" +"X-Generator: Poedit 2.3\n" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx:68 -#: superset-frontend/src/explore/components/controls/OptionControls/index.tsx:323 -#, fuzzy -msgid "" -"\n" -" This filter was inherited from the dashboard's context.\n" -" It won't be saved when saving the chart.\n" -" " -msgstr "" -"\r\n" -" Ta filter izvira iz konteksta nadzorne plošče.\r\n" -" Pri shranjevanju grafikona se ne bo shranil.\r\n" -" " +#: superset/errors.py:95 +msgid "The datasource is too large to query." +msgstr "Podatkovni vir je prevelik za poizvedbo." -#: superset/tasks/schedules.py:184 -#, python-format -msgid "" -"\n" -" <b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>\n" -" <img src=\"cid:%(msgid)s\">\n" -" " -msgstr "" -"\n" -" <b><a href=\"%(url)s\">Razišči v Supersetu</a></b><p></p>\n" -" <img src=\"cid:%(msgid)s\">\n" -" " +#: superset/errors.py:96 +msgid "The database is under an unusual load." +msgstr "Podatkovni vir je neobičajno obremenjen." -#: superset/reports/notifications/email.py:60 -#, python-format -msgid "" -"\n" -" Error: %(text)s\n" -" " -msgstr "" -"\n" -" Napaka: %(text)s\n" -" " +#: superset/errors.py:97 +msgid "The database returned an unexpected error." +msgstr "Podatkovna baza je vrnila nepričakovano napako." -#: superset/tasks/schedules.py:159 -#, python-format +#: superset/errors.py:98 msgid "" -"\n" -" *%(name)s*\n" -"\n" -" <%(url)s|Explore in Superset>\n" -" " -msgstr "" -"\n" -" *%(name)s*\n" -"\n" -" <%(url)s|Razišči v Supersetu>\n" -" " +"There is a syntax error in the SQL query. Perhaps there was a misspelling or a " +"typo." +msgstr "V SQL-poizvedbi je sintaktična napaka. Mogoče ste se zatipkali." -#: superset/tasks/schedules.py:372 -#, python-format -msgid "" -"\n" -" *%(slice_name)s*\n" -"\n" -" <%(slice_url_user_friendly)s|Explore in Superset>\n" -" " -msgstr "" -"\n" -" *%(slice_name)s*\n" -"\n" -" <%(slice_url_user_friendly)s|Razišči v Supersetu>\n" -" " +#: superset/errors.py:102 +msgid "The column was deleted or renamed in the database." +msgstr "Stolpec je bil izbrisan ali preimenovan v podatkovni bazi." -#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:122 -msgid " (excluded)" -msgstr "" +#: superset/errors.py:103 +msgid "The table was deleted or renamed in the database." +msgstr "Tabela je bila izbrisana ali preimenovana v podatkovni bazi." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:235 -msgid " expression which needs to adhere to the " -msgstr " , ki mora upoštevati " +#: superset/errors.py:104 +msgid "One or more parameters specified in the query are missing." +msgstr "En ali več parametrov v SQL-poizvedbi manjka." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:239 -#, fuzzy -msgid "" -" standard to ensure that the lexicographical ordering\n" -" coincides with the chronological ordering. If the\n" -" timestamp format does not adhere to the ISO 8601 " -"standard\n" -" you will need to define an expression and type for\n" -" transforming the string into a date or timestamp. " -"Note\n" -" currently time zones are not supported. If time is " -"stored\n" -" in epoch format, put `epoch_s` or `epoch_ms`. If no" -" pattern\n" -" is specified we fall back to using the optional " -"defaults on a per\n" -" database/column name level via the extra parameter." -msgstr "" -" standard, ki zagotavlja, de se leksikografsko razvrščanje\r\n" -" sklada s kronološkim razvrščanjem. Če oblika\r\n" -" časovne značke ni v skladu s standardom ISO 8601," -"\r\n" -" boste morali definirati izraz in tip za " -"transformacijo\r\n" -" znakovnega niza v datum ali časovno značko.\r\n" -" Trenutno časovni pasovi niso podprti.\r\n" -" Če je čas shranjen v obliki epohe, dodajte " -"`epoch_s` ali `epoch_ms`.\r\n" -" Če ni podan vzorec, se uporabijo privzete vrednosti" -" na podlagi imena\r\n" -" podatkovne baze oz. stolpca s pomočjo dodatnega " -"parametra." - -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:111 -msgid "!= (Is not equal)" -msgstr "!= (ni enako)" +#: superset/errors.py:105 +msgid "The hostname provided can't be resolved." +msgstr "Imena gostitelja ni mogoče razrešiti." -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:125 -#, fuzzy -msgid "" -"${tableName\n" -" .split('')\n" -" .slice(0, tableName.length - 1)\n" -" .join('')}\n" -" " -msgstr "" -"${tableName\r\n" -" .split('')\r\n" -" .slice(0, tableName.length - 1)\r\n" -" .join('')}\r\n" -" " +#: superset/errors.py:106 +msgid "The port is closed." +msgstr "Vrata so zaprta." -#: superset/security/analytics_db_safety.py:44 -#, python-format -msgid "%(dialect)s cannot be used as a data source for security reasons." -msgstr "" -"%(dialect)s ni mogoče uporabiti kot podatkovni vir zaradi varnostnih " -"razlogov." +#: superset/errors.py:107 +msgid "The host might be down, and can't be reached on the provided port." +msgstr "Gostitelj mogoče ne deluje in ga ni mogoče doseči preko podanih vrat." -#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:84 -#, fuzzy, python-format -msgid "" -"%(message)s\n" -"This may be triggered by: \n" -"%(issues)s" -msgstr "To je lahko sproženo z/s:" +#: superset/errors.py:108 +msgid "Superset encountered an error while running a command." +msgstr "Superset je naletel na napako pri izvajanju ukaza." -#: superset/reports/notifications/email.py:122 superset/tasks/schedules.py:364 -#, python-format -msgid "%(name)s.csv" -msgstr "%(name)s.csv" +#: superset/errors.py:109 +msgid "Superset encountered an unexpected error." +msgstr "Superset je naletel na nepričakovano napako." -#: superset/db_engine_specs/snowflake.py:99 -#, python-format -msgid "%(object)s does not exist in this database." -msgstr "%(object)s ne obstaja v tej podatkovni bazi." +#: superset/errors.py:110 +msgid "The username provided when connecting to a database is not valid." +msgstr "Uporabniško ime za povezavo s podatkovno bazo je neveljavno." -#: superset/reports/notifications/email.py:126 superset/tasks/schedules.py:296 -#: superset/tasks/schedules.py:465 -#, python-format -msgid "%(prefix)s %(title)s" -msgstr "%(prefix)s %(title)s" +#: superset/errors.py:111 +msgid "The password provided when connecting to a database is not valid." +msgstr "Geslo za povezavo s podatkovno bazo je neveljavno." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:635 -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:642 -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:656 -#, python-format -msgid "%(rows)d rows returned" -msgstr "%(rows)d vrnjenih vrstic" +#: superset/errors.py:112 +msgid "Either the username or the password is wrong." +msgstr "Uporabniško ime ali/in geslo sta napačna." -#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:93 -#, fuzzy, python-format -msgid "" -"%(subtitle)s\n" -"This may be triggered by:\n" -" %(issue)s" -msgstr "To je lahko sproženo z/s:" +#: superset/errors.py:113 +msgid "Either the database is spelled incorrectly or does not exist." +msgstr "Ime podatkovne baze je zapisano napačno ali pa ne obstaja." -#: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:88 -#, python-format -msgid "%(suggestion)s instead of \"%(undefinedParameter)s?\"" -msgstr "%(suggestion)s namesto \"%(undefinedParameter)s?\"" +#: superset/errors.py:114 +msgid "The schema was deleted or renamed in the database." +msgstr "Shema je bila izbrisana ali preimenovana v podatkovni bazi." -#: superset/views/core.py:366 -#, python-format -msgid "" -"%(user)s was granted the role %(role)s that gives access to the " -"%(datasource)s" +#: superset/errors.py:115 +msgid "User doesn't have the proper permissions." +msgstr "Uporabnik nima ustreznih dovoljenj." + +#: superset/errors.py:116 +msgid "One or more parameters needed to configure a database are missing." +msgstr "En ali več parametrov, potrebnih za nastavitev podatkovne baze, manjka." + +#: superset/errors.py:117 +msgid "The submitted payload has the incorrect format." +msgstr "Podani podatki so v neustrezni obliki." + +#: superset/errors.py:118 +msgid "The submitted payload has the incorrect schema." +msgstr "Podani podatki imajo neustrezno shemo." + +#: superset/errors.py:119 +msgid "Results backend needed for asynchronous queries is not configured." msgstr "" -"Uporabniku %(user)s je bila dodeljena vloga %(role)s, ki omogoča dostop " -"do %(datasource)s" +"Zaledni sistem za rezultate, potreben za asinhrone poizvedbe, ni konfiguriran." -#: superset/views/core.py:2773 -#, python-format -msgid "%(user)s's profile" -msgstr "Profil uporabnika: %(user)s" +#: superset/errors.py:120 +msgid "Database does not allow data manipulation." +msgstr "Podatkovna baza ne dovoljuje manipulacije podatkov." -#: superset/views/core.py:2442 -#, python-format +#: superset/errors.py:121 msgid "" -"%(validator)s was unable to check your query.\n" -"Please recheck your query.\n" -"Exception: %(ex)s" +"The CTAS (create table as select) doesn't have a SELECT statement at the end. " +"Please make sure your query has a SELECT as its last statement. Then, try running " +"your query again." msgstr "" -"%(validator)s ni mogel preveriti vaše poizvedbe.\n" -"Ponovno preverite poizvedbo.\n" -"Izjema: %(ex)s" +"CTAS (create table as select) na koncu nima SELECT stavka. Poskrbite, da bo v " +"poizvedbi SELECT zadnji stavek. Potem ponovno poženite poizvedbo." -#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:170 -#, python-format -msgid "%s - untitled" -msgstr "%s - neimenovan" +#: superset/errors.py:126 +msgid "CVAS (create view as select) query has more than one statement." +msgstr "CVAS (create view as select) poizvedba ima več kot en stavek." -#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:90 -#, python-format -msgid "%s Error" -msgstr "%s napaka" +#: superset/errors.py:127 +msgid "CVAS (create view as select) query is not a SELECT statement." +msgstr "CVAS (create view as select) poizvedba ni SELECT stavek." -#: superset-frontend/src/components/ListView/ListView.tsx:244 -#, python-format -msgid "%s Selected" -msgstr "Izbranih: %s" +#: superset/errors.py:128 +msgid "Query is too complex and takes too long to run." +msgstr "Poizvedba je prekompleksna in se izvaja predolgo." -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:685 -#, python-format -msgid "%s Selected (%s Physical, %s Virtual)" -msgstr "Izbranih: %s (fizični: %s, virtualni: %s)" +#: superset/errors.py:129 +msgid "The database is currently running too many queries." +msgstr "Podatkovna baza trenutno izvaja preveč poizvedb." -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:678 -#, python-format -msgid "%s Selected (Physical)" -msgstr "Izbranih: %s (fizični)" +#: superset/errors.py:130 +msgid "One or more parameters specified in the query are malformatted." +msgstr "En ali več parametrov v SQL-poizvedbi ima napačno obliko." -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:671 -#, python-format -msgid "%s Selected (Virtual)" -msgstr "Izbranih: %s (virtualni)" +#: superset/errors.py:131 +msgid "The object does not exist in the given database." +msgstr "Objekt ne obstaja v podani podatkovni bazi." -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:311 -#, python-format -msgid "%s aggregates(s)" -msgstr "Agreg. funkcije: %s" +#: superset/errors.py:132 +msgid "The query has a syntax error." +msgstr "Poizvedba ima sintaktično napako." -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:249 -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:270 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:286 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:302 -#, python-format -msgid "%s column(s)" -msgstr "Stolpci: %s" +#: superset/errors.py:133 +msgid "The results backend no longer has the data from the query." +msgstr "Zaledni sistem rezultatov nima več podatkov iz poizvedbe." -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:276 -#, python-format -msgid "%s column(s) and metric(s)" -msgstr "Stolpcev in mer: %s" +#: superset/errors.py:134 +msgid "The query associated with the results was deleted." +msgstr "Poizvedba, povezana z rezultati, je bila izbrisana." -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:297 -#, python-format -msgid "%s operator(s)" -msgstr "Operatorji: %s" +#: superset/errors.py:135 +msgid "" +"The results stored in the backend were stored in a different format, and no " +"longer can be deserialized." +msgstr "" +"Rezultati v zalednem sistemu so bili shranjeni v drugačni obliki in jih ni več " +"mogoče deserializirati." -#: superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx:83 -#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:256 -#: superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx:82 -#: superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx:92 -#, python-format -msgid "%s option" -msgstr "%s možnost" +#: superset/errors.py:139 +msgid "The port number is invalid." +msgstr "Številka vrat je neveljavna." -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:252 -#, python-format -msgid "%s option(s)" -msgstr "Možnosti: %s" +#: superset/errors.py:140 superset/sqllab/sql_json_executer.py:190 +msgid "Failed to start remote query on a worker." +msgstr "Na delavcu ni bilo mogoče zagnati oddaljene poizvedbe." + +#: superset/errors.py:141 +msgid "The database was deleted." +msgstr "Podatkovna baza je bila izbrisana." + +#: superset/connectors/sqla/utils.py:175 superset/errors.py:142 +msgid "Custom SQL fields cannot contain sub-queries." +msgstr "Prilagojena SQL-polja ne smejo vsebovati podpoizvedb." + +#: superset/databases/schemas.py:173 superset/exceptions.py:188 +msgid "Invalid certificate" +msgstr "Neveljaven certifikat" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:320 +#: superset/jinja_context.py:348 #, python-format -msgid "%s saved metric(s)" -msgstr "Shranjene mere: %s" +msgid "Unsafe return type for function %(func)s: %(value_type)s" +msgstr "Nevaren tip rezultata, ki ga vrne funkcija %(func)s: %(value_type)s" -#: superset-frontend/src/components/URLShortLinkButton/index.jsx:59 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:123 +#: superset/jinja_context.py:359 #, python-format -msgid "%s%s" -msgstr "%s%s" +msgid "Unsupported return value for method %(name)s" +msgstr "Nepodprt rezultat vračanja za metodo %(name)s" -#: superset-frontend/src/components/ListView/ListView.tsx:419 -#: superset-frontend/src/components/TableView/TableView.tsx:237 +#: superset/jinja_context.py:375 #, python-format -msgid "%s-%s of %s" -msgstr "%s-%s od %s" +msgid "Unsafe template value for key %(key)s: %(value_type)s" +msgstr "Nevaren vzorec za ključ %(key)s: %(value_type)s" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx:110 -msgid "(Removed)" -msgstr "(Odstranjeno)" +#: superset/jinja_context.py:386 +#, python-format +msgid "Unsupported template value for key %(key)s" +msgstr "Nepodprta vrednost vzorca za ključ %(key)s" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:637 -msgid "(deleted)" -msgstr "(izbrisano)" +#: superset/sql_lab.py:225 +msgid "Only SELECT statements are allowed against this database." +msgstr "Za to podatkovno bazo so dovoljeni le `SELECT` stavki." -#: superset-frontend/src/utils/getClientErrorObject.ts:56 -msgid "(no description, click to see stack trace)" -msgstr "(ni opisa, kliknite za ogled zapisov)" - -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:168 +#: superset/sql_lab.py:294 +#, python-format msgid "" -"(optional) default value for the filter, when using the multiple option, " -"you can use a semicolon-delimited list of options." +"The query was killed after %(sqllab_timeout)s seconds. It might be too complex, " +"or the database might be under heavy load." msgstr "" -"(opcijsko) privzeta vrednost za filter, če uporabite opcijo izbire večih " -", lahko uporabite seznam nastavitev ločen s podpičji." +"Poizvedba je bila ustavljena po %(sqllab_timeout)s sekundah. Lahko je " +"prekompleksna ali pa je podatkovna baza preobremenjena." -#: superset/reports/notifications/slack.py:50 -#, python-format +#: superset/sql_lab.py:404 superset/views/core.py:2178 +msgid "Results backend is not configured." +msgstr "Zaledni sistem rezultatov ni konfiguriran." + +#: superset/sql_lab.py:434 msgid "" -"*%(name)s*\n" -"\n" -"%(description)s\n" -"\n" -"<%(url)s|Explore in Superset>\n" -"\n" -"%(table)s\n" +"CTAS (create table as select) can only be run with a query where the last " +"statement is a SELECT. Please make sure your query has a SELECT as its last " +"statement. Then, try running your query again." msgstr "" -"*%(name)s*\n" -"\n" -"%(description)s\n" -"\n" -"<%(url)s|Razišči v Supersetu>\n" -"\n" -"%(table)s\n" +"CTAS (create table as select) lahko izvajate le v poizvedbah, kjer je zadnji " +"stavek SELECT. Poskrbite, da bo zadnji stavek v vaši poizvedbi SELECT in " +"poskusite ponovno zagnati poizvedbo." -#: superset/reports/notifications/slack.py:67 -#, python-format +#: superset/sql_lab.py:451 msgid "" -"*%(name)s*\n" -"\n" -"%(description)s\n" -"\n" -"Error: %(text)s\n" +"CVAS (create view as select) can only be run with a query with a single SELECT " +"statement. Please make sure your query has only a SELECT statement. Then, try " +"running your query again." msgstr "" -"*%(name)s*\n" -"\n" -"%(description)s\n" -"\n" -"napaka: %(text)s\n" +"CVAS (create view as select) lahko izvajate le v poizvedbah z enim SELECT " +"stavkom. Poskrbite, da bo v vaši poizvedbi le en SELECT stavek in poskusite " +"ponovno zagnati poizvedbo." -#: superset-frontend/src/explore/components/SaveModal.tsx:35 -msgid "**Select** a dashboard OR **create** a new one" -msgstr "**Izberite** nadzorno ploščo ALI **ustvarite** novo" +#: superset/viz.py:140 +msgid "Viz is missing a datasource" +msgstr "Vizualizaciji manjka podatkovni vir" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:260 +#: superset/viz.py:244 msgid "" -"-- Note: Unless you save your query, these tabs will NOT persist if you " -"clear your cookies or change browsers.\n" -"\n" +"Applied rolling window did not return any data. Please make sure the source query " +"satisfies the minimum periods defined in the rolling window." msgstr "" +"Izbrano drseče okno ni vrnilo podatkov. Poskrbite, da izvorna poizvedba ustreza " +"minimalni periodi drsečega okna." -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:668 -msgid "0 Selected" -msgstr "Izbranih: 0" - -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:35 -msgid "1 hour" -msgstr "1 ura" +#: superset/utils/date_parser.py:267 superset/viz.py:383 +msgid "From date cannot be larger than to date" +msgstr "Začetni datum ne sme biti večji od končnega datuma" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:32 -msgid "1 minute" -msgstr "1 minuta" +#: superset/viz.py:554 +msgid "Cached value not found" +msgstr "Predpomnjena vrednost ni najdena" -#: superset/db_engine_specs/base.py:91 -msgid "10 minute" -msgstr "10 minut" +#: superset/common/query_context_processor.py:121 superset/viz.py:569 +#, python-format +msgid "Columns missing in datasource: %(invalid_columns)s" +msgstr "V podatkovnem viru manjkajo stolpci: %(invalid_columns)s" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:30 -msgid "10 seconds" -msgstr "10 sekund" +#: superset/viz.py:690 +msgid "Table View" +msgstr "Tabelarični pogled" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:37 -msgid "12 hours" -msgstr "12 ur" +#: superset/viz.py:715 +msgid "" +"You cannot use [Columns] in combination with [Group By]/[Metrics]/[Percentage " +"Metrics]. Please choose one or the other." +msgstr "" +"Ne smete uporabiti [Stolpci] v kombinaciji z [Združevanje]/[Mere]/[Procentualne " +"mere]. Izberite eno ali drugo." -#: superset/db_engine_specs/base.py:92 -msgid "15 minute" -msgstr "15 minut" +#: superset/viz.py:761 +msgid "Pick a granularity in the Time section or uncheck 'Include Time'" +msgstr "Izberite granulacijo v razdelku 'Čas' ali odstranite 'Vključi čas'" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:38 -msgid "24 hours" -msgstr "24 ur" +#: superset/viz.py:841 +msgid "Time Table View" +msgstr "Pogled urnika" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:32 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:35 -msgid "2D" -msgstr "2D" +#: superset/viz.py:849 superset/viz.py:1805 +msgid "Pick at least one metric" +msgstr "Izberite vsaj eno mero" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:116 -msgid "3 letter code of the country" -msgstr "Tričrkovna oznaka države" +#: superset/viz.py:853 +msgid "When using 'Group By' you are limited to use a single metric" +msgstr "Ko uporabljate 'Group By', ste omejeni na uporabo ene mere" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:128 -msgid "30 days" -msgstr "30 dni" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:30 +#: superset/viz.py:886 +msgid "Pivot Table" +msgstr "Vrtilna tabela" -#: superset/db_engine_specs/base.py:93 -msgid "30 minute" -msgstr "30 minut" +#: superset/viz.py:903 +msgid "Please choose at least one 'Group by' field " +msgstr "Izberite vsaj eno 'Group by' polje " -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:34 -msgid "30 minutes" -msgstr "30 minut" +#: superset/viz.py:915 +msgid "Please choose at least one metric" +msgstr "Izberite vsaj eno mero" -#: superset/db_engine_specs/base.py:88 -msgid "30 second" -msgstr "30 sekund" +#: superset/viz.py:919 +msgid "Group By' and 'Columns' can't overlap" +msgstr "'Združevanje' in 'Stolpci' se ne smeta prekrivati" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:31 -msgid "30 seconds" -msgstr "30 sekund" +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:40 +#: superset/viz.py:1027 +msgid "Treemap" +msgstr "Drevesni grafikon s pravokotniki" -#: superset/db_engine_specs/base.py:90 -msgid "5 minute" -msgstr "5 minut" +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:30 +#: superset/viz.py:1072 +msgid "Calendar Heatmap" +msgstr "Koledarska barvna lestvica" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:33 -msgid "5 minutes" -msgstr "5 minut" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:30 +#: superset/viz.py:1163 +msgid "Bubble Chart" +msgstr "Mehurčkasti grafikon" -#: superset/db_engine_specs/base.py:87 -msgid "5 second" -msgstr "5 sekund" +#: superset/viz.py:1185 +msgid "Please use 3 different metric labels" +msgstr "Uporabite 3 različne oznake mer" -#: superset/db_engine_specs/base.py:95 -msgid "6 hour" -msgstr "6 ur" +#: superset/viz.py:1187 +msgid "Pick a metric for x, y and size" +msgstr "Izberite mere za x, y in velikost" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:36 -msgid "6 hours" -msgstr "6 ur" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:30 +#: superset/viz.py:1214 +msgid "Bullet Chart" +msgstr "'Bullet' grafikon" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:132 -msgid "60 days" -msgstr "60 dni" +#: superset/viz.py:1226 +msgid "Pick a metric to display" +msgstr "Izberite mero za prikaz" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:136 -msgid "90 days" -msgstr "90 dni" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:36 +#: superset/viz.py:1244 +msgid "Big Number with Trendline" +msgstr "Velika številka s trendno krivuljo" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:49 -msgid ":" -msgstr ":" +#: superset/viz.py:1252 superset/viz.py:1286 +msgid "Pick a metric!" +msgstr "Izberite mero!" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:86 -msgid "< (Smaller than)" -msgstr "< (manjše kot)" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:37 +#: superset/viz.py:1278 +msgid "Big Number" +msgstr "Velika številka" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:96 -msgid "<= (Smaller or equal)" -msgstr "<= (manjše ali enako)" +#: superset/viz.py:1300 +msgid "Time Series - Line Chart" +msgstr "Časovna vrsta - Črtni grafikon" -#: superset/tasks/schedules.py:171 superset/tasks/schedules.py:365 -#, python-format -msgid "<b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>" -msgstr "<b><a href=\"%(url)s\">Razišči v Supersetu</a></b><p></p>" +#: superset/viz.py:1382 superset/viz.py:1645 +msgid "Pick a time granularity for your time series" +msgstr "Izberite granulacijo časa za časovno vrsto" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:106 -msgid "== (Is equal)" -msgstr "== (je enako)" +#: superset/common/query_context_processor.py:272 superset/viz.py:1439 +msgid "" +"An enclosed time range (both start and end) must be specified when using a Time " +"Comparison." +msgstr "" +"Pri časovni primerjavi mora biti določeno zaprto časovno obdobje (s časom začetka " +"in konca)." -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:91 -msgid "> (Larger than)" -msgstr "> (večje kot)" +#: superset/viz.py:1510 +msgid "Time Series - Multiple Line Charts" +msgstr "Časovna vrsta - Veččrtni grafikon" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:101 -msgid ">= (Larger or equal)" -msgstr ">= (večje ali enako)" +#: superset/viz.py:1588 +msgid "Time Series - Dual Axis Line Chart" +msgstr "Časovna vrsta - Črtni grafikon z dvojno osjo" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:35 -msgid "A Big Number" -msgstr "Velika številka" +#: superset/viz.py:1597 +msgid "Pick a metric for left axis!" +msgstr "Izberite mero za levo os!" -#: superset/views/alerts.py:195 -msgid "" -"A SQL statement that defines whether the alert should get triggered or " -"not. The query is expected to return either NULL or a number value." -msgstr "" -"SQL izraz, ki definira ali naj se opozorilo sproži ali ne. Od poizvedbe " -"se pričakuje, da vrne bodisi NULL bodisi številsko vrednost." +#: superset/viz.py:1599 +msgid "Pick a metric for right axis!" +msgstr "Izberite mero za desno os!" -#: superset/views/database/forms.py:204 superset/views/database/forms.py:341 -msgid "A comma separated list of columns that should be parsed as dates." -msgstr "Z vejico ločen seznam stolpcev, v katerih bodo prepoznani datumi." +#: superset/viz.py:1602 +msgid "Please choose different metrics on left and right axis" +msgstr "Izberite različni meri za levo in desno os" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:383 -msgid "A comma-separated list of schemas that CSVs are allowed to upload to." -msgstr "Z vejicami ločen seznam shem, kjer je dovoljeno nalaganje CSV-jev." +#: superset/viz.py:1662 +msgid "Time Series - Bar Chart" +msgstr "Časovna vrsta - Stolpčni grafikon" -#: superset/databases/commands/exceptions.py:42 -msgid "A database with the same name already exists." -msgstr "Podatkovna baza z enakim imenom že obstaja." +#: superset/viz.py:1671 +msgid "Time Series - Period Pivot" +msgstr "Časovna vrsta - Vrtenje period" -#: superset/views/dynamic_plugins.py:52 -msgid "" -"A full URL pointing to the location of the built plugin (could be hosted " -"on a CDN for example)" -msgstr "" -"Celoten URL, ki kaže na lokacijo zgrajenega vtičnika (lahko gostuje npr. " -"na CDN)" +#: superset/viz.py:1717 +msgid "Time Series - Percent Change" +msgstr "Časovna vrsta - Procentualna sprememba" -#: superset/views/dynamic_plugins.py:47 -msgid "A human-friendly name" -msgstr "Človeku prijazno ime" +#: superset/viz.py:1725 +msgid "Time Series - Stacked" +msgstr "Časovna vrsta - Naložen graf" -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:300 -msgid "A list of users who can alter the chart. Searchable by name or username." -msgstr "" -"Seznam uporabnikov, ki lahko spreminjajo ta grafikon. Možno je iskanje po" -" imenu ali uporabniškem imenu." +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:37 +#: superset/viz.py:1735 +msgid "Histogram" +msgstr "Histogram" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:29 -msgid "A map of the world, that can indicate values in different countries." -msgstr "Zemljevid sveta, ki lahko prikazuje vrednosti po državah." +#: superset/viz.py:1744 +msgid "Must have at least one numeric column specified" +msgstr "Definiran mora biti vsaj en numerični stolpec" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:161 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:209 -#: superset-frontend/src/explore/controls.jsx:238 -msgid "A metric to use for color" -msgstr "Mera za barvo" +#: superset/viz.py:1793 +msgid "Distribution - Bar Chart" +msgstr "Porazdelitev - Stolpčni grafikon" -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:26 -msgid "" -"A polar coordinate chart where the circle is broken into wedges of equal " -"angle, and the value represented by any wedge is illustrated by its area," -" rather than its radius or sweep angle." -msgstr "" -"Grafikon s polarnimi koordinatami, kjer je krog razdeljen na enakokotne " -"izseke, vrednosti pa so ponazorjene s ploščino izseka (namesto polmera " -"ali kota)." +#: superset/viz.py:1802 +msgid "Can't have overlap between Series and Breakdowns" +msgstr "Ne sme imeti prekrivanja med podatkovnimi serijami in členitvami" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:523 -msgid "A readable URL for your dashboard" -msgstr "Berljiv URL za vašo nadzorno ploščo" +#: superset/viz.py:1807 +msgid "Pick at least one field for [Series]" +msgstr "Izberite vsaj eno polje za [Serije]" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:39 -#: superset-frontend/src/explore/controls.jsx:113 -msgid "A reference to the [Time] configuration, taking granularity into account" -msgstr "Sklic na nastavitve za [Čas], ki upošteva granulacijo" +#: superset/viz.py:1880 +msgid "Sunburst" +msgstr "Sunburst" -#: superset/views/alerts.py:189 -msgid "A semicolon ';' delimited list of email addresses" -msgstr "S podpičjem ';' ločen seznam naslovov e-pošte" +#: superset/viz.py:1927 +msgid "Sankey" +msgstr "Sankey" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:789 -#: superset/connectors/sqla/views.py:469 -msgid "" -"A set of parameters that become available in the query using Jinja " -"templating syntax" -msgstr "" -"Nabor parametrov, ki postanejo razpoložljivi za poizvedbo z uporabo " -"sintakse za Jinja predloge" +#: superset/viz.py:1935 +msgid "Pick exactly 2 columns as [Source / Target]" +msgstr "Izberite natanko dva stolpca za [Izvor / Cilj]" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:32 +#: superset/viz.py:1984 msgid "" -"A time series chart that visualizes how a related metric from multiple " -"groups vary over time. Each group is visualized using a different color." -msgstr "" -"Grafikon časovne vrste, ki prikaže kako se povezane mere skupin " -"spreminjajo skozi čas. Vsaka skupina je prikazana s svojo barvo." +"There's a loop in your Sankey, please provide a tree. Here's a faulty link: {}" +msgstr "V 'Sankey' je zanka, določite drevo. To je okvarjena povezava: {}" -#: superset/reports/commands/exceptions.py:198 -msgid "A timeout occurred while executing the query." -msgstr "Pri izvajanju poizvedbe je potekel čas." +#: superset/viz.py:1997 +msgid "Directed Force Layout" +msgstr "Izgled usmerjene sile" -#: superset/reports/commands/exceptions.py:206 -msgid "A timeout occurred while generating a csv." -msgstr "Pri ustvarjanju csv je potekel čas." - -#: superset/reports/commands/exceptions.py:210 -msgid "A timeout occurred while generating a dataframe." -msgstr "Pri ustvarjanju podatkovnega okvira je potekel čas." - -#: superset/reports/commands/exceptions.py:202 -msgid "A timeout occurred while taking a screenshot." -msgstr "Pri ustvarjanju zaslonske slike je potekel čas." +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:30 +#: superset/viz.py:2036 +msgid "Country Map" +msgstr "Zemljevid držav" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:168 -msgid "A valid color scheme is required" -msgstr "Zahtevana je veljavna barvna shema" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:33 +#: superset/viz.py:2071 +msgid "World Map" +msgstr "Zemljevid sveta" -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:344 -msgid "APPLY" -msgstr "UPORABI" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:95 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:508 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:88 +#: superset-frontend/src/explore/controls.jsx:462 superset/viz.py:2134 +msgid "Filters" +msgstr "Filtri" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:94 -msgid "APR" -msgstr "APR" +#: superset/viz.py:2152 +msgid "Invalid filter configuration, please select a column" +msgstr "Neveljavna nastavitev filtrov, izberite stolpec" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:239 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:404 -msgid "AQE" -msgstr "AQE" +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:30 +#: superset/viz.py:2211 +msgid "Parallel Coordinates" +msgstr "Vzporedne koordinate" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:98 -msgid "AUG" -msgstr "AVG" +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:38 +#: superset/viz.py:2241 +msgid "Heatmap" +msgstr "Toplotni prikaz" -#: superset-frontend/src/components/Menu/MenuRight.tsx:176 -msgid "About" -msgstr "O programu" +#: superset/viz.py:2302 +msgid "Horizon Charts" +msgstr "Horizontni grafikon" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:354 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:397 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:287 -msgid "Access" -msgstr "Dostop" +#: superset/viz.py:2314 +msgid "Mapbox" +msgstr "Mapbox" -#: superset/initialization/__init__.py:491 -msgid "Access requests" -msgstr "Zahteve za dostop" +#: superset/viz.py:2328 +msgid "[Longitude] and [Latitude] must be set" +msgstr "[Zemljepisna dolžina] in [Zemljepisna širina] morata biti nastavljeni" -#: superset/views/core.py:300 -msgid "Access was requested" -msgstr "Zahtevan je bil dostop" +#: superset/viz.py:2338 +msgid "Must have a [Group By] column to have 'count' as the [Label]" +msgstr "Mora imeti stolpec [Združevanje], da ima število (count) kot [Oznaka]" -#: superset/views/log/__init__.py:31 -msgid "Action" -msgstr "Aktivnost" +#: superset/viz.py:2362 +msgid "Choice of [Label] must be present in [Group By]" +msgstr "Izbira [Oznaka] mora biti prisotna v [Združevanje]" -#: superset/initialization/__init__.py:419 -msgid "Action Log" -msgstr "Dnevnik aktivnosti" +#: superset/viz.py:2370 +msgid "Choice of [Point Radius] must be present in [Group By]" +msgstr "Izbran [Point Radius] mora biti prisoten v [Združevanje]" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:335 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:189 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:249 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:420 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:229 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:417 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:375 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:405 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:309 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:413 -msgid "Actions" -msgstr "Aktivnosti" +#: superset/viz.py:2378 +msgid "[Longitude] and [Latitude] columns must be present in [Group By]" +msgstr "" +"Stolpca [Zemljepisna dolžina] in [Zemljepisna širina] morata biti prisotna v " +"[Združevanje]" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:290 -#: superset/views/schedules.py:240 superset/views/schedules.py:320 -msgid "Active" -msgstr "Aktiven" +#: superset/viz.py:2460 +msgid "Deck.gl - Multiple Layers" +msgstr "Deck.gl - Večplastni" -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:316 -msgid "Actual time range" -msgstr "Dejansko časovno obdobje" +#: superset/viz.py:2501 superset/viz.py:2537 +msgid "Bad spatial key" +msgstr "Neustrezen prostorski ključ" -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:28 -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:49 -msgid "Adaptive formatting" -msgstr "Adaptivno oblikovanje" +#: superset/viz.py:2522 +#, python-format +msgid "Invalid spatial point encountered: %s" +msgstr "Neustrezna prostorska točka: %s" -#: superset-frontend/src/components/ReportModal/index.tsx:267 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitlePane.tsx:133 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1039 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:273 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:226 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:220 -#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:119 -msgid "Add" -msgstr "Dodaj" +#: superset/viz.py:2559 +msgid "" +"Encountered invalid NULL spatial entry, " +"please consider filtering those out" +msgstr "" +"Prišlo je do neveljavnega NULL prostorskega " +"vnosa, poskusite ga izločiti s filtrom" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1056 -#, fuzzy -msgid "Add Alert" -msgstr "opozorilo" +#: superset/viz.py:2654 +msgid "Deck.gl - Scatter plot" +msgstr "Deck.gl - Raztreseni graf" -#: superset/views/annotations.py:60 -msgid "Add Annotation" -msgstr "Dodaj oznako" +#: superset/viz.py:2706 +msgid "Deck.gl - Screen Grid" +msgstr "Deck.gl - Mreža" -#: superset/views/annotations.py:119 -msgid "Add Annotation Layer" -msgstr "Dodaj sloj z oznakami" +#: superset/viz.py:2735 +msgid "Deck.gl - 3D Grid" +msgstr "Deck.gl - 3D mreža" -#: superset/views/css_templates.py:38 -msgid "Add CSS Template" -msgstr "Dodaj CSS predlogo" +#: superset/viz.py:2767 +msgid "Deck.gl - Paths" +msgstr "Deck.gl - Poti" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:232 -msgid "Add CSS template" -msgstr "Dodaj CSS predlogo" +#: superset/viz.py:2818 +msgid "Deck.gl - Polygon" +msgstr "Deck.gl - Poligon" -#: superset/views/chart/mixin.py:28 -msgid "Add Chart" -msgstr "Dodaj grafikon" +#: superset/viz.py:2851 +msgid "Deck.gl - 3D HEX" +msgstr "Deck.gl - 3D HEX" -#: superset/connectors/sqla/views.py:65 -msgid "Add Column" -msgstr "Dodaj stolpec" +#: superset/viz.py:2872 +msgid "Deck.gl - GeoJSON" +msgstr "Deck.gl - GeoJSON" -#: superset/views/dashboard/mixin.py:27 -msgid "Add Dashboard" -msgstr "Dodaj nadzorno ploščo" +#: superset/viz.py:2891 +msgid "Deck.gl - Arc" +msgstr "Deck.gl - Arc" -#: superset/views/database/mixins.py:35 -msgid "Add Database" -msgstr "Dodaj podatkovno bazo" +#: superset/viz.py:2925 +msgid "Event flow" +msgstr "Potek dogodkov" -#: superset/connectors/druid/views.py:215 -msgid "Add Druid Cluster" -msgstr "Dodaj Druid gručo" +#: superset/viz.py:2957 +msgid "Time Series - Paired t-test" +msgstr "Časovna vrsta - t-test za odvisne vzorce" -#: superset/connectors/druid/views.py:72 -msgid "Add Druid Column" -msgstr "Dodaj Druid stolpec" +#: superset/viz.py:3029 +msgid "Time Series - Nightingale Rose Chart" +msgstr "Časovna vrsta - Nightingale Rose grafikon" -#: superset/connectors/druid/views.py:279 -msgid "Add Druid Datasource" -msgstr "Dodaj podatkovni vir za Druid" +#: superset/viz.py:3064 +msgid "Partition Diagram" +msgstr "Grafikon s pravokotniki" -#: superset/connectors/druid/views.py:161 -msgid "Add Druid Metric" -msgstr "Dodaj Druid mere" +#: superset/advanced_data_type/api.py:100 +#, python-format +msgid "Invalid advanced data type: %(advanced_data_type)s" +msgstr "Neveljaven napreden tip rezultata: %(advanced_data_type)s" -#: superset/views/log/__init__.py:23 -msgid "Add Log" -msgstr "Dodaj dnevnik" +#: superset/annotation_layers/api.py:355 +#, python-format +msgid "Deleted %(num)d annotation layer" +msgid_plural "Deleted %(num)d annotation layers" +msgstr[0] "Izbrisan je %(num)d sloj z oznakami" +msgstr[1] "Izbrisana sta %(num)d sloja z oznakami" +msgstr[2] "Izbrisanih so %(num)d sloji z oznakami" +msgstr[3] "Izbrisanih je %(num)d slojev z oznakami" -#: superset/connectors/sqla/views.py:214 -msgid "Add Metric" -msgstr "Dodaj mero" +#: superset/annotation_layers/annotations/filters.py:28 +#: superset/annotation_layers/filters.py:30 superset/charts/filters.py:31 +#: superset/css_templates/filters.py:28 superset/queries/saved_queries/filters.py:31 +#: superset/reports/filters.py:28 +msgid "All Text" +msgstr "Celotno besedilo" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1055 -#, fuzzy -msgid "Add Report" -msgstr "poročilo" +#: superset/annotation_layers/annotations/api.py:504 +#, python-format +msgid "Deleted %(num)d annotation" +msgid_plural "Deleted %(num)d annotations" +msgstr[0] "Izbrisana je %(num)d oznaka" +msgstr[1] "Izbrisani sta %(num)d oznaki" +msgstr[2] "Izbrisane so %(num)d oznake" +msgstr[3] "Izbrisanih je %(num)d oznak" -#: superset/connectors/sqla/views.py:316 -msgid "Add Row level security filter" -msgstr "Dodaj filter za varnost na nivoju vrstic" +#: superset/annotation_layers/annotations/commands/exceptions.py:35 +msgid "End date must be after start date" +msgstr "Končni datum mora biti za začetnim" -#: superset/views/sql_lab.py:41 -msgid "Add Saved Query" -msgstr "Dodaj shranjeno poizvedbo" +#: superset/annotation_layers/annotations/commands/exceptions.py:46 +msgid "Short description must be unique for this layer" +msgstr "Kratek opis mora biti za ta sloj unikaten" -#: superset/views/dynamic_plugins.py:60 -msgid "Add a Plugin" -msgstr "Dodaj vtičnik" +#: superset/annotation_layers/annotations/commands/exceptions.py:52 +msgid "Annotations could not be deleted." +msgstr "Oznak ni mogoče izbrisati." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:175 -msgid "Add additional custom parameters" -msgstr "Dodaj dodatne parametre po meri" +#: superset/annotation_layers/annotations/commands/exceptions.py:56 +msgid "Annotation not found." +msgstr "Oznaka ni najdena." -#: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:63 -msgid "Add an item" -msgstr "Dodaj element" +#: superset/annotation_layers/annotations/commands/exceptions.py:60 +msgid "Annotation parameters are invalid." +msgstr "Parametri oznak so neveljavni." -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:283 -msgid "Add annotation" -msgstr "Dodaj oznako" +#: superset/annotation_layers/annotations/commands/exceptions.py:64 +msgid "Annotation could not be created." +msgstr "Oznake ni mogoče ustvariti." -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:201 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:213 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:238 -msgid "Add annotation layer" -msgstr "Dodaj sloj z oznakami" +#: superset/annotation_layers/annotations/commands/exceptions.py:68 +msgid "Annotation could not be updated." +msgstr "Oznake ni mogoče posodobiti." -#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:121 -msgid "Add dataset" -msgstr "Dodaj podatkovni set" +#: superset/annotation_layers/annotations/commands/exceptions.py:72 +msgid "Annotation delete failed." +msgstr "Izbris oznake ni uspel." -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:387 -msgid "Add delivery method" -msgstr "Dodajte način dostave" +#: superset/annotation_layers/commands/exceptions.py:29 +msgid "Annotation layer parameters are invalid." +msgstr "Parametri sloja z oznakami so neveljavni." -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx:367 -msgid "Add filter" -msgstr "Dodaj filter" +#: superset/annotation_layers/commands/exceptions.py:33 +msgid "Annotation layer could not be deleted." +msgstr "Sloja z oznakami ni mogoče izbrisati." -#: superset-frontend/src/CRUD/CollectionTable.tsx:417 -msgid "Add item" -msgstr "Dodaj" +#: superset/annotation_layers/commands/exceptions.py:37 +msgid "Annotation layer could not be created." +msgstr "Sloja z oznakami ni mogoče ustvariti." -#: superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.jsx:336 -msgid "Add metric" -msgstr "Dodaj mero" +#: superset/annotation_layers/commands/exceptions.py:41 +msgid "Annotation layer could not be updated." +msgstr "Sloja z oznakami ni mogoče posodobiti." -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:176 -msgid "Add new color formatter" -msgstr "Dodaj novo oblikovanje barve" +#: superset/annotation_layers/commands/exceptions.py:45 +msgid "Annotation layer not found." +msgstr "Sloja z oznakami ni mogoče najti." -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:169 -msgid "Add new formatter" -msgstr "Dodaj novo oblikovanje" +#: superset/annotation_layers/commands/exceptions.py:49 +msgid "Annotation layer delete failed." +msgstr "Izbris sloja z oznakami ni uspel." -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:386 -msgid "Add notification method" -msgstr "Dodajte način obveščanja" +#: superset/annotation_layers/commands/exceptions.py:53 +#: superset/annotation_layers/commands/exceptions.py:57 +msgid "Annotation layer has associated annotations." +msgstr "Sloj z oznakami ima povezane oznake." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:99 -msgid "Add sheet" -msgstr "Dodaj preglednico" +#: superset/annotation_layers/commands/exceptions.py:66 +msgid "Name must be unique" +msgstr "Ime mora biti unikatno" -#: superset-frontend/src/explore/components/SaveModal.tsx:258 -msgid "Add to dashboard" -msgstr "Dodaj na nadzorno ploščo" +#: superset/charts/api.py:483 +#, python-format +msgid "Deleted %(num)d chart" +msgid_plural "Deleted %(num)d charts" +msgstr[0] "Izbrisan je %(num)d grafikon" +msgstr[1] "Izbrisana sta %(num)d grafikona" +msgstr[2] "Izbrisani so %(num)d grafikoni" +msgstr[3] "Izbrisanih je %(num)d grafikonov" -#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:141 -msgid "Added" -msgstr "Dodano" +#: superset/charts/filters.py:63 superset/dashboards/filters.py:219 +#: superset/datasets/filters.py:39 +msgid "Is certified" +msgstr "Certificiran" -#: superset/connectors/druid/models.py:256 -msgid "Adding new datasource [{}]" -msgstr "Dodajanje novega podatkovnega vira [{}]" +#: superset/charts/schemas.py:566 +msgid "`confidence_interval` must be between 0 and 1 (exclusive)" +msgstr "`confidence_interval` mora biti med 0 in 1 (odprt)" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:173 -#, fuzzy -msgid "Additional Parameters" -msgstr "Dodatni parametri" +#: superset/charts/schemas.py:638 +msgid "" +"lower percentile must be greater than 0 and less than 100. Must be lower than " +"upper percentile." +msgstr "" +"spodnji percentil mora biti večji od 0 in manjši od 100 ter mora biti manjši od " +"zgornjega percentila." -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:324 -msgid "Additional information" -msgstr "Dodatne informacije" +#: superset/charts/schemas.py:653 +msgid "" +"upper percentile must be greater than 0 and less than 100. Must be higher than " +"lower percentile." +msgstr "" +"zgornji percentil mora biti večji od 0 in manjši od 100 ter mora biti večji od " +"spodnjega percentila." -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:96 -msgid "Additional metadata" -msgstr "Dodatni metapodatki" +#: superset/charts/schemas.py:968 +msgid "`width` must be greater or equal to 0" +msgstr "`width` mora biti večja ali enaka 0" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:50 -msgid "Additional padding for legend." -msgstr "Dodatni razmak za legendo." +#: superset/charts/schemas.py:1110 +msgid "`row_limit` must be greater than or equal to 0" +msgstr "`row_limit` mora biti večja ali enaka 0" -#: superset/db_engine_specs/base.py:1398 -msgid "Additional parameters" -msgstr "Dodatni parametri" +#: superset/charts/schemas.py:1117 +msgid "`row_offset` must be greater than or equal to 0" +msgstr "`row_offset` mora biti večja ali enaka 1" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:166 -msgid "Additional text to add before or after the value, e.g. unit" -msgstr "Dodatno besedilo, ki ga dodate pred ali za vrednost, npr. enota" +#: superset/charts/schemas.py:1139 +msgid "orderby column must be populated" +msgstr "stolpec za razvrščanje (orderby) mora biti izpolnjen" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:40 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:40 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:43 -msgid "Additive" -msgstr "Aditivno" +#: superset/charts/commands/bulk_delete.py:64 superset/charts/commands/delete.py:68 +#: superset/dashboards/commands/bulk_delete.py:65 +#: superset/dashboards/commands/delete.py:66 +#: superset/databases/commands/delete.py:65 +#, python-format +msgid "There are associated alerts or reports: %s," +msgstr "Prisotna so opozorila in poročila: %s," -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:765 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:580 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:267 -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:34 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1146 -msgid "Advanced" -msgstr "Napredno" +#: superset/charts/commands/exceptions.py:38 +#, python-format +msgid "" +"Time string is ambiguous. Please specify [%(human_readable)s ago] or " +"[%(human_readable)s later]." +msgstr "" +"Časovni niz je nejasen. Podajte [%(human_readable)s ago] ali [%(human_readable)s " +"later]." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:122 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:242 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:125 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:148 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:375 -msgid "Advanced Analytics" -msgstr "Napredna analitika" +#: superset/charts/commands/exceptions.py:51 +#, python-format +msgid "Cannot parse time string [%(human_readable)s]" +msgstr "Ni mogoče razčleniti časovnega izraza [%(human_readable)s]" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:25 -#: superset-frontend/src/explore/controlPanels/sections.tsx:144 -msgid "Advanced analytics" -msgstr "Napredna analitika" +#: superset/charts/commands/exceptions.py:66 +#, python-format +msgid "" +"Time delta is ambiguous. Please specify [%(human_readable)s ago] or " +"[%(human_readable)s later]." +msgstr "" +"Časovna razlika je nejasna. Podajte [%(human_readable)s ago] ali " +"[%(human_readable)s later]." -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:32 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:36 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:35 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:79 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:79 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:74 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:64 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:71 -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:124 -msgid "Advanced-Analytics" -msgstr "Napredna analitika" +#: superset/charts/commands/exceptions.py:82 +#: superset/datasets/commands/exceptions.py:41 +#: superset/reports/commands/exceptions.py:36 +msgid "Database does not exist" +msgstr "Podatkovna baza ne obstaja" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:36 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:36 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:33 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:39 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:70 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:65 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:80 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:80 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:75 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:74 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:74 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:65 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:58 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:41 -msgid "Aesthetic" -msgstr "Estetika" +#: superset/charts/commands/exceptions.py:91 +msgid "Dashboards do not exist" +msgstr "Nadzorna plošča ne obstaja" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:84 -msgid "After" -msgstr "PO" +#: superset/charts/commands/exceptions.py:101 +msgid "Datasource type is required when datasource_id is given" +msgstr "Ko se podaja datasource_id, je potreben tip podatkovnega vira" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:45 -msgid "Aggregate" -msgstr "Agregacija" +#: superset/charts/commands/exceptions.py:111 +msgid "Chart parameters are invalid." +msgstr "Parametri grafikona so neveljavni." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:91 -msgid "Aggregate Mean" -msgstr "Agregirano povprečje" +#: superset/charts/commands/exceptions.py:115 +msgid "Chart could not be created." +msgstr "Grafikona ni mogoče ustvariti." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:96 -msgid "Aggregate Sum" -msgstr "Agregirana vsota" +#: superset/charts/commands/exceptions.py:119 +msgid "Chart could not be updated." +msgstr "Grafikona ni mogoče posodobiti." -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:182 -msgid "" -"Aggregate function applied to the list of points in each cluster to " -"produce the cluster label." -msgstr "" -"Agregacijska funkcija za seznam točk v vsaki gruči, s katero se ustvari " -"oznaka gruče." +#: superset/charts/commands/exceptions.py:123 +msgid "Chart could not be deleted." +msgstr "Grafikona ni mogoče izbrisati." -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:74 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:137 -msgid "" -"Aggregate function to apply when pivoting and computing the total rows " -"and columns" -msgstr "Agregacijska funkcija za vrtenje in izračun vseh vrstic in stolpcev" +#: superset/charts/commands/exceptions.py:127 +#: superset/charts/commands/exceptions.py:151 +#: superset/dashboards/commands/exceptions.py:62 +#: superset/dashboards/commands/exceptions.py:74 +#: superset/databases/commands/exceptions.py:119 +msgid "There are associated alerts or reports" +msgstr "Prisotna so povezana opozorila in poročila" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:63 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:114 -msgid "Aggregation function" -msgstr "Agregacijska funkcija" +#: superset/charts/commands/exceptions.py:131 +msgid "You don't have access to this chart." +msgstr "Nimate dostopa do tega grafikona." -#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:92 -msgid "Alert Triggered, In Grace Period" -msgstr "Opozorilo sproženo, v obdobju mirovanja" +#: superset/charts/commands/exceptions.py:135 +msgid "Changing this chart is forbidden" +msgstr "Spreminjanje tega grafikona ni dovoljeno" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1123 -msgid "Alert condition" -msgstr "Status opozorila" +#: superset/charts/commands/exceptions.py:139 +msgid "Charts could not be deleted." +msgstr "Grafikonov ni mogoče izbrisati." -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1215 -msgid "Alert condition schedule" -msgstr "Urnik statusov opozoril" +#: superset/charts/commands/exceptions.py:155 +msgid "Import chart failed for an unknown reason" +msgstr "Uvoz grafikona ni uspel zaradi neznanega razloga" -#: superset/reports/commands/exceptions.py:218 -msgid "Alert ended grace period." -msgstr "Opozorilo je končalo obdobje mirovanja." +#: superset/charts/data/api.py:123 +msgid "Chart has no query context saved. Please save the chart again." +msgstr "Grafikon nima shranjenega konteksta poizvedbe. Ponovno shranite grafikon." -#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:82 -msgid "Alert failed" -msgstr "Opozorilo ni uspelo" +#: superset/charts/data/api.py:143 superset/charts/data/api.py:231 +#: superset/charts/data/api.py:297 +#, python-format +msgid "Request is incorrect: %(error)s" +msgstr "Zahtevek je napačen: %(error)s" -#: superset/reports/commands/exceptions.py:214 -msgid "Alert fired during grace period." -msgstr "Opozorilo sproženo med obdobjem mirovanja." +#: superset/charts/data/api.py:220 +msgid "Request is not JSON" +msgstr "Zahtevek ni JSON" -#: superset/reports/commands/exceptions.py:194 -msgid "Alert found an error while executing a query." -msgstr "Opozorilo je našlo napako pri izvajanju poizvedbe." +#: superset/charts/data/api.py:351 +msgid "Empty query result" +msgstr "Rezultat prazne poizvedbe" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1064 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1072 -msgid "Alert name" -msgstr "Naslov opozorila" +#: superset/commands/exceptions.py:108 superset/datasets/commands/exceptions.py:144 +msgid "Owners are invalid" +msgstr "Lastniki niso veljavni" -#: superset/reports/commands/exceptions.py:222 -msgid "Alert on grace period" -msgstr "Opozorilo v obdobju mirovanja" +#: superset/commands/exceptions.py:115 +msgid "Some roles do not exist" +msgstr "Nekatere vloge ne obstajajo" -#: superset/reports/commands/exceptions.py:190 -msgid "Alert query returned a non-number value." -msgstr "Opozorilna poizvedba je vrnila neštevilsko vrednost." +#: superset/commands/exceptions.py:123 +msgid "Datasource type is invalid" +msgstr "Neveljaven tip podatkovnega vira" -#: superset/reports/commands/exceptions.py:186 -msgid "Alert query returned more than one column." -msgstr "Opozorilna poizvedba je vrnila več kot en stolpec." +#: superset/commands/exceptions.py:131 +msgid "Datasource does not exist" +msgstr "Podatkovni vir ne obstaja" -#: superset/reports/commands/alert.py:105 +#: superset/commands/exceptions.py:138 +msgid "Query does not exist" +msgstr "Poizvedba ne obstaja" + +#: superset/common/query_actions.py:202 #, python-format -msgid "Alert query returned more than one column. %s columns returned" -msgstr "" -"Opozorilna poizvedba je vrnila več kot en stolpec. Število vrnjenih " -"stolpcev: %s" +msgid "Invalid result type: %(result_type)s" +msgstr "Neveljaven tip rezultata: %(result_type)s" -#: superset/reports/commands/exceptions.py:177 -msgid "Alert query returned more than one row." -msgstr "Opozorilna poizvedba je vrnila več kot eno vrstico." +#: superset/common/query_context_processor.py:475 +msgid "The chart does not exist" +msgstr "Grafikon ne obstaja" -#: superset/reports/commands/alert.py:96 +#: superset/common/query_object.py:292 #, python-format -msgid "Alert query returned more than one row. %s rows returned" +msgid "" +"Duplicate column/metric labels: %(labels)s. Please make sure all columns and " +"metrics have a unique label." msgstr "" -"Opozorilna poizvedba je vrnila več kot eno vrstico. Število vrnjenih " -"vrstic: %s" +"Podvojene oznake stolpcev/mer: %(labels)s. Poskrbite, da bodo imeli stolpci in " +"mere unikatne oznake." -#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:75 -msgid "Alert running" -msgstr "Opozorilo aktivno" +#: superset/common/query_object.py:314 +#, python-format +msgid "" +"The following entries in `series_columns` are missing in `columns`: %(columns)s. " +msgstr "V 'columns' manjkajo naslednji vnosi iz 'series_columns': %(columns)s. " -#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:68 -msgid "Alert triggered, notification sent" -msgstr "Opozorilo sproženo, obvestilo poslano" +#: superset/common/query_object.py:416 +msgid "`operation` property of post processing object undefined" +msgstr "Lastnost `operation` poprocesirnega objekta ni definirana" -#: superset/reports/commands/exceptions.py:182 -msgid "Alert validator config error." -msgstr "Napaka nastavitev potrjevalnika opozoril." +#: superset/common/query_object.py:420 +#, python-format +msgid "Unsupported post processing operation: %(operation)s" +msgstr "Nepodprta poprocesirna operacija: %(operation)s" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:436 -#: superset/initialization/__init__.py:468 -msgid "Alerts" -msgstr "Opozorila" +#: superset/connectors/connector_registry.py:99 +#, python-format +msgid "Datasource id not found: %(id)s" +msgstr "ID podatkovnega vira ni bil najden: %(id)s" -#: superset/initialization/__init__.py:480 -msgid "Alerts & Reports" -msgstr "Opozorila in poročila" +#: superset/connectors/sqla/models.py:899 +#, python-format +msgid "Error in jinja expression in fetch values predicate: %(msg)s" +msgstr "Napaka v jinja izrazu za pridobivanje vrednosti predikatov: %(msg)s" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:432 -msgid "Alerts & reports" -msgstr "Opozorila in poročila" +#: superset/connectors/sqla/models.py:989 +msgid "Virtual dataset query must be read-only" +msgstr "Poizvedba na virtualnem podatkovnem setu mora biti samo za branje" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:127 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:427 -msgid "Align +/-" -msgstr "Poravnaj +/-" +#: superset/connectors/sqla/models.py:1014 +#, python-format +msgid "Error while rendering virtual dataset query: %(msg)s" +msgstr "Napaka pri izvajanju poizvedbe virtualnega podatkovnega seta: %(msg)s" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:457 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:478 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:499 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:524 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:454 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:475 -msgid "All" -msgstr "Vsi" +#: superset/connectors/sqla/models.py:1021 superset/connectors/sqla/utils.py:109 +msgid "Virtual dataset query cannot be empty" +msgstr "Poizvedba na virtualnem podatkovnem setu ne sme biti prazna" -#: superset/annotation_layers/annotations/filters.py:28 -#: superset/annotation_layers/filters.py:30 superset/charts/filters.py:31 -#: superset/css_templates/filters.py:28 -#: superset/queries/saved_queries/filters.py:31 superset/reports/filters.py:28 -msgid "All Text" -msgstr "Celotno besedilo" +#: superset/connectors/sqla/models.py:1024 +msgid "Virtual dataset query cannot consist of multiple statements" +msgstr "" +"Poizvedba na virtualnem podatkovnem setu ne sme biti sestavljena iz več stavkov" -#: superset-frontend/src/dashboard/util/getFilterScopeNodesTree.js:85 -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:122 -msgid "All charts" -msgstr "Vsi grafikoni" +#: superset/connectors/sqla/models.py:1176 +#, python-format +msgid "Error in jinja expression in RLS filters: %(msg)s" +msgstr "Napaka v jinja izrazu RLS filtrov: %(msg)s" -#: superset-frontend/src/dashboard/util/getFilterFieldNodesTree.js:44 -msgid "All filters" -msgstr "Vsi filtri" - -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:326 -#, fuzzy, python-format -msgid "All filters (%(filterCount)d)" -msgstr "Vsi filtri (${filterValues.length})" - -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/state.ts:49 -msgid "All panels" -msgstr "Vsi paneli" - -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:132 -msgid "All panels with this column will be affected by this filter" -msgstr "Ta filter bo vplival na vse panele s tem stolpcem" +#: superset/connectors/sqla/models.py:1265 +msgid "" +"Datetime column not provided as part table configuration and is required by this " +"type of chart" +msgstr "" +"Stolpec datum-čas ni podan kot del tabele, čeprav mora biti za ta tip grafikona" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:95 -#: superset/views/database/mixins.py:187 -msgid "Allow CREATE TABLE AS" -msgstr "Dovoli CREATE TABLE AS" +#: superset/connectors/sqla/models.py:1271 +msgid "Empty query?" +msgstr "Prazna poizvedba?" -#: superset/views/database/mixins.py:113 -msgid "Allow CREATE TABLE AS option in SQL Lab" -msgstr "Dovoli opcijo CREATE TABLE AS v SQL laboratoriju" +#: superset/connectors/sqla/models.py:1288 superset/connectors/sqla/models.py:1768 +#, python-format +msgid "Metric '%(metric)s' does not exist" +msgstr "Mera '%(metric)s' ne obstaja" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:109 -#: superset/views/database/mixins.py:188 -msgid "Allow CREATE VIEW AS" -msgstr "Dovoli CREATE VIEW AS" +#: superset/connectors/sqla/models.py:1337 +#, python-format +msgid "Unknown column used in orderby: %(col)s" +msgstr "Za razvrščanje je uporabljen neznan stolpec: %(col)s" -#: superset/views/database/mixins.py:114 -msgid "Allow CREATE VIEW AS option in SQL Lab" -msgstr "Dovoli opcijo CREATE VIEW AS v SQL laboratoriju" +#: superset/connectors/sqla/models.py:1397 +#, python-format +msgid "Time column \"%(col)s\" does not exist in dataset" +msgstr "Časovni stolpec \"%(col)s\" ne obstaja v podatkovnem setu" -#: superset/views/database/mixins.py:201 -msgid "Allow Csv Upload" -msgstr "Dovoli nalaganje CSV" +#: superset/connectors/sqla/models.py:1523 +msgid "error_message" +msgstr "error_message" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:142 -#: superset/views/database/mixins.py:189 -msgid "Allow DML" -msgstr "Dovoli DML" +#: superset/connectors/sqla/models.py:1535 +msgid "Filter value list cannot be empty" +msgstr "Seznam vrednosti filtra ne sme biti prazen" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:158 -#: superset/views/database/mixins.py:203 -msgid "Allow Multi Schema Metadata Fetch" -msgstr "Dovoli pridobivanje metapodatkov z več shemami" +#: superset/connectors/sqla/models.py:1561 +msgid "Must specify a value for filters with comparison operators" +msgstr "Potrebno je podati vrednost za filter s primerjalnim operandom" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:161 -#: superset/views/database/mixins.py:170 -msgid "" -"Allow SQL Lab to fetch a list of all tables and all views across all " -"database schemas. For large data warehouse with thousands of tables, this" -" can be expensive and put strain on the system." -msgstr "" -"Dovoli SQL laboratoriju, da pridobi seznam vseh tabel in pogledov iz vseh" -" shem podatkovne baze. Pri velikih podatkovnih skladiščih s tisoči tabel " -"je to lahko potratno in obremeni sistem." +#: superset/connectors/sqla/models.py:1584 +#, python-format +msgid "Invalid filter operation type: %(op)s" +msgstr "Neveljaven tip operacije filtra: %(op)s" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:98 -msgid "Allow creation of new tables based on queries" -msgstr "Dovoli ustvarjanje novih tabel s poizvedbami" +#: superset/connectors/sqla/models.py:1594 +#, python-format +msgid "Error in jinja expression in WHERE clause: %(msg)s" +msgstr "Napaka v jinja izrazu WHERE stavka: %(msg)s" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:112 -msgid "Allow creation of new views based on queries" -msgstr "Dovoli ustvarjanje novih pogledov s poizvedbami" +#: superset/connectors/sqla/models.py:1606 +#, python-format +msgid "Error in jinja expression in HAVING clause: %(msg)s" +msgstr "Napaka v jinja izrazu HAVING stavka: %(msg)s" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:256 -msgid "Allow data manipulation language" -msgstr "Dovoli jezik za manipulacijo podatkov (DML)" +#: superset/connectors/sqla/models.py:1736 +msgid "Database does not support subqueries" +msgstr "Podatkovna baza ne podpira podpoizvedb" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:417 -msgid "Allow data upload" -msgstr "Dovoli nalaganje podatkov" +#: superset/connectors/sqla/models.py:1857 +msgid "Db engine did not return all queried columns" +msgstr "Sitem podatkovne baze ni vrnil vse stolpcev poizvedbe" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:145 -msgid "" -"Allow manipulation of the database using non-SELECT statements such as " -"UPDATE, DELETE, CREATE, etc." -msgstr "" -"Dovoli manipulacije podatkovne baze z uporabo ne-SELECT stavkov, kot so " -"UPDATE, DELETE, CREATE, itd." +#: superset/connectors/sqla/utils.py:122 +msgid "Only `SELECT` statements are allowed" +msgstr "Dovoljeni so le `SELECT` stavki" -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:216 -msgid "Allow multiple selections" -msgstr "Dovoli več izbir" +#: superset/connectors/sqla/utils.py:131 +msgid "Only single queries supported" +msgstr "Podprte so le enojne poizvedbe" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:189 -msgid "Allow node selections" -msgstr "Dovoli izbiro vozlišča" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:68 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:238 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:36 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:38 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:62 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:50 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:84 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:104 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:128 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1364 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:389 +#: superset-frontend/src/explore/controls.jsx:245 +#: superset-frontend/src/explore/fixtures.tsx:96 +#: superset/connectors/sqla/views.py:57 +msgid "Columns" +msgstr "Stolpci" -#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:64 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:82 -msgid "Allow selecting multiple values" -msgstr "Dovoli izbiro več vrednosti" +#: superset/connectors/sqla/views.py:58 +msgid "Show Column" +msgstr "Pokaži stolpec" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:192 -msgid "Allow this database to be explored" -msgstr "Dovoli raziskovanje te podatkovne baze" +#: superset/connectors/sqla/views.py:59 +msgid "Add Column" +msgstr "Dodaj stolpec" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:79 -msgid "Allow this database to be queried in SQL Lab" -msgstr "Dovoli poizvedbo na to podatkovno bazo v SQL laboratoriju" +#: superset/connectors/sqla/views.py:60 +msgid "Edit Column" +msgstr "Uredi stolpec" -#: superset/views/database/mixins.py:115 +#: superset/connectors/sqla/views.py:90 msgid "" -"Allow users to run non-SELECT statements (UPDATE, DELETE, CREATE, ...) in" -" SQL Lab" +"Whether to make this column available as a [Time Granularity] option, column has " +"to be DATETIME or DATETIME-like" msgstr "" -"Dovoli uporabnikom poganjanje ne-SELECT stavkov (UPDATE, DELETE, CREATE, " -"...) v SQL laboratoriju" - -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:555 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:529 -msgid "Alphabetical" -msgstr "Po abecedi" +"Če želite, da bo ta stolpec na razpolago kot možnost [Granulacija časa]. Stolpec " +"mora biti tipa DATETIME ali DATETIME-like" -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:50 -msgid "" -"Also known as a box and whisker plot, this visualization compares the " -"distributions of a related metric across multiple groups. The box in the " -"middle emphasizes the mean, median, and inner 2 quartiles. The whiskers " -"around each box visualize the min, max, range, and outer 2 quartiles." +#: superset/connectors/sqla/views.py:95 +msgid "Whether this column is exposed in the `Filters` section of the explore view." msgstr "" -"Znan tudi kot grafikon škatla z brki. prikaže primerjavo porazdelitev " -"povezanih mer v različnih skupinah. Škatla na sredini predstavlja " -"povprečje, mediano in notranja 2 kvartila. Brki na vsaki škatli " -"prikazujejo minimum, maksimum, območje in zunanja dva kvartila." +"Če želite, da je ta stolpec na voljo v sekciji `Filtri` v raziskovalnem pogledu." -#: superset-frontend/src/components/AlteredSliceTag/index.jsx:182 -msgid "Altered" -msgstr "Spremenjeno" - -#: superset/common/query_context_processor.py:257 superset/viz.py:1415 +#: superset/connectors/sqla/views.py:99 msgid "" -"An enclosed time range (both start and end) must be specified when using " -"a Time Comparison." +"The data type that was inferred by the database. It may be necessary to input a " +"type manually for expression-defined columns in some cases. In most case users " +"should not need to alter this." msgstr "" -"Pri časovni primerjavi mora biti določeno zaprto časovno obdobje (s časom" -" začetka in konca)." +"Podatkovni tip, ki izvira iz podatkovne baze. V nekaterih primerih je potrebno " +"ročno vnesti tip za stolpce, ki temeljijo na izrazih. V večini primerov " +"uporabniku tega ni potrebno spreminjati." -#: superset/databases/schemas.py:299 -msgid "" -"An engine must be specified when passing individual parameters to a " -"database." -msgstr "" -"Pri podajanju posameznih parametrov podatkovne baze mora biti podan njen " -"tip." +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:351 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:360 +#: superset-frontend/src/dashboard/components/gridComponents/new/NewColumn.jsx:31 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:112 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:204 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:231 +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:137 +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:140 +#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:194 +#: superset/connectors/sqla/views.py:139 +msgid "Column" +msgstr "Stolpec" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:623 -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:140 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:69 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:116 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx:46 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:64 -msgid "An error has occurred" -msgstr "Prišlo je do napake" +#: superset/connectors/sqla/views.py:140 superset/connectors/sqla/views.py:233 +msgid "Verbose Name" +msgstr "Podrobno ime" -#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.jsx:80 -#: superset-frontend/src/components/TableLoader/index.tsx:48 -#: superset-frontend/src/utils/getClientErrorObject.ts:135 -msgid "An error occurred" -msgstr "Prišlo je do napake" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:85 +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:116 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:46 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:44 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:51 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:44 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:137 +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:183 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:254 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:258 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:852 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1205 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1209 +#: superset-frontend/src/components/ReportModal/index.tsx:288 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:51 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1102 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:255 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1118 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1124 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:161 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:156 +#: superset/connectors/sqla/views.py:141 superset/connectors/sqla/views.py:232 +#: superset/connectors/sqla/views.py:448 superset/views/annotations.py:77 +#: superset/views/annotations.py:122 superset/views/chart/mixin.py:81 +#: superset/views/sql_lab.py:76 +msgid "Description" +msgstr "Opis" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:347 -msgid "An error occurred saving dataset" -msgstr "Pri shranjevanju podatkovnega seta je prišlo do napake" +#: superset/connectors/sqla/views.py:142 +msgid "Groupable" +msgstr "Združevanje" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "Pri osveževanju poizvedb je prišlo do napake" +#: superset/connectors/sqla/views.py:143 +msgid "Filterable" +msgstr "Filtriranje" -#: superset/key_value/commands/exceptions.py:33 -#, fuzzy -msgid "An error occurred while accessing the value." -msgstr "Pri ustvarjanju podatkovnega vira je prišlo do težave" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:25 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:50 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:35 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:41 +#: superset-frontend/src/components/TableSelector/index.tsx:326 +#: superset-frontend/src/visualizations/TimeTable/index.ts:25 +#: superset/connectors/sqla/views.py:144 superset/connectors/sqla/views.py:236 +#: superset/connectors/sqla/views.py:434 superset/views/chart/mixin.py:87 +msgid "Table" +msgstr "Tabela" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1165 -msgid "" -"An error occurred while collapsing the table schema. Please contact your " -"administrator." -msgstr "" -"Pri krčenju sheme tabele je prišlo do napake. Kontaktirajte " -"administratorja." +#: superset/connectors/sqla/views.py:145 +msgid "Expression" +msgstr "Izraz" -#: superset-frontend/src/views/CRUD/hooks.ts:301 -#, python-format -msgid "An error occurred while creating %ss: %s" -msgstr "Napaka pri ustvarjanju %s: %s" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:355 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:363 +#: superset/connectors/sqla/views.py:146 +msgid "Is temporal" +msgstr "Časoven" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1313 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1335 -msgid "An error occurred while creating the data source" -msgstr "Pri ustvarjanju podatkovnega vira je prišlo do težave" +#: superset/connectors/sqla/views.py:147 +msgid "Datetime Format" +msgstr "Oblika zapisa datuma,časa" -#: superset/key_value/commands/exceptions.py:29 -#, fuzzy -msgid "An error occurred while creating the value." -msgstr "Pri ustvarjanju podatkovnega vira je prišlo do težave" +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:216 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:219 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:276 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:320 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:509 +#: superset/connectors/sqla/views.py:148 superset/connectors/sqla/views.py:234 +msgid "Type" +msgstr "Tip" -#: superset/key_value/commands/exceptions.py:37 -#, fuzzy, python-format -msgid "An error occurred while deleting the value." -msgstr "Pri pridobivanju vrednosti shem je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:149 +msgid "Business Data Type" +msgstr "Poslovni podatkovni tip" -#: superset-frontend/src/reports/actions/reports.js:138 -msgid "An error occurred while editing this report." -msgstr "Pri urejanju tega poročila je prišlo do napake." +#: superset/connectors/sqla/views.py:165 superset/datasets/schemas.py:44 +msgid "Invalid date/timestamp format" +msgstr "Neveljaven zapis datuma/časa" -#: superset-frontend/src/reports/actions/reports.js:120 -#, python-format -msgid "An error occurred while editing this report: %s" -msgstr "Pri urejanju tega poročila je prišlo do napake: %s" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:114 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:157 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1353 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:353 +#: superset-frontend/src/explore/controls.jsx:152 +#: superset/connectors/sqla/views.py:188 +msgid "Metrics" +msgstr "Mere" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1141 -msgid "" -"An error occurred while expanding the table schema. Please contact your " -"administrator." -msgstr "" -"Pri širitvi sheme tabele je prišlo do napake. Kontaktirajte " -"administratorja." +#: superset/connectors/sqla/views.py:189 +msgid "Show Metric" +msgstr "Pokaži mero" -#: superset-frontend/src/views/CRUD/hooks.ts:103 -#, python-format -msgid "An error occurred while fetching %s info: %s" -msgstr "Napaka pri pridobivanju informacij za %s: %s" +#: superset/connectors/sqla/views.py:190 +msgid "Add Metric" +msgstr "Dodaj mero" -#: superset-frontend/src/views/CRUD/hooks.ts:171 -#: superset-frontend/src/views/CRUD/hooks.ts:258 -#: superset-frontend/src/views/CRUD/hooks.ts:344 -#, python-format -msgid "An error occurred while fetching %ss: %s" -msgstr "Napaka pri pridobivanju informacij za %s: %s" +#: superset/connectors/sqla/views.py:191 +msgid "Edit Metric" +msgstr "Uredi mero" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:132 -msgid "An error occurred while fetching available CSS templates" -msgstr "Pri pridobivanju CSS predlog je prišlo do napake" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:128 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:129 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:171 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:172 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:84 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:118 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:97 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1196 +#: superset-frontend/src/explore/controls.jsx:167 +#: superset-frontend/src/explore/controls.jsx:168 +#: superset/connectors/sqla/views.py:231 +msgid "Metric" +msgstr "Mera" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:484 -#, python-format -msgid "An error occurred while fetching chart created by values: %s" -msgstr "Pri pridobivanju polja Grafikon ustvaril je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:235 +msgid "SQL Expression" +msgstr "SQL izraz" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:463 -#, python-format -msgid "An error occurred while fetching chart owners values: %s" -msgstr "Pri pridobivanju polja lastnik grafikona je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:237 +msgid "D3 Format" +msgstr "D3 zapis" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:392 -#, python-format -msgid "An error occurred while fetching created by values: %s" -msgstr "Pri pridobivanju vrednosti \"Ustvaril\" je prišlo do napake: %s" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:895 +#: superset/connectors/sqla/views.py:238 superset/connectors/sqla/views.py:451 +#: superset/views/database/mixins.py:199 +msgid "Extra" +msgstr "Dodatno" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:481 -#, python-format -msgid "An error occurred while fetching dashboard created by values: %s" -msgstr "Pri pridobivanju polja Nadzorno ploščo ustvaril je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:239 +msgid "Warning Message" +msgstr "Opozorilo" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:460 -#, python-format -msgid "An error occurred while fetching dashboard owner values: %s" -msgstr "Pri pridobivanju polja lastnik nadzorne plošče je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:269 +msgid "Row level security filter" +msgstr "Filter za varnost na nivoju vrstic" -#: superset-frontend/src/components/OmniContainer/getDashboards.ts:48 -msgid "An error occurred while fetching dashboards" -msgstr "Prišlo je do napake pri pridobivanju nadzornih plošč" +#: superset/connectors/sqla/views.py:270 +msgid "Show Row level security filter" +msgstr "Prikaži filter za varnost na nivoju vrstic" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:200 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:127 -#, python-format -msgid "An error occurred while fetching dashboards: %s" -msgstr "Prišlo je do napake pri pridobivanju nadzornih plošč: %s" +#: superset/connectors/sqla/views.py:271 +msgid "Add Row level security filter" +msgstr "Dodaj filter za varnost na nivoju vrstic" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:129 -#, python-format -msgid "An error occurred while fetching database related data: %s" -msgstr "Pri pridobivanju podatkov iz podatkovne baze je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:272 +msgid "Edit Row level security filter" +msgstr "Uredi filter za varnost na nivoju vrstic" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:341 -#, python-format -msgid "An error occurred while fetching database values: %s" -msgstr "Pri pridobivanju vrednosti podatkovne baze je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:290 +msgid "" +"Regular filters add where clauses to queries if a user belongs to a role " +"referenced in the filter. Base filters apply filters to all queries except the " +"roles defined in the filter, and can be used to define what users can see if no " +"RLS filters within a filter group apply to them." +msgstr "" +"Navadni filtri dodajo WHERE stavek v poizvedbe, če ima uporabnik vlogo podano v " +"filtru. Osnovni filtri filtrirajo vse poizvedbe, razen vlog, definiranih v " +"filtru, in jih je mogoče uporabiti za nastavitev tega kaj uporabnik vidi, če v " +"skupini filtrov ni RLS-filtrov, ki bi se nanašali nanje." -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:295 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:282 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:434 -#, python-format -msgid "An error occurred while fetching dataset datasource values: %s" +#: superset/connectors/sqla/views.py:296 +msgid "These are the tables this filter will be applied to." +msgstr "To so tabele, na katere se nanaša ta filter." + +#: superset/connectors/sqla/views.py:297 +msgid "" +"For regular filters, these are the roles this filter will be applied to. For base " +"filters, these are the roles that the filter DOES NOT apply to, e.g. Admin if " +"admin should see all data." msgstr "" -"Pri pridobivanju vrednosti podatkovnega vira podatkovnega seta je prišlo " -"do napake: %s" +"Za regularne filtre so te vloge tiste, ki bodo filtrirane. Za osnovne filtre, so " +"te vloge tiste, ki NE bodo filtrirane, npr. Admin, če naj administrator vidi vse " +"podatke." -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:426 -#, python-format -msgid "An error occurred while fetching dataset owner values: %s" -msgstr "Pri pridobivanju polja lastnik podatkovnega seta je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:303 +msgid "" +"Filters with the same group key will be ORed together within the group, while " +"different filter groups will be ANDed together. Undefined group keys are treated " +"as unique groups, i.e. are not grouped together. For example, if a table has " +"three filters, of which two are for departments Finance and Marketing (group key " +"= 'department'), and one refers to the region Europe (group key = 'region'), the " +"filter clause would apply the filter (department = 'Finance' OR department = " +"'Marketing') AND (region = 'Europe')." +msgstr "" +"Filtri z enakim skupinskim ključem bodo znotraj skupine združeni z OR funkcijo, " +"medtem ko bodo različne skupine združene z AND funkcijo. Nedefinirani skupinski " +"ključi so obravnavani kot unikatne skupine in niso združeni v svojo skupino. " +"Npr., če ima tabela tri filtre, pri čemer sta dva za oddelka marketinga in financ " +"(skupinski ključ = 'oddelek') tretji pa se nanaša na regijo Evropa (skupinski " +"ključ = 'regija'), bo filtrski izraz (oddelek = 'Finance' OR oddelek = " +"'Marketing') AND (regija = 'Evropa')." -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:184 -msgid "An error occurred while fetching dataset related data" -msgstr "Napaka pri pridobivanju podatkov iz podatkovnega seta" +#: superset/connectors/sqla/views.py:313 +msgid "" +"This is the condition that will be added to the WHERE clause. For example, to " +"only return rows for a particular client, you might define a regular filter with " +"the clause `client_id = 9`. To display no rows unless a user belongs to a RLS " +"filter role, a base filter can be created with the clause `1 = 0` (always false)." +msgstr "" +"To je pogoj, ki bo dodan WHERE stavku. Npr., če želite dobiti vrstice za določeno " +"stranko, lahko definirate regularni filter z izrazom 'id_stranke = 9'. Če ne " +"želimo prikazati vrstic, razen če uporabnik pripada RLS vlogi, lahko filter " +"ustvarimo z izrazom `1 = 0` (vedno neresnično)." -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:204 -#, python-format -msgid "An error occurred while fetching dataset related data: %s" -msgstr "Napaka pri pridobivanju podatkov iz podatkovnega seta: %s" +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:269 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:326 +#: superset/connectors/sqla/views.py:322 superset/connectors/sqla/views.py:341 +msgid "Tables" +msgstr "Tabele" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:445 -#, python-format -msgid "An error occurred while fetching datasets: %s" -msgstr "Prišlo je do napake pri pridobivanju podatkovnih setov: %s" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:439 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:442 +#: superset-frontend/src/profile/components/Security.tsx:35 +#: superset/connectors/sqla/views.py:323 superset/views/dashboard/mixin.py:83 +msgid "Roles" +msgstr "Vloge" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1356 -msgid "An error occurred while fetching function names." -msgstr "Pri pridobivanju imen funkcij je prišlo do napake." +#: superset/connectors/sqla/views.py:324 +msgid "Clause" +msgstr "Stavek" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:460 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:358 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:454 -#, python-format -msgid "An error occurred while fetching schema values: %s" -msgstr "Pri pridobivanju vrednosti shem je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:325 superset/views/chart/mixin.py:78 +#: superset/views/dashboard/mixin.py:85 superset/views/dashboard/views.py:196 +#: superset/views/database/mixins.py:195 +msgid "Creator" +msgstr "Avtor" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:662 -msgid "An error occurred while fetching tab state" -msgstr "Pri pridobivanju stanja zavihka je prišlo do napake" +#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:127 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:295 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:315 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:341 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:361 +#: superset/connectors/sqla/views.py:326 superset/connectors/sqla/views.py:452 +#: superset/views/dashboard/mixin.py:86 superset/views/dashboard/views.py:197 +#: superset/views/database/mixins.py:205 superset/views/sql_lab.py:77 +msgid "Modified" +msgstr "Spremenjeno" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1027 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1052 -msgid "An error occurred while fetching table metadata" -msgstr "Pri pridobivanju metapodatkov tabele je prišlo do napake" +#: superset/connectors/sqla/views.py:342 +msgid "Show Table" +msgstr "Prikaži tabelo" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1093 -msgid "" -"An error occurred while fetching table metadata. Please contact your " -"administrator." -msgstr "" -"Pri pridobivanju metapodatkov tabele je prišlo do napake. Kontaktirajte " -"administratorja." +#: superset/connectors/sqla/views.py:343 +msgid "Import a table definition" +msgstr "Uvozi definicijo tabele" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:375 -#, python-format -msgid "An error occurred while fetching user values: %s" -msgstr "Pri pridobivanju vrednosti uporabnika je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:344 +msgid "Edit Table" +msgstr "Uredi tabelo" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:698 +#: superset/connectors/sqla/views.py:375 msgid "" -"An error occurred while hiding the left bar. Please contact your " -"administrator." +"The list of charts associated with this table. By altering this datasource, you " +"may change how these associated charts behave. Also note that charts need to " +"point to a datasource, so this form will fail at saving if removing charts from a " +"datasource. If you want to change the datasource for a chart, overwrite the chart " +"from the 'explore view'" msgstr "" -"Pri skrivanju leve vrstice je prišlo do napake. Kontaktirajte " -"administratorja." +"Seznam grafikonov, povezanih s to tabelo. S spreminjanjem podatkovnega vira lahko " +"spremenite, kako se povezani grafikoni obnašajo. Poleg tega morajo biti grafikoni " +"povezani s podatkovnim virom. Če odstranite grafikon s podatkovnega vira ne bo " +"mogoče shraniti tega vnosa. Če želite spremeniti podatkovni vir grafikona, " +"prepišite grafikon v raziskovalnem pogledu." -#: superset-frontend/src/views/CRUD/hooks.ts:438 -#: superset-frontend/src/views/CRUD/hooks.ts:451 -#, python-format -msgid "An error occurred while importing %s: %s" -msgstr "Napaka pri uvažanju %s: %s" - -#: superset-frontend/src/chart/chartAction.js:569 -msgid "An error occurred while loading the SQL" -msgstr "Pri nalaganju SQL je prišlo do napake" +#: superset/connectors/sqla/views.py:384 +msgid "Timezone offset (in hours) for this datasource" +msgstr "Razlika časovnega pasu (v urah) za ta podatkovni vir" -#: superset/reports/commands/exceptions.py:242 -msgid "An error occurred while pruning logs " -msgstr "Pri krajšanju dnevnikov je prišlo do napake " +#: superset/connectors/sqla/views.py:385 +msgid "Name of the table that exists in the source database" +msgstr "Ime tabele, ki obstaja v izvorni podatkovni bazi" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:744 -msgid "An error occurred while removing query. Please contact your administrator." +#: superset/connectors/sqla/views.py:386 +msgid "Schema, as used only in some databases like Postgres, Redshift and DB2" msgstr "" -"Pri odstranjevanju poizvedbe je prišlo do napake. Kontaktirajte " -"administratorja." +"Shema, ki se uporablja pri nekaterih podatkovnih bazah, kot so Postgres, Redshift " +"in DB2" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:720 -msgid "An error occurred while removing tab. Please contact your administrator." +#: superset/connectors/sqla/views.py:393 +msgid "" +"This fields acts a Superset view, meaning that Superset will run a query against " +"this string as a subquery." msgstr "" -"Pri odstranjevanju zavihka je prišlo do napake. Kontaktirajte " -"administratorja." +"To polje se obnaša kot Supersetov pogled, kar pomeni, da bo Superset izvedel " +"poizvedbo za ta niz kot podpoizvedbo." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1188 +#: superset/connectors/sqla/views.py:397 msgid "" -"An error occurred while removing the table schema. Please contact your " -"administrator." +"Predicate applied when fetching distinct value to populate the filter control " +"component. Supports jinja template syntax. Applies only when `Enable Filter " +"Select` is on." msgstr "" -"Pri odstranjevanju sheme tabele je prišlo do napake. Kontaktirajte " -"administratorja." +"Privzeta vrednost za pridobivanje različnih vrednost pri oblikovanju filtrov. " +"Podpira sintakso za jinja predloge. Potrebno le, ko je vključeno `Omogoči izbiro " +"filtra`." -#: superset-frontend/src/chart/chartReducer.ts:94 -#, python-format -msgid "An error occurred while rendering the visualization: %s" -msgstr "Pri prikazovanju vizualizacije je prišlo do napake: %s" +#: superset/connectors/sqla/views.py:403 +msgid "Redirects to this endpoint when clicking on the table from the table list" +msgstr "Preusmeri v to končno točko, ko kliknete na tabelo v seznamu tabel" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:575 +#: superset/connectors/sqla/views.py:407 msgid "" -"An error occurred while setting the active tab. Please contact your " -"administrator." +"Whether to populate the filter's dropdown in the explore view's filter section " +"with a list of distinct values fetched from the backend on the fly" msgstr "" -"Pri določanju aktivnega zavihka je prišlo do napake. Kontaktirajte " -"administratorja." +"Če želite napolniti spustni seznam filtra v raziskovalnem pogledu filtrske " +"sekcije z različnimi vrednostmi, pridobljenimi sproti v ozadju" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:825 -msgid "" -"An error occurred while setting the tab autorun. Please contact your " -"administrator." +#: superset/connectors/sqla/views.py:412 +msgid "Whether the table was generated by the 'Visualize' flow in SQL Lab" msgstr "" -"Pri določanju samodejnega zagona zavihka je prišlo do napake. " -"Kontaktirajte administratorja." +"Če želite, da je tabela ustvarjena s postopkom 'Vizualizacija' v SQL laboratoriju" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:767 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:949 +#: superset/connectors/sqla/views.py:415 msgid "" -"An error occurred while setting the tab database ID. Please contact your " -"administrator." +"A set of parameters that become available in the query using Jinja templating " +"syntax" msgstr "" -"Pri določanju ID-ja v podatkovne baze za zavihek je prišlo do napake. " -"Kontaktirajte administratorja." +"Nabor parametrov, ki postanejo razpoložljivi za poizvedbo z uporabo sintakse za " +"Jinja predloge" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:792 +#: superset/connectors/sqla/views.py:419 msgid "" -"An error occurred while setting the tab schema. Please contact your " -"administrator." +"Duration (in seconds) of the caching timeout for this table. A timeout of 0 " +"indicates that the cache never expires. Note this defaults to the database " +"timeout if undefined." msgstr "" -"Pri določanju sheme zavihka je prišlo do napake. Kontaktirajte " -"administratorja." +"Trajanje (v sekundah) predpomnjenja za to tabelo. Vrednost 0 označuje, da " +"predpomnilnik nikoli ne poteče. V primeru, da ni definirano, ima nastavitev " +"trajanja za podatkovno bazo." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:967 -msgid "" -"An error occurred while setting the tab template parameters. Please " -"contact your administrator." -msgstr "" -"Pri določanju parametrov predloge zavihka je prišlo do napake. " -"Kontaktirajte administratorja." +#: superset/connectors/sqla/views.py:433 +msgid "Associated Charts" +msgstr "Povezani grafikoni" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:850 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:941 -msgid "" -"An error occurred while setting the tab title. Please contact your " -"administrator." -msgstr "" -"Pri določanju naslova zavihka je prišlo do napake. Kontaktirajte " -"administratorja." +#: superset/connectors/sqla/views.py:435 +msgid "Changed By" +msgstr "Spremenil" -#: superset-frontend/src/explore/actions/exploreActions.ts:95 -msgid "An error occurred while starring this chart" -msgstr "Pri ocenjevanju grafikona je prišlo do napake" +#: superset-frontend/src/components/DatabaseSelector/index.tsx:279 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1145 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1150 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:251 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:280 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:326 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:479 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:223 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:331 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:279 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:426 +#: superset/connectors/sqla/views.py:436 superset/connectors/sqla/views.py:437 +#: superset/templates/superset/import_dashboards.html:53 +#: superset/views/database/forms.py:123 superset/views/database/forms.py:285 +#: superset/views/database/forms.py:416 superset/views/database/mixins.py:194 +#: superset/views/sql_lab.py:75 +msgid "Database" +msgstr "Podatkovna baza" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:232 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:258 -msgid "" -"An error occurred while storing the latest query id in the backend. " -"Please contact your administrator if this problem persists." -msgstr "" -"Pri shranjevanju zadnjega id-ja poizvedbe v sistem je prišlo do napake. " -"Če se težava ponavlja, kontaktirajte administratorja." +#: superset/connectors/sqla/views.py:438 superset/views/database/mixins.py:196 +msgid "Last Changed" +msgstr "Zadnja sprememba" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:908 -msgid "" -"An error occurred while storing your query in the backend. To avoid " -"losing your changes, please save your query using the \"Save Query\" " -"button." -msgstr "" -"Pri shranjevanju vaše poizvedbe v sistem je prišlo do napake. Da ne " -"izgubite sprememb, shranite poizvedbo z gumbom \"Shrani poizvedbo\"." +#: superset/connectors/sqla/views.py:439 +msgid "Enable Filter Select" +msgstr "Omogoči izbiro filtra" -#: superset/key_value/commands/exceptions.py:41 -#, fuzzy -msgid "An error occurred while updating the value." -msgstr "Pri ustvarjanju podatkovnega vira je prišlo do težave" +#: superset-frontend/src/components/DatabaseSelector/index.tsx:303 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:221 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:331 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:494 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:232 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:289 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:446 +#: superset/connectors/sqla/views.py:440 superset/views/database/forms.py:129 +#: superset/views/database/forms.py:291 superset/views/database/forms.py:422 +msgid "Schema" +msgstr "Shema" -#: superset/views/core.py:711 -msgid "An unknown error occurred. Please contact your Superset administrator" -msgstr "" -"Zgodila se je neznana napaka. Kontaktirajte svojega administratorja za " -"Superset" +#: superset/connectors/sqla/views.py:441 +msgid "Default Endpoint" +msgstr "Privzeta končna točka" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:223 -msgid "Anchor to" -msgstr "Sidraj na" +#: superset/connectors/sqla/views.py:442 +msgid "Offset" +msgstr "Odmik" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:121 -msgid "Angle at which to end progress axis" -msgstr "Kot, pri katerem se konča os območja" +#: superset/connectors/sqla/views.py:443 superset/views/chart/mixin.py:77 +msgid "Cache Timeout" +msgstr "Trajanje predpomnilnika" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:111 -msgid "Angle at which to start progress axis" -msgstr "Kot, pri katerem se začne os območja" +#: superset/connectors/sqla/views.py:444 superset/views/database/forms.py:95 +#: superset/views/database/forms.py:249 superset/views/database/forms.py:385 +msgid "Table Name" +msgstr "Ime tabele" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:191 -msgid "Animation" -msgstr "Animacija" +#: superset/connectors/sqla/views.py:445 +msgid "Fetch Values Predicate" +msgstr "Pridobi vrednosti predikatov" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:202 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:248 -msgid "Annotation" -msgstr "Oznaka" +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:235 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:558 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:372 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:375 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:419 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:422 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:173 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:284 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1097 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1102 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:337 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:366 +#: superset/connectors/sqla/views.py:446 superset/views/chart/mixin.py:83 +#: superset/views/dashboard/mixin.py:82 +msgid "Owners" +msgstr "Lastniki" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:263 -msgid "Annotation Layer ${annotationLayerName}" -msgstr "Sloj z oznakami ${annotationLayerName}" +#: superset/connectors/sqla/views.py:447 +msgid "Main Datetime Column" +msgstr "Glavni stolpec Datum-Čas" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/annotationsAndLayers.tsx:35 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:124 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:271 -#: superset/initialization/__init__.py:229 superset/views/annotations.py:117 -msgid "Annotation Layers" -msgstr "Sloji z oznakami" +#: superset/connectors/sqla/views.py:449 +msgid "SQL Lab View" +msgstr "Pogled SQL laboratorija" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:465 -msgid "Annotation Slice Configuration" -msgstr "Nastavitve rezine z oznakami" +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:93 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:948 +#: superset/connectors/sqla/views.py:450 +msgid "Template parameters" +msgstr "Parametri predlog" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:758 -msgid "Annotation Source" -msgstr "Vir oznak" +#: superset/connectors/sqla/views.py:473 +msgid "" +"The table was created. As part of this two-phase configuration process, you " +"should now click the edit button by the new table to configure it." +msgstr "" +"Tabela je ustvarjena. Sedaj morate v tem dvodelnem postopku klikniti gumb za " +"urejanje nove tabele." -#: superset/annotation_layers/annotations/commands/exceptions.py:64 -msgid "Annotation could not be created." -msgstr "Oznake ni mogoče ustvariti." +#: superset/css_templates/api.py:139 +#, python-format +msgid "Deleted %(num)d css template" +msgid_plural "Deleted %(num)d css templates" +msgstr[0] "Izbrisana %(num)d css predloga" +msgstr[1] "Izbrisani %(num)d css predlogi" +msgstr[2] "Izbrisane %(num)d css predloge" +msgstr[3] "Izbrisanih %(num)d css predlog" -#: superset/annotation_layers/annotations/commands/exceptions.py:68 -msgid "Annotation could not be updated." -msgstr "Oznake ni mogoče posodobiti." +#: superset/css_templates/commands/exceptions.py:23 +msgid "CSS template could not be deleted." +msgstr "CSS predloge ni mogoče izbrisati." -#: superset/annotation_layers/annotations/commands/exceptions.py:72 -msgid "Annotation delete failed." -msgstr "Izbris oznake ni uspel." +#: superset/css_templates/commands/exceptions.py:27 +msgid "CSS template not found." +msgstr "CSS predloga ni najdena." -#: superset/views/annotations.py:47 -msgid "Annotation end time must be no earlier than start time." -msgstr "Končni čas oznake ne sem biti pred začetnim." +#: superset/dashboards/api.py:713 +#, python-format +msgid "Deleted %(num)d dashboard" +msgid_plural "Deleted %(num)d dashboards" +msgstr[0] "Izbrisana je %(num)d nadzorna plošča" +msgstr[1] "Izbrisani sta %(num)d nadzorni plošči" +msgstr[2] "Izbrisane so %(num)d nadzorne plošče" +msgstr[3] "Izbrisanih je %(num)d nadzornih plošč" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:265 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:322 -msgid "Annotation layer" -msgstr "Sloj z oznakami" +#: superset/dashboards/filters.py:37 +msgid "Title or Slug" +msgstr "Naslov ali `Slug`" -#: superset/annotation_layers/commands/exceptions.py:37 -msgid "Annotation layer could not be created." -msgstr "Sloja z oznakami ni mogoče ustvariti." +#: superset/dashboards/filters.py:53 +msgid "Created by me" +msgstr "Ustvarjeno z moje strani" -#: superset/annotation_layers/commands/exceptions.py:33 -msgid "Annotation layer could not be deleted." -msgstr "Sloja z oznakami ni mogoče izbrisati." +#: superset/dashboards/filters.py:202 +msgid "Role" +msgstr "Vloga" -#: superset/annotation_layers/commands/exceptions.py:41 -msgid "Annotation layer could not be updated." -msgstr "Sloja z oznakami ni mogoče posodobiti." +#: superset/dashboards/commands/exceptions.py:39 +msgid "Must be unique" +msgstr "Mora biti unikaten" -#: superset/annotation_layers/commands/exceptions.py:49 -msgid "Annotation layer delete failed." -msgstr "Izbris sloja z oznakami ni uspel." +#: superset/dashboards/commands/exceptions.py:43 +msgid "Dashboard parameters are invalid." +msgstr "Parametri nadzorne plošče so neveljavni." -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:517 -msgid "Annotation layer description columns" -msgstr "Stolpci z opisi slojev z oznakami" +#: superset/dashboards/commands/exceptions.py:54 +msgid "Dashboard could not be created." +msgstr "Nadzorne plošče ni mogoče ustvariti." -#: superset/annotation_layers/commands/exceptions.py:53 -#: superset/annotation_layers/commands/exceptions.py:57 -msgid "Annotation layer has associated annotations." -msgstr "Sloj z oznakami ima povezane oznake." - -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:492 -msgid "Annotation layer interval end" -msgstr "Konec intervala sloja z oznakami" - -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:247 -msgid "Annotation layer name" -msgstr "Ime sloja z oznakami" - -#: superset/annotation_layers/commands/exceptions.py:45 -msgid "Annotation layer not found." -msgstr "Sloja z oznakami ni mogoče najti." - -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:634 -msgid "Annotation layer opacity" -msgstr "Prosojnost sloja z oznakami" - -#: superset/annotation_layers/commands/exceptions.py:29 -msgid "Annotation layer parameters are invalid." -msgstr "Parametri sloja z oznakami so neveljavni." - -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:619 -msgid "Annotation layer stroke" -msgstr "Obroba sloja z oznakami" - -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:472 -msgid "Annotation layer time column" -msgstr "Časovni stolpec sloja z oznakami" - -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:506 -msgid "Annotation layer title column" -msgstr "Stolpec z naslovom sloja z oznakami" - -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:743 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:746 -msgid "Annotation layer type" -msgstr "Tip sloja z oznakami" - -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:403 -msgid "Annotation layer value" -msgstr "Vrednost sloja z oznakami" +#: superset/dashboards/commands/exceptions.py:58 +msgid "Dashboards could not be deleted." +msgstr "Nadzornih plošč ni mogoče izbrisati." -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:72 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:343 -msgid "Annotation layers" -msgstr "Sloji z oznakami" +#: superset/dashboards/commands/exceptions.py:66 +msgid "Dashboard could not be updated." +msgstr "Nadzorne plošče ni mogoče posodobiti." -#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:45 -msgid "Annotation layers are still loading." -msgstr "Sloj z oznakami se še vedno nalaga." +#: superset/dashboards/commands/exceptions.py:70 +msgid "Dashboard could not be deleted." +msgstr "Nadzorne plošče ni mogoče izbrisati." -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:292 -msgid "Annotation name" -msgstr "Ime oznake" +#: superset/dashboards/commands/exceptions.py:78 +msgid "Changing this Dashboard is forbidden" +msgstr "Spreminjanje te nadzorne plošče ni dovoljeno" -#: superset/annotation_layers/annotations/commands/exceptions.py:56 -msgid "Annotation not found." -msgstr "Oznaka ni najdena." +#: superset/dashboards/commands/exceptions.py:82 +msgid "Import dashboard failed for an unknown reason" +msgstr "Uvoz nadzorne plošče ni uspel zaradi neznanega razloga" -#: superset/annotation_layers/annotations/commands/exceptions.py:60 -msgid "Annotation parameters are invalid." -msgstr "Parametri oznak so neveljavni." +#: superset/dashboards/commands/exceptions.py:86 +msgid "You don't have access to this dashboard." +msgstr "Nimate dostopa do te nadzorne plošče." -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:755 -msgid "Annotation source type" -msgstr "Tip vira oznak" +#: superset/dashboards/commands/importers/v0.py:305 +msgid "No data in file" +msgstr "V datoteki ni podatkov" -#: superset/views/annotations.py:58 -msgid "Annotations" -msgstr "Oznake" +#: superset/dashboards/permalink/exceptions.py:23 +#: superset/explore/permalink/exceptions.py:23 +msgid "Invalid state." +msgstr "Neveljavno stanje." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/annotationsAndLayers.tsx:25 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:113 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:261 -msgid "Annotations and Layers" -msgstr "Oznake in sloji" +#: superset/dashboards/permalink/exceptions.py:27 +#: superset/explore/permalink/exceptions.py:27 superset/key_value/exceptions.py:34 +#: superset/temporary_cache/commands/exceptions.py:29 +msgid "An error occurred while creating the value." +msgstr "Pri ustvarjanju vrednosti je prišlo do težave." -#: superset-frontend/src/explore/controlPanels/sections.tsx:91 -msgid "Annotations and layers" -msgstr "Oznake in sloji" +#: superset/dashboards/permalink/exceptions.py:31 +#: superset/explore/permalink/exceptions.py:31 superset/key_value/exceptions.py:38 +#: superset/temporary_cache/commands/exceptions.py:33 +msgid "An error occurred while accessing the value." +msgstr "Pri dostopanju do vednosti je prišlo do težave." -#: superset/annotation_layers/annotations/commands/exceptions.py:52 -msgid "Annotations could not be deleted." -msgstr "Oznak ni mogoče izbrisati." +#: superset/databases/decorators.py:46 +msgid "Table name undefined" +msgstr "Ime tabele ni definirano" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:441 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:535 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:438 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:496 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:509 -msgid "Any" -msgstr "Katerikoli" +#: superset/databases/filters.py:66 +msgid "Upload Enabled" +msgstr "Nalaganje omogočeno" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:563 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:269 -msgid "Any additional detail to show in the certification tooltip." +#: superset/databases/schemas.py:151 +msgid "" +"Invalid connection string, a valid string usually follows: driver://user:" +"password@database-host/database-name" msgstr "" +"Neveljaven niz povezave - veljaven niz običajno sledi: driver://user:" +"password@database-host/database-name" -#: superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx:56 +#: superset/databases/schemas.py:186 superset/databases/schemas.py:201 +#, python-format +msgid "Field cannot be decoded by JSON. %(msg)s" +msgstr "Polja ni mogoče dekodirati z JSON. %(msg)s" + +#: superset/databases/schemas.py:209 +#, python-format msgid "" -"Any color palette selected here will override the colors applied to this " -"dashboard's individual charts" +"The metadata_params in Extra field is not configured correctly. The key %(key)s " +"is invalid." msgstr "" -"Na tem mestu izbrana barvna shema bo nadomestila barve posameznih " -"grafikonov v tej nadzorni plošči" +"Metadata_params v polju Dodatno niso pravilno nastavljeni. Ključ %(key)s je " +"neveljaven." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:702 -msgid "Any databases that allow connections via SQL Alchemy URIs can be added. " +#: superset/databases/schemas.py:275 +msgid "" +"Engine spec \"InvalidEngine\" does not support being configured via individual " +"parameters." msgstr "" +"Specifikacija baze \"InvalidEngine\" ne podpira konfiguracije s posameznimi " +"parametri." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:716 +#: superset/databases/schemas.py:302 msgid "" -"Any databases that allow connections via SQL Alchemy URIs can be added. " -"Learn about how to connect a database driver " +"An engine must be specified when passing individual parameters to a database." msgstr "" +"Pri podajanju posameznih parametrov podatkovne baze mora biti podan njen tip." -#: superset/views/database/forms.py:147 superset/views/database/forms.py:300 -#: superset/views/database/forms.py:428 -msgid "Append" -msgstr "Dodaj" - -#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:186 +#: superset/databases/commands/validate.py:60 superset/databases/schemas.py:312 #, python-format -msgid "Applied Cross Filters (%d)" -msgstr "Uporabljeni medsebojni filtri (%d)" +msgid "Engine \"%(engine)s\" is not a valid engine." +msgstr "\"%(engine)s\" ni veljaven tip podatkovne baze." -#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:210 +#: superset/databases/commands/exceptions.py:32 +msgid "Database parameters are invalid." +msgstr "Parametri podatkovne baze so neveljavni." + +#: superset/databases/commands/exceptions.py:42 +msgid "A database with the same name already exists." +msgstr "Podatkovna baza z enakim imenom že obstaja." + +#: superset/databases/commands/exceptions.py:50 +msgid "Field is required" +msgstr "Polje je obvezno" + +#: superset/databases/commands/exceptions.py:63 #, python-format -msgid "Applied Filters (%d)" -msgstr "Uporabljeni filtri (%d)" +msgid "Field cannot be decoded by JSON. %(json_error)s" +msgstr "Polja ni mogoče dekodirati z JSON. %(json_error)s" -#: superset/viz.py:237 +#: superset/databases/commands/exceptions.py:80 +#: superset/views/database/mixins.py:255 msgid "" -"Applied rolling window did not return any data. Please make sure the " -"source query satisfies the minimum periods defined in the rolling window." +"The metadata_params in Extra field is not configured correctly. The key %{key}s " +"is invalid." msgstr "" -"Izbrano drseče okno ni vrnilo podatkov. Poskrbite, da izvorna poizvedba " -"ustreza minimalni periodi drsečega okna." +"Metadata_params v polju Dodatno niso pravilno nastavljeni. Ključ %{key}s je " +"neveljaven." -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:458 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:144 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:788 -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:228 -#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:433 -msgid "Apply" -msgstr "Uporabi" +#: superset/databases/commands/exceptions.py:92 +msgid "Database not found." +msgstr "Podatkovna baza ni najdena." -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:321 -msgid "Apply conditional color formatting to metrics" -msgstr "Za mere uporabi pogojno oblikovanje z barvami" +#: superset/databases/commands/exceptions.py:96 +msgid "Database could not be created." +msgstr "Podatkovne baze ni mogoče ustvariti." -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:474 -msgid "Apply conditional color formatting to numeric columns" -msgstr "Za numerične stolpce uporabi pogojno oblikovanje z barvami" +#: superset/databases/commands/exceptions.py:100 +msgid "Database could not be updated." +msgstr "Podatkovne baze ni mogoče posodobiti." -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:79 -msgid "Apply metrics on" -msgstr "Uporabi mero na" +#: superset/databases/commands/exceptions.py:107 +#: superset/databases/commands/exceptions.py:124 superset/views/core.py:1403 +msgid "Connection failed, please check your connection settings" +msgstr "Povezava neuspešna. Preverite nastavitve povezave" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:123 -msgid "Apply to all panels" -msgstr "Uporabi za vse panele" +#: superset/databases/commands/exceptions.py:111 +msgid "Cannot delete a database that has datasets attached" +msgstr "Podatkovne baze s povezanimi podatkovnimi viri ni mogoče izbrisati" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:125 -msgid "Apply to specific panels" -msgstr "Uporabi za določene panele" +#: superset/databases/commands/exceptions.py:115 +msgid "Database could not be deleted." +msgstr "Podatkovne baze ni mogoče izbrisati." -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:69 -msgid "April" -msgstr "April" +#: superset/databases/commands/exceptions.py:128 +msgid "Stopped an unsafe database connection" +msgstr "Nevarna povezava s podatkovno bazo je bila ustavljena" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:49 -msgid "Are you sure you want to cancel?" -msgstr "Ali želite prekiniti?" +#: superset/databases/commands/exceptions.py:132 +msgid "Could not load database driver" +msgstr "Ni mogoče naložiti gonilnika podatkovne baze" -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:80 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:360 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:108 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:358 -msgid "Are you sure you want to delete" -msgstr "Ali ste prepričani, da želite izbrisati" +#: superset/databases/commands/exceptions.py:137 superset/views/core.py:1411 +msgid "Unexpected error occurred, please check your logs for details" +msgstr "Zgodila se je nepričakovana napaka. Podrobnosti preverite v dnevnikih" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:286 -msgid "" -"Are you sure you want to delete " -"${annotationCurrentlyDeleting?.short_descr}?" -msgstr "" -"Ste prepričani, da želite izbrisati " -"${annotationCurrentlyDeleting?.short_descr}?" +#: superset/databases/commands/exceptions.py:142 +msgid "no SQL validator is configured" +msgstr "SQL potrjevalnik ni nastavljen" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:486 -#, python-format -msgid "Are you sure you want to delete the selected %s?" -msgstr "Ali ste prepričani, da želite izbrisati izbrane %s?" +#: superset/databases/commands/exceptions.py:147 +msgid "No validator found (configured for the engine)" +msgstr "Potrjevalnik ni najden (nastavljen za podatkovno bazo)" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:301 -msgid "Are you sure you want to delete the selected annotations?" -msgstr "Ali ste prepričani, da želite izbrisati izbrane oznake?" +#: superset/databases/commands/exceptions.py:152 +#: superset/databases/commands/exceptions.py:162 +msgid "Was unable to check your query" +msgstr "Poizvedbe ni bilo mogoče preveriti" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:645 -msgid "Are you sure you want to delete the selected charts?" -msgstr "Ali ste prepričani, da želite izbrisati izbrane grafikone?" +#: superset/databases/commands/exceptions.py:157 +msgid "An unexpected error occurred" +msgstr "Prišlo je do nepričakovane napake" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:612 -msgid "Are you sure you want to delete the selected dashboards?" -msgstr "Ali ste prepričani, da želite izbrisati izbrane nadzorne plošče?" +#: superset/databases/commands/exceptions.py:166 +msgid "Import database failed for an unknown reason" +msgstr "Uvoz podatkovne baze ni uspel zaradi neznanega razloga" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:618 -msgid "Are you sure you want to delete the selected datasets?" -msgstr "Ali ste prepričani, da želite izbrisati izbrane podatkovne sete?" +#: superset/databases/commands/test_connection.py:134 +msgid "Could not load database driver: {}" +msgstr "Ni mogoče naložiti gonilnika podatkovne baze: {}" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:366 -msgid "Are you sure you want to delete the selected layers?" -msgstr "Ali ste prepričani, da želite izbrisati izbrane sloje?" +#: superset/databases/commands/validate.py:73 +#, python-format +msgid "Engine \"%(engine)s\" cannot be configured through parameters." +msgstr "Podatkovne baze tipa \"%(engine)s\" ni mogoče konfigurirati s parametri." -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:500 -msgid "Are you sure you want to delete the selected queries?" -msgstr "Ali ste prepričani, da želite izbrisati izbrane poizvedbe?" +#: superset/databases/commands/validate.py:140 +msgid "Database is offline." +msgstr "Podatkovna baza ni povezana." -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:326 -msgid "Are you sure you want to delete the selected templates?" -msgstr "Ali ste prepričani, da želite izbrisati izbrane predloge?" +#: superset/databases/commands/validate_sql.py:73 superset/views/core.py:2372 +#, python-format +msgid "" +"%(validator)s was unable to check your query.\n" +"Please recheck your query.\n" +"Exception: %(ex)s" +msgstr "" +"%(validator)s ni mogel preveriti vaše poizvedbe.\n" +"Ponovno preverite poizvedbo.\n" +"Izjema: %(ex)s" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:133 -msgid "Are you sure you want to proceed?" -msgstr "Ali želite nadaljevati?" +#: superset/databases/commands/validate_sql.py:101 +msgid "no SQL validator is configured for {}" +msgstr "SQL potrjevalnik ni nastavljen za {}" -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:173 -msgid "Are you sure you want to save and apply changes?" -msgstr "Ali resnično želite shraniti in uporabiti spremembe?" +#: superset/databases/commands/validate_sql.py:114 +msgid "No validator named {} found (configured for the {} engine)" +msgstr "Potrjevalnik {} ni bil najden (nastavljen za podatkovno bazo {})" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:41 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:132 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:135 -msgid "Area Chart" -msgstr "Ploščinski grafikon" +#: superset/datasets/api.py:680 +#, python-format +msgid "Deleted %(num)d dataset" +msgid_plural "Deleted %(num)d datasets" +msgstr[0] "Izbrisan %(num)d podatkovni set" +msgstr[1] "Izbrisana %(num)d podatkovna niza" +msgstr[2] "Izbrisani %(num)d podatkovni nizi" +msgstr[3] "Izbrisanih %(num)d podatkovnih nizov" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:168 -msgid "Area chart" -msgstr "Ploščinski grafikon" +#: superset/datasets/filters.py:26 +msgid "Null or Empty" +msgstr "Nič (NULL) ali prazen" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:131 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:146 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:149 -msgid "Area chart opacity" -msgstr "Prosojnost ploščinskega grafikona" +#: superset/datasets/columns/commands/exceptions.py:23 +msgid "Dataset column not found." +msgstr "Stolpec podatkovnega seta ni najden." -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:238 -msgid "Arrow" -msgstr "Puščica" +#: superset/datasets/columns/commands/exceptions.py:27 +msgid "Dataset column delete failed." +msgstr "Brisanje stolpca podatkovnega seta neuspešno." -#: superset/connectors/druid/views.py:342 superset/connectors/sqla/views.py:487 -msgid "Associated Charts" -msgstr "Povezani grafikoni" +#: superset/datasets/columns/commands/exceptions.py:31 +#: superset/datasets/metrics/commands/exceptions.py:31 +msgid "Changing this dataset is forbidden." +msgstr "Spreminjanje tega podatkovnega seta ni dovoljeno." -#: superset/views/database/mixins.py:199 -msgid "Async Execution" -msgstr "Asinhrono izvajanje" +#: superset/datasets/commands/exceptions.py:32 +#, python-format +msgid "Dataset %(name)s already exists" +msgstr "Podatkovni set %(name)s že obstaja" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:236 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:401 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:285 -msgid "Asynchronous query execution" -msgstr "Asinhroni zagon poizvedb" +#: superset/datasets/commands/exceptions.py:50 +msgid "Database not allowed to change" +msgstr "Podatkovne baze ni dovoljeno spreminjati" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:73 -msgid "August" -msgstr "Avgust" +#: superset/datasets/commands/exceptions.py:70 +msgid "One or more columns do not exist" +msgstr "En ali več stolpcev ne obstaja" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:523 -msgid "Autocomplete" -msgstr "Samodokončaj" +#: superset/datasets/commands/exceptions.py:80 +msgid "One or more columns are duplicated" +msgstr "En ali več stolpcev je podvojenih" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:708 -msgid "Autocomplete filters" -msgstr "Samodokončaj filtre" +#: superset/datasets/commands/exceptions.py:90 +msgid "One or more columns already exist" +msgstr "En ali več stolpcev že obstaja" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:715 -msgid "Autocomplete query predicate" -msgstr "Predikat za samodokončanje poizvedb" +#: superset/datasets/commands/exceptions.py:99 +msgid "One or more metrics do not exist" +msgstr "Ena ali več mer ne obstaja" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:242 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:270 -msgid "Available sorting modes:" -msgstr "" +#: superset/datasets/commands/exceptions.py:109 +msgid "One or more metrics are duplicated" +msgstr "Ena ali več mer je podvojenih" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:200 -msgid "Axis" -msgstr "Os" +#: superset/datasets/commands/exceptions.py:119 +msgid "One or more metrics already exist" +msgstr "Ena ali več mer že obstaja" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:36 -msgid "Axis ascending" -msgstr "Naraščajoča os" +#: superset/datasets/commands/exceptions.py:130 +#, python-format +msgid "" +"Table [%(table_name)s] could not be found, please double check your database " +"connection, schema, and table name" +msgstr "" +"Tabele [%(table_name)s] ni mogoče najti. Preverite povezavo, shemo in ime " +"podatkovne baze" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:37 -msgid "Axis descending" -msgstr "Padajoča os" +#: superset/datasets/commands/exceptions.py:149 +msgid "Dataset does not exist" +msgstr "Podatkovni set ne obstaja" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:770 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:786 -msgid "Back" -msgstr "Nazaj" +#: superset/datasets/commands/exceptions.py:153 +msgid "Dataset parameters are invalid." +msgstr "Parametri podatkovnega seta so neveljavni." -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:227 -#: superset/views/database/mixins.py:204 -msgid "Backend" -msgstr "Vrsta" +#: superset/datasets/commands/exceptions.py:157 +msgid "Dataset could not be created." +msgstr "Podatkovnega niza ni mogoče ustvariti." -#: superset/viz.py:2472 superset/viz.py:2508 -msgid "Bad spatial key" -msgstr "Neustrezen prostorski ključ" +#: superset/datasets/commands/exceptions.py:161 +#: superset/datasets/commands/exceptions.py:173 +msgid "Dataset could not be updated." +msgstr "Podatkovnega niza ni mogoče posodobiti." -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:85 -msgid "Bar" -msgstr "Stolpec" +#: superset/datasets/commands/exceptions.py:165 +msgid "Dataset could not be deleted." +msgstr "Podatkovnega niza ni mogoče izbrisati." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:38 -msgid "Bar Chart" -msgstr "Stolpčni grafikon" +#: superset/datasets/commands/exceptions.py:169 +msgid "Dataset(s) could not be bulk deleted." +msgstr "Podatkovnih nizov ni mogoče množično izbrisati." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:294 -msgid "Bar Values" -msgstr "Vrednosti stolpcev" +#: superset/datasets/commands/exceptions.py:177 +msgid "Samples for dataset could not be retrieved." +msgstr "Vzorcev za podatkovni set ni bilo mogoče pridobiti." -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:227 -msgid "Base layer map style" -msgstr "Slog osnovnega sloja zemljevida" +#: superset/datasets/commands/exceptions.py:181 +msgid "Changing this dataset is forbidden" +msgstr "Spreminjanje tega podatkovnega seta ni dovoljeno" -#: superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx:165 -msgid "Based on a metric" -msgstr "Osnovan na meri" +#: superset/datasets/commands/exceptions.py:185 +msgid "Import dataset failed for an unknown reason" +msgstr "Uvoz podatkovnega seta ni uspel zaradi neznanega razloga" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:50 -msgid "Based on granularity, number of time periods to compare against" -msgstr "Na osnovi granulacije, število časovnih obdobij za primerjavo" +#: superset/datasets/commands/exceptions.py:189 +msgid "You don't have access to this dataset." +msgstr "Nimate dostopa do tega podatkovnega seta." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:686 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:263 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1034 -msgid "Basic" -msgstr "Osnovno" +#: superset/datasets/metrics/commands/exceptions.py:23 +msgid "Dataset metric not found." +msgstr "Mer podatkovnega seta ni najdena." -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:497 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:229 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:288 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:243 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:237 -msgid "Basic information" -msgstr "Osnovne informacije" +#: superset/datasets/metrics/commands/exceptions.py:27 +msgid "Dataset metric delete failed." +msgstr "Brisanje mere podatkovnega seta ni uspelo." -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:486 +#: superset/db_engine_specs/athena.py:55 superset/db_engine_specs/bigquery.py:181 +#: superset/db_engine_specs/postgres.py:145 +#: superset/db_engine_specs/snowflake.py:105 #, python-format -msgid "Batch editing %d filters:" -msgstr "Skupinsko urejanje %d filtrov:" +msgid "" +"Please check your query for syntax errors at or near \"%(syntax_error)s\". Then, " +"try running your query again." +msgstr "" +"Preverite, če ima vaša poizvedba sintaktične napake pri \"%(syntax_error)s\". " +"Potem ponovno poženite poizvedbo." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:36 -msgid "Battery level over time" -msgstr "Napolnjenost baterije skozi čas" +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:29 +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:143 +#: superset/db_engine_specs/base.py:96 +msgid "Original value" +msgstr "Izvorna vrednost" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1175 -msgid "Be careful." -msgstr "Bodite previdni." +#: superset/db_engine_specs/base.py:97 +msgid "Second" +msgstr "Sekunda" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:76 -msgid "Before" -msgstr "PRED" +#: superset/db_engine_specs/base.py:98 +msgid "5 second" +msgstr "5 sekund" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:38 -#: superset/viz.py:1254 -msgid "Big Number" -msgstr "Velika številka" +#: superset/db_engine_specs/base.py:99 +msgid "30 second" +msgstr "30 sekund" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:28 -msgid "Big Number Font Size" -msgstr "Velikost pisave Velike številke" +#: superset/db_engine_specs/base.py:100 +msgid "Minute" +msgstr "Minuta" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:34 -#: superset/viz.py:1220 -msgid "Big Number with Trendline" -msgstr "Velika številka s trendno krivuljo" +#: superset/db_engine_specs/base.py:101 +msgid "5 minute" +msgstr "5 minut" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:290 -msgid "Bottom" -msgstr "Spodaj" +#: superset/db_engine_specs/base.py:102 +msgid "10 minute" +msgstr "10 minut" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:212 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:187 -msgid "Bottom Margin" -msgstr "Spodnji rob" +#: superset/db_engine_specs/base.py:103 +msgid "15 minute" +msgstr "15 minut" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:224 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:191 -msgid "Bottom margin, in pixels, allowing for more room for axis labels" -msgstr "Spodnji rob, v pikslih, s katerim povečamo prostor za oznake osi" +#: superset/db_engine_specs/base.py:104 +msgid "30 minute" +msgstr "30 minut" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:140 -msgid "Bottom to Top" -msgstr "Iz dna proti vrhu" +#: superset/db_engine_specs/base.py:105 +msgid "Hour" +msgstr "Ura" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:241 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:257 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:357 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:272 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:235 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:215 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:232 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:288 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:291 -msgid "" -"Bounds for the Y-axis. When left empty, the bounds are dynamically " -"defined based on the min/max of the data. Note that this feature will " -"only expand the axis range. It won't narrow the data's extent." -msgstr "" -"Meje Y-osi. Če je prazno, se meje nastavijo dinamično na podlagi " -"min./max. vrednosti podatkov. Funkcija omeji le prikaz, obseg podatkov pa" -" ostane enak." +#: superset/db_engine_specs/base.py:106 +msgid "6 hour" +msgstr "6 ur" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/BoxPlot/index.js:26 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:54 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/createMetadata.ts:27 -msgid "Box Plot" -msgstr "Box Plot" +#: superset/db_engine_specs/base.py:107 +msgid "Day" +msgstr "Dan" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:133 -msgid "Breakdowns" -msgstr "Razčlenitev" +#: superset/db_engine_specs/base.py:108 +msgid "Week" +msgstr "Teden" + +#: superset/db_engine_specs/base.py:109 +msgid "Month" +msgstr "Mesec" + +#: superset/db_engine_specs/base.py:110 +msgid "Quarter" +msgstr "Četrtletje" -#: superset/connectors/druid/views.py:237 -msgid "Broker Endpoint" -msgstr "Končna točka posrednika" +#: superset/db_engine_specs/base.py:111 +msgid "Year" +msgstr "Leto" -#: superset/connectors/druid/views.py:233 -msgid "Broker Host" -msgstr "Gostitelj posrednika" +#: superset/db_engine_specs/base.py:112 +msgid "Week starting Sunday" +msgstr "Teden z začetkom v nedeljo" -#: superset/connectors/druid/views.py:236 -msgid "Broker Password" -msgstr "Geslo posrednika" +#: superset/db_engine_specs/base.py:113 +msgid "Week starting Monday" +msgstr "Teden z začetkom v ponedeljek" -#: superset/connectors/druid/views.py:234 -msgid "Broker Port" -msgstr "Vrata posrednika" +#: superset/db_engine_specs/base.py:114 +msgid "Week ending Saturday" +msgstr "Teden s koncem v soboto" -#: superset/connectors/druid/views.py:235 -msgid "Broker Username" -msgstr "Uporabniško ime posrednika" +#: superset/db_engine_specs/base.py:115 +msgid "Week_ending Sunday" +msgstr "Teden s koncem v nedeljo" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:30 -#: superset/viz.py:1139 -msgid "Bubble Chart" -msgstr "Mehurčkasti grafikon" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:109 +#: superset/db_engine_specs/base.py:1544 +msgid "Username" +msgstr "Uporabniško ime" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:127 -msgid "Bubble Color" -msgstr "Barva mehurčka" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:130 +#: superset/db_engine_specs/base.py:1545 +msgid "Password" +msgstr "Geslo" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:141 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:420 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:123 -msgid "Bubble Size" -msgstr "Velikost mehurčka" +#: superset/db_engine_specs/base.py:1546 +msgid "Hostname or IP address" +msgstr "Ime gostitelja ali IP naslov" -#: superset-frontend/src/explore/controls.jsx:435 -msgid "Bubble size" -msgstr "Velikost mehurčka" +#: superset/db_engine_specs/base.py:1549 +msgid "Database port" +msgstr "Vrata podatkovne baze" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:362 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:212 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:277 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:597 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:262 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:572 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:495 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:169 -msgid "Bulk select" -msgstr "Izberi hkrati" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:89 +#: superset/db_engine_specs/base.py:1552 +msgid "Database name" +msgstr "Ime podatkovne baze" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:30 -#: superset/viz.py:1190 -msgid "Bullet Chart" -msgstr "'Bullet' grafikon" +#: superset/db_engine_specs/base.py:1554 +msgid "Additional parameters" +msgstr "Dodatni parametri" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:32 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:40 -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:35 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:41 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:54 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:45 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:55 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:44 -msgid "Business" -msgstr "Aktivnost" +#: superset/db_engine_specs/base.py:1557 +msgid "Use an encrypted connection to the database" +msgstr "Uporabite šifrirano povezavo s podatkovno bazo" -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:233 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:139 +#: superset/db_engine_specs/bigquery.py:151 msgid "" -"By default, each filter loads at most 1000 choices at the initial page " -"load. Check this box if you have more than 1000 filter values and want to" -" enable dynamically searching that loads filter values as users type (may" -" add stress to your database)." +"We were unable to connect to your database. Please confirm that your service " +"account has the Viewer and Job User roles on the project." msgstr "" -"Privzeto vsak filter pri nalaganju začetne strani naloži največ 1000 " -"možnosti. Označite polje, če imate več kot 1000 vrednosti filtra in " -"želite omogočiti dinamično iskanje, ki nalaga vrednosti filtra ko " -"uporabnik tipka (to lahko preobremeni vašo podatkovno bazo)." +"Povezava s podatkovno bazo ni uspela. Preverite, da ima vaš dostop dodeljeni " +"vlogi Viewer in Job User." -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:272 -msgid "By key: use column names as sorting key" +#: superset/db_engine_specs/bigquery.py:160 +#, python-format +msgid "" +"The table \"%(table)s\" does not exist. A valid table must be used to run this " +"query." msgstr "" +"Tabela \"%(table)s\" ne obstaja. V poizvedbi mora biti uporabljena veljavna " +"tabela." -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:244 -msgid "By key: use row names as sorting key" +#: superset/db_engine_specs/bigquery.py:168 +#, python-format +msgid "We can't seem to resolve column \"%(column)s\" at line %(location)s." msgstr "" +"Zdi se, da ni mogoče razrešiti stolpca \"%(column)s\" v vrstici %(location)s." -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:245 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:273 -msgid "By value: use metric values as sorting key" +#: superset/db_engine_specs/bigquery.py:173 +#, python-format +msgid "" +"The schema \"%(schema)s\" does not exist. A valid schema must be used to run this " +"query." msgstr "" +"Shema \"%(schema)s\" ne obstaja. Za poizvedbo mora biti uporabljena veljavna " +"shema." -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:334 -msgid "CANCEL" -msgstr "PREKINI" +#: superset/db_engine_specs/duckdb.py:56 superset/db_engine_specs/sqlite.py:65 +#, python-format +msgid "We can't seem to resolve the column \"%(column_name)s\"" +msgstr "Zdi se, da ni mogoče razrešiti stolpca \"%(column_name)s\"" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:601 -msgid "CREATE TABLE AS" -msgstr "CREATE TABLE AS" +#: superset/db_engine_specs/gsheets.py:74 superset/db_engine_specs/mysql.py:172 +#, python-format +msgid "" +"Please check your query for syntax errors near \"%(server_error)s\". Then, try " +"running your query again." +msgstr "" +"Preverite, če ima vaša poizvedba sintaktične napake pri \"%(server_error)s\". " +"Potem ponovno poženite poizvedbo." -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:614 -msgid "CREATE VIEW AS" -msgstr "CREATE VIEW AS" +#: superset/db_engine_specs/mssql.py:76 +#, python-format +msgid "" +"Either the username \"%(username)s\", password, or database name \"%(database)s\" " +"is incorrect." +msgstr "" +"Uporabniško ime \"%(username)s\", geslo ali ime podatkovne baze \"%(database)s\" " +"so napačni." -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:205 -msgid "CREATE VIEW statement" -msgstr "CREATE VIEW stavek" +#: superset/db_engine_specs/mssql.py:84 superset/db_engine_specs/postgres.py:114 +#: superset/db_engine_specs/presto.py:197 superset/db_engine_specs/redshift.py:68 +#, python-format +msgid "The hostname \"%(hostname)s\" cannot be resolved." +msgstr "Imena gostitelja \"%(hostname)s\" ni mogoče razrešiti." -#: superset-frontend/src/views/CRUD/alert/components/AlertReportCronScheduler.tsx:75 -msgid "CRON expression" -msgstr "Izraz CRON" +#: superset/db_engine_specs/mssql.py:89 superset/db_engine_specs/postgres.py:119 +#: superset/db_engine_specs/presto.py:210 superset/db_engine_specs/redshift.py:73 +#, python-format +msgid "Port %(port)s on hostname \"%(hostname)s\" refused the connection." +msgstr "Vrata %(port)s na gostitelju \"%(hostname)s\" niso sprejela povezave." -#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:104 -#: superset/views/dashboard/mixin.py:88 -msgid "CSS" -msgstr "CSS" +#: superset/db_engine_specs/mssql.py:94 superset/db_engine_specs/postgres.py:124 +#: superset/db_engine_specs/presto.py:202 superset/db_engine_specs/redshift.py:78 +#, python-format +msgid "" +"The host \"%(hostname)s\" might be down, and can't be reached on port %(port)s." +msgstr "" +"Gostitelj \"%(hostname)s\" mogoče ne deluje in ga ni mogoče doseči na vratih " +"%(port)s." -#: superset/initialization/__init__.py:265 superset/views/css_templates.py:36 -msgid "CSS Templates" -msgstr "CSS predloge" +#: superset/db_engine_specs/mysql.py:152 superset/db_engine_specs/presto.py:192 +#: superset/db_engine_specs/redshift.py:63 +#, python-format +msgid "Either the username \"%(username)s\" or the password is incorrect." +msgstr "Uporabniško ime \"%(username)s\" ali geslo sta napačna." -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:249 -msgid "CSS template" -msgstr "CSS predloga" +#: superset/db_engine_specs/mysql.py:157 +#, python-format +msgid "Unknown MySQL server host \"%(hostname)s\"." +msgstr "Neznan MySQL strežnik \"%(hostname)s\"." -#: superset/css_templates/commands/exceptions.py:23 -msgid "CSS template could not be deleted." -msgstr "CSS predloge ni mogoče izbrisati." +#: superset/db_engine_specs/mysql.py:162 +#, python-format +msgid "The host \"%(hostname)s\" might be down and can't be reached." +msgstr "Gostitelj \"%(hostname)s\" mogoče ne deluje in ga ni mogoče doseči." -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:241 -msgid "CSS template name" -msgstr "Ime CSS predloge" +#: superset/db_engine_specs/mysql.py:167 superset/db_engine_specs/postgres.py:132 +#, python-format +msgid "Unable to connect to database \"%(database)s\"." +msgstr "Povezava s podatkovno bazo \"%(database)s\" ni uspela." -#: superset/css_templates/commands/exceptions.py:27 -msgid "CSS template not found." -msgstr "CSS predloga ni najdena." +#: superset/db_engine_specs/postgres.py:99 +#, python-format +msgid "The username \"%(username)s\" does not exist." +msgstr "Uporabniško ime \"%(username)s\" ne obstaja." -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:71 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:240 -msgid "CSS templates" -msgstr "CSS predloge" +#: superset/db_engine_specs/postgres.py:104 +#, python-format +msgid "The password provided for username \"%(username)s\" is incorrect." +msgstr "Geslo za uporabniško ime \"%(username)s\" je napačno." -#: superset/views/database/forms.py:101 -msgid "CSV File" -msgstr "CSV datoteka" +#: superset/db_engine_specs/postgres.py:109 +msgid "Please re-enter the password." +msgstr "Ponovno vpišite geslo." -#: superset/views/database/views.py:252 +#: superset/db_engine_specs/postgres.py:137 superset/db_engine_specs/presto.py:168 #, python-format msgid "" -"CSV file \"%(csv_filename)s\" uploaded to table \"%(table_name)s\" in " -"database \"%(db_name)s\"" +"We can't seem to resolve the column \"%(column_name)s\" at line %(location)s." msgstr "" -"CSV datoteka \"%(csv_filename)s\" naložena v tabelo \"%(table_name)s\" v " -"podatkovni bazi \"%(db_name)s\"" - -#: superset/views/database/views.py:118 -msgid "CSV to Database configuration" -msgstr "Nastavitve pretvorbe CSV v podatkovno bazo" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:271 -msgid "CSV upload" -msgstr "Nalaganje CSV" +"Zdi se, da ni mogoče razrešiti stolpca \"%(column_name)s\" v vrstici %(location)s." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:118 -msgid "CTAS & CVAS SCHEMA" -msgstr "CTAS & CVAS SHEMA" - -#: superset/sql_lab.py:405 +#: superset/db_engine_specs/presto.py:176 +#, python-format msgid "" -"CTAS (create table as select) can only be run with a query where the last" -" statement is a SELECT. Please make sure your query has a SELECT as its " -"last statement. Then, try running your query again." +"The table \"%(table_name)s\" does not exist. A valid table must be used to run " +"this query." msgstr "" -"CTAS (create table as select) lahko izvajate le v poizvedbah, kjer je " -"zadnji stavek SELECT. Poskrbite, da bo zadnji stavek v vaši poizvedbi " -"SELECT in poskusite ponovno zagnati poizvedbo." - -#: superset/views/database/mixins.py:190 -msgid "CTAS Schema" -msgstr "CTAS shema" +"Tabela \"%(table_name)s\" ne obstaja. V poizvedbi mora biti uporabljena veljavna " +"tabela." -#: superset/sql_lab.py:422 +#: superset/db_engine_specs/presto.py:184 +#, python-format msgid "" -"CVAS (create view as select) can only be run with a query with a single " -"SELECT statement. Please make sure your query has only a SELECT " -"statement. Then, try running your query again." +"The schema \"%(schema_name)s\" does not exist. A valid schema must be used to run " +"this query." msgstr "" -"CVAS (create view as select) lahko izvajate le v poizvedbah z enim SELECT" -" stavkom. Poskrbite, da bo v vaši poizvedbi le en SELECT stavek in " -"poskusite ponovno zagnati poizvedbo." - -#: superset/errors.py:123 -msgid "CVAS (create view as select) query has more than one statement." -msgstr "CVAS (create view as select) poizvedba ima več kot en stavek." - -#: superset/errors.py:124 -msgid "CVAS (create view as select) query is not a SELECT statement." -msgstr "CVAS (create view as select) poizvedba ni SELECT stavek." +"Shema \"%(schema_name)s\" ne obstaja. Za poizvedbo mora biti uporabljena veljavna " +"shema." -#: superset/connectors/druid/views.py:239 -#: superset/connectors/druid/views.py:351 superset/connectors/sqla/views.py:497 -#: superset/views/chart/mixin.py:77 -msgid "Cache Timeout" -msgstr "Trajanje predpomnilnika" +#: superset/db_engine_specs/presto.py:215 +#, python-format +msgid "Unable to connect to catalog named \"%(catalog_name)s\"." +msgstr "Povezava na katalog \"%(catalog_name)s\" ni uspela." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:67 -#: superset-frontend/src/explore/controlPanels/sections.tsx:51 -msgid "Cache Timeout (seconds)" -msgstr "Trajanje predpomnilnika (sekunde)" +#: superset/db_engine_specs/presto.py:1021 +msgid "Unknown Presto Error" +msgstr "Neznana Presto napaka" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:771 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:278 -msgid "Cache timeout" -msgstr "Časovna omejitev predpomnilnika" +#: superset/db_engine_specs/redshift.py:86 +#, python-format +msgid "" +"We were unable to connect to your database named \"%(database)s\". Please verify " +"your database name and try again." +msgstr "" +"Povezava s podatkovno bazo \"%(database)s\" ni uspela. Preverite ime podatkovne " +"baze in poskusite ponovno." -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:241 +#: superset/db_engine_specs/snowflake.py:100 #, python-format -msgid "Cached %s" -msgstr "Predpomnjeno %s" +msgid "%(object)s does not exist in this database." +msgstr "%(object)s ne obstaja v tej podatkovni bazi." -#: superset/viz.py:539 -msgid "Cached value not found" -msgstr "Predpomnjena vrednost ni najdena" +#: superset/embedded_dashboard/commands/exceptions.py:34 +msgid "You don't have access to this embedded dashboard config." +msgstr "Nimate dostopa do konfiguracije te vgrajene nadzorne plošče." -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:70 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:77 -msgid "Calculate contribution per series or total" -msgstr "Izračunaj delež za podatkovno serijo ali skupnega" +#: superset/initialization/__init__.py:221 +msgid "Home" +msgstr "Domov" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:667 -#, python-format -msgid "Calculated column [%s] requires an expression" -msgstr "Izračunan stolpec [%s] zahteva izraz" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/annotationsAndLayers.tsx:36 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:115 +#: superset/initialization/__init__.py:228 superset/views/annotations.py:113 +msgid "Annotation Layers" +msgstr "Sloji z oznakami" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1241 -msgid "Calculated columns" -msgstr "Izračunani stolpci" +#: superset/initialization/__init__.py:231 superset/initialization/__init__.py:255 +#: superset/initialization/__init__.py:267 superset/initialization/__init__.py:316 +#: superset/initialization/__init__.py:389 +msgid "Manage" +msgstr "Upravljaj" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:121 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:334 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:217 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:469 -#: superset-frontend/src/explore/controlPanels/sections.tsx:232 -msgid "Calculation type" -msgstr "Tip izračuna" +#: superset-frontend/src/profile/components/CreatedContent.tsx:84 +#: superset-frontend/src/profile/components/Favorites.tsx:85 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:630 +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:308 +#: superset/initialization/__init__.py:237 superset/views/chart/mixin.py:79 +#: superset/views/dashboard/mixin.py:25 +msgid "Dashboards" +msgstr "Nadzorne plošče" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:30 -#: superset/viz.py:1048 -msgid "Calendar Heatmap" -msgstr "Koledarska barvna lestvica" +#: superset-frontend/src/dashboard/components/BuilderComponentPane/index.tsx:106 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx:61 +#: superset-frontend/src/profile/components/CreatedContent.tsx:87 +#: superset-frontend/src/profile/components/Favorites.tsx:88 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:677 +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:320 +#: superset/initialization/__init__.py:245 superset/views/chart/mixin.py:26 +#: superset/views/dashboard/mixin.py:81 +msgid "Charts" +msgstr "Grafikoni" -#: superset-frontend/src/dashboard/actions/dashboardLayout.js:211 -msgid "Can not move top level tab into nested tabs" -msgstr "Najvišjega zavihka ni mogoče premakniti v gnezdene zavihke" +#: superset/initialization/__init__.py:253 +msgid "Plugins" +msgstr "Vtičniki" -#: superset/views/core.py:2010 -#, python-format -msgid "Can't find DruidCluster with cluster_name = '%(name)s'" -msgstr "Ni mogoče najti DruidCluster s cluster_name = '%(name)s'" +#: superset/initialization/__init__.py:264 superset/views/css_templates.py:35 +msgid "CSS Templates" +msgstr "CSS predloge" -#: superset/views/core.py:1998 -#, python-format -msgid "Can't find User '%(name)s', please ask your admin to create one." -msgstr "" -"Uporabnika '%(name)s' ni mogoče najti. Prosite administratorja, da ga " -"ustvari." +#: superset/initialization/__init__.py:273 +msgid "Row Level Security" +msgstr "Varnost na nivoju vrstic" -#: superset/viz.py:1778 -msgid "Can't have overlap between Series and Breakdowns" -msgstr "Ne sme imeti prekrivanja med podatkovnimi serijami in členitvami" +#: superset/initialization/__init__.py:275 superset/initialization/__init__.py:372 +#: superset/initialization/__init__.py:399 +msgid "Security" +msgstr "Varnost" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:173 -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:218 -#: superset-frontend/src/components/Modal/Modal.tsx:240 -#: superset-frontend/src/components/ReportModal/index.tsx:259 -#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:80 -#: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:72 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:474 -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:151 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:137 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:76 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:62 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:194 -#: superset-frontend/src/explore/components/SaveModal.tsx:179 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:775 -#: superset/templates/superset/request_access.html:34 -msgid "Cancel" -msgstr "Prekliči" +#: superset/initialization/__init__.py:312 +msgid "Import Dashboards" +msgstr "Uvozi nadzorne plošče" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:304 -msgid "Cancel query on window unload event" -msgstr "Prekini poizvedbo pri dogodku zaprtja okna (window unload event)" +#: superset/initialization/__init__.py:324 +msgid "SQL Editor" +msgstr "SQL urejevalnik" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts:83 -msgid "Cannot create cyclic hierarchy" -msgstr "Ciklične hierarhije ni mogoče ustvariti" +#: superset/initialization/__init__.py:329 superset/initialization/__init__.py:344 +msgid "SQL Lab" +msgstr "SQL laboratorij" -#: superset/databases/commands/exceptions.py:109 -msgid "Cannot delete a database that has datasets attached" -msgstr "Podatkovne baze s povezanimi podatkovnimi viri ni mogoče izbrisati" +#: superset/initialization/__init__.py:332 +msgid "Saved Queries" +msgstr "Shranjene poizvedbe" -#: superset/views/core.py:700 -#, python-format -msgid "" -"Cannot import dashboard: %(db_error)s.\n" -"Make sure to create the database before importing the dashboard." -msgstr "" -"Nadzorne plošče ni mogoče uvoziti: %(db_error)s.\n" -"Pred uvozom poskrbite za ustvarjenje podatkovne baze." +#: superset/initialization/__init__.py:339 +msgid "Query History" +msgstr "Zgodovina poizvedb" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:242 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:944 -msgid "Cannot load filter" -msgstr "Filtra ni mogoče naložiti" +#: superset-frontend/src/profile/components/Security.tsx:46 +#: superset-frontend/src/views/CRUD/data/common.ts:26 +#: superset/initialization/__init__.py:349 superset/views/database/mixins.py:33 +msgid "Databases" +msgstr "Podatkovne baze" -#: superset/charts/commands/exceptions.py:51 -#, python-format -msgid "Cannot parse time string [%(human_readable)s]" -msgstr "Ni mogoče razčleniti časovnega izraza [%(human_readable)s]" +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:492 +#: superset-frontend/src/views/CRUD/data/common.ts:22 +#: superset-frontend/src/views/components/MenuRight.tsx:132 +#: superset/initialization/__init__.py:352 superset/initialization/__init__.py:361 +msgid "Data" +msgstr "Podatki" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:38 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:42 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:41 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:41 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:59 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:42 -msgid "Categorical" -msgstr "Kategorični" +#: superset-frontend/src/profile/components/Security.tsx:60 +#: superset-frontend/src/views/CRUD/data/common.ts:32 +#: superset/initialization/__init__.py:357 +msgid "Datasets" +msgstr "Podatkovni seti" -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:129 -msgid "Categories to group by on the x-axis." -msgstr "Kategorije za združevanje po x-osi." +#: superset/initialization/__init__.py:370 +msgid "Action Log" +msgstr "Dnevnik aktivnosti" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:602 -msgid "Category" -msgstr "Kategorija" +#: superset/initialization/__init__.py:387 +msgid "Alerts & Reports" +msgstr "Opozorila in poročila" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:87 -msgid "Category of target nodes" -msgstr "Kategorija ciljnih vozlišč" +#: superset/initialization/__init__.py:397 +msgid "Access requests" +msgstr "Zahteve za dostop" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:103 -msgid "Cell Padding" -msgstr "Razmak med celicami" +#: superset/key_value/exceptions.py:30 +msgid "An error occurred while parsing the key." +msgstr "Pri branju ključa je prišlo do težave." -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:117 -msgid "Cell Radius" -msgstr "Polmer celice" +#: superset/key_value/exceptions.py:42 +#: superset/temporary_cache/commands/exceptions.py:37 +msgid "An error occurred while deleting the value." +msgstr "Pri brisanju vrednosti je prišlo do napake." -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:91 -msgid "Cell Size" -msgstr "Velikost celice" +#: superset/key_value/exceptions.py:46 +#: superset/temporary_cache/commands/exceptions.py:41 +msgid "An error occurred while updating the value." +msgstr "Pri posodabljanju vrednosti je prišlo do težave." -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:413 -msgid "Cell bars" -msgstr "Stolp. graf v celicah" +#: superset/key_value/exceptions.py:50 +#: superset/temporary_cache/commands/exceptions.py:45 +msgid "You don't have permission to modify the value." +msgstr "Nimate dovoljenja za spreminjanje vrednosti." -#: superset-frontend/src/components/FilterableTable/FilterableTable.tsx:319 -msgid "Cell content" -msgstr "Vsebina celice" +#: superset/key_value/utils.py:60 +msgid "Invalid permalink key" +msgstr "Neveljaven ključ povezave" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:112 -msgid "Center" -msgstr "Na sredino" +#: superset/queries/saved_queries/api.py:201 +#, python-format +msgid "Deleted %(num)d saved query" +msgid_plural "Deleted %(num)d saved queries" +msgstr[0] "Izbrisana %(num)d shranjena poizvedba" +msgstr[1] "Izbrisani %(num)d shranjeni poizvedbi" +msgstr[2] "Izbrisane %(num)d shranjene poizvedbe" +msgstr[3] "Izbrisanih %(num)d shranjenih poizvedb" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:533 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:252 -#, fuzzy -msgid "Certification" -msgstr "Podrobnosti certifikacije" +#: superset/queries/saved_queries/commands/exceptions.py:28 +msgid "Saved queries could not be deleted." +msgstr "Shranjenih poizvedb ni mogoče izbrisati." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:270 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:275 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1079 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1085 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:553 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:555 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:263 -msgid "Certification details" -msgstr "Podrobnosti certifikacije" +#: superset/queries/saved_queries/commands/exceptions.py:32 +msgid "Saved query not found." +msgstr "Shranjena poizvedba ni najdena." -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:530 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:504 -#, fuzzy -msgid "Certified" -msgstr "Certificiral/a" +#: superset/queries/saved_queries/commands/exceptions.py:36 +msgid "Import saved query failed for an unknown reason." +msgstr "Uvoz shranjene poizvedbe ni uspel zaradi neznanega razloga." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:259 -msgid "Certified By" -msgstr "Certificiral/a" +#: superset/queries/saved_queries/commands/exceptions.py:40 +msgid "Saved query parameters are invalid." +msgstr "Parametri shranjene poizvedbe so neveljavni." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:264 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1066 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1074 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:538 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:540 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:254 -msgid "Certified by" -msgstr "Certificiral/a" +#: superset/reports/api.py:492 +#, python-format +msgid "Deleted %(num)d report schedule" +msgid_plural "Deleted %(num)d report schedules" +msgstr[0] "Izbrisan %(num)d urnik poročanja" +msgstr[1] "Izbrisana %(num)d urnika poročanja" +msgstr[2] "Izbrisani %(num)d urniki poročanja" +msgstr[3] "Izbrisanih %(num)d urnikov poročanja" -#: superset-frontend/packages/superset-ui-chart-controls/src/components/CertifiedIconWithTooltip.tsx:46 -#: superset-frontend/src/components/CertifiedIcon/index.tsx:42 +#: superset/reports/schemas.py:186 superset/reports/schemas.py:192 +#: superset/reports/schemas.py:198 superset/reports/schemas.py:280 +#: superset/reports/schemas.py:286 superset/reports/schemas.py:293 +msgid "Value must be greater than 0" +msgstr "Vrednost mora biti večja od 0" + +#: superset/reports/commands/alert.py:96 #, python-format -msgid "Certified by %s" -msgstr "Certificiral/a %s" +msgid "Alert query returned more than one row. %s rows returned" +msgstr "" +"Poizvedba za opozorilo je vrnila več kot eno vrstico. Št. vrnjenih vrstic: %s" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:253 -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:195 -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:267 -msgid "Change dataset" -msgstr "Spremeni podatkovni set" +#: superset/reports/commands/alert.py:105 +#, python-format +msgid "Alert query returned more than one column. %s columns returned" +msgstr "" +"Poizvedba za opozorilo je vrnila več kot en stolpec. Število vrnjenih stolpcev: %s" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:269 -#, fuzzy -msgid "Change order of columns." -msgstr "Vrstni red stolpcev" +#: superset/reports/commands/exceptions.py:45 +msgid "Dashboard does not exist" +msgstr "Nadzorna plošča ne obstaja" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:241 -#, fuzzy -msgid "Change order of rows." -msgstr "Vrstni red vrstic" +#: superset/reports/commands/exceptions.py:54 +msgid "Chart does not exist" +msgstr "Grafikon ne obstaja" -#: superset/connectors/druid/views.py:354 superset/connectors/sqla/views.py:489 -msgid "Changed By" -msgstr "Spremenil" +#: superset/reports/commands/exceptions.py:63 +msgid "Database is required for alerts" +msgstr "Podatkovna baza je obvezna za opozorila" -#: superset/views/schedules.py:238 superset/views/schedules.py:318 -msgid "Changed On" -msgstr "Spremenjeno" +#: superset/reports/commands/exceptions.py:72 +msgid "Type is required" +msgstr "Tip je obvezen" -#: superset/views/sql_lab.py:75 -msgid "Changed on" -msgstr "Spremenjen" +#: superset/reports/commands/exceptions.py:81 +msgid "Choose a chart or dashboard not both" +msgstr "Izberite grafikon ali nadzorno ploščo, ne obojega" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:50 -msgid "" -"Changing the dataset may break the chart if the chart relies on columns " -"or metadata that does not exist in the target dataset" +#: superset/reports/commands/exceptions.py:91 +msgid "Please save your chart first, then try creating a new email report." msgstr "" -"Sprememba podatkovnega seta lahko pokvari grafikon, če se le-ta zanaša na" -" stolpce ali metapodatke, ki ne obstajajo v ciljnem podatkovnem nizu" +"Najprej shranite grafikon, potem pa poskusite ustvariti novo e-poštno poročilo." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1176 -msgid "" -"Changing these settings will affect all charts using this dataset, " -"including charts owned by other people." +#: superset/reports/commands/exceptions.py:103 +msgid "Please save your dashboard first, then try creating a new email report." msgstr "" -"Spreminjanje teh nastavitev bo vplivalo na vse grafikone, ki uporabljajo " -"ta podatkovni set, vključno z grafikoni v lasti drugih oseb." +"Najprej shranite nadzorno ploščo, potem pa poskusite ustvariti novo e-poštno " +"poročilo." -#: superset/dashboards/commands/exceptions.py:78 -msgid "Changing this Dashboard is forbidden" -msgstr "Spreminjanje te nadzorne plošče ni dovoljeno" +#: superset/reports/commands/exceptions.py:111 +msgid "Report Schedule parameters are invalid." +msgstr "Parametri urnika poročanja so neveljavni." -#: superset/charts/commands/exceptions.py:131 -msgid "Changing this chart is forbidden" -msgstr "Spreminjanje tega grafikona ni dovoljeno" +#: superset/reports/commands/exceptions.py:115 +msgid "Report Schedule could not be deleted." +msgstr "Urnika poročanja ni mogoče izbrisati." -#: superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx:75 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:40 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:55 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:68 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:83 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:98 -#: superset-frontend/src/explore/components/ControlHeader.jsx:77 -msgid "Changing this control takes effect instantly" -msgstr "Sprememba tega kontrolnika se odrazi takoj" +#: superset/reports/commands/exceptions.py:119 +msgid "Report Schedule could not be created." +msgstr "Urnika poročanja ni mogoče ustvariti." -#: superset/datasets/commands/exceptions.py:177 -msgid "Changing this dataset is forbidden" -msgstr "Spreminjanje tega podatkovnega seta ni dovoljeno" +#: superset/reports/commands/exceptions.py:123 +msgid "Report Schedule could not be updated." +msgstr "Urnika poročanja ni mogoče posodobiti." -#: superset/datasets/columns/commands/exceptions.py:31 -#: superset/datasets/metrics/commands/exceptions.py:31 -msgid "Changing this dataset is forbidden." -msgstr "Spreminjanje tega podatkovnega seta ni dovoljeno." +#: superset/reports/commands/exceptions.py:127 +msgid "Report Schedule not found." +msgstr "Urnika poročanja ni najden." -#: superset/reports/commands/exceptions.py:238 -msgid "Changing this report is forbidden" -msgstr "Spreminjanje tega poročila ni dovoljeno" +#: superset/reports/commands/exceptions.py:131 +msgid "Report Schedule delete failed." +msgstr "Izbris urnika poročanja ni uspel." -#: superset/views/database/forms.py:216 superset/views/database/forms.py:349 -msgid "Character to interpret as decimal point." -msgstr "Znak, ki bo prepoznan kot decimalno ločilo." +#: superset/reports/commands/exceptions.py:135 +msgid "Report Schedule log prune failed." +msgstr "Krajšanje dnevnika urnika poročanja ni uspelo." -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:81 -msgid "Charge" -msgstr "Naboj" - -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:95 -msgid "Charge in the force layout" -msgstr "Naboj v postavitvi sil" - -#: superset-frontend/src/components/Menu/MenuRight.tsx:39 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:387 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1297 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1300 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:261 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:607 -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:208 -#: superset/templates/appbuilder/navbar_right.html:39 -#: superset/views/chart/mixin.py:85 superset/views/chart/views.py:108 -#: superset/views/schedules.py:316 -msgid "Chart" -msgstr "Grafikon" +#: superset/reports/commands/exceptions.py:139 +msgid "Report Schedule execution failed when generating a screenshot." +msgstr "" +"Izvajanje urnika poročanja je bilo neuspešno pri ustvarjanju zaslonske slike." -#: superset/views/core.py:1748 -#, python-format -msgid "Chart %(id)s not found" -msgstr "Grafikon %(id)s ni najden" +#: superset/reports/commands/exceptions.py:143 +msgid "Report Schedule execution failed when generating a csv." +msgstr "Izvajanje urnika poročanja je bilo neuspešno pri ustvarjanju csv." -#: superset/views/database/mixins.py:195 -msgid "Chart Cache Timeout" -msgstr "Trajanje predpomnilnika grafikona" +#: superset/reports/commands/exceptions.py:147 +msgid "Report Schedule execution failed when generating a dataframe." +msgstr "" +"Izvajanje urnika poročanja je bilo neuspešno pri ustvarjanju podatkovnega okvira." -#: superset/initialization/__init__.py:453 -msgid "Chart Email Schedules" -msgstr "Urniki za e-pošto grafikonov" +#: superset/reports/commands/exceptions.py:151 +msgid "Report Schedule execution got an unexpected error." +msgstr "Pri izvajanju urnika poročanja je prišlo do nepričakovane napake." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:58 -#: superset-frontend/src/explore/controlPanels/sections.tsx:42 -msgid "Chart ID" -msgstr "ID grafikona" +#: superset/reports/commands/exceptions.py:155 +msgid "Report Schedule is still working, refusing to re-compute." +msgstr "Urnik poročanja se še vedno izvaja, ponovni izračun je zavrnjen." -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:77 -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:49 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:54 -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:48 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:75 -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:61 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:140 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:65 -#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:36 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:65 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:49 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:53 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:139 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:88 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:42 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:48 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:77 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:31 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:40 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:79 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:35 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:54 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:39 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:81 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:69 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:75 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:279 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:83 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:103 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:100 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:80 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:97 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:103 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:104 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:61 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:35 -msgid "Chart Options" -msgstr "Možnosti grafikona" +#: superset/reports/commands/exceptions.py:159 +msgid "Report Schedule reached a working timeout." +msgstr "Urnik poročanja je dosegel mejo časa izvedbe." -#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:70 -#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:83 +#: superset/reports/commands/exceptions.py:168 #, python-format -msgid "Chart Owner: %s" -msgstr "Lastnik grafikona: %s" +msgid "A report named \"%(name)s\" already exists" +msgstr "Poročilo poimenovano %(name)s že obstaja" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:27 -msgid "Chart Title" -msgstr "Naslov grafikona" +#: superset/reports/commands/exceptions.py:170 +#, python-format +msgid "An alert named \"%(name)s\" already exists" +msgstr "Opozorilo poimenovano %(name)s že obstaja" -#: superset/views/core.py:979 -msgid "Chart [{}] has been overwritten" -msgstr "Grafikon [{}] je bil prepisan" +#: superset/reports/commands/exceptions.py:176 +msgid "Resource already has an attached report." +msgstr "Vir že ima povezano poročilo." -#: superset/views/core.py:975 -msgid "Chart [{}] has been saved" -msgstr "Grafikon [{}] je bil shranjen" +#: superset/reports/commands/exceptions.py:181 +msgid "Alert query returned more than one row." +msgstr "Poizvedba za opozorilo je vrnila več kot eno vrstico." -#: superset/views/core.py:1006 -msgid "Chart [{}] was added to dashboard [{}]" -msgstr "Grafikon [{}] je bil dodan na nadzorno ploščo [{}]" +#: superset/reports/commands/exceptions.py:186 +msgid "Alert validator config error." +msgstr "Napaka nastavitev potrjevalnika opozoril." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:216 -msgid "Chart cache timeout" -msgstr "Trajanje predpomnilnika grafikona" +#: superset/reports/commands/exceptions.py:190 +msgid "Alert query returned more than one column." +msgstr "Poizvedba za opozorilo je vrnila več kot en stolpec." -#: superset-frontend/src/components/AlteredSliceTag/index.jsx:199 -msgid "Chart changes" -msgstr "Spremembe grafikona" +#: superset/reports/commands/exceptions.py:194 +msgid "Alert query returned a non-number value." +msgstr "Poizvedba za opozorilo je vrnila neštevilsko vrednost." -#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:28 -#, fuzzy -msgid "" -"Chart component that lets you add a custom filter UI in your dashboard. " -"When added to dashboard, a filter box lets users specify specific values " -"or ranges to filter charts by. The charts that each filter box is applied" -" to can be fine tuned as well in the dashboard view.\n" -"\n" -" Note that this plugin is being replaced with the new Filters feature " -"that lives in the dashboard view itself. It's easier to use and has more " -"capabilities!" -msgstr "" -"Komponenta grafikona, ki omogoča dodajanje vmesnika filtrov po meri v " -"nadzorno ploščo. Ko je dodana na nadzorno ploščo, lahko uporabnik določi " -"poljubne vrednosti ali obsege filtrov. Grafikoni, na katere se nanašajo " -"filtri, so lahko precizno izbrani tudi v pogledu nadzorne plošče.\r\n" -"\r\n" -" Vedite, da bo ta vtičnik v prihodnosti zamenjan z novim konceptom " -"filtrov, ki bodo živeli v kontekstu same nadzorne plošče in bodo " -"zmogljivejši ter enostavnejši za uporabo!" +#: superset/reports/commands/exceptions.py:198 +msgid "Alert found an error while executing a query." +msgstr "Opozorilo je našlo napako pri izvajanju poizvedbe." -#: superset/charts/commands/exceptions.py:115 -msgid "Chart could not be created." -msgstr "Grafikona ni mogoče ustvariti." +#: superset/reports/commands/exceptions.py:202 +msgid "A timeout occurred while executing the query." +msgstr "Pri izvajanju poizvedbe je potekel čas." -#: superset/charts/commands/exceptions.py:123 -msgid "Chart could not be deleted." -msgstr "Grafikona ni mogoče izbrisati." +#: superset/reports/commands/exceptions.py:206 +msgid "A timeout occurred while taking a screenshot." +msgstr "Pri ustvarjanju zaslonske slike je potekel čas." -#: superset/charts/commands/exceptions.py:119 -msgid "Chart could not be updated." -msgstr "Grafikona ni mogoče posodobiti." +#: superset/reports/commands/exceptions.py:210 +msgid "A timeout occurred while generating a csv." +msgstr "Pri ustvarjanju csv je potekel čas." -#: superset/reports/commands/exceptions.py:53 -msgid "Chart does not exist" -msgstr "Grafikon ne obstaja" +#: superset/reports/commands/exceptions.py:214 +msgid "A timeout occurred while generating a dataframe." +msgstr "Pri ustvarjanju podatkovnega okvira je potekel čas." -#: superset/charts/data/api.py:125 -msgid "Chart has no query context saved. Please save the chart again." -msgstr "Grafikon nima shranjenega konteksta poizvedbe. Ponovno shranite grafikon." +#: superset/reports/commands/exceptions.py:218 +msgid "Alert fired during grace period." +msgstr "Opozorilo sproženo med obdobjem mirovanja." -#: superset-frontend/src/explore/components/SaveModal.tsx:247 -msgid "Chart name" -msgstr "Ime grafikona" +#: superset/reports/commands/exceptions.py:222 +msgid "Alert ended grace period." +msgstr "Opozorilo je končalo obdobje mirovanja." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:96 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:107 -msgid "Chart options" -msgstr "Možnosti grafikona" +#: superset/reports/commands/exceptions.py:226 +msgid "Alert on grace period" +msgstr "Opozorilo v obdobju mirovanja" -#: superset/charts/commands/exceptions.py:111 -msgid "Chart parameters are invalid." -msgstr "Parametri grafikona so neveljavni." +#: superset/reports/commands/exceptions.py:230 +msgid "Report Schedule sellenium user not found" +msgstr "Selenium uporabnik za urnik poročanja ni najden" -#: superset-frontend/src/explore/controlPanels/sections.tsx:32 -msgid "Chart type" -msgstr "Tip grafikona" +#: superset/reports/commands/exceptions.py:234 +msgid "Report Schedule state not found" +msgstr "Stanje urnika poročanj ni najdeno" -#: superset-frontend/src/dashboard/components/BuilderComponentPane.tsx:112 -#: superset-frontend/src/profile/components/CreatedContent.tsx:76 -#: superset-frontend/src/profile/components/Favorites.tsx:77 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:634 -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:306 -#: superset/initialization/__init__.py:246 superset/views/chart/mixin.py:26 -#: superset/views/dashboard/mixin.py:81 -msgid "Charts" -msgstr "Grafikoni" +#: superset/reports/commands/exceptions.py:238 +msgid "Report schedule unexpected error" +msgstr "Nepričakovana napaka urnika poročanja" -#: superset/charts/commands/exceptions.py:135 -msgid "Charts could not be deleted." -msgstr "Grafikonov ni mogoče izbrisati." - -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:162 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:488 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:505 -msgid "Check configuration" -msgstr "Preveri nastavitve" +#: superset/reports/commands/exceptions.py:242 +msgid "Changing this report is forbidden" +msgstr "Spreminjanje tega poročila ni dovoljeno" -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:206 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:68 -msgid "Check for sorting ascending" -msgstr "Označi za naraščajoče razvrščanje" +#: superset/reports/commands/exceptions.py:246 +msgid "An error occurred while pruning logs " +msgstr "Pri krajšanju dnevnikov je prišlo do napake " -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:113 +#: superset/reports/notifications/email.py:62 +#, python-format msgid "" -"Check if the Rose Chart should use segment area instead of segment radius" -" for proportioning" +"\n" +" Error: %(text)s\n" +" " msgstr "" -"Če želite, da grafikon \"Rose\" uporablja površino segmenta namesto " -"radija za proporcioniranje" +"\n" +" Napaka: %(text)s\n" +" " -#: superset-frontend/src/components/AnchorLink/index.jsx:85 -msgid "Check out this chart in dashboard:" -msgstr "Preizkusite ta grafikon v nadzorni plošči:" +#: superset/reports/notifications/email.py:98 +msgid "Explore in Superset" +msgstr "Razišči v Supersetu" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:319 -msgid "Check out this chart: " -msgstr "Preizkusite ta grafikon: " +#: superset/reports/notifications/email.py:140 +#, python-format +msgid "%(name)s.csv" +msgstr "%(name)s.csv" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:220 -msgid "Check out this dashboard: " -msgstr "Preizkusite to nadzorno ploščo: " +#: superset/reports/notifications/email.py:144 +#, python-format +msgid "%(prefix)s %(title)s" +msgstr "%(prefix)s %(title)s" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:93 +#: superset/reports/notifications/slack.py:57 +#, python-format msgid "" -"Check to apply filters instantly as they change instead of displaying " -"[Apply] button" +"*%(name)s*\n" +"\n" +"%(description)s\n" +"\n" +"<%(url)s|Explore in Superset>\n" +"\n" +"%(table)s\n" msgstr "" -"Izberite za takojšnjo uporabo filtrov, ko se spremenijo, brez " -"prikazovanja gumba Uveljavi" +"*%(name)s*\n" +"\n" +"%(description)s\n" +"\n" +"<%(url)s|Razišči v Supersetu>\n" +"\n" +"%(table)s\n" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:219 -msgid "Check to force date partitions to have the same height" -msgstr "Če želite, da imajo datumske particije enako višino" +#: superset/reports/notifications/slack.py:74 +#, python-format +msgid "" +"*%(name)s*\n" +"\n" +"%(description)s\n" +"\n" +"Error: %(text)s\n" +msgstr "" +"*%(name)s*\n" +"\n" +"%(description)s\n" +"\n" +"napaka: %(text)s\n" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:35 -msgid "Check to include Druid granularity dropdown" -msgstr "Izberite za vključitev spustnega seznama za Druid granulacijo" +#: superset/security/analytics_db_safety.py:44 +#, python-format +msgid "%(dialect)s cannot be used as a data source for security reasons." +msgstr "" +"%(dialect)s ni mogoče uporabiti kot podatkovni vir zaradi varnostnih razlogov." -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:109 -msgid "Check to include SQL time grain dropdown" -msgstr "Izberite za vključitev spustnega seznama za časovno granulacijo SQL" +#: superset/sqllab/command.py:159 +msgid "" +"The database referenced in this query was not found. Please contact an " +"administrator for further assistance or try again." +msgstr "" +"Podatkovna baza, referencirana v tej poizvedbi, ni bila najdena. Kontaktirajte " +"administratorja za napotke ali pa poskusite znova." -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:123 -msgid "Check to include time column dropdown" -msgstr "Izberite za vključitev časovnega stolpca v spustni seznam" +#: superset/sqllab/query_render.py:97 +#, python-format +msgid "The parameter %(parameters)s in your query is undefined." +msgid_plural "The following parameters in your query are undefined: %(parameters)s." +msgstr[0] "V vaši poizvedbi ni definiranih naslednjih parametrov: %(parameters)s." +msgstr[1] "V vaši poizvedbi ni definiranih naslednjih parametrov: %(parameters)s." +msgstr[2] "V vaši poizvedbi ni definiranih naslednjih parametrov: %(parameters)s." +msgstr[3] "V vaši poizvedbi ni definiranih naslednjih parametrov: %(parameters)s." -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:110 -msgid "Check to include time grain dropdown" -msgstr "Izberite za vključitev spustnega seznama za časovno granullacijo" +#: superset/sqllab/query_render.py:118 +msgid "The query contains one or more malformed template parameters." +msgstr "Poizvedba vsebuje enega ali več parametrov predlog z napačno obliko." -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:46 -msgid "Check to include time origin dropdown" -msgstr "Izberi za vključitev spustnega seznama za časovno izhodišče" +#: superset/sqllab/query_render.py:121 +msgid "" +"Please check your query and confirm that all template parameters are surround by " +"double braces, for example, \"{{ ds }}\". Then, try running your query again." +msgstr "" +"V poizvedbi preverite, da so vsi parametri obdani z dvojnimi oklepaji, npr. " +"\"{{ ds }}\". Potem poskusite ponovno." -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:173 -msgid "Child label position" -msgstr "Položaj podrejene oznake" +#: superset/templates/appbuilder/navbar_right.html:35 +msgid "New" +msgstr "Nov" -#: superset/viz.py:2333 -msgid "Choice of [Label] must be present in [Group By]" -msgstr "Izbira [Oznaka] mora biti prisotna v [Združevanje]" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1168 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:288 +#: superset/templates/appbuilder/navbar_right.html:38 +msgid "SQL Query" +msgstr "SQL poizvedba" -#: superset/viz.py:2341 -msgid "Choice of [Point Radius] must be present in [Group By]" -msgstr "Izbran [Point Radius] mora biti prisoten v [Združevanje]" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:419 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1320 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1323 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:289 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:650 +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:211 +#: superset-frontend/src/views/components/MenuRight.tsx:173 +#: superset/templates/appbuilder/navbar_right.html:39 +#: superset/views/chart/mixin.py:85 superset/views/chart/views.py:104 +msgid "Chart" +msgstr "Grafikon" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:150 -#: superset/templates/superset/import_dashboards.html:47 -msgid "Choose File" -msgstr "Izberite datoteko" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1319 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1340 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:603 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:219 +#: superset-frontend/src/views/components/MenuRight.tsx:182 +#: superset/templates/appbuilder/navbar_right.html:40 +#: superset/views/dashboard/mixin.py:78 superset/views/dashboard/views.py:194 +msgid "Dashboard" +msgstr "Nadzorna plošča" -#: superset/reports/commands/exceptions.py:80 -msgid "Choose a chart or dashboard not both" -msgstr "Izberite grafikon ali nadzorno ploščo, ne obojega" +#: superset-frontend/src/views/components/MenuRight.tsx:362 +#: superset/templates/appbuilder/navbar_right.html:109 +msgid "Profile" +msgstr "Profil" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:674 -#, fuzzy -msgid "Choose a database..." -msgstr "Izberite podatkovni set" +#: superset-frontend/src/views/components/MenuRight.tsx:367 +#: superset/templates/appbuilder/navbar_right.html:110 +msgid "Info" +msgstr "Informacije" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:278 -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:288 -msgid "Choose a dataset" -msgstr "Izberite podatkovni set" +#: superset-frontend/src/views/components/MenuRight.tsx:371 +#: superset/templates/appbuilder/navbar_right.html:111 +msgid "Logout" +msgstr "Odjava" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:69 -msgid "Choose a metric for left axis" -msgstr "Izberite mero za levo os" +#: superset-frontend/src/views/components/MenuRight.tsx:434 +#: superset/templates/appbuilder/navbar_right.html:126 +msgid "Login" +msgstr "Prijava" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:120 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:185 -#: superset-frontend/src/explore/controls.jsx:217 -msgid "Choose a metric for right axis" -msgstr "Izberite mero za desno os" +#: superset/templates/appbuilder/general/widgets/base_list.html:55 +msgid "Record Count" +msgstr "Število zapisov" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:57 -msgid "Choose a number format" -msgstr "Izberite obliko zapisa števila" +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:166 +#: superset/templates/appbuilder/general/widgets/base_list.html:64 +msgid "No records found" +msgstr "Ni zapisov" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:63 -msgid "Choose a source" -msgstr "Izberite izvor" +#: superset/templates/appbuilder/general/widgets/search.html:24 +msgid "Filter List" +msgstr "Seznam filtrov" -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:105 -#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:44 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:34 -msgid "Choose a source and a target" -msgstr "Izberite izhodišče in cilj" +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:122 +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:107 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:453 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:304 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:575 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:292 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:524 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:474 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:532 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:463 +#: superset/templates/appbuilder/general/widgets/search.html:40 +msgid "Search" +msgstr "Iskanje" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:69 -msgid "Choose a target" -msgstr "Izberite cilj" +#: superset/templates/appbuilder/general/widgets/search.html:57 +msgid "Refresh" +msgstr "Osveži" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:308 -msgid "Choose chart type" -msgstr "Izberite tip grafikona" +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:617 +#: superset/templates/superset/import_dashboards.html:21 +msgid "Import dashboards" +msgstr "Uvozi nadzorne plošče" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:100 -msgid "Choose one or more charts for left axis" -msgstr "Izberite enega ali več grafikonov za levo os" +#: superset/templates/superset/import_dashboards.html:26 +msgid "Import Dashboard(s)" +msgstr "Uvozi nadzorne plošče" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:135 -msgid "Choose one or more charts for right axis" -msgstr "Izberite enega ali več grafikonov za desno os" +#: superset/templates/superset/import_dashboards.html:37 +msgid "File" +msgstr "Datoteka" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:745 -msgid "Choose the annotation layer type" -msgstr "Izberite tip sloja z oznakami" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:150 +#: superset/templates/superset/import_dashboards.html:47 +msgid "Choose File" +msgstr "Izberite datoteko" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:757 -msgid "Choose the source of your annotations" -msgstr "Izberite vir svojih oznak" +#: superset/templates/superset/import_dashboards.html:63 +msgid "Upload" +msgstr "Naloži" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:34 -msgid "Chord Diagram" -msgstr "Tetivni grafikon" +#: superset/templates/superset/request_access.html:20 +msgid "No Access!" +msgstr "Ni dostopa!" -#: superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx:281 -msgid "Chosen non-numeric column" -msgstr "Izbran ne-numeričen stolpec" +#: superset/templates/superset/request_access.html:25 +#, python-format +msgid "You do not have permissions to access the datasource(s): %(name)s." +msgstr "Nimate dovoljenj za dostop do podatkovnih virov: %(name)s." -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:218 -msgid "Circle" -msgstr "Krog" +#: superset/templates/superset/request_access.html:31 +msgid "Request Permissions" +msgstr "Zahtevaj dovoljenja" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:130 -msgid "Circle -> Arrow" -msgstr "Krog -> Puščica" +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:179 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:220 +#: superset-frontend/src/components/Modal/Modal.tsx:253 +#: superset-frontend/src/components/ReportModal/index.tsx:214 +#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:80 +#: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:72 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:513 +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:153 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:136 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:76 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:62 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:199 +#: superset-frontend/src/explore/components/SaveModal.tsx:192 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:813 +#: superset/templates/superset/request_access.html:34 +msgid "Cancel" +msgstr "Prekliči" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:131 -msgid "Circle -> Circle" -msgstr "Krog -> Krog" +#: superset/templates/superset/fab_overrides/list_with_checkboxes.html:82 +msgid "Use the edit button to change this field" +msgstr "Za spreminjanje tega polja uporabite gumb za urejanje" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:198 -msgid "Circle radar shape" -msgstr "Okrogla oblika radarja" +#: superset/templates/superset/models/database/macros.html:22 +msgid "Test Connection" +msgstr "Preizkusi povezavo" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:37 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:33 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:112 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:40 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:67 -msgid "Circular" -msgstr "Krožno" +#: superset/temporary_cache/commands/exceptions.py:49 +msgid "Resource was not found." +msgstr "Vir ni bil najden." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:32 -msgid "Classic chart that visualizes how metrics change over time." -msgstr "Standardni grafikon za prikaz spreminjanje mere skozi čas." +#: superset/utils/core.py:881 +#, python-format +msgid "[Superset] Access to the datasource %(name)s was granted" +msgstr "[Superset] dostop do podatkovnega vira %(name)s je odobren" -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:37 -msgid "" -"Classic row-by-column spreadsheet like view of a dataset. Use tables to " -"showcase a view into the underlying data or to show aggregated metrics." -msgstr "Standardna razpredelnica za prikaz podatkovnega seta." +#: superset/utils/core.py:1068 +#, python-format +msgid "Unsupported clause type: %(clause)s" +msgstr "Nepodprt tip izraza: %(clause)s" -#: superset/connectors/sqla/views.py:369 -msgid "Clause" -msgstr "Stavek" +#: superset/utils/core.py:1306 +msgid "Invalid metric object" +msgstr "Neveljaven objekt mere" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:53 -msgid "Clear" -msgstr "Počisti" +#: superset/utils/date_parser.py:393 +#, python-format +msgid "Unable to find such a holiday: [%(holiday)s]" +msgstr "Ni mogoče najti takšnega praznika: [%(holiday)s]" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:133 -msgid "Clear all" -msgstr "Počisti vse" +#: superset/utils/pandas_postprocessing/boxplot.py:88 +msgid "" +"percentiles must be a list or tuple with two numeric values, of which the first " +"is lower than the second value" +msgstr "" +"percentili morajo biti tipa list ali tuple z vsaj dvema numeričnima vrednostma, " +"pri čemer je prva manjša od druge" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:997 -msgid "Click the lock to make changes." -msgstr "Kliknite ključavnico, da omogočite spreminjanje." +#: superset/utils/pandas_postprocessing/compare.py:53 +msgid "`compare_columns` must have the same length as `source_columns`." +msgstr "`compare_columns` morajo imeti enako dolžino kot `source_columns`." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1000 -msgid "Click the lock to prevent further changes." -msgstr "Kliknite ključavnico, da onemogočite spreminjanje." +#: superset/utils/pandas_postprocessing/compare.py:57 +msgid "`compare_type` must be `difference`, `percentage` or `ratio`" +msgstr "`compare_type` mora biti `difference`, `percentage` ali `ratio`" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1306 +#: superset/utils/pandas_postprocessing/contribution.py:59 +#, python-format msgid "" -"Click this link to switch to an alternate form that allows you to input " -"the SQLAlchemy URL for this database manually." -msgstr "" -"Kliknite to povezavo za drugo vnosno formo, ki omogoča ročni vnos " -"SQLAlchemy URL-ja za to podatkovno bazo." +"Column \"%(column)s\" is not numeric or does not exists in the query results." +msgstr "Stolpec \"%(column)s\" ni numeričen ali ne obstaja v rezultatu poizvedbe." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1071 -msgid "" -"Click this link to switch to an alternate form that exposes only the " -"required fields needed to connect this database." -msgstr "" -"Kliknite to povezavo za drugo vnosno formo, ki prikaže samo zahtevana " -"polja za povezavo s podatkovno bazo." +#: superset/utils/pandas_postprocessing/contribution.py:69 +msgid "`rename_columns` must have the same length as `columns`." +msgstr "`rename_columns` morajo imeti enako dolžino kot `columns`." -#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:114 -msgid "Click to change visualization type" -msgstr "Kliknite za spremembo tipa vizualizacije" +#: superset/utils/pandas_postprocessing/cum.py:55 +#, python-format +msgid "Invalid cumulative operator: %(operator)s" +msgstr "Neveljaven kumulativni operand: %(operator)s" -#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:151 -msgid "Click to clear emitted filters" -msgstr "S klikom počistite oddane filtre" +#: superset/utils/pandas_postprocessing/geography.py:49 +msgid "Invalid geohash string" +msgstr "Neveljaven niz za geohash" -#: superset-frontend/src/components/EditableTitle/index.tsx:197 -msgid "Click to edit" -msgstr "Kliknite za urejanje" +#: superset/utils/pandas_postprocessing/geography.py:76 +msgid "Invalid longitude/latitude" +msgstr "Neveljavna zemljepisna dolžina/širina" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.jsx:76 -#, fuzzy -msgid "Click to edit label" -msgstr "Kliknite za urejanje" +#: superset/utils/pandas_postprocessing/geography.py:118 +msgid "Invalid geodetic string" +msgstr "Neveljaven geodetski niz" -#: superset-frontend/src/components/FaveStar/index.tsx:81 -msgid "Click to favorite/unfavorite" -msgstr "Kliknite za priljubljeno/nepriljubljeno" +#: superset/utils/pandas_postprocessing/pivot.py:71 +msgid "Pivot operation requires at least one index" +msgstr "Vrtilna operacija zahteva vsaj en indeks" -#: superset-frontend/src/components/CachedLabel/TooltipContent.tsx:39 -msgid "Click to force-refresh" -msgstr "Kliknite za prisilno osvežitev" +#: superset/utils/pandas_postprocessing/pivot.py:75 +msgid "Pivot operation must include at least one aggregate" +msgstr "Vrtilna operacija mora vsebovati vsaj en agregat" -#: superset-frontend/src/components/AlteredSliceTag/index.jsx:177 -msgid "Click to see difference" -msgstr "Kliknite za prikaz razlike" +#: superset/utils/pandas_postprocessing/prophet.py:61 +msgid "`prophet` package not installed" +msgstr "Knjižnica `prophet` ni nameščena" -#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:192 -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:523 -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:307 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:247 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:476 -#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:337 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:805 -msgid "Close" -msgstr "Zapri" +#: superset/utils/pandas_postprocessing/prophet.py:114 +msgid "Time grain missing" +msgstr "Časovna granulacija manjka" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:360 -msgid "Close all other tabs" -msgstr "Zapri vse ostale zavihke" +#: superset/utils/pandas_postprocessing/prophet.py:117 +#, python-format +msgid "Unsupported time grain: %(time_grain)s" +msgstr "Nepodprta časovna granulacija: %(time_grain)s" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:339 -msgid "Close tab" -msgstr "Zapri zavihek" +#: superset/utils/pandas_postprocessing/prophet.py:126 +msgid "Periods must be a whole number" +msgstr "Periode morajo biti celo število" -#: superset/connectors/druid/views.py:344 -msgid "Cluster" -msgstr "Gruča" +#: superset/utils/pandas_postprocessing/prophet.py:129 +msgid "Confidence interval must be between 0 and 1 (exclusive)" +msgstr "Interval zaupanja mora biti med 0 in 1 (odprt)" -#: superset/connectors/druid/views.py:232 -msgid "Cluster Name" -msgstr "Ime gruče" +#: superset/utils/pandas_postprocessing/prophet.py:132 +msgid "DataFrame must include temporal column" +msgstr "DataFrame mora vsebovati časovni stolpec" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:171 -msgid "Cluster label aggregator" -msgstr "Agregator za oznako gruče" +#: superset/utils/pandas_postprocessing/prophet.py:134 +msgid "DataFrame include at least one series" +msgstr "DataFrame vsebuje vsaj eno serijo" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:74 -msgid "Clustering Radius" -msgstr "Radij gručenja" +#: superset/utils/pandas_postprocessing/rename.py:53 +msgid "Label already exists" +msgstr "Oznaka že obstaja" -#: superset-frontend/src/explore/controlPanels/Separator.js:25 -#: superset-frontend/src/explore/controlPanels/Separator.js:46 -msgid "Code" -msgstr "Koda" +#: superset/utils/pandas_postprocessing/resample.py:43 +msgid "Resample operation requires DatetimeIndex" +msgstr "Prevzorčevalna operacija zahteva indeks tipa datumčas" -#: superset-frontend/src/dashboard/components/filterscope/treeIcons.jsx:39 -msgid "Collapse all" -msgstr "Skrči vse" +#: superset/utils/pandas_postprocessing/resample.py:46 +msgid "Resample method should in " +msgstr "Metoda za prevzorčenje v Pandas mora " -#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:152 -#, fuzzy -msgid "Collapse table preview" -msgstr "Odstrani predogled tabele" +#: superset/utils/pandas_postprocessing/rolling.py:67 +msgid "Undefined window for rolling operation" +msgstr "Nedefinirano okno za drsečo operacijo" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:648 -msgid "Color" -msgstr "Barva" +#: superset/utils/pandas_postprocessing/rolling.py:69 +msgid "Window must be > 0" +msgstr "Okno mora biti > 0" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:137 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:439 -msgid "Color +/-" -msgstr "Barva +/-" +#: superset/utils/pandas_postprocessing/rolling.py:84 +#, python-format +msgid "Invalid rolling_type: %(type)s" +msgstr "Neveljaven rolling_type: %(type)s" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:159 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:206 -msgid "Color Metric" -msgstr "Mera za barvo" +#: superset/utils/pandas_postprocessing/rolling.py:90 +#, python-format +msgid "Invalid options for %(rolling_type)s: %(options)s" +msgstr "Neveljavne možnosti za %(rolling_type)s: %(options)s" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:108 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:474 -msgid "Color Scheme" -msgstr "Barvna shema" +#: superset/utils/pandas_postprocessing/utils.py:141 +msgid "Referenced columns not available in DataFrame." +msgstr "Referencirani stolpci niso razpoložljivi v Dataframe-u." -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:129 -msgid "Color Steps" -msgstr "Barvni koraki" +#: superset/utils/pandas_postprocessing/utils.py:167 +#, python-format +msgid "Column referenced by aggregate is undefined: %(column)s" +msgstr "Stolpec referenciran z agregacijo ni definiran: %(column)s" -#: superset-frontend/src/explore/controls.jsx:235 -msgid "Color metric" -msgstr "P" +#: superset/utils/pandas_postprocessing/utils.py:174 +#, python-format +msgid "Operator undefined for aggregator: %(name)s" +msgstr "Operand ni definiran za agregatorja: %(name)s" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:50 -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:214 -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:218 -#: superset-frontend/src/explore/controlPanels/sections.tsx:79 -#: superset-frontend/src/explore/controls.jsx:480 -msgid "Color scheme" -msgstr "Barvna shema" +#: superset/utils/pandas_postprocessing/utils.py:186 +#, python-format +msgid "Invalid numpy function: %(operator)s" +msgstr "Neveljavna numpy funkcija: %(operator)s" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:172 -msgid "" -"Color will be rendered based on a ratio of the cell against the sum of " -"across this criteria" -msgstr "" -"Barva bo prikazana na osnovi razmerja med celico in vsoto glede na ta " -"kriterij" +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:275 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:365 +#: superset-frontend/src/views/components/MenuRight.tsx:359 +#: superset/views/access_requests.py:41 superset/views/log/__init__.py:30 +#: superset/views/sql_lab.py:74 +msgid "User" +msgstr "Uporabnik" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:374 -msgid "Colors" -msgstr "Barve" +#: superset/views/access_requests.py:42 +msgid "User Roles" +msgstr "Vloge uporabnikov" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:283 -#: superset-frontend/src/dashboard/components/gridComponents/new/NewColumn.jsx:31 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:109 -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:204 -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:227 -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:137 -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:140 -#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:194 -#: superset/connectors/druid/views.py:91 superset/connectors/sqla/views.py:143 -msgid "Column" -msgstr "Stolpec" +#: superset/views/access_requests.py:43 +msgid "Database URL" +msgstr "URL podatkovne baze" -#: superset/utils/pandas_postprocessing.py:712 -#, python-format -msgid "" -"Column \"%(column)s\" is not numeric or does not exists in the query " -"results." -msgstr "Stolpec \"%(column)s\" ni numeričen ali ne obstaja v rezultatu poizvedbe." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:177 +#: superset/views/access_requests.py:44 superset/views/chart/mixin.py:80 +msgid "Datasource" +msgstr "Podatkovni vir" -#: superset/views/database/forms.py:224 superset/views/database/forms.py:357 -#: superset/views/database/forms.py:445 -msgid "Column Label(s)" -msgstr "Naslovi stolpcev" +#: superset/views/access_requests.py:45 +msgid "Roles to grant" +msgstr "Vloge za dovoljevanje" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:79 -msgid "" -"Column containing ISO 3166-2 codes of region/province/department in your " -"table." -msgstr "" -"Stolpec, ki vsebuje ISO 3166-2 oznake regij/provinc/departmajev v vaši " -"tabeli." +#: superset/views/access_requests.py:46 +msgid "Created On" +msgstr "Ustvarjeno" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:64 -msgid "Column containing latitude data" -msgstr "Stolpec s podatki zemljepisne širine" +#: superset/views/annotations.py:39 +msgid "annotation start time or end time is required." +msgstr "začetni in končni čas oznake je obvezen." -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:54 -msgid "Column containing longitude data" -msgstr "Stolpec s podatki zemljepisne dolžine" +#: superset/views/annotations.py:46 +msgid "Annotation end time must be no earlier than start time." +msgstr "Končni čas oznake ne sem biti pred začetnim." -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:115 -msgid "Column is required" -msgstr "Zahtevan je stolpec" +#: superset/views/annotations.py:57 +msgid "Annotations" +msgstr "Oznake" -#: superset/views/database/forms.py:225 superset/views/database/forms.py:358 -#: superset/views/database/forms.py:446 -msgid "" -"Column label for index column(s). If None is given and Dataframe Index is" -" True, Index Names are used." -msgstr "" -"Naslovi stolpcev za indeksne stolpce. Če le-ti niso podani in indeksi " -"Dataframe-a obstajajo, se uporabijo imena indeksov." +#: superset/views/annotations.py:58 +msgid "Show Annotation" +msgstr "Prikaži oznako" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:652 -#, python-format -msgid "Column name [%s] is duplicated" -msgstr "Ime stolpca [%s] je podvojeno" +#: superset/views/annotations.py:59 +msgid "Add Annotation" +msgstr "Dodaj oznako" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:139 -msgid "Column name(s) " -msgstr "Imena stolpcev " +#: superset/views/annotations.py:60 +msgid "Edit Annotation" +msgstr "Uredi oznako" -#: superset/utils/pandas_postprocessing.py:168 -#, python-format -msgid "Column referenced by aggregate is undefined: %(column)s" -msgstr "Stolpec referenciran z agregacijo ni definiran: %(column)s" +#: superset/views/annotations.py:75 +msgid "Layer" +msgstr "Sloj" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:130 -msgid "Column select" -msgstr "Izbira stolpca" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:82 +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:111 +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:169 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:244 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:248 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1197 +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:157 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:157 +#: superset/views/annotations.py:76 superset/views/sql_lab.py:73 +msgid "Label" +msgstr "Naziv" -#: superset/views/database/forms.py:163 superset/views/database/forms.py:316 -msgid "" -"Column to use as the row labels of the dataframe. Leave empty if no index" -" column." -msgstr "" -"Stolpec, ki se uporabi za naslove vrstic v dataframe-u. Pustite prazno, " -"če ni indeksnega stolpca." +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:169 +#: superset/views/annotations.py:78 +msgid "Start" +msgstr "Začetek" -#: superset/views/database/forms.py:385 -msgid "Columnar File" -msgstr "Stoplčna datoteka" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:178 +#: superset/views/annotations.py:79 +msgid "End" +msgstr "Konec" -#: superset/views/database/views.py:550 -#, python-format -msgid "" -"Columnar file \"%(columnar_filename)s\" uploaded to table " -"\"%(table_name)s\" in database \"%(db_name)s\"" -msgstr "" -"Stolpčna datoteka \"%(columnar_filename)s\" naložena v tabelo " -"\"%(table_name)s\" v podatkovni bazi \"%(db_name)s\"" +#: superset/views/annotations.py:80 superset/views/dashboard/mixin.py:89 +msgid "JSON Metadata" +msgstr "JSON metapodatki" -#: superset/views/database/views.py:414 -msgid "Columnar to Database configuration" -msgstr "Nastavitve pretvorbe Stolpci v Podatkovno bazo" +#: superset/views/annotations.py:114 +msgid "Show Annotation Layer" +msgstr "Prikaži sloj z oznakami" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:55 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:214 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:36 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:59 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:82 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:101 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:124 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1207 -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:334 -#: superset-frontend/src/explore/controls.jsx:245 -#: superset/connectors/druid/views.py:70 superset/connectors/sqla/views.py:63 -msgid "Columns" -msgstr "Stolpci" +#: superset/views/annotations.py:115 +msgid "Add Annotation Layer" +msgstr "Dodaj sloj z oznakami" -#: superset/common/query_context_processor.py:114 superset/viz.py:554 -#, python-format -msgid "Columns missing in datasource: %(invalid_columns)s" -msgstr "V podatkovnem viru manjkajo stolpci: %(invalid_columns)s" +#: superset/views/annotations.py:116 +msgid "Edit Annotation Layer" +msgstr "Uredi sloj z oznakami" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:302 -#, fuzzy -msgid "Columns subtotal position" -msgstr "Položaj vsot stolpcev" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:72 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:129 +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:212 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:242 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:244 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:759 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:232 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:130 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:131 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:311 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:275 +#: superset/views/annotations.py:122 superset/views/chart/mixin.py:86 +msgid "Name" +msgstr "Ime" -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:134 +#: superset/views/base.py:257 msgid "" -"Columns to calculate distribution across. Defaults to temporal column if " -"left empty." +"Table [%{table}s] could not be found, please double check your database " +"connection, schema, and table name, error: {}" msgstr "" -"Stolpci za izračun porazdelitve. Privzeto je izbran časovni stolpec (če " -"je prazno)." +"Tabela [%{table}s] ni najdena. Preverite povezavo, shemo in ime tabele v " +"podatkovni bazi. Napaka: {}" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:44 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:45 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:54 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:102 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:125 -msgid "Columns to display" -msgstr "Stolpci za prikaz" +#: superset/views/base.py:533 +msgid "json isn't valid" +msgstr "json ni veljaven" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:43 -msgid "Columns to group by" -msgstr "Stolpci za združevanje" +#: superset/views/base.py:544 +msgid "Export to YAML" +msgstr "Izvozi v YAML" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:60 -msgid "Columns to group by on the columns" -msgstr "Stolpci za združevanje stolpcev" +#: superset/views/base.py:544 +msgid "Export to YAML?" +msgstr "Izvozim v YAML?" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:50 -msgid "Columns to group by on the rows" -msgstr "Stolpci za združevanje vrstic" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:90 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:343 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:531 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:307 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:366 +#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:104 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:397 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:696 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:336 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:132 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:370 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:643 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:394 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:675 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:510 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:239 +#: superset/views/base.py:601 +msgid "Delete" +msgstr "Izbriši" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:96 -msgid "Combine Metrics" -msgstr "Združuj mere" +#: superset/views/base.py:601 +msgid "Delete all Really?" +msgstr "Ali resnično vse izbrišem?" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:185 -msgid "Combine metrics" -msgstr "Združuj mere" +#: superset/views/base_api.py:135 +msgid "Is favorite" +msgstr "Je priljubljen" + +#: superset/views/core.py:189 +msgid "The data source seems to have been deleted" +msgstr "Zdi se, da je bil podatkovni vir izbrisan" + +#: superset/views/core.py:190 +msgid "The user seems to have been deleted" +msgstr "Zdi se, da je bil uporabnik izbrisan" + +#: superset/views/core.py:307 +msgid "Access was requested" +msgstr "Zahtevan je bil dostop" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:301 +#: superset/views/core.py:363 +msgid "The access requests seem to have been deleted" +msgstr "Zdi se, da je bila zahteva za dostop izbrisana" + +#: superset/views/core.py:375 +#, python-format msgid "" -"Comma-separated color picks for the intervals, e.g. 1,2,4. Integers " -"denote colors from the chosen color scheme and are 1-indexed. Length must" -" be matching that of interval bounds." +"%(user)s was granted the role %(role)s that gives access to the %(datasource)s" msgstr "" -"Z vejico ločene barve za intervale, npr. 1,2,4. Cela števila " -"predstavljajo barve iz barvne sheme (začnejo se z 1). Dolžina mora " -"ustrezati mejam intervala." +"Uporabniku %(user)s je bila dodeljena vloga %(role)s, ki omogoča dostop do " +"%(datasource)s" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:287 -msgid "" -"Comma-separated interval bounds, e.g. 2,4,5 for intervals 0-2, 2-4 and " -"4-5. Last number should match the value provided for MAX." +#: superset/views/core.py:398 +#, python-format +msgid "Role %(r)s was extended to provide the access to the datasource %(ds)s" msgstr "" -"Z vejico ločeni intervali, npr. 2,4,5 za intervale 0-2, 2-4 in 4-5. " -"Zadnja številka naj bo enaka vrednosti za MAX." +"Vloga %(r)s je bila razširjena za zagotovitev dostopa do podatkovnega vira %(ds)s" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:312 -msgid "Comparator option" -msgstr "Možnosti komparatorja" +#: superset/views/core.py:415 +msgid "You have no permission to approve this request" +msgstr "Nimate dovoljenja za odobritev te zahteve" -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:26 -msgid "" -"Compare multiple time series charts (as sparklines) and related metrics " -"quickly." -msgstr "" -"Hitra primerjava več grafikonov časovnih vrst (sparkline način) in " -"povezanih mer." +#: superset/views/core.py:633 superset/views/core.py:857 superset/views/core.py:863 +#: superset/views/core.py:1037 superset/views/core.py:1055 +msgid "You don't have the rights to " +msgstr "Nimate pravic za " -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:26 -msgid "Compare the same summarized metric across multiple groups." -msgstr "Primerja isto mero med različnimi skupinami." +#: superset/views/core.py:633 +msgid "download as csv" +msgstr "prenos kot csv" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:28 +#: superset/views/core.py:713 +#, python-format msgid "" -"Compares how a metric changes over time between different groups. Each " -"group is mapped to a row and change over time is visualized bar lengths " -"and color." +"Cannot import dashboard: %(db_error)s.\n" +"Make sure to create the database before importing the dashboard." msgstr "" -"Primerja kako se mera spreminja s časom med različnimi skupinami. Vsaka " -"skupina predstavlja eno vrstico, časovne spremembe pa so prikazane z " -"dolžino stolpcev in barvami." +"Nadzorne plošče ni mogoče uvoziti: %(db_error)s.\n" +"Pred uvozom poskrbite za ustvarjenje podatkovne baze." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:30 -msgid "" -"Compares metrics from different categories using bars. Bar lengths are " -"used to indicate the magnitude of each value and color is used to " -"differentiate groups." +#: superset/views/core.py:724 +msgid "An unknown error occurred. Please contact your Superset administrator" msgstr "" -"Primerjava mer različnih kategorij s pomočjo stolpcev. Dolžina stolpca " -"prestavlja višino vrednosti, z barvami pa so ločene skupine." +"Zgodila se je neznana napaka. Kontaktirajte svojega administratorja za Superset" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:26 -msgid "" -"Compares the lengths of time different activities take in a shared " -"timeline view." -msgstr "Primerja dolžine časovno različnih aktivnosti na skupni časovnici." +#: superset/views/core.py:766 +msgid "Error: permalink state not found" +msgstr "Napaka: stanje povezave ni najdeno" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:33 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:33 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:37 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:34 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:36 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:42 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:35 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:46 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:41 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:68 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:56 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:60 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:43 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:31 -msgid "Comparison" -msgstr "Primerjava" +#: superset/views/core.py:769 superset/views/core.py:1980 +#, python-format +msgid "Error: %(msg)s" +msgstr "Napaka: %(msg)s" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:48 -msgid "Comparison Period Lag" -msgstr "Zaostanek obdobja za primerjavo" +#: superset/views/core.py:783 +msgid "Form data not found in cache, reverting to chart metadata." +msgstr "" +"Podatkov ni mogoče najti v predpomnilniku. Uporabljeni bodo metapodatki grafikona." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:61 -msgid "Comparison suffix" -msgstr "Pripona za primerjavo" +#: superset/views/core.py:789 +msgid "Form data not found in cache, reverting to dataset metadata." +msgstr "" +"Podatkov ni mogoče najti v predpomnilniku. Uporabljeni bodo metapodatki " +"podatkovnega seta." -#: superset-frontend/src/dashboard/components/BuilderComponentPane.tsx:102 -msgid "Components" -msgstr "Komponente" +#: superset/views/core.py:817 +msgid "[Missing Dataset]" +msgstr "[Manjka podatkovni set]" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:53 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:56 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:59 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:57 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:72 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:367 -#: superset-frontend/src/explore/controlPanels/sections.tsx:136 -msgid "Compute the contribution to the total" -msgstr "Izračunaj prispevek k celoti" +#: superset/views/core.py:857 superset/views/core.py:1038 +msgid "alter this " +msgstr "spreminjanje tega " -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1173 -msgid "Condition" -msgstr "Pogoj" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:167 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:742 +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:84 +#: superset/views/core.py:857 superset/views/core.py:863 +msgid "chart" +msgstr "grafikona" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:320 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:473 -msgid "Conditional formatting" -msgstr "Pogojno oblikovanje" +#: superset/views/core.py:863 superset/views/core.py:1056 +msgid "create a " +msgstr "ustvarite " -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:70 -msgid "Confidence interval" -msgstr "Interval zaupanja" +#: superset/views/core.py:919 +#, python-format +msgid "Explore - %(table)s" +msgstr "Razišči - %(table)s" -#: superset/utils/pandas_postprocessing.py:827 -msgid "Confidence interval must be between 0 and 1 (exclusive)" -msgstr "Interval zaupanja mora biti med 0 in 1 (odprt)" +#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx:90 +#: superset/views/core.py:921 +msgid "Explore" +msgstr "Raziskovanje" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:252 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:276 -msgid "Configuration" -msgstr "Nastavitve" +#: superset/views/core.py:1013 +msgid "Chart [{}] has been saved" +msgstr "Grafikon [{}] je bil shranjen" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:58 -msgid "Configure Advanced Time Range " -msgstr "Nastavi napredno časovno obdobje " +#: superset/views/core.py:1017 +msgid "Chart [{}] has been overwritten" +msgstr "Grafikon [{}] je bil prepisan" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx:41 -msgid "Configure Time Range: Last..." -msgstr "Nastavi časovno obdobje: Zadnji ..." +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:118 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:699 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:80 +#: superset/views/core.py:1039 superset/views/core.py:1057 +msgid "dashboard" +msgstr "nadzorna plošča" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CalendarFrame.tsx:46 -msgid "Configure Time Range: Previous..." -msgstr "Nastavi časovno obdobje: Prejšnji ..." +#: superset/views/core.py:1044 +msgid "Chart [{}] was added to dashboard [{}]" +msgstr "Grafikon [{}] je bil dodan na nadzorno ploščo [{}]" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:111 -msgid "Configure custom time range" -msgstr "Nastavi prilagojeno časovno obdobje" +#: superset/views/core.py:1066 +msgid "Dashboard [{}] just got created and chart [{}] was added to it" +msgstr "Nadzorna plošča [{}] je bila ravno ustvarjena in grafikon [{}] dodan nanjo" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:500 -msgid "Configure filter scopes" -msgstr "Nastavi doseg filtrov" +#: superset/views/core.py:1292 +msgid "" +"This dashboard was changed recently. Please reload dashboard to get latest " +"version." +msgstr "" +"Nadzorna plošča je bila pred kratkim spremenjena. Ponovno jo naložite, da dobite " +"zadnjo verzijo." -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:718 -msgid "Configure the basics of your Annotation Layer." -msgstr "Osnovne nastavitve sloja z oznakami." +#: superset/views/core.py:1386 +#, python-format +msgid "Could not load database driver: %(driver_name)s" +msgstr "Gonilnika podatkovne baze ni mogoče naložiti: %(driver_name)s" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:616 -msgid "Configure your how you overlay is displayed here." -msgstr "Nastavite kako se tukaj prikazuje vrhnja plast." +#: superset/views/core.py:1395 +msgid "" +"Invalid connection string, a valid string usually follows:\n" +"'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'" +msgstr "" +"Neveljaven niz povezave, veljaven niz običajno sledi:\n" +"'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'" -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:179 -msgid "Confirm save" -msgstr "Potrdite shranjevanje" +#: superset/views/core.py:1788 +msgid "Malformed request. slice_id or table_name and db_name arguments are expected" +msgstr "" +"Deformirana zahteva. Pričakovani so argumenti slice_id ali table_name in db_name" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:777 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1006 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1193 -msgid "Connect" -msgstr "Poveži" +#: superset/views/core.py:1798 +#, python-format +msgid "Chart %(id)s not found" +msgstr "Grafikon %(id)s ni najden" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:41 -msgid "Connect Google Sheets as tables to this database" -msgstr "Googlove preglednice poveži s to podatkovno bazo kot tabele" +#: superset/views/core.py:1811 +#, python-format +msgid "Table %(table)s wasn't found in the database %(db)s" +msgstr "Tabela %(table)s ni bila najdena v podatkovni bazi %(db)s" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1011 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1197 -msgid "Connect a database" -msgstr "Poveži se s podatkovno bazo" +#: superset/views/core.py:1983 +msgid "permalink state not found" +msgstr "stanje povezave ni najdeno" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1068 -msgid "Connect this database using the dynamic form instead" +#: superset/views/core.py:2053 +msgid "" +"One or more required fields are missing in the request. Please try again, and if " +"the problem persists conctact your administrator." msgstr "" +"Eno ali več zahtevanih polj manjka v zahtevi. Poskusite znova, če težava ostane, " +"kontaktirajte administratorja." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1301 -msgid "Connect this database with a SQLAlchemy URI string instead" +#: superset/views/core.py:2063 +msgid "The database was not found." +msgstr "Podatkovna baza ni bila najdena." + +#: superset/views/core.py:2193 +msgid "" +"Data could not be retrieved from the results backend. You need to re-run the " +"original query." msgstr "" +"Podatkov ni bilo mogoče pridobiti iz zalednega sistema rezultatov. Ponovno morate " +"zagnati izvorno poizvedbo." -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:224 -msgid "Connection" -msgstr "Povezava" +#: superset/views/core.py:2207 +msgid "" +"The query associated with these results could not be found. You need to re-run the " +"original query." +msgstr "" +"Poizvedbe, povezane s temi rezultati, ni bilo mogoče najti. Ponovno morate " +"zagnati izvorno poizvedbo." -#: superset/databases/commands/exceptions.py:105 -#: superset/databases/commands/exceptions.py:122 superset/views/core.py:1383 -msgid "Connection failed, please check your connection settings" -msgstr "Povezava neuspešna. Preverite nastavitve povezave" +#: superset/views/core.py:2222 +msgid "" +"You are not authorized to see this query. If you think this is an error, please " +"reach out to your administrator." +msgstr "" +"Nimate dovoljenja za ogled te poizvedbe. Če menite, da je to napaka, " +"kontaktirajte administratorja." -#: superset-frontend/src/views/CRUD/hooks.ts:625 -msgid "Connection looks good!" -msgstr "Povezava izgleda v redu!" +#: superset/views/core.py:2240 +msgid "" +"Data could not be deserialized from the results backend. The storage format might " +"have changed, rendering the old data stake. You need to re-run the original query." +msgstr "" +"Podatkov ni bilo mogoče deserializirati iz zalednega sistema rezultatov. Lahko je " +"prišlo do spremembe oblike zapisa. Ponovno zaženite izvorno poizvedbo." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:46 -msgid "Continuous" -msgstr "Zvezno" +#: superset/views/core.py:2257 +msgid "The provided `rows` argument is not a valid integer." +msgstr "Podani argument `rows` ni veljavno celo število." -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:51 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:54 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:57 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:55 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:70 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:365 -#: superset-frontend/src/explore/controlPanels/sections.tsx:134 -msgid "Contribution" -msgstr "Prispevek" +#: superset/views/core.py:2706 +#, python-format +msgid "%(user)s's profile" +msgstr "Profil uporabnika: %(user)s" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:69 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:69 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:70 -msgid "Contribution Mode" -msgstr "Način deležev" +#: superset/views/css_templates.py:36 +msgid "Show CSS Template" +msgstr "Prikaži CSS predlogo" -#: superset-frontend/src/explore/components/ExploreViewContainer.jsx:430 -msgid "Control labeled " -msgstr "Nastavitev " +#: superset/views/css_templates.py:37 +msgid "Add CSS Template" +msgstr "Dodaj CSS predlogo" -#: superset-frontend/src/explore/components/ExploreViewContainer.jsx:430 -msgid "Controls labeled " -msgstr "Kontrolniki imenovani " +#: superset/views/css_templates.py:38 +msgid "Edit CSS Template" +msgstr "Uredi CSS predlogo" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:57 -msgid "Coordinates" -msgstr "Koordinate" +#: superset/views/css_templates.py:43 +msgid "Template Name" +msgstr "Ime predloge" -#: superset-frontend/src/components/CopyToClipboard/index.jsx:75 -#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:53 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:113 -msgid "Copied to clipboard!" -msgstr "Kopirano na odložišče!" +#: superset/views/dynamic_plugins.py:47 +msgid "A human-friendly name" +msgstr "Človeku prijazno ime" -#: superset-frontend/src/explore/components/DataTableControl/index.tsx:48 -msgid "Copy" -msgstr "Kopiraj" +#: superset/views/dynamic_plugins.py:48 +msgid "" +"Used internally to identify the plugin. Should be set to the package name from " +"the pluginʼs package.json" +msgstr "" +"Uporablja se za interno identifikacijo vtičnika. Naj bo nastavljeno na ime paketa " +"v vtičnikovem package.json" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:192 -msgid "Copy SELECT statement to the clipboard" -msgstr "Kopiraj stavek SELECT na odložišče" +#: superset/views/dynamic_plugins.py:52 +msgid "" +"A full URL pointing to the location of the built plugin (could be hosted on a CDN " +"for example)" +msgstr "" +"Celoten URL, ki kaže na lokacijo zgrajenega vtičnika (lahko gostuje npr. na CDN)" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:106 -msgid "Copy and Paste JSON credentials" -msgstr "Kopiraj in prilepi JSON prijavne podatke" +#: superset/views/dynamic_plugins.py:58 +msgid "Custom Plugins" +msgstr "Prilagojeni vtičniki" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:124 -msgid "Copy and paste the entire service account .json file here" -msgstr "Tukaj kopirajte in prilepite celotno json datoteko servisnega računa" +#: superset/views/dynamic_plugins.py:59 +msgid "Custom Plugin" +msgstr "Prilagojeni vtičnik" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:316 -msgid "Copy chart URL" -msgstr "Kopiraj URL grafikona" +#: superset/views/dynamic_plugins.py:60 +msgid "Add a Plugin" +msgstr "Dodaj vtičnik" -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:103 -msgid "Copy chart URL to clipboard" -msgstr "Kopiraj URL grafikona na odložišče" +#: superset/views/dynamic_plugins.py:61 +msgid "Edit Plugin" +msgstr "Uredi vtičnik" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:263 -msgid "Copy dashboard URL" -msgstr "Kopiraj URL nadzorne plošče" - -#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:98 -msgid "Copy link" -msgstr "Kopiraj povezavo" - -#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:184 -msgid "Copy message" -msgstr "Kopiraj sporočilo" - -#: superset-frontend/src/SqlLab/actions/sqlLab.js:548 -#: superset-frontend/src/SqlLab/reducers/sqlLab.js:74 -#, python-format -msgid "Copy of %s" -msgstr "Kopija %s" - -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:103 -msgid "Copy partition query to clipboard" -msgstr "Kopiraj particijsko poizvedbo na odložišče" - -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:390 -msgid "Copy query URL" -msgstr "Kopiraj URL poizvedbe" +#: superset/views/sql_lab.py:44 +msgid "List Saved Query" +msgstr "Seznam shranjenih poizvedb" -#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:88 -msgid "Copy query link to your clipboard" -msgstr "Kopiraj povezavo do poizvedbe v odložišče" +#: superset/views/sql_lab.py:45 +msgid "Show Saved Query" +msgstr "Prikaži shranjeno poizvedbo" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx:26 -msgid "Copy the account name of that database you are trying to connect to." -msgstr "Kopirajte ime računa podatkovne baze, s katero se skušate povezati." +#: superset/views/sql_lab.py:46 +msgid "Add Saved Query" +msgstr "Dodaj shranjeno poizvedbo" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:91 -msgid "Copy the name of the database you are trying to connect to." -msgstr "Kopirajte ime podatkovne baze, s katero se skušate povezati." +#: superset/views/sql_lab.py:47 +msgid "Edit Saved Query" +msgstr "Uredi shranjeno poizvedbo" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:552 -msgid "Copy to Clipboard" -msgstr "Kopiraj na odložišče" +#: superset/views/sql_lab.py:78 +msgid "End Time" +msgstr "Končni čas" -#: superset-frontend/src/components/CopyToClipboard/index.jsx:43 -#: superset-frontend/src/components/URLShortLinkButton/index.jsx:65 -#: superset-frontend/src/explore/components/EmbedCodeButton.jsx:106 -msgid "Copy to clipboard" -msgstr "Kopiraj na odložišče" +#: superset/views/sql_lab.py:79 +msgid "Pop Tab Link" +msgstr "Prikaži povezavo zavihka" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:25 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:28 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:25 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:25 -msgid "Correlation" -msgstr "Korelacija" +#: superset/views/sql_lab.py:80 +msgid "Changed on" +msgstr "Spremenjen" -#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:95 -msgid "Cost estimate" -msgstr "Ocena potratnosti" +#: superset-frontend/src/components/Chart/Chart.jsx:80 superset/views/utils.py:271 +msgid "The dataset associated with this chart no longer exists" +msgstr "Podatkovni set, povezan s tem grafikonom, ne obstaja več" -#: superset/views/utils.py:547 +#: superset/views/utils.py:500 msgid "Could not determine datasource type" msgstr "Ni mogoče določiti tipa podatkovnega vira" -#: superset-frontend/src/dashboard/actions/sliceEntities.js:116 -#: superset-frontend/src/dashboard/reducers/sliceEntities.js:65 -msgid "Could not fetch all saved charts" -msgstr "Vseh shranjenih grafikonov ni bilo mogoče pridobiti" - -#: superset/views/utils.py:563 +#: superset/views/utils.py:516 msgid "Could not find viz object" msgstr "Ni mogoče najti vizualizacijskega objekta" -#: superset/databases/commands/exceptions.py:130 -msgid "Could not load database driver" -msgstr "Ni mogoče naložiti gonilnika podatkovne baze" +#: superset/views/chart/mixin.py:27 +msgid "Show Chart" +msgstr "Prikaži grafikon" -#: superset/views/core.py:1366 -#, python-format -msgid "Could not load database driver: %(driver_name)s" -msgstr "Gonilnika podatkovne baze ni mogoče naložiti: %(driver_name)s" +#: superset/views/chart/mixin.py:28 +msgid "Add Chart" +msgstr "Dodaj grafikon" -#: superset/databases/commands/test_connection.py:99 -msgid "Could not load database driver: {}" -msgstr "Ni mogoče naložiti gonilnika podatkovne baze: {}" +#: superset/views/chart/mixin.py:29 +msgid "Edit Chart" +msgstr "Uredi grafikon" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:97 -msgid "Could not verify the host" +#: superset/views/chart/mixin.py:64 +msgid "" +"These parameters are generated dynamically when clicking the save or overwrite " +"button in the explore view. This JSON object is exposed here for reference and " +"for power users who may want to alter specific parameters." msgstr "" +"Ti parametri se ustvarijo dinamično s klikom gumba Shrani ali Prepiši v " +"raziskovalnem pogledu. Ta JSON objekt je prikazan kot vzorec za napredne " +"uporabnike, ki želijo spreminjati posamezne parametre." -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:40 -msgid "Country" -msgstr "Država" +#: superset/views/chart/mixin.py:70 +msgid "" +"Duration (in seconds) of the caching timeout for this chart. Note this defaults " +"to the datasource/table timeout if undefined." +msgstr "" +"Časovna veljavnost (v sekundah) predpomnjenja za ta grafikon. Če ni definirana, " +"je uporabljena vrednost za podatkovni vir/tabelo." -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:130 -msgid "Country Color Scheme" -msgstr "Barvna shema držav" +#: superset/views/chart/mixin.py:82 +msgid "Last Modified" +msgstr "Zadnja sprememba" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:115 -msgid "Country Column" -msgstr "Stolpec z državami" +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:56 +#: superset/views/chart/mixin.py:84 +msgid "Parameters" +msgstr "Parametri" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:39 -msgid "Country Field Type" -msgstr "Tip polja za države" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:189 +#: superset/views/chart/mixin.py:88 +msgid "Visualization Type" +msgstr "Tip vizualizacije" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:30 -#: superset/viz.py:2007 -msgid "Country Map" -msgstr "Zemljevid držav" +#: superset/views/dashboard/mixin.py:26 +msgid "Show Dashboard" +msgstr "Prikaži nadzorno ploščo" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:96 -msgid "Create" -msgstr "Ustvari" +#: superset/views/dashboard/mixin.py:27 +msgid "Add Dashboard" +msgstr "Dodaj nadzorno ploščo" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:275 -msgid "Create a new chart" -msgstr "Ustvari nov grafikon" +#: superset/views/dashboard/mixin.py:28 +msgid "Edit Dashboard" +msgstr "Uredi nadzorno ploščo" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:330 -msgid "Create new chart" -msgstr "Ustvari nov grafikon" +#: superset/views/dashboard/mixin.py:47 +msgid "" +"This json object describes the positioning of the widgets in the dashboard. It is " +"dynamically generated when adjusting the widgets size and positions by using drag " +"& drop in the dashboard view" +msgstr "" +"Ta JSON objekt opisuje postavitev pripomočkov na nadzorni plošči. Ustvari se " +"dinamično, ko prilagajamo velikost in postavitev pripomočkov z uporabo " +"povleci&spusti v pogledu nadzorne plošče" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:111 -msgid "Create new filter set" -msgstr "Ustvarite nov set filtrov" +#: superset/views/dashboard/mixin.py:53 +msgid "" +"The CSS for individual dashboards can be altered here, or in the dashboard view " +"where changes are immediately visible" +msgstr "" +"CSS za posamezne nadzorne plošče lahko spreminjamo tukaj ali pa v pogledu " +"nadzorne plošče, kjer so spremembe vidne takoj" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:124 -msgid "Create or select schema..." -msgstr "Ustvarite ali izberite shemo..." +#: superset/views/dashboard/mixin.py:58 +msgid "To get a readable URL for your dashboard" +msgstr "Za pridobitev berljivega URL-ja za nadzorno ploščo" -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:169 -msgid "Created" -msgstr "Ustvarjene" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:625 +#: superset/views/dashboard/mixin.py:59 +msgid "" +"This JSON object is generated dynamically when clicking the save or overwrite " +"button in the dashboard view. It is exposed here for reference and for power " +"users who may want to alter specific parameters." +msgstr "" +"Ta JSON objekt se ustvari dinamično s klikom gumba Shrani ali Prepiši v pogledu " +"nadzorne plošče. Tukaj je prikazan kot vzorec za napredne uporabnike, ki želijo " +"spreminjati posamezne parametre." -#: superset/views/access_requests.py:46 superset/views/schedules.py:237 -#: superset/views/schedules.py:317 -msgid "Created On" -msgstr "Ustvarjeno" +#: superset/views/dashboard/mixin.py:65 +msgid "Owners is a list of users who can alter the dashboard." +msgstr "\"Lastniki\" je seznam uporabnikov, ki lahko spreminjajo nadzorno ploščo." -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:383 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:212 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:286 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:333 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:474 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:192 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:273 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:323 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:471 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:292 -msgid "Created by" -msgstr "Ustvaril" +#: superset/views/dashboard/mixin.py:66 +msgid "" +"Roles is a list which defines access to the dashboard. Granting a role access to " +"a dashboard will bypass dataset level checks.If no roles defined then the " +"dashboard is available to all roles." +msgstr "" +"\"Vloge\" je seznam, ki definira dostop do nadzorne plošče. Dodelitev vloge za " +"dostop do nadzorne plošče bo obšlo preverjanje na nivoju podatkovnega seta. Če " +"vloga ni definirana, bo nadzorna plošča dostopna vsem vlogam." -#: superset-frontend/src/profile/components/App.tsx:62 -msgid "Created content" -msgstr "Ustvarjena vsebina" +#: superset/views/dashboard/mixin.py:71 +msgid "" +"Determines whether or not this dashboard is visible in the list of all dashboards" +msgstr "Določa ali je nadzorna plošča vidna na seznamu vseh nadzornih plošč" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:205 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:184 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:349 -msgid "Created on" -msgstr "Ustvarjeno" +#: superset-frontend/src/components/DynamicEditableTitle/index.tsx:186 +#: superset-frontend/src/components/DynamicEditableTitle/index.tsx:207 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:550 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:41 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:281 +#: superset/views/dashboard/mixin.py:79 superset/views/dashboard/views.py:195 +msgid "Title" +msgstr "Naslov" -#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.jsx:72 -msgid "Creating a data source and creating a new tab" -msgstr "Ustvarjanje podatkovnega vira in novega zavihka" +#: superset/views/dashboard/mixin.py:80 +msgid "Slug" +msgstr "Slug" -#: superset/connectors/sqla/views.py:370 superset/views/chart/mixin.py:78 -#: superset/views/dashboard/mixin.py:85 superset/views/dashboard/views.py:157 -#: superset/views/database/mixins.py:192 -msgid "Creator" -msgstr "Avtor" +#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:101 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:304 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:506 +#: superset/views/dashboard/mixin.py:84 +msgid "Published" +msgstr "Objavljeno" -#: superset/views/schedules.py:241 superset/views/schedules.py:321 -msgid "Crontab" -msgstr "Crontab" +#: superset/views/dashboard/mixin.py:87 +msgid "Position JSON" +msgstr "JSON za postavitev" -#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:65 -msgid "Cross Filter Scoping" -msgstr "Doseg medsebojnega filtra" +#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:105 +#: superset/views/dashboard/mixin.py:88 +msgid "CSS" +msgstr "CSS" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:349 -msgid "Cross-filter scoping" -msgstr "Doseg medsebojnega filtra" +#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:117 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:416 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:704 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:99 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:388 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:651 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:399 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:410 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:683 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:518 +#: superset/views/dashboard/views.py:66 +msgid "Export" +msgstr "Izvoz" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:153 -msgid "Cumulative" -msgstr "Kumulativno" +#: superset/views/dashboard/views.py:66 +msgid "Export dashboards?" +msgstr "Izvozim nadzorne plošče?" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:33 -msgid "Custom" -msgstr "Prilagojen" +#: superset/views/database/forms.py:96 +msgid "Name of table to be created from csv data." +msgstr "Ime tabele, ki bo ustvarjena iz CSV podatkov." -#: superset/views/dynamic_plugins.py:59 -msgid "Custom Plugin" -msgstr "Prilagojeni vtičnik" +#: superset/views/database/forms.py:99 superset/views/database/forms.py:253 +#: superset/views/database/forms.py:389 +msgid "Table name cannot contain a schema" +msgstr "Ime tabele ne sme vsebovati sheme" -#: superset/views/dynamic_plugins.py:58 -msgid "Custom Plugins" -msgstr "Prilagojeni vtičniki" +#: superset/views/database/forms.py:104 +msgid "CSV File" +msgstr "CSV datoteka" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:283 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:226 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:229 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:440 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:443 -msgid "Custom SQL" -msgstr "Prilagojen SQL" +#: superset/views/database/forms.py:105 +msgid "Select a CSV file to be uploaded to a database." +msgstr "Izberite CSV datoteko, ki bo naložena v podatkovno bazo." -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:222 -msgid "Custom SQL ad-hoc filters are not available for the native Druid connector" -msgstr "Ad-hoc SQL filtri po meri niso na voljo za nativni konektor za Druid" +#: superset/views/database/forms.py:114 superset/views/database/forms.py:268 +#: superset/views/database/forms.py:406 +#, python-format +msgid "Only the following file extensions are allowed: %(allowed_extensions)s" +msgstr "Dovoljene so le naslednje končnice: %(allowed_extensions)s" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:432 -msgid "Custom SQL ad-hoc metrics are not available for the native Druid connector" -msgstr "Ad-hoc SQL mere po meri niso na voljo za nativni konektor za Druid" +#: superset/views/database/forms.py:130 superset/views/database/forms.py:292 +#: superset/views/database/forms.py:423 +msgid "Specify a schema (if database flavor supports this)." +msgstr "Podajte shemo (če vrsta podatkovne baze to podpira)" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:435 -msgid "Custom SQL ad-hoc metrics are not enabled for this dataset" -msgstr "Ad-hoc SQL mere po meri za ta podatkovni set niso omogočene" +#: superset/views/database/forms.py:135 +msgid "Delimiter" +msgstr "Ločilnik" -#: superset-frontend/src/filters/components/Time/index.ts:28 -msgid "Custom time filter plugin" -msgstr "Prilagojeni vtičnik za časovni filter" +#: superset/views/database/forms.py:136 +msgid "Delimiter used by CSV file (for whitespace use \\s+)." +msgstr "Ločilnik, uporabljen v CSV datoteki (za presledek uporabi \\s+)." -#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:417 -msgid "Customize" -msgstr "Prilagodi" +#: superset/views/database/forms.py:141 superset/views/database/forms.py:297 +#: superset/views/database/forms.py:428 +msgid "Table Exists" +msgstr "Tabela obstaja" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:167 -msgid "Customize Metrics" -msgstr "Prilagodi mere" +#: superset/views/database/forms.py:142 superset/views/database/forms.py:298 +#: superset/views/database/forms.py:429 +msgid "" +"If table exists do one of the following: Fail (do nothing), Replace (drop and " +"recreate table) or Append (insert data)." +msgstr "" +"Če tabela obstaja, naredite nekaj od sledečega: Prekini (ne naredi nič), Zamenjaj " +"(zbriši in ponovno ustvari tabelo) ali Dodaj (vstavi podatke)." -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:453 -msgid "Customize columns" -msgstr "Prilagodi stolpce" +#: superset/views/database/forms.py:148 superset/views/database/forms.py:304 +#: superset/views/database/forms.py:435 +msgid "Fail" +msgstr "Prekini" -#: superset/connectors/sqla/views.py:261 -msgid "D3 Format" -msgstr "D3 zapis" +#: superset/views/database/forms.py:149 superset/views/database/forms.py:305 +#: superset/views/database/forms.py:436 +msgid "Replace" +msgstr "Zamenjaj" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:58 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:69 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1060 -msgid "D3 format" -msgstr "D3 format" +#: superset/views/database/forms.py:150 superset/views/database/forms.py:306 +#: superset/views/database/forms.py:437 +msgid "Append" +msgstr "Dodaj" -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:22 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:150 -msgid "D3 format syntax: https://github.com/d3/d3-format" -msgstr "Sintaksa D3 formata: https://github.com/d3/d3-format" +#: superset/views/database/forms.py:155 superset/views/database/forms.py:311 +msgid "Header Row" +msgstr "Naslovna vrstica" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:154 +#: superset/views/database/forms.py:156 superset/views/database/forms.py:312 msgid "" -"D3 number format for numbers between -1.0 and 1.0, useful when you want " -"to have different siginificant digits for small and large numbers" +"Row containing the headers to use as column names (0 is first line of data). " +"Leave empty if there is no header row." msgstr "" -"D3 oblika zapisa za števila med -1.0 in 1.0. Uporabno, če želite različno" -" število števk za majhna in velika števila" +"Vrstica z naslovi, ki se uporabi za imena stolpcev (0 je prva vrstica podatkov). " +"Pustite prazno, če ni naslovne vrstice." -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:220 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:377 -msgid "D3 time format for datetime columns" -msgstr "D3 oblika zapisa za časovne stolpce" - -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:44 -msgid "D3 time format syntax: https://github.com/d3/d3-time-format" -msgstr "Sintaksa D3 časovnega formata:: https://github.com/d3/d3-time-format" +#: superset/views/database/forms.py:165 superset/views/database/forms.py:321 +msgid "Index Column" +msgstr "Indeksni stolpec" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:102 -msgid "DEC" -msgstr "DEC" +#: superset/views/database/forms.py:166 superset/views/database/forms.py:322 +msgid "" +"Column to use as the row labels of the dataframe. Leave empty if no index column." +msgstr "" +"Stolpec, ki se uporabi za naslove vrstic v dataframe-u. Pustite prazno, če ni " +"indeksnega stolpca." -#: superset-frontend/src/components/DeleteModal/index.tsx:69 -msgid "DELETE" -msgstr "IZBRIŠI" +#: superset/views/database/forms.py:174 superset/views/database/forms.py:330 +msgid "Mangle Duplicate Columns" +msgstr "Odstrani podvojene stolpce" -#: superset-frontend/src/components/ReportModal/index.tsx:345 -msgid "DESCRIPTION ERROR" -msgstr "NAPAKA OPISA" +#: superset/views/database/forms.py:175 superset/views/database/forms.py:331 +msgid "Specify duplicate columns as \"X.0, X.1\"." +msgstr "Določite podvojene stolpce kot \"X.0, X.1\"." -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:259 -msgid "DML" -msgstr "DML" +#: superset/views/database/forms.py:178 superset/views/database/forms.py:442 +msgid "Use Columns" +msgstr "Uporabi stolpce" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:31 -msgid "Dark mode" -msgstr "Temni način" +#: superset/views/database/forms.py:180 superset/views/database/forms.py:444 +msgid "" +"Json list of the column names that should be read. If not None, only these " +"columns will be read from the file." +msgstr "" +"JSON seznam imen stolpcev, ki morajo biti prebrani. Če ni prazen, bodo iz " +"datoteke prebrani le ti stolpci." -#: superset-frontend/src/components/Menu/MenuRight.tsx:46 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1296 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1317 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:582 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:210 -#: superset/templates/appbuilder/navbar_right.html:40 -#: superset/views/dashboard/mixin.py:78 superset/views/dashboard/views.py:155 -#: superset/views/schedules.py:236 -msgid "Dashboard" -msgstr "Nadzorna plošča" +#: superset/views/database/forms.py:187 +msgid "Skip Initial Space" +msgstr "Izpusti začetni presledek" -#: superset/initialization/__init__.py:444 -msgid "Dashboard Emails" -msgstr "E-pošta za nadzorno ploščo" +#: superset/views/database/forms.py:187 +msgid "Skip spaces after delimiter." +msgstr "Izpusti presledek za ločilnikom." -#: superset/views/core.py:1028 -msgid "Dashboard [{}] just got created and chart [{}] was added to it" -msgstr "Nadzorna plošča [{}] je bila ravno ustvarjena in grafikon [{}] dodan nanjo" +#: superset/views/database/forms.py:190 superset/views/database/forms.py:334 +msgid "Skip Rows" +msgstr "Izpusti vrstice" -#: superset/dashboards/commands/exceptions.py:54 -msgid "Dashboard could not be created." -msgstr "Nadzorne plošče ni mogoče ustvariti." +#: superset/views/database/forms.py:191 superset/views/database/forms.py:335 +msgid "Number of rows to skip at start of file." +msgstr "Število vrstic, ki se izpustijo na začetku datoteke." -#: superset/dashboards/commands/exceptions.py:70 -msgid "Dashboard could not be deleted." -msgstr "Nadzorne plošče ni mogoče izbrisati." +#: superset/views/database/forms.py:196 superset/views/database/forms.py:340 +msgid "Rows to Read" +msgstr "Vrstice za branje" -#: superset/dashboards/commands/exceptions.py:66 -msgid "Dashboard could not be updated." -msgstr "Nadzorne plošče ni mogoče posodobiti." +#: superset/views/database/forms.py:197 superset/views/database/forms.py:341 +msgid "Number of rows of file to read." +msgstr "Število vrstic v datoteki za branje." -#: superset/reports/commands/exceptions.py:44 -msgid "Dashboard does not exist" -msgstr "Nadzorna plošča ne obstaja" +#: superset/views/database/forms.py:202 +msgid "Skip Blank Lines" +msgstr "Izpusti prazne vrstice" -#: superset/dashboards/commands/exceptions.py:43 -msgid "Dashboard parameters are invalid." -msgstr "Parametri nadzorne plošče so neveljavni." +#: superset/views/database/forms.py:203 +msgid "Skip blank lines rather than interpreting them as NaN values." +msgstr "Raje izpusti prazne vrstice, kot pa da so prepoznane kot NaN vrednosti." -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:464 -msgid "Dashboard properties" -msgstr "Lastnosti nadzorne plošče" +#: superset/views/database/forms.py:206 superset/views/database/forms.py:346 +msgid "Parse Dates" +msgstr "Prepoznaj datume" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:153 -#, fuzzy -msgid "Dashboard scheme" -msgstr "[ime nadzorne plošče]" +#: superset/views/database/forms.py:207 superset/views/database/forms.py:347 +msgid "A comma separated list of columns that should be parsed as dates." +msgstr "Z vejico ločen seznam stolpcev, v katerih bodo prepoznani datumi." -#: superset-frontend/src/profile/components/CreatedContent.tsx:73 -#: superset-frontend/src/profile/components/Favorites.tsx:74 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:609 -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:294 -#: superset/initialization/__init__.py:238 superset/views/chart/mixin.py:79 -#: superset/views/dashboard/mixin.py:25 -msgid "Dashboards" -msgstr "Nadzorne plošče" +#: superset/views/database/forms.py:213 +msgid "Infer Datetime Format" +msgstr "Prepoznaj obliko datuma/časa" -#: superset/dashboards/commands/exceptions.py:58 -msgid "Dashboards could not be deleted." -msgstr "Nadzornih plošč ni mogoče izbrisati." +#: superset/views/database/forms.py:214 +msgid "Use Pandas to interpret the datetime format automatically." +msgstr "Uporabi Pandas za samodejno prepoznavo oblike datumov/časov." -#: superset/charts/commands/exceptions.py:91 -msgid "Dashboards do not exist" -msgstr "Nadzorna plošča ne obstaja" +#: superset/views/database/forms.py:217 superset/views/database/forms.py:353 +msgid "Decimal Character" +msgstr "Decimalno ločilo" -#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:401 -#: superset-frontend/src/explore/components/DataTablesPane/index.tsx:388 -#: superset-frontend/src/views/CRUD/data/common.ts:22 -#: superset/initialization/__init__.py:354 -#: superset/initialization/__init__.py:363 -#: superset/initialization/__init__.py:373 -#: superset/initialization/__init__.py:387 -#: superset/initialization/__init__.py:404 -#: superset/initialization/__init__.py:509 -#: superset/initialization/__init__.py:519 -#: superset/initialization/__init__.py:532 -#: superset/initialization/__init__.py:545 -msgid "Data" -msgstr "Podatki" +#: superset/views/database/forms.py:219 superset/views/database/forms.py:355 +msgid "Character to interpret as decimal point." +msgstr "Znak, ki bo prepoznan kot decimalno ločilo." -#: superset/connectors/druid/views.py:343 -msgid "Data Source" -msgstr "Podatkovni vir" +#: superset/views/database/forms.py:224 superset/views/database/forms.py:360 +#: superset/views/database/forms.py:451 +msgid "Dataframe Index" +msgstr "Indeks dataframe-a" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:57 -msgid "Data Table" -msgstr "Tabela podatkov" +#: superset/views/database/forms.py:224 superset/views/database/forms.py:360 +#: superset/views/database/forms.py:451 +msgid "Write dataframe index as a column." +msgstr "Zapiši indeks dataframe-a kot stolpec." -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:290 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:181 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:142 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:122 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:139 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:197 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:200 -msgid "Data Zoom" -msgstr "Zoom funkcija" +#: superset/views/database/forms.py:227 superset/views/database/forms.py:363 +#: superset/views/database/forms.py:454 +msgid "Column Label(s)" +msgstr "Naslovi stolpcev" -#: superset/views/core.py:2313 +#: superset/views/database/forms.py:228 superset/views/database/forms.py:364 +#: superset/views/database/forms.py:455 msgid "" -"Data could not be deserialized from the results backend. The storage " -"format might have changed, rendering the old data stake. You need to re-" -"run the original query." +"Column label for index column(s). If None is given and Dataframe Index is True, " +"Index Names are used." msgstr "" -"Podatkov ni bilo mogoče deserializirati iz zalednega sistema rezultatov. " -"Lahko je prišlo do spremembe oblike zapisa. Ponovno zaženite izvorno " -"poizvedbo." +"Naslovi stolpcev za indeksne stolpce. Če le-ti niso podani in indeksi Dataframe-a " +"obstajajo, se uporabijo imena indeksov." + +#: superset/views/database/forms.py:236 superset/views/database/forms.py:372 +msgid "Null values" +msgstr "Prazne (Null) vrednosti" -#: superset/views/core.py:2266 +#: superset/views/database/forms.py:238 superset/views/database/forms.py:374 msgid "" -"Data could not be retrieved from the results backend. You need to re-run " -"the original query." +"Json list of the values that should be treated as null. Examples: [\"\"], [\"None" +"\", \"N/A\"], [\"nan\", \"null\"]. Warning: Hive database supports only single " +"value. Use [\"\"] for empty string." msgstr "" -"Podatkov ni bilo mogoče pridobiti iz zalednega sistema rezultatov. " -"Ponovno morate zagnati izvorno poizvedbo." +"JSON seznam vrednosti, ki naj bodo obravnavane kot prazne (Null). Primeri: " +"[\"\"], [\"None\", \"N/A\"], [\"nan\", \"null\"]. Opozorilo: Podatkovna baza Hive " +"podpira le eno vrednost. Uporabite [\"\"] za prazen znakovni niz." -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:219 -msgid "Data preview" -msgstr "Ogled podatkov" +#: superset/views/database/forms.py:250 +msgid "Name of table to be created from excel data." +msgstr "Ime tabele, ki bo ustvarjena iz Excel-ovih podatkov." -#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:136 -msgid "Data source" -msgstr "Podatkovni vir" +#: superset/views/database/forms.py:258 +msgid "Excel File" +msgstr "Excel-ova datoteka" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:213 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:216 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:284 -msgid "Data type" -msgstr "Tip podatka" +#: superset/views/database/forms.py:259 +msgid "Select a Excel file to be uploaded to a database." +msgstr "Izberite Excel-ovo datoteko, ki bo naložena v podatkovno bazo." -#: superset/utils/pandas_postprocessing.py:832 -msgid "DataFrame include at least one series" -msgstr "DataFrame vsebuje vsaj eno serijo" +#: superset/views/database/forms.py:278 +msgid "Sheet Name" +msgstr "Ime zvezka" -#: superset/utils/pandas_postprocessing.py:830 -msgid "DataFrame must include temporal column" -msgstr "DataFrame mora vsebovati časovni stolpec" +#: superset/views/database/forms.py:279 +msgid "Strings used for sheet names (default is the first sheet)." +msgstr "" +"Znakovni nizi uporabljeni za imena preglednic (privzeto je prva preglednica)." -#: superset-frontend/src/components/DatabaseSelector/index.tsx:271 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1127 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1132 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:179 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:223 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:294 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:436 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:223 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:331 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:277 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:424 -#: superset/connectors/sqla/views.py:490 superset/connectors/sqla/views.py:491 -#: superset/templates/superset/import_dashboards.html:53 -#: superset/views/database/forms.py:120 superset/views/database/forms.py:279 -#: superset/views/database/forms.py:407 superset/views/database/mixins.py:191 -#: superset/views/sql_lab.py:70 -msgid "Database" -msgstr "Podatkovna baza" +#: superset/views/database/forms.py:386 +msgid "Name of table to be created from columnar data." +msgstr "Ime tabele, ki bo ustvarjena iz podatkov v stolpcih." -#: superset/views/database/views.py:452 -#, python-format +#: superset/views/database/forms.py:394 +msgid "Columnar File" +msgstr "Stoplčna datoteka" + +#: superset/views/database/forms.py:395 +msgid "Select a Columnar file to be uploaded to a database." +msgstr "Izberite stolpčno datoteko, ki bo naložena v podatkovno bazo." + +#: superset/views/database/mixins.py:34 +msgid "Show Database" +msgstr "Prikaži podatkovno bazo" + +#: superset/views/database/mixins.py:35 +msgid "Add Database" +msgstr "Dodaj podatkovno bazo" + +#: superset/views/database/mixins.py:36 +msgid "Edit Database" +msgstr "Uredi podatkovno bazo" + +#: superset/views/database/mixins.py:104 +msgid "Expose this DB in SQL Lab" +msgstr "Uporabi to podatkovno bazo v SQL laboratoriju" + +#: superset/views/database/mixins.py:105 msgid "" -"Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed " -"for columnar uploads. Please contact your Superset Admin." +"Operate the database in asynchronous mode, meaning that the queries are executed " +"on remote workers as opposed to on the web server itself. This assumes that you " +"have a Celery worker setup as well as a results backend. Refer to the " +"installation docs for more information." msgstr "" -"Shema \"%(schema_name)s\" podatkovne baze \"%(database_name)s\" ni " -"dovoljena za nalaganje stolpčnih datotek. Kontaktirajte administratorja " -"za Superset." +"Upravljanje podatkovne baze v asinhronem načinu pomeni, da se poizvedbe zaženejo " +"na oddaljenih »delavcih« in ne na samem spletnem strežniku. S tem je " +"predpostavljeno, da imate nastavljenega »delavca« za Celery in zaledni sistem za " +"rezultate. Več informacij je v navodilih za namestitev." -#: superset/views/database/views.py:136 -#, python-format +#: superset/views/database/mixins.py:113 +msgid "Allow CREATE TABLE AS option in SQL Lab" +msgstr "Dovoli opcijo CREATE TABLE AS v SQL laboratoriju" + +#: superset/views/database/mixins.py:114 +msgid "Allow CREATE VIEW AS option in SQL Lab" +msgstr "Dovoli opcijo CREATE VIEW AS v SQL laboratoriju" + +#: superset/views/database/mixins.py:115 msgid "" -"Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed " -"for csv uploads. Please contact your Superset Admin." +"Allow users to run non-SELECT statements (UPDATE, DELETE, CREATE, ...) in SQL Lab" msgstr "" -"Shema \"%(schema_name)s\" podatkovne baze \"%(database_name)s\" ni " -"dovoljena za nalaganje CSV. Kontaktirajte administratorja za Superset." +"Dovoli uporabnikom poganjanje ne-SELECT stavkov (UPDATE, DELETE, CREATE, ...) v " +"SQL laboratoriju" -#: superset/views/database/views.py:283 -#, python-format +#: superset/views/database/mixins.py:120 msgid "" -"Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed " -"for excel uploads. Please contact your Superset Admin." +"When allowing CREATE TABLE AS option in SQL Lab, this option forces the table to " +"be created in this schema" msgstr "" -"Shema \"%(schema_name)s\" podatkovne baze \"%(database_name)s\" ni " -"dovoljena za nalaganje Excel datotek. Kontaktirajte administratorja za " -"Superset." +"Z dovolitvijo opcije CREATE TABLE AS v SQL laboratoriju se tabele ustvarjajo s to " +"shemo" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:910 -#, fuzzy -msgid "Database Creation Error" -msgstr "Napaka podatkovne baze" +#: superset/views/database/mixins.py:166 +msgid "" +"If Presto, all the queries in SQL Lab are going to be executed as the currently " +"logged on user who must have permission to run them.<br/>If Hive and hive.server2." +"enable.doAs is enabled, will run the queries as service account, but impersonate " +"the currently logged on user via hive.server2.proxy.user property." +msgstr "" +"V primeru Presto se vse poizvedbe v SQL laboratoriju zaženejo pod trenutno " +"prijavljenim uporabnikom, ki mora imeti pravice za poganjanje.<br/>Če je omogočen " +"Hive in hive.server2.enable.doAs, poizvedbe tečejo pod servisnim računom, vendar " +"je trenutno prijavljen uporabnik predstavljen z lastnostjo hive.server2.proxy." +"user." -#: superset/views/access_requests.py:43 -msgid "Database URL" -msgstr "URL podatkovne baze" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:161 +#: superset/views/database/mixins.py:173 +msgid "" +"Allow SQL Lab to fetch a list of all tables and all views across all database " +"schemas. For large data warehouse with thousands of tables, this can be expensive " +"and put strain on the system." +msgstr "" +"Dovoli SQL laboratoriju, da pridobi seznam vseh tabel in pogledov iz vseh shem " +"podatkovne baze. Pri velikih podatkovnih skladiščih s tisoči tabel je to lahko " +"potratno in obremeni sistem." -#: superset/databases/commands/exceptions.py:95 -msgid "Database could not be created." -msgstr "Podatkovne baze ni mogoče ustvariti." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:245 +#: superset/views/database/mixins.py:178 +msgid "" +"Duration (in seconds) of the caching timeout for charts of this database. A " +"timeout of 0 indicates that the cache never expires. Note this defaults to the " +"global timeout if undefined." +msgstr "" +"Trajanje (v sekundah) predpomnjenja za grafikon v tej podatkovni bazi. Vrednost 0 " +"označuje, da predpomnilnik nikoli ne poteče. V primeru, da ni definirano, ima " +"globalno nastavitev." -#: superset/databases/commands/exceptions.py:113 -msgid "Database could not be deleted." -msgstr "Podatkovne baze ni mogoče izbrisati." +#: superset/views/database/mixins.py:183 +msgid "If selected, please set the schemas allowed for csv upload in Extra." +msgstr "Če je izbrano, nastavite dovoljene sheme za nalaganje CSV v Dodatno." -#: superset/databases/commands/exceptions.py:99 -msgid "Database could not be updated." -msgstr "Podatkovne baze ni mogoče posodobiti." +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:338 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:444 +#: superset/views/database/mixins.py:189 +msgid "Expose in SQL Lab" +msgstr "Uporabi v SQL laboratoriju" -#: superset/errors.py:117 -msgid "Database does not allow data manipulation." -msgstr "Podatkovna baza ne dovoljuje manipulacije podatkov." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:95 +#: superset/views/database/mixins.py:190 +msgid "Allow CREATE TABLE AS" +msgstr "Dovoli CREATE TABLE AS" -#: superset/charts/commands/exceptions.py:82 -#: superset/datasets/commands/exceptions.py:41 -#: superset/reports/commands/exceptions.py:35 -msgid "Database does not exist" -msgstr "Podatkovna baza ne obstaja" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:109 +#: superset/views/database/mixins.py:191 +msgid "Allow CREATE VIEW AS" +msgstr "Dovoli CREATE VIEW AS" -#: superset/connectors/sqla/models.py:1478 -msgid "Database does not support subqueries" -msgstr "Podatkovna baza ne podpira podpoizvedb" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:142 +#: superset/views/database/mixins.py:192 +msgid "Allow DML" +msgstr "Dovoli DML" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:688 -msgid "Database error" -msgstr "Napaka podatkovne baze" +#: superset/views/database/mixins.py:193 +msgid "CTAS Schema" +msgstr "CTAS shema" -#: superset/databases/commands/validate.py:136 -msgid "Database is offline." -msgstr "Podatkovna baza ni povezana." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:74 +#: superset/views/database/mixins.py:197 +msgid "SQLAlchemy URI" +msgstr "SQLAlchemy URI" -#: superset/reports/commands/exceptions.py:62 -msgid "Database is required for alerts" -msgstr "Podatkovna baza je obvezna za opozorila" +#: superset/views/database/mixins.py:198 +msgid "Chart Cache Timeout" +msgstr "Trajanje predpomnilnika grafikona" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:89 -#: superset/db_engine_specs/base.py:1396 -msgid "Database name" -msgstr "Ime podatkovne baze" +#: superset/views/database/mixins.py:200 +msgid "Secure Extra" +msgstr "Dodatna varnost" -#: superset/datasets/commands/exceptions.py:50 -msgid "Database not allowed to change" -msgstr "Podatkovne baze ni dovoljeno spreminjati" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:369 +#: superset/views/database/mixins.py:201 +msgid "Root certificate" +msgstr "Korenski certifikat" -#: superset/databases/commands/exceptions.py:91 -msgid "Database not found." -msgstr "Podatkovna baza ni najdena." +#: superset/views/database/mixins.py:202 +msgid "Async Execution" +msgstr "Asinhrono izvajanje" -#: superset/databases/commands/exceptions.py:32 -msgid "Database parameters are invalid." -msgstr "Parametri podatkovne baze so neveljavni." - -#: superset/db_engine_specs/base.py:1393 -msgid "Database port" -msgstr "Vrata podatkovne baze" +#: superset/views/database/mixins.py:203 +msgid "Impersonate the logged on user" +msgstr "Predstavljaj se kot prijavljeni uporabnik" -#: superset-frontend/src/profile/components/Security.tsx:46 -#: superset-frontend/src/views/CRUD/data/common.ts:26 -#: superset/initialization/__init__.py:351 superset/views/database/mixins.py:33 -msgid "Databases" -msgstr "Podatkovne baze" +#: superset/views/database/mixins.py:204 +msgid "Allow Csv Upload" +msgstr "Dovoli nalaganje CSV" -#: superset/views/database/forms.py:221 superset/views/database/forms.py:354 -#: superset/views/database/forms.py:442 -msgid "Dataframe Index" -msgstr "Indeks dataframe-a" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:158 +#: superset/views/database/mixins.py:206 +msgid "Allow Multi Schema Metadata Fetch" +msgstr "Dovoli pridobivanje metapodatkov z več shemami" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:284 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx:89 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:833 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:862 -#: superset-frontend/src/explore/components/ExploreViewContainer.jsx:521 -#: superset-frontend/src/explore/controls.jsx:189 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:283 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:520 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:505 -msgid "Dataset" -msgstr "Podatkovni set" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:284 +#: superset/views/database/mixins.py:207 +msgid "Backend" +msgstr "Vrsta" -#: superset/datasets/commands/exceptions.py:32 +#: superset/views/database/mixins.py:247 superset/views/database/mixins.py:271 #, python-format -msgid "Dataset %(name)s already exists" -msgstr "Podatkovni set %(name)s že obstaja" - -#: superset/datasets/columns/commands/exceptions.py:27 -msgid "Dataset column delete failed." -msgstr "Brisanje stolpca podatkovnega seta neuspešno." - -#: superset/datasets/columns/commands/exceptions.py:23 -msgid "Dataset column not found." -msgstr "Stolpec podatkovnega seta ni najden." +msgid "Extra field cannot be decoded by JSON. %(msg)s" +msgstr "Dodatnega polja ni mogoče dekodirati z JSON. %(msg)s" -#: superset/datasets/commands/exceptions.py:157 -msgid "Dataset could not be created." -msgstr "Podatkovnega niza ni mogoče ustvariti." +#: superset/views/database/validators.py:40 +msgid "" +"Invalid connection string, a valid string usually follows:'DRIVER://USER:" +"PASSWORD@DB-HOST/DATABASE-NAME'<p>Example:'postgresql://user:password@your-" +"postgres-db/database'</p>" +msgstr "" +"Neveljaven niz povezave. Veljaven niz običajno sledi zapisu:'DRIVER://USER:" +"PASSWORD@DB-HOST/DATABASE-NAME'<p>Primer:'postgresql://user:password@your-" +"postgres-db/database'</p>" -#: superset/datasets/commands/exceptions.py:165 -msgid "Dataset could not be deleted." -msgstr "Podatkovnega niza ni mogoče izbrisati." +#: superset/views/database/views.py:115 +msgid "CSV to Database configuration" +msgstr "Nastavitve pretvorbe CSV v podatkovno bazo" -#: superset/datasets/commands/exceptions.py:161 -#: superset/datasets/commands/exceptions.py:173 -msgid "Dataset could not be updated." -msgstr "Podatkovnega niza ni mogoče posodobiti." +#: superset/views/database/views.py:133 +#, python-format +msgid "" +"Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for csv " +"uploads. Please contact your Superset Admin." +msgstr "" +"Shema \"%(schema_name)s\" podatkovne baze \"%(database_name)s\" ni dovoljena za " +"nalaganje CSV. Kontaktirajte administratorja za Superset." -#: superset/commands/exceptions.py:119 -#: superset/datasets/commands/exceptions.py:149 -msgid "Dataset does not exist" -msgstr "Podatkovni set ne obstaja" +#: superset/views/database/views.py:226 +#, python-format +msgid "" +"Unable to upload CSV file \"%(filename)s\" to table \"%(table_name)s\" in " +"database \"%(db_name)s\". Error message: %(error_msg)s" +msgstr "" +"CSV datoteke \"%(filename)s\" ni mogoče naložiti v tabelo \"%(table_name)s\" v " +"podatkovni bazi \"%(db_name)s\". Sporočilo napake: %(error_msg)s" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:843 -msgid "Dataset is required" -msgstr "Zahtevan je podatkovni set" +#: superset/views/database/views.py:238 +#, python-format +msgid "" +"CSV file \"%(csv_filename)s\" uploaded to table \"%(table_name)s\" in database " +"\"%(db_name)s\"" +msgstr "" +"CSV datoteka \"%(csv_filename)s\" naložena v tabelo \"%(table_name)s\" v " +"podatkovni bazi \"%(db_name)s\"" -#: superset/datasets/metrics/commands/exceptions.py:27 -msgid "Dataset metric delete failed." -msgstr "Brisanje mere podatkovnega seta ni uspelo." +#: superset/views/database/views.py:254 +msgid "Excel to Database configuration" +msgstr "Nastavitve pretvorbe Excel v Podatkovno bazo" -#: superset/datasets/metrics/commands/exceptions.py:23 -msgid "Dataset metric not found." -msgstr "Mer podatkovnega seta ni najdena." +#: superset/views/database/views.py:269 +#, python-format +msgid "" +"Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for " +"excel uploads. Please contact your Superset Admin." +msgstr "" +"Shema \"%(schema_name)s\" podatkovne baze \"%(database_name)s\" ni dovoljena za " +"nalaganje Excel datotek. Kontaktirajte administratorja za Superset." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:881 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:888 -msgid "Dataset name" -msgstr "Ime podatkovnega seta" +#: superset/views/database/views.py:363 +#, python-format +msgid "" +"Unable to upload Excel file \"%(filename)s\" to table \"%(table_name)s\" in " +"database \"%(db_name)s\". Error message: %(error_msg)s" +msgstr "" +"Excel datoteke \"%(filename)s\" ni mogoče naložiti v tabelo \"%(table_name)s\" v " +"podatkovni bazi \"%(db_name)s\". Sporočilo napake: %(error_msg)s" -#: superset/datasets/commands/exceptions.py:153 -msgid "Dataset parameters are invalid." -msgstr "Parametri podatkovnega seta so neveljavni." +#: superset/views/database/views.py:375 +#, python-format +msgid "" +"Excel file \"%(excel_filename)s\" uploaded to table \"%(table_name)s\" in " +"database \"%(db_name)s\"" +msgstr "" +"Excel datoteka \"%(excel_filename)s\" naložena v tabelo \"%(table_name)s\" v " +"podatkovni bazi \"%(db_name)s\"" -#: superset/datasets/commands/exceptions.py:169 -msgid "Dataset(s) could not be bulk deleted." -msgstr "Podatkovnih nizov ni mogoče množično izbrisati." +#: superset/views/database/views.py:391 +msgid "Columnar to Database configuration" +msgstr "Nastavitve pretvorbe Stolpci v Podatkovno bazo" -#: superset-frontend/src/profile/components/Security.tsx:60 -#: superset-frontend/src/views/CRUD/data/common.ts:32 -#: superset/initialization/__init__.py:359 -msgid "Datasets" -msgstr "Podatkovni seti" +#: superset/views/database/views.py:416 +msgid "" +"Multiple file extensions are not allowed for columnar uploads. Please make sure " +"all files are of the same extension." +msgstr "" +"Za nalaganje stolpčnih datotek niso dovoljene različne končnice. Poskrbite, da " +"imajo vse datoteke enake končnice." -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:809 -msgid "Datasets do not contain a temporal column" -msgstr "Podatkovni seti ne vsebujejo časovnega stolpca" +#: superset/views/database/views.py:429 +#, python-format +msgid "" +"Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for " +"columnar uploads. Please contact your Superset Admin." +msgstr "" +"Shema \"%(schema_name)s\" podatkovne baze \"%(database_name)s\" ni dovoljena za " +"nalaganje stolpčnih datotek. Kontaktirajte administratorja za Superset." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:157 -#: superset/connectors/druid/views.py:93 superset/views/access_requests.py:44 -#: superset/views/chart/mixin.py:80 -msgid "Datasource" -msgstr "Podatkovni vir" +#: superset/views/database/views.py:504 +#, python-format +msgid "" +"Unable to upload Columnar file \"%(filename)s\" to table \"%(table_name)s\" in " +"database \"%(db_name)s\". Error message: %(error_msg)s" +msgstr "" +"Stolpčne datoteke \"%(filename)s\" ni mogoče naložiti v tabelo \"%(table_name)s\" " +"v podatkovni bazi \"%(db_name)s\". Sporočilo napake: %(error_msg)s" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:48 -msgid "Datasource & Chart Type" -msgstr "Tip podatkovnega vira in grafikona" +#: superset/views/database/views.py:516 +#, python-format +msgid "" +"Columnar file \"%(columnar_filename)s\" uploaded to table \"%(table_name)s\" in " +"database \"%(db_name)s\"" +msgstr "" +"Stolpčna datoteka \"%(columnar_filename)s\" naložena v tabelo \"%(table_name)s\" " +"v podatkovni bazi \"%(db_name)s\"" -#: superset/connectors/druid/views.py:352 -msgid "Datasource Name" -msgstr "Ime podatkovnega vira" +#: superset/views/datasource/views.py:71 +msgid "Request missing data field." +msgstr "Zahtevaj manjkajoča podatkovna polja." -#: superset/connectors/connector_registry.py:99 +#: superset/views/datasource/views.py:105 #, python-format -msgid "Datasource id not found: %(id)s" -msgstr "ID podatkovnega vira ni bil najden: %(id)s" +msgid "Duplicate column name(s): %(columns)s" +msgstr "Podvojena imena stolpcev: %(columns)s" -#: superset/charts/commands/exceptions.py:101 -msgid "Datasource type is required when datasource_id is given" -msgstr "Ko se podaja datasource_id, je potreben tip podatkovnega vira" +#: superset/views/log/__init__.py:21 +msgid "Logs" +msgstr "Dnevniki" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:163 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:87 -msgid "Date Time Format" -msgstr "Oblika zapisa Datum-Časa" +#: superset/views/log/__init__.py:22 +msgid "Show Log" +msgstr "Prikaži dnevnik" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:79 -msgid "Date filter" -msgstr "Filter po datumu" +#: superset/views/log/__init__.py:23 +msgid "Add Log" +msgstr "Dodaj dnevnik" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:142 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:115 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:136 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:153 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:129 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:216 -msgid "Date format" -msgstr "Oblika zapisa datuma" +#: superset/views/log/__init__.py:24 +msgid "Edit Log" +msgstr "Uredi dnevnik" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:235 -msgid "Date/Time" -msgstr "Datum/Čas" +#: superset/views/log/__init__.py:31 +msgid "Action" +msgstr "Aktivnost" -#: superset/connectors/sqla/views.py:151 -msgid "Datetime Format" -msgstr "Oblika zapisa datuma,časa" +#: superset/views/log/__init__.py:32 +msgid "dttm" +msgstr "dttm" -#: superset/connectors/sqla/models.py:1062 -msgid "" -"Datetime column not provided as part table configuration and is required " -"by this type of chart" -msgstr "" -"Stolpec datum-čas ni podan kot del tabele, čeprav mora biti za ta tip " -"grafikona" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1095 +#: superset/views/log/__init__.py:33 +msgid "JSON" +msgstr "JSON" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:227 -msgid "Datetime format" -msgstr "Oblika datum-časa" +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:31 +msgid "Time Range" +msgstr "Časovno obdobje" -#: superset/db_engine_specs/base.py:96 -msgid "Day" -msgstr "Dan" +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:32 +msgid "Time Column" +msgstr "Časovni stolpec" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:66 -#, fuzzy, python-format -msgid "Days %s" -msgstr "Pretečeno %s" +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:33 +msgid "Time Grain" +msgstr "Granulacija časa" -#: superset/connectors/sqla/models.py:1593 -msgid "Db engine did not return all queried columns" -msgstr "Sitem podatkovne baze ni vrnil vse stolpcev poizvedbe" +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:34 +#: superset-frontend/src/explore/constants.ts:122 +msgid "Origin" +msgstr "Izhodišče" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:77 -msgid "December" -msgstr "December" +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:35 +msgid "Time Granularity" +msgstr "Granulacija časa" -#: superset/views/database/forms.py:214 superset/views/database/forms.py:347 -msgid "Decimal Character" -msgstr "Decimalno ločilo" +# SUPERSET UI +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:39 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:26 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:52 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:39 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:37 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:87 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:74 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:73 +#: superset-frontend/src/explore/controlPanels/sections.tsx:25 +#: superset-frontend/src/explore/controlPanels/sections.tsx:75 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:182 +msgid "Time" +msgstr "Čas" -#: superset/viz.py:2706 -msgid "Deck.gl - 3D Grid" -msgstr "Deck.gl - 3D mreža" +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:46 +#: superset-frontend/src/explore/controls.jsx:113 +msgid "A reference to the [Time] configuration, taking granularity into account" +msgstr "Sklic na nastavitve za [Čas], ki upošteva granulacijo" -#: superset/viz.py:2822 -msgid "Deck.gl - 3D HEX" -msgstr "Deck.gl - 3D HEX" +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:58 +msgid "Aggregate" +msgstr "Agregacija" -#: superset/viz.py:2862 -msgid "Deck.gl - Arc" -msgstr "Deck.gl - Arc" +#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:59 +msgid "Raw records" +msgstr "Surovi podatki" -#: superset/viz.py:2843 -msgid "Deck.gl - GeoJSON" -msgstr "Deck.gl - GeoJSON" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/CertifiedIconWithTooltip.tsx:46 +#: superset-frontend/src/components/CertifiedBadge/index.tsx:44 +#, python-format +msgid "Certified by %s" +msgstr "Certificiral/a %s" -#: superset/viz.py:2431 -msgid "Deck.gl - Multiple Layers" -msgstr "Deck.gl - Večplastni" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx:64 +#: superset-frontend/src/explore/components/ControlHeader.tsx:82 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:327 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:262 +msgid "description" +msgstr "opis" -#: superset/viz.py:2738 -msgid "Deck.gl - Paths" -msgstr "Deck.gl - Poti" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx:74 +#: superset-frontend/src/explore/components/ControlHeader.tsx:92 +msgid "bolt" +msgstr "vijak" -#: superset/viz.py:2789 -msgid "Deck.gl - Polygon" -msgstr "Deck.gl - Poligon" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx:75 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:42 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:57 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:70 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:85 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:100 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:72 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:89 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:103 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:120 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:137 +#: superset-frontend/src/explore/components/ControlHeader.tsx:93 +msgid "Changing this control takes effect instantly" +msgstr "Sprememba tega kontrolnika se odrazi takoj" -#: superset/viz.py:2625 -msgid "Deck.gl - Scatter plot" -msgstr "Deck.gl - Raztreseni graf" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/InfoTooltipWithTrigger.tsx:52 +msgid "Show info tooltip" +msgstr "Prikaži opis orodja" -#: superset/viz.py:2677 -msgid "Deck.gl - Screen Grid" -msgstr "Deck.gl - Mreža" - -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:167 -msgid "Default" -msgstr "Privzeto" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/SQLPopover.tsx:64 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:233 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1198 +msgid "SQL expression" +msgstr "SQL izraz" -#: superset/connectors/druid/views.py:349 superset/connectors/sqla/views.py:495 -msgid "Default Endpoint" -msgstr "Privzeta končna točka" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:80 +msgid "Column name" +msgstr "Ime stolpca" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:699 -msgid "Default URL" -msgstr "Privzeti URL" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx:108 +msgid "Metric name" +msgstr "Ime mere" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:700 -msgid "Default URL to redirect to when accessing from the dataset list page" -msgstr "" -"Privzeti URL za preusmeritev, ko dostopate iz strani s seznamom " -"podatkovnih setov" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:53 +msgid "unknown type icon" +msgstr "ikona neznanega tipa" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:907 -msgid "Default Value" -msgstr "Privzeta vrednost" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:57 +msgid "function type icon" +msgstr "ikona funkcijskega tipa" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:290 -msgid "Default latitude" -msgstr "Privzeta širina" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:59 +msgid "string type icon" +msgstr "ikona znakovnega tipa" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:276 -msgid "Default longitude" -msgstr "Privzeta dolžina" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:61 +msgid "numeric type icon" +msgstr "ikona numeričnega tipa" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:91 -msgid "" -"Default minimal column width in pixels, actual width may still be larger " -"than this if other columns don't need much space" -msgstr "" -"Privzeta min. širina stolpca v pikslih. Dejanska širina bo lahko večja, " -"če drugi stolpci ne potrebujejo veliko prostora" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:63 +msgid "boolean type icon" +msgstr "ikona binarnega tipa" -#: superset-frontend/src/filters/components/Select/controlPanel.ts:105 -msgid "Default to first item" -msgstr "Privzet prvi element" +#: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:65 +msgid "temporal type icon" +msgstr "ikona časovnega tipa" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:936 -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:222 -msgid "Default value is required" -msgstr "Zahtevana je privzeta vrednost" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:25 +#: superset-frontend/src/explore/controlPanels/sections.tsx:127 +msgid "Advanced analytics" +msgstr "Napredna analitika" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:95 -msgid "Default value must be set when \"Filter has default value\" is checked" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:27 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:236 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:119 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:367 +#: superset-frontend/src/explore/controlPanels/sections.tsx:129 +msgid "" +"This section contains options that allow for advanced analytical post processing " +"of query results" msgstr "" -"Privzeta vrednost mora biti določena, če je izbrano \"Filter ima privzeto" -" vrednost\"" +"Ta sekcija vsebuje možnosti, ki omogočajo napredno analitično poprocesiranje " +"rezultatov poizvedb" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:93 -msgid "Default value must be set when \"Required\" is checked" -msgstr "Privzeta vrednost mora biti določena, če je izbrano \"Obvezno\"" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:33 +#: superset-frontend/src/explore/controlPanels/sections.tsx:135 +msgid "Rolling window" +msgstr "Drseče okno" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:89 -msgid "Default value set automatically when \"Default to first item\" is checked" -msgstr "" -"Privzeta vrednost je samodejno izbrana, če je izbrano \"Privzet prvi " -"element\"" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:39 +#: superset-frontend/src/explore/controlPanels/sections.tsx:141 +msgid "Rolling function" +msgstr "Drseča funkcija" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:242 +#: superset-frontend/plugins/plugin-chart-echarts/src/constants.ts:75 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:124 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx:77 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:120 +msgid "None" +msgstr "Brez" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:44 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:266 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:149 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:167 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:398 -#: superset-frontend/src/explore/controlPanels/sections.tsx:167 -msgid "" -"Defines a rolling window function to apply, works along with the " -"[Periods] text box" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:258 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:141 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:388 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:182 +#: superset-frontend/src/explore/controlPanels/sections.tsx:150 +msgid "" +"Defines a rolling window function to apply, works along with the [Periods] text " +"box" msgstr "Določi funkcijo drsečega okna. Dela skupaj s tekstovnim okvirjem [Obdobja]" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:134 -msgid "Defines how each series is broken down" -msgstr "Določa, kako se vsaka podatkovna serija razčleni" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:56 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:270 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:153 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:400 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:194 +#: superset-frontend/src/explore/controlPanels/sections.tsx:160 +msgid "Periods" +msgstr "Št. period" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:64 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:388 -#: superset-frontend/src/explore/controls.jsx:403 -msgid "" -"Defines the grouping of entities. Each series is shown as a specific " -"color on the chart and has a legend toggle" -msgstr "" -"Določa združevanje entitet. Vsak niz je na grafikonu prikazan z določeno " -"barvo in ima lahko prikazano legendo" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:58 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:272 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:155 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:402 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:196 +#: superset-frontend/src/explore/controlPanels/sections.tsx:162 +msgid "" +"Defines the size of the rolling window function, relative to the time granularity " +"selected" +msgstr "Določi velikost funkcije drsečega okna, glede na izbrano granulacijo časa" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:227 -#: superset-frontend/src/explore/controls.jsx:258 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:80 +#: superset-frontend/src/explore/controlPanels/sections.tsx:172 +msgid "Min periods" +msgstr "Min. št. period" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:82 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:284 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:167 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:416 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:210 +#: superset-frontend/src/explore/controlPanels/sections.tsx:174 +msgid "" +"The minimum number of rolling periods required to show a value. For instance if " +"you do a cumulative sum on 7 days you may want your \"Min Period\" to be 7, so " +"that all data points shown are the total of 7 periods. This will hide the \"ramp " +"up\" taking place over the first 7 periods" +msgstr "" +"Minimalno število drsečih obdobij, potrebnih za prikaz vrednosti. Če računate " +"kumulativno vsoto 7-dnevnega obdobja, boste nastavili \"Min. št. period\" na 7. " +"Tako bodo vse prikazane točke skupaj obsegale 7 obdobij. To bo prikrilo rampo, ki " +"bi trajala prvih 7 obdobij" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:102 +#: superset-frontend/src/explore/controlPanels/sections.tsx:184 +msgid "Time comparison" +msgstr "Časovna primerjava" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:110 +#: superset-frontend/src/explore/controlPanels/sections.tsx:192 +msgid "Time shift" +msgstr "Časovni zamik" + +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:123 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:316 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:199 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:447 +#: superset-frontend/src/explore/controlPanels/sections.tsx:205 msgid "" -"Defines the origin where time buckets start, accepts natural dates as in " -"`now`, `sunday` or `1970-01-01`" +"Overlay one or more timeseries from a relative time period. Expects relative time " +"deltas in natural language (example: 24 hours, 7 days, 52 weeks, 365 days). Free " +"text is supported." msgstr "" -"Določa izhodišče, kadar se začnejo časovni razdelki. Sprejema naravne " -"zapise kot so `zdaj`, `nedelja` ali `1970-01-01`" +"Zamaknite eno ali več časovnih vrst za relativno časovno obdobje. Vnaša se " +"relativne časovne razlike v naravnem jeziku (npr. 24 ur, 7 dni, 52 tednov, 365 " +"dni). Prosto besedilo je podprto." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:58 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:280 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:163 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:181 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:412 -#: superset-frontend/src/explore/controlPanels/sections.tsx:179 -msgid "" -"Defines the size of the rolling window function, relative to the time " -"granularity selected" -msgstr "Določi velikost funkcije drsečega okna, glede na izbrano granulacijo časa" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:137 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:328 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:211 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:461 +#: superset-frontend/src/explore/controlPanels/sections.tsx:217 +msgid "Calculation type" +msgstr "Tip izračuna" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:120 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:145 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:336 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:219 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:469 +#: superset-frontend/src/explore/controlPanels/sections.tsx:225 msgid "" -"Defines whether the step should appear at the beginning, middle or end " -"between two data points" +"How to display time shifts: as individual lines; as the difference between the " +"main time series and each time shift; as the percentage change; or as the ratio " +"between series and time shifts." msgstr "" -"Določa, če se na začetku, na sredini ali na koncu pojavi stopnica med " -"dvema točkama" +"Način prikaza časovnih zamikov: kot samostojne črte; kot razlike med osnovno " +"časovno vrsto in vsakim časovnim zamikom; kot procentualna sprememba; kot " +"razmerje med vrsto in časovnim zamikom." -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:82 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:325 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:497 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:310 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:374 -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:103 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:369 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:653 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:336 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:131 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:367 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:622 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:357 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:628 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:508 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:238 -#: superset/views/base.py:595 -msgid "Delete" -msgstr "Izbriši" - -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:481 -#, python-format -msgid "Delete %s?" -msgstr "Izbrišem %s?" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:153 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:344 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:227 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:477 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:220 +#: superset-frontend/src/explore/controlPanels/sections.tsx:233 +msgid "Resample" +msgstr "Prevzorči" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:296 -msgid "Delete Annotation?" -msgstr "Izbrišem oznako?" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:160 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:351 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:234 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:484 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:227 +#: superset-frontend/src/explore/controlPanels/sections.tsx:240 +msgid "Rule" +msgstr "Pravilo" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:453 -msgid "Delete Database?" -msgstr "Izbrišem podatkovno bazo?" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:172 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:361 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:244 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:487 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:239 +#: superset-frontend/src/explore/controlPanels/sections.tsx:243 +msgid "Pandas resample rule" +msgstr "Pravilo za prevzorčenje v Pandas" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:605 -msgid "Delete Dataset?" -msgstr "Izbrišem podatkovni set?" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:182 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:249 +msgid "Fill method" +msgstr "Način polnjenja" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:361 -msgid "Delete Layer?" -msgstr "Izbrišem sloj?" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:194 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:379 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:262 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:507 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:261 +#: superset-frontend/src/explore/controlPanels/sections.tsx:261 +msgid "Pandas resample method" +msgstr "Metoda za prevzorčenje v Pandas" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:485 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:261 -msgid "Delete Query?" -msgstr "Izbrišem poizvedbo?" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/annotationsAndLayers.tsx:25 +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:104 +msgid "Annotations and Layers" +msgstr "Oznake in sloji" -#: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:110 -msgid "Delete Report?" -msgstr "Izbrišem poročilo?" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:29 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:326 +msgid "Chart Title" +msgstr "Naslov grafikona" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:321 -msgid "Delete Template?" -msgstr "Izbrišem predlogo?" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:33 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:162 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:449 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:69 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:99 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:83 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:97 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:69 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:77 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:90 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:327 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:214 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:330 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:355 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:123 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:140 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:198 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:201 +#: superset-frontend/src/explore/controls.jsx:417 +msgid "X Axis" +msgstr "X os" -#: superset/views/base.py:595 -msgid "Delete all Really?" -msgstr "Ali resnično vse izbrišem?" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:39 +msgid "X Axis Title" +msgstr "Naslov X osi" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:181 -msgid "Delete annotation" -msgstr "Izbriši oznako" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:53 +msgid "X AXIS TITLE BOTTOM MARGIN" +msgstr "SPODNJA OBROBA NASLOVA X OSI" -#: superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx:202 -msgid "Delete dashboard tab?" -msgstr "Ali izbrišem zavihek nadzorne plošče?" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:61 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:168 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:456 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:79 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:111 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:115 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:80 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:109 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:256 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:351 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:249 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:332 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:358 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:160 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:176 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:233 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:236 +#: superset-frontend/src/explore/controls.jsx:424 +msgid "Y Axis" +msgstr "Y os" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:332 -msgid "Delete database" -msgstr "Izbriši podatkovno bazo" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:67 +msgid "Y Axis Title" +msgstr "Naslov Y osi" -#: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:78 -msgid "Delete email report" -msgstr "Izbriši e-poštno poročilo" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:81 +msgid "Y AXIS TITLE MARGIN" +msgstr "OBROBA NASLOVA Y OSI" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:404 -msgid "Delete query" -msgstr "Izbriši poizvedbo" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:96 +msgid "Y AXIS TITLE POSITION" +msgstr "POZICIJA NASLOVA Y OSI" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:239 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:219 -msgid "Delete template" -msgstr "Izbriši predlogo" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:36 +msgid "Predictive Analytics" +msgstr "Prediktivna analitika" -#: superset-frontend/src/dashboard/components/MissingChart.jsx:36 -msgid "Delete this container and save to remove this message." -msgstr "Izbrišite ta okvir in shranite za odpravo tega sporočila." +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:44 +msgid "Enable forecast" +msgstr "Omogoči napoved" -#: superset/annotation_layers/annotations/api.py:502 -#, python-format -msgid "Deleted %(num)d annotation" -msgid_plural "Deleted %(num)d annotations" -msgstr[0] "Izbrisana je %(num)d oznaka" -msgstr[1] "Izbrisani sta %(num)d oznaki" -msgstr[2] "Izbrisane so %(num)d oznake" -msgstr[3] "Izbrisanih je %(num)d oznak" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:47 +msgid "Enable forecasting" +msgstr "Omogoči napovedovanje" -#: superset/annotation_layers/api.py:353 -#, python-format -msgid "Deleted %(num)d annotation layer" -msgid_plural "Deleted %(num)d annotation layers" -msgstr[0] "Izbrisan je %(num)d sloj z oznakami" -msgstr[1] "Izbrisana sta %(num)d sloja z oznakami" -msgstr[2] "Izbrisanih so %(num)d sloji z oznakami" -msgstr[3] "Izbrisanih je %(num)d slojev z oznakami" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:56 +msgid "Forecast periods" +msgstr "Periode napovedi" -#: superset/charts/api.py:480 -#, python-format -msgid "Deleted %(num)d chart" -msgid_plural "Deleted %(num)d charts" -msgstr[0] "Izbrisan je %(num)d grafikon" -msgstr[1] "Izbrisana sta %(num)d grafikona" -msgstr[2] "Izbrisani so %(num)d grafikoni" -msgstr[3] "Izbrisanih je %(num)d grafikonov" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:59 +msgid "How many periods into the future do we want to predict" +msgstr "Za koliko period v prihodnosti želite napoved" -#: superset/css_templates/api.py:137 -#, python-format -msgid "Deleted %(num)d css template" -msgid_plural "Deleted %(num)d css templates" -msgstr[0] "Izbrisana %(num)d css predloga" -msgstr[1] "Izbrisani %(num)d css predlogi" -msgstr[2] "Izbrisane %(num)d css predloge" -msgstr[3] "Izbrisanih %(num)d css predlog" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:70 +msgid "Confidence interval" +msgstr "Interval zaupanja" -#: superset/dashboards/api.py:674 -#, python-format -msgid "Deleted %(num)d dashboard" -msgid_plural "Deleted %(num)d dashboards" -msgstr[0] "Izbrisana je %(num)d nadzorna plošča" -msgstr[1] "Izbrisani sta %(num)d nadzorni plošči" -msgstr[2] "Izbrisane so %(num)d nadzorne plošče" -msgstr[3] "Izbrisanih je %(num)d nadzornih plošč" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:73 +msgid "Width of the confidence interval. Should be between 0 and 1" +msgstr "Širina intervala zaupanja. Mora bit med 0 in 1" -#: superset/datasets/api.py:666 -#, python-format -msgid "Deleted %(num)d dataset" -msgid_plural "Deleted %(num)d datasets" -msgstr[0] "Izbrisan %(num)d podatkovni set" -msgstr[1] "Izbrisana %(num)d podatkovna niza" -msgstr[2] "Izbrisani %(num)d podatkovni nizi" -msgstr[3] "Izbrisanih %(num)d podatkovnih nizov" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:92 +msgid "" +"Should yearly seasonality be applied. An integer value will specify Fourier order " +"of seasonality." +msgstr "" +"Če želite letno sezonskost. Celo število določa Fourier-jev red sezonskosti." -#: superset/reports/api.py:452 -#, python-format -msgid "Deleted %(num)d report schedule" -msgid_plural "Deleted %(num)d report schedules" -msgstr[0] "Izbrisan %(num)d urnik poročanja" -msgstr[1] "Izbrisana %(num)d urnika poročanja" -msgstr[2] "Izbrisani %(num)d urniki poročanja" -msgstr[3] "Izbrisanih %(num)d urnikov poročanja" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:111 +msgid "" +"Should weekly seasonality be applied. An integer value will specify Fourier order " +"of seasonality." +msgstr "" +"Če želite tedensko sezonskost. Celo število določa Fourier-jev red sezonskosti." -#: superset/queries/saved_queries/api.py:197 -#, python-format -msgid "Deleted %(num)d saved query" -msgid_plural "Deleted %(num)d saved queries" -msgstr[0] "Izbrisana %(num)d shranjena poizvedba" -msgstr[1] "Izbrisani %(num)d shranjeni poizvedbi" -msgstr[2] "Izbrisane %(num)d shranjene poizvedbe" -msgstr[3] "Izbrisanih %(num)d shranjenih poizvedb" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:130 +msgid "" +"Should daily seasonality be applied. An integer value will specify Fourier order " +"of seasonality." +msgstr "" +"Če želite dnevno sezonskost. Celo število določa Fourier-jev red sezonskosti." -#: superset-frontend/src/reports/actions/reports.js:176 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:162 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:103 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:91 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:93 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:142 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:546 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:232 -#: superset-frontend/src/views/CRUD/utils.tsx:246 -#: superset-frontend/src/views/CRUD/utils.tsx:285 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:172 -#, python-format -msgid "Deleted: %s" -msgstr "Izbrisano: %s" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:28 +#: superset-frontend/src/explore/controlPanels/sections.tsx:27 +#: superset-frontend/src/explore/controlPanels/sections.tsx:76 +msgid "Time related form attributes" +msgstr "S časom povezani atributi prikaza" -#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:184 -msgid "Delimited long & lat single column" -msgstr "En stolpec z ločenima zemljepisno dolžino in širino" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:48 +msgid "Datasource & Chart Type" +msgstr "Tip podatkovnega vira in grafikona" -#: superset/views/database/forms.py:132 -msgid "Delimiter" -msgstr "Ločilnik" - -#: superset/views/database/forms.py:133 -msgid "Delimiter used by CSV file (for whitespace use \\s+)." -msgstr "Ločilnik, uporabljen v CSV datoteki (za presledek uporabi \\s+)." +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:58 +#: superset-frontend/src/explore/controlPanels/sections.tsx:42 +msgid "Chart ID" +msgstr "ID grafikona" -#: superset/views/schedules.py:244 superset/views/schedules.py:324 -msgid "Deliver As Group" -msgstr "Dostavi kot skupino" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:60 +#: superset-frontend/src/explore/controlPanels/sections.tsx:44 +msgid "The id of the active chart" +msgstr "Identifikator aktivnega grafikona" -#: superset/views/schedules.py:245 superset/views/schedules.py:325 -msgid "Delivery Type" -msgstr "Tip dostave" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:67 +#: superset-frontend/src/explore/controlPanels/sections.tsx:51 +msgid "Cache Timeout (seconds)" +msgstr "Trajanje predpomnilnika (sekunde)" -#: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:124 -msgid "Delivery method" -msgstr "Način dostave" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:69 +#: superset-frontend/src/explore/controlPanels/sections.tsx:53 +msgid "The number of seconds before expiring the cache" +msgstr "Trajanje (v sekundah) do razveljavitve predpomnilnika" -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:33 -msgid "Demographics" -msgstr "Demografija" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:76 +msgid "URL Parameters" +msgstr "Parametri URL" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:43 -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:38 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:45 -msgid "Density" -msgstr "Gostota" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:78 +msgid "Extra url parameters for use in Jinja templated queries" +msgstr "Dodatni parametri za poizvedbe z Jinja predlogami" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:55 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:38 -msgid "Deprecated" -msgstr "Zastarelo" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:87 +msgid "Extra Parameters" +msgstr "Dodatni parametri" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:42 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:47 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:51 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:44 -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:131 -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:163 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:202 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:206 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:692 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1050 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1054 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:52 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:994 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:243 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1100 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1106 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:147 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:157 -#: superset/connectors/druid/views.py:188 -#: superset/connectors/druid/views.py:345 superset/connectors/sqla/views.py:145 -#: superset/connectors/sqla/views.py:256 superset/connectors/sqla/views.py:502 -#: superset/views/annotations.py:78 superset/views/annotations.py:126 -#: superset/views/chart/mixin.py:81 superset/views/sql_lab.py:71 -msgid "Description" -msgstr "Opis" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:89 +msgid "" +"Extra parameters that any plugins can choose to set for use in Jinja templated " +"queries" +msgstr "" +"Dodatni parametri, ki jih lahko uporabi kateri koli vtičnik za poizvedbe z Jinja " +"predlogami" -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:331 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:262 -msgid "Description (this can be seen in the list)" -msgstr "Opis (lahko je viden na seznamu)" +#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:99 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:525 +msgid "Color Scheme" +msgstr "Barvna shema" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:520 -msgid "Description Columns" -msgstr "Stolpci z opisi" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:34 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:74 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:116 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:428 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:128 +#: superset-frontend/src/explore/controls.jsx:123 +#: superset-frontend/src/explore/controls.jsx:396 +msgid "Dimensions" +msgstr "Dimenzije" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:48 -msgid "Description text that shows up below your Big Number" -msgstr "Besedilo, ki se prikaže pod veliko številko" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:36 +#: superset-frontend/src/explore/controls.jsx:126 +msgid "" +"One or many columns to group by. High cardinality groupings should include a " +"series limit to limit the number of fetched and rendered series." +msgstr "" +"Eden ali več stolpcev za združevanje. Združevanje z visoko kardinalnostjo naj " +"vsebuje omejitev serij, s čimer omejite število pridobljenih in prikazanih serij." -#: superset-frontend/src/components/ListView/ListView.tsx:348 -msgid "Deselect all" -msgstr "Počisti izbor" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:69 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:239 +msgid "One or many columns to pivot as columns" +msgstr "En ali več stolpcev za stolpčno vrtenje" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:271 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1081 -msgid "Details of the certification" -msgstr "Podrobnosti certifikacije" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:77 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:431 +#: superset-frontend/src/explore/controls.jsx:399 +msgid "" +"Defines the grouping of entities. Each series is shown as a specific color on the " +"chart and has a legend toggle" +msgstr "" +"Določa združevanje entitet. Vsak niz je na grafikonu prikazan z določeno barvo in " +"ima lahko prikazano legendo" -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:53 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:47 -msgid "Determines how whiskers and outliers are calculated." -msgstr "Določa kako so izračunani kvantili in izstopajoče vrednosti." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:86 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:440 +#: superset-frontend/src/explore/controls.jsx:408 +msgid "Entity" +msgstr "Entiteta" -#: superset/views/dashboard/mixin.py:71 -msgid "" -"Determines whether or not this dashboard is visible in the list of all " -"dashboards" -msgstr "Določa ali je nadzorna plošča vidna na seznamu vseh nadzornih plošč" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:90 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:444 +#: superset-frontend/src/explore/controls.jsx:412 +msgid "This defines the element to be plotted on the chart" +msgstr "Določa element, ki bo izrisan na grafikonu" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:230 -msgid "Diamond" -msgstr "Karo" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:122 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:165 +#: superset-frontend/src/explore/controls.jsx:162 +msgid "One or many metrics to display" +msgstr "Ena ali več mer za prikaz" -#: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:77 -msgid "Did you mean:" -msgstr "Ste mislili:" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:134 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:204 +msgid "Right Axis Metric" +msgstr "Mera desne osi" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:101 -msgid "Difference" -msgstr "Razlika" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:135 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:206 +#: superset-frontend/src/explore/controls.jsx:217 +msgid "Choose a metric for right axis" +msgstr "Izberite mero za desno os" -#: superset/viz.py:1968 -msgid "Directed Force Layout" -msgstr "Izgled usmerjene sile" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:140 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:412 +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:307 +#: superset-frontend/src/explore/controls.jsx:380 +msgid "Sort by" +msgstr "Razvrščanje" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:39 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:42 -msgid "Directional" -msgstr "Usmerjeni" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:142 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:414 +#: superset-frontend/src/explore/controls.jsx:383 +msgid "" +"Metric used to define how the top series are sorted if a series or row limit is " +"present. If undefined reverts to the first metric (where appropriate)." +msgstr "" +"Mera, ki določa kako so razvrščene prve serije, če je določena omejitev serij ali " +"vrstic. Če ni določena, se uporabi prva mera (kjer je ustrezno)." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:165 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:185 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:274 -msgid "Disabled" -msgstr "Onemogočeno" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:156 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:463 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:138 +msgid "Bubble Size" +msgstr "Velikost mehurčka" -#: superset-frontend/src/dashboard/components/Header/index.jsx:579 -msgid "Discard changes" -msgstr "Zavrzi spremembe" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:157 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:464 +msgid "Metric used to calculate bubble size" +msgstr "Mera za izračun velikosti mehurčkov" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:43 -msgid "Discrete" -msgstr "Diskretno" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:163 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:450 +#: superset-frontend/src/explore/controls.jsx:418 +msgid "Metric assigned to the [X] axis" +msgstr "Mera za [X] os" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:149 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:42 -msgid "Display Name" -msgstr "Ime za prikaz" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:169 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:458 +#: superset-frontend/src/explore/controls.jsx:426 +msgid "Metric assigned to the [Y] axis" +msgstr "Mera za [Y] os" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:164 -msgid "Display column level total" -msgstr "Prikaži vsote na nivoju stolpcev" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:174 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:230 +msgid "Color Metric" +msgstr "Mera za barvo" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:615 -msgid "Display configuration" -msgstr "Prikaži nastavitve" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:176 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:233 +#: superset-frontend/src/explore/controls.jsx:238 +msgid "A metric to use for color" +msgstr "Mera za barvo" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:98 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:187 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:182 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:290 +#: superset-frontend/src/explore/controls.jsx:297 msgid "" -"Display metrics side by side within each column, as opposed to each " -"column being displayed side by side for each metric." +"The time column for the visualization. Note that you can define arbitrary " +"expression that return a DATETIME column in the table. Also note that the filter " +"below is applied against this column or expression" msgstr "" -"Prikazuj mere eno ob drugi ob vsakem stolpcu, drugače je vsak stolpec " -"prikazan en ob drugem za vsako mero." +"Časovni stolpec za vizualizacijo. Določite lahko poljuben izraz, ki vrne DATETIME " +"stolpec v tabeli. Spodnji filter se nanaša na ta stolpec ali izraz" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:152 -msgid "Display row level total" -msgstr "Prikaži vsote na nivoju vrstic" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:191 +msgid "Drop temporal column here" +msgstr "Spustite časovni stolpec sem" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:89 -msgid "Display total row/column" -msgstr "Pokaži vsote vrstic/stolpcev" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx:30 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx:33 +msgid "Enable dashboard cross filters" +msgstr "Omogoči medsebojne filtre nadzorne plošče" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:34 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:122 msgid "" -"Displays connections between entities in a graph structure. Useful for " -"mapping relationships and showing which nodes are important in a network." -" Graph charts can be configured to be force-directed or circulate. If " -"your data has a geospatial component, try the deck.gl Arc chart." +"One or many columns to group by. High cardinality groupings should include a sort " +"by metric and series limit to limit the number of fetched and rendered series." msgstr "" -"Prikaže povezave med entitetami v strukturi grafa. Uporabno za prikaz " -"razmerij in pomembnih točk v omrežju. Grafikon je lahko krožnega tipa ali" -" z usmerjenimi silami. Če imajo podatki geoprostorsko komponento, " -"poskusite grafikon decl.gl - Arc." +"Eden ali več stolpcev za združevanje. Združevanje z visoko kardinalnostjo naj " +"vsebuje mero za razvrščanje in omjitev serij, s čimer omejite število " +"pridobljenih in prikazanih serij." -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:132 -msgid "Distribute across" -msgstr "Porazdeli glede na" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:191 +#: superset-frontend/src/explore/controls.jsx:202 +msgid "The type of visualization to display" +msgstr "Tip vizualizacije za prikaz" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:28 -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:26 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:48 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/createMetadata.ts:25 -msgid "Distribution" -msgstr "Porazdelitev" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:196 +msgid "Fixed Color" +msgstr "Izbrana barva" -#: superset/viz.py:1769 -msgid "Distribution - Bar Chart" -msgstr "Porazdelitev - Stolpčni grafikon" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:197 +#: superset-frontend/src/explore/controls.jsx:207 +msgid "Use this to define a static color for all circles" +msgstr "S tem definirate določeno barvo za vse kroge" -#: superset-frontend/src/dashboard/components/gridComponents/new/NewDivider.jsx:31 -msgid "Divider" -msgstr "Ločilnik" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:211 +msgid "Linear Color Scheme" +msgstr "Linearna barvna shema" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:86 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:211 -msgid "Do you want a donut or a pie?" -msgstr "Želite kolobar ali torto?" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:251 +#: superset-frontend/src/explore/controls.jsx:258 +msgid "" +"Defines the origin where time buckets start, accepts natural dates as in `now`, " +"`sunday` or `1970-01-01`" +msgstr "" +"Določa izhodišče, kadar se začnejo časovni razdelki. Sprejema naravne zapise kot " +"so `zdaj`, `nedelja` ali `1970-01-01`" -#: superset-frontend/src/components/Menu/MenuRight.tsx:214 -msgid "Documentation" -msgstr "Dokumentacija" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:280 +#: superset-frontend/src/explore/controls.jsx:287 +msgid "" +"The time granularity for the visualization. Note that you can type and use simple " +"natural language as in `10 seconds`, `1 day` or `56 weeks`" +msgstr "" +"Granulacija časa za vizualizacijo. Uporabite lahko vnos z naravnim jezikom, kot " +"npr. `10 sekund`, `1 dni` ali `56 tednov`" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:40 -msgid "Domain" -msgstr "Domena" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:329 +#: superset-frontend/src/explore/controls.jsx:326 +msgid "" +"The time granularity for the visualization. This applies a date transformation to " +"alter your time column and defines a new time granularity. The options here are " +"defined on a per database engine basis in the Superset source code." +msgstr "" +"Granulacija časa za to vizualizacijo. Izvede transformacijo podatkov, ki spremeni " +"vaš časovni stolpec in določi novo časovno granulacija. Ta možnost je definirana " +"na ravni sistema podatkovne baze v izvorni kodi Superseta." -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:29 -msgid "Don't refresh" -msgstr "Ne osvežuj" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:345 +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:35 +#: superset-frontend/src/explore/controls.jsx:342 +msgid "No filter" +msgstr "Brez filtra" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:83 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:208 -msgid "Donut" -msgstr "Kolobar" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:346 +#: superset-frontend/src/explore/controls.jsx:343 +msgid "" +"The time range for the visualization. All relative times, e.g. \"Last month\", " +"\"Last 7 days\", \"now\", etc. are evaluated on the server using the server's " +"local time (sans timezone). All tooltips and placeholder times are expressed in " +"UTC (sans timezone). The timestamps are then evaluated by the database using the " +"engine's local timezone. Note one can explicitly set the timezone per the ISO " +"8601 format if specifying either the start and/or end time." +msgstr "" +"Časovno obdobje za vizualizacijo. Vsi relativni časi, kot npr. \"Zadnji mesec\", " +"Zadnjih 7 dni\", \"Zdaj\" so izračunani na strežniku z njegovim lokalnim časom. " +"Vsi opisi orodij in časi so izraženi v UTC. Časovne značke se nato izračunajo v " +"podatkovni bazi z njenim lokalnim časovnim pasom. Eksplicitno lahko nastavite " +"časovni pas v ISO 8601 formatu, če določite čas začetka ali konca." + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:362 +#: superset-frontend/src/explore/controls.jsx:356 +msgid "Row limit" +msgstr "Omejitev števila vrstic" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:319 -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:328 -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:105 -msgid "Download as image" -msgstr "Izvozi kot sliko" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:366 +#: superset-frontend/src/explore/controls.jsx:360 +msgid "Limits the number of rows that get displayed." +msgstr "Omeji število vrstic za prikaz." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:543 -msgid "Download to CSV" -msgstr "Izvozi kot CSV" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:371 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:111 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:124 +msgid "Sort Descending" +msgstr "Razvrsti padajoče" -#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:72 -#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:83 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:301 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:499 -msgid "Draft" -msgstr "Osnutek" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:373 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:113 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/orderBy.tsx:47 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:126 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:357 +msgid "Whether to sort descending or ascending" +msgstr "Če želite padajoče ali naraščajoče razvrščanje" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:214 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:152 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:113 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:93 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:110 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:168 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:171 -msgid "Draw a marker on data points. Only applicable for line types." -msgstr "Nariši markerje na točke grafikona. Samo za črtne grafikone." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:384 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:399 +#: superset-frontend/src/explore/controls.jsx:366 +msgid "Series limit" +msgstr "Omejitev števila serij" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:171 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:135 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:138 -msgid "Draw area under curves. Only applicable for line types." -msgstr "Izriši površino pod krivuljo. Samo za črtne grafikone." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:388 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:402 +#: superset-frontend/src/explore/controls.jsx:370 +msgid "" +"Limits the number of series that get displayed. A joined subquery (or an extra " +"phase where subqueries are not supported) is applied to limit the number of " +"series that get fetched and rendered. This feature is useful when grouping by " +"high cardinality column(s) though does increase the query complexity and cost." +msgstr "" +"Omeji število časovnih vrst za prikaz. S podpoizvedbo (ali dodatno fazo, kjer " +"podpoizvedbe niso podprte) se omeji število časovnih vrst, ki bodo pridobljene za " +"prikaz. Ta funkcija je uporabna pri združevanju s stolpci z veliko " +"kardinalnostjo, vendar poveča kompleksnost poizvedbe." -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:178 -msgid "Draw line from Pie to label when labels outside?" -msgstr "Ali želite črto do oznake, ko so le-te zunaj?" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:472 +#: superset-frontend/src/explore/controls.jsx:438 +msgid "Y Axis Format" +msgstr "Oblika Y osi" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:331 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:246 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:209 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:189 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:206 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:262 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:265 -msgid "Draw split lines for minor y-axis ticks" -msgstr "Izriši ločilne črte za pomožne oznake y-osi" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:497 +msgid "Time format" +msgstr "Oblika zapisa časa" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:217 -msgid "Drop a column here or click" -msgstr "Spustite stolpec sem ali kliknite" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:529 +#: superset-frontend/src/explore/controls.jsx:480 +msgid "The color scheme for rendering chart" +msgstr "Barvna shema za izris grafikona" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:367 -msgid "Drop a column/metric here or click" -msgstr "Spustite stolpec/mero sem ali kliknite" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:538 +msgid "Truncate Metric" +msgstr "Odstrani mero" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:222 -msgid "Drop column here" -msgstr "Spustite stolpec sem" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:540 +msgid "Whether to truncate metrics" +msgstr "Če želite odstraniti naziv mere" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:372 -msgid "Drop column or metric here" -msgstr "Spustite stolpec ali mero sem" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/legacySortBy.tsx:29 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/orderBy.tsx:45 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:355 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1008 +msgid "Sort descending" +msgstr "Razvrsti padajoče" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx:80 -msgid "Drop columns here" -msgstr "Spustite stolpce sem" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/legacySortBy.tsx:31 +msgid "" +"Whether to sort descending or ascending. Takes effect only when \"Sort by\" is set" +msgstr "" +"Če želite padajoče ali naraščajoče razvrščanje. Učinkuje samo, ko je vključen " +"\"Sort by\"" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx:389 -msgid "Drop columns or metrics here" -msgstr "Spustite stolpce ali mere sem" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx:168 +msgid "Show less columns" +msgstr "Prikaži manj stolpcev" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx:388 -msgid "Drop columns/metrics here or click" -msgstr "Spustite stolpce/mere sem ali kliknite" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx:173 +msgid "Show all columns" +msgstr "Prikaži vse stolpce" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:176 -msgid "Drop temporal column here" -msgstr "Spustite časovni stolpec sem" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:47 +msgid "Emit Target" +msgstr "Cilj oddajanja" -#: superset/connectors/druid/views.py:213 -#: superset/initialization/__init__.py:516 -msgid "Druid Clusters" -msgstr "Druid gruče" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:48 +msgid "" +"If you wish to specify a different target column than the original column, it can " +"be entered here" +msgstr "" +"Če želite nastaviti drug ciljni stolpec od izvornega, ga lahko vnesete tukaj" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:58 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:69 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1215 +msgid "D3 format" +msgstr "D3 format" -#: superset/connectors/druid/views.py:192 -msgid "Druid Datasource" -msgstr "Podatkovni vir Druid" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:80 +msgid "Fraction digits" +msgstr "Število decimalk" + +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:81 +msgid "Number of decimal digits to round numbers to" +msgstr "Število decimalnih mest za zaokroževanje števil" -#: superset/connectors/druid/views.py:277 -#: superset/initialization/__init__.py:507 -msgid "Druid Datasources" -msgstr "Druid podatkovni viri" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:90 +msgid "Min Width" +msgstr "Min. širina" -#: superset/connectors/druid/views.py:248 -#: superset/connectors/druid/views.py:253 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:91 msgid "" -"Druid supports basic authentication. See " -"[auth](http://druid.io/docs/latest/design/auth.html) and druid-basic-" -"security extension" +"Default minimal column width in pixels, actual width may still be larger than " +"this if other columns don't need much space" msgstr "" -"Druid podpira osnovno avtentikacijo. Glejte " -"[auth](http://druid.io/docs/latest/design/auth.html) in razširitev druid-" -"basic-security" +"Privzeta min. širina stolpca v pikslih. Dejanska širina bo lahko večja, če drugi " +"stolpci ne potrebujejo veliko prostora" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:30 -msgid "Dual Line Chart" -msgstr "Grafikon z dvojno krivuljo" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:105 +msgid "Text align" +msgstr "Poravnava besedila" -#: superset/views/datasource/views.py:119 -#, python-format -msgid "Duplicate column name(s): %(columns)s" -msgstr "Podvojena imena stolpcev: %(columns)s" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:106 +msgid "Horizontal alignment" +msgstr "Vodoravna poravnava" -#: superset/common/query_object.py:284 -#, python-format -msgid "" -"Duplicate column/metric labels: %(labels)s. Please make sure all columns " -"and metrics have a unique label." -msgstr "" -"Podvojene oznake stolpcev/mer: %(labels)s. Poskrbite, da bodo imeli " -"stolpci in mere unikatne oznake." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:111 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:334 +msgid "Left" +msgstr "Levo" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:366 -msgid "Duplicate tab" -msgstr "Podvoji zavihek" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:112 +msgid "Center" +msgstr "Na sredino" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:135 -msgid "Duration" -msgstr "Trajanje" +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:113 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:335 +msgid "Right" +msgstr "Desno" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:227 -#: superset/views/database/mixins.py:175 -msgid "" -"Duration (in seconds) of the caching timeout for charts of this database." -" A timeout of 0 indicates that the cache never expires. Note this " -"defaults to the global timeout if undefined." -msgstr "" -"Trajanje (v sekundah) predpomnjenja za grafikon v tej podatkovni bazi. " -"Vrednost 0 označuje, da predpomnilnik nikoli ne poteče. V primeru, da ni " -"definirano, ima globalno nastavitev." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:119 +msgid "Show cell bars" +msgstr "Prikaži stolp. graf v celicah" -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:282 -msgid "" -"Duration (in seconds) of the caching timeout for this chart. Note this " -"defaults to the dataset's timeout if undefined." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:120 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:435 +msgid "Whether to display a bar chart background in table columns" msgstr "" -"Časovna veljavnost (v sekundah) predpomnjenja za ta grafikon. Če ni " -"definirana, je uporabljena vrednost za podatkovni set." +"Če želite omogočiti prikaz manjših stolpčnih grafikonov v ozadju stolpcev tabele" -#: superset/views/chart/mixin.py:70 -msgid "" -"Duration (in seconds) of the caching timeout for this chart. Note this " -"defaults to the datasource/table timeout if undefined." -msgstr "" -"Časovna veljavnost (v sekundah) predpomnjenja za ta grafikon. Če ni " -"definirana, je uporabljena vrednost za podatkovni vir/tabelo." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:127 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:446 +msgid "Align +/-" +msgstr "Poravnaj +/-" -#: superset/connectors/druid/views.py:243 -msgid "" -"Duration (in seconds) of the caching timeout for this cluster. A timeout " -"of 0 indicates that the cache never expires. Note this defaults to the " -"global timeout if undefined." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:128 +msgid "Whether to align positive and negative values in cell bar chart at 0" msgstr "" -"Trajanje (v sekundah) predpomnjenja za to gručo. Vrednost 0 označuje, da " -"predpomnilnik nikoli ne poteče. V primeru, da ni definirano, ima globalno" -" nastavitev trajanja." +"Če želite poravnati pozitivne in negativne vrednosti v stolpčnem grafikonu celic " +"pri 0" -#: superset/connectors/druid/views.py:334 -msgid "" -"Duration (in seconds) of the caching timeout for this datasource. A " -"timeout of 0 indicates that the cache never expires. Note this defaults " -"to the cluster timeout if undefined." -msgstr "" -"Trajanje (v sekundah) predpomnjenja za ta podatkovni vir. Vrednost 0 " -"označuje, da predpomnilnik nikoli ne poteče. V primeru, da ni definirano," -" ima nastavitev trajanja za gručo." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:137 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:458 +msgid "Color +/-" +msgstr "Barva +/-" -#: superset/connectors/sqla/views.py:473 -msgid "" -"Duration (in seconds) of the caching timeout for this table. A timeout of" -" 0 indicates that the cache never expires. Note this defaults to the " -"database timeout if undefined." -msgstr "" -"Trajanje (v sekundah) predpomnjenja za to tabelo. Vrednost 0 označuje, da" -" predpomnilnik nikoli ne poteče. V primeru, da ni definirano, ima " -"nastavitev trajanja za podatkovno bazo." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:138 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:461 +msgid "Whether to colorize numeric values by if they are positive or negative" +msgstr "Če želite obarvati številske vrednosti, ko so le-te pozitivne ali negativne" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:250 -msgid "" -"Duration (in seconds) of the metadata caching timeout for schemas of this" -" database. If left unset, the cache never expires." -msgstr "" -"Trajanje (v sekundah) predpomnilnika metapodatkov za sheme v tej " -"podatkovni bazi. Če ni nastavljeno, predpomnilnik ne poteče." +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:153 +msgid "Small number format" +msgstr "Oblika zapisa majhnih števil" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:272 +#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:154 msgid "" -"Duration (in seconds) of the metadata caching timeout for tables of this " -"database. If left unset, the cache never expires. " +"D3 number format for numbers between -1.0 and 1.0, useful when you want to have " +"different siginificant digits for small and large numbers" msgstr "" -"Trajanje (v sekundah) predpomnilnika metapodatkov za tabele v tej " -"podatkovni bazi. Če ni nastavljeno, predpomnilnik ne poteče. " +"D3 oblika zapisa za števila med -1.0 in 1.0. Uporabno, če želite različno število " +"števk za majhna in velika števila" -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:41 -msgid "Duration in ms (1.40008 => 1ms 400µs 80ns)" -msgstr "Trajanje v ms (1.40008 => 1ms 400µs 80ns)" +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:22 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:149 +msgid "D3 format syntax: https://github.com/d3/d3-format" +msgstr "Sintaksa D3 formata: https://github.com/d3/d3-format" + +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:28 +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:51 +msgid "Adaptive formatting" +msgstr "Adaptivno oblikovanje" -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:40 +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:42 msgid "Duration in ms (66000 => 1m 6s)" msgstr "Trajanje v ms (66000 => 1m 6s)" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:205 -#, python-format -msgid "Duration: %s" -msgstr "Trajanje: %s" - -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:55 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:47 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:43 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:71 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:61 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:77 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:77 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:71 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:71 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:62 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:42 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:61 -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:124 -msgid "ECharts" -msgstr "ECharts" +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:43 +msgid "Duration in ms (1.40008 => 1ms 400µs 80ns)" +msgstr "Trajanje v ms (1.40008 => 1ms 400µs 80ns)" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:76 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:169 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:176 -msgid "END (EXCLUSIVE)" -msgstr "KONEC (NI VKLJUČEN)" +#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:46 +msgid "D3 time format syntax: https://github.com/d3/d3-time-format" +msgstr "Sintaksa D3 časovnega formata:: https://github.com/d3/d3-time-format" -#: superset-frontend/src/views/CRUD/hooks.ts:628 -#, python-format -msgid "ERROR: %s" +#: superset-frontend/packages/superset-ui-core/src/chart/components/NoResultsComponent.tsx:65 +msgid "" +"No results were returned for this query. If you expected results to be returned, " +"ensure any filters are configured properly and the datasource contains data for " +"the selected time range." msgstr "" +"Poizvedba ni vrnila rezultatov. Če ste pričakovali rezultate, poskrbite, da so " +"filtri pravilno nastavljeni in podatkovni vir vsebuje podatke za izbrano časovno " +"obdobje." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:241 -msgid "Edge length" -msgstr "Dolžina povezave" - -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:247 -msgid "Edge length between nodes" -msgstr "Dolžina povezave med vozlišči" - -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:124 -msgid "Edge symbols" -msgstr "Simboli povezav" +#: superset-frontend/packages/superset-ui-core/src/chart/components/NoResultsComponent.tsx:78 +msgid "No Results" +msgstr "Ni rezultatov" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:226 -msgid "Edge width" -msgstr "Debelina povezave" +#: superset-frontend/packages/superset-ui-core/src/query/extractQueryFields.ts:130 +msgid "Found invalid orderby options" +msgstr "Najdene so neveljavne možnosti razvrščanja" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:197 -#: superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.tsx:35 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:75 -#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:121 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:316 -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:128 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:404 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:85 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:401 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:358 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:389 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:219 -msgid "Edit" -msgstr "Urejanje" +#: superset-frontend/packages/superset-ui-core/src/validator/legacyValidateInteger.ts:31 +#: superset-frontend/packages/superset-ui-core/src/validator/validateInteger.ts:32 +msgid "is expected to be an integer" +msgstr "pričakovano je celo število" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1053 -#, fuzzy -msgid "Edit Alert" -msgstr "Uredi tabelo" +#: superset-frontend/packages/superset-ui-core/src/validator/legacyValidateNumber.ts:28 +#: superset-frontend/packages/superset-ui-core/src/validator/validateNumber.ts:32 +msgid "is expected to be a number" +msgstr "pričakovano je število" -#: superset/views/annotations.py:61 -msgid "Edit Annotation" -msgstr "Uredi oznako" +#: superset-frontend/packages/superset-ui-core/src/validator/validateNonEmpty.ts:29 +msgid "cannot be empty" +msgstr "ne sme biti prazno" -#: superset/views/annotations.py:120 -msgid "Edit Annotation Layer" -msgstr "Uredi sloj z oznakami" +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:32 +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:26 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:32 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:90 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:65 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:60 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:30 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:26 +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:26 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:36 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:33 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:34 +#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:26 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:26 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:30 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:31 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:31 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:63 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:44 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts:39 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:40 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts:41 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:56 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:39 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:44 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:26 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:60 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:158 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:341 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:29 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:32 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:34 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:34 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:34 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:48 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:63 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:62 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:269 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:53 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:54 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:60 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:61 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:42 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:38 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx:56 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:42 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:185 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:26 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:30 +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:62 +#: superset-frontend/src/explore/controlPanels/sections.tsx:104 +#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:34 +#: superset-frontend/src/filters/components/Range/controlPanel.ts:31 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:41 +#: superset-frontend/src/filters/components/Time/controlPanel.ts:29 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:178 +#: superset-frontend/src/visualizations/TimeTable/controlPanel.js:26 +msgid "Query" +msgstr "Poizvedba" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:309 -msgid "Edit CSS" -msgstr "Uredi CSS" +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:40 +msgid "Domain" +msgstr "Domena" -#: superset/views/css_templates.py:39 -msgid "Edit CSS Template" -msgstr "Uredi CSS predlogo" +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:49 +msgid "The time unit used for the grouping of blocks" +msgstr "Časovna enota za združevanje blokov" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:231 -msgid "Edit CSS template properties" -msgstr "Uredi lastnosti CSS predloge" +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:56 +msgid "Subdomain" +msgstr "Poddomena" -#: superset/views/chart/mixin.py:29 -msgid "Edit Chart" -msgstr "Uredi grafikon" +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:65 +msgid "" +"The time unit for each block. Should be a smaller unit than domain_granularity. " +"Should be larger or equal to Time Grain" +msgstr "" +"Časovna enota za vsak blok. Mora biti manjša enota kot domenska_granulacija. Mora " +"biti večja ali enaka Granulaciji časa" -#: superset/connectors/sqla/views.py:66 -msgid "Edit Column" -msgstr "Uredi stolpec" +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:77 +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:49 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:75 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:53 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:132 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:57 +#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:36 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:65 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:53 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:42 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:84 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:77 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:31 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:40 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:69 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:35 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:39 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:57 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:125 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:69 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:73 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:74 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:308 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:72 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:98 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:337 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:73 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:90 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:96 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:97 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:61 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:35 +#: superset-frontend/src/explore/fixtures.tsx:33 +#: superset-frontend/src/explore/fixtures.tsx:76 +#: superset-frontend/src/explore/fixtures.tsx:85 +msgid "Chart Options" +msgstr "Možnosti grafikona" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:91 +msgid "Cell Size" +msgstr "Velikost celice" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:92 +msgid "The size of the square cell, in pixels" +msgstr "Velikost kvadratne celice v pikslih" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:103 +msgid "Cell Padding" +msgstr "Razmak med celicami" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:104 +msgid "The distance between cells, in pixels" +msgstr "Razdalja med celicami v pikslih" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:117 +msgid "Cell Radius" +msgstr "Polmer celice" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:118 +msgid "The pixel radius" +msgstr "Polmer piksla" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:129 +msgid "Color Steps" +msgstr "Barvni koraki" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:130 +msgid "The number color \"steps\"" +msgstr "Število barvnih korakov" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:141 +msgid "Time Format" +msgstr "Oblika zapisa časa" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:154 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:275 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:129 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:149 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:104 +msgid "Legend" +msgstr "Legenda" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:157 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:278 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:132 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:152 +msgid "Whether to display the legend (toggles)" +msgstr "Preklapljanje prikaza legende" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:164 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:301 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:197 +msgid "Show Values" +msgstr "Pokaži vrednosti" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:167 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:304 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:200 +msgid "Whether to display the numerical values within the cells" +msgstr "Če želite v celicah prikazati numerične vrednosti" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:178 +msgid "Show Metric Names" +msgstr "Pokaži imena mer" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:181 +msgid "Whether to display the metric name as a title" +msgstr "Če želite prikazati ime mere kot naslov" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:191 +msgid "Number Format" +msgstr "Oblika zapisa števila" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:25 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:28 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:25 +msgid "Correlation" +msgstr "Korelacija" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:27 +msgid "" +"Visualizes how a metric has changed over a time using a color scale and a " +"calendar view. Gray values are used to indicate missing values and the linear " +"color scheme is used to encode the magnitude of each day's value." +msgstr "" +"Prikaže kako se je mera spreminjala s časom s pomočjo barvne lestvice in " +"koledarskega pogleda. Sive vrednosti ponazarjajo manjkajoče vrednosti. Amplituda " +"dnevnih vrednosti je ponazorjena z linearno barvno shemo." + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:32 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:40 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:35 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:40 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:54 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:45 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:55 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:44 +msgid "Business" +msgstr "Aktivnost" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:33 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:33 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:37 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:35 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:35 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:34 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:43 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:35 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:46 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:68 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:56 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:60 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:43 +#: superset-frontend/src/visualizations/TimeTable/index.ts:32 +msgid "Comparison" +msgstr "Primerjava" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:34 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:41 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:36 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:38 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:39 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:36 +msgid "Intensity" +msgstr "Intenzivnost" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:35 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:35 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:46 +msgid "Pattern" +msgstr "Vzorec" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:36 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:45 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:57 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:48 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:59 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:48 +msgid "Report" +msgstr "Poročilo" + +#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:37 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:37 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:53 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:40 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:38 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:40 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:45 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:59 +#: superset-frontend/src/visualizations/TimeTable/index.ts:37 +msgid "Trend" +msgstr "Trend" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:39 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:94 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:55 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:63 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:63 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:64 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:62 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:49 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:38 +msgid "Sort by metric" +msgstr "Mera za razvrščanje" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:40 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:95 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:56 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:44 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:64 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:64 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:65 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:63 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:50 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:39 +msgid "Whether to sort results by the selected metric in descending order." +msgstr "Če želite padajoče razvrstiti rezultate z izbrano mero." + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:56 +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:64 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:143 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:118 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:67 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:67 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:66 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:96 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:270 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:99 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:112 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:148 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:120 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:137 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:113 +msgid "Number format" +msgstr "Oblika zapisa števila" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:57 +msgid "Choose a number format" +msgstr "Izberite obliko zapisa števila" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:60 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:52 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1346 +msgid "Source" +msgstr "Izvor" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:63 +msgid "Choose a source" +msgstr "Izberite izvor" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:66 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:62 +msgid "Target" +msgstr "Cilj" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:69 +msgid "Choose a target" +msgstr "Izberite cilj" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:26 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:24 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:27 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:32 +msgid "Flow" +msgstr "Potek" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:28 +msgid "" +"Showcases the flow or link between categories using thickness of chords. The " +"value and corresponding thickness can be different for each side." +msgstr "" +"Prikaže potek ali povezave med kategorijami z debelino tetiv. Vrednost in " +"debelina sta lahko različni za vsako stran." + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:32 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:35 +msgid "Relationships between community channels" +msgstr "Razmerja med skupnostnimi kanali" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:34 +msgid "Chord Diagram" +msgstr "Tetivni grafikon" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:36 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:44 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:39 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:65 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:78 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:86 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:73 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:70 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:58 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:41 +msgid "Aesthetic" +msgstr "Estetika" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:37 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:33 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:112 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:40 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:67 +msgid "Circular" +msgstr "Krožno" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:38 +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:30 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:42 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:33 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:37 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:31 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:31 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:40 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:43 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:39 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:47 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:35 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:32 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:42 +#: superset-frontend/src/visualizations/TimeTable/index.ts:33 +msgid "Legacy" +msgstr "Staro" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:39 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:42 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:46 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:50 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:71 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:64 +msgid "Proportional" +msgstr "Proporcionalno" + +#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:40 +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:43 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:33 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:44 +msgid "Relational" +msgstr "Relacijsko" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:40 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:119 +msgid "Country" +msgstr "Država" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:43 +msgid "Which country to plot the map for?" +msgstr "Za katero državo želite grafikon?" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:78 +msgid "ISO 3166-2 Codes" +msgstr "Oznake po ISO 3166-2" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:79 +msgid "" +"Column containing ISO 3166-2 codes of region/province/department in your table." +msgstr "" +"Stolpec, ki vsebuje ISO 3166-2 oznake regij/provinc/departmajev v vaši tabeli." + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:85 +msgid "Metric to display bottom title" +msgstr "Mera za prikaz spodnjega naslova" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:25 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:26 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:27 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:27 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:78 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts:64 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts:50 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:51 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts:67 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:94 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:63 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:50 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:25 +msgid "Map" +msgstr "Zemljevid" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:27 +msgid "" +"Visualizes how a single metric varies across a country's principal subdivisions " +"(states, provinces, etc) on a chloropleth map. Each subdivision's value is " +"elevated when you hover over the corresponding geographic boundary." +msgstr "" +"Prikaže kako se posamezna mera spreminja glede na območja države (dežele, " +"province, itd.) na kloropletnem zemljevidu. Vsak podrazdelek se dvigne, ko z " +"miško preidete mejo njegovega območja." -#: superset/views/dashboard/mixin.py:28 -msgid "Edit Dashboard" -msgstr "Uredi nadzorno ploščo" +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:32 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:35 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:37 +msgid "2D" +msgstr "2D" -#: superset/views/database/mixins.py:36 -msgid "Edit Database" -msgstr "Uredi podatkovno bazo" +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:34 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:37 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:38 +msgid "Geo" +msgstr "Geo" -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:192 -msgid "Edit Dataset " -msgstr "Uredi podatkovni set " +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:35 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 +msgid "Range" +msgstr "Doseg" + +#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:37 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:51 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:41 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:48 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:89 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:76 +msgid "Stacked" +msgstr "Naložen" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/EventFlow.tsx:50 +msgid "Sorry, there appears to be no data" +msgstr "Ni podatkov" -#: superset/connectors/druid/views.py:216 -msgid "Edit Druid Cluster" -msgstr "Uredi Druid gručo" +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:36 +msgid "Event definition" +msgstr "Definicija dogodka" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:44 +msgid "Event Names" +msgstr "Imena dogodkov" -#: superset/connectors/druid/views.py:73 -msgid "Edit Druid Column" -msgstr "Uredi Druid stolpec" +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:45 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:54 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:39 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:63 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:105 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:129 +#: superset-frontend/src/explore/fixtures.tsx:98 +msgid "Columns to display" +msgstr "Stolpci za prikaz" -#: superset/connectors/druid/views.py:280 -msgid "Edit Druid Datasource" -msgstr "Uredi podatkovni vir za Druid" +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:62 +msgid "Order by entity id" +msgstr "Uredi po ID entitete" -#: superset/connectors/druid/views.py:162 -msgid "Edit Druid Metric" -msgstr "Uredi Druid mere" +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:63 +msgid "" +"Important! Select this if the table is not already sorted by entity id, else " +"there is no guarantee that all events for each entity are returned." +msgstr "" +"Pomembno! Izberite, če tabela še ni razvrščena po ID entitete, v nasprotnem " +"primeru ni nujno, da bodo vrnjeni vsi dogodki za posamezno entiteto." -#: superset-frontend/src/components/ReportModal/index.tsx:251 -msgid "Edit Email Report" -msgstr "Uredi e-poštno poročilo" +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:77 +msgid "Minimum leaf node event count" +msgstr "Min. število dogodkov za list" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:80 +msgid "" +"Leaf nodes that represent fewer than this number of events will be initially " +"hidden in the visualization" +msgstr "" +"Listna vozlišča, ki predstavljajo manjše število dogodkov od te vrednosti, bodo v " +"vizualizaciji skrita" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:95 +msgid "Additional metadata" +msgstr "Dodatni metapodatki" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:104 +msgid "Metadata" +msgstr "Metapodatki" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:106 +msgid "Select any columns for metadata inspection" +msgstr "Izberite poljubne stolpce za pregled metapodatkov" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:124 +msgid "Entity ID" +msgstr "ID entitete" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:125 +msgid "e.g., a \"user id\" column" +msgstr "t.j. stolpec \"id uporabnika\"" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:128 +msgid "Max Events" +msgstr "Max. dogodkov" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:129 +msgid "The maximum number of events to return, equivalent to the number of rows" +msgstr "Največje število dogodkov, ki bodo vrnjeni - enako številu vrstic" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:26 +msgid "" +"Compares the lengths of time different activities take in a shared timeline view." +msgstr "Primerja dolžine časovno različnih aktivnosti na skupni časovnici." + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:29 +msgid "Event Flow" +msgstr "Potek dogodkov" + +#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:30 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:56 +msgid "Progressive" +msgstr "Progresivno" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:36 +msgid "Axis ascending" +msgstr "Naraščajoča os" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:37 +msgid "Axis descending" +msgstr "Padajoča os" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:38 +msgid "Metric ascending" +msgstr "Naraščajoča mera" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:39 +msgid "Metric descending" +msgstr "Padajoča mera" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:104 +msgid "Heatmap Options" +msgstr "Možnosti toplotnega prikaza" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:114 +msgid "XScale Interval" +msgstr "Interval X-osi" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:119 +msgid "Number of steps to take between ticks when displaying the X scale" +msgstr "Število korakov med oznakami pri prikazu X-osi" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:130 +msgid "YScale Interval" +msgstr "Interval Y-osi" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:135 +msgid "Number of steps to take between ticks when displaying the Y scale" +msgstr "Število korakov med oznakami pri prikazu Y-osi" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:146 +msgid "Rendering" +msgstr "Izris" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:153 +msgid "" +"image-rendering CSS attribute of the canvas object that defines how the browser " +"scales up the image" +msgstr "atribut CSS za izris objekta platna, ki določa, kako brskalnik poveča sliko" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:165 +msgid "Normalize Across" +msgstr "Normiraj glede na" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:172 +msgid "" +"Color will be rendered based on a ratio of the cell against the sum of across " +"this criteria" +msgstr "" +"Barva bo prikazana na osnovi razmerja med celico in vsoto glede na ta kriterij" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:187 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:77 +msgid "Left Margin" +msgstr "Levi rob" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:199 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:81 +msgid "Left margin, in pixels, allowing for more room for axis labels" +msgstr "Levi rob, v pikslih, s katerim povečamo prostor za oznake osi" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:212 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:187 +msgid "Bottom Margin" +msgstr "Spodnji rob" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:224 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:191 +msgid "Bottom margin, in pixels, allowing for more room for axis labels" +msgstr "Spodnji rob, v pikslih, s katerim povečamo prostor za oznake osi" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:235 +msgid "Value bounds" +msgstr "Meje vrednosti" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:238 +msgid "" +"Hard value bounds applied for color coding. Is only relevant and applied when the " +"normalization is applied against the whole heatmap." +msgstr "" +"Mejne vrednosti za barvno lestvico. Upošteva se le, če je normiranje uporabljeno " +"glede na celotni toplotni prikaz." + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:251 +msgid "Sort X Axis" +msgstr "Razvrsti X-os" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:263 +msgid "Sort Y Axis" +msgstr "Razvrsti Y-os" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:287 +msgid "Show percentage" +msgstr "Prikaži procente" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:289 +msgid "Whether to include the percentage in the tooltip" +msgstr "Če želite prikaz procentov v opisu orodja" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:315 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:141 +msgid "Normalized" +msgstr "Normiran" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:317 +msgid "Whether to apply a normal distribution based on rank on the color scale" +msgstr "" +"Če želite uporabiti normalno porazdelitev glede na stopnjo na barvni lestvici" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:329 +msgid "Value Format" +msgstr "Oblika zapisa vrednosti" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:30 +msgid "" +"Visualize a related metric across pairs of groups. Heatmaps excel at showcasing " +"the correlation or strength between two groups. Color is used to emphasize the " +"strength of the link between each pair of groups." +msgstr "Vizualizacija povezanih mer med pari skupin." + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:34 +msgid "Sizes of vehicles" +msgstr "Velikosti vozil" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:36 +msgid "Employment and education" +msgstr "Zaposlitev in izobrazba" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:43 +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:38 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:40 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:38 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:45 +msgid "Density" +msgstr "Gostota" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:44 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:39 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:76 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:71 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:72 +msgid "Predictive" +msgstr "Prediktivno" + +#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:45 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:46 +msgid "Single Metric" +msgstr "Ena mera" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:117 +msgid "count" +msgstr "število" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:121 +msgid "cumulative" +msgstr "kumulativno" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:125 +msgid "percentile (exclusive)" +msgstr "percentil (ekskluzivno)" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:38 +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:48 +msgid "Select the numeric columns to draw the histogram" +msgstr "Izberite numerične stolpce za izris histograma" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:86 +msgid "No of Bins" +msgstr "Št. razdelkov" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:98 +msgid "Select the number of bins for the histogram" +msgstr "Izberite število razdelkov za histogram" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:107 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:175 +msgid "X Axis Label" +msgstr "Naslov X osi" + +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:118 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:333 +msgid "Y Axis Label" +msgstr "Naslov Y osi" -#: superset/views/log/__init__.py:24 -msgid "Edit Log" -msgstr "Uredi dnevnik" +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:143 +msgid "Whether to normalize the histogram" +msgstr "Če želite normirati histogram" -#: superset/connectors/sqla/views.py:215 -msgid "Edit Metric" -msgstr "Uredi mero" +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:153 +msgid "Cumulative" +msgstr "Kumulativno" -#: superset/views/dynamic_plugins.py:61 -msgid "Edit Plugin" -msgstr "Uredi vtičnik" +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:155 +msgid "Whether to make the histogram cumulative" +msgstr "Če želite kumulativni histogram" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1051 -#, fuzzy -msgid "Edit Report" -msgstr "Uredi zapis" +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:28 +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:26 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:48 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/createMetadata.ts:25 +msgid "Distribution" +msgstr "Porazdelitev" -#: superset/connectors/sqla/views.py:317 -msgid "Edit Row level security filter" -msgstr "Uredi filter za varnost na nivoju vrstic" +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:29 +msgid "" +"Take your data points, and group them into \"bins\" to see where the densest " +"areas of information lie" +msgstr "" +"Vzame podatkovne točke in jih razporedi v razdelke, kjer se vidi območja z " +"največjo gostoto informacij" -#: superset/views/sql_lab.py:42 -msgid "Edit Saved Query" -msgstr "Uredi shranjeno poizvedbo" +#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:33 +msgid "Population age data" +msgstr "Podatki starosti populacije" -#: superset/connectors/sqla/views.py:398 -msgid "Edit Table" -msgstr "Uredi tabelo" +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:46 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:49 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:47 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:60 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:355 +#: superset-frontend/src/explore/controlPanels/sections.tsx:117 +msgid "Contribution" +msgstr "Prispevek" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:174 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:283 -msgid "Edit annotation" -msgstr "Uredi oznako" +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:45 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:48 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:51 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:49 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:62 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:357 +#: superset-frontend/src/explore/controlPanels/sections.tsx:119 +msgid "Compute the contribution to the total" +msgstr "Izračunaj prispevek k celoti" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:170 -msgid "Edit annotation layer" -msgstr "Uredi sloj z oznakami" +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:63 +msgid "Series Height" +msgstr "Višina serije" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:237 -msgid "Edit annotation layer properties" -msgstr "Uredi lastnosti sloja z oznakami" +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:75 +msgid "Pixel height of each series" +msgstr "Višina vsake serije v pikslih" -#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:305 -#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:308 -msgid "Edit chart properties" -msgstr "Uredi lastnosti grafikona" +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:83 +msgid "Value Domain" +msgstr "Domena vrednosti" -#: superset-frontend/src/dashboard/components/Header/index.jsx:605 -msgid "Edit dashboard" -msgstr "Uredi nadzorno ploščo" +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:90 +msgid "" +"series: Treat each series independently; overall: All series use the same scale; " +"change: Show changes compared to the first data point in each series" +msgstr "" +"serije: Obravnavaj vsako podatkovno serijo neodvisno; skupno: Vse vrste " +"uporabljajo enako skalo; razlika: Pokaži razlike glede na prvo točko vsake serije" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:302 -msgid "Edit dashboard properties" -msgstr "Uredi lastnosti nadzorne plošče" +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:28 +msgid "" +"Compares how a metric changes over time between different groups. Each group is " +"mapped to a row and change over time is visualized bar lengths and color." +msgstr "" +"Primerja kako se mera spreminja s časom med različnimi skupinami. Vsaka skupina " +"predstavlja eno vrstico, časovne spremembe pa so prikazane z dolžino stolpcev in " +"barvami." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1011 -msgid "Edit database" -msgstr "Uredi podatkovno bazo" +#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:32 +msgid "Horizon Chart" +msgstr "Horizontni grafikon" -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:192 -msgid "Edit dataset" -msgstr "Uredi podatkovni set" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:62 +msgid "Longitude" +msgstr "Dolžina" -#: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:73 -msgid "Edit email report" -msgstr "Uredi e-poštno poročilo" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:63 +msgid "Column containing longitude data" +msgstr "Stolpec s podatki zemljepisne dolžine" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:151 -msgid "Edit formatter" -msgstr "Uredi oblikovanje" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:72 +msgid "Latitude" +msgstr "Širina" -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:80 -msgid "Edit properties" -msgstr "Uredi lastnosti" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:73 +msgid "Column containing latitude data" +msgstr "Stolpec s podatki zemljepisne širine" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:383 -msgid "Edit query" -msgstr "Uredi poizvedbo" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:83 +msgid "Clustering Radius" +msgstr "Radij gručenja" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:230 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:210 -msgid "Edit template" -msgstr "Uredi predlogo" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:96 +msgid "" +"The radius (in pixels) the algorithm uses to define a cluster. Choose 0 to turn " +"off clustering, but beware that a large number of points (>1000) will cause lag." +msgstr "" +"Radij (v pikslih), s katerim algoritem definira gručo. Izberite 0 za izklop " +"gručenja - veliko število točk (>1000) bo povzročilo upočasnitev." -#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:99 -msgid "Edit template parameters" -msgstr "Uredi parametre predloge" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:110 +msgid "Points" +msgstr "Točke" -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:353 -msgid "Edit time range" -msgstr "Uredi časovno obdobje" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:117 +msgid "Point Radius" +msgstr "Radij točk" -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:161 -msgid "Edited" -msgstr "Urejane" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:119 +msgid "" +"The radius of individual points (ones that are not in a cluster). Either a " +"numerical column or `Auto`, which scales the point based on the largest cluster" +msgstr "" +"Radij posameznih točk (tistih, ki niso v gruči). Numerični stolpec ali `Auto` " +"(skalira točke na osnovi največje gruče)" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:484 -msgid "Editing 1 filter:" -msgstr "Urejanje enega filtra:" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:141 +msgid "Point Radius Unit" +msgstr "Enota radija točk" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:119 -msgid "Editing filter set:" -msgstr "Urejanje seta filtrov:" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:144 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:90 +msgid "The unit of measure for the specified point radius" +msgstr "Enota merila za definiran radij točk" -#: superset/errors.py:110 -msgid "Either the database is spelled incorrectly or does not exist." -msgstr "Ime podatkovne baze je zapisano napačno ali pa ne obstaja." +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:153 +msgid "Labelling" +msgstr "Oznake" -#: superset/db_engine_specs/mysql.py:124 superset/db_engine_specs/presto.py:195 -#: superset/db_engine_specs/redshift.py:63 -#, python-format -msgid "Either the username \"%(username)s\" or the password is incorrect." -msgstr "Uporabniško ime \"%(username)s\" ali geslo sta napačna." +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:161 +msgid "label" +msgstr "oznaka" -#: superset/db_engine_specs/mssql.py:74 -#, python-format +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:163 msgid "" -"Either the username \"%(username)s\", password, or database name " -"\"%(database)s\" is incorrect." +"`count` is COUNT(*) if a group by is used. Numerical columns will be aggregated " +"with the aggregator. Non-numerical columns will be used to label points. Leave " +"empty to get a count of points in each cluster." msgstr "" -"Uporabniško ime \"%(username)s\", geslo ali ime podatkovne baze " -"\"%(database)s\" so napačni." +"`število` je COUNT(*), če je uporabljeno združevanje (group by). Numerični " +"stolpci bodo agregirani z agregatorjem. Ne-numerični stolpci, bodo uporabljeni za " +"oznake točk. Pustite prazno, da dobite število točk v posamezni gruči." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:114 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:118 -#, fuzzy, python-format -msgid "Either the username or password is incorrect." -msgstr "Uporabniško ime \"%(username)s\" ali geslo sta napačna." +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:180 +msgid "Cluster label aggregator" +msgstr "Agregator za oznako gruče" -#: superset/errors.py:109 -msgid "Either the username or the password is wrong." -msgstr "Uporabniško ime ali/in geslo sta napačna." +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:191 +msgid "" +"Aggregate function applied to the list of points in each cluster to produce the " +"cluster label." +msgstr "" +"Agregacijska funkcija za seznam točk v vsaki gruči, s katero se ustvari oznaka " +"gruče." -#: superset/views/schedules.py:326 -msgid "Email Format" -msgstr "Oblika e-pošte" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:201 +msgid "Visual Tweaks" +msgstr "Nastavitve izgleda" -#: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:64 -msgid "Email reports active" -msgstr "E-poštna poročila aktivna" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:208 +msgid "Live render" +msgstr "Sprotni izris" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:47 -msgid "Emit Target" -msgstr "Cilj oddajanja" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:210 +msgid "Points and clusters will update as the viewport is being changed" +msgstr "Točke in gruče se bodo posodabljale, če se bo spremenil pogled" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx:30 -msgid "Emit dashboard cross filters" -msgstr "Oddajaj medsebojne filtre nadzorne plošče" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:221 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:370 +msgid "Map Style" +msgstr "Slog zemljevida" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx:33 -msgid "Emit dashboard cross filters." -msgstr "Oddajaj medsebojne filtre nadzorne plošče." +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:236 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:382 +msgid "Base layer map style" +msgstr "Slog osnovnega sloja zemljevida" -#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:95 -msgid "Emitted values" -msgstr "Oddane vrednosti" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:245 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:115 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:211 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:671 +msgid "Opacity" +msgstr "Prosojnost" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:191 -msgid "Emphasis" -msgstr "Poudari" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:248 +msgid "Opacity of all clusters, points, and labels. Between 0 and 1." +msgstr "Prosojnost vseh gruč, točk in oznak (vrednost med 0 in 1)." -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:36 -msgid "Employment and education" -msgstr "Zaposlitev in izobrazba" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:260 +msgid "RGB Color" +msgstr "RGB barva" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:214 -msgid "Empty circle" -msgstr "Prazen krog" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:263 +msgid "The color for points and clusters in RGB" +msgstr "Barva točk in gruč v RGB zapisu" -#: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:59 -msgid "Empty collection" -msgstr "Prazen izbor" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:270 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:293 +msgid "Viewport" +msgstr "Pogled" -#: superset/connectors/sqla/models.py:1068 -msgid "Empty query?" -msgstr "Prazna poizvedba?" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:278 +msgid "Default longitude" +msgstr "Privzeta dolžina" -#: superset/connectors/druid/views.py:348 superset/connectors/sqla/views.py:493 -msgid "Enable Filter Select" -msgstr "Omogoči izbiro filtra" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:282 +msgid "Longitude of default viewport" +msgstr "Dolžina privzetega pogleda" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:293 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:184 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:145 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:125 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:142 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:200 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:203 -msgid "Enable data zooming controls" -msgstr "Omogoči kontrolnik za povečavo podatkov" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:292 +msgid "Default latitude" +msgstr "Privzeta širina" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:44 -msgid "Enable forecast" -msgstr "Omogoči napoved" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:296 +msgid "Latitude of default viewport" +msgstr "Širina privzetega pogleda" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:47 -msgid "Enable forecasting" -msgstr "Omogoči napovedovanje" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:308 +msgid "Zoom" +msgstr "Povečava" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:161 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:270 -msgid "Enable graph roaming" -msgstr "Omogoči preoblikovanje grafikona" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:312 +msgid "Zoom level of the map" +msgstr "Stopnja povečave zemljevida" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:141 -msgid "Enable node dragging" -msgstr "Omogoči premikanje vozlišč" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:325 +msgid "" +"One or many controls to group by. If grouping, latitude and longitude columns " +"must be present." +msgstr "" +"Eden ali več kontrolnikov za združevanje. Pri združevanju morata biti prisotna " +"stolpca širine in dolžine." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:176 -msgid "Enable query cost estimation" -msgstr "Omogoči ocenjevanje potratnosti poizvedbe" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:30 +msgid "Light mode" +msgstr "Svetli način" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:290 -msgid "Enable server side pagination of results (experimental feature)" -msgstr "" -"Omogoči številčenje strani rezultatov na strani strežnika (preizkusna " -"funkcija)" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:31 +msgid "Dark mode" +msgstr "Temni način" -#: superset/viz.py:2530 -msgid "" -"Encountered invalid NULL spatial entry," -" please consider filtering those " -"out" -msgstr "" -"Prišlo je do neveljavnega NULL prostorskega vnosa," -" poskusite ga izločiti s filtrom" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:33 +msgid "MapBox" +msgstr "MapBox" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:164 -#: superset/views/annotations.py:80 -msgid "End" -msgstr "Konec" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:39 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:43 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:36 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:85 +msgid "Scatter" +msgstr "Raztreseni" -#: superset/views/sql_lab.py:73 -msgid "End Time" -msgstr "Končni čas" +#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:40 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:46 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:88 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:75 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:74 +msgid "Transformable" +msgstr "Prilagodljiv" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:120 -msgid "End angle" -msgstr "Končni kot" +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:64 +msgid "Significance Level" +msgstr "Stopnja značilnosti" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:78 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:171 -msgid "End date excluded from time range" -msgstr "Končni datum ni vključen v časovno obdobje" +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:66 +msgid "Threshold alpha level for determining significance" +msgstr "Mejna vrednost alfa za določanje značilnosti" -#: superset/annotation_layers/annotations/commands/exceptions.py:35 -msgid "End date must be after start date" -msgstr "Končni datum mora biti za začetnim" +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:77 +msgid "p-value precision" +msgstr "točnost p-vrednosti" -#: superset/databases/commands/validate.py:71 -#, python-format -msgid "Engine \"%(engine)s\" cannot be configured through parameters." -msgstr "Podatkovne baze tipa \"%(engine)s\" ni mogoče konfigurirati s parametri." +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:79 +msgid "Number of decimal places with which to display p-values" +msgstr "Število decimalnih mest za prikaz p-vrednosti" -#: superset/databases/commands/validate.py:59 superset/databases/schemas.py:308 -#, python-format -msgid "Engine \"%(engine)s\" is not a valid engine." -msgstr "\"%(engine)s\" ni veljaven tip podatkovne baze." +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:90 +msgid "Lift percent precision" +msgstr "Točnost procentualnega dviga" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:459 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:464 -msgid "Engine Parameters" -msgstr "Parametri podatkovne baze" +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:92 +msgid "Number of decimal places with which to display lift values" +msgstr "Število decimalnih mest za prikaz vrednosti dviga" -#: superset/databases/schemas.py:272 +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:26 msgid "" -"Engine spec \"InvalidEngine\" does not support being configured via " -"individual parameters." +"Table that visualizes paired t-tests, which are used to understand statistical " +"differences between groups." msgstr "" -"Specifikacija baze \"InvalidEngine\" ne podpira konfiguracije s " -"posameznimi parametri." - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:356 -msgid "Enter CA_BUNDLE" -msgstr "Vnesite CA_BUNDLE" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:55 -msgid "Enter a name for this sheet" -msgstr "Vnesite ime te preglednice" +"Tabela, ki prikazuje uparjene t-teste, ki se uporabljajo za prikaz statističnih " +"razlik med skupinami." -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:238 -msgid "Enter a new title for the tab" -msgstr "Vnesite novo naslov zavihka" +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:29 +msgid "Paired t-test Table" +msgstr "Tabela t-testa za odvisne vzorce" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:222 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:244 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:266 -msgid "Enter duration in seconds" -msgstr "Vnesite trajanje v sekundah" +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 +msgid "Statistical" +msgstr "Statistično" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:327 -msgid "Enter fullscreen" -msgstr "Vklopi celozaslonski način" +#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:50 +#: superset-frontend/src/visualizations/TimeTable/index.ts:35 +msgid "Tabular" +msgstr "Tabelarično" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:73 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:397 -#: superset-frontend/src/explore/controls.jsx:412 -msgid "Entity" -msgstr "Entiteta" +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:39 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:67 +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:109 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:73 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:39 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx:73 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:133 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:226 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:382 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:48 +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:67 +msgid "Options" +msgstr "Možnosti" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:125 -msgid "Entity ID" -msgstr "ID entitete" +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:47 +msgid "Data Table" +msgstr "Tabela podatkov" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:216 -msgid "Equal Date Sizes" -msgstr "Enaki datumi" +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:50 +msgid "Whether to display the interactive data table" +msgstr "Če želite prikaz interaktivne podatkovne tabele" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:56 -#, fuzzy -msgid "Error" -msgstr "Operator" +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:57 +msgid "Include Series" +msgstr "Vključi serijo" -#: superset/views/alerts.py:83 -msgid "Error Message" -msgstr "Sporočilo napake" +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:60 +msgid "Include series name as an axis" +msgstr "Vključi ime podatkovne serije v naslov osi" -#: superset/connectors/sqla/models.py:1349 -#, python-format -msgid "Error in jinja expression in HAVING clause: %(msg)s" -msgstr "Napaka v jinja izrazu HAVING stavka: %(msg)s" +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:25 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:28 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:48 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:33 +msgid "Ranking" +msgstr "Rangiranje" -#: superset/connectors/sqla/models.py:976 -#, python-format -msgid "Error in jinja expression in RLS filters: %(msg)s" -msgstr "Napaka v jinja izrazu RLS filtrov: %(msg)s" +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:27 +msgid "" +"Plots the individual metrics for each row in the data vertically and links them " +"together as a line. This chart is useful for comparing multiple metrics across " +"all of the samples or rows in the data." +msgstr "" +"Izriše posamezne mere za vsako vrstico podatkov navpično in jih med seboj poveže " +"kot črto. Grafikon je uporaben za primerjavo več mer med vsemi vzorci ali " +"vrsticami podatkov." -#: superset/connectors/sqla/models.py:1337 -#, python-format -msgid "Error in jinja expression in WHERE clause: %(msg)s" -msgstr "Napaka v jinja izrazu WHERE stavka: %(msg)s" +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:57 +msgid "Coordinates" +msgstr "Koordinate" -#: superset/connectors/sqla/models.py:735 -#, python-format -msgid "Error in jinja expression in fetch values predicate: %(msg)s" -msgstr "Napaka v jinja izrazu za pridobivanje vrednosti predikatov: %(msg)s" +#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:39 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:42 +msgid "Directional" +msgstr "Usmerjeni" -#: superset-frontend/src/dashboard/containers/DashboardPage.tsx:190 -msgid "Error loading chart datasources. Filters may not work correctly." -msgstr "" -"Napaka pri nalaganju podatkovnih virov grafikona. Filtri lahko ne " -"delujejo pravilno." +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:59 +msgid "Time Series Options" +msgstr "Možnosti časovne vrste" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:144 -msgid "Error message" -msgstr "Sporočilo napake" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:73 +msgid "Not Time Series" +msgstr "Ni časovna vrsta" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:104 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:139 -msgid "Error while fetching charts" -msgstr "Napaka pri pridobivanju grafikonov" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:75 +msgid "Ignore time" +msgstr "Ne upoštevaj časa" -#: superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx:89 -#, fuzzy, python-format -msgid "Error while fetching data: %s" -msgstr "Napaka pri pridobivanju grafikonov" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:78 +msgid "Time Series" +msgstr "Časovna vrsta" -#: superset/connectors/sqla/models.py:842 -#, python-format -msgid "Error while rendering virtual dataset query: %(msg)s" -msgstr "Napaka pri izvajanju poizvedbe virtualnega podatkovnega seta: %(msg)s" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:80 +msgid "Standard time series" +msgstr "Standardna časovna vrsta" -#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:91 -msgid "Estimate cost" -msgstr "Oceni potratnost" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:83 +msgid "Aggregate Mean" +msgstr "Agregirano povprečje" -#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:90 -msgid "Estimate selected query cost" -msgstr "Oceni potratnost izbrane poizvedbe" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:85 +msgid "Mean of values over specified period" +msgstr "Povprečna vrednost v dani periodi" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:648 -msgid "Estimate the cost before running a query" -msgstr "Oceni potratnost pred zagonom poizvedbe" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:88 +msgid "Aggregate Sum" +msgstr "Agregirana vsota" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:29 -msgid "Event Flow" -msgstr "Potek dogodkov" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:90 +msgid "Sum of values over specified period" +msgstr "Vsota vrednosti v dani periodi" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:43 -msgid "Event Names" -msgstr "Imena dogodkov" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:93 +msgid "Difference" +msgstr "Razlika" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:35 -msgid "Event definition" -msgstr "Definicija dogodka" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:95 +msgid "Metric change in value from `since` to `until`" +msgstr "Sprememba mere od vrednosti \"OD\" do \"DO\"" -#: superset/viz.py:2896 -msgid "Event flow" -msgstr "Potek dogodkov" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:100 +msgid "Percent Change" +msgstr "Procentualna sprememba" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:478 -msgid "Event time column" -msgstr "Stolpec časa dogodka" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:102 +msgid "Metric percent change in value from `since` to `until`" +msgstr "Procentualna sprememba mere od vrednosti \"OD\" do \"DO\"" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:43 -msgid "Every" -msgstr "Vsak" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:107 +msgid "Factor" +msgstr "Faktor" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:30 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:29 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:25 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:25 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:30 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:25 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:25 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:56 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:59 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:58 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:57 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:57 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:48 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:57 -msgid "Evolution" -msgstr "Evolucija" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:109 +msgid "Metric factor change from `since` to `until`" +msgstr "Sprememba faktorja mere od vrednosti \"OD\" do \"DO\"" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1263 -#, fuzzy -msgid "Exact" -msgstr "Besedilo" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:114 +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:234 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:117 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:365 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:163 +msgid "Advanced Analytics" +msgstr "Napredna analitika" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:34 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:49 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:67 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:81 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:95 -msgid "Example" -msgstr "Primer" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:116 +msgid "Use the Advanced Analytics options below" +msgstr "Uporabite spodnje možnosti napredne analitike" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:92 -#, fuzzy, python-format -msgid "Example %(tableName)s will appear here" -msgstr "Primer ${tableName.toLowerCase()} se bo prikazal tukaj" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:125 +msgid "Settings for time series" +msgstr "Nastavitve časovne vrste" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:759 -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:180 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:178 -msgid "Examples" -msgstr "Vzorci" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:155 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:79 +msgid "Date Time Format" +msgstr "Oblika zapisa Datum-Časa" -#: superset/views/database/forms.py:252 -msgid "Excel File" -msgstr "Excel-ova datoteka" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:168 +msgid "Partition Limit" +msgstr "Omejitev particij" -#: superset/views/database/views.py:398 -#, python-format +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:171 msgid "" -"Excel file \"%(excel_filename)s\" uploaded to table \"%(table_name)s\" in" -" database \"%(db_name)s\"" +"The maximum number of subdivisions of each group; lower values are pruned first" msgstr "" -"Excel datoteka \"%(excel_filename)s\" naložena v tabelo " -"\"%(table_name)s\" v podatkovni bazi \"%(db_name)s\"" +"Največje število podrazdelkov posamezne skupine; nižje vrednosti so zanemarjene " +"prve" -#: superset/views/database/views.py:268 -msgid "Excel to Database configuration" -msgstr "Nastavitve pretvorbe Excel v Podatkovno bazo" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:181 +msgid "Partition Threshold" +msgstr "Prag particije" -#: superset-frontend/src/filters/components/Select/controlPanel.ts:126 -msgid "Exclude selected values" -msgstr "Izloči izbrane vrednosti" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:184 +msgid "" +"Partitions whose height to parent height proportions are below this value are " +"pruned" +msgstr "" +"Particije z nižjim razmerjem med njihovo višino in dolžino starša so zanemarjene" -#: superset-frontend/src/SqlLab/components/HighlightedSql/index.tsx:82 -msgid "Executed SQL" -msgstr "Izvedena poizvedba" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:196 +msgid "Log Scale" +msgstr "Logaritemska skala" -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:162 -msgid "Executed query" -msgstr "Zagnana poizvedba" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:199 +msgid "Use a log scale" +msgstr "Uporabi logaritemsko skalo" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:105 -msgid "Execution ID" -msgstr "ID izvedbe" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:208 +msgid "Equal Date Sizes" +msgstr "Enaki datumi" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:307 -msgid "Execution log" -msgstr "Dnevnik izvajanja" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:211 +msgid "Check to force date partitions to have the same height" +msgstr "Če želite, da imajo datumske particije enako višino" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:326 -msgid "Exit fullscreen" -msgstr "Izhod iz celozaslonskega načina" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:222 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:92 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:281 +msgid "Rich Tooltip" +msgstr "Podroben opis orodja" -#: superset-frontend/src/dashboard/components/filterscope/treeIcons.jsx:36 -msgid "Expand all" -msgstr "Razširi vse" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:225 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:95 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:284 +msgid "The rich tooltip shows a list of all series for that point in time" +msgstr "" +"Podroben opis orodja prikaže seznam vseh podatkovnih serij za posamezno časovno " +"točko" -#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:152 -#, fuzzy -msgid "Expand table preview" -msgstr "Odstrani predogled tabele" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:243 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:126 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:373 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:167 +msgid "Rolling Window" +msgstr "Drseče okno" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:351 -msgid "Expand tool bar" -msgstr "Razširi orodno vrstico" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:249 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:132 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:379 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:173 +msgid "Rolling Function" +msgstr "Drseča funkcija" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:72 -#: superset-frontend/src/filters/components/GroupBy/index.ts:31 -#: superset-frontend/src/filters/components/Range/index.ts:31 -#: superset-frontend/src/filters/components/Select/index.ts:32 -#: superset-frontend/src/filters/components/Time/index.ts:31 -#: superset-frontend/src/filters/components/TimeColumn/index.ts:31 -#: superset-frontend/src/filters/components/TimeGrain/index.ts:31 -msgid "Experimental" -msgstr "Eksperimentalno" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:282 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:165 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:414 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:208 +msgid "Min Periods" +msgstr "Min. št. period" -#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.jsx:98 -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:168 -#: superset/views/core.py:883 -msgid "Explore" -msgstr "Raziskovanje" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:295 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:178 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:426 +msgid "Time Comparison" +msgstr "Časovna primerjava" -#: superset/views/core.py:881 -#, python-format -msgid "Explore - %(table)s" -msgstr "Razišči - %(table)s" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:303 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:186 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:434 +msgid "Time Shift" +msgstr "Časovni zamik" -#: superset/reports/notifications/email.py:91 -msgid "Explore in Superset" -msgstr "Razišči v Supersetu" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:369 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:252 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:497 +#: superset-frontend/src/explore/controlPanels/sections.tsx:251 +msgid "Method" +msgstr "Metoda" -#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.jsx:91 -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:161 -msgid "Explore the result set in the data exploration view" -msgstr "Raziščite rezultate v pogledu raziskovanja podatkov" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:25 +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:26 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:29 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:51 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:33 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:50 +msgid "Part of a Whole" +msgstr "Del celote" -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:116 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:388 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:661 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:98 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:385 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:630 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:342 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:373 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:636 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:516 -#: superset/views/dashboard/views.py:67 -msgid "Export" -msgstr "Izvoz" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:26 +msgid "Compare the same summarized metric across multiple groups." +msgstr "Primerja isto mero med različnimi skupinami." -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:333 -msgid "Export CSV" -msgstr "Izvozi CSV" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:27 +msgid "Partition Chart" +msgstr "Grafikon razdelkov" -#: superset/views/dashboard/views.py:67 -msgid "Export dashboards?" -msgstr "Izvozim nadzorne plošče?" +#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:38 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:42 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:42 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:66 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:59 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:42 +msgid "Categorical" +msgstr "Kategorični" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:341 -msgid "Export full CSV" -msgstr "Izvozi celoten CSV" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:46 +msgid "Pivot Options" +msgstr "Vrtilne možnosti" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:397 -msgid "Export query" -msgstr "Izvozi poizvedbe" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:53 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:142 +msgid "Aggregation function" +msgstr "Agregacijska funkcija" -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:202 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:210 -msgid "Export to .CSV format" -msgstr "Izvozi v .csv format" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:64 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:165 +msgid "" +"Aggregate function to apply when pivoting and computing the total rows and columns" +msgstr "Agregacijska funkcija za vrtenje in izračun vseh vrstic in stolpcev" -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:182 -msgid "Export to .JSON format" -msgstr "Izvozi v .json format" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:77 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx:105 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:368 +msgid "Show totals" +msgstr "Pokaži vsote" -#: superset/views/base.py:538 -msgid "Export to YAML" -msgstr "Izvozi v YAML" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:79 +msgid "Display total row/column" +msgstr "Pokaži vsote vrstic/stolpcev" -#: superset/views/base.py:538 -msgid "Export to YAML?" -msgstr "Izvozim v YAML?" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:86 +msgid "Combine Metrics" +msgstr "Združuj mere" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:76 -msgid "Expose database in SQL Lab" -msgstr "Razkrij podatkovno bazo v SQL laboratoriju" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:88 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:215 +msgid "" +"Display metrics side by side within each column, as opposed to each column being " +"displayed side by side for each metric." +msgstr "" +"Prikazuj mere eno ob drugi ob vsakem stolpcu, drugače je vsak stolpec prikazan en " +"ob drugem za vsako mero." -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:281 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:387 -#: superset/views/database/mixins.py:186 -msgid "Expose in SQL Lab" -msgstr "Uporabi v SQL laboratoriju" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:100 +msgid "Transpose Pivot" +msgstr "Transponirano vrtenje" -#: superset/views/database/mixins.py:104 -msgid "Expose this DB in SQL Lab" -msgstr "Uporabi to podatkovno bazo v SQL laboratoriju" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:102 +msgid "Swap Groups and Columns" +msgstr "Zamenjaj Skupine in Stolpce" -#: superset/connectors/sqla/views.py:149 -msgid "Expression" -msgstr "Izraz" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:132 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:69 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:138 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:115 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:136 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:153 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:129 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:244 +msgid "Date format" +msgstr "Oblika zapisa datuma" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:735 -#: superset/connectors/sqla/views.py:262 superset/connectors/sqla/views.py:505 -#: superset/views/database/mixins.py:196 -msgid "Extra" -msgstr "Dodatno" +#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:27 +msgid "" +"Used to summarize a set of data by grouping together multiple statistics along " +"two axes. Examples: Sales numbers by region and month, tasks by status and " +"assignee, active users by age and location.\n" +"\n" +" This chart is being deprecated and we recommend checking out Pivot Table V2 " +"instead!" +msgstr "" +"Uporablja se za predstavitev podatkov z združevanjem različnih statistik na dveh " +"oseh. Npr. Prodaja po regijah in mesecih, Naloge po statusih in izvajalcih, " +"aktivni uporabniki po starosti in lokaciji.\n" +"\n" +" Ta grafikon se opušča. Priporočamo uporabo Vrtilne tabele V2!" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:160 -msgid "Extra Controls" -msgstr "Dodatni kontrolniki" +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:104 +#: superset-frontend/src/explore/controlUtils/controlUtils.test.tsx:112 +#: superset-frontend/src/explore/fixtures.tsx:42 +msgid "Use Area Proportions" +msgstr "Uporabi razmerje površin" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:87 -msgid "Extra Parameters" -msgstr "Dodatni parametri" +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:105 +#: superset-frontend/src/explore/controlUtils/controlUtils.test.tsx:113 +#: superset-frontend/src/explore/fixtures.tsx:43 +msgid "" +"Check if the Rose Chart should use segment area instead of segment radius for " +"proportioning" +msgstr "" +"Če želite, da grafikon \"Rose\" uporablja površino segmenta namesto radija za " +"proporcioniranje" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:736 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:26 msgid "" -"Extra data to specify table metadata. Currently supports metadata of the " -"format: `{ \"certification\": { \"certified_by\": \"Data Platform Team\"," -" \"details\": \"This table is the source of truth.\" }, " -"\"warning_markdown\": \"This is a warning.\" }`." +"A polar coordinate chart where the circle is broken into wedges of equal angle, " +"and the value represented by any wedge is illustrated by its area, rather than " +"its radius or sweep angle." msgstr "" -"Dodatni podatki za tabelo metapodatkov. Trenutno je podprta naslednja " -"oblika zapisa metapodatkov: `{ \"certification\": { \"certified_by\": " -"\"Tim za razvoj\", \"details\": \"Ta tabela je vir resnice.\" }, " -"\"warning_markdown\": \"To je opozorilo.\" }`." +"Grafikon s polarnimi koordinatami, kjer je krog razdeljen na enakokotne izseke, " +"vrednosti pa so ponazorjene s ploščino izseka (namesto polmera ali kota)." -#: superset/views/database/mixins.py:244 superset/views/database/mixins.py:268 -#, python-format -msgid "Extra field cannot be decoded by JSON. %(msg)s" -msgstr "Dodatnega polja ni mogoče dekodirati z JSON. %(msg)s" +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:29 +msgid "Nightingale Rose Chart" +msgstr "Nightingale Rose grafikon" -#: superset-frontend/src/explore/controlPanels/sections.tsx:62 -msgid "Extra parameters for use in jinja templated queries" -msgstr "Dodatni parametri za poizvedbe z jinja predlogami" +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:32 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:35 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:38 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:78 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:77 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:72 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:69 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:128 +msgid "Advanced-Analytics" +msgstr "Napredna analitika" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:89 +#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:34 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:41 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:37 +msgid "Multi-Layers" +msgstr "Večplastni" + +#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:43 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:33 +msgid "Source / Target" +msgstr "Izhodišče/Cilj" + +#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:44 +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:34 +msgid "Choose a source and a target" +msgstr "Izberite izhodišče in cilj" + +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:44 msgid "" -"Extra parameters that any plugins can choose to set for use in Jinja " -"templated queries" +"Limiting rows may result in incomplete data and misleading charts. Consider " +"filtering or grouping source/target names instead." msgstr "" -"Dodatni parametri, ki jih lahko uporabi kateri koli vtičnik za poizvedbe " -"z Jinja predlogami" +"Omejitev vrstic lahko povzroči nepopolne podatke in zavajajoč grafikon. " +"Premislite o uporabi filtriranja ali združevanja imen izvorov/ciljev." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:78 -msgid "Extra url parameters for use in Jinja templated queries" -msgstr "Dodatni parametri za poizvedbe z Jinja predlogami" +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:29 +msgid "" +"Visualizes the flow of different group's values through different stages of a " +"system. New stages in the pipeline are visualized as nodes or layers. The " +"thickness of the bars or edges represent the metric being visualized." +msgstr "" +"Prikaže potek vrednosti različnih skupin na različnih nivojih sistema. Novi " +"nivoji so prikazani kot točke ali plasti. Debelina stolpcev ali povezav " +"predstavlja prikazano mero." -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:92 -msgid "FEB" -msgstr "FEB" +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:33 +msgid "Demographics" +msgstr "Demografija" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:86 -msgid "FRI" -msgstr "PET" +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:34 +msgid "Survey Responses" +msgstr "Rezultati anket" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:115 -msgid "Factor" -msgstr "Faktor" +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:36 +msgid "Sankey Diagram" +msgstr "Sankey grafikon" -#: superset/views/database/forms.py:145 superset/views/database/forms.py:298 -#: superset/views/database/forms.py:426 -msgid "Fail" -msgstr "Prekini" +#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:41 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:49 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:43 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:38 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:46 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:69 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:63 +#: superset-frontend/src/visualizations/TimeTable/index.ts:34 +msgid "Percentages" +msgstr "Procenti" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:69 -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:75 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:153 -msgid "Failed" -msgstr "Ni uspelo" +#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/index.js:27 +msgid "Sankey Diagram with Loops" +msgstr "Sankey grafikon z zankami" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:194 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:305 -msgid "Failed at retrieving results" -msgstr "Napaka pri pridobivanju rezultatov" +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:60 +msgid "Primary Metric" +msgstr "Primarna mera" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:409 -#, python-format -msgid "Failed at stopping query. %s" -msgstr "" +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:61 +msgid "The primary metric is used to define the arc segment sizes" +msgstr "Primarna mera določa velikost lokov segmentov" -#: superset/errors.py:137 superset/sqllab/sql_json_executer.py:194 -msgid "Failed to start remote query on a worker." -msgstr "Na delavcu ni bilo mogoče zagnati oddaljene poizvedbe." +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:66 +msgid "Secondary Metric" +msgstr "Sekundarna mera" -#: superset-frontend/src/explore/components/controls/withAsyncVerification.tsx:201 -#, python-format -msgid "Failed to verify select options: %s" -msgstr "Preverjanje možnosti izbire ni uspelo: %s" +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:68 +msgid "" +"[optional] this secondary metric is used to define the color as a ratio against " +"the primary metric. When omitted, the color is categorical and based on labels" +msgstr "" +"[opcijsko] sekundarna mera določa barvo kot razmerje do primarne mere. Če je " +"izpuščena, je barva določena kategorično na podlagi oznak" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:436 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:433 -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:162 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:159 -msgid "Favorite" -msgstr "Priljubljene" +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:75 +msgid "When only a primary metric is provided, a categorical color scale is used." +msgstr "" +"Če je podana samo primarna metrika, je uporabljena kategorična barvna skala." -#: superset-frontend/src/profile/components/App.tsx:52 -msgid "Favorites" -msgstr "Priljubljene" +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:85 +msgid "When a secondary metric is provided, a linear color scale is used." +msgstr "Če je podana sekundarna metrika, je uporabljena linearna barvna skala." -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:67 -msgid "February" -msgstr "Februar" +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:95 +msgid "Hierarchy" +msgstr "Hierarhija" -#: superset/connectors/druid/views.py:353 -msgid "Fetch Values From" -msgstr "Pridobi vrednosti iz" +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:96 +msgid "This defines the level of the hierarchy" +msgstr "Določa stopnjo hierarhije" -#: superset/connectors/sqla/views.py:499 -msgid "Fetch Values Predicate" -msgstr "Pridobi vrednosti predikatov" +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:28 +msgid "" +"Uses circles to visualize the flow of data through different stages of a system. " +"Hover over individual paths in the visualization to understand the stages a value " +"took. Useful for multi-stage, multi-group visualizing funnels and pipelines." +msgstr "" +"S pomočjo krogov prikaže potek podatkov na različnih nivojih sistema. S premikom " +"kurzorja prikaže vrednosti na posameznem nivoju. Uporabno za večnivojsko, " +"večskupinsko vizualizacijo." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:788 -msgid "Fetch data preview" -msgstr "Pridobi predogled podatkov" +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:32 +msgid "Sunburst Chart" +msgstr "Večnivojski tortni grafikon" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:244 -#, python-format -msgid "Fetched %s" -msgstr "Pridobljeno %s" +#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:62 +msgid "Multi-Levels" +msgstr "Večplastni" -#: superset/databases/commands/exceptions.py:62 -#, fuzzy, python-format -msgid "Field cannot be decoded by JSON. %(json_error)s" -msgstr "Polja ni mogoče dekodirati z JSON. %{json_error}s" +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:53 +msgid "Ratio" +msgstr "Razmerje" -#: superset/databases/schemas.py:183 superset/databases/schemas.py:198 -#, python-format -msgid "Field cannot be decoded by JSON. %(msg)s" -msgstr "Polja ni mogoče dekodirati z JSON. %(msg)s" +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:57 +msgid "Target aspect ratio for treemap tiles." +msgstr "Ciljno razmerje za razdelke drevesnega grafikona." -#: superset/databases/commands/exceptions.py:50 -msgid "Field is required" -msgstr "Polje je obvezno" +#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:31 +msgid "" +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " +"query." +msgstr "" +"Prikaže zgradbo podatkovnega seta na podlagi segmentacije danega pravokotnika na " +"manjše pravokotnike, pri čemer je ploščina sorazmerna vrednostim oz. deležem. " +"Pravokotniki se lahko dodatno hierarhično segmentirajo." -#: superset/templates/superset/import_dashboards.html:37 -msgid "File" -msgstr "Datoteka" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:40 +msgid "Country Field Type" +msgstr "Tip polja za države" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:982 -msgid "Fill all required fields to enable \"Default Value\"" -msgstr "Izpolnite vsa polja, da omogočite \"Privzeto vrednost\"" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:48 +msgid "" +"The country code standard that Superset should expect to find in the [country] " +"column" +msgstr "Standard za oznake držav, ki bodo podane v stolpcu z državami" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:166 -msgid "Fill method" -msgstr "Način polnjenja" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:81 +msgid "Show Bubbles" +msgstr "Prikaži mehurčke" -#: superset-frontend/src/components/ListView/Filters/Select.tsx:77 -msgid "Filter" -msgstr "Filter" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:84 +msgid "Whether to display bubbles on top of countries" +msgstr "Če želite prikaz mehurčkov nad državami" -#: superset/templates/appbuilder/general/widgets/search.html:24 -msgid "Filter List" -msgstr "Seznam filtrov" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:95 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:59 +msgid "Max Bubble Size" +msgstr "Max. velikost mehurčka" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:787 -msgid "Filter Type" -msgstr "Tip filtra" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:115 +msgid "Color by" +msgstr "Barva glede na" -#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:26 -msgid "Filter box" -msgstr "Izbirnik za filtriranje" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:121 +msgid "" +"Choose whether a country should be shaded by the metric, or assigned a color " +"based on a categorical color palette" +msgstr "" +"Izberite, če želite barvanje držav glede na mero ali kategorično določeno barvno " +"paleto" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "Filtriraj po podatkovni bazi" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:134 +msgid "Country Column" +msgstr "Stolpec z državami" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "Filtriraj po statusu" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:135 +msgid "3 letter code of the country" +msgstr "Tričrkovna oznaka države" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "Filtriraj po uporabniku" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:139 +msgid "Metric that defines the size of the bubble" +msgstr "Mera, ki določa velikost mehurčka" -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 -msgid "Filter configuration" -msgstr "Nastavitve filtra" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:142 +msgid "Bubble Color" +msgstr "Barva mehurčka" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:66 -msgid "Filter configuration for the filter box" -msgstr "Nastavitve za polje filtra" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:145 +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:150 +msgid "Country Color Scheme" +msgstr "Barvna shema držav" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:895 -msgid "Filter has default value" -msgstr "Filter ima privzeto vrednost" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:29 +msgid "A map of the world, that can indicate values in different countries." +msgstr "Zemljevid sveta, ki lahko prikazuje vrednosti po državah." -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1010 -msgid "Filter is hierarchical" -msgstr "Filter je hierarhičen" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:40 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:36 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:32 +msgid "Multi-Dimensions" +msgstr "Večdimenzionalni" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:109 -msgid "Filter metadata changed in dashboard. It will not be applied." -msgstr "Metapodatki filtra so se spremenili v nadzorni plošči. Ne bo uveljavljen." +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:42 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:32 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:58 +#: superset-frontend/src/visualizations/TimeTable/index.ts:31 +msgid "Multi-Variables" +msgstr "Več spremenljivk" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:777 -msgid "Filter name" -msgstr "Ime filtra" +#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:44 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:47 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:44 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:42 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:70 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:92 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:86 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:47 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:128 +msgid "Popular" +msgstr "Priljubljeni" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:563 -msgid "Filter results" -msgstr "Filtriraj rezultate" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:37 +msgid "deck.gl charts" +msgstr "grafikoni deck.gl" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:144 -msgid "Filter set already exists" -msgstr "Set filtrov že obstaja" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:40 +msgid "Pick a set of deck.gl charts to layer on top of one another" +msgstr "Izberite nabor deck.gl grafikonov, ki bodo nanizani en na drugem" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:143 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:83 -msgid "Filter set with this name already exists" -msgstr "Set filtrov z enakim imenom že obstaja" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:103 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:138 +msgid "Select charts" +msgstr "Izberi grafikone" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:348 -#, python-format -msgid "Filter sets (%(filterSetCount)d)" -msgstr "" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/controlPanel.js:46 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:104 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:139 +msgid "Error while fetching charts" +msgstr "Napaka pri pridobivanju grafikonov" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:791 -msgid "Filter type" -msgstr "Tip filtra" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/index.js:27 +msgid "Compose multiple layers together to form complex visuals." +msgstr "Združi več plasti za oblikovanje kompleksnih vizualizacij." + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/index.js:28 +msgid "deck.gl Multiple Layers" +msgstr "deck.gl - večplastni grafikon" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:34 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:34 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:34 +msgid "deckGL" +msgstr "deckGL" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/components/PlaySlider.jsx:182 +msgid "Data has no time steps" +msgstr "Podatki nimajo časovnih korakov" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:52 +msgid "Start Longitude & Latitude" +msgstr "Začetna Dolž. in Širina" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:54 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:66 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:309 +msgid "Point to your spatial columns" +msgstr "Pokažite na stolpec z lokacijskimi podatki" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:64 +msgid "End Longitude & Latitude" +msgstr "Končna Dolž. in Širina" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:85 +msgid "Arc" +msgstr "Lok" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:92 +msgid "Target Color" +msgstr "Ciljna barva" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:93 +msgid "Color of the target location" +msgstr "Barva ciljne lokacije" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:105 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:142 +msgid "Categorical Color" +msgstr "Kategorična barva" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:106 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:143 +msgid "Pick a dimension from which categorical colors are defined" +msgstr "Izberite dimenzijo, ki bo določala kategorične barve" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:119 +msgid "Stroke Width" +msgstr "Debelina obrobe" + +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/controlPanel.ts:132 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts:91 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts:58 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:90 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/controlPanel.ts:76 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:182 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:153 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:62 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:925 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:607 +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:34 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1375 +msgid "Advanced" +msgstr "Napredno" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:417 -msgid "Filter value (case sensitive)" -msgstr "Vrednost filtra (razlik. velikih/malih črk)" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:27 +msgid "Plot the distance (like flight paths) between origin and destination." +msgstr "Izriši razdalje (kot letalske koridorje) med izhodiščem in ciljem." -#: superset/connectors/sqla/models.py:1278 -msgid "Filter value list cannot be empty" -msgstr "Seznam vrednosti filtra ne sme biti prazen" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:30 +msgid "deck.gl Arc" +msgstr "deck.gl - grafikon lokov" -#: superset-frontend/src/dashboard/components/SliceAdder.jsx:245 -msgid "Filter your charts" -msgstr "Filtriraj grafikone" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:35 +msgid "3D" +msgstr "3D" -#: superset/connectors/druid/views.py:95 superset/connectors/sqla/views.py:147 -msgid "Filterable" -msgstr "Filtriranje" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Arc/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/index.js:31 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:60 +msgid "Web" +msgstr "Mreža" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:82 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:459 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:103 -#: superset-frontend/src/explore/controls.jsx:466 superset/viz.py:2105 -msgid "Filters" -msgstr "Filtri" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts:68 +msgid "GeoJson Settings" +msgstr "GeoJson nastavitve" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:84 -#, python-format -msgid "Filters (%d)" -msgstr "Filtri (%d)" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts:80 +msgid "Point Radius Scale" +msgstr "Skaliranje radija točk" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:134 -msgid "Filters by columns" -msgstr "Filtrira po stolpcu" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:27 +msgid "" +"The GeoJsonLayer takes in GeoJSON formatted data and renders it as interactive " +"polygons, lines and points (circles, icons and/or texts)." +msgstr "" +"GeoJsonLayer uporablja podatke v formatu GeoJSON in jih izriše kot interaktivne " +"poligone, črte in točke (krogi, ikone in/ali besedila)." -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:136 -msgid "Filters by metrics" -msgstr "Filtrira po merah" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/index.js:30 +msgid "deck.gl Geojson" +msgstr "deck.gl - GeoJson grafikon" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:57 -msgid "Filters configuration" -msgstr "Nastavitve filtrov" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts:69 +msgid "Height" +msgstr "Višina" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx:467 -msgid "Filters configuration and scoping" -msgstr "Nastavitve in doseg filtrov" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/controlPanel.ts:70 +msgid "Metric used to control height" +msgstr "Mera za določanje višine" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx:159 -#, python-format -msgid "Filters out of scope (%d)" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:27 +msgid "" +"Visualize geospatial data like 3D buildings, landscapes, or objects in grid view." msgstr "" +"Prikaz geoprostorskih podatkov kot so 3D zgradbe, parcele ali objekti v mrežnem " +"pogledu." -#: superset/connectors/sqla/views.py:348 -msgid "" -"Filters with the same group key will be ORed together within the group, " -"while different filter groups will be ANDed together. Undefined group " -"keys are treated as unique groups, i.e. are not grouped together. For " -"example, if a table has three filters, of which two are for departments " -"Finance and Marketing (group key = 'department'), and one refers to the " -"region Europe (group key = 'region'), the filter clause would apply the " -"filter (department = 'Finance' OR department = 'Marketing') AND (region =" -" 'Europe')." -msgstr "" -"Filtri z enakim skupinskim ključem bodo znotraj skupine združeni z OR " -"funkcijo, medtem ko bodo različne skupine združene z AND funkcijo. " -"Nedefinirani skupinski ključi so obravnavani kot unikatne skupine in niso" -" združeni v svojo skupino. Npr., če ima tabela tri filtre, pri čemer sta " -"dva za oddelka marketinga in financ (skupinski ključ = 'oddelek') tretji " -"pa se nanaša na regijo Evropa (skupinski ključ = 'regija'), bo filtrski " -"izraz (oddelek = 'Finance' OR oddelek = 'Marketing') AND (regija = " -"'Evropa')." - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:794 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:808 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1193 -msgid "Finish" -msgstr "Končaj" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:30 +msgid "deck.gl Grid" +msgstr "deck.gl - grafikon mreže" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:124 -msgid "" -"Fix the trend line to the full time range specified in case filtered " -"results do not include the start or end dates" -msgstr "" -"Trendno črto nastavite na izbrano obdobje, v primeru, da filtrirani " -"rezultati ne vsebujejo začetnega in/ali končnega datuma" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Grid/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:33 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:38 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:37 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:81 +#: superset-frontend/src/filters/components/GroupBy/index.ts:31 +#: superset-frontend/src/filters/components/Range/index.ts:31 +#: superset-frontend/src/filters/components/Select/index.ts:32 +#: superset-frontend/src/filters/components/Time/index.ts:31 +#: superset-frontend/src/filters/components/TimeColumn/index.ts:31 +#: superset-frontend/src/filters/components/TimeGrain/index.ts:31 +msgid "Experimental" +msgstr "Eksperimentalno" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:123 -msgid "Fix to selected Time Range" -msgstr "Nastavi na izbrano časovno obdobje" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:63 +msgid "Dynamic Aggregation Function" +msgstr "Dinamična agregacijska funkcija" -#: superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx:149 -msgid "Fixed" -msgstr "Fiksno" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/controlPanel.ts:64 +msgid "The function to use when aggregating points into groups" +msgstr "Funkcija za agregacijo točk v skupine" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:175 -msgid "Fixed Color" -msgstr "Izbrana barva" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:27 +msgid "" +"Overlays a hexagonal grid on a map, and aggregates data within the boundary of " +"each cell." +msgstr "" +"Prikaže šestkotno mrežo na zemljevidu in agregira podatke znotraj meja vsake " +"celice." -#: superset-frontend/src/explore/controls.jsx:206 -msgid "Fixed color" -msgstr "Izbrana barva" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Hex/index.js:30 +msgid "deck.gl 3D Hexagon" +msgstr "deck.gl - grafikon 3D šestkotnikov" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:26 -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:24 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:27 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:32 -msgid "Flow" -msgstr "Potek" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/index.js:27 +msgid "Visualizes connected points, which form a path, on a map." +msgstr "Na zemljevidu prikaže povezane točke, ki tvorijo pot." -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:133 -msgid "Font size" -msgstr "Velikost pisave" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Path/index.js:28 +msgid "deck.gl Path" +msgstr "deck.gl - grafikon poti" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:134 -msgid "Font size for axis labels, detail value and other text elements" -msgstr "Velikost pisave za oznake osi, podrobnosti in druge besedilne elemente" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:64 +msgid "Polygon Column" +msgstr "Stolpec poligonov" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:71 -msgid "Font size for the biggest value in the list" -msgstr "Velikost pisave za največjo vrednost na seznamu" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:73 +msgid "Polygon Encoding" +msgstr "Kodiranje poligonov" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:60 -msgid "Font size for the smallest value in the list" -msgstr "Velikost pisave za najmanjšo vrednost na seznamu" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:84 +msgid "Elevation" +msgstr "Višina" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 -msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " -"query." -msgstr "" -"Za Presto in Postgres prikaže gumb za izračun potratnosti pred zagonom " -"poizvedbe." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:102 +msgid "Polygon Settings" +msgstr "Nastavitve poligonov" -#: superset/connectors/sqla/views.py:342 -msgid "" -"For regular filters, these are the roles this filter will be applied to. " -"For base filters, these are the roles that the filter DOES NOT apply to, " -"e.g. Admin if admin should see all data." -msgstr "" -"Za regularne filtre so te vloge tiste, ki bodo filtrirane. Za osnovne " -"filtre, so te vloge tiste, ki NE bodo filtrirane, npr. Admin, če naj " -"administrator vidi vse podatke." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:121 +msgid "Opacity, expects values between 0 and 100" +msgstr "Prosojnost, vnesite vrednosti med 0 in 100" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:111 -msgid "Force" -msgstr "Sila" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:132 +msgid "Number of buckets to group data" +msgstr "Število razdelkov za združevanje podatkov" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:129 -msgid "" -"Force all tables and views to be created in this schema when clicking " -"CTAS or CVAS in SQL Lab." -msgstr "" -"Vsilite, da bodo vse tabele in pogledi ustvarjeni s to shemo, ko kliknete" -" CTAS ali CVAS v SQL laboratoriju." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:135 +msgid "How many buckets should the data be grouped in." +msgstr "V koliko razdelkov bodo razvrščeni podatki." -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:270 -msgid "Force refresh" -msgstr "Osveži" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:145 +msgid "Bucket break points" +msgstr "Točke za razčlenitev razdelkov" -#: superset-frontend/src/components/DatabaseSelector/index.tsx:287 -msgid "Force refresh schema list" -msgstr "Osveži seznam shem" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:147 +msgid "List of n+1 values for bucketing metric into n buckets." +msgstr "Seznam n+1 vrednosti za mero razvrščanja v n razdelkov." -#: superset-frontend/src/components/TableSelector/index.tsx:317 -msgid "Force refresh table list" -msgstr "Osveži seznam tabel" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:159 +msgid "Emit Filter Events" +msgstr "Oddajaj dogodke filtrov" -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/index.js:27 -msgid "Force-directed Graph" -msgstr "Graf usmerjenih sil" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:162 +msgid "Whether to apply filter when items are clicked" +msgstr "Če želite uporabiti filter, ko kliknete na elemente" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:56 -msgid "Forecast periods" -msgstr "Periode napovedi" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:169 +msgid "Multiple filtering" +msgstr "Večkratno filtriranje" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:37 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:42 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:45 -msgid "Formattable" -msgstr "Prilagodljiv" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/controlPanel.ts:172 +msgid "Allow sending multiple polygons as a filter event" +msgstr "Dovoli pošiljanje več poligonov kot dogodek filtra" -#: superset-frontend/src/components/ReportModal/index.tsx:296 -msgid "Formatted CSV attached in email" -msgstr "Oblikovan CSV pripet e-pošti" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:27 +msgid "" +"Visualizes geographic areas from your data as polygons on a Mapbox rendered map. " +"Polygons can be colored using a metric." +msgstr "" +"Prikaže geografsko območje kot poligone na zemljevidu zagotovljenim preko " +"storitve Mapbox. Poligoni so lahko obarvani glede na mero." -#: superset-frontend/packages/superset-ui-core/src/query/extractQueryFields.ts:130 -msgid "Found invalid orderby options" -msgstr "Najdene so neveljavne možnosti razvrščanja" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/index.js:30 +msgid "deck.gl Polygon" +msgstr "deck.gl - grafikon poligonov" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:80 -msgid "Fraction digits" -msgstr "Število decimalk" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:71 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:320 +msgid "Point Size" +msgstr "Velikost točke" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:53 -msgid "Frequency" -msgstr "Frekvenca" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:79 +msgid "Point Unit" +msgstr "Enota točke" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:304 -msgid "Friction" -msgstr "Trenje" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:101 +msgid "Minimum Radius" +msgstr "Min. polmer" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:310 -msgid "Friction between nodes" -msgstr "Trenje med vozlišči" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:106 +msgid "" +"Minimum radius size of the circle, in pixels. As the zoom level changes, this " +"insures that the circle respects this minimum radius." +msgstr "" +"Minimalni polmer kroga v pikslih. S tem je določen minimalni polmer kroga, ko se " +"spreminja stopnja povečave." -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:61 -msgid "Friday" -msgstr "Petek" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:116 +msgid "Maximum Radius" +msgstr "Max. polmer" -#: superset/utils/date_parser.py:264 superset/viz.py:370 -msgid "From date cannot be larger than to date" -msgstr "Začetni datum ne sme biti večji od končnega datuma" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:121 +msgid "" +"Maxium radius size of the circle, in pixels. As the zoom level changes, this " +"insures that the circle respects this maximum radius." +msgstr "" +"Maksimalni polmer kroga v pikslih. S tem je določen maksimalni polmer kroga, ko " +"se spreminja stopnja povečave." -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:52 -msgid "Funnel Chart" -msgstr "Lijakasti grafikon" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/controlPanel.ts:132 +msgid "Point Color" +msgstr "Barva točke" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:454 -msgid "Further customize how to display each column" -msgstr "Dodatne prilagoditve prikaza posameznih stolpcev" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:27 +msgid "" +"A map that takes rendering circles with a variable radius at latitude/longitude " +"coordinates" +msgstr "" +"Zemljevid, ki na zemljepisnih koordinatah prikazuje kroge s spremenljivim polmerom" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:168 -msgid "Further customize how to display each metric" -msgstr "Dodatne prilagoditve prikaza posameznih mer" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Scatter/index.js:30 +msgid "deck.gl Scatterplot" +msgstr "deck.gl - raztreseni grafikon" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:42 -msgid "Gauge Chart" -msgstr "Števčni grafikon" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:57 +msgid "Grid" +msgstr "Mreža" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:78 -msgid "General" -msgstr "Splošno" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:73 +msgid "Weight" +msgstr "Utež" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:34 -msgid "Geo" -msgstr "Geo" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/controlPanel.ts:74 +msgid "Metric used as a weight for the grid's coloring" +msgstr "Mera, ki služi kot utež za barvo mreže" -#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:203 -msgid "Geohash" -msgstr "Geohash" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:27 +msgid "" +"Aggregates data within the boundary of grid cells and maps the aggregated values " +"to a dynamic color scale" +msgstr "" +"Agregira podatke znotraj meja celic in agregirane vrednosti ponazori z dinamično " +"barvno lestvico" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:75 -msgid "Get the last date by the date unit." -msgstr "Pridobi zadnji datum glede na časovno enoto." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/index.js:30 +msgid "deck.gl Screen Grid" +msgstr "deck.gl - grafikon mreže" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:88 -msgid "Get the specify date for the holiday" -msgstr "Določi datum praznika" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:45 +msgid "" +"For more information about objects are in context in the scope of this function, " +"refer to the" +msgstr "Za dodatne informacije o objektih v kontekstu te funkcije si oglejte" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:47 -msgid "Google Sheet Name and URL" -msgstr "Ime Googlove preglednice in URL" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:48 +msgid " source code of Superset's sandboxed parser" +msgstr " izvorno kodo za Supersetov \"sandboxed parser\"" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1275 -msgid "Grace period" -msgstr "Obdobje mirovanja" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:75 +msgid "This functionality is disabled in your environment for security reasons." +msgstr "Ta funkcionalnost je v vašem okolju onemogočena zaradi varnosti." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:37 -msgid "Graph Chart" -msgstr "Graf" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:87 +msgid "Ignore null locations" +msgstr "Izpusti prazne lokacije" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:108 -msgid "Graph layout" -msgstr "Izgled grafikona" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:89 +msgid "Whether to ignore locations that are null" +msgstr "Če ne želite upoštevati praznih (NULL) lokacij" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:262 -msgid "Gravity" -msgstr "Gravitacija" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:97 +msgid "Auto Zoom" +msgstr "Samodejna povečava" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:299 -#: superset-frontend/src/filters/components/GroupBy/index.ts:28 -msgid "Group By" -msgstr "Združevanje (Group by)" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:100 +msgid "When checked, the map will zoom to your data after each query" +msgstr "Če želite, da se zemljevid prilagodi vašim podatkom po vsaki poizvedbi" -#: superset-frontend/src/filters/components/GroupBy/index.ts:29 -msgid "Group By filter plugin" -msgstr "Vtičnik za filter za združevanje" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:110 +msgid "Dimension" +msgstr "Dimenzija" -#: superset/viz.py:895 -msgid "Group By' and 'Columns' can't overlap" -msgstr "'Združevanje' in 'Stolpci' se ne smeta prekrivati" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:111 +msgid "Select a dimension" +msgstr "Izberite dimenzijo" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:83 -msgid "Group By, Metrics or Percentage Metrics must have a value" -msgstr "Združevanje, Mera ali Procentualna mera morajo imeti vrednost" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:121 +msgid "Extra data for JS" +msgstr "Dodatni podatki za JS" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:31 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:99 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:42 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:299 -#: superset-frontend/src/explore/controls.jsx:123 -msgid "Group by" -msgstr "Združevanje (Group by)" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:123 +msgid "List of extra columns made available in Javascript functions" +msgstr "Seznam dodatnih podatkov, ki so na razpolago v Javascript funkcijah" -#: superset/connectors/druid/views.py:94 superset/connectors/sqla/views.py:146 -msgid "Groupable" -msgstr "Združevanje" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:132 +msgid "Javascript data interceptor" +msgstr "Javascript prestreznik podatkov" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:238 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:133 msgid "" -"Hard value bounds applied for color coding. Is only relevant and applied " -"when the normalization is applied against the whole heatmap." +"Define a javascript function that receives the data array used in the " +"visualization and is expected to return a modified version of that array. This " +"can be used to alter properties of the data, filter, or enrich the array." msgstr "" -"Mejne vrednosti za barvno lestvico. Upošteva se le, če je normiranje " -"uporabljeno glede na celotni toplotni prikaz." +"Določite Javascript funkcijo, ki sprejme podatkovni niz za vizualizacijo in vrne " +"spremenjeno verzijo tega niza. Lahko se uporabi za spreminjanje lastnosti " +"podatkov, filtra ali obogatitve niza." -#: superset-frontend/src/dashboard/components/gridComponents/new/NewHeader.jsx:31 -msgid "Header" -msgstr "Glava" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:144 +msgid "Javascript tooltip generator" +msgstr "Javascript generator opisa orodja" -#: superset/views/database/forms.py:152 superset/views/database/forms.py:305 -msgid "Header Row" -msgstr "Naslovna vrstica" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:145 +msgid "" +"Define a function that receives the input and outputs the content for a tooltip" +msgstr "Določite funkcijo, ki sprejme vhodne podatke in vrne vsebino opisa orodja" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:38 -#: superset/viz.py:2212 -msgid "Heatmap" -msgstr "Toplotni prikaz" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:154 +msgid "Javascript onClick href" +msgstr "Javascript onClick href" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:104 -msgid "Heatmap Options" -msgstr "Možnosti toplotnega prikaza" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:155 +msgid "Define a function that returns a URL to navigate to when user clicks" +msgstr "Določite funkcijo, ki vrne URL za navigacijo, ko uporabnik klikne" -#: superset-frontend/src/explore/components/EmbedCodeButton.jsx:116 -msgid "Height" -msgstr "Višina" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:162 +msgid "Legend Format" +msgstr "Oblika legende" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:730 -msgid "Hide layer" -msgstr "Skrij sloj" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:163 +msgid "Choose the format for legend values" +msgstr "Izberite obliko vrednosti legende" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:351 -msgid "Hide tool bar" -msgstr "Skrij orodno vrstico" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:176 +msgid "Legend Position" +msgstr "Položaj legende" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:81 -msgid "Hierarchy" -msgstr "Hierarhija" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:177 +msgid "Choose the position of the legend" +msgstr "Izberite položaj legende" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:37 -#: superset/viz.py:1711 -msgid "Histogram" -msgstr "Histogram" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:196 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx:27 +msgid "Lines column" +msgstr "Stolpec črt" -#: superset/initialization/__init__.py:222 -msgid "Home" -msgstr "Domov" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:198 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx:28 +msgid "The database columns that contains lines information" +msgstr "Stolpec v podatkovni bazi, ki vsebuje podatke črt" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:32 -msgid "Horizon Chart" -msgstr "Horizontni grafikon" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:210 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:702 +msgid "Line width" +msgstr "Debelina črte" -#: superset/viz.py:2273 -msgid "Horizon Charts" -msgstr "Horizontni grafikon" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:214 +msgid "The width of the lines" +msgstr "Debelina črt" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:106 -msgid "Horizontal alignment" -msgstr "Vodoravna poravnava" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:221 +msgid "Fill Color" +msgstr "Barva polnila" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:47 -msgid "Host" -msgstr "" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:222 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:235 +msgid "" +" Set the opacity to 0 if you do not want to override the color specified in the " +"GeoJSON" +msgstr " Nastavite prosojnost na 0, če želite obdržati barvo določeno v GeoJSON" -#: superset/db_engine_specs/base.py:1390 -msgid "Hostname or IP address" -msgstr "Ime gostitelja ali IP naslov" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:234 +msgid "Stroke Color" +msgstr "Barva obrobe" -#: superset/db_engine_specs/base.py:94 -msgid "Hour" -msgstr "Ura" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:248 +msgid "Filled" +msgstr "Zapolnjeno" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:65 -#, fuzzy, python-format -msgid "Hours %s" -msgstr "ura" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:250 +msgid "Whether to fill the objects" +msgstr "Če želite zapolniti objekte" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:779 -msgid "Hours offset" -msgstr "Urni premik" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:259 +msgid "Stroked" +msgstr "Obrobljeno" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:94 -msgid "How do you want to enter service account credentials?" -msgstr "Kako želite vnesti prijavne podatke servisnega računa?" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:261 +msgid "Whether to display the stroke" +msgstr "Če želite prikazati obrobe" -#: superset/views/alerts.py:190 -msgid "How long to keep the logs around for this alert" -msgstr "Kako dolgo ohraniti dnevnike za to opozorilo" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:270 +msgid "Extruded" +msgstr "Relief" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:59 -msgid "How many periods into the future do we want to predict" -msgstr "Za koliko period v prihodnosti želite napoved" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:281 +msgid "Grid Size" +msgstr "Velikost mreže" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:129 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:342 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:225 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:477 -#: superset-frontend/src/explore/controlPanels/sections.tsx:240 -msgid "" -"How to display time shifts: as individual lines; as the difference " -"between the main time series and each time shift; as the percentage " -"change; or as the ratio between series and time shifts." -msgstr "" -"Način prikaza časovnih zamikov: kot samostojne črte; kot razlike med " -"osnovno časovno vrsto in vsakim časovnim zamikom; kot procentualna " -"sprememba; kot razmerje med vrsto in časovnim zamikom." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:285 +msgid "Defines the grid size in pixels" +msgstr "Določa velikost mreže v pikslih" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:51 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:85 -msgid "Huge" -msgstr "Ogromna" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:295 +msgid "Parameters related to the view and perspective on the map" +msgstr "Parametri povezani s pogledom in perspektivo zemljevida" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:78 -msgid "ISO 3166-2 Codes" -msgstr "Oznake po ISO 3166-2" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:307 +msgid "Longitude & Latitude" +msgstr "Dolžina in širina" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:237 -msgid "ISO 8601" -msgstr "ISO 8601" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:322 +msgid "Fixed point radius" +msgstr "Fiksni radij točk" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:50 -msgid "Id" -msgstr "Id" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:333 +msgid "Multiplier" +msgstr "Množitelj" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:85 -msgid "Id of root node of the tree." -msgstr "Id korenskega vozlišča drevesa." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:337 +msgid "Factor to multiply the metric by" +msgstr "Faktor, s katerim množite mero" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:400 -msgid "" -"If Presto or Trino, all the queries in SQL Lab are going to be executed " -"as the currently logged on user who must have permission to run them. If " -"Hive and hive.server2.enable.doAs is enabled, will run the queries as " -"service account, but impersonate the currently logged on user via " -"hive.server2.proxy.user property." -msgstr "" -"V primeru Presto ali Trino se vse poizvedbe v SQL laboratoriju zaženejo " -"pod trenutno prijavljenim uporabnikom, ki mora imeti pravice za " -"poganjanje. Če je omogočen Hive in hive.server2.enable.doAs, poizvedbe " -"tečejo pod servisnim računom, vendar je trenutno prijavljen uporabnik " -"predstavljen z lastnostjo hive.server2.proxy.user." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:345 +msgid "Lines encoding" +msgstr "Kodiranje črt" -#: superset/views/database/mixins.py:163 -msgid "" -"If Presto, all the queries in SQL Lab are going to be executed as the " -"currently logged on user who must have permission to run them.<br/>If " -"Hive and hive.server2.enable.doAs is enabled, will run the queries as " -"service account, but impersonate the currently logged on user via " -"hive.server2.proxy.user property." -msgstr "" -"V primeru Presto se vse poizvedbe v SQL laboratoriju zaženejo pod " -"trenutno prijavljenim uporabnikom, ki mora imeti pravice za " -"poganjanje.<br/>Če je omogočen Hive in hive.server2.enable.doAs, " -"poizvedbe tečejo pod servisnim računom, vendar je trenutno prijavljen " -"uporabnik predstavljen z lastnostjo hive.server2.proxy.user." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:348 +msgid "The encoding format of the lines" +msgstr "Oblika kodiranja črt" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1201 -msgid "If a metric is specified, sorting will be done based on the metric value" -msgstr "Če je določena mera, bo razvrščanje izvedeno na podlagi vrednosti mere" +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:361 +msgid "Reverse Lat & Long" +msgstr "Zamenjaj širino in dolžino" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:121 -msgid "If activated you can use the " -msgstr "Če je aktivirana, lahko uporabite " +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:390 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx:36 +msgid "GeoJson Column" +msgstr "GeoJson stolpec" -#: superset/views/database/mixins.py:180 -msgid "If selected, please set the schemas allowed for csv upload in Extra." -msgstr "Če je izbrano, nastavite dovoljene sheme za nalaganje CSV v Dodatno." +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx:392 +#: superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/sharedDndControls.jsx:37 +msgid "Select the geojson column" +msgstr "Izberite geojson stolpec" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:420 -msgid "If selected, please set the schemas allowed for data upload in Extra." -msgstr "Če je izbrano, nastavite dovoljene sheme za nalaganje podatkov v Dodatno." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:53 +msgid "Right Axis Format" +msgstr "Oblika desne osi" -#: superset/views/database/forms.py:139 superset/views/database/forms.py:292 -#: superset/views/database/forms.py:420 -msgid "" -"If table exists do one of the following: Fail (do nothing), Replace (drop" -" and recreate table) or Append (insert data)." -msgstr "" -"Če tabela obstaja, naredite nekaj od sledečega: Prekini (ne naredi nič), " -"Zamenjaj (zbriši in ponovno ustvari tabelo) ali Dodaj (vstavi podatke)." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:64 +msgid "Show Markers" +msgstr "Prikaži markerje" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:48 -msgid "" -"If you wish to specify a different target column than the original " -"column, it can be entered here" -msgstr "" -"Če želite nastaviti drug ciljni stolpec od izvornega, ga lahko vnesete " -"tukaj" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:67 +msgid "Show data points as circle markers on the lines" +msgstr "Pokaži točke kot krožne markerje na krivuljah" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:83 -msgid "Ignore time" -msgstr "Ne upoštevaj časa" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:91 +msgid "Y bounds" +msgstr "Y meje" -#: superset-frontend/src/components/ReportModal/index.tsx:293 -msgid "Image (PNG) embedded in email" -msgstr "Slika (PNG) vključena v e-pošto" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:94 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:105 +msgid "Whether to display the min and max values of the Y-axis" +msgstr "Če želite prikaz min. in max. vrednosti Y-osi" -#: superset-frontend/src/utils/downloadAsImage.ts:63 -msgid "Image download failed, please refresh and try again." -msgstr "Prenos slike ni uspel. Osvežite in poskusite ponovno." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:102 +msgid "Y 2 bounds" +msgstr "Meje Y 2" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:395 -msgid "Impersonate logged in user (Presto, Trino, Drill, Hive, and GSheets)" -msgstr "" -"Predstavljanje kot prijavljeni uporabnik (Presto, Trino, Drill, Hive in " -"GSheets)" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:113 +msgid "Line Style" +msgstr "Slog črte" -#: superset/views/database/mixins.py:200 -msgid "Impersonate the logged on user" -msgstr "Predstavljaj se kot prijavljeni uporabnik" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:124 +msgid "Line interpolation as defined by d3.js" +msgstr "Interpolacija krivulje na osnovi d3.js" -#: superset-frontend/src/components/ImportModal/index.tsx:282 -msgid "Import" -msgstr "Uvozi" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:132 +msgid "Show Range Filter" +msgstr "Pokaži filter obdobja" -#: superset-frontend/src/components/ImportModal/index.tsx:286 -#, python-format -msgid "Import %s" -msgstr "Uvozi %s" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:141 +msgid "Whether to display the time range interactive selector" +msgstr "Če želite prikaz interaktivnega izbirnika časovnega obdobja" -#: superset/templates/superset/import_dashboards.html:26 -msgid "Import Dashboard(s)" -msgstr "Uvozi nadzorne plošče" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:160 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:158 +msgid "Extra Controls" +msgstr "Dodatni kontrolniki" -#: superset/initialization/__init__.py:314 -msgid "Import Dashboards" -msgstr "Uvozi nadzorne plošče" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:163 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:161 +msgid "" +"Whether to show extra controls or not. Extra controls include things like making " +"mulitBar charts stacked or side by side." +msgstr "" +"Če želite prikaz dodatnih kontrolnikov. Dodatni kontrolniki vključujejo možnost " +"izdelave večstolpčnih grafikonov, naloženih ali drug ob drugem." -#: superset/connectors/sqla/views.py:397 -msgid "Import a table definition" -msgstr "Uvozi definicijo tabele" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:201 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:78 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:62 +msgid "X Tick Layout" +msgstr "Postavitev oznak na X-osi" -#: superset/charts/commands/exceptions.py:151 -msgid "Import chart failed for an unknown reason" -msgstr "Uvoz grafikona ni uspel zaradi neznanega razloga" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:206 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:89 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:72 +msgid "The way the ticks are laid out on the X-axis" +msgstr "Način razporeditve oznak na X-osi" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:621 -msgid "Import charts" -msgstr "Uvozi grafikone" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:215 +msgid "X Axis Format" +msgstr "Oblika X-osi" -#: superset/dashboards/commands/exceptions.py:82 -msgid "Import dashboard failed for an unknown reason" -msgstr "Uvoz nadzorne plošče ni uspel zaradi neznanega razloga" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:227 +msgid "Y Log Scale" +msgstr "Logaritemska Y-os" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:596 -#: superset/templates/superset/import_dashboards.html:21 -msgid "Import dashboards" -msgstr "Uvozi nadzorne plošče" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:230 +msgid "Use a log scale for the Y-axis" +msgstr "Uporabi logaritemsko skalo za Y-os" -#: superset/databases/commands/exceptions.py:139 -msgid "Import database failed for an unknown reason" -msgstr "Uvoz podatkovne baze ni uspel zaradi neznanega razloga" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:238 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:383 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:294 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:205 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:222 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:278 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:281 +msgid "Y Axis Bounds" +msgstr "Meje Y-osi" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:195 -msgid "Import databases" -msgstr "Uvozi podatkovne baze" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:241 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:257 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:386 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:297 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:208 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:225 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:281 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:284 +msgid "" +"Bounds for the Y-axis. When left empty, the bounds are dynamically defined based " +"on the min/max of the data. Note that this feature will only expand the axis " +"range. It won't narrow the data's extent." +msgstr "" +"Meje Y-osi. Če je prazno, se meje nastavijo dinamično na podlagi min./max. " +"vrednosti podatkov. Funkcija omeji le prikaz, obseg podatkov pa ostane enak." -#: superset/datasets/commands/exceptions.py:181 -msgid "Import dataset failed for an unknown reason" -msgstr "Uvoz podatkovnega seta ni uspel zaradi neznanega razloga" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:254 +msgid "Y Axis 2 Bounds" +msgstr "Meje Y 2-osi" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:517 -msgid "Import datasets" -msgstr "Uvozi podatkovne sete" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:270 +msgid "X bounds" +msgstr "Meje X-osi" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:273 +msgid "Whether to display the min and max values of the X-axis" +msgstr "Če želite prikaz min. in max. vrednosti X-osi" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:294 +msgid "Bar Values" +msgstr "Vrednosti stolpcev" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:297 +msgid "Show the value on top of the bar" +msgstr "Prikaži vrednosti na vrhu stolpcev" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:190 -msgid "Import queries" -msgstr "Uvozi poizvedbe" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:305 +msgid "Stacked Bars" +msgstr "Naloženi stolpci" -#: superset/queries/saved_queries/commands/exceptions.py:36 -msgid "Import saved query failed for an unknown reason." -msgstr "Uvoz shranjene poizvedbe ni uspel zaradi neznanega razloga." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:316 +msgid "Reduce X ticks" +msgstr "Manj oznak X-osi" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:64 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:319 msgid "" -"Important! Select this if the table is not already sorted by entity id, " -"else there is no guarantee that all events for each entity are returned." +"Reduces the number of X-axis ticks to be rendered. If true, the x-axis will not " +"overflow and labels may be missing. If false, a minimum width will be applied to " +"columns and the width may overflow into an horizontal scroll." msgstr "" -"Pomembno! Izberite, če tabela še ni razvrščena po ID entitete, v " -"nasprotnem primeru ni nujno, da bodo vrnjeni vsi dogodki za posamezno " -"entiteto." +"Zmanjša število izrisanih oznak na X-osi. Če je vklopljeno, se x-os ne bo prelila " +"in lahko oznake manjkajo. Če je izklopljeno, bo upoštevana min. širina stolpcev, " +"ki pa se lahko prelije v horizontalni drsnik." -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:67 -msgid "Include Series" -msgstr "Vključi serijo" - -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:70 -msgid "Include series name as an axis" -msgstr "Vključi ime podatkovne serije v naslov osi" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Vis.js:367 +msgid "You cannot use 45° tick layout along with the time range filter" +msgstr "" +"Skupaj s filtriranjem časovnega obdobja ne morete uporabiti oznak pod 45° kotom" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:325 -msgid "Include time" -msgstr "Vključi čas" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:52 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:144 +#: superset-frontend/src/explore/fixtures.tsx:57 +msgid "Stacked Style" +msgstr "Slog nalaganja" -#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:231 -#, python-format -msgid "Incompatible Filters (%d)" -msgstr "Neskladni filtri (%d)" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:30 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:29 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:30 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:25 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:25 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:58 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:55 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:61 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:60 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:59 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:59 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:50 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:49 +msgid "Evolution" +msgstr "Evolucija" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:121 -msgid "Incorrect Fields" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:32 +msgid "" +"A time series chart that visualizes how a related metric from multiple groups " +"vary over time. Each group is visualized using a different color." msgstr "" +"Grafikon časovne vrste, ki prikaže kako se povezane mere skupin spreminjajo skozi " +"čas. Vsaka skupina je prikazana s svojo barvo." -#: superset/views/database/forms.py:162 superset/views/database/forms.py:315 -msgid "Index Column" -msgstr "Indeksni stolpec" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:36 +msgid "Stretched style" +msgstr "Raztegnjen slog" -#: superset/views/database/forms.py:210 -msgid "Infer Datetime Format" -msgstr "Prepoznaj obliko datuma/časa" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:37 +msgid "Stacked style" +msgstr "Naložen slog" -#: superset-frontend/src/components/Menu/MenuRight.tsx:166 -#: superset/templates/appbuilder/navbar_right.html:110 -msgid "Info" -msgstr "Informacije" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:38 +msgid "Video game consoles" +msgstr "Igralne konzole" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:220 -msgid "Inner Radius" -msgstr "Notranji polmer" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:39 +msgid "Vehicle Types" +msgstr "Vrste vozil" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:226 -msgid "Inner radius of donut hole" -msgstr "Notranji polmer kolobarja" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:125 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:128 +msgid "Area Chart" +msgstr "Ploščinski grafikon" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:314 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:216 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:177 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:158 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:174 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:232 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:235 -msgid "Input field supports custom rotation. e.g. 30 for 30°" -msgstr "Vnosno polje omogoča poljubno rotacijo (vnesite 30 za 30°)" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:46 +msgid "Continuous" +msgstr "Zvezno" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:90 -msgid "Instant filtering" -msgstr "Takojšnje filtriranje" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:48 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:37 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:40 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:84 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:71 +msgid "Line" +msgstr "Črta" -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:293 -msgid "Instructions to add a dataset are available in the Superset tutorial." -msgstr "Navodila za dodajanje podatkovnega seta so v vodiču za Superset." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:54 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:46 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:39 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:34 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:50 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:31 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:34 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 +msgid "nvd3" +msgstr "nvd3" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:34 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:41 -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:36 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:38 -msgid "Intensity" -msgstr "Intenzivnost" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:55 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:38 +msgid "Deprecated" +msgstr "Zastarelo" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:495 -msgid "Interval End column" -msgstr "Stolpec konca intervala" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:53 +msgid "Series Limit Sort By" +msgstr "Razvrščanje omejitev serije" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:286 -msgid "Interval bounds" -msgstr "Meje intervalov" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:54 +msgid "" +"Metric used to order the limit if a series limit is present. If undefined reverts " +"to the first metric (where appropriate)." +msgstr "" +"Mera, ki določa kako je razvrščena meja, če je določena omejitev serij. Če ni " +"določena, se uporabi prva mera (kjer je to ustrezno)." -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:300 -msgid "Interval colors" -msgstr "Barve intervalov" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:72 +msgid "Series Limit Sort Descending" +msgstr "Razvrsti padajoče" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:477 -msgid "Interval start column" -msgstr "Stolpec začetka intervala" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:74 +msgid "Whether to sort descending or ascending if a series limit is present" +msgstr "" +"Če želite padajoče ali naraščajoče razvrščanje, ko je prisotna omejitev serije" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:280 -msgid "Intervals" -msgstr "Intervali" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:31 +msgid "" +"Visualize how a metric changes over time using bars. Add a group by column to " +"visualize group level metrics and how they change over time." +msgstr "" +"Prikaže spreminjanje mere skozi čas s pomočjo stolpcev. Z dodajanjem stolpcev za " +"združevanje prikaže mere skupin in njihovo spreminjanje." -#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:109 -msgid "Invalid JSON" -msgstr "Neveljaven JSON" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:35 +msgid "Time-series Bar Chart" +msgstr "Stolpčni grafikon za časovno vrsto" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:107 -#, fuzzy -msgid "Invalid Port Number" -msgstr "Število razdelitev" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:38 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:91 +msgid "Bar" +msgstr "Stolpec" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:113 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:117 -#, fuzzy -msgid "Invalid account information" -msgstr "Osnovne informacije" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:42 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:49 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:316 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:90 +msgid "Vertical" +msgstr "Navpično" -#: superset/databases/schemas.py:170 superset/exceptions.py:182 -msgid "Invalid certificate" -msgstr "Neveljaven certifikat" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/BoxPlot/index.js:26 +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:54 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/createMetadata.ts:27 +msgid "Box Plot" +msgstr "Box Plot" -#: superset/views/core.py:1375 -msgid "" -"Invalid connection string, a valid string usually follows:\n" -"'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'" -msgstr "" -"Neveljaven niz povezave, veljaven niz običajno sledi:\n" -"'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:104 +msgid "X Log Scale" +msgstr "Logaritemska X-os" -#: superset/databases/schemas.py:148 -msgid "" -"Invalid connection string, a valid string usually follows: " -"driver://user:password@database-host/database-name" -msgstr "" -"Neveljaven niz povezave - veljaven niz običajno sledi: " -"driver://user:password@database-host/database-name" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:107 +msgid "Use a log scale for the X-axis" +msgstr "Uporabi logaritemsko skalo za X-os" -#: superset/views/database/validators.py:40 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:27 msgid "" -"Invalid connection string, a valid string usually " -"follows:'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-" -"NAME'<p>Example:'postgresql://user:password@your-postgres-" -"db/database'</p>" +"Visualizes a metric across three dimensions of data in a single chart (X axis, Y " +"axis, and bubble size). Bubbles from the same group can be showcased using bubble " +"color." msgstr "" -"Neveljaven niz povezave. Veljaven niz običajno sledi " -"zapisu:'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-" -"NAME'<p>Primer:'postgresql://user:password@your-postgres-db/database'</p>" - -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:52 -msgid "Invalid cron expression" -msgstr "Neveljaven cron izraz" +"Prikaže mero v treh dimenzijah podatkov na istem grafikonu (x os, y os, velikost " +"mehurčka). Mehurčki v isti skupini so predstavljeni z barvo." -#: superset/utils/pandas_postprocessing.py:578 -#, python-format -msgid "Invalid cumulative operator: %(operator)s" -msgstr "Neveljaven kumulativni operand: %(operator)s" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:39 +msgid "Ranges" +msgstr "Razponi" -#: superset/connectors/sqla/views.py:168 superset/datasets/schemas.py:39 -msgid "Invalid date/timestamp format" -msgstr "Neveljaven zapis datuma/časa" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:41 +msgid "Ranges to highlight with shading" +msgstr "Razponi za označitev s senčenjem" -#: superset/viz.py:2123 -msgid "Invalid filter configuration, please select a column" -msgstr "Neveljavna nastavitev filtrov, izberite stolpec" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:48 +msgid "Range labels" +msgstr "Oznake razponov" -#: superset/connectors/sqla/models.py:1326 -#, python-format -msgid "Invalid filter operation type: %(op)s" -msgstr "Neveljaven tip operacije filtra: %(op)s" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:50 +msgid "Labels for the ranges" +msgstr "Oznake za razpone" -#: superset/utils/pandas_postprocessing.py:679 -msgid "Invalid geodetic string" -msgstr "Neveljaven geodetski niz" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:59 +msgid "Markers" +msgstr "Markerji" -#: superset/utils/pandas_postprocessing.py:614 -msgid "Invalid geohash string" -msgstr "Neveljaven niz za geohash" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:61 +msgid "List of values to mark with triangles" +msgstr "Seznam vrednosti, ki bodo markirane s trikotniki" -#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:82 -msgid "Invalid lat/long configuration." -msgstr "Neveljavna nastavitev zemljepisne dolžine/širine." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:68 +msgid "Marker labels" +msgstr "Oznake markerjev" -#: superset/utils/pandas_postprocessing.py:637 -msgid "Invalid longitude/latitude" -msgstr "Neveljavna zemljepisna dolžina/širina" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:70 +msgid "Labels for the markers" +msgstr "Oznake za markerje" -#: superset/utils/core.py:1318 -msgid "Invalid metric object" -msgstr "Neveljaven objekt mere" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:79 +msgid "Marker lines" +msgstr "Markirne črtice" -#: superset/utils/pandas_postprocessing.py:184 -#, python-format -msgid "Invalid numpy function: %(operator)s" -msgstr "Neveljavna numpy funkcija: %(operator)s" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:81 +msgid "List of values to mark with lines" +msgstr "Seznam vrednosti, ki bodo markirane s črticami" -#: superset/utils/pandas_postprocessing.py:414 -#, python-format -msgid "Invalid options for %(rolling_type)s: %(options)s" -msgstr "Neveljavne možnosti za %(rolling_type)s: %(options)s" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:88 +msgid "Marker line labels" +msgstr "Oznake markirnih črtic" -#: superset/common/query_actions.py:192 -#, python-format -msgid "Invalid result type: %(result_type)s" -msgstr "Neveljaven tip rezultata: %(result_type)s" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:90 +msgid "Labels for the marker lines" +msgstr "Oznake za markirne črtice" -#: superset/utils/pandas_postprocessing.py:408 -#, python-format -msgid "Invalid rolling_type: %(type)s" -msgstr "Neveljaven rolling_type: %(type)s" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:25 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:29 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:31 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:47 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:37 +msgid "KPI" +msgstr "KPI" -#: superset/viz.py:2493 -#, python-format -msgid "Invalid spatial point encountered: %s" -msgstr "Neustrezna prostorska točka: %s" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:27 +msgid "" +"Showcases the progress of a single metric against a given target. The higher the " +"fill, the closer the metric is to the target." +msgstr "" +"Prikaže napredovanje posamezne mere glede na cilj. Večja napolnjenost, pomeni, da " +"je mera bližje cilju." -#: superset-frontend/src/filters/components/Select/controlPanel.ts:124 -msgid "Inverse selection" -msgstr "Invertiraj izbiro" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:27 +msgid "" +"Visualizes many different time-series objects in a single chart. This chart is " +"being deprecated and we recommend using the Time-series Chart instead." +msgstr "" +"Prikaže več različnih časovnih vrst na istem grafikonu. Grafikon se opušča, zato " +"priporočamo uporabo Grafikona časovne vrste." -#: superset/connectors/druid/views.py:347 -msgid "Is Hidden" -msgstr "Skrito" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:30 +msgid "Time-series Percent Change" +msgstr "Časovna vrsta - Procentualna sprememba" -#: superset/charts/filters.py:63 superset/dashboards/filters.py:168 -#, fuzzy -msgid "Is certified" -msgstr "Certificiral/a" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:82 +msgid "Sort Bars" +msgstr "Uredi stolpce" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:285 -msgid "Is dimension" -msgstr "Dimenzija" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:85 +msgid "Sort bars by x labels." +msgstr "Uredi stolpce po x-oznakah." -#: superset/views/base_api.py:107 -msgid "Is favorite" -msgstr "Je priljubljen" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:122 +msgid "Breakdowns" +msgstr "Razčlenitev" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:287 -msgid "Is filterable" -msgstr "Filtriranje" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:123 +msgid "Defines how each series is broken down" +msgstr "Določa, kako se vsaka podatkovna serija razčleni" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:286 -#: superset/connectors/sqla/views.py:150 -msgid "Is temporal" -msgstr "Časoven" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:30 +msgid "" +"Compares metrics from different categories using bars. Bar lengths are used to " +"indicate the magnitude of each value and color is used to differentiate groups." +msgstr "" +"Primerjava mer različnih kategorij s pomočjo stolpcev. Dolžina stolpca prestavlja " +"višino vrednosti, z barvami pa so ločene skupine." -#: superset-frontend/src/utils/getClientErrorObject.ts:112 -msgid "Issue 1000 - The dataset is too large to query." -msgstr "Težava 1000 - podatkovni vir je prevelik za poizvedbo." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:38 +msgid "Bar Chart" +msgstr "Stolpčni grafikon" -#: superset-frontend/src/utils/getClientErrorObject.ts:118 -msgid "Issue 1001 - The database is under an unusual load." -msgstr "Težava 1001 - podatkovni vir je neobičajno obremenjen." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:40 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:39 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:43 +msgid "Additive" +msgstr "Aditivno" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 -#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 -#: superset-frontend/src/components/DatabaseSelector/index.tsx:183 -msgid "It seems you don't have access to any database" -msgstr "Zdi se, da nimate dostopa do nobene podatkovne baz" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:44 +msgid "Discrete" +msgstr "Diskretno" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:221 -msgid "It’s not recommended to truncate y-axis in Bar chart." -msgstr "V stolpčnem grafikonu ni priporočljivo omejiti y-osi." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:40 +msgid "Y Axis 1" +msgstr "Y-os 1" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:91 -msgid "JAN" -msgstr "JAN" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:50 +msgid "Y Axis 2" +msgstr "Y-os 2" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:918 -#: superset/connectors/druid/views.py:191 superset/views/log/__init__.py:33 -msgid "JSON" -msgstr "JSON" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:68 +msgid "Left Axis Metric" +msgstr "Mera za levo os" -#: superset/views/annotations.py:81 superset/views/dashboard/mixin.py:89 -msgid "JSON Metadata" -msgstr "JSON metapodatki" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:69 +msgid "Choose a metric for left axis" +msgstr "Izberite mero za levo os" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:584 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:336 -msgid "JSON metadata" -msgstr "JSON metapodatki" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:72 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:166 +msgid "Left Axis Format" +msgstr "Oblika leve osi" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:341 +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:27 msgid "" -"JSON string containing additional connection configuration. This is used " -"to provide connection information for systems like Hive, Presto and " -"BigQuery which do not conform to the username:password syntax normally " -"used by SQLAlchemy." +"Visualizes 2 metrics as line plots using the same x-axis. This chart is useful " +"for comparing metrics across the same time range." msgstr "" -"JSON niz, ki vsebuje dodatno konfiguracijo povezave. Uporablja se za " -"zagotavljanje dodatnih informacij povezave za sisteme kot sta Presto in " -"BigQuery, ki nista skladna s sintakso username:password, ki jo običajno " -"uporablja SQLAlchemy." +"Prikaže dve meri na črtnem grafu z isto x-osjo. Grafikon je uporaben za " +"primerjavo mer v istem časovnem obdobju." -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:97 -msgid "JUL" -msgstr "JUL" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:30 +msgid "Dual Line Chart" +msgstr "Grafikon z dvojno krivuljo" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:96 -msgid "JUN" -msgstr "JUN" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:55 +msgid "Propagate" +msgstr "Razširi" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:66 -msgid "January" -msgstr "Januar" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:58 +msgid "Send range filter events to other charts" +msgstr "Pošlji dogodke filtra obdobja na druge grafikone" -#: superset/views/database/forms.py:177 superset/views/database/forms.py:435 -msgid "" -"Json list of the column names that should be read. If not None, only " -"these columns will be read from the file." -msgstr "" -"JSON seznam imen stolpcev, ki morajo biti prebrani. Če ni prazen, bodo iz" -" datoteke prebrani le ti stolpci." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:32 +msgid "Classic chart that visualizes how metrics change over time." +msgstr "Standardni grafikon za prikaz spreminjanje mere skozi čas." -#: superset/views/database/forms.py:235 superset/views/database/forms.py:368 -msgid "" -"Json list of the values that should be treated as null. Examples: [\"\"]," -" [\"None\", \"N/A\"], [\"nan\", \"null\"]. Warning: Hive database " -"supports only single value. Use [\"\"] for empty string." -msgstr "" -"JSON seznam vrednosti, ki naj bodo obravnavane kot prazne (Null). " -"Primeri: [\"\"], [\"None\", \"N/A\"], [\"nan\", \"null\"]. Opozorilo: " -"Podatkovna baza Hive podpira le eno vrednost. Uporabite [\"\"] za prazen " -"znakovni niz." +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:36 +msgid "Battery level over time" +msgstr "Napolnjenost baterije skozi čas" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:72 -msgid "July" -msgstr "Julij" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:38 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:77 +#: superset-frontend/plugins/preset-chart-xy/src/Line/createMetadata.ts:26 +msgid "Line Chart" +msgstr "Črtni grafikon" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:71 -msgid "June" -msgstr "Junij" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:64 +msgid "Prefix metric name with slice name" +msgstr "Imenu mere pripni ime rezine" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:29 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:30 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:25 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:47 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:37 -msgid "KPI" -msgstr "KPI" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:88 +msgid "Y Axis Left" +msgstr "Y-os levo" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx:56 -msgid "Keep editing" -msgstr "Nadaljuj z urejanjem" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:97 +msgid "Left Axis chart(s)" +msgstr "Grafikoni leve osi" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:157 -msgid "Keys for table" -msgstr "Ključi za tabele" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:100 +msgid "Choose one or more charts for left axis" +msgstr "Izberite enega ali več grafikonov za levo os" -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:149 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:192 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:196 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1037 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1045 -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:157 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:143 -#: superset/views/annotations.py:77 superset/views/sql_lab.py:68 -msgid "Label" -msgstr "Naziv" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:123 +msgid "Y Axis Right" +msgstr "Y-os desno" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:175 -msgid "Label Line" -msgstr "Črta oznake" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:132 +msgid "Right Axis chart(s)" +msgstr "Grafikoni desne osi" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:135 +msgid "Choose one or more charts for right axis" +msgstr "Izberite enega ali več grafikonov za desno os" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:27 +msgid "" +"Visualize two different time series using the same x-axis time range. This chart " +"is being deprecated and we recommend using the Mixed Timeseries Chart instead!" +msgstr "" +"Prikaže dve različni časovni vrsti z isto x-osjo oz. časovnim obdobjem. Grafikon " +"se opušča, zato priporočamo uporabo kombiniranega grafikona časovne vrste!" + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:30 +msgid "Multiple Line Charts" +msgstr "Veččrtni grafikon" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:47 #: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:85 @@ -6835,9025 +7849,8907 @@ msgstr "Črta oznake" msgid "Label Type" msgstr "Oblika oznake" -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:152 -msgid "Label for your query" -msgstr "Ime vaše poizvedbe" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:58 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:102 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:110 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:113 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:103 +msgid "What should be shown on the label?" +msgstr "Kaj bo prikazano na oznaki?" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:123 -msgid "Label position" -msgstr "Položaj oznake" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:220 +msgid "Donut" +msgstr "Kolobar" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:198 -msgid "Label threshold" -msgstr "Prag oznak" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:86 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:223 +msgid "Do you want a donut or a pie?" +msgstr "Želite kolobar ali torto?" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:144 -msgid "Labelling" -msgstr "Oznake" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:96 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:127 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:149 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:94 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:71 +msgid "Show Labels" +msgstr "Pokaži oznake" -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:79 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:93 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:88 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:65 -msgid "Labels" -msgstr "Oznake" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:99 +msgid "" +"Whether to display the labels. Note that the label only displays when the the 5% " +"threshold." +msgstr "" +"Če želite prikazati oznake. Oznake so prikazane le pri vsaj 5-odstotnem pragu." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:90 -msgid "Labels for the marker lines" -msgstr "Oznake za markirne črtice" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:109 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:161 +msgid "Put labels outside" +msgstr "Postavi oznake zunaj" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:70 -msgid "Labels for the markers" -msgstr "Oznake za markerje" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:112 +msgid "Put the labels outside the pie?" +msgstr "Postavim oznake zunaj torte?" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:50 -msgid "Labels for the ranges" -msgstr "Oznake za razpone" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/index.js:27 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:63 +msgid "Pie Chart" +msgstr "Tortni grafikon" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:47 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:81 -#: superset-frontend/src/dashboard/util/headerStyleOptions.ts:35 -msgid "Large" -msgstr "Veliko" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:53 +msgid "Frequency" +msgstr "Frekvenca" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:31 -msgid "Last" -msgstr "Zadnji" +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:65 +msgid "" +"The periodicity over which to pivot time. Users can provide\n" +" \"Pandas\" offset alias.\n" +" Click on the info bubble for more details on accepted \"freq\" " +"expressions." +msgstr "" +"Periodičnost za vrtenje časa. Uporabnik lahko poda\n" +" psevdonim za zamik v \"Pandas\".\n" +" Kliknite na mehurček za podrobnosti dovoljenih izrazov za \"freq\"." + +#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:28 +msgid "Time-series Period Pivot" +msgstr "Časovna serija - Vrtenje periode" + +#: superset-frontend/plugins/plugin-chart-echarts/src/constants.ts:76 +msgid "Stack" +msgstr "Naloži" + +#: superset-frontend/plugins/plugin-chart-echarts/src/constants.ts:77 +msgid "Expand" +msgstr "Razširi" + +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:44 +msgid "Show legend" +msgstr "Prikaži legendo" + +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:47 +msgid "Whether to display a legend for the chart" +msgstr "Če želite prikaz legende za grafikon" + +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:55 +msgid "Margin" +msgstr "Rob" + +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:59 +msgid "Additional padding for legend." +msgstr "Dodatni razmak za legendo." + +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:77 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:97 +msgid "Legend type" +msgstr "Tip legende" -#: superset/connectors/sqla/views.py:492 superset/views/database/mixins.py:193 -msgid "Last Changed" -msgstr "Zadnja sprememba" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:115 +msgid "Show Value" +msgstr "Prikaži vrednost" -#: superset/views/chart/mixin.py:82 -msgid "Last Modified" -msgstr "Zadnja sprememba" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:118 +msgid "Show series values on the chart" +msgstr "Na grafikonu prikaži vrednosti serij" -#: superset-frontend/src/components/LastUpdated/index.tsx:74 -#, python-format -msgid "Last Updated %s" -msgstr "Zadnja posodobitev %s" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:171 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:126 +msgid "Stack series" +msgstr "Nalagaj serije" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:149 -#, python-format -msgid "Last available value seen on %s" -msgstr "Zadnja razpoložljiva vrednost na %s" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:174 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:148 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:129 +msgid "Stack series on top of each other" +msgstr "Nalagaj serije eno na drugo" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:180 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:317 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:158 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:307 -msgid "Last modified" -msgstr "Zadnja sprememba" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:137 +msgid "Only Total" +msgstr "Samo vsota" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:151 -#, python-format -msgid "Last modified by %s" -msgstr "Nazadnje spremenil %s" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:140 +msgid "" +"Only show the total value on the stacked chart, and not show on the selected " +"category" +msgstr "" +"Na naloženem grafikonu prikaži samo skupno vsoto, za izbrane kategorije pa ne" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:228 -msgid "Last run" -msgstr "Zadnji zagon" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:152 +msgid "X-axis" +msgstr "X-os" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:63 -msgid "Latitude" -msgstr "Širina" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:170 +msgid "Dimension to use on x-axis." +msgstr "Dimenzija z x-os." -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:294 -msgid "Latitude of default viewport" -msgstr "Širina privzetega pogleda" +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:81 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:179 +msgid "Percentage threshold" +msgstr "Procentualni prag" -#: superset/views/annotations.py:76 -msgid "Layer" -msgstr "Sloj" +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:183 +msgid "Minimum threshold in percentage points for showing labels." +msgstr "Minimalni prag v odstotnih točkah za prikaz oznak." -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:717 -msgid "Layer configuration" -msgstr "Nastavitve sloja" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:209 +msgid "Rich tooltip" +msgstr "Podroben opis orodja" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:101 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:110 -msgid "Layout" -msgstr "Izgled" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:212 +msgid "Shows a list of all series available at that point in time" +msgstr "Prikaže seznam vseh razpoložljivih podatkovnih serij za istočasno točko" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:114 -msgid "Layout type of graph" -msgstr "Tip izgleda grafikona" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:222 +msgid "Tooltip time format" +msgstr "Oblika zapisa časa v opisu orodja" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:123 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:246 -msgid "Layout type of tree" -msgstr "Način izgleda drevesa" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:232 +msgid "Tooltip sort by metric" +msgstr "Mera za razvrščanje opisa orodja" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:81 -msgid "" -"Leaf nodes that represent fewer than this number of events will be " -"initially hidden in the visualization" -msgstr "" -"Listna vozlišča, ki predstavljajo manjše število dogodkov od te " -"vrednosti, bodo v vizualizaciji skrita" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:235 +msgid "Whether to sort tooltip by the selected metric in descending order." +msgstr "Če želite padajoče razvrstiti opis orodja z izbrano mero." -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:567 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:541 -msgid "Least recently modified" -msgstr "Zadnje spremenjeno" +#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:244 +msgid "Tooltip" +msgstr "Opis orodja" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:111 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:306 -msgid "Left" -msgstr "Levo" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:109 +#, python-format +msgid "Last available value seen on %s" +msgstr "Zadnja razpoložljiva vrednost na %s" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:72 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:166 -msgid "Left Axis Format" -msgstr "Oblika leve osi" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:112 +msgid "Not up to date" +msgstr "Ni posodobljeno" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:68 -msgid "Left Axis Metric" -msgstr "Mera za levo os" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:149 +#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:259 +#: superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx:93 +msgid "No data" +msgstr "Ni podatkov" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:97 -msgid "Left Axis chart(s)" -msgstr "Grafikoni leve osi" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:179 +msgid "No data after filtering or data is NULL for the latest time record" +msgstr "" +"Ni podatkov po filtriranju ali pa imajo vrednost NULL za zadnji časovni zapis" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:187 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:77 -msgid "Left Margin" -msgstr "Levi rob" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:182 +msgid "Try applying different filters or ensuring your datasource has data" +msgstr "" +"Poskusite uporabiti druge filtre oz. zagotovite, da so v podatkovnem viru podatki" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:199 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:81 -msgid "Left margin, in pixels, allowing for more room for axis labels" -msgstr "Levi rob, v pikslih, s katerim povečamo prostor za oznake osi" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:28 +msgid "Big Number Font Size" +msgstr "Velikost pisave Velike številke" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:137 -msgid "Left to Right" -msgstr "Iz leve proti desni" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:35 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:69 +msgid "Tiny" +msgstr "Drobna" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:147 -msgid "Left value" -msgstr "Leva vrednost" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:39 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:73 +#: superset-frontend/src/dashboard/util/headerStyleOptions.ts:25 +msgid "Small" +msgstr "Majhno" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:38 -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:30 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:42 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:33 -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:37 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:31 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:31 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:40 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:43 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:39 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:43 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:47 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:35 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:32 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:31 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:33 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:32 -msgid "Legacy" -msgstr "Staro" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:77 +msgid "Normal" +msgstr "Normalna" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:154 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:275 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:129 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:149 -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:95 -msgid "Legend" -msgstr "Legenda" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:47 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:81 +#: superset-frontend/src/dashboard/util/headerStyleOptions.ts:35 +msgid "Large" +msgstr "Veliko" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:68 -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:88 -msgid "Legend type" -msgstr "Tip legende" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:51 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:85 +msgid "Huge" +msgstr "Ogromna" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:98 -msgid "Lift percent precision" -msgstr "Točnost procentualnega dviga" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts:62 +msgid "Subheader Font Size" +msgstr "Velikost pisave podnaslova" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:30 -msgid "Light mode" -msgstr "Svetli način" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:37 +msgid "Display settings" +msgstr "Nastavitve prikaza" -#: superset-frontend/src/explore/components/RowCountLabel.jsx:45 -msgid "Limit reached" -msgstr "Omejitev dosežena" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:46 +msgid "Subheader" +msgstr "Podnaslov" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:134 -msgid "Limit selector values" -msgstr "Omeji vrednosti izbirnikov" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:48 +msgid "Description text that shows up below your Big Number" +msgstr "Besedilo, ki se prikaže pod veliko številko" -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:44 -msgid "" -"Limiting rows may result in incomplete data and misleading charts. " -"Consider filtering or grouping source/target names instead." -msgstr "" -"Omejitev vrstic lahko povzroči nepopolne podatke in zavajajoč grafikon. " -"Premislite o uporabi filtriranja ali združevanja imen izvorov/ciljev." +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:82 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:151 +msgid "Force date format" +msgstr "Vsili obliko zapisa datuma" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:335 -#: superset-frontend/src/explore/controls.jsx:364 -msgid "Limits the number of rows that get displayed." -msgstr "Omeji število vrstic za prikaz." +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:154 +msgid "Use date formatting even when metric value is not a timestamp" +msgstr "Oblikovanje datuma uporabi tudi, ko vrednost mere ni časovna značka" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:345 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:359 -#: superset-frontend/src/explore/controls.jsx:374 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:30 msgid "" -"Limits the number of series that get displayed. A joined subquery (or an " -"extra phase where subqueries are not supported) is applied to limit the " -"number of series that get fetched and rendered. This feature is useful " -"when grouping by high cardinality column(s) though does increase the " -"query complexity and cost." +"Showcases a single metric front-and-center. Big number is best used to call " +"attention to a KPI or the one thing you want your audience to focus on." msgstr "" -"Omeji število časovnih vrst za prikaz. S podpoizvedbo (ali dodatno fazo, " -"kjer podpoizvedbe niso podprte) se omeji število časovnih vrst, ki bodo " -"pridobljene za prikaz. Ta funkcija je uporabna pri združevanju s stolpci " -"z veliko kardinalnostjo, vendar poveča kompleksnost poizvedbe." - -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:38 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:48 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:37 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:82 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:73 -msgid "Line" -msgstr "Črta" - -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:38 -#: superset-frontend/plugins/preset-chart-xy/src/Line/createMetadata.ts:26 -msgid "Line Chart" -msgstr "Črtni grafikon" - -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:113 -msgid "Line Style" -msgstr "Slog črte" +"Prikaže eno vrednost. Velika številka je primerna za poudarek KPI-ja ali " +"vrednosti, na katero želite usmeriti pozornost." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:124 -msgid "Line interpolation as defined by d3.js" -msgstr "Interpolacija krivulje na osnovi d3.js" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:34 +msgid "A Big Number" +msgstr "Velika številka" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:667 -msgid "Line width" -msgstr "Debelina črte" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:35 +msgid "With a subheader" +msgstr "S podnaslovom" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:190 -msgid "Linear Color Scheme" -msgstr "Linearna barvna shema" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts:41 +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:39 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:45 +msgid "Formattable" +msgstr "Prilagodljiv" -#: superset-frontend/src/explore/controls.jsx:222 -msgid "Linear color scheme" -msgstr "Linearna barvna shema" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:48 +msgid "Comparison Period Lag" +msgstr "Zaostanek obdobja za primerjavo" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:216 -#: superset-frontend/src/views/CRUD/hooks.ts:601 -msgid "Link Copied!" -msgstr "Povezava kopirana!" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:50 +msgid "Based on granularity, number of time periods to compare against" +msgstr "Na osnovi granulacije, število časovnih obdobij za primerjavo" -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:58 -msgid "Link Length" -msgstr "Dolžina povezave" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:61 +msgid "Comparison suffix" +msgstr "Pripona za primerjavo" -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:70 -msgid "Link length in the force layout" -msgstr "Dolžina povezave v postavitvi sil" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:62 +msgid "Suffix to apply after the percentage display" +msgstr "Pripona za prikaz procenta" -#: superset/views/alerts.py:75 -msgid "List Observations" -msgstr "Naštej opažanja" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:71 +msgid "Show Timestamp" +msgstr "Prikaži časovno značko" -#: superset/views/sql_lab.py:39 -msgid "List Saved Query" -msgstr "Seznam shranjenih poizvedb" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:74 +msgid "Whether to display the timestamp" +msgstr "Če želite prikazati časovno značko" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:81 -msgid "List of values to mark with lines" -msgstr "Seznam vrednosti, ki bodo markirane s črticami" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:83 +msgid "Show Trend Line" +msgstr "Pokaži trendno črto" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:61 -msgid "List of values to mark with triangles" -msgstr "Seznam vrednosti, ki bodo markirane s trikotniki" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:86 +msgid "Whether to display the trend line" +msgstr "Če želite prikazati trendno črto" -#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:108 -msgid "Live CSS editor" -msgstr "CSS urejevalnik v živo" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:95 +msgid "Start y-axis at 0" +msgstr "Začni y-os z 0" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:199 -msgid "Live render" -msgstr "Sprotni izris" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:98 +msgid "Start y-axis at zero. Uncheck to start y-axis at minimum value in the data." +msgstr "" +"Začni y-os z nič. Ne izberite, če želite, da se y-os začne z najmanjšo vrednostjo " +"podatkov." -#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:93 -msgid "Load a CSS template" -msgstr "Naloži CSS predlogo" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:109 +msgid "Fix to selected Time Range" +msgstr "Nastavi na izbrano časovno obdobje" -#: superset-frontend/src/components/CachedLabel/TooltipContent.tsx:30 -msgid "Loaded data cached" -msgstr "Podatki so naloženi v predpomnilnik" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx:110 +msgid "" +"Fix the trend line to the full time range specified in case filtered results do " +"not include the start or end dates" +msgstr "" +"Trendno črto nastavite na izbrano obdobje, v primeru, da filtrirani rezultati ne " +"vsebujejo začetnega in/ali končnega datuma" -#: superset-frontend/src/components/CachedLabel/TooltipContent.tsx:34 -msgid "Loaded from cache" -msgstr "Naloženo iz predpomnilnika" +#: superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts:32 +msgid "" +"Showcases a single number accompanied by a simple line chart, to call attention " +"to an important metric along with its change over time or other dimension." +msgstr "" +"Prikaže eno vrednost skupaj s preprostim črtnim grafikonom, za poudarek pomembne " +"mere skupaj z njeno časovno spremembo." -#: superset-frontend/src/components/Select/Select.tsx:603 -#: superset-frontend/src/components/Select/Select.tsx:714 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:110 -msgid "Loading..." -msgstr "Nalagam ..." +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:51 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:45 +msgid "Whisker/outlier options" +msgstr "Možnosti grafikona kvantilov" -#: superset/views/alerts.py:180 -msgid "Log Retentions (days)" -msgstr "Ohranjanje dnevnika (dnevi)" +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:53 +#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:47 +msgid "Determines how whiskers and outliers are calculated." +msgstr "Določa kako so izračunani kvantili in izstopajoče vrednosti." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:204 -msgid "Log Scale" -msgstr "Logaritemska skala" +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:129 +msgid "Categories to group by on the x-axis." +msgstr "Kategorije za združevanje po x-osi." -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1238 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1243 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1244 -msgid "Log retention" -msgstr "Hranjenje dnevnikov" +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:132 +msgid "Distribute across" +msgstr "Porazdeli glede na" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:383 -msgid "Logarithmic scale on primary y-axis" -msgstr "Logaritemska skala na primarni y-osi" +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:134 +msgid "" +"Columns to calculate distribution across. Defaults to temporal column if left " +"empty." +msgstr "" +"Stolpci za izračun porazdelitve. Privzeto je izbran časovni stolpec (če je " +"prazno)." -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:416 -msgid "Logarithmic scale on secondary y-axis" -msgstr "Logaritemska skala na sekundarni y-osi" +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:50 +msgid "" +"Also known as a box and whisker plot, this visualization compares the " +"distributions of a related metric across multiple groups. The box in the middle " +"emphasizes the mean, median, and inner 2 quartiles. The whiskers around each box " +"visualize the min, max, range, and outer 2 quartiles." +msgstr "" +"Znan tudi kot grafikon škatla z brki. prikaže primerjavo porazdelitev povezanih " +"mer v različnih skupinah. Škatla na sredini predstavlja povprečje, mediano in " +"notranja 2 kvartila. Brki na vsaki škatli prikazujejo minimum, maksimum, območje " +"in zunanja dva kvartila." -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:380 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:404 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:413 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:231 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:234 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:194 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:197 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:174 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:177 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:191 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:194 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:247 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:250 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:250 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:253 -msgid "Logarithmic y-axis" -msgstr "Logaritemska y-os" +#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:55 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:47 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:43 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:72 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:61 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:75 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:70 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:42 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:61 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:128 +msgid "ECharts" +msgstr "ECharts" -#: superset-frontend/src/components/Menu/MenuRight.tsx:233 -#: superset/templates/appbuilder/navbar_right.html:126 -msgid "Login" -msgstr "Prijava" +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:79 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:93 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:88 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:65 +msgid "Labels" +msgstr "Oznake" -#: superset-frontend/src/components/Menu/MenuRight.tsx:170 -#: superset/templates/appbuilder/navbar_right.html:111 -msgid "Logout" -msgstr "Odjava" +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:130 +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:152 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:97 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:74 +msgid "Whether to display the labels." +msgstr "Če želite prikaz oznak." -#: superset/views/log/__init__.py:21 -msgid "Logs" -msgstr "Dnevniki" +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:49 +msgid "" +"Showcases how a metric changes as the funnel progresses. This classic chart is " +"useful for visualizing drop-off between stages in a pipeline or lifecycle." +msgstr "" +"Prikaže kako se mera spreminja, ko lijak napreduje. Standardni grafikon za prikaz " +"sprememb med nivoji v procesu ali življenjskem ciklu." -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:53 -msgid "Longitude" -msgstr "Dolžina" +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:52 +msgid "Funnel Chart" +msgstr "Lijakasti grafikon" -#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:168 -msgid "Longitude & Latitude columns" -msgstr "Stolpci zemljepisne dolžine in širine" +#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:58 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:49 +msgid "Sequential" +msgstr "Sekvenčni" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:280 -msgid "Longitude of default viewport" -msgstr "Dolžina privzetega pogleda" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:42 +msgid "Columns to group by" +msgstr "Stolpci za združevanje" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:93 -msgid "MAR" -msgstr "MAR" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:77 +msgid "General" +msgstr "Splošno" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:95 -msgid "MAY" -msgstr "MAJ" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:87 +#: superset-frontend/src/explore/components/controls/BoundsControl.tsx:88 +msgid "Min" +msgstr "Min" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:82 -msgid "MON" -msgstr "PON" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:88 +msgid "Minimum value on the gauge axis" +msgstr "Najmanjša vrednost na številčnici" -#: superset/connectors/sqla/views.py:501 -msgid "Main Datetime Column" -msgstr "Glavni stolpec Datum-Čas" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:99 +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:48 +#: superset-frontend/src/explore/components/controls/BoundsControl.tsx:96 +msgid "Max" +msgstr "Max" -#: superset/views/core.py:1738 -msgid "" -"Malformed request. slice_id or table_name and db_name arguments are " -"expected" -msgstr "" -"Deformirana zahteva. Pričakovani so argumenti slice_id ali table_name in " -"db_name" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:100 +msgid "Maximum value on the gauge axis" +msgstr "Največja vrednost na številčnici" -#: superset/initialization/__init__.py:232 -#: superset/initialization/__init__.py:256 -#: superset/initialization/__init__.py:268 -#: superset/initialization/__init__.py:318 -#: superset/initialization/__init__.py:446 -#: superset/initialization/__init__.py:455 -#: superset/initialization/__init__.py:470 -#: superset/initialization/__init__.py:482 -msgid "Manage" -msgstr "Upravljaj" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:109 +msgid "Start angle" +msgstr "Začetni kot" -#: superset/views/schedules.py:276 -msgid "Manage Email Reports for Charts" -msgstr "Upravljaj e-poštna poročila za grafikone" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:110 +msgid "Angle at which to start progress axis" +msgstr "Kot, pri katerem se začne os območja" -#: superset/views/schedules.py:198 -msgid "Manage Email Reports for Dashboards" -msgstr "Upravljaj e-poštna poročila za nadzorne plošče" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:119 +msgid "End angle" +msgstr "Končni kot" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:726 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:763 -msgid "Mandatory" -msgstr "Obvezno" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:120 +msgid "Angle at which to end progress axis" +msgstr "Kot, pri katerem se konča os območja" -#: superset/views/database/forms.py:171 superset/views/database/forms.py:324 -msgid "Mangle Duplicate Columns" -msgstr "Odstrani podvojene stolpce" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:132 +msgid "Font size" +msgstr "Velikost pisave" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:25 -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:26 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:27 -msgid "Map" -msgstr "Zemljevid" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:133 +msgid "Font size for axis labels, detail value and other text elements" +msgstr "Velikost pisave za oznake osi, podrobnosti in druge besedilne elemente" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:212 -msgid "Map Style" -msgstr "Slog zemljevida" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:164 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:234 +msgid "Value format" +msgstr "Oblika zapisa vrednosti" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:33 -msgid "MapBox" -msgstr "MapBox" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:165 +msgid "Additional text to add before or after the value, e.g. unit" +msgstr "Dodatno besedilo, ki ga dodate pred ali za vrednost, npr. enota" -#: superset/viz.py:2285 -msgid "Mapbox" -msgstr "Mapbox" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:178 +msgid "Show pointer" +msgstr "Prikaži kazalec" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:68 -msgid "March" -msgstr "Marec" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:179 +msgid "Whether to show the pointer" +msgstr "Če želite prikazati kazalec" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:46 -msgid "Margin" -msgstr "Rob" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:190 +msgid "Animation" +msgstr "Animacija" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:211 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:149 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:110 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:90 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:107 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:165 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:168 -msgid "Marker" -msgstr "Marker" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:191 +msgid "Whether to animate the progress and the value or just display them" +msgstr "Če želite animiran prikaz grafikona" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:163 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:124 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:104 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:121 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:179 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:182 -msgid "Marker Size" -msgstr "Velikost markerja" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:199 +msgid "Axis" +msgstr "Os" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:68 -msgid "Marker labels" -msgstr "Oznake markerjev" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:205 +msgid "Show axis line ticks" +msgstr "Prikaži oznake na X-osi" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:88 -msgid "Marker line labels" -msgstr "Oznake markirnih črtic" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:206 +msgid "Whether to show minor ticks on the axis" +msgstr "Če želite prikaz manjših oznak na osi" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:79 -msgid "Marker lines" -msgstr "Markirne črtice" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:217 +msgid "Show split lines" +msgstr "Prikaži razdelitvene črte" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:225 -msgid "Marker size" -msgstr "Velikost markerja" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:218 +msgid "Whether to show the split lines on the axis" +msgstr "Če želite prikazati razdelitvene črte na osi" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:59 -msgid "Markers" -msgstr "Markerji" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:229 +msgid "Split number" +msgstr "Število razdelitev" -#: superset-frontend/src/explore/controlPanels/Separator.js:32 -msgid "Markup type" -msgstr "Tip označevanja" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:230 +msgid "Number of split segments on the axis" +msgstr "Število razdelkov na osi" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:100 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:48 -#: superset-frontend/src/explore/components/controls/BoundsControl.jsx:118 -msgid "Max" -msgstr "Max" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:238 +msgid "Progress" +msgstr "Območje" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:94 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:59 -msgid "Max Bubble Size" -msgstr "Max. velikost mehurčka" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:244 +msgid "Show progress" +msgstr "Prikaži območje" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:129 -msgid "Max Events" -msgstr "Max. dogodkov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:245 +msgid "Whether to show the progress of gauge chart" +msgstr "Prikaži merilno območje števčnega grafikona" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:257 -msgid "Maximize chart" -msgstr "Povečaj grafikon" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:256 +msgid "Overlap" +msgstr "Prekrivanje" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1266 -msgid "Maximum" -msgstr "" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:257 +msgid "Whether the progress bar overlaps when there are multiple groups of data" +msgstr "Če želite prekrivanje območij, ko imate več skupin podatkov" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:68 -msgid "Maximum Font Size" -msgstr "Max. velikost pisave" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:270 +msgid "Round cap" +msgstr "Zaobljeni konci" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:271 +msgid "Style the ends of the progress bar with a round cap" +msgstr "Zaobljena oblika koncev območja" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:101 -msgid "Maximum value on the gauge axis" -msgstr "Največja vrednost na številčnici" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:279 +msgid "Intervals" +msgstr "Intervali" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:70 -msgid "May" -msgstr "Maj" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:285 +msgid "Interval bounds" +msgstr "Meje intervalov" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:93 -msgid "Mean of values over specified period" -msgstr "Povprečna vrednost v dani periodi" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:286 +msgid "" +"Comma-separated interval bounds, e.g. 2,4,5 for intervals 0-2, 2-4 and 4-5. Last " +"number should match the value provided for MAX." +msgstr "" +"Z vejico ločeni intervali, npr. 2,4,5 za intervale 0-2, 2-4 in 4-5. Zadnja " +"številka naj bo enaka vrednosti za MAX." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:230 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:299 +msgid "Interval colors" +msgstr "Barve intervalov" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:300 msgid "" -"Median edge width, the thickest edge will be 4 times thicker than the " -"thinnest." +"Comma-separated color picks for the intervals, e.g. 1,2,4. Integers denote colors " +"from the chosen color scheme and are 1-indexed. Length must be matching that of " +"interval bounds." msgstr "" -"Mediana debeline povezave. Najdebelejša povezava bo 4-krat debelejša od " -"najtanjše." +"Z vejico ločene barve za intervale, npr. 1,2,4. Cela števila predstavljajo barve " +"iz barvne sheme (začnejo se z 1). Dolžina mora ustrezati mejam intervala." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:217 +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:39 msgid "" -"Median node size, the largest node will be 4 times larger than the " -"smallest" +"Uses a gauge to showcase progress of a metric towards a target. The position of " +"the dial represents the progress and the terminal value in the gauge represents " +"the target value." msgstr "" -"Mediana velikosti vozlišča. Največje vozlišče bo 4-krat večje od " -"najmanjšega" +"Uporablja števec za prikaz napredovanja mere k ciljni vrednosti. Položaj kazalca " +"predstavlja napredek, končna vrednost na števcu pa ciljno vrednost." -#: superset-frontend/src/dashboard/util/headerStyleOptions.ts:30 -msgid "Medium" -msgstr "Srednje" +#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:42 +msgid "Gauge Chart" +msgstr "Števčni grafikon" -#: superset-frontend/src/components/ReportModal/index.tsx:275 -msgid "Message Content" -msgstr "Vsebina sporočila" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:53 +msgid "Name of the source nodes" +msgstr "Imena izvornih vozlišč" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1292 -msgid "Message content" -msgstr "Vsebina sporočila" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:63 +msgid "Name of the target nodes" +msgstr "Imena ciljnih vozlišč" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:105 -msgid "Metadata" -msgstr "Metapodatki" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:73 +msgid "Source category" +msgstr "Kategorija izvora" -#: superset/connectors/druid/views.py:240 -msgid "Metadata Last Refreshed" -msgstr "Meta-podatki nazadnje osveženi" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:74 +msgid "" +"The category of source nodes used to assign colors. If a node is associated with " +"more than one category, only the first will be used." +msgstr "" +"Kategorija izvornih vozlišč, na podlagi katere je določena barva. Če je vozlišče " +"povezano z več kot eno kategorijo, bo uporabljena samo prva." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:437 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:442 -msgid "Metadata Parameters" -msgstr "Parametri metapodatkov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:86 +msgid "Target category" +msgstr "Kategorija cilja" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:617 -msgid "Metadata has been synced" -msgstr "Metapodatki so sinhronizirani" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:87 +msgid "Category of target nodes" +msgstr "Kategorija ciljnih vozlišč" -#: superset/connectors/sqla/views.py:602 -#, python-format -msgid "Metadata refreshed for the following table(s): %(tables)s" -msgstr "Metapodatki osveženi za naslednje tabele: %(tables)s" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:96 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:107 +msgid "Chart options" +msgstr "Možnosti grafikona" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:378 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:261 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:506 -#: superset-frontend/src/explore/controlPanels/sections.tsx:268 -msgid "Method" -msgstr "Metoda" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:101 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:110 +msgid "Layout" +msgstr "Izgled" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:113 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:114 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:151 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:152 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:84 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:97 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1036 -#: superset-frontend/src/explore/controls.jsx:167 -#: superset-frontend/src/explore/controls.jsx:168 -#: superset/connectors/druid/views.py:187 superset/connectors/sqla/views.py:255 -msgid "Metric" -msgstr "Mera" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:108 +msgid "Graph layout" +msgstr "Izgled grafikona" -#: superset/connectors/sqla/models.py:1079 -#: superset/connectors/sqla/models.py:1509 -#, python-format -msgid "Metric '%(metric)s' does not exist" -msgstr "Mera '%(metric)s' ne obstaja" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:111 +msgid "Force" +msgstr "Sila" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:38 -msgid "Metric ascending" -msgstr "Naraščajoča mera" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:114 +msgid "Layout type of graph" +msgstr "Tip izgleda grafikona" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:148 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:407 -#: superset-frontend/src/explore/controls.jsx:422 -msgid "Metric assigned to the [X] axis" -msgstr "Mera za [X] os" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:124 +msgid "Edge symbols" +msgstr "Simboli povezav" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:154 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:415 -#: superset-frontend/src/explore/controls.jsx:430 -msgid "Metric assigned to the [Y] axis" -msgstr "Mera za [Y] os" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:125 +msgid "Symbol of two ends of edge line" +msgstr "Simbol za konca povezave" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:103 -msgid "Metric change in value from `since` to `until`" -msgstr "Sprememba mere od vrednosti \"OD\" do \"DO\"" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:128 +msgid "None -> None" +msgstr "Brez -> Brez" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:39 -msgid "Metric descending" -msgstr "Padajoča mera" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:129 +msgid "None -> Arrow" +msgstr "Brez -> Puščica" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:117 -msgid "Metric factor change from `since` to `until`" -msgstr "Sprememba faktorja mere od vrednosti \"OD\" do \"DO\"" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:130 +msgid "Circle -> Arrow" +msgstr "Krog -> Puščica" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:119 -msgid "Metric for Color" -msgstr "Mera za barvo" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:131 +msgid "Circle -> Circle" +msgstr "Krog -> Krog" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:98 -msgid "Metric for node values" -msgstr "Mera za vrednosti vozlišč" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:141 +msgid "Enable node dragging" +msgstr "Omogoči premikanje vozlišč" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:658 -#, python-format -msgid "Metric name [%s] is duplicated" -msgstr "Ime mere [%s] je podvojeno" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:144 +msgid "Whether to enable node dragging in force layout mode." +msgstr "Če želite omogočiti premikanje vozlišč v načinu vsiljenega prikaza." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:110 -msgid "Metric percent change in value from `since` to `until`" -msgstr "Procentualna sprememba mere od vrednosti \"OD\" do \"DO\"" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:161 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:270 +msgid "Enable graph roaming" +msgstr "Omogoči preoblikovanje grafikona" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:120 -msgid "Metric that defines the color of the country" -msgstr "Mera, ki določa barvo države" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:165 +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:185 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:274 +msgid "Disabled" +msgstr "Onemogočeno" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:124 -msgid "Metric that defines the size of the bubble" -msgstr "Mera, ki določa velikost mehurčka" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:166 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:275 +msgid "Scale only" +msgstr "Samo povečava" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:85 -msgid "Metric to display bottom title" -msgstr "Mera za prikaz spodnjega naslova" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:167 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:276 +msgid "Move only" +msgstr "Samo premikanje" -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:185 -msgid "Metric to sort the results by" -msgstr "Mera za razvrščanje rezultatov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:168 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:277 +msgid "Scale and Move" +msgstr "Povečava in premikanje" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:142 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:421 -msgid "Metric used to calculate bubble size" -msgstr "Mera za izračun velikosti mehurčkov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:170 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:279 +msgid "Whether to enable changing graph position and scaling." +msgstr "Če želite omogočiti premikanje in povečevanje/zmanjševanje grafikona." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:127 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:371 -#: superset-frontend/src/explore/controls.jsx:387 -msgid "" -"Metric used to define how the top series are sorted if a series or row " -"limit is present. If undefined reverts to the first metric (where " -"appropriate)." -msgstr "" -"Mera, ki določa kako so razvrščene prve serije, če je določena omejitev " -"serij ali vrstic. Če ni določena, se uporabi prva mera (kjer je " -"ustrezno)." +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:182 +msgid "Node select mode" +msgstr "Način izbire vozlišč" -#: superset/connectors/druid/models.py:1072 -msgid "Metric(s) {} must be aggregations." -msgstr "Mere {} morajo biti agregacije." +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:186 +msgid "Single" +msgstr "Posamezno" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:99 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:137 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1196 -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:301 -#: superset-frontend/src/explore/controls.jsx:152 -#: superset/connectors/druid/views.py:159 superset/connectors/sqla/views.py:212 -msgid "Metrics" -msgstr "Mere" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:187 +msgid "Multiple" +msgstr "Več" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:148 -msgid "" -"Metrics for which percentage of total are to be displayed. Calculated " -"from only data within the row limit." -msgstr "" -"Mera, za katero je prikazan odstotek od celote. Izračunan je samo iz " -"podatkov znotraj omejitve števila vrstic." +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:189 +msgid "Allow node selections" +msgstr "Dovoli izbiro vozlišča" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:93 -msgid "Midnight" -msgstr "Polnoč" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:198 +msgid "Label threshold" +msgstr "Prag oznak" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:88 -#: superset-frontend/src/explore/components/controls/BoundsControl.jsx:112 -msgid "Min" -msgstr "Min" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:202 +msgid "Minimum value for label to be displayed on graph." +msgstr "Najmanjša vrednost, za katero bo na grafikonu prikazana oznaka." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:290 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:173 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:193 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:424 -msgid "Min Periods" -msgstr "Min. št. period" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:213 +msgid "Node size" +msgstr "Velikost vozlišča" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:90 -msgid "Min Width" -msgstr "Min. širina" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:217 +msgid "Median node size, the largest node will be 4 times larger than the smallest" +msgstr "" +"Mediana velikosti vozlišča. Največje vozlišče bo 4-krat večje od najmanjšega" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:73 -#: superset-frontend/src/explore/controlPanels/sections.tsx:189 -msgid "Min periods" -msgstr "Min. št. period" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:226 +msgid "Edge width" +msgstr "Debelina povezave" -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:170 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:167 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:278 -msgid "Mine" -msgstr "Moje" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:230 +msgid "" +"Median edge width, the thickest edge will be 4 times thicker than the thinnest." +msgstr "" +"Mediana debeline povezave. Najdebelejša povezava bo 4-krat debelejša od najtanjše." -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:257 -msgid "Minimize chart" -msgstr "Pomanjšaj grafikon" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:241 +msgid "Edge length" +msgstr "Dolžina povezave" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1260 -#, fuzzy -msgid "Minimum" -msgstr "minuta" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:247 +msgid "Edge length between nodes" +msgstr "Dolžina povezave med vozlišči" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:57 -msgid "Minimum Font Size" -msgstr "Min. velikost pisave" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:262 +msgid "Gravity" +msgstr "Gravitacija" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:78 -msgid "Minimum leaf node event count" -msgstr "Min. število dogodkov za list" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:268 +msgid "Strength to pull the graph toward center" +msgstr "Sila privlačnosti med grafikonom in središčem" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:85 -msgid "Minimum threshold in percentage points for showing labels." -msgstr "Minimalni prag v odstotnih točkah za prikaz oznak." +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:283 +msgid "Repulsion" +msgstr "Odbijanje" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:202 -msgid "Minimum value for label to be displayed on graph." -msgstr "Najmanjša vrednost, za katero bo na grafikonu prikazana oznaka." +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:289 +msgid "Repulsion strength between nodes" +msgstr "Odbojna sila med vozlišči" + +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:304 +msgid "Friction" +msgstr "Trenje" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:89 -msgid "Minimum value on the gauge axis" -msgstr "Najmanjša vrednost na številčnici" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:310 +msgid "Friction between nodes" +msgstr "Trenje med vozlišči" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:328 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:243 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:206 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:186 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:203 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:259 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:262 -msgid "Minor Split Line" -msgstr "Manjša ločilna črta" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:34 +msgid "" +"Displays connections between entities in a graph structure. Useful for mapping " +"relationships and showing which nodes are important in a network. Graph charts " +"can be configured to be force-directed or circulate. If your data has a " +"geospatial component, try the deck.gl Arc chart." +msgstr "" +"Prikaže povezave med entitetami v strukturi grafa. Uporabno za prikaz razmerij in " +"pomembnih točk v omrežju. Grafikon je lahko krožnega tipa ali z usmerjenimi " +"silami. Če imajo podatki geoprostorsko komponento, poskusite grafikon decl.gl - " +"Arc." -#: superset/db_engine_specs/base.py:89 -msgid "Minute" -msgstr "Minuta" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:37 +msgid "Graph Chart" +msgstr "Graf" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:64 -#, fuzzy, python-format -msgid "Minutes %s" -msgstr "minuta" +#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:45 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:45 +msgid "Structural" +msgstr "Strukturni" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:93 -#, fuzzy -msgid "Missing Required Fields" -msgstr "Zahtevano je ime" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:150 +msgid "Series type" +msgstr "Tip serije" -#: superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.tsx:34 -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:251 -msgid "Missing dataset" -msgstr "Manjka podatkovni set" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:162 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:117 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:118 +msgid "Series chart type (line, bar etc)" +msgstr "Tip grafikona za posamezno podatkovno serijo (črtni, stolpčni, ...)" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:67 -msgid "Mixed Time-Series" -msgstr "Kombiniran grafikon časovne vrste" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:183 +msgid "Area chart" +msgstr "Ploščinski grafikon" -#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:128 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:312 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:309 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:359 -#: superset/connectors/druid/views.py:355 superset/connectors/sqla/views.py:371 -#: superset/connectors/sqla/views.py:506 superset/views/dashboard/mixin.py:86 -#: superset/views/dashboard/views.py:158 superset/views/database/mixins.py:202 -#: superset/views/sql_lab.py:72 -msgid "Modified" -msgstr "Spremenjeno" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:186 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:128 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:131 +msgid "Draw area under curves. Only applicable for line types." +msgstr "Izriši površino pod krivuljo. Samo za črtne grafikone." -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:155 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:164 -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:130 -#, python-format -msgid "Modified %s" -msgstr "Zadnja sprememba %s" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:217 +msgid "Opacity of area chart." +msgstr "Prosojnost ploščinskega grafikona." -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:303 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:291 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:319 -msgid "Modified by" -msgstr "Spremenil" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:226 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:174 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:83 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:100 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:158 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:161 +msgid "Marker" +msgstr "Marker" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:604 -#, python-format -msgid "Modified columns: %s" -msgstr "Spremenjeni stolpci: %s" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:229 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:177 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:86 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:103 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:161 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:164 +msgid "Draw a marker on data points. Only applicable for line types." +msgstr "Nariši markerje na točke grafikona. Samo za črtne grafikone." -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:57 -msgid "Monday" -msgstr "Ponedeljek" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:240 +msgid "Marker size" +msgstr "Velikost markerja" -#: superset/db_engine_specs/base.py:98 -msgid "Month" -msgstr "Mesec" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:245 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:193 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:102 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:119 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:177 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:180 +msgid "Size of marker. Also applies to forecast observations." +msgstr "Velikost markerja. Upošteva se tudi za napovedi." -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:68 -#, fuzzy, python-format -msgid "Months %s" -msgstr "mesec" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:258 +msgid "Primary" +msgstr "Primarna" -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:238 -msgid "More dataset related options" -msgstr "Več nastavitev za podatkovni set" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:259 +msgid "Secondary" +msgstr "Sekundarna" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:167 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:276 -msgid "Move only" -msgstr "Samo premikanje" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:264 +msgid "Primary or secondary y-axis" +msgstr "Primarna ali sekundarna y-os" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:43 -msgid "Moves the given set of dates by a specified interval." -msgstr "Premakne dani nabor datumov za definirano obdobje." +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:296 +msgid "Shared query fields" +msgstr "Polja deljenih poizvedb" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:40 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:32 -msgid "Multi-Dimensions" -msgstr "Večdimenzionalni" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:301 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:312 +msgid "Query A" +msgstr "Poizvedba A" -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:34 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:41 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:37 -msgid "Multi-Layers" -msgstr "Večplastni" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:302 +msgid "Advanced analytics Query A" +msgstr "Poizvedba A za napredno analitiko" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:44 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:43 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:62 -msgid "Multi-Levels" -msgstr "Večplastni" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:303 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:313 +msgid "Query B" +msgstr "Poizvedba B" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:42 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:32 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:44 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:74 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:58 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:30 -msgid "Multi-Variables" -msgstr "Več spremenljivk" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:304 +msgid "Advanced analytics Query B" +msgstr "Poizvedba B za napredno analitiko" + +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:319 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:206 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:347 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:115 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:132 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:190 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:193 +msgid "Data Zoom" +msgstr "Zoom funkcija" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:187 -msgid "Multiple" -msgstr "Več" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:322 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:209 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:350 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:118 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:135 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:193 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:196 +msgid "Enable data zooming controls" +msgstr "Omogoči kontrolnik za povečavo podatkov" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:30 -msgid "Multiple Line Charts" -msgstr "Veččrtni grafikon" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:336 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:234 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:144 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:160 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:218 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:221 +msgid "Rotate x axis label" +msgstr "Zavrti oznako x-osi" -#: superset/views/database/views.py:439 -msgid "" -"Multiple file extensions are not allowed for columnar uploads. Please " -"make sure all files are of the same extension." -msgstr "" -"Za nalaganje stolpčnih datotek niso dovoljene različne končnice. " -"Poskrbite, da imajo vse datoteke enake končnice." +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:343 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:241 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:181 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:151 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:167 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:225 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:228 +msgid "Input field supports custom rotation. e.g. 30 for 30°" +msgstr "Vnosno polje omogoča poljubno rotacijo (vnesite 30 za 30°)" -#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:185 -msgid "" -"Multiple formats accepted, look the geopy.points Python library for more " -"details" -msgstr "" -"Sprejema različne zapise - podrobnosti najdete v Pythonovi knjižnici " -"geopy.points" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:357 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:268 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:219 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:179 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:196 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:252 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:255 +msgid "Minor Split Line" +msgstr "Manjša ločilna črta" -#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:59 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:77 -msgid "Multiple select" -msgstr "Več izborov" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:360 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:271 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:182 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:199 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:255 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:258 +msgid "Draw split lines for minor y-axis ticks" +msgstr "Izriši ločilne črte za pomožne oznake y-osi" -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:218 -msgid "Multiple selections allowed, otherwise filter is limited to a single value" -msgstr "Lahko izberete več elementov, drugače pa je filter omejen na eno vrednost" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:369 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:280 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:191 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:208 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:264 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:267 +msgid "Truncate Y Axis" +msgstr "Prireži Y-os" -#: superset/dashboards/commands/exceptions.py:39 -msgid "Must be unique" -msgstr "Mora biti unikaten" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:372 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:283 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:194 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:211 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:267 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:270 +msgid "Truncate Y Axis. Can be overridden by specifying a min or max bound." +msgstr "" +"Prireži Y-os. Če določite spodnjo ali zgornjo mejo, preprečite prirezovanje." -#: superset/viz.py:2309 -msgid "Must have a [Group By] column to have 'count' as the [Label]" -msgstr "Mora imeti stolpec [Združevanje], da ima število (count) kot [Oznaka]" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:400 +msgid "Primary y-axis format" +msgstr "Oblika primarne y-osi" -#: superset/viz.py:1720 -msgid "Must have at least one numeric column specified" -msgstr "Definiran mora biti vsaj en numerični stolpec" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:409 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:433 +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:442 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:256 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:259 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:167 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:170 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:184 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:187 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:240 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:243 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:243 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:246 +msgid "Logarithmic y-axis" +msgstr "Logaritemska y-os" -#: superset/connectors/sqla/models.py:1303 -msgid "Must specify a value for filters with comparison operators" -msgstr "Potrebno je podati vrednost za filter s primerjalnim operandom" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:412 +msgid "Logarithmic scale on primary y-axis" +msgstr "Logaritemska skala na primarni y-osi" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx:47 -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.jsx:59 -#, fuzzy -msgid "My column" -msgstr "stolpec" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:421 +msgid "Secondary y-axis format" +msgstr "Oblika sekundarne y-osi" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.jsx:73 -msgid "My metric" -msgstr "Moja mera" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:430 +msgid "Secondary y-axis title" +msgstr "Naslov sekundarne y-osi" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:76 -msgid "N/A" -msgstr "N/A" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:445 +msgid "Logarithmic scale on secondary y-axis" +msgstr "Logaritemska skala na sekundarni y-osi" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:101 -msgid "NOV" -msgstr "NOV" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:61 +msgid "" +"Visualize two different series using the same x-axis. Note that both series can " +"be visualized with a different chart type (e.g. 1 using bars and 1 using a line)." +msgstr "" +"Prikaže dva različna niza na isti x-osi. Niza sta lahko prikazana z različnim " +"tipom grafikona (npr. en s stolpci in drug s črto)." -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:232 -msgid "NOW" -msgstr "ZDAJ" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:64 +msgid "" +"Visualize two different time series using the same x-axis. Note that each time " +"series can be visualized differently (e.g. 1 using bars and 1 using a line)." +msgstr "" +"Prikaže dve različni časovni vrsti na isti x-osi. Časovni vrsti sta lahko " +"prikazani različno (npr. ena s stolpci in druga s črto)." -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:72 -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:123 -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:211 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:230 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:232 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:722 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:233 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:131 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:131 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:279 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:273 -#: superset/views/annotations.py:126 superset/views/chart/mixin.py:86 -msgid "Name" -msgstr "Ime" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:74 +msgid "Mixed Chart" +msgstr "Kombinirani grafikon" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:779 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:785 -msgid "Name is required" -msgstr "Zahtevano je ime" +#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:75 +msgid "Mixed Time-Series" +msgstr "Kombiniran grafikon časovne vrste" -#: superset/annotation_layers/commands/exceptions.py:66 -#: superset/reports/commands/exceptions.py:167 -msgid "Name must be unique" -msgstr "Ime mora biti unikatno" +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:164 +msgid "Put the labels outside of the pie?" +msgstr "Postavim oznake zunaj torte?" -#: superset/views/database/forms.py:380 -msgid "Name of table to be created from columnar data." -msgstr "Ime tabele, ki bo ustvarjena iz podatkov v stolpcih." +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:175 +msgid "Label Line" +msgstr "Črta oznake" -#: superset/views/database/forms.py:96 -msgid "Name of table to be created from csv data." -msgstr "Ime tabele, ki bo ustvarjena iz CSV podatkov." +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:178 +msgid "Draw line from Pie to label when labels outside?" +msgstr "Ali želite črto do oznake, ko so le-te zunaj?" -#: superset/views/database/forms.py:247 -msgid "Name of table to be created from excel data." -msgstr "Ime tabele, ki bo ustvarjena iz Excel-ovih podatkov." +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:191 +msgid "Show Total" +msgstr "Pokaži vsoto" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:61 -msgid "Name of the column containing the id of the parent node" -msgstr "Ime stolpca, ki vsebuje id nadrejenega vozlišča" +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:194 +msgid "Whether to display the aggregate count" +msgstr "Če želite prikazati agregirano število" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:51 -msgid "Name of the id column" -msgstr "Naziv id-stolpca" +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:199 +msgid "Pie shape" +msgstr "Oblika torte" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:53 -msgid "Name of the source nodes" -msgstr "Imena izvornih vozlišč" +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:205 +msgid "Outer Radius" +msgstr "Zunanji polmer" -#: superset/connectors/sqla/views.py:439 -msgid "Name of the table that exists in the source database" -msgstr "Ime tabele, ki obstaja v izvorni podatkovni bazi" +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:211 +msgid "Outer edge of Pie chart" +msgstr "Zunanji rob tortnega grafikona" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:63 -msgid "Name of the target nodes" -msgstr "Imena ciljnih vozlišč" +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:232 +msgid "Inner Radius" +msgstr "Notranji polmer" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:51 -msgid "Name your database" -msgstr "Poimenujte podatkovno bazo" +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:238 +msgid "Inner radius of donut hole" +msgstr "Notranji polmer kolobarja" -#: superset-frontend/src/chart/chartReducer.ts:106 -#: superset-frontend/src/chart/chartReducer.ts:170 -msgid "Network error." -msgstr "Napaka omrežja." +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:54 +msgid "" +"The classic. Great for showing how much of a company each investor gets, what " +"demographics follow your blog, or what portion of the budget goes to the military " +"industrial complex.\n" +"\n" +" Pie charts can be difficult to interpret precisely. If clarity of " +"relative proportion is important, consider using a bar or other chart type " +"instead." +msgstr "" +"Standardni grafikon za prikaz deležev. Tortne grafikone je težje natančno " +"interpretirati, takrat lahko uporabite npr. stolpčni grafikon." -#: superset/templates/appbuilder/navbar_right.html:35 -msgid "New" -msgstr "Nov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts:319 +#, python-format +msgid "Total: %s" +msgstr "Vsota: %s" -#: superset-frontend/src/components/ReportModal/index.tsx:251 -msgid "New Email Report" -msgstr "Novo e-poštno poročilo" +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:49 +msgid "The maximum value of metrics. It is an optional configuration" +msgstr "Največja vrednost mere. To je opcijska nastavitev" -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:61 -msgid "New chart" -msgstr "Nov grafikon" +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:123 +msgid "Label position" +msgstr "Položaj oznake" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:614 -#, python-format -msgid "New columns added: %s" -msgstr "Dodani novi stolpci: %s" +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:161 +msgid "Radar" +msgstr "Radar" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx:81 -msgid "New filter set" -msgstr "Nov set filtrov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:167 +msgid "Customize Metrics" +msgstr "Prilagodi mere" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:327 -msgid "New tab" -msgstr "Nov zavihek" +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:168 +msgid "Further customize how to display each metric" +msgstr "Dodatne prilagoditve prikaza posameznih mer" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:420 -msgid "New tab (Ctrl + q)" -msgstr "Nov zavihek (Ctrl + q)" +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:201 +msgid "Circle radar shape" +msgstr "Okrogla oblika radarja" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:421 -msgid "New tab (Ctrl + t)" -msgstr "Nov zavihek (Ctrl + t)" +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:204 +msgid "Radar render type, whether to display 'circle' shape." +msgstr "Način prikaza radarja - če se prikaže okrogla oblika." -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:133 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:113 -msgid "Next" -msgstr "Naslednji" +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:50 +msgid "" +"Visualize a parallel set of metrics across multiple groups. Each group is " +"visualized using its own line of points and each metric is represented as an edge " +"in the chart." +msgstr "" +"Prikaže vzporedni nabor mer za različne skupine. Vsaka skupina je prikazana s " +"svojim naborom točk in vsaka mera s povezavo na grafikonu." -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:29 -msgid "Nightingale Rose Chart" -msgstr "Nightingale Rose grafikon" +#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:53 +msgid "Radar Chart" +msgstr "Radarski grafikon" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:444 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:538 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:441 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:512 -msgid "No" -msgstr "Ne" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:73 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:280 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:65 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:71 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:72 +msgid "Contribution Mode" +msgstr "Način deležev" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:74 -#, python-format -msgid "No %(tableName)s yet" -msgstr "" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:80 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:287 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:72 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:78 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:79 +msgid "Calculate contribution per series or row" +msgstr "Izračunaj delež za serijo ali vrstico" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:376 -#, python-format -msgid "No %s yet" -msgstr "%s še ne obstajajo" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:107 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:106 +msgid "Series Style" +msgstr "Slog serije" -#: superset/templates/superset/request_access.html:20 -msgid "No Access!" -msgstr "Ni dostopa!" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:126 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:139 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:142 +msgid "Area chart opacity" +msgstr "Prosojnost ploščinskega grafikona" -#: superset-frontend/src/components/ListView/ListView.tsx:398 -msgid "No Data" -msgstr "Ni podatkov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:132 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:145 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:148 +msgid "Opacity of Area Chart. Also applies to confidence band." +msgstr "Prosojnost ploščinskega grafikona. Upošteva se tudi za interval zaupanja." -#: superset-frontend/packages/superset-ui-core/src/chart/components/NoResultsComponent.tsx:75 -msgid "No Results" -msgstr "Ni rezultatov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:188 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:97 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:114 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:172 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:175 +msgid "Marker Size" +msgstr "Velikost markerja" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:328 -msgid "No annotation layers yet" -msgstr "Slojev z oznakami še ni" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:52 +msgid "" +"Swiss army knife for visualizing data. Choose between step, line, scatter, and " +"bar charts. This viz type has many customization options as well." +msgstr "" +"Univerzalni grafikon za vizualizacijo podatkov. Izbirajte med stopničastimi, " +"črtnimi, raztresenimi in stolpčnimi grafikoni. Grafikon ima širok nabor " +"prilagoditev." -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:254 -msgid "No annotation yet" -msgstr "Oznak še ni" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:55 +msgid "" +"Swiss army knife for visualizing time series data. Choose between step, line, " +"scatter, and bar charts. This viz type has many customization options as well." +msgstr "" +"Univerzalni grafikon za prikaz časovnih vrst. Izbirajte med stopničnimi, črtnimi, " +"raztresenimi in stolpčnimi grafikoni. Grafikon ima širok nabor prilagoditev." -#: superset-frontend/src/profile/components/CreatedContent.tsx:45 -msgid "No charts" -msgstr "Ni grafikonov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:66 +msgid "Generic Chart" +msgstr "Generičen grafikon" -#: superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx:82 -msgid "No columns" -msgstr "Brez stolpcev" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:67 +msgid "Time-series Chart" +msgstr "Grafikon časovne vrste" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:134 -msgid "No compatible columns found" -msgstr "Ni najdenih skladnih stolpcev" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts:408 +msgid "zoom area" +msgstr "približaj območje" -#: superset-frontend/src/profile/components/CreatedContent.tsx:63 -msgid "No dashboards" -msgstr "Ni nadzornih plošč" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts:409 +msgid "restore zoom" +msgstr "ponastavi prikaz" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:189 -#: superset-frontend/src/explore/components/DataTablesPane/index.tsx:146 -#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:255 -#: superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx:91 -msgid "No data" -msgstr "Ni podatkov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:58 +msgid "" +"Area charts are similar to line charts in that they represent variables with the " +"same scale, but area charts stack the metrics on top of each other." +msgstr "" +"Ploščinski grafikoni so podobni črtnim grafikonom, saj predstavljajo " +"spremenljivke v istem razmerju, vendar se pri ploščinskih grafikonih mere " +"nalagajo ena na drugo." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:219 -msgid "No data after filtering or data is NULL for the latest time record" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:61 +msgid "" +"Time-series Area chart are similar to line chart in that they represent variables " +"with the same scale, but area charts stack the metrics on top of each other. An " +"area chart in Superset can be stream, stack, or expand." msgstr "" -"Ni podatkov po filtriranju ali pa imajo vrednost NULL za zadnji časovni " -"zapis" +"Ploščinski grafikoni časovne vrste so podobni črtnim grafikonom, saj " +"predstavljajo spremenljivke v istem razmerju, vendar se pri ploščinskih " +"grafikonih mere nalagajo ena na drugo." -#: superset/dashboards/commands/importers/v0.py:321 -msgid "No data in file" -msgstr "V datoteki ni podatkov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:72 +msgid "Area Chart v2" +msgstr "Ploščinski grafikon v2" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:752 -msgid "No description available." -msgstr "Opisa ni na razpolago." +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:73 +msgid "Time-series Area Chart" +msgstr "Ploščinski grafikon časovne vrste" -#: superset-frontend/src/profile/components/Favorites.tsx:46 -msgid "No favorite charts yet, go click on stars!" -msgstr "Priljubljenih grafikonov še ni. Kliknite na zvezdice!" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:69 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:100 +msgid "Axis Title" +msgstr "Naslov osi" -#: superset-frontend/src/profile/components/Favorites.tsx:64 -msgid "No favorite dashboards yet, go click on stars!" -msgstr "Priljubljenih nadzornih plošč še ni. Kliknite na zvezdice!" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:85 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:116 +msgid "AXIS TITLE MARGIN" +msgstr "OBROBA OZNAKE OSI" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:313 -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:35 -#: superset-frontend/src/explore/controls.jsx:342 -msgid "No filter" -msgstr "Brez filtra" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:133 +msgid "AXIS TITLE POSITION" +msgstr "POLOŽAJ OZNAKE OSI" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:483 -msgid "No filter is selected." -msgstr "Noben filter ni izbran." +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:174 +msgid "Rotate axis label" +msgstr "Zavrti oznako osi" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:86 -msgid "No of Bins" -msgstr "Št. razdelkov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:194 +msgid "Axis Format" +msgstr "Oblika osi" -#: superset-frontend/src/SqlLab/components/QueryHistory/index.tsx:49 -msgid "No query history yet..." -msgstr "Zgodovine poizvedb še ni." +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:205 +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:208 +msgid "Logarithmic axis" +msgstr "Logaritemska os" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:494 -#: superset/templates/appbuilder/general/widgets/base_list.html:64 -msgid "No records found" -msgstr "Ni zapisov" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:222 +msgid "Draw split lines for minor axis ticks" +msgstr "Izriši ločilne črte za pomožne oznake osi" -#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:400 -msgid "No results found" -msgstr "Rezultati niso najdeni" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:233 +msgid "Truncate Axis" +msgstr "Prireži os" -#: superset-frontend/packages/superset-ui-core/src/chart/components/NoResultsComponent.tsx:63 -msgid "" -"No results were returned for this query. If you expected results to be " -"returned, ensure any filters are configured properly and the datasource " -"contains data for the selected time range." -msgstr "" -"Poizvedba ni vrnila rezultatov. Če ste pričakovali rezultate, poskrbite, " -"da so filtri pravilno nastavljeni in podatkovni vir vsebuje podatke za " -"izbrano časovno obdobje." +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:236 +msgid "It’s not recommended to truncate axis in Bar chart." +msgstr "V stolpčnem grafikonu ni priporočljivo omejiti osi." -#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:133 -msgid "No stored results found, you need to re-run your query" -msgstr "Rezultatov še ni shranjenih, ponovno morate zagnati poizvedbo" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:247 +msgid "Axis Bounds" +msgstr "Meje osi" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:268 -msgid "No such column found. To filter on a metric, try the Custom SQL tab." +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:250 +msgid "" +"Bounds for the axis. When left empty, the bounds are dynamically defined based on " +"the min/max of the data. Note that this feature will only expand the axis range. " +"It won't narrow the data's extent." msgstr "" -"Tak stolpec ni najden. Za filtriranje po meri uporabite prilagojen SQL " -"zavihek." - -#: superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx:81 -msgid "No time columns" -msgstr "Ni časovnih stolpcev" - -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:155 -msgid "Node label position" -msgstr "Položaj oznake vozlišča" +"Meje osi. Če je prazno, se meje nastavijo dinamično na podlagi min./max. " +"vrednosti podatkov. Funkcija omeji le prikaz, obseg podatkov pa ostane enak." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:182 -msgid "Node select mode" -msgstr "Način izbire vozlišč" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:304 +msgid "Chart Orientation" +msgstr "Orientacija grafikona" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:213 -msgid "Node size" -msgstr "Velikost vozlišča" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:313 +msgid "Bar orientation" +msgstr "Orientacija stolpcev" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:41 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:242 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:120 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:644 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:124 -msgid "None" -msgstr "Brez" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:317 +msgid "Horizontal" +msgstr "Vodoravno" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:129 -msgid "None -> Arrow" -msgstr "Brez -> Puščica" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:319 +msgid "Orientation of bar chart" +msgstr "Orientacija stolpčnega grafikona" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:128 -msgid "None -> None" -msgstr "Brez -> Brez" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:64 +msgid "Bar Charts are used to show metrics as a series of bars." +msgstr "Stolpčni grafikoni se uporabljajo za prikaz mer z nizi stolpcev." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:43 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:77 -msgid "Normal" -msgstr "Normalna" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:65 +msgid "" +"Time-series Bar Charts are used to show the changes in a metric over time as a " +"series of bars." +msgstr "" +"Stolpčni grafikoni časovne vrste se uporabljajo za prikaz sprememb mere skozi čas " +"s pomočjo niza stolpcev." -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:165 -msgid "Normalize Across" -msgstr "Normiraj glede na" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:80 +msgid "Bar Chart v2" +msgstr "Stolpčni grafikon v2" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:315 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:141 -msgid "Normalized" -msgstr "Normiran" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:81 +msgid "Time-series Bar Chart v2" +msgstr "Stolpčni grafikon časovne vrste v2" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:81 -msgid "Not Time Series" -msgstr "Ni časovna vrsta" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:63 +msgid "" +"Line chart is used to visualize measurements taken over a given category. Line " +"chart is a type of chart which displays information as a series of data points " +"connected by straight line segments. It is a basic type of chart common in many " +"fields." +msgstr "" +"Črtni grafikon se uporablja se za vizualizacijo meritev zajetih skozi čas. " +"Posamezne točke so med seboj povezane z ravnimi črtami." -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:116 -msgid "Not null" -msgstr "Ni nič (null)" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:66 +msgid "" +"Time-series line chart is used to visualize repeated measurements taken over " +"regular time intervals. Line chart is a type of chart which displays information " +"as a series of data points connected by straight line segments. It is a basic " +"type of chart common in many fields." +msgstr "" +"Črtni grafikon časovne vrste je osnovni grafikon, ki se uporablja na različnih " +"področjih. Uporablja se za vizualizacijo meritev zajetih skozi čas. Posamezne " +"točke so med seboj povezane z ravnimi črtami." -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:57 -#, fuzzy -msgid "Not triggered" -msgstr "Ni ni sproženo" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:78 +msgid "Time-series Line Chart" +msgstr "Črtni grafikon časovne vrste" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:152 -msgid "Not up to date" -msgstr "Ni posodobljeno" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:62 +msgid "" +"Scatter Plot has the horizontal axis in linear units, and the points are " +"connected in order. It shows a statistical relationship between two variables." +msgstr "" +"Raztreseni grafikon ima vodoravno os v linearnih enotah, prikazuje podatkovne " +"točke v povezanem redu in prikazuje statistično razmerje med dvema " +"spremenljivkama." -#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:87 -#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:97 -msgid "Nothing triggered" -msgstr "Ni ni sproženo" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:65 +msgid "" +"Time-series Scatter Plot has time on the horizontal axis in linear units, and the " +"points are connected in order. It shows a statistical relationship between two " +"variables." +msgstr "" +"Raztreseni grafikon časovne vrste prikazuje podatkovne točke v povezanem redu in " +"prikazuje statistično razmerje med spremenljivkami." -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:260 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1348 -msgid "Notification method" -msgstr "Način obveščanja" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:76 +#: superset-frontend/plugins/preset-chart-xy/src/ScatterPlot/createMetadata.ts:26 +msgid "Scatter Plot" +msgstr "Raztreseni grafikon" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:76 -msgid "November" -msgstr "November" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:77 +msgid "Time-series Scatter Plot" +msgstr "Raztreseni grafikon časovne vrste" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:92 -msgid "Now" -msgstr "Zdaj" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:62 +msgid "" +"Smooth-line is a variation of the line chart. Without angles and hard edges, " +"Smooth-line sometimes looks smarter and more professional." +msgstr "" +"Zglajeni črtni grafikon je izpeljanka črtnega grafikona, ki zgladi ostre robove " +"krivulje." -#: superset/datasets/filters.py:26 -msgid "Null or Empty" -msgstr "Nič (NULL) ali prazen" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:65 +msgid "" +"Time-series Smooth-line is a variation of the line chart. Without angles and hard " +"edges, Smooth-line sometimes looks smarter and more professional." +msgstr "" +"Zglajeni grafikon časovne vrste je izpeljanka črtnega grafikona, ki zgladi ostre " +"robove krivulje." -#: superset/views/database/forms.py:233 superset/views/database/forms.py:366 -msgid "Null values" -msgstr "Prazne (Null) vrednosti" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:76 +msgid "Smooth Line" +msgstr "Zglajena črta" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:191 -msgid "Number Format" -msgstr "Oblika zapisa števila" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:77 +msgid "Time-series Smooth Line" +msgstr "Zglajeni črtni grafikon časovne vrste" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:56 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:64 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:151 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:128 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:75 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:77 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:210 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:95 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:99 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:112 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:149 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:120 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:137 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:113 -msgid "Number format" -msgstr "Oblika zapisa števila" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:105 +msgid "Step type" +msgstr "Stopnični tip" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:81 -msgid "Number of decimal digits to round numbers to" -msgstr "Število decimalnih mest za zaokroževanje števil" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:113 +msgid "" +"Defines whether the step should appear at the beginning, middle or end between " +"two data points" +msgstr "" +"Določa, če se na začetku, na sredini ali na koncu pojavi stopnica med dvema " +"točkama" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:100 -msgid "Number of decimal places with which to display lift values" -msgstr "Število decimalnih mest za prikaz vrednosti dviga" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:53 +msgid "" +"Stepped-line graph (also called step chart) is a variation of line chart but with " +"the line forming a series of steps between data points. A step chart can be " +"useful when you want to show the changes that occur at irregular intervals." +msgstr "" +"Stopničasti grafikon je izpeljanka črtnega grafikona, pri čemer krivuljo tvorijo " +"stopnice med posameznimi točkami. Koristen je za prikaz sprememb na posameznih " +"intervalih." -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:87 -msgid "Number of decimal places with which to display p-values" -msgstr "Število decimalnih mest za prikaz p-vrednosti" +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:56 +msgid "" +"Time-series Stepped-line graph (also called step chart) is a variation of line " +"chart but with the line forming a series of steps between data points. A step " +"chart can be useful when you want to show the changes that occur at irregular " +"intervals." +msgstr "" +"Stopnični grafikon časovne vrste je izpeljanka črtnega grafikona, pri čemer " +"krivuljo tvorijo stopnice med posameznimi točkami. Koristen je za prikaz sprememb " +"na posameznih intervalih." -#: superset/views/database/forms.py:194 superset/views/database/forms.py:335 -msgid "Number of rows of file to read." -msgstr "Število vrstic v datoteki za branje." +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:67 +msgid "Stepped Line" +msgstr "Stopničasta črta" -#: superset/views/database/forms.py:188 superset/views/database/forms.py:329 -msgid "Number of rows to skip at start of file." -msgstr "Število vrstic, ki se izpustijo na začetku datoteke." +#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:68 +msgid "Time-series Stepped Line" +msgstr "Stopnični črtni grafikon časovne vrste" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:231 -msgid "Number of split segments on the axis" -msgstr "Število razdelkov na osi" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:50 +msgid "Id" +msgstr "Id" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:119 -msgid "Number of steps to take between ticks when displaying the X scale" -msgstr "Število korakov med oznakami pri prikazu X-osi" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:51 +msgid "Name of the id column" +msgstr "Naziv id-stolpca" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:135 -msgid "Number of steps to take between ticks when displaying the Y scale" -msgstr "Število korakov med oznakami pri prikazu Y-osi" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:60 +msgid "Parent" +msgstr "Nadrejeni" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:295 -msgid "Numerical range" -msgstr "Številski obseg" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:61 +msgid "Name of the column containing the id of the parent node" +msgstr "Ime stolpca, ki vsebuje id nadrejenega vozlišča" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:100 -msgid "OCT" -msgstr "OKT" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:73 +msgid "Optional name of the data column." +msgstr "Opcijsko ime podatkovnega stolpca." -#: superset-frontend/src/components/Modal/Modal.tsx:198 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:797 -msgid "OK" -msgstr "OK" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:84 +msgid "Root node id" +msgstr "Id korenskega vozlišča" -#: superset-frontend/src/components/ImportModal/index.tsx:210 -msgid "OVERWRITE" -msgstr "OVERWRITE" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:85 +msgid "Id of root node of the tree." +msgstr "Id korenskega vozlišča drevesa." -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:75 -msgid "October" -msgstr "Oktober" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:98 +msgid "Metric for node values" +msgstr "Mera za vrednosti vozlišč" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:93 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:163 -msgid "Offline" -msgstr "Offline" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:117 +msgid "Tree layout" +msgstr "Oblika drevesa" -#: superset/connectors/sqla/views.py:496 -msgid "Offset" -msgstr "Odmik" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:120 +msgid "Orthogonal" +msgstr "Pravokotna" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:58 -#, fuzzy -msgid "On Grace" -msgstr "Sila" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:121 +msgid "Radial" +msgstr "Radialna" -#: superset/views/alerts.py:191 -msgid "" -"Once an alert is triggered, how long, in seconds, before Superset nags " -"you again." -msgstr "" -"Kako dolgo naj traja (v sekundah), da vas Superset ponovno opomni, ko je " -"opozorilo sproženo." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:123 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:246 +msgid "Layout type of tree" +msgstr "Način izgleda drevesa" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:33 -#: superset-frontend/src/explore/controls.jsx:126 -msgid "" -"One or many columns to group by. High cardinality groupings should " -"include a series limit to limit the number of fetched and rendered " -"series." -msgstr "" -"Eden ali več stolpcev za združevanje. Združevanje z visoko kardinalnostjo" -" naj vsebuje omejitev serij, s čimer omejite število pridobljenih in " -"prikazanih serij." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:134 +msgid "Tree orientation" +msgstr "Orientacija drevesa" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:105 -msgid "" -"One or many columns to group by. High cardinality groupings should " -"include a sort by metric and series limit to limit the number of fetched " -"and rendered series." -msgstr "" -"Eden ali več stolpcev za združevanje. Združevanje z visoko kardinalnostjo" -" naj vsebuje mero za razvrščanje in omjitev serij, s čimer omejite " -"število pridobljenih in prikazanih serij." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:137 +msgid "Left to Right" +msgstr "Iz leve proti desni" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:56 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:215 -msgid "One or many columns to pivot as columns" -msgstr "En ali več stolpcev za stolpčno vrtenje" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:138 +msgid "Right to Left" +msgstr "Iz desne proti levi" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:323 -msgid "" -"One or many controls to group by. If grouping, latitude and longitude " -"columns must be present." -msgstr "" -"Eden ali več kontrolnikov za združevanje. Pri združevanju morata biti " -"prisotna stolpca širine in dolžine." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:139 +msgid "Top to Bottom" +msgstr "Iz vrha proti dnu" -#: superset-frontend/src/explore/controls.jsx:246 -msgid "One or many controls to pivot as columns" -msgstr "En ali več kontrolnikov za stolpčno vrtenje" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:140 +msgid "Bottom to Top" +msgstr "Iz dna proti vrhu" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:107 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:145 -#: superset-frontend/src/explore/controls.jsx:162 -msgid "One or many metrics to display" -msgstr "Ena ali več mer za prikaz" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:142 +msgid "Orientation of tree" +msgstr "Orientacija drevesa" -#: superset/datasets/commands/exceptions.py:90 -msgid "One or more columns already exist" -msgstr "En ali več stolpcev že obstaja" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:155 +msgid "Node label position" +msgstr "Položaj oznake vozlišča" -#: superset/datasets/commands/exceptions.py:80 -msgid "One or more columns are duplicated" -msgstr "En ali več stolpcev je podvojenih" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:158 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:176 +msgid "left" +msgstr "levo" -#: superset/datasets/commands/exceptions.py:70 -msgid "One or more columns do not exist" -msgstr "En ali več stolpcev ne obstaja" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:159 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:177 +msgid "top" +msgstr "zgoraj" -#: superset/datasets/commands/exceptions.py:119 -msgid "One or more metrics already exist" -msgstr "Ena ali več mer že obstaja" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:160 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:178 +msgid "right" +msgstr "desno" -#: superset/datasets/commands/exceptions.py:109 -msgid "One or more metrics are duplicated" -msgstr "Ena ali več mer je podvojenih" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:161 +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:179 +msgid "bottom" +msgstr "spodaj" -#: superset/datasets/commands/exceptions.py:99 -msgid "One or more metrics do not exist" -msgstr "Ena ali več mer ne obstaja" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:163 +msgid "Position of intermidiate node label on tree" +msgstr "Položaj vmesne oznake vozlišča na drevesu" -#: superset/errors.py:113 -msgid "One or more parameters needed to configure a database are missing." -msgstr "En ali več parametrov, potrebnih za nastavitev podatkovne baze, manjka." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:173 +msgid "Child label position" +msgstr "Položaj podrejene oznake" -#: superset/errors.py:127 -msgid "One or more parameters specified in the query are malformatted." -msgstr "En ali več parametrov v SQL-poizvedbi ima napačno obliko." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:181 +msgid "Position of child node label on tree" +msgstr "Položaj oznake podrejenega vozlišča na drevesu" -#: superset/errors.py:101 -msgid "One or more parameters specified in the query are missing." -msgstr "En ali več parametrov v SQL-poizvedbi manjka." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:191 +msgid "Emphasis" +msgstr "Poudari" -#: superset/views/core.py:2075 -msgid "" -"One or more required fields are missing in the request. Please try again," -" and if the problem persists conctact your administrator." -msgstr "" -"Eno ali več zahtevanih polj manjka v zahtevi. Poskusite znova, če težava " -"ostane, kontaktirajte administratorja." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:194 +msgid "ancestor" +msgstr "nadrejeni" -#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:46 -msgid "One ore more annotation layers failed loading." -msgstr "Eden ali več slojev z oznakami se ni naložil." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:195 +msgid "descendant" +msgstr "podrejeni" -#: superset/sql_lab.py:201 -msgid "Only SELECT statements are allowed against this database." -msgstr "Za to podatkovno bazo so dovoljeni le `SELECT` stavki." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:197 +msgid "Which relatives to highlight on hover" +msgstr "Kateri element se poudari na prehodu z miško" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:128 -msgid "Only Total" -msgstr "Samo vsota" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:210 +msgid "Symbol" +msgstr "Simbol" -#: superset/connectors/sqla/utils.py:96 -msgid "Only `SELECT` statements are allowed" -msgstr "Dovoljeni so le `SELECT` stavki" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:214 +msgid "Empty circle" +msgstr "Prazen krog" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:131 -msgid "Only selected panels will be affected by this filter" -msgstr "Ta filter bo vplival le na izbrane panele" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:218 +msgid "Circle" +msgstr "Krog" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:131 -msgid "" -"Only show the total value on the stacked chart, and not show on the " -"selected category" -msgstr "" -"Na naloženem grafikonu prikaži samo skupno vsoto, za izbrane kategorije " -"pa ne" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:222 +msgid "Rectangle" +msgstr "Pravokotnik" -#: superset/connectors/sqla/utils.py:105 -msgid "Only single queries supported" -msgstr "Podprte so le enojne poizvedbe" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:226 +msgid "Triangle" +msgstr "Trikotnik" -#: superset/views/database/forms.py:111 superset/views/database/forms.py:262 -#: superset/views/database/forms.py:397 -#, python-format -msgid "Only the following file extensions are allowed: %(allowed_extensions)s" -msgstr "Dovoljene so le naslednje končnice: %(allowed_extensions)s" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:230 +msgid "Diamond" +msgstr "Karo" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:236 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:196 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:636 -msgid "Opacity" -msgstr "Prosojnost" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:234 +msgid "Pin" +msgstr "Žebljiček" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:137 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:152 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:155 -msgid "Opacity of Area Chart. Also applies to confidence band." -msgstr "Prosojnost ploščinskega grafikona. Upošteva se tudi za interval zaupanja." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:238 +msgid "Arrow" +msgstr "Puščica" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:239 -msgid "Opacity of all clusters, points, and labels. Between 0 and 1." -msgstr "Prosojnost vseh gruč, točk in oznak (vrednost med 0 in 1)." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:255 +msgid "Symbol size" +msgstr "Velikost simbola" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:202 -msgid "Opacity of area chart." -msgstr "Prosojnost ploščinskega grafikona." +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:261 +msgid "Size of edge symbols" +msgstr "Velikost simbola povezave" -#: superset-frontend/src/explore/components/ExploreViewContainer.jsx:550 -msgid "Open Datasource tab" -msgstr "Odpri zavihek s podatkovnim virom" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:35 +msgid "Visualize multiple levels of hierarchy using a familiar tree-like structure." +msgstr "Prikaz več hierarhičnih nivojev z drevesno strukturo." -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:141 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:121 -msgid "Open in SQL Lab" -msgstr "Odpri v SQL laboratoriju" +#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:39 +msgid "Tree Chart" +msgstr "Drevesni grafikon" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:317 -msgid "Open query in SQL Lab" -msgstr "Odpri poizvedbo v SQL laboratoriju" +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:83 +msgid "Show Upper Labels" +msgstr "Prikaži zgornje oznake" -#: superset/views/database/mixins.py:105 -msgid "" -"Operate the database in asynchronous mode, meaning that the queries are " -"executed on remote workers as opposed to on the web server itself. This " -"assumes that you have a Celery worker setup as well as a results backend." -" Refer to the installation docs for more information." -msgstr "" -"Upravljanje podatkovne baze v asinhronem načinu pomeni, da se poizvedbe " -"zaženejo na oddaljenih »delavcih« in ne na samem spletnem strežniku. S " -"tem je predpostavljeno, da imate nastavljenega »delavca« za Celery in " -"zaledni sistem za rezultate. Več informacij je v navodilih za namestitev." +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:86 +msgid "Show labels when the node has children." +msgstr "Prikaži oznake, ko ima vozlišče podrejene elemente." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:288 +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:52 msgid "" -"Operate the database in asynchronous mode, meaning that the queries are " -"executed on remote workers as opposed to on the web server itself. This " -"assumes that you have a Celery worker setup as well as a results backend." -" Refer to the installation docs for more information." +"Show hierarchical relationships of data, with with the value represented by area, " +"showing proportion and contribution to the whole." msgstr "" -"Upravljanje podatkovne baze v asinhronem načinu pomeni, da se poizvedbe " -"zaženejo na oddaljenih »delavcih« in ne na samem spletnem strežniku. S " -"tem je predpostavljeno, da imate nastavljenega »delavca« za Celery in " -"zaledni sistem za rezultate. Več informacij je v navodilih za namestitev." +"Prikaže hierarhična razmerja podatkov, pri čemer je vrednost ponazorjena s " +"ploščino, in deleže oz. prispevke k celoti." -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:125 -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:130 -msgid "Operator" -msgstr "Operator" +#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:56 +msgid "Treemap v2" +msgstr "Drevesni grafikon s pravokotniki v2" -#: superset/utils/pandas_postprocessing.py:175 -#, python-format -msgid "Operator undefined for aggregator: %(name)s" -msgstr "Operand ni definiran za agregatorja: %(name)s" +#: superset-frontend/plugins/plugin-chart-handlebars/src/consts.ts:27 +#: superset-frontend/plugins/plugin-chart-table/src/consts.ts:26 +msgid "page_size.all" +msgstr "page_size.all" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:361 -msgid "" -"Optional CA_BUNDLE contents to validate HTTPS requests. Only available on" -" certain database engines." -msgstr "" -"Opcijska CA_BUNDLE vsebina, za potrjevanje HTTPS zahtev. Razpoložljivo le" -" na določenih sistemih podatkovnih baz." +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/index.ts:39 +msgid "Handlebars" +msgstr "Handlebars" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:73 -msgid "Optional name of the data column." -msgstr "Opcijsko ime podatkovnega stolpca." +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:53 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx:78 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:119 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:142 +msgid "must have a value" +msgstr "mora imeti vrednost" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1135 -msgid "" -"Optional time column if time range should apply to another column than " -"the default time column" -msgstr "" -"Izbirni časovni stolpec se mora nanašati na drug stolpec kot privzeti " -"časovni stolpec" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/handlebarTemplate.tsx:60 +msgid "Handlebars Template" +msgstr "Predloga za Handlebars" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1092 -msgid "Optional warning about use of this metric" -msgstr "Opcijsko opozorilo za uporabo te mere" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/handlebarTemplate.tsx:61 +msgid "A handlebars template that is applied to the data" +msgstr "Predloga za Handlebars, ki je uporabljena za podatke" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:49 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:75 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:119 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:72 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:39 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:37 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:105 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:198 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:363 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:48 -msgid "Options" -msgstr "Možnosti" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/includeTime.ts:27 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:342 +msgid "Include time" +msgstr "Vključi čas" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:668 -msgid "Or choose from a list of other databases we support:" -msgstr "" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/includeTime.ts:28 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:343 +msgid "Whether to include the time granularity as defined in the time section" +msgstr "Če želite vključiti granulacijo časa, ki je določena v sekciji Čas" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:63 -msgid "Order by entity id" -msgstr "Uredi po ID entitete" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx:33 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:152 +msgid "Percentage metrics" +msgstr "Procentualne mere" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:272 -msgid "Order results by selected columns" -msgstr "Razvrsti rezultate glede na izbrani stolpec" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx:34 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:153 +msgid "" +"Metrics for which percentage of total are to be displayed. Calculated from only " +"data within the row limit." +msgstr "" +"Mera, za katero je prikazan odstotek od celote. Izračunan je samo iz podatkov " +"znotraj omejitve števila vrstic." + +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx:107 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:370 +msgid "" +"Show total aggregations of selected metrics. Note that row limit does not apply " +"to the result." +msgstr "" +"Prikaži skupno agregacijo izbrane mere. Omejitev števila vrstic ne vpliva na " +"rezultat." -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:271 +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/orderBy.tsx:27 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:285 msgid "Ordering" msgstr "Razvrščanje" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:142 -msgid "Orientation of tree" -msgstr "Orientacija drevesa" - -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:27 -#: superset-frontend/src/explore/constants.ts:116 -msgid "Origin" -msgstr "Izhodišče" - -#: superset-frontend/src/explore/components/ExportToCSVDropdown/index.tsx:74 -#, fuzzy -msgid "Original" -msgstr "Izhodišče" - -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:183 -msgid "Original table column order" -msgstr "Vrstni red stolpcev izvorne tabele" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/orderBy.tsx:28 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:286 +msgid "Order results by selected columns" +msgstr "Razvrsti rezultate glede na izbrani stolpec" -#: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:29 -#: superset/db_engine_specs/base.py:85 -msgid "Original value" -msgstr "Izvorna vrednost" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/pagination.tsx:35 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:306 +msgid "Server pagination" +msgstr "Paginacija na strani strežnika" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:120 -msgid "Orthogonal" -msgstr "Pravokotna" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/pagination.tsx:36 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:307 +msgid "Enable server side pagination of results (experimental feature)" +msgstr "" +"Omogoči številčenje strani rezultatov na strani strežnika (preizkusna funkcija)" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:120 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:687 -msgid "Other" -msgstr "Ostali" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/pagination.tsx:50 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:328 +msgid "Server Page Length" +msgstr "Dolžina strani strežnika" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:193 -msgid "Outer Radius" -msgstr "Zunanji polmer" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/pagination.tsx:53 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:331 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:410 +msgid "Rows per page, 0 means no pagination" +msgstr "Vrstic na stran (0 pomeni brez številčenja strani)" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:199 -msgid "Outer edge of Pie chart" -msgstr "Zunanji rob tortnega grafikona" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/queryMode.tsx:29 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:92 +msgid "Query mode" +msgstr "Poizvedbeni način" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:257 -msgid "Overlap" -msgstr "Prekrivanje" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/shared.ts:59 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:86 +msgid "Group By, Metrics or Percentage Metrics must have a value" +msgstr "Združevanje, Mera ali Procentualna mera morajo imeti vrednost" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:107 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:322 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:205 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:455 -#: superset-frontend/src/explore/controlPanels/sections.tsx:220 -msgid "" -"Overlay one or more timeseries from a relative time period. Expects " -"relative time deltas in natural language (example: 24 hours, 7 days, 52 " -"weeks, 365 days). Free text is supported." -msgstr "" -"Zamaknite eno ali več časovnih vrst za relativno časovno obdobje. Vnaša " -"se relativne časovne razlike v naravnem jeziku (npr. 24 ur, 7 dni, 52 " -"tednov, 365 dni). Prosto besedilo je podprto." +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/style.tsx:59 +msgid "CSS Styles" +msgstr "CSS slogi" -#: superset-frontend/src/components/ImportModal/index.tsx:282 -msgid "Overwrite" -msgstr "Prepiši" +#: superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/style.tsx:60 +msgid "CSS applied to the chart" +msgstr "CSS slogi uporabljeni za grafikon" -#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:120 -msgid "Overwrite & Explore" -msgstr "Prepiši & Razišči" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:51 +msgid "Columns to group by on the columns" +msgstr "Stolpci za združevanje stolpcev" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:191 -#, python-format -msgid "Overwrite Dashboard [%s]" -msgstr "Prepiši nadzorno ploščo [%s]" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:60 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:85 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:289 +msgid "Rows" +msgstr "Vrstice" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:264 -msgid "Overwrite text in the editor with a query on this table" -msgstr "Besedilo v urejevalniku prepišite s poizvedbo na to tabelo" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:61 +msgid "Columns to group by on the rows" +msgstr "Stolpci za združevanje vrstic" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:453 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:450 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:417 -msgid "Owner" -msgstr "Lastnik" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:81 +msgid "Apply metrics on" +msgstr "Uporabi mero na" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:234 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:399 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:355 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:358 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:402 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:405 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:168 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:276 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1079 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1084 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:334 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:334 -#: superset/connectors/druid/views.py:346 superset/connectors/sqla/views.py:500 -#: superset/views/chart/mixin.py:83 superset/views/dashboard/mixin.py:82 -msgid "Owners" -msgstr "Lastniki" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:87 +msgid "Use metrics as a top level group for columns or for rows" +msgstr "Uporabi mere kot vrhovni nivo grupiranja za stolpce ali vrstice" -#: superset/commands/exceptions.py:105 -#: superset/datasets/commands/exceptions.py:144 -msgid "Owners are invalid" -msgstr "Lastniki niso veljavni" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:101 +msgid "Cell limit" +msgstr "Omejitev celice" -#: superset/views/dashboard/mixin.py:65 -msgid "Owners is a list of users who can alter the dashboard." -msgstr "\"Lastniki\" je seznam uporabnikov, ki lahko spreminjajo nadzorno ploščo." +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:102 +msgid "Limits the number of cells that get retrieved." +msgstr "Omeji število pridobljenih celic." -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:367 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:414 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:112 msgid "" -"Owners is a list of users who can alter the dashboard. Searchable by name" -" or username." +"Metric used to define how the top series are sorted if a series or cell limit is " +"present. If undefined reverts to the first metric (where appropriate)." msgstr "" -"\"Lastniki\" je seznam uporabnikov, ki lahko spreminjajo nadzorno ploščo." -" Iskanje je možno po imenu ali uporabniškem imenu." +"Mera, ki določa kako so razvrščene prve serije, če je določena omejitev serij ali " +"vrstic. Če ni določena, se uporabi prva mera (kjer je ustrezno)." -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:388 -msgid "Page length" -msgstr "Dolžina strani" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:177 +msgid "Show rows total" +msgstr "Prikaži vsoto vrstic" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:29 -msgid "Paired t-test Table" -msgstr "Tabela t-testa za odvisne vzorce" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:180 +msgid "Display row level total" +msgstr "Prikaži vsote na nivoju vrstic" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:177 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:388 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:271 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:516 -#: superset-frontend/src/explore/controlPanels/sections.tsx:278 -msgid "Pandas resample method" -msgstr "Metoda za prevzorčenje v Pandas" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:189 +msgid "Show columns total" +msgstr "Prikaži vsoto stolpcev" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:156 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:370 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:253 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:496 -#: superset-frontend/src/explore/controlPanels/sections.tsx:260 -msgid "Pandas resample rule" -msgstr "Pravilo za prevzorčenje v Pandas" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:192 +msgid "Display column level total" +msgstr "Prikaži vsote na nivoju stolpcev" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:30 -#: superset/viz.py:2182 -msgid "Parallel Coordinates" -msgstr "Vzporedne koordinate" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:201 +msgid "Transpose pivot" +msgstr "Transponirano vrtenje" -#: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:116 -msgid "Parameter error" -msgstr "Napaka parametra" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:203 +msgid "Swap rows and columns" +msgstr "Zamenjaj vrstice in stolpce" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:64 -#: superset/views/chart/mixin.py:84 -msgid "Parameters" -msgstr "Parametri" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:213 +msgid "Combine metrics" +msgstr "Združuj mere" -#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:103 -#, fuzzy -msgid "Parameters " -msgstr "Parametri" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:248 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:396 +msgid "D3 time format for datetime columns" +msgstr "D3 oblika zapisa za časovne stolpce" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:60 -msgid "Parent" -msgstr "Nadrejeni" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:257 +msgid "Sort rows by" +msgstr "Razvrsti vrstice" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:643 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1037 -msgid "Parent filter" -msgstr "Nadrejeni filter" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:261 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:289 +msgid "key a-z" +msgstr "a - ž" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1045 -msgid "Parent filter is required" -msgstr "Zahtevan je nadrejeni filter" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:262 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:290 +msgid "key z-a" +msgstr "ž - a" -#: superset/views/database/forms.py:203 superset/views/database/forms.py:340 -msgid "Parse Dates" -msgstr "Prepoznaj datume" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:263 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:291 +msgid "value ascending" +msgstr "0 - 9" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:25 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:26 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:29 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:51 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:33 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:50 -msgid "Part of a Whole" -msgstr "Del celote" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:264 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:292 +msgid "value descending" +msgstr "9 - 0" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:27 -msgid "Partition Chart" -msgstr "Grafikon razdelkov" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:269 +msgid "Change order of rows." +msgstr "Spremeni vrstni red vrstic." -#: superset/viz.py:3035 -msgid "Partition Diagram" -msgstr "Grafikon s pravokotniki" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:270 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:298 +msgid "Available sorting modes:" +msgstr "Razpoložljivi načini razvrščanja:" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:176 -msgid "Partition Limit" -msgstr "Omejitev particij" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:272 +msgid "By key: use row names as sorting key" +msgstr "Po ključu: za razvrščanje uporabite imena vrstic" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:189 -msgid "Partition Threshold" -msgstr "Prag particije" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:273 +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:301 +msgid "By value: use metric values as sorting key" +msgstr "Po vrednosti: za razvrščanje uporabite vrednosti mere" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:192 -msgid "" -"Partitions whose height to parent height proportions are below this value" -" are pruned" -msgstr "" -"Particije z nižjim razmerjem med njihovo višino in dolžino starša so " -"zanemarjene" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:285 +msgid "Sort columns by" +msgstr "Razvrsti stolpce" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:130 -#: superset/db_engine_specs/base.py:1389 -msgid "Password" -msgstr "Geslo" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:297 +msgid "Change order of columns." +msgstr "Spremeni vrstni red stolpcev." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:79 -msgid "Paste the shareable Google Sheet URL here" -msgstr "Prilepite deljeni URL Googlove preglednice sem" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:300 +msgid "By key: use column names as sorting key" +msgstr "Po ključu: za razvrščanje uporabite imena stolpcev" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:35 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:35 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:46 -msgid "Pattern" -msgstr "Vzorec" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:313 +msgid "Rows subtotal position" +msgstr "Položaj vsot vrstic" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:108 -msgid "Percent Change" -msgstr "Procentualna sprememba" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:317 +msgid "Top" +msgstr "Zgoraj" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:147 -msgid "Percentage metrics" -msgstr "Procentualne mere" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:318 +msgid "Bottom" +msgstr "Spodaj" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:81 -msgid "Percentage threshold" -msgstr "Procentualni prag" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:321 +msgid "Position of row level subtotal" +msgstr "Položaj vsot na nivoju vrstic" -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:41 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:45 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:39 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:49 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:42 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:38 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:45 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:69 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:63 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:33 -msgid "Percentages" -msgstr "Procenti" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:330 +msgid "Columns subtotal position" +msgstr "Položaj delnih vsot stolpcev" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:56 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:278 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:161 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:179 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:410 -#: superset-frontend/src/explore/controlPanels/sections.tsx:177 -msgid "Periods" -msgstr "Št. period" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:338 +msgid "Position of column level subtotal" +msgstr "Položaj vsot na nivoju stolpcev" -#: superset/utils/pandas_postprocessing.py:824 -msgid "Periods must be a positive integer value" -msgstr "Periode morajo biti pozitivno celo število" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:348 +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:509 +msgid "Conditional formatting" +msgstr "Pogojno oblikovanje" -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:258 -#, fuzzy -msgid "Person or group that has certified this chart." -msgstr "Oseba ali skupina, ki je certificirala to mero" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:349 +msgid "Apply conditional color formatting to metrics" +msgstr "Za mere uporabi pogojno oblikovanje z barvami" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:548 -#, fuzzy -msgid "Person or group that has certified this dashboard." -msgstr "Oseba ali skupina, ki je certificirala to mero" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:51 +msgid "" +"Used to summarize a set of data by grouping together multiple statistics along " +"two axes. Examples: Sales numbers by region and month, tasks by status and " +"assignee, active users by age and location. Not the most visually stunning " +"visualization, but highly informative and versatile." +msgstr "" +"Ponazori podatke na podlagi združevanja več statistik vzdolž dveh osi. Npr. " +"prodaja po regijah in mesecih, opravila po statusih in izvajalcih, itd." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:260 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1068 -msgid "Person or group that has certified this metric" -msgstr "Oseba ali skupina, ki je certificirala to mero" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:54 +msgid "Pivot Table v2" +msgstr "Vrtilna tabela v2" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:936 -msgid "Physical" -msgstr "Fizičen" +#: superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.js:842 +msgid "Unknown input format" +msgstr "Neznana oblika vnosa" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:132 -msgid "Physical (table or view)" -msgstr "Fizičen (tabela ali pogled)" +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:125 +msgid "search.num_records" +msgstr "search.num_records" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:223 -msgid "Physical dataset" -msgstr "Fizičen podatkovni set" +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:140 +msgid "page_size.show" +msgstr "page_size.show" -#: superset/viz.py:742 -msgid "Pick a granularity in the Time section or uncheck 'Include Time'" -msgstr "Izberite granulacijo v razdelku 'Čas' ali odstranite 'Vključi čas'" +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:160 +msgid "page_size.entries" +msgstr "page_size.entries" -#: superset/viz.py:1573 -msgid "Pick a metric for left axis!" -msgstr "Izberite mero za levo os!" +#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:462 +msgid "Totals" +msgstr "Vsote" -#: superset/viz.py:1575 -msgid "Pick a metric for right axis!" -msgstr "Izberite mero za desno os!" +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:391 +msgid "Timestamp format" +msgstr "Oblika zapisa časovne značke" -#: superset/viz.py:1163 -msgid "Pick a metric for x, y and size" -msgstr "Izberite mere za x, y in velikost" +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:407 +msgid "Page length" +msgstr "Dolžina strani" -#: superset/viz.py:1202 -msgid "Pick a metric to display" -msgstr "Izberite mero za prikaz" +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:422 +msgid "Search box" +msgstr "Iskalno polje" -#: superset/viz.py:1228 superset/viz.py:1262 -msgid "Pick a metric!" -msgstr "Izberite mero!" +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:425 +msgid "Whether to include a client-side search box" +msgstr "Če želite vključiti iskalno polje za uporabnika" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:56 -msgid "Pick a name to help you identify this database." -msgstr "Izberite ime za lažjo prepoznavo podatkovne baze." +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:432 +msgid "Cell bars" +msgstr "Stolp. graf v celicah" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:151 -msgid "Pick a nickname for this database to display as in Superset." -msgstr "Izberite vzdevek za to podatkovno bazo, ki bo prikazan v Supersetu." +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:449 +msgid "" +"Whether to align background charts with both positive and negative values at 0" +msgstr "" +"Če želite poravnati graf v ozadju celic za negativne in pozitivne vrednosti okrog " +"0" -#: superset/viz.py:1358 superset/viz.py:1621 -msgid "Pick a time granularity for your time series" -msgstr "Izberite granulacijo časa za časovno vrsto" +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:472 +msgid "Allow columns to be rearranged" +msgstr "Omogoči razvrščanje stolpcev" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:510 -msgid "Pick a title for you annotation." -msgstr "Izberite naslov za oznako." +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:475 +msgid "" +"Allow end user to drag-and-drop column headers to rearrange them. Note their " +"changes won't persist for the next time they open the chart." +msgstr "" +"Uporabniku omogočite, da s potegom razvrsti stolpce. Sprememba se ne bo ohranila, " +"ko bo grafikon ponovno naložen." -#: superset/viz.py:1783 -msgid "Pick at least one field for [Series]" -msgstr "Izberite vsaj eno polje za [Serije]" +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:486 +msgid "Customize columns" +msgstr "Prilagodi stolpce" -#: superset/viz.py:830 superset/viz.py:1781 -msgid "Pick at least one metric" -msgstr "Izberite vsaj eno mero" +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:487 +msgid "Further customize how to display each column" +msgstr "Dodatne prilagoditve prikaza posameznih stolpcev" -#: superset/viz.py:1911 -msgid "Pick exactly 2 columns as [Source / Target]" -msgstr "Izberite natanko dva stolpca za [Izvor / Cilj]" +#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:510 +msgid "Apply conditional color formatting to numeric columns" +msgstr "Za numerične stolpce uporabi pogojno oblikovanje z barvami" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:521 +#: superset-frontend/plugins/plugin-chart-table/src/index.ts:37 msgid "" -"Pick one or more columns that should be shown in the annotation. If you " -"don't select a column all of them will be shown." -msgstr "" -"Izberite enega ali več stolpcev, ki bodo prikazani v oznakah. Če ne " -"izberete stolpca, bodo prikazani vsi." +"Classic row-by-column spreadsheet like view of a dataset. Use tables to showcase " +"a view into the underlying data or to show aggregated metrics." +msgstr "Standardna razpredelnica za prikaz podatkovnega seta." -#: superset-frontend/src/explore/controlPanels/Separator.js:37 -msgid "Pick your favorite markup language" -msgstr "Izberite svoj priljubljen označevalni jezik" +#: superset-frontend/plugins/plugin-chart-word-cloud/src/legacyPlugin/index.ts:29 +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:39 +msgid "Word Cloud" +msgstr "Oblak besed" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/index.js:27 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:63 -msgid "Pie Chart" -msgstr "Tortni grafikon" +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:57 +msgid "Minimum Font Size" +msgstr "Min. velikost pisave" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:187 -msgid "Pie shape" -msgstr "Oblika torte" +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:60 +msgid "Font size for the smallest value in the list" +msgstr "Velikost pisave za najmanjšo vrednost na seznamu" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:234 -msgid "Pin" -msgstr "Žebljiček" +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:68 +msgid "Maximum Font Size" +msgstr "Max. velikost pisave" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:56 -msgid "Pivot Options" -msgstr "Vrtilne možnosti" +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:71 +msgid "Font size for the biggest value in the list" +msgstr "Velikost pisave za največjo vrednost na seznamu" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:30 -#: superset/viz.py:862 -msgid "Pivot Table" -msgstr "Vrtilna tabela" +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:80 +msgid "Word Rotation" +msgstr "Vrtenje besed" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:54 -msgid "Pivot Table v2" -msgstr "Vrtilna tabela v2" +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:89 +msgid "Rotation to apply to words in the cloud" +msgstr "Če želite vrtenje besed v oblaku" -#: superset/utils/pandas_postprocessing.py:260 -msgid "Pivot operation must include at least one aggregate" -msgstr "Vrtilna operacija mora vsebovati vsaj en agregat" +#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:35 +msgid "" +"Visualizes the words in a column that appear the most often. Bigger font " +"corresponds to higher frequency." +msgstr "" +"Prikaže besede v stolpcu, glede na pogostost pojavljanja. Večja pisava pomeni " +"večjo frekvenco." -#: superset/utils/pandas_postprocessing.py:256 -msgid "Pivot operation requires at least one index" -msgstr "Vrtilna operacija zahteva vsaj en indeks" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:106 +msgid "The query couldn't be loaded" +msgstr "Poizvedbe ni mogoče naložiti" -#: superset-frontend/src/explore/components/ExportToCSVDropdown/index.tsx:80 -#, fuzzy -msgid "Pivoted" -msgstr "priljubljeno" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:159 +msgid "" +"Your query has been scheduled. To see details of your query, navigate to Saved " +"queries" +msgstr "" +"Vaša poizvedba je v urniku. Za ogled podrobnosti poizvedbe pojdite na shranjene " +"poizvedbe" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:83 -msgid "Pixel height of each series" -msgstr "Višina vsake serije v pikslih" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:166 +msgid "Your query could not be scheduled" +msgstr "Vaše poizvedbe ni mogoče uvrstiti v urnik" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:28 -msgid "Please apply filter changes" -msgstr "Potrdite spremembe filtra" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:194 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:305 +msgid "Failed at retrieving results" +msgstr "Napaka pri pridobivanju rezultatov" -#: superset/sqllab/query_render.py:116 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:232 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:258 msgid "" -"Please check your query and confirm that all template parameters are " -"surround by double braces, for example, \"{{ ds }}\". Then, try running " -"your query again." +"An error occurred while storing the latest query id in the backend. Please " +"contact your administrator if this problem persists." msgstr "" -"V poizvedbi preverite, da so vsi parametri obdani z dvojnimi oklepaji, " -"npr. \"{{ ds }}\". Potem poskusite ponovno." +"Pri shranjevanju zadnjega id-ja poizvedbe v sistem je prišlo do napake. Če se " +"težava ponavlja, kontaktirajte administratorja." + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:350 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:385 +msgid "Unknown error" +msgstr "Neznana napaka" -#: superset/db_engine_specs/athena.py:55 -#: superset/db_engine_specs/bigquery.py:179 -#: superset/db_engine_specs/postgres.py:158 -#: superset/db_engine_specs/snowflake.py:104 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:403 +msgid "Query was stopped." +msgstr "Poizvedba je bila ustavljena." + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:405 #, python-format +msgid "Failed at stopping query. %s" +msgstr "Neuspešno ustavljanje poizvedbe. %s" + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:430 msgid "" -"Please check your query for syntax errors at or near " -"\"%(syntax_error)s\". Then, try running your query again." +"Unable to migrate table schema state to backend. Superset will retry later. " +"Please contact your administrator if this problem persists." msgstr "" -"Preverite, če ima vaša poizvedba sintaktične napake pri " -"\"%(syntax_error)s\". Potem ponovno poženite poizvedbo." +"Stanja sheme tabele ni mogoče prenesti v sistem. Superset bo ponovil poskus " +"kasneje. Če se težava ponavlja, kontaktirajte administratorja." -#: superset/db_engine_specs/gsheets.py:74 superset/db_engine_specs/mysql.py:144 -#, python-format +#: superset-frontend/src/SqlLab/actions/sqlLab.js:448 msgid "" -"Please check your query for syntax errors near \"%(server_error)s\". " -"Then, try running your query again." +"Unable to migrate query state to backend. Superset will retry later. Please " +"contact your administrator if this problem persists." msgstr "" -"Preverite, če ima vaša poizvedba sintaktične napake pri " -"\"%(server_error)s\". Potem ponovno poženite poizvedbo." +"Stanja poizvedbe ni mogoče prenesti v sistem. Superset bo ponovil poskus kasneje. " +"Če se težava ponavlja, kontaktirajte administratorja." -#: superset/viz.py:879 -msgid "Please choose at least one 'Group by' field " -msgstr "Izberite vsaj eno 'Group by' polje " +#: superset-frontend/src/SqlLab/actions/sqlLab.js:494 +msgid "" +"Unable to migrate query editor state to backend. Superset will retry later. " +"Please contact your administrator if this problem persists." +msgstr "" +"Stanja urejevalnika poizvedb ni mogoče prenesti v sistem. Superset bo ponovil " +"poskus kasneje. Če se težava ponavlja, kontaktirajte administratorja." -#: superset/viz.py:891 -msgid "Please choose at least one metric" -msgstr "Izberite vsaj eno mero" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:527 +msgid "Unable to add a new tab to the backend. Please contact your administrator." +msgstr "Novega zavihka ni mogoče dodati v sistem. Kontaktirajte administratorja." -#: superset/viz.py:1578 -msgid "Please choose different metrics on left and right axis" -msgstr "Izberite različni meri za levo in desno os" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:544 +#: superset-frontend/src/SqlLab/reducers/sqlLab.js:74 +#, python-format +msgid "Copy of %s" +msgstr "Kopija %s" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:94 -msgid "Please complete all required fields." +#: superset-frontend/src/SqlLab/actions/sqlLab.js:571 +msgid "" +"An error occurred while setting the active tab. Please contact your administrator." msgstr "" +"Pri določanju aktivnega zavihka je prišlo do napake. Kontaktirajte " +"administratorja." -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:485 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:300 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:365 -#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:77 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:357 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:644 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:325 -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:105 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:355 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:611 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:617 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:499 -msgid "Please confirm" -msgstr "Prosim, potrdite" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:659 +msgid "An error occurred while fetching tab state" +msgstr "Pri pridobivanju stanja zavihka je prišlo do napake" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:485 -msgid "Please enter a SQLAlchemy URI to test" -msgstr "Vnesite SQLAlchemy URI za test" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:695 +msgid "" +"An error occurred while hiding the left bar. Please contact your administrator." +msgstr "" +"Pri skrivanju leve vrstice je prišlo do napake. Kontaktirajte administratorja." -#: superset-frontend/src/explore/components/SaveModal.tsx:133 -msgid "Please enter a chart name" -msgstr "Vnesite ime grafikona" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:717 +msgid "An error occurred while removing tab. Please contact your administrator." +msgstr "" +"Pri odstranjevanju zavihka je prišlo do napake. Kontaktirajte administratorja." -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:81 -msgid "Please filter set name" -msgstr "Vnesite ime seta filtrov" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:741 +msgid "An error occurred while removing query. Please contact your administrator." +msgstr "" +"Pri odstranjevanju poizvedbe je prišlo do napake. Kontaktirajte administratorja." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:122 -msgid "Please make sure all fields are filled out correctly" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:764 +msgid "" +"An error occurred while setting the tab database ID. Please contact your " +"administrator." msgstr "" +"Pri določanju ID-ja v podatkovne baze za zavihek je prišlo do napake. " +"Kontaktirajte administratorja." -#: superset/db_engine_specs/postgres.py:122 -msgid "Please re-enter the password." -msgstr "Ponovno vpišite geslo." +#: superset-frontend/src/SqlLab/actions/sqlLab.js:795 +msgid "" +"An error occurred while setting the tab schema. Please contact your administrator." +msgstr "" +"Pri določanju sheme zavihka je prišlo do napake. Kontaktirajte administratorja." -#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:59 -#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:72 -msgid "Please reach out to the Chart Owner for assistance." -msgstr "Za pomoč se obrnite na lastnika grafikona." +#: superset-frontend/src/SqlLab/actions/sqlLab.js:828 +msgid "" +"An error occurred while setting the tab autorun. Please contact your " +"administrator." +msgstr "" +"Pri določanju samodejnega zagona zavihka je prišlo do napake. Kontaktirajte " +"administratorja." -#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:75 -msgid "Please save the query to enable sharing" -msgstr "Shranite poizvedbo za deljenje" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:853 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:967 +msgid "" +"An error occurred while setting the tab title. Please contact your administrator." +msgstr "" +"Pri določanju naslova zavihka je prišlo do napake. Kontaktirajte administratorja." -#: superset/reports/commands/exceptions.py:90 -msgid "Please save your chart first, then try creating a new email report." +#: superset-frontend/src/SqlLab/actions/sqlLab.js:880 +msgid "Your query could not be saved" +msgstr "Vaše poizvedbe ni mogoče shraniti" + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:895 +msgid "Your query was not properly saved" +msgstr "Vaša poizvedba ni bila pravilno shranjena" + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:898 +msgid "Your query was saved" +msgstr "Vaša poizvedba je shranjena" + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:910 +msgid "Your query was updated" +msgstr "Vaša poizvedba je posodobljena" + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:914 +msgid "Your query could not be updated" +msgstr "Vaše poizvedbe ni mogoče posodobiti" + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:934 +msgid "" +"An error occurred while storing your query in the backend. To avoid losing your " +"changes, please save your query using the \"Save Query\" button." msgstr "" -"Najprej shranite grafikon, potem pa poskusite ustvariti novo e-poštno " -"poročilo." +"Pri shranjevanju vaše poizvedbe v sistem je prišlo do napake. Da ne izgubite " +"sprememb, shranite poizvedbo z gumbom \"Shrani poizvedbo\"." -#: superset/reports/commands/exceptions.py:102 -msgid "Please save your dashboard first, then try creating a new email report." +#: superset-frontend/src/SqlLab/actions/sqlLab.js:993 +msgid "" +"An error occurred while setting the tab template parameters. Please contact your " +"administrator." msgstr "" -"Najprej shranite nadzorno ploščo, potem pa poskusite ustvariti novo " -"e-poštno poročilo." +"Pri določanju parametrov predloge zavihka je prišlo do napake. Kontaktirajte " +"administratorja." -#: superset-frontend/src/addSlice/AddSliceContainer.tsx:322 -msgid "Please select both a Dataset and a Chart type to proceed" -msgstr "Za nadaljevanje izberite podatkovni set in tip grafikona" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1038 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1063 +msgid "An error occurred while fetching table metadata" +msgstr "Pri pridobivanju metapodatkov tabele je prišlo do napake" + +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1134 +msgid "" +"An error occurred while fetching table metadata. Please contact your " +"administrator." +msgstr "" +"Pri pridobivanju metapodatkov tabele je prišlo do napake. Kontaktirajte " +"administratorja." -#: superset/viz.py:1161 -msgid "Please use 3 different metric labels" -msgstr "Uporabite 3 različne oznake mer" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1182 +msgid "" +"An error occurred while expanding the table schema. Please contact your " +"administrator." +msgstr "" +"Pri širitvi sheme tabele je prišlo do napake. Kontaktirajte administratorja." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:104 -msgid "Please verify that port is open to connect." +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1206 +msgid "" +"An error occurred while collapsing the table schema. Please contact your " +"administrator." msgstr "" +"Pri krčenju sheme tabele je prišlo do napake. Kontaktirajte administratorja." -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:27 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1229 msgid "" -"Plots the individual metrics for each row in the data vertically and " -"links them together as a line. This chart is useful for comparing " -"multiple metrics across all of the samples or rows in the data." +"An error occurred while removing the table schema. Please contact your " +"administrator." msgstr "" -"Izriše posamezne mere za vsako vrstico podatkov navpično in jih med seboj" -" poveže kot črto. Grafikon je uporaben za primerjavo več mer med vsemi " -"vzorci ali vrsticami podatkov." +"Pri odstranjevanju sheme tabele je prišlo do napake. Kontaktirajte " +"administratorja." -#: superset/initialization/__init__.py:254 -msgid "Plugins" -msgstr "Vtičniki" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1262 +msgid "Shared query" +msgstr "Deljene poizvedbe" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:108 -msgid "Point Radius" -msgstr "Radij točk" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1325 +msgid "The datasource couldn't be loaded" +msgstr "Podatkovnega vira ni mogoče naložiti" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:132 -msgid "Point Radius Unit" -msgstr "Enota radija točk" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1355 +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1377 +msgid "An error occurred while creating the data source" +msgstr "Pri ustvarjanju podatkovnega vira je prišlo do težave" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:101 -msgid "Points" -msgstr "Točke" +#: superset-frontend/src/SqlLab/actions/sqlLab.js:1407 +msgid "An error occurred while fetching function names." +msgstr "Pri pridobivanju imen funkcij je prišlo do napake." -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:201 -msgid "Points and clusters will update as the viewport is being changed" -msgstr "Točke in gruče se bodo posodabljale, če se bo spremenil pogled" +#: superset-frontend/src/SqlLab/components/App/index.jsx:89 +#, python-format +msgid "" +"SQL Lab uses your browser's local storage to store queries and results.\n" +"Currently, you are using %(currentUsage)s KB out of %(maxStorage)d KB storage " +"space.\n" +"To keep SQL Lab from crashing, please delete some query tabs.\n" +"You can re-access these queries by using the Save feature before you delete the " +"tab.\n" +"Note that you will need to close other SQL Lab windows before you do this." +msgstr "" +"SQL laboratorij uporablja lokalno shrambo brskalnika za shranjevanje poizvedb in " +"rezultatov.\n" +"Trenutno uporabljate %(currentUsage)s KB od %(maxStorage)d KB prostora.\n" +"Da preprečite sesutje SQL laba, izbrišite nekaj zavihkov s poizvedbami.\n" +"Poizvedbe lahko ponovno pridobite, če pred brisanjem uporabite funkcijo Shrani.\n" +"Pred tem morate zapreti druga okna SQL laboratorija." -#: superset/views/sql_lab.py:74 -msgid "Pop Tab Link" -msgstr "Prikaži povezavo zavihka" +#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:84 +msgid "Estimate selected query cost" +msgstr "Oceni potratnost izbrane poizvedbe" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:44 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:40 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:46 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:70 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:85 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:86 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:77 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:78 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:47 -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:124 -msgid "Popular" -msgstr "Priljubljeni" +#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:85 +msgid "Estimate cost" +msgstr "Oceni potratnost" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:170 -msgid "Populate \"Default value\" to enable this control" -msgstr "Izpolnite \"Privzeto vrednost\", da omogočite ta kontrolnik" +#: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:89 +msgid "Cost estimate" +msgstr "Ocena potratnosti" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:33 -msgid "Population age data" -msgstr "Podatki starosti populacije" +#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx:70 +msgid "Creating a data source and creating a new tab" +msgstr "Ustvarjanje podatkovnega vira in novega zavihka" -#: superset/db_engine_specs/mssql.py:87 -#: superset/db_engine_specs/postgres.py:132 -#: superset/db_engine_specs/presto.py:213 -#: superset/db_engine_specs/redshift.py:73 -#, python-format -msgid "Port %(port)s on hostname \"%(hostname)s\" refused the connection." -msgstr "Vrata %(port)s na gostitelju \"%(hostname)s\" niso sprejela povezave." +#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx:75 +#: superset-frontend/src/components/TableLoader/index.tsx:55 +#: superset-frontend/src/utils/getClientErrorObject.ts:161 +msgid "An error occurred" +msgstr "Prišlo je do napake" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:103 -#, fuzzy -msgid "Port is closed" -msgstr "Vrata so zaprta." +#: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.tsx:83 +#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx:41 +msgid "Explore the result set in the data exploration view" +msgstr "Raziščite rezultate v pogledu raziskovanja podatkov" -#: superset/views/dashboard/mixin.py:87 -msgid "Position JSON" -msgstr "JSON za postavitev" +#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx:48 +msgid "Create Chart" +msgstr "Ustvarite grafikon" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:181 -msgid "Position of child node label on tree" -msgstr "Položaj oznake podrejenega vozlišča na drevesu" +#: superset-frontend/src/SqlLab/components/HighlightedSql/index.tsx:76 +msgid "Source SQL" +msgstr "Izvorni SQL" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:310 -msgid "Position of column level subtotal" -msgstr "Položaj vsot na nivoju stolpcev" +#: superset-frontend/src/SqlLab/components/HighlightedSql/index.tsx:82 +msgid "Executed SQL" +msgstr "Izvedena poizvedba" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:163 -msgid "Position of intermidiate node label on tree" -msgstr "Položaj vmesne oznake vozlišča na drevesu" +#: superset-frontend/src/SqlLab/components/HighlightedSql/index.tsx:101 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1074 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:294 +msgid "SQL" +msgstr "SQL" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:293 -msgid "Position of row level subtotal" -msgstr "Položaj vsot na nivoju vrstic" +#: superset-frontend/src/SqlLab/components/QueryHistory/index.tsx:74 +msgid "Run a query to display query history" +msgstr "Za prikaz zgodovine poizvedb zaženite poizvedbo" -#: superset-frontend/src/components/Menu/MenuRight.tsx:180 -msgid "Powered by Apache Superset" -msgstr "Omogoča Apache Superset" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:121 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:53 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:142 +msgid "Success" +msgstr "Uspelo" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1096 -msgid "Pre-filter" -msgstr "Predfilter" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:127 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:133 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:153 +msgid "Failed" +msgstr "Ni uspelo" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1061 -msgid "Pre-filter available values" -msgstr "Predfiltriraj razpoložljive vrednosti" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:139 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:158 +msgid "Running" +msgstr "V teku" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:623 -msgid "Pre-filter is required" -msgstr "Zahtevan je predfilter" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:145 +msgid "Fetching" +msgstr "Pridobivam" -#: superset/connectors/sqla/views.py:451 -msgid "" -"Predicate applied when fetching distinct value to populate the filter " -"control component. Supports jinja template syntax. Applies only when " -"`Enable Filter Select` is on." -msgstr "" -"Privzeta vrednost za pridobivanje različnih vrednost pri oblikovanju " -"filtrov. Podpira sintakso za jinja predloge. Potrebno le, ko je vključeno" -" `Omogoči izbiro filtra`." +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:151 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:163 +msgid "Offline" +msgstr "Offline" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:39 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:75 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:78 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:78 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:73 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:72 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:74 -msgid "Predictive" -msgstr "Prediktivno" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:157 +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:163 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:168 +msgid "Scheduled" +msgstr "V urniku" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:36 -msgid "Predictive Analytics" -msgstr "Prediktivna analitika" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:169 +msgid "Unknown Status" +msgstr "Neznan status" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:64 -msgid "Prefix metric name with slice name" -msgstr "Imenu mere pripni ime rezine" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:218 +#: superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.tsx:35 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:83 +#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:127 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:334 +#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:129 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:432 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:86 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:404 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:415 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:428 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:220 +msgid "Edit" +msgstr "Urejanje" -#: superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.tsx:39 -msgid "Preview" -msgstr "Predogled" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:237 +msgid "View" +msgstr "Pogled" -#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:166 -#, python-format -msgid "Preview: `%s`" -msgstr "Predogled: `%s`" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:240 +msgid "Data preview" +msgstr "Ogled podatkov" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:32 -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:125 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:105 -msgid "Previous" -msgstr "Prejšnji" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:280 +msgid "Overwrite text in the editor with a query on this table" +msgstr "Besedilo v urejevalniku prepišite s poizvedbo na to tabelo" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:243 -msgid "Primary" -msgstr "Primarna" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:289 +msgid "Run query in a new tab" +msgstr "Zaženi poizvedbo v novem zavihku" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:56 -msgid "Primary Metric" -msgstr "Primarna mera" +#: superset-frontend/src/SqlLab/components/QueryTable/index.tsx:296 +msgid "Remove query from log" +msgstr "Odstrani poizvedbo iz dnevnika" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:248 -msgid "Primary or secondary y-axis" -msgstr "Primarna ali sekundarna y-os" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:228 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:397 +msgid "Save & Explore" +msgstr "Shrani & Razišči" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:371 -msgid "Primary y-axis format" -msgstr "Oblika primarne y-osi" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:229 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:398 +msgid "Overwrite & Explore" +msgstr "Prepiši & Razišči" -#: superset-frontend/src/components/Menu/MenuRight.tsx:161 -#: superset/templates/appbuilder/navbar_right.html:109 -msgid "Profile" -msgstr "Profil" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:230 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:399 +msgid "Save this query as a virtual dataset to continue exploring" +msgstr "Shranite poizvedbo kot virtualni podatkovni set" -#: superset-frontend/src/profile/components/UserInfo.tsx:44 -msgid "Profile picture provided by Gravatar" -msgstr "Profilno sliko je zagotovil Gravatar" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:245 +msgid "Download to CSV" +msgstr "Izvozi kot CSV" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:239 -msgid "Progress" -msgstr "Območje" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:254 +msgid "Copy to Clipboard" +msgstr "Kopiraj na odložišče" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:30 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:56 -msgid "Progressive" -msgstr "Progresivno" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:269 +msgid "Too many columns to filter" +msgstr "Preveč stolpcev za filtriranje" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:55 -msgid "Propagate" -msgstr "Razširi" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:270 +msgid "Filter results" +msgstr "Filtriraj rezultate" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:39 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:42 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:46 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:50 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:43 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:71 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:64 -msgid "Proportional" -msgstr "Proporcionalno" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:289 +#, python-format +msgid "" +"The number of results displayed is limited to %(rows)d by the configuration " +"DISPLAY_MAX_ROWS. Please add additional limits/filters or download to csv to see " +"more rows up to the %(limit)d limit." +msgstr "" +"Število prikazanih rezultatov je omejeno na %(rows)d na podlagi parametra " +"DISPLAY_MAX_ROWS. V csv dodajte dodatne omejitve/filtre, da boste lahko videli " +"več vrstic do meje %(limit)d ." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:86 -msgid "Public and privately shared sheets" -msgstr "Javno in zasebno deljene preglednice" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:295 +#, python-format +msgid "" +"The number of results displayed is limited to %(rows)d. Please add additional " +"limits/filters, download to csv, or contact an admin to see more rows up to the " +"%(limit)d limit." +msgstr "" +"Število prikazanih rezultatov je omejeno na %(rows)d . V csv dodajte dodatne " +"omejitve/filtre, da boste lahko videli več vrstic do meje %(limit)d ." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:83 -msgid "Publicly shared sheets only" -msgstr "Samo javno deljene preglednice" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:307 +#, python-format +msgid "The number of rows displayed is limited to %(rows)d by the query" +msgstr "Število prikazanih vrstic je omejeno na %(rows)d s poizvedbo" -#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:101 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:301 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:498 -#: superset/views/dashboard/mixin.py:84 -msgid "Published" -msgstr "Objavljeno" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:315 +#, python-format +msgid "The number of rows displayed is limited to %(rows)d by the limit dropdown." +msgstr "Število prikazanih rezultatov je omejeno na %(rows)d s poizvedbo." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:109 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:161 -msgid "Put labels outside" -msgstr "Postavi oznake zunaj" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:320 +#, python-format +msgid "" +"The number of rows displayed is limited to %(rows)d by the query and limit " +"dropdown." +msgstr "" +"Število prikazanih vrstic je omejeno na %(rows)d s poizvedbo in spustnim " +"izbirnikom omejitev." -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:164 -msgid "Put the labels outside of the pie?" -msgstr "Postavim oznake zunaj torte?" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:326 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:344 +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:358 +#, python-format +msgid "%(rows)d rows returned" +msgstr "%(rows)d vrnjenih vrstic" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:112 -msgid "Put the labels outside the pie?" -msgstr "Postavim oznake zunaj torte?" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:346 +#, python-format +msgid "The number of rows displayed is limited to %s by the dropdown." +msgstr "Število prikazanih vrstic je omejeno na %s s spustnim izbirnikom." -#: superset-frontend/src/explore/controlPanels/Separator.js:47 -msgid "Put your code here" -msgstr "Vstavite svojo kodo sem" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:383 +msgid "Query was stopped" +msgstr "Poizvedba je bila ustavljena" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:351 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:234 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:485 -msgid "Python Functions" -msgstr "Pythonove funkcije" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:389 +msgid "Database error" +msgstr "Napaka podatkovne baze" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:233 -msgid "Python datetime string pattern" -msgstr "Pythonov vzorec zapisa datum-časa" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:416 +msgid "was created" +msgstr "ustvarjeno" -#: superset-frontend/src/explore/controlPanels/sections.tsx:248 -msgid "Python functions" -msgstr "Pythonove funkcije" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:423 +msgid "Query in a new tab" +msgstr "Poizvedba v novem zavihku" -#: superset/db_engine_specs/base.py:99 -msgid "Quarter" -msgstr "Četrtletje" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:479 +msgid "The query returned no data" +msgstr "Poizvedba ni vrnila podatkov" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:69 -#, fuzzy, python-format -msgid "Quarters %s" -msgstr "Četrtletje" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:496 +msgid "Fetch data preview" +msgstr "Pridobi predogled podatkov" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:32 -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:32 -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:91 -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:65 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:60 -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:30 -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:45 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:36 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:33 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:34 -#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:31 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:30 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:34 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:32 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:26 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:60 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:158 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:341 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:29 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:43 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:34 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:41 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:34 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:44 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:48 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:59 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:56 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:52 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:53 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:59 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:60 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:42 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:38 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:41 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:179 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:26 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:30 -#: superset-frontend/src/explore/controlPanels/TimeTable.js:26 -#: superset-frontend/src/explore/controlPanels/sections.tsx:113 -#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:34 -#: superset-frontend/src/filters/components/Range/controlPanel.ts:31 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:41 -#: superset-frontend/src/filters/components/Time/controlPanel.ts:29 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:178 -msgid "Query" -msgstr "Poizvedba" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:507 +msgid "Refetch results" +msgstr "Ponovno pridobi rezultate" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:253 -#, python-format -msgid "Query %s: %s" -msgstr "" +#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:528 +msgid "Track job" +msgstr "Sledi opravilom" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:258 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:283 -msgid "Query A" -msgstr "Poizvedba A" +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:50 +#: superset-frontend/src/explore/components/RunQueryButton/index.tsx:45 +msgid "Stop" +msgstr "Ustavi" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:259 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:284 -msgid "Query B" -msgstr "Poizvedba B" +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:55 +msgid "Run selection" +msgstr "Zaženi izbrano" -#: superset/initialization/__init__.py:341 -msgid "Query History" -msgstr "Zgodovina poizvedb" +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:57 +msgid "Run" +msgstr "Zaženi" -#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:197 -#: superset-frontend/src/views/CRUD/data/common.ts:44 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:89 -msgid "Query history" -msgstr "Zgodovina poizvedb" +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:113 +msgid "Stop running (Ctrl + x)" +msgstr "Ustavi (Ctrl + x)" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:722 -msgid "Query in a new tab" -msgstr "Poizvedba v novem zavihku" +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:114 +msgid "Stop running (Ctrl + e)" +msgstr "Ustavi (Ctrl + e)" -#: superset/errors.py:125 -msgid "Query is too complex and takes too long to run." -msgstr "Poizvedba je prekompleksna in se izvaja predolgo." +#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:129 +msgid "Run query (Ctrl + Return)" +msgstr "Zaženi poizvedbo (Ctrl + Return)" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:89 -msgid "Query mode" -msgstr "Poizvedbeni način" +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:252 +msgid "An error occurred saving dataset" +msgstr "Pri shranjevanju podatkovnega seta je prišlo do napake" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:125 -msgid "Query name" -msgstr "Ime poizvedbe" +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:294 +msgid "Save or Overwrite Dataset" +msgstr "Shrani ali prepiši podatkovni set" -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:117 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:376 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:97 -msgid "Query preview" -msgstr "Predogled poizvedbe" +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:336 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:187 +msgid "Save as new" +msgstr "Shrani kot novo" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "Iskalni niz za poizvedbo" +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:345 +msgid "Overwrite existing" +msgstr "Prepiši obstoječe" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 -msgid "Query was stopped" -msgstr "Poizvedba je bila ustavljena" +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:355 +msgid "Select or type dataset name" +msgstr "Izberite ali vnesite naziv podatkovnega seta" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:407 -msgid "Query was stopped." -msgstr "Poizvedba je bila ustavljena." +#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:366 +msgid "Are you sure you want to overwrite this dataset?" +msgstr "Ali ste prepričani, da želite prepisati podatkovni set?" -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:292 -#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:294 -msgid "RANGE TYPE" -msgstr "TIP OBDOBJA" +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:76 +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:134 +msgid "Undefined" +msgstr "Ni definirano" -#: superset-frontend/src/components/ReportModal/index.tsx:327 -msgid "REPORT NAME ERROR" -msgstr "NAPAKA NAZIVA POROČILA" +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:166 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:172 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:187 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:240 +#: superset-frontend/src/components/ReportModal/index.tsx:223 +#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:88 +#: superset-frontend/src/dashboard/components/Header/index.jsx:589 +#: superset-frontend/src/dashboard/components/Header/index.jsx:591 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:100 +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:150 +#: superset-frontend/src/dashboard/components/SaveModal.tsx:220 +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:532 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:156 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:71 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:446 +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:202 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:217 +#: superset-frontend/src/explore/components/SaveModal.tsx:219 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:354 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:271 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:498 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:345 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1057 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:273 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:230 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:220 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1235 +msgid "Save" +msgstr "Shrani" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:251 -msgid "RGB Color" -msgstr "RGB barva" +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:166 +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:172 +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:303 +msgid "Save as" +msgstr "Shrani kot" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:161 -msgid "Radar" -msgstr "Radar" +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:175 +msgid "Save query" +msgstr "Shrani poizvedbo" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:53 -msgid "Radar Chart" -msgstr "Radarski grafikon" +#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:196 +msgid "Update" +msgstr "Posodobi" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:201 -msgid "Radar render type, whether to display 'circle' shape." -msgstr "Način prikaza radarja - če se prikaže okrogla oblika." +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:172 +msgid "Label for your query" +msgstr "Ime vaše poizvedbe" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:121 -msgid "Radial" -msgstr "Radialna" +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:186 +msgid "Write a description for your query" +msgstr "Dodajte opis vaše poizvedbe" -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:318 -#, python-format -msgid "Ran %s" -msgstr "Pretečeno %s" +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:231 +msgid "Schedule query" +msgstr "Urnik poizvedb" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:35 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 -msgid "Range" -msgstr "Doseg" +#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:241 +#: superset-frontend/src/components/ReportModal/index.tsx:300 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:236 +msgid "Schedule" +msgstr "Urnik" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:295 -#: superset-frontend/src/filters/components/Range/index.ts:28 -msgid "Range filter" -msgstr "Filter obdobja" +#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:61 +msgid "There was an error with your request" +msgstr "Pri zahtevi je prišlo do napake" -#: superset-frontend/src/filters/components/Range/index.ts:29 -msgid "Range filter plugin using AntD" -msgstr "Vtičnik za filter obdobja z uporabo AntD" +#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:75 +msgid "Please save the query to enable sharing" +msgstr "Shranite poizvedbo za deljenje" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:48 -msgid "Range labels" -msgstr "Oznake razponov" +#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:88 +msgid "Copy query link to your clipboard" +msgstr "Kopiraj povezavo do poizvedbe v odložišče" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:39 -msgid "Ranges" -msgstr "Razponi" +#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:89 +msgid "Save the query to enable this feature" +msgstr "Za omogočenje te funkcije shranite poizvedbo" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:41 -msgid "Ranges to highlight with shading" -msgstr "Razponi za označitev s senčenjem" +#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:98 +msgid "Copy link" +msgstr "Kopiraj povezavo" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:25 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:25 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:28 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:48 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:33 -msgid "Ranking" -msgstr "Rangiranje" +#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:157 +msgid "No stored results found, you need to re-run your query" +msgstr "Rezultatov še ni shranjenih, ponovno morate zagnati poizvedbo" -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:63 -msgid "Ratio" -msgstr "Razmerje" +#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:183 +#: superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:95 +msgid "Run a query to display results" +msgstr "Za prikaz rezultatov morate zagnati poizvedbo" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:46 -msgid "Raw records" -msgstr "Surovi podatki" +#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:195 +#, python-format +msgid "Preview: `%s`" +msgstr "Predogled: `%s`" -#: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:64 -msgid "Ready to review filters in this dashboard?" -msgstr "Ste pripravljeni za pregled filtrov v tej nadzorni plošči?" +#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:223 +#: superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:200 +#: superset-frontend/src/explore/components/DataTablesPane/components/ResultsPaneOnDashboard.tsx:52 +msgid "Results" +msgstr "Rezultati" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:78 -msgid "Rebuild" -msgstr "Obnovi" +#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:226 +#: superset-frontend/src/views/CRUD/data/common.ts:44 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:89 +msgid "Query history" +msgstr "Zgodovina poizvedb" -#: superset-frontend/src/profile/components/App.tsx:72 -msgid "Recent activity" -msgstr "Nedavna aktivnost" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:326 +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:336 +msgid "Run query" +msgstr "Zaženi poizvedbo" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:86 -msgid "Recently created charts, dashboards, and saved queries will appear here" -msgstr "" -"Nedavno ustvarjeni grafikoni, nadzorne plošče in shranjene poizvedbe bodo" -" prikazane tukaj" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:346 +msgid "New tab" +msgstr "Nov zavihek" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:96 -msgid "Recently edited charts, dashboards, and saved queries will appear here" -msgstr "" -"Nedavno urejani grafikoni, nadzorne plošče in shranjene poizvedbe bodo " -"prikazane tukaj" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:358 +msgid "Stop query" +msgstr "Ustavi poizvedbo" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:561 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:535 -msgid "Recently modified" -msgstr "Nedavno spremenjeno" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:367 +msgid "Previous Line" +msgstr "Prejšnja linija" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:81 -msgid "Recently viewed charts, dashboards, and saved queries will appear here" -msgstr "" -"Nedavno ogledani grafikoni, nadzorne plošče in shranjene poizvedbe bodo " -"prikazane tukaj" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:560 +msgid "Schedule the query periodically" +msgstr "Periodično zaganjaj poizvedbo" -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:277 -msgid "Recents" -msgstr "Nedavno" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:561 +msgid "You must run the query successfully first" +msgstr "Najprej morate uspešno izvesti poizvedbo" -#: superset/views/schedules.py:242 superset/views/schedules.py:322 -msgid "Recipients" -msgstr "Prejemniki" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:566 +msgid "Autocomplete" +msgstr "Samodokončaj" -#: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:160 -msgid "Recipients are separated by \",\" or \";\"" -msgstr "Prejemniki so ločeni z \",\" ali \";\"" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:647 +msgid "CREATE TABLE AS" +msgstr "CREATE TABLE AS" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:597 -msgid "Recommended tags" -msgstr "Priporočene značke" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:660 +msgid "CREATE VIEW AS" +msgstr "CREATE VIEW AS" -#: superset/templates/appbuilder/general/widgets/base_list.html:55 -msgid "Record Count" -msgstr "Število zapisov" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:692 +msgid "Estimate the cost before running a query" +msgstr "Oceni potratnost pred zagonom poizvedbe" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:222 -msgid "Rectangle" -msgstr "Pravokotnik" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:776 +msgid "Select a database to write a query" +msgstr "Izberite podatkovno bazo za poizvedbo" -#: superset/connectors/druid/views.py:330 -msgid "" -"Redirects to this endpoint when clicking on the datasource from the " -"datasource list" -msgstr "" -"Preusmeri v to končno točko, ko kliknete na podatkovni vir v seznamu " -"podatkovnih virov" +#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:777 +msgid "Choose one of the available databases from the panel on the left." +msgstr "Izberite eno od razpoložljivih podatkovnih baz v panelu na levi." -#: superset/connectors/sqla/views.py:457 -msgid "Redirects to this endpoint when clicking on the table from the table list" -msgstr "Preusmeri v to končno točko, ko kliknete na tabelo v seznamu tabel" +#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx:171 +msgid "Collapse table preview" +msgstr "Zapri predogled tabele" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:316 -msgid "Reduce X ticks" -msgstr "Manj oznak X-osi" +#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx:171 +msgid "Expand table preview" +msgstr "Odpri predogled tabele" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:319 -msgid "" -"Reduces the number of X-axis ticks to be rendered. If true, the x-axis " -"will not overflow and labels may be missing. If false, a minimum width " -"will be applied to columns and the width may overflow into an horizontal " -"scroll." -msgstr "" -"Zmanjša število izrisanih oznak na X-osi. Če je vklopljeno, se x-os ne bo" -" prelila in lahko oznake manjkajo. Če je izklopljeno, bo upoštevana min. " -"širina stolpcev, ki pa se lahko prelije v horizontalni drsnik." +#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx:191 +msgid "No databases match your search" +msgstr "Nobena podatkovna baza ne ustreza iskanju" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:78 -msgid "Refer to the" -msgstr "Obrnite se na" +#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx:192 +msgid "There are no databases available" +msgstr "Podatkovnih baz ni na voljo" -#: superset/utils/pandas_postprocessing.py:143 -msgid "Referenced columns not available in DataFrame." -msgstr "Referencirani stolpci niso razpoložljivi v Dataframe-u." +#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx:196 +msgid "Manage your databases" +msgstr "Upravljajte podatkovne baze" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:799 -msgid "Refetch results" -msgstr "Ponovno pridobi rezultate" +#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx:197 +#: superset-frontend/src/components/ImportModal/ErrorAlert.tsx:55 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:122 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:771 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1365 +msgid "here" +msgstr "tukaj" -#: superset/templates/appbuilder/general/widgets/search.html:57 -msgid "Refresh" -msgstr "Osveži" +#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx:266 +msgid "Reset state" +msgstr "Ponastavi stanje" -#: superset/initialization/__init__.py:542 -msgid "Refresh Druid Metadata" -msgstr "Osveži metapodatke za Druid" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:241 +msgid "Enter a new title for the tab" +msgstr "Vnesite novo naslov zavihka" -#: superset/connectors/sqla/views.py:565 -msgid "Refresh Metadata" -msgstr "Osveži metapodatke" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:262 +msgid "" +"-- Note: Unless you save your query, these tabs will NOT persist if you clear " +"your cookies or change browsers.\n" +"\n" +msgstr "" +"-- Opomba: Če ne shranite poizvedbe, se ti zavihki NE bodo ohranili, ko boste " +"počistili piškote ali zamenjali brskalnik.\n" +"\n" -#: superset/connectors/sqla/views.py:565 -msgid "Refresh column metadata" -msgstr "Osveži metapodatke stolpca" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:345 +msgid "Close tab" +msgstr "Zapri zavihek" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:276 -msgid "Refresh dashboard" -msgstr "Osveži nadzorno ploščo" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:351 +msgid "Rename tab" +msgstr "Preimenuj zavihek" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:117 -msgid "Refresh frequency" -msgstr "Frekvenca osveževanja" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:357 +msgid "Expand tool bar" +msgstr "Razširi orodno vrstico" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:114 -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:119 -msgid "Refresh interval" -msgstr "Interval osveževanja" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:357 +msgid "Hide tool bar" +msgstr "Skrij orodno vrstico" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:976 -msgid "Refresh the default values" -msgstr "Osveži privzete vrednosti" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:366 +msgid "Close all other tabs" +msgstr "Zapri vse ostale zavihke" -#: superset/connectors/druid/views.py:420 -msgid "Refreshed metadata from cluster [{}]" -msgstr "Osveženi meta-podatki iz gruče [{}]" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:372 +msgid "Duplicate tab" +msgstr "Podvoji zavihek" -#: superset/connectors/druid/models.py:259 -msgid "Refreshing datasource [{}]" -msgstr "Osveževanje podatkovnega vira [{}]" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:410 +msgid "Add a new tab" +msgstr "Dodaj nov zavihek" -#: superset/connectors/sqla/views.py:335 -msgid "" -"Regular filters add where clauses to queries if a user belongs to a role " -"referenced in the filter. Base filters apply filters to all queries " -"except the roles defined in the filter, and can be used to define what " -"users can see if no RLS filters within a filter group apply to them." -msgstr "" -"Navadni filtri dodajo WHERE stavek v poizvedbe, če ima uporabnik vlogo " -"podano v filtru. Osnovni filtri filtrirajo vse poizvedbe, razen vlog, " -"definiranih v filtru, in jih je mogoče uporabiti za nastavitev tega kaj " -"uporabnik vidi, če v skupini filtrov ni RLS-filtrov, ki bi se nanašali " -"nanje." +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:416 +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:458 +msgid "New tab (Ctrl + q)" +msgstr "Nov zavihek (Ctrl + q)" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:40 -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:43 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:44 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:44 -msgid "Relational" -msgstr "Relacijsko" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:417 +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:459 +msgid "New tab (Ctrl + t)" +msgstr "Nov zavihek (Ctrl + t)" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:32 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:35 -msgid "Relationships between community channels" -msgstr "Razmerja med skupnostnimi kanali" +#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:434 +msgid "Add a new tab to create SQL Query" +msgstr "Dodaj nov zavihek za SQL-poizvedbo" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:91 -msgid "Relative Date/Time" -msgstr "Relativen Datum/Čas" +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:103 +msgid "Copy partition query to clipboard" +msgstr "Kopiraj particijsko poizvedbo na odložišče" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:157 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:210 -msgid "Relative period" -msgstr "Relativno obdobje" +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:120 +msgid "latest partition:" +msgstr "zadnja particija:" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:145 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:198 -msgid "Relative quantity" -msgstr "Relativne vrednosti" +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:157 +msgid "Keys for table" +msgstr "Ključi za tabele" -#: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:69 -msgid "Remind me in 24 hours" -msgstr "Opomni me čez 24 ur" +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:166 +#, python-format +msgid "View keys & indexes (%s)" +msgstr "Ogled ključev in indeksov (%s)" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:779 -msgid "Remove" -msgstr "Odstrani" +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:183 +msgid "Original table column order" +msgstr "Vrstni red stolpcev izvorne tabele" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:77 -msgid "Remove invalid filters" -msgstr "Odstrani neveljavne filtre" +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:184 +msgid "Sort columns alphabetically" +msgstr "Razvrsti stolpce po abecedi" -#: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:142 -msgid "Remove item" -msgstr "Odstrani element" +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:192 +msgid "Copy SELECT statement to the clipboard" +msgstr "Kopiraj stavek SELECT na odložišče" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:282 -msgid "Remove query from log" -msgstr "Odstrani poizvedbo iz dnevnika" +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:204 +msgid "Show CREATE VIEW statement" +msgstr "Prikaži CREATE VIEW stavek" + +#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:205 +msgid "CREATE VIEW statement" +msgstr "CREATE VIEW stavek" #: superset-frontend/src/SqlLab/components/TableElement/index.tsx:211 msgid "Remove table preview" msgstr "Odstrani predogled tabele" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:609 +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:98 +msgid "Edit template parameters" +msgstr "Uredi parametre predloge" + +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:102 +msgid "Parameters " +msgstr "Parametri " + +#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:108 +msgid "Invalid JSON" +msgstr "Neveljaven JSON" + +#: superset-frontend/src/SqlLab/reducers/getInitialState.js:44 +msgid "Untitled query" +msgstr "Neimenovana poizvedba" + +#: superset-frontend/src/SqlLab/utils/newQueryTabName.ts:43 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:124 #, python-format -msgid "Removed columns: %s" -msgstr "Odstranjeni stolpci: %s" +msgid "%s%s" +msgstr "%s%s" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:345 -msgid "Rename tab" -msgstr "Preimenuj zavihek" +#: superset-frontend/src/addSlice/AddSliceContainer.tsx:281 +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:168 +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:191 +msgid "Create a new chart" +msgstr "Ustvari nov grafikon" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:146 -msgid "Rendering" -msgstr "Izris" +#: superset-frontend/src/addSlice/AddSliceContainer.tsx:284 +#: superset-frontend/src/addSlice/AddSliceContainer.tsx:295 +msgid "Choose a dataset" +msgstr "Izberite podatkovni set" -#: superset/views/database/forms.py:146 superset/views/database/forms.py:299 -#: superset/views/database/forms.py:427 -msgid "Replace" -msgstr "Zamenjaj" +#: superset-frontend/src/addSlice/AddSliceContainer.tsx:290 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx:89 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:802 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:831 +#: superset-frontend/src/explore/components/ExploreViewContainer/index.jsx:606 +#: superset-frontend/src/explore/controls.jsx:189 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:311 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:553 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:560 +msgid "Dataset" +msgstr "Podatkovni set" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:36 -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:36 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:41 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:46 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:57 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:48 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:59 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:48 -msgid "Report" -msgstr "Poročilo" +#: superset-frontend/src/addSlice/AddSliceContainer.tsx:300 +msgid "Instructions to add a dataset are available in the Superset tutorial." +msgstr "Navodila za dodajanje podatkovnega seta so v vodiču za Superset." -#: superset/reports/commands/exceptions.py:118 -msgid "Report Schedule could not be created." -msgstr "Urnika poročanja ni mogoče ustvariti." +#: superset-frontend/src/addSlice/AddSliceContainer.tsx:315 +msgid "Choose chart type" +msgstr "Izberite tip grafikona" -#: superset/reports/commands/exceptions.py:114 -msgid "Report Schedule could not be deleted." -msgstr "Urnika poročanja ni mogoče izbrisati." +#: superset-frontend/src/addSlice/AddSliceContainer.tsx:329 +msgid "Please select both a Dataset and a Chart type to proceed" +msgstr "Za nadaljevanje izberite podatkovni set in tip grafikona" -#: superset/reports/commands/exceptions.py:122 -msgid "Report Schedule could not be updated." -msgstr "Urnika poročanja ni mogoče posodobiti." +#: superset-frontend/src/addSlice/AddSliceContainer.tsx:337 +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:288 +msgid "Create new chart" +msgstr "Ustvari nov grafikon" -#: superset/reports/commands/exceptions.py:130 -msgid "Report Schedule delete failed." -msgstr "Izbris urnika poročanja ni uspel." +#: superset-frontend/src/components/AlteredSliceTag/index.jsx:201 +msgid "Click to see difference" +msgstr "Kliknite za prikaz razlike" -#: superset/reports/commands/exceptions.py:142 -msgid "Report Schedule execution failed when generating a csv." -msgstr "Izvajanje urnika poročanja je bilo neuspešno pri ustvarjanju csv." +#: superset-frontend/src/components/AlteredSliceTag/index.jsx:202 +msgid "Altered" +msgstr "Spremenjeno" -#: superset/reports/commands/exceptions.py:146 -msgid "Report Schedule execution failed when generating a dataframe." -msgstr "" -"Izvajanje urnika poročanja je bilo neuspešno pri ustvarjanju podatkovnega" -" okvira." +#: superset-frontend/src/components/AlteredSliceTag/index.jsx:218 +msgid "Chart changes" +msgstr "Spremembe grafikona" -#: superset/reports/commands/exceptions.py:138 -msgid "Report Schedule execution failed when generating a screenshot." -msgstr "" -"Izvajanje urnika poročanja je bilo neuspešno pri ustvarjanju zaslonske " -"slike." +#: superset-frontend/src/components/AsyncSelect/index.jsx:41 +#: superset-frontend/src/components/Select/Select.tsx:311 +#: superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx:106 +#: superset-frontend/src/explore/components/controls/SelectControl.jsx:231 +msgid "Select ..." +msgstr "Izberite ..." -#: superset/reports/commands/exceptions.py:150 -msgid "Report Schedule execution got an unexpected error." -msgstr "Pri izvajanju urnika poročanja je prišlo do nepričakovane napake." +#: superset-frontend/src/components/CachedLabel/TooltipContent.tsx:30 +msgid "Loaded data cached" +msgstr "Podatki so naloženi v predpomnilnik" -#: superset/reports/commands/exceptions.py:154 -msgid "Report Schedule is still working, refusing to re-compute." -msgstr "Urnik poročanja se še vedno izvaja, ponovni izračun je zavrnjen." +#: superset-frontend/src/components/CachedLabel/TooltipContent.tsx:34 +msgid "Loaded from cache" +msgstr "Naloženo iz predpomnilnika" -#: superset/reports/commands/exceptions.py:134 -msgid "Report Schedule log prune failed." -msgstr "Krajšanje dnevnika urnika poročanja ni uspelo." +#: superset-frontend/src/components/CachedLabel/TooltipContent.tsx:39 +msgid "Click to force-refresh" +msgstr "Kliknite za prisilno osvežitev" -#: superset/reports/commands/exceptions.py:126 -msgid "Report Schedule not found." -msgstr "Urnika poročanja ni najden." +#: superset-frontend/src/components/CachedLabel/index.tsx:51 +msgid "Cached" +msgstr "Predpomnjeno" -#: superset/reports/commands/exceptions.py:110 -msgid "Report Schedule parameters are invalid." -msgstr "Parametri urnika poročanja so neveljavni." +#: superset-frontend/src/components/Chart/Chart.jsx:265 +msgid "Add required control values to preview chart" +msgstr "Dodaj potrebne parametre za predogled grafikona" -#: superset/reports/commands/exceptions.py:158 -msgid "Report Schedule reached a working timeout." -msgstr "Urnik poročanja je dosegel mejo časa izvedbe." +#: superset-frontend/src/components/Chart/Chart.jsx:281 +msgid "Your chart is ready to go!" +msgstr "Grafikon je pripravljen!" -#: superset/reports/commands/exceptions.py:226 -msgid "Report Schedule sellenium user not found" -msgstr "Selenium uporabnik za urnik poročanja ni najden" +#: superset-frontend/src/components/Chart/Chart.jsx:284 +msgid "" +"Click on \"Create chart\" button in the control panel on the left to preview a " +"visualization or" +msgstr "" +"Kliknite na gumb \"Ustvari grafikon\" v kontrolni plošči na levi za predogled ali" -#: superset/reports/commands/exceptions.py:230 -msgid "Report Schedule state not found" -msgstr "Stanje urnika poročanj ni najdeno" +#: superset-frontend/src/components/Chart/Chart.jsx:288 +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:305 +msgid "click here" +msgstr "kliknite tukaj" -#: superset-frontend/src/components/Menu/MenuRight.tsx:225 -msgid "Report a bug" -msgstr "Sporočite napako" +#: superset-frontend/src/components/Chart/ChartRenderer.jsx:227 +#: superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:119 +msgid "No results were returned for this query" +msgstr "Poizvedba ni vrnila rezultatov" -#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:81 -msgid "Report failed" -msgstr "Poročilo ni uspelo" +#: superset-frontend/src/components/Chart/ChartRenderer.jsx:230 +msgid "" +"Make sure that the controls are configured properly and the datasource contains " +"data for the selected time range" +msgstr "" +"Poskrbite, da so kontrolniki pravilno nastavljeni in podatkovni vir vsebuje " +"podatke za izbrano časovno obdobje" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1064 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1072 -msgid "Report name" -msgstr "Naslov poročila" +#: superset-frontend/src/components/Chart/chartAction.js:571 +msgid "An error occurred while loading the SQL" +msgstr "Pri nalaganju SQL je prišlo do napake" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1214 -msgid "Report schedule" -msgstr "Urnik poročanja" +#: superset-frontend/src/components/Chart/chartAction.js:609 +#: superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:75 +msgid "Sorry, an error occurred" +msgstr "Prišlo je do napake" -#: superset/reports/commands/exceptions.py:234 -msgid "Report schedule unexpected error" -msgstr "Nepričakovana napaka urnika poročanja" +#: superset-frontend/src/components/Chart/chartReducer.ts:82 +msgid "Updating chart was stopped" +msgstr "Posodabljanje grafikona je bilo ustavljeno" + +#: superset-frontend/src/components/Chart/chartReducer.ts:94 +#, python-format +msgid "An error occurred while rendering the visualization: %s" +msgstr "Pri prikazovanju vizualizacije je prišlo do napake: %s" -#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:74 -msgid "Report sending" -msgstr "Pošiljanje poročila" +#: superset-frontend/src/components/Chart/chartReducer.ts:106 +#: superset-frontend/src/components/Chart/chartReducer.ts:170 +msgid "Network error." +msgstr "Napaka omrežja." -#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:67 -msgid "Report sent" -msgstr "Poročilo poslano" +#: superset-frontend/src/components/CopyToClipboard/index.jsx:44 +#: superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx:73 +msgid "Copy to clipboard" +msgstr "Kopiraj na odložišče" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:443 -msgid "Reports" -msgstr "Poročila" +#: superset-frontend/src/components/CopyToClipboard/index.jsx:77 +#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:68 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:172 +msgid "Copied to clipboard!" +msgstr "Kopirano na odložišče!" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:283 -msgid "Repulsion" -msgstr "Odbijanje" +#: superset-frontend/src/components/CopyToClipboard/index.jsx:81 +msgid "Sorry, your browser does not support copying. Use Ctrl / Cmd + C!" +msgstr "Vaš brskalnik ne podpira kopiranja. Uporabite Ctrl / Cmd + C!" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:289 -msgid "Repulsion strength between nodes" -msgstr "Odbojna sila med vozlišči" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:27 +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:35 +msgid "every" +msgstr "vsak" -#: superset/templates/superset/request_access.html:31 -msgid "Request Permissions" -msgstr "Zahtevaj dovoljenja" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:28 +msgid "every month" +msgstr "vsak mesec" -#: superset/charts/data/api.py:145 superset/charts/data/api.py:233 -#: superset/charts/data/api.py:297 -#, python-format -msgid "Request is incorrect: %(error)s" -msgstr "Zahtevek je napačen: %(error)s" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:29 +msgid "every day of the month" +msgstr "vsak dan v mesecu" -#: superset/charts/data/api.py:222 -msgid "Request is not JSON" -msgstr "Zahtevek ni JSON" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:30 +msgid "day of the month" +msgstr "dan v mesecu" -#: superset/views/datasource/views.py:71 -msgid "Request missing data field." -msgstr "Zahtevaj manjkajoča podatkovna polja." +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:31 +msgid "every day of the week" +msgstr "vsak dan v tednu" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:93 -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:97 -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:104 -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:252 -#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:73 -#: superset-frontend/src/filters/components/Range/controlPanel.ts:55 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:91 -#: superset-frontend/src/filters/components/Time/controlPanel.ts:53 -#: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:33 -#: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:33 -msgid "Required" -msgstr "Obvezno" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:32 +msgid "day of the week" +msgstr "dan v tednu" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:137 -msgid "Resample" -msgstr "Prevzorči" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:33 +msgid "every hour" +msgstr "vsako uro" -#: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:231 -msgid "Reset state" -msgstr "Ponastavi stanje" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:34 +msgid "every minute" +msgstr "vsako minuto" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/RemovedFilter.tsx:46 -msgid "Restore Filter" -msgstr "Povrni filter" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:36 +msgid "year" +msgstr "leto" -#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:194 -msgid "Results" -msgstr "Rezultati" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:37 +msgid "month" +msgstr "mesec" -#: superset/sql_lab.py:375 superset/views/core.py:2251 -msgid "Results backend is not configured." -msgstr "Zaledni sistem rezultatov ni konfiguriran." +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:38 +msgid "week" +msgstr "teden" -#: superset/errors.py:116 -msgid "Results backend needed for asynchronous queries is not configured." -msgstr "" -"Zaledni sistem za rezultate, potreben za asinhrone poizvedbe, ni " -"konfiguriran." +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:39 +msgid "day" +msgstr "dan" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:29 -msgid "Return to specific datetime." -msgstr "Vrne določen datum-čas." +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:40 +msgid "hour" +msgstr "ura" -#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:155 -msgid "Reverse lat/long " -msgstr "Zamenjaj zemljepisno dolžino/širino " +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:41 +msgid "minute" +msgstr "minuta" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:230 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:100 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:281 -msgid "Rich Tooltip" -msgstr "Podroben opis orodja" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:42 +msgid "reboot" +msgstr "ponovni zagon" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:149 -msgid "Rich tooltip" -msgstr "Podroben opis orodja" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:43 +msgid "Every" +msgstr "Vsak" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:113 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:307 -msgid "Right" -msgstr "Desno" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:44 +msgid "in" +msgstr "v" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:53 -msgid "Right Axis Format" -msgstr "Oblika desne osi" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:45 +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:46 +msgid "on" +msgstr "v" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:119 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:183 -msgid "Right Axis Metric" -msgstr "Mera desne osi" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:47 +msgid "and" +msgstr "in" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:132 -msgid "Right Axis chart(s)" -msgstr "Grafikoni desne osi" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:48 +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:50 +msgid "at" +msgstr "ob" -#: superset-frontend/src/explore/controls.jsx:215 -msgid "Right axis metric" -msgstr "Mera desne osi" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:49 +msgid ":" +msgstr ":" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:138 -msgid "Right to Left" -msgstr "Iz desne proti levi" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:51 +msgid "minute(s)" +msgstr "minuta/e" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:160 -msgid "Right value" -msgstr "Desna vrednost" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:52 +msgid "Invalid cron expression" +msgstr "Neveljaven cron izraz" -#: superset/dashboards/filters.py:153 -msgid "Role" -msgstr "Vloga" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:53 +msgid "Clear" +msgstr "Počisti" -#: superset/views/core.py:389 -#, python-format -msgid "Role %(r)s was extended to provide the access to the datasource %(ds)s" -msgstr "" -"Vloga %(r)s je bila razširjena za zagotovitev dostopa do podatkovnega " -"vira %(ds)s" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:56 +msgid "Sunday" +msgstr "Nedelja" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:421 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:424 -#: superset-frontend/src/profile/components/Security.tsx:35 -#: superset/connectors/sqla/views.py:368 superset/views/dashboard/mixin.py:83 -msgid "Roles" -msgstr "Vloge" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:57 +msgid "Monday" +msgstr "Ponedeljek" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:433 -msgid "" -"Roles is a list which defines access to the dashboard. Granting a role " -"access to a dashboard will bypass dataset level checks. If no roles " -"defined then the dashboard is available to all roles." -msgstr "" -"\"Vloge\" je seznam, ki definira dostop do nadzorne plošče. Dodelitev " -"vloge za dostop do nadzorne plošče bo obšlo preverjanje na nivoju " -"podatkovnega seta. Če vloga ni definirana, bo nadzorna plošča dostopna " -"vsem vlogam." +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:58 +msgid "Tuesday" +msgstr "Torek" -#: superset/views/dashboard/mixin.py:66 -msgid "" -"Roles is a list which defines access to the dashboard. Granting a role " -"access to a dashboard will bypass dataset level checks.If no roles " -"defined then the dashboard is available to all roles." -msgstr "" -"\"Vloge\" je seznam, ki definira dostop do nadzorne plošče. Dodelitev " -"vloge za dostop do nadzorne plošče bo obšlo preverjanje na nivoju " -"podatkovnega seta. Če vloga ni definirana, bo nadzorna plošča dostopna " -"vsem vlogam." +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:59 +msgid "Wednesday" +msgstr "Sreda" -#: superset/views/access_requests.py:45 -msgid "Roles to grant" -msgstr "Vloge za dovoljevanje" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:60 +msgid "Thursday" +msgstr "Četrtek" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:257 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:140 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:158 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:389 -msgid "Rolling Function" -msgstr "Drseča funkcija" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:61 +msgid "Friday" +msgstr "Petek" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:251 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:134 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:152 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:383 -msgid "Rolling Window" -msgstr "Drseče okno" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:62 +msgid "Saturday" +msgstr "Sobota" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:39 -#: superset-frontend/src/explore/controlPanels/sections.tsx:158 -msgid "Rolling function" -msgstr "Drseča funkcija" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:66 +msgid "January" +msgstr "Januar" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:33 -#: superset-frontend/src/explore/controlPanels/sections.tsx:152 -msgid "Rolling window" -msgstr "Drseče okno" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:67 +msgid "February" +msgstr "Februar" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:351 -#: superset/views/database/mixins.py:198 -msgid "Root certificate" -msgstr "Korenski certifikat" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:68 +msgid "March" +msgstr "Marec" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:84 -msgid "Root node id" -msgstr "Id korenskega vozlišča" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:69 +msgid "April" +msgstr "April" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:307 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:209 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:170 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:151 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:167 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:225 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:228 -msgid "Rotate x axis label" -msgstr "Zavrti oznako x-osi" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:70 +msgid "May" +msgstr "Maj" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:89 -msgid "Rotation to apply to words in the cloud" -msgstr "Če želite vrtenje besed v oblaku" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:71 +msgid "June" +msgstr "Junij" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:271 -msgid "Round cap" -msgstr "Zaobljeni konci" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:72 +msgid "July" +msgstr "Julij" -#: superset-frontend/src/dashboard/components/gridComponents/new/NewRow.jsx:31 -msgid "Row" -msgstr "Vrstica" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:73 +msgid "August" +msgstr "Avgust" + +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:74 +msgid "September" +msgstr "September" -#: superset/initialization/__init__.py:274 -msgid "Row Level Security" -msgstr "Varnost na nivoju vrstic" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:75 +msgid "October" +msgstr "Oktober" -#: superset/views/database/forms.py:153 superset/views/database/forms.py:306 -msgid "" -"Row containing the headers to use as column names (0 is first line of " -"data). Leave empty if there is no header row." -msgstr "" -"Vrstica z naslovi, ki se uporabi za imena stolpcev (0 je prva vrstica " -"podatkov). Pustite prazno, če ni naslovne vrstice." +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:76 +msgid "November" +msgstr "November" -#: superset/connectors/sqla/views.py:314 -msgid "Row level security filter" -msgstr "Filter za varnost na nivoju vrstic" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:77 +msgid "December" +msgstr "December" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:331 -#: superset-frontend/src/explore/controls.jsx:360 -msgid "Row limit" -msgstr "Omejitev št. vrstic" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:81 +msgid "SUN" +msgstr "NED" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:49 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:83 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:289 -msgid "Rows" -msgstr "Vrstice" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:82 +msgid "MON" +msgstr "PON" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:314 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:391 -msgid "Rows per page, 0 means no pagination" -msgstr "Vrstic na stran (0 pomeni brez številčenja strani)" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:83 +msgid "TUE" +msgstr "TOR" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:285 -msgid "Rows subtotal position" -msgstr "Položaj vsot vrstic" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:84 +msgid "WED" +msgstr "SRE" -#: superset/views/database/forms.py:193 superset/views/database/forms.py:334 -msgid "Rows to Read" -msgstr "Vrstice za branje" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:85 +msgid "THU" +msgstr "ČET" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:144 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:360 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:243 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:493 -#: superset-frontend/src/explore/controlPanels/sections.tsx:257 -msgid "Rule" -msgstr "Pravilo" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:86 +msgid "FRI" +msgstr "PET" -#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:56 -#: superset-frontend/src/explore/components/QueryAndSaveBtns.jsx:76 -msgid "Run" -msgstr "Zaženi" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:87 +msgid "SAT" +msgstr "SOB" -#: superset-frontend/src/SqlLab/components/SouthPane/index.tsx:157 -msgid "Run a query to display results here" -msgstr "Za prikaz rezultatov morate zagnati poizvedbo" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:91 +msgid "JAN" +msgstr "JAN" -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:101 -msgid "Run in SQL Lab" -msgstr "Zaženi v SQL laboratoriju" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:92 +msgid "FEB" +msgstr "FEB" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:307 -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:317 -#: superset-frontend/src/chart/Chart.jsx:280 -msgid "Run query" -msgstr "Zaženi poizvedbo" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:93 +msgid "MAR" +msgstr "MAR" -#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:116 -msgid "Run query (Ctrl + Return)" -msgstr "Zaženi poizvedbo (Ctrl + Return)" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:94 +msgid "APR" +msgstr "APR" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:273 -msgid "Run query in a new tab" -msgstr "Zaženi poizvedbo v novem zavihku" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:95 +msgid "MAY" +msgstr "MAJ" -#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:54 -msgid "Run selection" -msgstr "Zaženi izbrano" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:96 +msgid "JUN" +msgstr "JUN" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:81 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:158 -msgid "Running" -msgstr "V teku" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:97 +msgid "JUL" +msgstr "JUL" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:87 -msgid "SAT" -msgstr "SOB" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:98 +msgid "AUG" +msgstr "AVG" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:99 msgid "SEP" msgstr "SEP" -#: superset-frontend/src/SqlLab/components/HighlightedSql/index.tsx:101 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:897 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:294 -msgid "SQL" -msgstr "SQL" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:100 +msgid "OCT" +msgstr "OKT" -#: superset-frontend/src/views/CRUD/data/components/SyntaxHighlighterCopy/index.tsx:71 -msgid "SQL Copied!" -msgstr "SQL kopiran!" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:101 +msgid "NOV" +msgstr "NOV" -#: superset/initialization/__init__.py:326 -msgid "SQL Editor" -msgstr "SQL urejevalnik" +#: superset-frontend/src/components/CronPicker/CronPicker.tsx:102 +msgid "DEC" +msgstr "DEC" -#: superset/connectors/sqla/views.py:259 -msgid "SQL Expression" -msgstr "SQL izraz" +#: superset-frontend/src/components/DatabaseSelector/index.tsx:238 +msgid "There was an error loading the schemas" +msgstr "Napaka pri nalaganju shem" -#: superset/initialization/__init__.py:331 -#: superset/initialization/__init__.py:346 -msgid "SQL Lab" -msgstr "SQL laboratorij" +#: superset-frontend/src/components/DatabaseSelector/index.tsx:276 +#: superset-frontend/src/components/DatabaseSelector/index.tsx:284 +msgid "Select database or type database name" +msgstr "Izberite ali vnesite ime podatkovne baze" -#: superset/connectors/sqla/views.py:503 -msgid "SQL Lab View" -msgstr "Pogled SQL laboratorija" +#: superset-frontend/src/components/DatabaseSelector/index.tsx:296 +msgid "Force refresh schema list" +msgstr "Osveži seznam shem" -#: superset-frontend/src/SqlLab/components/App/index.jsx:91 -#, python-format +#: superset-frontend/src/components/DatabaseSelector/index.tsx:301 +#: superset-frontend/src/components/DatabaseSelector/index.tsx:308 +msgid "Select schema or type schema name" +msgstr "Izberite ali vnesite ime sheme" + +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:47 msgid "" -"SQL Lab uses your browser's local storage to store queries and results.\n" -"Currently, you are using %(currentUsage)s KB out of %(maxStorage)d KB " -"storage space.\n" -"To keep SQL Lab from crashing, please delete some query tabs.\n" -"You can re-access these queries by using the Save feature before you " -"delete the tab.\n" -"Note that you will need to close other SQL Lab windows before you do this." +"Warning! Changing the dataset may break the chart if the metadata does not exist." msgstr "" +"Opozorilo! Sprememba podatkovnega seta lahko pokvari grafikon, če metapodatki ne " +"obstajajo." -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1150 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:287 -#: superset/templates/appbuilder/navbar_right.html:38 -msgid "SQL Query" -msgstr "SQL poizvedba" +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:51 +msgid "" +"Changing the dataset may break the chart if the chart relies on columns or " +"metadata that does not exist in the target dataset" +msgstr "" +"Sprememba podatkovnega seta lahko pokvari grafikon, če se le-ta zanaša na stolpce " +"ali metapodatke, ki ne obstajajo v ciljnem podatkovnem nizu" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:181 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1038 -msgid "SQL expression" -msgstr "SQL izraz" +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:117 +#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:64 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:144 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:746 +msgid "dataset" +msgstr "podatkovni set" -#: superset-frontend/src/components/Menu/MenuRight.tsx:32 -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:124 -msgid "SQL query" -msgstr "SQL poizvedba" +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:225 +msgid "Connection" +msgstr "Povezava" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:61 -#: superset/views/database/mixins.py:194 -msgid "SQLAlchemy URI" -msgstr "SQLAlchemy URI" +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:254 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:267 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:369 +msgid "Change dataset" +msgstr "Spremeni podatkovni set" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:202 -msgid "SSL Mode \"require\" will be used." -msgstr "Uporabljen bo SSL način \"require\"." +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:286 +msgid "Warning!" +msgstr "Opozorilo!" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:64 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:115 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:122 -msgid "START (INCLUSIVE)" -msgstr "ZAČETEK (VKLJUČEN)" +#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:294 +msgid "Search / Filter" +msgstr "Iskanje / Filter" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:81 -msgid "SUN" -msgstr "NED" +#: superset-frontend/src/components/Datasource/CollectionTable.tsx:442 +msgid "Add item" +msgstr "Dodaj" -#: superset/viz.py:1903 -msgid "Sankey" -msgstr "Sankey" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:144 +msgid "Physical (table or view)" +msgstr "Fizičen (tabela ali pogled)" -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:36 -msgid "Sankey Diagram" -msgstr "Sankey grafikon" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:145 +msgid "Virtual (SQL)" +msgstr "Virtualen (SQL)" -#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/index.js:27 -msgid "Sankey Diagram with Loops" -msgstr "Sankey grafikon z zankami" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:265 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:268 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:353 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:361 +msgid "Data type" +msgstr "Tip podatka" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:62 -msgid "Saturday" -msgstr "Sobota" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:280 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:352 +msgid "Advanced data type" +msgstr "Napredni podatkovni tip" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:160 -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:166 -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:181 -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:227 -#: superset-frontend/src/components/ReportModal/index.tsx:267 -#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:88 -#: superset-frontend/src/dashboard/components/Header/index.jsx:588 -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:458 -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:148 -#: superset-frontend/src/dashboard/components/SaveModal.tsx:224 -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:531 -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:157 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:71 -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:205 -#: superset-frontend/src/explore/components/QueryAndSaveBtns.jsx:112 -#: superset-frontend/src/explore/components/SaveModal.tsx:202 -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:318 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:260 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:488 -#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:345 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1039 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:273 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:226 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:220 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1006 -msgid "Save" -msgstr "Shrani" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:284 +msgid "Advanced Data type" +msgstr "Napredni podatkovni tip" -#: superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx:108 -msgid "Save & Explore" -msgstr "Shrani & Razišči" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:293 +msgid "Datetime format" +msgstr "Oblika datum-časa" -#: superset-frontend/src/explore/components/SaveModal.tsx:190 -msgid "Save & go to dashboard" -msgstr "Shrani in pojdi na nadzorno ploščo" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:297 +msgid "The pattern of timestamp format. For strings use " +msgstr "Vzorec zapisa časovne značke. Za znakovne nize uporabite " -#: superset-frontend/src/explore/components/SaveModal.tsx:234 -msgid "Save (Overwrite)" -msgstr "Shrani (prepiši)" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:299 +msgid "Python datetime string pattern" +msgstr "Pythonov vzorec zapisa datum-časa" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:160 -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:166 -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:254 -msgid "Save as" -msgstr "Shrani kot" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:301 +msgid " expression which needs to adhere to the " +msgstr " , ki mora upoštevati " -#: superset-frontend/src/explore/components/SaveModal.tsx:243 -msgid "Save as ..." -msgstr "Shrani kot ..." +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:303 +msgid "ISO 8601" +msgstr "ISO 8601" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:181 -msgid "Save as new" -msgstr "Shrani kot novo" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:305 +msgid "" +" standard to ensure that the lexicographical ordering\n" +" coincides with the chronological ordering. If the\n" +" timestamp format does not adhere to the ISO 8601 standard\n" +" you will need to define an expression and type for\n" +" transforming the string into a date or timestamp. Note\n" +" currently time zones are not supported. If time is stored\n" +" in epoch format, put `epoch_s` or `epoch_ms`. If no " +"pattern\n" +" is specified we fall back to using the optional defaults on " +"a per\n" +" database/column name level via the extra parameter." +msgstr "" +" standard, ki zagotavlja, de se leksikografsko razvrščanje\n" +" sklada s kronološkim razvrščanjem. Če oblika\n" +" časovne značke ni v skladu s standardom ISO 8601,\n" +" boste morali definirati izraz in tip za transformacijo\n" +" znakovnega niza v datum ali časovno značko.\n" +" Trenutno časovni pasovi niso podprti.\n" +" Če je čas shranjen v obliki epohe, dodajte `epoch_s` ali " +"`epoch_ms`.\n" +" Če ni podan vzorec, se uporabijo privzete vrednosti na " +"podlagi imena\n" +" podatkovne baze oz. stolpca s pomočjo dodatnega parametra." + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:325 +msgid "Certified By" +msgstr "Certificiral/a" -#: superset-frontend/src/explore/components/SaveModal.tsx:201 -msgid "Save as new chart" -msgstr "Shrani kot nov grafikon" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:326 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1223 +msgid "Person or group that has certified this metric" +msgstr "Oseba ali skupina, ki je certificirala to mero" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:199 -msgid "Save as:" -msgstr "Shrani kot:" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:330 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1221 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1229 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:577 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:266 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:267 +msgid "Certified by" +msgstr "Certificiral/a" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:336 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:341 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1234 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1240 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:586 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:275 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:278 +msgid "Certification details" +msgstr "Podrobnosti certifikacije" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:337 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1236 +msgid "Details of the certification" +msgstr "Podrobnosti certifikacije" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:354 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:362 +msgid "Is dimension" +msgstr "Dimenzija" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:356 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:364 +msgid "Default datetime" +msgstr "Privzet datumčas" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:357 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:365 +msgid "Is filterable" +msgstr "Filtriranje" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:552 +msgid "Select owners" +msgstr "Izberite lastnike" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:764 +#, python-format +msgid "Modified columns: %s" +msgstr "Spremenjeni stolpci: %s" + +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:769 +#, python-format +msgid "Removed columns: %s" +msgstr "Odstranjeni stolpci: %s" -#: superset-frontend/src/explore/components/SaveModal.tsx:171 -msgid "Save chart" -msgstr "Shrani grafikon" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:774 +#, python-format +msgid "New columns added: %s" +msgstr "Dodani novi stolpci: %s" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:182 -msgid "Save dashboard" -msgstr "Shrani nadzorno ploščo" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:777 +msgid "Metadata has been synced" +msgstr "Metapodatki so sinhronizirani" -#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:148 -msgid "Save for this session" -msgstr "Shranite za to sejo" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:783 +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:137 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:104 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:115 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx:46 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:67 +msgid "An error has occurred" +msgstr "Prišlo je do napake" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:169 -msgid "Save query" -msgstr "Shrani poizvedbo" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:812 +#, python-format +msgid "Column name [%s] is duplicated" +msgstr "Ime stolpca [%s] je podvojeno" -#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:89 -msgid "Save the query to enable this feature" -msgstr "Za omogočenje te funkcije shranite poizvedbo" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:818 +#, python-format +msgid "Metric name [%s] is duplicated" +msgstr "Ime mere [%s] je podvojeno" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:241 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:368 -msgid "Saved" -msgstr "Shranjeno" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:827 +#, python-format +msgid "Calculated column [%s] requires an expression" +msgstr "Izračunan stolpec [%s] zahteva izraz" -#: superset/initialization/__init__.py:334 -msgid "Saved Queries" -msgstr "Shranjene poizvedbe" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:846 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1263 +msgid "Basic" +msgstr "Osnovno" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:226 -msgid "Saved expressions" -msgstr "Shranjeni izrazi" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:859 +msgid "Default URL" +msgstr "Privzeti URL" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:369 -msgid "Saved metric" -msgstr "Shranjena mera" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:860 +msgid "Default URL to redirect to when accessing from the dataset list page" +msgstr "" +"Privzeti URL za preusmeritev, ko dostopate iz strani s seznamom podatkovnih setov" -#: superset-frontend/src/views/CRUD/data/common.ts:38 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:108 -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:318 -msgid "Saved queries" -msgstr "Shranjene poizvedbe" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:868 +msgid "Autocomplete filters" +msgstr "Samodokončaj filtre" -#: superset/queries/saved_queries/commands/exceptions.py:28 -msgid "Saved queries could not be deleted." -msgstr "Shranjenih poizvedb ni mogoče izbrisati." +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:869 +msgid "Whether to populate autocomplete filters options" +msgstr "Če želite napolniti možnosti za samodokončanje filtrov" -#: superset/queries/saved_queries/commands/exceptions.py:32 -msgid "Saved query not found." -msgstr "Shranjena poizvedba ni najdena." +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:875 +msgid "Autocomplete query predicate" +msgstr "Predikat za samodokončanje poizvedb" -#: superset/queries/saved_queries/commands/exceptions.py:40 -msgid "Saved query parameters are invalid." -msgstr "Parametri shranjene poizvedbe so neveljavni." +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:876 +msgid "" +"When using \"Autocomplete filters\", this can be used to improve performance of " +"the query fetching the values. Use this option to apply a predicate (WHERE " +"clause) to the query selecting the distinct values from the table. Typically the " +"intent would be to limit the scan by applying a relative time filter on a " +"partitioned or indexed time-related field." +msgstr "" +"Ko uporabljate \"Samodokončaj filtre\", lahko s tem izboljšate hitrost " +"pridobivanja rezultatov s poizvedbo. Z uporabo te možnosti dodate predikat (WHERE " +"stavek) k poizvedbi za izbiro različnih vrednosti iz tabele. Običajno je namen " +"omejiti poizvedbo z uporabo filtra za relativni čas na particioniranem ali " +"indeksiranem časovnem polju." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:168 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:277 -msgid "Scale and Move" -msgstr "Povečava in premikanje" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:896 +msgid "" +"Extra data to specify table metadata. Currently supports metadata of the format: " +"`{ \"certification\": { \"certified_by\": \"Data Platform Team\", \"details\": " +"\"This table is the source of truth.\" }, \"warning_markdown\": \"This is a " +"warning.\" }`." +msgstr "" +"Dodatni podatki za tabelo metapodatkov. Trenutno je podprta naslednja oblika " +"zapisa metapodatkov: `{ \"certification\": { \"certified_by\": \"Tim za razvoj\", " +"\"details\": \"Ta tabela je vir resnice.\" }, \"warning_markdown\": \"To je " +"opozorilo.\" }`." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:166 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:275 -msgid "Scale only" -msgstr "Samo povečava" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:931 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:290 +msgid "Cache timeout" +msgstr "Časovna omejitev predpomnilnika" -#: superset/initialization/__init__.py:529 -msgid "Scan New Datasources" -msgstr "Preišči nove podatkovne vire" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:932 +msgid "The duration of time in seconds before the cache is invalidated" +msgstr "Trajanje (v sekundah) do razveljavitve predpomnilnika" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:39 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:43 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:36 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:77 -msgid "Scatter" -msgstr "Raztreseni" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:939 +msgid "Hours offset" +msgstr "Urni premik" -#: superset-frontend/plugins/preset-chart-xy/src/ScatterPlot/createMetadata.ts:26 -msgid "Scatter Plot" -msgstr "Raztreseni grafikon" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:941 +msgid "" +"The number of hours, negative or positive, to shift the time column. This can be " +"used to move UTC time to local time." +msgstr "" +"Število ur, negativno ali pozitivno, za zamik časovnega stolpca. Na ta način je " +"mogoče UTC čas prestaviti na lokalni čas." -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:221 -#: superset-frontend/src/components/ReportModal/index.tsx:357 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:237 -msgid "Schedule" -msgstr "Urnik" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:964 +msgid "Spatial" +msgstr "Prostorski" -#: superset/views/schedules.py:274 -msgid "Schedule Email Reports for Charts" -msgstr "Razporedi e-poštna poročila za grafikone" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1004 +msgid "Click the lock to make changes." +msgstr "Kliknite ključavnico, da omogočite spreminjanje." -#: superset/views/schedules.py:196 -msgid "Schedule Email Reports for Dashboards" -msgstr "Razporedi e-poštna poročila za nadzorne plošče" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1007 +msgid "Click the lock to prevent further changes." +msgstr "Kliknite ključavnico, da onemogočite spreminjanje." -#: superset-frontend/src/dashboard/components/Header/index.jsx:423 -#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:218 -msgid "Schedule email report" -msgstr "Dodaj e-poštno poročilo na urnik" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1034 +msgid "virtual" +msgstr "virtualni" -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:211 -msgid "Schedule query" -msgstr "Urnik poizvedb" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1058 +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1065 +msgid "Dataset name" +msgstr "Ime podatkovnega seta" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1234 -msgid "Schedule settings" -msgstr "Nastavitve urnika" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1075 +msgid "" +"When specifying SQL, the datasource acts as a view. Superset will use this " +"statement as a subquery while grouping and filtering on the generated parent " +"queries." +msgstr "" +"Ko podajate SQL, se podatkovni vir obnaša kot pogled (view). Superset bo ta zapis " +"uporabil kot podpoizvedbo, pri čemer bo združeval in filtriral na podlagi " +"ustvarjenih starševskih poizvedb." -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:517 -msgid "Schedule the query periodically" -msgstr "Periodično zaganjaj poizvedbo" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1098 +msgid "The JSON metric or post aggregation definition." +msgstr "JSON mera ali po-agregacijska definicija." -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:99 -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:105 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:168 -msgid "Scheduled" -msgstr "V urniku" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1113 +msgid "Physical" +msgstr "Fizičen" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:117 -msgid "Scheduled at (UTC)" -msgstr "Izvede se ob (UTC)" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1154 +msgid "" +"The pointer to a physical table (or view). Keep in mind that the chart is " +"associated to this Superset logical table, and this logical table points the " +"physical table referenced here." +msgstr "" +"Kazalec na fizično tabelo (ali pogled). Grafikon je povezan s to Supersetovo " +"logično tabelo, ki kaže na tukaj referencirano fizično tabelo." -#: superset-frontend/src/components/ReportModal/index.tsx:359 -msgid "Scheduled reports will be sent to your email as a PNG" -msgstr "Poročila na urniku bodo poslana na vaš e-naslov kot PNG" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1245 +msgid "Warning" +msgstr "Opozorilo" -#: superset-frontend/src/components/DatabaseSelector/index.tsx:295 -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:220 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:299 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:451 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:232 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:287 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:444 -#: superset/connectors/sqla/views.py:494 superset/views/database/forms.py:126 -#: superset/views/database/forms.py:285 superset/views/database/forms.py:413 -msgid "Schema" -msgstr "Shema" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1247 +msgid "Optional warning about use of this metric" +msgstr "Opcijsko opozorilo za uporabo te mere" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:235 -msgid "Schema cache timeout" -msgstr "Trajanje prepomnilnika sheme" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1332 +msgid "Be careful." +msgstr "Bodite previdni." -#: superset/connectors/sqla/views.py:440 -msgid "Schema, as used only in some databases like Postgres, Redshift and DB2" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1333 +msgid "" +"Changing these settings will affect all charts using this dataset, including " +"charts owned by other people." msgstr "" -"Shema, ki se uporablja pri nekaterih podatkovnih bazah, kot so Postgres, " -"Redshift in DB2" - -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:369 -msgid "Schemas allowed for CSV upload" -msgstr "Dovoljene sheme za nalaganje CSV" +"Spreminjanje teh nastavitev bo vplivalo na vse grafikone, ki uporabljajo ta " +"podatkovni set, vključno z grafikoni v lasti drugih oseb." -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:256 -msgid "Scoping" -msgstr "Doseg" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1380 +msgid "Sync columns from source" +msgstr "Sinhroniziraj stolpce z virom" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 -#: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:542 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:292 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:516 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:417 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:477 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:461 -#: superset/templates/appbuilder/general/widgets/search.html:40 -msgid "Search" -msgstr "Iskanje" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1400 +msgid "Calculated columns" +msgstr "Izračunani stolpci" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:293 -msgid "Search / Filter" -msgstr "Iskanje / Filter" +#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1427 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:264 +#: superset-frontend/src/views/components/MenuRight.tsx:332 +msgid "Settings" +msgstr "Nastavitve" -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:291 -msgid "Search Metrics & Columns" -msgstr "Iskanje mer in stolpcev" +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:125 +#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:112 +msgid "The dataset has been saved" +msgstr "Podatkovni set je shranjen" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:703 -msgid "Search all charts" -msgstr "Išči vse grafikone" +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:164 +msgid "" +"The dataset configuration exposed here\n" +" affects all the charts using this dataset.\n" +" Be mindful that changing settings\n" +" here may affect other charts\n" +" in undesirable ways." +msgstr "" +"Tukaj prikazane nastavitve podatkovnega seta\n" +" vplivajo na vse grafikone, ki uporabljajo\n" +" ta podatkovni set. Spreminjanje\n" +" nastavitev lahko nezaželeno vpliva\n" +" na druge grafikone." -#: superset-frontend/src/components/OmniContainer/index.tsx:102 -msgid "Search all dashboards" -msgstr "Išči vse nadzorne plošče" +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:170 +msgid "Are you sure you want to save and apply changes?" +msgstr "Ali resnično želite shraniti in uporabiti spremembe?" -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:232 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:137 -msgid "Search all filter options" -msgstr "Poišči vse možnosti filtra" +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:176 +msgid "Confirm save" +msgstr "Potrdite shranjevanje" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:403 -msgid "Search box" -msgstr "Iskalno polje" +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:193 +msgid "Edit Dataset " +msgstr "Uredi podatkovni set " -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:388 -msgid "Search by query text" -msgstr "Išči z besedilom poizvedbe" +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:211 +msgid "Use legacy datasource editor" +msgstr "Uporabi starejši urejevalnik podatkovnega vira" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:452 -msgid "Search..." -msgstr "Iskanje ..." +#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:234 +msgid "This dataset is managed externally, and can't be edited in Superset" +msgstr "Ta podatkovni set se ne ureja znotraj Superseta" -#: superset/db_engine_specs/base.py:86 -msgid "Second" -msgstr "Sekunda" +#: superset-frontend/src/components/DeleteModal/index.tsx:69 +msgid "DELETE" +msgstr "IZBRIŠI" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:244 -msgid "Secondary" -msgstr "Sekundarna" +#: superset-frontend/src/components/DeleteModal/index.tsx:84 +msgid "delete" +msgstr "izbriši" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:62 -msgid "Secondary Metric" -msgstr "Sekundarna mera" +#: superset-frontend/src/components/DeleteModal/index.tsx:92 +#: superset-frontend/src/components/ImportModal/index.tsx:252 +#, python-format +msgid "Type \"%s\" to confirm" +msgstr "Vnesite \"%s\" za potrditev" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:392 -msgid "Secondary y-axis format" -msgstr "Oblika sekundarne y-osi" +#: superset-frontend/src/components/EditableTitle/index.tsx:210 +msgid "Click to edit" +msgstr "Kliknite za urejanje" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:401 -msgid "Secondary y-axis title" -msgstr "Naslov sekundarne y-osi" +#: superset-frontend/src/components/EditableTitle/index.tsx:212 +msgid "You don't have the rights to alter this title." +msgstr "Nimate pravic za spreminjanje tega naslova." -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:63 -#, fuzzy, python-format -msgid "Seconds %s" -msgstr "sekunda" +#: superset-frontend/src/components/ErrorBoundary/index.jsx:51 +#: superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx:26 +msgid "Unexpected error" +msgstr "Nepričakovana napaka" -#: superset/views/database/mixins.py:197 -msgid "Secure Extra" -msgstr "Dodatna varnost" +#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:47 +#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:62 +msgid "This may be triggered by:" +msgstr "To je lahko sproženo z/s:" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:326 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:331 -msgid "Secure extra" -msgstr "Dodatna varnost" +#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:59 +#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:72 +msgid "Please reach out to the Chart Owner for assistance." +msgstr "Za pomoč se obrnite na lastnika grafikona." -#: superset/initialization/__init__.py:276 -#: superset/initialization/__init__.py:421 -#: superset/initialization/__init__.py:493 -msgid "Security" -msgstr "Varnost" +#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:70 +#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:83 +#, python-format +msgid "Chart Owner: %s" +msgstr "Lastnik grafikona: %s" -#: superset-frontend/src/profile/components/App.tsx:82 -msgid "Security & Access" -msgstr "Varnost in Dostopi" +#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:84 +#, python-format +msgid "" +"%(message)s\n" +"This may be triggered by: \n" +"%(issues)s" +msgstr "" +"%(message)s\n" +"To je lahko sproženo z/s: \n" +"%(issues)s" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:157 -#, fuzzy, python-format -msgid "See all %(tableName)s" -msgstr "Razišči - %(table)s" +#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:90 +#, python-format +msgid "%s Error" +msgstr "%s napaka" -#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:155 -msgid "See less" -msgstr "Oglejte si manj" +#: superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.tsx:34 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:353 +msgid "Missing dataset" +msgstr "Manjka podatkovni set" #: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:126 #: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:142 msgid "See more" msgstr "Oglejte si več" -#: superset-frontend/src/components/TableSelector/index.tsx:291 -msgid "See table schema" -msgstr "Ogled sheme tabele" +#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:155 +msgid "See less" +msgstr "Oglejte si manj" -#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:132 -msgid "Select" -msgstr "Izberi" +#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:184 +msgid "Copy message" +msgstr "Kopiraj sporočilo" -#: superset-frontend/src/components/AsyncSelect/index.jsx:41 -#: superset-frontend/src/components/Select/Select.tsx:290 -#: superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx:106 -#: superset-frontend/src/explore/components/controls/SelectControl.jsx:227 -msgid "Select ..." -msgstr "Izberite ..." +#: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:192 +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:524 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:342 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:258 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:486 +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:337 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:882 +msgid "Close" +msgstr "Zapri" -#: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:127 -msgid "Select Delivery Method" -msgstr "Izberite način dostave" +#: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:61 +msgid "This was triggered by:" +msgstr "To je bilo sproženo z/s:" -#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:106 -msgid "Select Viz Type" -msgstr "Izberite tip vizualizacije" +#: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:77 +msgid "Did you mean:" +msgstr "Ste mislili:" -#: superset/views/database/forms.py:102 -msgid "Select a CSV file to be uploaded to a database." -msgstr "Izberite CSV datoteko, ki bo naložena v podatkovno bazo." +#: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:88 +#, python-format +msgid "%(suggestion)s instead of \"%(undefinedParameter)s?\"" +msgstr "%(suggestion)s namesto \"%(undefinedParameter)s?\"" -#: superset/views/database/forms.py:386 -msgid "Select a Columnar file to be uploaded to a database." -msgstr "Izberite stolpčno datoteko, ki bo naložena v podatkovno bazo." +#: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:116 +msgid "Parameter error" +msgstr "Napaka parametra" -#: superset/views/database/forms.py:253 -msgid "Select a Excel file to be uploaded to a database." -msgstr "Izberite Excel-ovo datoteko, ki bo naložena v podatkovno bazo." +#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:46 +#, python-format +msgid "" +"We’re having trouble loading this visualization. Queries are set to timeout after " +"%s second." +msgstr "" +"Težava pri nalaganju vizualizacije. Časovni iztek poizvedb je nastavljen na %s " +"sekund." -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:133 -msgid "Select a column" -msgstr "Izberite stolpec" +#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:52 +#, python-format +msgid "" +"We’re having trouble loading these results. Queries are set to timeout after %s " +"second." +msgstr "" +"Težava pri nalaganju rezultatov. Časovni iztek poizvedb je nastavljen na %s " +"sekund." -#: superset-frontend/src/explore/components/SaveModal.tsx:264 -msgid "Select a dashboard" -msgstr "Izberite nadzorno ploščo" +#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:93 +#, python-format +msgid "" +"%(subtitle)s\n" +"This may be triggered by:\n" +" %(issue)s" +msgstr "" +"%(subtitle)s\n" +"To je lahko sproženo z/s: \n" +" %(issue)s" -#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:131 -msgid "Select a visualization type" -msgstr "Izberite tip vizualizacije" +#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:98 +msgid "Timeout error" +msgstr "Napaka pretečenega časa" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:310 -msgid "Select aggregate options" -msgstr "Izberite agregacijske možnosti" +#: superset-frontend/src/components/FaveStar/index.tsx:79 +msgid "Click to favorite/unfavorite" +msgstr "Kliknite za priljubljeno/nepriljubljeno" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:107 -msgid "Select any columns for metadata inspection" -msgstr "Izberite poljubne stolpce za pregled metapodatkov" +#: superset-frontend/src/components/FilterableTable/index.tsx:465 +msgid "Cell content" +msgstr "Vsebina celice" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:103 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:138 -msgid "Select charts" -msgstr "Izberi grafikone" +#: superset-frontend/src/components/ImportModal/ErrorAlert.tsx:46 +msgid "" +"Database driver for importing maybe not installed. Visit the Superset " +"documentation page for installation instructions:" +msgstr "" +"Gonilnik podatkovne baze za uvoz ni nameščen. Za navodila pojdite na " +"dokumentacijo Superseta:" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:188 -msgid "Select color scheme" -msgstr "Izberite barvno shemo" +#: superset-frontend/src/components/ImportModal/index.tsx:209 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1019 +msgid "OVERWRITE" +msgstr "OVERWRITE" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:208 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:63 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:301 -msgid "Select column" -msgstr "Izberite stolpec" +#: superset-frontend/src/components/ImportModal/index.tsx:281 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:447 +msgid "Overwrite" +msgstr "Prepiši" -#: superset-frontend/src/components/DatabaseSelector/index.tsx:268 -#: superset-frontend/src/components/DatabaseSelector/index.tsx:275 -msgid "Select database or type database name" -msgstr "Izberite ali vnesite ime podatkovne baze" +#: superset-frontend/src/components/ImportModal/index.tsx:281 +msgid "Import" +msgstr "Uvozi" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1127 -msgid "" -"Select databases require additional fields to be completed in the " -"Advanced tab to successfully connect the database. Learn what " -"requirements your databases has " -msgstr "" +#: superset-frontend/src/components/ImportModal/index.tsx:285 +#, python-format +msgid "Import %s" +msgstr "Uvozi %s" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:294 -#: superset-frontend/src/filters/components/Select/index.ts:28 -msgid "Select filter" -msgstr "Izbirni filter" +#: superset-frontend/src/components/LastUpdated/index.tsx:74 +#, python-format +msgid "Last Updated %s" +msgstr "Zadnja posodobitev %s" -#: superset-frontend/src/filters/components/Select/index.ts:29 -msgid "Select filter plugin using AntD" -msgstr "Izberite Vtičnik za filter z uporabo AntD" +#: superset-frontend/src/components/ListView/CardSortSelect.tsx:82 +#: superset-frontend/src/components/ListView/CardSortSelect.tsx:83 +msgid "Sort" +msgstr "Razvrsti" -#: superset-frontend/src/filters/components/Select/controlPanel.ts:111 -msgid "" -"Select first item by default (when using this option, default value can’t" -" be set)" -msgstr "" -"Izberi prvi element kot privzet (ko uporabljate to možnost, privzete " -"vrednost ni mogoče nastaviti)" +#: superset-frontend/src/components/ListView/ListView.tsx:244 +#, python-format +msgid "%s Selected" +msgstr "Izbranih: %s" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:303 -msgid "Select operator" -msgstr "Izberite operator" +#: superset-frontend/src/components/ListView/ListView.tsx:358 +msgid "Deselect all" +msgstr "Počisti izbor" -#: superset-frontend/src/components/ListView/Filters/Select.tsx:84 -msgid "Select or type a value" -msgstr "Izberite ali vnesite vrednost" +#: superset-frontend/src/components/ListView/ListView.tsx:408 +msgid "No results match your filter criteria" +msgstr "Noben rezultat ne ustreza vašim kriterijem" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:393 -msgid "Select owners" -msgstr "Izberite lastnike" +#: superset-frontend/src/components/ListView/ListView.tsx:409 +msgid "Try different criteria to display results." +msgstr "Za prikaz rezultatov poskusite z drugačnimi kriteriji." -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadeFilters/CascadePopover/index.tsx:177 -msgid "Select parent filters" -msgstr "Izberi starševske filtre" +#: superset-frontend/src/components/ListView/ListView.tsx:412 +msgid "clear all filters" +msgstr "počisti vse filtre" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:319 -msgid "Select saved metrics" -msgstr "Izberite shranjene mere" +#: superset-frontend/src/components/ListView/ListView.tsx:417 +msgid "No Data" +msgstr "Ni podatkov" -#: superset-frontend/src/components/DatabaseSelector/index.tsx:293 -#: superset-frontend/src/components/DatabaseSelector/index.tsx:300 -msgid "Select schema or type schema name" -msgstr "Izberite ali vnesite ime sheme" +#: superset-frontend/src/components/ListView/ListView.tsx:438 +#: superset-frontend/src/components/TableView/TableView.tsx:240 +#, python-format +msgid "%s-%s of %s" +msgstr "%s-%s od %s" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:194 -#, fuzzy -msgid "Select scheme" -msgstr "Izberite barvno shemo" +#: superset-frontend/src/components/ListView/Filters/Search.tsx:75 +msgid "Type a value" +msgstr "Vnesite vrednost" -#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:273 -msgid "Select start and end date" -msgstr "Izberite začetni in končni datum" +#: superset-frontend/src/components/ListView/Filters/Select.tsx:91 +msgid "Filter" +msgstr "Filter" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:265 -msgid "Select subject" -msgstr "Izberite zadevo" +#: superset-frontend/src/components/ListView/Filters/Select.tsx:98 +msgid "Select or type a value" +msgstr "Izberite ali vnesite vrednost" -#: superset-frontend/src/components/TableSelector/index.tsx:298 -#: superset-frontend/src/components/TableSelector/index.tsx:308 -msgid "Select table or type table name" -msgstr "Izberite ali vnesite ime tabele" +#: superset-frontend/src/components/Modal/Modal.tsx:211 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:835 +msgid "OK" +msgstr "OK" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:98 -msgid "Select the number of bins for the histogram" -msgstr "Izberite število razdelkov za histogram" +#: superset-frontend/src/components/PageHeaderWithActions/index.tsx:154 +msgid "Menu actions trigger" +msgstr "Preklapljanje funkcionalnosti menijev" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:38 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:48 -msgid "Select the numeric columns to draw the histogram" -msgstr "Izberite numerične stolpce za izris histograma" +#: superset-frontend/src/components/ReportModal/index.tsx:119 +#, python-format +msgid "Weekly Report for %s" +msgstr "Tedensko poročilo za %s" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1340 -msgid "Send as CSV" -msgstr "Pošlji kot CSV" +#: superset-frontend/src/components/ReportModal/index.tsx:120 +msgid "Weekly Report" +msgstr "Tedensko poročilo" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1339 -msgid "Send as PNG" -msgstr "Pošlji kot PNG" +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:197 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:225 +#: superset-frontend/src/components/ReportModal/index.tsx:206 +msgid "Edit email report" +msgstr "Uredi e-poštno poročilo" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1342 -msgid "Send as text" -msgstr "Pošlji kot besedilo" +#: superset-frontend/src/components/ReportModal/index.tsx:206 +msgid "Schedule a new email report" +msgstr "Dodaj novo e-poštno poročilo na urnik" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:58 -msgid "Send range filter events to other charts" -msgstr "Pošlji dogodke filtra obdobja na druge grafikone" +#: superset-frontend/src/components/ReportModal/index.tsx:223 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1057 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:273 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:230 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:220 +#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:123 +msgid "Add" +msgstr "Dodaj" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:74 -msgid "September" -msgstr "September" +#: superset-frontend/src/components/ReportModal/index.tsx:231 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1315 +msgid "Message content" +msgstr "Vsebina sporočila" -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:58 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:49 -msgid "Sequential" -msgstr "Sekvenčni" +#: superset-frontend/src/components/ReportModal/index.tsx:242 +msgid "Text embedded in email" +msgstr "Besedilo vključeno v e-pošto" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:61 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:385 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:119 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:128 -#: superset-frontend/src/explore/controls.jsx:400 -msgid "Series" -msgstr "Niz" +#: superset-frontend/src/components/ReportModal/index.tsx:246 +msgid "Image (PNG) embedded in email" +msgstr "Slika (PNG) vključena v e-pošto" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:71 -msgid "Series Height" -msgstr "Višina serije" +#: superset-frontend/src/components/ReportModal/index.tsx:249 +msgid "Formatted CSV attached in email" +msgstr "Oblikovan CSV pripet e-pošti" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:112 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:113 -msgid "Series Style" -msgstr "Slog serije" +#: superset-frontend/src/components/ReportModal/index.tsx:289 +msgid "Include a description that will be sent with your report" +msgstr "Vključite opis, ki bo vključen v poročilo" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:147 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:122 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:125 -msgid "Series chart type (line, bar etc)" -msgstr "Tip grafikona za posamezno podatkovno serijo (črtni, stolpčni, ...)" +#: superset-frontend/src/components/ReportModal/index.tsx:303 +msgid "A screenshot of the dashboard will be sent to your email at" +msgstr "Zaslonska slika nadzorne plošče bo poslana na vaš e-naslov ob" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:341 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:356 -#: superset-frontend/src/explore/controls.jsx:370 -msgid "Series limit" -msgstr "Omejitev št. serij" +#: superset-frontend/src/components/ReportModal/index.tsx:320 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1245 +msgid "Timezone" +msgstr "Časovni pas" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:135 -msgid "Series type" -msgstr "Tip serije" +#: superset-frontend/src/components/ReportModal/index.tsx:336 +msgid "Failed to update report" +msgstr "Posodabljanje poročila neuspešno" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:311 -msgid "Server Page Length" -msgstr "Dolžina strani strežnika" +#: superset-frontend/src/components/ReportModal/index.tsx:337 +msgid "Failed to create report" +msgstr "Ustvarjanje poročila nesupešno" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:289 -msgid "Server pagination" -msgstr "Paginacija na strani strežnika" +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:193 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:215 +msgid "Email reports active" +msgstr "E-poštna poročila aktivna" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:115 -msgid "Service Account" -msgstr "Servisni račun" +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:200 +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:231 +msgid "Delete email report" +msgstr "Izbriši e-poštno poročilo" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:286 -msgid "Set auto-refresh interval" -msgstr "Nastavi interval samodejnega osveževanja" +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:207 +msgid "Set up an email report" +msgstr "Nastavite e-poštno poročilo" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:295 -msgid "Set filter mapping" -msgstr "Nastavi shemo filtrov" +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:258 +msgid "Schedule email report" +msgstr "Dodaj e-poštno poročilo na urnik" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1264 -#: superset-frontend/src/components/Menu/MenuRight.tsx:133 -msgid "Settings" -msgstr "Nastavitve" +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:285 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:504 +#, python-format +msgid "This action will permanently delete %s." +msgstr "S tem dejanjem boste trajno izbrisali %s." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:133 -msgid "Settings for time series" -msgstr "Nastavitve časovne vrste" +#: superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx:296 +msgid "Delete Report?" +msgstr "Izbrišem poročilo?" -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:229 -msgid "Share" -msgstr "Deljenje" +#: superset-frontend/src/components/Select/Select.tsx:614 +#: superset-frontend/src/components/Select/Select.tsx:694 +#: superset-frontend/src/dashboard/components/gridComponents/DynamicComponent.tsx:165 +#: superset-frontend/src/explore/components/RowCountLabel/index.tsx:40 +msgid "Loading..." +msgstr "Nalagam ..." -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:317 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:175 -msgid "Share chart by email" -msgstr "Deli grafikon po e-pošti" +#: superset-frontend/src/components/TableLoader/index.tsx:91 +msgid "Access to user activity data is restricted" +msgstr "Dostop do aktivnosti uporabnikov je omejen" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:264 -msgid "Share dashboard by email" -msgstr "Deli nadzorno ploščo po e-pošti" +#: superset-frontend/src/components/TableSelector/index.tsx:240 +msgid "There was an error loading the tables" +msgstr "Napaka pri nalaganju tabel" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1221 -msgid "Shared query" -msgstr "Deljene poizvedbe" +#: superset-frontend/src/components/TableSelector/index.tsx:324 +msgid "See table schema" +msgstr "Ogled sheme tabele" -#: superset/views/database/forms.py:272 -msgid "Sheet Name" -msgstr "Ime zvezka" +#: superset-frontend/src/components/TableSelector/index.tsx:331 +#: superset-frontend/src/components/TableSelector/index.tsx:343 +msgid "Select table or type table name" +msgstr "Izberite ali vnesite ime tabele" -#: superset/annotation_layers/annotations/commands/exceptions.py:46 -msgid "Short description must be unique for this layer" -msgstr "Kratek opis mora biti za ta sloj unikaten" +#: superset-frontend/src/components/TableSelector/index.tsx:354 +msgid "Force refresh table list" +msgstr "Osveži seznam tabel" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:126 -msgid "" -"Should daily seasonality be applied. An integer value will specify " -"Fourier order of seasonality." -msgstr "" -"Če želite dnevno sezonskost. Celo število določa Fourier-jev red " -"sezonskosti." +#: superset-frontend/src/components/TimezoneSelector/index.tsx:129 +msgid "Timezone selector" +msgstr "Izbira časovnega pasa" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:109 +#: superset-frontend/src/dashboard/actions/dashboardLayout.js:182 msgid "" -"Should weekly seasonality be applied. An integer value will specify " -"Fourier order of seasonality." +"There is not enough space for this component. Try decreasing its width, or " +"increasing the destination width." msgstr "" -"Če želite tedensko sezonskost. Celo število določa Fourier-jev red " -"sezonskosti." +"Za to komponento ni dovolj prostora. Poskusite zmanjšati širino ali pa povečati " +"širino cilja." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:90 -msgid "" -"Should yearly seasonality be applied. An integer value will specify " -"Fourier order of seasonality." +#: superset-frontend/src/dashboard/actions/dashboardLayout.js:213 +msgid "Can not move top level tab into nested tabs" +msgstr "Najvišjega zavihka ni mogoče premakniti v gnezdene zavihke" + +#: superset-frontend/src/dashboard/actions/dashboardLayout.js:260 +msgid "This chart has been moved to a different filter scope." +msgstr "Ta grafikon je bil prestavljen v drug doseg filtrov." + +#: superset-frontend/src/dashboard/actions/dashboardState.js:98 +msgid "There was an issue fetching the favorite status of this dashboard." msgstr "" -"Če želite letno sezonskost. Celo število določa Fourier-jev red " -"sezonskosti." +"Pri pridobivanju statusa \"priljubljeno\" za to nadzorno ploščo je prišlo do " +"težave." -#: superset/views/annotations.py:59 -msgid "Show Annotation" -msgstr "Prikaži oznako" +#: superset-frontend/src/dashboard/actions/dashboardState.js:119 +msgid "There was an issue favoriting this dashboard." +msgstr "Pri uvrščanju nadzorne plošče med priljubljene je prišlo do težave." -#: superset/views/annotations.py:118 -msgid "Show Annotation Layer" -msgstr "Prikaži sloj z oznakami" +#: superset-frontend/src/dashboard/actions/dashboardState.js:143 +msgid "This dashboard is now published" +msgstr "Ta nadzorna plošča je sedaj objavljena" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:80 -msgid "Show Bubbles" -msgstr "Prikaži mehurčke" +#: superset-frontend/src/dashboard/actions/dashboardState.js:144 +msgid "This dashboard is now hidden" +msgstr "Ta nadzorna plošča je sedaj skrita" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:204 -msgid "Show CREATE VIEW statement" -msgstr "Prikaži CREATE VIEW stavek" +#: superset-frontend/src/dashboard/actions/dashboardState.js:152 +msgid "You do not have permissions to edit this dashboard." +msgstr "Nimate dovoljenj za urejanje te nadzorne plošče." -#: superset/views/css_templates.py:37 -msgid "Show CSS Template" -msgstr "Prikaži CSS predlogo" +#: superset-frontend/src/dashboard/actions/dashboardState.js:233 +msgid "[ untitled dashboard ]" +msgstr "[ neimenovana nadzorna plošča ]" -#: superset/views/chart/mixin.py:27 -msgid "Show Chart" -msgstr "Prikaži grafikon" +#: superset-frontend/src/dashboard/actions/dashboardState.js:284 +#: superset-frontend/src/dashboard/actions/dashboardState.js:322 +msgid "This dashboard was saved successfully." +msgstr "Nadzorna plošča je bila uspešno shranjena." -#: superset/connectors/sqla/views.py:64 -msgid "Show Column" -msgstr "Pokaži stolpec" +#: superset-frontend/src/dashboard/actions/dashboardState.js:328 +msgid "Sorry, an unknown error occured" +msgstr "Prišlo je do neznane napake" -#: superset/views/dashboard/mixin.py:26 -msgid "Show Dashboard" -msgstr "Prikaži nadzorno ploščo" +#: superset-frontend/src/dashboard/actions/dashboardState.js:331 +#, python-format +msgid "Sorry, there was an error saving this dashboard: %s" +msgstr "Prišlo je do napake pri shranjevanju nadzorne plošče: %s" -#: superset/views/database/mixins.py:34 -msgid "Show Database" -msgstr "Prikaži podatkovno bazo" +#: superset-frontend/src/dashboard/actions/dashboardState.js:337 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:111 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:117 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx:48 +msgid "You do not have permission to edit this dashboard" +msgstr "Nimate dovoljenja za urejanje te nadzorne plošče" -#: superset/connectors/druid/views.py:214 -msgid "Show Druid Cluster" -msgstr "Pokaži Druid gručo" +#: superset-frontend/src/dashboard/actions/sliceEntities.js:119 +#: superset-frontend/src/dashboard/reducers/sliceEntities.js:65 +msgid "Could not fetch all saved charts" +msgstr "Vseh shranjenih grafikonov ni bilo mogoče pridobiti" -#: superset/connectors/druid/views.py:71 -msgid "Show Druid Column" -msgstr "Pokaži Druid stolpec" +#: superset-frontend/src/dashboard/actions/sliceEntities.js:124 +msgid "Sorry there was an error fetching saved charts: " +msgstr "Prišlo je do napake pri pridobivanju shranjenih grafikonov: " -#: superset/connectors/druid/views.py:278 -msgid "Show Druid Datasource" -msgstr "Prikaži podatkovni vir za Druid" +#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:131 +msgid "Visualization" +msgstr "Vizualizacija" -#: superset/connectors/druid/views.py:160 -msgid "Show Druid Metric" -msgstr "Prikaži Druid mere" +#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:135 +msgid "Data source" +msgstr "Podatkovni vir" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:33 -msgid "Show Druid granularity dropdown" -msgstr "Prikaži spustni seznam za Druid granulacijo" +#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:140 +msgid "Added" +msgstr "Dodano" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:44 -msgid "Show Druid time origin" -msgstr "Prikaži časovno izhodišče za Druid" +#: superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx:56 +msgid "" +"Any color palette selected here will override the colors applied to this " +"dashboard's individual charts" +msgstr "" +"Na tem mestu izbrana barvna shema bo nadomestila barve posameznih grafikonov v " +"tej nadzorni plošči" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:96 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:127 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:149 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:94 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:71 -msgid "Show Labels" -msgstr "Pokaži oznake" +#: superset-frontend/src/dashboard/components/Dashboard.jsx:87 +msgid "You have unsaved changes." +msgstr "Imate neshranjene spremembe." -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:359 -msgid "Show Less..." -msgstr "Prikaži manj..." +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:80 +msgid "Changes saved." +msgstr "Spremembe shranjene." -#: superset/views/log/__init__.py:22 -msgid "Show Log" -msgstr "Prikaži dnevnik" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:98 +msgid "Disable embedding?" +msgstr "Onemogočite vgrajevanje?" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:64 -msgid "Show Markers" -msgstr "Prikaži markerje" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:99 +msgid "This will remove your current embed configuration." +msgstr "To bo odstranilo trenutno konfiguracijo za vgrajevanje." -#: superset/connectors/sqla/views.py:213 -msgid "Show Metric" -msgstr "Pokaži mero" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:108 +msgid "Embedding deactivated." +msgstr "Vgrajevanje deaktivirano." -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:178 -msgid "Show Metric Names" -msgstr "Pokaži imena mer" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:114 +msgid "Sorry, something went wrong. Embedding could not be deactivated." +msgstr "Nekaj je šlo narobe. Vgrajevanja ni mogoče deaktivirati." -#: superset/views/alerts.py:76 -msgid "Show Observation" -msgstr "Prikaži opažanja" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:163 +msgid "" +"This dashboard is ready to embed. In your application, pass the following id to " +"the SDK:" +msgstr "" +"Nadzorna plošča je pripravljena za vgradnjo. V svoji aplikaciji v SDK vključite " +"naslednji ID:" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:132 -msgid "Show Range Filter" -msgstr "Pokaži filter obdobja" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:170 +msgid "Configure this dashboard to embed it into an external web application." +msgstr "Nastavite nadzorno ploščo za vgradnjo v zunanjo spletno aplikacijo." -#: superset/connectors/sqla/views.py:315 -msgid "Show Row level security filter" -msgstr "Prikaži filter za varnost na nivoju vrstic" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:176 +msgid "For further instructions, consult the" +msgstr "Za nadaljnja navodila se posvetujte z" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:120 -msgid "Show SQL time column" -msgstr "Prikaži stolpec SQL čas" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:180 +msgid "Superset Embedded SDK documentation." +msgstr "Dokumentacija SDK za vgrajevanje." -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:105 -msgid "Show SQL time grain dropdown" -msgstr "Prikaži SQL spustni seznam za časovno granulacijo" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:186 +msgid "Allowed Domains (comma separated)" +msgstr "Dovoljene domene (ločeno z vejico)" -#: superset/views/sql_lab.py:40 -msgid "Show Saved Query" -msgstr "Prikaži shranjeno poizvedbo" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:188 +msgid "" +"A list of domain names that can embed this dashboard. Leaving this field empty " +"will allow embedding from any domain." +msgstr "" +"Seznam imen domen, ki lahko vgradijo to nadzorno ploščo. Če polje ostane prazno, " +"je vgrajevanje dovoljeno iz vseh domen." -#: superset/connectors/sqla/views.py:396 -msgid "Show Table" -msgstr "Prikaži tabelo" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:208 +msgid "Deactivate" +msgstr "Deaktiviraj" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:85 -msgid "Show Timestamp" -msgstr "Prikaži časovno značko" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:216 +msgid "Save changes" +msgstr "Shrani spremembe" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:97 -msgid "Show Trend Line" -msgstr "Pokaži trendno črto" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:225 +msgid "Enable embedding" +msgstr "Omogoči vgrajevanje" -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:83 -msgid "Show Upper Labels" -msgstr "Prikaži zgornje oznake" +#: superset-frontend/src/dashboard/components/DashboardEmbedControls.tsx:237 +msgid "Embed" +msgstr "Vgradi" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:106 -msgid "Show Value" -msgstr "Prikaži vrednost" +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:161 +msgid "Drag and drop components and charts to the dashboard" +msgstr "Povlecite in spustite elemente in grafikone na nadzorno ploščo" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:164 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:301 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:182 -msgid "Show Values" -msgstr "Pokaži vrednosti" +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:162 +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:185 +msgid "You can create a new chart or use existing ones from the panel on the right" +msgstr "Ustvarite lahko nove grafikone ali uporabite obstoječe iz panela na desni" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx:173 -msgid "Show all columns" -msgstr "Prikaži vse stolpce" +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:184 +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:178 +msgid "Drag and drop components to this tab" +msgstr "Povlecite in spustite elemente na zavihek" -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:326 -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:359 -msgid "Show all..." -msgstr "Prikaži vse..." +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:205 +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:179 +msgid "There are no components added to this tab" +msgstr "Na zavihek niso bili dodani elementi" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:206 -msgid "Show axis line ticks" -msgstr "Prikaži oznake na X-osi" +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:207 +msgid "You can add the components in the edit mode." +msgstr "Elemente lahko dodate v načinu urejanja." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:119 -msgid "Show cell bars" -msgstr "Prikaži stolp. graf v celicah" +#: superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx:447 +#: superset-frontend/src/dashboard/components/DashboardGrid.jsx:209 +msgid "Edit the dashboard" +msgstr "Uredi nadzorno ploščo" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:161 -msgid "Show columns total" -msgstr "Prikaži vsoto stolpcev" +#: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:64 +msgid "Ready to review filters in this dashboard?" +msgstr "Ste pripravljeni za pregled filtrov v tej nadzorni plošči?" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:67 -msgid "Show data points as circle markers on the lines" -msgstr "Pokaži točke kot krožne markerje na krivuljah" +#: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:69 +msgid "Remind me in 24 hours" +msgstr "Opomni me čez 24 ur" -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:52 +#: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:79 +msgid "Start Review" +msgstr "Začetek pregleda" + +#: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:86 +#: superset-frontend/src/dashboard/containers/DashboardPage.tsx:169 msgid "" -"Show hierarchical relationships of data, with with the value represented " -"by area, showing proportion and contribution to the whole." +"filter_box will be deprecated in a future version of Superset. Please replace " +"filter_box by dashboard filter components." msgstr "" -"Prikaže hierarhična razmerja podatkov, pri čemer je vrednost ponazorjena " -"s ploščino, in deleže oz. prispevke k celoti." +"Element filter_box bo v prihodnjih verzijah Superseta opuščen. Nadomestite ga s " +"filtri nadzorne plošče." -#: superset-frontend/packages/superset-ui-chart-controls/src/components/InfoTooltipWithTrigger.tsx:50 -msgid "Show info tooltip" -msgstr "Prikaži opis orodja" +#: superset-frontend/src/dashboard/components/MissingChart.jsx:31 +msgid "" +"There is no chart definition associated with this component, could it have been " +"deleted?" +msgstr "" +"S to komponento ni povezana nobena definicija grafikona. Ali je bila izbrisana?" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:736 -#, fuzzy -msgid "Show label" -msgstr "Pokaži oznake" +#: superset-frontend/src/dashboard/components/MissingChart.jsx:36 +msgid "Delete this container and save to remove this message." +msgstr "Izbrišite ta okvir in shranite za odpravo tega sporočila." -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:86 -msgid "Show labels when the node has children." -msgstr "Prikaži oznake, ko ima vozlišče podrejene elemente." +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:29 +msgid "Don't refresh" +msgstr "Ne osvežuj" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:35 -msgid "Show legend" -msgstr "Prikaži legendo" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:30 +msgid "10 seconds" +msgstr "10 sekund" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx:168 -msgid "Show less columns" -msgstr "Prikaži manj stolpcev" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:31 +msgid "30 seconds" +msgstr "30 sekund" -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:326 -msgid "Show less..." -msgstr "Prikaži manj..." +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:32 +msgid "1 minute" +msgstr "1 minuta" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:287 -msgid "Show percentage" -msgstr "Prikaži procente" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:33 +msgid "5 minutes" +msgstr "5 minut" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:179 -msgid "Show pointer" -msgstr "Prikaži kazalec" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:34 +msgid "30 minutes" +msgstr "30 minut" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:245 -msgid "Show progress" -msgstr "Prikaži območje" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:35 +msgid "1 hour" +msgstr "1 ura" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:149 -msgid "Show rows total" -msgstr "Prikaži vsoto vrstic" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:36 +msgid "6 hours" +msgstr "6 ur" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:109 -msgid "Show series values on the chart" -msgstr "Na grafikonu prikaži vrednosti serij" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:37 +msgid "12 hours" +msgstr "12 ur" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:218 -msgid "Show split lines" -msgstr "Prikaži razdelitvene črte" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:38 +msgid "24 hours" +msgstr "24 ur" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:297 -msgid "Show the value on top of the bar" -msgstr "Prikaži vrednosti na vrhu stolpcev" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:90 +msgid "Refresh interval saved" +msgstr "Interval osveževanja shranjen" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:121 -msgid "Show time column" -msgstr "Prikaži časovni stolpec" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:116 +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:121 +msgid "Refresh interval" +msgstr "Interval osveževanja" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:106 -msgid "Show time grain dropdown" -msgstr "Prikaži spustni seznam za časovno granulacijo" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:119 +msgid "Refresh frequency" +msgstr "Frekvenca osveževanja" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:351 -msgid "" -"Show total aggregations of selected metrics. Note that row limit does not" -" apply to the result." -msgstr "" -"Prikaži skupno agregacijo izbrane mere. Omejitev števila vrstic ne vpliva" -" na rezultat." +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:135 +msgid "Are you sure you want to proceed?" +msgstr "Ali želite nadaljevati?" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:87 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:349 -msgid "Show totals" -msgstr "Pokaži vsote" +#: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:150 +msgid "Save for this session" +msgstr "Shranite za to sejo" + +#: superset-frontend/src/dashboard/components/SaveModal.tsx:156 +msgid "You must pick a name for the new dashboard" +msgstr "Izbrati morate ime nove nadzorne plošče" + +#: superset-frontend/src/dashboard/components/SaveModal.tsx:178 +msgid "Save dashboard" +msgstr "Shrani nadzorno ploščo" + +#: superset-frontend/src/dashboard/components/SaveModal.tsx:187 +#, python-format +msgid "Overwrite Dashboard [%s]" +msgstr "Prepiši nadzorno ploščo [%s]" + +#: superset-frontend/src/dashboard/components/SaveModal.tsx:195 +msgid "Save as:" +msgstr "Shrani kot:" + +#: superset-frontend/src/dashboard/components/SaveModal.tsx:199 +msgid "[dashboard name]" +msgstr "[ime nadzorne plošče]" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:31 -msgid "" -"Showcases a single metric front-and-center. Big number is best used to " -"call attention to a KPI or the one thing you want your audience to focus " -"on." -msgstr "" -"Prikaže eno vrednost. Velika številka je primerna za poudarek KPI-ja ali " -"vrednosti, na katero želite usmeriti pozornost." +#: superset-frontend/src/dashboard/components/SaveModal.tsx:209 +msgid "also copy (duplicate) charts" +msgstr "kopiraj (podvoji) tudi grafikone" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:30 -msgid "" -"Showcases a single number accompanied by a simple line chart, to call " -"attention to an important metric along with its change over time or other" -" dimension." -msgstr "" -"Prikaže eno vrednost skupaj s preprostim črtnim grafikonom, za poudarek " -"pomembne mere skupaj z njeno časovno spremembo." +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:293 +msgid "Filter your charts" +msgstr "Filtriraj grafikone" -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:49 -msgid "" -"Showcases how a metric changes as the funnel progresses. This classic " -"chart is useful for visualizing drop-off between stages in a pipeline or " -"lifecycle." -msgstr "" -"Prikaže kako se mera spreminja, ko lijak napreduje. Standardni grafikon " -"za prikaz sprememb med nivoji v procesu ali življenjskem ciklu." +#: superset-frontend/src/dashboard/components/SliceAdder.jsx:304 +#, python-format +msgid "Sort by %s" +msgstr "Razvrščanje po %s" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:28 -msgid "" -"Showcases the flow or link between categories using thickness of chords. " -"The value and corresponding thickness can be different for each side." -msgstr "" -"Prikaže potek ali povezave med kategorijami z debelino tetiv. Vrednost in" -" debelina sta lahko različni za vsako stran." +#: superset-frontend/src/dashboard/components/AnchorLink/index.tsx:71 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:388 +msgid "Superset chart" +msgstr "Superset grafikon" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:27 -msgid "" -"Showcases the progress of a single metric against a given target. The " -"higher the fill, the closer the metric is to the target." -msgstr "" -"Prikaže napredovanje posamezne mere glede na cilj. Večja napolnjenost, " -"pomeni, da je mera bližje cilju." +#: superset-frontend/src/dashboard/components/AnchorLink/index.tsx:72 +msgid "Check out this chart in dashboard:" +msgstr "Preizkusite ta grafikon v nadzorni plošči:" -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:305 -#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:338 -#, python-format -msgid "Showing %s of %s" -msgstr "Prikazanih %s od %s" +#: superset-frontend/src/dashboard/components/BuilderComponentPane/index.tsx:115 +msgid "Layout elements" +msgstr "Postavitev elementov" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:152 -msgid "Shows a list of all series available at that point in time" -msgstr "Prikaže seznam vseh razpoložljivih podatkovnih serij za istočasno točko" +#: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:65 +msgid "Cross Filter Scoping" +msgstr "Doseg medsebojnega filtra" -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:31 -msgid "" -"Shows the composition of a dataset by segmenting a given rectangle as " -"smaller rectangles with areas proportional to their value or contribution" -" to the whole. Those rectangles may also, in turn, be further segmented " -"hierarchically." -msgstr "" -"Prikaže zgradbo podatkovnega seta na podlagi segmentacije danega " -"pravokotnika na manjše pravokotnike, pri čemer je ploščina sorazmerna " -"vrednostim oz. deležem. Pravokotniki se lahko dodatno hierarhično " -"segmentirajo." +#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:94 +msgid "Load a CSS template" +msgstr "Naloži CSS predlogo" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:72 -msgid "Significance Level" -msgstr "Stopnja značilnosti" +#: superset-frontend/src/dashboard/components/CssEditor/index.jsx:109 +msgid "Live CSS editor" +msgstr "CSS urejevalnik v živo" -#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:262 -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:201 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:394 -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:397 -msgid "Simple" -msgstr "Preprosto" +#: superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx:440 +msgid "There are no charts added to this dashboard" +msgstr "V nadzorni plošči ni grafikonov" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:390 -msgid "Simple ad-hoc metrics are not enabled for this dataset" -msgstr "Preproste ad-hoc mere za ta podatkovni set niso omogočene" +#: superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx:443 +msgid "Go to the edit mode to configure the dashboard and add charts" +msgstr "" +"Za nastavitve nadzorne plošče in dodajanje grafikonov pojdite v način urejanja" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:186 -msgid "Single" -msgstr "Posamezno" +#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:186 +#, python-format +msgid "Applied Cross Filters (%d)" +msgstr "Uporabljeni medsebojni filtri (%d)" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:45 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:46 -msgid "Single Metric" -msgstr "Ena mera" +#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:210 +#, python-format +msgid "Applied Filters (%d)" +msgstr "Uporabljeni filtri (%d)" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1234 -#, fuzzy -msgid "Single Value" -msgstr "Desna vrednost" +#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:231 +#, python-format +msgid "Incompatible Filters (%d)" +msgstr "Neskladni filtri (%d)" -#: superset-frontend/src/filters/components/Range/controlPanel.ts:65 -#, fuzzy -msgid "Single value" -msgstr "Desna vrednost" +#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:255 +#, python-format +msgid "Unset Filters (%d)" +msgstr "Neuporabljeni filtri (%d)" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1251 -msgid "Single value type" +#: superset-frontend/src/dashboard/components/Header/index.jsx:306 +#, python-format +msgid "" +"This dashboard is currently auto refreshing; the next auto refresh will be in %s." msgstr "" +"Nadzorna plošča se trenutno samodejno osvežuje. Naslednja samodejna osvežitev bo " +"čez %s." -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:261 -msgid "Size of edge symbols" -msgstr "Velikost simbola povezave" +#: superset-frontend/src/dashboard/components/Header/index.jsx:396 +msgid "Your dashboard is too large. Please reduce its size before saving it." +msgstr "Vaša nadzorna plošča je prevelika. Pred shranjevanjem jo zmanjšajte." -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:230 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:168 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:129 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:109 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:126 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:184 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:187 -msgid "Size of marker. Also applies to forecast observations." -msgstr "Velikost markerja. Upošteva se tudi za napovedi." +#: superset-frontend/src/dashboard/components/Header/index.jsx:497 +msgid "Add the name of the dashboard" +msgstr "Dodajte naziv nadzorne plošče" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:34 -msgid "Sizes of vehicles" -msgstr "Velikosti vozil" +#: superset-frontend/src/dashboard/components/Header/index.jsx:498 +msgid "Dashboard title" +msgstr "Naziv nadzorne plošče" -#: superset/views/database/forms.py:199 -msgid "Skip Blank Lines" -msgstr "Izpusti prazne vrstice" +#: superset-frontend/src/dashboard/components/Header/index.jsx:533 +msgid "Undo the action" +msgstr "Razveljavi dejanje" -#: superset/views/database/forms.py:184 -msgid "Skip Initial Space" -msgstr "Izpusti začetni presledek" +#: superset-frontend/src/dashboard/components/Header/index.jsx:553 +msgid "Redo the action" +msgstr "Ponovno uveljavi dejanje" -#: superset/views/database/forms.py:187 superset/views/database/forms.py:328 -msgid "Skip Rows" -msgstr "Izpusti vrstice" +#: superset-frontend/src/dashboard/components/Header/index.jsx:578 +#: superset-frontend/src/dashboard/components/Header/index.jsx:580 +msgid "Discard" +msgstr "Zavrzi" -#: superset/views/database/forms.py:200 -msgid "Skip blank lines rather than interpreting them as NaN values." -msgstr "Raje izpusti prazne vrstice, kot pa da so prepoznane kot NaN vrednosti." +#: superset-frontend/src/dashboard/components/Header/index.jsx:611 +#: superset-frontend/src/dashboard/components/Header/index.jsx:613 +msgid "Edit dashboard" +msgstr "Uredi nadzorno ploščo" -#: superset/views/database/forms.py:184 -msgid "Skip spaces after delimiter." -msgstr "Izpusti presledek za ločilnikom." +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:129 +msgid "An error occurred while fetching available CSS templates" +msgstr "Pri pridobivanju CSS predlog je prišlo do napake" -#: superset/views/schedules.py:243 superset/views/schedules.py:323 -msgid "Slack Channel" -msgstr "Slack Channel" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:162 +msgid "Refreshing charts" +msgstr "Osveževanje grafikonov" -#: superset/views/dashboard/mixin.py:80 -msgid "Slug" -msgstr "Slug" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:233 +msgid "Superset dashboard" +msgstr "Superset nadzorna plošča" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:39 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:73 -#: superset-frontend/src/dashboard/util/headerStyleOptions.ts:25 -msgid "Small" -msgstr "Majhno" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:235 +msgid "Check out this dashboard: " +msgstr "Preizkusite to nadzorno ploščo: " -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:153 -msgid "Small number format" -msgstr "Oblika zapisa majhnih števil" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:252 +msgid "Refresh dashboard" +msgstr "Osveži nadzorno ploščo" -#: superset/commands/exceptions.py:112 -msgid "Some roles do not exist" -msgstr "Nekatere vloge ne obstajajo" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:261 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:274 +msgid "Exit fullscreen" +msgstr "Izhod iz celozaslonskega načina" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:623 -#, python-format -msgid "Sorry there was an error fetching database information: %s" -msgstr "Pri pridobivanju informacij o podatkovni bazi je prišlo do napake: %s" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:262 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:275 +msgid "Enter fullscreen" +msgstr "Vklopi celozaslonski način" -#: superset-frontend/src/dashboard/actions/sliceEntities.js:121 -msgid "Sorry there was an error fetching saved charts: " -msgstr "Prišlo je do napake pri pridobivanju shranjenih grafikonov: " +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:270 +msgid "Edit properties" +msgstr "Uredi lastnosti" -#: superset-frontend/src/explore/components/DataTablesPane/index.tsx:273 -#: superset-frontend/src/explore/components/controls/ViewQueryModal.tsx:84 -msgid "Sorry, An error occurred" -msgstr "Prišlo je do napake" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:276 +msgid "Edit CSS" +msgstr "Uredi CSS" -#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:65 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:126 -msgid "Sorry, something went wrong. Try again later." -msgstr "Nekaj je šlo narobe. Poskusite ponovno kasneje." +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:314 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:422 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:300 +msgid "Download as image" +msgstr "Izvozi kot sliko" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/EventFlow.tsx:50 -msgid "Sorry, there appears to be no data" -msgstr "Ni podatkov" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:322 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:382 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:303 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:230 +msgid "Share" +msgstr "Deljenje" -#: superset-frontend/src/dashboard/actions/dashboardState.js:238 -#, fuzzy, python-format -msgid "Sorry, there was an error saving this dashboard: %s" -msgstr "Prišlo je do napake pri pridobivanju shranjenih grafikonov: " +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:326 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:386 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:305 +msgid "Copy permalink to clipboard" +msgstr "Kopiraj povezavo v odložišče" -#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:55 -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:115 -#: superset-frontend/src/views/CRUD/data/components/SyntaxHighlighterCopy/index.tsx:76 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:219 -#: superset-frontend/src/views/CRUD/hooks.ts:604 -msgid "Sorry, your browser does not support copying." -msgstr "Vaš brskalnik ne podpira kopiranja." +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:327 +msgid "Share permalink by email" +msgstr "Deli povezavo po e-pošti" -#: superset-frontend/src/components/CopyToClipboard/index.jsx:79 -msgid "Sorry, your browser does not support copying. Use Ctrl / Cmd + C!" -msgstr "Vaš brskalnik ne podpira kopiranja. Uporabite Ctrl / Cmd + C!" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:341 +msgid "Embed dashboard" +msgstr "Vgradi nadzorno ploščo" -#: superset-frontend/src/components/ListView/CardSortSelect.tsx:82 -#: superset-frontend/src/components/ListView/CardSortSelect.tsx:83 -msgid "Sort" -msgstr "Razvrsti" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:348 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:331 +msgid "Manage email report" +msgstr "Upravljaj e-poštno poročilo" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:92 -msgid "Sort Bars" -msgstr "Uredi stolpce" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:377 +msgid "Set filter mapping" +msgstr "Nastavi shemo filtrov" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:42 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:45 -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:40 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:48 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:47 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:46 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:44 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:59 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:354 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:105 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:89 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:86 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:83 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:89 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:90 -msgid "Sort Descending" -msgstr "Razvrsti padajoče" +#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:390 +msgid "Set auto-refresh interval" +msgstr "Nastavi interval samodejnega osveževanja" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1198 -msgid "Sort Metric" -msgstr "Mera za razvrščanje" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:100 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:826 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:228 +#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:484 +msgid "Apply" +msgstr "Uporabi" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:251 -msgid "Sort X Axis" -msgstr "Razvrsti X-os" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:272 +msgid "A valid color scheme is required" +msgstr "Zahtevana je veljavna barvna shema" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:263 -msgid "Sort Y Axis" -msgstr "Razvrsti Y-os" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:337 +msgid "Dashboard properties updated" +msgstr "Lastnosti nadzorne plošče posodobljene" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1188 -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:205 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:66 -msgid "Sort ascending" -msgstr "Razvrsti naraščajoče" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:355 +msgid "The dashboard has been saved" +msgstr "Nadzorna plošča je bila shranjena" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:95 -msgid "Sort bars by x labels." -msgstr "Uredi stolpce po x-oznakah." +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:371 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:414 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:299 +msgid "Access" +msgstr "Dostop" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:125 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:369 -#: superset-frontend/src/dashboard/components/SliceAdder.jsx:259 -#: superset-frontend/src/explore/controls.jsx:384 -msgid "Sort by" -msgstr "Razvrščanje" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:386 +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:433 +msgid "" +"Owners is a list of users who can alter the dashboard. Searchable by name or " +"username." +msgstr "" +"\"Lastniki\" je seznam uporabnikov, ki lahko spreminjajo nadzorno ploščo. Iskanje " +"je možno po imenu ali uporabniškem imenu." -#: superset-frontend/src/dashboard/components/SliceAdder.jsx:256 -#, fuzzy, python-format -msgid "Sort by %s" -msgstr "Razvrščanje" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:392 +msgid "Colors" +msgstr "Barve" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:39 -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:38 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:94 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:55 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:39 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:62 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:65 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:62 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:49 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:38 -msgid "Sort by metric" -msgstr "Mera za razvrščanje" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:453 +msgid "" +"Roles is a list which defines access to the dashboard. Granting a role access to " +"a dashboard will bypass dataset level checks. If no roles are defined, then the " +"dashboard is available to all roles." +msgstr "" +"\"Vloge\" je seznam, ki definira dostop do nadzorne plošče. Dodelitev vloge za " +"dostop do nadzorne plošče bo obšlo preverjanje na nivoju podatkovnega seta. Če " +"vloga ni definirana, bo nadzorna plošča dostopna vsem vlogam." -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:184 -msgid "Sort columns alphabetically" -msgstr "Razvrsti stolpce po abecedi" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:503 +msgid "Dashboard properties" +msgstr "Lastnosti nadzorne plošče" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:257 -#, fuzzy -msgid "Sort columns by" -msgstr "Brez stolpcev" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:524 +msgid "This dashboard is managed externally, and can't be edited in Superset" +msgstr "Ta nadzorna plošča se ne ureja znotraj Superseta" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/legacySortBy.tsx:29 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:337 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1189 -#: superset-frontend/src/explore/controlPanels/sections.tsx:125 -msgid "Sort descending" -msgstr "Razvrsti padajoče" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:545 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:241 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:288 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:247 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:237 +msgid "Basic information" +msgstr "Osnovne informacije" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1167 -msgid "Sort filter values" -msgstr "Razvrsti vrednosti filtra" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:559 +msgid "URL slug" +msgstr "URL slug" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1211 -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:184 -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:188 -msgid "Sort metric" -msgstr "Mera za razvrščanje" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:563 +msgid "A readable URL for your dashboard" +msgstr "Berljiv URL za vašo nadzorno ploščo" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:229 -#, fuzzy -msgid "Sort rows by" -msgstr "Razvrščanje" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:572 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:264 +msgid "Certification" +msgstr "Certifikacija" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1181 -msgid "Sort type" -msgstr "Način razvrščanja" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:581 +msgid "Person or group that has certified this dashboard." +msgstr "Oseba ali skupina, ki je certificirala to nadzorno ploščo." -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:60 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:52 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1189 -msgid "Source" -msgstr "Izvor" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:592 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:281 +msgid "Any additional detail to show in the certification tooltip." +msgstr "Dodatne podrobnosti za prikaz v certifikacijskem orodju." -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:104 -#: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:43 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:33 -msgid "Source / Target" -msgstr "Izhodišče/Cilj" +#: superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:612 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:336 +msgid "JSON metadata" +msgstr "JSON metapodatki" + +#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:33 +msgid "" +"This dashboard is not published, it will not show up in the list of dashboards. " +"Click here to publish this dashboard." +msgstr "" +"Ta nadzorna plošča ni objavljena in se ne bo prikazala na seznamu nadzornih " +"plošč. Kliknite tukaj za njeno objavo." -#: superset-frontend/src/SqlLab/components/HighlightedSql/index.tsx:76 -msgid "Source SQL" -msgstr "Izvorni SQL" +#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:38 +msgid "" +"This dashboard is not published which means it will not show up in the list of " +"dashboards. Favorite it to see it there or access it by using the URL directly." +msgstr "" +"Ta nadzorna plošča ni objavljena in se ne bo prikazala na seznamu nadzornih " +"plošč. Uvrstite jo med priljubljene, da jo boste videli tam, ali pa uporabite URL " +"za neposredni dostop." -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:73 -msgid "Source category" -msgstr "Kategorija izvora" +#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:43 +msgid "This dashboard is published. Click to make it a draft." +msgstr "Ta nadzorna plošča je objavljena. Kliknite, da jo uvrstite med osnutke." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:804 -msgid "Spatial" -msgstr "Prostorski" +#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:72 +#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:83 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:304 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:507 +msgid "Draft" +msgstr "Osnutek" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:90 -msgid "Specific Date/Time" -msgstr "Fiksen Datum/Čas" +#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:48 +msgid "Annotation layers are still loading." +msgstr "Sloj z oznakami se še vedno nalaga." -#: superset/views/database/forms.py:127 superset/views/database/forms.py:286 -#: superset/views/database/forms.py:414 -msgid "Specify a schema (if database flavor supports this)." -msgstr "Podajte shemo (če vrsta podatkovne baze to podpira)" +#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:49 +msgid "One ore more annotation layers failed loading." +msgstr "Eden ali več slojev z oznakami se ni naložil." -#: superset/views/database/forms.py:172 superset/views/database/forms.py:325 -msgid "Specify duplicate columns as \"X.0, X.1\"." -msgstr "Določite podvojene stolpce kot \"X.0, X.1\"." +#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:102 +msgid "Emitted values" +msgstr "Oddane vrednosti" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:494 -msgid "" -"Specify the database version. This should be used with Presto in order to" -" enable query cost estimation." -msgstr "" -"Podajte verzijo podatkovne baze. Uporablja se s Presto, za potrebe " -"ocenjevanja potratnosti poizvedbe." +#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:115 +#, python-format +msgid "Click to edit %s in a new tab" +msgstr "Kliknite za urejanje %s v novem zavihku" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:230 -msgid "Split number" -msgstr "Število razdelitev" +#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:116 +msgid "Click to edit chart in a new tab" +msgstr "Kliknite za urejanje grafikona v novem zavihku" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:156 -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:117 -msgid "Stack series" -msgstr "Nalagaj serije" +#: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:183 +msgid "Click to clear emitted filters" +msgstr "S klikom počistite oddane filtre" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:159 -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:120 -msgid "Stack series on top of each other" -msgstr "Nalagaj serije eno na drugo" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:179 +msgid "Data refreshed" +msgstr "Podatki osveženi" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:37 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:51 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:40 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:47 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:84 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:83 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:68 -msgid "Stacked" -msgstr "Naložen" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:257 +#, python-format +msgid "Cached %s" +msgstr "Predpomnjeno %s" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:305 -msgid "Stacked Bars" -msgstr "Naloženi stolpci" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:260 +#, python-format +msgid "Fetched %s" +msgstr "Pridobljeno %s" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:52 -msgid "Stacked Style" -msgstr "Slog nalaganja" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:269 +#, python-format +msgid "Query %s: %s" +msgstr "Poizvedba %s: %s" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:37 -msgid "Stacked style" -msgstr "Naložen slog" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:288 +msgid "Force refresh" +msgstr "Osveži" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:88 -msgid "Standard time series" -msgstr "Standardna časovna vrsta" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:301 +msgid "Hide chart description" +msgstr "Skrij opis grafikona" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:155 -#: superset/views/annotations.py:79 -msgid "Start" -msgstr "Začetek" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:302 +msgid "Show chart description" +msgstr "Prikaži opis grafikona" -#: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:79 -msgid "Start Review" -msgstr "Začetek pregleda" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:311 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:356 +msgid "Edit chart" +msgstr "Uredi grafikon" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:110 -msgid "Start angle" -msgstr "Začetni kot" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:319 +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:321 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:357 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:359 +msgid "View query" +msgstr "Ogled poizvedbe" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:125 -msgid "Start at (UTC)" -msgstr "Zažene se ob (UTC)" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:337 +msgid "Drill to detail" +msgstr "Vrtaj v podrobnosti" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:66 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:117 -msgid "Start date included in time range" -msgstr "Začetni datum je vključen v časovno obdobje" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:340 +#, python-format +msgid "Chart Data: %s" +msgstr "Podatki grafikona: %s" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:109 -msgid "Start y-axis at 0" -msgstr "Začni y-os z 0" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:375 +msgid "Cross-filter scoping" +msgstr "Doseg medsebojnega filtra" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:112 -msgid "" -"Start y-axis at zero. Uncheck to start y-axis at minimum value in the " -"data." -msgstr "" -"Začni y-os z nič. Ne izberite, če želite, da se y-os začne z najmanjšo " -"vrednostjo podatkov." +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:387 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:308 +msgid "Share chart by email" +msgstr "Deli grafikon po e-pošti" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:94 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:348 -msgid "State" -msgstr "Status" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:389 +msgid "Check out this chart: " +msgstr "Preizkusite ta grafikon: " -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 -msgid "Statistical" -msgstr "Statistično" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:398 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:266 +msgid "Download" +msgstr "Prenos" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:399 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:302 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:492 -msgid "Status" -msgstr "Status" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:403 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:290 +msgid "Export to .CSV" +msgstr "Izvozi v .CSV" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:112 -msgid "Step type" -msgstr "Stopnični tip" +#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:414 +msgid "Export to full .CSV" +msgstr "Izvozi v celoten .CSV" -#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:49 -#: superset-frontend/src/explore/components/QueryAndSaveBtns.jsx:66 -msgid "Stop" -msgstr "Ustavi" +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:453 +msgid "Search..." +msgstr "Iskanje ..." -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:339 -msgid "Stop query" -msgstr "Ustavi poizvedbo" +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:484 +msgid "No filter is selected." +msgstr "Noben filter ni izbran." -#: superset-frontend/src/SqlLab/components/RunQueryActionButton/index.tsx:115 -msgid "Stop running (Ctrl + x)" -msgstr "Ustavi (Ctrl + x)" +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:485 +msgid "Editing 1 filter:" +msgstr "Urejanje enega filtra:" -#: superset/databases/commands/exceptions.py:126 -msgid "Stopped an unsafe database connection" -msgstr "Nevarna povezava s podatkovno bazo je bila ustavljena" +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:487 +#, python-format +msgid "Batch editing %d filters:" +msgstr "Skupinsko urejanje %d filtrov:" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:268 -msgid "Strength to pull the graph toward center" -msgstr "Sila privlačnosti med grafikonom in središčem" +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:501 +msgid "Configure filter scopes" +msgstr "Nastavi doseg filtrov" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:36 -msgid "Stretched style" -msgstr "Raztegnjen slog" +#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:508 +msgid "There are no filters in this dashboard." +msgstr "V nadzorni plošči ni filtrov." -#: superset/views/database/forms.py:273 -msgid "Strings used for sheet names (default is the first sheet)." -msgstr "" -"Znakovni nizi uporabljeni za imena preglednic (privzeto je prva " -"preglednica)." +#: superset-frontend/src/dashboard/components/filterscope/treeIcons.jsx:36 +msgid "Expand all" +msgstr "Razširi vse" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:45 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:45 -msgid "Structural" -msgstr "Strukturni" +#: superset-frontend/src/dashboard/components/filterscope/treeIcons.jsx:39 +msgid "Collapse all" +msgstr "Skrči vse" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:621 -msgid "Style" -msgstr "Slog" +#: superset-frontend/src/dashboard/components/gridComponents/Chart.jsx:293 +msgid "An error occurred while opening Explore" +msgstr "Pri odpiranju Raziskovalca je prišlo do napake" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:272 -msgid "Style the ends of the progress bar with a round cap" -msgstr "Zaobljena oblika koncev območja" +#: superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx:80 +msgid "This markdown component has an error." +msgstr "Markdown komponenta ima napako." -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:56 -msgid "Subdomain" -msgstr "Poddomena" +#: superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx:167 +msgid "This markdown component has an error. Please revert your recent changes." +msgstr "Markdown komponenta ima napako. Povrnite nedavne spremembe." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:46 -msgid "Subheader" -msgstr "Podnaslov" +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:185 +msgid "You can" +msgstr "Lahko" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:62 -msgid "Subheader Font Size" -msgstr "Velikost pisave podnaslova" +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:191 +msgid "create a new chart" +msgstr "ustvarite nov grafikon" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:63 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:54 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:142 -msgid "Success" -msgstr "Uspelo" +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:193 +msgid "or use existing ones from the panel on the right" +msgstr "ali uporabite obstoječe iz panela na desni" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:62 -msgid "Suffix to apply after the percentage display" -msgstr "Pripona za prikaz procenta" +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:197 +msgid "You can add the components in the" +msgstr "Lahko dodate elemente v" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:98 -msgid "Sum of values over specified period" -msgstr "Vsota vrednosti v dani periodi" +#: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:203 +msgid "edit mode" +msgstr "načinu urejanja" -#: superset/viz.py:1856 -msgid "Sunburst" -msgstr "Sunburst" +#: superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx:193 +msgid "Delete dashboard tab?" +msgstr "Ali izbrišem zavihek nadzorne plošče?" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:32 -msgid "Sunburst Chart" -msgstr "Večnivojski tortni grafikon" +#: superset-frontend/src/dashboard/components/gridComponents/new/NewDivider.jsx:31 +msgid "Divider" +msgstr "Ločilnik" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:56 -msgid "Sunday" -msgstr "Nedelja" +#: superset-frontend/src/dashboard/components/gridComponents/new/NewHeader.jsx:31 +msgid "Header" +msgstr "Glava" -#: superset-frontend/src/explore/components/ExploreActionButtons.tsx:121 -msgid "Superset Chart" -msgstr "Superset grafikon" +#: superset-frontend/src/dashboard/components/gridComponents/new/NewRow.jsx:31 +msgid "Row" +msgstr "Vrstica" -#: superset-frontend/src/components/AnchorLink/index.jsx:84 -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:318 -msgid "Superset chart" -msgstr "Superset grafikon" +#: superset-frontend/src/dashboard/components/gridComponents/new/NewTabs.jsx:31 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx:60 +msgid "Tabs" +msgstr "Zavihki" -#: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:218 -msgid "Superset dashboard" -msgstr "Superset nadzorna plošča" +#: superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.tsx:39 +msgid "Preview" +msgstr "Predogled" -#: superset/errors.py:105 -msgid "Superset encountered an error while running a command." -msgstr "Superset je naletel na napako pri izvajanju ukaza." +#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:71 +#: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:84 +#: superset-frontend/src/explore/components/EmbedCodeContent.jsx:58 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:127 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:174 +msgid "Sorry, something went wrong. Try again later." +msgstr "Nekaj je šlo narobe. Poskusite ponovno kasneje." -#: superset/errors.py:106 -msgid "Superset encountered an unexpected error." -msgstr "Superset je naletel na nepričakovano napako." +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:419 +#, python-format +msgid "All filters (%(filterCount)d)" +msgstr "Vsi filtri (%(filterCount)d)" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:670 -#, fuzzy -msgid "Supported databases" -msgstr "Uvozi podatkovne baze" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:436 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:476 +msgid "No filters are currently added" +msgstr "Trenutno ni dodanih filtrov" -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:34 -msgid "Survey Responses" -msgstr "Rezultati anket" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:440 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:480 +msgid "Click the button above to add a filter to the dashboard" +msgstr "S klikom gumba zgoraj dodate filter na nadzorno ploščo" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:112 -msgid "Swap Groups and Columns" -msgstr "Zamenjaj Skupine in Stolpce" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:456 +#, python-format +msgid "Filter sets (%(filterSetCount)d)" +msgstr "Nastavljeni filtri (%(filterSetCount)d)" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:175 -msgid "Swap rows and columns" -msgstr "Zamenjaj vrstice in stolpce" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx:115 +msgid "Apply filters" +msgstr "Uporabi filtre" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:59 -msgid "" -"Swiss army knife for visualizing time series data. Choose between step, " -"line, scatter, and bar charts. This viz type has many customization " -"options as well." -msgstr "" -"Univerzalni grafikon za prikaz časovnih vrst. Izbirajte med stopničnimi, " -"črtnimi, raztresenimi in stolpčnimi grafikoni. Grafikon ima širok nabor " -"prilagoditev." +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx:125 +msgid "Clear all" +msgstr "Počisti vse" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:210 -msgid "Symbol" -msgstr "Simbol" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx:152 +#, python-format +msgid "Filters out of scope (%d)" +msgstr "Filtri izven dosega (%d)" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:125 -msgid "Symbol of two ends of edge line" -msgstr "Simbol za konca povezave" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:179 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:502 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:519 +msgid "Check configuration" +msgstr "Preveri nastavitve" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:255 -msgid "Symbol size" -msgstr "Velikost simbola" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:257 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1170 +msgid "Cannot load filter" +msgstr "Filtra ni mogoče naložiti" + +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:118 +msgid "Editing filter set:" +msgstr "Urejanje seta filtrov:" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1223 -msgid "Sync columns from source" -msgstr "Sinhroniziraj stolpce z virom" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:142 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:83 +msgid "Filter set with this name already exists" +msgstr "Set filtrov z enakim imenom že obstaja" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:30 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:44 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:62 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:76 -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:89 -msgid "Syntax" -msgstr "Sintaksa" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:143 +msgid "Filter set already exists" +msgstr "Set filtrov že obstaja" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:250 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:305 -msgid "TABLES" -msgstr "TABELE" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:164 +#, python-format +msgid "This filter set is identical to: \"%s\"" +msgstr "Ta set filtrov je enak: \"%s\"" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:85 -msgid "THU" -msgstr "ČET" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:85 +msgid "Remove invalid filters" +msgstr "Odstrani neveljavne filtre" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:83 -msgid "TUE" -msgstr "TOR" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:86 +msgid "Rebuild" +msgstr "Obnovi" -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:218 -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:145 -msgid "Tab name" -msgstr "Naslov zavihka" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:88 +#, python-format +msgid "Filters (%d)" +msgstr "Filtri (%d)" -#: superset-frontend/src/dashboard/util/newComponentFactory.js:56 -#: superset-frontend/src/dashboard/util/newComponentFactory.js:57 -msgid "Tab title" -msgstr "Naslov zavihka" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:109 +msgid "This filter doesn't exist in dashboard. It will not be applied." +msgstr "Ta filter ne obstaja v nadzorni plošči in ne bo uveljavljen." -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:25 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:50 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:35 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:41 -#: superset-frontend/src/components/TableSelector/index.tsx:293 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:24 -#: superset/connectors/sqla/views.py:148 superset/connectors/sqla/views.py:260 -#: superset/connectors/sqla/views.py:488 superset/views/chart/mixin.py:87 -msgid "Table" -msgstr "Tabela" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:113 +msgid "Filter metadata changed in dashboard. It will not be applied." +msgstr "Metapodatki filtra so se spremenili v nadzorni plošči. Ne bo uveljavljen." -#: superset/views/core.py:1761 -#, python-format -msgid "Table %(table)s wasn't found in the database %(db)s" -msgstr "Tabela %(table)s ni bila najdena v podatkovni bazi %(db)s" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:81 +msgid "Please filter set name" +msgstr "Vnesite ime seta filtrov" -#: superset/views/database/forms.py:138 superset/views/database/forms.py:291 -#: superset/views/database/forms.py:419 -msgid "Table Exists" -msgstr "Tabela obstaja" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:96 +msgid "Create" +msgstr "Ustvari" -#: superset/connectors/sqla/views.py:498 superset/views/database/forms.py:95 -#: superset/views/database/forms.py:246 superset/views/database/forms.py:379 -msgid "Table Name" -msgstr "Ime tabele" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:111 +msgid "Create new filter set" +msgstr "Ustvarite nov set filtrov" -#: superset/viz.py:671 -msgid "Table View" -msgstr "Tabelarični pogled" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx:90 +msgid "New filter set" +msgstr "Nov set filtrov" -#: superset/datasets/commands/exceptions.py:130 -#, python-format -msgid "" -"Table [%(table_name)s] could not be found, please double check your " -"database connection, schema, and table name" -msgstr "" -"Tabele [%(table_name)s] ni mogoče najti. Preverite povezavo, shemo in ime" -" podatkovne baze" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:26 +msgid "Please apply filter changes" +msgstr "Potrdite spremembe filtra" -#: superset/views/base.py:251 -msgid "" -"Table [%{table}s] could not be found, please double check your database " -"connection, schema, and table name, error: {}" -msgstr "" -"Tabela [%{table}s] ni najdena. Preverite povezavo, shemo in ime tabele v " -"podatkovni bazi. Napaka: {}" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:43 +msgid "Unknown value" +msgstr "Neznana vrednost" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:257 -msgid "Table cache timeout" -msgstr "Trajanje predpomnilnika tabele" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:104 +msgid "Add/Edit Filters" +msgstr "Dodaj/uredi filter" -#: superset/databases/decorators.py:46 -msgid "Table name undefined" -msgstr "Ime tabele ni definirano" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/DependenciesRow.tsx:86 +msgid "Dependent on" +msgstr "Odvisen od" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:26 -msgid "" -"Table that visualizes paired t-tests, which are used to understand " -"statistical differences between groups." -msgstr "" -"Tabela, ki prikazuje uparjene t-teste, ki se uporabljajo za prikaz " -"statističnih razlik med skupinami." +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/DependenciesRow.tsx:88 +msgid "Filter only displays values relevant to selections made in other filters." +msgstr "Filter prikazuje samo vrednosti vezane na izbire v drugih filtrih." -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:269 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:324 -#: superset/connectors/sqla/views.py:367 superset/connectors/sqla/views.py:395 -msgid "Tables" -msgstr "Tabele" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx:56 +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useFilterScope.ts:70 +#: superset-frontend/src/dashboard/util/getFilterScopeNodesTree.js:85 +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:126 +msgid "All charts" +msgstr "Vsi grafikoni" -#: superset-frontend/src/dashboard/components/gridComponents/new/NewTabs.jsx:31 -msgid "Tabs" -msgstr "Zavihki" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/ScopeRow.tsx:68 +msgid "Scope" +msgstr "Doseg" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 -#: superset-frontend/plugins/plugin-chart-table/src/index.ts:50 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:34 -msgid "Tabular" -msgstr "Tabelarično" +#: superset-frontend/src/dashboard/components/nativeFilters/FilterCard/TypeRow.tsx:31 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:760 +msgid "Filter type" +msgstr "Tip filtra" -#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:607 -msgid "Tags" -msgstr "Značke" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:44 +msgid "Title is required" +msgstr "Naslov je obvezen" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:29 -msgid "" -"Take your data points, and group them into \"bins\" to see where the " -"densest areas of information lie" -msgstr "" -"Vzame podatkovne točke in jih razporedi v razdelke, kjer se vidi območja " -"z največjo gostoto informacij" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx:115 +msgid "(Removed)" +msgstr "(Odstranjeno)" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:62 -msgid "Target" -msgstr "Cilj" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx:131 +msgid "Undo?" +msgstr "Povrni?" -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:67 -msgid "Target aspect ratio for treemap tiles." -msgstr "Ciljno razmerje za razdelke drevesnega grafikona." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitlePane.tsx:109 +msgid "Add filters and dividers" +msgstr "Dodaj filtre in ločilnike" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:86 -msgid "Target category" -msgstr "Kategorija cilja" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx:245 +msgid "[untitled]" +msgstr "[neimenovana]" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:176 -msgid "Target value" -msgstr "Ciljna vrednost" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx:416 +msgid "Cyclic dependency detected" +msgstr "Zaznana krožna odvisnost" -#: superset/views/css_templates.py:44 -msgid "Template Name" -msgstr "Ime predloge" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx:500 +msgid "Add and edit filters" +msgstr "Dodaj in uredi filtre" -#: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:94 -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:788 -#: superset/connectors/sqla/views.py:504 -msgid "Template parameters" -msgstr "Parametri predlog" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:129 +msgid "Column select" +msgstr "Izbira stolpca" -#: superset-frontend/src/explore/controlPanels/TimeTable.js:52 -msgid "" -"Templated link, it's possible to include {{ metric }} or other values " -"coming from the controls." -msgstr "" -"Vzorčna povezava, vključiti je mogoče {{ metric }} ali drugo vrednost iz " -"kontrolnikov." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:132 +msgid "Select a column" +msgstr "Izberite stolpec" -#: superset/models/sql_types/base.py:54 -#, python-format -msgid "Temporal expression not supported for type: %(col_type)s" -msgstr "Časovni izraz ni podprt za podatkovne tipe: %(col_type)s" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:133 +msgid "No compatible columns found" +msgstr "Ni najdenih skladnih stolpcev" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:307 -msgid "" -"Terminate running queries when browser window closed or navigated to " -"another page. Available for Presto, Hive, MySQL, Postgres and Snowflake " -"databases." -msgstr "" -"Ustavi zagnane poizvedbe, ko se zapre okno brskalnika ali gre na drugo " -"stran. na razpolago za Presto, Hive, MySQL, Postgres in Snowflake " -"podatkovne baze." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx:75 +msgid "Value is required" +msgstr "Zahtevana je vrednost" -#: superset/templates/superset/models/database/macros.html:22 -msgid "Test Connection" -msgstr "Preizkusi povezavo" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:92 +msgid "(deleted or invalid type)" +msgstr "(izbrisan ali neveljaven tip)" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:95 -msgid "Test connection" -msgstr "Preizkus povezave" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:98 +msgid "Limit type" +msgstr "Tip omejitve" -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:35 -msgid "Text" -msgstr "Besedilo" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:148 +msgid "No available filters." +msgstr "Ni razpoložljivih filtrov." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:105 -msgid "Text align" -msgstr "Poravnava besedila" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:167 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx:367 +msgid "Add filter" +msgstr "Dodaj filter" -#: superset-frontend/src/components/ReportModal/index.tsx:289 -msgid "Text embedded in email" -msgstr "Besedilo vključeno v e-pošto" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:194 +msgid "Values are dependent on other filters" +msgstr "Vrednosti so odvisne od drugih filtrov" -#: superset/views/dashboard/mixin.py:53 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:197 msgid "" -"The CSS for individual dashboards can be altered here, or in the " -"dashboard view where changes are immediately visible" -msgstr "" -"CSS za posamezne nadzorne plošče lahko spreminjamo tukaj ali pa v pogledu" -" nadzorne plošče, kjer so spremembe vidne takoj" +"Values selected in other filters will affect the filter options to only show " +"relevant values" +msgstr "Vrednosti izbrane v drugih filtrih bodo vplivale na možnosti filtra" -#: superset/errors.py:118 -msgid "" -"The CTAS (create table as select) doesn't have a SELECT statement at the " -"end. Please make sure your query has a SELECT as its last statement. " -"Then, try running your query again." -msgstr "" -"CTAS (create table as select) na koncu nima SELECT stavka. Poskrbite, da " -"bo v poizvedbi SELECT zadnji stavek. Potem ponovno poženite poizvedbo." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DependencyList.tsx:201 +msgid "Values dependent on" +msgstr "Vrednosti so odvisne od" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:921 -msgid "The JSON metric or post aggregation definition." -msgstr "JSON mera ali po-agregacijska definicija." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:268 +msgid "Scoping" +msgstr "Doseg" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:126 -msgid "" -"The URL could not be identified. Please check for typos and make sure " -"that \"Type of google sheet allowed\" selection matches the input" -msgstr "" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:275 +msgid "Filter Configuration" +msgstr "Nastavitve filtra" -#: superset/views/core.py:354 -msgid "The access requests seem to have been deleted" -msgstr "Zdi se, da je bila zahteva za dostop izbrisana" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:279 +msgid "Filter Settings" +msgstr "Nastavitve filtra" -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:168 -msgid "The annotation has been saved" -msgstr "Označba je bila shranjena" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:302 +#: superset-frontend/src/filters/components/Select/index.ts:28 +msgid "Select filter" +msgstr "Izbirni filter" -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:152 -msgid "The annotation has been updated" -msgstr "Označba je bila posodobljena" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:302 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1203 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1224 +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:143 +msgid "Value" +msgstr "Vrednost" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:74 -msgid "" -"The category of source nodes used to assign colors. If a node is " -"associated with more than one category, only the first will be used." -msgstr "" -"Kategorija izvornih vozlišč, na podlagi katere je določena barva. Če je " -"vozlišče povezano z več kot eno kategorijo, bo uporabljena samo prva." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:303 +#: superset-frontend/src/filters/components/Range/index.ts:28 +msgid "Range filter" +msgstr "Filter obdobja" -#: superset/common/query_context_processor.py:449 -msgid "The chart does not exist" -msgstr "Grafikon ne obstaja" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:303 +msgid "Numerical range" +msgstr "Številski obseg" -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:54 -#, fuzzy -msgid "" -"The classic. Great for showing how much of a company each investor gets, " -"what demographics follow your blog, or what portion of the budget goes to" -" the military industrial complex.\n" -"\n" -" Pie charts can be difficult to interpret precisely. If clarity of" -" relative proportion is important, consider using a bar or other chart " -"type instead." -msgstr "" -"Standardni grafikon za prikaz deležev. Tortne grafikone je težje natančno" -" interpretirati, takrat lahko uporabite npr. stolpčni grafikon." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:304 +#: superset-frontend/src/filters/components/Time/index.ts:27 +msgid "Time filter" +msgstr "Časovni filter" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:261 -msgid "The color for points and clusters in RGB" -msgstr "Barva točk in gruč v RGB zapisu" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:304 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:925 +#: superset-frontend/src/explore/constants.ts:119 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:382 +msgid "Time range" +msgstr "Časovno obdobje" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:478 -#: superset-frontend/src/explore/controls.jsx:484 -msgid "The color scheme for rendering chart" -msgstr "Barvna shema za izris grafikona" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:305 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:951 +#: superset-frontend/src/explore/constants.ts:120 +#: superset-frontend/src/filters/components/TimeColumn/index.ts:28 +msgid "Time column" +msgstr "Časovni stolpec" -#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:66 -msgid "" -"The color scheme is determined by the related dashboard.\n" -" Edit the color scheme in the dashboard properties." -msgstr "" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:306 +#: superset-frontend/src/explore/constants.ts:121 +#: superset-frontend/src/filters/components/TimeGrain/index.ts:28 +msgid "Time grain" +msgstr "Granulacija časa" -#: superset/errors.py:99 -msgid "The column was deleted or renamed in the database." -msgstr "Stolpec je bil izbrisan ali preimenovan v podatkovni bazi." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:307 +#: superset-frontend/src/filters/components/GroupBy/index.ts:28 +msgid "Group By" +msgstr "Združevanje (Group by)" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:47 -msgid "" -"The country code standard that Superset should expect to find in the " -"[country] column" -msgstr "Standard za oznake držav, ki bodo podane v stolpcu z državami" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:307 +msgid "Group by" +msgstr "Združevanje (Group by)" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:327 -msgid "The dashboard has been saved" -msgstr "Nadzorna plošča je bila shranjena" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:638 +msgid "Pre-filter is required" +msgstr "Zahtevan je predfilter" -#: superset/views/core.py:182 -msgid "The data source seems to have been deleted" -msgstr "Zdi se, da je bil podatkovni vir izbrisan" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:746 +msgid "Filter name" +msgstr "Ime filtra" -#: superset/connectors/sqla/views.py:103 -msgid "" -"The data type that was inferred by the database. It may be necessary to " -"input a type manually for expression-defined columns in some cases. In " -"most case users should not need to alter this." -msgstr "" -"Podatkovni tip, ki izvira iz podatkovne baze. V nekaterih primerih je " -"potrebno ročno vnesti tip za stolpce, ki temeljijo na izrazih. V večini " -"primerov uporabniku tega ni potrebno spreminjati." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:748 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:754 +msgid "Name is required" +msgstr "Zahtevano je ime" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:756 +msgid "Filter Type" +msgstr "Tip filtra" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:778 +msgid "Datasets do not contain a temporal column" +msgstr "Podatkovni seti ne vsebujejo časovnega stolpca" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:439 -#, python-format -msgid "" -"The database %s is linked to %s charts that appear on %s dashboards and " -"users have %s SQL Lab tabs using this database open. Are you sure you " -"want to continue? Deleting the database will break those objects." -msgstr "" -"Podatkovna baza %s je povezana z grafikoni %s, ki so prisotni na nadzorni" -" plošči %s in uporabniki imajo odprtih %s zavihkov SQL laboratorija. Ali " -"želite nadaljevati? Izbris podatkovne baze bo pokvaril te objekte." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:812 +msgid "Dataset is required" +msgstr "Zahtevan je podatkovni set" -#: superset/errors.py:126 -msgid "The database is currently running too many queries." -msgstr "Podatkovna baza trenutno izvaja preveč poizvedb." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:881 +msgid "Pre-filter available values" +msgstr "Predfiltriraj razpoložljive vrednosti" -#: superset/errors.py:93 -msgid "The database is under an unusual load." -msgstr "Podatkovni vir je neobičajno obremenjen." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:916 +msgid "Pre-filter" +msgstr "Predfilter" -#: superset/sqllab/command.py:149 +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:954 msgid "" -"The database referenced in this query was not found. Please contact an " -"administrator for further assistance or try again." +"Optional time column if time range should apply to another column than the " +"default time column" msgstr "" -"Podatkovna baza, referencirana v tej poizvedbi, ni bila najdena. " -"Kontaktirajte administratorja za napotke ali pa poskusite znova." +"Izbirni časovni stolpec se mora nanašati na drug stolpec kot privzeti časovni " +"stolpec" -#: superset/errors.py:94 -msgid "The database returned an unexpected error." -msgstr "Podatkovna baza je vrnila nepričakovano napako." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:986 +msgid "Sort filter values" +msgstr "Razvrsti vrednosti filtra" -#: superset/errors.py:138 -msgid "The database was deleted." -msgstr "Podatkovna baza je bila izbrisana." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1000 +msgid "Sort type" +msgstr "Način razvrščanja" -#: superset/views/core.py:2085 superset/views/core.py:2155 -msgid "The database was not found." -msgstr "Podatkovna baza ni bila najdena." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1007 +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:205 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:66 +msgid "Sort ascending" +msgstr "Razvrsti naraščajoče" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:592 -#, python-format -msgid "" -"The dataset %s is linked to %s charts that appear on %s dashboards. Are " -"you sure you want to continue? Deleting the dataset will break those " -"objects." -msgstr "" -"Podatkovni set %s je povezan z grafikoni %s, ki so prisotni na nadzorni " -"plošči %s. Ali želite nadaljevati? Izbris podatkovnega seta bo pokvaril " -"te objekte." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1017 +msgid "Sort Metric" +msgstr "Mera za razvrščanje" -#: superset-frontend/src/chart/Chart.jsx:73 superset/views/utils.py:268 -msgid "The dataset associated with this chart no longer exists" -msgstr "Podatkovni set, povezan s tem grafikonom, ne obstaja več" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1020 +msgid "If a metric is specified, sorting will be done based on the metric value" +msgstr "Če je določena mera, bo razvrščanje izvedeno na podlagi vrednosti mere" -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:167 -#, fuzzy -msgid "" -"The dataset configuration exposed here\n" -" affects all the charts using this dataset.\n" -" Be mindful that changing settings\n" -" here may affect other charts\n" -" in undesirable ways." -msgstr "" -"Tukaj prikazane nastavitve podatkovnega seta\r\n" -" vplivajo na vse grafikone, ki uporabljajo\r\n" -" ta podatkovni set. Spreminjanje\r\n" -" nastavitev lahko nezaželeno vpliva\r\n" -" na druge grafikone." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1030 +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:184 +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:188 +msgid "Sort metric" +msgstr "Mera za razvrščanje" -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:128 -#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:109 -msgid "The dataset has been saved" -msgstr "Podatkovni set je shranjen" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1053 +msgid "Single Value" +msgstr "Ena vrednost" -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:256 -msgid "The dataset linked to this chart may have been deleted." -msgstr "Podatkovni set, povezan s tem grafikonom, je bil izbrisan." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1070 +msgid "Single value type" +msgstr "Tip z eno vrednostjo" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:1283 -msgid "The datasource couldn't be loaded" -msgstr "Podatkovnega vira ni mogoče naložiti" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1079 +msgid "Minimum" +msgstr "Minimum" -#: superset/errors.py:92 -msgid "The datasource is too large to query." -msgstr "Podatkovni vir je prevelik za poizvedbo." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1082 +msgid "Exact" +msgstr "Natančno" -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:247 -msgid "" -"The description can be displayed as widget headers in the dashboard view." -" Supports markdown." -msgstr "" -"Opis je lahko prikazan kot glava gradnika in pogledu nadzorne plošče. " -"Podpira markdown." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1085 +msgid "Maximum" +msgstr "Maksimum" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:104 -msgid "The distance between cells, in pixels" -msgstr "Razdalja med celicami v pikslih" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1116 +msgid "Filter has default value" +msgstr "Filter ima privzeto vrednost" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:772 -msgid "The duration of time in seconds before the cache is invalidated" -msgstr "Trajanje (v sekundah) do razveljavitve predpomnilnika" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1133 +msgid "Default Value" +msgstr "Privzeta vrednost" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:474 -msgid "" -"The engine_params object gets unpacked into the sqlalchemy.create_engine " -"call." -msgstr "Objekt engine_params se razširi v klic sqlalchemy.create_engine." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1162 +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:223 +msgid "Default value is required" +msgstr "Zahtevana je privzeta vrednost" -#: superset/common/query_object.py:295 -#, python-format -msgid "" -"The following entries in `series_columns` are missing in `columns`: " -"%(columns)s. " -msgstr "V 'columns' manjkajo naslednji vnosi iz 'series_columns': %(columns)s. " +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1202 +msgid "Refresh the default values" +msgstr "Osveži privzete vrednosti" -#: superset/connectors/sqla/views.py:612 -#, python-format -msgid "The following tables added new columns: %(tables)s" -msgstr "Nove stolpce so dodale naslednje tabele: %(tables)s" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1208 +msgid "Fill all required fields to enable \"Default Value\"" +msgstr "Izpolnite vsa polja, da omogočite \"Privzeto vrednost\"" -#: superset/connectors/sqla/views.py:623 -#, python-format -msgid "The following tables removed columns: %(tables)s" -msgstr "Stolpce so odstranile naslednje tabele: %(tables)s" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/RemovedFilter.tsx:39 +msgid "You have removed this filter." +msgstr "Odstranili ste ta filter." -#: superset/connectors/sqla/views.py:634 -#, python-format -msgid "The following tables update column metadata: %(tables)s" -msgstr "Metapodatke stolpcev so posodobile naslednje tabele: %(tables)s" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/RemovedFilter.tsx:46 +msgid "Restore Filter" +msgstr "Povrni filter" -#: superset/db_engine_specs/mysql.py:134 -#, python-format -msgid "The host \"%(hostname)s\" might be down and can't be reached." -msgstr "Gostitelj \"%(hostname)s\" mogoče ne deluje in ga ni mogoče doseči." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:118 +msgid "Column is required" +msgstr "Zahtevan je stolpec" -#: superset/db_engine_specs/mssql.py:92 -#: superset/db_engine_specs/postgres.py:137 -#: superset/db_engine_specs/presto.py:205 -#: superset/db_engine_specs/redshift.py:78 -#, python-format +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:173 +msgid "Populate \"Default value\" to enable this control" +msgstr "Izpolnite \"Privzeto vrednost\", da omogočite ta kontrolnik" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:88 msgid "" -"The host \"%(hostname)s\" might be down, and can't be reached on port " -"%(port)s." +"Default value set automatically when \"Select first filter value by default\" is " +"checked" msgstr "" -"Gostitelj \"%(hostname)s\" mogoče ne deluje in ga ni mogoče doseči na " -"vratih %(port)s." +"Privzeta vrednost je samodejno izbrana, če je izbrano \"Prvi element je izbran " +"kot privzet\"" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:98 -msgid "The host is invalid. Please verify that this field is entered correctly." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:92 +msgid "Default value must be set when \"Filter value is required\" is checked" msgstr "" +"Privzeta vrednost mora biti določena, če je izbrano \"Vrednost filtra obvezna\"" -#: superset/errors.py:104 -msgid "The host might be down, and can't be reached on the provided port." -msgstr "Gostitelj mogoče ne deluje in ga ni mogoče doseči preko podanih vrat." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:96 +msgid "Default value must be set when \"Filter has default value\" is checked" +msgstr "" +"Privzeta vrednost mora biti določena, če je izbrano \"Filter ima privzeto vrednost" +"\"" -#: superset/db_engine_specs/mssql.py:82 -#: superset/db_engine_specs/postgres.py:127 -#: superset/db_engine_specs/presto.py:200 -#: superset/db_engine_specs/redshift.py:68 -#, python-format -msgid "The hostname \"%(hostname)s\" cannot be resolved." -msgstr "Imena gostitelja \"%(hostname)s\" ni mogoče razrešiti." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:122 +msgid "Apply to all panels" +msgstr "Uporabi za vse panele" -#: superset/errors.py:102 -msgid "The hostname provided can't be resolved." -msgstr "Imena gostitelja ni mogoče razrešiti." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:124 +msgid "Apply to specific panels" +msgstr "Uporabi za določene panele" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:60 -#: superset-frontend/src/explore/controlPanels/sections.tsx:44 -msgid "The id of the active chart" -msgstr "Identifikator aktivnega grafikona" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:130 +msgid "Only selected panels will be affected by this filter" +msgstr "Ta filter bo vplival le na izbrane panele" -#: superset-frontend/src/components/ImportModal/index.tsx:187 -msgid "The import was successful" -msgstr "Uvoz je uspel" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:131 +msgid "All panels with this column will be affected by this filter" +msgstr "Ta filter bo vplival na vse panele s tem stolpcem" -#: superset/connectors/druid/views.py:303 superset/connectors/sqla/views.py:429 -msgid "" -"The list of charts associated with this table. By altering this " -"datasource, you may change how these associated charts behave. Also note " -"that charts need to point to a datasource, so this form will fail at " -"saving if removing charts from a datasource. If you want to change the " -"datasource for a chart, overwrite the chart from the 'explore view'" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/state.ts:49 +msgid "All panels" +msgstr "Vsi paneli" + +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.ts:55 +msgid "This chart might be incompatible with the filter (datasets don't match)" msgstr "" -"Seznam grafikonov, povezanih s to tabelo. S spreminjanjem podatkovnega " -"vira lahko spremenite, kako se povezani grafikoni obnašajo. Poleg tega " -"morajo biti grafikoni povezani s podatkovnim virom. Če odstranite " -"grafikon s podatkovnega vira ne bo mogoče shraniti tega vnosa. Če želite " -"spremeniti podatkovni vir grafikona, prepišite grafikon v raziskovalnem " -"pogledu." +"Ta grafikon je lahko nekompatibilen s filtrom (podatkovni seti se ne ujemajo)" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:130 -msgid "The maximum number of events to return, equivalent to the number of rows" -msgstr "Največje število dogodkov, ki bodo vrnjeni - enako številu vrstic" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx:56 +msgid "Keep editing" +msgstr "Nadaljuj z urejanjem" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:179 -msgid "" -"The maximum number of subdivisions of each group; lower values are pruned" -" first" -msgstr "" -"Največje število podrazdelkov posamezne skupine; nižje vrednosti so " -"zanemarjene prve" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx:64 +msgid "Yes, cancel" +msgstr "Da, prekini" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:49 -msgid "The maximum value of metrics. It is an optional configuration" -msgstr "Največja vrednost mere. To je opcijska nastavitev" +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:45 +msgid "There are unsaved changes." +msgstr "Imate neshranjene spremembe." -#: superset/databases/schemas.py:206 -#, python-format -msgid "" -"The metadata_params in Extra field is not configured correctly. The key " -"%(key)s is invalid." -msgstr "" -"Metadata_params v polju Dodatno niso pravilno nastavljeni. Ključ %(key)s " -"je neveljaven." +#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:49 +msgid "Are you sure you want to cancel?" +msgstr "Ali želite prekiniti?" -#: superset/databases/commands/exceptions.py:79 -#: superset/views/database/mixins.py:252 -msgid "" -"The metadata_params in Extra field is not configured correctly. The key " -"%{key}s is invalid." +#: superset-frontend/src/dashboard/containers/DashboardPage.tsx:257 +msgid "Error loading chart datasources. Filters may not work correctly." msgstr "" -"Metadata_params v polju Dodatno niso pravilno nastavljeni. Ključ %{key}s " -"je neveljaven." +"Napaka pri nalaganju podatkovnih virov grafikona. Filtri lahko ne delujejo " +"pravilno." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:452 -msgid "" -"The metadata_params object gets unpacked into the sqlalchemy.MetaData " -"call." -msgstr "Objekt metadata_params se razpakira v klic sqlalchemy.MetaData." +#: superset-frontend/src/dashboard/util/backgroundStyleOptions.ts:25 +msgid "Transparent" +msgstr "Prozorno" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:75 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:292 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:175 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:195 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:426 -#: superset-frontend/src/explore/controlPanels/sections.tsx:191 -msgid "" -"The minimum number of rolling periods required to show a value. For " -"instance if you do a cumulative sum on 7 days you may want your \"Min " -"Period\" to be 7, so that all data points shown are the total of 7 " -"periods. This will hide the \"ramp up\" taking place over the first 7 " -"periods" -msgstr "" -"Minimalno število drsečih obdobij, potrebnih za prikaz vrednosti. Če " -"računate kumulativno vsoto 7-dnevnega obdobja, boste nastavili \"Min. št." -" period\" na 7. Tako bodo vse prikazane točke skupaj obsegale 7 obdobij. " -"To bo prikrilo rampo, ki bi trajala prvih 7 obdobij" +#: superset-frontend/src/dashboard/util/backgroundStyleOptions.ts:30 +msgid "White" +msgstr "Belo" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:130 -msgid "The number color \"steps\"" -msgstr "Število barvnih korakov" +#: superset-frontend/src/dashboard/util/getFilterFieldNodesTree.js:44 +msgid "All filters" +msgstr "Vsi filtri" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:781 -msgid "" -"The number of hours, negative or positive, to shift the time column. This" -" can be used to move UTC time to local time." -msgstr "" -"Število ur, negativno ali pozitivno, za zamik časovnega stolpca. Na ta " -"način je mogoče UTC čas prestaviti na lokalni čas." +#: superset-frontend/src/dashboard/util/headerStyleOptions.ts:30 +msgid "Medium" +msgstr "Srednje" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:583 -#, python-format -msgid "" -"The number of results displayed is limited to %(rows)d by the " -"configuration DISPLAY_MAX_ROWS. Please add additional limits/filters or " -"download to csv to see more rows up to the %(limit)d limit." -msgstr "" +#: superset-frontend/src/dashboard/util/newComponentFactory.js:58 +#: superset-frontend/src/dashboard/util/newComponentFactory.js:59 +msgid "Tab title" +msgstr "Naslov zavihka" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:589 -#, python-format +#: superset-frontend/src/embedded/index.tsx:107 msgid "" -"The number of results displayed is limited to %(rows)d. Please add " -"additional limits/filters, download to csv, or contact an admin to see " -"more rows up to the %(limit)d limit." +"This session has encountered an interruption, and some controls may not work as " +"intended. If you are the developer of this app, please check that the guest token " +"is being generated correctly." msgstr "" +"Ta seja je bila prekinjena in nekateri kontrolniki mogoče ne delujejo kot bi " +"morali. Če ste razvijalec te aplikacije, preverite, da je žeton za gosta pravilno " +"generiran." -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:615 -#, python-format -msgid "The number of rows displayed is limited to %(rows)d by the limit dropdown." -msgstr "Število prikazanih rezultatov je omejeno na %(rows)d s poizvedbo." +#: superset-frontend/src/explore/constants.ts:123 +msgid "Time granularity" +msgstr "Granulacija časa" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:603 -#, python-format -msgid "The number of rows displayed is limited to %(rows)d by the query" -msgstr "Število prikazanih vrstic je omejeno na %(rows)d s poizvedbo" +#: superset-frontend/src/explore/controlPanels/sections.tsx:32 +#: superset-frontend/src/explore/controls.jsx:200 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:298 +msgid "Visualization type" +msgstr "Tip vizualizacije" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:624 -#, python-format +#: superset-frontend/src/explore/controls.jsx:206 +msgid "Fixed color" +msgstr "Izbrana barva" + +#: superset-frontend/src/explore/controls.jsx:215 +msgid "Right axis metric" +msgstr "Mera desne osi" + +#: superset-frontend/src/explore/controls.jsx:222 +msgid "Linear color scheme" +msgstr "Linearna barvna shema" + +#: superset-frontend/src/explore/controls.jsx:235 +msgid "Color metric" +msgstr "P" + +#: superset-frontend/src/explore/controls.jsx:246 +msgid "One or many controls to pivot as columns" +msgstr "En ali več kontrolnikov za stolpčno vrtenje" + +#: superset-frontend/src/explore/controls.jsx:431 +msgid "Bubble size" +msgstr "Velikost mehurčka" + +#: superset-frontend/src/explore/controls.jsx:450 msgid "" -"The number of rows displayed is limited to %(rows)d by the query and " -"limit dropdown." +"When `Calculation type` is set to \"Percentage change\", the Y Axis Format is " +"forced to `.1%`" msgstr "" -"Število prikazanih vrstic je omejeno na %(rows)d s poizvedbo in spustnim " -"izbirnikom omejitev." +"Če je `Vrsta izračuna` nastavljena na \"Procentualna sprememba\", bo oblika Y-osi " +"vsiljena na `.1%`" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:644 -#, python-format -msgid "The number of rows displayed is limited to %s by the dropdown." -msgstr "Število prikazanih vrstic je omejeno na %s s spustnim izbirnikom." +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:50 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:214 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:218 +#: superset-frontend/src/explore/controlPanels/sections.tsx:70 +#: superset-frontend/src/explore/controls.jsx:476 +msgid "Color scheme" +msgstr "Barvna shema" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:69 -#: superset-frontend/src/explore/controlPanels/sections.tsx:53 -msgid "The number of seconds before expiring the cache" -msgstr "Trajanje (v sekundah) do razveljavitve predpomnilnika" +#: superset-frontend/src/explore/actions/exploreActions.ts:95 +msgid "An error occurred while starring this chart" +msgstr "Pri ocenjevanju grafikona je prišlo do napake" -#: superset/errors.py:128 -msgid "The object does not exist in the given database." -msgstr "Objekt ne obstaja v podani podatkovni bazi." +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:38 +msgid "GROUP BY" +msgstr "GROUP BY" -#: superset/sqllab/query_render.py:97 -#, python-format -msgid "The parameter %(parameters)s in your query is undefined." -msgid_plural "The following parameters in your query are undefined: %(parameters)s." -msgstr[0] "V vaši poizvedbi ni definiranih naslednjih parametrov: %(parameters)s." -msgstr[1] "V vaši poizvedbi ni definiranih naslednjih parametrov: %(parameters)s." -msgstr[2] "V vaši poizvedbi ni definiranih naslednjih parametrov: %(parameters)s." -msgstr[3] "V vaši poizvedbi ni definiranih naslednjih parametrov: %(parameters)s." +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:39 +msgid "Use this section if you want a query that aggregates" +msgstr "Ta sklop uporabite če želite poizvedbo za agregacijo" -#: superset/db_engine_specs/postgres.py:117 -#, python-format -msgid "The password provided for username \"%(username)s\" is incorrect." -msgstr "Geslo za uporabniško ime \"%(username)s\" je napačno." +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:52 +msgid "NOT GROUPED BY" +msgstr "NOT GROUPED BY" -#: superset/errors.py:108 -msgid "The password provided when connecting to a database is not valid." -msgstr "Geslo za povezavo s podatkovno bazo je neveljavno." +#: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:53 +msgid "Use this section if you want to query atomic rows" +msgstr "Ta sklop uporabite, če želite poizvedbo za posamezne vrstice" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:65 -msgid "" -"The passwords for the databases below are needed in order to import them " -"together with the charts. Please note that the \"Secure Extra\" and " -"\"Certificate\" sections of the database configuration are not present in" -" export files, and should be added manually after the import if they are " -"needed." -msgstr "" -"Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj z grafikoni. " -"Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne " -"baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno" -" po uvozu, če je to potrebno." +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:465 +msgid "Keep control settings?" +msgstr "Obdržim nastavitve kontrolnika?" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:57 +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:466 msgid "" -"The passwords for the databases below are needed in order to import them " -"together with the dashboards. Please note that the \"Secure Extra\" and " -"\"Certificate\" sections of the database configuration are not present in" -" export files, and should be added manually after the import if they are " -"needed." +"You've changed datasets. Any controls with data (columns, metrics) that match " +"this new dataset have been retained." msgstr "" -"Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj z nadzornimi " -"ploščami. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah " -"podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno " -"dodati ročno po uvozu, če je to potrebno." +"Spremenili ste podatkovne sete. Vsi kontrolniki nad podatki (stolpci, mere), ki " +"se ujemajo z novim podatkovnim setom, se bodo ohranili." -#: superset-frontend/src/views/CRUD/data/dataset/constants.ts:23 -msgid "" -"The passwords for the databases below are needed in order to import them " -"together with the datasets. Please note that the \"Secure Extra\" and " -"\"Certificate\" sections of the database configuration are not present in" -" export files, and should be added manually after the import if they are " -"needed." -msgstr "" -"Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj s " -"podatkovnimi seti. Sekciji \"Dodatna varnost\" in \"Certifikati\" v " -"nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih " -"je potrebno dodati ročno po uvozu, če je to potrebno." +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:471 +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:482 +msgid "Continue" +msgstr "Nadaljuj" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:56 -msgid "" -"The passwords for the databases below are needed in order to import them " -"together with the saved queries. Please note that the \"Secure Extra\" " -"and \"Certificate\" sections of the database configuration are not " -"present in export files, and should be added manually after the import if" -" they are needed." -msgstr "" -"Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj s shranjenimi" -" poizvedbami. Sekciji \"Dodatna varnost\" in \"Certifikati\" v " -"nastavitvah podatkovne baze nista prisotni v izvoženih datotekah in jih " -"je potrebno dodati ročno po uvozu, če je to potrebno." +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:472 +msgid "Clear form" +msgstr "Počisti polja" + +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:477 +msgid "No form settings were maintained" +msgstr "Nastavitve forme se niso ohranile" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:39 +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:478 msgid "" -"The passwords for the databases below are needed in order to import them." -" Please note that the \"Secure Extra\" and \"Certificate\" sections of " -"the database configuration are not present in export files, and should be" -" added manually after the import if they are needed." -msgstr "" -"Gesla za spodnje podatkovne baze so potrebna za njihov uvoz. Sekciji " -"\"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze " -"nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po " -"uvozu, če je to potrebno." +"We were unable to carry over any controls when switching to this new dataset." +msgstr "Prenos kontrolnikov pri preklopu na nov podatkovni set ni bil uspešen." -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:231 -msgid "The pattern of timestamp format. For strings use " -msgstr "Vzorec zapisa časovne značke. Za znakovne nize uporabite " +#: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:544 +msgid "Customize" +msgstr "Prilagodi" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:65 -#, fuzzy -msgid "" -"The periodicity over which to pivot time. Users can provide\n" -" \"Pandas\" offset alias.\n" -" Click on the info bubble for more details on accepted " -"\"freq\" expressions." -msgstr "" -"Periodičnost za vrtenje časa. Uporabnik lahko poda\n" -" psevdonim za zamik v \"Pandas\".\n" -" Kliknite na mehurček za podrobnosti dovoljenih izrazov za " -"\"freq\"." +#: superset-frontend/src/explore/components/EmbedCodeContent.jsx:57 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:55 +msgid "Error" +msgstr "Napaka" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:118 -msgid "The pixel radius" -msgstr "Polmer piksla" +#: superset-frontend/src/explore/components/EmbedCodeContent.jsx:82 +msgid "Generating link, please wait.." +msgstr "Ustvarjam povezavo, prosim počakajte..." + +#: superset-frontend/src/explore/components/EmbedCodeContent.jsx:130 +msgid "Chart height" +msgstr "Višina grafikona" + +#: superset-frontend/src/explore/components/EmbedCodeContent.jsx:139 +msgid "Chart width" +msgstr "Širina grafikona" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:977 +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:293 +msgid "Required control values have been removed" +msgstr "Zahtevane kontrolne vrednosti so bile odstranjene" + +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:294 +msgid "Your chart is not up to date" +msgstr "Grafikon ni aktualen" + +#: superset-frontend/src/explore/components/ExploreChartPanel.jsx:301 msgid "" -"The pointer to a physical table (or view). Keep in mind that the chart is" -" associated to this Superset logical table, and this logical table points" -" the physical table referenced here." +"You updated the values in the control panel, but the chart was not updated " +"automatically. Run the query by clicking on the \"Update chart\" button or" msgstr "" -"Kazalec na fizično tabelo (ali pogled). Grafikon je povezan s to " -"Supersetovo logično tabelo, ki kaže na tukaj referencirano fizično " -"tabelo." +"Posodobili ste vrednosti v kontrolni plošči, vendar se grafikon ni samodejno " +"posodobil. Zaženite poizvedbo z gumbom \"Posodobi grafikon\" ali" -#: superset/errors.py:103 -msgid "The port is closed." -msgstr "Vrata so zaprta." +#: superset-frontend/src/explore/components/SaveModal.tsx:35 +msgid "**Select** a dashboard OR **create** a new one" +msgstr "**Izberite** nadzorno ploščo ALI **ustvarite** novo" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:108 -#, fuzzy -msgid "The port must be a whole number less than or equal to 65535." -msgstr "`row_limit` mora biti večja ali enaka 0" +#: superset-frontend/src/explore/components/SaveModal.tsx:141 +msgid "Please enter a chart name" +msgstr "Vnesite ime grafikona" -#: superset/errors.py:136 -msgid "The port number is invalid." -msgstr "Številka vrat je neveljavna." +#: superset-frontend/src/explore/components/SaveModal.tsx:184 +msgid "Save chart" +msgstr "Shrani grafikon" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:57 -msgid "The primary metric is used to define the arc segment sizes" -msgstr "Primarna mera določa velikost lokov segmentov" +#: superset-frontend/src/explore/components/SaveModal.tsx:204 +msgid "Save & go to new dashboard" +msgstr "Shrani in pojdi na novo nadzorno ploščo" -#: superset/views/core.py:2330 -msgid "The provided `rows` argument is not a valid integer." -msgstr "Podani argument `rows` ni veljavno celo število." +#: superset-frontend/src/explore/components/SaveModal.tsx:205 +msgid "Save & go to dashboard" +msgstr "Shrani in pojdi na nadzorno ploščo" -#: superset/errors.py:131 -msgid "The query associated with the results was deleted." -msgstr "Poizvedba, povezana z rezultati, je bila izbrisana." +#: superset-frontend/src/explore/components/SaveModal.tsx:216 +msgid "Save as new chart" +msgstr "Shrani kot nov grafikon" -#: superset/views/core.py:2280 -msgid "" -"The query associated with these results could not be find. You need to " -"re-run the original query." -msgstr "" -"Poizvedbe, povezane s temi rezultati, ni bilo mogoče najti. Ponovno " -"morate zagnati izvorno poizvedbo." +#: superset-frontend/src/explore/components/SaveModal.tsx:218 +msgid "Save to new dashboard" +msgstr "Shrani v novo nadzorno ploščo" -#: superset/sqllab/query_render.py:113 -msgid "The query contains one or more malformed template parameters." -msgstr "Poizvedba vsebuje enega ali več parametrov predlog z napačno obliko." +#: superset-frontend/src/explore/components/SaveModal.tsx:251 +msgid "Save (Overwrite)" +msgstr "Shrani (prepiši)" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:106 -msgid "The query couldn't be loaded" -msgstr "Poizvedbe ni mogoče naložiti" +#: superset-frontend/src/explore/components/SaveModal.tsx:259 +msgid "Save as..." +msgstr "Shrani kot ..." -#: superset/errors.py:129 -msgid "The query has a syntax error." -msgstr "Poizvedba ima sintaktično napako." +#: superset-frontend/src/explore/components/SaveModal.tsx:263 +msgid "Chart name" +msgstr "Ime grafikona" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:771 -msgid "The query returned no data" -msgstr "Poizvedba ni vrnila podatkov" +#: superset-frontend/src/explore/components/SaveModal.tsx:274 +msgid "Add to dashboard" +msgstr "Dodaj na nadzorno ploščo" -#: superset/sql_lab.py:265 -#, python-format -msgid "" -"The query was killed after %(sqllab_timeout)s seconds. It might be too " -"complex, or the database might be under heavy load." -msgstr "" -"Poizvedba je bila ustavljena po %(sqllab_timeout)s sekundah. Lahko je " -"prekompleksna ali pa je podatkovna baza preobremenjena." +#: superset-frontend/src/explore/components/SaveModal.tsx:280 +msgid "Select a dashboard" +msgstr "Izberite nadzorno ploščo" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:87 -msgid "" -"The radius (in pixels) the algorithm uses to define a cluster. Choose 0 " -"to turn off clustering, but beware that a large number of points (>1000) " -"will cause lag." -msgstr "" -"Radij (v pikslih), s katerim algoritem definira gručo. Izberite 0 za " -"izklop gručenja - veliko število točk (>1000) bo povzročilo upočasnitev." +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:84 +msgid "Copy" +msgstr "Kopiraj" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:110 -msgid "" -"The radius of individual points (ones that are not in a cluster). Either " -"a numerical column or `Auto`, which scales the point based on the largest" -" cluster" -msgstr "" -"Radij posameznih točk (tistih, ki niso v gruči). Numerični stolpec ali " -"`Auto` (skalira točke na osnovi največje gruče)" +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:142 +msgid "Formatted date" +msgstr "Oblikovan datum" -#: superset-frontend/src/reports/actions/reports.js:111 -msgid "The report has been created" -msgstr "Poročilo je bilo ustvarjeno" +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:194 +msgid "Column Formatting" +msgstr "Oblikovanje stolpca" -#: superset/errors.py:130 -msgid "The results backend no longer has the data from the query." -msgstr "Zaledni sistem rezultatov nima več podatkov iz poizvedbe." +#: superset-frontend/src/explore/components/DataTableControl/index.tsx:239 +msgid "N/A" +msgstr "N/A" -#: superset/errors.py:132 -msgid "" -"The results stored in the backend were stored in a different format, and " -"no longer can be deserialized." -msgstr "" -"Rezultati v zalednem sistemu so bili shranjeni v drugačni obliki in jih " -"ni več mogoče deserializirati." +#: superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:158 +msgid "Collapse data panel" +msgstr "Skrij podatkovni panel" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:233 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:103 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:284 -msgid "The rich tooltip shows a list of all series for that point in time" -msgstr "" -"Podroben opis orodja prikaže seznam vseh podatkovnih serij za posamezno " -"časovno točko" +#: superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:163 +msgid "Expand data panel" +msgstr "Razširi podatkovni panel" -#: superset/db_engine_specs/bigquery.py:171 +#: superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:208 +#: superset-frontend/src/explore/components/DataTablesPane/components/ResultsPaneOnDashboard.tsx:60 #, python-format -msgid "" -"The schema \"%(schema)s\" does not exist. A valid schema must be used to " -"run this query." -msgstr "" -"Shema \"%(schema)s\" ne obstaja. Za poizvedbo mora biti uporabljena " -"veljavna shema." +msgid "Results %s" +msgstr "Rezultati %s" -#: superset/db_engine_specs/presto.py:187 -#, python-format -msgid "" -"The schema \"%(schema_name)s\" does not exist. A valid schema must be " -"used to run this query." -msgstr "" -"Shema \"%(schema_name)s\" ne obstaja. Za poizvedbo mora biti uporabljena " -"veljavna shema." +#: superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:227 +msgid "Samples" +msgstr "Vzorci" -#: superset/errors.py:111 -msgid "The schema was deleted or renamed in the database." -msgstr "Shema je bila izbrisana ali preimenovana v podatkovni bazi." +#: superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx:119 +msgid "No samples were returned for this dataset" +msgstr "Za podatkovni set ni vrnjenih vzorcev" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:92 -msgid "The size of the square cell, in pixels" -msgstr "Velikost kvadratne celice v pikslih" +#: superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx:137 +#: superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx:64 +msgid "No results" +msgstr "Ni rezultatov" -#: superset/errors.py:114 -msgid "The submitted payload has the incorrect format." -msgstr "Podani podatki so v neustrezni obliki." +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:321 +msgid "Search Metrics & Columns" +msgstr "Iskanje mer in stolpcev" -#: superset/errors.py:115 -msgid "The submitted payload has the incorrect schema." -msgstr "Podani podatki imajo neustrezno shemo." +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:339 +msgid "Create a dataset" +msgstr "Ustvarite podatkovni set" -#: superset/db_engine_specs/bigquery.py:158 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:341 #, python-format -msgid "" -"The table \"%(table)s\" does not exist. A valid table must be used to run" -" this query." -msgstr "" -"Tabela \"%(table)s\" ne obstaja. V poizvedbi mora biti uporabljena " -"veljavna tabela." +msgid " to edit or add columns and metrics." +msgstr " za urejanje ali dodajanje stolpcev in mer." -#: superset/db_engine_specs/presto.py:179 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:357 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:393 #, python-format -msgid "" -"The table \"%(table_name)s\" does not exist. A valid table must be used " -"to run this query." -msgstr "" -"Tabela \"%(table_name)s\" ne obstaja. V poizvedbi mora biti uporabljena " -"veljavna tabela." +msgid "Showing %s of %s" +msgstr "Prikazanih %s od %s" -#: superset/connectors/sqla/views.py:540 -msgid "" -"The table was created. As part of this two-phase configuration process, " -"you should now click the edit button by the new table to configure it." -msgstr "" -"Tabela je ustvarjena. Sedaj morate v tem dvodelnem postopku klikniti gumb" -" za urejanje nove tabele." +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:381 +msgid "Show less..." +msgstr "Prikaži manj..." -#: superset/errors.py:100 -msgid "The table was deleted or renamed in the database." -msgstr "Tabela je bila izbrisana ali preimenovana v podatkovni bazi." +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:381 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:417 +msgid "Show all..." +msgstr "Prikaži vse..." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:167 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:266 -#: superset-frontend/src/explore/controls.jsx:297 +#: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:417 +msgid "Show Less..." +msgstr "Prikaži manj..." + +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:156 +msgid "Add the name of the chart" +msgstr "Dodajte naslov grafikona" + +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:157 +msgid "Chart title" +msgstr "Naslov grafikona" + +#: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:188 +msgid "Add required control values to save chart" +msgstr "Dodaj potrebne parametre za shranjenje grafikona" + +#: superset-frontend/src/explore/components/ExploreViewContainer/index.jsx:499 +msgid "Controls labeled " +msgstr "Kontrolniki imenovani " + +#: superset-frontend/src/explore/components/ExploreViewContainer/index.jsx:499 +msgid "Control labeled " +msgstr "Nastavitev " + +#: superset-frontend/src/explore/components/ExploreViewContainer/index.jsx:637 +msgid "Open Datasource tab" +msgstr "Odpri zavihek s podatkovnim virom" + +#: superset-frontend/src/explore/components/ExportToCSVDropdown/index.tsx:75 +msgid "Original" +msgstr "Izvoren" + +#: superset-frontend/src/explore/components/ExportToCSVDropdown/index.tsx:81 +msgid "Pivoted" +msgstr "Vrtilni" + +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:69 +msgid "You do not have permission to edit this chart" +msgstr "Nimate dovoljenja za urejanje tega grafikona" + +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:164 +msgid "Chart properties updated" +msgstr "Lastnosti grafikona posodobljene" + +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:210 +msgid "This chart is managed externally, and can't be edited in Superset" +msgstr "Ta grafikon se ne ureja znotraj Superseta" + +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:259 msgid "" -"The time column for the visualization. Note that you can define arbitrary" -" expression that return a DATETIME column in the table. Also note that " -"the filter below is applied against this column or expression" +"The description can be displayed as widget headers in the dashboard view. " +"Supports markdown." msgstr "" -"Časovni stolpec za vizualizacijo. Določite lahko poljuben izraz, ki vrne " -"DATETIME stolpec v tabeli. Spodnji filter se nanaša na ta stolpec ali " -"izraz" +"Opis je lahko prikazan kot glava gradnika in pogledu nadzorne plošče. Podpira " +"markdown." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:256 -#: superset-frontend/src/explore/controls.jsx:287 +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:270 +msgid "Person or group that has certified this chart." +msgstr "Oseba ali skupina, ki je certificirala ta grafikon." + +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:288 +msgid "Configuration" +msgstr "Nastavitve" + +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:294 msgid "" -"The time granularity for the visualization. Note that you can type and " -"use simple natural language as in `10 seconds`, `1 day` or `56 weeks`" +"Duration (in seconds) of the caching timeout for this chart. Note this defaults " +"to the dataset's timeout if undefined." msgstr "" -"Granulacija časa za vizualizacijo. Uporabite lahko vnos z naravnim " -"jezikom, kot npr. `10 sekund`, `1 dni` ali `56 tednov`" +"Časovna veljavnost (v sekundah) predpomnjenja za ta grafikon. Če ni definirana, " +"je uporabljena vrednost za podatkovni set." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:297 -#: superset-frontend/src/explore/controls.jsx:326 -msgid "" -"The time granularity for the visualization. This applies a date " -"transformation to alter your time column and defines a new time " -"granularity. The options here are defined on a per database engine basis " -"in the Superset source code." +#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:312 +msgid "A list of users who can alter the chart. Searchable by name or username." msgstr "" -"Granulacija časa za to vizualizacijo. Izvede transformacijo podatkov, ki " -"spremeni vaš časovni stolpec in določi novo časovno granulacija. Ta " -"možnost je definirana na ravni sistema podatkovne baze v izvorni kodi " -"Superseta." +"Seznam uporabnikov, ki lahko spreminjajo ta grafikon. Možno je iskanje po imenu " +"ali uporabniškem imenu." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:314 -#: superset-frontend/src/explore/controls.jsx:343 -msgid "" -"The time range for the visualization. All relative times, e.g. \"Last " -"month\", \"Last 7 days\", \"now\", etc. are evaluated on the server using" -" the server's local time (sans timezone). All tooltips and placeholder " -"times are expressed in UTC (sans timezone). The timestamps are then " -"evaluated by the database using the engine's local timezone. Note one can" -" explicitly set the timezone per the ISO 8601 format if specifying either" -" the start and/or end time." -msgstr "" -"Časovno obdobje za vizualizacijo. Vsi relativni časi, kot npr. \"Zadnji " -"mesec\", Zadnjih 7 dni\", \"Zdaj\" so izračunani na strežniku z njegovim " -"lokalnim časom. Vsi opisi orodij in časi so izraženi v UTC. Časovne " -"značke se nato izračunajo v podatkovni bazi z njenim lokalnim časovnim " -"pasom. Eksplicitno lahko nastavite časovni pas v ISO 8601 formatu, če " -"določite čas začetka ali konca." +#: superset-frontend/src/explore/components/RowCountLabel/index.tsx:41 +#, python-format +msgid "%s row" +msgstr "%s vrstica" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:65 -msgid "" -"The time unit for each block. Should be a smaller unit than " -"domain_granularity. Should be larger or equal to Time Grain" -msgstr "" -"Časovna enota za vsak blok. Mora biti manjša enota kot " -"domenska_granulacija. Mora biti večja ali enaka Granulaciji časa" +#: superset-frontend/src/explore/components/RowCountLabel/index.tsx:45 +msgid "Limit reached" +msgstr "Omejitev dosežena" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:49 -msgid "The time unit used for the grouping of blocks" -msgstr "Časovna enota za združevanje blokov" +#: superset-frontend/src/explore/components/RunQueryButton/index.tsx:54 +msgid "Create chart" +msgstr "Ustvari grafikon" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:170 -#: superset-frontend/src/explore/controls.jsx:202 -msgid "The type of visualization to display" -msgstr "Tip vizualizacije za prikaz" +#: superset-frontend/src/explore/components/RunQueryButton/index.tsx:54 +msgid "Update chart" +msgstr "Posodobi grafikon" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:135 -msgid "The unit of measure for the specified point radius" -msgstr "Enota merila za definiran radij točk" +#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:82 +msgid "Invalid lat/long configuration." +msgstr "Neveljavna nastavitev zemljepisne dolžine/širine." -#: superset/views/core.py:183 -msgid "The user seems to have been deleted" -msgstr "Zdi se, da je bil uporabnik izbrisan" +#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:155 +msgid "Reverse lat/long " +msgstr "Zamenjaj zemljepisno dolžino/širino " -#: superset/db_engine_specs/postgres.py:112 -#, python-format -msgid "The username \"%(username)s\" does not exist." -msgstr "Uporabniško ime \"%(username)s\" ne obstaja." +#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:168 +msgid "Longitude & Latitude columns" +msgstr "Stolpci zemljepisne dolžine in širine" -#: superset/errors.py:107 -msgid "The username provided when connecting to a database is not valid." -msgstr "Uporabniško ime za povezavo s podatkovno bazo je neveljavno." +#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:184 +msgid "Delimited long & lat single column" +msgstr "En stolpec z ločenima zemljepisno dolžino in širino" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:206 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:89 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:72 -msgid "The way the ticks are laid out on the X-axis" -msgstr "Način razporeditve oznak na X-osi" +#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:185 +msgid "" +"Multiple formats accepted, look the geopy.points Python library for more details" +msgstr "" +"Sprejema različne zapise - podrobnosti najdete v Pythonovi knjižnici geopy.points" -#: superset/charts/commands/exceptions.py:127 -#: superset/charts/commands/exceptions.py:147 -#: superset/dashboards/commands/exceptions.py:62 -#: superset/dashboards/commands/exceptions.py:74 -#: superset/databases/commands/exceptions.py:117 -msgid "There are associated alerts or reports" -msgstr "Prisotna so povezana opozorila in poročila" +#: superset-frontend/src/explore/components/controls/SpatialControl.jsx:203 +msgid "Geohash" +msgstr "Geohash" -#: superset/charts/commands/bulk_delete.py:64 -#: superset/charts/commands/delete.py:68 -#: superset/dashboards/commands/bulk_delete.py:65 -#: superset/dashboards/commands/delete.py:66 -#: superset/databases/commands/delete.py:65 -#, python-format -msgid "There are associated alerts or reports: %s," -msgstr "Prisotna so opozorila in poročila: %s," +#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:98 +msgid "textarea" +msgstr "področje besedila" -#: superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx:507 -msgid "There are no filters in this dashboard." -msgstr "V nadzorni plošči ni filtrov." +#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:128 +msgid "in modal" +msgstr "v modalnem oknu" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:45 -msgid "There are unsaved changes." -msgstr "Imate neshranjene spremembe." +#: superset-frontend/src/explore/components/controls/ViewQueryModal.tsx:84 +msgid "Sorry, An error occurred" +msgstr "Prišlo je do napake" -#: superset/errors.py:95 -msgid "" -"There is a syntax error in the SQL query. Perhaps there was a misspelling" -" or a typo." -msgstr "V SQL-poizvedbi je sintaktična napaka. Mogoče ste se zatipkali." +#: superset-frontend/src/explore/components/controls/withAsyncVerification.tsx:201 +#, python-format +msgid "Failed to verify select options: %s" +msgstr "Preverjanje možnosti izbire ni uspelo: %s" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:113 +msgid "No annotation layers" +msgstr "Ni slojev z oznakami" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:116 +msgid "Add an annotation layer" +msgstr "Dodaj sloj z oznakami" -#: superset-frontend/src/dashboard/components/MissingChart.jsx:31 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:425 +#, python-format msgid "" -"There is no chart definition associated with this component, could it " -"have been deleted?" +"Use another existing chart as a source for annotations and overlays.\n" +" Your chart must be one of these visualization types: [%s]" msgstr "" -"S to komponento ni povezana nobena definicija grafikona. Ali je bila " -"izbrisana?" +"Uporabite enega izmed obstoječih grafikonov kot vir oznak.\n" +" Grafikon mora biti naslednjega tipa: [%s]" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:437 +msgid "Annotation layer value" +msgstr "Vrednost sloja z oznakami" + +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:500 +msgid "Annotation Slice Configuration" +msgstr "Nastavitve rezine z oznakami" -#: superset-frontend/src/dashboard/actions/dashboardLayout.js:180 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:501 msgid "" -"There is not enough space for this component. Try decreasing its width, " -"or increasing the destination width." +"This section allows you to configure how to use the slice\n" +" to generate annotations." msgstr "" -"Za to komponento ni dovolj prostora. Poskusite zmanjšati širino ali pa " -"povečati širino cilja." - -#: superset-frontend/src/views/CRUD/hooks.ts:522 -#, python-format -msgid "There was an error fetching the favorite status: %s" -msgstr "Napaka pri pridobivanju statusa \"Priljubljeno\": %s" +"V tem sklopu lahko nastavite način uporabe rezine\n" +" za ustvarjanje oznak." -#: superset-frontend/src/views/CRUD/utils.tsx:181 -msgid "There was an error fetching your recent activity:" -msgstr "Pri pridobivanju nedavnih aktivnosti je prišlo do napake:" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:507 +msgid "Annotation layer time column" +msgstr "Časovni stolpec sloja z oznakami" -#: superset-frontend/src/components/DatabaseSelector/index.tsx:230 -msgid "There was an error loading the schemas" -msgstr "Napaka pri nalaganju shem" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:512 +msgid "Interval start column" +msgstr "Stolpec začetka intervala" -#: superset-frontend/src/components/TableSelector/index.tsx:218 -msgid "There was an error loading the tables" -msgstr "Napaka pri nalaganju tabel" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:513 +msgid "Event time column" +msgstr "Stolpec časa dogodka" -#: superset-frontend/src/views/CRUD/hooks.ts:543 -#, python-format -msgid "There was an error saving the favorite status: %s" -msgstr "Napaka pri shranjevanju statusa \"Priljubljeno\": %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:515 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:531 +msgid "This column must contain date/time information." +msgstr "Ta stolpec mora vsebovati informacijo o datumu/času." -#: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:61 -msgid "There was an error with your request" -msgstr "Pri zahtevi je prišlo do napake" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:527 +msgid "Annotation layer interval end" +msgstr "Konec intervala sloja z oznakami" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:165 -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:107 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:94 -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:97 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:148 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:550 -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:235 -#: superset-frontend/src/views/CRUD/utils.tsx:289 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:175 -#, python-format -msgid "There was an issue deleting %s: %s" -msgstr "Težava pri brisanju %s: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:530 +msgid "Interval End column" +msgstr "Stolpec konca intervala" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:180 -#, python-format -msgid "There was an issue deleting the selected %s: %s" -msgstr "Težava pri brisanju izbranih %s: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:541 +msgid "Annotation layer title column" +msgstr "Stolpec z naslovom sloja z oznakami" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:127 -#, python-format -msgid "There was an issue deleting the selected annotations: %s" -msgstr "Pri brisanju izbranih oznak je prišlo do težave: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:544 +msgid "Title Column" +msgstr "Stolpec z naslovi" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:209 -#, python-format -msgid "There was an issue deleting the selected charts: %s" -msgstr "Pri brisanju izbranih grafikonov je prišlo do težave: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:545 +msgid "Pick a title for you annotation." +msgstr "Izberite naslov za oznako." -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:226 -msgid "There was an issue deleting the selected dashboards: " -msgstr "Pri brisanju izbranih nadzornih plošč je prišlo do težave: " +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:552 +msgid "Annotation layer description columns" +msgstr "Stolpci z opisi slojev z oznakami" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:568 -#, python-format -msgid "There was an issue deleting the selected datasets: %s" -msgstr "Pri brisanju izbranih podatkovnih setov je prišlo do težave: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:555 +msgid "Description Columns" +msgstr "Stolpci z opisi" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:111 -#, python-format -msgid "There was an issue deleting the selected layers: %s" -msgstr "Pri brisanju izbranih slojev je prišlo do težave: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:556 +msgid "" +"Pick one or more columns that should be shown in the annotation. If you don't " +"select a column all of them will be shown." +msgstr "" +"Izberite enega ali več stolpcev, ki bodo prikazani v oznakah. Če ne izberete " +"stolpca, bodo prikazani vsi." -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:262 -#, python-format -msgid "There was an issue deleting the selected queries: %s" -msgstr "Do težave je prišlo pri brisanju izbranih poizvedb: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:650 +msgid "Display configuration" +msgstr "Prikaži nastavitve" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:115 -#, python-format -msgid "There was an issue deleting the selected templates: %s" -msgstr "Pri brisanju izbranih predlog je prišlo do težave: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:651 +msgid "Configure your how you overlay is displayed here." +msgstr "Nastavite kako se tukaj prikazuje vrhnja plast." -#: superset-frontend/src/views/CRUD/utils.tsx:249 -#, python-format -msgid "There was an issue deleting: %s" -msgstr "Težava pri brisanju: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:654 +msgid "Annotation layer stroke" +msgstr "Obroba sloja z oznakami" -#: superset-frontend/src/dashboard/actions/dashboardState.js:100 -msgid "There was an issue favoriting this dashboard." -msgstr "Pri uvrščanju nadzorne plošče med priljubljene je prišlo do težave." +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:656 +msgid "Style" +msgstr "Slog" -#: superset-frontend/src/reports/actions/reports.js:68 -msgid "There was an issue fetching reports attached to this dashboard." -msgstr "Pri pridobivanju poročil za to nadzorno ploščo je prišlo do težave." +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:669 +msgid "Annotation layer opacity" +msgstr "Prosojnost sloja z oznakami" -#: superset-frontend/src/dashboard/actions/dashboardState.js:79 -msgid "There was an issue fetching the favorite status of this dashboard." -msgstr "" -"Pri pridobivanju statusa \"priljubljeno\" za to nadzorno ploščo je prišlo" -" do težave." +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:683 +msgid "Color" +msgstr "Barva" -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:195 -#, python-format -msgid "There was an issue fetching your recent activity: %s" -msgstr "Pri pridobivanju vaše nedavne aktivnosti je prišlo do napake: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:754 +msgid "Layer configuration" +msgstr "Nastavitve sloja" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:152 -#, python-format -msgid "There was an issue previewing the selected query %s" -msgstr "Do težave je prišlo pri predogledu izbrane poizvedbe %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:755 +msgid "Configure the basics of your Annotation Layer." +msgstr "Osnovne nastavitve sloja z oznakami." -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:109 -#, python-format -msgid "There was an issue previewing the selected query. %s" -msgstr "Pri predogledu izbrane poizvedbe je prišlo do težave. %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:763 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:801 +msgid "Mandatory" +msgstr "Obvezno" -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:222 -#, python-format -msgid "There was an issues fetching your chart: %s" -msgstr "Prišlo je do napake pri pridobivanju grafikona: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:767 +msgid "Hide layer" +msgstr "Skrij sloj" -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:211 -#, python-format -msgid "There was an issues fetching your dashboards: %s" -msgstr "Prišlo je do napake pri pridobivanju nadzornih plošč: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:773 +msgid "Show label" +msgstr "Pokaži oznako" -#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:233 -#, python-format -msgid "There was an issues fetching your saved queries: %s" -msgstr "Prišlo je do napake pri pridobivanju shranjenih poizvedb: %s" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:776 +msgid "Whether to always show the annotation label" +msgstr "Če želite vedno prikazati naslov oznake" -#: superset/viz.py:1955 -msgid "" -"There's a loop in your Sankey, please provide a tree. Here's a faulty " -"link: {}" -msgstr "V 'Sankey' je zanka, določite drevo. To je okvarjena povezava: {}" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:780 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:783 +msgid "Annotation layer type" +msgstr "Tip sloja z oznakami" -#: superset/connectors/sqla/views.py:341 -msgid "These are the tables this filter will be applied to." -msgstr "To so tabele, na katere se nanaša ta filter." +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:782 +msgid "Choose the annotation layer type" +msgstr "Izberite tip sloja z oznakami" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:135 -msgid "These filters apply to the values available in the dropdowns" -msgstr "Ti filtri se nanašajo na vrednosti v spustnih seznamih" +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:792 +msgid "Annotation source type" +msgstr "Tip vira oznak" -#: superset/views/chart/mixin.py:64 -msgid "" -"These parameters are generated dynamically when clicking the save or " -"overwrite button in the explore view. This JSON object is exposed here " -"for reference and for power users who may want to alter specific " -"parameters." -msgstr "" -"Ti parametri se ustvarijo dinamično s klikom gumba Shrani ali Prepiši v " -"raziskovalnem pogledu. Ta JSON objekt je prikazan kot vzorec za napredne " -"uporabnike, ki želijo spreminjati posamezne parametre." +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:794 +msgid "Choose the source of your annotations" +msgstr "Izberite vir svojih oznak" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:597 -#: superset/views/dashboard/mixin.py:59 -msgid "" -"This JSON object is generated dynamically when clicking the save or " -"overwrite button in the dashboard view. It is exposed here for reference " -"and for power users who may want to alter specific parameters." -msgstr "" -"Ta JSON objekt se ustvari dinamično s klikom gumba Shrani ali Prepiši v " -"pogledu nadzorne plošče. Tukaj je prikazan kot vzorec za napredne " -"uporabnike, ki želijo spreminjati posamezne parametre." +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:795 +msgid "Annotation source" +msgstr "Vir oznak" -#: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:99 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:470 -#, python-format -msgid "This action will permanently delete %s." -msgstr "S tem dejanjem boste trajno izbrisali %s." +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:817 +msgid "Remove" +msgstr "Odstrani" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:353 -msgid "This action will permanently delete the layer." -msgstr "S tem dejanjem boste trajno izbrisali sloj." +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:177 +msgid "Edit annotation layer" +msgstr "Uredi sloj z oznakami" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:475 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:249 -msgid "This action will permanently delete the saved query." -msgstr "S tem dejanjem boste trajno izbrisali shranjeno poizvedbo." +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:207 +#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx:219 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:242 +msgid "Add annotation layer" +msgstr "Dodaj sloj z oznakami" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:313 -msgid "This action will permanently delete the template." -msgstr "S tem dejanjem boste trajno izbrisali predlogo." +#: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:59 +msgid "Empty collection" +msgstr "Prazen izbor" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:40 -msgid "" -"This can be either an IP address (e.g. 127.0.0.1) or a domain name (e.g. " -"mydatabase.com)." -msgstr "" -"To je lahko bodisi IP naslov (npr. 127.0.0.1) bodisi ime domene (npr. " -"mydatabase.com)." +#: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:63 +msgid "Add an item" +msgstr "Dodaj element" -#: superset-frontend/src/dashboard/actions/dashboardLayout.js:258 -msgid "This chart has been moved to a different filter scope." -msgstr "Ta grafikon je bil prestavljen v drug doseg filtrov." +#: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:142 +msgid "Remove item" +msgstr "Odstrani element" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.ts:56 -msgid "This chart might be incompatible with the filter (datasets don't match)" +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:66 +msgid "" +"The color scheme is determined by the related dashboard.\n" +" Edit the color scheme in the dashboard properties." msgstr "" -"Ta grafikon je lahko nekompatibilen s filtrom (podatkovni seti se ne " -"ujemajo)" +"Barvna shema je določena s povezano nadzorno ploščo.\n" +" Barvno shemo uredite v nastavitvah nadzorne plošče." #: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:127 msgid "" "This color scheme is being overriden by custom label colors.\n" " Check the JSON metadata in the Advanced settings" msgstr "" +"Barvna shema je bila preglasovana z barvo oznake po meri.\n" +" Preverite JSON metapodatke v naprednih nastavitvah" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:480 -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:496 -msgid "This column must contain date/time information." -msgstr "Ta stolpec mora vsebovati informacijo o datumu/času." +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:153 +msgid "Dashboard scheme" +msgstr "Shema nadzorne plošče" -#: superset-frontend/src/dashboard/components/Header/index.jsx:303 -#, python-format -msgid "" -"This dashboard is currently auto refreshing; the next auto refresh will " -"be in %s." -msgstr "" -"Nadzorna plošča se trenutno samodejno osvežuje. Naslednja samodejna " -"osvežitev bo čez %s." +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:188 +msgid "Select color scheme" +msgstr "Izberite barvno shemo" + +#: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:194 +msgid "Select scheme" +msgstr "Izberite shemo" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:151 +msgid "Edit formatter" +msgstr "Uredi oblikovanje" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:169 +msgid "Add new formatter" +msgstr "Dodaj novo oblikovanje" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:176 +msgid "Add new color formatter" +msgstr "Dodaj novo oblikovanje barve" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:42 +msgid "green" +msgstr "zelena" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:43 +msgid "yellow" +msgstr "rumena" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:44 +msgid "red" +msgstr "rdeča" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:80 +msgid "This value should be smaller than the right target value" +msgstr "Ta vrednost mora biti manjša od desne ciljne vrednosti" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:85 +msgid "This value should be greater than the left target value" +msgstr "Ta vrednost mora biti večja od leve ciljne vrednosti" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:94 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:98 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:105 +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:252 +msgid "Required" +msgstr "Obvezno" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:126 +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:130 +msgid "Operator" +msgstr "Operator" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:144 +msgid "Left value" +msgstr "Leva vrednost" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:157 +msgid "Right value" +msgstr "Desna vrednost" + +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:173 +msgid "Target value" +msgstr "Ciljna vrednost" -#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:38 -msgid "" -"This dashboard is not published which means it will not show up in the " -"list of dashboards. Favorite it to see it there or access it by using the" -" URL directly." -msgstr "" -"Ta nadzorna plošča ni objavljena in se ne bo prikazala na seznamu " -"nadzornih plošč. Uvrstite jo med priljubljene, da jo boste videli tam, " -"ali pa uporabite URL za neposredni dostop." +#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:208 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:63 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:300 +msgid "Select column" +msgstr "Izberite stolpec" -#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:33 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:244 +msgid "Edit dataset" +msgstr "Uredi podatkovni set" + +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:256 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:429 msgid "" -"This dashboard is not published, it will not show up in the list of " -"dashboards. Click here to publish this dashboard." +"You must be a dataset owner in order to edit. Please reach out to a dataset owner " +"to request modifications or edit access." msgstr "" -"Ta nadzorna plošča ni objavljena in se ne bo prikazala na seznamu " -"nadzornih plošč. Kliknite tukaj za njeno objavo." +"Za urejanje morate biti lastnik podatkovnega seta. Za dostop do urejanja " +"kontaktirajte lastnika podatkovnega seta." -#: superset-frontend/src/dashboard/actions/dashboardState.js:125 -#, fuzzy -msgid "This dashboard is now hidden" -msgstr "Spreminjanje te nadzorne plošče ni dovoljeno" +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:269 +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:277 +msgid "View in SQL Lab" +msgstr "Ogled v SQL laboratoriju" -#: superset-frontend/src/dashboard/actions/dashboardState.js:124 -#, fuzzy -msgid "This dashboard is now published" -msgstr "Ta nadzorna plošča je sedaj ${nowPublished}" +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:276 +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:117 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:378 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:97 +msgid "Query preview" +msgstr "Predogled poizvedbe" -#: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:43 -msgid "This dashboard is published. Click to make it a draft." -msgstr "Ta nadzorna plošča je objavljena. Kliknite, da jo uvrstite med osnutke." +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:278 +msgid "Save as dataset" +msgstr "Shrani kot podatkovni set" -#: superset/views/core.py:1273 -msgid "" -"This dashboard was changed recently. Please reload dashboard to get " -"latest version." -msgstr "" -"Nadzorna plošča je bila pred kratkim spremenjena. Ponovno jo naložite, da" -" dobite zadnjo verzijo." +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:322 +msgid "More dataset related options" +msgstr "Več nastavitev za podatkovni set" -#: superset-frontend/src/dashboard/actions/dashboardState.js:231 -msgid "This dashboard was saved successfully." -msgstr "Nadzorna plošča je bila uspešno shranjena." +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:335 +msgid "Missing URL parameters" +msgstr "Manjkajo parametri URL-ja" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:77 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:401 -#: superset-frontend/src/explore/controls.jsx:416 -msgid "This defines the element to be plotted on the chart" -msgstr "Določa element, ki bo izrisan na grafikonu" +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:340 +msgid "The URL is missing the dataset_id or slice_id parameters." +msgstr "V URL-ju manjkata parametra dataset_id ali slice_id." -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:82 -msgid "This defines the level of the hierarchy" -msgstr "Določa stopnjo hierarhije" +#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:358 +msgid "The dataset linked to this chart may have been deleted." +msgstr "Podatkovni set, povezan s tem grafikonom, je bil izbrisan." -#: superset/views/alerts.py:232 superset/views/schedules.py:253 -#: superset/views/schedules.py:334 -msgid "" -"This feature is deprecated and will be removed on 2.0. Take a look at the" -" replacement feature <a " -"href='https://superset.apache.org/docs/installation/alerts-" -"reports'>Alerts & Reports documentation</a>" -msgstr "" -"Ta funkcija je zastarela in bo odstranjena v verziji 2.0. Oglejte si " -"zamenjavo <a href='https://superset.apache.org/docs/installation/alerts-" -"reports'>Dokumentacija za Opozorila & Poročila</a>" +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:293 +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:295 +msgid "RANGE TYPE" +msgstr "TIP OBDOBJA" -#: superset/connectors/sqla/views.py:447 -msgid "" -"This fields acts a Superset view, meaning that Superset will run a query " -"against this string as a subquery." -msgstr "" -"To polje se obnaša kot Supersetov pogled, kar pomeni, da bo Superset " -"izvedel poizvedbo za ta niz kot podpoizvedbo." +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:316 +msgid "Actual time range" +msgstr "Dejansko časovno obdobje" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:105 -msgid "This filter doesn't exist in dashboard. It will not be applied." -msgstr "Ta filter ne obstaja v nadzorni plošči in ne bo uveljavljen." +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:334 +msgid "CANCEL" +msgstr "PREKINI" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:165 -#, python-format -msgid "This filter set is identical to: \"%s\"" -msgstr "Ta set filtrov je enak: \"%s\"" +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:344 +msgid "APPLY" +msgstr "UPORABI" -#: superset/connectors/sqla/views.py:358 -msgid "" -"This is the condition that will be added to the WHERE clause. For " -"example, to only return rows for a particular client, you might define a " -"regular filter with the clause `client_id = 9`. To display no rows unless" -" a user belongs to a RLS filter role, a base filter can be created with " -"the clause `1 = 0` (always false)." -msgstr "" -"To je pogoj, ki bo dodan WHERE stavku. Npr., če želite dobiti vrstice za " -"določeno stranko, lahko definirate regularni filter z izrazom 'id_stranke" -" = 9'. Če ne želimo prikazati vrstic, razen če uporabnik pripada RLS " -"vlogi, lahko filter ustvarimo z izrazom `1 = 0` (vedno neresnično)." +#: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:353 +msgid "Edit time range" +msgstr "Uredi časovno obdobje" -#: superset/views/dashboard/mixin.py:47 -msgid "" -"This json object describes the positioning of the widgets in the " -"dashboard. It is dynamically generated when adjusting the widgets size " -"and positions by using drag & drop in the dashboard view" -msgstr "" -"Ta JSON objekt opisuje postavitev pripomočkov na nadzorni plošči. Ustvari" -" se dinamično, ko prilagajamo velikost in postavitev pripomočkov z " -"uporabo povleci&spusti v pogledu nadzorne plošče" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:58 +msgid "Configure Advanced Time Range " +msgstr "Nastavi napredno časovno obdobje " -#: superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx:80 -msgid "This markdown component has an error." -msgstr "Markdown komponenta ima napako." +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:64 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:114 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:121 +msgid "START (INCLUSIVE)" +msgstr "ZAČETEK (VKLJUČEN)" -#: superset-frontend/src/dashboard/components/gridComponents/Markdown.jsx:167 -msgid "This markdown component has an error. Please revert your recent changes." -msgstr "Markdown komponenta ima napako. Povrnite nedavne spremembe." +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:66 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:116 +msgid "Start date included in time range" +msgstr "Začetni datum je vključen v časovno obdobje" -#: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:47 -#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:62 -msgid "This may be triggered by:" -msgstr "To je lahko sproženo z/s:" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:76 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:166 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:173 +msgid "END (EXCLUSIVE)" +msgstr "KONEC (NI VKLJUČEN)" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:109 -#, python-format -msgid "This query took %s seconds to run, " -msgstr "Trajanje poizvedbe v sekundah: %s, " +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:78 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:168 +msgid "End date excluded from time range" +msgstr "Končni datum ni vključen v časovno obdobje" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:466 -#, fuzzy -msgid "" -"This section allows you to configure how to use the slice\n" -" to generate annotations." -msgstr "" -"V tem sklopu lahko nastavite način uporabe rezine\r\n" -" za ustvarjanje oznak." +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CalendarFrame.tsx:46 +msgid "Configure Time Range: Previous..." +msgstr "Nastavi časovno obdobje: Prejšnji ..." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:27 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:244 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:127 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:377 -#: superset-frontend/src/explore/controlPanels/sections.tsx:146 -msgid "" -"This section contains options that allow for advanced analytical post " -"processing of query results" -msgstr "" -"Ta sekcija vsebuje možnosti, ki omogočajo napredno analitično " -"poprocesiranje rezultatov poizvedb" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx:41 +msgid "Configure Time Range: Last..." +msgstr "Nastavi časovno obdobje: Zadnji ..." -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:84 -msgid "This value should be greater than the left target value" -msgstr "Ta vrednost mora biti večja od leve ciljne vrednosti" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:110 +msgid "Configure custom time range" +msgstr "Nastavi prilagojeno časovno obdobje" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:79 -msgid "This value should be smaller than the right target value" -msgstr "Ta vrednost mora biti manjša od desne ciljne vrednosti" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:143 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:194 +msgid "Relative quantity" +msgstr "Relativne vrednosti" -#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:67 -msgid "This visualization type is not supported." -msgstr "Ta tip vizualizacije ni podprt." +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:155 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:206 +msgid "Relative period" +msgstr "Relativno obdobje" -#: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:61 -msgid "This was triggered by:" -msgstr "To je bilo sproženo z/s:" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:218 +msgid "Anchor to" +msgstr "Sidraj na" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:74 -msgid "Threshold alpha level for determining significance" -msgstr "Mejna vrednost alfa za določanje značilnosti" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:227 +msgid "NOW" +msgstr "ZDAJ" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:60 -msgid "Thursday" -msgstr "Četrtek" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:230 +msgid "Date/Time" +msgstr "Datum/Čas" -# SUPERSET UI -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:32 -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:26 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:36 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:52 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:38 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:37 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:33 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:36 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:81 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:81 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:75 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:75 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:75 -#: superset-frontend/src/explore/controlPanels/sections.tsx:25 -#: superset-frontend/src/explore/controlPanels/sections.tsx:84 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:182 -msgid "Time" -msgstr "Čas" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:29 +msgid "Return to specific datetime." +msgstr "Vrne določen datum-čas." -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:25 -msgid "Time Column" -msgstr "Časovni stolpec" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:30 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:44 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:62 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:76 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:89 +msgid "Syntax" +msgstr "Sintaksa" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:303 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:186 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:436 -msgid "Time Comparison" -msgstr "Časovna primerjava" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:34 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:49 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:67 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:81 +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:95 +msgid "Example" +msgstr "Primer" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:141 -msgid "Time Format" -msgstr "Oblika zapisa časa" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:43 +msgid "Moves the given set of dates by a specified interval." +msgstr "Premakne dani nabor datumov za definirano obdobje." -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:26 -msgid "Time Grain" -msgstr "Granulacija časa" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:58 +msgid "Truncates the specified date to the accuracy specified by the date unit." +msgstr "Zaokroži določen datum, glede na natančnost, definirano s časovno enoto." -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:28 -msgid "Time Granularity" -msgstr "Granulacija časa" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:75 +msgid "Get the last date by the date unit." +msgstr "Pridobi zadnji datum glede na časovno enoto." -#: superset/connectors/druid/views.py:350 -msgid "Time Offset" -msgstr "Časovni zamik" +#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:88 +msgid "Get the specify date for the holiday" +msgstr "Določi datum praznika" -#: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:24 -msgid "Time Range" -msgstr "Časovno obdobje" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:31 +msgid "Last" +msgstr "Zadnji" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:86 -msgid "Time Series" -msgstr "Časovna vrsta" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:32 +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:125 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:105 +msgid "Previous" +msgstr "Prejšnji" -#: superset/viz.py:1638 -msgid "Time Series - Bar Chart" -msgstr "Časovna vrsta - Stolpčni grafikon" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:33 +msgid "Custom" +msgstr "Prilagojen" -#: superset/viz.py:1564 -msgid "Time Series - Dual Axis Line Chart" -msgstr "Časovna vrsta - Črtni grafikon z dvojno osjo" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:39 +msgid "last day" +msgstr "zadnji dan" -#: superset/viz.py:1276 -msgid "Time Series - Line Chart" -msgstr "Časovna vrsta - Črtni grafikon" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:40 +msgid "last week" +msgstr "zadnji teden" -#: superset/viz.py:1486 -msgid "Time Series - Multiple Line Charts" -msgstr "Časovna vrsta - Veččrtni grafikon" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:41 +msgid "last month" +msgstr "zadnji mesec" -#: superset/viz.py:3000 -msgid "Time Series - Nightingale Rose Chart" -msgstr "Časovna vrsta - Nightingale Rose grafikon" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:42 +msgid "last quarter" +msgstr "zadnje četrletje" -#: superset/viz.py:2928 -msgid "Time Series - Paired t-test" -msgstr "Časovna vrsta - t-test za odvisne vzorce" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:43 +msgid "last year" +msgstr "zadnje leto" -#: superset/viz.py:1693 -msgid "Time Series - Percent Change" -msgstr "Časovna vrsta - Procentualna sprememba" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:50 +msgid "previous calendar week" +msgstr "prejšnji koledarski teden" -#: superset/viz.py:1647 -msgid "Time Series - Period Pivot" -msgstr "Časovna vrsta - Vrtenje period" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:53 +msgid "previous calendar month" +msgstr "prejšnji koledarski mesec" -#: superset/viz.py:1701 -msgid "Time Series - Stacked" -msgstr "Časovna vrsta - Naložen graf" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:55 +msgid "previous calendar year" +msgstr "prejšnje koledarsko leto" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:67 -msgid "Time Series Options" -msgstr "Možnosti časovne vrste" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:62 +#, python-format +msgid "Seconds %s" +msgstr "Sekunde %s" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:311 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:194 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:444 -msgid "Time Shift" -msgstr "Časovni zamik" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:63 +#, python-format +msgid "Minutes %s" +msgstr "Minute %s" -#: superset/viz.py:822 -msgid "Time Table View" -msgstr "Pogled urnika" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:64 +#, python-format +msgid "Hours %s" +msgstr "Ure %s" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:297 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1132 -#: superset-frontend/src/explore/constants.ts:114 -#: superset-frontend/src/filters/components/TimeColumn/index.ts:28 -msgid "Time column" -msgstr "Časovni stolpec" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:65 +#, python-format +msgid "Days %s" +msgstr "Dnevi %s" -#: superset/connectors/sqla/models.py:1173 +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:66 #, python-format -msgid "Time column \"%(col)s\" does not exist in dataset" -msgstr "Časovni stolpec \"%(col)s\" ne obstaja v podatkovnem setu" +msgid "Weeks %s" +msgstr "Tedni %s" -#: superset-frontend/src/filters/components/TimeColumn/index.ts:29 -msgid "Time column filter plugin" -msgstr "Vtičnik za časovni filter" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:67 +#, python-format +msgid "Months %s" +msgstr "Meseci %s" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:88 -#: superset-frontend/src/explore/controlPanels/sections.tsx:201 -msgid "Time comparison" -msgstr "Časovna primerjava" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:68 +#, python-format +msgid "Quarters %s" +msgstr "Četrtletja %s" -#: superset/charts/commands/exceptions.py:66 +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:69 #, python-format -msgid "" -"Time delta is ambiguous. Please specify [%(human_readable)s ago] or " -"[%(human_readable)s later]." -msgstr "" -"Časovna razlika je nejasna. Podajte [%(human_readable)s ago] ali " -"[%(human_readable)s later]." +msgid "Years %s" +msgstr "Leta %s" -#: superset/connectors/druid/views.py:317 -msgid "" -"Time expression to use as a predicate when retrieving distinct values to " -"populate the filter component. Only applies when `Enable Filter Select` " -"is on. If you enter `7 days ago`, the distinct list of values in the " -"filter will be populated based on the distinct value over the past week" -msgstr "" -"Prednastavljeni časovni izraz za pridobitev različnih vrednosti filtrirne" -" komponente. Upošteva se le v primeru, da je vključeno `Omogoči izbiro " -"filtra`. Če vnesete `7 days ago`, bo seznam vrednosti filtra napolnjen na" -" podlagi različnih vrednosti v prejšnjem tednu" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:75 +msgid "Before" +msgstr "PRED" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:296 -#: superset-frontend/src/filters/components/Time/index.ts:27 -msgid "Time filter" -msgstr "Časovni filter" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:82 +msgid "After" +msgstr "PO" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:450 -msgid "Time format" -msgstr "Oblika zapisa časa" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:87 +msgid "Specific Date/Time" +msgstr "Fiksen Datum/Čas" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:298 -#: superset-frontend/src/explore/constants.ts:115 -#: superset-frontend/src/filters/components/TimeGrain/index.ts:28 -msgid "Time grain" -msgstr "Granulacija časa" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:88 +msgid "Relative Date/Time" +msgstr "Relativen Datum/Čas" -#: superset-frontend/src/filters/components/TimeGrain/index.ts:29 -msgid "Time grain filter plugin" -msgstr "Vtičnik za filter časovne granulacije" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:89 +msgid "Now" +msgstr "Zdaj" -#: superset/utils/pandas_postprocessing.py:815 -msgid "Time grain missing" -msgstr "Časovna granulacija manjka" +#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:90 +msgid "Midnight" +msgstr "Polnoč" -#: superset-frontend/src/explore/constants.ts:117 -msgid "Time granularity" -msgstr "Granulacija časa" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:230 +msgid "Saved expressions" +msgstr "Shranjeni izrazi" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1267 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1282 -msgid "Time in seconds" -msgstr "Čas v sekundah" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:246 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:367 +msgid "Saved" +msgstr "Shranjeno" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:296 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1105 -#: superset-frontend/src/explore/constants.ts:113 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:382 -msgid "Time range" -msgstr "Časovno obdobje" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:255 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:305 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:330 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:301 +#, python-format +msgid "%s column(s)" +msgstr "Stolpci: %s" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:98 -#: superset-frontend/src/explore/controlPanels/sections.tsx:69 -msgid "Time range endpoints" -msgstr "Krajne točke časovnega obdobja" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:273 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:292 +msgid "No temporal columns found" +msgstr "Ni najdenih časovnih stolpcev" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:100 -#: superset-frontend/src/explore/controlPanels/sections.tsx:71 -msgid "Time range endpoints (SIP-15)" -msgstr "Krajne točke časovnega obdobja (SIP-15)" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:274 +msgid "No saved expressions found" +msgstr "Shranjeni izrazi niso najdeni" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:28 -#: superset-frontend/src/explore/controlPanels/sections.tsx:27 -#: superset-frontend/src/explore/controlPanels/sections.tsx:85 -msgid "Time related form attributes" -msgstr "S časom povezani atributi prikaza" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:278 +msgid "Add calculated temporal columns to dataset in \"Edit datasource\" modal" +msgstr "" +"Dodaj izračunan časovni stolpec v podatkovni set v oknu \"Uredi podatkovni vir\"" -#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:48 -#: superset-frontend/src/explore/controlPanels/TimeTable.js:38 -msgid "Time series columns" -msgstr "Stolpci s časovnimi vrstami" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:281 +msgid "Add calculated columns to dataset in \"Edit datasource\" modal" +msgstr "Dodaj izračunan stolpec v podatkovni set v oknu \"Uredi podatkovni vir\"" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:96 -#: superset-frontend/src/explore/controlPanels/sections.tsx:209 -msgid "Time shift" -msgstr "Časovni zamik" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:288 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:211 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:401 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:404 +msgid "Simple" +msgstr "Preprosto" -#: superset/charts/commands/exceptions.py:38 -#, python-format -msgid "" -"Time string is ambiguous. Please specify [%(human_readable)s ago] or " -"[%(human_readable)s later]." -msgstr "" -"Časovni niz je nejasen. Podajte [%(human_readable)s ago] ali " -"[%(human_readable)s later]." +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:293 +msgid "Mark a column as temporal in \"Edit datasource\" modal" +msgstr "Označite stolpec kot časoven preko okna \"Uredi podatkovni vir\"" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:75 -msgid "Time-series Area Chart" -msgstr "Ploščinski grafikon časovne vrste" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:319 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:237 +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:240 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:447 +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:450 +msgid "Custom SQL" +msgstr "Prilagojen SQL" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:65 -msgid "" -"Time-series Area chart are similar to line chart in that they represent " -"variables with the same scale, but area charts stack the metrics on top " -"of each other. An area chart in Superset can be stream, stack, or expand." -msgstr "" -"Ploščinski grafikoni časovne vrste so podobni črtnim grafikonom, saj " -"predstavljajo spremenljivke v istem razmerju, vendar se pri ploščinskih " -"grafikonih mere nalagajo ena na drugo." +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx:43 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.jsx:65 +msgid "My column" +msgstr "Moj stolpec" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:35 -msgid "Time-series Bar Chart" -msgstr "Stolpčni grafikon za časovno vrsto" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:211 +msgid "Drop a column here or click" +msgstr "Spustite stolpec sem ali kliknite" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:75 -msgid "Time-series Bar Chart v2" -msgstr "Stolpčni grafikon časovne vrste v2" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:216 +msgid "Drop column here" +msgstr "Spustite stolpec sem" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:61 -msgid "" -"Time-series Bar Charts are used to show the changes in a metric over time" -" as a series of bars." -msgstr "" -"Stolpčni grafikoni časovne vrste se uporabljajo za prikaz sprememb mere " -"skozi čas s pomočjo niza stolpcev." +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.jsx:81 +msgid "Click to edit label" +msgstr "Kliknite za urejanje oznake" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:69 -msgid "Time-series Chart" -msgstr "Grafikon časovne vrste" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx:388 +msgid "Drop columns/metrics here or click" +msgstr "Spustite stolpce/mere sem ali kliknite" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:70 -msgid "Time-series Line Chart" -msgstr "Črtni grafikon časovne vrste" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx:389 +msgid "Drop columns or metrics here" +msgstr "Spustite stolpce ali mere sem" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:30 -msgid "Time-series Percent Change" -msgstr "Časovna vrsta - Procentualna sprememba" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:367 +msgid "Drop a column/metric here or click" +msgstr "Spustite stolpec/mero sem ali kliknite" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:28 -msgid "Time-series Period Pivot" -msgstr "Časovna serija - Vrtenje periode" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:372 +msgid "Drop column or metric here" +msgstr "Spustite stolpec ali mero sem" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:69 -msgid "Time-series Scatter Plot" -msgstr "Raztreseni grafikon časovne vrste" +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx:83 +msgid "Drop columns here" +msgstr "Spustite stolpce sem" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:59 +#: superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx:68 +#: superset-frontend/src/explore/components/controls/OptionControls/index.tsx:322 msgid "" -"Time-series Scatter Plot has time on the horizontal axis in linear units," -" and the points are connected in order. It shows a statistical " -"relationship between two variables." +"\n" +" This filter was inherited from the dashboard's context.\n" +" It won't be saved when saving the chart.\n" +" " msgstr "" -"Raztreseni grafikon časovne vrste prikazuje podatkovne točke v povezanem " -"redu in prikazuje statistično razmerje med spremenljivkami." +"\n" +" Ta filter izvira iz konteksta nadzorne plošče.\n" +" Pri shranjevanju grafikona se ne bo shranil.\n" +" " -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:69 -msgid "Time-series Smooth Line" -msgstr "Zglajeni črtni grafikon časovne vrste" +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:167 +msgid "Default" +msgstr "Privzeto" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:59 +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:168 msgid "" -"Time-series Smooth-line is a variation of line chart. Without angles and " -"hard edges, Smooth-line looks more smarter and more professional." +"(optional) default value for the filter, when using the multiple option, you can " +"use a semicolon-delimited list of options." msgstr "" -"Zglajeni grafikon časovne vrste je izpeljanka črtnega grafikona, ki " -"zgladi ostre robove krivulje." +"(opcijsko) privzeta vrednost za filter, če uporabite opcijo izbire večih , lahko " +"uporabite seznam nastavitev ločen s podpičji." -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:60 -msgid "Time-series Stepped Line" -msgstr "Stopnični črtni grafikon časovne vrste" +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:185 +msgid "Metric to sort the results by" +msgstr "Mera za razvrščanje rezultatov" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:50 -msgid "" -"Time-series Stepped-line graph (also called step chart) is a variation of" -" line chart but with the line forming a series of steps between data " -"points. A step chart can be useful when you want to show the changes that" -" occur at irregular intervals." -msgstr "" -"Stopnični grafikon časovne vrste je izpeljanka črtnega grafikona, pri " -"čemer krivuljo tvorijo stopnice med posameznimi točkami. Koristen je za " -"prikaz sprememb na posameznih intervalih." +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:206 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:68 +msgid "Check for sorting ascending" +msgstr "Označi za naraščajoče razvrščanje" -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:25 -msgid "Time-series Table" -msgstr "Tabela s časovno vrsto" +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:216 +msgid "Allow multiple selections" +msgstr "Dovoli več izbir" -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:60 +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:218 +msgid "Multiple selections allowed, otherwise filter is limited to a single value" +msgstr "Lahko izberete več elementov, drugače pa je filter omejen na eno vrednost" + +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:232 +msgid "Search all filter options" +msgstr "Poišči vse možnosti filtra" + +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:233 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:138 msgid "" -"Time-series line chart is used to visualize repeated measurements taken " -"over regular time intervals. Line chart is a type of chart which displays" -" information as a series of data points connected by straight line " -"segments. It is a basic type of chart common in many fields." +"By default, each filter loads at most 1000 choices at the initial page load. " +"Check this box if you have more than 1000 filter values and want to enable " +"dynamically searching that loads filter values as users type (may add stress to " +"your database)." msgstr "" -"Črtni grafikon časovne vrste je osnovni grafikon, ki se uporablja na " -"različnih področjih. Uporablja se za vizualizacijo meritev zajetih skozi " -"čas. Posamezne točke so med seboj povezane z ravnimi črtami." +"Privzeto vsak filter pri nalaganju začetne strani naloži največ 1000 možnosti. " +"Označite polje, če imate več kot 1000 vrednosti filtra in želite omogočiti " +"dinamično iskanje, ki nalaga vrednosti filtra ko uporabnik tipka (to lahko " +"preobremeni vašo podatkovno bazo)." -#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:98 -msgid "Timeout error" -msgstr "Napaka pretečenega časa" +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:253 +msgid "User must select a value for this filter" +msgstr "Uporabnik mora izbrati vrednost za ta filter" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:60 -msgid "Timestamp Format" -msgstr "Oblika časovne značke" +#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:281 +msgid "Filter configuration" +msgstr "Nastavitve filtra" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:73 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:372 -msgid "Timestamp format" -msgstr "Oblika zapisa časovne značke" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:233 +msgid "Custom SQL ad-hoc filters are not available for the native Druid connector" +msgstr "Ad-hoc SQL filtri po meri niso na voljo za nativni konektor za Druid" -#: superset-frontend/src/components/ReportModal/index.tsx:378 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1223 -msgid "Timezone" -msgstr "Časovni pas" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:296 +#, python-format +msgid "%s option(s)" +msgstr "Možnosti: %s" -#: superset/connectors/druid/views.py:312 superset/connectors/sqla/views.py:438 -msgid "Timezone offset (in hours) for this datasource" -msgstr "Razlika časovnega pasu (v urah) za ta podatkovni vir" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:309 +msgid "Select subject" +msgstr "Izberite zadevo" -#: superset-frontend/src/components/TimezoneSelector/index.tsx:120 -msgid "Timezone selector" -msgstr "Izbira časovnega pasa" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:312 +msgid "No such column found. To filter on a metric, try the Custom SQL tab." +msgstr "" +"Tak stolpec ni najden. Za filtriranje po meri uporabite prilagojen SQL zavihek." -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:35 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:69 -msgid "Tiny" -msgstr "Drobna" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:320 +#, python-format +msgid "%s column(s) and metric(s)" +msgstr "Stolpcev in mer: %s" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:502 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:42 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:278 -#: superset/views/dashboard/mixin.py:79 superset/views/dashboard/views.py:156 -msgid "Title" -msgstr "Naslov" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:331 +msgid "To filter on a metric, use Custom SQL tab." +msgstr "Za filtriranje po meri uporabite prilagojen SQL zavihek." -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:509 -msgid "Title Column" -msgstr "Stolpec z naslovi" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:341 +#, python-format +msgid "%s operator(s)" +msgstr "Operatorji: %s" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:45 -#, fuzzy -msgid "Title is required" -msgstr "Zahtevana je vrednost" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:347 +msgid "Select operator" +msgstr "Izberite operator" -#: superset/dashboards/filters.py:33 -msgid "Title or Slug" -msgstr "Naslov ali `Slug`" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:356 +msgid "Comparator option" +msgstr "Možnosti komparatorja" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:287 -msgid "To filter on a metric, use Custom SQL tab." -msgstr "Za filtriranje po meri uporabite prilagojen SQL zavihek." +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:363 +msgid "Type a value here" +msgstr "Vnesite vrednost sem" -#: superset/views/dashboard/mixin.py:58 -msgid "To get a readable URL for your dashboard" -msgstr "Za pridobitev berljivega URL-ja za nadzorno ploščo" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:496 +msgid "Filter value (case sensitive)" +msgstr "Vrednost filtra (razlik. velikih/malih črk)" + +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/useAdvancedDataTypes.ts:70 +msgid "Failed to retrieve advanced type" +msgstr "Napaka pri pridobivanju naprednega tipa" + +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:101 +msgid "choose WHERE or HAVING..." +msgstr "izberite WHERE ali HAVING..." -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:280 -msgid "Toggle chart description" -msgstr "Preklopi opis grafikona" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:134 +msgid "Filters by columns" +msgstr "Filtrira po stolpcu" -#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:25 -msgid "Tools" -msgstr "Orodja" +#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:136 +msgid "Filters by metrics" +msgstr "Filtrira po merah" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:184 -msgid "Tooltip" -msgstr "Opis orodja" +#: superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx:149 +msgid "Fixed" +msgstr "Fiksno" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:172 -msgid "Tooltip sort by metric" -msgstr "Mera za razvrščanje opisa orodja" +#: superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx:165 +msgid "Based on a metric" +msgstr "Osnovan na meri" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:162 -msgid "Tooltip time format" -msgstr "Oblika zapisa časa v opisu orodja" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx:55 +msgid "My metric" +msgstr "Moja mera" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:289 -msgid "Top" -msgstr "Zgoraj" +#: superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.jsx:336 +msgid "Add metric" +msgstr "Dodaj mero" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:139 -msgid "Top to Bottom" -msgstr "Iz vrha proti dnu" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:309 +msgid "Select aggregate options" +msgstr "Izberite agregacijske možnosti" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:439 -msgid "Totals" -msgstr "Vsote" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:310 +#, python-format +msgid "%s aggregates(s)" +msgstr "Agreg. funkcije: %s" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:820 -msgid "Track job" -msgstr "Sledi opravilom" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:318 +msgid "Select saved metrics" +msgstr "Izberite shranjene mere" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:40 -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:46 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:77 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:83 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:82 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:76 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:77 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:67 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:76 -msgid "Transformable" -msgstr "Prilagodljiv" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:319 +#, python-format +msgid "%s saved metric(s)" +msgstr "Shranjene mere: %s" -#: superset-frontend/src/dashboard/util/backgroundStyleOptions.ts:25 -msgid "Transparent" -msgstr "Prozorno" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:369 +msgid "Saved metric" +msgstr "Shranjena mera" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:110 -msgid "Transpose Pivot" -msgstr "Transponirano vrtenje" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:385 +msgid "No saved metrics found" +msgstr "Shranjene mere niso najdene" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:173 -msgid "Transpose pivot" -msgstr "Transponirano vrtenje" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:386 +msgid "Add metrics to dataset in \"Edit datasource\" modal" +msgstr "Dodaj mero v podatkovni set v oknu \"Uredi podatkovni vir\"" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:39 -msgid "Tree Chart" -msgstr "Drevesni grafikon" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:397 +msgid "Simple ad-hoc metrics are not enabled for this dataset" +msgstr "Preproste ad-hoc mere za ta podatkovni set niso omogočene" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:117 -msgid "Tree layout" -msgstr "Oblika drevesa" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:409 +msgid "column" +msgstr "stolpec" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:134 -msgid "Tree orientation" -msgstr "Orientacija drevesa" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:420 +msgid "aggregate" +msgstr "agregacija" -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:40 -#: superset/viz.py:1003 -msgid "Treemap" -msgstr "Drevesni grafikon s pravokotniki" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:439 +msgid "Custom SQL ad-hoc metrics are not available for the native Druid connector" +msgstr "Ad-hoc SQL mere po meri niso na voljo za nativni konektor za Druid" -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:56 -msgid "Treemap v2" -msgstr "Drevesni grafikon s pravokotniki v2" +#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:442 +msgid "Custom SQL ad-hoc metrics are not enabled for this dataset" +msgstr "Ad-hoc SQL mere po meri za ta podatkovni set niso omogočene" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:37 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:37 -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:43 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:53 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:39 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:38 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:40 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:59 -#: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:36 -msgid "Trend" -msgstr "Trend" +#: superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx:89 +#, python-format +msgid "Error while fetching data: %s" +msgstr "Napaka pri pridobivanju podatkov: %s" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:226 -msgid "Triangle" -msgstr "Trikotnik" +#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:48 +#: superset-frontend/src/visualizations/TimeTable/controlPanel.js:38 +msgid "Time series columns" +msgstr "Stolpci s časovnimi vrstami" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1168 -msgid "Trigger Alert If..." -msgstr "Sproži opozorilo v primeru ..." +#: superset-frontend/src/explore/components/controls/VizTypeControl/FastVizSwitcher.tsx:83 +msgid "Select Viz Type" +msgstr "Izberite tip vizualizacije" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:340 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:255 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:218 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:198 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:215 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:271 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:274 -msgid "Truncate Y Axis" -msgstr "Prireži Y-os" +#: superset-frontend/src/explore/components/controls/VizTypeControl/FastVizSwitcher.tsx:120 +#, python-format +msgid "Currently rendered: %s" +msgstr "Trenutno izrisano: %s" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:343 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:258 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:201 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:218 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:274 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:277 -msgid "Truncate Y Axis. Can be overridden by specifying a min or max bound." -msgstr "" -"Prireži Y-os. Če določite spodnjo ali zgornjo mejo, preprečite " -"prirezovanje." +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:124 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:734 +msgid "Other" +msgstr "Ostali" -#: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:58 -msgid "Truncates the specified date to the accuracy specified by the date unit." -msgstr "Zaokroži določen datum, glede na natančnost, definirano s časovno enoto." +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:666 +msgid "Recommended tags" +msgstr "Priporočene značke" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:222 -msgid "Try applying different filters or ensuring your datasource has data" -msgstr "" -"Poskusite uporabiti druge filtre oz. zagotovite, da so v podatkovnem viru" -" podatki" +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:671 +msgid "Category" +msgstr "Kategorija" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:58 -msgid "Tuesday" -msgstr "Torek" +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:676 +msgid "Tags" +msgstr "Značke" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:215 -#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:219 -#: superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/index.jsx:276 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:288 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:466 -#: superset/connectors/druid/views.py:92 superset/connectors/druid/views.py:190 -#: superset/connectors/sqla/views.py:152 superset/connectors/sqla/views.py:258 -msgid "Type" -msgstr "Tip" +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:772 +msgid "Search all charts" +msgstr "Išči vse grafikone" -#: superset-frontend/src/components/DeleteModal/index.tsx:92 -#: superset-frontend/src/components/ImportModal/index.tsx:253 -#, python-format -msgid "Type \"%s\" to confirm" -msgstr "Vnesite \"%s\" za potrditev" +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:838 +msgid "No description available." +msgstr "Opisa ni na razpolago." -#: superset-frontend/src/components/ListView/Filters/Search.tsx:71 -msgid "Type a value" -msgstr "Vnesite vrednost" +#: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:845 +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:183 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:197 +msgid "Examples" +msgstr "Vzorci" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:319 -msgid "Type a value here" -msgstr "Vnesite vrednost sem" +#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:63 +msgid "This visualization type is not supported." +msgstr "Ta tip vizualizacije ni podprt." -#: superset/reports/commands/exceptions.py:71 -msgid "Type is required" -msgstr "Tip je obvezen" +#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:125 +msgid "View all charts" +msgstr "Pokaži vse grafikone" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:73 -msgid "Type of Google Sheets allowed" -msgstr "Dovoljeni tipi Googlovih preglednic" +#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:131 +msgid "Select a visualization type" +msgstr "Izberite tip vizualizacije" -#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:379 -#, python-format -msgid "Type or Select [%s]" -msgstr "Vnesite ali izberite [%s]" +#: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:132 +msgid "Select" +msgstr "Izberi" -#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:51 -#: superset-frontend/src/filters/components/Range/controlPanel.ts:47 -#: superset-frontend/src/filters/components/Select/controlPanel.ts:57 -#: superset-frontend/src/filters/components/Time/controlPanel.ts:45 -#: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:25 -#: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:25 -msgid "UI Configuration" -msgstr "UI nastavitve" +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:122 +msgid "Superset Chart" +msgstr "Superset grafikon" -#: superset-frontend/src/explore/controlPanels/TimeTable.js:51 -msgid "URL" -msgstr "URL" +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:205 +msgid "New chart" +msgstr "Nov grafikon" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:76 -msgid "URL Parameters" -msgstr "Parametri URL" +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:261 +msgid "Edit chart properties" +msgstr "Uredi lastnosti grafikona" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:125 -#, fuzzy -msgid "URL could not be identified" -msgstr "Grafikona ni mogoče izbrisati." +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:274 +msgid "Export to original .CSV" +msgstr "Izvozi v izvorni .CSV" -#: superset-frontend/src/explore/controlPanels/sections.tsx:60 -msgid "URL parameters" -msgstr "Parametri URL" +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:281 +msgid "Export to pivoted .CSV" +msgstr "Izvozi v vrtilni .CSV" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:514 -msgid "URL slug" -msgstr "URL slug" +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:294 +msgid "Export to .JSON" +msgstr "Izvozi v .JSON" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:531 -msgid "Unable to add a new tab to the backend. Please contact your administrator." -msgstr "Novega zavihka ni mogoče dodati v sistem. Kontaktirajte administratorja." +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:313 +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:315 +msgid "Embed code" +msgstr "Vgradi kodo" -#: superset/db_engine_specs/presto.py:218 -#, python-format -msgid "Unable to connect to catalog named \"%(catalog_name)s\"." -msgstr "Povezava na katalog \"%(catalog_name)s\" ni uspela." +#: superset-frontend/src/explore/components/useExploreAdditionalActionsMenu/index.jsx:370 +msgid "Run in SQL Lab" +msgstr "Zaženi v SQL laboratoriju" -#: superset/db_engine_specs/mysql.py:139 -#: superset/db_engine_specs/postgres.py:145 -#, python-format -msgid "Unable to connect to database \"%(database)s\"." -msgstr "Povezava s podatkovno bazo \"%(database)s\" ni uspela." +#: superset-frontend/src/explore/controlPanels/Separator.js:25 +#: superset-frontend/src/explore/controlPanels/Separator.js:46 +msgid "Code" +msgstr "Koda" -#: superset/utils/date_parser.py:390 -#, python-format -msgid "Unable to find such a holiday: [%(holiday)s]" -msgstr "Ni mogoče najti takšnega praznika: [%(holiday)s]" +#: superset-frontend/src/explore/controlPanels/Separator.js:32 +msgid "Markup type" +msgstr "Tip označevanja" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:498 -msgid "" -"Unable to migrate query editor state to backend. Superset will retry " -"later. Please contact your administrator if this problem persists." -msgstr "" -"Stanja urejevalnika poizvedb ni mogoče prenesti v sistem. Superset bo " -"ponovil poskus kasneje. Če se težava ponavlja, kontaktirajte " -"administratorja." +#: superset-frontend/src/explore/controlPanels/Separator.js:37 +msgid "Pick your favorite markup language" +msgstr "Izberite svoj priljubljen označevalni jezik" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:452 -msgid "" -"Unable to migrate query state to backend. Superset will retry later. " -"Please contact your administrator if this problem persists." -msgstr "" -"Stanja poizvedbe ni mogoče prenesti v sistem. Superset bo ponovil poskus " -"kasneje. Če se težava ponavlja, kontaktirajte administratorja." +#: superset-frontend/src/explore/controlPanels/Separator.js:47 +msgid "Put your code here" +msgstr "Vstavite svojo kodo sem" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:434 -msgid "" -"Unable to migrate table schema state to backend. Superset will retry " -"later. Please contact your administrator if this problem persists." -msgstr "" -"Stanja sheme tabele ni mogoče prenesti v sistem. Superset bo ponovil " -"poskus kasneje. Če se težava ponavlja, kontaktirajte administratorja." +#: superset-frontend/src/explore/controlPanels/sections.tsx:60 +msgid "URL parameters" +msgstr "Parametri URL" -#: superset/connectors/sqla/views.py:641 -#, python-format -msgid "Unable to refresh metadata for the following table(s): %(tables)s" -msgstr "Ni mogoče osvežiti metapodatkov za naslednje tabele: %(tables)s" +#: superset-frontend/src/explore/controlPanels/sections.tsx:62 +msgid "Extra parameters for use in jinja templated queries" +msgstr "Dodatni parametri za poizvedbe z jinja predlogami" -#: superset/views/database/views.py:240 -#, python-format -msgid "" -"Unable to upload CSV file \"%(filename)s\" to table \"%(table_name)s\" in" -" database \"%(db_name)s\". Error message: %(error_msg)s" -msgstr "" -"CSV datoteke \"%(filename)s\" ni mogoče naložiti v tabelo " -"\"%(table_name)s\" v podatkovni bazi \"%(db_name)s\". Sporočilo napake: " -"%(error_msg)s" +#: superset-frontend/src/explore/controlPanels/sections.tsx:82 +msgid "Annotations and layers" +msgstr "Oznake in sloji" -#: superset/views/database/views.py:538 -#, python-format -msgid "" -"Unable to upload Columnar file \"%(filename)s\" to table " -"\"%(table_name)s\" in database \"%(db_name)s\". Error message: " -"%(error_msg)s" -msgstr "" -"Stolpčne datoteke \"%(filename)s\" ni mogoče naložiti v tabelo " -"\"%(table_name)s\" v podatkovni bazi \"%(db_name)s\". Sporočilo napake: " -"%(error_msg)s" +#: superset-frontend/src/explore/controlUtils/controlUtils.test.tsx:73 +msgid "My beautiful colors" +msgstr "Moje čudovite barve" + +#: superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx:84 +msgid "No columns" +msgstr "Brez stolpcev" -#: superset/views/database/views.py:386 +#: superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx:85 +#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:260 +#: superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx:84 +#: superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx:94 #, python-format -msgid "" -"Unable to upload Excel file \"%(filename)s\" to table \"%(table_name)s\" " -"in database \"%(db_name)s\". Error message: %(error_msg)s" -msgstr "" -"Excel datoteke \"%(filename)s\" ni mogoče naložiti v tabelo " -"\"%(table_name)s\" v podatkovni bazi \"%(db_name)s\". Sporočilo napake: " -"%(error_msg)s" +msgid "%s option" +msgstr "%s možnost" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:75 -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:114 -msgid "Undefined" -msgstr "Ni definirano" +#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:51 +#: superset-frontend/src/filters/components/Range/controlPanel.ts:47 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:57 +#: superset-frontend/src/filters/components/Time/controlPanel.ts:45 +#: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:25 +#: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:25 +msgid "UI Configuration" +msgstr "UI nastavitve" -#: superset/utils/pandas_postprocessing.py:391 -msgid "Undefined window for rolling operation" -msgstr "Nedefinirano okno za drsečo operacijo" +#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:59 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:77 +msgid "Can select multiple values" +msgstr "Dovoli izbiro več vrednosti" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx:126 -msgid "Undo?" -msgstr "Povrni?" +#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:72 +#: superset-frontend/src/filters/components/Range/controlPanel.ts:55 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:90 +#: superset-frontend/src/filters/components/Time/controlPanel.ts:53 +#: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:33 +#: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:33 +msgid "Filter value is required" +msgstr "Vrednost filtra je obvezna" -#: superset-frontend/src/components/ErrorBoundary/index.jsx:51 -#: superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx:26 -msgid "Unexpected error" -msgstr "Nepričakovana napaka" +#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:75 +#: superset-frontend/src/filters/components/Range/controlPanel.ts:58 +#: superset-frontend/src/filters/components/Select/controlPanel.ts:93 +#: superset-frontend/src/filters/components/Time/controlPanel.ts:56 +#: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:36 +#: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:36 +msgid "User must select a value before applying the filter" +msgstr "Uporabnik mora izbrati vrednost pred uporabo filtra" -#: superset/databases/commands/exceptions.py:135 superset/views/core.py:1391 -msgid "Unexpected error occurred, please check your logs for details" -msgstr "Zgodila se je nepričakovana napaka. Podrobnosti preverite v dnevnikih" +#: superset-frontend/src/filters/components/GroupBy/index.ts:29 +msgid "Group By filter plugin" +msgstr "Vtičnik za filter za združevanje" -#: superset-frontend/src/utils/getClientErrorObject.ts:55 -msgid "Unexpected error: " -msgstr "Nepričakovana napaka: " +#: superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx:283 +msgid "Chosen non-numeric column" +msgstr "Izbran ne-numeričen stolpec" -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:95 -msgid "Unknown" -msgstr "Neznano" +#: superset-frontend/src/filters/components/Range/controlPanel.ts:67 +msgid "Single value" +msgstr "Ena vrednost" -#: superset/db_engine_specs/mysql.py:129 -#, python-format -msgid "Unknown MySQL server host \"%(hostname)s\"." -msgstr "Neznan MySQL strežnik \"%(hostname)s\"." +#: superset-frontend/src/filters/components/Range/controlPanel.ts:70 +msgid "Use only a single value." +msgstr "Uporabite le eno vrednost." -#: superset/db_engine_specs/presto.py:1005 -msgid "Unknown Presto Error" -msgstr "Neznana Presto napaka" +#: superset-frontend/src/filters/components/Range/index.ts:29 +msgid "Range filter plugin using AntD" +msgstr "Vtičnik za filter obdobja z uporabo AntD" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:111 -msgid "Unknown Status" -msgstr "Neznan status" +#: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:125 +msgid " (excluded)" +msgstr " (ni vključeno)" -#: superset/connectors/sqla/models.py:1121 -#, python-format -msgid "Unknown column used in orderby: %(col)s" -msgstr "Za razvrščanje je uporabljen neznan stolpec: %(col)s" +#: superset-frontend/src/filters/components/Select/controlPanel.ts:104 +msgid "Select first filter value by default" +msgstr "Izberi prvo vrednost kot privzeto" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:349 -#: superset-frontend/src/SqlLab/actions/sqlLab.js:389 -msgid "Unknown error" -msgstr "Neznana napaka" +#: superset-frontend/src/filters/components/Select/controlPanel.ts:110 +msgid "When using this option, default value can’t be set" +msgstr "Če uporabite to možnost, privzeta vrednost ne more biti nastavljena" -#: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:45 -msgid "Unknown value" -msgstr "Neznana vrednost" +#: superset-frontend/src/filters/components/Select/controlPanel.ts:123 +msgid "Inverse selection" +msgstr "Invertiraj izbiro" -#: superset/jinja_context.py:347 -#, python-format -msgid "Unsafe return type for function %(func)s: %(value_type)s" -msgstr "Nevaren tip rezultata, ki ga vrne funkcija %(func)s: %(value_type)s" +#: superset-frontend/src/filters/components/Select/controlPanel.ts:125 +msgid "Exclude selected values" +msgstr "Izloči izbrane vrednosti" -#: superset/jinja_context.py:371 -#, python-format -msgid "Unsafe template value for key %(key)s: %(value_type)s" -msgstr "Nevaren vzorec za ključ %(key)s: %(value_type)s" +#: superset-frontend/src/filters/components/Select/controlPanel.ts:136 +msgid "Dynamically search all filter values" +msgstr "Dinamično poišče vse možnosti filtra" -#: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:255 -#, python-format -msgid "Unset Filters (%d)" -msgstr "Neuporabljeni filtri (%d)" +#: superset-frontend/src/filters/components/Select/index.ts:29 +msgid "Select filter plugin using AntD" +msgstr "Izberite Vtičnik za filter z uporabo AntD" -#: superset/utils/core.py:1048 -#, python-format -msgid "Unsupported clause type: %(clause)s" -msgstr "Nepodprt tip izraza: %(clause)s" +#: superset-frontend/src/filters/components/Time/index.ts:28 +msgid "Custom time filter plugin" +msgstr "Prilagojeni vtičnik za časovni filter" -#: superset/connectors/druid/models.py:1492 -msgid "Unsupported extraction function: " -msgstr "Nepodprta ekstrakcijska funkcija: " +#: superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx:83 +msgid "No time columns" +msgstr "Ni časovnih stolpcev" -#: superset/common/query_object.py:392 -#, python-format -msgid "Unsupported post processing operation: %(operation)s" -msgstr "Nepodprta poprocesirna operacija: %(operation)s" +#: superset-frontend/src/filters/components/TimeColumn/index.ts:29 +msgid "Time column filter plugin" +msgstr "Vtičnik za časovni filter" -#: superset/jinja_context.py:358 -#, python-format -msgid "Unsupported return value for method %(name)s" -msgstr "Nepodprt rezultat vračanja za metodo %(name)s" +#: superset-frontend/src/filters/components/TimeGrain/index.ts:29 +msgid "Time grain filter plugin" +msgstr "Vtičnik za filter časovne granulacije" -#: superset/jinja_context.py:382 -#, python-format -msgid "Unsupported template value for key %(key)s" -msgstr "Nepodprta vrednost vzorca za ključ %(key)s" +#: superset-frontend/src/profile/components/App.tsx:52 +msgid "Favorites" +msgstr "Priljubljene" -#: superset/utils/pandas_postprocessing.py:818 -#, python-format -msgid "Unsupported time grain: %(time_grain)s" -msgstr "Nepodprta časovna granulacija: %(time_grain)s" +#: superset-frontend/src/profile/components/App.tsx:62 +msgid "Created content" +msgstr "Ustvarjena vsebina" -#: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:264 -#, python-format -msgid "Untitled Query %s" -msgstr "Neimenovana poizvedba %s" +#: superset-frontend/src/profile/components/App.tsx:72 +msgid "Recent activity" +msgstr "Nedavna aktivnost" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:331 -#: superset-frontend/src/SqlLab/reducers/getInitialState.js:44 -msgid "Untitled query" -msgstr "Neimenovana poizvedba" +#: superset-frontend/src/profile/components/App.tsx:82 +msgid "Security & Access" +msgstr "Varnost in Dostopi" -#: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:190 -msgid "Update" -msgstr "Posodobi" +#: superset-frontend/src/profile/components/CreatedContent.tsx:46 +msgid "No charts" +msgstr "Ni grafikonov" -#: superset-frontend/src/chart/chartReducer.ts:82 -msgid "Updating chart was stopped" -msgstr "Posodabljanje grafikona je bilo ustavljeno" +#: superset-frontend/src/profile/components/CreatedContent.tsx:74 +msgid "No dashboards" +msgstr "Ni nadzornih plošč" -#: superset/templates/superset/import_dashboards.html:63 -msgid "Upload" -msgstr "Naloži" +#: superset-frontend/src/profile/components/Favorites.tsx:47 +msgid "No favorite charts yet, go click on stars!" +msgstr "Priljubljenih grafikonov še ni. Kliknite na zvezdice!" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:134 -msgid "Upload Credentials" -msgstr "Naloži prijavne podatke" +#: superset-frontend/src/profile/components/Favorites.tsx:75 +msgid "No favorite dashboards yet, go click on stars!" +msgstr "Priljubljenih nadzornih plošč še ni. Kliknite na zvezdice!" -#: superset/initialization/__init__.py:400 -msgid "Upload Excel" -msgstr "Naloži Excel" +#: superset-frontend/src/profile/components/UserInfo.tsx:44 +msgid "Profile picture provided by Gravatar" +msgstr "Profilno sliko je zagotovil Gravatar" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:102 -msgid "Upload JSON file" -msgstr "Naloži JSON datoteko" +#: superset-frontend/src/profile/components/UserInfo.tsx:64 +msgid "joined" +msgstr "pridružen" -#: superset/initialization/__init__.py:369 -msgid "Upload a CSV" -msgstr "Naloži CSV" +#: superset-frontend/src/profile/components/UserInfo.tsx:75 +msgid "id:" +msgstr "id:" -#: superset/initialization/__init__.py:383 -msgid "Upload a Columnar File" -msgstr "Naloži datoteko s stolpci" +#: superset-frontend/src/reports/actions/reports.js:67 +msgid "There was an issue fetching reports attached to this dashboard." +msgstr "Pri pridobivanju poročil za to nadzorno ploščo je prišlo do težave." -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:112 -msgid "Use Area Proportions" -msgstr "Uporabi razmerje površin" +#: superset-frontend/src/reports/actions/reports.js:109 +msgid "The report has been created" +msgstr "Poročilo je bilo ustvarjeno" -#: superset/views/database/forms.py:175 superset/views/database/forms.py:433 -msgid "Use Columns" -msgstr "Uporabi stolpce" +#: superset-frontend/src/reports/actions/reports.js:120 +msgid "Report updated" +msgstr "Poročilo posodobljeno" -#: superset/views/database/forms.py:211 -msgid "Use Pandas to interpret the datetime format automatically." -msgstr "Uporabi Pandas za samodejno prepoznavo oblike datumov/časov." +#: superset-frontend/src/reports/actions/reports.js:135 +msgid "We were unable to active or deactivate this report." +msgstr "Aktiviranje ali deaktiviranje poročila ni uspelo." -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:207 -msgid "Use a log scale" -msgstr "Uporabi logaritemsko skalo" +#: superset-frontend/src/reports/actions/reports.js:151 +msgid "Your report could not be deleted" +msgstr "Vašega poročila ni mogoče izbrisati" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:107 -msgid "Use a log scale for the X-axis" -msgstr "Uporabi logaritemsko skalo za X-os" +#: superset-frontend/src/reports/actions/reports.js:155 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:161 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:117 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:90 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:93 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:153 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:601 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:234 +#: superset-frontend/src/views/CRUD/utils.tsx:274 +#: superset-frontend/src/views/CRUD/utils.tsx:313 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:173 +#, python-format +msgid "Deleted: %s" +msgstr "Izbrisano: %s" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:230 -msgid "Use a log scale for the Y-axis" -msgstr "Uporabi logaritemsko skalo za Y-os" +#: superset-frontend/src/utils/downloadAsImage.ts:62 +msgid "Image download failed, please refresh and try again." +msgstr "Prenos slike ni uspel. Osvežite in poskusite ponovno." -#: superset/db_engine_specs/base.py:1401 -msgid "Use an encrypted connection to the database" -msgstr "Uporabite šifrirano povezavo s podatkovno bazo" +#: superset-frontend/src/utils/getChartRequiredFieldsMissingMessage.ts:23 +#, python-format +msgid "" +"Select values in highlighted field(s) in the control panel. Then run the query by " +"clicking on the %s button." +msgstr "" +"Izberite vrednosti v osvetljenih poljih na levi strani kontrolnika in zaženite " +"poizvedbo z gumbom %s." -#: superset-frontend/src/components/Datasource/DatasourceModal.tsx:209 -msgid "Use legacy datasource editor" -msgstr "Uporabi starejši urejevalnik podatkovnega vira" +#: superset-frontend/src/utils/getClientErrorObject.ts:56 +msgid "Invalid input" +msgstr "Neveljaven vnos" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:85 -msgid "Use metrics as a top level group for columns or for rows" -msgstr "Uporabi mere kot vrhovni nivo grupiranja za stolpce ali vrstice" +#: superset-frontend/src/utils/getClientErrorObject.ts:62 +msgid "Unexpected error: " +msgstr "Nepričakovana napaka: " -#: superset-frontend/src/filters/components/Range/controlPanel.ts:68 -msgid "Use only a single value." -msgstr "" +#: superset-frontend/src/utils/getClientErrorObject.ts:63 +msgid "(no description, click to see stack trace)" +msgstr "(ni opisa, kliknite za ogled zapisov)" -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:124 -msgid "Use the Advanced Analytics options below" -msgstr "Uporabite spodnje možnosti napredne analitike" +#: superset-frontend/src/utils/getClientErrorObject.ts:96 +msgid "Network error" +msgstr "Napaka omrežja" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:136 -msgid "" -"Use the JSON file you automatically downloaded when creating your service" -" account." -msgstr "" -"Uporabite JSON datoteko, ki ste jo prenesli pri ustvarjanju servisnega " -"računa." +#: superset-frontend/src/utils/getClientErrorObject.ts:108 +msgid "Request timed out" +msgstr "Zahtevek pretečen" -#: superset/templates/superset/fab_overrides/list_with_checkboxes.html:82 -msgid "Use the edit buttom to change this field" -msgstr "Za spreminjanje tega polja uporabite gumb za urejanje" +#: superset-frontend/src/utils/getClientErrorObject.ts:117 +msgid "Issue 1000 - The dataset is too large to query." +msgstr "Težava 1000 - podatkovni vir je prevelik za poizvedbo." -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:176 -#: superset-frontend/src/explore/controls.jsx:207 -msgid "Use this to define a static color for all circles" -msgstr "S tem definirate določeno barvo za vse kroge" +#: superset-frontend/src/utils/getClientErrorObject.ts:121 +msgid "Issue 1001 - The database is under an unusual load." +msgstr "Težava 1001 - podatkovni vir je neobičajno obremenjen." -#: superset/views/dynamic_plugins.py:48 -msgid "" -"Used internally to identify the plugin. Should be set to the package name" -" from the pluginʼs package.json" -msgstr "" -"Uporablja se za interno identifikacijo vtičnika. Naj bo nastavljeno na " -"ime paketa v vtičnikovem package.json" +#: superset-frontend/src/views/CRUD/hooks.ts:103 +#, python-format +msgid "An error occurred while fetching %s info: %s" +msgstr "Napaka pri pridobivanju informacij za %s: %s" -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:27 -#, fuzzy -msgid "" -"Used to summarize a set of data by grouping together multiple statistics " -"along two axes. Examples: Sales numbers by region and month, tasks by " -"status and assignee, active users by age and location.\n" -"\n" -" This chart is being deprecated and we recommend checking out Pivot " -"Table V2 instead!" -msgstr "" -"Uporablja se za predstavitev podatkov z združevanjem različnih statistik " -"na dveh oseh. Npr. Prodaja po regijah in mesecih, Naloge po statusih in " -"izvajalcih, aktivni uporabniki po starosti in lokaciji.\r\n" -"\r\n" -" Ta grafikon se opušča. Priporočamo uporabo Vrtilne tabele V2!" +#: superset-frontend/src/views/CRUD/hooks.ts:171 +#: superset-frontend/src/views/CRUD/hooks.ts:258 +#: superset-frontend/src/views/CRUD/hooks.ts:344 +#, python-format +msgid "An error occurred while fetching %ss: %s" +msgstr "Napaka pri pridobivanju informacij za %s: %s" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:51 -msgid "" -"Used to summarize a set of data by grouping together multiple statistics " -"along two axes. Examples: Sales numbers by region and month, tasks by " -"status and assignee, active users by age and location. Not the most " -"visually stunning visualization, but highly informative and versatile." -msgstr "" -"Ponazori podatke na podlagi združevanja več statistik vzdolž dveh osi. " -"Npr. prodaja po regijah in mesecih, opravila po statusih in izvajalcih, " -"itd." +#: superset-frontend/src/views/CRUD/hooks.ts:301 +#, python-format +msgid "An error occurred while creating %ss: %s" +msgstr "Napaka pri ustvarjanju %s: %s" -#: superset-frontend/src/components/Menu/MenuRight.tsx:158 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:275 -#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:365 -#: superset/views/access_requests.py:41 superset/views/log/__init__.py:30 -#: superset/views/schedules.py:239 superset/views/schedules.py:319 -#: superset/views/sql_lab.py:69 -msgid "User" -msgstr "Uporabnik" +#: superset-frontend/src/views/CRUD/hooks.ts:451 +#: superset-frontend/src/views/CRUD/hooks.ts:467 +#, python-format +msgid "An error occurred while importing %s: %s" +msgstr "Napaka pri uvažanju %s: %s" -#: superset/views/access_requests.py:42 -msgid "User Roles" -msgstr "Vloge uporabnikov" +#: superset-frontend/src/views/CRUD/hooks.ts:538 +#, python-format +msgid "There was an error fetching the favorite status: %s" +msgstr "Napaka pri pridobivanju statusa \"Priljubljeno\": %s" + +#: superset-frontend/src/views/CRUD/hooks.ts:559 +#, python-format +msgid "There was an error saving the favorite status: %s" +msgstr "Napaka pri shranjevanju statusa \"Priljubljeno\": %s" -#: superset/errors.py:112 -msgid "User doesn't have the proper permissions." -msgstr "Uporabnik nima ustreznih dovoljenj." +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:218 +#: superset-frontend/src/views/CRUD/hooks.ts:620 +msgid "Link Copied!" +msgstr "Povezava kopirana!" -#: superset-frontend/src/filters/components/Select/controlPanel.ts:94 -msgid "User must select a value before applying the filter" -msgstr "Uporabnik mora izbrati vrednost pred uporabo filtra" +#: superset-frontend/src/views/CRUD/data/components/SyntaxHighlighterCopy/index.tsx:76 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:221 +#: superset-frontend/src/views/CRUD/hooks.ts:623 +msgid "Sorry, your browser does not support copying." +msgstr "Vaš brskalnik ne podpira kopiranja." -#: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:253 -msgid "User must select a value for this filter" -msgstr "Uporabnik mora izbrati vrednost za ta filter" +#: superset-frontend/src/views/CRUD/hooks.ts:644 +msgid "Connection looks good!" +msgstr "Povezava izgleda v redu!" -#: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:76 -#: superset-frontend/src/filters/components/Range/controlPanel.ts:58 -#: superset-frontend/src/filters/components/Time/controlPanel.ts:56 -#: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:36 -#: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:36 -msgid "User must select a value for this filter." -msgstr "Uporabnik mora izbrati vrednost za ta filter." +#: superset-frontend/src/views/CRUD/hooks.ts:647 +#, python-format +msgid "ERROR: %s" +msgstr "NAPAKA: %s" -#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:154 -msgid "User query" -msgstr "Uporabnikova poizvedba" +#: superset-frontend/src/views/CRUD/utils.tsx:209 +msgid "There was an error fetching your recent activity:" +msgstr "Pri pridobivanju nedavnih aktivnosti je prišlo do napake:" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:109 -#: superset/db_engine_specs/base.py:1388 -msgid "Username" -msgstr "Uporabniško ime" +#: superset-frontend/src/views/CRUD/utils.tsx:277 +#, python-format +msgid "There was an issue deleting: %s" +msgstr "Težava pri brisanju: %s" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:39 -msgid "" -"Uses a gauge to showcase progress of a metric towards a target. The " -"position of the dial represents the progress and the terminal value in " -"the gauge represents the target value." -msgstr "" -"Uporablja števec za prikaz napredovanja mere k ciljni vrednosti. Položaj " -"kazalca predstavlja napredek, končna vrednost na števcu pa ciljno " -"vrednost." +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:164 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:121 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:93 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:97 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:159 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:605 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:237 +#: superset-frontend/src/views/CRUD/utils.tsx:317 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:176 +#, python-format +msgid "There was an issue deleting %s: %s" +msgstr "Težava pri brisanju %s: %s" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:28 -msgid "" -"Uses circles to visualize the flow of data through different stages of a " -"system. Hover over individual paths in the visualization to understand " -"the stages a value took. Useful for multi-stage, multi-group visualizing " -"funnels and pipelines." -msgstr "" -"S pomočjo krogov prikaže potek podatkov na različnih nivojih sistema. S " -"premikom kurzorja prikaže vrednosti na posameznem nivoju. Uporabno za " -"večnivojsko, večskupinsko vizualizacijo." +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:54 +msgid "Working" +msgstr "Delam" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:294 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1186 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1202 -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:140 -msgid "Value" -msgstr "Vrednost" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:56 +msgid "Not triggered" +msgstr "Ni sproženo" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:91 -msgid "Value Domain" -msgstr "Domena vrednosti" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:57 +msgid "On Grace" +msgstr "V mirovanju" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:329 -msgid "Value Format" -msgstr "Oblika zapisa vrednosti" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:89 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:489 +msgid "report" +msgstr "poročilo" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:235 -msgid "Value bounds" -msgstr "Meje vrednosti" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:89 +msgid "alert" +msgstr "opozorilo" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:165 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:206 -msgid "Value format" -msgstr "Oblika zapisa vrednosti" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:90 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:116 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:125 +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:75 +msgid "reports" +msgstr "poročila" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx:75 -msgid "Value is required" -msgstr "Zahtevana je vrednost" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:90 +msgid "alerts" +msgstr "opozorila" -#: superset/reports/schemas.py:185 superset/reports/schemas.py:191 -#: superset/reports/schemas.py:197 superset/reports/schemas.py:275 -#: superset/reports/schemas.py:281 superset/reports/schemas.py:288 -msgid "Value must be greater than 0" -msgstr "Vrednost mora biti večja od 0" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:179 +#, python-format +msgid "There was an issue deleting the selected %s: %s" +msgstr "Težava pri brisanju izbranih %s: %s" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:39 -msgid "Vehicle Types" -msgstr "Vrste vozil" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:227 +msgid "Last run" +msgstr "Zadnji zagon" -#: superset/connectors/druid/views.py:189 -#: superset/connectors/druid/views.py:238 superset/connectors/sqla/views.py:144 -#: superset/connectors/sqla/views.py:257 -msgid "Verbose Name" -msgstr "Podrobno ime" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:262 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1387 +msgid "Notification method" +msgstr "Način obveščanja" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:482 -msgid "Version" -msgstr "Verzija" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:273 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:417 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:211 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:285 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:361 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:507 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:192 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:273 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:326 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:479 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:349 +msgid "Created by" +msgstr "Ustvaril" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:489 -msgid "Version number" -msgstr "Številka verzije" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:308 +msgid "Active" +msgstr "Aktiven" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:41 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:48 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:84 -msgid "Vertical" -msgstr "Navpično" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:325 +msgid "Execution log" +msgstr "Dnevnik izvajanja" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:38 -msgid "Video game consoles" -msgstr "Igralne konzole" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:353 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:203 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:248 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:448 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:229 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:420 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:432 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:448 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:309 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:415 +msgid "Actions" +msgstr "Aktivnosti" -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:217 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:219 -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:296 -msgid "View All »" -msgstr "" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:380 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:226 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:276 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:640 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:262 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:593 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:550 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:169 +msgid "Bulk select" +msgstr "Izberi hkrati" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:287 -msgid "View chart in Explore" -msgstr "Ogled grafikona v Raziskovalcu" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:388 +#, python-format +msgid "No %s yet" +msgstr "%s še ne obstajajo" -#: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:197 -msgid "View in SQL Lab" -msgstr "Ogled v SQL laboratoriju" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:401 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:486 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:458 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:460 +msgid "Owner" +msgstr "Lastnik" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:166 +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:410 #, python-format -msgid "View keys & indexes (%s)" -msgstr "Ogled ključev in indeksov (%s)" +msgid "An error occurred while fetching owners values: %s" +msgstr "Pri pridobivanju polja lastnik je prišlo do napake: %s" -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:296 -#: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:298 -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:86 -#: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:88 -msgid "View query" -msgstr "Ogled poizvedbe" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:426 +#, python-format +msgid "An error occurred while fetching created by values: %s" +msgstr "Pri pridobivanju vrednosti \"Ustvaril\" je prišlo do napake: %s" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:216 -#: superset-frontend/src/explore/components/DataTablesPane/index.tsx:396 -msgid "View results" -msgstr "Ogled rezultatov" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:433 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:305 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:500 +msgid "Status" +msgstr "Status" -#: superset-frontend/src/explore/components/DataTablesPane/index.tsx:409 -msgid "View samples" -msgstr "Ogled vzorcev" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:466 +msgid "Alerts & reports" +msgstr "Opozorila in poročila" -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:180 -msgid "Viewed" -msgstr "Ogledane" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:470 +msgid "Alerts" +msgstr "Opozorila" -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:124 -#, fuzzy, python-format -msgid "Viewed %s" -msgstr "Ogledane" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:477 +msgid "Reports" +msgstr "Poročila" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:268 -msgid "Viewport" -msgstr "Pogled" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:515 +#, python-format +msgid "Delete %s?" +msgstr "Izbrišem %s?" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:133 -msgid "Virtual (SQL)" -msgstr "Virtualen (SQL)" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:519 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:297 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:357 +#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:78 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:385 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:687 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:325 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:106 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:358 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:632 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:664 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:501 +msgid "Please confirm" +msgstr "Prosim, potrdite" -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:231 -msgid "Virtual dataset" -msgstr "Virtualen podatkovni set" +#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:520 +#, python-format +msgid "Are you sure you want to delete the selected %s?" +msgstr "Ali ste prepričani, da želite izbrisati izbrane %s?" -#: superset/connectors/sqla/models.py:849 superset/connectors/sqla/utils.py:83 -msgid "Virtual dataset query cannot be empty" -msgstr "Poizvedba na virtualnem podatkovnem setu ne sme biti prazna" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:89 +msgid "< (Smaller than)" +msgstr "< (manjše kot)" -#: superset/connectors/sqla/models.py:852 -msgid "Virtual dataset query cannot consist of multiple statements" -msgstr "" -"Poizvedba na virtualnem podatkovnem setu ne sme biti sestavljena iz več " -"stavkov" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:93 +msgid "> (Larger than)" +msgstr "> (večje kot)" -#: superset/connectors/sqla/models.py:825 -msgid "Virtual dataset query must be read-only" -msgstr "Poizvedba na virtualnem podatkovnem setu mora biti samo za branje" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:97 +msgid "<= (Smaller or equal)" +msgstr "<= (manjše ali enako)" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:192 -msgid "Visual Tweaks" -msgstr "Nastavitve izgleda" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:101 +msgid ">= (Larger or equal)" +msgstr ">= (večje ali enako)" -#: superset-frontend/src/dashboard/components/AddSliceCard.jsx:132 -msgid "Visualization" -msgstr "Vizualizacija" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:105 +msgid "== (Is equal)" +msgstr "== (je enako)" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:168 -#: superset/views/chart/mixin.py:88 -msgid "Visualization Type" -msgstr "Tip vizualizacije" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:109 +msgid "!= (Is not equal)" +msgstr "!= (ni enako)" -#: superset-frontend/src/explore/controls.jsx:200 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:270 -msgid "Visualization type" -msgstr "Tip vizualizacije" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:113 +msgid "Not null" +msgstr "Ni nič (null)" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:50 -msgid "" -"Visualize a parallel set of metrics across multiple groups. Each group is" -" visualized using its own line of points and each metric is represented " -"as an edge in the chart." -msgstr "" -"Prikaže vzporedni nabor mer za različne skupine. Vsaka skupina je " -"prikazana s svojim naborom točk in vsaka mera s povezavo na grafikonu." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:124 +msgid "30 days" +msgstr "30 dni" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:30 -msgid "" -"Visualize a related metric across pairs of groups. Heatmaps excel at " -"showcasing the correlation or strength between two groups. Color is used " -"to emphasize the strength of the link between each pair of groups." -msgstr "Vizualizacija povezanih mer med pari skupin." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:128 +msgid "60 days" +msgstr "60 dni" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:31 -msgid "" -"Visualize how a metric changes over time using bars. Add a group by " -"column to visualize group level metrics and how they change over time." -msgstr "" -"Prikaže spreminjanje mere skozi čas s pomočjo stolpcev. Z dodajanjem " -"stolpcev za združevanje prikaže mere skupin in njihovo spreminjanje." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:132 +msgid "90 days" +msgstr "90 dni" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:35 -msgid "" -"Visualize multiple levels of hierarchy using a familiar tree-like " -"structure." -msgstr "Prikaz več hierarhičnih nivojev z drevesno strukturo." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:389 +msgid "Add notification method" +msgstr "Dodajte način obveščanja" -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:58 -msgid "" -"Visualize two different time series using the same x-axis time range. " -"Note that each time series can be visualized differently (e.g. 1 using " -"bars and 1 using a line)." -msgstr "" -"Prikaže dve različni časovni vrsti na isti x-osi. Časovni vrsti sta lahko" -" prikazani različno (npr. ena s stolpci in druga s črto)." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:390 +msgid "Add delivery method" +msgstr "Dodajte način dostave" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:27 -msgid "" -"Visualize two different time series using the same x-axis time range. " -"This chart is being deprecated and we recommend using the Mixed " -"Timeseries Chart instead!" -msgstr "" -"Prikaže dve različni časovni vrsti z isto x-osjo oz. časovnim obdobjem. " -"Grafikon se opušča, zato priporočamo uporabo kombiniranega grafikona " -"časovne vrste!" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:562 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:578 +#, python-format +msgid "%s updated" +msgstr "%s posodobljeni" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:27 -msgid "" -"Visualizes 2 metrics as line plots using the same x-axis. This chart is " -"useful for comparing metrics across the same time range." -msgstr "" -"Prikaže dve meri na črtnem grafu z isto x-osjo. Grafikon je uporaben za " -"primerjavo mer v istem časovnem obdobju." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1069 +msgid "Edit Report" +msgstr "Uredi poročilo" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:27 -msgid "" -"Visualizes a metric across three dimensions of data in a single chart (X " -"axis, Y axis, and bubble size). Bubbles from the same group can be " -"showcased using bubble color." -msgstr "" -"Prikaže mero v treh dimenzijah podatkov na istem grafikonu (x os, y os, " -"velikost mehurčka). Mehurčki v isti skupini so predstavljeni z barvo." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1071 +msgid "Edit Alert" +msgstr "Uredi opozorilo" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:27 -msgid "" -"Visualizes how a metric has changed over a time using a color scale and a" -" calendar view. Gray values are used to indicate missing values and the " -"linear color scheme is used to encode the magnitude of each day's value." -msgstr "" -"Prikaže kako se je mera spreminjala s časom s pomočjo barvne lestvice in " -"koledarskega pogleda. Sive vrednosti ponazarjajo manjkajoče vrednosti. " -"Amplituda dnevnih vrednosti je ponazorjena z linearno barvno shemo." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1073 +msgid "Add Report" +msgstr "Dodaj poročilo" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:27 -msgid "" -"Visualizes how a single metric varies across a country's principal " -"subdivisions (states, provinces, etc) on a chloropleth map. Each " -"subdivision's value is elevated when you hover over the corresponding " -"geographic boundary." -msgstr "" -"Prikaže kako se posamezna mera spreminja glede na območja države (dežele," -" province, itd.) na kloropletnem zemljevidu. Vsak podrazdelek se dvigne, " -"ko z miško preidete mejo njegovega območja." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1074 +msgid "Add Alert" +msgstr "Dodaj opozorilo" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:27 -msgid "" -"Visualizes many different time-series objects in a single chart. This " -"chart is being deprecated and we recommend using the Time-series Chart " -"instead." -msgstr "" -"Prikaže več različnih časovnih vrst na istem grafikonu. Grafikon se " -"opušča, zato priporočamo uporabo Grafikona časovne vrste." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1082 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1090 +msgid "Report name" +msgstr "Naslov poročila" -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:29 -msgid "" -"Visualizes the flow of different group's values through different stages " -"of a system. New stages in the pipeline are visualized as nodes or " -"layers. The thickness of the bars or edges represent the metric being " -"visualized." -msgstr "" -"Prikaže potek vrednosti različnih skupin na različnih nivojih sistema. " -"Novi nivoji so prikazani kot točke ali plasti. Debelina stolpcev ali " -"povezav predstavlja prikazano mero." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1082 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1090 +msgid "Alert name" +msgstr "Naslov opozorila" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:35 -msgid "" -"Visualizes the words in a column that appear the most often. Bigger font " -"corresponds to higher frequency." -msgstr "" -"Prikaže besede v stolpcu, glede na pogostost pojavljanja. Večja pisava " -"pomeni večjo frekvenco." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1141 +msgid "Alert condition" +msgstr "Status opozorila" -#: superset/viz.py:133 -msgid "Viz is missing a datasource" -msgstr "Vizualizaciji manjka podatkovni vir" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1186 +msgid "Trigger Alert If..." +msgstr "Sproži opozorilo v primeru ..." -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:495 -msgid "Viz type" -msgstr "Tip vizualizacije" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1191 +msgid "Condition" +msgstr "Pogoj" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:84 -msgid "WED" -msgstr "SRE" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1205 +msgid "Threshold value should be double precision number" +msgstr "Mejna vrednost naj bo število z dvojno natančnostjo (double)" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:697 -msgid "Want to add a new database?" -msgstr "Želite dodati novo podatkovno bazo?" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1236 +msgid "Report schedule" +msgstr "Urnik poročanja" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1090 -msgid "Warning" -msgstr "Opozorilo" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1237 +msgid "Alert condition schedule" +msgstr "Urnik statusov opozoril" -#: superset/connectors/druid/views.py:193 superset/connectors/sqla/views.py:263 -msgid "Warning Message" -msgstr "Opozorilo" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1257 +msgid "Schedule settings" +msgstr "Nastavitve urnika" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:285 -msgid "Warning!" -msgstr "Opozorilo!" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1261 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1266 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1267 +msgid "Log retention" +msgstr "Hranjenje dnevnikov" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:46 -msgid "" -"Warning! Changing the dataset may break the chart if the metadata does " -"not exist." -msgstr "" -"Opozorilo! Sprememba podatkovnega seta lahko pokvari grafikon, če " -"metapodatki ne obstajajo." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1281 +msgid "Working timeout" +msgstr "Pretek delovanja" -#: superset/db_engine_specs/bigquery.py:166 -#, python-format -msgid "We can't seem to resolve column \"%(column)s\" at line %(location)s." -msgstr "" -"Zdi se, da ni mogoče razrešiti stolpca \"%(column)s\" v vrstici " -"%(location)s." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1290 +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1305 +msgid "Time in seconds" +msgstr "Čas v sekundah" -#: superset/db_engine_specs/sqlite.py:63 -#, python-format -msgid "We can't seem to resolve the column \"%(column_name)s\"" -msgstr "Zdi se, da ni mogoče razrešiti stolpca \"%(column_name)s\"" +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1298 +msgid "Grace period" +msgstr "Obdobje mirovanja" -#: superset/db_engine_specs/postgres.py:150 -#: superset/db_engine_specs/presto.py:171 -#, python-format -msgid "" -"We can't seem to resolve the column \"%(column_name)s\" at line " -"%(location)s." -msgstr "" -"Zdi se, da ni mogoče razrešiti stolpca \"%(column_name)s\" v vrstici " -"%(location)s." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1363 +msgid "Send as PNG" +msgstr "Pošlji kot PNG" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:118 -msgid "We recommend your summarize your data further before following that flow. " -msgstr "Priporočamo, da zahtevane podatke pred nadaljevanjem strnete. " +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1364 +msgid "Send as CSV" +msgstr "Pošlji kot CSV" -#: superset-frontend/src/reports/actions/reports.js:156 -msgid "We were unable to active or deactivate this report." -msgstr "Aktiviranje ali deaktiviranje poročila ni uspelo." +#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1367 +msgid "Send as text" +msgstr "Pošlji kot besedilo" -#: superset/db_engine_specs/redshift.py:86 -#, python-format -msgid "" -"We were unable to connect to your database named \"%(database)s\". Please" -" verify your database name and try again." -msgstr "" -"Povezava s podatkovno bazo \"%(database)s\" ni uspela. Preverite ime " -"podatkovne baze in poskusite ponovno." +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:66 +msgid "log" +msgstr "dnevnik" -#: superset/db_engine_specs/bigquery.py:149 -msgid "" -"We were unable to connect to your database. Please confirm that your " -"service account has the Viewer and Job User roles on the project." -msgstr "" -"Povezava s podatkovno bazo ni uspela. Preverite, da ima vaš dostop " -"dodeljeni vlogi Viewer in Job User." +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:97 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:348 +msgid "State" +msgstr "Status" -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:60 -msgid "Web" -msgstr "Mreža" +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:108 +msgid "Execution ID" +msgstr "ID izvedbe" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:59 -msgid "Wednesday" -msgstr "Sreda" +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:120 +msgid "Scheduled at (UTC)" +msgstr "Izvede se ob (UTC)" -#: superset/db_engine_specs/base.py:97 -msgid "Week" -msgstr "Teden" +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:128 +msgid "Start at (UTC)" +msgstr "Zažene se ob (UTC)" -#: superset/db_engine_specs/base.py:103 -msgid "Week ending Saturday" -msgstr "Teden s koncem v soboto" +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:138 +msgid "Duration" +msgstr "Trajanje" -#: superset/db_engine_specs/base.py:102 -msgid "Week starting Monday" -msgstr "Teden z začetkom v ponedeljek" +#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:147 +msgid "Error message" +msgstr "Sporočilo napake" -#: superset/db_engine_specs/base.py:101 -msgid "Week starting Sunday" -msgstr "Teden z začetkom v nedeljo" +#: superset-frontend/src/views/CRUD/alert/components/AlertReportCronScheduler.tsx:94 +msgid "CRON expression" +msgstr "Izraz CRON" -#: superset/db_engine_specs/base.py:104 -msgid "Week_ending Sunday" -msgstr "Teden s koncem v nedeljo" +#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:67 +msgid "Report sent" +msgstr "Poročilo poslano" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:67 -#, fuzzy, python-format -msgid "Weeks %s" -msgstr "teden" +#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:68 +msgid "Alert triggered, notification sent" +msgstr "Opozorilo sproženo, obvestilo poslano" -#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:52 -#, python-format -msgid "" -"We’re having trouble loading these results. Queries are set to timeout " -"after %s second." -msgstr "" -"Težava pri nalaganju rezultatov. Časovni iztek poizvedb je nastavljen na " -"%s sekund." +#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:74 +msgid "Report sending" +msgstr "Pošiljanje poročila" -#: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:46 -#, python-format -msgid "" -"We’re having trouble loading this visualization. Queries are set to " -"timeout after %s second." -msgstr "" -"Težava pri nalaganju vizualizacije. Časovni iztek poizvedb je nastavljen " -"na %s sekund." +#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:75 +msgid "Alert running" +msgstr "Opozorilo aktivno" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:58 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:102 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:110 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:113 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:103 -msgid "What should be shown on the label?" -msgstr "Kaj bo prikazano na oznaki?" +#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:81 +msgid "Report failed" +msgstr "Poročilo ni uspelo" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:437 -#: superset-frontend/src/explore/controls.jsx:454 -msgid "" -"When `Calculation type` is set to \"Percentage change\", the Y Axis " -"Format is forced to `.1%`" -msgstr "" -"Če je `Vrsta izračuna` nastavljena na \"Procentualna sprememba\", bo " -"oblika Y-osi vsiljena na `.1%`" +#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:82 +msgid "Alert failed" +msgstr "Opozorilo ni uspelo" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:76 -msgid "When a secondary metric is provided, a linear color scale is used." -msgstr "Če je podana sekundarna metrika, je uporabljena linearna barvna skala." +#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:87 +#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:97 +msgid "Nothing triggered" +msgstr "Ni ni sproženo" -#: superset/views/database/mixins.py:120 -msgid "" -"When allowing CREATE TABLE AS option in SQL Lab, this option forces the " -"table to be created in this schema" -msgstr "" -"Z dovolitvijo opcije CREATE TABLE AS v SQL laboratoriju se tabele " -"ustvarjajo s to shemo" +#: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:92 +msgid "Alert Triggered, In Grace Period" +msgstr "Opozorilo sproženo, v obdobju mirovanja" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:195 -msgid "When enabled, users are able to visualize SQL Lab results in Explore." -msgstr "" -"Ko je omogočeno, lahko uporabniki prikazujejo rezultate SQL laboratorija " -"v raziskovalcu." +#: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:124 +msgid "Delivery method" +msgstr "Način dostave" -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:71 -msgid "When only a primary metric is provided, a categorical color scale is used." -msgstr "" -"Če je podana samo primarna metrika, je uporabljena kategorična barvna " -"skala." +#: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:127 +msgid "Select Delivery Method" +msgstr "Izberite način dostave" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:898 -msgid "" -"When specifying SQL, the datasource acts as a view. Superset will use " -"this statement as a subquery while grouping and filtering on the " -"generated parent queries." -msgstr "" -"Ko podajate SQL, se podatkovni vir obnaša kot pogled (view). Superset bo " -"ta zapis uporabil kot podpoizvedbo, pri čemer bo združeval in filtriral " -"na podlagi ustvarjenih starševskih poizvedb." +#: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:160 +msgid "Recipients are separated by \",\" or \";\"" +msgstr "Prejemniki so ločeni z \",\" ali \";\"" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:716 -msgid "" -"When using \"Autocomplete filters\", this can be used to improve " -"performance of the query fetching the values. Use this option to apply a " -"predicate (WHERE clause) to the query selecting the distinct values from " -"the table. Typically the intent would be to limit the scan by applying a " -"relative time filter on a partitioned or indexed time-related field." -msgstr "" -"Ko uporabljate \"Samodokončaj filtre\", lahko s tem izboljšate hitrost " -"pridobivanja rezultatov s poizvedbo. Z uporabo te možnosti dodate " -"predikat (WHERE stavek) k poizvedbi za izbiro različnih vrednosti iz " -"tabele. Običajno je namen omejiti poizvedbo z uporabo filtra za relativni" -" čas na particioniranem ali indeksiranem časovnem polju." +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:78 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:106 +msgid "annotation" +msgstr "oznaka" -#: superset/viz.py:834 -msgid "When using 'Group By' you are limited to use a single metric" -msgstr "Ko uporabljate 'Group By', ste omejeni na uporabo ene mere" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:141 +#, python-format +msgid "There was an issue deleting the selected annotations: %s" +msgstr "Pri brisanju izbranih oznak je prišlo do težave: %s" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:258 -msgid "Whether the progress bar overlaps when there are multiple groups of data" -msgstr "Če želite prekrivanje območij, ko imate več skupin podatkov" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:188 +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:283 +msgid "Edit annotation" +msgstr "Uredi oznako" -#: superset/connectors/sqla/views.py:466 -msgid "Whether the table was generated by the 'Visualize' flow in SQL Lab" -msgstr "" -"Če želite, da je tabela ustvarjena s postopkom 'Vizualizacija' v SQL " -"laboratoriju" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:195 +msgid "Delete annotation" +msgstr "Izbriši oznako" -#: superset/connectors/druid/views.py:98 superset/connectors/sqla/views.py:99 -msgid "" -"Whether this column is exposed in the `Filters` section of the explore " -"view." -msgstr "" -"Če želite, da je ta stolpec na voljo v sekciji `Filtri` v raziskovalnem " -"pogledu." +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:216 +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:249 +msgid "Annotation" +msgstr "Oznaka" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:430 -msgid "" -"Whether to align background charts with both positive and negative values" -" at 0" -msgstr "" -"Če želite poravnati graf v ozadju celic za negativne in pozitivne " -"vrednosti okrog 0" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:242 +msgid "No annotation yet" +msgstr "Oznak še ni" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:128 -msgid "Whether to align positive and negative values in cell bar chart at 0" -msgstr "" -"Če želite poravnati pozitivne in negativne vrednosti v stolpčnem " -"grafikonu celic pri 0" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:259 +#, python-format +msgid "Annotation Layer %s" +msgstr "Sloj z oznakami %s" -#: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:739 -#, fuzzy -msgid "Whether to always show the annotation label" -msgstr "Če želite prikazati kazalec" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:282 +#, python-format +msgid "Are you sure you want to delete %s?" +msgstr "Ali ste prepričani, da želite izbrisati %s?" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:192 -msgid "Whether to animate the progress and the value or just display them" -msgstr "Če želite animiran prikaz grafikona" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:293 +msgid "Delete Annotation?" +msgstr "Izbrišem oznako?" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:317 -msgid "Whether to apply a normal distribution based on rank on the color scale" -msgstr "" -"Če želite uporabiti normalno porazdelitev glede na stopnjo na barvni " -"lestvici" +#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:298 +msgid "Are you sure you want to delete the selected annotations?" +msgstr "Ali ste prepričani, da želite izbrisati izbrane oznake?" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:138 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:442 -msgid "Whether to colorize numeric values by if they are positive or negative" -msgstr "" -"Če želite obarvati številske vrednosti, ko so le-te pozitivne ali " -"negativne" +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:152 +msgid "The annotation has been updated" +msgstr "Označba je bila posodobljena" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:120 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:416 -msgid "Whether to display a bar chart background in table columns" -msgstr "" -"Če želite omogočiti prikaz manjših stolpčnih grafikonov v ozadju stolpcev" -" tabele" +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:168 +msgid "The annotation has been saved" +msgstr "Označba je bila shranjena" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:38 -msgid "Whether to display a legend for the chart" -msgstr "Če želite prikaz legende za grafikon" +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:283 +msgid "Add annotation" +msgstr "Dodaj oznako" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:83 -msgid "Whether to display bubbles on top of countries" -msgstr "Če želite prikaz mehurčkov nad državami" +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:292 +msgid "Annotation name" +msgstr "Ime oznake" -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:60 -msgid "Whether to display the interactive data table" -msgstr "Če želite prikaz interaktivne podatkovne tabele" +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:304 +msgid "date" +msgstr "datum" -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:130 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:152 -#: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:97 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:74 -msgid "Whether to display the labels." -msgstr "Če želite prikaz oznak." +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:324 +msgid "Additional information" +msgstr "Dodatne informacije" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:99 -msgid "" -"Whether to display the labels. Note that the label only displays when the" -" the 5% threshold." -msgstr "" -"Če želite prikazati oznake. Oznake so prikazane le pri vsaj 5-odstotnem " -"pragu." +#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:331 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:266 +msgid "Description (this can be seen in the list)" +msgstr "Opis (lahko je viden na seznamu)" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:157 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:278 -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:132 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:152 -msgid "Whether to display the legend (toggles)" -msgstr "Preklapljanje prikaza legende" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:104 +msgid "annotation_layer" +msgstr "annotation_layer" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:181 -msgid "Whether to display the metric name as a title" -msgstr "Če želite prikazati ime mere kot naslov" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:139 +msgid "Annotation template updated" +msgstr "Predloga oznake posodobljena" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:273 -msgid "Whether to display the min and max values of the X-axis" -msgstr "Če želite prikaz min. in max. vrednosti X-osi" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:154 +msgid "Annotation template created" +msgstr "Predloga oznake ustvarjena" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:94 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:105 -msgid "Whether to display the min and max values of the Y-axis" -msgstr "Če želite prikaz min. in max. vrednosti Y-osi" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:241 +msgid "Edit annotation layer properties" +msgstr "Uredi lastnosti sloja z oznakami" -#: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:167 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:304 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:185 -msgid "Whether to display the numerical values within the cells" -msgstr "Če želite v celicah prikazati numerične vrednosti" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:251 +msgid "Annotation layer name" +msgstr "Ime sloja z oznakami" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:141 -msgid "Whether to display the time range interactive selector" -msgstr "Če želite prikaz interaktivnega izbirnika časovnega obdobja" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:71 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:335 +msgid "Annotation layers" +msgstr "Sloji z oznakami" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:88 -msgid "Whether to display the timestamp" -msgstr "Če želite prikazati časovno značko" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:110 +#, python-format +msgid "There was an issue deleting the selected layers: %s" +msgstr "Pri brisanju izbranih slojev je prišlo do težave: %s" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:100 -msgid "Whether to display the trend line" -msgstr "Če želite prikazati trendno črto" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:179 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:345 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:158 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:364 +msgid "Last modified" +msgstr "Zadnja sprememba" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:170 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:279 -msgid "Whether to enable changing graph position and scaling." -msgstr "Če želite omogočiti premikanje in povečevanje/zmanjševanje grafikona." +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:204 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:184 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:351 +msgid "Created on" +msgstr "Ustvarjeno" -#: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:144 -msgid "Whether to enable node dragging in force layout mode." -msgstr "Če želite omogočiti premikanje vozlišč v načinu vsiljenega prikaza." +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:229 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:210 +msgid "Edit template" +msgstr "Uredi predlogo" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:63 -msgid "Whether to format the timestamp" -msgstr "Če želite oblikovati časovno značko" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:238 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:219 +msgid "Delete template" +msgstr "Izbriši predlogo" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:406 -msgid "Whether to include a client-side search box" -msgstr "Če želite vključiti iskalno polje za uporabnika" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:264 +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:319 +msgid "Annotation layer" +msgstr "Sloj z oznakami" -#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:81 -msgid "Whether to include a time filter" -msgstr "Če želite vključiti časovni filter" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:294 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:282 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:436 +#, python-format +msgid "An error occurred while fetching dataset datasource values: %s" +msgstr "" +"Pri pridobivanju vrednosti podatkovnega vira podatkovnega seta je prišlo do " +"napake: %s" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:289 -msgid "Whether to include the percentage in the tooltip" -msgstr "Če želite prikaz procentov v opisu orodja" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:314 +msgid "No annotation layers yet" +msgstr "Slojev z oznakami še ni" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:326 -msgid "Whether to include the time granularity as defined in the time section" -msgstr "Če želite vključiti granulacijo časa, ki je določena v sekciji Čas" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:345 +msgid "This action will permanently delete the layer." +msgstr "S tem dejanjem boste trajno izbrisali sloj." -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:155 -msgid "Whether to make the histogram cumulative" -msgstr "Če želite kumulativni histogram" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:353 +msgid "Delete Layer?" +msgstr "Izbrišem sloj?" -#: superset/connectors/sqla/views.py:94 -msgid "" -"Whether to make this column available as a [Time Granularity] option, " -"column has to be DATETIME or DATETIME-like" -msgstr "" -"Če želite, da bo ta stolpec na razpolago kot možnost [Granulacija časa]. " -"Stolpec mora biti tipa DATETIME ali DATETIME-like" +#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:358 +msgid "Are you sure you want to delete the selected layers?" +msgstr "Ali ste prepričani, da želite izbrisati izbrane sloje?" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:143 -msgid "Whether to normalize the histogram" -msgstr "Če želite normirati histogram" +#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:81 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:388 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:109 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:361 +msgid "Are you sure you want to delete" +msgstr "Ali ste prepričani, da želite izbrisati" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:709 -msgid "Whether to populate autocomplete filters options" -msgstr "Če želite napolniti možnosti za samodokončanje filtrov" +#: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:156 +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:165 +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:129 +#, python-format +msgid "Modified %s" +msgstr "Zadnja sprememba %s" -#: superset/connectors/druid/views.py:325 superset/connectors/sqla/views.py:461 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:82 msgid "" -"Whether to populate the filter's dropdown in the explore view's filter " -"section with a list of distinct values fetched from the backend on the " -"fly" +"The passwords for the databases below are needed in order to import them together " +"with the charts. Please note that the \"Secure Extra\" and \"Certificate\" " +"sections of the database configuration are not present in export files, and " +"should be added manually after the import if they are needed." msgstr "" -"Če želite napolniti spustni seznam filtra v raziskovalnem pogledu " -"filtrske sekcije z različnimi vrednostmi, pridobljenimi sproti v ozadju" +"Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj z grafikoni. Sekciji " +"\"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista " +"prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to " +"potrebno." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:163 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:89 msgid "" -"Whether to show extra controls or not. Extra controls include things like" -" making mulitBar charts stacked or side by side." +"You are importing one or more charts that already exist. Overwriting might cause " +"you to lose some of your work. Are you sure you want to overwrite?" msgstr "" -"Če želite prikaz dodatnih kontrolnikov. Dodatni kontrolniki vključujejo " -"možnost izdelave večstolpčnih grafikonov, naloženih ali drug ob drugem." +"Uvažate enega ali več grafikonov, ki že obstajajo. S prepisom lahko izgubite " +"podatke. Ali ste prepričani, da želite prepisati?" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:207 -msgid "Whether to show minor ticks on the axis" -msgstr "Če želite prikaz manjših oznak na osi" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:203 +msgid "Chart imported" +msgstr "Grafikon uvožen" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:180 -msgid "Whether to show the pointer" -msgstr "Če želite prikazati kazalec" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:233 +#, python-format +msgid "There was an issue deleting the selected charts: %s" +msgstr "Pri brisanju izbranih grafikonov je prišlo do težave: %s" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:246 -msgid "Whether to show the progress of gauge chart" -msgstr "Prikaži merilno območje števčnega grafikona" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:331 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:294 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:351 +msgid "Modified by" +msgstr "Spremenil" -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:219 -msgid "Whether to show the split lines on the axis" -msgstr "Če želite prikazati razdelitvene črte na osi" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:469 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:441 +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:165 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:175 +msgid "Favorite" +msgstr "Priljubljene" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:44 -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:47 -#: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:42 -#: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:50 -#: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:49 -#: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:48 -#: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:46 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:61 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:356 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:107 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:91 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:88 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:68 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:85 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:91 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:92 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:339 -#: superset-frontend/src/explore/controlPanels/sections.tsx:127 -msgid "Whether to sort descending or ascending" -msgstr "Če želite padajoče ali naraščajoče razvrščanje" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:474 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:568 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:446 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:504 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:517 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:525 +msgid "Any" +msgstr "Katerikoli" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/legacySortBy.tsx:31 -msgid "" -"Whether to sort descending or ascending. Takes effect only when \"Sort " -"by\" is set" -msgstr "" -"Če želite padajoče ali naraščajoče razvrščanje. Učinkuje samo, ko je " -"vključen \"Sort by\"" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:476 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:570 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:448 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:519 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:527 +msgid "Yes" +msgstr "Da" -#: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:40 -#: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:39 -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:95 -#: superset-frontend/plugins/legacy-plugin-chart-sankey/src/controlPanel.ts:56 -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:40 -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx:64 -#: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:66 -#: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:63 -#: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:50 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:39 -msgid "Whether to sort results by the selected metric in descending order." -msgstr "Če želite padajoče razvrstiti rezultate z izbrano mero." +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:477 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:571 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:449 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:520 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:528 +msgid "No" +msgstr "Ne" -#: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:175 -msgid "Whether to sort tooltip by the selected metric in descending order." -msgstr "Če želite padajoče razvrstiti opis orodja z izbrano mero." +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:490 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:511 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:532 +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:557 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:462 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:483 +msgid "All" +msgstr "Vsi" -#: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:43 -msgid "Which country to plot the map for?" -msgstr "Za katero državo želite grafikon?" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:496 +#, python-format +msgid "An error occurred while fetching chart owners values: %s" +msgstr "Pri pridobivanju polja lastnik grafikona je prišlo do napake: %s" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:197 -msgid "Which relatives to highlight on hover" -msgstr "Kateri element se poudari na prehodu z miško" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:517 +#, python-format +msgid "An error occurred while fetching chart created by values: %s" +msgstr "Pri pridobivanju polja Grafikon ustvaril je prišlo do napake: %s" -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:51 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:45 -msgid "Whisker/outlier options" -msgstr "Možnosti grafikona kvantilov" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:528 +msgid "Chart type" +msgstr "Tip grafikona" -#: superset-frontend/src/dashboard/util/backgroundStyleOptions.ts:30 -msgid "White" -msgstr "Belo" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:563 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:512 +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:520 +msgid "Certified" +msgstr "Certificirano" -#: superset-frontend/src/explore/components/EmbedCodeButton.jsx:130 -msgid "Width" -msgstr "Širina" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:588 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:537 +msgid "Alphabetical" +msgstr "Po abecedi" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:73 -msgid "Width of the confidence interval. Should be between 0 and 1" -msgstr "Širina intervala zaupanja. Mora bit med 0 in 1" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:594 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:543 +msgid "Recently modified" +msgstr "Nedavno spremenjeno" -#: superset/utils/pandas_postprocessing.py:393 -msgid "Window must be > 0" -msgstr "Okno mora biti > 0" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:600 +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:549 +msgid "Least recently modified" +msgstr "Zadnje spremenjeno" -#: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:36 -msgid "With a subheader" -msgstr "S podnaslovom" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:664 +msgid "Import charts" +msgstr "Uvozi grafikone" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/legacyPlugin/index.ts:29 -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:39 -msgid "Word Cloud" -msgstr "Oblak besed" +#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:688 +msgid "Are you sure you want to delete the selected charts?" +msgstr "Ali ste prepričani, da želite izbrisati izbrane grafikone?" -#: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:80 -msgid "Word Rotation" -msgstr "Vrtenje besed" +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:91 +msgid "css_template" +msgstr "css_template" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:55 -msgid "Working" -msgstr "" +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:231 +msgid "Edit CSS template properties" +msgstr "Uredi lastnosti CSS predloge" -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1258 -msgid "Working timeout" -msgstr "Pretek delovanja" +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:232 +msgid "Add CSS template" +msgstr "Dodaj CSS predlogo" -#: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:33 -#: superset/viz.py:2042 -msgid "World Map" -msgstr "Zemljevid sveta" +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:241 +msgid "CSS template name" +msgstr "Ime CSS predloge" + +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:253 +msgid "css" +msgstr "css" + +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:71 +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:240 +msgid "CSS templates" +msgstr "CSS predloge" + +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:115 +#, python-format +msgid "There was an issue deleting the selected templates: %s" +msgstr "Pri brisanju izbranih predlog je prišlo do težave: %s" + +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:151 +#, python-format +msgid "Last modified by %s" +msgstr "Nazadnje spremenil %s" + +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:249 +msgid "CSS template" +msgstr "CSS predloga" + +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:313 +msgid "This action will permanently delete the template." +msgstr "S tem dejanjem boste trajno izbrisali predlogo." + +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:321 +msgid "Delete Template?" +msgstr "Izbrišem predlogo?" + +#: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:326 +msgid "Are you sure you want to delete the selected templates?" +msgstr "Ali ste prepričani, da želite izbrisati izbrane predloge?" + +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:154 +msgid "published" +msgstr "objavljeno" -#: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:166 -msgid "Write a description for your query" -msgstr "Dodajte opis vaše poizvedbe" +#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:154 +msgid "draft" +msgstr "osnutek" -#: superset/views/database/forms.py:221 superset/views/database/forms.py:354 -#: superset/views/database/forms.py:442 -msgid "Write dataframe index as a column." -msgstr "Zapiši indeks dataframe-a kot stolpec." +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:56 +msgid "" +"The passwords for the databases below are needed in order to import them together " +"with the dashboards. Please note that the \"Secure Extra\" and \"Certificate\" " +"sections of the database configuration are not present in export files, and " +"should be added manually after the import if they are needed." +msgstr "" +"Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj z nadzornimi " +"ploščami. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne " +"baze nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po " +"uvozu, če je to potrebno." -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:51 -msgid "X AXIS TITLE BOTTOM MARGIN" -msgstr "SPODNJA OBROBA NASLOVA X OSI" +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:63 +msgid "" +"You are importing one or more dashboards that already exist. Overwriting might " +"cause you to lose some of your work. Are you sure you want to overwrite?" +msgstr "" +"Uvažate eno ali več nadzornih plošč, ki že obstajajo. S prepisom lahko izgubite " +"podatke. Ali ste prepričani, da želite prepisati?" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:31 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:147 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:406 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:69 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:63 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:83 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/controlPanel.ts:107 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:69 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:77 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:90 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:298 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:189 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:150 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:130 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:147 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:205 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:208 -#: superset-frontend/src/explore/controls.jsx:421 -msgid "X Axis" -msgstr "X os" +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:147 +msgid "Dashboard imported" +msgstr "Nadzorna plošča uvožena" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:215 -msgid "X Axis Format" -msgstr "Oblika X-osi" +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:205 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:167 +#, python-format +msgid "An error occurred while fetching dashboards: %s" +msgstr "Prišlo je do napake pri pridobivanju nadzornih plošč: %s" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:107 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:175 -msgid "X Axis Label" -msgstr "Naslov X osi" +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:231 +msgid "There was an issue deleting the selected dashboards: " +msgstr "Pri brisanju izbranih nadzornih plošč je prišlo do težave: " -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:37 -msgid "X Axis Title" -msgstr "Naslov X osi" +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:468 +#, python-format +msgid "An error occurred while fetching dashboard owner values: %s" +msgstr "Pri pridobivanju polja lastnik nadzorne plošče je prišlo do napake: %s" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:104 -msgid "X Log Scale" -msgstr "Logaritemska X-os" +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:489 +#, python-format +msgid "An error occurred while fetching dashboard created by values: %s" +msgstr "Pri pridobivanju polja Nadzorno ploščo ustvaril je prišlo do napake: %s" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:201 -#: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:78 -#: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:62 -msgid "X Tick Layout" -msgstr "Postavitev oznak na X-osi" +#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:633 +msgid "Are you sure you want to delete the selected dashboards?" +msgstr "Ali ste prepričani, da želite izbrisati izbrane nadzorne plošče?" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:270 -msgid "X bounds" -msgstr "Meje X-osi" +#: superset-frontend/src/views/CRUD/data/common.ts:38 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:107 +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:332 +msgid "Saved queries" +msgstr "Shranjene poizvedbe" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:114 -msgid "XScale Interval" -msgstr "Interval X-osi" +#: superset-frontend/src/views/CRUD/data/components/SyntaxHighlighterCopy/index.tsx:71 +msgid "SQL Copied!" +msgstr "SQL kopiran!" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:102 -msgid "Y 2 bounds" -msgstr "Meje Y 2" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:89 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:432 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:533 +msgid "database" +msgstr "podatkovna baza" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:79 -msgid "Y AXIS TITLE MARGIN" -msgstr "OBROBA NASLOVA Y OSI" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:140 +#, python-format +msgid "An error occurred while fetching database related data: %s" +msgstr "Pri pridobivanju podatkov iz podatkovne baze je prišlo do napake: %s" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:94 -msgid "Y AXIS TITLE POSITION" -msgstr "POZICIJA NASLOVA Y OSI" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:191 +msgid "Upload file to database" +msgstr "Naloži datoteko v podatkovno bazo" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:59 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:153 -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:413 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/controlPanel.ts:79 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/controlPanel.ts:75 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:115 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/controlPanel.ts:54 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:80 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:109 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:241 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:322 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:224 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:186 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:167 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:183 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:240 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:243 -#: superset-frontend/src/explore/controls.jsx:428 -msgid "Y Axis" -msgstr "Y os" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:194 +msgid "Upload CSV" +msgstr "Naloži CSV" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:40 -msgid "Y Axis 1" -msgstr "Y-os 1" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:201 +msgid "Upload columnar file" +msgstr "Naloži datoteko s stolpci" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:50 -msgid "Y Axis 2" -msgstr "Y-os 2" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:208 +msgid "Upload Excel file" +msgstr "Naloži Excel-ovo datoteko" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:254 -msgid "Y Axis 2 Bounds" -msgstr "Meje Y 2-osi" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:293 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:458 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:303 +msgid "Asynchronous query execution" +msgstr "Asinhroni zagon poizvedb" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:238 -#: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:354 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:269 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:232 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/controlPanel.tsx:212 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:229 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:285 -#: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:288 -msgid "Y Axis Bounds" -msgstr "Meje Y-osi" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:296 +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:461 +msgid "AQE" +msgstr "AQE" -#: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:428 -#: superset-frontend/src/explore/controls.jsx:442 -msgid "Y Axis Format" -msgstr "Oblika Y osi" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:313 +msgid "Allow data manipulation language" +msgstr "Dovoli jezik za manipulacijo podatkov (DML)" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:118 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:333 -msgid "Y Axis Label" -msgstr "Naslov Y osi" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:316 +msgid "DML" +msgstr "DML" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:88 -msgid "Y Axis Left" -msgstr "Y-os levo" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:328 +msgid "CSV upload" +msgstr "Nalaganje CSV" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:123 -msgid "Y Axis Right" -msgstr "Y-os desno" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:389 +msgid "Delete database" +msgstr "Izbriši podatkovno bazo" -#: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:65 -msgid "Y Axis Title" -msgstr "Naslov Y osi" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:496 +#, python-format +msgid "" +"The database %s is linked to %s charts that appear on %s dashboards and users " +"have %s SQL Lab tabs using this database open. Are you sure you want to continue? " +"Deleting the database will break those objects." +msgstr "" +"Podatkovna baza %s je povezana z grafikoni %s, ki so prisotni na nadzorni plošči " +"%s in uporabniki imajo odprtih %s zavihkov SQL laboratorija. Ali želite " +"nadaljevati? Izbris podatkovne baze bo pokvaril te objekte." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:227 -msgid "Y Log Scale" -msgstr "Logaritemska Y-os" +#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:510 +msgid "Delete Database?" +msgstr "Izbrišem podatkovno bazo?" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:91 -msgid "Y bounds" -msgstr "Y meje" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:76 +msgid "Expose database in SQL Lab" +msgstr "Razkrij podatkovno bazo v SQL laboratoriju" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:130 -msgid "YScale Interval" -msgstr "Interval Y-osi" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:79 +msgid "Allow this database to be queried in SQL Lab" +msgstr "Dovoli poizvedbo na to podatkovno bazo v SQL laboratoriju" -#: superset/db_engine_specs/base.py:100 -msgid "Year" -msgstr "Leto" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:98 +msgid "Allow creation of new tables based on queries" +msgstr "Dovoli ustvarjanje novih tabel s poizvedbami" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:70 -#, fuzzy, python-format -msgid "Years %s" -msgstr "leto" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:112 +msgid "Allow creation of new views based on queries" +msgstr "Dovoli ustvarjanje novih pogledov s poizvedbami" -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:443 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:537 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:440 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:511 -msgid "Yes" -msgstr "Da" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:118 +msgid "CTAS & CVAS SCHEMA" +msgstr "CTAS & CVAS SHEMA" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx:64 -msgid "Yes, cancel" -msgstr "Da, prekini" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:124 +msgid "Create or select schema..." +msgstr "Ustvarite ali izberite shemo..." -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:72 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:129 msgid "" -"You are importing one or more charts that already exist. Overwriting " -"might cause you to lose some of your work. Are you sure you want to " -"overwrite?" +"Force all tables and views to be created in this schema when clicking CTAS or " +"CVAS in SQL Lab." msgstr "" -"Uvažate enega ali več grafikonov, ki že obstajajo. S prepisom lahko " -"izgubite podatke. Ali ste prepričani, da želite prepisati?" +"Vsilite, da bodo vse tabele in pogledi ustvarjeni s to shemo, ko kliknete CTAS " +"ali CVAS v SQL laboratoriju." -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:64 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:145 msgid "" -"You are importing one or more dashboards that already exist. Overwriting " -"might cause you to lose some of your work. Are you sure you want to " -"overwrite?" +"Allow manipulation of the database using non-SELECT statements such as UPDATE, " +"DELETE, CREATE, etc." msgstr "" -"Uvažate eno ali več nadzornih plošč, ki že obstajajo. S prepisom lahko " -"izgubite podatke. Ali ste prepričani, da želite prepisati?" +"Dovoli manipulacije podatkovne baze z uporabo ne-SELECT stavkov, kot so UPDATE, " +"DELETE, CREATE, itd." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:176 +msgid "Enable query cost estimation" +msgstr "Omogoči ocenjevanje potratnosti poizvedbe" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:45 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 msgid "" -"You are importing one or more databases that already exist. Overwriting " -"might cause you to lose some of your work. Are you sure you want to " -"overwrite?" +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a query." msgstr "" -"Uvažate eno ali več podatkovnih baz, ki že obstajajo. S prepisom lahko " -"izgubite podatke. Ali ste prepričani, da želite prepisati?" +"Za Presto in Postgres prikaže gumb za izračun potratnosti pred zagonom poizvedbe." -#: superset-frontend/src/views/CRUD/data/dataset/constants.ts:30 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:192 +msgid "Allow this database to be explored" +msgstr "Dovoli raziskovanje te podatkovne baze" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:195 +msgid "When enabled, users are able to visualize SQL Lab results in Explore." +msgstr "" +"Ko je omogočeno, lahko uporabniki prikazujejo rezultate SQL laboratorija v " +"raziskovalcu." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:208 +msgid "Disable SQL Lab data preview queries" +msgstr "Izključite poizvedbe za predogled podatkov v SQL Laboratoriju" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:211 msgid "" -"You are importing one or more datasets that already exist. Overwriting " -"might cause you to lose some of your work. Are you sure you want to " -"overwrite?" +"Disable data preview when fetching table metadata in SQL Lab. Useful to avoid " +"browser performance issues when using databases with very wide tables." msgstr "" -"Uvažate enega ali več podatkovnih setov, ki že obstajajo. S prepisom " -"lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" +"Izključite predogled podatkov pri pridobivanju metapodatkov v SQL laboratoriju. S " +"tem se zmanjša obremenitev brskalnika pri podatkovnih bazah z zelo širokimi " +"tabelami." -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:63 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:234 +msgid "Chart cache timeout" +msgstr "Trajanje predpomnilnika grafikona" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:240 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:262 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:284 +msgid "Enter duration in seconds" +msgstr "Vnesite trajanje v sekundah" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:253 +msgid "Schema cache timeout" +msgstr "Trajanje prepomnilnika sheme" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:268 msgid "" -"You are importing one or more saved queries that already exist. " -"Overwriting might cause you to lose some of your work. Are you sure you " -"want to overwrite?" +"Duration (in seconds) of the metadata caching timeout for schemas of this " +"database. If left unset, the cache never expires." msgstr "" -"Uvažate eno ali več shranjenih poizvedb, ki že obstajajo. S prepisom " -"lahko izgubite podatke. Ali ste prepričani, da želite prepisati?" +"Trajanje (v sekundah) predpomnilnika metapodatkov za sheme v tej podatkovni bazi. " +"Če ni nastavljeno, predpomnilnik ne poteče." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:275 +msgid "Table cache timeout" +msgstr "Trajanje predpomnilnika tabele" -#: superset/views/core.py:2175 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:290 msgid "" -"You are not authorized to fetch samples from this table. If you think " -"this is an error, please reach out to your administrator." +"Duration (in seconds) of the metadata caching timeout for tables of this " +"database. If left unset, the cache never expires. " msgstr "" -"Nimate dovoljenja za pridobitev vzorcev iz te tabele. Če menite, da je to" -" napaka, kontaktirajte administratorja." +"Trajanje (v sekundah) predpomnilnika metapodatkov za tabele v tej podatkovni " +"bazi. Če ni nastavljeno, predpomnilnik ne poteče. " -#: superset/views/core.py:2295 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:306 msgid "" -"You are not authorized to see this query. If you think this is an error, " -"please reach out to your administrator." +"Operate the database in asynchronous mode, meaning that the queries are executed " +"on remote workers as opposed to on the web server itself. This assumes that you " +"have a Celery worker setup as well as a results backend. Refer to the " +"installation docs for more information." msgstr "" -"Nimate dovoljenja za ogled te poizvedbe. Če menite, da je to napaka, " -"kontaktirajte administratorja." +"Upravljanje podatkovne baze v asinhronem načinu pomeni, da se poizvedbe zaženejo " +"na oddaljenih »delavcih« in ne na samem spletnem strežniku. S tem je " +"predpostavljeno, da imate nastavljenega »delavca« za Celery in zaledni sistem za " +"rezultate. Več informacij je v navodilih za namestitev." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:322 +msgid "Cancel query on window unload event" +msgstr "Prekini poizvedbo pri dogodku zaprtja okna (window unload event)" -#: superset/views/database/views.py:463 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:325 msgid "" -"You cannot specify a namespace both in the name of the table: " -"\"%(columnar_table.table)s\" and in the schema field: " -"\"%(columnar_table.schema)s\". Please remove one" +"Terminate running queries when browser window closed or navigated to another " +"page. Available for Presto, Hive, MySQL, Postgres and Snowflake databases." msgstr "" -"Imenskega prostora ni mogoče podati hkrati v imenu tabele: " -"\"%(columnar_table.table)s\" in polju sheme: " -"\"%(columnar_table.schema)s\". Odstranite enega" +"Ustavi zagnane poizvedbe, ko se zapre okno brskalnika ali gre na drugo stran. na " +"razpolago za Presto, Hive, MySQL, Postgres in Snowflake podatkovne baze." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:344 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:349 +msgid "Secure extra" +msgstr "Dodatna varnost" -#: superset/views/database/views.py:146 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:359 msgid "" -"You cannot specify a namespace both in the name of the table: " -"\"%(csv_table.table)s\" and in the schema field: " -"\"%(csv_table.schema)s\". Please remove one" +"JSON string containing additional connection configuration. This is used to " +"provide connection information for systems like Hive, Presto and BigQuery which " +"do not conform to the username:password syntax normally used by SQLAlchemy." msgstr "" -"Imenskega prostora ni mogoče podati hkrati v tabeli: " -"\"%(csv_table.table)s\" in polju sheme: \"%(csv_table.schema)s\". " -"Odstranite enega" +"JSON niz, ki vsebuje dodatno konfiguracijo povezave. Uporablja se za " +"zagotavljanje dodatnih informacij povezave za sisteme kot sta Presto in BigQuery, " +"ki nista skladna s sintakso username:password, ki jo običajno uporablja " +"SQLAlchemy." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:374 +msgid "Enter CA_BUNDLE" +msgstr "Vnesite CA_BUNDLE" -#: superset/views/database/views.py:293 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:379 msgid "" -"You cannot specify a namespace both in the name of the table: " -"\"%(excel_table.table)s\" and in the schema field: " -"\"%(excel_table.schema)s\". Please remove one" +"Optional CA_BUNDLE contents to validate HTTPS requests. Only available on certain " +"database engines." msgstr "" -"Imenskega prostora ni mogoče podati hkrati v tabeli: " -"\"%(excel_table.table)s\" in polju sheme: \"%(excel_table.schema)s\". " -"Odstranite enega" +"Opcijska CA_BUNDLE vsebina, za potrjevanje HTTPS zahtev. Razpoložljivo le na " +"določenih sistemih podatkovnih baz." -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Vis.js:366 -msgid "You cannot use 45° tick layout along with the time range filter" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:387 +msgid "Schemas allowed for CSV upload" +msgstr "Dovoljene sheme za nalaganje CSV" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:401 +msgid "A comma-separated list of schemas that CSVs are allowed to upload to." +msgstr "Z vejicami ločen seznam shem, kjer je dovoljeno nalaganje CSV-jev." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:413 +msgid "Impersonate logged in user (Presto, Trino, Drill, Hive, and GSheets)" msgstr "" -"Skupaj s filtriranjem časovnega obdobja ne morete uporabiti oznak pod 45°" -" kotom" +"Predstavljanje kot prijavljeni uporabnik (Presto, Trino, Drill, Hive in GSheets)" -#: superset/viz.py:696 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:418 msgid "" -"You cannot use [Columns] in combination with [Group " -"By]/[Metrics]/[Percentage Metrics]. Please choose one or the other." +"If Presto or Trino, all the queries in SQL Lab are going to be executed as the " +"currently logged on user who must have permission to run them. If Hive and hive." +"server2.enable.doAs is enabled, will run the queries as service account, but " +"impersonate the currently logged on user via hive.server2.proxy.user property." msgstr "" -"Ne smete uporabiti [Stolpci] v kombinaciji z " -"[Združevanje]/[Mere]/[Procentualne mere]. Izberite eno ali drugo." +"V primeru Presto ali Trino se vse poizvedbe v SQL laboratoriju zaženejo pod " +"trenutno prijavljenim uporabnikom, ki mora imeti pravice za poganjanje. Če je " +"omogočen Hive in hive.server2.enable.doAs, poizvedbe tečejo pod servisnim " +"računom, vendar je trenutno prijavljen uporabnik predstavljen z lastnostjo hive." +"server2.proxy.user." -#: superset-frontend/src/explore/components/PropertiesModal/index.tsx:66 -msgid "You do not have permission to edit this chart" -msgstr "Nimate dovoljenja za urejanje tega grafikona" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:435 +msgid "Allow data upload" +msgstr "Dovoli nalaganje podatkov" -#: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:77 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:118 -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx:48 -msgid "You do not have permission to edit this dashboard" -msgstr "Nimate dovoljenja za urejanje te nadzorne plošče" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:438 +msgid "If selected, please set the schemas allowed for data upload in Extra." +msgstr "Če je izbrano, nastavite dovoljene sheme za nalaganje podatkov v Dodatno." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:455 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:460 +msgid "Metadata Parameters" +msgstr "Parametri metapodatkov" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:470 +msgid "The metadata_params object gets unpacked into the sqlalchemy.MetaData call." +msgstr "Objekt metadata_params se razpakira v klic sqlalchemy.MetaData." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:477 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:482 +msgid "Engine Parameters" +msgstr "Parametri podatkovne baze" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:492 +msgid "" +"The engine_params object gets unpacked into the sqlalchemy.create_engine call." +msgstr "Objekt engine_params se razširi v klic sqlalchemy.create_engine." + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:500 +msgid "Version" +msgstr "Verzija" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:507 +msgid "Version number" +msgstr "Številka verzije" + +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:512 +msgid "" +"Specify the database version. This should be used with Presto in order to enable " +"query cost estimation." +msgstr "" +"Podajte verzijo podatkovne baze. Uporablja se s Presto, za potrebe ocenjevanja " +"potratnosti poizvedbe." -#: superset/templates/superset/request_access.html:25 -#, python-format -msgid "You do not have permissions to access the datasource(s): %(name)s." -msgstr "Nimate dovoljenj za dostop do podatkovnih virov: %(name)s." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:149 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:55 +msgid "Display Name" +msgstr "Ime za prikaz" -#: superset-frontend/src/dashboard/actions/dashboardState.js:133 -msgid "You do not have permissions to edit this dashboard." -msgstr "Nimate dovoljenj za urejanje te nadzorne plošče." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:64 +msgid "Name your database" +msgstr "Poimenujte podatkovno bazo" -#: superset/dashboards/commands/exceptions.py:86 -msgid "You don't have access to this dashboard." -msgstr "Nimate dostopa do te nadzorne plošče." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:69 +msgid "Pick a name to help you identify this database." +msgstr "Izberite ime za lažjo prepoznavo podatkovne baze." -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:144 -msgid "You don't have any favorites yet!" -msgstr "Priljubljenih še niste izbrali!" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:84 +msgid "dialect+driver://username:password@host:port/database" +msgstr "dialect+driver://username:password@host:port/database" -#: superset/key_value/commands/exceptions.py:45 -#, fuzzy -msgid "You don't have permission to modify the value." -msgstr "Nimate dovoljenja za urejanje tega grafikona" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:91 +msgid "Refer to the" +msgstr "Obrnite se na" -#: superset/views/core.py:618 superset/views/core.py:823 -#: superset/views/core.py:829 superset/views/core.py:999 -#: superset/views/core.py:1017 -msgid "You don't have the rights to " -msgstr "Nimate pravic za " +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:99 +msgid "for more information on how to structure your URI." +msgstr "za več informacij o oblikovanju URI." -#: superset-frontend/src/components/EditableTitle/index.tsx:199 -msgid "You don't have the rights to alter this title." -msgstr "Nimate pravic za spreminjanje tega naslova." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:109 +msgid "Test connection" +msgstr "Preizkus povezave" -#: superset/views/core.py:406 -msgid "You have no permission to approve this request" -msgstr "Nimate dovoljenja za odobritev te zahteve" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:480 +msgid "Please enter a SQLAlchemy URI to test" +msgstr "Vnesite SQLAlchemy URI za test" -#: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/RemovedFilter.tsx:39 -msgid "You have removed this filter." -msgstr "Odstranili ste ta filter." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:620 +msgid "Database settings updated" +msgstr "Nastavitve podatkovne baze posodobljene" -#: superset-frontend/src/dashboard/components/Dashboard.jsx:88 -msgid "You have unsaved changes." -msgstr "Imate neshranjene spremembe." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:636 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:655 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:919 +msgid "Database connected" +msgstr "Podatkovna baza povezana" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:160 -msgid "You must pick a name for the new dashboard" -msgstr "Izbrati morate ime nove nadzorne plošče" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:669 +#, python-format +msgid "Sorry there was an error fetching database information: %s" +msgstr "Pri pridobivanju informacij o podatkovni bazi je prišlo do napake: %s" -#: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:518 -msgid "You must run the query successfully first" -msgstr "Najprej morate uspešno izvesti poizvedbo" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:714 +msgid "Or choose from a list of other databases we support:" +msgstr "Ali izberite iz seznama drugih podatkovnih baz, ki jih podpiramo:" -#: superset-frontend/src/dashboard/components/Header/index.jsx:382 -msgid "Your dashboard is too large. Please reduce its size before saving it." -msgstr "Vaša nadzorna plošča je prevelika. Pred shranjevanjem jo zmanjšajte." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:716 +msgid "Supported databases" +msgstr "Podprte podatkovne baze" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:876 -msgid "Your query could not be saved" -msgstr "Vaše poizvedbe ni mogoče shraniti" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:720 +msgid "Choose a database..." +msgstr "Izberite podatkovno bazo..." -#: superset-frontend/src/SqlLab/actions/sqlLab.js:166 -msgid "Your query could not be scheduled" -msgstr "Vaše poizvedbe ni mogoče uvrstiti v urnik" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:744 +msgid "Want to add a new database?" +msgstr "Želite dodati novo podatkovno bazo?" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:892 -msgid "Your query could not be updated" -msgstr "Vaše poizvedbe ni mogoče posodobiti" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:749 +msgid "Any databases that allow connections via SQL Alchemy URIs can be added. " +msgstr "" +"Dodate lahko katerokoli podatkovno bazo, ki podpira konekcije z SQL Alchemy URI-" +"ji. " -#: superset-frontend/src/SqlLab/actions/sqlLab.js:159 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:763 msgid "" -"Your query has been scheduled. To see details of your query, navigate to " -"Saved queries" +"Any databases that allow connections via SQL Alchemy URIs can be added. Learn " +"about how to connect a database driver " msgstr "" -"Vaša poizvedba je v urniku. Za ogled podrobnosti poizvedbe pojdite na " -"shranjene poizvedbe" +"Dodate lahko katerokoli podatkovno bazo, ki podpira konekcije z SQL Alchemy URI-" +"ji. Naučite se kako povezati gonilnik podatkovne baze " -#: superset-frontend/src/SqlLab/actions/sqlLab.js:872 -msgid "Your query was saved" -msgstr "Vaša poizvedba je shranjena" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:827 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:843 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:862 +msgid "Back" +msgstr "Nazaj" -#: superset-frontend/src/SqlLab/actions/sqlLab.js:888 -msgid "Your query was updated" -msgstr "Vaša poizvedba je posodobljena" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:834 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:870 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1199 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1235 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1422 +msgid "Connect" +msgstr "Poveži" -#: superset-frontend/src/reports/actions/reports.js:172 -msgid "Your report could not be deleted" -msgstr "Vašega poročila ni mogoče izbrisati" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:851 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:897 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1422 +msgid "Finish" +msgstr "Zaključi" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:306 -msgid "Zoom" -msgstr "Povečava" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:891 +msgid "This database is managed externally, and can't be edited in Superset" +msgstr "Ta podatkovna baza se ne ureja znotraj Superseta" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:310 -msgid "Zoom level of the map" -msgstr "Stopnja povečave zemljevida" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:995 +msgid "" +"The passwords for the databases below are needed in order to import them. Please " +"note that the \"Secure Extra\" and \"Certificate\" sections of the database " +"configuration are not present in explore files and should be added manually after " +"the import if they are needed." +msgstr "" +"Gesla za spodnje podatkovne baze so potrebna za njihov uvoz. Sekciji \"Dodatna " +"varnost\" in \"Certifikati\" v nastavitvah podatkovne baze nista prisotni v " +"izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če je to potrebno." -#: superset/tasks/schedules.py:658 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1010 #, python-format -msgid "[Alert] %(label)s" -msgstr "[Alert] %(label)s" +msgid "%s PASSWORD" +msgstr "%s GESLO" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "[Od]-" - -#: superset/viz.py:2349 -msgid "[Longitude] and [Latitude] columns must be present in [Group By]" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1034 +msgid "" +"You are importing one or more databases that already exist. Overwriting might " +"cause you to lose some of your work. Are you sure you want to overwrite?" msgstr "" -"Stolpca [Zemljepisna dolžina] in [Zemljepisna širina] morata biti " -"prisotna v [Združevanje]" +"Uvažate eno ali več podatkovnih baz, ki že obstajajo. S prepisom lahko izgubite " +"podatke. Ali ste prepričani, da želite prepisati?" -#: superset/viz.py:2299 -msgid "[Longitude] and [Latitude] must be set" -msgstr "[Zemljepisna dolžina] in [Zemljepisna širina] morata biti nastavljeni" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1045 +#, python-format +msgid "TYPE \"OVERWRITE\" TO CONFIRM" +msgstr "VNESITE \"PREPIŠI\" ZA POTRDITEV" -#: superset/views/core.py:783 -msgid "[Missing Dataset]" -msgstr "[Manjka podatkovni set]" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1102 +msgid "Database Creation Error" +msgstr "Napaka pri ustvarjanju podatkovne baze" -#: superset/utils/core.py:864 -#, python-format -msgid "[Superset] Access to the datasource %(name)s was granted" -msgstr "[Superset] dostop do podatkovnega vira %(name)s je odobren" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1203 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1240 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1426 +msgid "Connect a database" +msgstr "Poveži se s podatkovno bazo" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "[Do]-" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1240 +msgid "Edit database" +msgstr "Uredi podatkovno bazo" -#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 -msgid "[Untitled]" -msgstr "[Neimenovana]" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1297 +msgid "Connect this database using the dynamic form instead" +msgstr "S podatkovno bazo se povežite z dinamičnim obrazcem" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:203 -msgid "[dashboard name]" -msgstr "[ime nadzorne plošče]" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1300 +msgid "" +"Click this link to switch to an alternate form that exposes only the required " +"fields needed to connect this database." +msgstr "" +"Kliknite to povezavo za drugo vnosno formo, ki prikaže samo zahtevana polja za " +"povezavo s podatkovno bazo." -#: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:64 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1356 msgid "" -"[optional] this secondary metric is used to define the color as a ratio " -"against the primary metric. When omitted, the color is categorical and " -"based on labels" +"Select databases require additional fields to be completed in the Advanced tab to " +"successfully connect the database. Learn what requirements your databases has " msgstr "" -"[opcijsko] sekundarna mera določa barvo kot razmerje do primarne mere. Če" -" je izpuščena, je barva določena kategorično na podlagi oznak" +"Izbira podatkovnih baz za uspešno povezavo zahteva izpolnitev dodatnih polj v " +"zavihku Napredno. Naučite se, kaj zahteva vaša podatkovna baza " -#: superset/utils/pandas_postprocessing.py:519 -msgid "`compare_columns` must have the same length as `source_columns`." -msgstr "`compare_columns` morajo imeti enako dolžino kot `source_columns`." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1476 +msgid "Import database from file" +msgstr "Uvozi podatkovno bazo iz datoteke" -#: superset/utils/pandas_postprocessing.py:523 -msgid "`compare_type` must be `difference`, `percentage` or `ratio`" -msgstr "`compare_type` mora biti `difference`, `percentage` ali `ratio`" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1552 +msgid "Connect this database with a SQLAlchemy URI string instead" +msgstr "S to podatkovno bazo se raje povežite z SQLAlchemy URI nizom" -#: superset/charts/schemas.py:557 -msgid "`confidence_interval` must be between 0 and 1 (exclusive)" -msgstr "`confidence_interval` mora biti med 0 in 1 (odprt)" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1557 +msgid "" +"Click this link to switch to an alternate form that allows you to input the " +"SQLAlchemy URL for this database manually." +msgstr "" +"Kliknite to povezavo za drugo vnosno formo, ki omogoča ročni vnos SQLAlchemy URL-" +"ja za to podatkovno bazo." -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:154 +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:40 msgid "" -"`count` is COUNT(*) if a group by is used. Numerical columns will be " -"aggregated with the aggregator. Non-numerical columns will be used to " -"label points. Leave empty to get a count of points in each cluster." +"This can be either an IP address (e.g. 127.0.0.1) or a domain name (e.g. " +"mydatabase.com)." msgstr "" -"`število` je COUNT(*), če je uporabljeno združevanje (group by). " -"Numerični stolpci bodo agregirani z agregatorjem. Ne-numerični stolpci, " -"bodo uporabljeni za oznake točk. Pustite prazno, da dobite število točk v" -" posamezni gruči." +"To je lahko bodisi IP naslov (npr. 127.0.0.1) bodisi ime domene (npr. mydatabase." +"com)." -#: superset/common/query_object.py:388 -msgid "`operation` property of post processing object undefined" -msgstr "Lastnost `operation` poprocesirnega objekta ni definirana" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:45 +msgid "e.g. 127.0.0.1" +msgstr "npr. 127.0.0.1" -#: superset/utils/pandas_postprocessing.py:765 -msgid "`prophet` package not installed" -msgstr "Knjižnica `prophet` ni nameščena" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:47 +msgid "Host" +msgstr "Gostitelj" -#: superset/utils/pandas_postprocessing.py:722 -msgid "`rename_columns` must have the same length as `columns`." -msgstr "`rename_columns` morajo imeti enako dolžino kot `columns`." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:67 +msgid "e.g. 5432" +msgstr "npr. 5432" -#: superset/charts/schemas.py:1070 -msgid "`row_limit` must be greater than or equal to 0" -msgstr "`row_limit` mora biti večja ali enaka 0" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:88 +msgid "e.g. world_population" +msgstr "npr. world_population" -#: superset/charts/schemas.py:1077 -msgid "`row_offset` must be greater than or equal to 0" -msgstr "`row_offset` mora biti večja ali enaka 1" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:91 +msgid "Copy the name of the database you are trying to connect to." +msgstr "Kopirajte ime podatkovne baze, s katero se skušate povezati." -#: superset/charts/schemas.py:932 -msgid "`width` must be greater or equal to 0" -msgstr "`width` mora biti večja ali enaka 0" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:108 +msgid "e.g. Analytics" +msgstr "npr. Analitika" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:413 -msgid "aggregate" -msgstr "agregacija" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:129 +msgid "e.g. ********" +msgstr "npr. ********" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:90 -msgid "alert" -msgstr "opozorilo" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:151 +msgid "Pick a nickname for this database to display as in Superset." +msgstr "Izberite vzdevek za to podatkovno bazo, ki bo prikazan v Supersetu." -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:91 -msgid "alerts" -msgstr "opozorila" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:172 +msgid "e.g. param1=value1¶m2=value2" +msgstr "npr. param1=value1¶m2=value2" -#: superset-frontend/src/dashboard/components/SaveModal.tsx:213 -msgid "also copy (duplicate) charts" -msgstr "kopiraj (podvoji) tudi grafikone" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:173 +msgid "Additional Parameters" +msgstr "Dodatni parametri" -#: superset/views/core.py:823 superset/views/core.py:1000 -msgid "alter this " -msgstr "spreminjanje tega " +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:175 +msgid "Add additional custom parameters" +msgstr "Dodaj dodatne parametre po meri" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:194 -msgid "ancestor" -msgstr "nadrejeni" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:202 +msgid "SSL Mode \"require\" will be used." +msgstr "Uporabljen bo SSL način tipa \"require\"." -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:47 -msgid "and" -msgstr "in" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:73 +msgid "Type of Google Sheets allowed" +msgstr "Dovoljeni tipi Googlovih preglednic" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:111 -#, python-format -msgid "and the explore view times out at %s seconds " -msgstr "čas izteka raziskovalnega pogleda v sekundah: %s " +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:83 +msgid "Publicly shared sheets only" +msgstr "Samo javno deljene preglednice" -#: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:64 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:106 -msgid "annotation" -msgstr "oznaka" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:86 +msgid "Public and privately shared sheets" +msgstr "Javno in zasebno deljene preglednice" -#: superset/views/annotations.py:40 -msgid "annotation start time or end time is required." -msgstr "začetni in končni čas oznake je obvezen." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:94 +msgid "How do you want to enter service account credentials?" +msgstr "Kako želite vnesti prijavne podatke servisnega računa?" -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:102 -msgid "annotation_layer" -msgstr "annotation_layer" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:102 +msgid "Upload JSON file" +msgstr "Naloži JSON datoteko" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:48 -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:50 -msgid "at" -msgstr "ob" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:106 +msgid "Copy and Paste JSON credentials" +msgstr "Kopiraj in prilepi JSON prijavne podatke" -#: superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx:74 -#: superset-frontend/src/explore/components/ControlHeader.jsx:76 -msgid "bolt" -msgstr "vijak" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:115 +msgid "Service Account" +msgstr "Servisni račun" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:161 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:179 -msgid "bottom" -msgstr "spodaj" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:124 +msgid "Copy and paste the entire service account .json file here" +msgstr "Tukaj kopirajte in prilepite celotno json datoteko servisnega računa" -#: superset-frontend/src/components/CachedLabel/index.tsx:51 -msgid "cached" -msgstr "predpomnjen" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:134 +msgid "Upload Credentials" +msgstr "Naloži prijavne podatke" -#: superset-frontend/packages/superset-ui-core/src/validator/validateNonEmpty.ts:29 -msgid "cannot be empty" -msgstr "ne sme biti prazno" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:136 +msgid "" +"Use the JSON file you automatically downloaded when creating your service account." +msgstr "" +"Uporabite JSON datoteko, ki ste jo prenesli pri ustvarjanju servisnega računa." -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:143 -#, fuzzy -msgid "" -"cannot be used as a column name. The column name/alias \"__timestamp\"\n" -" is reserved for the main temporal expression, and column " -"aliases ending with\n" -" double underscores followed by a numeric value (e.g. " -"\"my_col__1\") are reserved\n" -" for deduplicating duplicate column names. Please use aliases to" -" rename the\n" -" invalid column names." -msgstr "" -"ni mogoče uporabiti kot imena stolpcev. Ime stolpca \"__timestamp\"\r\n" -" je rezervirano za glavni časovni izraz. Imena stolpcev, ki se " -"končajo z\r\n" -" dvojnim podčrtajem, ki mu sledi številska vrednost (npr. " -"\"moj_stolpec__1\") so rezervirana\r\n" -" za deduplikacijo duplikatov imen stolpcev. Za preimenovanje " -"neustreznih imen\r\n" -" uporabite psevdonime." - -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:146 -#: superset-frontend/src/views/CRUD/chart/ChartList.tsx:699 -#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:81 -#: superset/views/core.py:823 superset/views/core.py:829 -msgid "chart" -msgstr "grafikona" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:40 +msgid "Connect Google Sheets as tables to this database" +msgstr "Googlove preglednice poveži s to podatkovno bazo kot tabele" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:26 -#, fuzzy -msgid "charts" -msgstr "grafikona" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:46 +msgid "Google Sheet Name and URL" +msgstr "Ime Googlove preglednice in URL" -#: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:101 -msgid "choose WHERE or HAVING..." -msgstr "izberite WHERE ali HAVING..." +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:54 +msgid "Enter a name for this sheet" +msgstr "Vnesite ime te preglednice" -#: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:402 -msgid "column" -msgstr "stolpec" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:78 +msgid "Paste the shareable Google Sheet URL here" +msgstr "Prilepite deljeni URL Googlove preglednice sem" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:116 -msgid "count" -msgstr "število" +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:98 +msgid "Add sheet" +msgstr "Dodaj preglednico" -#: superset/views/core.py:829 superset/views/core.py:1018 -msgid "create a " -msgstr "ustvarite " +#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx:26 +msgid "Copy the account name of that database you are trying to connect to." +msgstr "Kopirajte ime računa podatkovne baze, s katero se skušate povezati." -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:253 -msgid "css" -msgstr "css" +#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:125 +msgid "Add dataset" +msgstr "Dodaj podatkovni set" -#: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:91 -msgid "css_template" -msgstr "css_template" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:171 +msgid "Dataset imported" +msgstr "Podatkovni set uvožen" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:120 -msgid "cumulative" -msgstr "kumulativno" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:207 +msgid "An error occurred while fetching dataset related data" +msgstr "Napaka pri pridobivanju podatkov iz podatkovnega seta" -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:115 -#: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:678 -#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:77 -#: superset/views/core.py:1001 superset/views/core.py:1019 -msgid "dashboard" -msgstr "nadzorna plošča" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:227 +#, python-format +msgid "An error occurred while fetching dataset related data: %s" +msgstr "Napaka pri pridobivanju podatkov iz podatkovnega seta: %s" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:27 -#, fuzzy -msgid "dashboards" -msgstr "nadzorna plošča" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:254 +msgid "Physical dataset" +msgstr "Fizičen podatkovni set" -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:89 -#: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:471 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:464 -msgid "database" -msgstr "podatkovna baza" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:262 +msgid "Virtual dataset" +msgstr "Virtualen podatkovni set" -#: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:116 -#: superset-frontend/src/views/CRUD/data/dataset/AddDatasetModal.tsx:61 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:123 -#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:699 -msgid "dataset" -msgstr "podatkovni set" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:469 +#, python-format +msgid "An error occurred while fetching dataset owner values: %s" +msgstr "Pri pridobivanju polja lastnik podatkovnega seta je prišlo do napake: %s" -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:304 -msgid "date" -msgstr "datum" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:488 +#, python-format +msgid "An error occurred while fetching datasets: %s" +msgstr "Prišlo je do napake pri pridobivanju podatkovnih setov: %s" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:39 -msgid "day" -msgstr "dan" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:503 +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:358 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:456 +#, python-format +msgid "An error occurred while fetching schema values: %s" +msgstr "Pri pridobivanju vrednosti shem je prišlo do napake: %s" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:30 -msgid "day of the month" -msgstr "dan v mesecu" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:572 +msgid "Import datasets" +msgstr "Uvozi podatkovne sete" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:32 -msgid "day of the week" -msgstr "dan v tednu" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:623 +#, python-format +msgid "There was an issue deleting the selected datasets: %s" +msgstr "Pri brisanju izbranih podatkovnih setov je prišlo do težave: %s" -#: superset-frontend/src/components/DeleteModal/index.tsx:84 -msgid "delete" -msgstr "izbriši" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:639 +#, python-format +msgid "" +"The dataset %s is linked to %s charts that appear on %s dashboards. Are you sure " +"you want to continue? Deleting the dataset will break those objects." +msgstr "" +"Podatkovni set %s je povezan z grafikoni %s, ki so prisotni na nadzorni plošči " +"%s. Ali želite nadaljevati? Izbris podatkovnega seta bo pokvaril te objekte." -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:195 -msgid "descendant" -msgstr "podrejeni" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:652 +msgid "Delete Dataset?" +msgstr "Izbrišem podatkovni set?" -#: superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx:64 -#: superset-frontend/src/explore/components/ControlHeader.jsx:66 -#: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:327 -#: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:258 -msgid "description" -msgstr "opis" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:665 +msgid "Are you sure you want to delete the selected datasets?" +msgstr "Ali ste prepričani, da želite izbrisati izbrane podatkovne sete?" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:71 -msgid "dialect+driver://username:password@host:port/database" -msgstr "dialect+driver://username:password@host:port/database" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:715 +msgid "0 Selected" +msgstr "Izbranih: 0" -#: superset/views/core.py:618 -msgid "download as csv" -msgstr "prenos kot csv" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:718 +#, python-format +msgid "%s Selected (Virtual)" +msgstr "Izbranih: %s (virtualni)" -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:153 -msgid "draft" -msgstr "osnutek" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:725 +#, python-format +msgid "%s Selected (Physical)" +msgstr "Izbranih: %s (fizični)" -#: superset/views/log/__init__.py:32 -msgid "dttm" -msgstr "dttm" +#: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:732 +#, python-format +msgid "%s Selected (%s Physical, %s Virtual)" +msgstr "Izbranih: %s (fizični: %s, virtualni: %s)" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:129 -msgid "e.g. ********" +#: superset-frontend/src/views/CRUD/data/dataset/constants.ts:23 +msgid "" +"The passwords for the databases below are needed in order to import them together " +"with the datasets. Please note that the \"Secure Extra\" and \"Certificate\" " +"sections of the database configuration are not present in export files, and " +"should be added manually after the import if they are needed." msgstr "" +"Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj s podatkovnimi seti. " +"Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah podatkovne baze " +"nista prisotni v izvoženih datotekah in jih je potrebno dodati ročno po uvozu, če " +"je to potrebno." -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:45 -msgid "e.g. 127.0.0.1" +#: superset-frontend/src/views/CRUD/data/dataset/constants.ts:30 +msgid "" +"You are importing one or more datasets that already exist. Overwriting might " +"cause you to lose some of your work. Are you sure you want to overwrite?" msgstr "" +"Uvažate enega ali več podatkovnih setov, ki že obstajajo. S prepisom lahko " +"izgubite podatke. Ali ste prepričani, da želite prepisati?" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:67 -msgid "e.g. 5432" -msgstr "" +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:109 +#, python-format +msgid "There was an issue previewing the selected query. %s" +msgstr "Pri predogledu izbrane poizvedbe je prišlo do težave. %s" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:108 -#, fuzzy -msgid "e.g. Analytics" -msgstr "Napredna analitika" +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:205 +#, python-format +msgid "Duration: %s" +msgstr "Trajanje: %s" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:172 -msgid "e.g. param1=value1¶m2=value2" -msgstr "" +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:218 +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:145 +msgid "Tab name" +msgstr "Naslov zavihka" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:88 -msgid "e.g. world_population" -msgstr "" +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:250 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:307 +msgid "TABLES" +msgstr "TABELE" -#: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:126 -msgid "e.g., a \"user id\" column" -msgstr "t.j. stolpec \"id uporabnika\"" +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:317 +msgid "Open query in SQL Lab" +msgstr "Odpri poizvedbo v SQL laboratoriju" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:27 -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:35 -msgid "every" -msgstr "vsak" +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:341 +#, python-format +msgid "An error occurred while fetching database values: %s" +msgstr "Pri pridobivanju vrednosti podatkovne baze je prišlo do napake: %s" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:29 -msgid "every day of the month" -msgstr "vsak dan v mesecu" +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:375 +#, python-format +msgid "An error occurred while fetching user values: %s" +msgstr "Pri pridobivanju vrednosti uporabnika je prišlo do napake: %s" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:31 -msgid "every day of the week" -msgstr "vsak dan v tednu" +#: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:388 +msgid "Search by query text" +msgstr "Išči z besedilom poizvedbe" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:33 -msgid "every hour" -msgstr "vsako uro" +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:133 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:113 +msgid "Next" +msgstr "Naslednji" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:34 -msgid "every minute" -msgstr "vsako minuto" +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:141 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:121 +msgid "Open in SQL Lab" +msgstr "Odpri v SQL laboratoriju" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:28 -msgid "every month" -msgstr "vsak mesec" +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:154 +msgid "User query" +msgstr "Uporabnikova poizvedba" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:123 -msgid "feature to store a summarized data set that you can then explore." -msgstr "funkcijo shranjevanja strnjenega podatkovnega seta, ki ga lahko raziščete." +#: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:162 +msgid "Executed query" +msgstr "Zagnana poizvedba" -#: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:87 -msgid "fetching" -msgstr "pridobivam" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:56 +msgid "" +"The passwords for the databases below are needed in order to import them together " +"with the saved queries. Please note that the \"Secure Extra\" and \"Certificate\" " +"sections of the database configuration are not present in export files, and " +"should be added manually after the import if they are needed." +msgstr "" +"Gesla za spodnje podatkovne baze so potrebna za uvoz skupaj s shranjenimi " +"poizvedbami. Sekciji \"Dodatna varnost\" in \"Certifikati\" v nastavitvah " +"podatkovne baze nista prisotni v izvoženih datotekah in jih je potrebno dodati " +"ročno po uvozu, če je to potrebno." -#: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:86 -#: superset-frontend/src/dashboard/containers/DashboardPage.tsx:143 +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:63 msgid "" -"filter_box will be deprecated in a future version of Superset. Please " -"replace filter_box by dashboard filter components." +"You are importing one or more saved queries that already exist. Overwriting might " +"cause you to lose some of your work. Are you sure you want to overwrite?" msgstr "" -"Element filter_box bo v prihodnjih verzijah Superseta opuščen. " -"Nadomestite ga s filtri nadzorne plošče." +"Uvažate eno ali več shranjenih poizvedb, ki že obstajajo. S prepisom lahko " +"izgubite podatke. Ali ste prepričani, da želite prepisati?" -#: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:115 -msgid "following this flow will most likely lead to your query timing out. " -msgstr "s takšnim potekom, bo poizvedba najverjetneje potekla. " +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:129 +msgid "Query imported" +msgstr "Poizvedba uvožena" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:86 -msgid "for more information on how to structure your URI." -msgstr "za več informacij o oblikovanju URI." +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:152 +#, python-format +msgid "There was an issue previewing the selected query %s" +msgstr "Do težave je prišlo pri predogledu izbrane poizvedbe %s" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:41 -msgid "green" -msgstr "zelena" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:190 +msgid "Import queries" +msgstr "Uvozi poizvedbe" -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:724 -#: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1136 -#, fuzzy -msgid "here" -msgstr "Deljenje" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:264 +#, python-format +msgid "There was an issue deleting the selected queries: %s" +msgstr "Do težave je prišlo pri brisanju izbranih poizvedb: %s" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:40 -msgid "hour" -msgstr "ura" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:385 +msgid "Edit query" +msgstr "Uredi poizvedbo" -#: superset-frontend/src/profile/components/UserInfo.tsx:75 -msgid "id:" -msgstr "id:" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:392 +msgid "Copy query URL" +msgstr "Kopiraj URL poizvedbe" -#: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:153 -msgid "" -"image-rendering CSS attribute of the canvas object that defines how the " -"browser scales up the image" -msgstr "" -"atribut CSS za izris objekta platna, ki določa, kako brskalnik poveča " -"sliko" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:399 +msgid "Export query" +msgstr "Izvozi poizvedbe" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:44 -msgid "in" -msgstr "v" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:406 +msgid "Delete query" +msgstr "Izbriši poizvedbo" -#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:122 -msgid "in modal" -msgstr "v modalnem" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:477 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:250 +msgid "This action will permanently delete the saved query." +msgstr "S tem dejanjem boste trajno izbrisali shranjeno poizvedbo." -#: superset-frontend/packages/superset-ui-core/src/validator/legacyValidateNumber.ts:28 -#: superset-frontend/packages/superset-ui-core/src/validator/validateNumber.ts:32 -msgid "is expected to be a number" -msgstr "pričakovano je število" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:487 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:262 +msgid "Delete Query?" +msgstr "Izbrišem poizvedbo?" -#: superset-frontend/packages/superset-ui-core/src/validator/legacyValidateInteger.ts:31 -#: superset-frontend/packages/superset-ui-core/src/validator/validateInteger.ts:32 -msgid "is expected to be an integer" -msgstr "pričakovano je celo število" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:502 +msgid "Are you sure you want to delete the selected queries?" +msgstr "Ali ste prepričani, da želite izbrisati izbrane poizvedbe?" -#: superset-frontend/src/profile/components/UserInfo.tsx:64 -msgid "joined" -msgstr "pridružen" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:545 +msgid "queries" +msgstr "poizvedbe" -#: superset/views/base.py:527 -msgid "json isn't valid" -msgstr "json ni veljaven" +#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryPreviewModal.tsx:125 +msgid "Query name" +msgstr "Ime poizvedbe" + +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:93 +msgid "[Untitled]" +msgstr "[Neimenovana]" + +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 +msgid "Unknown" +msgstr "Neznano" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:233 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:261 -msgid "key a-z" -msgstr "a - ž" +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:123 +#, python-format +msgid "Viewed %s" +msgstr "Ogledane %s" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:234 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:262 -msgid "key z-a" -msgstr "ž - a" +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:160 +msgid "Edited" +msgstr "Urejane" -#: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:152 -msgid "label" -msgstr "oznaka" +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:168 +msgid "Created" +msgstr "Ustvarjene" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:39 -msgid "last day" -msgstr "zadnji dan" +#: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:179 +msgid "Viewed" +msgstr "Ogledane" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:41 -msgid "last month" -msgstr "zadnji mesec" +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:173 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:186 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:279 +msgid "Mine" +msgstr "Moje" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:42 -msgid "last quarter" -msgstr "zadnje četrletje" +#: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:220 +#: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:228 +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:297 +msgid "View All »" +msgstr "Poglejte vse »" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:40 -msgid "last week" -msgstr "zadnji teden" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:26 +msgid "charts" +msgstr "grafikoni" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:43 -msgid "last year" -msgstr "zadnje leto" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:27 +msgid "dashboards" +msgstr "nadzorne plošče" -#: superset-frontend/src/SqlLab/components/TableElement/index.tsx:120 -msgid "latest partition:" -msgstr "zadnja particija:" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:28 +msgid "recents" +msgstr "nedavne" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:158 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:176 -msgid "left" -msgstr "levo" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:29 +msgid "saved queries" +msgstr "shranjene poizvedbe" -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:63 -msgid "log" -msgstr "dnevnik" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:74 +#, python-format +msgid "No %(tableName)s yet" +msgstr "%(tableName)s še ni" -#: superset/charts/schemas.py:624 -msgid "" -"lower percentile must be greater than 0 and less than 100. Must be lower " -"than upper percentile." +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:81 +msgid "Recently viewed charts, dashboards, and saved queries will appear here" msgstr "" -"spodnji percentil mora biti večji od 0 in manjši od 100 ter mora biti " -"manjši od zgornjega percentila." - -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:41 -msgid "minute" -msgstr "minuta" +"Nedavno ogledani grafikoni, nadzorne plošče in shranjene poizvedbe bodo prikazane " +"tukaj" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:51 -msgid "minute(s)" -msgstr "minuta/e" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:86 +msgid "Recently created charts, dashboards, and saved queries will appear here" +msgstr "" +"Nedavno ustvarjeni grafikoni, nadzorne plošče in shranjene poizvedbe bodo " +"prikazane tukaj" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:37 -msgid "month" -msgstr "mesec" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:92 +#, python-format +msgid "Example %(tableName)s will appear here" +msgstr "Primer %(tableName)s se bo prikazal tukaj" -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:116 -#: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:138 -msgid "must have a value" -msgstr "mora imeti vrednost" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:96 +msgid "Recently edited charts, dashboards, and saved queries will appear here" +msgstr "" +"Nedavno urejani grafikoni, nadzorne plošče in shranjene poizvedbe bodo prikazane " +"tukaj" -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:54 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:39 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:31 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:34 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:49 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:34 -#: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 -msgid "nvd3" -msgstr "nvd3" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:124 +#: superset-frontend/src/views/components/MenuRight.tsx:166 +msgid "SQL query" +msgstr "SQL poizvedba" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:45 -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:46 -msgid "on" -msgstr "v" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:143 +msgid "You don't have any favorites yet!" +msgstr "Priljubljenih še niste izbrali!" -#: superset/charts/schemas.py:1098 -msgid "orderby column must be populated" -msgstr "stolpec za razvrščanje (orderby) mora biti izpolnjen" +#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:156 +#, python-format +msgid "See all %(tableName)s" +msgstr "Poglej vse %(tableName)s" -#: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:85 -msgid "p-value precision" -msgstr "točnost p-vrednosti" +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:130 +msgid "query" +msgstr "poizvedba" -#: superset-frontend/plugins/plugin-chart-table/src/consts.ts:26 -msgid "page_size.all" -msgstr "page_size.all" +#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:319 +#, python-format +msgid "Ran %s" +msgstr "Pretečeno %s" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:159 -msgid "page_size.entries" -msgstr "page_size.entries" +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:203 +#, python-format +msgid "There was an issue fetching your recent activity: %s" +msgstr "Pri pridobivanju vaše nedavne aktivnosti je prišlo do napake: %s" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:139 -msgid "page_size.show" -msgstr "page_size.show" +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:225 +#, python-format +msgid "There was an issue fetching your dashboards: %s" +msgstr "Prišlo je do napake pri pridobivanju nadzornih plošč: %s" -#: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:124 -msgid "percentile (exclusive)" -msgstr "percentil (ekskluzivno)" +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:236 +#, python-format +msgid "There was an issue fetching your chart: %s" +msgstr "Prišlo je do napake pri pridobivanju grafikona: %s" -#: superset/utils/pandas_postprocessing.py:921 -msgid "" -"percentiles must be a list or tuple with two numeric values, of which the" -" first is lower than the second value" -msgstr "" -"percentili morajo biti tipa list ali tuple z vsaj dvema numeričnima " -"vrednostma, pri čemer je prva manjša od druge" +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:247 +#, python-format +msgid "There was an issues fetching your saved queries: %s" +msgstr "Prišlo je do napake pri pridobivanju shranjenih poizvedb: %s" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:53 -msgid "previous calendar month" -msgstr "prejšnji koledarski mesec" +#: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:291 +msgid "Recents" +msgstr "Nedavno" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:50 -msgid "previous calendar week" -msgstr "prejšnji koledarski teden" +#: superset-frontend/src/views/components/MenuRight.tsx:136 +msgid "Connect database" +msgstr "Poveži se s podatkovno bazo" -#: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:56 -msgid "previous calendar year" -msgstr "prejšnje koledarsko leto" +#: superset-frontend/src/views/components/MenuRight.tsx:141 +msgid "Connect Google Sheet" +msgstr "Povežite Googlovo preglednico" -#: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:153 -msgid "published" -msgstr "objavljeno" +#: superset-frontend/src/views/components/MenuRight.tsx:146 +msgid "Upload CSV to database" +msgstr "Naloži CSV v podatkovno bazo" -#: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:543 -msgid "queries" -msgstr "poizvedbe" +#: superset-frontend/src/views/components/MenuRight.tsx:152 +msgid "Upload columnar file to database" +msgstr "Naloži datoteko s stolpci v podatkovno bazo" -#: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:129 -msgid "query" -msgstr "poizvedba" +#: superset-frontend/src/views/components/MenuRight.tsx:158 +msgid "Upload Excel file to database" +msgstr "Naloži Excel-ovo datoteko v podatkovno bazo" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:42 -msgid "reboot" -msgstr "ponovni zagon" +#: superset-frontend/src/views/components/MenuRight.tsx:232 +#: superset-frontend/src/views/components/SubMenu.tsx:301 +msgid "Enable 'Allow data upload' in any database's settings" +msgstr "Omogoči 'Dovoli nalaganje podatkov' za vse podatkovne baze" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:28 -#, fuzzy -msgid "recents" -msgstr "Nedavno" +#: superset-frontend/src/views/components/MenuRight.tsx:377 +msgid "About" +msgstr "O programu" -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:43 -msgid "red" -msgstr "rdeča" +#: superset-frontend/src/views/components/MenuRight.tsx:381 +msgid "Powered by Apache Superset" +msgstr "Omogoča Apache Superset" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:90 -#: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:484 -msgid "report" -msgstr "poročilo" +#: superset-frontend/src/views/components/MenuRight.tsx:415 +msgid "Documentation" +msgstr "Dokumentacija" -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:91 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:117 -#: superset-frontend/src/views/CRUD/alert/AlertList.tsx:126 -#: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:72 -msgid "reports" -msgstr "poročila" +#: superset-frontend/src/views/components/MenuRight.tsx:426 +msgid "Report a bug" +msgstr "Sporočite napako" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:160 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:178 -msgid "right" -msgstr "desno" +#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:305 +msgid "Select start and end date" +msgstr "Izberite začetni in končni datum" -#: superset-frontend/src/explore/components/RowCountLabel.jsx:35 -msgid "rows" -msgstr "vrstic" +#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:412 +#, python-format +msgid "Type or Select [%s]" +msgstr "Vnesite ali izberite [%s]" -#: superset-frontend/src/explore/components/DataTableControl/index.tsx:96 -msgid "rows retrieved" -msgstr "vrnjenih vrstic" +#: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:433 +msgid "No results found" +msgstr "Rezultati niso najdeni" -#: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:29 -#, fuzzy -msgid "saved queries" -msgstr "Shranjene poizvedbe" +#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:25 +msgid "Tools" +msgstr "Orodja" -#: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:124 -msgid "search.num_records" -msgstr "search.num_records" +#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:26 +msgid "Filter box" +msgstr "Izbirnik za filtriranje" -#: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:98 +#: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:28 msgid "" -"series: Treat each series independently; overall: All series use the same" -" scale; change: Show changes compared to the first data point in each " -"series" +"Chart component that lets you add a custom filter UI in your dashboard. When " +"added to dashboard, a filter box lets users specify specific values or ranges to " +"filter charts by. The charts that each filter box is applied to can be fine tuned " +"as well in the dashboard view.\n" +"\n" +" Note that this plugin is being replaced with the new Filters feature that " +"lives in the dashboard view itself. It's easier to use and has more capabilities!" msgstr "" -"serije: Obravnavaj vsako podatkovno serijo neodvisno; skupno: Vse vrste " -"uporabljajo enako skalo; razlika: Pokaži razlike glede na prvo točko " -"vsake serije" +"Komponenta grafikona, ki omogoča dodajanje vmesnika filtrov po meri v nadzorno " +"ploščo. Ko je dodana na nadzorno ploščo, lahko uporabnik določi poljubne " +"vrednosti ali obsege filtrov. Grafikoni, na katere se nanašajo filtri, so lahko " +"precizno izbrani tudi v pogledu nadzorne plošče.\n" +"\n" +" Vedite, da bo ta vtičnik v prihodnosti zamenjan z novim konceptom filtrov, ki " +"bodo živeli v kontekstu same nadzorne plošče in bodo zmogljivejši ter " +"enostavnejši za uporabo!" -#: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:92 -msgid "textarea" -msgstr "področje besedila" +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:27 +msgid "Filters configuration" +msgstr "Nastavitve filtrov" -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:159 -#: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:177 -msgid "top" -msgstr "zgoraj" +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:36 +msgid "Filter configuration for the filter box" +msgstr "Nastavitve za polje filtra" + +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:49 +msgid "Date filter" +msgstr "Filter po datumu" + +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:51 +msgid "Whether to include a time filter" +msgstr "Če želite vključiti časovni filter" -#: superset/charts/schemas.py:639 +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:60 +msgid "Instant filtering" +msgstr "Takojšnje filtriranje" + +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:63 msgid "" -"upper percentile must be greater than 0 and less than 100. Must be higher" -" than lower percentile." +"Check to apply filters instantly as they change instead of displaying [Apply] " +"button" msgstr "" -"zgornji percentil mora biti večji od 0 in manjši od 100 ter mora biti " -"večji od spodnjega percentila." +"Izberite za takojšnjo uporabo filtrov, ko se spremenijo, brez prikazovanja gumba " +"Uveljavi" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:235 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:263 -msgid "value ascending" -msgstr "0 - 9" +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:75 +msgid "Limit selector values" +msgstr "Omeji vrednosti izbirnikov" -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:236 -#: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:264 -msgid "value descending" -msgstr "9 - 0" +#: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:76 +msgid "These filters apply to the values available in the dropdowns" +msgstr "Ti filtri se nanašajo na vrednosti v spustnih seznamih" -#: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:857 -msgid "virtual" -msgstr "virtualni" +#: superset-frontend/src/visualizations/TimeTable/controlPanel.js:51 +msgid "URL" +msgstr "URL" -#: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:715 -msgid "was created" -msgstr "ustvarjeno" +#: superset-frontend/src/visualizations/TimeTable/controlPanel.js:52 +msgid "" +"Templated link, it's possible to include {{ metric }} or other values coming from " +"the controls." +msgstr "" +"Vzorčna povezava, vključiti je mogoče {{ metric }} ali drugo vrednost iz " +"kontrolnikov." -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:38 -msgid "week" -msgstr "teden" +#: superset-frontend/src/visualizations/TimeTable/index.ts:26 +msgid "Time-series Table" +msgstr "Tabela s časovno vrsto" -#: superset-frontend/src/components/CronPicker/CronPicker.tsx:36 -msgid "year" -msgstr "leto" +#: superset-frontend/src/visualizations/TimeTable/index.ts:27 +msgid "" +"Compare multiple time series charts (as sparklines) and related metrics quickly." +msgstr "" +"Hitra primerjava več grafikonov časovnih vrst (sparkline način) in povezanih mer." -#: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:42 -msgid "yellow" -msgstr "rumena" +#: superset-frontend/src/visualizations/TimeTable/index.ts:36 +msgid "Text" +msgstr "Besedilo" + +#: superset-frontend/src/visualizations/dashboardComponents/ExampleComponent/ExampleComponent.tsx:29 +#, python-format +msgid "We have the following keys: %s" +msgstr "Imamo naslednje ključe: %s" diff --git a/superset/translations/zh/LC_MESSAGES/messages.json b/superset/translations/zh/LC_MESSAGES/messages.json index b7fd50528ee24..f703ec251889c 100644 --- a/superset/translations/zh/LC_MESSAGES/messages.json +++ b/superset/translations/zh/LC_MESSAGES/messages.json @@ -7,3119 +7,4534 @@ "plural_forms": "nplurals=1; plural=0", "lang": "zh" }, - "Home": ["主页"], - "Annotation Layers": ["注释层"], - "Manage": ["管理"], - "Databases": ["数据库"], - "Data": ["数据"], - "Datasets": ["数据集"], - "Charts": ["图表"], - "Dashboards": ["看板"], - "Plugins": ["插件"], - "CSS Templates": ["CSS 模板"], - "Row level security": ["行级安全"], - "Security": ["安全"], - "Import Dashboards": ["导入看板"], - "SQL Editor": ["SQL 编辑器"], - "SQL Lab": ["SQL 工具箱"], - "Saved Queries": ["已保存查询"], - "Query History": ["历史查询"], - "Upload a CSV": ["上传CSV文件"], - "Upload Excel": ["上传Excel"], - "Action Log": ["操作日志"], - "Dashboard Emails": ["看板"], - "Chart Email Schedules": ["图表电子邮件时间表"], - "Alerts": ["警报"], - "Alerts & Reports": ["警报和报告"], - "Access requests": ["访问请求"], - "Druid Datasources": ["Druid 数据源"], - "Druid Clusters": ["Druid 集群"], - "Scan New Datasources": ["扫描新的数据源"], - "Refresh Druid Metadata": ["刷新 Druid 元数据"], - "Issue 1000 - The datasource is too large to query.": [ - "Issue 1000 - 数据源太大,无法进行查询。" - ], - "Issue 1001 - The database is under an unusual load.": [ - "Issue 1001 - 数据库负载异常。" + "\n This filter was inherited from the dashboard's context.\n It won't be saved when saving the chart.\n ": [ + "此过滤条件是从看板上下文继承的。保存图表时不会保存。" ], - "Issue 1002 - The database returned an unexpected error.": [ - "Issue 1002 - 数据库返回意外错误。" + "\n <b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>\n <img src=\"cid:%(msgid)s\">\n ": [ + "\n <b><a href=\"%(url)s\">探索 Superset</a></b><p></p>\n <img src=\"cid:%(msgid)s\">\n " ], - "Issue 1003 - There is a syntax error in the SQL query. Perhaps there was a misspelling or a typo.": [ - "Issue 1003 - SQL查询中存在语法错误。可能是拼写错误或是打错关键字。" + "\n Error: %(text)s\n ": [""], + "\n *%(name)s*\n\n <%(url)s|Explore in Superset>\n ": [ + "\n *%(name)s*\n\n <%(url)s|探索 Superset>\n " ], - "Issue 1004 - The column was deleted or renamed in the database.": [ - "Issue 1004 - 该列已在数据库中删除或重命名。" + "\n *%(slice_name)s*\n\n <%(slice_url_user_friendly)s|Explore in Superset>\n ": [ + "\n *%(slice_name)s*\n\n <%(slice_url_user_friendly)s|探索 Superset>\n " ], - "Issue 1005 - The table was deleted or renamed in the database.": [ - "Issue 1005 - 该表已在数据库中删除或重命名。" + " (excluded)": ["(不包含)"], + " expression which needs to adhere to the ": [" 表达式并基于 "], + " standard to ensure that the lexicographical ordering\n coincides with the chronological ordering. If the\n timestamp format does not adhere to the ISO 8601 standard\n you will need to define an expression and type for\n transforming the string into a date or timestamp. Note\n currently time zones are not supported. If time is stored\n in epoch format, put `epoch_s` or `epoch_ms`. If no pattern\n is specified we fall back to using the optional defaults on a per\n database/column name level via the extra parameter.": [ + "来确保字符的表达顺序与时间顺序一致的标准。如果时间戳格式不符合 ISO 8601 标准,则需要定义表达式和类型,以便将字符串转换为日期或时间戳。注意:当前不支持时区。如果时间以epoch格式存储,请输入 `epoch_s` or `epoch_ms` 。如果没有指定任何模式,我们可以通过额外的参数在每个数据库/列名级别上使用可选的默认值。" ], - "Issue 1006 - One or more parameters specified in the query are missing.": [ - "Issue 1006 - 查询中指定的一个或多个参数丢失。" + "!= (Is not equal)": ["!= (不等于)"], + "${tableName\n .split('')\n .slice(0, tableName.length - 1)\n .join('')}\n ": [ + "" ], - "Invalid certificate": ["无效认证"], - "Unsafe return type for function %(func)s: %(value_type)s": [ - "函数返回不安全的类型 %(func)s: %(value_type)s" + "%(dialect)s cannot be used as a data source for security reasons.": [ + "出于安全原因,%(dialect)s SQLite数据库不能用作数据源。" ], - "Unsupported return value for method %(name)s": [ - "方法的返回值不受支持 %(name)s" + "%(message)s\nThis may be triggered by: \n%(issues)s": [ + "%(message)s\n这可能由以下因素触发:%(issues)s" ], - "Unsafe template value for key %(key)s: %(value_type)s": [ - "键的模板值不安全 %(key)s: %(value_type)s" + "%(name)s.csv": [""], + "%(object)s does not exist in this database.": [ + "%(object)s 数据库中不存在。" ], - "Unsupported template value for key %(key)s": [ - "键的模板值不受支持 %(key)s" + "%(prefix)s %(title)s": [""], + "%(rows)d rows returned": ["%(rows)d行被检索到"], + "%(subtitle)s\nThis may be triggered by:\n %(issue)s": [ + "%(subtitle)s\n这可能由以下因素触发:%(issue)s" ], - "Only `SELECT` statements are allowed against this database": [ - "此数据库只允许使用 `SELECT` 语句" + "%(suggestion)s instead of \"%(undefinedParameter)s?\"": [ + "用 %(suggestion)s 替换 \"%(undefinedParameter)s\" 吗?" ], - "CTAS (create table as select) can only be run with a query where the last statement is a SELECT. Please make sure your query has a SELECT as its last statement. Then, try running your query again.": [ - "CTA(create table as select)只能与最后一条语句为SELECT的查询一起运行。请确保查询的最后一个语句是SELECT。然后再次尝试运行查询。" + "%(user)s was granted the role %(role)s that gives access to the %(datasource)s": [ + "授予 %(user)s %(role)s 角色来访问 %(datasource)s 数据库" ], - "CVAS (create view as select) can only be run with a query with a single SELECT statement. Please make sure your query has only a SELECT statement. Then, try running your query again.": [ - "CVAS(createview as select)只能与带有单个SELECT语句的查询一起运行。请确保您的查询只有SELECT语句。然后再次尝试运行查询。" + "%(user)s's profile": ["%(user)s 的信息"], + "%(validator)s was unable to check your query.\nPlease recheck your query.\nException: %(ex)s": [ + "%(validator)s 无法检查您的查询。\n请重新检查您的查询。\n异常: %(ex)s" ], - "Viz is missing a datasource": ["Viz 缺少一个数据源"], - "Applied rolling window did not return any data. Please make sure the source query satisfies the minimum periods defined in the rolling window.": [ - "应用的滚动窗口(rolling window)未返回任何数据。请确保源查询满足滚动窗口中定义的最小周期。" + "%s - untitled": ["%s - 无标题"], + "%s Error": ["%s 异常"], + "%s Selected": ["%s 已选定"], + "%s Selected (%s Physical, %s Virtual)": [ + "%s 个被选中 (%s 个物理, %s 个虚拟)" ], - "From date cannot be larger than to date": ["起始时间不可以大于当前时间"], - "Cached value not found": ["缓存的值未找到"], - "Columns missing in datasource: %(invalid_columns)s": [ - "数据源中缺少列:%(invalid_columns)s" + "%s Selected (Physical)": ["%s 个被选中(物理)"], + "%s Selected (Virtual)": ["%s 个被选中(虚拟)"], + "%s aggregates(s)": ["%s 聚合"], + "%s column(s)": ["%s 列"], + "%s column(s) and metric(s)": ["%s 列与计量指标"], + "%s operator(s)": ["%s 运算符"], + "%s option": ["%s 个选项"], + "%s option(s)": ["%s 个选项"], + "%s saved metric(s)": ["%s 列与计量指标"], + "%s%s": ["%s%s"], + "%s-%s of %s": ["%s-%s 总计 %s"], + "(Removed)": ["(已删除)"], + "(deleted)": ["删除"], + "(no description, click to see stack trace)": [ + "无描述,单击可查看堆栈跟踪" ], - "Table View": ["表视图"], - "You cannot use [Columns] in combination with [Group By]/[Metrics]/[Percentage Metrics]. Please choose one or the other.": [ - "不能将 [列] 与 [分组]/[指标]/[百分比度量] 结合使用。请选择其中一个。" + "(optional) default value for the filter, when using the multiple option, you can use a semicolon-delimited list of options.": [ + "过滤器的默认值,当使用多选框的时候,您可以使用带分号的分隔列表。" ], - "Pick a granularity in the Time section or uncheck 'Include Time'": [ - "在“时间”部分选择一个粒度,或取消选中“包含时间”" + "*%(name)s*\n\n%(description)s\n\n<%(url)s|Explore in Superset>\n\n%(table)s\n": [ + "" ], - "Time Table View": ["时间表视图"], - "Pick at least one metric": ["选择至少一个指标"], - "When using 'Group By' you are limited to use a single metric": [ - "当使用“Group by”时,只限于使用单个度量。" + "*%(name)s*\n\n%(description)s\n\nError: %(text)s\n": [""], + "**Select** a dashboard OR **create** a new one": [ + "**选择** 一个看板或者 **创建** 一个看板" ], - "Pivot Table": ["透视表"], - "Please choose at least one 'Group by' field ": [ - "请至少选择一个分组字段 " + "-- Note: Unless you save your query, these tabs will NOT persist if you clear your cookies or change browsers.\n\n": [ + "-- 注意:除非您保存查询,否则如果清除cookie或更改浏览器时,这些选项卡将不会保留。" ], - "Please choose at least one metric": ["请至少选择一个指标"], - "Group By' and 'Columns' can't overlap": ["“Group by”列和字段不能重叠"], - "Treemap": ["树状图"], - "Calendar Heatmap": ["时间热力图"], - "Bubble Chart": ["气泡图"], - "Please use 3 different metric labels": ["请在左右轴上选择不同的指标"], - "Pick a metric for x, y and size": ["为 x 轴,y 轴和大小选择一个指标"], - "Bullet Chart": ["子弹图"], - "Pick a metric to display": ["选择一个指标来显示"], - "Big Number with Trendline": ["数字和趋势线"], - "Pick a metric!": ["选择一个指标!"], - "Big Number": ["数字"], - "Time Series - Line Chart": ["时间序列-折线图"], - "Pick a time granularity for your time series": [ - "为您的时间序列选择一个时间粒度" + "0 Selected": ["0个被选中"], + "1 hour": ["1小时"], + "1 minute": ["1分钟"], + "10 minute": ["10分钟"], + "10 seconds": ["10秒钟"], + "12 hours": ["12小时"], + "15 minute": ["15分钟"], + "24 hours": ["24 小时"], + "2D": ["2D"], + "3 letter code of the country": ["国家3字码"], + "30 days": ["30天"], + "30 minute": ["30分钟"], + "30 minutes": ["30分钟"], + "30 second": ["30秒钟"], + "30 seconds": ["30秒钟"], + "5 minute": ["5分钟"], + "5 minutes": ["5分钟"], + "5 second": ["5秒"], + "6 hour": ["6小时"], + "6 hours": ["6小时"], + "60 days": ["60天"], + "90 days": ["90天"], + ":": [":"], + "< (Smaller than)": ["< (小于)"], + "<= (Smaller or equal)": ["<= (小于等于)"], + "<b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>": [ + "<b><a href=\"%(url)s\">探索 Superset</a></b><p></p>" ], - "An enclosed time range (both start and end) must be specified when using a Time Comparison.": [ - "使用时间比较时,必须指定封闭的时间范围(有开始和结束)。" + "== (Is equal)": ["== (等于)"], + "> (Larger than)": ["> (大于)"], + ">= (Larger or equal)": [">= (大于等于)"], + "A Big Number": ["大数字"], + "A SQL statement that defines whether the alert should get triggered or not. The query is expected to return either NULL or a number value.": [ + "定义是否应触发警报的SQL语句。查询应返回NULL或数字值。" ], - "Time Series - Multiple Line Charts": ["时间序列-多线图"], - "Time Series - Dual Axis Line Chart": ["时间序列-双轴线图"], - "Pick a metric for left axis!": ["为左轴选择一个指标!"], - "Pick a metric for right axis!": ["为右轴选择一个指标!"], - "Please choose different metrics on left and right axis": [ - "请在左右轴上选择不同的指标" + "A comma separated list of columns that should be parsed as dates.": [ + "应作为日期解析的列的逗号分隔列表。" ], - "Time Series - Bar Chart": ["时间序列 - 柱状图"], - "Time Series - Period Pivot": ["时间序列 - 周期透视表"], - "Time Series - Percent Change": ["时间序列 - 百分比变化"], - "Time Series - Stacked": ["时间序列 - 堆积图"], - "Histogram": ["直方图"], - "Must have at least one numeric column specified": [ - "必须至少指明一个数值列" + "A comma-separated list of schemas that CSVs are allowed to upload to.": [ + "允许以逗号分割的CSV文件上传" ], - "Distribution - Bar Chart": ["分布 - 柱状图"], - "Can't have overlap between Series and Breakdowns": [ - "Series 和 Breakdown 之间不能有重叠" + "A database with the same name already exists.": ["已存在同名的数据库。"], + "A full URL pointing to the location of the built plugin (could be hosted on a CDN for example)": [ + "指向内置插件位置的完整URL(例如,可以托管在CDN上)" ], - "Pick at least one field for [Series]": ["为 [序列] 选择至少一个字段"], - "Sunburst": ["环状层次图"], - "Sankey": ["蛇形图"], - "Pick exactly 2 columns as [Source / Target]": [ - "为 [来源 / 目标] 选择两个列" + "A human-friendly name": ["人性化的名称"], + "A list of users who can alter the chart. Searchable by name or username.": [ + "有权处理该图表的用户列表。可按名称或用户名搜索。" ], - "There's a loop in your Sankey, please provide a tree. Here's a faulty link: {}": [ - "桑基图里面有一个循环,请提供一棵树。这是一个错误的链接:{}" + "A map of the world, that can indicate values in different countries.": [ + "一张世界地图,可以显示不同国家的价值观。" ], - "Directed Force Layout": ["有向图"], - "Pick exactly 2 columns to 'Group By'": ["为 “Group By” 选择两个列"], - "Country Map": ["国家地图"], - "World Map": ["世界地图"], - "Filters": ["过滤"], - "Invalid filter configuration, please select a column": [ - "过滤器配置无效,请选择一个列" + "A metric to use for color": ["用于颜色的指标"], + "A polar coordinate chart where the circle is broken into wedges of equal angle, and the value represented by any wedge is illustrated by its area, rather than its radius or sweep angle.": [ + "一种极坐标图表,其中圆被分成等角度的楔形,任何楔形表示的值由其面积表示,而不是其半径或扫掠角度。" ], - "Parallel Coordinates": ["平行坐标"], - "Heatmap": ["热力图"], - "Horizon Charts": ["水平图"], - "Mapbox": ["箱图"], - "[Longitude] and [Latitude] must be set": [ - "[经度] 和 [纬度] 的选择项必须出现在 [Group By]" + "A readable URL for your dashboard": ["为看板生成一个可读的 URL"], + "A reference to the [Time] configuration, taking granularity into account": [ + "对 [时间] 配置的引用,会将粒度考虑在内" ], - "Must have a [Group By] column to have 'count' as the [Label]": [ - "[Group By] 列必须要有 ‘count’字段作为 [标签]" + "A semicolon ';' delimited list of email addresses": [ + "以分号 ';' 分隔的电子邮件地址列表" ], - "Choice of [Label] must be present in [Group By]": [ - "[标签] 的选择项必须出现在 [Group By]" + "A set of parameters that become available in the query using Jinja templating syntax": [ + "在查询中可用的一组参数使用JINJA模板语法" ], - "Choice of [Point Radius] must be present in [Group By]": [ - "[点半径] 的选择项必须出现在 [Group By]" + "A time series chart that visualizes how a related metric from multiple groups vary over time. Each group is visualized using a different color.": [ + "时间序列图表,直观显示多个组中的相关指标随时间的变化情况。每组使用不同的颜色进行可视化" ], - "[Longitude] and [Latitude] columns must be present in [Group By]": [ - "[经度] 和 [纬度] 的选择项必须出现在 [Group By]" + "A timeout occurred while executing the query.": ["查询超时。"], + "A timeout occurred while generating a csv.": ["生成CSV时超时。"], + "A timeout occurred while generating a dataframe.": ["生成数据超时"], + "A timeout occurred while taking a screenshot.": ["截图超时"], + "A valid color scheme is required": ["需要有效的配色方案"], + "APPLY": ["应用"], + "APR": ["四月"], + "AQE": ["AQE(异步执行查询)"], + "AUG": ["八月"], + "About": ["关于"], + "Access": ["访问"], + "Access requests": ["访问请求"], + "Access was requested": ["请求访问"], + "Action": ["操作"], + "Action Log": ["操作日志"], + "Actions": ["操作"], + "Active": ["激活"], + "Actual time range": ["实际时间范围"], + "Adaptive formatting": ["自动匹配格式化"], + "Add": ["新增"], + "Add Alert": ["添加告警"], + "Add Annotation": ["添加注释"], + "Add Annotation Layer": ["添加注释层"], + "Add CSS Template": ["新增CSS模板"], + "Add CSS template": ["新增CSS模板"], + "Add Chart": ["添加图表"], + "Add Column": ["添加列"], + "Add Dashboard": ["添加看板"], + "Add Database": ["添加数据库"], + "Add Druid Cluster": ["添加 Druid 集群"], + "Add Druid Column": ["添加 Druid 列"], + "Add Druid Datasource": ["添加 Druid 数据源"], + "Add Druid Metric": ["添加 Druid 指标"], + "Add Log": ["新增日志"], + "Add Metric": ["添加指标"], + "Add Report": ["添加报告"], + "Add Row level security filter": ["添加行级安全过滤"], + "Add Saved Query": ["添加保存的查询"], + "Add a Plugin": ["添加插件"], + "Add additional custom parameters": ["添加其他自定义参数"], + "Add an item": ["新增一行"], + "Add annotation": ["添加注释"], + "Add annotation layer": ["添加注释层"], + "Add dataset": ["添加数据集"], + "Add delivery method": ["添加通知方法"], + "Add filter": ["增加过滤条件"], + "Add item": ["增加条件"], + "Add metric": ["添加指标"], + "Add new color formatter": ["添加新的颜色"], + "Add new formatter": ["新增格式化"], + "Add notification method": ["添加注释层"], + "Add sheet": ["添加sheet页"], + "Add to dashboard": ["添加到看板"], + "Added": ["已添加"], + "Adding new datasource [{}]": ["添加 Druid 数据源 [{}]"], + "Additional Parameters": ["附加参数"], + "Additional information": ["附加信息"], + "Additional metadata": ["附加元数据"], + "Additional padding for legend.": ["图示附加的padding值。"], + "Additional parameters": ["编辑模板参数"], + "Additional text to add before or after the value, e.g. unit": [ + "附加文本到数据前(后),例如:单位" ], - "Deck.gl - Multiple Layers": ["多图层"], - "Bad spatial key": ["错误的空间字段"], - "Invalid spatial point encountered: %s": ["遇到无效的空间点:%s"], - "Encountered invalid NULL spatial entry, please consider filtering those out": [ - "遇到无效的为 NULL 的空间条目,请考虑将其过滤掉" + "Additive": ["附加"], + "Advanced": ["进阶"], + "Advanced Analytics": ["高级分析"], + "Advanced analytics": ["高级分析"], + "Advanced-Analytics": ["高级分析"], + "Aesthetic": ["炫酷"], + "After": ["之后"], + "Aggregate": ["聚合"], + "Aggregate Mean": ["合计平均值"], + "Aggregate Sum": ["合计"], + "Aggregate function applied to the list of points in each cluster to produce the cluster label.": [ + "聚合函数应用于每个群集中的点列表以产生群集标签。" ], - "Deck.gl - Scatter plot": ["Deck.gl - 散点图"], - "Deck.gl - Screen Grid": ["Deck.gl - 屏幕网格"], - "Deck.gl - 3D Grid": ["Deck.gl - 3D网格"], - "Deck.gl - Paths": ["Deck.gl - 路径"], - "Deck.gl - Polygon": ["Deck.gl - 多角形"], - "Deck.gl - 3D HEX": ["Deck.gl - 3D六角曲面"], - "Deck.gl - GeoJSON": ["Deck.gl - GeoJson"], - "Deck.gl - Arc": ["Deck.gl - 弧度"], - "Event flow": ["事件流"], - "Time Series - Paired t-test": ["时间序列 - 配对t检验"], - "Time Series - Nightingale Rose Chart": ["时间序列 - 南丁格尔玫瑰图"], - "Partition Diagram": ["分区图"], - "Choose either fields to [Group By] and [Metrics] and/or [Percentage Metrics], or [Columns], not both": [ - "为[分组]和[指标]或[列]选择任何的字段,或者两个都不选" + "Aggregate function to apply when pivoting and computing the total rows and columns": [ + "在旋转和计算总的行和列时,应用聚合函数" ], - "Box Plot": ["箱线图"], - "Distribution - NVD3 - Pie Chart": ["分布 - NVD3 - 饼图"], - "iFrame": [""], - "Deleted %(num)d annotation layer": ["选择一个注释图层"], - "All Text": ["所有文本"], - "Deleted %(num)d annotation": ["选择一个注释图层"], - "End date must be after start date": ["起始时间不可以大于当前时间"], - "Short description must be unique for this layer": [ - "此层的简述必须是唯一的" + "Aggregation function": ["聚合功能"], + "Alert Triggered, In Grace Period": ["告警已触发,在宽限期内"], + "Alert condition": ["告警条件"], + "Alert condition schedule": ["告警条件计划"], + "Alert ended grace period.": ["告警已结束宽限期。"], + "Alert failed": ["告警失败"], + "Alert fired during grace period.": ["在宽限期内触发告警。"], + "Alert found an error while executing a query.": [ + "告警在执行查询时发现错误。" ], - "Annotations could not be deleted.": ["无法删除注释。"], - "Annotation not found.": ["注释不存在。"], - "Annotation parameters are invalid.": ["注释层仍在加载。"], - "Annotation could not be created.": ["注释无法创建。"], - "Annotation could not be updated.": ["注释无法更新。"], - "Annotation delete failed.": ["注释与注释层"], - "Annotation layer parameters are invalid.": ["注释层仍在加载。"], - "Annotation layer could not be deleted.": ["注释层仍在加载。"], - "Annotation layer could not be created.": ["您的查询无法保存"], - "Annotation layer could not be updated.": ["您的查询无法保存"], - "Annotation layer not found.": ["注释层仍在加载。"], - "Annotation layer delete failed.": ["注释层仍在加载。"], - "Annotation layer has associated annotations.": ["注释层仍在加载。"], - "Name must be unique": ["名称必须是唯一的"], - "Deleted %(num)d chart": ["删除了 %(num)d 个图表"], - "Request is not JSON": ["请求不是JSON"], - "Request is incorrect: %(error)s": ["请求不正确: %(error)s"], - "`confidence_interval` must be between 0 and 1 (exclusive)": [ - "`置信区间` 必须介于0和1之间(开区间)" + "Alert name": ["告警名称"], + "Alert on grace period": ["告警宽限期"], + "Alert query returned a non-number value.": ["告警查询返回非数字值。"], + "Alert query returned more than one column.": ["告警查询返回多个列。"], + "Alert query returned more than one column. %s columns returned": [ + "告警查询返回多个列。%s 列被返回" ], - "lower percentile must be greater than 0 and less than 100. Must be lower than upper percentile.": [ - "下百分位数必须大于0且小于100。而且必须低于上百分位" + "Alert query returned more than one row.": ["告警查询返回了多行。"], + "Alert query returned more than one row. %s rows returned": [ + "告警查询返回了多行。%s 行被返回" + ], + "Alert running": ["告警运行中"], + "Alert triggered, notification sent": ["告警已触发,通知已发送"], + "Alert validator config error.": ["告警验证器配置错误。"], + "Alerts": ["告警"], + "Alerts & Reports": ["告警和报告"], + "Alerts & reports": ["告警和报告"], + "Align +/-": ["对齐 +/-"], + "All": ["所有"], + "All Text": ["所有文本"], + "All charts": ["所有图表"], + "All filters": ["所有过滤"], + "All filters (%(filterCount)d)": ["所有过滤(%(filterCount)d)"], + "All panels": ["应用于所有面板"], + "All panels with this column will be affected by this filter": [ + "包含此列的所有面板都将受到此过滤条件的影响" ], - "upper percentile must be greater than 0 and less than 100. Must be higher than lower percentile.": [ - "上百分位数必须大于0且小于100。而且必须高于下百分位。" + "Allow CREATE TABLE AS": ["允许 CREATE TABLE AS"], + "Allow CREATE TABLE AS option in SQL Lab": [ + "在 SQL 编辑器中允许 CREATE TABLE AS 选项" ], - "`width` must be greater or equal to 0": ["`宽度` 必须大于或等于0"], - "`row_limit` must be greater than or equal to 1": [ - "`行限制` 必须大于或等于1" + "Allow CREATE VIEW AS": ["允许 CREATE VIEW AS"], + "Allow CREATE VIEW AS option in SQL Lab": [ + "在 SQL 编辑器中允许 CREATE VIEW AS 选项" ], - "`row_offset` must be greater than or equal to 0": [ - "`行偏移量` 必须大于或等于0" + "Allow Csv Upload": ["允许Csv上传"], + "Allow DML": ["允许 DML"], + "Allow Multi Schema Metadata Fetch": ["允许多Schema元数据获取"], + "Allow SQL Lab to fetch a list of all tables and all views across all database schemas. For large data warehouse with thousands of tables, this can be expensive and put strain on the system.": [ + "允许 sql lab 获取所有数据库架构中的所有表和所有视图的列表。对于具有数千个表的大型数据仓库, 这可能会很耗费性能, 并给系统带来压力。" ], - "There are associated alerts or reports: %s,": [ - "存在关联的警报或报告:%s," + "Allow creation of new tables based on queries": ["允许基于查询创建新表"], + "Allow creation of new views based on queries": [ + "允许基于查询创建新视图" ], - "Database does not exist": ["数据库不存在"], - "Dashboards do not exist": ["看板"], - "Datasource type is required when datasource_id is given": [ - "给定数据源id时,需要提供数据源类型" + "Allow data manipulation language": ["允许数据操作语言"], + "Allow data upload": ["允许数据上传"], + "Allow manipulation of the database using non-SELECT statements such as UPDATE, DELETE, CREATE, etc.": [ + "允许使用非SELECT语句(如UPDATE、DELETE、CREATE等)操作数据库。" ], - "Chart parameters are invalid.": ["图表参数无效。"], - "Chart could not be created.": ["您的查询无法保存。"], - "Chart could not be updated.": ["您的查询无法保存。"], - "Chart could not be deleted.": ["这个查询无法被加载。"], - "There are associated alerts or reports": ["存在关联的警报或报告"], - "Changing this chart is forbidden": ["禁止更改此图表"], - "Charts could not be deleted.": ["这个查询无法被加载"], - "Import chart failed for an unknown reason": ["导入图表失败,原因未知"], - "Owners are invalid": ["所有者无效"], - "Dataset does not exist": ["数据集不存在"], - "`operation` property of post processing object undefined": [ - "后处理必须指定操作类型(`operation`)" + "Allow multiple selections": ["允许多选"], + "Allow node selections": ["允许多节点选择"], + "Allow selecting multiple values": ["允许选择多个值"], + "Allow this database to be explored": ["允许浏览此数据库"], + "Allow this database to be queried in SQL Lab": [ + "允许在SQL工具箱中查询此数据库" ], - "Unsupported post processing operation: %(operation)s": [ - "不支持的处理操作:%(operation)s" + "Allow users to run non-SELECT statements (UPDATE, DELETE, CREATE, ...) in SQL Lab": [ + "允许用户在 SQL 编辑器中运行非 SELECT 语句(UPDATE,DELETE,CREATE,...)" ], - "Adding new datasource [{}]": ["添加 Druid 数据源 [{}]"], - "Refreshing datasource [{}]": ["刷新数据源 [{}]"], - "Metric(s) {} must be aggregations.": ["度量(s) {} 必须是聚合。"], - "Unsupported extraction function: ": ["不支持的提取函数:"], - "Columns": ["列"], - "Show Druid Column": ["显示 Druid 列"], - "Add Druid Column": ["添加 Druid 列"], - "Edit Druid Column": ["编辑 Druid 列"], - "Column": ["列"], - "Type": ["类型"], - "Datasource": ["数据源"], - "Groupable": ["可分组"], - "Filterable": ["可过滤"], - "Whether this column is exposed in the `Filters` section of the explore view.": [ - "该列是否在浏览视图的`过滤器`部分显示。" + "Alphabetical": ["按字母顺序排列"], + "Also known as a box and whisker plot, this visualization compares the distributions of a related metric across multiple groups. The box in the middle emphasizes the mean, median, and inner 2 quartiles. The whiskers around each box visualize the min, max, range, and outer 2 quartiles.": [ + "也称为框须图,该可视化比较了一个相关指标在多个组中的分布。中间的框强调平均值、中值和内部2个四分位数。每个框周围的触须可视化了最小值、最大值、范围和外部2个四分区。" ], - "Metrics": ["指标"], - "Show Druid Metric": ["显示 Druid 指标"], - "Add Druid Metric": ["添加 Druid 指标"], - "Edit Druid Metric": ["编辑 Druid 指标"], - "Metric": ["指标"], - "Description": ["描述"], - "Verbose Name": ["全称"], - "JSON": ["JSON"], - "Druid Datasource": ["Druid 数据源"], - "Warning Message": ["告警信息"], - "Show Druid Cluster": ["显示 Druid 集群"], - "Add Druid Cluster": ["添加 Druid 集群"], - "Edit Druid Cluster": ["编辑 Druid 集群"], - "Cluster Name": ["群集名称"], - "Broker Host": ["Broker的地址"], - "Broker Port": ["Broker的端口"], - "Broker Username": ["Broker的用户名"], - "Broker Password": ["Broker的密码"], - "Broker Endpoint": ["Broker的Endpoint"], - "Cache Timeout": ["缓存超时"], - "Metadata Last Refreshed": ["上次刷新的元数据"], - "Duration (in seconds) of the caching timeout for this cluster. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.": [ - "此集群的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为全局超时。" + "Altered": ["已更改"], + "An enclosed time range (both start and end) must be specified when using a Time Comparison.": [ + "使用时间比较时,必须指定封闭的时间范围(有开始和结束)。" ], - "Druid supports basic authentication. See [auth](http://druid.io/docs/latest/design/auth.html) and druid-basic-security extension": [ - "Druid支持基本的身份验证。可以参考 [auth](http://druid.io/docs/latest/design/auth.html) 和 druid-basic-security 部分" + "An engine must be specified when passing individual parameters to a database.": [ + "向数据库传递单个参数时必须指定引擎。" ], - "Show Druid Datasource": ["显示 Druid 数据源"], - "Add Druid Datasource": ["添加 Druid 数据源"], - "Edit Druid Datasource": ["编辑 Druid 数据源"], - "The list of charts associated with this table. By altering this datasource, you may change how these associated charts behave. Also note that charts need to point to a datasource, so this form will fail at saving if removing charts from a datasource. If you want to change the datasource for a chart, overwrite the chart from the 'explore view'": [ - "与此表关联的图表列表。通过更改此数据源,您可以更改这些相关图表的行为。还要注意,图表需要指向数据源,如果从数据源中删除图表,则此窗体将无法保存。如果要为图表更改数据源,请从“浏览视图”更改该图表。" + "An error has occurred": ["发生了一个错误"], + "An error occurred": ["发生了一个错误"], + "An error occurred saving dataset": ["保存数据集时发生错误"], + "An error occurred when refreshing queries": ["创建数据源时发生错误"], + "An error occurred while accessing the value.": ["访问值时出错。"], + "An error occurred while collapsing the table schema. Please contact your administrator.": [ + "收起表结构时出错。请与管理员联系。" ], - "Timezone offset (in hours) for this datasource": [ - "数据源的时差(单位:小时)" + "An error occurred while creating %ss: %s": ["创建时出错:%ss: %s"], + "An error occurred while creating the data source": [ + "创建数据源时发生错误" ], - "Time expression to use as a predicate when retrieving distinct values to populate the filter component. Only applies when `Enable Filter Select` is on. If you enter `7 days ago`, the distinct list of values in the filter will be populated based on the distinct value over the past week": [ - "当检索不同的值以填充过滤器组件时,时间表达式用作条件。只适用于`启用过滤器选择`。如果您输入`7天前`,将根据过去一周的不同值来填充ilter中不同的值列表" + "An error occurred while creating the value.": ["创建值时出错。"], + "An error occurred while deleting the value.": ["删除值时出错。"], + "An error occurred while editing this report.": ["编辑此报告时出错。"], + "An error occurred while editing this report: %s": [ + "编辑此报告时出错:%s" ], - "Whether to populate the filter's dropdown in the explore view's filter section with a list of distinct values fetched from the backend on the fly": [ - "是否在浏览视图的过滤器部分中填充过滤器的下拉列表,并提供从后端获取的不同值的列表" + "An error occurred while expanding the table schema. Please contact your administrator.": [ + "展开表结构时出错。请与管理员联系。" ], - "Redirects to this endpoint when clicking on the datasource from the datasource list": [ - "在数据源列表中点击数据源将重定向到此端点" + "An error occurred while fetching %s info: %s": [ + "获取%s仪表板时出错:%s" ], - "Duration (in seconds) of the caching timeout for this datasource. A timeout of 0 indicates that the cache never expires. Note this defaults to the cluster timeout if undefined.": [ - "此数据源的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为集群超时。" + "An error occurred while fetching %ss: %s": ["抓取出错:%ss: %s"], + "An error occurred while fetching available CSS templates": [ + "获取可用的CSS模板时出错" ], - "Associated Charts": ["关联的图表"], - "Data Source": ["数据源"], - "Cluster": ["集群"], - "Owners": ["所有者"], - "Is Hidden": ["隐藏"], - "Enable Filter Select": ["启用过滤器选择"], - "Default Endpoint": ["默认端点"], - "Time Offset": ["时间偏移"], - "Datasource Name": ["数据库名称"], - "Fetch Values From": ["取值谓词"], - "Changed By": ["修改人"], - "Modified": ["已修改"], - "Refreshed metadata from cluster [{}]": ["从群集刷新元数据 [{}]"], - "Only `SELECT` statements are allowed": ["将 SELECT 语句复制到剪贴板"], - "Only single queries supported": ["仅支持单个查询"], - "Error in jinja expression in fetch values predicate: %(msg)s": [ - "获取jinja表达式中的谓词的值出错:%(msg)s" + "An error occurred while fetching chart created by values: %s": [ + "获取图表的创建人时出错:%s" ], - "Error in jinja expression in FROM clause: %(msg)s": [ - "jinja表达式中的FROM子句出错:%(msg)s" + "An error occurred while fetching chart owners values: %s": [ + "获取图表所有者时出错 %s" ], - "Virtual dataset query cannot consist of multiple statements": [ - "虚拟数据集查询不能由多个语句组成" + "An error occurred while fetching created by values: %s": [ + "获取创建人时出错:%s" ], - "Virtual dataset query must be read-only": ["虚拟数据集查询必须是只读的"], - "Error in jinja expression in RLS filters: %(msg)s": [ - "jinja表达式中的 RLS filters 出错:%(msg)s" + "An error occurred while fetching dashboard created by values: %s": [ + "获取仪表板创建者时出错:%s" ], - "Datetime column not provided as part table configuration and is required by this type of chart": [ - "没有提供该表配置的日期时间列,它是此类型图表所必需的" + "An error occurred while fetching dashboard owner values: %s": [ + "获取仪表板所有者时出错:%s" ], - "Empty query?": ["查询为空?"], - "Metric '%(metric)s' does not exist": ["指标 '%(metric)s' 不存在"], - "Invalid filter operation type: %(op)s": ["选择框的操作类型无效: %(op)s"], - "Error in jinja expression in WHERE clause: %(msg)s": [ - "jinja表达式中的WHERE子句出错:%(msg)s" + "An error occurred while fetching dashboards": ["获取看板时出错"], + "An error occurred while fetching dashboards: %s": [ + "获取仪表板时出错:%s" ], - "Error in jinja expression in HAVING clause: %(msg)s": [ - "jinja表达式中的HAVING子句出错:%(msg)s" + "An error occurred while fetching database related data: %s": [ + "获取数据库相关数据时出错:%s" ], - "Show Column": ["显示列"], - "Add Column": ["添加列"], - "Edit Column": ["编辑列"], - "Whether to make this column available as a [Time Granularity] option, column has to be DATETIME or DATETIME-like": [ - "是否将此列作为[时间粒度]选项, 列中的数据类型必须是DATETIME" + "An error occurred while fetching database values: %s": [ + "获取数据库信息时出错:%s" ], - "The data type that was inferred by the database. It may be necessary to input a type manually for expression-defined columns in some cases. In most case users should not need to alter this.": [ - "由数据库推断的数据类型。在某些情况下,可能需要为表达式定义的列手工输入一个类型。在大多数情况下,用户不需要修改这个数据类型。" + "An error occurred while fetching dataset datasource values: %s": [ + "获取数据集数据源信息时出错: %s" ], - "Table": ["表"], - "Expression": ["表达式"], - "Is temporal": ["时间条件"], - "Datetime Format": ["时间格式"], - "Invalid date/timestamp format": ["无效的日期/时间戳格式"], - "Show Metric": ["显示指标"], - "Add Metric": ["添加指标"], - "Edit Metric": ["编辑指标"], - "SQL Expression": ["SQL表达式"], - "D3 Format": ["D3 格式"], - "Extra": ["扩展"], - "Row level security filter": ["行级安全过滤"], - "Show Row level security filter": ["显示行级安全过滤"], - "Add Row level security filter": ["添加行级安全过滤"], - "Edit Row level security filter": ["编辑行级安全过滤"], - "Regular filters add where clauses to queries if a user belongs to a role referenced in the filter. Base filters apply filters to all queries except the roles defined in the filter, and can be used to define what users can see if no RLS filters within a filter group apply to them.": [ - "常规过滤将where子句添加到查询中,以确定用户是否属于过滤中引用的角色。基本过滤将应用于除过滤中定义的角色之外的所有查询,并且可以用于定义在没有应用RLS过滤组的情况下,哪些用户可以看到内容。" + "An error occurred while fetching dataset owner values: %s": [ + "获取数据集所有者值时出错:%s" ], - "These are the tables this filter will be applied to.": [ - "这些是将应用此过滤的表。" + "An error occurred while fetching dataset related data": [ + "获取数据集相关数据时出错" ], - "For regular filters, these are the roles this filter will be applied to. For base filters, these are the roles that the filter DOES NOT apply to, e.g. Admin if admin should see all data.": [ - "对于常规过滤,这些是此过滤将应用于的角色。对于基本过滤,这些是过滤不适用的角色,例如Admin代表admin应该查看所有数据。" + "An error occurred while fetching dataset related data: %s": [ + "获取数据集相关数据时出错:%s" ], - "Filters with the same group key will be ORed together within the group, while different filter groups will be ANDed together. Undefined group keys are treated as unique groups, i.e. are not grouped together. For example, if a table has three filters, of which two are for departments Finance and Marketing (group key = 'department'), and one refers to the region Europe (group key = 'region'), the filter clause would apply the filter (department = 'Finance' OR department = 'Marketing') AND (region = 'Europe').": [ - "具有相同组key的过滤将在组中一起进行\"OR\"运算,而不同的过滤组将一起进行\"AND\"运算。未定义的组的key被视为唯一组,即不分组在一起。例如,如果表有三个过滤,其中两个用于财务部门和市场营销 (group key = 'department'),其中一个表示欧洲地区(group key = 'region'),filter子句将应用过滤 (department = 'Finance' OR department = 'Marketing') 和 (region = 'Europe')" + "An error occurred while fetching datasets: %s": ["获取数据集时出错:%s"], + "An error occurred while fetching function names.": [ + "获取函数名称时出错。" ], - "This is the condition that will be added to the WHERE clause. For example, to only return rows for a particular client, you might define a regular filter with the clause `client_id = 9`. To display no rows unless a user belongs to a RLS filter role, a base filter can be created with the clause `1 = 0` (always false).": [ - "这是将会添加到WHERE子句的条件。例如,要仅返回特定客户端的行,可以使用子句 `client_id = 9` 定义常规过滤。若要在用户不属于RLS过滤角色的情况下不显示行,可以使用子句 `1 = 0`(始终为false)创建基本过滤。" + "An error occurred while fetching schema values: %s": [ + "获取结构信息时出错:%s" ], - "Tables": ["数据表"], - "Roles": ["角色"], - "Clause": ["从句"], - "Creator": ["作者"], - "Show Table": ["显示表"], - "Import a table definition": ["导入一个已定义的表"], - "Edit Table": ["编辑表"], - "Name of the table that exists in the source database": [ - "源数据库中存在的表的名称" + "An error occurred while fetching tab state": ["获取tab页状态时出错"], + "An error occurred while fetching table metadata": [ + "获取表格元数据时发生错误" ], - "Schema, as used only in some databases like Postgres, Redshift and DB2": [ - "模式,只在一些数据库中使用,比如Postgres、Redshift和DB2" + "An error occurred while fetching table metadata. Please contact your administrator.": [ + "获取表格元数据时发生错误。请与管理员联系。" ], - "This fields acts a Superset view, meaning that Superset will run a query against this string as a subquery.": [ - "这个字段执行Superset视图时,意味着Superset将以子查询的形式对字符串运行查询。" + "An error occurred while fetching user values: %s": [ + "获取用户信息出错:%s" ], - "Predicate applied when fetching distinct value to populate the filter control component. Supports jinja template syntax. Applies only when `Enable Filter Select` is on.": [ - "当获取不同的值来填充过滤器组件应用时。支持jinja的模板语法。只在`启用过滤器选择`时应用。" + "An error occurred while hiding the left bar. Please contact your administrator.": [ + "隐藏左栏时出错。请与管理员联系。" ], - "Redirects to this endpoint when clicking on the table from the table list": [ - "点击表列表中的表时将重定向到此端点" + "An error occurred while importing %s: %s": ["导入时出错 %s: %s"], + "An error occurred while loading the SQL": ["创建数据源时发生错误"], + "An error occurred while pruning logs ": ["精简日志时出错 "], + "An error occurred while removing query. Please contact your administrator.": [ + "删除查询时出错。请与管理员联系。" ], - "Whether the table was generated by the 'Visualize' flow in SQL Lab": [ - "表是否由 sql 实验室中的 \"可视化\" 流生成" + "An error occurred while removing tab. Please contact your administrator.": [ + "删除tab页时出错。请与管理员联系。" ], - "A set of parameters that become available in the query using Jinja templating syntax": [ - "在查询中可用的一组参数使用JINJA模板语法" + "An error occurred while removing the table schema. Please contact your administrator.": [ + "删除表结构时出错。请与管理员联系。" ], - "Duration (in seconds) of the caching timeout for this table. A timeout of 0 indicates that the cache never expires. Note this defaults to the database timeout if undefined.": [ - "此表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为数据库的超时。" + "An error occurred while rendering the visualization: %s": [ + "渲染可视化时发生错误:%s" ], - "Database": ["数据库"], - "Last Changed": ["更新时间"], - "Schema": ["模式"], - "Offset": ["偏移"], - "Table Name": ["表名"], - "Fetch Values Predicate": ["取值谓词"], - "Main Datetime Column": ["主日期列"], - "SQL Lab View": ["SQL Lab 视图"], - "Template parameters": ["模板参数"], - "The table was created. As part of this two-phase configuration process, you should now click the edit button by the new table to configure it.": [ - "表被创建。作为这两个阶段配置过程的一部分,您现在应该单击新表的编辑按钮来配置它。" + "An error occurred while setting the active tab. Please contact your administrator.": [ + "设置活动tab页时出错。请与管理员联系。" ], - "Refresh Metadata": ["刷新元数据"], - "Refresh column metadata": ["刷新字段元数据"], - "Metadata refreshed for the following table(s): %(tables)s": [ - "为下表刷新元数据:%(tables)s" + "An error occurred while setting the tab autorun. Please contact your administrator.": [ + "设置tab页自动运行时出错。请与管理员联系。" ], - "The following tables added new columns: %(tables)s": [ - "下表添加了新列:%(tables)s" + "An error occurred while setting the tab database ID. Please contact your administrator.": [ + "设置tab页数据库ID时出错。请与管理员联系。" ], - "The following tables removed columns: %(tables)s": [ - "下表删除了列:%(tables)s" + "An error occurred while setting the tab schema. Please contact your administrator.": [ + "设置tab页结构时出错。请与管理员联系。" ], - "The following tables update column metadata: %(tables)s": [ - "下表更新列元数据:%(tables)s" + "An error occurred while setting the tab template parameters. Please contact your administrator.": [ + "设置tab页模板参数时出错。请与管理员联系。" ], - "Unable to refresh metadata for the following table(s): %(tables)s": [ - "为下表刷新元数据: %(tables)s" + "An error occurred while setting the tab title. Please contact your administrator.": [ + "设置tab页标题时出错。请与管理员联系。" ], - "Deleted %(num)d css template": ["删除了 %(num)d 个css模板"], - "CSS template could not be deleted.": ["CSS模板不能被删除"], - "CSS template not found.": ["CSS模板未找到"], - "Deleted %(num)d dashboard": ["删除了 %(num)d 个看板"], - "Title or Slug": ["标题或者Slug"], - "Must be unique": ["需要唯一"], - "Dashboard parameters are invalid.": ["看板参数无效。"], - "Dashboard not found.": ["看板没有找到"], - "Dashboard could not be created.": ["看板无法被创建"], - "Dashboards could not be deleted.": ["看板无法被删除。"], - "Dashboard could not be updated.": ["看板无法更新。"], - "Dashboard could not be deleted.": ["看板无法被删除。"], - "Changing this Dashboard is forbidden": ["无法修改该看板"], - "Import dashboard failed for an unknown reason": [ - "因为未知原因导入看板失败" + "An error occurred while starring this chart": ["以此字符开头时出错"], + "An error occurred while storing the latest query id in the backend. Please contact your administrator if this problem persists.": [ + "在后端存储最新查询id时出错。如果此问题仍然存在,请与管理员联系。" ], - "No data in file": ["文件中无数据"], - "Table name undefined": ["表名未定义"], - "Invalid connection string, a valid string usually follows: driver://user:password@database-host/database-name": [ - "连接字符串无效,有效字符串通常如下:driver://user:password@database-host/database-name" + "An error occurred while storing your query in the backend. To avoid losing your changes, please save your query using the \"Save Query\" button.": [ + "在后端存储查询时出错。为避免丢失更改,请使用 \"保存查询\" 按钮保存查询。" ], - "SQLite database cannot be used as a data source for security reasons.": [ - "出于安全原因,SQLite数据库不能用作数据源。" + "An error occurred while updating the value.": ["更新值时出错。"], + "An unknown error occurred. Please contact your Superset administrator": [ + "发生未知错误。请与管理员联系" ], - "Field cannot be decoded by JSON. %(msg)s": [ - "字段不能由JSON解码。%(msg)s" + "Anchor to": ["锚定到"], + "Angle at which to end progress axis": ["进度轴结束的角度"], + "Angle at which to start progress axis": ["开始进度轴的角度"], + "Animation": ["动画"], + "Annotation": ["注释"], + "Annotation Layer ${annotationLayerName}": [ + "注释层 ${annotationLayerName}" ], - "The metadata_params in Extra field is not configured correctly. The key %(key)s is invalid.": [ - "额外字段中的元数据参数配置不正确。键 %(key)s 无效。" + "Annotation Layers": ["注释层"], + "Annotation Slice Configuration": ["注释切片配置"], + "Annotation Source": ["注释来源"], + "Annotation could not be created.": ["注释无法创建。"], + "Annotation could not be updated.": ["注释无法更新。"], + "Annotation delete failed.": ["注释与注释层"], + "Annotation end time must be no earlier than start time.": [ + "注释的结束时间不能早于开始时间。" ], - "Database parameters are invalid.": ["数据库参数无效"], - "A database with the same name already exists": ["同名数据库已存在"], - "Field is required": ["字段是必需的"], - "Field cannot be decoded by JSON. %{json_error}s": [ - "字段不能由JSON解码。%{json_error}s" + "Annotation layer": ["注释层"], + "Annotation layer could not be created.": ["您的查询无法保存"], + "Annotation layer could not be deleted.": ["注释层仍在加载。"], + "Annotation layer could not be updated.": ["您的查询无法保存"], + "Annotation layer delete failed.": ["注释层仍在加载。"], + "Annotation layer description columns": ["注释层描述列。"], + "Annotation layer has associated annotations.": ["注释层仍在加载。"], + "Annotation layer interval end": ["注释层间隔结束"], + "Annotation layer name": ["注释层名称"], + "Annotation layer not found.": ["注释层仍在加载。"], + "Annotation layer opacity": ["注释层不透明度"], + "Annotation layer parameters are invalid.": ["注释层仍在加载。"], + "Annotation layer stroke": ["注释层混乱"], + "Annotation layer time column": ["注释层时间列"], + "Annotation layer title column": ["注释层标题列"], + "Annotation layer type": ["注释层类型"], + "Annotation layer value": ["注释层值"], + "Annotation layers": ["注解层"], + "Annotation layers are still loading.": ["注释层仍在加载。"], + "Annotation name": ["注释名称"], + "Annotation not found.": ["注释不存在。"], + "Annotation parameters are invalid.": ["注释层仍在加载。"], + "Annotation source type": ["注释数据源类型"], + "Annotations": ["注释"], + "Annotations and Layers": ["注释与注释层"], + "Annotations and layers": ["注释与注释层"], + "Annotations could not be deleted.": ["无法删除注释。"], + "Any": ["所有"], + "Any additional detail to show in the certification tooltip.": [ + "要在认证工具提示中显示详细信息。" ], - "The metadata_params in Extra field is not configured correctly. The key %{key}s is invalid.": [ - "额外字段中的元数据参数配置不正确。键 %{key}s 无效。" + "Any color palette selected here will override the colors applied to this dashboard's individual charts": [ + "此处选择的任何调色板都将覆盖应用于此看板的各个图表的颜色" ], - "Database not found.": ["数据库没有找到"], - "Database could not be created.": ["数据库无法被创建"], - "Database could not be updated.": ["数据库无法更新"], - "Connection failed, please check your connection settings": [ - "连接失败,请检查您的连接配置" + "Any databases that allow connections via SQL Alchemy URIs can be added. ": [ + "可以添加任何允许通过SQL AlChemy URI进行连接的数据库。" ], - "Cannot delete a database that has tables attached": [ - "无法删除已含有表的数据库" + "Any databases that allow connections via SQL Alchemy URIs can be added. Learn about how to connect a database driver ": [ + "可以添加任何允许通过SQL AlChemy URI进行连接的数据库。了解如何连接数据库驱动程序" ], - "Database could not be deleted.": ["数据库不能删除。"], - "Stopped an unsafe database connection": ["已停止不安全的数据库连接"], - "Could not load database driver": ["无法加载数据库驱动程序"], - "Unexpected error occurred, please check your logs for details": [ - "发生意外错误,请检查日志以了解详细信息" + "Append": ["追加"], + "Applied Cross Filters (%d)": ["应用的交叉条件 (%d)"], + "Applied Filters (%d)": ["应用的条件 (%d)"], + "Applied rolling window did not return any data. Please make sure the source query satisfies the minimum periods defined in the rolling window.": [ + "应用的滚动窗口(rolling window)未返回任何数据。请确保源查询满足滚动窗口中定义的最小周期。" ], - "Import database failed for an unknown reason": [ - "导入数据库失败,原因未知" + "Apply": ["应用"], + "Apply conditional color formatting to metrics": [ + "将条件颜色格式应用于指标" ], - "Could not load database driver: {}": ["无法加载数据库驱动程序:{}"], - "Deleted %(num)d dataset": ["已经删除 %(num)d 个数据集"], - "Null or Empty": ["Null或空"], - "Database not allowed to change": ["数据集不允许被修改"], - "One or more columns do not exist": ["一个或多个字段不存在"], - "One or more columns are duplicated": ["一个或多个列被复制"], - "One or more columns already exist": ["一个或多个列已存在"], - "One or more metrics do not exist": ["一个或多个指标不存在"], - "One or more metrics are duplicated": ["一个或多个指标重复"], - "One or more metrics already exist": ["一个或多个度量已存在"], - "Table [%(table_name)s] could not be found, please double check your database connection, schema, and table name": [ - "找不到 [%(table_name)s] 表,请仔细检查您的数据库连接、Schema 和 表名" + "Apply conditional color formatting to numeric columns": [ + "将条件颜色格式应用于数字列" ], - "Dataset parameters are invalid.": ["数据集参数无效。"], - "Dataset could not be created.": ["无法创建数据集。"], - "Dataset could not be updated.": ["无法更新数据集。"], - "Dataset could not be deleted.": ["无法删除数据集"], - "Dataset(s) could not be bulk deleted.": ["数据集无法批量删除"], - "Changing this dataset is forbidden": ["没有权限更新此数据集"], - "Import dataset failed for an unknown reason": [ - "因为未知的原因导入数据集失败" + "Apply metrics on": ["应用指标到"], + "Apply to all panels": ["应用于所有面板"], + "Apply to specific panels": ["应用于特定面板"], + "April": ["四月"], + "Are you sure you want to cancel?": ["您确定要取消吗?"], + "Are you sure you want to delete": ["确定要删除吗"], + "Are you sure you want to delete ${annotationCurrentlyDeleting?.short_descr}?": [ + "请确认您想删除 ${annotationCurrentlyDeleting?.short_descr}?" ], - "Unknown Presto Error": ["未知 Presto 错误"], - "We can't seem to resolve the column \"%(column_name)s\" at line %(location)s.": [ - "我们似乎无法解析行 %(location)s 所处的列 \"%(column_name)s\" 。" + "Are you sure you want to delete the selected %s?": [ + "确实要删除选定的 %s 吗?" ], - "The table \"%(table_name)s\" does not exist. A valid table must be used to run this query.": [ - "表 \"%(table_name)s\" 不存在。必须使用有效的表来运行此查询。" + "Are you sure you want to delete the selected annotations?": [ + "确实要删除选定的注释吗?" ], - "Deleted %(num)d saved query": ["已经删除 %(num)d 个保存的查询"], - "Saved queries could not be deleted.": ["保存的查询无法被删除"], - "Saved query not found.": ["保存的查询未找到"], - "Deleted %(num)d report schedule": ["已经删除了 %(num)d 个报告时间表"], - "Alert query returned more than one row. %s rows returned": [ - "警报查询返回了多行。%s 行被返回" + "Are you sure you want to delete the selected charts?": [ + "确实要删除所选图表吗?" ], - "Alert query returned more than one column. %s columns returned": [ - "警报查询返回多个列。%s 列被返回" + "Are you sure you want to delete the selected dashboards?": [ + "确实要删除选定的仪表板吗?" ], - "Dashboard does not exist": ["看板不存在"], - "Chart does not exist": ["图表没有找到"], - "Database is required for alerts": ["警报需要数据库"], - "Type is required": ["类型是必需的"], - "Choose a chart or dashboard not both": [ - "选择图表或看板,不能都全部选择" + "Are you sure you want to delete the selected datasets?": [ + "确实要删除选定的数据集吗?" ], - "Report Schedule parameters are invalid.": ["报表计划参数无效。"], - "Report Schedule could not be deleted.": ["无法删除报表计划。"], - "Report Schedule could not be created.": ["无法创建报表计划。"], - "Report Schedule could not be updated.": ["无法更新报表计划。"], - "Report Schedule not found.": ["找不到报表计划。"], - "Report Schedule delete failed.": ["报表计划删除失败。"], - "Report Schedule log prune failed.": ["报表计划日志精简失败。"], - "Report Schedule execution failed when generating a screenshot.": [ - "生成屏幕截图时报表计划执行失败。" + "Are you sure you want to delete the selected layers?": [ + "确实要删除选定的图层吗?" ], - "Report Schedule execution got an unexpected error.": [ - "报表计划执行遇到意外错误。" + "Are you sure you want to delete the selected queries?": [ + "您确实要删除选定的查询吗?" ], - "Report Schedule is still working, refusing to re-compute.": [ - "报表计划仍在运行,拒绝重新计算。" + "Are you sure you want to delete the selected templates?": [ + "确实要删除选定的模板吗?" ], - "Report Schedule reached a working timeout.": ["报表计划已超时。"], - "Alert query returned more than one row.": ["警报查询返回了多行。"], - "Alert validator config error.": ["错误的经纬度配置。"], - "Alert query returned more than one column.": ["警报查询返回多个列。"], - "Alert query returned a non-number value.": ["警报查询返回非数字值。"], - "Alert found an error while executing a query.": [ - "警报在执行查询时发现错误。" + "Are you sure you want to proceed?": ["您确定要继续执行吗?"], + "Are you sure you want to save and apply changes?": [ + "确实要保存并应用更改吗?" ], - "Alert fired during grace period.": ["在宽限期内触发警报。"], - "Alert ended grace period.": ["警报已结束宽限期。"], - "Alert on grace period": ["警报宽限期"], - "Report Schedule sellenium user not found": [ - "找不到报表计划sellenium用户" + "Area Chart": ["面积图"], + "Area chart": ["面积图"], + "Area chart opacity": ["面积图不透明度"], + "Arrow": ["箭头"], + "Associated Charts": ["关联的图表"], + "Async Execution": ["异步执行查询"], + "Asynchronous query execution": ["异步执行查询"], + "August": ["八月"], + "Autocomplete": ["自动补全"], + "Autocomplete filters": ["自适配过滤条件"], + "Autocomplete query predicate": ["自动补全查询谓词"], + "Available sorting modes:": ["可用分类模式:"], + "Axis": ["坐标轴"], + "Axis ascending": ["轴线升序"], + "Axis descending": ["轴线降序"], + "Back": ["返回"], + "Backend": ["后端"], + "Bad spatial key": ["错误的空间字段"], + "Bar": ["条形图"], + "Bar Chart": ["条形图"], + "Bar Values": ["条形栏的值"], + "Base layer map style": ["地图基本层样式"], + "Based on a metric": ["基于指标"], + "Based on granularity, number of time periods to compare against": [ + "根据粒度、要比较的时间阶段" ], - "Report Schedule state not found": ["未找到报表计划状态"], - "Report schedule unexpected error": ["报告计划意外错误。"], - "Changing this report is forbidden": ["禁止更改此报告"], - "An error occurred while pruning logs ": ["精简日志时出错 "], - "\n <b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>\n <img src=\"cid:%(msgid)s\">\n ": [ - "\n <b><a href=\"%(url)s\">探索 Superset</a></b><p></p>\n <img src=\"cid:%(msgid)s\">\n " - ], - "%(prefix)s %(title)s": [""], - "\n *%(name)s*\n\n <%(url)s|Explore in Superset>\n ": [ - "\n *%(name)s*\n\n <%(url)s|探索 Superset>\n " + "Basic": ["基础"], + "Basic information": ["基本情况"], + "Batch editing %d filters:": ["批量编辑 %d 个过滤条件:"], + "Battery level over time": ["电池电量随时间变化"], + "Be careful.": ["小心。"], + "Before": ["之前"], + "Big Number": ["数字"], + "Big Number Font Size": ["数字的字体大小"], + "Big Number with Trendline": ["数字和趋势线"], + "Bottom": ["底端"], + "Bottom Margin": ["底部边距"], + "Bottom margin, in pixels, allowing for more room for axis labels": [ + "底部边距,以像素为单位,为轴标签留出更多空间" ], - "\n *%(name)s*\n\n <%(url)s|Explore in Superset>\n ": [ - "\n *%(name)s*\n\n <%(url)s|探索 Superset>\n " + "Bottom to Top": ["自下而上"], + "Bounds for the Y-axis. When left empty, the bounds are dynamically defined based on the min/max of the data. Note that this feature will only expand the axis range. It won't narrow the data's extent.": [ + "Y轴的边界。当空时,边界是根据数据的最小/最大值动态定义的。请注意,此功能只会扩展轴范围。它不会缩小数据范围。" ], - "<b><a href=\"%(url)s\">Explore in Superset</a></b><p></p>": [ - "<b><a href=\"%(url)s\">探索 Superset</a></b><p></p>" + "Box Plot": ["箱线图"], + "Breakdowns": ["分解"], + "Broker Endpoint": ["Broker的Endpoint"], + "Broker Host": ["Broker的地址"], + "Broker Password": ["Broker的密码"], + "Broker Port": ["Broker的端口"], + "Broker Username": ["Broker的用户名"], + "Bubble Chart": ["气泡图"], + "Bubble Color": ["气泡颜色"], + "Bubble Size": ["气泡大小"], + "Bubble size": ["气泡尺寸"], + "Bulk select": ["批量选择"], + "Bullet Chart": ["子弹图"], + "Business": ["商业"], + "By default, each filter loads at most 1000 choices at the initial page load. Check this box if you have more than 1000 filter values and want to enable dynamically searching that loads filter values as users type (may add stress to your database).": [ + "默认情况下,每个过滤器在初始页面加载时最多加载1000个选项。如果您有超过1000个过滤值,并且希望启用动态搜索,以便在键入时加载筛选值(可能会给数据库增加压力),请选中此框。" ], - "%(name)s.csv": [""], - "\n *%(slice_name)s*\n\n <%(slice_url_user_friendly)s|Explore in Superset>\n ": [ - "\n *%(slice_name)s*\n\n <%(slice_url_user_friendly)s|探索 Superset>\n " + "By key: use column names as sorting key": ["使用列名作为排序关键字"], + "By key: use row names as sorting key": ["使用行名作为排序关键字"], + "By value: use metric values as sorting key": [ + "使用度量值作为排序关键字" ], - "[Alert] %(label)s": ["[警报] %(label)s"], - "New": ["新增"], - "SQL Query": ["SQL查询"], - "Chart": ["图表"], - "Dashboard": ["看板"], - "Profile": ["用户信息"], - "Info": ["信息"], - "Logout": ["退出"], - "Login": ["登录"], - "Record Count": ["记录数"], - "No records found": ["没有找到任何记录"], - "Filter List": ["过滤"], - "Search": ["搜索"], - "Refresh": ["刷新间隔"], - "Import dashboards": ["导入看板"], - "Import Dashboard(s)": ["导入看板"], - "File": ["文件"], - "Choose File": ["选择文件"], - "Upload": ["上传"], - "No Access!": ["不能访问!"], - "You do not have permissions to access the datasource(s): %(name)s.": [ - "您没有权限访问该数据源: %(name)s。" + "CANCEL": ["取消"], + "CREATE TABLE AS": ["允许 CREATE TABLE AS"], + "CREATE VIEW AS": ["允许 CREATE VIEW AS"], + "CREATE VIEW statement": ["CREATE VIEW 语句"], + "CRON expression": ["CRON表达式"], + "CSS": ["CSS"], + "CSS Templates": ["CSS 模板"], + "CSS template": ["CSS 模板"], + "CSS template could not be deleted.": ["CSS模板不能被删除"], + "CSS template name": ["CSS模板名称"], + "CSS template not found.": ["CSS模板未找到"], + "CSS templates": ["CSS 模板"], + "CSV File": ["CSV文件"], + "CSV file \"%(csv_filename)s\" uploaded to table \"%(table_name)s\" in database \"%(db_name)s\"": [ + "csv 文件 \"%(csv_filename)s\" 上传到数据库 \"%(db_name)s\" 中的表 \"%(table_name)s\"" ], - "Request Permissions": ["请求权限"], - "Cancel": ["取消"], - "Use the edit buttom to change this field": ["使用编辑按钮更改此字段"], - "Test Connection": ["测试连接"], - "[Superset] Access to the datasource %(name)s was granted": [ - "[Superset] 允许访问数据源 %(name)s" + "CSV to Database configuration": ["csv 到数据库配置"], + "CSV upload": ["CSV上传"], + "CTAS & CVAS SCHEMA": ["CTAS和CVAS方案"], + "CTAS (create table as select) can only be run with a query where the last statement is a SELECT. Please make sure your query has a SELECT as its last statement. Then, try running your query again.": [ + "CTA(create table as select)只能与最后一条语句为SELECT的查询一起运行。请确保查询的最后一个语句是SELECT。然后再次尝试运行查询。" ], - "Unable to find such a holiday: [{}]": ["找不到这样的假期:[{}]"], - "Referenced columns not available in DataFrame.": [ - "引用的列在数据帧(DataFrame)中不可用。" + "CTAS Schema": ["CTAS 模式"], + "CVAS (create view as select) can only be run with a query with a single SELECT statement. Please make sure your query has only a SELECT statement. Then, try running your query again.": [ + "CVAS(createview as select)只能与带有单个SELECT语句的查询一起运行。请确保您的查询只有SELECT语句。然后再次尝试运行查询。" ], - "Column referenced by aggregate is undefined: %(column)s": [ - "聚合引用的列未定义:%(column)s" + "CVAS (create view as select) query has more than one statement.": [ + "CVAS (create view as select)查询有多条语句。" ], - "Operator undefined for aggregator: %(name)s": [ - "未定义聚合器的运算符:%(name)s" + "CVAS (create view as select) query is not a SELECT statement.": [ + "CVAS (create view as select)查询不是SELECT语句。" ], - "Invalid numpy function: %(operator)s": ["无效的numpy函数:%(operator)s"], - "Pivot operation requires at least one index": [ - "透视操作至少需要一个索引" + "Cache Timeout": ["缓存超时"], + "Cache Timeout (seconds)": ["缓存超时(秒)"], + "Cache timeout": ["缓存时间"], + "Cached %s": ["缓存于%s"], + "Cached value not found": ["缓存的值未找到"], + "Calculate contribution per series or total": [ + "计算每个系列或总计的贡献" ], - "Pivot operation must include at least one aggregate": [ - "数据透视操作必须至少包含一个聚合" + "Calculated column [%s] requires an expression": [ + "计算列 [%s] 需要一个表达式" ], - "Undefined window for rolling operation": ["未定义滚动操作窗口"], - "Invalid rolling_type: %(type)s": ["无效的滚动类型:%(type)s"], - "Invalid options for %(rolling_type)s: %(options)s": [ - "%(rolling_type)s 的选项无效:%(options)s" + "Calculated columns": ["计算列"], + "Calculation type": ["计算类型"], + "Calendar Heatmap": ["时间热力图"], + "Can not move top level tab into nested tabs": [ + "无法将顶级tab页移动到嵌套tab页中" ], - "Invalid cumulative operator: %(operator)s": [ - "累积运算符无效:%(operator)s" + "Can't find DruidCluster with cluster_name = '%(name)s'": [ + "不能找到具有 cluster_name = '%(name)s' 的 Druid 集群" ], - "Invalid geohash string": ["无效的geohash字符串"], - "Invalid longitude/latitude": ["无效的经度/纬度"], - "Invalid geodetic string": ["无效的 geodetic 字符串"], - "`fbprophet` package not installed": ["未安装程序包 `fbprophet`"], - "Time grain missing": ["时间粒度缺失"], - "Unsupported time grain: %(time_grain)s": [ - "不支持的时间粒度:%(time_grain)s" + "Can't find User '%(name)s', please ask your admin to create one.": [ + "用户’%(name)s’没有找到,请联系管理员创建。" ], - "Periods must be a positive integer value": ["句点必须是正整数值"], - "Confidence interval must be between 0 and 1 (exclusive)": [ - "置信区间必须介于0和1(不包含1)之间" + "Can't have overlap between Series and Breakdowns": [ + "Series 和 Breakdown 之间不能有重叠" ], - "DataFrame must include temporal column": [ - "数据帧(DataFrame)必须包含时间列" + "Cancel": ["取消"], + "Cancel query on window unload event": ["取消窗口上传事件的查询"], + "Cannot create cyclic hierarchy": ["无法创建循环层级"], + "Cannot delete a database that has datasets attached": [ + "无法删除附加了数据集的数据库" ], - "DataFrame include at least one series": [ - "数据帧(DataFrame)至少包括一个序列" + "Cannot import dashboard: %(db_error)s.\nMake sure to create the database before importing the dashboard.": [ + "无法导入看板:%(db_error)s 。\n请确保在导入看板之前创建数据库。" ], - "percentiles must be a list or tuple with two numeric values, of which the first is lower than the second value": [ - "百分位数必须是具有两个数值的列表或元组,其中第一个数值要小于第二个数值" + "Cannot load filter": ["无法加载筛选器"], + "Cannot parse time string [%(human_readable)s]": [ + "无法解析时间字符串[%(human_readable)s]" ], - "User": ["用户"], - "User Roles": ["用户角色"], - "Database URL": ["数据库URL"], - "Roles to grant": ["角色授权"], - "Created On": ["创建日期"], - "List Observations": ["观察结果列表"], - "Show Observation": ["显示观察结果"], - "Error Message": ["错误消息"], - "Log Retentions (days)": ["日志保留(天)"], - "A semicolon ';' delimited list of email addresses": [ - "以分号 ';' 分隔的电子邮件地址列表" + "Categorical": ["分类"], + "Categories to group by on the x-axis.": ["要在x轴上分组的类别。"], + "Category": ["分类"], + "Category of target nodes": ["目标节点类别"], + "Cell Padding": ["单元填充"], + "Cell Radius": ["单元格半径"], + "Cell Size": ["单元尺寸"], + "Cell bars": ["单元格柱状图"], + "Cell content": ["单元格内容"], + "Center": ["中心对齐"], + "Certification": ["认证"], + "Certification details": ["认证细节"], + "Certified": ["认证"], + "Certified By": ["认证"], + "Certified by": ["认证"], + "Certified by %s": ["认证人 %s"], + "Change dataset": ["修改数据集"], + "Change order of columns.": ["更改列的顺序。"], + "Change order of rows.": ["更改行的顺序。"], + "Changed By": ["修改人"], + "Changed On": ["改变为"], + "Changed on": ["改变为"], + "Changing the dataset may break the chart if the chart relies on columns or metadata that does not exist in the target dataset": [ + "如果图表依赖于目标数据集中不存在的列或元数据,则更改数据集可能会破坏图表" ], - "How long to keep the logs around for this alert": [ - "这个警报的日志要保存多久" + "Changing these settings will affect all charts using this dataset, including charts owned by other people.": [ + "更改这些设置将影响使用此数据集的所有图表,包括其他人拥有的图表。" ], - "Once an alert is triggered, how long, in seconds, before Superset nags you again.": [ - "在Superset再次提醒您之前需要多长时间--以秒为单位--来触发一个警报" + "Changing this Dashboard is forbidden": ["无法修改该看板"], + "Changing this chart is forbidden": ["禁止更改此图表"], + "Changing this control takes effect instantly": ["更改此控件立即生效。"], + "Changing this dataset is forbidden": ["没有权限更新此数据集"], + "Changing this dataset is forbidden.": ["禁止更改此数据集。"], + "Changing this report is forbidden": ["禁止更改此报告"], + "Character to interpret as decimal point.": [ + "将字符解释为小数点的字符。" ], - "A SQL statement that defines whether the alert should get triggered or not. The query is expected to return either NULL or a number value.": [ - "定义是否应触发警报的SQL语句。查询应返回NULL或数字值。" + "Charge": ["电荷数(作用力)"], + "Charge in the force layout": ["在力导向图中的电荷数(作用力)"], + "Chart": ["图表"], + "Chart %(id)s not found": ["图表 %(id)s 没有找到"], + "Chart Cache Timeout": ["表缓存超时"], + "Chart Email Schedules": ["图表电子邮件时间表"], + "Chart ID": ["图表 ID"], + "Chart Options": ["图表选项"], + "Chart Owner: %s": ["图表所有者:%s"], + "Chart Title": ["图表标题"], + "Chart [{}] has been overwritten": ["图表 [{}] 已经覆盖"], + "Chart [{}] has been saved": ["图表 [{}] 已经保存"], + "Chart [{}] was added to dashboard [{}]": [ + "图表 [{}] 已经添加到看板 [{}]" ], - "annotation start time or end time is required.": [ - "注释的开始时间或结束时间是必需的。" + "Chart cache timeout": ["图表缓存超时"], + "Chart changes": ["图表变化"], + "Chart component that lets you add a custom filter UI in your dashboard. When added to dashboard, a filter box lets users specify specific values or ranges to filter charts by. The charts that each filter box is applied to can be fine tuned as well in the dashboard view.\n\n Note that this plugin is being replaced with the new Filters feature that lives in the dashboard view itself. It's easier to use and has more capabilities!": [ + "图表组件,允许您在仪表板中添加自定义过滤器UI。当添加到仪表板时,过滤器框允许用户指定特定的值或范围来过滤图表。每个筛选框所应用的图表也可以在仪表板视图中进行微调。请注意,这个插件正在被仪表板视图中的新过滤器功能所取代。它更易于使用,功能更强大!" ], - "Annotation end time must be no earlier than start time.": [ - "注释的结束时间不能早于开始时间。" + "Chart could not be created.": ["您的查询无法保存。"], + "Chart could not be deleted.": ["这个查询无法被加载。"], + "Chart could not be updated.": ["您的查询无法保存。"], + "Chart does not exist": ["图表没有找到"], + "Chart has no query context saved. Please save the chart again.": [ + "图表未保存任何查询上下文。请重新保存图表。" ], - "Annotations": ["注释"], - "Show Annotation": ["查看注释"], - "Add Annotation": ["添加注释"], - "Edit Annotation": ["编辑注释"], - "Layer": ["层"], - "Label": ["标签"], - "Start": ["开始"], - "End": ["结束"], - "JSON Metadata": ["JSON 元数据"], - "Show Annotation Layer": ["查看注释层"], - "Add Annotation Layer": ["添加注释层"], - "Edit Annotation Layer": ["编辑注释层"], - "Name": ["名称"], - "Dataset %(name)s already exists": ["数据集 %(name)s 已存在"], - "Table [%{table}s] could not be found, please double check your database connection, schema, and table name, error: {}": [ - "找不到 [%{table}s] 表,请仔细检查您的数据库连接、Schema 和 表名" + "Chart name": ["图表名称"], + "Chart options": ["图表选项"], + "Chart parameters are invalid.": ["图表参数无效。"], + "Chart type": ["图表类型"], + "Charts": ["图表"], + "Charts could not be deleted.": ["这个查询无法被加载"], + "Check configuration": ["检查配置"], + "Check for sorting ascending": ["按照升序进行排序"], + "Check if the Rose Chart should use segment area instead of segment radius for proportioning": [ + "检查玫瑰图是否应该使用线段面积而不是线段半径来进行比例" ], - "json isn't valid": ["无效 JSON"], - "Export to YAML": ["导出到YAML"], - "Export to YAML?": ["导出到YAML?"], - "Delete": ["删除"], - "Delete all Really?": ["确定删除全部?"], - "Is favorite": ["收藏"], - "The data source seems to have been deleted": ["数据源已经被删除"], - "The user seems to have been deleted": ["用户已经被删除"], - "Access was requested": ["请求访问"], - "The access requests seem to have been deleted": ["访问请求已被删除"], - "%(user)s was granted the role %(role)s that gives access to the %(datasource)s": [ - "授予 %(user)s %(role)s 角色来访问 %(datasource)s 数据库" + "Check out this chart in dashboard:": ["在仪表盘中查看此图表"], + "Check out this chart: ": ["看看这张图表:"], + "Check out this dashboard: ": ["查看此看板:"], + "Check to apply filters instantly as they change instead of displaying [Apply] button": [ + "选中可在过滤条件更改时立即应用过滤,而不是使用 [应用] 按钮" ], - "Role %(r)s was extended to provide the access to the datasource %(ds)s": [ - "扩展角色 %(r)s 以提供对 datasource %(ds)s 的访问" + "Check to force date partitions to have the same height": [ + "选中以强制日期分区具有相同的高度" ], - "You have no permission to approve this request": [ - "您没有此请求的访问权限" + "Check to include Druid granularity dropdown": [ + "检查包含Druid时间粒度下拉列表" ], - "Cannot import dashboard: %(db_error)s.\nMake sure to create the database before importing the dashboard.": [ - "无法导入看板:%(db_error)s 。\n请确保在导入看板之前创建数据库。" + "Check to include SQL time grain dropdown": [ + "选中以包括SQL时间粒度下拉菜单" ], - "An unknown error occurred. Please contact your Superset administrator": [ - "发生未知错误。请与管理员联系" + "Check to include time column dropdown": ["检查包含时间列下拉列表"], + "Check to include time grain dropdown": ["选中以包括时间粒度下拉菜单"], + "Check to include time origin dropdown": ["检查包含时间原点的下拉列表"], + "Child label position": ["子标签位置"], + "Choice of [Label] must be present in [Group By]": [ + "[标签] 的选择项必须出现在 [Group By]" ], - "Error occurred when opening the chart: %(error)s": [ - "打开图表时出错: %(error)s" + "Choice of [Point Radius] must be present in [Group By]": [ + "[点半径] 的选择项必须出现在 [Group By]" ], - "You don't have the rights to ": ["您没有授权 "], - "alter this ": ["修改这个 "], - "chart": ["图表"], - "create a ": ["创建一个 "], - "Explore - %(table)s": ["查看 - %(table)s"], - "Chart [{}] has been saved": ["图表 [{}] 已经保存"], - "Chart [{}] has been overwritten": ["图表 [{}] 已经覆盖"], - "dashboard": ["看板"], - "Chart [{}] was added to dashboard [{}]": [ - "图表 [{}] 已经添加到看板 [{}]" + "Choose File": ["选择文件"], + "Choose a chart or dashboard not both": [ + "选择图表或看板,不能都全部选择" ], - "Dashboard [{}] just got created and chart [{}] was added to it": [ - "看板 [{}] 刚刚被创建,并且图表 [{}] 已被添加到其中" + "Choose a database...": ["选择数据库"], + "Choose a dataset": ["选择数据源"], + "Choose a metric for left axis": ["选择左轴的计量指标"], + "Choose a metric for right axis": ["为右轴选择一个指标"], + "Choose a number format": ["选择一种数字格式"], + "Choose a source": ["选择一个源"], + "Choose a source and a target": ["选择一个源和一个目标"], + "Choose a target": ["选择一个目标"], + "Choose chart type": ["选择图表类型"], + "Choose one or more charts for left axis": ["为左轴选择一个或多个图表"], + "Choose one or more charts for right axis": ["为右轴选择一个或多个图表"], + "Choose the annotation layer type": ["选择注释层类型"], + "Choose the source of your annotations": ["选择您的注释来源"], + "Chord Diagram": ["弦图"], + "Chosen non-numeric column": ["选定的非数字列"], + "Circle": ["圆"], + "Circle -> Arrow": ["圆 -> 箭头"], + "Circle -> Circle": ["圆 -> 圆"], + "Circle radar shape": ["圆形雷达图"], + "Circular": ["圆"], + "Classic chart that visualizes how metrics change over time.": [ + "直观显示指标随时间变化的经典图表。" + ], + "Classic row-by-column spreadsheet like view of a dataset. Use tables to showcase a view into the underlying data or to show aggregated metrics.": [ + "数据集的典型的逐行逐列电子表格视图。使用表格显示底层数据的视图或显示聚合指标。" ], - "This dashboard was changed recently. Please reload dashboard to get latest version.": [ - "此看板最近已更新。请重新加载看板以获取最新版本。" + "Clause": ["从句"], + "Clear": ["清除"], + "Clear all": ["清楚所有"], + "Click the lock to make changes.": ["单击锁以进行更改。"], + "Click the lock to prevent further changes.": [ + "单击锁定以防止进一步更改。" ], - "Could not load database driver: %(driver_name)s": [ - "无法加载数据库驱动程序:%(driver_name)s" + "Click this link to switch to an alternate form that allows you to input the SQLAlchemy URL for this database manually.": [ + "单击此链接可切换到备用表单,该表单允许您手动输入此数据库的SQLAlChemy URL。" ], - "Invalid connection string, a valid string usually follows:\n'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'": [ - "连接字符串无效,有效字符串的格式通常如下:\n'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'" + "Click this link to switch to an alternate form that exposes only the required fields needed to connect this database.": [ + "单击此链接可切换到仅显示连接此数据库所需的必填字段的备用表单。" ], - "Malformed request. slice_id or table_name and db_name arguments are expected": [ - "格式错误的请求。需要使用 slice_id 或 table_name 和 db_name 参数" + "Click to change visualization type": ["选择一个可视化类型"], + "Click to clear emitted filters": ["点击清除过滤"], + "Click to edit": ["点击编辑"], + "Click to edit label": ["单击以编辑标签"], + "Click to favorite/unfavorite": ["点击 收藏/取消收藏"], + "Click to force-refresh": ["点击强制刷新"], + "Click to see difference": ["点击查看差异"], + "Close": ["关闭"], + "Close all other tabs": ["关闭其他tab页"], + "Close tab": ["关闭标签"], + "Cluster": ["集群"], + "Cluster Name": ["群集名称"], + "Cluster label aggregator": ["集群标签聚合器"], + "Clustering Radius": ["簇半径"], + "Code": ["代码"], + "Collapse all": ["全部折叠"], + "Collapse table preview": ["折叠表的预览"], + "Color": ["颜色"], + "Color +/-": ["色彩 +/-"], + "Color Metric": ["颜色指标"], + "Color Scheme": ["配色方案"], + "Color Steps": ["色彩 Steps"], + "Color metric": ["颜色指标"], + "Color scheme": ["配色方案"], + "Color will be rendered based on a ratio of the cell against the sum of across this criteria": [ + "颜色将根据单元格与整个标准之和的比率来展示" ], - "Chart %(id)s not found": ["图表 %(id)s 没有找到"], - "Table %(table)s wasn't found in the database %(db)s": [ - "在数据库 %(db)s 中找不到表 %(table)s" + "Colors": ["颜色"], + "Column": ["列"], + "Column \"%(column)s\" is not numeric or does not exists in the query results.": [ + "列\"%(column)s\"不是数字或不在查询结果中" ], - "Can't find User '%(name)s', please ask your admin to create one.": [ - "用户’%(name)s’没有找到,请联系管理员创建。" + "Column Label(s)": ["字段标签"], + "Column containing ISO 3166-2 codes of region/province/department in your table.": [ + "表中包含地区/省/省的ISO 3166-2代码的列" ], - "Can't find DruidCluster with cluster_name = '%(name)s'": [ - "不能找到具有 cluster_name = '%(name)s' 的 Druid 集群" + "Column containing latitude data": ["包含纬度数据的列"], + "Column containing longitude data": ["包含经度数据的列"], + "Column is required": ["列是必填项"], + "Column label for index column(s). If None is given and Dataframe Index is True, Index Names are used.": [ + "索引列的列标签。如果为None, 并且数据框索引为 true, 则使用 \"索引名称\"。" ], - "Data could not be deserialized. You may want to re-run the query.": [ - "无法反序列化数据。您可能需要重新运行查询。" + "Column name [%s] is duplicated": ["列名 [%s] 重复"], + "Column name(s) ": ["列名"], + "Column referenced by aggregate is undefined: %(column)s": [ + "聚合引用的列未定义:%(column)s" ], - "%(validator)s was unable to check your query.\nPlease recheck your query.\nException: %(ex)s": [ - "%(validator)s 无法检查您的查询。\n请重新检查您的查询。\n异常: %(ex)s" + "Column select": ["选择列"], + "Column to use as the row labels of the dataframe. Leave empty if no index column.": [ + "字段作为数据文件的行标签使用。如果没有索引字段,则留空。" ], - "Failed to start remote query on a worker. Tell your administrator to verify the availability of the message queue.": [ - "无法对工作进程启动远程查询。请和管理员确认验证消息队列的可用性。" + "Columnar File": ["列式存储文件"], + "Columnar file \"%(columnar_filename)s\" uploaded to table \"%(table_name)s\" in database \"%(db_name)s\"": [ + "Excel 文件 \"%(columnar_filename)s\" 上传到数据库 \"%(db_name)s\" 中的表 \"%(table_name)s\"" ], - "Query record was not created as expected.": ["查询记录没有按预期创建。"], - "The parameter %(parameters)s in your query is undefined.": [ - "查询中的以下参数未定义:%(parameters)s 。" + "Columnar to Database configuration": ["列式存储文件到数据库配置"], + "Columns": ["列"], + "Columns missing in datasource: %(invalid_columns)s": [ + "数据源中缺少列:%(invalid_columns)s" ], - "%(user)s's profile": ["%(user)s 的信息"], - "Show CSS Template": ["查看CSS模板"], - "Add CSS Template": ["新增CSS模板"], - "Edit CSS Template": ["编辑CSS模板"], - "Template Name": ["模板名称"], - "A human-friendly name": ["人性化的名称"], - "Used internally to identify the plugin. Should be set to the package name from the pluginʼs package.json": [ - "在内部用于标识插件。应该在插件的 package.json 内被设置为包名。" + "Columns subtotal position": ["列的小计位置"], + "Columns to calculate distribution across. Defaults to temporal column if left empty.": [ + "计算分布的列。如果留空,则默认为临时列。" ], - "A full URL pointing to the location of the built plugin (could be hosted on a CDN for example)": [ - "指向内置插件位置的完整URL(例如,可以托管在CDN上)" + "Columns to display": ["要显示的字段"], + "Columns to group by": ["需要进行分组的一列或多列"], + "Columns to group by on the columns": ["必须是分组列"], + "Columns to group by on the rows": ["行上分组所依据的列"], + "Combine Metrics": ["整合指标"], + "Combine metrics": ["整合指标"], + "Comma-separated color picks for the intervals, e.g. 1,2,4. Integers denote colors from the chosen color scheme and are 1-indexed. Length must be matching that of interval bounds.": [ + "间隔的逗号分隔色选项,例如1、2、4。整数表示所选配色方案中的颜色,并以1为索引。长度必须与间隔界限匹配。" ], - "Custom Plugins": ["自定义插件"], - "Custom Plugin": ["自定义插件"], - "Add a Plugin": ["添加插件"], - "Edit Plugin": ["编辑插件"], - "Schedule Email Reports for Dashboards": ["为看板添加电子邮件报告"], - "Manage Email Reports for Dashboards": ["管理看板的电子邮件报告"], - "Changed On": ["改变为"], - "Active": ["激活"], - "Crontab": [""], - "Recipients": ["收件人"], - "Slack Channel": ["Slack 频道"], - "Deliver As Group": ["作为组交付"], - "Delivery Type": ["交付类型"], - "Schedule Email Reports for Charts": ["为图表配置电子邮件报告"], - "Manage Email Reports for Charts": ["管理图表的电子邮件报告"], - "Email Format": ["电子邮件格式"], - "List Saved Query": ["保存的查询列表"], - "Show Saved Query": ["显示保存的查询"], - "Add Saved Query": ["添加保存的查询"], - "Edit Saved Query": ["编辑保存的查询"], - "End Time": ["结束时间"], - "Pop Tab Link": ["流行标签链接"], - "Changed on": ["改变为"], - "Could not determine datasource type": ["无法确定数据源类型"], - "Could not find viz object": ["找不到可视化对象"], - "Show Chart": ["显示图表"], - "Add Chart": ["添加图表"], - "Edit Chart": ["编辑图表"], - "These parameters are generated dynamically when clicking the save or overwrite button in the explore view. This JSON object is exposed here for reference and for power users who may want to alter specific parameters.": [ - "这些参数是在浏览视图中单击保存或覆盖按钮时动态生成的。这个JSON对象在这里公开以供参考,并提供给可能希望更改特定参数的高级用户使用。" + "Comma-separated interval bounds, e.g. 2,4,5 for intervals 0-2, 2-4 and 4-5. Last number should match the value provided for MAX.": [ + "逗号分隔的区间界限,例如0-2、2-4和4-5区间的2、4、5。最后一个数字应与为Max提供的值匹配。" ], - "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the datasource/table timeout if undefined.": [ - "此图表的缓存超时持续时间(以秒为单位)。注意,如果未定义,这默认为数据源/表超时。" + "Comparator option": ["比较器选项"], + "Compare multiple time series charts (as sparklines) and related metrics quickly.": [ + "快速比较多个时间序列图表和相关指标。" ], - "Last Modified": ["最后修改"], - "Parameters": ["参数"], - "Visualization Type": ["可视化类型"], - "Show Dashboard": ["显示看板"], - "Add Dashboard": ["添加看板"], - "Edit Dashboard": ["编辑看板"], - "This json object describes the positioning of the widgets in the dashboard. It is dynamically generated when adjusting the widgets size and positions by using drag & drop in the dashboard view": [ - "这个JSON对象描述了部件在看板中的位置。它是动态生成的,可以通过拖放,在看板中调整整部件的大小和位置" + "Compare the same summarized metric across multiple groups.": [ + "跨多个组比较相同的汇总指标" ], - "The CSS for individual dashboards can be altered here, or in the dashboard view where changes are immediately visible": [ - "可以在这里或者在看板视图修改单个看板的CSS样式" + "Compares how a metric changes over time between different groups. Each group is mapped to a row and change over time is visualized bar lengths and color.": [ + "比较指标在不同组之间随时间的变化情况。每一组被映射到一行,并且随着时间的变化被可视化地显示条的长度和颜色。" ], - "To get a readable URL for your dashboard": ["为看板生成一个可读的 URL"], - "This JSON object is generated dynamically when clicking the save or overwrite button in the dashboard view. It is exposed here for reference and for power users who may want to alter specific parameters.": [ - "这个JSON对象描述了部件在看板中的位置。它是动态生成的,可以通过拖放,在看板中调整整部件的大小和位置" + "Compares metrics from different categories using bars. Bar lengths are used to indicate the magnitude of each value and color is used to differentiate groups.": [ + "使用条形图比较不同类别的指标。条形长度用于指示每个值的大小,颜色用于区分组。" ], - "Owners is a list of users who can alter the dashboard.": [ - "所有者是可以更改看板的用户列表。" + "Compares the lengths of time different activities take in a shared timeline view.": [ + "比较不同活动在共享时间线视图中所花费的时间长度。" ], - "Determines whether or not this dashboard is visible in the list of all dashboards": [ - "确定此看板在所有看板列表中是否可见" + "Comparison": ["比较"], + "Comparison Period Lag": ["滞后比较"], + "Comparison suffix": ["比较前缀"], + "Components": ["组件"], + "Compute the contribution to the total": ["计算对总数的贡献值"], + "Condition": ["条件"], + "Conditional formatting": ["条件格式设置"], + "Confidence interval": ["信区间间隔"], + "Confidence interval must be between 0 and 1 (exclusive)": [ + "置信区间必须介于0和1(不包含1)之间" ], - "Title": ["标题"], - "Slug": ["Slug"], - "Published": ["已发布"], - "Position JSON": ["位置JSON"], - "CSS": ["CSS"], - "Underlying Tables": ["底层表"], - "Export": ["导出"], - "Export dashboards?": ["导出看板?"], - "Name of table to be created from csv data.": [ - "从CSV数据将创建的表的名称。" + "Configuration": ["配置"], + "Configure Advanced Time Range ": ["配置进阶时间范围"], + "Configure Time Range: Last...": ["配置时间范围:上一(Last).."], + "Configure Time Range: Previous...": ["配置时间范围:前一(Previous).."], + "Configure custom time range": ["配置自定义时间范围"], + "Configure filter scopes": ["配置过滤范围"], + "Configure the basics of your Annotation Layer.": ["注释层基本配置"], + "Configure your how you overlay is displayed here.": [ + "配置如何在这里显示您的覆盖。" ], - "CSV File": ["CSV文件"], - "Select a CSV file to be uploaded to a database.": [ - "选择一个CSV文件上传到数据库." + "Confirm save": ["确认保存"], + "Connect": ["连接"], + "Connect Google Sheets as tables to this database": [ + "将Google Sheet作为表格连接到此数据库" ], - "Only the following file extensions are allowed: %(allowed_extensions)s": [ - "仅允许以下文件扩展名:%(allowed_extensions)s" + "Connect a database": ["连接数据库"], + "Connect this database using the dynamic form instead": [ + "使用动态参数连接此数据库" ], - "Specify a schema (if database flavor supports this).": [ - "指定一个Schema(需要数据库支持)" + "Connect this database with a SQLAlchemy URI string instead": [ + "使用SQLAlchemy URI链接此数据库" ], - "Delimiter": ["分隔符"], - "Delimiter used by CSV file (for whitespace use \\s+).": [ - "CSV文件使用的分隔符 (空白请使用 \\s+)" + "Connection": ["连接"], + "Connection failed, please check your connection settings": [ + "连接失败,请检查您的连接配置" ], - "Table Exists": ["表已存在处理"], - "If table exists do one of the following: Fail (do nothing), Replace (drop and recreate table) or Append (insert data).": [ - "如果表已存在,执行其中一个:舍弃(什么都不做),替换(删除表并重建),或者追加(插入数据)" + "Connection looks good!": ["连接测试成功!"], + "Continuous": ["连续式"], + "Contribution": ["贡献"], + "Contribution Mode": ["贡献模式"], + "Control labeled ": ["控件已标记 "], + "Controls labeled ": ["控件已标记"], + "Coordinates": ["坐标"], + "Copied to clipboard!": ["复制到剪贴板!"], + "Copy": ["复制"], + "Copy SELECT statement to the clipboard": ["将 SELECT 语句复制到剪贴板"], + "Copy and Paste JSON credentials": ["复制和粘贴JSON凭据"], + "Copy and paste the entire service account .json file here": [ + "复制服务帐户的json文件复制并粘贴到此处" ], - "Fail": ["失败"], - "Replace": ["替换"], - "Append": ["追加"], - "Header Row": ["标题行"], - "Row containing the headers to use as column names (0 is first line of data). Leave empty if there is no header row.": [ - "作为列名的带有标题的行(0是第一行数据)。如果没有标题行则留空。" + "Copy chart URL": ["复制图表URL"], + "Copy chart URL to clipboard": ["复制图表URL到剪贴板"], + "Copy dashboard URL": ["复制仪表盘URL"], + "Copy link": ["复制链接"], + "Copy message": ["复制信息"], + "Copy of %s": ["%s 的副本"], + "Copy partition query to clipboard": ["将分区查询复制到剪贴板"], + "Copy query URL": ["复制查询URL"], + "Copy query link to your clipboard": ["将查询链接复制到剪贴板"], + "Copy the account name of that database you are trying to connect to.": [ + "复制尝试连接的数据库帐户名" ], - "Index Column": ["索引字段"], - "Column to use as the row labels of the dataframe. Leave empty if no index column.": [ - "字段作为数据文件的行标签使用。如果没有索引字段,则留空。" + "Copy the name of the database you are trying to connect to.": [ + "复制尝试连接的数据库名" ], - "Mangle Duplicate Columns": ["混合重复列"], - "Specify duplicate columns as \"X.0, X.1\".": [ - "将重复列指定为“x.0,x.1”。" + "Copy to Clipboard": ["复制到剪贴板"], + "Copy to clipboard": ["复制到剪贴板"], + "Correlation": ["相关性"], + "Cost estimate": ["成本估算"], + "Could not determine datasource type": ["无法确定数据源类型"], + "Could not fetch all saved charts": ["无法获取所有保存的图表"], + "Could not find viz object": ["找不到可视化对象"], + "Could not load database driver": ["无法加载数据库驱动程序"], + "Could not load database driver: %(driver_name)s": [ + "无法加载数据库驱动程序:%(driver_name)s" ], - "Skip Initial Space": ["跳过初始空格"], - "Skip spaces after delimiter.": ["在分隔符之后跳过空格。"], - "Skip Rows": ["跳过行"], - "Number of rows to skip at start of file.": ["在文件开始时跳过的行数。"], - "Rows to Read": ["读取的行"], - "Number of rows of file to read.": ["要读取的文件行数。"], - "Skip Blank Lines": ["跳过空白行"], - "Skip blank lines rather than interpreting them as NaN values.": [ - "跳过空白行而不是把它们解释为NaN值。" + "Could not load database driver: {}": ["无法加载数据库驱动程序:{}"], + "Could not verify the host": ["无法验证主机名(IP)"], + "Country": ["国家"], + "Country Color Scheme": ["国家颜色方案"], + "Country Column": ["国家字段"], + "Country Field Type": ["国家字段的类型"], + "Country Map": ["国家地图"], + "Create": ["创建"], + "Create a new chart": ["创建新图表"], + "Create new chart": ["创建新图表"], + "Create new filter set": ["创建新的过滤器"], + "Create or select schema...": ["创建或者选择模式"], + "Created": ["已创建"], + "Created On": ["创建日期"], + "Created by": ["创建人"], + "Created content": ["创建的内容"], + "Created on": ["创建日期"], + "Creating a data source and creating a new tab": [ + "创建数据源,并弹出一个新的标签页" ], - "Parse Dates": ["解析日期"], - "A comma separated list of columns that should be parsed as dates.": [ - "应作为日期解析的列的逗号分隔列表。" + "Creator": ["作者"], + "Crontab": ["定时任务"], + "Cross Filter Scoping": ["交叉筛选作用域"], + "Cross-filter scoping": ["交叉筛选作用域"], + "Cumulative": ["累计"], + "Custom": ["自定义"], + "Custom Plugin": ["自定义插件"], + "Custom Plugins": ["自定义插件"], + "Custom SQL": ["自定义SQL"], + "Custom SQL ad-hoc filters are not available for the native Druid connector": [ + "自定义SQL即席筛选器不适用于本机Druid连接器" ], - "Infer Datetime Format": ["日期时间格式"], - "Use Pandas to interpret the datetime format automatically.": [ - "使用Pandas自动解释日期时间格式。" + "Custom SQL ad-hoc metrics are not available for the native Druid connector": [ + "自定义SQL即席查询不适用于本机Druid连接器" ], - "Decimal Character": ["十进制字符"], - "Character to interpret as decimal point.": [ - "将字符解释为小数点的字符。" + "Custom SQL ad-hoc metrics are not enabled for this dataset": [ + "此数据集无法启用自定义SQL即席查询、" ], - "Dataframe Index": ["Dataframe索引"], - "Write dataframe index as a column.": ["将dataframe index 作为列."], - "Column Label(s)": ["字段标签"], - "Column label for index column(s). If None is given and Dataframe Index is True, Index Names are used.": [ - "索引列的列标签。如果为None, 并且数据框索引为 true, 则使用 \"索引名称\"。" - ], - "Null values": ["空值"], - "Json list of the values that should be treated as null. Examples: [\"\"], [\"None\", \"N/A\"], [\"nan\", \"null\"]. Warning: Hive database supports only single value. Use [\"\"] for empty string.": [ - "应视为null的值的Json列表。例如:[\"\"], [\"None\", \"N/A\"], [\"nan\", \"null\"]。警告:Hive数据库仅支持单个值。用 [\"\"] 代表空字符串。" - ], - "Name of table to be created from excel data.": [ - "从excel数据将创建的表的名称。" - ], - "Excel File": ["Excel文件"], - "Select a Excel file to be uploaded to a database.": [ - "选择要上传到数据库的Excel文件。" - ], - "Sheet Name": ["Sheet名称"], - "Strings used for sheet names (default is the first sheet).": [ - "用于sheet名称的字符串(默认为第一个sheet)。" - ], - "Show Database": ["显示数据库"], - "Add Database": ["添加数据库"], - "Edit Database": ["编辑数据库"], - "Expose this DB in SQL Lab": ["在 SQL 工具箱中公开这个数据库"], - "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.": [ - "以异步模式操作数据库,这意味着查询是在远程工作人员上执行的,而不是在web服务器本身上执行的, 这假设您有一个Celery worker setup以及一个结果后端。有关更多信息,请参考安装文档。" - ], - "Allow CREATE TABLE AS option in SQL Lab": [ - "在 SQL 编辑器中允许 CREATE TABLE AS 选项" - ], - "Allow CREATE VIEW AS option in SQL Lab": [ - "在 SQL 编辑器中允许 CREATE VIEW AS 选项" + "Custom time filter plugin": ["自定义时间过滤器插件"], + "Customize": ["定制化配置"], + "Customize Metrics": ["自定义指标"], + "Customize columns": ["自定义列"], + "D3 Format": ["D3 格式"], + "D3 format": ["D3 格式"], + "D3 format syntax: https://github.com/d3/d3-format": [ + "D3插件格式语法: https://github.com/d3/d3-time-format" ], - "Allow users to run non-SELECT statements (UPDATE, DELETE, CREATE, ...) in SQL Lab": [ - "允许用户在 SQL 编辑器中运行非 SELECT 语句(UPDATE,DELETE,CREATE,...)" + "D3 number format for numbers between -1.0 and 1.0, useful when you want to have different siginificant digits for small and large numbers": [ + "D3数字格式,用于-1.0和1.0之间的数字,当您希望小数和大数有不同的符号数字时很有用" ], - "When allowing CREATE TABLE AS option in SQL Lab, this option forces the table to be created in this schema": [ - "当在 SQL 编辑器中允许 CREATE TABLE AS 选项时,此选项可以此模式中强制创建表" + "D3 time format for datetime columns": ["D3时间格式的时间列"], + "D3 time format syntax: https://github.com/d3/d3-time-format": [ + "D3时间插件格式语法: https://github.com/d3/d3-time-format" ], - "If Presto, Trino or Drill all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them.<br/>If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.": [ - "如果使用Presto,SQL 工具箱中的所有查询都将被当前登录的用户执行,并且这些用户必须拥有运行它们的权限。<br/>如果启用 Hive 和hive.server2.enable.doAs,将作为服务帐户运行查询,但会根据hive.server2.proxy.user的属性伪装当前登录用户。" + "DEC": ["十二月"], + "DELETE": ["删除"], + "DESCRIPTION ERROR": ["描述错误"], + "DML": ["DML(数据操作语言)"], + "Dark mode": ["黑暗模式"], + "Dashboard": ["看板"], + "Dashboard Emails": ["看板"], + "Dashboard [{}] just got created and chart [{}] was added to it": [ + "看板 [{}] 刚刚被创建,并且图表 [{}] 已被添加到其中" ], - "Allow SQL Lab to fetch a list of all tables and all views across all database schemas. For large data warehouse with thousands of tables, this can be expensive and put strain on the system.": [ - "允许 sql lab 获取所有数据库架构中的所有表和所有视图的列表。对于具有数千个表的大型数据仓库, 这可能会很耗费性能, 并给系统带来压力。" + "Dashboard could not be created.": ["看板无法被创建"], + "Dashboard could not be deleted.": ["看板无法被删除。"], + "Dashboard could not be updated.": ["看板无法更新。"], + "Dashboard does not exist": ["看板不存在"], + "Dashboard parameters are invalid.": ["看板参数无效。"], + "Dashboard properties": ["看板属性"], + "Dashboard scheme": ["仪表盘模式"], + "Dashboards": ["仪表盘"], + "Dashboards could not be deleted.": ["仪表盘无法被删除。"], + "Dashboards do not exist": ["仪表盘"], + "Data": ["数据"], + "Data Source": ["数据源"], + "Data Table": ["数据表"], + "Data Zoom": ["数据缩放"], + "Data could not be deserialized from the results backend. The storage format might have changed, rendering the old data stake. You need to re-run the original query.": [ + "无法从结果后端反序列化数据。存储格式可能已经改变,呈现了旧的数据桩。您需要重新运行原始查询。" ], - "Duration (in seconds) of the caching timeout for charts of this database. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.": [ - "此数据库图表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为全局超时。" + "Data could not be retrieved from the results backend. You need to re-run the original query.": [ + "无法从结果后端检索数据。您需要重新运行原始查询。" ], - "If selected, please set the schemas allowed for csv upload in Extra.": [ - "如果选择,请额外设置csv上传允许的模式。" + "Data preview": ["数据预览"], + "Data source": ["数据源"], + "Data type": ["数据类型"], + "DataFrame include at least one series": [ + "数据帧(DataFrame)至少包括一个序列" ], - "Expose in SQL Lab": ["在 SQL 工具箱中公开"], - "Allow CREATE TABLE AS": ["允许 CREATE TABLE AS"], - "Allow CREATE VIEW AS": ["允许 CREATE VIEW AS"], - "Allow DML": ["允许 DML"], - "CTAS Schema": ["CTAS 模式"], - "SQLAlchemy URI": ["SQLAlchemy URI"], - "Chart Cache Timeout": ["表缓存超时"], - "Secure Extra": ["安全"], - "Root certificate": ["根证书"], - "Async Execution": ["异步执行查询"], - "Impersonate the logged on user": ["模拟登录用户"], - "Allow Csv Upload": ["允许Csv上传"], - "Allow Multi Schema Metadata Fetch": ["允许多Schema元数据获取"], - "Backend": ["后端"], - "Extra field cannot be decoded by JSON. %(msg)s": [ - "JSON无法解码额外字段。%(msg)s" + "DataFrame must include temporal column": [ + "数据帧(DataFrame)必须包含时间列" ], - "Invalid connection string, a valid string usually follows:'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'<p>Example:'postgresql://user:password@your-postgres-db/database'</p>": [ - "连接字符串无效,有效字符串格式通常如下:'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'<p>例如:'postgresql://user:password@your-postgres-db/database'</p>" + "Database": ["数据库"], + "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for columnar uploads. Please contact your Superset Admin.": [ + "数据库 \"%(database_name)s\" schema \"%(schema_name)s\" 不允许用于excel上传。请联系管理员。" ], - "CSV to Database configuration": ["csv 到数据库配置"], "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for csv uploads. Please contact your Superset Admin.": [ "数据库 \"%(database_name)s\" schema \"%(schema_name)s\" 不允许用于csv上传。请联系管理员。" ], - "You cannot specify a namespace both in the name of the table: \"%(csv_table.table)s\" and in the schema field: \"%(csv_table.schema)s\". Please remove one": [ - "不能同时在表名 \"%(csv_table.table)s\" 和schema字段 \"%(csv_table.schema)s\" 中指定命名空间。请删除一个。" - ], - "Unable to upload CSV file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ - "无法将CSV文件 \"%(filename)s\" 上传到数据库 \"%(db_name)s\" 中的表 \"%(table_name)s\" 内。错误消息:%(error_msg)s" - ], - "CSV file \"%(csv_filename)s\" uploaded to table \"%(table_name)s\" in database \"%(db_name)s\"": [ - "csv 文件 \"%(csv_filename)s\" 上传到数据库 \"%(db_name)s\" 中的表 \"%(table_name)s\"" - ], - "Excel to Database configuration": ["Excel 到数据库配置"], "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed for excel uploads. Please contact your Superset Admin.": [ "数据库 \"%(database_name)s\" schema \"%(schema_name)s\" 不允许用于excel上传。请联系管理员。" ], - "You cannot specify a namespace both in the name of the table: \"%(excel_table.table)s\" and in the schema field: \"%(excel_table.schema)s\". Please remove one": [ - "不能同时在表名 \"%(excel_table.table)s\" 和schema字段 \"%(excel_table.schema)s\" 中指定命名空间。请删除一个。" + "Database Creation Error": ["数据库创建错误"], + "Database URL": ["数据库URL"], + "Database could not be created.": ["数据库无法被创建"], + "Database could not be deleted.": ["数据库不能删除。"], + "Database could not be updated.": ["数据库无法更新"], + "Database does not allow data manipulation.": [ + "数据库不允许此数据操作。" ], - "Unable to upload Excel file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ - "无法将Excel文件 \"%(filename)s\" 上传到数据库 \"%(db_name)s\" 中的表 \"%(table_name)s\" 内。错误消息:%(error_msg)s" + "Database does not exist": ["数据库不存在"], + "Database does not support subqueries": ["数据库不支持子查询"], + "Database error": ["数据库错误"], + "Database is offline.": ["数据库已下线"], + "Database is required for alerts": ["警报需要数据库"], + "Database name": ["数据库名称"], + "Database not allowed to change": ["数据集不允许被修改"], + "Database not found.": ["数据库没有找到"], + "Database parameters are invalid.": ["数据库参数无效"], + "Database port": ["数据库端口"], + "Databases": ["数据库"], + "Dataframe Index": ["Dataframe索引"], + "Dataset": ["数据集"], + "Dataset %(name)s already exists": ["数据集 %(name)s 已存在"], + "Dataset column delete failed.": ["数据集列删除失败。"], + "Dataset column not found.": ["数据集行删除失败。"], + "Dataset could not be created.": ["无法创建数据集。"], + "Dataset could not be deleted.": ["无法删除数据集"], + "Dataset could not be updated.": ["无法更新数据集。"], + "Dataset does not exist": ["数据集不存在"], + "Dataset is required": ["需要数据集"], + "Dataset metric delete failed.": ["数据集指标删除失败"], + "Dataset metric not found.": ["数据集指标没找到"], + "Dataset name": ["数据集名称"], + "Dataset parameters are invalid.": ["数据集参数无效。"], + "Dataset(s) could not be bulk deleted.": ["数据集无法批量删除"], + "Datasets": ["数据集"], + "Datasets do not contain a temporal column": ["数据集不包含时间列"], + "Datasource": ["数据源"], + "Datasource & Chart Type": ["数据源 & 图表类型"], + "Datasource Name": ["数据库名称"], + "Datasource id not found: %(id)s": ["数据源id不存在:%(id)s"], + "Datasource type is required when datasource_id is given": [ + "给定数据源id时,需要提供数据源类型" ], - "Excel file \"%(excel_filename)s\" uploaded to table \"%(table_name)s\" in database \"%(db_name)s\"": [ - "Excel 文件 \"%(excel_filename)s\" 上传到数据库 \"%(db_name)s\" 中的表 \"%(table_name)s\"" + "Date Time Format": ["时间格式"], + "Date filter": ["日期过滤器"], + "Date format": ["日期格式化"], + "Date/Time": ["日期/时间"], + "Datetime Format": ["时间格式"], + "Datetime column not provided as part table configuration and is required by this type of chart": [ + "没有提供该表配置的日期时间列,它是此类型图表所必需的" ], - "Logs": ["日志"], - "Show Log": ["查看日志"], - "Add Log": ["新增日志"], - "Edit Log": ["编辑日志"], - "Action": ["操作"], - "dttm": ["dttm"], - "Add item": ["增加条件"], - "The query couldn't be loaded": ["这个查询无法被加载"], - "Your query has been scheduled. To see details of your query, navigate to Saved queries": [ - "您的查询已被调度。要查看查询的详细信息,请跳转到保存查询页面查看。" + "Datetime format": ["时间格式"], + "Day": ["天"], + "Days %s": ["%s天"], + "Db engine did not return all queried columns": [ + "数据库引擎未返回所有查询的列" ], - "Your query could not be scheduled": ["无法调度您的查询"], - "Failed at retrieving results": ["检索结果失败"], - "An error occurred while storing the latest query id in the backend. Please contact your administrator if this problem persists.": [ - "在后端存储最新查询id时出错。如果此问题仍然存在,请与管理员联系。" + "December": ["十二月"], + "Decimal Character": ["十进制字符"], + "Deck.gl - 3D Grid": ["Deck.gl - 3D网格"], + "Deck.gl - 3D HEX": ["Deck.gl - 3D六角曲面"], + "Deck.gl - Arc": ["Deck.gl - 弧度"], + "Deck.gl - GeoJSON": ["Deck.gl - 地理json"], + "Deck.gl - Multiple Layers": ["多图层"], + "Deck.gl - Paths": ["Deck.gl - 路径"], + "Deck.gl - Polygon": ["Deck.gl - 多角形"], + "Deck.gl - Scatter plot": ["Deck.gl - 散点图"], + "Deck.gl - Screen Grid": ["Deck.gl - 屏幕网格"], + "Default": ["默认"], + "Default Endpoint": ["默认端点"], + "Default URL": ["默认URL"], + "Default URL to redirect to when accessing from the dataset list page": [ + "从数据集列表页访问时重定向到的默认URL" ], - "Unknown error": ["未知错误"], - "Query was stopped.": ["查询被终止。"], - "Unable to migrate table schema state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ - "无法将表结构状态迁移到后端。系统将稍后重试。如果此问题仍然存在,请与管理员联系。" + "Default Value": ["缺省值"], + "Default latitude": ["默认纬度"], + "Default longitude": ["默认经度"], + "Default minimal column width in pixels, actual width may still be larger than this if other columns don't need much space": [ + "默认最小列宽(以像素为单位),如果其他列不需要太多空间,则实际宽度可能仍大于此值" ], - "Unable to migrate query state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ - "无法将查询状态迁移到后端。系统将稍后重试。如果此问题仍然存在,请与管理员联系。" + "Default to first item": ["默认为第一项"], + "Default value is required": ["需要默认值"], + "Default value must be set when \"Filter has default value\" is checked": [ + "选中筛选器具有默认值时,必须设置默认值" ], - "Unable to migrate query editor state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ - "无法将查询编辑器状态迁移到后端。系统将稍后重试。如果此问题仍然存在,请与管理员联系。" + "Default value must be set when \"Required\" is checked": [ + "当\"必填项\"被选中时默认值必须被设置" ], - "Unable to add a new tab to the backend. Please contact your administrator.": [ - "无法将新选项卡添加到后端。请与管理员联系。" + "Default value set automatically when \"Default to first item\" is checked": [ + "当\"默认为第一项\"被选中时默认值需要设置为自动" ], - "Copy of %s": ["%s 的副本"], - "An error occurred while setting the active tab. Please contact your administrator.": [ - "设置活动tab页时出错。请与管理员联系。" + "Defines a rolling window function to apply, works along with the [Periods] text box": [ + "定义要应用的滚动窗口函数,与 [期限] 文本框一起使用" ], - "An error occurred while fetching tab state": ["获取tab页状态时出错"], - "An error occurred while removing tab. Please contact your administrator.": [ - "删除tab页时出错。请与管理员联系。" + "Defines how each series is broken down": ["定义每个序列是如何被分解的"], + "Defines the grouping of entities. Each series is shown as a specific color on the chart and has a legend toggle": [ + "定义实体的分组。每个序列在图表上显示为特定颜色,并有一个可切换的图例" ], - "An error occurred while removing query. Please contact your administrator.": [ - "删除查询时出错。请与管理员联系。" + "Defines the origin where time buckets start, accepts natural dates as in `now`, `sunday` or `1970-01-01`": [ + "定义时间桶的起点,接受 `now`,`sunday` 或 `1970-01-01` 等格式的日期表达" ], - "An error occurred while setting the tab database ID. Please contact your administrator.": [ - "设置tab页数据库ID时出错。请与管理员联系。" + "Defines the size of the rolling window function, relative to the time granularity selected": [ + "定义滚动窗口函数的大小,相对于所选的时间粒度" ], - "An error occurred while setting the tab schema. Please contact your administrator.": [ - "设置tab页结构时出错。请与管理员联系。" + "Defines whether the step should appear at the beginning, middle or end between two data points": [ + "定义步骤应出现在两个数据点之间的开始、中间还是结束处" ], - "An error occurred while setting the tab autorun. Please contact your administrator.": [ - "设置tab页自动运行时出错。请与管理员联系。" + "Delete": ["删除"], + "Delete %s?": ["需要删除 %s 吗?"], + "Delete Annotation?": ["删除注释?"], + "Delete Database?": ["确定删除数据库?"], + "Delete Dataset?": ["确定删除数据集?"], + "Delete Layer?": ["确定删除图层?"], + "Delete Query?": ["确定删除查询?"], + "Delete Report?": ["删除报表?"], + "Delete Template?": ["删除模板?"], + "Delete all Really?": ["确定删除全部?"], + "Delete annotation": ["删除注释"], + "Delete dashboard tab?": ["是否删除仪表盘tab页?"], + "Delete database": ["删除数据库"], + "Delete email report": ["删除邮件报告"], + "Delete query": ["删除查询"], + "Delete template": ["删除模板"], + "Delete this container and save to remove this message.": [ + "删除此容器并保存以删除此邮件。" ], - "An error occurred while setting the tab title. Please contact your administrator.": [ - "设置tab页标题时出错。请与管理员联系。" + "Deleted %(num)d annotation": ["选择一个注释图层"], + "Deleted %(num)d annotation layer": ["选择一个注释图层"], + "Deleted %(num)d chart": ["删除了 %(num)d 个图表"], + "Deleted %(num)d css template": ["删除了 %(num)d 个css模板"], + "Deleted %(num)d dashboard": ["删除了 %(num)d 个看板"], + "Deleted %(num)d dataset": ["已经删除 %(num)d 个数据集"], + "Deleted %(num)d report schedule": ["已经删除了 %(num)d 个报告时间表"], + "Deleted %(num)d saved query": ["已经删除 %(num)d 个保存的查询"], + "Deleted: %s": ["已删除:%s"], + "Delimited long & lat single column": ["经度&纬度单列限定"], + "Delimiter": ["分隔符"], + "Delimiter used by CSV file (for whitespace use \\s+).": [ + "CSV文件使用的分隔符 (空白请使用 \\s+)" ], - "Your query was saved": ["您的查询已保存"], - "Your query could not be saved": ["您的查询无法保存"], - "Your query was updated": ["您的查询已保存"], - "Your query could not be updated": ["无法更新您的查询"], - "An error occurred while storing your query in the backend. To avoid losing your changes, please save your query using the \"Save Query\" button.": [ - "在后端存储查询时出错。为避免丢失更改,请使用 \"保存查询\" 按钮保存查询。" + "Deliver As Group": ["作为组交付"], + "Delivery Type": ["交付类型"], + "Delivery method": ["发送方式"], + "Demographics": ["人口统计"], + "Density": ["密度"], + "Deprecated": ["过时"], + "Description": ["描述"], + "Description (this can be seen in the list)": ["说明(见列表)"], + "Description Columns": ["列描述"], + "Description text that shows up below your Big Number": [ + "在大数字下面显示描述文本" ], - "An error occurred while setting the tab template parameters. Please contact your administrator.": [ - "设置tab页模板参数时出错。请与管理员联系。" + "Deselect all": ["反选所有"], + "Details of the certification": ["认证详情"], + "Determines how whiskers and outliers are calculated.": [ + "确定如何计算箱须和离群值。" ], - "An error occurred while fetching table metadata": [ - "获取表格元数据时发生错误" + "Determines whether or not this dashboard is visible in the list of all dashboards": [ + "确定此看板在所有看板列表中是否可见" ], - "An error occurred while fetching table metadata. Please contact your administrator.": [ - "获取表格元数据时发生错误。请与管理员联系。" + "Diamond": ["下钻"], + "Did you mean:": ["您的意思是:"], + "Difference": ["差异"], + "Directed Force Layout": ["有向图"], + "Directional": ["方向"], + "Disabled": ["禁用"], + "Discard changes": ["放弃更改"], + "Discrete": ["离散"], + "Display Name": ["显示名称"], + "Display column level total": ["显示列级别合计"], + "Display configuration": ["显示配置"], + "Display metrics side by side within each column, as opposed to each column being displayed side by side for each metric.": [ + "在每个列中并排显示指标,而不是每个指标并排显示每个列。" ], - "An error occurred while expanding the table schema. Please contact your administrator.": [ - "展开表结构时出错。请与管理员联系。" + "Display row level total": ["显示行级合计"], + "Display total row/column": ["显示总行 / 列"], + "Displays connections between entities in a graph structure. Useful for mapping relationships and showing which nodes are important in a network. Graph charts can be configured to be force-directed or circulate. If your data has a geospatial component, try the deck.gl Arc chart.": [ + "显示图形结构中实体之间的连接。用于映射关系和显示网络中哪些节点是重要的。图表可以配置为强制引导或循环。如果您的数据具有地理空间组件,请尝试使用deck.gl圆弧图表。" ], - "An error occurred while collapsing the table schema. Please contact your administrator.": [ - "收起表结构时出错。请与管理员联系。" + "Distribute across": ["基于某列进行分布"], + "Distribution": ["分布"], + "Distribution - Bar Chart": ["分布 - 柱状图"], + "Divider": ["分隔"], + "Do you want a donut or a pie?": ["是否用圆环圈替代饼图?"], + "Documentation": ["文档"], + "Domain": ["主域"], + "Don't refresh": ["不刷新"], + "Donut": ["圆环圈"], + "Download as image": ["下载为图片"], + "Download to CSV": ["下载到CSV"], + "Draft": ["草稿"], + "Draw a marker on data points. Only applicable for line types.": [ + "在数据点上绘制标记。仅适用于线型。" ], - "An error occurred while removing the table schema. Please contact your administrator.": [ - "删除表结构时出错。请与管理员联系。" + "Draw area under curves. Only applicable for line types.": [ + "在曲线下绘制区域。仅适用于线型。" ], - "Shared query": ["已分享的查询"], - "The datasource couldn't be loaded": ["这个查询无法被加载"], - "An error occurred while creating the data source": [ - "创建数据源时发生错误" + "Draw line from Pie to label when labels outside?": [ + "当标签在外侧时,是否在饼图到标签之间连线?" ], - "SQL Lab uses your browser's local storage to store queries and results.\n Currently, you are using ${currentUsage.toFixed(\n 2,\n )} KB out of ${LOCALSTORAGE_MAX_USAGE_KB} KB. storage space.\n To keep SQL Lab from crashing, please delete some query tabs.\n You can re-access these queries by using the Save feature before you delete the tab. Note that you will need to close other SQL Lab windows before you do this.": [ - "SQL Lab 使用浏览器的本地存储来存储查询和结果。\n目前,您正在使用${currentUsage.toFixed(\n 2,\n )} KB / ${LOCALSTORAGE_MAX_USAGE_KB} KB 的存储空间。\n为了防止SQLLab崩溃,请删除一些查询tab页。\n在删除tab页之前,可以使用 \"保存\" 功能重新访问这些查询。请注意,在执行此操作之前,需要关闭其他SQLLab窗口。" + "Draw split lines for minor y-axis ticks": ["绘制次要y轴记号的分割线"], + "Drop a column here or click": ["将列拖放到此处或单击"], + "Drop a column/metric here or click": ["将列/指标放在此处或单击"], + "Drop column here": ["将列拖放到此处"], + "Drop column or metric here": ["将列或指标放在此处"], + "Drop columns here": ["将列拖放到此处"], + "Drop columns or metrics here": ["将列或指标拖放到此处"], + "Drop columns/metrics here or click": ["将列/指标拖放到此处或单击"], + "Drop temporal column here": ["将时间列拖放到此处"], + "Druid Clusters": ["Druid 集群"], + "Druid Datasource": ["Druid 数据源"], + "Druid Datasources": ["Druid 数据源"], + "Druid supports basic authentication. See [auth](http://druid.io/docs/latest/design/auth.html) and druid-basic-security extension": [ + "Druid支持基本的身份验证。可以参考 [auth](http://druid.io/docs/latest/design/auth.html) 和 druid-basic-security 部分" ], - "Estimate selected query cost": ["运行选定的查询"], - "Estimate cost": ["运行选定的查询"], - "Cost estimate": ["成本估算"], - "Creating a data source and creating a new tab": [ - "创建数据源,并弹出一个新的标签页" + "Dual Line Chart": ["双线图"], + "Duplicate column name(s): %(columns)s": ["重复的列名%(columns)s"], + "Duplicate column/metric labels: %(labels)s. Please make sure all columns and metrics have a unique label.": [ + "重复的列/指标标签:%(labels)s。请确保所有列和指标都有唯一的标签。" ], - "An error occurred": ["发生了一个错误"], - "Explore the result set in the data exploration view": [ - "在数据探索视图中探索结果集" + "Duplicate tab": ["复制tab页"], + "Duration": ["持续时间"], + "Duration (in seconds) of the caching timeout for charts of this database. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.": [ + "此数据库图表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为全局超时。" ], - "Explore": ["探索"], - "This query took %s seconds to run, ": ["这个查询使用了 %s 秒去执行,"], - "and the explore view times out at %s seconds ": [ - ",浏览视图在 %s 秒超时" + "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the dataset's timeout if undefined.": [ + "此图表的缓存超时前的持续时间(秒)。请注意,如果未定义则默认为数据集的超时时间。" ], - "following this flow will most likely lead to your query timing out. ": [ - "遵循此流程很可能会导致查询超时。" + "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the datasource/table timeout if undefined.": [ + "此图表的缓存超时持续时间(以秒为单位)。注意,如果未定义,这默认为数据源/表超时。" ], - "We recommend your summarize your data further before following that flow. ": [ - "我们建议您在遵循流程之前进一步总结数据。" + "Duration (in seconds) of the caching timeout for this cluster. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.": [ + "此集群的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为全局超时。" ], - "If activated you can use the ": ["如果激活,您可以使用 "], - "feature to store a summarized data set that you can then explore.": [ - "用于存储可供浏览的汇总数据集的功能。" + "Duration (in seconds) of the caching timeout for this datasource. A timeout of 0 indicates that the cache never expires. Note this defaults to the cluster timeout if undefined.": [ + "此数据源的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为集群超时。" ], - "Column name(s) ": ["列名"], - "cannot be used as a column name. The column name/alias \"__timestamp\"\n is reserved for the main temporal expression, and column aliases ending with\n double underscores followed by a numeric value (e.g. \"my_col__1\") are reserved\n for deduplicating duplicate column names. Please use aliases to rename the\n invalid column names.": [ - "不能作为一个列名称使用。列名/别名 \"__timestamp\"\n 是为主要的时间表达式保留的,列别名以双下划线结尾\n 并后跟一个数值(例如 \"my_col__1\")。 这是为了\n 保留用于消除重复的列名。请使用别名来\n 重命名无效的列名。" + "Duration (in seconds) of the caching timeout for this table. A timeout of 0 indicates that the cache never expires. Note this defaults to the database timeout if undefined.": [ + "此表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为数据库的超时。" ], - "Raw SQL": ["行 SQL"], - "Source SQL": ["源 SQL"], - "SQL": ["SQL"], - "No query history yet...": ["暂无历史查询..."], - "It seems you don't have access to any database": [ - "貌似您没有访问到任何数据库" + "Duration (in seconds) of the metadata caching timeout for schemas of this database. If left unset, the cache never expires.": [ + "此数据库图表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为永不过期。" ], - "An error occurred when refreshing queries": ["创建数据源时发生错误"], - "Filter by user": ["过滤用户"], - "Filter by database": ["过滤数据库"], - "Query search string": ["查询搜索字符串"], - "[From]-": ["[从]-"], - "[To]-": ["[至]-"], - "Filter by status": ["过滤状态"], + "Duration (in seconds) of the metadata caching timeout for tables of this database. If left unset, the cache never expires. ": [ + "此数据库图表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,缓存为永不过期。" + ], + "Duration in ms (1.40008 => 1ms 400µs 80ns)": [ + "持续时间(毫秒)(1.40008 => 1ms 400µs 80ns)" + ], + "Duration in ms (66000 => 1m 6s)": ["持续时间(毫秒)(66000 => 1m 6s)"], + "Duration: %s": ["持续时间:%s"], + "ECharts": ["ECharts图表"], + "END (EXCLUSIVE)": ["结束"], + "ERROR: %s": ["错误: %s"], + "Edge length": ["边长"], + "Edge length between nodes": ["节点之间的边长"], + "Edge symbols": ["边符号"], + "Edge width": ["边缘宽度"], "Edit": ["编辑"], - "View results": ["展示结果"], - "Data preview": ["数据预览"], - "Overwrite text in the editor with a query on this table": [ - "使用该表上的查询覆盖编辑器中的文本" + "Edit Alert": ["编辑警报"], + "Edit Annotation": ["编辑注释"], + "Edit Annotation Layer": ["编辑注释层"], + "Edit CSS": ["编辑CSS"], + "Edit CSS Template": ["编辑CSS模板"], + "Edit CSS template properties": ["编辑CSS属性属性"], + "Edit Chart": ["编辑图表"], + "Edit Column": ["编辑列"], + "Edit Dashboard": ["编辑看板"], + "Edit Database": ["编辑数据库"], + "Edit Dataset ": ["编辑数据集"], + "Edit Druid Cluster": ["编辑 Druid 集群"], + "Edit Druid Column": ["编辑 Druid 列"], + "Edit Druid Datasource": ["编辑 Druid 数据源"], + "Edit Druid Metric": ["编辑 Druid 指标"], + "Edit Email Report": ["编辑邮件报告"], + "Edit Log": ["编辑日志"], + "Edit Metric": ["编辑指标"], + "Edit Plugin": ["编辑插件"], + "Edit Report": ["编辑报表"], + "Edit Row level security filter": ["编辑行级安全过滤"], + "Edit Saved Query": ["编辑保存的查询"], + "Edit Table": ["编辑表"], + "Edit annotation": ["编辑注释"], + "Edit annotation layer": ["添加注释层"], + "Edit annotation layer properties": ["编辑注释图层属性"], + "Edit chart properties": ["编辑图表属性"], + "Edit dashboard": ["编辑仪表盘"], + "Edit dashboard properties": ["编辑看板属性"], + "Edit database": ["编辑数据库"], + "Edit dataset": ["编辑数据集"], + "Edit email report": ["编辑邮件报告"], + "Edit formatter": ["日期格式化"], + "Edit properties": ["编辑属性"], + "Edit query": ["编辑查询"], + "Edit template": ["编辑模板"], + "Edit template parameters": ["编辑模板参数"], + "Edit time range": ["编辑时间范围"], + "Edited": ["已编辑"], + "Editing 1 filter:": ["编辑1个过滤条件:"], + "Editing filter set:": ["编辑过滤条件集合"], + "Either the database is spelled incorrectly or does not exist.": [ + "数据库拼写不正确或不存在。" ], - "Run query in a new tab": ["在新标签中运行查询"], - "Remove query from log": ["从日志中删除查询"], - "An error occurred saving dataset": ["保存数据集时发生错误"], - ".CSV": [".CSV"], - "Clipboard": ["复制到剪贴板"], - "Filter results": ["过滤结果"], - "Database error": ["数据库错误"], - "was created": ["已创建"], - "Query in a new tab": ["在新标签中查询"], - "The query returned no data": ["查询无结果"], - "Fetch data preview": ["获取数据预览"], - "Refetch results": ["重新获取结果"], - "Track job": ["跟踪任务"], - "Stop": ["停止"], - "Run selection": ["运行选定的查询"], - "Run": ["执行"], - "Stop running (Ctrl + x)": ["停止运行 (Ctrl + x)"], - "Stop running (Ctrl + e)": ["停止运行 (Ctrl + e)"], - "Run query (Ctrl + Return)": ["执行运行 (Ctrl + Return)"], - "Save & Explore": ["保存和浏览"], - "Overwrite & Explore": ["覆写和浏览"], - "Save or Overwrite Dataset": ["保存或覆盖数据集"], - "Save this query as a virtual dataset to continue exploring": [ - "将此查询另存为虚拟数据集以继续探索" + "Either the username \"%(username)s\" or the password is incorrect.": [ + "用户名\"%(username)s\"或密码不正确" ], - "Overwrite existing": ["覆盖已有"], - "Select or type dataset name": ["选择或者键入数据集名称"], - "Are you sure you want to overwrite this dataset?": [ - "您确定要覆盖此数据集吗?" + "Either the username \"%(username)s\", password, or database name \"%(database)s\" is incorrect.": [ + "用户名\"%(username)s\"、密码或数据库名称\"%(database)s\"不正确" ], - "Undefined": ["未命名"], - "Save": ["保存"], - "Save as": ["另存为"], - "Save query": ["保存查询"], - "Save as new": ["保存为新的"], - "Update": ["更新"], - "Label for your query": ["为您的查询设置标签"], - "Write a description for your query": ["为您的查询写一段描述"], - "Schedule query": ["分享查询"], - "Schedule": ["调度"], - "There was an error with your request": ["您的请求有错误"], - "Please save the query to enable sharing": ["请保存查询以启用共享"], - "Copy link": ["复制链接"], - "Copy query link to your clipboard": ["将查询链接复制到剪贴板"], - "Save the query to copy the link": ["保存查询以复制链接"], - "No stored results found, you need to re-run your query": [ - "找不到存储的结果,需要重新运行查询" + "Either the username or password is incorrect.": ["用户名或密码不正确。"], + "Either the username or the password is wrong.": ["用户名或密码错误。"], + "Email Format": ["电子邮件格式"], + "Email reports active": ["激活邮件报告"], + "Emit Target": ["发送目标"], + "Emit dashboard cross filters": ["发送仪表盘过滤"], + "Emit dashboard cross filters.": ["发送仪表盘过滤"], + "Emitted values": ["限制选择器值"], + "Emphasis": ["重点"], + "Employment and education": ["就业和教育"], + "Empty circle": ["空圈"], + "Empty collection": ["空集合"], + "Empty query?": ["查询为空?"], + "Enable Filter Select": ["启用过滤器选择"], + "Enable data zooming controls": ["启用数据缩放控件"], + "Enable forecast": ["启用预测"], + "Enable forecasting": ["启用预测中"], + "Enable graph roaming": ["启用图形漫游"], + "Enable node dragging": ["启用节点拖动"], + "Enable query cost estimation": ["启用查询成本估算"], + "Enable server side pagination of results (experimental feature)": [ + "支持服务器端结果分页(实验功能)" ], - "Run a query to display results here": ["运行一个查询,在此会显示结果"], - "Preview: `%s`": ["预览 %s"], - "Results": ["结果"], - "Query history": ["历史查询"], - "Run query": ["运行查询"], - "New tab": ["新Tab页"], - "Untitled query": ["未命名的查询"], - "Stop query": ["停止查询"], - "Schedule the query periodically": ["定期调度查询"], - "You must run the query successfully first": ["必须先成功运行查询"], - "It appears that the number of rows in the query results displayed\n was limited on the server side to\n the %s limit.": [ - "服务器端显示的查询结果中的行数似乎限制在 %s 以内。" + "Encountered invalid NULL spatial entry, please consider filtering those out": [ + "遇到无效的为 NULL 的空间条目,请考虑将其过滤掉" ], - "CREATE TABLE AS": ["允许 CREATE TABLE AS"], - "CREATE VIEW AS": ["允许 CREATE VIEW AS"], + "End": ["结束"], + "End Time": ["结束时间"], + "End angle": ["结束角度"], + "End date excluded from time range": ["从时间范围中排除的结束日期"], + "End date must be after start date": ["起始时间不可以大于当前时间"], + "Engine \"%(engine)s\" cannot be configured through parameters.": [ + "引擎 \"%(engine)s\" 不能通过参数配置。" + ], + "Engine \"%(engine)s\" is not a valid engine.": [ + "无效引擎\"%(engine)s\"" + ], + "Engine Parameters": ["引擎参数"], + "Engine spec \"InvalidEngine\" does not support being configured via individual parameters.": [ + "引擎\"InvalidEngine\"不支持通过单独的参数进行配置。" + ], + "Enter CA_BUNDLE": ["进入CA_BUNDLE"], + "Enter a name for this sheet": ["输入此工作表的名称"], + "Enter a new title for the tab": ["输入标签的新标题"], + "Enter duration in seconds": ["输入间隔时间(秒)"], + "Enter fullscreen": ["全屏"], + "Entity": ["实体"], + "Entity ID": ["实体ID"], + "Equal Date Sizes": ["相同的日期大小"], + "Error": ["错误"], + "Error Message": ["错误消息"], + "Error in jinja expression in HAVING clause: %(msg)s": [ + "jinja表达式中的HAVING子句出错:%(msg)s" + ], + "Error in jinja expression in RLS filters: %(msg)s": [ + "jinja表达式中的 RLS filters 出错:%(msg)s" + ], + "Error in jinja expression in WHERE clause: %(msg)s": [ + "jinja表达式中的WHERE子句出错:%(msg)s" + ], + "Error in jinja expression in fetch values predicate: %(msg)s": [ + "获取jinja表达式中的谓词的值出错:%(msg)s" + ], + "Error loading chart datasources. Filters may not work correctly.": [ + "加载图表数据源时出错。过滤器可能无法正常工作。" + ], + "Error message": ["错误信息"], + "Error while fetching charts": ["获取图表时出错"], + "Error while fetching data: %s": ["获取数据时出错:%s"], + "Error while rendering virtual dataset query: %(msg)s": [ + "保存查询时出错:%(msg)s" + ], + "Estimate cost": ["运行选定的查询"], + "Estimate selected query cost": ["运行选定的查询"], "Estimate the cost before running a query": [ "在运行查询之前计算执行计划" ], - "Reset state": ["状态重置"], - "Enter a new title for the tab": ["输入标签的新标题"], - "Untitled Query %s": ["未命名的查询 %s"], - "Close tab": ["关闭标签"], - "Rename tab": ["重命名标签"], - "Expand tool bar": ["展开工具栏"], - "Hide tool bar": ["隐藏工具栏"], - "Close all other tabs": ["关闭其他tab页"], - "Duplicate tab": ["复制tab页"], - "Copy partition query to clipboard": ["将分区查询复制到剪贴板"], - "latest partition:": ["最新分区:"], - "Keys for table": ["表的键"], - "View keys & indexes (%s)": ["查看键和索引(%s)"], - "Sort columns alphabetically": ["对列按字母顺序进行排列"], - "Original table column order": ["原始表列顺序"], - "Copy SELECT statement to the clipboard": ["将 SELECT 语句复制到剪贴板"], - "Show CREATE VIEW statement": ["显示 CREATE VIEW 语句"], - "CREATE VIEW statement": ["CREATE VIEW 语句"], - "Remove table preview": ["删除表格预览"], - "Assign a set of parameters as": ["将一组参数指定为"], - "below (example:": ["以下(例如:"], - "), and they become available in your SQL (example:": [ - "),通过使用(例如:" + "Event Flow": ["事件流"], + "Event Names": ["事件名称"], + "Event definition": ["事件定义"], + "Event flow": ["事件流"], + "Event time column": ["事件时间列"], + "Every": ["每个"], + "Evolution": ["演化"], + "Exact": ["精确"], + "Example": ["例子"], + "Example %(tableName)s will appear here": [ + "示例 %(tableName)s 将出现在此处" ], - ") by using": [") 让它在SQL中可用"], - "Edit template parameters": ["编辑模板参数"], - "Invalid JSON": ["无效的JSON"], - "Create a new chart": ["创建新图表"], - "Choose a dataset": ["选择数据源"], - "If the dataset you are looking for is not available in the list, follow the instructions on how to add it in the Superset tutorial.": [ - "如果您正在寻找的数据源在列表中不可用,请按照说明进行添加" + "Examples": ["示例"], + "Excel File": ["Excel文件"], + "Excel file \"%(excel_filename)s\" uploaded to table \"%(table_name)s\" in database \"%(db_name)s\"": [ + "Excel 文件 \"%(excel_filename)s\" 上传到数据库 \"%(db_name)s\" 中的表 \"%(table_name)s\"" ], - "Choose a visualization type": ["选择可视化类型"], - "Create new chart": ["创建新图表"], - "An error occurred while loading the SQL": ["创建数据源时发生错误"], - "Updating chart was stopped": ["更新图表已停止"], - "An error occurred while rendering the visualization: %s": [ - "渲染可视化时发生错误:%s" + "Excel to Database configuration": ["Excel 到数据库配置"], + "Exclude selected values": ["排除选定的值"], + "Executed SQL": ["已执行的SQL"], + "Executed query": ["已执行查询"], + "Execution ID": ["任务ID"], + "Execution log": ["操作日志"], + "Exit fullscreen": ["退出全屏"], + "Expand all": ["全部展开"], + "Expand table preview": ["展开表格预览"], + "Expand tool bar": ["展开工具栏"], + "Experimental": ["实验"], + "Explore": ["探索"], + "Explore - %(table)s": ["查看 - %(table)s"], + "Explore in Superset": ["探索"], + "Explore the result set in the data exploration view": [ + "在数据探索视图中探索结果集" ], - "Network error.": ["网络异常。"], - "every": ["任意"], - "every month": ["每个月"], - "every day of the month": ["每月的每一天"], - "day of the month": ["一个月中的天数"], - "every day of the week": ["一周的每一天"], - "day of the week": ["一周的天数"], - "every hour": ["每小时"], - "every minute UTC": ["每分钟 UTC"], - "year": ["年"], - "month": ["月"], - "week": ["周"], - "day": ["天"], - "hour": ["小时"], - "minute": ["分"], - "reboot": ["重启"], - "Every": ["每"], - "in": [""], - "on": [""], - "and": [""], - "at": [""], - ":": [""], - "minute(s) UTC": ["分钟 UTC"], - "Invalid cron expression": ["cron表达式无效"], - "Clear": ["清除"], - "Sunday": ["星期日"], - "Monday": ["星期一"], - "Tuesday": ["星期二"], - "Wednesday": ["星期三"], - "Thursday": ["星期四"], - "Friday": ["星期五"], - "Saturday": ["星期六"], - "January": ["一月"], - "February": ["二月"], - "March": ["三月"], - "April": ["四月"], - "May": ["五月"], - "June": ["六月"], - "July": ["七月"], - "August": ["八月"], - "September": ["九月"], - "October": ["十月"], - "November": ["十一月"], - "December": ["十二月"], - "SUN": ["星期日"], - "MON": ["星期一"], - "TUE": ["星期二"], - "WED": ["星期三"], - "THU": ["星期四"], + "Export": ["导出"], + "Export CSV": ["导出 CSV"], + "Export dashboards?": ["导出看板?"], + "Export full CSV": ["导出全量CSV"], + "Export query": ["导出查询"], + "Export to .CSV format": ["导出为CSV格式"], + "Export to .JSON format": ["导出为JSON格式"], + "Export to YAML": ["导出到YAML格式"], + "Export to YAML?": ["导出到YAML?"], + "Expose database in SQL Lab": ["在SQL工具箱中展示数据库"], + "Expose in SQL Lab": ["在 SQL 工具箱中公开"], + "Expose this DB in SQL Lab": ["在 SQL 工具箱中公开这个数据库"], + "Expression": ["表达式"], + "Extra": ["扩展"], + "Extra Controls": ["额外控件"], + "Extra Parameters": ["额外参数"], + "Extra data to specify table metadata. Currently supports metadata of the format: `{ \"certification\": { \"certified_by\": \"Data Platform Team\", \"details\": \"This table is the source of truth.\" }, \"warning_markdown\": \"This is a warning.\" }`.": [ + "指定表元数据的额外内容。目前支持的认证数据格式为:`{ \"certification\": { \"certified_by\": \"Data Platform Team\", \"details\": \"This table is the source of truth.\" } }`." + ], + "Extra field cannot be decoded by JSON. %(msg)s": [ + "JSON无法解码额外字段。%(msg)s" + ], + "Extra parameters for use in jinja templated queries": [ + "用于jinja模板化查询的额外参数" + ], + "Extra parameters that any plugins can choose to set for use in Jinja templated queries": [ + "用于jinja模板化查询的额外参数" + ], + "Extra url parameters for use in Jinja templated queries": [ + "用于jinja模板化查询的额外url" + ], + "FEB": ["二月"], "FRI": ["星期五"], - "SAT": ["星期六"], + "Factor": ["因素"], + "Fail": ["失败"], + "Failed": ["失败"], + "Failed at retrieving results": ["检索结果失败"], + "Failed at stopping query. %s": ["停止查询失败。 %s"], + "Failed to start remote query on a worker.": ["无法启动远程查询"], + "Failed to verify select options: %s": ["验证选择选项失败:%s"], + "Favorite": ["收藏"], + "Favorites": ["收藏"], + "February": ["二月"], + "Fetch Values From": ["取值谓词"], + "Fetch Values Predicate": ["取值谓词"], + "Fetch data preview": ["获取数据预览"], + "Fetched %s": ["刷新于 %s"], + "Field cannot be decoded by JSON. %(json_error)s": [ + "字段不能由JSON解码。%{json_error}s" + ], + "Field cannot be decoded by JSON. %(msg)s": [ + "字段不能由JSON解码。%(msg)s" + ], + "Field is required": ["字段是必需的"], + "File": ["文件"], + "Fill all required fields to enable \"Default Value\"": [ + "填写所有必填字段以启用默认值" + ], + "Fill method": ["填充方式"], + "Filter": ["过滤器"], + "Filter List": ["过滤"], + "Filter Type": ["过滤类型"], + "Filter box": ["过滤器"], + "Filter by database": ["过滤数据库"], + "Filter by status": ["过滤状态"], + "Filter by user": ["过滤用户"], + "Filter configuration": ["过滤配置"], + "Filter configuration for the filter box": ["过滤条件的过滤配置"], + "Filter has default value": ["过滤器默认值"], + "Filter is hierarchical": ["分层过滤"], + "Filter metadata changed in dashboard. It will not be applied.": [ + "仪表盘的过滤器已被更改,将不会被应用" + ], + "Filter name": ["过滤值"], + "Filter results": ["过滤结果"], + "Filter set already exists": ["过滤器已存在"], + "Filter set with this name already exists": ["过滤器已存在"], + "Filter sets (%(filterSetCount)d)": ["过滤器个数(%(filterSetCount)d)"], + "Filter type": ["过滤类型"], + "Filter value (case sensitive)": ["过滤值(区分大小写)"], + "Filter value list cannot be empty": ["不能为空"], + "Filter your charts": ["过滤您的图表"], + "Filterable": ["可过滤"], + "Filters": ["过滤"], + "Filters (%d)": ["过滤 (%d)"], + "Filters by columns": ["按列过滤"], + "Filters by metrics": ["按指标过滤"], + "Filters configuration": ["过滤配置"], + "Filters configuration and scoping": ["过滤配置和作用域"], + "Filters out of scope (%d)": ["筛选器超出范围(%d)"], + "Filters with the same group key will be ORed together within the group, while different filter groups will be ANDed together. Undefined group keys are treated as unique groups, i.e. are not grouped together. For example, if a table has three filters, of which two are for departments Finance and Marketing (group key = 'department'), and one refers to the region Europe (group key = 'region'), the filter clause would apply the filter (department = 'Finance' OR department = 'Marketing') AND (region = 'Europe').": [ + "具有相同组key的过滤将在组中一起进行\"OR\"运算,而不同的过滤组将一起进行\"AND\"运算。未定义的组的key被视为唯一组,即不分组在一起。例如,如果表有三个过滤,其中两个用于财务部门和市场营销 (group key = 'department'),其中一个表示欧洲地区(group key = 'region'),filter子句将应用过滤 (department = 'Finance' OR department = 'Marketing') 和 (region = 'Europe')" + ], + "Finish": ["完成"], + "Fix the trend line to the full time range specified in case filtered results do not include the start or end dates": [ + "将趋势线固定为指定的完整时间范围,以防过滤的结果不包括开始日期或结束日期" + ], + "Fix to selected Time Range": ["固定到选定的时间范围"], + "Fixed": ["固定值"], + "Fixed Color": ["固定颜色"], + "Fixed color": ["固定颜色"], + "Flow": ["流图"], + "Font size": ["字体大小"], + "Font size for axis labels, detail value and other text elements": [ + "轴标签、详图值和其他文本元素的字体大小" + ], + "Font size for the biggest value in the list": ["列表中最大值的字体大小"], + "Font size for the smallest value in the list": [ + "列表中最小值的字体大小" + ], + "For Presto and Postgres, shows a button to compute cost before running a query.": [ + "对于Presto和Postgres,显示计算成本按钮(查询后)" + ], + "For regular filters, these are the roles this filter will be applied to. For base filters, these are the roles that the filter DOES NOT apply to, e.g. Admin if admin should see all data.": [ + "对于常规过滤,这些是此过滤将应用于的角色。对于基本过滤,这些是过滤不适用的角色,例如Admin代表admin应该查看所有数据。" + ], + "Force": ["强制"], + "Force all tables and views to be created in this schema when clicking CTAS or CVAS in SQL Lab.": [ + "在SQL工具箱中点击CTAS or CVAS强制创建所有数据表或视图" + ], + "Force refresh": ["强制刷新"], + "Force refresh schema list": ["强制刷新数据"], + "Force refresh table list": ["强制刷新数据"], + "Force-directed Graph": ["力导向图"], + "Forecast periods": ["预测期"], + "Formattable": ["格式表"], + "Formatted CSV attached in email": ["在邮件中附件CSV"], + "Found invalid orderby options": ["发现无效的orderby选项"], + "Fraction digits": ["分数位"], + "Frequency": ["频率"], + "Friction": ["摩擦"], + "Friction between nodes": ["节点之间的摩擦"], + "Friday": ["星期五"], + "From date cannot be larger than to date": ["起始时间不可以大于当前时间"], + "Funnel Chart": ["漏斗图"], + "Further customize how to display each column": [ + "进一步自定义如何显示每列" + ], + "Further customize how to display each metric": [ + "进一步定制如何显示每个指标" + ], + "Gauge Chart": ["仪表图"], + "General": ["一般"], + "Geo": ["地理位置"], + "Geohash": ["Geo哈希"], + "Get the last date by the date unit.": ["按日期单位获取最后的日期。"], + "Get the specify date for the holiday": ["获取指定节假日的日期"], + "Google Sheet Name and URL": ["Google Sheet名称和URL"], + "Grace period": ["宽限期"], + "Graph Chart": ["圆点图"], + "Graph layout": ["图表布局"], + "Gravity": ["重力"], + "Group By": ["分组"], + "Group By filter plugin": ["分组过滤插件"], + "Group By' and 'Columns' can't overlap": ["“Group by”列和字段不能重叠"], + "Group By, Metrics or Percentage Metrics must have a value": [ + "分组、指标或百分比指标必须具有值" + ], + "Group by": ["分组"], + "Groupable": ["可分组"], + "Hard value bounds applied for color coding. Is only relevant and applied when the normalization is applied against the whole heatmap.": [ + "应用于颜色编码的硬值边界。只有当对整个热图应用标准化时才是相关的和应用的。" + ], + "Header": ["标题行"], + "Header Row": ["标题行"], + "Heatmap": ["热力图"], + "Heatmap Options": ["热图选项"], + "Height": ["高度"], + "Hide layer": ["隐藏Layer"], + "Hide tool bar": ["隐藏工具栏"], + "Hierarchy": ["层次"], + "Histogram": ["直方图"], + "Home": ["主页"], + "Horizon Chart": ["地平线图"], + "Horizon Charts": ["水平图"], + "Horizontal alignment": ["水平对齐"], + "Host": ["主机"], + "Hostname or IP address": ["主机名或IP"], + "Hour": ["小时"], + "Hours %s": ["%s小时"], + "Hours offset": ["小时偏移"], + "How do you want to enter service account credentials?": [ + "您希望如何输入服务帐户凭据?" + ], + "How long to keep the logs around for this alert": [ + "这个警报的日志要保存多久" + ], + "How many periods into the future do we want to predict": [ + "想要预测未来的多少个时期" + ], + "How to display time shifts: as individual lines; as the difference between the main time series and each time shift; as the percentage change; or as the ratio between series and time shifts.": [ + "如何显示时间偏移:作为单独的行显示;作为主时间序列与每次时间偏移之间的绝对差显示;作为百分比变化显示;或作为序列与时间偏移之间的比率显示。" + ], + "Huge": ["巨大"], + "ISO 3166-2 Codes": ["ISO 3166-2 代码"], + "ISO 8601": ["ISO 8601"], + "Id": ["Id"], + "Id of root node of the tree.": ["树的根节点的ID。"], + "If Presto or Trino, all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them. If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.": [ + "如果使用Presto,SQL 工具箱中的所有查询都将被当前登录的用户执行,并且这些用户必须拥有运行它们的权限。如果启用 Hive 和 hive.server2.enable.doAs,将作为服务帐户运行查询,但会根据 hive.server2.proxy.user 的属性伪装当前登录用户。" + ], + "If Presto, all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them.<br/>If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.": [ + "如果使用Presto,SQL 工具箱中的所有查询都将被当前登录的用户执行,并且这些用户必须拥有运行它们的权限。<br/>如果启用 Hive 和hive.server2.enable.doAs,将作为服务帐户运行查询,但会根据hive.server2.proxy.user的属性伪装当前登录用户。" + ], + "If a metric is specified, sorting will be done based on the metric value": [ + "如果指定了度量,则将根据该度量值进行排序" + ], + "If activated you can use the ": ["如果激活,您可以使用 "], + "If selected, please set the schemas allowed for csv upload in Extra.": [ + "如果选择,请额外设置csv上传允许的模式。" + ], + "If selected, please set the schemas allowed for data upload in Extra.": [ + "如果选中,请额外设置允许数据上传的schema。" + ], + "If table exists do one of the following: Fail (do nothing), Replace (drop and recreate table) or Append (insert data).": [ + "如果表已存在,执行其中一个:舍弃(什么都不做),替换(删除表并重建),或者追加(插入数据)" + ], + "If you wish to specify a different target column than the original column, it can be entered here": [ + "如果要指定与原始列不同的目标列,可以在此处输入" + ], + "Ignore time": ["忽略时间"], + "Image (PNG) embedded in email": ["使用邮箱发送图片(PNG)"], + "Image download failed, please refresh and try again.": [ + "图片发送失败,请刷新或重试" + ], + "Impersonate logged in user (Presto, Trino, Drill, Hive, and GSheets)": [ + "模拟登录用户 (Presto, Trino, Drill & Hive)" + ], + "Impersonate the logged on user": ["模拟登录用户"], + "Import": ["导入"], + "Import %s": ["导入 %s"], + "Import Dashboard(s)": ["导入看板"], + "Import Dashboards": ["导入看板"], + "Import a table definition": ["导入一个已定义的表"], + "Import chart failed for an unknown reason": ["导入图表失败,原因未知"], + "Import charts": ["导入图表"], + "Import dashboard failed for an unknown reason": [ + "因为未知原因导入看板失败" + ], + "Import dashboards": ["导入看板"], + "Import database failed for an unknown reason": [ + "导入数据库失败,原因未知" + ], + "Import databases": ["导入数据集"], + "Import dataset failed for an unknown reason": [ + "因为未知的原因导入数据集失败" + ], + "Import datasets": ["导入数据集"], + "Import queries": ["导入查询"], + "Import saved query failed for an unknown reason.": [ + "由于未知原因,导入保存的查询失败。" + ], + "Important! Select this if the table is not already sorted by entity id, else there is no guarantee that all events for each entity are returned.": [ + "很重要!如果表尚未按实体ID排序,则选择此项,否则无法保证返回每个实体的所有事件。" + ], + "Include Series": ["包含系列"], + "Include series name as an axis": ["包括系列名称作为轴"], + "Include time": ["包含时间"], + "Incompatible Filters (%d)": ["不兼容的条件 (%d)"], + "Incorrect Fields": ["不正确的字段"], + "Index Column": ["索引字段"], + "Infer Datetime Format": ["日期时间格式"], + "Info": ["信息"], + "Inner Radius": ["内半径"], + "Inner radius of donut hole": ["圆环圈内部空洞的内径"], + "Input field supports custom rotation. e.g. 30 for 30°": [ + "输入字段支持自定义。例如,30代表30°" + ], + "Instant filtering": ["即时过滤"], + "Instructions to add a dataset are available in the Superset tutorial.": [ + "有关添加数据集的说明,请参阅教程。" + ], + "Intensity": ["强度"], + "Interval End column": ["间隔结束列"], + "Interval bounds": ["区间间隔"], + "Interval colors": ["间隔颜色"], + "Interval start column": ["间隔开始列"], + "Intervals": ["间隔"], + "Invalid JSON": ["无效的JSON"], + "Invalid Port Number": ["无效端口号"], + "Invalid account information": ["无效账户信息"], + "Invalid certificate": ["无效认证"], + "Invalid connection string, a valid string usually follows:\n'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'": [ + "连接字符串无效,有效字符串的格式通常如下:\n'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'" + ], + "Invalid connection string, a valid string usually follows: driver://user:password@database-host/database-name": [ + "连接字符串无效,有效字符串通常如下:driver://user:password@database-host/database-name" + ], + "Invalid connection string, a valid string usually follows:'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'<p>Example:'postgresql://user:password@your-postgres-db/database'</p>": [ + "连接字符串无效,有效字符串格式通常如下:'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'<p>例如:'postgresql://user:password@your-postgres-db/database'</p>" + ], + "Invalid cron expression": ["无效cron表达式"], + "Invalid cumulative operator: %(operator)s": [ + "累积运算符无效:%(operator)s" + ], + "Invalid date/timestamp format": ["无效的日期/时间戳格式"], + "Invalid filter configuration, please select a column": [ + "过滤器配置无效,请选择一个列" + ], + "Invalid filter operation type: %(op)s": ["选择框的操作类型无效: %(op)s"], + "Invalid geodetic string": ["无效的 geodetic 字符串"], + "Invalid geohash string": ["无效的geohash字符串"], + "Invalid lat/long configuration.": ["错误的经纬度配置。"], + "Invalid longitude/latitude": ["无效的经度/纬度"], + "Invalid metric object": ["无效的指标对象"], + "Invalid numpy function: %(operator)s": ["无效的numpy函数:%(operator)s"], + "Invalid options for %(rolling_type)s: %(options)s": [ + "%(rolling_type)s 的选项无效:%(options)s" + ], + "Invalid result type: %(result_type)s": [ + "无效的结果类型:%(result_type)s" + ], + "Invalid rolling_type: %(type)s": ["无效的滚动类型:%(type)s"], + "Invalid spatial point encountered: %s": ["遇到无效的空间点:%s"], + "Inverse selection": ["反选"], + "Is Hidden": ["隐藏"], + "Is certified": ["已认证"], + "Is dimension": ["维度"], + "Is favorite": ["收藏"], + "Is filterable": ["可被过滤"], + "Is temporal": ["时间条件"], + "Issue 1000 - The dataset is too large to query.": [ + "Issue 1000 - 数据集太大,无法进行查询。" + ], + "Issue 1001 - The database is under an unusual load.": [ + "Issue 1001 - 数据库负载异常。" + ], + "It seems you don't have access to any database": [ + "貌似您没有访问到任何数据库" + ], + "It’s not recommended to truncate y-axis in Bar chart.": [ + "不建议截断柱状图中的y轴。" + ], "JAN": ["一月"], - "FEB": ["二月"], - "MAR": ["三月"], - "APR": ["四月"], - "MAY": ["五月"], - "JUN": ["六月"], + "JSON": ["JSON"], + "JSON Metadata": ["JSON 元数据"], + "JSON metadata": ["JSON 元数据"], + "JSON string containing additional connection configuration. This is used to provide connection information for systems like Hive, Presto and BigQuery which do not conform to the username:password syntax normally used by SQLAlchemy.": [ + "包含附加连接配置的JSON字符串。它用于为配置单元、Presto和BigQuery等系统提供连接信息,这些系统不符合SQLAlChemy通常使用的用户名:密码语法。" + ], "JUL": ["七月"], - "AUG": ["八月"], - "SEP": ["九月"], - "OCT": ["十月"], - "NOV": ["十一月"], - "DEC": ["十二月"], - "OK": ["确认"], - "Click to see difference": ["点击查看差异"], - "Altered": ["已更改"], - "Chart changes": ["图表变化"], - "Superset chart": ["选择图表"], - "Check out this chart in dashboard:": ["查看这个看板:%s"], + "JUN": ["六月"], + "January": ["一月"], + "Json list of the column names that should be read. If not None, only these columns will be read from the file.": [ + "Json应读取的列名列表。如果不是“无”,则仅从文件中读取这些列" + ], + "Json list of the values that should be treated as null. Examples: [\"\"], [\"None\", \"N/A\"], [\"nan\", \"null\"]. Warning: Hive database supports only single value. Use [\"\"] for empty string.": [ + "应视为null的值的Json列表。例如:[\"\"], [\"None\", \"N/A\"], [\"nan\", \"null\"]。警告:Hive数据库仅支持单个值。用 [\"\"] 代表空字符串。" + ], + "July": ["七月"], + "June": ["六月"], + "KPI": ["指标"], + "Keep editing": ["继续编辑"], + "Keys for table": ["表的键"], + "Label": ["标签"], + "Label Line": ["标签线"], + "Label Type": ["标签类型"], + "Label for your query": ["为您的查询设置标签"], + "Label position": ["标签位置"], + "Label threshold": ["标签阈值"], + "Labelling": ["标签"], + "Labels": ["标签"], + "Labels for the marker lines": ["标记线的标签"], + "Labels for the markers": ["标记的标签"], + "Labels for the ranges": ["范围的标签"], + "Large": ["大"], + "Last": ["上一"], + "Last Changed": ["更新时间"], + "Last Modified": ["最后修改"], + "Last Updated %s": ["上次更新 %s"], + "Last available value seen on %s": [" %s 最后一个可用值"], + "Last modified": ["最后修改"], + "Last modified by %s": ["上次修改人 %s"], + "Last run": ["上次执行"], + "Latitude": ["纬度"], + "Latitude of default viewport": ["默认视口纬度"], + "Layer": ["层"], + "Layer configuration": ["配置Layer"], + "Layout": ["布局"], + "Layout type of graph": ["图形的布局类型"], + "Layout type of tree": ["树的布局类型"], + "Leaf nodes that represent fewer than this number of events will be initially hidden in the visualization": [ + "表示少于此数量的事件的叶节点最初将隐藏在可视化中" + ], + "Least recently modified": ["最远修改"], + "Left": ["左边"], + "Left Axis Format": ["左轴格式化"], + "Left Axis Metric": ["左轴指标"], + "Left Axis chart(s)": ["左轴图表"], + "Left Margin": ["左边距"], + "Left margin, in pixels, allowing for more room for axis labels": [ + "左边距,以像素为单位,为轴标签留出更多空间" + ], + "Left to Right": ["从左到右"], + "Left value": ["左值"], + "Legacy": ["遗产"], + "Legend": ["图示"], + "Legend type": ["图示类型"], + "Lift percent precision": ["提升百分比精度"], + "Light mode": ["光模式"], + "Limit reached": ["达到限制"], + "Limit selector values": ["限制选择器值"], + "Limiting rows may result in incomplete data and misleading charts. Consider filtering or grouping source/target names instead.": [ + "限制行数可能导致不完整的数据和误导性的图表。可以考虑过滤或分组源/目标名称。" + ], + "Limits the number of rows that get displayed.": ["限制显示的行数。"], + "Limits the number of series that get displayed. A joined subquery (or an extra phase where subqueries are not supported) is applied to limit the number of series that get fetched and rendered. This feature is useful when grouping by high cardinality column(s) though does increase the query complexity and cost.": [ + "限制显示的系列数。应用联接的子查询(或不支持子查询的额外阶段)来限制获取和呈现的序列数量。此功能在按高基数列分组时很有用,但会增加查询的复杂性和成本。" + ], + "Line": ["行"], + "Line Chart": ["多线图"], + "Line Style": ["线条样式"], + "Line interpolation as defined by d3.js": ["由 d3.js 定义的线插值"], + "Line width": ["线宽"], + "Linear Color Scheme": ["线性颜色方案"], + "Linear color scheme": ["线性颜色方案"], + "Link Copied!": ["链接成功!"], + "Link Length": ["连接长度"], + "Link length in the force layout": ["在力布局中的连接长度"], + "List Observations": ["观察结果列表"], + "List Saved Query": ["保存的查询列表"], + "List of values to mark with lines": ["要用行标记的值列表"], + "List of values to mark with triangles": ["要用三角形标记的值列表"], + "Live CSS editor": ["即时 CSS 编辑器"], + "Live render": ["实时渲染"], + "Load a CSS template": ["加载一个 CSS 模板"], + "Loaded data cached": ["数据缓存已加载"], + "Loaded from cache": ["从缓存中加载"], + "Loading...": ["加载中..."], + "Log Retentions (days)": ["日志保留(天)"], + "Log Scale": ["日志规模"], + "Log retention": ["日志保留"], + "Logarithmic scale on primary y-axis": ["对数刻度在主y轴上"], + "Logarithmic scale on secondary y-axis": ["二次y轴上的对数刻度"], + "Logarithmic y-axis": ["对数轴"], + "Login": ["登录"], + "Logout": ["退出"], + "Logs": ["日志"], + "Longitude": ["经度"], + "Longitude & Latitude columns": ["经纬度字段"], + "Longitude of default viewport": ["默认视口经度"], + "MAR": ["三月"], + "MAY": ["五月"], + "MON": ["星期一"], + "Main Datetime Column": ["主日期列"], + "Malformed request. slice_id or table_name and db_name arguments are expected": [ + "格式错误的请求。需要使用 slice_id 或 table_name 和 db_name 参数" + ], + "Manage": ["管理"], + "Manage Email Reports for Charts": ["管理图表的电子邮件报告"], + "Manage Email Reports for Dashboards": ["管理看板的电子邮件报告"], + "Mandatory": ["必填参数"], + "Mangle Duplicate Columns": ["混合重复列"], + "Map": ["地图"], + "Map Style": ["地图样式"], + "MapBox": ["MapBox地图"], + "Mapbox": ["箱图"], + "March": ["三月"], + "Margin": ["边距(margin)"], + "Marker": ["标记"], + "Marker Size": ["标记大小"], + "Marker labels": ["标记标签"], + "Marker line labels": ["标记线标签"], + "Marker lines": ["标记线"], + "Marker size": ["标记大小"], + "Markers": ["标记"], + "Markup type": ["Markup 类型"], + "Max": ["最大值"], + "Max Bubble Size": ["最大气泡的尺寸"], + "Max Events": ["最大事件数"], + "Maximize chart": ["最大化图表"], + "Maximum": ["最大"], + "Maximum Font Size": ["最大字体大小"], + "Maximum value on the gauge axis": ["量规轴上的最大值"], + "May": ["五月"], + "Mean of values over specified period": ["特定时期内的平均值"], + "Median edge width, the thickest edge will be 4 times thicker than the thinnest.": [ + "边缘宽度中间值,最厚的边缘将比最薄的边缘厚4倍" + ], + "Median node size, the largest node will be 4 times larger than the smallest": [ + "节点大小中位数,最大的节点将比最小的节点大4倍" + ], + "Medium": ["中"], + "Message Content": ["消息内容"], + "Message content": ["消息内容"], + "Metadata": ["元数据"], + "Metadata Last Refreshed": ["上次刷新的元数据"], + "Metadata Parameters": ["元数据参数"], + "Metadata has been synced": ["元数据已同步"], + "Metadata refreshed for the following table(s): %(tables)s": [ + "为下表刷新元数据:%(tables)s" + ], + "Method": ["方法"], + "Metric": ["指标"], + "Metric '%(metric)s' does not exist": ["指标 '%(metric)s' 不存在"], + "Metric ascending": ["指标升序"], + "Metric assigned to the [X] axis": ["分配给 [X] 轴的指标"], + "Metric assigned to the [Y] axis": ["分配给 [Y] 轴的指标"], + "Metric change in value from `since` to `until`": [ + "从 `since` 到 `until` 的度量值变化" + ], + "Metric descending": ["指标降序"], + "Metric factor change from `since` to `until`": [ + "度量因子从 `since` 到 `until` 的变化" + ], + "Metric for Color": ["颜色指标"], + "Metric for node values": ["节点值的度量"], + "Metric name [%s] is duplicated": ["指标名称 [%s] 重复"], + "Metric percent change in value from `since` to `until`": [ + "从 `since` 到 `until` 的价值变化百分比" + ], + "Metric that defines the color of the country": ["定义国家度量的颜色"], + "Metric that defines the size of the bubble": ["定义指标的气泡大小"], + "Metric to display bottom title": ["显示底部标题的度量值"], + "Metric to sort the results by": ["按照指标的结果进行排序"], + "Metric used to calculate bubble size": ["用来计算气泡大小的公制"], + "Metric used to define how the top series are sorted if a series or row limit is present. If undefined reverts to the first metric (where appropriate).": [ + "如果存在序列或行限制,则用于定义顶部序列的排序方式的度量。如果未定义,则返回第一个度量(如果适用)。" + ], + "Metric(s) {} must be aggregations.": ["度量(s) {} 必须是聚合。"], + "Metrics": ["指标"], + "Metrics for which percentage of total are to be displayed. Calculated from only data within the row limit.": [ + "要显示其占总数百分比的指标。只计算行限制内的只读存储器数据。" + ], + "Midnight": ["凌晨(当天)"], + "Min": ["最小值"], + "Min Periods": ["最小周期"], + "Min Width": ["最小宽度"], + "Min periods": ["最小周期"], + "Mine": ["我的编辑"], + "Minimize chart": ["最小化图表"], + "Minimum": ["最小"], + "Minimum Font Size": ["最小字体大小"], + "Minimum leaf node event count": ["节点最小事件数"], + "Minimum threshold in percentage points for showing labels.": [ + "标签显示百分比最小阈值" + ], + "Minimum value for label to be displayed on graph.": [ + "在图形上显示标签的最小值。" + ], + "Minimum value on the gauge axis": ["量规轴上的最小值"], + "Minor Split Line": ["小的分模线"], + "Minute": ["分钟"], + "Minutes %s": ["%s分钟"], + "Missing Required Fields": ["缺少必填字段"], + "Missing dataset": ["丢失数据集"], + "Mixed Time-Series": ["混和时间序列"], + "Modified": ["已修改"], + "Modified %s": ["最后修改 %s"], + "Modified by": ["修改人"], + "Modified columns: %s": ["修改的列:%s"], + "Monday": ["星期一"], + "Month": ["月"], + "Months %s": ["%s月"], + "More dataset related options": ["更多数据集相关选项"], + "Move only": ["移动"], + "Moves the given set of dates by a specified interval.": [ + "将给定的日期集以指定的间隔进行移动" + ], + "Multi-Dimensions": ["多维度"], + "Multi-Layers": ["多层"], + "Multi-Levels": ["多层次"], + "Multi-Variables": ["多元"], + "Multiple": ["多方"], + "Multiple Line Charts": ["复合折线图"], + "Multiple file extensions are not allowed for columnar uploads. Please make sure all files are of the same extension.": [ + "柱状上传不允许使用多个文件扩展名请确保所有文件的扩展名相同。" + ], + "Multiple formats accepted, look the geopy.points Python library for more details": [ + "接受多种格式,查看geopy.points库以获取更多细节" + ], + "Multiple select": ["多选"], + "Multiple selections allowed, otherwise filter is limited to a single value": [ + "允许多选下拉框,不勾选的话过滤器就是单选下拉框" + ], + "Must be unique": ["需要唯一"], + "Must have a [Group By] column to have 'count' as the [Label]": [ + "[Group By] 列必须要有 ‘count’字段作为 [标签]" + ], + "Must have at least one numeric column specified": [ + "必须至少指明一个数值列" + ], + "Must specify a value for filters with comparison operators": [ + "必须为带有比较操作符的过滤器指定一个值吗" + ], + "My column": ["我的列"], + "My metric": ["我的指标"], + "N/A": ["N/A"], + "NOV": ["十一月"], + "NOW": ["现在"], + "Name": ["名称"], + "Name is required": ["需要名称"], + "Name must be unique": ["名称必须是唯一的"], + "Name of table to be created from columnar data.": [ + "从列存储数据创建的表的名称。" + ], + "Name of table to be created from csv data.": [ + "从CSV数据将创建的表的名称。" + ], + "Name of table to be created from excel data.": [ + "从excel数据将创建的表的名称。" + ], + "Name of the column containing the id of the parent node": [ + "包含父节点id的列的名称" + ], + "Name of the id column": ["ID列名称"], + "Name of the source nodes": ["源节点名称"], + "Name of the table that exists in the source database": [ + "源数据库中存在的表名称" + ], + "Name of the target nodes": ["目标节点名称"], + "Name your database": ["您的数据集"], + "Network error.": ["网络异常。"], + "New": ["新增"], + "New Email Report": ["新的电子邮件报告"], + "New chart": ["新增图表"], + "New columns added: %s": ["新增的列:%s"], + "New filter set": ["新的过滤器"], + "New tab": ["关闭标签"], + "New tab (Ctrl + q)": ["新建Tab页 (Ctrl + q)"], + "New tab (Ctrl + t)": ["新建Tab页 (Ctrl + t)"], + "Next": ["之后"], + "Nightingale Rose Chart": ["南丁格尔玫瑰图"], + "No": ["否"], + "No %(tableName)s yet": ["还没有 %(tableName)s"], + "No %s yet": ["还没有 %s"], + "No Access!": ["不能访问!"], + "No Data": ["没有数据"], + "No Results": ["无结果"], + "No annotation layers yet": ["没有注释层"], + "No annotation yet": ["没有注释"], + "No charts": ["没有图表"], + "No columns": ["没有列"], + "No compatible columns found": ["找不到兼容的列"], + "No dashboards": ["没有看板"], + "No data": ["没有数据"], + "No data after filtering or data is NULL for the latest time record": [ + "过滤后没有数据,或者最新时间记录的数据为NULL" + ], + "No data in file": ["文件中无数据"], + "No description available.": ["没有可用的描述"], + "No favorite charts yet, go click on stars!": [ + "暂无收藏的图表,去点击星星吧!" + ], + "No favorite dashboards yet, go click on stars!": [ + "暂无收藏的看板,去点击星星吧!" + ], + "No filter": ["无筛选"], + "No filter is selected.": ["未选择过滤条件。"], + "No of Bins": ["直方图容器数"], + "No query history yet...": ["暂无历史查询..."], + "No records found": ["没有找到任何记录"], + "No results found": ["未找到结果"], + "No results were returned for this query. If you expected results to be returned, ensure any filters are configured properly and the datasource contains data for the selected time range.": [ + "此查询没有返回任何结果。如果希望返回结果,请确保所有过滤选择的配置正确,并且数据源包含所选时间范围的数据。" + ], + "No stored results found, you need to re-run your query": [ + "找不到存储的结果,需要重新运行查询" + ], + "No such column found. To filter on a metric, try the Custom SQL tab.": [ + "没有发现这样的列。若要在度量值上筛选,请尝试自定义SQL选项卡。" + ], + "No time columns": ["没有时间列"], + "Node label position": ["节点标签位置"], + "Node select mode": ["节点选择模式"], + "Node size": ["节点大小"], + "None": ["空"], + "None -> Arrow": ["无-> 箭头"], + "None -> None": ["无->无"], + "Normal": ["正常"], + "Normalize Across": ["标准化通过"], + "Normalized": ["标准化"], + "Not Time Series": ["美誉时间序列"], + "Not null": ["非空"], + "Not triggered": ["没有触发"], + "Not up to date": ["不是最新的"], + "Nothing triggered": ["无触发"], + "Notification method": ["通知方式"], + "November": ["十一月"], + "Now": ["现在"], + "Null or Empty": ["Null或空"], + "Null values": ["空值"], + "Number Format": ["数字格式"], + "Number format": ["数字格式化"], + "Number of decimal digits to round numbers to": [ + "要四舍五入的十进制位数" + ], + "Number of decimal places with which to display lift values": [ + "用于显示升力值的小数位数" + ], + "Number of decimal places with which to display p-values": [ + "用于显示p值的小数位数" + ], + "Number of rows of file to read.": ["要读取的文件行数。"], + "Number of rows to skip at start of file.": ["在文件开始时跳过的行数。"], + "Number of split segments on the axis": ["轴上分割段的数目"], + "Number of steps to take between ticks when displaying the X scale": [ + "显示 X 刻度时,在刻度之间表示的步骤数" + ], + "Number of steps to take between ticks when displaying the Y scale": [ + "显示 Y 刻度时,在刻度之间表示的步骤数" + ], + "Numerical range": ["数值范围"], + "OCT": ["十月"], + "OK": ["确认"], + "OVERWRITE": ["覆盖"], + "October": ["十月"], + "Offline": ["离线"], + "Offset": ["偏移"], + "On Grace": ["在宽限期内"], + "Once an alert is triggered, how long, in seconds, before Superset nags you again.": [ + "在Superset再次提醒您之前需要多长时间--以秒为单位--来触发一个警报" + ], + "One or many columns to group by. High cardinality groupings should include a series limit to limit the number of fetched and rendered series.": [ + "要分组的一列或多列。高基数分组应包括序列限制,以限制提取和呈现的序列数。" + ], + "One or many columns to group by. High cardinality groupings should include a sort by metric and series limit to limit the number of fetched and rendered series.": [ + "要分组的一列或多列。高基数分组应包括按度量排序和序列限制,以限制提取和呈现的序列数。" + ], + "One or many columns to pivot as columns": [ + "需要作为列属性进行透视的一列或多列" + ], + "One or many controls to group by. If grouping, latitude and longitude columns must be present.": [ + "使用一个或多个控件来分组。一旦分组,则纬度和经度列必须存在。" + ], + "One or many controls to pivot as columns": ["一个或多个控件作为主列"], + "One or many metrics to display": ["一个或多个指标显示"], + "One or more columns already exist": ["一个或多个列已存在"], + "One or more columns are duplicated": ["一个或多个列被复制"], + "One or more columns do not exist": ["一个或多个字段不存在"], + "One or more metrics already exist": ["一个或多个度量已存在"], + "One or more metrics are duplicated": ["一个或多个指标重复"], + "One or more metrics do not exist": ["一个或多个指标不存在"], + "One or more parameters needed to configure a database are missing.": [ + "数据库配置缺少所需的一个或多个参数。" + ], + "One or more parameters specified in the query are malformatted.": [ + "查询中指定的一个或多个参数的格式不正确。" + ], + "One or more parameters specified in the query are missing.": [ + "查询中指定的一个或多个参数丢失。" + ], + "One or more required fields are missing in the request. Please try again, and if the problem persists conctact your administrator.": [ + "请求中缺少一个或多个必填字段。请重试,如果问题仍然存在,请与管理员联系。" + ], + "One ore more annotation layers failed loading.": [ + "一个或多个注释层加载失败。" + ], + "Only SELECT statements are allowed against this database.": [ + "此数据库只允许使用 `SELECT` 语句" + ], + "Only Total": ["仅总计"], + "Only `SELECT` statements are allowed": ["将 SELECT 语句复制到剪贴板"], + "Only selected panels will be affected by this filter": [ + "只有选定的面板将受此过滤条件的影响" + ], + "Only show the total value on the stacked chart, and not show on the selected category": [ + "仅在堆积图上显示合计值,而不在所选类别上显示" + ], + "Only single queries supported": ["仅支持单个查询"], + "Only the following file extensions are allowed: %(allowed_extensions)s": [ + "仅允许以下文件扩展名:%(allowed_extensions)s" + ], + "Opacity": ["不透明度"], + "Opacity of Area Chart. Also applies to confidence band.": [ + "区域图的不透明度。也适用于置信带" + ], + "Opacity of all clusters, points, and labels. Between 0 and 1.": [ + "所有簇、点和标签的不透明度。在0到1之间。" + ], + "Opacity of area chart.": ["面积图的不透明度"], + "Open Datasource tab": ["打开数据源tab"], + "Open in SQL Lab": ["在 SQL 工具箱中打开"], + "Open query in SQL Lab": ["在 SQL 工具箱中打开查询"], + "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.": [ + "以异步模式操作数据库,这意味着查询是在远程工作人员上执行的,而不是在web服务器本身上执行的, 这假设您有一个Celery worker setup以及一个结果后端。有关更多信息,请参考安装文档。" + ], + "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.": [ + "以异步模式操作数据库,这意味着查询是在远程worker上执行的,而不是在web服务器本身上执行的, 这假设您有一个Celery worker setup以及一个执行后端。有关更多信息,请参考安装文档。" + ], + "Operator": ["运算符"], + "Operator undefined for aggregator: %(name)s": [ + "未定义聚合器的运算符:%(name)s" + ], + "Optional CA_BUNDLE contents to validate HTTPS requests. Only available on certain database engines.": [ + "用于验证HTTPS请求的可选 CA_BUNDLE 内容。仅在某些数据库引擎上可用。" + ], + "Optional name of the data column.": ["数据列的可选名称"], + "Optional time column if time range should apply to another column than the default time column": [ + "如果时间范围应应用于默认时间列以外的其他列,则可选时间列" + ], + "Optional warning about use of this metric": ["关于使用此指标的可选警告"], + "Options": ["设置"], + "Or choose from a list of other databases we support:": [ + "或者从我们支持的其他数据库列表中选择:" + ], + "Order by entity id": ["按实体ID排序"], + "Order results by selected columns": ["按选定列对结果进行排序"], + "Ordering": ["排序"], + "Orientation of tree": ["树的方向"], + "Origin": ["起点"], + "Original": ["起点"], + "Original table column order": ["原始表列顺序"], + "Original value": ["原始值"], + "Orthogonal": ["正交化"], + "Other": ["其他"], + "Outer Radius": ["外缘"], + "Outer edge of Pie chart": ["饼图外缘"], + "Overlap": ["重叠"], + "Overlay one or more timeseries from a relative time period. Expects relative time deltas in natural language (example: 24 hours, 7 days, 52 weeks, 365 days). Free text is supported.": [ + "从相对时间段覆盖一个或多个时间序列。期望自然语言中的相对时间增量(例如:24小时、7天、56周、365天)" + ], + "Overwrite": ["覆盖"], + "Overwrite & Explore": ["覆写和浏览"], + "Overwrite Dashboard [%s]": ["覆盖看板 [%s]"], + "Overwrite text in the editor with a query on this table": [ + "使用该表上的查询覆盖编辑器中的文本" + ], + "Owner": ["所有者"], + "Owners": ["所有者"], + "Owners are invalid": ["所有者无效"], + "Owners is a list of users who can alter the dashboard.": [ + "所有者是可以更改看板的用户列表。" + ], + "Owners is a list of users who can alter the dashboard. Searchable by name or username.": [ + "所有者是可以更改看板的用户列表。可按名称或用户名搜索。" + ], + "Page length": ["页长"], + "Paired t-test Table": ["配对T检测表"], + "Pandas resample method": ["Pandas 重新采样的填充方法"], + "Pandas resample rule": ["Pandas 重新采样的规则"], + "Parallel Coordinates": ["平行坐标"], + "Parameter error": ["参数错误"], + "Parameters": ["参数"], + "Parameters ": ["参数"], + "Parent": ["父类"], + "Parent filter": ["父级过滤"], + "Parent filter is required": ["需要父筛选器"], + "Parse Dates": ["解析日期"], + "Part of a Whole": ["占比"], + "Partition Chart": ["分区图"], + "Partition Diagram": ["分区图"], + "Partition Limit": ["分区限制"], + "Partition Threshold": ["分区阈值"], + "Partitions whose height to parent height proportions are below this value are pruned": [ + "高度与父高度的比例低于此值的分区将被修剪" + ], + "Password": ["密码"], + "Paste the shareable Google Sheet URL here": [ + "将可共享的Google Sheet URL粘贴到此处" + ], + "Pattern": ["规则"], + "Percent Change": ["百分比变化"], + "Percentage metrics": ["百分比指标"], + "Percentage threshold": ["百分比阈值"], + "Percentages": ["百分比"], + "Periods": ["周期"], + "Periods must be a positive integer value": ["句点必须是正整数值"], + "Person or group that has certified this chart.": [ + "对此图表进行认证的个人或团体。" + ], + "Person or group that has certified this dashboard.": [ + "已对此仪表板进行认证的个人或组。" + ], + "Person or group that has certified this metric": [ + "认证此指标的个人或团体" + ], + "Physical": ["物理信息"], + "Physical (table or view)": ["物理(表或视图)"], + "Physical dataset": ["物化数据集"], + "Pick a granularity in the Time section or uncheck 'Include Time'": [ + "在“时间”部分选择一个粒度,或取消选中“包含时间”" + ], + "Pick a metric for left axis!": ["为左轴选择一个指标!"], + "Pick a metric for right axis!": ["为右轴选择一个指标!"], + "Pick a metric for x, y and size": ["为 x 轴,y 轴和大小选择一个指标"], + "Pick a metric to display": ["选择一个指标来显示"], + "Pick a metric!": ["选择一个指标!"], + "Pick a name to help you identify this database.": [ + "选择一个名称来帮助您识别这个数据库。" + ], + "Pick a nickname for this database to display as in Superset.": [ + "为这个数据库选择一个昵称以在Superset中显示" + ], + "Pick a time granularity for your time series": [ + "为您的时间序列选择一个时间粒度" + ], + "Pick a title for you annotation.": ["为您的注释选择一个标题"], + "Pick at least one field for [Series]": ["为 [序列] 选择至少一个字段"], + "Pick at least one metric": ["选择至少一个指标"], + "Pick exactly 2 columns as [Source / Target]": [ + "为 [来源 / 目标] 选择两个列" + ], + "Pick one or more columns that should be shown in the annotation. If you don't select a column all of them will be shown.": [ + "选择注释中应该显示的一个或多个列如果您不选择一列,所有的选项都会显示出来。" + ], + "Pick your favorite markup language": ["选择您最爱的 Markup 语言"], + "Pie Chart": ["饼图"], + "Pie shape": ["饼图形状"], + "Pin": ["Pin"], + "Pivot Options": ["透视表选项"], + "Pivot Table": ["透视表"], + "Pivot Table v2": ["透视表 v2"], + "Pivot operation must include at least one aggregate": [ + "数据透视操作必须至少包含一个聚合" + ], + "Pivot operation requires at least one index": [ + "透视操作至少需要一个索引" + ], + "Pivoted": ["旋转"], + "Pixel height of each series": ["每个序列的像素高度"], + "Please apply filter changes": ["请应用滤镜更改"], + "Please check your query and confirm that all template parameters are surround by double braces, for example, \"{{ ds }}\". Then, try running your query again.": [ + "请检查查询并确认所有模板参数都用双大括号括起来,例如 \"{{ ds }}\"。然后,再次尝试运行查询" + ], + "Please check your query for syntax errors at or near \"%(syntax_error)s\". Then, try running your query again.": [ + "请检查查询中 \"%(syntax_error)s\" 处或附近的语法错误。然后,再次尝试运行查询。“" + ], + "Please check your query for syntax errors near \"%(server_error)s\". Then, try running your query again.": [ + "请检查查询中\"%(server_error)s\"附近的语法错误然后,再次尝试运行查询" + ], + "Please choose at least one 'Group by' field ": [ + "请至少选择一个分组字段 " + ], + "Please choose at least one metric": ["请至少选择一个指标"], + "Please choose different metrics on left and right axis": [ + "请在左右轴上选择不同的指标" + ], + "Please complete all required fields.": ["请填写所有必填项"], + "Please confirm": ["请确认"], + "Please enter a SQLAlchemy URI to test": ["请输入要测试的SQLAlchemy URI"], + "Please enter a chart name": ["请输入图表名称"], + "Please filter set name": ["请筛选集合名称"], + "Please make sure all fields are filled out correctly": [ + "请确保所有字段填写正确" + ], + "Please re-enter the password.": ["请重新输入密码。"], + "Please reach out to the Chart Owner for assistance.": [ + "请联系图表所有者寻求帮助。" + ], + "Please save the query to enable sharing": ["请保存查询以启用共享"], + "Please save your chart first, then try creating a new email report.": [ + "请先保存您的图表,然后尝试创建一个新的电子邮件报告。" + ], + "Please save your dashboard first, then try creating a new email report.": [ + "请先保存您的仪表盘,然后尝试创建一个新的电子邮件报告。" + ], + "Please select both a Dataset and a Chart type to proceed": [ + "请同时选择数据集和图表类型以继续" + ], + "Please use 3 different metric labels": ["请在左右轴上选择不同的指标"], + "Please verify that port is open to connect.": [ + "请检查端口是否打开以进行连接" + ], + "Plots the individual metrics for each row in the data vertically and links them together as a line. This chart is useful for comparing multiple metrics across all of the samples or rows in the data.": [ + "垂直地绘制数据中每一行的单个指标,并将它们链接成一行。此图表用于比较数据中所有样本或行中的多个指标。" + ], + "Plugins": ["插件"], + "Point Radius": ["点半径"], + "Point Radius Unit": ["点半径单位"], + "Points": ["点配置"], + "Points and clusters will update as the viewport is being changed": [ + "点和簇将随着视图改变而更新。" + ], + "Pop Tab Link": ["流行标签链接"], + "Popular": ["常用"], + "Populate \"Default value\" to enable this control": [ + "填充 \"Default value\" 以启用此控件" + ], + "Population age data": ["人口年龄数据"], + "Port %(port)s on hostname \"%(hostname)s\" refused the connection.": [ + "主机名 \"%(hostname)s\" 上的端口 %(port)s 拒绝连接。" + ], + "Port is closed": ["端口已关闭"], + "Position JSON": ["位置JSON"], + "Position of child node label on tree": ["子节点标签在树上的位置"], + "Position of column level subtotal": ["列级小计的位置"], + "Position of intermidiate node label on tree": [ + "中间节点标签在树中的位置" + ], + "Position of row level subtotal": ["行级小计的位置"], + "Powered by Apache Superset": ["由Apache Superset提供支持"], + "Pre-filter": ["预过滤"], + "Pre-filter available values": ["预滤器可用值"], + "Pre-filter is required": ["预过滤是必须的"], + "Predicate applied when fetching distinct value to populate the filter control component. Supports jinja template syntax. Applies only when `Enable Filter Select` is on.": [ + "当获取不同的值来填充过滤器组件应用时。支持jinja的模板语法。只在`启用过滤器选择`时应用。" + ], + "Predictive": ["预测"], + "Predictive Analytics": ["预测分析"], + "Prefix metric name with slice name": ["用图表名称作为指标名称的前缀"], + "Preview": ["预览"], + "Preview: `%s`": ["预览 %s"], + "Previous": ["之前"], + "Primary": ["主键"], + "Primary Metric": ["主计量指标"], + "Primary or secondary y-axis": ["主或次y轴"], + "Primary y-axis format": ["主轴格式"], + "Profile": ["用户信息"], + "Profile picture provided by Gravatar": ["资料图片由 Gravatar 提供"], + "Progress": ["进度"], + "Progressive": ["进度"], + "Propagate": ["传播"], + "Proportional": ["比例"], + "Public and privately shared sheets": ["公共和私人共享的表"], + "Publicly shared sheets only": ["仅公开共享表"], + "Published": ["已发布"], + "Put labels outside": ["外侧显示标签"], + "Put the labels outside of the pie?": ["是否将标签显示在饼图外侧?"], + "Put the labels outside the pie?": ["是否将标签显示在饼图外侧?"], + "Put your code here": ["把您的代码放在这里"], + "Python Functions": ["Python函数"], + "Python datetime string pattern": ["Python日期格式模板"], + "Python functions": ["Python函数"], + "Quarter": ["季度"], + "Quarters %s": [" %s 季度"], + "Query": ["查询"], + "Query %s: %s": ["查询 : %s "], + "Query A": ["查询 A"], + "Query B": ["查询 B"], + "Query History": ["历史查询"], + "Query history": ["历史查询"], + "Query in a new tab": ["在新标签中查询"], + "Query is too complex and takes too long to run.": [ + "查询太复杂,运行时间太长。" + ], + "Query mode": ["查询模式"], + "Query name": ["查询名称"], + "Query preview": ["查询预览"], + "Query search string": ["查询搜索字符串"], + "Query was stopped": ["查询被终止。"], + "Query was stopped.": ["查询被终止。"], + "RANGE TYPE": ["范围类型"], + "REPORT NAME ERROR": ["报告名称错误"], + "RGB Color": ["RGB颜色"], + "Radar": ["雷达"], + "Radar Chart": ["雷达图"], + "Radar render type, whether to display 'circle' shape.": [ + "雷达渲染类型,是否显示圆形" + ], + "Radial": ["径向"], + "Ran %s": ["持续时间:%s"], + "Range": ["范围"], + "Range filter": ["范围过滤"], + "Range filter plugin using AntD": ["范围过滤器"], + "Range labels": ["范围标签"], + "Ranges": ["管理"], + "Ranges to highlight with shading": ["突出阴影的范围"], + "Ranking": ["排名"], + "Ratio": ["比率"], + "Raw records": ["原始记录"], + "Ready to review filters in this dashboard?": [ + "准备查看此仪表板中的筛选器吗?" + ], + "Rebuild": ["重构"], + "Recent activity": ["近期活动"], + "Recently created charts, dashboards, and saved queries will appear here": [ + "最近创建的图表、看板和保存的查询将显示在此处" + ], + "Recently edited charts, dashboards, and saved queries will appear here": [ + "最近编辑的图表、看板和保存的查询将显示在此处" + ], + "Recently modified": ["最近修改"], + "Recently viewed charts, dashboards, and saved queries will appear here": [ + "最近查看的图表、看板和保存的查询将显示在此处" + ], + "Recents": ["最近"], + "Recipients": ["收件人"], + "Recipients are separated by \",\" or \";\"": [ + "收件人之间用 \",\" 或者 \";\" 隔开" + ], + "Recommended tags": ["推荐标签"], + "Record Count": ["记录数"], + "Rectangle": ["长方形"], + "Redirects to this endpoint when clicking on the datasource from the datasource list": [ + "在数据源列表中点击数据源将重定向到此端点" + ], + "Redirects to this endpoint when clicking on the table from the table list": [ + "点击表列表中的表时将重定向到此端点" + ], + "Reduce X ticks": ["减少 X 轴的刻度"], + "Reduces the number of X-axis ticks to be rendered. If true, the x-axis will not overflow and labels may be missing. If false, a minimum width will be applied to columns and the width may overflow into an horizontal scroll.": [ + "减少要渲染的X轴标记数。如果为true,x轴将不会溢出,但是标签可能丢失。如果为false,则对列应用最小宽度,宽度可能溢出到水平滚动条中。" + ], + "Refer to the": ["参考 "], + "Referenced columns not available in DataFrame.": [ + "引用的列在数据帧(DataFrame)中不可用。" + ], + "Refetch results": ["重新获取结果"], + "Refresh": ["刷新间隔"], + "Refresh Druid Metadata": ["刷新 Druid 元数据"], + "Refresh Metadata": ["刷新元数据"], + "Refresh column metadata": ["刷新字段元数据"], + "Refresh dashboard": ["刷新看板"], + "Refresh frequency": ["刷新频率"], + "Refresh interval": ["刷新间隔"], + "Refresh the default values": ["刷新默认值"], + "Refreshed metadata from cluster [{}]": ["从群集刷新元数据 [{}]"], + "Refreshing datasource [{}]": ["刷新数据源 [{}]"], + "Regular filters add where clauses to queries if a user belongs to a role referenced in the filter. Base filters apply filters to all queries except the roles defined in the filter, and can be used to define what users can see if no RLS filters within a filter group apply to them.": [ + "常规过滤将where子句添加到查询中,以确定用户是否属于过滤中引用的角色。基本过滤将应用于除过滤中定义的角色之外的所有查询,并且可以用于定义在没有应用RLS过滤组的情况下,哪些用户可以看到内容。" + ], + "Relational": ["执行时间"], + "Relationships between community channels": ["社区渠道之间的关系"], + "Relative Date/Time": ["相对日期/时间"], + "Relative period": ["宽限期"], + "Relative quantity": ["相对量"], + "Remind me in 24 hours": ["24小时后提醒我"], + "Remove": ["删除"], + "Remove invalid filters": ["删除该行"], + "Remove item": ["删除该行"], + "Remove query from log": ["从日志中删除查询"], + "Remove table preview": ["删除表格预览"], + "Removed columns: %s": ["删除的列:%s"], + "Rename tab": ["重命名标签"], + "Rendering": ["渲染"], + "Replace": ["替换"], + "Report": ["报表"], + "Report Schedule could not be created.": ["无法创建报表计划。"], + "Report Schedule could not be deleted.": ["无法删除报表计划。"], + "Report Schedule could not be updated.": ["无法更新报表计划。"], + "Report Schedule delete failed.": ["报表计划删除失败。"], + "Report Schedule execution failed when generating a csv.": [ + "生成屏幕截图时报表计划执行失败。" + ], + "Report Schedule execution failed when generating a dataframe.": [ + "生成屏幕截图时报表计划执行失败。" + ], + "Report Schedule execution failed when generating a screenshot.": [ + "生成屏幕截图时报表计划执行失败。" + ], + "Report Schedule execution got an unexpected error.": [ + "报表计划执行遇到意外错误。" + ], + "Report Schedule is still working, refusing to re-compute.": [ + "报表计划仍在运行,拒绝重新计算。" + ], + "Report Schedule log prune failed.": ["报表计划日志精简失败。"], + "Report Schedule not found.": ["找不到报表计划。"], + "Report Schedule parameters are invalid.": ["报表计划参数无效。"], + "Report Schedule reached a working timeout.": ["报表计划已超时。"], + "Report Schedule sellenium user not found": [ + "找不到报表计划sellenium用户" + ], + "Report Schedule state not found": ["未找到报表计划状态"], + "Report a bug": ["报告bug"], + "Report failed": ["报告失败"], + "Report name": ["报告名称"], + "Report schedule": ["报告时间表"], + "Report schedule unexpected error": ["报告计划意外错误。"], + "Report sending": ["报告发送"], + "Report sent": ["已发送报告"], + "Reports": ["报告"], + "Repulsion": ["表达式"], + "Repulsion strength between nodes": ["节点间的斥力"], + "Request Permissions": ["请求权限"], + "Request is incorrect: %(error)s": ["请求不正确: %(error)s"], + "Request is not JSON": ["请求不是JSON"], + "Request missing data field.": ["请求丢失的数据字段。"], + "Required": ["必填"], + "Resample": ["重新采样"], + "Reset state": ["状态重置"], + "Restore Filter": ["还原过滤条件"], + "Results": ["结果"], + "Results backend is not configured.": ["后端未配置结果"], + "Results backend needed for asynchronous queries is not configured.": [ + "后端未配置异步查询所需的结果" + ], + "Return to specific datetime.": ["返回指定的日期时间。"], + "Reverse lat/long ": ["经纬度互换"], + "Rich Tooltip": ["详细提示"], + "Rich tooltip": ["详细提示"], + "Right": ["高度"], + "Right Axis Format": ["右轴格式化"], + "Right Axis Metric": ["右轴指标"], + "Right Axis chart(s)": ["右轴图表"], + "Right axis metric": ["右轴指标"], + "Right to Left": ["右到左"], + "Right value": ["右侧的值"], + "Role": ["用户信息"], + "Role %(r)s was extended to provide the access to the datasource %(ds)s": [ + "扩展角色 %(r)s 以提供对 datasource %(ds)s 的访问" + ], + "Roles": ["角色"], + "Roles is a list which defines access to the dashboard. Granting a role access to a dashboard will bypass dataset level checks. If no roles defined then the dashboard is available to all roles.": [ + "角色是一个定义对仪表板访问权限的列表。授予角色对仪表板的访问权限将绕过数据集级别的检查。如果未定义角色,则仪表板对所有角色都可用。" + ], + "Roles is a list which defines access to the dashboard. Granting a role access to a dashboard will bypass dataset level checks.If no roles defined then the dashboard is available to all roles.": [ + "角色是一个定义对仪表板访问权限的列表。授予角色对仪表板的访问权限将绕过数据集级别的检查。如果未定义角色,则仪表板对所有角色都可用。" + ], + "Roles to grant": ["角色授权"], + "Rolling Function": ["滚动函数"], + "Rolling Window": ["滚动窗口"], + "Rolling function": ["滚动函数"], + "Rolling window": ["滚动窗口"], + "Root certificate": ["根证书"], + "Root node id": ["根节点id"], + "Rotate x axis label": ["旋转x轴标签"], + "Rotation to apply to words in the cloud": [ + "应用于词云中的单词的旋转方式" + ], + "Round cap": ["国家地图"], + "Row": ["行"], + "Row Level Security": ["行级安全"], + "Row containing the headers to use as column names (0 is first line of data). Leave empty if there is no header row.": [ + "作为列名的带有标题的行(0是第一行数据)。如果没有标题行则留空。" + ], + "Row level security filter": ["行级安全过滤"], + "Row limit": ["行限制"], + "Rows": ["行"], + "Rows per page, 0 means no pagination": ["每页行数,0 表示没有分页"], + "Rows subtotal position": ["行小计的位置"], + "Rows to Read": ["读取的行"], + "Rule": ["规则"], + "Run": ["执行"], + "Run a query to display results here": ["运行一个查询,在此会显示结果"], + "Run in SQL Lab": ["在 SQL 工具箱中执行"], + "Run query": ["运行查询"], + "Run query (Ctrl + Return)": ["执行运行 (Ctrl + Return)"], + "Run query in a new tab": ["在新标签中运行查询"], + "Run selection": ["运行选定的查询"], + "Running": ["正在执行"], + "SAT": ["星期六"], + "SEP": ["九月"], + "SQL": ["SQL"], + "SQL Copied!": ["SQL复制成功!"], + "SQL Editor": ["SQL 编辑器"], + "SQL Expression": ["SQL表达式"], + "SQL Lab": ["SQL 工具箱"], + "SQL Lab View": ["SQL Lab 视图"], + "SQL Lab uses your browser's local storage to store queries and results.\nCurrently, you are using %(currentUsage)s KB out of %(maxStorage)d KB storage space.\nTo keep SQL Lab from crashing, please delete some query tabs.\nYou can re-access these queries by using the Save feature before you delete the tab.\nNote that you will need to close other SQL Lab windows before you do this.": [ + "SQL Lab使用浏览器的本地存储来存储查询和结果" + ], + "SQL Query": ["SQL查询"], + "SQL expression": ["SQL表达式"], + "SQL query": ["SQL查询"], + "SQLAlchemy URI": ["SQLAlchemy URI"], + "SSL Mode \"require\" will be used.": ["SSL模式 \"require\" 将被使用。"], + "START (INCLUSIVE)": ["开始 (包含)"], + "SUN": ["星期日"], + "Sankey": ["蛇形图"], + "Sankey Diagram": ["桑基图"], + "Sankey Diagram with Loops": ["桑基图"], + "Saturday": ["星期六"], + "Save": ["保存"], + "Save & Explore": ["保存和浏览"], + "Save & go to dashboard": ["保存并转到看板"], + "Save (Overwrite)": ["保存(覆盖)"], + "Save as": ["另存为"], + "Save as ...": ["另存为 ..."], + "Save as new": ["保存为新的"], + "Save as new chart": ["创建新图表"], + "Save as:": ["另存为:"], + "Save chart": ["图表保存"], + "Save dashboard": ["保存看板"], + "Save for this session": ["保存此会话"], + "Save query": ["保存查询"], + "Save the query to enable this feature": ["请保存查询以启用共享"], + "Saved": ["保存"], + "Saved Queries": ["已保存查询"], + "Saved expressions": ["保存表达式"], + "Saved metric": ["保存的指标"], + "Saved queries": ["已保存查询"], + "Saved queries could not be deleted.": ["保存的查询无法被删除"], + "Saved query not found.": ["保存的查询未找到"], + "Saved query parameters are invalid.": ["保存的查询参数无效"], + "Scale and Move": ["缩放和移动"], + "Scale only": ["存在规模"], + "Scan New Datasources": ["扫描新的数据源"], + "Scatter": ["散点"], + "Scatter Plot": ["散点图"], + "Schedule": ["调度"], + "Schedule Email Reports for Charts": ["为图表配置电子邮件报告"], + "Schedule Email Reports for Dashboards": ["为看板添加电子邮件报告"], + "Schedule email report": ["为图表配置电子邮件报告"], + "Schedule query": ["分享查询"], + "Schedule settings": ["计划设置"], + "Schedule the query periodically": ["定期调度查询"], + "Scheduled": ["被调度"], + "Scheduled at (UTC)": ["计划时间"], + "Scheduled reports will be sent to your email as a PNG": [ + "计划的报告将作为PNG发送到您的电子邮件" + ], + "Schema": ["模式"], + "Schema cache timeout": ["图表缓存超时"], + "Schema, as used only in some databases like Postgres, Redshift and DB2": [ + "模式,只在一些数据库中使用,比如Postgres、Redshift和DB2" + ], + "Schemas allowed for CSV upload": ["模式允许使用CSV上传"], + "Scoping": ["范围"], + "Search": ["搜索"], + "Search / Filter": ["搜索 / 过滤"], + "Search Metrics & Columns": ["搜索指标和列"], + "Search all charts": ["搜索所有图表"], + "Search all dashboards": ["搜索所有看板"], + "Search all filter options": ["搜索所有过滤选项"], + "Search box": ["搜索框"], + "Search by query text": ["按查询文本搜索"], + "Search...": ["搜索..."], + "Second": ["秒"], + "Secondary": ["次要的"], + "Secondary Metric": ["次计量指标"], + "Secondary y-axis format": ["次级y轴格式"], + "Secondary y-axis title": ["二级轴标题"], + "Seconds %s": ["%s 秒"], + "Secure Extra": ["安全"], + "Secure extra": ["安全"], + "Security": ["安全"], + "Security & Access": ["安全 & 访问"], + "See all %(tableName)s": ["查看全部 - %(tableName)s"], + "See less": ["查看更少"], + "See more": ["查看更多"], + "See table schema": ["选择表"], + "Select": ["批量选择"], "Select ...": ["选择 ..."], - "Loaded data cached": ["数据缓存已加载"], - "Loaded from cache": ["从缓存中加载"], - "Click to force-refresh": ["点击强制刷新"], - "cached": ["已缓存"], - "Certified by %s": ["认证人 %s"], - "Copy to clipboard": ["复制到剪贴板"], - "Copied!": ["复制成功!"], + "Select Delivery Method": ["添加通知方法"], + "Select Viz Type": ["选择一个可视化类型"], + "Select a CSV file to be uploaded to a database.": [ + "选择一个CSV文件上传到数据库." + ], + "Select a Columnar file to be uploaded to a database.": [ + "选择要上传到数据库的Excel文件。" + ], + "Select a Excel file to be uploaded to a database.": [ + "选择要上传到数据库的Excel文件。" + ], + "Select a column": ["反选所有"], + "Select a dashboard": ["看板"], + "Select a visualization type": ["选择一个可视化类型"], + "Select aggregate options": ["选择总选项"], + "Select any columns for metadata inspection": [ + "选择任意列进行元数据巡检" + ], + "Select charts": ["所有图表"], + "Select color scheme": ["线性颜色方案"], + "Select column": ["时间列"], + "Select database or type database name": ["选择表或输入表名"], + "Select databases require additional fields to be completed in the Advanced tab to successfully connect the database. Learn what requirements your databases has ": [ + "选择数据库需要在Advanced选项卡中完成额外的字段才能成功连接数据库了解数据库的需求" + ], + "Select filter": ["选择过滤器"], + "Select filter plugin using AntD": ["选择过滤器"], + "Select first item by default (when using this option, default value can’t be set)": [ + "默认选择第一项(使用此选项时,不能“设置默认值”)" + ], + "Select operator": ["选择运营商"], + "Select or type a value": ["选择或者输入值"], + "Select owners": ["运行选定的查询"], + "Select parent filters": ["选择父级过滤"], + "Select saved metrics": ["选择保存指标"], + "Select schema or type schema name": ["选择表或输入表名"], + "Select scheme": ["选择表"], + "Select start and end date": ["选择开始和结束时间"], + "Select subject": ["选择主题"], + "Select table or type table name": ["选择表或输入表名"], + "Select the number of bins for the histogram": ["选择直方图的容器数"], + "Select the numeric columns to draw the histogram": [ + "选择直方图的容器数" + ], + "Send as CSV": ["发送为CSV"], + "Send as PNG": ["发送PNG"], + "Send as text": ["发送文本"], + "Send range filter events to other charts": [ + "将过滤条件的事件发送到其他图表" + ], + "September": ["九月"], + "Sequential": ["顺序"], + "Series": ["序列"], + "Series Height": ["序列高度"], + "Series Style": ["线条样式"], + "Series chart type (line, bar etc)": ["系列图表类型(折线,柱状图等)"], + "Series limit": ["序列限制"], + "Series type": ["图示类型"], + "Server Page Length": ["页面长度"], + "Server pagination": ["服务器分页"], + "Service Account": ["服务帐户"], + "Set auto-refresh interval": ["设置自动刷新"], + "Set filter mapping": ["设置过滤映射"], + "Settings": ["设置"], + "Settings for time series": ["时间序列设置"], + "Share": ["分享"], + "Share chart by email": ["通过电子邮件分享图表”"], + "Share dashboard by email": ["通过电子邮件分享仪表盘"], + "Shared query": ["已分享的查询"], + "Sheet Name": ["Sheet名称"], + "Short description must be unique for this layer": [ + "此层的简述必须是唯一的" + ], + "Should daily seasonality be applied. An integer value will specify Fourier order of seasonality.": [ + "一个整数值将指定季节性的傅立叶顺序。" + ], + "Should weekly seasonality be applied. An integer value will specify Fourier order of seasonality.": [ + "一个整数值将指定季节性的傅立叶顺序。" + ], + "Should yearly seasonality be applied. An integer value will specify Fourier order of seasonality.": [ + "一个整数值将指定“季节性的傅立叶顺序。" + ], + "Show Annotation": ["查看注释"], + "Show Annotation Layer": ["查看注释层"], + "Show Bubbles": ["显示气泡"], + "Show CREATE VIEW statement": ["显示 CREATE VIEW 语句"], + "Show CSS Template": ["查看CSS模板"], + "Show Chart": ["显示图表"], + "Show Column": ["显示列"], + "Show Dashboard": ["显示看板"], + "Show Database": ["显示数据库"], + "Show Druid Cluster": ["显示 Druid 集群"], + "Show Druid Column": ["显示 Druid 列"], + "Show Druid Datasource": ["显示 Druid 数据源"], + "Show Druid Metric": ["显示 Druid 指标"], + "Show Druid granularity dropdown": ["显示Druid时间粒度下拉列表"], + "Show Druid time origin": ["显示Druid原始时间"], + "Show Labels": ["显示标签"], + "Show Less...": ["显示. ."], + "Show Log": ["查看日志"], + "Show Markers": ["显示标记"], + "Show Metric": ["显示指标"], + "Show Metric Names": ["显示指标名"], + "Show Observation": ["显示观察结果"], + "Show Range Filter": ["显示范围过滤器"], + "Show Row level security filter": ["显示行级安全过滤"], + "Show SQL time column": ["显示SQL时间列"], + "Show SQL time grain dropdown": ["检查包含时间原点的下拉列表"], + "Show Saved Query": ["显示保存的查询"], + "Show Table": ["显示表"], + "Show Timestamp": ["显示时间戳"], + "Show Trend Line": ["显示趋势线"], + "Show Upper Labels": ["显示标签"], + "Show Value": ["显示值"], + "Show Values": ["显示值"], + "Show all columns": ["显示所有列"], + "Show all...": ["显示所有..."], + "Show axis line ticks": ["显示轴线刻度"], + "Show cell bars": ["显示单元格的栏"], + "Show columns total": ["显示总计"], + "Show data points as circle markers on the lines": [ + "将数据点显示为线条上的圆形标记" + ], + "Show hierarchical relationships of data, with with the value represented by area, showing proportion and contribution to the whole.": [ + "显示数据的层次关系与表示的值。按面积划分显示其占整体的比例" + ], + "Show info tooltip": ["显示信息提示"], + "Show label": ["显示标签"], + "Show labels when the node has children.": ["当节点有子节点时显示标签"], + "Show legend": ["显示图例"], + "Show less columns": ["显示较少时间列"], + "Show less...": ["显示..."], + "Show percentage": ["显示百分比"], + "Show pointer": ["显示鼠标"], + "Show progress": ["显示进度"], + "Show rows total": ["显示总计行数"], + "Show series values on the chart": ["显示栏上的值"], + "Show split lines": ["显示分割线"], + "Show the value on top of the bar": ["显示栏上的值"], + "Show time column": ["显示时间列"], + "Show time grain dropdown": ["显示Druid时间粒度下拉列表"], + "Show total aggregations of selected metrics. Note that row limit does not apply to the result.": [ + "显示所选指标的总聚合。注意行限制并不应用于结果" + ], + "Show totals": ["显示总计"], + "Showcases a single metric front-and-center. Big number is best used to call attention to a KPI or the one thing you want your audience to focus on.": [ + "显示单个公制正面和中间。大数字最好用来唤起人们对KPI或你希望观众关注的一件事的关注" + ], + "Showcases a single number accompanied by a simple line chart, to call attention to an important metric along with its change over time or other dimension.": [ + "显示一个数字和一个简单的折线图,以提醒注意一个重要指标及其随时间或其他维度的变化" + ], + "Showcases how a metric changes as the funnel progresses. This classic chart is useful for visualizing drop-off between stages in a pipeline or lifecycle.": [ + "显示指标如何随着漏斗的进展而变化。此经典图表对于可视化管道或生命周期中各阶段之间的下降非常有用。" + ], + "Showcases the flow or link between categories using thickness of chords. The value and corresponding thickness can be different for each side.": [ + "使用弦的厚度显示类别之间的流或链接。每一侧的值和相应厚度可能不同。" + ], + "Showcases the progress of a single metric against a given target. The higher the fill, the closer the metric is to the target.": [ + "显示单个指标相对于给定目标的进度。填充越高,度量越接近目标" + ], + "Showing %s of %s": ["显示 %s个 总计 %s个"], + "Shows a list of all series available at that point in time": [ + "详细提示显示了该时间点的所有序列的列表。" + ], + "Shows the composition of a dataset by segmenting a given rectangle as smaller rectangles with areas proportional to their value or contribution to the whole. Those rectangles may also, in turn, be further segmented hierarchically.": [ + "显示数据集的组成,方法是将给定矩形分割为较小的矩形,其面积与矩形的值或对整体的贡献成比例。这些矩形也可以按层次进一步分割" + ], + "Significance Level": ["显著性"], + "Simple": ["简单配置"], + "Simple ad-hoc metrics are not enabled for this dataset": [ + "此数据集没有启用简单的特别度量" + ], + "Single": ["我的编辑"], + "Single Metric": ["按指标过滤"], + "Single Value": ["空值"], + "Single value": ["空值"], + "Single value type": ["单值类型"], + "Size of edge symbols": ["边缘符号的大小"], + "Size of marker. Also applies to forecast observations.": [ + "标记的大小也适用于预测观察。”" + ], + "Sizes of vehicles": ["工具尺寸"], + "Skip Blank Lines": ["跳过空白行"], + "Skip Initial Space": ["跳过初始空格"], + "Skip Rows": ["跳过行"], + "Skip blank lines rather than interpreting them as NaN values.": [ + "跳过空白行而不是把它们解释为NaN值。" + ], + "Skip spaces after delimiter.": ["在分隔符之后跳过空格。"], + "Slack Channel": ["Slack 频道"], + "Slug": ["Slug"], + "Small": ["小"], + "Small number format": ["数字格式化"], + "Some roles do not exist": ["看板"], + "Sorry there was an error fetching database information: %s": [ + "抱歉,获取数据库信息时出错:%s" + ], + "Sorry there was an error fetching saved charts: ": [ + "抱歉,这个看板在获取图表时发生错误:" + ], + "Sorry, An error occurred": ["抱歉,发生错误"], + "Sorry, something went wrong. Try again later.": [ + "抱歉,出了点问题。请稍后再试。" + ], + "Sorry, there appears to be no data": ["抱歉,似乎没有数据"], + "Sorry, there was an error saving this dashboard: %s": [ + "抱歉,这个看板在获取图表时发生错误:%s" + ], + "Sorry, your browser does not support copying.": [ + "抱歉,您的浏览器不支持复制操作。使用 Ctrl / Cmd + C!" + ], "Sorry, your browser does not support copying. Use Ctrl / Cmd + C!": [ "抱歉,您的浏览器不支持复制操作。使用 Ctrl / Cmd + C!" ], - "Error while fetching schema list": ["获取schema列表时出错"], - "Error while fetching database list": ["获取数据库列表时出错"], - "Database:": ["数据库:"], - "Select a database": ["选择一个数据库"], - "Force refresh schema list": ["强制刷新数据"], - "Select a schema (%s)": ["选择一个schema(%s)"], - "Schema:": [""], - "datasource": ["数据源"], - "schema": ["模式"], - "delete": ["删除"], - "Type \"%s\" to confirm": ["键入 \"%s\" 来确认"], - "DELETE": ["删除"], - "Click to edit": ["点击编辑"], - "You don't have the rights to alter this title.": [ - "您没有权利修改这个标题。" + "Sort": ["排序:"], + "Sort Bars": ["排序条形栏"], + "Sort Descending": ["降序"], + "Sort Metric": ["排序指标"], + "Sort X Axis": ["排序X轴"], + "Sort Y Axis": ["排序Y轴"], + "Sort ascending": ["升序排序"], + "Sort bars by x labels.": ["按 x 标签排序。"], + "Sort by": ["排序 "], + "Sort by %s": ["排序 %s"], + "Sort by metric": ["排序指标"], + "Sort columns alphabetically": ["对列按字母顺序进行排列"], + "Sort columns by": ["对列按字母顺序进行排列"], + "Sort descending": ["降序"], + "Sort filter values": ["可被过滤"], + "Sort metric": ["排序指标"], + "Sort rows by": ["排序 "], + "Sort type": ["图表类型"], + "Source": ["来源"], + "Source / Target": ["源/目标"], + "Source SQL": ["源 SQL"], + "Source category": ["数据库名称"], + "Spatial": ["空间"], + "Specific Date/Time": ["具体日期/时间"], + "Specify a schema (if database flavor supports this).": [ + "指定一个Schema(需要数据库支持)" + ], + "Specify duplicate columns as \"X.0, X.1\".": [ + "将重复列指定为“x.0,x.1”。" + ], + "Specify the database version. This should be used with Presto in order to enable query cost estimation.": [ + "指定数据库版本。这应该与Presto一起使用,以便启用查询成本估算。" + ], + "Split number": ["数字"], + "Stack series": ["已保存查询"], + "Stack series on top of each other": ["叠加系列"], + "Stacked": ["堆叠"], + "Stacked Bars": ["堆叠条形图"], + "Stacked Style": ["堆积样式"], + "Stacked style": ["堆积样式"], + "Standard time series": ["时间序列"], + "Start": ["开始"], + "Start Review": ["数据预览"], + "Start angle": ["开始时间"], + "Start at (UTC)": ["由UTC开始"], + "Start date included in time range": ["开始日期包含在时间范围内"], + "Start y-axis at 0": ["y轴从0开始"], + "Start y-axis at zero. Uncheck to start y-axis at minimum value in the data.": [ + "从零开始y轴。取消选中以从数据中的最小值开始y轴 " + ], + "State": ["状态"], + "Statistical": ["统计"], + "Status": ["状态"], + "Step type": ["数据类型"], + "Stop": ["停止"], + "Stop query": ["停止查询"], + "Stop running (Ctrl + x)": ["停止运行 (Ctrl + x)"], + "Stopped an unsafe database connection": ["已停止不安全的数据库连接"], + "Strength to pull the graph toward center": ["将图形拉向中心"], + "Stretched style": ["堆积样式"], + "Strings used for sheet names (default is the first sheet).": [ + "用于sheet名称的字符串(默认为第一个sheet)。" + ], + "Structural": ["结构"], + "Style": ["风格"], + "Style the ends of the progress bar with a round cap": [ + "用圆帽设置进度条末端的样式" + ], + "Subdomain": ["子域"], + "Subheader": ["子标题"], + "Subheader Font Size": ["子标题的字体大小"], + "Success": ["成功"], + "Suffix to apply after the percentage display": [ + "百分比显示后要应用的后缀" + ], + "Sum of values over specified period": ["指定期间内的值总和"], + "Sunburst": ["环状层次图"], + "Sunburst Chart": ["旭日/太阳图"], + "Sunday": ["星期日"], + "Superset Chart": ["选择图表"], + "Superset chart": ["选择图表"], + "Superset dashboard": ["看板"], + "Superset encountered an error while running a command.": [ + "警报在执行查询时发现错误。" + ], + "Superset encountered an unexpected error.": ["报告计划意外错误。"], + "Supported databases": ["已支持数据库"], + "Survey Responses": ["调查结果"], + "Swap Groups and Columns": ["交换组和列"], + "Swap rows and columns": ["交换组和列"], + "Swiss army knife for visualizing time series data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.": [ + "用于可视化时间序列数据。在步进图、折线图、散点图和条形图之间进行选择,也有许多自定义选项" + ], + "Symbol": ["符号"], + "Symbol of two ends of edge line": ["边线两端的符号"], + "Symbol size": ["符号的大小"], + "Sync columns from source": ["从源同步列"], + "Syntax": ["语法"], + "TABLES": ["表"], + "THU": ["星期四"], + "TUE": ["星期二"], + "Tab name": ["选项卡名字"], + "Tab title": ["选项卡标题"], + "Table": ["表"], + "Table %(table)s wasn't found in the database %(db)s": [ + "在数据库 %(db)s 中找不到表 %(table)s" + ], + "Table Exists": ["表已存在处理"], + "Table Name": ["表名"], + "Table View": ["表视图"], + "Table [%(table_name)s] could not be found, please double check your database connection, schema, and table name": [ + "找不到 [%(table_name)s] 表,请仔细检查您的数据库连接、Schema 和 表名" + ], + "Table [%{table}s] could not be found, please double check your database connection, schema, and table name, error: {}": [ + "找不到 [%{table}s] 表,请仔细检查您的数据库连接、Schema 和 表名" + ], + "Table cache timeout": ["图表缓存超时"], + "Table name undefined": ["表名未定义"], + "Table that visualizes paired t-tests, which are used to understand statistical differences between groups.": [ + "可视化检验的表格,用于了解各组之间的统计差异" + ], + "Tables": ["数据表"], + "Tabs": ["选项卡"], + "Tabular": ["表格"], + "Tags": ["标签"], + "Take your data points, and group them into \"bins\" to see where the densest areas of information lie": [ + "获取数据点,并将其分组,以查看信息最密集的区域" + ], + "Target": ["目标"], + "Target aspect ratio for treemap tiles.": ["树形图中图块的目标高宽比。"], + "Target category": ["目标类别"], + "Target value": ["目标值"], + "Template Name": ["模板名称"], + "Template parameters": ["模板参数"], + "Templated link, it's possible to include {{ metric }} or other values coming from the controls.": [ + "模板链接,可以包含{{度量}}或来自控件的其他值。" + ], + "Temporal expression not supported for type: %(col_type)s": [ + "%(col_type)s不支持时间表达式" + ], + "Terminate running queries when browser window closed or navigated to another page. Available for Presto, Hive, MySQL, Postgres and Snowflake databases.": [ + "当浏览器窗口关闭或导航到其他页面时,终止正在运行的查询。适用于Presto、Hive、MySQL、Postgres和Snowflake数据库" + ], + "Test Connection": ["测试连接"], + "Test connection": ["测试连接"], + "Text": ["文本"], + "Text align": ["文本对齐"], + "Text embedded in email": ["邮件中嵌入的文本"], + "The CSS for individual dashboards can be altered here, or in the dashboard view where changes are immediately visible": [ + "可以在这里或者在看板视图修改单个看板的CSS样式" + ], + "The CTAS (create table as select) doesn't have a SELECT statement at the end. Please make sure your query has a SELECT as its last statement. Then, try running your query again.": [ + "CTA(create table as select)只能与最后一条语句为SELECT的查询一起运行。请确保查询的最后一个语句是SELECT。然后再次尝试运行查询。" ], - "Unexpected error": ["意外错误。"], - "Click to favorite/unfavorite": ["点击 收藏/取消收藏"], - "An error occurred while fetching dashboards": ["获取看板时出错"], - "Error while fetching table list": ["获取表列表时出错"], - "Select table or type table name": ["选择表或输入表名"], - "Type to search ...": ["输入搜索条件 ..."], - "Select table ": ["选择表"], - "Force refresh table list": ["强制刷新数据"], - "See table schema": ["选择表"], - "%s%s": ["%s%s"], - "Share dashboard": ["分享看板"], - "This may be triggered by:": ["这可能由以下因素触发:"], - "Please reach out to the Chart Owner for assistance.": [ - "请联系图表所有者寻求帮助。" + "The JSON metric or post aggregation definition.": [ + "JSON指标或处理聚合定义。" ], - "Chart Owner: %s": ["图表所有者:%s"], - "%s Error": ["%s 异常"], - "See more": ["查看更多"], - "See less": ["查看更少"], - "Copy message": ["复制信息"], - "Close": ["关闭"], - "This was triggered by:": ["这是由以下因素引发的:"], - "Did you mean:": ["您的意思是:"], - "%(suggestion)s instead of \"%(undefinedParameter)s?\"": [ - "用 %(suggestion)s 替换 \"%(undefinedParameter)s\" 吗?" + "The URL could not be identified. Please check for typos and make sure that \"Type of google sheet allowed\" selection matches the input": [ + "无法识别URL。请检查拼写错误,并确保允许的谷歌工作表类型选择与输入匹配" ], - "Parameter error": ["参数错误"], - "We’re having trouble loading this visualization. Queries are set to timeout after %s second.": [ - "加载此可视化效果时遇到问题。查询设置为 %s 秒后超时。" + "The access requests seem to have been deleted": ["访问请求已被删除"], + "The annotation has been saved": ["注释已保存。"], + "The annotation has been updated": ["注释已更新。"], + "The category of source nodes used to assign colors. If a node is associated with more than one category, only the first will be used.": [ + "用于分配颜色的源节点类别。如果一个节点与多个类别关联,则只使用第一个类别" ], - "We’re having trouble loading these results. Queries are set to timeout after %s second.": [ - "加载结果时遇到问题。查询设置为 %s 秒后超时。" + "The chart does not exist": ["图表不存在"], + "The classic. Great for showing how much of a company each investor gets, what demographics follow your blog, or what portion of the budget goes to the military industrial complex.\n\n Pie charts can be difficult to interpret precisely. If clarity of relative proportion is important, consider using a bar or other chart type instead.": [ + "经典的,很好地展示了每个投资者获得了多少公司,“有多少人关注你的博客,或者预算的哪一部分流向了军事工业综合体饼状图很难精确解释。如果“相对比例”的清晰性很重要,可以考虑使用柱状图或其他图表来代替。" ], - "Timeout error": ["超时错误"], - "Cell content": ["单元格内容"], - "The import was successful": ["导入成功"], - "OVERWRITE": ["覆盖"], - "Overwrite": ["覆盖"], - "Import": ["导入"], - "Import %s": ["导入 %s"], - "Last Updated %s": ["上次更新 %s"], - "%s Selected": ["%s 已选定"], - "Deselect all": ["反选所有"], - "%s-%s of %s": ["%s-%s 总计 %s"], - "Settings": ["设置"], - "About": ["关于"], - "SQL query": ["SQL查询"], - "There is not enough space for this component. Try decreasing its width, or increasing the destination width.": [ - "此组件没有足够的空间。请尝试减小其宽度,或增加目标宽度。" + "The color for points and clusters in RGB": ["点和簇的颜色(RGB)"], + "The color scheme for rendering chart": ["绘制图表的配色方案"], + "The color scheme is determined by the related dashboard.\n Edit the color scheme in the dashboard properties.": [ + "配色方案由相关的仪表盘决定。在仪表板属性中编辑配色方案" ], - "Can not move top level tab into nested tabs": [ - "无法将顶级tab页移动到嵌套tab页中" + "The column was deleted or renamed in the database.": [ + "该列已在数据库中删除或重命名。" ], - "This chart has been moved to a different filter scope.": [ - "此图表已移至其他过滤器范围内。" + "The country code standard that Superset should expect to find in the [country] column": [ + "Superset 希望能够在 [国家] 栏中找到的 国家 / 地区 的标准代码" ], - "There was an issue fetching the favorite status of this dashboard.": [ - "获取此看板的收藏夹状态时出现问题。" + "The dashboard has been saved": ["该看板已成功保存。"], + "The data source seems to have been deleted": ["数据源已经被删除"], + "The data type that was inferred by the database. It may be necessary to input a type manually for expression-defined columns in some cases. In most case users should not need to alter this.": [ + "由数据库推断的数据类型。在某些情况下,可能需要为表达式定义的列手工输入一个类型。在大多数情况下,用户不需要修改这个数据类型。" ], - "There was an issue favoriting this dashboard.": [ - "收藏看板时候出现问题。" + "The database %s is linked to %s charts that appear on %s dashboards and users have %s SQL Lab tabs using this database open. Are you sure you want to continue? Deleting the database will break those objects.": [ + "数据库 %s 已经关联了 %s 图表和 %s 看板。确定要继续吗?删除数据库将破坏这些对象。" ], - "This dashboard is now ${nowPublished}": ["当前看板 ${nowPublished}"], - "You do not have permissions to edit this dashboard.": [ - "您没有编辑此看板的权限。" + "The database is currently running too many queries.": [ + "数据库当前运行的查询太多" ], - "This dashboard was saved successfully.": ["该看板已成功保存。"], - "Could not fetch all saved charts": ["无法获取所有保存的图表"], - "Sorry there was an error fetching saved charts: ": [ - "抱歉,这个看板在获取图表时发生错误:" + "The database is under an unusual load.": ["数据库负载异常。"], + "The database referenced in this query was not found. Please contact an administrator for further assistance or try again.": [ + "找不到此查询中引用的数据库。请与管理员联系以获得进一步帮助,或重试。" ], - "Visualization": ["可视化模式"], - "Data source": ["数据源"], - "Added": ["已添加"], - "Components": ["组件"], - "Any color palette selected here will override the colors applied to this dashboard's individual charts": [ - "此处选择的任何调色板都将覆盖应用于此看板的各个图表的颜色" + "The database returned an unexpected error.": ["数据库返回意外错误。"], + "The database was deleted.": ["数据集已保存"], + "The database was not found.": ["数据库没有找到"], + "The dataset %s is linked to %s charts that appear on %s dashboards. Are you sure you want to continue? Deleting the dataset will break those objects.": [ + "数据集 %s 已经链接到 %s 图表和 %s 看板内。确定要继续吗?删除数据集将破坏这些对象。" ], - "Color scheme": ["配色方案"], - "Load a template": ["加载一个模板"], - "Load a CSS template": ["加载一个 CSS 模板"], - "Live CSS editor": ["即时 CSS 编辑器"], - "You have unsaved changes.": ["您有一些未保存的修改。"], - "This dashboard is currently force refreshing; the next force refresh will be in %s.": [ - "此看板当前正在强制刷新;下一次强制刷新将在 %s 内执行。" + "The dataset associated with this chart no longer exists": [ + "这个图表所链接的数据集可能被删除了。" ], - "Your dashboard is too large. Please reduce the size before save it.": [ - "您的看板太大了。保存前请缩小尺寸。" + "The dataset configuration exposed here\n affects all the charts using this dataset.\n Be mindful that changing settings\n here may affect other charts\n in undesirable ways.": [ + "这里公开的数据集配置会影响使用此数据集的所有图表。请注意,更改此处的设置可能会以未预想的方式影响其他图表。" ], - "Discard changes": ["放弃更改"], - "An error occurred while fetching available CSS templates": [ - "获取可用的CSS模板时出错" + "The dataset has been saved": ["数据集已保存"], + "The dataset linked to this chart may have been deleted.": [ + "这个图表所链接的数据集可能被删除了。" ], - "Superset dashboard": ["看板"], - "Check out this dashboard: ": ["查看此看板:"], - "Refresh dashboard": ["刷新看板"], - "Set auto-refresh interval": ["设置自动刷新"], - "Set filter mapping": ["设置过滤映射"], - "Edit dashboard properties": ["编辑看板属性"], - "Edit CSS": ["编辑CSS"], - "Download as image": ["下载为图片"], - "Toggle fullscreen": ["切换全屏"], - "There is no chart definition associated with this component, could it have been deleted?": [ - "没有与此组件关联的图表定义,是否已将其删除?" + "The datasource couldn't be loaded": ["这个查询无法被加载"], + "The datasource is too large to query.": ["数据源太大,无法进行查询。"], + "The description can be displayed as widget headers in the dashboard view. Supports markdown.": [ + "作为为小部件标题可以在仪表板视图中显示的描述,支持markdown格式语法。" ], - "Delete this container and save to remove this message.": [ - "删除此容器并保存以删除此邮件。" + "The distance between cells, in pixels": [ + "单元格之间的距离,以像素为单位" ], - "An error has occurred": ["发生了一个错误"], - "You do not have permission to edit this dashboard": [ - "您没有编辑此看板的权限" + "The duration of time in seconds before the cache is invalidated": [ + "缓存失效前的持续时间(以秒为单位)" ], - "A valid color scheme is required": ["需要有效的配色方案"], - "The dashboard has been saved": ["该看板已成功保存。"], - "Apply": ["应用"], - "Dashboard properties": ["看板属性"], - "Basic information": ["基本情况"], - "URL slug": ["使用 Slug"], - "A readable URL for your dashboard": ["为看板生成一个可读的 URL"], - "Access": ["访问"], - "Owners is a list of users who can alter the dashboard. Searchable by name or username.": [ - "所有者是可以更改看板的用户列表。可按名称或用户名搜索。" + "The engine_params object gets unpacked into the sqlalchemy.create_engine call.": [ + "1. engine_params 对象在调用 sqlalchemy.create_engine 时被引用, metadata_params 在调用 sqlalchemy.MetaData 时被引用。" ], - "Colors": ["颜色"], - "Advanced": ["进阶"], - "JSON metadata": ["JSON 元数据"], - "This dashboard is not published, it will not show up in the list of dashboards. Click here to publish this dashboard.": [ - "此看板未发布,它将不会显示在看板列表中。单击此处以发布此看板。" + "The following entries in `series_columns` are missing in `columns`: %(columns)s. ": [ + " `series_columns`中的下列条目在 `columns` 中缺失: %(columns)s. " ], - "This dashboard is not published which means it will not show up in the list of dashboards. Favorite it to see it there or access it by using the URL directly.": [ - "此看板未发布,这意味着它不会显示在仪表板列表中。您可以进行收藏并在收藏栏中查看或直接使用URL访问它。" + "The following tables added new columns: %(tables)s": [ + "下表添加了新列:%(tables)s" ], - "This dashboard is published. Click to make it a draft.": [ - "此看板已发布。单击以使其成为草稿。" + "The following tables removed columns: %(tables)s": [ + "下表删除了列:%(tables)s" ], - "Draft": ["草稿"], - "Don't refresh": ["不要刷新"], - "10 seconds": ["10秒钟"], - "30 seconds": ["30秒钟"], - "1 minute": ["1分钟"], - "5 minutes": ["5分钟"], - "30 minutes": ["30分钟"], - "1 hour": ["1小时"], - "6 hours": ["6小时"], - "12 hours": ["12小时"], - "24 hours": ["24 小时"], - "Refresh interval": ["刷新间隔"], - "Refresh frequency": ["刷新频率"], - "Are you sure you want to proceed?": ["您确定要继续执行吗?"], - "Save for this session": ["保存此会话"], - "You must pick a name for the new dashboard": [ - "您必须为新的看板选择一个名称" + "The following tables update column metadata: %(tables)s": [ + "下表更新列元数据:%(tables)s" ], - "Save dashboard": ["保存看板"], - "Overwrite Dashboard [%s]": ["覆盖看板 [%s]"], - "Save as:": ["另存为:"], - "[dashboard name]": ["[看板名称]"], - "also copy (duplicate) charts": ["同时复制图表"], - "Filter your charts": ["过滤您的图表"], - "Annotation layers are still loading.": ["注释层仍在加载。"], - "One ore more annotation layers failed loading.": [ - "一个或多个注释层加载失败。" + "The host \"%(hostname)s\" might be down and can't be reached.": [ + "主机 \"%(hostname)s\" 可能已关闭,无法连接到" ], - "Cached %s": ["缓存于%s"], - "Fetched %s": ["刷新于 %s"], - "Minimize chart": ["最小化图表"], - "Maximize chart": ["最大化图表"], - "Force refresh": ["强制刷新"], - "Toggle chart description": ["切换图表说明"], - "View chart in Explore": ["查看图表"], - "Share chart": ["共享图表"], - "Export CSV": ["导出 CSV"], - "Applied Filters (%d)": ["应用的条件 (%d)"], - "Incompatible Filters (%d)": ["不兼容的条件 (%d)"], - "Unset Filters (%d)": ["未选择的条件 (%d)"], - "Search...": ["搜索..."], - "No filter is selected.": ["未选择过滤条件。"], - "Editing 1 filter:": ["编辑1个过滤条件:"], - "Batch editing %d filters:": ["批量编辑 %d 个过滤条件:"], - "Configure filter scopes": ["配置过滤范围"], - "There are no filters in this dashboard.": ["此看板中没有过滤条件。"], - "Expand all": ["全部展开"], - "Collapse all": ["全部折叠"], - "This markdown component has an error.": ["此 markdown 组件有错误。"], - "This markdown component has an error. Please revert your recent changes.": [ - "此 markdown 组件有错误。请还原最近的更改。" + "The host \"%(hostname)s\" might be down, and can't be reached on port %(port)s.": [ + "主机 \"%(hostname)s\" 可能已关闭,无法通过端口访问 " ], - "Delete dashboard tab?": ["是否删除tab页?"], - "Divider": ["分隔"], - "Header": ["标题行"], - "Row": ["行"], - "Tabs": [""], - "Preview": ["预览"], - "Yes, cancel": ["是的,取消"], - "Keep editing": ["继续编辑"], - "Select parent filters": ["选择父级过滤"], - "Reset all": ["全部重置"], - "You have removed this filter.": ["您已删除此过滤条件。"], - "Restore filter": ["还原过滤条件"], - "Filter name": ["过滤值"], - "Name is required": ["需要名称"], - "Datasource is required": ["需要数据源"], - "Field": ["字段"], - "Parent filter": ["父级过滤"], - "None": ["空"], - "Apply changes instantly": ["立即应用更改"], - "Allow multiple selections": ["允许多选"], - "Inverse selection": ["反选"], - "Required": ["必填"], - "Are you sure you want to cancel?": ["您确定要取消吗?"], - "will not be saved.": ["不会被保存。"], - "Filter configuration and scoping": ["过滤配置和范围"], - "Add filter": ["增加过滤条件"], - "(Removed)": ["(已删除)"], - "Undo?": ["撤消?"], - "Scoping": ["范围"], - "Apply to all panels": ["应用于所有面板"], - "Apply to specific panels": ["应用于特定面板"], - "Only selected panels will be affected by this filter": [ - "只有选定的面板将受此过滤条件的影响" + "The host is invalid. Please verify that this field is entered correctly.": [ + "主机无效。请检查此字段是否输入正确。" + ], + "The host might be down, and can't be reached on the provided port.": [ + "主机可能宕机了,无法在所提供的端口上连接到它" + ], + "The hostname \"%(hostname)s\" cannot be resolved.": [ + "无法解析主机名 \"%(hostname)s\" " + ], + "The hostname provided can't be resolved.": ["提供的主机名无法解析。"], + "The id of the active chart": ["活动图表的ID"], + "The import was successful": ["导入成功"], + "The list of charts associated with this table. By altering this datasource, you may change how these associated charts behave. Also note that charts need to point to a datasource, so this form will fail at saving if removing charts from a datasource. If you want to change the datasource for a chart, overwrite the chart from the 'explore view'": [ + "与此表关联的图表列表。通过更改此数据源,您可以更改这些相关图表的行为。还要注意,图表需要指向数据源,如果从数据源中删除图表,则此窗体将无法保存。如果要为图表更改数据源,请从“浏览视图”更改该图表。" + ], + "The maximum number of events to return, equivalent to the number of rows": [ + "返回的最大事件数,相当于行数" + ], + "The maximum number of subdivisions of each group; lower values are pruned first": [ + "每组的最大细分数;较低的值首先被删除" + ], + "The maximum value of metrics. It is an optional configuration": [ + "度量的最大值。这是一个可选配置" + ], + "The metadata_params in Extra field is not configured correctly. The key %(key)s is invalid.": [ + "额外字段中的元数据参数配置不正确。键 %(key)s 无效。" + ], + "The metadata_params in Extra field is not configured correctly. The key %{key}s is invalid.": [ + "额外字段中的元数据参数配置不正确。键 %{key}s 无效。" + ], + "The metadata_params object gets unpacked into the sqlalchemy.MetaData call.": [ + "metadata_params对象被解压缩到sqlalchemy.metadata调用中。" + ], + "The minimum number of rolling periods required to show a value. For instance if you do a cumulative sum on 7 days you may want your \"Min Period\" to be 7, so that all data points shown are the total of 7 periods. This will hide the \"ramp up\" taking place over the first 7 periods": [ + "显示值所需的滚动周期的最小值。例如,如果您想累积 7 天的总额,您可能希望您的“最小周期”为 7,以便显示的所有数据点都是 7 个区间的总和。这将隐藏掉前 7 个阶段的“加速”效果" + ], + "The number color \"steps\"": ["色彩 \"Steps\" 数字"], + "The number of hours, negative or positive, to shift the time column. This can be used to move UTC time to local time.": [ + "用于移动时间列的小时数(负数或正数)。这可用于将UTC时间移动到本地时间" + ], + "The number of results displayed is limited to %(rows)d by the configuration DISPLAY_MAX_ROWS. Please add additional limits/filters or download to csv to see more rows up to the %(limit)d limit.": [ + "显示的结果数由配置DISPLAY_MAX_rows限制为 %(rows)d 。请添加其他限制/筛选器或下载到csv以查看更多行数,限制为 %(limit)d " + ], + "The number of results displayed is limited to %(rows)d. Please add additional limits/filters, download to csv, or contact an admin to see more rows up to the %(limit)d limit.": [ + "显示的结果数限制为 %(rows)d。请添加其他筛选器,下载到csv,或与管理员联系以查看 %(limit)d 的更多行”" + ], + "The number of rows displayed is limited to %(rows)d by the limit dropdown.": [ + "显示的行数通过限制下拉框限制为 %(rows)d 。" + ], + "The number of rows displayed is limited to %(rows)d by the query": [ + "查询将显示的行数限制为 %(rows)d " + ], + "The number of rows displayed is limited to %(rows)d by the query and limit dropdown.": [ + "查询和限制下拉列表将显示的行数限制为 %(rows)d" + ], + "The number of rows displayed is limited to %s by the dropdown.": [ + "通过下拉菜单显示的行数限制为 %s " + ], + "The number of seconds before expiring the cache": [ + "终止缓存前的时间(秒)" + ], + "The object does not exist in the given database.": [ + "源数据库中存在的表的名称" + ], + "The parameter %(parameters)s in your query is undefined.": [ + "查询中的以下参数未定义:%(parameters)s 。" + ], + "The password provided for username \"%(username)s\" is incorrect.": [ + "用户名 \"%(username)s\" 提供的密码不正确。" + ], + "The password provided when connecting to a database is not valid.": [ + "连接数据库时提供的密码无效。" + ], + "The passwords for the databases below are needed in order to import them together with the charts. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "需要以下数据库的密码才能将其与图表一起导入。请注意,数据库配置的 \"Secure Extra\" 和 \"Certificate\" 部分不在导出文件中,如果需要,应在导入后手动添加。" ], - "All panels with this column will be affected by this filter": [ - "包含此列的所有面板都将受到此过滤条件的影响" + "The passwords for the databases below are needed in order to import them together with the dashboards. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "需要以下数据库的密码才能将它们与仪表板一起导入。请注意,数据库配置的 \"Secure Extra\" 和 \"Certificate\" 部分不在导出文件中,如果需要,应在导入后手动添加。" ], - "All filters": ["所有过滤"], - "All charts": ["所有图表"], - "Warning! Changing the dataset may break the chart if the metadata does not exist.": [ - "警告!如果元数据不存在,更改数据集可能会破坏图表。" + "The passwords for the databases below are needed in order to import them together with the datasets. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "需要以下数据库的密码才能将其与数据集一起导入。请注意,数据库配置的 \"Secure Extra\" 和 \"Certificate\" 部分不在导出文件中,如果需要,应在导入后手动添加。" ], - "Changing the dataset may break the chart if the chart relies on columns or metadata that does not exist in the target dataset": [ - "如果图表依赖于目标数据集中不存在的列或元数据,则更改数据集可能会破坏图表" + "The passwords for the databases below are needed in order to import them together with the saved queries. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "需要以下数据库的密码才能将其与图表一起导入。请注意,数据库配置的 \"Secure Extra\" 和 \"Certificate\" 部分不在导出文件中,如果需要,应在导入后手动添加。" + ], + "The passwords for the databases below are needed in order to import them. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ + "需要以下数据库的密码才能导入它们。请注意,数据库配置的 \"Secure Extra\" 和 \"Certificate\" 部分不在导出文件中。如果需要,应在导入后手动添加。" ], - "dataset": ["数据集"], - "Change dataset": ["修改数据集"], - "Warning!": ["警告!"], - "Search / Filter": ["搜索 / 过滤"], - "Physical (table or view)": ["物理(表或视图)"], - "Virtual (SQL)": ["虚拟(SQL)"], - "SQL expression": ["SQL表达式"], - "Data type": ["数据类型"], - "Datetime format": ["时间格式"], "The pattern of timestamp format. For strings use ": [ "时间戳格式的模式。供字符串使用 " ], - "Python datetime string pattern": ["Python日期格式模板"], - " expression which needs to adhere to the ": [" 表达式并基于 "], - "ISO 8601": [""], - " standard to ensure that the lexicographical ordering\n coincides with the chronological ordering. If the\n timestamp format does not adhere to the ISO 8601 standard\n you will need to define an expression and type for\n transforming the string into a date or timestamp. Note\n currently time zones are not supported. If time is stored\n in epoch format, put `epoch_s` or `epoch_ms`. If no pattern\n is specified we fall back to using the optional defaults on a per\n database/column name level via the extra parameter.": [ - "来确保字符的表达顺序与时间顺序一致的标准。如果时间戳格式不符合 ISO 8601 标准,则需要定义表达式和类型,以便将字符串转换为日期或时间戳。注意:当前不支持时区。如果时间以epoch格式存储,请输入 `epoch_s` or `epoch_ms` 。如果没有指定任何模式,我们可以通过额外的参数在每个数据库/列名级别上使用可选的默认值。" + "The periodicity over which to pivot time. Users can provide\n \"Pandas\" offset alias.\n Click on the info bubble for more details on accepted \"freq\" expressions.": [ + "旋转时间的周期性。" ], - "Is dimension": ["维度"], - "Is filterable": ["可被过滤"], - "Modified columns: %s": ["修改的列:%s"], - "Removed columns: %s": ["删除的列:%s"], - "New columns added: %s": ["新增的列:%s"], - "Metadata has been synced": ["元数据已同步"], - "Column name [%s] is duplicated": ["列名 [%s] 重复"], - "Metric name [%s] is duplicated": ["指标名称 [%s] 重复"], - "Calculated column [%s] requires an expression": [ - "计算列 [%s] 需要一个表达式" + "The pixel radius": ["像素半径"], + "The pointer to a physical table (or view). Keep in mind that the chart is associated to this Superset logical table, and this logical table points the physical table referenced here.": [ + "指向物理表(或视图)的指针。请记住,图表将与此逻辑表相关联,并且此逻辑表指向此处引用的物理表。" ], - "Basic": ["基础"], - "Default URL": ["默认URL"], - "Default URL to redirect to when accessing from the dataset list page": [ - "从数据集列表页访问时重定向到的默认URL" + "The port is closed.": ["报告失败"], + "The port must be a whole number less than or equal to 65535.": [ + "`行限制` 必须大于或等于1" ], - "Autocomplete filters": ["自适配过滤条件"], - "Whether to populate autocomplete filters options": [ - "是否填充自适配过滤条件选项" + "The port number is invalid.": ["数据库参数无效"], + "The primary metric is used to define the arc segment sizes": [ + "主计量指标用于定义弧段大小。" ], - "Autocomplete query predicate": ["自动补全查询谓词"], - "When using \"Autocomplete filters\", this can be used to improve performance of the query fetching the values. Use this option to apply a predicate (WHERE clause) to the query selecting the distinct values from the table. Typically the intent would be to limit the scan by applying a relative time filter on a partitioned or indexed time-related field.": [ - "当使用 \"自适配过滤条件\" 时,这可以用来提高获取查询数据的性能。使用此选项可将谓词(WHERE子句)应用于从表中进行选择不同值的查询。通常,这样做的目的是通过对分区或索引的相关时间字段配置相对应的过滤时间来限制扫描。" + "The provided `rows` argument is not a valid integer.": [ + "提供的 `rows` 参数不是有效整数。" ], - "Extra data to specify table metadata. Currently supports certification data of the format: `{ \"certification\": { \"certified_by\": \"Data Platform Team\", \"details\": \"This table is the source of truth.\" } }`.": [ - "指定表元数据的额外内容。目前支持的认证数据格式为:`{ \"certification\": { \"certified_by\": \"Data Platform Team\", \"details\": \"This table is the source of truth.\" } }`." + "The query associated with the results was deleted.": [ + "删除与结果关联的查询。" ], - "Owners of the dataset": ["数据集的所有者"], - "Cache timeout": ["缓存时间"], - "The duration of time in seconds before the cache is invalidated": [ - "缓存失效前的持续时间(以秒为单位)" + "The query associated with these results could not be find. You need to re-run the original query.": [ + "找不到与这些结果相关联的查询。你需要重新运行查询" ], - "Hours offset": ["小时偏移"], - "Spatial": ["空间"], - "virtual": ["虚拟信息"], - "Dataset name": ["数据集名称"], - "When specifying SQL, the datasource acts as a view. Superset will use this statement as a subquery while grouping and filtering on the generated parent queries.": [ - "指定SQL时,数据源会充当视图。在对生成的父查询进行分组和筛选时,系统将使用此语句作为子查询。" + "The query contains one or more malformed template parameters.": [ + "该查询包含一个或多个格式不正确的模板参数。" ], - "The JSON metric or post aggregation definition.": [ - "JSON指标或处理聚合定义。" + "The query couldn't be loaded": ["这个查询无法被加载"], + "The query has a syntax error.": ["查询有语法错误。"], + "The query returned no data": ["查询无结果"], + "The query was killed after %(sqllab_timeout)s seconds. It might be too complex, or the database might be under heavy load.": [ + "查询在 %(sqllab_timeout)s 秒后被终止。它可能太复杂,或者数据库可能负载过重。" ], - "Physical": ["物理信息"], - "The pointer to a physical table (or view). Keep in mind that the chart is associated to this Superset logical table, and this logical table points the physical table referenced here.": [ - "指向物理表(或视图)的指针。请记住,图表将与此逻辑表相关联,并且此逻辑表指向此处引用的物理表。" + "The radius (in pixels) the algorithm uses to define a cluster. Choose 0 to turn off clustering, but beware that a large number of points (>1000) will cause lag.": [ + "算法用来定义一个簇的半径(以像素为单位)。选择0关闭聚,但要注意大量的点(>1000)会导致处理时间变长。" ], - "Click the lock to make changes.": ["单击锁以进行更改。"], - "Click the lock to prevent further changes.": [ - "单击锁定以防止进一步更改。" + "The radius of individual points (ones that are not in a cluster). Either a numerical column or `Auto`, which scales the point based on the largest cluster": [ + "单个点的半径(不在簇中的点)。一个数值列或“AUTO”,它根据最大的聚类来缩放点。" ], - "D3 format": ["D3 格式"], - "Warning message": ["告警信息"], - "Warning message to display in the metric selector": [ - "要在指标选择器中显示的警告消息" + "The report has been created": ["数据集已保存"], + "The results backend no longer has the data from the query.": [ + "结果后端不再拥有来自查询的数据。" ], - "Certified by": ["认证"], - "Person or group that has certified this metric": [ - "认证此指标的个人或团体" + "The results stored in the backend were stored in a different format, and no longer can be deserialized.": [ + "后端存储的结果以不同的格式存储,而且不再可以反序列化" ], - "Certification details": ["认证细节"], - "Details of the certification": ["认证详情"], - "Be careful.": ["小心。"], - "Changing these settings will affect all charts using this dataset, including charts owned by other people.": [ - "更改这些设置将影响使用此数据集的所有图表,包括其他人拥有的图表。" + "The rich tooltip shows a list of all series for that point in time": [ + "详细提示显示了该时间点的所有序列的列表。" ], - "Source": ["来源"], - "Sync columns from source": ["从源同步列"], - "Calculated columns": ["计算列"], - "The dataset has been saved": ["数据集已保存"], - "The dataset configuration exposed here\n affects all the charts using this dataset.\n Be mindful that changing settings\n here may affect other charts\n in undesirable ways.": [ - "这里公开的数据集配置会影响使用此数据集的所有图表。请注意,更改此处的设置可能会以未预想的方式影响其他图表。" + "The schema \"%(schema)s\" does not exist. A valid schema must be used to run this query.": [ + "表 \"%(schema)s\" 不存在。必须使用有效的表来运行此查询。" ], - "Are you sure you want to save and apply changes?": [ - "确实要保存并应用更改吗?" + "The schema \"%(schema_name)s\" does not exist. A valid schema must be used to run this query.": [ + "表 \"%(schema_name)s\" 不存在。必须使用有效的表来运行此查询。" ], - "Confirm save": ["确认保存"], - "Edit Dataset ": ["编辑数据集"], - "Use legacy datasource editor": ["使用旧数据源编辑器"], - "Time range": ["时间范围"], - "Time column": ["时间列"], - "Time grain": ["时间粒度(grain)"], - "Origin": ["起点"], - "Time granularity": ["时间粒度(granularity)"], - "A reference to the [Time] configuration, taking granularity into account": [ - "对 [时间] 配置的引用,会将粒度考虑在内" + "The schema was deleted or renamed in the database.": [ + "该列已在数据库中删除或重命名。" ], - "Group by": ["分组"], - "One or many controls to group by": ["一个或多个控件来分组"], - "One or many metrics to display": ["一个或多个指标显示"], - "Dataset": ["数据集"], - "Visualization type": ["可视化类型"], - "The type of visualization to display": ["要显示的可视化类型"], - "Fixed color": ["固定颜色"], - "Use this to define a static color for all circles": [ - "使用此定义所有圆圈的静态颜色" + "The size of the square cell, in pixels": [ + "平方单元的大小,以像素为单位" ], - "Right axis metric": ["右轴指标"], - "Choose a metric for right axis": ["为右轴选择一个指标"], - "Linear color scheme": ["线性颜色方案"], - "Color metric": ["颜色指标"], - "A metric to use for color": ["用于颜色的指标"], - "One or many controls to pivot as columns": ["一个或多个控件作为主列"], - "Defines the origin where time buckets start, accepts natural dates as in `now`, `sunday` or `1970-01-01`": [ - "定义时间桶的起点,接受 `now`,`sunday` 或 `1970-01-01` 等格式的日期表达" + "The submitted payload has the incorrect format.": [ + "提交的有效载荷格式不正确" ], - "The time granularity for the visualization. Note that you can type and use simple natural language as in `10 seconds`, `1 day` or `56 weeks`": [ - "可视化的时间粒度。请注意,您可以输入和使用简单的日期表达方式,如 `10 seconds`, `1 day` or `56 weeks`" + "The submitted payload has the incorrect schema.": [ + "提交的有效负载的模式不正确。" + ], + "The table \"%(table)s\" does not exist. A valid table must be used to run this query.": [ + "表 \"%(table)s\" 不存在。必须使用有效的表来运行此查询。" + ], + "The table \"%(table_name)s\" does not exist. A valid table must be used to run this query.": [ + "表 \"%(table_name)s\" 不存在。必须使用有效的表来运行此查询。" + ], + "The table was created. As part of this two-phase configuration process, you should now click the edit button by the new table to configure it.": [ + "表被创建。作为这两个阶段配置过程的一部分,您现在应该单击新表的编辑按钮来配置它。" + ], + "The table was deleted or renamed in the database.": [ + "Issue 1005 - 该表已在数据库中删除或重命名。" ], "The time column for the visualization. Note that you can define arbitrary expression that return a DATETIME column in the table. Also note that the filter below is applied against this column or expression": [ "可视化的时间栏。注意,您可以定义返回表中的DATETIMLE列的任意表达式。还请注意下面的筛选器应用于该列或表达式。" ], + "The time granularity for the visualization. Note that you can type and use simple natural language as in `10 seconds`, `1 day` or `56 weeks`": [ + "可视化的时间粒度。请注意,您可以输入和使用简单的日期表达方式,如 `10 seconds`, `1 day` or `56 weeks`" + ], "The time granularity for the visualization. This applies a date transformation to alter your time column and defines a new time granularity. The options here are defined on a per database engine basis in the Superset source code.": [ "可视化的时间粒度。这将应用日期转换来更改时间列,并定义新的时间粒度。这里的选项是在 Superset 源代码中的每个数据库引擎基础上定义的。" ], - "Last week": ["上周"], "The time range for the visualization. All relative times, e.g. \"Last month\", \"Last 7 days\", \"now\", etc. are evaluated on the server using the server's local time (sans timezone). All tooltips and placeholder times are expressed in UTC (sans timezone). The timestamps are then evaluated by the database using the engine's local timezone. Note one can explicitly set the timezone per the ISO 8601 format if specifying either the start and/or end time.": [ "可视化的时间范围。所有相关的时间,例如\"上个月\"、\"过去7天\"、\"现在\"等,都在服务器上使用服务器的本地时间(sans时区)进行计算。所有工具提示和占位符时间均以UTC(无时区)表示。然后,数据库使用引擎的本地时区来评估时间戳。注:如果指定开始时间和、或者结束时间,可以根据ISO 8601格式显式设置时区。" ], - "Row limit": ["行限制"], - "Series limit": ["序列限制"], - "Limits the number of time series that get displayed. A sub query (or an extra phase where sub queries are not supported) is applied to limit the number of time series that get fetched and displayed. This feature is useful when grouping by high cardinality dimension(s).": [ - "限制显示的时间序列的数量。应用子查询(或者不支持子查询)来限制获取和显示的时间序列的数量。在高基数维度(S)分组时,此特性是有用的。" + "The time unit for each block. Should be a smaller unit than domain_granularity. Should be larger or equal to Time Grain": [ + "每个块的时间单位。应该是主域域粒度更小的单位。应该大于或等于时间粒度" ], - "Sort by": ["排序 "], - "Metric used to define the top series": ["用于定义顶级序列的指标"], - "Series": ["序列"], - "Defines the grouping of entities. Each series is shown as a specific color on the chart and has a legend toggle": [ - "定义实体的分组。每个序列在图表上显示为特定颜色,并有一个可切换的图例" + "The time unit used for the grouping of blocks": ["用于块分组的时间单位"], + "The type of visualization to display": ["要显示的可视化类型"], + "The unit of measure for the specified point radius": [ + "指定点半径的度量单位" ], - "Entity": ["实体"], - "This defines the element to be plotted on the chart": [ - "这定义了要在图表上绘制的元素" + "The user seems to have been deleted": ["用户已经被删除"], + "The username \"%(username)s\" does not exist.": [ + "指标 '%(username)s' 不存在" ], - "X Axis": ["X 轴"], - "Metric assigned to the [X] axis": ["分配给 [X] 轴的指标"], - "Y Axis": ["Y 轴"], - "Metric assigned to the [Y] axis": ["分配给 [Y] 轴的指标"], - "Bubble size": ["气泡尺寸"], - "Y Axis Format": ["Y 轴格式化"], - "When `Calculation type` is set to \"Percentage change\", the Y Axis Format is forced to `.1%`": [ - "当设置“周期比”时,y轴格式强制为“1%”。" + "The username provided when connecting to a database is not valid.": [ + "连接到数据库时提供的用户名无效。" ], - "The color scheme for rendering chart": ["绘制图表的配色方案"], - "Color map": ["彩色地图"], - "description": ["描述"], - "bolt": ["螺栓"], - "Changing this control takes effect instantly": ["更改此控件立即生效。"], - "Customize": ["定制化配置"], - "rows retrieved": ["行被检索到"], - "Sorry, An error occurred": ["抱歉,发生错误"], - "No data": ["没有数据"], - "View samples": ["查看样例"], - "Search Metrics & Columns": ["搜索指标和列"], - "Showing %s of %s": ["显示 %s个 总计 %s个"], - "New chart": ["新增图表"], - "Edit properties": ["编辑属性"], - "View query": ["检查查询"], - "Run in SQL Lab": ["在 SQL 工具箱中执行"], - "Height": ["高度"], - "Width": ["宽度"], - "Export to .json": ["导出到 .json"], - "Export to .csv format": ["导出为 .csv 格式"], - "%s - untitled": ["%s - 无标题"], - "Edit chart properties": ["编辑图表属性"], - "Control labeled ": ["控件名称为 "], - "Open Datasource tab": ["打开数据源tab"], - "You do not have permission to edit this chart": [ - "您没有编辑此图表的权限" + "The way the ticks are laid out on the X-axis": ["X轴记号的排列显示方式"], + "There are associated alerts or reports": ["存在关联的警报或报告"], + "There are associated alerts or reports: %s,": [ + "存在关联的警报或报告:%s," + ], + "There are no filters in this dashboard.": ["此看板中没有过滤条件。"], + "There are unsaved changes.": ["您有一些未保存的修改。"], + "There is a syntax error in the SQL query. Perhaps there was a misspelling or a typo.": [ + "Issue 1003 - SQL查询中存在语法错误。可能是拼写错误或是打错关键字。" + ], + "There is no chart definition associated with this component, could it have been deleted?": [ + "没有与此组件关联的图表定义,是否已将其删除?" + ], + "There is not enough space for this component. Try decreasing its width, or increasing the destination width.": [ + "此组件没有足够的空间。请尝试减小其宽度,或增加目标宽度。" + ], + "There was an error fetching the favorite status: %s": [ + "获取此看板的收藏夹状态时出现问题。" + ], + "There was an error fetching your recent activity:": [ + "获取您最近的活动时出错:" + ], + "There was an error loading the schemas": [ + "抱歉,这个看板在获取图表时发生错误:" + ], + "There was an error loading the tables": ["您的请求有错误"], + "There was an error saving the favorite status: %s": [ + "获取此看板的收藏夹状态时出现问题: %s" + ], + "There was an error with your request": ["您的请求有错误"], + "There was an issue deleting %s: %s": ["删除 %s 时出现问题:%s"], + "There was an issue deleting the selected %s: %s": [ + "删除所选 %s 时出现问题: %s" + ], + "There was an issue deleting the selected annotations: %s": [ + "删除所选注释时出现问题:%s" + ], + "There was an issue deleting the selected charts: %s": [ + "删除所选图表时出现问题:%s" + ], + "There was an issue deleting the selected dashboards: ": [ + "删除所选仪表板时出现问题:" + ], + "There was an issue deleting the selected datasets: %s": [ + "删除选定的数据集时出现问题:%s" + ], + "There was an issue deleting the selected layers: %s": [ + "删除所选图层时出现问题:%s" + ], + "There was an issue deleting the selected queries: %s": [ + "删除所选查询时出现问题:%s" + ], + "There was an issue deleting the selected templates: %s": [ + "删除所选模板时出现问题:%s" + ], + "There was an issue deleting: %s": ["删除时出现问题:%s"], + "There was an issue favoriting this dashboard.": [ + "收藏看板时候出现问题。" + ], + "There was an issue fetching reports attached to this dashboard.": [ + "获取此看板的收藏夹状态时出现问题。" + ], + "There was an issue fetching the favorite status of this dashboard.": [ + "获取此看板的收藏夹状态时出现问题。" + ], + "There was an issue fetching your recent activity: %s": [ + "获取您最近的活动时出错:" + ], + "There was an issue previewing the selected query %s": [ + "预览所选查询时出现问题 %s" + ], + "There was an issue previewing the selected query. %s": [ + "预览所选查询时出现问题。%s" + ], + "There was an issues fetching your chart: %s": ["删除时出现问题:%s"], + "There was an issues fetching your dashboards: %s": [ + "删除所选仪表板时出现问题:" + ], + "There was an issues fetching your saved queries: %s": [ + "删除所选查询时出现问题:%s" ], - "The description can be displayed as widget headers in the dashboard view. Supports markdown.": [ - "作为为小部件标题可以在仪表板视图中显示的描述,支持markdown格式语法。" + "There's a loop in your Sankey, please provide a tree. Here's a faulty link: {}": [ + "桑基图里面有一个循环,请提供一棵树。这是一个错误的链接:{}" ], - "Configuration": ["配置"], - "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the dataset's timeout if undefined.": [ - "此图表的缓存超时前的持续时间(秒)。请注意,如果未定义则默认为数据集的超时时间。" + "These are the tables this filter will be applied to.": [ + "这些是将应用此过滤的表。" ], - "A list of users who can alter the chart. Searchable by name or username.": [ - "有权处理该图表的用户列表。可按名称或用户名搜索。" + "These filters apply to the values available in the dropdowns": [ + "这些过滤器应用于下拉列表中的可用值" ], - "rows": ["行"], - "Limit reached": ["达到限制"], - "**Select** a dashboard OR **create** a new one": [ - "**选择** 一个看板或者 **创建** 一个看板" + "These parameters are generated dynamically when clicking the save or overwrite button in the explore view. This JSON object is exposed here for reference and for power users who may want to alter specific parameters.": [ + "这些参数是在浏览视图中单击保存或覆盖按钮时动态生成的。这个JSON对象在这里公开以供参考,并提供给可能希望更改特定参数的高级用户使用。" ], - "Please enter a chart name": ["请输入图表名称"], - "Save chart": ["图表保存"], - "Save & go to dashboard": ["保存并转到看板"], - "Save as new chart": ["创建新图表"], - "Save (Overwrite)": ["保存(覆盖)"], - "Save as ...": ["另存为"], - "Chart name": ["图表名称"], - "Add to dashboard": ["添加到看板"], - "Display configuration": ["显示配置"], - "Configure your how you overlay is displayed here.": [ - "配置如何在这里显示您的覆盖。" + "This JSON object is generated dynamically when clicking the save or overwrite button in the dashboard view. It is exposed here for reference and for power users who may want to alter specific parameters.": [ + "这个JSON对象描述了部件在看板中的位置。它是动态生成的,可以通过拖放,在看板中调整整部件的大小和位置" ], - "Style": ["风格"], - "Opacity": ["不透明度"], - "Color": ["颜色"], - "Line width": ["线宽"], - "Layer configuration": ["配置Layer"], - "Configure the basics of your Annotation Layer.": ["注释层基本配置"], - "Mandatory": ["必填参数"], - "Hide layer": ["隐藏Layer"], - "Choose the annotation layer type": ["选择注释层类型"], - "Annotation layer type": ["注释层类型"], - "Remove": ["删除"], - "Edit annotation layer": ["添加注释层"], - "Add annotation layer": ["添加注释层"], - "`Min` value should be numeric or empty": ["最小值应该是数字或空的"], - "`Max` value should be numeric or empty": ["最大值应该是数字或空的"], - "Min": ["最小值"], - "Max": ["最大值"], - "Edit dataset": ["编辑数据集"], - "View in SQL Lab": ["在 SQL 工具箱中公开"], - "More dataset related options": ["更多数据集相关选项"], - "Superset supports smart date parsing. Strings like `3 weeks ago`, `last sunday`, or `2 weeks from now` can be used.": [ - "系统支持智能的时间格式化。文本类似 `last sunday` 或者 `last october`这样的语句也可以被识别。" + "This action will permanently delete %s.": ["此操作将永久删除 %s 。"], + "This action will permanently delete the layer.": [ + "此操作将永久删除图层。" ], - "Default": ["默认"], - "(optional) default value for the filter, when using the multiple option, you can use a semicolon-delimited list of options.": [ - "过滤器的默认值,当使用多选框的时候,您可以使用带分号的分隔列表。" + "This action will permanently delete the saved query.": [ + "此操作将永久删除保存的查询。" ], - "Sort metric": ["排序指标"], - "Metric to sort the results by": ["按照指标的结果进行排序"], - "Sort ascending": ["升序排序"], - "Check for sorting ascending": ["按照升序进行排序"], - "Multiple selections allowed, otherwise filter is limited to a single value": [ - "允许多选下拉框,不勾选的话过滤器就是单选下拉框" + "This action will permanently delete the template.": [ + "此操作将永久删除模板。" ], - "Search all filter options": ["搜索所有过滤选项"], - "By default, each filter loads at most 1000 choices at the initial page load. Check this box if you have more than 1000 filter values and want to enable dynamically searching that loads filter values as users type (may add stress to your database).": [ - "默认情况下,每个过滤器在初始页面加载时最多加载1000个选项。如果您有超过1000个过滤值,并且希望启用动态搜索,以便在键入时加载筛选值(可能会给数据库增加压力),请选中此框。" + "This can be either an IP address (e.g. 127.0.0.1) or a domain name (e.g. mydatabase.com).": [ + "这可以是一个IP地址(例如127.0.0.1)或一个域名(例如127.0.0.1)" ], - "User must select a value for this filter": [ - "用户必须给过滤器选择一个值" + "This chart has been moved to a different filter scope.": [ + "此图表已移至其他过滤器范围内。" ], - "Filter configuration": ["过滤配置"], - "Error while fetching data": ["获取数据时出错"], - "No results found": ["未找到结果"], - "%s option(s)": ["%s 个选项"], - "Invalid lat/long configuration.": ["错误的经纬度配置。"], - "Reverse lat/long ": ["经纬度互换"], - "Longitude & Latitude columns": ["经纬度字段"], - "Delimited long & lat single column": ["经度&纬度单列限定"], - "Multiple formats accepted, look the geopy.points Python library for more details": [ - "接受多种格式,查看geopy.points库以获取更多细节" + "This chart might be incompatible with the filter (datasets don't match)": [ + "此图表可能与过滤器不兼容(数据集不匹配)" ], - "Geohash": ["Geo哈希"], - "textarea": ["文本区域"], - "in modal": ["(在模型中)"], - "Time series columns": ["时间序列的列"], - "This visualization type is not supported.": ["选择可视化类型"], - "Click to change visualization type": ["选择一个可视化类型"], - "Select a visualization type": ["选择一个可视化类型"], - "Failed to verify select options: %s": ["验证选择选项失败:%s"], - "RANGE TYPE": ["范围类型"], - "Actual time range": ["实际时间范围"], - "CANCEL": ["取消"], - "APPLY": ["应用"], - "Edit time range": ["编辑时间范围"], - "Configure advanced time range": ["配置高级时间范围"], - "START": ["开始"], - "END": ["结束"], - "Configure Time Range: Previous...": ["配置时间范围:前一(Previous).."], - "Configure Time Range: Last...": ["配置时间范围:上一(Last).."], - "Configure custom time range": ["配置自定义时间范围"], - "Relative quantity": ["相对量"], - "Anchor to": ["锚定到"], - "NOW": ["现在"], - "Date/Time": ["日期/时间"], - "Simple": ["简单配置"], - "Custom SQL": ["自定义SQL"], - "No such column found. To filter on a metric, try the Custom SQL tab.": [ - "没有发现这样的列。若要在度量值上筛选,请尝试自定义SQL选项卡。" + "This color scheme is being overriden by custom label colors.\n Check the JSON metadata in the Advanced settings": [ + "此配色方案正被自定义标签颜色覆盖。" ], - "%s column(s) and metric(s)": ["%s 列与计量指标"], - "%s column(s)": ["%s 列"], - "To filter on a metric, use Custom SQL tab.": [ - "若要在计量值上筛选,请使用自定义SQL选项卡。" + "This column must contain date/time information.": [ + "包含行信息的数据库列" ], - "%s operators(s)": ["%s 运算符"], - "Type a value here": ["在这里键入一个值"], - "Filter value (case sensitive)": ["过滤值(区分大小写)"], - "choose WHERE or HAVING...": ["选择WHERE或HAVING子句..."], - "Filters by columns": ["按列过滤"], - "Filters by metrics": ["按指标过滤"], - "\n This filter was inherited from the dashboard's context.\n It won't be saved when saving the chart.\n ": [ - "此过滤条件是从看板上下文继承的。保存图表时不会保存。" + "This dashboard is currently auto refreshing; the next auto refresh will be in %s.": [ + "此看板当前正在强制刷新;下一次强制刷新将在 %s 内执行。" ], - "%s aggregates(s)": ["%s 聚合"], - "%s saved metric(s)": ["%s 列与计量指标"], - "Saved": ["保存"], - "Saved metric": ["保存的指标"], - "column": ["列"], - "aggregate": ["合计"], - "My metric": ["我的指标"], - "Add metric": ["添加指标"], - "Code": ["代码"], - "Markup type": ["Markup 格式"], - "Pick your favorite markup language": ["选择您最爱的 Markup 语言"], - "Put your code here": ["把您的代码放在这里"], - "Query": ["查询"], - "URL": ["URL 地址"], - "Templated link, it's possible to include {{ metric }} or other values coming from the controls.": [ - "模板链接,可以包含{{度量}}或来自控件的其他值。" + "This dashboard is not published which means it will not show up in the list of dashboards. Favorite it to see it there or access it by using the URL directly.": [ + "此看板未发布,这意味着它不会显示在仪表板列表中。您可以进行收藏并在收藏栏中查看或直接使用URL访问它。" ], - "Time": ["时间"], - "Time related form attributes": ["时间相关的表单属性"], - "Chart type": ["图表类型"], - "Chart ID": ["图表 ID"], - "The id of the active chart": ["活动图表的ID"], - "Cache Timeout (seconds)": ["缓存超时(秒)"], - "The number of seconds before expiring the cache": [ - "终止缓存前的时间(秒)" + "This dashboard is not published, it will not show up in the list of dashboards. Click here to publish this dashboard.": [ + "此看板未发布,它将不会显示在看板列表中。单击此处以发布此看板。" ], - "URL parameters": ["URL 参数"], - "Extra parameters for use in jinja templated queries": [ - "用于jinja模板化查询的额外参数" + "This dashboard is now hidden": ["无法修改该看板"], + "This dashboard is now published": ["当前看板 ${nowPublished}"], + "This dashboard is published. Click to make it a draft.": [ + "此看板已发布。单击以使其成为草稿。" ], - "Time range endpoints": ["时间范围端点"], - "Time range endpoints (SIP-15)": ["时间范围端点 (SIP-15)"], - "Annotations and layers": ["注释与注释层"], - "Sort descending": ["降序"], - "Whether to sort descending or ascending": ["是降序还是升序排序"], - "Contribution": ["贡献"], - "Compute the contribution to the total": ["计算对总数的贡献值"], - "Advanced analytics": ["高级分析"], - "This section contains options that allow for advanced analytical post processing of query results": [ - "本节包含允许对查询结果进行高级分析处理后的选项。" + "This dashboard was changed recently. Please reload dashboard to get latest version.": [ + "此看板最近已更新。请重新加载看板以获取最新版本。" ], - "Rolling window": ["滚动窗口"], - "Rolling function": ["滚动函数"], - "Defines a rolling window function to apply, works along with the [Periods] text box": [ - "定义要应用的滚动窗口函数,与 [期限] 文本框一起使用" + "This dashboard was saved successfully.": ["该看板已成功保存。"], + "This defines the element to be plotted on the chart": [ + "这定义了要在图表上绘制的元素" ], - "Periods": ["周期"], - "Defines the size of the rolling window function, relative to the time granularity selected": [ - "定义滚动窗口函数的大小,相对于所选的时间粒度" + "This defines the level of the hierarchy": ["该选项定义了层次级别"], + "This feature is deprecated and will be removed on 2.0. Take a look at the replacement feature <a href='https://superset.apache.org/docs/installation/alerts-reports'>Alerts & Reports documentation</a>": [ + "此功能已弃用,将在2.0中删除。" ], - "Min periods": ["最小周期"], - "The minimum number of rolling periods required to show a value. For instance if you do a cumulative sum on 7 days you may want your \"Min Period\" to be 7, so that all data points shown are the total of 7 periods. This will hide the \"ramp up\" taking place over the first 7 periods": [ - "显示值所需的滚动周期的最小值。例如,如果您想累积 7 天的总额,您可能希望您的“最小周期”为 7,以便显示的所有数据点都是 7 个区间的总和。这将隐藏掉前 7 个阶段的“加速”效果" + "This fields acts a Superset view, meaning that Superset will run a query against this string as a subquery.": [ + "这个字段执行Superset视图时,意味着Superset将以子查询的形式对字符串运行查询。" ], - "Time comparison": ["时间比较"], - "Time shift": ["时间偏移"], - "Overlay one or more timeseries from a relative time period. Expects relative time deltas in natural language (example: 24 hours, 7 days, 52 weeks, 365 days). Free text is supported.": [ - "从相对时间段覆盖一个或多个时间序列。期望自然语言中的相对时间增量(例如:24小时、7天、56周、365天)" + "This filter doesn't exist in dashboard. It will not be applied.": [ + "此过滤器在仪表板中不存在。它不会被应用。" ], - "Calculation type": ["计算类型"], - "How to display time shifts: as individual lines; as the absolute difference between the main time series and each time shift; as the percentage change; or as the ratio between series and time shifts.": [ - "如何显示时间偏移:作为单独的行显示;作为主时间序列与每次时间偏移之间的绝对差显示;作为百分比变化显示;或作为序列与时间偏移之间的比率显示。" + "This filter set is identical to: \"%s\"": ["此过滤器集等同于: \"%s\" "], + "This is the condition that will be added to the WHERE clause. For example, to only return rows for a particular client, you might define a regular filter with the clause `client_id = 9`. To display no rows unless a user belongs to a RLS filter role, a base filter can be created with the clause `1 = 0` (always false).": [ + "这是将会添加到WHERE子句的条件。例如,要仅返回特定客户端的行,可以使用子句 `client_id = 9` 定义常规过滤。若要在用户不属于RLS过滤角色的情况下不显示行,可以使用子句 `1 = 0`(始终为false)创建基本过滤。" ], - "Python functions": ["Python函数"], - "Rule": ["规则"], - "Pandas resample rule": ["Pandas 重新采样的规则"], - "Method": ["方法"], - "Pandas resample method": ["Pandas 重新采样的填充方法"], - "Favorites": ["收藏"], - "Created content": ["创建的内容"], - "Recent activity": ["近期活动"], - "Security & Access": ["安全 & 访问"], - "No charts": ["没有图表"], - "No dashboards": ["没有看板"], - "No favorite charts yet, go click on stars!": [ - "暂无收藏的图表,去点击星星吧!" + "This json object describes the positioning of the widgets in the dashboard. It is dynamically generated when adjusting the widgets size and positions by using drag & drop in the dashboard view": [ + "这个JSON对象描述了部件在看板中的位置。它是动态生成的,可以通过拖放,在看板中调整整部件的大小和位置" ], - "No favorite dashboards yet, go click on stars!": [ - "暂无收藏的看板,去点击星星吧!" + "This markdown component has an error.": ["此 markdown 组件有错误。"], + "This markdown component has an error. Please revert your recent changes.": [ + "此 markdown 组件有错误。请还原最近的更改。" ], - "Profile picture provided by Gravatar": ["资料图片由 Gravatar 提供"], - "joined": ["已加入"], - "id:": ["id:"], - "There was an error fetching your recent activity:": [ - "获取您最近的活动时出错:" + "This may be triggered by:": ["这可能由以下因素触发:"], + "This query took %s seconds to run, ": ["这个查询使用了 %s 秒去执行,"], + "This section allows you to configure how to use the slice\n to generate annotations.": [ + "此部分允许您配置如何使用切片生成注释。" ], - "Deleted: %s": ["已删除:%s"], - "There was an issue deleting: %s": ["删除时出现问题:%s"], - "There was an issue deleting %s: %s": ["删除 %s 时出现问题:%s"], - "report": ["报告"], - "alert": ["警报"], - "reports": ["报告"], - "alerts": ["警报"], - "There was an issue deleting the selected %s: %s": [ - "删除所选 %s 时出现问题: %s" + "This section contains options that allow for advanced analytical post processing of query results": [ + "本节包含允许对查询结果进行高级分析处理后的选项。" ], - "Last run": ["上次执行"], - "Notification method": ["通知方式"], - "Execution log": ["操作日志"], - "Actions": ["操作"], - "Bulk select": ["批量选择"], - "No %s yet": ["还没有相关的%s数据"], - "Created by": ["创建人"], - "An error occurred while fetching created by values: %s": [ - "获取创建人时出错:%s" + "This value should be greater than the left target value": [ + "这个值应该大于左边的目标值" + ], + "This value should be smaller than the right target value": [ + "这个值应该小于正确的目标值" + ], + "This visualization type is not supported.": ["选择可视化类型"], + "This was triggered by:": ["这是由以下因素引发的:"], + "Threshold alpha level for determining significance": [ + "确定重要性的阈值α水平" + ], + "Thursday": ["星期四"], + "Time": ["时间"], + "Time Column": ["时间列"], + "Time Comparison": ["时间比对"], + "Time Format": ["时间格式"], + "Time Grain": ["时间粒度(Grain)"], + "Time Granularity": ["时间粒度(Granularity)"], + "Time Offset": ["时间偏移"], + "Time Range": ["时间范围"], + "Time Series": ["时间序列"], + "Time Series - Bar Chart": ["时间序列 - 柱状图"], + "Time Series - Dual Axis Line Chart": ["时间序列-双轴线图"], + "Time Series - Line Chart": ["时间序列-折线图"], + "Time Series - Multiple Line Charts": ["时间序列-多线图"], + "Time Series - Nightingale Rose Chart": ["时间序列 - 南丁格尔玫瑰图"], + "Time Series - Paired t-test": ["时间序列 - 配对t检验"], + "Time Series - Percent Change": ["时间序列 - 百分比变化"], + "Time Series - Period Pivot": ["时间序列 - 周期透视表"], + "Time Series - Stacked": ["时间序列 - 堆积图"], + "Time Series Options": ["时间序列的列"], + "Time Shift": ["时间偏移"], + "Time Table View": ["时间表视图"], + "Time column": ["时间列"], + "Time column \"%(col)s\" does not exist in dataset": [ + "时间列 \"%(col)s\" 在数据集中不存在" ], - "Status": ["状态"], - "Working": ["正在执行"], - "Error": ["错误"], - "Not triggered": ["没有触发"], - "On Grace": ["在宽限期内"], - "Alerts & reports": ["警报和报告"], - "Reports": ["报告"], - "This action will permanently delete %s.": ["此操作将永久删除 %s 。"], - "Delete %s?": ["需要删除 %s 吗?"], - "Please confirm": ["请确认"], - "Are you sure you want to delete the selected %s?": [ - "确实要删除选定的 %s 吗?" + "Time column filter plugin": ["选择过滤器"], + "Time comparison": ["时间比较"], + "Time delta is ambiguous. Please specify [%(human_readable)s ago] or [%(human_readable)s later].": [ + "时间是模糊的。" ], - "< (Smaller than)": ["< (小于)"], - "> (Larger than)": ["> (大于)"], - "<= (Smaller or equal)": ["<= (小于等于)"], - ">= (Larger or equal)": [">= (大于等于)"], - "== (Is equal)": ["== (等于)"], - "!= (Is not equal)": ["!= (不等于)"], - "Not null": ["非空"], - "30 days": ["30天"], - "60 days": ["60天"], - "90 days": ["90天"], - "Add notification method": ["添加注释层"], - "Add delivery method": ["添加通知方法"], - "Recipients are separated by \",\" or \";\"": [ - "收件人之间用 \",\" 或者 \";\" 隔开" + "Time expression to use as a predicate when retrieving distinct values to populate the filter component. Only applies when `Enable Filter Select` is on. If you enter `7 days ago`, the distinct list of values in the filter will be populated based on the distinct value over the past week": [ + "当检索不同的值以填充过滤器组件时,时间表达式用作条件。只适用于`启用过滤器选择`。如果您输入`7天前`,将根据过去一周的不同值来填充ilter中不同的值列表" ], - "Add": ["新增"], - "Edit ${isReport ? 'Report' : 'Alert'}": [ - "编辑 ${isReport ? '报告' : '警报'}" + "Time filter": ["日期过滤器"], + "Time format": ["时间格式"], + "Time grain": ["时间粒度(grain)"], + "Time grain filter plugin": ["范围过滤器"], + "Time grain missing": ["时间粒度缺失"], + "Time granularity": ["时间粒度(granularity)"], + "Time in seconds": ["时间(秒)"], + "Time range": ["时间范围"], + "Time range endpoints": ["时间范围端点"], + "Time range endpoints (SIP-15)": ["时间范围端点 (SIP-15)"], + "Time related form attributes": ["时间相关的表单属性"], + "Time series columns": ["时间序列的列"], + "Time shift": ["时间偏移"], + "Time string is ambiguous. Please specify [%(human_readable)s ago] or [%(human_readable)s later].": [ + "时间字符串是模糊的。" ], - "Add ${isReport ? 'Report' : 'Alert'}": [ - "新增 ${isReport ? '报告' : '警报'}" + "Time-series Area Chart": ["时间序列条形图"], + "Time-series Area chart are similar to line chart in that they represent variables with the same scale, but area charts stack the metrics on top of each other. An area chart in Superset can be stream, stack, or expand.": [ + "时间序列面积图与折线图相似,因为它们表示具有相同比例的变量,但面积图将度量叠加在一起。超级集中的面积图可以是流式、堆栈式或展开式" ], - "Report name": ["报告名称"], - "Alert name": ["警报名称"], - "Alert condition": ["警报状态"], - "Trigger Alert If...": ["如果 ... 则触发警报"], - "Value": ["值"], - "Report schedule": ["报告时间表"], - "Alert condition schedule": ["警报条件计划"], - "Schedule settings": ["计划设置"], - "Log retention": ["日志保留"], - "Working timeout": ["执行超时"], - "Time in seconds": ["时间(秒)"], - "Grace period": ["宽限期"], - "Message content": ["消息内容"], - "log": ["日志"], - "State": ["状态"], - "Scheduled at": ["计划时间"], - "Start at": ["开始/从"], - "Duration": ["持续时间"], - "Error message": ["错误信息"], - "${alertResource?.type}": [""], - "CRON expression": ["CRON表达式"], - "Report sent": ["已发送报告"], - "Alert triggered, notification sent": ["警报已触发,通知已发送"], - "Report sending": ["报告发送"], - "Alert running": ["警报运行"], - "Report failed": ["报告失败"], - "Alert failed": ["警报失败"], - "Nothing triggered": ["无触发"], - "Alert Triggered, In Grace Period": ["警报已触发,在宽限期内"], - "Email": [""], - "Slack": [""], - "annotation": ["注释"], - "There was an issue deleting the selected annotations: %s": [ - "删除所选注释时出现问题:%s" + "Time-series Bar Chart": ["时间序列-条形图"], + "Time-series Bar Chart v2": ["时间序列条形图 v2"], + "Time-series Bar Charts are used to show the changes in a metric over time as a series of bars.": [ + "时间序列条形图用于显示指标随时间的变化" ], - "Edit annotation": ["编辑注释"], - "Delete annotation": ["删除注释"], - "Annotation": ["注释"], - "No annotation yet": ["没有注释"], - "Annotation Layer ${annotationLayerName}": [ - "注释层 ${annotationLayerName}" + "Time-series Chart": ["时间序列图"], + "Time-series Line Chart": ["时间序列折线图"], + "Time-series Percent Change": ["时间序列-百分比变化"], + "Time-series Period Pivot": ["时间序列-周期轴"], + "Time-series Scatter Plot": ["时间序列散点图"], + "Time-series Scatter Plot has time on the horizontal axis in linear units, and the points are connected in order. It shows a statistical relationship between two variables.": [ + "时间序列散点图在水平轴上以线性单位表示时间,点按顺序连接。它显示了两个变量之间的统计关系" ], - "Are you sure you want to delete ${annotationCurrentlyDeleting?.short_descr}?": [ - "请确认您想删除 ${annotationCurrentlyDeleting?.short_descr}?" + "Time-series Smooth Line": ["时间序列光滑曲线图"], + "Time-series Smooth-line is a variation of line chart. Without angles and hard edges, Smooth-line looks more smarter and more professional.": [ + "时间序列平滑线是折线图的变体。没有角度和硬边,平滑线看起来更聪明、更专业。" ], - "Delete Annotation?": ["删除注释?"], - "Are you sure you want to delete the selected annotations?": [ - "确实要删除选定的注释吗?" + "Time-series Stepped Line": ["时间序列阶梯图"], + "Time-series Stepped-line graph (also called step chart) is a variation of line chart but with the line forming a series of steps between data points. A step chart can be useful when you want to show the changes that occur at irregular intervals.": [ + "“时间序列步进折线图(也称为步进图)是折线图的一种变体,但线条在数据点之间形成一系列步进。当您希望显示不规则间隔发生的变化时,步进图可能很有用。”" ], - "Add annotation": ["添加注释"], - "Annotation name": ["注释名称"], - "date": ["日期"], - "Additional information": ["附加信息"], - "Description (this can be seen in the list)": ["说明(见列表)"], - "annotation_layer": ["注释层"], - "Edit annotation layer properties": ["编辑注释图层属性"], - "Annotation layer name": ["注释层名称"], - "Annotation layers": ["注解层"], - "There was an issue deleting the selected layers: %s": [ - "删除所选图层时出现问题:%s" + "Time-series Table": ["时间序列-表格"], + "Time-series line chart is used to visualize repeated measurements taken over regular time intervals. Line chart is a type of chart which displays information as a series of data points connected by straight line segments. It is a basic type of chart common in many fields.": [ + "时间序列折线图用于可视化在规则时间间隔内进行的重复测量。折线图是一种图表,它将信息显示为一系列由直线段连接的数据点。它是许多领域中常见的一种基本类型的图表。" ], - "Last modified": ["最后修改"], - "Created on": ["创建日期"], - "Edit template": ["编辑模板"], - "Delete template": ["删除模板"], - "Annotation layer": ["注释层"], - "An error occurred while fetching dataset datasource values: %s": [ - "获取数据集数据源信息时出错: %s" + "Timeout error": ["超时错误"], + "Timestamp Format": ["时间戳格式"], + "Timestamp format": ["时间戳格式"], + "Timezone": ["时区"], + "Timezone offset (in hours) for this datasource": [ + "数据源的时差(单位:小时)" ], - "No annotation layers yet": ["没有注释层"], - "This action will permanently delete the layer.": [ - "此操作将永久删除图层。" + "Timezone selector": ["时区选择"], + "Tiny": ["微小"], + "Title": ["标题"], + "Title Column": ["标题栏"], + "Title is required": ["标题是必填项"], + "Title or Slug": ["标题或者Slug"], + "To filter on a metric, use Custom SQL tab.": [ + "若要在计量值上筛选,请使用自定义SQL选项卡。" ], - "Delete Layer?": ["确定删除图层?"], - "Are you sure you want to delete the selected layers?": [ - "确实要删除选定的图层吗?" + "To get a readable URL for your dashboard": ["为看板生成一个可读的 URL"], + "Toggle chart description": ["切换图表说明"], + "Tools": ["工具"], + "Tooltip": ["详细提示"], + "Tooltip sort by metric": ["排序指标"], + "Tooltip time format": ["时间格式"], + "Top": ["顶部"], + "Top to Bottom": ["点击回顶部"], + "Totals": ["显示总计"], + "Track job": ["跟踪任务"], + "Transformable": ["转换"], + "Transparent": ["透明"], + "Transpose Pivot": ["转置透视图"], + "Transpose pivot": ["转置透视图"], + "Tree Chart": ["树状图"], + "Tree layout": ["布局"], + "Tree orientation": ["方向"], + "Treemap": ["树状地图"], + "Treemap v2": ["树状地图 v2"], + "Trend": ["趋势"], + "Triangle": ["三角形"], + "Trigger Alert If...": ["如果 ... 则触发警报"], + "Truncate Y Axis": ["截断Y轴"], + "Truncate Y Axis. Can be overridden by specifying a min or max bound.": [ + "截断Y轴。可以通过指定最小或最大界限来重写。" ], - "Are you sure you want to delete": ["确定要删除吗"], - "Last modified %s": ["最后修改 %s"], - "The passwords for the databases below are needed in order to import them together with the charts. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "需要以下数据库的密码才能将其与图表一起导入。请注意,数据库配置的 \"Secure Extra\" 和 \"Certificate\" 部分不在导出文件中,如果需要,应在导入后手动添加。" + "Truncates the specified date to the accuracy specified by the date unit.": [ + "将指定的日期截取为指定的日期单位精度。" ], - "You are importing one or more charts that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "您正在导入一个或多个已存在的图表。覆盖可能会导致您丢失一些工作。您确定要覆盖吗?" + "Try applying different filters or ensuring your datasource has data": [ + "尝试应用不同的筛选器或确保您的数据源包含数据。“" ], - "There was an issue deleting the selected charts: %s": [ - "删除所选图表时出现问题:%s" + "Tuesday": ["星期二"], + "Type": ["类型"], + "Type \"%s\" to confirm": ["键入 \"%s\" 来确认"], + "Type a value": ["请输入值"], + "Type a value here": ["请输入值"], + "Type is required": ["类型是必需的"], + "Type of Google Sheets allowed": ["接受Google Sheets的类型"], + "Type or Select [%s]": ["键入或选择 [%s]"], + "UI Configuration": ["UI 配置"], + "URL": ["URL 地址"], + "URL Parameters": ["URL参数"], + "URL could not be identified": ["无法识别的URL。"], + "URL parameters": ["URL 参数"], + "URL slug": ["使用 Slug"], + "Unable to add a new tab to the backend. Please contact your administrator.": [ + "无法将新选项卡添加到后端。请与管理员联系。" ], - "Modified by": ["修改人"], - "Owner": ["所有者"], - "An error occurred while fetching chart owners values: %s": [ - "获取图表所有者时出错 %s" + "Unable to connect to catalog named \"%(catalog_name)s\".": [ + "无法连接到名为%(catalog_name)s的目录。" ], - "An error occurred while fetching chart created by values: %s": [ - "获取图表的创建人时出错:%s" + "Unable to connect to database \"%(database)s\".": [ + "不能连接到数据库\"%(database)s\"" ], - "Viz type": ["可视化类型"], - "An error occurred while fetching chart dataset values: %s": [ - "获取图表数据集时出错:%s" + "Unable to find such a holiday: [%(holiday)s]": [ + "找不到这样的假期:[{}]" ], - "Favorite": ["收藏"], - "Yes": ["是"], - "No": ["否"], - "Are you sure you want to delete the selected charts?": [ - "确实要删除所选图表吗?" + "Unable to migrate query editor state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ + "无法将查询编辑器状态迁移到后端。系统将稍后重试。如果此问题仍然存在,请与管理员联系。" ], - "css_template": ["css模板"], - "Edit CSS template properties": ["编辑CSS属性属性"], - "Add CSS template": ["新增CSS模板"], - "CSS template name": ["CSS模板名称"], - "css": [""], - "CSS templates": ["CSS 模板"], - "There was an issue deleting the selected templates: %s": [ - "删除所选模板时出现问题:%s" + "Unable to migrate query state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ + "无法将查询状态迁移到后端。系统将稍后重试。如果此问题仍然存在,请与管理员联系。" ], - "Last modified by %s": ["上次修改人 %s"], - "CSS template": ["CSS 模板"], - "This action will permanently delete the template.": [ - "此操作将永久删除模板。" + "Unable to migrate table schema state to backend. Superset will retry later. Please contact your administrator if this problem persists.": [ + "无法将表结构状态迁移到后端。系统将稍后重试。如果此问题仍然存在,请与管理员联系。" ], - "Delete Template?": ["删除模板?"], - "Are you sure you want to delete the selected templates?": [ - "确实要删除选定的模板吗?" + "Unable to refresh metadata for the following table(s): %(tables)s": [ + "为下表刷新元数据: %(tables)s" ], - "The passwords for the databases below are needed in order to import them together with the dashboards. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "需要以下数据库的密码才能将它们与仪表板一起导入。请注意,数据库配置的 \"Secure Extra\" 和 \"Certificate\" 部分不在导出文件中,如果需要,应在导入后手动添加。" + "Unable to upload CSV file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ + "无法将CSV文件 \"%(filename)s\" 上传到数据库 \"%(db_name)s\" 中的表 \"%(table_name)s\" 内。错误消息:%(error_msg)s" ], - "You are importing one or more dashboards that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "您正在导入一个或多个已存在的仪表板。覆盖可能会导致您丢失一些工作。确定要覆盖吗?" + "Unable to upload Columnar file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ + "无法将Excel文件 \"%(filename)s\" 上传到数据库 \"%(db_name)s\" 中的表 \"%(table_name)s\" 内。错误消息:%(error_msg)s" ], - "An error occurred while fetching dashboards: %s": [ - "获取仪表板时出错:%s" + "Unable to upload Excel file \"%(filename)s\" to table \"%(table_name)s\" in database \"%(db_name)s\". Error message: %(error_msg)s": [ + "无法将Excel文件 \"%(filename)s\" 上传到数据库 \"%(db_name)s\" 中的表 \"%(table_name)s\" 内。错误消息:%(error_msg)s" ], - "There was an issue deleting the selected dashboards: ": [ - "删除所选仪表板时出现问题:" + "Undefined": ["未命名"], + "Undefined window for rolling operation": ["未定义滚动操作窗口"], + "Undo?": ["撤消?"], + "Unexpected error": ["意外错误。"], + "Unexpected error occurred, please check your logs for details": [ + "发生意外错误,请检查日志以了解详细信息" ], - "An error occurred while fetching dashboard owner values: %s": [ - "获取仪表板所有者时出错:%s" + "Unexpected error: ": ["意外错误。"], + "Unknown": ["未知"], + "Unknown MySQL server host \"%(hostname)s\".": [ + "未知MySQL服务器主机 \"%(hostname)s\"." ], - "An error occurred while fetching dashboard created by values: %s": [ - "获取仪表板创建者时出错:%s" + "Unknown Presto Error": ["未知 Presto 错误"], + "Unknown Status": ["未知状态"], + "Unknown column used in orderby: %(col)s": [ + "订单中使用的未知列: %(col)s" ], - "Unpublished": ["未发布"], - "Are you sure you want to delete the selected dashboards?": [ - "确实要删除选定的仪表板吗?" + "Unknown error": ["未知错误"], + "Unknown value": ["未知错误"], + "Unsafe return type for function %(func)s: %(value_type)s": [ + "函数返回不安全的类型 %(func)s: %(value_type)s" ], - "Sorry, your browser does not support copying.": [ - "抱歉,您的浏览器不支持复制操作。使用 Ctrl / Cmd + C!" + "Unsafe template value for key %(key)s: %(value_type)s": [ + "键的模板值不安全 %(key)s: %(value_type)s" ], - "SQL Copied!": ["SQL复制成功!"], - "The passwords for the databases below are needed in order to import them. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "需要以下数据库的密码才能导入它们。请注意,数据库配置的 \"Secure Extra\" 和 \"Certificate\" 部分不在导出文件中。如果需要,应在导入后手动添加。" + "Unset Filters (%d)": ["未选择的条件 (%d)"], + "Unsupported clause type: %(clause)s": ["不支持的条款类型: %(clause)s"], + "Unsupported extraction function: ": ["不支持的提取函数:"], + "Unsupported post processing operation: %(operation)s": [ + "不支持的处理操作:%(operation)s" ], - "You are importing one or more databases that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "您正在导入一个或多个已存在的数据库。覆盖可能会导致您丢失一些工作。您确定要覆盖吗?" + "Unsupported return value for method %(name)s": [ + "方法的返回值不受支持 %(name)s" ], - "database": ["数据库"], - "An error occurred while fetching database related data: %s": [ - "获取数据库相关数据时出错:%s" + "Unsupported template value for key %(key)s": [ + "键的模板值不受支持 %(key)s" ], - "Asynchronous query execution": ["异步执行查询"], - "AQE": ["AQE(异步执行查询)"], - "Allow data manipulation language": ["允许数据操作语言"], - "DML": ["DML(数据操作语言)"], - "CSV upload": ["CSV上传"], - "Delete database": ["删除数据库"], - "The database %s is linked to %s charts that appear on %s dashboards. Are you sure you want to continue? Deleting the database will break those objects.": [ - "数据库 %s 已经关联了 %s 图表和 %s 看板。确定要继续吗?删除数据库将破坏这些对象。" + "Unsupported time grain: %(time_grain)s": [ + "不支持的时间粒度:%(time_grain)s" ], - "Delete Database?": ["确定删除数据库?"], - "Please enter a SQLAlchemy URI to test": ["请输入要测试的SQLAlchemy URI"], - "Connection looks good!": ["连接测试成功!"], - "ERROR: Connection failed. ": ["错误:连接失败。"], - "Sorry there was an error fetching database information: %s": [ - "抱歉,获取数据库信息时出错:%s" + "Untitled Query %s": ["未命名的查询 %s"], + "Untitled query": ["未命名的查询"], + "Update": ["更新"], + "Updating chart was stopped": ["更新图表已停止"], + "Upload": ["上传"], + "Upload Credentials": ["上传验证文件"], + "Upload Excel file to database": ["上传Excel"], + "Upload JSON file": ["上传JSON文件"], + "Upload CSV to database": ["上传CSV文件"], + "Upload a Columnar File": ["上传列式存储文件"], + "Use Area Proportions": ["使用面积比例"], + "Use Columns": ["使用列"], + "Use Pandas to interpret the datetime format automatically.": [ + "使用Pandas自动解释日期时间格式。" ], - "Edit database": ["编辑数据库"], - "Add database": ["添加数据库"], - "Connection": ["测试连接"], - "Database name": ["数据库名称"], - "Name your dataset": ["命名数据集"], - "dialect+driver://username:password@host:port/database": [""], - "Test connection": ["测试连接"], - "Refer to the ": ["参考 "], - "SQLAlchemy docs": ["SQLAlchemy 文档"], - " for more information on how to structure your URI.": [ - " 来查询有关如何构造URI的更多信息。" + "Use a log scale": ["使用Y轴的对数刻度"], + "Use a log scale for the X-axis": ["使用Y轴的对数刻度"], + "Use a log scale for the Y-axis": ["使用Y轴的对数刻度"], + "Use an encrypted connection to the database": ["使用到数据库的加密连接"], + "Use legacy datasource editor": ["使用旧数据源编辑器"], + "Use metrics as a top level group for columns or for rows": [ + "将指标作为列或行的顶级组使用" ], - "Performance": ["性能"], - "Chart cache timeout": ["图表缓存超时"], - "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.": [ - "以异步模式操作数据库,这意味着查询是在远程worker上执行的,而不是在web服务器本身上执行的, 这假设您有一个Celery worker setup以及一个执行后端。有关更多信息,请参考安装文档。" + "Use only a single value.": ["只使用一个值"], + "Use the Advanced Analytics options below": ["使用下面的高级分析选项"], + "Use the JSON file you automatically downloaded when creating your service account.": [ + "使用您在创建服务帐户时自动下载的JSON文件" ], - "SQL Lab settings": ["SQL Lab 设置"], - "Allow users to run non-SELECT statements (UPDATE, DELETE, CREATE, ...)": [ - "允许用户在 SQL 编辑器中运行非 SELECT 语句(UPDATE,DELETE,CREATE,...)" + "Use the edit buttom to change this field": ["使用编辑按钮更改此字段"], + "Use this to define a static color for all circles": [ + "使用此定义所有圆圈的静态颜色" ], - "Allow multi schema metadata fetch": ["允许多Schema元数据获取"], - "CTAS schema": ["CTAS 模式"], - "When allowing CREATE TABLE AS option in SQL Lab, this option forces the table to be created in this schema.": [ - "当在 SQL 编辑器中允许 CREATE TABLE AS 选项时,此选项可以此模式中强制创建表" + "Used internally to identify the plugin. Should be set to the package name from the pluginʼs package.json": [ + "在内部用于标识插件。应该在插件的 package.json 内被设置为包名。" ], - "Secure extra": ["安全"], - "JSON string containing additional connection configuration.": [ - "包含附加连接配置的JSON字符串。" + "Used to summarize a set of data by grouping together multiple statistics along two axes. Examples: Sales numbers by region and month, tasks by status and assignee, active users by age and location.\n\n This chart is being deprecated and we recommend checking out Pivot Table V2 instead!": [ + "用于通过将多个统计数据分组来总结一组数据" ], - "This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.": [ - "这用于为SQLAlchemy提供Hive、Presto和BigQuery等不符合 用户名:密码 的语法规范。" + "Used to summarize a set of data by grouping together multiple statistics along two axes. Examples: Sales numbers by region and month, tasks by status and assignee, active users by age and location. Not the most visually stunning visualization, but highly informative and versatile.": [ + "用于通过将多个统计信息分组在一起来汇总一组数据" ], - "Optional CA_BUNDLE contents to validate HTTPS requests. Only available on certain database engines.": [ - "用于验证HTTPS请求的可选 CA_BUNDLE 内容。仅在某些数据库引擎上可用。" + "User": ["用户"], + "User Roles": ["用户角色"], + "User doesn't have the proper permissions.": ["您没有授权 "], + "User must select a value before applying the filter": [ + "用户必须给过滤器选择一个值" ], - "Impersonate Logged In User (Presto, Trino, Drill & Hive)": [ - "模拟登录用户 (Presto, Trino, Drill & Hive)" + "User must select a value for this filter": [ + "用户必须给过滤器选择一个值" ], - "If Presto, Trino or Drill all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them. If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.": [ - "如果使用Presto,SQL 工具箱中的所有查询都将被当前登录的用户执行,并且这些用户必须拥有运行它们的权限。如果启用 Hive 和 hive.server2.enable.doAs,将作为服务帐户运行查询,但会根据 hive.server2.proxy.user 的属性伪装当前登录用户。" + "User must select a value for this filter.": [ + "用户必须给过滤器选择一个值" ], - "Allow data upload": ["允许数据上传"], - "If selected, please set the schemas allowed for data upload in Extra.": [ - "如果选中,请额外设置允许数据上传的schema。" + "User query": ["用户查询"], + "Username": ["用户名"], + "Uses a gauge to showcase progress of a metric towards a target. The position of the dial represents the progress and the terminal value in the gauge represents the target value.": [ + "使用一个度量来展示实现目标的度量的进展" ], - "JSON string containing extra configuration elements.": [ - "包含额外配置元素的JSON字符串。" + "Uses circles to visualize the flow of data through different stages of a system. Hover over individual paths in the visualization to understand the stages a value took. Useful for multi-stage, multi-group visualizing funnels and pipelines.": [ + "使用圆圈来可视化系统不同阶段的数据流。" ], - "1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.": [ - "1. engine_params 对象在调用 sqlalchemy.create_engine 时被引用, metadata_params 在调用 sqlalchemy.MetaData 时被引用。" + "Value": ["值"], + "Value Domain": ["值域"], + "Value Format": ["数值格式"], + "Value bounds": ["值边界"], + "Value format": ["数值格式"], + "Value is required": ["需要名称"], + "Value must be greater than 0": ["`行偏移量` 必须大于或等于0"], + "Vehicle Types": ["类型"], + "Verbose Name": ["全称"], + "Version": ["版本"], + "Version number": ["版本"], + "Vertical": ["垂直"], + "Video game consoles": ["控制台"], + "View All »": ["查看所有 »"], + "View chart in Explore": ["查看图表"], + "View in SQL Lab": ["在 SQL 工具箱中公开"], + "View keys & indexes (%s)": ["查看键和索引(%s)"], + "View query": ["检查查询"], + "View results": ["展示结果"], + "View samples": ["查看样例"], + "Viewed": ["已查看"], + "Viewed %s": ["已查看"], + "Viewport": ["视口"], + "Virtual (SQL)": ["虚拟(SQL)"], + "Virtual dataset": ["虚拟数据集"], + "Virtual dataset query cannot be empty": ["虚拟数据集查询必须是只读的"], + "Virtual dataset query cannot consist of multiple statements": [ + "虚拟数据集查询不能由多个语句组成" ], - "2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.": [ - "2. metadata_cache_timeout 是获取该数据库元数据的缓存超时设置(秒)。可以这样进行设置:\"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}。如果未设置,则不会为该功能启用缓存。如果超时时间设置为0,则表示缓存永不过期。" + "Virtual dataset query must be read-only": ["虚拟数据集查询必须是只读的"], + "Visual Tweaks": ["视觉调整"], + "Visualization": ["可视化模式"], + "Visualization Type": ["可视化类型"], + "Visualization type": ["可视化类型"], + "Visualize a parallel set of metrics across multiple groups. Each group is visualized using its own line of points and each metric is represented as an edge in the chart.": [ + "在多个组中可视化一组平行的度量。每个组都使用自己的点线进行可视化,每个度量在图表中表示为一条边。" ], - "3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty.": [ - "3. schemas_allowed_for_file_upload 是CSV文件允许上传的schema,该结构以逗号进行分割。 可以这样进行设置:\"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]。如果数据库风格不支持schema或任何schema都被允许,请将列表留空。" + "Visualize a related metric across pairs of groups. Heatmaps excel at showcasing the correlation or strength between two groups. Color is used to emphasize the strength of the link between each pair of groups.": [ + "可视化各组之间的相关指标。热图擅长显示两组之间的相关性或强度。颜色用于强调各组之间的联系强度。" ], - "4. The version field is a string specifying this db's version. This should be used with Presto DBs so that the syntax is correct.": [ - "4. version 字段是指定此数据库版本的字符串。这应该与Presto DBs一起使用,以便语法正确。" + "Visualize how a metric changes over time using bars. Add a group by column to visualize group level metrics and how they change over time.": [ + "使用条形图可视化指标随时间的变化。按列添加分组以可视化分组级别的指标及其随时间变化的方式。" ], - "5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.": [ - "5. allows_virtual_table_explore 字段是一个布尔值,它指定是否显示 SQL Lab 结果中的explore按钮。" + "Visualize multiple levels of hierarchy using a familiar tree-like structure.": [ + "使用熟悉的树状结构可视化多层次结构。" ], - "Error while saving dataset: %s": ["保存数据集时出错:%s"], - "Add dataset": ["添加数据集"], - "The passwords for the databases below are needed in order to import them together with the datasets. Please note that the \"Secure Extra\" and \"Certificate\" sections of the database configuration are not present in export files, and should be added manually after the import if they are needed.": [ - "需要以下数据库的密码才能将其与数据集一起导入。请注意,数据库配置的 \"Secure Extra\" 和 \"Certificate\" 部分不在导出文件中,如果需要,应在导入后手动添加。" + "Visualize two different time series using the same x-axis time range. Note that each time series can be visualized differently (e.g. 1 using bars and 1 using a line).": [ + "使用相同的x轴时间范围可视化两个不同的时间序列。请注意,每个时间序列可以以不同的方式可视化(例如1个使用条形图,1个使用线条)。" ], - "You are importing one or more datasets that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ - "您正在导入一个或多个已存在的数据集。覆盖可能会导致您丢失一些工作。确定要覆盖吗?" + "Visualize two different time series using the same x-axis time range. This chart is being deprecated and we recommend using the Mixed Timeseries Chart instead!": [ + "使用相同的x轴时间范围可视化两个不同的时间序列。此图表已被弃用,我们建议使用混合改为时间序列图!" ], - "An error occurred while fetching dataset related data": [ - "获取数据集相关数据时出错" + "Visualizes 2 metrics as line plots using the same x-axis. This chart is useful for comparing metrics across the same time range.": [ + "使用相同的x轴将2个指标可视化为折线图。此图表可用于比较相同时间范围内的指标。" ], - "An error occurred while fetching dataset related data: %s": [ - "获取数据集相关数据时出错:%s" + "Visualizes a metric across three dimensions of data in a single chart (X axis, Y axis, and bubble size). Bubbles from the same group can be showcased using bubble color.": [ + "在单个图表中跨三维数据(X轴、Y轴和气泡大小)可视化度量。同一组中的气泡可以“使用气泡颜色显示" ], - "Physical dataset": ["物化数据集"], - "Virtual dataset": ["虚拟数据集"], - "An error occurred while fetching dataset owner values: %s": [ - "获取数据集所有者值时出错:%s" + "Visualizes how a metric has changed over a time using a color scale and a calendar view. Gray values are used to indicate missing values and the linear color scheme is used to encode the magnitude of each day's value.": [ + "使用色标和日历视图可视化指标在一段时间内的变化情况。灰色值用于指示缺少的值,线性配色方案用于编码每天值的大小。" ], - "An error occurred while fetching datasets: %s": ["获取数据集时出错:%s"], - "An error occurred while fetching schema values: %s": [ - "获取结构信息时出错:%s" + "Visualizes how a single metric varies across a country's principal subdivisions (states, provinces, etc) on a chloropleth map. Each subdivision's value is elevated when you hover over the corresponding geographic boundary.": [ + "在叶绿体地图上显示一个国家的主要分区(州、省等)之间单个指标的变化情况。当您悬停在相应的地理边界上时,每个分区的值都会升高" ], - "There was an issue deleting the selected datasets: %s": [ - "删除选定的数据集时出现问题:%s" + "Visualizes many different time-series objects in a single chart. This chart is being deprecated and we recommend using the Time-series Chart instead.": [ + "在一个图表中显示许多不同的时间序列对象。此图表已被弃用,建议改用时间序列图表" ], - "The dataset %s is linked to %s charts that appear on %s dashboards. Are you sure you want to continue? Deleting the dataset will break those objects.": [ - "数据集 %s 已经链接到 %s 图表和 %s 看板内。确定要继续吗?删除数据集将破坏这些对象。" + "Visualizes the flow of different group's values through different stages of a system. New stages in the pipeline are visualized as nodes or layers. The thickness of the bars or edges represent the metric being visualized.": [ + "可视化不同组的值在系统不同阶段的流动。管道中的新阶段被可视化为节点或层。条形或边缘的厚度表示正在可视化的度量。" ], - "Delete Dataset?": ["确定删除数据集?"], - "Are you sure you want to delete the selected datasets?": [ - "确实要删除选定的数据集吗?" + "Visualizes the words in a column that appear the most often. Bigger font corresponds to higher frequency.": [ + "可视化列中出现频率最高的单词。字体越大,出现频率越高。" ], - "0 Selected": ["0个被选中"], - "%s Selected (Virtual)": ["%s 个被选中(虚拟)"], - "%s Selected (Physical)": ["%s 个被选中(物理)"], - "%s Selected (%s Physical, %s Virtual)": [ - "%s 个被选中 (%s 个物理, %s 个虚拟)" + "Viz is missing a datasource": ["Viz 缺少一个数据源"], + "Viz type": ["可视化类型"], + "WED": ["星期三"], + "Want to add a new database?": ["添加一个新数据库?"], + "Warning": ["警告!"], + "Warning Message": ["告警信息"], + "Warning!": ["警告!"], + "Warning! Changing the dataset may break the chart if the metadata does not exist.": [ + "警告!如果元数据不存在,更改数据集可能会破坏图表。" ], - "There was an issue previewing the selected query. %s": [ - "预览所选查询时出现问题。%s" + "We can't seem to resolve column \"%(column)s\" at line %(location)s.": [ + "我们似乎无法解析行 %(location)s 所处的列 \"%(column_name)s\" 。" ], - "Success": ["成功"], - "Failed": ["失败"], - "Running": ["正在执行"], - "Offline": ["离线"], - "Scheduled": ["被调度"], - "Duration: %s": ["持续时间:%s"], - "Tab name": ["tab名"], - "TABLES": ["表"], - "Rows": ["行"], - "Open query in SQL Lab": ["在 SQL 工具箱中打开查询"], - "An error occurred while fetching database values: %s": [ - "获取数据库信息时出错:%s" + "We can't seem to resolve the column \"%(column_name)s\"": [ + "我们似乎无法解析行 %(location)s 所处的列 \"%(column_name)s\" 。" ], - "Search by query text": ["按查询文本搜索"], - "Query preview": ["查询预览"], - "Previous": ["之前"], - "Next": ["之后"], - "Open in SQL Lab": ["在 SQL 工具箱中打开"], - "User query": ["用户查询"], - "Executed query": ["已执行查询"], - "Saved queries": ["已保存查询"], - "There was an issue previewing the selected query %s": [ - "预览所选查询时出现问题 %s" + "We can't seem to resolve the column \"%(column_name)s\" at line %(location)s.": [ + "我们似乎无法解析行 %(location)s 所处的列 \"%(column_name)s\" 。" ], - "Link Copied!": ["链接成功!"], - "There was an issue deleting the selected queries: %s": [ - "删除所选查询时出现问题:%s" + "We recommend your summarize your data further before following that flow. ": [ + "我们建议您在遵循流程之前进一步总结数据。" ], - "Edit query": ["编辑查询"], - "Copy query URL": ["复制查询URL"], - "Delete query": ["删除查询"], - "This action will permanently delete the saved query.": [ - "此操作将永久删除保存的查询。" + "We were unable to active or deactivate this report.": [ + "“我们无法激活或禁用该报告。" ], - "Delete Query?": ["确定删除查询?"], - "Are you sure you want to delete the selected queries?": [ - "您确实要删除选定的查询吗?" + "We were unable to connect to your database named \"%(database)s\". Please verify your database name and try again.": [ + "我们无法连接到名为 \"%(database)s\" 的数据库。请确认您的数据库名字并重试" ], - "Query name": ["查询名称"], - "Edited": ["已编辑"], - "Created": ["已创建"], - "Viewed": ["已查看"], - "Examples": ["示例"], - "Mine": ["我的编辑"], - "Recently viewed charts, dashboards, and saved queries will appear here": [ - "最近查看的图表、看板和保存的查询将显示在此处" + "We were unable to connect to your database. Please confirm that your service account has the Viewer and Job User roles on the project.": [ + "我们无法连接到您的数据库。请确认您的服务帐户在项目中具有查看器和作业用户角色。" ], - "Recently created charts, dashboards, and saved queries will appear here": [ - "最近创建的图表、看板和保存的查询将显示在此处" + "Web": ["网络"], + "Wednesday": ["星期三"], + "Week": ["周"], + "Week ending Saturday": ["周一为一周结束"], + "Week starting Monday": ["周一为一周开始"], + "Week starting Sunday": ["周日为一周开始"], + "Week_ending Sunday": ["周日为一周结束"], + "Weeks %s": ["周 %s"], + "We’re having trouble loading these results. Queries are set to timeout after %s second.": [ + "加载结果时遇到问题。查询设置为 %s 秒后超时。" ], - "Recent example charts, dashboards, and saved queries will appear here": [ - "最近的示例图表、看板和保存的查询将显示在此处" + "We’re having trouble loading this visualization. Queries are set to timeout after %s second.": [ + "加载此可视化效果时遇到问题。查询设置为 %s 秒后超时。" ], - "Recently edited charts, dashboards, and saved queries will appear here": [ - "最近编辑的图表、看板和保存的查询将显示在此处" + "What should be shown on the label?": ["标签上需要显示的内容"], + "When `Calculation type` is set to \"Percentage change\", the Y Axis Format is forced to `.1%`": [ + "当设置“周期比”时,y轴格式强制为“1%”。" ], - "DASHBOARD": ["看板"], - "CHART": ["图表"], - "You don't have any favorites yet!": ["您还没有任何的收藏!"], - "SQL Lab queries": ["SQL工具箱查询"], - "See all": ["查看所有"], - "saved queries": ["已保存查询"], - "dashboards": ["看板"], - "charts": ["图表"], - "query": ["查询"], - "Share": ["分享"], - "Last run %s": ["上次执行 %s"], - "Recents": ["最近"], - "Select start and end date": ["选择开始和结束时间"], - "Type or Select [%s]": ["键入或选择 [%s]"], - "Filter box": ["过滤器"], - "Filters configuration": ["过滤配置"], - "Filter configuration for the filter box": ["过滤条件的过滤配置"], - "Date filter": ["日期过滤器"], - "Whether to include a time filter": ["是否包含时间过滤器"], - "Instant filtering": ["即时过滤"], - "Check to apply filters instantly as they change instead of displaying [Apply] button": [ - "选中可在过滤条件更改时立即应用过滤,而不是使用 [应用] 按钮" + "When a secondary metric is provided, a linear color scale is used.": [ + "当提供次计量指标时,会使用线性色阶。" ], - "Show SQL granularity dropdown": ["显示SQL时间粒度下拉列表"], - "Check to include SQL granularity dropdown": [ - "检查是否包含SQL时间粒度下拉列表" + "When allowing CREATE TABLE AS option in SQL Lab, this option forces the table to be created in this schema": [ + "当在 SQL 编辑器中允许 CREATE TABLE AS 选项时,此选项可以此模式中强制创建表" ], - "Show SQL time column": ["显示SQL时间列"], - "Check to include time column dropdown": ["检查包含时间列下拉列表"], - "Show Druid granularity dropdown": ["显示Druid时间粒度下拉列表"], - "Check to include Druid granularity dropdown": [ - "检查包含Druid时间粒度下拉列表" + "When enabled, users are able to visualize SQL Lab results in Explore.": [ + "启用后,用户可以在Explore中可视化SQL实验室结果。" ], - "Show Druid time origin": ["显示Druid原始时间"], - "Check to include time origin dropdown": ["检查包含时间原点的下拉列表"], - "Limit selector values": ["限制选择器值"], - "These filters apply to the values available in the dropdowns": [ - "这些过滤器应用于下拉列表中的可用值" + "When only a primary metric is provided, a categorical color scale is used.": [ + "如果只提供了一个主计量指标,则使用分类色阶。" ], - "Time-series Table": ["时间序列-表格"], - "All": ["所有"], - "Any": ["所有"], - "Line Chart": ["多线图"], - "Bar Chart": ["条形图"], - "Area Chart": ["面积图"], - "deck.gl Polygon": ["deck.gl 多边形图层"], - "deck.gl Scatterplot": ["deck.gl 散点图"], - "deck.gl 3D Hexagon": ["deck.gl 3D 六角图层"], - "Time-series Period Pivot": ["时间序列-周期轴"], - "deck.gl Arc": ["deck.gl 弧形图层"], - "deck.gl Grid": ["deck.gl 网格图层"], - "deck.gl Screen Grid": ["deck.gl 筛网图层"], - "Dual Line Chart": ["双线图"], - "Multiple Line Charts": ["复合折线图"], - "Sunburst Chart": ["旭日/太阳图"], - "Sankey Diagram": ["桑基图"], - "MapBox": ["MapBox地图"], - "Nightingale Rose Chart": ["南丁格尔玫瑰图"], - "deck.gl Geojson": ["deck.gl Geojson"], - "Horizon Chart": ["地平线图"], - "deck.gl Multiple Layers": ["deck.gl 复合图层"], - "Time-series Percent Change": ["时间序列-百分比变化"], - "Partition Chart": ["分区图"], - "Event Flow": ["事件流"], - "deck.gl Path": ["deck.gl 路线图层"], - "Force-directed Graph": ["力导向图"], - "Paired t-test Table": ["配对T检测表"], - "Time-series Chart": ["时间序列图"], - "Time-series Bar Chart": ["时间序列-条形图"], - "Word Cloud": ["词汇云"], - "Chord Diagram": ["弦图"], - "Pie Chart": ["饼图"], - "Range filter plugin": ["范围过滤器"], - "Select filter plugin": ["选择过滤器"], - "Anhui": ["安徽"], - "Beijing": ["北京"], - "Chongqing": ["重庆"], - "Fujian": ["福建"], - "Gansu": ["甘肃"], - "Guangdong": ["广东"], - "Guangxi": ["广西"], - "Guizhou": ["贵州"], - "Hainan": ["海南"], - "Hebei": ["河北"], - "Heilongjiang": ["黑龙江"], - "Henan": ["河南"], - "Hubei": ["湖北"], - "Hunan": ["湖南"], - "Jiangsu": ["江苏"], - "Jiangxi": ["江西"], - "Jilin": ["吉林"], - "Liaoning": ["辽宁"], - "Nei Mongol": ["内蒙古"], - "Ningxia Hui": ["宁夏"], - "Qinghai": ["青海"], - "Shaanxi": ["陕西"], - "Shandong": ["山东"], - "Shanghai": ["上海"], - "Shanxi": ["山西"], - "Sichuan": ["四川"], - "Tianjin": ["天津"], - "Xinjiang Uygur": ["新疆"], - "Xizang": ["西藏"], - "Yunnan": ["云南"], - "Zhejiang": ["浙江"], - "Taiwan": ["台湾"], - "Hong Kong": ["香港"], - "Macao": ["澳门"], - "Sort:": ["排序:"], - "Alphabetical": ["按字母顺序排列"], - "Recently modified": ["最近修改"], - "Least recently modified": ["最远修改"], - "[ untitled dashboard ]": ["[ 未命名看板 ]"], - "published": ["已发布"], - "draft": ["草稿"], - "Recent": ["最近"], - "Sort by %s": ["排序 %s"], - "Missing dataset": ["丢失数据集"], - "The dataset linked to this chart may have been deleted.": [ - "这个图表所链接的数据集可能被删除了。" + "When specifying SQL, the datasource acts as a view. Superset will use this statement as a subquery while grouping and filtering on the generated parent queries.": [ + "指定SQL时,数据源会充当视图。在对生成的父查询进行分组和筛选时,系统将使用此语句作为子查询。" ], - "Autocomplete": ["自动补全"], - "Failed at stopping query. ": ["停止查询时候出错。 "], - "-- Note: Unless you save your query, these tabs will NOT persist if you clear your cookies or change browsers.": [ - "-- 注意:除非您保存查询,否则如果清除cookie或更改浏览器时,这些选项卡将不会保留。" + "When using \"Autocomplete filters\", this can be used to improve performance of the query fetching the values. Use this option to apply a predicate (WHERE clause) to the query selecting the distinct values from the table. Typically the intent would be to limit the scan by applying a relative time filter on a partitioned or indexed time-related field.": [ + "当使用 \"自适配过滤条件\" 时,这可以用来提高获取查询数据的性能。使用此选项可将谓词(WHERE子句)应用于从表中进行选择不同值的查询。通常,这样做的目的是通过对分区或索引的相关时间字段配置相对应的过滤时间来限制扫描。" ], - "New tab (Ctrl + t)": ["新建Tab页 (Ctrl + t)"], - "Last Edited: %s": ["最后编辑时间:%s"], - "View All »": ["查看所有 »"], - "Add an item": ["新增一行"], - "remove item": ["删除该行"], - "last day": ["上一(昨)天"], - "last week": ["上一周"], - "last month": ["上一月"], - "last quarter": ["上一季度"], - "last year": ["上一年"], - "previous calendar week": ["前一周"], - "previous calendar month": ["前一月"], - "previous calendar year": ["前一年"], - "Configure Advanced Time Range ": ["配置进阶时间范围"], - "Specific Date/Time": ["具体日期/时间"], - "Relative Date/Time": ["相对日期/时间"], - "Now": ["现在"], - "Midnight": ["凌晨(当天)"], - "Seconds": ["秒"], - "Minutes": ["分钟"], - "Hours": ["小时"], - "Days": ["天"], - "Weeks": ["周"], - "Months": ["月"], - "Quarters": ["季度"], - "Years": ["年"], - "Before": ["之前"], - "Unexpected time range: %(error)s": ["时间范围异常: %(error)s"], - "Return to specific datetime.": ["返回指定的日期时间。"], - "Syntax": ["语法"], - "Example": ["例子"], - "Moves the given set of dates by a specified interval.": [ - "将给定的日期集以指定的间隔进行移动" + "When using 'Group By' you are limited to use a single metric": [ + "当使用“Group by”时,只限于使用单个度量。" ], - "Truncates the specified date to the accuracy specified by the date unit.": [ - "将指定的日期截取为指定的日期单位精度。" + "Whether the progress bar overlaps when there are multiple groups of data": [ + "当有多组数据时进度条是否重叠" ], - "Get the last date by the date unit.": ["按日期单位获取最后的日期。"], - "Get the specify date for the holiday": ["获取指定节假日的日期"], - "Loading...": ["加载中..."], - "Transparent": ["透明"], - "White": ["白色"], - "background": ["背景"], - "New header": ["新标题"], - "Fixed": ["固定值"], - "Based on a metric": ["基于指标"], - "week_start_sunday": ["周日为一周结束"], - "week_start_monday": ["周一为一周开始"], - "duration": ["执行时间"], - "state": ["状态"], - "started": ["开始时间"], - "progress": ["进度"], - "output": ["输出"], - "actions": ["操作"], - "success": ["成功"], - "failed": ["失败"], - "cannot be empty": ["不能为空"], - "Options": ["设置"], - "Time Column": ["时间列"], - "Time Range": ["时间范围"], - "Color Scheme": ["配色方案"], - "Datasource & Chart Type": ["数据源 & 图表类型"], - "URL Parameters": ["URL参数"], - "Annotations and Layers": ["注释与注释层"], - "Time Grain": ["时间粒度(Grain)"], - "Time Granularity": ["时间粒度(Granularity)"], - "Minimum Font Size": ["最小字体大小"], - "Maximum Font Size": ["最大字体大小"], - "Word Rotation": ["单词旋转"], - "Rotation to apply to words in the cloud": [ - "应用于词云中的单词的旋转方式" + "Whether the table was generated by the 'Visualize' flow in SQL Lab": [ + "表是否由 sql 实验室中的 \"可视化\" 流生成" ], - "Font size for the smallest value in the list": [ - "列表中最小值的字体大小" + "Whether this column is exposed in the `Filters` section of the explore view.": [ + "该列是否在浏览视图的`过滤器`部分显示。" ], - "Font size for the biggest value in the list": ["列表中最大值的字体大小"], - "D3 time format syntax: https://github.com/d3/d3-time-format": [ - "D3时间插件格式语法: https://github.com/d3/d3-time-format" + "Whether to align background charts with both positive and negative values at 0": [ + "是否 +/- 对齐背景图数值" ], - "D3 format syntax: https://github.com/d3/d3-format": [ - "D3插件格式语法: https://github.com/d3/d3-time-format" + "Whether to align positive and negative values in cell bar chart at 0": [ + "单元格条形图中的正负值是否按0对齐" ], - "Whether to apply filter to dashboards when table cells are clicked": [ - "单击表单元格时是否对看板应用过滤条件" + "Whether to always show the annotation label": ["是否显示标签。"], + "Whether to animate the progress and the value or just display them": [ + "是以动画形式显示进度和值,还是仅显示它们" ], - "Adaptive formatting": ["自动匹配格式化"], - "Aggregate": ["聚合"], - "Raw Records": ["原始记录"], - "Query Mode": ["查询模式"], - "Columns to display": ["要显示的字段"], - "Percentage Metrics": ["百分比度量"], - "Metrics for which percentage of total are to be displayed": [ - "要显示总数百分比的度量" + "Whether to apply a normal distribution based on rank on the color scale": [ + "是否应用基于色标等级的正态分布" ], - "Ordering": ["排序"], - "Include Time": ["包含时间"], - "Sort Descending": ["降序"], - "Table Timestamp Format": ["表时间戳格式"], - "Timestamp Format": ["时间戳格式"], - "Page Length": ["页面长度"], - "Rows per page, 0 means no pagination": ["每页行数,0 表示没有分页"], - "Search Box": ["搜索框"], - "Whether to include a client-side search box": ["是否包含客户端搜索框"], - "Emit Filter Events": ["触发筛选器事件"], - "Align +/-": ["对齐 +/-"], - "Whether to align the background chart for +/- values": [ - "是否 +/- 对齐背景图数值" + "Whether to colorize numeric values by if they are positive or negative": [ + "根据数值是正数还是负数来为其上色" ], - "Color +/-": ["色彩 +/-"], - "Whether to color +/- values": ["是否 +/- 颜色数值"], - "Show Cell Bars": ["显示单元格的栏"], - "Enable to display bar chart background elements in table columns": [ + "Whether to display a bar chart background in table columns": [ "为指标添加条状图背景" ], - "X Tick Layout": ["X轴记号图层"], - "The way the ticks are laid out on the X-axis": ["X轴记号的排列显示方式"], - "Number format": ["数字格式化"], - "Distribute across": ["基于某列进行分布"], - "Categories to group by on the x-axis.": ["要在x轴上分组的类别。"], - "Columns to calculate distribution across. Defaults to temporal column if left empty.": [ - "计算分布的列。如果留空,则默认为临时列。" + "Whether to display a legend for the chart": [ + "是否显示图表的图示(色块分布)" ], - "Determines how whiskers and outliers are calculated.": [ - "确定如何计算箱须和离群值。" + "Whether to display bubbles on top of countries": [ + "是否在国家之上展示气泡" ], - "Whisker/outlier options": ["箱须/离群值选项"], - "Chart Options": ["图表选项"], - "Sort By": ["排序"], - "Whether to include the time granularity as defined in the time section": [ - "是否包含时间段中定义的时间粒度" + "Whether to display the interactive data table": [ + "是否将指标名显示为标题" + ], + "Whether to display the labels.": ["是否显示标签。"], + "Whether to display the labels. Note that the label only displays when the the 5% threshold.": [ + "是否显示标签。" ], - "No filter": ["无筛选"], - "Last": ["上一"], - "Custom": ["自定义"], - "custom_start_end": ["自定义起始时间"], - "custom_range": ["自定义区间"], - "Legend": ["图示"], "Whether to display the legend (toggles)": ["是否显示图示(切换)"], - "Show Metric Names": ["显示指标名"], "Whether to display the metric name as a title": [ "是否将指标名显示为标题" ], - "Number Format": ["数字格式"], - "Pivot Options": ["透视表选项"], - "Domain": ["主域"], - "The time unit used for the grouping of blocks": ["用于块分组的时间单位"], - "Subdomain": ["子域"], - "The time unit for each block. Should be a smaller unit than domain_granularity. Should be larger or equal to Time Grain": [ - "每个块的时间单位。应该是主域域粒度更小的单位。应该大于或等于时间粒度" - ], - "Cell Size": ["单元尺寸"], - "The size of the square cell, in pixels": [ - "平方单元的大小,以像素为单位" + "Whether to display the min and max values of the X-axis": [ + "是否显示X轴的最小值和最大值" ], - "Cell Padding": ["单元填充"], - "The distance between cells, in pixels": [ - "单元格之间的距离,以像素为单位" + "Whether to display the min and max values of the Y-axis": [ + "是否显示Y轴的最小值和最大值" ], - "Cell Radius": ["单元格半径"], - "The pixel radius": ["像素半径"], - "Color Steps": ["色彩 Steps"], - "The number color \"steps\"": ["色彩 \"Steps\" 数字"], - "Time Format": ["时间格式"], - "Show Values": ["显示值"], "Whether to display the numerical values within the cells": [ "是否在单元格内显示数值" ], - "Aggregate function to apply when pivoting and computing the total rows and columns": [ - "在旋转和计算总的行和列时,应用聚合函数" - ], - "Show totals": ["显示总计"], - "Display total row/column": ["显示总行 / 列"], - "Combine Metrics": ["整合指标"], - "Display metrics side by side within each column, as opposed to each column being displayed side by side for each metric.": [ - "在每个列中并排显示指标,而不是每个指标并排显示每个列。" - ], - "Transpose Pivot": ["转置透视图"], - "Swap Groups and Columns": ["交换组和列"], - "Date format": ["日期格式化"], - "Labels": ["标签"], - "Label Type": ["标签类型"], - "Whether to display a legend for the chart": [ - "是否显示图表的图示(色块分布)" + "Whether to display the time range interactive selector": [ + "是否显示时间范围交互选择器" ], - "What should be shown on the label?": ["标签上需要显示的内容"], - "Only applies when \"Label Type\" is set to show values.": [ - "仅当\"标签类型\"设置为显示值时适用。" + "Whether to display the timestamp": ["是否显示笔划"], + "Whether to display the trend line": ["是否显示笔划"], + "Whether to enable changing graph position and scaling.": [ + "是否启用更改图形位置和缩放。" ], - "Show Labels": ["显示标签"], - "Whether to display the labels.": ["是否显示标签。"], - "Put labels outside": ["外侧显示标签"], - "Put the labels outside of the pie?": ["是否将标签显示在饼图外侧?"], - "Label Line": ["标签线"], - "Draw line from Pie to label when labels outside?": [ - "当标签在外侧时,是否在饼图到标签之间连线?" + "Whether to enable node dragging in force layout mode.": [ + "是否在强制布局模式下启用节点拖动。" ], - "Pie shape": ["饼图形状"], - "Outer Radius": ["外缘"], - "Outer edge of Pie chart": ["饼图外缘"], - "Donut": ["圆环圈"], - "Do you want a donut or a pie?": ["是否用圆环圈替代饼图?"], - "Inner Radius": ["内半径"], - "Inner radius of donut hole": ["圆环圈内部空洞的内径"], - "Show percentage": ["显示百分比"], + "Whether to format the timestamp": ["是否规范化直方图"], + "Whether to include a client-side search box": ["是否包含客户端搜索框"], + "Whether to include a time filter": ["是否包含时间过滤器"], "Whether to include the percentage in the tooltip": [ "是否在工具提示中包含百分比" ], - "Normalized": ["标准化"], + "Whether to include the time granularity as defined in the time section": [ + "是否包含时间段中定义的时间粒度" + ], + "Whether to make the histogram cumulative": ["是否规范化直方图"], + "Whether to make this column available as a [Time Granularity] option, column has to be DATETIME or DATETIME-like": [ + "是否将此列作为[时间粒度]选项, 列中的数据类型必须是DATETIME" + ], "Whether to normalize the histogram": ["是否规范化直方图"], - "Sort X Axis": ["排序X轴"], - "Sort Y Axis": ["排序Y轴"], - "Value Format": ["数值格式"], - "Value bounds": ["值边界"], - "Hard value bounds applied for color coding. Is only relevant and applied when the normalization is applied against the whole heatmap.": [ - "应用于颜色编码的硬值边界。只有当对整个热图应用标准化时才是相关的和应用的。" + "Whether to populate autocomplete filters options": [ + "是否填充自适配过滤条件选项" ], - "Bottom Margin": ["底部边距"], - "Bottom margin, in pixels, allowing for more room for axis labels": [ - "底部边距,以像素为单位,为轴标签留出更多空间" + "Whether to populate the filter's dropdown in the explore view's filter section with a list of distinct values fetched from the backend on the fly": [ + "是否在浏览视图的过滤器部分中填充过滤器的下拉列表,并提供从后端获取的不同值的列表" ], - "Left Margin": ["左边距"], - "Left margin, in pixels, allowing for more room for axis labels": [ - "左边距,以像素为单位,为轴标签留出更多空间" + "Whether to show extra controls or not. Extra controls include things like making mulitBar charts stacked or side by side.": [ + "是否显示额外的控件。额外的控制包括使多栏图表堆叠或并排。" ], - "Normalize Across": ["标准化通过"], - "Color will be rendered based on a ratio of the cell against the sum of across this criteria": [ - "颜色将根据单元格与整个标准之和的比率来展示" + "Whether to show minor ticks on the axis": ["是否忽略空位置"], + "Whether to show the pointer": ["是否显示笔划"], + "Whether to show the progress of gauge chart": ["是否显示量规图进度"], + "Whether to show the split lines on the axis": [ + "是否显示Y轴的最小值和最大值" ], - "Rendering": ["渲染"], - "image-rendering CSS attribute of the canvas object that defines how the browser scales up the image": [ - "图像渲染画布对象的 CSS 属性,它定义了浏览器如何放大图像" + "Whether to sort descending or ascending": ["是降序还是升序排序"], + "Whether to sort descending or ascending. Takes effect only when \"Sort by\" is set": [ + "是降序还是升序排序" ], - "YScale Interval": ["Y轴比例尺间隔"], - "Number of steps to take between ticks when displaying the Y scale": [ - "显示 Y 刻度时,在刻度之间表示的步骤数" + "Whether to sort results by the selected metric in descending order.": [ + "是否按所选指标按降序对结果进行排序。" + ], + "Whether to sort tooltip by the selected metric in descending order.": [ + "是否按所选指标按降序对结果进行排序。" + ], + "Which country to plot the map for?": ["为哪个国家绘制地图?"], + "Which relatives to highlight on hover": ["在悬停时突出显示哪些关系"], + "Whisker/outlier options": ["箱须/离群值选项"], + "White": ["白色"], + "Width": ["宽度"], + "Width of the confidence interval. Should be between 0 and 1": [ + "置信区间必须介于0和1(不包含1)之间" ], + "Window must be > 0": ["窗口必须大于0"], + "With a subheader": ["子标题"], + "Word Cloud": ["词汇云"], + "Word Rotation": ["单词旋转"], + "Working": ["正在执行"], + "Working timeout": ["执行超时"], + "World Map": ["世界地图"], + "Write a description for your query": ["为您的查询写一段描述"], + "Write dataframe index as a column.": ["将dataframe index 作为列."], + "X AXIS TITLE BOTTOM MARGIN": ["X 轴标题下边距"], + "X Axis": ["X 轴"], + "X Axis Format": ["X 轴格式化"], + "X Axis Label": ["X 轴标签"], + "X Axis Title": ["X轴标题"], + "X Log Scale": ["X经度标度"], + "X Tick Layout": ["X轴记号图层"], + "X bounds": ["X界限"], "XScale Interval": ["X轴比例尺间隔"], - "Number of steps to take between ticks when displaying the X scale": [ - "显示 X 刻度时,在刻度之间表示的步骤数" + "Y 2 bounds": ["Y界限"], + "Y AXIS TITLE MARGIN": ["Y轴标题页边距"], + "Y AXIS TITLE POSITION": ["Y轴标题位置"], + "Y Axis": ["Y 轴"], + "Y Axis 1": ["Y 轴 1"], + "Y Axis 2": ["Y 轴 2"], + "Y Axis 2 Bounds": ["Y 轴界限"], + "Y Axis Bounds": ["Y 轴界限"], + "Y Axis Format": ["Y 轴格式化"], + "Y Axis Label": ["Y 轴标签"], + "Y Axis Left": ["Y轴左侧"], + "Y Axis Right": ["Y轴右侧"], + "Y Axis Title": ["Y 轴标题"], + "Y Log Scale": ["Y经度标度"], + "Y bounds": ["Y界限"], + "YScale Interval": ["Y轴比例尺间隔"], + "Year": ["年"], + "Years %s": ["年"], + "Yes": ["是"], + "Yes, cancel": ["是的,取消"], + "You are importing one or more charts that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "您正在导入一个或多个已存在的图表。覆盖可能会导致您丢失一些工作。您确定要覆盖吗?" ], - "Margin": ["边距(margin)"], - "Additional padding for legend.": ["图示附加的padding值。"], - "Legend type": ["图示类型"], - "Orientation": ["方向"], - "Axis ascending": ["轴线升序"], - "Axis descending": ["轴线降序"], - "Metric ascending": ["指标升序"], - "Metric descending": ["指标降序"], - "Series Height": ["序列高度"], - "Pixel height of each series": ["每个序列的像素高度"], - "Value Domain": ["值域"], - "series: Treat each series independently; overall: All series use the same scale; change: Show changes compared to the first data point in each series": [ - "series:独立处理每个序列;overall:所有序列使用相同的比例;change:显示与每个序列中第一个数据点相比的更改" + "You are importing one or more dashboards that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "您正在导入一个或多个已存在的仪表板。覆盖可能会导致您丢失一些工作。确定要覆盖吗?" ], - "Ratio": ["比率"], - "Target aspect ratio for treemap tiles.": ["树形图中图块的目标高宽比。"], - "Country Field Type": ["国家字段的类型"], - "The country code standard that Superset should expect to find in the [country] column": [ - "Superset 希望能够在 [国家] 栏中找到的 国家 / 地区 的标准代码" + "You are importing one or more databases that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "您正在导入一个或多个已存在的数据库。覆盖可能会导致您丢失一些工作。您确定要覆盖吗?" ], - "Show Bubbles": ["显示气泡"], - "Whether to display bubbles on top of countries": [ - "是否在国家之上展示气泡" + "You are importing one or more datasets that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "您正在导入一个或多个已存在的数据集。覆盖可能会导致您丢失一些工作。确定要覆盖吗?" ], - "Max Bubble Size": ["最大气泡的尺寸"], - "Country Column": ["国家字段"], - "3 letter code of the country": ["国家3字母代码"], - "Metric for Color": ["颜色指标"], - "Metric that defines the color of the country": ["定义国家度量的颜色"], - "Bubble Size": ["气泡大小"], - "Metric that defines the size of the bubble": ["定义指标的气泡大小"], - "Bubble Color": ["气泡颜色"], - "Country Color Scheme": ["国家颜色方案"], - "Linear Color Scheme": ["线性颜色方案"], - "Heatmap Options": ["热图选项"], - "Advanced Analytics": ["高级分析"], - "Rolling Window": ["滚动窗口"], - "Rolling Function": ["滚动函数"], - "Min Periods": ["最小周期"], - "Time Comparison": ["时间比对"], - "Time Shift": ["时间偏移"], - "Python Functions": ["Python函数"], - "Bad formula.": ["错误公式。"], - "Select the Annotation Layer you would like to use.": [ - "选择要使用的注释图层。" + "You are importing one or more saved queries that already exist. Overwriting might cause you to lose some of your work. Are you sure you want to overwrite?": [ + "您正在导入一个或多个已存在的图表。覆盖可能会导致您丢失一些工作。您确定要覆盖吗?" ], - "Formula": ["公式"], - "Automatic Color": ["自动上色"], - "Choose the source of your annotations": ["选择您的注释来源"], - "Annotation Source": ["注释来源"], - "No options": ["没有选项"], - "Superset annotation": ["Superset注释"], - "Use another existing chart as a source for annotations and overlays. Your chart must be one of these visualization types: [%s]": [ - "使用预定义的图表作为注释和覆盖的源。图表必须是以下可视化类型之一: [%s]" + "You are not authorized to fetch samples from this table. If you think this is an error, please reach out to your administrator.": [ + "您无权从这个表中获取样本。" ], - "Expects a formula with depending time parameter 'x'\n in milliseconds since epoch. mathjs is used to evaluate the formulas.\n Example: '2x+5'": [ - "需要一个从Epoch(1970年1月1日00:00:00 UTC)时间点开始的时间参数“x”,并以此来计算的公式(以毫秒为单位)。我们使用“mathjs”来进行公式的计算。例如:'2x+5'" + "You are not authorized to see this query. If you think this is an error, please reach out to your administrator.": [ + "您无权查看此查询。" ], - "No of Bins": ["直方图容器数"], - "Select number of bins for the histogram": ["选择直方图的容器数"], - "X Axis Label": ["X 轴标签"], - "Y Axis Label": ["Y 轴标签"], - "Right Axis Format": ["右轴格式化"], - "Show Markers": ["显示标记"], - "Show data points as circle markers on the lines": [ - "将数据点显示为线条上的圆形标记" + "You cannot specify a namespace both in the name of the table: \"%(columnar_table.table)s\" and in the schema field: \"%(columnar_table.schema)s\". Please remove one": [ + "不能同时在表名 \"%(columnar_table.table)s\" 和schema字段 \"%(columnar_table.schema)s\" 中指定命名空间。请删除一个。" ], - "Y bounds": ["Y界限"], - "Whether to display the min and max values of the Y-axis": [ - "是否显示Y轴的最小值和最大值" + "You cannot specify a namespace both in the name of the table: \"%(csv_table.table)s\" and in the schema field: \"%(csv_table.schema)s\". Please remove one": [ + "不能同时在表名 \"%(csv_table.table)s\" 和schema字段 \"%(csv_table.schema)s\" 中指定命名空间。请删除一个。" + ], + "You cannot specify a namespace both in the name of the table: \"%(excel_table.table)s\" and in the schema field: \"%(excel_table.schema)s\". Please remove one": [ + "不能同时在表名 \"%(excel_table.table)s\" 和schema字段 \"%(excel_table.schema)s\" 中指定命名空间。请删除一个。" + ], + "You cannot use 45° tick layout along with the time range filter": [ + "不能将45°刻度线布局与时间范围过滤器一起使用" + ], + "You cannot use [Columns] in combination with [Group By]/[Metrics]/[Percentage Metrics]. Please choose one or the other.": [ + "不能将 [列] 与 [分组]/[指标]/[百分比度量] 结合使用。请选择其中一个。" + ], + "You do not have permission to edit this chart": [ + "您没有编辑此图表的权限" + ], + "You do not have permission to edit this dashboard": [ + "您没有编辑此看板的权限" + ], + "You do not have permissions to access the datasource(s): %(name)s.": [ + "您没有权限访问该数据源: %(name)s。" + ], + "You do not have permissions to edit this dashboard.": [ + "您没有编辑此看板的权限。" ], - "Line Style": ["线条样式"], - "Line interpolation as defined by d3.js": ["由 d3.js 定义的线插值"], - "Show Range Filter": ["显示范围过滤器"], - "Whether to display the time range interactiWhether to display the legend (toggles)ve selector": [ - "是否显示时间范围交互选择器" + "You don't have access to this dashboard.": ["您没有编辑此看板的权限。"], + "You don't have any favorites yet!": ["您还没有任何的收藏!"], + "You don't have permission to modify the value.": [ + "您没有编辑此图表的权限" ], - "Extra Controls": ["额外控件"], - "Whether to show extra controls or not. Extra controls include things like making mulitBar charts stacked or side by side.": [ - "是否显示额外的控件。额外的控制包括使多栏图表堆叠或并排。" + "You don't have the rights to ": ["您没有授权 "], + "You don't have the rights to alter this title.": [ + "您没有权利修改这个标题。" ], - "X Axis Format": ["X 轴格式化"], - "Y Log Scale": ["Y经度标度"], - "Use a log scale for the Y-axis": ["使用Y轴的对数刻度"], - "Y Axis Bounds": ["Y 轴界限"], - "Bounds for the Y axis. When left empty, the bounds are dynamically defined based on the min/max of the data. Note that this feature will only expand the axis range. It won't narrow the data's extent.": [ - "Y轴的边界。当空时,边界是根据数据的最小/最大值动态定义的。请注意,此功能只会扩展轴范围。它不会缩小数据范围。" + "You have no permission to approve this request": [ + "您没有此请求的访问权限" ], - "X bounds": ["X界限"], - "Whether to display the min and max values of the X-axis": [ - "是否显示X轴的最小值和最大值" + "You have removed this filter.": ["您已删除此过滤条件。"], + "You have unsaved changes.": ["您有一些未保存的修改。"], + "You must pick a name for the new dashboard": [ + "您必须为新的看板选择一个名称" ], - "Rich Tooltip": ["详细提示"], - "The rich tooltip shows a list of all series for that point in time": [ - "详细提示显示了该时间点的所有序列的列表。" + "You must run the query successfully first": ["必须先成功运行查询"], + "Your dashboard is too large. Please reduce its size before saving it.": [ + "您的看板太大了。保存前请缩小尺寸。" ], - "Bar Values": ["条形栏的值"], - "Show the value on top of the bar": ["显示栏上的值"], - "Stacked Bars": ["堆叠条形图"], - "Reduce X ticks": ["减少 X 轴的刻度"], - "Reduces the number of X-axis ticks to be rendered. If true, the x-axis will not overflow and labels may be missing. If false, a minimum width will be applied to columns and the width may overflow into an horizontal scroll.": [ - "减少要渲染的X轴标记数。如果为true,x轴将不会溢出,但是标签可能丢失。如果为false,则对列应用最小宽度,宽度可能溢出到水平滚动条中。" + "Your query could not be saved": ["您的查询无法保存"], + "Your query could not be scheduled": ["无法调度您的查询"], + "Your query could not be updated": ["无法更新您的查询"], + "Your query has been scheduled. To see details of your query, navigate to Saved queries": [ + "您的查询已被调度。要查看查询的详细信息,请跳转到保存查询页面查看。" ], - "Time series": ["时间序列"], - "Interval": ["间隔"], - "Event": ["事件"], - "Hierarchy": ["层次"], - "This defines the level of the hierarchy": ["该选项定义了层次级别"], - "Primary Metric": ["主计量指标"], - "The primary metric is used to define the arc segment sizes": [ - "主计量指标用于定义弧段大小。" + "Your query was saved": ["您的查询已保存"], + "Your query was updated": ["您的查询已保存"], + "Your report could not be deleted": ["这个查询无法被加载。"], + "Zoom": ["缩放"], + "Zoom level of the map": ["地图缩放等级"], + "[Alert] %(label)s": ["[警报] %(label)s"], + "[From]-": ["[从]-"], + "[Longitude] and [Latitude] columns must be present in [Group By]": [ + "[经度] 和 [纬度] 的选择项必须出现在 [Group By]" ], - "Secondary Metric": ["次计量指标"], - "When only a primary metric is provided, a categorical color scale is used.": [ - "如果只提供了一个主计量指标,则使用分类色阶。" + "[Longitude] and [Latitude] must be set": [ + "[经度] 和 [纬度] 的选择项必须出现在 [Group By]" ], - "When a secondary metric is provided, a linear color scale is used.": [ - "当提供次计量指标时,会使用线性色阶。" + "[Missing Dataset]": ["丢失数据集"], + "[Superset] Access to the datasource %(name)s was granted": [ + "[Superset] 允许访问数据源 %(name)s" ], + "[To]-": ["[至]-"], + "[Untitled]": ["无标题"], + "[dashboard name]": ["[看板名称]"], "[optional] this secondary metric is used to define the color as a ratio against the primary metric. When omitted, the color is categorical and based on labels": [ "次计量指标用来定义颜色与主度量的比率。如果两个度量匹配,则将颜色映射到级别组" ], - "Stacked Style": ["堆积样式"], - "Subheader": ["子标题"], - "Description text that shows up below your Big Number": [ - "在大数字下面显示描述文本" + "`compare_columns` must have the same length as `source_columns`.": [ + "长度必须保持一致" ], - "Big Number Font Size": ["数字的字体大小"], - "Subheader Font Size": ["子标题的字体大小"], - "Tiny": ["微小"], - "Small": ["小"], - "Normal": ["正常"], - "Large": ["大"], - "Medium": ["中"], - "Huge": ["巨大"], - "Breakdowns": ["分解"], - "Defines how each series is broken down": ["定义每个序列是如何被分解的"], - "Sort Bars": ["排序条形栏"], - "Sort bars by x labels.": ["按 x 标签排序。"], - "Source / Target": ["源/目标"], - "Choose a source and a target": ["选择一个源和一个目标"], - "Sort by metric": ["排序指标"], - "Whether to sort results by the selected metric in descending order.": [ - "是否按所选指标按降序对结果进行排序。" + "`compare_type` must be `difference`, `percentage` or `ratio`": [ + "`compare_type` 必须是 `difference`, `percentage` 或 `ratio`" ], - "Left Axis Metric": ["左轴指标"], - "Choose a metric for left axis": ["选择左轴的计量指标"], - "Left Axis Format": ["左轴格式化"], - "Right Axis Metric": ["右轴指标"], - "Propagate": ["传播"], - "Send range filter events to other charts": [ - "将过滤条件的事件发送到其他图表" + "`confidence_interval` must be between 0 and 1 (exclusive)": [ + "`置信区间` 必须介于0和1之间(开区间)" ], - "Aggregation function": ["聚合功能"], - "Y Axis Left": ["Y轴左侧"], - "Left Axis chart(s)": ["左轴图表"], - "Choose one or more charts for left axis": ["为左轴选择一个或多个图表"], - "Prefix metric name with slice name": ["用图表名称作为指标名称的前缀"], - "Y Axis Right": ["Y轴右侧"], - "Right Axis chart(s)": ["右轴图表"], - "Choose one or more charts for right axis": ["为右轴选择一个或多个图表"], - "X Log Scale": ["X经度标度"], - "Use a log scale for the X axis": ["X轴使用经度刻度"], - "Longitude": ["经度"], - "Column containing longitude data": ["包含经度数据的列"], - "Latitude": ["纬度"], - "Column containing latitude data": ["包含纬度数据的列"], - "Clustering Radius": ["簇半径"], - "The radius (in pixels) the algorithm uses to define a cluster. Choose 0 to turn off clustering, but beware that a large number of points (>1000) will cause lag.": [ - "算法用来定义一个簇的半径(以像素为单位)。选择0关闭聚,但要注意大量的点(>1000)会导致处理时间变长。" + "`count` is COUNT(*) if a group by is used. Numerical columns will be aggregated with the aggregator. Non-numerical columns will be used to label points. Leave empty to get a count of points in each cluster.": [ + "如果分组被使用 `count` 表示 COUNT(*)。数值列将与聚合器聚合。非数值列将用于维度列。留空以获得每个簇中的点计数。" ], - "Point Radius Scale": ["点半径比例尺"], - "The radius of individual points (ones that are not in a cluster). Either a numerical column or `Auto`, which scales the point based on the largest cluster": [ - "单个点的半径(不在簇中的点)。一个数值列或“AUTO”,它根据最大的聚类来缩放点。" + "`operation` property of post processing object undefined": [ + "后处理必须指定操作类型(`operation`)" ], - "Point Radius Unit": ["点半径单位"], - "The unit of measure for the specified point radius": [ - "指定点半径的度量单位" + "`prophet` package not installed": ["未安装程序包 `fbprophet`"], + "`rename_columns` must have the same length as `columns`.": [ + "长度必须保持一致" ], - "label": ["标签"], - "`count` is COUNT(*) if a group by is used. Numerical columns will be aggregated with the aggregator. Non-numerical columns will be used to label points. Leave empty to get a count of points in each cluster.": [ - "如果分组被使用 `count` 表示 COUNT(*)。数值列将与聚合器聚合。非数值列将用于维度列。留空以获得每个簇中的点计数。" + "`row_limit` must be greater than or equal to 0": [ + "`行限制` 必须大于或等于1" ], - "Cluster label aggregator": ["集群标签聚合器"], - "Aggregate function applied to the list of points in each cluster to produce the cluster label.": [ - "聚合函数应用于每个群集中的点列表以产生群集标签。" + "`row_offset` must be greater than or equal to 0": [ + "`行偏移量` 必须大于或等于0" ], - "Live render": ["实时渲染"], - "Points and clusters will update as viewport is being changed": [ - "点和簇将随着视图改变而更新。" + "`width` must be greater or equal to 0": ["`宽度` 必须大于或等于0"], + "aggregate": ["合计"], + "alert": ["警报"], + "alerts": ["警报"], + "also copy (duplicate) charts": ["同时复制图表"], + "alter this ": ["修改这个 "], + "ancestor": ["上一个"], + "and": ["和"], + "and the explore view times out at %s seconds ": [ + ",浏览视图在 %s 秒超时" ], - "Map Style": ["地图样式"], - "Base layer map style": ["地图基本层样式"], - "Opacity of all clusters, points, and labels. Between 0 and 1.": [ - "所有簇、点和标签的不透明度。在0到1之间。" + "annotation": ["注释"], + "annotation start time or end time is required.": [ + "注释的开始时间或结束时间是必需的。" ], - "RGB Color": ["RGB颜色"], - "The color for points and clusters in RGB": ["点和簇的颜色(RGB)"], - "Default longitude": ["默认经度"], - "Longitude of default viewport": ["默认视口经度"], - "Default latitude": ["默认纬度"], - "Latitude of default viewport": ["默认视口纬度"], - "Zoom": ["缩放"], - "Zoom level of the map": ["地图缩放等级"], - "One or many controls to group by. If grouping, latitude and longitude columns must be present.": [ - "使用一个或多个控件来分组。一旦分组,则纬度和经度列必须存在。" + "annotation_layer": ["注释层"], + "at": ["在"], + "bolt": ["螺栓"], + "bottom": ["底部"], + "cached": ["已缓存"], + "cannot be empty": ["不能为空"], + "cannot be used as a column name. The column name/alias \"__timestamp\"\n is reserved for the main temporal expression, and column aliases ending with\n double underscores followed by a numeric value (e.g. \"my_col__1\") are reserved\n for deduplicating duplicate column names. Please use aliases to rename the\n invalid column names.": [ + "不能作为一个列名称使用。列名/别名 \"__timestamp\"\n 是为主要的时间表达式保留的,列别名以双下划线结尾\n 并后跟一个数值(例如 \"my_col__1\")。 这是为了\n 保留用于消除重复的列名。请使用别名来\n 重命名无效的列名。" ], - "Visual Tweaks": ["视觉调整"], - "Labelling": ["标签"], - "Points": ["点配置"], - "Point Radius": ["点半径"], - "Link Length": ["连接长度"], - "Link length in the force layout": ["在力布局中的连接长度"], - "Charge": ["电荷数(作用力)"], - "Charge in the force layout": ["在力导向图中的电荷数(作用力)"], - "Longitude & Latitude": ["经纬度"], - "Ignore null locations": ["忽略空位置"], - "Whether to ignore locations that are null": ["是否忽略空位置"], - "Viewport": ["视口"], - "Parameters related to the view and perspective on the map": [ - "与视图和透视图相关的参数" + "chart": ["图表"], + "charts": ["图表"], + "choose WHERE or HAVING...": ["选择WHERE或HAVING子句..."], + "column": ["列"], + "count": ["列"], + "create a ": ["创建一个 "], + "css": ["css"], + "css_template": ["css模板"], + "cumulative": ["激活"], + "dashboard": ["看板"], + "dashboards": ["看板"], + "database": ["数据库"], + "dataset": ["数据集"], + "date": ["日期"], + "day": ["天"], + "day of the month": ["一个月中的天数"], + "day of the week": ["一周的天数"], + "delete": ["删除"], + "descendant": ["降序"], + "description": ["描述"], + "dialect+driver://username:password@host:port/database": [""], + "download as csv": ["下载为图片"], + "draft": ["草稿"], + "dttm": ["dttm"], + "e.g. ********": ["********"], + "e.g. 127.0.0.1": ["127.0.0.1"], + "e.g. 5432": ["5432"], + "e.g. Analytics": ["高级分析"], + "e.g. param1=value1¶m2=value2": ["例如:param1=value1¶m2=value2"], + "e.g. world_population": ["世界人口"], + "e.g., a \"user id\" column": ["时间序列的列"], + "every": ["任意"], + "every day of the month": ["每月的每一天"], + "every day of the week": ["一周的每一天"], + "every hour": ["每小时"], + "every minute": ["每分钟 UTC"], + "every month": ["每个月"], + "feature to store a summarized data set that you can then explore.": [ + "用于存储可供浏览的汇总数据集的功能。" ], - "Auto Zoom": ["自动缩放"], - "When checked, the map will zoom to your data after each query": [ - "选中后,地图将根据您的数据进行缩放。" + "fetching": ["抓取中"], + "filter_box will be deprecated in a future version of Superset. Please replace filter_box by dashboard filter components.": [ + "'filter_box将在Superset的未来版本中弃用。" ], - "Map": ["地图"], - "Point Size": ["点大小"], - "Fixed point radius": ["固定的点半径"], - "Point Unit": ["点单位"], - "Minimum Radius": ["最小半径"], - "Minimum radius size of the circle, in pixels. As the zoom level changes, this insures that the circle respects this minimum radius.": [ - "圆的最小半径大小,以像素为单位。随着缩放等级的变化,这保证了圆根据这个最小半径变化。" - ], - "Maximum Radius": ["最大半径"], - "Maxium radius size of the circle, in pixels. As the zoom level changes, this insures that the circle respects this maximum radius.": [ - "圆的最大半径大小,以像素为单位。随着缩放等级的变化,这保证了圆根据这个最大半径变化。" - ], - "Multiplier": ["乘数"], - "Factor to multiply the metric by": ["因子乘以度量指标"], - "Point Color": ["点颜色"], - "Categorical Color": ["分类颜色"], - "Fixed Color": ["固定颜色"], - "Legend Position": ["图示位置"], - "Choose the position of the legend": ["选择图示的位置"], - "Legend Format": ["图示格式化"], - "Choose the format for legend values": ["选择图示值的格式化方式"], - "Dimension": ["维度"], - "Select a dimension": ["选择一个维度"], - "Extra data for JS": ["额外的JS数据"], - "List of extra columns made available in Javascript functions": [ - "JavaScript函数中可用的额外列的列表" - ], - "Javascript tooltip generator": ["JavaScript工具提示生成器"], - "Define a function that receives the input and outputs the content for a tooltip": [ - "定义一个函数,接收输入输出工具提示的内容" - ], - "This functionality is disabled in your environment for security reasons.": [ - "出于安全原因,该功能在您的环境中被禁用。" - ], - "Javascript onClick href": ["Javascript onClick事件触发转跳地址"], - "Define a function that returns a URL to navigate to when user clicks": [ - "定义一个函数,当用户单击时返回导航URL" - ], - "Grid": ["网格"], - "Grid Size": ["网格大小"], - "Defines the grid size in pixels": ["定义网格像素大小"], - "GeoJson Column": ["GeoJson 列"], - "Select the geojson column": ["选择 GeoJson 列"], - "GeoJson Settings": ["GeoJson设置"], - "Fill Color": ["填充颜色"], - " Set the opacity to 0 if you do not want to override the color specified in the GeoJSON": [ - "如果不想重写GeoJSON中指定的颜色,则将不透明度设置为0。" - ], - "Stroke Color": ["笔划颜色"], - "Filled": ["填充"], - "Whether to fill the objects": ["是否填充对象"], - "Stroked": ["笔划"], - "Whether to display the stroke": ["是否显示笔划"], - "Extruded": ["突出"], - "Whether to make the grid 3D": ["是否将网格设置为3D"], - "Reverse Lat & Long": ["反向经纬度"], - "Lines column": ["线列"], - "The database columns that contains lines information": [ - "包含行信息的数据库列" + "following this flow will most likely lead to your query timing out. ": [ + "遵循此流程很可能会导致查询超时。" ], - "Lines encoding": ["线编码"], - "The encoding format of the lines": ["线的编码格式"], - "Polygon Settings": ["多边形设置"], - "Number of buckets to group data": ["分组数据的桶数量"], - "How many buckets should the data be grouped in.": [ - "应该将数据分组到多少个存储桶中。" - ], - "Bucket break points": ["桶断点"], - "List of n+1 values for bucketing metric into n buckets.": [ - "n+1个值的列表,用于将指标值放入n个桶中。" - ], - "Multiple filtering": ["多重过滤"], - "Allow sending multiple polygons as a filter event": [ - "允许将多个多边形作为过滤事件进行发送" - ], - "Whether to apply filter when items are clicked": [ - "单击选项时是否应用筛选器" - ], - "Start Longitude & Latitude": ["开始经纬度"], - "End Longitude & Latitude": ["经纬度结束"], - "Point to your spatial columns": ["指向您的空间列"], - "Arc": ["弧"], - "Target Color": ["目标颜色"], - "Color of the target location": ["目标位置的颜色"], - "Javascript data interceptor": ["JavaScript数据拦截器"], - "Define a javascript function that receives the data array used in the visualization and is expected to return a modified version of that array. This can be used to alter properties of the data, filter, or enrich the array.": [ - "定义一个JavaScript函数,该函数接收可视化中使用的数组数据,并返回修改版本的数组。这可用于更改数据、筛选或丰富数组的属性。" - ], - "No database is allowed for your csv upload": [ - "不允许将数据库用于csv上载" - ], - "Failed to fetch schemas allowed for csv upload in this database! Please contact your Superset Admin!": [ - "无法获取此数据库中允许csv上载的结构!请联系系统的管理员!" - ], - "One or many columns to group by": ["需要进行分组的一列或多列"], - "One or many columns to pivot as columns": [ - "需要作为列属性进行透视的一列或多列" + "for more information on how to structure your URI.": [ + " 来查询有关如何构造URI的更多信息。" ], - "Square meters": ["平方米"], - "Square kilometers": ["平方千米"], - "quarter": ["季度"], - "second": ["秒"], - "Last day": ["昨天"], - "Last month": ["上个月"], - "Last quarter": ["上个季度"], - "Last year": ["去年"], - "Defaults": ["默认"], - "Start / end": ["开始 / 结束"], - "Relative to today": ["相对于今天"], - "seconds": ["秒"], - "minutes": ["分钟"], - "hours": ["小时"], - "days": ["天"], - "weeks": ["周"], - "months": ["月"], - "years": ["年"], - "Ok": ["确认"], - "No Results": ["无结果"], - "No results were returned for this query. If you expected results to be returned, ensure any filters are configured properly and the datasource contains data for the selected time range.": [ - "此查询没有返回任何结果。如果希望返回结果,请确保所有过滤选择的配置正确,并且数据源包含所选时间范围的数据。" - ] + "green": ["绿色"], + "shere": ["分享"], + "hour": ["小时"], + "id:": ["id:"], + "image-rendering CSS attribute of the canvas object that defines how the browser scales up the image": [ + "图像渲染画布对象的 CSS 属性,它定义了浏览器如何放大图像" + ], + "in": ["在"], + "in modal": ["(在模型中)"], + "is expected to be a number": ["应该为数字"], + "is expected to be an integer": ["应该为为整数"], + "joined": ["已加入"], + "json isn't valid": ["无效 JSON"], + "key a-z": ["a-z"], + "key z-a": ["z-a"], + "label": ["标签"], + "last day": ["上一(昨)天"], + "last month": ["上一月"], + "last quarter": ["上一季度"], + "last week": ["上一周"], + "last year": ["上一年"], + "latest partition:": ["最新分区:"], + "left": ["警报"], + "log": ["日志"], + "lower percentile must be greater than 0 and less than 100. Must be lower than upper percentile.": [ + "下百分位数必须大于0且小于100。而且必须低于上百分位" + ], + "minute": ["分"], + "minute(s)": ["分钟"], + "month": ["月"], + "must have a value": ["必填"], + "nvd3": ["nvd3"], + "on": ["位于"], + "orderby column must be populated": ["无法更新您的查询"], + "p-value precision": ["假定值精度"], + "page_size.all": [""], + "page_size.entries": [""], + "page_size.show": [""], + "percentile (exclusive)": ["百分位数(独占)"], + "percentiles must be a list or tuple with two numeric values, of which the first is lower than the second value": [ + "百分位数必须是具有两个数值的列表或元组,其中第一个数值要小于第二个数值" + ], + "previous calendar month": ["前一月"], + "previous calendar week": ["前一周"], + "previous calendar year": ["前一年"], + "published": ["已发布"], + "queries": ["序列"], + "query": ["查询"], + "reboot": ["重启"], + "recents": ["最近"], + "red": ["红色"], + "report": ["报告"], + "reports": ["报告"], + "right": ["高度"], + "rows": ["行"], + "rows retrieved": ["行被检索到"], + "saved queries": ["已保存查询"], + "search.num_records": [""], + "series: Treat each series independently; overall: All series use the same scale; change: Show changes compared to the first data point in each series": [ + "series:独立处理每个序列;overall:所有序列使用相同的比例;change:显示与每个序列中第一个数据点相比的更改" + ], + "textarea": ["文本区域"], + "stop": ["停止"], + "upper percentile must be greater than 0 and less than 100. Must be higher than lower percentile.": [ + "上百分位数必须大于0且小于100。而且必须高于下百分位。" + ], + "value ascending": ["指标升序"], + "value descending": ["指标降序"], + "virtual": ["虚拟信息"], + "was created": ["已创建"], + "week": ["周"], + "year": ["年"], + "yellow": ["黄色"], + "Upload file to database": ["上传文件到数据库"], + "Connect database": ["连接数据库"], + "Upload columnar file to database": ["上传列级文件"], + "Upload CSV": ["上传CSV"], + "Upload columnar file": ["上传列级文件"], + "Upload Excel file": ["上传Excel"], + "Handlebars": ["句柄图"], + "deck.gl Arc": ["圆弧图"], + "Import database from file": ["从文件中导入数据库"], + "Select a database to connect": ["选择将要连接的数据库"], + "Select a database to write a query": ["选择要写入查询的数据库"], + "Choose one of the available databases from the panel on the left.": [ + "从左侧的面板中选择一个可用的数据库" + ], + "Add a new tab": ["添加新的标签页"], + "There are no databases available": ["没有可用的数据库"], + "No databases match your search": ["没有与您的搜索匹配的数据库"], + "Manage your databases": ["管理你的数据库"], + "here": ["这里"] } } } diff --git a/superset/translations/zh/LC_MESSAGES/messages.po b/superset/translations/zh/LC_MESSAGES/messages.po index ea3762b1c6c91..9ac344983a0ea 100644 --- a/superset/translations/zh/LC_MESSAGES/messages.po +++ b/superset/translations/zh/LC_MESSAGES/messages.po @@ -91,7 +91,7 @@ msgstr "" #: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:122 msgid " (excluded)" -msgstr "" +msgstr "(不包含)" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:235 msgid " expression which needs to adhere to the " @@ -132,17 +132,17 @@ msgid "" msgstr "" #: superset/security/analytics_db_safety.py:44 -#, fuzzy, python-format +#, python-format msgid "%(dialect)s cannot be used as a data source for security reasons." -msgstr "出于安全原因,SQLite数据库不能用作数据源。" +msgstr "出于安全原因,%(dialect)s SQLite数据库不能用作数据源。" #: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:84 -#, fuzzy, python-format +#, python-format msgid "" "%(message)s\n" "This may be triggered by: \n" "%(issues)s" -msgstr "这可能由以下因素触发:" +msgstr "%(message)s\n这可能由以下因素触发:%(issues)s" #: superset/reports/notifications/email.py:122 superset/tasks/schedules.py:364 #, python-format @@ -152,7 +152,7 @@ msgstr "" #: superset/db_engine_specs/snowflake.py:99 #, python-format msgid "%(object)s does not exist in this database." -msgstr "" +msgstr "%(object)s 数据库中不存在。" #: superset/reports/notifications/email.py:126 superset/tasks/schedules.py:296 #: superset/tasks/schedules.py:465 @@ -163,17 +163,17 @@ msgstr "" #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:635 #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:642 #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:656 -#, fuzzy, python-format +#, python-format msgid "%(rows)d rows returned" -msgstr "行被检索到" +msgstr "%(rows)d行被检索到" #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:93 -#, fuzzy, python-format +#, python-format msgid "" "%(subtitle)s\n" "This may be triggered by:\n" " %(issue)s" -msgstr "这可能由以下因素触发:" +msgstr "%(subtitle)s\n这可能由以下因素触发:%(issue)s" #: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:88 #, python-format @@ -252,7 +252,7 @@ msgid "%s column(s) and metric(s)" msgstr "%s 列与计量指标" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:297 -#, fuzzy, python-format +#, python-format msgid "%s operator(s)" msgstr "%s 运算符" @@ -260,7 +260,7 @@ msgstr "%s 运算符" #: superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx:256 #: superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx:82 #: superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx:92 -#, fuzzy, python-format +#, python-format msgid "%s option" msgstr "%s 个选项" @@ -291,13 +291,12 @@ msgid "(Removed)" msgstr "(已删除)" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:637 -#, fuzzy msgid "(deleted)" msgstr "删除" #: superset-frontend/src/utils/getClientErrorObject.ts:56 msgid "(no description, click to see stack trace)" -msgstr "" +msgstr "无描述,单击可查看堆栈跟踪" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:168 msgid "" @@ -332,7 +331,6 @@ msgid "**Select** a dashboard OR **create** a new one" msgstr "**选择** 一个看板或者 **创建** 一个看板" #: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:260 -#, fuzzy msgid "" "-- Note: Unless you save your query, these tabs will NOT persist if you " "clear your cookies or change browsers.\n" @@ -352,9 +350,8 @@ msgid "1 minute" msgstr "1分钟" #: superset/db_engine_specs/base.py:91 -#, fuzzy msgid "10 minute" -msgstr "1分钟" +msgstr "10分钟" #: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:30 msgid "10 seconds" @@ -365,9 +362,8 @@ msgid "12 hours" msgstr "12小时" #: superset/db_engine_specs/base.py:92 -#, fuzzy msgid "15 minute" -msgstr "1分钟" +msgstr "15分钟" #: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:38 msgid "24 hours" @@ -376,18 +372,17 @@ msgstr "24 小时" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:32 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:35 msgid "2D" -msgstr "" +msgstr "2D" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:116 msgid "3 letter code of the country" -msgstr "国家3字母代码" +msgstr "国家3字码" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:128 msgid "30 days" msgstr "30天" #: superset/db_engine_specs/base.py:93 -#, fuzzy msgid "30 minute" msgstr "30分钟" @@ -396,7 +391,6 @@ msgid "30 minutes" msgstr "30分钟" #: superset/db_engine_specs/base.py:88 -#, fuzzy msgid "30 second" msgstr "30秒钟" @@ -405,7 +399,6 @@ msgid "30 seconds" msgstr "30秒钟" #: superset/db_engine_specs/base.py:90 -#, fuzzy msgid "5 minute" msgstr "5分钟" @@ -414,12 +407,10 @@ msgid "5 minutes" msgstr "5分钟" #: superset/db_engine_specs/base.py:87 -#, fuzzy msgid "5 second" -msgstr "秒" +msgstr "5秒" #: superset/db_engine_specs/base.py:95 -#, fuzzy msgid "6 hour" msgstr "6小时" @@ -437,7 +428,7 @@ msgstr "90天" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:49 msgid ":" -msgstr "" +msgstr ":" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:86 msgid "< (Smaller than)" @@ -465,9 +456,8 @@ msgid ">= (Larger or equal)" msgstr ">= (大于等于)" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:35 -#, fuzzy msgid "A Big Number" -msgstr "数字" +msgstr "大数字" #: superset/views/alerts.py:195 msgid "" @@ -480,14 +470,12 @@ msgid "A comma separated list of columns that should be parsed as dates." msgstr "应作为日期解析的列的逗号分隔列表。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:383 -#, fuzzy msgid "A comma-separated list of schemas that CSVs are allowed to upload to." -msgstr "应作为日期解析的列的逗号分隔列表。" +msgstr "允许以逗号分割的CSV文件上传" #: superset/databases/commands/exceptions.py:42 -#, fuzzy msgid "A database with the same name already exists." -msgstr "同名数据库已存在" +msgstr "已存在同名的数据库。" #: superset/views/dynamic_plugins.py:52 msgid "" @@ -505,7 +493,7 @@ msgstr "有权处理该图表的用户列表。可按名称或用户名搜索。 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:29 msgid "A map of the world, that can indicate values in different countries." -msgstr "" +msgstr "一张世界地图,可以显示不同国家的价值观。" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:161 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:209 @@ -518,7 +506,7 @@ msgid "" "A polar coordinate chart where the circle is broken into wedges of equal " "angle, and the value represented by any wedge is illustrated by its area," " rather than its radius or sweep angle." -msgstr "" +msgstr "一种极坐标图表,其中圆被分成等角度的楔形,任何楔形表示的值由其面积表示,而不是其半径或扫掠角度。" #: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:523 msgid "A readable URL for your dashboard" @@ -544,27 +532,23 @@ msgstr "在查询中可用的一组参数使用JINJA模板语法" msgid "" "A time series chart that visualizes how a related metric from multiple " "groups vary over time. Each group is visualized using a different color." -msgstr "" +msgstr "时间序列图表,直观显示多个组中的相关指标随时间的变化情况。每组使用不同的颜色进行可视化" #: superset/reports/commands/exceptions.py:198 -#, fuzzy msgid "A timeout occurred while executing the query." -msgstr "警报在执行查询时发现错误。" +msgstr "查询超时。" #: superset/reports/commands/exceptions.py:206 -#, fuzzy msgid "A timeout occurred while generating a csv." -msgstr "获取tab页状态时出错" +msgstr "生成CSV时超时。" #: superset/reports/commands/exceptions.py:210 -#, fuzzy msgid "A timeout occurred while generating a dataframe." -msgstr "创建数据源时发生错误" +msgstr "生成数据超时" #: superset/reports/commands/exceptions.py:202 -#, fuzzy msgid "A timeout occurred while taking a screenshot." -msgstr "获取tab页状态时出错" +msgstr "截图超时" #: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:168 msgid "A valid color scheme is required" @@ -651,9 +635,8 @@ msgid "Add" msgstr "新增" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1056 -#, fuzzy msgid "Add Alert" -msgstr "警报" +msgstr "添加告警" #: superset/views/annotations.py:60 msgid "Add Annotation" @@ -712,9 +695,8 @@ msgid "Add Metric" msgstr "添加指标" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1055 -#, fuzzy msgid "Add Report" -msgstr "报告" +msgstr "添加报告" #: superset/connectors/sqla/views.py:316 msgid "Add Row level security filter" @@ -729,9 +711,8 @@ msgid "Add a Plugin" msgstr "添加插件" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:175 -#, fuzzy msgid "Add additional custom parameters" -msgstr "编辑模板参数" +msgstr "添加其他自定义参数" #: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:63 msgid "Add an item" @@ -769,21 +750,19 @@ msgstr "添加指标" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:176 msgid "Add new color formatter" -msgstr "" +msgstr "添加新的颜色" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:169 -#, fuzzy msgid "Add new formatter" -msgstr "日期格式化" +msgstr "新增格式化" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:386 msgid "Add notification method" msgstr "添加注释层" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:99 -#, fuzzy msgid "Add sheet" -msgstr "添加数据集" +msgstr "添加sheet页" #: superset-frontend/src/explore/components/SaveModal.tsx:258 msgid "Add to dashboard" @@ -798,39 +777,35 @@ msgid "Adding new datasource [{}]" msgstr "添加 Druid 数据源 [{}]" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:173 -#, fuzzy msgid "Additional Parameters" -msgstr "编辑模板参数" +msgstr "附加参数" #: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:324 msgid "Additional information" msgstr "附加信息" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:96 -#, fuzzy msgid "Additional metadata" -msgstr "附加信息" +msgstr "附加元数据" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:50 msgid "Additional padding for legend." msgstr "图示附加的padding值。" #: superset/db_engine_specs/base.py:1398 -#, fuzzy msgid "Additional parameters" msgstr "编辑模板参数" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:166 msgid "Additional text to add before or after the value, e.g. unit" -msgstr "" +msgstr "附加文本到数据前(后),例如:单位" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:40 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:40 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:43 -#, fuzzy msgid "Additive" -msgstr "增加条件" +msgstr "附加" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:765 #: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:580 @@ -865,7 +840,6 @@ msgstr "高级分析" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:64 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:71 #: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:124 -#, fuzzy msgid "Advanced-Analytics" msgstr "高级分析" @@ -888,24 +862,21 @@ msgstr "高级分析" #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:58 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:41 msgid "Aesthetic" -msgstr "" +msgstr "炫酷" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:84 -#, fuzzy msgid "After" -msgstr "季度" +msgstr "之后" #: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:45 msgid "Aggregate" msgstr "聚合" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:91 -#, fuzzy msgid "Aggregate Mean" -msgstr "合计" +msgstr "合计平均值" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:96 -#, fuzzy msgid "Aggregate Sum" msgstr "合计" @@ -929,87 +900,87 @@ msgstr "聚合功能" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:92 msgid "Alert Triggered, In Grace Period" -msgstr "警报已触发,在宽限期内" +msgstr "告警已触发,在宽限期内" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1123 msgid "Alert condition" -msgstr "警报状态" +msgstr "告警条件" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1215 msgid "Alert condition schedule" -msgstr "警报条件计划" +msgstr "告警条件计划" #: superset/reports/commands/exceptions.py:218 msgid "Alert ended grace period." -msgstr "警报已结束宽限期。" +msgstr "告警已结束宽限期。" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:82 msgid "Alert failed" -msgstr "警报失败" +msgstr "告警失败" #: superset/reports/commands/exceptions.py:214 msgid "Alert fired during grace period." -msgstr "在宽限期内触发警报。" +msgstr "在宽限期内触发告警。" #: superset/reports/commands/exceptions.py:194 msgid "Alert found an error while executing a query." -msgstr "警报在执行查询时发现错误。" +msgstr "告警在执行查询时发现错误。" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1064 #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1072 msgid "Alert name" -msgstr "警报名称" +msgstr "告警名称" #: superset/reports/commands/exceptions.py:222 msgid "Alert on grace period" -msgstr "警报宽限期" +msgstr "告警宽限期" #: superset/reports/commands/exceptions.py:190 msgid "Alert query returned a non-number value." -msgstr "警报查询返回非数字值。" +msgstr "告警查询返回非数字值。" #: superset/reports/commands/exceptions.py:186 msgid "Alert query returned more than one column." -msgstr "警报查询返回多个列。" +msgstr "告警查询返回多个列。" #: superset/reports/commands/alert.py:105 #, python-format msgid "Alert query returned more than one column. %s columns returned" -msgstr "警报查询返回多个列。%s 列被返回" +msgstr "告警查询返回多个列。%s 列被返回" #: superset/reports/commands/exceptions.py:177 msgid "Alert query returned more than one row." -msgstr "警报查询返回了多行。" +msgstr "告警查询返回了多行。" #: superset/reports/commands/alert.py:96 #, python-format msgid "Alert query returned more than one row. %s rows returned" -msgstr "警报查询返回了多行。%s 行被返回" +msgstr "告警查询返回了多行。%s 行被返回" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:75 msgid "Alert running" -msgstr "警报运行" +msgstr "告警运行中" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:68 msgid "Alert triggered, notification sent" -msgstr "警报已触发,通知已发送" +msgstr "告警已触发,通知已发送" #: superset/reports/commands/exceptions.py:182 msgid "Alert validator config error." -msgstr "错误的经纬度配置。" +msgstr "告警验证器配置错误。" #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:436 #: superset/initialization/__init__.py:468 msgid "Alerts" -msgstr "警报" +msgstr "告警" #: superset/initialization/__init__.py:480 msgid "Alerts & Reports" -msgstr "警报和报告" +msgstr "告警和报告" #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:432 msgid "Alerts & reports" -msgstr "警报和报告" +msgstr "告警和报告" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:127 #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:427 @@ -1044,10 +1015,9 @@ msgstr "所有过滤" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:326 #, python-format msgid "All filters (%(filterCount)d)" -msgstr "" +msgstr "所有过滤(%(filterCount)d)" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/state.ts:49 -#, fuzzy msgid "All panels" msgstr "应用于所有面板" @@ -1097,11 +1067,11 @@ msgstr "允许 sql lab 获取所有数据库架构中的所有表和所有视图 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:98 msgid "Allow creation of new tables based on queries" -msgstr "" +msgstr "允许基于查询创建新表" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:112 msgid "Allow creation of new views based on queries" -msgstr "" +msgstr "允许基于查询创建新视图" #: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:256 msgid "Allow data manipulation language" @@ -1115,29 +1085,28 @@ msgstr "允许数据上传" msgid "" "Allow manipulation of the database using non-SELECT statements such as " "UPDATE, DELETE, CREATE, etc." -msgstr "" +msgstr "允许使用非SELECT语句(如UPDATE、DELETE、CREATE等)操作数据库。" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:216 msgid "Allow multiple selections" msgstr "允许多选" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:189 -#, fuzzy msgid "Allow node selections" -msgstr "允许多选" +msgstr "允许多节点选择" #: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:64 #: superset-frontend/src/filters/components/Select/controlPanel.ts:82 msgid "Allow selecting multiple values" -msgstr "" +msgstr "允许选择多个值" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:192 msgid "Allow this database to be explored" -msgstr "" +msgstr "允许浏览此数据库" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:79 msgid "Allow this database to be queried in SQL Lab" -msgstr "" +msgstr "允许在SQL工具箱中查询此数据库" #: superset/views/database/mixins.py:115 msgid "" @@ -1156,7 +1125,7 @@ msgid "" "distributions of a related metric across multiple groups. The box in the " "middle emphasizes the mean, median, and inner 2 quartiles. The whiskers " "around each box visualize the min, max, range, and outer 2 quartiles." -msgstr "" +msgstr "也称为框须图,该可视化比较了一个相关指标在多个组中的分布。中间的框强调平均值、中值和内部2个四分位数。每个框周围的触须可视化了最小值、最大值、范围和外部2个四分区。" #: superset-frontend/src/components/AlteredSliceTag/index.jsx:182 msgid "Altered" @@ -1172,7 +1141,7 @@ msgstr "使用时间比较时,必须指定封闭的时间范围(有开始和 msgid "" "An engine must be specified when passing individual parameters to a " "database." -msgstr "" +msgstr "向数据库传递单个参数时必须指定引擎。" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:623 #: superset-frontend/src/components/Datasource/DatasourceModal.tsx:140 @@ -1193,14 +1162,9 @@ msgstr "发生了一个错误" msgid "An error occurred saving dataset" msgstr "保存数据集时发生错误" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:132 -msgid "An error occurred when refreshing queries" -msgstr "创建数据源时发生错误" - #: superset/key_value/commands/exceptions.py:33 -#, fuzzy msgid "An error occurred while accessing the value." -msgstr "创建数据源时发生错误" +msgstr "访问值时出错。" #: superset-frontend/src/SqlLab/actions/sqlLab.js:1165 msgid "" @@ -1209,9 +1173,9 @@ msgid "" msgstr "收起表结构时出错。请与管理员联系。" #: superset-frontend/src/views/CRUD/hooks.ts:301 -#, fuzzy, python-format +#, python-format msgid "An error occurred while creating %ss: %s" -msgstr "获取数据集时出错:%s" +msgstr "创建时出错:%ss: %s" #: superset-frontend/src/SqlLab/actions/sqlLab.js:1313 #: superset-frontend/src/SqlLab/actions/sqlLab.js:1335 @@ -1219,24 +1183,22 @@ msgid "An error occurred while creating the data source" msgstr "创建数据源时发生错误" #: superset/key_value/commands/exceptions.py:29 -#, fuzzy msgid "An error occurred while creating the value." -msgstr "创建数据源时发生错误" +msgstr "创建值时出错。" #: superset/key_value/commands/exceptions.py:37 -#, fuzzy, python-format +#, python-format msgid "An error occurred while deleting the value." -msgstr "获取结构信息时出错:%s" +msgstr "删除值时出错。" #: superset-frontend/src/reports/actions/reports.js:138 -#, fuzzy msgid "An error occurred while editing this report." -msgstr "创建数据源时发生错误" +msgstr "编辑此报告时出错。" #: superset-frontend/src/reports/actions/reports.js:120 -#, fuzzy, python-format +#, python-format msgid "An error occurred while editing this report: %s" -msgstr "获取数据集时出错:%s" +msgstr "编辑此报告时出错:%s" #: superset-frontend/src/SqlLab/actions/sqlLab.js:1141 msgid "" @@ -1245,16 +1207,16 @@ msgid "" msgstr "展开表结构时出错。请与管理员联系。" #: superset-frontend/src/views/CRUD/hooks.ts:103 -#, fuzzy, python-format +#, python-format msgid "An error occurred while fetching %s info: %s" -msgstr "获取仪表板时出错:%s" +msgstr "获取%s仪表板时出错:%s" #: superset-frontend/src/views/CRUD/hooks.ts:171 #: superset-frontend/src/views/CRUD/hooks.ts:258 #: superset-frontend/src/views/CRUD/hooks.ts:344 -#, fuzzy, python-format +#, python-format msgid "An error occurred while fetching %ss: %s" -msgstr "获取数据集时出错:%s" +msgstr "抓取出错:%ss: %s" #: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:132 msgid "An error occurred while fetching available CSS templates" @@ -1332,9 +1294,8 @@ msgid "An error occurred while fetching datasets: %s" msgstr "获取数据集时出错:%s" #: superset-frontend/src/SqlLab/actions/sqlLab.js:1356 -#, fuzzy msgid "An error occurred while fetching function names." -msgstr "获取tab页状态时出错" +msgstr "获取函数名称时出错。" #: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:460 #: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:358 @@ -1359,22 +1320,21 @@ msgid "" msgstr "获取表格元数据时发生错误。请与管理员联系。" #: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:375 -#, fuzzy, python-format +#, python-format msgid "An error occurred while fetching user values: %s" -msgstr "获取结构信息时出错:%s" +msgstr "获取用户信息出错:%s" #: superset-frontend/src/SqlLab/actions/sqlLab.js:698 -#, fuzzy msgid "" "An error occurred while hiding the left bar. Please contact your " "administrator." -msgstr "展开表结构时出错。请与管理员联系。" +msgstr "隐藏左栏时出错。请与管理员联系。" #: superset-frontend/src/views/CRUD/hooks.ts:438 #: superset-frontend/src/views/CRUD/hooks.ts:451 -#, fuzzy, python-format +#, python-format msgid "An error occurred while importing %s: %s" -msgstr "精简日志时出错 " +msgstr "导入时出错 %s: %s" #: superset-frontend/src/chart/chartAction.js:569 msgid "An error occurred while loading the SQL" @@ -1441,9 +1401,8 @@ msgid "" msgstr "设置tab页标题时出错。请与管理员联系。" #: superset-frontend/src/explore/actions/exploreActions.ts:95 -#, fuzzy msgid "An error occurred while starring this chart" -msgstr "创建数据源时发生错误" +msgstr "以此字符开头时出错" #: superset-frontend/src/SqlLab/actions/sqlLab.js:232 #: superset-frontend/src/SqlLab/actions/sqlLab.js:258 @@ -1460,9 +1419,8 @@ msgid "" msgstr "在后端存储查询时出错。为避免丢失更改,请使用 \"保存查询\" 按钮保存查询。" #: superset/key_value/commands/exceptions.py:41 -#, fuzzy msgid "An error occurred while updating the value." -msgstr "创建数据源时发生错误" +msgstr "更新值时出错。" #: superset/views/core.py:711 msgid "An unknown error occurred. Please contact your Superset administrator" @@ -1474,16 +1432,15 @@ msgstr "锚定到" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:121 msgid "Angle at which to end progress axis" -msgstr "" +msgstr "进度轴结束的角度" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:111 msgid "Angle at which to start progress axis" -msgstr "" +msgstr "开始进度轴的角度" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:191 -#, fuzzy msgid "Animation" -msgstr "注释" +msgstr "动画" #: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:202 #: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:248 @@ -1502,9 +1459,8 @@ msgid "Annotation Layers" msgstr "注释层" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:465 -#, fuzzy msgid "Annotation Slice Configuration" -msgstr "过滤配置" +msgstr "注释切片配置" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:758 msgid "Annotation Source" @@ -1548,9 +1504,8 @@ msgid "Annotation layer delete failed." msgstr "注释层仍在加载。" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:517 -#, fuzzy msgid "Annotation layer description columns" -msgstr "注释层仍在加载。" +msgstr "注释层描述列。" #: superset/annotation_layers/commands/exceptions.py:53 #: superset/annotation_layers/commands/exceptions.py:57 @@ -1558,9 +1513,8 @@ msgid "Annotation layer has associated annotations." msgstr "注释层仍在加载。" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:492 -#, fuzzy msgid "Annotation layer interval end" -msgstr "注释层名称" +msgstr "注释层间隔结束" #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayerModal.tsx:247 msgid "Annotation layer name" @@ -1571,28 +1525,25 @@ msgid "Annotation layer not found." msgstr "注释层仍在加载。" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:634 -#, fuzzy msgid "Annotation layer opacity" -msgstr "注释层类型" +msgstr "注释层不透明度" #: superset/annotation_layers/commands/exceptions.py:29 msgid "Annotation layer parameters are invalid." msgstr "注释层仍在加载。" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:619 -#, fuzzy +# stroke 中风??? msgid "Annotation layer stroke" -msgstr "注释层类型" +msgstr "注释层混乱" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:472 -#, fuzzy msgid "Annotation layer time column" -msgstr "注释层类型" +msgstr "注释层时间列" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:506 -#, fuzzy msgid "Annotation layer title column" -msgstr "注释层类型" +msgstr "注释层标题列" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:743 #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:746 @@ -1600,9 +1551,8 @@ msgid "Annotation layer type" msgstr "注释层类型" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:403 -#, fuzzy msgid "Annotation layer value" -msgstr "注释层名称" +msgstr "注释层值" #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:72 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:343 @@ -1626,9 +1576,8 @@ msgid "Annotation parameters are invalid." msgstr "注释层仍在加载。" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:755 -#, fuzzy msgid "Annotation source type" -msgstr "注释来源" +msgstr "注释数据源类型" #: superset/views/annotations.py:58 msgid "Annotations" @@ -1659,7 +1608,7 @@ msgstr "所有" #: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:563 #: superset-frontend/src/explore/components/PropertiesModal/index.tsx:269 msgid "Any additional detail to show in the certification tooltip." -msgstr "" +msgstr "要在认证工具提示中显示详细信息。" #: superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx:56 msgid "" @@ -1669,13 +1618,13 @@ msgstr "此处选择的任何调色板都将覆盖应用于此看板的各个图 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:702 msgid "Any databases that allow connections via SQL Alchemy URIs can be added. " -msgstr "" +msgstr "可以添加任何允许通过SQL AlChemy URI进行连接的数据库。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:716 msgid "" "Any databases that allow connections via SQL Alchemy URIs can be added. " "Learn about how to connect a database driver " -msgstr "" +msgstr "可以添加任何允许通过SQL AlChemy URI进行连接的数据库。了解如何连接数据库驱动程序" #: superset/views/database/forms.py:147 superset/views/database/forms.py:300 #: superset/views/database/forms.py:428 @@ -1683,9 +1632,9 @@ msgid "Append" msgstr "追加" #: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:186 -#, fuzzy, python-format +#, python-format msgid "Applied Cross Filters (%d)" -msgstr "应用的条件 (%d)" +msgstr "应用的交叉条件 (%d)" #: superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/index.tsx:210 #, python-format @@ -1708,16 +1657,15 @@ msgstr "应用" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:321 msgid "Apply conditional color formatting to metrics" -msgstr "" +msgstr "将条件颜色格式应用于指标" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:474 msgid "Apply conditional color formatting to numeric columns" -msgstr "" +msgstr "将条件颜色格式应用于数字列" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:79 -#, fuzzy msgid "Apply metrics on" -msgstr "我的指标" +msgstr "应用指标到" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx:123 msgid "Apply to all panels" @@ -1796,21 +1744,18 @@ msgid "Area Chart" msgstr "面积图" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:168 -#, fuzzy msgid "Area chart" -msgstr "共享图表" +msgstr "面积图" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:131 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:146 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:149 -#, fuzzy msgid "Area chart opacity" -msgstr "共享图表" +msgstr "面积图不透明度" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:238 -#, fuzzy msgid "Arrow" -msgstr "行" +msgstr "箭头" #: superset/connectors/druid/views.py:342 superset/connectors/sqla/views.py:487 msgid "Associated Charts" @@ -1845,12 +1790,11 @@ msgstr "自动补全查询谓词" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:242 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:270 msgid "Available sorting modes:" -msgstr "" +msgstr "可用分类模式:" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:200 -#, fuzzy msgid "Axis" -msgstr "Y 轴" +msgstr "坐标轴" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:36 msgid "Axis ascending" @@ -1863,7 +1807,7 @@ msgstr "轴线降序" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:770 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:786 msgid "Back" -msgstr "" +msgstr "返回" #: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:227 #: superset/views/database/mixins.py:204 @@ -1876,7 +1820,7 @@ msgstr "错误的空间字段" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:85 msgid "Bar" -msgstr "" +msgstr "条形图" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:38 msgid "Bar Chart" @@ -1896,7 +1840,7 @@ msgstr "基于指标" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:50 msgid "Based on granularity, number of time periods to compare against" -msgstr "" +msgstr "根据粒度、要比较的时间阶段" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:686 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:263 @@ -1919,7 +1863,7 @@ msgstr "批量编辑 %d 个过滤条件:" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:36 msgid "Battery level over time" -msgstr "" +msgstr "电池电量随时间变化" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1175 msgid "Be careful." @@ -1944,9 +1888,8 @@ msgid "Big Number with Trendline" msgstr "数字和趋势线" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:290 -#, fuzzy msgid "Bottom" -msgstr "dttm" +msgstr "底端" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:212 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:187 @@ -1960,7 +1903,7 @@ msgstr "底部边距,以像素为单位,为轴标签留出更多空间" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:140 msgid "Bottom to Top" -msgstr "" +msgstr "自下而上" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:241 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:257 @@ -1971,7 +1914,6 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:232 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:288 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:291 -#, fuzzy msgid "" "Bounds for the Y-axis. When left empty, the bounds are dynamically " "defined based on the min/max of the data. Note that this feature will " @@ -2053,7 +1995,7 @@ msgstr "子弹图" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:55 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:44 msgid "Business" -msgstr "" +msgstr "商业" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:233 #: superset-frontend/src/filters/components/Select/controlPanel.ts:139 @@ -2066,16 +2008,16 @@ msgstr "默认情况下,每个过滤器在初始页面加载时最多加载100 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:272 msgid "By key: use column names as sorting key" -msgstr "" +msgstr "使用列名作为排序关键字" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:244 msgid "By key: use row names as sorting key" -msgstr "" +msgstr "使用行名作为排序关键字" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:245 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:273 msgid "By value: use metric values as sorting key" -msgstr "" +msgstr "使用度量值作为排序关键字" #: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:334 msgid "CANCEL" @@ -2148,7 +2090,7 @@ msgstr "CSV上传" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:118 msgid "CTAS & CVAS SCHEMA" -msgstr "" +msgstr "CTAS和CVAS方案" #: superset/sql_lab.py:405 msgid "" @@ -2174,11 +2116,11 @@ msgstr "" #: superset/errors.py:123 msgid "CVAS (create view as select) query has more than one statement." -msgstr "" +msgstr "CVAS (create view as select)查询有多条语句。" #: superset/errors.py:124 msgid "CVAS (create view as select) query is not a SELECT statement." -msgstr "" +msgstr "CVAS (create view as select)查询不是SELECT语句。" #: superset/connectors/druid/views.py:239 #: superset/connectors/druid/views.py:351 superset/connectors/sqla/views.py:497 @@ -2210,9 +2152,8 @@ msgstr "缓存的值未找到" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:70 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:76 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:77 -#, fuzzy msgid "Calculate contribution per series or total" -msgstr "计算对总数的贡献值" +msgstr "计算每个系列或总计的贡献" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:667 #, python-format @@ -2274,16 +2215,15 @@ msgstr "取消" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:304 msgid "Cancel query on window unload event" -msgstr "" +msgstr "取消窗口上传事件的查询" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts:83 msgid "Cannot create cyclic hierarchy" -msgstr "" +msgstr "无法创建循环层级" #: superset/databases/commands/exceptions.py:109 -#, fuzzy msgid "Cannot delete a database that has datasets attached" -msgstr "无法删除已含有表的数据库" +msgstr "无法删除附加了数据集的数据库" #: superset/views/core.py:700 #, python-format @@ -2296,14 +2236,13 @@ msgstr "" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:242 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:944 -#, fuzzy msgid "Cannot load filter" -msgstr "父级过滤" +msgstr "无法加载筛选器" #: superset/charts/commands/exceptions.py:51 #, python-format msgid "Cannot parse time string [%(human_readable)s]" -msgstr "" +msgstr "无法解析时间字符串[%(human_readable)s]" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:28 #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:38 @@ -2313,9 +2252,8 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:41 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:59 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:42 -#, fuzzy msgid "Categorical" -msgstr "分类颜色" +msgstr "分类" #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:129 msgid "Categories to group by on the x-axis." @@ -2323,11 +2261,11 @@ msgstr "要在x轴上分组的类别。" #: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:602 msgid "Category" -msgstr "" +msgstr "分类" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:87 msgid "Category of target nodes" -msgstr "" +msgstr "目标节点类别" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:103 msgid "Cell Padding" @@ -2342,24 +2280,21 @@ msgid "Cell Size" msgstr "单元尺寸" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:413 -#, fuzzy msgid "Cell bars" -msgstr "所有图表" +msgstr "单元格柱状图" #: superset-frontend/src/components/FilterableTable/FilterableTable.tsx:319 msgid "Cell content" msgstr "单元格内容" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:112 -#, fuzzy msgid "Center" -msgstr "最近" +msgstr "中心对齐" #: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:533 #: superset-frontend/src/explore/components/PropertiesModal/index.tsx:252 -#, fuzzy msgid "Certification" -msgstr "认证细节" +msgstr "认证" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:270 #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:275 @@ -2373,12 +2308,10 @@ msgstr "认证细节" #: superset-frontend/src/views/CRUD/chart/ChartList.tsx:530 #: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:504 -#, fuzzy msgid "Certified" msgstr "认证" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:259 -#, fuzzy msgid "Certified By" msgstr "认证" @@ -2405,11 +2338,11 @@ msgstr "修改数据集" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:269 msgid "Change order of columns." -msgstr "" +msgstr "更改列的顺序。" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:241 msgid "Change order of rows." -msgstr "" +msgstr "更改行的顺序。" #: superset/connectors/druid/views.py:354 superset/connectors/sqla/views.py:489 msgid "Changed By" @@ -2459,9 +2392,8 @@ msgstr "没有权限更新此数据集" #: superset/datasets/columns/commands/exceptions.py:31 #: superset/datasets/metrics/commands/exceptions.py:31 -#, fuzzy msgid "Changing this dataset is forbidden." -msgstr "没有权限更新此数据集" +msgstr "禁止更改此数据集。" #: superset/reports/commands/exceptions.py:238 msgid "Changing this report is forbidden" @@ -2559,9 +2491,8 @@ msgid "Chart Owner: %s" msgstr "图表所有者:%s" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:27 -#, fuzzy msgid "Chart Title" -msgstr "图表类型" +msgstr "图表标题" #: superset/views/core.py:979 msgid "Chart [{}] has been overwritten" @@ -2594,6 +2525,11 @@ msgid "" "that lives in the dashboard view itself. It's easier to use and has more " "capabilities!" msgstr "" +"图表组件,允许您在仪表板中添加自定义过滤器UI。" +"当添加到仪表板时,过滤器框允许用户指定特定的值或范围来过滤图表。每个筛选框所应用的图表也可以在仪表板视图中进行微调。" +"请注意,这个插件正在被仪表板视图中的新过滤器功能所取代。它更易于使用,功能更强大!" + + #: superset/charts/commands/exceptions.py:115 msgid "Chart could not be created." @@ -2613,7 +2549,7 @@ msgstr "图表没有找到" #: superset/charts/data/api.py:125 msgid "Chart has no query context saved. Please save the chart again." -msgstr "" +msgstr "图表未保存任何查询上下文。请重新保存图表。" #: superset-frontend/src/explore/components/SaveModal.tsx:247 msgid "Chart name" @@ -2621,7 +2557,6 @@ msgstr "图表名称" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:96 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:107 -#, fuzzy msgid "Chart options" msgstr "图表选项" @@ -2650,9 +2585,8 @@ msgstr "这个查询无法被加载" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:162 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:488 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:505 -#, fuzzy msgid "Check configuration" -msgstr "配置Layer" +msgstr "检查配置" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:206 #: superset-frontend/src/filters/components/Select/controlPanel.ts:68 @@ -2663,16 +2597,15 @@ msgstr "按照升序进行排序" msgid "" "Check if the Rose Chart should use segment area instead of segment radius" " for proportioning" -msgstr "" +msgstr "检查玫瑰图是否应该使用线段面积而不是线段半径来进行比例" #: superset-frontend/src/components/AnchorLink/index.jsx:85 msgid "Check out this chart in dashboard:" -msgstr "查看这个看板:%s" +msgstr "在仪表盘中查看此图表" #: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:319 -#, fuzzy msgid "Check out this chart: " -msgstr "查看此看板:" +msgstr "看看这张图表:" #: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:220 msgid "Check out this dashboard: " @@ -2686,25 +2619,23 @@ msgstr "选中可在过滤条件更改时立即应用过滤,而不是使用 [ #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:219 msgid "Check to force date partitions to have the same height" -msgstr "" +msgstr "选中以强制日期分区具有相同的高度" #: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:35 msgid "Check to include Druid granularity dropdown" msgstr "检查包含Druid时间粒度下拉列表" #: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:109 -#, fuzzy msgid "Check to include SQL time grain dropdown" -msgstr "检查包含时间原点的下拉列表" +msgstr "选中以包括SQL时间粒度下拉菜单" #: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:123 msgid "Check to include time column dropdown" msgstr "检查包含时间列下拉列表" #: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:110 -#, fuzzy msgid "Check to include time grain dropdown" -msgstr "检查包含时间原点的下拉列表" +msgstr "选中以包括时间粒度下拉菜单" #: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:46 msgid "Check to include time origin dropdown" @@ -2712,7 +2643,7 @@ msgstr "检查包含时间原点的下拉列表" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:173 msgid "Child label position" -msgstr "" +msgstr "子标签位置" #: superset/viz.py:2333 msgid "Choice of [Label] must be present in [Group By]" @@ -2732,9 +2663,8 @@ msgid "Choose a chart or dashboard not both" msgstr "选择图表或看板,不能都全部选择" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:674 -#, fuzzy msgid "Choose a database..." -msgstr "选择数据源" +msgstr "选择数据库" #: superset-frontend/src/addSlice/AddSliceContainer.tsx:278 #: superset-frontend/src/addSlice/AddSliceContainer.tsx:288 @@ -2752,14 +2682,12 @@ msgid "Choose a metric for right axis" msgstr "为右轴选择一个指标" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:57 -#, fuzzy msgid "Choose a number format" -msgstr "数字格式化" +msgstr "选择一种数字格式" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:63 -#, fuzzy msgid "Choose a source" -msgstr "选择一个源和一个目标" +msgstr "选择一个源" #: superset-frontend/plugins/legacy-plugin-chart-force-directed/src/controlPanel.ts:105 #: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/controlPanel.ts:44 @@ -2768,14 +2696,12 @@ msgid "Choose a source and a target" msgstr "选择一个源和一个目标" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:69 -#, fuzzy msgid "Choose a target" -msgstr "选择数据源" +msgstr "选择一个目标" #: superset-frontend/src/addSlice/AddSliceContainer.tsx:308 -#, fuzzy msgid "Choose chart type" -msgstr "图表类型" +msgstr "选择图表类型" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:100 msgid "Choose one or more charts for left axis" @@ -2799,24 +2725,23 @@ msgstr "弦图" #: superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx:281 msgid "Chosen non-numeric column" -msgstr "" +msgstr "选定的非数字列" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:218 -#, fuzzy msgid "Circle" -msgstr "文件" +msgstr "圆" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:130 msgid "Circle -> Arrow" -msgstr "" +msgstr "圆 -> 箭头" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:131 msgid "Circle -> Circle" -msgstr "" +msgstr "圆 -> 圆" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:198 msgid "Circle radar shape" -msgstr "" +msgstr "圆形雷达图" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:37 #: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:33 @@ -2824,17 +2749,17 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:40 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:67 msgid "Circular" -msgstr "" +msgstr "圆" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:32 msgid "Classic chart that visualizes how metrics change over time." -msgstr "" +msgstr "直观显示指标随时间变化的经典图表。" #: superset-frontend/plugins/plugin-chart-table/src/index.ts:37 msgid "" "Classic row-by-column spreadsheet like view of a dataset. Use tables to " "showcase a view into the underlying data or to show aggregated metrics." -msgstr "" +msgstr "数据集的典型的逐行逐列电子表格视图。使用表格显示底层数据的视图或显示聚合指标。" #: superset/connectors/sqla/views.py:369 msgid "Clause" @@ -2845,9 +2770,8 @@ msgid "Clear" msgstr "清除" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx:133 -#, fuzzy msgid "Clear all" -msgstr "查看所有" +msgstr "清楚所有" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:997 msgid "Click the lock to make changes." @@ -2861,31 +2785,29 @@ msgstr "单击锁定以防止进一步更改。" msgid "" "Click this link to switch to an alternate form that allows you to input " "the SQLAlchemy URL for this database manually." -msgstr "" +msgstr "单击此链接可切换到备用表单,该表单允许您手动输入此数据库的SQLAlChemy URL。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1071 msgid "" "Click this link to switch to an alternate form that exposes only the " "required fields needed to connect this database." -msgstr "" +msgstr "单击此链接可切换到仅显示连接此数据库所需的必填字段的备用表单。" #: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:114 msgid "Click to change visualization type" msgstr "选择一个可视化类型" #: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:151 -#, fuzzy msgid "Click to clear emitted filters" -msgstr "自适配过滤条件" +msgstr "点击清除过滤" #: superset-frontend/src/components/EditableTitle/index.tsx:197 msgid "Click to edit" msgstr "点击编辑" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.jsx:76 -#, fuzzy msgid "Click to edit label" -msgstr "点击编辑" +msgstr "单击以编辑标签" #: superset-frontend/src/components/FaveStar/index.tsx:81 msgid "Click to favorite/unfavorite" @@ -2943,9 +2865,8 @@ msgid "Collapse all" msgstr "全部折叠" #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:152 -#, fuzzy msgid "Collapse table preview" -msgstr "删除表格预览" +msgstr "折叠表的预览" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:648 msgid "Color" @@ -2958,7 +2879,6 @@ msgstr "色彩 +/-" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:159 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:206 -#, fuzzy msgid "Color Metric" msgstr "颜色指标" @@ -3010,7 +2930,7 @@ msgstr "列" msgid "" "Column \"%(column)s\" is not numeric or does not exists in the query " "results." -msgstr "" +msgstr "列\"%(column)s\"不是数字或不在查询结果中" #: superset/views/database/forms.py:224 superset/views/database/forms.py:357 #: superset/views/database/forms.py:445 @@ -3021,7 +2941,7 @@ msgstr "字段标签" msgid "" "Column containing ISO 3166-2 codes of region/province/department in your " "table." -msgstr "" +msgstr "表中包含地区/省/省的ISO 3166-2代码的列" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:64 msgid "Column containing latitude data" @@ -3032,9 +2952,8 @@ msgid "Column containing longitude data" msgstr "包含经度数据的列" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:115 -#, fuzzy msgid "Column is required" -msgstr "需要名称" +msgstr "列是必填项" #: superset/views/database/forms.py:225 superset/views/database/forms.py:358 #: superset/views/database/forms.py:446 @@ -3058,9 +2977,8 @@ msgid "Column referenced by aggregate is undefined: %(column)s" msgstr "聚合引用的列未定义:%(column)s" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:130 -#, fuzzy msgid "Column select" -msgstr "运行选定的查询" +msgstr "选择列" #: superset/views/database/forms.py:163 superset/views/database/forms.py:316 msgid "" @@ -3069,12 +2987,10 @@ msgid "" msgstr "字段作为数据文件的行标签使用。如果没有索引字段,则留空。" #: superset/views/database/forms.py:385 -#, fuzzy msgid "Columnar File" msgstr "列式存储文件" #: superset/views/database/views.py:550 -#, fuzzy, python-format msgid "" "Columnar file \"%(columnar_filename)s\" uploaded to table " "\"%(table_name)s\" in database \"%(db_name)s\"" @@ -3083,7 +2999,6 @@ msgstr "" "\"%(table_name)s\"" #: superset/views/database/views.py:414 -#, fuzzy msgid "Columnar to Database configuration" msgstr "列式存储文件到数据库配置" @@ -3108,7 +3023,7 @@ msgstr "数据源中缺少列:%(invalid_columns)s" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:302 msgid "Columns subtotal position" -msgstr "" +msgstr "列的小计位置" #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:134 msgid "" @@ -3125,26 +3040,22 @@ msgid "Columns to display" msgstr "要显示的字段" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:43 -#, fuzzy msgid "Columns to group by" msgstr "需要进行分组的一列或多列" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:60 -#, fuzzy msgid "Columns to group by on the columns" -msgstr "要在x轴上分组的类别。" +msgstr "必须是分组列" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:50 -#, fuzzy msgid "Columns to group by on the rows" -msgstr "要在x轴上分组的类别。" +msgstr "行上分组所依据的列" #: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:96 msgid "Combine Metrics" msgstr "整合指标" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:185 -#, fuzzy msgid "Combine metrics" msgstr "整合指标" @@ -3153,48 +3064,47 @@ msgid "" "Comma-separated color picks for the intervals, e.g. 1,2,4. Integers " "denote colors from the chosen color scheme and are 1-indexed. Length must" " be matching that of interval bounds." -msgstr "" +msgstr "间隔的逗号分隔色选项,例如1、2、4。整数表示所选配色方案中的颜色,并以1为索引。长度必须与间隔界限匹配。" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:287 msgid "" "Comma-separated interval bounds, e.g. 2,4,5 for intervals 0-2, 2-4 and " "4-5. Last number should match the value provided for MAX." -msgstr "" +msgstr "逗号分隔的区间界限,例如0-2、2-4和4-5区间的2、4、5。最后一个数字应与为Max提供的值匹配。" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:312 -#, fuzzy msgid "Comparator option" -msgstr "图表选项" +msgstr "比较器选项" #: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:26 msgid "" "Compare multiple time series charts (as sparklines) and related metrics " "quickly." -msgstr "" +msgstr "快速比较多个时间序列图表和相关指标。" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:26 msgid "Compare the same summarized metric across multiple groups." -msgstr "" +msgstr "跨多个组比较相同的汇总指标" #: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:28 msgid "" "Compares how a metric changes over time between different groups. Each " "group is mapped to a row and change over time is visualized bar lengths " "and color." -msgstr "" +msgstr "比较指标在不同组之间随时间的变化情况。每一组被映射到一行,并且随着时间的变化被可视化地显示条的长度和颜色。" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:30 msgid "" "Compares metrics from different categories using bars. Bar lengths are " "used to indicate the magnitude of each value and color is used to " "differentiate groups." -msgstr "" +msgstr "使用条形图比较不同类别的指标。条形长度用于指示每个值的大小,颜色用于区分组。" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:26 msgid "" "Compares the lengths of time different activities take in a shared " "timeline view." -msgstr "" +msgstr "比较不同活动在共享时间线视图中所花费的时间长度。" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:33 #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:33 @@ -3213,18 +3123,16 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:60 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:43 #: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:31 -#, fuzzy msgid "Comparison" -msgstr "时间比较" +msgstr "比较" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:48 msgid "Comparison Period Lag" -msgstr "" +msgstr "滞后比较" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:61 -#, fuzzy msgid "Comparison suffix" -msgstr "时间比较" +msgstr "比较前缀" #: superset-frontend/src/dashboard/components/BuilderComponentPane.tsx:102 msgid "Components" @@ -3241,20 +3149,17 @@ msgid "Compute the contribution to the total" msgstr "计算对总数的贡献值" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1173 -#, fuzzy msgid "Condition" -msgstr "警报状态" +msgstr "条件" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:320 #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:473 -#, fuzzy msgid "Conditional formatting" -msgstr "附加信息" +msgstr "条件格式设置" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:70 -#, fuzzy msgid "Confidence interval" -msgstr "刷新间隔" +msgstr "信区间间隔" #: superset/utils/pandas_postprocessing.py:827 msgid "Confidence interval must be between 0 and 1 (exclusive)" @@ -3300,31 +3205,29 @@ msgstr "确认保存" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:777 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1006 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1193 -#, fuzzy msgid "Connect" -msgstr "测试连接" +msgstr "连接" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:41 msgid "Connect Google Sheets as tables to this database" -msgstr "" +msgstr "将Google Sheet作为表格连接到此数据库" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1011 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1197 -#, fuzzy msgid "Connect a database" -msgstr "选择一个数据库" +msgstr "连接数据库" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1068 msgid "Connect this database using the dynamic form instead" -msgstr "" +msgstr "使用动态参数连接此数据库" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1301 msgid "Connect this database with a SQLAlchemy URI string instead" -msgstr "" +msgstr "使用SQLAlchemy URI链接此数据库" #: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:224 msgid "Connection" -msgstr "测试连接" +msgstr "连接" #: superset/databases/commands/exceptions.py:105 #: superset/databases/commands/exceptions.py:122 superset/views/core.py:1383 @@ -3337,7 +3240,7 @@ msgstr "连接测试成功!" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:46 msgid "Continuous" -msgstr "" +msgstr "连续式" #: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:51 #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:54 @@ -3354,35 +3257,31 @@ msgstr "贡献" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:63 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:69 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:70 -#, fuzzy msgid "Contribution Mode" -msgstr "贡献" +msgstr "贡献模式" #: superset-frontend/src/explore/components/ExploreViewContainer.jsx:430 msgid "Control labeled " -msgstr "控件名称为 " +msgstr "控件已标记 " #: superset-frontend/src/explore/components/ExploreViewContainer.jsx:430 -#, fuzzy msgid "Controls labeled " -msgstr "控件名称为 " +msgstr "控件已标记" #: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:57 -#, fuzzy msgid "Coordinates" -msgstr "平行坐标" +msgstr "坐标" #: superset-frontend/src/components/CopyToClipboard/index.jsx:75 #: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:53 #: superset-frontend/src/explore/components/ExploreActionButtons.tsx:113 -#, fuzzy msgid "Copied to clipboard!" -msgstr "复制到剪贴板" +msgstr "复制到剪贴板!" #: superset-frontend/src/explore/components/DataTableControl/index.tsx:48 msgid "Copy" -msgstr "" +msgstr "复制" #: superset-frontend/src/SqlLab/components/TableElement/index.tsx:192 msgid "Copy SELECT statement to the clipboard" @@ -3390,26 +3289,23 @@ msgstr "将 SELECT 语句复制到剪贴板" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:106 msgid "Copy and Paste JSON credentials" -msgstr "" +msgstr "复制和粘贴JSON凭据" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:124 msgid "Copy and paste the entire service account .json file here" -msgstr "" +msgstr "复制服务帐户的json文件复制并粘贴到此处" #: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:316 -#, fuzzy msgid "Copy chart URL" -msgstr "没有图表" +msgstr "复制图表URL" #: superset-frontend/src/explore/components/ExploreActionButtons.tsx:103 -#, fuzzy msgid "Copy chart URL to clipboard" -msgstr "将分区查询复制到剪贴板" +msgstr "复制图表URL到剪贴板" #: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:263 -#, fuzzy msgid "Copy dashboard URL" -msgstr "没有看板" +msgstr "复制仪表盘URL" #: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:98 msgid "Copy link" @@ -3439,14 +3335,13 @@ msgstr "将查询链接复制到剪贴板" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/ValidatedInputField.tsx:26 msgid "Copy the account name of that database you are trying to connect to." -msgstr "" +msgstr "复制尝试连接的数据库帐户名" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:91 msgid "Copy the name of the database you are trying to connect to." -msgstr "" +msgstr "复制尝试连接的数据库名" #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:552 -#, fuzzy msgid "Copy to Clipboard" msgstr "复制到剪贴板" @@ -3460,9 +3355,8 @@ msgstr "复制到剪贴板" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:28 #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:25 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:25 -#, fuzzy msgid "Correlation" -msgstr "方向" +msgstr "相关性" #: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:95 msgid "Cost estimate" @@ -3496,12 +3390,11 @@ msgstr "无法加载数据库驱动程序:{}" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:97 msgid "Could not verify the host" -msgstr "" +msgstr "无法验证主机名(IP)" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:40 -#, fuzzy msgid "Country" -msgstr "国家地图" +msgstr "国家" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:130 msgid "Country Color Scheme" @@ -3521,9 +3414,8 @@ msgid "Country Map" msgstr "国家地图" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:96 -#, fuzzy msgid "Create" -msgstr "创建一个 " +msgstr "创建" #: superset-frontend/src/addSlice/AddSliceContainer.tsx:275 msgid "Create a new chart" @@ -3534,13 +3426,12 @@ msgid "Create new chart" msgstr "创建新图表" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:111 -#, fuzzy msgid "Create new filter set" -msgstr "创建新图表" +msgstr "创建新的过滤器" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:124 msgid "Create or select schema..." -msgstr "" +msgstr "创建或者选择模式" #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:169 msgid "Created" @@ -3586,21 +3477,19 @@ msgstr "作者" #: superset/views/schedules.py:241 superset/views/schedules.py:321 msgid "Crontab" -msgstr "" +msgstr "定时任务" #: superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx:65 -#, fuzzy msgid "Cross Filter Scoping" -msgstr "设置过滤映射" +msgstr "交叉筛选作用域" #: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:349 msgid "Cross-filter scoping" -msgstr "" +msgstr "交叉筛选作用域" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:153 -#, fuzzy msgid "Cumulative" -msgstr "激活" +msgstr "累计" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:33 msgid "Custom" @@ -3624,34 +3513,31 @@ msgstr "自定义SQL" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:222 msgid "Custom SQL ad-hoc filters are not available for the native Druid connector" -msgstr "" +msgstr "自定义SQL即席筛选器不适用于本机Druid连接器" #: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:432 msgid "Custom SQL ad-hoc metrics are not available for the native Druid connector" -msgstr "" +msgstr "自定义SQL即席查询不适用于本机Druid连接器" #: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:435 msgid "Custom SQL ad-hoc metrics are not enabled for this dataset" -msgstr "" +msgstr "此数据集无法启用自定义SQL即席查询、" #: superset-frontend/src/filters/components/Time/index.ts:28 -#, fuzzy msgid "Custom time filter plugin" -msgstr "范围过滤器" +msgstr "自定义时间过滤器插件" #: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:417 msgid "Customize" msgstr "定制化配置" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:167 -#, fuzzy msgid "Customize Metrics" -msgstr "整合指标" +msgstr "自定义指标" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:453 -#, fuzzy msgid "Customize columns" -msgstr "计算列" +msgstr "自定义列" #: superset/connectors/sqla/views.py:261 msgid "D3 Format" @@ -3672,13 +3558,12 @@ msgstr "D3插件格式语法: https://github.com/d3/d3-time-format" msgid "" "D3 number format for numbers between -1.0 and 1.0, useful when you want " "to have different siginificant digits for small and large numbers" -msgstr "" +msgstr "D3数字格式,用于-1.0和1.0之间的数字,当您希望小数和大数有不同的符号数字时很有用" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:220 #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:377 -#, fuzzy msgid "D3 time format for datetime columns" -msgstr "选择图示值的格式化方式" +msgstr "D3时间格式的时间列" #: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:44 msgid "D3 time format syntax: https://github.com/d3/d3-time-format" @@ -3693,9 +3578,8 @@ msgid "DELETE" msgstr "删除" #: superset-frontend/src/components/ReportModal/index.tsx:345 -#, fuzzy msgid "DESCRIPTION ERROR" -msgstr "描述" +msgstr "描述错误" #: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:259 msgid "DML" @@ -3703,7 +3587,7 @@ msgstr "DML(数据操作语言)" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:31 msgid "Dark mode" -msgstr "" +msgstr "黑暗模式" #: superset-frontend/src/components/Menu/MenuRight.tsx:46 #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1296 @@ -3749,9 +3633,8 @@ msgid "Dashboard properties" msgstr "看板属性" #: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:153 -#, fuzzy msgid "Dashboard scheme" -msgstr "看板" +msgstr "仪表盘模式" #: superset-frontend/src/profile/components/CreatedContent.tsx:73 #: superset-frontend/src/profile/components/Favorites.tsx:74 @@ -3760,15 +3643,15 @@ msgstr "看板" #: superset/initialization/__init__.py:238 superset/views/chart/mixin.py:79 #: superset/views/dashboard/mixin.py:25 msgid "Dashboards" -msgstr "看板" +msgstr "仪表盘" #: superset/dashboards/commands/exceptions.py:58 msgid "Dashboards could not be deleted." -msgstr "看板无法被删除。" +msgstr "仪表盘无法被删除。" #: superset/charts/commands/exceptions.py:91 msgid "Dashboards do not exist" -msgstr "看板" +msgstr "仪表盘" #: superset-frontend/src/explore/components/ControlPanelsContainer.tsx:401 #: superset-frontend/src/explore/components/DataTablesPane/index.tsx:388 @@ -3790,9 +3673,8 @@ msgid "Data Source" msgstr "数据源" #: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:57 -#, fuzzy msgid "Data Table" -msgstr "编辑表" +msgstr "数据表" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:290 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:181 @@ -3802,21 +3684,20 @@ msgstr "编辑表" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:197 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:200 msgid "Data Zoom" -msgstr "" +msgstr "数据缩放" #: superset/views/core.py:2313 msgid "" "Data could not be deserialized from the results backend. The storage " "format might have changed, rendering the old data stake. You need to re-" "run the original query." -msgstr "" +msgstr "无法从结果后端反序列化数据。存储格式可能已经改变,呈现了旧的数据桩。您需要重新运行原始查询。" #: superset/views/core.py:2266 -#, fuzzy msgid "" "Data could not be retrieved from the results backend. You need to re-run " "the original query." -msgstr "无法反序列化数据。您可能需要重新运行查询。" +msgstr "无法从结果后端检索数据。您需要重新运行原始查询。" #: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:219 msgid "Data preview" @@ -3860,7 +3741,7 @@ msgid "Database" msgstr "数据库" #: superset/views/database/views.py:452 -#, fuzzy, python-format +#, python-format msgid "" "Database \"%(database_name)s\" schema \"%(schema_name)s\" is not allowed " "for columnar uploads. Please contact your Superset Admin." @@ -3881,9 +3762,8 @@ msgid "" msgstr "数据库 \"%(database_name)s\" schema \"%(schema_name)s\" 不允许用于excel上传。请联系管理员。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:910 -#, fuzzy msgid "Database Creation Error" -msgstr "数据库错误" +msgstr "数据库创建错误" #: superset/views/access_requests.py:43 msgid "Database URL" @@ -3903,7 +3783,7 @@ msgstr "数据库无法更新" #: superset/errors.py:117 msgid "Database does not allow data manipulation." -msgstr "" +msgstr "数据库不允许此数据操作。" #: superset/charts/commands/exceptions.py:82 #: superset/datasets/commands/exceptions.py:41 @@ -3912,18 +3792,16 @@ msgid "Database does not exist" msgstr "数据库不存在" #: superset/connectors/sqla/models.py:1478 -#, fuzzy msgid "Database does not support subqueries" -msgstr "数据库不存在" +msgstr "数据库不支持子查询" #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:688 msgid "Database error" msgstr "数据库错误" #: superset/databases/commands/validate.py:136 -#, fuzzy msgid "Database is offline." -msgstr "数据库名称" +msgstr "数据库已下线" #: superset/reports/commands/exceptions.py:62 msgid "Database is required for alerts" @@ -3947,9 +3825,8 @@ msgid "Database parameters are invalid." msgstr "数据库参数无效" #: superset/db_engine_specs/base.py:1393 -#, fuzzy msgid "Database port" -msgstr "数据库" +msgstr "数据库端口" #: superset-frontend/src/profile/components/Security.tsx:46 #: superset-frontend/src/views/CRUD/data/common.ts:26 @@ -3980,14 +3857,12 @@ msgid "Dataset %(name)s already exists" msgstr "数据集 %(name)s 已存在" #: superset/datasets/columns/commands/exceptions.py:27 -#, fuzzy msgid "Dataset column delete failed." -msgstr "注释与注释层" +msgstr "数据集列删除失败。" #: superset/datasets/columns/commands/exceptions.py:23 -#, fuzzy msgid "Dataset column not found." -msgstr "数据库没有找到" +msgstr "数据集行删除失败。" #: superset/datasets/commands/exceptions.py:157 msgid "Dataset could not be created." @@ -4008,19 +3883,16 @@ msgid "Dataset does not exist" msgstr "数据集不存在" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:843 -#, fuzzy msgid "Dataset is required" -msgstr "需要数据源" +msgstr "需要数据集" #: superset/datasets/metrics/commands/exceptions.py:27 -#, fuzzy msgid "Dataset metric delete failed." -msgstr "注释与注释层" +msgstr "数据集指标删除失败" #: superset/datasets/metrics/commands/exceptions.py:23 -#, fuzzy msgid "Dataset metric not found." -msgstr "数据库没有找到" +msgstr "数据集指标没找到" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:881 #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:888 @@ -4042,9 +3914,8 @@ msgid "Datasets" msgstr "数据集" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:809 -#, fuzzy msgid "Datasets do not contain a temporal column" -msgstr "数据帧(DataFrame)必须包含时间列" +msgstr "数据集不包含时间列" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:157 #: superset/connectors/druid/views.py:93 superset/views/access_requests.py:44 @@ -4061,9 +3932,9 @@ msgid "Datasource Name" msgstr "数据库名称" #: superset/connectors/connector_registry.py:99 -#, fuzzy, python-format +#, python-format msgid "Datasource id not found: %(id)s" -msgstr "数据库没有找到" +msgstr "数据源id不存在:%(id)s" #: superset/charts/commands/exceptions.py:101 msgid "Datasource type is required when datasource_id is given" @@ -4071,7 +3942,6 @@ msgstr "给定数据源id时,需要提供数据源类型" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:163 #: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:87 -#, fuzzy msgid "Date Time Format" msgstr "时间格式" @@ -4108,18 +3978,17 @@ msgid "Datetime format" msgstr "时间格式" #: superset/db_engine_specs/base.py:96 -#, fuzzy msgid "Day" msgstr "天" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:66 -#, fuzzy, python-format +#, python-format msgid "Days %s" -msgstr "天" +msgstr "%s天" #: superset/connectors/sqla/models.py:1593 msgid "Db engine did not return all queried columns" -msgstr "" +msgstr "数据库引擎未返回所有查询的列" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:77 msgid "December" @@ -4143,7 +4012,7 @@ msgstr "Deck.gl - 弧度" #: superset/viz.py:2843 msgid "Deck.gl - GeoJSON" -msgstr "Deck.gl - GeoJson" +msgstr "Deck.gl - 地理json" #: superset/viz.py:2431 msgid "Deck.gl - Multiple Layers" @@ -4182,9 +4051,8 @@ msgid "Default URL to redirect to when accessing from the dataset list page" msgstr "从数据集列表页访问时重定向到的默认URL" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:907 -#, fuzzy msgid "Default Value" -msgstr "默认纬度" +msgstr "缺省值" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:290 msgid "Default latitude" @@ -4198,29 +4066,28 @@ msgstr "默认经度" msgid "" "Default minimal column width in pixels, actual width may still be larger " "than this if other columns don't need much space" -msgstr "" +msgstr "默认最小列宽(以像素为单位),如果其他列不需要太多空间,则实际宽度可能仍大于此值" #: superset-frontend/src/filters/components/Select/controlPanel.ts:105 msgid "Default to first item" -msgstr "" +msgstr "默认为第一项" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:936 #: superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx:222 -#, fuzzy msgid "Default value is required" -msgstr "需要数据源" +msgstr "需要默认值" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:95 msgid "Default value must be set when \"Filter has default value\" is checked" -msgstr "" +msgstr "选中筛选器具有默认值时,必须设置默认值" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:93 msgid "Default value must be set when \"Required\" is checked" -msgstr "" +msgstr "当\"必填项\"被选中时默认值必须被设置" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts:89 msgid "Default value set automatically when \"Default to first item\" is checked" -msgstr "" +msgstr "当\"默认为第一项\"被选中时默认值需要设置为自动" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:44 #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:266 @@ -4267,7 +4134,7 @@ msgstr "定义滚动窗口函数的大小,相对于所选的时间粒度" msgid "" "Defines whether the step should appear at the beginning, middle or end " "between two data points" -msgstr "" +msgstr "定义步骤应出现在两个数据点之间的开始、中间还是结束处" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:82 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:325 @@ -4316,9 +4183,8 @@ msgid "Delete Query?" msgstr "确定删除查询?" #: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:110 -#, fuzzy msgid "Delete Report?" -msgstr "删除模板?" +msgstr "删除报表?" #: superset-frontend/src/views/CRUD/csstemplates/CssTemplatesList.tsx:321 msgid "Delete Template?" @@ -4334,16 +4200,15 @@ msgstr "删除注释" #: superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx:202 msgid "Delete dashboard tab?" -msgstr "是否删除tab页?" +msgstr "是否删除仪表盘tab页?" #: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:332 msgid "Delete database" msgstr "删除数据库" #: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:78 -#, fuzzy msgid "Delete email report" -msgstr "警报和报告" +msgstr "删除邮件报告" #: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:404 msgid "Delete query" @@ -4442,27 +4307,24 @@ msgid "Delivery Type" msgstr "交付类型" #: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:124 -#, fuzzy msgid "Delivery method" -msgstr "添加通知方法" +msgstr "发送方式" #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:33 msgid "Demographics" -msgstr "" +msgstr "人口统计" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:43 #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:38 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:45 -#, fuzzy msgid "Density" -msgstr "实体" +msgstr "密度" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:55 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:45 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:38 -#, fuzzy msgid "Deprecated" -msgstr "已创建" +msgstr "过时" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:42 #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:47 @@ -4496,9 +4358,8 @@ msgid "Description (this can be seen in the list)" msgstr "说明(见列表)" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:520 -#, fuzzy msgid "Description Columns" -msgstr "描述" +msgstr "列描述" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:48 msgid "Description text that shows up below your Big Number" @@ -4526,16 +4387,15 @@ msgstr "确定此看板在所有看板列表中是否可见" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:230 msgid "Diamond" -msgstr "" +msgstr "下钻" #: superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx:77 msgid "Did you mean:" msgstr "您的意思是:" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:101 -#, fuzzy msgid "Difference" -msgstr "点击查看差异" +msgstr "差异" #: superset/viz.py:1968 msgid "Directed Force Layout" @@ -4544,35 +4404,31 @@ msgstr "有向图" #: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:31 #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:39 #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:42 -#, fuzzy msgid "Directional" -msgstr "描述" +msgstr "方向" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:165 #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:185 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:274 -#, fuzzy msgid "Disabled" -msgstr "编辑表" +msgstr "禁用" #: superset-frontend/src/dashboard/components/Header/index.jsx:579 msgid "Discard changes" msgstr "放弃更改" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:43 -#, fuzzy msgid "Discrete" -msgstr "已创建" +msgstr "离散" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:149 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:42 -#, fuzzy msgid "Display Name" -msgstr "过滤值" +msgstr "显示名称" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:164 msgid "Display column level total" -msgstr "" +msgstr "显示列级别合计" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:615 msgid "Display configuration" @@ -4587,7 +4443,7 @@ msgstr "在每个列中并排显示指标,而不是每个指标并排显示每 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:152 msgid "Display row level total" -msgstr "" +msgstr "显示行级合计" #: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:89 msgid "Display total row/column" @@ -4599,7 +4455,7 @@ msgid "" "mapping relationships and showing which nodes are important in a network." " Graph charts can be configured to be force-directed or circulate. If " "your data has a geospatial component, try the deck.gl Arc chart." -msgstr "" +msgstr "显示图形结构中实体之间的连接。用于映射关系和显示网络中哪些节点是重要的。图表可以配置为强制引导或循环。如果您的数据具有地理空间组件,请尝试使用deck.gl圆弧图表。" #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:132 msgid "Distribute across" @@ -4609,9 +4465,8 @@ msgstr "基于某列进行分布" #: superset-frontend/plugins/legacy-plugin-chart-horizon/src/index.js:26 #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:48 #: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/createMetadata.ts:25 -#, fuzzy msgid "Distribution" -msgstr "贡献" +msgstr "分布" #: superset/viz.py:1769 msgid "Distribution - Bar Chart" @@ -4627,9 +4482,8 @@ msgid "Do you want a donut or a pie?" msgstr "是否用圆环圈替代饼图?" #: superset-frontend/src/components/Menu/MenuRight.tsx:214 -#, fuzzy msgid "Documentation" -msgstr "执行时间" +msgstr "文档" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:40 msgid "Domain" @@ -4637,7 +4491,7 @@ msgstr "主域" #: superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx:29 msgid "Don't refresh" -msgstr "不要刷新" +msgstr "不刷新" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:83 #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:208 @@ -4652,7 +4506,7 @@ msgstr "下载为图片" #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:543 msgid "Download to CSV" -msgstr "" +msgstr "下载到CSV" #: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:72 #: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:83 @@ -4669,13 +4523,13 @@ msgstr "草稿" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:168 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:171 msgid "Draw a marker on data points. Only applicable for line types." -msgstr "" +msgstr "在数据点上绘制标记。仅适用于线型。" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:171 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:135 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:138 msgid "Draw area under curves. Only applicable for line types." -msgstr "" +msgstr "在曲线下绘制区域。仅适用于线型。" #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:178 msgid "Draw line from Pie to label when labels outside?" @@ -4689,40 +4543,40 @@ msgstr "当标签在外侧时,是否在饼图到标签之间连线?" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:262 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:265 msgid "Draw split lines for minor y-axis ticks" -msgstr "" +msgstr "绘制次要y轴记号的分割线" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:217 msgid "Drop a column here or click" -msgstr "" +msgstr "将列拖放到此处或单击" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:367 msgid "Drop a column/metric here or click" -msgstr "" +msgstr "将列/指标放在此处或单击" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx:222 msgid "Drop column here" -msgstr "" +msgstr "将列拖放到此处" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx:372 msgid "Drop column or metric here" -msgstr "" +msgstr "将列或指标放在此处" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx:80 msgid "Drop columns here" -msgstr "" +msgstr "将列拖放到此处" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx:389 -#, fuzzy, python-format +#, python-format msgid "Drop columns or metrics here" -msgstr "%s 列与计量指标" +msgstr "将列或指标拖放到此处" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx:388 msgid "Drop columns/metrics here or click" -msgstr "" +msgstr "将列/指标拖放到此处或单击" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:176 msgid "Drop temporal column here" -msgstr "" +msgstr "将时间列拖放到此处" #: superset/connectors/druid/views.py:213 #: superset/initialization/__init__.py:516 @@ -4755,14 +4609,14 @@ msgstr "双线图" #: superset/views/datasource/views.py:119 #, python-format msgid "Duplicate column name(s): %(columns)s" -msgstr "" +msgstr "重复的列名%(columns)s" #: superset/common/query_object.py:284 #, python-format msgid "" "Duplicate column/metric labels: %(labels)s. Please make sure all columns " "and metrics have a unique label." -msgstr "" +msgstr "重复的列/指标标签:%(labels)s。请确保所有列和指标都有唯一的标签。" #: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:366 msgid "Duplicate tab" @@ -4814,26 +4668,24 @@ msgid "" msgstr "此表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为数据库的超时。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:250 -#, fuzzy msgid "" "Duration (in seconds) of the metadata caching timeout for schemas of this" " database. If left unset, the cache never expires." -msgstr "此数据库图表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为全局超时。" +msgstr "此数据库图表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为永不过期。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:272 -#, fuzzy msgid "" "Duration (in seconds) of the metadata caching timeout for tables of this " "database. If left unset, the cache never expires. " -msgstr "此数据库图表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,这默认为全局超时。" +msgstr "此数据库图表的缓存超时持续时间(以秒为单位)。超时为0表示缓存永远不会过期。注意,如果未定义,缓存为永不过期。" #: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:41 msgid "Duration in ms (1.40008 => 1ms 400µs 80ns)" -msgstr "" +msgstr "持续时间(毫秒)(1.40008 => 1ms 400µs 80ns)" #: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:40 msgid "Duration in ms (66000 => 1m 6s)" -msgstr "" +msgstr "持续时间(毫秒)(66000 => 1m 6s)" #: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:205 #, python-format @@ -4856,38 +4708,35 @@ msgstr "持续时间:%s" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:42 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:61 #: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:124 -#, fuzzy msgid "ECharts" -msgstr "图表" +msgstr "ECharts图表" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:76 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:169 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:176 msgid "END (EXCLUSIVE)" -msgstr "" +msgstr "结束" #: superset-frontend/src/views/CRUD/hooks.ts:628 #, python-format msgid "ERROR: %s" -msgstr "" +msgstr "错误: %s" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:241 -#, fuzzy msgid "Edge length" -msgstr "页面长度" +msgstr "边长" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:247 msgid "Edge length between nodes" -msgstr "" +msgstr "节点之间的边长" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:124 msgid "Edge symbols" -msgstr "" +msgstr "边符号" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:226 -#, fuzzy msgid "Edge width" -msgstr "线宽" +msgstr "边缘宽度" #: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:197 #: superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.tsx:35 @@ -4905,9 +4754,8 @@ msgid "Edit" msgstr "编辑" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1053 -#, fuzzy msgid "Edit Alert" -msgstr "编辑表" +msgstr "编辑警报" #: superset/views/annotations.py:61 msgid "Edit Annotation" @@ -4967,7 +4815,7 @@ msgstr "编辑 Druid 指标" #: superset-frontend/src/components/ReportModal/index.tsx:251 msgid "Edit Email Report" -msgstr "" +msgstr "编辑邮件报告" #: superset/views/log/__init__.py:24 msgid "Edit Log" @@ -4982,9 +4830,8 @@ msgid "Edit Plugin" msgstr "编辑插件" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1051 -#, fuzzy msgid "Edit Report" -msgstr "报告" +msgstr "编辑报表" #: superset/connectors/sqla/views.py:317 msgid "Edit Row level security filter" @@ -5017,9 +4864,8 @@ msgid "Edit chart properties" msgstr "编辑图表属性" #: superset-frontend/src/dashboard/components/Header/index.jsx:605 -#, fuzzy msgid "Edit dashboard" -msgstr "编辑看板" +msgstr "编辑仪表盘" #: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:302 msgid "Edit dashboard properties" @@ -5035,10 +4881,9 @@ msgstr "编辑数据集" #: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:73 msgid "Edit email report" -msgstr "" +msgstr "编辑邮件报告" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx:151 -#, fuzzy msgid "Edit formatter" msgstr "日期格式化" @@ -5072,35 +4917,34 @@ msgid "Editing 1 filter:" msgstr "编辑1个过滤条件:" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:119 -#, fuzzy msgid "Editing filter set:" -msgstr "编辑1个过滤条件:" +msgstr "编辑过滤条件集合" #: superset/errors.py:110 msgid "Either the database is spelled incorrectly or does not exist." -msgstr "" +msgstr "数据库拼写不正确或不存在。" #: superset/db_engine_specs/mysql.py:124 superset/db_engine_specs/presto.py:195 #: superset/db_engine_specs/redshift.py:63 #, python-format msgid "Either the username \"%(username)s\" or the password is incorrect." -msgstr "" +msgstr "用户名\"%(username)s\"或密码不正确" #: superset/db_engine_specs/mssql.py:74 #, python-format msgid "" "Either the username \"%(username)s\", password, or database name " "\"%(database)s\" is incorrect." -msgstr "" +msgstr "用户名\"%(username)s\"、密码或数据库名称\"%(database)s\"不正确" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:114 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:118 msgid "Either the username or password is incorrect." -msgstr "" +msgstr "用户名或密码不正确。" #: superset/errors.py:109 msgid "Either the username or the password is wrong." -msgstr "" +msgstr "用户名或密码错误。" #: superset/views/schedules.py:326 msgid "Email Format" @@ -5108,44 +4952,39 @@ msgstr "电子邮件格式" #: superset-frontend/src/components/ReportModal/HeaderReportActionsDropdown/index.tsx:64 msgid "Email reports active" -msgstr "" +msgstr "激活邮件报告" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:47 -#, fuzzy msgid "Emit Target" -msgstr "编辑数据集" +msgstr "发送目标" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx:30 -#, fuzzy msgid "Emit dashboard cross filters" -msgstr "编辑看板属性" +msgstr "发送仪表盘过滤" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/emitFilterControl.tsx:33 -#, fuzzy msgid "Emit dashboard cross filters." -msgstr "编辑看板属性" +msgstr "发送仪表盘过滤" #: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:95 -#, fuzzy msgid "Emitted values" msgstr "限制选择器值" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:191 msgid "Emphasis" -msgstr "" +msgstr "重点" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:36 msgid "Employment and education" -msgstr "" +msgstr "就业和教育" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:214 msgid "Empty circle" -msgstr "" +msgstr "空圈" #: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:59 -#, fuzzy msgid "Empty collection" -msgstr "测试连接" +msgstr "空集合" #: superset/connectors/sqla/models.py:1068 msgid "Empty query?" @@ -5163,33 +5002,32 @@ msgstr "启用过滤器选择" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:200 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:203 msgid "Enable data zooming controls" -msgstr "" +msgstr "启用数据缩放控件" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:44 -#, fuzzy msgid "Enable forecast" -msgstr "日期格式化" +msgstr "启用预测" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:47 msgid "Enable forecasting" -msgstr "" +msgstr "启用预测中" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:161 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:270 msgid "Enable graph roaming" -msgstr "" +msgstr "启用图形漫游" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:141 msgid "Enable node dragging" -msgstr "" +msgstr "启用节点拖动" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:176 msgid "Enable query cost estimation" -msgstr "" +msgstr "启用查询成本估算" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:290 msgid "Enable server side pagination of results (experimental feature)" -msgstr "" +msgstr "支持服务器端结果分页(实验功能)" #: superset/viz.py:2530 msgid "" @@ -5208,15 +5046,13 @@ msgid "End Time" msgstr "结束时间" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:120 -#, fuzzy msgid "End angle" -msgstr "时间范围" +msgstr "结束角度" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:78 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:171 -#, fuzzy msgid "End date excluded from time range" -msgstr "配置自定义时间范围" +msgstr "从时间范围中排除的结束日期" #: superset/annotation_layers/annotations/commands/exceptions.py:35 msgid "End date must be after start date" @@ -5225,33 +5061,31 @@ msgstr "起始时间不可以大于当前时间" #: superset/databases/commands/validate.py:71 #, python-format msgid "Engine \"%(engine)s\" cannot be configured through parameters." -msgstr "" +msgstr "引擎 \"%(engine)s\" 不能通过参数配置。" #: superset/databases/commands/validate.py:59 superset/databases/schemas.py:308 #, python-format msgid "Engine \"%(engine)s\" is not a valid engine." -msgstr "" +msgstr "无效引擎\"%(engine)s\"" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:459 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:464 -#, fuzzy msgid "Engine Parameters" -msgstr "模板参数" +msgstr "引擎参数" #: superset/databases/schemas.py:272 msgid "" "Engine spec \"InvalidEngine\" does not support being configured via " "individual parameters." -msgstr "" +msgstr "引擎\"InvalidEngine\"不支持通过单独的参数进行配置。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:356 msgid "Enter CA_BUNDLE" -msgstr "" +msgstr "进入CA_BUNDLE" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:55 -#, fuzzy msgid "Enter a name for this sheet" -msgstr "输入标签的新标题" +msgstr "输入此工作表的名称" #: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:238 msgid "Enter a new title for the tab" @@ -5260,14 +5094,12 @@ msgstr "输入标签的新标题" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:222 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:244 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:266 -#, fuzzy msgid "Enter duration in seconds" -msgstr "时间(秒)" +msgstr "输入间隔时间(秒)" #: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:327 -#, fuzzy msgid "Enter fullscreen" -msgstr "切换全屏" +msgstr "全屏" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:73 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:397 @@ -5276,13 +5108,12 @@ msgid "Entity" msgstr "实体" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:125 -#, fuzzy msgid "Entity ID" -msgstr "实体" +msgstr "实体ID" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:216 msgid "Equal Date Sizes" -msgstr "" +msgstr "相同的日期大小" #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:56 msgid "Error" @@ -5314,7 +5145,7 @@ msgstr "获取jinja表达式中的谓词的值出错:%(msg)s" #: superset-frontend/src/dashboard/containers/DashboardPage.tsx:190 msgid "Error loading chart datasources. Filters may not work correctly." -msgstr "" +msgstr "加载图表数据源时出错。过滤器可能无法正常工作。" #: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:144 msgid "Error message" @@ -5322,19 +5153,18 @@ msgstr "错误信息" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:104 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:139 -#, fuzzy msgid "Error while fetching charts" -msgstr "获取数据时出错" +msgstr "获取图表时出错" #: superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx:89 -#, fuzzy, python-format +#, python-format msgid "Error while fetching data: %s" -msgstr "获取数据时出错" +msgstr "获取数据时出错:%s" #: superset/connectors/sqla/models.py:842 -#, fuzzy, python-format +#, python-format msgid "Error while rendering virtual dataset query: %(msg)s" -msgstr "保存数据集时出错:%s" +msgstr "保存查询时出错:%(msg)s" #: superset-frontend/src/SqlLab/components/EstimateQueryCostButton/index.tsx:91 msgid "Estimate cost" @@ -5353,26 +5183,24 @@ msgid "Event Flow" msgstr "事件流" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:43 -#, fuzzy msgid "Event Names" -msgstr "Sheet名称" +msgstr "事件名称" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:35 msgid "Event definition" -msgstr "" +msgstr "事件定义" #: superset/viz.py:2896 msgid "Event flow" msgstr "事件流" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:478 -#, fuzzy msgid "Event time column" -msgstr "时间列" +msgstr "事件时间列" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:43 msgid "Every" -msgstr "每" +msgstr "每个" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:30 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:29 @@ -5390,12 +5218,11 @@ msgstr "每" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:48 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:57 msgid "Evolution" -msgstr "" +msgstr "演化" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1263 -#, fuzzy msgid "Exact" -msgstr "之后" +msgstr "精确" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:34 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:49 @@ -5408,7 +5235,7 @@ msgstr "例子" #: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:92 #, python-format msgid "Example %(tableName)s will appear here" -msgstr "" +msgstr "示例 %(tableName)s 将出现在此处" #: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:759 #: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:180 @@ -5434,41 +5261,36 @@ msgid "Excel to Database configuration" msgstr "Excel 到数据库配置" #: superset-frontend/src/filters/components/Select/controlPanel.ts:126 -#, fuzzy msgid "Exclude selected values" -msgstr "限制选择器值" +msgstr "排除选定的值" #: superset-frontend/src/SqlLab/components/HighlightedSql/index.tsx:82 -#, fuzzy msgid "Executed SQL" -msgstr "已执行查询" +msgstr "已执行的SQL" #: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:162 msgid "Executed query" msgstr "已执行查询" #: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:105 -#, fuzzy msgid "Execution ID" -msgstr "操作日志" +msgstr "任务ID" #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:307 msgid "Execution log" msgstr "操作日志" #: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:326 -#, fuzzy msgid "Exit fullscreen" -msgstr "切换全屏" +msgstr "退出全屏" #: superset-frontend/src/dashboard/components/filterscope/treeIcons.jsx:36 msgid "Expand all" msgstr "全部展开" #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:152 -#, fuzzy msgid "Expand table preview" -msgstr "删除表格预览" +msgstr "展开表格预览" #: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:351 msgid "Expand tool bar" @@ -5482,7 +5304,7 @@ msgstr "展开工具栏" #: superset-frontend/src/filters/components/TimeColumn/index.ts:31 #: superset-frontend/src/filters/components/TimeGrain/index.ts:31 msgid "Experimental" -msgstr "" +msgstr "实验" #: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.jsx:98 #: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:168 @@ -5497,7 +5319,7 @@ msgstr "查看 - %(table)s" #: superset/reports/notifications/email.py:91 msgid "Explore in Superset" -msgstr "" +msgstr "探索" #: superset-frontend/src/SqlLab/components/ExploreCtasResultsButton/index.jsx:91 #: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:161 @@ -5528,27 +5350,24 @@ msgstr "导出看板?" #: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:341 msgid "Export full CSV" -msgstr "" +msgstr "导出全量CSV" #: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:397 -#, fuzzy msgid "Export query" -msgstr "用户查询" +msgstr "导出查询" #: superset-frontend/src/explore/components/ExploreActionButtons.tsx:202 #: superset-frontend/src/explore/components/ExploreActionButtons.tsx:210 -#, fuzzy msgid "Export to .CSV format" -msgstr "导出为 .csv 格式" +msgstr "导出为CSV格式" #: superset-frontend/src/explore/components/ExploreActionButtons.tsx:182 -#, fuzzy msgid "Export to .JSON format" -msgstr "导出为 .csv 格式" +msgstr "导出为JSON格式" #: superset/views/base.py:538 msgid "Export to YAML" -msgstr "导出到YAML" +msgstr "导出到YAML格式" #: superset/views/base.py:538 msgid "Export to YAML?" @@ -5556,7 +5375,7 @@ msgstr "导出到YAML?" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:76 msgid "Expose database in SQL Lab" -msgstr "" +msgstr "在SQL工具箱中展示数据库" #: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:281 #: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:387 @@ -5583,12 +5402,10 @@ msgid "Extra Controls" msgstr "额外控件" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:87 -#, fuzzy msgid "Extra Parameters" -msgstr "模板参数" +msgstr "额外参数" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:736 -#, fuzzy msgid "" "Extra data to specify table metadata. Currently supports metadata of the " "format: `{ \"certification\": { \"certified_by\": \"Data Platform Team\"," @@ -5609,16 +5426,14 @@ msgid "Extra parameters for use in jinja templated queries" msgstr "用于jinja模板化查询的额外参数" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:89 -#, fuzzy msgid "" "Extra parameters that any plugins can choose to set for use in Jinja " "templated queries" msgstr "用于jinja模板化查询的额外参数" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:78 -#, fuzzy msgid "Extra url parameters for use in Jinja templated queries" -msgstr "用于jinja模板化查询的额外参数" +msgstr "用于jinja模板化查询的额外url" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:92 msgid "FEB" @@ -5629,9 +5444,8 @@ msgid "FRI" msgstr "星期五" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:115 -#, fuzzy msgid "Factor" -msgstr "操作" +msgstr "因素" #: superset/views/database/forms.py:145 superset/views/database/forms.py:298 #: superset/views/database/forms.py:426 @@ -5650,13 +5464,13 @@ msgid "Failed at retrieving results" msgstr "检索结果失败" #: superset-frontend/src/SqlLab/actions/sqlLab.js:409 -#, fuzzy, python-format +#, python-format msgid "Failed at stopping query. %s" -msgstr "停止查询时候出错。 " +msgstr "停止查询失败。 %s" #: superset/errors.py:137 superset/sqllab/sql_json_executer.py:194 msgid "Failed to start remote query on a worker." -msgstr "" +msgstr "无法启动远程查询" #: superset-frontend/src/explore/components/controls/withAsyncVerification.tsx:201 #, python-format @@ -5696,7 +5510,7 @@ msgid "Fetched %s" msgstr "刷新于 %s" #: superset/databases/commands/exceptions.py:62 -#, fuzzy, python-format +#, python-format msgid "Field cannot be decoded by JSON. %(json_error)s" msgstr "字段不能由JSON解码。%{json_error}s" @@ -5715,43 +5529,28 @@ msgstr "文件" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:982 msgid "Fill all required fields to enable \"Default Value\"" -msgstr "" +msgstr "填写所有必填字段以启用默认值" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:166 -#, fuzzy msgid "Fill method" -msgstr "通知方式" +msgstr "填充方式" #: superset-frontend/src/components/ListView/Filters/Select.tsx:77 -#, fuzzy msgid "Filter" -msgstr "无筛选" +msgstr "过滤器" #: superset/templates/appbuilder/general/widgets/search.html:24 msgid "Filter List" msgstr "过滤" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:787 -#, fuzzy msgid "Filter Type" -msgstr "过滤用户" +msgstr "过滤类型" #: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:26 msgid "Filter box" msgstr "过滤器" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:204 -msgid "Filter by database" -msgstr "过滤数据库" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:240 -msgid "Filter by status" -msgstr "过滤状态" - -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:195 -msgid "Filter by user" -msgstr "过滤用户" - #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:282 msgid "Filter configuration" msgstr "过滤配置" @@ -5762,15 +5561,15 @@ msgstr "过滤条件的过滤配置" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:895 msgid "Filter has default value" -msgstr "" +msgstr "过滤器默认值" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1010 msgid "Filter is hierarchical" -msgstr "" +msgstr "分层过滤" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:109 msgid "Filter metadata changed in dashboard. It will not be applied." -msgstr "" +msgstr "仪表盘的过滤器已被更改,将不会被应用" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:777 msgid "Filter name" @@ -5781,32 +5580,29 @@ msgid "Filter results" msgstr "过滤结果" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:144 -#, fuzzy, python-format +#, python-format msgid "Filter set already exists" -msgstr "数据集 %(name)s 已存在" +msgstr "过滤器已存在" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:143 #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:83 -#, fuzzy msgid "Filter set with this name already exists" -msgstr "同名数据库已存在" +msgstr "过滤器已存在" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx:348 #, python-format msgid "Filter sets (%(filterSetCount)d)" -msgstr "" +msgstr "过滤器个数(%(filterSetCount)d)" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:791 -#, fuzzy msgid "Filter type" -msgstr "过滤用户" +msgstr "过滤类型" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:417 msgid "Filter value (case sensitive)" msgstr "过滤值(区分大小写)" #: superset/connectors/sqla/models.py:1278 -#, fuzzy msgid "Filter value list cannot be empty" msgstr "不能为空" @@ -5826,9 +5622,9 @@ msgid "Filters" msgstr "过滤" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:84 -#, fuzzy, python-format +#, python-format msgid "Filters (%d)" -msgstr "未选择的条件 (%d)" +msgstr "过滤 (%d)" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:134 msgid "Filters by columns" @@ -5843,14 +5639,13 @@ msgid "Filters configuration" msgstr "过滤配置" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx:467 -#, fuzzy msgid "Filters configuration and scoping" -msgstr "过滤配置和范围" +msgstr "过滤配置和作用域" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx:159 #, python-format msgid "Filters out of scope (%d)" -msgstr "" +msgstr "筛选器超出范围(%d)" #: superset/connectors/sqla/views.py:348 msgid "" @@ -5872,18 +5667,17 @@ msgstr "" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:808 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1193 msgid "Finish" -msgstr "" +msgstr "完成" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:124 msgid "" "Fix the trend line to the full time range specified in case filtered " "results do not include the start or end dates" -msgstr "" +msgstr "将趋势线固定为指定的完整时间范围,以防过滤的结果不包括开始日期或结束日期" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:123 -#, fuzzy msgid "Fix to selected Time Range" -msgstr "配置高级时间范围" +msgstr "固定到选定的时间范围" #: superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx:149 msgid "Fixed" @@ -5902,16 +5696,15 @@ msgstr "固定颜色" #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:27 #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:32 msgid "Flow" -msgstr "" +msgstr "流图" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:133 -#, fuzzy msgid "Font size" -msgstr "点大小" +msgstr "字体大小" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:134 msgid "Font size for axis labels, detail value and other text elements" -msgstr "" +msgstr "轴标签、详图值和其他文本元素的字体大小" #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:71 msgid "Font size for the biggest value in the list" @@ -5922,11 +5715,10 @@ msgid "Font size for the smallest value in the list" msgstr "列表中最小值的字体大小" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:179 -#, fuzzy msgid "" -"For Presto and Postgres, shows a button to compute cost before running a " +"For Bigquery, Presto and Postgres, shows a button to compute cost before running a " "query." -msgstr "在运行查询之前计算执行计划" +msgstr "对于Presto和Postgres,显示计算成本按钮(查询后)" #: superset/connectors/sqla/views.py:342 msgid "" @@ -5936,15 +5728,14 @@ msgid "" msgstr "对于常规过滤,这些是此过滤将应用于的角色。对于基本过滤,这些是过滤不适用的角色,例如Admin代表admin应该查看所有数据。" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:111 -#, fuzzy msgid "Force" -msgstr "来源" +msgstr "强制" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:129 msgid "" "Force all tables and views to be created in this schema when clicking " "CTAS or CVAS in SQL Lab." -msgstr "" +msgstr "在SQL工具箱中点击CTAS or CVAS强制创建所有数据表或视图" #: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:270 msgid "Force refresh" @@ -5963,43 +5754,38 @@ msgid "Force-directed Graph" msgstr "力导向图" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:56 -#, fuzzy msgid "Forecast periods" -msgstr "宽限期" +msgstr "预测期" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:37 #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:42 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:45 -#, fuzzy msgid "Formattable" -msgstr "表的键" +msgstr "格式表" #: superset-frontend/src/components/ReportModal/index.tsx:296 msgid "Formatted CSV attached in email" -msgstr "" +msgstr "在邮件中附件CSV" #: superset-frontend/packages/superset-ui-core/src/query/extractQueryFields.ts:130 msgid "Found invalid orderby options" -msgstr "" +msgstr "发现无效的orderby选项" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:80 -#, fuzzy msgid "Fraction digits" -msgstr "操作" +msgstr "分数位" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/controlPanel.ts:53 -#, fuzzy msgid "Frequency" -msgstr "刷新频率" +msgstr "频率" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:304 -#, fuzzy msgid "Friction" -msgstr "操作" +msgstr "摩擦" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:310 msgid "Friction between nodes" -msgstr "" +msgstr "节点之间的摩擦" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:61 msgid "Friday" @@ -6010,31 +5796,28 @@ msgid "From date cannot be larger than to date" msgstr "起始时间不可以大于当前时间" #: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:52 -#, fuzzy msgid "Funnel Chart" -msgstr "新增图表" +msgstr "漏斗图" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:454 msgid "Further customize how to display each column" -msgstr "" +msgstr "进一步自定义如何显示每列" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:168 msgid "Further customize how to display each metric" -msgstr "" +msgstr "进一步定制如何显示每个指标" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:42 -#, fuzzy msgid "Gauge Chart" -msgstr "图表保存" +msgstr "仪表图" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:78 -#, fuzzy msgid "General" -msgstr "间隔" +msgstr "一般" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:34 msgid "Geo" -msgstr "" +msgstr "地理位置" #: superset-frontend/src/explore/components/controls/SpatialControl.jsx:203 msgid "Geohash" @@ -6050,35 +5833,32 @@ msgstr "获取指定节假日的日期" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:47 msgid "Google Sheet Name and URL" -msgstr "" +msgstr "Google Sheet名称和URL" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1275 msgid "Grace period" msgstr "宽限期" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:37 -#, fuzzy msgid "Graph Chart" -msgstr "图表保存" +msgstr "圆点图" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:108 msgid "Graph layout" -msgstr "" +msgstr "图表布局" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:262 msgid "Gravity" -msgstr "" +msgstr "重力" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:299 #: superset-frontend/src/filters/components/GroupBy/index.ts:28 -#, fuzzy msgid "Group By" msgstr "分组" #: superset-frontend/src/filters/components/GroupBy/index.ts:29 -#, fuzzy msgid "Group By filter plugin" -msgstr "范围过滤器" +msgstr "分组过滤插件" #: superset/viz.py:895 msgid "Group By' and 'Columns' can't overlap" @@ -6086,7 +5866,7 @@ msgstr "“Group by”列和字段不能重叠" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:83 msgid "Group By, Metrics or Percentage Metrics must have a value" -msgstr "" +msgstr "分组、指标或百分比指标必须具有值" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:31 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:99 @@ -6158,26 +5938,24 @@ msgstr "水平图" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:106 msgid "Horizontal alignment" -msgstr "" +msgstr "水平对齐" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:47 -#, fuzzy msgid "Host" -msgstr "小时" +msgstr "主机" #: superset/db_engine_specs/base.py:1390 msgid "Hostname or IP address" -msgstr "" +msgstr "主机名或IP" #: superset/db_engine_specs/base.py:94 -#, fuzzy msgid "Hour" msgstr "小时" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:65 -#, fuzzy, python-format +#, python-format msgid "Hours %s" -msgstr "小时" +msgstr "%s小时" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:779 msgid "Hours offset" @@ -6185,7 +5963,7 @@ msgstr "小时偏移" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:94 msgid "How do you want to enter service account credentials?" -msgstr "" +msgstr "您希望如何输入服务帐户凭据?" #: superset/views/alerts.py:190 msgid "How long to keep the logs around for this alert" @@ -6193,14 +5971,13 @@ msgstr "这个警报的日志要保存多久" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:59 msgid "How many periods into the future do we want to predict" -msgstr "" +msgstr "想要预测未来的多少个时期" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:129 #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:342 #: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:225 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:477 #: superset-frontend/src/explore/controlPanels/sections.tsx:240 -#, fuzzy msgid "" "How to display time shifts: as individual lines; as the difference " "between the main time series and each time shift; as the percentage " @@ -6214,23 +5991,21 @@ msgstr "巨大" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:78 msgid "ISO 3166-2 Codes" -msgstr "" +msgstr "ISO 3166-2 代码" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:237 msgid "ISO 8601" -msgstr "" +msgstr "ISO 8601" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:50 -#, fuzzy msgid "Id" -msgstr "id:" +msgstr "Id" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:85 msgid "Id of root node of the tree." -msgstr "" +msgstr "树的根节点的ID。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:400 -#, fuzzy msgid "" "If Presto or Trino, all the queries in SQL Lab are going to be executed " "as the currently logged on user who must have permission to run them. If " @@ -6255,7 +6030,7 @@ msgstr "" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1201 msgid "If a metric is specified, sorting will be done based on the metric value" -msgstr "" +msgstr "如果指定了度量,则将根据该度量值进行排序" #: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:121 msgid "If activated you can use the " @@ -6280,22 +6055,21 @@ msgstr "如果表已存在,执行其中一个:舍弃(什么都不做), msgid "" "If you wish to specify a different target column than the original " "column, it can be entered here" -msgstr "" +msgstr "如果要指定与原始列不同的目标列,可以在此处输入" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:83 msgid "Ignore time" -msgstr "" +msgstr "忽略时间" #: superset-frontend/src/components/ReportModal/index.tsx:293 msgid "Image (PNG) embedded in email" -msgstr "" +msgstr "使用邮箱发送图片(PNG)" #: superset-frontend/src/utils/downloadAsImage.ts:63 msgid "Image download failed, please refresh and try again." -msgstr "" +msgstr "图片发送失败,请刷新或重试" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:395 -#, fuzzy msgid "Impersonate logged in user (Presto, Trino, Drill, Hive, and GSheets)" msgstr "模拟登录用户 (Presto, Trino, Drill & Hive)" @@ -6329,9 +6103,8 @@ msgid "Import chart failed for an unknown reason" msgstr "导入图表失败,原因未知" #: superset-frontend/src/views/CRUD/chart/ChartList.tsx:621 -#, fuzzy msgid "Import charts" -msgstr "没有图表" +msgstr "导入图表" #: superset/dashboards/commands/exceptions.py:82 msgid "Import dashboard failed for an unknown reason" @@ -6347,46 +6120,40 @@ msgid "Import database failed for an unknown reason" msgstr "导入数据库失败,原因未知" #: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:195 -#, fuzzy msgid "Import databases" -msgstr "编辑数据库" +msgstr "导入数据集" #: superset/datasets/commands/exceptions.py:181 msgid "Import dataset failed for an unknown reason" msgstr "因为未知的原因导入数据集失败" #: superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx:517 -#, fuzzy msgid "Import datasets" -msgstr "编辑数据集" +msgstr "导入数据集" #: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:190 -#, fuzzy msgid "Import queries" -msgstr "时间序列" +msgstr "导入查询" #: superset/queries/saved_queries/commands/exceptions.py:36 -#, fuzzy msgid "Import saved query failed for an unknown reason." -msgstr "导入图表失败,原因未知" +msgstr "由于未知原因,导入保存的查询失败。" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:64 msgid "" "Important! Select this if the table is not already sorted by entity id, " "else there is no guarantee that all events for each entity are returned." -msgstr "" +msgstr "很重要!如果表尚未按实体ID排序,则选择此项,否则无法保证返回每个实体的所有事件。" #: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:67 -#, fuzzy msgid "Include Series" -msgstr "时间序列" +msgstr "包含系列" #: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:70 msgid "Include series name as an axis" -msgstr "" +msgstr "包括系列名称作为轴" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:325 -#, fuzzy msgid "Include time" msgstr "包含时间" @@ -6397,7 +6164,7 @@ msgstr "不兼容的条件 (%d)" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:121 msgid "Incorrect Fields" -msgstr "" +msgstr "不正确的字段" #: superset/views/database/forms.py:162 superset/views/database/forms.py:315 msgid "Index Column" @@ -6428,7 +6195,7 @@ msgstr "圆环圈内部空洞的内径" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:232 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:235 msgid "Input field supports custom rotation. e.g. 30 for 30°" -msgstr "" +msgstr "输入字段支持自定义。例如,30代表30°" #: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:90 msgid "Instant filtering" @@ -6436,38 +6203,32 @@ msgstr "即时过滤" #: superset-frontend/src/addSlice/AddSliceContainer.tsx:293 msgid "Instructions to add a dataset are available in the Superset tutorial." -msgstr "" +msgstr "有关添加数据集的说明,请参阅教程。" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:34 #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:41 #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:36 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:38 -#, fuzzy msgid "Intensity" -msgstr "实体" +msgstr "强度" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:495 -#, fuzzy msgid "Interval End column" -msgstr "按列过滤" +msgstr "间隔结束列" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:286 -#, fuzzy msgid "Interval bounds" -msgstr "值边界" +msgstr "区间间隔" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:300 -#, fuzzy msgid "Interval colors" -msgstr "线性颜色方案" +msgstr "间隔颜色" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:477 -#, fuzzy msgid "Interval start column" -msgstr "线列" +msgstr "间隔开始列" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:280 -#, fuzzy msgid "Intervals" msgstr "间隔" @@ -6477,13 +6238,12 @@ msgstr "无效的JSON" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:107 msgid "Invalid Port Number" -msgstr "" +msgstr "无效端口号" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:113 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:117 -#, fuzzy msgid "Invalid account information" -msgstr "基本情况" +msgstr "无效账户信息" #: superset/databases/schemas.py:170 superset/exceptions.py:182 msgid "Invalid certificate" @@ -6515,7 +6275,7 @@ msgstr "" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:52 msgid "Invalid cron expression" -msgstr "cron表达式无效" +msgstr "无效cron表达式" #: superset/utils/pandas_postprocessing.py:578 #, python-format @@ -6552,9 +6312,8 @@ msgid "Invalid longitude/latitude" msgstr "无效的经度/纬度" #: superset/utils/core.py:1318 -#, fuzzy msgid "Invalid metric object" -msgstr "无效认证" +msgstr "无效的指标对象" #: superset/utils/pandas_postprocessing.py:184 #, python-format @@ -6567,9 +6326,9 @@ msgid "Invalid options for %(rolling_type)s: %(options)s" msgstr "%(rolling_type)s 的选项无效:%(options)s" #: superset/common/query_actions.py:192 -#, fuzzy, python-format +#, python-format msgid "Invalid result type: %(result_type)s" -msgstr "无效的滚动类型:%(type)s" +msgstr "无效的结果类型:%(result_type)s" #: superset/utils/pandas_postprocessing.py:408 #, python-format @@ -6590,9 +6349,8 @@ msgid "Is Hidden" msgstr "隐藏" #: superset/charts/filters.py:63 superset/dashboards/filters.py:168 -#, fuzzy msgid "Is certified" -msgstr "认证" +msgstr "已认证" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:285 msgid "Is dimension" @@ -6612,15 +6370,13 @@ msgid "Is temporal" msgstr "时间条件" #: superset-frontend/src/utils/getClientErrorObject.ts:112 -#, fuzzy msgid "Issue 1000 - The dataset is too large to query." -msgstr "Issue 1000 - 数据源太大,无法进行查询。" +msgstr "Issue 1000 - 数据集太大,无法进行查询。" #: superset-frontend/src/utils/getClientErrorObject.ts:118 msgid "Issue 1001 - The database is under an unusual load." msgstr "Issue 1001 - 数据库负载异常。" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:180 #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:125 #: superset-frontend/src/components/DatabaseSelector/index.tsx:183 msgid "It seems you don't have access to any database" @@ -6628,7 +6384,7 @@ msgstr "貌似您没有访问到任何数据库" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:221 msgid "It’s not recommended to truncate y-axis in Bar chart." -msgstr "" +msgstr "不建议截断柱状图中的y轴。" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:91 msgid "JAN" @@ -6649,13 +6405,12 @@ msgid "JSON metadata" msgstr "JSON 元数据" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:341 -#, fuzzy msgid "" "JSON string containing additional connection configuration. This is used " "to provide connection information for systems like Hive, Presto and " "BigQuery which do not conform to the username:password syntax normally " "used by SQLAlchemy." -msgstr "这用于为SQLAlchemy提供Hive、Presto和BigQuery等不符合 用户名:密码 的语法规范。" +msgstr "包含附加连接配置的JSON字符串。它用于为配置单元、Presto和BigQuery等系统提供连接信息,这些系统不符合SQLAlChemy通常使用的用户名:密码语法。" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:97 msgid "JUL" @@ -6673,7 +6428,7 @@ msgstr "一月" msgid "" "Json list of the column names that should be read. If not None, only " "these columns will be read from the file." -msgstr "" +msgstr "Json应读取的列名列表。如果不是“无”,则仅从文件中读取这些列" #: superset/views/database/forms.py:235 superset/views/database/forms.py:368 msgid "" @@ -6698,7 +6453,7 @@ msgstr "六月" #: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:47 #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:37 msgid "KPI" -msgstr "" +msgstr "指标" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx:56 msgid "Keep editing" @@ -6736,13 +6491,12 @@ msgid "Label for your query" msgstr "为您的查询设置标签" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:123 -#, fuzzy msgid "Label position" -msgstr "最新分区:" +msgstr "标签位置" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:198 msgid "Label threshold" -msgstr "" +msgstr "标签阈值" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:144 msgid "Labelling" @@ -6757,15 +6511,15 @@ msgstr "标签" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:90 msgid "Labels for the marker lines" -msgstr "" +msgstr "标记线的标签" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:70 msgid "Labels for the markers" -msgstr "" +msgstr "标记的标签" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:50 msgid "Labels for the ranges" -msgstr "" +msgstr "范围的标签" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:47 #: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:81 @@ -6793,7 +6547,7 @@ msgstr "上次更新 %s" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:149 #, python-format msgid "Last available value seen on %s" -msgstr "" +msgstr " %s 最后一个可用值" #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:180 #: superset-frontend/src/views/CRUD/chart/ChartList.tsx:317 @@ -6830,22 +6584,22 @@ msgstr "配置Layer" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:101 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:110 msgid "Layout" -msgstr "" +msgstr "布局" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:114 msgid "Layout type of graph" -msgstr "" +msgstr "图形的布局类型" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:123 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:246 msgid "Layout type of tree" -msgstr "" +msgstr "树的布局类型" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:81 msgid "" "Leaf nodes that represent fewer than this number of events will be " "initially hidden in the visualization" -msgstr "" +msgstr "表示少于此数量的事件的叶节点最初将隐藏在可视化中" #: superset-frontend/src/views/CRUD/chart/ChartList.tsx:567 #: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:541 @@ -6854,9 +6608,8 @@ msgstr "最远修改" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:111 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:306 -#, fuzzy msgid "Left" -msgstr "警报" +msgstr "左边" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:72 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:166 @@ -6883,12 +6636,11 @@ msgstr "左边距,以像素为单位,为轴标签留出更多空间" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:137 msgid "Left to Right" -msgstr "" +msgstr "从左到右" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:147 -#, fuzzy msgid "Left value" -msgstr "空值" +msgstr "左值" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:38 #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:30 @@ -6917,7 +6669,7 @@ msgstr "空值" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 #: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:32 msgid "Legacy" -msgstr "" +msgstr "遗产" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:154 #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:275 @@ -6934,11 +6686,11 @@ msgstr "图示类型" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:98 msgid "Lift percent precision" -msgstr "" +msgstr "提升百分比精度" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/index.js:30 msgid "Light mode" -msgstr "" +msgstr "光模式" #: superset-frontend/src/explore/components/RowCountLabel.jsx:45 msgid "Limit reached" @@ -6953,23 +6705,24 @@ msgid "" "Limiting rows may result in incomplete data and misleading charts. " "Consider filtering or grouping source/target names instead." msgstr "" +"限制行数可能导致不完整的数据和误导性的图表。" +"可以考虑过滤或分组源/目标名称。" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:335 #: superset-frontend/src/explore/controls.jsx:364 msgid "Limits the number of rows that get displayed." -msgstr "" +msgstr "限制显示的行数。" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:345 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:359 #: superset-frontend/src/explore/controls.jsx:374 -#, fuzzy msgid "" "Limits the number of series that get displayed. A joined subquery (or an " "extra phase where subqueries are not supported) is applied to limit the " "number of series that get fetched and rendered. This feature is useful " "when grouping by high cardinality column(s) though does increase the " "query complexity and cost." -msgstr "限制显示的时间序列的数量。应用子查询(或者不支持子查询)来限制获取和显示的时间序列的数量。在高基数维度(S)分组时,此特性是有用的。" +msgstr "限制显示的系列数。应用联接的子查询(或不支持子查询的额外阶段)来限制获取和呈现的序列数量。此功能在按高基数列分组时很有用,但会增加查询的复杂性和成本。" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:38 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:48 @@ -6979,9 +6732,8 @@ msgstr "限制显示的时间序列的数量。应用子查询(或者不支持 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:76 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:76 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:73 -#, fuzzy msgid "Line" -msgstr "我的编辑" +msgstr "行" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/index.js:38 #: superset-frontend/plugins/preset-chart-xy/src/Line/createMetadata.ts:26 @@ -7031,11 +6783,11 @@ msgstr "保存的查询列表" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:81 msgid "List of values to mark with lines" -msgstr "" +msgstr "要用行标记的值列表" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:61 msgid "List of values to mark with triangles" -msgstr "" +msgstr "要用三角形标记的值列表" #: superset-frontend/src/dashboard/components/CssEditor/index.jsx:108 msgid "Live CSS editor" @@ -7068,9 +6820,8 @@ msgid "Log Retentions (days)" msgstr "日志保留(天)" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:204 -#, fuzzy msgid "Log Scale" -msgstr "Y经度标度" +msgstr "日志规模" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1238 #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1243 @@ -7080,11 +6831,11 @@ msgstr "日志保留" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:383 msgid "Logarithmic scale on primary y-axis" -msgstr "" +msgstr "对数刻度在主y轴上" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:416 msgid "Logarithmic scale on secondary y-axis" -msgstr "" +msgstr "二次y轴上的对数刻度" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:380 #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:404 @@ -7102,7 +6853,7 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:250 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:253 msgid "Logarithmic y-axis" -msgstr "" +msgstr "对数轴" #: superset-frontend/src/components/Menu/MenuRight.tsx:233 #: superset/templates/appbuilder/navbar_right.html:126 @@ -7213,9 +6964,8 @@ msgstr "边距(margin)" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx:107 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:165 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:168 -#, fuzzy msgid "Marker" -msgstr "季度" +msgstr "标记" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:163 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/controlPanel.tsx:124 @@ -7224,33 +6974,32 @@ msgstr "季度" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:179 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:182 msgid "Marker Size" -msgstr "" +msgstr "标记大小" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:68 -#, fuzzy, python-format +#, python-format msgid "Marker labels" -msgstr "[警报] %(label)s" +msgstr "标记标签" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:88 msgid "Marker line labels" -msgstr "" +msgstr "标记线标签" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:79 msgid "Marker lines" -msgstr "" +msgstr "标记线" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:225 msgid "Marker size" -msgstr "" +msgstr "标记大小" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:59 -#, fuzzy msgid "Markers" -msgstr "季度" +msgstr "标记" #: superset-frontend/src/explore/controlPanels/Separator.js:32 msgid "Markup type" -msgstr "Markup 格式" +msgstr "Markup 类型" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:100 #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:48 @@ -7265,7 +7014,7 @@ msgstr "最大气泡的尺寸" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:129 msgid "Max Events" -msgstr "" +msgstr "最大事件数" #: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:257 msgid "Maximize chart" @@ -7273,7 +7022,7 @@ msgstr "最大化图表" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1266 msgid "Maximum" -msgstr "" +msgstr "最大" #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:68 msgid "Maximum Font Size" @@ -7281,7 +7030,7 @@ msgstr "最大字体大小" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:101 msgid "Maximum value on the gauge axis" -msgstr "" +msgstr "量规轴上的最大值" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:70 msgid "May" @@ -7289,26 +7038,25 @@ msgstr "五月" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:93 msgid "Mean of values over specified period" -msgstr "" +msgstr "特定时期内的平均值" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:230 msgid "" "Median edge width, the thickest edge will be 4 times thicker than the " "thinnest." -msgstr "" +msgstr "边缘宽度中间值,最厚的边缘将比最薄的边缘厚4倍" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:217 msgid "" "Median node size, the largest node will be 4 times larger than the " "smallest" -msgstr "" +msgstr "节点大小中位数,最大的节点将比最小的节点大4倍" #: superset-frontend/src/dashboard/util/headerStyleOptions.ts:30 msgid "Medium" msgstr "中" #: superset-frontend/src/components/ReportModal/index.tsx:275 -#, fuzzy msgid "Message Content" msgstr "消息内容" @@ -7317,9 +7065,8 @@ msgid "Message content" msgstr "消息内容" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:105 -#, fuzzy msgid "Metadata" -msgstr "JSON 元数据" +msgstr "元数据" #: superset/connectors/druid/views.py:240 msgid "Metadata Last Refreshed" @@ -7327,9 +7074,8 @@ msgstr "上次刷新的元数据" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:437 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:442 -#, fuzzy msgid "Metadata Parameters" -msgstr "模板参数" +msgstr "元数据参数" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:617 msgid "Metadata has been synced" @@ -7384,7 +7130,7 @@ msgstr "分配给 [Y] 轴的指标" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:103 msgid "Metric change in value from `since` to `until`" -msgstr "" +msgstr "从 `since` 到 `until` 的度量值变化" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:39 msgid "Metric descending" @@ -7392,16 +7138,15 @@ msgstr "指标降序" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:117 msgid "Metric factor change from `since` to `until`" -msgstr "" +msgstr "度量因子从 `since` 到 `until` 的变化" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:119 msgid "Metric for Color" msgstr "颜色指标" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:98 -#, fuzzy msgid "Metric for node values" -msgstr "颜色指标" +msgstr "节点值的度量" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:658 #, python-format @@ -7410,7 +7155,7 @@ msgstr "指标名称 [%s] 重复" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:110 msgid "Metric percent change in value from `since` to `until`" -msgstr "" +msgstr "从 `since` 到 `until` 的价值变化百分比" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:120 msgid "Metric that defines the color of the country" @@ -7421,9 +7166,8 @@ msgid "Metric that defines the size of the bubble" msgstr "定义指标的气泡大小" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:85 -#, fuzzy msgid "Metric to display bottom title" -msgstr "选择一个指标来显示" +msgstr "显示底部标题的度量值" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:185 msgid "Metric to sort the results by" @@ -7432,7 +7176,7 @@ msgstr "按照指标的结果进行排序" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:142 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:421 msgid "Metric used to calculate bubble size" -msgstr "" +msgstr "用来计算气泡大小的公制" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:127 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:371 @@ -7441,7 +7185,7 @@ msgid "" "Metric used to define how the top series are sorted if a series or row " "limit is present. If undefined reverts to the first metric (where " "appropriate)." -msgstr "" +msgstr "如果存在序列或行限制,则用于定义顶部序列的排序方式的度量。如果未定义,则返回第一个度量(如果适用)。" #: superset/connectors/druid/models.py:1072 msgid "Metric(s) {} must be aggregations." @@ -7457,11 +7201,10 @@ msgid "Metrics" msgstr "指标" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:148 -#, fuzzy msgid "" "Metrics for which percentage of total are to be displayed. Calculated " "from only data within the row limit." -msgstr "要显示总数百分比的度量" +msgstr "要显示其占总数百分比的指标。只计算行限制内的只读存储器数据。" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:93 msgid "Midnight" @@ -7480,9 +7223,8 @@ msgid "Min Periods" msgstr "最小周期" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:90 -#, fuzzy msgid "Min Width" -msgstr "线宽" +msgstr "最小宽度" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:73 #: superset-frontend/src/explore/controlPanels/sections.tsx:189 @@ -7500,9 +7242,8 @@ msgid "Minimize chart" msgstr "最小化图表" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1260 -#, fuzzy msgid "Minimum" -msgstr "分" +msgstr "最小" #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:57 msgid "Minimum Font Size" @@ -7510,19 +7251,19 @@ msgstr "最小字体大小" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:78 msgid "Minimum leaf node event count" -msgstr "" +msgstr "节点最小事件数" #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:85 msgid "Minimum threshold in percentage points for showing labels." -msgstr "" +msgstr "标签显示百分比最小阈值" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:202 msgid "Minimum value for label to be displayed on graph." -msgstr "" +msgstr "在图形上显示标签的最小值。" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:89 msgid "Minimum value on the gauge axis" -msgstr "" +msgstr "量规轴上的最小值" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:328 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:243 @@ -7532,22 +7273,20 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:259 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:262 msgid "Minor Split Line" -msgstr "" +msgstr "小的分模线" #: superset/db_engine_specs/base.py:89 -#, fuzzy msgid "Minute" -msgstr "分" +msgstr "分钟" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:64 -#, fuzzy, python-format +#, python-format msgid "Minutes %s" -msgstr "分钟" +msgstr "%s分钟" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:93 -#, fuzzy msgid "Missing Required Fields" -msgstr "需要名称" +msgstr "缺少必填字段" #: superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.tsx:34 #: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:251 @@ -7555,9 +7294,8 @@ msgid "Missing dataset" msgstr "丢失数据集" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:67 -#, fuzzy msgid "Mixed Time-Series" -msgstr "时间序列" +msgstr "混和时间序列" #: superset-frontend/src/dashboard/components/AddSliceCard.jsx:128 #: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:312 @@ -7573,7 +7311,7 @@ msgstr "已修改" #: superset-frontend/src/views/CRUD/chart/ChartCard.tsx:155 #: superset-frontend/src/views/CRUD/dashboard/DashboardCard.tsx:164 #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:130 -#, fuzzy, python-format +#, python-format msgid "Modified %s" msgstr "最后修改 %s" @@ -7593,14 +7331,14 @@ msgid "Monday" msgstr "星期一" #: superset/db_engine_specs/base.py:98 -#, fuzzy +# msgid "Month" msgstr "月" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:68 -#, fuzzy, python-format +#, python-format msgid "Months %s" -msgstr "月" +msgstr "%s月" #: superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx:238 msgid "More dataset related options" @@ -7609,7 +7347,7 @@ msgstr "更多数据集相关选项" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:167 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:276 msgid "Move only" -msgstr "" +msgstr "移动" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:43 msgid "Moves the given set of dates by a specified interval." @@ -7617,23 +7355,21 @@ msgstr "将给定的日期集以指定的间隔进行移动" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:40 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:32 -#, fuzzy msgid "Multi-Dimensions" -msgstr "选择一个维度" +msgstr "多维度" #: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:34 #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:41 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:37 -#, fuzzy msgid "Multi-Layers" -msgstr "乘数" +msgstr "多层" #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:33 #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:44 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:43 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:62 msgid "Multi-Levels" -msgstr "" +msgstr "多层次" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:42 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:32 @@ -7642,12 +7378,11 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:58 #: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:30 msgid "Multi-Variables" -msgstr "" +msgstr "多元" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:187 -#, fuzzy msgid "Multiple" -msgstr "乘数" +msgstr "多方" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:30 msgid "Multiple Line Charts" @@ -7658,6 +7393,8 @@ msgid "" "Multiple file extensions are not allowed for columnar uploads. Please " "make sure all files are of the same extension." msgstr "" +"柱状上传不允许使用多个文件扩展名" +"请确保所有文件的扩展名相同。" #: superset-frontend/src/explore/components/controls/SpatialControl.jsx:185 msgid "" @@ -7667,9 +7404,8 @@ msgstr "接受多种格式,查看geopy.points库以获取更多细节" #: superset-frontend/src/filters/components/GroupBy/controlPanel.ts:59 #: superset-frontend/src/filters/components/Select/controlPanel.ts:77 -#, fuzzy msgid "Multiple select" -msgstr "允许多选" +msgstr "多选" #: superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx:218 msgid "Multiple selections allowed, otherwise filter is limited to a single value" @@ -7689,13 +7425,12 @@ msgstr "必须至少指明一个数值列" #: superset/connectors/sqla/models.py:1303 msgid "Must specify a value for filters with comparison operators" -msgstr "" +msgstr "必须为带有比较操作符的过滤器指定一个值吗" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx:47 #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.jsx:59 -#, fuzzy msgid "My column" -msgstr "列" +msgstr "我的列" #: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.jsx:73 msgid "My metric" @@ -7703,7 +7438,7 @@ msgstr "我的指标" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:76 msgid "N/A" -msgstr "" +msgstr "N/A" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:101 msgid "NOV" @@ -7739,9 +7474,8 @@ msgid "Name must be unique" msgstr "名称必须是唯一的" #: superset/views/database/forms.py:380 -#, fuzzy msgid "Name of table to be created from columnar data." -msgstr "从excel数据将创建的表的名称。" +msgstr "从列存储数据创建的表的名称。" #: superset/views/database/forms.py:96 msgid "Name of table to be created from csv data." @@ -7753,30 +7487,27 @@ msgstr "从excel数据将创建的表的名称。" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:61 msgid "Name of the column containing the id of the parent node" -msgstr "" +msgstr "包含父节点id的列的名称" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:51 -#, fuzzy msgid "Name of the id column" -msgstr "时间序列的列" +msgstr "ID列名称" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:53 msgid "Name of the source nodes" -msgstr "" +msgstr "源节点名称" #: superset/connectors/sqla/views.py:439 msgid "Name of the table that exists in the source database" -msgstr "源数据库中存在的表的名称" +msgstr "源数据库中存在的表名称" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:63 -#, fuzzy msgid "Name of the target nodes" -msgstr "数据集的所有者" +msgstr "目标节点名称" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:51 -#, fuzzy msgid "Name your database" -msgstr "命名数据集" +msgstr "您的数据集" #: superset-frontend/src/chart/chartReducer.ts:106 #: superset-frontend/src/chart/chartReducer.ts:170 @@ -7789,7 +7520,7 @@ msgstr "新增" #: superset-frontend/src/components/ReportModal/index.tsx:251 msgid "New Email Report" -msgstr "" +msgstr "新的电子邮件报告" #: superset-frontend/src/explore/components/ExploreAdditionalActionsMenu/index.jsx:61 msgid "New chart" @@ -7801,18 +7532,16 @@ msgid "New columns added: %s" msgstr "新增的列:%s" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx:81 -#, fuzzy msgid "New filter set" -msgstr "配置过滤范围" +msgstr "新的过滤器" #: superset-frontend/src/SqlLab/components/SqlEditor/index.jsx:327 msgid "New tab" msgstr "关闭标签" #: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:420 -#, fuzzy msgid "New tab (Ctrl + q)" -msgstr "新建Tab页 (Ctrl + t)" +msgstr "新建Tab页 (Ctrl + q)" #: superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.jsx:421 msgid "New tab (Ctrl + t)" @@ -7837,7 +7566,7 @@ msgstr "否" #: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:74 #, python-format msgid "No %(tableName)s yet" -msgstr "" +msgstr "还没有 %(tableName)s" #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:376 #, python-format @@ -7849,7 +7578,6 @@ msgid "No Access!" msgstr "不能访问!" #: superset-frontend/src/components/ListView/ListView.tsx:398 -#, fuzzy msgid "No Data" msgstr "没有数据" @@ -7870,14 +7598,13 @@ msgid "No charts" msgstr "没有图表" #: superset-frontend/src/filters/components/GroupBy/GroupByFilterPlugin.tsx:82 -#, fuzzy msgid "No columns" -msgstr "列" +msgstr "没有列" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:134 -#, fuzzy, python-format +#, python-format msgid "No compatible columns found" -msgstr "不兼容的条件 (%d)" +msgstr "找不到兼容的列" #: superset-frontend/src/profile/components/CreatedContent.tsx:63 msgid "No dashboards" @@ -7892,16 +7619,15 @@ msgstr "没有数据" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:219 msgid "No data after filtering or data is NULL for the latest time record" -msgstr "" +msgstr "过滤后没有数据,或者最新时间记录的数据为NULL" #: superset/dashboards/commands/importers/v0.py:321 msgid "No data in file" msgstr "文件中无数据" #: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:752 -#, fuzzy msgid "No description available." -msgstr "描述" +msgstr "没有可用的描述" #: superset-frontend/src/profile/components/Favorites.tsx:46 msgid "No favorite charts yet, go click on stars!" @@ -7954,24 +7680,20 @@ msgid "No such column found. To filter on a metric, try the Custom SQL tab." msgstr "没有发现这样的列。若要在度量值上筛选,请尝试自定义SQL选项卡。" #: superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx:81 -#, fuzzy msgid "No time columns" -msgstr "时间列" +msgstr "没有时间列" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:155 -#, fuzzy msgid "Node label position" -msgstr "忽略空位置" +msgstr "节点标签位置" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:182 -#, fuzzy msgid "Node select mode" -msgstr "运行选定的查询" +msgstr "节点选择模式" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:213 -#, fuzzy msgid "Node size" -msgstr "气泡尺寸" +msgstr "节点大小" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:41 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:242 @@ -7983,11 +7705,11 @@ msgstr "空" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:129 msgid "None -> Arrow" -msgstr "" +msgstr "无-> 箭头" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:128 msgid "None -> None" -msgstr "" +msgstr "无->无" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:43 #: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:77 @@ -8004,9 +7726,8 @@ msgid "Normalized" msgstr "标准化" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:81 -#, fuzzy msgid "Not Time Series" -msgstr "时间序列" +msgstr "美誉时间序列" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:116 msgid "Not null" @@ -8018,7 +7739,7 @@ msgstr "没有触发" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:152 msgid "Not up to date" -msgstr "" +msgstr "不是最新的" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:87 #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:97 @@ -8070,15 +7791,15 @@ msgstr "数字格式化" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:81 msgid "Number of decimal digits to round numbers to" -msgstr "" +msgstr "要四舍五入的十进制位数" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:100 msgid "Number of decimal places with which to display lift values" -msgstr "" +msgstr "用于显示升力值的小数位数" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:87 msgid "Number of decimal places with which to display p-values" -msgstr "" +msgstr "用于显示p值的小数位数" #: superset/views/database/forms.py:194 superset/views/database/forms.py:335 msgid "Number of rows of file to read." @@ -8090,7 +7811,7 @@ msgstr "在文件开始时跳过的行数。" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:231 msgid "Number of split segments on the axis" -msgstr "" +msgstr "轴上分割段的数目" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:119 msgid "Number of steps to take between ticks when displaying the X scale" @@ -8101,9 +7822,8 @@ msgid "Number of steps to take between ticks when displaying the Y scale" msgstr "显示 Y 刻度时,在刻度之间表示的步骤数" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:295 -#, fuzzy msgid "Numerical range" -msgstr "时间范围" +msgstr "数值范围" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:100 msgid "OCT" @@ -8147,14 +7867,14 @@ msgid "" "One or many columns to group by. High cardinality groupings should " "include a series limit to limit the number of fetched and rendered " "series." -msgstr "" +msgstr "要分组的一列或多列。高基数分组应包括序列限制,以限制提取和呈现的序列数。" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:105 msgid "" "One or many columns to group by. High cardinality groupings should " "include a sort by metric and series limit to limit the number of fetched " "and rendered series." -msgstr "" +msgstr "要分组的一列或多列。高基数分组应包括按度量排序和序列限制,以限制提取和呈现的序列数。" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:56 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:215 @@ -8202,39 +7922,34 @@ msgid "One or more metrics do not exist" msgstr "一个或多个指标不存在" #: superset/errors.py:113 -#, fuzzy msgid "One or more parameters needed to configure a database are missing." -msgstr "Issue 1006 - 查询中指定的一个或多个参数丢失。" +msgstr "数据库配置缺少所需的一个或多个参数。" #: superset/errors.py:127 -#, fuzzy msgid "One or more parameters specified in the query are malformatted." -msgstr "Issue 1006 - 查询中指定的一个或多个参数丢失。" +msgstr "查询中指定的一个或多个参数的格式不正确。" #: superset/errors.py:101 -#, fuzzy msgid "One or more parameters specified in the query are missing." -msgstr "Issue 1006 - 查询中指定的一个或多个参数丢失。" +msgstr "查询中指定的一个或多个参数丢失。" #: superset/views/core.py:2075 msgid "" "One or more required fields are missing in the request. Please try again," " and if the problem persists conctact your administrator." -msgstr "" +msgstr "请求中缺少一个或多个必填字段。请重试,如果问题仍然存在,请与管理员联系。" #: superset-frontend/src/dashboard/components/SliceHeader/index.tsx:46 msgid "One ore more annotation layers failed loading." msgstr "一个或多个注释层加载失败。" #: superset/sql_lab.py:201 -#, fuzzy msgid "Only SELECT statements are allowed against this database." msgstr "此数据库只允许使用 `SELECT` 语句" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:128 -#, fuzzy msgid "Only Total" -msgstr "显示总计" +msgstr "仅总计" #: superset/connectors/sqla/utils.py:96 msgid "Only `SELECT` statements are allowed" @@ -8248,7 +7963,7 @@ msgstr "只有选定的面板将受此过滤条件的影响" msgid "" "Only show the total value on the stacked chart, and not show on the " "selected category" -msgstr "" +msgstr "仅在堆积图上显示合计值,而不在所选类别上显示" #: superset/connectors/sqla/utils.py:105 msgid "Only single queries supported" @@ -8270,7 +7985,7 @@ msgstr "不透明度" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:152 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:155 msgid "Opacity of Area Chart. Also applies to confidence band." -msgstr "" +msgstr "区域图的不透明度。也适用于置信带" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:239 msgid "Opacity of all clusters, points, and labels. Between 0 and 1." @@ -8278,7 +7993,7 @@ msgstr "所有簇、点和标签的不透明度。在0到1之间。" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:202 msgid "Opacity of area chart." -msgstr "" +msgstr "面积图的不透明度" #: superset-frontend/src/explore/components/ExploreViewContainer.jsx:550 msgid "Open Datasource tab" @@ -8315,9 +8030,9 @@ msgstr "" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:125 #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:130 -#, fuzzy, python-format +#, python-format msgid "Operator" -msgstr "%s 运算符" +msgstr "运算符" #: superset/utils/pandas_postprocessing.py:175 #, python-format @@ -8332,17 +8047,17 @@ msgstr "用于验证HTTPS请求的可选 CA_BUNDLE 内容。仅在某些数据 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:73 msgid "Optional name of the data column." -msgstr "" +msgstr "数据列的可选名称" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1135 msgid "" "Optional time column if time range should apply to another column than " "the default time column" -msgstr "" +msgstr "如果时间范围应应用于默认时间列以外的其他列,则可选时间列" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1092 msgid "Optional warning about use of this metric" -msgstr "" +msgstr "关于使用此指标的可选警告" # 以下部分来源于 superset-ui 项目 #: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:49 @@ -8360,24 +8075,23 @@ msgstr "设置" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:668 msgid "Or choose from a list of other databases we support:" -msgstr "" +msgstr "或者从我们支持的其他数据库列表中选择:" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:63 msgid "Order by entity id" -msgstr "" +msgstr "按实体ID排序" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:272 msgid "Order results by selected columns" -msgstr "" +msgstr "按选定列对结果进行排序" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:271 msgid "Ordering" msgstr "排序" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:142 -#, fuzzy msgid "Orientation of tree" -msgstr "方向" +msgstr "树的方向" #: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:27 #: superset-frontend/src/explore/constants.ts:116 @@ -8385,7 +8099,6 @@ msgid "Origin" msgstr "起点" #: superset-frontend/src/explore/components/ExportToCSVDropdown/index.tsx:74 -#, fuzzy msgid "Original" msgstr "起点" @@ -8396,17 +8109,16 @@ msgstr "原始表列顺序" #: superset-frontend/packages/superset-ui-chart-controls/src/utils/D3Formatting.ts:29 #: superset/db_engine_specs/base.py:85 msgid "Original value" -msgstr "" +msgstr "原始值" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:120 msgid "Orthogonal" -msgstr "" +msgstr "正交化" #: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:120 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:687 -#, fuzzy msgid "Other" -msgstr "月" +msgstr "其他" #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:193 msgid "Outer Radius" @@ -8417,9 +8129,8 @@ msgid "Outer edge of Pie chart" msgstr "饼图外缘" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:257 -#, fuzzy msgid "Overlap" -msgstr "世界地图" +msgstr "重叠" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:107 #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:322 @@ -8489,9 +8200,8 @@ msgid "" msgstr "所有者是可以更改看板的用户列表。可按名称或用户名搜索。" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:388 -#, fuzzy msgid "Page length" -msgstr "页面长度" +msgstr "页长" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:29 msgid "Paired t-test Table" @@ -8528,14 +8238,12 @@ msgid "Parameters" msgstr "参数" #: superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx:103 -#, fuzzy msgid "Parameters " msgstr "参数" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:60 -#, fuzzy msgid "Parent" -msgstr "透明" +msgstr "父类" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:643 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1037 @@ -8543,9 +8251,8 @@ msgid "Parent filter" msgstr "父级过滤" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1045 -#, fuzzy msgid "Parent filter is required" -msgstr "类型是必需的" +msgstr "需要父筛选器" #: superset/views/database/forms.py:203 superset/views/database/forms.py:340 msgid "Parse Dates" @@ -8558,7 +8265,7 @@ msgstr "解析日期" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:33 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:50 msgid "Part of a Whole" -msgstr "" +msgstr "占比" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/index.js:27 msgid "Partition Chart" @@ -8569,53 +8276,46 @@ msgid "Partition Diagram" msgstr "分区图" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:176 -#, fuzzy msgid "Partition Limit" -msgstr "分区图" +msgstr "分区限制" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:189 -#, fuzzy msgid "Partition Threshold" -msgstr "分区图" +msgstr "分区阈值" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:192 msgid "" "Partitions whose height to parent height proportions are below this value" " are pruned" -msgstr "" +msgstr "高度与父高度的比例低于此值的分区将被修剪" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:130 #: superset/db_engine_specs/base.py:1389 -#, fuzzy msgid "Password" -msgstr "Broker的密码" +msgstr "密码" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx:79 msgid "Paste the shareable Google Sheet URL here" -msgstr "" +msgstr "将可共享的Google Sheet URL粘贴到此处" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:35 #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 #: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:35 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:46 -#, fuzzy msgid "Pattern" -msgstr "更新" +msgstr "规则" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:108 -#, fuzzy msgid "Percent Change" -msgstr "显示百分比" +msgstr "百分比变化" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:147 -#, fuzzy msgid "Percentage metrics" -msgstr "百分比度量" +msgstr "百分比指标" #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx:81 -#, fuzzy msgid "Percentage threshold" -msgstr "百分比度量" +msgstr "百分比阈值" #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:41 #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:45 @@ -8628,9 +8328,8 @@ msgstr "百分比度量" #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:69 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:63 #: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:33 -#, fuzzy msgid "Percentages" -msgstr "显示百分比" +msgstr "百分比" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:56 #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:278 @@ -8646,14 +8345,12 @@ msgid "Periods must be a positive integer value" msgstr "句点必须是正整数值" #: superset-frontend/src/explore/components/PropertiesModal/index.tsx:258 -#, fuzzy msgid "Person or group that has certified this chart." -msgstr "认证此指标的个人或团体" +msgstr "对此图表进行认证的个人或团体。" #: superset-frontend/src/dashboard/components/PropertiesModal/index.jsx:548 -#, fuzzy msgid "Person or group that has certified this dashboard." -msgstr "认证此指标的个人或团体" +msgstr "已对此仪表板进行认证的个人或组。" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:260 #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1068 @@ -8698,11 +8395,11 @@ msgstr "选择一个指标!" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:56 msgid "Pick a name to help you identify this database." -msgstr "" +msgstr "选择一个名称来帮助您识别这个数据库。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:151 msgid "Pick a nickname for this database to display as in Superset." -msgstr "" +msgstr "为这个数据库选择一个昵称以在Superset中显示" #: superset/viz.py:1358 superset/viz.py:1621 msgid "Pick a time granularity for your time series" @@ -8710,7 +8407,7 @@ msgstr "为您的时间序列选择一个时间粒度" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:510 msgid "Pick a title for you annotation." -msgstr "" +msgstr "为您的注释选择一个标题" #: superset/viz.py:1783 msgid "Pick at least one field for [Series]" @@ -8729,6 +8426,8 @@ msgid "" "Pick one or more columns that should be shown in the annotation. If you " "don't select a column all of them will be shown." msgstr "" +"选择注释中应该显示的一个或多个列" +"如果您不选择一列,所有的选项都会显示出来。" #: superset-frontend/src/explore/controlPanels/Separator.js:37 msgid "Pick your favorite markup language" @@ -8744,9 +8443,8 @@ msgid "Pie shape" msgstr "饼图形状" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:234 -#, fuzzy msgid "Pin" -msgstr "最小值" +msgstr "Pin" #: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:56 msgid "Pivot Options" @@ -8758,9 +8456,8 @@ msgid "Pivot Table" msgstr "透视表" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:54 -#, fuzzy msgid "Pivot Table v2" -msgstr "透视表" +msgstr "透视表 v2" #: superset/utils/pandas_postprocessing.py:260 msgid "Pivot operation must include at least one aggregate" @@ -8771,9 +8468,8 @@ msgid "Pivot operation requires at least one index" msgstr "透视操作至少需要一个索引" #: superset-frontend/src/explore/components/ExportToCSVDropdown/index.tsx:80 -#, fuzzy msgid "Pivoted" -msgstr "已编辑" +msgstr "旋转" #: superset-frontend/plugins/legacy-plugin-chart-horizon/src/controlPanel.ts:83 msgid "Pixel height of each series" @@ -8781,14 +8477,14 @@ msgstr "每个序列的像素高度" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:28 msgid "Please apply filter changes" -msgstr "" +msgstr "请应用滤镜更改" #: superset/sqllab/query_render.py:116 msgid "" "Please check your query and confirm that all template parameters are " "surround by double braces, for example, \"{{ ds }}\". Then, try running " "your query again." -msgstr "" +msgstr "请检查查询并确认所有模板参数都用双大括号括起来,例如 \"{{ ds }}\"。然后,再次尝试运行查询" #: superset/db_engine_specs/athena.py:55 #: superset/db_engine_specs/bigquery.py:179 @@ -8798,14 +8494,14 @@ msgstr "" msgid "" "Please check your query for syntax errors at or near " "\"%(syntax_error)s\". Then, try running your query again." -msgstr "" +msgstr "请检查查询中 \"%(syntax_error)s\" 处或附近的语法错误。然后,再次尝试运行查询。“" #: superset/db_engine_specs/gsheets.py:74 superset/db_engine_specs/mysql.py:144 #, python-format msgid "" "Please check your query for syntax errors near \"%(server_error)s\". " "Then, try running your query again." -msgstr "" +msgstr "请检查查询中\"%(server_error)s\"附近的语法错误然后,再次尝试运行查询" #: superset/viz.py:879 msgid "Please choose at least one 'Group by' field " @@ -8821,7 +8517,7 @@ msgstr "请在左右轴上选择不同的指标" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:94 msgid "Please complete all required fields." -msgstr "" +msgstr "请填写所有必填项" #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:485 #: superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx:300 @@ -8847,17 +8543,16 @@ msgid "Please enter a chart name" msgstr "请输入图表名称" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx:81 -#, fuzzy msgid "Please filter set name" -msgstr "请输入图表名称" +msgstr "请筛选集合名称" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:122 msgid "Please make sure all fields are filled out correctly" -msgstr "" +msgstr "请确保所有字段填写正确" #: superset/db_engine_specs/postgres.py:122 msgid "Please re-enter the password." -msgstr "" +msgstr "请重新输入密码。" #: superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx:59 #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:72 @@ -8870,15 +8565,15 @@ msgstr "请保存查询以启用共享" #: superset/reports/commands/exceptions.py:90 msgid "Please save your chart first, then try creating a new email report." -msgstr "" +msgstr "请先保存您的图表,然后尝试创建一个新的电子邮件报告。" #: superset/reports/commands/exceptions.py:102 msgid "Please save your dashboard first, then try creating a new email report." -msgstr "" +msgstr "请先保存您的仪表盘,然后尝试创建一个新的电子邮件报告。" #: superset-frontend/src/addSlice/AddSliceContainer.tsx:322 msgid "Please select both a Dataset and a Chart type to proceed" -msgstr "" +msgstr "请同时选择数据集和图表类型以继续" #: superset/viz.py:1161 msgid "Please use 3 different metric labels" @@ -8886,14 +8581,14 @@ msgstr "请在左右轴上选择不同的指标" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:104 msgid "Please verify that port is open to connect." -msgstr "" +msgstr "请检查端口是否打开以进行连接" #: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:27 msgid "" "Plots the individual metrics for each row in the data vertically and " "links them together as a line. This chart is useful for comparing " "multiple metrics across all of the samples or rows in the data." -msgstr "" +msgstr "垂直地绘制数据中每一行的单个指标,并将它们链接成一行。此图表用于比较数据中所有样本或行中的多个指标。" #: superset/initialization/__init__.py:254 msgid "Plugins" @@ -8912,7 +8607,6 @@ msgid "Points" msgstr "点配置" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:201 -#, fuzzy msgid "Points and clusters will update as the viewport is being changed" msgstr "点和簇将随着视图改变而更新。" @@ -8933,15 +8627,15 @@ msgstr "流行标签链接" #: superset-frontend/plugins/plugin-chart-table/src/index.ts:47 #: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:124 msgid "Popular" -msgstr "" +msgstr "常用" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx:170 msgid "Populate \"Default value\" to enable this control" -msgstr "" +msgstr "填充 \"Default value\" 以启用此控件" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:33 msgid "Population age data" -msgstr "" +msgstr "人口年龄数据" #: superset/db_engine_specs/mssql.py:87 #: superset/db_engine_specs/postgres.py:132 @@ -8949,12 +8643,11 @@ msgstr "" #: superset/db_engine_specs/redshift.py:73 #, python-format msgid "Port %(port)s on hostname \"%(hostname)s\" refused the connection." -msgstr "" +msgstr "主机名 \"%(hostname)s\" 上的端口 %(port)s 拒绝连接。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:103 -#, fuzzy msgid "Port is closed" -msgstr "报告失败" +msgstr "端口已关闭" #: superset/views/dashboard/mixin.py:87 msgid "Position JSON" @@ -8962,37 +8655,35 @@ msgstr "位置JSON" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:181 msgid "Position of child node label on tree" -msgstr "" +msgstr "子节点标签在树上的位置" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:310 msgid "Position of column level subtotal" -msgstr "" +msgstr "列级小计的位置" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:163 msgid "Position of intermidiate node label on tree" -msgstr "" +msgstr "中间节点标签在树中的位置" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:293 msgid "Position of row level subtotal" -msgstr "" +msgstr "行级小计的位置" #: superset-frontend/src/components/Menu/MenuRight.tsx:180 msgid "Powered by Apache Superset" -msgstr "" +msgstr "由Apache Superset提供支持" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1096 -#, fuzzy msgid "Pre-filter" -msgstr "父级过滤" +msgstr "预过滤" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1061 msgid "Pre-filter available values" -msgstr "" +msgstr "预滤器可用值" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:623 -#, fuzzy msgid "Pre-filter is required" -msgstr "类型是必需的" +msgstr "预过滤是必须的" #: superset/connectors/sqla/views.py:451 msgid "" @@ -9011,14 +8702,12 @@ msgstr "当获取不同的值来填充过滤器组件应用时。支持jinja的 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:72 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:63 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:74 -#, fuzzy msgid "Predictive" -msgstr "激活" +msgstr "预测" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:36 -#, fuzzy msgid "Predictive Analytics" -msgstr "高级分析" +msgstr "预测分析" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:64 msgid "Prefix metric name with slice name" @@ -9040,9 +8729,8 @@ msgid "Previous" msgstr "之前" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:243 -#, fuzzy msgid "Primary" -msgstr "星期五" +msgstr "主键" #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:56 msgid "Primary Metric" @@ -9050,11 +8738,11 @@ msgstr "主计量指标" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:248 msgid "Primary or secondary y-axis" -msgstr "" +msgstr "主或次y轴" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:371 msgid "Primary y-axis format" -msgstr "" +msgstr "主轴格式" #: superset-frontend/src/components/Menu/MenuRight.tsx:161 #: superset/templates/appbuilder/navbar_right.html:109 @@ -9066,13 +8754,11 @@ msgid "Profile picture provided by Gravatar" msgstr "资料图片由 Gravatar 提供" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:239 -#, fuzzy msgid "Progress" msgstr "进度" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/index.ts:30 #: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:56 -#, fuzzy msgid "Progressive" msgstr "进度" @@ -9090,15 +8776,15 @@ msgstr "传播" #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:71 #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:64 msgid "Proportional" -msgstr "" +msgstr "比例" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:86 msgid "Public and privately shared sheets" -msgstr "" +msgstr "公共和私人共享的表" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:83 msgid "Publicly shared sheets only" -msgstr "" +msgstr "仅公开共享表" #: superset-frontend/src/dashboard/components/PublishedStatus/index.jsx:101 #: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:301 @@ -9117,7 +8803,6 @@ msgid "Put the labels outside of the pie?" msgstr "是否将标签显示在饼图外侧?" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Pie/controlPanel.ts:112 -#, fuzzy msgid "Put the labels outside the pie?" msgstr "是否将标签显示在饼图外侧?" @@ -9140,14 +8825,13 @@ msgid "Python functions" msgstr "Python函数" #: superset/db_engine_specs/base.py:99 -#, fuzzy msgid "Quarter" msgstr "季度" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:69 -#, fuzzy, python-format +#, python-format msgid "Quarters %s" -msgstr "季度" +msgstr " %s 季度" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:32 #: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:26 @@ -9209,19 +8893,17 @@ msgstr "查询" #: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:253 #, python-format msgid "Query %s: %s" -msgstr "" +msgstr "查询 : %s " #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:258 #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:283 -#, fuzzy msgid "Query A" -msgstr "查询" +msgstr "查询 A" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:259 #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:284 -#, fuzzy msgid "Query B" -msgstr "查询" +msgstr "查询 B" #: superset/initialization/__init__.py:341 msgid "Query History" @@ -9239,10 +8921,9 @@ msgstr "在新标签中查询" #: superset/errors.py:125 msgid "Query is too complex and takes too long to run." -msgstr "" +msgstr "查询太复杂,运行时间太长。" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:89 -#, fuzzy msgid "Query mode" msgstr "查询模式" @@ -9256,12 +8937,7 @@ msgstr "查询名称" msgid "Query preview" msgstr "查询预览" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:213 -msgid "Query search string" -msgstr "查询搜索字符串" - #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:682 -#, fuzzy msgid "Query was stopped" msgstr "查询被终止。" @@ -9275,9 +8951,8 @@ msgid "RANGE TYPE" msgstr "范围类型" #: superset-frontend/src/components/ReportModal/index.tsx:327 -#, fuzzy msgid "REPORT NAME ERROR" -msgstr "报告名称" +msgstr "报告名称错误" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:251 msgid "RGB Color" @@ -9285,84 +8960,75 @@ msgstr "RGB颜色" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:161 msgid "Radar" -msgstr "" +msgstr "雷达" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:53 -#, fuzzy msgid "Radar Chart" -msgstr "共享图表" +msgstr "雷达图" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:201 msgid "Radar render type, whether to display 'circle' shape." -msgstr "" +msgstr "雷达渲染类型,是否显示圆形" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:121 -#, fuzzy msgid "Radial" -msgstr "空间" +msgstr "径向" #: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:318 -#, fuzzy, python-format +#, python-format msgid "Ran %s" msgstr "持续时间:%s" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:35 #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:38 #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 -#, fuzzy msgid "Range" -msgstr "管理" +msgstr "范围" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:295 #: superset-frontend/src/filters/components/Range/index.ts:28 -#, fuzzy msgid "Range filter" -msgstr "日期过滤器" +msgstr "范围过滤" #: superset-frontend/src/filters/components/Range/index.ts:29 -#, fuzzy msgid "Range filter plugin using AntD" msgstr "范围过滤器" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:48 msgid "Range labels" -msgstr "" +msgstr "范围标签" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:39 -#, fuzzy msgid "Ranges" msgstr "管理" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/controlPanel.ts:41 msgid "Ranges to highlight with shading" -msgstr "" +msgstr "突出阴影的范围" #: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/index.js:25 #: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:25 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:28 #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:48 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:33 -#, fuzzy msgid "Ranking" -msgstr "正在执行" +msgstr "排名" #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:63 msgid "Ratio" msgstr "比率" #: superset-frontend/packages/superset-ui-chart-controls/src/constants.ts:46 -#, fuzzy msgid "Raw records" msgstr "原始记录" #: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:64 -#, fuzzy msgid "Ready to review filters in this dashboard?" -msgstr "此看板中没有过滤条件。" +msgstr "准备查看此仪表板中的筛选器吗?" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:78 msgid "Rebuild" -msgstr "" +msgstr "重构" #: superset-frontend/src/profile/components/App.tsx:72 msgid "Recent activity" @@ -9399,7 +9065,7 @@ msgstr "收件人之间用 \",\" 或者 \";\" 隔开" #: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:597 msgid "Recommended tags" -msgstr "" +msgstr "推荐标签" #: superset/templates/appbuilder/general/widgets/base_list.html:55 msgid "Record Count" @@ -9407,7 +9073,7 @@ msgstr "记录数" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:222 msgid "Rectangle" -msgstr "" +msgstr "长方形" #: superset/connectors/druid/views.py:330 msgid "" @@ -9432,7 +9098,6 @@ msgid "" msgstr "减少要渲染的X轴标记数。如果为true,x轴将不会溢出,但是标签可能丢失。如果为false,则对列应用最小宽度,宽度可能溢出到水平滚动条中。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:78 -#, fuzzy msgid "Refer to the" msgstr "参考 " @@ -9475,7 +9140,7 @@ msgstr "刷新间隔" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:976 msgid "Refresh the default values" -msgstr "" +msgstr "刷新默认值" #: superset/connectors/druid/views.py:420 msgid "Refreshed metadata from cluster [{}]" @@ -9498,14 +9163,13 @@ msgstr "常规过滤将where子句添加到查询中,以确定用户是否属 #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:43 #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:44 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:44 -#, fuzzy msgid "Relational" msgstr "执行时间" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:32 #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:35 msgid "Relationships between community channels" -msgstr "" +msgstr "社区渠道之间的关系" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:91 msgid "Relative Date/Time" @@ -9513,7 +9177,6 @@ msgstr "相对日期/时间" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:157 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:210 -#, fuzzy msgid "Relative period" msgstr "宽限期" @@ -9524,19 +9187,17 @@ msgstr "相对量" #: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:69 msgid "Remind me in 24 hours" -msgstr "" +msgstr "24小时后提醒我" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:779 msgid "Remove" msgstr "删除" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx:77 -#, fuzzy msgid "Remove invalid filters" msgstr "删除该行" #: superset-frontend/src/explore/components/controls/CollectionControl/index.jsx:142 -#, fuzzy msgid "Remove item" msgstr "删除该行" @@ -9576,9 +9237,8 @@ msgstr "替换" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:59 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:48 -#, fuzzy msgid "Report" -msgstr "报告" +msgstr "报表" #: superset/reports/commands/exceptions.py:118 msgid "Report Schedule could not be created." @@ -9597,12 +9257,10 @@ msgid "Report Schedule delete failed." msgstr "报表计划删除失败。" #: superset/reports/commands/exceptions.py:142 -#, fuzzy msgid "Report Schedule execution failed when generating a csv." msgstr "生成屏幕截图时报表计划执行失败。" #: superset/reports/commands/exceptions.py:146 -#, fuzzy msgid "Report Schedule execution failed when generating a dataframe." msgstr "生成屏幕截图时报表计划执行失败。" @@ -9643,9 +9301,8 @@ msgid "Report Schedule state not found" msgstr "未找到报表计划状态" #: superset-frontend/src/components/Menu/MenuRight.tsx:225 -#, fuzzy msgid "Report a bug" -msgstr "报告" +msgstr "报告bug" #: superset-frontend/src/views/CRUD/alert/components/AlertStatusIcon.tsx:81 msgid "Report failed" @@ -9677,13 +9334,12 @@ msgid "Reports" msgstr "报告" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:283 -#, fuzzy msgid "Repulsion" msgstr "表达式" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:289 msgid "Repulsion strength between nodes" -msgstr "" +msgstr "节点间的斥力" #: superset/templates/superset/request_access.html:31 msgid "Request Permissions" @@ -9701,7 +9357,7 @@ msgstr "请求不是JSON" #: superset/views/datasource/views.py:71 msgid "Request missing data field." -msgstr "" +msgstr "请求丢失的数据字段。" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:93 #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:97 @@ -9717,16 +9373,14 @@ msgid "Required" msgstr "必填" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:137 -#, fuzzy msgid "Resample" -msgstr "查看样例" +msgstr "重新采样" #: superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.jsx:231 msgid "Reset state" msgstr "状态重置" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/RemovedFilter.tsx:46 -#, fuzzy msgid "Restore Filter" msgstr "还原过滤条件" @@ -9736,11 +9390,11 @@ msgstr "结果" #: superset/sql_lab.py:375 superset/views/core.py:2251 msgid "Results backend is not configured." -msgstr "" +msgstr "后端未配置结果" #: superset/errors.py:116 msgid "Results backend needed for asynchronous queries is not configured." -msgstr "" +msgstr "后端未配置异步查询所需的结果" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:29 msgid "Return to specific datetime." @@ -9757,13 +9411,11 @@ msgid "Rich Tooltip" msgstr "详细提示" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:149 -#, fuzzy msgid "Rich tooltip" msgstr "详细提示" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:113 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:307 -#, fuzzy msgid "Right" msgstr "高度" @@ -9786,14 +9438,13 @@ msgstr "右轴指标" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:138 msgid "Right to Left" -msgstr "" +msgstr "右到左" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:160 msgid "Right value" -msgstr "" +msgstr "右侧的值" #: superset/dashboards/filters.py:153 -#, fuzzy msgid "Role" msgstr "用户信息" @@ -9814,14 +9465,14 @@ msgid "" "Roles is a list which defines access to the dashboard. Granting a role " "access to a dashboard will bypass dataset level checks. If no roles " "defined then the dashboard is available to all roles." -msgstr "" +msgstr "角色是一个定义对仪表板访问权限的列表。授予角色对仪表板的访问权限将绕过数据集级别的检查。如果未定义角色,则仪表板对所有角色都可用。" #: superset/views/dashboard/mixin.py:66 msgid "" "Roles is a list which defines access to the dashboard. Granting a role " "access to a dashboard will bypass dataset level checks.If no roles " "defined then the dashboard is available to all roles." -msgstr "" +msgstr "角色是一个定义对仪表板访问权限的列表。授予角色对仪表板的访问权限将绕过数据集级别的检查。如果未定义角色,则仪表板对所有角色都可用。" #: superset/views/access_requests.py:45 msgid "Roles to grant" @@ -9858,7 +9509,7 @@ msgstr "根证书" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:84 msgid "Root node id" -msgstr "" +msgstr "根节点id" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:307 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:209 @@ -9868,14 +9519,13 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:225 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:228 msgid "Rotate x axis label" -msgstr "" +msgstr "旋转x轴标签" #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.ts:89 msgid "Rotation to apply to words in the cloud" msgstr "应用于词云中的单词的旋转方式" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:271 -#, fuzzy msgid "Round cap" msgstr "国家地图" @@ -9884,7 +9534,6 @@ msgid "Row" msgstr "行" #: superset/initialization/__init__.py:274 -#, fuzzy msgid "Row Level Security" msgstr "行级安全" @@ -9916,7 +9565,7 @@ msgstr "每页行数,0 表示没有分页" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:285 msgid "Rows subtotal position" -msgstr "" +msgstr "行小计的位置" #: superset/views/database/forms.py:193 superset/views/database/forms.py:334 msgid "Rows to Read" @@ -10011,7 +9660,7 @@ msgid "" "You can re-access these queries by using the Save feature before you " "delete the tab.\n" "Note that you will need to close other SQL Lab windows before you do this." -msgstr "" +msgstr "SQL Lab使用浏览器的本地存储来存储查询和结果" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1150 #: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:287 @@ -10036,13 +9685,13 @@ msgstr "SQLAlchemy URI" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:202 msgid "SSL Mode \"require\" will be used." -msgstr "" +msgstr "SSL模式 \"require\" 将被使用。" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:64 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:115 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:122 msgid "START (INCLUSIVE)" -msgstr "" +msgstr "开始 (包含)" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:81 msgid "SUN" @@ -10057,7 +9706,6 @@ msgid "Sankey Diagram" msgstr "桑基图" #: superset-frontend/plugins/legacy-plugin-chart-sankey-loop/src/index.js:27 -#, fuzzy msgid "Sankey Diagram with Loops" msgstr "桑基图" @@ -10113,7 +9761,7 @@ msgstr "另存为" #: superset-frontend/src/explore/components/SaveModal.tsx:243 msgid "Save as ..." -msgstr "另存为" +msgstr "另存为 ..." #: superset-frontend/src/SqlLab/components/SaveQuery/index.tsx:181 msgid "Save as new" @@ -10144,7 +9792,6 @@ msgid "Save query" msgstr "保存查询" #: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:89 -#, fuzzy msgid "Save the query to enable this feature" msgstr "请保存查询以启用共享" @@ -10158,9 +9805,8 @@ msgid "Saved Queries" msgstr "已保存查询" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:226 -#, fuzzy msgid "Saved expressions" -msgstr "SQL表达式" +msgstr "保存表达式" #: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:369 msgid "Saved metric" @@ -10181,19 +9827,18 @@ msgid "Saved query not found." msgstr "保存的查询未找到" #: superset/queries/saved_queries/commands/exceptions.py:40 -#, fuzzy msgid "Saved query parameters are invalid." -msgstr "图表参数无效。" +msgstr "保存的查询参数无效" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:168 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:277 msgid "Scale and Move" -msgstr "" +msgstr "缩放和移动" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:166 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:275 msgid "Scale only" -msgstr "" +msgstr "存在规模" #: superset/initialization/__init__.py:529 msgid "Scan New Datasources" @@ -10203,14 +9848,12 @@ msgstr "扫描新的数据源" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/index.js:43 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:36 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:77 -#, fuzzy msgid "Scatter" -msgstr "状态" +msgstr "散点" #: superset-frontend/plugins/preset-chart-xy/src/ScatterPlot/createMetadata.ts:26 -#, fuzzy msgid "Scatter Plot" -msgstr "Deck.gl - 散点图" +msgstr "散点图" #: superset-frontend/src/SqlLab/components/ScheduleQueryButton/index.tsx:221 #: superset-frontend/src/components/ReportModal/index.tsx:357 @@ -10228,7 +9871,6 @@ msgstr "为看板添加电子邮件报告" #: superset-frontend/src/dashboard/components/Header/index.jsx:423 #: superset-frontend/src/explore/components/ExploreChartHeader/index.jsx:218 -#, fuzzy msgid "Schedule email report" msgstr "为图表配置电子邮件报告" @@ -10251,13 +9893,12 @@ msgid "Scheduled" msgstr "被调度" #: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:117 -#, fuzzy msgid "Scheduled at (UTC)" msgstr "计划时间" #: superset-frontend/src/components/ReportModal/index.tsx:359 msgid "Scheduled reports will be sent to your email as a PNG" -msgstr "" +msgstr "计划的报告将作为PNG发送到您的电子邮件" #: superset-frontend/src/components/DatabaseSelector/index.tsx:295 #: superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx:220 @@ -10272,7 +9913,6 @@ msgid "Schema" msgstr "模式" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:235 -#, fuzzy msgid "Schema cache timeout" msgstr "图表缓存超时" @@ -10281,16 +9921,14 @@ msgid "Schema, as used only in some databases like Postgres, Redshift and DB2" msgstr "模式,只在一些数据库中使用,比如Postgres、Redshift和DB2" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:369 -#, fuzzy msgid "Schemas allowed for CSV upload" -msgstr "不允许将数据库用于csv上载" +msgstr "模式允许使用CSV上传" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:256 msgid "Scoping" msgstr "范围" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:121 -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:256 #: superset-frontend/src/explore/components/DataTableControl/index.tsx:77 #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:419 #: superset-frontend/src/views/CRUD/annotationlayers/AnnotationLayersList.tsx:305 @@ -10313,12 +9951,10 @@ msgid "Search Metrics & Columns" msgstr "搜索指标和列" #: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:703 -#, fuzzy msgid "Search all charts" msgstr "搜索所有图表" #: superset-frontend/src/components/OmniContainer/index.tsx:102 -#, fuzzy msgid "Search all dashboards" msgstr "搜索所有看板" @@ -10328,7 +9964,6 @@ msgid "Search all filter options" msgstr "搜索所有过滤选项" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:403 -#, fuzzy msgid "Search box" msgstr "搜索框" @@ -10341,14 +9976,12 @@ msgid "Search..." msgstr "搜索..." #: superset/db_engine_specs/base.py:86 -#, fuzzy msgid "Second" msgstr "秒" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:244 -#, fuzzy msgid "Secondary" -msgstr "秒" +msgstr "次要的" #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:62 msgid "Secondary Metric" @@ -10356,16 +9989,16 @@ msgstr "次计量指标" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:392 msgid "Secondary y-axis format" -msgstr "" +msgstr "次级y轴格式" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:401 msgid "Secondary y-axis title" -msgstr "" +msgstr "二级轴标题" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:63 -#, fuzzy, python-format +#, python-format msgid "Seconds %s" -msgstr "秒" +msgstr "%s 秒" #: superset/views/database/mixins.py:197 msgid "Secure Extra" @@ -10387,9 +10020,9 @@ msgid "Security & Access" msgstr "安全 & 访问" #: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:157 -#, fuzzy, python-format +#, python-format msgid "See all %(tableName)s" -msgstr "查看 - %(table)s" +msgstr "查看全部 - %(tableName)s" #: superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx:155 msgid "See less" @@ -10405,7 +10038,6 @@ msgid "See table schema" msgstr "选择表" #: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:132 -#, fuzzy msgid "Select" msgstr "批量选择" @@ -10417,12 +10049,10 @@ msgid "Select ..." msgstr "选择 ..." #: superset-frontend/src/views/CRUD/alert/components/NotificationMethod.tsx:127 -#, fuzzy msgid "Select Delivery Method" msgstr "添加通知方法" #: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:106 -#, fuzzy msgid "Select Viz Type" msgstr "选择一个可视化类型" @@ -10431,7 +10061,6 @@ msgid "Select a CSV file to be uploaded to a database." msgstr "选择一个CSV文件上传到数据库." #: superset/views/database/forms.py:386 -#, fuzzy msgid "Select a Columnar file to be uploaded to a database." msgstr "选择要上传到数据库的Excel文件。" @@ -10440,12 +10069,10 @@ msgid "Select a Excel file to be uploaded to a database." msgstr "选择要上传到数据库的Excel文件。" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx:133 -#, fuzzy msgid "Select a column" msgstr "反选所有" #: superset-frontend/src/explore/components/SaveModal.tsx:264 -#, fuzzy msgid "Select a dashboard" msgstr "看板" @@ -10454,35 +10081,31 @@ msgid "Select a visualization type" msgstr "选择一个可视化类型" #: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:310 -#, fuzzy, python-format +#, python-format msgid "Select aggregate options" -msgstr "%s 聚合" +msgstr "选择总选项" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:107 msgid "Select any columns for metadata inspection" -msgstr "" +msgstr "选择任意列进行元数据巡检" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:103 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/controlPanel.ts:138 -#, fuzzy msgid "Select charts" msgstr "所有图表" #: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:188 -#, fuzzy msgid "Select color scheme" msgstr "线性颜色方案" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:208 #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx:63 #: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:301 -#, fuzzy msgid "Select column" msgstr "时间列" #: superset-frontend/src/components/DatabaseSelector/index.tsx:268 #: superset-frontend/src/components/DatabaseSelector/index.tsx:275 -#, fuzzy msgid "Select database or type database name" msgstr "选择表或输入表名" @@ -10491,16 +10114,14 @@ msgid "" "Select databases require additional fields to be completed in the " "Advanced tab to successfully connect the database. Learn what " "requirements your databases has " -msgstr "" +msgstr "选择数据库需要在Advanced选项卡中完成额外的字段才能成功连接数据库了解数据库的需求" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:294 #: superset-frontend/src/filters/components/Select/index.ts:28 -#, fuzzy msgid "Select filter" msgstr "选择过滤器" #: superset-frontend/src/filters/components/Select/index.ts:29 -#, fuzzy msgid "Select filter plugin using AntD" msgstr "选择过滤器" @@ -10508,20 +10129,18 @@ msgstr "选择过滤器" msgid "" "Select first item by default (when using this option, default value can’t" " be set)" -msgstr "" +msgstr "默认选择第一项(使用此选项时,不能“设置默认值”)" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:303 -#, fuzzy, python-format +#,python-format msgid "Select operator" -msgstr "%s 运算符" +msgstr "选择运营商" #: superset-frontend/src/components/ListView/Filters/Select.tsx:84 -#, fuzzy msgid "Select or type a value" -msgstr "选择或者键入数据集名称" +msgstr "选择或键入一个值" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:393 -#, fuzzy msgid "Select owners" msgstr "运行选定的查询" @@ -10530,20 +10149,19 @@ msgid "Select parent filters" msgstr "选择父级过滤" #: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:319 -#, fuzzy, python-format +#, python-format msgid "Select saved metrics" -msgstr "%s 列与计量指标" +msgstr "选择保存指标" #: superset-frontend/src/components/DatabaseSelector/index.tsx:293 #: superset-frontend/src/components/DatabaseSelector/index.tsx:300 -#, fuzzy msgid "Select schema or type schema name" msgstr "选择表或输入表名" #: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:194 -#, fuzzy, python-format +#,python-format msgid "Select scheme" -msgstr "选择一个schema(%s)" +msgstr "选择表" #: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:273 msgid "Select start and end date" @@ -10551,7 +10169,7 @@ msgstr "选择开始和结束时间" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:265 msgid "Select subject" -msgstr "" +msgstr "选择主题" #: superset-frontend/src/components/TableSelector/index.tsx:298 #: superset-frontend/src/components/TableSelector/index.tsx:308 @@ -10559,27 +10177,25 @@ msgid "Select table or type table name" msgstr "选择表或输入表名" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:98 -#, fuzzy msgid "Select the number of bins for the histogram" msgstr "选择直方图的容器数" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:38 #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:48 -#, fuzzy msgid "Select the numeric columns to draw the histogram" msgstr "选择直方图的容器数" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1340 msgid "Send as CSV" -msgstr "" +msgstr "发送为CSV" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1339 msgid "Send as PNG" -msgstr "" +msgstr "发送PNG" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1342 msgid "Send as text" -msgstr "" +msgstr "发送文本" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Line/controlPanel.ts:58 msgid "Send range filter events to other charts" @@ -10592,7 +10208,7 @@ msgstr "九月" #: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:58 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:49 msgid "Sequential" -msgstr "" +msgstr "顺序" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:61 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:385 @@ -10608,7 +10224,6 @@ msgstr "序列高度" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:112 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:113 -#, fuzzy msgid "Series Style" msgstr "线条样式" @@ -10616,7 +10231,7 @@ msgstr "线条样式" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:122 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:125 msgid "Series chart type (line, bar etc)" -msgstr "" +msgstr "系列图表类型(折线,柱状图等)" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:341 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:356 @@ -10625,23 +10240,20 @@ msgid "Series limit" msgstr "序列限制" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:135 -#, fuzzy msgid "Series type" msgstr "图示类型" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:311 -#, fuzzy msgid "Server Page Length" msgstr "页面长度" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:289 -#, fuzzy msgid "Server pagination" -msgstr "Superset注释" +msgstr "服务器分页" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:115 msgid "Service Account" -msgstr "" +msgstr "服务帐户" #: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:286 msgid "Set auto-refresh interval" @@ -10658,7 +10270,7 @@ msgstr "设置" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:133 msgid "Settings for time series" -msgstr "" +msgstr "时间序列设置" #: superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx:229 msgid "Share" @@ -10666,14 +10278,12 @@ msgstr "分享" #: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:317 #: superset-frontend/src/explore/components/ExploreActionButtons.tsx:175 -#, fuzzy msgid "Share chart by email" -msgstr "共享图表" +msgstr "通过电子邮件分享图表”" #: superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx:264 -#, fuzzy msgid "Share dashboard by email" -msgstr "分享看板" +msgstr "通过电子邮件分享仪表盘" #: superset-frontend/src/SqlLab/actions/sqlLab.js:1221 msgid "Shared query" @@ -10691,19 +10301,19 @@ msgstr "此层的简述必须是唯一的" msgid "" "Should daily seasonality be applied. An integer value will specify " "Fourier order of seasonality." -msgstr "" +msgstr "一个整数值将指定季节性的傅立叶顺序。" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:109 msgid "" "Should weekly seasonality be applied. An integer value will specify " "Fourier order of seasonality." -msgstr "" +msgstr "一个整数值将指定季节性的傅立叶顺序。" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:90 msgid "" "Should yearly seasonality be applied. An integer value will specify " "Fourier order of seasonality." -msgstr "" +msgstr "一个整数值将指定“季节性的傅立叶顺序。" #: superset/views/annotations.py:59 msgid "Show Annotation" @@ -10774,9 +10384,8 @@ msgid "Show Labels" msgstr "显示标签" #: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:359 -#, fuzzy msgid "Show Less..." -msgstr "显示值" +msgstr "显示. ." #: superset/views/log/__init__.py:22 msgid "Show Log" @@ -10811,7 +10420,6 @@ msgid "Show SQL time column" msgstr "显示SQL时间列" #: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:105 -#, fuzzy msgid "Show SQL time grain dropdown" msgstr "检查包含时间原点的下拉列表" @@ -10825,19 +10433,17 @@ msgstr "显示表" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:85 msgid "Show Timestamp" -msgstr "" +msgstr "显示时间戳" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:97 msgid "Show Trend Line" -msgstr "" +msgstr "显示趋势线" #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:83 -#, fuzzy msgid "Show Upper Labels" msgstr "显示标签" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:106 -#, fuzzy msgid "Show Value" msgstr "显示值" @@ -10848,26 +10454,23 @@ msgid "Show Values" msgstr "显示值" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx:173 -#, fuzzy msgid "Show all columns" -msgstr "显示列" +msgstr "显示所有列" #: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:326 #: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:359 msgid "Show all..." -msgstr "" +msgstr "显示所有..." #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:206 msgid "Show axis line ticks" -msgstr "" +msgstr "显示轴线刻度" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:119 -#, fuzzy msgid "Show cell bars" msgstr "显示单元格的栏" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:161 -#, fuzzy msgid "Show columns total" msgstr "显示总计" @@ -10879,34 +10482,31 @@ msgstr "将数据点显示为线条上的圆形标记" msgid "" "Show hierarchical relationships of data, with with the value represented " "by area, showing proportion and contribution to the whole." -msgstr "" +msgstr "显示数据的层次关系与表示的值。按面积划分显示其占整体的比例" #: superset-frontend/packages/superset-ui-chart-controls/src/components/InfoTooltipWithTrigger.tsx:50 msgid "Show info tooltip" -msgstr "" +msgstr "显示信息提示" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:736 -#, fuzzy msgid "Show label" msgstr "显示标签" #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx:86 msgid "Show labels when the node has children." -msgstr "" +msgstr "当节点有子节点时显示标签" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:35 msgid "Show legend" -msgstr "" +msgstr "显示图例" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx:168 -#, fuzzy msgid "Show less columns" -msgstr "显示SQL时间列" +msgstr "显示较少时间列" #: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:326 -#, fuzzy msgid "Show less..." -msgstr "显示值" +msgstr "显示..." #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:287 msgid "Show percentage" @@ -10914,38 +10514,33 @@ msgstr "显示百分比" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:179 msgid "Show pointer" -msgstr "" +msgstr "显示鼠标" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:245 -#, fuzzy msgid "Show progress" -msgstr "进度" +msgstr "显示进度" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:149 -#, fuzzy msgid "Show rows total" -msgstr "显示总计" +msgstr "显示总计行数" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:109 -#, fuzzy msgid "Show series values on the chart" msgstr "显示栏上的值" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:218 msgid "Show split lines" -msgstr "" +msgstr "显示分割线" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:297 msgid "Show the value on top of the bar" msgstr "显示栏上的值" #: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:121 -#, fuzzy msgid "Show time column" -msgstr "显示SQL时间列" +msgstr "显示时间列" #: superset-frontend/src/visualizations/FilterBox/controlPanel.jsx:106 -#, fuzzy msgid "Show time grain dropdown" msgstr "显示Druid时间粒度下拉列表" @@ -10953,7 +10548,7 @@ msgstr "显示Druid时间粒度下拉列表" msgid "" "Show total aggregations of selected metrics. Note that row limit does not" " apply to the result." -msgstr "" +msgstr "显示所选指标的总聚合。注意行限制并不应用于结果" #: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:87 #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:349 @@ -10965,33 +10560,33 @@ msgid "" "Showcases a single metric front-and-center. Big number is best used to " "call attention to a KPI or the one thing you want your audience to focus " "on." -msgstr "" +msgstr "显示单个公制正面和中间。大数字最好用来唤起人们对KPI或你希望观众关注的一件事的关注" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts:30 msgid "" "Showcases a single number accompanied by a simple line chart, to call " "attention to an important metric along with its change over time or other" " dimension." -msgstr "" +msgstr "显示一个数字和一个简单的折线图,以提醒注意一个重要指标及其随时间或其他维度的变化" #: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:49 msgid "" "Showcases how a metric changes as the funnel progresses. This classic " "chart is useful for visualizing drop-off between stages in a pipeline or " "lifecycle." -msgstr "" +msgstr "显示指标如何随着漏斗的进展而变化。此经典图表对于可视化管道或生命周期中各阶段之间的下降非常有用。" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/index.js:28 msgid "" "Showcases the flow or link between categories using thickness of chords. " "The value and corresponding thickness can be different for each side." -msgstr "" +msgstr "使用弦的厚度显示类别之间的流或链接。每一侧的值和相应厚度可能不同。" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bullet/index.js:27 msgid "" "Showcases the progress of a single metric against a given target. The " "higher the fill, the closer the metric is to the target." -msgstr "" +msgstr "显示单个指标相对于给定目标的进度。填充越高,度量越接近目标" #: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:305 #: superset-frontend/src/explore/components/DatasourcePanel/index.tsx:338 @@ -11000,7 +10595,6 @@ msgid "Showing %s of %s" msgstr "显示 %s个 总计 %s个" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:152 -#, fuzzy msgid "Shows a list of all series available at that point in time" msgstr "详细提示显示了该时间点的所有序列的列表。" @@ -11010,11 +10604,11 @@ msgid "" "smaller rectangles with areas proportional to their value or contribution" " to the whole. Those rectangles may also, in turn, be further segmented " "hierarchically." -msgstr "" +msgstr "显示数据集的组成,方法是将给定矩形分割为较小的矩形,其面积与矩形的值或对整体的贡献成比例。这些矩形也可以按层次进一步分割" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:72 msgid "Significance Level" -msgstr "" +msgstr "显著性" #: superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx:262 #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx:201 @@ -11025,36 +10619,32 @@ msgstr "简单配置" #: superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.jsx:390 msgid "Simple ad-hoc metrics are not enabled for this dataset" -msgstr "" +msgstr "此数据集没有启用简单的特别度量" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:186 -#, fuzzy msgid "Single" msgstr "我的编辑" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:45 #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:46 -#, fuzzy msgid "Single Metric" msgstr "按指标过滤" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1234 -#, fuzzy msgid "Single Value" msgstr "空值" #: superset-frontend/src/filters/components/Range/controlPanel.ts:65 -#, fuzzy msgid "Single value" msgstr "空值" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1251 msgid "Single value type" -msgstr "" +msgstr "单值类型" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:261 msgid "Size of edge symbols" -msgstr "" +msgstr "边缘符号的大小" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:230 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:168 @@ -11064,11 +10654,11 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:184 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:187 msgid "Size of marker. Also applies to forecast observations." -msgstr "" +msgstr "标记的大小也适用于预测观察。”" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:34 msgid "Sizes of vehicles" -msgstr "" +msgstr "工具尺寸" #: superset/views/database/forms.py:199 msgid "Skip Blank Lines" @@ -11105,12 +10695,10 @@ msgid "Small" msgstr "小" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:153 -#, fuzzy msgid "Small number format" msgstr "数字格式化" #: superset/commands/exceptions.py:112 -#, fuzzy msgid "Some roles do not exist" msgstr "看板" @@ -11131,16 +10719,16 @@ msgstr "抱歉,发生错误" #: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:65 #: superset-frontend/src/explore/components/ExploreActionButtons.tsx:126 msgid "Sorry, something went wrong. Try again later." -msgstr "" +msgstr "抱歉,出了点问题。请稍后再试。" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/EventFlow.tsx:50 msgid "Sorry, there appears to be no data" -msgstr "" +msgstr "抱歉,似乎没有数据" #: superset-frontend/src/dashboard/actions/dashboardState.js:238 -#, fuzzy, python-format +#, python-format msgid "Sorry, there was an error saving this dashboard: %s" -msgstr "抱歉,这个看板在获取图表时发生错误:" +msgstr "抱歉,这个看板在获取图表时发生错误:%s" #: superset-frontend/src/dashboard/components/menu/ShareMenuItems/index.tsx:55 #: superset-frontend/src/explore/components/ExploreActionButtons.tsx:115 @@ -11156,7 +10744,6 @@ msgstr "抱歉,您的浏览器不支持复制操作。使用 Ctrl / Cmd + C! #: superset-frontend/src/components/ListView/CardSortSelect.tsx:82 #: superset-frontend/src/components/ListView/CardSortSelect.tsx:83 -#, fuzzy msgid "Sort" msgstr "排序:" @@ -11184,7 +10771,6 @@ msgid "Sort Descending" msgstr "降序" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1198 -#, fuzzy msgid "Sort Metric" msgstr "排序指标" @@ -11237,7 +10823,6 @@ msgid "Sort columns alphabetically" msgstr "对列按字母顺序进行排列" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:257 -#, fuzzy msgid "Sort columns by" msgstr "对列按字母顺序进行排列" @@ -11249,7 +10834,6 @@ msgid "Sort descending" msgstr "降序" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1167 -#, fuzzy msgid "Sort filter values" msgstr "可被过滤" @@ -11260,12 +10844,10 @@ msgid "Sort metric" msgstr "排序指标" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:229 -#, fuzzy msgid "Sort rows by" msgstr "排序 " #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:1181 -#, fuzzy msgid "Sort type" msgstr "图表类型" @@ -11286,7 +10868,6 @@ msgid "Source SQL" msgstr "源 SQL" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:73 -#, fuzzy msgid "Source category" msgstr "数据库名称" @@ -11311,23 +10892,21 @@ msgstr "将重复列指定为“x.0,x.1”。" msgid "" "Specify the database version. This should be used with Presto in order to" " enable query cost estimation." -msgstr "" +msgstr "指定数据库版本。这应该与Presto一起使用,以便启用查询成本估算。" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:230 -#, fuzzy msgid "Split number" msgstr "数字" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:156 #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:117 -#, fuzzy msgid "Stack series" msgstr "已保存查询" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:159 #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:120 msgid "Stack series on top of each other" -msgstr "" +msgstr "叠加系列" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:37 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:51 @@ -11336,9 +10915,8 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:84 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:83 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:68 -#, fuzzy msgid "Stacked" -msgstr "开始时间" +msgstr "堆叠" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:305 msgid "Stacked Bars" @@ -11349,12 +10927,10 @@ msgid "Stacked Style" msgstr "堆积样式" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:37 -#, fuzzy msgid "Stacked style" msgstr "堆积样式" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:88 -#, fuzzy msgid "Standard time series" msgstr "时间序列" @@ -11364,34 +10940,31 @@ msgid "Start" msgstr "开始" #: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:79 -#, fuzzy msgid "Start Review" msgstr "数据预览" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:110 -#, fuzzy msgid "Start angle" msgstr "开始时间" #: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:125 -#, fuzzy msgid "Start at (UTC)" -msgstr "开始/从" +msgstr "由UTC开始" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx:66 #: superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx:117 msgid "Start date included in time range" -msgstr "" +msgstr "开始日期包含在时间范围内" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:109 msgid "Start y-axis at 0" -msgstr "" +msgstr "y轴从0开始" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:112 msgid "" "Start y-axis at zero. Uncheck to start y-axis at minimum value in the " "data." -msgstr "" +msgstr "从零开始y轴。取消选中以从数据中的最小值开始y轴 " #: superset-frontend/src/views/CRUD/alert/ExecutionLog.tsx:94 #: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:348 @@ -11401,7 +10974,7 @@ msgstr "状态" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts:55 msgid "Statistical" -msgstr "" +msgstr "统计" #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:399 #: superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx:302 @@ -11410,7 +10983,6 @@ msgid "Status" msgstr "状态" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:112 -#, fuzzy msgid "Step type" msgstr "数据类型" @@ -11433,10 +11005,9 @@ msgstr "已停止不安全的数据库连接" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:268 msgid "Strength to pull the graph toward center" -msgstr "" +msgstr "将图形拉向中心" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:36 -#, fuzzy msgid "Stretched style" msgstr "堆积样式" @@ -11447,7 +11018,7 @@ msgstr "用于sheet名称的字符串(默认为第一个sheet)。" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts:45 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:45 msgid "Structural" -msgstr "" +msgstr "结构" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:621 msgid "Style" @@ -11455,7 +11026,7 @@ msgstr "风格" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:272 msgid "Style the ends of the progress bar with a round cap" -msgstr "" +msgstr "用圆帽设置进度条末端的样式" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:56 msgid "Subdomain" @@ -11477,11 +11048,11 @@ msgstr "成功" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:62 msgid "Suffix to apply after the percentage display" -msgstr "" +msgstr "百分比显示后要应用的后缀" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:98 msgid "Sum of values over specified period" -msgstr "" +msgstr "指定期间内的值总和" #: superset/viz.py:1856 msgid "Sunburst" @@ -11496,7 +11067,6 @@ msgid "Sunday" msgstr "星期日" #: superset-frontend/src/explore/components/ExploreActionButtons.tsx:121 -#, fuzzy msgid "Superset Chart" msgstr "选择图表" @@ -11510,30 +11080,26 @@ msgid "Superset dashboard" msgstr "看板" #: superset/errors.py:105 -#, fuzzy msgid "Superset encountered an error while running a command." msgstr "警报在执行查询时发现错误。" #: superset/errors.py:106 -#, fuzzy msgid "Superset encountered an unexpected error." msgstr "报告计划意外错误。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:670 -#, fuzzy msgid "Supported databases" msgstr "已支持数据库" #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:34 msgid "Survey Responses" -msgstr "" +msgstr "调查结果" #: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/controlPanel.ts:112 msgid "Swap Groups and Columns" msgstr "交换组和列" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:175 -#, fuzzy msgid "Swap rows and columns" msgstr "交换组和列" @@ -11542,21 +11108,19 @@ msgid "" "Swiss army knife for visualizing time series data. Choose between step, " "line, scatter, and bar charts. This viz type has many customization " "options as well." -msgstr "" +msgstr "用于可视化时间序列数据。在步进图、折线图、散点图和条形图之间进行选择,也有许多自定义选项" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:210 -#, fuzzy msgid "Symbol" -msgstr "螺栓" +msgstr "符号" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:125 msgid "Symbol of two ends of edge line" -msgstr "" +msgstr "边线两端的符号" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:255 -#, fuzzy msgid "Symbol size" -msgstr "气泡尺寸" +msgstr "符号的大小" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1223 msgid "Sync columns from source" @@ -11586,12 +11150,12 @@ msgstr "星期二" #: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:218 #: superset-frontend/src/views/CRUD/data/query/QueryPreviewModal.tsx:145 msgid "Tab name" -msgstr "tab名" +msgstr "选项卡名字" #: superset-frontend/src/dashboard/util/newComponentFactory.js:56 #: superset-frontend/src/dashboard/util/newComponentFactory.js:57 msgid "Tab title" -msgstr "" +msgstr "选项卡标题" #: superset-frontend/plugins/legacy-plugin-chart-pivot-table/src/index.js:25 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:50 @@ -11637,7 +11201,6 @@ msgid "" msgstr "找不到 [%{table}s] 表,请仔细检查您的数据库连接、Schema 和 表名" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:257 -#, fuzzy msgid "Table cache timeout" msgstr "图表缓存超时" @@ -11649,7 +11212,7 @@ msgstr "表名未定义" msgid "" "Table that visualizes paired t-tests, which are used to understand " "statistical differences between groups." -msgstr "" +msgstr "可视化检验的表格,用于了解各组之间的统计差异" #: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:269 #: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:324 @@ -11659,45 +11222,41 @@ msgstr "数据表" #: superset-frontend/src/dashboard/components/gridComponents/new/NewTabs.jsx:31 msgid "Tabs" -msgstr "" +msgstr "选项卡" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/index.js:30 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:55 #: superset-frontend/plugins/plugin-chart-table/src/index.ts:50 #: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:34 msgid "Tabular" -msgstr "" +msgstr "表格" #: superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx:607 -#, fuzzy msgid "Tags" -msgstr "状态" +msgstr "标签" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/index.js:29 msgid "" "Take your data points, and group them into \"bins\" to see where the " "densest areas of information lie" -msgstr "" +msgstr "获取数据点,并将其分组,以查看信息最密集的区域" #: superset-frontend/plugins/legacy-plugin-chart-chord/src/controlPanel.ts:66 #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:62 -#, fuzzy msgid "Target" -msgstr "开始" +msgstr "目标" #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/controlPanel.ts:67 msgid "Target aspect ratio for treemap tiles." msgstr "树形图中图块的目标高宽比。" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:86 -#, fuzzy msgid "Target category" -msgstr "开始/从" +msgstr "目标类别" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:176 -#, fuzzy msgid "Target value" -msgstr "条形栏的值" +msgstr "目标值" #: superset/views/css_templates.py:44 msgid "Template Name" @@ -11718,14 +11277,14 @@ msgstr "模板链接,可以包含{{度量}}或来自控件的其他值。" #: superset/models/sql_types/base.py:54 #, python-format msgid "Temporal expression not supported for type: %(col_type)s" -msgstr "" +msgstr "%(col_type)s不支持时间表达式" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:307 msgid "" "Terminate running queries when browser window closed or navigated to " "another page. Available for Presto, Hive, MySQL, Postgres and Snowflake " "databases." -msgstr "" +msgstr "当浏览器窗口关闭或导航到其他页面时,终止正在运行的查询。适用于Presto、Hive、MySQL、Postgres和Snowflake数据库" #: superset/templates/superset/models/database/macros.html:22 msgid "Test Connection" @@ -11736,17 +11295,16 @@ msgid "Test connection" msgstr "测试连接" #: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:35 -#, fuzzy msgid "Text" -msgstr "之后" +msgstr "文本" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:105 msgid "Text align" -msgstr "" +msgstr "文本对齐" #: superset-frontend/src/components/ReportModal/index.tsx:289 msgid "Text embedded in email" -msgstr "" +msgstr "邮件中嵌入的文本" #: superset/views/dashboard/mixin.py:53 msgid "" @@ -11755,7 +11313,6 @@ msgid "" msgstr "可以在这里或者在看板视图修改单个看板的CSS样式" #: superset/errors.py:118 -#, fuzzy msgid "" "The CTAS (create table as select) doesn't have a SELECT statement at the " "end. Please make sure your query has a SELECT as its last statement. " @@ -11772,32 +11329,29 @@ msgstr "JSON指标或处理聚合定义。" msgid "" "The URL could not be identified. Please check for typos and make sure " "that \"Type of google sheet allowed\" selection matches the input" -msgstr "" +msgstr "无法识别URL。请检查拼写错误,并确保允许的谷歌工作表类型选择与输入匹配" #: superset/views/core.py:354 msgid "The access requests seem to have been deleted" msgstr "访问请求已被删除" #: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:168 -#, fuzzy msgid "The annotation has been saved" -msgstr "该看板已成功保存。" +msgstr "注释已保存。" #: superset-frontend/src/views/CRUD/annotation/AnnotationModal.tsx:152 -#, fuzzy msgid "The annotation has been updated" -msgstr "注释无法更新。" +msgstr "注释已更新。" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:74 msgid "" "The category of source nodes used to assign colors. If a node is " "associated with more than one category, only the first will be used." -msgstr "" +msgstr "用于分配颜色的源节点类别。如果一个节点与多个类别关联,则只使用第一个类别" #: superset/common/query_context_processor.py:449 -#, fuzzy msgid "The chart does not exist" -msgstr "图表没有找到" +msgstr "图表不存在" #: superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts:54 msgid "" @@ -11809,6 +11363,8 @@ msgid "" " relative proportion is important, consider using a bar or other chart " "type instead." msgstr "" +"经典的,很好地展示了每个投资者获得了多少公司,“有多少人关注你的博客,或者预算的哪一部分流向了军事工业综合体" +"饼状图很难精确解释。如果“相对比例”的清晰性很重要,可以考虑使用柱状图或其他图表来代替。" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:261 msgid "The color for points and clusters in RGB" @@ -11824,11 +11380,12 @@ msgid "" "The color scheme is determined by the related dashboard.\n" " Edit the color scheme in the dashboard properties." msgstr "" +"配色方案由相关的仪表盘决定。" +"在仪表板属性中编辑配色方案" #: superset/errors.py:99 -#, fuzzy msgid "The column was deleted or renamed in the database." -msgstr "Issue 1004 - 该列已在数据库中删除或重命名。" +msgstr "该列已在数据库中删除或重命名。" #: superset-frontend/plugins/legacy-plugin-chart-world-map/src/controlPanel.ts:47 msgid "" @@ -11852,7 +11409,7 @@ msgid "" msgstr "由数据库推断的数据类型。在某些情况下,可能需要为表达式定义的列手工输入一个类型。在大多数情况下,用户不需要修改这个数据类型。" #: superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx:439 -#, fuzzy, python-format +#, python-format msgid "" "The database %s is linked to %s charts that appear on %s dashboards and " "users have %s SQL Lab tabs using this database open. Are you sure you " @@ -11861,31 +11418,27 @@ msgstr "数据库 %s 已经关联了 %s 图表和 %s 看板。确定要继续吗 #: superset/errors.py:126 msgid "The database is currently running too many queries." -msgstr "" +msgstr "数据库当前运行的查询太多" #: superset/errors.py:93 -#, fuzzy msgid "The database is under an unusual load." -msgstr "Issue 1001 - 数据库负载异常。" +msgstr "数据库负载异常。" #: superset/sqllab/command.py:149 msgid "" "The database referenced in this query was not found. Please contact an " "administrator for further assistance or try again." -msgstr "" +msgstr "找不到此查询中引用的数据库。请与管理员联系以获得进一步帮助,或重试。" #: superset/errors.py:94 -#, fuzzy msgid "The database returned an unexpected error." -msgstr "Issue 1002 - 数据库返回意外错误。" +msgstr "数据库返回意外错误。" #: superset/errors.py:138 -#, fuzzy msgid "The database was deleted." msgstr "数据集已保存" #: superset/views/core.py:2085 superset/views/core.py:2155 -#, fuzzy msgid "The database was not found." msgstr "数据库没有找到" @@ -11898,7 +11451,6 @@ msgid "" msgstr "数据集 %s 已经链接到 %s 图表和 %s 看板内。确定要继续吗?删除数据集将破坏这些对象。" #: superset-frontend/src/chart/Chart.jsx:73 superset/views/utils.py:268 -#, fuzzy msgid "The dataset associated with this chart no longer exists" msgstr "这个图表所链接的数据集可能被删除了。" @@ -11925,9 +11477,8 @@ msgid "The datasource couldn't be loaded" msgstr "这个查询无法被加载" #: superset/errors.py:92 -#, fuzzy msgid "The datasource is too large to query." -msgstr "Issue 1000 - 数据源太大,无法进行查询。" +msgstr "数据源太大,无法进行查询。" #: superset-frontend/src/explore/components/PropertiesModal/index.tsx:247 msgid "" @@ -11944,7 +11495,6 @@ msgid "The duration of time in seconds before the cache is invalidated" msgstr "缓存失效前的持续时间(以秒为单位)" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:474 -#, fuzzy msgid "" "The engine_params object gets unpacked into the sqlalchemy.create_engine " "call." @@ -11957,7 +11507,7 @@ msgstr "" msgid "" "The following entries in `series_columns` are missing in `columns`: " "%(columns)s. " -msgstr "" +msgstr " `series_columns`中的下列条目在 `columns` 中缺失: %(columns)s. " #: superset/connectors/sqla/views.py:612 #, python-format @@ -11977,7 +11527,7 @@ msgstr "下表更新列元数据:%(tables)s" #: superset/db_engine_specs/mysql.py:134 #, python-format msgid "The host \"%(hostname)s\" might be down and can't be reached." -msgstr "" +msgstr "主机 \"%(hostname)s\" 可能已关闭,无法连接到" #: superset/db_engine_specs/mssql.py:92 #: superset/db_engine_specs/postgres.py:137 @@ -11987,15 +11537,15 @@ msgstr "" msgid "" "The host \"%(hostname)s\" might be down, and can't be reached on port " "%(port)s." -msgstr "" +msgstr "主机 \"%(hostname)s\" 可能已关闭,无法通过端口访问 " #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:98 msgid "The host is invalid. Please verify that this field is entered correctly." -msgstr "" +msgstr "主机无效。请检查此字段是否输入正确。" #: superset/errors.py:104 msgid "The host might be down, and can't be reached on the provided port." -msgstr "" +msgstr "主机可能宕机了,无法在所提供的端口上连接到它" #: superset/db_engine_specs/mssql.py:82 #: superset/db_engine_specs/postgres.py:127 @@ -12003,11 +11553,11 @@ msgstr "" #: superset/db_engine_specs/redshift.py:68 #, python-format msgid "The hostname \"%(hostname)s\" cannot be resolved." -msgstr "" +msgstr "无法解析主机名 \"%(hostname)s\" " #: superset/errors.py:102 msgid "The hostname provided can't be resolved." -msgstr "" +msgstr "提供的主机名无法解析。" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:60 #: superset-frontend/src/explore/controlPanels/sections.tsx:44 @@ -12029,17 +11579,17 @@ msgstr "与此表关联的图表列表。通过更改此数据源,您可以更 #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:130 msgid "The maximum number of events to return, equivalent to the number of rows" -msgstr "" +msgstr "返回的最大事件数,相当于行数" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:179 msgid "" "The maximum number of subdivisions of each group; lower values are pruned" " first" -msgstr "" +msgstr "每组的最大细分数;较低的值首先被删除" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx:49 msgid "The maximum value of metrics. It is an optional configuration" -msgstr "" +msgstr "度量的最大值。这是一个可选配置" #: superset/databases/schemas.py:206 #, python-format @@ -12059,7 +11609,7 @@ msgstr "额外字段中的元数据参数配置不正确。键 %{key}s 无效。 msgid "" "The metadata_params object gets unpacked into the sqlalchemy.MetaData " "call." -msgstr "" +msgstr "metadata_params对象被解压缩到sqlalchemy.metadata调用中。" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:75 #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:292 @@ -12085,7 +11635,7 @@ msgstr "色彩 \"Steps\" 数字" msgid "" "The number of hours, negative or positive, to shift the time column. This" " can be used to move UTC time to local time." -msgstr "" +msgstr "用于移动时间列的小时数(负数或正数)。这可用于将UTC时间移动到本地时间" #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:583 #, python-format @@ -12093,7 +11643,7 @@ msgid "" "The number of results displayed is limited to %(rows)d by the " "configuration DISPLAY_MAX_ROWS. Please add additional limits/filters or " "download to csv to see more rows up to the %(limit)d limit." -msgstr "" +msgstr "显示的结果数由配置DISPLAY_MAX_rows限制为 %(rows)d 。请添加其他限制/筛选器或下载到csv以查看更多行数,限制为 %(limit)d " #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:589 #, python-format @@ -12101,29 +11651,29 @@ msgid "" "The number of results displayed is limited to %(rows)d. Please add " "additional limits/filters, download to csv, or contact an admin to see " "more rows up to the %(limit)d limit." -msgstr "" +msgstr "显示的结果数限制为 %(rows)d。请添加其他筛选器,下载到csv,或与管理员联系以查看 %(limit)d 的更多行”" #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:615 #, python-format msgid "The number of rows displayed is limited to %(rows)d by the limit dropdown." -msgstr "" +msgstr "显示的行数通过限制下拉框限制为 %(rows)d 。" #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:603 #, python-format msgid "The number of rows displayed is limited to %(rows)d by the query" -msgstr "" +msgstr "查询将显示的行数限制为 %(rows)d " #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:624 #, python-format msgid "" "The number of rows displayed is limited to %(rows)d by the query and " "limit dropdown." -msgstr "" +msgstr "查询和限制下拉列表将显示的行数限制为 %(rows)d" #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:644 #, python-format msgid "The number of rows displayed is limited to %s by the dropdown." -msgstr "" +msgstr "通过下拉菜单显示的行数限制为 %s " #: superset-frontend/packages/superset-ui-chart-controls/src/sections/sections.tsx:69 #: superset-frontend/src/explore/controlPanels/sections.tsx:53 @@ -12131,7 +11681,6 @@ msgid "The number of seconds before expiring the cache" msgstr "终止缓存前的时间(秒)" #: superset/errors.py:128 -#, fuzzy msgid "The object does not exist in the given database." msgstr "源数据库中存在的表的名称" @@ -12144,11 +11693,11 @@ msgstr[0] "查询中的以下参数未定义:%(parameters)s 。" #: superset/db_engine_specs/postgres.py:117 #, python-format msgid "The password provided for username \"%(username)s\" is incorrect." -msgstr "" +msgstr "用户名 \"%(username)s\" 提供的密码不正确。" #: superset/errors.py:108 msgid "The password provided when connecting to a database is not valid." -msgstr "" +msgstr "连接数据库时提供的密码无效。" #: superset-frontend/src/views/CRUD/chart/ChartList.tsx:65 msgid "" @@ -12184,7 +11733,6 @@ msgstr "" "部分不在导出文件中,如果需要,应在导入后手动添加。" #: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:56 -#, fuzzy msgid "" "The passwords for the databases below are needed in order to import them " "together with the saved queries. Please note that the \"Secure Extra\" " @@ -12215,7 +11763,7 @@ msgid "" " \"Pandas\" offset alias.\n" " Click on the info bubble for more details on accepted " "\"freq\" expressions." -msgstr "" +msgstr "旋转时间的周期性。" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:118 msgid "The pixel radius" @@ -12229,17 +11777,14 @@ msgid "" msgstr "指向物理表(或视图)的指针。请记住,图表将与此逻辑表相关联,并且此逻辑表指向此处引用的物理表。" #: superset/errors.py:103 -#, fuzzy msgid "The port is closed." msgstr "报告失败" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:108 -#, fuzzy msgid "The port must be a whole number less than or equal to 65535." msgstr "`行限制` 必须大于或等于1" #: superset/errors.py:136 -#, fuzzy msgid "The port number is invalid." msgstr "数据库参数无效" @@ -12249,21 +11794,23 @@ msgstr "主计量指标用于定义弧段大小。" #: superset/views/core.py:2330 msgid "The provided `rows` argument is not a valid integer." -msgstr "" +msgstr "提供的 `rows` 参数不是有效整数。" #: superset/errors.py:131 msgid "The query associated with the results was deleted." -msgstr "" +msgstr "删除与结果关联的查询。" #: superset/views/core.py:2280 msgid "" -"The query associated with these results could not be find. You need to " +"The query associated with these results could not be found. You need to " "re-run the original query." msgstr "" +"找不到与这些结果相关联的查询。你需要" +"重新运行查询" #: superset/sqllab/query_render.py:113 msgid "The query contains one or more malformed template parameters." -msgstr "" +msgstr "该查询包含一个或多个格式不正确的模板参数。" #: superset-frontend/src/SqlLab/actions/sqlLab.js:106 msgid "The query couldn't be loaded" @@ -12271,7 +11818,7 @@ msgstr "这个查询无法被加载" #: superset/errors.py:129 msgid "The query has a syntax error." -msgstr "" +msgstr "查询有语法错误。" #: superset-frontend/src/SqlLab/components/ResultSet/index.tsx:771 msgid "The query returned no data" @@ -12282,7 +11829,7 @@ msgstr "查询无结果" msgid "" "The query was killed after %(sqllab_timeout)s seconds. It might be too " "complex, or the database might be under heavy load." -msgstr "" +msgstr "查询在 %(sqllab_timeout)s 秒后被终止。它可能太复杂,或者数据库可能负载过重。" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:87 msgid "" @@ -12299,19 +11846,20 @@ msgid "" msgstr "单个点的半径(不在簇中的点)。一个数值列或“AUTO”,它根据最大的聚类来缩放点。" #: superset-frontend/src/reports/actions/reports.js:111 -#, fuzzy msgid "The report has been created" msgstr "数据集已保存" #: superset/errors.py:130 msgid "The results backend no longer has the data from the query." -msgstr "" +msgstr "结果后端不再拥有来自查询的数据。" #: superset/errors.py:132 msgid "" "The results stored in the backend were stored in a different format, and " "no longer can be deserialized." msgstr "" +"后端存储的结果以不同的格式存储,而且" +"不再可以反序列化" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:233 #: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:103 @@ -12320,23 +11868,22 @@ msgid "The rich tooltip shows a list of all series for that point in time" msgstr "详细提示显示了该时间点的所有序列的列表。" #: superset/db_engine_specs/bigquery.py:171 -#, fuzzy, python-format +#, python-format msgid "" "The schema \"%(schema)s\" does not exist. A valid schema must be used to " "run this query." msgstr "表 \"%(schema)s\" 不存在。必须使用有效的表来运行此查询。" #: superset/db_engine_specs/presto.py:187 -#, fuzzy, python-format +#, python-format msgid "" "The schema \"%(schema_name)s\" does not exist. A valid schema must be " "used to run this query." msgstr "表 \"%(schema_name)s\" 不存在。必须使用有效的表来运行此查询。" #: superset/errors.py:111 -#, fuzzy msgid "The schema was deleted or renamed in the database." -msgstr "Issue 1004 - 该列已在数据库中删除或重命名。" +msgstr "该列已在数据库中删除或重命名。" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:92 msgid "The size of the square cell, in pixels" @@ -12344,14 +11891,14 @@ msgstr "平方单元的大小,以像素为单位" #: superset/errors.py:114 msgid "The submitted payload has the incorrect format." -msgstr "" +msgstr "提交的有效载荷格式不正确" #: superset/errors.py:115 msgid "The submitted payload has the incorrect schema." -msgstr "" +msgstr "提交的有效负载的模式不正确。" #: superset/db_engine_specs/bigquery.py:158 -#, fuzzy, python-format +#, python-format msgid "" "The table \"%(table)s\" does not exist. A valid table must be used to run" " this query." @@ -12371,7 +11918,6 @@ msgid "" msgstr "表被创建。作为这两个阶段配置过程的一部分,您现在应该单击新表的编辑按钮来配置它。" #: superset/errors.py:100 -#, fuzzy msgid "The table was deleted or renamed in the database." msgstr "Issue 1005 - 该表已在数据库中删除或重命名。" @@ -12438,13 +11984,13 @@ msgid "The user seems to have been deleted" msgstr "用户已经被删除" #: superset/db_engine_specs/postgres.py:112 -#, fuzzy, python-format +#, python-format msgid "The username \"%(username)s\" does not exist." -msgstr "指标 '%(metric)s' 不存在" +msgstr "指标 '%(username)s' 不存在" #: superset/errors.py:107 msgid "The username provided when connecting to a database is not valid." -msgstr "" +msgstr "连接到数据库时提供的用户名无效。" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:206 #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:89 @@ -12474,12 +12020,10 @@ msgid "There are no filters in this dashboard." msgstr "此看板中没有过滤条件。" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/Footer.tsx:45 -#, fuzzy msgid "There are unsaved changes." msgstr "您有一些未保存的修改。" #: superset/errors.py:95 -#, fuzzy msgid "" "There is a syntax error in the SQL query. Perhaps there was a misspelling" " or a typo." @@ -12498,7 +12042,7 @@ msgid "" msgstr "此组件没有足够的空间。请尝试减小其宽度,或增加目标宽度。" #: superset-frontend/src/views/CRUD/hooks.ts:522 -#, fuzzy, python-format +#, python-format msgid "There was an error fetching the favorite status: %s" msgstr "获取此看板的收藏夹状态时出现问题。" @@ -12507,19 +12051,17 @@ msgid "There was an error fetching your recent activity:" msgstr "获取您最近的活动时出错:" #: superset-frontend/src/components/DatabaseSelector/index.tsx:230 -#, fuzzy msgid "There was an error loading the schemas" msgstr "抱歉,这个看板在获取图表时发生错误:" #: superset-frontend/src/components/TableSelector/index.tsx:218 -#, fuzzy msgid "There was an error loading the tables" msgstr "您的请求有错误" #: superset-frontend/src/views/CRUD/hooks.ts:543 -#, fuzzy, python-format +#, python-format msgid "There was an error saving the favorite status: %s" -msgstr "获取此看板的收藏夹状态时出现问题。" +msgstr "获取此看板的收藏夹状态时出现问题: %s" #: superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx:61 msgid "There was an error with your request" @@ -12587,7 +12129,6 @@ msgid "There was an issue favoriting this dashboard." msgstr "收藏看板时候出现问题。" #: superset-frontend/src/reports/actions/reports.js:68 -#, fuzzy msgid "There was an issue fetching reports attached to this dashboard." msgstr "获取此看板的收藏夹状态时出现问题。" @@ -12596,7 +12137,7 @@ msgid "There was an issue fetching the favorite status of this dashboard." msgstr "获取此看板的收藏夹状态时出现问题。" #: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:195 -#, fuzzy, python-format +#, python-format msgid "There was an issue fetching your recent activity: %s" msgstr "获取您最近的活动时出错:" @@ -12611,17 +12152,17 @@ msgid "There was an issue previewing the selected query. %s" msgstr "预览所选查询时出现问题。%s" #: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:222 -#, fuzzy, python-format +#, python-format msgid "There was an issues fetching your chart: %s" msgstr "删除时出现问题:%s" #: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:211 -#, fuzzy, python-format +#, python-format msgid "There was an issues fetching your dashboards: %s" msgstr "删除所选仪表板时出现问题:" #: superset-frontend/src/views/CRUD/welcome/Welcome.tsx:233 -#, fuzzy, python-format +#, python-format msgid "There was an issues fetching your saved queries: %s" msgstr "删除所选查询时出现问题:%s" @@ -12678,7 +12219,7 @@ msgstr "此操作将永久删除模板。" msgid "" "This can be either an IP address (e.g. 127.0.0.1) or a domain name (e.g. " "mydatabase.com)." -msgstr "" +msgstr "这可以是一个IP地址(例如127.0.0.1)或一个域名(例如127.0.0.1)" #: superset-frontend/src/dashboard/actions/dashboardLayout.js:258 msgid "This chart has been moved to a different filter scope." @@ -12686,22 +12227,21 @@ msgstr "此图表已移至其他过滤器范围内。" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.ts:56 msgid "This chart might be incompatible with the filter (datasets don't match)" -msgstr "" +msgstr "此图表可能与过滤器不兼容(数据集不匹配)" #: superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx:127 msgid "" "This color scheme is being overriden by custom label colors.\n" " Check the JSON metadata in the Advanced settings" -msgstr "" +msgstr "此配色方案正被自定义标签颜色覆盖。" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:480 #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:496 -#, fuzzy msgid "This column must contain date/time information." msgstr "包含行信息的数据库列" #: superset-frontend/src/dashboard/components/Header/index.jsx:303 -#, fuzzy, python-format +#, python-format msgid "" "This dashboard is currently auto refreshing; the next auto refresh will " "be in %s." @@ -12721,12 +12261,10 @@ msgid "" msgstr "此看板未发布,它将不会显示在看板列表中。单击此处以发布此看板。" #: superset-frontend/src/dashboard/actions/dashboardState.js:125 -#, fuzzy msgid "This dashboard is now hidden" msgstr "无法修改该看板" #: superset-frontend/src/dashboard/actions/dashboardState.js:124 -#, fuzzy msgid "This dashboard is now published" msgstr "当前看板 ${nowPublished}" @@ -12761,7 +12299,7 @@ msgid "" " replacement feature <a " "href='https://superset.apache.org/docs/installation/alerts-" "reports'>Alerts & Reports documentation</a>" -msgstr "" +msgstr "此功能已弃用,将在2.0中删除。" #: superset/connectors/sqla/views.py:447 msgid "" @@ -12771,12 +12309,12 @@ msgstr "这个字段执行Superset视图时,意味着Superset将以子查询 #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx:105 msgid "This filter doesn't exist in dashboard. It will not be applied." -msgstr "" +msgstr "此过滤器在仪表板中不存在。它不会被应用。" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx:165 #, python-format msgid "This filter set is identical to: \"%s\"" -msgstr "" +msgstr "此过滤器集等同于: \"%s\" " #: superset/connectors/sqla/views.py:358 msgid "" @@ -12818,7 +12356,7 @@ msgstr "这个查询使用了 %s 秒去执行," msgid "" "This section allows you to configure how to use the slice\n" " to generate annotations." -msgstr "" +msgstr "此部分允许您配置如何使用切片生成注释。" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/advancedAnalytics.tsx:27 #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:244 @@ -12832,11 +12370,11 @@ msgstr "本节包含允许对查询结果进行高级分析处理后的选项。 #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:84 msgid "This value should be greater than the left target value" -msgstr "" +msgstr "这个值应该大于左边的目标值" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:79 msgid "This value should be smaller than the right target value" -msgstr "" +msgstr "这个值应该小于正确的目标值" #: superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx:67 msgid "This visualization type is not supported." @@ -12848,7 +12386,7 @@ msgstr "这是由以下因素引发的:" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:74 msgid "Threshold alpha level for determining significance" -msgstr "" +msgstr "确定重要性的阈值α水平" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:60 msgid "Thursday" @@ -12907,7 +12445,6 @@ msgid "Time Range" msgstr "时间范围" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:86 -#, fuzzy msgid "Time Series" msgstr "时间序列" @@ -12948,7 +12485,6 @@ msgid "Time Series - Stacked" msgstr "时间序列 - 堆积图" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:67 -#, fuzzy msgid "Time Series Options" msgstr "时间序列的列" @@ -12972,10 +12508,9 @@ msgstr "时间列" #: superset/connectors/sqla/models.py:1173 #, python-format msgid "Time column \"%(col)s\" does not exist in dataset" -msgstr "" +msgstr "时间列 \"%(col)s\" 在数据集中不存在" #: superset-frontend/src/filters/components/TimeColumn/index.ts:29 -#, fuzzy msgid "Time column filter plugin" msgstr "选择过滤器" @@ -12989,7 +12524,7 @@ msgstr "时间比较" msgid "" "Time delta is ambiguous. Please specify [%(human_readable)s ago] or " "[%(human_readable)s later]." -msgstr "" +msgstr "时间是模糊的。" #: superset/connectors/druid/views.py:317 msgid "" @@ -13001,12 +12536,10 @@ msgstr "当检索不同的值以填充过滤器组件时,时间表达式用作 #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:296 #: superset-frontend/src/filters/components/Time/index.ts:27 -#, fuzzy msgid "Time filter" msgstr "日期过滤器" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx:450 -#, fuzzy msgid "Time format" msgstr "时间格式" @@ -13017,7 +12550,6 @@ msgid "Time grain" msgstr "时间粒度(grain)" #: superset-frontend/src/filters/components/TimeGrain/index.ts:29 -#, fuzzy msgid "Time grain filter plugin" msgstr "范围过滤器" @@ -13072,43 +12604,40 @@ msgstr "时间偏移" msgid "" "Time string is ambiguous. Please specify [%(human_readable)s ago] or " "[%(human_readable)s later]." -msgstr "" +msgstr "时间字符串是模糊的。" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:75 -#, fuzzy msgid "Time-series Area Chart" -msgstr "时间序列-条形图" +msgstr "时间序列条形图" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts:65 msgid "" "Time-series Area chart are similar to line chart in that they represent " "variables with the same scale, but area charts stack the metrics on top " "of each other. An area chart in Superset can be stream, stack, or expand." -msgstr "" +msgstr "时间序列面积图与折线图相似,因为它们表示具有相同比例的变量,但面积图将度量叠加在一起。超级集中的面积图可以是流式、堆栈式或展开式" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:35 msgid "Time-series Bar Chart" msgstr "时间序列-条形图" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:75 -#, fuzzy msgid "Time-series Bar Chart v2" -msgstr "时间序列-条形图" +msgstr "时间序列条形图 v2" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:61 msgid "" "Time-series Bar Charts are used to show the changes in a metric over time" " as a series of bars." -msgstr "" +msgstr "时间序列条形图用于显示指标随时间的变化" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:69 msgid "Time-series Chart" msgstr "时间序列图" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts:70 -#, fuzzy msgid "Time-series Line Chart" -msgstr "时间序列图" +msgstr "时间序列折线图" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:30 msgid "Time-series Percent Change" @@ -13119,32 +12648,29 @@ msgid "Time-series Period Pivot" msgstr "时间序列-周期轴" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:69 -#, fuzzy msgid "Time-series Scatter Plot" -msgstr "时间序列图" +msgstr "时间序列散点图" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Scatter/index.ts:59 msgid "" "Time-series Scatter Plot has time on the horizontal axis in linear units," " and the points are connected in order. It shows a statistical " "relationship between two variables." -msgstr "" +msgstr "时间序列散点图在水平轴上以线性单位表示时间,点按顺序连接。它显示了两个变量之间的统计关系" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:69 -#, fuzzy msgid "Time-series Smooth Line" -msgstr "时间序列-表格" +msgstr "时间序列光滑曲线图" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/SmoothLine/index.ts:59 msgid "" "Time-series Smooth-line is a variation of line chart. Without angles and " "hard edges, Smooth-line looks more smarter and more professional." -msgstr "" +msgstr "时间序列平滑线是折线图的变体。没有角度和硬边,平滑线看起来更聪明、更专业。" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:60 -#, fuzzy msgid "Time-series Stepped Line" -msgstr "时间序列-表格" +msgstr "时间序列阶梯图" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:50 msgid "" @@ -13152,7 +12678,7 @@ msgid "" " line chart but with the line forming a series of steps between data " "points. A step chart can be useful when you want to show the changes that" " occur at irregular intervals." -msgstr "" +msgstr "“时间序列步进折线图(也称为步进图)是折线图的一种变体,但线条在数据点之间形成一系列步进。当您希望显示不规则间隔发生的变化时,步进图可能很有用。”" #: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:25 msgid "Time-series Table" @@ -13164,7 +12690,7 @@ msgid "" "over regular time intervals. Line chart is a type of chart which displays" " information as a series of data points connected by straight line " "segments. It is a basic type of chart common in many fields." -msgstr "" +msgstr "时间序列折线图用于可视化在规则时间间隔内进行的重复测量。折线图是一种图表,它将信息显示为一系列由直线段连接的数据点。它是许多领域中常见的一种基本类型的图表。" #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:98 msgid "Timeout error" @@ -13176,23 +12702,21 @@ msgstr "时间戳格式" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:73 #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:372 -#, fuzzy msgid "Timestamp format" msgstr "时间戳格式" #: superset-frontend/src/components/ReportModal/index.tsx:378 #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1223 msgid "Timezone" -msgstr "" +msgstr "时区" #: superset/connectors/druid/views.py:312 superset/connectors/sqla/views.py:438 msgid "Timezone offset (in hours) for this datasource" msgstr "数据源的时差(单位:小时)" #: superset-frontend/src/components/TimezoneSelector/index.tsx:120 -#, fuzzy msgid "Timezone selector" -msgstr "运行选定的查询" +msgstr "时区选择" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:35 #: superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts:69 @@ -13207,14 +12731,12 @@ msgid "Title" msgstr "标题" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:509 -#, fuzzy msgid "Title Column" -msgstr "时间列" +msgstr "标题栏" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/DividerConfigForm.tsx:45 -#, fuzzy msgid "Title is required" -msgstr "字段是必需的" +msgstr "标题是必填项" #: superset/dashboards/filters.py:33 msgid "Title or Slug" @@ -13233,36 +12755,30 @@ msgid "Toggle chart description" msgstr "切换图表说明" #: superset-frontend/src/visualizations/FilterBox/FilterBoxChartPlugin.js:25 -#, fuzzy msgid "Tools" -msgstr "角色" +msgstr "工具" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:184 -#, fuzzy msgid "Tooltip" msgstr "详细提示" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:172 -#, fuzzy msgid "Tooltip sort by metric" msgstr "排序指标" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:162 -#, fuzzy msgid "Tooltip time format" msgstr "时间格式" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:289 -#, fuzzy msgid "Top" -msgstr "停止" +msgstr "顶部" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:139 msgid "Top to Bottom" -msgstr "" +msgstr "点击回顶部" #: superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:439 -#, fuzzy msgid "Totals" msgstr "显示总计" @@ -13280,7 +12796,7 @@ msgstr "跟踪任务" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/index.ts:67 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:76 msgid "Transformable" -msgstr "" +msgstr "转换" #: superset-frontend/src/dashboard/util/backgroundStyleOptions.ts:25 msgid "Transparent" @@ -13291,33 +12807,29 @@ msgid "Transpose Pivot" msgstr "转置透视图" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:173 -#, fuzzy msgid "Transpose pivot" msgstr "转置透视图" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:39 -#, fuzzy msgid "Tree Chart" -msgstr "共享图表" +msgstr "树状图" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:117 msgid "Tree layout" -msgstr "" +msgstr "布局" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:134 -#, fuzzy msgid "Tree orientation" msgstr "方向" #: superset-frontend/plugins/legacy-plugin-chart-treemap/src/index.js:40 #: superset/viz.py:1003 msgid "Treemap" -msgstr "树状图" +msgstr "树状地图" #: superset-frontend/plugins/plugin-chart-echarts/src/Treemap/index.ts:56 -#, fuzzy msgid "Treemap v2" -msgstr "树状图" +msgstr "树状地图 v2" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:37 #: superset-frontend/plugins/legacy-plugin-chart-rose/src/index.js:37 @@ -13328,14 +12840,12 @@ msgstr "树状图" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:40 #: superset-frontend/plugins/plugin-chart-echarts/src/Funnel/index.ts:59 #: superset-frontend/src/visualizations/TimeTable/TimeTableChartPlugin.ts:36 -#, fuzzy msgid "Trend" -msgstr "开始时间" +msgstr "趋势" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:226 -#, fuzzy msgid "Triangle" -msgstr "自定义区间" +msgstr "三角形" #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1168 msgid "Trigger Alert If..." @@ -13349,7 +12859,7 @@ msgstr "如果 ... 则触发警报" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:271 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:274 msgid "Truncate Y Axis" -msgstr "" +msgstr "截断Y轴" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx:343 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/controlPanel.tsx:258 @@ -13358,7 +12868,7 @@ msgstr "" #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Step/controlPanel.tsx:274 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/controlPanel.tsx:277 msgid "Truncate Y Axis. Can be overridden by specifying a min or max bound." -msgstr "" +msgstr "截断Y轴。可以通过指定最小或最大界限来重写。" #: superset-frontend/src/explore/components/controls/DateFilterControl/components/DateFunctionTooltip.tsx:58 msgid "Truncates the specified date to the accuracy specified by the date unit." @@ -13366,7 +12876,7 @@ msgstr "将指定的日期截取为指定的日期单位精度。" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx:222 msgid "Try applying different filters or ensuring your datasource has data" -msgstr "" +msgstr "尝试应用不同的筛选器或确保您的数据源包含数据。“" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:58 msgid "Tuesday" @@ -13389,13 +12899,12 @@ msgid "Type \"%s\" to confirm" msgstr "键入 \"%s\" 来确认" #: superset-frontend/src/components/ListView/Filters/Search.tsx:71 -#, fuzzy msgid "Type a value" -msgstr "在这里键入一个值" +msgstr "请输入值" #: superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx:319 msgid "Type a value here" -msgstr "在这里键入一个值" +msgstr "请输入值" #: superset/reports/commands/exceptions.py:71 msgid "Type is required" @@ -13403,7 +12912,7 @@ msgstr "类型是必需的" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:73 msgid "Type of Google Sheets allowed" -msgstr "" +msgstr "接受Google Sheets的类型" #: superset-frontend/src/visualizations/FilterBox/FilterBox.jsx:379 #, python-format @@ -13416,9 +12925,8 @@ msgstr "键入或选择 [%s]" #: superset-frontend/src/filters/components/Time/controlPanel.ts:45 #: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:25 #: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:25 -#, fuzzy msgid "UI Configuration" -msgstr "过滤配置" +msgstr "UI 配置" #: superset-frontend/src/explore/controlPanels/TimeTable.js:51 msgid "URL" @@ -13429,9 +12937,8 @@ msgid "URL Parameters" msgstr "URL参数" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:125 -#, fuzzy msgid "URL could not be identified" -msgstr "这个查询无法被加载。" +msgstr "无法识别的URL。" #: superset-frontend/src/explore/controlPanels/sections.tsx:60 msgid "URL parameters" @@ -13448,16 +12955,16 @@ msgstr "无法将新选项卡添加到后端。请与管理员联系。" #: superset/db_engine_specs/presto.py:218 #, python-format msgid "Unable to connect to catalog named \"%(catalog_name)s\"." -msgstr "" +msgstr "无法连接到名为\%(catalog_name)s\的目录。" #: superset/db_engine_specs/mysql.py:139 #: superset/db_engine_specs/postgres.py:145 #, python-format msgid "Unable to connect to database \"%(database)s\"." -msgstr "" +msgstr "不能连接到数据库\"%(database)s\"" #: superset/utils/date_parser.py:390 -#, fuzzy, python-format +#, python-format msgid "Unable to find such a holiday: [%(holiday)s]" msgstr "找不到这样的假期:[{}]" @@ -13494,7 +13001,7 @@ msgstr "" "内。错误消息:%(error_msg)s" #: superset/views/database/views.py:538 -#, fuzzy, python-format +#, python-format msgid "" "Unable to upload Columnar file \"%(filename)s\" to table " "\"%(table_name)s\" in database \"%(db_name)s\". Error message: " @@ -13535,19 +13042,17 @@ msgid "Unexpected error occurred, please check your logs for details" msgstr "发生意外错误,请检查日志以了解详细信息" #: superset-frontend/src/utils/getClientErrorObject.ts:55 -#, fuzzy msgid "Unexpected error: " msgstr "意外错误。" #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:95 -#, fuzzy msgid "Unknown" -msgstr "云南" +msgstr "未知" #: superset/db_engine_specs/mysql.py:129 #, python-format msgid "Unknown MySQL server host \"%(hostname)s\"." -msgstr "" +msgstr "未知MySQL服务器主机 \"%(hostname)s\"." #: superset/db_engine_specs/presto.py:1005 msgid "Unknown Presto Error" @@ -13555,12 +13060,12 @@ msgstr "未知 Presto 错误" #: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:111 msgid "Unknown Status" -msgstr "" +msgstr "未知状态" #: superset/connectors/sqla/models.py:1121 #, python-format msgid "Unknown column used in orderby: %(col)s" -msgstr "" +msgstr "订单中使用的未知列: %(col)s" #: superset-frontend/src/SqlLab/actions/sqlLab.js:349 #: superset-frontend/src/SqlLab/actions/sqlLab.js:389 @@ -13568,7 +13073,6 @@ msgid "Unknown error" msgstr "未知错误" #: superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/utils/index.ts:45 -#, fuzzy msgid "Unknown value" msgstr "未知错误" @@ -13590,7 +13094,7 @@ msgstr "未选择的条件 (%d)" #: superset/utils/core.py:1048 #, python-format msgid "Unsupported clause type: %(clause)s" -msgstr "" +msgstr "不支持的条款类型: %(clause)s" #: superset/connectors/druid/models.py:1492 msgid "Unsupported extraction function: " @@ -13639,7 +13143,6 @@ msgid "Upload" msgstr "上传" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:134 -#, fuzzy msgid "Upload Credentials" msgstr "上传验证文件" @@ -13649,7 +13152,7 @@ msgstr "上传Excel" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:102 msgid "Upload JSON file" -msgstr "" +msgstr "上传JSON文件" #: superset/initialization/__init__.py:369 msgid "Upload CSV to database" @@ -13660,26 +13163,23 @@ msgid "Upload a Columnar File" msgstr "上传列式存储文件" #: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:112 -#, fuzzy msgid "Use Area Proportions" -msgstr "桶断点" +msgstr "使用面积比例" #: superset/views/database/forms.py:175 superset/views/database/forms.py:433 -#, fuzzy, python-format +#, python-format msgid "Use Columns" -msgstr "%s 列" +msgstr "使用列" #: superset/views/database/forms.py:211 msgid "Use Pandas to interpret the datetime format automatically." msgstr "使用Pandas自动解释日期时间格式。" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:207 -#, fuzzy msgid "Use a log scale" msgstr "使用Y轴的对数刻度" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:107 -#, fuzzy msgid "Use a log scale for the X-axis" msgstr "使用Y轴的对数刻度" @@ -13689,7 +13189,7 @@ msgstr "使用Y轴的对数刻度" #: superset/db_engine_specs/base.py:1401 msgid "Use an encrypted connection to the database" -msgstr "" +msgstr "使用到数据库的加密连接" #: superset-frontend/src/components/Datasource/DatasourceModal.tsx:209 msgid "Use legacy datasource editor" @@ -13697,21 +13197,21 @@ msgstr "使用旧数据源编辑器" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:85 msgid "Use metrics as a top level group for columns or for rows" -msgstr "" +msgstr "将指标作为列或行的顶级组使用" #: superset-frontend/src/filters/components/Range/controlPanel.ts:68 msgid "Use only a single value." -msgstr "" +msgstr "只使用一个值" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:124 msgid "Use the Advanced Analytics options below" -msgstr "" +msgstr "使用下面的高级分析选项" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx:136 msgid "" "Use the JSON file you automatically downloaded when creating your service" " account." -msgstr "" +msgstr "使用您在创建服务帐户时自动下载的JSON文件" #: superset/templates/superset/fab_overrides/list_with_checkboxes.html:82 msgid "Use the edit buttom to change this field" @@ -13736,7 +13236,7 @@ msgid "" "\n" " This chart is being deprecated and we recommend checking out Pivot " "Table V2 instead!" -msgstr "" +msgstr "用于通过将多个统计数据分组来总结一组数据" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/index.ts:51 msgid "" @@ -13744,7 +13244,7 @@ msgid "" "along two axes. Examples: Sales numbers by region and month, tasks by " "status and assignee, active users by age and location. Not the most " "visually stunning visualization, but highly informative and versatile." -msgstr "" +msgstr "用于通过将多个统计信息分组在一起来汇总一组数据" #: superset-frontend/src/components/Menu/MenuRight.tsx:158 #: superset-frontend/src/views/CRUD/data/query/QueryList.tsx:275 @@ -13760,12 +13260,10 @@ msgid "User Roles" msgstr "用户角色" #: superset/errors.py:112 -#, fuzzy msgid "User doesn't have the proper permissions." msgstr "您没有授权 " #: superset-frontend/src/filters/components/Select/controlPanel.ts:94 -#, fuzzy msgid "User must select a value before applying the filter" msgstr "用户必须给过滤器选择一个值" @@ -13778,7 +13276,6 @@ msgstr "用户必须给过滤器选择一个值" #: superset-frontend/src/filters/components/Time/controlPanel.ts:56 #: superset-frontend/src/filters/components/TimeColumn/controlPanel.ts:36 #: superset-frontend/src/filters/components/TimeGrain/controlPanel.ts:36 -#, fuzzy msgid "User must select a value for this filter." msgstr "用户必须给过滤器选择一个值" @@ -13788,16 +13285,15 @@ msgstr "用户查询" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:109 #: superset/db_engine_specs/base.py:1388 -#, fuzzy msgid "Username" -msgstr "查询名称" +msgstr "用户名" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts:39 msgid "" "Uses a gauge to showcase progress of a metric towards a target. The " "position of the dial represents the progress and the terminal value in " "the gauge represents the target value." -msgstr "" +msgstr "使用一个度量来展示实现目标的度量的进展" #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js:28 msgid "" @@ -13805,7 +13301,7 @@ msgid "" "system. Hover over individual paths in the visualization to understand " "the stages a value took. Useful for multi-stage, multi-group visualizing " "funnels and pipelines." -msgstr "" +msgstr "使用圆圈来可视化系统不同阶段的数据流。" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx:294 #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:1186 @@ -13828,25 +13324,22 @@ msgstr "值边界" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:165 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:206 -#, fuzzy msgid "Value format" msgstr "数值格式" #: superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx:75 -#, fuzzy msgid "Value is required" msgstr "需要名称" #: superset/reports/schemas.py:185 superset/reports/schemas.py:191 #: superset/reports/schemas.py:197 superset/reports/schemas.py:275 #: superset/reports/schemas.py:281 superset/reports/schemas.py:288 -#, fuzzy msgid "Value must be greater than 0" msgstr "`行偏移量` 必须大于或等于0" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:39 msgid "Vehicle Types" -msgstr "" +msgstr "类型" #: superset/connectors/druid/views.py:189 #: superset/connectors/druid/views.py:238 superset/connectors/sqla/views.py:144 @@ -13855,24 +13348,22 @@ msgid "Verbose Name" msgstr "全称" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:482 -#, fuzzy msgid "Version" -msgstr "维度" +msgstr "版本" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:489 msgid "Version number" -msgstr "" +msgstr "版本" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:41 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DistBar/index.js:48 #: superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:84 -#, fuzzy msgid "Vertical" -msgstr "虚拟信息" +msgstr "垂直" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:38 msgid "Video game consoles" -msgstr "" +msgstr "控制台" #: superset-frontend/src/views/CRUD/welcome/ChartTable.tsx:217 #: superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx:219 @@ -13914,7 +13405,6 @@ msgid "Viewed" msgstr "已查看" #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:124 -#, fuzzy, python-format msgid "Viewed %s" msgstr "已查看" @@ -13931,7 +13421,6 @@ msgid "Virtual dataset" msgstr "虚拟数据集" #: superset/connectors/sqla/models.py:849 superset/connectors/sqla/utils.py:83 -#, fuzzy msgid "Virtual dataset query cannot be empty" msgstr "虚拟数据集查询必须是只读的" @@ -13966,33 +13455,33 @@ msgid "" "Visualize a parallel set of metrics across multiple groups. Each group is" " visualized using its own line of points and each metric is represented " "as an edge in the chart." -msgstr "" +msgstr "在多个组中可视化一组平行的度量。每个组都使用自己的点线进行可视化,每个度量在图表中表示为一条边。" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/index.js:30 msgid "" "Visualize a related metric across pairs of groups. Heatmaps excel at " "showcasing the correlation or strength between two groups. Color is used " "to emphasize the strength of the link between each pair of groups." -msgstr "" +msgstr "可视化各组之间的相关指标。热图擅长显示两组之间的相关性或强度。颜色用于强调各组之间的联系强度。" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bar/index.js:31 msgid "" "Visualize how a metric changes over time using bars. Add a group by " "column to visualize group level metrics and how they change over time." -msgstr "" +msgstr "使用条形图可视化指标随时间的变化。按列添加分组以可视化分组级别的指标及其随时间变化的方式。" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/index.ts:35 msgid "" "Visualize multiple levels of hierarchy using a familiar tree-like " "structure." -msgstr "" +msgstr "使用熟悉的树状结构可视化多层次结构。" #: superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts:58 msgid "" "Visualize two different time series using the same x-axis time range. " "Note that each time series can be visualized differently (e.g. 1 using " "bars and 1 using a line)." -msgstr "" +msgstr "使用相同的x轴时间范围可视化两个不同的时间序列。请注意,每个时间序列可以以不同的方式可视化(例如1个使用条形图,1个使用线条)。" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:27 msgid "" @@ -14000,26 +13489,29 @@ msgid "" "This chart is being deprecated and we recommend using the Mixed " "Timeseries Chart instead!" msgstr "" +"使用相同的x轴时间范围可视化两个不同的时间序列。" +"此图表已被弃用,我们建议使用混合" +"改为时间序列图!" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/index.js:27 msgid "" "Visualizes 2 metrics as line plots using the same x-axis. This chart is " "useful for comparing metrics across the same time range." -msgstr "" +msgstr "使用相同的x轴将2个指标可视化为折线图。此图表可用于比较相同时间范围内的指标。" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:27 msgid "" "Visualizes a metric across three dimensions of data in a single chart (X " "axis, Y axis, and bubble size). Bubbles from the same group can be " "showcased using bubble color." -msgstr "" +msgstr "在单个图表中跨三维数据(X轴、Y轴和气泡大小)可视化度量。同一组中的气泡可以“使用气泡颜色显示" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/index.js:27 msgid "" "Visualizes how a metric has changed over a time using a color scale and a" " calendar view. Gray values are used to indicate missing values and the " "linear color scheme is used to encode the magnitude of each day's value." -msgstr "" +msgstr "使用色标和日历视图可视化指标在一段时间内的变化情况。灰色值用于指示缺少的值,线性配色方案用于编码每天值的大小。" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/index.js:27 msgid "" @@ -14027,14 +13519,14 @@ msgid "" "subdivisions (states, provinces, etc) on a chloropleth map. Each " "subdivision's value is elevated when you hover over the corresponding " "geographic boundary." -msgstr "" +msgstr "在叶绿体地图上显示一个国家的主要分区(州、省等)之间单个指标的变化情况。当您悬停在相应的地理边界上时,每个分区的值都会升高" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Compare/index.js:27 msgid "" "Visualizes many different time-series objects in a single chart. This " "chart is being deprecated and we recommend using the Time-series Chart " "instead." -msgstr "" +msgstr "在一个图表中显示许多不同的时间序列对象。此图表已被弃用,建议改用时间序列图表" #: superset-frontend/plugins/legacy-plugin-chart-sankey/src/index.js:29 msgid "" @@ -14042,13 +13534,13 @@ msgid "" "of a system. New stages in the pipeline are visualized as nodes or " "layers. The thickness of the bars or edges represent the metric being " "visualized." -msgstr "" +msgstr "可视化不同组的值在系统不同阶段的流动。管道中的新阶段被可视化为节点或层。条形或边缘的厚度表示正在可视化的度量。" #: superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts:35 msgid "" "Visualizes the words in a column that appear the most often. Bigger font " "corresponds to higher frequency." -msgstr "" +msgstr "可视化列中出现频率最高的单词。字体越大,出现频率越高。" #: superset/viz.py:133 msgid "Viz is missing a datasource" @@ -14064,10 +13556,9 @@ msgstr "星期三" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:697 msgid "Want to add a new database?" -msgstr "" +msgstr "添加一个新数据库?" #: superset-frontend/src/components/Datasource/DatasourceEditor.jsx:1090 -#, fuzzy msgid "Warning" msgstr "警告!" @@ -14086,12 +13577,12 @@ msgid "" msgstr "警告!如果元数据不存在,更改数据集可能会破坏图表。" #: superset/db_engine_specs/bigquery.py:166 -#, fuzzy, python-format +#, python-format msgid "We can't seem to resolve column \"%(column)s\" at line %(location)s." msgstr "我们似乎无法解析行 %(location)s 所处的列 \"%(column_name)s\" 。" #: superset/db_engine_specs/sqlite.py:63 -#, fuzzy, python-format +#, python-format msgid "We can't seem to resolve the column \"%(column_name)s\"" msgstr "我们似乎无法解析行 %(location)s 所处的列 \"%(column_name)s\" 。" @@ -14109,57 +13600,53 @@ msgstr "我们建议您在遵循流程之前进一步总结数据。" #: superset-frontend/src/reports/actions/reports.js:156 msgid "We were unable to active or deactivate this report." -msgstr "" +msgstr "“我们无法激活或禁用该报告。" #: superset/db_engine_specs/redshift.py:86 #, python-format msgid "" "We were unable to connect to your database named \"%(database)s\". Please" " verify your database name and try again." -msgstr "" +msgstr "我们无法连接到名为 \"%(database)s\" 的数据库。请确认您的数据库名字并重试" #: superset/db_engine_specs/bigquery.py:149 msgid "" "We were unable to connect to your database. Please confirm that your " "service account has the Viewer and Job User roles on the project." -msgstr "" +msgstr "我们无法连接到您的数据库。请确认您的服务帐户在项目中具有查看器和作业用户角色。" #: superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts:60 msgid "Web" -msgstr "" +msgstr "网络" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:59 msgid "Wednesday" msgstr "星期三" #: superset/db_engine_specs/base.py:97 -#, fuzzy msgid "Week" msgstr "周" #: superset/db_engine_specs/base.py:103 msgid "Week ending Saturday" -msgstr "" +msgstr "周一为一周结束" #: superset/db_engine_specs/base.py:102 -#, fuzzy msgid "Week starting Monday" msgstr "周一为一周开始" #: superset/db_engine_specs/base.py:101 -#, fuzzy msgid "Week starting Sunday" -msgstr "周日为一周结束" +msgstr "周日为一周开始" #: superset/db_engine_specs/base.py:104 -#, fuzzy msgid "Week_ending Sunday" msgstr "周日为一周结束" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:67 -#, fuzzy, python-format +#, python-format msgid "Weeks %s" -msgstr "周" +msgstr "周 %s" #: superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx:52 #, python-format @@ -14202,7 +13689,7 @@ msgstr "当在 SQL 编辑器中允许 CREATE TABLE AS 选项时,此选项可 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/ExtraOptions.tsx:195 msgid "When enabled, users are able to visualize SQL Lab results in Explore." -msgstr "" +msgstr "启用后,用户可以在Explore中可视化SQL实验室结果。" #: superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts:71 msgid "When only a primary metric is provided, a categorical color scale is used." @@ -14232,7 +13719,7 @@ msgstr "当使用“Group by”时,只限于使用单个度量。" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:258 msgid "Whether the progress bar overlaps when there are multiple groups of data" -msgstr "" +msgstr "当有多组数据时进度条是否重叠" #: superset/connectors/sqla/views.py:466 msgid "Whether the table was generated by the 'Visualize' flow in SQL Lab" @@ -14245,7 +13732,6 @@ msgid "" msgstr "该列是否在浏览视图的`过滤器`部分显示。" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:430 -#, fuzzy msgid "" "Whether to align background charts with both positive and negative values" " at 0" @@ -14253,29 +13739,27 @@ msgstr "是否 +/- 对齐背景图数值" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:128 msgid "Whether to align positive and negative values in cell bar chart at 0" -msgstr "" +msgstr "单元格条形图中的正负值是否按0对齐" #: superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx:739 -#, fuzzy msgid "Whether to always show the annotation label" msgstr "是否显示标签。" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:192 msgid "Whether to animate the progress and the value or just display them" -msgstr "" +msgstr "是以动画形式显示进度和值,还是仅显示它们" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:317 msgid "Whether to apply a normal distribution based on rank on the color scale" -msgstr "" +msgstr "是否应用基于色标等级的正态分布" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:138 #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:442 msgid "Whether to colorize numeric values by if they are positive or negative" -msgstr "" +msgstr "根据数值是正数还是负数来为其上色" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx:120 #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:416 -#, fuzzy msgid "Whether to display a bar chart background in table columns" msgstr "为指标添加条状图背景" @@ -14288,7 +13772,6 @@ msgid "Whether to display bubbles on top of countries" msgstr "是否在国家之上展示气泡" #: superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/src/controlPanel.ts:60 -#, fuzzy msgid "Whether to display the interactive data table" msgstr "是否将指标名显示为标题" @@ -14303,7 +13786,7 @@ msgstr "是否显示标签。" msgid "" "Whether to display the labels. Note that the label only displays when the" " the 5% threshold." -msgstr "" +msgstr "是否显示标签。" #: superset-frontend/plugins/legacy-plugin-chart-calendar/src/controlPanel.ts:157 #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts:278 @@ -14332,31 +13815,27 @@ msgid "Whether to display the numerical values within the cells" msgstr "是否在单元格内显示数值" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:141 -#, fuzzy msgid "Whether to display the time range interactive selector" msgstr "是否显示时间范围交互选择器" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:88 -#, fuzzy msgid "Whether to display the timestamp" msgstr "是否显示笔划" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx:100 -#, fuzzy msgid "Whether to display the trend line" msgstr "是否显示笔划" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:170 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:279 msgid "Whether to enable changing graph position and scaling." -msgstr "" +msgstr "是否启用更改图形位置和缩放。" #: superset-frontend/plugins/plugin-chart-echarts/src/Graph/controlPanel.tsx:144 msgid "Whether to enable node dragging in force layout mode." -msgstr "" +msgstr "是否在强制布局模式下启用节点拖动。" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts:63 -#, fuzzy msgid "Whether to format the timestamp" msgstr "是否规范化直方图" @@ -14377,7 +13856,6 @@ msgid "Whether to include the time granularity as defined in the time section" msgstr "是否包含时间段中定义的时间粒度" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts:155 -#, fuzzy msgid "Whether to make the histogram cumulative" msgstr "是否规范化直方图" @@ -14409,21 +13887,18 @@ msgid "" msgstr "是否显示额外的控件。额外的控制包括使多栏图表堆叠或并排。" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:207 -#, fuzzy msgid "Whether to show minor ticks on the axis" msgstr "是否忽略空位置" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:180 -#, fuzzy msgid "Whether to show the pointer" msgstr "是否显示笔划" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:246 msgid "Whether to show the progress of gauge chart" -msgstr "" +msgstr "是否显示量规图进度" #: superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx:219 -#, fuzzy msgid "Whether to show the split lines on the axis" msgstr "是否显示Y轴的最小值和最大值" @@ -14449,7 +13924,6 @@ msgid "Whether to sort descending or ascending" msgstr "是降序还是升序排序" #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/legacySortBy.tsx:31 -#, fuzzy msgid "" "Whether to sort descending or ascending. Takes effect only when \"Sort " "by\" is set" @@ -14470,17 +13944,16 @@ msgid "Whether to sort results by the selected metric in descending order." msgstr "是否按所选指标按降序对结果进行排序。" #: superset-frontend/plugins/plugin-chart-echarts/src/controls.tsx:175 -#, fuzzy msgid "Whether to sort tooltip by the selected metric in descending order." msgstr "是否按所选指标按降序对结果进行排序。" #: superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts:43 msgid "Which country to plot the map for?" -msgstr "" +msgstr "为哪个国家绘制地图?" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:197 msgid "Which relatives to highlight on hover" -msgstr "" +msgstr "在悬停时突出显示哪些关系" #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:51 #: superset-frontend/plugins/preset-chart-xy/src/BoxPlot/controlPanel.ts:45 @@ -14496,16 +13969,14 @@ msgid "Width" msgstr "宽度" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/forecastInterval.tsx:73 -#, fuzzy msgid "Width of the confidence interval. Should be between 0 and 1" msgstr "置信区间必须介于0和1(不包含1)之间" #: superset/utils/pandas_postprocessing.py:393 msgid "Window must be > 0" -msgstr "" +msgstr "窗口必须大于0" #: superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts:36 -#, fuzzy msgid "With a subheader" msgstr "子标题" @@ -14542,7 +14013,7 @@ msgstr "将dataframe index 作为列." #: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:51 msgid "X AXIS TITLE BOTTOM MARGIN" -msgstr "" +msgstr "X 轴标题下边距" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:31 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:147 @@ -14577,7 +14048,7 @@ msgstr "X 轴标签" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:37 msgid "X Axis Title" -msgstr "" +msgstr "X轴标题" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts:104 msgid "X Log Scale" @@ -14598,17 +14069,16 @@ msgid "XScale Interval" msgstr "X轴比例尺间隔" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:102 -#, fuzzy msgid "Y 2 bounds" msgstr "Y界限" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:79 msgid "Y AXIS TITLE MARGIN" -msgstr "" +msgstr "Y轴标题页边距" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:94 msgid "Y AXIS TITLE POSITION" -msgstr "" +msgstr "Y轴标题位置" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:59 #: superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx:153 @@ -14633,14 +14103,13 @@ msgstr "Y 轴" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:40 msgid "Y Axis 1" -msgstr "" +msgstr "Y 轴 1" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/DualLine/controlPanel.ts:50 msgid "Y Axis 2" -msgstr "" +msgstr "Y 轴 2" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:254 -#, fuzzy msgid "Y Axis 2 Bounds" msgstr "Y 轴界限" @@ -14675,7 +14144,7 @@ msgstr "Y轴右侧" #: superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx:65 msgid "Y Axis Title" -msgstr "" +msgstr "Y 轴标题" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:227 msgid "Y Log Scale" @@ -14690,12 +14159,11 @@ msgid "YScale Interval" msgstr "Y轴比例尺间隔" #: superset/db_engine_specs/base.py:100 -#, fuzzy msgid "Year" msgstr "年" #: superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts:70 -#, fuzzy, python-format +#, python-format msgid "Years %s" msgstr "年" @@ -14739,7 +14207,6 @@ msgid "" msgstr "您正在导入一个或多个已存在的数据集。覆盖可能会导致您丢失一些工作。确定要覆盖吗?" #: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:63 -#, fuzzy msgid "" "You are importing one or more saved queries that already exist. " "Overwriting might cause you to lose some of your work. Are you sure you " @@ -14750,16 +14217,15 @@ msgstr "您正在导入一个或多个已存在的图表。覆盖可能会导致 msgid "" "You are not authorized to fetch samples from this table. If you think " "this is an error, please reach out to your administrator." -msgstr "" +msgstr "您无权从这个表中获取样本。" #: superset/views/core.py:2295 msgid "" "You are not authorized to see this query. If you think this is an error, " "please reach out to your administrator." -msgstr "" +msgstr "您无权查看此查询。" #: superset/views/database/views.py:463 -#, fuzzy msgid "" "You cannot specify a namespace both in the name of the table: " "\"%(columnar_table.table)s\" and in the schema field: " @@ -14788,7 +14254,7 @@ msgstr "" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Vis.js:366 msgid "You cannot use 45° tick layout along with the time range filter" -msgstr "" +msgstr "不能将45°刻度线布局与时间范围过滤器一起使用" #: superset/viz.py:696 msgid "" @@ -14816,7 +14282,6 @@ msgid "You do not have permissions to edit this dashboard." msgstr "您没有编辑此看板的权限。" #: superset/dashboards/commands/exceptions.py:86 -#, fuzzy msgid "You don't have access to this dashboard." msgstr "您没有编辑此看板的权限。" @@ -14825,7 +14290,6 @@ msgid "You don't have any favorites yet!" msgstr "您还没有任何的收藏!" #: superset/key_value/commands/exceptions.py:45 -#, fuzzy msgid "You don't have permission to modify the value." msgstr "您没有编辑此图表的权限" @@ -14860,7 +14324,6 @@ msgid "You must run the query successfully first" msgstr "必须先成功运行查询" #: superset-frontend/src/dashboard/components/Header/index.jsx:382 -#, fuzzy msgid "Your dashboard is too large. Please reduce its size before saving it." msgstr "您的看板太大了。保存前请缩小尺寸。" @@ -14891,7 +14354,6 @@ msgid "Your query was updated" msgstr "您的查询已保存" #: superset-frontend/src/reports/actions/reports.js:172 -#, fuzzy msgid "Your report could not be deleted" msgstr "这个查询无法被加载。" @@ -14908,10 +14370,6 @@ msgstr "地图缩放等级" msgid "[Alert] %(label)s" msgstr "[警报] %(label)s" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:219 -msgid "[From]-" -msgstr "[从]-" - #: superset/viz.py:2349 msgid "[Longitude] and [Latitude] columns must be present in [Group By]" msgstr "[经度] 和 [纬度] 的选择项必须出现在 [Group By]" @@ -14921,7 +14379,6 @@ msgid "[Longitude] and [Latitude] must be set" msgstr "[经度] 和 [纬度] 的选择项必须出现在 [Group By]" #: superset/views/core.py:783 -#, fuzzy msgid "[Missing Dataset]" msgstr "丢失数据集" @@ -14930,14 +14387,10 @@ msgstr "丢失数据集" msgid "[Superset] Access to the datasource %(name)s was granted" msgstr "[Superset] 允许访问数据源 %(name)s" -#: superset-frontend/src/SqlLab/components/QuerySearch/index.tsx:231 -msgid "[To]-" -msgstr "[至]-" - #: superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx:94 -#, fuzzy, python-format +#, python-format msgid "[Untitled]" -msgstr "%s - 无标题" +msgstr "无标题" #: superset-frontend/src/dashboard/components/SaveModal.tsx:203 msgid "[dashboard name]" @@ -14952,11 +14405,11 @@ msgstr "次计量指标用来定义颜色与主度量的比率。如果两个度 #: superset/utils/pandas_postprocessing.py:519 msgid "`compare_columns` must have the same length as `source_columns`." -msgstr "" +msgstr "长度必须保持一致" #: superset/utils/pandas_postprocessing.py:523 msgid "`compare_type` must be `difference`, `percentage` or `ratio`" -msgstr "" +msgstr "`compare_type` 必须是 `difference`, `percentage` 或 `ratio`" #: superset/charts/schemas.py:557 msgid "`confidence_interval` must be between 0 and 1 (exclusive)" @@ -14974,16 +14427,14 @@ msgid "`operation` property of post processing object undefined" msgstr "后处理必须指定操作类型(`operation`)" #: superset/utils/pandas_postprocessing.py:765 -#, fuzzy msgid "`prophet` package not installed" msgstr "未安装程序包 `fbprophet`" #: superset/utils/pandas_postprocessing.py:722 msgid "`rename_columns` must have the same length as `columns`." -msgstr "" +msgstr "长度必须保持一致" #: superset/charts/schemas.py:1070 -#, fuzzy msgid "`row_limit` must be greater than or equal to 0" msgstr "`行限制` 必须大于或等于1" @@ -15017,11 +14468,11 @@ msgstr "修改这个 " #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:194 msgid "ancestor" -msgstr "" +msgstr "上一个" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:47 msgid "and" -msgstr "" +msgstr "和" #: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:111 #, python-format @@ -15044,7 +14495,7 @@ msgstr "注释层" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:48 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:50 msgid "at" -msgstr "" +msgstr "在" #: superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx:74 #: superset-frontend/src/explore/components/ControlHeader.jsx:76 @@ -15053,9 +14504,8 @@ msgstr "螺栓" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:161 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:179 -#, fuzzy msgid "bottom" -msgstr "dttm" +msgstr "底部" #: superset-frontend/src/components/CachedLabel/index.tsx:51 msgid "cached" @@ -15102,7 +14552,6 @@ msgid "column" msgstr "列" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:116 -#, fuzzy msgid "count" msgstr "列" @@ -15112,14 +14561,13 @@ msgstr "创建一个 " #: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:253 msgid "css" -msgstr "" +msgstr "css" #: superset-frontend/src/views/CRUD/csstemplates/CssTemplateModal.tsx:91 msgid "css_template" msgstr "css模板" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:120 -#, fuzzy msgid "cumulative" msgstr "激活" @@ -15168,7 +14616,6 @@ msgid "delete" msgstr "删除" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:195 -#, fuzzy msgid "descendant" msgstr "降序" @@ -15184,7 +14631,6 @@ msgid "dialect+driver://username:password@host:port/database" msgstr "" #: superset/views/core.py:618 -#, fuzzy msgid "download as csv" msgstr "下载为图片" @@ -15198,31 +14644,29 @@ msgstr "dttm" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:129 msgid "e.g. ********" -msgstr "" +msgstr "********" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:45 msgid "e.g. 127.0.0.1" -msgstr "" +msgstr "127.0.0.1" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:67 msgid "e.g. 5432" -msgstr "" +msgstr "5432" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:108 -#, fuzzy msgid "e.g. Analytics" msgstr "高级分析" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:172 msgid "e.g. param1=value1¶m2=value2" -msgstr "" +msgstr "例如:param1=value1¶m2=value2" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx:88 msgid "e.g. world_population" -msgstr "" +msgstr "世界人口" #: superset-frontend/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx:126 -#, fuzzy msgid "e.g., a \"user id\" column" msgstr "时间序列的列" @@ -15244,7 +14688,6 @@ msgid "every hour" msgstr "每小时" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:34 -#, fuzzy msgid "every minute" msgstr "每分钟 UTC" @@ -15257,34 +14700,31 @@ msgid "feature to store a summarized data set that you can then explore." msgstr "用于存储可供浏览的汇总数据集的功能。" #: superset-frontend/src/SqlLab/components/QueryTable/index.jsx:87 -#, fuzzy msgid "fetching" -msgstr "设置" +msgstr "抓取中" #: superset-frontend/src/dashboard/components/FilterBoxMigrationModal.tsx:86 #: superset-frontend/src/dashboard/containers/DashboardPage.tsx:143 msgid "" "filter_box will be deprecated in a future version of Superset. Please " "replace filter_box by dashboard filter components." -msgstr "" +msgstr "'filter_box将在Superset的未来版本中弃用。" #: superset-frontend/src/SqlLab/components/ExploreResultsButton/index.jsx:115 msgid "following this flow will most likely lead to your query timing out. " msgstr "遵循此流程很可能会导致查询超时。" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/SqlAlchemyForm.tsx:86 -#, fuzzy msgid "for more information on how to structure your URI." msgstr " 来查询有关如何构造URI的更多信息。" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:41 msgid "green" -msgstr "" +msgstr "绿色" #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:724 #: superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx:1136 -#, fuzzy -msgid "here" +msgid "shere" msgstr "分享" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:40 @@ -15303,7 +14743,7 @@ msgstr "图像渲染画布对象的 CSS 属性,它定义了浏览器如何放 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:44 msgid "in" -msgstr "" +msgstr "在" #: superset-frontend/src/explore/components/controls/TextAreaControl.jsx:122 msgid "in modal" @@ -15312,12 +14752,12 @@ msgstr "(在模型中)" #: superset-frontend/packages/superset-ui-core/src/validator/legacyValidateNumber.ts:28 #: superset-frontend/packages/superset-ui-core/src/validator/validateNumber.ts:32 msgid "is expected to be a number" -msgstr "" +msgstr "应该为数字" #: superset-frontend/packages/superset-ui-core/src/validator/legacyValidateInteger.ts:31 #: superset-frontend/packages/superset-ui-core/src/validator/validateInteger.ts:32 msgid "is expected to be an integer" -msgstr "" +msgstr "应该为为整数" #: superset-frontend/src/profile/components/UserInfo.tsx:64 msgid "joined" @@ -15330,12 +14770,12 @@ msgstr "无效 JSON" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:233 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:261 msgid "key a-z" -msgstr "" +msgstr "a-z" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:234 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:262 msgid "key z-a" -msgstr "" +msgstr "z-a" #: superset-frontend/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts:152 msgid "label" @@ -15367,7 +14807,6 @@ msgstr "最新分区:" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:158 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:176 -#, fuzzy msgid "left" msgstr "警报" @@ -15386,7 +14825,6 @@ msgid "minute" msgstr "分" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:51 -#, fuzzy msgid "minute(s)" msgstr "分钟" @@ -15397,7 +14835,7 @@ msgstr "月" #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:116 #: superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx:138 msgid "must have a value" -msgstr "" +msgstr "必填" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Area/index.js:54 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/Bubble/index.js:39 @@ -15408,21 +14846,20 @@ msgstr "" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/LineMulti/index.js:34 #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/TimePivot/index.js:29 msgid "nvd3" -msgstr "" +msgstr "nvd3" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:45 #: superset-frontend/src/components/CronPicker/CronPicker.tsx:46 msgid "on" -msgstr "" +msgstr "位于" #: superset/charts/schemas.py:1098 -#, fuzzy msgid "orderby column must be populated" msgstr "无法更新您的查询" #: superset-frontend/plugins/legacy-plugin-chart-paired-t-test/src/controlPanel.ts:85 msgid "p-value precision" -msgstr "" +msgstr "假定值精度" #: superset-frontend/plugins/plugin-chart-table/src/consts.ts:26 msgid "page_size.all" @@ -15438,7 +14875,7 @@ msgstr "" #: superset-frontend/plugins/legacy-plugin-chart-histogram/src/Histogram.jsx:124 msgid "percentile (exclusive)" -msgstr "" +msgstr "百分位数(独占)" #: superset/utils/pandas_postprocessing.py:921 msgid "" @@ -15463,7 +14900,6 @@ msgid "published" msgstr "已发布" #: superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx:543 -#, fuzzy msgid "queries" msgstr "序列" @@ -15476,14 +14912,12 @@ msgid "reboot" msgstr "重启" #: superset-frontend/src/views/CRUD/welcome/EmptyState.tsx:28 -#, fuzzy msgid "recents" msgstr "最近" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:43 -#, fuzzy msgid "red" -msgstr "开始时间" +msgstr "红色" #: superset-frontend/src/views/CRUD/alert/AlertList.tsx:90 #: superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx:484 @@ -15499,7 +14933,6 @@ msgstr "报告" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:160 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:178 -#, fuzzy msgid "right" msgstr "高度" @@ -15532,8 +14965,7 @@ msgstr "文本区域" #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:159 #: superset-frontend/plugins/plugin-chart-echarts/src/Tree/controlPanel.tsx:177 -#, fuzzy -msgid "top" +msgid "stop" msgstr "停止" #: superset/charts/schemas.py:639 @@ -15544,13 +14976,11 @@ msgstr "上百分位数必须大于0且小于100。而且必须高于下百分 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:235 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:263 -#, fuzzy msgid "value ascending" msgstr "指标升序" #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:236 #: superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx:264 -#, fuzzy msgid "value descending" msgstr "指标降序" @@ -15573,3 +15003,57 @@ msgstr "年" #: superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:42 msgid "yellow" msgstr "黄色" + +msgid "Upload file to database" +msgstr "上传文件到数据库" + +msgid "Select or type a value" +msgstr "选择或者输入值" + +msgid "Connect database" +msgstr "连接数据库" + +msgid "Upload columnar file to database" +msgstr "上传列级文件" + +msgid "Upload CSV" +msgstr "上传CSV" + +msgid "Upload columnar file" +msgstr "上传列级文件" + +msgid "Upload Excel file" +msgstr "上传Excel" + +msgid "Handlebars" +msgstr "句柄图" + +msgid "deck.gl Arc" +msgstr "圆弧图" + +msgid "Import database from file" +msgstr "从文件中导入数据库" + +msgid "Select a database to connect" +msgstr "选择将要连接的数据库" + +msgid "Select a database to write a query" +msgstr "选择要写入查询的数据库" + +msgid "Choose one of the available databases from the panel on the left." +msgstr "从左侧的面板中选择一个可用的数据库" + +msgid "Add a new tab" +msgstr "添加新的标签页" + +msgid "There are no databases available" +msgstr "没有可用的数据库" + +msgid "No databases match your search" +msgstr "没有与您的搜索匹配的数据库" + +msgid "Manage your databases" +msgstr "管理你的数据库" + +msgid "here" +msgstr "这里" diff --git a/superset/utils/async_query_manager.py b/superset/utils/async_query_manager.py index f823fb394e9a5..71559aaa3dcbc 100644 --- a/superset/utils/async_query_manager.py +++ b/superset/utils/async_query_manager.py @@ -17,11 +17,13 @@ import json import logging import uuid -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Literal, Optional, Tuple import jwt import redis -from flask import Flask, g, request, Request, Response, session +from flask import Flask, request, Request, Response, session + +from superset.utils.core import get_user_id logger = logging.getLogger(__name__) @@ -35,12 +37,12 @@ class AsyncQueryJobException(Exception): def build_job_metadata( - channel_id: str, job_id: str, user_id: Optional[str], **kwargs: Any + channel_id: str, job_id: str, user_id: Optional[int], **kwargs: Any ) -> Dict[str, Any]: return { "channel_id": channel_id, "job_id": job_id, - "user_id": int(user_id) if user_id else None, + "user_id": user_id, "status": kwargs.get("status"), "errors": kwargs.get("errors", []), "result_url": kwargs.get("result_url"), @@ -75,9 +77,10 @@ def __init__(self) -> None: self._stream_prefix: str = "" self._stream_limit: Optional[int] self._stream_limit_firehose: Optional[int] - self._jwt_cookie_name: str + self._jwt_cookie_name: str = "" self._jwt_cookie_secure: bool = False self._jwt_cookie_domain: Optional[str] + self._jwt_cookie_samesite: Optional[Literal["None", "Lax", "Strict"]] = None self._jwt_secret: str def init_app(self, app: Flask) -> None: @@ -108,18 +111,13 @@ def init_app(self, app: Flask) -> None: ] self._jwt_cookie_name = config["GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME"] self._jwt_cookie_secure = config["GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE"] + self._jwt_cookie_samesite = config["GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE"] self._jwt_cookie_domain = config["GLOBAL_ASYNC_QUERIES_JWT_COOKIE_DOMAIN"] self._jwt_secret = config["GLOBAL_ASYNC_QUERIES_JWT_SECRET"] @app.after_request def validate_session(response: Response) -> Response: - user_id = None - - try: - user_id = g.user.get_id() - user_id = int(user_id) - except Exception: # pylint: disable=broad-except - pass + user_id = get_user_id() reset_token = ( not request.cookies.get(self._jwt_cookie_name) @@ -146,6 +144,7 @@ def validate_session(response: Response) -> Response: httponly=True, secure=self._jwt_cookie_secure, domain=self._jwt_cookie_domain, + samesite=self._jwt_cookie_samesite, ) return response @@ -161,7 +160,7 @@ def parse_jwt_from_request(self, req: Request) -> Dict[str, Any]: logger.warning("Parse jwt failed", exc_info=True) raise AsyncQueryTokenException("Failed to parse token") from ex - def init_job(self, channel_id: str, user_id: Optional[str]) -> Dict[str, Any]: + def init_job(self, channel_id: str, user_id: Optional[int]) -> Dict[str, Any]: job_id = str(uuid.uuid4()) return build_job_metadata( channel_id, job_id, user_id, status=self.STATUS_PENDING diff --git a/superset/utils/core.py b/superset/utils/core.py index 76e566a895f86..6f86372f753f6 100644 --- a/superset/utils/core.py +++ b/superset/utils/core.py @@ -16,6 +16,8 @@ # under the License. """Utility functions used across Superset""" # pylint: disable=too-many-lines +from __future__ import annotations + import _thread import collections import decimal @@ -34,6 +36,7 @@ import uuid import zlib from contextlib import contextmanager +from dataclasses import dataclass from datetime import date, datetime, time, timedelta from distutils.util import strtobool from email.mime.application import MIMEApplication @@ -71,9 +74,8 @@ import numpy as np import pandas as pd import sqlalchemy as sa -from cryptography import x509 from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.backends.openssl.x509 import _Certificate +from cryptography.x509 import Certificate, load_pem_x509_certificate from flask import current_app, flash, g, Markup, render_template, request from flask_appbuilder import SQLA from flask_appbuilder.security.sqla.models import Role, User @@ -93,6 +95,7 @@ EXTRA_FORM_DATA_APPEND_KEYS, EXTRA_FORM_DATA_OVERRIDE_EXTRA_KEYS, EXTRA_FORM_DATA_OVERRIDE_REGULAR_MAPPINGS, + NO_TIME_RANGE, ) from superset.errors import ErrorLevel, SupersetErrorType from superset.exceptions import ( @@ -112,6 +115,7 @@ Metric, ) from superset.utils.database import get_example_database +from superset.utils.date_parser import parse_human_timedelta from superset.utils.dates import datetime_to_epoch, EPOCH from superset.utils.hashing import md5_sha_from_dict, md5_sha_from_str @@ -128,14 +132,14 @@ DTTM_ALIAS = "__timestamp" -NO_TIME_RANGE = "No filter" - TIME_COMPARISON = "__" JS_MAX_INTEGER = 9007199254740991 # Largest int Java Script can handle 2^53-1 InputType = TypeVar("InputType") +ADHOC_FILTERS_REGEX = re.compile("^adhoc_filters") + class LenientEnum(Enum): """Enums with a `get` method that convert a enum value to `Enum` if it is a @@ -185,6 +189,21 @@ class DatasourceType(str, Enum): VIEW = "view" +class LoggerLevel(str, Enum): + INFO = "info" + WARNING = "warning" + EXCEPTION = "exception" + + +class HeaderDataType(TypedDict): + notification_format: str + owners: List[int] + notification_type: str + notification_source: Optional[str] + chart_id: Optional[int] + dashboard_id: Optional[int] + + class DatasourceDict(TypedDict): type: str # todo(hugh): update this to be DatasourceType id: int @@ -220,7 +239,6 @@ class ExtraFiltersTimeColumnType(str, Enum): class ExtraFiltersReasonType(str, Enum): NO_TEMPORAL_COLUMN = "no_temporal_column" COL_NOT_IN_DATASOURCE = "not_in_datasource" - NOT_DRUID_DATASOURCE = "not_druid_datasource" class FilterOperator(str, Enum): @@ -243,6 +261,7 @@ class FilterOperator(str, Enum): REGEX = "REGEX" IS_TRUE = "IS TRUE" IS_FALSE = "IS FALSE" + TEMPORAL_RANGE = "TEMPORAL_RANGE" class FilterStringOperators(str, Enum): @@ -345,24 +364,9 @@ class RowLevelSecurityFilterType(str, Enum): BASE = "Base" -class TemporalType(str, Enum): - """ - Supported temporal types - """ - - DATE = "DATE" - DATETIME = "DATETIME" - SMALLDATETIME = "SMALLDATETIME" - TEXT = "TEXT" - TIME = "TIME" - TIME_WITH_TIME_ZONE = "TIME WITH TIME ZONE" - TIMESTAMP = "TIMESTAMP" - TIMESTAMP_WITH_TIME_ZONE = "TIMESTAMP WITH TIME ZONE" - - class ColumnTypeSource(Enum): GET_TABLE = 1 - CURSOR_DESCRIPION = 2 + CURSOR_DESCRIPTION = 2 class ColumnSpec(NamedTuple): @@ -409,7 +413,7 @@ def parse_js_uri_path_item( :param item: a uri path component :param unquote: Perform unquoting of string using urllib.parse.unquote_plus() - :param eval_undefined: When set to True and item is either 'null' or 'undefined', + :param eval_undefined: When set to True and item is either 'null' or 'undefined', assume item is undefined and return None. :return: Either None, the original item or unquoted item """ @@ -542,9 +546,16 @@ def format_timedelta(time_delta: timedelta) -> str: return str(time_delta) -def base_json_conv( # pylint: disable=inconsistent-return-statements - obj: Any, -) -> Any: +def base_json_conv(obj: Any) -> Any: + """ + Tries to convert additional types to JSON compatible forms. + + :param obj: The serializable object + :returns: The JSON compatible form + :raises TypeError: If the object cannot be serialized + :see: https://docs.python.org/3/library/json.html#encoders-and-decoders + """ + if isinstance(obj, memoryview): obj = obj.tobytes() if isinstance(obj, np.int64): @@ -567,51 +578,65 @@ def base_json_conv( # pylint: disable=inconsistent-return-statements except Exception: # pylint: disable=broad-except return "[bytes]" + raise TypeError(f"Unserializable object {obj} of type {type(obj)}") -def json_iso_dttm_ser(obj: Any, pessimistic: bool = False) -> str: + +def json_iso_dttm_ser(obj: Any, pessimistic: bool = False) -> Any: """ - json serializer that deals with dates + A JSON serializer that deals with dates by serializing them to ISO 8601. + + >>> json.dumps({'dttm': datetime(1970, 1, 1)}, default=json_iso_dttm_ser) + '{"dttm": "1970-01-01T00:00:00"}' - >>> dttm = datetime(1970, 1, 1) - >>> json.dumps({'dttm': dttm}, default=json_iso_dttm_ser) - '{"dttm": "1970-01-01T00:00:00"}' + :param obj: The serializable object + :param pessimistic: Whether to be pessimistic regarding serialization + :returns: The JSON compatible form + :raises TypeError: If the non-pessimistic object cannot be serialized """ - val = base_json_conv(obj) - if val is not None: - return val + if isinstance(obj, (datetime, date, pd.Timestamp)): - obj = obj.isoformat() - else: + return obj.isoformat() + + try: + return base_json_conv(obj) + except TypeError as ex: if pessimistic: - return "Unserializable [{}]".format(type(obj)) + return f"Unserializable [{type(obj)}]" - raise TypeError("Unserializable object {} of type {}".format(obj, type(obj))) - return obj + raise ex -def pessimistic_json_iso_dttm_ser(obj: Any) -> str: +def pessimistic_json_iso_dttm_ser(obj: Any) -> Any: """Proxy to call json_iso_dttm_ser in a pessimistic way If one of object is not serializable to json, it will still succeed""" return json_iso_dttm_ser(obj, pessimistic=True) -def json_int_dttm_ser(obj: Any) -> float: - """json serializer that deals with dates""" - val = base_json_conv(obj) - if val is not None: - return val +def json_int_dttm_ser(obj: Any) -> Any: + """ + A JSON serializer that deals with dates by serializing them to EPOCH. + + >>> json.dumps({'dttm': datetime(1970, 1, 1)}, default=json_int_dttm_ser) + '{"dttm": 0.0}' + + :param obj: The serializable object + :returns: The JSON compatible form + :raises TypeError: If the object cannot be serialized + """ + if isinstance(obj, (datetime, pd.Timestamp)): - obj = datetime_to_epoch(obj) - elif isinstance(obj, date): - obj = (obj - EPOCH.date()).total_seconds() * 1000 - else: - raise TypeError("Unserializable object {} of type {}".format(obj, type(obj))) - return obj + return datetime_to_epoch(obj) + + if isinstance(obj, date): + return (obj - EPOCH.date()).total_seconds() * 1000 + return base_json_conv(obj) -def json_dumps_w_dates(payload: Dict[Any, Any]) -> str: - return json.dumps(payload, default=json_int_dttm_ser) + +def json_dumps_w_dates(payload: Dict[Any, Any], sort_keys: bool = False) -> str: + """Dumps payload to JSON with Datetime objects properly converted""" + return json.dumps(payload, default=json_int_dttm_ser, sort_keys=sort_keys) def error_msg_from_exception(ex: Exception) -> str: @@ -905,6 +930,7 @@ def send_email_smtp( # pylint: disable=invalid-name,too-many-arguments,too-many cc: Optional[str] = None, bcc: Optional[str] = None, mime_subtype: str = "mixed", + header_data: Optional[HeaderDataType] = None, ) -> None: """ Send an email with html content, eg: @@ -918,6 +944,7 @@ def send_email_smtp( # pylint: disable=invalid-name,too-many-arguments,too-many msg["Subject"] = subject msg["From"] = smtp_mail_from msg["To"] = ", ".join(smtp_mail_to) + msg.preamble = "This is a multi-part message in MIME format." recipients = smtp_mail_to @@ -964,8 +991,10 @@ def send_email_smtp( # pylint: disable=invalid-name,too-many-arguments,too-many image.add_header("Content-ID", "<%s>" % msgid) image.add_header("Content-Disposition", "inline") msg.attach(image) - - send_mime_email(smtp_mail_from, recipients, msg, config, dryrun=dryrun) + msg_mutator = config["EMAIL_HEADER_MUTATOR"] + # the base notification returns the message without any editing. + new_msg = msg_mutator(msg, **(header_data or {})) + send_mime_email(smtp_mail_from, recipients, new_msg, config, dryrun=dryrun) def send_mime_email( @@ -981,7 +1010,7 @@ def send_mime_email( smtp_password = config["SMTP_PASSWORD"] smtp_starttls = config["SMTP_STARTTLS"] smtp_ssl = config["SMTP_SSL"] - smpt_ssl_server_auth = config["SMTP_SSL_SERVER_AUTH"] + smtp_ssl_server_auth = config["SMTP_SSL_SERVER_AUTH"] if dryrun: logger.info("Dryrun enabled, email notification content is below:") @@ -990,7 +1019,7 @@ def send_mime_email( # Default ssl context is SERVER_AUTH using the default system # root CA certificates - ssl_context = ssl.create_default_context() if smpt_ssl_server_auth else None + ssl_context = ssl.create_default_context() if smtp_ssl_server_auth else None smtp = ( smtplib.SMTP_SSL(smtp_host, smtp_port, context=ssl_context) if smtp_ssl @@ -1137,8 +1166,7 @@ def merge_extra_filters(form_data: Dict[str, Any]) -> None: # that are external to the slice definition. We use those for dynamic # interactive filters like the ones emitted by the "Filter Box" visualization. # Note extra_filters only support simple filters. - applied_time_extras: Dict[str, str] = {} - form_data["applied_time_extras"] = applied_time_extras + form_data.setdefault("applied_time_extras", {}) adhoc_filters = form_data.get("adhoc_filters", []) form_data["adhoc_filters"] = adhoc_filters merge_extra_form_data(form_data) @@ -1151,7 +1179,6 @@ def merge_extra_filters(form_data: Dict[str, Any]) -> None: "__time_range": "time_range", "__time_col": "granularity_sqla", "__time_grain": "time_grain_sqla", - "__time_origin": "druid_time_origin", "__granularity": "granularity", } # Grab list of existing filters 'keyed' on the column and operator @@ -1182,7 +1209,7 @@ def get_filter_key(f: Dict[str, Any]) -> str: time_extra_value = filtr.get("val") if time_extra_value and time_extra_value != NO_TIME_RANGE: form_data[time_extra] = time_extra_value - applied_time_extras[filter_column] = time_extra_value + form_data["applied_time_extras"][filter_column] = time_extra_value elif filtr["val"]: # Merge column filters filter_key = get_filter_key(filtr) @@ -1240,8 +1267,8 @@ def get_example_default_schema() -> Optional[str]: Return the default schema of the examples database, if any. """ database = get_example_database() - engine = database.get_sqla_engine() - return inspect(engine).default_schema_name + with database.get_sqla_engine_with_context() as engine: + return inspect(engine).default_schema_name def backend() -> str: @@ -1267,6 +1294,11 @@ def get_base_axis_labels(columns: Optional[List[Column]]) -> Tuple[str, ...]: return tuple(get_column_name(col) for col in axis_cols) +def get_xaxis_label(columns: Optional[List[Column]]) -> Optional[str]: + labels = get_base_axis_labels(columns) + return labels[0] if labels else None + + def get_column_name( column: Column, verbose_map: Optional[Dict[str, Any]] = None ) -> str: @@ -1286,9 +1318,12 @@ def get_column_name( expr = column.get("sqlExpression") if expr: return expr - raise ValueError("Missing label") - verbose_map = verbose_map or {} - return verbose_map.get(column, column) + + if isinstance(column, str): + verbose_map = verbose_map or {} + return verbose_map.get(column, column) + + raise ValueError("Missing label") def get_metric_name( @@ -1312,7 +1347,7 @@ def get_metric_name( sql_expression = metric.get("sqlExpression") if sql_expression: return sql_expression - elif expression_type == "SIMPLE": + if expression_type == "SIMPLE": column: AdhocMetricColumn = metric.get("column") or {} column_name = column.get("column_name") aggregate = metric.get("aggregate") @@ -1320,10 +1355,12 @@ def get_metric_name( return f"{aggregate}({column_name})" if column_name: return column_name - raise ValueError(__("Invalid metric object")) - verbose_map = verbose_map or {} - return verbose_map.get(metric, metric) # type: ignore + if isinstance(metric, str): + verbose_map = verbose_map or {} + return verbose_map.get(metric, metric) + + raise ValueError(__("Invalid metric object: %(metric)s", metric=str(metric))) def get_column_names( @@ -1439,38 +1476,65 @@ def split_adhoc_filters_into_base_filters( # pylint: disable=invalid-name def get_username() -> Optional[str]: - """Get username if within the flask context, otherwise return noffin'""" + """ + Get username (if defined) associated with the current user. + + :returns: The username + """ + try: return g.user.username except Exception: # pylint: disable=broad-except return None +def get_user_id() -> Optional[int]: + """ + Get the user identifier (if defined) associated with the current user. + + Though the Flask-AppBuilder `User` and Flask-Login `AnonymousUserMixin` and + `UserMixin` models provide a convenience `get_id` method, for generality, the + identifier is encoded as a `str` whereas in Superset all identifiers are encoded as + an `int`. + + returns: The user identifier + """ + + try: + return g.user.id + except Exception: # pylint: disable=broad-except + return None + + @contextmanager -def override_user(user: Optional[User]) -> Iterator[Any]: +def override_user(user: Optional[User], force: bool = True) -> Iterator[Any]: """ - Temporarily override the current user (if defined) per `flask.g`. + Temporarily override the current user per `flask.g` with the specified user. Sometimes, often in the context of async Celery tasks, it is useful to switch the current user (which may be undefined) to different one, execute some SQLAlchemy - tasks and then revert back to the original one. + tasks et al. and then revert back to the original one. :param user: The override user + :param force: Whether to override the current user if set """ # pylint: disable=assigning-non-slot if hasattr(g, "user"): - current = g.user - g.user = user - yield - g.user = current + if force or g.user is None: + current = g.user + g.user = user + yield + g.user = current + else: + yield else: g.user = user yield delattr(g, "user") -def parse_ssl_cert(certificate: str) -> _Certificate: +def parse_ssl_cert(certificate: str) -> Certificate: """ Parses the contents of a certificate and returns a valid certificate object if valid. @@ -1480,9 +1544,7 @@ def parse_ssl_cert(certificate: str) -> _Certificate: :raises CertificateException: If certificate is not valid/unparseable """ try: - return x509.load_pem_x509_certificate( - certificate.encode("utf-8"), default_backend() - ) + return load_pem_x509_certificate(certificate.encode("utf-8"), default_backend()) except ValueError as ex: raise CertificateException("Invalid certificate") from ex @@ -1665,21 +1727,31 @@ def extract_dataframe_dtypes( "date": GenericDataType.TEMPORAL, } - columns_by_name = ( - {column.column_name: column for column in datasource.columns} - if datasource - else {} - ) + columns_by_name: Dict[str, Any] = {} + if datasource: + for column in datasource.columns: + if isinstance(column, dict): + columns_by_name[column.get("column_name")] = column + else: + columns_by_name[column.column_name] = column + generic_types: List[GenericDataType] = [] for column in df.columns: column_object = columns_by_name.get(column) series = df[column] inferred_type = infer_dtype(series) - generic_type = ( - GenericDataType.TEMPORAL - if column_object and column_object.is_dttm - else inferred_type_map.get(inferred_type, GenericDataType.STRING) - ) + if isinstance(column_object, dict): + generic_type = ( + GenericDataType.TEMPORAL + if column_object and column_object.get("is_dttm") + else inferred_type_map.get(inferred_type, GenericDataType.STRING) + ) + else: + generic_type = ( + GenericDataType.TEMPORAL + if column_object and column_object.is_dttm + else inferred_type_map.get(inferred_type, GenericDataType.STRING) + ) generic_types.append(generic_type) return generic_types @@ -1713,7 +1785,16 @@ def get_time_filter_status( datasource: "BaseDatasource", applied_time_extras: Dict[str, str], ) -> Tuple[List[Dict[str, str]], List[Dict[str, str]]]: - temporal_columns = {col.column_name for col in datasource.columns if col.is_dttm} + + temporal_columns: Set[Any] + if datasource.type == "query": + temporal_columns = { + col.get("column_name") for col in datasource.columns if col.get("is_dttm") + } + else: + temporal_columns = { + col.column_name for col in datasource.columns if col.is_dttm + } applied: List[Dict[str, str]] = [] rejected: List[Dict[str, str]] = [] time_column = applied_time_extras.get(ExtraFiltersTimeColumnType.TIME_COL) @@ -1753,28 +1834,6 @@ def get_time_filter_status( } ) - if ExtraFiltersTimeColumnType.TIME_ORIGIN in applied_time_extras: - if datasource.type == "druid": - applied.append({"column": ExtraFiltersTimeColumnType.TIME_ORIGIN}) - else: - rejected.append( - { - "reason": ExtraFiltersReasonType.NOT_DRUID_DATASOURCE, - "column": ExtraFiltersTimeColumnType.TIME_ORIGIN, - } - ) - - if ExtraFiltersTimeColumnType.GRANULARITY in applied_time_extras: - if datasource.type == "druid": - applied.append({"column": ExtraFiltersTimeColumnType.GRANULARITY}) - else: - rejected.append( - { - "reason": ExtraFiltersReasonType.NOT_DRUID_DATASOURCE, - "column": ExtraFiltersTimeColumnType.GRANULARITY, - } - ) - return applied, rejected @@ -1804,33 +1863,64 @@ def remove_duplicates( return result +@dataclass +class DateColumn: + col_label: str + timestamp_format: Optional[str] = None + offset: Optional[int] = None + time_shift: Optional[str] = None + + def __hash__(self) -> int: + return hash(self.col_label) + + def __eq__(self, other: object) -> bool: + return isinstance(other, DateColumn) and hash(self) == hash(other) + + @classmethod + def get_legacy_time_column( + cls, + timestamp_format: Optional[str], + offset: Optional[int], + time_shift: Optional[str], + ) -> DateColumn: + return cls( + timestamp_format=timestamp_format, + offset=offset, + time_shift=time_shift, + col_label=DTTM_ALIAS, + ) + + def normalize_dttm_col( df: pd.DataFrame, - timestamp_format: Optional[str], - offset: int, - time_shift: Optional[timedelta], + dttm_cols: Tuple[DateColumn, ...] = tuple(), ) -> None: - if DTTM_ALIAS not in df.columns: - return - if timestamp_format in ("epoch_s", "epoch_ms"): - dttm_col = df[DTTM_ALIAS] - if is_numeric_dtype(dttm_col): - # Column is formatted as a numeric value - unit = timestamp_format.replace("epoch_", "") - df[DTTM_ALIAS] = pd.to_datetime( - dttm_col, utc=False, unit=unit, origin="unix", errors="coerce" - ) + for _col in dttm_cols: + if _col.col_label not in df.columns: + continue + + if _col.timestamp_format in ("epoch_s", "epoch_ms"): + dttm_series = df[_col.col_label] + if is_numeric_dtype(dttm_series): + # Column is formatted as a numeric value + unit = _col.timestamp_format.replace("epoch_", "") + df[_col.col_label] = pd.to_datetime( + dttm_series, utc=False, unit=unit, origin="unix", errors="coerce" + ) + else: + # Column has already been formatted as a timestamp. + df[_col.col_label] = dttm_series.apply(pd.Timestamp) else: - # Column has already been formatted as a timestamp. - df[DTTM_ALIAS] = dttm_col.apply(pd.Timestamp) - else: - df[DTTM_ALIAS] = pd.to_datetime( - df[DTTM_ALIAS], utc=False, format=timestamp_format, errors="coerce" - ) - if offset: - df[DTTM_ALIAS] += timedelta(hours=offset) - if time_shift is not None: - df[DTTM_ALIAS] += time_shift + df[_col.col_label] = pd.to_datetime( + df[_col.col_label], + utc=False, + format=_col.timestamp_format, + errors="coerce", + ) + if _col.offset: + df[_col.col_label] += timedelta(hours=_col.offset) + if _col.time_shift is not None: + df[_col.col_label] += parse_human_timedelta(_col.time_shift) def parse_boolean_string(bool_str: Optional[str]) -> bool: @@ -1898,3 +1988,16 @@ def create_zip(files: Dict[str, Any]) -> BytesIO: fp.write(contents) buf.seek(0) return buf + + +def remove_extra_adhoc_filters(form_data: Dict[str, Any]) -> None: + """ + Remove filters from slice data that originate from a filter box or native filter + """ + adhoc_filters = { + key: value for key, value in form_data.items() if ADHOC_FILTERS_REGEX.match(key) + } + for key, value in adhoc_filters.items(): + form_data[key] = [ + filter_ for filter_ in value or [] if not filter_.get("isExtra") + ] diff --git a/superset/utils/csv.py b/superset/utils/csv.py index 914ab8cf56231..54f30362fede3 100644 --- a/superset/utils/csv.py +++ b/superset/utils/csv.py @@ -14,6 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +import logging import re import urllib.request from typing import Any, Dict, Optional @@ -23,6 +24,10 @@ import pandas as pd import simplejson +from superset.utils.core import GenericDataType + +logger = logging.getLogger(__name__) + negative_number_re = re.compile(r"^-[0-9.]+$") # This regex will match if the string starts with: @@ -102,11 +107,22 @@ def get_chart_dataframe( return None result = simplejson.loads(content.decode("utf-8")) - # need to convert float value to string to show full long number pd.set_option("display.float_format", lambda x: str(x)) df = pd.DataFrame.from_dict(result["result"][0]["data"]) + try: + # if any column type is equal to 2, need to convert data into + # datetime timestamp for that column. + if GenericDataType.TEMPORAL in result["result"][0]["coltypes"]: + for i in range(len(result["result"][0]["coltypes"])): + if result["result"][0]["coltypes"][i] == GenericDataType.TEMPORAL: + df[result["result"][0]["colnames"][i]] = df[ + result["result"][0]["colnames"][i] + ].astype("datetime64[ms]") + except BaseException as err: + logger.error(err) + # rebuild hierarchical columns and index df.columns = pd.MultiIndex.from_tuples( tuple(colname) if isinstance(colname, list) else (colname,) diff --git a/superset/utils/dashboard_filter_scopes_converter.py b/superset/utils/dashboard_filter_scopes_converter.py index db897fa64c5a7..3aeb32360a775 100644 --- a/superset/utils/dashboard_filter_scopes_converter.py +++ b/superset/utils/dashboard_filter_scopes_converter.py @@ -63,10 +63,6 @@ def add_filter_scope( add_filter_scope(filter_fields, "__time_col", filter_id) if slice_params.get("show_sqla_time_granularity"): add_filter_scope(filter_fields, "__time_grain", filter_id) - if slice_params.get("show_druid_time_granularity"): - add_filter_scope(filter_fields, "__granularity", filter_id) - if slice_params.get("show_druid_time_origin"): - add_filter_scope(filter_fields, "druid_time_origin", filter_id) for config in configs: add_filter_scope(filter_fields, config.get("column"), filter_id) diff --git a/superset/utils/database.py b/superset/utils/database.py index 1375611ab877e..750d873d1c9cf 100644 --- a/superset/utils/database.py +++ b/superset/utils/database.py @@ -39,10 +39,7 @@ def get_or_create_db( from superset.models import core as models database = ( - db.session.query(models.Database) - .filter_by(database_name=database_name) - .autoflush(False) - .first() + db.session.query(models.Database).filter_by(database_name=database_name).first() ) # databases with a fixed UUID @@ -56,8 +53,11 @@ def get_or_create_db( database_name=database_name, uuid=uuids.get(database_name) ) db.session.add(database) + database.set_sqlalchemy_uri(sqlalchemy_uri) + db.session.commit() - if database: + # todo: it's a bad idea to do an update in a get/create function + if database and database.sqlalchemy_uri_decrypted != sqlalchemy_uri: database.set_sqlalchemy_uri(sqlalchemy_uri) db.session.commit() diff --git a/superset/utils/date_parser.py b/superset/utils/date_parser.py index 69f7542cdeba0..a300117a55a3f 100644 --- a/superset/utils/date_parser.py +++ b/superset/utils/date_parser.py @@ -25,8 +25,9 @@ import parsedatetime from dateutil.parser import parse from dateutil.relativedelta import relativedelta +from flask import current_app as app from flask_babel import lazy_gettext as _ -from holidays import CountryHoliday +from holidays import country_holidays from pyparsing import ( CaselessKeyword, Forward, @@ -40,13 +41,12 @@ Suppress, ) -from superset import app from superset.charts.commands.exceptions import ( TimeDeltaAmbiguousError, TimeRangeAmbiguousError, TimeRangeParseFailError, ) -from superset.utils.core import NO_TIME_RANGE +from superset.constants import NO_TIME_RANGE from superset.utils.memoized import memoized ParserElement.enablePackrat() @@ -175,7 +175,7 @@ def get_since_until( # pylint: disable=too-many-arguments,too-many-locals,too-m - Next X seconds/minutes/hours/days/weeks/months/years """ - config = app.config # type: ignore + config = app.config default_relative_start = config["DEFAULT_RELATIVE_START_TIME"] default_relative_end = config["DEFAULT_RELATIVE_END_TIME"] @@ -183,7 +183,7 @@ def get_since_until( # pylint: disable=too-many-arguments,too-many-locals,too-m _relative_start = relative_start if relative_start else default_relative_start _relative_end = relative_end if relative_end else default_relative_end - if time_range == NO_TIME_RANGE: + if time_range == NO_TIME_RANGE or time_range == _(NO_TIME_RANGE): return None, None if time_range and time_range.startswith("Last") and separator not in time_range: @@ -390,7 +390,7 @@ def eval(self) -> datetime: holiday_year = dttm.year if dttm else parse_human_datetime("today").year country = country.eval() if country else "US" - holiday_lookup = CountryHoliday(country, years=[holiday_year], observed=False) + holiday_lookup = country_holidays(country, years=[holiday_year], observed=False) searched_result = holiday_lookup.get_named(holiday) if len(searched_result) == 1: return dttm_from_timetuple(searched_result[0].timetuple()) diff --git a/superset/utils/dates.py b/superset/utils/dates.py index 021ec7f07c608..b2b422a1f0944 100644 --- a/superset/utils/dates.py +++ b/superset/utils/dates.py @@ -22,6 +22,7 @@ def datetime_to_epoch(dttm: datetime) -> float: + """Convert datetime to milliseconds to epoch""" if dttm.tzinfo: dttm = dttm.replace(tzinfo=pytz.utc) epoch_with_tz = pytz.utc.localize(EPOCH) diff --git a/superset/utils/decorators.py b/superset/utils/decorators.py index f14335f2cada5..073139574cd68 100644 --- a/superset/utils/decorators.py +++ b/superset/utils/decorators.py @@ -45,7 +45,17 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: current_app.config["STATS_LOGGER"].gauge(f"{metric_prefix_}.ok", 1) return result except Exception as ex: - current_app.config["STATS_LOGGER"].gauge(f"{metric_prefix_}.error", 1) + if ( + hasattr(ex, "status") + and ex.status < 500 # type: ignore # pylint: disable=no-member + ): + current_app.config["STATS_LOGGER"].gauge( + f"{metric_prefix_}.warning", 1 + ) + else: + current_app.config["STATS_LOGGER"].gauge( + f"{metric_prefix_}.error", 1 + ) raise ex return wrapped diff --git a/superset/utils/encrypt.py b/superset/utils/encrypt.py index 7c93764f691ba..0c230c6cd9248 100644 --- a/superset/utils/encrypt.py +++ b/superset/utils/encrypt.py @@ -19,8 +19,9 @@ from typing import Any, Dict, List, Optional from flask import Flask +from flask_babel import lazy_gettext as _ from sqlalchemy import text, TypeDecorator -from sqlalchemy.engine import Connection, Dialect, RowProxy +from sqlalchemy.engine import Connection, Dialect, Row from sqlalchemy_utils import EncryptedType logger = logging.getLogger(__name__) @@ -109,18 +110,24 @@ def _read_bytes(col_name: str, value: Any) -> Optional[bytes]: return bytes(value.encode("utf8")) # Just bail if we haven't seen this type before... - raise ValueError(f"DB column {col_name} has unknown type: {type(value)}") + raise ValueError( + _( + "DB column %(col_name)s has unknown type: %(value_type)s", + col_name=col_name, + value_type=type(value), + ) + ) @staticmethod def _select_columns_from_table( conn: Connection, column_names: List[str], table_name: str - ) -> RowProxy: + ) -> Row: return conn.execute(f"SELECT id, {','.join(column_names)} FROM {table_name}") def _re_encrypt_row( self, conn: Connection, - row: RowProxy, + row: Row, table_name: str, columns: Dict[str, EncryptedType], ) -> None: diff --git a/superset/utils/excel.py b/superset/utils/excel.py new file mode 100644 index 0000000000000..1f68031b6497b --- /dev/null +++ b/superset/utils/excel.py @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import io +from typing import Any + +import pandas as pd + + +def df_to_excel(df: pd.DataFrame, **kwargs: Any) -> Any: + output = io.BytesIO() + # pylint: disable=abstract-class-instantiated + with pd.ExcelWriter(output, engine="xlsxwriter") as writer: + df.to_excel(writer, **kwargs) + + return output.getvalue() diff --git a/superset/utils/file.py b/superset/utils/file.py new file mode 100644 index 0000000000000..f1bdac897eab5 --- /dev/null +++ b/superset/utils/file.py @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from werkzeug.utils import secure_filename + + +def get_filename(model_name: str, model_id: int, skip_id: bool = False) -> str: + slug = secure_filename(model_name) + filename = slug if skip_id else f"{slug}_{model_id}" + return filename if slug else str(model_id) diff --git a/superset/utils/log.py b/superset/utils/log.py index 4eafb669328fc..f2379fe11c491 100644 --- a/superset/utils/log.py +++ b/superset/utils/log.py @@ -31,6 +31,7 @@ Dict, Iterator, Optional, + Tuple, Type, TYPE_CHECKING, Union, @@ -41,9 +42,14 @@ from sqlalchemy.exc import SQLAlchemyError from typing_extensions import Literal +from superset.extensions import stats_logger_manager +from superset.utils.core import get_user_id, LoggerLevel + if TYPE_CHECKING: from superset.stats_logger import BaseStatsLogger +logger = logging.getLogger(__name__) + def collect_request_payload() -> Dict[str, Any]: """Collect log payload identifiable from request context""" @@ -73,6 +79,24 @@ def collect_request_payload() -> Dict[str, Any]: return payload +def get_logger_from_status( + status: int, +) -> Tuple[Callable[..., None], str]: + """ + Return logger method by status of exception. + Maps logger level to status code level + """ + log_map = { + "2": LoggerLevel.INFO, + "3": LoggerLevel.INFO, + "4": LoggerLevel.WARNING, + "5": LoggerLevel.EXCEPTION, + } + log_level = log_map[str(status)[0]] + + return (getattr(logger, log_level), log_level) + + class AbstractEventLogger(ABC): def __call__( self, @@ -133,10 +157,7 @@ def log_with_context( # pylint: disable=too-many-locals duration_ms = int(duration.total_seconds() * 1000) if duration else None # Initial try and grab user_id via flask.g.user - try: - user_id = g.user.get_id() - except Exception: # pylint: disable=broad-except - user_id = None + user_id = get_user_id() # Whenever a user is not bounded to a session we # need to add them back before logging to capture user_id @@ -144,7 +165,7 @@ def log_with_context( # pylint: disable=too-many-locals try: session = current_app.appbuilder.get_session session.add(g.user) - user_id = g.user.get_id() + user_id = get_user_id() except Exception as ex: # pylint: disable=broad-except logging.warning(ex) user_id = None @@ -174,7 +195,7 @@ def log_with_context( # pylint: disable=too-many-locals slice_id = 0 if log_to_statsd: - self.stats_logger.incr(action) + stats_logger_manager.instance.incr(action) try: # bulk insert @@ -263,10 +284,6 @@ def log_this_with_extra_payload(self, f: Callable[..., Any]) -> Callable[..., An """Decorator that instrument `update_log_payload` to kwargs""" return self._wrapper(f, allow_extra_payload=True) - @property - def stats_logger(self) -> BaseStatsLogger: - return current_app.config["STATS_LOGGER"] - def get_event_logger_from_cfg_value(cfg_value: Any) -> AbstractEventLogger: """ diff --git a/superset/utils/machine_auth.py b/superset/utils/machine_auth.py index 01347f90f1c25..d58f739f7713c 100644 --- a/superset/utils/machine_auth.py +++ b/superset/utils/machine_auth.py @@ -15,6 +15,8 @@ # specific language governing permissions and limitations # under the License. +from __future__ import annotations + import importlib import logging from typing import Callable, Dict, TYPE_CHECKING @@ -34,7 +36,7 @@ class MachineAuthProvider: def __init__( - self, auth_webdriver_func_override: Callable[[WebDriver, "User"], WebDriver] + self, auth_webdriver_func_override: Callable[[WebDriver, User], WebDriver] ): # This is here in order to allow for the authenticate_webdriver func to be # overridden via config, as opposed to the entire provider implementation @@ -43,7 +45,7 @@ def __init__( def authenticate_webdriver( self, driver: WebDriver, - user: "User", + user: User, ) -> WebDriver: """ Default AuthDriverFuncType type that sets a session cookie flask-login style @@ -69,7 +71,7 @@ def authenticate_webdriver( return driver @staticmethod - def get_auth_cookies(user: "User") -> Dict[str, str]: + def get_auth_cookies(user: User) -> Dict[str, str]: # Login with the user specified to get the reports with current_app.test_request_context("/login"): login_user(user) diff --git a/superset/utils/mock_data.py b/superset/utils/mock_data.py index ea83f7398251f..4b156cc10c10d 100644 --- a/superset/utils/mock_data.py +++ b/superset/utils/mock_data.py @@ -187,31 +187,29 @@ def add_data( database = get_example_database() table_exists = database.has_table_by_name(table_name) - engine = database.get_sqla_engine() - - if columns is None: - if not table_exists: - raise Exception( - f"The table {table_name} does not exist. To create it you need to " - "pass a list of column names and types." - ) - - inspector = inspect(engine) - columns = inspector.get_columns(table_name) - - # create table if needed - column_objects = get_column_objects(columns) - metadata = MetaData() - table = Table(table_name, metadata, *column_objects) - metadata.create_all(engine) - - if not append: - # pylint: disable=no-value-for-parameter # sqlalchemy/issues/4656 - engine.execute(table.delete()) - - data = generate_data(columns, num_rows) - # pylint: disable=no-value-for-parameter # sqlalchemy/issues/4656 - engine.execute(table.insert(), data) + + with database.get_sqla_engine_with_context() as engine: + if columns is None: + if not table_exists: + raise Exception( + f"The table {table_name} does not exist. To create it you need to " + "pass a list of column names and types." + ) + + inspector = inspect(engine) + columns = inspector.get_columns(table_name) + + # create table if needed + column_objects = get_column_objects(columns) + metadata = MetaData() + table = Table(table_name, metadata, *column_objects) + metadata.create_all(engine) + + if not append: + engine.execute(table.delete()) + + data = generate_data(columns, num_rows) + engine.execute(table.insert(), data) def get_column_objects(columns: List[ColumnInfo]) -> List[Column]: diff --git a/superset/utils/network.py b/superset/utils/network.py index 8079a96e203b1..7a1aea5a7178c 100644 --- a/superset/utils/network.py +++ b/superset/utils/network.py @@ -27,16 +27,19 @@ def is_port_open(host: str, port: int) -> bool: Test if a given port in a host is open. """ # pylint: disable=invalid-name - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.settimeout(PORT_TIMEOUT) - try: - s.connect((host, port)) - s.shutdown(socket.SHUT_RDWR) - return True - except socket.error: - return False - finally: - s.close() + for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): + af, _, _, _, sockaddr = res + s = socket.socket(af, socket.SOCK_STREAM) + try: + s.settimeout(PORT_TIMEOUT) + s.connect((sockaddr)) + s.shutdown(socket.SHUT_RDWR) + return True + except socket.error as _: + continue + finally: + s.close() + return False def is_hostname_valid(host: str) -> bool: @@ -44,7 +47,7 @@ def is_hostname_valid(host: str) -> bool: Test if a given hostname can be resolved. """ try: - socket.gethostbyname(host) + socket.getaddrinfo(host, None) return True except socket.gaierror: return False diff --git a/superset/utils/pandas_postprocessing/__init__.py b/superset/utils/pandas_postprocessing/__init__.py index 9755df984cc56..e66a52f6552e4 100644 --- a/superset/utils/pandas_postprocessing/__init__.py +++ b/superset/utils/pandas_postprocessing/__init__.py @@ -33,7 +33,10 @@ from superset.utils.pandas_postprocessing.rolling import rolling from superset.utils.pandas_postprocessing.select import select from superset.utils.pandas_postprocessing.sort import sort -from superset.utils.pandas_postprocessing.utils import _flatten_column_after_pivot +from superset.utils.pandas_postprocessing.utils import ( + escape_separator, + unescape_separator, +) __all__ = [ "aggregate", @@ -53,5 +56,6 @@ "select", "sort", "flatten", - "_flatten_column_after_pivot", + "escape_separator", + "unescape_separator", ] diff --git a/superset/utils/pandas_postprocessing/boxplot.py b/superset/utils/pandas_postprocessing/boxplot.py index 40ce9200d358e..d4c78bf15e8c8 100644 --- a/superset/utils/pandas_postprocessing/boxplot.py +++ b/superset/utils/pandas_postprocessing/boxplot.py @@ -57,10 +57,10 @@ def boxplot( """ def quartile1(series: Series) -> float: - return np.nanpercentile(series, 25, interpolation="midpoint") + return np.nanpercentile(series, 25, method="midpoint") def quartile3(series: Series) -> float: - return np.nanpercentile(series, 75, interpolation="midpoint") + return np.nanpercentile(series, 75, method="midpoint") if whisker_type == PostProcessingBoxplotWhiskerType.TUKEY: @@ -99,8 +99,8 @@ def whisker_low(series: Series) -> float: return np.nanpercentile(series, low) else: - whisker_high = np.max - whisker_low = np.min + whisker_high = np.max # type: ignore + whisker_low = np.min # type: ignore def outliers(series: Series) -> Set[float]: above = series[series > whisker_high(series)] @@ -126,7 +126,7 @@ def outliers(series: Series) -> Set[float]: # nanpercentile needs numeric values, otherwise the isnan function # that's used in the underlying function will fail for column in metrics: - if df.dtypes[column] == np.object: + if df.dtypes[column] == np.object_: df[column] = to_numeric(df[column], errors="coerce") return aggregate(df, groupby=groupby, aggregates=aggregates) diff --git a/superset/utils/pandas_postprocessing/flatten.py b/superset/utils/pandas_postprocessing/flatten.py index 2874ac57970a4..1026164e454ee 100644 --- a/superset/utils/pandas_postprocessing/flatten.py +++ b/superset/utils/pandas_postprocessing/flatten.py @@ -22,6 +22,7 @@ from superset.utils.pandas_postprocessing.utils import ( _is_multi_index_on_columns, + escape_separator, FLAT_COLUMN_SEPARATOR, ) @@ -84,10 +85,10 @@ def flatten( _columns = [] for series in df.columns.to_flat_index(): _cells = [] - for cell in series if is_sequence(series) else [series]: + for cell in series if is_sequence(series) else [series]: # type: ignore if pd.notnull(cell): - # every cell should be converted to string - _cells.append(str(cell)) + # every cell should be converted to string and escape comma + _cells.append(escape_separator(str(cell))) _columns.append(FLAT_COLUMN_SEPARATOR.join(_cells)) df.columns = _columns diff --git a/superset/utils/pandas_postprocessing/pivot.py b/superset/utils/pandas_postprocessing/pivot.py index 89a187ce89c0b..e18d58e28e4e8 100644 --- a/superset/utils/pandas_postprocessing/pivot.py +++ b/superset/utils/pandas_postprocessing/pivot.py @@ -22,7 +22,6 @@ from superset.constants import NULL_STRING, PandasAxis from superset.exceptions import InvalidPostProcessingError from superset.utils.pandas_postprocessing.utils import ( - _flatten_column_after_pivot, _get_aggregate_funcs, validate_column_args, ) @@ -40,8 +39,6 @@ def pivot( # pylint: disable=too-many-arguments,too-many-locals combine_value_with_metric: bool = False, marginal_distributions: Optional[bool] = None, marginal_distribution_name: Optional[str] = None, - flatten_columns: bool = True, - reset_index: bool = True, ) -> DataFrame: """ Perform a pivot operation on a DataFrame. @@ -61,8 +58,6 @@ def pivot( # pylint: disable=too-many-arguments,too-many-locals :param marginal_distributions: Add totals for row/column. Default to False :param marginal_distribution_name: Name of row/column with marginal distribution. Default to 'All'. - :param flatten_columns: Convert column names to strings - :param reset_index: Convert index to column :return: A pivot table :raises InvalidPostProcessingError: If the request in incorrect """ @@ -114,12 +109,4 @@ def pivot( # pylint: disable=too-many-arguments,too-many-locals if combine_value_with_metric: df = df.stack(0).unstack() - # Make index regular column - if flatten_columns: - df.columns = [ - _flatten_column_after_pivot(col, aggregates) for col in df.columns - ] - # return index as regular column - if reset_index: - df.reset_index(level=0, inplace=True) return df diff --git a/superset/utils/pandas_postprocessing/sort.py b/superset/utils/pandas_postprocessing/sort.py index feacfb68ea1d3..66041a7166b9f 100644 --- a/superset/utils/pandas_postprocessing/sort.py +++ b/superset/utils/pandas_postprocessing/sort.py @@ -14,22 +14,34 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from typing import Dict +from typing import List, Optional, Union from pandas import DataFrame from superset.utils.pandas_postprocessing.utils import validate_column_args -@validate_column_args("columns") -def sort(df: DataFrame, columns: Dict[str, bool]) -> DataFrame: +# pylint: disable=invalid-name +@validate_column_args("by") +def sort( + df: DataFrame, + is_sort_index: bool = False, + by: Optional[Union[List[str], str]] = None, + ascending: Union[List[bool], bool] = True, +) -> DataFrame: """ Sort a DataFrame. :param df: DataFrame to sort. - :param columns: columns by by which to sort. The key specifies the column name, - value specifies if sorting in ascending order. + :param is_sort_index: Whether by index or value to sort + :param by: Name or list of names to sort by. + :param ascending: Sort ascending or descending. :return: Sorted DataFrame :raises InvalidPostProcessingError: If the request in incorrect """ - return df.sort_values(by=list(columns.keys()), ascending=list(columns.values())) + if not is_sort_index and not by: + return df + + if is_sort_index: + return df.sort_index(ascending=ascending) + return df.sort_values(by=by, ascending=ascending) diff --git a/superset/utils/pandas_postprocessing/utils.py b/superset/utils/pandas_postprocessing/utils.py index ab39135918b7c..2b754fbbefae4 100644 --- a/superset/utils/pandas_postprocessing/utils.py +++ b/superset/utils/pandas_postprocessing/utils.py @@ -15,16 +15,16 @@ # specific language governing permissions and limitations # under the License. from functools import partial -from typing import Any, Callable, Dict, Tuple, Union +from typing import Any, Callable, Dict, Sequence import numpy as np import pandas as pd from flask_babel import gettext as _ -from pandas import DataFrame, NamedAgg, Timestamp +from pandas import DataFrame, NamedAgg from superset.exceptions import InvalidPostProcessingError -NUMPY_FUNCTIONS = { +NUMPY_FUNCTIONS: Dict[str, Callable[..., Any]] = { "average": np.average, "argmin": np.argmin, "argmax": np.argmax, @@ -97,34 +97,18 @@ FLAT_COLUMN_SEPARATOR = ", " -def _flatten_column_after_pivot( - column: Union[float, Timestamp, str, Tuple[str, ...]], - aggregates: Dict[str, Dict[str, Any]], -) -> str: - """ - Function for flattening column names into a single string. This step is necessary - to be able to properly serialize a DataFrame. If the column is a string, return - element unchanged. For multi-element columns, join column elements with a comma, - with the exception of pivots made with a single aggregate, in which case the - aggregate column name is omitted. - - :param column: single element from `DataFrame.columns` - :param aggregates: aggregates - :return: - """ - if not isinstance(column, tuple): - column = (column,) - if len(aggregates) == 1 and len(column) > 1: - # drop aggregate for single aggregate pivots with multiple groupings - # from column name (aggregates always come first in column name) - column = column[1:] - return FLAT_COLUMN_SEPARATOR.join([str(col) for col in column]) - - def _is_multi_index_on_columns(df: DataFrame) -> bool: return isinstance(df.columns, pd.MultiIndex) +def scalar_to_sequence(val: Any) -> Sequence[str]: + if val is None: + return [] + if isinstance(val, str): + return [val] + return val + + def validate_column_args(*argnames: str) -> Callable[..., Any]: def wrapper(func: Callable[..., Any]) -> Callable[..., Any]: def wrapped(df: DataFrame, **options: Any) -> Any: @@ -135,7 +119,7 @@ def wrapped(df: DataFrame, **options: Any) -> Any: columns = df.columns.tolist() for name in argnames: if name in options and not all( - elem in columns for elem in options.get(name) or [] + elem in columns for elem in scalar_to_sequence(options.get(name)) ): raise InvalidPostProcessingError( _("Referenced columns not available in DataFrame.") @@ -222,3 +206,13 @@ def _append_columns( return _base_df append_df = append_df.rename(columns=columns) return pd.concat([base_df, append_df], axis="columns") + + +def escape_separator(plain_str: str, sep: str = FLAT_COLUMN_SEPARATOR) -> str: + char = sep.strip() + return plain_str.replace(char, "\\" + char) + + +def unescape_separator(escaped_str: str, sep: str = FLAT_COLUMN_SEPARATOR) -> str: + char = sep.strip() + return escaped_str.replace("\\" + char, char) diff --git a/superset/utils/screenshots.py b/superset/utils/screenshots.py index 7c4d372414fc6..a904b7dc4384a 100644 --- a/superset/utils/screenshots.py +++ b/superset/utils/screenshots.py @@ -14,6 +14,8 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from __future__ import annotations + import logging from io import BytesIO from typing import Optional, TYPE_CHECKING, Union @@ -21,7 +23,13 @@ from flask import current_app from superset.utils.hashing import md5_sha_from_dict -from superset.utils.webdriver import WebDriverProxy, WindowSize +from superset.utils.urls import modify_url_query +from superset.utils.webdriver import ( + ChartStandaloneMode, + DashboardStandaloneMode, + WebDriverProxy, + WindowSize, +) logger = logging.getLogger(__name__) @@ -68,7 +76,7 @@ def cache_key( return md5_sha_from_dict(args) def get_screenshot( - self, user: "User", window_size: Optional[WindowSize] = None + self, user: User, window_size: Optional[WindowSize] = None ) -> Optional[bytes]: driver = self.driver(window_size) self.screenshot = driver.get_screenshot(self.url, self.element, user) @@ -76,8 +84,8 @@ def get_screenshot( def get( self, - user: "User" = None, - cache: "Cache" = None, + user: User = None, + cache: Cache = None, thumb_size: Optional[WindowSize] = None, ) -> Optional[BytesIO]: """ @@ -103,7 +111,7 @@ def get( def get_from_cache( self, - cache: "Cache", + cache: Cache, window_size: Optional[WindowSize] = None, thumb_size: Optional[WindowSize] = None, ) -> Optional[BytesIO]: @@ -111,7 +119,7 @@ def get_from_cache( return self.get_from_cache_key(cache, cache_key) @staticmethod - def get_from_cache_key(cache: "Cache", cache_key: str) -> Optional[BytesIO]: + def get_from_cache_key(cache: Cache, cache_key: str) -> Optional[BytesIO]: logger.info("Attempting to get from cache: %s", cache_key) payload = cache.get(cache_key) if payload: @@ -121,10 +129,10 @@ def get_from_cache_key(cache: "Cache", cache_key: str) -> Optional[BytesIO]: def compute_and_cache( # pylint: disable=too-many-arguments self, - user: "User" = None, + user: User = None, window_size: Optional[WindowSize] = None, thumb_size: Optional[WindowSize] = None, - cache: "Cache" = None, + cache: Cache = None, force: bool = True, ) -> Optional[bytes]: """ @@ -203,6 +211,11 @@ def __init__( window_size: Optional[WindowSize] = None, thumb_size: Optional[WindowSize] = None, ): + # Chart reports are in standalone="true" mode + url = modify_url_query( + url, + standalone=ChartStandaloneMode.HIDE_NAV.value, + ) super().__init__(url, digest) self.window_size = window_size or (800, 600) self.thumb_size = thumb_size or (800, 600) @@ -210,7 +223,7 @@ def __init__( class DashboardScreenshot(BaseScreenshot): thumbnail_type: str = "dashboard" - element: str = "grid-container" + element: str = "standalone" def __init__( self, @@ -219,6 +232,13 @@ def __init__( window_size: Optional[WindowSize] = None, thumb_size: Optional[WindowSize] = None, ): + # per the element above, dashboard screenshots + # should always capture in standalone + url = modify_url_query( + url, + standalone=DashboardStandaloneMode.REPORT.value, + ) + super().__init__(url, digest) self.window_size = window_size or (1600, 1200) self.thumb_size = thumb_size or (800, 600) diff --git a/superset/utils/ssh_tunnel.py b/superset/utils/ssh_tunnel.py new file mode 100644 index 0000000000000..48ada98dccaaf --- /dev/null +++ b/superset/utils/ssh_tunnel.py @@ -0,0 +1,43 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from typing import Any, Dict + +from superset.constants import PASSWORD_MASK +from superset.databases.ssh_tunnel.models import SSHTunnel + + +def mask_password_info(ssh_tunnel: Dict[str, Any]) -> Dict[str, Any]: + if ssh_tunnel.pop("password", None) is not None: + ssh_tunnel["password"] = PASSWORD_MASK + if ssh_tunnel.pop("private_key", None) is not None: + ssh_tunnel["private_key"] = PASSWORD_MASK + if ssh_tunnel.pop("private_key_password", None) is not None: + ssh_tunnel["private_key_password"] = PASSWORD_MASK + return ssh_tunnel + + +def unmask_password_info( + ssh_tunnel: Dict[str, Any], model: SSHTunnel +) -> Dict[str, Any]: + if ssh_tunnel.get("password") == PASSWORD_MASK: + ssh_tunnel["password"] = model.password + if ssh_tunnel.get("private_key") == PASSWORD_MASK: + ssh_tunnel["private_key"] = model.private_key + if ssh_tunnel.get("private_key_password") == PASSWORD_MASK: + ssh_tunnel["private_key_password"] = model.private_key_password + return ssh_tunnel diff --git a/superset/utils/url_map_converters.py b/superset/utils/url_map_converters.py index c6a14f3fd8048..c5eaf3b359f06 100644 --- a/superset/utils/url_map_converters.py +++ b/superset/utils/url_map_converters.py @@ -18,7 +18,7 @@ from werkzeug.routing import BaseConverter, Map -from superset.models.tags import ObjectTypes +from superset.tags.models import ObjectTypes class RegexConverter(BaseConverter): diff --git a/superset/utils/urls.py b/superset/utils/urls.py index c31bfb1a5103c..31fbd89337af4 100644 --- a/superset/utils/urls.py +++ b/superset/utils/urls.py @@ -48,7 +48,9 @@ def modify_url_query(url: str, **kwargs: Any) -> str: v = [v] params[k] = v - parts[3] = "&".join(f"{k}={urllib.parse.quote(v[0])}" for k, v in params.items()) + parts[3] = "&".join( + f"{k}={urllib.parse.quote(str(v[0]))}" for k, v in params.items() + ) return urllib.parse.urlunsplit(parts) diff --git a/superset/utils/webdriver.py b/superset/utils/webdriver.py index 5fdc0a2131165..e678587029dbc 100644 --- a/superset/utils/webdriver.py +++ b/superset/utils/webdriver.py @@ -15,10 +15,12 @@ # specific language governing permissions and limitations # under the License. +from __future__ import annotations + import logging from enum import Enum from time import sleep -from typing import Any, Dict, Optional, Tuple, TYPE_CHECKING +from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING from flask import current_app from selenium.common.exceptions import ( @@ -49,6 +51,67 @@ class DashboardStandaloneMode(Enum): REPORT = 3 +class ChartStandaloneMode(Enum): + HIDE_NAV = "true" + SHOW_NAV = 0 + + +def find_unexpected_errors(driver: WebDriver) -> List[str]: + error_messages = [] + + try: + alert_divs = driver.find_elements(By.XPATH, "//div[@role = 'alert']") + logger.debug( + "%i alert elements have been found in the screenshot", len(alert_divs) + ) + + for alert_div in alert_divs: + # See More button + alert_div.find_element(By.XPATH, ".//*[@role = 'button']").click() + + # wait for modal to show up + modal = WebDriverWait( + driver, current_app.config["SCREENSHOT_WAIT_FOR_ERROR_MODAL_VISIBLE"] + ).until( + EC.visibility_of_any_elements_located( + (By.CLASS_NAME, "ant-modal-content") + ) + )[ + 0 + ] + + err_msg_div = modal.find_element(By.CLASS_NAME, "ant-modal-body") + + # collect error message + error_messages.append(err_msg_div.text) + + # close modal after collecting error messages + modal.find_element(By.CLASS_NAME, "ant-modal-close").click() + + # wait until the modal becomes invisible + WebDriverWait( + driver, current_app.config["SCREENSHOT_WAIT_FOR_ERROR_MODAL_INVISIBLE"] + ).until(EC.invisibility_of_element(modal)) + + # Use HTML so that error messages are shown in the same style (color) + error_as_html = err_msg_div.get_attribute("innerHTML").replace("'", "\\'") + + try: + # Even if some errors can't be updated in the screenshot, + # keep all the errors in the server log and do not fail the loop + driver.execute_script( + f"arguments[0].innerHTML = '{error_as_html}'", alert_div + ) + except WebDriverException: + logger.warning( + "Failed to update error messages using alert_div", exc_info=True + ) + except WebDriverException: + logger.warning("Failed to capture unexpected errors", exc_info=True) + + return error_messages + + class WebDriverProxy: def __init__(self, driver_type: str, window: Optional[WindowSize] = None): self._driver_type = driver_type @@ -83,7 +146,7 @@ def create(self) -> WebDriver: return driver_class(**kwargs) - def auth(self, user: "User") -> WebDriver: + def auth(self, user: User) -> WebDriver: driver = self.create() return machine_auth_provider_factory.instance.authenticate_webdriver( driver, user @@ -104,7 +167,7 @@ def destroy(driver: WebDriver, tries: int = 2) -> None: pass def get_screenshot( - self, url: str, element_name: str, user: "User" + self, url: str, element_name: str, user: User ) -> Optional[bytes]: driver = self.auth(user) driver.set_window_size(*self._window) @@ -119,23 +182,42 @@ def get_screenshot( element = WebDriverWait(driver, self._screenshot_locate_wait).until( EC.presence_of_element_located((By.CLASS_NAME, element_name)) ) - logger.debug("Wait for .loading to be done") - WebDriverWait(driver, self._screenshot_load_wait).until_not( - EC.presence_of_all_elements_located((By.CLASS_NAME, "loading")) - ) - logger.debug("Wait for chart to have content") + + logger.debug("Wait for chart containers to draw") WebDriverWait(driver, self._screenshot_locate_wait).until( EC.visibility_of_all_elements_located( (By.CLASS_NAME, "slice_container") ) ) + + logger.debug("Wait for loading element of charts to be gone") + WebDriverWait(driver, self._screenshot_load_wait).until_not( + EC.presence_of_all_elements_located((By.CLASS_NAME, "loading")) + ) + selenium_animation_wait = current_app.config[ "SCREENSHOT_SELENIUM_ANIMATION_WAIT" ] logger.debug("Wait %i seconds for chart animation", selenium_animation_wait) sleep(selenium_animation_wait) - logger.info("Taking a PNG screenshot of url %s", url) + logger.info( + "Taking a PNG screenshot of url %s as user %s", + url, + user.username, + ) + + if current_app.config["SCREENSHOT_REPLACE_UNEXPECTED_ERRORS"]: + unexpected_errors = find_unexpected_errors(driver) + if unexpected_errors: + logger.warning( + "%i errors found in the screenshot. URL: %s. Errors are: %s", + len(unexpected_errors), + url, + unexpected_errors, + ) + img = element.screenshot_as_png + except TimeoutException: logger.warning("Selenium timed out requesting url %s", url, exc_info=True) except StaleElementReferenceException: diff --git a/superset/views/__init__.py b/superset/views/__init__.py index c33601f7278d6..5247f215c1870 100644 --- a/superset/views/__init__.py +++ b/superset/views/__init__.py @@ -17,7 +17,6 @@ from . import ( access_requests, alerts, - annotations, api, base, core, diff --git a/superset/views/access_requests.py b/superset/views/access_requests.py index e60662e36e70a..063ef5e0be91b 100644 --- a/superset/views/access_requests.py +++ b/superset/views/access_requests.py @@ -25,9 +25,10 @@ from superset.views.core import DAR -class AccessRequestsModelView( - SupersetModelView, DeleteMixin -): # pylint: disable=too-many-ancestors +class AccessRequestsModelView( # pylint: disable=too-many-ancestors + SupersetModelView, + DeleteMixin, +): datamodel = SQLAInterface(DAR) include_route_methods = RouteMethod.CRUD_SET list_columns = [ diff --git a/superset/views/annotations.py b/superset/views/annotations.py index 69718f5f5af52..cc8c58fe47f1a 100644 --- a/superset/views/annotations.py +++ b/superset/views/annotations.py @@ -14,116 +14,27 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from typing import Any, Dict - -from flask_appbuilder import CompactCRUDMixin +from flask_appbuilder import permission_name from flask_appbuilder.api import expose -from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_appbuilder.security.decorators import has_access -from flask_babel import lazy_gettext as _ -from wtforms.validators import StopValidation -from superset.constants import MODEL_VIEW_RW_METHOD_PERMISSION_MAP, RouteMethod -from superset.models.annotations import Annotation, AnnotationLayer from superset.superset_typing import FlaskResponse -from superset.views.base import SupersetModelView - - -class StartEndDttmValidator: # pylint: disable=too-few-public-methods - """ - Validates dttm fields. - """ - def __call__(self, form: Dict[str, Any], field: Any) -> None: - if not form["start_dttm"].data and not form["end_dttm"].data: - raise StopValidation(_("annotation start time or end time is required.")) - if ( - form["end_dttm"].data - and form["start_dttm"].data - and form["end_dttm"].data < form["start_dttm"].data - ): - raise StopValidation( - _("Annotation end time must be no earlier than start time.") - ) +from .base import BaseSupersetView -class AnnotationModelView( - SupersetModelView, CompactCRUDMixin -): # pylint: disable=too-many-ancestors - datamodel = SQLAInterface(Annotation) - include_route_methods = RouteMethod.CRUD_SET | {"annotation"} - +class AnnotationLayerView(BaseSupersetView): + route_base = "/annotationlayer" class_permission_name = "Annotation" - method_permission_name = MODEL_VIEW_RW_METHOD_PERMISSION_MAP - - list_title = _("Annotations") - show_title = _("Show Annotation") - add_title = _("Add Annotation") - edit_title = _("Edit Annotation") - - list_columns = ["short_descr", "start_dttm", "end_dttm"] - edit_columns = [ - "layer", - "short_descr", - "long_descr", - "start_dttm", - "end_dttm", - "json_metadata", - ] - - add_columns = edit_columns - - label_columns = { - "layer": _("Layer"), - "short_descr": _("Label"), - "long_descr": _("Description"), - "start_dttm": _("Start"), - "end_dttm": _("End"), - "json_metadata": _("JSON Metadata"), - } - - description_columns = { - "json_metadata": "This JSON represents any additional metadata this \ - annotation needs to add more context." - } - - validators_columns = {"start_dttm": [StartEndDttmValidator()]} - - def pre_add(self, item: "AnnotationModelView") -> None: - if not item.start_dttm: - item.start_dttm = item.end_dttm - elif not item.end_dttm: - item.end_dttm = item.start_dttm - - def pre_update(self, item: "AnnotationModelView") -> None: - self.pre_add(item) - @expose("/<pk>/annotation/", methods=["GET"]) + @expose("/list/") @has_access - def annotation(self, pk: int) -> FlaskResponse: # pylint: disable=unused-argument + @permission_name("read") + def list(self) -> FlaskResponse: return super().render_app_template() - -class AnnotationLayerModelView(SupersetModelView): - datamodel = SQLAInterface(AnnotationLayer) - include_route_methods = RouteMethod.CRUD_SET | {RouteMethod.API_READ} - related_views = [AnnotationModelView] - - class_permission_name = "Annotation" - method_permission_name = MODEL_VIEW_RW_METHOD_PERMISSION_MAP - - list_title = _("Annotation Layers") - show_title = _("Show Annotation Layer") - add_title = _("Add Annotation Layer") - edit_title = _("Edit Annotation Layer") - - list_columns = ["id", "name", "descr"] - edit_columns = ["name", "descr"] - add_columns = edit_columns - - label_columns = {"name": _("Name"), "descr": _("Description")} - - @expose("/list/") + @expose("/<int:pk>/annotation") @has_access - def list(self) -> FlaskResponse: + @permission_name("read") + def get(self, pk: int) -> FlaskResponse: # pylint: disable=unused-argument return super().render_app_template() diff --git a/superset/views/api.py b/superset/views/api.py index bde25236460da..fc7c5b76d26c1 100644 --- a/superset/views/api.py +++ b/superset/views/api.py @@ -23,6 +23,7 @@ from flask_appbuilder import expose from flask_appbuilder.api import rison from flask_appbuilder.security.decorators import has_access_api +from flask_babel import lazy_gettext as _ from superset import db, event_logger from superset.charts.commands.exceptions import ( @@ -105,7 +106,7 @@ def time_range(self, **kwargs: Any) -> FlaskResponse: } return self.json_response({"result": result}) except (ValueError, TimeRangeParseFailError, TimeRangeAmbiguousError) as error: - error_msg = {"message": f"Unexpected time range: {error}"} + error_msg = {"message": _("Unexpected time range: %s" % error)} return self.json_response(error_msg, 400) def get_query_context_factory(self) -> QueryContextFactory: diff --git a/superset/views/base.py b/superset/views/base.py index cd13972c93fe0..bffb95ea33203 100644 --- a/superset/views/base.py +++ b/superset/views/base.py @@ -72,11 +72,13 @@ SupersetException, SupersetSecurityException, ) +from superset.extensions import cache_manager from superset.models.helpers import ImportExportMixin -from superset.models.reports import ReportRecipientType +from superset.reports.models import ReportRecipientType from superset.superset_typing import FlaskResponse from superset.translations.utils import get_language_pack from superset.utils import core as utils +from superset.utils.core import get_user_id from .utils import bootstrap_user_data @@ -101,13 +103,19 @@ "SQLALCHEMY_DISPLAY_TEXT", "GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL", "DASHBOARD_AUTO_REFRESH_MODE", + "DASHBOARD_AUTO_REFRESH_INTERVALS", + "DASHBOARD_VIRTUALIZATION", "SCHEDULED_QUERIES", "EXCEL_EXTENSIONS", "CSV_EXTENSIONS", "COLUMNAR_EXTENSIONS", "ALLOWED_EXTENSIONS", + "SAMPLES_ROW_LIMIT", + "DEFAULT_TIME_FILTER", "HTML_SANITIZATION", "HTML_SANITIZATION_SCHEMA_EXTENSIONS", + "WELCOME_PAGE_LAST_TAB", + "VIZ_TYPE_DENYLIST", ) logger = logging.getLogger(__name__) @@ -178,6 +186,30 @@ def generate_download_headers( return headers +def deprecated( + eol_version: str = "3.0.0", +) -> Callable[[Callable[..., FlaskResponse]], Callable[..., FlaskResponse]]: + """ + A decorator to set an API endpoint from SupersetView has deprecated. + Issues a log warning + """ + + def _deprecated(f: Callable[..., FlaskResponse]) -> Callable[..., FlaskResponse]: + def wraps(self: "BaseSupersetView", *args: Any, **kwargs: Any) -> FlaskResponse: + logger.warning( + "%s.%s " + "This API endpoint is deprecated and will be removed in version %s", + self.__class__.__name__, + f.__name__, + eol_version, + ) + return f(self, *args, **kwargs) + + return functools.update_wrapper(wraps, f) + + return _deprecated + + def api(f: Callable[..., FlaskResponse]) -> Callable[..., FlaskResponse]: """ A decorator to label an endpoint as an API. Catches uncaught exceptions and @@ -267,17 +299,6 @@ def validate_sqlatable(table: models.SqlaTable) -> None: ) from ex -def create_table_permissions(table: models.SqlaTable) -> None: - security_manager.add_permission_view_menu("datasource_access", table.get_perm()) - if table.schema: - security_manager.add_permission_view_menu("schema_access", table.schema_perm) - - -def is_user_admin() -> bool: - user_roles = [role.name.lower() for role in list(security_manager.get_user_roles())] - return "admin" in user_roles - - class BaseSupersetView(BaseView): @staticmethod def json_response(obj: Any, status: int = 200) -> FlaskResponse: @@ -290,7 +311,7 @@ def json_response(obj: Any, status: int = 200) -> FlaskResponse: def render_app_template(self) -> FlaskResponse: payload = { "user": bootstrap_user_data(g.user, include_perms=True), - "common": common_bootstrap_payload(), + "common": common_bootstrap_payload(g.user), } return self.render_template( "superset/spa.html", @@ -301,7 +322,7 @@ def render_app_template(self) -> FlaskResponse: ) -def menu_data() -> Dict[str, Any]: +def menu_data(user: User) -> Dict[str, Any]: menu = appbuilder.menu.get_data() languages = {} @@ -314,16 +335,22 @@ def menu_data() -> Dict[str, Any]: if callable(brand_text): brand_text = brand_text() build_number = appbuilder.app.config["BUILD_NUMBER"] - environment_tag = ( - appbuilder.app.config["ENVIRONMENT_TAG_CONFIG"]["values"][ - os.environ.get(appbuilder.app.config["ENVIRONMENT_TAG_CONFIG"]["variable"]) - ] - or {} - ) + try: + environment_tag = ( + appbuilder.app.config["ENVIRONMENT_TAG_CONFIG"]["values"][ + os.environ.get( + appbuilder.app.config["ENVIRONMENT_TAG_CONFIG"]["variable"] + ) + ] + or {} + ) + except KeyError: + environment_tag = {} + return { "menu": menu, "brand": { - "path": appbuilder.app.config["LOGO_TARGET_PATH"] or "/", + "path": appbuilder.app.config["LOGO_TARGET_PATH"] or "/superset/welcome/", "icon": appbuilder.app_icon, "alt": appbuilder.app_name, "tooltip": appbuilder.app.config["LOGO_TOOLTIP"], @@ -331,32 +358,40 @@ def menu_data() -> Dict[str, Any]: }, "environment_tag": environment_tag, "navbar_right": { - # show the watermark if the default app icon has been overriden + # show the watermark if the default app icon has been overridden "show_watermark": ("superset-logo-horiz" not in appbuilder.app_icon), "bug_report_url": appbuilder.app.config["BUG_REPORT_URL"], + "bug_report_icon": appbuilder.app.config["BUG_REPORT_ICON"], + "bug_report_text": appbuilder.app.config["BUG_REPORT_TEXT"], "documentation_url": appbuilder.app.config["DOCUMENTATION_URL"], + "documentation_icon": appbuilder.app.config["DOCUMENTATION_ICON"], + "documentation_text": appbuilder.app.config["DOCUMENTATION_TEXT"], "version_string": appbuilder.app.config["VERSION_STRING"], "version_sha": appbuilder.app.config["VERSION_SHA"], "build_number": build_number, "languages": languages, "show_language_picker": len(languages.keys()) > 1, - "user_is_anonymous": g.user.is_anonymous, + "user_is_anonymous": user.is_anonymous, "user_info_url": None if appbuilder.app.config["MENU_HIDE_USER_INFO"] else appbuilder.get_url_for_userinfo, "user_logout_url": appbuilder.get_url_for_logout, "user_login_url": appbuilder.get_url_for_login, "user_profile_url": None - if g.user.is_anonymous or appbuilder.app.config["MENU_HIDE_USER_INFO"] - else f"/superset/profile/{g.user.username}", + if user.is_anonymous or appbuilder.app.config["MENU_HIDE_USER_INFO"] + else f"/superset/profile/{user.username}", "locale": session.get("locale", "en"), }, } -def common_bootstrap_payload() -> Dict[str, Any]: - """Common data always sent to the client""" - messages = get_flashed_messages(with_categories=True) +@cache_manager.cache.memoize(timeout=60) +def cached_common_bootstrap_data(user: User) -> Dict[str, Any]: + """Common data always sent to the client + + The function is memoized as the return value only changes when user permissions + or configuration values change. + """ locale = str(get_locale()) # should not expose API TOKEN to frontend @@ -380,7 +415,6 @@ def common_bootstrap_payload() -> Dict[str, Any]: frontend_config["HAS_GSHEETS_INSTALLED"] = bool(available_specs[GSheetsEngineSpec]) bootstrap_data = { - "flash_messages": messages, "conf": frontend_config, "locale": locale, "language_pack": get_language_pack(locale), @@ -388,7 +422,7 @@ def common_bootstrap_payload() -> Dict[str, Any]: "extra_sequential_color_schemes": conf["EXTRA_SEQUENTIAL_COLOR_SCHEMES"], "extra_categorical_color_schemes": conf["EXTRA_CATEGORICAL_COLOR_SCHEMES"], "theme_overrides": conf["THEME_OVERRIDES"], - "menu_data": menu_data(), + "menu_data": menu_data(user), "datahub_url": conf.get("DATAHUB_URL", ""), "advanced_data_types": list( map( @@ -406,6 +440,13 @@ def common_bootstrap_payload() -> Dict[str, Any]: return bootstrap_data +def common_bootstrap_payload(user: User) -> Dict[str, Any]: + return { + **(cached_common_bootstrap_data(user)), + "flash_messages": get_flashed_messages(with_categories=True), + } + + def get_error_level_from_status_code( # pylint: disable=invalid-name status: int, ) -> ErrorLevel: @@ -511,7 +552,7 @@ def show_unexpected_exception(ex: Exception) -> FlaskResponse: def get_common_bootstrap_data() -> Dict[str, Any]: def serialize_bootstrap_data() -> str: return json.dumps( - {"common": common_bootstrap_payload()}, + {"common": common_bootstrap_payload(g.user)}, default=utils.pessimistic_json_iso_dttm_ser, ) @@ -529,7 +570,7 @@ class SupersetModelView(ModelView): def render_app_template(self) -> FlaskResponse: payload = { "user": bootstrap_user_data(g.user, include_perms=True), - "common": common_bootstrap_payload(), + "common": common_bootstrap_payload(g.user), } return self.render_template( "superset/spa.html", @@ -583,7 +624,7 @@ def yaml_export( class DeleteMixin: # pylint: disable=too-few-public-methods def _delete(self: BaseView, primary_key: int) -> None: """ - Delete function logic, override to implement diferent logic + Delete function logic, override to implement different logic deletes the record with primary_key = primary_key :param primary_key: @@ -646,10 +687,7 @@ def apply(self, query: Query, value: Any) -> Query: owner_ids_query = ( db.session.query(models.SqlaTable.id) .join(models.SqlaTable.owners) - .filter( - security_manager.user_model.id - == security_manager.user_model.get_user_id() - ) + .filter(security_manager.user_model.id == get_user_id()) ) return query.filter( or_( @@ -669,51 +707,15 @@ class CsvResponse(Response): default_mimetype = "text/csv" -def check_ownership(obj: Any, raise_if_false: bool = True) -> bool: - """Meant to be used in `pre_update` hooks on models to enforce ownership - - Admin have all access, and other users need to be referenced on either - the created_by field that comes with the ``AuditMixin``, or in a field - named ``owners`` which is expected to be a one-to-many with the User - model. It is meant to be used in the ModelView's pre_update hook in - which raising will abort the update. +class XlsxResponse(Response): + """ + Override Response to use xlsx mimetype """ - if not obj: - return False - - security_exception = SupersetSecurityException( - SupersetError( - error_type=SupersetErrorType.MISSING_OWNERSHIP_ERROR, - message="You don't have the rights to alter [{}]".format(obj), - level=ErrorLevel.ERROR, - ) - ) - if g.user.is_anonymous: - if raise_if_false: - raise security_exception - return False - if is_user_admin(): - return True - scoped_session = db.create_scoped_session() - orig_obj = scoped_session.query(obj.__class__).filter_by(id=obj.id).first() - - # Making a list of owners that works across ORM models - owners: List[User] = [] - if hasattr(orig_obj, "owners"): - owners += orig_obj.owners - if hasattr(orig_obj, "owner"): - owners += [orig_obj.owner] - if hasattr(orig_obj, "created_by"): - owners += [orig_obj.created_by] - - owner_names = [o.username for o in owners if o] - - if g.user and hasattr(g.user, "username") and g.user.username in owner_names: - return True - if raise_if_false: - raise security_exception - return False + charset = "utf-8" + default_mimetype = ( + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ) def bind_field( diff --git a/superset/views/base_api.py b/superset/views/base_api.py index 01b462bb321f6..57d7e17367922 100644 --- a/superset/views/base_api.py +++ b/superset/views/base_api.py @@ -14,13 +14,15 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from __future__ import annotations + import functools import logging from typing import Any, Callable, cast, Dict, List, Optional, Set, Tuple, Type, Union -from flask import Blueprint, g, request, Response -from flask_appbuilder import AppBuilder, Model, ModelRestApi -from flask_appbuilder.api import expose, protect, rison, safe +from flask import request, Response +from flask_appbuilder import Model, ModelRestApi +from flask_appbuilder.api import BaseApi, expose, protect, rison, safe from flask_appbuilder.models.filters import BaseFilter, Filters from flask_appbuilder.models.sqla.filters import FilterStartsWith from flask_appbuilder.models.sqla.interface import SQLAInterface @@ -30,15 +32,14 @@ from sqlalchemy.orm.query import Query from superset.exceptions import InvalidPayloadFormatError -from superset.extensions import db, event_logger, security_manager +from superset.extensions import db, event_logger, security_manager, stats_logger_manager from superset.models.core import FavStar from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.schemas import error_payload_content from superset.sql_lab import Query as SqllabQuery -from superset.stats_logger import BaseStatsLogger from superset.superset_typing import FlaskResponse -from superset.utils.core import time_function +from superset.utils.core import get_user_id, time_function from superset.views.base import handle_api_exception logger = logging.getLogger(__name__) @@ -56,6 +57,7 @@ class RelatedResultResponseSchema(Schema): value = fields.Integer(description="The related item identifier") text = fields.String(description="The related item string representation") + extra = fields.Dict(description="The extra metadata for related item") class RelatedResponseSchema(Schema): @@ -90,7 +92,7 @@ def requires_form_data(f: Callable[..., Any]) -> Callable[..., Any]: Require 'multipart/form-data' as request MIME type """ - def wraps(self: "BaseSupersetModelRestApi", *args: Any, **kwargs: Any) -> Response: + def wraps(self: BaseSupersetApiMixin, *args: Any, **kwargs: Any) -> Response: if not request.mimetype == "multipart/form-data": raise InvalidPayloadFormatError( message="Request MIME type is not 'multipart/form-data'" @@ -105,14 +107,21 @@ def statsd_metrics(f: Callable[..., Any]) -> Callable[..., Any]: Handle sending all statsd metrics from the REST API """ - def wraps(self: "BaseSupersetModelRestApi", *args: Any, **kwargs: Any) -> Response: + def wraps(self: BaseSupersetApiMixin, *args: Any, **kwargs: Any) -> Response: + func_name = f.__name__ try: duration, response = time_function(f, self, *args, **kwargs) except Exception as ex: - self.incr_stats("error", f.__name__) + if ( + hasattr(ex, "status") + and ex.status < 500 # type: ignore # pylint: disable=no-member + ): + self.incr_stats("warning", func_name) + else: + self.incr_stats("error", func_name) raise ex - self.send_stats_metrics(response, f.__name__, duration) + self.send_stats_metrics(response, func_name, duration) return response return functools.update_wrapper(wraps, f) @@ -145,7 +154,7 @@ def apply(self, query: Query, value: Any) -> Query: return query users_favorite_query = db.session.query(FavStar.obj_id).filter( and_( - FavStar.user_id == g.user.get_id(), + FavStar.user_id == get_user_id(), FavStar.class_name == self.class_name, ) ) @@ -154,12 +163,71 @@ def apply(self, query: Query, value: Any) -> Query: return query.filter(and_(~self.model.id.in_(users_favorite_query))) -class BaseSupersetModelRestApi(ModelRestApi): +class BaseSupersetApiMixin: + csrf_exempt = False + + responses = { + "400": {"description": "Bad request", "content": error_payload_content}, + "401": {"description": "Unauthorized", "content": error_payload_content}, + "403": {"description": "Forbidden", "content": error_payload_content}, + "404": {"description": "Not found", "content": error_payload_content}, + "410": {"description": "Gone", "content": error_payload_content}, + "422": { + "description": "Could not process entity", + "content": error_payload_content, + }, + "500": {"description": "Fatal error", "content": error_payload_content}, + } + + def incr_stats(self, action: str, func_name: str) -> None: + """ + Proxy function for statsd.incr to impose a key structure for REST API's + :param action: String with an action name eg: error, success + :param func_name: The function name + """ + stats_logger_manager.instance.incr( + f"{self.__class__.__name__}.{func_name}.{action}" + ) + + def timing_stats(self, action: str, func_name: str, value: float) -> None: + """ + Proxy function for statsd.incr to impose a key structure for REST API's + :param action: String with an action name eg: error, success + :param func_name: The function name + :param value: A float with the time it took for the endpoint to execute + """ + stats_logger_manager.instance.timing( + f"{self.__class__.__name__}.{func_name}.{action}", value + ) + + def send_stats_metrics( + self, response: Response, key: str, time_delta: Optional[float] = None + ) -> None: + """ + Helper function to handle sending statsd metrics + :param response: flask response object, will evaluate if it was an error + :param key: The function name + :param time_delta: Optional time it took for the endpoint to execute + """ + if 200 <= response.status_code < 400: + self.incr_stats("success", key) + elif 400 <= response.status_code < 500: + self.incr_stats("warning", key) + else: + self.incr_stats("error", key) + if time_delta: + self.timing_stats("time", key, time_delta) + + +class BaseSupersetApi(BaseSupersetApiMixin, BaseApi): + ... + + +class BaseSupersetModelRestApi(ModelRestApi, BaseSupersetApiMixin): """ Extends FAB's ModelResApi to implement specific superset generic functionality """ - csrf_exempt = False method_permission_name = { "bulk_delete": "delete", "data": "list", @@ -194,21 +262,27 @@ class BaseSupersetModelRestApi(ModelRestApi): } """ - related_field_filters: Dict[str, Union[RelatedFieldFilter, str]] = {} + base_related_field_filters: Dict[str, BaseFilter] = {} """ - Declare the filters for related fields:: + This is used to specify a base filter for related fields + when they are accessed through the '/related/<column_name>' endpoint. + When combined with the `related_field_filters` attribute, + this filter will be applied in addition to the latest:: - related_fields = { - "<RELATED_FIELD>": <RelatedFieldFilter>) + base_related_field_filters = { + "<RELATED_FIELD>": "<FILTER>") } """ - filter_rel_fields: Dict[str, BaseFilter] = {} + related_field_filters: Dict[str, Union[RelatedFieldFilter, str]] = {} """ - Declare the related field base filter:: + Specify a filter for related fields when they are accessed + through the '/related/<column_name>' endpoint. + When combined with the `base_related_field_filters` attribute, + this filter will be applied in prior to the latest:: - filter_rel_fields_field = { - "<RELATED_FIELD>": "<FILTER>") + related_fields = { + "<RELATED_FIELD>": <RelatedFieldFilter>) } """ allowed_rel_fields: Set[str] = set() @@ -223,6 +297,15 @@ class BaseSupersetModelRestApi(ModelRestApi): } """ + extra_fields_rel_fields: Dict[str, List[str]] = {"owners": ["email", "active"]} + """ + Declare extra fields for the representation of the Model object:: + + extra_fields_rel_fields = { + "<RELATED_FIELD>": "[<RELATED_OBJECT_FIELD_1>, <RELATED_OBJECT_FIELD_2>]" + } + """ + allowed_distinct_fields: Set[str] = set() add_columns: List[str] @@ -230,22 +313,8 @@ class BaseSupersetModelRestApi(ModelRestApi): list_columns: List[str] show_columns: List[str] - responses = { - "400": {"description": "Bad request", "content": error_payload_content}, - "401": {"description": "Unauthorized", "content": error_payload_content}, - "403": {"description": "Forbidden", "content": error_payload_content}, - "404": {"description": "Not found", "content": error_payload_content}, - "422": { - "description": "Could not process entity", - "content": error_payload_content, - }, - "500": {"description": "Fatal error", "content": error_payload_content}, - } - def __init__(self) -> None: super().__init__() - # Setup statsd - self.stats_logger = BaseStatsLogger() # Add base API spec base query parameter schemas if self.apispec_parameter_schemas is None: # type: ignore self.apispec_parameter_schemas = {} @@ -257,12 +326,6 @@ def __init__(self) -> None: DistincResponseSchema, ) - def create_blueprint( - self, appbuilder: AppBuilder, *args: Any, **kwargs: Any - ) -> Blueprint: - self.stats_logger = self.appbuilder.get_app.config["STATS_LOGGER"] - return super().create_blueprint(appbuilder, *args, **kwargs) - def _init_properties(self) -> None: """ Lock down initial not configured REST API columns. We want to just expose @@ -289,7 +352,7 @@ def _get_related_filter( filter_field = cast(RelatedFieldFilter, filter_field) search_columns = [filter_field.field_name] if filter_field else None filters = datamodel.get_filters(search_columns) - base_filters = self.filter_rel_fields.get(column_name) + base_filters = self.base_related_field_filters.get(column_name) if base_filters: filters.add_filter_list(base_filters) if value and filter_field: @@ -317,6 +380,17 @@ def _get_text_for_model(self, model: Model, column_name: str) -> str: return getattr(model, model_column_name) return str(model) + def _get_extra_field_for_model( + self, model: Model, column_name: str + ) -> Dict[str, str]: + ret = {} + if column_name in self.extra_fields_rel_fields: + model_column_names = self.extra_fields_rel_fields.get(column_name) + if model_column_names: + for key in model_column_names: + ret[key] = getattr(model, key) + return ret + def _get_result_from_rows( self, datamodel: SQLAInterface, rows: List[Model], column_name: str ) -> List[Dict[str, Any]]: @@ -324,6 +398,7 @@ def _get_result_from_rows( { "value": datamodel.get_pk_value(row), "text": self._get_text_for_model(row, column_name), + "extra": self._get_extra_field_for_model(row, column_name), } for row in rows ] @@ -344,44 +419,6 @@ def _add_extra_ids_to_result( extra_rows = db.session.query(datamodel.obj).filter(pk_col.in_(ids)).all() result += self._get_result_from_rows(datamodel, extra_rows, column_name) - def incr_stats(self, action: str, func_name: str) -> None: - """ - Proxy function for statsd.incr to impose a key structure for REST API's - - :param action: String with an action name eg: error, success - :param func_name: The function name - """ - self.stats_logger.incr(f"{self.__class__.__name__}.{func_name}.{action}") - - def timing_stats(self, action: str, func_name: str, value: float) -> None: - """ - Proxy function for statsd.incr to impose a key structure for REST API's - - :param action: String with an action name eg: error, success - :param func_name: The function name - :param value: A float with the time it took for the endpoint to execute - """ - self.stats_logger.timing( - f"{self.__class__.__name__}.{func_name}.{action}", value - ) - - def send_stats_metrics( - self, response: Response, key: str, time_delta: Optional[float] = None - ) -> None: - """ - Helper function to handle sending statsd metrics - - :param response: flask response object, will evaluate if it was an error - :param key: The function name - :param time_delta: Optional time it took for the endpoint to execute - """ - if 200 <= response.status_code < 400: - self.incr_stats("success", key) - else: - self.incr_stats("error", key) - if time_delta: - self.timing_stats("time", key, time_delta) - @event_logger.log_this_with_context( action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.info", object_ref=False, diff --git a/superset/views/base_schemas.py b/superset/views/base_schemas.py index b7ffc72223db6..778f737fe09cb 100644 --- a/superset/views/base_schemas.py +++ b/superset/views/base_schemas.py @@ -21,6 +21,8 @@ from marshmallow import post_load, pre_load, Schema, ValidationError from sqlalchemy.orm.exc import NoResultFound +from superset.utils.core import get_user_id + def validate_owner(value: int) -> None: try: @@ -113,8 +115,9 @@ def pre_load(self, data: Dict[Any, Any]) -> None: @staticmethod def set_owners(instance: Model, owners: List[int]) -> None: owner_objs = [] - if g.user.get_id() not in owners: - owners.append(g.user.get_id()) + user_id = get_user_id() + if user_id and user_id not in owners: + owners.append(user_id) for owner_id in owners: user = current_app.appbuilder.get_session.query( current_app.appbuilder.sm.user_model diff --git a/superset/views/chart/views.py b/superset/views/chart/views.py index 72058c32e7f33..250fa901e9a6d 100644 --- a/superset/views/chart/views.py +++ b/superset/views/chart/views.py @@ -14,25 +14,17 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import json - -from flask import g from flask_appbuilder import expose, has_access from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_babel import lazy_gettext as _ +from superset import security_manager from superset.constants import MODEL_VIEW_RW_METHOD_PERMISSION_MAP, RouteMethod from superset.models.slice import Slice from superset.superset_typing import FlaskResponse from superset.utils import core as utils -from superset.views.base import ( - check_ownership, - common_bootstrap_payload, - DeleteMixin, - SupersetModelView, -) +from superset.views.base import DeleteMixin, SupersetModelView from superset.views.chart.mixin import SliceMixin -from superset.views.utils import bootstrap_user_data class SliceModelView( @@ -53,21 +45,15 @@ def pre_add(self, item: "SliceModelView") -> None: def pre_update(self, item: "SliceModelView") -> None: utils.validate_json(item.params) - check_ownership(item) + security_manager.raise_for_ownership(item) def pre_delete(self, item: "SliceModelView") -> None: - check_ownership(item) + security_manager.raise_for_ownership(item) @expose("/add", methods=["GET", "POST"]) @has_access def add(self) -> FlaskResponse: - payload = { - "common": common_bootstrap_payload(), - "user": bootstrap_user_data(g.user), - } - return self.render_template( - "superset/add_slice.html", bootstrap_data=json.dumps(payload) - ) + return super().render_app_template() @expose("/list/") @has_access diff --git a/superset/views/core.py b/superset/views/core.py index 83c0a33386ed6..d602d88bce669 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -20,12 +20,11 @@ import logging import re from contextlib import closing -from datetime import datetime, timedelta +from datetime import datetime from typing import Any, Callable, cast, Dict, List, Optional, Union from urllib import parse import backoff -import humanize import pandas as pd import simplejson as json from flask import abort, flash, g, redirect, render_template, request, Response @@ -41,7 +40,6 @@ from sqlalchemy import and_, or_ from sqlalchemy.exc import DBAPIError, NoSuchModuleError, SQLAlchemyError from sqlalchemy.orm.session import Session -from sqlalchemy.sql import functions as func from superset import ( app, @@ -58,16 +56,17 @@ ) from superset.charts.commands.exceptions import ChartNotFoundError from superset.charts.dao import ChartDAO +from superset.charts.data.commands.get_data_command import ChartDataCommand from superset.common.chart_data import ChartDataResultFormat, ChartDataResultType from superset.common.db_query_status import QueryStatus from superset.connectors.base.models import BaseDatasource -from superset.connectors.connector_registry import ConnectorRegistry from superset.connectors.sqla.models import ( AnnotationDatasource, SqlaTable, SqlMetric, TableColumn, ) +from superset.constants import QUERY_EARLY_CANCEL_KEY from superset.dashboards.commands.importers.v0 import ImportDashboardsCommand from superset.dashboards.dao import DashboardDAO from superset.dashboards.permalink.commands.get import GetDashboardPermalinkCommand @@ -77,6 +76,7 @@ from superset.databases.filters import DatabaseFilter from superset.databases.utils import make_url_safe from superset.datasets.commands.exceptions import DatasetNotFoundError +from superset.datasource.dao import DatasourceDAO from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import ( CacheLoadError, @@ -90,13 +90,14 @@ SupersetSecurityException, SupersetTimeoutException, ) +from superset.explore.form_data.commands.create import CreateFormDataCommand from superset.explore.form_data.commands.get import GetFormDataCommand from superset.explore.form_data.commands.parameters import CommandParameters from superset.explore.permalink.commands.get import GetExplorePermalinkCommand from superset.explore.permalink.exceptions import ExplorePermalinkGetFailedError from superset.extensions import async_query_manager, cache_manager from superset.jinja_context import get_template_processor -from superset.models.core import Database, FavStar, Log +from superset.models.core import Database, FavStar from superset.models.dashboard import Dashboard from superset.models.datasource_access_request import DatasourceAccessRequest from superset.models.slice import Slice @@ -107,8 +108,8 @@ from superset.sql_lab import get_sql_results from superset.sql_parse import ParsedQuery from superset.sql_validators import get_validator_by_name -from superset.sqllab.command import CommandResult, ExecuteSqlCommand from superset.sqllab.command_status import SqlJsonExecutionStatus +from superset.sqllab.commands.execute import CommandResult, ExecuteSqlCommand from superset.sqllab.exceptions import ( QueryIsForbiddenToAccessException, SqlLabException, @@ -129,17 +130,21 @@ from superset.utils import core as utils, csv from superset.utils.async_query_manager import AsyncQueryTokenException from superset.utils.cache import etag_cache -from superset.utils.core import apply_max_row_limit, ReservedUrlParameters +from superset.utils.core import ( + apply_max_row_limit, + DatasourceType, + get_user_id, + ReservedUrlParameters, +) from superset.utils.dates import now_as_float from superset.utils.decorators import check_dashboard_access from superset.views.base import ( api, BaseSupersetView, - check_ownership, common_bootstrap_payload, - create_table_permissions, CsvResponse, data_payload_response, + deprecated, generate_download_headers, get_error_msg, handle_api_exception, @@ -148,6 +153,8 @@ json_success, validate_sqlatable, ) +from superset.views.log.dao import LogDAO +from superset.views.sql_lab.schemas import SqlJsonPayloadSchema from superset.views.utils import ( _deserialize_results_payload, bootstrap_user_data, @@ -159,7 +166,7 @@ get_datasource_info, get_form_data, get_viz, - is_owner, + loads_request_json, sanitize_datasource_data, ) from superset.viz import BaseViz @@ -175,7 +182,6 @@ "allow_ctas", "allow_cvas", "allow_dml", - "allow_multi_schema_metadata_fetch", "allow_run_async", "allows_subquery", "backend", @@ -188,7 +194,7 @@ DATASOURCE_MISSING_ERR = __("The data source seems to have been deleted") USER_MISSING_ERR = __("The user seems to have been deleted") -PARAMETER_MISSING_ERR = ( +PARAMETER_MISSING_ERR = __( "Please check your template parameters for syntax errors and make sure " "they match across your SQL query and Set Parameters. Then, try running " "your query again." @@ -205,6 +211,7 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods @has_access_api @event_logger.log_this @expose("/datasources/") + @deprecated() def datasources(self) -> FlaskResponse: return self.json_response( sorted( @@ -250,7 +257,7 @@ def override_role_permissions(self) -> FlaskResponse: ) db_ds_names.add(fullname) - existing_datasources = ConnectorRegistry.get_all_datasources(db.session) + existing_datasources = SqlaTable.get_all_datasources(db.session) datasources = [d for d in existing_datasources if d.full_name in db_ds_names] role = security_manager.find_role(role_name) # remove all permissions @@ -273,6 +280,7 @@ def override_role_permissions(self) -> FlaskResponse: @has_access @event_logger.log_this @expose("/request_access/", methods=["POST"]) + @deprecated() def request_access(self) -> FlaskResponse: logger.warning( "%s.approve " @@ -288,7 +296,7 @@ def request_access(self) -> FlaskResponse: datasource_id = request.args.get("datasource_id") datasource_type = request.args.get("datasource_type") if datasource_id and datasource_type: - ds_class = ConnectorRegistry.sources.get(datasource_type) + ds_class = DatasourceDAO.sources.get(datasource_type) datasource = ( db.session.query(ds_class).filter_by(id=int(datasource_id)).one() ) @@ -322,13 +330,12 @@ def request_access(self) -> FlaskResponse: @has_access @event_logger.log_this @expose("/approve", methods=["POST"]) - def approve(self) -> FlaskResponse: # pylint: disable=too-many-locals + @deprecated() + def approve(self) -> FlaskResponse: # pylint: disable=too-many-locals,no-self-use def clean_fulfilled_requests(session: Session) -> None: for dar in session.query(DAR).all(): - datasource = ConnectorRegistry.get_datasource( - dar.datasource_type, - dar.datasource_id, - session, + datasource = DatasourceDAO.get_datasource( + session, DatasourceType(dar.datasource_type), dar.datasource_id ) if not datasource or security_manager.can_access_datasource(datasource): # Dataset does not exist anymore @@ -348,8 +355,8 @@ def clean_fulfilled_requests(session: Session) -> None: role_to_extend = request.args.get("role_to_extend") session = db.session - datasource = ConnectorRegistry.get_datasource( - datasource_type, datasource_id, session + datasource = DatasourceDAO.get_datasource( + session, DatasourceType(datasource_type), int(datasource_id) ) if not datasource: @@ -377,8 +384,8 @@ def clean_fulfilled_requests(session: Session) -> None: return json_error_response(err) # check if you can approve - if security_manager.can_access_all_datasources() or check_ownership( - datasource, raise_if_false=False + if security_manager.can_access_all_datasources() or security_manager.is_owner( + datasource ): # can by done by admin only if role_to_grant: @@ -438,13 +445,13 @@ def slice(self, slice_id: int) -> FlaskResponse: # pylint: disable=no-self-use _, slc = get_form_data(slice_id, use_slice_data=True) if not slc: abort(404) - endpoint = "/superset/explore/?form_data={}".format( + endpoint = "/explore/?form_data={}".format( parse.quote(json.dumps({"slice_id": slice_id})) ) is_standalone_mode = ReservedUrlParameters.is_standalone_mode() if is_standalone_mode: - endpoint += f"&{ReservedUrlParameters.STANDALONE}={is_standalone_mode}" + endpoint += f"&{ReservedUrlParameters.STANDALONE}=true" return redirect(endpoint) def get_query_string_response(self, viz_obj: BaseViz) -> FlaskResponse: @@ -510,6 +517,7 @@ def generate_json( @expose("/slice_json/<int:slice_id>") @etag_cache() @check_resource_permissions(check_slice_perms) + @deprecated() def slice_json(self, slice_id: int) -> FlaskResponse: form_data, slc = get_form_data(slice_id, use_slice_data=True) if not slc: @@ -533,6 +541,7 @@ def slice_json(self, slice_id: int) -> FlaskResponse: @has_access_api @event_logger.log_this @expose("/annotation_json/<int:layer_id>") + @deprecated() def annotation_json( # pylint: disable=no-self-use self, layer_id: int ) -> FlaskResponse: @@ -642,7 +651,7 @@ def explore_json( and not security_manager.can_access("can_csv", "Superset") ): return json_error_response( - _("You don't have the rights to ") + _("download as csv"), + _("You don't have the rights to download as csv"), status=403, ) @@ -651,7 +660,6 @@ def explore_json( datasource_id, datasource_type = get_datasource_info( datasource_id, datasource_type, form_data ) - force = request.args.get("force") == "true" # TODO: support CSV, SQL query and other non-JSON types @@ -684,7 +692,7 @@ def explore_json( request )["channel"] job_metadata = async_query_manager.init_job( - async_channel_id, g.user.get_id() + async_channel_id, get_user_id() ) load_explore_json_into_cache.delay( job_metadata, form_data, response_type, force @@ -748,11 +756,49 @@ def import_dashboards(self) -> FlaskResponse: "superset/import_dashboards.html", databases=databases ) + @staticmethod + def get_redirect_url() -> str: + """Assembles the redirect URL to the new endpoint. It also replaces + the form_data param with a form_data_key by saving the original content + to the cache layer. + """ + redirect_url = request.url.replace("/superset/explore", "/explore") + form_data_key = None + request_form_data = request.args.get("form_data") + if request_form_data: + parsed_form_data = loads_request_json(request_form_data) + slice_id = parsed_form_data.get( + "slice_id", int(request.args.get("slice_id", 0)) + ) + datasource = parsed_form_data.get("datasource") + if datasource: + datasource_id, datasource_type = datasource.split("__") + parameters = CommandParameters( + datasource_id=datasource_id, + datasource_type=datasource_type, + chart_id=slice_id, + form_data=request_form_data, + ) + form_data_key = CreateFormDataCommand(parameters).run() + if form_data_key: + url = parse.urlparse(redirect_url) + query = parse.parse_qs(url.query) + query.pop("form_data") + query["form_data_key"] = [form_data_key] + url = url._replace(query=parse.urlencode(query, True)) + redirect_url = parse.urlunparse(url) + + # Return a relative URL + url = parse.urlparse(redirect_url) + if url.query: + return f"{url.path}?{url.query}" + return url.path + @has_access @event_logger.log_this @expose("/explore/<datasource_type>/<int:datasource_id>/", methods=["GET", "POST"]) @expose("/explore/", methods=["GET", "POST"]) - @expose("/explore/p/<key>/", methods=["GET"]) + @deprecated() # pylint: disable=too-many-locals,too-many-branches,too-many-statements def explore( self, @@ -760,11 +806,14 @@ def explore( datasource_id: Optional[int] = None, key: Optional[str] = None, ) -> FlaskResponse: + if request.method == "GET": + return redirect(Superset.get_redirect_url()) + initial_form_data = {} form_data_key = request.args.get("form_data_key") if key is not None: - command = GetExplorePermalinkCommand(g.user, key) + command = GetExplorePermalinkCommand(key) try: permalink_value = command.run() if permalink_value: @@ -781,7 +830,7 @@ def explore( flash(__("Error: %(msg)s", msg=ex.message), "danger") return redirect("/chart/list/") elif form_data_key: - parameters = CommandParameters(actor=g.user, key=form_data_key) + parameters = CommandParameters(key=form_data_key) value = GetFormDataCommand(parameters).run() initial_form_data = json.loads(value) if value else {} @@ -815,14 +864,16 @@ def explore( ) except SupersetException: datasource_id = None - # fallback unkonw datasource to table type + # fallback unknown datasource to table type datasource_type = SqlaTable.type datasource: Optional[BaseDatasource] = None if datasource_id is not None: try: - datasource = ConnectorRegistry.get_datasource( - cast(str, datasource_type), datasource_id, db.session + datasource = DatasourceDAO.get_datasource( + db.session, + DatasourceType("table"), + datasource_id, ) except DatasetNotFoundError: pass @@ -846,9 +897,22 @@ def explore( if not viz_type and datasource and datasource.default_endpoint: return redirect(datasource.default_endpoint) + selectedColumns = [] + + if "selectedColumns" in form_data: + selectedColumns = form_data.pop("selectedColumns") + + if "viz_type" not in form_data: + form_data["viz_type"] = app.config["DEFAULT_VIZ_TYPE"] + if app.config["DEFAULT_VIZ_TYPE"] == "table": + all_columns = [] + for x in selectedColumns: + all_columns.append(x["name"]) + form_data["all_columns"] = all_columns + # slc perms slice_add_perm = security_manager.can_access("can_write", "Chart") - slice_overwrite_perm = is_owner(slc, g.user) if slc else False + slice_overwrite_perm = security_manager.is_owner(slc) if slc else False slice_download_perm = security_manager.can_access("can_csv", "Superset") form_data["datasource"] = str(datasource_id) + "__" + cast(str, datasource_type) @@ -866,13 +930,13 @@ def explore( if action == "overwrite" and not slice_overwrite_perm: return json_error_response( - _("You don't have the rights to ") + _("alter this ") + _("chart"), + _("You don't have the rights to alter this chart"), status=403, ) if action == "saveas" and not slice_add_perm: return json_error_response( - _("You don't have the rights to ") + _("create a ") + _("chart"), + _("You don't have the rights to create a chart"), status=403, ) @@ -918,7 +982,7 @@ def explore( "force": force, "user": bootstrap_user_data(g.user, include_perms=True), "forced_height": request.args.get("height"), - "common": common_bootstrap_payload(), + "common": common_bootstrap_payload(g.user), } if slc: title = slc.slice_name @@ -947,6 +1011,7 @@ def explore( @has_access_api @event_logger.log_this @expose("/filter/<datasource_type>/<int:datasource_id>/<column>/") + @deprecated() def filter( # pylint: disable=no-self-use self, datasource_type: str, datasource_id: int, column: str ) -> FlaskResponse: @@ -960,10 +1025,8 @@ def filter( # pylint: disable=no-self-use :raises SupersetSecurityException: If the user cannot access the resource """ # TODO: Cache endpoint by user, datasource and column - datasource = ConnectorRegistry.get_datasource( - datasource_type, - datasource_id, - db.session, + datasource = DatasourceDAO.get_datasource( + db.session, DatasourceType(datasource_type), datasource_id ) if not datasource: return json_error_response(DATASOURCE_MISSING_ERR) @@ -978,14 +1041,8 @@ def filter( # pylint: disable=no-self-use return json_success(payload) @staticmethod - def remove_extra_filters(filters: List[Dict[str, Any]]) -> List[Dict[str, Any]]: - """Extra filters are ones inherited from the dashboard's temporary context - Those should not be saved when saving the chart""" - return [f for f in filters if not f.get("isExtra")] - def save_or_overwrite_slice( # pylint: disable=too-many-arguments,too-many-locals - self, slc: Optional[Slice], slice_add_perm: bool, slice_overwrite_perm: bool, @@ -1005,9 +1062,7 @@ def save_or_overwrite_slice( form_data.pop("slice_id") # don't save old slice_id slc = Slice(owners=[g.user] if g.user else []) - form_data["adhoc_filters"] = self.remove_extra_filters( - form_data.get("adhoc_filters") or [] - ) + utils.remove_extra_adhoc_filters(form_data) assert slc slc.params = json.dumps(form_data, indent=2, sort_keys=True) @@ -1043,12 +1098,10 @@ def save_or_overwrite_slice( .one(), ) # check edit dashboard permissions - dash_overwrite_perm = check_ownership(dash, raise_if_false=False) + dash_overwrite_perm = security_manager.is_owner(dash) if not dash_overwrite_perm: return json_error_response( - _("You don't have the rights to ") - + _("alter this ") - + _("dashboard"), + _("You don't have the rights to alter this dashboard"), status=403, ) @@ -1064,9 +1117,7 @@ def save_or_overwrite_slice( dash_add_perm = security_manager.can_access("can_write", "Dashboard") if not dash_add_perm: return json_error_response( - _("You don't have the rights to ") - + _("create a ") - + _("dashboard"), + _("You don't have the rights to create a dashboard"), status=403, ) @@ -1102,132 +1153,100 @@ def save_or_overwrite_slice( @api @has_access_api @event_logger.log_this - @expose("/tables/<int:db_id>/<schema>/<substr>/") - @expose("/tables/<int:db_id>/<schema>/<substr>/<force_refresh>/") - @expose("/tables/<int:db_id>/<schema>/<substr>/<force_refresh>/<exact_match>") - def tables( # pylint: disable=too-many-locals,no-self-use,too-many-arguments + @expose("/tables/<int:db_id>/<schema>/") + @expose("/tables/<int:db_id>/<schema>/<force_refresh>/") + @deprecated() + def tables( # pylint: disable=no-self-use self, db_id: int, schema: str, - substr: str, force_refresh: str = "false", - exact_match: str = "false", ) -> FlaskResponse: """Endpoint to fetch the list of tables for given database""" - # Guarantees database filtering by security access - query = db.session.query(Database) - query = DatabaseFilter("id", SQLAInterface(Database, db.session)).apply( - query, None - ) - database = query.filter_by(id=db_id).one_or_none() - if not database: - return json_error_response("Not found", 404) force_refresh_parsed = force_refresh.lower() == "true" - exact_match_parsed = exact_match.lower() == "true" schema_parsed = utils.parse_js_uri_path_item(schema, eval_undefined=True) - substr_parsed = utils.parse_js_uri_path_item(substr, eval_undefined=True) - - if schema_parsed: - tables = [ - utils.DatasourceName(*datasource_name) - for datasource_name in database.get_all_table_names_in_schema( - schema=schema_parsed, - force=force_refresh_parsed, - cache=database.table_cache_enabled, - cache_timeout=database.table_cache_timeout, - ) - ] or [] - views = [ - utils.DatasourceName(*datasource_name) - for datasource_name in database.get_all_view_names_in_schema( - schema=schema_parsed, - force=force_refresh_parsed, - cache=database.table_cache_enabled, - cache_timeout=database.table_cache_timeout, - ) - ] or [] - else: - tables = [ - utils.DatasourceName(*datasource_name) - for datasource_name in database.get_all_table_names_in_database( - cache=True, force=False, cache_timeout=24 * 60 * 60 - ) - ] - views = [ - utils.DatasourceName(*datasource_name) - for datasource_name in database.get_all_view_names_in_database( - cache=True, force=False, cache_timeout=24 * 60 * 60 - ) - ] - tables = security_manager.get_datasources_accessible_by_user( - database, tables, schema_parsed - ) - views = security_manager.get_datasources_accessible_by_user( - database, views, schema_parsed - ) - - def get_datasource_label(ds_name: utils.DatasourceName) -> str: - return ( - ds_name.table if schema_parsed else f"{ds_name.schema}.{ds_name.table}" - ) - def is_match(src: str, target: utils.DatasourceName) -> bool: - target_label = get_datasource_label(target) - if exact_match_parsed: - return src == target_label - return src in target_label + if not schema_parsed: + return json_error_response(_("Schema undefined"), status=422) - if substr_parsed: - tables = [tn for tn in tables if is_match(substr_parsed, tn)] - views = [vn for vn in views if is_match(substr_parsed, vn)] - - if not schema_parsed and database.default_schemas: - user_schemas = ( - [g.user.email.split("@")[0]] if hasattr(g.user, "email") else [] + # Guarantees database filtering by security access + database = ( + DatabaseFilter("id", SQLAInterface(Database, db.session)) + .apply( + db.session.query(Database), + None, ) - valid_schemas = set(database.default_schemas + user_schemas) + .filter_by(id=db_id) + .one_or_none() + ) - tables = [tn for tn in tables if tn.schema in valid_schemas] - views = [vn for vn in views if vn.schema in valid_schemas] + if not database: + return json_error_response( + __("Database not found: %(id)s", id=db_id), status=404 + ) - max_items = config["MAX_TABLE_NAMES"] or len(tables) - total_items = len(tables) + len(views) - max_tables = len(tables) - max_views = len(views) - if total_items and substr_parsed: - max_tables = max_items * len(tables) // total_items - max_views = max_items * len(views) // total_items + try: + tables = security_manager.get_datasources_accessible_by_user( + database=database, + schema=schema_parsed, + datasource_names=sorted( + utils.DatasourceName(*datasource_name) + for datasource_name in database.get_all_table_names_in_schema( + schema=schema_parsed, + force=force_refresh_parsed, + cache=database.table_cache_enabled, + cache_timeout=database.table_cache_timeout, + ) + ), + ) - dataset_tables = {table.name: table for table in database.tables} + views = security_manager.get_datasources_accessible_by_user( + database=database, + schema=schema_parsed, + datasource_names=sorted( + utils.DatasourceName(*datasource_name) + for datasource_name in database.get_all_view_names_in_schema( + schema=schema_parsed, + force=force_refresh_parsed, + cache=database.table_cache_enabled, + cache_timeout=database.table_cache_timeout, + ) + ), + ) + except SupersetException as ex: + return json_error_response(ex.message, ex.status) + + extra_dict_by_name = { + table.name: table.extra_dict + for table in ( + db.session.query(SqlaTable).filter( + SqlaTable.database_id == database.id, + SqlaTable.schema == schema_parsed, + ) + ).all() + } - table_options = [ - { - "value": tn.table, - "schema": tn.schema, - "label": get_datasource_label(tn), - "title": get_datasource_label(tn), - "type": "table", - "extra": dataset_tables[f"{tn.schema}.{tn.table}"].extra_dict - if (f"{tn.schema}.{tn.table}" in dataset_tables) - else None, - } - for tn in tables[:max_tables] - ] - table_options.extend( + options = sorted( [ { - "value": vn.table, - "schema": vn.schema, - "label": get_datasource_label(vn), - "title": get_datasource_label(vn), - "type": "view", + "value": table.table, + "type": "table", + "extra": extra_dict_by_name.get(table.table, None), } - for vn in views[:max_views] + for table in tables ] + + [ + { + "value": view.table, + "type": "view", + } + for view in views + ], + key=lambda item: item["value"], ) - table_options.sort(key=lambda value: value["label"]) - payload = {"tableLength": len(tables) + len(views), "options": table_options} + + payload = {"tableLength": len(tables) + len(views), "options": options} return json_success(json.dumps(payload)) @api @@ -1290,7 +1309,7 @@ def save_dash( # pylint: disable=no-self-use """Save a dashboard's metadata""" session = db.session() dash = session.query(Dashboard).get(dashboard_id) - check_ownership(dash, raise_if_false=True) + security_manager.raise_for_ownership(dash) data = json.loads(request.form["data"]) # client-side send back last_modified_time which was set when # the dashboard was open. it was use to avoid mid-air collision. @@ -1333,7 +1352,7 @@ def add_slices( # pylint: disable=no-self-use data = json.loads(request.form["data"]) session = db.session() dash = session.query(Dashboard).get(dashboard_id) - check_ownership(dash, raise_if_false=True) + security_manager.raise_for_ownership(dash) new_slices = session.query(Slice).filter(Slice.id.in_(data["slice_ids"])) dash.slices += new_slices session.merge(dash) @@ -1345,13 +1364,9 @@ def add_slices( # pylint: disable=no-self-use @has_access_api @event_logger.log_this @expose("/testconn", methods=["POST", "GET"]) - def testconn(self) -> FlaskResponse: + @deprecated() + def testconn(self) -> FlaskResponse: # pylint: disable=no-self-use """Tests a sqla connection""" - logger.warning( - "%s.testconn " - "This API endpoint is deprecated and will be removed in version 3.0.0", - self.__class__.__name__, - ) db_name = request.json.get("name") uri = request.json.get("uri") try: @@ -1381,11 +1396,11 @@ def testconn(self) -> FlaskResponse: ) database.set_sqlalchemy_uri(uri) database.db_engine_spec.mutate_db_for_connection_test(database) - engine = database.get_sqla_engine() - with closing(engine.raw_connection()) as conn: - if engine.dialect.do_ping(conn): - return json_success('"OK"') + with database.get_sqla_engine_with_context() as engine: + with closing(engine.raw_connection()) as conn: + if engine.dialect.do_ping(conn): + return json_success('"OK"') raise DBAPIError(None, None, None) except CertificateException as ex: @@ -1438,9 +1453,8 @@ def get_user_activity_access_error(user_id: int) -> Optional[FlaskResponse]: @has_access_api @event_logger.log_this @expose("/recent_activity/<int:user_id>/", methods=["GET"]) - def recent_activity( # pylint: disable=too-many-locals - self, user_id: int - ) -> FlaskResponse: + @deprecated() + def recent_activity(self, user_id: int) -> FlaskResponse: """Recent activity (actions) for a given user""" error_obj = self.get_user_activity_access_error(user_id) if error_obj: @@ -1452,102 +1466,15 @@ def recent_activity( # pylint: disable=too-many-locals # whether to get distinct subjects distinct = request.args.get("distinct") != "false" - has_subject_title = or_( - and_( - Dashboard.dashboard_title is not None, - Dashboard.dashboard_title != "", - ), - and_(Slice.slice_name is not None, Slice.slice_name != ""), - ) - - if distinct: - one_year_ago = datetime.today() - timedelta(days=365) - subqry = ( - db.session.query( - Log.dashboard_id, - Log.slice_id, - Log.action, - func.max(Log.dttm).label("dttm"), - ) - .group_by(Log.dashboard_id, Log.slice_id, Log.action) - .filter( - and_( - Log.action.in_(actions), - Log.user_id == user_id, - # limit to one year of data to improve performance - Log.dttm > one_year_ago, - or_(Log.dashboard_id.isnot(None), Log.slice_id.isnot(None)), - ) - ) - .subquery() - ) - qry = ( - db.session.query( - subqry, - Dashboard.slug.label("dashboard_slug"), - Dashboard.dashboard_title, - Slice.slice_name, - ) - .outerjoin(Dashboard, Dashboard.id == subqry.c.dashboard_id) - .outerjoin( - Slice, - Slice.id == subqry.c.slice_id, - ) - .filter(has_subject_title) - .order_by(subqry.c.dttm.desc()) - .limit(limit) - ) - else: - qry = ( - db.session.query( - Log.dttm, - Log.action, - Log.dashboard_id, - Log.slice_id, - Dashboard.slug.label("dashboard_slug"), - Dashboard.dashboard_title, - Slice.slice_name, - ) - .outerjoin(Dashboard, Dashboard.id == Log.dashboard_id) - .outerjoin(Slice, Slice.id == Log.slice_id) - .filter(has_subject_title) - .order_by(Log.dttm.desc()) - .limit(limit) - ) + payload = LogDAO.get_recent_activity(user_id, actions, distinct, 0, limit) - payload = [] - for log in qry.all(): - item_url = None - item_title = None - item_type = None - if log.dashboard_id: - item_type = "dashboard" - item_url = Dashboard(id=log.dashboard_id, slug=log.dashboard_slug).url - item_title = log.dashboard_title - elif log.slice_id: - slc = Slice(id=log.slice_id, slice_name=log.slice_name) - item_type = "slice" - item_url = slc.slice_url - item_title = slc.chart - - payload.append( - { - "action": log.action, - "item_type": item_type, - "item_url": item_url, - "item_title": item_title, - "time": log.dttm, - "time_delta_humanized": humanize.naturaltime( - datetime.now() - log.dttm - ), - } - ) return json_success(json.dumps(payload, default=utils.json_int_dttm_ser)) @api @has_access_api @event_logger.log_this @expose("/available_domains/", methods=["GET"]) + @deprecated() def available_domains(self) -> FlaskResponse: # pylint: disable=no-self-use """ Returns the list of available Superset Webserver domains (if any) @@ -1562,13 +1489,9 @@ def available_domains(self) -> FlaskResponse: # pylint: disable=no-self-use @has_access_api @event_logger.log_this @expose("/fave_dashboards_by_username/<username>/", methods=["GET"]) + @deprecated() def fave_dashboards_by_username(self, username: str) -> FlaskResponse: """This lets us use a user's username to pull favourite dashboards""" - logger.warning( - "%s.fave_dashboards_by_username " - "This API endpoint is deprecated and will be removed in version 3.0.0", - self.__class__.__name__, - ) user = security_manager.find_user(username=username) return self.fave_dashboards(user.id) @@ -1576,12 +1499,8 @@ def fave_dashboards_by_username(self, username: str) -> FlaskResponse: @has_access_api @event_logger.log_this @expose("/fave_dashboards/<int:user_id>/", methods=["GET"]) + @deprecated() def fave_dashboards(self, user_id: int) -> FlaskResponse: - logger.warning( - "%s.fave_dashboards " - "This API endpoint is deprecated and will be removed in version 3.0.0", - self.__class__.__name__, - ) error_obj = self.get_user_activity_access_error(user_id) if error_obj: return error_obj @@ -1617,13 +1536,8 @@ def fave_dashboards(self, user_id: int) -> FlaskResponse: @has_access_api @event_logger.log_this @expose("/created_dashboards/<int:user_id>/", methods=["GET"]) + @deprecated() def created_dashboards(self, user_id: int) -> FlaskResponse: - logger.warning( - "%s.created_dashboards " - "This API endpoint is deprecated and will be removed in version 3.0.0", - self.__class__.__name__, - ) - error_obj = self.get_user_activity_access_error(user_id) if error_obj: return error_obj @@ -1657,7 +1571,7 @@ def created_dashboards(self, user_id: int) -> FlaskResponse: def user_slices(self, user_id: Optional[int] = None) -> FlaskResponse: """List of slices a user owns, created, modified or faved""" if not user_id: - user_id = cast(int, g.user.id) + user_id = cast(int, get_user_id()) error_obj = self.get_user_activity_access_error(user_id) if error_obj: return error_obj @@ -1707,10 +1621,11 @@ def user_slices(self, user_id: Optional[int] = None) -> FlaskResponse: @event_logger.log_this @expose("/created_slices", methods=["GET"]) @expose("/created_slices/<int:user_id>/", methods=["GET"]) + @deprecated() def created_slices(self, user_id: Optional[int] = None) -> FlaskResponse: """List of slices created by this user""" if not user_id: - user_id = cast(int, g.user.id) + user_id = cast(int, get_user_id()) error_obj = self.get_user_activity_access_error(user_id) if error_obj: return error_obj @@ -1741,7 +1656,7 @@ def created_slices(self, user_id: Optional[int] = None) -> FlaskResponse: def fave_slices(self, user_id: Optional[int] = None) -> FlaskResponse: """Favorite slices for a user""" if user_id is None: - user_id = g.user.id + user_id = cast(int, get_user_id()) error_obj = self.get_user_activity_access_error(user_id) if error_obj: return error_obj @@ -1837,28 +1752,35 @@ def warm_up_cache( # pylint: disable=too-many-locals,no-self-use for slc in slices: try: - form_data = get_form_data(slc.id, use_slice_data=True)[0] - if dashboard_id: - form_data["extra_filters"] = ( - json.loads(extra_filters) - if extra_filters - else get_dashboard_extra_filters(slc.id, dashboard_id) - ) + query_context = slc.get_query_context() + if query_context: + query_context.force = True + command = ChartDataCommand(query_context) + command.validate() + payload = command.run() + else: + form_data = get_form_data(slc.id, use_slice_data=True)[0] + if dashboard_id: + form_data["extra_filters"] = ( + json.loads(extra_filters) + if extra_filters + else get_dashboard_extra_filters(slc.id, dashboard_id) + ) - if not slc.datasource: - raise Exception("Slice's datasource does not exist") + if not slc.datasource: + raise Exception("Slice's datasource does not exist") - obj = get_viz( - datasource_type=slc.datasource.type, - datasource_id=slc.datasource.id, - form_data=form_data, - force=True, - ) + obj = get_viz( + datasource_type=slc.datasource.type, + datasource_id=slc.datasource.id, + form_data=form_data, + force=True, + ) + # pylint: disable=assigning-non-slot + g.form_data = form_data + payload = obj.get_payload() + delattr(g, "form_data") - # pylint: disable=assigning-non-slot - g.form_data = form_data - payload = obj.get_payload() - delattr(g, "form_data") error = payload["errors"] or None status = payload["status"] except Exception as ex: # pylint: disable=broad-except @@ -1878,13 +1800,13 @@ def favstar( # pylint: disable=no-self-use self, class_name: str, obj_id: int, action: str ) -> FlaskResponse: """Toggle favorite stars on Slices and Dashboard""" - if not g.user.get_id(): + if not get_user_id(): return json_error_response("ERROR: Favstar toggling denied", status=403) session = db.session() count = 0 favs = ( session.query(FavStar) - .filter_by(class_name=class_name, obj_id=obj_id, user_id=g.user.get_id()) + .filter_by(class_name=class_name, obj_id=obj_id, user_id=get_user_id()) .all() ) if action == "select": @@ -1893,7 +1815,7 @@ def favstar( # pylint: disable=no-self-use FavStar( class_name=class_name, obj_id=obj_id, - user_id=g.user.get_id(), + user_id=get_user_id(), dttm=datetime.now(), ) ) @@ -1932,8 +1854,8 @@ def dashboard( if config["ENABLE_ACCESS_REQUEST"]: for datasource in dashboard.datasources: - datasource = ConnectorRegistry.get_datasource( - datasource_type=datasource.type, + datasource = DatasourceDAO.get_datasource( + datasource_type=DatasourceType(datasource.type), datasource_id=datasource.id, session=db.session(), ) @@ -1950,8 +1872,8 @@ def dashboard( f"/superset/request_access/?dashboard_id={dashboard.id}" ) - dash_edit_perm = check_ownership( - dashboard, raise_if_false=False + dash_edit_perm = security_manager.is_owner( + dashboard ) and security_manager.can_access("can_save_dash", "Superset") edit_mode = ( request.args.get(utils.ReservedUrlParameters.EDIT_MODE.value) == "true" @@ -1968,12 +1890,14 @@ def dashboard( bootstrap_data = { "user": bootstrap_user_data(g.user, include_perms=True), - "common": common_bootstrap_payload(), + "common": common_bootstrap_payload(g.user), } return self.render_template( "superset/spa.html", entry="spa", + # dashboard title is always visible + title=dashboard.dashboard_title, bootstrap_data=json.dumps( bootstrap_data, default=utils.pessimistic_json_iso_dttm_ser ), @@ -1987,19 +1911,19 @@ def dashboard_permalink( # pylint: disable=no-self-use key: str, ) -> FlaskResponse: try: - value = GetDashboardPermalinkCommand(g.user, key).run() + value = GetDashboardPermalinkCommand(key).run() except DashboardPermalinkGetFailedError as ex: flash(__("Error: %(msg)s", msg=ex.message), "danger") return redirect("/dashboard/list/") if not value: return json_error_response(_("permalink state not found"), status=404) - dashboard_id = value["dashboardId"] + dashboard_id, state = value["dashboardId"], value.get("state", {}) url = f"/superset/dashboard/{dashboard_id}?permalink_key={key}" - url_params = value["state"].get("urlParams") + url_params = state.get("urlParams") if url_params: params = parse.urlencode(url_params) url = f"{url}&{params}" - hash_ = value["state"].get("hash") + hash_ = state.get("anchor", state.get("hash")) if hash_: url = f"{url}#{hash_}" return redirect(url) @@ -2014,6 +1938,7 @@ def log(self) -> FlaskResponse: # pylint: disable=no-self-use @has_access @expose("/get_or_create_table/", methods=["POST"]) @event_logger.log_this + @deprecated() def sqllab_table_viz(self) -> FlaskResponse: # pylint: disable=no-self-use """Gets or creates a table object with attributes passed to the API. @@ -2043,11 +1968,11 @@ def sqllab_table_viz(self) -> FlaskResponse: # pylint: disable=no-self-use table.schema = data.get("schema") table.template_params = data.get("templateParams") # needed for the table validation. + # fn can be deleted when this endpoint is removed validate_sqlatable(table) db.session.add(table) table.fetch_metadata() - create_table_permissions(table) db.session.commit() return json_success(json.dumps({"table_id": table.id})) @@ -2083,8 +2008,20 @@ def sqllab_viz(self) -> FlaskResponse: # pylint: disable=no-self-use .filter_by(database_id=database_id, table_name=table_name) .one_or_none() ) - if not table: - table = SqlaTable(table_name=table_name, owners=[g.user]) + + if table: + return json_errors_response( + [ + SupersetError( + message=f"Dataset [{table_name}] already exists", + error_type=SupersetErrorType.GENERIC_BACKEND_ERROR, + level=ErrorLevel.WARNING, + ) + ], + status=422, + ) + + table = SqlaTable(table_name=table_name, owners=[g.user]) table.database = database table.schema = data.get("schema") table.template_params = data.get("templateParams") @@ -2106,20 +2043,20 @@ def sqllab_viz(self) -> FlaskResponse: # pylint: disable=no-self-use table.columns = cols table.metrics = [SqlMetric(metric_name="count", expression="count(*)")] db.session.commit() - return json_success(json.dumps({"table_id": table.id})) + + return json_success( + json.dumps( + {"table_id": table.id, "data": sanitize_datasource_data(table.data)} + ) + ) @has_access @expose("/extra_table_metadata/<int:database_id>/<table_name>/<schema>/") @event_logger.log_this - def extra_table_metadata( + @deprecated() + def extra_table_metadata( # pylint: disable=no-self-use self, database_id: int, table_name: str, schema: str ) -> FlaskResponse: - logger.warning( - "%s.extra_table_metadata " - "This API endpoint is deprecated and will be removed in version 3.0.0", - self.__class__.__name__, - ) - parsed_schema = utils.parse_js_uri_path_item(schema, eval_undefined=True) table_name = utils.parse_js_uri_path_item(table_name) # type: ignore mydb = db.session.query(Database).filter_by(id=database_id).one() @@ -2174,6 +2111,7 @@ def theme(self) -> FlaskResponse: @has_access_api @expose("/results/<key>/") @event_logger.log_this + @deprecated() def results(self, key: str) -> FlaskResponse: return self.results_exec(key) @@ -2217,7 +2155,7 @@ def results_exec(key: str) -> FlaskResponse: raise SupersetErrorException( SupersetError( message=__( - "The query associated with these results could not be find. " + "The query associated with these results could not be found. " "You need to re-run the original query." ), error_type=SupersetErrorType.RESULTS_BACKEND_ERROR, @@ -2295,6 +2233,7 @@ def results_exec(key: str) -> FlaskResponse: on_giveup=lambda details: db.session.rollback(), max_tries=5, ) + @deprecated() def stop_query(self) -> FlaskResponse: client_id = request.form.get("client_id") query = db.session.query(Query).filter_by(client_id=client_id).one() @@ -2312,6 +2251,10 @@ def stop_query(self) -> FlaskResponse: raise SupersetCancelQueryException("Could not cancel query") query.status = QueryStatus.STOPPED + # Add the stop identity attribute because the sqlalchemy thread is unsafe + # because of multiple updates to the status in the query table + query.set_extra_json_key(QUERY_EARLY_CANCEL_KEY, True) + query.end_time = now_as_float() db.session.commit() return self.json_response("OK") @@ -2319,19 +2262,14 @@ def stop_query(self) -> FlaskResponse: @has_access_api @event_logger.log_this @expose("/validate_sql_json/", methods=["POST", "GET"]) + @deprecated() def validate_sql_json( - # pylint: disable=too-many-locals + # pylint: disable=too-many-locals,no-self-use self, ) -> FlaskResponse: """Validates that arbitrary sql is acceptable for the given database. Returns a list of error/warning annotations as json. """ - logger.warning( - "%s.validate_sql_json " - "This API endpoint is deprecated and will be removed in version 3.0.0", - self.__class__.__name__, - ) - sql = request.form["sql"] database_id = request.form["database_id"] schema = request.form.get("schema") or None @@ -2397,7 +2335,12 @@ def validate_sql_json( @handle_api_exception @event_logger.log_this @expose("/sql_json/", methods=["POST"]) + @deprecated() def sql_json(self) -> FlaskResponse: + errors = SqlJsonPayloadSchema().validate(request.json) + if errors: + return json_error_response(status=400, payload=errors) + try: log_params = { "user_agent": cast(Optional[str], request.headers.get("USER_AGENT")) @@ -2432,7 +2375,7 @@ def _create_sql_json_command( SqlQueryRenderImpl(get_template_processor), sql_json_executor, execution_context_convertor, - config.get("SQLLAB_CTAS_NO_LIMIT"), # type: ignore + config["SQLLAB_CTAS_NO_LIMIT"], log_params, ) @@ -2470,9 +2413,8 @@ def _create_response_from_execution_context( # pylint: disable=invalid-name, no @has_access @event_logger.log_this @expose("/csv/<client_id>") - def csv( # pylint: disable=no-self-use,too-many-locals - self, client_id: str - ) -> FlaskResponse: + @deprecated() + def csv(self, client_id: str) -> FlaskResponse: # pylint: disable=no-self-use """Download the query results as csv.""" logger.info("Exporting CSV file [%s]", client_id) query = db.session.query(Query).filter_by(client_id=client_id).one() @@ -2495,8 +2437,13 @@ def csv( # pylint: disable=no-self-use,too-many-locals obj = _deserialize_results_payload( payload, query, cast(bool, results_backend_use_msgpack) ) - columns = [c["name"] for c in obj["columns"]] - df = pd.DataFrame.from_records(obj["data"], columns=columns) + + df = pd.DataFrame( + data=obj["data"], + dtype=object, + columns=[c["name"] for c in obj["columns"]], + ) + logger.info("Using pandas to convert to CSV") else: logger.info("Running a query to turn into CSV") @@ -2540,6 +2487,7 @@ def csv( # pylint: disable=no-self-use,too-many-locals @has_access @event_logger.log_this @expose("/fetch_datasource_metadata") + @deprecated() def fetch_datasource_metadata(self) -> FlaskResponse: # pylint: disable=no-self-use """ Fetch the datasource metadata. @@ -2547,12 +2495,9 @@ def fetch_datasource_metadata(self) -> FlaskResponse: # pylint: disable=no-self :returns: The Flask response :raises SupersetSecurityException: If the user cannot access the resource """ - datasource_id, datasource_type = request.args["datasourceKey"].split("__") - datasource = ConnectorRegistry.get_datasource( - datasource_type, - datasource_id, - db.session, + datasource = DatasourceDAO.get_datasource( + db.session, DatasourceType(datasource_type), int(datasource_id) ) # Check if datasource exists if not datasource: @@ -2565,6 +2510,7 @@ def fetch_datasource_metadata(self) -> FlaskResponse: # pylint: disable=no-self @event_logger.log_this @expose("/queries/<float:last_updated_ms>") @expose("/queries/<int:last_updated_ms>") + @deprecated() def queries(self, last_updated_ms: Union[float, int]) -> FlaskResponse: """ Get the updated queries. @@ -2577,7 +2523,7 @@ def queries(self, last_updated_ms: Union[float, int]) -> FlaskResponse: @staticmethod def queries_exec(last_updated_ms: Union[float, int]) -> FlaskResponse: stats_logger.incr("queries") - if not g.user.get_id(): + if not get_user_id(): return json_error_response( "Please login to access the queries.", status=403 ) @@ -2587,9 +2533,7 @@ def queries_exec(last_updated_ms: Union[float, int]) -> FlaskResponse: sql_queries = ( db.session.query(Query) - .filter( - Query.user_id == g.user.get_id(), Query.changed_on >= last_updated_dt - ) + .filter(Query.user_id == get_user_id(), Query.changed_on >= last_updated_dt) .all() ) dict_queries = {q.client_id: q.to_dict() for q in sql_queries} @@ -2598,6 +2542,7 @@ def queries_exec(last_updated_ms: Union[float, int]) -> FlaskResponse: @has_access @event_logger.log_this @expose("/search_queries") + @deprecated() def search_queries(self) -> FlaskResponse: # pylint: disable=no-self-use """ Search for previously run sqllab queries. Used for Sqllab Query Search @@ -2615,10 +2560,10 @@ def search_queries(self) -> FlaskResponse: # pylint: disable=no-self-use search_user_id = int(cast(int, request.args.get("user_id"))) except ValueError: return Response(status=400, mimetype="application/json") - if search_user_id != g.user.get_user_id(): + if search_user_id != get_user_id(): return Response(status=403, mimetype="application/json") else: - search_user_id = g.user.get_user_id() + search_user_id = get_user_id() database_id = request.args.get("database_id") search_text = request.args.get("search_text") status = request.args.get("status") @@ -2671,14 +2616,14 @@ def show_traceback(self) -> FlaskResponse: # pylint: disable=no-self-use @expose("/welcome/") def welcome(self) -> FlaskResponse: """Personalized welcome page""" - if not g.user or not g.user.get_id(): + if not g.user or not get_user_id(): if conf["PUBLIC_ROLE_LIKE"]: return self.render_template("superset/public_welcome.html") return redirect(appbuilder.get_url_for_login) welcome_dashboard_id = ( db.session.query(UserAttribute.welcome_dashboard_id) - .filter_by(user_id=g.user.get_id()) + .filter_by(user_id=get_user_id()) .scalar() ) if welcome_dashboard_id: @@ -2686,7 +2631,7 @@ def welcome(self) -> FlaskResponse: payload = { "user": bootstrap_user_data(g.user, include_perms=True), - "common": common_bootstrap_payload(), + "common": common_bootstrap_payload(g.user), } return self.render_template( @@ -2715,7 +2660,7 @@ def profile(self, username: str) -> FlaskResponse: payload = { "user": bootstrap_user_data(user, include_perms=True), - "common": common_bootstrap_payload(), + "common": common_bootstrap_payload(g.user), } return self.render_template( @@ -2728,7 +2673,7 @@ def profile(self, username: str) -> FlaskResponse: ) @staticmethod - def _get_sqllab_tabs(user_id: int) -> Dict[str, Any]: + def _get_sqllab_tabs(user_id: Optional[int]) -> Dict[str, Any]: # send list of tab state ids tabs_state = ( db.session.query(TabState.id, TabState.label) @@ -2779,8 +2724,8 @@ def sqllab(self) -> FlaskResponse: """SQL Editor""" payload = { "defaultDbId": config["SQLLAB_DEFAULT_DBID"], - "common": common_bootstrap_payload(), - **self._get_sqllab_tabs(g.user.get_id()), + "common": common_bootstrap_payload(g.user), + **self._get_sqllab_tabs(get_user_id()), } form_data = request.form.get("form_data") diff --git a/superset/views/css_templates.py b/superset/views/css_templates.py index 597f9efbd4571..2041eaa94fc06 100644 --- a/superset/views/css_templates.py +++ b/superset/views/css_templates.py @@ -25,9 +25,10 @@ from superset.views.base import DeleteMixin, SupersetModelView -class CssTemplateModelView( - SupersetModelView, DeleteMixin -): # pylint: disable=too-many-ancestors +class CssTemplateModelView( # pylint: disable=too-many-ancestors + SupersetModelView, + DeleteMixin, +): datamodel = SQLAInterface(models.CssTemplate) include_route_methods = RouteMethod.CRUD_SET diff --git a/superset/views/dashboard/mixin.py b/superset/views/dashboard/mixin.py index 77748fdc3b105..d8838b26c9d30 100644 --- a/superset/views/dashboard/mixin.py +++ b/superset/views/dashboard/mixin.py @@ -16,8 +16,8 @@ # under the License. from flask_babel import lazy_gettext as _ -from ...dashboards.filters import DashboardAccessFilter -from ..base import check_ownership +from superset import security_manager +from superset.dashboards.filters import DashboardAccessFilter class DashboardMixin: # pylint: disable=too-few-public-methods @@ -66,7 +66,7 @@ class DashboardMixin: # pylint: disable=too-few-public-methods "roles": _( "Roles is a list which defines access to the dashboard. " "Granting a role access to a dashboard will bypass dataset level checks." - "If no roles defined then the dashboard is available to all roles." + "If no roles are defined then the dashboard is available to all roles." ), "published": _( "Determines whether or not this dashboard is " @@ -90,4 +90,4 @@ class DashboardMixin: # pylint: disable=too-few-public-methods } def pre_delete(self, item: "DashboardMixin") -> None: # pylint: disable=no-self-use - check_ownership(item) + security_manager.raise_for_ownership(item) diff --git a/superset/views/dashboard/views.py b/superset/views/dashboard/views.py index 256bb4c95c025..52cb2da82e911 100644 --- a/superset/views/dashboard/views.py +++ b/superset/views/dashboard/views.py @@ -24,7 +24,7 @@ from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_appbuilder.security.decorators import has_access from flask_babel import gettext as __, lazy_gettext as _ -from flask_login import AnonymousUserMixin, LoginManager +from flask_login import AnonymousUserMixin, login_user from superset import db, event_logger, is_feature_enabled, security_manager from superset.constants import MODEL_VIEW_RW_METHOD_PERMISSION_MAP, RouteMethod @@ -33,7 +33,6 @@ from superset.utils import core as utils from superset.views.base import ( BaseSupersetView, - check_ownership, common_bootstrap_payload, DeleteMixin, generate_download_headers, @@ -97,12 +96,11 @@ def pre_add(self, item: "DashboardModelView") -> None: item.owners.append(g.user) utils.validate_json(item.json_metadata) utils.validate_json(item.position_json) - owners = list(item.owners) for slc in item.slices: - slc.owners = list(set(owners) | set(slc.owners)) + slc.owners = list(set(item.owners) | set(slc.owners)) def pre_update(self, item: "DashboardModelView") -> None: - check_ownership(item) + security_manager.raise_for_ownership(item) self.pre_add(item) @@ -151,8 +149,7 @@ def embedded( # Log in as an anonymous user, just for this view. # This view needs to be visible to all users, # and building the page fails if g.user and/or ctx.user aren't present. - login_manager: LoginManager = security_manager.lm - login_manager.reload_user(AnonymousUserMixin()) + login_user(AnonymousUserMixin(), force=True) add_extra_log_payload( dashboard_id=dashboard_id_or_slug, @@ -160,7 +157,7 @@ def embedded( ) bootstrap_data = { - "common": common_bootstrap_payload(), + "common": common_bootstrap_payload(g.user), "embedded": {"dashboard_id": dashboard_id_or_slug}, } diff --git a/superset/views/database/forms.py b/superset/views/database/forms.py index 4cf594c48705e..91ab38dc2fe5e 100644 --- a/superset/views/database/forms.py +++ b/superset/views/database/forms.py @@ -52,6 +52,7 @@ def file_allowed_dbs() -> List[Database]: # type: ignore file_enabled_db for file_enabled_db in file_enabled_dbs if UploadToDatabaseForm.at_least_one_schema_is_allowed(file_enabled_db) + and UploadToDatabaseForm.is_engine_allowed_to_file_upl(file_enabled_db) ] @staticmethod @@ -89,20 +90,24 @@ def at_least_one_schema_is_allowed(database: Database) -> bool: return True return False + @staticmethod + def is_engine_allowed_to_file_upl(database: Database) -> bool: + """ + This method is mainly used for existing Gsheets and Clickhouse DBs + that have allow_file_upload set as True but they are no longer valid + DBs for file uploading. + New GSheets and Clickhouse DBs won't have the option to set + allow_file_upload set as True. + """ + if database.db_engine_spec.supports_file_upload: + return True + return False + class CsvToDatabaseForm(UploadToDatabaseForm): - name = StringField( - _("Table Name"), - description=_("Name of table to be created from csv data."), - validators=[ - DataRequired(), - Regexp(r"^[^\.]+$", message=_("Table name cannot contain a schema")), - ], - widget=BS3TextFieldWidget(), - ) csv_file = FileField( - _("CSV File"), - description=_("Select a CSV file to be uploaded to a database."), + _("CSV Upload"), + description=_("Select a file to be uploaded to the database"), validators=[ FileRequired(), FileAllowed( @@ -119,31 +124,45 @@ class CsvToDatabaseForm(UploadToDatabaseForm): ), ], ) - con = QuerySelectField( + table_name = StringField( + _("Table Name"), + description=_("Name of table to be created with CSV file"), + validators=[ + DataRequired(), + Regexp(r"^[^\.]+$", message=_("Table name cannot contain a schema")), + ], + widget=BS3TextFieldWidget(), + ) + database = QuerySelectField( _("Database"), + description=_("Select a database to upload the file to"), query_factory=UploadToDatabaseForm.file_allowed_dbs, get_pk=lambda a: a.id, get_label=lambda a: a.database_name, ) schema = StringField( _("Schema"), - description=_("Specify a schema (if database flavor supports this)."), + description=_("Select a schema if the database supports this"), validators=[Optional()], widget=BS3TextFieldWidget(), ) - sep = StringField( + delimiter = SelectField( _("Delimiter"), - description=_("Delimiter used by CSV file (for whitespace use \\s+)."), + description=_("Enter a delimiter for this data"), + choices=[ + (",", _(",")), + (".", _(".")), + ("other", _("Other")), + ], validators=[DataRequired()], - widget=BS3TextFieldWidget(), + default=[","], + ) + otherInput = StringField( + _("Other"), ) if_exists = SelectField( - _("Table Exists"), - description=_( - "If table exists do one of the following: " - "Fail (do nothing), Replace (drop and recreate table) " - "or Append (insert data)." - ), + _("If Table Already Exists"), + description=_("What should happen if the table already exists"), choices=[ ("fail", _("Fail")), ("replace", _("Replace")), @@ -151,97 +170,98 @@ class CsvToDatabaseForm(UploadToDatabaseForm): ], validators=[DataRequired()], ) - header = IntegerField( - _("Header Row"), - description=_( - "Row containing the headers to use as " - "column names (0 is first line of data). " - "Leave empty if there is no header row." - ), - validators=[Optional(), NumberRange(min=0)], - widget=BS3TextFieldWidget(), - ) - index_col = IntegerField( - _("Index Column"), - description=_( - "Column to use as the row labels of the " - "dataframe. Leave empty if no index column." - ), - validators=[Optional(), NumberRange(min=0)], - widget=BS3TextFieldWidget(), - ) - mangle_dupe_cols = BooleanField( - _("Mangle Duplicate Columns"), - description=_('Specify duplicate columns as "X.0, X.1".'), - ) - usecols = JsonListField( - _("Use Columns"), - default=None, - description=_( - "Json list of the column names that should be read. " - "If not None, only these columns will be read from the file." - ), - validators=[Optional()], - ) - skipinitialspace = BooleanField( - _("Skip Initial Space"), description=_("Skip spaces after delimiter.") - ) - skiprows = IntegerField( - _("Skip Rows"), - description=_("Number of rows to skip at start of file."), - validators=[Optional(), NumberRange(min=0)], - widget=BS3TextFieldWidget(), - ) - nrows = IntegerField( - _("Rows to Read"), - description=_("Number of rows of file to read."), - validators=[Optional(), NumberRange(min=0)], - widget=BS3TextFieldWidget(), + skip_initial_space = BooleanField( + _("Skip Initial Space"), description=_("Skip spaces after delimiter") ) skip_blank_lines = BooleanField( _("Skip Blank Lines"), - description=_("Skip blank lines rather than interpreting them as NaN values."), + description=_( + "Skip blank lines rather than interpreting them as Not A Number values" + ), ) parse_dates = CommaSeparatedListField( - _("Parse Dates"), + _("Columns To Be Parsed as Dates"), description=_( - "A comma separated list of columns that should be parsed as dates." + "A comma separated list of columns that should be parsed as dates" ), filters=[filter_not_empty_values], ) infer_datetime_format = BooleanField( - _("Infer Datetime Format"), - description=_("Use Pandas to interpret the datetime format automatically."), + _("Interpret Datetime Format Automatically"), + description=_("Interpret the datetime format automatically"), ) decimal = StringField( _("Decimal Character"), default=".", - description=_("Character to interpret as decimal point."), + description=_("Character to interpret as decimal point"), validators=[Optional(), Length(min=1, max=1)], widget=BS3TextFieldWidget(), ) - index = BooleanField( - _("Dataframe Index"), description=_("Write dataframe index as a column.") + null_values = JsonListField( + _("Null Values"), + default=config["CSV_DEFAULT_NA_NAMES"], + description=_( + "Json list of the values that should be treated as null. " + 'Examples: [""] for empty strings, ["None", "N/A"], ["nan", "null"]. ' + "Warning: Hive database supports only a single value" + ), + ) + index_col = IntegerField( + _("Index Column"), + description=_( + "Column to use as the row labels of the " + "dataframe. Leave empty if no index column" + ), + validators=[Optional(), NumberRange(min=0)], + widget=BS3TextFieldWidget(), + ) + dataframe_index = BooleanField( + _("Dataframe Index"), description=_("Write dataframe index as a column") ) index_label = StringField( _("Column Label(s)"), description=_( "Column label for index column(s). If None is given " - "and Dataframe Index is True, Index Names are used." + "and Dataframe Index is checked, Index Names are used" ), validators=[Optional()], widget=BS3TextFieldWidget(), ) - null_values = JsonListField( - _("Null values"), - default=config["CSV_DEFAULT_NA_NAMES"], + use_cols = JsonListField( + _("Columns To Read"), + default=None, + description=_("Json list of the column names that should be read"), + validators=[Optional()], + ) + overwrite_duplicate = BooleanField( + _("Overwrite Duplicate Columns"), description=_( - "Json list of the values that should be treated as null. " - 'Examples: [""], ["None", "N/A"], ["nan", "null"]. ' - "Warning: Hive database supports only single value. " - 'Use [""] for empty string.' + "If duplicate columns are not overridden, " + 'they will be presented as "X.1, X.2 ...X.x"' ), ) + header = IntegerField( + _("Header Row"), + description=_( + "Row containing the headers to use as " + "column names (0 is first line of data). " + "Leave empty if there is no header row" + ), + validators=[Optional(), NumberRange(min=0)], + widget=BS3TextFieldWidget(), + ) + nrows = IntegerField( + _("Rows to Read"), + description=_("Number of rows of file to read"), + validators=[Optional(), NumberRange(min=0)], + widget=BS3TextFieldWidget(), + ) + skiprows = IntegerField( + _("Skip Rows"), + description=_("Number of rows to skip at start of file"), + validators=[Optional(), NumberRange(min=0)], + widget=BS3TextFieldWidget(), + ) class ExcelToDatabaseForm(UploadToDatabaseForm): @@ -281,7 +301,7 @@ class ExcelToDatabaseForm(UploadToDatabaseForm): widget=BS3TextFieldWidget(), ) - con = QuerySelectField( + database = QuerySelectField( _("Database"), query_factory=UploadToDatabaseForm.file_allowed_dbs, get_pk=lambda a: a.id, @@ -412,7 +432,7 @@ class ColumnarToDatabaseForm(UploadToDatabaseForm): ], ) - con = QuerySelectField( + database = QuerySelectField( _("Database"), query_factory=UploadToDatabaseForm.file_allowed_dbs, get_pk=lambda a: a.id, diff --git a/superset/views/database/mixins.py b/superset/views/database/mixins.py index f6f7f1115e201..efd0b6c6eb25e 100644 --- a/superset/views/database/mixins.py +++ b/superset/views/database/mixins.py @@ -63,7 +63,6 @@ class DatabaseMixin: "allow_dml", "force_ctas_schema", "impersonate_user", - "allow_multi_schema_metadata_fetch", "extra", "encrypted_extra", "server_cert", @@ -103,7 +102,7 @@ class DatabaseMixin: ), "expose_in_sqllab": _("Expose this DB in SQL Lab"), "allow_run_async": _( - "Operate the database in asynchronous mode, meaning " + "Operate the database in asynchronous mode, meaning " "that the queries are executed on remote workers as opposed " "to on the web server itself. " "This assumes that you have a Celery worker setup as well " @@ -170,11 +169,6 @@ class DatabaseMixin: "service account, but impersonate the currently logged on user " "via hive.server2.proxy.user property." ), - "allow_multi_schema_metadata_fetch": _( - "Allow SQL Lab to fetch a list of all tables and all views across " - "all database schemas. For large data warehouse with thousands of " - "tables, this can be expensive and put strain on the system." - ), "cache_timeout": _( "Duration (in seconds) of the caching timeout for charts of this database. " "A timeout of 0 indicates that the cache never expires. " @@ -203,7 +197,6 @@ class DatabaseMixin: "impersonate_user": _("Impersonate the logged on user"), "allow_file_upload": _("Allow Csv Upload"), "modified": _("Modified"), - "allow_multi_schema_metadata_fetch": _("Allow Multi Schema Metadata Fetch"), "backend": _("Backend"), } diff --git a/superset/views/database/views.py b/superset/views/database/views.py index e95f668353e73..62f7d45d3ab62 100644 --- a/superset/views/database/views.py +++ b/superset/views/database/views.py @@ -18,7 +18,7 @@ import os import tempfile import zipfile -from typing import TYPE_CHECKING +from typing import Any, TYPE_CHECKING import pandas as pd from flask import flash, g, redirect @@ -109,25 +109,71 @@ def list(self) -> FlaskResponse: return super().render_app_template() -class CsvToDatabaseView(SimpleFormView): +class CustomFormView(SimpleFormView): + """ + View for presenting your own forms + Inherit from this view to provide some base + processing for your customized form views. + + Notice that this class inherits from BaseView + so all properties from the parent class can be overridden also. + + Implement form_get and form_post to implement + your form pre-processing and post-processing + """ + + @expose("/form", methods=["GET"]) + @has_access + def this_form_get(self) -> Any: + self._init_vars() + form = self.form.refresh() + self.form_get(form) + self.update_redirect() + return self.render_template( + self.form_template, + title=self.form_title, + form=form, + appbuilder=self.appbuilder, + ) + + @expose("/form", methods=["POST"]) + @has_access + def this_form_post(self) -> Any: + self._init_vars() + form = self.form.refresh() + if form.validate_on_submit(): + response = self.form_post(form) # pylint: disable=assignment-from-no-return + if not response: + return redirect(self.get_redirect()) + return response + return self.render_template( + self.form_template, + title=self.form_title, + form=form, + appbuilder=self.appbuilder, + ) + + +class CsvToDatabaseView(CustomFormView): form = CsvToDatabaseForm form_template = "superset/form_view/csv_to_database_view/edit.html" form_title = _("CSV to Database configuration") add_columns = ["database", "schema", "table_name"] def form_get(self, form: CsvToDatabaseForm) -> None: - form.sep.data = "," + form.delimiter.data = "," form.header.data = 0 - form.mangle_dupe_cols.data = True - form.skipinitialspace.data = False + form.overwrite_duplicate.data = True + form.skip_initial_space.data = False form.skip_blank_lines.data = True form.infer_datetime_format.data = True form.decimal.data = "." form.if_exists.data = "fail" def form_post(self, form: CsvToDatabaseForm) -> Response: - database = form.con.data - csv_table = Table(table=form.name.data, schema=form.schema.data) + database = form.database.data + csv_table = Table(table=form.table_name.data, schema=form.schema.data) + delimiter_input = form.delimiter.data if not schema_allows_file_upload(database, csv_table.schema): message = __( @@ -139,6 +185,9 @@ def form_post(self, form: CsvToDatabaseForm) -> Response: flash(message, "danger") return redirect("/csvtodatabaseview/form") + if form.delimiter.data == "other": + delimiter_input = form.otherInput.data + try: df = pd.concat( pd.read_csv( @@ -150,21 +199,21 @@ def form_post(self, form: CsvToDatabaseForm) -> Response: infer_datetime_format=form.infer_datetime_format.data, iterator=True, keep_default_na=not form.null_values.data, - mangle_dupe_cols=form.mangle_dupe_cols.data, - usecols=form.usecols.data if form.usecols.data else None, + mangle_dupe_cols=form.overwrite_duplicate.data, + usecols=form.use_cols.data if form.use_cols.data else None, na_values=form.null_values.data if form.null_values.data else None, nrows=form.nrows.data, parse_dates=form.parse_dates.data, - sep=form.sep.data, + sep=delimiter_input, skip_blank_lines=form.skip_blank_lines.data, - skipinitialspace=form.skipinitialspace.data, + skipinitialspace=form.skip_initial_space.data, skiprows=form.skiprows.data, ) ) database = ( db.session.query(models.Database) - .filter_by(id=form.data.get("con").data.get("id")) + .filter_by(id=form.data.get("database").data.get("id")) .one() ) @@ -175,7 +224,7 @@ def form_post(self, form: CsvToDatabaseForm) -> Response: to_sql_kwargs={ "chunksize": 1000, "if_exists": form.if_exists.data, - "index": form.index.data, + "index": form.dataframe_index.data, "index_label": form.index_label.data, }, ) @@ -221,7 +270,7 @@ def form_post(self, form: CsvToDatabaseForm) -> Response: '"%(table_name)s" in database "%(db_name)s". ' "Error message: %(error_msg)s", filename=form.csv_file.data.filename, - table_name=form.name.data, + table_name=form.table_name.data, db_name=database.database_name, error_msg=str(ex), ) @@ -241,9 +290,9 @@ def form_post(self, form: CsvToDatabaseForm) -> Response: flash(message, "info") event_logger.log_with_context( action="successful_csv_upload", - database=form.con.data.name, + database=form.database.data.name, schema=form.schema.data, - table=form.name.data, + table=form.table_name.data, ) return redirect("/tablemodelview/list/") @@ -262,7 +311,7 @@ def form_get(self, form: ExcelToDatabaseForm) -> None: form.sheet_name.data = "" def form_post(self, form: ExcelToDatabaseForm) -> Response: - database = form.con.data + database = form.database.data excel_table = Table(table=form.name.data, schema=form.schema.data) if not schema_allows_file_upload(database, excel_table.schema): @@ -301,7 +350,7 @@ def form_post(self, form: ExcelToDatabaseForm) -> Response: database = ( db.session.query(models.Database) - .filter_by(id=form.data.get("con").data.get("id")) + .filter_by(id=form.data.get("database").data.get("id")) .one() ) @@ -378,7 +427,7 @@ def form_post(self, form: ExcelToDatabaseForm) -> Response: flash(message, "info") event_logger.log_with_context( action="successful_excel_upload", - database=form.con.data.name, + database=form.database.data.name, schema=form.schema.data, table=form.name.data, ) @@ -397,7 +446,7 @@ def form_get(self, form: ColumnarToDatabaseForm) -> None: def form_post( # pylint: disable=too-many-locals self, form: ColumnarToDatabaseForm ) -> Response: - database = form.con.data + database = form.database.data columnar_table = Table(table=form.name.data, schema=form.schema.data) files = form.columnar_file.data file_type = {file.filename.split(".")[-1] for file in files} @@ -442,7 +491,7 @@ def form_post( # pylint: disable=too-many-locals database = ( db.session.query(models.Database) - .filter_by(id=form.data.get("con").data.get("id")) + .filter_by(id=form.data.get("database").data.get("id")) .one() ) @@ -519,7 +568,7 @@ def form_post( # pylint: disable=too-many-locals flash(message, "info") event_logger.log_with_context( action="successful_columnar_upload", - database=form.con.data.name, + database=form.database.data.name, schema=form.schema.data, table=form.name.data, ) diff --git a/superset/views/datasource/schemas.py b/superset/views/datasource/schemas.py index 64b2b854bb148..f9be7a7d4e1f7 100644 --- a/superset/views/datasource/schemas.py +++ b/superset/views/datasource/schemas.py @@ -14,11 +14,15 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from typing import Any +from typing import Any, Dict -from marshmallow import fields, post_load, Schema +from marshmallow import fields, post_load, pre_load, Schema, validate from typing_extensions import TypedDict +from superset import app +from superset.charts.schemas import ChartDataExtrasSchema, ChartDataFilterSchema +from superset.utils.core import DatasourceType + class ExternalMetadataParams(TypedDict): datasource_type: str @@ -54,3 +58,38 @@ def normalize( schema_name=data.get("schema_name", ""), table_name=data["table_name"], ) + + +class SamplesPayloadSchema(Schema): + filters = fields.List(fields.Nested(ChartDataFilterSchema), required=False) + granularity = fields.String( + allow_none=True, + ) + time_range = fields.String( + allow_none=True, + ) + extras = fields.Nested( + ChartDataExtrasSchema, + description="Extra parameters to add to the query.", + allow_none=True, + ) + + @pre_load + # pylint: disable=no-self-use, unused-argument + def handle_none(self, data: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: + if data is None: + return {} + return data + + +class SamplesRequestSchema(Schema): + datasource_type = fields.String( + validate=validate.OneOf([e.value for e in DatasourceType]), required=True + ) + datasource_id = fields.Integer(required=True) + force = fields.Boolean(load_default=False) + page = fields.Integer(load_default=1) + per_page = fields.Integer( + validate=validate.Range(min=1, max=app.config.get("SAMPLES_ROW_LIMIT", 1000)), + load_default=app.config.get("SAMPLES_ROW_LIMIT", 1000), + ) diff --git a/superset/views/datasource/utils.py b/superset/views/datasource/utils.py new file mode 100644 index 0000000000000..42cddf416794d --- /dev/null +++ b/superset/views/datasource/utils.py @@ -0,0 +1,128 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from typing import Any, Dict, Optional + +from superset import app, db +from superset.common.chart_data import ChartDataResultType +from superset.common.query_context_factory import QueryContextFactory +from superset.common.utils.query_cache_manager import QueryCacheManager +from superset.constants import CacheRegion +from superset.datasets.commands.exceptions import DatasetSamplesFailedError +from superset.datasource.dao import DatasourceDAO +from superset.utils.core import QueryStatus +from superset.views.datasource.schemas import SamplesPayloadSchema + + +def get_limit_clause(page: Optional[int], per_page: Optional[int]) -> Dict[str, int]: + samples_row_limit = app.config.get("SAMPLES_ROW_LIMIT", 1000) + limit = samples_row_limit + offset = 0 + + if isinstance(page, int) and isinstance(per_page, int): + limit = int(per_page) + if limit < 0 or limit > samples_row_limit: + # reset limit value if input is invalid + limit = samples_row_limit + + offset = max((int(page) - 1) * limit, 0) + + return {"row_offset": offset, "row_limit": limit} + + +def get_samples( # pylint: disable=too-many-arguments,too-many-locals + datasource_type: str, + datasource_id: int, + force: bool = False, + page: int = 1, + per_page: int = 1000, + payload: Optional[SamplesPayloadSchema] = None, +) -> Dict[str, Any]: + datasource = DatasourceDAO.get_datasource( + session=db.session, + datasource_type=datasource_type, + datasource_id=datasource_id, + ) + + limit_clause = get_limit_clause(page, per_page) + + # todo(yongjie): Constructing count(*) and samples in the same query_context, + if payload is None: + # constructing samples query + samples_instance = QueryContextFactory().create( + datasource={ + "type": datasource.type, + "id": datasource.id, + }, + queries=[limit_clause], + result_type=ChartDataResultType.SAMPLES, + force=force, + ) + else: + # constructing drill detail query + # When query_type == 'samples' the `time filter` will be removed, + # so it is not applicable drill detail query + samples_instance = QueryContextFactory().create( + datasource={ + "type": datasource.type, + "id": datasource.id, + }, + queries=[{**payload, **limit_clause}], + result_type=ChartDataResultType.DRILL_DETAIL, + force=force, + ) + + # constructing count(*) query + count_star_metric = { + "metrics": [ + { + "expressionType": "SQL", + "sqlExpression": "COUNT(*)", + "label": "COUNT(*)", + } + ] + } + count_star_instance = QueryContextFactory().create( + datasource={ + "type": datasource.type, + "id": datasource.id, + }, + queries=[{**payload, **count_star_metric} if payload else count_star_metric], + result_type=ChartDataResultType.FULL, + force=force, + ) + samples_results = samples_instance.get_payload() + count_star_results = count_star_instance.get_payload() + + try: + sample_data = samples_results["queries"][0] + count_star_data = count_star_results["queries"][0] + failed_status = ( + sample_data.get("status") == QueryStatus.FAILED + or count_star_data.get("status") == QueryStatus.FAILED + ) + error_msg = sample_data.get("error") or count_star_data.get("error") + if failed_status and error_msg: + cache_key = sample_data.get("cache_key") + QueryCacheManager.delete(cache_key, region=CacheRegion.DATA) + raise DatasetSamplesFailedError(error_msg) + + sample_data["page"] = page + sample_data["per_page"] = per_page + sample_data["total_count"] = count_star_data["data"][0]["COUNT(*)"] + return sample_data + except (IndexError, KeyError) as exc: + raise DatasetSamplesFailedError from exc diff --git a/superset/views/datasource/views.py b/superset/views/datasource/views.py index e942296df757f..4f158e836936a 100644 --- a/superset/views/datasource/views.py +++ b/superset/views/datasource/views.py @@ -18,25 +18,25 @@ from collections import Counter from typing import Any -from flask import current_app, g, request -from flask_appbuilder import expose +from flask import current_app, redirect, request +from flask_appbuilder import expose, permission_name from flask_appbuilder.api import rison -from flask_appbuilder.security.decorators import has_access_api +from flask_appbuilder.security.decorators import has_access, has_access_api from flask_babel import _ from marshmallow import ValidationError from sqlalchemy.exc import NoSuchTableError from sqlalchemy.orm.exc import NoResultFound -from superset import db, event_logger +from superset import db, event_logger, security_manager from superset.commands.utils import populate_owners -from superset.connectors.connector_registry import ConnectorRegistry +from superset.connectors.sqla.models import SqlaTable from superset.connectors.sqla.utils import get_physical_table_metadata from superset.datasets.commands.exceptions import ( DatasetForbiddenError, DatasetNotFoundError, ) +from superset.datasource.dao import DatasourceDAO from superset.exceptions import SupersetException, SupersetSecurityException -from superset.extensions import security_manager from superset.models.core import Database from superset.superset_typing import FlaskResponse from superset.utils.core import DatasourceType @@ -44,7 +44,6 @@ from superset.views.base import ( api, BaseSupersetView, - check_ownership, handle_api_exception, json_error_response, ) @@ -52,7 +51,10 @@ ExternalMetadataParams, ExternalMetadataSchema, get_external_metadata_schema, + SamplesPayloadSchema, + SamplesRequestSchema, ) +from superset.views.datasource.utils import get_samples from superset.views.utils import sanitize_datasource_data @@ -90,21 +92,20 @@ def save(self) -> FlaskResponse: status=400, ) - orm_datasource = ConnectorRegistry.get_datasource( - DatasourceType(datasource_type), datasource_id, db.session + orm_datasource = DatasourceDAO.get_datasource( + db.session, DatasourceType(datasource_type), datasource_id ) orm_datasource.database_id = database_id if "owners" in datasource_dict and orm_datasource.owner_class is not None: # Check ownership try: - check_ownership(orm_datasource) + security_manager.raise_for_ownership(orm_datasource) except SupersetSecurityException as ex: raise DatasetForbiddenError() from ex - user = security_manager.get_user_by_id(g.user.id) datasource_dict["owners"] = populate_owners( - user, datasource_dict["owners"], default_to_user=False + datasource_dict["owners"], default_to_user=False ) duplicates = [ @@ -133,8 +134,8 @@ def save(self) -> FlaskResponse: @api @handle_api_exception def get(self, datasource_type: str, datasource_id: int) -> FlaskResponse: - datasource = ConnectorRegistry.get_datasource( - datasource_type, datasource_id, db.session + datasource = DatasourceDAO.get_datasource( + db.session, DatasourceType(datasource_type), datasource_id ) return self.json_response(sanitize_datasource_data(datasource.data)) @@ -146,8 +147,10 @@ def external_metadata( self, datasource_type: str, datasource_id: int ) -> FlaskResponse: """Gets column info from the source system""" - datasource = ConnectorRegistry.get_datasource( - datasource_type, datasource_id, db.session + datasource = DatasourceDAO.get_datasource( + db.session, + DatasourceType(datasource_type), + datasource_id, ) try: external_metadata = datasource.external_metadata() @@ -169,9 +172,8 @@ def external_metadata_by_name(self, **kwargs: Any) -> FlaskResponse: except ValidationError as err: return json_error_response(str(err), status=400) - datasource = ConnectorRegistry.get_datasource_by_name( + datasource = SqlaTable.get_datasource_by_name( session=db.session, - datasource_type=params["datasource_type"], database_name=params["database_name"], schema=params["schema_name"], datasource_name=params["table_name"], @@ -195,3 +197,45 @@ def external_metadata_by_name(self, **kwargs: Any) -> FlaskResponse: except (NoResultFound, NoSuchTableError) as ex: raise DatasetNotFoundError() from ex return self.json_response(external_metadata) + + @expose("/samples", methods=["POST"]) + @has_access_api + @api + @handle_api_exception + def samples(self) -> FlaskResponse: + try: + params = SamplesRequestSchema().load(request.args) + payload = SamplesPayloadSchema().load(request.json) + except ValidationError as err: + return json_error_response(err.messages, status=400) + + rv = get_samples( + datasource_type=params["datasource_type"], + datasource_id=params["datasource_id"], + force=params["force"], + page=params["page"], + per_page=params["per_page"], + payload=payload, + ) + return self.json_response({"result": rv}) + + +class DatasetEditor(BaseSupersetView): + route_base = "/dataset" + class_permission_name = "Dataset" + + @expose("/add/") + @has_access + @permission_name("read") + def root(self) -> FlaskResponse: + return super().render_app_template() + + @expose("/<pk>", methods=["GET"]) + @has_access + @permission_name("read") + # pylint: disable=unused-argument + def show(self, pk: int) -> FlaskResponse: + dev = request.args.get("testing") + if dev is not None: + return super().render_app_template() + return redirect("/") diff --git a/superset/views/explore.py b/superset/views/explore.py new file mode 100644 index 0000000000000..8becaaba70354 --- /dev/null +++ b/superset/views/explore.py @@ -0,0 +1,49 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from flask_appbuilder import permission_name +from flask_appbuilder.api import expose +from flask_appbuilder.security.decorators import has_access + +from superset import event_logger +from superset.superset_typing import FlaskResponse + +from .base import BaseSupersetView + + +class ExploreView(BaseSupersetView): + route_base = "/explore" + class_permission_name = "Explore" + + @expose("/") + @has_access + @permission_name("read") + @event_logger.log_this + def root(self) -> FlaskResponse: + return super().render_app_template() + + +class ExplorePermalinkView(BaseSupersetView): + route_base = "/superset" + class_permission_name = "Explore" + + @expose("/explore/p/<key>/") + @has_access + @permission_name("read") + @event_logger.log_this + # pylint: disable=unused-argument + def permalink(self, key: str) -> FlaskResponse: + return super().render_app_template() diff --git a/superset/views/filters.py b/superset/views/filters.py index 3a503e66b614a..625566b98828a 100644 --- a/superset/views/filters.py +++ b/superset/views/filters.py @@ -14,15 +14,19 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +import logging from typing import Any, cast, Optional +from flask import current_app from flask_appbuilder.models.filters import BaseFilter from flask_babel import lazy_gettext -from sqlalchemy import or_ +from sqlalchemy import and_, or_ from sqlalchemy.orm import Query from superset import security_manager +logger = logging.getLogger(__name__) + class FilterRelatedOwners(BaseFilter): # pylint: disable=too-few-public-methods @@ -48,3 +52,55 @@ def apply(self, query: Query, value: Optional[Any]) -> Query: user_model.username.ilike(like_value), ) ) + + +class BaseFilterRelatedUsers(BaseFilter): # pylint: disable=too-few-public-methods + + """ + Filter to apply on related users. Will exclude users in EXCLUDE_USERS_FROM_LISTS + + Use in the api by adding something like: + ``` + base_related_field_filters = { + "owners": [["id", BaseFilterRelatedUsers, lambda: []]], + "created_by": [["id", BaseFilterRelatedUsers, lambda: []]], + } + ``` + """ + + name = lazy_gettext("username") + arg_name = "username" + + def apply(self, query: Query, value: Optional[Any]) -> Query: + if extra_filters := current_app.config["EXTRA_RELATED_QUERY_FILTERS"].get( + "user", + ): + query = extra_filters(query) + + exclude_users = ( + security_manager.get_exclude_users_from_lists() + if current_app.config["EXCLUDE_USERS_FROM_LISTS"] is None + else current_app.config["EXCLUDE_USERS_FROM_LISTS"] + ) + if exclude_users: + user_model = security_manager.user_model + return query.filter(and_(user_model.username.not_in(exclude_users))) + + return query + + +class BaseFilterRelatedRoles(BaseFilter): # pylint: disable=too-few-public-methods + """ + Filter to apply on related roles. + """ + + name = lazy_gettext("role") + arg_name = "role" + + def apply(self, query: Query, value: Optional[Any]) -> Query: + if extra_filters := current_app.config["EXTRA_RELATED_QUERY_FILTERS"].get( + "role", + ): + return extra_filters(query) + + return query diff --git a/superset/views/health.py b/superset/views/health.py index cf85b8927899d..8b082ff88ffec 100644 --- a/superset/views/health.py +++ b/superset/views/health.py @@ -15,22 +15,15 @@ # specific language governing permissions and limitations # under the License. from superset import app, talisman +from superset.stats_logger import BaseStatsLogger from superset.superset_typing import FlaskResponse -@talisman(force_https=False) -@app.route("/ping") -def ping() -> FlaskResponse: - return "OK" - - -@talisman(force_https=False) -@app.route("/healthcheck") -def healthcheck() -> FlaskResponse: - return "OK" - - @talisman(force_https=False) @app.route("/health") +@app.route("/healthcheck") +@app.route("/ping") def health() -> FlaskResponse: + stats_logger: BaseStatsLogger = app.config["STATS_LOGGER"] + stats_logger.incr("health") return "OK" diff --git a/superset/views/log/api.py b/superset/views/log/api.py index a92626df49cb3..5c73dba4a73ef 100644 --- a/superset/views/log/api.py +++ b/superset/views/log/api.py @@ -14,12 +14,24 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from typing import Any, Optional + from flask import current_app as app +from flask_appbuilder.api import expose, protect, rison, safe from flask_appbuilder.hooks import before_request from flask_appbuilder.models.sqla.interface import SQLAInterface import superset.models.core as models -from superset.views.base_api import BaseSupersetModelRestApi +from superset import event_logger, security_manager +from superset.exceptions import SupersetSecurityException +from superset.superset_typing import FlaskResponse +from superset.views.base_api import BaseSupersetModelRestApi, statsd_metrics +from superset.views.log.dao import LogDAO +from superset.views.log.schemas import ( + get_recent_activity_schema, + RecentActivityResponseSchema, + RecentActivitySchema, +) from ...constants import MODEL_API_RW_METHOD_PERMISSION_MAP from . import LogMixin @@ -27,7 +39,7 @@ class LogRestApi(LogMixin, BaseSupersetModelRestApi): datamodel = SQLAInterface(models.Log) - include_route_methods = {"get_list", "get", "post"} + include_route_methods = {"get_list", "get", "post", "recent_activity"} class_permission_name = "Log" method_permission_name = MODEL_API_RW_METHOD_PERMISSION_MAP resource_name = "log" @@ -44,13 +56,86 @@ class LogRestApi(LogMixin, BaseSupersetModelRestApi): "referrer", ] show_columns = list_columns + page_size = 20 + apispec_parameter_schemas = { + "get_recent_activity_schema": get_recent_activity_schema, + } + openapi_spec_component_schemas = ( + RecentActivityResponseSchema, + RecentActivitySchema, + ) @staticmethod def is_enabled() -> bool: return app.config["FAB_ADD_SECURITY_VIEWS"] and app.config["SUPERSET_LOG_VIEW"] - @before_request + @before_request(only=["get_list", "get", "post"]) def ensure_enabled(self) -> None: if not self.is_enabled(): return self.response_404() return None + + def get_user_activity_access_error(self, user_id: int) -> Optional[FlaskResponse]: + try: + security_manager.raise_for_user_activity_access(user_id) + except SupersetSecurityException as ex: + return self.response(403, message=ex.message) + return None + + @expose("/recent_activity/<int:user_id>/", methods=["GET"]) + @protect() + @safe + @statsd_metrics + @rison(get_recent_activity_schema) + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" + f".recent_activity", + log_to_statsd=False, + ) + def recent_activity(self, user_id: int, **kwargs: Any) -> FlaskResponse: + """Get recent activity data for a user + --- + get: + summary: Get recent activity data for a user + parameters: + - in: path + schema: + type: integer + name: user_id + description: The id of the user + - in: query + name: q + content: + application/json: + schema: + $ref: '#/components/schemas/get_recent_activity_schema' + responses: + 200: + description: A List of recent activity objects + content: + application/json: + schema: + $ref: "#/components/schemas/RecentActivityResponseSchema" + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 403: + $ref: '#/components/responses/403' + 500: + $ref: '#/components/responses/500' + """ + error_obj = self.get_user_activity_access_error(user_id) + if error_obj: + return error_obj + + args = kwargs["rison"] + page, page_size = self._sanitize_page_args(*self._handle_page_args(args)) + actions = args.get("actions", ["explore", "dashboard"]) + distinct = args.get("distinct", True) + + payload = LogDAO.get_recent_activity( + user_id, actions, distinct, page, page_size + ) + + return self.response(200, result=payload) diff --git a/superset/views/log/dao.py b/superset/views/log/dao.py new file mode 100644 index 0000000000000..71d8a62348641 --- /dev/null +++ b/superset/views/log/dao.py @@ -0,0 +1,131 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from datetime import datetime, timedelta +from typing import Any, Dict, List + +import humanize +from sqlalchemy import and_, or_ +from sqlalchemy.sql import functions as func + +from superset import db +from superset.dao.base import BaseDAO +from superset.models.core import Log +from superset.models.dashboard import Dashboard +from superset.models.slice import Slice +from superset.utils.dates import datetime_to_epoch + + +class LogDAO(BaseDAO): + model_cls = Log + + @staticmethod + def get_recent_activity( + user_id: int, actions: List[str], distinct: bool, page: int, page_size: int + ) -> List[Dict[str, Any]]: + has_subject_title = or_( + and_( + Dashboard.dashboard_title is not None, + Dashboard.dashboard_title != "", + ), + and_(Slice.slice_name is not None, Slice.slice_name != ""), + ) + + if distinct: + one_year_ago = datetime.today() - timedelta(days=365) + subqry = ( + db.session.query( + Log.dashboard_id, + Log.slice_id, + Log.action, + func.max(Log.dttm).label("dttm"), + ) + .group_by(Log.dashboard_id, Log.slice_id, Log.action) + .filter( + and_( + Log.action.in_(actions), + Log.user_id == user_id, + # limit to one year of data to improve performance + Log.dttm > one_year_ago, + or_(Log.dashboard_id.isnot(None), Log.slice_id.isnot(None)), + ) + ) + .subquery() + ) + qry = ( + db.session.query( + subqry, + Dashboard.slug.label("dashboard_slug"), + Dashboard.dashboard_title, + Slice.slice_name, + ) + .outerjoin(Dashboard, Dashboard.id == subqry.c.dashboard_id) + .outerjoin( + Slice, + Slice.id == subqry.c.slice_id, + ) + .filter(has_subject_title) + .order_by(subqry.c.dttm.desc()) + .limit(page_size) + .offset(page * page_size) + ) + else: + qry = ( + db.session.query( + Log.dttm, + Log.action, + Log.dashboard_id, + Log.slice_id, + Dashboard.slug.label("dashboard_slug"), + Dashboard.dashboard_title, + Slice.slice_name, + ) + .outerjoin(Dashboard, Dashboard.id == Log.dashboard_id) + .outerjoin(Slice, Slice.id == Log.slice_id) + .filter(has_subject_title) + .filter(Log.action.in_(actions), Log.user_id == user_id) + .order_by(Log.dttm.desc()) + .limit(page_size) + .offset(page * page_size) + ) + + payload = [] + for log in qry.all(): + item_url = None + item_title = None + item_type = None + if log.dashboard_id: + item_type = "dashboard" + item_url = Dashboard.get_url(log.dashboard_id, log.dashboard_slug) + item_title = log.dashboard_title + elif log.slice_id: + item_type = "slice" + item_url = Slice.build_explore_url(log.slice_id) + item_title = log.slice_name or "<empty>" + + payload.append( + { + "action": log.action, + "item_type": item_type, + "item_url": item_url, + "item_title": item_title, + "time": datetime_to_epoch(log.dttm), + "time_delta_humanized": humanize.naturaltime( + datetime.utcnow() - log.dttm + ), + } + ) + return payload diff --git a/superset/views/log/schemas.py b/superset/views/log/schemas.py new file mode 100644 index 0000000000000..bb4569893d741 --- /dev/null +++ b/superset/views/log/schemas.py @@ -0,0 +1,45 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from marshmallow import fields, Schema + +get_recent_activity_schema = { + "type": "object", + "properties": { + "page": {"type": "number"}, + "page_size": {"type": "number"}, + "actions": {"type": "array", "items": {"type": "string"}}, + "distinct": {"type": "boolean"}, + }, +} + + +class RecentActivitySchema(Schema): + action = fields.String(description="Action taken describing type of activity") + item_type = fields.String(description="Type of item, e.g. slice or dashboard") + item_url = fields.String(description="URL to item") + item_title = fields.String(description="Title of item") + time = fields.Float(description="Time of activity, in epoch milliseconds") + time_delta_humanized = fields.String( + description="Human-readable description of how long ago activity took place" + ) + + +class RecentActivityResponseSchema(Schema): + result = fields.List( + fields.Nested(RecentActivitySchema), + description="A list of recent activity objects", + ) diff --git a/superset/views/log/views.py b/superset/views/log/views.py index 6cc8d2ffd6a63..89623d8ec8c67 100644 --- a/superset/views/log/views.py +++ b/superset/views/log/views.py @@ -26,7 +26,10 @@ from . import LogMixin -class LogModelView(LogMixin, SupersetModelView): # pylint: disable=too-many-ancestors +class LogModelView( # pylint: disable=too-many-ancestors + LogMixin, + SupersetModelView, +): datamodel = SQLAInterface(models.Log) include_route_methods = {RouteMethod.LIST, RouteMethod.SHOW} class_permission_name = "Log" diff --git a/superset/views/redirects.py b/superset/views/redirects.py index 831fc978b9473..93a4339403109 100644 --- a/superset/views/redirects.py +++ b/superset/views/redirects.py @@ -34,25 +34,40 @@ class R(BaseSupersetView): # pylint: disable=invalid-name """used for short urls""" @staticmethod - def _validate_url(url: Optional[str] = None) -> bool: - if url and ( - url.startswith("//superset/dashboard/") - or url.startswith("//superset/explore/") - ): - return True - return False + def _validate_explore_url(url: str) -> Optional[str]: + if url.startswith("//superset/explore/p/"): + return url + + if url.startswith("//superset/explore"): + return "/" + url[10:] # Remove /superset from old Explore URLs + + if url.startswith("//explore"): + return url + + return None + + @staticmethod + def _validate_dashboard_url(url: str) -> Optional[str]: + if url.startswith("//superset/dashboard/"): + return url + + return None @event_logger.log_this @expose("/<int:url_id>") def index(self, url_id: int) -> FlaskResponse: url = db.session.query(models.Url).get(url_id) if url and url.url: - explore_url = "//superset/explore/?" - if url.url.startswith(explore_url): - explore_url += f"r={url_id}" + explore_url = self._validate_explore_url(url.url) + if explore_url: + if explore_url.startswith("//explore/?"): + explore_url = f"//explore/?r={url_id}" return redirect(explore_url[1:]) - if self._validate_url(url.url): - return redirect(url.url[1:]) + + dashboard_url = self._validate_dashboard_url(url.url) + if dashboard_url: + return redirect(dashboard_url[1:]) + return redirect("/") flash("URL to nowhere...", "danger") diff --git a/superset/views/sql_lab/__init__.py b/superset/views/sql_lab/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/superset/views/sql_lab/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/superset/views/sql_lab/schemas.py b/superset/views/sql_lab/schemas.py new file mode 100644 index 0000000000000..399665afc1bf2 --- /dev/null +++ b/superset/views/sql_lab/schemas.py @@ -0,0 +1,35 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from marshmallow import fields, Schema + + +class SqlJsonPayloadSchema(Schema): + database_id = fields.Integer(required=True) + sql = fields.String(required=True) + client_id = fields.String(allow_none=True) + queryLimit = fields.Integer(allow_none=True) + sql_editor_id = fields.String(allow_none=True) + schema = fields.String(allow_none=True) + tab = fields.String(allow_none=True) + ctas_method = fields.String(allow_none=True) + templateParams = fields.String(allow_none=True) + tmp_table_name = fields.String(allow_none=True) + select_as_cta = fields.Boolean(allow_none=True) + json = fields.Boolean(allow_none=True) + runAsync = fields.Boolean(allow_none=True) + expand_data = fields.Boolean(allow_none=True) diff --git a/superset/views/sql_lab.py b/superset/views/sql_lab/views.py similarity index 91% rename from superset/views/sql_lab.py rename to superset/views/sql_lab/views.py index a75225da9117f..99b57fe195bb5 100644 --- a/superset/views/sql_lab.py +++ b/superset/views/sql_lab/views.py @@ -29,15 +29,21 @@ from superset.models.sql_lab import Query, SavedQuery, TableSchema, TabState from superset.superset_typing import FlaskResponse from superset.utils import core as utils - -from .base import BaseSupersetView, DeleteMixin, json_success, SupersetModelView +from superset.utils.core import get_user_id +from superset.views.base import ( + BaseSupersetView, + DeleteMixin, + json_success, + SupersetModelView, +) logger = logging.getLogger(__name__) -class SavedQueryView( - SupersetModelView, DeleteMixin -): # pylint: disable=too-many-ancestors +class SavedQueryView( # pylint: disable=too-many-ancestors + SupersetModelView, + DeleteMixin, +): datamodel = SQLAInterface(SavedQuery) include_route_methods = RouteMethod.CRUD_SET @@ -136,8 +142,10 @@ class TabStateView(BaseSupersetView): def post(self) -> FlaskResponse: # pylint: disable=no-self-use query_editor = json.loads(request.form["queryEditor"]) tab_state = TabState( - user_id=g.user.get_id(), - label=query_editor.get("title", "Untitled Query"), + user_id=get_user_id(), + # This is for backward compatibility + label=query_editor.get("name") + or query_editor.get("title", _("Untitled Query")), active=True, database_id=query_editor["dbId"], schema=query_editor.get("schema"), @@ -147,7 +155,7 @@ def post(self) -> FlaskResponse: # pylint: disable=no-self-use ) ( db.session.query(TabState) - .filter_by(user_id=g.user.get_id()) + .filter_by(user_id=get_user_id()) .update({"active": False}) ) db.session.add(tab_state) @@ -157,7 +165,7 @@ def post(self) -> FlaskResponse: # pylint: disable=no-self-use @has_access_api @expose("/<int:tab_state_id>", methods=["DELETE"]) def delete(self, tab_state_id: int) -> FlaskResponse: # pylint: disable=no-self-use - if _get_owner_id(tab_state_id) != int(g.user.get_id()): + if _get_owner_id(tab_state_id) != get_user_id(): return Response(status=403) db.session.query(TabState).filter(TabState.id == tab_state_id).delete( @@ -172,7 +180,7 @@ def delete(self, tab_state_id: int) -> FlaskResponse: # pylint: disable=no-self @has_access_api @expose("/<int:tab_state_id>", methods=["GET"]) def get(self, tab_state_id: int) -> FlaskResponse: # pylint: disable=no-self-use - if _get_owner_id(tab_state_id) != int(g.user.get_id()): + if _get_owner_id(tab_state_id) != get_user_id(): return Response(status=403) tab_state = db.session.query(TabState).filter_by(id=tab_state_id).first() @@ -190,12 +198,12 @@ def activate( # pylint: disable=no-self-use owner_id = _get_owner_id(tab_state_id) if owner_id is None: return Response(status=404) - if owner_id != int(g.user.get_id()): + if owner_id != get_user_id(): return Response(status=403) ( db.session.query(TabState) - .filter_by(user_id=g.user.get_id()) + .filter_by(user_id=get_user_id()) .update({"active": TabState.id == tab_state_id}) ) db.session.commit() @@ -204,7 +212,7 @@ def activate( # pylint: disable=no-self-use @has_access_api @expose("<int:tab_state_id>", methods=["PUT"]) def put(self, tab_state_id: int) -> FlaskResponse: # pylint: disable=no-self-use - if _get_owner_id(tab_state_id) != int(g.user.get_id()): + if _get_owner_id(tab_state_id) != get_user_id(): return Response(status=403) fields = {k: json.loads(v) for k, v in request.form.to_dict().items()} @@ -217,7 +225,7 @@ def put(self, tab_state_id: int) -> FlaskResponse: # pylint: disable=no-self-us def migrate_query( # pylint: disable=no-self-use self, tab_state_id: int ) -> FlaskResponse: - if _get_owner_id(tab_state_id) != int(g.user.get_id()): + if _get_owner_id(tab_state_id) != get_user_id(): return Response(status=403) client_id = json.loads(request.form["queryId"]) @@ -244,7 +252,7 @@ def delete_query( # pylint: disable=no-self-use .filter( and_( Query.client_id != client_id, - Query.user_id == g.user.get_id(), + Query.user_id == get_user_id(), Query.sql_editor_id == str(tab_state_id), ), ) @@ -257,7 +265,7 @@ def delete_query( # pylint: disable=no-self-use db.session.query(Query).filter_by( client_id=client_id, - user_id=g.user.get_id(), + user_id=get_user_id(), sql_editor_id=str(tab_state_id), ).delete(synchronize_session=False) db.session.commit() @@ -327,4 +335,4 @@ def my_queries(self) -> FlaskResponse: # pylint: disable=no-self-use logger.warning( "This endpoint is deprecated and will be removed in the next major release" ) - return redirect("/savedqueryview/list/?_flt_0_user={}".format(g.user.get_id())) + return redirect(f"/savedqueryview/list/?_flt_0_user={get_user_id()}") diff --git a/superset/views/tags.py b/superset/views/tags.py index 8ab2798f5d84c..985d26179fe28 100644 --- a/superset/views/tags.py +++ b/superset/views/tags.py @@ -28,12 +28,13 @@ from werkzeug.exceptions import NotFound from superset import db, is_feature_enabled, utils +from superset.connectors.sqla.models import SqlaTable from superset.jinja_context import ExtraCache from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.models.sql_lab import SavedQuery -from superset.models.tags import ObjectTypes, Tag, TaggedObject, TagTypes from superset.superset_typing import FlaskResponse +from superset.tags.models import ObjectTypes, Tag, TaggedObject, TagTypes from .base import BaseSupersetView, json_success @@ -238,4 +239,31 @@ def tagged_objects(self) -> FlaskResponse: # pylint: disable=no-self-use for obj in saved_queries ) + # datasets + if not types or "dataset" in types: + datasets = ( + db.session.query(SqlaTable) + .join( + TaggedObject, + and_( + TaggedObject.object_id == SqlaTable.id, + TaggedObject.object_type == ObjectTypes.dataset, + ), + ) + .join(Tag, TaggedObject.tag_id == Tag.id) + .filter(Tag.name.in_(tags)) + ) + results.extend( + { + "id": obj.id, + "type": ObjectTypes.dataset.name, + "name": obj.table_name, + "url": obj.sql_url(), + "changed_on": obj.changed_on, + "created_by": obj.created_by_fk, + "creator": obj.creator(), + } + for obj in datasets + ) + return json_success(json.dumps(results, default=utils.core.json_int_dttm_ser)) diff --git a/superset/views/users/api.py b/superset/views/users/api.py index 29d376935a77e..675b918847c46 100644 --- a/superset/views/users/api.py +++ b/superset/views/users/api.py @@ -15,17 +15,17 @@ # specific language governing permissions and limitations # under the License. from flask import g, Response -from flask_appbuilder.api import BaseApi, expose, safe +from flask_appbuilder.api import expose, safe from flask_jwt_extended.exceptions import NoAuthorizationError +from superset.views.base_api import BaseSupersetApi +from superset.views.users.schemas import UserResponseSchema from superset.views.utils import bootstrap_user_data -from .schemas import UserResponseSchema - user_response_schema = UserResponseSchema() -class CurrentUserRestApi(BaseApi): +class CurrentUserRestApi(BaseSupersetApi): """An api to get information about the current user""" resource_name = "me" diff --git a/superset/views/utils.py b/superset/views/utils.py index 1f72324a9677c..835c8eda0d8d6 100644 --- a/superset/views/utils.py +++ b/superset/views/utils.py @@ -32,8 +32,7 @@ import superset.models.core as models from superset import app, dataframe, db, result_set, viz from superset.common.db_query_status import QueryStatus -from superset.connectors.connector_registry import ConnectorRegistry -from superset.connectors.sqla.models import SqlaTable +from superset.datasource.dao import DatasourceDAO from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import ( CacheLoadError, @@ -48,6 +47,7 @@ from superset.models.slice import Slice from superset.models.sql_lab import Query from superset.superset_typing import FormData +from superset.utils.core import DatasourceType from superset.utils.decorators import stats_timing from superset.viz import BaseViz @@ -103,23 +103,20 @@ def bootstrap_user_data(user: User, include_perms: bool = False) -> Dict[str, An def get_permissions( user: User, -) -> Tuple[Dict[str, List[List[str]]], DefaultDict[str, List[str]]]: +) -> Tuple[Dict[str, List[Tuple[str]]], DefaultDict[str, List[str]]]: if not user.roles: raise AttributeError("User object does not have roles") - roles = defaultdict(list) - permissions = defaultdict(set) - - for role in user.roles: - permissions_ = security_manager.get_role_permissions(role) - for permission in permissions_: + data_permissions = defaultdict(set) + roles_permissions = security_manager.get_user_roles_permissions(user) + for _, permissions in roles_permissions.items(): + for permission in permissions: if permission[0] in ("datasource_access", "database_access"): - permissions[permission[0]].add(permission[1]) - roles[role.name].append([permission[0], permission[1]]) + data_permissions[permission[0]].add(permission[1]) transformed_permissions = defaultdict(list) - for perm in permissions: - transformed_permissions[perm] = list(permissions[perm]) - return roles, transformed_permissions + for perm in data_permissions: + transformed_permissions[perm] = list(data_permissions[perm]) + return roles_permissions, transformed_permissions def get_viz( @@ -130,8 +127,10 @@ def get_viz( force_cached: bool = False, ) -> BaseViz: viz_type = form_data.get("viz_type", "table") - datasource = ConnectorRegistry.get_datasource( - datasource_type, datasource_id, db.session + datasource = DatasourceDAO.get_datasource( + db.session, + DatasourceType(datasource_type), + datasource_id, ) viz_obj = viz.viz_types[viz_type]( datasource, form_data=form_data, force=force, force_cached=force_cached @@ -424,11 +423,6 @@ def is_slice_in_container( return False -def is_owner(obj: Union[Dashboard, Slice, SqlaTable], user: User) -> bool: - """Check if user is owner of the slice""" - return obj and user in obj.owners - - def check_resource_permissions( check_perms: Callable[..., Any], ) -> Callable[..., Any]: diff --git a/superset/viz.py b/superset/viz.py index e83e0127775cb..1f4c795325b4b 100644 --- a/superset/viz.py +++ b/superset/viz.py @@ -80,6 +80,7 @@ from superset.utils.cache import set_and_log_cache from superset.utils.core import ( apply_max_row_limit, + DateColumn, DTTM_ALIAS, ExtraFiltersReasonType, get_column_name, @@ -301,9 +302,15 @@ def get_df(self, query_obj: Optional[QueryObjectDict] = None) -> pd.DataFrame: if not df.empty: utils.normalize_dttm_col( df=df, - timestamp_format=timestamp_format, - offset=self.datasource.offset, - time_shift=self.time_shift, + dttm_cols=tuple( + [ + DateColumn.get_legacy_time_column( + timestamp_format=timestamp_format, + offset=self.datasource.offset, + time_shift=self.form_data.get("time_shift"), + ) + ] + ), ) if self.enforce_numerical_metrics: @@ -397,9 +404,7 @@ def query_obj(self) -> QueryObjectDict: # pylint: disable=too-many-locals # extras are used to query elements specific to a datasource type # for instance the extra where clause that applies only to Tables extras = { - "druid_time_origin": self.form_data.get("druid_time_origin", ""), "having": self.form_data.get("having", ""), - "having_druid": self.form_data.get("having_filters", []), "time_grain_sqla": self.form_data.get("time_grain_sqla"), "where": self.form_data.get("where", ""), } @@ -900,7 +905,7 @@ def query_obj(self) -> QueryObjectDict: groupby = [] if not groupby: raise QueryObjectValidationError( - _("Please choose at least one 'Group by' field ") + _("Please choose at least one 'Group by' field") ) if transpose and not columns: raise QueryObjectValidationError( @@ -2174,14 +2179,14 @@ def get_data(self, df: pd.DataFrame) -> VizData: if df is not None and not df.empty: if metric: df = df.sort_values( - utils.get_metric_name(metric), ascending=flt.get("asc") + utils.get_metric_name(metric), ascending=flt.get("asc", False) ) data[col] = [ {"id": row[0], "text": row[0], "metric": row[1]} for row in df.itertuples(index=False) ] else: - df = df.sort_values(col, ascending=flt.get("asc")) + df = df.sort_values(col, ascending=flt.get("asc", False)) data[col] = [ {"id": row[0], "text": row[0]} for row in df.itertuples(index=False) @@ -3219,7 +3224,7 @@ def get_data(self, df: pd.DataFrame) -> VizData: groups = get_column_names(self.form_data.get("groupby")) time_op = self.form_data.get("time_series_option", "not_time") if not groups: - raise ValueError("Please choose at least one groupby") + raise ValueError(_("Please choose at least one groupby")) if time_op == "not_time": levels = self.levels_for("agg_sum", groups, df) elif time_op in ["agg_sum", "agg_mean"]: diff --git a/tests/common/query_context_generator.py b/tests/common/query_context_generator.py index 8fddeb92ffda9..15b013dc845c2 100644 --- a/tests/common/query_context_generator.py +++ b/tests/common/query_context_generator.py @@ -22,7 +22,7 @@ from superset.utils.core import AnnotationType, DTTM_ALIAS query_birth_names = { - "extras": {"where": "", "time_grain_sqla": "P1D"}, + "extras": {"where": "", "time_grain_sqla": "P1D", "having_druid": []}, "columns": ["name"], "metrics": [{"label": "sum__num"}], "orderby": [("sum__num", False)], @@ -195,9 +195,7 @@ }, { "operation": "sort", - "options": { - "columns": {"q1": False, "name": True}, - }, + "options": {"by": ["q1", "name"], "ascending": [False, True]}, }, ] } diff --git a/tests/conftest.py b/tests/conftest.py index 2c129965f1bd6..9d13e581704e4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -28,7 +28,7 @@ from typing import Callable, TYPE_CHECKING from unittest.mock import MagicMock, Mock, PropertyMock -from flask import Flask +from flask import current_app, Flask from flask.ctx import AppContext from pytest import fixture @@ -40,6 +40,7 @@ from tests.example_data.data_loading.pandas.table_df_convertor import ( TableToDfConvertorImpl, ) +from tests.integration_tests.test_app import app SUPPORT_DATETIME_TYPE = "support_datetime_type" @@ -70,7 +71,9 @@ def mock_provider() -> Mock: @fixture(scope="session") def example_db_engine(example_db_provider: Callable[[], Database]) -> Engine: - return example_db_provider().get_sqla_engine() + with app.app_context(): + with example_db_provider().get_sqla_engine_with_context() as engine: + return engine @fixture(scope="session") diff --git a/tests/integration_tests/access_tests.py b/tests/integration_tests/access_tests.py index 64b09fb926522..38fd10524019f 100644 --- a/tests/integration_tests/access_tests.py +++ b/tests/integration_tests/access_tests.py @@ -18,11 +18,12 @@ """Unit tests for Superset""" import json import unittest +from typing import Optional from unittest import mock import pytest -from flask import g from flask.ctx import AppContext +from pytest_mock import MockFixture from sqlalchemy import inspect from tests.integration_tests.fixtures.birth_names_dashboard import ( @@ -39,11 +40,10 @@ ) from tests.integration_tests.test_app import app # isort:skip from superset import db, security_manager -from superset.connectors.connector_registry import ConnectorRegistry from superset.connectors.sqla.models import SqlaTable from superset.models import core as models from superset.models.datasource_access_request import DatasourceAccessRequest -from superset.utils.core import get_username, override_user +from superset.utils.core import get_user_id, get_username, override_user from superset.utils.database import get_example_database from .base_tests import SupersetTestCase @@ -90,12 +90,12 @@ def create_access_request(session, ds_type, ds_name, role_name, username): - ds_class = ConnectorRegistry.sources[ds_type] # TODO: generalize datasource names if ds_type == "table": - ds = session.query(ds_class).filter(ds_class.table_name == ds_name).first() + ds = session.query(SqlaTable).filter(SqlaTable.table_name == ds_name).first() else: - ds = session.query(ds_class).filter(ds_class.datasource_name == ds_name).first() + # This function will only work for ds_type == "table" + raise NotImplementedError() ds_perm_view = security_manager.find_permission_view_menu( "datasource_access", ds.perm ) @@ -158,8 +158,8 @@ def test_override_role_permissions_is_admin_only(self): @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_override_role_permissions_1_table(self): database = get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name perm_data = ROLE_TABLES_PERM_DATA.copy() perm_data["database"][0]["schema"][0]["name"] = schema @@ -186,8 +186,8 @@ def test_override_role_permissions_1_table(self): ) def test_override_role_permissions_drops_absent_perms(self): database = get_example_database() - engine = database.get_sqla_engine() - schema = inspect(engine).default_schema_name + with database.get_sqla_engine_with_context() as engine: + schema = inspect(engine).default_schema_name override_me = security_manager.find_role("override_me") override_me.permissions.append( @@ -449,49 +449,6 @@ def test_approve(self, mock_send_mime): TEST_ROLE = security_manager.find_role(TEST_ROLE_NAME) self.assertIn(perm_view, TEST_ROLE.permissions) - # Case 3. Grant new role to the user to access the druid datasource. - - security_manager.add_role("druid_role") - access_request3 = create_access_request( - session, "druid", "druid_ds_1", "druid_role", "gamma" - ) - self.get_resp( - GRANT_ROLE_REQUEST.format( - "druid", access_request3.datasource_id, "gamma", "druid_role" - ) - ) - - # user was granted table_role - user_roles = [r.name for r in security_manager.find_user("gamma").roles] - self.assertIn("druid_role", user_roles) - - # Case 4. Extend the role to have access to the druid datasource - - access_request4 = create_access_request( - session, "druid", "druid_ds_2", "druid_role", "gamma" - ) - druid_ds_2_perm = access_request4.datasource.perm - - self.client.get( - EXTEND_ROLE_REQUEST.format( - "druid", access_request4.datasource_id, "gamma", "druid_role" - ) - ) - # druid_role was extended to grant access to the druid_access_ds_2 - druid_role = security_manager.find_role("druid_role") - perm_view = security_manager.find_permission_view_menu( - "datasource_access", druid_ds_2_perm - ) - self.assertIn(perm_view, druid_role.permissions) - - # cleanup - gamma_user = security_manager.find_user(username="gamma") - gamma_user.roles.remove(security_manager.find_role("druid_role")) - gamma_user.roles.remove(security_manager.find_role(TEST_ROLE_NAME)) - session.delete(security_manager.find_role("druid_role")) - session.delete(security_manager.find_role(TEST_ROLE_NAME)) - session.commit() - def test_request_access(self): if app.config["ENABLE_ACCESS_REQUEST"]: session = db.session @@ -569,44 +526,72 @@ def test_request_access(self): @pytest.mark.parametrize( - "username", + "username,user_id", [ - None, - "gamma", + (None, None), + ("alpha", 5), + ("gamma", 2), ], ) -def test_get_username(app_context: AppContext, username: str) -> None: - assert not hasattr(g, "user") - assert get_username() is None - - g.user = security_manager.find_user(username) - assert get_username() == username +def test_get_user_id( + app_context: AppContext, + mocker: MockFixture, + username: Optional[str], + user_id: Optional[int], +) -> None: + mock_g = mocker.patch("superset.utils.core.g", spec={}) + mock_g.user = security_manager.find_user(username) + assert get_user_id() == user_id @pytest.mark.parametrize( "username", [ None, + "alpha", "gamma", ], ) -def test_override_user(app_context: AppContext, username: str) -> None: +def test_get_username( + app_context: AppContext, + mocker: MockFixture, + username: Optional[str], +) -> None: + mock_g = mocker.patch("superset.utils.core.g", spec={}) + mock_g.user = security_manager.find_user(username) + assert get_username() == username + + +@pytest.mark.parametrize("username", [None, "alpha", "gamma"]) +@pytest.mark.parametrize("force", [False, True]) +def test_override_user( + app_context: AppContext, + mocker: MockFixture, + username: str, + force: bool, +) -> None: + mock_g = mocker.patch("superset.utils.core.g", spec={}) admin = security_manager.find_user(username="admin") user = security_manager.find_user(username) - assert not hasattr(g, "user") + with override_user(user, force): + assert mock_g.user == user + + assert not hasattr(mock_g, "user") + + mock_g.user = None - with override_user(user): - assert g.user == user + with override_user(user, force): + assert mock_g.user == user - assert not hasattr(g, "user") + assert mock_g.user is None - g.user = admin + mock_g.user = admin - with override_user(user): - assert g.user == user + with override_user(user, force): + assert mock_g.user == user if force else admin - assert g.user == admin + assert mock_g.user == admin if __name__ == "__main__": diff --git a/tests/integration_tests/advanced_data_type/api_tests.py b/tests/integration_tests/advanced_data_type/api_tests.py index 7daa5f0067ddc..5bfe308e1683b 100644 --- a/tests/integration_tests/advanced_data_type/api_tests.py +++ b/tests/integration_tests/advanced_data_type/api_tests.py @@ -18,17 +18,9 @@ """Unit tests for Superset""" import json import prison -from sqlalchemy import null -from superset.connectors.sqla.models import SqlaTable from superset.utils.core import get_example_default_schema -from tests.integration_tests.base_tests import ( - SupersetTestCase, - logged_in_admin, - test_client, -) -from tests.integration_tests.test_app import app from tests.integration_tests.utils.get_dashboards import get_dashboards_ids from unittest import mock from sqlalchemy import Column @@ -80,7 +72,7 @@ def translate_filter_func(col: Column, op: FilterOperator, values: List[Any]): "superset.advanced_data_type.api.ADVANCED_DATA_TYPES", {"type": 1}, ) -def test_types_type_request(logged_in_admin): +def test_types_type_request(test_client, login_as_admin): """ Advanced Data Type API: Test to see if the API call returns all the valid advanced data types """ @@ -91,7 +83,7 @@ def test_types_type_request(logged_in_admin): assert data == {"result": ["type"]} -def test_types_convert_bad_request_no_vals(logged_in_admin): +def test_types_convert_bad_request_no_vals(test_client, login_as_admin): """ Advanced Data Type API: Test request to see if it behaves as expected when no values are passed """ @@ -101,7 +93,7 @@ def test_types_convert_bad_request_no_vals(logged_in_admin): assert response_value.status_code == 400 -def test_types_convert_bad_request_no_type(logged_in_admin): +def test_types_convert_bad_request_no_type(test_client, login_as_admin): """ Advanced Data Type API: Test request to see if it behaves as expected when no type is passed """ @@ -115,7 +107,7 @@ def test_types_convert_bad_request_no_type(logged_in_admin): "superset.advanced_data_type.api.ADVANCED_DATA_TYPES", {"type": 1}, ) -def test_types_convert_bad_request_type_not_found(logged_in_admin): +def test_types_convert_bad_request_type_not_found(test_client, login_as_admin): """ Advanced Data Type API: Test request to see if it behaves as expected when passed in type is not found/not valid @@ -130,7 +122,7 @@ def test_types_convert_bad_request_type_not_found(logged_in_admin): "superset.advanced_data_type.api.ADVANCED_DATA_TYPES", {"type": test_type}, ) -def test_types_convert_request(logged_in_admin): +def test_types_convert_request(test_client, login_as_admin): """ Advanced Data Type API: Test request to see if it behaves as expected when a valid type and valid values are passed in diff --git a/tests/integration_tests/annotation_layers/fixtures.py b/tests/integration_tests/annotation_layers/fixtures.py index 52cb8ca2abf41..8243d7e474d57 100644 --- a/tests/integration_tests/annotation_layers/fixtures.py +++ b/tests/integration_tests/annotation_layers/fixtures.py @@ -73,7 +73,7 @@ def _insert_annotation( def create_annotation_layers(): """ Creates ANNOTATION_LAYERS_COUNT-1 layers with no annotations - and a final one with ANNOTATION_COUNT childs + and a final one with ANNOTATION_COUNT children :return: """ with app.app_context(): diff --git a/tests/integration_tests/available_domains/__init__.py b/tests/integration_tests/available_domains/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/integration_tests/available_domains/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/integration_tests/available_domains/api_tests.py b/tests/integration_tests/available_domains/api_tests.py new file mode 100644 index 0000000000000..8838207d29094 --- /dev/null +++ b/tests/integration_tests/available_domains/api_tests.py @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import json + +from tests.integration_tests.test_app import app + + +def test_get_available_domains(test_client, login_as_admin): + cached = app.config["SUPERSET_WEBSERVER_DOMAINS"] + app.config["SUPERSET_WEBSERVER_DOMAINS"] = ["a", "b"] + resp = test_client.get("api/v1/available_domains/") + assert resp.status_code == 200 + data = json.loads(resp.data.decode("utf-8")) + result = data.get("result") + assert result == {"domains": ["a", "b"]} + app.config["SUPERSET_WEBSERVER_DOMAINS"] = cached diff --git a/tests/integration_tests/base_api_tests.py b/tests/integration_tests/base_api_tests.py index 8dbbb6862e3bf..478fee0a0dca4 100644 --- a/tests/integration_tests/base_api_tests.py +++ b/tests/integration_tests/base_api_tests.py @@ -16,6 +16,8 @@ # under the License. # isort:skip_file import json +from unittest.mock import patch + from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices, load_world_bank_data, @@ -32,6 +34,7 @@ from superset.views.base_api import BaseSupersetModelRestApi, requires_json from .base_tests import SupersetTestCase +from .conftest import with_config class Model1Api(BaseSupersetModelRestApi): @@ -216,6 +219,26 @@ def test_get_related_owners(self): for expected_user in expected_users: assert expected_user in response_users + def test_get_related_owners_with_extra_filters(self): + """ + API: Test get related owners with extra related query filters + """ + self.login(username="admin") + + def _base_filter(query): + return query.filter_by(username="alpha") + + with patch.dict( + "superset.views.filters.current_app.config", + {"EXTRA_RELATED_QUERY_FILTERS": {"user": _base_filter}}, + ): + uri = f"api/v1/{self.resource_name}/related/owners" + rv = self.client.get(uri) + assert rv.status_code == 200 + response = json.loads(rv.data.decode("utf-8")) + response_users = [result["text"] for result in response["result"]] + assert response_users == ["alpha user"] + def test_get_related_owners_paginated(self): """ API: Test get related owners with pagination @@ -264,14 +287,79 @@ def test_get_filter_related_owners(self): assert 4 == response["count"] sorted_results = sorted(response["result"], key=lambda value: value["text"]) expected_results = [ - {"text": "gamma user", "value": 2}, - {"text": "gamma2 user", "value": 3}, - {"text": "gamma_no_csv user", "value": 6}, - {"text": "gamma_sqllab user", "value": 4}, + { + "extra": {"active": True, "email": "gamma@fab.org"}, + "text": "gamma user", + "value": 2, + }, + { + "extra": {"active": True, "email": "gamma2@fab.org"}, + "text": "gamma2 user", + "value": 3, + }, + { + "extra": {"active": True, "email": "gamma_no_csv@fab.org"}, + "text": "gamma_no_csv user", + "value": 6, + }, + { + "extra": {"active": True, "email": "gamma_sqllab@fab.org"}, + "text": "gamma_sqllab user", + "value": 4, + }, ] # TODO Check me assert expected_results == sorted_results + @with_config({"EXCLUDE_USERS_FROM_LISTS": ["gamma"]}) + def test_get_base_filter_related_owners(self): + """ + API: Test get base filter related owners + """ + self.login(username="admin") + uri = f"api/v1/{self.resource_name}/related/owners" + gamma_user = ( + db.session.query(security_manager.user_model) + .filter(security_manager.user_model.username == "gamma") + .one_or_none() + ) + assert gamma_user is not None + users = db.session.query(security_manager.user_model).all() + + rv = self.client.get(uri) + assert rv.status_code == 200 + response = json.loads(rv.data.decode("utf-8")) + assert response["count"] == len(users) - 1 + response_users = [result["text"] for result in response["result"]] + assert "gamma user" not in response_users + + @patch( + "superset.security.SupersetSecurityManager.get_exclude_users_from_lists", + return_value=["gamma"], + ) + def test_get_base_filter_related_owners_on_sm( + self, mock_get_exclude_users_from_list + ): + """ + API: Test get base filter related owners using security manager + """ + self.login(username="admin") + uri = f"api/v1/{self.resource_name}/related/owners" + gamma_user = ( + db.session.query(security_manager.user_model) + .filter(security_manager.user_model.username == "gamma") + .one_or_none() + ) + assert gamma_user is not None + users = db.session.query(security_manager.user_model).all() + + rv = self.client.get(uri) + assert rv.status_code == 200 + response = json.loads(rv.data.decode("utf-8")) + assert response["count"] == len(users) - 1 + response_users = [result["text"] for result in response["result"]] + assert "gamma user" not in response_users + def test_get_ids_related_owners(self): """ API: Test get filter related owners @@ -286,8 +374,16 @@ def test_get_ids_related_owners(self): assert 2 == response["count"] sorted_results = sorted(response["result"], key=lambda value: value["text"]) expected_results = [ - {"text": "gamma user", "value": 2}, - {"text": "gamma_sqllab user", "value": 4}, + { + "extra": {"active": True, "email": "gamma@fab.org"}, + "text": "gamma user", + "value": 2, + }, + { + "extra": {"active": True, "email": "gamma_sqllab@fab.org"}, + "text": "gamma_sqllab user", + "value": 4, + }, ] assert expected_results == sorted_results @@ -305,8 +401,16 @@ def test_get_repeated_ids_related_owners(self): assert 2 == response["count"] sorted_results = sorted(response["result"], key=lambda value: value["text"]) expected_results = [ - {"text": "gamma user", "value": 2}, - {"text": "gamma_sqllab user", "value": 4}, + { + "extra": {"active": True, "email": "gamma@fab.org"}, + "text": "gamma user", + "value": 2, + }, + { + "extra": {"active": True, "email": "gamma_sqllab@fab.org"}, + "text": "gamma_sqllab user", + "value": 4, + }, ] assert expected_results == sorted_results diff --git a/tests/integration_tests/base_tests.py b/tests/integration_tests/base_tests.py index 280d58774ab06..f70f0f63bde36 100644 --- a/tests/integration_tests/base_tests.py +++ b/tests/integration_tests/base_tests.py @@ -24,17 +24,16 @@ from unittest.mock import Mock, patch, MagicMock import pandas as pd -import pytest from flask import Response from flask_appbuilder.security.sqla import models as ab_models from flask_testing import TestCase from sqlalchemy.engine.interfaces import Dialect -from sqlalchemy.ext.declarative.api import DeclarativeMeta +from sqlalchemy.ext.declarative import DeclarativeMeta from sqlalchemy.orm import Session from sqlalchemy.sql import func from sqlalchemy.dialects.mysql import dialect -from tests.integration_tests.test_app import app +from tests.integration_tests.test_app import app, login from superset.sql_parse import CtasMethod from superset import db, security_manager from superset.connectors.base.models import BaseDatasource @@ -52,11 +51,6 @@ test_client = app.test_client() -def login(client: Any, username: str = "admin", password: str = "general"): - resp = get_resp(client, "/login/", data=dict(username=username, password=password)) - assert "User confirmation needed" not in resp - - def get_resp( client: Any, url: str, @@ -96,20 +90,13 @@ def post_assert_metric( rv = client.post(uri, json=data) if 200 <= rv.status_code < 400: mock_method.assert_called_once_with("success", func_name) + elif 400 <= rv.status_code < 500: + mock_method.assert_called_once_with("warning", func_name) else: mock_method.assert_called_once_with("error", func_name) return rv -@pytest.fixture -def logged_in_admin(): - """Fixture with app context and logged in admin user.""" - with app.app_context(): - login(test_client, username="admin") - yield - test_client.get("/logout/", follow_redirects=True) - - class SupersetTestCase(TestCase): default_schema_backend_map = { "sqlite": "main", @@ -362,7 +349,7 @@ def run_sql( json_payload["schema"] = schema resp = self.get_json_resp( - "/superset/sql_json/", raise_on_error=False, json_=json_payload + "/api/v1/sqllab/execute/", raise_on_error=False, json_=json_payload ) if raise_on_error and "error" in resp: raise Exception("run_sql failed") @@ -470,6 +457,8 @@ def get_assert_metric(self, uri: str, func_name: str) -> Response: rv = self.client.get(uri) if 200 <= rv.status_code < 400: mock_method.assert_called_once_with("success", func_name) + elif 400 <= rv.status_code < 500: + mock_method.assert_called_once_with("warning", func_name) else: mock_method.assert_called_once_with("error", func_name) return rv @@ -489,6 +478,8 @@ def delete_assert_metric(self, uri: str, func_name: str) -> Response: rv = self.client.delete(uri) if 200 <= rv.status_code < 400: mock_method.assert_called_once_with("success", func_name) + elif 400 <= rv.status_code < 500: + mock_method.assert_called_once_with("warning", func_name) else: mock_method.assert_called_once_with("error", func_name) return rv @@ -516,6 +507,8 @@ def put_assert_metric( rv = self.client.put(uri, json=data) if 200 <= rv.status_code < 400: mock_method.assert_called_once_with("success", func_name) + elif 400 <= rv.status_code < 500: + mock_method.assert_called_once_with("warning", func_name) else: mock_method.assert_called_once_with("error", func_name) return rv diff --git a/tests/integration_tests/cachekeys/api_tests.py b/tests/integration_tests/cachekeys/api_tests.py index e994380e9d998..d3552bfc8df26 100644 --- a/tests/integration_tests/cachekeys/api_tests.py +++ b/tests/integration_tests/cachekeys/api_tests.py @@ -18,7 +18,7 @@ """Unit tests for Superset""" from typing import Dict, Any -from tests.integration_tests.test_app import app # noqa +import pytest from superset.extensions import cache_manager, db from superset.models.cache import CacheKey @@ -26,23 +26,25 @@ from tests.integration_tests.base_tests import ( SupersetTestCase, post_assert_metric, - test_client, - logged_in_admin, -) # noqa +) -def invalidate(params: Dict[str, Any]): - return post_assert_metric( - test_client, "api/v1/cachekey/invalidate", params, "invalidate" - ) +@pytest.fixture +def invalidate(test_client, login_as_admin): + def _invalidate(params: Dict[str, Any]): + return post_assert_metric( + test_client, "api/v1/cachekey/invalidate", params, "invalidate" + ) + + return _invalidate -def test_invalidate_cache(logged_in_admin): +def test_invalidate_cache(invalidate): rv = invalidate({"datasource_uids": ["3__table"]}) assert rv.status_code == 201 -def test_invalidate_existing_cache(logged_in_admin): +def test_invalidate_existing_cache(invalidate): db.session.add(CacheKey(cache_key="cache_key", datasource_uid="3__table")) db.session.commit() cache_manager.cache.set("cache_key", "value") @@ -56,7 +58,7 @@ def test_invalidate_existing_cache(logged_in_admin): ) -def test_invalidate_cache_empty_input(logged_in_admin): +def test_invalidate_cache_empty_input(invalidate): rv = invalidate({"datasource_uids": []}) assert rv.status_code == 201 @@ -67,7 +69,7 @@ def test_invalidate_cache_empty_input(logged_in_admin): assert rv.status_code == 201 -def test_invalidate_cache_bad_request(logged_in_admin): +def test_invalidate_cache_bad_request(invalidate): rv = invalidate( { "datasource_uids": [], @@ -93,7 +95,7 @@ def test_invalidate_cache_bad_request(logged_in_admin): assert rv.status_code == 400 -def test_invalidate_existing_caches(logged_in_admin): +def test_invalidate_existing_caches(invalidate): schema = get_example_default_schema() or "" bn = SupersetTestCase.get_birth_names_dataset() diff --git a/tests/integration_tests/celery_tests.py b/tests/integration_tests/celery_tests.py index 9a9447640f120..8693a888879d4 100644 --- a/tests/integration_tests/celery_tests.py +++ b/tests/integration_tests/celery_tests.py @@ -17,7 +17,6 @@ # isort:skip_file """Unit tests for Superset Celery worker""" import datetime -import json import random import string import time @@ -33,9 +32,6 @@ import flask from flask import current_app -from tests.integration_tests.base_tests import login -from tests.integration_tests.conftest import CTAS_SCHEMA_NAME -from tests.integration_tests.test_app import app from superset import db, sql_lab from superset.common.db_query_status import QueryStatus from superset.result_set import SupersetResultSet @@ -46,6 +42,8 @@ from superset.sql_parse import ParsedQuery, CtasMethod from superset.utils.core import backend from superset.utils.database import get_example_database +from tests.integration_tests.conftest import CTAS_SCHEMA_NAME +from tests.integration_tests.test_app import app CELERY_SLEEP_TIME = 6 QUERY = "SELECT name FROM birth_names LIMIT 1" @@ -63,9 +61,6 @@ ] -test_client = app.test_client() - - def get_query_by_id(id: int): db.session.commit() query = db.session.query(Query).filter_by(id=id).first() @@ -74,10 +69,10 @@ def get_query_by_id(id: int): @pytest.fixture(autouse=True, scope="module") def setup_sqllab(): - + yield + # clean up after all tests are done + # use a new app context with app.app_context(): - yield - db.session.query(Query).delete() db.session.commit() for tbl in TMP_TABLES: @@ -92,12 +87,16 @@ def setup_sqllab(): def run_sql( - sql, cta=False, ctas_method=CtasMethod.TABLE, tmp_table="tmp", async_=False + test_client, + sql, + cta=False, + ctas_method=CtasMethod.TABLE, + tmp_table="tmp", + async_=False, ): - login(test_client, username="admin") db_id = get_example_database().id - resp = test_client.post( - "/superset/sql_json/", + return test_client.post( + "/api/v1/sqllab/execute/", json=dict( database_id=db_id, sql=sql, @@ -107,15 +106,15 @@ def run_sql( client_id="".join(random.choice(string.ascii_lowercase) for i in range(5)), ctas_method=ctas_method, ), - ) - test_client.get("/logout/", follow_redirects=True) - return json.loads(resp.data) + ).json def drop_table_if_exists(table_name: str, table_type: CtasMethod) -> None: """Drop table if it exists, works on any DB""" - sql = f"DROP {table_type} IF EXISTS {table_name}" - get_example_database().get_sqla_engine().execute(sql) + sql = f"DROP {table_type} IF EXISTS {table_name}" + database = get_example_database() + with database.get_sqla_engine_with_context() as engine: + engine.execute(sql) def quote_f(value: Optional[str]): @@ -144,12 +143,13 @@ def get_select_star(table: str, limit: int, schema: Optional[str] = None): return f"SELECT *\nFROM {table}\nLIMIT {limit}" +@pytest.mark.usefixtures("login_as_admin") @pytest.mark.parametrize("ctas_method", [CtasMethod.TABLE, CtasMethod.VIEW]) -def test_run_sync_query_dont_exist(setup_sqllab, ctas_method): +def test_run_sync_query_dont_exist(test_client, ctas_method): examples_db = get_example_database() engine_name = examples_db.db_engine_spec.engine_name sql_dont_exist = "SELECT name FROM table_dont_exist" - result = run_sql(sql_dont_exist, cta=True, ctas_method=ctas_method) + result = run_sql(test_client, sql_dont_exist, cta=True, ctas_method=ctas_method) if backend() == "sqlite" and ctas_method == CtasMethod.VIEW: assert QueryStatus.SUCCESS == result["status"], result elif backend() == "presto": @@ -188,27 +188,29 @@ def test_run_sync_query_dont_exist(setup_sqllab, ctas_method): } -@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") +@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices", "login_as_admin") @pytest.mark.parametrize("ctas_method", [CtasMethod.TABLE, CtasMethod.VIEW]) -def test_run_sync_query_cta(setup_sqllab, ctas_method): +def test_run_sync_query_cta(test_client, ctas_method): tmp_table_name = f"{TEST_SYNC}_{ctas_method.lower()}" - result = run_sql(QUERY, tmp_table=tmp_table_name, cta=True, ctas_method=ctas_method) + result = run_sql( + test_client, QUERY, tmp_table=tmp_table_name, cta=True, ctas_method=ctas_method + ) assert QueryStatus.SUCCESS == result["query"]["state"], result assert cta_result(ctas_method) == (result["data"], result["columns"]) # Check the data in the tmp table. select_query = get_query_by_id(result["query"]["serverId"]) - results = run_sql(select_query.select_sql) + results = run_sql(test_client, select_query.select_sql) assert QueryStatus.SUCCESS == results["status"], results assert len(results["data"]) > 0 delete_tmp_view_or_table(tmp_table_name, ctas_method) -@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") -def test_run_sync_query_cta_no_data(setup_sqllab): +@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices", "login_as_admin") +def test_run_sync_query_cta_no_data(test_client): sql_empty_result = "SELECT * FROM birth_names WHERE name='random'" - result = run_sql(sql_empty_result) + result = run_sql(test_client, sql_empty_result) assert QueryStatus.SUCCESS == result["query"]["state"] assert ([], []) == (result["data"], result["columns"]) @@ -216,18 +218,20 @@ def test_run_sync_query_cta_no_data(setup_sqllab): assert QueryStatus.SUCCESS == query.status -@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") +@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices", "login_as_admin") @pytest.mark.parametrize("ctas_method", [CtasMethod.TABLE, CtasMethod.VIEW]) @mock.patch( "superset.sqllab.sqllab_execution_context.get_cta_schema_name", lambda d, u, s, sql: CTAS_SCHEMA_NAME, ) -def test_run_sync_query_cta_config(setup_sqllab, ctas_method): +def test_run_sync_query_cta_config(test_client, ctas_method): if backend() == "sqlite": # sqlite doesn't support schemas return tmp_table_name = f"{TEST_SYNC_CTA}_{ctas_method.lower()}" - result = run_sql(QUERY, cta=True, ctas_method=ctas_method, tmp_table=tmp_table_name) + result = run_sql( + test_client, QUERY, cta=True, ctas_method=ctas_method, tmp_table=tmp_table_name + ) assert QueryStatus.SUCCESS == result["query"]["state"], result assert cta_result(ctas_method) == (result["data"], result["columns"]) @@ -239,24 +243,25 @@ def test_run_sync_query_cta_config(setup_sqllab, ctas_method): assert query.select_sql == get_select_star( tmp_table_name, limit=query.limit, schema=CTAS_SCHEMA_NAME ) - results = run_sql(query.select_sql) + results = run_sql(test_client, query.select_sql) assert QueryStatus.SUCCESS == results["status"], result delete_tmp_view_or_table(f"{CTAS_SCHEMA_NAME}.{tmp_table_name}", ctas_method) -@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") +@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices", "login_as_admin") @pytest.mark.parametrize("ctas_method", [CtasMethod.TABLE, CtasMethod.VIEW]) @mock.patch( "superset.sqllab.sqllab_execution_context.get_cta_schema_name", lambda d, u, s, sql: CTAS_SCHEMA_NAME, ) -def test_run_async_query_cta_config(setup_sqllab, ctas_method): +def test_run_async_query_cta_config(test_client, ctas_method): if backend() in {"sqlite", "mysql"}: # sqlite doesn't support schemas, mysql is flaky return tmp_table_name = f"{TEST_ASYNC_CTA_CONFIG}_{ctas_method.lower()}" result = run_sql( + test_client, QUERY, cta=True, ctas_method=ctas_method, @@ -279,16 +284,21 @@ def test_run_async_query_cta_config(setup_sqllab, ctas_method): delete_tmp_view_or_table(f"{CTAS_SCHEMA_NAME}.{tmp_table_name}", ctas_method) -@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") +@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices", "login_as_admin") @pytest.mark.parametrize("ctas_method", [CtasMethod.TABLE, CtasMethod.VIEW]) -def test_run_async_cta_query(setup_sqllab, ctas_method): +def test_run_async_cta_query(test_client, ctas_method): if backend() == "mysql": # failing return table_name = f"{TEST_ASYNC_CTA}_{ctas_method.lower()}" result = run_sql( - QUERY, cta=True, ctas_method=ctas_method, async_=True, tmp_table=table_name + test_client, + QUERY, + cta=True, + ctas_method=ctas_method, + async_=True, + tmp_table=table_name, ) query = wait_for_success(result) @@ -305,16 +315,21 @@ def test_run_async_cta_query(setup_sqllab, ctas_method): delete_tmp_view_or_table(table_name, ctas_method) -@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") +@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices", "login_as_admin") @pytest.mark.parametrize("ctas_method", [CtasMethod.TABLE, CtasMethod.VIEW]) -def test_run_async_cta_query_with_lower_limit(setup_sqllab, ctas_method): +def test_run_async_cta_query_with_lower_limit(test_client, ctas_method): if backend() == "mysql": # failing return tmp_table = f"{TEST_ASYNC_LOWER_LIMIT}_{ctas_method.lower()}" result = run_sql( - QUERY, cta=True, ctas_method=ctas_method, async_=True, tmp_table=tmp_table + test_client, + QUERY, + cta=True, + ctas_method=ctas_method, + async_=True, + tmp_table=tmp_table, ) query = wait_for_success(result) assert QueryStatus.SUCCESS == query.status diff --git a/tests/integration_tests/charts/api_tests.py b/tests/integration_tests/charts/api_tests.py index a37acf6eafc3a..965a9c137ba87 100644 --- a/tests/integration_tests/charts/api_tests.py +++ b/tests/integration_tests/charts/api_tests.py @@ -17,6 +17,7 @@ # isort:skip_file """Unit tests for Superset""" import json +import logging from io import BytesIO from zipfile import is_zipfile, ZipFile @@ -30,7 +31,7 @@ from superset.extensions import cache_manager, db from superset.models.core import Database, FavStar, FavStarClassName from superset.models.dashboard import Dashboard -from superset.models.reports import ReportSchedule, ReportScheduleType +from superset.reports.models import ReportSchedule, ReportScheduleType from superset.models.slice import Slice from superset.utils.core import get_example_default_schema @@ -100,6 +101,19 @@ def create_charts(self): db.session.delete(fav_chart) db.session.commit() + @pytest.fixture() + def create_charts_created_by_gamma(self): + with self.create_app().app_context(): + charts = [] + user = self.get_user("gamma") + for cx in range(CHARTS_FIXTURE_COUNT - 1): + charts.append(self.insert_chart(f"gamma{cx}", [user.id], 1)) + yield charts + # rollback changes + for chart in charts: + db.session.delete(chart) + db.session.commit() + @pytest.fixture() def create_certified_charts(self): with self.create_app().app_context(): @@ -678,6 +692,61 @@ def test_update_chart_not_owned(self): db.session.delete(user_alpha2) db.session.commit() + def test_update_chart_linked_with_not_owned_dashboard(self): + """ + Chart API: Test update chart which is linked to not owned dashboard + """ + user_alpha1 = self.create_user( + "alpha1", "password", "Alpha", email="alpha1@superset.org" + ) + user_alpha2 = self.create_user( + "alpha2", "password", "Alpha", email="alpha2@superset.org" + ) + chart = self.insert_chart("title", [user_alpha1.id], 1) + + original_dashboard = Dashboard() + original_dashboard.dashboard_title = "Original Dashboard" + original_dashboard.slug = "slug" + original_dashboard.owners = [user_alpha1] + original_dashboard.slices = [chart] + original_dashboard.published = False + db.session.add(original_dashboard) + + new_dashboard = Dashboard() + new_dashboard.dashboard_title = "Cloned Dashboard" + new_dashboard.slug = "new_slug" + new_dashboard.owners = [user_alpha2] + new_dashboard.slices = [chart] + new_dashboard.published = False + db.session.add(new_dashboard) + + self.login(username="alpha1", password="password") + chart_data_with_invalid_dashboard = { + "slice_name": "title1_changed", + "dashboards": [original_dashboard.id, 0], + } + chart_data = { + "slice_name": "title1_changed", + "dashboards": [original_dashboard.id, new_dashboard.id], + } + uri = f"api/v1/chart/{chart.id}" + + rv = self.put_assert_metric(uri, chart_data_with_invalid_dashboard, "put") + self.assertEqual(rv.status_code, 422) + response = json.loads(rv.data.decode("utf-8")) + expected_response = {"message": {"dashboards": ["Dashboards do not exist"]}} + self.assertEqual(response, expected_response) + + rv = self.put_assert_metric(uri, chart_data, "put") + self.assertEqual(rv.status_code, 200) + + db.session.delete(chart) + db.session.delete(original_dashboard) + db.session.delete(new_dashboard) + db.session.delete(user_alpha1) + db.session.delete(user_alpha2) + db.session.commit() + def test_update_chart_validate_datasource(self): """ Chart API: Test update validate datasource @@ -762,7 +831,19 @@ def test_get_chart(self): "is_managed_externally": False, } data = json.loads(rv.data.decode("utf-8")) - self.assertEqual(data["result"], expected_result) + self.assertIn("changed_on_delta_humanized", data["result"]) + self.assertIn("id", data["result"]) + self.assertIn("thumbnail_url", data["result"]) + self.assertIn("url", data["result"]) + for key, value in data["result"].items(): + # We can't assert timestamp values or id/urls + if key not in ( + "changed_on_delta_humanized", + "id", + "thumbnail_url", + "url", + ): + self.assertEqual(value, expected_result[key]) db.session.delete(chart) db.session.commit() @@ -808,6 +889,51 @@ def test_get_charts(self): data = json.loads(rv.data.decode("utf-8")) self.assertEqual(data["count"], 34) + @pytest.mark.usefixtures("load_energy_table_with_slice", "add_dashboard_to_chart") + def test_get_charts_dashboards(self): + """ + Chart API: Test get charts with related dashboards + """ + self.login(username="admin") + arguments = { + "filters": [ + {"col": "slice_name", "opr": "eq", "value": self.chart.slice_name} + ] + } + uri = f"api/v1/chart/?q={prison.dumps(arguments)}" + rv = self.get_assert_metric(uri, "get_list") + self.assertEqual(rv.status_code, 200) + data = json.loads(rv.data.decode("utf-8")) + assert data["result"][0]["dashboards"] == [ + { + "id": self.original_dashboard.id, + "dashboard_title": self.original_dashboard.dashboard_title, + } + ] + + @pytest.mark.usefixtures("load_energy_table_with_slice", "add_dashboard_to_chart") + def test_get_charts_dashboard_filter(self): + """ + Chart API: Test get charts with dashboard filter + """ + self.login(username="admin") + arguments = { + "filters": [ + { + "col": "dashboards", + "opr": "rel_m_m", + "value": self.original_dashboard.id, + } + ] + } + uri = f"api/v1/chart/?q={prison.dumps(arguments)}" + rv = self.get_assert_metric(uri, "get_list") + self.assertEqual(rv.status_code, 200) + data = json.loads(rv.data.decode("utf-8")) + result = data["result"] + assert len(result) == 1 + assert result[0]["slice_name"] == self.chart.slice_name + def test_get_charts_changed_on(self): """ Dashboard API: Test get charts changed on @@ -933,15 +1059,27 @@ def test_admin_gets_filtered_energy_slices(self): } ], "keys": ["none"], - "columns": ["slice_name"], + "columns": ["slice_name", "description", "table.table_name"], } self.login(username="admin") uri = f"api/v1/chart/?q={prison.dumps(arguments)}" rv = self.get_assert_metric(uri, "get_list") - self.assertEqual(rv.status_code, 200) - data = json.loads(rv.data.decode("utf-8")) - self.assertEqual(data["count"], 8) + data = rv.json + assert rv.status_code == 200 + assert data["count"] > 0 + for chart in data["result"]: + print(chart) + assert ( + "energy" + in " ".join( + [ + chart["slice_name"] or "", + chart["description"] or "", + chart["table"]["table_name"] or "", + ] + ).lower() + ) @pytest.mark.usefixtures("create_certified_charts") def test_gets_certified_charts_filter(self): @@ -1054,6 +1192,33 @@ def test_get_charts_favorite_filter(self): assert rv.status_code == 200 assert len(expected_models) == data["count"] + @pytest.mark.usefixtures("create_charts_created_by_gamma") + def test_get_charts_created_by_me_filter(self): + """ + Chart API: Test get charts with created by me special filter + """ + gamma_user = self.get_user("gamma") + expected_models = ( + db.session.query(Slice).filter(Slice.created_by_fk == gamma_user.id).all() + ) + arguments = { + "filters": [ + {"col": "created_by", "opr": "chart_created_by_me", "value": "me"} + ], + "order_column": "slice_name", + "order_direction": "asc", + "keys": ["none"], + "columns": ["slice_name"], + } + self.login(username="gamma") + uri = f"api/v1/chart/?q={prison.dumps(arguments)}" + rv = self.client.get(uri) + data = json.loads(rv.data.decode("utf-8")) + assert rv.status_code == 200 + assert len(expected_models) == data["count"] + for i, expected_model in enumerate(expected_models): + assert expected_model.slice_name == data["result"][i]["slice_name"] + @pytest.mark.usefixtures("create_charts") def test_get_current_user_favorite_status(self): """ @@ -1205,9 +1370,10 @@ def test_import_chart(self): chart.owners = [] dataset.owners = [] - database.owners = [] db.session.delete(chart) + db.session.commit() db.session.delete(dataset) + db.session.commit() db.session.delete(database) db.session.commit() @@ -1277,9 +1443,10 @@ def test_import_chart_overwrite(self): chart.owners = [] dataset.owners = [] - database.owners = [] db.session.delete(chart) + db.session.commit() db.session.delete(dataset) + db.session.commit() db.session.delete(database) db.session.commit() @@ -1332,3 +1499,31 @@ def test_import_chart_invalid(self): } ] } + + def test_gets_created_by_user_charts_filter(self): + arguments = { + "filters": [{"col": "id", "opr": "chart_has_created_by", "value": True}], + "keys": ["none"], + "columns": ["slice_name"], + } + self.login(username="admin") + + uri = f"api/v1/chart/?q={prison.dumps(arguments)}" + rv = self.get_assert_metric(uri, "get_list") + self.assertEqual(rv.status_code, 200) + data = json.loads(rv.data.decode("utf-8")) + self.assertEqual(data["count"], 8) + + def test_gets_not_created_by_user_charts_filter(self): + arguments = { + "filters": [{"col": "id", "opr": "chart_has_created_by", "value": False}], + "keys": ["none"], + "columns": ["slice_name"], + } + self.login(username="admin") + + uri = f"api/v1/chart/?q={prison.dumps(arguments)}" + rv = self.get_assert_metric(uri, "get_list") + self.assertEqual(rv.status_code, 200) + data = json.loads(rv.data.decode("utf-8")) + self.assertEqual(data["count"], 8) diff --git a/tests/integration_tests/charts/commands_tests.py b/tests/integration_tests/charts/commands_tests.py index ec205b6a6abee..da9a7550acb44 100644 --- a/tests/integration_tests/charts/commands_tests.py +++ b/tests/integration_tests/charts/commands_tests.py @@ -72,6 +72,9 @@ def test_export_chart_command(self, mock_g): assert metadata == { "slice_name": "Energy Sankey", + "description": None, + "certified_by": None, + "certification_details": None, "viz_type": "sankey", "params": { "collapsed_fieldsets": "", @@ -85,49 +88,7 @@ def test_export_chart_command(self, mock_g): "dataset_uuid": str(example_chart.table.uuid), "uuid": str(example_chart.uuid), "version": "1.0.0", - } - - @patch("superset.security.manager.g") - @pytest.mark.usefixtures("load_energy_table_with_slice") - def test_export_chart_with_query_context(self, mock_g): - """Test that charts that have a query_context are exported correctly""" - - mock_g.user = security_manager.find_user("alpha") - example_chart = db.session.query(Slice).filter_by(slice_name="Heatmap").one() - command = ExportChartsCommand([example_chart.id]) - - contents = dict(command.run()) - - expected = [ - "metadata.yaml", - f"charts/Heatmap_{example_chart.id}.yaml", - "datasets/examples/energy_usage.yaml", - "databases/examples.yaml", - ] - assert expected == list(contents.keys()) - - metadata = yaml.safe_load(contents[f"charts/Heatmap_{example_chart.id}.yaml"]) - - assert metadata == { - "slice_name": "Heatmap", - "viz_type": "heatmap", - "params": { - "all_columns_x": "source", - "all_columns_y": "target", - "canvas_image_rendering": "pixelated", - "collapsed_fieldsets": "", - "linear_color_scheme": "blue_white_yellow", - "metric": "sum__value", - "normalize_across": "heatmap", - "slice_name": "Heatmap", - "viz_type": "heatmap", - "xscale_interval": "1", - "yscale_interval": "1", - }, - "cache_timeout": None, - "dataset_uuid": str(example_chart.table.uuid), - "uuid": str(example_chart.uuid), - "version": "1.0.0", + "query_context": None, } @patch("superset.security.manager.g") @@ -168,8 +129,12 @@ def test_export_chart_command_key_order(self, mock_g): ) assert list(metadata.keys()) == [ "slice_name", + "description", + "certified_by", + "certification_details", "viz_type", "params", + "query_context", "cache_timeout", "uuid", "version", @@ -350,58 +315,60 @@ def test_import_v1_chart_validation(self): class TestChartsCreateCommand(SupersetTestCase): - @patch("superset.views.base.g") + @patch("superset.utils.core.g") + @patch("superset.charts.commands.create.g") @patch("superset.security.manager.g") @pytest.mark.usefixtures("load_energy_table_with_slice") - def test_create_v1_response(self, mock_sm_g, mock_g): + def test_create_v1_response(self, mock_sm_g, mock_c_g, mock_u_g): """Test that the create chart command creates a chart""" - actor = security_manager.find_user(username="admin") - mock_g.user = mock_sm_g.user = actor + user = security_manager.find_user(username="admin") + mock_u_g.user = mock_c_g.user = mock_sm_g.user = user chart_data = { "slice_name": "new chart", "description": "new description", - "owners": [actor.id], + "owners": [user.id], "viz_type": "new_viz_type", "params": json.dumps({"viz_type": "new_viz_type"}), "cache_timeout": 1000, "datasource_id": 1, "datasource_type": "table", } - command = CreateChartCommand(actor, chart_data) + command = CreateChartCommand(chart_data) chart = command.run() chart = db.session.query(Slice).get(chart.id) assert chart.viz_type == "new_viz_type" json_params = json.loads(chart.params) assert json_params == {"viz_type": "new_viz_type"} assert chart.slice_name == "new chart" - assert chart.owners == [actor] + assert chart.owners == [user] db.session.delete(chart) db.session.commit() class TestChartsUpdateCommand(SupersetTestCase): - @patch("superset.views.base.g") + @patch("superset.charts.commands.update.g") + @patch("superset.utils.core.g") @patch("superset.security.manager.g") @pytest.mark.usefixtures("load_energy_table_with_slice") - def test_update_v1_response(self, mock_sm_g, mock_g): + def test_update_v1_response(self, mock_sm_g, mock_c_g, mock_u_g): """Test that a chart command updates properties""" pk = db.session.query(Slice).all()[0].id - actor = security_manager.find_user(username="admin") - mock_g.user = mock_sm_g.user = actor + user = security_manager.find_user(username="admin") + mock_u_g.user = mock_c_g.user = mock_sm_g.user = user model_id = pk json_obj = { "description": "test for update", "cache_timeout": None, - "owners": [actor.id], + "owners": [user.id], } - command = UpdateChartCommand(actor, model_id, json_obj) + command = UpdateChartCommand(model_id, json_obj) last_saved_before = db.session.query(Slice).get(pk).last_saved_at command.run() chart = db.session.query(Slice).get(pk) assert chart.last_saved_at != last_saved_before - assert chart.last_saved_by == actor + assert chart.last_saved_by == user - @patch("superset.views.base.g") + @patch("superset.utils.core.g") @patch("superset.security.manager.g") @pytest.mark.usefixtures("load_energy_table_with_slice") def test_query_context_update_command(self, mock_sm_g, mock_g): @@ -415,14 +382,14 @@ def test_query_context_update_command(self, mock_sm_g, mock_g): chart.owners = [admin] db.session.commit() - actor = security_manager.find_user(username="alpha") - mock_g.user = mock_sm_g.user = actor + user = security_manager.find_user(username="alpha") + mock_g.user = mock_sm_g.user = user query_context = json.dumps({"foo": "bar"}) json_obj = { "query_context_generation": True, "query_context": query_context, } - command = UpdateChartCommand(actor, pk, json_obj) + command = UpdateChartCommand(pk, json_obj) command.run() chart = db.session.query(Slice).get(pk) assert chart.query_context == query_context diff --git a/tests/integration_tests/charts/data/api_tests.py b/tests/integration_tests/charts/data/api_tests.py index d360b152be2a4..66151362ff1d4 100644 --- a/tests/integration_tests/charts/data/api_tests.py +++ b/tests/integration_tests/charts/data/api_tests.py @@ -185,7 +185,7 @@ def test_with_row_limit_bigger_then_sql_max_row__rowcount_as_sql_max_row(self): "superset.utils.core.current_app.config", {**app.config, "SQL_MAX_ROW": 5}, ) - def test_as_samples_with_row_limit_bigger_then_sql_max_row__rowcount_as_sql_max_row( + def test_as_samples_with_row_limit_bigger_then_sql_max_row_rowcount_as_sql_max_row( self, ): expected_row_count = app.config["SQL_MAX_ROW"] @@ -255,6 +255,16 @@ def test_empty_request_with_csv_result_format(self): rv = self.post_assert_metric(CHART_DATA_URI, self.query_context_payload, "data") assert rv.status_code == 400 + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + def test_empty_request_with_excel_result_format(self): + """ + Chart data API: Test empty chart data with Excel result format + """ + self.query_context_payload["result_format"] = "xlsx" + self.query_context_payload["queries"] = [] + rv = self.post_assert_metric(CHART_DATA_URI, self.query_context_payload, "data") + assert rv.status_code == 400 + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_with_csv_result_format(self): """ @@ -265,6 +275,17 @@ def test_with_csv_result_format(self): assert rv.status_code == 200 assert rv.mimetype == "text/csv" + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + def test_with_excel_result_format(self): + """ + Chart data API: Test chart data with Excel result format + """ + self.query_context_payload["result_format"] = "xlsx" + mimetype = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + rv = self.post_assert_metric(CHART_DATA_URI, self.query_context_payload, "data") + assert rv.status_code == 200 + assert rv.mimetype == mimetype + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_with_multi_query_csv_result_format(self): """ @@ -280,6 +301,21 @@ def test_with_multi_query_csv_result_format(self): zipfile = ZipFile(BytesIO(rv.data), "r") assert zipfile.namelist() == ["query_1.csv", "query_2.csv"] + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + def test_with_multi_query_excel_result_format(self): + """ + Chart data API: Test chart data with multi-query Excel result format + """ + self.query_context_payload["result_format"] = "xlsx" + self.query_context_payload["queries"].append( + self.query_context_payload["queries"][0] + ) + rv = self.post_assert_metric(CHART_DATA_URI, self.query_context_payload, "data") + assert rv.status_code == 200 + assert rv.mimetype == "application/zip" + zipfile = ZipFile(BytesIO(rv.data), "r") + assert zipfile.namelist() == ["query_1.xlsx", "query_2.xlsx"] + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_with_csv_result_format_when_actor_not_permitted_for_csv__403(self): """ @@ -292,6 +328,18 @@ def test_with_csv_result_format_when_actor_not_permitted_for_csv__403(self): rv = self.post_assert_metric(CHART_DATA_URI, self.query_context_payload, "data") assert rv.status_code == 403 + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + def test_with_excel_result_format_when_actor_not_permitted_for_excel__403(self): + """ + Chart data API: Test chart data with Excel result format + """ + self.logout() + self.login(username="gamma_no_csv") + self.query_context_payload["result_format"] = "xlsx" + + rv = self.post_assert_metric(CHART_DATA_URI, self.query_context_payload, "data") + assert rv.status_code == 403 + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_with_row_limit_and_offset__row_limit_and_offset_were_applied(self): """ @@ -339,12 +387,6 @@ def test_chart_data_applied_time_extras(self): {"column": "__time_range"}, ], ) - self.assertEqual( - data["result"][0]["rejected_filters"], - [ - {"column": "__time_origin", "reason": "not_druid_datasource"}, - ], - ) expected_row_count = self.get_expected_row_count("client_id_2") self.assertEqual(data["result"][0]["rowcount"], expected_row_count) @@ -457,7 +499,7 @@ def test_with_filter_suppose_to_return_empty_data__no_data_returned(self): def test_with_invalid_where_parameter__400(self): self.query_context_payload["queries"][0]["filters"] = [] - # erroneus WHERE-clause + # erroneous WHERE-clause self.query_context_payload["queries"][0]["extras"]["where"] = "(gender abc def)" rv = self.post_assert_metric(CHART_DATA_URI, self.query_context_payload, "data") @@ -843,7 +885,6 @@ def test_chart_data_get(self): "filters": [], "extras": { "having": "", - "having_druid": [], "where": "", }, "applied_time_extras": {}, @@ -869,6 +910,56 @@ def test_chart_data_get(self): assert data["result"][0]["status"] == "success" assert data["result"][0]["rowcount"] == 2 + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + def test_chart_data_get_forced(self): + """ + Chart data API: Test GET endpoint with force cache parameter + """ + chart = db.session.query(Slice).filter_by(slice_name="Genders").one() + chart.query_context = json.dumps( + { + "datasource": {"id": chart.table.id, "type": "table"}, + "force": False, + "queries": [ + { + "time_range": "1900-01-01T00:00:00 : 2000-01-01T00:00:00", + "granularity": "ds", + "filters": [], + "extras": { + "having": "", + "having_druid": [], + "where": "", + }, + "applied_time_extras": {}, + "columns": ["gender"], + "metrics": ["sum__num"], + "orderby": [["sum__num", False]], + "annotation_layers": [], + "row_limit": 50000, + "timeseries_limit": 0, + "order_desc": True, + "url_params": {}, + "custom_params": {}, + "custom_form_data": {}, + } + ], + "result_format": "json", + "result_type": "full", + } + ) + + self.get_assert_metric(f"api/v1/chart/{chart.id}/data/?force=true", "get_data") + + # should burst cache + rv = self.get_assert_metric( + f"api/v1/chart/{chart.id}/data/?force=true", "get_data" + ) + assert rv.json["result"][0]["is_cached"] is None + + # should get response from the cache + rv = self.get_assert_metric(f"api/v1/chart/{chart.id}/data/", "get_data") + assert rv.json["result"][0]["is_cached"] + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(GLOBAL_ASYNC_QUERIES=True) @mock.patch("superset.charts.data.api.QueryContextCacheLoader") diff --git a/tests/integration_tests/cli_tests.py b/tests/integration_tests/cli_tests.py index f69efc6253943..aaa682bee0f3e 100644 --- a/tests/integration_tests/cli_tests.py +++ b/tests/integration_tests/cli_tests.py @@ -27,7 +27,9 @@ from freezegun import freeze_time import superset.cli.importexport -from superset import app +import superset.cli.thumbnails +from superset import app, db +from superset.models.dashboard import Dashboard from tests.integration_tests.fixtures.birth_names_dashboard import ( load_birth_names_dashboard_with_slices, load_birth_names_data, @@ -495,3 +497,23 @@ def test_failing_import_datasets_versioned_export( ) assert_cli_fails_properly(response, caplog) + + +@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") +@mock.patch("superset.tasks.thumbnails.cache_dashboard_thumbnail") +def test_compute_thumbnails(thumbnail_mock, app_context, fs): + + thumbnail_mock.return_value = None + runner = app.test_cli_runner() + dashboard = db.session.query(Dashboard).filter_by(slug="births").first() + response = runner.invoke( + superset.cli.thumbnails.compute_thumbnails, + ["-d", "-i", dashboard.id], + ) + + thumbnail_mock.assert_called_with( + None, + dashboard.id, + force=False, + ) + assert response.exit_code == 0 diff --git a/tests/integration_tests/config_tests.py b/tests/integration_tests/config_tests.py deleted file mode 100644 index 45528913effad..0000000000000 --- a/tests/integration_tests/config_tests.py +++ /dev/null @@ -1,173 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# isort:skip_file - -import unittest -from typing import Any, Dict - -from tests.integration_tests.base_tests import SupersetTestCase -from tests.integration_tests.test_app import app - -from superset import db -from superset.connectors.sqla.models import SqlaTable -from superset.utils.database import get_or_create_db - -FULL_DTTM_DEFAULTS_EXAMPLE = { - "main_dttm_col": "id", - "dttm_columns": { - "dttm": { - "python_date_format": "epoch_s", - "expression": "CAST(dttm as INTEGER)", - }, - "id": {"python_date_format": "epoch_ms"}, - "month": { - "python_date_format": "%Y-%m-%d", - "expression": "CASE WHEN length(month) = 7 THEN month || '-01' ELSE month END", - }, - }, -} - - -def apply_dttm_defaults(table: SqlaTable, dttm_defaults: Dict[str, Any]): - """Applies dttm defaults to the table, mutates in place.""" - for dbcol in table.columns: - # Set is_dttm is column is listed in dttm_columns. - if dbcol.column_name in dttm_defaults.get("dttm_columns", {}): - dbcol.is_dttm = True - - # Skip non dttm columns. - if dbcol.column_name not in dttm_defaults.get("dttm_columns", {}): - continue - - # Set table main_dttm_col. - if dbcol.column_name == dttm_defaults.get("main_dttm_col"): - table.main_dttm_col = dbcol.column_name - - # Apply defaults if empty. - dttm_column_defaults = dttm_defaults.get("dttm_columns", {}).get( - dbcol.column_name, {} - ) - dbcol.is_dttm = True - if ( - not dbcol.python_date_format - and "python_date_format" in dttm_column_defaults - ): - dbcol.python_date_format = dttm_column_defaults["python_date_format"] - if not dbcol.expression and "expression" in dttm_column_defaults: - dbcol.expression = dttm_column_defaults["expression"] - - -class TestConfig(SupersetTestCase): - def setUp(self) -> None: - self.login(username="admin") - self._test_db_id = get_or_create_db( - "column_test_db", app.config["SQLALCHEMY_DATABASE_URI"] - ).id - self._old_sqla_table_mutator = app.config["SQLA_TABLE_MUTATOR"] - - def createTable(self, dttm_defaults): - app.config["SQLA_TABLE_MUTATOR"] = lambda t: apply_dttm_defaults( - t, dttm_defaults - ) - resp = self.client.post( - "/tablemodelview/add", - data=dict(database=self._test_db_id, table_name="logs"), - follow_redirects=True, - ) - self.assertEqual(resp.status_code, 200) - self._logs_table = ( - db.session.query(SqlaTable).filter_by(table_name="logs").one() - ) - - def tearDown(self): - app.config["SQLA_TABLE_MUTATOR"] = self._old_sqla_table_mutator - if hasattr(self, "_logs_table"): - db.session.delete(self._logs_table) - db.session.delete(self._logs_table.database) - db.session.commit() - - def test_main_dttm_col(self): - # Make sure that dttm column is set properly. - self.createTable({"main_dttm_col": "id", "dttm_columns": {"id": {}}}) - self.assertEqual(self._logs_table.main_dttm_col, "id") - - def test_main_dttm_col_nonexistent(self): - self.createTable({"main_dttm_col": "nonexistent"}) - # Column doesn't exist, falls back to dttm. - self.assertEqual(self._logs_table.main_dttm_col, "dttm") - - def test_main_dttm_col_nondttm(self): - self.createTable({"main_dttm_col": "duration_ms"}) - # duration_ms is not dttm column, falls back to dttm. - self.assertEqual(self._logs_table.main_dttm_col, "dttm") - - def test_python_date_format_by_column_name(self): - table_defaults = { - "dttm_columns": { - "id": {"python_date_format": "epoch_ms"}, - "dttm": {"python_date_format": "epoch_s"}, - "duration_ms": {"python_date_format": "invalid"}, - } - } - self.createTable(table_defaults) - id_col = [c for c in self._logs_table.columns if c.column_name == "id"][0] - self.assertTrue(id_col.is_dttm) - self.assertEqual(id_col.python_date_format, "epoch_ms") - dttm_col = [c for c in self._logs_table.columns if c.column_name == "dttm"][0] - self.assertTrue(dttm_col.is_dttm) - self.assertEqual(dttm_col.python_date_format, "epoch_s") - dms_col = [ - c for c in self._logs_table.columns if c.column_name == "duration_ms" - ][0] - self.assertTrue(dms_col.is_dttm) - self.assertEqual(dms_col.python_date_format, "invalid") - - def test_expression_by_column_name(self): - table_defaults = { - "dttm_columns": { - "dttm": {"expression": "CAST(dttm as INTEGER)"}, - "duration_ms": {"expression": "CAST(duration_ms as DOUBLE)"}, - } - } - self.createTable(table_defaults) - dttm_col = [c for c in self._logs_table.columns if c.column_name == "dttm"][0] - self.assertTrue(dttm_col.is_dttm) - self.assertEqual(dttm_col.expression, "CAST(dttm as INTEGER)") - dms_col = [ - c for c in self._logs_table.columns if c.column_name == "duration_ms" - ][0] - self.assertEqual(dms_col.expression, "CAST(duration_ms as DOUBLE)") - self.assertTrue(dms_col.is_dttm) - - def test_full_setting(self): - self.createTable(FULL_DTTM_DEFAULTS_EXAMPLE) - - self.assertEqual(self._logs_table.main_dttm_col, "id") - - id_col = [c for c in self._logs_table.columns if c.column_name == "id"][0] - self.assertTrue(id_col.is_dttm) - self.assertEqual(id_col.python_date_format, "epoch_ms") - self.assertIsNone(id_col.expression) - - dttm_col = [c for c in self._logs_table.columns if c.column_name == "dttm"][0] - self.assertTrue(dttm_col.is_dttm) - self.assertEqual(dttm_col.python_date_format, "epoch_s") - self.assertEqual(dttm_col.expression, "CAST(dttm as INTEGER)") - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py index 3e2744d2b1946..2cdfef984bf69 100644 --- a/tests/integration_tests/conftest.py +++ b/tests/integration_tests/conftest.py @@ -19,7 +19,7 @@ import contextlib import functools import os -from typing import Any, Callable, Optional, TYPE_CHECKING +from typing import Any, Callable, Dict, Optional, TYPE_CHECKING from unittest.mock import patch import pytest @@ -44,8 +44,75 @@ @pytest.fixture def app_context(): - with app.app_context(): - yield + with app.app_context() as ctx: + yield ctx + + +@pytest.fixture +def test_client(app_context: AppContext): + with app.test_client() as client: + yield client + + +@pytest.fixture +def login_as(test_client: "FlaskClient[Any]"): + """Fixture with app context and logged in admin user.""" + + def _login_as(username: str, password: str = "general"): + login(test_client, username=username, password=password) + + yield _login_as + # no need to log out as both app_context and test_client are + # function level fixtures anyway + + +@pytest.fixture +def login_as_admin(login_as: Callable[..., None]): + yield login_as("admin") + + +@pytest.fixture +def create_user(app_context: AppContext): + def _create_user(username: str, role: str = "Admin", password: str = "general"): + security_manager.add_user( + username, + "firstname", + "lastname", + "email@exaple.com", + security_manager.find_role(role), + password, + ) + return security_manager.find_user(username) + + return _create_user + + +@pytest.fixture +def get_user(app_context: AppContext): + def _get_user(username: str) -> ab_models.User: + return ( + db.session.query(security_manager.user_model) + .filter_by(username=username) + .one_or_none() + ) + + return _get_user + + +@pytest.fixture +def get_or_create_user(get_user, create_user) -> ab_models.User: + @contextlib.contextmanager + def _get_user(username: str) -> ab_models.User: + user = get_user(username) + if not user: + # if user is created by test, remove it after done + user = create_user(username) + yield user + db.session.delete(user) + else: + yield user + + return _get_user @pytest.fixture @@ -171,7 +238,7 @@ def __call__(self) -> Database: return self._db def _load_lazy_data_to_decouple_from_session(self) -> None: - self._db.get_sqla_engine() # type: ignore + self._db._get_sqla_engine() # type: ignore self._db.backend # type: ignore def remove(self) -> None: @@ -188,7 +255,11 @@ def remove(self) -> None: def setup_presto_if_needed(): - backend = app.config["SQLALCHEMY_EXAMPLES_URI"].split("://")[0] + db_uri = ( + app.config.get("SQLALCHEMY_EXAMPLES_URI") + or app.config["SQLALCHEMY_DATABASE_URI"] + ) + backend = db_uri.split("://")[0] database = get_example_database() extra = database.get_extra() @@ -208,14 +279,14 @@ def setup_presto_if_needed(): if backend in {"presto", "hive"}: database = get_example_database() - engine = database.get_sqla_engine() - drop_from_schema(engine, CTAS_SCHEMA_NAME) - engine.execute(f"DROP SCHEMA IF EXISTS {CTAS_SCHEMA_NAME}") - engine.execute(f"CREATE SCHEMA {CTAS_SCHEMA_NAME}") + with database.get_sqla_engine_with_context() as engine: + drop_from_schema(engine, CTAS_SCHEMA_NAME) + engine.execute(f"DROP SCHEMA IF EXISTS {CTAS_SCHEMA_NAME}") + engine.execute(f"CREATE SCHEMA {CTAS_SCHEMA_NAME}") - drop_from_schema(engine, ADMIN_SCHEMA_NAME) - engine.execute(f"DROP SCHEMA IF EXISTS {ADMIN_SCHEMA_NAME}") - engine.execute(f"CREATE SCHEMA {ADMIN_SCHEMA_NAME}") + drop_from_schema(engine, ADMIN_SCHEMA_NAME) + engine.execute(f"DROP SCHEMA IF EXISTS {ADMIN_SCHEMA_NAME}") + engine.execute(f"CREATE SCHEMA {ADMIN_SCHEMA_NAME}") def with_feature_flags(**mock_feature_flags): @@ -253,6 +324,83 @@ def wrapper(*args, **kwargs): return decorate +def with_config(override_config: Dict[str, Any]): + """ + Use this decorator to mock specific config keys. + + Usage: + + class TestYourFeature(SupersetTestCase): + + @with_config({"SOME_CONFIG": True}) + def test_your_config(self): + self.assertEqual(curren_app.config["SOME_CONFIG"), True) + + """ + + def decorate(test_fn): + config_backup = {} + + def wrapper(*args, **kwargs): + from flask import current_app + + for key, value in override_config.items(): + config_backup[key] = current_app.config[key] + current_app.config[key] = value + test_fn(*args, **kwargs) + for key, value in config_backup.items(): + current_app.config[key] = value + + return functools.update_wrapper(wrapper, test_fn) + + return decorate + + +@pytest.fixture +def virtual_dataset(): + from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn + + dataset = SqlaTable( + table_name="virtual_dataset", + sql=( + "SELECT 0 as col1, 'a' as col2, 1.0 as col3, NULL as col4, '2000-01-01 00:00:00' as col5 " + "UNION ALL " + "SELECT 1, 'b', 1.1, NULL, '2000-01-02 00:00:00' " + "UNION ALL " + "SELECT 2 as col1, 'c' as col2, 1.2, NULL, '2000-01-03 00:00:00' " + "UNION ALL " + "SELECT 3 as col1, 'd' as col2, 1.3, NULL, '2000-01-04 00:00:00' " + "UNION ALL " + "SELECT 4 as col1, 'e' as col2, 1.4, NULL, '2000-01-05 00:00:00' " + "UNION ALL " + "SELECT 5 as col1, 'f' as col2, 1.5, NULL, '2000-01-06 00:00:00' " + "UNION ALL " + "SELECT 6 as col1, 'g' as col2, 1.6, NULL, '2000-01-07 00:00:00' " + "UNION ALL " + "SELECT 7 as col1, 'h' as col2, 1.7, NULL, '2000-01-08 00:00:00' " + "UNION ALL " + "SELECT 8 as col1, 'i' as col2, 1.8, NULL, '2000-01-09 00:00:00' " + "UNION ALL " + "SELECT 9 as col1, 'j' as col2, 1.9, NULL, '2000-01-10 00:00:00' " + ), + database=get_example_database(), + ) + TableColumn(column_name="col1", type="INTEGER", table=dataset) + TableColumn(column_name="col2", type="VARCHAR(255)", table=dataset) + TableColumn(column_name="col3", type="DECIMAL(4,2)", table=dataset) + TableColumn(column_name="col4", type="VARCHAR(255)", table=dataset) + # Different database dialect datetime type is not consistent, so temporarily use varchar + TableColumn(column_name="col5", type="VARCHAR(255)", table=dataset) + + SqlMetric(metric_name="count", expression="count(*)", table=dataset) + db.session.merge(dataset) + + yield dataset + + db.session.delete(dataset) + db.session.commit() + + @pytest.fixture def physical_dataset(): from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn @@ -323,3 +471,46 @@ def physical_dataset(): for ds in dataset: db.session.delete(ds) db.session.commit() + + +@pytest.fixture +def virtual_dataset_comma_in_column_value(): + from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn + + dataset = SqlaTable( + table_name="virtual_dataset", + sql=( + "SELECT 'col1,row1' as col1, 'col2, row1' as col2 " + "UNION ALL " + "SELECT 'col1,row2' as col1, 'col2, row2' as col2 " + "UNION ALL " + "SELECT 'col1,row3' as col1, 'col2, row3' as col2 " + ), + database=get_example_database(), + ) + TableColumn(column_name="col1", type="VARCHAR(255)", table=dataset) + TableColumn(column_name="col2", type="VARCHAR(255)", table=dataset) + + SqlMetric(metric_name="count", expression="count(*)", table=dataset) + db.session.merge(dataset) + + yield dataset + + db.session.delete(dataset) + db.session.commit() + + +only_postgresql = pytest.mark.skipif( + "postgresql" not in os.environ.get("SUPERSET__SQLALCHEMY_DATABASE_URI", ""), + reason="Only run test case in Postgresql", +) + +only_sqlite = pytest.mark.skipif( + "sqlite" not in os.environ.get("SUPERSET__SQLALCHEMY_DATABASE_URI", ""), + reason="Only run test case in SQLite", +) + +only_mysql = pytest.mark.skipif( + "mysql" not in os.environ.get("SUPERSET__SQLALCHEMY_DATABASE_URI", ""), + reason="Only run test case in MySQL", +) diff --git a/tests/integration_tests/core_tests.py b/tests/integration_tests/core_tests.py index f0d79253345c5..f036f18bf6aa3 100644 --- a/tests/integration_tests/core_tests.py +++ b/tests/integration_tests/core_tests.py @@ -27,10 +27,12 @@ from urllib.parse import quote import superset.utils.database +from superset.utils.core import backend from tests.integration_tests.fixtures.birth_names_dashboard import ( load_birth_names_dashboard_with_slices, load_birth_names_data, ) +from sqlalchemy import Table import pytest import pytz @@ -62,7 +64,7 @@ from superset.db_engine_specs.base import BaseEngineSpec from superset.db_engine_specs.mssql import MssqlEngineSpec from superset.exceptions import SupersetException -from superset.extensions import async_query_manager +from superset.extensions import async_query_manager, cache_manager from superset.models import core as models from superset.models.annotations import Annotation, AnnotationLayer from superset.models.dashboard import Dashboard @@ -79,15 +81,22 @@ load_world_bank_dashboard_with_slices, load_world_bank_data, ) +from tests.integration_tests.conftest import CTAS_SCHEMA_NAME logger = logging.getLogger(__name__) +@pytest.fixture(scope="module") +def cleanup(): + db.session.query(Query).delete() + db.session.query(DatasourceAccessRequest).delete() + db.session.query(models.Log).delete() + db.session.commit() + yield + + class TestCore(SupersetTestCase): def setUp(self): - db.session.query(Query).delete() - db.session.query(DatasourceAccessRequest).delete() - db.session.query(models.Log).delete() self.table_ids = { tbl.table_name: tbl.id for tbl in (db.session.query(SqlaTable).all()) } @@ -117,15 +126,6 @@ def test_dashboard_endpoint(self): @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_slice_endpoint(self): self.login(username="admin") - slc = self.get_slice("Girls", db.session) - resp = self.get_resp("/superset/slice/{}/".format(slc.id)) - assert "Original value" in resp - assert "List Roles" in resp - - # Testing overrides - resp = self.get_resp("/superset/slice/{}/?standalone=true".format(slc.id)) - assert '<div class="navbar' not in resp - resp = self.client.get("/superset/slice/-1/") assert resp.status_code == 404 @@ -159,7 +159,7 @@ def test_get_superset_tables_not_allowed(self): example_db = superset.utils.database.get_example_database() schema_name = self.default_schema_backend_map[example_db.backend] self.login(username="gamma") - uri = f"superset/tables/{example_db.id}/{schema_name}/undefined/" + uri = f"superset/tables/{example_db.id}/{schema_name}/" rv = self.client.get(uri) self.assertEqual(rv.status_code, 404) @@ -188,7 +188,7 @@ def test_get_superset_tables_allowed(self): example_db = utils.get_example_database() schema_name = self.default_schema_backend_map[example_db.backend] - uri = f"superset/tables/{example_db.id}/{schema_name}/{table_name}/" + uri = f"superset/tables/{example_db.id}/{schema_name}/" rv = self.client.get(uri) self.assertEqual(rv.status_code, 200) @@ -200,7 +200,6 @@ def test_get_superset_tables_allowed(self): @pytest.mark.usefixtures("load_energy_table_with_slice") def test_get_superset_tables_not_allowed_with_out_permissions(self): session = db.session - table_name = "energy_usage" role_name = "dummy_role_no_table_access" self.logout() self.login(username="gamma") @@ -213,7 +212,7 @@ def test_get_superset_tables_not_allowed_with_out_permissions(self): example_db = utils.get_example_database() schema_name = self.default_schema_backend_map[example_db.backend] - uri = f"superset/tables/{example_db.id}/{schema_name}/{table_name}/" + uri = f"superset/tables/{example_db.id}/{schema_name}/" rv = self.client.get(uri) self.assertEqual(rv.status_code, 404) @@ -222,73 +221,18 @@ def test_get_superset_tables_not_allowed_with_out_permissions(self): gamma_user.roles.remove(security_manager.find_role(role_name)) session.commit() - def test_get_superset_tables_substr(self): - example_db = superset.utils.database.get_example_database() - if example_db.backend in {"presto", "hive"}: - # TODO: change table to the real table that is in examples. - return - self.login(username="admin") - schema_name = self.default_schema_backend_map[example_db.backend] - uri = f"superset/tables/{example_db.id}/{schema_name}/ab_role/" - rv = self.client.get(uri) - response = json.loads(rv.data.decode("utf-8")) - self.assertEqual(rv.status_code, 200) - - expected_response = { - "options": [ - { - "label": "ab_role", - "schema": schema_name, - "title": "ab_role", - "type": "table", - "value": "ab_role", - "extra": None, - } - ], - "tableLength": 1, - } - self.assertEqual(response, expected_response) - - def test_get_superset_tables_not_found(self): + def test_get_superset_tables_database_not_found(self): self.login(username="admin") - uri = f"superset/tables/invalid/public/undefined/" + uri = f"superset/tables/invalid/public/" rv = self.client.get(uri) self.assertEqual(rv.status_code, 404) - def test_annotation_json_endpoint(self): - # Set up an annotation layer and annotation - layer = AnnotationLayer(name="foo", descr="bar") - db.session.add(layer) - db.session.commit() - - annotation = Annotation( - layer_id=layer.id, - short_descr="my_annotation", - start_dttm=datetime.datetime(2020, 5, 20, 18, 21, 51), - end_dttm=datetime.datetime(2020, 5, 20, 18, 31, 51), - ) - - db.session.add(annotation) - db.session.commit() - - self.login() - resp_annotations = json.loads( - self.get_resp("annotationlayermodelview/api/read") - ) - # the UI needs id and name to function - self.assertIn("id", resp_annotations["result"][0]) - self.assertIn("name", resp_annotations["result"][0]) - - response = self.get_resp( - f"/superset/annotation_json/{layer.id}?form_data=" - + quote(json.dumps({"time_range": "100 years ago : now"})) - ) - assert "my_annotation" in response - - # Rollback changes - db.session.delete(annotation) - db.session.delete(layer) - db.session.commit() + def test_get_superset_tables_schema_undefined(self): + example_db = superset.utils.database.get_example_database() + self.login(username="gamma") + uri = f"superset/tables/{example_db.id}/undefined/" + rv = self.client.get(uri) + self.assertEqual(rv.status_code, 422) def test_admin_only_permissions(self): def assert_admin_permission_in(role_name, assert_func): @@ -381,21 +325,13 @@ def test_save_slice(self): @pytest.mark.usefixtures("load_energy_table_with_slice") def test_filter_endpoint(self): self.login(username="admin") - slice_name = "Energy Sankey" - slice_id = self.get_slice(slice_name, db.session).id - db.session.commit() tbl_id = self.table_ids.get("energy_usage") table = db.session.query(SqlaTable).filter(SqlaTable.id == tbl_id) table.filter_select_enabled = True - url = ( - "/superset/filter/table/{}/target/?viz_type=sankey&groupby=source" - "&metric=sum__value&flt_col_0=source&flt_op_0=in&flt_eq_0=&" - "slice_id={}&datasource_name=energy_usage&" - "datasource_id=1&datasource_type=table" - ) + url = "/superset/filter/table/{}/target/" # Changing name - resp = self.get_resp(url.format(tbl_id, slice_id)) + resp = self.get_resp(url.format(tbl_id)) assert len(resp) > 0 assert "energy_target0" in resp @@ -481,7 +417,7 @@ def test_get_user_slices(self): @pytest.mark.usefixtures("load_energy_table_with_slice") def test_slices_V2(self): # Add explore-v2-beta role to admin user - # Test all slice urls as user with with explore-v2-beta role + # Test all slice urls as user with explore-v2-beta role security_manager.add_role("explore-v2-beta") security_manager.add_user( @@ -685,7 +621,7 @@ def test_redirect_invalid(self): self.login(username="admin") response = self.client.get(f"/r/{model_url.id}") - assert response.headers["Location"] == "http://localhost/" + assert response.headers["Location"] == "/" db.session.delete(model_url) db.session.commit() @@ -766,6 +702,52 @@ def test_extra_table_metadata(self): f"/superset/extra_table_metadata/{example_db.id}/birth_names/{schema}/" ) + def test_required_params_in_sql_json(self): + self.login() + client_id = "{}".format(random.getrandbits(64))[:10] + + data = {"client_id": client_id} + rv = self.client.post( + "/superset/sql_json/", + json=data, + ) + failed_resp = { + "sql": ["Missing data for required field."], + "database_id": ["Missing data for required field."], + } + resp_data = json.loads(rv.data.decode("utf-8")) + self.assertDictEqual(resp_data, failed_resp) + self.assertEqual(rv.status_code, 400) + + data = {"sql": "SELECT 1", "client_id": client_id} + rv = self.client.post( + "/superset/sql_json/", + json=data, + ) + failed_resp = {"database_id": ["Missing data for required field."]} + resp_data = json.loads(rv.data.decode("utf-8")) + self.assertDictEqual(resp_data, failed_resp) + self.assertEqual(rv.status_code, 400) + + data = {"database_id": 1, "client_id": client_id} + rv = self.client.post( + "/superset/sql_json/", + json=data, + ) + failed_resp = {"sql": ["Missing data for required field."]} + resp_data = json.loads(rv.data.decode("utf-8")) + self.assertDictEqual(resp_data, failed_resp) + self.assertEqual(rv.status_code, 400) + + data = {"sql": "SELECT 1", "database_id": 1, "client_id": client_id} + rv = self.client.post( + "/superset/sql_json/", + json=data, + ) + resp_data = json.loads(rv.data.decode("utf-8")) + self.assertEqual(resp_data.get("status"), "success") + self.assertEqual(rv.status_code, 200) + def test_templated_sql_json(self): if superset.utils.database.get_example_database().backend == "presto": # TODO: make it work for presto @@ -887,11 +869,11 @@ def test_user_activity_access(self, username="gamma"): @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_slice_id_is_always_logged_correctly_on_web_request(self): - # superset/explore case + # explore case self.login("admin") slc = db.session.query(Slice).filter_by(slice_name="Girls").one() qry = db.session.query(models.Log).filter_by(slice_id=slc.id) - self.get_resp(slc.slice_url, {"form_data": json.dumps(slc.form_data)}) + self.get_resp(slc.slice_url) self.assertEqual(1, qry.count()) def create_sample_csvfile(self, filename: str, content: List[str]) -> None: @@ -1412,6 +1394,8 @@ def test_feature_flag_serialization(self): """ Functions in feature flags don't break bootstrap data serialization. """ + # feature flags are cached + cache_manager.cache.clear() self.login() encoded = json.dumps( @@ -1430,7 +1414,7 @@ def test_feature_flag_serialization(self): "/superset/welcome", f"/superset/dashboard/{dash_id}/", "/superset/profile/admin/", - f"/superset/explore/table/{tbl_id}", + f"/explore/?datasource_type=table&datasource_id={tbl_id}", ] for url in urls: data = self.get_resp(url) @@ -1483,6 +1467,38 @@ def test_sqllab_backend_persistence_payload(self): payload = views.Superset._get_sqllab_tabs(user_id=user_id) self.assertEqual(len(payload["queries"]), 1) + @mock.patch.dict( + "superset.extensions.feature_flag_manager._feature_flags", + {"SQLLAB_BACKEND_PERSISTENCE": True}, + clear=True, + ) + def test_tabstate_with_name(self): + """ + The tabstateview endpoint GET should be able to take name or title + for backward compatibility + """ + username = "admin" + self.login(username) + + # create a tab + data = { + "queryEditor": json.dumps( + { + "name": "Untitled Query foo", + "dbId": 1, + "schema": None, + "autorun": False, + "sql": "SELECT ...", + "queryLimit": 1000, + } + ) + } + resp = self.get_json_resp("/tabstateview/", data=data) + tab_state_id = resp["id"] + payload = self.get_json_resp(f"/tabstateview/{tab_state_id}") + + self.assertEqual(payload["label"], "Untitled Query foo") + def test_virtual_table_explore_visibility(self): # test that default visibility it set to True database = superset.utils.database.get_example_database() @@ -1572,7 +1588,7 @@ def test_explore_injected_exceptions(self, mock_db_connection_mutator): exception = SupersetException("Error message") mock_db_connection_mutator.side_effect = exception slice = db.session.query(Slice).first() - url = f"/superset/explore/?form_data=%7B%22slice_id%22%3A%20{slice.id}%7D" + url = f"/explore/?form_data=%7B%22slice_id%22%3A%20{slice.id}%7D" self.login() data = self.get_resp(url) @@ -1582,7 +1598,7 @@ def test_explore_injected_exceptions(self, mock_db_connection_mutator): exception = SQLAlchemyError("Error message") mock_db_connection_mutator.side_effect = exception slice = db.session.query(Slice).first() - url = f"/superset/explore/?form_data=%7B%22slice_id%22%3A%20{slice.id}%7D" + url = f"/explore/?form_data=%7B%22slice_id%22%3A%20{slice.id}%7D" self.login() data = self.get_resp(url) @@ -1595,7 +1611,7 @@ def test_dashboard_injected_exceptions(self, mock_db_connection_mutator): Handle injected exceptions from the db mutator """ - # Assert we can handle a custom excetion at the mutator level + # Assert we can handle a custom exception at the mutator level exception = SupersetException("Error message") mock_db_connection_mutator.side_effect = exception dash = db.session.query(Dashboard).first() @@ -1638,6 +1654,32 @@ def test_stop_query_not_implemented( assert rv.status_code == 422 + @pytest.mark.usefixtures("load_energy_table_with_slice") + @mock.patch("superset.explore.form_data.commands.create.CreateFormDataCommand.run") + def test_explore_redirect(self, mock_command: mock.Mock): + self.login(username="admin") + random_key = "random_key" + mock_command.return_value = random_key + slice_name = f"Energy Sankey" + slice_id = self.get_slice(slice_name, db.session).id + form_data = {"slice_id": slice_id, "viz_type": "line", "datasource": "1__table"} + rv = self.client.get( + f"/superset/explore/?form_data={quote(json.dumps(form_data))}" + ) + self.assertEqual( + rv.headers["Location"], f"/explore/?form_data_key={random_key}" + ) + + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + def test_has_table_by_name(self): + if backend() in ("sqlite", "mysql"): + return + example_db = superset.utils.database.get_example_database() + assert ( + example_db.has_table_by_name(table_name="birth_names", schema="public") + is True + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/integration_tests/csv_upload_tests.py b/tests/integration_tests/csv_upload_tests.py index c9bc11db98557..3e0200d18a26b 100644 --- a/tests/integration_tests/csv_upload_tests.py +++ b/tests/integration_tests/csv_upload_tests.py @@ -29,13 +29,13 @@ import superset.utils.database from superset.sql_parse import Table -from superset import security_manager from tests.integration_tests.conftest import ADMIN_SCHEMA_NAME -from tests.integration_tests.test_app import app # isort:skip from superset import db +from superset import security_manager from superset.models.core import Database from superset.utils import core as utils -from tests.integration_tests.base_tests import get_resp, login, SupersetTestCase +from tests.integration_tests.test_app import app, login +from tests.integration_tests.base_tests import get_resp, SupersetTestCase logger = logging.getLogger(__name__) @@ -58,31 +58,39 @@ CSV_UPLOAD_TABLE_W_EXPLORE = "csv_upload_w_explore" -@pytest.fixture(scope="module") -def setup_csv_upload(): - with app.app_context(): - login(test_client, username="admin") - - upload_db = superset.utils.database.get_or_create_db( - CSV_UPLOAD_DATABASE, app.config["SQLALCHEMY_EXAMPLES_URI"] - ) - extra = upload_db.get_extra() - extra["explore_database_id"] = superset.utils.database.get_example_database().id - upload_db.extra = json.dumps(extra) - upload_db.allow_file_upload = True - db.session.commit() +def _setup_csv_upload(): + upload_db = superset.utils.database.get_or_create_db( + CSV_UPLOAD_DATABASE, app.config["SQLALCHEMY_EXAMPLES_URI"] + ) + extra = upload_db.get_extra() + extra["explore_database_id"] = superset.utils.database.get_example_database().id + upload_db.extra = json.dumps(extra) + upload_db.allow_file_upload = True + db.session.commit() - yield + yield - upload_db = get_upload_db() - engine = upload_db.get_sqla_engine() + upload_db = get_upload_db() + with upload_db.get_sqla_engine_with_context() as engine: engine.execute(f"DROP TABLE IF EXISTS {EXCEL_UPLOAD_TABLE}") engine.execute(f"DROP TABLE IF EXISTS {CSV_UPLOAD_TABLE}") engine.execute(f"DROP TABLE IF EXISTS {PARQUET_UPLOAD_TABLE}") engine.execute(f"DROP TABLE IF EXISTS {CSV_UPLOAD_TABLE_W_SCHEMA}") engine.execute(f"DROP TABLE IF EXISTS {CSV_UPLOAD_TABLE_W_EXPLORE}") - db.session.delete(upload_db) - db.session.commit() + db.session.delete(upload_db) + db.session.commit() + + +@pytest.fixture(scope="module") +def setup_csv_upload(login_as_admin): + yield from _setup_csv_upload() + + +@pytest.fixture(scope="module") +def setup_csv_upload_with_context(): + with app.app_context(): + login(test_client, username="admin") + yield from _setup_csv_upload() @pytest.fixture(scope="module") @@ -126,12 +134,12 @@ def upload_csv(filename: str, table_name: str, extra: Optional[Dict[str, str]] = schema = utils.get_example_default_schema() form_data = { "csv_file": open(filename, "rb"), - "sep": ",", - "name": table_name, - "con": csv_upload_db_id, + "delimiter": ",", + "table_name": table_name, + "database": csv_upload_db_id, "if_exists": "fail", "index_label": "test_label", - "mangle_dupe_cols": False, + "overwrite_duplicate": False, } if schema: form_data["schema"] = schema @@ -148,7 +156,7 @@ def upload_excel( form_data = { "excel_file": open(filename, "rb"), "name": table_name, - "con": excel_upload_db_id, + "database": excel_upload_db_id, "sheet_name": "Sheet1", "if_exists": "fail", "index_label": "test_label", @@ -169,7 +177,7 @@ def upload_columnar( form_data = { "columnar_file": open(filename, "rb"), "name": table_name, - "con": columnar_upload_db_id, + "database": columnar_upload_db_id, "if_exists": "fail", "index_label": "test_label", } @@ -201,5 +209,308 @@ def mock_upload_to_s3(filename: str, upload_prefix: str, table: Table) -> str: container.exec_run(f"hdfs dfs -mkdir -p {dest_dir}") dest = os.path.join(dest_dir, os.path.basename(filename)) container.exec_run(f"hdfs dfs -put {src} {dest}") - # hive external table expectes a directory for the location + # hive external table expects a directory for the location return dest_dir + + +def escaped_double_quotes(text): + return f"\"{text}\"" + + +def escaped_parquet(text): + return escaped_double_quotes(f"['{text}']") + + +@pytest.mark.usefixtures("setup_csv_upload_with_context") +@pytest.mark.usefixtures("create_csv_files") +@mock.patch( + "superset.models.core.config", + {**app.config, "ALLOWED_USER_CSV_SCHEMA_FUNC": lambda d, u: ["admin_database"]}, +) +@mock.patch("superset.db_engine_specs.hive.upload_to_s3", mock_upload_to_s3) +@mock.patch("superset.views.database.views.event_logger.log_with_context") +def test_import_csv_enforced_schema(mock_event_logger): + if utils.backend() == "sqlite": + pytest.skip("Sqlite doesn't support schema / database creation") + + full_table_name = f"admin_database.{CSV_UPLOAD_TABLE_W_SCHEMA}" + + # Invalid table name + resp = upload_csv(CSV_FILENAME1, full_table_name) + assert "Table name cannot contain a schema" in resp + + # no schema specified, fail upload + resp = upload_csv(CSV_FILENAME1, CSV_UPLOAD_TABLE_W_SCHEMA, extra={"schema": None}) + assert ( + f"Database {escaped_double_quotes(CSV_UPLOAD_DATABASE)} schema" + f" {escaped_double_quotes('None')} is not allowed for csv uploads" in resp + ) + + success_msg = f"CSV file {escaped_double_quotes(CSV_FILENAME1)} uploaded to table {escaped_double_quotes(full_table_name)}" + + resp = upload_csv( + CSV_FILENAME1, + CSV_UPLOAD_TABLE_W_SCHEMA, + extra={"schema": "admin_database", "if_exists": "replace"}, + ) + + assert success_msg in resp + mock_event_logger.assert_called_with( + action="successful_csv_upload", + database=get_upload_db().name, + schema="admin_database", + table=CSV_UPLOAD_TABLE_W_SCHEMA, + ) + + with get_upload_db().get_sqla_engine_with_context() as engine: + data = engine.execute( + f"SELECT * from {ADMIN_SCHEMA_NAME}.{CSV_UPLOAD_TABLE_W_SCHEMA}" + ).fetchall() + assert data == [("john", 1), ("paul", 2)] + + # user specified schema doesn't match, fail + resp = upload_csv( + CSV_FILENAME1, CSV_UPLOAD_TABLE_W_SCHEMA, extra={"schema": "gold"} + ) + assert ( + f'Database {escaped_double_quotes(CSV_UPLOAD_DATABASE)} schema {escaped_double_quotes("gold")} is not allowed for csv uploads' + in resp + ) + + # user specified schema matches the expected schema, append + if utils.backend() == "hive": + pytest.skip("Hive database doesn't support append csv uploads.") + resp = upload_csv( + CSV_FILENAME1, + CSV_UPLOAD_TABLE_W_SCHEMA, + extra={"schema": "admin_database", "if_exists": "append"}, + ) + assert success_msg in resp + + # Clean up + with get_upload_db().get_sqla_engine_with_context() as engine: + engine.execute(f"DROP TABLE {full_table_name}") + + +@mock.patch("superset.db_engine_specs.hive.upload_to_s3", mock_upload_to_s3) +def test_import_csv_explore_database(setup_csv_upload_with_context, create_csv_files): + schema = utils.get_example_default_schema() + full_table_name = ( + f"{schema}.{CSV_UPLOAD_TABLE_W_EXPLORE}" + if schema + else CSV_UPLOAD_TABLE_W_EXPLORE + ) + + if utils.backend() == "sqlite": + pytest.skip("Sqlite doesn't support schema / database creation") + + resp = upload_csv(CSV_FILENAME1, CSV_UPLOAD_TABLE_W_EXPLORE) + assert ( + f"CSV file {escaped_double_quotes(CSV_FILENAME1)} uploaded to table {escaped_double_quotes(full_table_name)}" + in resp + ) + table = SupersetTestCase.get_table(name=CSV_UPLOAD_TABLE_W_EXPLORE) + assert table.database_id == superset.utils.database.get_example_database().id + + +@pytest.mark.usefixtures("setup_csv_upload_with_context") +@pytest.mark.usefixtures("create_csv_files") +@mock.patch("superset.db_engine_specs.hive.upload_to_s3", mock_upload_to_s3) +@mock.patch("superset.views.database.views.event_logger.log_with_context") +def test_import_csv(mock_event_logger): + schema = utils.get_example_default_schema() + full_table_name = f"{schema}.{CSV_UPLOAD_TABLE}" if schema else CSV_UPLOAD_TABLE + success_msg_f1 = f"CSV file {escaped_double_quotes(CSV_FILENAME1)} uploaded to table {escaped_double_quotes(full_table_name)}" + + test_db = get_upload_db() + + # initial upload with fail mode + resp = upload_csv(CSV_FILENAME1, CSV_UPLOAD_TABLE) + assert success_msg_f1 in resp + + # upload again with fail mode; should fail + fail_msg = f"Unable to upload CSV file {escaped_double_quotes(CSV_FILENAME1)} to table {escaped_double_quotes(CSV_UPLOAD_TABLE)}" + resp = upload_csv(CSV_FILENAME1, CSV_UPLOAD_TABLE) + assert fail_msg in resp + + if utils.backend() != "hive": + # upload again with append mode + resp = upload_csv( + CSV_FILENAME1, CSV_UPLOAD_TABLE, extra={"if_exists": "append"} + ) + assert success_msg_f1 in resp + mock_event_logger.assert_called_with( + action="successful_csv_upload", + database=test_db.name, + schema=schema, + table=CSV_UPLOAD_TABLE, + ) + + # upload again with replace mode + resp = upload_csv(CSV_FILENAME1, CSV_UPLOAD_TABLE, extra={"if_exists": "replace"}) + assert success_msg_f1 in resp + + # try to append to table from file with different schema + resp = upload_csv(CSV_FILENAME2, CSV_UPLOAD_TABLE, extra={"if_exists": "append"}) + fail_msg_f2 = f"Unable to upload CSV file {escaped_double_quotes(CSV_FILENAME2)} to table {escaped_double_quotes(CSV_UPLOAD_TABLE)}" + assert fail_msg_f2 in resp + + # replace table from file with different schema + resp = upload_csv(CSV_FILENAME2, CSV_UPLOAD_TABLE, extra={"if_exists": "replace"}) + success_msg_f2 = f"CSV file {escaped_double_quotes(CSV_FILENAME2)} uploaded to table {escaped_double_quotes(full_table_name)}" + assert success_msg_f2 in resp + + table = SupersetTestCase.get_table(name=CSV_UPLOAD_TABLE) + # make sure the new column name is reflected in the table metadata + assert "d" in table.column_names + + # ensure user is assigned as an owner + assert security_manager.find_user("admin") in table.owners + + # null values are set + upload_csv( + CSV_FILENAME2, + CSV_UPLOAD_TABLE, + extra={"null_values": '["", "john"]', "if_exists": "replace"}, + ) + # make sure that john and empty string are replaced with None + with test_db.get_sqla_engine_with_context() as engine: + data = engine.execute(f"SELECT * from {CSV_UPLOAD_TABLE}").fetchall() + assert data == [(None, 1, "x"), ("paul", 2, None)] + # default null values + upload_csv(CSV_FILENAME2, CSV_UPLOAD_TABLE, extra={"if_exists": "replace"}) + # make sure that john and empty string are replaced with None + data = engine.execute(f"SELECT * from {CSV_UPLOAD_TABLE}").fetchall() + assert data == [("john", 1, "x"), ("paul", 2, None)] + + +@pytest.mark.usefixtures("setup_csv_upload_with_context") +@pytest.mark.usefixtures("create_excel_files") +@mock.patch("superset.db_engine_specs.hive.upload_to_s3", mock_upload_to_s3) +@mock.patch("superset.views.database.views.event_logger.log_with_context") +def test_import_excel(mock_event_logger): + if utils.backend() == "hive": + pytest.skip("Hive doesn't excel upload.") + + schema = utils.get_example_default_schema() + full_table_name = f"{schema}.{EXCEL_UPLOAD_TABLE}" if schema else EXCEL_UPLOAD_TABLE + test_db = get_upload_db() + + success_msg = f"Excel file {escaped_double_quotes(EXCEL_FILENAME)} uploaded to table {escaped_double_quotes(full_table_name)}" + + # initial upload with fail mode + resp = upload_excel(EXCEL_FILENAME, EXCEL_UPLOAD_TABLE) + assert success_msg in resp + mock_event_logger.assert_called_with( + action="successful_excel_upload", + database=test_db.name, + schema=schema, + table=EXCEL_UPLOAD_TABLE, + ) + + # ensure user is assigned as an owner + table = SupersetTestCase.get_table(name=EXCEL_UPLOAD_TABLE) + assert security_manager.find_user("admin") in table.owners + + # upload again with fail mode; should fail + fail_msg = f"Unable to upload Excel file {escaped_double_quotes(EXCEL_FILENAME)} to table {escaped_double_quotes(EXCEL_UPLOAD_TABLE)}" + resp = upload_excel(EXCEL_FILENAME, EXCEL_UPLOAD_TABLE) + assert fail_msg in resp + + if utils.backend() != "hive": + # upload again with append mode + resp = upload_excel( + EXCEL_FILENAME, EXCEL_UPLOAD_TABLE, extra={"if_exists": "append"} + ) + assert success_msg in resp + + # upload again with replace mode + resp = upload_excel( + EXCEL_FILENAME, EXCEL_UPLOAD_TABLE, extra={"if_exists": "replace"} + ) + assert success_msg in resp + mock_event_logger.assert_called_with( + action="successful_excel_upload", + database=test_db.name, + schema=schema, + table=EXCEL_UPLOAD_TABLE, + ) + + with test_db.get_sqla_engine_with_context() as engine: + data = engine.execute(f"SELECT * from {EXCEL_UPLOAD_TABLE}").fetchall() + assert data == [(0, "john", 1), (1, "paul", 2)] + + +@pytest.mark.usefixtures("setup_csv_upload_with_context") +@pytest.mark.usefixtures("create_columnar_files") +@mock.patch("superset.db_engine_specs.hive.upload_to_s3", mock_upload_to_s3) +@mock.patch("superset.views.database.views.event_logger.log_with_context") +def test_import_parquet(mock_event_logger): + if utils.backend() == "hive": + pytest.skip("Hive doesn't allow parquet upload.") + + schema = utils.get_example_default_schema() + full_table_name = ( + f"{schema}.{PARQUET_UPLOAD_TABLE}" if schema else PARQUET_UPLOAD_TABLE + ) + test_db = get_upload_db() + + success_msg_f1 = f"Columnar file {escaped_parquet(PARQUET_FILENAME1)} uploaded to table {escaped_double_quotes(full_table_name)}" + + # initial upload with fail mode + resp = upload_columnar(PARQUET_FILENAME1, PARQUET_UPLOAD_TABLE) + assert success_msg_f1 in resp + + # upload again with fail mode; should fail + fail_msg = f"Unable to upload Columnar file {escaped_parquet(PARQUET_FILENAME1)} to table {escaped_double_quotes(PARQUET_UPLOAD_TABLE)}" + resp = upload_columnar(PARQUET_FILENAME1, PARQUET_UPLOAD_TABLE) + assert fail_msg in resp + + if utils.backend() != "hive": + # upload again with append mode + resp = upload_columnar( + PARQUET_FILENAME1, PARQUET_UPLOAD_TABLE, extra={"if_exists": "append"} + ) + assert success_msg_f1 in resp + mock_event_logger.assert_called_with( + action="successful_columnar_upload", + database=test_db.name, + schema=schema, + table=PARQUET_UPLOAD_TABLE, + ) + + # upload again with replace mode and specific columns + resp = upload_columnar( + PARQUET_FILENAME1, + PARQUET_UPLOAD_TABLE, + extra={"if_exists": "replace", "usecols": '["a"]'}, + ) + assert success_msg_f1 in resp + + table = SupersetTestCase.get_table(name=PARQUET_UPLOAD_TABLE, schema=None) + # make sure only specified column name was read + assert "b" not in table.column_names + + # ensure user is assigned as an owner + assert security_manager.find_user("admin") in table.owners + + # upload again with replace mode + resp = upload_columnar( + PARQUET_FILENAME1, PARQUET_UPLOAD_TABLE, extra={"if_exists": "replace"} + ) + assert success_msg_f1 in resp + + with test_db.get_sqla_engine_with_context() as engine: + data = engine.execute(f"SELECT * from {PARQUET_UPLOAD_TABLE}").fetchall() + assert data == [("john", 1), ("paul", 2)] + + # replace table with zip file + resp = upload_columnar( + ZIP_FILENAME, PARQUET_UPLOAD_TABLE, extra={"if_exists": "replace"} + ) + success_msg_f2 = f"Columnar file {escaped_parquet(ZIP_FILENAME)} uploaded to table {escaped_double_quotes(full_table_name)}" + assert success_msg_f2 in resp + + with test_db.get_sqla_engine_with_context() as engine: + data = engine.execute(f"SELECT * from {PARQUET_UPLOAD_TABLE}").fetchall() + assert data == [("john", 1), ("paul", 2), ("max", 3), ("bob", 4)] diff --git a/tests/integration_tests/dashboard_tests.py b/tests/integration_tests/dashboard_tests.py index 3ad9b07e29c14..d54151db83c2d 100644 --- a/tests/integration_tests/dashboard_tests.py +++ b/tests/integration_tests/dashboard_tests.py @@ -23,7 +23,7 @@ from random import random import pytest -from flask import escape, url_for +from flask import Response, escape, url_for from sqlalchemy import func from tests.integration_tests.test_app import app @@ -125,13 +125,12 @@ def get_mock_positions(self, dash): positions[id] = d return positions - def test_dashboard(self): + def test_get_dashboard(self): self.login(username="admin") - urls = {} - for dash in db.session.query(Dashboard).all(): - urls[dash.dashboard_title] = dash.url - for title, url in urls.items(): - assert escape(title) in self.client.get(url).data.decode("utf-8") + for dash in db.session.query(Dashboard): + assert escape(dash.dashboard_title) in self.client.get(dash.url).get_data( + as_text=True + ) def test_superset_dashboard_url(self): url_for("Superset.dashboard", dashboard_id_or_slug=1) @@ -144,7 +143,7 @@ def test_new_dashboard(self): dash_count_after = db.session.query(func.count(Dashboard.id)).first()[0] self.assertEqual(dash_count_before + 1, dash_count_after) group = re.match( - r"http:\/\/localhost\/superset\/dashboard\/([0-9]*)\/\?edit=true", + r"\/superset\/dashboard\/([0-9]*)\/\?edit=true", response.headers["Location"], ) assert group is not None @@ -424,8 +423,9 @@ def test_public_user_dashboard_access(self): # Cleanup self.revoke_public_access_to_table(table) - @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") - @pytest.mark.usefixtures("public_role_like_gamma") + @pytest.mark.usefixtures( + "load_birth_names_dashboard_with_slices", "public_role_like_gamma" + ) def test_dashboard_with_created_by_can_be_accessed_by_public_users(self): self.logout() table = db.session.query(SqlaTable).filter_by(table_name="birth_names").one() @@ -437,8 +437,9 @@ def test_dashboard_with_created_by_can_be_accessed_by_public_users(self): db.session.merge(dash) db.session.commit() - # this asserts a non-4xx response - self.get_resp("/superset/dashboard/births/") + res: Response = self.client.get("/superset/dashboard/births/") + assert res.status_code == 200 + # Cleanup self.revoke_public_access_to_table(table) @@ -486,13 +487,18 @@ def test_users_can_view_own_dashboard(self): hidden_dash.slices = [] hidden_dash.owners = [] - db.session.merge(dash) - db.session.merge(hidden_dash) + db.session.add(dash) + db.session.add(hidden_dash) db.session.commit() self.login(user.username) resp = self.get_resp("/api/v1/dashboard/") + + db.session.delete(dash) + db.session.delete(hidden_dash) + db.session.commit() + self.assertIn(f"/superset/dashboard/{my_dash_slug}/", resp) self.assertNotIn(f"/superset/dashboard/{not_my_dash_slug}/", resp) @@ -509,8 +515,8 @@ def test_users_can_view_favorited_dashboards(self): regular_dash.dashboard_title = "A Plain Ol Dashboard" regular_dash.slug = regular_dash_slug - db.session.merge(favorite_dash) - db.session.merge(regular_dash) + db.session.add(favorite_dash) + db.session.add(regular_dash) db.session.commit() dash = db.session.query(Dashboard).filter_by(slug=fav_dash_slug).first() @@ -520,12 +526,18 @@ def test_users_can_view_favorited_dashboards(self): favorites.class_name = "Dashboard" favorites.user_id = user.id - db.session.merge(favorites) + db.session.add(favorites) db.session.commit() self.login(user.username) resp = self.get_resp("/api/v1/dashboard/") + + db.session.delete(favorites) + db.session.delete(regular_dash) + db.session.delete(favorite_dash) + db.session.commit() + self.assertIn(f"/superset/dashboard/{fav_dash_slug}/", resp) def test_user_can_not_view_unpublished_dash(self): @@ -540,12 +552,16 @@ def test_user_can_not_view_unpublished_dash(self): dash.owners = [admin_user] dash.slices = [] dash.published = False - db.session.merge(dash) + db.session.add(dash) db.session.commit() # list dashboards as a gamma user self.login(gamma_user.username) resp = self.get_resp("/api/v1/dashboard/") + + db.session.delete(dash) + db.session.commit() + self.assertNotIn(f"/superset/dashboard/{slug}/", resp) diff --git a/tests/integration_tests/dashboard_utils.py b/tests/integration_tests/dashboard_utils.py index 41a34fa36edf5..bea724dafc95d 100644 --- a/tests/integration_tests/dashboard_utils.py +++ b/tests/integration_tests/dashboard_utils.py @@ -21,7 +21,7 @@ from pandas import DataFrame -from superset import ConnectorRegistry, db +from superset import db from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database from superset.models.dashboard import Dashboard @@ -35,9 +35,8 @@ def get_table( schema: Optional[str] = None, ): schema = schema or get_example_default_schema() - table_source = ConnectorRegistry.sources["table"] return ( - db.session.query(table_source) + db.session.query(SqlaTable) .filter_by(database_id=database.id, schema=schema, table_name=table_name) .one_or_none() ) @@ -54,8 +53,7 @@ def create_table_metadata( table = get_table(table_name, database, schema) if not table: - table_source = ConnectorRegistry.sources["table"] - table = table_source(schema=schema, table_name=table_name) + table = SqlaTable(schema=schema, table_name=table_name) if fetch_values_predicate: table.fetch_values_predicate = fetch_values_predicate table.database = database @@ -82,8 +80,9 @@ def create_dashboard( slug: str, title: str, position: str, slices: List[Slice] ) -> Dashboard: dash = db.session.query(Dashboard).filter_by(slug=slug).one_or_none() - if not dash: - dash = Dashboard() + if dash: + return dash + dash = Dashboard() dash.dashboard_title = title if position is not None: js = position @@ -92,7 +91,7 @@ def create_dashboard( dash.slug = slug if slices is not None: dash.slices = slices - db.session.merge(dash) + db.session.add(dash) db.session.commit() return dash diff --git a/tests/integration_tests/dashboards/api_tests.py b/tests/integration_tests/dashboards/api_tests.py index a027dcffae604..725811ce5f68d 100644 --- a/tests/integration_tests/dashboards/api_tests.py +++ b/tests/integration_tests/dashboards/api_tests.py @@ -34,7 +34,7 @@ from superset import db, security_manager from superset.models.dashboard import Dashboard from superset.models.core import FavStar, FavStarClassName -from superset.models.reports import ReportSchedule, ReportScheduleType +from superset.reports.models import ReportSchedule, ReportScheduleType from superset.models.slice import Slice from superset.utils.core import backend from superset.views.base import generate_download_headers @@ -72,7 +72,7 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixi "slug": "slug1_changed", "position_json": '{"b": "B"}', "css": "css_changed", - "json_metadata": '{"refresh_frequency": 30, "timed_refresh_immune_slices": [], "expanded_slices": {}, "color_scheme": "", "label_colors": {}, "shared_label_colors": {}}', + "json_metadata": '{"refresh_frequency": 30, "timed_refresh_immune_slices": [], "expanded_slices": {}, "color_scheme": "", "label_colors": {}, "shared_label_colors": {}, "color_scheme_domain": [], "cross_filters_enabled": false}', "published": False, } @@ -161,16 +161,16 @@ def create_dashboards(self): db.session.commit() @pytest.fixture() - def create_created_by_admin_dashboards(self): + def create_created_by_gamma_dashboards(self): with self.create_app().app_context(): dashboards = [] - admin = self.get_user("admin") + gamma = self.get_user("gamma") for cx in range(2): dashboard = self.insert_dashboard( f"create_title{cx}", f"create_slug{cx}", - [admin.id], - created_by=admin, + [gamma.id], + created_by=gamma, ) sleep(1) dashboards.append(dashboard) @@ -225,15 +225,36 @@ def test_get_dashboard_datasets_not_found(self): response = self.get_assert_metric(uri, "get_datasets") self.assertEqual(response.status_code, 404) - @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices") - def test_get_draft_dashboard_datasets(self): + @pytest.mark.usefixtures("create_dashboards") + def test_get_gamma_dashboard_datasets(self): """ - All users should have access to dashboards without roles + Check that a gamma user with data access can access dashboard/datasets """ + from superset.connectors.sqla.models import SqlaTable + + # Set correct role permissions + gamma_role = security_manager.find_role("Gamma") + fixture_dataset = db.session.query(SqlaTable).get(1) + data_access_pvm = security_manager.add_permission_view_menu( + "datasource_access", fixture_dataset.perm + ) + gamma_role.permissions.append(data_access_pvm) + db.session.commit() + self.login(username="gamma") - uri = "api/v1/dashboard/world_health/datasets" + dashboard = self.dashboards[0] + dashboard.published = True + db.session.commit() + + uri = f"api/v1/dashboard/{dashboard.id}/datasets" response = self.get_assert_metric(uri, "get_datasets") - self.assertEqual(response.status_code, 200) + assert response.status_code == 200 + + # rollback permission change + data_access_pvm = security_manager.find_permission_view_menu( + "datasource_access", fixture_dataset.perm + ) + security_manager.del_permission_role(gamma_role, data_access_pvm) @pytest.mark.usefixtures("create_dashboards") def get_dashboard_by_slug(self): @@ -275,10 +296,22 @@ def test_get_dashboard_charts(self): response = self.get_assert_metric(uri, "get_charts") self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode("utf-8")) - self.assertEqual(len(data["result"]), 1) - self.assertEqual( - data["result"][0]["slice_name"], dashboard.slices[0].slice_name - ) + assert len(data["result"]) == 1 + result = data["result"][0] + assert set(result.keys()) == { + "cache_timeout", + "certification_details", + "certified_by", + "changed_on", + "description", + "description_markeddown", + "form_data", + "id", + "slice_name", + "slice_url", + } + assert result["id"] == dashboard.slices[0].id + assert result["slice_name"] == dashboard.slices[0].slice_name @pytest.mark.usefixtures("create_dashboards") def test_get_dashboard_charts_by_slug(self): @@ -307,17 +340,45 @@ def test_get_dashboard_charts_not_found(self): response = self.get_assert_metric(uri, "get_charts") self.assertEqual(response.status_code, 404) + @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices") + def test_get_dashboard_datasets_not_allowed(self): + self.login(username="gamma") + uri = "api/v1/dashboard/world_health/datasets" + response = self.get_assert_metric(uri, "get_datasets") + self.assertEqual(response.status_code, 404) + @pytest.mark.usefixtures("create_dashboards") - def test_get_draft_dashboard_charts(self): + def test_get_gamma_dashboard_charts(self): """ - All users should have access to draft dashboards without roles + Check that a gamma user with data access can access dashboard/charts """ + from superset.connectors.sqla.models import SqlaTable + + # Set correct role permissions + gamma_role = security_manager.find_role("Gamma") + fixture_dataset = db.session.query(SqlaTable).get(1) + data_access_pvm = security_manager.add_permission_view_menu( + "datasource_access", fixture_dataset.perm + ) + gamma_role.permissions.append(data_access_pvm) + db.session.commit() + self.login(username="gamma") + dashboard = self.dashboards[0] + dashboard.published = True + db.session.commit() + uri = f"api/v1/dashboard/{dashboard.id}/charts" response = self.get_assert_metric(uri, "get_charts") assert response.status_code == 200 + # rollback permission change + data_access_pvm = security_manager.find_permission_view_menu( + "datasource_access", fixture_dataset.perm + ) + security_manager.del_permission_role(gamma_role, data_access_pvm) + @pytest.mark.usefixtures("create_dashboards") def test_get_dashboard_charts_empty(self): """ @@ -439,7 +500,7 @@ def test_get_dashboard_no_data_access(self): self.login(username="gamma") uri = f"api/v1/dashboard/{dashboard.id}" rv = self.client.get(uri) - assert rv.status_code == 200 + assert rv.status_code == 404 # rollback changes db.session.delete(dashboard) db.session.commit() @@ -695,23 +756,25 @@ def test_gets_not_certified_dashboards_filter(self): rv = self.get_assert_metric(uri, "get_list") self.assertEqual(rv.status_code, 200) data = json.loads(rv.data.decode("utf-8")) - self.assertEqual(data["count"], 5) + self.assertEqual(data["count"], 0) - @pytest.mark.usefixtures("create_created_by_admin_dashboards") + @pytest.mark.usefixtures("create_created_by_gamma_dashboards") def test_get_dashboards_created_by_me(self): """ Dashboard API: Test get dashboards created by current user """ query = { "columns": ["created_on_delta_humanized", "dashboard_title", "url"], - "filters": [{"col": "created_by", "opr": "created_by_me", "value": "me"}], + "filters": [ + {"col": "created_by", "opr": "dashboard_created_by_me", "value": "me"} + ], "order_column": "changed_on", "order_direction": "desc", "page": 0, "page_size": 100, } uri = f"api/v1/dashboard/?q={prison.dumps(query)}" - self.login(username="admin") + self.login(username="gamma") rv = self.client.get(uri) data = json.loads(rv.data.decode("utf-8")) assert rv.status_code == 200 @@ -801,6 +864,46 @@ def test_delete_bulk_dashboards(self): model = db.session.query(Dashboard).get(dashboard_id) self.assertEqual(model, None) + def test_delete_bulk_embedded_dashboards(self): + """ + Dashboard API: Test delete bulk embedded + """ + user = self.get_user("admin") + dashboard_count = 4 + dashboard_ids = list() + for dashboard_name_index in range(dashboard_count): + dashboard_ids.append( + self.insert_dashboard( + f"title{dashboard_name_index}", + None, + [user.id], + ).id + ) + self.login(username=user.username) + for dashboard_id in dashboard_ids: + # post succeeds and returns value + allowed_domains = ["test.example", "embedded.example"] + resp = self.post_assert_metric( + f"api/v1/dashboard/{dashboard_id}/embedded", + {"allowed_domains": allowed_domains}, + "set_embedded", + ) + self.assertEqual(resp.status_code, 200) + result = json.loads(resp.data.decode("utf-8"))["result"] + self.assertIsNotNone(result["uuid"]) + self.assertNotEqual(result["uuid"], "") + self.assertEqual(result["allowed_domains"], allowed_domains) + argument = dashboard_ids + uri = f"api/v1/dashboard/?q={prison.dumps(argument)}" + rv = self.delete_assert_metric(uri, "bulk_delete") + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + expected_response = {"message": f"Deleted {dashboard_count} dashboards"} + self.assertEqual(response, expected_response) + for dashboard_id in dashboard_ids: + model = db.session.query(Dashboard).get(dashboard_id) + self.assertEqual(model, None) + def test_delete_bulk_dashboards_bad_request(self): """ Dashboard API: Test delete bulk bad request @@ -1244,6 +1347,65 @@ def test_update_dashboard_chart_owners(self): db.session.delete(user_alpha2) db.session.commit() + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + def test_update_dashboard_chart_owners_propagation(self): + """ + Dashboard API: Test update chart owners propagation + """ + user_alpha1 = self.create_user( + "alpha1", + "password", + "Alpha", + email="alpha1@superset.org", + first_name="alpha1", + ) + admin = self.get_user("admin") + slices = [] + slices.append(db.session.query(Slice).filter_by(slice_name="Trends").one()) + slices.append(db.session.query(Slice).filter_by(slice_name="Boys").one()) + + # Insert dashboard with admin as owner + dashboard = self.insert_dashboard( + "title1", + "slug1", + [admin.id], + slices=slices, + ) + + # Updates dashboard without Boys in json_metadata positions + # and user_alpha1 as owner + dashboard_data = { + "owners": [user_alpha1.id], + "json_metadata": json.dumps( + { + "positions": { + f"{slices[0].id}": { + "type": "CHART", + "meta": {"chartId": slices[0].id}, + }, + } + } + ), + } + self.login(username="admin") + uri = f"api/v1/dashboard/{dashboard.id}" + rv = self.client.put(uri, json=dashboard_data) + self.assertEqual(rv.status_code, 200) + + # Check that chart named Boys does not contain alpha 1 in its owners + boys = db.session.query(Slice).filter_by(slice_name="Boys").one() + self.assertNotIn(user_alpha1, boys.owners) + + # Revert owners on slice + for slice in slices: + slice.owners = [] + db.session.commit() + + # Rollback changes + db.session.delete(dashboard) + db.session.delete(user_alpha1) + db.session.commit() + def test_update_partial_dashboard(self): """ Dashboard API: Test update partial @@ -1774,6 +1936,26 @@ def test_get_filter_related_roles(self): response_roles = [result["text"] for result in response["result"]] assert "Alpha" in response_roles + def test_get_all_related_roles_with_with_extra_filters(self): + """ + API: Test get filter related roles with extra related query filters + """ + self.login(username="admin") + + def _base_filter(query): + return query.filter_by(name="Alpha") + + with patch.dict( + "superset.views.filters.current_app.config", + {"EXTRA_RELATED_QUERY_FILTERS": {"role": _base_filter}}, + ): + uri = f"api/v1/dashboard/related/roles" + rv = self.client.get(uri) + assert rv.status_code == 200 + response = json.loads(rv.data.decode("utf-8")) + response_roles = [result["text"] for result in response["result"]] + assert response_roles == ["Alpha"] + @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices") def test_embedded_dashboards(self): self.login(username="admin") @@ -1836,3 +2018,49 @@ def test_embedded_dashboards(self): # get returns 404 resp = self.get_assert_metric(uri, "get_embedded") self.assertEqual(resp.status_code, 404) + + @pytest.mark.usefixtures("create_created_by_gamma_dashboards") + def test_gets_created_by_user_dashboards_filter(self): + expected_models = ( + db.session.query(Dashboard) + .filter(Dashboard.created_by_fk.isnot(None)) + .all() + ) + + arguments = { + "filters": [ + {"col": "created_by", "opr": "dashboard_has_created_by", "value": True} + ], + "keys": ["none"], + "columns": ["dashboard_title"], + } + self.login(username="admin") + + uri = f"api/v1/dashboard/?q={prison.dumps(arguments)}" + rv = self.get_assert_metric(uri, "get_list") + self.assertEqual(rv.status_code, 200) + data = json.loads(rv.data.decode("utf-8")) + self.assertEqual(data["count"], len(expected_models)) + + def test_gets_not_created_by_user_dashboards_filter(self): + dashboard = self.insert_dashboard(f"title", f"slug", []) + expected_models = ( + db.session.query(Dashboard).filter(Dashboard.created_by_fk.is_(None)).all() + ) + + arguments = { + "filters": [ + {"col": "created_by", "opr": "dashboard_has_created_by", "value": False} + ], + "keys": ["none"], + "columns": ["dashboard_title"], + } + self.login(username="admin") + + uri = f"api/v1/dashboard/?q={prison.dumps(arguments)}" + rv = self.get_assert_metric(uri, "get_list") + self.assertEqual(rv.status_code, 200) + data = json.loads(rv.data.decode("utf-8")) + self.assertEqual(data["count"], len(expected_models)) + db.session.delete(dashboard) + db.session.commit() diff --git a/tests/integration_tests/dashboards/dao_tests.py b/tests/integration_tests/dashboards/dao_tests.py index e9d73764955f0..672e930364f2a 100644 --- a/tests/integration_tests/dashboards/dao_tests.py +++ b/tests/integration_tests/dashboards/dao_tests.py @@ -18,11 +18,11 @@ import copy import json import time - +from unittest.mock import patch import pytest import tests.integration_tests.test_app # pylint: disable=unused-import -from superset import db +from superset import db, security_manager from superset.dashboards.dao import DashboardDAO from superset.models.dashboard import Dashboard from tests.integration_tests.base_tests import SupersetTestCase @@ -88,37 +88,42 @@ def test_set_dash_metadata(self): DashboardDAO.set_dash_metadata(dash, original_data) @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices") - def test_get_dashboard_changed_on(self): - self.login(username="admin") - session = db.session() - dashboard = session.query(Dashboard).filter_by(slug="world_health").first() + @patch("superset.utils.core.g") + @patch("superset.security.manager.g") + def test_get_dashboard_changed_on(self, mock_sm_g, mock_g): + mock_g.user = mock_sm_g.user = security_manager.find_user("admin") + with self.client.application.test_request_context(): + self.login(username="admin") + dashboard = ( + db.session.query(Dashboard).filter_by(slug="world_health").first() + ) - changed_on = dashboard.changed_on.replace(microsecond=0) - assert changed_on == DashboardDAO.get_dashboard_changed_on(dashboard) - assert changed_on == DashboardDAO.get_dashboard_changed_on("world_health") + changed_on = dashboard.changed_on.replace(microsecond=0) + assert changed_on == DashboardDAO.get_dashboard_changed_on(dashboard) + assert changed_on == DashboardDAO.get_dashboard_changed_on("world_health") - old_changed_on = dashboard.changed_on + old_changed_on = dashboard.changed_on - # freezegun doesn't work for some reason, so we need to sleep here :( - time.sleep(1) - data = dashboard.data - positions = data["position_json"] - data.update({"positions": positions}) - original_data = copy.deepcopy(data) + # freezegun doesn't work for some reason, so we need to sleep here :( + time.sleep(1) + data = dashboard.data + positions = data["position_json"] + data.update({"positions": positions}) + original_data = copy.deepcopy(data) - data.update({"foo": "bar"}) - DashboardDAO.set_dash_metadata(dashboard, data) - session.merge(dashboard) - session.commit() - new_changed_on = DashboardDAO.get_dashboard_changed_on(dashboard) - assert old_changed_on.replace(microsecond=0) < new_changed_on - assert new_changed_on == DashboardDAO.get_dashboard_and_datasets_changed_on( - dashboard - ) - assert new_changed_on == DashboardDAO.get_dashboard_and_slices_changed_on( - dashboard - ) + data.update({"foo": "bar"}) + DashboardDAO.set_dash_metadata(dashboard, data) + db.session.merge(dashboard) + db.session.commit() + new_changed_on = DashboardDAO.get_dashboard_changed_on(dashboard) + assert old_changed_on.replace(microsecond=0) < new_changed_on + assert new_changed_on == DashboardDAO.get_dashboard_and_datasets_changed_on( + dashboard + ) + assert new_changed_on == DashboardDAO.get_dashboard_and_slices_changed_on( + dashboard + ) - DashboardDAO.set_dash_metadata(dashboard, original_data) - session.merge(dashboard) - session.commit() + DashboardDAO.set_dash_metadata(dashboard, original_data) + db.session.merge(dashboard) + db.session.commit() diff --git a/tests/integration_tests/dashboards/filter_sets/create_api_tests.py b/tests/integration_tests/dashboards/filter_sets/create_api_tests.py index fcd2923fb8696..b5d1919dd430a 100644 --- a/tests/integration_tests/dashboards/filter_sets/create_api_tests.py +++ b/tests/integration_tests/dashboards/filter_sets/create_api_tests.py @@ -16,7 +16,9 @@ # under the License. from __future__ import annotations -from typing import Any, Dict, TYPE_CHECKING +from typing import Any, Dict + +from flask.testing import FlaskClient from superset.dashboards.filter_sets.consts import ( DASHBOARD_OWNER_TYPE, @@ -27,7 +29,6 @@ OWNER_TYPE_FIELD, USER_OWNER_TYPE, ) -from tests.integration_tests.base_tests import login from tests.integration_tests.dashboards.filter_sets.consts import ( ADMIN_USERNAME_FOR_TEST, DASHBOARD_OWNER_USERNAME, @@ -38,9 +39,7 @@ get_filter_set_by_dashboard_id, get_filter_set_by_name, ) - -if TYPE_CHECKING: - from flask.testing import FlaskClient +from tests.integration_tests.test_app import login def assert_filterset_was_not_created(filter_set_data: Dict[str, Any]) -> None: diff --git a/tests/integration_tests/dashboards/filter_sets/delete_api_tests.py b/tests/integration_tests/dashboards/filter_sets/delete_api_tests.py index 8e7e0bcb6004e..7011cb5781282 100644 --- a/tests/integration_tests/dashboards/filter_sets/delete_api_tests.py +++ b/tests/integration_tests/dashboards/filter_sets/delete_api_tests.py @@ -18,7 +18,6 @@ from typing import Any, Dict, List, TYPE_CHECKING -from tests.integration_tests.base_tests import login from tests.integration_tests.dashboards.filter_sets.consts import ( DASHBOARD_OWNER_USERNAME, FILTER_SET_OWNER_USERNAME, @@ -29,6 +28,7 @@ collect_all_ids, get_filter_set_by_name, ) +from tests.integration_tests.test_app import login if TYPE_CHECKING: from flask.testing import FlaskClient diff --git a/tests/integration_tests/dashboards/filter_sets/get_api_tests.py b/tests/integration_tests/dashboards/filter_sets/get_api_tests.py index 7be6f367dd6b9..ad40d0e33c859 100644 --- a/tests/integration_tests/dashboards/filter_sets/get_api_tests.py +++ b/tests/integration_tests/dashboards/filter_sets/get_api_tests.py @@ -18,7 +18,6 @@ from typing import Any, Dict, List, Set, TYPE_CHECKING -from tests.integration_tests.base_tests import login from tests.integration_tests.dashboards.filter_sets.consts import ( DASHBOARD_OWNER_USERNAME, FILTER_SET_OWNER_USERNAME, @@ -28,6 +27,7 @@ call_get_filter_sets, collect_all_ids, ) +from tests.integration_tests.test_app import login if TYPE_CHECKING: from flask.testing import FlaskClient diff --git a/tests/integration_tests/dashboards/filter_sets/update_api_tests.py b/tests/integration_tests/dashboards/filter_sets/update_api_tests.py index 4096e100994f8..07db98f617815 100644 --- a/tests/integration_tests/dashboards/filter_sets/update_api_tests.py +++ b/tests/integration_tests/dashboards/filter_sets/update_api_tests.py @@ -26,7 +26,6 @@ OWNER_TYPE_FIELD, PARAMS_PROPERTY, ) -from tests.integration_tests.base_tests import login from tests.integration_tests.dashboards.filter_sets.consts import ( DASHBOARD_OWNER_USERNAME, FILTER_SET_OWNER_USERNAME, @@ -37,6 +36,7 @@ collect_all_ids, get_filter_set_by_name, ) +from tests.integration_tests.test_app import login if TYPE_CHECKING: from flask.testing import FlaskClient diff --git a/tests/integration_tests/dashboards/filter_state/api_tests.py b/tests/integration_tests/dashboards/filter_state/api_tests.py index ea00f2e6714f5..15b479686a4ec 100644 --- a/tests/integration_tests/dashboards/filter_state/api_tests.py +++ b/tests/integration_tests/dashboards/filter_state/api_tests.py @@ -18,6 +18,7 @@ from unittest.mock import patch import pytest +from flask.ctx import AppContext from flask_appbuilder.security.sqla.models import User from sqlalchemy.orm import Session @@ -26,8 +27,6 @@ from superset.models.dashboard import Dashboard from superset.temporary_cache.commands.entry import Entry from superset.temporary_cache.utils import cache_key -from tests.integration_tests.base_tests import login -from tests.integration_tests.fixtures.client import client from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices, load_world_bank_data, @@ -40,19 +39,17 @@ @pytest.fixture -def dashboard_id(load_world_bank_dashboard_with_slices) -> int: - with app.app_context() as ctx: - session: Session = ctx.app.appbuilder.get_session - dashboard = session.query(Dashboard).filter_by(slug="world_health").one() - return dashboard.id +def dashboard_id(app_context: AppContext, load_world_bank_dashboard_with_slices) -> int: + session: Session = app_context.app.appbuilder.get_session + dashboard = session.query(Dashboard).filter_by(slug="world_health").one() + return dashboard.id @pytest.fixture -def admin_id() -> int: - with app.app_context() as ctx: - session: Session = ctx.app.appbuilder.get_session - admin = session.query(User).filter_by(username="admin").one_or_none() - return admin.id +def admin_id(app_context: AppContext) -> int: + session: Session = app_context.app.appbuilder.get_session + admin = session.query(User).filter_by(username="admin").one_or_none() + return admin.id @pytest.fixture(autouse=True) @@ -61,55 +58,59 @@ def cache(dashboard_id, admin_id): cache_manager.filter_state_cache.set(cache_key(dashboard_id, KEY), entry) -def test_post(client, dashboard_id: int): - login(client, "admin") - payload = { - "value": INITIAL_VALUE, - } - resp = client.post(f"api/v1/dashboard/{dashboard_id}/filter_state", json=payload) +def test_post(test_client, login_as_admin, dashboard_id: int): + resp = test_client.post( + f"api/v1/dashboard/{dashboard_id}/filter_state", + json={ + "value": INITIAL_VALUE, + }, + ) assert resp.status_code == 201 -def test_post_bad_request_non_string(client, dashboard_id: int): - login(client, "admin") - payload = { - "value": 1234, - } - resp = client.post(f"api/v1/dashboard/{dashboard_id}/filter_state", json=payload) +def test_post_bad_request_non_string(test_client, login_as_admin, dashboard_id: int): + resp = test_client.post( + f"api/v1/dashboard/{dashboard_id}/filter_state", + json={ + "value": 1234, + }, + ) assert resp.status_code == 400 -def test_post_bad_request_non_json_string(client, dashboard_id: int): - login(client, "admin") +def test_post_bad_request_non_json_string( + test_client, login_as_admin, dashboard_id: int +): payload = { "value": "foo", } - resp = client.post(f"api/v1/dashboard/{dashboard_id}/filter_state", json=payload) + resp = test_client.post( + f"api/v1/dashboard/{dashboard_id}/filter_state", json=payload + ) assert resp.status_code == 400 -@patch("superset.security.SupersetSecurityManager.raise_for_dashboard_access") -def test_post_access_denied(mock_raise_for_dashboard_access, client, dashboard_id: int): - login(client, "admin") - mock_raise_for_dashboard_access.side_effect = DashboardAccessDeniedError() +def test_post_access_denied(test_client, login_as, dashboard_id: int): + login_as("gamma") payload = { "value": INITIAL_VALUE, } - resp = client.post(f"api/v1/dashboard/{dashboard_id}/filter_state", json=payload) - assert resp.status_code == 403 + resp = test_client.post( + f"api/v1/dashboard/{dashboard_id}/filter_state", json=payload + ) + assert resp.status_code == 404 -def test_post_same_key_for_same_tab_id(client, dashboard_id: int): - login(client, "admin") +def test_post_same_key_for_same_tab_id(test_client, login_as_admin, dashboard_id: int): payload = { "value": INITIAL_VALUE, } - resp = client.post( + resp = test_client.post( f"api/v1/dashboard/{dashboard_id}/filter_state?tab_id=1", json=payload ) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.post( + resp = test_client.post( f"api/v1/dashboard/{dashboard_id}/filter_state?tab_id=1", json=payload ) data = json.loads(resp.data.decode("utf-8")) @@ -117,17 +118,18 @@ def test_post_same_key_for_same_tab_id(client, dashboard_id: int): assert first_key == second_key -def test_post_different_key_for_different_tab_id(client, dashboard_id: int): - login(client, "admin") +def test_post_different_key_for_different_tab_id( + test_client, login_as_admin, dashboard_id: int +): payload = { "value": INITIAL_VALUE, } - resp = client.post( + resp = test_client.post( f"api/v1/dashboard/{dashboard_id}/filter_state?tab_id=1", json=payload ) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.post( + resp = test_client.post( f"api/v1/dashboard/{dashboard_id}/filter_state?tab_id=2", json=payload ) data = json.loads(resp.data.decode("utf-8")) @@ -135,42 +137,45 @@ def test_post_different_key_for_different_tab_id(client, dashboard_id: int): assert first_key != second_key -def test_post_different_key_for_no_tab_id(client, dashboard_id: int): - login(client, "admin") +def test_post_different_key_for_no_tab_id( + test_client, login_as_admin, dashboard_id: int +): payload = { "value": INITIAL_VALUE, } - resp = client.post(f"api/v1/dashboard/{dashboard_id}/filter_state", json=payload) + resp = test_client.post( + f"api/v1/dashboard/{dashboard_id}/filter_state", json=payload + ) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.post(f"api/v1/dashboard/{dashboard_id}/filter_state", json=payload) + resp = test_client.post( + f"api/v1/dashboard/{dashboard_id}/filter_state", json=payload + ) data = json.loads(resp.data.decode("utf-8")) second_key = data.get("key") assert first_key != second_key -def test_put(client, dashboard_id: int): - login(client, "admin") - payload = { - "value": UPDATED_VALUE, - } - resp = client.put( - f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", json=payload +def test_put(test_client, login_as_admin, dashboard_id: int): + resp = test_client.put( + f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", + json={ + "value": UPDATED_VALUE, + }, ) assert resp.status_code == 200 -def test_put_same_key_for_same_tab_id(client, dashboard_id: int): - login(client, "admin") +def test_put_same_key_for_same_tab_id(test_client, login_as_admin, dashboard_id: int): payload = { "value": INITIAL_VALUE, } - resp = client.put( + resp = test_client.put( f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}?tab_id=1", json=payload ) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.put( + resp = test_client.put( f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}?tab_id=1", json=payload ) data = json.loads(resp.data.decode("utf-8")) @@ -178,17 +183,18 @@ def test_put_same_key_for_same_tab_id(client, dashboard_id: int): assert first_key == second_key -def test_put_different_key_for_different_tab_id(client, dashboard_id: int): - login(client, "admin") +def test_put_different_key_for_different_tab_id( + test_client, login_as_admin, dashboard_id: int +): payload = { "value": INITIAL_VALUE, } - resp = client.put( + resp = test_client.put( f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}?tab_id=1", json=payload ) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.put( + resp = test_client.put( f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}?tab_id=2", json=payload ) data = json.loads(resp.data.decode("utf-8")) @@ -196,17 +202,18 @@ def test_put_different_key_for_different_tab_id(client, dashboard_id: int): assert first_key != second_key -def test_put_different_key_for_no_tab_id(client, dashboard_id: int): - login(client, "admin") +def test_put_different_key_for_no_tab_id( + test_client, login_as_admin, dashboard_id: int +): payload = { "value": INITIAL_VALUE, } - resp = client.put( + resp = test_client.put( f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", json=payload ) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.put( + resp = test_client.put( f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", json=payload ) data = json.loads(resp.data.decode("utf-8")) @@ -214,97 +221,74 @@ def test_put_different_key_for_no_tab_id(client, dashboard_id: int): assert first_key != second_key -def test_put_bad_request_non_string(client, dashboard_id: int): - login(client, "admin") - payload = { - "value": 1234, - } - resp = client.put( - f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", json=payload +def test_put_bad_request_non_string(test_client, login_as_admin, dashboard_id: int): + resp = test_client.put( + f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", + json={ + "value": 1234, + }, ) assert resp.status_code == 400 -def test_put_bad_request_non_json_string(client, dashboard_id: int): - login(client, "admin") - payload = { - "value": "foo", - } - resp = client.put( - f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", json=payload +def test_put_bad_request_non_json_string( + test_client, login_as_admin, dashboard_id: int +): + resp = test_client.put( + f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", + json={ + "value": "foo", + }, ) assert resp.status_code == 400 -@patch("superset.security.SupersetSecurityManager.raise_for_dashboard_access") -def test_put_access_denied(mock_raise_for_dashboard_access, client, dashboard_id: int): - login(client, "admin") - mock_raise_for_dashboard_access.side_effect = DashboardAccessDeniedError() - payload = { - "value": UPDATED_VALUE, - } - resp = client.put( - f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", json=payload +def test_put_access_denied(test_client, login_as, dashboard_id: int): + login_as("gamma") + resp = test_client.put( + f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", + json={ + "value": UPDATED_VALUE, + }, ) - assert resp.status_code == 403 - - -def test_put_not_owner(client, dashboard_id: int): - login(client, "gamma") - payload = { - "value": UPDATED_VALUE, - } - resp = client.put( - f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}", json=payload - ) - assert resp.status_code == 403 + assert resp.status_code == 404 -def test_get_key_not_found(client, dashboard_id: int): - login(client, "admin") - resp = client.get(f"api/v1/dashboard/{dashboard_id}/filter_state/unknown-key/") +def test_get_key_not_found(test_client, login_as_admin, dashboard_id: int): + resp = test_client.get(f"api/v1/dashboard/{dashboard_id}/filter_state/unknown-key/") assert resp.status_code == 404 -def test_get_dashboard_not_found(client): - login(client, "admin") - resp = client.get(f"api/v1/dashboard/{-1}/filter_state/{KEY}") +def test_get_dashboard_not_found(test_client, login_as_admin): + resp = test_client.get(f"api/v1/dashboard/{-1}/filter_state/{KEY}") assert resp.status_code == 404 -def test_get(client, dashboard_id: int): - login(client, "admin") - resp = client.get(f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}") +def test_get_dashboard_filter_state(test_client, login_as_admin, dashboard_id: int): + resp = test_client.get(f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}") assert resp.status_code == 200 data = json.loads(resp.data.decode("utf-8")) assert INITIAL_VALUE == data.get("value") -@patch("superset.security.SupersetSecurityManager.raise_for_dashboard_access") -def test_get_access_denied(mock_raise_for_dashboard_access, client, dashboard_id): - login(client, "admin") - mock_raise_for_dashboard_access.side_effect = DashboardAccessDeniedError() - resp = client.get(f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}") - assert resp.status_code == 403 +def test_get_access_denied(test_client, login_as, dashboard_id): + login_as("gamma") + resp = test_client.get(f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}") + assert resp.status_code == 404 -def test_delete(client, dashboard_id: int): - login(client, "admin") - resp = client.delete(f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}") +def test_delete(test_client, login_as_admin, dashboard_id: int): + resp = test_client.delete(f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}") assert resp.status_code == 200 -@patch("superset.security.SupersetSecurityManager.raise_for_dashboard_access") -def test_delete_access_denied( - mock_raise_for_dashboard_access, client, dashboard_id: int -): - login(client, "admin") - mock_raise_for_dashboard_access.side_effect = DashboardAccessDeniedError() - resp = client.delete(f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}") - assert resp.status_code == 403 +def test_delete_access_denied(test_client, login_as, dashboard_id: int): + login_as("gamma") + resp = test_client.delete(f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}") + assert resp.status_code == 404 -def test_delete_not_owner(client, dashboard_id: int): - login(client, "gamma") - resp = client.delete(f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}") - assert resp.status_code == 403 +def test_delete_not_owner(test_client, login_as, dashboard_id: int): + login_as("gamma") + resp = test_client.delete(f"api/v1/dashboard/{dashboard_id}/filter_state/{KEY}") + assert resp.status_code == 404 diff --git a/tests/integration_tests/dashboards/permalink/api_tests.py b/tests/integration_tests/dashboards/permalink/api_tests.py index 33186131d559f..40a312ef855a1 100644 --- a/tests/integration_tests/dashboards/permalink/api_tests.py +++ b/tests/integration_tests/dashboards/permalink/api_tests.py @@ -29,8 +29,6 @@ from superset.key_value.types import KeyValueResource from superset.key_value.utils import decode_permalink_id from superset.models.dashboard import Dashboard -from tests.integration_tests.base_tests import login -from tests.integration_tests.fixtures.client import client from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices, load_world_bank_data, @@ -38,8 +36,8 @@ from tests.integration_tests.test_app import app STATE = { - "filterState": {"FILTER_1": "foo"}, - "hash": "my-anchor", + "dataMask": {"FILTER_1": "foo"}, + "activeTabs": ["my-anchor"], } @@ -67,43 +65,48 @@ def permalink_salt() -> Iterator[str]: db.session.commit() -def test_post(client, dashboard_id: int, permalink_salt: str) -> None: - login(client, "admin") - resp = client.post(f"api/v1/dashboard/{dashboard_id}/permalink", json=STATE) +def test_post( + test_client, login_as_admin, dashboard_id: int, permalink_salt: str +) -> None: + resp = test_client.post(f"api/v1/dashboard/{dashboard_id}/permalink", json=STATE) assert resp.status_code == 201 - data = json.loads(resp.data.decode("utf-8")) + data = resp.json key = data["key"] url = data["url"] assert key in url id_ = decode_permalink_id(key, permalink_salt) + + assert ( + data + == test_client.post( + f"api/v1/dashboard/{dashboard_id}/permalink", json=STATE + ).json + ), "Should always return the same permalink key for the same payload" + db.session.query(KeyValueEntry).filter_by(id=id_).delete() db.session.commit() -@patch("superset.security.SupersetSecurityManager.raise_for_dashboard_access") -def test_post_access_denied(mock_raise_for_dashboard_access, client, dashboard_id: int): - login(client, "admin") - mock_raise_for_dashboard_access.side_effect = DashboardAccessDeniedError() - resp = client.post(f"api/v1/dashboard/{dashboard_id}/permalink", json=STATE) - assert resp.status_code == 403 +def test_post_access_denied(test_client, login_as, dashboard_id: int): + login_as("gamma") + resp = test_client.post(f"api/v1/dashboard/{dashboard_id}/permalink", json=STATE) + assert resp.status_code == 404 -def test_post_invalid_schema(client, dashboard_id: int): - login(client, "admin") - resp = client.post( +def test_post_invalid_schema(test_client, login_as_admin, dashboard_id: int): + resp = test_client.post( f"api/v1/dashboard/{dashboard_id}/permalink", json={"foo": "bar"} ) assert resp.status_code == 400 -def test_get(client, dashboard_id: int, permalink_salt: str): - login(client, "admin") - resp = client.post(f"api/v1/dashboard/{dashboard_id}/permalink", json=STATE) - data = json.loads(resp.data.decode("utf-8")) - key = data["key"] - resp = client.get(f"api/v1/dashboard/permalink/{key}") +def test_get(test_client, login_as_admin, dashboard_id: int, permalink_salt: str): + key = test_client.post( + f"api/v1/dashboard/{dashboard_id}/permalink", json=STATE + ).json["key"] + resp = test_client.get(f"api/v1/dashboard/permalink/{key}") assert resp.status_code == 200 - result = json.loads(resp.data.decode("utf-8")) + result = resp.json assert result["dashboardId"] == str(dashboard_id) assert result["state"] == STATE id_ = decode_permalink_id(key, permalink_salt) diff --git a/tests/integration_tests/dashboards/security/security_dataset_tests.py b/tests/integration_tests/dashboards/security/security_dataset_tests.py index 34a5fedad0bfb..2eafc4b53e0cd 100644 --- a/tests/integration_tests/dashboards/security/security_dataset_tests.py +++ b/tests/integration_tests/dashboards/security/security_dataset_tests.py @@ -137,8 +137,8 @@ def test_get_dashboards__users_can_view_favorites_dashboards(self): regular_dash.dashboard_title = "A Plain Ol Dashboard" regular_dash.slug = regular_dash_slug - db.session.merge(favorite_dash) - db.session.merge(regular_dash) + db.session.add(favorite_dash) + db.session.add(regular_dash) db.session.commit() dash = db.session.query(Dashboard).filter_by(slug=fav_dash_slug).first() @@ -148,7 +148,7 @@ def test_get_dashboards__users_can_view_favorites_dashboards(self): favorites.class_name = "Dashboard" favorites.user_id = user.id - db.session.merge(favorites) + db.session.add(favorites) db.session.commit() self.login(user.username) @@ -156,6 +156,12 @@ def test_get_dashboards__users_can_view_favorites_dashboards(self): # act get_dashboards_response = self.get_resp(DASHBOARDS_API_URL) + # cleanup + db.session.delete(favorites) + db.session.delete(favorite_dash) + db.session.delete(regular_dash) + db.session.commit() + # assert self.assertIn(f"/superset/dashboard/{fav_dash_slug}/", get_dashboards_response) diff --git a/tests/integration_tests/databases/api_tests.py b/tests/integration_tests/databases/api_tests.py index 791705ee1e0b0..c9d3855e5608e 100644 --- a/tests/integration_tests/databases/api_tests.py +++ b/tests/integration_tests/databases/api_tests.py @@ -35,6 +35,8 @@ from superset import db, security_manager from superset.connectors.sqla.models import SqlaTable +from superset.databases.ssh_tunnel.models import SSHTunnel +from superset.databases.utils import make_url_safe from superset.db_engine_specs.mysql import MySQLEngineSpec from superset.db_engine_specs.postgres import PostgresEngineSpec from superset.db_engine_specs.redshift import RedshiftEngineSpec @@ -43,7 +45,7 @@ from superset.db_engine_specs.hana import HanaEngineSpec from superset.errors import SupersetError from superset.models.core import Database, ConfigurationMethod -from superset.models.reports import ReportSchedule, ReportScheduleType +from superset.reports.models import ReportSchedule, ReportScheduleType from superset.utils.database import get_example_database, get_main_database from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.fixtures.birth_names_dashboard import ( @@ -185,7 +187,6 @@ def test_get_items(self): "allow_cvas", "allow_dml", "allow_file_upload", - "allow_multi_schema_metadata_fetch", "allow_run_async", "allows_cost_estimate", "allows_preview_data", @@ -197,11 +198,13 @@ def test_get_items(self): "created_by", "database_name", "disable_data_preview", + "engine_information", "explore_database_id", "expose_in_sqllab", "extra", "force_ctas_schema", "id", + "uuid", ] self.assertGreater(response["count"], 0) @@ -280,6 +283,405 @@ def test_create_database(self): db.session.delete(model) db.session.commit() + @mock.patch( + "superset.databases.commands.test_connection.TestConnectionDatabaseCommand.run", + ) + @mock.patch("superset.databases.commands.create.is_feature_enabled") + @mock.patch( + "superset.models.core.Database.get_all_schema_names", + ) + def test_create_database_with_ssh_tunnel( + self, + mock_test_connection_database_command_run, + mock_create_is_feature_enabled, + mock_get_all_schema_names, + ): + """ + Database API: Test create with SSH Tunnel + """ + mock_create_is_feature_enabled.return_value = True + self.login(username="admin") + example_db = get_example_database() + if example_db.backend == "sqlite": + return + ssh_tunnel_properties = { + "server_address": "123.132.123.1", + "server_port": 8080, + "username": "foo", + "password": "bar", + } + database_data = { + "database_name": "test-db-with-ssh-tunnel", + "sqlalchemy_uri": example_db.sqlalchemy_uri_decrypted, + "ssh_tunnel": ssh_tunnel_properties, + } + uri = "api/v1/database/" + rv = self.client.post(uri, json=database_data) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(rv.status_code, 201) + model_ssh_tunnel = ( + db.session.query(SSHTunnel) + .filter(SSHTunnel.database_id == response.get("id")) + .one() + ) + self.assertEqual(response.get("result")["ssh_tunnel"]["password"], "XXXXXXXXXX") + self.assertEqual(model_ssh_tunnel.database_id, response.get("id")) + # Cleanup + model = db.session.query(Database).get(response.get("id")) + db.session.delete(model) + db.session.commit() + + @mock.patch( + "superset.databases.commands.test_connection.TestConnectionDatabaseCommand.run", + ) + @mock.patch("superset.databases.commands.create.is_feature_enabled") + @mock.patch("superset.databases.commands.update.is_feature_enabled") + @mock.patch( + "superset.models.core.Database.get_all_schema_names", + ) + def test_update_database_with_ssh_tunnel( + self, + mock_test_connection_database_command_run, + mock_create_is_feature_enabled, + mock_update_is_feature_enabled, + mock_get_all_schema_names, + ): + """ + Database API: Test update Database with SSH Tunnel + """ + mock_create_is_feature_enabled.return_value = True + mock_update_is_feature_enabled.return_value = True + self.login(username="admin") + example_db = get_example_database() + if example_db.backend == "sqlite": + return + ssh_tunnel_properties = { + "server_address": "123.132.123.1", + "server_port": 8080, + "username": "foo", + "password": "bar", + } + database_data = { + "database_name": "test-db-with-ssh-tunnel", + "sqlalchemy_uri": example_db.sqlalchemy_uri_decrypted, + } + database_data_with_ssh_tunnel = { + "database_name": "test-db-with-ssh-tunnel", + "sqlalchemy_uri": example_db.sqlalchemy_uri_decrypted, + "ssh_tunnel": ssh_tunnel_properties, + } + + uri = "api/v1/database/" + rv = self.client.post(uri, json=database_data) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(rv.status_code, 201) + + uri = "api/v1/database/{}".format(response.get("id")) + rv = self.client.put(uri, json=database_data_with_ssh_tunnel) + response_update = json.loads(rv.data.decode("utf-8")) + self.assertEqual(rv.status_code, 200) + + model_ssh_tunnel = ( + db.session.query(SSHTunnel) + .filter(SSHTunnel.database_id == response_update.get("id")) + .one() + ) + self.assertEqual(model_ssh_tunnel.database_id, response_update.get("id")) + # Cleanup + model = db.session.query(Database).get(response.get("id")) + db.session.delete(model) + db.session.commit() + + @mock.patch( + "superset.databases.commands.test_connection.TestConnectionDatabaseCommand.run", + ) + @mock.patch("superset.databases.commands.create.is_feature_enabled") + @mock.patch("superset.databases.commands.update.is_feature_enabled") + @mock.patch( + "superset.models.core.Database.get_all_schema_names", + ) + def test_update_ssh_tunnel_via_database_api( + self, + mock_test_connection_database_command_run, + mock_create_is_feature_enabled, + mock_update_is_feature_enabled, + mock_get_all_schema_names, + ): + """ + Database API: Test update SSH Tunnel via Database API + """ + mock_create_is_feature_enabled.return_value = True + mock_update_is_feature_enabled.return_value = True + self.login(username="admin") + example_db = get_example_database() + + if example_db.backend == "sqlite": + return + initial_ssh_tunnel_properties = { + "server_address": "123.132.123.1", + "server_port": 8080, + "username": "foo", + "password": "bar", + } + updated_ssh_tunnel_properties = { + "server_address": "123.132.123.1", + "server_port": 8080, + "username": "Test", + "password": "new_bar", + } + database_data_with_ssh_tunnel = { + "database_name": "test-db-with-ssh-tunnel", + "sqlalchemy_uri": example_db.sqlalchemy_uri_decrypted, + "ssh_tunnel": initial_ssh_tunnel_properties, + } + database_data_with_ssh_tunnel_update = { + "database_name": "test-db-with-ssh-tunnel", + "sqlalchemy_uri": example_db.sqlalchemy_uri_decrypted, + "ssh_tunnel": updated_ssh_tunnel_properties, + } + + uri = "api/v1/database/" + rv = self.client.post(uri, json=database_data_with_ssh_tunnel) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(rv.status_code, 201) + model_ssh_tunnel = ( + db.session.query(SSHTunnel) + .filter(SSHTunnel.database_id == response.get("id")) + .one() + ) + self.assertEqual(model_ssh_tunnel.database_id, response.get("id")) + self.assertEqual(model_ssh_tunnel.username, "foo") + uri = "api/v1/database/{}".format(response.get("id")) + rv = self.client.put(uri, json=database_data_with_ssh_tunnel_update) + response_update = json.loads(rv.data.decode("utf-8")) + self.assertEqual(rv.status_code, 200) + model_ssh_tunnel = ( + db.session.query(SSHTunnel) + .filter(SSHTunnel.database_id == response_update.get("id")) + .one() + ) + self.assertEqual(model_ssh_tunnel.database_id, response_update.get("id")) + self.assertEqual( + response_update.get("result")["ssh_tunnel"]["password"], "XXXXXXXXXX" + ) + self.assertEqual(model_ssh_tunnel.username, "Test") + self.assertEqual(model_ssh_tunnel.server_address, "123.132.123.1") + self.assertEqual(model_ssh_tunnel.server_port, 8080) + # Cleanup + model = db.session.query(Database).get(response.get("id")) + db.session.delete(model) + db.session.commit() + + @mock.patch( + "superset.databases.commands.test_connection.TestConnectionDatabaseCommand.run", + ) + @mock.patch( + "superset.models.core.Database.get_all_schema_names", + ) + @mock.patch("superset.databases.commands.create.is_feature_enabled") + def test_cascade_delete_ssh_tunnel( + self, + mock_test_connection_database_command_run, + mock_get_all_schema_names, + mock_create_is_feature_enabled, + ): + """ + Database API: SSH Tunnel gets deleted if Database gets deleted + """ + mock_create_is_feature_enabled.return_value = True + self.login(username="admin") + example_db = get_example_database() + if example_db.backend == "sqlite": + return + ssh_tunnel_properties = { + "server_address": "123.132.123.1", + "server_port": 8080, + "username": "foo", + "password": "bar", + } + database_data = { + "database_name": "test-db-with-ssh-tunnel", + "sqlalchemy_uri": example_db.sqlalchemy_uri_decrypted, + "ssh_tunnel": ssh_tunnel_properties, + } + + uri = "api/v1/database/" + rv = self.client.post(uri, json=database_data) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(rv.status_code, 201) + model_ssh_tunnel = ( + db.session.query(SSHTunnel) + .filter(SSHTunnel.database_id == response.get("id")) + .one() + ) + self.assertEqual(model_ssh_tunnel.database_id, response.get("id")) + # Cleanup + model = db.session.query(Database).get(response.get("id")) + db.session.delete(model) + db.session.commit() + model_ssh_tunnel = ( + db.session.query(SSHTunnel) + .filter(SSHTunnel.database_id == response.get("id")) + .one_or_none() + ) + assert model_ssh_tunnel is None + + @mock.patch( + "superset.databases.commands.test_connection.TestConnectionDatabaseCommand.run", + ) + @mock.patch("superset.databases.commands.create.is_feature_enabled") + @mock.patch( + "superset.models.core.Database.get_all_schema_names", + ) + def test_do_not_create_database_if_ssh_tunnel_creation_fails( + self, + mock_test_connection_database_command_run, + mock_create_is_feature_enabled, + mock_get_all_schema_names, + ): + """ + Database API: Test Database is not created if SSH Tunnel creation fails + """ + mock_create_is_feature_enabled.return_value = True + self.login(username="admin") + example_db = get_example_database() + if example_db.backend == "sqlite": + return + ssh_tunnel_properties = { + "server_address": "123.132.123.1", + } + database_data = { + "database_name": "test-db-failure-ssh-tunnel", + "sqlalchemy_uri": example_db.sqlalchemy_uri_decrypted, + "ssh_tunnel": ssh_tunnel_properties, + } + fail_message = {"message": "SSH Tunnel parameters are invalid."} + + uri = "api/v1/database/" + rv = self.client.post(uri, json=database_data) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(rv.status_code, 422) + model_ssh_tunnel = ( + db.session.query(SSHTunnel) + .filter(SSHTunnel.database_id == response.get("id")) + .one_or_none() + ) + assert model_ssh_tunnel is None + self.assertEqual(response, fail_message) + # Cleanup + model = ( + db.session.query(Database) + .filter(Database.database_name == "test-db-failure-ssh-tunnel") + .one_or_none() + ) + # the DB should not be created + assert model is None + + @mock.patch( + "superset.databases.commands.test_connection.TestConnectionDatabaseCommand.run", + ) + @mock.patch("superset.databases.commands.create.is_feature_enabled") + @mock.patch( + "superset.models.core.Database.get_all_schema_names", + ) + def test_get_database_returns_related_ssh_tunnel( + self, + mock_test_connection_database_command_run, + mock_create_is_feature_enabled, + mock_get_all_schema_names, + ): + """ + Database API: Test GET Database returns its related SSH Tunnel + """ + mock_create_is_feature_enabled.return_value = True + self.login(username="admin") + example_db = get_example_database() + if example_db.backend == "sqlite": + return + ssh_tunnel_properties = { + "server_address": "123.132.123.1", + "server_port": 8080, + "username": "foo", + "password": "bar", + } + database_data = { + "database_name": "test-db-with-ssh-tunnel", + "sqlalchemy_uri": example_db.sqlalchemy_uri_decrypted, + "ssh_tunnel": ssh_tunnel_properties, + } + response_ssh_tunnel = { + "server_address": "123.132.123.1", + "server_port": 8080, + "username": "foo", + "password": "XXXXXXXXXX", + } + + uri = "api/v1/database/" + rv = self.client.post(uri, json=database_data) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(rv.status_code, 201) + model_ssh_tunnel = ( + db.session.query(SSHTunnel) + .filter(SSHTunnel.database_id == response.get("id")) + .one() + ) + self.assertEqual(model_ssh_tunnel.database_id, response.get("id")) + self.assertEqual(response.get("result")["ssh_tunnel"], response_ssh_tunnel) + # Cleanup + model = db.session.query(Database).get(response.get("id")) + db.session.delete(model) + db.session.commit() + + @mock.patch( + "superset.databases.commands.test_connection.TestConnectionDatabaseCommand.run", + ) + @mock.patch( + "superset.models.core.Database.get_all_schema_names", + ) + def test_if_ssh_tunneling_flag_is_not_active_it_raises_new_exception( + self, + mock_test_connection_database_command_run, + mock_get_all_schema_names, + ): + """ + Database API: Test raises SSHTunneling feature flag not enabled + """ + self.login(username="admin") + example_db = get_example_database() + if example_db.backend == "sqlite": + return + ssh_tunnel_properties = { + "server_address": "123.132.123.1", + "server_port": 8080, + "username": "foo", + "password": "bar", + } + database_data = { + "database_name": "test-db-with-ssh-tunnel-7", + "sqlalchemy_uri": example_db.sqlalchemy_uri_decrypted, + "ssh_tunnel": ssh_tunnel_properties, + } + + uri = "api/v1/database/" + rv = self.client.post(uri, json=database_data) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(rv.status_code, 400) + self.assertEqual(response, {"message": "SSH Tunneling is not enabled"}) + model_ssh_tunnel = ( + db.session.query(SSHTunnel) + .filter(SSHTunnel.database_id == response.get("id")) + .one_or_none() + ) + assert model_ssh_tunnel is None + # Cleanup + model = ( + db.session.query(Database) + .filter(Database.database_name == "test-db-with-ssh-tunnel-7") + .one_or_none() + ) + # the DB should not be created + assert model is None + def test_create_database_invalid_configuration_method(self): """ Database API: Test create with an invalid configuration method. @@ -375,7 +777,7 @@ def test_create_database_json_validate(self): "database_name": "test-create-database-invalid-json", "sqlalchemy_uri": example_db.sqlalchemy_uri_decrypted, "configuration_method": ConfigurationMethod.SQLALCHEMY_FORM, - "encrypted_extra": '{"A": "a", "B", "C"}', + "masked_encrypted_extra": '{"A": "a", "B", "C"}', "extra": '["A": "a", "B", "C"]', } @@ -384,7 +786,7 @@ def test_create_database_json_validate(self): response = json.loads(rv.data.decode("utf-8")) expected_response = { "message": { - "encrypted_extra": [ + "masked_encrypted_extra": [ "Field cannot be decoded by JSON. Expecting ':' " "delimiter: line 1 column 15 (char 14)" ], @@ -526,11 +928,55 @@ def test_create_database_conn_fail(self): self.login(username="admin") response = self.client.post(uri, json=database_data) response_data = json.loads(response.data.decode("utf-8")) - expected_response = { - "message": "Connection failed, please check your connection settings" + superset_error_mysql = SupersetError( + message='Either the username "superset" or the password is incorrect.', + error_type="CONNECTION_ACCESS_DENIED_ERROR", + level="error", + extra={ + "engine_name": "MySQL", + "invalid": ["username", "password"], + "issue_codes": [ + { + "code": 1014, + "message": ( + "Issue 1014 - Either the username or the password is wrong." + ), + }, + { + "code": 1015, + "message": ( + "Issue 1015 - Issue 1015 - Either the database is spelled incorrectly or does not exist." + ), + }, + ], + }, + ) + superset_error_postgres = SupersetError( + message='The password provided for username "superset" is incorrect.', + error_type="CONNECTION_INVALID_PASSWORD_ERROR", + level="error", + extra={ + "engine_name": "PostgreSQL", + "invalid": ["username", "password"], + "issue_codes": [ + { + "code": 1013, + "message": ( + "Issue 1013 - The password provided when connecting to a database is not valid." + ), + } + ], + }, + ) + expected_response_mysql = {"errors": [dataclasses.asdict(superset_error_mysql)]} + expected_response_postgres = { + "errors": [dataclasses.asdict(superset_error_postgres)] } - self.assertEqual(response.status_code, 422) - self.assertEqual(response_data, expected_response) + self.assertEqual(response.status_code, 500) + if example_db.backend == "mysql": + self.assertEqual(response_data, expected_response_mysql) + else: + self.assertEqual(response_data, expected_response_postgres) def test_update_database(self): """ @@ -1337,6 +1783,66 @@ def test_database_schemas_invalid_query(self): ) self.assertEqual(rv.status_code, 400) + def test_database_tables(self): + """ + Database API: Test database tables + """ + self.login(username="admin") + database = db.session.query(Database).filter_by(database_name="examples").one() + + schema_name = self.default_schema_backend_map[database.backend] + rv = self.client.get( + f"api/v1/database/{database.id}/tables/?q={prison.dumps({'schema_name': schema_name})}" + ) + + self.assertEqual(rv.status_code, 200) + if database.backend == "postgresql": + response = json.loads(rv.data.decode("utf-8")) + schemas = [ + s[0] for s in database.get_all_table_names_in_schema(schema_name) + ] + self.assertEquals(response["count"], len(schemas)) + for option in response["result"]: + self.assertEquals(option["extra"], None) + self.assertEquals(option["type"], "table") + self.assertTrue(option["value"] in schemas) + + def test_database_tables_not_found(self): + """ + Database API: Test database tables not found + """ + self.logout() + self.login(username="gamma") + example_db = get_example_database() + uri = f"api/v1/database/{example_db.id}/tables/?q={prison.dumps({'schema_name': 'non_existent'})}" + rv = self.client.get(uri) + self.assertEqual(rv.status_code, 404) + + def test_database_tables_invalid_query(self): + """ + Database API: Test database tables with invalid query + """ + self.login("admin") + database = db.session.query(Database).first() + rv = self.client.get( + f"api/v1/database/{database.id}/tables/?q={prison.dumps({'force': 'nop'})}" + ) + self.assertEqual(rv.status_code, 400) + + @mock.patch("superset.security.manager.SupersetSecurityManager.can_access_database") + def test_database_tables_unexpected_error(self, mock_can_access_database): + """ + Database API: Test database tables with unexpected error + """ + self.login(username="admin") + database = db.session.query(Database).filter_by(database_name="examples").one() + mock_can_access_database.side_effect = Exception("Test Error") + + rv = self.client.get( + f"api/v1/database/{database.id}/tables/?q={prison.dumps({'schema_name': 'main'})}" + ) + self.assertEqual(rv.status_code, 422) + def test_test_connection(self): """ Database API: Test test connection @@ -1354,13 +1860,13 @@ def test_test_connection(self): # validate that the endpoint works with the password-masked sqlalchemy uri data = { "database_name": "examples", - "encrypted_extra": "{}", + "masked_encrypted_extra": "{}", "extra": json.dumps(extra), "impersonate_user": False, "sqlalchemy_uri": example_db.safe_sqlalchemy_uri(), "server_cert": None, } - url = "api/v1/database/test_connection" + url = "api/v1/database/test_connection/" rv = self.post_assert_metric(url, data, "test_connection") self.assertEqual(rv.status_code, 200) self.assertEqual(rv.headers["Content-Type"], "application/json; charset=utf-8") @@ -1389,7 +1895,7 @@ def test_test_connection_failed(self): "impersonate_user": False, "server_cert": None, } - url = "api/v1/database/test_connection" + url = "api/v1/database/test_connection/" rv = self.post_assert_metric(url, data, "test_connection") self.assertEqual(rv.status_code, 422) self.assertEqual(rv.headers["Content-Type"], "application/json; charset=utf-8") @@ -1426,7 +1932,7 @@ def test_test_connection_failed(self): expected_response = { "errors": [ { - "message": "Could not load database driver: AzureSynapseSpec", + "message": "Could not load database driver: MssqlEngineSpec", "error_type": "GENERIC_COMMAND_ERROR", "level": "warning", "extra": { @@ -1455,7 +1961,7 @@ def test_test_connection_unsafe_uri(self): "impersonate_user": False, "server_cert": None, } - url = "api/v1/database/test_connection" + url = "api/v1/database/test_connection/" rv = self.post_assert_metric(url, data, "test_connection") self.assertEqual(rv.status_code, 400) response = json.loads(rv.data.decode("utf-8")) @@ -1514,10 +2020,10 @@ def test_test_connection_failed_invalid_hostname( "impersonate_user": False, "server_cert": None, } - url = "api/v1/database/test_connection" + url = "api/v1/database/test_connection/" rv = self.post_assert_metric(url, data, "test_connection") - assert rv.status_code == 422 + assert rv.status_code == 500 assert rv.headers["Content-Type"] == "application/json; charset=utf-8" response = json.loads(rv.data.decode("utf-8")) expected_response = {"errors": [dataclasses.asdict(superset_error)]} @@ -1628,8 +2134,8 @@ def test_import_database(self): assert str(dataset.uuid) == dataset_config["uuid"] dataset.owners = [] - database.owners = [] db.session.delete(dataset) + db.session.commit() db.session.delete(database) db.session.commit() @@ -1699,8 +2205,8 @@ def test_import_database_overwrite(self): ) dataset = database.tables[0] dataset.owners = [] - database.owners = [] db.session.delete(dataset) + db.session.commit() db.session.delete(database) db.session.commit() @@ -1943,6 +2449,10 @@ def test_available(self, app, get_available_engine_specs): }, "preferred": True, "sqlalchemy_uri_placeholder": "postgresql://user:password@host:port/dbname[?key=value&key=value...]", + "engine_information": { + "supports_file_upload": True, + "disable_ssh_tunneling": False, + }, }, { "available_drivers": ["bigquery"], @@ -1962,6 +2472,10 @@ def test_available(self, app, get_available_engine_specs): }, "preferred": True, "sqlalchemy_uri_placeholder": "bigquery://{project_id}", + "engine_information": { + "supports_file_upload": True, + "disable_ssh_tunneling": True, + }, }, { "available_drivers": ["psycopg2"], @@ -2010,6 +2524,10 @@ def test_available(self, app, get_available_engine_specs): }, "preferred": False, "sqlalchemy_uri_placeholder": "redshift+psycopg2://user:password@host:port/dbname[?key=value&key=value...]", + "engine_information": { + "supports_file_upload": True, + "disable_ssh_tunneling": False, + }, }, { "available_drivers": ["apsw"], @@ -2029,6 +2547,10 @@ def test_available(self, app, get_available_engine_specs): }, "preferred": False, "sqlalchemy_uri_placeholder": "gsheets://", + "engine_information": { + "supports_file_upload": False, + "disable_ssh_tunneling": True, + }, }, { "available_drivers": ["mysqlconnector", "mysqldb"], @@ -2077,12 +2599,20 @@ def test_available(self, app, get_available_engine_specs): }, "preferred": False, "sqlalchemy_uri_placeholder": "mysql://user:password@host:port/dbname[?key=value&key=value...]", + "engine_information": { + "supports_file_upload": True, + "disable_ssh_tunneling": False, + }, }, { "available_drivers": [""], "engine": "hana", "name": "SAP HANA", "preferred": False, + "engine_information": { + "supports_file_upload": True, + "disable_ssh_tunneling": False, + }, }, ] } @@ -2110,19 +2640,27 @@ def test_available_no_default(self, app, get_available_engine_specs): "engine": "mysql", "name": "MySQL", "preferred": True, + "engine_information": { + "supports_file_upload": True, + "disable_ssh_tunneling": False, + }, }, { "available_drivers": [""], "engine": "hana", "name": "SAP HANA", "preferred": False, + "engine_information": { + "supports_file_upload": True, + "disable_ssh_tunneling": False, + }, }, ] } def test_validate_parameters_invalid_payload_format(self): self.login(username="admin") - url = "api/v1/database/validate_parameters" + url = "api/v1/database/validate_parameters/" rv = self.client.post(url, data="INVALID", content_type="text/plain") response = json.loads(rv.data.decode("utf-8")) @@ -2147,7 +2685,7 @@ def test_validate_parameters_invalid_payload_format(self): def test_validate_parameters_invalid_payload_schema(self): self.login(username="admin") - url = "api/v1/database/validate_parameters" + url = "api/v1/database/validate_parameters/" payload = {"foo": "bar"} rv = self.client.post(url, json=payload) response = json.loads(rv.data.decode("utf-8")) @@ -2191,7 +2729,7 @@ def test_validate_parameters_invalid_payload_schema(self): def test_validate_parameters_missing_fields(self): self.login(username="admin") - url = "api/v1/database/validate_parameters" + url = "api/v1/database/validate_parameters/" payload = { "configuration_method": ConfigurationMethod.SQLALCHEMY_FORM, "engine": "postgresql", @@ -2242,7 +2780,7 @@ def test_validate_parameters_valid_payload( is_port_open.return_value = True self.login(username="admin") - url = "api/v1/database/validate_parameters" + url = "api/v1/database/validate_parameters/" payload = { "engine": "postgresql", "parameters": defaultdict(dict), @@ -2266,7 +2804,7 @@ def test_validate_parameters_valid_payload( def test_validate_parameters_invalid_port(self): self.login(username="admin") - url = "api/v1/database/validate_parameters" + url = "api/v1/database/validate_parameters/" payload = { "engine": "postgresql", "parameters": defaultdict(dict), @@ -2325,7 +2863,7 @@ def test_validate_parameters_invalid_host(self, is_hostname_valid): is_hostname_valid.return_value = False self.login(username="admin") - url = "api/v1/database/validate_parameters" + url = "api/v1/database/validate_parameters/" payload = { "engine": "postgresql", "parameters": defaultdict(dict), @@ -2385,7 +2923,7 @@ def test_validate_parameters_invalid_port_range(self, is_hostname_valid): is_hostname_valid.return_value = True self.login(username="admin") - url = "api/v1/database/validate_parameters" + url = "api/v1/database/validate_parameters/" payload = { "engine": "postgresql", "parameters": defaultdict(dict), @@ -2468,7 +3006,7 @@ def test_validate_sql(self): pytest.skip("Only presto and PG are implemented") self.login(username="admin") - uri = f"api/v1/database/{example_db.id}/validate_sql" + uri = f"api/v1/database/{example_db.id}/validate_sql/" rv = self.client.post(uri, json=request_payload) response = json.loads(rv.data.decode("utf-8")) self.assertEqual(rv.status_code, 200) @@ -2494,7 +3032,7 @@ def test_validate_sql_errors(self): pytest.skip("Only presto and PG are implemented") self.login(username="admin") - uri = f"api/v1/database/{example_db.id}/validate_sql" + uri = f"api/v1/database/{example_db.id}/validate_sql/" rv = self.client.post(uri, json=request_payload) response = json.loads(rv.data.decode("utf-8")) self.assertEqual(rv.status_code, 200) @@ -2526,7 +3064,7 @@ def test_validate_sql_not_found(self): } self.login(username="admin") uri = ( - f"api/v1/database/{self.get_nonexistent_numeric_id(Database)}/validate_sql" + f"api/v1/database/{self.get_nonexistent_numeric_id(Database)}/validate_sql/" ) rv = self.client.post(uri, json=request_payload) self.assertEqual(rv.status_code, 404) @@ -2547,7 +3085,7 @@ def test_validate_sql_validation_fails(self): } self.login(username="admin") uri = ( - f"api/v1/database/{self.get_nonexistent_numeric_id(Database)}/validate_sql" + f"api/v1/database/{self.get_nonexistent_numeric_id(Database)}/validate_sql/" ) rv = self.client.post(uri, json=request_payload) response = json.loads(rv.data.decode("utf-8")) @@ -2572,7 +3110,7 @@ def test_validate_sql_endpoint_noconfig(self): example_db = get_example_database() - uri = f"api/v1/database/{example_db.id}/validate_sql" + uri = f"api/v1/database/{example_db.id}/validate_sql/" rv = self.client.post(uri, json=request_payload) response = json.loads(rv.data.decode("utf-8")) self.assertEqual(rv.status_code, 422) @@ -2625,7 +3163,7 @@ def test_validate_sql_endpoint_failure(self, get_validator_by_name): example_db = get_example_database() - uri = f"api/v1/database/{example_db.id}/validate_sql" + uri = f"api/v1/database/{example_db.id}/validate_sql/" rv = self.client.post(uri, json=request_payload) response = json.loads(rv.data.decode("utf-8")) diff --git a/tests/integration_tests/databases/commands_tests.py b/tests/integration_tests/databases/commands_tests.py index 7f9daedea743c..7e4fcaad789ed 100644 --- a/tests/integration_tests/databases/commands_tests.py +++ b/tests/integration_tests/databases/commands_tests.py @@ -31,18 +31,20 @@ DatabaseInvalidError, DatabaseNotFoundError, DatabaseSecurityUnsafeError, + DatabaseTablesUnexpectedError, DatabaseTestConnectionDriverError, - DatabaseTestConnectionFailedError, DatabaseTestConnectionUnexpectedError, ) from superset.databases.commands.export import ExportDatabasesCommand from superset.databases.commands.importers.v1 import ImportDatabasesCommand +from superset.databases.commands.tables import TablesDatabaseCommand from superset.databases.commands.test_connection import TestConnectionDatabaseCommand from superset.databases.commands.validate import ValidateDatabaseParametersCommand from superset.databases.schemas import DatabaseTestConnectionSchema from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import ( SupersetErrorsException, + SupersetException, SupersetSecurityException, SupersetTimeoutException, ) @@ -70,10 +72,11 @@ class TestCreateDatabaseCommand(SupersetTestCase): @mock.patch( "superset.databases.commands.test_connection.event_logger.log_with_context" ) - def test_create_duplicate_error(self, mock_logger): + @mock.patch("superset.utils.core.g") + def test_create_duplicate_error(self, mock_g, mock_logger): example_db = get_example_database() + mock_g.user = security_manager.find_user("admin") command = CreateDatabaseCommand( - security_manager.find_user("admin"), {"database_name": example_db.database_name}, ) with pytest.raises(DatabaseInvalidError) as excinfo: @@ -90,8 +93,10 @@ def test_create_duplicate_error(self, mock_logger): @mock.patch( "superset.databases.commands.test_connection.event_logger.log_with_context" ) - def test_multiple_error_logging(self, mock_logger): - command = CreateDatabaseCommand(security_manager.find_user("admin"), {}) + @mock.patch("superset.utils.core.g") + def test_multiple_error_logging(self, mock_g, mock_logger): + mock_g.user = security_manager.find_user("admin") + command = CreateDatabaseCommand({}) with pytest.raises(DatabaseInvalidError) as excinfo: command.run() assert str(excinfo.value) == ("Database parameters are invalid.") @@ -157,6 +162,7 @@ def test_export_database_command(self, mock_g): "allow_csv_upload": True, "allow_ctas": True, "allow_cvas": True, + "allow_dml": True, "allow_run_async": False, "cache_timeout": None, "database_name": "examples", @@ -360,6 +366,7 @@ def test_export_database_command_key_order(self, mock_g): "allow_run_async", "allow_ctas", "allow_cvas", + "allow_dml", "allow_csv_upload", "extra", "uuid", @@ -403,6 +410,7 @@ def test_import_v1_database(self): assert database.allow_file_upload assert database.allow_ctas assert database.allow_cvas + assert database.allow_dml assert not database.allow_run_async assert database.cache_timeout is None assert database.database_name == "imported_database" @@ -438,6 +446,7 @@ def test_import_v1_database_broken_csv_fields(self): assert database.allow_file_upload assert database.allow_ctas assert database.allow_cvas + assert database.allow_dml assert not database.allow_run_async assert database.cache_timeout is None assert database.database_name == "imported_database" @@ -639,19 +648,21 @@ def test_import_v1_rollback(self, mock_import_dataset): class TestTestConnectionDatabaseCommand(SupersetTestCase): - @mock.patch("superset.databases.dao.Database.get_sqla_engine") + @mock.patch("superset.databases.dao.Database._get_sqla_engine") @mock.patch( "superset.databases.commands.test_connection.event_logger.log_with_context" ) - def test_connection_db_exception(self, mock_event_logger, mock_get_sqla_engine): + @mock.patch("superset.utils.core.g") + def test_connection_db_exception( + self, mock_g, mock_event_logger, mock_get_sqla_engine + ): """Test to make sure event_logger is called when an exception is raised""" database = get_example_database() + mock_g.user = security_manager.find_user("admin") mock_get_sqla_engine.side_effect = Exception("An error has occurred!") db_uri = database.sqlalchemy_uri_decrypted json_payload = {"sqlalchemy_uri": db_uri} - command_without_db_name = TestConnectionDatabaseCommand( - security_manager.find_user("admin"), json_payload - ) + command_without_db_name = TestConnectionDatabaseCommand(json_payload) with pytest.raises(DatabaseTestConnectionUnexpectedError) as excinfo: command_without_db_name.run() @@ -660,25 +671,25 @@ def test_connection_db_exception(self, mock_event_logger, mock_get_sqla_engine): ) mock_event_logger.assert_called() - @mock.patch("superset.databases.dao.Database.get_sqla_engine") + @mock.patch("superset.databases.dao.Database._get_sqla_engine") @mock.patch( "superset.databases.commands.test_connection.event_logger.log_with_context" ) + @mock.patch("superset.utils.core.g") def test_connection_do_ping_exception( - self, mock_event_logger, mock_get_sqla_engine + self, mock_g, mock_event_logger, mock_get_sqla_engine ): """Test to make sure do_ping exceptions gets captured""" database = get_example_database() + mock_g.user = security_manager.find_user("admin") mock_get_sqla_engine.return_value.dialect.do_ping.side_effect = Exception( "An error has occurred!" ) db_uri = database.sqlalchemy_uri_decrypted json_payload = {"sqlalchemy_uri": db_uri} - command_without_db_name = TestConnectionDatabaseCommand( - security_manager.find_user("admin"), json_payload - ) + command_without_db_name = TestConnectionDatabaseCommand(json_payload) - with pytest.raises(DatabaseTestConnectionFailedError) as excinfo: + with pytest.raises(SupersetErrorsException) as excinfo: command_without_db_name.run() assert ( excinfo.value.errors[0].error_type @@ -689,15 +700,17 @@ def test_connection_do_ping_exception( @mock.patch( "superset.databases.commands.test_connection.event_logger.log_with_context" ) - def test_connection_do_ping_timeout(self, mock_event_logger, mock_func_timeout): + @mock.patch("superset.utils.core.g") + def test_connection_do_ping_timeout( + self, mock_g, mock_event_logger, mock_func_timeout + ): """Test to make sure do_ping exceptions gets captured""" database = get_example_database() + mock_g.user = security_manager.find_user("admin") mock_func_timeout.side_effect = FunctionTimedOut("Time out") db_uri = database.sqlalchemy_uri_decrypted json_payload = {"sqlalchemy_uri": db_uri} - command_without_db_name = TestConnectionDatabaseCommand( - security_manager.find_user("admin"), json_payload - ) + command_without_db_name = TestConnectionDatabaseCommand(json_payload) with pytest.raises(SupersetTimeoutException) as excinfo: command_without_db_name.run() @@ -707,24 +720,24 @@ def test_connection_do_ping_timeout(self, mock_event_logger, mock_func_timeout): == SupersetErrorType.CONNECTION_DATABASE_TIMEOUT ) - @mock.patch("superset.databases.dao.Database.get_sqla_engine") + @mock.patch("superset.databases.dao.Database._get_sqla_engine") @mock.patch( "superset.databases.commands.test_connection.event_logger.log_with_context" ) + @mock.patch("superset.utils.core.g") def test_connection_superset_security_connection( - self, mock_event_logger, mock_get_sqla_engine + self, mock_g, mock_event_logger, mock_get_sqla_engine ): """Test to make sure event_logger is called when security connection exc is raised""" database = get_example_database() + mock_g.user = security_manager.find_user("admin") mock_get_sqla_engine.side_effect = SupersetSecurityException( SupersetError(error_type=500, message="test", level="info") ) db_uri = database.sqlalchemy_uri_decrypted json_payload = {"sqlalchemy_uri": db_uri} - command_without_db_name = TestConnectionDatabaseCommand( - security_manager.find_user("admin"), json_payload - ) + command_without_db_name = TestConnectionDatabaseCommand(json_payload) with pytest.raises(DatabaseSecurityUnsafeError) as excinfo: command_without_db_name.run() @@ -732,23 +745,25 @@ def test_connection_superset_security_connection( mock_event_logger.assert_called() - @mock.patch("superset.databases.dao.Database.get_sqla_engine") + @mock.patch("superset.databases.dao.Database._get_sqla_engine") @mock.patch( "superset.databases.commands.test_connection.event_logger.log_with_context" ) - def test_connection_db_api_exc(self, mock_event_logger, mock_get_sqla_engine): + @mock.patch("superset.utils.core.g") + def test_connection_db_api_exc( + self, mock_g, mock_event_logger, mock_get_sqla_engine + ): """Test to make sure event_logger is called when DBAPIError is raised""" database = get_example_database() + mock_g.user = security_manager.find_user("admin") mock_get_sqla_engine.side_effect = DBAPIError( statement="error", params={}, orig={} ) db_uri = database.sqlalchemy_uri_decrypted json_payload = {"sqlalchemy_uri": db_uri} - command_without_db_name = TestConnectionDatabaseCommand( - security_manager.find_user("admin"), json_payload - ) + command_without_db_name = TestConnectionDatabaseCommand(json_payload) - with pytest.raises(DatabaseTestConnectionFailedError) as excinfo: + with pytest.raises(SupersetErrorsException) as excinfo: command_without_db_name.run() assert str(excinfo.value) == ( "Connection failed, please check your connection settings" @@ -778,7 +793,7 @@ def test_validate(DatabaseDAO, is_port_open, is_hostname_valid, app_context): "query": {}, }, } - command = ValidateDatabaseParametersCommand(None, payload) + command = ValidateDatabaseParametersCommand(payload) command.run() @@ -802,7 +817,7 @@ def test_validate_partial(is_port_open, is_hostname_valid, app_context): "query": {}, }, } - command = ValidateDatabaseParametersCommand(None, payload) + command = ValidateDatabaseParametersCommand(payload) with pytest.raises(SupersetErrorsException) as excinfo: command.run() assert excinfo.value.errors == [ @@ -841,7 +856,7 @@ def test_validate_partial_invalid_hostname(is_hostname_valid, app_context): "query": {}, }, } - command = ValidateDatabaseParametersCommand(None, payload) + command = ValidateDatabaseParametersCommand(payload) with pytest.raises(SupersetErrorsException) as excinfo: command.run() assert excinfo.value.errors == [ @@ -874,3 +889,74 @@ def test_validate_partial_invalid_hostname(is_hostname_valid, app_context): }, ), ] + + +class TestTablesDatabaseCommand(SupersetTestCase): + @mock.patch("superset.databases.dao.DatabaseDAO.find_by_id") + def test_database_tables_list_with_unknown_database(self, mock_find_by_id): + mock_find_by_id.return_value = None + command = TablesDatabaseCommand(1, "test", False) + + with pytest.raises(DatabaseNotFoundError) as excinfo: + command.run() + assert str(excinfo.value) == ("Database not found.") + + @mock.patch("superset.databases.dao.DatabaseDAO.find_by_id") + @mock.patch("superset.security.manager.SupersetSecurityManager.can_access_database") + @mock.patch("superset.utils.core.g") + def test_database_tables_superset_exception( + self, mock_g, mock_can_access_database, mock_find_by_id + ): + database = get_example_database() + if database.backend == "mysql": + return + + mock_find_by_id.return_value = database + mock_can_access_database.side_effect = SupersetException("Test Error") + mock_g.user = security_manager.find_user("admin") + + command = TablesDatabaseCommand(database.id, "main", False) + with pytest.raises(SupersetException) as excinfo: + command.run() + assert str(excinfo.value) == "Test Error" + + @mock.patch("superset.databases.dao.DatabaseDAO.find_by_id") + @mock.patch("superset.security.manager.SupersetSecurityManager.can_access_database") + @mock.patch("superset.utils.core.g") + def test_database_tables_exception( + self, mock_g, mock_can_access_database, mock_find_by_id + ): + database = get_example_database() + mock_find_by_id.return_value = database + mock_can_access_database.side_effect = Exception("Test Error") + mock_g.user = security_manager.find_user("admin") + + command = TablesDatabaseCommand(database.id, "main", False) + with pytest.raises(DatabaseTablesUnexpectedError) as excinfo: + command.run() + assert ( + str(excinfo.value) + == "Unexpected error occurred, please check your logs for details" + ) + + @mock.patch("superset.databases.dao.DatabaseDAO.find_by_id") + @mock.patch("superset.security.manager.SupersetSecurityManager.can_access_database") + @mock.patch("superset.utils.core.g") + def test_database_tables_list_tables( + self, mock_g, mock_can_access_database, mock_find_by_id + ): + database = get_example_database() + mock_find_by_id.return_value = database + mock_can_access_database.return_value = True + mock_g.user = security_manager.find_user("admin") + + schema_name = self.default_schema_backend_map[database.backend] + if database.backend == "postgresql" or database.backend == "mysql": + return + + command = TablesDatabaseCommand(database.id, schema_name, False) + result = command.run() + + assert result["count"] > 0 + assert len(result["result"]) > 0 + assert len(result["result"]) == result["count"] diff --git a/tests/integration_tests/databases/schema_tests.py b/tests/integration_tests/databases/schema_tests.py deleted file mode 100644 index 1f8ca067f6b0d..0000000000000 --- a/tests/integration_tests/databases/schema_tests.py +++ /dev/null @@ -1,153 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from marshmallow import fields, Schema, ValidationError - -from superset.databases.schemas import DatabaseParametersSchemaMixin -from superset.db_engine_specs.base import BasicParametersMixin -from superset.models.core import ConfigurationMethod - - -class DummySchema(Schema, DatabaseParametersSchemaMixin): - sqlalchemy_uri = fields.String() - - -class DummyEngine(BasicParametersMixin): - engine = "dummy" - default_driver = "dummy" - - -class InvalidEngine: - pass - - -@mock.patch("superset.databases.schemas.get_engine_specs") -def test_database_parameters_schema_mixin(get_engine_specs): - get_engine_specs.return_value = {"dummy_engine": DummyEngine} - payload = { - "engine": "dummy_engine", - "configuration_method": ConfigurationMethod.DYNAMIC_FORM, - "parameters": { - "username": "username", - "password": "password", - "host": "localhost", - "port": 12345, - "database": "dbname", - }, - } - schema = DummySchema() - result = schema.load(payload) - assert result == { - "configuration_method": ConfigurationMethod.DYNAMIC_FORM, - "sqlalchemy_uri": "dummy+dummy://username:password@localhost:12345/dbname", - } - - -def test_database_parameters_schema_mixin_no_engine(): - payload = { - "configuration_method": ConfigurationMethod.DYNAMIC_FORM, - "parameters": { - "username": "username", - "password": "password", - "host": "localhost", - "port": 12345, - "dbname": "dbname", - }, - } - schema = DummySchema() - try: - schema.load(payload) - except ValidationError as err: - assert err.messages == { - "_schema": [ - "An engine must be specified when passing individual parameters to a database." - ] - } - - -@mock.patch("superset.databases.schemas.get_engine_specs") -def test_database_parameters_schema_mixin_invalid_engine(get_engine_specs): - get_engine_specs.return_value = {} - payload = { - "engine": "dummy_engine", - "configuration_method": ConfigurationMethod.DYNAMIC_FORM, - "parameters": { - "username": "username", - "password": "password", - "host": "localhost", - "port": 12345, - "dbname": "dbname", - }, - } - schema = DummySchema() - try: - schema.load(payload) - except ValidationError as err: - assert err.messages == { - "_schema": ['Engine "dummy_engine" is not a valid engine.'] - } - - -@mock.patch("superset.databases.schemas.get_engine_specs") -def test_database_parameters_schema_no_mixin(get_engine_specs): - get_engine_specs.return_value = {"invalid_engine": InvalidEngine} - payload = { - "engine": "invalid_engine", - "configuration_method": ConfigurationMethod.DYNAMIC_FORM, - "parameters": { - "username": "username", - "password": "password", - "host": "localhost", - "port": 12345, - "database": "dbname", - }, - } - schema = DummySchema() - try: - schema.load(payload) - except ValidationError as err: - assert err.messages == { - "_schema": [ - ( - 'Engine spec "InvalidEngine" does not support ' - "being configured via individual parameters." - ) - ] - } - - -@mock.patch("superset.databases.schemas.get_engine_specs") -def test_database_parameters_schema_mixin_invalid_type(get_engine_specs): - get_engine_specs.return_value = {"dummy_engine": DummyEngine} - payload = { - "engine": "dummy_engine", - "configuration_method": ConfigurationMethod.DYNAMIC_FORM, - "parameters": { - "username": "username", - "password": "password", - "host": "localhost", - "port": "badport", - "database": "dbname", - }, - } - schema = DummySchema() - try: - schema.load(payload) - except ValidationError as err: - assert err.messages == {"port": ["Not a valid integer."]} diff --git a/tests/integration_tests/databases/ssh_tunnel/__init__.py b/tests/integration_tests/databases/ssh_tunnel/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/integration_tests/databases/ssh_tunnel/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/integration_tests/databases/ssh_tunnel/commands/__init__.py b/tests/integration_tests/databases/ssh_tunnel/commands/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/integration_tests/databases/ssh_tunnel/commands/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/integration_tests/databases/ssh_tunnel/commands/commands_tests.py b/tests/integration_tests/databases/ssh_tunnel/commands/commands_tests.py new file mode 100644 index 0000000000000..86c280b9bb1c4 --- /dev/null +++ b/tests/integration_tests/databases/ssh_tunnel/commands/commands_tests.py @@ -0,0 +1,78 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from unittest import mock, skip +from unittest.mock import patch + +import pytest + +from superset import security_manager +from superset.databases.ssh_tunnel.commands.create import CreateSSHTunnelCommand +from superset.databases.ssh_tunnel.commands.delete import DeleteSSHTunnelCommand +from superset.databases.ssh_tunnel.commands.exceptions import ( + SSHTunnelInvalidError, + SSHTunnelNotFoundError, +) +from superset.databases.ssh_tunnel.commands.update import UpdateSSHTunnelCommand +from tests.integration_tests.base_tests import SupersetTestCase + + +class TestCreateSSHTunnelCommand(SupersetTestCase): + @mock.patch("superset.utils.core.g") + def test_create_invalid_database_id(self, mock_g): + mock_g.user = security_manager.find_user("admin") + command = CreateSSHTunnelCommand( + None, + { + "server_address": "127.0.0.1", + "server_port": 5432, + "username": "test_user", + }, + ) + with pytest.raises(SSHTunnelInvalidError) as excinfo: + command.run() + assert str(excinfo.value) == ("SSH Tunnel parameters are invalid.") + + +class TestUpdateSSHTunnelCommand(SupersetTestCase): + @mock.patch("superset.utils.core.g") + def test_update_ssh_tunnel_not_found(self, mock_g): + mock_g.user = security_manager.find_user("admin") + # We have not created a SSH Tunnel yet so id = 1 is invalid + command = UpdateSSHTunnelCommand( + 1, + { + "server_address": "127.0.0.1", + "server_port": 5432, + "username": "test_user", + }, + ) + with pytest.raises(SSHTunnelNotFoundError) as excinfo: + command.run() + assert str(excinfo.value) == ("SSH Tunnel not found.") + + +class TestDeleteSSHTunnelCommand(SupersetTestCase): + @mock.patch("superset.utils.core.g") + @mock.patch("superset.databases.ssh_tunnel.commands.delete.is_feature_enabled") + def test_delete_ssh_tunnel_not_found(self, mock_g, mock_delete_is_feature_enabled): + mock_g.user = security_manager.find_user("admin") + mock_delete_is_feature_enabled.return_value = True + # We have not created a SSH Tunnel yet so id = 1 is invalid + command = DeleteSSHTunnelCommand(1) + with pytest.raises(SSHTunnelNotFoundError) as excinfo: + command.run() + assert str(excinfo.value) == ("SSH Tunnel not found.") diff --git a/tests/integration_tests/datasets/api_tests.py b/tests/integration_tests/datasets/api_tests.py index 24c48845a1101..1331a20dc4924 100644 --- a/tests/integration_tests/datasets/api_tests.py +++ b/tests/integration_tests/datasets/api_tests.py @@ -25,16 +25,16 @@ import prison import pytest import yaml +from sqlalchemy.orm import joinedload from sqlalchemy.sql import func -from superset.common.utils.query_cache_manager import QueryCacheManager from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn -from superset.constants import CacheRegion from superset.dao.exceptions import ( DAOCreateFailedError, DAODeleteFailedError, DAOUpdateFailedError, ) +from superset.datasets.commands.exceptions import DatasetCreateFailedError from superset.datasets.models import Dataset from superset.extensions import db, security_manager from superset.models.core import Database @@ -97,13 +97,25 @@ def insert_default_dataset(self): def get_fixture_datasets(self) -> List[SqlaTable]: return ( db.session.query(SqlaTable) + .options(joinedload(SqlaTable.database)) .filter(SqlaTable.table_name.in_(self.fixture_tables_names)) .all() ) + def get_fixture_virtual_datasets(self) -> List[SqlaTable]: + return ( + db.session.query(SqlaTable) + .filter(SqlaTable.table_name.in_(self.fixture_virtual_table_names)) + .all() + ) + @pytest.fixture() def create_virtual_datasets(self): with self.create_app().app_context(): + if backend() == "sqlite": + yield + return + datasets = [] admin = self.get_user("admin") main_db = get_main_database() @@ -126,6 +138,10 @@ def create_virtual_datasets(self): @pytest.fixture() def create_datasets(self): with self.create_app().app_context(): + if backend() == "sqlite": + yield + return + datasets = [] admin = self.get_user("admin") main_db = get_main_database() @@ -172,6 +188,9 @@ def test_get_dataset_list(self): """ Dataset API: Test get dataset list """ + if backend() == "sqlite": + return + example_db = get_example_database() self.login(username="admin") arguments = { @@ -210,6 +229,9 @@ def test_get_dataset_list_gamma(self): """ Dataset API: Test get dataset list gamma """ + if backend() == "sqlite": + return + self.login(username="gamma") uri = "api/v1/dataset/" rv = self.get_assert_metric(uri, "get_list") @@ -221,6 +243,9 @@ def test_get_dataset_list_gamma_owned(self): """ Dataset API: Test get dataset list owned by gamma """ + if backend() == "sqlite": + return + main_db = get_main_database() owned_dataset = self.insert_dataset( "ab_user", [self.get_user("gamma").id], main_db @@ -242,6 +267,18 @@ def test_get_dataset_related_database_gamma(self): """ Dataset API: Test get dataset related databases gamma """ + if backend() == "sqlite": + return + + # Add main database access to gamma role + main_db = get_main_database() + main_db_pvm = security_manager.find_permission_view_menu( + "database_access", main_db.perm + ) + gamma_role = security_manager.find_role("Gamma") + gamma_role.permissions.append(main_db_pvm) + db.session.commit() + self.login(username="gamma") uri = "api/v1/dataset/related/database" rv = self.client.get(uri) @@ -252,11 +289,18 @@ def test_get_dataset_related_database_gamma(self): main_db = get_main_database() assert filter(lambda x: x.text == main_db, response["result"]) != [] + # revert gamma permission + gamma_role.permissions.remove(main_db_pvm) + db.session.commit() + @pytest.mark.usefixtures("load_energy_table_with_slice") def test_get_dataset_item(self): """ Dataset API: Test get dataset item """ + if backend() == "sqlite": + return + table = self.get_energy_usage_dataset() main_db = get_main_database() self.login(username="admin") @@ -297,6 +341,8 @@ def test_get_dataset_distinct_schema(self): """ Dataset API: Test get dataset distinct schema """ + if backend() == "sqlite": + return def pg_test_query_parameter(query_parameter, expected_response): uri = f"api/v1/dataset/distinct/schema?q={prison.dumps(query_parameter)}" @@ -321,12 +367,18 @@ def pg_test_query_parameter(query_parameter, expected_response): schema="information_schema", ) ) - schema_values = [ - "information_schema", - "public", - ] + all_datasets = db.session.query(SqlaTable).all() + schema_values = sorted( + set( + [ + dataset.schema + for dataset in all_datasets + if dataset.schema is not None + ] + ) + ) expected_response = { - "count": 2, + "count": len(schema_values), "result": [{"text": val, "value": val} for val in schema_values], } self.login(username="admin") @@ -352,10 +404,8 @@ def pg_test_query_parameter(query_parameter, expected_response): pg_test_query_parameter( query_parameter, { - "count": 2, - "result": [ - {"text": "information_schema", "value": "information_schema"} - ], + "count": len(schema_values), + "result": [expected_response["result"][0]], }, ) @@ -367,6 +417,9 @@ def test_get_dataset_distinct_not_allowed(self): """ Dataset API: Test get dataset distinct not allowed """ + if backend() == "sqlite": + return + self.login(username="admin") uri = "api/v1/dataset/distinct/table_name" rv = self.client.get(uri) @@ -376,6 +429,9 @@ def test_get_dataset_distinct_gamma(self): """ Dataset API: Test get dataset distinct with gamma """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="gamma") @@ -393,6 +449,9 @@ def test_get_dataset_info(self): """ Dataset API: Test get dataset info """ + if backend() == "sqlite": + return + self.login(username="admin") uri = "api/v1/dataset/_info" rv = self.get_assert_metric(uri, "info") @@ -402,18 +461,30 @@ def test_info_security_dataset(self): """ Dataset API: Test info security """ + if backend() == "sqlite": + return + self.login(username="admin") params = {"keys": ["permissions"]} uri = f"api/v1/dataset/_info?q={prison.dumps(params)}" rv = self.get_assert_metric(uri, "info") data = json.loads(rv.data.decode("utf-8")) assert rv.status_code == 200 - assert set(data["permissions"]) == {"can_read", "can_write", "can_export"} + assert set(data["permissions"]) == { + "can_read", + "can_write", + "can_export", + "can_duplicate", + "can_get_or_create_dataset", + } def test_create_dataset_item(self): """ Dataset API: Test create dataset item """ + if backend() == "sqlite": + return + main_db = get_main_database() self.login(username="admin") table_data = { @@ -456,6 +527,9 @@ def test_create_dataset_item_gamma(self): """ Dataset API: Test create dataset item gamma """ + if backend() == "sqlite": + return + self.login(username="gamma") main_db = get_main_database() table_data = { @@ -471,6 +545,9 @@ def test_create_dataset_item_owner(self): """ Dataset API: Test create item owner """ + if backend() == "sqlite": + return + main_db = get_main_database() self.login(username="alpha") admin = self.get_user("admin") @@ -496,6 +573,9 @@ def test_create_dataset_item_owners_invalid(self): """ Dataset API: Test create dataset item owner invalid """ + if backend() == "sqlite": + return + admin = self.get_user("admin") main_db = get_main_database() self.login(username="admin") @@ -517,6 +597,9 @@ def test_create_dataset_validate_uniqueness(self): """ Dataset API: Test create dataset validate table uniqueness """ + if backend() == "sqlite": + return + schema = get_example_default_schema() energy_usage_ds = self.get_energy_usage_dataset() self.login(username="admin") @@ -533,6 +616,61 @@ def test_create_dataset_validate_uniqueness(self): "message": {"table_name": ["Dataset energy_usage already exists"]} } + @pytest.mark.usefixtures("load_energy_table_with_slice") + def test_create_dataset_with_sql_validate_uniqueness(self): + """ + Dataset API: Test create dataset with sql + """ + if backend() == "sqlite": + return + + schema = get_example_default_schema() + energy_usage_ds = self.get_energy_usage_dataset() + self.login(username="admin") + table_data = { + "database": energy_usage_ds.database_id, + "table_name": energy_usage_ds.table_name, + "sql": "select * from energy_usage", + } + if schema: + table_data["schema"] = schema + rv = self.post_assert_metric("/api/v1/dataset/", table_data, "post") + assert rv.status_code == 422 + data = json.loads(rv.data.decode("utf-8")) + assert data == { + "message": {"table_name": ["Dataset energy_usage already exists"]} + } + + @pytest.mark.usefixtures("load_energy_table_with_slice") + def test_create_dataset_with_sql(self): + """ + Dataset API: Test create dataset with sql + """ + if backend() == "sqlite": + return + + schema = get_example_default_schema() + energy_usage_ds = self.get_energy_usage_dataset() + self.login(username="alpha") + admin = self.get_user("admin") + alpha = self.get_user("alpha") + table_data = { + "database": energy_usage_ds.database_id, + "table_name": "energy_usage_virtual", + "sql": "select * from energy_usage", + "owners": [admin.id], + } + if schema: + table_data["schema"] = schema + rv = self.post_assert_metric("/api/v1/dataset/", table_data, "post") + assert rv.status_code == 201 + data = json.loads(rv.data.decode("utf-8")) + model = db.session.query(SqlaTable).get(data.get("id")) + assert admin in model.owners + assert alpha in model.owners + db.session.delete(model) + db.session.commit() + @unittest.skip("test is failing stochastically") def test_create_dataset_same_name_different_schema(self): if backend() == "sqlite": @@ -540,9 +678,10 @@ def test_create_dataset_same_name_different_schema(self): return example_db = get_example_database() - example_db.get_sqla_engine().execute( - f"CREATE TABLE {CTAS_SCHEMA_NAME}.birth_names AS SELECT 2 as two" - ) + with example_db.get_sqla_engine_with_context() as engine: + engine.execute( + f"CREATE TABLE {CTAS_SCHEMA_NAME}.birth_names AS SELECT 2 as two" + ) self.login(username="admin") table_data = { @@ -560,14 +699,16 @@ def test_create_dataset_same_name_different_schema(self): uri = f'api/v1/dataset/{data.get("id")}' rv = self.client.delete(uri) assert rv.status_code == 200 - example_db.get_sqla_engine().execute( - f"DROP TABLE {CTAS_SCHEMA_NAME}.birth_names" - ) + with example_db.get_sqla_engine_with_context() as engine: + engine.execute(f"DROP TABLE {CTAS_SCHEMA_NAME}.birth_names") def test_create_dataset_validate_database(self): """ Dataset API: Test create dataset validate database exists """ + if backend() == "sqlite": + return + self.login(username="admin") dataset_data = {"database": 1000, "schema": "", "table_name": "birth_names"} uri = "api/v1/dataset/" @@ -580,6 +721,9 @@ def test_create_dataset_validate_tables_exists(self): """ Dataset API: Test create dataset validate table exists """ + if backend() == "sqlite": + return + example_db = get_example_database() self.login(username="admin") table_data = { @@ -593,13 +737,20 @@ def test_create_dataset_validate_tables_exists(self): @patch("superset.models.core.Database.get_columns") @patch("superset.models.core.Database.has_table_by_name") + @patch("superset.models.core.Database.has_view_by_name") @patch("superset.models.core.Database.get_table") def test_create_dataset_validate_view_exists( - self, mock_get_table, mock_has_table_by_name, mock_get_columns + self, + mock_get_table, + mock_has_table_by_name, + mock_has_view_by_name, + mock_get_columns, ): """ Dataset API: Test create dataset validate view exists """ + if backend() == "sqlite": + return mock_get_columns.return_value = [ { @@ -611,16 +762,18 @@ def test_create_dataset_validate_view_exists( ] mock_has_table_by_name.return_value = False + mock_has_view_by_name.return_value = True mock_get_table.return_value = None example_db = get_example_database() - engine = example_db.get_sqla_engine() - dialect = engine.dialect + with example_db.get_sqla_engine_with_context() as engine: + engine = engine + dialect = engine.dialect - with patch.object( - dialect, "get_view_names", wraps=dialect.get_view_names - ) as patch_get_view_names: - patch_get_view_names.return_value = ["test_case_view"] + with patch.object( + dialect, "get_view_names", wraps=dialect.get_view_names + ) as patch_get_view_names: + patch_get_view_names.return_value = {"test_case_view"} self.login(username="admin") table_data = { @@ -644,6 +797,9 @@ def test_create_dataset_sqlalchemy_error(self, mock_dao_create): """ Dataset API: Test create dataset sqlalchemy error """ + if backend() == "sqlite": + return + mock_dao_create.side_effect = DAOCreateFailedError() self.login(username="admin") main_db = get_main_database() @@ -662,6 +818,9 @@ def test_update_dataset_item(self): """ Dataset API: Test update dataset item """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="admin") dataset_data = {"description": "changed_description"} @@ -678,6 +837,9 @@ def test_update_dataset_item_w_override_columns(self): """ Dataset API: Test update dataset with override columns """ + if backend() == "sqlite": + return + # Add default dataset dataset = self.insert_default_dataset() self.login(username="admin") @@ -706,10 +868,63 @@ def test_update_dataset_item_w_override_columns(self): db.session.delete(dataset) db.session.commit() + def test_update_dataset_item_w_override_columns_same_columns(self): + """ + Dataset API: Test update dataset with override columns + """ + if backend() == "sqlite": + return + + # Add default dataset + main_db = get_main_database() + dataset = self.insert_default_dataset() + prev_col_len = len(dataset.columns) + + cols = [ + { + "column_name": c.column_name, + "description": c.description, + "expression": c.expression, + "type": c.type, + "advanced_data_type": c.advanced_data_type, + "verbose_name": c.verbose_name, + } + for c in dataset.columns + ] + + cols.append( + { + "column_name": "new_col", + "description": "description", + "expression": "expression", + "type": "INTEGER", + "advanced_data_type": "ADVANCED_DATA_TYPE", + "verbose_name": "New Col", + } + ) + + self.login(username="admin") + dataset_data = { + "columns": cols, + } + uri = f"api/v1/dataset/{dataset.id}?override_columns=true" + rv = self.put_assert_metric(uri, dataset_data, "put") + + assert rv.status_code == 200 + + columns = db.session.query(TableColumn).filter_by(table_id=dataset.id).all() + assert len(columns) != prev_col_len + assert len(columns) == 3 + db.session.delete(dataset) + db.session.commit() + def test_update_dataset_create_column_and_metric(self): """ Dataset API: Test update dataset create column """ + if backend() == "sqlite": + return + # create example dataset by Command dataset = self.insert_default_dataset() @@ -805,6 +1020,9 @@ def test_update_dataset_delete_column(self): """ Dataset API: Test update dataset delete column """ + if backend() == "sqlite": + return + # create example dataset by Command dataset = self.insert_default_dataset() @@ -854,6 +1072,9 @@ def test_update_dataset_update_column(self): """ Dataset API: Test update dataset columns """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="admin") @@ -890,6 +1111,9 @@ def test_update_dataset_delete_metric(self): """ Dataset API: Test update dataset delete metric """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() metrics_query = ( db.session.query(SqlMetric) @@ -933,6 +1157,9 @@ def test_update_dataset_update_column_uniqueness(self): """ Dataset API: Test update dataset columns uniqueness """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="admin") @@ -953,6 +1180,9 @@ def test_update_dataset_update_metric_uniqueness(self): """ Dataset API: Test update dataset metric uniqueness """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="admin") @@ -973,6 +1203,9 @@ def test_update_dataset_update_column_duplicate(self): """ Dataset API: Test update dataset columns duplicate """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="admin") @@ -998,6 +1231,9 @@ def test_update_dataset_update_metric_duplicate(self): """ Dataset API: Test update dataset metric duplicate """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="admin") @@ -1023,6 +1259,9 @@ def test_update_dataset_item_gamma(self): """ Dataset API: Test update dataset item gamma """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="gamma") table_data = {"description": "changed_description"} @@ -1036,6 +1275,9 @@ def test_update_dataset_item_not_owned(self): """ Dataset API: Test update dataset item not owned """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="alpha") table_data = {"description": "changed_description"} @@ -1049,6 +1291,9 @@ def test_update_dataset_item_owners_invalid(self): """ Dataset API: Test update dataset item owner invalid """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="admin") table_data = {"description": "changed_description", "owners": [1000]} @@ -1062,6 +1307,9 @@ def test_update_dataset_item_uniqueness(self): """ Dataset API: Test update dataset uniqueness """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="admin") ab_user = self.insert_dataset( @@ -1085,6 +1333,9 @@ def test_update_dataset_sqlalchemy_error(self, mock_dao_update): """ Dataset API: Test update dataset sqlalchemy error """ + if backend() == "sqlite": + return + mock_dao_update.side_effect = DAOUpdateFailedError() dataset = self.insert_default_dataset() @@ -1103,6 +1354,9 @@ def test_delete_dataset_item(self): """ Dataset API: Test delete dataset item """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() view_menu = security_manager.find_view_menu(dataset.get_perm()) assert view_menu is not None @@ -1120,6 +1374,9 @@ def test_delete_item_dataset_not_owned(self): """ Dataset API: Test delete item not owned """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="alpha") uri = f"api/v1/dataset/{dataset.id}" @@ -1132,6 +1389,9 @@ def test_delete_dataset_item_not_authorized(self): """ Dataset API: Test delete item not authorized """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="gamma") uri = f"api/v1/dataset/{dataset.id}" @@ -1145,6 +1405,9 @@ def test_delete_dataset_sqlalchemy_error(self, mock_dao_delete): """ Dataset API: Test delete dataset sqlalchemy error """ + if backend() == "sqlite": + return + mock_dao_delete.side_effect = DAODeleteFailedError() dataset = self.insert_default_dataset() @@ -1162,6 +1425,9 @@ def test_delete_dataset_column(self): """ Dataset API: Test delete dataset column """ + if backend() == "sqlite": + return + dataset = self.get_fixture_datasets()[0] column_id = dataset.columns[0].id self.login(username="admin") @@ -1175,6 +1441,9 @@ def test_delete_dataset_column_not_found(self): """ Dataset API: Test delete dataset column not found """ + if backend() == "sqlite": + return + dataset = self.get_fixture_datasets()[0] non_id = self.get_nonexistent_numeric_id(TableColumn) @@ -1196,6 +1465,9 @@ def test_delete_dataset_column_not_owned(self): """ Dataset API: Test delete dataset column not owned """ + if backend() == "sqlite": + return + dataset = self.get_fixture_datasets()[0] column_id = dataset.columns[0].id @@ -1210,6 +1482,9 @@ def test_delete_dataset_column_fail(self, mock_dao_delete): """ Dataset API: Test delete dataset column """ + if backend() == "sqlite": + return + mock_dao_delete.side_effect = DAODeleteFailedError() dataset = self.get_fixture_datasets()[0] column_id = dataset.columns[0].id @@ -1225,6 +1500,9 @@ def test_delete_dataset_metric(self): """ Dataset API: Test delete dataset metric """ + if backend() == "sqlite": + return + dataset = self.get_fixture_datasets()[0] test_metric = SqlMetric( metric_name="metric1", expression="COUNT(*)", table=dataset @@ -1243,6 +1521,9 @@ def test_delete_dataset_metric_not_found(self): """ Dataset API: Test delete dataset metric not found """ + if backend() == "sqlite": + return + dataset = self.get_fixture_datasets()[0] non_id = self.get_nonexistent_numeric_id(SqlMetric) @@ -1264,6 +1545,9 @@ def test_delete_dataset_metric_not_owned(self): """ Dataset API: Test delete dataset metric not owned """ + if backend() == "sqlite": + return + dataset = self.get_fixture_datasets()[0] metric_id = dataset.metrics[0].id @@ -1278,6 +1562,9 @@ def test_delete_dataset_metric_fail(self, mock_dao_delete): """ Dataset API: Test delete dataset metric """ + if backend() == "sqlite": + return + mock_dao_delete.side_effect = DAODeleteFailedError() dataset = self.get_fixture_datasets()[0] column_id = dataset.metrics[0].id @@ -1293,6 +1580,9 @@ def test_bulk_delete_dataset_items(self): """ Dataset API: Test bulk delete dataset items """ + if backend() == "sqlite": + return + datasets = self.get_fixture_datasets() dataset_ids = [dataset.id for dataset in datasets] @@ -1322,6 +1612,9 @@ def test_bulk_delete_item_dataset_not_owned(self): """ Dataset API: Test bulk delete item not owned """ + if backend() == "sqlite": + return + datasets = self.get_fixture_datasets() dataset_ids = [dataset.id for dataset in datasets] @@ -1335,6 +1628,9 @@ def test_bulk_delete_item_not_found(self): """ Dataset API: Test bulk delete item not found """ + if backend() == "sqlite": + return + datasets = self.get_fixture_datasets() dataset_ids = [dataset.id for dataset in datasets] dataset_ids.append(db.session.query(func.max(SqlaTable.id)).scalar()) @@ -1349,6 +1645,9 @@ def test_bulk_delete_dataset_item_not_authorized(self): """ Dataset API: Test bulk delete item not authorized """ + if backend() == "sqlite": + return + datasets = self.get_fixture_datasets() dataset_ids = [dataset.id for dataset in datasets] @@ -1362,6 +1661,9 @@ def test_bulk_delete_dataset_item_incorrect(self): """ Dataset API: Test bulk delete item incorrect request """ + if backend() == "sqlite": + return + datasets = self.get_fixture_datasets() dataset_ids = [dataset.id for dataset in datasets] dataset_ids.append("Wrong") @@ -1375,6 +1677,9 @@ def test_dataset_item_refresh(self): """ Dataset API: Test item refresh """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() # delete a column id_column = ( @@ -1403,6 +1708,9 @@ def test_dataset_item_refresh_not_found(self): """ Dataset API: Test item refresh not found dataset """ + if backend() == "sqlite": + return + max_id = db.session.query(func.max(SqlaTable.id)).scalar() self.login(username="admin") @@ -1414,6 +1722,9 @@ def test_dataset_item_refresh_not_owned(self): """ Dataset API: Test item refresh not owned dataset """ + if backend() == "sqlite": + return + dataset = self.insert_default_dataset() self.login(username="alpha") uri = f"api/v1/dataset/{dataset.id}/refresh" @@ -1428,6 +1739,9 @@ def test_export_dataset(self): """ Dataset API: Test export dataset """ + if backend() == "sqlite": + return + birth_names_dataset = self.get_birth_names_dataset() # TODO: fix test for presto # debug with dump: https://github.com/apache/superset/runs/1092546855 @@ -1460,6 +1774,9 @@ def test_export_dataset_not_found(self): """ Dataset API: Test export dataset not found """ + if backend() == "sqlite": + return + max_id = db.session.query(func.max(SqlaTable.id)).scalar() # Just one does not exist and we get 404 argument = [max_id + 1, 1] @@ -1473,6 +1790,9 @@ def test_export_dataset_gamma(self): """ Dataset API: Test export dataset has gamma """ + if backend() == "sqlite": + return + dataset = self.get_fixture_datasets()[0] argument = [dataset.id] @@ -1488,7 +1808,7 @@ def test_export_dataset_gamma(self): "datasource_access", dataset.perm ) - # add perissions to allow export + access to query this dataset + # add permissions to allow export + access to query this dataset gamma_role = security_manager.find_role("Gamma") security_manager.add_permission_role(gamma_role, perm1) security_manager.add_permission_role(gamma_role, perm2) @@ -1501,6 +1821,9 @@ def test_export_dataset_bundle(self): """ Dataset API: Test export dataset """ + if backend() == "sqlite": + return + birth_names_dataset = self.get_birth_names_dataset() # TODO: fix test for presto # debug with dump: https://github.com/apache/superset/runs/1092546855 @@ -1522,6 +1845,9 @@ def test_export_dataset_bundle_not_found(self): """ Dataset API: Test export dataset not found """ + if backend() == "sqlite": + return + # Just one does not exist and we get 404 argument = [-1, 1] uri = f"api/v1/dataset/export/?q={prison.dumps(argument)}" @@ -1535,6 +1861,9 @@ def test_export_dataset_bundle_gamma(self): """ Dataset API: Test export dataset has gamma """ + if backend() == "sqlite": + return + dataset = self.get_fixture_datasets()[0] argument = [dataset.id] @@ -1552,6 +1881,9 @@ def test_get_dataset_related_objects(self): Dataset API: Test get chart and dashboard count related to a dataset :return: """ + if backend() == "sqlite": + return + self.login(username="admin") table = self.get_birth_names_dataset() uri = f"api/v1/dataset/{table.id}/related_objects" @@ -1565,6 +1897,9 @@ def test_get_dataset_related_objects_not_found(self): """ Dataset API: Test related objects not found """ + if backend() == "sqlite": + return + max_id = db.session.query(func.max(SqlaTable.id)).scalar() # id does not exist and we get 404 invalid_id = max_id + 1 @@ -1573,6 +1908,7 @@ def test_get_dataset_related_objects_not_found(self): rv = self.client.get(uri) assert rv.status_code == 404 self.logout() + self.login(username="gamma") table = self.get_birth_names_dataset() uri = f"api/v1/dataset/{table.id}/related_objects" @@ -1584,6 +1920,9 @@ def test_get_datasets_custom_filter_sql(self): """ Dataset API: Test custom dataset_is_null_or_empty filter for sql """ + if backend() == "sqlite": + return + arguments = { "filters": [ {"col": "sql", "opr": "dataset_is_null_or_empty", "value": False} @@ -1617,12 +1956,17 @@ def test_import_dataset(self): """ Dataset API: Test import dataset """ + if backend() == "sqlite": + return + self.login(username="admin") uri = "api/v1/dataset/import/" buf = self.create_dataset_import() form_data = { "formData": (buf, "dataset_export.zip"), + "sync_columns": "true", + "sync_metrics": "true", } rv = self.client.post(uri, data=form_data, content_type="multipart/form-data") response = json.loads(rv.data.decode("utf-8")) @@ -1633,25 +1977,24 @@ def test_import_dataset(self): database = ( db.session.query(Database).filter_by(uuid=database_config["uuid"]).one() ) - shadow_dataset = ( - db.session.query(Dataset).filter_by(uuid=dataset_config["uuid"]).one() - ) + assert database.database_name == "imported_database" assert len(database.tables) == 1 dataset = database.tables[0] assert dataset.table_name == "imported_dataset" assert str(dataset.uuid) == dataset_config["uuid"] - assert str(shadow_dataset.uuid) == dataset_config["uuid"] dataset.owners = [] - database.owners = [] db.session.delete(dataset) - db.session.delete(shadow_dataset) + db.session.commit() db.session.delete(database) db.session.commit() def test_import_dataset_v0_export(self): + if backend() == "sqlite": + return + num_datasets = db.session.query(SqlaTable).count() self.login(username="admin") @@ -1662,6 +2005,8 @@ def test_import_dataset_v0_export(self): buf.seek(0) form_data = { "formData": (buf, "dataset_export.zip"), + "sync_columns": "true", + "sync_metrics": "true", } rv = self.client.post(uri, data=form_data, content_type="multipart/form-data") response = json.loads(rv.data.decode("utf-8")) @@ -1680,6 +2025,9 @@ def test_import_dataset_overwrite(self): """ Dataset API: Test import existing dataset """ + if backend() == "sqlite": + return + self.login(username="admin") uri = "api/v1/dataset/import/" @@ -1740,8 +2088,8 @@ def test_import_dataset_overwrite(self): dataset = database.tables[0] dataset.owners = [] - database.owners = [] db.session.delete(dataset) + db.session.commit() db.session.delete(database) db.session.commit() @@ -1749,6 +2097,9 @@ def test_import_dataset_invalid(self): """ Dataset API: Test import invalid dataset """ + if backend() == "sqlite": + return + self.login(username="admin") uri = "api/v1/dataset/import/" @@ -1799,6 +2150,9 @@ def test_import_dataset_invalid_v0_validation(self): """ Dataset API: Test import invalid dataset """ + if backend() == "sqlite": + return + self.login(username="admin") uri = "api/v1/dataset/import/" @@ -1844,6 +2198,9 @@ def test_get_datasets_is_certified_filter(self): """ Dataset API: Test custom dataset_is_certified filter """ + if backend() == "sqlite": + return + table_w_certification = SqlaTable( table_name="foo", schema=None, @@ -1869,92 +2226,164 @@ def test_get_datasets_is_certified_filter(self): db.session.delete(table_w_certification) db.session.commit() - @pytest.mark.usefixtures("create_datasets") - def test_get_dataset_samples(self): + @pytest.mark.usefixtures("create_virtual_datasets") + def test_duplicate_virtual_dataset(self): """ - Dataset API: Test get dataset samples + Dataset API: Test duplicate virtual dataset """ - dataset = self.get_fixture_datasets()[0] + if backend() == "sqlite": + return - self.login(username="admin") - uri = f"api/v1/dataset/{dataset.id}/samples" + dataset = self.get_fixture_virtual_datasets()[0] - # 1. should cache data - # feeds data - self.client.get(uri) - # get from cache - rv = self.client.get(uri) + self.login(username="admin") + uri = f"api/v1/dataset/duplicate" + table_data = {"base_model_id": dataset.id, "table_name": "Dupe1"} + rv = self.post_assert_metric(uri, table_data, "duplicate") + assert rv.status_code == 201 rv_data = json.loads(rv.data) - assert rv.status_code == 200 - assert "result" in rv_data - assert rv_data["result"]["cached_dttm"] is not None - cache_key1 = rv_data["result"]["cache_key"] - assert QueryCacheManager.has(cache_key1, region=CacheRegion.DATA) - - # 2. should through cache - uri2 = f"api/v1/dataset/{dataset.id}/samples?force=true" - # feeds data - self.client.get(uri2) - # force query - rv2 = self.client.get(uri2) - rv_data2 = json.loads(rv2.data) - assert rv_data2["result"]["cached_dttm"] is None - cache_key2 = rv_data2["result"]["cache_key"] - assert QueryCacheManager.has(cache_key2, region=CacheRegion.DATA) - - # 3. data precision - assert "colnames" in rv_data2["result"] - assert "coltypes" in rv_data2["result"] - assert "data" in rv_data2["result"] - - eager_samples = dataset.database.get_df( - f"select * from {dataset.table_name}" - f' limit {self.app.config["SAMPLES_ROW_LIMIT"]}' - ).to_dict(orient="records") - assert eager_samples == rv_data2["result"]["data"] + new_dataset: SqlaTable = ( + db.session.query(SqlaTable).filter_by(id=rv_data["id"]).one_or_none() + ) + assert new_dataset is not None + assert new_dataset.id != dataset.id + assert new_dataset.table_name == "Dupe1" + assert len(new_dataset.columns) == 2 + assert new_dataset.columns[0].column_name == "id" + assert new_dataset.columns[1].column_name == "name" @pytest.mark.usefixtures("create_datasets") - def test_get_dataset_samples_with_failed_cc(self): + def test_duplicate_physical_dataset(self): + """ + Dataset API: Test duplicate physical dataset + """ + if backend() == "sqlite": + return + dataset = self.get_fixture_datasets()[0] self.login(username="admin") - failed_column = TableColumn( - column_name="DUMMY CC", - type="VARCHAR(255)", - table=dataset, - expression="INCORRECT SQL", + uri = f"api/v1/dataset/duplicate" + table_data = {"base_model_id": dataset.id, "table_name": "Dupe2"} + rv = self.post_assert_metric(uri, table_data, "duplicate") + assert rv.status_code == 422 + + @pytest.mark.usefixtures("create_virtual_datasets") + def test_duplicate_existing_dataset(self): + """ + Dataset API: Test duplicate dataset with existing name + """ + if backend() == "sqlite": + return + + dataset = self.get_fixture_virtual_datasets()[0] + + self.login(username="admin") + uri = f"api/v1/dataset/duplicate" + table_data = { + "base_model_id": dataset.id, + "table_name": "sql_virtual_dataset_2", + } + rv = self.post_assert_metric(uri, table_data, "duplicate") + assert rv.status_code == 422 + + def test_duplicate_invalid_dataset(self): + """ + Dataset API: Test duplicate invalid dataset + """ + + self.login(username="admin") + uri = f"api/v1/dataset/duplicate" + table_data = { + "base_model_id": -1, + "table_name": "Dupe3", + } + rv = self.post_assert_metric(uri, table_data, "duplicate") + assert rv.status_code == 422 + + @pytest.mark.usefixtures("app_context", "virtual_dataset") + def test_get_or_create_dataset_already_exists(self): + """ + Dataset API: Test get or create endpoint when table already exists + """ + self.login(username="admin") + rv = self.client.post( + "api/v1/dataset/get_or_create/", + json={ + "table_name": "virtual_dataset", + "database_id": get_example_database().id, + }, ) - uri = f"api/v1/dataset/{dataset.id}/samples" - dataset.columns.append(failed_column) - rv = self.client.get(uri) - assert rv.status_code == 400 - rv_data = json.loads(rv.data) - assert "message" in rv_data - if dataset.database.db_engine_spec.engine_name == "PostgreSQL": - assert "INCORRECT SQL" in rv_data.get("message") - - def test_get_dataset_samples_on_virtual_dataset(self): - virtual_dataset = SqlaTable( - table_name="virtual_dataset", - sql=("SELECT 'foo' as foo, 'bar' as bar"), - database=get_example_database(), + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + dataset = ( + db.session.query(SqlaTable) + .filter(SqlaTable.table_name == "virtual_dataset") + .one() ) - TableColumn(column_name="foo", type="VARCHAR(255)", table=virtual_dataset) - TableColumn(column_name="bar", type="VARCHAR(255)", table=virtual_dataset) - SqlMetric(metric_name="count", expression="count(*)", table=virtual_dataset) + self.assertEqual(response["result"], {"table_id": dataset.id}) + def test_get_or_create_dataset_database_not_found(self): + """ + Dataset API: Test get or create endpoint when database doesn't exist + """ self.login(username="admin") - uri = f"api/v1/dataset/{virtual_dataset.id}/samples" - rv = self.client.get(uri) - assert rv.status_code == 200 - rv_data = json.loads(rv.data) - cache_key = rv_data["result"]["cache_key"] - assert QueryCacheManager.has(cache_key, region=CacheRegion.DATA) + rv = self.client.post( + "api/v1/dataset/get_or_create/", + json={"table_name": "virtual_dataset", "database_id": 999}, + ) + self.assertEqual(rv.status_code, 422) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(response["message"], {"database": ["Database does not exist"]}) - # remove original column in dataset - virtual_dataset.sql = "SELECT 'foo' as foo" - rv = self.client.get(uri) - assert rv.status_code == 400 + @patch("superset.datasets.commands.create.CreateDatasetCommand.run") + def test_get_or_create_dataset_create_fails(self, command_run_mock): + """ + Dataset API: Test get or create endpoint when create fails + """ + command_run_mock.side_effect = DatasetCreateFailedError + self.login(username="admin") + rv = self.client.post( + "api/v1/dataset/get_or_create/", + json={ + "table_name": "virtual_dataset", + "database_id": get_example_database().id, + }, + ) + self.assertEqual(rv.status_code, 422) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(response["message"], "Dataset could not be created.") + + def test_get_or_create_dataset_creates_table(self): + """ + Dataset API: Test get or create endpoint when table is created + """ + self.login(username="admin") + + examples_db = get_example_database() + with examples_db.get_sqla_engine_with_context() as engine: + engine.execute("DROP TABLE IF EXISTS test_create_sqla_table_api") + engine.execute("CREATE TABLE test_create_sqla_table_api AS SELECT 2 as col") + + rv = self.client.post( + "api/v1/dataset/get_or_create/", + json={ + "table_name": "test_create_sqla_table_api", + "database_id": examples_db.id, + "template_params": '{"param": 1}', + }, + ) + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + table = ( + db.session.query(SqlaTable) + .filter_by(table_name="test_create_sqla_table_api") + .one() + ) + self.assertEqual(response["result"], {"table_id": table.id}) + self.assertEqual(table.template_params, '{"param": 1}') - db.session.delete(virtual_dataset) + db.session.delete(table) + with examples_db.get_sqla_engine_with_context() as engine: + engine.execute("DROP TABLE test_create_sqla_table_api") db.session.commit() diff --git a/tests/integration_tests/datasets/commands_tests.py b/tests/integration_tests/datasets/commands_tests.py index 9498c911f266d..0ce98477a0b2d 100644 --- a/tests/integration_tests/datasets/commands_tests.py +++ b/tests/integration_tests/datasets/commands_tests.py @@ -20,13 +20,18 @@ import pytest import yaml +from sqlalchemy.exc import SQLAlchemyError from superset import db, security_manager from superset.commands.exceptions import CommandInvalidError from superset.commands.importers.exceptions import IncorrectVersionError from superset.connectors.sqla.models import SqlaTable from superset.databases.commands.importers.v1 import ImportDatabasesCommand -from superset.datasets.commands.exceptions import DatasetNotFoundError +from superset.datasets.commands.create import CreateDatasetCommand +from superset.datasets.commands.exceptions import ( + DatasetInvalidError, + DatasetNotFoundError, +) from superset.datasets.commands.export import ExportDatasetsCommand from superset.datasets.commands.importers import v0, v1 from superset.models.core import Database @@ -72,7 +77,7 @@ def test_export_dataset_command(self, mock_g): metadata = yaml.safe_load(contents["datasets/examples/energy_usage.yaml"]) - # sort columns for deterministc comparison + # sort columns for deterministic comparison metadata["columns"] = sorted(metadata["columns"], key=itemgetter("column_name")) metadata["metrics"] = sorted(metadata["metrics"], key=itemgetter("metric_name")) @@ -519,3 +524,47 @@ def _get_table_from_list_by_name(name: str, tables: List[Any]): if table.table_name == name: return table raise ValueError(f"Table {name} does not exists in database") + + +class TestCreateDatasetCommand(SupersetTestCase): + def test_database_not_found(self): + self.login(username="admin") + with self.assertRaises(DatasetInvalidError): + CreateDatasetCommand({"table_name": "table", "database": 9999}).run() + + @patch("superset.models.core.Database.get_table") + def test_get_table_from_database_error(self, get_table_mock): + self.login(username="admin") + get_table_mock.side_effect = SQLAlchemyError + with self.assertRaises(DatasetInvalidError): + CreateDatasetCommand( + {"table_name": "table", "database": get_example_database().id} + ).run() + + @patch("superset.security.manager.g") + @patch("superset.commands.utils.g") + def test_create_dataset_command(self, mock_g, mock_g2): + mock_g.user = security_manager.find_user("admin") + mock_g2.user = mock_g.user + examples_db = get_example_database() + with examples_db.get_sqla_engine_with_context() as engine: + engine.execute("DROP TABLE IF EXISTS test_create_dataset_command") + engine.execute( + "CREATE TABLE test_create_dataset_command AS SELECT 2 as col" + ) + + table = CreateDatasetCommand( + {"table_name": "test_create_dataset_command", "database": examples_db.id} + ).run() + fetched_table = ( + db.session.query(SqlaTable) + .filter_by(table_name="test_create_dataset_command") + .one() + ) + self.assertEqual(table, fetched_table) + self.assertEqual([owner.username for owner in table.owners], ["admin"]) + + db.session.delete(table) + with examples_db.get_sqla_engine_with_context() as engine: + engine.execute("DROP TABLE test_create_dataset_command") + db.session.commit() diff --git a/tests/integration_tests/datasets/model_tests.py b/tests/integration_tests/datasets/model_tests.py deleted file mode 100644 index 3bcc4c0793101..0000000000000 --- a/tests/integration_tests/datasets/model_tests.py +++ /dev/null @@ -1,87 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from unittest import mock - -import pytest -from sqlalchemy import inspect -from sqlalchemy.orm.exc import NoResultFound - -from superset.columns.models import Column -from superset.connectors.sqla.models import SqlaTable, TableColumn -from superset.extensions import db -from tests.integration_tests.base_tests import SupersetTestCase -from tests.integration_tests.fixtures.datasource import load_dataset_with_columns - - -class SqlaTableModelTest(SupersetTestCase): - @pytest.mark.usefixtures("load_dataset_with_columns") - def test_dual_update_column(self) -> None: - """ - Test that when updating a sqla ``TableColumn`` - That the shadow ``Column`` is also updated - """ - dataset = db.session.query(SqlaTable).filter_by(table_name="students").first() - column = dataset.columns[0] - column_name = column.column_name - column.column_name = "new_column_name" - SqlaTable.update_column(None, None, target=column) - - # refetch - dataset = db.session.query(SqlaTable).filter_by(id=dataset.id).one() - assert dataset.columns[0].column_name == "new_column_name" - - # reset - column.column_name = column_name - SqlaTable.update_column(None, None, target=column) - - @pytest.mark.usefixtures("load_dataset_with_columns") - @mock.patch("superset.columns.models.Column") - def test_dual_update_column_not_found(self, column_mock) -> None: - """ - Test that when updating a sqla ``TableColumn`` - That the shadow ``Column`` is also updated - """ - dataset = db.session.query(SqlaTable).filter_by(table_name="students").first() - column = dataset.columns[0] - column_uuid = column.uuid - with mock.patch("sqlalchemy.orm.query.Query.one", side_effect=NoResultFound): - SqlaTable.update_column(None, None, target=column) - - session = inspect(column).session - - session.flush() - - # refetch - dataset = db.session.query(SqlaTable).filter_by(id=dataset.id).one() - # it should create a new uuid - assert dataset.columns[0].uuid != column_uuid - - # reset - column.uuid = column_uuid - SqlaTable.update_column(None, None, target=column) - - @pytest.mark.usefixtures("load_dataset_with_columns") - def test_to_sl_column_no_known_columns(self) -> None: - """ - Test that the function returns a new column - """ - dataset = db.session.query(SqlaTable).filter_by(table_name="students").first() - column = dataset.columns[0] - new_column = column.to_sl_column() - - # it should use the same uuid - assert column.uuid == new_column.uuid diff --git a/tests/integration_tests/datasource/__init__.py b/tests/integration_tests/datasource/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/integration_tests/datasource/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/integration_tests/datasource/api_tests.py b/tests/integration_tests/datasource/api_tests.py new file mode 100644 index 0000000000000..522aa33383e62 --- /dev/null +++ b/tests/integration_tests/datasource/api_tests.py @@ -0,0 +1,137 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import json +from unittest.mock import Mock, patch + +import pytest + +from superset import db, security_manager +from superset.connectors.sqla.models import SqlaTable +from superset.dao.exceptions import DatasourceTypeNotSupportedError +from tests.integration_tests.base_tests import SupersetTestCase + + +class TestDatasourceApi(SupersetTestCase): + def get_virtual_dataset(self): + return ( + db.session.query(SqlaTable) + .filter(SqlaTable.table_name == "virtual_dataset") + .one() + ) + + @pytest.mark.usefixtures("app_context", "virtual_dataset") + def test_get_column_values_ints(self): + self.login(username="admin") + table = self.get_virtual_dataset() + rv = self.client.get(f"api/v1/datasource/table/{table.id}/column/col1/values/") + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + for val in range(10): + assert val in response["result"] + + @pytest.mark.usefixtures("app_context", "virtual_dataset") + def test_get_column_values_strs(self): + self.login(username="admin") + table = self.get_virtual_dataset() + rv = self.client.get(f"api/v1/datasource/table/{table.id}/column/col2/values/") + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + for val in ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]: + assert val in response["result"] + + @pytest.mark.usefixtures("app_context", "virtual_dataset") + def test_get_column_values_floats(self): + self.login(username="admin") + table = self.get_virtual_dataset() + rv = self.client.get(f"api/v1/datasource/table/{table.id}/column/col3/values/") + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + for val in [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9]: + assert val in response["result"] + + @pytest.mark.usefixtures("app_context", "virtual_dataset") + def test_get_column_values_nulls(self): + self.login(username="admin") + table = self.get_virtual_dataset() + rv = self.client.get(f"api/v1/datasource/table/{table.id}/column/col4/values/") + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(response["result"], [None]) + + @pytest.mark.usefixtures("app_context", "virtual_dataset") + def test_get_column_values_invalid_datasource_type(self): + self.login(username="admin") + table = self.get_virtual_dataset() + rv = self.client.get( + f"api/v1/datasource/not_table/{table.id}/column/col1/values/" + ) + self.assertEqual(rv.status_code, 400) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(response["message"], "Invalid datasource type: not_table") + + @patch("superset.datasource.api.DatasourceDAO.get_datasource") + def test_get_column_values_datasource_type_not_supported(self, get_datasource_mock): + get_datasource_mock.side_effect = DatasourceTypeNotSupportedError + self.login(username="admin") + rv = self.client.get("api/v1/datasource/table/1/column/col1/values/") + self.assertEqual(rv.status_code, 400) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual( + response["message"], "DAO datasource query source type is not supported" + ) + + def test_get_column_values_datasource_not_found(self): + self.login(username="admin") + rv = self.client.get("api/v1/datasource/table/999/column/col1/values/") + self.assertEqual(rv.status_code, 404) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(response["message"], "Datasource does not exist") + + @pytest.mark.usefixtures("app_context", "virtual_dataset") + def test_get_column_values_no_datasource_access(self): + # Allow gamma user to use this endpoint, but does not have datasource access + perm = security_manager.find_permission_view_menu( + "can_get_column_values", "Datasource" + ) + gamma_role = security_manager.find_role("Gamma") + security_manager.add_permission_role(gamma_role, perm) + + self.login(username="gamma") + table = self.get_virtual_dataset() + rv = self.client.get(f"api/v1/datasource/table/{table.id}/column/col1/values/") + self.assertEqual(rv.status_code, 403) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual( + response["message"], + "This endpoint requires the datasource virtual_dataset, " + "database or `all_datasource_access` permission", + ) + + @patch("superset.datasource.api.DatasourceDAO.get_datasource") + def test_get_column_values_not_implemented_error(self, get_datasource_mock): + datasource = Mock() + datasource.values_for_column.side_effect = NotImplementedError + get_datasource_mock.return_value = datasource + + self.login(username="admin") + rv = self.client.get("api/v1/datasource/sl_table/1/column/col1/values/") + self.assertEqual(rv.status_code, 400) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual( + response["message"], + "Unable to get column values for datasource type: sl_table", + ) diff --git a/tests/integration_tests/datasource_tests.py b/tests/integration_tests/datasource_tests.py index 19cc35c5c1bc7..52bd9ec244cc3 100644 --- a/tests/integration_tests/datasource_tests.py +++ b/tests/integration_tests/datasource_tests.py @@ -22,13 +22,16 @@ import prison import pytest -from superset import app, ConnectorRegistry, db -from superset.connectors.sqla.models import SqlaTable +from superset import app, db +from superset.common.utils.query_cache_manager import QueryCacheManager +from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn +from superset.constants import CacheRegion +from superset.dao.exceptions import DatasourceNotFound, DatasourceTypeNotSupportedError from superset.datasets.commands.exceptions import DatasetNotFoundError from superset.exceptions import SupersetGenericDBErrorException from superset.models.core import Database -from superset.utils.core import get_example_default_schema -from superset.utils.database import get_example_database +from superset.utils.core import backend, get_example_default_schema +from superset.utils.database import get_example_database, get_main_database from tests.integration_tests.base_tests import db_insert_temp_object, SupersetTestCase from tests.integration_tests.fixtures.birth_names_dashboard import ( load_birth_names_dashboard_with_slices, @@ -42,18 +45,17 @@ def create_test_table_context(database: Database): schema = get_example_default_schema() full_table_name = f"{schema}.test_table" if schema else "test_table" - database.get_sqla_engine().execute( - f"CREATE TABLE IF NOT EXISTS {full_table_name} AS SELECT 1 as first, 2 as second" - ) - database.get_sqla_engine().execute( - f"INSERT INTO {full_table_name} (first, second) VALUES (1, 2)" - ) - database.get_sqla_engine().execute( - f"INSERT INTO {full_table_name} (first, second) VALUES (3, 4)" - ) + with database.get_sqla_engine_with_context() as engine: + engine.execute( + f"CREATE TABLE IF NOT EXISTS {full_table_name} AS SELECT 1 as first, 2 as second" + ) + engine.execute(f"INSERT INTO {full_table_name} (first, second) VALUES (1, 2)") + engine.execute(f"INSERT INTO {full_table_name} (first, second) VALUES (3, 4)") yield db.session - database.get_sqla_engine().execute(f"DROP TABLE {full_table_name}") + + with database.get_sqla_engine_with_context() as engine: + engine.execute(f"DROP TABLE {full_table_name}") class TestDatasource(SupersetTestCase): @@ -231,7 +233,7 @@ def test_external_metadata_for_malicious_virtual_table(self): resp = self.get_json_resp(url) self.assertEqual(resp["error"], "Only `SELECT` statements are allowed") - def test_external_metadata_for_mutistatement_virtual_table(self): + def test_external_metadata_for_multistatement_virtual_table(self): self.login(username="admin") table = SqlaTable( table_name="multistatement_sql_table", @@ -256,9 +258,10 @@ def test_external_metadata_error_return_400(self, mock_get_datasource): pytest.raises( SupersetGenericDBErrorException, - lambda: ConnectorRegistry.get_datasource( - "table", tbl.id, db.session - ).external_metadata(), + lambda: db.session.query(SqlaTable) + .filter_by(id=tbl.id) + .one_or_none() + .external_metadata(), ) resp = self.client.get(url) @@ -288,6 +291,8 @@ def test_save(self): self.compare_lists(datasource_post[k], resp[k], "metric_name") elif k == "database": self.assertEqual(resp[k]["id"], datasource_post[k]["id"]) + elif k == "owners": + self.assertEqual([o["id"] for o in resp[k]], datasource_post["owners"]) else: print(k) self.assertEqual(resp[k], datasource_post[k]) @@ -423,21 +428,262 @@ def my_check(datasource): app.config["DATASET_HEALTH_CHECK"] = my_check self.login(username="admin") tbl = self.get_table(name="birth_names") - datasource = ConnectorRegistry.get_datasource("table", tbl.id, db.session) + datasource = db.session.query(SqlaTable).filter_by(id=tbl.id).one_or_none() assert datasource.health_check_message == "Warning message!" app.config["DATASET_HEALTH_CHECK"] = None def test_get_datasource_failed(self): + from superset.datasource.dao import DatasourceDAO + pytest.raises( - DatasetNotFoundError, - lambda: ConnectorRegistry.get_datasource("table", 9999999, db.session), + DatasourceNotFound, + lambda: DatasourceDAO.get_datasource(db.session, "table", 9999999), ) self.login(username="admin") - resp = self.get_json_resp("/datasource/get/druid/500000/", raise_on_error=False) - self.assertEqual(resp.get("error"), "Dataset does not exist") + resp = self.get_json_resp("/datasource/get/table/500000/", raise_on_error=False) + self.assertEqual(resp.get("error"), "Datasource does not exist") + + def test_get_datasource_invalid_datasource_failed(self): + from superset.datasource.dao import DatasourceDAO - resp = self.get_json_resp( - "/datasource/get/invalid-datasource-type/500000/", raise_on_error=False + pytest.raises( + DatasourceTypeNotSupportedError, + lambda: DatasourceDAO.get_datasource(db.session, "druid", 9999999), ) - self.assertEqual(resp.get("error"), "Dataset does not exist") + + self.login(username="admin") + resp = self.get_json_resp("/datasource/get/druid/500000/", raise_on_error=False) + self.assertEqual(resp.get("error"), "'druid' is not a valid DatasourceType") + + +def test_get_samples(test_client, login_as_admin, virtual_dataset): + """ + Dataset API: Test get dataset samples + """ + # 1. should cache data + uri = ( + f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=table" + ) + # feeds data + test_client.post(uri, json={}) + # get from cache + rv = test_client.post(uri, json={}) + assert rv.status_code == 200 + assert len(rv.json["result"]["data"]) == 10 + assert QueryCacheManager.has( + rv.json["result"]["cache_key"], + region=CacheRegion.DATA, + ) + assert rv.json["result"]["is_cached"] + + # 2. should read through cache data + uri2 = f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=table&force=true" + # feeds data + test_client.post(uri2, json={}) + # force query + rv2 = test_client.post(uri2, json={}) + assert rv2.status_code == 200 + assert len(rv2.json["result"]["data"]) == 10 + assert QueryCacheManager.has( + rv2.json["result"]["cache_key"], + region=CacheRegion.DATA, + ) + assert not rv2.json["result"]["is_cached"] + + # 3. data precision + assert "colnames" in rv2.json["result"] + assert "coltypes" in rv2.json["result"] + assert "data" in rv2.json["result"] + + eager_samples = virtual_dataset.database.get_df( + f"select * from ({virtual_dataset.sql}) as tbl" + f' limit {app.config["SAMPLES_ROW_LIMIT"]}' + ) + # the col3 is Decimal + eager_samples["col3"] = eager_samples["col3"].apply(float) + eager_samples = eager_samples.to_dict(orient="records") + assert eager_samples == rv2.json["result"]["data"] + + +def test_get_samples_with_incorrect_cc(test_client, login_as_admin, virtual_dataset): + TableColumn( + column_name="DUMMY CC", + type="VARCHAR(255)", + table=virtual_dataset, + expression="INCORRECT SQL", + ) + db.session.merge(virtual_dataset) + + uri = ( + f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=table" + ) + rv = test_client.post(uri, json={}) + assert rv.status_code == 422 + + assert "error" in rv.json + if virtual_dataset.database.db_engine_spec.engine_name == "PostgreSQL": + assert "INCORRECT SQL" in rv.json.get("error") + + +def test_get_samples_on_physical_dataset(test_client, login_as_admin, physical_dataset): + uri = ( + f"/datasource/samples?datasource_id={physical_dataset.id}&datasource_type=table" + ) + rv = test_client.post(uri, json={}) + assert rv.status_code == 200 + assert QueryCacheManager.has( + rv.json["result"]["cache_key"], region=CacheRegion.DATA + ) + assert len(rv.json["result"]["data"]) == 10 + + +def test_get_samples_with_filters(test_client, login_as_admin, virtual_dataset): + uri = ( + f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=table" + ) + rv = test_client.post(uri, json=None) + assert rv.status_code == 400 + + rv = test_client.post(uri, json={}) + assert rv.status_code == 200 + + rv = test_client.post(uri, json={"foo": "bar"}) + assert rv.status_code == 400 + + rv = test_client.post( + uri, json={"filters": [{"col": "col1", "op": "INVALID", "val": 0}]} + ) + assert rv.status_code == 400 + + rv = test_client.post( + uri, + json={ + "filters": [ + {"col": "col2", "op": "==", "val": "a"}, + {"col": "col1", "op": "==", "val": 0}, + ] + }, + ) + assert rv.status_code == 200 + assert rv.json["result"]["colnames"] == ["col1", "col2", "col3", "col4", "col5"] + assert rv.json["result"]["rowcount"] == 1 + + # empty results + rv = test_client.post( + uri, + json={ + "filters": [ + {"col": "col2", "op": "==", "val": "x"}, + ] + }, + ) + assert rv.status_code == 200 + assert rv.json["result"]["colnames"] == [] + assert rv.json["result"]["rowcount"] == 0 + + +def test_get_samples_with_time_filter(test_client, login_as_admin, physical_dataset): + uri = ( + f"/datasource/samples?datasource_id={physical_dataset.id}&datasource_type=table" + ) + payload = { + "granularity": "col5", + "time_range": "2000-01-02 : 2000-01-04", + } + rv = test_client.post(uri, json=payload) + assert len(rv.json["result"]["data"]) == 2 + if physical_dataset.database.backend != "sqlite": + assert [row["col5"] for row in rv.json["result"]["data"]] == [ + 946771200000.0, # 2000-01-02 00:00:00 + 946857600000.0, # 2000-01-03 00:00:00 + ] + assert rv.json["result"]["page"] == 1 + assert rv.json["result"]["per_page"] == app.config["SAMPLES_ROW_LIMIT"] + assert rv.json["result"]["total_count"] == 2 + + +def test_get_samples_with_multiple_filters( + test_client, login_as_admin, physical_dataset +): + # 1. empty response + uri = ( + f"/datasource/samples?datasource_id={physical_dataset.id}&datasource_type=table" + ) + payload = { + "granularity": "col5", + "time_range": "2000-01-02 : 2000-01-04", + "filters": [ + {"col": "col4", "op": "IS NOT NULL"}, + ], + } + rv = test_client.post(uri, json=payload) + assert len(rv.json["result"]["data"]) == 0 + + # 2. adhoc filters, time filters, and custom where + payload = { + "granularity": "col5", + "time_range": "2000-01-02 : 2000-01-04", + "filters": [ + {"col": "col2", "op": "==", "val": "c"}, + ], + "extras": {"where": "col3 = 1.2 and col4 is null"}, + } + rv = test_client.post(uri, json=payload) + assert len(rv.json["result"]["data"]) == 1 + assert rv.json["result"]["total_count"] == 1 + assert "2000-01-02" in rv.json["result"]["query"] + assert "2000-01-04" in rv.json["result"]["query"] + assert "col3 = 1.2" in rv.json["result"]["query"] + assert "col4 is null" in rv.json["result"]["query"] + assert "col2 = 'c'" in rv.json["result"]["query"] + + +def test_get_samples_pagination(test_client, login_as_admin, virtual_dataset): + # 1. default page, per_page and total_count + uri = ( + f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=table" + ) + rv = test_client.post(uri, json={}) + assert rv.json["result"]["page"] == 1 + assert rv.json["result"]["per_page"] == app.config["SAMPLES_ROW_LIMIT"] + assert rv.json["result"]["total_count"] == 10 + + # 2. incorrect per_page + per_pages = (app.config["SAMPLES_ROW_LIMIT"] + 1, 0, "xx") + for per_page in per_pages: + uri = f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=table&per_page={per_page}" + rv = test_client.post(uri, json={}) + assert rv.status_code == 400 + + # 3. incorrect page or datasource_type + uri = f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=table&page=xx" + rv = test_client.post(uri, json={}) + assert rv.status_code == 400 + + uri = f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=xx" + rv = test_client.post(uri, json={}) + assert rv.status_code == 400 + + # 4. turning pages + uri = f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=table&per_page=2&page=1" + rv = test_client.post(uri, json={}) + assert rv.json["result"]["page"] == 1 + assert rv.json["result"]["per_page"] == 2 + assert rv.json["result"]["total_count"] == 10 + assert [row["col1"] for row in rv.json["result"]["data"]] == [0, 1] + + uri = f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=table&per_page=2&page=2" + rv = test_client.post(uri, json={}) + assert rv.json["result"]["page"] == 2 + assert rv.json["result"]["per_page"] == 2 + assert rv.json["result"]["total_count"] == 10 + assert [row["col1"] for row in rv.json["result"]["data"]] == [2, 3] + + # 5. Exceeding the maximum pages + uri = f"/datasource/samples?datasource_id={virtual_dataset.id}&datasource_type=table&per_page=2&page=6" + rv = test_client.post(uri, json={}) + assert rv.json["result"]["page"] == 6 + assert rv.json["result"]["per_page"] == 2 + assert rv.json["result"]["total_count"] == 10 + assert [row["col1"] for row in rv.json["result"]["data"]] == [] diff --git a/tests/integration_tests/db_engine_specs/base_engine_spec_tests.py b/tests/integration_tests/db_engine_specs/base_engine_spec_tests.py index c4432e3ad1f93..87de98db1c1d2 100644 --- a/tests/integration_tests/db_engine_specs/base_engine_spec_tests.py +++ b/tests/integration_tests/db_engine_specs/base_engine_spec_tests.py @@ -20,7 +20,7 @@ import pytest from superset.connectors.sqla.models import TableColumn -from superset.db_engine_specs import get_engine_specs +from superset.db_engine_specs import load_engine_specs from superset.db_engine_specs.base import ( BaseEngineSpec, BasicParametersMixin, @@ -195,7 +195,7 @@ class DummyEngineSpec(BaseEngineSpec): def test_engine_time_grain_validity(self): time_grains = set(builtin_time_grains.keys()) # loop over all subclasses of BaseEngineSpec - for engine in get_engine_specs().values(): + for engine in load_engine_specs(): if engine is not BaseEngineSpec: # make sure time grain functions have been defined self.assertGreater(len(engine.get_time_grain_expressions()), 0) @@ -229,11 +229,11 @@ def test_get_table_names(self): """ Make sure base engine spec removes schema name from table name ie. when try_remove_schema_from_table_name == True. """ - base_result_expected = ["table", "table_2"] + base_result_expected = {"table", "table_2"} base_result = BaseEngineSpec.get_table_names( database=mock.ANY, schema="schema", inspector=inspector ) - self.assertListEqual(base_result_expected, base_result) + assert base_result_expected == base_result @pytest.mark.usefixtures("load_energy_table_with_slice") def test_column_datatype_to_string(self): @@ -293,8 +293,8 @@ def test_calculated_column_in_order_by_base_engine_spec(self): table=table, expression=""" case - when gender=true then "male" - else "female" + when gender='boy' then 'male' + else 'female' end """, ) @@ -309,8 +309,8 @@ def test_calculated_column_in_order_by_base_engine_spec(self): sql = table.get_query_str(query_obj) assert ( """ORDER BY case - when gender=true then "male" - else "female" + when gender='boy' then 'male' + else 'female' end ASC;""" in sql ) @@ -395,7 +395,7 @@ def test_get_time_grain_with_config(): app.config = config -def test_get_time_grain_with_unkown_values(): +def test_get_time_grain_with_unknown_values(): """Should concatenate from configs and then sort in the proper order putting unknown patterns at the end""" config = app.config.copy() @@ -421,28 +421,32 @@ def test_validate(is_port_open, is_hostname_valid): is_hostname_valid.return_value = True is_port_open.return_value = True - parameters = { - "host": "localhost", - "port": 5432, - "username": "username", - "password": "password", - "database": "dbname", - "query": {"sslmode": "verify-full"}, + properties = { + "parameters": { + "host": "localhost", + "port": 5432, + "username": "username", + "password": "password", + "database": "dbname", + "query": {"sslmode": "verify-full"}, + } } - errors = BasicParametersMixin.validate_parameters(parameters) + errors = BasicParametersMixin.validate_parameters(properties) assert errors == [] def test_validate_parameters_missing(): - parameters = { - "host": "", - "port": None, - "username": "", - "password": "", - "database": "", - "query": {}, + properties = { + "parameters": { + "host": "", + "port": None, + "username": "", + "password": "", + "database": "", + "query": {}, + } } - errors = BasicParametersMixin.validate_parameters(parameters) + errors = BasicParametersMixin.validate_parameters(properties) assert errors == [ SupersetError( message=( @@ -459,15 +463,17 @@ def test_validate_parameters_missing(): def test_validate_parameters_invalid_host(is_hostname_valid): is_hostname_valid.return_value = False - parameters = { - "host": "localhost", - "port": None, - "username": "username", - "password": "password", - "database": "dbname", - "query": {"sslmode": "verify-full"}, + properties = { + "parameters": { + "host": "localhost", + "port": None, + "username": "username", + "password": "password", + "database": "dbname", + "query": {"sslmode": "verify-full"}, + } } - errors = BasicParametersMixin.validate_parameters(parameters) + errors = BasicParametersMixin.validate_parameters(properties) assert errors == [ SupersetError( message="One or more parameters are missing: port", @@ -490,15 +496,17 @@ def test_validate_parameters_port_closed(is_port_open, is_hostname_valid): is_hostname_valid.return_value = True is_port_open.return_value = False - parameters = { - "host": "localhost", - "port": 5432, - "username": "username", - "password": "password", - "database": "dbname", - "query": {"sslmode": "verify-full"}, + properties = { + "parameters": { + "host": "localhost", + "port": 5432, + "username": "username", + "password": "password", + "database": "dbname", + "query": {"sslmode": "verify-full"}, + } } - errors = BasicParametersMixin.validate_parameters(parameters) + errors = BasicParametersMixin.validate_parameters(properties) assert errors == [ SupersetError( message="The port is closed.", diff --git a/tests/integration_tests/db_engine_specs/base_tests.py b/tests/integration_tests/db_engine_specs/base_tests.py index 6496d4609ab8e..e20ea35ae4131 100644 --- a/tests/integration_tests/db_engine_specs/base_tests.py +++ b/tests/integration_tests/db_engine_specs/base_tests.py @@ -22,7 +22,6 @@ from tests.integration_tests.base_tests import SupersetTestCase from superset.db_engine_specs.base import BaseEngineSpec from superset.models.core import Database -from superset.utils.core import GenericDataType class TestDbEngineSpec(SupersetTestCase): @@ -37,16 +36,3 @@ def sql_limit_regex( main = Database(database_name="test_database", sqlalchemy_uri="sqlite://") limited = engine_spec_class.apply_limit_to_sql(sql, limit, main, force) self.assertEqual(expected_sql, limited) - - -def assert_generic_types( - spec: Type[BaseEngineSpec], - type_expectations: Tuple[Tuple[str, GenericDataType], ...], -) -> None: - for type_str, expected_type in type_expectations: - column_spec = spec.get_column_spec(type_str) - assert column_spec is not None - actual_type = column_spec.generic_type - assert ( - actual_type == expected_type - ), f"{type_str} should be {expected_type.name} but is {actual_type.name}" diff --git a/tests/integration_tests/db_engine_specs/bigquery_tests.py b/tests/integration_tests/db_engine_specs/bigquery_tests.py index 549b1109529e9..574a2b75e32ca 100644 --- a/tests/integration_tests/db_engine_specs/bigquery_tests.py +++ b/tests/integration_tests/db_engine_specs/bigquery_tests.py @@ -48,23 +48,6 @@ def test_bigquery_sqla_column_label(self): actual = BigQueryEngineSpec.make_label_compatible(column(original).name) self.assertEqual(actual, expected) - def test_convert_dttm(self): - """ - DB Eng Specs (bigquery): Test conversion to date time - """ - dttm = self.get_dttm() - test_cases = { - "DATE": "CAST('2019-01-02' AS DATE)", - "DATETIME": "CAST('2019-01-02T03:04:05.678900' AS DATETIME)", - "TIMESTAMP": "CAST('2019-01-02T03:04:05.678900' AS TIMESTAMP)", - "TIME": "CAST('03:04:05.678900' AS TIME)", - "UNKNOWNTYPE": None, - } - - for target_type, expected in test_cases.items(): - actual = BigQueryEngineSpec.convert_dttm(target_type, dttm) - self.assertEqual(actual, expected) - def test_timegrain_expressions(self): """ DB Eng Specs (bigquery): Test time grain expressions @@ -77,8 +60,9 @@ def test_timegrain_expressions(self): "TIMESTAMP": "TIMESTAMP_TRUNC(temporal, HOUR)", } for type_, expected in test_cases.items(): + col.type = type_ actual = BigQueryEngineSpec.get_timestamp_expr( - col=col, pdf=None, time_grain="PT1H", type_=type_ + col=col, pdf=None, time_grain="PT1H" ) self.assertEqual(str(actual), expected) @@ -99,8 +83,9 @@ def test_custom_minute_timegrain_expressions(self): ") AS TIMESTAMP)", } for type_, expected in test_cases.items(): + col.type = type_ actual = BigQueryEngineSpec.get_timestamp_expr( - col=col, pdf=None, time_grain="PT5M", type_=type_ + col=col, pdf=None, time_grain="PT5M" ) assert str(actual) == expected @@ -225,8 +210,10 @@ def test_df_to_sql(self, mock_get_engine): return_value="account_info" ) - mock_get_engine.return_value.url.host = "google-host" - mock_get_engine.return_value.dialect.credentials_info = "secrets" + mock_get_engine.return_value.__enter__.return_value.url.host = "google-host" + mock_get_engine.return_value.__enter__.return_value.dialect.credentials_info = ( + "secrets" + ) BigQueryEngineSpec.df_to_sql( database=database, @@ -244,11 +231,11 @@ def test_df_to_sql(self, mock_get_engine): ) def test_extract_errors(self): - msg = "403 POST https://bigquery.googleapis.com/bigquery/v2/projects/test-keel-310804/jobs?prettyPrint=false: Access Denied: Project User does not have bigquery.jobs.create permission in project profound-keel-310804" + msg = "403 POST https://bigquery.googleapis.com/bigquery/v2/projects/test-keel-310804/jobs?prettyPrint=false: Access Denied: Project profound-keel-310804: User does not have bigquery.jobs.create permission in project profound-keel-310804" result = BigQueryEngineSpec.extract_errors(Exception(msg)) assert result == [ SupersetError( - message="We were unable to connect to your database. Please confirm that your service account has the Viewer and Job User roles on the project.", + message='Unable to connect. Verify that the following roles are set on the service account: "BigQuery Data Viewer", "BigQuery Metadata Viewer", "BigQuery Job User" and the following permissions are set "bigquery.readsessions.create", "bigquery.readsessions.getData"', error_type=SupersetErrorType.CONNECTION_DATABASE_PERMISSIONS_ERROR, level=ErrorLevel.ERROR, extra={ @@ -352,7 +339,7 @@ def test_extract_errors(self): ] @mock.patch("superset.models.core.Database.db_engine_spec", BigQueryEngineSpec) - @mock.patch("pybigquery._helpers.create_bigquery_client", mock.Mock) + @mock.patch("sqlalchemy_bigquery._helpers.create_bigquery_client", mock.Mock) @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_calculated_column_in_order_by(self): table = self.get_table(name="birth_names") @@ -362,8 +349,8 @@ def test_calculated_column_in_order_by(self): table=table, expression=""" case - when gender=true then "male" - else "female" + when gender='boy' then 'male' + else 'female' end """, ) diff --git a/tests/integration_tests/db_engine_specs/clickhouse_tests.py b/tests/integration_tests/db_engine_specs/clickhouse_tests.py deleted file mode 100644 index c8019a8758db7..0000000000000 --- a/tests/integration_tests/db_engine_specs/clickhouse_tests.py +++ /dev/null @@ -1,47 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from unittest import mock - -import pytest - -from superset.db_engine_specs.clickhouse import ClickHouseEngineSpec -from superset.db_engine_specs.exceptions import SupersetDBAPIDatabaseError -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec - - -class TestClickHouseDbEngineSpec(TestDbEngineSpec): - def test_convert_dttm(self): - dttm = self.get_dttm() - - self.assertEqual( - ClickHouseEngineSpec.convert_dttm("DATE", dttm), "toDate('2019-01-02')" - ) - - self.assertEqual( - ClickHouseEngineSpec.convert_dttm("DATETIME", dttm), - "toDateTime('2019-01-02 03:04:05')", - ) - - def test_execute_connection_error(self): - from urllib3.exceptions import NewConnectionError - - cursor = mock.Mock() - cursor.execute.side_effect = NewConnectionError( - "Dummypool", message="Exception with sensitive data" - ) - with pytest.raises(SupersetDBAPIDatabaseError) as ex: - ClickHouseEngineSpec.execute(cursor, "SELECT col1 from table1") diff --git a/tests/integration_tests/db_engine_specs/crate_tests.py b/tests/integration_tests/db_engine_specs/crate_tests.py deleted file mode 100644 index 7c86b34b335ff..0000000000000 --- a/tests/integration_tests/db_engine_specs/crate_tests.py +++ /dev/null @@ -1,53 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from superset.connectors.sqla.models import SqlaTable, TableColumn -from superset.db_engine_specs.crate import CrateEngineSpec -from superset.models.core import Database -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec - - -class TestCrateDbEngineSpec(TestDbEngineSpec): - def test_convert_dttm(self): - """ - DB Eng Specs (crate): Test conversion to date time - """ - dttm = self.get_dttm() - assert CrateEngineSpec.convert_dttm("TIMESTAMP", dttm) == str( - dttm.timestamp() * 1000 - ) - - def test_epoch_to_dttm(self): - """ - DB Eng Specs (crate): Test epoch to dttm - """ - assert CrateEngineSpec.epoch_to_dttm() == "{col} * 1000" - - def test_epoch_ms_to_dttm(self): - """ - DB Eng Specs (crate): Test epoch ms to dttm - """ - assert CrateEngineSpec.epoch_ms_to_dttm() == "{col}" - - def test_alter_new_orm_column(self): - """ - DB Eng Specs (crate): Test alter orm column - """ - database = Database(database_name="crate", sqlalchemy_uri="crate://db") - tbl = SqlaTable(table_name="druid_tbl", database=database) - col = TableColumn(column_name="ts", type="TIMESTAMP", table=tbl) - CrateEngineSpec.alter_new_orm_column(col) - assert col.python_date_format == "epoch_ms" diff --git a/tests/integration_tests/db_engine_specs/databricks_tests.py b/tests/integration_tests/db_engine_specs/databricks_tests.py new file mode 100644 index 0000000000000..5ff20b7347af2 --- /dev/null +++ b/tests/integration_tests/db_engine_specs/databricks_tests.py @@ -0,0 +1,61 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from unittest import mock + +from superset.db_engine_specs import get_engine_spec +from superset.db_engine_specs.databricks import DatabricksNativeEngineSpec +from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec +from tests.integration_tests.fixtures.certificates import ssl_certificate +from tests.integration_tests.fixtures.database import default_db_extra + + +class TestDatabricksDbEngineSpec(TestDbEngineSpec): + def test_get_engine_spec(self): + """ + DB Eng Specs (databricks): Test "databricks" in engine spec + """ + assert get_engine_spec("databricks", "connector").engine == "databricks" + assert get_engine_spec("databricks", "pyodbc").engine == "databricks" + assert get_engine_spec("databricks", "pyhive").engine == "databricks" + + def test_extras_without_ssl(self): + db = mock.Mock() + db.extra = default_db_extra + db.server_cert = None + extras = DatabricksNativeEngineSpec.get_extra_params(db) + assert extras == { + "engine_params": { + "connect_args": { + "_user_agent_entry": "Apache Superset", + "http_headers": [("User-Agent", "Apache Superset")], + }, + }, + "metadata_cache_timeout": {}, + "metadata_params": {}, + "schemas_allowed_for_file_upload": [], + } + + def test_extras_with_ssl_custom(self): + db = mock.Mock() + db.extra = default_db_extra.replace( + '"engine_params": {}', + '"engine_params": {"connect_args": {"ssl": "1"}}', + ) + db.server_cert = ssl_certificate + extras = DatabricksNativeEngineSpec.get_extra_params(db) + connect_args = extras["engine_params"]["connect_args"] + assert connect_args["ssl"] == "1" diff --git a/tests/integration_tests/db_engine_specs/druid_tests.py b/tests/integration_tests/db_engine_specs/druid_tests.py deleted file mode 100644 index 232787ba61850..0000000000000 --- a/tests/integration_tests/db_engine_specs/druid_tests.py +++ /dev/null @@ -1,78 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from unittest import mock - -from sqlalchemy import column - -from superset.db_engine_specs.druid import DruidEngineSpec -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec -from tests.integration_tests.fixtures.certificates import ssl_certificate -from tests.integration_tests.fixtures.database import default_db_extra - - -class TestDruidDbEngineSpec(TestDbEngineSpec): - def test_convert_dttm(self): - dttm = self.get_dttm() - - self.assertEqual( - DruidEngineSpec.convert_dttm("DATETIME", dttm), - "TIME_PARSE('2019-01-02T03:04:05')", - ) - - self.assertEqual( - DruidEngineSpec.convert_dttm("TIMESTAMP", dttm), - "TIME_PARSE('2019-01-02T03:04:05')", - ) - - self.assertEqual( - DruidEngineSpec.convert_dttm("DATE", dttm), - "CAST(TIME_PARSE('2019-01-02') AS DATE)", - ) - - def test_timegrain_expressions(self): - """ - DB Eng Specs (druid): Test time grain expressions - """ - col = "__time" - sqla_col = column(col) - test_cases = { - "PT1S": f"TIME_FLOOR(CAST({col} AS TIMESTAMP), 'PT1S')", - "PT5M": f"TIME_FLOOR(CAST({col} AS TIMESTAMP), 'PT5M')", - "P1W/1970-01-03T00:00:00Z": f"TIME_SHIFT(TIME_FLOOR(TIME_SHIFT(CAST({col} AS TIMESTAMP), 'P1D', 1), 'P1W'), 'P1D', 5)", - "1969-12-28T00:00:00Z/P1W": f"TIME_SHIFT(TIME_FLOOR(TIME_SHIFT(CAST({col} AS TIMESTAMP), 'P1D', 1), 'P1W'), 'P1D', -1)", - } - for grain, expected in test_cases.items(): - actual = DruidEngineSpec.get_timestamp_expr( - col=sqla_col, pdf=None, time_grain=grain - ) - self.assertEqual(str(actual), expected) - - def test_extras_without_ssl(self): - db = mock.Mock() - db.extra = default_db_extra - db.server_cert = None - extras = DruidEngineSpec.get_extra_params(db) - assert "connect_args" not in extras["engine_params"] - - def test_extras_with_ssl(self): - db = mock.Mock() - db.extra = default_db_extra - db.server_cert = ssl_certificate - extras = DruidEngineSpec.get_extra_params(db) - connect_args = extras["engine_params"]["connect_args"] - assert connect_args["scheme"] == "https" - assert "ssl_verify_cert" in connect_args diff --git a/tests/integration_tests/db_engine_specs/elasticsearch_tests.py b/tests/integration_tests/db_engine_specs/elasticsearch_tests.py deleted file mode 100644 index 7dd5157792acc..0000000000000 --- a/tests/integration_tests/db_engine_specs/elasticsearch_tests.py +++ /dev/null @@ -1,104 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from unittest.mock import MagicMock - -import pytest -from sqlalchemy import column - -from superset.db_engine_specs.elasticsearch import ( - ElasticSearchEngineSpec, - OpenDistroEngineSpec, -) -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec - - -class TestElasticSearchDbEngineSpec(TestDbEngineSpec): - @pytest.fixture(autouse=True) - def inject_fixtures(self, caplog): - self._caplog = caplog - - def test_convert_dttm(self): - dttm = self.get_dttm() - - self.assertEqual( - ElasticSearchEngineSpec.convert_dttm("DATETIME", dttm, db_extra=None), - "CAST('2019-01-02T03:04:05' AS DATETIME)", - ) - - def test_convert_dttm2(self): - """ - ES 7.8 and above versions need to use the DATETIME_PARSE function to - solve the time zone problem - """ - dttm = self.get_dttm() - db_extra = {"version": "7.8"} - - self.assertEqual( - ElasticSearchEngineSpec.convert_dttm("DATETIME", dttm, db_extra=db_extra), - "DATETIME_PARSE('2019-01-02 03:04:05', 'yyyy-MM-dd HH:mm:ss')", - ) - - def test_convert_dttm3(self): - dttm = self.get_dttm() - db_extra = {"version": 7.8} - - self.assertEqual( - ElasticSearchEngineSpec.convert_dttm("DATETIME", dttm, db_extra=db_extra), - "CAST('2019-01-02T03:04:05' AS DATETIME)", - ) - - self.assertNotEqual( - ElasticSearchEngineSpec.convert_dttm("DATETIME", dttm, db_extra=db_extra), - "DATETIME_PARSE('2019-01-02 03:04:05', 'yyyy-MM-dd HH:mm:ss')", - ) - - self.assertIn("Unexpected error while convert es_version", self._caplog.text) - - def test_opendistro_convert_dttm(self): - """ - DB Eng Specs (opendistro): Test convert_dttm - """ - dttm = self.get_dttm() - - self.assertEqual( - OpenDistroEngineSpec.convert_dttm("DATETIME", dttm, db_extra=None), - "'2019-01-02T03:04:05'", - ) - - def test_opendistro_sqla_column_label(self): - """ - DB Eng Specs (opendistro): Test column label - """ - test_cases = { - "Col": "Col", - "Col.keyword": "Col_keyword", - } - for original, expected in test_cases.items(): - actual = OpenDistroEngineSpec.make_label_compatible(column(original).name) - self.assertEqual(actual, expected) - - def test_opendistro_strip_comments(self): - """ - DB Eng Specs (opendistro): Test execute sql strip comments - """ - mock_cursor = MagicMock() - mock_cursor.execute.return_value = [] - - OpenDistroEngineSpec.execute( - mock_cursor, "-- some comment \nSELECT 1\n --other comment" - ) - mock_cursor.execute.assert_called_once_with("SELECT 1\n") diff --git a/tests/integration_tests/db_engine_specs/firebird_tests.py b/tests/integration_tests/db_engine_specs/firebird_tests.py deleted file mode 100644 index 5e00e2ed4d9a6..0000000000000 --- a/tests/integration_tests/db_engine_specs/firebird_tests.py +++ /dev/null @@ -1,81 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from datetime import datetime -from unittest import mock - -import pytest - -from superset.db_engine_specs.firebird import FirebirdEngineSpec - -grain_expressions = { - None: "timestamp_column", - "PT1S": ( - "CAST(CAST(timestamp_column AS DATE) " - "|| ' ' " - "|| EXTRACT(HOUR FROM timestamp_column) " - "|| ':' " - "|| EXTRACT(MINUTE FROM timestamp_column) " - "|| ':' " - "|| FLOOR(EXTRACT(SECOND FROM timestamp_column)) AS TIMESTAMP)" - ), - "PT1M": ( - "CAST(CAST(timestamp_column AS DATE) " - "|| ' ' " - "|| EXTRACT(HOUR FROM timestamp_column) " - "|| ':' " - "|| EXTRACT(MINUTE FROM timestamp_column) " - "|| ':00' AS TIMESTAMP)" - ), - "P1D": "CAST(timestamp_column AS DATE)", - "P1M": ( - "CAST(EXTRACT(YEAR FROM timestamp_column) " - "|| '-' " - "|| EXTRACT(MONTH FROM timestamp_column) " - "|| '-01' AS DATE)" - ), - "P1Y": "CAST(EXTRACT(YEAR FROM timestamp_column) || '-01-01' AS DATE)", -} - - -@pytest.mark.parametrize("grain,expected", grain_expressions.items()) -def test_time_grain_expressions(grain, expected): - assert ( - FirebirdEngineSpec._time_grain_expressions[grain].format(col="timestamp_column") - == expected - ) - - -def test_epoch_to_dttm(): - assert ( - FirebirdEngineSpec.epoch_to_dttm().format(col="timestamp_column") - == "DATEADD(second, timestamp_column, CAST('00:00:00' AS TIMESTAMP))" - ) - - -def test_convert_dttm(): - dttm = datetime(2021, 1, 1) - assert ( - FirebirdEngineSpec.convert_dttm("timestamp", dttm) - == "CAST('2021-01-01 00:00:00' AS TIMESTAMP)" - ) - assert ( - FirebirdEngineSpec.convert_dttm("TIMESTAMP", dttm) - == "CAST('2021-01-01 00:00:00' AS TIMESTAMP)" - ) - assert FirebirdEngineSpec.convert_dttm("TIME", dttm) == "CAST('00:00:00' AS TIME)" - assert FirebirdEngineSpec.convert_dttm("DATE", dttm) == "CAST('2021-01-01' AS DATE)" - assert FirebirdEngineSpec.convert_dttm("STRING", dttm) is None diff --git a/tests/integration_tests/db_engine_specs/firebolt_tests.py b/tests/integration_tests/db_engine_specs/firebolt_tests.py deleted file mode 100644 index 793b32970bddb..0000000000000 --- a/tests/integration_tests/db_engine_specs/firebolt_tests.py +++ /dev/null @@ -1,39 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from superset.db_engine_specs.firebolt import FireboltEngineSpec -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec - - -class TestFireboltDbEngineSpec(TestDbEngineSpec): - def test_convert_dttm(self): - dttm = self.get_dttm() - test_cases = { - "DATE": "CAST('2019-01-02' AS DATE)", - "DATETIME": "CAST('2019-01-02T03:04:05' AS DATETIME)", - "TIMESTAMP": "CAST('2019-01-02T03:04:05' AS TIMESTAMP)", - "UNKNOWNTYPE": None, - } - - for target_type, expected in test_cases.items(): - actual = FireboltEngineSpec.convert_dttm(target_type, dttm) - self.assertEqual(actual, expected) - - def test_epoch_to_dttm(self): - assert ( - FireboltEngineSpec.epoch_to_dttm().format(col="timestamp_column") - == "from_unixtime(timestamp_column)" - ) diff --git a/tests/integration_tests/db_engine_specs/hive_tests.py b/tests/integration_tests/db_engine_specs/hive_tests.py index ad80f8397ffe1..b63f64ab03cb8 100644 --- a/tests/integration_tests/db_engine_specs/hive_tests.py +++ b/tests/integration_tests/db_engine_specs/hive_tests.py @@ -150,19 +150,6 @@ def test_hive_error_msg(): ) -def test_hive_get_view_names_return_empty_list(): # pylint: disable=invalid-name - assert HiveEngineSpec.get_view_names(mock.ANY, mock.ANY, mock.ANY) == [] - - -def test_convert_dttm(): - dttm = datetime.strptime("2019-01-02 03:04:05.678900", "%Y-%m-%d %H:%M:%S.%f") - assert HiveEngineSpec.convert_dttm("DATE", dttm) == "CAST('2019-01-02' AS DATE)" - assert ( - HiveEngineSpec.convert_dttm("TIMESTAMP", dttm) - == "CAST('2019-01-02 03:04:05.678900' AS TIMESTAMP)" - ) - - def test_df_to_csv() -> None: with pytest.raises(SupersetException): HiveEngineSpec.df_to_sql( @@ -208,7 +195,9 @@ def test_df_to_sql_if_exists_replace(mock_upload_to_s3, mock_g): mock_database = mock.MagicMock() mock_database.get_df.return_value.empty = False mock_execute = mock.MagicMock(return_value=True) - mock_database.get_sqla_engine.return_value.execute = mock_execute + mock_database.get_sqla_engine_with_context.return_value.__enter__.return_value.execute = ( + mock_execute + ) table_name = "foobar" with app.app_context(): @@ -233,7 +222,9 @@ def test_df_to_sql_if_exists_replace_with_schema(mock_upload_to_s3, mock_g): mock_database = mock.MagicMock() mock_database.get_df.return_value.empty = False mock_execute = mock.MagicMock(return_value=True) - mock_database.get_sqla_engine.return_value.execute = mock_execute + mock_database.get_sqla_engine_with_context.return_value.__enter__.return_value.execute = ( + mock_execute + ) table_name = "foobar" schema = "schema" @@ -403,3 +394,41 @@ def is_correct_result(data: List, result: List) -> bool: ["ds=01-01-19/hour=1", "ds=01-03-19/hour=1", "ds=01-02-19/hour=2"], ["01-03-19", "1"], ) + + +def test_get_view_names_with_schema(): + database = mock.MagicMock() + mock_execute = mock.MagicMock() + database.get_raw_connection().__enter__().cursor().execute = mock_execute + database.get_raw_connection().__enter__().cursor().fetchall = mock.MagicMock( + return_value=[["a", "b,", "c"], ["d", "e"]] + ) + + schema = "schema" + result = HiveEngineSpec.get_view_names(database, mock.Mock(), schema) + mock_execute.assert_called_once_with(f"SHOW VIEWS IN `{schema}`") + assert result == {"a", "d"} + + +def test_get_view_names_without_schema(): + database = mock.MagicMock() + mock_execute = mock.MagicMock() + database.get_raw_connection().__enter__().cursor().execute = mock_execute + database.get_raw_connection().__enter__().cursor().fetchall = mock.MagicMock( + return_value=[["a", "b,", "c"], ["d", "e"]] + ) + result = HiveEngineSpec.get_view_names(database, mock.Mock(), None) + mock_execute.assert_called_once_with("SHOW VIEWS") + assert result == {"a", "d"} + + +@mock.patch("superset.db_engine_specs.base.BaseEngineSpec.get_table_names") +@mock.patch("superset.db_engine_specs.hive.HiveEngineSpec.get_view_names") +def test_get_table_names( + mock_get_view_names, + mock_get_table_names, +): + mock_get_view_names.return_value = {"view1", "view2"} + mock_get_table_names.return_value = {"table1", "table2", "view1", "view2"} + tables = HiveEngineSpec.get_table_names(mock.Mock(), mock.Mock(), None) + assert tables == {"table1", "table2"} diff --git a/tests/integration_tests/db_engine_specs/mysql_tests.py b/tests/integration_tests/db_engine_specs/mysql_tests.py index b069bba69047a..36b41222b3cc5 100644 --- a/tests/integration_tests/db_engine_specs/mysql_tests.py +++ b/tests/integration_tests/db_engine_specs/mysql_tests.py @@ -21,12 +21,7 @@ from superset.db_engine_specs.mysql import MySQLEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType -from superset.models.sql_lab import Query -from superset.utils.core import GenericDataType -from tests.integration_tests.db_engine_specs.base_tests import ( - assert_generic_types, - TestDbEngineSpec, -) +from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec class TestMySQLEngineSpecsDbEngineSpec(TestDbEngineSpec): @@ -38,19 +33,6 @@ def test_get_datatype_mysql(self): self.assertEqual("TINY", MySQLEngineSpec.get_datatype(1)) self.assertEqual("VARCHAR", MySQLEngineSpec.get_datatype(15)) - def test_convert_dttm(self): - dttm = self.get_dttm() - - self.assertEqual( - MySQLEngineSpec.convert_dttm("DATE", dttm), - "STR_TO_DATE('2019-01-02', '%Y-%m-%d')", - ) - - self.assertEqual( - MySQLEngineSpec.convert_dttm("DATETIME", dttm), - "STR_TO_DATE('2019-01-02 03:04:05.678900', '%Y-%m-%d %H:%i:%s.%f')", - ) - def test_column_datatype_to_string(self): test_cases = ( (DATE(), "DATE"), @@ -69,32 +51,6 @@ def test_column_datatype_to_string(self): ) self.assertEqual(actual, expected) - def test_generic_type(self): - type_expectations = ( - # Numeric - ("TINYINT", GenericDataType.NUMERIC), - ("SMALLINT", GenericDataType.NUMERIC), - ("MEDIUMINT", GenericDataType.NUMERIC), - ("INT", GenericDataType.NUMERIC), - ("BIGINT", GenericDataType.NUMERIC), - ("DECIMAL", GenericDataType.NUMERIC), - ("FLOAT", GenericDataType.NUMERIC), - ("DOUBLE", GenericDataType.NUMERIC), - ("BIT", GenericDataType.NUMERIC), - # String - ("CHAR", GenericDataType.STRING), - ("VARCHAR", GenericDataType.STRING), - ("TINYTEXT", GenericDataType.STRING), - ("MEDIUMTEXT", GenericDataType.STRING), - ("LONGTEXT", GenericDataType.STRING), - # Temporal - ("DATE", GenericDataType.TEMPORAL), - ("DATETIME", GenericDataType.TEMPORAL), - ("TIMESTAMP", GenericDataType.TEMPORAL), - ("TIME", GenericDataType.TEMPORAL), - ) - assert_generic_types(MySQLEngineSpec, type_expectations) - def test_extract_error_message(self): from MySQLdb._exceptions import OperationalError @@ -239,22 +195,3 @@ def test_extract_errors(self): }, ) ] - - @unittest.mock.patch("sqlalchemy.engine.Engine.connect") - def test_get_cancel_query_id(self, engine_mock): - query = Query() - cursor_mock = engine_mock.return_value.__enter__.return_value - cursor_mock.fetchone.return_value = [123] - assert MySQLEngineSpec.get_cancel_query_id(cursor_mock, query) == 123 - - @unittest.mock.patch("sqlalchemy.engine.Engine.connect") - def test_cancel_query(self, engine_mock): - query = Query() - cursor_mock = engine_mock.return_value.__enter__.return_value - assert MySQLEngineSpec.cancel_query(cursor_mock, query, 123) is True - - @unittest.mock.patch("sqlalchemy.engine.Engine.connect") - def test_cancel_query_failed(self, engine_mock): - query = Query() - cursor_mock = engine_mock.raiseError.side_effect = Exception() - assert MySQLEngineSpec.cancel_query(cursor_mock, query, 123) is False diff --git a/tests/integration_tests/db_engine_specs/oracle_tests.py b/tests/integration_tests/db_engine_specs/oracle_tests.py deleted file mode 100644 index b2f4f9f23120c..0000000000000 --- a/tests/integration_tests/db_engine_specs/oracle_tests.py +++ /dev/null @@ -1,87 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from unittest import mock - -import pytest -from sqlalchemy import column -from sqlalchemy.dialects import oracle -from sqlalchemy.dialects.oracle import DATE, NVARCHAR, VARCHAR - -from superset.db_engine_specs.oracle import OracleEngineSpec -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec - - -class TestOracleDbEngineSpec(TestDbEngineSpec): - def test_oracle_sqla_column_name_length_exceeded(self): - col = column("This_Is_32_Character_Column_Name") - label = OracleEngineSpec.make_label_compatible(col.name) - self.assertEqual(label.quote, True) - label_expected = "3b26974078683be078219674eeb8f5" - self.assertEqual(label, label_expected) - - def test_oracle_time_expression_reserved_keyword_1m_grain(self): - col = column("decimal") - expr = OracleEngineSpec.get_timestamp_expr(col, None, "P1M") - result = str(expr.compile(dialect=oracle.dialect())) - self.assertEqual(result, "TRUNC(CAST(\"decimal\" as DATE), 'MONTH')") - dttm = self.get_dttm() - - def test_column_datatype_to_string(self): - test_cases = ( - (DATE(), "DATE"), - (VARCHAR(length=255), "VARCHAR(255 CHAR)"), - (VARCHAR(length=255, collation="utf8"), "VARCHAR(255 CHAR)"), - (NVARCHAR(length=128), "NVARCHAR2(128)"), - ) - - for original, expected in test_cases: - actual = OracleEngineSpec.column_datatype_to_string( - original, oracle.dialect() - ) - self.assertEqual(actual, expected) - - def test_fetch_data_no_description(self): - cursor = mock.MagicMock() - cursor.description = [] - assert OracleEngineSpec.fetch_data(cursor) == [] - - def test_fetch_data(self): - cursor = mock.MagicMock() - result = ["a", "b"] - cursor.fetchall.return_value = result - assert OracleEngineSpec.fetch_data(cursor) == result - - -@pytest.mark.parametrize( - "date_format,expected", - [ - ("DATE", "TO_DATE('2019-01-02', 'YYYY-MM-DD')"), - ("DATETIME", """TO_DATE('2019-01-02T03:04:05', 'YYYY-MM-DD"T"HH24:MI:SS')"""), - ( - "TIMESTAMP", - """TO_TIMESTAMP('2019-01-02T03:04:05.678900', 'YYYY-MM-DD"T"HH24:MI:SS.ff6')""", - ), - ( - "timestamp", - """TO_TIMESTAMP('2019-01-02T03:04:05.678900', 'YYYY-MM-DD"T"HH24:MI:SS.ff6')""", - ), - ("Other", None), - ], -) -def test_convert_dttm(date_format, expected): - dttm = TestOracleDbEngineSpec.get_dttm() - assert OracleEngineSpec.convert_dttm(date_format, dttm) == expected diff --git a/tests/integration_tests/db_engine_specs/postgres_tests.py b/tests/integration_tests/db_engine_specs/postgres_tests.py index e6eb4fc1d13ea..a6145432c2a17 100644 --- a/tests/integration_tests/db_engine_specs/postgres_tests.py +++ b/tests/integration_tests/db_engine_specs/postgres_tests.py @@ -20,15 +20,11 @@ from sqlalchemy import column, literal_column from sqlalchemy.dialects import postgresql -from superset.db_engine_specs import get_engine_specs +from superset.db_engine_specs import load_engine_specs from superset.db_engine_specs.postgres import PostgresEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.models.sql_lab import Query -from superset.utils.core import GenericDataType -from tests.integration_tests.db_engine_specs.base_tests import ( - assert_generic_types, - TestDbEngineSpec, -) +from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec from tests.integration_tests.fixtures.certificates import ssl_certificate from tests.integration_tests.fixtures.database import default_db_extra @@ -45,11 +41,11 @@ def test_get_table_names(self): inspector.get_table_names = mock.Mock(return_value=["schema.table", "table_2"]) inspector.get_foreign_table_names = mock.Mock(return_value=["table_3"]) - pg_result_expected = ["schema.table", "table_2", "table_3"] + pg_result_expected = {"schema.table", "table_2", "table_3"} pg_result = PostgresEngineSpec.get_table_names( database=mock.ANY, schema="schema", inspector=inspector ) - self.assertListEqual(pg_result_expected, pg_result) + assert pg_result_expected == pg_result def test_time_exp_literal_no_grain(self): """ @@ -100,29 +96,6 @@ def test_time_exp_mixd_case_col_1y(self): result = str(expr.compile(None, dialect=postgresql.dialect())) self.assertEqual(result, "DATE_TRUNC('year', \"MixedCase\")") - def test_convert_dttm(self): - """ - DB Eng Specs (postgres): Test conversion to date time - """ - dttm = self.get_dttm() - - self.assertEqual( - PostgresEngineSpec.convert_dttm("DATE", dttm), - "TO_DATE('2019-01-02', 'YYYY-MM-DD')", - ) - - self.assertEqual( - PostgresEngineSpec.convert_dttm("TIMESTAMP", dttm), - "TO_TIMESTAMP('2019-01-02 03:04:05.678900', 'YYYY-MM-DD HH24:MI:SS.US')", - ) - - self.assertEqual( - PostgresEngineSpec.convert_dttm("DATETIME", dttm), - "TO_TIMESTAMP('2019-01-02 03:04:05.678900', 'YYYY-MM-DD HH24:MI:SS.US')", - ) - - self.assertEqual(PostgresEngineSpec.convert_dttm("TIME", dttm), None) - def test_empty_dbapi_cursor_description(self): """ DB Eng Specs (postgres): Test empty cursor description (no columns) @@ -137,7 +110,11 @@ def test_engine_alias_name(self): """ DB Eng Specs (postgres): Test "postgres" in engine spec """ - self.assertIn("postgres", get_engine_specs()) + backends = set() + for engine in load_engine_specs(): + backends.add(engine.engine) + backends.update(engine.engine_aliases) + assert "postgres" in backends def test_extras_without_ssl(self): db = mock.Mock() @@ -174,7 +151,7 @@ def test_estimate_statement_cost_select_star(self): cursor = mock.Mock() cursor.fetchone.return_value = ( - "Seq Scan on birth_names (cost=0.00..1537.91 rows=75691 width=46)", + "Seq Scan on birth_names (cost=0.00..1537.91 rows=75691 width=46)", ) sql = "SELECT * FROM birth_names" results = PostgresEngineSpec.estimate_statement_cost(sql, cursor) @@ -500,7 +477,15 @@ def test_base_parameters_mixin(): ) parameters_from_uri = PostgresEngineSpec.get_parameters_from_uri(sqlalchemy_uri) - assert parameters_from_uri == parameters + assert parameters_from_uri == { + "username": "username", + "password": "password", + "host": "localhost", + "port": 5432, + "database": "dbname", + "query": {"foo": "bar"}, + "encryption": True, + } json_schema = PostgresEngineSpec.parameters_json_schema() assert json_schema == { @@ -529,28 +514,3 @@ def test_base_parameters_mixin(): }, "required": ["database", "host", "port", "username"], } - - -def test_generic_type(): - type_expectations = ( - # Numeric - ("SMALLINT", GenericDataType.NUMERIC), - ("INTEGER", GenericDataType.NUMERIC), - ("BIGINT", GenericDataType.NUMERIC), - ("DECIMAL", GenericDataType.NUMERIC), - ("NUMERIC", GenericDataType.NUMERIC), - ("REAL", GenericDataType.NUMERIC), - ("DOUBLE PRECISION", GenericDataType.NUMERIC), - ("MONEY", GenericDataType.NUMERIC), - # String - ("CHAR", GenericDataType.STRING), - ("VARCHAR", GenericDataType.STRING), - ("TEXT", GenericDataType.STRING), - # Temporal - ("DATE", GenericDataType.TEMPORAL), - ("TIMESTAMP", GenericDataType.TEMPORAL), - ("TIME", GenericDataType.TEMPORAL), - # Boolean - ("BOOLEAN", GenericDataType.BOOLEAN), - ) - assert_generic_types(PostgresEngineSpec, type_expectations) diff --git a/tests/integration_tests/db_engine_specs/presto_tests.py b/tests/integration_tests/db_engine_specs/presto_tests.py index 954f8d660a972..78b552ecb8635 100644 --- a/tests/integration_tests/db_engine_specs/presto_tests.py +++ b/tests/integration_tests/db_engine_specs/presto_tests.py @@ -15,17 +15,16 @@ # specific language governing permissions and limitations # under the License. from collections import namedtuple +from textwrap import dedent from unittest import mock, skipUnless import pandas as pd from sqlalchemy import types -from sqlalchemy.engine.result import RowProxy from sqlalchemy.sql import select from superset.db_engine_specs.presto import PrestoEngineSpec from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.sql_parse import ParsedQuery -from superset.utils.core import DatasourceName, GenericDataType from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec @@ -34,62 +33,53 @@ class TestPrestoDbEngineSpec(TestDbEngineSpec): def test_get_datatype_presto(self): self.assertEqual("STRING", PrestoEngineSpec.get_datatype("string")) - def test_presto_get_view_names_return_empty_list( - self, - ): # pylint: disable=invalid-name - self.assertEqual( - [], PrestoEngineSpec.get_view_names(mock.ANY, mock.ANY, mock.ANY) - ) - - @mock.patch("superset.db_engine_specs.presto.is_feature_enabled") - def test_get_view_names(self, mock_is_feature_enabled): - mock_is_feature_enabled.return_value = True - mock_execute = mock.MagicMock() - mock_fetchall = mock.MagicMock(return_value=[["a", "b,", "c"], ["d", "e"]]) + def test_get_view_names_with_schema(self): database = mock.MagicMock() - database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value.execute = ( - mock_execute - ) - database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value.fetchall = ( - mock_fetchall + mock_execute = mock.MagicMock() + database.get_raw_connection().__enter__().cursor().execute = mock_execute + database.get_raw_connection().__enter__().cursor().fetchall = mock.MagicMock( + return_value=[["a", "b,", "c"], ["d", "e"]] ) - result = PrestoEngineSpec.get_view_names(database, mock.Mock(), None) + + schema = "schema" + result = PrestoEngineSpec.get_view_names(database, mock.Mock(), schema) mock_execute.assert_called_once_with( - "SELECT table_name FROM information_schema.views", {} + dedent( + """ + SELECT table_name FROM information_schema.tables + WHERE table_schema = %(schema)s + AND table_type = 'VIEW' + """ + ).strip(), + {"schema": schema}, ) - assert result == ["a", "d"] + assert result == {"a", "d"} - @mock.patch("superset.db_engine_specs.presto.is_feature_enabled") - def test_get_view_names_with_schema(self, mock_is_feature_enabled): - mock_is_feature_enabled.return_value = True - mock_execute = mock.MagicMock() - mock_fetchall = mock.MagicMock(return_value=[["a", "b,", "c"], ["d", "e"]]) + def test_get_view_names_without_schema(self): database = mock.MagicMock() - database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value.execute = ( - mock_execute - ) - database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value.fetchall = ( - mock_fetchall + mock_execute = mock.MagicMock() + database.get_raw_connection().__enter__().cursor().execute = mock_execute + database.get_raw_connection().__enter__().cursor().fetchall = mock.MagicMock( + return_value=[["a", "b,", "c"], ["d", "e"]] ) - schema = "schema" - result = PrestoEngineSpec.get_view_names(database, mock.Mock(), schema) + result = PrestoEngineSpec.get_view_names(database, mock.Mock(), None) mock_execute.assert_called_once_with( - "SELECT table_name FROM information_schema.views " - "WHERE table_schema=%(schema)s", - {"schema": schema}, + dedent( + """ + SELECT table_name FROM information_schema.tables + WHERE table_type = 'VIEW' + """ + ).strip(), + {}, ) - assert result == ["a", "d"] + assert result == {"a", "d"} def verify_presto_column(self, column, expected_results): inspector = mock.Mock() inspector.engine.dialect.identifier_preparer.quote_identifier = mock.Mock() - keymap = { - "Column": (None, None, 0), - "Type": (None, None, 1), - "Null": (None, None, 2), - } - row = RowProxy(mock.Mock(), column, [None, None, None, None], keymap) - inspector.bind.execute = mock.Mock(return_value=[row]) + row = mock.Mock() + row.Column, row.Type, row.Null = column + inspector.bind.execute.return_value.fetchall = mock.Mock(return_value=[row]) results = PrestoEngineSpec.get_columns(inspector, "", "") self.assertEqual(len(expected_results), len(results)) for expected_result, result in zip(expected_results, results): @@ -497,7 +487,8 @@ def test_presto_extra_table_metadata(self): db.get_df = mock.Mock(return_value=df) PrestoEngineSpec.get_create_view = mock.Mock(return_value=None) result = PrestoEngineSpec.extra_table_metadata(db, "test_table", "test_schema") - self.assertEqual({"ds": "01-01-19", "hour": 1}, result["partitions"]["latest"]) + assert result["partitions"]["cols"] == ["ds", "hour"] + assert result["partitions"]["latest"] == {"ds": "01-01-19", "hour": 1} def test_presto_where_latest_partition(self): db = mock.Mock() @@ -632,86 +623,17 @@ def test_presto_expand_data_array(self): self.assertEqual(actual_data, expected_data) self.assertEqual(actual_expanded_cols, expected_expanded_cols) - def test_get_sqla_column_type(self): - column_spec = PrestoEngineSpec.get_column_spec("varchar(255)") - assert isinstance(column_spec.sqla_type, types.VARCHAR) - assert column_spec.sqla_type.length == 255 - self.assertEqual(column_spec.generic_type, GenericDataType.STRING) - - column_spec = PrestoEngineSpec.get_column_spec("varchar") - assert isinstance(column_spec.sqla_type, types.String) - assert column_spec.sqla_type.length is None - self.assertEqual(column_spec.generic_type, GenericDataType.STRING) - - column_spec = PrestoEngineSpec.get_column_spec("char(10)") - assert isinstance(column_spec.sqla_type, types.CHAR) - assert column_spec.sqla_type.length == 10 - self.assertEqual(column_spec.generic_type, GenericDataType.STRING) - - column_spec = PrestoEngineSpec.get_column_spec("char") - assert isinstance(column_spec.sqla_type, types.CHAR) - assert column_spec.sqla_type.length is None - self.assertEqual(column_spec.generic_type, GenericDataType.STRING) - - column_spec = PrestoEngineSpec.get_column_spec("integer") - assert isinstance(column_spec.sqla_type, types.Integer) - self.assertEqual(column_spec.generic_type, GenericDataType.NUMERIC) - - column_spec = PrestoEngineSpec.get_column_spec("time") - assert isinstance(column_spec.sqla_type, types.Time) - self.assertEqual(column_spec.generic_type, GenericDataType.TEMPORAL) - - column_spec = PrestoEngineSpec.get_column_spec("timestamp") - assert isinstance(column_spec.sqla_type, types.TIMESTAMP) - self.assertEqual(column_spec.generic_type, GenericDataType.TEMPORAL) - - sqla_type = PrestoEngineSpec.get_sqla_column_type(None) - assert sqla_type is None - - @mock.patch( - "superset.utils.feature_flag_manager.FeatureFlagManager.is_feature_enabled" - ) - @mock.patch("superset.db_engine_specs.base.BaseEngineSpec.get_table_names") - @mock.patch("superset.db_engine_specs.presto.PrestoEngineSpec.get_view_names") - def test_get_table_names_no_split_views_from_tables( - self, mock_get_view_names, mock_get_table_names, mock_is_feature_enabled - ): - mock_get_view_names.return_value = ["view1", "view2"] - table_names = ["table1", "table2", "view1", "view2"] - mock_get_table_names.return_value = table_names - mock_is_feature_enabled.return_value = False - tables = PrestoEngineSpec.get_table_names(mock.Mock(), mock.Mock(), None) - assert tables == table_names - - @mock.patch( - "superset.utils.feature_flag_manager.FeatureFlagManager.is_feature_enabled" - ) - @mock.patch("superset.db_engine_specs.base.BaseEngineSpec.get_table_names") - @mock.patch("superset.db_engine_specs.presto.PrestoEngineSpec.get_view_names") - def test_get_table_names_split_views_from_tables( - self, mock_get_view_names, mock_get_table_names, mock_is_feature_enabled - ): - mock_get_view_names.return_value = ["view1", "view2"] - table_names = ["table1", "table2", "view1", "view2"] - mock_get_table_names.return_value = table_names - mock_is_feature_enabled.return_value = True - tables = PrestoEngineSpec.get_table_names(mock.Mock(), mock.Mock(), None) - assert sorted(tables) == sorted(table_names) - - @mock.patch( - "superset.utils.feature_flag_manager.FeatureFlagManager.is_feature_enabled" - ) @mock.patch("superset.db_engine_specs.base.BaseEngineSpec.get_table_names") @mock.patch("superset.db_engine_specs.presto.PrestoEngineSpec.get_view_names") - def test_get_table_names_split_views_from_tables_no_tables( - self, mock_get_view_names, mock_get_table_names, mock_is_feature_enabled + def test_get_table_names( + self, + mock_get_view_names, + mock_get_table_names, ): - mock_get_view_names.return_value = [] - table_names = [] - mock_get_table_names.return_value = table_names - mock_is_feature_enabled.return_value = True + mock_get_view_names.return_value = {"view1", "view2"} + mock_get_table_names.return_value = {"table1", "table2", "view1", "view2"} tables = PrestoEngineSpec.get_table_names(mock.Mock(), mock.Mock(), None) - assert tables == [] + assert tables == {"table1", "table2"} def test_get_full_name(self): names = [ @@ -749,25 +671,29 @@ def test_show_columns(self): inspector.engine.dialect.identifier_preparer.quote_identifier = ( lambda x: f'"{x}"' ) - mock_execute = mock.MagicMock(return_value=["a", "b"]) - inspector.bind.execute = mock_execute + inspector.bind.execute.return_value.fetchall = mock.MagicMock( + return_value=["a", "b"] + ) table_name = "table_name" result = PrestoEngineSpec._show_columns(inspector, table_name, None) assert result == ["a", "b"] - mock_execute.assert_called_once_with(f'SHOW COLUMNS FROM "{table_name}"') + inspector.bind.execute.assert_called_once_with( + f'SHOW COLUMNS FROM "{table_name}"' + ) def test_show_columns_with_schema(self): inspector = mock.MagicMock() inspector.engine.dialect.identifier_preparer.quote_identifier = ( lambda x: f'"{x}"' ) - mock_execute = mock.MagicMock(return_value=["a", "b"]) - inspector.bind.execute = mock_execute + inspector.bind.execute.return_value.fetchall = mock.MagicMock( + return_value=["a", "b"] + ) table_name = "table_name" schema = "schema" result = PrestoEngineSpec._show_columns(inspector, table_name, schema) assert result == ["a", "b"] - mock_execute.assert_called_once_with( + inspector.bind.execute.assert_called_once_with( f'SHOW COLUMNS FROM "{schema}"."{table_name}"' ) @@ -852,32 +778,13 @@ def test_estimate_statement_cost_invalid_syntax(self): "DROP TABLE brth_names", mock_cursor ) - def test_get_all_datasource_names(self): - df = pd.DataFrame.from_dict( - {"table_schema": ["schema1", "schema2"], "table_name": ["name1", "name2"]} - ) - database = mock.MagicMock() - database.get_df.return_value = df - result = PrestoEngineSpec.get_all_datasource_names(database, "table") - expected_result = [ - DatasourceName(schema="schema1", table="name1"), - DatasourceName(schema="schema2", table="name2"), - ] - assert result == expected_result - def test_get_create_view(self): mock_execute = mock.MagicMock() mock_fetchall = mock.MagicMock(return_value=[["a", "b,", "c"], ["d", "e"]]) database = mock.MagicMock() - database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value.execute = ( - mock_execute - ) - database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value.fetchall = ( - mock_fetchall - ) - database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value.poll.return_value = ( - False - ) + database.get_raw_connection().__enter__().cursor().execute = mock_execute + database.get_raw_connection().__enter__().cursor().fetchall = mock_fetchall + database.get_raw_connection().__enter__().cursor().return_value = False schema = "schema" table = "table" result = PrestoEngineSpec.get_create_view(database, schema=schema, table=table) @@ -887,9 +794,7 @@ def test_get_create_view(self): def test_get_create_view_exception(self): mock_execute = mock.MagicMock(side_effect=Exception()) database = mock.MagicMock() - database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value.execute = ( - mock_execute - ) + database.get_raw_connection().__enter__().cursor().execute = mock_execute schema = "schema" table = "table" with self.assertRaises(Exception): @@ -900,9 +805,7 @@ def test_get_create_view_database_error(self): mock_execute = mock.MagicMock(side_effect=DatabaseError()) database = mock.MagicMock() - database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value.execute = ( - mock_execute - ) + database.get_raw_connection().__enter__().cursor().execute = mock_execute schema = "schema" table = "table" result = PrestoEngineSpec.get_create_view(database, schema=schema, table=table) diff --git a/tests/integration_tests/db_engine_specs/trino_tests.py b/tests/integration_tests/db_engine_specs/trino_tests.py deleted file mode 100644 index fc83b8c64c3d7..0000000000000 --- a/tests/integration_tests/db_engine_specs/trino_tests.py +++ /dev/null @@ -1,150 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -import json -from typing import Any, Dict -from unittest.mock import Mock, patch - -import pytest -from sqlalchemy.engine.url import URL - -import superset.config -from superset.db_engine_specs.trino import TrinoEngineSpec -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec - - -class TestTrinoDbEngineSpec(TestDbEngineSpec): - def test_get_extra_params(self): - database = Mock() - - database.extra = json.dumps({}) - database.server_cert = None - extra = TrinoEngineSpec.get_extra_params(database) - expected = {"engine_params": {"connect_args": {}}} - self.assertEqual(extra, expected) - - expected = { - "first": 1, - "engine_params": {"second": "two", "connect_args": {"third": "three"}}, - } - database.extra = json.dumps(expected) - database.server_cert = None - extra = TrinoEngineSpec.get_extra_params(database) - self.assertEqual(extra, expected) - - @patch("superset.utils.core.create_ssl_cert_file") - def test_get_extra_params_with_server_cert(self, create_ssl_cert_file_func: Mock): - database = Mock() - - database.extra = json.dumps({}) - database.server_cert = "TEST_CERT" - create_ssl_cert_file_func.return_value = "/path/to/tls.crt" - extra = TrinoEngineSpec.get_extra_params(database) - - connect_args = extra.get("engine_params", {}).get("connect_args", {}) - self.assertEqual(connect_args.get("http_scheme"), "https") - self.assertEqual(connect_args.get("verify"), "/path/to/tls.crt") - create_ssl_cert_file_func.assert_called_once_with(database.server_cert) - - @patch("trino.auth.BasicAuthentication") - def test_auth_basic(self, auth: Mock): - database = Mock() - - auth_params = {"username": "username", "password": "password"} - database.encrypted_extra = json.dumps( - {"auth_method": "basic", "auth_params": auth_params} - ) - - params: Dict[str, Any] = {} - TrinoEngineSpec.update_encrypted_extra_params(database, params) - connect_args = params.setdefault("connect_args", {}) - self.assertEqual(connect_args.get("http_scheme"), "https") - auth.assert_called_once_with(**auth_params) - - @patch("trino.auth.KerberosAuthentication") - def test_auth_kerberos(self, auth: Mock): - database = Mock() - - auth_params = { - "service_name": "superset", - "mutual_authentication": False, - "delegate": True, - } - database.encrypted_extra = json.dumps( - {"auth_method": "kerberos", "auth_params": auth_params} - ) - - params: Dict[str, Any] = {} - TrinoEngineSpec.update_encrypted_extra_params(database, params) - connect_args = params.setdefault("connect_args", {}) - self.assertEqual(connect_args.get("http_scheme"), "https") - auth.assert_called_once_with(**auth_params) - - @patch("trino.auth.JWTAuthentication") - def test_auth_jwt(self, auth: Mock): - database = Mock() - - auth_params = {"token": "jwt-token-string"} - database.encrypted_extra = json.dumps( - {"auth_method": "jwt", "auth_params": auth_params} - ) - - params: Dict[str, Any] = {} - TrinoEngineSpec.update_encrypted_extra_params(database, params) - connect_args = params.setdefault("connect_args", {}) - self.assertEqual(connect_args.get("http_scheme"), "https") - auth.assert_called_once_with(**auth_params) - - def test_auth_custom_auth(self): - database = Mock() - auth_class = Mock() - - auth_method = "custom_auth" - auth_params = {"params1": "params1", "params2": "params2"} - database.encrypted_extra = json.dumps( - {"auth_method": auth_method, "auth_params": auth_params} - ) - - with patch.dict( - "superset.config.ALLOWED_EXTRA_AUTHENTICATIONS", - {"trino": {"custom_auth": auth_class}}, - clear=True, - ): - params: Dict[str, Any] = {} - TrinoEngineSpec.update_encrypted_extra_params(database, params) - - connect_args = params.setdefault("connect_args", {}) - self.assertEqual(connect_args.get("http_scheme"), "https") - - auth_class.assert_called_once_with(**auth_params) - - def test_auth_custom_auth_denied(self): - database = Mock() - auth_method = "my.module:TrinoAuthClass" - auth_params = {"params1": "params1", "params2": "params2"} - database.encrypted_extra = json.dumps( - {"auth_method": auth_method, "auth_params": auth_params} - ) - - superset.config.ALLOWED_EXTRA_AUTHENTICATIONS = {} - - with pytest.raises(ValueError) as excinfo: - TrinoEngineSpec.update_encrypted_extra_params(database, {}) - - assert str(excinfo.value) == ( - f"For security reason, custom authentication '{auth_method}' " - f"must be listed in 'ALLOWED_EXTRA_AUTHENTICATIONS' config" - ) diff --git a/tests/integration_tests/email_tests.py b/tests/integration_tests/email_tests.py index 68e4aaf71e3f6..723901b74fb51 100644 --- a/tests/integration_tests/email_tests.py +++ b/tests/integration_tests/email_tests.py @@ -59,6 +59,37 @@ def test_send_smtp(self, mock_send_mime): mimeapp = MIMEApplication("attachment") assert msg.get_payload()[-1].get_payload() == mimeapp.get_payload() + @mock.patch("superset.utils.core.send_mime_email") + def test_send_smtp_with_email_mutator(self, mock_send_mime): + attachment = tempfile.NamedTemporaryFile() + attachment.write(b"attachment") + attachment.seek(0) + + # putting this into a variable so that we can reset after the test + base_email_mutator = app.config["EMAIL_HEADER_MUTATOR"] + + def mutator(msg, **kwargs): + msg["foo"] = "bar" + return msg + + app.config["EMAIL_HEADER_MUTATOR"] = mutator + utils.send_email_smtp( + "to", "subject", "content", app.config, files=[attachment.name] + ) + assert mock_send_mime.called + call_args = mock_send_mime.call_args[0] + logger.debug(call_args) + assert call_args[0] == app.config["SMTP_MAIL_FROM"] + assert call_args[1] == ["to"] + msg = call_args[2] + assert msg["Subject"] == "subject" + assert msg["From"] == app.config["SMTP_MAIL_FROM"] + assert msg["foo"] == "bar" + assert len(msg.get_payload()) == 2 + mimeapp = MIMEApplication("attachment") + assert msg.get_payload()[-1].get_payload() == mimeapp.get_payload() + app.config["EMAIL_HEADER_MUTATOR"] = base_email_mutator + @mock.patch("superset.utils.core.send_mime_email") def test_send_smtp_data(self, mock_send_mime): utils.send_email_smtp( @@ -174,6 +205,32 @@ def test_send_mime_tls_server_auth(self, mock_smtp): called_context = mock_smtp.return_value.starttls.call_args.kwargs["context"] self.assertEqual(called_context.verify_mode, ssl.CERT_REQUIRED) + @mock.patch("smtplib.SMTP_SSL") + @mock.patch("smtplib.SMTP") + def test_send_mime_ssl_server_auth(self, mock_smtp, mock_smtp_ssl): + app.config["SMTP_SSL"] = True + app.config["SMTP_SSL_SERVER_AUTH"] = True + mock_smtp.return_value = mock.Mock() + mock_smtp_ssl.return_value = mock.Mock() + utils.send_mime_email("from", "to", MIMEMultipart(), app.config, dryrun=False) + assert not mock_smtp.called + mock_smtp_ssl.assert_called_with( + app.config["SMTP_HOST"], app.config["SMTP_PORT"], context=mock.ANY + ) + called_context = mock_smtp_ssl.call_args.kwargs["context"] + self.assertEqual(called_context.verify_mode, ssl.CERT_REQUIRED) + + @mock.patch("smtplib.SMTP") + def test_send_mime_tls_server_auth(self, mock_smtp): + app.config["SMTP_STARTTLS"] = True + app.config["SMTP_SSL_SERVER_AUTH"] = True + mock_smtp.return_value = mock.Mock() + mock_smtp.return_value.starttls.return_value = mock.Mock() + utils.send_mime_email("from", "to", MIMEMultipart(), app.config, dryrun=False) + mock_smtp.return_value.starttls.assert_called_with(context=mock.ANY) + called_context = mock_smtp.return_value.starttls.call_args.kwargs["context"] + self.assertEqual(called_context.verify_mode, ssl.CERT_REQUIRED) + @mock.patch("smtplib.SMTP_SSL") @mock.patch("smtplib.SMTP") def test_send_mime_noauth(self, mock_smtp, mock_smtp_ssl): diff --git a/tests/integration_tests/embedded/test_view.py b/tests/integration_tests/embedded/test_view.py new file mode 100644 index 0000000000000..9f524e9c09e2b --- /dev/null +++ b/tests/integration_tests/embedded/test_view.py @@ -0,0 +1,72 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +from typing import TYPE_CHECKING +from unittest import mock + +import pytest + +from superset import db +from superset.embedded.dao import EmbeddedDAO +from superset.models.dashboard import Dashboard +from tests.integration_tests.fixtures.birth_names_dashboard import ( + load_birth_names_dashboard_with_slices, + load_birth_names_data, +) +from tests.integration_tests.fixtures.client import client + +if TYPE_CHECKING: + from typing import Any + + from flask.testing import FlaskClient + + +@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") +@mock.patch.dict( + "superset.extensions.feature_flag_manager._feature_flags", + EMBEDDED_SUPERSET=True, +) +def test_get_embedded_dashboard(client: FlaskClient[Any]): + dash = db.session.query(Dashboard).filter_by(slug="births").first() + embedded = EmbeddedDAO.upsert(dash, []) + uri = f"embedded/{embedded.uuid}" + response = client.get(uri) + assert response.status_code == 200 + + +@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") +@mock.patch.dict( + "superset.extensions.feature_flag_manager._feature_flags", + EMBEDDED_SUPERSET=True, +) +def test_get_embedded_dashboard_referrer_not_allowed(client: FlaskClient[Any]): + dash = db.session.query(Dashboard).filter_by(slug="births").first() + embedded = EmbeddedDAO.upsert(dash, ["test.example.com"]) + uri = f"embedded/{embedded.uuid}" + response = client.get(uri) + assert response.status_code == 403 + + +@mock.patch.dict( + "superset.extensions.feature_flag_manager._feature_flags", + EMBEDDED_SUPERSET=True, +) +def test_get_embedded_dashboard_non_found(client: FlaskClient[Any]): + uri = f"embedded/bad-uuid" + response = client.get(uri) + assert response.status_code == 404 diff --git a/tests/integration_tests/event_logger_tests.py b/tests/integration_tests/event_logger_tests.py index ddbe42bb4fc5a..4553bb9dc789b 100644 --- a/tests/integration_tests/event_logger_tests.py +++ b/tests/integration_tests/event_logger_tests.py @@ -112,7 +112,7 @@ def test_func(arg1, add_extra_log_payload, karg1=1): ) self.assertGreaterEqual(payload["duration_ms"], 100) - @patch("superset.utils.log.g", spec={}) + @patch("superset.utils.core.g", spec={}) @freeze_time("Jan 14th, 2020", auto_tick_seconds=15) def test_context_manager_log(self, mock_g): class DummyEventLogger(AbstractEventLogger): @@ -144,12 +144,12 @@ def log( assert logger.records == [ { "records": [{"path": "/", "engine": "bar"}], - "user_id": "2", + "user_id": 2, "duration": 15000.0, } ] - @patch("superset.utils.log.g", spec={}) + @patch("superset.utils.core.g", spec={}) def test_context_manager_log_with_context(self, mock_g): class DummyEventLogger(AbstractEventLogger): def __init__(self): @@ -191,12 +191,12 @@ def log( "payload_override": {"engine": "sqllite"}, } ], - "user_id": "2", + "user_id": 2, "duration": 5558756000, } ] - @patch("superset.utils.log.g", spec={}) + @patch("superset.utils.core.g", spec={}) def test_log_with_context_user_null(self, mock_g): class DummyEventLogger(AbstractEventLogger): def __init__(self): diff --git a/tests/integration_tests/explore/api_tests.py b/tests/integration_tests/explore/api_tests.py new file mode 100644 index 0000000000000..af5bd8813753d --- /dev/null +++ b/tests/integration_tests/explore/api_tests.py @@ -0,0 +1,240 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import json +from unittest.mock import patch + +import pytest +from flask_appbuilder.security.sqla.models import User +from sqlalchemy.orm import Session + +from superset.connectors.sqla.models import SqlaTable +from superset.explore.exceptions import DatasetAccessDeniedError +from superset.explore.form_data.commands.state import TemporaryExploreState +from superset.extensions import cache_manager +from superset.models.slice import Slice +from tests.integration_tests.fixtures.world_bank_dashboard import ( + load_world_bank_dashboard_with_slices, + load_world_bank_data, +) +from tests.integration_tests.test_app import app + +FORM_DATA_KEY = "form_data_key" +FORM_DATA = {"test": "test value"} + + +@pytest.fixture +def chart_id(load_world_bank_dashboard_with_slices) -> int: + with app.app_context() as ctx: + session: Session = ctx.app.appbuilder.get_session + chart = session.query(Slice).filter_by(slice_name="World's Population").one() + return chart.id + + +@pytest.fixture +def admin_id() -> int: + with app.app_context() as ctx: + session: Session = ctx.app.appbuilder.get_session + admin = session.query(User).filter_by(username="admin").one() + return admin.id + + +@pytest.fixture +def dataset() -> int: + with app.app_context() as ctx: + session: Session = ctx.app.appbuilder.get_session + dataset = ( + session.query(SqlaTable) + .filter_by(table_name="wb_health_population") + .first() + ) + return dataset + + +@pytest.fixture(autouse=True) +def cache(chart_id, admin_id, dataset): + entry: TemporaryExploreState = { + "owner": admin_id, + "datasource_id": dataset.id, + "datasource_type": dataset.type, + "chart_id": chart_id, + "form_data": json.dumps(FORM_DATA), + } + cache_manager.explore_form_data_cache.set(FORM_DATA_KEY, entry) + + +# partially match the dataset using the most important attributes +def assert_dataset(result, dataset_id): + dataset = result["dataset"] + assert dataset["id"] == dataset_id + assert dataset["datasource_name"] == "wb_health_population" + assert dataset["is_sqllab_view"] == False + assert dataset["main_dttm_col"] == "year" + assert dataset["sql"] == None + assert dataset["type"] == "table" + assert dataset["uid"] == f"{dataset_id}__table" + + +# partially match the slice using the most important attributes +def assert_slice(result, chart_id, dataset_id): + slice = result["slice"] + assert slice["edit_url"] == f"/chart/edit/{chart_id}" + assert slice["is_managed_externally"] == False + assert slice["slice_id"] == chart_id + assert slice["slice_name"] == "World's Population" + assert slice["form_data"]["datasource"] == f"{dataset_id}__table" + assert slice["form_data"]["viz_type"] == "big_number" + + +def test_no_params_provided(test_client, login_as_admin): + resp = test_client.get(f"api/v1/explore/") + assert resp.status_code == 200 + data = json.loads(resp.data.decode("utf-8")) + result = data.get("result") + assert result["dataset"]["name"] == "[Missing Dataset]" + assert result["form_data"]["datasource"] == "None__table" + assert result["message"] == None + assert result["slice"] == None + + +def test_get_from_cache(test_client, login_as_admin, dataset): + resp = test_client.get( + f"api/v1/explore/?form_data_key={FORM_DATA_KEY}&datasource_id={dataset.id}&datasource_type={dataset.type}" + ) + assert resp.status_code == 200 + data = json.loads(resp.data.decode("utf-8")) + result = data.get("result") + assert_dataset(result, dataset.id) + assert result["form_data"]["datasource"] == f"{dataset.id}__table" + assert result["form_data"]["test"] == "test value" + assert result["message"] == None + assert result["slice"] == None + + +def test_get_from_cache_unknown_key_chart_id( + test_client, login_as_admin, chart_id, dataset +): + unknown_key = "unknown_key" + resp = test_client.get( + f"api/v1/explore/?form_data_key={unknown_key}&slice_id={chart_id}" + ) + assert resp.status_code == 200 + data = json.loads(resp.data.decode("utf-8")) + result = data.get("result") + assert_dataset(result, dataset.id) + assert_slice(result, chart_id, dataset.id) + assert result["form_data"]["datasource"] == f"{dataset.id}__table" + assert ( + result["message"] + == "Form data not found in cache, reverting to chart metadata." + ) + + +def test_get_from_cache_unknown_key_dataset(test_client, login_as_admin, dataset): + unknown_key = "unknown_key" + resp = test_client.get( + f"api/v1/explore/?form_data_key={unknown_key}&datasource_id={dataset.id}&datasource_type={dataset.type}" + ) + assert resp.status_code == 200 + data = json.loads(resp.data.decode("utf-8")) + result = data.get("result") + assert_dataset(result, dataset.id) + assert result["form_data"]["datasource"] == f"{dataset.id}__table" + assert ( + result["message"] + == "Form data not found in cache, reverting to dataset metadata." + ) + assert result["slice"] == None + + +def test_get_from_cache_unknown_key_no_extra_parameters(test_client, login_as_admin): + unknown_key = "unknown_key" + resp = test_client.get(f"api/v1/explore/?form_data_key={unknown_key}") + assert resp.status_code == 200 + data = json.loads(resp.data.decode("utf-8")) + result = data.get("result") + assert result["dataset"]["name"] == "[Missing Dataset]" + assert result["form_data"]["datasource"] == "None__table" + assert result["message"] == None + assert result["slice"] == None + + +def test_get_from_permalink(test_client, login_as_admin, chart_id, dataset): + form_data = { + "chart_id": chart_id, + "datasource": f"{dataset.id}__{dataset.type}", + **FORM_DATA, + } + resp = test_client.post(f"api/v1/explore/permalink", json={"formData": form_data}) + data = json.loads(resp.data.decode("utf-8")) + permalink_key = data["key"] + resp = test_client.get(f"api/v1/explore/?permalink_key={permalink_key}") + assert resp.status_code == 200 + data = json.loads(resp.data.decode("utf-8")) + result = data.get("result") + assert_dataset(result, dataset.id) + assert result["form_data"]["datasource"] == f"{dataset.id}__table" + assert result["form_data"]["test"] == "test value" + assert result["message"] == None + assert result["slice"] == None + + +def test_get_from_permalink_unknown_key(test_client, login_as_admin): + unknown_key = "unknown_key" + resp = test_client.get(f"api/v1/explore/?permalink_key={unknown_key}") + assert resp.status_code == 404 + + +@patch("superset.security.SupersetSecurityManager.can_access_datasource") +def test_get_dataset_access_denied( + mock_can_access_datasource, test_client, login_as_admin, dataset +): + message = "Dataset access denied" + mock_can_access_datasource.side_effect = DatasetAccessDeniedError( + message=message, datasource_id=dataset.id, datasource_type=dataset.type + ) + resp = test_client.get( + f"api/v1/explore/?form_data_key={FORM_DATA_KEY}&datasource_id={dataset.id}&datasource_type={dataset.type}" + ) + data = json.loads(resp.data.decode("utf-8")) + assert resp.status_code == 403 + assert data["datasource_id"] == dataset.id + assert data["datasource_type"] == dataset.type + assert data["message"] == message + + +@patch("superset.datasource.dao.DatasourceDAO.get_datasource") +def test_wrong_endpoint(mock_get_datasource, test_client, login_as_admin, dataset): + dataset.default_endpoint = "another_endpoint" + mock_get_datasource.return_value = dataset + resp = test_client.get( + f"api/v1/explore/?datasource_id={dataset.id}&datasource_type={dataset.type}" + ) + data = json.loads(resp.data.decode("utf-8")) + assert resp.status_code == 302 + assert data["redirect"] == dataset.default_endpoint + + +def test_get_url_params(test_client, login_as_admin, chart_id): + resp = test_client.get(f"api/v1/explore/?slice_id={chart_id}&foo=bar") + assert resp.status_code == 200 + data = json.loads(resp.data.decode("utf-8")) + result = data.get("result") + + assert result["form_data"]["url_params"] == { + "foo": "bar", + "slice_id": str(chart_id), + } diff --git a/tests/integration_tests/explore/form_data/api_tests.py b/tests/integration_tests/explore/form_data/api_tests.py index 8b375df56ae38..0e73d0b51656a 100644 --- a/tests/integration_tests/explore/form_data/api_tests.py +++ b/tests/integration_tests/explore/form_data/api_tests.py @@ -26,8 +26,7 @@ from superset.explore.form_data.commands.state import TemporaryExploreState from superset.extensions import cache_manager from superset.models.slice import Slice -from tests.integration_tests.base_tests import login -from tests.integration_tests.fixtures.client import client +from superset.utils.core import DatasourceType from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices, load_world_bank_data, @@ -79,82 +78,85 @@ def cache(chart_id, admin_id, datasource): cache_manager.explore_form_data_cache.set(KEY, entry) -def test_post(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_post(test_client, login_as_admin, chart_id: int, datasource: SqlaTable): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": INITIAL_FORM_DATA, } - resp = client.post("api/v1/explore/form_data", json=payload) + resp = test_client.post("api/v1/explore/form_data", json=payload) assert resp.status_code == 201 -def test_post_bad_request_non_string(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_post_bad_request_non_string( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable +): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": 1234, } - resp = client.post("api/v1/explore/form_data", json=payload) + resp = test_client.post("api/v1/explore/form_data", json=payload) assert resp.status_code == 400 -def test_post_bad_request_non_json_string(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_post_bad_request_non_json_string( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable +): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": "foo", } - resp = client.post("api/v1/explore/form_data", json=payload) + resp = test_client.post("api/v1/explore/form_data", json=payload) assert resp.status_code == 400 -def test_post_access_denied(client, chart_id: int, datasource: SqlaTable): - login(client, "gamma") +def test_post_access_denied( + test_client, login_as, chart_id: int, datasource: SqlaTable +): + login_as("gamma") payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": INITIAL_FORM_DATA, } - resp = client.post("api/v1/explore/form_data", json=payload) - assert resp.status_code == 404 + resp = test_client.post("api/v1/explore/form_data", json=payload) + assert resp.status_code == 403 -def test_post_same_key_for_same_context(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_post_same_key_for_same_context( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable +): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": UPDATED_FORM_DATA, } - resp = client.post("api/v1/explore/form_data?tab_id=1", json=payload) + resp = test_client.post("api/v1/explore/form_data?tab_id=1", json=payload) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.post("api/v1/explore/form_data?tab_id=1", json=payload) + resp = test_client.post("api/v1/explore/form_data?tab_id=1", json=payload) data = json.loads(resp.data.decode("utf-8")) second_key = data.get("key") assert first_key == second_key def test_post_different_key_for_different_context( - client, chart_id: int, datasource: SqlaTable + test_client, login_as_admin, chart_id: int, datasource: SqlaTable ): - login(client, "admin") payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": UPDATED_FORM_DATA, } - resp = client.post("api/v1/explore/form_data?tab_id=1", json=payload) + resp = test_client.post("api/v1/explore/form_data?tab_id=1", json=payload) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") payload = { @@ -162,241 +164,244 @@ def test_post_different_key_for_different_context( "datasource_type": datasource.type, "form_data": json.dumps({"test": "initial value"}), } - resp = client.post("api/v1/explore/form_data?tab_id=1", json=payload) + resp = test_client.post("api/v1/explore/form_data?tab_id=1", json=payload) data = json.loads(resp.data.decode("utf-8")) second_key = data.get("key") assert first_key != second_key -def test_post_same_key_for_same_tab_id(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_post_same_key_for_same_tab_id( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable +): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": json.dumps({"test": "initial value"}), } - resp = client.post("api/v1/explore/form_data?tab_id=1", json=payload) + resp = test_client.post("api/v1/explore/form_data?tab_id=1", json=payload) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.post("api/v1/explore/form_data?tab_id=1", json=payload) + resp = test_client.post("api/v1/explore/form_data?tab_id=1", json=payload) data = json.loads(resp.data.decode("utf-8")) second_key = data.get("key") assert first_key == second_key def test_post_different_key_for_different_tab_id( - client, chart_id: int, datasource: SqlaTable + test_client, login_as_admin, chart_id: int, datasource: SqlaTable ): - login(client, "admin") payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": json.dumps({"test": "initial value"}), } - resp = client.post("api/v1/explore/form_data?tab_id=1", json=payload) + resp = test_client.post("api/v1/explore/form_data?tab_id=1", json=payload) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.post("api/v1/explore/form_data?tab_id=2", json=payload) + resp = test_client.post("api/v1/explore/form_data?tab_id=2", json=payload) data = json.loads(resp.data.decode("utf-8")) second_key = data.get("key") assert first_key != second_key -def test_post_different_key_for_no_tab_id(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_post_different_key_for_no_tab_id( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable +): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": INITIAL_FORM_DATA, } - resp = client.post("api/v1/explore/form_data", json=payload) + resp = test_client.post("api/v1/explore/form_data", json=payload) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.post("api/v1/explore/form_data", json=payload) + resp = test_client.post("api/v1/explore/form_data", json=payload) data = json.loads(resp.data.decode("utf-8")) second_key = data.get("key") assert first_key != second_key -def test_put(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_put(test_client, login_as_admin, chart_id: int, datasource: SqlaTable): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": UPDATED_FORM_DATA, } - resp = client.put(f"api/v1/explore/form_data/{KEY}", json=payload) + resp = test_client.put(f"api/v1/explore/form_data/{KEY}", json=payload) assert resp.status_code == 200 -def test_put_same_key_for_same_tab_id(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_put_same_key_for_same_tab_id( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable +): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": UPDATED_FORM_DATA, } - resp = client.put(f"api/v1/explore/form_data/{KEY}?tab_id=1", json=payload) + resp = test_client.put(f"api/v1/explore/form_data/{KEY}?tab_id=1", json=payload) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.put(f"api/v1/explore/form_data/{KEY}?tab_id=1", json=payload) + resp = test_client.put(f"api/v1/explore/form_data/{KEY}?tab_id=1", json=payload) data = json.loads(resp.data.decode("utf-8")) second_key = data.get("key") assert first_key == second_key def test_put_different_key_for_different_tab_id( - client, chart_id: int, datasource: SqlaTable + test_client, login_as_admin, chart_id: int, datasource: SqlaTable ): - login(client, "admin") payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": UPDATED_FORM_DATA, } - resp = client.put(f"api/v1/explore/form_data/{KEY}?tab_id=1", json=payload) + resp = test_client.put(f"api/v1/explore/form_data/{KEY}?tab_id=1", json=payload) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.put(f"api/v1/explore/form_data/{KEY}?tab_id=2", json=payload) + resp = test_client.put(f"api/v1/explore/form_data/{KEY}?tab_id=2", json=payload) data = json.loads(resp.data.decode("utf-8")) second_key = data.get("key") assert first_key != second_key -def test_put_different_key_for_no_tab_id(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_put_different_key_for_no_tab_id( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable +): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": UPDATED_FORM_DATA, } - resp = client.put(f"api/v1/explore/form_data/{KEY}", json=payload) + resp = test_client.put(f"api/v1/explore/form_data/{KEY}", json=payload) data = json.loads(resp.data.decode("utf-8")) first_key = data.get("key") - resp = client.put(f"api/v1/explore/form_data/{KEY}", json=payload) + resp = test_client.put(f"api/v1/explore/form_data/{KEY}", json=payload) data = json.loads(resp.data.decode("utf-8")) second_key = data.get("key") assert first_key != second_key -def test_put_bad_request(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_put_bad_request( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable +): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": 1234, } - resp = client.put(f"api/v1/explore/form_data/{KEY}", json=payload) + resp = test_client.put(f"api/v1/explore/form_data/{KEY}", json=payload) assert resp.status_code == 400 -def test_put_bad_request_non_string(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_put_bad_request_non_string( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable +): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": 1234, } - resp = client.put(f"api/v1/explore/form_data/{KEY}", json=payload) + resp = test_client.put(f"api/v1/explore/form_data/{KEY}", json=payload) assert resp.status_code == 400 -def test_put_bad_request_non_json_string(client, chart_id: int, datasource: SqlaTable): - login(client, "admin") +def test_put_bad_request_non_json_string( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable +): payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": "foo", } - resp = client.put(f"api/v1/explore/form_data/{KEY}", json=payload) + resp = test_client.put(f"api/v1/explore/form_data/{KEY}", json=payload) assert resp.status_code == 400 -def test_put_access_denied(client, chart_id: int, datasource: SqlaTable): - login(client, "gamma") +def test_put_access_denied(test_client, login_as, chart_id: int, datasource: SqlaTable): + login_as("gamma") payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": UPDATED_FORM_DATA, } - resp = client.put(f"api/v1/explore/form_data/{KEY}", json=payload) - assert resp.status_code == 404 + resp = test_client.put(f"api/v1/explore/form_data/{KEY}", json=payload) + assert resp.status_code == 403 -def test_put_not_owner(client, chart_id: int, datasource: SqlaTable): - login(client, "gamma") +def test_put_not_owner(test_client, login_as, chart_id: int, datasource: SqlaTable): + login_as("gamma") payload = { "datasource_id": datasource.id, "datasource_type": datasource.type, "chart_id": chart_id, "form_data": UPDATED_FORM_DATA, } - resp = client.put(f"api/v1/explore/form_data/{KEY}", json=payload) - assert resp.status_code == 404 + resp = test_client.put(f"api/v1/explore/form_data/{KEY}", json=payload) + assert resp.status_code == 403 -def test_get_key_not_found(client): - login(client, "admin") - resp = client.get(f"api/v1/explore/form_data/unknown-key") +def test_get_key_not_found(test_client, login_as_admin): + resp = test_client.get(f"api/v1/explore/form_data/unknown-key") assert resp.status_code == 404 -def test_get(client): - login(client, "admin") - resp = client.get(f"api/v1/explore/form_data/{KEY}") +def test_get(test_client, login_as_admin): + resp = test_client.get(f"api/v1/explore/form_data/{KEY}") assert resp.status_code == 200 data = json.loads(resp.data.decode("utf-8")) assert INITIAL_FORM_DATA == data.get("form_data") -def test_get_access_denied(client): - login(client, "gamma") - resp = client.get(f"api/v1/explore/form_data/{KEY}") - assert resp.status_code == 404 +def test_get_access_denied(test_client, login_as): + login_as("gamma") + resp = test_client.get(f"api/v1/explore/form_data/{KEY}") + assert resp.status_code == 403 @patch("superset.security.SupersetSecurityManager.can_access_datasource") -def test_get_dataset_access_denied(mock_can_access_datasource, client): +def test_get_dataset_access_denied( + mock_can_access_datasource, test_client, login_as_admin +): mock_can_access_datasource.side_effect = DatasetAccessDeniedError() - login(client, "admin") - resp = client.get(f"api/v1/explore/form_data/{KEY}") + resp = test_client.get(f"api/v1/explore/form_data/{KEY}") assert resp.status_code == 403 -def test_delete(client): - login(client, "admin") - resp = client.delete(f"api/v1/explore/form_data/{KEY}") +def test_delete(test_client, login_as_admin): + resp = test_client.delete(f"api/v1/explore/form_data/{KEY}") assert resp.status_code == 200 -def test_delete_access_denied(client): - login(client, "gamma") - resp = client.delete(f"api/v1/explore/form_data/{KEY}") - assert resp.status_code == 404 +def test_delete_access_denied(test_client, login_as): + login_as("gamma") + resp = test_client.delete(f"api/v1/explore/form_data/{KEY}") + assert resp.status_code == 403 -def test_delete_not_owner(client, chart_id: int, datasource: SqlaTable, admin_id: int): +def test_delete_not_owner( + test_client, login_as_admin, chart_id: int, datasource: SqlaTable, admin_id: int +): another_key = "another_key" another_owner = admin_id + 1 entry: TemporaryExploreState = { "owner": another_owner, "datasource_id": datasource.id, - "datasource_type": datasource.type, + "datasource_type": DatasourceType(datasource.type), "chart_id": chart_id, "form_data": INITIAL_FORM_DATA, } cache_manager.explore_form_data_cache.set(another_key, entry) - login(client, "admin") - resp = client.delete(f"api/v1/explore/form_data/{another_key}") + resp = test_client.delete(f"api/v1/explore/form_data/{another_key}") assert resp.status_code == 403 diff --git a/tests/integration_tests/explore/form_data/commands_tests.py b/tests/integration_tests/explore/form_data/commands_tests.py index 4db48cfa79737..18dd8415f6c60 100644 --- a/tests/integration_tests/explore/form_data/commands_tests.py +++ b/tests/integration_tests/explore/form_data/commands_tests.py @@ -110,7 +110,6 @@ def test_create_form_data_command(self, mock_g): datasource = f"{dataset.id}__{DatasourceType.TABLE}" args = CommandParameters( - actor=mock_g.user, datasource_id=dataset.id, datasource_type=DatasourceType.TABLE, chart_id=slice.id, @@ -136,7 +135,6 @@ def test_create_form_data_command_invalid_type(self, mock_g): datasource = f"{dataset.id}__{DatasourceType.TABLE}" create_args = CommandParameters( - actor=mock_g.user, datasource_id=dataset.id, datasource_type="InvalidType", chart_id=slice.id, @@ -163,7 +161,6 @@ def test_create_form_data_command_type_as_string(self, mock_g): datasource = f"{dataset.id}__{DatasourceType.TABLE}" create_args = CommandParameters( - actor=mock_g.user, datasource_id=dataset.id, datasource_type="table", chart_id=slice.id, @@ -189,7 +186,6 @@ def test_get_form_data_command(self, mock_g): datasource = f"{dataset.id}__{DatasourceType.TABLE}" create_args = CommandParameters( - actor=mock_g.user, datasource_id=dataset.id, datasource_type=DatasourceType.TABLE, chart_id=slice.id, @@ -198,7 +194,7 @@ def test_get_form_data_command(self, mock_g): ) key = CreateFormDataCommand(create_args).run() - key_args = CommandParameters(actor=mock_g.user, key=key) + key_args = CommandParameters(key=key) get_command = GetFormDataCommand(key_args) cache_data = json.loads(get_command.run()) @@ -221,7 +217,6 @@ def test_update_form_data_command(self, mock_g): datasource = f"{dataset.id}__{DatasourceType.TABLE}" create_args = CommandParameters( - actor=mock_g.user, datasource_id=dataset.id, datasource_type=DatasourceType.TABLE, chart_id=slice.id, @@ -232,7 +227,6 @@ def test_update_form_data_command(self, mock_g): query_datasource = f"{dataset.id}__{DatasourceType.TABLE}" update_args = CommandParameters( - actor=mock_g.user, datasource_id=query.id, datasource_type=DatasourceType.QUERY, chart_id=slice.id, @@ -249,7 +243,7 @@ def test_update_form_data_command(self, mock_g): # the updated key returned should be different from the old one assert new_key != key - key_args = CommandParameters(actor=mock_g.user, key=key) + key_args = CommandParameters(key=key) get_command = GetFormDataCommand(key_args) cache_data = json.loads(get_command.run()) @@ -271,7 +265,6 @@ def test_update_form_data_command_same_form_data(self, mock_g): datasource = f"{dataset.id}__{DatasourceType.TABLE}" create_args = CommandParameters( - actor=mock_g.user, datasource_id=dataset.id, datasource_type=DatasourceType.TABLE, chart_id=slice.id, @@ -281,7 +274,6 @@ def test_update_form_data_command_same_form_data(self, mock_g): key = CreateFormDataCommand(create_args).run() update_args = CommandParameters( - actor=mock_g.user, datasource_id=dataset.id, datasource_type=DatasourceType.TABLE, chart_id=slice.id, @@ -299,7 +291,7 @@ def test_update_form_data_command_same_form_data(self, mock_g): # the updated key returned should be the same as the old one assert new_key == key - key_args = CommandParameters(actor=mock_g.user, key=key) + key_args = CommandParameters(key=key) get_command = GetFormDataCommand(key_args) cache_data = json.loads(get_command.run()) @@ -321,7 +313,6 @@ def test_delete_form_data_command(self, mock_g): datasource = f"{dataset.id}__{DatasourceType.TABLE}" create_args = CommandParameters( - actor=mock_g.user, datasource_id=dataset.id, datasource_type=DatasourceType.TABLE, chart_id=slice.id, @@ -331,7 +322,6 @@ def test_delete_form_data_command(self, mock_g): key = CreateFormDataCommand(create_args).run() delete_args = CommandParameters( - actor=mock_g.user, key=key, ) @@ -349,7 +339,6 @@ def test_delete_form_data_command_key_expired(self, mock_g): } delete_args = CommandParameters( - actor=mock_g.user, key="some_expired_key", ) diff --git a/tests/integration_tests/explore/permalink/api_tests.py b/tests/integration_tests/explore/permalink/api_tests.py index b5228ab301b24..22a36f41e1be5 100644 --- a/tests/integration_tests/explore/permalink/api_tests.py +++ b/tests/integration_tests/explore/permalink/api_tests.py @@ -28,8 +28,6 @@ from superset.key_value.utils import decode_permalink_id, encode_permalink_key from superset.models.slice import Slice from superset.utils.core import DatasourceType -from tests.integration_tests.base_tests import login -from tests.integration_tests.fixtures.client import client from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices, load_world_bank_data, @@ -38,11 +36,10 @@ @pytest.fixture -def chart(load_world_bank_dashboard_with_slices) -> Slice: - with app.app_context() as ctx: - session: Session = ctx.app.appbuilder.get_session - chart = session.query(Slice).filter_by(slice_name="World's Population").one() - return chart +def chart(app_context, load_world_bank_dashboard_with_slices) -> Slice: + session: Session = app_context.app.appbuilder.get_session + chart = session.query(Slice).filter_by(slice_name="World's Population").one() + return chart @pytest.fixture @@ -70,9 +67,10 @@ def permalink_salt() -> Iterator[str]: db.session.commit() -def test_post(client, form_data: Dict[str, Any], permalink_salt: str): - login(client, "admin") - resp = client.post(f"api/v1/explore/permalink", json={"formData": form_data}) +def test_post( + test_client, login_as_admin, form_data: Dict[str, Any], permalink_salt: str +): + resp = test_client.post(f"api/v1/explore/permalink", json={"formData": form_data}) assert resp.status_code == 201 data = json.loads(resp.data.decode("utf-8")) key = data["key"] @@ -83,13 +81,15 @@ def test_post(client, form_data: Dict[str, Any], permalink_salt: str): db.session.commit() -def test_post_access_denied(client, form_data): - login(client, "gamma") - resp = client.post(f"api/v1/explore/permalink", json={"formData": form_data}) - assert resp.status_code == 404 +def test_post_access_denied(test_client, login_as, form_data): + login_as("gamma") + resp = test_client.post(f"api/v1/explore/permalink", json={"formData": form_data}) + assert resp.status_code == 403 -def test_get_missing_chart(client, chart, permalink_salt: str) -> None: +def test_get_missing_chart( + test_client, login_as_admin, chart, permalink_salt: str +) -> None: from superset.key_value.models import KeyValueEntry chart_id = 1234 @@ -110,25 +110,24 @@ def test_get_missing_chart(client, chart, permalink_salt: str) -> None: db.session.add(entry) db.session.commit() key = encode_permalink_key(entry.id, permalink_salt) - login(client, "admin") - resp = client.get(f"api/v1/explore/permalink/{key}") + resp = test_client.get(f"api/v1/explore/permalink/{key}") assert resp.status_code == 404 db.session.delete(entry) db.session.commit() -def test_post_invalid_schema(client) -> None: - login(client, "admin") - resp = client.post(f"api/v1/explore/permalink", json={"abc": 123}) +def test_post_invalid_schema(test_client, login_as_admin) -> None: + resp = test_client.post(f"api/v1/explore/permalink", json={"abc": 123}) assert resp.status_code == 400 -def test_get(client, form_data: Dict[str, Any], permalink_salt: str) -> None: - login(client, "admin") - resp = client.post(f"api/v1/explore/permalink", json={"formData": form_data}) +def test_get( + test_client, login_as_admin, form_data: Dict[str, Any], permalink_salt: str +) -> None: + resp = test_client.post(f"api/v1/explore/permalink", json={"formData": form_data}) data = json.loads(resp.data.decode("utf-8")) key = data["key"] - resp = client.get(f"api/v1/explore/permalink/{key}") + resp = test_client.get(f"api/v1/explore/permalink/{key}") assert resp.status_code == 200 result = json.loads(resp.data.decode("utf-8")) assert result["state"]["formData"] == form_data diff --git a/tests/integration_tests/explore/permalink/commands_tests.py b/tests/integration_tests/explore/permalink/commands_tests.py index 2bb44bb068edd..63ed02cd7bd91 100644 --- a/tests/integration_tests/explore/permalink/commands_tests.py +++ b/tests/integration_tests/explore/permalink/commands_tests.py @@ -109,7 +109,7 @@ def test_create_permalink_command(self, mock_g): datasource = f"{dataset.id}__{DatasourceType.TABLE}" command = CreateExplorePermalinkCommand( - mock_g.user, {"formData": {"datasource": datasource, "slice_id": slice.id}} + {"formData": {"datasource": datasource, "slice_id": slice.id}} ) assert isinstance(command.run(), str) @@ -130,10 +130,10 @@ def test_get_permalink_command(self, mock_g): datasource = f"{dataset.id}__{DatasourceType.TABLE}" key = CreateExplorePermalinkCommand( - mock_g.user, {"formData": {"datasource": datasource, "slice_id": slice.id}} + {"formData": {"datasource": datasource, "slice_id": slice.id}} ).run() - get_command = GetExplorePermalinkCommand(mock_g.user, key) + get_command = GetExplorePermalinkCommand(key) cache_data = get_command.run() assert cache_data.get("datasource") == datasource @@ -166,7 +166,7 @@ def test_get_permalink_command_with_old_dataset_key( "formData": {"datasource": datasource_string, "slice_id": slice.id} }, } - get_command = GetExplorePermalinkCommand(mock_g.user, "thisisallmocked") + get_command = GetExplorePermalinkCommand("thisisallmocked") cache_data = get_command.run() assert cache_data.get("datasource") == datasource_string diff --git a/tests/integration_tests/fixtures/birth_names_dashboard.py b/tests/integration_tests/fixtures/birth_names_dashboard.py index ef71803aa5db7..be680a720dd84 100644 --- a/tests/integration_tests/fixtures/birth_names_dashboard.py +++ b/tests/integration_tests/fixtures/birth_names_dashboard.py @@ -18,7 +18,7 @@ import pytest -from superset import ConnectorRegistry, db +from superset import db from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database from superset.models.dashboard import Dashboard @@ -68,7 +68,7 @@ def _create_dashboards(): from superset.examples.birth_names import create_dashboard, create_slices - slices, _ = create_slices(table, admin_owner=False) + slices, _ = create_slices(table) dash = create_dashboard(slices) slices_ids_to_delete = [slice.id for slice in slices] dash_id_to_delete = dash.id @@ -93,27 +93,16 @@ def _create_table( return table -def _cleanup(dash_id: int, slices_ids: List[int]) -> None: +def _cleanup(dash_id: int, slice_ids: List[int]) -> None: schema = get_example_default_schema() - - table_id = ( - db.session.query(SqlaTable) - .filter_by(table_name="birth_names", schema=schema) - .one() - .id - ) - datasource = ConnectorRegistry.get_datasource("table", table_id, db.session) - columns = [column for column in datasource.columns] - metrics = [metric for metric in datasource.metrics] - - for column in columns: - db.session.delete(column) - for metric in metrics: - db.session.delete(metric) - - dash = db.session.query(Dashboard).filter_by(id=dash_id).first() - - db.session.delete(dash) - for slice_id in slices_ids: - db.session.query(Slice).filter_by(id=slice_id).delete() + for datasource in db.session.query(SqlaTable).filter_by( + table_name="birth_names", schema=schema + ): + for col in datasource.columns + datasource.metrics: + db.session.delete(col) + + for dash in db.session.query(Dashboard).filter_by(id=dash_id): + db.session.delete(dash) + for slc in db.session.query(Slice).filter(Slice.id.in_(slice_ids)): + db.session.delete(slc) db.session.commit() diff --git a/tests/integration_tests/fixtures/datasource.py b/tests/integration_tests/fixtures/datasource.py index 574f43d52bbcb..f394d68a0e76b 100644 --- a/tests/integration_tests/fixtures/datasource.py +++ b/tests/integration_tests/fixtures/datasource.py @@ -19,7 +19,7 @@ import pytest from sqlalchemy import Column, create_engine, Date, Integer, MetaData, String, Table -from sqlalchemy.ext.declarative.api import declarative_base +from sqlalchemy.ext.declarative import declarative_base from superset.columns.models import Column as Sl_Column from superset.connectors.sqla.models import SqlaTable, TableColumn diff --git a/tests/integration_tests/fixtures/deck_geojson_form_data.json b/tests/integration_tests/fixtures/deck_geojson_form_data.json index 422197a2855c7..e8258c7d443a1 100644 --- a/tests/integration_tests/fixtures/deck_geojson_form_data.json +++ b/tests/integration_tests/fixtures/deck_geojson_form_data.json @@ -43,5 +43,5 @@ "granularity_sqla": null, "autozoom": true, "url_params": {}, - "size": 100 + "size": "100" } diff --git a/tests/integration_tests/fixtures/deck_path_form_data.json b/tests/integration_tests/fixtures/deck_path_form_data.json index 39cc2007f85b4..ac2e404d83fb4 100644 --- a/tests/integration_tests/fixtures/deck_path_form_data.json +++ b/tests/integration_tests/fixtures/deck_path_form_data.json @@ -45,5 +45,5 @@ "granularity_sqla": null, "autozoom": true, "url_params": {}, - "size": 100 + "size": "100" } diff --git a/tests/integration_tests/fixtures/energy_dashboard.py b/tests/integration_tests/fixtures/energy_dashboard.py index 73f2f1e239ae0..202f494aa2d15 100644 --- a/tests/integration_tests/fixtures/energy_dashboard.py +++ b/tests/integration_tests/fixtures/energy_dashboard.py @@ -39,17 +39,18 @@ def load_energy_table_data(): with app.app_context(): database = get_example_database() - df = _get_dataframe() - df.to_sql( - ENERGY_USAGE_TBL_NAME, - database.get_sqla_engine(), - if_exists="replace", - chunksize=500, - index=False, - dtype={"source": String(255), "target": String(255), "value": Float()}, - method="multi", - schema=get_example_default_schema(), - ) + with database.get_sqla_engine_with_context() as engine: + df = _get_dataframe() + df.to_sql( + ENERGY_USAGE_TBL_NAME, + engine, + if_exists="replace", + chunksize=500, + index=False, + dtype={"source": String(255), "target": String(255), "value": Float()}, + method="multi", + schema=get_example_default_schema(), + ) yield with app.app_context(): with get_example_database().get_sqla_engine_with_context() as engine: @@ -82,7 +83,6 @@ def _create_energy_table() -> List[Slice]: table.metrics.append( SqlMetric(metric_name="sum__value", expression=f"SUM({col})") ) - db.session.merge(table) db.session.commit() table.fetch_metadata() diff --git a/tests/integration_tests/fixtures/importexport.py b/tests/integration_tests/fixtures/importexport.py index 18bec4f17995b..b624f3e63ced6 100644 --- a/tests/integration_tests/fixtures/importexport.py +++ b/tests/integration_tests/fixtures/importexport.py @@ -350,6 +350,7 @@ "allow_csv_upload": True, "allow_ctas": True, "allow_cvas": True, + "allow_dml": True, "allow_run_async": False, "cache_timeout": None, "database_name": "imported_database", diff --git a/tests/integration_tests/fixtures/tabbed_dashboard.py b/tests/integration_tests/fixtures/tabbed_dashboard.py index 4f9c4465c2d0b..15a871c7aea9e 100644 --- a/tests/integration_tests/fixtures/tabbed_dashboard.py +++ b/tests/integration_tests/fixtures/tabbed_dashboard.py @@ -20,16 +20,16 @@ from superset import db from superset.models.dashboard import Dashboard -from tests.integration_tests.dashboard_utils import create_dashboard -from tests.integration_tests.test_app import app +from superset.utils.core import shortid +from tests.integration_tests.dashboards.superset_factory_util import create_dashboard -@pytest.fixture(scope="session") -def tabbed_dashboard(): +@pytest.fixture +def tabbed_dashboard(app_context): position_json = { "DASHBOARD_VERSION_KEY": "v2", "GRID_ID": { - "children": ["TABS-IpViLohnyP"], + "children": ["TABS-L1A", "TABS-L1B"], "id": "GRID_ID", "parents": ["ROOT_ID"], "type": "GRID", @@ -40,38 +40,102 @@ def tabbed_dashboard(): "type": "HEADER", }, "ROOT_ID": {"children": ["GRID_ID"], "id": "ROOT_ID", "type": "ROOT"}, - "TAB-j53G4gtKGF": { + "TAB-L1AA": { "children": [], - "id": "TAB-j53G4gtKGF", + "id": "TAB-L1AA", "meta": { "defaultText": "Tab title", "placeholder": "Tab title", - "text": "Tab 1", + "text": "Tab L1AA", }, - "parents": ["ROOT_ID", "GRID_ID", "TABS-IpViLohnyP"], + "parents": ["ROOT_ID", "GRID_ID", "TABS-L1A"], "type": "TAB", }, - "TAB-nerWR09Ju": { + "TAB-L1AB": { "children": [], - "id": "TAB-nerWR09Ju", + "id": "TAB-L1AB", + "meta": { + "defaultText": "Tab title", + "placeholder": "Tab title", + "text": "Tab L1AB", + }, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L1A"], + "type": "TAB", + }, + "TABS-L1A": { + "children": ["TAB-L1AA", "TAB-L1AB"], + "id": "TABS-L1A", + "meta": {}, + "parents": ["ROOT_ID", "GRID_ID"], + "type": "TABS", + }, + "TAB-L1BA": { + "children": [], + "id": "TAB-L1BA", + "meta": { + "defaultText": "Tab title", + "placeholder": "Tab title", + "text": "Tab L1B", + }, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L1B"], + "type": "TAB", + }, + "TAB-L1BB": { + "children": ["TABS-L2A"], + "id": "TAB-L1BB", "meta": { "defaultText": "Tab title", "placeholder": "Tab title", "text": "Tab 2", }, - "parents": ["ROOT_ID", "GRID_ID", "TABS-IpViLohnyP"], + "parents": ["ROOT_ID", "GRID_ID", "TABS-L1B"], "type": "TAB", }, - "TABS-IpViLohnyP": { - "children": ["TAB-j53G4gtKGF", "TAB-nerWR09Ju"], - "id": "TABS-IpViLohnyP", + "TABS-L1B": { + "children": ["TAB-L1BA", "TAB-L1BB"], + "id": "TABS-L1B", "meta": {}, "parents": ["ROOT_ID", "GRID_ID"], "type": "TABS", }, + "TAB-L2AA": { + "children": [], + "id": "TAB-L2AA", + "meta": { + "defaultText": "Tab title", + "placeholder": "Tab title", + "text": "Tab L2AA", + }, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L2A"], + "type": "TAB", + }, + "TAB-L2AB": { + "children": [], + "id": "TAB-L2AB", + "meta": { + "defaultText": "Tab title", + "placeholder": "Tab title", + "text": "Tab L2AB", + }, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L2A"], + "type": "TAB", + }, + "TABS-L2A": { + "children": ["TAB-L2AA", "TAB-L2AB"], + "id": "TABS-L2A", + "meta": {}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L1BB"], + "type": "TABS", + }, } - with app.app_context(): - dash = create_dashboard( - "tabbed-dash-test", "Tabbed Dash Test", json.dumps(position_json), [] - ) + dash = create_dashboard( + slug=f"tabbed-dash-{shortid()}", + dashboard_title="Test tabbed dash", + position_json=json.dumps(position_json), + slices=[], + ) + db.session.add(dash) + db.session.commit() yield dash + db.session.query(Dashboard).filter_by(id=dash.id).delete() + db.session.commit() diff --git a/tests/integration_tests/db_engine_specs/dremio_tests.py b/tests/integration_tests/fixtures/tags.py similarity index 57% rename from tests/integration_tests/db_engine_specs/dremio_tests.py rename to tests/integration_tests/fixtures/tags.py index 5d678c947bb2e..57fd4ec7196e2 100644 --- a/tests/integration_tests/db_engine_specs/dremio_tests.py +++ b/tests/integration_tests/fixtures/tags.py @@ -14,20 +14,20 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from superset.db_engine_specs.dremio import DremioEngineSpec -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec +import pytest -class TestDremioDbEngineSpec(TestDbEngineSpec): - def test_convert_dttm(self): - dttm = self.get_dttm() +from superset.tags.core import clear_sqla_event_listeners, register_sqla_event_listeners +from tests.integration_tests.test_app import app - self.assertEqual( - DremioEngineSpec.convert_dttm("DATE", dttm), - "TO_DATE('2019-01-02', 'YYYY-MM-DD')", - ) - self.assertEqual( - DremioEngineSpec.convert_dttm("TIMESTAMP", dttm), - "TO_TIMESTAMP('2019-01-02 03:04:05.678', 'YYYY-MM-DD HH24:MI:SS.FFF')", - ) +@pytest.fixture +def with_tagging_system_feature(): + with app.app_context(): + is_enabled = app.config["DEFAULT_FEATURE_FLAGS"]["TAGGING_SYSTEM"] + if not is_enabled: + app.config["DEFAULT_FEATURE_FLAGS"]["TAGGING_SYSTEM"] = True + register_sqla_event_listeners() + yield + app.config["DEFAULT_FEATURE_FLAGS"]["TAGGING_SYSTEM"] = False + clear_sqla_event_listeners() diff --git a/tests/integration_tests/fixtures/unicode_dashboard.py b/tests/integration_tests/fixtures/unicode_dashboard.py index c7b828176f2c8..78178bcde7551 100644 --- a/tests/integration_tests/fixtures/unicode_dashboard.py +++ b/tests/integration_tests/fixtures/unicode_dashboard.py @@ -37,21 +37,22 @@ @pytest.fixture(scope="session") def load_unicode_data(): with app.app_context(): - _get_dataframe().to_sql( - UNICODE_TBL_NAME, - get_example_database().get_sqla_engine(), - if_exists="replace", - chunksize=500, - dtype={"phrase": String(500)}, - index=False, - method="multi", - schema=get_example_default_schema(), - ) + with get_example_database().get_sqla_engine_with_context() as engine: + _get_dataframe().to_sql( + UNICODE_TBL_NAME, + engine, + if_exists="replace", + chunksize=500, + dtype={"phrase": String(500)}, + index=False, + method="multi", + schema=get_example_default_schema(), + ) yield with app.app_context(): - engine = get_example_database().get_sqla_engine() - engine.execute("DROP TABLE IF EXISTS unicode_test") + with get_example_database().get_sqla_engine_with_context() as engine: + engine.execute("DROP TABLE IF EXISTS unicode_test") @pytest.fixture() diff --git a/tests/integration_tests/fixtures/world_bank_dashboard.py b/tests/integration_tests/fixtures/world_bank_dashboard.py index 2c6fb2c3e26e4..561bbe10b2709 100644 --- a/tests/integration_tests/fixtures/world_bank_dashboard.py +++ b/tests/integration_tests/fixtures/world_bank_dashboard.py @@ -50,21 +50,22 @@ def load_world_bank_data(): "country_name": String(255), "region": String(255), } - _get_dataframe(database).to_sql( - WB_HEALTH_POPULATION, - get_example_database().get_sqla_engine(), - if_exists="replace", - chunksize=500, - dtype=dtype, - index=False, - method="multi", - schema=get_example_default_schema(), - ) + with database.get_sqla_engine_with_context() as engine: + _get_dataframe(database).to_sql( + WB_HEALTH_POPULATION, + engine, + if_exists="replace", + chunksize=500, + dtype=dtype, + index=False, + method="multi", + schema=get_example_default_schema(), + ) yield with app.app_context(): - engine = get_example_database().get_sqla_engine() - engine.execute("DROP TABLE IF EXISTS wb_health_population") + with get_example_database().get_sqla_engine_with_context() as engine: + engine.execute("DROP TABLE IF EXISTS wb_health_population") @pytest.fixture() diff --git a/tests/integration_tests/import_export_tests.py b/tests/integration_tests/import_export_tests.py index 81acda80185ca..5bbc985a36672 100644 --- a/tests/integration_tests/import_export_tests.py +++ b/tests/integration_tests/import_export_tests.py @@ -50,33 +50,31 @@ from .base_tests import SupersetTestCase +def delete_imports(): + with app.app_context(): + # Imported data clean up + session = db.session + for slc in session.query(Slice): + if "remote_id" in slc.params_dict: + session.delete(slc) + for dash in session.query(Dashboard): + if "remote_id" in dash.params_dict: + session.delete(dash) + for table in session.query(SqlaTable): + if "remote_id" in table.params_dict: + session.delete(table) + session.commit() + + +@pytest.fixture(autouse=True, scope="module") +def clean_imports(): + yield + delete_imports() + + class TestImportExport(SupersetTestCase): """Testing export import functionality for dashboards""" - @classmethod - def delete_imports(cls): - with app.app_context(): - # Imported data clean up - session = db.session - for slc in session.query(Slice): - if "remote_id" in slc.params_dict: - session.delete(slc) - for dash in session.query(Dashboard): - if "remote_id" in dash.params_dict: - session.delete(dash) - for table in session.query(SqlaTable): - if "remote_id" in table.params_dict: - session.delete(table) - session.commit() - - @classmethod - def setUpClass(cls): - cls.delete_imports() - - @classmethod - def tearDownClass(cls): - cls.delete_imports() - def create_slice( self, name, diff --git a/tests/integration_tests/insert_chart_mixin.py b/tests/integration_tests/insert_chart_mixin.py index 8fcb33067e351..da05d0c49d043 100644 --- a/tests/integration_tests/insert_chart_mixin.py +++ b/tests/integration_tests/insert_chart_mixin.py @@ -16,7 +16,8 @@ # under the License. from typing import List, Optional -from superset import ConnectorRegistry, db, security_manager +from superset import db, security_manager +from superset.connectors.sqla.models import SqlaTable from superset.models.slice import Slice @@ -43,8 +44,8 @@ def insert_chart( for owner in owners: user = db.session.query(security_manager.user_model).get(owner) obj_owners.append(user) - datasource = ConnectorRegistry.get_datasource( - datasource_type, datasource_id, db.session + datasource = ( + db.session.query(SqlaTable).filter_by(id=datasource_id).one_or_none() ) slice = Slice( cache_timeout=cache_timeout, diff --git a/tests/integration_tests/key_value/commands/create_test.py b/tests/integration_tests/key_value/commands/create_test.py index 2718aa822c3e4..0e789026baff4 100644 --- a/tests/integration_tests/key_value/commands/create_test.py +++ b/tests/integration_tests/key_value/commands/create_test.py @@ -23,6 +23,7 @@ from flask_appbuilder.security.sqla.models import User from superset.extensions import db +from superset.utils.core import override_user from tests.integration_tests.key_value.commands.fixtures import ( admin, ID_KEY, @@ -36,19 +37,23 @@ def test_create_id_entry(app_context: AppContext, admin: User) -> None: from superset.key_value.commands.create import CreateKeyValueCommand from superset.key_value.models import KeyValueEntry - key = CreateKeyValueCommand(actor=admin, resource=RESOURCE, value=VALUE).run() - entry = db.session.query(KeyValueEntry).filter_by(id=key.id).autoflush(False).one() - assert pickle.loads(entry.value) == VALUE - assert entry.created_by_fk == admin.id - db.session.delete(entry) - db.session.commit() + with override_user(admin): + key = CreateKeyValueCommand(resource=RESOURCE, value=VALUE).run() + entry = ( + db.session.query(KeyValueEntry).filter_by(id=key.id).autoflush(False).one() + ) + assert pickle.loads(entry.value) == VALUE + assert entry.created_by_fk == admin.id + db.session.delete(entry) + db.session.commit() def test_create_uuid_entry(app_context: AppContext, admin: User) -> None: from superset.key_value.commands.create import CreateKeyValueCommand from superset.key_value.models import KeyValueEntry - key = CreateKeyValueCommand(actor=admin, resource=RESOURCE, value=VALUE).run() + with override_user(admin): + key = CreateKeyValueCommand(resource=RESOURCE, value=VALUE).run() entry = ( db.session.query(KeyValueEntry).filter_by(uuid=key.uuid).autoflush(False).one() ) diff --git a/tests/integration_tests/key_value/commands/update_test.py b/tests/integration_tests/key_value/commands/update_test.py index 3b24ecdf0a300..8eb03b4eda9eb 100644 --- a/tests/integration_tests/key_value/commands/update_test.py +++ b/tests/integration_tests/key_value/commands/update_test.py @@ -24,6 +24,7 @@ from flask_appbuilder.security.sqla.models import User from superset.extensions import db +from superset.utils.core import override_user from tests.integration_tests.key_value.commands.fixtures import ( admin, ID_KEY, @@ -47,12 +48,12 @@ def test_update_id_entry( from superset.key_value.commands.update import UpdateKeyValueCommand from superset.key_value.models import KeyValueEntry - key = UpdateKeyValueCommand( - actor=admin, - resource=RESOURCE, - key=ID_KEY, - value=NEW_VALUE, - ).run() + with override_user(admin): + key = UpdateKeyValueCommand( + resource=RESOURCE, + key=ID_KEY, + value=NEW_VALUE, + ).run() assert key is not None assert key.id == ID_KEY entry = db.session.query(KeyValueEntry).filter_by(id=ID_KEY).autoflush(False).one() @@ -68,12 +69,12 @@ def test_update_uuid_entry( from superset.key_value.commands.update import UpdateKeyValueCommand from superset.key_value.models import KeyValueEntry - key = UpdateKeyValueCommand( - actor=admin, - resource=RESOURCE, - key=UUID_KEY, - value=NEW_VALUE, - ).run() + with override_user(admin): + key = UpdateKeyValueCommand( + resource=RESOURCE, + key=UUID_KEY, + value=NEW_VALUE, + ).run() assert key is not None assert key.uuid == UUID_KEY entry = ( @@ -86,10 +87,10 @@ def test_update_uuid_entry( def test_update_missing_entry(app_context: AppContext, admin: User) -> None: from superset.key_value.commands.update import UpdateKeyValueCommand - key = UpdateKeyValueCommand( - actor=admin, - resource=RESOURCE, - key=456, - value=NEW_VALUE, - ).run() + with override_user(admin): + key = UpdateKeyValueCommand( + resource=RESOURCE, + key=456, + value=NEW_VALUE, + ).run() assert key is None diff --git a/tests/integration_tests/key_value/commands/upsert_test.py b/tests/integration_tests/key_value/commands/upsert_test.py index 1970a1fc2c293..e5cd27e3a6cc8 100644 --- a/tests/integration_tests/key_value/commands/upsert_test.py +++ b/tests/integration_tests/key_value/commands/upsert_test.py @@ -24,6 +24,7 @@ from flask_appbuilder.security.sqla.models import User from superset.extensions import db +from superset.utils.core import override_user from tests.integration_tests.key_value.commands.fixtures import ( admin, ID_KEY, @@ -47,12 +48,12 @@ def test_upsert_id_entry( from superset.key_value.commands.upsert import UpsertKeyValueCommand from superset.key_value.models import KeyValueEntry - key = UpsertKeyValueCommand( - actor=admin, - resource=RESOURCE, - key=ID_KEY, - value=NEW_VALUE, - ).run() + with override_user(admin): + key = UpsertKeyValueCommand( + resource=RESOURCE, + key=ID_KEY, + value=NEW_VALUE, + ).run() assert key is not None assert key.id == ID_KEY entry = ( @@ -70,12 +71,12 @@ def test_upsert_uuid_entry( from superset.key_value.commands.upsert import UpsertKeyValueCommand from superset.key_value.models import KeyValueEntry - key = UpsertKeyValueCommand( - actor=admin, - resource=RESOURCE, - key=UUID_KEY, - value=NEW_VALUE, - ).run() + with override_user(admin): + key = UpsertKeyValueCommand( + resource=RESOURCE, + key=UUID_KEY, + value=NEW_VALUE, + ).run() assert key is not None assert key.uuid == UUID_KEY entry = ( @@ -89,12 +90,12 @@ def test_upsert_missing_entry(app_context: AppContext, admin: User) -> None: from superset.key_value.commands.upsert import UpsertKeyValueCommand from superset.key_value.models import KeyValueEntry - key = UpsertKeyValueCommand( - actor=admin, - resource=RESOURCE, - key=456, - value=NEW_VALUE, - ).run() + with override_user(admin): + key = UpsertKeyValueCommand( + resource=RESOURCE, + key=456, + value=NEW_VALUE, + ).run() assert key is not None assert key.id == 456 db.session.query(KeyValueEntry).filter_by(id=456).delete() diff --git a/tests/integration_tests/log_api_tests.py b/tests/integration_tests/log_api_tests.py index 089ac07921c5a..83a7f5fd84b31 100644 --- a/tests/integration_tests/log_api_tests.py +++ b/tests/integration_tests/log_api_tests.py @@ -16,16 +16,20 @@ # under the License. # isort:skip_file """Unit tests for Superset""" +from datetime import datetime, timedelta import json from typing import Optional +from unittest.mock import ANY -import prison from flask_appbuilder.security.sqla.models import User +import prison from unittest.mock import patch from superset import db from superset.models.core import Log from superset.views.log.api import LogRestApi +from tests.integration_tests.dashboard_utils import create_dashboard +from tests.integration_tests.test_app import app from .base_tests import SupersetTestCase @@ -106,6 +110,8 @@ def test_get_list_not_allowed(self): self.login(username="alpha") rv = self.client.get(uri) self.assertEqual(rv.status_code, 403) + db.session.delete(log) + db.session.commit() def test_get_item(self): """ @@ -152,3 +158,178 @@ def test_update_log(self): self.assertEqual(rv.status_code, 405) db.session.delete(log) db.session.commit() + + def test_get_recent_activity_no_broad_access(self): + """ + Log API: Test recent activity not visible for other users without + ENABLE_BROAD_ACTIVITY_ACCESS flag on + """ + admin_user = self.get_user("admin") + self.login(username="admin") + app.config["ENABLE_BROAD_ACTIVITY_ACCESS"] = False + + uri = f"api/v1/log/recent_activity/{admin_user.id + 1}/" + rv = self.client.get(uri) + self.assertEqual(rv.status_code, 403) + app.config["ENABLE_BROAD_ACTIVITY_ACCESS"] = True + + def test_get_recent_activity(self): + """ + Log API: Test recent activity endpoint + """ + admin_user = self.get_user("admin") + self.login(username="admin") + dash = create_dashboard("dash_slug", "dash_title", "{}", []) + log1 = self.insert_log("dashboard", admin_user, dashboard_id=dash.id) + log2 = self.insert_log("dashboard", admin_user, dashboard_id=dash.id) + + uri = f"api/v1/log/recent_activity/{admin_user.id}/" + rv = self.client.get(uri) + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + + db.session.delete(log1) + db.session.delete(log2) + db.session.delete(dash) + db.session.commit() + + self.assertEqual( + response, + { + "result": [ + { + "action": "dashboard", + "item_type": "dashboard", + "item_url": "/superset/dashboard/dash_slug/", + "item_title": "dash_title", + "time": ANY, + "time_delta_humanized": ANY, + } + ] + }, + ) + + def test_get_recent_activity_actions_filter(self): + """ + Log API: Test recent activity actions argument + """ + admin_user = self.get_user("admin") + self.login(username="admin") + dash = create_dashboard("dash_slug", "dash_title", "{}", []) + log = self.insert_log("dashboard", admin_user, dashboard_id=dash.id) + log2 = self.insert_log("explore", admin_user, dashboard_id=dash.id) + + arguments = {"actions": ["dashboard"]} + uri = f"api/v1/log/recent_activity/{admin_user.id}/?q={prison.dumps(arguments)}" + rv = self.client.get(uri) + + db.session.delete(log) + db.session.delete(log2) + db.session.delete(dash) + db.session.commit() + + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(len(response["result"]), 1) + + def test_get_recent_activity_distinct_false(self): + """ + Log API: Test recent activity when distinct is false + """ + db.session.query(Log).delete(synchronize_session=False) + db.session.commit() + admin_user = self.get_user("admin") + self.login(username="admin") + dash = create_dashboard("dash_slug", "dash_title", "{}", []) + log = self.insert_log("dashboard", admin_user, dashboard_id=dash.id) + log2 = self.insert_log("dashboard", admin_user, dashboard_id=dash.id) + + arguments = {"distinct": False} + uri = f"api/v1/log/recent_activity/{admin_user.id}/?q={prison.dumps(arguments)}" + rv = self.client.get(uri) + + db.session.delete(log) + db.session.delete(log2) + db.session.delete(dash) + db.session.commit() + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(len(response["result"]), 2) + + def test_get_recent_activity_pagination(self): + """ + Log API: Test recent activity pagination arguments + """ + admin_user = self.get_user("admin") + self.login(username="admin") + dash = create_dashboard("dash_slug", "dash_title", "{}", []) + dash2 = create_dashboard("dash2_slug", "dash2_title", "{}", []) + dash3 = create_dashboard("dash3_slug", "dash3_title", "{}", []) + log = self.insert_log("dashboard", admin_user, dashboard_id=dash.id) + log2 = self.insert_log("dashboard", admin_user, dashboard_id=dash2.id) + log3 = self.insert_log("dashboard", admin_user, dashboard_id=dash3.id) + + now = datetime.now() + log3.dttm = now + log2.dttm = now - timedelta(days=1) + log.dttm = now - timedelta(days=2) + + arguments = {"page": 0, "page_size": 2} + uri = f"api/v1/log/recent_activity/{admin_user.id}/?q={prison.dumps(arguments)}" + rv = self.client.get(uri) + + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual( + response, + { + "result": [ + { + "action": "dashboard", + "item_type": "dashboard", + "item_url": "/superset/dashboard/dash3_slug/", + "item_title": "dash3_title", + "time": ANY, + "time_delta_humanized": ANY, + }, + { + "action": "dashboard", + "item_type": "dashboard", + "item_url": "/superset/dashboard/dash2_slug/", + "item_title": "dash2_title", + "time": ANY, + "time_delta_humanized": ANY, + }, + ] + }, + ) + + arguments = {"page": 1, "page_size": 2} + uri = f"api/v1/log/recent_activity/{admin_user.id}/?q={prison.dumps(arguments)}" + rv = self.client.get(uri) + + db.session.delete(log) + db.session.delete(log2) + db.session.delete(log3) + db.session.delete(dash) + db.session.delete(dash2) + db.session.delete(dash3) + db.session.commit() + + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual( + response, + { + "result": [ + { + "action": "dashboard", + "item_type": "dashboard", + "item_url": "/superset/dashboard/dash_slug/", + "item_title": "dash_title", + "time": ANY, + "time_delta_humanized": ANY, + } + ] + }, + ) diff --git a/tests/integration_tests/migrations/06e1e70058c7_migrate_legacy_area__tests.py b/tests/integration_tests/migrations/06e1e70058c7_migrate_legacy_area__tests.py new file mode 100644 index 0000000000000..f02d069b2bafb --- /dev/null +++ b/tests/integration_tests/migrations/06e1e70058c7_migrate_legacy_area__tests.py @@ -0,0 +1,99 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import json + +from superset.app import SupersetApp +from superset.migrations.shared.migrate_viz import MigrateAreaChart + +area_form_data = """{ + "adhoc_filters": [], + "annotation_layers": [], + "bottom_margin": "auto", + "color_scheme": "lyftColors", + "comparison_type": "values", + "contribution": true, + "datasource": "2__table", + "extra_form_data": {}, + "granularity_sqla": "ds", + "groupby": [ + "gender" + ], + "line_interpolation": "linear", + "metrics": [ + "sum__num" + ], + "order_desc": true, + "rich_tooltip": true, + "rolling_type": "None", + "row_limit": 10000, + "show_brush": "auto", + "show_controls": true, + "show_legend": true, + "slice_id": 165, + "stacked_style": "stack", + "time_grain_sqla": "P1D", + "time_range": "No filter", + "viz_type": "area", + "x_axis_format": "smart_date", + "x_axis_label": "x asix label", + "x_axis_showminmax": false, + "x_ticks_layout": "auto", + "y_axis_bounds": [ + null, + null + ], + "y_axis_format": "SMART_NUMBER" +} +""" + + +def test_area_migrate(app_context: SupersetApp) -> None: + from superset.models.slice import Slice + + slc = Slice( + viz_type=MigrateAreaChart.source_viz_type, + datasource_type="table", + params=area_form_data, + query_context=f'{{"form_data": {area_form_data}}}', + ) + + slc = MigrateAreaChart.upgrade_slice(slc) + assert slc.viz_type == MigrateAreaChart.target_viz_type + # verify form_data + new_form_data = json.loads(slc.params) + assert new_form_data["contributionMode"] == "row" + assert "contribution" not in new_form_data + assert new_form_data["show_extra_controls"] is True + assert new_form_data["stack"] == "Stack" + assert new_form_data["x_axis_title"] == "x asix label" + assert new_form_data["x_axis_title_margin"] == 30 + assert json.dumps(new_form_data["form_data_bak"], sort_keys=True) == json.dumps( + json.loads(area_form_data), sort_keys=True + ) + + # verify query_context + new_query_context = json.loads(slc.query_context) + assert ( + new_query_context["form_data"]["viz_type"] == MigrateAreaChart.target_viz_type + ) + + # downgrade + slc = MigrateAreaChart.downgrade_slice(slc) + assert slc.viz_type == MigrateAreaChart.source_viz_type + assert json.dumps(json.loads(slc.params), sort_keys=True) == json.dumps( + json.loads(area_form_data), sort_keys=True + ) diff --git a/tests/integration_tests/migrations/c747c78868b6_migrating_legacy_treemap__tests.py b/tests/integration_tests/migrations/c747c78868b6_migrating_legacy_treemap__tests.py new file mode 100644 index 0000000000000..3e9ef330924cb --- /dev/null +++ b/tests/integration_tests/migrations/c747c78868b6_migrating_legacy_treemap__tests.py @@ -0,0 +1,91 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import json + +from superset.app import SupersetApp +from superset.migrations.shared.migrate_viz import MigrateTreeMap + +treemap_form_data = """{ + "adhoc_filters": [ + { + "clause": "WHERE", + "comparator": [ + "Edward" + ], + "expressionType": "SIMPLE", + "filterOptionName": "filter_xhbus6irfa_r10k9nwmwy", + "isExtra": false, + "isNew": false, + "operator": "IN", + "operatorId": "IN", + "sqlExpression": null, + "subject": "name" + } + ], + "color_scheme": "bnbColors", + "datasource": "2__table", + "extra_form_data": {}, + "granularity_sqla": "ds", + "groupby": [ + "state", + "gender" + ], + "metrics": [ + "sum__num" + ], + "number_format": ",d", + "order_desc": true, + "row_limit": 10, + "time_range": "No filter", + "timeseries_limit_metric": "sum__num", + "treemap_ratio": 1.618033988749895, + "viz_type": "treemap" +} +""" + + +def test_treemap_migrate(app_context: SupersetApp) -> None: + from superset.models.slice import Slice + + slc = Slice( + viz_type=MigrateTreeMap.source_viz_type, + datasource_type="table", + params=treemap_form_data, + query_context=f'{{"form_data": {treemap_form_data}}}', + ) + + slc = MigrateTreeMap.upgrade_slice(slc) + assert slc.viz_type == MigrateTreeMap.target_viz_type + # verify form_data + new_form_data = json.loads(slc.params) + assert new_form_data["metric"] == "sum__num" + assert new_form_data["viz_type"] == "treemap_v2" + assert "metrics" not in new_form_data + assert json.dumps(new_form_data["form_data_bak"], sort_keys=True) == json.dumps( + json.loads(treemap_form_data), sort_keys=True + ) + + # verify query_context + new_query_context = json.loads(slc.query_context) + assert new_query_context["form_data"]["viz_type"] == "treemap_v2" + + # downgrade + slc = MigrateTreeMap.downgrade_slice(slc) + assert slc.viz_type == MigrateTreeMap.source_viz_type + assert json.dumps(json.loads(slc.params), sort_keys=True) == json.dumps( + json.loads(treemap_form_data), sort_keys=True + ) diff --git a/tests/integration_tests/model_tests.py b/tests/integration_tests/model_tests.py index a1791db34bffe..da6c5e6a3c254 100644 --- a/tests/integration_tests/model_tests.py +++ b/tests/integration_tests/model_tests.py @@ -57,30 +57,36 @@ def test_database_schema_presto(self): sqlalchemy_uri = "presto://presto.airbnb.io:8080/hive/default" model = Database(database_name="test_database", sqlalchemy_uri=sqlalchemy_uri) - db = make_url(model.get_sqla_engine().url).database - self.assertEqual("hive/default", db) + with model.get_sqla_engine_with_context() as engine: + db = make_url(engine.url).database + self.assertEqual("hive/default", db) - db = make_url(model.get_sqla_engine(schema="core_db").url).database - self.assertEqual("hive/core_db", db) + with model.get_sqla_engine_with_context(schema="core_db") as engine: + db = make_url(engine.url).database + self.assertEqual("hive/core_db", db) sqlalchemy_uri = "presto://presto.airbnb.io:8080/hive" model = Database(database_name="test_database", sqlalchemy_uri=sqlalchemy_uri) - db = make_url(model.get_sqla_engine().url).database - self.assertEqual("hive", db) + with model.get_sqla_engine_with_context() as engine: + db = make_url(engine.url).database + self.assertEqual("hive", db) - db = make_url(model.get_sqla_engine(schema="core_db").url).database - self.assertEqual("hive/core_db", db) + with model.get_sqla_engine_with_context(schema="core_db") as engine: + db = make_url(engine.url).database + self.assertEqual("hive/core_db", db) def test_database_schema_postgres(self): sqlalchemy_uri = "postgresql+psycopg2://postgres.airbnb.io:5439/prod" model = Database(database_name="test_database", sqlalchemy_uri=sqlalchemy_uri) - db = make_url(model.get_sqla_engine().url).database - self.assertEqual("prod", db) + with model.get_sqla_engine_with_context() as engine: + db = make_url(engine.url).database + self.assertEqual("prod", db) - db = make_url(model.get_sqla_engine(schema="foo").url).database - self.assertEqual("prod", db) + with model.get_sqla_engine_with_context(schema="foo") as engine: + db = make_url(engine.url).database + self.assertEqual("prod", db) @unittest.skipUnless( SupersetTestCase.is_module_installed("thrift"), "thrift not installed" @@ -91,11 +97,14 @@ def test_database_schema_postgres(self): def test_database_schema_hive(self): sqlalchemy_uri = "hive://hive@hive.airbnb.io:10000/default?auth=NOSASL" model = Database(database_name="test_database", sqlalchemy_uri=sqlalchemy_uri) - db = make_url(model.get_sqla_engine().url).database - self.assertEqual("default", db) - db = make_url(model.get_sqla_engine(schema="core_db").url).database - self.assertEqual("core_db", db) + with model.get_sqla_engine_with_context() as engine: + db = make_url(engine.url).database + self.assertEqual("default", db) + + with model.get_sqla_engine_with_context(schema="core_db") as engine: + db = make_url(engine.url).database + self.assertEqual("core_db", db) @unittest.skipUnless( SupersetTestCase.is_module_installed("MySQLdb"), "mysqlclient not installed" @@ -104,11 +113,13 @@ def test_database_schema_mysql(self): sqlalchemy_uri = "mysql://root@localhost/superset" model = Database(database_name="test_database", sqlalchemy_uri=sqlalchemy_uri) - db = make_url(model.get_sqla_engine().url).database - self.assertEqual("superset", db) + with model.get_sqla_engine_with_context() as engine: + db = make_url(engine.url).database + self.assertEqual("superset", db) - db = make_url(model.get_sqla_engine(schema="staging").url).database - self.assertEqual("staging", db) + with model.get_sqla_engine_with_context(schema="staging") as engine: + db = make_url(engine.url).database + self.assertEqual("staging", db) @unittest.skipUnless( SupersetTestCase.is_module_installed("MySQLdb"), "mysqlclient not installed" @@ -120,12 +131,14 @@ def test_database_impersonate_user(self): with override_user(example_user): model.impersonate_user = True - username = make_url(model.get_sqla_engine().url).username - self.assertEqual(example_user.username, username) + with model.get_sqla_engine_with_context() as engine: + username = make_url(engine.url).username + self.assertEqual(example_user.username, username) model.impersonate_user = False - username = make_url(model.get_sqla_engine().url).username - self.assertNotEqual(example_user.username, username) + with model.get_sqla_engine_with_context() as engine: + username = make_url(engine.url).username + self.assertNotEqual(example_user.username, username) @mock.patch("superset.models.core.create_engine") def test_impersonate_user_presto(self, mocked_create_engine): @@ -151,7 +164,7 @@ def test_impersonate_user_presto(self, mocked_create_engine): database_name="test_database", sqlalchemy_uri=uri, extra=extra ) model.impersonate_user = True - model.get_sqla_engine() + model._get_sqla_engine() call_args = mocked_create_engine.call_args assert str(call_args[0][0]) == "presto://gamma@localhost" @@ -164,7 +177,7 @@ def test_impersonate_user_presto(self, mocked_create_engine): } model.impersonate_user = False - model.get_sqla_engine() + model._get_sqla_engine() call_args = mocked_create_engine.call_args assert str(call_args[0][0]) == "presto://localhost" @@ -184,11 +197,11 @@ def test_impersonate_user_trino(self, mocked_create_engine): database_name="test_database", sqlalchemy_uri="trino://localhost" ) model.impersonate_user = True - model.get_sqla_engine() + model._get_sqla_engine() call_args = mocked_create_engine.call_args assert str(call_args[0][0]) == "trino://localhost" - assert call_args[1]["connect_args"] == {"user": "gamma"} + assert call_args[1]["connect_args"]["user"] == "gamma" model = Database( database_name="test_database", @@ -196,11 +209,14 @@ def test_impersonate_user_trino(self, mocked_create_engine): ) model.impersonate_user = True - model.get_sqla_engine() + model._get_sqla_engine() call_args = mocked_create_engine.call_args - assert str(call_args[0][0]) == "trino://original_user@localhost" - assert call_args[1]["connect_args"] == {"user": "gamma"} + assert ( + str(call_args[0][0]) + == "trino://original_user:original_user_password@localhost" + ) + assert call_args[1]["connect_args"]["user"] == "gamma" @mock.patch("superset.models.core.create_engine") def test_impersonate_user_hive(self, mocked_create_engine): @@ -226,7 +242,7 @@ def test_impersonate_user_hive(self, mocked_create_engine): database_name="test_database", sqlalchemy_uri=uri, extra=extra ) model.impersonate_user = True - model.get_sqla_engine() + model._get_sqla_engine() call_args = mocked_create_engine.call_args assert str(call_args[0][0]) == "hive://localhost" @@ -239,7 +255,7 @@ def test_impersonate_user_hive(self, mocked_create_engine): } model.impersonate_user = False - model.get_sqla_engine() + model._get_sqla_engine() call_args = mocked_create_engine.call_args assert str(call_args[0][0]) == "hive://localhost" @@ -364,7 +380,7 @@ def test_get_sqla_engine(self, mocked_create_engine): ) mocked_create_engine.side_effect = Exception() with self.assertRaises(SupersetException): - model.get_sqla_engine() + model._get_sqla_engine() class TestSqlaTableModel(SupersetTestCase): @@ -460,15 +476,15 @@ def test_query_with_expr_groupby_timeseries(self): # TODO(bkyryliuk): make it work for presto. return - def cannonicalize_df(df): + def canonicalize_df(df): ret = df.sort_values(by=list(df.columns.values), inplace=False) ret.reset_index(inplace=True, drop=True) return ret df1 = self.query_with_expr_helper(is_timeseries=True, inner_join=True) - name_list1 = cannonicalize_df(df1).name.values.tolist() + name_list1 = canonicalize_df(df1).name.values.tolist() df2 = self.query_with_expr_helper(is_timeseries=True, inner_join=False) - name_list2 = cannonicalize_df(df1).name.values.tolist() + name_list2 = canonicalize_df(df1).name.values.tolist() self.assertFalse(df2.empty) assert name_list2 == name_list1 @@ -589,7 +605,9 @@ def test_data_for_slices_with_query_context(self): assert len(data_for_slices["metrics"]) == 1 assert len(data_for_slices["columns"]) == 2 assert data_for_slices["metrics"][0]["metric_name"] == "sum__num" - assert data_for_slices["columns"][0]["column_name"] == "name" + column_names = [col["column_name"] for col in data_for_slices["columns"]] + assert "name" in column_names + assert "state" in column_names assert set(data_for_slices["verbose_map"].keys()) == { "__timestamp", "sum__num", diff --git a/tests/integration_tests/queries/api_tests.py b/tests/integration_tests/queries/api_tests.py index eaf4e00576573..b491cf8498b0e 100644 --- a/tests/integration_tests/queries/api_tests.py +++ b/tests/integration_tests/queries/api_tests.py @@ -17,6 +17,7 @@ # isort:skip_file """Unit tests for Superset""" from datetime import datetime, timedelta +from unittest import mock import json import random import string @@ -51,6 +52,7 @@ def insert_query( rows: int = 100, tab_name: str = "", status: str = "success", + changed_on: datetime = datetime(2020, 1, 1), ) -> Query: database = db.session.query(Database).get(database_id) user = db.session.query(security_manager.user_model).get(user_id) @@ -66,7 +68,7 @@ def insert_query( rows=rows, tab_name=tab_name, status=status, - changed_on=datetime(2020, 1, 1), + changed_on=changed_on, ) db.session.add(query) db.session.commit() @@ -392,3 +394,108 @@ def test_get_list_query_no_data_access(self): # rollback changes db.session.delete(query) db.session.commit() + + def test_get_updated_since(self): + """ + Query API: Test get queries updated since timestamp + """ + now = datetime.utcnow() + client_id = self.get_random_string() + + admin = self.get_user("admin") + example_db = get_example_database() + + old_query = self.insert_query( + example_db.id, + admin.id, + self.get_random_string(), + sql="SELECT col1, col2 from table1", + select_sql="SELECT col1, col2 from table1", + executed_sql="SELECT col1, col2 from table1 LIMIT 100", + changed_on=now - timedelta(days=3), + ) + updated_query = self.insert_query( + example_db.id, + admin.id, + client_id, + sql="SELECT col1, col2 from table1", + select_sql="SELECT col1, col2 from table1", + executed_sql="SELECT col1, col2 from table1 LIMIT 100", + changed_on=now - timedelta(days=1), + ) + + self.login(username="admin") + timestamp = datetime.timestamp(now - timedelta(days=2)) * 1000 + uri = f"api/v1/query/updated_since?q={prison.dumps({'last_updated_ms': timestamp})}" + rv = self.client.get(uri) + self.assertEqual(rv.status_code, 200) + + expected_result = updated_query.to_dict() + data = json.loads(rv.data.decode("utf-8")) + self.assertEqual(len(data["result"]), 1) + for key, value in data["result"][0].items(): + # We can't assert timestamp + if key not in ( + "changedOn", + "changed_on", + "end_time", + "start_running_time", + "start_time", + "id", + ): + self.assertEqual(value, expected_result[key]) + # rollback changes + db.session.delete(old_query) + db.session.delete(updated_query) + db.session.commit() + + @mock.patch("superset.sql_lab.cancel_query") + @mock.patch("superset.views.core.db.session") + def test_stop_query_not_found( + self, mock_superset_db_session, mock_sql_lab_cancel_query + ): + """ + Handles stop query when the DB engine spec does not + have a cancel query method (with invalid client_id). + """ + form_data = {"client_id": "foo2"} + query_mock = mock.Mock() + query_mock.return_value = None + self.login(username="admin") + mock_superset_db_session.query().filter_by().one_or_none = query_mock + mock_sql_lab_cancel_query.return_value = True + rv = self.client.post( + "/api/v1/query/stop", + data=json.dumps(form_data), + content_type="application/json", + ) + + assert rv.status_code == 404 + data = json.loads(rv.data.decode("utf-8")) + assert data["message"] == "Query with client_id foo2 not found" + + @mock.patch("superset.sql_lab.cancel_query") + @mock.patch("superset.views.core.db.session") + def test_stop_query(self, mock_superset_db_session, mock_sql_lab_cancel_query): + """ + Handles stop query when the DB engine spec does not + have a cancel query method. + """ + form_data = {"client_id": "foo"} + query_mock = mock.Mock() + query_mock.client_id = "foo" + query_mock.status = QueryStatus.RUNNING + self.login(username="admin") + mock_superset_db_session.query().filter_by().one_or_none().return_value = ( + query_mock + ) + mock_sql_lab_cancel_query.return_value = True + rv = self.client.post( + "/api/v1/query/stop", + data=json.dumps(form_data), + content_type="application/json", + ) + + assert rv.status_code == 200 + data = json.loads(rv.data.decode("utf-8")) + assert data["result"] == "OK" diff --git a/tests/integration_tests/queries/saved_queries/api_tests.py b/tests/integration_tests/queries/saved_queries/api_tests.py index 2659bc224ff30..91843b0085dda 100644 --- a/tests/integration_tests/queries/saved_queries/api_tests.py +++ b/tests/integration_tests/queries/saved_queries/api_tests.py @@ -98,7 +98,7 @@ def create_saved_queries(self): self.insert_default_saved_query( label=f"label{SAVED_QUERIES_FIXTURE_COUNT}", schema=f"schema{SAVED_QUERIES_FIXTURE_COUNT}", - username="gamma", + username="gamma_sqllab", ) ) @@ -157,12 +157,12 @@ def test_get_list_saved_query_gamma(self): """ Saved Query API: Test get list saved query """ - gamma = self.get_user("gamma") + user = self.get_user("gamma_sqllab") saved_queries = ( - db.session.query(SavedQuery).filter(SavedQuery.created_by == gamma).all() + db.session.query(SavedQuery).filter(SavedQuery.created_by == user).all() ) - self.login(username="gamma") + self.login(username=user.username) uri = f"api/v1/saved_query/" rv = self.get_assert_metric(uri, "get_list") assert rv.status_code == 200 @@ -445,7 +445,8 @@ def test_related_saved_query(self): expected_result = { "count": len(databases), "result": [ - {"text": str(database), "value": database.id} for database in databases + {"extra": {}, "text": str(database), "value": database.id} + for database in databases ], } @@ -523,10 +524,13 @@ def test_get_saved_query(self): "sql_tables": [{"catalog": None, "schema": None, "table": "table1"}], "schema": "schema1", "label": "label1", + "template_parameters": None, } data = json.loads(rv.data.decode("utf-8")) + self.assertIn("changed_on_delta_humanized", data["result"]) for key, value in data["result"].items(): - assert value == expected_result[key] + if key not in ("changed_on_delta_humanized",): + assert value == expected_result[key] def test_get_saved_query_not_found(self): """ diff --git a/tests/integration_tests/query_context_tests.py b/tests/integration_tests/query_context_tests.py index 816267678f9e0..5e5beae345b86 100644 --- a/tests/integration_tests/query_context_tests.py +++ b/tests/integration_tests/query_context_tests.py @@ -18,6 +18,8 @@ import time from typing import Any, Dict +import numpy as np +import pandas as pd import pytest from pandas import DateOffset @@ -25,12 +27,21 @@ from superset.charts.schemas import ChartDataQueryContextSchema from superset.common.chart_data import ChartDataResultFormat, ChartDataResultType from superset.common.query_context import QueryContext +from superset.common.query_context_factory import QueryContextFactory from superset.common.query_object import QueryObject -from superset.connectors.connector_registry import ConnectorRegistry from superset.connectors.sqla.models import SqlMetric +from superset.datasource.dao import DatasourceDAO from superset.extensions import cache_manager -from superset.utils.core import AdhocMetricExpressionType, backend, QueryStatus +from superset.superset_typing import AdhocColumn +from superset.utils.core import ( + AdhocMetricExpressionType, + backend, + DatasourceType, + QueryStatus, +) +from superset.utils.pandas_postprocessing.utils import FLAT_COLUMN_SEPARATOR from tests.integration_tests.base_tests import SupersetTestCase +from tests.integration_tests.conftest import only_postgresql, only_sqlite from tests.integration_tests.fixtures.birth_names_dashboard import ( load_birth_names_dashboard_with_slices, load_birth_names_data, @@ -63,7 +74,7 @@ def test_schema_deserialization(self): for query_idx, query in enumerate(query_context.queries): payload_query = payload["queries"][query_idx] - # check basic properies + # check basic properties self.assertEqual(query.extras, payload_query["extras"]) self.assertEqual(query.filter, payload_query["filters"]) self.assertEqual(query.columns, payload_query["columns"]) @@ -132,10 +143,10 @@ def test_query_cache_key_changes_when_datasource_is_updated(self): cache_key_original = query_context.query_cache_key(query_object) # make temporary change and revert it to refresh the changed_on property - datasource = ConnectorRegistry.get_datasource( - datasource_type=payload["datasource"]["type"], - datasource_id=payload["datasource"]["id"], + datasource = DatasourceDAO.get_datasource( session=db.session, + datasource_type=DatasourceType(payload["datasource"]["type"]), + datasource_id=payload["datasource"]["id"], ) description_original = datasource.description datasource.description = "temporary description" @@ -156,10 +167,10 @@ def test_query_cache_key_changes_when_metric_is_updated(self): payload = get_query_context("birth_names") # make temporary change and revert it to refresh the changed_on property - datasource = ConnectorRegistry.get_datasource( - datasource_type=payload["datasource"]["type"], - datasource_id=payload["datasource"]["id"], + datasource = DatasourceDAO.get_datasource( session=db.session, + datasource_type=DatasourceType(payload["datasource"]["type"]), + datasource_id=payload["datasource"]["id"], ) datasource.metrics.append(SqlMetric(metric_name="foo", expression="select 1;")) @@ -278,7 +289,6 @@ def test_convert_deprecated_fields(self): self.assertEqual(query_object.columns, columns) self.assertEqual(query_object.series_limit, 99) self.assertEqual(query_object.series_limit_metric, "sum__num") - self.assertIn("having_druid", query_object.extras) @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_csv_response_format(self): @@ -289,7 +299,7 @@ def test_csv_response_format(self): payload = get_query_context("birth_names") payload["result_format"] = ChartDataResultFormat.CSV.value payload["queries"][0]["row_limit"] = 10 - query_context = ChartDataQueryContextSchema().load(payload) + query_context: QueryContext = ChartDataQueryContextSchema().load(payload) responses = query_context.get_payload() self.assertEqual(len(responses), 1) data = responses["queries"][0]["data"] @@ -679,3 +689,414 @@ def test_time_offsets_accuracy(self): row["sum__num__3 years later"] == df_3_years_later.loc[index]["sum__num"] ) + + +def test_get_label_map(app_context, virtual_dataset_comma_in_column_value): + qc = QueryContextFactory().create( + datasource={ + "type": virtual_dataset_comma_in_column_value.type, + "id": virtual_dataset_comma_in_column_value.id, + }, + queries=[ + { + "columns": ["col1", "col2"], + "metrics": ["count"], + "post_processing": [ + { + "operation": "pivot", + "options": { + "aggregates": {"count": {"operator": "mean"}}, + "columns": ["col2"], + "index": ["col1"], + }, + }, + {"operation": "flatten"}, + ], + } + ], + result_type=ChartDataResultType.FULL, + force=True, + ) + query_object = qc.queries[0] + df = qc.get_df_payload(query_object)["df"] + label_map = qc.get_df_payload(query_object)["label_map"] + assert list(df.columns.values) == [ + "col1", + "count" + FLAT_COLUMN_SEPARATOR + "col2, row1", + "count" + FLAT_COLUMN_SEPARATOR + "col2, row2", + "count" + FLAT_COLUMN_SEPARATOR + "col2, row3", + ] + assert label_map == { + "col1": ["col1"], + "count, col2, row1": ["count", "col2, row1"], + "count, col2, row2": ["count", "col2, row2"], + "count, col2, row3": ["count", "col2, row3"], + } + + +def test_time_column_with_time_grain(app_context, physical_dataset): + column_on_axis: AdhocColumn = { + "label": "I_AM_AN_ORIGINAL_COLUMN", + "sqlExpression": "col5", + "timeGrain": "P1Y", + } + adhoc_column: AdhocColumn = { + "label": "I_AM_A_TRUNC_COLUMN", + "sqlExpression": "col6", + "columnType": "BASE_AXIS", + "timeGrain": "P1Y", + } + qc = QueryContextFactory().create( + datasource={ + "type": physical_dataset.type, + "id": physical_dataset.id, + }, + queries=[ + { + "columns": ["col1", column_on_axis, adhoc_column], + "metrics": ["count"], + "orderby": [["col1", True]], + } + ], + result_type=ChartDataResultType.FULL, + force=True, + ) + query_object = qc.queries[0] + df = qc.get_df_payload(query_object)["df"] + if query_object.datasource.database.backend == "sqlite": + # sqlite returns string as timestamp column + assert df["I_AM_AN_ORIGINAL_COLUMN"][0] == "2000-01-01 00:00:00" + assert df["I_AM_AN_ORIGINAL_COLUMN"][1] == "2000-01-02 00:00:00" + assert df["I_AM_A_TRUNC_COLUMN"][0] == "2002-01-01 00:00:00" + assert df["I_AM_A_TRUNC_COLUMN"][1] == "2002-01-01 00:00:00" + else: + assert df["I_AM_AN_ORIGINAL_COLUMN"][0].strftime("%Y-%m-%d") == "2000-01-01" + assert df["I_AM_AN_ORIGINAL_COLUMN"][1].strftime("%Y-%m-%d") == "2000-01-02" + assert df["I_AM_A_TRUNC_COLUMN"][0].strftime("%Y-%m-%d") == "2002-01-01" + assert df["I_AM_A_TRUNC_COLUMN"][1].strftime("%Y-%m-%d") == "2002-01-01" + + +def test_non_time_column_with_time_grain(app_context, physical_dataset): + qc = QueryContextFactory().create( + datasource={ + "type": physical_dataset.type, + "id": physical_dataset.id, + }, + queries=[ + { + "columns": [ + "col1", + { + "label": "COL2 ALIAS", + "sqlExpression": "col2", + "columnType": "BASE_AXIS", + "timeGrain": "P1Y", + }, + ], + "metrics": ["count"], + "orderby": [["col1", True]], + "row_limit": 1, + } + ], + result_type=ChartDataResultType.FULL, + force=True, + ) + + query_object = qc.queries[0] + df = qc.get_df_payload(query_object)["df"] + assert df["COL2 ALIAS"][0] == "a" + + +def test_special_chars_in_column_name(app_context, physical_dataset): + qc = QueryContextFactory().create( + datasource={ + "type": physical_dataset.type, + "id": physical_dataset.id, + }, + queries=[ + { + "columns": [ + "col1", + "time column with spaces", + { + "label": "I_AM_A_TRUNC_COLUMN", + "sqlExpression": "time column with spaces", + "columnType": "BASE_AXIS", + "timeGrain": "P1Y", + }, + ], + "metrics": ["count"], + "orderby": [["col1", True]], + "row_limit": 1, + } + ], + result_type=ChartDataResultType.FULL, + force=True, + ) + + query_object = qc.queries[0] + df = qc.get_df_payload(query_object)["df"] + if query_object.datasource.database.backend == "sqlite": + # sqlite returns string as timestamp column + assert df["time column with spaces"][0] == "2002-01-03 00:00:00" + assert df["I_AM_A_TRUNC_COLUMN"][0] == "2002-01-01 00:00:00" + else: + assert df["time column with spaces"][0].strftime("%Y-%m-%d") == "2002-01-03" + assert df["I_AM_A_TRUNC_COLUMN"][0].strftime("%Y-%m-%d") == "2002-01-01" + + +@only_postgresql +def test_date_adhoc_column(app_context, physical_dataset): + # sql expression returns date type + column_on_axis: AdhocColumn = { + "label": "ADHOC COLUMN", + "sqlExpression": "col6 + interval '20 year'", + "columnType": "BASE_AXIS", + "timeGrain": "P1Y", + } + qc = QueryContextFactory().create( + datasource={ + "type": physical_dataset.type, + "id": physical_dataset.id, + }, + queries=[ + { + "columns": [column_on_axis], + "metrics": ["count"], + } + ], + result_type=ChartDataResultType.FULL, + force=True, + ) + query_object = qc.queries[0] + df = qc.get_df_payload(query_object)["df"] + # ADHOC COLUMN count + # 0 2022-01-01 10 + assert df["ADHOC COLUMN"][0].strftime("%Y-%m-%d") == "2022-01-01" + assert df["count"][0] == 10 + + +@only_postgresql +def test_non_date_adhoc_column(app_context, physical_dataset): + # sql expression returns non-date type + column_on_axis: AdhocColumn = { + "label": "ADHOC COLUMN", + "sqlExpression": "col1 * 10", + "columnType": "BASE_AXIS", + "timeGrain": "P1Y", + } + qc = QueryContextFactory().create( + datasource={ + "type": physical_dataset.type, + "id": physical_dataset.id, + }, + queries=[ + { + "columns": [column_on_axis], + "metrics": ["count"], + "orderby": [ + [ + { + "expressionType": "SQL", + "sqlExpression": '"ADHOC COLUMN"', + }, + True, + ] + ], + } + ], + result_type=ChartDataResultType.FULL, + force=True, + ) + query_object = qc.queries[0] + df = qc.get_df_payload(query_object)["df"] + assert df["ADHOC COLUMN"][0] == 0 + assert df["ADHOC COLUMN"][1] == 10 + + +@only_sqlite +def test_time_grain_and_time_offset_with_base_axis(app_context, physical_dataset): + column_on_axis: AdhocColumn = { + "label": "col6", + "sqlExpression": "col6", + "columnType": "BASE_AXIS", + "timeGrain": "P3M", + } + qc = QueryContextFactory().create( + datasource={ + "type": physical_dataset.type, + "id": physical_dataset.id, + }, + queries=[ + { + "columns": [column_on_axis], + "metrics": [ + { + "label": "SUM(col1)", + "expressionType": "SQL", + "sqlExpression": "SUM(col1)", + } + ], + "time_offsets": ["3 month ago"], + "granularity": "col6", + "time_range": "2002-01 : 2003-01", + } + ], + result_type=ChartDataResultType.FULL, + force=True, + ) + query_object = qc.queries[0] + df = qc.get_df_payload(query_object)["df"] + # todo: MySQL returns integer and float column as object type + """ + col6 SUM(col1) SUM(col1)__3 month ago +0 2002-01-01 3 NaN +1 2002-04-01 12 3.0 +2 2002-07-01 21 12.0 +3 2002-10-01 9 21.0 + """ + assert df.equals( + pd.DataFrame( + data={ + "col6": pd.to_datetime( + ["2002-01-01", "2002-04-01", "2002-07-01", "2002-10-01"] + ), + "SUM(col1)": [3, 12, 21, 9], + "SUM(col1)__3 month ago": [np.nan, 3, 12, 21], + } + ) + ) + + +@only_sqlite +def test_time_grain_and_time_offset_on_legacy_query(app_context, physical_dataset): + qc = QueryContextFactory().create( + datasource={ + "type": physical_dataset.type, + "id": physical_dataset.id, + }, + queries=[ + { + "columns": [], + "extras": { + "time_grain_sqla": "P3M", + }, + "metrics": [ + { + "label": "SUM(col1)", + "expressionType": "SQL", + "sqlExpression": "SUM(col1)", + } + ], + "time_offsets": ["3 month ago"], + "granularity": "col6", + "time_range": "2002-01 : 2003-01", + "is_timeseries": True, + } + ], + result_type=ChartDataResultType.FULL, + force=True, + ) + query_object = qc.queries[0] + df = qc.get_df_payload(query_object)["df"] + # todo: MySQL returns integer and float column as object type + """ + __timestamp SUM(col1) SUM(col1)__3 month ago +0 2002-01-01 3 NaN +1 2002-04-01 12 3.0 +2 2002-07-01 21 12.0 +3 2002-10-01 9 21.0 + """ + assert df.equals( + pd.DataFrame( + data={ + "__timestamp": pd.to_datetime( + ["2002-01-01", "2002-04-01", "2002-07-01", "2002-10-01"] + ), + "SUM(col1)": [3, 12, 21, 9], + "SUM(col1)__3 month ago": [np.nan, 3, 12, 21], + } + ) + ) + + +def test_time_offset_with_temporal_range_filter(app_context, physical_dataset): + qc = QueryContextFactory().create( + datasource={ + "type": physical_dataset.type, + "id": physical_dataset.id, + }, + queries=[ + { + "columns": [ + { + "label": "col6", + "sqlExpression": "col6", + "columnType": "BASE_AXIS", + "timeGrain": "P3M", + } + ], + "metrics": [ + { + "label": "SUM(col1)", + "expressionType": "SQL", + "sqlExpression": "SUM(col1)", + } + ], + "time_offsets": ["3 month ago"], + "filters": [ + { + "col": "col6", + "op": "TEMPORAL_RANGE", + "val": "2002-01 : 2003-01", + } + ], + } + ], + result_type=ChartDataResultType.FULL, + force=True, + ) + query_payload = qc.get_df_payload(qc.queries[0]) + df = query_payload["df"] + """ + col6 SUM(col1) SUM(col1)__3 month ago +0 2002-01-01 3 NaN +1 2002-04-01 12 3.0 +2 2002-07-01 21 12.0 +3 2002-10-01 9 21.0 + """ + assert df["SUM(col1)"].to_list() == [3, 12, 21, 9] + # df["SUM(col1)__3 month ago"].dtype is object so have to convert to float first + assert df["SUM(col1)__3 month ago"].astype("float").astype("Int64").to_list() == [ + pd.NA, + 3, + 12, + 21, + ] + + sqls = query_payload["query"].split(";") + """ + SELECT DATE_TRUNC('quarter', col6) AS col6, + SUM(col1) AS "SUM(col1)" + FROM physical_dataset + WHERE col6 >= TO_TIMESTAMP('2002-01-01 00:00:00.000000', 'YYYY-MM-DD HH24:MI:SS.US') + AND col6 < TO_TIMESTAMP('2003-01-01 00:00:00.000000', 'YYYY-MM-DD HH24:MI:SS.US') + GROUP BY DATE_TRUNC('quarter', col6) + LIMIT 10000; + + SELECT DATE_TRUNC('quarter', col6) AS col6, + SUM(col1) AS "SUM(col1)" + FROM physical_dataset + WHERE col6 >= TO_TIMESTAMP('2001-10-01 00:00:00.000000', 'YYYY-MM-DD HH24:MI:SS.US') + AND col6 < TO_TIMESTAMP('2002-10-01 00:00:00.000000', 'YYYY-MM-DD HH24:MI:SS.US') + GROUP BY DATE_TRUNC('quarter', col6) + LIMIT 10000; + """ + assert ( + re.search(r"WHERE col6 >= .*2002-01-01", sqls[0]) + and re.search(r"AND col6 < .*2003-01-01", sqls[0]) + ) is not None + assert ( + re.search(r"WHERE col6 >= .*2001-10-01", sqls[1]) + and re.search(r"AND col6 < .*2002-10-01", sqls[1]) + ) is not None diff --git a/tests/integration_tests/reports/alert_tests.py b/tests/integration_tests/reports/alert_tests.py index d868aaea232d1..6c5c41a81ff23 100644 --- a/tests/integration_tests/reports/alert_tests.py +++ b/tests/integration_tests/reports/alert_tests.py @@ -15,10 +15,91 @@ # specific language governing permissions and limitations # under the License. # pylint: disable=invalid-name, unused-argument, import-outside-toplevel +from contextlib import nullcontext +from typing import List, Optional, Tuple, Union import pandas as pd +import pytest from pytest_mock import MockFixture +from superset.reports.commands.exceptions import AlertQueryError +from superset.reports.models import ReportCreationMethod, ReportScheduleType +from superset.tasks.types import ExecutorType +from superset.utils.database import get_example_database +from tests.integration_tests.test_app import app + + +@pytest.mark.parametrize( + "owner_names,creator_name,config,expected_result", + [ + (["gamma"], None, [ExecutorType.SELENIUM], "admin"), + (["gamma"], None, [ExecutorType.OWNER], "gamma"), + ( + ["alpha", "gamma"], + "gamma", + [ExecutorType.CREATOR_OWNER], + "gamma", + ), + ( + ["alpha", "gamma"], + "alpha", + [ExecutorType.CREATOR_OWNER], + "alpha", + ), + ( + ["alpha", "gamma"], + "admin", + [ExecutorType.CREATOR_OWNER], + AlertQueryError(), + ), + (["gamma"], None, [ExecutorType.CURRENT_USER], AlertQueryError()), + ], +) +def test_execute_query_as_report_executor( + owner_names: List[str], + creator_name: Optional[str], + config: List[ExecutorType], + expected_result: Union[Tuple[ExecutorType, str], Exception], + mocker: MockFixture, + app_context: None, + get_user, +) -> None: + + from superset.reports.commands.alert import AlertCommand + from superset.reports.models import ReportSchedule + + with app.app_context(): + original_config = app.config["ALERT_REPORTS_EXECUTE_AS"] + app.config["ALERT_REPORTS_EXECUTE_AS"] = config + owners = [get_user(owner_name) for owner_name in owner_names] + report_schedule = ReportSchedule( + created_by=get_user(creator_name) if creator_name else None, + owners=owners, + type=ReportScheduleType.ALERT, + description="description", + crontab="0 9 * * *", + creation_method=ReportCreationMethod.ALERTS_REPORTS, + sql="SELECT 1", + grace_period=14400, + working_timeout=3600, + database=get_example_database(), + validator_config_json='{"op": "==", "threshold": 1}', + ) + command = AlertCommand(report_schedule=report_schedule) + override_user_mock = mocker.patch( + "superset.reports.commands.alert.override_user" + ) + cm = ( + pytest.raises(type(expected_result)) + if isinstance(expected_result, Exception) + else nullcontext() + ) + with cm: + command.run() + assert override_user_mock.call_args[0][0].username == expected_result + + app.config["ALERT_REPORTS_EXECUTE_AS"] = original_config + def test_execute_query_succeeded_no_retry( mocker: MockFixture, app_context: None diff --git a/tests/integration_tests/reports/api_tests.py b/tests/integration_tests/reports/api_tests.py index 2ca41610a2e41..22b9be9990b74 100644 --- a/tests/integration_tests/reports/api_tests.py +++ b/tests/integration_tests/reports/api_tests.py @@ -23,13 +23,14 @@ import pytest import prison +from parameterized import parameterized from sqlalchemy.sql import func -from superset import db +from superset import db, security_manager from superset.models.core import Database from superset.models.slice import Slice from superset.models.dashboard import Dashboard -from superset.models.reports import ( +from superset.reports.models import ( ReportSchedule, ReportCreationMethod, ReportRecipients, @@ -45,15 +46,98 @@ load_birth_names_dashboard_with_slices, load_birth_names_data, ) -from tests.integration_tests.fixtures.tabbed_dashboard import tabbed_dashboard from tests.integration_tests.reports.utils import insert_report_schedule REPORTS_COUNT = 10 +REPORTS_ROLE_NAME = "reports_role" +REPORTS_GAMMA_USER = "reports_gamma" class TestReportSchedulesApi(SupersetTestCase): @pytest.fixture() - def create_working_report_schedule(self): + def gamma_user_with_alerts_role(self): + with self.create_app().app_context(): + user = self.create_user( + REPORTS_GAMMA_USER, + "general", + "Gamma", + email=f"{REPORTS_GAMMA_USER}@superset.org", + ) + + security_manager.add_role(REPORTS_ROLE_NAME) + read_perm = security_manager.find_permission_view_menu( + "can_read", + "ReportSchedule", + ) + write_perm = security_manager.find_permission_view_menu( + "can_write", + "ReportSchedule", + ) + reports_role = security_manager.find_role(REPORTS_ROLE_NAME) + security_manager.add_permission_role(reports_role, read_perm) + security_manager.add_permission_role(reports_role, write_perm) + user.roles.append(reports_role) + + yield user + + # rollback changes (assuming cascade delete) + db.session.delete(reports_role) + db.session.delete(user) + db.session.commit() + + @pytest.fixture() + def create_working_admin_report_schedule(self): + with self.create_app().app_context(): + + admin_user = self.get_user("admin") + chart = db.session.query(Slice).first() + example_db = get_example_database() + + report_schedule = insert_report_schedule( + type=ReportScheduleType.ALERT, + name="name_admin_working", + crontab="* * * * *", + sql="SELECT value from table", + description="Report working", + chart=chart, + database=example_db, + owners=[admin_user], + last_state=ReportState.WORKING, + ) + + yield + + db.session.delete(report_schedule) + db.session.commit() + + @pytest.mark.usefixtures("gamma_user_with_alerts_role") + @pytest.fixture() + def create_working_gamma_report_schedule(self, gamma_user_with_alerts_role): + with self.create_app().app_context(): + + chart = db.session.query(Slice).first() + example_db = get_example_database() + + report_schedule = insert_report_schedule( + type=ReportScheduleType.ALERT, + name="name_gamma_working", + crontab="* * * * *", + sql="SELECT value from table", + description="Report working", + chart=chart, + database=example_db, + owners=[gamma_user_with_alerts_role], + last_state=ReportState.WORKING, + ) + + yield + + db.session.delete(report_schedule) + db.session.commit() + + @pytest.mark.usefixtures("gamma_user_with_alerts_role") + @pytest.fixture() + def create_working_shared_report_schedule(self, gamma_user_with_alerts_role): with self.create_app().app_context(): admin_user = self.get_user("admin") @@ -63,13 +147,13 @@ def create_working_report_schedule(self): report_schedule = insert_report_schedule( type=ReportScheduleType.ALERT, - name="name_working", + name="name_shared_working", crontab="* * * * *", sql="SELECT value from table", description="Report working", chart=chart, database=example_db, - owners=[admin_user, alpha_user], + owners=[admin_user, alpha_user, gamma_user_with_alerts_role], last_state=ReportState.WORKING, ) @@ -281,6 +365,7 @@ def test_get_list_report_schedule(self): "crontab_humanized", "dashboard_id", "description", + "extra", "id", "last_eval_dttm", "last_state", @@ -305,6 +390,61 @@ def test_get_list_report_schedule(self): data_keys = sorted(list(data["result"][1]["recipients"][0].keys())) assert expected_recipients_fields == data_keys + @parameterized.expand( + [ + ( + "admin", + { + "name_admin_working", + "name_gamma_working", + "name_shared_working", + }, + ), + ( + "alpha", + { + "name_admin_working", + "name_gamma_working", + "name_shared_working", + }, + ), + ( + REPORTS_GAMMA_USER, + { + "name_gamma_working", + "name_shared_working", + }, + ), + ], + ) + @pytest.mark.usefixtures( + "create_working_admin_report_schedule", + "create_working_gamma_report_schedule", + "create_working_shared_report_schedule", + "gamma_user_with_alerts_role", + ) + def test_get_list_report_schedule_perms(self, username, report_names): + """ + ReportSchedule Api: Test get list report schedules for different roles + """ + self.login(username=username) + uri = f"api/v1/report/" + rv = self.get_assert_metric(uri, "get_list") + + assert rv.status_code == 200 + data = json.loads(rv.data.decode("utf-8")) + assert {report["name"] for report in data["result"]} == report_names + + def test_get_list_report_schedule_gamma(self): + """ + ReportSchedule Api: Test get list report schedules for regular gamma user + """ + self.login(username="gamma") + uri = f"api/v1/report/" + rv = self.client.get(uri) + + assert rv.status_code == 403 + @pytest.mark.usefixtures("create_report_schedules") def test_get_list_report_schedule_sorting(self): """ @@ -431,7 +571,7 @@ def test_get_list_report_schedule_filter_type(self): @pytest.mark.usefixtures("create_report_schedules") def test_get_related_report_schedule(self): """ - ReportSchedule Api: Test get releated report schedule + ReportSchedule Api: Test get related report schedule """ self.login(username="admin") related_columns = ["created_by", "chart", "dashboard", "database"] @@ -1159,14 +1299,14 @@ def test_update_report_schedule(self): assert updated_model.chart_id == report_schedule_data["chart"] assert updated_model.database_id == report_schedule_data["database"] - @pytest.mark.usefixtures("create_working_report_schedule") + @pytest.mark.usefixtures("create_working_shared_report_schedule") def test_update_report_schedule_state_working(self): """ ReportSchedule Api: Test update state in a working report """ report_schedule = ( db.session.query(ReportSchedule) - .filter(ReportSchedule.name == "name_working") + .filter(ReportSchedule.name == "name_shared_working") .one_or_none() ) @@ -1177,7 +1317,7 @@ def test_update_report_schedule_state_working(self): assert rv.status_code == 200 report_schedule = ( db.session.query(ReportSchedule) - .filter(ReportSchedule.name == "name_working") + .filter(ReportSchedule.name == "name_shared_working") .one_or_none() ) assert report_schedule.last_state == ReportState.NOOP @@ -1528,84 +1668,3 @@ def test_report_schedule_logs_no_mutations(self): assert rv.status_code == 405 rv = self.client.delete(uri) assert rv.status_code == 405 - - @pytest.mark.usefixtures("create_report_schedules") - @pytest.mark.usefixtures("tabbed_dashboard") - def test_when_invalid_tab_ids_are_given_it_raises_bad_request(self): - """ - when tab ids are specified in the extra argument, make sure that the - tab ids are valid. - """ - self.login(username="admin") - dashboard = ( - db.session.query(Dashboard) - .filter(Dashboard.slug == "tabbed-dash-test") - .first() - ) - example_db = get_example_database() - report_schedule_data = { - "type": ReportScheduleType.ALERT, - "name": "new3", - "description": "description", - "crontab": "0 9 * * *", - "creation_method": ReportCreationMethod.ALERTS_REPORTS, - "recipients": [ - { - "type": ReportRecipientType.EMAIL, - "recipient_config_json": {"target": "target@superset.org"}, - }, - ], - "grace_period": 14400, - "working_timeout": 3600, - "chart": None, - "dashboard": dashboard.id, - "database": example_db.id, - "extra": {"dashboard_tab_ids": ["INVALID-TAB-ID-1", "TABS-IpViLohnyP"]}, - } - response = self.post_assert_metric( - "api/v1/report/", report_schedule_data, "post" - ) - assert response.status_code == 422 - assert response.json == { - "message": {"extra": ["Invalid tab IDs selected: ['INVALID-TAB-ID-1']"]} - } - - @pytest.mark.usefixtures("create_report_schedules") - @pytest.mark.usefixtures("tabbed_dashboard") - def test_when_tab_ids_are_given_it_gets_added_to_extra(self): - self.login(username="admin") - dashboard = ( - db.session.query(Dashboard) - .filter(Dashboard.slug == "tabbed-dash-test") - .first() - ) - example_db = get_example_database() - report_schedule_data = { - "type": ReportScheduleType.ALERT, - "name": "new3", - "description": "description", - "crontab": "0 9 * * *", - "creation_method": ReportCreationMethod.ALERTS_REPORTS, - "recipients": [ - { - "type": ReportRecipientType.EMAIL, - "recipient_config_json": {"target": "target@superset.org"}, - }, - ], - "grace_period": 14400, - "working_timeout": 3600, - "chart": None, - "dashboard": dashboard.id, - "database": example_db.id, - "extra": {"dashboard_tab_ids": ["TABS-IpViLohnyP"]}, - } - response = self.post_assert_metric( - "api/v1/report/", report_schedule_data, "post" - ) - assert response.status_code == 201 - assert json.loads( - db.session.query(ReportSchedule) - .filter(ReportSchedule.id == response.json["id"]) - .first() - .extra - ) == {"dashboard_tab_ids": ["TABS-IpViLohnyP"]} diff --git a/tests/integration_tests/reports/commands/create_dashboard_report_tests.py b/tests/integration_tests/reports/commands/create_dashboard_report_tests.py new file mode 100644 index 0000000000000..81945c18a9abd --- /dev/null +++ b/tests/integration_tests/reports/commands/create_dashboard_report_tests.py @@ -0,0 +1,91 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import pytest + +from superset import db +from superset.models.dashboard import Dashboard +from superset.reports.commands.create import CreateReportScheduleCommand +from superset.reports.commands.exceptions import ReportScheduleInvalidError +from superset.reports.models import ( + ReportCreationMethod, + ReportRecipientType, + ReportScheduleType, +) +from tests.integration_tests.fixtures.tabbed_dashboard import tabbed_dashboard + +DASHBOARD_REPORT_SCHEDULE_DEFAULTS = { + "type": ReportScheduleType.REPORT, + "description": "description", + "crontab": "0 9 * * *", + "creation_method": ReportCreationMethod.ALERTS_REPORTS, + "recipients": [ + { + "type": ReportRecipientType.EMAIL, + "recipient_config_json": {"target": "target@example.com"}, + }, + ], + "grace_period": 14400, + "working_timeout": 3600, +} + + +@pytest.mark.usefixtures("login_as_admin") +def test_accept_valid_tab_ids(tabbed_dashboard: Dashboard) -> None: + report_schedule = CreateReportScheduleCommand( + { + **DASHBOARD_REPORT_SCHEDULE_DEFAULTS, + "name": "tabbed dashboard report (valid tabs id)", + "dashboard": tabbed_dashboard.id, + "extra": {"dashboard": {"activeTabs": ["TAB-L1AA", "TAB-L2AB"]}}, + } + ).run() + assert report_schedule.extra == { + "dashboard": {"activeTabs": ["TAB-L1AA", "TAB-L2AB"]} + } + db.session.delete(report_schedule) + db.session.commit() + + +@pytest.mark.usefixtures("login_as_admin") +def test_raise_exception_for_invalid_tab_ids(tabbed_dashboard: Dashboard) -> None: + with pytest.raises(ReportScheduleInvalidError) as exc_info: + CreateReportScheduleCommand( + { + **DASHBOARD_REPORT_SCHEDULE_DEFAULTS, + "name": "tabbed dashboard report (invalid tab ids)", + "dashboard": tabbed_dashboard.id, + "extra": {"dashboard": {"activeTabs": ["TAB-INVALID_ID"]}}, + } + ).run() + assert "Invalid tab ids" in str(exc_info.value.normalized_messages()) + + with pytest.raises(ReportScheduleInvalidError) as exc_info: + CreateReportScheduleCommand( + { + **DASHBOARD_REPORT_SCHEDULE_DEFAULTS, + "name": "tabbed dashboard report (invalid tab ids in anchor)", + "dashboard": tabbed_dashboard.id, + "extra": { + "dashboard": { + "activeTabs": ["TAB-L1AA"], + "anchor": "TAB-INVALID_ID", + } + }, + } + ).run() + assert "Invalid tab ids" in str(exc_info.value.normalized_messages()) diff --git a/tests/integration_tests/reports/commands/execute_dashboard_report_tests.py b/tests/integration_tests/reports/commands/execute_dashboard_report_tests.py new file mode 100644 index 0000000000000..0027738fd9807 --- /dev/null +++ b/tests/integration_tests/reports/commands/execute_dashboard_report_tests.py @@ -0,0 +1,113 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from datetime import datetime +from unittest.mock import MagicMock, patch +from uuid import uuid4 + +from flask import current_app + +from superset.dashboards.permalink.commands.create import ( + CreateDashboardPermalinkCommand, +) +from superset.models.dashboard import Dashboard +from superset.reports.commands.execute import AsyncExecuteReportScheduleCommand +from superset.reports.models import ReportSourceFormat +from tests.integration_tests.fixtures.tabbed_dashboard import tabbed_dashboard +from tests.integration_tests.reports.utils import create_dashboard_report + + +@patch("superset.reports.notifications.email.send_email_smtp") +@patch( + "superset.reports.commands.execute.DashboardScreenshot", +) +@patch( + "superset.dashboards.permalink.commands.create.CreateDashboardPermalinkCommand.run" +) +def test_report_for_dashboard_with_tabs( + create_dashboard_permalink_mock: MagicMock, + dashboard_screenshot_mock: MagicMock, + send_email_smtp_mock: MagicMock, + tabbed_dashboard: Dashboard, +) -> None: + create_dashboard_permalink_mock.return_value = "permalink" + dashboard_screenshot_mock.get_screenshot.return_value = b"test-image" + current_app.config["ALERT_REPORTS_NOTIFICATION_DRY_RUN"] = False + + with create_dashboard_report( + dashboard=tabbed_dashboard, + extra={"active_tabs": ["TAB-L1B", "TAB-L2BB"]}, + name="test report tabbed dashboard", + ) as report_schedule: + dashboard: Dashboard = report_schedule.dashboard + AsyncExecuteReportScheduleCommand( + str(uuid4()), report_schedule.id, datetime.utcnow() + ).run() + dashboard_state = report_schedule.extra.get("dashboard", {}) + permalink_key = CreateDashboardPermalinkCommand( + dashboard.id, dashboard_state + ).run() + + assert dashboard_screenshot_mock.call_count == 1 + (url, digest) = dashboard_screenshot_mock.call_args.args + assert url.endswith(f"/superset/dashboard/p/{permalink_key}/") + assert digest == dashboard.digest + assert send_email_smtp_mock.call_count == 1 + assert len(send_email_smtp_mock.call_args.kwargs["images"]) == 1 + + +@patch("superset.reports.notifications.email.send_email_smtp") +@patch( + "superset.reports.commands.execute.DashboardScreenshot", +) +@patch( + "superset.dashboards.permalink.commands.create.CreateDashboardPermalinkCommand.run" +) +def test_report_with_header_data( + create_dashboard_permalink_mock: MagicMock, + dashboard_screenshot_mock: MagicMock, + send_email_smtp_mock: MagicMock, + tabbed_dashboard: Dashboard, +) -> None: + create_dashboard_permalink_mock.return_value = "permalink" + dashboard_screenshot_mock.get_screenshot.return_value = b"test-image" + current_app.config["ALERT_REPORTS_NOTIFICATION_DRY_RUN"] = False + + with create_dashboard_report( + dashboard=tabbed_dashboard, + extra={"active_tabs": ["TAB-L1B"]}, + name="test report tabbed dashboard", + ) as report_schedule: + dashboard: Dashboard = report_schedule.dashboard + AsyncExecuteReportScheduleCommand( + str(uuid4()), report_schedule.id, datetime.utcnow() + ).run() + dashboard_state = report_schedule.extra.get("dashboard", {}) + permalink_key = CreateDashboardPermalinkCommand( + dashboard.id, dashboard_state + ).run() + + assert dashboard_screenshot_mock.call_count == 1 + (url, digest) = dashboard_screenshot_mock.call_args.args + assert url.endswith(f"/superset/dashboard/p/{permalink_key}/") + assert digest == dashboard.digest + assert send_email_smtp_mock.call_count == 1 + header_data = send_email_smtp_mock.call_args.kwargs["header_data"] + assert header_data.get("dashboard_id") == dashboard.id + assert header_data.get("notification_format") == report_schedule.report_format + assert header_data.get("notification_source") == ReportSourceFormat.DASHBOARD + assert header_data.get("notification_type") == report_schedule.type + assert len(send_email_smtp_mock.call_args.kwargs["header_data"]) == 6 diff --git a/tests/integration_tests/reports/commands_tests.py b/tests/integration_tests/reports/commands_tests.py index 8163f48abd266..8d6a76c14f67e 100644 --- a/tests/integration_tests/reports/commands_tests.py +++ b/tests/integration_tests/reports/commands_tests.py @@ -16,70 +16,89 @@ # under the License. import json from contextlib import contextmanager -from datetime import datetime, timedelta -from typing import Any, Dict, List, Optional -from unittest.mock import Mock, patch +from datetime import datetime, timedelta, timezone +from typing import List, Optional +from unittest.mock import call, Mock, patch from uuid import uuid4 import pytest from flask import current_app +from flask_appbuilder.security.sqla.models import User from flask_sqlalchemy import BaseQuery from freezegun import freeze_time +from slack_sdk.errors import ( + BotUserAccessError, + SlackApiError, + SlackClientConfigurationError, + SlackClientError, + SlackClientNotConnectedError, + SlackObjectFormationError, + SlackRequestError, + SlackTokenRotationError, +) from sqlalchemy.sql import func -from superset import db, security_manager +from superset import db +from superset.exceptions import SupersetException from superset.models.core import Database from superset.models.dashboard import Dashboard -from superset.models.reports import ( - ReportDataFormat, - ReportExecutionLog, - ReportRecipients, - ReportRecipientType, - ReportSchedule, - ReportScheduleType, - ReportScheduleValidatorType, - ReportState, -) from superset.models.slice import Slice from superset.reports.commands.exceptions import ( AlertQueryError, AlertQueryInvalidTypeError, AlertQueryMultipleColumnsError, AlertQueryMultipleRowsError, + ReportScheduleClientErrorsException, ReportScheduleCsvFailedError, ReportScheduleCsvTimeout, ReportScheduleNotFoundError, - ReportScheduleNotificationError, ReportSchedulePreviousWorkingError, ReportScheduleScreenshotFailedError, ReportScheduleScreenshotTimeout, + ReportScheduleSystemErrorsException, ReportScheduleWorkingTimeoutError, ) -from superset.reports.commands.execute import AsyncExecuteReportScheduleCommand +from superset.reports.commands.execute import ( + AsyncExecuteReportScheduleCommand, + BaseReportState, +) from superset.reports.commands.log_prune import AsyncPruneReportScheduleLogCommand +from superset.reports.models import ( + ReportDataFormat, + ReportExecutionLog, + ReportSchedule, + ReportScheduleType, + ReportScheduleValidatorType, + ReportState, +) +from superset.reports.notifications.exceptions import ( + NotificationError, + NotificationParamException, +) +from superset.tasks.types import ExecutorType from superset.utils.database import get_example_database from tests.integration_tests.fixtures.birth_names_dashboard import ( load_birth_names_dashboard_with_slices, load_birth_names_data, ) -from tests.integration_tests.fixtures.tabbed_dashboard import tabbed_dashboard from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices_module_scope, load_world_bank_data, ) -from tests.integration_tests.reports.utils import insert_report_schedule +from tests.integration_tests.reports.utils import ( + cleanup_report_schedule, + create_report_notification, + CSV_FILE, + DEFAULT_OWNER_EMAIL, + SCREENSHOT_FILE, + TEST_ID, +) from tests.integration_tests.test_app import app -from tests.integration_tests.utils import read_fixture pytestmark = pytest.mark.usefixtures( "load_world_bank_dashboard_with_slices_module_scope" ) -TEST_ID = str(uuid4()) -CSV_FILE = read_fixture("trends.csv") -SCREENSHOT_FILE = read_fixture("sample.png") -OWNER_EMAIL = "admin@fab.org" - def get_target_from_report_schedule(report_schedule: ReportSchedule) -> List[str]: return [ @@ -129,92 +148,16 @@ def assert_log(state: str, error_message: Optional[str] = None): assert log.value_row_json is None -def create_report_notification( - email_target: Optional[str] = None, - slack_channel: Optional[str] = None, - chart: Optional[Slice] = None, - dashboard: Optional[Dashboard] = None, - database: Optional[Database] = None, - sql: Optional[str] = None, - report_type: Optional[str] = None, - validator_type: Optional[str] = None, - validator_config_json: Optional[str] = None, - grace_period: Optional[int] = None, - report_format: Optional[ReportDataFormat] = None, - name: Optional[str] = None, - extra: Optional[Dict[str, Any]] = None, - force_screenshot: bool = False, -) -> ReportSchedule: - report_type = report_type or ReportScheduleType.REPORT - target = email_target or slack_channel - config_json = {"target": target} - owner = ( - db.session.query(security_manager.user_model) - .filter_by(email=OWNER_EMAIL) - .one_or_none() - ) - - if slack_channel: - recipient = ReportRecipients( - type=ReportRecipientType.SLACK, - recipient_config_json=json.dumps(config_json), - ) - else: - recipient = ReportRecipients( - type=ReportRecipientType.EMAIL, - recipient_config_json=json.dumps(config_json), - ) - - if name is None: - name = "report_with_csv" if report_format else "report" - - report_schedule = insert_report_schedule( - type=report_type, - name=name, - crontab="0 9 * * *", - description="Daily report", - sql=sql, - chart=chart, - dashboard=dashboard, - database=database, - recipients=[recipient], - owners=[owner], - validator_type=validator_type, - validator_config_json=validator_config_json, - grace_period=grace_period, - report_format=report_format or ReportDataFormat.VISUALIZATION, - extra=extra, - force_screenshot=force_screenshot, - ) - return report_schedule - - -def cleanup_report_schedule(report_schedule: ReportSchedule) -> None: - db.session.query(ReportExecutionLog).filter( - ReportExecutionLog.report_schedule == report_schedule - ).delete() - db.session.query(ReportRecipients).filter( - ReportRecipients.report_schedule == report_schedule - ).delete() - - db.session.delete(report_schedule) - db.session.commit() - - @contextmanager def create_test_table_context(database: Database): - database.get_sqla_engine().execute( - "CREATE TABLE test_table AS SELECT 1 as first, 2 as second" - ) - database.get_sqla_engine().execute( - "INSERT INTO test_table (first, second) VALUES (1, 2)" - ) - database.get_sqla_engine().execute( - "INSERT INTO test_table (first, second) VALUES (3, 4)" - ) + with database.get_sqla_engine_with_context() as engine: + engine.execute("CREATE TABLE test_table AS SELECT 1 as first, 2 as second") + engine.execute("INSERT INTO test_table (first, second) VALUES (1, 2)") + engine.execute("INSERT INTO test_table (first, second) VALUES (3, 4)") yield db.session - database.get_sqla_engine().execute("DROP TABLE test_table") + with database.get_sqla_engine_with_context() as engine: + engine.execute("DROP TABLE test_table") @pytest.fixture() @@ -229,6 +172,19 @@ def create_report_email_chart(): cleanup_report_schedule(report_schedule) +@pytest.fixture() +def create_report_email_chart_alpha_owner(get_user): + with app.app_context(): + owners = [get_user("alpha")] + chart = db.session.query(Slice).first() + report_schedule = create_report_notification( + email_target="target@email.com", chart=chart, owners=owners + ) + yield report_schedule + + cleanup_report_schedule(report_schedule) + + @pytest.fixture() def create_report_email_chart_force_screenshot(): with app.app_context(): @@ -308,23 +264,6 @@ def create_report_email_dashboard_force_screenshot(): cleanup_report_schedule(report_schedule) -@pytest.fixture() -def create_report_email_tabbed_dashboard(tabbed_dashboard): - with app.app_context(): - report_schedule = create_report_notification( - email_target="target@email.com", - dashboard=tabbed_dashboard, - extra={ - "dashboard_tab_ids": [ - "TAB-j53G4gtKGF", - "TAB-nerWR09Ju", - ] - }, - ) - yield report_schedule - cleanup_report_schedule(report_schedule) - - @pytest.fixture() def create_report_slack_chart(): with app.app_context(): @@ -724,11 +663,64 @@ def test_email_chart_report_schedule( ) # assert that the link sent is correct assert ( - '<a href="http://0.0.0.0:8080/superset/explore/?' - "form_data=%7B%22slice_id%22%3A%20" - f"{create_report_email_chart.chart.id}%7D&" - 'standalone=0&force=false">Explore in Superset</a>' - in email_mock.call_args[0][2] + '<a href="http://0.0.0.0:8080/explore/?form_data=%7B%22slice_id%22%3A+' + f"{create_report_email_chart.chart.id}" + '%7D&force=false">Explore in Superset</a>' in email_mock.call_args[0][2] + ) + # Assert the email smtp address + assert email_mock.call_args[0][0] == notification_targets[0] + # Assert the email inline screenshot + smtp_images = email_mock.call_args[1]["images"] + assert smtp_images[list(smtp_images.keys())[0]] == SCREENSHOT_FILE + # Assert logs are correct + assert_log(ReportState.SUCCESS) + + +@pytest.mark.usefixtures( + "load_birth_names_dashboard_with_slices", "create_report_email_chart_alpha_owner" +) +@patch("superset.reports.notifications.email.send_email_smtp") +@patch("superset.utils.screenshots.ChartScreenshot.get_screenshot") +def test_email_chart_report_schedule_alpha_owner( + screenshot_mock, + email_mock, + create_report_email_chart_alpha_owner, +): + """ + ExecuteReport Command: Test chart email report schedule with screenshot + executed as the chart owner + """ + config_key = "ALERT_REPORTS_EXECUTE_AS" + original_config_value = app.config[config_key] + app.config[config_key] = [ExecutorType.OWNER] + + # setup screenshot mock + username = "" + + def _screenshot_side_effect(user: User) -> Optional[bytes]: + nonlocal username + username = user.username + + return SCREENSHOT_FILE + + screenshot_mock.side_effect = _screenshot_side_effect + + with freeze_time("2020-01-01T00:00:00Z"): + AsyncExecuteReportScheduleCommand( + TEST_ID, create_report_email_chart_alpha_owner.id, datetime.utcnow() + ).run() + + notification_targets = get_target_from_report_schedule( + create_report_email_chart_alpha_owner + ) + # assert that the screenshot is executed as the chart owner + assert username == "alpha" + + # assert that the link sent is correct + assert ( + '<a href="http://0.0.0.0:8080/explore/?form_data=%7B%22slice_id%22%3A+' + f"{create_report_email_chart_alpha_owner.chart.id}" + '%7D&force=false">Explore in Superset</a>' in email_mock.call_args[0][2] ) # Assert the email smtp address assert email_mock.call_args[0][0] == notification_targets[0] @@ -738,6 +730,8 @@ def test_email_chart_report_schedule( # Assert logs are correct assert_log(ReportState.SUCCESS) + app.config[config_key] = original_config_value + @pytest.mark.usefixtures( "load_birth_names_dashboard_with_slices", @@ -769,11 +763,9 @@ def test_email_chart_report_schedule_force_screenshot( ) # assert that the link sent is correct assert ( - '<a href="http://0.0.0.0:8080/superset/explore/?' - "form_data=%7B%22slice_id%22%3A%20" - f"{create_report_email_chart_force_screenshot.chart.id}%7D&" - 'standalone=0&force=true">Explore in Superset</a>' - in email_mock.call_args[0][2] + '<a href="http://0.0.0.0:8080/explore/?form_data=%7B%22slice_id%22%3A+' + f"{create_report_email_chart_force_screenshot.chart.id}" + '%7D&force=true">Explore in Superset</a>' in email_mock.call_args[0][2] ) # Assert the email smtp address assert email_mock.call_args[0][0] == notification_targets[0] @@ -808,11 +800,9 @@ def test_email_chart_alert_schedule( notification_targets = get_target_from_report_schedule(create_alert_email_chart) # assert that the link sent is correct assert ( - '<a href="http://0.0.0.0:8080/superset/explore/?' - "form_data=%7B%22slice_id%22%3A%20" - f"{create_alert_email_chart.chart.id}%7D&" - 'standalone=0&force=true">Explore in Superset</a>' - in email_mock.call_args[0][2] + '<a href="http://0.0.0.0:8080/explore/?form_data=%7B%22slice_id%22%3A+' + f"{create_alert_email_chart.chart.id}" + '%7D&force=true">Explore in Superset</a>' in email_mock.call_args[0][2] ) # Assert the email smtp address assert email_mock.call_args[0][0] == notification_targets[0] @@ -882,11 +872,9 @@ def test_email_chart_report_schedule_with_csv( ) # assert that the link sent is correct assert ( - '<a href="http://0.0.0.0:8080/superset/explore/?' - "form_data=%7B%22slice_id%22%3A%20" + '<a href="http://0.0.0.0:8080/explore/?form_data=%7B%22slice_id%22%3A+' f"{create_report_email_chart_with_csv.chart.id}%7D&" - 'standalone=0&force=false">Explore in Superset</a>' - in email_mock.call_args[0][2] + 'force=false">Explore in Superset</a>' in email_mock.call_args[0][2] ) # Assert the email smtp address assert email_mock.call_args[0][0] == notification_targets[0] @@ -960,6 +948,8 @@ def test_email_chart_report_schedule_with_text( mock_open.return_value = response mock_urlopen.return_value = response mock_urlopen.return_value.getcode.return_value = 200 + + # test without date type. response.read.return_value = json.dumps( { "result": [ @@ -971,6 +961,7 @@ def test_email_chart_report_schedule_with_text( }, "colnames": [("t1",), ("t2",), ("t3__sum",)], "indexnames": [(0,), (1,)], + "coltypes": [1, 1], }, ], } @@ -1011,6 +1002,59 @@ def test_email_chart_report_schedule_with_text( # Assert logs are correct assert_log(ReportState.SUCCESS) + # test with date type. + dt = datetime(2022, 1, 1).replace(tzinfo=timezone.utc) + ts = datetime.timestamp(dt) * 1000 + response.read.return_value = json.dumps( + { + "result": [ + { + "data": { + "t1": {0: "c11", 1: "c21"}, + "t2__date": {0: ts, 1: ts}, + "t3__sum": {0: "c13", 1: "c23"}, + }, + "colnames": [("t1",), ("t2__date",), ("t3__sum",)], + "indexnames": [(0,), (1,)], + "coltypes": [1, 2], + }, + ], + } + ).encode("utf-8") + + with freeze_time("2020-01-01T00:00:00Z"): + AsyncExecuteReportScheduleCommand( + TEST_ID, create_report_email_chart_with_text.id, datetime.utcnow() + ).run() + + # assert that the data is embedded correctly + table_html = """<table border="1" class="dataframe"> + <thead> + <tr> + <th></th> + <th>t1</th> + <th>t2__date</th> + <th>t3__sum</th> + </tr> + </thead> + <tbody> + <tr> + <th>0</th> + <td>c11</td> + <td>2022-01-01</td> + <td>c13</td> + </tr> + <tr> + <th>1</th> + <td>c21</td> + <td>2022-01-01</td> + <td>c23</td> + </tr> + </tbody> +</table>""" + + assert table_html in email_mock.call_args[0][2] + @pytest.mark.usefixtures( "load_birth_names_dashboard_with_slices", "create_report_email_dashboard" @@ -1116,6 +1160,61 @@ def test_slack_chart_report_schedule( statsd_mock.assert_called_once_with("reports.slack.send.ok", 1) +@pytest.mark.usefixtures( + "load_birth_names_dashboard_with_slices", "create_report_slack_chart" +) +@patch("superset.reports.notifications.slack.WebClient") +@patch("superset.utils.screenshots.ChartScreenshot.get_screenshot") +def test_slack_chart_report_schedule_with_errors( + screenshot_mock, + web_client_mock, + create_report_slack_chart, +): + """ + ExecuteReport Command: Test that all slack errors will + properly log something + """ + # setup screenshot mock + screenshot_mock.return_value = SCREENSHOT_FILE + + slack_errors = [ + BotUserAccessError(), + SlackRequestError(), + SlackClientConfigurationError(), + SlackObjectFormationError(), + SlackTokenRotationError(api_error="foo"), + SlackClientNotConnectedError(), + SlackClientError(), + SlackApiError(message="foo", response="bar"), + ] + + for idx, er in enumerate(slack_errors): + web_client_mock.side_effect = er + + with pytest.raises(ReportScheduleClientErrorsException): + + AsyncExecuteReportScheduleCommand( + TEST_ID, create_report_slack_chart.id, datetime.utcnow() + ).run() + + db.session.commit() + + # Assert errors are being logged + + # Only one notification log is sent because it's in grace period + # for the rest of the reports + notification_logs_count = get_notification_error_sent_count( + create_report_slack_chart + ) + error_logs = get_error_logs_query(create_report_slack_chart) + + # check that we have two logs for each error + assert error_logs.count() == (len(slack_errors) + notification_logs_count) * 2 + + # check that each error has a message + assert len([log.error_message for log in error_logs]) == error_logs.count() + + @pytest.mark.usefixtures( "load_birth_names_dashboard_with_slices", "create_report_slack_chart_with_csv" ) @@ -1204,7 +1303,7 @@ def test_slack_chart_report_schedule_with_text( | 1 | c21 | c22 | c23 |""" assert table_markdown in post_message_mock.call_args[1]["text"] assert ( - f"<http://0.0.0.0:8080/superset/explore/?form_data=%7B%22slice_id%22%3A%20{create_report_slack_chart_with_text.chart.id}%7D&standalone=0&force=false|Explore in Superset>" + f"<http://0.0.0.0:8080/explore/?form_data=%7B%22slice_id%22%3A+{create_report_slack_chart_with_text.chart.id}%7D&force=false|Explore in Superset>" in post_message_mock.call_args[1]["text"] ) @@ -1356,7 +1455,7 @@ def test_email_dashboard_report_fails( screenshot_mock.return_value = SCREENSHOT_FILE email_mock.side_effect = SMTPException("Could not connect to SMTP XPTO") - with pytest.raises(ReportScheduleNotificationError): + with pytest.raises(ReportScheduleSystemErrorsException): AsyncExecuteReportScheduleCommand( TEST_ID, create_report_email_dashboard.id, datetime.utcnow() ).run() @@ -1364,6 +1463,32 @@ def test_email_dashboard_report_fails( assert_log(ReportState.ERROR, error_message="Could not connect to SMTP XPTO") +@pytest.mark.usefixtures( + "load_birth_names_dashboard_with_slices", "create_report_email_dashboard" +) +@patch("superset.reports.notifications.email.send_email_smtp") +@patch("superset.utils.screenshots.DashboardScreenshot.get_screenshot") +def test_email_dashboard_report_fails_uncaught_exception( + screenshot_mock, email_mock, create_report_email_dashboard +): + """ + ExecuteReport Command: Test dashboard email report schedule notification fails + and logs with uncaught exception + """ + # setup screenshot mock + from smtplib import SMTPException + + screenshot_mock.return_value = SCREENSHOT_FILE + email_mock.side_effect = Exception("Uncaught exception") + + with pytest.raises(Exception): + AsyncExecuteReportScheduleCommand( + TEST_ID, create_report_email_dashboard.id, datetime.utcnow() + ).run() + + assert_log(ReportState.ERROR, error_message="Uncaught exception") + + @pytest.mark.usefixtures( "load_birth_names_dashboard_with_slices", "create_alert_email_chart" ) @@ -1503,7 +1628,7 @@ def test_soft_timeout_alert(email_mock, create_alert_email_chart): notification_targets = get_target_from_report_schedule(create_alert_email_chart) # Assert the email smtp address, asserts a notification was sent with the error - assert email_mock.call_args[0][0] == OWNER_EMAIL + assert email_mock.call_args[0][0] == DEFAULT_OWNER_EMAIL assert_log( ReportState.ERROR, error_message="A timeout occurred while executing the query." @@ -1532,7 +1657,7 @@ def test_soft_timeout_screenshot(screenshot_mock, email_mock, create_alert_email ).run() # Assert the email smtp address, asserts a notification was sent with the error - assert email_mock.call_args[0][0] == OWNER_EMAIL + assert email_mock.call_args[0][0] == DEFAULT_OWNER_EMAIL assert_log( ReportState.ERROR, error_message="A timeout occurred while taking a screenshot." @@ -1572,7 +1697,7 @@ def test_soft_timeout_csv( create_report_email_chart_with_csv ) # Assert the email smtp address, asserts a notification was sent with the error - assert email_mock.call_args[0][0] == OWNER_EMAIL + assert email_mock.call_args[0][0] == DEFAULT_OWNER_EMAIL assert_log( ReportState.ERROR, @@ -1612,7 +1737,7 @@ def test_generate_no_csv( create_report_email_chart_with_csv ) # Assert the email smtp address, asserts a notification was sent with the error - assert email_mock.call_args[0][0] == OWNER_EMAIL + assert email_mock.call_args[0][0] == DEFAULT_OWNER_EMAIL assert_log( ReportState.ERROR, @@ -1641,7 +1766,7 @@ def test_fail_screenshot(screenshot_mock, email_mock, create_report_email_chart) notification_targets = get_target_from_report_schedule(create_report_email_chart) # Assert the email smtp address, asserts a notification was sent with the error - assert email_mock.call_args[0][0] == OWNER_EMAIL + assert email_mock.call_args[0][0] == DEFAULT_OWNER_EMAIL assert_log( ReportState.ERROR, error_message="Failed taking a screenshot Unexpected error" @@ -1674,7 +1799,7 @@ def test_fail_csv( get_target_from_report_schedule(create_report_email_chart_with_csv) # Assert the email smtp address, asserts a notification was sent with the error - assert email_mock.call_args[0][0] == OWNER_EMAIL + assert email_mock.call_args[0][0] == DEFAULT_OWNER_EMAIL assert_log( ReportState.ERROR, error_message="Failed generating csv <urlopen error 500>" @@ -1719,11 +1844,9 @@ def test_invalid_sql_alert(email_mock, create_invalid_sql_alert_email_chart): TEST_ID, create_invalid_sql_alert_email_chart.id, datetime.utcnow() ).run() - notification_targets = get_target_from_report_schedule( - create_invalid_sql_alert_email_chart - ) # Assert the email smtp address, asserts a notification was sent with the error - assert email_mock.call_args[0][0] == OWNER_EMAIL + assert email_mock.call_args[0][0] == DEFAULT_OWNER_EMAIL + assert_log(ReportState.ERROR) @pytest.mark.usefixtures("create_invalid_sql_alert_email_chart") @@ -1740,11 +1863,9 @@ def test_grace_period_error(email_mock, create_invalid_sql_alert_email_chart): # Only needed for MySQL, understand why db.session.commit() - notification_targets = get_target_from_report_schedule( - create_invalid_sql_alert_email_chart - ) + # Assert the email smtp address, asserts a notification was sent with the error - assert email_mock.call_args[0][0] == OWNER_EMAIL + assert email_mock.call_args[0][0] == DEFAULT_OWNER_EMAIL assert ( get_notification_error_sent_count(create_invalid_sql_alert_email_chart) == 1 ) @@ -1844,8 +1965,6 @@ def test_grace_period_error_flap( ) @patch("superset.reports.dao.ReportScheduleDAO.bulk_delete_logs") def test_prune_log_soft_time_out(bulk_delete_logs, create_report_email_dashboard): - from datetime import datetime, timedelta - from celery.exceptions import SoftTimeLimitExceeded bulk_delete_logs.side_effect = SoftTimeLimitExceeded() @@ -1854,31 +1973,64 @@ def test_prune_log_soft_time_out(bulk_delete_logs, create_report_email_dashboard assert str(excinfo.value) == "SoftTimeLimitExceeded()" -@pytest.mark.usefixtures( - "create_report_email_tabbed_dashboard", -) -@patch("superset.reports.notifications.email.send_email_smtp") -@patch( - "superset.reports.commands.execute.DashboardScreenshot", -) -def test_when_tabs_are_selected_it_takes_screenshots_for_every_tabs( - dashboard_screenshot_mock, - send_email_smtp_mock, - create_report_email_tabbed_dashboard, -): - dashboard_screenshot_mock.get_screenshot.return_value = b"test-image" - dashboard = create_report_email_tabbed_dashboard.dashboard +@patch("superset.reports.commands.execute.logger") +@patch("superset.reports.commands.execute.create_notification") +def test__send_with_client_errors(notification_mock, logger_mock): + notification_content = "I am some content" + recipients = ["test@foo.com"] + notification_mock.return_value.send.side_effect = NotificationParamException() + with pytest.raises(ReportScheduleClientErrorsException) as excinfo: + BaseReportState._send(BaseReportState, notification_content, recipients) + + assert excinfo.errisinstance(SupersetException) + logger_mock.warning.assert_called_with( + ( + "SupersetError(message='', error_type=<SupersetErrorType.REPORT_NOTIFICATION_ERROR: 'REPORT_NOTIFICATION_ERROR'>, level=<ErrorLevel.WARNING: 'warning'>, extra=None)" + ) + ) - AsyncExecuteReportScheduleCommand( - TEST_ID, create_report_email_tabbed_dashboard.id, datetime.utcnow() - ).run() - tabs = json.loads(create_report_email_tabbed_dashboard.extra)["dashboard_tab_ids"] - assert dashboard_screenshot_mock.call_count == 2 - for index, tab in enumerate(tabs): - assert dashboard_screenshot_mock.call_args_list[index].args == ( - f"http://0.0.0.0:8081/superset/dashboard/{dashboard.id}/?standalone=3&force=false#{tab}", - f"{dashboard.digest}", +@patch("superset.reports.commands.execute.logger") +@patch("superset.reports.commands.execute.create_notification") +def test__send_with_multiple_errors(notification_mock, logger_mock): + notification_content = "I am some content" + recipients = ["test@foo.com", "test2@bar.com"] + notification_mock.return_value.send.side_effect = [ + NotificationParamException(), + NotificationError(), + ] + # it raises the error with a 500 status if present + with pytest.raises(ReportScheduleSystemErrorsException) as excinfo: + BaseReportState._send(BaseReportState, notification_content, recipients) + + assert excinfo.errisinstance(SupersetException) + # it logs both errors as warnings + logger_mock.warning.assert_has_calls( + [ + call( + "SupersetError(message='', error_type=<SupersetErrorType.REPORT_NOTIFICATION_ERROR: 'REPORT_NOTIFICATION_ERROR'>, level=<ErrorLevel.WARNING: 'warning'>, extra=None)" + ), + call( + "SupersetError(message='', error_type=<SupersetErrorType.REPORT_NOTIFICATION_ERROR: 'REPORT_NOTIFICATION_ERROR'>, level=<ErrorLevel.ERROR: 'error'>, extra=None)" + ), + ] + ) + + +@patch("superset.reports.commands.execute.logger") +@patch("superset.reports.commands.execute.create_notification") +def test__send_with_server_errors(notification_mock, logger_mock): + + notification_content = "I am some content" + recipients = ["test@foo.com"] + notification_mock.return_value.send.side_effect = NotificationError() + with pytest.raises(ReportScheduleSystemErrorsException) as excinfo: + BaseReportState._send(BaseReportState, notification_content, recipients) + + assert excinfo.errisinstance(SupersetException) + # it logs the error + logger_mock.warning.assert_called_with( + ( + "SupersetError(message='', error_type=<SupersetErrorType.REPORT_NOTIFICATION_ERROR: 'REPORT_NOTIFICATION_ERROR'>, level=<ErrorLevel.ERROR: 'error'>, extra=None)" ) - assert send_email_smtp_mock.called is True - assert len(send_email_smtp_mock.call_args.kwargs["images"]) == 2 + ) diff --git a/tests/integration_tests/reports/scheduler_tests.py b/tests/integration_tests/reports/scheduler_tests.py index 77894a6d2ef3c..3dd6e72941e2e 100644 --- a/tests/integration_tests/reports/scheduler_tests.py +++ b/tests/integration_tests/reports/scheduler_tests.py @@ -14,22 +14,31 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. + +from random import randint from typing import List from unittest.mock import patch import pytest +from flask_appbuilder.security.sqla.models import User from freezegun import freeze_time from freezegun.api import FakeDatetime # type: ignore from superset.extensions import db -from superset.models.reports import ReportScheduleType -from superset.tasks.scheduler import scheduler +from superset.reports.models import ReportScheduleType +from superset.tasks.scheduler import execute, scheduler from tests.integration_tests.reports.utils import insert_report_schedule from tests.integration_tests.test_app import app +@pytest.fixture +def owners(get_user) -> List[User]: + return [get_user("admin")] + + +@pytest.mark.usefixtures("owners") @patch("superset.tasks.scheduler.execute.apply_async") -def test_scheduler_celery_timeout_ny(execute_mock): +def test_scheduler_celery_timeout_ny(execute_mock, owners): """ Reports scheduler: Test scheduler setting celery soft and hard timeout """ @@ -40,6 +49,7 @@ def test_scheduler_celery_timeout_ny(execute_mock): name="report", crontab="0 4 * * *", timezone="America/New_York", + owners=owners, ) with freeze_time("2020-01-01T09:00:00Z"): @@ -50,8 +60,9 @@ def test_scheduler_celery_timeout_ny(execute_mock): db.session.commit() +@pytest.mark.usefixtures("owners") @patch("superset.tasks.scheduler.execute.apply_async") -def test_scheduler_celery_no_timeout_ny(execute_mock): +def test_scheduler_celery_no_timeout_ny(execute_mock, owners): """ Reports scheduler: Test scheduler setting celery soft and hard timeout """ @@ -62,6 +73,7 @@ def test_scheduler_celery_no_timeout_ny(execute_mock): name="report", crontab="0 4 * * *", timezone="America/New_York", + owners=owners, ) with freeze_time("2020-01-01T09:00:00Z"): @@ -72,8 +84,9 @@ def test_scheduler_celery_no_timeout_ny(execute_mock): app.config["ALERT_REPORTS_WORKING_TIME_OUT_KILL"] = True +@pytest.mark.usefixtures("owners") @patch("superset.tasks.scheduler.execute.apply_async") -def test_scheduler_celery_timeout_utc(execute_mock): +def test_scheduler_celery_timeout_utc(execute_mock, owners): """ Reports scheduler: Test scheduler setting celery soft and hard timeout """ @@ -84,19 +97,20 @@ def test_scheduler_celery_timeout_utc(execute_mock): name="report", crontab="0 9 * * *", timezone="UTC", + owners=owners, ) with freeze_time("2020-01-01T09:00:00Z"): scheduler() - print(execute_mock.call_args) assert execute_mock.call_args[1]["soft_time_limit"] == 3601 assert execute_mock.call_args[1]["time_limit"] == 3610 db.session.delete(report_schedule) db.session.commit() +@pytest.mark.usefixtures("owners") @patch("superset.tasks.scheduler.execute.apply_async") -def test_scheduler_celery_no_timeout_utc(execute_mock): +def test_scheduler_celery_no_timeout_utc(execute_mock, owners): """ Reports scheduler: Test scheduler setting celery soft and hard timeout """ @@ -107,6 +121,7 @@ def test_scheduler_celery_no_timeout_utc(execute_mock): name="report", crontab="0 9 * * *", timezone="UTC", + owners=owners, ) with freeze_time("2020-01-01T09:00:00Z"): @@ -117,9 +132,10 @@ def test_scheduler_celery_no_timeout_utc(execute_mock): app.config["ALERT_REPORTS_WORKING_TIME_OUT_KILL"] = True +@pytest.mark.usefixtures("owners") @patch("superset.tasks.scheduler.is_feature_enabled") @patch("superset.tasks.scheduler.execute.apply_async") -def test_scheduler_feature_flag_off(execute_mock, is_feature_enabled): +def test_scheduler_feature_flag_off(execute_mock, is_feature_enabled, owners): """ Reports scheduler: Test scheduler with feature flag off """ @@ -130,6 +146,7 @@ def test_scheduler_feature_flag_off(execute_mock, is_feature_enabled): name="report", crontab="0 9 * * *", timezone="UTC", + owners=owners, ) with freeze_time("2020-01-01T09:00:00Z"): @@ -137,3 +154,60 @@ def test_scheduler_feature_flag_off(execute_mock, is_feature_enabled): execute_mock.assert_not_called() db.session.delete(report_schedule) db.session.commit() + + +@pytest.mark.usefixtures("owners") +@patch("superset.reports.commands.execute.AsyncExecuteReportScheduleCommand.__init__") +@patch("superset.reports.commands.execute.AsyncExecuteReportScheduleCommand.run") +@patch("superset.tasks.scheduler.execute.update_state") +def test_execute_task(update_state_mock, command_mock, init_mock, owners): + from superset.reports.commands.exceptions import ReportScheduleUnexpectedError + + with app.app_context(): + report_schedule = insert_report_schedule( + type=ReportScheduleType.ALERT, + name=f"report-{randint(0,1000)}", + crontab="0 4 * * *", + timezone="America/New_York", + owners=owners, + ) + init_mock.return_value = None + command_mock.side_effect = ReportScheduleUnexpectedError("Unexpected error") + with freeze_time("2020-01-01T09:00:00Z"): + execute(report_schedule.id, "2020-01-01T09:00:00Z") + update_state_mock.assert_called_with(state="FAILURE") + + db.session.delete(report_schedule) + db.session.commit() + + +@pytest.mark.usefixtures("owners") +@patch("superset.reports.commands.execute.AsyncExecuteReportScheduleCommand.__init__") +@patch("superset.reports.commands.execute.AsyncExecuteReportScheduleCommand.run") +@patch("superset.tasks.scheduler.execute.update_state") +@patch("superset.utils.log.logger") +def test_execute_task_with_command_exception( + logger_mock, update_state_mock, command_mock, init_mock, owners +): + from superset.commands.exceptions import CommandException + + with app.app_context(): + report_schedule = insert_report_schedule( + type=ReportScheduleType.ALERT, + name=f"report-{randint(0,1000)}", + crontab="0 4 * * *", + timezone="America/New_York", + owners=owners, + ) + init_mock.return_value = None + command_mock.side_effect = CommandException("Unexpected error") + with freeze_time("2020-01-01T09:00:00Z"): + execute(report_schedule.id, "2020-01-01T09:00:00Z") + update_state_mock.assert_called_with(state="FAILURE") + logger_mock.exception.assert_called_with( + "A downstream exception occurred while generating a report: None. Unexpected error", + exc_info=True, + ) + + db.session.delete(report_schedule) + db.session.commit() diff --git a/tests/integration_tests/reports/utils.py b/tests/integration_tests/reports/utils.py index 1f04f07988607..3801beb1a328e 100644 --- a/tests/integration_tests/reports/utils.py +++ b/tests/integration_tests/reports/utils.py @@ -15,34 +15,47 @@ # specific language governing permissions and limitations # under the License. +import json +from contextlib import contextmanager from typing import Any, Dict, List, Optional +from uuid import uuid4 from flask_appbuilder.security.sqla.models import User -from superset import db +from superset import db, security_manager from superset.models.core import Database from superset.models.dashboard import Dashboard -from superset.models.reports import ( +from superset.models.slice import Slice +from superset.reports.models import ( ReportDataFormat, ReportExecutionLog, ReportRecipients, + ReportRecipientType, ReportSchedule, + ReportScheduleType, ReportState, ) -from superset.models.slice import Slice +from superset.utils.core import override_user +from tests.integration_tests.test_app import app +from tests.integration_tests.utils import read_fixture + +TEST_ID = str(uuid4()) +CSV_FILE = read_fixture("trends.csv") +SCREENSHOT_FILE = read_fixture("sample.png") +DEFAULT_OWNER_EMAIL = "admin@fab.org" def insert_report_schedule( type: str, name: str, crontab: str, + owners: List[User], timezone: Optional[str] = None, sql: Optional[str] = None, description: Optional[str] = None, chart: Optional[Slice] = None, dashboard: Optional[Dashboard] = None, database: Optional[Database] = None, - owners: Optional[List[User]] = None, validator_type: Optional[str] = None, validator_config_json: Optional[str] = None, log_retention: Optional[int] = None, @@ -58,28 +71,131 @@ def insert_report_schedule( recipients = recipients or [] logs = logs or [] last_state = last_state or ReportState.NOOP - report_schedule = ReportSchedule( - type=type, + + with override_user(owners[0]): + report_schedule = ReportSchedule( + type=type, + name=name, + crontab=crontab, + timezone=timezone, + sql=sql, + description=description, + chart=chart, + dashboard=dashboard, + database=database, + owners=owners, + validator_type=validator_type, + validator_config_json=validator_config_json, + log_retention=log_retention, + grace_period=grace_period, + recipients=recipients, + logs=logs, + last_state=last_state, + report_format=report_format, + extra=extra, + force_screenshot=force_screenshot, + ) + db.session.add(report_schedule) + db.session.commit() + return report_schedule + + +def create_report_notification( + email_target: Optional[str] = None, + slack_channel: Optional[str] = None, + chart: Optional[Slice] = None, + dashboard: Optional[Dashboard] = None, + database: Optional[Database] = None, + sql: Optional[str] = None, + report_type: ReportScheduleType = ReportScheduleType.REPORT, + validator_type: Optional[str] = None, + validator_config_json: Optional[str] = None, + grace_period: Optional[int] = None, + report_format: Optional[ReportDataFormat] = None, + name: Optional[str] = None, + extra: Optional[Dict[str, Any]] = None, + force_screenshot: bool = False, + owners: Optional[List[User]] = None, +) -> ReportSchedule: + if not owners: + owners = [ + ( + db.session.query(security_manager.user_model) + .filter_by(email=DEFAULT_OWNER_EMAIL) + .one_or_none() + ) + ] + + if slack_channel: + recipient = ReportRecipients( + type=ReportRecipientType.SLACK, + recipient_config_json=json.dumps( + { + "target": slack_channel, + } + ), + ) + else: + recipient = ReportRecipients( + type=ReportRecipientType.EMAIL, + recipient_config_json=json.dumps({"target": email_target}), + ) + + if name is None: + name = "report_with_csv" if report_format else "report" + + report_schedule = insert_report_schedule( + report_type, name=name, - crontab=crontab, - timezone=timezone, + crontab="0 9 * * *", + description="Daily report", sql=sql, - description=description, chart=chart, dashboard=dashboard, database=database, + recipients=[recipient], owners=owners, validator_type=validator_type, validator_config_json=validator_config_json, - log_retention=log_retention, grace_period=grace_period, - recipients=recipients, - logs=logs, - last_state=last_state, - report_format=report_format, + report_format=report_format or ReportDataFormat.VISUALIZATION, extra=extra, force_screenshot=force_screenshot, ) - db.session.add(report_schedule) - db.session.commit() return report_schedule + + +def cleanup_report_schedule(report_schedule: ReportSchedule) -> None: + db.session.query(ReportExecutionLog).filter( + ReportExecutionLog.report_schedule == report_schedule + ).delete() + db.session.query(ReportRecipients).filter( + ReportRecipients.report_schedule == report_schedule + ).delete() + + db.session.delete(report_schedule) + db.session.commit() + + +@contextmanager +def create_dashboard_report(dashboard, extra, **kwargs): + report_schedule = create_report_notification( + email_target="target@example.com", + dashboard=dashboard, + extra={ + "dashboard": extra, + }, + **kwargs + ) + error = None + + try: + yield report_schedule + except Exception as ex: # pylint: disable=broad-except + error = ex + + # make sure to clean up in case of yield exceptions + cleanup_report_schedule(report_schedule) + + if error: + raise error diff --git a/tests/integration_tests/result_set_tests.py b/tests/integration_tests/result_set_tests.py index 626468fc5aae0..18135c486dbea 100644 --- a/tests/integration_tests/result_set_tests.py +++ b/tests/integration_tests/result_set_tests.py @@ -169,13 +169,13 @@ def test_nested_types(self): "id": 4, "dict_arr": '[{"table_name": "unicode_test", "database_id": 1}]', "num_arr": "[1, 2, 3]", - "map_col": '{"chart_name": "scatter"}', + "map_col": "{'chart_name': 'scatter'}", }, { "id": 3, "dict_arr": '[{"table_name": "birth_names", "database_id": 1}]', "num_arr": "[4, 5, 6]", - "map_col": '{"chart_name": "plot"}', + "map_col": "{'chart_name': 'plot'}", }, ], ) diff --git a/tests/integration_tests/security/migrate_roles_tests.py b/tests/integration_tests/security/migrate_roles_tests.py index ad8d01691a599..a541f00952773 100644 --- a/tests/integration_tests/security/migrate_roles_tests.py +++ b/tests/integration_tests/security/migrate_roles_tests.py @@ -76,7 +76,7 @@ def create_old_role(pvm_map: PvmMigrationMapType, external_pvms): @pytest.mark.parametrize( - "descriptiom, new_pvms, pvm_map, external_pvms, deleted_views, deleted_permissions", + "description, new_pvms, pvm_map, external_pvms, deleted_views, deleted_permissions", [ ( "Many to one readonly", @@ -178,7 +178,7 @@ def create_old_role(pvm_map: PvmMigrationMapType, external_pvms): (), ), ( - "Many to one with with old permission that gets deleted", + "Many to one with old permission that gets deleted", { "NewDummy": ( "can_read", @@ -239,12 +239,12 @@ def create_old_role(pvm_map: PvmMigrationMapType, external_pvms): ], ) def test_migrate_role( - descriptiom, new_pvms, pvm_map, external_pvms, deleted_views, deleted_permissions + description, new_pvms, pvm_map, external_pvms, deleted_views, deleted_permissions ): """ Permission migration: generic tests """ - logger.info(descriptiom) + logger.info(description) with create_old_role(pvm_map, external_pvms) as old_role: role_name = old_role.name session = db.session diff --git a/tests/integration_tests/security/row_level_security_tests.py b/tests/integration_tests/security/row_level_security_tests.py index 1e46bfb996c5b..ebd95cae39bd7 100644 --- a/tests/integration_tests/security/row_level_security_tests.py +++ b/tests/integration_tests/security/row_level_security_tests.py @@ -25,7 +25,6 @@ from superset import db, security_manager from superset.connectors.sqla.models import RowLevelSecurityFilter, SqlaTable from superset.security.guest_token import ( - GuestTokenRlsRule, GuestTokenResourceType, GuestUser, ) @@ -82,6 +81,7 @@ def setUp(self): # Create regular RowLevelSecurityFilter (energy_usage, unicode_test) self.rls_entry1 = RowLevelSecurityFilter() + self.rls_entry1.name = "rls_entry1" self.rls_entry1.tables.extend( session.query(SqlaTable) .filter(SqlaTable.table_name.in_(["energy_usage", "unicode_test"])) @@ -96,6 +96,7 @@ def setUp(self): # Create regular RowLevelSecurityFilter (birth_names name starts with A or B) self.rls_entry2 = RowLevelSecurityFilter() + self.rls_entry2.name = "rls_entry2" self.rls_entry2.tables.extend( session.query(SqlaTable) .filter(SqlaTable.table_name.in_(["birth_names"])) @@ -109,6 +110,7 @@ def setUp(self): # Create Regular RowLevelSecurityFilter (birth_names name starts with Q) self.rls_entry3 = RowLevelSecurityFilter() + self.rls_entry3.name = "rls_entry3" self.rls_entry3.tables.extend( session.query(SqlaTable) .filter(SqlaTable.table_name.in_(["birth_names"])) @@ -122,6 +124,7 @@ def setUp(self): # Create Base RowLevelSecurityFilter (birth_names boys) self.rls_entry4 = RowLevelSecurityFilter() + self.rls_entry4.name = "rls_entry4" self.rls_entry4.tables.extend( session.query(SqlaTable) .filter(SqlaTable.table_name.in_(["birth_names"])) @@ -146,6 +149,94 @@ def tearDown(self): session.delete(self.get_user("NoRlsRoleUser")) session.commit() + @pytest.fixture() + def create_dataset(self): + with self.create_app().app_context(): + + dataset = SqlaTable(database_id=1, schema=None, table_name="table1") + db.session.add(dataset) + db.session.flush() + db.session.commit() + + yield dataset + + # rollback changes (assuming cascade delete) + db.session.delete(dataset) + db.session.commit() + + def _get_test_dataset(self): + return ( + db.session.query(SqlaTable).filter(SqlaTable.table_name == "table1") + ).one_or_none() + + @pytest.mark.usefixtures("create_dataset") + def test_model_view_rls_add_success(self): + self.login(username="admin") + test_dataset = self._get_test_dataset() + rv = self.client.post( + "/rowlevelsecurityfiltersmodelview/add", + data=dict( + name="rls1", + description="Some description", + filter_type="Regular", + tables=[test_dataset.id], + roles=[security_manager.find_role("Alpha").id], + group_key="group_key_1", + clause="client_id=1", + ), + follow_redirects=True, + ) + self.assertEqual(rv.status_code, 200) + rls1 = ( + db.session.query(RowLevelSecurityFilter).filter_by(name="rls1") + ).one_or_none() + assert rls1 is not None + + # Revert data changes + db.session.delete(rls1) + db.session.commit() + + @pytest.mark.usefixtures("create_dataset") + def test_model_view_rls_add_name_unique(self): + self.login(username="admin") + test_dataset = self._get_test_dataset() + rv = self.client.post( + "/rowlevelsecurityfiltersmodelview/add", + data=dict( + name="rls_entry1", + description="Some description", + filter_type="Regular", + tables=[test_dataset.id], + roles=[security_manager.find_role("Alpha").id], + group_key="group_key_1", + clause="client_id=1", + ), + follow_redirects=True, + ) + self.assertEqual(rv.status_code, 200) + data = rv.data.decode("utf-8") + assert "Already exists." in data + + @pytest.mark.usefixtures("create_dataset") + def test_model_view_rls_add_tables_required(self): + self.login(username="admin") + rv = self.client.post( + "/rowlevelsecurityfiltersmodelview/add", + data=dict( + name="rls1", + description="Some description", + filter_type="Regular", + tables=[], + roles=[security_manager.find_role("Alpha").id], + group_key="group_key_1", + clause="client_id=1", + ), + follow_redirects=True, + ) + self.assertEqual(rv.status_code, 200) + data = rv.data.decode("utf-8") + assert "This field is required." in data + @pytest.mark.usefixtures("load_energy_table_with_slice") def test_rls_filter_alters_energy_query(self): g.user = self.get_user(username="alpha") diff --git a/tests/integration_tests/security_tests.py b/tests/integration_tests/security_tests.py index 9de83f665a9f5..6ee6bc6524c59 100644 --- a/tests/integration_tests/security_tests.py +++ b/tests/integration_tests/security_tests.py @@ -20,7 +20,7 @@ import unittest from collections import namedtuple from unittest import mock -from unittest.mock import Mock, patch +from unittest.mock import Mock, patch, call, ANY from typing import Any import jwt @@ -28,10 +28,10 @@ import pytest from flask import current_app - +from flask_appbuilder.security.sqla.models import Role +from superset.datasource.dao import DatasourceDAO from superset.models.dashboard import Dashboard - -from superset import app, appbuilder, db, security_manager, viz, ConnectorRegistry +from superset import app, appbuilder, db, security_manager, viz from superset.connectors.sqla.models import SqlaTable from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import SupersetSecurityException @@ -155,12 +155,92 @@ def tearDown(self): session.delete(security_manager.find_role(SCHEMA_ACCESS_ROLE)) session.commit() - def test_set_perm_sqla_table(self): + def test_after_insert_dataset(self): + security_manager.on_view_menu_after_insert = Mock() + security_manager.on_permission_view_after_insert = Mock() + + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + + table = SqlaTable( + schema="tmp_schema", + table_name="tmp_perm_table", + database=tmp_db1, + ) + session.add(table) + session.commit() + + table = session.query(SqlaTable).filter_by(table_name="tmp_perm_table").one() + self.assertEqual(table.perm, f"[tmp_db1].[tmp_perm_table](id:{table.id})") + + pvm_dataset = security_manager.find_permission_view_menu( + "datasource_access", table.perm + ) + pvm_schema = security_manager.find_permission_view_menu( + "schema_access", table.schema_perm + ) + + # Assert dataset permission is created and local perms are ok + self.assertIsNotNone(pvm_dataset) + self.assertEqual(table.perm, f"[tmp_db1].[tmp_perm_table](id:{table.id})") + self.assertEqual(table.schema_perm, "[tmp_db1].[tmp_schema]") + self.assertIsNotNone(pvm_schema) + + # assert on permission hooks + call_args = security_manager.on_permission_view_after_insert.call_args + assert call_args.args[2].id == pvm_schema.id + + security_manager.on_permission_view_after_insert.assert_has_calls( + [ + call(ANY, ANY, ANY), + call(ANY, ANY, ANY), + ] + ) + + # Cleanup + session.delete(table) + session.delete(tmp_db1) + session.commit() + + def test_after_insert_dataset_rollback(self): + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.commit() + + table = SqlaTable( + schema="tmp_schema", + table_name="tmp_table", + database=tmp_db1, + ) + session.add(table) + session.flush() + + pvm_dataset = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table](id:{table.id})" + ) + self.assertIsNotNone(pvm_dataset) + table_id = table.id + session.rollback() + + table = session.query(SqlaTable).filter_by(table_name="tmp_table").one_or_none() + self.assertIsNone(table) + pvm_dataset = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table](id:{table_id})" + ) + self.assertIsNone(pvm_dataset) + + session.delete(tmp_db1) + session.commit() + + def test_after_insert_dataset_table_none(self): session = db.session table = SqlaTable( schema="tmp_schema", table_name="tmp_perm_table", - database=get_example_database(), + # Setting database_id instead of database will skip permission creation + database_id=get_example_database().id, ) session.add(table) session.commit() @@ -168,168 +248,854 @@ def test_set_perm_sqla_table(self): stored_table = ( session.query(SqlaTable).filter_by(table_name="tmp_perm_table").one() ) - self.assertEqual( - stored_table.perm, f"[examples].[tmp_perm_table](id:{stored_table.id})" - ) + # Assert permission is created self.assertIsNotNone( security_manager.find_permission_view_menu( "datasource_access", stored_table.perm ) ) - self.assertEqual(stored_table.schema_perm, "[examples].[tmp_schema]") - self.assertIsNotNone( + # Assert no bogus permission is created + self.assertIsNone( security_manager.find_permission_view_menu( - "schema_access", stored_table.schema_perm + "datasource_access", f"[None].[tmp_perm_table](id:{stored_table.id})" ) ) - # table name change - stored_table.table_name = "tmp_perm_table_v2" + # Cleanup + session.delete(table) session.commit() - stored_table = ( - session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one() + + def test_after_insert_database(self): + security_manager.on_permission_view_after_insert = Mock() + + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + + tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + self.assertEqual(tmp_db1.perm, f"[tmp_db1].(id:{tmp_db1.id})") + tmp_db1_pvm = security_manager.find_permission_view_menu( + "database_access", tmp_db1.perm ) - self.assertEqual( - stored_table.perm, f"[examples].[tmp_perm_table_v2](id:{stored_table.id})" + self.assertIsNotNone(tmp_db1_pvm) + + # Assert the hook is called + security_manager.on_permission_view_after_insert.assert_has_calls( + [ + call(ANY, ANY, ANY), + ] + ) + call_args = security_manager.on_permission_view_after_insert.call_args + assert call_args.args[2].id == tmp_db1_pvm.id + session.delete(tmp_db1) + session.commit() + + def test_after_insert_database_rollback(self): + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.flush() + + pvm_database = security_manager.find_permission_view_menu( + "database_access", f"[tmp_db1].(id:{tmp_db1.id})" + ) + self.assertIsNotNone(pvm_database) + session.rollback() + + pvm_database = security_manager.find_permission_view_menu( + "database_access", f"[tmp_db1](id:{tmp_db1.id})" ) + self.assertIsNone(pvm_database) + + def test_after_update_database__perm_database_access(self): + security_manager.on_view_menu_after_update = Mock() + + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.commit() + tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + self.assertIsNotNone( + security_manager.find_permission_view_menu("database_access", tmp_db1.perm) + ) + + tmp_db1.database_name = "tmp_db2" + session.commit() + + # Assert that the old permission was updated + self.assertIsNone( security_manager.find_permission_view_menu( - "datasource_access", stored_table.perm + "database_access", f"[tmp_db1].(id:{tmp_db1.id})" ) ) - # no changes in schema - self.assertEqual(stored_table.schema_perm, "[examples].[tmp_schema]") + # Assert that the db permission was updated self.assertIsNotNone( security_manager.find_permission_view_menu( - "schema_access", stored_table.schema_perm + "database_access", f"[tmp_db2].(id:{tmp_db1.id})" ) ) - # schema name change - stored_table.schema = "tmp_schema_v2" - session.commit() - stored_table = ( - session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one() + # Assert the hook is called + tmp_db1_view_menu = security_manager.find_view_menu( + f"[tmp_db2].(id:{tmp_db1.id})" ) - self.assertEqual( - stored_table.perm, f"[examples].[tmp_perm_table_v2](id:{stored_table.id})" + security_manager.on_view_menu_after_update.assert_has_calls( + [ + call(ANY, ANY, tmp_db1_view_menu), + ] ) + + session.delete(tmp_db1) + session.commit() + + def test_after_update_database_rollback(self): + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.commit() + tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + self.assertIsNotNone( + security_manager.find_permission_view_menu("database_access", tmp_db1.perm) + ) + + tmp_db1.database_name = "tmp_db2" + session.flush() + + # Assert that the old permission was updated + self.assertIsNone( security_manager.find_permission_view_menu( - "datasource_access", stored_table.perm + "database_access", f"[tmp_db1].(id:{tmp_db1.id})" ) ) - # no changes in schema - self.assertEqual(stored_table.schema_perm, "[examples].[tmp_schema_v2]") + # Assert that the db permission was updated self.assertIsNotNone( security_manager.find_permission_view_menu( - "schema_access", stored_table.schema_perm + "database_access", f"[tmp_db2].(id:{tmp_db1.id})" ) ) - # database change - new_db = Database(sqlalchemy_uri="sqlite://", database_name="tmp_db") - session.add(new_db) - stored_table.database = ( - session.query(Database).filter_by(database_name="tmp_db").one() - ) - session.commit() - stored_table = ( - session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one() - ) - self.assertEqual( - stored_table.perm, f"[tmp_db].[tmp_perm_table_v2](id:{stored_table.id})" - ) + session.rollback() self.assertIsNotNone( security_manager.find_permission_view_menu( - "datasource_access", stored_table.perm + "database_access", f"[tmp_db1].(id:{tmp_db1.id})" ) ) - # no changes in schema - self.assertEqual(stored_table.schema_perm, "[tmp_db].[tmp_schema_v2]") - self.assertIsNotNone( + # Assert that the db permission was updated + self.assertIsNone( security_manager.find_permission_view_menu( - "schema_access", stored_table.schema_perm + "database_access", f"[tmp_db2].(id:{tmp_db1.id})" ) ) - # no schema - stored_table.schema = None + session.delete(tmp_db1) session.commit() - stored_table = ( - session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one() + + def test_after_update_database__perm_database_access_exists(self): + security_manager.on_permission_view_after_delete = Mock() + + session = db.session + # Add a bogus existing permission before the change + + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.commit() + tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + security_manager.add_permission_view_menu( + "database_access", f"[tmp_db2].(id:{tmp_db1.id})" ) - self.assertEqual( - stored_table.perm, f"[tmp_db].[tmp_perm_table_v2](id:{stored_table.id})" + + self.assertIsNotNone( + security_manager.find_permission_view_menu("database_access", tmp_db1.perm) ) + + tmp_db1.database_name = "tmp_db2" + session.commit() + + # Assert that the old permission was updated + self.assertIsNone( + security_manager.find_permission_view_menu( + "database_access", f"[tmp_db1].(id:{tmp_db1.id})" + ) + ) + # Assert that the db permission was updated self.assertIsNotNone( security_manager.find_permission_view_menu( - "datasource_access", stored_table.perm + "database_access", f"[tmp_db2].(id:{tmp_db1.id})" ) ) - self.assertIsNone(stored_table.schema_perm) - session.delete(new_db) - session.delete(stored_table) + security_manager.on_permission_view_after_delete.assert_has_calls( + [ + call(ANY, ANY, ANY), + ] + ) + + session.delete(tmp_db1) session.commit() - def test_set_perm_sqla_table_none(self): + def test_after_update_database__perm_datasource_access(self): + security_manager.on_view_menu_after_update = Mock() + session = db.session - table = SqlaTable( + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.commit() + + table1 = SqlaTable( schema="tmp_schema", - table_name="tmp_perm_table", - # Setting database_id instead of database will skip permission creation - database_id=get_example_database().id, + table_name="tmp_table1", + database=tmp_db1, ) - session.add(table) + session.add(table1) + table2 = SqlaTable( + schema="tmp_schema", + table_name="tmp_table2", + database=tmp_db1, + ) + session.add(table2) + session.commit() + slice1 = Slice( + datasource_id=table1.id, + datasource_type=DatasourceType.TABLE, + datasource_name="tmp_table1", + slice_name="tmp_slice1", + ) + session.add(slice1) session.commit() + slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one() + table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table2 = session.query(SqlaTable).filter_by(table_name="tmp_table2").one() - stored_table = ( - session.query(SqlaTable).filter_by(table_name="tmp_perm_table").one() + # assert initial perms + self.assertIsNotNone( + security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" + ) ) - # Assert no permission is created + self.assertIsNotNone( + security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table2](id:{table2.id})" + ) + ) + self.assertEqual(slice1.perm, f"[tmp_db1].[tmp_table1](id:{table1.id})") + self.assertEqual(table1.perm, f"[tmp_db1].[tmp_table1](id:{table1.id})") + self.assertEqual(table2.perm, f"[tmp_db1].[tmp_table2](id:{table2.id})") + + # Refresh and update the database name + tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + tmp_db1.database_name = "tmp_db2" + session.commit() + + # Assert that the old permissions were updated self.assertIsNone( security_manager.find_permission_view_menu( - "datasource_access", stored_table.perm + "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" ) ) - # Assert no bogus permission is created self.assertIsNone( security_manager.find_permission_view_menu( - "datasource_access", f"[None].[tmp_perm_table](id:{stored_table.id})" + "datasource_access", f"[tmp_db1].[tmp_table2](id:{table2.id})" ) ) - session.delete(table) + + # Assert that the db permission was updated + self.assertIsNotNone( + security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db2].[tmp_table1](id:{table1.id})" + ) + ) + self.assertIsNotNone( + security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db2].[tmp_table2](id:{table2.id})" + ) + ) + self.assertEqual(slice1.perm, f"[tmp_db2].[tmp_table1](id:{table1.id})") + self.assertEqual(table1.perm, f"[tmp_db2].[tmp_table1](id:{table1.id})") + self.assertEqual(table2.perm, f"[tmp_db2].[tmp_table2](id:{table2.id})") + + # Assert hooks are called + tmp_db1_view_menu = security_manager.find_view_menu( + f"[tmp_db2].(id:{tmp_db1.id})" + ) + table1_view_menu = security_manager.find_view_menu( + f"[tmp_db2].[tmp_table1](id:{table1.id})" + ) + table2_view_menu = security_manager.find_view_menu( + f"[tmp_db2].[tmp_table2](id:{table2.id})" + ) + security_manager.on_view_menu_after_update.assert_has_calls( + [ + call(ANY, ANY, tmp_db1_view_menu), + call(ANY, ANY, table1_view_menu), + call(ANY, ANY, table2_view_menu), + ] + ) + + session.delete(slice1) + session.delete(table1) + session.delete(table2) + session.delete(tmp_db1) session.commit() - def test_set_perm_database(self): + def test_after_delete_database(self): session = db.session - database = Database(database_name="tmp_database", sqlalchemy_uri="sqlite://") - session.add(database) + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.commit() + tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() - stored_db = ( - session.query(Database).filter_by(database_name="tmp_database").one() + database_pvm = security_manager.find_permission_view_menu( + "database_access", tmp_db1.perm ) - self.assertEqual(stored_db.perm, f"[tmp_database].(id:{stored_db.id})") - self.assertIsNotNone( + self.assertIsNotNone(database_pvm) + role1 = Role(name="tmp_role1") + role1.permissions.append(database_pvm) + session.add(role1) + session.commit() + + session.delete(tmp_db1) + session.commit() + + # Assert that PVM is removed from Role + role1 = security_manager.find_role("tmp_role1") + self.assertEqual(role1.permissions, []) + + # Assert that the old permission was updated + self.assertIsNone( security_manager.find_permission_view_menu( - "database_access", stored_db.perm + "database_access", f"[tmp_db1].(id:{tmp_db1.id})" ) ) - stored_db.database_name = "tmp_database2" + # Cleanup + session.delete(role1) + session.commit() + + def test_after_delete_database_rollback(self): + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) session.commit() - stored_db = ( - session.query(Database).filter_by(database_name="tmp_database2").one() + tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + + database_pvm = security_manager.find_permission_view_menu( + "database_access", tmp_db1.perm ) - self.assertEqual(stored_db.perm, f"[tmp_database2].(id:{stored_db.id})") - self.assertIsNotNone( + self.assertIsNotNone(database_pvm) + role1 = Role(name="tmp_role1") + role1.permissions.append(database_pvm) + session.add(role1) + session.commit() + + session.delete(tmp_db1) + session.flush() + + role1 = security_manager.find_role("tmp_role1") + self.assertEqual(role1.permissions, []) + + self.assertIsNone( security_manager.find_permission_view_menu( - "database_access", stored_db.perm + "database_access", f"[tmp_db1].(id:{tmp_db1.id})" ) ) - session.delete(stored_db) + session.rollback() + + # Test a rollback reverts everything + database_pvm = security_manager.find_permission_view_menu( + "database_access", f"[tmp_db1].(id:{tmp_db1.id})" + ) + + role1 = security_manager.find_role("tmp_role1") + self.assertEqual(role1.permissions, [database_pvm]) + + # Cleanup + session.delete(role1) + session.delete(tmp_db1) + session.commit() + + def test_after_delete_dataset(self): + security_manager.on_permission_view_after_delete = Mock() + + session = db.session + tmp_db = Database(database_name="tmp_db", sqlalchemy_uri="sqlite://") + session.add(tmp_db) + session.commit() + + table1 = SqlaTable( + schema="tmp_schema", + table_name="tmp_table1", + database=tmp_db, + ) + session.add(table1) + session.commit() + + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + + role1 = Role(name="tmp_role1") + role1.permissions.append(table1_pvm) + session.add(role1) + session.commit() + + # refresh + table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + + # Test delete + session.delete(table1) + session.commit() + + role1 = security_manager.find_role("tmp_role1") + self.assertEqual(role1.permissions, []) + + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" + ) + self.assertIsNone(table1_pvm) + table1_view_menu = security_manager.find_view_menu( + f"[tmp_db].[tmp_table1](id:{table1.id})" + ) + self.assertIsNone(table1_view_menu) + + # Assert the hook is called + security_manager.on_permission_view_after_delete.assert_has_calls( + [ + call(ANY, ANY, ANY), + ] + ) + + # cleanup + session.delete(role1) + session.delete(tmp_db) + session.commit() + + def test_after_delete_dataset_rollback(self): + session = db.session + tmp_db = Database(database_name="tmp_db", sqlalchemy_uri="sqlite://") + session.add(tmp_db) + session.commit() + + table1 = SqlaTable( + schema="tmp_schema", + table_name="tmp_table1", + database=tmp_db, + ) + session.add(table1) + session.commit() + + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + + role1 = Role(name="tmp_role1") + role1.permissions.append(table1_pvm) + session.add(role1) + session.commit() + + # refresh + table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + + # Test delete, permissions are correctly deleted + session.delete(table1) + session.flush() + + role1 = security_manager.find_role("tmp_role1") + self.assertEqual(role1.permissions, []) + + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" + ) + self.assertIsNone(table1_pvm) + + # Test rollback, permissions exist everything is correctly rollback + session.rollback() + role1 = security_manager.find_role("tmp_role1") + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + self.assertEqual(role1.permissions, [table1_pvm]) + + # cleanup + session.delete(table1) + session.delete(role1) + session.delete(tmp_db) + session.commit() + + def test_after_update_dataset__name_changes(self): + security_manager.on_view_menu_after_update = Mock() + + session = db.session + tmp_db = Database(database_name="tmp_db", sqlalchemy_uri="sqlite://") + session.add(tmp_db) + session.commit() + + table1 = SqlaTable( + schema="tmp_schema", + table_name="tmp_table1", + database=tmp_db, + ) + session.add(table1) + session.commit() + + slice1 = Slice( + datasource_id=table1.id, + datasource_type=DatasourceType.TABLE, + datasource_name="tmp_table1", + slice_name="tmp_slice1", + ) + session.add(slice1) + session.commit() + + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + + # refresh + table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + # Test update + table1.table_name = "tmp_table1_changed" + session.commit() + + # Test old permission does not exist + old_table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" + ) + self.assertIsNone(old_table1_pvm) + + # Test new permission exist + new_table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1_changed](id:{table1.id})" + ) + self.assertIsNotNone(new_table1_pvm) + + # test dataset permission changed + changed_table1 = ( + session.query(SqlaTable).filter_by(table_name="tmp_table1_changed").one() + ) + self.assertEqual( + changed_table1.perm, f"[tmp_db].[tmp_table1_changed](id:{table1.id})" + ) + + # Test Chart permission changed + slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one() + self.assertEqual(slice1.perm, f"[tmp_db].[tmp_table1_changed](id:{table1.id})") + + # Assert hook is called + view_menu_dataset = security_manager.find_view_menu( + f"[tmp_db].[tmp_table1_changed](id:{table1.id})" + ) + security_manager.on_view_menu_after_update.assert_has_calls( + [ + call(ANY, ANY, view_menu_dataset), + ] + ) + # cleanup + session.delete(slice1) + session.delete(table1) + session.delete(tmp_db) + session.commit() + + def test_after_update_dataset_rollback(self): + session = db.session + tmp_db = Database(database_name="tmp_db", sqlalchemy_uri="sqlite://") + session.add(tmp_db) + session.commit() + + table1 = SqlaTable( + schema="tmp_schema", + table_name="tmp_table1", + database=tmp_db, + ) + session.add(table1) + session.commit() + + slice1 = Slice( + datasource_id=table1.id, + datasource_type=DatasourceType.TABLE, + datasource_name="tmp_table1", + slice_name="tmp_slice1", + ) + session.add(slice1) + session.commit() + + # refresh + table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + # Test update + table1.table_name = "tmp_table1_changed" + session.flush() + + # Test old permission does not exist + old_table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" + ) + self.assertIsNone(old_table1_pvm) + + # Test new permission exist + new_table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1_changed](id:{table1.id})" + ) + self.assertIsNotNone(new_table1_pvm) + + # Test rollback + session.rollback() + + old_table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(old_table1_pvm) + + # cleanup + session.delete(slice1) + session.delete(table1) + session.delete(tmp_db) + session.commit() + + def test_after_update_dataset__db_changes(self): + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + tmp_db2 = Database(database_name="tmp_db2", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.add(tmp_db2) + session.commit() + + table1 = SqlaTable( + schema="tmp_schema", + table_name="tmp_table1", + database=tmp_db1, + ) + session.add(table1) + session.commit() + + slice1 = Slice( + datasource_id=table1.id, + datasource_type=DatasourceType.TABLE, + datasource_name="tmp_table1", + slice_name="tmp_slice1", + ) + session.add(slice1) + session.commit() + + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + + # refresh + table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + # Test update + table1.database = tmp_db2 + session.commit() + + # Test old permission does not exist + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" + ) + self.assertIsNone(table1_pvm) + + # Test new permission exist + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db2].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + + # test dataset permission and schema permission changed + changed_table1 = ( + session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + ) + self.assertEqual(changed_table1.perm, f"[tmp_db2].[tmp_table1](id:{table1.id})") + self.assertEqual(changed_table1.schema_perm, f"[tmp_db2].[tmp_schema]") + + # Test Chart permission changed + slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one() + self.assertEqual(slice1.perm, f"[tmp_db2].[tmp_table1](id:{table1.id})") + self.assertEqual(slice1.schema_perm, f"[tmp_db2].[tmp_schema]") + + # cleanup + session.delete(slice1) + session.delete(table1) + session.delete(tmp_db1) + session.delete(tmp_db2) + session.commit() + + def test_after_update_dataset__schema_changes(self): + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.commit() + + table1 = SqlaTable( + schema="tmp_schema", + table_name="tmp_table1", + database=tmp_db1, + ) + session.add(table1) + session.commit() + + slice1 = Slice( + datasource_id=table1.id, + datasource_type=DatasourceType.TABLE, + datasource_name="tmp_table1", + slice_name="tmp_slice1", + ) + session.add(slice1) + session.commit() + + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + + # refresh + table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + # Test update + table1.schema = "tmp_schema_changed" + session.commit() + + # Test permission still exists + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + + # test dataset schema permission changed + changed_table1 = ( + session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + ) + self.assertEqual(changed_table1.perm, f"[tmp_db1].[tmp_table1](id:{table1.id})") + self.assertEqual(changed_table1.schema_perm, f"[tmp_db1].[tmp_schema_changed]") + + # Test Chart schema permission changed + slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one() + self.assertEqual(slice1.perm, f"[tmp_db1].[tmp_table1](id:{table1.id})") + self.assertEqual(slice1.schema_perm, f"[tmp_db1].[tmp_schema_changed]") + + # cleanup + session.delete(slice1) + session.delete(table1) + session.delete(tmp_db1) + session.commit() + + def test_after_update_dataset__schema_none(self): + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.commit() + + table1 = SqlaTable( + schema="tmp_schema", + table_name="tmp_table1", + database=tmp_db1, + ) + session.add(table1) + session.commit() + + slice1 = Slice( + datasource_id=table1.id, + datasource_type=DatasourceType.TABLE, + datasource_name="tmp_table1", + slice_name="tmp_slice1", + ) + session.add(slice1) + session.commit() + + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + + # refresh + table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + # Test update + table1.schema = None + session.commit() + + # refresh + table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + + self.assertEqual(table1.perm, f"[tmp_db1].[tmp_table1](id:{table1.id})") + self.assertIsNone(table1.schema_perm) + + # cleanup + session.delete(slice1) + session.delete(table1) + session.delete(tmp_db1) + session.commit() + + def test_after_update_dataset__name_db_changes(self): + session = db.session + tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") + tmp_db2 = Database(database_name="tmp_db2", sqlalchemy_uri="sqlite://") + session.add(tmp_db1) + session.add(tmp_db2) + session.commit() + + table1 = SqlaTable( + schema="tmp_schema", + table_name="tmp_table1", + database=tmp_db1, + ) + session.add(table1) + session.commit() + + slice1 = Slice( + datasource_id=table1.id, + datasource_type=DatasourceType.TABLE, + datasource_name="tmp_table1", + slice_name="tmp_slice1", + ) + session.add(slice1) + session.commit() + + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + + # refresh + table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + # Test update + table1.table_name = "tmp_table1_changed" + table1.database = tmp_db2 + session.commit() + + # Test old permission does not exist + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" + ) + self.assertIsNone(table1_pvm) + + # Test new permission exist + table1_pvm = security_manager.find_permission_view_menu( + "datasource_access", f"[tmp_db2].[tmp_table1_changed](id:{table1.id})" + ) + self.assertIsNotNone(table1_pvm) + + # test dataset permission and schema permission changed + changed_table1 = ( + session.query(SqlaTable).filter_by(table_name="tmp_table1_changed").one() + ) + self.assertEqual( + changed_table1.perm, f"[tmp_db2].[tmp_table1_changed](id:{table1.id})" + ) + self.assertEqual(changed_table1.schema_perm, f"[tmp_db2].[tmp_schema]") + + # Test Chart permission changed + slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one() + self.assertEqual(slice1.perm, f"[tmp_db2].[tmp_table1_changed](id:{table1.id})") + self.assertEqual(slice1.schema_perm, f"[tmp_db2].[tmp_schema]") + + # cleanup + session.delete(slice1) + session.delete(table1) + session.delete(tmp_db1) + session.delete(tmp_db2) session.commit() def test_hybrid_perm_database(self): @@ -382,23 +1148,14 @@ def test_set_perm_slice(self): table.schema = "tmp_perm_schema" table.table_name = "tmp_perm_table_v2" session.commit() - # TODO(bogdan): modify slice permissions on the table update. - self.assertNotEqual(slice.perm, table.perm) - self.assertEqual(slice.perm, f"[tmp_database].[tmp_perm_table](id:{table.id})") - self.assertEqual( - table.perm, f"[tmp_database].[tmp_perm_table_v2](id:{table.id})" - ) - # TODO(bogdan): modify slice schema permissions on the table update. - self.assertNotEqual(slice.schema_perm, table.schema_perm) - self.assertIsNone(slice.schema_perm) - - # updating slice refreshes the permissions - slice.slice_name = "slice_name_v2" - session.commit() + table = session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one() self.assertEqual(slice.perm, table.perm) self.assertEqual( slice.perm, f"[tmp_database].[tmp_perm_table_v2](id:{table.id})" ) + self.assertEqual( + table.perm, f"[tmp_database].[tmp_perm_table_v2](id:{table.id})" + ) self.assertEqual(slice.schema_perm, table.schema_perm) self.assertEqual(slice.schema_perm, "[tmp_database].[tmp_perm_schema]") @@ -408,11 +1165,10 @@ def test_set_perm_slice(self): session.commit() - # TODO test slice permission - + @patch("superset.utils.core.g") @patch("superset.security.manager.g") - def test_schemas_accessible_by_user_admin(self, mock_g): - mock_g.user = security_manager.find_user("admin") + def test_schemas_accessible_by_user_admin(self, mock_sm_g, mock_g): + mock_g.user = mock_sm_g.user = security_manager.find_user("admin") with self.client.application.test_request_context(): database = get_example_database() schemas = security_manager.get_schemas_accessible_by_user( @@ -420,11 +1176,12 @@ def test_schemas_accessible_by_user_admin(self, mock_g): ) self.assertEqual(schemas, ["1", "2", "3"]) # no changes + @patch("superset.utils.core.g") @patch("superset.security.manager.g") - def test_schemas_accessible_by_user_schema_access(self, mock_g): + def test_schemas_accessible_by_user_schema_access(self, mock_sm_g, mock_g): # User has schema access to the schema 1 create_schema_perm("[examples].[1]") - mock_g.user = security_manager.find_user("gamma") + mock_g.user = mock_sm_g.user = security_manager.find_user("gamma") with self.client.application.test_request_context(): database = get_example_database() schemas = security_manager.get_schemas_accessible_by_user( @@ -434,10 +1191,11 @@ def test_schemas_accessible_by_user_schema_access(self, mock_g): self.assertEqual(schemas, ["1"]) delete_schema_perm("[examples].[1]") + @patch("superset.utils.core.g") @patch("superset.security.manager.g") - def test_schemas_accessible_by_user_datasource_access(self, mock_g): + def test_schemas_accessible_by_user_datasource_access(self, mock_sm_g, mock_g): # User has schema access to the datasource temp_schema.wb_health_population in examples DB. - mock_g.user = security_manager.find_user("gamma") + mock_g.user = mock_sm_g.user = security_manager.find_user("gamma") with self.client.application.test_request_context(): database = get_example_database() schemas = security_manager.get_schemas_accessible_by_user( @@ -445,11 +1203,14 @@ def test_schemas_accessible_by_user_datasource_access(self, mock_g): ) self.assertEqual(schemas, ["temp_schema"]) + @patch("superset.utils.core.g") @patch("superset.security.manager.g") - def test_schemas_accessible_by_user_datasource_and_schema_access(self, mock_g): + def test_schemas_accessible_by_user_datasource_and_schema_access( + self, mock_sm_g, mock_g + ): # User has schema access to the datasource temp_schema.wb_health_population in examples DB. create_schema_perm("[examples].[2]") - mock_g.user = security_manager.find_user("gamma") + mock_g.user = mock_sm_g.user = security_manager.find_user("gamma") with self.client.application.test_request_context(): database = get_example_database() schemas = security_manager.get_schemas_accessible_by_user( @@ -567,13 +1328,26 @@ def assert_can_all(self, view_menu, permissions_set): def assert_can_menu(self, view_menu, permissions_set): self.assertIn(("menu_access", view_menu), permissions_set) + def assert_cannot_menu(self, view_menu, permissions_set): + self.assertNotIn(("menu_access", view_menu), permissions_set) + + def assert_cannot_gamma(self, perm_set): + self.assert_cannot_write("CssTemplate", perm_set) + self.assert_cannot_menu("CSS Templates", perm_set) + self.assert_cannot_menu("Manage", perm_set) + self.assert_cannot_menu("Queries", perm_set) + self.assert_cannot_menu("Import dashboards", perm_set) + self.assert_cannot_menu("Upload a CSV", perm_set) + self.assert_cannot_menu("ReportSchedule", perm_set) + self.assert_cannot_menu("Alerts & Report", perm_set) + def assert_can_gamma(self, perm_set): + self.assert_can_read("CssTemplate", perm_set) self.assert_can_read("Dataset", perm_set) # make sure that user can create slices and dashboards self.assert_can_all("Dashboard", perm_set) self.assert_can_all("Chart", perm_set) - self.assertIn(("can_add_slices", "Superset"), perm_set) self.assertIn(("can_copy_dash", "Superset"), perm_set) self.assertIn(("can_created_dashboards", "Superset"), perm_set) @@ -716,6 +1490,7 @@ def test_is_gamma_pvm(self): def test_gamma_permissions_basic(self): self.assert_can_gamma(get_perm_tuples("Gamma")) self.assert_cannot_alpha(get_perm_tuples("Gamma")) + self.assert_cannot_gamma(get_perm_tuples("Gamma")) @pytest.mark.usefixtures("public_role_like_gamma") def test_public_permissions_basic(self): @@ -876,9 +1651,9 @@ def test_can_access_table(self, mock_raise_for_access): self.assertFalse(security_manager.can_access_table(database, table)) + @patch("superset.security.SupersetSecurityManager.is_owner") @patch("superset.security.SupersetSecurityManager.can_access") @patch("superset.security.SupersetSecurityManager.can_access_schema") - @patch("superset.views.utils.is_owner") def test_raise_for_access_datasource( self, mock_can_access_schema, mock_can_access, mock_is_owner ): @@ -894,8 +1669,8 @@ def test_raise_for_access_datasource( with self.assertRaises(SupersetSecurityException): security_manager.raise_for_access(datasource=datasource) + @patch("superset.security.SupersetSecurityManager.is_owner") @patch("superset.security.SupersetSecurityManager.can_access") - @patch("superset.views.utils.is_owner") def test_raise_for_access_query(self, mock_can_access, mock_is_owner): query = Mock( database=get_example_database(), schema="bar", sql="SELECT * FROM foo" @@ -910,10 +1685,11 @@ def test_raise_for_access_query(self, mock_can_access, mock_is_owner): with self.assertRaises(SupersetSecurityException): security_manager.raise_for_access(query=query) + @patch("superset.security.SupersetSecurityManager.is_owner") @patch("superset.security.SupersetSecurityManager.can_access") @patch("superset.security.SupersetSecurityManager.can_access_schema") def test_raise_for_access_query_context( - self, mock_can_access_schema, mock_can_access + self, mock_can_access_schema, mock_can_access, mock_is_owner ): query_context = Mock(datasource=self.get_datasource_mock()) @@ -922,6 +1698,7 @@ def test_raise_for_access_query_context( mock_can_access.return_value = False mock_can_access_schema.return_value = False + mock_is_owner.return_value = False with self.assertRaises(SupersetSecurityException): security_manager.raise_for_access(query_context=query_context) @@ -939,9 +1716,12 @@ def test_raise_for_access_table(self, mock_can_access): with self.assertRaises(SupersetSecurityException): security_manager.raise_for_access(database=database, table=table) + @patch("superset.security.SupersetSecurityManager.is_owner") @patch("superset.security.SupersetSecurityManager.can_access") @patch("superset.security.SupersetSecurityManager.can_access_schema") - def test_raise_for_access_viz(self, mock_can_access_schema, mock_can_access): + def test_raise_for_access_viz( + self, mock_can_access_schema, mock_can_access, mock_is_owner + ): test_viz = viz.TableViz(self.get_datasource_mock(), form_data={}) mock_can_access_schema.return_value = True @@ -949,6 +1729,7 @@ def test_raise_for_access_viz(self, mock_can_access_schema, mock_can_access): mock_can_access.return_value = False mock_can_access_schema.return_value = False + mock_is_owner.return_value = False with self.assertRaises(SupersetSecurityException): security_manager.raise_for_access(viz=test_viz) @@ -996,7 +1777,7 @@ def test_get_user_datasources_admin( mock_get_session.query.return_value.filter.return_value.all.return_value = [] with mock.patch.object( - ConnectorRegistry, "get_all_datasources" + SqlaTable, "get_all_datasources" ) as mock_get_all_datasources: mock_get_all_datasources.return_value = [ Datasource("database1", "schema1", "table1"), @@ -1024,7 +1805,7 @@ def test_get_user_datasources_gamma( mock_get_session.query.return_value.filter.return_value.all.return_value = [] with mock.patch.object( - ConnectorRegistry, "get_all_datasources" + SqlaTable, "get_all_datasources" ) as mock_get_all_datasources: mock_get_all_datasources.return_value = [ Datasource("database1", "schema1", "table1"), @@ -1052,7 +1833,7 @@ def test_get_user_datasources_gamma_with_schema( ] with mock.patch.object( - ConnectorRegistry, "get_all_datasources" + SqlaTable, "get_all_datasources" ) as mock_get_all_datasources: mock_get_all_datasources.return_value = [ Datasource("database1", "schema1", "table1"), diff --git a/tests/integration_tests/sql_lab/__init__.py b/tests/integration_tests/sql_lab/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/integration_tests/sql_lab/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/integration_tests/sql_lab/api_tests.py b/tests/integration_tests/sql_lab/api_tests.py new file mode 100644 index 0000000000000..93beb380f0db6 --- /dev/null +++ b/tests/integration_tests/sql_lab/api_tests.py @@ -0,0 +1,215 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# isort:skip_file +"""Unit tests for Superset""" +import datetime +import json +import random +import csv +import pandas as pd +import io + +import pytest +import prison +from sqlalchemy.sql import func +from unittest import mock + +from tests.integration_tests.test_app import app +from superset import db, sql_lab +from superset.common.db_query_status import QueryStatus +from superset.models.core import Database +from superset.utils.database import get_example_database, get_main_database +from superset.utils import core as utils +from superset.models.sql_lab import Query + +from tests.integration_tests.base_tests import SupersetTestCase + +QUERIES_FIXTURE_COUNT = 10 + + +class TestSqlLabApi(SupersetTestCase): + @mock.patch("superset.sqllab.commands.results.results_backend_use_msgpack", False) + def test_execute_required_params(self): + self.login() + client_id = "{}".format(random.getrandbits(64))[:10] + + data = {"client_id": client_id} + rv = self.client.post( + "/api/v1/sqllab/execute/", + json=data, + ) + failed_resp = { + "message": { + "sql": ["Missing data for required field."], + "database_id": ["Missing data for required field."], + } + } + resp_data = json.loads(rv.data.decode("utf-8")) + self.assertDictEqual(resp_data, failed_resp) + self.assertEqual(rv.status_code, 400) + + data = {"sql": "SELECT 1", "client_id": client_id} + rv = self.client.post( + "/api/v1/sqllab/execute/", + json=data, + ) + failed_resp = {"message": {"database_id": ["Missing data for required field."]}} + resp_data = json.loads(rv.data.decode("utf-8")) + self.assertDictEqual(resp_data, failed_resp) + self.assertEqual(rv.status_code, 400) + + data = {"database_id": 1, "client_id": client_id} + rv = self.client.post( + "/api/v1/sqllab/execute/", + json=data, + ) + failed_resp = {"message": {"sql": ["Missing data for required field."]}} + resp_data = json.loads(rv.data.decode("utf-8")) + self.assertDictEqual(resp_data, failed_resp) + self.assertEqual(rv.status_code, 400) + + @mock.patch("superset.sqllab.commands.results.results_backend_use_msgpack", False) + def test_execute_valid_request(self) -> None: + from superset import sql_lab as core + + core.results_backend = mock.Mock() + core.results_backend.get.return_value = {} + + self.login() + client_id = "{}".format(random.getrandbits(64))[:10] + + data = {"sql": "SELECT 1", "database_id": 1, "client_id": client_id} + rv = self.client.post( + "/api/v1/sqllab/execute/", + json=data, + ) + resp_data = json.loads(rv.data.decode("utf-8")) + self.assertEqual(resp_data.get("status"), "success") + self.assertEqual(rv.status_code, 200) + + @mock.patch( + "tests.integration_tests.superset_test_custom_template_processors.datetime" + ) + @mock.patch("superset.sqllab.api.get_sql_results") + def test_execute_custom_templated(self, sql_lab_mock, mock_dt) -> None: + mock_dt.utcnow = mock.Mock(return_value=datetime.datetime(1970, 1, 1)) + self.login() + sql = "SELECT '$DATE()' as test" + resp = { + "status": QueryStatus.SUCCESS, + "query": {"rows": 1}, + "data": [{"test": "'1970-01-01'"}], + } + sql_lab_mock.return_value = resp + + dbobj = self.create_fake_db_for_macros() + json_payload = dict(database_id=dbobj.id, sql=sql) + self.get_json_resp( + "/api/v1/sqllab/execute/", raise_on_error=False, json_=json_payload + ) + assert sql_lab_mock.called + self.assertEqual(sql_lab_mock.call_args[0][1], "SELECT '1970-01-01' as test") + + self.delete_fake_db_for_macros() + + @mock.patch("superset.sqllab.commands.results.results_backend_use_msgpack", False) + def test_get_results_with_display_limit(self): + from superset.sqllab.commands import results as command + + command.results_backend = mock.Mock() + self.login() + + data = [{"col_0": i} for i in range(100)] + payload = { + "status": QueryStatus.SUCCESS, + "query": {"rows": 100}, + "data": data, + } + # limit results to 1 + expected_key = {"status": "success", "query": {"rows": 100}, "data": data} + limited_data = data[:1] + expected_limited = { + "status": "success", + "query": {"rows": 100}, + "data": limited_data, + "displayLimitReached": True, + } + + query_mock = mock.Mock() + query_mock.sql = "SELECT *" + query_mock.database = 1 + query_mock.schema = "superset" + + # do not apply msgpack serialization + use_msgpack = app.config["RESULTS_BACKEND_USE_MSGPACK"] + app.config["RESULTS_BACKEND_USE_MSGPACK"] = False + serialized_payload = sql_lab._serialize_payload(payload, False) + compressed = utils.zlib_compress(serialized_payload) + command.results_backend.get.return_value = compressed + + with mock.patch("superset.sqllab.commands.results.db") as mock_superset_db: + mock_superset_db.session.query().filter_by().one_or_none.return_value = ( + query_mock + ) + # get all results + arguments = {"key": "key"} + result_key = json.loads( + self.get_resp(f"/api/v1/sqllab/results/?q={prison.dumps(arguments)}") + ) + arguments = {"key": "key", "rows": 1} + result_limited = json.loads( + self.get_resp(f"/api/v1/sqllab/results/?q={prison.dumps(arguments)}") + ) + + self.assertEqual(result_key, expected_key) + self.assertEqual(result_limited, expected_limited) + + app.config["RESULTS_BACKEND_USE_MSGPACK"] = use_msgpack + + @mock.patch("superset.models.sql_lab.Query.raise_for_access", lambda _: None) + @mock.patch("superset.models.core.Database.get_df") + def test_export_results(self, get_df_mock: mock.Mock) -> None: + self.login() + + database = get_example_database() + query_obj = Query( + client_id="test", + database=database, + tab_name="test_tab", + sql_editor_id="test_editor_id", + sql="select * from bar", + select_sql=None, + executed_sql="select * from bar limit 2", + limit=100, + select_as_cta=False, + rows=104, + error_message="none", + results_key="test_abc", + ) + + db.session.add(query_obj) + db.session.commit() + + get_df_mock.return_value = pd.DataFrame({"foo": [1, 2, 3]}) + + resp = self.get_resp("/api/v1/sqllab/export/test/") + data = csv.reader(io.StringIO(resp)) + expected_data = csv.reader(io.StringIO("foo\n1\n2")) + + self.assertEqual(list(expected_data), list(data)) + db.session.delete(query_obj) + db.session.commit() diff --git a/tests/integration_tests/sql_lab/commands_tests.py b/tests/integration_tests/sql_lab/commands_tests.py new file mode 100644 index 0000000000000..cf0aebf001e01 --- /dev/null +++ b/tests/integration_tests/sql_lab/commands_tests.py @@ -0,0 +1,293 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from unittest import mock, skip +from unittest.mock import Mock, patch + +import pandas as pd +import pytest + +from superset import db, sql_lab +from superset.common.db_query_status import QueryStatus +from superset.errors import ErrorLevel, SupersetErrorType +from superset.exceptions import ( + SerializationError, + SupersetError, + SupersetErrorException, + SupersetSecurityException, +) +from superset.models.core import Database +from superset.models.sql_lab import Query +from superset.sqllab.commands import export, results +from superset.sqllab.limiting_factor import LimitingFactor +from superset.utils import core as utils +from superset.utils.database import get_example_database +from tests.integration_tests.base_tests import SupersetTestCase + + +class TestSqlResultExportCommand(SupersetTestCase): + @pytest.fixture() + def create_database_and_query(self): + with self.create_app().app_context(): + database = get_example_database() + query_obj = Query( + client_id="test", + database=database, + tab_name="test_tab", + sql_editor_id="test_editor_id", + sql="select * from bar", + select_sql="select * from bar", + executed_sql="select * from bar", + limit=100, + select_as_cta=False, + rows=104, + error_message="none", + results_key="abc_query", + ) + + db.session.add(query_obj) + db.session.commit() + + yield + + db.session.delete(query_obj) + db.session.commit() + + @pytest.mark.usefixtures("create_database_and_query") + def test_validation_query_not_found(self) -> None: + command = export.SqlResultExportCommand("asdf") + + with pytest.raises(SupersetErrorException) as ex_info: + command.run() + assert ex_info.value.error.error_type == SupersetErrorType.RESULTS_BACKEND_ERROR + + @pytest.mark.usefixtures("create_database_and_query") + def test_validation_invalid_access(self) -> None: + command = export.SqlResultExportCommand("test") + + with mock.patch( + "superset.security_manager.raise_for_access", + side_effect=SupersetSecurityException( + SupersetError( + "dummy", + SupersetErrorType.DATASOURCE_SECURITY_ACCESS_ERROR, + ErrorLevel.ERROR, + ) + ), + ): + with pytest.raises(SupersetErrorException) as ex_info: + command.run() + assert ( + ex_info.value.error.error_type + == SupersetErrorType.QUERY_SECURITY_ACCESS_ERROR + ) + + @pytest.mark.usefixtures("create_database_and_query") + @patch("superset.models.sql_lab.Query.raise_for_access", lambda _: None) + @patch("superset.models.core.Database.get_df") + def test_run_no_results_backend_select_sql(self, get_df_mock: Mock) -> None: + command = export.SqlResultExportCommand("test") + + get_df_mock.return_value = pd.DataFrame({"foo": [1, 2, 3]}) + result = command.run() + + assert result["data"] == "foo\n1\n2\n3\n" + assert result["count"] == 3 + assert result["query"].client_id == "test" + + @pytest.mark.usefixtures("create_database_and_query") + @patch("superset.models.sql_lab.Query.raise_for_access", lambda _: None) + @patch("superset.models.core.Database.get_df") + def test_run_no_results_backend_executed_sql(self, get_df_mock: Mock) -> None: + query_obj = db.session.query(Query).filter_by(client_id="test").one() + query_obj.executed_sql = "select * from bar limit 2" + query_obj.select_sql = None + db.session.commit() + + command = export.SqlResultExportCommand("test") + + get_df_mock.return_value = pd.DataFrame({"foo": [1, 2, 3]}) + result = command.run() + + assert result["data"] == "foo\n1\n2\n" + assert result["count"] == 2 + assert result["query"].client_id == "test" + + @pytest.mark.usefixtures("create_database_and_query") + @patch("superset.models.sql_lab.Query.raise_for_access", lambda _: None) + @patch("superset.models.core.Database.get_df") + def test_run_no_results_backend_executed_sql_limiting_factor( + self, get_df_mock: Mock + ) -> None: + query_obj = db.session.query(Query).filter_by(results_key="abc_query").one() + query_obj.executed_sql = "select * from bar limit 2" + query_obj.select_sql = None + query_obj.limiting_factor = LimitingFactor.DROPDOWN + db.session.commit() + + command = export.SqlResultExportCommand("test") + + get_df_mock.return_value = pd.DataFrame({"foo": [1, 2, 3]}) + + result = command.run() + + assert result["data"] == "foo\n1\n" + assert result["count"] == 1 + assert result["query"].client_id == "test" + + @pytest.mark.usefixtures("create_database_and_query") + @patch("superset.models.sql_lab.Query.raise_for_access", lambda _: None) + @patch("superset.sqllab.commands.export.results_backend_use_msgpack", False) + def test_run_with_results_backend(self) -> None: + command = export.SqlResultExportCommand("test") + + data = [{"foo": i} for i in range(5)] + payload = { + "columns": [{"name": "foo"}], + "data": data, + } + serialized_payload = sql_lab._serialize_payload(payload, False) + compressed = utils.zlib_compress(serialized_payload) + + export.results_backend = mock.Mock() + export.results_backend.get.return_value = compressed + + result = command.run() + + assert result["data"] == "foo\n0\n1\n2\n3\n4\n" + assert result["count"] == 5 + assert result["query"].client_id == "test" + + +class TestSqlExecutionResultsCommand(SupersetTestCase): + @pytest.fixture() + def create_database_and_query(self): + with self.create_app().app_context(): + database = get_example_database() + query_obj = Query( + client_id="test", + database=database, + tab_name="test_tab", + sql_editor_id="test_editor_id", + sql="select * from bar", + select_sql="select * from bar", + executed_sql="select * from bar", + limit=100, + select_as_cta=False, + rows=104, + error_message="none", + results_key="abc_query", + ) + + db.session.add(query_obj) + db.session.commit() + + yield + + db.session.delete(query_obj) + db.session.commit() + + @patch("superset.sqllab.commands.results.results_backend_use_msgpack", False) + @patch("superset.sqllab.commands.results.results_backend", None) + def test_validation_no_results_backend(self) -> None: + command = results.SqlExecutionResultsCommand("test", 1000) + + with pytest.raises(SupersetErrorException) as ex_info: + command.run() + assert ( + ex_info.value.error.error_type + == SupersetErrorType.RESULTS_BACKEND_NOT_CONFIGURED_ERROR + ) + + @patch("superset.sqllab.commands.results.results_backend_use_msgpack", False) + def test_validation_data_cannot_be_retrieved(self) -> None: + results.results_backend = mock.Mock() + results.results_backend.get.return_value = None + + command = results.SqlExecutionResultsCommand("test", 1000) + + with pytest.raises(SupersetErrorException) as ex_info: + command.run() + assert ex_info.value.error.error_type == SupersetErrorType.RESULTS_BACKEND_ERROR + + @patch("superset.sqllab.commands.results.results_backend_use_msgpack", False) + def test_validation_data_not_found(self) -> None: + data = [{"col_0": i} for i in range(100)] + payload = { + "status": QueryStatus.SUCCESS, + "query": {"rows": 100}, + "data": data, + } + serialized_payload = sql_lab._serialize_payload(payload, False) + compressed = utils.zlib_compress(serialized_payload) + + results.results_backend = mock.Mock() + results.results_backend.get.return_value = compressed + + command = results.SqlExecutionResultsCommand("test", 1000) + + with pytest.raises(SupersetErrorException) as ex_info: + command.run() + assert ex_info.value.error.error_type == SupersetErrorType.RESULTS_BACKEND_ERROR + + @pytest.mark.usefixtures("create_database_and_query") + @patch("superset.sqllab.commands.results.results_backend_use_msgpack", False) + def test_validation_query_not_found(self) -> None: + data = [{"col_0": i} for i in range(104)] + payload = { + "status": QueryStatus.SUCCESS, + "query": {"rows": 104}, + "data": data, + } + serialized_payload = sql_lab._serialize_payload(payload, False) + compressed = utils.zlib_compress(serialized_payload) + + results.results_backend = mock.Mock() + results.results_backend.get.return_value = compressed + + with mock.patch( + "superset.views.utils._deserialize_results_payload", + side_effect=SerializationError(), + ): + with pytest.raises(SupersetErrorException) as ex_info: + command = results.SqlExecutionResultsCommand("test_other", 1000) + command.run() + assert ( + ex_info.value.error.error_type + == SupersetErrorType.RESULTS_BACKEND_ERROR + ) + + @pytest.mark.usefixtures("create_database_and_query") + @patch("superset.sqllab.commands.results.results_backend_use_msgpack", False) + def test_run_succeeds(self) -> None: + data = [{"col_0": i} for i in range(104)] + payload = { + "status": QueryStatus.SUCCESS, + "query": {"rows": 104}, + "data": data, + } + serialized_payload = sql_lab._serialize_payload(payload, False) + compressed = utils.zlib_compress(serialized_payload) + + results.results_backend = mock.Mock() + results.results_backend.get.return_value = compressed + + command = results.SqlExecutionResultsCommand("abc_query", 1000) + result = command.run() + + assert result.get("status") == "success" + assert result["query"].get("rows") == 104 + assert result.get("data") == data diff --git a/tests/integration_tests/sql_lab/conftest.py b/tests/integration_tests/sql_lab/conftest.py new file mode 100644 index 0000000000000..8b4a0e63a5aac --- /dev/null +++ b/tests/integration_tests/sql_lab/conftest.py @@ -0,0 +1,71 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from typing import Callable, ContextManager + +import pytest +from flask_appbuilder.security.sqla import models as ab_models + +from superset import db +from superset.models.sql_lab import Query +from superset.utils.core import shortid +from superset.utils.database import get_example_database + + +def force_async_run(allow_run_async: bool): + example_db = get_example_database() + orig_allow_run_async = example_db.allow_run_async + + example_db.allow_run_async = allow_run_async + db.session.commit() + + yield example_db + + example_db.allow_run_async = orig_allow_run_async + db.session.commit() + + +@pytest.fixture +def non_async_example_db(app_context): + gen = force_async_run(False) + yield next(gen) + try: + next(gen) + except StopIteration: + pass + + +@pytest.fixture +def async_example_db(app_context): + gen = force_async_run(True) + yield next(gen) + try: + next(gen) + except StopIteration: + pass + + +@pytest.fixture +def example_query(get_or_create_user: Callable[..., ContextManager[ab_models.User]]): + with get_or_create_user("sqllab-test-user") as user: + query = Query( + client_id=shortid()[:10], database=get_example_database(), user=user + ) + db.session.add(query) + db.session.commit() + yield query + db.session.delete(query) + db.session.commit() diff --git a/tests/integration_tests/sql_lab/test_execute_sql_statements.py b/tests/integration_tests/sql_lab/test_execute_sql_statements.py new file mode 100644 index 0000000000000..48fcfe31f03cb --- /dev/null +++ b/tests/integration_tests/sql_lab/test_execute_sql_statements.py @@ -0,0 +1,56 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from superset import app, db +from superset.common.db_query_status import QueryStatus +from superset.models.core import Database +from superset.models.sql_lab import Query +from superset.sql_lab import execute_sql_statements +from superset.utils.dates import now_as_float + + +def test_non_async_execute(non_async_example_db: Database, example_query: Query): + """Test query.tracking_url is attached for Presto and Hive queries""" + result = execute_sql_statements( + example_query.id, + "select 1 as foo;", + store_results=False, + return_results=True, + session=db.session, + start_time=now_as_float(), + expand_data=True, + log_params=dict(), + ) + assert result + assert result["query_id"] == example_query.id + assert result["status"] == QueryStatus.SUCCESS + assert result["data"] == [{"foo": 1}] + + # should attach apply tracking URL for Presto & Hive + if non_async_example_db.db_engine_spec.engine == "presto": + assert example_query.tracking_url + assert "/ui/query.html?" in example_query.tracking_url + + app.config["TRACKING_URL_TRANSFORMER"] = lambda url, query: url.replace( + "/ui/query.html?", f"/{query.client_id}/" + ) + assert f"/{example_query.client_id}/" in example_query.tracking_url + + app.config["TRACKING_URL_TRANSFORMER"] = lambda url: url + "&foo=bar" + assert example_query.tracking_url.endswith("&foo=bar") + + if non_async_example_db.db_engine_spec.engine_name == "hive": + assert example_query.tracking_url_raw diff --git a/tests/integration_tests/sql_validator_tests.py b/tests/integration_tests/sql_validator_tests.py index ff4c74fa45fba..d2f6e7108d42a 100644 --- a/tests/integration_tests/sql_validator_tests.py +++ b/tests/integration_tests/sql_validator_tests.py @@ -174,7 +174,9 @@ class TestPrestoValidator(SupersetTestCase): def setUp(self): self.validator = PrestoDBSQLValidator self.database = MagicMock() - self.database_engine = self.database.get_sqla_engine.return_value + self.database_engine = ( + self.database.get_sqla_engine_with_context.return_value.__enter__.return_value + ) self.database_conn = self.database_engine.raw_connection.return_value self.database_cursor = self.database_conn.cursor.return_value self.database_cursor.poll.return_value = None diff --git a/tests/integration_tests/sqla_models_tests.py b/tests/integration_tests/sqla_models_tests.py index 5614ad263a4f2..4003913516fee 100644 --- a/tests/integration_tests/sqla_models_tests.py +++ b/tests/integration_tests/sqla_models_tests.py @@ -23,7 +23,6 @@ import numpy as np import pandas as pd -import sqlalchemy as sa from flask import Flask from pytest_mock import MockFixture from sqlalchemy.sql import text @@ -40,8 +39,6 @@ AdhocMetricExpressionType, FilterOperator, GenericDataType, - TemporalType, - backend, ) from superset.utils.database import get_example_database from tests.integration_tests.fixtures.birth_names_dashboard import ( @@ -51,6 +48,7 @@ from tests.integration_tests.test_app import app from .base_tests import SupersetTestCase +from .conftest import only_postgresql VIRTUAL_TABLE_INT_TYPES: Dict[str, Pattern[str]] = { "hive": re.compile(r"^INT_TYPE$"), @@ -70,6 +68,7 @@ class FilterTestCase(NamedTuple): + column: str operator: str value: Union[float, int, List[Any], str] expected: Union[str, List[str]] @@ -201,22 +200,34 @@ def test_jinja_metrics_and_calc_columns(self, flask_g): "granularity": None, "from_dttm": None, "to_dttm": None, - "groupby": ["user", "expr"], + "columns": [ + "user", + "expr", + { + "hasCustomLabel": True, + "label": "adhoc_column", + "sqlExpression": "'{{ 'foo_' + time_grain }}'", + }, + ], "metrics": [ { + "hasCustomLabel": True, + "label": "adhoc_metric", "expressionType": AdhocMetricExpressionType.SQL, - "sqlExpression": "SUM(case when user = '{{ current_username() }}' " - "then 1 else 0 end)", - "label": "SUM(userid)", - } + "sqlExpression": "SUM(case when user = '{{ 'user_' + " + "current_username() }}' then 1 else 0 end)", + }, + "count_timegrain", ], "is_timeseries": False, "filter": [], + "extras": {"time_grain_sqla": "P1D"}, } table = SqlaTable( table_name="test_has_jinja_metric_and_expr", - sql="SELECT '{{ current_username() }}' as user", + sql="SELECT '{{ 'user_' + current_username() }}' as user, " + "'{{ 'xyz_' + time_grain }}' as time_grain", database=get_example_database(), ) TableColumn( @@ -226,14 +237,25 @@ def test_jinja_metrics_and_calc_columns(self, flask_g): type="VARCHAR(100)", table=table, ) + SqlMetric( + metric_name="count_timegrain", + expression="count('{{ 'bar_' + time_grain }}')", + table=table, + ) db.session.commit() sqla_query = table.get_sqla_query(**base_query_obj) query = table.database.compile_sqla_query(sqla_query.sqla_query) - # assert expression - assert "case when 'abc' = 'abc' then 'yes' else 'no' end" in query - # assert metric - assert "SUM(case when user = 'abc' then 1 else 0 end)" in query + # assert virtual dataset + assert "SELECT 'user_abc' as user, 'xyz_P1D' as time_grain" in query + # assert dataset calculated column + assert "case when 'abc' = 'abc' then 'yes' else 'no' end AS expr" in query + # assert adhoc column + assert "'foo_P1D'" in query + # assert dataset saved metric + assert "count('bar_P1D')" in query + # assert adhoc metric + assert "SUM(case when user = 'user_abc' then 1 else 0 end)" in query # Cleanup db.session.delete(table) db.session.commit() @@ -270,19 +292,22 @@ def test_adhoc_metrics_and_calc_columns(self): @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_where_operators(self): filters: Tuple[FilterTestCase, ...] = ( - FilterTestCase(FilterOperator.IS_NULL, "", "IS NULL"), - FilterTestCase(FilterOperator.IS_NOT_NULL, "", "IS NOT NULL"), + FilterTestCase("num", FilterOperator.IS_NULL, "", "IS NULL"), + FilterTestCase("num", FilterOperator.IS_NOT_NULL, "", "IS NOT NULL"), # Some db backends translate true/false to 1/0 - FilterTestCase(FilterOperator.IS_TRUE, "", ["IS 1", "IS true"]), - FilterTestCase(FilterOperator.IS_FALSE, "", ["IS 0", "IS false"]), - FilterTestCase(FilterOperator.GREATER_THAN, 0, "> 0"), - FilterTestCase(FilterOperator.GREATER_THAN_OR_EQUALS, 0, ">= 0"), - FilterTestCase(FilterOperator.LESS_THAN, 0, "< 0"), - FilterTestCase(FilterOperator.LESS_THAN_OR_EQUALS, 0, "<= 0"), - FilterTestCase(FilterOperator.EQUALS, 0, "= 0"), - FilterTestCase(FilterOperator.NOT_EQUALS, 0, "!= 0"), - FilterTestCase(FilterOperator.IN, ["1", "2"], "IN (1, 2)"), - FilterTestCase(FilterOperator.NOT_IN, ["1", "2"], "NOT IN (1, 2)"), + FilterTestCase("num", FilterOperator.IS_TRUE, "", ["IS 1", "IS true"]), + FilterTestCase("num", FilterOperator.IS_FALSE, "", ["IS 0", "IS false"]), + FilterTestCase("num", FilterOperator.GREATER_THAN, 0, "> 0"), + FilterTestCase("num", FilterOperator.GREATER_THAN_OR_EQUALS, 0, ">= 0"), + FilterTestCase("num", FilterOperator.LESS_THAN, 0, "< 0"), + FilterTestCase("num", FilterOperator.LESS_THAN_OR_EQUALS, 0, "<= 0"), + FilterTestCase("num", FilterOperator.EQUALS, 0, "= 0"), + FilterTestCase("num", FilterOperator.NOT_EQUALS, 0, "!= 0"), + FilterTestCase("num", FilterOperator.IN, ["1", "2"], "IN (1, 2)"), + FilterTestCase("num", FilterOperator.NOT_IN, ["1", "2"], "NOT IN (1, 2)"), + FilterTestCase( + "ds", FilterOperator.TEMPORAL_RANGE, "2020 : 2021", "2020-01-01" + ), ) table = self.get_table(name="birth_names") for filter_ in filters: @@ -294,7 +319,11 @@ def test_where_operators(self): "metrics": ["count"], "is_timeseries": False, "filter": [ - {"col": "num", "op": filter_.operator, "val": filter_.value} + { + "col": filter_.column, + "op": filter_.operator, + "val": filter_.value, + } ], "extras": {}, } @@ -379,9 +408,8 @@ def test_query_format_strip_trailing_semicolon(self): "extras": {}, } - # Table with Jinja callable. table = SqlaTable( - table_name="test_table", + table_name="another_test_table", sql="SELECT * from test_table;", database=get_example_database(), ) @@ -454,7 +482,8 @@ def test_fetch_metadata_for_updated_virtual_table(self): # make sure the columns have been mapped properly assert len(table.columns) == 4 - table.fetch_metadata(commit=False) + with db.session.no_autoflush: + table.fetch_metadata(commit=False) # assert that the removed column has been dropped and # the physical and calculated columns are present @@ -466,15 +495,13 @@ def test_fetch_metadata_for_updated_virtual_table(self): } cols: Dict[str, TableColumn] = {col.column_name: col for col in table.columns} # assert that the type for intcol has been updated (asserting CI types) - backend = get_example_database().backend + backend = table.database.backend assert VIRTUAL_TABLE_INT_TYPES[backend].match(cols["intcol"].type) # assert that the expression has been replaced with the new physical column assert cols["mycase"].expression == "" assert VIRTUAL_TABLE_STRING_TYPES[backend].match(cols["mycase"].type) assert cols["expr"].expression == "case when 1 then 1 else 0 end" - db.session.delete(table) - @patch("superset.models.core.Database.db_engine_spec", BigQueryEngineSpec) def test_labels_expected_on_mutated_query(self): query_obj = { @@ -661,51 +688,90 @@ def test_filter_on_text_column(text_column_table): assert result_object.df["count"][0] == 1 -def test_should_generate_closed_and_open_time_filter_range(): - with app.app_context(): - if backend() != "postgresql": - pytest.skip(f"{backend()} has different dialect for datetime column") - - table = SqlaTable( - table_name="temporal_column_table", - sql=( - "SELECT '2021-12-31'::timestamp as datetime_col " - "UNION SELECT '2022-01-01'::timestamp " - "UNION SELECT '2022-03-10'::timestamp " - "UNION SELECT '2023-01-01'::timestamp " - "UNION SELECT '2023-03-10'::timestamp " - ), - database=get_example_database(), - ) - TableColumn( - column_name="datetime_col", - type="TIMESTAMP", - table=table, - is_dttm=True, - ) - SqlMetric(metric_name="count", expression="count(*)", table=table) - result_object = table.query( +@only_postgresql +def test_should_generate_closed_and_open_time_filter_range(login_as_admin): + table = SqlaTable( + table_name="temporal_column_table", + sql=( + "SELECT '2021-12-31'::timestamp as datetime_col " + "UNION SELECT '2022-01-01'::timestamp " + "UNION SELECT '2022-03-10'::timestamp " + "UNION SELECT '2023-01-01'::timestamp " + "UNION SELECT '2023-03-10'::timestamp " + ), + database=get_example_database(), + ) + TableColumn( + column_name="datetime_col", + type="TIMESTAMP", + table=table, + is_dttm=True, + ) + SqlMetric(metric_name="count", expression="count(*)", table=table) + result_object = table.query( + { + "metrics": ["count"], + "is_timeseries": False, + "filter": [], + "from_dttm": datetime(2022, 1, 1), + "to_dttm": datetime(2023, 1, 1), + "granularity": "datetime_col", + } + ) + """ >>> result_object.query + SELECT count(*) AS count + FROM + (SELECT '2021-12-31'::timestamp as datetime_col + UNION SELECT '2022-01-01'::timestamp + UNION SELECT '2022-03-10'::timestamp + UNION SELECT '2023-01-01'::timestamp + UNION SELECT '2023-03-10'::timestamp) AS virtual_table + WHERE datetime_col >= TO_TIMESTAMP('2022-01-01 00:00:00.000000', 'YYYY-MM-DD HH24:MI:SS.US') + AND datetime_col < TO_TIMESTAMP('2023-01-01 00:00:00.000000', 'YYYY-MM-DD HH24:MI:SS.US') + """ + assert result_object.df.iloc[0]["count"] == 2 + + +def test_none_operand_in_filter(login_as_admin, physical_dataset): + expected_results = [ + { + "operator": FilterOperator.EQUALS.value, + "count": 10, + "sql_should_contain": "COL4 IS NULL", + }, + { + "operator": FilterOperator.NOT_EQUALS.value, + "count": 0, + "sql_should_contain": "COL4 IS NOT NULL", + }, + ] + for expected in expected_results: + result = physical_dataset.query( { "metrics": ["count"], + "filter": [{"col": "col4", "val": None, "op": expected["operator"]}], "is_timeseries": False, - "filter": [], - "from_dttm": datetime(2022, 1, 1), - "to_dttm": datetime(2023, 1, 1), - "granularity": "datetime_col", } ) - """ >>> result_object.query - SELECT count(*) AS count - FROM - (SELECT '2021-12-31'::timestamp as datetime_col - UNION SELECT '2022-01-01'::timestamp - UNION SELECT '2022-03-10'::timestamp - UNION SELECT '2023-01-01'::timestamp - UNION SELECT '2023-03-10'::timestamp) AS virtual_table - WHERE datetime_col >= TO_TIMESTAMP('2022-01-01 00:00:00.000000', 'YYYY-MM-DD HH24:MI:SS.US') - AND datetime_col < TO_TIMESTAMP('2023-01-01 00:00:00.000000', 'YYYY-MM-DD HH24:MI:SS.US') - """ - assert result_object.df.iloc[0]["count"] == 2 + assert result.df["count"][0] == expected["count"] + assert expected["sql_should_contain"] in result.query.upper() + + with pytest.raises(QueryObjectValidationError): + for flt in [ + FilterOperator.GREATER_THAN, + FilterOperator.LESS_THAN, + FilterOperator.GREATER_THAN_OR_EQUALS, + FilterOperator.LESS_THAN_OR_EQUALS, + FilterOperator.LIKE, + FilterOperator.ILIKE, + ]: + physical_dataset.query( + { + "metrics": ["count"], + "filter": [{"col": "col4", "val": None, "op": flt.value}], + "is_timeseries": False, + } + ) @pytest.mark.parametrize( @@ -738,7 +804,7 @@ def test__normalize_prequery_result_type( def _convert_dttm( target_type: str, dttm: datetime, db_extra: Optional[Dict[str, Any]] = None ) -> Optional[str]: - if target_type.upper() == TemporalType.TIMESTAMP: + if target_type.upper() == "TIMESTAMP": return f"""TIME_PARSE('{dttm.isoformat(timespec="seconds")}')""" return None @@ -797,3 +863,26 @@ def _convert_dttm( assert str(normalized) == str(result) else: assert normalized == result + + +def test__temporal_range_operator_in_adhoc_filter(app_context, physical_dataset): + result = physical_dataset.query( + { + "columns": ["col1", "col2"], + "filter": [ + { + "col": "col5", + "val": "2000-01-05 : 2000-01-06", + "op": FilterOperator.TEMPORAL_RANGE.value, + }, + { + "col": "col6", + "val": "2002-05-11 : 2002-05-12", + "op": FilterOperator.TEMPORAL_RANGE.value, + }, + ], + "is_timeseries": False, + } + ) + df = pd.DataFrame(index=[0], data={"col1": 4, "col2": "e"}) + assert df.equals(result.df) diff --git a/tests/integration_tests/sqllab_tests.py b/tests/integration_tests/sqllab_tests.py index 7ded842ef7afd..19e397e8f6961 100644 --- a/tests/integration_tests/sqllab_tests.py +++ b/tests/integration_tests/sqllab_tests.py @@ -18,6 +18,7 @@ """Unit tests for Sql Lab""" import json from datetime import datetime, timedelta +from math import ceil, floor import pytest from celery.exceptions import SoftTimeLimitExceeded @@ -65,12 +66,13 @@ class TestSqlLab(SupersetTestCase): """Testings for Sql Lab""" + @pytest.mark.usefixtures("load_birth_names_data") def run_some_queries(self): db.session.query(Query).delete() db.session.commit() self.run_sql(QUERY_1, client_id="client_id_1", username="admin") - self.run_sql(QUERY_2, client_id="client_id_3", username="admin") - self.run_sql(QUERY_3, client_id="client_id_2", username="gamma_sqllab") + self.run_sql(QUERY_2, client_id="client_id_2", username="admin") + self.run_sql(QUERY_3, client_id="client_id_3", username="gamma_sqllab") self.logout() def tearDown(self): @@ -89,7 +91,7 @@ def test_sql_json(self): data = self.run_sql("SELECT * FROM birth_names LIMIT 10", "1") self.assertLess(0, len(data["data"])) - data = self.run_sql("SELECT * FROM unexistant_table", "2") + data = self.run_sql("SELECT * FROM nonexistent_table", "2") if backend() == "presto": assert ( data["errors"][0]["error_type"] @@ -205,19 +207,21 @@ def test_sql_json_cta_dynamic_db(self, ctas_method): # assertions db.session.commit() examples_db = get_example_database() - engine = examples_db.get_sqla_engine() - data = engine.execute( - f"SELECT * FROM admin_database.{tmp_table_name}" - ).fetchall() - names_count = engine.execute(f"SELECT COUNT(*) FROM birth_names").first() - self.assertEqual( - names_count[0], len(data) - ) # SQL_MAX_ROW not applied due to the SQLLAB_CTAS_NO_LIMIT set to True - - # cleanup - engine.execute(f"DROP {ctas_method} admin_database.{tmp_table_name}") - examples_db.allow_ctas = old_allow_ctas - db.session.commit() + with examples_db.get_sqla_engine_with_context() as engine: + data = engine.execute( + f"SELECT * FROM admin_database.{tmp_table_name}" + ).fetchall() + names_count = engine.execute( + f"SELECT COUNT(*) FROM birth_names" + ).first() + self.assertEqual( + names_count[0], len(data) + ) # SQL_MAX_ROW not applied due to the SQLLAB_CTAS_NO_LIMIT set to True + + # cleanup + engine.execute(f"DROP {ctas_method} admin_database.{tmp_table_name}") + examples_db.allow_ctas = old_allow_ctas + db.session.commit() @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_multi_sql(self): @@ -253,6 +257,22 @@ def test_sql_json_has_access(self): db.session.commit() self.assertLess(0, len(data["data"])) + def test_sqllab_has_access(self): + for username in ("admin", "gamma_sqllab"): + self.login(username) + for endpoint in ("/superset/sqllab/", "/superset/sqllab/history/"): + resp = self.client.get(endpoint) + self.assertEqual(200, resp.status_code) + + self.logout() + + def test_sqllab_no_access(self): + self.login("gamma") + for endpoint in ("/superset/sqllab/", "/superset/sqllab/history/"): + resp = self.client.get(endpoint) + # Redirects to the main page + self.assertEqual(302, resp.status_code) + def test_sql_json_schema_access(self): examples_db = get_example_database() db_backend = examples_db.backend @@ -273,9 +293,10 @@ def test_sql_json_schema_access(self): "SchemaUser", ["SchemaPermission", "Gamma", "sql_lab"] ) - examples_db.get_sqla_engine().execute( - f"CREATE TABLE IF NOT EXISTS {CTAS_SCHEMA_NAME}.test_table AS SELECT 1 as c1, 2 as c2" - ) + with examples_db.get_sqla_engine_with_context() as engine: + engine.execute( + f"CREATE TABLE IF NOT EXISTS {CTAS_SCHEMA_NAME}.test_table AS SELECT 1 as c1, 2 as c2" + ) data = self.run_sql( f"SELECT * FROM {CTAS_SCHEMA_NAME}.test_table", "3", username="SchemaUser" @@ -301,9 +322,8 @@ def test_sql_json_schema_access(self): self.assertEqual(1, len(data["data"])) db.session.query(Query).delete() - get_example_database().get_sqla_engine().execute( - f"DROP TABLE IF EXISTS {CTAS_SCHEMA_NAME}.test_table" - ) + with get_example_database().get_sqla_engine_with_context() as engine: + engine.execute(f"DROP TABLE IF EXISTS {CTAS_SCHEMA_NAME}.test_table") db.session.commit() def test_queries_endpoint(self): @@ -405,22 +425,17 @@ def test_search_query_on_text(self): self.assertEqual(2, len(data)) self.assertIn("birth", data[0]["sql"]) - def test_search_query_on_time(self): + def test_search_query_filter_by_time(self): self.run_some_queries() self.login("admin") - first_query_time = ( - db.session.query(Query).filter_by(sql=QUERY_1).one() - ).start_time - second_query_time = ( - db.session.query(Query).filter_by(sql=QUERY_3).one() - ).start_time - # Test search queries on time filter - from_time = "from={}".format(int(first_query_time)) - to_time = "to={}".format(int(second_query_time)) - params = [from_time, to_time] - resp = self.get_resp("/superset/search_queries?" + "&".join(params)) - data = json.loads(resp) - self.assertEqual(2, len(data)) + from_time = floor( + (db.session.query(Query).filter_by(sql=QUERY_1).one()).start_time + ) + to_time = ceil( + (db.session.query(Query).filter_by(sql=QUERY_2).one()).start_time + ) + url = f"/superset/search_queries?from={from_time}&to={to_time}" + assert len(self.client.get(url).json) == 2 def test_search_query_only_owned(self) -> None: """ @@ -523,12 +538,10 @@ def test_sqllab_viz_bad_payload(self): def test_sqllab_table_viz(self): self.login("admin") examples_db = get_example_database() - examples_db.get_sqla_engine().execute( - "DROP TABLE IF EXISTS test_sqllab_table_viz" - ) - examples_db.get_sqla_engine().execute( - "CREATE TABLE test_sqllab_table_viz AS SELECT 2 as col" - ) + with examples_db.get_sqla_engine_with_context() as engine: + engine.execute("DROP TABLE IF EXISTS test_sqllab_table_viz") + engine.execute("CREATE TABLE test_sqllab_table_viz AS SELECT 2 as col") + examples_dbid = examples_db.id payload = { @@ -546,9 +559,9 @@ def test_sqllab_table_viz(self): table = db.session.query(SqlaTable).filter_by(id=table_id).one() self.assertEqual([owner.username for owner in table.owners], ["admin"]) db.session.delete(table) - get_example_database().get_sqla_engine().execute( - "DROP TABLE test_sqllab_table_viz" - ) + + with get_example_database().get_sqla_engine_with_context() as engine: + engine.execute("DROP TABLE test_sqllab_table_viz") db.session.commit() @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @@ -736,7 +749,7 @@ def test_execute_sql_statements(self, mock_execute_sql_statement, mock_get_query mock_query = mock.MagicMock() mock_query.database.allow_run_async = False mock_cursor = mock.MagicMock() - mock_query.database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value = ( + mock_query.database.get_raw_connection().__enter__().cursor.return_value = ( mock_cursor ) mock_query.database.db_engine_spec.run_multiple_statements_as_one = False @@ -789,7 +802,7 @@ def test_execute_sql_statements_no_results_backend( mock_query = mock.MagicMock() mock_query.database.allow_run_async = True mock_cursor = mock.MagicMock() - mock_query.database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value = ( + mock_query.database.get_raw_connection().__enter__().cursor.return_value = ( mock_cursor ) mock_query.database.db_engine_spec.run_multiple_statements_as_one = False @@ -839,7 +852,7 @@ def test_execute_sql_statements_ctas( mock_query = mock.MagicMock() mock_query.database.allow_run_async = False mock_cursor = mock.MagicMock() - mock_query.database.get_sqla_engine.return_value.raw_connection.return_value.cursor.return_value = ( + mock_query.database.get_raw_connection().__enter__().cursor.return_value = ( mock_cursor ) mock_query.database.db_engine_spec.run_multiple_statements_as_one = False diff --git a/tests/integration_tests/strategy_tests.py b/tests/integration_tests/strategy_tests.py index f31489bb04569..e54ae865e3c15 100644 --- a/tests/integration_tests/strategy_tests.py +++ b/tests/integration_tests/strategy_tests.py @@ -35,7 +35,7 @@ from superset import db from superset.models.core import Log -from superset.models.tags import get_tag, ObjectTypes, TaggedObject, TagTypes +from superset.tags.models import get_tag, ObjectTypes, TaggedObject, TagTypes from superset.tasks.cache import ( DashboardTagsStrategy, TopNDashboardsStrategy, diff --git a/tests/integration_tests/superset_test_config.py b/tests/integration_tests/superset_test_config.py index 10d81a2cf1986..19c2cc000f545 100644 --- a/tests/integration_tests/superset_test_config.py +++ b/tests/integration_tests/superset_test_config.py @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. # type: ignore +import logging import math from copy import copy from datetime import timedelta @@ -24,6 +25,12 @@ CustomPrestoTemplateProcessor, ) +logging.getLogger("flask_appbuilder.baseviews").setLevel(logging.WARNING) +logging.getLogger("flask_appbuilder.base").setLevel(logging.WARNING) +logging.getLogger("flask_appbuilder.api").setLevel(logging.WARNING) +logging.getLogger("flask_appbuilder.security.sqla.manager").setLevel(logging.WARNING) +logging.getLogger("sqlalchemy.engine.Engine").setLevel(logging.WARNING) + AUTH_USER_REGISTRATION_ROLE = "alpha" SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join( DATA_DIR, "unittests.integration_tests.db" @@ -63,6 +70,8 @@ "ENABLE_TEMPLATE_PROCESSING": True, "ALERT_REPORTS": True, "DASHBOARD_NATIVE_FILTERS": True, + "DRILL_TO_DETAIL": True, + "HORIZONTAL_FILTER_BAR": True, } WEBDRIVER_BASEURL = "http://0.0.0.0:8081/" diff --git a/tests/integration_tests/tagging_tests.py b/tests/integration_tests/tagging_tests.py index 9ae8764d40d55..4ee10041d2c53 100644 --- a/tests/integration_tests/tagging_tests.py +++ b/tests/integration_tests/tagging_tests.py @@ -15,11 +15,33 @@ # specific language governing permissions and limitations # under the License. +from unittest import mock + +import pytest + +from superset.connectors.sqla.models import SqlaTable +from superset.extensions import db +from superset.models.core import FavStar +from superset.models.dashboard import Dashboard +from superset.models.slice import Slice +from superset.models.sql_lab import SavedQuery +from superset.tags.models import TaggedObject +from superset.utils.core import DatasourceType +from superset.utils.database import get_main_database from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.conftest import with_feature_flags +from tests.integration_tests.fixtures.tags import with_tagging_system_feature class TestTagging(SupersetTestCase): + def query_tagged_object_table(self): + query = db.session.query(TaggedObject).all() + return query + + def clear_tagged_object_table(self): + db.session.query(TaggedObject).delete() + db.session.commit() + @with_feature_flags(TAGGING_SYSTEM=False) def test_tag_view_disabled(self): self.login("admin") @@ -31,3 +53,257 @@ def test_tag_view_enabled(self): self.login("admin") response = self.client.get("/tagview/tags/suggestions/") self.assertNotEqual(404, response.status_code) + + @pytest.mark.usefixtures("with_tagging_system_feature") + def test_dataset_tagging(self): + """ + Test to make sure that when a new dataset is created, + a corresponding tag in the tagged_objects table + is created + """ + + # Remove all existing rows in the tagged_object table + self.clear_tagged_object_table() + + # Test to make sure nothing is in the tagged_object table + self.assertEqual([], self.query_tagged_object_table()) + + # Create a dataset and add it to the db + test_dataset = SqlaTable( + table_name="foo", + schema=None, + owners=[], + database=get_main_database(), + sql=None, + extra='{"certification": 1}', + ) + db.session.add(test_dataset) + db.session.commit() + + # Test to make sure that a dataset tag was added to the tagged_object table + tags = self.query_tagged_object_table() + self.assertEqual(1, len(tags)) + self.assertEqual("ObjectTypes.dataset", str(tags[0].object_type)) + self.assertEqual(test_dataset.id, tags[0].object_id) + + # Cleanup the db + db.session.delete(test_dataset) + db.session.commit() + + # Test to make sure the tag is deleted when the associated object is deleted + self.assertEqual([], self.query_tagged_object_table()) + + @pytest.mark.usefixtures("with_tagging_system_feature") + def test_chart_tagging(self): + """ + Test to make sure that when a new chart is created, + a corresponding tag in the tagged_objects table + is created + """ + + # Remove all existing rows in the tagged_object table + self.clear_tagged_object_table() + + # Test to make sure nothing is in the tagged_object table + self.assertEqual([], self.query_tagged_object_table()) + + # Create a chart and add it to the db + test_chart = Slice( + slice_name="test_chart", + datasource_type=DatasourceType.TABLE, + viz_type="bubble", + datasource_id=1, + id=1, + ) + db.session.add(test_chart) + db.session.commit() + + # Test to make sure that a chart tag was added to the tagged_object table + tags = self.query_tagged_object_table() + self.assertEqual(1, len(tags)) + self.assertEqual("ObjectTypes.chart", str(tags[0].object_type)) + self.assertEqual(test_chart.id, tags[0].object_id) + + # Cleanup the db + db.session.delete(test_chart) + db.session.commit() + + # Test to make sure the tag is deleted when the associated object is deleted + self.assertEqual([], self.query_tagged_object_table()) + + @pytest.mark.usefixtures("with_tagging_system_feature") + def test_dashboard_tagging(self): + """ + Test to make sure that when a new dashboard is created, + a corresponding tag in the tagged_objects table + is created + """ + + # Remove all existing rows in the tagged_object table + self.clear_tagged_object_table() + + # Test to make sure nothing is in the tagged_object table + self.assertEqual([], self.query_tagged_object_table()) + + # Create a dashboard and add it to the db + test_dashboard = Dashboard() + test_dashboard.dashboard_title = "test_dashboard" + test_dashboard.slug = "test_slug" + test_dashboard.slices = [] + test_dashboard.published = True + + db.session.add(test_dashboard) + db.session.commit() + + # Test to make sure that a dashboard tag was added to the tagged_object table + tags = self.query_tagged_object_table() + self.assertEqual(1, len(tags)) + self.assertEqual("ObjectTypes.dashboard", str(tags[0].object_type)) + self.assertEqual(test_dashboard.id, tags[0].object_id) + + # Cleanup the db + db.session.delete(test_dashboard) + db.session.commit() + + # Test to make sure the tag is deleted when the associated object is deleted + self.assertEqual([], self.query_tagged_object_table()) + + @pytest.mark.usefixtures("with_tagging_system_feature") + def test_saved_query_tagging(self): + """ + Test to make sure that when a new saved query is + created, a corresponding tag in the tagged_objects + table is created + """ + + # Remove all existing rows in the tagged_object table + self.clear_tagged_object_table() + + # Test to make sure nothing is in the tagged_object table + self.assertEqual([], self.query_tagged_object_table()) + + # Create a saved query and add it to the db + test_saved_query = SavedQuery(id=1, label="test saved query") + db.session.add(test_saved_query) + db.session.commit() + + # Test to make sure that a saved query tag was added to the tagged_object table + tags = self.query_tagged_object_table() + + self.assertEqual(2, len(tags)) + + self.assertEqual("ObjectTypes.query", str(tags[0].object_type)) + self.assertEqual("owner:None", str(tags[0].tag.name)) + self.assertEqual("TagTypes.owner", str(tags[0].tag.type)) + self.assertEqual(test_saved_query.id, tags[0].object_id) + + self.assertEqual("ObjectTypes.query", str(tags[1].object_type)) + self.assertEqual("type:query", str(tags[1].tag.name)) + self.assertEqual("TagTypes.type", str(tags[1].tag.type)) + self.assertEqual(test_saved_query.id, tags[1].object_id) + + # Cleanup the db + db.session.delete(test_saved_query) + db.session.commit() + + # Test to make sure the tag is deleted when the associated object is deleted + self.assertEqual([], self.query_tagged_object_table()) + + @pytest.mark.usefixtures("with_tagging_system_feature") + def test_favorite_tagging(self): + """ + Test to make sure that when a new favorite object is + created, a corresponding tag in the tagged_objects + table is created + """ + + # Remove all existing rows in the tagged_object table + self.clear_tagged_object_table() + + # Test to make sure nothing is in the tagged_object table + self.assertEqual([], self.query_tagged_object_table()) + + # Create a favorited object and add it to the db + test_saved_query = FavStar(user_id=1, class_name="slice", obj_id=1) + db.session.add(test_saved_query) + db.session.commit() + + # Test to make sure that a favorited object tag was added to the tagged_object table + tags = self.query_tagged_object_table() + self.assertEqual(1, len(tags)) + self.assertEqual("ObjectTypes.chart", str(tags[0].object_type)) + self.assertEqual(test_saved_query.obj_id, tags[0].object_id) + + # Cleanup the db + db.session.delete(test_saved_query) + db.session.commit() + + # Test to make sure the tag is deleted when the associated object is deleted + self.assertEqual([], self.query_tagged_object_table()) + + @with_feature_flags(TAGGING_SYSTEM=False) + def test_tagging_system(self): + """ + Test to make sure that when the TAGGING_SYSTEM + feature flag is false, that no tags are created + """ + + # Remove all existing rows in the tagged_object table + self.clear_tagged_object_table() + + # Test to make sure nothing is in the tagged_object table + self.assertEqual([], self.query_tagged_object_table()) + + # Create a dataset and add it to the db + test_dataset = SqlaTable( + table_name="foo", + schema=None, + owners=[], + database=get_main_database(), + sql=None, + extra='{"certification": 1}', + ) + + # Create a chart and add it to the db + test_chart = Slice( + slice_name="test_chart", + datasource_type=DatasourceType.TABLE, + viz_type="bubble", + datasource_id=1, + id=1, + ) + + # Create a dashboard and add it to the db + test_dashboard = Dashboard() + test_dashboard.dashboard_title = "test_dashboard" + test_dashboard.slug = "test_slug" + test_dashboard.slices = [] + test_dashboard.published = True + + # Create a saved query and add it to the db + test_saved_query = SavedQuery(id=1, label="test saved query") + + # Create a favorited object and add it to the db + test_favorited_object = FavStar(user_id=1, class_name="slice", obj_id=1) + + db.session.add(test_dataset) + db.session.add(test_chart) + db.session.add(test_dashboard) + db.session.add(test_saved_query) + db.session.add(test_favorited_object) + db.session.commit() + + # Test to make sure that no tags were added to the tagged_object table + tags = self.query_tagged_object_table() + self.assertEqual(0, len(tags)) + + # Cleanup the db + db.session.delete(test_dataset) + db.session.delete(test_chart) + db.session.delete(test_dashboard) + db.session.delete(test_saved_query) + db.session.delete(test_favorited_object) + db.session.commit() + + # Test to make sure all the tags are deleted when the associated objects are deleted + self.assertEqual([], self.query_tagged_object_table()) diff --git a/tests/integration_tests/tasks/async_queries_tests.py b/tests/integration_tests/tasks/async_queries_tests.py index 596505a32a485..20d0f39eea0f4 100644 --- a/tests/integration_tests/tasks/async_queries_tests.py +++ b/tests/integration_tests/tasks/async_queries_tests.py @@ -28,10 +28,10 @@ from superset.extensions import async_query_manager, security_manager from superset.tasks import async_queries from superset.tasks.async_queries import ( - ensure_user_is_set, load_chart_data_into_cache, load_explore_json_into_cache, ) +from superset.utils.core import get_user_id from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.fixtures.birth_names_dashboard import ( load_birth_names_dashboard_with_slices, @@ -57,12 +57,7 @@ def test_load_chart_data_into_cache(self, mock_set_form_data, mock_update_job): "errors": [], } - with mock.patch.object( - async_queries, "ensure_user_is_set" - ) as ensure_user_is_set: - load_chart_data_into_cache(job_metadata, query_context) - - ensure_user_is_set.assert_called_once_with(user.id) + load_chart_data_into_cache(job_metadata, query_context) mock_set_form_data.assert_called_once_with(query_context) mock_update_job.assert_called_once_with( job_metadata, "done", result_url=mock.ANY @@ -84,11 +79,7 @@ def test_load_chart_data_into_cache_error(self, mock_update_job, mock_run_comman "errors": [], } with pytest.raises(ChartDataQueryFailedError): - with mock.patch.object( - async_queries, "ensure_user_is_set" - ) as ensure_user_is_set: - load_chart_data_into_cache(job_metadata, query_context) - ensure_user_is_set.assert_called_once_with(user.id) + load_chart_data_into_cache(job_metadata, query_context) mock_run_command.assert_called_once_with(cache=True) errors = [{"message": "Error: foo"}] @@ -114,11 +105,11 @@ def test_soft_timeout_load_chart_data_into_cache( with pytest.raises(SoftTimeLimitExceeded): with mock.patch.object( async_queries, - "ensure_user_is_set", - ) as ensure_user_is_set: - ensure_user_is_set.side_effect = SoftTimeLimitExceeded() + "set_form_data", + ) as set_form_data: + set_form_data.side_effect = SoftTimeLimitExceeded() load_chart_data_into_cache(job_metadata, form_data) - ensure_user_is_set.assert_called_once_with(user.id, "error", errors=errors) + set_form_data.assert_called_once_with(form_data, "error", errors=errors) @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @mock.patch.object(async_query_manager, "update_job") @@ -144,12 +135,7 @@ def test_load_explore_json_into_cache(self, mock_update_job): "errors": [], } - with mock.patch.object( - async_queries, "ensure_user_is_set" - ) as ensure_user_is_set: - load_explore_json_into_cache(job_metadata, form_data) - - ensure_user_is_set.assert_called_once_with(user.id) + load_explore_json_into_cache(job_metadata, form_data) mock_update_job.assert_called_once_with( job_metadata, "done", result_url=mock.ANY ) @@ -171,11 +157,7 @@ def test_load_explore_json_into_cache_error( } with pytest.raises(SupersetException): - with mock.patch.object( - async_queries, "ensure_user_is_set" - ) as ensure_user_is_set: - load_explore_json_into_cache(job_metadata, form_data) - ensure_user_is_set.assert_called_once_with(user.id) + load_explore_json_into_cache(job_metadata, form_data) mock_set_form_data.assert_called_once_with(form_data) errors = ["The dataset associated with this chart no longer exists"] @@ -201,49 +183,8 @@ def test_soft_timeout_load_explore_json_into_cache( with pytest.raises(SoftTimeLimitExceeded): with mock.patch.object( async_queries, - "ensure_user_is_set", - ) as ensure_user_is_set: - ensure_user_is_set.side_effect = SoftTimeLimitExceeded() + "set_form_data", + ) as set_form_data: + set_form_data.side_effect = SoftTimeLimitExceeded() load_explore_json_into_cache(job_metadata, form_data) - ensure_user_is_set.assert_called_once_with(user.id, "error", errors=errors) - - def test_ensure_user_is_set(self): - g_user_is_set = hasattr(g, "user") - original_g_user = g.user if g_user_is_set else None - - if g_user_is_set: - del g.user - - self.assertFalse(hasattr(g, "user")) - ensure_user_is_set(1) - self.assertTrue(hasattr(g, "user")) - self.assertFalse(g.user.is_anonymous) - self.assertEqual("1", g.user.get_id()) - - del g.user - - self.assertFalse(hasattr(g, "user")) - ensure_user_is_set(None) - self.assertTrue(hasattr(g, "user")) - self.assertTrue(g.user.is_anonymous) - self.assertEqual(None, g.user.get_id()) - - del g.user - - g.user = security_manager.get_user_by_id(2) - self.assertEqual("2", g.user.get_id()) - - ensure_user_is_set(1) - self.assertTrue(hasattr(g, "user")) - self.assertFalse(g.user.is_anonymous) - self.assertEqual("2", g.user.get_id()) - - ensure_user_is_set(None) - self.assertTrue(hasattr(g, "user")) - self.assertFalse(g.user.is_anonymous) - self.assertEqual("2", g.user.get_id()) - - if g_user_is_set: - g.user = original_g_user - else: - del g.user + set_form_data.assert_called_once_with(form_data, "error", errors=errors) diff --git a/tests/integration_tests/test_app.py b/tests/integration_tests/test_app.py index 2ca39ba16bbca..fb7b47b67cb96 100644 --- a/tests/integration_tests/test_app.py +++ b/tests/integration_tests/test_app.py @@ -14,11 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - -""" -Here is where we create the app which ends up being shared across all tests.integration_tests. A future -optimization will be to create a separate app instance for each test class. -""" from typing import TYPE_CHECKING from superset.app import create_app @@ -27,7 +22,6 @@ from typing import Any from flask.testing import FlaskClient -from superset.app import create_app app = create_app() diff --git a/tests/integration_tests/thumbnails_tests.py b/tests/integration_tests/thumbnails_tests.py index 5eabc4da00090..efa0d73cb49f0 100644 --- a/tests/integration_tests/thumbnails_tests.py +++ b/tests/integration_tests/thumbnails_tests.py @@ -16,11 +16,15 @@ # under the License. # from superset import db # from superset.models.dashboard import Dashboard + +import json import urllib.request from io import BytesIO +from typing import Tuple from unittest import skipUnless -from unittest.mock import ANY, call, patch +from unittest.mock import ANY, call, MagicMock, patch +import pytest from flask_testing import LiveServerTestCase from sqlalchemy.sql import func @@ -28,14 +32,22 @@ from superset.extensions import machine_auth_provider_factory from superset.models.dashboard import Dashboard from superset.models.slice import Slice +from superset.tasks.types import ExecutorType from superset.utils.screenshots import ChartScreenshot, DashboardScreenshot -from superset.utils.urls import get_url_host, get_url_path -from superset.utils.webdriver import WebDriverProxy +from superset.utils.urls import get_url_path +from superset.utils.webdriver import find_unexpected_errors, WebDriverProxy from tests.integration_tests.conftest import with_feature_flags +from tests.integration_tests.fixtures.birth_names_dashboard import ( + load_birth_names_dashboard_with_slices, + load_birth_names_data, +) from tests.integration_tests.test_app import app from .base_tests import SupersetTestCase +CHART_URL = "/api/v1/chart/" +DASHBOARD_URL = "/api/v1/dashboard/" + class TestThumbnailsSeleniumLive(LiveServerTestCase): def create_app(self): @@ -53,15 +65,83 @@ def test_get_async_dashboard_screenshot(self): """ Thumbnails: Simple get async dashboard screenshot """ - dashboard = db.session.query(Dashboard).all()[0] with patch("superset.dashboards.api.DashboardRestApi.get") as mock_get: + rv = self.client.get(DASHBOARD_URL) + resp = json.loads(rv.data.decode("utf-8")) + thumbnail_url = resp["result"][0]["thumbnail_url"] + response = self.url_open_auth( "admin", - f"api/v1/dashboard/{dashboard.id}/thumbnail/{dashboard.digest}/", + thumbnail_url, ) self.assertEqual(response.getcode(), 202) +class TestWebDriverScreenshotErrorDetector(SupersetTestCase): + @patch("superset.utils.webdriver.WebDriverWait") + @patch("superset.utils.webdriver.firefox") + @patch("superset.utils.webdriver.find_unexpected_errors") + def test_not_call_find_unexpected_errors_if_feature_disabled( + self, mock_find_unexpected_errors, mock_firefox, mock_webdriver_wait + ): + webdriver_proxy = WebDriverProxy("firefox") + user = security_manager.get_user_by_username( + app.config["THUMBNAIL_SELENIUM_USER"] + ) + url = get_url_path("Superset.dashboard", dashboard_id_or_slug=1) + webdriver_proxy.get_screenshot(url, "grid-container", user=user) + + assert not mock_find_unexpected_errors.called + + @patch("superset.utils.webdriver.WebDriverWait") + @patch("superset.utils.webdriver.firefox") + @patch("superset.utils.webdriver.find_unexpected_errors") + def test_call_find_unexpected_errors_if_feature_enabled( + self, mock_find_unexpected_errors, mock_firefox, mock_webdriver_wait + ): + app.config["SCREENSHOT_REPLACE_UNEXPECTED_ERRORS"] = True + webdriver_proxy = WebDriverProxy("firefox") + user = security_manager.get_user_by_username( + app.config["THUMBNAIL_SELENIUM_USER"] + ) + url = get_url_path("Superset.dashboard", dashboard_id_or_slug=1) + webdriver_proxy.get_screenshot(url, "grid-container", user=user) + + assert mock_find_unexpected_errors.called + + app.config["SCREENSHOT_REPLACE_UNEXPECTED_ERRORS"] = False + + def test_find_unexpected_errors_no_alert(self): + webdriver = MagicMock() + + webdriver.find_elements.return_value = [] + + unexpected_errors = find_unexpected_errors(driver=webdriver) + assert len(unexpected_errors) == 0 + + assert "alert" in webdriver.find_elements.call_args_list[0][0][1] + + @patch("superset.utils.webdriver.WebDriverWait") + def test_find_unexpected_errors(self, mock_webdriver_wait): + webdriver = MagicMock() + alert_div = MagicMock() + + webdriver.find_elements.return_value = [alert_div] + alert_div.find_elements.return_value = MagicMock() + + unexpected_errors = find_unexpected_errors(driver=webdriver) + assert len(unexpected_errors) == 1 + + # attempt to find alerts + assert "alert" in webdriver.find_elements.call_args_list[0][0][1] + # attempt to click on "See more" buttons + assert "button" in alert_div.find_element.call_args_list[0][0][1] + # Wait for error modal to show up and to hide + assert 2 == len(mock_webdriver_wait.call_args_list) + # replace the text in alert div, eg, "unexpected errors" + assert alert_div == webdriver.execute_script.call_args_list[0][0][1] + + class TestWebDriverProxy(SupersetTestCase): @patch("superset.utils.webdriver.WebDriverWait") @patch("superset.utils.webdriver.firefox") @@ -100,7 +180,7 @@ def test_screenshot_selenium_load_wait(self, mock_webdriver, mock_webdriver_wait ) url = get_url_path("Superset.slice", slice_id=1, standalone="true") webdriver.get_screenshot(url, "chart-container", user=user) - assert mock_webdriver_wait.call_args_list[1] == call(ANY, 15) + assert mock_webdriver_wait.call_args_list[2] == call(ANY, 15) @patch("superset.utils.webdriver.WebDriverWait") @patch("superset.utils.webdriver.firefox") @@ -121,50 +201,82 @@ def test_screenshot_selenium_animation_wait( class TestThumbnails(SupersetTestCase): mock_image = b"bytes mock image" + digest_return_value = "foo_bar" + digest_hash = "5c7d96a3dd7a87850a2ef34087565a6e" + def _get_id_and_thumbnail_url(self, url: str) -> Tuple[int, str]: + rv = self.client.get(url) + resp = json.loads(rv.data.decode("utf-8")) + obj = resp["result"][0] + return obj["id"], obj["thumbnail_url"] + + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(THUMBNAILS=False) def test_dashboard_thumbnail_disabled(self): """ Thumbnails: Dashboard thumbnail disabled """ - dashboard = db.session.query(Dashboard).all()[0] self.login(username="admin") - uri = f"api/v1/dashboard/{dashboard.id}/thumbnail/{dashboard.digest}/" - rv = self.client.get(uri) + _, thumbnail_url = self._get_id_and_thumbnail_url(DASHBOARD_URL) + rv = self.client.get(thumbnail_url) self.assertEqual(rv.status_code, 404) + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(THUMBNAILS=False) def test_chart_thumbnail_disabled(self): """ Thumbnails: Chart thumbnail disabled """ - chart = db.session.query(Slice).all()[0] self.login(username="admin") - uri = f"api/v1/chart/{chart}/thumbnail/{chart.digest}/" - rv = self.client.get(uri) + _, thumbnail_url = self._get_id_and_thumbnail_url(CHART_URL) + rv = self.client.get(thumbnail_url) self.assertEqual(rv.status_code, 404) + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(THUMBNAILS=True) - def test_get_async_dashboard_screenshot(self): + def test_get_async_dashboard_screenshot_as_selenium(self): """ - Thumbnails: Simple get async dashboard screenshot + Thumbnails: Simple get async dashboard screenshot as selenium user """ - dashboard = db.session.query(Dashboard).all()[0] - self.login(username="admin") - uri = f"api/v1/dashboard/{dashboard.id}/thumbnail/{dashboard.digest}/" + self.login(username="alpha") with patch( - "superset.tasks.thumbnails.cache_dashboard_thumbnail.delay" - ) as mock_task: - rv = self.client.get(uri) + "superset.thumbnails.digest._adjust_string_for_executor" + ) as mock_adjust_string: + mock_adjust_string.return_value = self.digest_return_value + _, thumbnail_url = self._get_id_and_thumbnail_url(DASHBOARD_URL) + assert self.digest_hash in thumbnail_url + assert mock_adjust_string.call_args[0][1] == ExecutorType.SELENIUM + assert mock_adjust_string.call_args[0][2] == "admin" + + rv = self.client.get(thumbnail_url) self.assertEqual(rv.status_code, 202) - expected_uri = f"{get_url_host()}superset/dashboard/{dashboard.id}/" - expected_digest = dashboard.digest - expected_kwargs = {"force": True} - mock_task.assert_called_with( - expected_uri, expected_digest, **expected_kwargs - ) + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + @with_feature_flags(THUMBNAILS=True) + def test_get_async_dashboard_screenshot_as_current_user(self): + """ + Thumbnails: Simple get async dashboard screenshot as current user + """ + username = "alpha" + self.login(username=username) + with patch.dict( + "superset.thumbnails.digest.current_app.config", + { + "THUMBNAIL_EXECUTE_AS": [ExecutorType.CURRENT_USER], + }, + ), patch( + "superset.thumbnails.digest._adjust_string_for_executor" + ) as mock_adjust_string: + mock_adjust_string.return_value = self.digest_return_value + _, thumbnail_url = self._get_id_and_thumbnail_url(DASHBOARD_URL) + assert self.digest_hash in thumbnail_url + assert mock_adjust_string.call_args[0][1] == ExecutorType.CURRENT_USER + assert mock_adjust_string.call_args[0][2] == username + rv = self.client.get(thumbnail_url) + self.assertEqual(rv.status_code, 202) + + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(THUMBNAILS=True) def test_get_async_dashboard_notfound(self): """ @@ -176,37 +288,62 @@ def test_get_async_dashboard_notfound(self): rv = self.client.get(uri) self.assertEqual(rv.status_code, 404) + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @skipUnless((is_feature_enabled("THUMBNAILS")), "Thumbnails feature") def test_get_async_dashboard_not_allowed(self): """ Thumbnails: Simple get async dashboard not allowed """ - dashboard = db.session.query(Dashboard).all()[0] self.login(username="gamma") - uri = f"api/v1/dashboard/{dashboard.id}/thumbnail/{dashboard.digest}/" - rv = self.client.get(uri) + _, thumbnail_url = self._get_id_and_thumbnail_url(DASHBOARD_URL) + rv = self.client.get(thumbnail_url) self.assertEqual(rv.status_code, 404) + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(THUMBNAILS=True) - def test_get_async_chart_screenshot(self): + def test_get_async_chart_screenshot_as_selenium(self): """ - Thumbnails: Simple get async chart screenshot + Thumbnails: Simple get async chart screenshot as selenium user """ - chart = db.session.query(Slice).all()[0] - self.login(username="admin") - uri = f"api/v1/chart/{chart.id}/thumbnail/{chart.digest}/" + self.login(username="alpha") with patch( - "superset.tasks.thumbnails.cache_chart_thumbnail.delay" - ) as mock_task: - rv = self.client.get(uri) + "superset.thumbnails.digest._adjust_string_for_executor" + ) as mock_adjust_string: + mock_adjust_string.return_value = self.digest_return_value + _, thumbnail_url = self._get_id_and_thumbnail_url(CHART_URL) + assert self.digest_hash in thumbnail_url + assert mock_adjust_string.call_args[0][1] == ExecutorType.SELENIUM + assert mock_adjust_string.call_args[0][2] == "admin" + + rv = self.client.get(thumbnail_url) self.assertEqual(rv.status_code, 202) - expected_uri = f"{get_url_host()}superset/slice/{chart.id}/?standalone=true" - expected_digest = chart.digest - expected_kwargs = {"force": True} - mock_task.assert_called_with( - expected_uri, expected_digest, **expected_kwargs - ) + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + @with_feature_flags(THUMBNAILS=True) + def test_get_async_chart_screenshot_as_current_user(self): + """ + Thumbnails: Simple get async chart screenshot as current user + """ + username = "alpha" + self.login(username=username) + with patch.dict( + "superset.thumbnails.digest.current_app.config", + { + "THUMBNAIL_EXECUTE_AS": [ExecutorType.CURRENT_USER], + }, + ), patch( + "superset.thumbnails.digest._adjust_string_for_executor" + ) as mock_adjust_string: + mock_adjust_string.return_value = self.digest_return_value + _, thumbnail_url = self._get_id_and_thumbnail_url(CHART_URL) + assert self.digest_hash in thumbnail_url + assert mock_adjust_string.call_args[0][1] == ExecutorType.CURRENT_USER + assert mock_adjust_string.call_args[0][2] == username + + rv = self.client.get(thumbnail_url) + self.assertEqual(rv.status_code, 202) + + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(THUMBNAILS=True) def test_get_async_chart_notfound(self): """ @@ -218,66 +355,62 @@ def test_get_async_chart_notfound(self): rv = self.client.get(uri) self.assertEqual(rv.status_code, 404) + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(THUMBNAILS=True) def test_get_cached_chart_wrong_digest(self): """ Thumbnails: Simple get chart with wrong digest """ - chart = db.session.query(Slice).all()[0] with patch.object( ChartScreenshot, "get_from_cache", return_value=BytesIO(self.mock_image) ): self.login(username="admin") - uri = f"api/v1/chart/{chart.id}/thumbnail/1234/" - rv = self.client.get(uri) + id_, thumbnail_url = self._get_id_and_thumbnail_url(CHART_URL) + rv = self.client.get(f"api/v1/chart/{id_}/thumbnail/1234/") self.assertEqual(rv.status_code, 302) - self.assertRedirects( - rv, f"api/v1/chart/{chart.id}/thumbnail/{chart.digest}/" - ) + self.assertEqual(rv.headers["Location"], thumbnail_url) + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(THUMBNAILS=True) def test_get_cached_dashboard_screenshot(self): """ Thumbnails: Simple get cached dashboard screenshot """ - dashboard = db.session.query(Dashboard).all()[0] with patch.object( DashboardScreenshot, "get_from_cache", return_value=BytesIO(self.mock_image) ): self.login(username="admin") - uri = f"api/v1/dashboard/{dashboard.id}/thumbnail/{dashboard.digest}/" - rv = self.client.get(uri) + _, thumbnail_url = self._get_id_and_thumbnail_url(DASHBOARD_URL) + rv = self.client.get(thumbnail_url) self.assertEqual(rv.status_code, 200) self.assertEqual(rv.data, self.mock_image) + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(THUMBNAILS=True) def test_get_cached_chart_screenshot(self): """ Thumbnails: Simple get cached chart screenshot """ - chart = db.session.query(Slice).all()[0] with patch.object( ChartScreenshot, "get_from_cache", return_value=BytesIO(self.mock_image) ): self.login(username="admin") - uri = f"api/v1/chart/{chart.id}/thumbnail/{chart.digest}/" - rv = self.client.get(uri) + id_, thumbnail_url = self._get_id_and_thumbnail_url(CHART_URL) + rv = self.client.get(thumbnail_url) self.assertEqual(rv.status_code, 200) self.assertEqual(rv.data, self.mock_image) + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @with_feature_flags(THUMBNAILS=True) def test_get_cached_dashboard_wrong_digest(self): """ Thumbnails: Simple get dashboard with wrong digest """ - dashboard = db.session.query(Dashboard).all()[0] with patch.object( DashboardScreenshot, "get_from_cache", return_value=BytesIO(self.mock_image) ): self.login(username="admin") - uri = f"api/v1/dashboard/{dashboard.id}/thumbnail/1234/" - rv = self.client.get(uri) + id_, thumbnail_url = self._get_id_and_thumbnail_url(DASHBOARD_URL) + rv = self.client.get(f"api/v1/dashboard/{id_}/thumbnail/1234/") self.assertEqual(rv.status_code, 302) - self.assertRedirects( - rv, f"api/v1/dashboard/{dashboard.id}/thumbnail/{dashboard.digest}/" - ) + self.assertEqual(rv.headers["Location"], thumbnail_url) diff --git a/tests/integration_tests/utils/decorators_tests.py b/tests/integration_tests/utils/decorators_tests.py deleted file mode 100644 index d0ab6f98434b3..0000000000000 --- a/tests/integration_tests/utils/decorators_tests.py +++ /dev/null @@ -1,61 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -from unittest.mock import call, Mock, patch - -import pytest -from flask import current_app - -from superset.utils import decorators -from tests.integration_tests.base_tests import SupersetTestCase - - -class UtilsDecoratorsTests(SupersetTestCase): - def test_debounce(self): - mock = Mock() - - @decorators.debounce() - def myfunc(arg1: int, arg2: int, kwarg1: str = "abc", kwarg2: int = 2): - mock(arg1, kwarg1) - return arg1 + arg2 + kwarg2 - - # should be called only once when arguments don't change - myfunc(1, 1) - myfunc(1, 1) - result = myfunc(1, 1) - mock.assert_called_once_with(1, "abc") - self.assertEqual(result, 4) - - # kwarg order shouldn't matter - myfunc(1, 0, kwarg2=2, kwarg1="haha") - result = myfunc(1, 0, kwarg1="haha", kwarg2=2) - mock.assert_has_calls([call(1, "abc"), call(1, "haha")]) - self.assertEqual(result, 3) - - def test_statsd_gauge(self): - @decorators.statsd_gauge("custom.prefix") - def my_func(fail: bool, *args, **kwargs): - if fail: - raise ValueError("Error") - return "OK" - - with patch.object(current_app.config["STATS_LOGGER"], "gauge") as mock: - my_func(False, 1, 2) - mock.assert_called_once_with("custom.prefix.ok", 1) - - with pytest.raises(ValueError): - my_func(True, 1, 2) - mock.assert_called_once_with("custom.prefix.error", 1) diff --git a/tests/integration_tests/utils_tests.py b/tests/integration_tests/utils_tests.py index 9b2a288964a7f..967a4e9388cf4 100644 --- a/tests/integration_tests/utils_tests.py +++ b/tests/integration_tests/utils_tests.py @@ -39,6 +39,7 @@ import tests.integration_tests.test_app from superset import app, db, security_manager +from superset.constants import NO_TIME_RANGE from superset.exceptions import CertificateException, SupersetException from superset.models.core import Database, Log from superset.models.dashboard import Dashboard @@ -62,7 +63,6 @@ merge_extra_filters, merge_extra_form_data, merge_request_params, - NO_TIME_RANGE, normalize_dttm_col, parse_ssl_cert, parse_js_uri_path_item, @@ -70,6 +70,7 @@ validate_json, zlib_compress, zlib_decompress, + DateColumn, ) from superset.utils.database import get_or_create_db from superset.utils import schema @@ -93,9 +94,10 @@ def test_json_int_dttm_ser(self): assert json_int_dttm_ser(datetime(1970, 1, 1)) == 0 assert json_int_dttm_ser(date(1970, 1, 1)) == 0 assert json_int_dttm_ser(dttm + timedelta(milliseconds=1)) == (ts + 1) + assert json_int_dttm_ser(np.int64(1)) == 1 with self.assertRaises(TypeError): - json_int_dttm_ser("this is not a date") + json_int_dttm_ser(np.datetime64()) def test_json_iso_dttm_ser(self): dttm = datetime(2020, 1, 1) @@ -104,19 +106,31 @@ def test_json_iso_dttm_ser(self): assert json_iso_dttm_ser(dttm) == dttm.isoformat() assert json_iso_dttm_ser(dt) == dt.isoformat() assert json_iso_dttm_ser(t) == t.isoformat() + assert json_iso_dttm_ser(np.int64(1)) == 1 + + assert ( + json_iso_dttm_ser(np.datetime64(), pessimistic=True) + == "Unserializable [<class 'numpy.datetime64'>]" + ) with self.assertRaises(TypeError): - json_iso_dttm_ser("this is not a date") + json_iso_dttm_ser(np.datetime64()) def test_base_json_conv(self): - assert isinstance(base_json_conv(np.bool_(1)), bool) is True - assert isinstance(base_json_conv(np.int64(1)), int) is True - assert isinstance(base_json_conv(np.array([1, 2, 3])), list) is True - assert isinstance(base_json_conv(set([1])), list) is True - assert isinstance(base_json_conv(Decimal("1.0")), float) is True - assert isinstance(base_json_conv(uuid.uuid4()), str) is True - assert isinstance(base_json_conv(time()), str) is True - assert isinstance(base_json_conv(timedelta(0)), str) is True + assert isinstance(base_json_conv(np.bool_(1)), bool) + assert isinstance(base_json_conv(np.int64(1)), int) + assert isinstance(base_json_conv(np.array([1, 2, 3])), list) + assert base_json_conv(np.array(None)) is None + assert isinstance(base_json_conv(set([1])), list) + assert isinstance(base_json_conv(Decimal("1.0")), float) + assert isinstance(base_json_conv(uuid.uuid4()), str) + assert isinstance(base_json_conv(time()), str) + assert isinstance(base_json_conv(timedelta(0)), str) + assert isinstance(base_json_conv(bytes()), str) + assert base_json_conv(bytes("", encoding="utf-16")) == "[bytes]" + + with pytest.raises(TypeError): + base_json_conv(np.datetime64()) def test_zlib_compression(self): json_str = '{"test": 1}' @@ -228,7 +242,6 @@ def test_merge_extra_filters(self): {"col": "__time_col", "op": "in", "val": "birth_year"}, {"col": "__time_grain", "op": "in", "val": "years"}, {"col": "A", "op": "like", "val": "hello"}, - {"col": "__time_origin", "op": "in", "val": "now"}, {"col": "__granularity", "op": "in", "val": "90 seconds"}, ] } @@ -248,12 +261,10 @@ def test_merge_extra_filters(self): "granularity_sqla": "birth_year", "time_grain_sqla": "years", "granularity": "90 seconds", - "druid_time_origin": "now", "applied_time_extras": { "__time_range": "1 year ago :", "__time_col": "birth_year", "__time_grain": "years", - "__time_origin": "now", "__granularity": "90 seconds", }, } @@ -528,6 +539,18 @@ def test_merge_extra_filters_adds_unequal_lists(self): merge_extra_filters(form_data) self.assertEqual(form_data, expected) + def test_merge_extra_filters_when_applied_time_extras_predefined(self): + form_data = {"applied_time_extras": {"__time_range": "Last week"}} + merge_extra_filters(form_data) + + self.assertEqual( + form_data, + { + "applied_time_extras": {"__time_range": "Last week"}, + "adhoc_filters": [], + }, + ) + def test_merge_request_params_when_url_params_undefined(self): form_data = {"since": "2000", "until": "now"} url_params = {"form_data": form_data, "dashboard_ids": "(1,2,3,4,5)"} @@ -887,7 +910,6 @@ def test_merge_extra_filters_with_extras(self): def test_ssl_certificate_parse(self): parsed_certificate = parse_ssl_cert(ssl_certificate) self.assertEqual(parsed_certificate.serial_number, 12355228710836649848) - self.assertRaises(CertificateException, parse_ssl_cert, "abc" + ssl_certificate) def test_ssl_certificate_file_creation(self): path = create_ssl_cert_file(ssl_certificate) @@ -1062,10 +1084,21 @@ def normalize_col( df: pd.DataFrame, timestamp_format: Optional[str], offset: int, - time_shift: Optional[timedelta], + time_shift: Optional[str], ) -> pd.DataFrame: df = df.copy() - normalize_dttm_col(df, timestamp_format, offset, time_shift) + normalize_dttm_col( + df, + tuple( + [ + DateColumn.get_legacy_time_column( + timestamp_format=timestamp_format, + offset=offset, + time_shift=time_shift, + ) + ] + ), + ) return df ts = pd.Timestamp(2021, 2, 15, 19, 0, 0, 0) @@ -1082,9 +1115,9 @@ def normalize_col( ) # test offset and timedelta - assert normalize_col(df, None, 1, timedelta(minutes=30))[DTTM_ALIAS][ - 0 - ] == pd.Timestamp(2021, 2, 15, 20, 30, 0, 0) + assert normalize_col(df, None, 1, "30 minutes")[DTTM_ALIAS][0] == pd.Timestamp( + 2021, 2, 15, 20, 30, 0, 0 + ) # test numeric epoch_s format df = pd.DataFrame([{"__timestamp": ts.timestamp(), "a": 1}]) diff --git a/tests/integration_tests/viz_tests.py b/tests/integration_tests/viz_tests.py index 6eb3f8c611487..137e2a474c344 100644 --- a/tests/integration_tests/viz_tests.py +++ b/tests/integration_tests/viz_tests.py @@ -288,13 +288,6 @@ def test_parse_adhoc_filters(self): "operator": ">", "comparator": "100", }, - { - "expressionType": "SIMPLE", - "clause": "HAVING", - "subject": "SUM(value1)", - "operator": "<", - "comparator": "10", - }, { "expressionType": "SQL", "clause": "HAVING", @@ -313,10 +306,6 @@ def test_parse_adhoc_filters(self): self.assertEqual( [{"col": "value2", "val": "100", "op": ">"}], query_obj["filter"] ) - self.assertEqual( - [{"op": "<", "val": "10", "col": "SUM(value1)"}], - query_obj["extras"]["having_druid"], - ) self.assertEqual("(value3 in ('North America'))", query_obj["extras"]["where"]) self.assertEqual("(SUM(value1) > 5)", query_obj["extras"]["having"]) @@ -352,7 +341,6 @@ def test_adhoc_filters_overwrite_legacy_filters(self): self.assertEqual( [{"col": "value2", "val": "100", "op": ">"}], query_obj["filter"] ) - self.assertEqual([], query_obj["extras"]["having_druid"]) self.assertEqual("(value3 in ('North America'))", query_obj["extras"]["where"]) self.assertEqual("", query_obj["extras"]["having"]) @@ -728,7 +716,7 @@ def test_get_data_transforms_dataframe(self): self.assertEqual(data, expected) def test_get_data_empty_null_keys(self): - form_data = {"groupby": [], "metrics": ["", None]} + form_data = {"groupby": [], "metrics": [""]} datasource = self.get_datasource_mock() # Test data raw = {} @@ -751,19 +739,13 @@ def test_get_data_empty_null_keys(self): "group": "All", } ], - "NULL": [ - { - "values": [ - {"x": 100, "y": 10}, - {"x": 200, "y": 20}, - {"x": 300, "y": 30}, - ], - "group": "All", - } - ], } self.assertEqual(data, expected) + form_data = {"groupby": [], "metrics": [None]} + with self.assertRaises(ValueError): + viz.viz_types["paired_ttest"](datasource, form_data) + class TestPartitionViz(SupersetTestCase): @patch("superset.viz.BaseViz.query_obj") diff --git a/tests/unit_tests/advanced_data_type/types_tests.py b/tests/unit_tests/advanced_data_type/types_tests.py index 82c9d8b29ad9c..189b9e1aab22d 100644 --- a/tests/unit_tests/advanced_data_type/types_tests.py +++ b/tests/unit_tests/advanced_data_type/types_tests.py @@ -17,11 +17,8 @@ # isort:skip_file """Unit tests for Superset""" -from ipaddress import ip_address import sqlalchemy -from flask.ctx import AppContext from sqlalchemy import Column, Integer -from tests.integration_tests.base_tests import SupersetTestCase from superset.advanced_data_type.types import ( AdvancedDataTypeRequest, AdvancedDataTypeResponse, @@ -36,7 +33,7 @@ # tox -e py38 -- tests/unit_tests/advanced_data_type/types_tests.py -def test_ip_func_valid_ip(app_context: None): +def test_ip_func_valid_ip(): """Test to see if the cidr_func behaves as expected when a valid IP is passed in""" cidr_request: AdvancedDataTypeRequest = { "advanced_data_type": "cidr", @@ -59,7 +56,7 @@ def test_ip_func_valid_ip(app_context: None): assert internet_address.translate_type(cidr_request) == cidr_response -def test_cidr_func_invalid_ip(app_context: None): +def test_cidr_func_invalid_ip(): """Test to see if the cidr_func behaves as expected when an invalid IP is passed in""" cidr_request: AdvancedDataTypeRequest = { "advanced_data_type": "cidr", @@ -82,7 +79,7 @@ def test_cidr_func_invalid_ip(app_context: None): assert internet_address.translate_type(cidr_request) == cidr_response -def test_port_translation_func_valid_port_number(app_context: None): +def test_port_translation_func_valid_port_number(): """Test to see if the port_translation_func behaves as expected when a valid port number is passed in""" port_request: AdvancedDataTypeRequest = { @@ -106,7 +103,7 @@ def test_port_translation_func_valid_port_number(app_context: None): assert port.translate_type(port_request) == port_response -def test_port_translation_func_valid_port_name(app_context: None): +def test_port_translation_func_valid_port_name(): """Test to see if the port_translation_func behaves as expected when a valid port name is passed in""" port_request: AdvancedDataTypeRequest = { @@ -130,7 +127,7 @@ def test_port_translation_func_valid_port_name(app_context: None): assert port.translate_type(port_request) == port_response -def test_port_translation_func_invalid_port_name(app_context: None): +def test_port_translation_func_invalid_port_name(): """Test to see if the port_translation_func behaves as expected when an invalid port name is passed in""" port_request: AdvancedDataTypeRequest = { @@ -154,7 +151,7 @@ def test_port_translation_func_invalid_port_name(app_context: None): assert port.translate_type(port_request) == port_response -def test_port_translation_func_invalid_port_number(app_context: None): +def test_port_translation_func_invalid_port_number(): """Test to see if the port_translation_func behaves as expected when an invalid port number is passed in""" port_request: AdvancedDataTypeRequest = { @@ -178,7 +175,7 @@ def test_port_translation_func_invalid_port_number(app_context: None): assert port.translate_type(port_request) == port_response -def test_cidr_translate_filter_func_equals(app_context: None): +def test_cidr_translate_filter_func_equals(): """Test to see if the cidr_translate_filter_func behaves as expected when the EQUALS operator is used""" @@ -193,7 +190,7 @@ def test_cidr_translate_filter_func_equals(app_context: None): ).compare(cidr_translate_filter_response) -def test_cidr_translate_filter_func_not_equals(app_context: None): +def test_cidr_translate_filter_func_not_equals(): """Test to see if the cidr_translate_filter_func behaves as expected when the NOT_EQUALS operator is used""" @@ -208,7 +205,7 @@ def test_cidr_translate_filter_func_not_equals(app_context: None): ).compare(cidr_translate_filter_response) -def test_cidr_translate_filter_func_greater_than_or_equals(app_context: None): +def test_cidr_translate_filter_func_greater_than_or_equals(): """Test to see if the cidr_translate_filter_func behaves as expected when the GREATER_THAN_OR_EQUALS operator is used""" @@ -225,7 +222,7 @@ def test_cidr_translate_filter_func_greater_than_or_equals(app_context: None): ).compare(cidr_translate_filter_response) -def test_cidr_translate_filter_func_greater_than(app_context: None): +def test_cidr_translate_filter_func_greater_than(): """Test to see if the cidr_translate_filter_func behaves as expected when the GREATER_THAN operator is used""" @@ -242,7 +239,7 @@ def test_cidr_translate_filter_func_greater_than(app_context: None): ).compare(cidr_translate_filter_response) -def test_cidr_translate_filter_func_less_than(app_context: None): +def test_cidr_translate_filter_func_less_than(): """Test to see if the cidr_translate_filter_func behaves as expected when the LESS_THAN operator is used""" @@ -259,7 +256,7 @@ def test_cidr_translate_filter_func_less_than(app_context: None): ).compare(cidr_translate_filter_response) -def test_cidr_translate_filter_func_less_than_or_equals(app_context: None): +def test_cidr_translate_filter_func_less_than_or_equals(): """Test to see if the cidr_translate_filter_func behaves as expected when the LESS_THAN_OR_EQUALS operator is used""" @@ -276,7 +273,7 @@ def test_cidr_translate_filter_func_less_than_or_equals(app_context: None): ).compare(cidr_translate_filter_response) -def test_cidr_translate_filter_func_in_single(app_context: None): +def test_cidr_translate_filter_func_in_single(): """Test to see if the cidr_translate_filter_func behaves as expected when the IN operator is used with a single IP""" @@ -293,7 +290,7 @@ def test_cidr_translate_filter_func_in_single(app_context: None): ).compare(cidr_translate_filter_response) -def test_cidr_translate_filter_func_in_double(app_context: None): +def test_cidr_translate_filter_func_in_double(): """Test to see if the cidr_translate_filter_func behaves as expected when the IN operator is used with two IP's""" @@ -312,7 +309,7 @@ def test_cidr_translate_filter_func_in_double(app_context: None): ).compare(cidr_translate_filter_response) -def test_cidr_translate_filter_func_not_in_single(app_context: None): +def test_cidr_translate_filter_func_not_in_single(): """Test to see if the cidr_translate_filter_func behaves as expected when the NOT_IN operator is used with a single IP""" @@ -329,7 +326,7 @@ def test_cidr_translate_filter_func_not_in_single(app_context: None): ).compare(cidr_translate_filter_response) -def test_cidr_translate_filter_func_not_in_double(app_context: None): +def test_cidr_translate_filter_func_not_in_double(): """Test to see if the cidr_translate_filter_func behaves as expected when the NOT_IN operator is used with two IP's""" @@ -348,7 +345,7 @@ def test_cidr_translate_filter_func_not_in_double(app_context: None): ).compare(cidr_translate_filter_response) -def test_port_translate_filter_func_equals(app_context: None): +def test_port_translate_filter_func_equals(): """Test to see if the port_translate_filter_func behaves as expected when the EQUALS operator is used""" @@ -365,7 +362,7 @@ def test_port_translate_filter_func_equals(app_context: None): ) -def test_port_translate_filter_func_not_equals(app_context: None): +def test_port_translate_filter_func_not_equals(): """Test to see if the port_translate_filter_func behaves as expected when the NOT_EQUALS operator is used""" @@ -382,7 +379,7 @@ def test_port_translate_filter_func_not_equals(app_context: None): ) -def test_port_translate_filter_func_greater_than_or_equals(app_context: None): +def test_port_translate_filter_func_greater_than_or_equals(): """Test to see if the port_translate_filter_func behaves as expected when the GREATER_THAN_OR_EQUALS operator is used""" @@ -399,7 +396,7 @@ def test_port_translate_filter_func_greater_than_or_equals(app_context: None): ) -def test_port_translate_filter_func_greater_than(app_context: None): +def test_port_translate_filter_func_greater_than(): """Test to see if the port_translate_filter_func behaves as expected when the GREATER_THAN operator is used""" @@ -416,7 +413,7 @@ def test_port_translate_filter_func_greater_than(app_context: None): ) -def test_port_translate_filter_func_less_than_or_equals(app_context: None): +def test_port_translate_filter_func_less_than_or_equals(): """Test to see if the port_translate_filter_func behaves as expected when the LESS_THAN_OR_EQUALS operator is used""" @@ -433,7 +430,7 @@ def test_port_translate_filter_func_less_than_or_equals(app_context: None): ) -def test_port_translate_filter_func_less_than(app_context: None): +def test_port_translate_filter_func_less_than(): """Test to see if the port_translate_filter_func behaves as expected when the LESS_THAN operator is used""" @@ -450,7 +447,7 @@ def test_port_translate_filter_func_less_than(app_context: None): ) -def test_port_translate_filter_func_in_single(app_context: None): +def test_port_translate_filter_func_in_single(): """Test to see if the port_translate_filter_func behaves as expected when the IN operator is used with a single port""" @@ -467,7 +464,7 @@ def test_port_translate_filter_func_in_single(app_context: None): ) -def test_port_translate_filter_func_in_double(app_context: None): +def test_port_translate_filter_func_in_double(): """Test to see if the port_translate_filter_func behaves as expected when the IN operator is used with two ports""" @@ -484,7 +481,7 @@ def test_port_translate_filter_func_in_double(app_context: None): ) -def test_port_translate_filter_func_not_in_single(app_context: None): +def test_port_translate_filter_func_not_in_single(): """Test to see if the port_translate_filter_func behaves as expected when the NOT_IN operator is used with a single port""" @@ -501,7 +498,7 @@ def test_port_translate_filter_func_not_in_single(app_context: None): ) -def test_port_translate_filter_func_not_in_double(app_context: None): +def test_port_translate_filter_func_not_in_double(): """Test to see if the port_translate_filter_func behaves as expected when the NOT_IN operator is used with two ports""" diff --git a/tests/unit_tests/charts/commands/importers/v1/import_test.py b/tests/unit_tests/charts/commands/importers/v1/import_test.py index e8687036394cb..e29fd70fb8a70 100644 --- a/tests/unit_tests/charts/commands/importers/v1/import_test.py +++ b/tests/unit_tests/charts/commands/importers/v1/import_test.py @@ -21,7 +21,7 @@ from sqlalchemy.orm.session import Session -def test_import_chart(app_context: None, session: Session) -> None: +def test_import_chart(session: Session) -> None: """ Test importing a chart. """ @@ -45,7 +45,7 @@ def test_import_chart(app_context: None, session: Session) -> None: assert chart.external_url is None -def test_import_chart_managed_externally(app_context: None, session: Session) -> None: +def test_import_chart_managed_externally(session: Session) -> None: """ Test importing a chart that is managed externally. """ diff --git a/tests/unit_tests/charts/dao/__init__.py b/tests/unit_tests/charts/dao/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/charts/dao/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/charts/dao/dao_tests.py b/tests/unit_tests/charts/dao/dao_tests.py new file mode 100644 index 0000000000000..15310712a5f8a --- /dev/null +++ b/tests/unit_tests/charts/dao/dao_tests.py @@ -0,0 +1,67 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from typing import Iterator + +import pytest +from sqlalchemy.orm.session import Session + +from superset.utils.core import DatasourceType + + +@pytest.fixture +def session_with_data(session: Session) -> Iterator[Session]: + from superset.models.slice import Slice + + engine = session.get_bind() + Slice.metadata.create_all(engine) # pylint: disable=no-member + + slice_obj = Slice( + id=1, + datasource_id=1, + datasource_type=DatasourceType.TABLE, + datasource_name="tmp_perm_table", + slice_name="slice_name", + ) + + session.add(slice_obj) + session.commit() + yield session + session.rollback() + + +def test_slice_find_by_id_skip_base_filter(session_with_data: Session) -> None: + from superset.charts.dao import ChartDAO + from superset.models.slice import Slice + + result = ChartDAO.find_by_id(1, session=session_with_data, skip_base_filter=True) + + assert result + assert 1 == result.id + assert "slice_name" == result.slice_name + assert isinstance(result, Slice) + + +def test_datasource_find_by_id_skip_base_filter_not_found( + session_with_data: Session, +) -> None: + from superset.charts.dao import ChartDAO + + result = ChartDAO.find_by_id( + 125326326, session=session_with_data, skip_base_filter=True + ) + assert result is None diff --git a/tests/unit_tests/charts/test_post_processing.py b/tests/unit_tests/charts/test_post_processing.py index f8586be1ff955..be28aba922037 100644 --- a/tests/unit_tests/charts/test_post_processing.py +++ b/tests/unit_tests/charts/test_post_processing.py @@ -15,9 +15,17 @@ # specific language governing permissions and limitations # under the License. +import json + import pandas as pd +from flask_babel import lazy_gettext as _ +from numpy import True_ +from pytest import raises +from sqlalchemy.orm.session import Session -from superset.charts.post_processing import pivot_df, table +from superset.charts.post_processing import apply_post_process, pivot_df, table +from superset.common.chart_data import ChartDataResultFormat +from superset.utils.core import GenericDataType def test_pivot_df_no_cols_no_rows_single_metric(): @@ -50,14 +58,14 @@ def test_pivot_df_no_cols_no_rows_single_metric(): ) assert ( pivoted.to_markdown() - == """ + == f""" | | ('SUM(num)',) | |:-----------------|----------------:| -| ('Total (Sum)',) | 8.06797e+07 | +| ('{_("Total")} (Sum)',) | 8.06797e+07 | """.strip() ) - # tranpose_pivot and combine_metrics do nothing in this case + # transpose_pivot and combine_metrics do nothing in this case pivoted = pivot_df( df, rows=[], @@ -72,10 +80,10 @@ def test_pivot_df_no_cols_no_rows_single_metric(): ) assert ( pivoted.to_markdown() - == """ + == f""" | | ('SUM(num)',) | |:-----------------|----------------:| -| ('Total (Sum)',) | 8.06797e+07 | +| ('{_("Total")} (Sum)',) | 8.06797e+07 | """.strip() ) @@ -95,8 +103,8 @@ def test_pivot_df_no_cols_no_rows_single_metric(): ) assert ( pivoted.to_markdown() - == """ -| | ('Total (Sum)',) | + == f""" +| | ('{_("Total")} (Sum)',) | |:--------------|-------------------:| | ('SUM(num)',) | 8.06797e+07 | """.strip() @@ -117,10 +125,10 @@ def test_pivot_df_no_cols_no_rows_single_metric(): ) assert ( pivoted.to_markdown() - == """ + == f""" | | ('SUM(num)',) | ('Total (Sum)',) | |:-----------------|----------------:|-------------------:| -| ('Total (Sum)',) | 8.06797e+07 | 8.06797e+07 | +| ('{_("Total")} (Sum)',) | 8.06797e+07 | 8.06797e+07 | """.strip() ) @@ -155,14 +163,14 @@ def test_pivot_df_no_cols_no_rows_two_metrics(): ) assert ( pivoted.to_markdown() - == """ + == f""" | | ('SUM(num)',) | ('MAX(num)',) | |:-----------------|----------------:|----------------:| -| ('Total (Sum)',) | 8.06797e+07 | 37296 | +| ('{_("Total")} (Sum)',) | 8.06797e+07 | 37296 | """.strip() ) - # tranpose_pivot and combine_metrics do nothing in this case + # transpose_pivot and combine_metrics do nothing in this case pivoted = pivot_df( df, rows=[], @@ -200,8 +208,8 @@ def test_pivot_df_no_cols_no_rows_two_metrics(): ) assert ( pivoted.to_markdown() - == """ -| | ('Total (Sum)',) | + == f""" +| | ('{_("Total")} (Sum)',) | |:--------------|-------------------:| | ('SUM(num)',) | 8.06797e+07 | | ('MAX(num)',) | 37296 | @@ -224,10 +232,10 @@ def test_pivot_df_no_cols_no_rows_two_metrics(): ) assert ( pivoted.to_markdown() - == """ -| | ('SUM(num)',) | ('MAX(num)',) | ('Total (Sum)',) | + == f""" +| | ('SUM(num)',) | ('MAX(num)',) | ('{_("Total")} (Sum)',) | |:-----------------|----------------:|----------------:|-------------------:| -| ('Total (Sum)',) | 8.06797e+07 | 37296 | 8.0717e+07 | +| ('{_("Total")} (Sum)',) | 8.06797e+07 | 37296 | 8.0717e+07 | """.strip() ) @@ -290,10 +298,10 @@ def test_pivot_df_single_row_two_metrics(): ) assert ( pivoted.to_markdown() - == """ + == f""" | | ('SUM(num)', 'boy') | ('SUM(num)', 'girl') | ('MAX(num)', 'boy') | ('MAX(num)', 'girl') | |:-----------------|----------------------:|-----------------------:|----------------------:|-----------------------:| -| ('Total (Sum)',) | 47123 | 118065 | 1280 | 2588 | +| ('{_("Total")} (Sum)',) | 47123 | 118065 | 1280 | 2588 | """.strip() ) @@ -335,12 +343,12 @@ def test_pivot_df_single_row_two_metrics(): ) assert ( pivoted.to_markdown() - == """ -| | ('SUM(num)',) | ('MAX(num)',) | ('Total (Sum)',) | + == f""" +| | ('SUM(num)',) | ('MAX(num)',) | ('{_("Total")} (Sum)',) | |:-----------------|----------------:|----------------:|-------------------:| | ('boy',) | 47123 | 1280 | 48403 | | ('girl',) | 118065 | 2588 | 120653 | -| ('Total (Sum)',) | 165188 | 3868 | 169056 | +| ('{_("Total")} (Sum)',) | 165188 | 3868 | 169056 | """.strip() ) @@ -359,8 +367,8 @@ def test_pivot_df_single_row_two_metrics(): ) assert ( pivoted.to_markdown() - == """ -| | ('Total (Sum)',) | + == f""" +| | ('{_("Total")} (Sum)',) | |:-------------------------|-------------------:| | ('SUM(num)', 'boy') | 47123 | | ('SUM(num)', 'girl') | 118065 | @@ -368,7 +376,7 @@ def test_pivot_df_single_row_two_metrics(): | ('MAX(num)', 'boy') | 1280 | | ('MAX(num)', 'girl') | 2588 | | ('MAX(num)', 'Subtotal') | 3868 | -| ('Total (Sum)', '') | 169056 | +| ('{_("Total")} (Sum)', '') | 169056 | """.strip() ) @@ -387,8 +395,8 @@ def test_pivot_df_single_row_two_metrics(): ) assert ( pivoted.to_markdown() - == """ -| | ('Total (Sum)',) | + == f""" +| | ('{_("Total")} (Sum)',) | |:---------------------|-------------------:| | ('boy', 'SUM(num)') | 47123 | | ('boy', 'MAX(num)') | 1280 | @@ -396,7 +404,7 @@ def test_pivot_df_single_row_two_metrics(): | ('girl', 'SUM(num)') | 118065 | | ('girl', 'MAX(num)') | 2588 | | ('girl', 'Subtotal') | 120653 | -| ('Total (Sum)', '') | 169056 | +| ('{_("Total")} (Sum)', '') | 169056 | """.strip() ) @@ -1363,3 +1371,661 @@ def test_table(): | 0 | 80,679,663 | """.strip() ) + + +def test_apply_post_process_no_form_invalid_viz_type(): + """ + Test with invalid viz type. It should just return the result + """ + result = {"foo": "bar"} + form_data = {"viz_type": "baz"} + assert apply_post_process(result, form_data) == result + + +def test_apply_post_process_without_result_format(): + """ + A query without result_format should raise an exception + """ + result = {"queries": [{"result_format": "foo"}]} + form_data = {"viz_type": "pivot_table"} + + with raises(Exception) as ex: + apply_post_process(result, form_data) + + assert ex.match("Result format foo not supported") == True + + +def test_apply_post_process_json_format(): + """ + It should be able to process json results + """ + + result = { + "queries": [ + { + "result_format": ChartDataResultFormat.JSON, + "data": { + "result": [ + { + "data": [{"COUNT(is_software_dev)": 4725}], + "colnames": ["COUNT(is_software_dev)"], + "coltypes": [0], + } + ] + }, + } + ] + } + form_data = { + "datasource": "19__table", + "viz_type": "pivot_table_v2", + "slice_id": 69, + "url_params": {}, + "granularity_sqla": "time_start", + "time_grain_sqla": "P1D", + "time_range": "No filter", + "groupbyColumns": [], + "groupbyRows": [], + "metrics": [ + { + "aggregate": "COUNT", + "column": { + "column_name": "is_software_dev", + "description": None, + "expression": None, + "filterable": True, + "groupby": True, + "id": 1463, + "is_dttm": False, + "python_date_format": None, + "type": "DOUBLE PRECISION", + "verbose_name": None, + }, + "expressionType": "SIMPLE", + "hasCustomLabel": False, + "isNew": False, + "label": "COUNT(is_software_dev)", + "optionName": "metric_9i1kctig9yr_sizo6ihd2o", + "sqlExpression": None, + } + ], + "metricsLayout": "COLUMNS", + "adhoc_filters": [ + { + "clause": "WHERE", + "comparator": "Currently A Developer", + "expressionType": "SIMPLE", + "filterOptionName": "filter_fvi0jg9aii_2lekqrhy7qk", + "isExtra": False, + "isNew": False, + "operator": "==", + "sqlExpression": None, + "subject": "developer_type", + } + ], + "row_limit": 10000, + "order_desc": True, + "aggregateFunction": "Sum", + "valueFormat": "SMART_NUMBER", + "date_format": "smart_date", + "rowOrder": "key_a_to_z", + "colOrder": "key_a_to_z", + "extra_form_data": {}, + "force": False, + "result_format": "json", + "result_type": "results", + } + + assert apply_post_process(result, form_data) == { + "queries": [ + { + "result_format": ChartDataResultFormat.JSON, + "data": { + "result": { + "Total (Sum)": { + "data": [{"COUNT(is_software_dev)": 4725}], + "colnames": ["COUNT(is_software_dev)"], + "coltypes": [0], + } + } + }, + "colnames": [("result",)], + "indexnames": [("Total (Sum)",)], + "coltypes": [GenericDataType.STRING], + "rowcount": 1, + } + ] + } + + +def test_apply_post_process_csv_format(): + """ + It should be able to process csv results + """ + + result = { + "queries": [ + { + "result_format": ChartDataResultFormat.CSV, + "data": """ +COUNT(is_software_dev) +4725 +""", + } + ] + } + form_data = { + "datasource": "19__table", + "viz_type": "pivot_table_v2", + "slice_id": 69, + "url_params": {}, + "granularity_sqla": "time_start", + "time_grain_sqla": "P1D", + "time_range": "No filter", + "groupbyColumns": [], + "groupbyRows": [], + "metrics": [ + { + "aggregate": "COUNT", + "column": { + "column_name": "is_software_dev", + "description": None, + "expression": None, + "filterable": True, + "groupby": True, + "id": 1463, + "is_dttm": False, + "python_date_format": None, + "type": "DOUBLE PRECISION", + "verbose_name": None, + }, + "expressionType": "SIMPLE", + "hasCustomLabel": False, + "isNew": False, + "label": "COUNT(is_software_dev)", + "optionName": "metric_9i1kctig9yr_sizo6ihd2o", + "sqlExpression": None, + } + ], + "metricsLayout": "COLUMNS", + "adhoc_filters": [ + { + "clause": "WHERE", + "comparator": "Currently A Developer", + "expressionType": "SIMPLE", + "filterOptionName": "filter_fvi0jg9aii_2lekqrhy7qk", + "isExtra": False, + "isNew": False, + "operator": "==", + "sqlExpression": None, + "subject": "developer_type", + } + ], + "row_limit": 10000, + "order_desc": True, + "aggregateFunction": "Sum", + "valueFormat": "SMART_NUMBER", + "date_format": "smart_date", + "rowOrder": "key_a_to_z", + "colOrder": "key_a_to_z", + "extra_form_data": {}, + "force": False, + "result_format": "json", + "result_type": "results", + } + + assert apply_post_process(result, form_data) == { + "queries": [ + { + "result_format": ChartDataResultFormat.CSV, + "data": ",COUNT(is_software_dev)\nTotal (Sum),4725\n", + "colnames": [("COUNT(is_software_dev)",)], + "indexnames": [("Total (Sum)",)], + "coltypes": [GenericDataType.NUMERIC], + "rowcount": 1, + } + ] + } + + +def test_apply_post_process_csv_format_empty_string(): + """ + It should be able to process csv results with no data + """ + + result = {"queries": [{"result_format": ChartDataResultFormat.CSV, "data": ""}]} + form_data = { + "datasource": "19__table", + "viz_type": "pivot_table_v2", + "slice_id": 69, + "url_params": {}, + "granularity_sqla": "time_start", + "time_grain_sqla": "P1D", + "time_range": "No filter", + "groupbyColumns": [], + "groupbyRows": [], + "metrics": [ + { + "aggregate": "COUNT", + "column": { + "column_name": "is_software_dev", + "description": None, + "expression": None, + "filterable": True, + "groupby": True, + "id": 1463, + "is_dttm": False, + "python_date_format": None, + "type": "DOUBLE PRECISION", + "verbose_name": None, + }, + "expressionType": "SIMPLE", + "hasCustomLabel": False, + "isNew": False, + "label": "COUNT(is_software_dev)", + "optionName": "metric_9i1kctig9yr_sizo6ihd2o", + "sqlExpression": None, + } + ], + "metricsLayout": "COLUMNS", + "adhoc_filters": [ + { + "clause": "WHERE", + "comparator": "Currently A Developer", + "expressionType": "SIMPLE", + "filterOptionName": "filter_fvi0jg9aii_2lekqrhy7qk", + "isExtra": False, + "isNew": False, + "operator": "==", + "sqlExpression": None, + "subject": "developer_type", + } + ], + "row_limit": 10000, + "order_desc": True, + "aggregateFunction": "Sum", + "valueFormat": "SMART_NUMBER", + "date_format": "smart_date", + "rowOrder": "key_a_to_z", + "colOrder": "key_a_to_z", + "extra_form_data": {}, + "force": False, + "result_format": "json", + "result_type": "results", + } + + assert apply_post_process(result, form_data) == { + "queries": [{"result_format": ChartDataResultFormat.CSV, "data": ""}] + } + + +def test_apply_post_process_csv_format_no_data(): + """ + It should be able to process csv results with no data + """ + + result = {"queries": [{"result_format": ChartDataResultFormat.CSV, "data": None}]} + form_data = { + "datasource": "19__table", + "viz_type": "pivot_table_v2", + "slice_id": 69, + "url_params": {}, + "granularity_sqla": "time_start", + "time_grain_sqla": "P1D", + "time_range": "No filter", + "groupbyColumns": [], + "groupbyRows": [], + "metrics": [ + { + "aggregate": "COUNT", + "column": { + "column_name": "is_software_dev", + "description": None, + "expression": None, + "filterable": True, + "groupby": True, + "id": 1463, + "is_dttm": False, + "python_date_format": None, + "type": "DOUBLE PRECISION", + "verbose_name": None, + }, + "expressionType": "SIMPLE", + "hasCustomLabel": False, + "isNew": False, + "label": "COUNT(is_software_dev)", + "optionName": "metric_9i1kctig9yr_sizo6ihd2o", + "sqlExpression": None, + } + ], + "metricsLayout": "COLUMNS", + "adhoc_filters": [ + { + "clause": "WHERE", + "comparator": "Currently A Developer", + "expressionType": "SIMPLE", + "filterOptionName": "filter_fvi0jg9aii_2lekqrhy7qk", + "isExtra": False, + "isNew": False, + "operator": "==", + "sqlExpression": None, + "subject": "developer_type", + } + ], + "row_limit": 10000, + "order_desc": True, + "aggregateFunction": "Sum", + "valueFormat": "SMART_NUMBER", + "date_format": "smart_date", + "rowOrder": "key_a_to_z", + "colOrder": "key_a_to_z", + "extra_form_data": {}, + "force": False, + "result_format": "json", + "result_type": "results", + } + + assert apply_post_process(result, form_data) == { + "queries": [{"result_format": ChartDataResultFormat.CSV, "data": None}] + } + + +def test_apply_post_process_csv_format_no_data_multiple_queries(): + """ + It should be able to process csv results multiple queries if one query has no data + """ + + result = { + "queries": [ + {"result_format": ChartDataResultFormat.CSV, "data": ""}, + { + "result_format": ChartDataResultFormat.CSV, + "data": """ +COUNT(is_software_dev) +4725 +""", + }, + ] + } + form_data = { + "datasource": "19__table", + "viz_type": "pivot_table_v2", + "slice_id": 69, + "url_params": {}, + "granularity_sqla": "time_start", + "time_grain_sqla": "P1D", + "time_range": "No filter", + "groupbyColumns": [], + "groupbyRows": [], + "metrics": [ + { + "aggregate": "COUNT", + "column": { + "column_name": "is_software_dev", + "description": None, + "expression": None, + "filterable": True, + "groupby": True, + "id": 1463, + "is_dttm": False, + "python_date_format": None, + "type": "DOUBLE PRECISION", + "verbose_name": None, + }, + "expressionType": "SIMPLE", + "hasCustomLabel": False, + "isNew": False, + "label": "COUNT(is_software_dev)", + "optionName": "metric_9i1kctig9yr_sizo6ihd2o", + "sqlExpression": None, + } + ], + "metricsLayout": "COLUMNS", + "adhoc_filters": [ + { + "clause": "WHERE", + "comparator": "Currently A Developer", + "expressionType": "SIMPLE", + "filterOptionName": "filter_fvi0jg9aii_2lekqrhy7qk", + "isExtra": False, + "isNew": False, + "operator": "==", + "sqlExpression": None, + "subject": "developer_type", + } + ], + "row_limit": 10000, + "order_desc": True, + "aggregateFunction": "Sum", + "valueFormat": "SMART_NUMBER", + "date_format": "smart_date", + "rowOrder": "key_a_to_z", + "colOrder": "key_a_to_z", + "extra_form_data": {}, + "force": False, + "result_format": "json", + "result_type": "results", + } + + assert apply_post_process(result, form_data) == { + "queries": [ + {"result_format": ChartDataResultFormat.CSV, "data": ""}, + { + "result_format": ChartDataResultFormat.CSV, + "data": ",COUNT(is_software_dev)\nTotal (Sum),4725\n", + "colnames": [("COUNT(is_software_dev)",)], + "indexnames": [("Total (Sum)",)], + "coltypes": [GenericDataType.NUMERIC], + "rowcount": 1, + }, + ] + } + + +def test_apply_post_process_json_format_empty_string(): + """ + It should be able to process json results with no data + """ + + result = {"queries": [{"result_format": ChartDataResultFormat.JSON, "data": ""}]} + form_data = { + "datasource": "19__table", + "viz_type": "pivot_table_v2", + "slice_id": 69, + "url_params": {}, + "granularity_sqla": "time_start", + "time_grain_sqla": "P1D", + "time_range": "No filter", + "groupbyColumns": [], + "groupbyRows": [], + "metrics": [ + { + "aggregate": "COUNT", + "column": { + "column_name": "is_software_dev", + "description": None, + "expression": None, + "filterable": True, + "groupby": True, + "id": 1463, + "is_dttm": False, + "python_date_format": None, + "type": "DOUBLE PRECISION", + "verbose_name": None, + }, + "expressionType": "SIMPLE", + "hasCustomLabel": False, + "isNew": False, + "label": "COUNT(is_software_dev)", + "optionName": "metric_9i1kctig9yr_sizo6ihd2o", + "sqlExpression": None, + } + ], + "metricsLayout": "COLUMNS", + "adhoc_filters": [ + { + "clause": "WHERE", + "comparator": "Currently A Developer", + "expressionType": "SIMPLE", + "filterOptionName": "filter_fvi0jg9aii_2lekqrhy7qk", + "isExtra": False, + "isNew": False, + "operator": "==", + "sqlExpression": None, + "subject": "developer_type", + } + ], + "row_limit": 10000, + "order_desc": True, + "aggregateFunction": "Sum", + "valueFormat": "SMART_NUMBER", + "date_format": "smart_date", + "rowOrder": "key_a_to_z", + "colOrder": "key_a_to_z", + "extra_form_data": {}, + "force": False, + "result_format": "json", + "result_type": "results", + } + + assert apply_post_process(result, form_data) == { + "queries": [{"result_format": ChartDataResultFormat.JSON, "data": ""}] + } + + +def test_apply_post_process_json_format_data_is_none(): + """ + It should be able to process json results with no data + """ + + result = {"queries": [{"result_format": ChartDataResultFormat.JSON, "data": None}]} + form_data = { + "datasource": "19__table", + "viz_type": "pivot_table_v2", + "slice_id": 69, + "url_params": {}, + "granularity_sqla": "time_start", + "time_grain_sqla": "P1D", + "time_range": "No filter", + "groupbyColumns": [], + "groupbyRows": [], + "metrics": [ + { + "aggregate": "COUNT", + "column": { + "column_name": "is_software_dev", + "description": None, + "expression": None, + "filterable": True, + "groupby": True, + "id": 1463, + "is_dttm": False, + "python_date_format": None, + "type": "DOUBLE PRECISION", + "verbose_name": None, + }, + "expressionType": "SIMPLE", + "hasCustomLabel": False, + "isNew": False, + "label": "COUNT(is_software_dev)", + "optionName": "metric_9i1kctig9yr_sizo6ihd2o", + "sqlExpression": None, + } + ], + "metricsLayout": "COLUMNS", + "adhoc_filters": [ + { + "clause": "WHERE", + "comparator": "Currently A Developer", + "expressionType": "SIMPLE", + "filterOptionName": "filter_fvi0jg9aii_2lekqrhy7qk", + "isExtra": False, + "isNew": False, + "operator": "==", + "sqlExpression": None, + "subject": "developer_type", + } + ], + "row_limit": 10000, + "order_desc": True, + "aggregateFunction": "Sum", + "valueFormat": "SMART_NUMBER", + "date_format": "smart_date", + "rowOrder": "key_a_to_z", + "colOrder": "key_a_to_z", + "extra_form_data": {}, + "force": False, + "result_format": "json", + "result_type": "results", + } + + assert apply_post_process(result, form_data) == { + "queries": [{"result_format": ChartDataResultFormat.JSON, "data": None}] + } + + +def test_apply_post_process_verbose_map(session: Session): + from superset.connectors.sqla.models import SqlaTable, SqlMetric + from superset.models.core import Database + + engine = session.get_bind() + SqlaTable.metadata.create_all(engine) # pylint: disable=no-member + db = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + sqla_table = SqlaTable( + table_name="my_sqla_table", + columns=[], + metrics=[ + SqlMetric( + metric_name="count", + verbose_name="COUNT(*)", + metric_type="count", + expression="COUNT(*)", + ) + ], + database=db, + ) + + result = { + "queries": [ + { + "result_format": ChartDataResultFormat.JSON, + "data": [{"count": 4725}], + } + ] + } + form_data = { + "datasource": "19__table", + "viz_type": "pivot_table_v2", + "slice_id": 69, + "url_params": {}, + "granularity_sqla": "time_start", + "time_grain_sqla": "P1D", + "time_range": "No filter", + "groupbyColumns": [], + "groupbyRows": [], + "metrics": ["COUNT(*)"], + "metricsLayout": "COLUMNS", + "row_limit": 10000, + "order_desc": True, + "valueFormat": "SMART_NUMBER", + "date_format": "smart_date", + "rowOrder": "key_a_to_z", + "colOrder": "key_a_to_z", + "extra_form_data": {}, + "force": False, + "result_format": "json", + "result_type": "results", + } + + assert apply_post_process(result, form_data, datasource=sqla_table) == { + "queries": [ + { + "result_format": ChartDataResultFormat.JSON, + "data": {"COUNT(*)": {"Total (Sum)": 4725}}, + "colnames": [("COUNT(*)",)], + "indexnames": [("Total (Sum)",)], + "coltypes": [GenericDataType.NUMERIC], + "rowcount": 1, + } + ] + } diff --git a/tests/unit_tests/columns/test_models.py b/tests/unit_tests/columns/test_models.py index 40cc2075d380e..068557e7a6a7f 100644 --- a/tests/unit_tests/columns/test_models.py +++ b/tests/unit_tests/columns/test_models.py @@ -20,7 +20,7 @@ from sqlalchemy.orm.session import Session -def test_column_model(app_context: None, session: Session) -> None: +def test_column_model(session: Session) -> None: """ Test basic attributes of a ``Column``. """ diff --git a/tests/unit_tests/commands/export_test.py b/tests/unit_tests/commands/export_test.py index 91aebf1b684eb..24fa491664042 100644 --- a/tests/unit_tests/commands/export_test.py +++ b/tests/unit_tests/commands/export_test.py @@ -20,7 +20,7 @@ from pytest_mock import MockFixture -def test_export_assets_command(mocker: MockFixture, app_context: None) -> None: +def test_export_assets_command(mocker: MockFixture) -> None: """ Test that all assets are exported correctly. """ diff --git a/tests/unit_tests/commands/importers/__init__.py b/tests/unit_tests/commands/importers/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/commands/importers/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/commands/importers/v1/__init__.py b/tests/unit_tests/commands/importers/v1/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/commands/importers/v1/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/commands/importers/v1/assets_test.py b/tests/unit_tests/commands/importers/v1/assets_test.py new file mode 100644 index 0000000000000..1a345ff2b913b --- /dev/null +++ b/tests/unit_tests/commands/importers/v1/assets_test.py @@ -0,0 +1,131 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import copy + +from sqlalchemy.orm.session import Session +from sqlalchemy.sql import select + +from tests.unit_tests.fixtures.assets_configs import ( + charts_config_1, + charts_config_2, + dashboards_config_1, + dashboards_config_2, + databases_config, + datasets_config, +) + + +def test_import_new_assets(session: Session) -> None: + """ + Test that all new assets are imported correctly. + """ + from superset.commands.importers.v1.assets import ImportAssetsCommand + from superset.models.dashboard import dashboard_slices + from superset.models.slice import Slice + + engine = session.get_bind() + Slice.metadata.create_all(engine) # pylint: disable=no-member + configs = { + **copy.deepcopy(databases_config), + **copy.deepcopy(datasets_config), + **copy.deepcopy(charts_config_1), + **copy.deepcopy(dashboards_config_1), + } + expected_number_of_dashboards = len(dashboards_config_1) + expected_number_of_charts = len(charts_config_1) + + ImportAssetsCommand._import(session, configs) + dashboard_ids = session.scalars( + select(dashboard_slices.c.dashboard_id).distinct() + ).all() + chart_ids = session.scalars(select(dashboard_slices.c.slice_id)).all() + + assert len(chart_ids) == expected_number_of_charts + assert len(dashboard_ids) == expected_number_of_dashboards + + +def test_import_adds_dashboard_charts(session: Session) -> None: + """ + Test that existing dashboards are updated with new charts. + """ + from superset.commands.importers.v1.assets import ImportAssetsCommand + from superset.models.dashboard import dashboard_slices + from superset.models.slice import Slice + + engine = session.get_bind() + Slice.metadata.create_all(engine) # pylint: disable=no-member + base_configs = { + **copy.deepcopy(databases_config), + **copy.deepcopy(datasets_config), + **copy.deepcopy(charts_config_2), + **copy.deepcopy(dashboards_config_2), + } + new_configs = { + **copy.deepcopy(databases_config), + **copy.deepcopy(datasets_config), + **copy.deepcopy(charts_config_1), + **copy.deepcopy(dashboards_config_1), + } + expected_number_of_dashboards = len(dashboards_config_1) + expected_number_of_charts = len(charts_config_1) + + ImportAssetsCommand._import(session, base_configs) + ImportAssetsCommand._import(session, new_configs) + dashboard_ids = session.scalars( + select(dashboard_slices.c.dashboard_id).distinct() + ).all() + chart_ids = session.scalars(select(dashboard_slices.c.slice_id)).all() + + assert len(chart_ids) == expected_number_of_charts + assert len(dashboard_ids) == expected_number_of_dashboards + + +def test_import_removes_dashboard_charts(session: Session) -> None: + """ + Test that existing dashboards are updated without old charts. + """ + from superset.commands.importers.v1.assets import ImportAssetsCommand + from superset.models.dashboard import dashboard_slices + from superset.models.slice import Slice + + engine = session.get_bind() + Slice.metadata.create_all(engine) # pylint: disable=no-member + base_configs = { + **copy.deepcopy(databases_config), + **copy.deepcopy(datasets_config), + **copy.deepcopy(charts_config_1), + **copy.deepcopy(dashboards_config_1), + } + new_configs = { + **copy.deepcopy(databases_config), + **copy.deepcopy(datasets_config), + **copy.deepcopy(charts_config_2), + **copy.deepcopy(dashboards_config_2), + } + expected_number_of_dashboards = len(dashboards_config_2) + expected_number_of_charts = len(charts_config_2) + + ImportAssetsCommand._import(session, base_configs) + ImportAssetsCommand._import(session, new_configs) + dashboard_ids = session.scalars( + select(dashboard_slices.c.dashboard_id).distinct() + ).all() + chart_ids = session.scalars(select(dashboard_slices.c.slice_id)).all() + + assert len(chart_ids) == expected_number_of_charts + assert len(dashboard_ids) == expected_number_of_dashboards diff --git a/tests/unit_tests/common/test_dataframe_utils.py b/tests/unit_tests/common/test_dataframe_utils.py new file mode 100644 index 0000000000000..01fa4224c3c83 --- /dev/null +++ b/tests/unit_tests/common/test_dataframe_utils.py @@ -0,0 +1,50 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import datetime + +import pandas as pd + +from superset.common.utils import dataframe_utils + + +def test_is_datetime_series(): + assert not dataframe_utils.is_datetime_series(None) + assert not dataframe_utils.is_datetime_series(pd.DataFrame({"foo": [1]})) + assert not dataframe_utils.is_datetime_series(pd.Series([1, 2, 3])) + assert not dataframe_utils.is_datetime_series(pd.Series(["1", "2", "3"])) + assert not dataframe_utils.is_datetime_series(pd.Series()) + assert not dataframe_utils.is_datetime_series(pd.Series([None, None])) + assert dataframe_utils.is_datetime_series( + pd.Series([datetime.date(2018, 1, 1), datetime.date(2018, 1, 2), None]) + ) + assert dataframe_utils.is_datetime_series( + pd.Series([datetime.date(2018, 1, 1), datetime.date(2018, 1, 2)]) + ) + assert dataframe_utils.is_datetime_series( + pd.Series([datetime.datetime(2018, 1, 1), datetime.datetime(2018, 1, 2), None]) + ) + assert dataframe_utils.is_datetime_series( + pd.Series([datetime.datetime(2018, 1, 1), datetime.datetime(2018, 1, 2)]) + ) + assert dataframe_utils.is_datetime_series( + pd.date_range(datetime.date(2018, 1, 1), datetime.date(2018, 2, 1)).to_series() + ) + assert dataframe_utils.is_datetime_series( + pd.date_range( + datetime.datetime(2018, 1, 1), datetime.datetime(2018, 2, 1) + ).to_series() + ) diff --git a/tests/unit_tests/common/test_time_range_utils.py b/tests/unit_tests/common/test_time_range_utils.py new file mode 100644 index 0000000000000..bde1bd4befc0a --- /dev/null +++ b/tests/unit_tests/common/test_time_range_utils.py @@ -0,0 +1,94 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from datetime import datetime +from unittest import mock + +import pytest + +from superset.common.utils.time_range_utils import ( + get_since_until_from_query_object, + get_since_until_from_time_range, +) + + +def test__get_since_until_from_time_range(): + assert get_since_until_from_time_range(time_range="2001 : 2002") == ( + datetime(2001, 1, 1), + datetime(2002, 1, 1), + ) + assert get_since_until_from_time_range( + time_range="2001 : 2002", time_shift="8 hours ago" + ) == ( + datetime(2000, 12, 31, 16, 0, 0), + datetime(2001, 12, 31, 16, 0, 0), + ) + with mock.patch( + "superset.utils.date_parser.EvalDateTruncFunc.eval", + return_value=datetime(2000, 1, 1, 0, 0, 0), + ): + assert ( + get_since_until_from_time_range( + time_range="Last year", + extras={ + "relative_end": "2100", + }, + ) + )[1] == datetime(2100, 1, 1, 0, 0) + with mock.patch( + "superset.utils.date_parser.EvalDateTruncFunc.eval", + return_value=datetime(2000, 1, 1, 0, 0, 0), + ): + assert ( + get_since_until_from_time_range( + time_range="Next year", + extras={ + "relative_start": "2000", + }, + ) + )[0] == datetime(2000, 1, 1, 0, 0) + + +@pytest.mark.query_object( + { + "time_range": "2001 : 2002", + "time_shift": "8 hours ago", + } +) +def test__since_until_from_time_range(dummy_query_object): + assert get_since_until_from_query_object(dummy_query_object) == ( + datetime(2000, 12, 31, 16, 0, 0), + datetime(2001, 12, 31, 16, 0, 0), + ) + + +@pytest.mark.query_object( + { + "filters": [{"col": "dttm", "op": "TEMPORAL_RANGE", "val": "2001 : 2002"}], + "columns": [ + { + "columnType": "BASE_AXIS", + "label": "dttm", + "sqlExpression": "dttm", + } + ], + } +) +def test__since_until_from_adhoc_filters(dummy_query_object): + assert get_since_until_from_query_object(dummy_query_object) == ( + datetime(2001, 1, 1, 0, 0, 0), + datetime(2002, 1, 1, 0, 0, 0), + ) diff --git a/tests/unit_tests/config_test.py b/tests/unit_tests/config_test.py new file mode 100644 index 0000000000000..021193a6cd36e --- /dev/null +++ b/tests/unit_tests/config_test.py @@ -0,0 +1,330 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# pylint: disable=import-outside-toplevel, unused-argument, redefined-outer-name, invalid-name + +from functools import partial +from typing import Any, Dict, TYPE_CHECKING + +import pytest +from pytest_mock import MockerFixture +from sqlalchemy.orm.session import Session + +if TYPE_CHECKING: + from superset.connectors.sqla.models import SqlaTable + +FULL_DTTM_DEFAULTS_EXAMPLE = { + "main_dttm_col": "id", + "dttm_columns": { + "dttm": { + "python_date_format": "epoch_s", + "expression": "CAST(dttm as INTEGER)", + }, + "id": {"python_date_format": "epoch_ms"}, + "month": { + "python_date_format": "%Y-%m-%d", + "expression": ( + "CASE WHEN length(month) = 7 THEN month || '-01' ELSE month END" + ), + }, + }, +} + + +def apply_dttm_defaults(table: "SqlaTable", dttm_defaults: Dict[str, Any]) -> None: + """Applies dttm defaults to the table, mutates in place.""" + for dbcol in table.columns: + # Set is_dttm is column is listed in dttm_columns. + if dbcol.column_name in dttm_defaults.get("dttm_columns", {}): + dbcol.is_dttm = True + + # Skip non dttm columns. + if dbcol.column_name not in dttm_defaults.get("dttm_columns", {}): + continue + + # Set table main_dttm_col. + if dbcol.column_name == dttm_defaults.get("main_dttm_col"): + table.main_dttm_col = dbcol.column_name + + # Apply defaults if empty. + dttm_column_defaults = dttm_defaults.get("dttm_columns", {}).get( + dbcol.column_name, {} + ) + dbcol.is_dttm = True + if ( + not dbcol.python_date_format + and "python_date_format" in dttm_column_defaults + ): + dbcol.python_date_format = dttm_column_defaults["python_date_format"] + if not dbcol.expression and "expression" in dttm_column_defaults: + dbcol.expression = dttm_column_defaults["expression"] + + +@pytest.fixture +def test_table(session: Session) -> "SqlaTable": + """ + Fixture that generates an in-memory table. + """ + from superset.connectors.sqla.models import SqlaTable, TableColumn + from superset.models.core import Database + + engine = session.get_bind() + SqlaTable.metadata.create_all(engine) # pylint: disable=no-member + + columns = [ + TableColumn(column_name="ds", is_dttm=1, type="TIMESTAMP"), + TableColumn(column_name="event_time", is_dttm=1, type="TIMESTAMP"), + TableColumn(column_name="id", type="INTEGER"), + TableColumn(column_name="dttm", type="INTEGER"), + TableColumn(column_name="duration_ms", type="INTEGER"), + ] + + return SqlaTable( + table_name="test_table", + columns=columns, + metrics=[], + main_dttm_col=None, + database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), + ) + + +def test_main_dttm_col(mocker: MockerFixture, test_table: "SqlaTable") -> None: + """ + Test the ``SQLA_TABLE_MUTATOR`` config. + """ + dttm_defaults = { + "main_dttm_col": "event_time", + "dttm_columns": {"ds": {}, "event_time": {}}, + } + mocker.patch( + "superset.connectors.sqla.models.config", + new={ + "SQLA_TABLE_MUTATOR": partial( + apply_dttm_defaults, + dttm_defaults=dttm_defaults, + ) + }, + ) + mocker.patch( + "superset.connectors.sqla.models.get_physical_table_metadata", + return_value=[ + {"name": "ds", "type": "TIMESTAMP", "is_dttm": True}, + {"name": "event_time", "type": "TIMESTAMP", "is_dttm": True}, + {"name": "id", "type": "INTEGER", "is_dttm": False}, + ], + ) + + assert test_table.main_dttm_col is None + test_table.fetch_metadata() + assert test_table.main_dttm_col == "event_time" + + +def test_main_dttm_col_nonexistent( + mocker: MockerFixture, + test_table: "SqlaTable", +) -> None: + """ + Test the ``SQLA_TABLE_MUTATOR`` config when main datetime column doesn't exist. + """ + dttm_defaults = { + "main_dttm_col": "nonexistent", + } + mocker.patch( + "superset.connectors.sqla.models.config", + new={ + "SQLA_TABLE_MUTATOR": partial( + apply_dttm_defaults, + dttm_defaults=dttm_defaults, + ) + }, + ) + mocker.patch( + "superset.connectors.sqla.models.get_physical_table_metadata", + return_value=[ + {"name": "ds", "type": "TIMESTAMP", "is_dttm": True}, + {"name": "event_time", "type": "TIMESTAMP", "is_dttm": True}, + {"name": "id", "type": "INTEGER", "is_dttm": False}, + ], + ) + + assert test_table.main_dttm_col is None + test_table.fetch_metadata() + # fall back to ds + assert test_table.main_dttm_col == "ds" + + +def test_main_dttm_col_nondttm( + mocker: MockerFixture, + test_table: "SqlaTable", +) -> None: + """ + Test the ``SQLA_TABLE_MUTATOR`` config when main datetime column has wrong type. + """ + dttm_defaults = { + "main_dttm_col": "id", + } + mocker.patch( + "superset.connectors.sqla.models.config", + new={ + "SQLA_TABLE_MUTATOR": partial( + apply_dttm_defaults, + dttm_defaults=dttm_defaults, + ) + }, + ) + mocker.patch( + "superset.connectors.sqla.models.get_physical_table_metadata", + return_value=[ + {"name": "ds", "type": "TIMESTAMP", "is_dttm": True}, + {"name": "event_time", "type": "TIMESTAMP", "is_dttm": True}, + {"name": "id", "type": "INTEGER", "is_dttm": False}, + ], + ) + + assert test_table.main_dttm_col is None + test_table.fetch_metadata() + # fall back to ds + assert test_table.main_dttm_col == "ds" + + +def test_python_date_format_by_column_name( + mocker: MockerFixture, + test_table: "SqlaTable", +) -> None: + """ + Test the ``SQLA_TABLE_MUTATOR`` setting for "python_date_format". + """ + table_defaults = { + "dttm_columns": { + "id": {"python_date_format": "epoch_ms"}, + "dttm": {"python_date_format": "epoch_s"}, + "duration_ms": {"python_date_format": "invalid"}, + }, + } + mocker.patch( + "superset.connectors.sqla.models.config", + new={ + "SQLA_TABLE_MUTATOR": partial( + apply_dttm_defaults, + dttm_defaults=table_defaults, + ) + }, + ) + mocker.patch( + "superset.connectors.sqla.models.get_physical_table_metadata", + return_value=[ + {"name": "id", "type": "INTEGER", "is_dttm": False}, + {"name": "dttm", "type": "INTEGER", "is_dttm": False}, + {"name": "duration_ms", "type": "INTEGER", "is_dttm": False}, + ], + ) + + test_table.fetch_metadata() + + id_col = [c for c in test_table.columns if c.column_name == "id"][0] + assert id_col.is_dttm + assert id_col.python_date_format == "epoch_ms" + + dttm_col = [c for c in test_table.columns if c.column_name == "dttm"][0] + assert dttm_col.is_dttm + assert dttm_col.python_date_format == "epoch_s" + + duration_ms_col = [c for c in test_table.columns if c.column_name == "duration_ms"][ + 0 + ] + assert duration_ms_col.is_dttm + assert duration_ms_col.python_date_format == "invalid" + + +def test_expression_by_column_name( + mocker: MockerFixture, + test_table: "SqlaTable", +) -> None: + """ + Test the ``SQLA_TABLE_MUTATOR`` setting for expression. + """ + table_defaults = { + "dttm_columns": { + "dttm": {"expression": "CAST(dttm as INTEGER)"}, + "duration_ms": {"expression": "CAST(duration_ms as DOUBLE)"}, + }, + } + mocker.patch( + "superset.connectors.sqla.models.config", + new={ + "SQLA_TABLE_MUTATOR": partial( + apply_dttm_defaults, + dttm_defaults=table_defaults, + ) + }, + ) + mocker.patch( + "superset.connectors.sqla.models.get_physical_table_metadata", + return_value=[ + {"name": "dttm", "type": "INTEGER", "is_dttm": False}, + {"name": "duration_ms", "type": "INTEGER", "is_dttm": False}, + ], + ) + + test_table.fetch_metadata() + + dttm_col = [c for c in test_table.columns if c.column_name == "dttm"][0] + assert dttm_col.is_dttm + assert dttm_col.expression == "CAST(dttm as INTEGER)" + + duration_ms_col = [c for c in test_table.columns if c.column_name == "duration_ms"][ + 0 + ] + assert duration_ms_col.is_dttm + assert duration_ms_col.expression == "CAST(duration_ms as DOUBLE)" + + +def test_full_setting( + mocker: MockerFixture, + test_table: "SqlaTable", +) -> None: + """ + Test the ``SQLA_TABLE_MUTATOR`` with full settings. + """ + mocker.patch( + "superset.connectors.sqla.models.config", + new={ + "SQLA_TABLE_MUTATOR": partial( + apply_dttm_defaults, + dttm_defaults=FULL_DTTM_DEFAULTS_EXAMPLE, + ) + }, + ) + mocker.patch( + "superset.connectors.sqla.models.get_physical_table_metadata", + return_value=[ + {"name": "id", "type": "INTEGER", "is_dttm": False}, + {"name": "dttm", "type": "INTEGER", "is_dttm": False}, + {"name": "duration_ms", "type": "INTEGER", "is_dttm": False}, + ], + ) + + test_table.fetch_metadata() + + id_col = [c for c in test_table.columns if c.column_name == "id"][0] + assert id_col.is_dttm + assert id_col.python_date_format == "epoch_ms" + assert id_col.expression == "" + + dttm_col = [c for c in test_table.columns if c.column_name == "dttm"][0] + assert dttm_col.is_dttm + assert dttm_col.python_date_format == "epoch_s" + assert dttm_col.expression == "CAST(dttm as INTEGER)" diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 274aff8194466..52c372ea59281 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -17,9 +17,12 @@ # pylint: disable=redefined-outer-name, import-outside-toplevel import importlib +import os +import unittest.mock from typing import Any, Callable, Iterator import pytest +from _pytest.fixtures import SubRequest from pytest_mock import MockFixture from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker @@ -27,6 +30,8 @@ from superset import security_manager from superset.app import SupersetApp +from superset.common.chart_data import ChartDataResultType +from superset.common.query_object_factory import QueryObjectFactory from superset.extensions import appbuilder from superset.initialization import SupersetAppInitializer @@ -46,10 +51,15 @@ def get_session(): in_memory_session.remove = lambda: None # patch session - mocker.patch( + get_session = mocker.patch( "superset.security.SupersetSecurityManager.get_session", - return_value=in_memory_session, ) + get_session.return_value = in_memory_session + # FAB calls get_session.get_bind() to get a handler to the engine + get_session.get_bind.return_value = engine + # Allow for queries on security manager + get_session.query = in_memory_session.query + mocker.patch("superset.db.session", in_memory_session) return in_memory_session @@ -62,17 +72,25 @@ def session(get_session) -> Iterator[Session]: @pytest.fixture(scope="module") -def app() -> Iterator[SupersetApp]: +def app(request: SubRequest) -> Iterator[SupersetApp]: """ A fixture that generates a Superset app. """ app = SupersetApp(__name__) app.config.from_object("superset.config") - app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://" + app.config["SQLALCHEMY_DATABASE_URI"] = ( + os.environ.get("SUPERSET__SQLALCHEMY_DATABASE_URI") or "sqlite://" + ) app.config["WTF_CSRF_ENABLED"] = False + app.config["PREVENT_UNSAFE_DB_CONNECTIONS"] = False app.config["TESTING"] = True + # loop over extra configs passed in by tests + if request and hasattr(request, "param"): + for key, val in request.param.items(): + app.config[key] = val + # ``superset.extensions.appbuilder`` is a singleton, and won't rebuild the # routes when this fixture is called multiple times; we need to clear the # registered views to ensure the initialization can happen more than once. @@ -96,7 +114,7 @@ def client(app: SupersetApp) -> Any: yield client -@pytest.fixture +@pytest.fixture(autouse=True) def app_context(app: SupersetApp) -> Iterator[None]: """ A fixture that yields and application context. @@ -120,3 +138,27 @@ def full_api_access(mocker: MockFixture) -> Iterator[None]: mocker.patch.object(security_manager, "can_access_all_databases", return_value=True) yield + + +@pytest.fixture +def dummy_query_object(request, app_context): + query_obj_marker = request.node.get_closest_marker("query_object") + result_type_marker = request.node.get_closest_marker("result_type") + + if query_obj_marker is None: + query_object = {} + else: + query_object = query_obj_marker.args[0] + + if result_type_marker is None: + result_type = ChartDataResultType.FULL + else: + result_type = result_type_marker.args[0] + + yield QueryObjectFactory( + app_configurations={ + "ROW_LIMIT": 100, + }, + _datasource_dao=unittest.mock.Mock(), + session_maker=unittest.mock.Mock(), + ).create(parent_result_type=result_type, **query_object) diff --git a/tests/unit_tests/core_tests.py b/tests/unit_tests/core_tests.py index f7a0047157bb8..1473f18382950 100644 --- a/tests/unit_tests/core_tests.py +++ b/tests/unit_tests/core_tests.py @@ -30,7 +30,6 @@ get_metric_names, get_time_filter_status, is_adhoc_metric, - NO_TIME_RANGE, ) from tests.unit_tests.fixtures.datasets import get_dataset_mock @@ -105,6 +104,18 @@ def test_get_metric_name_invalid_metric(): with pytest.raises(ValueError): get_metric_name(metric) + metric = deepcopy(SQL_ADHOC_METRIC) + del metric["expressionType"] + with pytest.raises(ValueError): + get_metric_name(metric) + + with pytest.raises(ValueError): + get_metric_name(None) + with pytest.raises(ValueError): + get_metric_name(0) + with pytest.raises(ValueError): + get_metric_name({}) + def test_get_metric_names(): assert get_metric_names( diff --git a/tests/unit_tests/dao/queries_test.py b/tests/unit_tests/dao/queries_test.py index 8df6d2066aaca..62eeff31065e0 100644 --- a/tests/unit_tests/dao/queries_test.py +++ b/tests/unit_tests/dao/queries_test.py @@ -15,13 +15,17 @@ # specific language governing permissions and limitations # under the License. import json -from typing import Iterator +from datetime import datetime, timedelta +from typing import Any, Iterator import pytest +from pytest_mock import MockFixture from sqlalchemy.orm.session import Session +from superset.exceptions import QueryNotFoundException, SupersetCancelQueryException -def test_query_dao_save_metadata(app_context: None, session: Session) -> None: + +def test_query_dao_save_metadata(session: Session) -> None: from superset.models.core import Database from superset.models.sql_lab import Query @@ -53,3 +57,218 @@ def test_query_dao_save_metadata(app_context: None, session: Session) -> None: query = session.query(Query).one() QueryDAO.save_metadata(query=query, payload={"columns": []}) assert query.extra.get("columns", None) == [] + + +def test_query_dao_get_queries_changed_after(session: Session) -> None: + from superset.models.core import Database + from superset.models.sql_lab import Query + + engine = session.get_bind() + Query.metadata.create_all(engine) # pylint: disable=no-member + + db = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + + now = datetime.utcnow() + + old_query_obj = Query( + client_id="foo", + database=db, + tab_name="test_tab", + sql_editor_id="test_editor_id", + sql="select * from bar", + select_sql="select * from bar", + executed_sql="select * from bar", + limit=100, + select_as_cta=False, + rows=100, + error_message="none", + results_key="abc", + changed_on=now - timedelta(days=3), + ) + + updated_query_obj = Query( + client_id="updated_foo", + database=db, + tab_name="test_tab", + sql_editor_id="test_editor_id", + sql="select * from foo", + select_sql="select * from foo", + executed_sql="select * from foo", + limit=100, + select_as_cta=False, + rows=100, + error_message="none", + results_key="abc", + changed_on=now - timedelta(days=1), + ) + + session.add(db) + session.add(old_query_obj) + session.add(updated_query_obj) + + from superset.queries.dao import QueryDAO + + timestamp = datetime.timestamp(now - timedelta(days=2)) * 1000 + result = QueryDAO.get_queries_changed_after(timestamp) + assert len(result) == 1 + assert result[0].client_id == "updated_foo" + + +def test_query_dao_stop_query_not_found( + mocker: MockFixture, app: Any, session: Session +) -> None: + from superset.common.db_query_status import QueryStatus + from superset.models.core import Database + from superset.models.sql_lab import Query + + engine = session.get_bind() + Query.metadata.create_all(engine) # pylint: disable=no-member + + db = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + + query_obj = Query( + client_id="foo", + database=db, + tab_name="test_tab", + sql_editor_id="test_editor_id", + sql="select * from bar", + select_sql="select * from bar", + executed_sql="select * from bar", + limit=100, + select_as_cta=False, + rows=100, + error_message="none", + results_key="abc", + status=QueryStatus.RUNNING, + ) + + session.add(db) + session.add(query_obj) + + mocker.patch("superset.sql_lab.cancel_query", return_value=False) + + from superset.queries.dao import QueryDAO + + with pytest.raises(QueryNotFoundException): + QueryDAO.stop_query("foo2") + + query = session.query(Query).one() + assert query.status == QueryStatus.RUNNING + + +def test_query_dao_stop_query_not_running( + mocker: MockFixture, app: Any, session: Session +) -> None: + from superset.common.db_query_status import QueryStatus + from superset.models.core import Database + from superset.models.sql_lab import Query + + engine = session.get_bind() + Query.metadata.create_all(engine) # pylint: disable=no-member + + db = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + + query_obj = Query( + client_id="foo", + database=db, + tab_name="test_tab", + sql_editor_id="test_editor_id", + sql="select * from bar", + select_sql="select * from bar", + executed_sql="select * from bar", + limit=100, + select_as_cta=False, + rows=100, + error_message="none", + results_key="abc", + status=QueryStatus.FAILED, + ) + + session.add(db) + session.add(query_obj) + + from superset.queries.dao import QueryDAO + + QueryDAO.stop_query(query_obj.client_id) + query = session.query(Query).one() + assert query.status == QueryStatus.FAILED + + +def test_query_dao_stop_query_failed( + mocker: MockFixture, app: Any, session: Session +) -> None: + from superset.common.db_query_status import QueryStatus + from superset.models.core import Database + from superset.models.sql_lab import Query + + engine = session.get_bind() + Query.metadata.create_all(engine) # pylint: disable=no-member + + db = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + + query_obj = Query( + client_id="foo", + database=db, + tab_name="test_tab", + sql_editor_id="test_editor_id", + sql="select * from bar", + select_sql="select * from bar", + executed_sql="select * from bar", + limit=100, + select_as_cta=False, + rows=100, + error_message="none", + results_key="abc", + status=QueryStatus.RUNNING, + ) + + session.add(db) + session.add(query_obj) + + mocker.patch("superset.sql_lab.cancel_query", return_value=False) + + from superset.queries.dao import QueryDAO + + with pytest.raises(SupersetCancelQueryException): + QueryDAO.stop_query(query_obj.client_id) + + query = session.query(Query).one() + assert query.status == QueryStatus.RUNNING + + +def test_query_dao_stop_query(mocker: MockFixture, app: Any, session: Session) -> None: + from superset.common.db_query_status import QueryStatus + from superset.models.core import Database + from superset.models.sql_lab import Query + + engine = session.get_bind() + Query.metadata.create_all(engine) # pylint: disable=no-member + + db = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + + query_obj = Query( + client_id="foo", + database=db, + tab_name="test_tab", + sql_editor_id="test_editor_id", + sql="select * from bar", + select_sql="select * from bar", + executed_sql="select * from bar", + limit=100, + select_as_cta=False, + rows=100, + error_message="none", + results_key="abc", + status=QueryStatus.RUNNING, + ) + + session.add(db) + session.add(query_obj) + + mocker.patch("superset.sql_lab.cancel_query", return_value=True) + + from superset.queries.dao import QueryDAO + + QueryDAO.stop_query(query_obj.client_id) + query = session.query(Query).one() + assert query.status == QueryStatus.STOPPED diff --git a/tests/unit_tests/dashboards/commands/importers/v1/import_test.py b/tests/unit_tests/dashboards/commands/importers/v1/import_test.py index 651e5dc10b7ca..08f681d916b3c 100644 --- a/tests/unit_tests/dashboards/commands/importers/v1/import_test.py +++ b/tests/unit_tests/dashboards/commands/importers/v1/import_test.py @@ -21,7 +21,7 @@ from sqlalchemy.orm.session import Session -def test_import_dashboard(app_context: None, session: Session) -> None: +def test_import_dashboard(session: Session) -> None: """ Test importing a dashboard. """ @@ -43,9 +43,7 @@ def test_import_dashboard(app_context: None, session: Session) -> None: assert dashboard.external_url is None -def test_import_dashboard_managed_externally( - app_context: None, session: Session -) -> None: +def test_import_dashboard_managed_externally(session: Session) -> None: """ Test importing a dashboard that is managed externally. """ diff --git a/tests/unit_tests/dashboards/commands/importers/v1/utils_test.py b/tests/unit_tests/dashboards/commands/importers/v1/utils_test.py index bddc96eda36e6..0392acb31596a 100644 --- a/tests/unit_tests/dashboards/commands/importers/v1/utils_test.py +++ b/tests/unit_tests/dashboards/commands/importers/v1/utils_test.py @@ -82,7 +82,7 @@ def test_update_id_refs_immune_missing( # pylint: disable=invalid-name } -def test_update_native_filter_config_scope_excluded(app_context: None): +def test_update_native_filter_config_scope_excluded(): from superset.dashboards.commands.importers.v1.utils import update_id_refs config = { diff --git a/tests/unit_tests/databases/api_test.py b/tests/unit_tests/databases/api_test.py index 2d20e5346f43e..68a9add12e9a4 100644 --- a/tests/unit_tests/databases/api_test.py +++ b/tests/unit_tests/databases/api_test.py @@ -17,10 +17,147 @@ # pylint: disable=unused-argument, import-outside-toplevel, line-too-long +import json from io import BytesIO from typing import Any +from uuid import UUID import pytest +from pytest_mock import MockFixture +from sqlalchemy.orm.session import Session + + +def test_post_with_uuid( + session: Session, + client: Any, + full_api_access: None, +) -> None: + """ + Test that we can set the database UUID when creating it. + """ + from superset.models.core import Database + + # create table for databases + Database.metadata.create_all(session.get_bind()) # pylint: disable=no-member + + response = client.post( + "/api/v1/database/", + json={ + "database_name": "my_db", + "sqlalchemy_uri": "sqlite://", + "uuid": "7c1b7880-a59d-47cd-8bf1-f1eb8d2863cb", + }, + ) + assert response.status_code == 201 + + database = session.query(Database).one() + assert database.uuid == UUID("7c1b7880-a59d-47cd-8bf1-f1eb8d2863cb") + + +def test_password_mask( + mocker: MockFixture, + app: Any, + session: Session, + client: Any, + full_api_access: None, +) -> None: + """ + Test that sensitive information is masked. + """ + from superset.databases.api import DatabaseRestApi + from superset.models.core import Database + + DatabaseRestApi.datamodel.session = session + + # create table for databases + Database.metadata.create_all(session.get_bind()) # pylint: disable=no-member + + database = Database( + database_name="my_database", + sqlalchemy_uri="gsheets://", + encrypted_extra=json.dumps( + { + "service_account_info": { + "type": "service_account", + "project_id": "black-sanctum-314419", + "private_key_id": "259b0d419a8f840056158763ff54d8b08f7b8173", + "private_key": "SECRET", + "client_email": "google-spreadsheets-demo-servi@black-sanctum-314419.iam.gserviceaccount.com", + "client_id": "114567578578109757129", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/google-spreadsheets-demo-servi%40black-sanctum-314419.iam.gserviceaccount.com", + }, + } + ), + ) + session.add(database) + session.commit() + + # mock the lookup so that we don't need to include the driver + mocker.patch("sqlalchemy.engine.URL.get_driver_name", return_value="gsheets") + mocker.patch("superset.utils.log.DBEventLogger.log") + + response = client.get("/api/v1/database/1") + assert ( + response.json["result"]["parameters"]["service_account_info"]["private_key"] + == "XXXXXXXXXX" + ) + assert "encrypted_extra" not in response.json["result"] + + +@pytest.mark.skip(reason="Works locally but fails on CI") +def test_update_with_password_mask( + app: Any, + session: Session, + client: Any, + full_api_access: None, +) -> None: + """ + Test that an update with a masked password doesn't overwrite the existing password. + """ + from superset.databases.api import DatabaseRestApi + from superset.models.core import Database + + DatabaseRestApi.datamodel.session = session + + # create table for databases + Database.metadata.create_all(session.get_bind()) # pylint: disable=no-member + + database = Database( + database_name="my_database", + sqlalchemy_uri="gsheets://", + encrypted_extra=json.dumps( + { + "service_account_info": { + "project_id": "black-sanctum-314419", + "private_key": "SECRET", + }, + } + ), + ) + session.add(database) + session.commit() + + client.put( + "/api/v1/database/1", + json={ + "encrypted_extra": json.dumps( + { + "service_account_info": { + "project_id": "yellow-unicorn-314419", + "private_key": "XXXXXXXXXX", + }, + } + ), + }, + ) + database = session.query(Database).one() + assert ( + database.encrypted_extra + == '{"service_account_info": {"project_id": "yellow-unicorn-314419", "private_key": "SECRET"}}' + ) def test_non_zip_import(client: Any, full_api_access: None) -> None: @@ -54,3 +191,155 @@ def test_non_zip_import(client: Any, full_api_access: None) -> None: } ] } + + +def test_delete_ssh_tunnel( + mocker: MockFixture, + app: Any, + session: Session, + client: Any, + full_api_access: None, +) -> None: + """ + Test that we can delete SSH Tunnel + """ + with app.app_context(): + from superset.databases.api import DatabaseRestApi + from superset.databases.dao import DatabaseDAO + from superset.databases.ssh_tunnel.models import SSHTunnel + from superset.models.core import Database + + DatabaseRestApi.datamodel.session = session + + # create table for databases + Database.metadata.create_all(session.get_bind()) # pylint: disable=no-member + + # Create our Database + database = Database( + database_name="my_database", + sqlalchemy_uri="gsheets://", + encrypted_extra=json.dumps( + { + "service_account_info": { + "type": "service_account", + "project_id": "black-sanctum-314419", + "private_key_id": "259b0d419a8f840056158763ff54d8b08f7b8173", + "private_key": "SECRET", + "client_email": "google-spreadsheets-demo-servi@black-sanctum-314419.iam.gserviceaccount.com", + "client_id": "SSH_TUNNEL_CREDENTIALS_CLIENT", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/google-spreadsheets-demo-servi%40black-sanctum-314419.iam.gserviceaccount.com", + }, + } + ), + ) + session.add(database) + session.commit() + + # mock the lookup so that we don't need to include the driver + mocker.patch("sqlalchemy.engine.URL.get_driver_name", return_value="gsheets") + mocker.patch("superset.utils.log.DBEventLogger.log") + mocker.patch( + "superset.databases.ssh_tunnel.commands.delete.is_feature_enabled", + return_value=True, + ) + + # Create our SSHTunnel + tunnel = SSHTunnel( + database_id=1, + database=database, + ) + + session.add(tunnel) + session.commit() + + # Get our recently created SSHTunnel + response_tunnel = DatabaseDAO.get_ssh_tunnel(1) + assert response_tunnel + assert isinstance(response_tunnel, SSHTunnel) + assert 1 == response_tunnel.database_id + + # Delete the recently created SSHTunnel + response_delete_tunnel = client.delete("/api/v1/database/1/ssh_tunnel/") + assert response_delete_tunnel.json["message"] == "OK" + + response_tunnel = DatabaseDAO.get_ssh_tunnel(1) + assert response_tunnel is None + + +def test_delete_ssh_tunnel_not_found( + mocker: MockFixture, + app: Any, + session: Session, + client: Any, + full_api_access: None, +) -> None: + """ + Test that we cannot delete a tunnel that does not exist + """ + with app.app_context(): + from superset.databases.api import DatabaseRestApi + from superset.databases.dao import DatabaseDAO + from superset.databases.ssh_tunnel.models import SSHTunnel + from superset.models.core import Database + + DatabaseRestApi.datamodel.session = session + + # create table for databases + Database.metadata.create_all(session.get_bind()) # pylint: disable=no-member + + # Create our Database + database = Database( + database_name="my_database", + sqlalchemy_uri="gsheets://", + encrypted_extra=json.dumps( + { + "service_account_info": { + "type": "service_account", + "project_id": "black-sanctum-314419", + "private_key_id": "259b0d419a8f840056158763ff54d8b08f7b8173", + "private_key": "SECRET", + "client_email": "google-spreadsheets-demo-servi@black-sanctum-314419.iam.gserviceaccount.com", + "client_id": "SSH_TUNNEL_CREDENTIALS_CLIENT", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/google-spreadsheets-demo-servi%40black-sanctum-314419.iam.gserviceaccount.com", + }, + } + ), + ) + session.add(database) + session.commit() + + # mock the lookup so that we don't need to include the driver + mocker.patch("sqlalchemy.engine.URL.get_driver_name", return_value="gsheets") + mocker.patch("superset.utils.log.DBEventLogger.log") + mocker.patch( + "superset.databases.ssh_tunnel.commands.delete.is_feature_enabled", + return_value=True, + ) + + # Create our SSHTunnel + tunnel = SSHTunnel( + database_id=1, + database=database, + ) + + session.add(tunnel) + session.commit() + + # Delete the recently created SSHTunnel + response_delete_tunnel = client.delete("/api/v1/database/2/ssh_tunnel/") + assert response_delete_tunnel.json["message"] == "Not found" + + # Get our recently created SSHTunnel + response_tunnel = DatabaseDAO.get_ssh_tunnel(1) + assert response_tunnel + assert isinstance(response_tunnel, SSHTunnel) + assert 1 == response_tunnel.database_id + + response_tunnel = DatabaseDAO.get_ssh_tunnel(2) + assert response_tunnel is None diff --git a/tests/unit_tests/databases/commands/importers/v1/import_test.py b/tests/unit_tests/databases/commands/importers/v1/import_test.py index 622aa27fc3d56..e665bcb505d55 100644 --- a/tests/unit_tests/databases/commands/importers/v1/import_test.py +++ b/tests/unit_tests/databases/commands/importers/v1/import_test.py @@ -21,7 +21,7 @@ from sqlalchemy.orm.session import Session -def test_import_database(app_context: None, session: Session) -> None: +def test_import_database(session: Session) -> None: """ Test importing a database. """ @@ -41,16 +41,24 @@ def test_import_database(app_context: None, session: Session) -> None: assert database.allow_run_async is False assert database.allow_ctas is True assert database.allow_cvas is True + assert database.allow_dml is True assert database.allow_file_upload is True assert database.extra == "{}" assert database.uuid == "b8a1ccd3-779d-4ab7-8ad8-9ab119d7fe89" assert database.is_managed_externally is False assert database.external_url is None + # ``allow_dml`` was initially not exported; the import should work if the field is + # missing + config = copy.deepcopy(database_config) + del config["allow_dml"] + session.delete(database) + session.flush() + database = import_database(session, config) + assert database.allow_dml is False + -def test_import_database_managed_externally( - app_context: None, session: Session -) -> None: +def test_import_database_managed_externally(session: Session) -> None: """ Test importing a database that is managed externally. """ diff --git a/tests/unit_tests/databases/commands/test_connection_test.py b/tests/unit_tests/databases/commands/test_connection_test.py new file mode 100644 index 0000000000000..8e86cfd1cfe9b --- /dev/null +++ b/tests/unit_tests/databases/commands/test_connection_test.py @@ -0,0 +1,32 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from parameterized import parameterized + +from superset.databases.commands.test_connection import get_log_connection_action +from superset.databases.ssh_tunnel.models import SSHTunnel + + +@parameterized.expand( + [ + ("foo", None, None, "foo"), + ("foo", SSHTunnel, None, "foo.ssh_tunnel"), + ("foo", SSHTunnel, Exception("oops"), "foo.Exception.ssh_tunnel"), + ], +) +def test_get_log_connection_action(action, tunnel, exc, expected_result): + assert expected_result == get_log_connection_action(action, tunnel, exc) diff --git a/tests/unit_tests/databases/dao/__init__.py b/tests/unit_tests/databases/dao/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/databases/dao/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/databases/dao/dao_tests.py b/tests/unit_tests/databases/dao/dao_tests.py new file mode 100644 index 0000000000000..47db402670dee --- /dev/null +++ b/tests/unit_tests/databases/dao/dao_tests.py @@ -0,0 +1,69 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from typing import Iterator + +import pytest +from sqlalchemy.orm.session import Session + + +@pytest.fixture +def session_with_data(session: Session) -> Iterator[Session]: + from superset.connectors.sqla.models import SqlaTable + from superset.databases.ssh_tunnel.models import SSHTunnel + from superset.models.core import Database + + engine = session.get_bind() + SqlaTable.metadata.create_all(engine) # pylint: disable=no-member + + db = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + sqla_table = SqlaTable( + table_name="my_sqla_table", + columns=[], + metrics=[], + database=db, + ) + ssh_tunnel = SSHTunnel( + database_id=db.id, + database=db, + ) + + session.add(db) + session.add(sqla_table) + session.add(ssh_tunnel) + session.flush() + yield session + session.rollback() + + +def test_database_get_ssh_tunnel(session_with_data: Session) -> None: + from superset.databases.dao import DatabaseDAO + from superset.databases.ssh_tunnel.models import SSHTunnel + + result = DatabaseDAO.get_ssh_tunnel(1) + + assert result + assert isinstance(result, SSHTunnel) + assert 1 == result.database_id + + +def test_database_get_ssh_tunnel_not_found(session_with_data: Session) -> None: + from superset.databases.dao import DatabaseDAO + + result = DatabaseDAO.get_ssh_tunnel(2) + + assert result is None diff --git a/tests/unit_tests/databases/schema_tests.py b/tests/unit_tests/databases/schema_tests.py new file mode 100644 index 0000000000000..c9fca22d1b28d --- /dev/null +++ b/tests/unit_tests/databases/schema_tests.py @@ -0,0 +1,227 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# pylint: disable=import-outside-toplevel, invalid-name, unused-argument, redefined-outer-name + +from typing import TYPE_CHECKING + +import pytest +from marshmallow import fields, Schema, ValidationError +from pytest_mock import MockFixture + +if TYPE_CHECKING: + from superset.databases.schemas import DatabaseParametersSchemaMixin + from superset.db_engine_specs.base import BasicParametersMixin + + +# pylint: disable=too-few-public-methods +class InvalidEngine: + """ + An invalid DB engine spec. + """ + + +@pytest.fixture +def dummy_schema() -> "DatabaseParametersSchemaMixin": + """ + Fixture providing a dummy schema. + """ + from superset.databases.schemas import DatabaseParametersSchemaMixin + + class DummySchema(Schema, DatabaseParametersSchemaMixin): + sqlalchemy_uri = fields.String() + + return DummySchema() + + +@pytest.fixture +def dummy_engine(mocker: MockFixture) -> None: + """ + Fixture proving a dummy DB engine spec. + """ + from superset.db_engine_specs.base import BasicParametersMixin + + class DummyEngine(BasicParametersMixin): + engine = "dummy" + default_driver = "dummy" + + mocker.patch("superset.databases.schemas.get_engine_spec", return_value=DummyEngine) + + +def test_database_parameters_schema_mixin( + dummy_engine: None, + dummy_schema: "Schema", +) -> None: + from superset.models.core import ConfigurationMethod + + payload = { + "engine": "dummy_engine", + "configuration_method": ConfigurationMethod.DYNAMIC_FORM, + "parameters": { + "username": "username", + "password": "password", + "host": "localhost", + "port": 12345, + "database": "dbname", + }, + } + result = dummy_schema.load(payload) + assert result == { + "configuration_method": ConfigurationMethod.DYNAMIC_FORM, + "sqlalchemy_uri": "dummy+dummy://username:password@localhost:12345/dbname", + } + + +def test_database_parameters_schema_mixin_no_engine( + dummy_schema: "Schema", +) -> None: + from superset.models.core import ConfigurationMethod + + payload = { + "configuration_method": ConfigurationMethod.DYNAMIC_FORM, + "parameters": { + "username": "username", + "password": "password", + "host": "localhost", + "port": 12345, + "database": "dbname", + }, + } + try: + dummy_schema.load(payload) + except ValidationError as err: + assert err.messages == { + "_schema": [ + ( + "An engine must be specified when passing individual parameters to " + "a database." + ), + ] + } + + +def test_database_parameters_schema_mixin_invalid_engine( + dummy_engine: None, + dummy_schema: "Schema", +) -> None: + from superset.models.core import ConfigurationMethod + + payload = { + "engine": "dummy_engine", + "configuration_method": ConfigurationMethod.DYNAMIC_FORM, + "parameters": { + "username": "username", + "password": "password", + "host": "localhost", + "port": 12345, + "database": "dbname", + }, + } + try: + dummy_schema.load(payload) + except ValidationError as err: + assert err.messages == { + "_schema": ['Engine "dummy_engine" is not a valid engine.'] + } + + +def test_database_parameters_schema_no_mixin( + dummy_engine: None, + dummy_schema: "Schema", +) -> None: + from superset.models.core import ConfigurationMethod + + payload = { + "engine": "invalid_engine", + "configuration_method": ConfigurationMethod.DYNAMIC_FORM, + "parameters": { + "username": "username", + "password": "password", + "host": "localhost", + "port": 12345, + "database": "dbname", + }, + } + try: + dummy_schema.load(payload) + except ValidationError as err: + assert err.messages == { + "_schema": [ + ( + 'Engine spec "InvalidEngine" does not support ' + "being configured via individual parameters." + ) + ] + } + + +def test_database_parameters_schema_mixin_invalid_type( + dummy_engine: None, + dummy_schema: "Schema", +) -> None: + from superset.models.core import ConfigurationMethod + + payload = { + "engine": "dummy_engine", + "configuration_method": ConfigurationMethod.DYNAMIC_FORM, + "parameters": { + "username": "username", + "password": "password", + "host": "localhost", + "port": "badport", + "database": "dbname", + }, + } + try: + dummy_schema.load(payload) + except ValidationError as err: + assert err.messages == {"port": ["Not a valid integer."]} + + +def test_rename_encrypted_extra() -> None: + """ + Test that ``encrypted_extra`` gets renamed to ``masked_encrypted_extra``. + """ + from superset.databases.schemas import ConfigurationMethod, DatabasePostSchema + + schema = DatabasePostSchema() + + # current schema + payload = schema.load( + { + "database_name": "My database", + "masked_encrypted_extra": "{}", + } + ) + assert payload == { + "database_name": "My database", + "configuration_method": ConfigurationMethod.SQLALCHEMY_FORM, + "masked_encrypted_extra": "{}", + } + + # previous schema + payload = schema.load( + { + "database_name": "My database", + "encrypted_extra": "{}", + } + ) + assert payload == { + "database_name": "My database", + "configuration_method": ConfigurationMethod.SQLALCHEMY_FORM, + "masked_encrypted_extra": "{}", + } diff --git a/tests/unit_tests/databases/ssh_tunnel/__init__.py b/tests/unit_tests/databases/ssh_tunnel/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/databases/ssh_tunnel/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/databases/ssh_tunnel/commands/__init__.py b/tests/unit_tests/databases/ssh_tunnel/commands/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/databases/ssh_tunnel/commands/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/databases/ssh_tunnel/commands/create_test.py b/tests/unit_tests/databases/ssh_tunnel/commands/create_test.py new file mode 100644 index 0000000000000..2a5738ebd396a --- /dev/null +++ b/tests/unit_tests/databases/ssh_tunnel/commands/create_test.py @@ -0,0 +1,68 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from typing import Iterator + +import pytest +from sqlalchemy.orm.session import Session + +from superset.databases.ssh_tunnel.commands.exceptions import SSHTunnelInvalidError + + +def test_create_ssh_tunnel_command() -> None: + from superset.databases.ssh_tunnel.commands.create import CreateSSHTunnelCommand + from superset.databases.ssh_tunnel.models import SSHTunnel + from superset.models.core import Database + + db = Database(id=1, database_name="my_database", sqlalchemy_uri="sqlite://") + + properties = { + "database_id": db.id, + "server_address": "123.132.123.1", + "server_port": "3005", + "username": "foo", + "password": "bar", + } + + result = CreateSSHTunnelCommand(db.id, properties).run() + + assert result is not None + assert isinstance(result, SSHTunnel) + + +def test_create_ssh_tunnel_command_invalid_params() -> None: + from superset.databases.ssh_tunnel.commands.create import CreateSSHTunnelCommand + from superset.databases.ssh_tunnel.models import SSHTunnel + from superset.models.core import Database + + db = Database(id=1, database_name="my_database", sqlalchemy_uri="sqlite://") + + # If we are trying to create a tunnel with a private_key_password + # then a private_key is mandatory + properties = { + "database_id": db.id, + "server_address": "123.132.123.1", + "server_port": "3005", + "username": "foo", + "private_key_password": "bar", + } + + command = CreateSSHTunnelCommand(db.id, properties) + + with pytest.raises(SSHTunnelInvalidError) as excinfo: + command.run() + assert str(excinfo.value) == ("SSH Tunnel parameters are invalid.") diff --git a/tests/unit_tests/databases/ssh_tunnel/commands/delete_test.py b/tests/unit_tests/databases/ssh_tunnel/commands/delete_test.py new file mode 100644 index 0000000000000..b5adf765fa5ab --- /dev/null +++ b/tests/unit_tests/databases/ssh_tunnel/commands/delete_test.py @@ -0,0 +1,73 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from typing import Iterator + +import pytest +from pytest_mock import MockFixture +from sqlalchemy.orm.session import Session + + +@pytest.fixture +def session_with_data(session: Session) -> Iterator[Session]: + from superset.connectors.sqla.models import SqlaTable + from superset.databases.ssh_tunnel.models import SSHTunnel + from superset.models.core import Database + + engine = session.get_bind() + SqlaTable.metadata.create_all(engine) # pylint: disable=no-member + + db = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + sqla_table = SqlaTable( + table_name="my_sqla_table", + columns=[], + metrics=[], + database=db, + ) + ssh_tunnel = SSHTunnel( + database_id=db.id, + database=db, + ) + + session.add(db) + session.add(sqla_table) + session.add(ssh_tunnel) + session.flush() + yield session + session.rollback() + + +def test_delete_ssh_tunnel_command( + mocker: MockFixture, session_with_data: Session +) -> None: + from superset.databases.dao import DatabaseDAO + from superset.databases.ssh_tunnel.commands.delete import DeleteSSHTunnelCommand + from superset.databases.ssh_tunnel.models import SSHTunnel + + result = DatabaseDAO.get_ssh_tunnel(1) + + assert result + assert isinstance(result, SSHTunnel) + assert 1 == result.database_id + mocker.patch( + "superset.databases.ssh_tunnel.commands.delete.is_feature_enabled", + return_value=True, + ) + DeleteSSHTunnelCommand(1).run() + result = DatabaseDAO.get_ssh_tunnel(1) + + assert result is None diff --git a/tests/unit_tests/databases/ssh_tunnel/commands/update_test.py b/tests/unit_tests/databases/ssh_tunnel/commands/update_test.py new file mode 100644 index 0000000000000..58f90054ccd1f --- /dev/null +++ b/tests/unit_tests/databases/ssh_tunnel/commands/update_test.py @@ -0,0 +1,93 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from typing import Iterator + +import pytest +from sqlalchemy.orm.session import Session + +from superset.databases.ssh_tunnel.commands.exceptions import SSHTunnelInvalidError + + +@pytest.fixture +def session_with_data(session: Session) -> Iterator[Session]: + from superset.connectors.sqla.models import SqlaTable + from superset.databases.ssh_tunnel.models import SSHTunnel + from superset.models.core import Database + + engine = session.get_bind() + SqlaTable.metadata.create_all(engine) # pylint: disable=no-member + + db = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + sqla_table = SqlaTable( + table_name="my_sqla_table", + columns=[], + metrics=[], + database=db, + ) + ssh_tunnel = SSHTunnel(database_id=db.id, database=db, server_address="Test") + + session.add(db) + session.add(sqla_table) + session.add(ssh_tunnel) + session.flush() + yield session + session.rollback() + + +def test_update_shh_tunnel_command(session_with_data: Session) -> None: + from superset.databases.dao import DatabaseDAO + from superset.databases.ssh_tunnel.commands.update import UpdateSSHTunnelCommand + from superset.databases.ssh_tunnel.models import SSHTunnel + + result = DatabaseDAO.get_ssh_tunnel(1) + + assert result + assert isinstance(result, SSHTunnel) + assert 1 == result.database_id + assert "Test" == result.server_address + + update_payload = {"server_address": "Test2"} + UpdateSSHTunnelCommand(1, update_payload).run() + + result = DatabaseDAO.get_ssh_tunnel(1) + + assert result + assert isinstance(result, SSHTunnel) + assert "Test2" == result.server_address + + +def test_update_shh_tunnel_invalid_params(session_with_data: Session) -> None: + from superset.databases.dao import DatabaseDAO + from superset.databases.ssh_tunnel.commands.update import UpdateSSHTunnelCommand + from superset.databases.ssh_tunnel.models import SSHTunnel + + result = DatabaseDAO.get_ssh_tunnel(1) + + assert result + assert isinstance(result, SSHTunnel) + assert 1 == result.database_id + assert "Test" == result.server_address + + # If we are trying to update a tunnel with a private_key_password + # then a private_key is mandatory + update_payload = {"private_key_password": "pass"} + command = UpdateSSHTunnelCommand(1, update_payload) + + with pytest.raises(SSHTunnelInvalidError) as excinfo: + command.run() + assert str(excinfo.value) == ("SSH Tunnel parameters are invalid.") diff --git a/tests/unit_tests/databases/ssh_tunnel/dao_tests.py b/tests/unit_tests/databases/ssh_tunnel/dao_tests.py new file mode 100644 index 0000000000000..ae5b6e9bd3c39 --- /dev/null +++ b/tests/unit_tests/databases/ssh_tunnel/dao_tests.py @@ -0,0 +1,43 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from typing import Iterator + +import pytest +from sqlalchemy.orm.session import Session + + +def test_create_ssh_tunnel(): + from superset.databases.dao import DatabaseDAO + from superset.databases.ssh_tunnel.dao import SSHTunnelDAO + from superset.databases.ssh_tunnel.models import SSHTunnel + from superset.models.core import Database + + db = Database(id=1, database_name="my_database", sqlalchemy_uri="sqlite://") + + properties = { + "database_id": db.id, + "server_address": "123.132.123.1", + "server_port": "3005", + "username": "foo", + "password": "bar", + } + + result = SSHTunnelDAO.create(properties) + + assert result is not None + assert isinstance(result, SSHTunnel) diff --git a/tests/unit_tests/databases/utils_test.py b/tests/unit_tests/databases/utils_test.py index 8dbc11a3b7a70..e402ced2a529f 100644 --- a/tests/unit_tests/databases/utils_test.py +++ b/tests/unit_tests/databases/utils_test.py @@ -21,7 +21,7 @@ from superset.databases.utils import make_url_safe -def test_make_url_safe_string(app_context: None, session: Session) -> None: +def test_make_url_safe_string(session: Session) -> None: """ Test converting a string to a safe uri """ @@ -31,7 +31,7 @@ def test_make_url_safe_string(app_context: None, session: Session) -> None: assert uri_safe == make_url(uri_string) -def test_make_url_safe_url(app_context: None, session: Session) -> None: +def test_make_url_safe_url(session: Session) -> None: """ Test converting a url to a safe uri """ diff --git a/tests/unit_tests/dataframe_test.py b/tests/unit_tests/dataframe_test.py index 8785ee1d7b3ec..f0d9bc31b064b 100644 --- a/tests/unit_tests/dataframe_test.py +++ b/tests/unit_tests/dataframe_test.py @@ -19,12 +19,13 @@ import pytest from pandas import Timestamp +from pandas._libs.tslibs import NaT from superset.dataframe import df_to_records from superset.superset_typing import DbapiDescription -def test_df_to_records(app_context: None) -> None: +def test_df_to_records() -> None: from superset.db_engine_specs import BaseEngineSpec from superset.result_set import SupersetResultSet @@ -41,7 +42,104 @@ def test_df_to_records(app_context: None) -> None: ] -def test_js_max_int(app_context: None) -> None: +def test_df_to_records_NaT_type() -> None: + from superset.db_engine_specs import BaseEngineSpec + from superset.result_set import SupersetResultSet + + data = [(NaT,), (Timestamp("2023-01-06 20:50:31.749000+0000", tz="UTC"),)] + cursor_descr: DbapiDescription = [ + ("date", "timestamp with time zone", None, None, None, None, False) + ] + results = SupersetResultSet(data, cursor_descr, BaseEngineSpec) + df = results.to_pandas_df() + + assert df_to_records(df) == [ + {"date": None}, + {"date": "2023-01-06 20:50:31.749000+00:00"}, + ] + + +def test_df_to_records_mixed_emoji_type() -> None: + from superset.db_engine_specs import BaseEngineSpec + from superset.result_set import SupersetResultSet + + data = [ + ("What's up?", "This is a string text", 1), + ("What's up?", "This is a string with an 😍 added", 2), + ("What's up?", NaT, 3), + ("What's up?", "Last emoji 😁", 4), + ] + + cursor_descr: DbapiDescription = [ + ("question", "varchar", None, None, None, None, False), + ("response", "varchar", None, None, None, None, False), + ("count", "integer", None, None, None, None, False), + ] + + results = SupersetResultSet(data, cursor_descr, BaseEngineSpec) + df = results.to_pandas_df() + + assert df_to_records(df) == [ + {"question": "What's up?", "response": "This is a string text", "count": 1}, + { + "question": "What's up?", + "response": "This is a string with an 😍 added", + "count": 2, + }, + { + "question": "What's up?", + "response": None, + "count": 3, + }, + { + "question": "What's up?", + "response": "Last emoji 😁", + "count": 4, + }, + ] + + +def test_df_to_records_mixed_accent_type() -> None: + from superset.db_engine_specs import BaseEngineSpec + from superset.result_set import SupersetResultSet + + data = [ + ("What's up?", "This is a string text", 1), + ("What's up?", "This is a string with áccent", 2), + ("What's up?", NaT, 3), + ("What's up?", "móre áccent", 4), + ] + + cursor_descr: DbapiDescription = [ + ("question", "varchar", None, None, None, None, False), + ("response", "varchar", None, None, None, None, False), + ("count", "integer", None, None, None, None, False), + ] + + results = SupersetResultSet(data, cursor_descr, BaseEngineSpec) + df = results.to_pandas_df() + + assert df_to_records(df) == [ + {"question": "What's up?", "response": "This is a string text", "count": 1}, + { + "question": "What's up?", + "response": "This is a string with áccent", + "count": 2, + }, + { + "question": "What's up?", + "response": None, + "count": 3, + }, + { + "question": "What's up?", + "response": "móre áccent", + "count": 4, + }, + ] + + +def test_js_max_int() -> None: from superset.db_engine_specs import BaseEngineSpec from superset.result_set import SupersetResultSet diff --git a/tests/unit_tests/datasets/commands/export_test.py b/tests/unit_tests/datasets/commands/export_test.py index c7e6da8649e7c..c3ad4f764c4f3 100644 --- a/tests/unit_tests/datasets/commands/export_test.py +++ b/tests/unit_tests/datasets/commands/export_test.py @@ -21,7 +21,7 @@ from sqlalchemy.orm.session import Session -def test_export(app_context: None, session: Session) -> None: +def test_export(session: Session) -> None: """ Test exporting a dataset. """ @@ -194,6 +194,7 @@ def test_export(app_context: None, session: Session) -> None: allow_run_async: false allow_ctas: false allow_cvas: false +allow_dml: false allow_file_upload: false extra: metadata_params: {{}} diff --git a/tests/unit_tests/datasets/commands/importers/v1/import_test.py b/tests/unit_tests/datasets/commands/importers/v1/import_test.py index 07ea8c49d04d9..5b52ac7f1da99 100644 --- a/tests/unit_tests/datasets/commands/importers/v1/import_test.py +++ b/tests/unit_tests/datasets/commands/importers/v1/import_test.py @@ -18,19 +18,25 @@ import copy import json +import re import uuid from typing import Any, Dict +from unittest.mock import Mock, patch +import pytest +from flask import current_app from sqlalchemy.orm.session import Session +from superset.datasets.commands.exceptions import DatasetForbiddenDataURI +from superset.datasets.commands.importers.v1.utils import validate_data_uri -def test_import_dataset(app_context: None, session: Session) -> None: + +def test_import_dataset(session: Session) -> None: """ Test importing a dataset. """ - from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn + from superset.connectors.sqla.models import SqlaTable from superset.datasets.commands.importers.v1.utils import import_dataset - from superset.datasets.schemas import ImportV1DatasetSchema from superset.models.core import Database engine = session.get_bind() @@ -124,11 +130,11 @@ def test_import_dataset(app_context: None, session: Session) -> None: assert len(sqla_table.columns) == 1 assert sqla_table.columns[0].column_name == "profit" assert sqla_table.columns[0].verbose_name is None - assert sqla_table.columns[0].is_dttm is None - assert sqla_table.columns[0].is_active is None + assert sqla_table.columns[0].is_dttm is False + assert sqla_table.columns[0].is_active is True assert sqla_table.columns[0].type == "INTEGER" - assert sqla_table.columns[0].groupby is None - assert sqla_table.columns[0].filterable is None + assert sqla_table.columns[0].groupby is True + assert sqla_table.columns[0].filterable is True assert sqla_table.columns[0].expression == "revenue-expenses" assert sqla_table.columns[0].description is None assert sqla_table.columns[0].python_date_format is None @@ -137,7 +143,130 @@ def test_import_dataset(app_context: None, session: Session) -> None: assert sqla_table.database.id == database.id -def test_import_column_extra_is_string(app_context: None, session: Session) -> None: +def test_import_dataset_duplicate_column(session: Session) -> None: + """ + Test importing a dataset with a column that already exists. + """ + from superset.columns.models import Column as NewColumn + from superset.connectors.sqla.models import SqlaTable, TableColumn + from superset.datasets.commands.importers.v1.utils import import_dataset + from superset.models.core import Database + + engine = session.get_bind() + SqlaTable.metadata.create_all(engine) # pylint: disable=no-member + + dataset_uuid = uuid.uuid4() + + database = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + + session.add(database) + session.flush() + + dataset = SqlaTable( + uuid=dataset_uuid, table_name="existing_dataset", database_id=database.id + ) + column = TableColumn(column_name="existing_column") + session.add(dataset) + session.add(column) + session.flush() + + config = { + "table_name": dataset.table_name, + "main_dttm_col": "ds", + "description": "This is the description", + "default_endpoint": None, + "offset": -8, + "cache_timeout": 3600, + "schema": "my_schema", + "sql": None, + "params": { + "remote_id": 64, + "database_name": "examples", + "import_time": 1606677834, + }, + "template_params": { + "answer": "42", + }, + "filter_select_enabled": True, + "fetch_values_predicate": "foo IN (1, 2)", + "extra": {"warning_markdown": "*WARNING*"}, + "uuid": dataset_uuid, + "metrics": [ + { + "metric_name": "cnt", + "verbose_name": None, + "metric_type": None, + "expression": "COUNT(*)", + "description": None, + "d3format": None, + "extra": {"warning_markdown": None}, + "warning_text": None, + } + ], + "columns": [ + { + "column_name": column.column_name, + "verbose_name": None, + "is_dttm": None, + "is_active": None, + "type": "INTEGER", + "groupby": None, + "filterable": None, + "expression": "revenue-expenses", + "description": None, + "python_date_format": None, + "extra": { + "certified_by": "User", + }, + } + ], + "database_uuid": database.uuid, + "database_id": database.id, + } + + sqla_table = import_dataset(session, config, overwrite=True) + assert sqla_table.table_name == dataset.table_name + assert sqla_table.main_dttm_col == "ds" + assert sqla_table.description == "This is the description" + assert sqla_table.default_endpoint is None + assert sqla_table.offset == -8 + assert sqla_table.cache_timeout == 3600 + assert sqla_table.schema == "my_schema" + assert sqla_table.sql is None + assert sqla_table.params == json.dumps( + {"remote_id": 64, "database_name": "examples", "import_time": 1606677834} + ) + assert sqla_table.template_params == json.dumps({"answer": "42"}) + assert sqla_table.filter_select_enabled is True + assert sqla_table.fetch_values_predicate == "foo IN (1, 2)" + assert sqla_table.extra == '{"warning_markdown": "*WARNING*"}' + assert sqla_table.uuid == dataset_uuid + assert len(sqla_table.metrics) == 1 + assert sqla_table.metrics[0].metric_name == "cnt" + assert sqla_table.metrics[0].verbose_name is None + assert sqla_table.metrics[0].metric_type is None + assert sqla_table.metrics[0].expression == "COUNT(*)" + assert sqla_table.metrics[0].description is None + assert sqla_table.metrics[0].d3format is None + assert sqla_table.metrics[0].extra == '{"warning_markdown": null}' + assert sqla_table.metrics[0].warning_text is None + assert len(sqla_table.columns) == 1 + assert sqla_table.columns[0].column_name == column.column_name + assert sqla_table.columns[0].verbose_name is None + assert sqla_table.columns[0].is_dttm is False + assert sqla_table.columns[0].is_active is True + assert sqla_table.columns[0].type == "INTEGER" + assert sqla_table.columns[0].groupby is True + assert sqla_table.columns[0].filterable is True + assert sqla_table.columns[0].expression == "revenue-expenses" + assert sqla_table.columns[0].description is None + assert sqla_table.columns[0].python_date_format is None + assert sqla_table.columns[0].extra == '{"certified_by": "User"}' + assert sqla_table.database.uuid == database.uuid + assert sqla_table.database.id == database.id + + +def test_import_column_extra_is_string(session: Session) -> None: """ Test importing a dataset when the column extra is a string. """ @@ -217,15 +346,19 @@ def test_import_column_extra_is_string(app_context: None, session: Session) -> N assert sqla_table.extra == '{"warning_markdown": "*WARNING*"}' -def test_import_dataset_managed_externally(app_context: None, session: Session) -> None: +@patch("superset.datasets.commands.importers.v1.utils.request") +def test_import_column_allowed_data_url(request: Mock, session: Session) -> None: """ - Test importing a dataset that is managed externally. + Test importing a dataset when using data key to fetch data from a URL. """ - from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn + import io + + from superset.connectors.sqla.models import SqlaTable from superset.datasets.commands.importers.v1.utils import import_dataset from superset.datasets.schemas import ImportV1DatasetSchema from superset.models.core import Database - from tests.integration_tests.fixtures.importexport import dataset_config + + request.urlopen.return_value = io.StringIO("col1\nvalue1\nvalue2\n") engine = session.get_bind() SqlaTable.metadata.create_all(engine) # pylint: disable=no-member @@ -235,6 +368,73 @@ def test_import_dataset_managed_externally(app_context: None, session: Session) session.flush() dataset_uuid = uuid.uuid4() + yaml_config: Dict[str, Any] = { + "version": "1.0.0", + "table_name": "my_table", + "main_dttm_col": "ds", + "description": "This is the description", + "default_endpoint": None, + "offset": -8, + "cache_timeout": 3600, + "schema": None, + "sql": None, + "params": { + "remote_id": 64, + "database_name": "examples", + "import_time": 1606677834, + }, + "template_params": None, + "filter_select_enabled": True, + "fetch_values_predicate": None, + "extra": None, + "uuid": dataset_uuid, + "metrics": [], + "columns": [ + { + "column_name": "col1", + "verbose_name": None, + "is_dttm": False, + "is_active": True, + "type": "TEXT", + "groupby": False, + "filterable": False, + "expression": None, + "description": None, + "python_date_format": None, + "extra": None, + } + ], + "database_uuid": database.uuid, + "data": "https://some-external-url.com/data.csv", + } + + # the Marshmallow schema should convert strings to objects + schema = ImportV1DatasetSchema() + dataset_config = schema.load(yaml_config) + dataset_config["database_id"] = database.id + _ = import_dataset(session, dataset_config, force_data=True) + session.connection() + assert [("value1",), ("value2",)] == session.execute( + "SELECT * FROM my_table" + ).fetchall() + + +def test_import_dataset_managed_externally(session: Session) -> None: + """ + Test importing a dataset that is managed externally. + """ + from superset.connectors.sqla.models import SqlaTable + from superset.datasets.commands.importers.v1.utils import import_dataset + from superset.models.core import Database + from tests.integration_tests.fixtures.importexport import dataset_config + + engine = session.get_bind() + SqlaTable.metadata.create_all(engine) # pylint: disable=no-member + + database = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + session.add(database) + session.flush() + config = copy.deepcopy(dataset_config) config["is_managed_externally"] = True config["external_url"] = "https://example.org/my_table" @@ -243,3 +443,44 @@ def test_import_dataset_managed_externally(app_context: None, session: Session) sqla_table = import_dataset(session, config) assert sqla_table.is_managed_externally is True assert sqla_table.external_url == "https://example.org/my_table" + + +@pytest.mark.parametrize( + "allowed_urls, data_uri, expected, exception_class", + [ + ([r".*"], "https://some-url/data.csv", True, None), + ( + [r"^https://.+\.domain1\.com\/?.*", r"^https://.+\.domain2\.com\/?.*"], + "https://host1.domain1.com/data.csv", + True, + None, + ), + ( + [r"^https://.+\.domain1\.com\/?.*", r"^https://.+\.domain2\.com\/?.*"], + "https://host2.domain1.com/data.csv", + True, + None, + ), + ( + [r"^https://.+\.domain1\.com\/?.*", r"^https://.+\.domain2\.com\/?.*"], + "https://host1.domain2.com/data.csv", + True, + None, + ), + ( + [r"^https://.+\.domain1\.com\/?.*", r"^https://.+\.domain2\.com\/?.*"], + "https://host1.domain3.com/data.csv", + False, + DatasetForbiddenDataURI, + ), + ([], "https://host1.domain3.com/data.csv", False, DatasetForbiddenDataURI), + (["*"], "https://host1.domain3.com/data.csv", False, re.error), + ], +) +def test_validate_data_uri(allowed_urls, data_uri, expected, exception_class): + current_app.config["DATASET_IMPORT_ALLOWED_DATA_URLS"] = allowed_urls + if expected: + validate_data_uri(data_uri) + else: + with pytest.raises(exception_class): + validate_data_uri(data_uri) diff --git a/tests/unit_tests/datasets/dao/__init__.py b/tests/unit_tests/datasets/dao/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/datasets/dao/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/datasets/dao/dao_tests.py b/tests/unit_tests/datasets/dao/dao_tests.py new file mode 100644 index 0000000000000..350425d08e897 --- /dev/null +++ b/tests/unit_tests/datasets/dao/dao_tests.py @@ -0,0 +1,103 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from typing import Iterator + +import pytest +from sqlalchemy.orm.session import Session + + +@pytest.fixture +def session_with_data(session: Session) -> Iterator[Session]: + from superset.connectors.sqla.models import SqlaTable + from superset.models.core import Database + + engine = session.get_bind() + SqlaTable.metadata.create_all(engine) # pylint: disable=no-member + + db = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + sqla_table = SqlaTable( + table_name="my_sqla_table", + columns=[], + metrics=[], + database=db, + ) + + session.add(db) + session.add(sqla_table) + session.flush() + yield session + session.rollback() + + +def test_datasource_find_by_id_skip_base_filter(session_with_data: Session) -> None: + from superset.connectors.sqla.models import SqlaTable + from superset.datasets.dao import DatasetDAO + + result = DatasetDAO.find_by_id( + 1, + session=session_with_data, + skip_base_filter=True, + ) + + assert result + assert 1 == result.id + assert "my_sqla_table" == result.table_name + assert isinstance(result, SqlaTable) + + +def test_datasource_find_by_id_skip_base_filter_not_found( + session_with_data: Session, +) -> None: + from superset.datasets.dao import DatasetDAO + + result = DatasetDAO.find_by_id( + 125326326, + session=session_with_data, + skip_base_filter=True, + ) + assert result is None + + +def test_datasource_find_by_ids_skip_base_filter(session_with_data: Session) -> None: + from superset.connectors.sqla.models import SqlaTable + from superset.datasets.dao import DatasetDAO + + result = DatasetDAO.find_by_ids( + [1, 125326326], + session=session_with_data, + skip_base_filter=True, + ) + + assert result + assert [1] == list(map(lambda x: x.id, result)) + assert ["my_sqla_table"] == list(map(lambda x: x.table_name, result)) + assert isinstance(result[0], SqlaTable) + + +def test_datasource_find_by_ids_skip_base_filter_not_found( + session_with_data: Session, +) -> None: + from superset.datasets.dao import DatasetDAO + + result = DatasetDAO.find_by_ids( + [125326326, 125326326125326326], + session=session_with_data, + skip_base_filter=True, + ) + + assert len(result) == 0 diff --git a/tests/unit_tests/datasets/test_models.py b/tests/unit_tests/datasets/test_models.py deleted file mode 100644 index cacaef5ef53f9..0000000000000 --- a/tests/unit_tests/datasets/test_models.py +++ /dev/null @@ -1,1154 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -import json -from typing import Any, Callable, Dict, List, TYPE_CHECKING - -from pytest_mock import MockFixture -from sqlalchemy.orm.session import Session - -from tests.unit_tests.utils.db import get_test_user - -if TYPE_CHECKING: - from superset.connectors.sqla.models import SqlMetric, TableColumn - - -def test_dataset_model(app_context: None, session: Session) -> None: - """ - Test basic attributes of a ``Dataset``. - """ - from superset.columns.models import Column - from superset.datasets.models import Dataset - from superset.models.core import Database - from superset.tables.models import Table - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - - table = Table( - name="my_table", - schema="my_schema", - catalog="my_catalog", - database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), - columns=[ - Column(name="longitude", expression="longitude"), - Column(name="latitude", expression="latitude"), - ], - ) - session.add(table) - session.flush() - - dataset = Dataset( - database=table.database, - name="positions", - expression=""" -SELECT array_agg(array[longitude,latitude]) AS position -FROM my_catalog.my_schema.my_table -""", - tables=[table], - columns=[ - Column( - name="position", - expression="array_agg(array[longitude,latitude])", - ), - ], - ) - session.add(dataset) - session.flush() - - assert dataset.id == 1 - assert dataset.uuid is not None - - assert dataset.name == "positions" - assert ( - dataset.expression - == """ -SELECT array_agg(array[longitude,latitude]) AS position -FROM my_catalog.my_schema.my_table -""" - ) - - assert [table.name for table in dataset.tables] == ["my_table"] - assert [column.name for column in dataset.columns] == ["position"] - - -def test_cascade_delete_table(app_context: None, session: Session) -> None: - """ - Test that deleting ``Table`` also deletes its columns. - """ - from superset.columns.models import Column - from superset.models.core import Database - from superset.tables.models import Table - - engine = session.get_bind() - Table.metadata.create_all(engine) # pylint: disable=no-member - - table = Table( - name="my_table", - schema="my_schema", - catalog="my_catalog", - database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), - columns=[ - Column(name="longitude", expression="longitude"), - Column(name="latitude", expression="latitude"), - ], - ) - session.add(table) - session.flush() - - columns = session.query(Column).all() - assert len(columns) == 2 - - session.delete(table) - session.flush() - - # test that columns were deleted - columns = session.query(Column).all() - assert len(columns) == 0 - - -def test_cascade_delete_dataset(app_context: None, session: Session) -> None: - """ - Test that deleting ``Dataset`` also deletes its columns. - """ - from superset.columns.models import Column - from superset.datasets.models import Dataset - from superset.models.core import Database - from superset.tables.models import Table - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - - table = Table( - name="my_table", - schema="my_schema", - catalog="my_catalog", - database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), - columns=[ - Column(name="longitude", expression="longitude"), - Column(name="latitude", expression="latitude"), - ], - ) - session.add(table) - session.flush() - - dataset = Dataset( - name="positions", - expression=""" -SELECT array_agg(array[longitude,latitude]) AS position -FROM my_catalog.my_schema.my_table -""", - database=table.database, - tables=[table], - columns=[ - Column( - name="position", - expression="array_agg(array[longitude,latitude])", - ), - ], - ) - session.add(dataset) - session.flush() - - columns = session.query(Column).all() - assert len(columns) == 3 - - session.delete(dataset) - session.flush() - - # test that dataset columns were deleted (but not table columns) - columns = session.query(Column).all() - assert len(columns) == 2 - - -def test_dataset_attributes(app_context: None, session: Session) -> None: - """ - Test that checks attributes in the dataset. - - If this check fails it means new attributes were added to ``SqlaTable``, and - ``SqlaTable.after_insert`` should be updated to handle them! - """ - from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn - from superset.models.core import Database - - engine = session.get_bind() - SqlaTable.metadata.create_all(engine) # pylint: disable=no-member - - columns = [ - TableColumn(column_name="ds", is_dttm=1, type="TIMESTAMP"), - TableColumn(column_name="num_boys", type="INTEGER"), - TableColumn(column_name="revenue", type="INTEGER"), - TableColumn(column_name="expenses", type="INTEGER"), - TableColumn( - column_name="profit", type="INTEGER", expression="revenue-expenses" - ), - ] - metrics = [ - SqlMetric(metric_name="cnt", expression="COUNT(*)"), - ] - - sqla_table = SqlaTable( - table_name="old_dataset", - columns=columns, - metrics=metrics, - main_dttm_col="ds", - default_endpoint="https://www.youtube.com/watch?v=dQw4w9WgXcQ", # not used - database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), - offset=-8, - description="This is the description", - is_featured=1, - cache_timeout=3600, - schema="my_schema", - sql=None, - params=json.dumps( - { - "remote_id": 64, - "database_name": "examples", - "import_time": 1606677834, - } - ), - perm=None, - filter_select_enabled=1, - fetch_values_predicate="foo IN (1, 2)", - is_sqllab_view=0, # no longer used? - template_params=json.dumps({"answer": "42"}), - schema_perm=None, - extra=json.dumps({"warning_markdown": "*WARNING*"}), - ) - - session.add(sqla_table) - session.flush() - - dataset = session.query(SqlaTable).one() - # If this test fails because attributes changed, make sure to update - # ``SqlaTable.after_insert`` accordingly. - assert sorted(dataset.__dict__.keys()) == [ - "_sa_instance_state", - "cache_timeout", - "changed_by_fk", - "changed_on", - "columns", - "created_by_fk", - "created_on", - "database", - "database_id", - "default_endpoint", - "description", - "external_url", - "extra", - "fetch_values_predicate", - "filter_select_enabled", - "id", - "is_featured", - "is_managed_externally", - "is_sqllab_view", - "main_dttm_col", - "metrics", - "offset", - "owners", - "params", - "perm", - "schema", - "schema_perm", - "sql", - "table_name", - "template_params", - "uuid", - ] - - -def test_create_physical_sqlatable( - app_context: None, - session: Session, - sample_columns: Dict["TableColumn", Dict[str, Any]], - sample_metrics: Dict["SqlMetric", Dict[str, Any]], - columns_default: Dict[str, Any], -) -> None: - """ - Test shadow write when creating a new ``SqlaTable``. - - When a new physical ``SqlaTable`` is created, new models should also be created for - ``Dataset``, ``Table``, and ``Column``. - """ - from superset.columns.models import Column - from superset.columns.schemas import ColumnSchema - from superset.connectors.sqla.models import SqlaTable - from superset.datasets.models import Dataset - from superset.datasets.schemas import DatasetSchema - from superset.models.core import Database - from superset.tables.models import Table - from superset.tables.schemas import TableSchema - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - user1 = get_test_user(1, "abc") - columns = list(sample_columns.keys()) - metrics = list(sample_metrics.keys()) - expected_table_columns = list(sample_columns.values()) - expected_metric_columns = list(sample_metrics.values()) - - sqla_table = SqlaTable( - table_name="old_dataset", - columns=columns, - metrics=metrics, - main_dttm_col="ds", - default_endpoint="https://www.youtube.com/watch?v=dQw4w9WgXcQ", # not used - database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), - offset=-8, - description="This is the description", - is_featured=1, - cache_timeout=3600, - schema="my_schema", - sql=None, - params=json.dumps( - { - "remote_id": 64, - "database_name": "examples", - "import_time": 1606677834, - } - ), - created_by=user1, - changed_by=user1, - owners=[user1], - perm=None, - filter_select_enabled=1, - fetch_values_predicate="foo IN (1, 2)", - is_sqllab_view=0, # no longer used? - template_params=json.dumps({"answer": "42"}), - schema_perm=None, - extra=json.dumps({"warning_markdown": "*WARNING*"}), - ) - session.add(sqla_table) - session.flush() - - # ignore these keys when comparing results - ignored_keys = {"created_on", "changed_on"} - - # check that columns were created - column_schema = ColumnSchema() - actual_columns = [ - {k: v for k, v in column_schema.dump(column).items() if k not in ignored_keys} - for column in session.query(Column).all() - ] - num_physical_columns = len( - [col for col in expected_table_columns if col.get("is_physical") == True] - ) - num_dataset_table_columns = len(columns) - num_dataset_metric_columns = len(metrics) - assert ( - len(actual_columns) - == num_physical_columns + num_dataset_table_columns + num_dataset_metric_columns - ) - - # table columns are created before dataset columns are created - offset = 0 - for i in range(num_physical_columns): - assert actual_columns[i + offset] == { - **columns_default, - **expected_table_columns[i], - "id": i + offset + 1, - # physical columns for table have its own uuid - "uuid": actual_columns[i + offset]["uuid"], - "is_physical": True, - # table columns do not have creators - "created_by": None, - "tables": [1], - } - - offset += num_physical_columns - for i, column in enumerate(sqla_table.columns): - assert actual_columns[i + offset] == { - **columns_default, - **expected_table_columns[i], - "id": i + offset + 1, - # columns for dataset reuses the same uuid of TableColumn - "uuid": str(column.uuid), - "datasets": [1], - } - - offset += num_dataset_table_columns - for i, metric in enumerate(sqla_table.metrics): - assert actual_columns[i + offset] == { - **columns_default, - **expected_metric_columns[i], - "id": i + offset + 1, - "uuid": str(metric.uuid), - "datasets": [1], - } - - # check that table was created - table_schema = TableSchema() - tables = [ - { - k: v - for k, v in table_schema.dump(table).items() - if k not in (ignored_keys | {"uuid"}) - } - for table in session.query(Table).all() - ] - assert len(tables) == 1 - assert tables[0] == { - "id": 1, - "database": 1, - "created_by": 1, - "changed_by": 1, - "datasets": [1], - "columns": [1, 2, 3], - "extra_json": "{}", - "catalog": None, - "schema": "my_schema", - "name": "old_dataset", - "is_managed_externally": False, - "external_url": None, - } - - # check that dataset was created - dataset_schema = DatasetSchema() - datasets = [ - {k: v for k, v in dataset_schema.dump(dataset).items() if k not in ignored_keys} - for dataset in session.query(Dataset).all() - ] - assert len(datasets) == 1 - assert datasets[0] == { - "id": 1, - "uuid": str(sqla_table.uuid), - "created_by": 1, - "changed_by": 1, - "owners": [1], - "name": "old_dataset", - "columns": [4, 5, 6, 7, 8, 9], - "is_physical": True, - "database": 1, - "tables": [1], - "extra_json": "{}", - "expression": "old_dataset", - "is_managed_externally": False, - "external_url": None, - } - - -def test_create_virtual_sqlatable( - app_context: None, - mocker: MockFixture, - session: Session, - sample_columns: Dict["TableColumn", Dict[str, Any]], - sample_metrics: Dict["SqlMetric", Dict[str, Any]], - columns_default: Dict[str, Any], -) -> None: - """ - Test shadow write when creating a new ``SqlaTable``. - - When a new virtual ``SqlaTable`` is created, new models should also be created for - ``Dataset`` and ``Column``. - """ - # patch session - mocker.patch( - "superset.security.SupersetSecurityManager.get_session", return_value=session - ) - - from superset.columns.models import Column - from superset.columns.schemas import ColumnSchema - from superset.connectors.sqla.models import SqlaTable - from superset.datasets.models import Dataset - from superset.datasets.schemas import DatasetSchema - from superset.models.core import Database - from superset.tables.models import Table - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - user1 = get_test_user(1, "abc") - physical_table_columns: List[Dict[str, Any]] = [ - dict( - name="ds", - is_temporal=True, - type="TIMESTAMP", - advanced_data_type=None, - expression="ds", - is_physical=True, - ), - dict( - name="num_boys", - type="INTEGER", - advanced_data_type=None, - expression="num_boys", - is_physical=True, - ), - dict( - name="revenue", - type="INTEGER", - advanced_data_type=None, - expression="revenue", - is_physical=True, - ), - dict( - name="expenses", - type="INTEGER", - advanced_data_type=None, - expression="expenses", - is_physical=True, - ), - ] - # create a physical ``Table`` that the virtual dataset points to - database = Database(database_name="my_database", sqlalchemy_uri="sqlite://") - table = Table( - name="some_table", - schema="my_schema", - catalog=None, - database=database, - columns=[ - Column(**props, created_by=user1, changed_by=user1) - for props in physical_table_columns - ], - ) - session.add(table) - session.commit() - - assert session.query(Table).count() == 1 - assert session.query(Dataset).count() == 0 - - # create virtual dataset - columns = list(sample_columns.keys()) - metrics = list(sample_metrics.keys()) - expected_table_columns = list(sample_columns.values()) - expected_metric_columns = list(sample_metrics.values()) - - sqla_table = SqlaTable( - created_by=user1, - changed_by=user1, - owners=[user1], - table_name="old_dataset", - columns=columns, - metrics=metrics, - main_dttm_col="ds", - default_endpoint="https://www.youtube.com/watch?v=dQw4w9WgXcQ", # not used - database=database, - offset=-8, - description="This is the description", - is_featured=1, - cache_timeout=3600, - schema="my_schema", - sql=""" -SELECT - ds, - num_boys, - revenue, - expenses, - revenue - expenses AS profit -FROM - some_table""", - params=json.dumps( - { - "remote_id": 64, - "database_name": "examples", - "import_time": 1606677834, - } - ), - perm=None, - filter_select_enabled=1, - fetch_values_predicate="foo IN (1, 2)", - is_sqllab_view=0, # no longer used? - template_params=json.dumps({"answer": "42"}), - schema_perm=None, - extra=json.dumps({"warning_markdown": "*WARNING*"}), - ) - session.add(sqla_table) - session.flush() - - # should not add a new table - assert session.query(Table).count() == 1 - assert session.query(Dataset).count() == 1 - - # ignore these keys when comparing results - ignored_keys = {"created_on", "changed_on"} - column_schema = ColumnSchema() - actual_columns = [ - {k: v for k, v in column_schema.dump(column).items() if k not in ignored_keys} - for column in session.query(Column).all() - ] - num_physical_columns = len(physical_table_columns) - num_dataset_table_columns = len(columns) - num_dataset_metric_columns = len(metrics) - assert ( - len(actual_columns) - == num_physical_columns + num_dataset_table_columns + num_dataset_metric_columns - ) - - for i, column in enumerate(table.columns): - assert actual_columns[i] == { - **columns_default, - **physical_table_columns[i], - "id": i + 1, - "uuid": str(column.uuid), - "tables": [1], - } - - offset = num_physical_columns - for i, column in enumerate(sqla_table.columns): - assert actual_columns[i + offset] == { - **columns_default, - **expected_table_columns[i], - "id": i + offset + 1, - "uuid": str(column.uuid), - "is_physical": False, - "datasets": [1], - } - - offset = num_physical_columns + num_dataset_table_columns - for i, metric in enumerate(sqla_table.metrics): - assert actual_columns[i + offset] == { - **columns_default, - **expected_metric_columns[i], - "id": i + offset + 1, - "uuid": str(metric.uuid), - "datasets": [1], - } - - # check that dataset was created, and has a reference to the table - dataset_schema = DatasetSchema() - datasets = [ - {k: v for k, v in dataset_schema.dump(dataset).items() if k not in ignored_keys} - for dataset in session.query(Dataset).all() - ] - assert len(datasets) == 1 - assert datasets[0] == { - "id": 1, - "database": 1, - "uuid": str(sqla_table.uuid), - "name": "old_dataset", - "changed_by": 1, - "created_by": 1, - "owners": [1], - "columns": [5, 6, 7, 8, 9, 10], - "is_physical": False, - "tables": [1], - "extra_json": "{}", - "external_url": None, - "is_managed_externally": False, - "expression": """ -SELECT - ds, - num_boys, - revenue, - expenses, - revenue - expenses AS profit -FROM - some_table""", - } - - -def test_delete_sqlatable(app_context: None, session: Session) -> None: - """ - Test that deleting a ``SqlaTable`` also deletes the corresponding ``Dataset``. - """ - from superset.columns.models import Column - from superset.connectors.sqla.models import SqlaTable, TableColumn - from superset.datasets.models import Dataset - from superset.models.core import Database - from superset.tables.models import Table - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - - columns = [ - TableColumn(column_name="ds", is_dttm=1, type="TIMESTAMP"), - ] - sqla_table = SqlaTable( - table_name="old_dataset", - columns=columns, - metrics=[], - database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), - ) - session.add(sqla_table) - session.flush() - - assert session.query(Dataset).count() == 1 - assert session.query(Table).count() == 1 - assert session.query(Column).count() == 2 - - session.delete(sqla_table) - session.flush() - - # test that dataset and dataset columns are also deleted - # but the physical table and table columns are kept - assert session.query(Dataset).count() == 0 - assert session.query(Table).count() == 1 - assert session.query(Column).count() == 1 - - -def test_update_physical_sqlatable_columns( - mocker: MockFixture, app_context: None, session: Session -) -> None: - """ - Test that updating a ``SqlaTable`` also updates the corresponding ``Dataset``. - """ - # patch session - mocker.patch( - "superset.security.SupersetSecurityManager.get_session", return_value=session - ) - - from superset.columns.models import Column - from superset.connectors.sqla.models import SqlaTable, TableColumn - from superset.datasets.models import Dataset - from superset.models.core import Database - from superset.tables.models import Table - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - - columns = [ - TableColumn(column_name="ds", is_dttm=1, type="TIMESTAMP"), - ] - sqla_table = SqlaTable( - table_name="old_dataset", - columns=columns, - metrics=[], - database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), - ) - - session.add(sqla_table) - session.flush() - - assert session.query(Table).count() == 1 - assert session.query(Dataset).count() == 1 - assert session.query(Column).count() == 2 # 1 for table, 1 for dataset - - dataset = session.query(Dataset).one() - assert len(dataset.columns) == 1 - - # add a column to the original ``SqlaTable`` instance - sqla_table.columns.append(TableColumn(column_name="num_boys", type="INTEGER")) - session.flush() - - assert session.query(Column).count() == 3 - dataset = session.query(Dataset).one() - assert len(dataset.columns) == 2 - - # check that both lists have the same uuids - assert [col.uuid for col in sqla_table.columns].sort() == [ - col.uuid for col in dataset.columns - ].sort() - - # delete the column in the original instance - sqla_table.columns = sqla_table.columns[1:] - session.flush() - - # check that the column was added to the dataset and the added columns have - # the correct uuid. - assert session.query(TableColumn).count() == 1 - # the extra Dataset.column is deleted, but Table.column is kept - assert session.query(Column).count() == 2 - - # check that the column was also removed from the dataset - dataset = session.query(Dataset).one() - assert len(dataset.columns) == 1 - - # modify the attribute in a column - sqla_table.columns[0].is_dttm = True - session.flush() - - # check that the dataset column was modified - dataset = session.query(Dataset).one() - assert dataset.columns[0].is_temporal is True - - -def test_update_physical_sqlatable_schema( - mocker: MockFixture, app_context: None, session: Session -) -> None: - """ - Test that updating a ``SqlaTable`` schema also updates the corresponding ``Dataset``. - """ - # patch session - mocker.patch( - "superset.security.SupersetSecurityManager.get_session", return_value=session - ) - mocker.patch("superset.datasets.dao.db.session", session) - - from superset.columns.models import Column - from superset.connectors.sqla.models import SqlaTable, TableColumn - from superset.datasets.models import Dataset - from superset.models.core import Database - from superset.tables.models import Table - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - - columns = [ - TableColumn(column_name="ds", is_dttm=1, type="TIMESTAMP"), - ] - sqla_table = SqlaTable( - table_name="old_dataset", - schema="old_schema", - columns=columns, - metrics=[], - database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), - ) - session.add(sqla_table) - session.flush() - - dataset = session.query(Dataset).one() - assert dataset.tables[0].schema == "old_schema" - assert dataset.tables[0].id == 1 - - sqla_table.schema = "new_schema" - session.flush() - - new_dataset = session.query(Dataset).one() - assert new_dataset.tables[0].schema == "new_schema" - assert new_dataset.tables[0].id == 2 - - -def test_update_physical_sqlatable_metrics( - mocker: MockFixture, - app_context: None, - session: Session, - get_session: Callable[[], Session], -) -> None: - """ - Test that updating a ``SqlaTable`` also updates the corresponding ``Dataset``. - - For this test we check that updating the SQL expression in a metric belonging to a - ``SqlaTable`` is reflected in the ``Dataset`` metric. - """ - # patch session - mocker.patch( - "superset.security.SupersetSecurityManager.get_session", return_value=session - ) - - from superset.columns.models import Column - from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn - from superset.datasets.models import Dataset - from superset.models.core import Database - from superset.tables.models import Table - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - - columns = [ - TableColumn(column_name="ds", is_dttm=1, type="TIMESTAMP"), - ] - metrics = [ - SqlMetric(metric_name="cnt", expression="COUNT(*)"), - ] - sqla_table = SqlaTable( - table_name="old_dataset", - columns=columns, - metrics=metrics, - database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), - ) - session.add(sqla_table) - session.flush() - - # check that the metric was created - # 1 physical column for table + (1 column + 1 metric for datasets) - assert session.query(Column).count() == 3 - - column = session.query(Column).filter_by(is_physical=False).one() - assert column.expression == "COUNT(*)" - - # change the metric definition - sqla_table.metrics[0].expression = "MAX(ds)" - session.flush() - - assert column.expression == "MAX(ds)" - - # in a new session, update new columns and metrics at the same time - # reload the sqla_table so we can test the case that accessing an not already - # loaded attribute (`sqla_table.metrics`) while there are updates on the instance - # may trigger `after_update` before the attribute is loaded - session = get_session() - sqla_table = session.query(SqlaTable).filter(SqlaTable.id == sqla_table.id).one() - sqla_table.columns.append( - TableColumn( - column_name="another_column", - is_dttm=0, - type="TIMESTAMP", - expression="concat('a', 'b')", - ) - ) - # Here `SqlaTable.after_update` is triggered - # before `sqla_table.metrics` is loaded - sqla_table.metrics.append( - SqlMetric(metric_name="another_metric", expression="COUNT(*)") - ) - # `SqlaTable.after_update` will trigger again at flushing - session.flush() - assert session.query(Column).count() == 5 - - -def test_update_physical_sqlatable_database( - mocker: MockFixture, - app_context: None, - session: Session, - get_session: Callable[[], Session], -) -> None: - """ - Test updating the table on a physical dataset. - - When updating the table on a physical dataset by pointing it somewhere else (change - in database ID, schema, or table name) we should point the ``Dataset`` to an - existing ``Table`` if possible, and create a new one otherwise. - """ - # patch session - mocker.patch( - "superset.security.SupersetSecurityManager.get_session", return_value=session - ) - mocker.patch("superset.datasets.dao.db.session", session) - - from superset.columns.models import Column - from superset.connectors.sqla.models import SqlaTable, TableColumn - from superset.datasets.models import Dataset, dataset_column_association_table - from superset.models.core import Database - from superset.tables.models import Table, table_column_association_table - from superset.tables.schemas import TableSchema - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - - columns = [ - TableColumn(column_name="a", type="INTEGER"), - ] - - original_database = Database( - database_name="my_database", sqlalchemy_uri="sqlite://" - ) - sqla_table = SqlaTable( - table_name="original_table", - columns=columns, - metrics=[], - database=original_database, - ) - session.add(sqla_table) - session.flush() - - assert session.query(Table).count() == 1 - assert session.query(Dataset).count() == 1 - assert session.query(Column).count() == 2 # 1 for table, 1 for dataset - - # check that the table was created, and that the created dataset points to it - table = session.query(Table).one() - assert table.id == 1 - assert table.name == "original_table" - assert table.schema is None - assert table.database_id == 1 - - dataset = session.query(Dataset).one() - assert dataset.tables == [table] - - # point ``SqlaTable`` to a different database - new_database = Database( - database_name="my_other_database", sqlalchemy_uri="sqlite://" - ) - session.add(new_database) - session.flush() - sqla_table.database = new_database - sqla_table.table_name = "new_table" - session.flush() - - assert session.query(Dataset).count() == 1 - assert session.query(Table).count() == 2 - # <Column:id=1> is kept for the old table - # <Column:id=2> is kept for the updated dataset - # <Column:id=3> is created for the new table - assert session.query(Column).count() == 3 - - # ignore these keys when comparing results - ignored_keys = {"created_on", "changed_on", "uuid"} - - # check that the old table still exists, and that the dataset points to the newly - # created table, column and dataset - table_schema = TableSchema() - tables = [ - {k: v for k, v in table_schema.dump(table).items() if k not in ignored_keys} - for table in session.query(Table).all() - ] - assert tables[0] == { - "id": 1, - "database": 1, - "columns": [1], - "datasets": [], - "created_by": None, - "changed_by": None, - "extra_json": "{}", - "catalog": None, - "schema": None, - "name": "original_table", - "external_url": None, - "is_managed_externally": False, - } - assert tables[1] == { - "id": 2, - "database": 2, - "datasets": [1], - "columns": [3], - "created_by": None, - "changed_by": None, - "catalog": None, - "schema": None, - "name": "new_table", - "is_managed_externally": False, - "extra_json": "{}", - "external_url": None, - } - - # check that dataset now points to the new table - assert dataset.tables[0].database_id == 2 - # and a new column is created - assert len(dataset.columns) == 1 - assert dataset.columns[0].id == 2 - - # point ``SqlaTable`` back - sqla_table.database = original_database - sqla_table.table_name = "original_table" - session.flush() - - # should not create more table and datasets - assert session.query(Dataset).count() == 1 - assert session.query(Table).count() == 2 - # <Column:id=1> is deleted for the old table - # <Column:id=2> is kept for the updated dataset - # <Column:id=3> is kept for the new table - assert session.query(Column.id).order_by(Column.id).all() == [ - (1,), - (2,), - (3,), - ] - assert session.query(dataset_column_association_table).all() == [(1, 2)] - assert session.query(table_column_association_table).all() == [(1, 1), (2, 3)] - assert session.query(Dataset).filter_by(id=1).one().columns[0].id == 2 - assert session.query(Table).filter_by(id=2).one().columns[0].id == 3 - assert session.query(Table).filter_by(id=1).one().columns[0].id == 1 - - # the dataset points back to the original table - assert dataset.tables[0].database_id == 1 - assert dataset.tables[0].name == "original_table" - - # kept the original column - assert dataset.columns[0].id == 2 - session.commit() - session.close() - - # querying in a new session should still return the same result - session = get_session() - assert session.query(table_column_association_table).all() == [(1, 1), (2, 3)] - - -def test_update_virtual_sqlatable_references( - mocker: MockFixture, app_context: None, session: Session -) -> None: - """ - Test that changing the SQL of a virtual ``SqlaTable`` updates ``Dataset``. - - When the SQL is modified the list of referenced tables should be updated in the new - ``Dataset`` model. - """ - # patch session - mocker.patch( - "superset.security.SupersetSecurityManager.get_session", return_value=session - ) - - from superset.columns.models import Column - from superset.connectors.sqla.models import SqlaTable, TableColumn - from superset.datasets.models import Dataset - from superset.models.core import Database - from superset.tables.models import Table - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - - database = Database(database_name="my_database", sqlalchemy_uri="sqlite://") - table1 = Table( - name="table_a", - schema="my_schema", - catalog=None, - database=database, - columns=[Column(name="a", type="INTEGER")], - ) - table2 = Table( - name="table_b", - schema="my_schema", - catalog=None, - database=database, - columns=[Column(name="b", type="INTEGER")], - ) - session.add(table1) - session.add(table2) - session.commit() - - # create virtual dataset - columns = [TableColumn(column_name="a", type="INTEGER")] - - sqla_table = SqlaTable( - table_name="old_dataset", - columns=columns, - database=database, - schema="my_schema", - sql="SELECT a FROM table_a", - ) - session.add(sqla_table) - session.flush() - - # check that new dataset has table1 - dataset: Dataset = session.query(Dataset).one() - assert dataset.tables == [table1] - - # change SQL - sqla_table.sql = "SELECT a, b FROM table_a JOIN table_b" - session.flush() - - # check that new dataset has both tables - new_dataset: Dataset = session.query(Dataset).one() - assert new_dataset.tables == [table1, table2] - assert new_dataset.expression == "SELECT a, b FROM table_a JOIN table_b" - - # automatically add new referenced table - sqla_table.sql = "SELECT a, b, c FROM table_a JOIN table_b JOIN table_c" - session.flush() - - new_dataset = session.query(Dataset).one() - assert len(new_dataset.tables) == 3 - assert new_dataset.tables[2].name == "table_c" - - -def test_quote_expressions(app_context: None, session: Session) -> None: - """ - Test that expressions are quoted appropriately in columns and datasets. - """ - from superset.connectors.sqla.models import SqlaTable, TableColumn - from superset.datasets.models import Dataset - from superset.models.core import Database - - engine = session.get_bind() - Dataset.metadata.create_all(engine) # pylint: disable=no-member - - columns = [ - TableColumn(column_name="has space", type="INTEGER"), - TableColumn(column_name="no_need", type="INTEGER"), - ] - - sqla_table = SqlaTable( - table_name="old dataset", - columns=columns, - metrics=[], - database=Database(database_name="my_database", sqlalchemy_uri="sqlite://"), - ) - session.add(sqla_table) - session.flush() - - dataset = session.query(Dataset).one() - assert dataset.expression == '"old dataset"' - assert dataset.columns[0].expression == '"has space"' - assert dataset.columns[1].expression == "no_need" diff --git a/tests/unit_tests/dao/datasource_test.py b/tests/unit_tests/datasource/dao_tests.py similarity index 68% rename from tests/unit_tests/dao/datasource_test.py rename to tests/unit_tests/datasource/dao_tests.py index a15684d71e699..16334066d7ba1 100644 --- a/tests/unit_tests/dao/datasource_test.py +++ b/tests/unit_tests/datasource/dao_tests.py @@ -99,11 +99,9 @@ def session_with_data(session: Session) -> Iterator[Session]: yield session -def test_get_datasource_sqlatable( - app_context: None, session_with_data: Session -) -> None: +def test_get_datasource_sqlatable(session_with_data: Session) -> None: from superset.connectors.sqla.models import SqlaTable - from superset.dao.datasource.dao import DatasourceDAO + from superset.datasource.dao import DatasourceDAO result = DatasourceDAO.get_datasource( datasource_type=DatasourceType.TABLE, @@ -116,8 +114,8 @@ def test_get_datasource_sqlatable( assert isinstance(result, SqlaTable) -def test_get_datasource_query(app_context: None, session_with_data: Session) -> None: - from superset.dao.datasource.dao import DatasourceDAO +def test_get_datasource_query(session_with_data: Session) -> None: + from superset.datasource.dao import DatasourceDAO from superset.models.sql_lab import Query result = DatasourceDAO.get_datasource( @@ -128,10 +126,8 @@ def test_get_datasource_query(app_context: None, session_with_data: Session) -> assert isinstance(result, Query) -def test_get_datasource_saved_query( - app_context: None, session_with_data: Session -) -> None: - from superset.dao.datasource.dao import DatasourceDAO +def test_get_datasource_saved_query(session_with_data: Session) -> None: + from superset.datasource.dao import DatasourceDAO from superset.models.sql_lab import SavedQuery result = DatasourceDAO.get_datasource( @@ -144,44 +140,73 @@ def test_get_datasource_saved_query( assert isinstance(result, SavedQuery) -def test_get_datasource_sl_table(app_context: None, session_with_data: Session) -> None: - from superset.dao.datasource.dao import DatasourceDAO +def test_get_datasource_sl_table(session_with_data: Session) -> None: + from superset.datasource.dao import DatasourceDAO from superset.tables.models import Table - # todo(hugh): This will break once we remove the dual write - # update the datsource_id=1 and this will pass again result = DatasourceDAO.get_datasource( datasource_type=DatasourceType.SLTABLE, - datasource_id=2, + datasource_id=1, session=session_with_data, ) - assert result.id == 2 + assert result.id == 1 assert isinstance(result, Table) -def test_get_datasource_sl_dataset( - app_context: None, session_with_data: Session -) -> None: - from superset.dao.datasource.dao import DatasourceDAO +def test_get_datasource_sl_dataset(session_with_data: Session) -> None: from superset.datasets.models import Dataset + from superset.datasource.dao import DatasourceDAO - # todo(hugh): This will break once we remove the dual write - # update the datsource_id=1 and this will pass again result = DatasourceDAO.get_datasource( datasource_type=DatasourceType.DATASET, - datasource_id=2, + datasource_id=1, session=session_with_data, ) - assert result.id == 2 + assert result.id == 1 assert isinstance(result, Dataset) -def test_get_all_sqlatables_datasources( - app_context: None, session_with_data: Session -) -> None: - from superset.dao.datasource.dao import DatasourceDAO +def test_get_datasource_w_str_param(session_with_data: Session) -> None: + from superset.connectors.sqla.models import SqlaTable + from superset.datasets.models import Dataset + from superset.datasource.dao import DatasourceDAO + from superset.tables.models import Table + + assert isinstance( + DatasourceDAO.get_datasource( + datasource_type="table", + datasource_id=1, + session=session_with_data, + ), + SqlaTable, + ) - result = DatasourceDAO.get_all_sqlatables_datasources(session=session_with_data) + assert isinstance( + DatasourceDAO.get_datasource( + datasource_type="sl_table", + datasource_id=1, + session=session_with_data, + ), + Table, + ) + + +def test_get_all_datasources(session_with_data: Session) -> None: + from superset.connectors.sqla.models import SqlaTable + + result = SqlaTable.get_all_datasources(session=session_with_data) assert len(result) == 1 + + +def test_not_found_datasource(session_with_data: Session) -> None: + from superset.dao.exceptions import DatasourceNotFound + from superset.datasource.dao import DatasourceDAO + + with pytest.raises(DatasourceNotFound): + DatasourceDAO.get_datasource( + datasource_type="table", + datasource_id=500000, + session=session_with_data, + ) diff --git a/tests/unit_tests/db_engine_specs/test_athena.py b/tests/unit_tests/db_engine_specs/test_athena.py index d7c1a3f606fca..51ec6656aa7f0 100644 --- a/tests/unit_tests/db_engine_specs/test_athena.py +++ b/tests/unit_tests/db_engine_specs/test_athena.py @@ -17,10 +17,12 @@ # pylint: disable=unused-argument, import-outside-toplevel, protected-access import re from datetime import datetime +from typing import Optional -from flask.ctx import AppContext +import pytest from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm from tests.unit_tests.fixtures.common import dttm SYNTAX_ERROR_REGEX = re.compile( @@ -28,22 +30,23 @@ ) -def test_convert_dttm(app_context: AppContext, dttm: datetime) -> None: - """ - Test that date objects are converted correctly. - """ - - from superset.db_engine_specs.athena import AthenaEngineSpec - - assert AthenaEngineSpec.convert_dttm("DATE", dttm) == "DATE '2019-01-02'" +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "DATE '2019-01-02'"), + ("TimeStamp", "TIMESTAMP '2019-01-02 03:04:05.678'"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.athena import AthenaEngineSpec as spec - assert ( - AthenaEngineSpec.convert_dttm("TIMESTAMP", dttm) - == "TIMESTAMP '2019-01-02 03:04:05.678'" - ) + assert_convert_dttm(spec, target_type, expected_result, dttm) -def test_extract_errors(app_context: AppContext) -> None: +def test_extract_errors() -> None: """ Test that custom error messages are extracted correctly. """ @@ -70,7 +73,7 @@ def test_extract_errors(app_context: AppContext) -> None: ] -def test_get_text_clause_with_colon(app_context: AppContext) -> None: +def test_get_text_clause_with_colon() -> None: """ Make sure text clauses don't escape the colon character """ diff --git a/tests/unit_tests/db_engine_specs/test_base.py b/tests/unit_tests/db_engine_specs/test_base.py index b112e2cec8ef4..868a6bbdc3fe6 100644 --- a/tests/unit_tests/db_engine_specs/test_base.py +++ b/tests/unit_tests/db_engine_specs/test_base.py @@ -17,13 +17,16 @@ # pylint: disable=unused-argument, import-outside-toplevel, protected-access from textwrap import dedent +from typing import Any, Dict, Optional, Type import pytest -from flask.ctx import AppContext -from sqlalchemy.types import TypeEngine +from sqlalchemy import types +from superset.utils.core import GenericDataType +from tests.unit_tests.db_engine_specs.utils import assert_column_spec -def test_get_text_clause_with_colon(app_context: AppContext) -> None: + +def test_get_text_clause_with_colon() -> None: """ Make sure text clauses are correctly escaped """ @@ -36,7 +39,7 @@ def test_get_text_clause_with_colon(app_context: AppContext) -> None: assert text_clause.text == "SELECT foo FROM tbl WHERE foo = '123\\:456')" -def test_parse_sql_single_statement(app_context: AppContext) -> None: +def test_parse_sql_single_statement() -> None: """ `parse_sql` should properly strip leading and trailing spaces and semicolons """ @@ -47,7 +50,7 @@ def test_parse_sql_single_statement(app_context: AppContext) -> None: assert queries == ["SELECT foo FROM tbl"] -def test_parse_sql_multi_statement(app_context: AppContext) -> None: +def test_parse_sql_multi_statement() -> None: """ For string with multiple SQL-statements `parse_sql` method should return list where each element represents the single SQL-statement @@ -95,10 +98,43 @@ def test_parse_sql_multi_statement(app_context: AppContext) -> None: ), ], ) -def test_cte_query_parsing( - app_context: AppContext, original: TypeEngine, expected: str -) -> None: +def test_cte_query_parsing(original: types.TypeEngine, expected: str) -> None: from superset.db_engine_specs.base import BaseEngineSpec actual = BaseEngineSpec.get_cte_query(original) assert actual == expected + + +@pytest.mark.parametrize( + "native_type,sqla_type,attrs,generic_type,is_dttm", + [ + ("SMALLINT", types.SmallInteger, None, GenericDataType.NUMERIC, False), + ("INTEGER", types.Integer, None, GenericDataType.NUMERIC, False), + ("BIGINT", types.BigInteger, None, GenericDataType.NUMERIC, False), + ("DECIMAL", types.Numeric, None, GenericDataType.NUMERIC, False), + ("NUMERIC", types.Numeric, None, GenericDataType.NUMERIC, False), + ("REAL", types.REAL, None, GenericDataType.NUMERIC, False), + ("DOUBLE PRECISION", types.Float, None, GenericDataType.NUMERIC, False), + ("MONEY", types.Numeric, None, GenericDataType.NUMERIC, False), + # String + ("CHAR", types.String, None, GenericDataType.STRING, False), + ("VARCHAR", types.String, None, GenericDataType.STRING, False), + ("TEXT", types.String, None, GenericDataType.STRING, False), + # Temporal + ("DATE", types.Date, None, GenericDataType.TEMPORAL, True), + ("TIMESTAMP", types.TIMESTAMP, None, GenericDataType.TEMPORAL, True), + ("TIME", types.Time, None, GenericDataType.TEMPORAL, True), + # Boolean + ("BOOLEAN", types.Boolean, None, GenericDataType.BOOLEAN, False), + ], +) +def test_get_column_spec( + native_type: str, + sqla_type: Type[types.TypeEngine], + attrs: Optional[Dict[str, Any]], + generic_type: GenericDataType, + is_dttm: bool, +) -> None: + from superset.db_engine_specs.databricks import DatabricksNativeEngineSpec as spec + + assert_column_spec(spec, native_type, sqla_type, attrs, generic_type, is_dttm) diff --git a/tests/unit_tests/db_engine_specs/test_bigquery.py b/tests/unit_tests/db_engine_specs/test_bigquery.py index a4a6f706ceab9..5b9c6a95636d3 100644 --- a/tests/unit_tests/db_engine_specs/test_bigquery.py +++ b/tests/unit_tests/db_engine_specs/test_bigquery.py @@ -14,16 +14,24 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# pylint: disable=unused-argument, import-outside-toplevel, protected-access -from flask.ctx import AppContext -from pybigquery.sqlalchemy_bigquery import BigQueryDialect +# pylint: disable=line-too-long, import-outside-toplevel, protected-access, invalid-name + +import json +from datetime import datetime +from typing import Optional + +import pytest from pytest_mock import MockFixture from sqlalchemy import select from sqlalchemy.sql import sqltypes +from sqlalchemy_bigquery import BigQueryDialect + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm -def test_get_fields(app_context: AppContext) -> None: +def test_get_fields() -> None: """ Test the custom ``_get_fields`` method. @@ -66,7 +74,7 @@ def test_get_fields(app_context: AppContext) -> None: ) -def test_select_star(mocker: MockFixture, app_context: AppContext) -> None: +def test_select_star(mocker: MockFixture) -> None: """ Test the ``select_star`` method. @@ -145,3 +153,162 @@ def test_select_star(mocker: MockFixture, app_context: AppContext) -> None: FROM `my_table` LIMIT :param_1""" ) + + +def test_get_parameters_from_uri_serializable() -> None: + """ + Test that the result from ``get_parameters_from_uri`` is JSON serializable. + """ + from superset.db_engine_specs.bigquery import BigQueryEngineSpec + + parameters = BigQueryEngineSpec.get_parameters_from_uri( + "bigquery://dbt-tutorial-347100/", + {"access_token": "TOP_SECRET"}, + ) + assert parameters == {"access_token": "TOP_SECRET", "query": {}} + assert json.loads(json.dumps(parameters)) == parameters + + +def test_unmask_encrypted_extra() -> None: + """ + Test that the private key can be reused from the previous ``encrypted_extra``. + """ + from superset.db_engine_specs.bigquery import BigQueryEngineSpec + + old = json.dumps( + { + "credentials_info": { + "project_id": "black-sanctum-314419", + "private_key": "SECRET", + }, + } + ) + new = json.dumps( + { + "credentials_info": { + "project_id": "yellow-unicorn-314419", + "private_key": "XXXXXXXXXX", + }, + } + ) + + assert json.loads(str(BigQueryEngineSpec.unmask_encrypted_extra(old, new))) == { + "credentials_info": { + "project_id": "yellow-unicorn-314419", + "private_key": "SECRET", + }, + } + + +def test_unmask_encrypted_extra_when_empty() -> None: + """ + Test that a None value works for ``encrypted_extra``. + """ + from superset.db_engine_specs.bigquery import BigQueryEngineSpec + + old = None + new = json.dumps( + { + "credentials_info": { + "project_id": "yellow-unicorn-314419", + "private_key": "XXXXXXXXXX", + }, + } + ) + + assert json.loads(str(BigQueryEngineSpec.unmask_encrypted_extra(old, new))) == { + "credentials_info": { + "project_id": "yellow-unicorn-314419", + "private_key": "XXXXXXXXXX", + }, + } + + +def test_unmask_encrypted_extra_when_new_is_empty() -> None: + """ + Test that a None value works for ``encrypted_extra``. + """ + from superset.db_engine_specs.bigquery import BigQueryEngineSpec + + old = json.dumps( + { + "credentials_info": { + "project_id": "black-sanctum-314419", + "private_key": "SECRET", + }, + } + ) + new = None + + assert BigQueryEngineSpec.unmask_encrypted_extra(old, new) is None + + +def test_mask_encrypted_extra_when_empty() -> None: + """ + Test that the encrypted extra will return a none value if the field is empty. + """ + from superset.db_engine_specs.bigquery import BigQueryEngineSpec + + assert BigQueryEngineSpec.mask_encrypted_extra(None) is None + + +def test_parse_error_message() -> None: + """ + Test that we parse a received message and just extract the useful information. + + Example errors: + bigquery error: 400 Syntax error: Table \"case_detail_all_suites\" must be qualified with a dataset (e.g. dataset.table). + + (job ID: ddf30b05-44e8-4fbf-aa29-40bfccaed886) + -----Query Job SQL Follows----- + | . | . | . |\n 1:select * from case_detail_all_suites\n 2:LIMIT 1001\n | . | . | . | + """ + from superset.db_engine_specs.bigquery import BigQueryEngineSpec + + message = 'bigquery error: 400 Syntax error: Table "case_detail_all_suites" must be qualified with a dataset (e.g. dataset.table).\n\n(job ID: ddf30b05-44e8-4fbf-aa29-40bfccaed886)\n\n -----Query Job SQL Follows----- \n\n | . | . | . |\n 1:select * from case_detail_all_suites\n 2:LIMIT 1001\n | . | . | . |' + expected_result = 'bigquery error: 400 Syntax error: Table "case_detail_all_suites" must be qualified with a dataset (e.g. dataset.table).' + assert ( + str(BigQueryEngineSpec.parse_error_exception(Exception(message))) + == expected_result + ) + + +def test_parse_error_raises_exception() -> None: + """ + Test that we handle any exception we might get from calling the parse_error_exception method. + + Example errors: + 400 Syntax error: Expected "(" or keyword UNNEST but got "@" at [4:80] + bigquery error: 400 Table \"case_detail_all_suites\" must be qualified with a dataset (e.g. dataset.table). + """ + from superset.db_engine_specs.bigquery import BigQueryEngineSpec + + message = 'bigquery error: 400 Syntax error: Table "case_detail_all_suites" must be qualified with a dataset (e.g. dataset.table).' + message_2 = "6" + expected_result = 'bigquery error: 400 Syntax error: Table "case_detail_all_suites" must be qualified with a dataset (e.g. dataset.table).' + assert ( + str(BigQueryEngineSpec.parse_error_exception(Exception(message))) + == expected_result + ) + assert str(BigQueryEngineSpec.parse_error_exception(Exception(message_2))) == "6" + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "CAST('2019-01-02' AS DATE)"), + ("DateTime", "CAST('2019-01-02T03:04:05.678900' AS DATETIME)"), + ("TimeStamp", "CAST('2019-01-02T03:04:05.678900' AS TIMESTAMP)"), + ("Time", "CAST('03:04:05.678900' AS TIME)"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + """ + DB Eng Specs (bigquery): Test conversion to date time + """ + from superset.db_engine_specs.bigquery import BigQueryEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_clickhouse.py b/tests/unit_tests/db_engine_specs/test_clickhouse.py new file mode 100644 index 0000000000000..9a52b04616af1 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_clickhouse.py @@ -0,0 +1,55 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from datetime import datetime +from typing import Optional +from unittest.mock import Mock + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "toDate('2019-01-02')"), + ("DateTime", "toDateTime('2019-01-02 03:04:05')"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.clickhouse import ClickHouseEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) + + +def test_execute_connection_error() -> None: + from urllib3.exceptions import NewConnectionError + + from superset.db_engine_specs.clickhouse import ClickHouseEngineSpec + from superset.db_engine_specs.exceptions import SupersetDBAPIDatabaseError + + cursor = Mock() + cursor.execute.side_effect = NewConnectionError( + "Dummypool", "Exception with sensitive data" + ) + with pytest.raises(SupersetDBAPIDatabaseError) as ex: + ClickHouseEngineSpec.execute(cursor, "SELECT col1 from table1") diff --git a/tests/unit_tests/db_engine_specs/test_crate.py b/tests/unit_tests/db_engine_specs/test_crate.py new file mode 100644 index 0000000000000..2cb1cd78966dc --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_crate.py @@ -0,0 +1,71 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from datetime import datetime +from typing import Optional + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +def test_epoch_to_dttm() -> None: + """ + DB Eng Specs (crate): Test epoch to dttm + """ + from superset.db_engine_specs.crate import CrateEngineSpec + + assert CrateEngineSpec.epoch_to_dttm() == "{col} * 1000" + + +def test_epoch_ms_to_dttm() -> None: + """ + DB Eng Specs (crate): Test epoch ms to dttm + """ + from superset.db_engine_specs.crate import CrateEngineSpec + + assert CrateEngineSpec.epoch_ms_to_dttm() == "{col}" + + +def test_alter_new_orm_column() -> None: + """ + DB Eng Specs (crate): Test alter orm column + """ + from superset.connectors.sqla.models import SqlaTable, TableColumn + from superset.db_engine_specs.crate import CrateEngineSpec + from superset.models.core import Database + + database = Database(database_name="crate", sqlalchemy_uri="crate://db") + tbl = SqlaTable(table_name="tbl", database=database) + col = TableColumn(column_name="ts", type="TIMESTAMP", table=tbl) + CrateEngineSpec.alter_new_orm_column(col) + assert col.python_date_format == "epoch_ms" + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("TimeStamp", "1546398245678.9"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.crate import CrateEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_databricks.py b/tests/unit_tests/db_engine_specs/test_databricks.py new file mode 100644 index 0000000000000..49d65b324b0bf --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_databricks.py @@ -0,0 +1,246 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# pylint: disable=unused-argument, import-outside-toplevel, protected-access + +import json +from datetime import datetime +from typing import Optional + +import pytest +from pytest_mock import MockerFixture + +from superset.db_engine_specs.databricks import DatabricksNativeEngineSpec +from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +def test_get_parameters_from_uri() -> None: + """ + Test that the result from ``get_parameters_from_uri`` is JSON serializable. + """ + from superset.db_engine_specs.databricks import ( + DatabricksNativeEngineSpec, + DatabricksParametersType, + ) + + parameters = DatabricksNativeEngineSpec.get_parameters_from_uri( + "databricks+connector://token:abc12345@my_hostname:1234/test" + ) + assert parameters == DatabricksParametersType( + { + "access_token": "abc12345", + "host": "my_hostname", + "port": 1234, + "database": "test", + "encryption": False, + } + ) + assert json.loads(json.dumps(parameters)) == parameters + + +def test_build_sqlalchemy_uri() -> None: + """ + test that the parameters are can correctly be compiled into a + sqlalchemy_uri + """ + from superset.db_engine_specs.databricks import ( + DatabricksNativeEngineSpec, + DatabricksParametersType, + ) + + parameters = DatabricksParametersType( + { + "access_token": "abc12345", + "host": "my_hostname", + "port": 1234, + "database": "test", + "encryption": False, + } + ) + encrypted_extra = None + sqlalchemy_uri = DatabricksNativeEngineSpec.build_sqlalchemy_uri( + parameters, encrypted_extra + ) + assert sqlalchemy_uri == ( + "databricks+connector://token:abc12345@my_hostname:1234/test" + ) + + +def test_parameters_json_schema() -> None: + """ + test that the parameters schema can be converted to json + """ + from superset.db_engine_specs.databricks import DatabricksNativeEngineSpec + + json_schema = DatabricksNativeEngineSpec.parameters_json_schema() + + assert json_schema == { + "type": "object", + "properties": { + "access_token": {"type": "string"}, + "database": {"type": "string"}, + "encryption": { + "description": "Use an encrypted connection to the database", + "type": "boolean", + }, + "host": {"type": "string"}, + "http_path": {"type": "string"}, + "port": { + "description": "Database port", + "format": "int32", + "maximum": 65536, + "minimum": 0, + "type": "integer", + }, + }, + "required": ["access_token", "database", "host", "http_path", "port"], + } + + +def test_get_extra_params(mocker: MockerFixture) -> None: + """ + Test the ``get_extra_params`` method. + """ + from superset.db_engine_specs.databricks import DatabricksNativeEngineSpec + + database = mocker.MagicMock() + + database.extra = {} + assert DatabricksNativeEngineSpec.get_extra_params(database) == { + "engine_params": { + "connect_args": { + "http_headers": [("User-Agent", "Apache Superset")], + "_user_agent_entry": "Apache Superset", + } + } + } + + database.extra = json.dumps( + { + "engine_params": { + "connect_args": { + "http_headers": [("User-Agent", "Custom user agent")], + "_user_agent_entry": "Custom user agent", + "foo": "bar", + } + } + } + ) + assert DatabricksNativeEngineSpec.get_extra_params(database) == { + "engine_params": { + "connect_args": { + "http_headers": [["User-Agent", "Custom user agent"]], + "_user_agent_entry": "Custom user agent", + "foo": "bar", + } + } + } + + # it should also remove whitespace from http_path + database.extra = json.dumps( + { + "engine_params": { + "connect_args": { + "http_headers": [("User-Agent", "Custom user agent")], + "_user_agent_entry": "Custom user agent", + "http_path": "/some_path_here_with_whitespace ", + } + } + } + ) + assert DatabricksNativeEngineSpec.get_extra_params(database) == { + "engine_params": { + "connect_args": { + "http_headers": [["User-Agent", "Custom user agent"]], + "_user_agent_entry": "Custom user agent", + "http_path": "/some_path_here_with_whitespace", + } + } + } + + +def test_extract_errors() -> None: + """ + Test that custom error messages are extracted correctly. + """ + + msg = ": mismatched input 'fromm'. Expecting: " + result = DatabricksNativeEngineSpec.extract_errors(Exception(msg)) + + assert result == [ + SupersetError( + message=": mismatched input 'fromm'. Expecting: ", + error_type=SupersetErrorType.GENERIC_DB_ENGINE_ERROR, + level=ErrorLevel.ERROR, + extra={ + "engine_name": "Databricks", + "issue_codes": [ + { + "code": 1002, + "message": "Issue 1002 - The database returned an unexpected error.", + } + ], + }, + ) + ] + + +def test_extract_errors_with_context() -> None: + """ + Test that custom error messages are extracted correctly with context. + """ + + msg = ": mismatched input 'fromm'. Expecting: " + context = {"hostname": "foo"} + result = DatabricksNativeEngineSpec.extract_errors(Exception(msg), context) + + assert result == [ + SupersetError( + message=": mismatched input 'fromm'. Expecting: ", + error_type=SupersetErrorType.GENERIC_DB_ENGINE_ERROR, + level=ErrorLevel.ERROR, + extra={ + "engine_name": "Databricks", + "issue_codes": [ + { + "code": 1002, + "message": "Issue 1002 - The database returned an unexpected error.", + } + ], + }, + ) + ] + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "CAST('2019-01-02' AS DATE)"), + ( + "TimeStamp", + "CAST('2019-01-02 03:04:05.678900' AS TIMESTAMP)", + ), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.databricks import DatabricksNativeEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_dremio.py b/tests/unit_tests/db_engine_specs/test_dremio.py new file mode 100644 index 0000000000000..6b1e8203b5dfe --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_dremio.py @@ -0,0 +1,42 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from datetime import datetime +from typing import Optional + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "TO_DATE('2019-01-02', 'YYYY-MM-DD')"), + ( + "TimeStamp", + "TO_TIMESTAMP('2019-01-02 03:04:05.678', 'YYYY-MM-DD HH24:MI:SS.FFF')", + ), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.dremio import DremioEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_drill.py b/tests/unit_tests/db_engine_specs/test_drill.py index ad7254870f6ef..e56df5d47cc4b 100644 --- a/tests/unit_tests/db_engine_specs/test_drill.py +++ b/tests/unit_tests/db_engine_specs/test_drill.py @@ -16,13 +16,18 @@ # under the License. # pylint: disable=unused-argument, import-outside-toplevel, protected-access -from flask.ctx import AppContext -from pytest import raises +from datetime import datetime +from typing import Optional +import pytest -def test_odbc_impersonation(app_context: AppContext) -> None: +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +def test_odbc_impersonation() -> None: """ - Test ``modify_url_for_impersonation`` method when driver == odbc. + Test ``get_url_for_impersonation`` method when driver == odbc. The method adds the parameter ``DelegationUID`` to the query string. """ @@ -32,13 +37,13 @@ def test_odbc_impersonation(app_context: AppContext) -> None: url = URL("drill+odbc") username = "DoAsUser" - DrillEngineSpec.modify_url_for_impersonation(url, True, username) + url = DrillEngineSpec.get_url_for_impersonation(url, True, username) assert url.query["DelegationUID"] == username -def test_jdbc_impersonation(app_context: AppContext) -> None: +def test_jdbc_impersonation() -> None: """ - Test ``modify_url_for_impersonation`` method when driver == jdbc. + Test ``get_url_for_impersonation`` method when driver == jdbc. The method adds the parameter ``impersonation_target`` to the query string. """ @@ -48,13 +53,13 @@ def test_jdbc_impersonation(app_context: AppContext) -> None: url = URL("drill+jdbc") username = "DoAsUser" - DrillEngineSpec.modify_url_for_impersonation(url, True, username) + url = DrillEngineSpec.get_url_for_impersonation(url, True, username) assert url.query["impersonation_target"] == username -def test_sadrill_impersonation(app_context: AppContext) -> None: +def test_sadrill_impersonation() -> None: """ - Test ``modify_url_for_impersonation`` method when driver == sadrill. + Test ``get_url_for_impersonation`` method when driver == sadrill. The method adds the parameter ``impersonation_target`` to the query string. """ @@ -64,13 +69,13 @@ def test_sadrill_impersonation(app_context: AppContext) -> None: url = URL("drill+sadrill") username = "DoAsUser" - DrillEngineSpec.modify_url_for_impersonation(url, True, username) + url = DrillEngineSpec.get_url_for_impersonation(url, True, username) assert url.query["impersonation_target"] == username -def test_invalid_impersonation(app_context: AppContext) -> None: +def test_invalid_impersonation() -> None: """ - Test ``modify_url_for_impersonation`` method when driver == foobar. + Test ``get_url_for_impersonation`` method when driver == foobar. The method raises an exception because impersonation is not supported for drill+foobar. @@ -83,5 +88,21 @@ def test_invalid_impersonation(app_context: AppContext) -> None: url = URL("drill+foobar") username = "DoAsUser" - with raises(SupersetDBAPIProgrammingError): - DrillEngineSpec.modify_url_for_impersonation(url, True, username) + with pytest.raises(SupersetDBAPIProgrammingError): + DrillEngineSpec.get_url_for_impersonation(url, True, username) + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "TO_DATE('2019-01-02', 'yyyy-MM-dd')"), + ("TimeStamp", "TO_TIMESTAMP('2019-01-02 03:04:05', 'yyyy-MM-dd HH:mm:ss')"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.drill import DrillEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_druid.py b/tests/unit_tests/db_engine_specs/test_druid.py new file mode 100644 index 0000000000000..d090dffcde043 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_druid.py @@ -0,0 +1,95 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from datetime import datetime +from typing import Optional +from unittest import mock + +import pytest +from sqlalchemy import column + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "CAST(TIME_PARSE('2019-01-02') AS DATE)"), + ("DateTime", "TIME_PARSE('2019-01-02T03:04:05')"), + ("TimeStamp", "TIME_PARSE('2019-01-02T03:04:05')"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.druid import DruidEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) + + +@pytest.mark.parametrize( + "time_grain,expected_result", + [ + ("PT1S", "TIME_FLOOR(CAST(col AS TIMESTAMP), 'PT1S')"), + ("PT5M", "TIME_FLOOR(CAST({col} AS TIMESTAMP), 'PT5M')"), + ( + "P1W/1970-01-03T00:00:00Z", + "TIME_SHIFT(TIME_FLOOR(TIME_SHIFT(CAST(col AS TIMESTAMP), 'P1D', 1), 'P1W'), 'P1D', 5)", + ), + ( + "1969-12-28T00:00:00Z/P1W", + "TIME_SHIFT(TIME_FLOOR(TIME_SHIFT(CAST(col AS TIMESTAMP), 'P1D', 1), 'P1W'), 'P1D', -1)", + ), + ], +) +def test_timegrain_expressions(time_grain: str, expected_result: str) -> None: + """ + DB Eng Specs (druid): Test time grain expressions + """ + from superset.db_engine_specs.druid import DruidEngineSpec + + assert str( + DruidEngineSpec.get_timestamp_expr( + col=column("col"), pdf=None, time_grain=time_grain + ) + ) + + +def test_extras_without_ssl() -> None: + from superset.db_engine_specs.druid import DruidEngineSpec + from tests.integration_tests.fixtures.database import default_db_extra + + db = mock.Mock() + db.extra = default_db_extra + db.server_cert = None + extras = DruidEngineSpec.get_extra_params(db) + assert "connect_args" not in extras["engine_params"] + + +def test_extras_with_ssl() -> None: + from superset.db_engine_specs.druid import DruidEngineSpec + from tests.integration_tests.fixtures.certificates import ssl_certificate + from tests.integration_tests.fixtures.database import default_db_extra + + db = mock.Mock() + db.extra = default_db_extra + db.server_cert = ssl_certificate + extras = DruidEngineSpec.get_extra_params(db) + connect_args = extras["engine_params"]["connect_args"] + assert connect_args["scheme"] == "https" + assert "ssl_verify_cert" in connect_args diff --git a/tests/unit_tests/db_engine_specs/test_duckdb.py b/tests/unit_tests/db_engine_specs/test_duckdb.py new file mode 100644 index 0000000000000..72d018f4fcdc8 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_duckdb.py @@ -0,0 +1,40 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from datetime import datetime +from typing import Optional + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Text", "'2019-01-02 03:04:05.678900'"), + ("DateTime", "'2019-01-02 03:04:05.678900'"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.duckdb import DuckDBEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_dynamodb.py b/tests/unit_tests/db_engine_specs/test_dynamodb.py new file mode 100644 index 0000000000000..26196f5b459e7 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_dynamodb.py @@ -0,0 +1,40 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from datetime import datetime +from typing import Optional + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("text", "'2019-01-02 03:04:05'"), + ("dateTime", "'2019-01-02 03:04:05'"), + ("unknowntype", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.dynamodb import DynamoDBEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_elasticsearch.py b/tests/unit_tests/db_engine_specs/test_elasticsearch.py new file mode 100644 index 0000000000000..de55c63426b70 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_elasticsearch.py @@ -0,0 +1,106 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from datetime import datetime +from typing import Any, Dict, Optional +from unittest.mock import MagicMock + +import pytest +from sqlalchemy import column + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,db_extra,expected_result", + [ + ("DateTime", None, "CAST('2019-01-02T03:04:05' AS DATETIME)"), + ( + "DateTime", + {"version": "7.7"}, + "CAST('2019-01-02T03:04:05' AS DATETIME)", + ), + ( + "DateTime", + {"version": "7.8"}, + "DATETIME_PARSE('2019-01-02 03:04:05', 'yyyy-MM-dd HH:mm:ss')", + ), + ( + "DateTime", + {"version": "unparseable semver version"}, + "CAST('2019-01-02T03:04:05' AS DATETIME)", + ), + ("Unknown", None, None), + ], +) +def test_elasticsearch_convert_dttm( + target_type: str, + db_extra: Optional[Dict[str, Any]], + expected_result: Optional[str], + dttm: datetime, +) -> None: + from superset.db_engine_specs.elasticsearch import ElasticSearchEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm, db_extra) + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("DateTime", "'2019-01-02T03:04:05'"), + ("Unknown", None), + ], +) +def test_opendistro_convert_dttm( + target_type: str, + expected_result: Optional[str], + dttm: datetime, +) -> None: + from superset.db_engine_specs.elasticsearch import OpenDistroEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) + + +@pytest.mark.parametrize( + "original,expected", + [ + ("Col", "Col"), + ("Col.keyword", "Col_keyword"), + ], +) +def test_opendistro_sqla_column_label(original: str, expected: str) -> None: + """ + DB Eng Specs (opendistro): Test column label + """ + from superset.db_engine_specs.elasticsearch import OpenDistroEngineSpec + + assert OpenDistroEngineSpec.make_label_compatible(original) == expected + + +def test_opendistro_strip_comments() -> None: + """ + DB Eng Specs (opendistro): Test execute sql strip comments + """ + from superset.db_engine_specs.elasticsearch import OpenDistroEngineSpec + + mock_cursor = MagicMock() + mock_cursor.execute.return_value = [] + + OpenDistroEngineSpec.execute( + mock_cursor, "-- some comment \nSELECT 1\n --other comment" + ) + mock_cursor.execute.assert_called_once_with("SELECT 1\n") diff --git a/tests/unit_tests/db_engine_specs/test_firebird.py b/tests/unit_tests/db_engine_specs/test_firebird.py new file mode 100644 index 0000000000000..c1add91678abc --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_firebird.py @@ -0,0 +1,102 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from datetime import datetime +from typing import Optional + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "time_grain,expected", + [ + (None, "timestamp_column"), + ( + "PT1S", + ( + "CAST(CAST(timestamp_column AS DATE) " + "|| ' ' " + "|| EXTRACT(HOUR FROM timestamp_column) " + "|| ':' " + "|| EXTRACT(MINUTE FROM timestamp_column) " + "|| ':' " + "|| FLOOR(EXTRACT(SECOND FROM timestamp_column)) AS TIMESTAMP)" + ), + ), + ( + "PT1M", + ( + "CAST(CAST(timestamp_column AS DATE) " + "|| ' ' " + "|| EXTRACT(HOUR FROM timestamp_column) " + "|| ':' " + "|| EXTRACT(MINUTE FROM timestamp_column) " + "|| ':00' AS TIMESTAMP)" + ), + ), + ("P1D", "CAST(timestamp_column AS DATE)"), + ( + "P1M", + ( + "CAST(EXTRACT(YEAR FROM timestamp_column) " + "|| '-' " + "|| EXTRACT(MONTH FROM timestamp_column) " + "|| '-01' AS DATE)" + ), + ), + ("P1Y", "CAST(EXTRACT(YEAR FROM timestamp_column) || '-01-01' AS DATE)"), + ], +) +def test_time_grain_expressions(time_grain: Optional[str], expected: str) -> None: + from superset.db_engine_specs.firebird import FirebirdEngineSpec + + assert ( + FirebirdEngineSpec._time_grain_expressions[time_grain].format( + col="timestamp_column", + ) + == expected + ) + + +def test_epoch_to_dttm() -> None: + from superset.db_engine_specs.firebird import FirebirdEngineSpec + + assert ( + FirebirdEngineSpec.epoch_to_dttm().format(col="timestamp_column") + == "DATEADD(second, timestamp_column, CAST('00:00:00' AS TIMESTAMP))" + ) + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "CAST('2019-01-02' AS DATE)"), + ("DateTime", "CAST('2019-01-02 03:04:05.6789' AS TIMESTAMP)"), + ("TimeStamp", "CAST('2019-01-02 03:04:05.6789' AS TIMESTAMP)"), + ("Time", "CAST('03:04:05.678900' AS TIME)"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.firebird import FirebirdEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_firebolt.py b/tests/unit_tests/db_engine_specs/test_firebolt.py new file mode 100644 index 0000000000000..eb84bb14b3ca8 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_firebolt.py @@ -0,0 +1,57 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +from datetime import datetime +from typing import Optional + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "CAST('2019-01-02' AS DATE)"), + ( + "DateTime", + "CAST('2019-01-02T03:04:05' AS DATETIME)", + ), + ( + "TimeStamp", + "CAST('2019-01-02T03:04:05' AS TIMESTAMP)", + ), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.firebolt import FireboltEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) + + +def test_epoch_to_dttm() -> None: + from superset.db_engine_specs.firebolt import FireboltEngineSpec + + assert ( + FireboltEngineSpec.epoch_to_dttm().format(col="timestamp_column") + == "from_unixtime(timestamp_column)" + ) diff --git a/tests/unit_tests/db_engine_specs/test_gsheets.py b/tests/unit_tests/db_engine_specs/test_gsheets.py index c2e8346c3c7ac..042e486642bd8 100644 --- a/tests/unit_tests/db_engine_specs/test_gsheets.py +++ b/tests/unit_tests/db_engine_specs/test_gsheets.py @@ -14,7 +14,11 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from flask.ctx import AppContext + +# pylint: disable=import-outside-toplevel, invalid-name, line-too-long + +import json + from pytest_mock import MockFixture from superset.errors import ErrorLevel, SupersetError, SupersetErrorType @@ -26,20 +30,44 @@ class ProgrammingError(Exception): """ -def test_validate_parameters_simple( - mocker: MockFixture, - app_context: AppContext, -) -> None: +def test_validate_parameters_simple() -> None: from superset.db_engine_specs.gsheets import ( GSheetsEngineSpec, - GSheetsParametersType, + GSheetsPropertiesType, ) - parameters: GSheetsParametersType = { - "service_account_info": "", + properties: GSheetsPropertiesType = { + "parameters": { + "service_account_info": "", + "catalog": {}, + }, "catalog": {}, } - errors = GSheetsEngineSpec.validate_parameters(parameters) + errors = GSheetsEngineSpec.validate_parameters(properties) + assert errors == [ + SupersetError( + message="Sheet name is required", + error_type=SupersetErrorType.CONNECTION_MISSING_PARAMETERS_ERROR, + level=ErrorLevel.WARNING, + extra={"catalog": {"idx": 0, "name": True}}, + ), + ] + + +def test_validate_parameters_simple_with_in_root_catalog() -> None: + from superset.db_engine_specs.gsheets import ( + GSheetsEngineSpec, + GSheetsPropertiesType, + ) + + properties: GSheetsPropertiesType = { + "parameters": { + "service_account_info": "", + "catalog": {}, + }, + "catalog": {}, + } + errors = GSheetsEngineSpec.validate_parameters(properties) assert errors == [ SupersetError( message="Sheet name is required", @@ -52,11 +80,10 @@ def test_validate_parameters_simple( def test_validate_parameters_catalog( mocker: MockFixture, - app_context: AppContext, ) -> None: from superset.db_engine_specs.gsheets import ( GSheetsEngineSpec, - GSheetsParametersType, + GSheetsPropertiesType, ) g = mocker.patch("superset.db_engine_specs.gsheets.g") @@ -71,15 +98,15 @@ def test_validate_parameters_catalog( ProgrammingError("Unsupported table: https://www.google.com/"), ] - parameters: GSheetsParametersType = { - "service_account_info": "", + properties: GSheetsPropertiesType = { + "parameters": {"service_account_info": "", "catalog": None}, "catalog": { "private_sheet": "https://docs.google.com/spreadsheets/d/1/edit", "public_sheet": "https://docs.google.com/spreadsheets/d/1/edit#gid=1", "not_a_sheet": "https://www.google.com/", }, } - errors = GSheetsEngineSpec.validate_parameters(parameters) # ignore: type + errors = GSheetsEngineSpec.validate_parameters(properties) # ignore: type assert errors == [ SupersetError( @@ -143,11 +170,10 @@ def test_validate_parameters_catalog( def test_validate_parameters_catalog_and_credentials( mocker: MockFixture, - app_context: AppContext, ) -> None: from superset.db_engine_specs.gsheets import ( GSheetsEngineSpec, - GSheetsParametersType, + GSheetsPropertiesType, ) g = mocker.patch("superset.db_engine_specs.gsheets.g") @@ -162,15 +188,18 @@ def test_validate_parameters_catalog_and_credentials( ProgrammingError("Unsupported table: https://www.google.com/"), ] - parameters: GSheetsParametersType = { - "service_account_info": "", + properties: GSheetsPropertiesType = { + "parameters": { + "service_account_info": "", + "catalog": None, + }, "catalog": { "private_sheet": "https://docs.google.com/spreadsheets/d/1/edit", "public_sheet": "https://docs.google.com/spreadsheets/d/1/edit#gid=1", "not_a_sheet": "https://www.google.com/", }, } - errors = GSheetsEngineSpec.validate_parameters(parameters) # ignore: type + errors = GSheetsEngineSpec.validate_parameters(properties) # ignore: type assert errors == [ SupersetError( message=( @@ -204,3 +233,77 @@ def test_validate_parameters_catalog_and_credentials( service_account_info={}, subject="admin@example.com", ) + + +def test_unmask_encrypted_extra() -> None: + """ + Test that the private key can be reused from the previous ``encrypted_extra``. + """ + from superset.db_engine_specs.gsheets import GSheetsEngineSpec + + old = json.dumps( + { + "service_account_info": { + "project_id": "black-sanctum-314419", + "private_key": "SECRET", + }, + } + ) + new = json.dumps( + { + "service_account_info": { + "project_id": "yellow-unicorn-314419", + "private_key": "XXXXXXXXXX", + }, + } + ) + + assert json.loads(str(GSheetsEngineSpec.unmask_encrypted_extra(old, new))) == { + "service_account_info": { + "project_id": "yellow-unicorn-314419", + "private_key": "SECRET", + }, + } + + +def test_unmask_encrypted_extra_when_old_is_none() -> None: + """ + Test that a None value works for ``encrypted_extra``. + """ + from superset.db_engine_specs.gsheets import GSheetsEngineSpec + + old = None + new = json.dumps( + { + "service_account_info": { + "project_id": "yellow-unicorn-314419", + "private_key": "XXXXXXXXXX", + }, + } + ) + + assert json.loads(str(GSheetsEngineSpec.unmask_encrypted_extra(old, new))) == { + "service_account_info": { + "project_id": "yellow-unicorn-314419", + "private_key": "XXXXXXXXXX", + }, + } + + +def test_unmask_encrypted_extra_when_new_is_none() -> None: + """ + Test that a None value works for ``encrypted_extra``. + """ + from superset.db_engine_specs.gsheets import GSheetsEngineSpec + + old = json.dumps( + { + "service_account_info": { + "project_id": "yellow-unicorn-314419", + "private_key": "XXXXXXXXXX", + }, + } + ) + new = None + + assert GSheetsEngineSpec.unmask_encrypted_extra(old, new) is None diff --git a/tests/integration_tests/db_engine_specs/hana_tests.py b/tests/unit_tests/db_engine_specs/test_hana.py similarity index 57% rename from tests/integration_tests/db_engine_specs/hana_tests.py rename to tests/unit_tests/db_engine_specs/test_hana.py index 06eee032e8d20..1d1ac6390839c 100644 --- a/tests/integration_tests/db_engine_specs/hana_tests.py +++ b/tests/unit_tests/db_engine_specs/test_hana.py @@ -14,20 +14,30 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from superset.db_engine_specs.hana import HanaEngineSpec -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec +from datetime import datetime +from typing import Optional -class TestHanaDbEngineSpec(TestDbEngineSpec): - def test_convert_dttm(self): - dttm = self.get_dttm() +import pytest - self.assertEqual( - HanaEngineSpec.convert_dttm("DATE", dttm), - "TO_DATE('2019-01-02', 'YYYY-MM-DD')", - ) +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm - self.assertEqual( - HanaEngineSpec.convert_dttm("TIMESTAMP", dttm), + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "TO_DATE('2019-01-02', 'YYYY-MM-DD')"), + ( + "TimeStamp", "TO_TIMESTAMP('2019-01-02T03:04:05.678900', 'YYYY-MM-DD\"T\"HH24:MI:SS.ff6')", - ) + ), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.hana import HanaEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_hive.py b/tests/unit_tests/db_engine_specs/test_hive.py new file mode 100644 index 0000000000000..3a5cb91405bd4 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_hive.py @@ -0,0 +1,44 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +from datetime import datetime +from typing import Optional + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "CAST('2019-01-02' AS DATE)"), + ( + "TimeStamp", + "CAST('2019-01-02 03:04:05.678900' AS TIMESTAMP)", + ), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.hive import HiveEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_impala.py b/tests/unit_tests/db_engine_specs/test_impala.py new file mode 100644 index 0000000000000..8a42440529ae0 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_impala.py @@ -0,0 +1,40 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from datetime import datetime +from typing import Optional + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "CAST('2019-01-02' AS DATE)"), + ("TimeStamp", "CAST('2019-01-02T03:04:05.678900' AS TIMESTAMP)"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.impala import ImpalaEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_init.py b/tests/unit_tests/db_engine_specs/test_init.py new file mode 100644 index 0000000000000..3189256c70f12 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_init.py @@ -0,0 +1,80 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +import pytest +from pkg_resources import EntryPoint +from pytest_mock import MockFixture + +from superset.db_engine_specs import get_available_engine_specs + + +def test_get_available_engine_specs(mocker: MockFixture) -> None: + """ + get_available_engine_specs should return all engine specs + """ + from superset.db_engine_specs.databricks import ( + DatabricksHiveEngineSpec, + DatabricksNativeEngineSpec, + DatabricksODBCEngineSpec, + ) + + mocker.patch( + "superset.db_engine_specs.load_engine_specs", + return_value=iter( + [ + DatabricksHiveEngineSpec, + DatabricksNativeEngineSpec, + DatabricksODBCEngineSpec, + ] + ), + ) + + assert list(get_available_engine_specs().keys()) == [ + DatabricksHiveEngineSpec, + DatabricksNativeEngineSpec, + DatabricksODBCEngineSpec, + ] + + +@pytest.mark.parametrize( + "app", + [{"DBS_AVAILABLE_DENYLIST": {"databricks": {"pyhive", "pyodbc"}}}], + indirect=True, +) +def test_get_available_engine_specs_with_denylist(mocker: MockFixture) -> None: + """ + The denylist removes items from the db engine spec list + """ + from superset.db_engine_specs.databricks import ( + DatabricksHiveEngineSpec, + DatabricksNativeEngineSpec, + DatabricksODBCEngineSpec, + ) + + mocker.patch( + "superset.db_engine_specs.load_engine_specs", + return_value=iter( + [ + DatabricksHiveEngineSpec, + DatabricksNativeEngineSpec, + DatabricksODBCEngineSpec, + ] + ), + ) + available = get_available_engine_specs() + assert list(available.keys()) == [DatabricksNativeEngineSpec] diff --git a/tests/unit_tests/db_engine_specs/test_kusto.py b/tests/unit_tests/db_engine_specs/test_kusto.py index fca6ee5817de1..538eafc6b176b 100644 --- a/tests/unit_tests/db_engine_specs/test_kusto.py +++ b/tests/unit_tests/db_engine_specs/test_kusto.py @@ -16,10 +16,11 @@ # under the License. # pylint: disable=unused-argument, import-outside-toplevel, protected-access from datetime import datetime +from typing import Optional import pytest -from flask.ctx import AppContext +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm from tests.unit_tests.fixtures.common import dttm @@ -32,9 +33,7 @@ ("INSERT INTO tbl (foo) VALUES (1)", False), ], ) -def test_sql_is_readonly_query( - app_context: AppContext, sql: str, expected: bool -) -> None: +def test_sql_is_readonly_query(sql: str, expected: bool) -> None: """ Make sure that SQL dialect consider only SELECT statements as read-only """ @@ -56,7 +55,7 @@ def test_sql_is_readonly_query( (".show tables", False), ], ) -def test_kql_is_select_query(app_context: AppContext, kql: str, expected: bool) -> None: +def test_kql_is_select_query(kql: str, expected: bool) -> None: """ Make sure that KQL dialect consider only statements that do not start with "." (dot) as a SELECT statements @@ -83,9 +82,7 @@ def test_kql_is_select_query(app_context: AppContext, kql: str, expected: bool) (".set-or-append table foo <| bar", False), ], ) -def test_kql_is_readonly_query( - app_context: AppContext, kql: str, expected: bool -) -> None: +def test_kql_is_readonly_query(kql: str, expected: bool) -> None: """ Make sure that KQL dialect consider only SELECT statements as read-only """ @@ -99,7 +96,7 @@ def test_kql_is_readonly_query( assert expected == is_readonly -def test_kql_parse_sql(app_context: AppContext) -> None: +def test_kql_parse_sql() -> None: """ parse_sql method should always return a list with a single element which is an original query @@ -113,47 +110,35 @@ def test_kql_parse_sql(app_context: AppContext) -> None: @pytest.mark.parametrize( - "target_type,expected_dttm", + "target_type,expected_result", [ - ("DATETIME", "datetime(2019-01-02T03:04:05.678900)"), - ("TIMESTAMP", "datetime(2019-01-02T03:04:05.678900)"), - ("DATE", "datetime(2019-01-02)"), + ("DateTime", "datetime(2019-01-02T03:04:05.678900)"), + ("TimeStamp", "datetime(2019-01-02T03:04:05.678900)"), + ("Date", "datetime(2019-01-02)"), + ("UnknownType", None), ], ) def test_kql_convert_dttm( - app_context: AppContext, - target_type: str, - expected_dttm: str, - dttm: datetime, + target_type: str, expected_result: Optional[str], dttm: datetime ) -> None: - """ - Test that date objects are converted correctly. - """ - - from superset.db_engine_specs.kusto import KustoKqlEngineSpec + from superset.db_engine_specs.kusto import KustoKqlEngineSpec as spec - assert expected_dttm == KustoKqlEngineSpec.convert_dttm(target_type, dttm) + assert_convert_dttm(spec, target_type, expected_result, dttm) @pytest.mark.parametrize( - "target_type,expected_dttm", + "target_type,expected_result", [ - ("DATETIME", "CONVERT(DATETIME, '2019-01-02T03:04:05.678', 126)"), - ("DATE", "CONVERT(DATE, '2019-01-02', 23)"), - ("SMALLDATETIME", "CONVERT(SMALLDATETIME, '2019-01-02 03:04:05', 20)"), - ("TIMESTAMP", "CONVERT(TIMESTAMP, '2019-01-02 03:04:05', 20)"), + ("Date", "CONVERT(DATE, '2019-01-02', 23)"), + ("DateTime", "CONVERT(DATETIME, '2019-01-02T03:04:05.678', 126)"), + ("SmallDateTime", "CONVERT(SMALLDATETIME, '2019-01-02 03:04:05', 20)"), + ("TimeStamp", "CONVERT(TIMESTAMP, '2019-01-02 03:04:05', 20)"), + ("UnknownType", None), ], ) def test_sql_convert_dttm( - app_context: AppContext, - target_type: str, - expected_dttm: str, - dttm: datetime, + target_type: str, expected_result: Optional[str], dttm: datetime ) -> None: - """ - Test that date objects are converted correctly. - """ - - from superset.db_engine_specs.kusto import KustoSqlEngineSpec + from superset.db_engine_specs.kusto import KustoSqlEngineSpec as spec - assert expected_dttm == KustoSqlEngineSpec.convert_dttm(target_type, dttm) + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_kylin.py b/tests/unit_tests/db_engine_specs/test_kylin.py new file mode 100644 index 0000000000000..cbc8c9133de7f --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_kylin.py @@ -0,0 +1,40 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from datetime import datetime +from typing import Optional + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "CAST('2019-01-02' AS DATE)"), + ("TimeStamp", "CAST('2019-01-02 03:04:05' AS TIMESTAMP)"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.kylin import KylinEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_mssql.py b/tests/unit_tests/db_engine_specs/test_mssql.py index ddade3bfdb38c..63a315c14c87d 100644 --- a/tests/unit_tests/db_engine_specs/test_mssql.py +++ b/tests/unit_tests/db_engine_specs/test_mssql.py @@ -17,10 +17,10 @@ import unittest.mock as mock from datetime import datetime from textwrap import dedent +from typing import Any, Dict, Optional, Type import pytest -from flask.ctx import AppContext -from sqlalchemy import column, table +from sqlalchemy import column, table, types from sqlalchemy.dialects import mssql from sqlalchemy.dialects.mssql import DATE, NTEXT, NVARCHAR, TEXT, VARCHAR from sqlalchemy.sql import select @@ -28,52 +28,51 @@ from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.utils.core import GenericDataType +from tests.unit_tests.db_engine_specs.utils import ( + assert_column_spec, + assert_convert_dttm, +) from tests.unit_tests.fixtures.common import dttm @pytest.mark.parametrize( - "type_string,type_expected,generic_type_expected", + "native_type,sqla_type,attrs,generic_type,is_dttm", [ - ("STRING", String, GenericDataType.STRING), - ("CHAR(10)", String, GenericDataType.STRING), - ("VARCHAR(10)", String, GenericDataType.STRING), - ("TEXT", String, GenericDataType.STRING), - ("NCHAR(10)", UnicodeText, GenericDataType.STRING), - ("NVARCHAR(10)", UnicodeText, GenericDataType.STRING), - ("NTEXT", UnicodeText, GenericDataType.STRING), + ("CHAR", String, None, GenericDataType.STRING, False), + ("CHAR(10)", String, None, GenericDataType.STRING, False), + ("VARCHAR", String, None, GenericDataType.STRING, False), + ("VARCHAR(10)", String, None, GenericDataType.STRING, False), + ("TEXT", String, None, GenericDataType.STRING, False), + ("NCHAR(10)", UnicodeText, None, GenericDataType.STRING, False), + ("NVARCHAR(10)", UnicodeText, None, GenericDataType.STRING, False), + ("NTEXT", UnicodeText, None, GenericDataType.STRING, False), ], ) -def test_mssql_column_types( - app_context: AppContext, - type_string: str, - type_expected: TypeEngine, - generic_type_expected: GenericDataType, +def test_get_column_spec( + native_type: str, + sqla_type: Type[types.TypeEngine], + attrs: Optional[Dict[str, Any]], + generic_type: GenericDataType, + is_dttm: bool, ) -> None: - from superset.db_engine_specs.mssql import MssqlEngineSpec + from superset.db_engine_specs.mssql import MssqlEngineSpec as spec - if type_expected is None: - type_assigned = MssqlEngineSpec.get_sqla_column_type(type_string) - assert type_assigned is None - else: - column_spec = MssqlEngineSpec.get_column_spec(type_string) - if column_spec is not None: - assert isinstance(column_spec.sqla_type, type_expected) - assert column_spec.generic_type == generic_type_expected + assert_column_spec(spec, native_type, sqla_type, attrs, generic_type, is_dttm) -def test_where_clause_n_prefix(app_context: AppContext) -> None: +def test_where_clause_n_prefix() -> None: from superset.db_engine_specs.mssql import MssqlEngineSpec dialect = mssql.dialect() # non-unicode col - sqla_column_type = MssqlEngineSpec.get_sqla_column_type("VARCHAR(10)") + sqla_column_type = MssqlEngineSpec.get_column_types("VARCHAR(10)") assert sqla_column_type is not None type_, _ = sqla_column_type str_col = column("col", type_=type_) # unicode col - sqla_column_type = MssqlEngineSpec.get_sqla_column_type("NTEXT") + sqla_column_type = MssqlEngineSpec.get_column_types("NTEXT") assert sqla_column_type is not None type_, _ = sqla_column_type unicode_col = column("unicode_col", type_=type_) @@ -95,7 +94,7 @@ def test_where_clause_n_prefix(app_context: AppContext) -> None: assert query == query_expected -def test_time_exp_mixd_case_col_1y(app_context: AppContext) -> None: +def test_time_exp_mixd_case_col_1y() -> None: from superset.db_engine_specs.mssql import MssqlEngineSpec col = column("MixedCase") @@ -105,34 +104,34 @@ def test_time_exp_mixd_case_col_1y(app_context: AppContext) -> None: @pytest.mark.parametrize( - "actual,expected", + "target_type,expected_result", [ ( - "DATE", + "date", "CONVERT(DATE, '2019-01-02', 23)", ), ( - "DATETIME", + "datetime", "CONVERT(DATETIME, '2019-01-02T03:04:05.678', 126)", ), ( - "SMALLDATETIME", + "smalldatetime", "CONVERT(SMALLDATETIME, '2019-01-02 03:04:05', 20)", ), + ("Other", None), ], ) def test_convert_dttm( - app_context: AppContext, - actual: str, - expected: str, + target_type: str, + expected_result: Optional[str], dttm: datetime, ) -> None: - from superset.db_engine_specs.mssql import MssqlEngineSpec + from superset.db_engine_specs.mssql import MssqlEngineSpec as spec - assert MssqlEngineSpec.convert_dttm(actual, dttm) == expected + assert_convert_dttm(spec, target_type, expected_result, dttm) -def test_extract_error_message(app_context: AppContext) -> None: +def test_extract_error_message() -> None: from superset.db_engine_specs.mssql import MssqlEngineSpec test_mssql_exception = Exception( @@ -158,7 +157,7 @@ def test_extract_error_message(app_context: AppContext) -> None: assert expected_message == error_message -def test_fetch_data(app_context: AppContext) -> None: +def test_fetch_data() -> None: from superset.db_engine_specs.base import BaseEngineSpec from superset.db_engine_specs.mssql import MssqlEngineSpec @@ -185,9 +184,7 @@ def test_fetch_data(app_context: AppContext) -> None: (NTEXT(collation="utf8_general_ci"), "NTEXT"), ], ) -def test_column_datatype_to_string( - app_context: AppContext, original: TypeEngine, expected: str -) -> None: +def test_column_datatype_to_string(original: TypeEngine, expected: str) -> None: from superset.db_engine_specs.mssql import MssqlEngineSpec actual = MssqlEngineSpec.column_datatype_to_string(original, mssql.dialect()) @@ -239,9 +236,7 @@ def test_column_datatype_to_string( ), ], ) -def test_cte_query_parsing( - app_context: AppContext, original: TypeEngine, expected: str -) -> None: +def test_cte_query_parsing(original: TypeEngine, expected: str) -> None: from superset.db_engine_specs.mssql import MssqlEngineSpec actual = MssqlEngineSpec.get_cte_query(original) @@ -270,16 +265,14 @@ def test_cte_query_parsing( ), ], ) -def test_top_query_parsing( - app_context: AppContext, original: TypeEngine, expected: str, top: int -) -> None: +def test_top_query_parsing(original: TypeEngine, expected: str, top: int) -> None: from superset.db_engine_specs.mssql import MssqlEngineSpec actual = MssqlEngineSpec.apply_top_to_sql(original, top) assert actual == expected -def test_extract_errors(app_context: AppContext) -> None: +def test_extract_errors() -> None: """ Test that custom error messages are extracted correctly. """ diff --git a/tests/unit_tests/db_engine_specs/test_mysql.py b/tests/unit_tests/db_engine_specs/test_mysql.py new file mode 100644 index 0000000000000..4562e497c6e61 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_mysql.py @@ -0,0 +1,130 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from datetime import datetime +from typing import Any, Dict, Optional, Type +from unittest.mock import Mock, patch + +import pytest +from sqlalchemy import types +from sqlalchemy.dialects.mysql import ( + BIT, + DECIMAL, + DOUBLE, + FLOAT, + INTEGER, + LONGTEXT, + MEDIUMINT, + MEDIUMTEXT, + TINYINT, + TINYTEXT, +) + +from superset.utils.core import GenericDataType +from tests.unit_tests.db_engine_specs.utils import ( + assert_column_spec, + assert_convert_dttm, +) +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "native_type,sqla_type,attrs,generic_type,is_dttm", + [ + # Numeric + ("TINYINT", TINYINT, None, GenericDataType.NUMERIC, False), + ("SMALLINT", types.SmallInteger, None, GenericDataType.NUMERIC, False), + ("MEDIUMINT", MEDIUMINT, None, GenericDataType.NUMERIC, False), + ("INT", INTEGER, None, GenericDataType.NUMERIC, False), + ("BIGINT", types.BigInteger, None, GenericDataType.NUMERIC, False), + ("DECIMAL", DECIMAL, None, GenericDataType.NUMERIC, False), + ("FLOAT", FLOAT, None, GenericDataType.NUMERIC, False), + ("DOUBLE", DOUBLE, None, GenericDataType.NUMERIC, False), + ("BIT", BIT, None, GenericDataType.NUMERIC, False), + # String + ("CHAR", types.String, None, GenericDataType.STRING, False), + ("VARCHAR", types.String, None, GenericDataType.STRING, False), + ("TINYTEXT", TINYTEXT, None, GenericDataType.STRING, False), + ("MEDIUMTEXT", MEDIUMTEXT, None, GenericDataType.STRING, False), + ("LONGTEXT", LONGTEXT, None, GenericDataType.STRING, False), + # Temporal + ("DATE", types.Date, None, GenericDataType.TEMPORAL, True), + ("DATETIME", types.DateTime, None, GenericDataType.TEMPORAL, True), + ("TIMESTAMP", types.TIMESTAMP, None, GenericDataType.TEMPORAL, True), + ("TIME", types.Time, None, GenericDataType.TEMPORAL, True), + ], +) +def test_get_column_spec( + native_type: str, + sqla_type: Type[types.TypeEngine], + attrs: Optional[Dict[str, Any]], + generic_type: GenericDataType, + is_dttm: bool, +) -> None: + from superset.db_engine_specs.mysql import MySQLEngineSpec as spec + + assert_column_spec(spec, native_type, sqla_type, attrs, generic_type, is_dttm) + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "STR_TO_DATE('2019-01-02', '%Y-%m-%d')"), + ( + "DateTime", + "STR_TO_DATE('2019-01-02 03:04:05.678900', '%Y-%m-%d %H:%i:%s.%f')", + ), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.mysql import MySQLEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) + + +@patch("sqlalchemy.engine.Engine.connect") +def test_get_cancel_query_id(engine_mock: Mock) -> None: + from superset.db_engine_specs.mysql import MySQLEngineSpec + from superset.models.sql_lab import Query + + query = Query() + cursor_mock = engine_mock.return_value.__enter__.return_value + cursor_mock.fetchone.return_value = ["123"] + assert MySQLEngineSpec.get_cancel_query_id(cursor_mock, query) == "123" + + +@patch("sqlalchemy.engine.Engine.connect") +def test_cancel_query(engine_mock: Mock) -> None: + from superset.db_engine_specs.mysql import MySQLEngineSpec + from superset.models.sql_lab import Query + + query = Query() + cursor_mock = engine_mock.return_value.__enter__.return_value + assert MySQLEngineSpec.cancel_query(cursor_mock, query, "123") is True + + +@patch("sqlalchemy.engine.Engine.connect") +def test_cancel_query_failed(engine_mock: Mock) -> None: + from superset.db_engine_specs.mysql import MySQLEngineSpec + from superset.models.sql_lab import Query + + query = Query() + cursor_mock = engine_mock.raiseError.side_effect = Exception() + assert MySQLEngineSpec.cancel_query(cursor_mock, query, "123") is False diff --git a/tests/unit_tests/db_engine_specs/test_oracle.py b/tests/unit_tests/db_engine_specs/test_oracle.py new file mode 100644 index 0000000000000..0dce956970611 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_oracle.py @@ -0,0 +1,113 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from datetime import datetime +from typing import Optional, Union +from unittest import mock + +import pytest +from sqlalchemy import column, types +from sqlalchemy.dialects import oracle +from sqlalchemy.dialects.oracle import DATE, NVARCHAR, VARCHAR +from sqlalchemy.sql import quoted_name + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "column_name,expected_result", + [ + ("This_Is_32_Character_Column_Name", "3b26974078683be078219674eeb8f5"), + ("snake_label", "snake_label"), + ("camelLabel", "camelLabel"), + ], +) +def test_oracle_sqla_column_name_length_exceeded( + column_name: str, expected_result: Union[str, quoted_name] +) -> None: + from superset.db_engine_specs.oracle import OracleEngineSpec + + label = OracleEngineSpec.make_label_compatible(column_name) + assert isinstance(label, quoted_name) + assert label.quote is True + assert label == expected_result + + +def test_oracle_time_expression_reserved_keyword_1m_grain() -> None: + from superset.db_engine_specs.oracle import OracleEngineSpec + + col = column("decimal") + expr = OracleEngineSpec.get_timestamp_expr(col, None, "P1M") + result = str(expr.compile(dialect=oracle.dialect())) + assert result == "TRUNC(CAST(\"decimal\" as DATE), 'MONTH')" + + +@pytest.mark.parametrize( + "sqla_type,expected_result", + [ + (DATE(), "DATE"), + (VARCHAR(length=255), "VARCHAR(255 CHAR)"), + (VARCHAR(length=255, collation="utf8"), "VARCHAR(255 CHAR)"), + (NVARCHAR(length=128), "NVARCHAR2(128)"), + ], +) +def test_column_datatype_to_string( + sqla_type: types.TypeEngine, expected_result: str +) -> None: + from superset.db_engine_specs.oracle import OracleEngineSpec + + assert ( + OracleEngineSpec.column_datatype_to_string(sqla_type, oracle.dialect()) + == expected_result + ) + + +def test_fetch_data_no_description() -> None: + from superset.db_engine_specs.oracle import OracleEngineSpec + + cursor = mock.MagicMock() + cursor.description = [] + assert OracleEngineSpec.fetch_data(cursor) == [] + + +def test_fetch_data() -> None: + from superset.db_engine_specs.oracle import OracleEngineSpec + + cursor = mock.MagicMock() + result = ["a", "b"] + cursor.fetchall.return_value = result + assert OracleEngineSpec.fetch_data(cursor) == result + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "TO_DATE('2019-01-02', 'YYYY-MM-DD')"), + ("DateTime", """TO_DATE('2019-01-02T03:04:05', 'YYYY-MM-DD"T"HH24:MI:SS')"""), + ( + "TimeStamp", + """TO_TIMESTAMP('2019-01-02T03:04:05.678900', 'YYYY-MM-DD"T"HH24:MI:SS.ff6')""", + ), + ("Other", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.oracle import OracleEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_postgres.py b/tests/unit_tests/db_engine_specs/test_postgres.py new file mode 100644 index 0000000000000..088ce2747834d --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_postgres.py @@ -0,0 +1,91 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from datetime import datetime +from typing import Any, Dict, Optional, Type + +import pytest +from sqlalchemy import types +from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION, ENUM, JSON + +from superset.utils.core import GenericDataType +from tests.unit_tests.db_engine_specs.utils import ( + assert_column_spec, + assert_convert_dttm, +) +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "TO_DATE('2019-01-02', 'YYYY-MM-DD')"), + ( + "DateTime", + "TO_TIMESTAMP('2019-01-02 03:04:05.678900', 'YYYY-MM-DD HH24:MI:SS.US')", + ), + ( + "TimeStamp", + "TO_TIMESTAMP('2019-01-02 03:04:05.678900', 'YYYY-MM-DD HH24:MI:SS.US')", + ), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.postgres import PostgresEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) + + +@pytest.mark.parametrize( + "native_type,sqla_type,attrs,generic_type,is_dttm", + [ + ("SMALLINT", types.SmallInteger, None, GenericDataType.NUMERIC, False), + ("INTEGER", types.Integer, None, GenericDataType.NUMERIC, False), + ("BIGINT", types.BigInteger, None, GenericDataType.NUMERIC, False), + ("DECIMAL", types.Numeric, None, GenericDataType.NUMERIC, False), + ("NUMERIC", types.Numeric, None, GenericDataType.NUMERIC, False), + ("REAL", types.REAL, None, GenericDataType.NUMERIC, False), + ("DOUBLE PRECISION", DOUBLE_PRECISION, None, GenericDataType.NUMERIC, False), + ("MONEY", types.Numeric, None, GenericDataType.NUMERIC, False), + # String + ("CHAR", types.String, None, GenericDataType.STRING, False), + ("VARCHAR", types.String, None, GenericDataType.STRING, False), + ("TEXT", types.String, None, GenericDataType.STRING, False), + ("ARRAY", types.String, None, GenericDataType.STRING, False), + ("ENUM", ENUM, None, GenericDataType.STRING, False), + ("JSON", JSON, None, GenericDataType.STRING, False), + # Temporal + ("DATE", types.Date, None, GenericDataType.TEMPORAL, True), + ("TIMESTAMP", types.TIMESTAMP, None, GenericDataType.TEMPORAL, True), + ("TIME", types.Time, None, GenericDataType.TEMPORAL, True), + # Boolean + ("BOOLEAN", types.Boolean, None, GenericDataType.BOOLEAN, False), + ], +) +def test_get_column_spec( + native_type: str, + sqla_type: Type[types.TypeEngine], + attrs: Optional[Dict[str, Any]], + generic_type: GenericDataType, + is_dttm: bool, +) -> None: + from superset.db_engine_specs.postgres import PostgresEngineSpec as spec + + assert_column_spec(spec, native_type, sqla_type, attrs, generic_type, is_dttm) diff --git a/tests/unit_tests/db_engine_specs/test_presto.py b/tests/unit_tests/db_engine_specs/test_presto.py index 228427c9caa76..fbae251fdc639 100644 --- a/tests/unit_tests/db_engine_specs/test_presto.py +++ b/tests/unit_tests/db_engine_specs/test_presto.py @@ -15,15 +15,21 @@ # specific language governing permissions and limitations # under the License. from datetime import datetime -from typing import Optional +from typing import Any, Dict, Optional, Type import pytest import pytz -from flask.ctx import AppContext +from sqlalchemy import types + +from superset.utils.core import GenericDataType +from tests.unit_tests.db_engine_specs.utils import ( + assert_column_spec, + assert_convert_dttm, +) @pytest.mark.parametrize( - "target_type,dttm,result", + "target_type,dttm,expected_result", [ ("VARCHAR", datetime(2022, 1, 1), None), ("DATE", datetime(2022, 1, 1), "DATE '2022-01-01'"), @@ -45,12 +51,34 @@ ], ) def test_convert_dttm( - app_context: AppContext, target_type: str, dttm: datetime, - result: Optional[str], + expected_result: Optional[str], +) -> None: + from superset.db_engine_specs.presto import PrestoEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) + + +@pytest.mark.parametrize( + "native_type,sqla_type,attrs,generic_type,is_dttm", + [ + ("varchar(255)", types.VARCHAR, {"length": 255}, GenericDataType.STRING, False), + ("varchar", types.String, None, GenericDataType.STRING, False), + ("char(255)", types.CHAR, {"length": 255}, GenericDataType.STRING, False), + ("char", types.String, None, GenericDataType.STRING, False), + ("integer", types.Integer, None, GenericDataType.NUMERIC, False), + ("time", types.Time, None, GenericDataType.TEMPORAL, True), + ("timestamp", types.TIMESTAMP, None, GenericDataType.TEMPORAL, True), + ], +) +def test_get_column_spec( + native_type: str, + sqla_type: Type[types.TypeEngine], + attrs: Optional[Dict[str, Any]], + generic_type: GenericDataType, + is_dttm: bool, ) -> None: - from superset.db_engine_specs.presto import PrestoEngineSpec + from superset.db_engine_specs.presto import PrestoEngineSpec as spec - for case in (str.lower, str.upper): - assert PrestoEngineSpec.convert_dttm(case(target_type), dttm) == result + assert_column_spec(spec, native_type, sqla_type, attrs, generic_type, is_dttm) diff --git a/tests/unit_tests/db_engine_specs/test_rockset.py b/tests/unit_tests/db_engine_specs/test_rockset.py new file mode 100644 index 0000000000000..c501dccf2e398 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_rockset.py @@ -0,0 +1,41 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from datetime import datetime +from typing import Optional + +import pytest + +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm +from tests.unit_tests.fixtures.common import dttm + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Date", "DATE '2019-01-02'"), + ("DateTime", "DATETIME '2019-01-02 03:04:05.678900'"), + ("Timestamp", "TIMESTAMP '2019-01-02T03:04:05.678900'"), + ("UnknownType", None), + ], +) +def test_convert_dttm( + target_type: str, expected_result: Optional[str], dttm: datetime +) -> None: + from superset.db_engine_specs.rockset import RocksetEngineSpec as spec + + assert_convert_dttm(spec, target_type, expected_result, dttm) diff --git a/tests/unit_tests/db_engine_specs/test_snowflake.py b/tests/unit_tests/db_engine_specs/test_snowflake.py index 961b92f626147..9689428d25653 100644 --- a/tests/unit_tests/db_engine_specs/test_snowflake.py +++ b/tests/unit_tests/db_engine_specs/test_snowflake.py @@ -14,34 +14,51 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. + +# pylint: disable=import-outside-toplevel + import json from datetime import datetime +from typing import Optional from unittest import mock import pytest -from flask.ctx import AppContext +from pytest_mock import MockerFixture from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm from tests.unit_tests.fixtures.common import dttm @pytest.mark.parametrize( - "actual,expected", + "target_type,expected_result", [ - ("DATE", "TO_DATE('2019-01-02')"), - ("DATETIME", "CAST('2019-01-02T03:04:05.678900' AS DATETIME)"), - ("TIMESTAMP", "TO_TIMESTAMP('2019-01-02T03:04:05.678900')"), + ("Date", "TO_DATE('2019-01-02')"), + ("DateTime", "CAST('2019-01-02T03:04:05.678900' AS DATETIME)"), + ("TimeStamp", "TO_TIMESTAMP('2019-01-02T03:04:05.678900')"), + ("TIMESTAMP_NTZ", "TO_TIMESTAMP('2019-01-02T03:04:05.678900')"), + ("TIMESTAMP_LTZ", "TO_TIMESTAMP('2019-01-02T03:04:05.678900')"), + ("TIMESTAMP_TZ", "TO_TIMESTAMP('2019-01-02T03:04:05.678900')"), + ("TIMESTAMPLTZ", "TO_TIMESTAMP('2019-01-02T03:04:05.678900')"), + ("TIMESTAMPNTZ", "TO_TIMESTAMP('2019-01-02T03:04:05.678900')"), + ("TIMESTAMPTZ", "TO_TIMESTAMP('2019-01-02T03:04:05.678900')"), + ( + "TIMESTAMP WITH LOCAL TIME ZONE", + "TO_TIMESTAMP('2019-01-02T03:04:05.678900')", + ), + ("TIMESTAMP WITHOUT TIME ZONE", "TO_TIMESTAMP('2019-01-02T03:04:05.678900')"), + ("UnknownType", None), ], ) def test_convert_dttm( - app_context: AppContext, actual: str, expected: str, dttm: datetime + target_type: str, expected_result: Optional[str], dttm: datetime ) -> None: - from superset.db_engine_specs.snowflake import SnowflakeEngineSpec + from superset.db_engine_specs.snowflake import SnowflakeEngineSpec as spec - assert SnowflakeEngineSpec.convert_dttm(actual, dttm) == expected + assert_convert_dttm(spec, target_type, expected_result, dttm) -def test_database_connection_test_mutator(app_context: AppContext) -> None: +def test_database_connection_test_mutator() -> None: from superset.db_engine_specs.snowflake import SnowflakeEngineSpec from superset.models.core import Database @@ -54,7 +71,7 @@ def test_database_connection_test_mutator(app_context: AppContext) -> None: } == engine_params -def test_extract_errors(app_context: AppContext) -> None: +def test_extract_errors() -> None: from superset.db_engine_specs.snowflake import SnowflakeEngineSpec msg = "Object dumbBrick does not exist or not authorized." @@ -76,11 +93,11 @@ def test_extract_errors(app_context: AppContext) -> None: ) ] - msg = "syntax error line 1 at position 10 unexpected 'limmmited'." + msg = "syntax error line 1 at position 10 unexpected 'limited'." result = SnowflakeEngineSpec.extract_errors(Exception(msg)) assert result == [ SupersetError( - message='Please check your query for syntax errors at or near "limmmited". Then, try running your query again.', + message='Please check your query for syntax errors at or near "limited". Then, try running your query again.', error_type=SupersetErrorType.SYNTAX_ERROR, level=ErrorLevel.ERROR, extra={ @@ -125,3 +142,30 @@ def test_cancel_query_failed(engine_mock: mock.Mock) -> None: query = Query() cursor_mock = engine_mock.raiseError.side_effect = Exception() assert SnowflakeEngineSpec.cancel_query(cursor_mock, query, "123") is False + + +def test_get_extra_params(mocker: MockerFixture) -> None: + """ + Test the ``get_extra_params`` method. + """ + from superset.db_engine_specs.snowflake import SnowflakeEngineSpec + + database = mocker.MagicMock() + + database.extra = {} + assert SnowflakeEngineSpec.get_extra_params(database) == { + "engine_params": {"connect_args": {"application": "Apache Superset"}} + } + + database.extra = json.dumps( + { + "engine_params": { + "connect_args": {"application": "Custom user agent", "foo": "bar"} + } + } + ) + assert SnowflakeEngineSpec.get_extra_params(database) == { + "engine_params": { + "connect_args": {"application": "Custom user agent", "foo": "bar"} + } + } diff --git a/tests/unit_tests/db_engine_specs/test_sqlite.py b/tests/unit_tests/db_engine_specs/test_sqlite.py index 1ce574abe39c4..11ce174c0f4ed 100644 --- a/tests/unit_tests/db_engine_specs/test_sqlite.py +++ b/tests/unit_tests/db_engine_specs/test_sqlite.py @@ -16,80 +16,32 @@ # under the License. # pylint: disable=invalid-name, unused-argument, import-outside-toplevel, redefined-outer-name from datetime import datetime -from unittest import mock +from typing import Optional import pytest -from flask.ctx import AppContext from sqlalchemy.engine import create_engine +from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm from tests.unit_tests.fixtures.common import dttm -def test_convert_dttm(app_context: AppContext, dttm: datetime) -> None: - from superset.db_engine_specs.sqlite import SqliteEngineSpec - - assert SqliteEngineSpec.convert_dttm("TEXT", dttm) == "'2019-01-02 03:04:05.678900'" - - -def test_convert_dttm_lower(app_context: AppContext, dttm: datetime) -> None: - from superset.db_engine_specs.sqlite import SqliteEngineSpec - - assert SqliteEngineSpec.convert_dttm("text", dttm) == "'2019-01-02 03:04:05.678900'" - - -def test_convert_dttm_invalid_type(app_context: AppContext, dttm: datetime) -> None: - from superset.db_engine_specs.sqlite import SqliteEngineSpec - - assert SqliteEngineSpec.convert_dttm("other", dttm) is None - - -def test_get_all_datasource_names_table(app_context: AppContext) -> None: - from superset.db_engine_specs.sqlite import SqliteEngineSpec - - database = mock.MagicMock() - database.get_all_schema_names.return_value = ["schema1"] - table_names = [("table1", "schema1"), ("table2", "schema1")] - get_tables = mock.MagicMock(return_value=table_names) - database.get_all_table_names_in_schema = get_tables - result = SqliteEngineSpec.get_all_datasource_names(database, "table") - - assert result == table_names - get_tables.assert_called_once_with( - schema="schema1", - force=True, - cache=database.table_cache_enabled, - cache_timeout=database.table_cache_timeout, - ) - - -def test_get_all_datasource_names_view(app_context: AppContext) -> None: - from superset.db_engine_specs.sqlite import SqliteEngineSpec - - database = mock.MagicMock() - database.get_all_schema_names.return_value = ["schema1"] - views_names = [("view1", "schema1"), ("view2", "schema1")] - get_views = mock.MagicMock(return_value=views_names) - database.get_all_view_names_in_schema = get_views - result = SqliteEngineSpec.get_all_datasource_names(database, "view") - - assert result == views_names - get_views.assert_called_once_with( - schema="schema1", - force=True, - cache=database.table_cache_enabled, - cache_timeout=database.table_cache_timeout, - ) - - -def test_get_all_datasource_names_invalid_type(app_context: AppContext) -> None: - from superset.db_engine_specs.sqlite import SqliteEngineSpec - - database = mock.MagicMock() - database.get_all_schema_names.return_value = ["schema1"] - invalid_type = "asdf" +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("Text", "'2019-01-02 03:04:05'"), + ("DateTime", "'2019-01-02 03:04:05'"), + ("TimeStamp", "'2019-01-02 03:04:05'"), + ("Other", None), + ], +) +def test_convert_dttm( + target_type: str, + expected_result: Optional[str], + dttm: datetime, +) -> None: + from superset.db_engine_specs.sqlite import SqliteEngineSpec as spec - with pytest.raises(Exception): - SqliteEngineSpec.get_all_datasource_names(database, invalid_type) + assert_convert_dttm(spec, target_type, expected_result, dttm) @pytest.mark.parametrize( @@ -132,9 +84,7 @@ def test_get_all_datasource_names_invalid_type(app_context: AppContext) -> None: ("2022-12-04T05:06:07.89Z", "P3M", "2022-10-01 00:00:00"), ], ) -def test_time_grain_expressions( - dttm: str, grain: str, expected: str, app_context: AppContext -) -> None: +def test_time_grain_expressions(dttm: str, grain: str, expected: str) -> None: from superset.db_engine_specs.sqlite import SqliteEngineSpec engine = create_engine("sqlite://") diff --git a/tests/unit_tests/db_engine_specs/test_teradata.py b/tests/unit_tests/db_engine_specs/test_teradata.py index 5887a9317c7f0..eab03e040d566 100644 --- a/tests/unit_tests/db_engine_specs/test_teradata.py +++ b/tests/unit_tests/db_engine_specs/test_teradata.py @@ -16,7 +16,6 @@ # under the License. # pylint: disable=unused-argument, import-outside-toplevel, protected-access import pytest -from flask.ctx import AppContext @pytest.mark.parametrize( @@ -32,7 +31,6 @@ ], ) def test_apply_top_to_sql_limit( - app_context: AppContext, limit: int, original: str, expected: str, diff --git a/tests/unit_tests/db_engine_specs/test_trino.py b/tests/unit_tests/db_engine_specs/test_trino.py index 9962a0f66d0dc..0ea296a075e71 100644 --- a/tests/unit_tests/db_engine_specs/test_trino.py +++ b/tests/unit_tests/db_engine_specs/test_trino.py @@ -14,43 +14,355 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +# pylint: disable=unused-argument, import-outside-toplevel, protected-access +import json from datetime import datetime -from typing import Optional +from typing import Any, Dict, Optional, Type +from unittest.mock import Mock, patch +import pandas as pd import pytest -import pytz -from flask.ctx import AppContext +from pytest_mock import MockerFixture +from sqlalchemy import types + +import superset.config +from superset.constants import QUERY_CANCEL_KEY, QUERY_EARLY_CANCEL_KEY, USER_AGENT +from superset.utils.core import GenericDataType +from tests.unit_tests.db_engine_specs.utils import ( + assert_column_spec, + assert_convert_dttm, +) +from tests.unit_tests.fixtures.common import dttm @pytest.mark.parametrize( - "target_type,dttm,result", + "extra,expected", [ - ("VARCHAR", datetime(2022, 1, 1), None), - ("DATE", datetime(2022, 1, 1), "from_iso8601_date('2022-01-01')"), + ({}, {"engine_params": {"connect_args": {"source": USER_AGENT}}}), ( - "TIMESTAMP", - datetime(2022, 1, 1, 1, 23, 45, 600000), - "from_iso8601_timestamp('2022-01-01T01:23:45.600000')", + { + "first": 1, + "engine_params": { + "second": "two", + "connect_args": {"source": "foobar", "third": "three"}, + }, + }, + { + "first": 1, + "engine_params": { + "second": "two", + "connect_args": {"source": "foobar", "third": "three"}, + }, + }, ), + ], +) +def test_get_extra_params(extra: Dict[str, Any], expected: Dict[str, Any]) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + + database = Mock() + + database.extra = json.dumps(extra) + database.server_cert = None + assert TrinoEngineSpec.get_extra_params(database) == expected + + +@patch("superset.utils.core.create_ssl_cert_file") +def test_get_extra_params_with_server_cert(mock_create_ssl_cert_file: Mock) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + + database = Mock() + + database.extra = json.dumps({}) + database.server_cert = "TEST_CERT" + mock_create_ssl_cert_file.return_value = "/path/to/tls.crt" + extra = TrinoEngineSpec.get_extra_params(database) + + connect_args = extra.get("engine_params", {}).get("connect_args", {}) + assert connect_args.get("http_scheme") == "https" + assert connect_args.get("verify") == "/path/to/tls.crt" + mock_create_ssl_cert_file.assert_called_once_with(database.server_cert) + + +@patch("trino.auth.BasicAuthentication") +def test_auth_basic(mock_auth: Mock) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + + database = Mock() + + auth_params = {"username": "username", "password": "password"} + database.encrypted_extra = json.dumps( + {"auth_method": "basic", "auth_params": auth_params} + ) + + params: Dict[str, Any] = {} + TrinoEngineSpec.update_params_from_encrypted_extra(database, params) + connect_args = params.setdefault("connect_args", {}) + assert connect_args.get("http_scheme") == "https" + mock_auth.assert_called_once_with(**auth_params) + + +@patch("trino.auth.KerberosAuthentication") +def test_auth_kerberos(mock_auth: Mock) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + + database = Mock() + + auth_params = { + "service_name": "superset", + "mutual_authentication": False, + "delegate": True, + } + database.encrypted_extra = json.dumps( + {"auth_method": "kerberos", "auth_params": auth_params} + ) + + params: Dict[str, Any] = {} + TrinoEngineSpec.update_params_from_encrypted_extra(database, params) + connect_args = params.setdefault("connect_args", {}) + assert connect_args.get("http_scheme") == "https" + mock_auth.assert_called_once_with(**auth_params) + + +@patch("trino.auth.CertificateAuthentication") +def test_auth_certificate(mock_auth: Mock) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + + database = Mock() + auth_params = {"cert": "/path/to/cert.pem", "key": "/path/to/key.pem"} + database.encrypted_extra = json.dumps( + {"auth_method": "certificate", "auth_params": auth_params} + ) + + params: Dict[str, Any] = {} + TrinoEngineSpec.update_params_from_encrypted_extra(database, params) + connect_args = params.setdefault("connect_args", {}) + assert connect_args.get("http_scheme") == "https" + mock_auth.assert_called_once_with(**auth_params) + + +@patch("trino.auth.JWTAuthentication") +def test_auth_jwt(mock_auth: Mock) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + + database = Mock() + + auth_params = {"token": "jwt-token-string"} + database.encrypted_extra = json.dumps( + {"auth_method": "jwt", "auth_params": auth_params} + ) + + params: Dict[str, Any] = {} + TrinoEngineSpec.update_params_from_encrypted_extra(database, params) + connect_args = params.setdefault("connect_args", {}) + assert connect_args.get("http_scheme") == "https" + mock_auth.assert_called_once_with(**auth_params) + + +def test_auth_custom_auth() -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + + database = Mock() + auth_class = Mock() + + auth_method = "custom_auth" + auth_params = {"params1": "params1", "params2": "params2"} + database.encrypted_extra = json.dumps( + {"auth_method": auth_method, "auth_params": auth_params} + ) + + with patch.dict( + "superset.config.ALLOWED_EXTRA_AUTHENTICATIONS", + {"trino": {"custom_auth": auth_class}}, + clear=True, + ): + params: Dict[str, Any] = {} + TrinoEngineSpec.update_params_from_encrypted_extra(database, params) + + connect_args = params.setdefault("connect_args", {}) + assert connect_args.get("http_scheme") == "https" + + auth_class.assert_called_once_with(**auth_params) + + +def test_auth_custom_auth_denied() -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + + database = Mock() + auth_method = "my.module:TrinoAuthClass" + auth_params = {"params1": "params1", "params2": "params2"} + database.encrypted_extra = json.dumps( + {"auth_method": auth_method, "auth_params": auth_params} + ) + + superset.config.ALLOWED_EXTRA_AUTHENTICATIONS = {} + + with pytest.raises(ValueError) as excinfo: + TrinoEngineSpec.update_params_from_encrypted_extra(database, {}) + + assert str(excinfo.value) == ( + f"For security reason, custom authentication '{auth_method}' " + f"must be listed in 'ALLOWED_EXTRA_AUTHENTICATIONS' config" + ) + + +@pytest.mark.parametrize( + "native_type,sqla_type,attrs,generic_type,is_dttm", + [ + ("BOOLEAN", types.Boolean, None, GenericDataType.BOOLEAN, False), + ("TINYINT", types.Integer, None, GenericDataType.NUMERIC, False), + ("SMALLINT", types.SmallInteger, None, GenericDataType.NUMERIC, False), + ("INTEGER", types.Integer, None, GenericDataType.NUMERIC, False), + ("BIGINT", types.BigInteger, None, GenericDataType.NUMERIC, False), + ("REAL", types.FLOAT, None, GenericDataType.NUMERIC, False), + ("DOUBLE", types.FLOAT, None, GenericDataType.NUMERIC, False), + ("DECIMAL", types.DECIMAL, None, GenericDataType.NUMERIC, False), + ("VARCHAR", types.String, None, GenericDataType.STRING, False), + ("VARCHAR(20)", types.VARCHAR, {"length": 20}, GenericDataType.STRING, False), + ("CHAR", types.String, None, GenericDataType.STRING, False), + ("CHAR(2)", types.CHAR, {"length": 2}, GenericDataType.STRING, False), + ("JSON", types.JSON, None, GenericDataType.STRING, False), + ("TIMESTAMP", types.TIMESTAMP, None, GenericDataType.TEMPORAL, True), + ("TIMESTAMP(3)", types.TIMESTAMP, None, GenericDataType.TEMPORAL, True), ( "TIMESTAMP WITH TIME ZONE", - datetime(2022, 1, 1, 1, 23, 45, 600000), - "from_iso8601_timestamp('2022-01-01T01:23:45.600000')", + types.TIMESTAMP, + None, + GenericDataType.TEMPORAL, + True, ), ( - "TIMESTAMP WITH TIME ZONE", - datetime(2022, 1, 1, 1, 23, 45, 600000, tzinfo=pytz.UTC), - "from_iso8601_timestamp('2022-01-01T01:23:45.600000+00:00')", + "TIMESTAMP(3) WITH TIME ZONE", + types.TIMESTAMP, + None, + GenericDataType.TEMPORAL, + True, ), + ("DATE", types.Date, None, GenericDataType.TEMPORAL, True), + ], +) +def test_get_column_spec( + native_type: str, + sqla_type: Type[types.TypeEngine], + attrs: Optional[Dict[str, Any]], + generic_type: GenericDataType, + is_dttm: bool, +) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec as spec + + assert_column_spec( + spec, + native_type, + sqla_type, + attrs, + generic_type, + is_dttm, + ) + + +@pytest.mark.parametrize( + "target_type,expected_result", + [ + ("TimeStamp", "TIMESTAMP '2019-01-02 03:04:05.678900'"), + ("TimeStamp(3)", "TIMESTAMP '2019-01-02 03:04:05.678900'"), + ("TimeStamp With Time Zone", "TIMESTAMP '2019-01-02 03:04:05.678900'"), + ("TimeStamp(3) With Time Zone", "TIMESTAMP '2019-01-02 03:04:05.678900'"), + ("Date", "DATE '2019-01-02'"), + ("Other", None), ], ) def test_convert_dttm( - app_context: AppContext, target_type: str, + expected_result: Optional[str], dttm: datetime, - result: Optional[str], ) -> None: from superset.db_engine_specs.trino import TrinoEngineSpec - for case in (str.lower, str.upper): - assert TrinoEngineSpec.convert_dttm(case(target_type), dttm) == result + assert_convert_dttm(TrinoEngineSpec, target_type, expected_result, dttm) + + +def test_extra_table_metadata() -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + + db_mock = Mock() + db_mock.get_indexes = Mock( + return_value=[{"column_names": ["ds", "hour"], "name": "partition"}] + ) + db_mock.get_extra = Mock(return_value={}) + db_mock.has_view_by_name = Mock(return_value=None) + db_mock.get_df = Mock(return_value=pd.DataFrame({"ds": ["01-01-19"], "hour": [1]})) + result = TrinoEngineSpec.extra_table_metadata(db_mock, "test_table", "test_schema") + assert result["partitions"]["cols"] == ["ds", "hour"] + assert result["partitions"]["latest"] == {"ds": "01-01-19", "hour": 1} + + +@patch("sqlalchemy.engine.Engine.connect") +def test_cancel_query_success(engine_mock: Mock) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + from superset.models.sql_lab import Query + + query = Query() + cursor_mock = engine_mock.return_value.__enter__.return_value + assert TrinoEngineSpec.cancel_query(cursor_mock, query, "123") is True + + +@patch("sqlalchemy.engine.Engine.connect") +def test_cancel_query_failed(engine_mock: Mock) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + from superset.models.sql_lab import Query + + query = Query() + cursor_mock = engine_mock.raiseError.side_effect = Exception() + assert TrinoEngineSpec.cancel_query(cursor_mock, query, "123") is False + + +@pytest.mark.parametrize( + "initial_extra,final_extra", + [ + ({}, {QUERY_EARLY_CANCEL_KEY: True}), + ({QUERY_CANCEL_KEY: "my_key"}, {QUERY_CANCEL_KEY: "my_key"}), + ], +) +def test_prepare_cancel_query( + initial_extra: Dict[str, Any], + final_extra: Dict[str, Any], + mocker: MockerFixture, +) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + from superset.models.sql_lab import Query + + session_mock = mocker.MagicMock() + query = Query(extra_json=json.dumps(initial_extra)) + TrinoEngineSpec.prepare_cancel_query(query=query, session=session_mock) + assert query.extra == final_extra + + +@pytest.mark.parametrize("cancel_early", [True, False]) +@patch("superset.db_engine_specs.trino.TrinoEngineSpec.cancel_query") +@patch("sqlalchemy.engine.Engine.connect") +def test_handle_cursor_early_cancel( + engine_mock: Mock, + cancel_query_mock: Mock, + cancel_early: bool, + mocker: MockerFixture, +) -> None: + from superset.db_engine_specs.trino import TrinoEngineSpec + from superset.models.sql_lab import Query + + query_id = "myQueryId" + + cursor_mock = engine_mock.return_value.__enter__.return_value + cursor_mock.stats = {"queryId": query_id} + session_mock = mocker.MagicMock() + + query = Query() + + if cancel_early: + TrinoEngineSpec.prepare_cancel_query(query=query, session=session_mock) + + TrinoEngineSpec.handle_cursor(cursor=cursor_mock, query=query, session=session_mock) + + if cancel_early: + assert cancel_query_mock.call_args[1]["cancel_query_id"] == query_id + else: + assert cancel_query_mock.call_args is None diff --git a/tests/unit_tests/db_engine_specs/utils.py b/tests/unit_tests/db_engine_specs/utils.py new file mode 100644 index 0000000000000..13ae7a34d2931 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/utils.py @@ -0,0 +1,67 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +from datetime import datetime +from typing import Any, Dict, Optional, Type, TYPE_CHECKING + +from sqlalchemy import types + +from superset.utils.core import GenericDataType + +if TYPE_CHECKING: + from superset.db_engine_specs.base import BaseEngineSpec + + +def assert_convert_dttm( + db_engine_spec: Type[BaseEngineSpec], + target_type: str, + expected_result: Optional[str], + dttm: datetime, + db_extra: Optional[Dict[str, Any]] = None, +) -> None: + for target in ( + target_type, + target_type.upper(), + target_type.lower(), + target_type.capitalize(), + ): + assert ( + result := db_engine_spec.convert_dttm( + target_type=target, + dttm=dttm, + db_extra=db_extra, + ) + ) == expected_result, result + + +def assert_column_spec( + db_engine_spec: Type[BaseEngineSpec], + native_type: str, + sqla_type: Type[types.TypeEngine], + attrs: Optional[Dict[str, Any]], + generic_type: GenericDataType, + is_dttm: bool, +) -> None: + assert (column_spec := db_engine_spec.get_column_spec(native_type)) is not None + assert isinstance(column_spec.sqla_type, sqla_type) + + for key, value in (attrs or {}).items(): + assert getattr(column_spec.sqla_type, key) == value + + assert column_spec.generic_type == generic_type + assert column_spec.is_dttm == is_dttm diff --git a/tests/unit_tests/explore/api_test.py b/tests/unit_tests/explore/api_test.py new file mode 100644 index 0000000000000..147790844dcdc --- /dev/null +++ b/tests/unit_tests/explore/api_test.py @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from typing import Any + +import pytest + + +def test_explore_datasource_not_found(client: Any, full_api_access: None) -> None: + # validating the payload for a dataset that doesn't exist + # user should be expecting missing_datasource view + response = client.get( + "/api/v1/explore/?datasource_id=50000&datasource_type=table", + ) + response.json["result"]["dataset"]["name"] == "[Missing Dataset]" + assert response.status_code == 200 diff --git a/tests/unit_tests/explore/utils_test.py b/tests/unit_tests/explore/utils_test.py index b902e9cd040ad..41441254191c2 100644 --- a/tests/unit_tests/explore/utils_test.py +++ b/tests/unit_tests/explore/utils_test.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from flask.ctx import AppContext from flask_appbuilder.security.sqla.models import User from pytest import raises from pytest_mock import MockFixture @@ -28,7 +27,7 @@ DatasetNotFoundError, ) from superset.exceptions import SupersetSecurityException -from superset.utils.core import DatasourceType +from superset.utils.core import DatasourceType, override_user dataset_find_by_id = "superset.datasets.dao.DatasetDAO.find_by_id" query_find_by_id = "superset.queries.dao.QueryDAO.find_by_id" @@ -44,49 +43,79 @@ "superset.connectors.sqla.models.SqlaTable.query_datasources_by_name" ) -def test_unsaved_chart_no_dataset_id(app_context: AppContext) -> None: - from superset.explore.utils import check_access - with raises(DatasetNotFoundError): - check_access(dataset_id=0, chart_id=0, actor=User()) +def test_unsaved_chart_no_dataset_id() -> None: + from superset.explore.utils import check_access as check_chart_access + with raises(DatasourceNotFoundValidationError): + with override_user(User()): + check_chart_access( + datasource_id=0, + chart_id=0, + datasource_type=DatasourceType.TABLE, + ) -def test_unsaved_chart_unknown_dataset_id( - mocker: MockFixture, app_context: AppContext -) -> None: - from superset.explore.utils import check_access + +def test_unsaved_chart_unknown_dataset_id(mocker: MockFixture) -> None: + from superset.explore.utils import check_access as check_chart_access with raises(DatasetNotFoundError): mocker.patch(dataset_find_by_id, return_value=None) - check_access(dataset_id=1, chart_id=0, actor=User()) + with override_user(User()): + check_chart_access( + datasource_id=1, + chart_id=0, + datasource_type=DatasourceType.TABLE, + ) + + +def test_unsaved_chart_unknown_query_id(mocker: MockFixture) -> None: + from superset.explore.utils import check_access as check_chart_access + + with raises(QueryNotFoundValidationError): + mocker.patch(query_find_by_id, return_value=None) + + with override_user(User()): + check_chart_access( + datasource_id=1, + chart_id=0, + datasource_type=DatasourceType.QUERY, + ) -def test_unsaved_chart_unauthorized_dataset( - mocker: MockFixture, app_context: AppContext -) -> None: + +def test_unsaved_chart_unauthorized_dataset(mocker: MockFixture) -> None: from superset.connectors.sqla.models import SqlaTable from superset.explore import utils with raises(DatasetAccessDeniedError): mocker.patch(dataset_find_by_id, return_value=SqlaTable()) mocker.patch(can_access_datasource, return_value=False) - utils.check_access(dataset_id=1, chart_id=0, actor=User()) + + with override_user(User()): + check_chart_access( + datasource_id=1, + chart_id=0, + datasource_type=DatasourceType.TABLE, + ) -def test_unsaved_chart_authorized_dataset( - mocker: MockFixture, app_context: AppContext -) -> None: +def test_unsaved_chart_authorized_dataset(mocker: MockFixture) -> None: from superset.connectors.sqla.models import SqlaTable from superset.explore.utils import check_access mocker.patch(dataset_find_by_id, return_value=SqlaTable()) mocker.patch(can_access_datasource, return_value=True) - assert check_access(dataset_id=1, chart_id=0, actor=User()) == True + with override_user(User()): + check_chart_access( + datasource_id=1, + chart_id=0, + datasource_type=DatasourceType.TABLE, + ) -def test_saved_chart_unknown_chart_id( - mocker: MockFixture, app_context: AppContext -) -> None: + +def test_saved_chart_unknown_chart_id(mocker: MockFixture) -> None: from superset.connectors.sqla.models import SqlaTable from superset.explore.utils import check_access @@ -94,22 +123,32 @@ def test_saved_chart_unknown_chart_id( mocker.patch(dataset_find_by_id, return_value=SqlaTable()) mocker.patch(can_access_datasource, return_value=True) mocker.patch(chart_find_by_id, return_value=None) - check_access(dataset_id=1, chart_id=1, actor=User()) + + with override_user(User()): + check_chart_access( + datasource_id=1, + chart_id=1, + datasource_type=DatasourceType.TABLE, + ) -def test_saved_chart_unauthorized_dataset( - mocker: MockFixture, app_context: AppContext -) -> None: +def test_saved_chart_unauthorized_dataset(mocker: MockFixture) -> None: from superset.connectors.sqla.models import SqlaTable from superset.explore import utils with raises(DatasetAccessDeniedError): mocker.patch(dataset_find_by_id, return_value=SqlaTable()) mocker.patch(can_access_datasource, return_value=False) - utils.check_access(dataset_id=1, chart_id=1, actor=User()) + + with override_user(User()): + check_chart_access( + datasource_id=1, + chart_id=1, + datasource_type=DatasourceType.TABLE, + ) -def test_saved_chart_is_admin(mocker: MockFixture, app_context: AppContext) -> None: +def test_saved_chart_is_admin(mocker: MockFixture) -> None: from superset.connectors.sqla.models import SqlaTable from superset.explore.utils import check_access from superset.models.slice import Slice @@ -118,10 +157,16 @@ def test_saved_chart_is_admin(mocker: MockFixture, app_context: AppContext) -> N mocker.patch(can_access_datasource, return_value=True) mocker.patch(is_admin, return_value=True) mocker.patch(chart_find_by_id, return_value=Slice()) - assert check_access(dataset_id=1, chart_id=1, actor=User()) is True + + with override_user(User()): + check_chart_access( + datasource_id=1, + chart_id=1, + datasource_type=DatasourceType.TABLE, + ) -def test_saved_chart_is_owner(mocker: MockFixture, app_context: AppContext) -> None: +def test_saved_chart_is_owner(mocker: MockFixture) -> None: from superset.connectors.sqla.models import SqlaTable from superset.explore.utils import check_access from superset.models.slice import Slice @@ -131,10 +176,16 @@ def test_saved_chart_is_owner(mocker: MockFixture, app_context: AppContext) -> N mocker.patch(is_admin, return_value=False) mocker.patch(is_owner, return_value=True) mocker.patch(chart_find_by_id, return_value=Slice()) - assert check_access(dataset_id=1, chart_id=1, actor=User()) == True + with override_user(User()): + check_chart_access( + datasource_id=1, + chart_id=1, + datasource_type=DatasourceType.TABLE, + ) -def test_saved_chart_has_access(mocker: MockFixture, app_context: AppContext) -> None: + +def test_saved_chart_has_access(mocker: MockFixture) -> None: from superset.connectors.sqla.models import SqlaTable from superset.explore.utils import check_access from superset.models.slice import Slice @@ -145,10 +196,16 @@ def test_saved_chart_has_access(mocker: MockFixture, app_context: AppContext) -> mocker.patch(is_owner, return_value=False) mocker.patch(can_access, return_value=True) mocker.patch(chart_find_by_id, return_value=Slice()) - assert check_access(dataset_id=1, chart_id=1, actor=User()) == True + + with override_user(User()): + check_chart_access( + datasource_id=1, + chart_id=1, + datasource_type=DatasourceType.TABLE, + ) -def test_saved_chart_no_access(mocker: MockFixture, app_context: AppContext) -> None: +def test_saved_chart_no_access(mocker: MockFixture) -> None: from superset.connectors.sqla.models import SqlaTable from superset.explore.utils import check_access as check_chart_access from superset.models.slice import Slice @@ -160,15 +217,16 @@ def test_saved_chart_no_access(mocker: MockFixture, app_context: AppContext) -> mocker.patch(is_owner, return_value=False) mocker.patch(can_access, return_value=False) mocker.patch(chart_find_by_id, return_value=Slice()) - check_chart_access( - datasource_id=1, - chart_id=1, - actor=User(), - datasource_type=DatasourceType.TABLE, - ) + + with override_user(User()): + check_chart_access( + datasource_id=1, + chart_id=1, + datasource_type=DatasourceType.TABLE, + ) -def test_dataset_has_access(mocker: MockFixture, app_context: AppContext) -> None: +def test_dataset_has_access(mocker: MockFixture) -> None: from superset.connectors.sqla.models import SqlaTable from superset.explore.utils import check_datasource_access @@ -186,7 +244,7 @@ def test_dataset_has_access(mocker: MockFixture, app_context: AppContext) -> Non ) -def test_query_has_access(mocker: MockFixture, app_context: AppContext) -> None: +def test_query_has_access(mocker: MockFixture) -> None: from superset.explore.utils import check_datasource_access from superset.models.sql_lab import Query @@ -204,7 +262,7 @@ def test_query_has_access(mocker: MockFixture, app_context: AppContext) -> None: ) -def test_query_no_access(mocker: MockFixture, client, app_context: AppContext) -> None: +def test_query_no_access(mocker: MockFixture, client) -> None: from superset.connectors.sqla.models import SqlaTable from superset.explore.utils import check_datasource_access from superset.models.core import Database @@ -215,9 +273,7 @@ def test_query_no_access(mocker: MockFixture, client, app_context: AppContext) - query_find_by_id, return_value=Query(database=Database(), sql="select * from foo"), ) - table = SqlaTable() - table.owners = [] - mocker.patch(query_datasources_by_name, return_value=[table]) + mocker.patch(query_datasources_by_name, return_value=[SqlaTable()]) mocker.patch(is_admin, return_value=False) mocker.patch(is_owner, return_value=False) mocker.patch(can_access, return_value=False) diff --git a/tests/unit_tests/fixtures/__init__.py b/tests/unit_tests/fixtures/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/fixtures/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/fixtures/assets_configs.py b/tests/unit_tests/fixtures/assets_configs.py new file mode 100644 index 0000000000000..6e78d9e562d10 --- /dev/null +++ b/tests/unit_tests/fixtures/assets_configs.py @@ -0,0 +1,260 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from typing import Any, Dict + +databases_config: Dict[str, Any] = { + "databases/examples.yaml": { + "database_name": "examples", + "sqlalchemy_uri": "sqlite:///test.db", + "cache_timeout": None, + "expose_in_sqllab": True, + "allow_run_async": False, + "allow_ctas": False, + "allow_cvas": False, + "extra": {}, + "uuid": "a2dc77af-e654-49bb-b321-40f6b559a1ee", + "version": "1.0.0", + "password": None, + "allow_csv_upload": False, + }, +} +datasets_config: Dict[str, Any] = { + "datasets/examples/video_game_sales.yaml": { + "table_name": "video_game_sales", + "main_dttm_col": None, + "description": None, + "default_endpoint": None, + "offset": 0, + "cache_timeout": None, + "schema": "main", + "sql": "", + "params": {}, + "template_params": None, + "filter_select_enabled": True, + "fetch_values_predicate": None, + "extra": None, + "uuid": "53d47c0c-c03d-47f0-b9ac-81225f808283", + "metrics": [ + { + "metric_name": "count", + "verbose_name": "COUNT(*)", + "metric_type": None, + "expression": "COUNT(*)", + "description": None, + "d3format": None, + "extra": None, + "warning_text": None, + } + ], + "columns": [ + { + "column_name": "genre", + "verbose_name": None, + "is_dttm": False, + "is_active": None, + "type": "STRING", + "advanced_data_type": None, + "groupby": True, + "filterable": True, + "expression": None, + "description": None, + "python_date_format": None, + "extra": None, + }, + ], + "version": "1.0.0", + "database_uuid": "a2dc77af-e654-49bb-b321-40f6b559a1ee", + }, +} +charts_config_1: Dict[str, Any] = { + "charts/Games_per_Genre_over_time_95.yaml": { + "slice_name": "Games per Genre over time", + "viz_type": "line", + "params": {}, + "cache_timeout": None, + "uuid": "0f8976aa-7bb4-40c7-860b-64445a51aaaf", + "version": "1.0.0", + "dataset_uuid": "53d47c0c-c03d-47f0-b9ac-81225f808283", + }, + "charts/Games_per_Genre_131.yaml": { + "slice_name": "Games per Genre", + "viz_type": "treemap", + "params": {}, + "cache_timeout": None, + "uuid": "0499bdec-0837-44f3-ae8a-8c670de81afd", + "version": "1.0.0", + "dataset_uuid": "53d47c0c-c03d-47f0-b9ac-81225f808283", + }, +} +dashboards_config_1: Dict[str, Any] = { + "dashboards/Video_Game_Sales_11.yaml": { + "dashboard_title": "Video Game Sales", + "description": None, + "css": "", + "slug": None, + "uuid": "c7bc10f4-6a2d-7569-caae-bbc91864ee11", + "position": { + "CHART-1L7NIcXvVN": { + "children": [], + "id": "CHART-1L7NIcXvVN", + "meta": { + "chartId": 95, + "height": 79, + "sliceName": "Games per Genre over time", + "uuid": "0f8976aa-7bb4-40c7-860b-64445a51aaaf", + "width": 6, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "ROW-0F99WDC-sz", + ], + "type": "CHART", + }, + "CHART-7mKdnU7OUJ": { + "children": [], + "id": "CHART-7mKdnU7OUJ", + "meta": { + "chartId": 131, + "height": 80, + "sliceName": "Games per Genre", + "uuid": "0499bdec-0837-44f3-ae8a-8c670de81afd", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "ROW-0F99WDC-sz", + ], + "type": "CHART", + }, + "DASHBOARD_VERSION_KEY": "v2", + "GRID_ID": { + "children": ["ROW-0F99WDC-sz"], + "id": "GRID_ID", + "parents": ["ROOT_ID"], + "type": "GRID", + }, + "HEADER_ID": { + "id": "HEADER_ID", + "meta": {"text": "Video Game Sales"}, + "type": "HEADER", + }, + "ROOT_ID": { + "children": ["GRID_ID"], + "id": "ROOT_ID", + "type": "ROOT", + }, + "ROW-0F99WDC-sz": { + "children": ["CHART-1L7NIcXvVN", "CHART-7mKdnU7OUJ"], + "id": "ROW-0F99WDC-sz", + "meta": {"0": "ROOT_ID", "background": "BACKGROUND_TRANSPARENT"}, + "parents": ["ROOT_ID", "GRID_ID"], + "type": "ROW", + }, + }, + "metadata": { + "timed_refresh_immune_slices": [], + "expanded_slices": {}, + "refresh_frequency": 0, + "default_filters": "{}", + "color_scheme": "supersetColors", + "label_colors": {}, + "show_native_filters": True, + "color_scheme_domain": [], + "shared_label_colors": {}, + "cross_filters_enabled": False, + }, + "version": "1.0.0", + }, +} + +charts_config_2: Dict[str, Any] = { + "charts/Games_per_Genre_131.yaml": { + "slice_name": "Games per Genre", + "viz_type": "treemap", + "params": {}, + "cache_timeout": None, + "uuid": "0499bdec-0837-44f3-ae8a-8c670de81afd", + "version": "1.0.0", + "dataset_uuid": "53d47c0c-c03d-47f0-b9ac-81225f808283", + }, +} +dashboards_config_2: Dict[str, Any] = { + "dashboards/Video_Game_Sales_11.yaml": { + "dashboard_title": "Video Game Sales", + "description": None, + "css": "", + "slug": None, + "uuid": "c7bc10f4-6a2d-7569-caae-bbc91864ee11", + "position": { + "CHART-7mKdnU7OUJ": { + "children": [], + "id": "CHART-7mKdnU7OUJ", + "meta": { + "chartId": 131, + "height": 80, + "sliceName": "Games per Genre", + "uuid": "0499bdec-0837-44f3-ae8a-8c670de81afd", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "ROW-0F99WDC-sz", + ], + "type": "CHART", + }, + "DASHBOARD_VERSION_KEY": "v2", + "GRID_ID": { + "children": ["ROW-0F99WDC-sz"], + "id": "GRID_ID", + "parents": ["ROOT_ID"], + "type": "GRID", + }, + "HEADER_ID": { + "id": "HEADER_ID", + "meta": {"text": "Video Game Sales"}, + "type": "HEADER", + }, + "ROOT_ID": { + "children": ["GRID_ID"], + "id": "ROOT_ID", + "type": "ROOT", + }, + "ROW-0F99WDC-sz": { + "children": ["CHART-7mKdnU7OUJ"], + "id": "ROW-0F99WDC-sz", + "meta": {"0": "ROOT_ID", "background": "BACKGROUND_TRANSPARENT"}, + "parents": ["ROOT_ID", "GRID_ID"], + "type": "ROW", + }, + }, + "metadata": { + "timed_refresh_immune_slices": [], + "expanded_slices": {}, + "refresh_frequency": 0, + "default_filters": "{}", + "color_scheme": "supersetColors", + "label_colors": {}, + "show_native_filters": True, + "color_scheme_domain": [], + "shared_label_colors": {}, + }, + "version": "1.0.0", + }, +} diff --git a/tests/unit_tests/importexport/api_test.py b/tests/unit_tests/importexport/api_test.py index 1ef4309fc21b9..a65a682018eda 100644 --- a/tests/unit_tests/importexport/api_test.py +++ b/tests/unit_tests/importexport/api_test.py @@ -28,18 +28,16 @@ from superset import security_manager -def test_export_assets(mocker: MockFixture, client: Any) -> None: +def test_export_assets( + mocker: MockFixture, + client: Any, + full_api_access: None, +) -> None: """ Test exporting assets. """ from superset.commands.importers.v1.utils import get_contents_from_bundle - # grant access - mocker.patch( - "flask_appbuilder.security.decorators.verify_jwt_in_request", return_value=True - ) - mocker.patch.object(security_manager, "has_access", return_value=True) - mocked_contents = [ ( "metadata.yaml", @@ -63,16 +61,14 @@ def test_export_assets(mocker: MockFixture, client: Any) -> None: assert contents == dict(mocked_contents) -def test_import_assets(mocker: MockFixture, client: Any) -> None: +def test_import_assets( + mocker: MockFixture, + client: Any, + full_api_access: None, +) -> None: """ Test importing assets. """ - # grant access - mocker.patch( - "flask_appbuilder.security.decorators.verify_jwt_in_request", return_value=True - ) - mocker.patch.object(security_manager, "has_access", return_value=True) - mocked_contents = { "metadata.yaml": ( "version: 1.0.0\ntype: assets\ntimestamp: '2022-01-01T00:00:00+00:00'\n" @@ -106,16 +102,14 @@ def test_import_assets(mocker: MockFixture, client: Any) -> None: ImportAssetsCommand.assert_called_with(mocked_contents, passwords=passwords) -def test_import_assets_not_zip(mocker: MockFixture, client: Any) -> None: +def test_import_assets_not_zip( + mocker: MockFixture, + client: Any, + full_api_access: None, +) -> None: """ Test error message when the upload is not a ZIP file. """ - # grant access - mocker.patch( - "flask_appbuilder.security.decorators.verify_jwt_in_request", return_value=True - ) - mocker.patch.object(security_manager, "has_access", return_value=True) - buf = BytesIO(b"definitely_not_a_zip_file") form_data = { "bundle": (buf, "broken.txt"), @@ -146,14 +140,14 @@ def test_import_assets_not_zip(mocker: MockFixture, client: Any) -> None: } -def test_import_assets_no_form_data(mocker: MockFixture, client: Any) -> None: +def test_import_assets_no_form_data( + mocker: MockFixture, + client: Any, + full_api_access: None, +) -> None: """ Test error message when the upload has no form data. """ - # grant access - mocker.patch( - "flask_appbuilder.security.decorators.verify_jwt_in_request", return_value=True - ) mocker.patch.object(security_manager, "has_access", return_value=True) response = client.post("/api/v1/assets/import/", data="some_content") @@ -180,16 +174,14 @@ def test_import_assets_no_form_data(mocker: MockFixture, client: Any) -> None: } -def test_import_assets_incorrect_form_data(mocker: MockFixture, client: Any) -> None: +def test_import_assets_incorrect_form_data( + mocker: MockFixture, + client: Any, + full_api_access: None, +) -> None: """ Test error message when the upload form data has the wrong key. """ - # grant access - mocker.patch( - "flask_appbuilder.security.decorators.verify_jwt_in_request", return_value=True - ) - mocker.patch.object(security_manager, "has_access", return_value=True) - buf = BytesIO(b"definitely_not_a_zip_file") form_data = { "wrong": (buf, "broken.txt"), @@ -201,16 +193,14 @@ def test_import_assets_incorrect_form_data(mocker: MockFixture, client: Any) -> assert response.json == {"message": "Arguments are not correct"} -def test_import_assets_no_contents(mocker: MockFixture, client: Any) -> None: +def test_import_assets_no_contents( + mocker: MockFixture, + client: Any, + full_api_access: None, +) -> None: """ Test error message when the ZIP bundle has no contents. """ - # grant access - mocker.patch( - "flask_appbuilder.security.decorators.verify_jwt_in_request", return_value=True - ) - mocker.patch.object(security_manager, "has_access", return_value=True) - mocked_contents = { "README.txt": "Something is wrong", } diff --git a/tests/unit_tests/jinja_context_test.py b/tests/unit_tests/jinja_context_test.py index 75c49f0977bf6..13b3ae9e9c948 100644 --- a/tests/unit_tests/jinja_context_test.py +++ b/tests/unit_tests/jinja_context_test.py @@ -34,7 +34,7 @@ def test_where_in() -> None: assert where_in(["O'Malley's"]) == "('O''Malley''s')" -def test_dataset_macro(mocker: MockFixture, app_context: None) -> None: +def test_dataset_macro(mocker: MockFixture) -> None: """ Test the ``dataset_macro`` macro. """ diff --git a/tests/unit_tests/models/__init__.py b/tests/unit_tests/models/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/models/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/models/core_test.py b/tests/unit_tests/models/core_test.py new file mode 100644 index 0000000000000..5eb60dc6f93ef --- /dev/null +++ b/tests/unit_tests/models/core_test.py @@ -0,0 +1,147 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# pylint: disable=import-outside-toplevel + +from typing import List, Optional + +from pytest_mock import MockFixture +from sqlalchemy.engine.reflection import Inspector + + +def test_get_metrics(mocker: MockFixture) -> None: + """ + Tests for ``get_metrics``. + """ + from superset.db_engine_specs.base import MetricType + from superset.db_engine_specs.sqlite import SqliteEngineSpec + from superset.models.core import Database + + database = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + assert database.get_metrics("table") == [ + { + "expression": "COUNT(*)", + "metric_name": "count", + "metric_type": "count", + "verbose_name": "COUNT(*)", + } + ] + + class CustomSqliteEngineSpec(SqliteEngineSpec): + @classmethod + def get_metrics( + cls, + database: Database, + inspector: Inspector, + table_name: str, + schema: Optional[str], + ) -> List[MetricType]: + return [ + { + "expression": "COUNT(DISTINCT user_id)", + "metric_name": "count_distinct_user_id", + "metric_type": "count_distinct", + "verbose_name": "COUNT(DISTINCT user_id)", + }, + ] + + database.get_db_engine_spec = mocker.MagicMock( # type: ignore + return_value=CustomSqliteEngineSpec + ) + assert database.get_metrics("table") == [ + { + "expression": "COUNT(DISTINCT user_id)", + "metric_name": "count_distinct_user_id", + "metric_type": "count_distinct", + "verbose_name": "COUNT(DISTINCT user_id)", + }, + ] + + +def test_get_db_engine_spec(mocker: MockFixture) -> None: + """ + Tests for ``get_db_engine_spec``. + """ + from superset.db_engine_specs import BaseEngineSpec + from superset.models.core import Database + + # pylint: disable=abstract-method + class PostgresDBEngineSpec(BaseEngineSpec): + """ + A DB engine spec with drivers and a default driver. + """ + + engine = "postgresql" + engine_aliases = {"postgres"} + drivers = { + "psycopg2": "The default Postgres driver", + "asyncpg": "An async Postgres driver", + } + default_driver = "psycopg2" + + # pylint: disable=abstract-method + class OldDBEngineSpec(BaseEngineSpec): + """ + And old DB engine spec without drivers nor a default driver. + """ + + engine = "mysql" + + load_engine_specs = mocker.patch("superset.db_engine_specs.load_engine_specs") + load_engine_specs.return_value = [ + PostgresDBEngineSpec, + OldDBEngineSpec, + ] + + assert ( + Database(database_name="db", sqlalchemy_uri="postgresql://").db_engine_spec + == PostgresDBEngineSpec + ) + assert ( + Database( + database_name="db", sqlalchemy_uri="postgresql+psycopg2://" + ).db_engine_spec + == PostgresDBEngineSpec + ) + assert ( + Database( + database_name="db", sqlalchemy_uri="postgresql+asyncpg://" + ).db_engine_spec + == PostgresDBEngineSpec + ) + assert ( + Database( + database_name="db", sqlalchemy_uri="postgresql+fancynewdriver://" + ).db_engine_spec + == PostgresDBEngineSpec + ) + assert ( + Database(database_name="db", sqlalchemy_uri="mysql://").db_engine_spec + == OldDBEngineSpec + ) + assert ( + Database( + database_name="db", sqlalchemy_uri="mysql+mysqlconnector://" + ).db_engine_spec + == OldDBEngineSpec + ) + assert ( + Database( + database_name="db", sqlalchemy_uri="mysql+fancynewdriver://" + ).db_engine_spec + == OldDBEngineSpec + ) diff --git a/tests/unit_tests/notifications/email_tests.py b/tests/unit_tests/notifications/email_tests.py new file mode 100644 index 0000000000000..4ce34b99cac4d --- /dev/null +++ b/tests/unit_tests/notifications/email_tests.py @@ -0,0 +1,54 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import pandas as pd + + +def test_render_description_with_html() -> None: + # `superset.models.helpers`, a dependency of following imports, + # requires app context + from superset.reports.models import ReportRecipients, ReportRecipientType + from superset.reports.notifications.base import NotificationContent + from superset.reports.notifications.email import EmailNotification + + content = NotificationContent( + name="test alert", + embedded_data=pd.DataFrame( + { + "A": [1, 2, 3], + "B": [4, 5, 6], + "C": ["111", "222", '<a href="http://www.example.com">333</a>'], + } + ), + description='<p>This is <a href="#">a test</a> alert</p><br />', + header_data={ + "notification_format": "PNG", + "notification_type": "Alert", + "owners": [1], + "notification_source": None, + "chart_id": None, + "dashboard_id": None, + }, + ) + email_body = ( + EmailNotification( + recipient=ReportRecipients(type=ReportRecipientType.EMAIL), content=content + ) + ._get_content() + .body + ) + assert '<p>This is <a href="#">a test</a> alert</p><br>' in email_body + assert '<td><a href="http://www.example.com">333</a></td>' in email_body diff --git a/tests/unit_tests/pandas_postprocessing/test_compare.py b/tests/unit_tests/pandas_postprocessing/test_compare.py index 4f742bae16139..9da8a31535470 100644 --- a/tests/unit_tests/pandas_postprocessing/test_compare.py +++ b/tests/unit_tests/pandas_postprocessing/test_compare.py @@ -188,8 +188,6 @@ def test_compare_after_pivot(): "sum_metric": {"operator": "sum"}, "count_metric": {"operator": "sum"}, }, - flatten_columns=False, - reset_index=False, ) """ count_metric sum_metric diff --git a/tests/unit_tests/pandas_postprocessing/test_cum.py b/tests/unit_tests/pandas_postprocessing/test_cum.py index 17cd3c0efc8a4..130e0602520a1 100644 --- a/tests/unit_tests/pandas_postprocessing/test_cum.py +++ b/tests/unit_tests/pandas_postprocessing/test_cum.py @@ -83,8 +83,6 @@ def test_cum_after_pivot_with_single_metric(): index=["dttm"], columns=["country"], aggregates={"sum_metric": {"operator": "sum"}}, - flatten_columns=False, - reset_index=False, ) """ sum_metric @@ -127,8 +125,6 @@ def test_cum_after_pivot_with_multiple_metrics(): "sum_metric": {"operator": "sum"}, "count_metric": {"operator": "sum"}, }, - flatten_columns=False, - reset_index=False, ) """ count_metric sum_metric diff --git a/tests/unit_tests/pandas_postprocessing/test_flatten.py b/tests/unit_tests/pandas_postprocessing/test_flatten.py index 78a2e3eea4421..fea84f7b9f5b0 100644 --- a/tests/unit_tests/pandas_postprocessing/test_flatten.py +++ b/tests/unit_tests/pandas_postprocessing/test_flatten.py @@ -156,3 +156,22 @@ def test_flat_integer_column_name(): } ) ) + + +def test_escape_column_name(): + index = pd.to_datetime(["2021-01-01", "2021-01-02", "2021-01-03"]) + index.name = "__timestamp" + columns = pd.MultiIndex.from_arrays( + [ + ["level1,value1", "level1,value2", "level1,value3"], + ["level2, value1", "level2, value2", "level2, value3"], + ], + names=["level1", "level2"], + ) + df = pd.DataFrame(index=index, columns=columns, data=1) + assert list(pp.flatten(df).columns.values) == [ + "__timestamp", + "level1\\,value1" + FLAT_COLUMN_SEPARATOR + "level2\\, value1", + "level1\\,value2" + FLAT_COLUMN_SEPARATOR + "level2\\, value2", + "level1\\,value3" + FLAT_COLUMN_SEPARATOR + "level2\\, value3", + ] diff --git a/tests/unit_tests/pandas_postprocessing/test_pivot.py b/tests/unit_tests/pandas_postprocessing/test_pivot.py index 658cb4edcda86..8efd203906077 100644 --- a/tests/unit_tests/pandas_postprocessing/test_pivot.py +++ b/tests/unit_tests/pandas_postprocessing/test_pivot.py @@ -17,86 +17,12 @@ import numpy as np import pytest -from pandas import DataFrame, Timestamp, to_datetime +from pandas import DataFrame, to_datetime from superset.exceptions import InvalidPostProcessingError -from superset.utils.pandas_postprocessing import _flatten_column_after_pivot, pivot -from tests.unit_tests.fixtures.dataframes import categories_df, single_metric_df -from tests.unit_tests.pandas_postprocessing.utils import ( - AGGREGATES_MULTIPLE, - AGGREGATES_SINGLE, -) - - -def test_flatten_column_after_pivot(): - """ - Test pivot column flattening function - """ - # single aggregate cases - assert ( - _flatten_column_after_pivot( - aggregates=AGGREGATES_SINGLE, - column="idx_nulls", - ) - == "idx_nulls" - ) - - assert ( - _flatten_column_after_pivot( - aggregates=AGGREGATES_SINGLE, - column=1234, - ) - == "1234" - ) - - assert ( - _flatten_column_after_pivot( - aggregates=AGGREGATES_SINGLE, - column=Timestamp("2020-09-29T00:00:00"), - ) - == "2020-09-29 00:00:00" - ) - - assert ( - _flatten_column_after_pivot( - aggregates=AGGREGATES_SINGLE, - column="idx_nulls", - ) - == "idx_nulls" - ) - - assert ( - _flatten_column_after_pivot( - aggregates=AGGREGATES_SINGLE, - column=("idx_nulls", "col1"), - ) - == "col1" - ) - - assert ( - _flatten_column_after_pivot( - aggregates=AGGREGATES_SINGLE, - column=("idx_nulls", "col1", 1234), - ) - == "col1, 1234" - ) - - # Multiple aggregate cases - assert ( - _flatten_column_after_pivot( - aggregates=AGGREGATES_MULTIPLE, - column=("idx_nulls", "asc_idx", "col1"), - ) - == "idx_nulls, asc_idx, col1" - ) - - assert ( - _flatten_column_after_pivot( - aggregates=AGGREGATES_MULTIPLE, - column=("idx_nulls", "asc_idx", "col1", 1234), - ) - == "idx_nulls, asc_idx, col1, 1234" - ) +from superset.utils.pandas_postprocessing import flatten, pivot +from tests.unit_tests.fixtures.dataframes import categories_df +from tests.unit_tests.pandas_postprocessing.utils import AGGREGATES_SINGLE def test_pivot_without_columns(): @@ -108,9 +34,9 @@ def test_pivot_without_columns(): index=["name"], aggregates=AGGREGATES_SINGLE, ) - assert df.columns.tolist() == ["name", "idx_nulls"] + assert df.columns.tolist() == ["idx_nulls"] assert len(df) == 101 - assert df.sum()[1] == 1050 + assert df["idx_nulls"].sum() == 1050 def test_pivot_with_single_column(): @@ -123,9 +49,13 @@ def test_pivot_with_single_column(): columns=["category"], aggregates=AGGREGATES_SINGLE, ) - assert df.columns.tolist() == ["name", "cat0", "cat1", "cat2"] + assert df.columns.tolist() == [ + ("idx_nulls", "cat0"), + ("idx_nulls", "cat1"), + ("idx_nulls", "cat2"), + ] assert len(df) == 101 - assert df.sum()[1] == 315 + assert df["idx_nulls"]["cat0"].sum() == 315 df = pivot( df=categories_df, @@ -133,7 +63,11 @@ def test_pivot_with_single_column(): columns=["category"], aggregates=AGGREGATES_SINGLE, ) - assert df.columns.tolist() == ["dept", "cat0", "cat1", "cat2"] + assert df.columns.tolist() == [ + ("idx_nulls", "cat0"), + ("idx_nulls", "cat1"), + ("idx_nulls", "cat2"), + ] assert len(df) == 5 @@ -147,6 +81,7 @@ def test_pivot_with_multiple_columns(): columns=["category", "dept"], aggregates=AGGREGATES_SINGLE, ) + df = flatten(df) assert len(df.columns) == 1 + 3 * 5 # index + possible permutations @@ -161,7 +96,7 @@ def test_pivot_fill_values(): metric_fill_value=1, aggregates={"idx_nulls": {"operator": "sum"}}, ) - assert df.sum()[1] == 382 + assert df["idx_nulls"]["cat0"].sum() == 382 def test_pivot_fill_column_values(): @@ -177,7 +112,7 @@ def test_pivot_fill_column_values(): aggregates={"idx_nulls": {"operator": "sum"}}, ) assert len(df) == 101 - assert df.columns.tolist() == ["name", "<NULL>"] + assert df.columns.tolist() == [("idx_nulls", "<NULL>")] def test_pivot_exceptions(): @@ -234,8 +169,9 @@ def test_pivot_eliminate_cartesian_product_columns(): aggregates={"metric": {"operator": "mean"}}, drop_missing_columns=False, ) - assert list(df.columns) == ["dttm", "0, 0", "1, 1"] - assert np.isnan(df["1, 1"][0]) + df = flatten(df) + assert list(df.columns) == ["dttm", "metric, 0, 0", "metric, 1, 1"] + assert np.isnan(df["metric, 1, 1"][0]) # multiple metrics mock_df = DataFrame( @@ -258,6 +194,7 @@ def test_pivot_eliminate_cartesian_product_columns(): }, drop_missing_columns=False, ) + df = flatten(df) assert list(df.columns) == [ "dttm", "metric, 0, 0", @@ -266,21 +203,3 @@ def test_pivot_eliminate_cartesian_product_columns(): "metric2, 1, 1", ] assert np.isnan(df["metric, 1, 1"][0]) - - -def test_pivot_without_flatten_columns_and_reset_index(): - df = pivot( - df=single_metric_df, - index=["dttm"], - columns=["country"], - aggregates={"sum_metric": {"operator": "sum"}}, - flatten_columns=False, - reset_index=False, - ) - # metric - # country UK US - # dttm - # 2019-01-01 5 6 - # 2019-01-02 7 8 - assert df.columns.to_list() == [("sum_metric", "UK"), ("sum_metric", "US")] - assert df.index.to_list() == to_datetime(["2019-01-01", "2019-01-02"]).to_list() diff --git a/tests/unit_tests/pandas_postprocessing/test_resample.py b/tests/unit_tests/pandas_postprocessing/test_resample.py index 9f1aaef3e62f6..b1414c5fe8fdc 100644 --- a/tests/unit_tests/pandas_postprocessing/test_resample.py +++ b/tests/unit_tests/pandas_postprocessing/test_resample.py @@ -110,8 +110,6 @@ def test_resample_after_pivot(): aggregates={ "val": {"operator": "sum"}, }, - flatten_columns=False, - reset_index=False, ) """ val diff --git a/tests/unit_tests/pandas_postprocessing/test_rolling.py b/tests/unit_tests/pandas_postprocessing/test_rolling.py index 4d4c4341b895a..b72a8bee44827 100644 --- a/tests/unit_tests/pandas_postprocessing/test_rolling.py +++ b/tests/unit_tests/pandas_postprocessing/test_rolling.py @@ -113,8 +113,6 @@ def test_rolling_should_empty_df(): index=["dttm"], columns=["country"], aggregates={"sum_metric": {"operator": "sum"}}, - flatten_columns=False, - reset_index=False, ) rolling_df = pp.rolling( df=pivot_df, @@ -132,8 +130,6 @@ def test_rolling_after_pivot_with_single_metric(): index=["dttm"], columns=["country"], aggregates={"sum_metric": {"operator": "sum"}}, - flatten_columns=False, - reset_index=False, ) """ sum_metric @@ -182,8 +178,6 @@ def test_rolling_after_pivot_with_multiple_metrics(): "sum_metric": {"operator": "sum"}, "count_metric": {"operator": "sum"}, }, - flatten_columns=False, - reset_index=False, ) """ count_metric sum_metric diff --git a/tests/unit_tests/pandas_postprocessing/test_sort.py b/tests/unit_tests/pandas_postprocessing/test_sort.py index c489381ff16fd..e19da38efc1ec 100644 --- a/tests/unit_tests/pandas_postprocessing/test_sort.py +++ b/tests/unit_tests/pandas_postprocessing/test_sort.py @@ -15,16 +15,39 @@ # specific language governing permissions and limitations # under the License. import pytest +from dateutil.parser import parse from superset.exceptions import InvalidPostProcessingError from superset.utils.pandas_postprocessing import sort -from tests.unit_tests.fixtures.dataframes import categories_df +from tests.unit_tests.fixtures.dataframes import categories_df, timeseries_df from tests.unit_tests.pandas_postprocessing.utils import series_to_list def test_sort(): - df = sort(df=categories_df, columns={"category": True, "asc_idx": False}) + df = sort(df=categories_df, by=["category", "asc_idx"], ascending=[True, False]) assert series_to_list(df["asc_idx"])[1] == 96 + df = sort(df=categories_df.set_index("name"), is_sort_index=True) + assert df.index[0] == "person0" + + df = sort(df=categories_df.set_index("name"), is_sort_index=True, ascending=False) + assert df.index[0] == "person99" + + df = sort(df=categories_df.set_index("name"), by="asc_idx") + assert df["asc_idx"][0] == 0 + + df = sort(df=categories_df.set_index("name"), by="asc_idx", ascending=False) + assert df["asc_idx"][0] == 100 + + df = sort(df=timeseries_df, is_sort_index=True) + assert df.index[0] == parse("2019-01-01") + + df = sort(df=timeseries_df, is_sort_index=True, ascending=False) + assert df.index[0] == parse("2019-01-07") + + df = sort(df=timeseries_df) + assert df.equals(timeseries_df) + with pytest.raises(InvalidPostProcessingError): - sort(df=df, columns={"abc": True}) + sort(df=df, by="abc", ascending=False) + sort(df=df, by=["abc", "def"]) diff --git a/tests/unit_tests/pandas_postprocessing/test_utils.py b/tests/unit_tests/pandas_postprocessing/test_utils.py new file mode 100644 index 0000000000000..058cefcd6c72a --- /dev/null +++ b/tests/unit_tests/pandas_postprocessing/test_utils.py @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from superset.utils.pandas_postprocessing import escape_separator, unescape_separator + + +def test_escape_separator(): + assert escape_separator(r" hell \world ") == r" hell \world " + assert unescape_separator(r" hell \world ") == r" hell \world " + + escape_string = escape_separator("hello, world") + assert escape_string == r"hello\, world" + assert unescape_separator(escape_string) == "hello, world" + + escape_string = escape_separator("hello,world") + assert escape_string == r"hello\,world" + assert unescape_separator(escape_string) == "hello,world" diff --git a/tests/unit_tests/result_set_test.py b/tests/unit_tests/result_set_test.py index 80d7ced61ecd0..331810bb1ed62 100644 --- a/tests/unit_tests/result_set_test.py +++ b/tests/unit_tests/result_set_test.py @@ -18,7 +18,14 @@ # pylint: disable=import-outside-toplevel, unused-argument -def test_column_names_as_bytes(app_context: None) -> None: +import numpy as np +import pandas as pd +from numpy.core.multiarray import array + +from superset.result_set import stringify_values + + +def test_column_names_as_bytes() -> None: """ Test that we can handle column names as bytes. """ @@ -65,3 +72,71 @@ def test_column_names_as_bytes(app_context: None) -> None: | 1 | 2016-01-27 | 392.444 | 396.843 | 391.782 | 394.972 | 394.972 | 47424400 | """.strip() ) + + +def test_stringify_with_null_integers(): + """ + Test that we can safely handle type errors when an integer column has a null value + """ + + data = [ + ("foo", "bar", pd.NA, None), + ("foo", "bar", pd.NA, True), + ("foo", "bar", pd.NA, None), + ] + numpy_dtype = [ + ("id", "object"), + ("value", "object"), + ("num", "object"), + ("bool", "object"), + ] + + array2 = np.array(data, dtype=numpy_dtype) + column_names = ["id", "value", "num", "bool"] + + result_set = np.array([stringify_values(array2[column]) for column in column_names]) + + expected = np.array( + [ + array(["foo", "foo", "foo"], dtype=object), + array(["bar", "bar", "bar"], dtype=object), + array([None, None, None], dtype=object), + array([None, "True", None], dtype=object), + ] + ) + + assert np.array_equal(result_set, expected) + + +def test_stringify_with_null_timestamps(): + """ + Test that we can safely handle type errors when a timestamp column has a null value + """ + + data = [ + ("foo", "bar", pd.NaT, None), + ("foo", "bar", pd.NaT, True), + ("foo", "bar", pd.NaT, None), + ] + numpy_dtype = [ + ("id", "object"), + ("value", "object"), + ("num", "object"), + ("bool", "object"), + ] + + array2 = np.array(data, dtype=numpy_dtype) + column_names = ["id", "value", "num", "bool"] + + result_set = np.array([stringify_values(array2[column]) for column in column_names]) + + expected = np.array( + [ + array(["foo", "foo", "foo"], dtype=object), + array(["bar", "bar", "bar"], dtype=object), + array([None, None, None], dtype=object), + array([None, "True", None], dtype=object), + ] + ) + + assert np.array_equal(result_set, expected) diff --git a/tests/unit_tests/sql_lab_test.py b/tests/unit_tests/sql_lab_test.py index 9950fb9fedda5..29f45eab682a0 100644 --- a/tests/unit_tests/sql_lab_test.py +++ b/tests/unit_tests/sql_lab_test.py @@ -63,7 +63,6 @@ def test_execute_sql_statement(mocker: MockerFixture, app: None) -> None: def test_execute_sql_statement_with_rls( mocker: MockerFixture, - app_context: None, ) -> None: """ Test for `execute_sql_statement` when an RLS rule is in place. @@ -118,7 +117,6 @@ def test_execute_sql_statement_with_rls( def test_sql_lab_insert_rls( mocker: MockerFixture, session: Session, - app_context: None, ) -> None: """ Integration test for `insert_rls`. @@ -186,6 +184,7 @@ def test_sql_lab_insert_rls( # now with RLS rls = RowLevelSecurityFilter( + name="sqllab_rls1", filter_type=RowLevelSecurityFilterType.REGULAR, tables=[SqlaTable(database_id=1, schema=None, table_name="t")], roles=[admin.roles[0]], diff --git a/tests/unit_tests/sql_parse_tests.py b/tests/unit_tests/sql_parse_tests.py index 1d2c788496af0..ba3da69aaefaf 100644 --- a/tests/unit_tests/sql_parse_tests.py +++ b/tests/unit_tests/sql_parse_tests.py @@ -266,13 +266,9 @@ def test_extract_tables_illdefined() -> None: assert extract_tables("SELECT * FROM catalogname..tbname") == set() -@unittest.skip("Requires sqlparse>=3.1") def test_extract_tables_show_tables_from() -> None: """ Test ``SHOW TABLES FROM``. - - This is currently broken in the pinned version of sqlparse, and fixed in - ``sqlparse>=3.1``. However, ``sqlparse==3.1`` breaks some sql formatting. """ assert extract_tables("SHOW TABLES FROM s1 like '%order%'") == set() @@ -679,7 +675,7 @@ def test_extract_tables_nested_select() -> None: """ select (extractvalue(1,concat(0x7e,(select GROUP_CONCAT(COLUMN_NAME) from INFORMATION_SCHEMA.COLUMNS -WHERE TABLE_NAME="bi_achivement_daily"),0x7e))); +WHERE TABLE_NAME="bi_achievement_daily"),0x7e))); """ ) == {Table("COLUMNS", "INFORMATION_SCHEMA")} @@ -1017,15 +1013,15 @@ def test_unknown_select() -> None: Test that `is_select` works when sqlparse fails to identify the type. """ sql = "WITH foo AS(SELECT 1) SELECT 1" - assert sqlparse.parse(sql)[0].get_type() == "UNKNOWN" + assert sqlparse.parse(sql)[0].get_type() == "SELECT" assert ParsedQuery(sql).is_select() sql = "WITH foo AS(SELECT 1) INSERT INTO my_table (a) VALUES (1)" - assert sqlparse.parse(sql)[0].get_type() == "UNKNOWN" + assert sqlparse.parse(sql)[0].get_type() == "INSERT" assert not ParsedQuery(sql).is_select() sql = "WITH foo AS(SELECT 1) DELETE FROM my_table" - assert sqlparse.parse(sql)[0].get_type() == "UNKNOWN" + assert sqlparse.parse(sql)[0].get_type() == "DELETE" assert not ParsedQuery(sql).is_select() @@ -1108,15 +1104,6 @@ def test_messy_breakdown_statements() -> None: def test_sqlparse_formatting(): """ Test that ``from_unixtime`` is formatted correctly. - - ``sqlparse==0.3.1`` has a bug and removes space between ``from`` and - ``from_unixtime``, resulting in:: - - SELECT extract(HOUR - fromfrom_unixtime(hour_ts) - AT TIME ZONE 'America/Los_Angeles') - from table - """ assert sqlparse.format( "SELECT extract(HOUR from from_unixtime(hour_ts) " @@ -1409,7 +1396,6 @@ def get_rls_for_table( candidate: Token, database_id: int, default_schema: str, - username: Optional[str] = None, ) -> Optional[TokenList]: """ Return the RLS ``condition`` if ``candidate`` matches ``table``. @@ -1446,7 +1432,7 @@ def test_add_table_name(rls: str, table: str, expected: str) -> None: assert str(condition) == expected -def test_get_rls_for_table(mocker: MockerFixture, app_context: None) -> None: +def test_get_rls_for_table(mocker: MockerFixture) -> None: """ Tests for ``get_rls_for_table``. """ diff --git a/tests/unit_tests/tables/test_models.py b/tests/unit_tests/tables/test_models.py index 56ca5ba82fbfc..7705dba6aa09d 100644 --- a/tests/unit_tests/tables/test_models.py +++ b/tests/unit_tests/tables/test_models.py @@ -20,7 +20,7 @@ from sqlalchemy.orm.session import Session -def test_table_model(app_context: None, session: Session) -> None: +def test_table_model(session: Session) -> None: """ Test basic attributes of a ``Table``. """ diff --git a/tests/unit_tests/tasks/__init__.py b/tests/unit_tests/tasks/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/tasks/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/tasks/test_cron_util.py b/tests/unit_tests/tasks/test_cron_util.py index 9042ccad58534..d0f9ae21705e2 100644 --- a/tests/unit_tests/tasks/test_cron_util.py +++ b/tests/unit_tests/tasks/test_cron_util.py @@ -20,7 +20,6 @@ import pytest import pytz from dateutil import parser -from flask.ctx import AppContext from freezegun import freeze_time from freezegun.api import FakeDatetime # type: ignore @@ -50,7 +49,7 @@ ], ) def test_cron_schedule_window_los_angeles( - app_context: AppContext, current_dttm: str, cron: str, expected: List[FakeDatetime] + current_dttm: str, cron: str, expected: List[FakeDatetime] ) -> None: """ Reports scheduler: Test cron schedule window for "America/Los_Angeles" @@ -87,7 +86,7 @@ def test_cron_schedule_window_los_angeles( ], ) def test_cron_schedule_window_invalid_timezone( - app_context: AppContext, current_dttm: str, cron: str, expected: List[FakeDatetime] + current_dttm: str, cron: str, expected: List[FakeDatetime] ) -> None: """ Reports scheduler: Test cron schedule window for "invalid timezone" @@ -125,7 +124,7 @@ def test_cron_schedule_window_invalid_timezone( ], ) def test_cron_schedule_window_new_york( - app_context: AppContext, current_dttm: str, cron: str, expected: List[FakeDatetime] + current_dttm: str, cron: str, expected: List[FakeDatetime] ) -> None: """ Reports scheduler: Test cron schedule window for "America/New_York" @@ -162,7 +161,7 @@ def test_cron_schedule_window_new_york( ], ) def test_cron_schedule_window_chicago( - app_context: AppContext, current_dttm: str, cron: str, expected: List[FakeDatetime] + current_dttm: str, cron: str, expected: List[FakeDatetime] ) -> None: """ Reports scheduler: Test cron schedule window for "America/Chicago" @@ -199,7 +198,7 @@ def test_cron_schedule_window_chicago( ], ) def test_cron_schedule_window_chicago_daylight( - app_context: AppContext, current_dttm: str, cron: str, expected: List[FakeDatetime] + current_dttm: str, cron: str, expected: List[FakeDatetime] ) -> None: """ Reports scheduler: Test cron schedule window for "America/Chicago" diff --git a/tests/unit_tests/tasks/test_utils.py b/tests/unit_tests/tasks/test_utils.py new file mode 100644 index 0000000000000..7854717201229 --- /dev/null +++ b/tests/unit_tests/tasks/test_utils.py @@ -0,0 +1,323 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from contextlib import nullcontext +from dataclasses import dataclass +from enum import Enum +from typing import Any, Dict, List, Optional, Tuple, Type, Union + +import pytest +from flask_appbuilder.security.sqla.models import User + +from superset.tasks.exceptions import ExecutorNotFoundError +from superset.tasks.types import ExecutorType + +SELENIUM_USER_ID = 1234 +SELENIUM_USERNAME = "admin" + + +def _get_users( + params: Optional[Union[int, List[int]]] +) -> Optional[Union[User, List[User]]]: + if params is None: + return None + if isinstance(params, int): + return User(id=params, username=str(params)) + return [User(id=user, username=str(user)) for user in params] + + +@dataclass +class ModelConfig: + owners: List[int] + creator: Optional[int] = None + modifier: Optional[int] = None + + +class ModelType(int, Enum): + DASHBOARD = 1 + CHART = 2 + REPORT_SCHEDULE = 3 + + +@pytest.mark.parametrize( + "model_type,executor_types,model_config,current_user,expected_result", + [ + ( + ModelType.REPORT_SCHEDULE, + [ExecutorType.SELENIUM], + ModelConfig( + owners=[1, 2], + creator=3, + modifier=4, + ), + None, + (ExecutorType.SELENIUM, SELENIUM_USER_ID), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.CREATOR, + ExecutorType.CREATOR_OWNER, + ExecutorType.OWNER, + ExecutorType.MODIFIER, + ExecutorType.MODIFIER_OWNER, + ExecutorType.SELENIUM, + ], + ModelConfig(owners=[]), + None, + (ExecutorType.SELENIUM, SELENIUM_USER_ID), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.CREATOR, + ExecutorType.CREATOR_OWNER, + ExecutorType.OWNER, + ExecutorType.MODIFIER, + ExecutorType.MODIFIER_OWNER, + ExecutorType.SELENIUM, + ], + ModelConfig(owners=[], modifier=1), + None, + (ExecutorType.MODIFIER, 1), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.CREATOR, + ExecutorType.CREATOR_OWNER, + ExecutorType.OWNER, + ExecutorType.MODIFIER, + ExecutorType.MODIFIER_OWNER, + ExecutorType.SELENIUM, + ], + ModelConfig(owners=[2], modifier=1), + None, + (ExecutorType.OWNER, 2), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.CREATOR, + ExecutorType.CREATOR_OWNER, + ExecutorType.OWNER, + ExecutorType.MODIFIER, + ExecutorType.MODIFIER_OWNER, + ExecutorType.SELENIUM, + ], + ModelConfig(owners=[2], creator=3, modifier=1), + None, + (ExecutorType.CREATOR, 3), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.OWNER, + ], + ModelConfig(owners=[1, 2, 3, 4, 5, 6, 7], creator=3, modifier=4), + None, + (ExecutorType.OWNER, 4), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.OWNER, + ], + ModelConfig(owners=[1, 2, 3, 4, 5, 6, 7], creator=3, modifier=8), + None, + (ExecutorType.OWNER, 3), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.MODIFIER_OWNER, + ], + ModelConfig(owners=[1, 2, 3, 4, 5, 6, 7], creator=8, modifier=9), + None, + ExecutorNotFoundError(), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.MODIFIER_OWNER, + ], + ModelConfig(owners=[1, 2, 3, 4, 5, 6, 7], creator=8, modifier=4), + None, + (ExecutorType.MODIFIER_OWNER, 4), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.CREATOR_OWNER, + ], + ModelConfig(owners=[1, 2, 3, 4, 5, 6, 7], creator=8, modifier=9), + None, + ExecutorNotFoundError(), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.CREATOR_OWNER, + ], + ModelConfig(owners=[1, 2, 3, 4, 5, 6, 7], creator=4, modifier=8), + None, + (ExecutorType.CREATOR_OWNER, 4), + ), + ( + ModelType.REPORT_SCHEDULE, + [ + ExecutorType.CURRENT_USER, + ], + ModelConfig(owners=[1, 2, 3, 4, 5, 6, 7], creator=4, modifier=8), + None, + ExecutorNotFoundError(), + ), + ( + ModelType.DASHBOARD, + [ + ExecutorType.CURRENT_USER, + ], + ModelConfig(owners=[1], creator=2, modifier=3), + 4, + (ExecutorType.CURRENT_USER, 4), + ), + ( + ModelType.DASHBOARD, + [ + ExecutorType.SELENIUM, + ], + ModelConfig(owners=[1], creator=2, modifier=3), + 4, + (ExecutorType.SELENIUM, SELENIUM_USER_ID), + ), + ( + ModelType.DASHBOARD, + [ + ExecutorType.CURRENT_USER, + ], + ModelConfig(owners=[1], creator=2, modifier=3), + None, + ExecutorNotFoundError(), + ), + ( + ModelType.DASHBOARD, + [ + ExecutorType.CREATOR_OWNER, + ExecutorType.MODIFIER_OWNER, + ExecutorType.CURRENT_USER, + ExecutorType.SELENIUM, + ], + ModelConfig(owners=[1], creator=2, modifier=3), + None, + (ExecutorType.SELENIUM, SELENIUM_USER_ID), + ), + ( + ModelType.CHART, + [ + ExecutorType.CURRENT_USER, + ], + ModelConfig(owners=[1], creator=2, modifier=3), + 4, + (ExecutorType.CURRENT_USER, 4), + ), + ( + ModelType.CHART, + [ + ExecutorType.SELENIUM, + ], + ModelConfig(owners=[1], creator=2, modifier=3), + 4, + (ExecutorType.SELENIUM, SELENIUM_USER_ID), + ), + ( + ModelType.CHART, + [ + ExecutorType.CURRENT_USER, + ], + ModelConfig(owners=[1], creator=2, modifier=3), + None, + ExecutorNotFoundError(), + ), + ( + ModelType.CHART, + [ + ExecutorType.CREATOR_OWNER, + ExecutorType.MODIFIER_OWNER, + ExecutorType.CURRENT_USER, + ExecutorType.SELENIUM, + ], + ModelConfig(owners=[1], creator=2, modifier=3), + None, + (ExecutorType.SELENIUM, SELENIUM_USER_ID), + ), + ], +) +def test_get_executor( + model_type: ModelType, + executor_types: List[ExecutorType], + model_config: ModelConfig, + current_user: Optional[int], + expected_result: Tuple[int, ExecutorNotFoundError], +) -> None: + from superset.models.dashboard import Dashboard + from superset.models.slice import Slice + from superset.reports.models import ReportSchedule + from superset.tasks.utils import get_executor + + model: Type[Union[Dashboard, ReportSchedule, Slice]] + model_kwargs: Dict[str, Any] = {} + if model_type == ModelType.REPORT_SCHEDULE: + model = ReportSchedule + model_kwargs = { + "type": "report", + "name": "test_report", + } + elif model_type == ModelType.DASHBOARD: + model = Dashboard + elif model_type == ModelType.CHART: + model = Slice + else: + raise Exception(f"Unsupported model type: {model_type}") + + obj = model( + id=1, + owners=_get_users(model_config.owners), + created_by=_get_users(model_config.creator), + changed_by=_get_users(model_config.modifier), + **model_kwargs, + ) + if isinstance(expected_result, Exception): + cm = pytest.raises(type(expected_result)) + expected_executor_type = None + expected_executor = None + else: + cm = nullcontext() + expected_executor_type = expected_result[0] + expected_executor = ( + SELENIUM_USERNAME + if expected_executor_type == ExecutorType.SELENIUM + else str(expected_result[1]) + ) + + with cm: + executor_type, executor = get_executor( + executor_types=executor_types, + model=obj, + current_user=str(current_user) if current_user else None, + ) + assert executor_type == expected_executor_type + assert executor == expected_executor diff --git a/tests/unit_tests/test_jinja_context.py b/tests/unit_tests/test_jinja_context.py index 7c301c88ea3e5..8704b1d65c211 100644 --- a/tests/unit_tests/test_jinja_context.py +++ b/tests/unit_tests/test_jinja_context.py @@ -18,7 +18,6 @@ from typing import Any import pytest -from flask.ctx import AppContext from sqlalchemy.dialects.postgresql import dialect from superset import app @@ -26,30 +25,30 @@ from superset.jinja_context import ExtraCache, safe_proxy -def test_filter_values_default(app_context: AppContext) -> None: +def test_filter_values_default() -> None: cache = ExtraCache() assert cache.filter_values("name", "foo") == ["foo"] assert cache.removed_filters == [] -def test_filter_values_remove_not_present(app_context: AppContext) -> None: +def test_filter_values_remove_not_present() -> None: cache = ExtraCache() assert cache.filter_values("name", remove_filter=True) == [] assert cache.removed_filters == [] -def test_get_filters_remove_not_present(app_context: AppContext) -> None: +def test_get_filters_remove_not_present() -> None: cache = ExtraCache() assert cache.get_filters("name", remove_filter=True) == [] assert cache.removed_filters == [] -def test_filter_values_no_default(app_context: AppContext) -> None: +def test_filter_values_no_default() -> None: cache = ExtraCache() assert cache.filter_values("name") == [] -def test_filter_values_adhoc_filters(app_context: AppContext) -> None: +def test_filter_values_adhoc_filters() -> None: with app.test_request_context( data={ "form_data": json.dumps( @@ -93,7 +92,7 @@ def test_filter_values_adhoc_filters(app_context: AppContext) -> None: assert cache.applied_filters == ["name"] -def test_get_filters_adhoc_filters(app_context: AppContext) -> None: +def test_get_filters_adhoc_filters() -> None: with app.test_request_context( data={ "form_data": json.dumps( @@ -167,7 +166,7 @@ def test_get_filters_adhoc_filters(app_context: AppContext) -> None: assert cache.applied_filters == ["name"] -def test_filter_values_extra_filters(app_context: AppContext) -> None: +def test_filter_values_extra_filters() -> None: with app.test_request_context( data={ "form_data": json.dumps( @@ -180,25 +179,25 @@ def test_filter_values_extra_filters(app_context: AppContext) -> None: assert cache.applied_filters == ["name"] -def test_url_param_default(app_context: AppContext) -> None: +def test_url_param_default() -> None: with app.test_request_context(): cache = ExtraCache() assert cache.url_param("foo", "bar") == "bar" -def test_url_param_no_default(app_context: AppContext) -> None: +def test_url_param_no_default() -> None: with app.test_request_context(): cache = ExtraCache() assert cache.url_param("foo") is None -def test_url_param_query(app_context: AppContext) -> None: +def test_url_param_query() -> None: with app.test_request_context(query_string={"foo": "bar"}): cache = ExtraCache() assert cache.url_param("foo") == "bar" -def test_url_param_form_data(app_context: AppContext) -> None: +def test_url_param_form_data() -> None: with app.test_request_context( query_string={"form_data": json.dumps({"url_params": {"foo": "bar"}})} ): @@ -206,7 +205,7 @@ def test_url_param_form_data(app_context: AppContext) -> None: assert cache.url_param("foo") == "bar" -def test_url_param_escaped_form_data(app_context: AppContext) -> None: +def test_url_param_escaped_form_data() -> None: with app.test_request_context( query_string={"form_data": json.dumps({"url_params": {"foo": "O'Brien"}})} ): @@ -214,7 +213,7 @@ def test_url_param_escaped_form_data(app_context: AppContext) -> None: assert cache.url_param("foo") == "O''Brien" -def test_url_param_escaped_default_form_data(app_context: AppContext) -> None: +def test_url_param_escaped_default_form_data() -> None: with app.test_request_context( query_string={"form_data": json.dumps({"url_params": {"foo": "O'Brien"}})} ): @@ -222,7 +221,7 @@ def test_url_param_escaped_default_form_data(app_context: AppContext) -> None: assert cache.url_param("bar", "O'Malley") == "O''Malley" -def test_url_param_unescaped_form_data(app_context: AppContext) -> None: +def test_url_param_unescaped_form_data() -> None: with app.test_request_context( query_string={"form_data": json.dumps({"url_params": {"foo": "O'Brien"}})} ): @@ -230,7 +229,7 @@ def test_url_param_unescaped_form_data(app_context: AppContext) -> None: assert cache.url_param("foo", escape_result=False) == "O'Brien" -def test_url_param_unescaped_default_form_data(app_context: AppContext) -> None: +def test_url_param_unescaped_default_form_data() -> None: with app.test_request_context( query_string={"form_data": json.dumps({"url_params": {"foo": "O'Brien"}})} ): @@ -238,21 +237,21 @@ def test_url_param_unescaped_default_form_data(app_context: AppContext) -> None: assert cache.url_param("bar", "O'Malley", escape_result=False) == "O'Malley" -def test_safe_proxy_primitive(app_context: AppContext) -> None: +def test_safe_proxy_primitive() -> None: def func(input_: Any) -> Any: return input_ assert safe_proxy(func, "foo") == "foo" -def test_safe_proxy_dict(app_context: AppContext) -> None: +def test_safe_proxy_dict() -> None: def func(input_: Any) -> Any: return input_ assert safe_proxy(func, {"foo": "bar"}) == {"foo": "bar"} -def test_safe_proxy_lambda(app_context: AppContext) -> None: +def test_safe_proxy_lambda() -> None: def func(input_: Any) -> Any: return input_ @@ -260,7 +259,7 @@ def func(input_: Any) -> Any: safe_proxy(func, lambda: "bar") -def test_safe_proxy_nested_lambda(app_context: AppContext) -> None: +def test_safe_proxy_nested_lambda() -> None: def func(input_: Any) -> Any: return input_ diff --git a/tests/unit_tests/thumbnails/__init__.py b/tests/unit_tests/thumbnails/__init__.py new file mode 100644 index 0000000000000..13a83393a9124 --- /dev/null +++ b/tests/unit_tests/thumbnails/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/tests/unit_tests/thumbnails/test_digest.py b/tests/unit_tests/thumbnails/test_digest.py new file mode 100644 index 0000000000000..04f244e629b59 --- /dev/null +++ b/tests/unit_tests/thumbnails/test_digest.py @@ -0,0 +1,258 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +from contextlib import nullcontext +from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union +from unittest.mock import patch + +import pytest +from flask_appbuilder.security.sqla.models import User + +from superset.tasks.exceptions import ExecutorNotFoundError +from superset.tasks.types import ExecutorType +from superset.utils.core import override_user + +if TYPE_CHECKING: + from superset.models.dashboard import Dashboard + from superset.models.slice import Slice + +_DEFAULT_DASHBOARD_KWARGS: Dict[str, Any] = { + "id": 1, + "dashboard_title": "My Title", + "slices": [{"id": 1, "slice_name": "My Chart"}], + "position_json": '{"a": "b"}', + "css": "background-color: lightblue;", + "json_metadata": '{"c": "d"}', +} + +_DEFAULT_CHART_KWARGS = { + "id": 2, + "params": {"a": "b"}, +} + + +def CUSTOM_DASHBOARD_FUNC( + dashboard: Dashboard, + executor_type: ExecutorType, + executor: str, +) -> str: + return f"{dashboard.id}.{executor_type.value}.{executor}" + + +def CUSTOM_CHART_FUNC( + chart: Slice, + executor_type: ExecutorType, + executor: str, +) -> str: + return f"{chart.id}.{executor_type.value}.{executor}" + + +@pytest.mark.parametrize( + "dashboard_overrides,execute_as,has_current_user,use_custom_digest,expected_result", + [ + ( + None, + [ExecutorType.SELENIUM], + False, + False, + "71452fee8ffbd8d340193d611bcd4559", + ), + ( + None, + [ExecutorType.CURRENT_USER], + True, + False, + "209dc060ac19271b8708731e3b8280f5", + ), + ( + { + "dashboard_title": "My Other Title", + }, + [ExecutorType.CURRENT_USER], + True, + False, + "209dc060ac19271b8708731e3b8280f5", + ), + ( + { + "id": 2, + }, + [ExecutorType.CURRENT_USER], + True, + False, + "06a4144466dbd5ffad0c3c2225e96296", + ), + ( + { + "slices": [{"id": 2, "slice_name": "My Other Chart"}], + }, + [ExecutorType.CURRENT_USER], + True, + False, + "a823ece9563895ccb14f3d9095e84f7a", + ), + ( + { + "position_json": {"b": "c"}, + }, + [ExecutorType.CURRENT_USER], + True, + False, + "33c5475f92a904925ab3ef493526e5b5", + ), + ( + { + "css": "background-color: darkblue;", + }, + [ExecutorType.CURRENT_USER], + True, + False, + "cec57345e6402c0d4b3caee5cfaa0a03", + ), + ( + { + "json_metadata": {"d": "e"}, + }, + [ExecutorType.CURRENT_USER], + True, + False, + "5380dcbe94621a0759b09554404f3d02", + ), + ( + None, + [ExecutorType.CURRENT_USER], + True, + True, + "1.current_user.1", + ), + ( + None, + [ExecutorType.CURRENT_USER], + False, + False, + ExecutorNotFoundError(), + ), + ], +) +def test_dashboard_digest( + dashboard_overrides: Optional[Dict[str, Any]], + execute_as: List[ExecutorType], + has_current_user: bool, + use_custom_digest: bool, + expected_result: Union[str, Exception], +) -> None: + from superset import app + from superset.models.dashboard import Dashboard + from superset.models.slice import Slice + from superset.thumbnails.digest import get_dashboard_digest + + kwargs = { + **_DEFAULT_DASHBOARD_KWARGS, + **(dashboard_overrides or {}), + } + slices = [Slice(**slice_kwargs) for slice_kwargs in kwargs.pop("slices")] + dashboard = Dashboard(**kwargs, slices=slices) + user: Optional[User] = None + if has_current_user: + user = User(id=1, username="1") + func = CUSTOM_DASHBOARD_FUNC if use_custom_digest else None + + with patch.dict( + app.config, + { + "THUMBNAIL_EXECUTE_AS": execute_as, + "THUMBNAIL_DASHBOARD_DIGEST_FUNC": func, + }, + ), override_user(user): + cm = ( + pytest.raises(type(expected_result)) + if isinstance(expected_result, Exception) + else nullcontext() + ) + with cm: + assert get_dashboard_digest(dashboard=dashboard) == expected_result + + +@pytest.mark.parametrize( + "chart_overrides,execute_as,has_current_user,use_custom_digest,expected_result", + [ + ( + None, + [ExecutorType.SELENIUM], + False, + False, + "47d852b5c4df211c115905617bb722c1", + ), + ( + None, + [ExecutorType.CURRENT_USER], + True, + False, + "4f8109d3761e766e650af514bb358f10", + ), + ( + None, + [ExecutorType.CURRENT_USER], + True, + True, + "2.current_user.1", + ), + ( + None, + [ExecutorType.CURRENT_USER], + False, + False, + ExecutorNotFoundError(), + ), + ], +) +def test_chart_digest( + chart_overrides: Optional[Dict[str, Any]], + execute_as: List[ExecutorType], + has_current_user: bool, + use_custom_digest: bool, + expected_result: Union[str, Exception], +) -> None: + from superset import app + from superset.models.slice import Slice + from superset.thumbnails.digest import get_chart_digest + + kwargs = { + **_DEFAULT_CHART_KWARGS, + **(chart_overrides or {}), + } + chart = Slice(**kwargs) + user: Optional[User] = None + if has_current_user: + user = User(id=1, username="1") + func = CUSTOM_CHART_FUNC if use_custom_digest else None + + with patch.dict( + app.config, + { + "THUMBNAIL_EXECUTE_AS": execute_as, + "THUMBNAIL_CHART_DIGEST_FUNC": func, + }, + ), override_user(user): + cm = ( + pytest.raises(type(expected_result)) + if isinstance(expected_result, Exception) + else nullcontext() + ) + with cm: + assert get_chart_digest(chart=chart) == expected_result diff --git a/tests/unit_tests/utils/cache_test.py b/tests/unit_tests/utils/cache_test.py index 7c1354aa3cb39..53650e1d20324 100644 --- a/tests/unit_tests/utils/cache_test.py +++ b/tests/unit_tests/utils/cache_test.py @@ -21,7 +21,7 @@ from pytest_mock import MockerFixture -def test_memoized_func(app_context: None, mocker: MockerFixture) -> None: +def test_memoized_func(mocker: MockerFixture) -> None: """ Test the ``memoized_func`` decorator. """ diff --git a/tests/unit_tests/utils/date_parser_tests.py b/tests/unit_tests/utils/date_parser_tests.py index e5b3eebd99bae..f3c8b6968077b 100644 --- a/tests/unit_tests/utils/date_parser_tests.py +++ b/tests/unit_tests/utils/date_parser_tests.py @@ -163,7 +163,7 @@ def test_datetime_eval() -> None: expected = datetime(2016, 11, 7, 9, 30, 10) assert result == expected - result = datetime_eval("datetime('today' )") + result = datetime_eval("datetime('today')") expected = datetime(2016, 11, 7) assert result == expected @@ -308,7 +308,7 @@ def test_get_past_or_future() -> None: def test_parse_human_datetime() -> None: with pytest.raises(TimeRangeAmbiguousError): - parse_human_datetime(" 2 days ") + parse_human_datetime("2 days") with pytest.raises(TimeRangeAmbiguousError): parse_human_datetime("2 day") diff --git a/tests/integration_tests/db_engine_specs/impala_tests.py b/tests/unit_tests/utils/log_tests.py similarity index 62% rename from tests/integration_tests/db_engine_specs/impala_tests.py rename to tests/unit_tests/utils/log_tests.py index 936ace98be39e..5b031b5778875 100644 --- a/tests/integration_tests/db_engine_specs/impala_tests.py +++ b/tests/unit_tests/utils/log_tests.py @@ -14,19 +14,24 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from superset.db_engine_specs.impala import ImpalaEngineSpec -from tests.integration_tests.db_engine_specs.base_tests import TestDbEngineSpec -class TestImpalaDbEngineSpec(TestDbEngineSpec): - def test_convert_dttm(self): - dttm = self.get_dttm() +from superset.utils.log import get_logger_from_status - self.assertEqual( - ImpalaEngineSpec.convert_dttm("DATE", dttm), "CAST('2019-01-02' AS DATE)" - ) - self.assertEqual( - ImpalaEngineSpec.convert_dttm("TIMESTAMP", dttm), - "CAST('2019-01-02T03:04:05.678900' AS TIMESTAMP)", - ) +def test_log_from_status_exception() -> None: + (func, log_level) = get_logger_from_status(500) + assert func.__name__ == "exception" + assert log_level == "exception" + + +def test_log_from_status_warning() -> None: + (func, log_level) = get_logger_from_status(422) + assert func.__name__ == "warning" + assert log_level == "warning" + + +def test_log_from_status_info() -> None: + (func, log_level) = get_logger_from_status(300) + assert func.__name__ == "info" + assert log_level == "info" diff --git a/tests/unit_tests/utils/test_core.py b/tests/unit_tests/utils/test_core.py new file mode 100644 index 0000000000000..6845bb2fc1545 --- /dev/null +++ b/tests/unit_tests/utils/test_core.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from typing import Any, Dict + +import pytest + +from superset.utils.core import QueryObjectFilterClause, remove_extra_adhoc_filters + +ADHOC_FILTER: QueryObjectFilterClause = { + "col": "foo", + "op": "==", + "val": "bar", +} + +EXTRA_FILTER: QueryObjectFilterClause = { + "col": "foo", + "op": "==", + "val": "bar", + "isExtra": True, +} + + +@pytest.mark.parametrize( + "original,expected", + [ + ({"foo": "bar"}, {"foo": "bar"}), + ( + {"foo": "bar", "adhoc_filters": [ADHOC_FILTER]}, + {"foo": "bar", "adhoc_filters": [ADHOC_FILTER]}, + ), + ( + {"foo": "bar", "adhoc_filters": [EXTRA_FILTER]}, + {"foo": "bar", "adhoc_filters": []}, + ), + ( + { + "foo": "bar", + "adhoc_filters": [ADHOC_FILTER, EXTRA_FILTER], + }, + {"foo": "bar", "adhoc_filters": [ADHOC_FILTER]}, + ), + ( + { + "foo": "bar", + "adhoc_filters_b": [ADHOC_FILTER, EXTRA_FILTER], + }, + {"foo": "bar", "adhoc_filters_b": [ADHOC_FILTER]}, + ), + ( + { + "foo": "bar", + "custom_adhoc_filters": [ + ADHOC_FILTER, + EXTRA_FILTER, + ], + }, + { + "foo": "bar", + "custom_adhoc_filters": [ + ADHOC_FILTER, + EXTRA_FILTER, + ], + }, + ), + ], +) +def test_remove_extra_adhoc_filters( + original: Dict[str, Any], expected: Dict[str, Any] +) -> None: + remove_extra_adhoc_filters(original) + assert expected == original diff --git a/tests/unit_tests/utils/test_decorators.py b/tests/unit_tests/utils/test_decorators.py new file mode 100644 index 0000000000000..3aafc7a91db2b --- /dev/null +++ b/tests/unit_tests/utils/test_decorators.py @@ -0,0 +1,87 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +from contextlib import nullcontext +from enum import Enum +from inspect import isclass +from typing import Any, Optional +from unittest.mock import call, Mock, patch + +import pytest + +from superset import app +from superset.utils import decorators + + +class ResponseValues(str, Enum): + FAIL = "fail" + WARN = "warn" + OK = "ok" + + +def test_debounce() -> None: + mock = Mock() + + @decorators.debounce() + def myfunc(arg1: int, arg2: int, kwarg1: str = "abc", kwarg2: int = 2) -> int: + mock(arg1, kwarg1) + return arg1 + arg2 + kwarg2 + + # should be called only once when arguments don't change + myfunc(1, 1) + myfunc(1, 1) + result = myfunc(1, 1) + mock.assert_called_once_with(1, "abc") + assert result == 4 + + # kwarg order shouldn't matter + myfunc(1, 0, kwarg2=2, kwarg1="haha") + result = myfunc(1, 0, kwarg1="haha", kwarg2=2) + mock.assert_has_calls([call(1, "abc"), call(1, "haha")]) + assert result == 3 + + +@pytest.mark.parametrize( + "response_value, expected_exception, expected_result", + [ + (ResponseValues.OK, None, "custom.prefix.ok"), + (ResponseValues.FAIL, ValueError, "custom.prefix.error"), + (ResponseValues.WARN, FileNotFoundError, "custom.prefix.warn"), + ], +) +def test_statsd_gauge( + response_value: str, expected_exception: Optional[Exception], expected_result: str +) -> None: + @decorators.statsd_gauge("custom.prefix") + def my_func(response: ResponseValues, *args: Any, **kwargs: Any) -> str: + if response == ResponseValues.FAIL: + raise ValueError("Error") + if response == ResponseValues.WARN: + raise FileNotFoundError("Not found") + return "OK" + + with patch.object(app.config["STATS_LOGGER"], "gauge") as mock: + cm = ( + pytest.raises(expected_exception) + if isclass(expected_exception) and issubclass(expected_exception, Exception) + else nullcontext() + ) + + with cm: + my_func(response_value, 1, 2) + mock.assert_called_once_with(expected_result, 1) diff --git a/tests/unit_tests/utils/test_file.py b/tests/unit_tests/utils/test_file.py new file mode 100644 index 0000000000000..de20402e5c21c --- /dev/null +++ b/tests/unit_tests/utils/test_file.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import pytest + +from superset.utils.file import get_filename + + +@pytest.mark.parametrize( + "model_name,model_id,skip_id,expected_filename", + [ + ("Energy Sankey", 132, False, "Energy_Sankey_132"), + ("Energy Sankey", 132, True, "Energy_Sankey"), + ("folder1/Energy Sankey", 132, True, "folder1_Energy_Sankey"), + ("D:\\Charts\\Energy Sankey", 132, True, "DChartsEnergy_Sankey"), + ("🥴🥴🥴", 4751, False, "4751"), + ("🥴🥴🥴", 4751, True, "4751"), + ("Energy Sankey 🥴🥴🥴", 4751, False, "Energy_Sankey_4751"), + ("Energy Sankey 🥴🥴🥴", 4751, True, "Energy_Sankey"), + ("你好", 475, False, "475"), + ("你好", 475, True, "475"), + ("Energy Sankey 你好", 475, False, "Energy_Sankey_475"), + ("Energy Sankey 你好", 475, True, "Energy_Sankey"), + ], +) +def test_get_filename( + model_name: str, model_id: int, skip_id: bool, expected_filename: str +) -> None: + original_filename = get_filename(model_name, model_id, skip_id) + assert expected_filename == original_filename diff --git a/tests/unit_tests/utils/urls_tests.py b/tests/unit_tests/utils/urls_tests.py index 59c7841b5d907..208d6caea4375 100644 --- a/tests/unit_tests/utils/urls_tests.py +++ b/tests/unit_tests/utils/urls_tests.py @@ -19,7 +19,7 @@ from superset.utils.urls import modify_url_query -EXPLORE_CHART_LINK = "http://localhost:9000/superset/explore/?form_data=%7B%22slice_id%22%3A+76%7D&standalone=true&force=false" +EXPLORE_CHART_LINK = "http://localhost:9000/explore/?form_data=%7B%22slice_id%22%3A+76%7D&standalone=true&force=false" EXPLORE_DASHBOARD_LINK = "http://localhost:9000/superset/dashboard/3/?standalone=3" @@ -28,7 +28,7 @@ def test_convert_chart_link() -> None: test_url = modify_url_query(EXPLORE_CHART_LINK, standalone="0") assert ( test_url - == "http://localhost:9000/superset/explore/?form_data=%7B%22slice_id%22%3A%2076%7D&standalone=0&force=false" + == "http://localhost:9000/explore/?form_data=%7B%22slice_id%22%3A%2076%7D&standalone=0&force=false" ) @@ -37,6 +37,11 @@ def test_convert_dashboard_link() -> None: assert test_url == "http://localhost:9000/superset/dashboard/3/?standalone=0" +def test_convert_dashboard_link_with_integer() -> None: + test_url = modify_url_query(EXPLORE_DASHBOARD_LINK, standalone=0) + assert test_url == "http://localhost:9000/superset/dashboard/3/?standalone=0" + + @pytest.mark.parametrize( "url,is_safe", [ @@ -53,7 +58,7 @@ def test_convert_dashboard_link() -> None: ("xpto://localhost:[3/1/", False), ], ) -def test_is_safe_url(app_context: None, url: str, is_safe: bool) -> None: +def test_is_safe_url(url: str, is_safe: bool) -> None: from superset import app from superset.utils.urls import is_safe_url